diff --git a/.codex/skills/add-oliphaunt-extension/SKILL.md b/.codex/skills/add-oliphaunt-extension/SKILL.md index 10f70c258..994cb9b0a 100644 --- a/.codex/skills/add-oliphaunt-extension/SKILL.md +++ b/.codex/skills/add-oliphaunt-extension/SKILL.md @@ -25,7 +25,12 @@ Keep the SQL extension name distinct from the release product id and upstream pr metadata. For a public external extension, also maintain its product-local `release.toml`, `VERSION`, and empty first-release `CHANGELOG.md`. Every external extension must own - `upstream-license-data.json` beside that metadata. Freeze exactly the source + `upstream-license-data.json` beside that metadata. After changing source or + license pins, fetch the selected pinned sources and run + `moon run extensions:audit-license-sources` to compare the actual upstream + bytes. `extensions:packaging-unit` remains a cold-checkout packaging proof + and does not silently expand its coverage when a local source cache exists. + Freeze exactly the source identities and license/notice rows used by that extension, include only the referenced content-addressed blobs, and audit those bytes against the clean pinned checkout. Never put independently versioned extensions into one @@ -35,7 +40,7 @@ Keep the SQL extension name distinct from the release product id and upstream pr When it does, record that reviewed endpoint as `mirror_url` and prove that it serves the exact pinned commit; never infer a mirror or use a community fork merely for availability. -2. The canonical target profiles in `tools/release/extension-target-profiles.toml` apply to every extension on main. A target-specific exception is branch work until its format and shipped behavior are implemented together; do not add status, promotion, or blocker metadata. +2. The canonical target profiles in `src/extensions/contracts/extension-target-profiles.toml` apply to every extension on main. A target-specific exception is branch work until its format and shipped behavior are implemented together; do not add status, promotion, or blocker metadata. 3. For an active public product, declare the stable Cargo façade plus native, mobile, WASIX portable/AOT, npm, and Maven carriers actually required by the owning release product. Contrib members use the shared bundle carriers and @@ -45,8 +50,7 @@ Keep the SQL extension name distinct from the release product id and upstream pr 4. Regenerate the shared extension model: ```sh -tools/dev/bun.sh src/extensions/tools/check-extension-model.mjs --write -cargo run -p xtask -- assets verify-committed +bash src/extensions/tools/check-extension-model.sh --write ``` Source-pin, patch, recipe, compiler-input, or producer-code changes require the @@ -56,8 +60,8 @@ target-profile edits are package-envelope changes. 5. Verify the model and release graph: ```sh -tools/dev/bun.sh src/extensions/tools/check-extension-model.mjs --check -tools/dev/bun.sh tools/release/release-check.mjs +bash src/extensions/tools/check-extension-model.sh --check +bash tools/release/release-check.sh ``` When source acquisition or `mirror_url` changes, also run the source-fetch diff --git a/.codex/skills/qualify-oliphaunt-change/SKILL.md b/.codex/skills/qualify-oliphaunt-change/SKILL.md index d4f212ddb..57c47d5f8 100644 --- a/.codex/skills/qualify-oliphaunt-change/SKILL.md +++ b/.codex/skills/qualify-oliphaunt-change/SKILL.md @@ -5,19 +5,30 @@ description: Select, run, and diagnose Oliphaunt local and GitHub CI qualificati # Qualify Oliphaunt Change -Use the repository graph to select work, but require the full exact-SHA gate for releases. +Use the repository graph to select work and require exact-SHA qualification for releases. +CI's `release_products_json` input selects stable product IDs and their Moon +task/dependency closure. Keep platform selectors at `all`; a focused platform +debug run cannot qualify publication. Empty product selection remains the +exhaustive audit. Selected-product records must cover every published product; +producer evidence still comes from the same candidate run. +Generated same-repository Release PRs and their merged main release commits +derive scope automatically from Release Please manifest changes. Main push +qualifies only after Plan and Required succeed; PR results cannot be published. ## Local feedback 1. Inspect the diff and ask Moon for affected projects/tasks. Do not infer affected products from directory names alone. 2. Run affected formatting (`format-check`, `js-format-check`, or - `rust-format-check`), `lint`, `compile`, `unit`, and `package` tasks - independently. Run producer, smoke, regression, and E2E lanes only when - their inputs or public behavior changed. -3. If the diff changes WASIX source pins, patches, build recipes, the toolchain, - or producer code, run the product-owned source checks and portable/AOT build. - Version, changelog, package-description, smoke-expectation, and - target-envelope-only changes do not require that expensive build. + `rust-format-check`), `lint`, `typecheck`, and `test` tasks as applicable. + Inspect the owner's actual task definitions before selecting `build`, + `package`, `test-consumer`, `test-integration`, `test-browser`, or installed + device tests. Let Moon build declared prerequisites; task names alone do + not justify running every available lane. +3. If the diff changes a WASIX producer's source pins, patches, recipes, + toolchain or code, qualify that owner's affected portable/AOT output. Reuse + compiler outputs only when their declared source, dependency and toolchain + identities still match. A package envelope or test-only edit alone does not + justify rebuilding unrelated core, tools or extension producers. 4. Select release-policy checks by the contract that changed: ```sh @@ -25,81 +36,77 @@ Use the repository graph to select work, but require the full exact-SHA gate for moon run release-tools:metadata # Release implementation changes: -moon run release-tools:unit +moon run release-tools:test -# Moon/release graph topology changes: +# Release Please candidate ownership/version selection changes: moon run release-tools:graph-unit -# Repository policy implementation changes: -moon run policy-tools:unit +# Workflow and CI planning changes: +moon run ci-workflows:check -# Exact release candidate (metadata plus both unit suites): -tools/dev/bun.sh tools/release/release-check.mjs - -# Committed generated runtime assets only: -cargo run -p xtask -- assets verify-committed +# Release metadata and release implementation tests: +bash tools/release/release-check.sh # Extension catalog, recipe, carrier, or generated extension metadata only: -moon run extensions:lint extensions:unit +moon run extensions:lint extensions:test ``` -Do not run all three for an unrelated package or version edit. The repository -release-policy gate runs structure, graph, metadata, and mutation checks; it is -not product build/test/package qualification. `release-tools:check` is the local -aggregate of metadata plus the release and policy unit suites. Hosted CI runs -metadata on the publication host, gives workflow/planner tests to -`ci-workflows:check`, and selects release or policy units only when their actual -implementation inputs change. Exact release candidates require the combined -runner in qualification; slim publishers consume that evidence instead of -replaying source-only checks. Do not schedule both forms in one lane. -The macOS publication-host metadata job is affected-only on pull requests and -mandatory on exhaustive push/manual runs; product source alone does not justify -that toolchain setup unless it changes release metadata or graph inputs. -`tools/graph/ci_plan.mjs` writes `target/graph/ci-plan.json`; there is no -`graph-tools` Moon project. Do not substitute policy unit tests: they prove the -classifiers but do not scan the candidate tree. +Select only the checks whose inputs changed. `release-tools:metadata` validates +product versions, compatibility, carrier declarations and derived files; +`release-tools:test` exercises release behavior; `graph-unit` exercises the +pinned Release Please candidate integration. `release-tools:check` is their +local Moon aggregate. There is no separate policy test project. The Shell +aggregate runs metadata and release tests, not product compilation or installed +consumer qualification. CI's `Checks / Policy` job runs on Ubuntu and sets up +only capabilities needed by its selected tasks. Workflow planning, affectedness, +artifact-transfer and security checks belong to `ci-workflows:check`. +Publishers consume source qualification and frozen artifacts instead of +replaying source-only suites. Do not schedule both aggregates and their +constituent checks in the same lane. +`tools/ci/ci_plan.mts` writes `target/graph/ci-plan.json`; there is no +`graph-tools` Moon project. The adapter consumes Moon's selected tasks; its +behavioral tests do not replace planning against the actual candidate tree. + +Ordinary source pushes, PR preparation and CI qualification do not select the +protected `release-bootstrap` environment. Bootstrap-token lifecycle findings +from the optional release-controls audit are setup/publication findings, not +source-qualification blockers. Preserve the actual CI ref, permission and +artifact checks; do not provision, remove or relabel registry credentials to +make an unrelated source run pass. For source-acquisition policy or a source `mirror_url`, run -`tools/dev/bun.sh test src/sources/tools/source-fetch-core.test.mjs` and -`tools/dev/bun.sh src/sources/tools/fetch-sources.mjs all --validate-only`. Prove a +`bash src/third-party/tools/source-fetch-core.test.sh` and +`bash src/third-party/tools/fetch-sources.sh production-all --validate-only`, or the +complete owner task `moon run source-inputs:test`. The paired Shell test owns +actual Git/archive operations and invokes its TypeScript assertions once. Prove a new endpoint with a live exact-commit fetch, but keep reachability out of the deterministic unit gate. Qualification must show bounded canonical-to-mirror failover, exact-pin rejection, canonical durable origin, and transactional preservation of an existing checkout when every endpoint fails. 5. For any workflow or local-action change, run - `bash tools/policy/check-workflows.sh` before waiting for CI. This is the + `bash tools/ci/check-workflows.sh` before waiting for CI. This is the repository's exact pinned `actionlint` plus `zizmor` gate and its workflow behavior tests; running `actionlint` alone is not sufficient. A disposable - `publish-dry-run` compiler probe is needed only when a release candidate + credential-free workflow compiler probe is needed only when a release candidate changes hosted-only job topology, permissions, protected environments, or dispatch inputs. The local gate cannot prove hosted environment-secret resolution or dispatch-time graph compilation. - When a changed release shell block is expected to run on macOS, run its - focused behavioral test with GNU Bash 3.2. Run the complete release-policy - gate under Bash 3.2 only for a release candidate. On macOS, omit the override; - elsewhere, point `OLIPHAUNT_BASH3` at a maintained local Bash 3.2 build: - - ```sh - bash3="${OLIPHAUNT_BASH3:-/bin/bash}" - case "$bash3" in - /*) ;; - */*) bash3="$(cd "$(dirname "$bash3")" && pwd -P)/$(basename "$bash3")" ;; - *) bash3="$(command -v "$bash3")" ;; - esac - "$bash3" -c '((BASH_VERSINFO[0] == 3 && BASH_VERSINFO[1] == 2))' - PATH="$(dirname "$bash3"):$PATH" \ - OLIPHAUNT_TEST_BASH="$bash3" \ - "$bash3" tools/dev/bun.sh tools/release/release-check.mjs - ``` - - This behavioral gate is authoritative for Bash 3.2 `set -u` empty-array - semantics; a syntax check or a source-pattern check is not a substitute. + Exercise macOS-executed Shell paths with the Bash actually selected by that + job, recording `command -v bash` and `bash --version`. `shell: bash` alone + does not establish a version. Normal release/Apple setup does not install + another Bash; the WASIX postmaster target job explicitly installs Homebrew + Bash. Keep focused Bash 3.2 behavioral checks for scripts claiming macOS + `/bin/bash` compatibility, including `set -u` empty-array behavior. Do not + impose the entire Linux release-tool suite on Bash 3.2. Syntax checks do not + replace actual Apple transport or publication-path behavior. 6. Declare runner capabilities on the narrowest Moon task that needs them. Use `requires-rust` for Cargo, rustc, rustfmt, or another Rust-toolchain command; `requires-maintainer-tools` for the pinned tools installed by `tools/dev/bootstrap-tools.sh`; and `requires-android-sdk` for Android SDK work. - Use `requires-apple` for Swift, Xcode, or Apple-platform work. + Use `requires-swift` for the portable Swift compiler; add `requires-apple` + only for Xcode, Apple frameworks, simulators or other Apple-only work. + Portable Swift source checks use the pinned Linux Swift setup. Capabilities propagate through task dependencies. The planner keeps capability-bearing checks grouped only with tasks requiring the same setup. 7. Treat a hosted runner-image pin as a toolchain dependency. Never introduce a mutable `*-latest` alias; after changing an explicit runner pin, inspect the image delta and run the platform binary contract for every affected release target. @@ -108,30 +115,35 @@ For a WASIX Docker, APT snapshot, or bootstrap trust change, also run the product-owned fault test and source verifier before the expensive build: ```sh -bash src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.test.sh -tools/dev/bun.sh src/sources/tools/fetch-sources.mjs wasix-runtime --verify-only -cargo run -p xtask -- assets source-spine --strict-local +bash src/third-party/tools/fetch-sources.sh wasix-runtime --verify-only +moon run liboliphaunt-wasix:build-orchestration-test liboliphaunt-wasix:test ``` -Then build the pinned Dockerfile from a clean builder context. Require a +Then use `liboliphaunt-wasix:compiler-output`, `runtime-portable` and +`runtime-aot` for the actual selected producer proof. Optional PostgreSQL tools +and extensions have separate owner producers; do not restore those as core +runtime build prerequisites. For a Docker trust change, build the pinned +Dockerfile from a clean builder context. Require a successful TLS-verified snapshot transaction and the exact declared wasixcc, -Clang, and Binaryen versions; a source-spine/static check alone does not prove +Clang, and Binaryen versions; a source/static check alone does not prove that the pinned trust chain still reaches the snapshot service. -For an SDK change, run `moon run sdk-contracts:all`, then run each affected -SDK's `compile`, `unit`, and `package` tasks in one Moon invocation. These tasks -are independent; `package` does not silently rerun source qualification. Set +For an SDK change, run each affected +SDK's relevant source checks, `test`, and `package` tasks in one Moon invocation. +Their declared dependencies remain necessary; `package` does not silently rerun +unrelated source qualification. Set `MOON_BASE` and `MOON_HEAD`, inspect affected SDK projects, and pass the exact targets to `moon run`; a workspace-wide selector also selects non-SDK products. Confirm ownership with `moon query tasks --project ` when changing task topology. Never replace the product task with a narrower native command: -for example, `cargo test -p oliphaunt --lib` excludes Rust executable tests under -`src/bin/**`, while `moon run oliphaunt-rust:unit` includes the library, -executable, integration, build-crate, and documentation tests. Add -the product's `qualify` task when the complete product replay is needed, and run -`moon run extensions:lint extensions:unit` when an extension catalog or generated SDK +for example, `cargo test -p oliphaunt --lib` omits other Cargo targets selected +by the owner task. Carrier producers copy the canonical C header; real consumers +compile against it instead of running a separate layout gate. Add +the product's explicit runtime or installed-host tests when that proof is needed, and run +`moon run extensions:lint extensions:test` when an extension catalog or generated SDK extension surface changes. Put new guarantees in a parsed schema/generated -contract, clean-consumer package check, or product-owned behavioral test. Do +contract where consumers require one, a clean-consumer package check, or a +product-owned behavioral test. Do not qualify SDK behavior by grepping prose, test names, or implementation-source spellings. @@ -153,10 +165,10 @@ implementation-source spellings. the final `main` SHA. Do not also create a push run: non-PR runs for the same SHA serialize rather than cancel one another. - The release prerequisite is the non-cancelled `Qualified` gate for that SHA, including required checks, builds, policy, tests, and selected E2E. -- When WASIX or an extension is selected, require the same-run full lifecycle evidence artifact. It must cover every catalogued extension in direct, server, restart, materialization, and dump/restore modes and satisfy `--require-current-evidence` for the candidate source digest. +- When WASIX or an extension is selected, require the same-run full lifecycle evidence artifact. It must cover every catalogued extension in direct, server, restart, materialization, and physical backup/restore modes and satisfy `--require-current-evidence` for the candidate source digest. - Ensure artifact attestations and the publication lock reference the same SHA/tree. - Require artifact evidence for the compatibility floors in - `docs/maintainers/release.md`: inspect Mach-O load commands, Android API/ELF + `src/docs/maintainers/release.md`: inspect Mach-O load commands, Android API/ELF metadata, and Linux ELF symbol versions rather than inferring support from a runner or package label. - Do not rerun duplicate downstream E2E workflows when the same evidence is already part of the required gate. diff --git a/.codex/skills/release-oliphaunt/SKILL.md b/.codex/skills/release-oliphaunt/SKILL.md index 6ea857fe5..cb79622c4 100644 --- a/.codex/skills/release-oliphaunt/SKILL.md +++ b/.codex/skills/release-oliphaunt/SKILL.md @@ -7,9 +7,33 @@ description: Prepare, audit, bootstrap, publish, verify, or recover Oliphaunt re Treat a release as a frozen, exact-SHA promotion of already-qualified artifacts. Never rebuild binary producer outputs or substitute artifacts. -Dry-run assembles the complete publication candidate once. Normal publish and -bootstrap both install the same explicitly approved candidate and verify its -complete contents against the embedded exhaustive lock. +The `publish` operation prepares the complete candidate once, conditionally +bootstraps missing names, and publishes it. Dependent jobs install the same +immutable candidate and verify its complete contents against the lock. + +Qualification may be exhaustive or selected through CI's +`release_products_json` input with every platform selector at `all`. The +existing candidate record binds product scope, required tasks and exact SHA; +publication rejects a product outside that scope. Generated release PRs and +their main merge derive scope automatically from the actual manifest transition; +only main push or eligible main dispatch can produce publishable evidence. +Publication first reuses covering completed CI or awaits an active main/requested +run. If none exists, a separate dispatch-only job requests CI for the selected +products, provided main still equals the exact candidate SHA. Failed causal +runs stop with their URL; resume by rerunning that run. An ambiguous dispatch +is never retried automatically. Cross-commit binary reuse remains pending. + +Local checks use `bash tools/release/release-check.sh` for source +metadata/release-tool tests and `bash tools/release/release-check-registries.sh +--products-json JSON --head-ref REF` for selected registry state. These commands +do not publish or assemble a release candidate; test fixtures may create local +packages. Product rehearsal uses the selected owners' package and artifact/consumer +tasks. Candidate preparation runs on Ubuntu, consuming qualified outputs without +product compilers. Publication uses macOS for its actual public Swift consumer, +not for portable release metadata. Candidate preparation verifies qualification once, +checks registry state once, and checks that the source is still clean at its +exact SHA immediately before assembly. Publication retains its live registry +recheck at the mutation boundary. Select release products and versions from the publication catalog and product-local metadata. PostgreSQL 18 contrib SQL members belong to the logical @@ -22,23 +46,45 @@ and do not treat target/ecosystem carriers as additional products. ## Start -1. Read `docs/maintainers/release.md` and `references/invariants.md`. +1. Read `src/docs/maintainers/release.md` and `references/invariants.md`. 2. For registry/GitHub setup, identity bootstrap, or trusted-publisher work, - also read `docs/maintainers/release-setup.md`. + also read `src/docs/maintainers/release-setup.md`. 3. For a failed or partially public release, also read `references/recovery.md` before changing state. 4. Record the candidate commit with `git rev-parse HEAD`; keep that SHA unchanged through qualification, lock creation, publish, and any retry. A - later commit cannot control or finish this release. + product change requires fresh qualification. A narrowly permitted + publication-only controller fix may reuse the unchanged approved candidate. 5. Inspect `git status`, product versions, existing product tags/releases, registry identities, and the latest exact-SHA CI run. Report any public collision before attempting a mutation. -6. Run `tools/dev/bun.sh tools/release/audit-github-release-controls.mjs` with the truthful credential lifecycle before any external mutation. Use `--governance solo --bootstrap-state idle` for qualification, release-PR preparation, and dry-run while bootstrap tokens are absent. Rerun with `--bootstrap-state ready` only for an imminent first-identity bootstrap after every reviewed short-lived token required by the approved lock is installed (one registry or both). If exact inventory proves that all selected Cargo/npm identities already match, keep the credential lifecycle `idle` and provision neither token. Use `retired` after trusted publishers are configured and every provisioned token is revoked. Select `team` only with an independent maintainer. Treat `FAIL` as a blocker; report but do not promote `WARN` to a solo-release blocker. -7. Generate trusted-publisher work from the approved publication lock with `tools/dev/bun.sh tools/release/trusted-publisher-config.mjs`. Its default mode is offline/read-only. Use authenticated `--audit` before considering `--apply`; mutation additionally requires the exact printed lock digest. Run npm audit and apply directly in a terminal because each classification pass starts with a discarded read-only TTY authentication warm-up before the bounded captured reads, and supply a fresh `--output` path for the atomically created mode-`0600` JSON evidence. Configure the direct workflow `release.yml` and `release-publish` environment. Keep release credentials only in their protected environments; do not add repository-level copies or a reusable-workflow secret bridge. +6. Use `bash tools/dev/bun.sh tools/release/audit-github-release-controls.mts` + for release setup and before public registry/tag/asset mutation, with the + truthful credential lifecycle. It is not a gate for ordinary branch pushes, + release-PR preparation or CI qualification: those jobs do not receive the + protected `release-bootstrap` secrets. Record unrelated setup findings + without stopping source work or changing credentials. For publication, use + `--governance solo --bootstrap-state idle` only when bootstrap tokens are + absent. Use `ready` only for imminent first-identity bootstrap after every + reviewed short-lived token required by the approved lock is installed. + Provision neither token when the exact scope needs neither registry; use + `retired` after trusted publishers are configured and provisioned tokens + revoked. Select `team` only with an independent maintainer. Release-safety + `FAIL` findings block the affected public mutation; `WARN` does not become a + solo-release blocker. The bootstrap job still checks required credentials + against the approved lock immediately before it publishes. +7. Generate trusted-publisher work from the approved publication lock with `bash tools/release/trusted-publisher-config.sh`. Its default mode is offline/read-only. Use authenticated `--audit` before considering `--apply`; mutation additionally requires the exact printed lock digest. Run npm audit and apply directly in a terminal because each classification pass starts with a discarded read-only TTY authentication warm-up before the bounded captured reads, and supply a fresh `--output` path for the atomically created mode-`0600` JSON evidence. Configure the direct workflow `release.yml` and `release-publish` environment. Keep release credentials only in their protected environments; do not add repository-level copies or a reusable-workflow secret bridge. 8. On a generated release PR, treat Release Please as the candidate authority - and `sync-release-pr.mjs` as the deterministic selected-candidate metadata - closer. It may add a shared-source candidate only when the same source bytes - are bundled by multiple products; it never creates a downstream release from - a Moon dependency edge. Before preparation, require - `release-please-pr-lifecycle.mjs assert-clean` to report no merged `main` PR - still pending. Before bootstrap or normal publication mutates public state, + and `sync-release-pr.mts` as the deterministic selected-candidate metadata + closer. The pinned Release Please library selects shared-contrib candidates + through the declared release-ownership graph; sync chooses no new versions + or changelogs. Ordinary task dependencies are not automatic release bumps. + In an isolated clean checkout, `bash tools/release/prepare-release-pr.sh OUTPUT_DIR` + generates locally. If `OUTPUT_DIR/required` is `true`, + `bash tools/release/close-release-candidate.sh OUTPUT_DIR` commits locally, + closes manifests and locks, and verifies the candidate. These commands read + GitHub metadata but do not push. Only the workflow + `.github/scripts/publish-release-pr.sh OUTPUT_DIR` mutates the remote PR, + after local validation succeeds. The preparation entrypoint already checks + that no merged `main` release PR is still pending; do not repeat that check + as a separate preparation phase. Before bootstrap or normal publication mutates public state, require `assert-markable` for the exact release SHA. Reassert it immediately before promotion; after promotion, require the exact release PR to be `autorelease: tagged` with `autorelease: pending` absent. @@ -53,9 +99,9 @@ release-PR mutation to finish before starting another. Treat `.github/workflows/release.yml` as the sole release workflow. Its credential-bearing jobs directly select their protected environments. Bootstrap and normal recovery rerun the original failed workflow run at the -exact same release commit and approved dry-run ID. +same release commit and frozen candidate. -A root `publish-bootstrap` or `publish` dispatch must run from the qualified +A root `publish` dispatch must run from the qualified current `main` commit. At the mutation boundary the transport helper first reads `oliphaunt-release-transport/` and accepts only a lightweight direct-commit tag at that exact SHA. When the tag is absent, or the root is on @@ -75,8 +121,9 @@ the root bootstrap job can create this transport tag and must not be used for another repository mutation. - Prepare: synchronize release-owned files, run release checks, create the generated release PR, and stop for review. -- Bootstrap: use the dedicated bootstrap environment only for identities that cannot use trusted publishing until their first package exists, including generated part identities introduced by a future lock. For npm, require a short-lived granular token with explicit `@oliphaunt` scope selection, Packages and scopes `Read and write`, and 2FA bypass, owned by a 2FA-enabled actor with scope write access; an ordinary token can authenticate yet fail the noninteractive publish with `EOTP`. Require one successful exact-SHA dry-run containing both `oliphaunt-publication-lock` and `oliphaunt-publication-candidate`; supply that run ID and publish only its frozen Cargo/npm bytes without rebuilding. Inventory the exact lock first and freeze only wholly absent names into the carrier-level bootstrap ledger; leave existing names awaiting the locked version for normal trusted publication. Provision only the registry token required by that scope. On rerun, a scoped name that exists without the exact version is a conflict. Model crates.io's documented token bucket; never accept an unverifiable numeric capacity assertion. Execute one sequential Cargo lane and one sequential npm lane, overlap only independent carriers, and preserve dependencies within the absent-name scope. A scoped npm package may leave an optional dependency on an existing name to the normal trusted-publication graph; other unavailable locked dependencies fail closed. If one hosted job cannot finish, drain in-flight uploads, reconcile receipts, upload the canonical hash-chained checkpoint, and fail as incomplete with the exact manual rerun command and not-before time. The maintainer reruns the failed job of that original workflow run; the rerun restores only the same release/lock/candidate identity and skips byte-matching public versions. A valid `429 Retry-After` may defer; ambiguous uploads, timeouts, integrity mismatches, malformed responses, and checkpoint failures remain hard failures. After every scoped identity has a receipt, use that exact lock with `tools/release/trusted-publisher-config.mjs`: its default plan has no network access, `--audit` is read-only, and mutation requires both `--apply` and the exact `--confirm-lock-digest`. Run npm audit/apply in a real TTY and retain each fresh `--output` JSON report, never the discarded authentication warm-up display. Require workflow `release.yml`, environment `release-publish`, and npm publish-only permission; reject extra or mismatched configurations. Revoke long-lived credentials, then resume normal publish. -- Publish: require a successful exact-SHA `Qualified` gate, complete artifact +- Bootstrap: use the dedicated bootstrap environment only for identities that cannot use trusted publishing until their first package exists, including generated part identities introduced by a future lock. For npm, require a short-lived granular token with explicit `@oliphaunt` scope selection, Packages and scopes `Read and write`, and 2FA bypass, owned by a 2FA-enabled actor with scope write access; an ordinary token can authenticate yet fail the noninteractive publish with `EOTP`. The `publish` operation prepares `oliphaunt-publication-lock` and `oliphaunt-publication-candidate` first, then passes immutable artifact IDs to this conditional job. Publish only those frozen Cargo/npm bytes without rebuilding. Inventory the exact lock first and freeze only wholly absent names into the carrier-level bootstrap ledger; leave existing names awaiting the locked version for normal trusted publication. Provision only the registry token required by that scope. On rerun, a scoped name that exists without the exact version is a conflict. Model crates.io's documented token bucket; never accept an unverifiable numeric capacity assertion. Execute one sequential Cargo lane and one sequential npm lane, overlap only independent carriers, and preserve dependencies within the absent-name scope. A scoped npm package may leave an optional dependency on an existing name to the normal trusted-publication graph; other unavailable locked dependencies fail closed. If one hosted job cannot finish, drain in-flight uploads, reconcile receipts, upload the canonical hash-chained checkpoint, and fail as incomplete with the exact manual rerun command and not-before time. The maintainer reruns the failed job of that original workflow run; the rerun restores only the same release/lock/candidate identity and skips byte-matching public versions. A valid `429 Retry-After` may defer; ambiguous uploads, timeouts, integrity mismatches, malformed responses, and checkpoint failures remain hard failures. After every scoped identity has a receipt, use that exact lock with `tools/release/trusted-publisher-config.sh`: its default plan has no network access, `--audit` is read-only, and mutation requires both `--apply` and the exact `--confirm-lock-digest`. Run npm audit/apply in a real TTY and retain each fresh `--output` JSON report, never the discarded authentication warm-up display. Require workflow `release.yml`, environment `release-publish`, and npm publish-only permission; reject extra or mismatched configurations. Publication continues automatically. Configure trusted publishers and revoke bootstrap credentials before the next release. +- Publish: prepare the frozen candidate, bootstrap absent Cargo/npm names if + needed, then publish in the same run. Require a successful exact-SHA `Qualified` gate, complete artifact set, frozen publication lock, and exact Release Please PR markability proof. Pin the immutable transport, stage GitHub drafts/assets/attestations, attempt the complete dependency-ordered registry plan once, verify public consumers, @@ -94,8 +141,10 @@ another repository mutation. GitHub's rerun for the original failed Release run, not a fresh dispatch after `main` moves; the original run and referenced artifacts must still be available. Prove and skip matching immutable state; publish only - what remains absent. A required code fix creates a new candidate and follows - normal versioning. Bootstrap uses the same manual rerun rule and its + what remains absent. Product fixes require a new candidate and normal + versioning. A publication-only fix may dispatch `publish` with the original + `release_commit` and `approval_run_id`; the previous run must have completed + with a successful candidate preparation job (or a successful legacy dry-run). Bootstrap uses the same manual rerun rule and its lock-bound checkpoint chain. ## Local gates @@ -106,19 +155,19 @@ producer code, require the product-owned portable/AOT build and runtime checks. Run these from the repository root: ```sh -tools/dev/bun.sh tools/release/release-check.mjs -cargo run -p xtask -- assets verify-committed -tools/dev/bun.sh src/extensions/tools/check-extension-model.mjs --check +bash tools/release/release-check.sh +bash src/extensions/tools/check-extension-model.sh --check ``` -Release Please selects direct candidates from configured product paths. Review -that selection against the shipped behavior; if shared code changes bytes for a -product outside the selected paths, move or represent the change under the -owner before releasing. Do not add repository-meta fingerprints to force a -candidate. +Release Please selects direct candidates from configured product paths. The +ownership plugin also supplies commits affecting declared shared shipped sources, +bounded by each product's published history. Review that selection against the +actual changed behavior; correct missing ownership in the graph rather than +copying source or adding repository-meta fingerprints to force a candidate. -For a normalized generated release PR, Moon edges affect qualification, not -candidate selection. Native, WASIX, SDKs, bindings, and external extensions are +For a normalized generated release PR, ordinary Moon task dependencies affect +qualification; declared release ownership controls shared-source candidate +selection. Native, WASIX, SDKs, bindings, resources, tools and external extensions are independently versioned. Sync updates compatibility pins only for consumers already selected by Release Please, using the dependency versions qualified at that commit; unselected consumers retain their older published pins. A selected @@ -126,13 +175,13 @@ consumer's dependency must be selected at the exact pinned version or already published with matching tag and carrier bytes. ```sh -tools/dev/bun.sh tools/release/sync-release-pr.mjs -tools/dev/bun.sh tools/release/sync-release-pr.mjs --check +bash tools/release/sync-release-pr.sh +bash tools/release/sync-release-pr.sh --check ``` -Use the protected `publish-dry-run` operation to assemble carriers once and -create, freeze, and verify the complete publication candidate from exact-SHA -artifacts. Preserve its run ID for bootstrap and normal publish. +Use `publish` to prepare and freeze the complete candidate from exact-SHA +artifacts, bootstrap absent names if needed, and publish in the same run. The +operator supplies a prior candidate run ID only for recovery. The committed extension evidence table may say `requires-exact-candidate-ci`; that is an honest pre-qualification state, not permission to skip the lane. The selected CI run must provide the current evidence artifact. Do not use `--allow-dirty` for release evidence. Do not publish from a local rebuild, a different workflow run, a branch name, or a moving ref. diff --git a/.codex/skills/release-oliphaunt/references/invariants.md b/.codex/skills/release-oliphaunt/references/invariants.md index 38739a501..a7d513ad3 100644 --- a/.codex/skills/release-oliphaunt/references/invariants.md +++ b/.codex/skills/release-oliphaunt/references/invariants.md @@ -8,17 +8,19 @@ distribution is not an independently versioned release product. External extensions own independent packaging SemVer and record their upstream version/commit separately. -- The generated release-bump commit, qualified workflow head, artifact - attestations, publication lock source SHA/tree, product tags, and every retry - agree exactly. A later commit cannot control or finish the release. +- The generated release-bump commit, qualified source SHA/tree, publication + lock, product tags, and package bytes agree exactly. An explicitly approved + publication-only controller fix may use a later workflow SHA; attestations + record that publishing identity separately. - Extension evidence runs are immutable observations. Claim regeneration never changes them, and current WASIX support is qualified only by the full lifecycle collector running against same-workflow exact-SHA artifacts and recording that commit/tree/run identity. - The publication lock is exhaustive: reject undeclared and missing packages/assets as well as hash, size, dependency, target, or version drift. -- Release Please selects direct candidates from configured product paths. - Shared byte producers must live in, or be represented by, every product whose - shipped behavior they change. Do not create repository-meta fingerprints to - force selection. -- Dry-run generates the lock after complete artifact assembly and freezes every - locked file in one approved candidate. Bootstrap and normal publish install +- Release Please selects direct candidates from configured product paths and + receives shared shipped-source commits from the declared release-ownership + graph, bounded by each product's published history. Ordinary task dependency + edges alone do not bump consumers. Correct missing ownership instead of copying + source or creating repository-meta fingerprints to force selection. +- The preparation job generates the lock after artifact assembly and freezes + every locked file in one candidate. Bootstrap and normal publish install that same candidate; they never rebuild it. Preserve its approval identity, lock, and ledger. - Publish leaves/parts before aggregators, target carriers before façades, runtime artifacts before SDKs, and packages before public GitHub release promotion. diff --git a/.codex/skills/release-oliphaunt/references/recovery.md b/.codex/skills/release-oliphaunt/references/recovery.md index b6fc937af..b1cb5aa87 100644 --- a/.codex/skills/release-oliphaunt/references/recovery.md +++ b/.codex/skills/release-oliphaunt/references/recovery.md @@ -9,9 +9,10 @@ link. Confirm the source SHA/tree, lock/catalog digests, package envelope, and selected products are unchanged. Never hand-edit or truncate the chain. 3. Query every expected identity and GitHub tag/release. Classify it as absent, present-and-byte-matching, or conflicting. An existence-only response is not matching evidence. -4. Do not modify the release commit. A required code or configuration fix - creates a new version, source commit, and qualification. Never attach an old - lock, artifacts, or ledger to a newer commit. +4. Keep the candidate source and bytes unchanged. Product or packaging fixes + require a new candidate and qualification. For a publication-only fix, the + controller allowlist may authorize a new current-main workflow to publish + the original candidate using explicit `release_commit` and `approval_run_id`. 5. For normal publication, use GitHub's rerun on the original Release run; it re-inventories the complete lock and publishes only identities still absent after byte verification. For bootstrap, use the failed job's reported rerun @@ -27,11 +28,13 @@ Normal recovery is an exact-commit rerun, not a new recovery commit: 1. Use GitHub's rerun for the original failed root `publish` run at the same release commit and approved publication candidate. Do not create a fresh - dispatch after `main` moves. The original run and every referenced dry-run + dispatch after `main` moves. The original run and every referenced candidate artifact must remain available. 2. Re-inventory every selected Cargo/npm/Maven identity and GitHub tag/release/asset. Skip an existing item only after its bytes and metadata match the lock. 3. Publish or stage only missing state. Any mismatch stops the release. -4. A later commit cannot finish the release. If a code fix is required, create - a new release candidate and follow normal versioning and qualification. +4. For a publication-only controller fix, dispatch `publish` with the original + source SHA and candidate run ID. A failed prior run is accepted only if its + candidate preparation job succeeded; active or cancelled runs are rejected. + Product, packaging, CI, or lockfile changes require fresh qualification. diff --git a/.github/actions/collect-ci-summary/action.yml b/.github/actions/collect-ci-summary/action.yml index 4586fd342..0fcacf360 100644 --- a/.github/actions/collect-ci-summary/action.yml +++ b/.github/actions/collect-ci-summary/action.yml @@ -12,5 +12,5 @@ runs: echo echo "- Moon projects: \`moon query projects\`" echo "- Moon tasks: \`moon query tasks\`" - echo "- Release plan: \`tools/dev/bun.sh tools/release/release_plan.mjs --from-product-tags --head-ref \`" + echo "- Release plan: \`bash tools/release/release-plan.sh --from-product-tags --head-ref \`" } >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/actions/setup-android/action.yml b/.github/actions/setup-android/action.yml index 313cdbf50..f2231e44a 100644 --- a/.github/actions/setup-android/action.yml +++ b/.github/actions/setup-android/action.yml @@ -53,9 +53,9 @@ runs: src/sdks/kotlin/**/*.gradle* src/sdks/kotlin/**/gradle-wrapper.properties src/sdks/kotlin/**/libs.versions.toml - examples/react-native-expo/package.json + src/examples/react-native-expo/package.json src/sdks/react-native/package.json - pnpm-lock.yaml + bun.lock - name: Set up Java without Gradle cache if: ${{ inputs.gradle-cache != 'true' || inputs.gradle-cache-save-if != 'true' }} @@ -71,7 +71,7 @@ runs: path: | ~/.gradle/caches ~/.gradle/wrapper - key: setup-java-${{ runner.os }}-${{ runner.arch == 'X64' && 'x64' || runner.arch == 'ARM64' && 'arm64' || runner.arch }}-gradle-${{ hashFiles('src/sdks/kotlin/**/*.gradle*', 'src/sdks/kotlin/**/gradle-wrapper.properties', 'src/sdks/kotlin/**/libs.versions.toml', 'examples/react-native-expo/package.json', 'src/sdks/react-native/package.json', 'pnpm-lock.yaml') }} + key: setup-java-${{ runner.os }}-${{ runner.arch == 'X64' && 'x64' || runner.arch == 'ARM64' && 'arm64' || runner.arch }}-gradle-${{ hashFiles('src/sdks/kotlin/**/*.gradle*', 'src/sdks/kotlin/**/gradle-wrapper.properties', 'src/sdks/kotlin/**/libs.versions.toml', 'src/examples/react-native-expo/package.json', 'src/sdks/react-native/package.json', 'bun.lock') }} - name: Prepare native Android ccache directory if: ${{ inputs.native-ccache == 'true' }} diff --git a/.github/actions/setup-apple/action.yml b/.github/actions/setup-apple/action.yml index 042b573fc..85dc139f8 100644 --- a/.github/actions/setup-apple/action.yml +++ b/.github/actions/setup-apple/action.yml @@ -2,6 +2,10 @@ name: Set up Apple description: Select and verify the supported Xcode toolchain for Apple SDK jobs. inputs: + install-build-dependencies: + description: Install PostgreSQL build utilities when the job compiles the runtime. + required: false + default: "true" xcode-minor: description: Supported Xcode minor version installed on the pinned macOS runner image. required: false @@ -90,24 +94,27 @@ runs: gem --version - name: Install Apple build dependencies + if: ${{ inputs.install-build-dependencies == 'true' }} shell: bash run: | .github/scripts/prepare-macos-homebrew.sh - if ! brew list bison >/dev/null 2>&1; then - installed=0 - for attempt in 1 2 3; do - if HOMEBREW_NO_AUTO_UPDATE=1 brew install bison; then - installed=1 - break - fi - if [ "$attempt" -lt 3 ]; then - sleep $((attempt * 15)) + for formula in bison coreutils; do + if ! brew list "$formula" >/dev/null 2>&1; then + installed=0 + for attempt in 1 2 3; do + if HOMEBREW_NO_AUTO_UPDATE=1 brew install "$formula"; then + installed=1 + break + fi + if [ "$attempt" -lt 3 ]; then + sleep $((attempt * 15)) + fi + done + if [ "$installed" != "1" ]; then + echo "setup-apple: Homebrew failed to install $formula after 3 attempts" >&2 + exit 1 fi - done - if [ "$installed" != "1" ]; then - echo "setup-apple: Homebrew failed to install bison after 3 attempts" >&2 - exit 1 fi - fi + done bison_prefix="$(brew --prefix bison)" "$bison_prefix/bin/bison" --version | head -n 1 diff --git a/.github/actions/setup-bun/action.yml b/.github/actions/setup-bun/action.yml index 1e58243dd..9ceab5727 100644 --- a/.github/actions/setup-bun/action.yml +++ b/.github/actions/setup-bun/action.yml @@ -1,12 +1,6 @@ name: Set up Bun description: Install the pinned Bun toolchain for TypeScript npm consumer checks. -inputs: - bun-version: - description: Bun version. - required: false - default: "1.3.14" - outputs: execution-envelope: description: Absolute digest-verified Bun execution envelope. @@ -19,11 +13,10 @@ runs: id: install shell: bash env: - BUN_VERSION_INPUT: ${{ inputs.bun-version }} OLIPHAUNT_PINNED_TOOL_CACHE_ROOT: ${{ runner.temp }}/oliphaunt-pinned-tools run: | # zizmor: ignore[github-env] the installer returns a digest- and version-verified runner-temp path. set -euo pipefail - binary="$(tools/dev/install-pinned-js-runtime.sh bun --expected-version "$BUN_VERSION_INPUT")" + binary="$(tools/dev/install-pinned-js-runtime.sh bun)" binary_dir="$(dirname "$binary")" execution_envelope="$(cd "$binary_dir/.." && pwd -P)" output_envelope="$execution_envelope" diff --git a/.github/actions/setup-moon/action.yml b/.github/actions/setup-moon/action.yml index 182f7851d..923b8993d 100644 --- a/.github/actions/setup-moon/action.yml +++ b/.github/actions/setup-moon/action.yml @@ -1,20 +1,15 @@ name: Set up Moon -description: Install verified Node.js, Moon, pnpm, and Bun binaries and optionally hydrate JavaScript workspace dependencies. +description: Install verified Node.js, Moon, and Bun binaries and optionally hydrate JavaScript workspace dependencies. inputs: install-workspace: - description: Install pnpm workspace dependencies for JavaScript-family tasks. + description: Install Bun workspace dependencies for JavaScript-family tasks. required: false default: "false" runs: using: composite steps: - - name: Set up exact Node.js - uses: ./.github/actions/setup-node-runtime - with: - node-version: "22.22.3" - - name: Restore verified tool archives id: restore_verified_moon_toolchain uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 @@ -22,9 +17,12 @@ runs: path: | ${{ runner.temp }}/oliphaunt-moon-toolchain ${{ runner.temp }}/oliphaunt-pinned-tools - key: verified-moon-toolchain-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.moon/toolchains.yml', '.github/actions/setup-moon/action.yml', '.github/actions/setup-moon/install-pinned-toolchain.sh', '.github/actions/setup-moon/toolchain-archive.py', 'src/sources/toolchains/moon-cli.toml', 'src/sources/toolchains/moon-plugins.toml', 'src/sources/toolchains/pnpm.toml', 'src/sources/toolchains/proto.toml', 'src/sources/toolchains/bun.toml', 'tools/dev/install-pinned-js-runtime.sh', 'tools/dev/extract-pinned-zip.sh', 'tools/dev/curl-platform-flags.sh') }} + key: verified-moon-toolchain-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.moon/toolchains.yml', '.github/actions/setup-moon/action.yml', '.github/actions/setup-node-bun/action.yml', '.github/actions/setup-moon/install-pinned-toolchain.sh', '.github/actions/setup-moon/toolchain-archive.mts', 'tools/dev/moon-cli.toml', 'tools/dev/moon-plugins.toml', 'tools/dev/proto.toml', 'tools/dev/bun.toml', 'tools/dev/install-pinned-js-runtime.sh', 'tools/dev/extract-pinned-zip.sh', 'tools/packaging/portable-archive.mts', 'tools/dev/extract-pinned-binary.sh', 'tools/dev/curl-platform-flags.sh') }} + + - name: Set up exact Node.js and Bun + uses: ./.github/actions/setup-node-bun - - name: Install verified Moon and pnpm + - name: Install verified Moon shell: bash env: OLIPHAUNT_MOON_TOOLCHAIN_CACHE_ROOT: ${{ runner.temp }}/oliphaunt-moon-toolchain @@ -48,66 +46,57 @@ runs: command -v cygpath >/dev/null 2>&1 toolchain_bin="$(cygpath -w "$toolchain_bin")" moon_bin="$(cygpath -w "${moon_bin}.exe")" + # Native executables do not inherit Git Bash's virtual /usr/bin + # lookup. Keep their bare `bash` commands away from System32's WSL + # launcher. Git's bin directory has no competing GNU link.exe. + git_root="$(cygpath -w /)" + git_bin="${git_root%\\}\\bin" + [[ -x "$(cygpath -u "$git_bin")/bash.exe" ]] + echo "$git_bin" >> "$GITHUB_PATH" fi echo "$toolchain_bin" >> "$GITHUB_PATH" echo "MOON_HOME=$moon_home_env" >> "$GITHUB_ENV" echo "MOON_BIN=$moon_bin" >> "$GITHUB_ENV" - echo "MOON_TOOLCHAIN_FORCE_GLOBALS=true" >> "$GITHUB_ENV" - - - name: Install verified Bun - shell: bash - env: - OLIPHAUNT_PINNED_TOOL_CACHE_ROOT: ${{ runner.temp }}/oliphaunt-pinned-tools - run: | # zizmor: ignore[github-env] the installer returns a digest- and version-verified runner-temp path. - set -euo pipefail - binary="$(bash tools/dev/install-pinned-js-runtime.sh bun --expected-version 1.3.14)" - export_dir="$RUNNER_TEMP/oliphaunt-bun-path" - export_dir_fs="$export_dir" - github_path_entry="$export_dir" - if [[ "${RUNNER_OS:-}" == "Windows" ]]; then - command -v cygpath >/dev/null 2>&1 - export_dir_fs="$(cygpath -u "$export_dir")" - github_path_entry="$(cygpath -w "$export_dir_fs")" - fi - rm -rf "$export_dir_fs" - mkdir -p "$export_dir_fs" - cp "$binary" "$export_dir_fs/$(basename "$binary")" - chmod 0555 "$export_dir_fs/$(basename "$binary")" - echo "$github_path_entry" >> "$GITHUB_PATH" + # List every configured plugin to keep verified global tools while Moon + # still injects a child PATH. With `true`, Rust searches System32 before + # inherited PATH on Windows and launches WSL's bash.exe. + echo "MOON_TOOLCHAIN_FORCE_GLOBALS=javascript,node,bun,rust" >> "$GITHUB_ENV" - name: Verify toolchain shell: bash run: | set -euo pipefail - [[ "$(moon --version)" == "moon 2.5.4" ]] - [[ "$(node --version)" == "v22.22.3" ]] - [[ "$(pnpm --version)" == "11.5.0" ]] - [[ "$(bun --version)" == "1.3.14" ]] + moon --version + node --version + bun --version + # This shell probe needs no source comparison or fetched base branch. + .github/scripts/run-moon-targets.sh --base HEAD --head HEAD ci-workflows:verify-bash - name: Save verified tool archives - if: ${{ env.HEAVY_CACHE_SAVE_IF == 'true' && steps.restore_verified_moon_toolchain.outputs.cache-hit != 'true' }} + if: ${{ steps.restore_verified_moon_toolchain.outputs.cache-hit != 'true' }} continue-on-error: true uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: path: | ${{ runner.temp }}/oliphaunt-moon-toolchain ${{ runner.temp }}/oliphaunt-pinned-tools - key: verified-moon-toolchain-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.moon/toolchains.yml', '.github/actions/setup-moon/action.yml', '.github/actions/setup-moon/install-pinned-toolchain.sh', '.github/actions/setup-moon/toolchain-archive.py', 'src/sources/toolchains/moon-cli.toml', 'src/sources/toolchains/moon-plugins.toml', 'src/sources/toolchains/pnpm.toml', 'src/sources/toolchains/proto.toml', 'src/sources/toolchains/bun.toml', 'tools/dev/install-pinned-js-runtime.sh', 'tools/dev/extract-pinned-zip.sh', 'tools/dev/curl-platform-flags.sh') }} + key: verified-moon-toolchain-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.moon/toolchains.yml', '.github/actions/setup-moon/action.yml', '.github/actions/setup-node-bun/action.yml', '.github/actions/setup-moon/install-pinned-toolchain.sh', '.github/actions/setup-moon/toolchain-archive.mts', 'tools/dev/moon-cli.toml', 'tools/dev/moon-plugins.toml', 'tools/dev/proto.toml', 'tools/dev/bun.toml', 'tools/dev/install-pinned-js-runtime.sh', 'tools/dev/extract-pinned-zip.sh', 'tools/packaging/portable-archive.mts', 'tools/dev/extract-pinned-binary.sh', 'tools/dev/curl-platform-flags.sh') }} - name: Install workspace dependencies if: ${{ inputs.install-workspace == 'true' }} shell: bash - run: pnpm install --frozen-lockfile + run: bun install --frozen-lockfile - name: Restore Moon task outputs uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: + # casOutputsCache uses these directories; hashes/ is diagnostic metadata. path: | - .moon/cache/hashes - .moon/cache/outputs - key: moon-task-cache-v1-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}-${{ strategy.job-index }}-${{ hashFiles('.prototools', '.moon/**/*.yml', '**/moon.yml', 'Cargo.lock', 'pnpm-lock.yaml') }}-${{ github.sha }} + .moon/cache/blobs + .moon/cache/manifests + key: moon-task-cache-v2-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}-${{ strategy.job-index }}-${{ hashFiles('.prototools', '.moon/toolchains.yml') }}-${{ github.sha }} restore-keys: | - moon-task-cache-v1-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}-${{ strategy.job-index }}-${{ hashFiles('.prototools', '.moon/**/*.yml', '**/moon.yml', 'Cargo.lock', 'pnpm-lock.yaml') }}- + moon-task-cache-v2-${{ runner.os }}-${{ runner.arch }}-${{ github.job }}-${{ strategy.job-index }}-${{ hashFiles('.prototools', '.moon/toolchains.yml') }}- - name: Hydrate Moon plugins shell: bash diff --git a/.github/actions/setup-moon/install-pinned-node.sh b/.github/actions/setup-moon/install-pinned-node.sh index 94517fd1a..7b9be6984 100755 --- a/.github/actions/setup-moon/install-pinned-node.sh +++ b/.github/actions/setup-moon/install-pinned-node.sh @@ -13,9 +13,9 @@ if [ -z "$root" ]; then fi action_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -manifest="${OLIPHAUNT_NODE_RUNTIME_MANIFEST:-$root/src/sources/toolchains/node-runtime.toml}" +manifest="${OLIPHAUNT_NODE_RUNTIME_MANIFEST:-$root/tools/dev/node-runtime.toml}" proto_file="${OLIPHAUNT_NODE_RUNTIME_PROTO_FILE:-$root/.prototools}" -extractor="${OLIPHAUNT_NODE_RUNTIME_ARCHIVE_EXTRACTOR:-$action_dir/toolchain-archive.py}" +extractor="$action_dir/../../../tools/dev/extract-pinned-binary.sh" curl_platform_flags="$root/tools/dev/curl-platform-flags.sh" cache_root="${OLIPHAUNT_NODE_RUNTIME_CACHE_ROOT:-${RUNNER_TEMP:-$root/target}/oliphaunt-node-runtime}" @@ -34,14 +34,6 @@ done # shellcheck source=tools/dev/curl-platform-flags.sh . "$curl_platform_flags" -python="" -for candidate in python3 python; do - if command -v "$candidate" >/dev/null 2>&1; then - python="$candidate" - break - fi -done -[ -n "$python" ] || fail "python3 or python is required for safe archive extraction" manifest_value() { local section="$1" @@ -96,27 +88,13 @@ sha256_file() { elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | awk '{print $1}' else - "$python" - "$1" <<'PY' -import hashlib -import pathlib -import sys - -digest = hashlib.sha256() -with pathlib.Path(sys.argv[1]).open("rb") as stream: - while block := stream.read(1024 * 1024): - digest.update(block) -print(digest.hexdigest()) -PY + fail "sha256sum or shasum is required" fi } -node_version="$(manifest_value toolchain version)" || - fail "$manifest must contain exactly one quoted toolchain.version" +node_version="$(proto_version)" || fail "$proto_file must contain exactly one node version" +node_version="${node_version#v}" [[ "$node_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "invalid Node.js version: $node_version" -configured="$(proto_version)" || fail "$proto_file must contain exactly one node version" -configured="${configured#v}" -[ "$configured" = "$node_version" ] || - fail "$proto_file node version $configured does not match pinned version $node_version" if [ -n "${OLIPHAUNT_NODE_RUNTIME_TARGET:-}" ]; then [ "${OLIPHAUNT_NODE_RUNTIME_TESTING:-0}" = "1" ] || @@ -267,15 +245,7 @@ trap 'exit 130' INT trap 'exit 143' TERM mkdir -p "$stage/bin" -"$python" "$extractor" extract-file \ - --archive "$archive" \ - --format "$archive_format" \ - --expected-bytes "$archive_bytes" \ - --member "$binary_path" \ - --member-bytes "$binary_bytes" \ - --member-sha256 "$binary_sha256" \ - --destination "$stage/bin/$binary_name" \ - --executable +bash "$extractor" "$archive_format" "$archive" "$binary_path" "$stage/bin/$binary_name" "$binary_sha256" "$binary_bytes" chmod 0555 "$stage/bin/$binary_name" printf '%s\n' "$receipt_text" >"$stage/receipt" chmod 0444 "$stage/receipt" diff --git a/.github/actions/setup-moon/install-pinned-node.test.sh b/.github/actions/setup-moon/install-pinned-node.test.sh index 17203cda5..cc226c37d 100755 --- a/.github/actions/setup-moon/install-pinned-node.test.sh +++ b/.github/actions/setup-moon/install-pinned-node.test.sh @@ -3,7 +3,6 @@ set -euo pipefail root="$(git rev-parse --show-toplevel)" installer="$root/.github/actions/setup-moon/install-pinned-node.sh" -extractor="$root/.github/actions/setup-moon/toolchain-archive.py" work="$(mktemp -d)" trap 'rm -rf "$work"' EXIT @@ -26,9 +25,6 @@ binary_bytes="$(wc -c <"$binary" | tr -d '[:space:]')" binary_sha256="$(sha256sum "$binary" | awk '{print $1}')" cat >"$work/node-runtime.toml" </dev/null 2>&1 || fail "cygpath is required on Windows" - windows_posix=1 cache_root="$(cygpath -u "$cache_root")" ;; esac for path in \ "$moon_manifest" \ - "$pnpm_manifest" \ "$proto_manifest" \ "$plugin_manifest" \ "$proto_file" \ @@ -47,14 +43,7 @@ done # shellcheck source=tools/dev/curl-platform-flags.sh . "$curl_platform_flags" -python="" -for candidate in python3 python; do - if command -v "$candidate" >/dev/null 2>&1; then - python="$candidate" - break - fi -done -[ -n "$python" ] || fail "python3 or python is required for safe archive extraction" +command -v bun >/dev/null 2>&1 || fail "Bun is required; run setup-node-bun first" manifest_value() { local manifest="$1" @@ -123,13 +112,6 @@ validate_digest() { fail "$label must contain exactly 64 lowercase hexadecimal characters" } -validate_sha512() { - local label="$1" - local digest="$2" - [ "${#digest}" -eq 128 ] && [[ ! "$digest" =~ [^0-9a-f] ]] || - fail "$label must contain exactly 128 lowercase hexadecimal characters" -} - validate_count() { local label="$1" local value="$2" @@ -145,61 +127,17 @@ sha256_file() { elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | awk '{print $1}' else - "$python" - "$1" <<'PY' -import hashlib -import pathlib -import sys - -digest = hashlib.sha256() -with pathlib.Path(sys.argv[1]).open("rb") as stream: - while block := stream.read(1024 * 1024): - digest.update(block) -print(digest.hexdigest()) -PY - fi -} - -sha512_file() { - if command -v sha512sum >/dev/null 2>&1; then - sha512sum "$1" | awk '{print $1}' - elif command -v shasum >/dev/null 2>&1; then - shasum -a 512 "$1" | awk '{print $1}' - else - "$python" - "$1" <<'PY' -import hashlib -import pathlib -import sys - -digest = hashlib.sha512() -with pathlib.Path(sys.argv[1]).open("rb") as stream: - while block := stream.read(1024 * 1024): - digest.update(block) -print(digest.hexdigest()) -PY + fail "sha256sum or shasum is required" fi } -moon_version="$(manifest_value "$moon_manifest" toolchain version)" || - fail "$moon_manifest must contain exactly one quoted toolchain.version" -pnpm_version="$(manifest_value "$pnpm_manifest" toolchain version)" || - fail "$pnpm_manifest must contain exactly one quoted toolchain.version" +moon_version="$(prototool_version moon)" || fail "$proto_file must contain exactly one moon version" +moon_version="${moon_version#v}" proto_version="$(manifest_value "$proto_manifest" toolchain version)" || fail "$proto_manifest must contain exactly one quoted toolchain.version" validate_version Moon "$moon_version" -validate_version pnpm "$pnpm_version" validate_version proto "$proto_version" -for tool in moon pnpm; do - configured="$(prototool_version "$tool")" || - fail "$proto_file must contain exactly one $tool version" - configured="${configured#v}" - case "$tool" in - moon) expected="$moon_version" ;; - pnpm) expected="$pnpm_version" ;; - esac - [ "$configured" = "$expected" ] || - fail "$proto_file $tool version $configured does not match pinned version $expected" -done configured_proto="$(moon_proto_version)" || fail "$moon_config must contain exactly one quoted proto.version" configured_proto="${configured_proto#v}" @@ -244,7 +182,6 @@ case "$target" in expected_moon_companion="moonx.exe" expected_moon_entries="5" moon_archive_suffix="zip" - moon_archive_executables=() ;; aarch64-apple-darwin | x86_64-apple-darwin | aarch64-unknown-linux-gnu | x86_64-unknown-linux-gnu) expected_moon_format="tar.xz" @@ -253,7 +190,6 @@ case "$target" in expected_moon_companion="moonx" expected_moon_entries="6" moon_archive_suffix="tar.xz" - moon_archive_executables=("$expected_moon_binary" "$expected_moon_companion") ;; *) fail "unsupported pinned Moon target: $target" ;; esac @@ -271,45 +207,8 @@ for value in "$moon_archive_bytes" "$moon_expanded_bytes" "$moon_entry_count"; d validate_count "$moon_manifest $moon_section count" "$value" done -pnpm_url="$(manifest_value "$pnpm_manifest" package url)" || fail "$pnpm_manifest is missing package.url" -pnpm_archive_sha256="$(manifest_value "$pnpm_manifest" package sha256)" || fail "$pnpm_manifest is missing package.sha256" -pnpm_archive_sha512="$(manifest_value "$pnpm_manifest" package sha512)" || fail "$pnpm_manifest is missing package.sha512" -pnpm_archive_bytes="$(manifest_value "$pnpm_manifest" package bytes)" || fail "$pnpm_manifest is missing package.bytes" -pnpm_expanded_bytes="$(manifest_value "$pnpm_manifest" package expanded_bytes)" || fail "$pnpm_manifest is missing package.expanded_bytes" -pnpm_format="$(manifest_value "$pnpm_manifest" package format)" || fail "$pnpm_manifest is missing package.format" -pnpm_prefix="$(manifest_value "$pnpm_manifest" package prefix)" || fail "$pnpm_manifest is missing package.prefix" -pnpm_entry_count="$(manifest_value "$pnpm_manifest" package entry_count)" || fail "$pnpm_manifest is missing package.entry_count" -pnpm_file_count="$(manifest_value "$pnpm_manifest" package file_count)" || fail "$pnpm_manifest is missing package.file_count" -pnpm_tree_sha256="$(manifest_value "$pnpm_manifest" package tree_sha256)" || fail "$pnpm_manifest is missing package.tree_sha256" -pnpm_executable_paths="$(manifest_value "$pnpm_manifest" package executable_paths)" || fail "$pnpm_manifest is missing package.executable_paths" -pnpm_binary_path="$(manifest_value "$pnpm_manifest" package binary_path)" || fail "$pnpm_manifest is missing package.binary_path" -pnpm_binary_sha256="$(manifest_value "$pnpm_manifest" package binary_sha256)" || fail "$pnpm_manifest is missing package.binary_sha256" -pnpm_companion_path="$(manifest_value "$pnpm_manifest" package companion_path)" || fail "$pnpm_manifest is missing package.companion_path" -pnpm_companion_sha256="$(manifest_value "$pnpm_manifest" package companion_sha256)" || fail "$pnpm_manifest is missing package.companion_sha256" -pnpm_payload_path="$(manifest_value "$pnpm_manifest" package payload_path)" || fail "$pnpm_manifest is missing package.payload_path" -pnpm_payload_sha256="$(manifest_value "$pnpm_manifest" package payload_sha256)" || fail "$pnpm_manifest is missing package.payload_sha256" - -expected_pnpm_url="https://registry.npmjs.org/pnpm/-/pnpm-$pnpm_version.tgz" -[ "$pnpm_url" = "$expected_pnpm_url" ] || fail "$pnpm_manifest package.url must be $expected_pnpm_url" -[ "$pnpm_format" = "tar.gz" ] || fail "$pnpm_manifest package.format must be tar.gz" -[ "$pnpm_prefix" = "package" ] || fail "$pnpm_manifest package.prefix must be package" -[ "$pnpm_binary_path" = "bin/pnpm.mjs" ] || fail "$pnpm_manifest package.binary_path must be bin/pnpm.mjs" -[ "$pnpm_companion_path" = "bin/pnpx.mjs" ] || fail "$pnpm_manifest package.companion_path must be bin/pnpx.mjs" -[ "$pnpm_payload_path" = "dist/pnpm.mjs" ] || fail "$pnpm_manifest package.payload_path must be dist/pnpm.mjs" -expected_pnpm_executable_paths="bin/pnpm.mjs,bin/pnpx.mjs,dist/node-gyp-bin/node-gyp,dist/node-gyp-bin/node-gyp.cmd,dist/node_modules/node-gyp/bin/node-gyp.js" -[ "$pnpm_executable_paths" = "$expected_pnpm_executable_paths" ] || - fail "$pnpm_manifest package.executable_paths must be $expected_pnpm_executable_paths" -IFS=',' read -r -a pnpm_executables <<<"$pnpm_executable_paths" -for digest in "$pnpm_archive_sha256" "$pnpm_tree_sha256" "$pnpm_binary_sha256" "$pnpm_companion_sha256" "$pnpm_payload_sha256"; do - validate_digest "$pnpm_manifest package digest" "$digest" -done -validate_sha512 "$pnpm_manifest package.sha512" "$pnpm_archive_sha512" -for value in "$pnpm_archive_bytes" "$pnpm_expanded_bytes" "$pnpm_entry_count" "$pnpm_file_count"; do - validate_count "$pnpm_manifest package count" "$value" -done - plugin_records=() -for plugin_id in javascript node pnpm rust; do +for plugin_id in javascript node bun rust; do section="plugins.$plugin_id" locator="$(manifest_value "$plugin_manifest" "$section" locator)" || fail "$plugin_manifest is missing $section.locator" repository="$(manifest_value "$plugin_manifest" "$section" repository)" || fail "$plugin_manifest is missing $section.repository" @@ -321,7 +220,7 @@ for plugin_id in javascript node pnpm rust; do case "$plugin_id" in javascript) expected_repository="moonrepo/javascript_toolchain" ;; node) expected_repository="moonrepo/node_toolchain" ;; - pnpm) expected_repository="moonrepo/node_depman_toolchain" ;; + bun) expected_repository="moonrepo/bun_toolchain" ;; rust) expected_repository="moonrepo/rust_toolchain" ;; esac [ "$repository" = "$expected_repository" ] || fail "$plugin_manifest $section.repository must be $expected_repository" @@ -337,7 +236,7 @@ for plugin_id in javascript node pnpm rust; do plugin_records+=("$plugin_id|$repository|$manifest_sha256|$manifest_bytes|$blob_sha256|$blob_bytes|$cache_file") done -for command_name in "${OLIPHAUNT_MOON_CURL:-curl}" mktemp node; do +for command_name in "${OLIPHAUNT_MOON_CURL:-curl}" mktemp bun; do command -v "$command_name" >/dev/null 2>&1 || fail "missing required command: $command_name" done @@ -358,7 +257,7 @@ curl_tls_flag="$(oliphaunt_curl_platform_tls_flag)" curl_common=( --fail --location --silent --show-error --proto '=https' --proto-redir '=https' --tlsv1.2 - --retry 5 --retry-all-errors --retry-connrefused --retry-delay 2 --retry-max-time 300 + --retry 6 --retry-all-errors --retry-connrefused --retry-max-time 300 --connect-timeout 20 --max-time 300 --speed-limit 1024 --speed-time 30 --remove-on-error ) @@ -371,14 +270,11 @@ download_verified() { local expected_sha256="$2" local expected_bytes="$3" local output="$4" - local expected_sha512="${5:-}" - local bearer="${6:-}" - local actual_size + local bearer="${5:-}" if [ -f "$output" ] && [ ! -L "$output" ]; then actual_size="$(wc -c <"$output" | tr -d '[:space:]')" if [ "$actual_size" = "$expected_bytes" ] && - [ "$(sha256_file "$output")" = "$expected_sha256" ] && - { [ -z "$expected_sha512" ] || [ "$(sha512_file "$output")" = "$expected_sha512" ]; }; then + [ "$(sha256_file "$output")" = "$expected_sha256" ]; then return 0 fi fi @@ -407,10 +303,6 @@ download_verified() { rm -f "$partial" fail "downloaded SHA-256 mismatch for $url" } - if [ -n "$expected_sha512" ] && [ "$(sha512_file "$partial")" != "$expected_sha512" ]; then - rm -f "$partial" - fail "downloaded SHA-512 mismatch for $url" - fi chmod 0444 "$partial" mv "$partial" "$output" } @@ -430,20 +322,7 @@ registry_token() { fail "could not obtain a bounded read-only GHCR token for $repository" fi local token - token="$($python - "$response" <<'PY' -import json -import pathlib -import sys - -data = pathlib.Path(sys.argv[1]).read_bytes() -if len(data) > 16384: - raise SystemExit(1) -value = json.loads(data).get("token") -if not isinstance(value, str): - raise SystemExit(1) -print(value) -PY - )" || { + token="$(bun "$extractor" oci-token "$response")" || { rm -f "$response" fail "GHCR returned an invalid token response for $repository" } @@ -492,9 +371,9 @@ download_oci_manifest() { rm -f "$headers" [ "$(wc -c <"$partial" | tr -d '[:space:]')" = "$expected_bytes" ] && [ "$(sha256_file "$partial")" = "$digest" ] || { - rm -f "$partial" - fail "OCI manifest body integrity mismatch for $repository" - } + rm -f "$partial" + fail "OCI manifest body integrity mismatch for $repository" + } chmod 0444 "$partial" mv "$partial" "$output" } @@ -503,28 +382,10 @@ validate_oci_manifest() { local manifest_path="$1" local expected_blob_sha256="$2" local expected_blob_bytes="$3" - "$python" - "$manifest_path" "$expected_blob_sha256" "$expected_blob_bytes" <<'PY' -import json -import pathlib -import sys - -value = json.loads(pathlib.Path(sys.argv[1]).read_bytes()) -expected_digest = f"sha256:{sys.argv[2]}" -expected_size = int(sys.argv[3]) -if value.get("schemaVersion") != 2: - raise SystemExit("OCI manifest schemaVersion must be 2") -if value.get("mediaType") != "application/vnd.oci.image.manifest.v1+json": - raise SystemExit("OCI manifest has the wrong mediaType") -layers = value.get("layers") -if not isinstance(layers, list): - raise SystemExit("OCI manifest layers must be an array") -wasm = [layer for layer in layers if isinstance(layer, dict) and layer.get("mediaType") == "application/wasm"] -if len(wasm) != 1 or wasm[0].get("digest") != expected_digest or wasm[0].get("size") != expected_size: - raise SystemExit("OCI manifest does not bind exactly one expected WASM blob") -PY + bun "$extractor" oci-manifest "$manifest_path" "$expected_blob_sha256" "$expected_blob_bytes" } -identity="moon-$moon_version-pnpm-$pnpm_version" +identity="moon-$moon_version" install_parent="$cache_root/installations/$identity" if [ -L "$cache_root/installations" ] || [ -L "$install_parent" ]; then fail "toolchain installation cache must not contain symbolic-link directories" @@ -534,100 +395,31 @@ final="$install_parent/$target" moon_exe="$expected_moon_binary" moonx_exe="$expected_moon_companion" -receipt_text="$(printf 'moon_version=%s\npnpm_version=%s\nproto_contract_version=%s\ntarget=%s\nmoon_archive_sha256=%s\npnpm_archive_sha256=%s\npnpm_tree_sha256=%s' \ - "$moon_version" \ - "$pnpm_version" \ - "$proto_version" \ - "$target" \ - "$moon_archive_sha256" \ - "$pnpm_archive_sha256" \ - "$pnpm_tree_sha256")" -pnpm_wrapper_text="$(printf '%s\n' \ - '#!/usr/bin/env bash' \ - 'set -euo pipefail' \ - 'script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"' \ - 'cli_path="$script_dir/../pnpm/bin/pnpm.mjs"' \ - 'case "$(uname -s)" in' \ - ' MINGW* | MSYS* | CYGWIN*)' \ - ' command -v cygpath >/dev/null 2>&1 || { echo "pnpm: cygpath is required on Windows" >&2; exit 1; }' \ - ' cli_path="$(cygpath -aw "$cli_path")"' \ - ' ;;' \ - 'esac' \ - 'exec node "$cli_path" "$@"')" -pnpx_wrapper_text="$(printf '%s\n' \ - '#!/usr/bin/env bash' \ - 'set -euo pipefail' \ - 'script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"' \ - 'cli_path="$script_dir/../pnpm/bin/pnpx.mjs"' \ - 'case "$(uname -s)" in' \ - ' MINGW* | MSYS* | CYGWIN*)' \ - ' command -v cygpath >/dev/null 2>&1 || { echo "pnpx: cygpath is required on Windows" >&2; exit 1; }' \ - ' cli_path="$(cygpath -aw "$cli_path")"' \ - ' ;;' \ - 'esac' \ - 'exec node "$cli_path" "$@"')" -pnpm_cmd_text="$(printf '%s\r\n' '@ECHO OFF' 'node "%~dp0..\pnpm\bin\pnpm.mjs" %*')" -pnpx_cmd_text="$(printf '%s\r\n' '@ECHO OFF' 'node "%~dp0..\pnpm\bin\pnpx.mjs" %*')" +receipt_text="$(printf 'moon_version=%s\nproto_contract_version=%s\ntarget=%s\nmoon_archive_sha256=%s' "$moon_version" "$proto_version" "$target" "$moon_archive_sha256")" moon_binary_version() { "$1" --version 2>/dev/null | awk '$1 == "moon" { print $2; exit }' } -pnpm_binary_version() { - local script="$1" - if [ "$windows_posix" = "1" ]; then - script="$(cygpath -aw "$script")" || return 1 - MSYS2_ARG_CONV_EXCL='*' node "$script" --version 2>/dev/null | - awk 'NF { print $1; exit }' - else - node "$script" --version 2>/dev/null | awk 'NF { print $1; exit }' - fi -} - cache_valid() { local candidate="$1" [ -d "$candidate" ] && [ ! -L "$candidate" ] || return 1 - [ "$(find "$candidate" -mindepth 1 -maxdepth 1 | wc -l | tr -d '[:space:]')" = "4" ] || return 1 + [ "$(find "$candidate" -mindepth 1 -maxdepth 1 | wc -l | tr -d '[:space:]')" = "3" ] || return 1 [ -d "$candidate/bin" ] && [ ! -L "$candidate/bin" ] || return 1 - [ -d "$candidate/pnpm" ] && [ ! -L "$candidate/pnpm" ] || return 1 [ -d "$candidate/plugins" ] && [ ! -L "$candidate/plugins" ] || return 1 - [ "$(find "$candidate/bin" -mindepth 1 -maxdepth 1 | wc -l | tr -d '[:space:]')" = "6" ] || return 1 + [ "$(find "$candidate/bin" -mindepth 1 -maxdepth 1 | wc -l | tr -d '[:space:]')" = "2" ] || return 1 for path in \ "$candidate/bin/$moon_exe" \ "$candidate/bin/$moonx_exe" \ - "$candidate/pnpm/$pnpm_binary_path" \ - "$candidate/pnpm/$pnpm_companion_path" \ - "$candidate/pnpm/$pnpm_payload_path" \ - "$candidate/bin/pnpm" \ - "$candidate/bin/pnpx" \ - "$candidate/bin/pnpm.cmd" \ - "$candidate/bin/pnpx.cmd" \ "$candidate/receipt"; do [ -f "$path" ] && [ ! -L "$path" ] || return 1 done [ "$(sha256_file "$candidate/bin/$moon_exe")" = "$moon_binary_sha256" ] || return 1 [ "$(sha256_file "$candidate/bin/$moonx_exe")" = "$moon_companion_sha256" ] || return 1 - [ "$(sha256_file "$candidate/pnpm/$pnpm_binary_path")" = "$pnpm_binary_sha256" ] || return 1 - [ "$(sha256_file "$candidate/pnpm/$pnpm_companion_path")" = "$pnpm_companion_sha256" ] || return 1 - [ "$(sha256_file "$candidate/pnpm/$pnpm_payload_path")" = "$pnpm_payload_sha256" ] || return 1 - [ "$(cat "$candidate/bin/pnpm")" = "$pnpm_wrapper_text" ] || return 1 - [ "$(cat "$candidate/bin/pnpx")" = "$pnpx_wrapper_text" ] || return 1 - [ "$(cat "$candidate/bin/pnpm.cmd")" = "$pnpm_cmd_text" ] || return 1 - [ "$(cat "$candidate/bin/pnpx.cmd")" = "$pnpx_cmd_text" ] || return 1 if [ "$target" != "x86_64-pc-windows-msvc" ]; then [ -x "$candidate/bin/$moon_exe" ] && [ -x "$candidate/bin/$moonx_exe" ] || return 1 - [ -x "$candidate/bin/pnpm" ] && [ -x "$candidate/bin/pnpx" ] || return 1 fi - local tree_result - local tree_args=(tree-digest --root "$candidate/pnpm") - local executable - for executable in "${pnpm_executables[@]}"; do - tree_args+=(--executable "$executable") - done - tree_result="$($python "$extractor" "${tree_args[@]}" 2>/dev/null)" || return 1 - [ "$tree_result" = "$pnpm_file_count $pnpm_tree_sha256" ] || return 1 [ "$(moon_binary_version "$candidate/bin/$moon_exe")" = "$moon_version" ] || return 1 - [ "$(pnpm_binary_version "$candidate/pnpm/$pnpm_binary_path")" = "$pnpm_version" ] || return 1 [ "$(cat "$candidate/receipt")" = "$receipt_text" ] || return 1 local plugin_count=0 for record in "${plugin_records[@]}"; do @@ -647,9 +439,7 @@ if cache_valid "$final"; then fi moon_archive="$archive_root/$moon_archive_sha256.$moon_archive_suffix" -pnpm_archive="$archive_root/$pnpm_archive_sha256.tgz" download_verified "$moon_url" "$moon_archive_sha256" "$moon_archive_bytes" "$moon_archive" -download_verified "$pnpm_url" "$pnpm_archive_sha256" "$pnpm_archive_bytes" "$pnpm_archive" "$pnpm_archive_sha512" for record in "${plugin_records[@]}"; do IFS='|' read -r plugin_id repository manifest_sha256 manifest_bytes blob_sha256 blob_bytes cache_file <<<"$record" @@ -671,7 +461,6 @@ for record in "${plugin_records[@]}"; do "$blob_sha256" \ "$blob_bytes" \ "$blob" \ - "" \ "$token" fi done @@ -698,55 +487,18 @@ trap 'exit 130' INT trap 'exit 143' TERM moon_extract="$stage/moon-extract" -pnpm_extract="$stage/pnpm" -moon_extract_args=( - extract \ - --archive "$moon_archive" \ - --format "$moon_format" \ - --prefix "$moon_prefix" \ - --entry-count "$moon_entry_count" \ - --expected-bytes "$moon_archive_bytes" \ - --expanded-bytes "$moon_expanded_bytes" \ - --destination "$moon_extract" \ - --required "$moon_binary_path" \ - --required "$moon_companion_path" -) -for executable in "${moon_archive_executables[@]}"; do - moon_extract_args+=(--executable "$executable") -done -"$python" "$extractor" "${moon_extract_args[@]}" -pnpm_extract_args=( - extract - --archive "$pnpm_archive" \ - --format "$pnpm_format" \ - --prefix "$pnpm_prefix" \ - --entry-count "$pnpm_entry_count" \ - --expected-bytes "$pnpm_archive_bytes" \ - --expanded-bytes "$pnpm_expanded_bytes" \ - --destination "$pnpm_extract" \ - --required "$pnpm_binary_path" \ - --required "$pnpm_companion_path" \ - --required "$pnpm_payload_path" \ - --required package.json -) -for executable in "${pnpm_executables[@]}"; do - pnpm_extract_args+=(--required "$executable" --executable "$executable") -done -"$python" "$extractor" "${pnpm_extract_args[@]}" - +mkdir -p "$moon_extract" +moon_member_prefix="" +[ "$moon_prefix" = "." ] || moon_member_prefix="$moon_prefix/" +binary_extractor="$action_dir/../../../tools/dev/extract-pinned-binary.sh" +bash "$binary_extractor" "$moon_format" "$moon_archive" "$moon_member_prefix$moon_binary_path" "$moon_extract/$moon_binary_path" "$moon_binary_sha256" +bash "$binary_extractor" "$moon_format" "$moon_archive" "$moon_member_prefix$moon_companion_path" "$moon_extract/$moon_companion_path" "$moon_companion_sha256" mkdir -p "$stage/bin" "$stage/plugins" mv "$moon_extract/$moon_binary_path" "$stage/bin/$moon_exe" mv "$moon_extract/$moon_companion_path" "$stage/bin/$moonx_exe" rm -rf "$moon_extract" chmod 0555 "$stage/bin/$moon_exe" "$stage/bin/$moonx_exe" -printf '%s\n' "$pnpm_wrapper_text" >"$stage/bin/pnpm" -printf '%s\n' "$pnpx_wrapper_text" >"$stage/bin/pnpx" -printf '%s\n' "$pnpm_cmd_text" >"$stage/bin/pnpm.cmd" -printf '%s\n' "$pnpx_cmd_text" >"$stage/bin/pnpx.cmd" -chmod 0555 "$stage/bin/pnpm" "$stage/bin/pnpx" -chmod 0444 "$stage/bin/pnpm.cmd" "$stage/bin/pnpx.cmd" - for record in "${plugin_records[@]}"; do IFS='|' read -r plugin_id repository manifest_sha256 manifest_bytes blob_sha256 blob_bytes cache_file <<<"$record" cp "$archive_root/$blob_sha256.wasm" "$stage/plugins/$cache_file" diff --git a/.github/actions/setup-moon/install-pinned-toolchain.test.sh b/.github/actions/setup-moon/install-pinned-toolchain.test.sh index ad617b406..eb1f3656b 100755 --- a/.github/actions/setup-moon/install-pinned-toolchain.test.sh +++ b/.github/actions/setup-moon/install-pinned-toolchain.test.sh @@ -3,7 +3,7 @@ set -euo pipefail root="$(git rev-parse --show-toplevel)" installer="$root/.github/actions/setup-moon/install-pinned-toolchain.sh" -extractor="$root/.github/actions/setup-moon/toolchain-archive.py" +extractor="$root/.github/actions/setup-moon/toolchain-archive.mts" tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT @@ -12,15 +12,6 @@ fail() { exit 1 } -python="" -for candidate in python3 python; do - if command -v "$candidate" >/dev/null 2>&1; then - python="$candidate" - break - fi -done -[ -n "$python" ] || fail "python3 or python is required" - sha256_file() { if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | awk '{print $1}' @@ -29,27 +20,15 @@ sha256_file() { fi } -sha512_file() { - if command -v sha512sum >/dev/null 2>&1; then - sha512sum "$1" | awk '{print $1}' - else - shasum -a 512 "$1" | awk '{print $1}' - fi -} - fixture="$tmp/fixture" mkdir -p \ "$fixture/.moon" \ - "$fixture/src/sources/toolchains" \ "$fixture/tools/dev" \ - "$fixture/content/pnpm/bin" \ - "$fixture/content/pnpm/dist/node-gyp-bin" \ - "$fixture/content/pnpm/dist/node_modules/node-gyp/bin" \ + "$fixture/content" \ "$fixture/blobs" cp "$root/tools/dev/curl-platform-flags.sh" "$fixture/tools/dev/curl-platform-flags.sh" moon_version="9.8.7" -pnpm_version="8.7.6" proto_version="7.6.5" moon_target="x86_64-unknown-linux-gnu" @@ -60,71 +39,19 @@ printf '%s\n' 'fixture readme' >"$fixture/content/README.md" printf '%s\n' 'fixture changelog' >"$fixture/content/CHANGELOG.md" printf '%s\n' 'fixture license' >"$fixture/content/LICENSE" -printf '%s\n' \ - '#!/usr/bin/env node' \ - "console.log(process.env.OLIPHAUNT_WRAPPER_ARGV_PROBE === '1' ? JSON.stringify(process.argv.slice(2)) : '$pnpm_version');" \ - >"$fixture/content/pnpm/bin/pnpm.mjs" -printf '%s\n' \ - '#!/usr/bin/env node' \ - "console.log(process.env.OLIPHAUNT_WRAPPER_ARGV_PROBE === '1' ? JSON.stringify(process.argv.slice(2)) : '$pnpm_version');" \ - >"$fixture/content/pnpm/bin/pnpx.mjs" -printf '%s\n' 'fixture pnpm payload' >"$fixture/content/pnpm/dist/pnpm.mjs" -printf '%s\n' '#!/bin/sh' 'exit 0' >"$fixture/content/pnpm/dist/node-gyp-bin/node-gyp" -printf '%s\r\n' '@exit /b 0' >"$fixture/content/pnpm/dist/node-gyp-bin/node-gyp.cmd" -printf '%s\n' '#!/usr/bin/env node' >"$fixture/content/pnpm/dist/node_modules/node-gyp/bin/node-gyp.js" -printf '%s\n' '{"name":"pnpm-fixture"}' >"$fixture/content/pnpm/package.json" -chmod 0755 \ - "$fixture/content/pnpm/bin/pnpm.mjs" \ - "$fixture/content/pnpm/bin/pnpx.mjs" \ - "$fixture/content/pnpm/dist/node-gyp-bin/node-gyp" \ - "$fixture/content/pnpm/dist/node-gyp-bin/node-gyp.cmd" \ - "$fixture/content/pnpm/dist/node_modules/node-gyp/bin/node-gyp.js" - moon_archive="$fixture/moon.tar.xz" -pnpm_archive="$fixture/pnpm.tgz" -"$python" - "$fixture/content" "$moon_archive" "$pnpm_archive" "$moon_target" <<'PY' -import io -import pathlib -import tarfile -import sys - -content = pathlib.Path(sys.argv[1]) -moon_archive = pathlib.Path(sys.argv[2]) -pnpm_archive = pathlib.Path(sys.argv[3]) -target = sys.argv[4] - -with tarfile.open(moon_archive, "w:xz", format=tarfile.PAX_FORMAT) as archive: - root = tarfile.TarInfo(f"moon_cli-{target}") - root.type = tarfile.DIRTYPE - root.mode = 0o755 - archive.addfile(root) - for name, mode in [ - ("moon", 0o755), - ("moonx", 0o755), - ("README.md", 0o644), - ("CHANGELOG.md", 0o644), - ("LICENSE", 0o644), - ]: - payload = (content / name).read_bytes() - info = tarfile.TarInfo(f"moon_cli-{target}/{name}") - info.mode = mode - info.size = len(payload) - archive.addfile(info, io.BytesIO(payload)) - -pnpm = content / "pnpm" -with tarfile.open(pnpm_archive, "w:gz", format=tarfile.PAX_FORMAT) as archive: - root = tarfile.TarInfo("package") - root.type = tarfile.DIRTYPE - root.mode = 0o755 - archive.addfile(root) - for path in sorted(candidate for candidate in pnpm.rglob("*") if candidate.is_file()): - relative = path.relative_to(pnpm).as_posix() - payload = path.read_bytes() - info = tarfile.TarInfo(f"package/{relative}") - info.mode = path.stat().st_mode & 0o777 - info.size = len(payload) - archive.addfile(info, io.BytesIO(payload)) -PY +bash "$root/tools/dev/bun.sh" - "$fixture/content" "$moon_archive" "$moon_target" <<'TS' +import {readFileSync,writeFileSync} from 'node:fs'; +import {tarArchive} from './tools/packaging/testdata/tar-fixture.mts'; +const [content, moonArchive, target] = process.argv.slice(2); +const moonRoot = 'moon_cli-' + target; +const moon = [{name:moonRoot+'/',type:'5',mode:0o755}]; +for (const name of ['moon','moonx','README.md','CHANGELOG.md','LICENSE']) moon.push({name:moonRoot+'/'+name,data:readFileSync(content+'/'+name),mode:name.startsWith('moon')?0o755:0o644}); +writeFileSync(moonArchive+'.gz',tarArchive(moon)); + +TS +gzip -dc "$moon_archive.gz" | xz -c >"$moon_archive" +rm "$moon_archive.gz" moon_archive_sha256="$(sha256_file "$moon_archive")" moon_archive_bytes="$(wc -c <"$moon_archive" | tr -d '[:space:]')" @@ -135,30 +62,7 @@ moon_expanded_bytes="$( )" moon_sha256="$(sha256_file "$fixture/content/moon")" moonx_sha256="$(sha256_file "$fixture/content/moonx")" -pnpm_archive_sha256="$(sha256_file "$pnpm_archive")" -pnpm_archive_sha512="$(sha512_file "$pnpm_archive")" -pnpm_archive_bytes="$(wc -c <"$pnpm_archive" | tr -d '[:space:]')" -pnpm_expanded_bytes="$( - find "$fixture/content/pnpm" -type f \ - -exec sh -c 'for file do wc -c < "$file"; done' sh {} + | - awk '{sum += $1} END {print sum}' -)" -pnpm_tree_result="$("$python" "$extractor" tree-digest \ - --root "$fixture/content/pnpm" \ - --executable bin/pnpm.mjs \ - --executable bin/pnpx.mjs \ - --executable dist/node-gyp-bin/node-gyp \ - --executable dist/node-gyp-bin/node-gyp.cmd \ - --executable dist/node_modules/node-gyp/bin/node-gyp.js)" -pnpm_tree_sha256="${pnpm_tree_result#* }" -pnpm_binary_sha256="$(sha256_file "$fixture/content/pnpm/bin/pnpm.mjs")" -pnpm_companion_sha256="$(sha256_file "$fixture/content/pnpm/bin/pnpx.mjs")" -pnpm_payload_sha256="$(sha256_file "$fixture/content/pnpm/dist/pnpm.mjs")" - -cat >"$fixture/src/sources/toolchains/moon-cli.toml" <"$fixture/tools/dev/moon-cli.toml" <"$fixture/src/sources/toolchains/pnpm.toml" <"$fixture/src/sources/toolchains/proto.toml" <"$fixture/tools/dev/proto.toml" <"$plugin_manifest" moon_config="$fixture/.moon/toolchains.yml" cat >"$moon_config" <"$fixture/.prototools" <"$FAKE_CURL_LOG" @@ -322,23 +198,8 @@ export RUNNER_OS=Windows final="$(bash "$installer")" [ -d "$final" ] || fail "installer did not return an installation directory" [ "$("$final/bin/moon" --version)" = "moon $moon_version" ] || fail "wrong Moon version" -[ "$("$final/bin/pnpm" --version)" = "$pnpm_version" ] || fail "wrong pnpm version" -[ "$("$final/bin/pnpx" --version)" = "$pnpm_version" ] || fail "wrong pnpx version" -expected_argv='["--flag","value with spaces","/path-like/argument"]' -for command_name in pnpm pnpx; do - observed_argv="$( - OLIPHAUNT_WRAPPER_ARGV_PROBE=1 \ - "$final/bin/$command_name" --flag "value with spaces" "/path-like/argument" - )" - [ "$observed_argv" = "$expected_argv" ] || - fail "Moon $command_name wrapper did not preserve structured caller arguments" -done -grep -Fq 'cli_path="$(cygpath -aw "$cli_path")"' "$final/bin/pnpm" || - fail "Moon pnpm wrapper does not explicitly convert its internal Windows script path" -grep -Fq 'cli_path="$(cygpath -aw "$cli_path")"' "$final/bin/pnpx" || - fail "Moon pnpx wrapper does not explicitly convert its internal Windows script path" [ "$(find "$final/plugins" -mindepth 1 -maxdepth 1 | wc -l | tr -d '[:space:]')" = "4" ] || fail "wrong plugin count" -[ "$(wc -l <"$FAKE_CURL_LOG" | tr -d '[:space:]')" = "14" ] || fail "unexpected first-install request count" +[ "$(wc -l <"$FAKE_CURL_LOG" | tr -d '[:space:]')" = "13" ] || fail "unexpected first-install request count" while IFS= read -r call; do for flag in --ssl-revoke-best-effort --tlsv1.2 --retry-all-errors --retry-connrefused --max-filesize --max-time --speed-limit; do [[ "$call" == *"$flag"* ]] || fail "curl request omitted $flag" @@ -349,15 +210,10 @@ done <"$FAKE_CURL_LOG" OLIPHAUNT_MOON_CURL=false bash "$installer" >"$tmp/cache-hit" [ "$(cat "$tmp/cache-hit")" = "$final" ] || fail "cache hit returned a different installation" -# Full-tree validation repairs unpinned PATH entries and non-component pnpm files. -chmod u+w "$final/bin/pnpm" -printf '%s\n' 'malicious wrapper' >"$final/bin/pnpm" +# Cache repair removes unexpected executables from PATH. printf '%s\n' 'shadow node' >"$final/bin/node" -printf '%s\n' 'mutated package metadata' >"$final/pnpm/package.json" OLIPHAUNT_MOON_CURL=false bash "$installer" >"$tmp/repaired" [ ! -e "$final/bin/node" ] || fail "cache repair retained an unexpected PATH entry" -[ "$("$final/bin/pnpm" --version)" = "$pnpm_version" ] || fail "cache repair did not restore pnpm" -grep -Fq 'pnpm-fixture' "$final/pnpm/package.json" || fail "tree-digest repair did not restore package metadata" # A corrupt cached archive is re-downloaded before rebuilding an invalid installation. moon_cached="$OLIPHAUNT_MOON_TOOLCHAIN_CACHE_ROOT/archives/$moon_archive_sha256.tar.xz" @@ -372,9 +228,9 @@ after_requests="$(wc -l <"$FAKE_CURL_LOG" | tr -d '[:space:]')" [ "$("$final/bin/moon" --version)" = "moon $moon_version" ] || fail "corrupt archive repair failed" # Promotion interruption restores the previous installation transactionally. -chmod u+w "$final/bin/pnpm" -printf '%s\n' 'previous installation' >"$final/bin/pnpm" -before_wrapper="$(sha256_file "$final/bin/pnpm")" +chmod u+w "$final/bin/moon" +printf '%s\n' 'previous installation' >"$final/bin/moon" +before_wrapper="$(sha256_file "$final/bin/moon")" set +e OLIPHAUNT_MOON_CURL=false \ OLIPHAUNT_MOON_TOOLCHAIN_TEST_INTERRUPT_AFTER_BACKUP=1 \ @@ -382,74 +238,7 @@ OLIPHAUNT_MOON_CURL=false \ interrupt_status="$?" set -e [ "$interrupt_status" -eq 143 ] || fail "interruption hook returned $interrupt_status instead of 143" -[ "$(sha256_file "$final/bin/pnpm")" = "$before_wrapper" ] || fail "interrupted promotion did not restore the prior installation" +[ "$(sha256_file "$final/bin/moon")" = "$before_wrapper" ] || fail "interrupted promotion did not restore the prior installation" OLIPHAUNT_MOON_CURL=false bash "$installer" >/dev/null -# Executable intent is part of the portable tree fingerprint on POSIX. -chmod 0644 "$final/pnpm/bin/pnpm.mjs" -set +e -"$python" "$extractor" tree-digest \ - --root "$final/pnpm" \ - --executable bin/pnpm.mjs \ - --executable bin/pnpx.mjs \ - --executable dist/node-gyp-bin/node-gyp \ - --executable dist/node-gyp-bin/node-gyp.cmd \ - --executable dist/node_modules/node-gyp/bin/node-gyp.js >/dev/null 2>"$tmp/mode.err" -mode_status="$?" -set -e -[ "$mode_status" -ne 0 ] || fail "tree digest accepted executable-mode drift" -chmod 0755 "$final/pnpm/bin/pnpm.mjs" - -# Reject traversal and non-zero directory payload metadata before extraction. -"$python" - "$tmp/unsafe.tar.xz" "$tmp/directory-payload.tar.xz" "$tmp/pax-payload.tar.xz" <<'PY' -import io -import tarfile -import sys - -with tarfile.open(sys.argv[1], "w:xz") as archive: - root = tarfile.TarInfo("root") - root.type = tarfile.DIRTYPE - archive.addfile(root) - payload = b"x" - bad = tarfile.TarInfo("root/../escape") - bad.size = len(payload) - archive.addfile(bad, io.BytesIO(payload)) - -with tarfile.open(sys.argv[2], "w:xz") as archive: - root = tarfile.TarInfo("root") - root.type = tarfile.DIRTYPE - root.size = 1 - archive.addfile(root, io.BytesIO(b"x")) - payload = b"x" - regular = tarfile.TarInfo("root/file") - regular.size = len(payload) - archive.addfile(regular, io.BytesIO(payload)) - -# Extended metadata is rejected from the raw stream before a decompression bomb -# can be materialized by tarfile's PAX parser. -with tarfile.open(sys.argv[3], "w:xz", format=tarfile.PAX_FORMAT) as archive: - payload = b"x" - regular = tarfile.TarInfo("root/file") - regular.size = len(payload) - regular.pax_headers = {"comment": "x" * (2 * 1024 * 1024)} - archive.addfile(regular, io.BytesIO(payload)) -PY - -for unsafe in "$tmp/unsafe.tar.xz" "$tmp/directory-payload.tar.xz" "$tmp/pax-payload.tar.xz"; do - set +e - "$python" "$extractor" extract \ - --archive "$unsafe" \ - --format tar.xz \ - --prefix root \ - --entry-count 2 \ - --expected-bytes "$(wc -c <"$unsafe" | tr -d '[:space:]')" \ - --expanded-bytes 1 \ - --destination "$unsafe.out" \ - --required file >/dev/null 2>"$tmp/unsafe.err" - unsafe_status="$?" - set -e - [ "$unsafe_status" -ne 0 ] || fail "unsafe archive was accepted: $unsafe" - [ ! -e "$unsafe.out" ] || fail "unsafe archive left a partial extraction tree" -done - echo "Pinned Moon toolchain bootstrap fault tests passed." diff --git a/.github/actions/setup-moon/toolchain-archive.mts b/.github/actions/setup-moon/toolchain-archive.mts new file mode 100644 index 000000000..a0a43371d --- /dev/null +++ b/.github/actions/setup-moon/toolchain-archive.mts @@ -0,0 +1,210 @@ +import { createHash } from 'node:crypto'; +import { + createReadStream, + lstatSync, + readdirSync, + readFileSync, + mkdirSync, + writeFileSync, + chmodSync, + rmSync, +} from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { + portableMemberName, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; + +const MAX_BYTES = 750 * 1024 * 1024; +function requireValue(condition, message) { + if (!condition) throw new Error(message); +} +function safeName(name) { + return portableMemberName(name, 'file', 'bootstrap'); +} +function number(value, maximum) { + const result = Number(value); + requireValue( + Number.isSafeInteger(result) && result > 0 && result <= maximum, + `invalid bounded count: ${value}`, + ); + return result; +} + +async function treeDigest(root, executables) { + requireValue(lstatSync(root).isDirectory(), 'tree root must be a real directory'); + const files = []; + const names = new Map(); + let totalBytes = 0; + let count = 0; + function walk(relative) { + for (const name of readdirSync(path.join(root, relative))) { + requireValue(++count <= 4096, 'tree exceeds entry limit'); + const member = safeName(relative ? `${relative}/${name}` : name); + const folded = member.normalize('NFC').toLowerCase(); + requireValue(!names.has(folded), `tree has colliding paths: ${member}`); + names.set(folded, member); + const file = path.join(root, member); + const stat = lstatSync(file); + if (stat.isDirectory()) { + walk(member); + continue; + } + requireValue(stat.isFile(), `tree contains a link or special file: ${member}`); + totalBytes += stat.size; + requireValue( + totalBytes <= MAX_BYTES && stat.size <= 250 * 1024 * 1024, + 'tree exceeds byte limit', + ); + if (process.platform !== 'win32') { + requireValue( + Boolean(stat.mode & 0o111) === executables.has(member), + `tree executable mode mismatch: ${member}`, + ); + } + files.push({ member, file, size: stat.size }); + } + } + walk(''); + for (const name of executables) + requireValue( + files.some((file) => file.member === name), + `missing executable: ${name}`, + ); + files.sort((a, b) => Buffer.compare(Buffer.from(a.member), Buffer.from(b.member))); + const digest = createHash('sha256').update('oliphaunt-bootstrap-tree-v2\0'); + for (const { member, file, size } of files) { + digest.update(`${member}\0${size}\0${executables.has(member) ? 'x' : '-'}\0`); + for await (const block of createReadStream(file)) digest.update(block); + digest.update('\0'); + } + return `${files.length} ${digest.digest('hex')}`; +} + +function extract(values, executables) { + const archive = values.archive; + const stat = lstatSync(archive); + requireValue( + stat.isFile() && stat.size === number(values['expected-bytes'], 250 * 1024 * 1024), + 'archive byte-size mismatch', + ); + requireValue(values.format === 'tar.gz', 'package archive must be tar.gz'); + const count = number(values['entry-count'], 4096); + const expanded = number(values['expanded-bytes'], MAX_BYTES); + const prefix = safeName(values.prefix); + const entries = readPortableArchiveEntries(archive, { + format: 'tar.gz', + maxArchiveBytes: 250 * 1024 * 1024, + maxEntryBytes: 250 * 1024 * 1024, + maxExpandedBytes: MAX_BYTES, + maxEntries: 4096, + }); + requireValue(entries.size === count, 'archive entry count mismatch'); + requireValue( + [...entries.values()].reduce((sum, entry) => sum + entry.size, 0) === expanded, + 'archive expanded byte-size mismatch', + ); + const required = new Set((values.required ?? []).map(safeName)); + requireValue( + required.size > 0 && [...executables].every((name) => required.has(name)), + 'executables must be required files', + ); + for (const entry of entries.values()) { + requireValue( + entry.name === prefix ? entry.isDirectory : entry.name.startsWith(`${prefix}/`), + `archive member outside pinned root: ${entry.name}`, + ); + if (entry.isFile) + requireValue( + Boolean(entry.mode & 0o111) === executables.has(entry.name.slice(prefix.length + 1)), + `archive executable mismatch: ${entry.name}`, + ); + } + for (const name of required) { + const entry = entries.get(`${prefix}/${name}`); + requireValue(entry?.isFile && entry.size > 0, `missing non-empty required file: ${name}`); + } + const destination = values.destination; + mkdirSync(path.dirname(path.resolve(destination)), { recursive: true }); + mkdirSync(destination, { mode: 0o700 }); + try { + for (const entry of entries.values()) { + if (entry.name === prefix) continue; + const relative = entry.name.slice(prefix.length + 1); + const output = path.join(destination, relative); + mkdirSync(entry.isDirectory ? output : path.dirname(output), { + recursive: true, + mode: 0o755, + }); + if (entry.isFile) { + const mode = executables.has(relative) ? 0o755 : 0o644; + writeFileSync(output, entry.data(), { flag: 'wx', mode }); + chmodSync(output, mode); + } + } + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + throw error; + } +} + +try { + const [command, ...args] = process.argv.slice(2); + if (command === 'oci-token' || command === 'oci-manifest') { + const bytes = readFileSync(args[0]); + requireValue( + bytes.length <= (command === 'oci-token' ? 16384 : 1024 * 1024), + 'oversized OCI response', + ); + const value = JSON.parse(bytes.toString('utf8')); + if (command === 'oci-token') { + requireValue( + typeof value.token === 'string' && + value.token.length <= 8192 && + /^[-A-Za-z0-9._~+/=]+$/u.test(value.token), + 'unsafe OCI token', + ); + console.log(value.token); + } else { + requireValue( + value.schemaVersion === 2 && + value.mediaType === 'application/vnd.oci.image.manifest.v1+json' && + Array.isArray(value.layers), + 'invalid OCI manifest', + ); + const wasm = value.layers.filter((layer) => layer?.mediaType === 'application/wasm'); + requireValue( + wasm.length === 1 && + wasm[0].digest === `sha256:${args[1]}` && + wasm[0].size === Number(args[2]), + 'OCI manifest does not bind the expected WASM blob', + ); + } + } else { + const { values } = parseArgs({ + args, + options: Object.fromEntries([ + ...[ + 'root', + 'archive', + 'format', + 'prefix', + 'entry-count', + 'expected-bytes', + 'expanded-bytes', + 'destination', + ].map((key) => [key, { type: 'string' }]), + ['required', { type: 'string', multiple: true }], + ['executable', { type: 'string', multiple: true }], + ]), + }); + const executables = new Set((values.executable ?? []).map(safeName)); + if (command === 'tree-digest') console.log(await treeDigest(values.root, executables)); + else if (command === 'extract') extract(values, executables); + else throw new Error(`unknown toolchain operation: ${command}`); + } +} catch (error) { + console.error(`pinned bootstrap archive rejected: ${error.message}`); + process.exitCode = 1; +} diff --git a/.github/actions/setup-moon/toolchain-archive.py b/.github/actions/setup-moon/toolchain-archive.py deleted file mode 100755 index 1276a4752..000000000 --- a/.github/actions/setup-moon/toolchain-archive.py +++ /dev/null @@ -1,642 +0,0 @@ -#!/usr/bin/env python3 -"""Safely extract and fingerprint the pinned bootstrap tool archives.""" - -from __future__ import annotations - -import argparse -import gzip -import hashlib -import lzma -import os -import shutil -import stat -import sys -import tarfile -import unicodedata -import zipfile -from dataclasses import dataclass -from pathlib import Path, PurePosixPath -from typing import BinaryIO, Iterable - - -COPY_BYTES = 1024 * 1024 -MAX_ARCHIVE_BYTES = 250 * 1024 * 1024 -MAX_EXPANDED_BYTES = 750 * 1024 * 1024 -MAX_ENTRY_BYTES = 250 * 1024 * 1024 -MAX_ENTRIES = 4096 -MAX_TARGET_SCAN_ENTRIES = 8192 -MAX_TARGET_SCAN_BYTES = 500 * 1024 * 1024 -MAX_PATH_BYTES = 4096 -MAX_COMPONENT_BYTES = 255 -WINDOWS_RESERVED_NAMES = { - "aux", - "con", - "nul", - "prn", - *(f"com{number}" for number in range(1, 10)), - *(f"lpt{number}" for number in range(1, 10)), - "com¹", - "com²", - "com³", - "conin$", - "conout$", - "clock$", - "lpt¹", - "lpt²", - "lpt³", -} - - -class UnsafeArchive(ValueError): - pass - - -@dataclass(frozen=True) -class Entry: - name: str - relative: str - size: int - directory: bool - executable: bool - source: object - - -def portable_path(value: str, label: str, *, allow_root: bool = False) -> str: - if not value or any(ord(character) < 32 or ord(character) == 127 for character in value): - raise UnsafeArchive(f"{label} is empty or contains control characters") - if "\\" in value or value.startswith("/") or (len(value) > 1 and value[1] == ":"): - raise UnsafeArchive(f"{label} is absolute or non-portable: {value!r}") - normalized = value.rstrip("/") - while normalized.startswith("./"): - normalized = normalized[2:] - if normalized in {"", "."}: - if allow_root: - return "" - raise UnsafeArchive(f"{label} resolves to the archive root") - parts = normalized.split("/") - if any(part in {"", ".", ".."} for part in parts): - raise UnsafeArchive(f"{label} contains an empty, dot, or traversal component") - for part in parts: - encoded = part.encode("utf-8") - if len(encoded) > MAX_COMPONENT_BYTES: - raise UnsafeArchive(f"{label} contains an oversized path component") - if part.endswith((" ", ".")) or any(character in part for character in '<>:"|?*'): - raise UnsafeArchive(f"{label} is ambiguous on Windows") - if part.split(".", 1)[0].casefold() in WINDOWS_RESERVED_NAMES: - raise UnsafeArchive(f"{label} contains a reserved Windows name") - result = "/".join(parts) - if len(result.encode("utf-8")) > MAX_PATH_BYTES: - raise UnsafeArchive(f"{label} exceeds the portable path-length limit") - return result - - -def relative_path(name: str, prefix: str, *, directory: bool) -> str: - normalized = portable_path(name, f"archive member {name!r}", allow_root=directory) - if prefix == ".": - return normalized - if normalized == prefix: - if not directory: - raise UnsafeArchive(f"archive root {prefix!r} is not a directory") - return "" - expected = f"{prefix}/" - if not normalized.startswith(expected): - raise UnsafeArchive(f"archive member {name!r} is outside required root {prefix!r}") - return normalized[len(expected) :] - - -def validate_entries( - entries: Iterable[Entry], - *, - expected_count: int, - expected_expanded_bytes: int, - required: set[str], - executables: set[str], -) -> list[Entry]: - checked = list(entries) - if len(checked) != expected_count: - raise UnsafeArchive( - f"archive entry count mismatch: expected {expected_count}, got {len(checked)}" - ) - paths: dict[str, Entry] = {} - portable: dict[str, str] = {} - expanded_bytes = 0 - for entry in checked: - if entry.relative == "": - continue - if entry.relative in paths: - raise UnsafeArchive(f"archive contains duplicate path {entry.relative!r}") - parts = entry.relative.split("/") - for depth in range(1, len(parts) + 1): - candidate = "/".join(parts[:depth]) - key = unicodedata.normalize("NFC", candidate).casefold() - prior = portable.get(key) - if prior is not None and prior != candidate: - raise UnsafeArchive( - f"archive paths {prior!r} and {candidate!r} collide on a portable filesystem" - ) - portable[key] = candidate - paths[entry.relative] = entry - if not entry.directory: - if entry.size < 0 or entry.size > MAX_ENTRY_BYTES: - raise UnsafeArchive(f"archive member {entry.relative!r} exceeds its file-size bound") - expanded_bytes += entry.size - if expanded_bytes > MAX_EXPANDED_BYTES: - raise UnsafeArchive("archive exceeds its expanded-size safety bound") - if expanded_bytes != expected_expanded_bytes: - raise UnsafeArchive( - f"archive expanded byte-size mismatch: expected {expected_expanded_bytes}, got {expanded_bytes}" - ) - missing = sorted(required - set(paths)) - if missing: - raise UnsafeArchive(f"archive is missing required files: {', '.join(missing)}") - for path in required: - entry = paths[path] - if entry.directory or entry.size == 0: - raise UnsafeArchive(f"required archive path is not a non-empty regular file: {path}") - actual_executables = { - path for path, entry in paths.items() if not entry.directory and entry.executable - } - if actual_executables != executables: - raise UnsafeArchive( - "archive executable paths mismatch: expected " - f"{sorted(executables)!r}, got {sorted(actual_executables)!r}" - ) - for entry in checked: - if entry.relative == "": - continue - parts = PurePosixPath(entry.relative).parts - for depth in range(1, len(parts)): - ancestor = paths.get("/".join(parts[:depth])) - if ancestor is not None and not ancestor.directory: - raise UnsafeArchive( - f"archive path {entry.relative!r} descends through a regular file" - ) - return checked - - -def tar_entries(archive: tarfile.TarFile, prefix: str, entry_limit: int) -> list[Entry]: - result: list[Entry] = [] - for member in archive: - if len(result) >= entry_limit: - raise UnsafeArchive("tar archive exceeds its entry-count bound") - if member.mode & (stat.S_ISUID | stat.S_ISGID): - raise UnsafeArchive(f"archive member {member.name!r} has set-id mode bits") - if not (member.isdir() or member.isreg()): - raise UnsafeArchive(f"archive member {member.name!r} is not a regular file or directory") - if member.isdir() and member.size != 0: - raise UnsafeArchive(f"archive directory {member.name!r} has a non-zero payload") - relative = relative_path(member.name, prefix, directory=member.isdir()) - result.append( - Entry( - member.name, - relative, - member.size if member.isreg() else 0, - member.isdir(), - bool(member.mode & 0o111), - member, - ) - ) - return result - - -def zip_entries(archive: zipfile.ZipFile, prefix: str, entry_limit: int) -> list[Entry]: - result: list[Entry] = [] - members = archive.infolist() - if len(members) > entry_limit: - raise UnsafeArchive("ZIP archive exceeds its entry-count bound") - for member in members: - mode = (member.external_attr >> 16) & 0xFFFF - file_type = stat.S_IFMT(mode) - directory = member.is_dir() or file_type == stat.S_IFDIR - if file_type not in {0, stat.S_IFREG, stat.S_IFDIR}: - raise UnsafeArchive(f"archive member {member.filename!r} is not a regular file or directory") - if bool(member.is_dir()) != directory: - raise UnsafeArchive(f"archive member {member.filename!r} has inconsistent directory metadata") - if directory and (member.file_size != 0 or member.compress_size != 0): - raise UnsafeArchive(f"archive directory {member.filename!r} has a non-zero payload") - if member.flag_bits & 0x1: - raise UnsafeArchive(f"archive member {member.filename!r} is encrypted") - if member.compress_type not in {zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED}: - raise UnsafeArchive(f"archive member {member.filename!r} uses unsupported compression") - relative = relative_path(member.filename, prefix, directory=directory) - result.append( - Entry( - member.filename, - relative, - member.file_size if not directory else 0, - directory, - bool(mode & 0o111), - member, - ) - ) - return result - - -def safe_parent(destination: Path, relative: str) -> Path: - parent = destination.joinpath(*PurePosixPath(relative).parts).parent - current = destination - for part in parent.relative_to(destination).parts: - current /= part - if current.exists() or current.is_symlink(): - mode = current.lstat().st_mode - if not stat.S_ISDIR(mode) or stat.S_ISLNK(mode): - raise UnsafeArchive(f"extraction ancestor is not a real directory: {current}") - else: - current.mkdir(mode=0o755) - return parent - - -def copy_regular(source: BinaryIO, output: Path, expected_bytes: int, executable: bool) -> None: - descriptor = os.open(output, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) - copied = 0 - try: - with source, os.fdopen(descriptor, "wb") as sink: - descriptor = -1 - while True: - block = source.read(COPY_BYTES) - if not block: - break - copied += len(block) - if copied > expected_bytes: - raise UnsafeArchive(f"archive member {output.name!r} exceeded its declared size") - sink.write(block) - finally: - if descriptor >= 0: - os.close(descriptor) - if copied != expected_bytes: - raise UnsafeArchive(f"archive member {output.name!r} was truncated") - os.chmod(output, 0o755 if executable else 0o644) - - -def read_exact(stream: BinaryIO, size: int, label: str) -> bytes: - chunks: list[bytes] = [] - remaining = size - while remaining: - chunk = stream.read(remaining) - if not chunk: - raise UnsafeArchive(f"truncated {label}") - chunks.append(chunk) - remaining -= len(chunk) - return b"".join(chunks) - - -def tar_octal(field: bytes, label: str) -> int: - if field and field[0] & 0x80: - raise UnsafeArchive(f"{label} uses unsupported base-256 encoding") - value = field.strip(b" \0") - if not value: - return 0 - if any(character not in b"01234567" for character in value): - raise UnsafeArchive(f"{label} is not a canonical octal value") - return int(value, 8) - - -def checked_tar_header(header: bytes) -> tuple[str, int, bytes]: - if len(header) != 512: - raise UnsafeArchive("truncated tar header") - stored_checksum = tar_octal(header[148:156], "tar header checksum") - checksum_header = bytearray(header) - checksum_header[148:156] = b" " - if sum(checksum_header) != stored_checksum: - raise UnsafeArchive("tar header checksum mismatch") - name_bytes = header[0:100].split(b"\0", 1)[0] - prefix_bytes = header[345:500].split(b"\0", 1)[0] - try: - name = name_bytes.decode("utf-8") - prefix = prefix_bytes.decode("utf-8") - except UnicodeDecodeError as error: - raise UnsafeArchive("tar header path is not UTF-8") from error - if prefix: - name = f"{prefix}/{name}" - size = tar_octal(header[124:136], f"tar member {name!r} size") - typeflag = header[156:157] or b"\0" - return name, size, typeflag - - -def open_raw_tar(archive_path: Path, archive_format: str) -> BinaryIO: - if archive_format == "tar.xz": - return lzma.open(archive_path, "rb") - return gzip.open(archive_path, "rb") - - -def skip_exact(stream: BinaryIO, size: int, label: str) -> None: - remaining = size - while remaining: - block = stream.read(min(COPY_BYTES, remaining)) - if not block: - raise UnsafeArchive(f"truncated {label}") - remaining -= len(block) - - -def scan_simple_tar( - archive_path: Path, - archive_format: str, - *, - expected_count: int, - expected_expanded_bytes: int, -) -> None: - count = 0 - expanded_bytes = 0 - with open_raw_tar(archive_path, archive_format) as stream: - while True: - header = read_exact(stream, 512, "tar header") - if not any(header): - second = read_exact(stream, 512, "tar end marker") - if any(second): - raise UnsafeArchive("tar archive has only one zero end marker") - break - name, size, typeflag = checked_tar_header(header) - count += 1 - if count > expected_count or count > MAX_ENTRIES: - raise UnsafeArchive("tar archive exceeds its entry-count bound") - if typeflag in {b"x", b"g", b"L", b"K", b"S"}: - raise UnsafeArchive(f"tar member {name!r} uses unsupported extended metadata") - expanded_bytes += size - if size > MAX_ENTRY_BYTES or expanded_bytes > MAX_EXPANDED_BYTES: - raise UnsafeArchive("tar archive exceeds its raw payload bound") - skip_exact(stream, ((size + 511) // 512) * 512, f"tar member {name!r}") - if count != expected_count: - raise UnsafeArchive(f"archive entry count mismatch: expected {expected_count}, got {count}") - if expanded_bytes != expected_expanded_bytes: - raise UnsafeArchive( - "archive expanded byte-size mismatch: " - f"expected {expected_expanded_bytes}, got {expanded_bytes}" - ) - - -def validate_archive_file(archive_path: Path, expected_bytes: int) -> None: - if not archive_path.is_file() or archive_path.is_symlink(): - raise UnsafeArchive(f"archive is not a regular file: {archive_path}") - actual_bytes = archive_path.stat().st_size - if actual_bytes != expected_bytes: - raise UnsafeArchive(f"archive byte-size mismatch: expected {expected_bytes}, got {actual_bytes}") - if actual_bytes < 1 or actual_bytes > MAX_ARCHIVE_BYTES: - raise UnsafeArchive("archive exceeds its compressed-size safety bound") - - -def extract(arguments: argparse.Namespace) -> None: - archive_path = arguments.archive - validate_archive_file(archive_path, arguments.expected_bytes) - if arguments.entry_count < 1 or arguments.entry_count > MAX_ENTRIES: - raise UnsafeArchive(f"entry count must be between 1 and {MAX_ENTRIES}") - if arguments.expanded_bytes < 1 or arguments.expanded_bytes > MAX_EXPANDED_BYTES: - raise UnsafeArchive("expanded byte count exceeds its safety bound") - prefix = "." if arguments.prefix == "." else portable_path(arguments.prefix, "strip prefix") - required = {portable_path(value, "required archive path") for value in arguments.required} - executables = {portable_path(value, "executable archive path") for value in arguments.executable} - if not executables.issubset(required): - raise UnsafeArchive("every executable archive path must also be required") - destination = arguments.destination - if destination.exists() or destination.is_symlink(): - raise UnsafeArchive(f"private extraction destination already exists: {destination}") - destination.parent.mkdir(parents=True, exist_ok=True) - destination.mkdir(mode=0o700) - try: - if arguments.format == "zip": - with zipfile.ZipFile(archive_path) as stream: - entries = validate_entries( - zip_entries(stream, prefix, arguments.entry_count), - expected_count=arguments.entry_count, - expected_expanded_bytes=arguments.expanded_bytes, - required=required, - executables=executables, - ) - for entry in entries: - if entry.relative == "": - continue - output = destination.joinpath(*PurePosixPath(entry.relative).parts) - safe_parent(destination, entry.relative) - if entry.directory: - if output.exists() or output.is_symlink(): - if not output.is_dir() or output.is_symlink(): - raise UnsafeArchive(f"cannot create archive directory {entry.relative!r}") - else: - output.mkdir(mode=0o755) - else: - copy_regular(stream.open(entry.source, "r"), output, entry.size, entry.executable) - else: - scan_simple_tar( - archive_path, - arguments.format, - expected_count=arguments.entry_count, - expected_expanded_bytes=arguments.expanded_bytes, - ) - mode = "r:xz" if arguments.format == "tar.xz" else "r:gz" - with tarfile.open(archive_path, mode=mode) as stream: - entries = validate_entries( - tar_entries(stream, prefix, arguments.entry_count), - expected_count=arguments.entry_count, - expected_expanded_bytes=arguments.expanded_bytes, - required=required, - executables=executables, - ) - with tarfile.open(archive_path, mode=mode) as stream: - by_name = {member.name: member for member in stream} - for entry in entries: - if entry.relative == "": - continue - output = destination.joinpath(*PurePosixPath(entry.relative).parts) - safe_parent(destination, entry.relative) - if entry.directory: - if output.exists() or output.is_symlink(): - if not output.is_dir() or output.is_symlink(): - raise UnsafeArchive(f"cannot create archive directory {entry.relative!r}") - else: - output.mkdir(mode=0o755) - else: - source = stream.extractfile(by_name[entry.name]) - if source is None: - raise UnsafeArchive(f"cannot read archive member {entry.name!r}") - copy_regular(source, output, entry.size, entry.executable) - except BaseException: - shutil.rmtree(destination, ignore_errors=True) - raise - - -def extract_one(arguments: argparse.Namespace) -> None: - archive_path = arguments.archive - validate_archive_file(archive_path, arguments.expected_bytes) - member = portable_path(arguments.member, "target archive member") - output = arguments.destination - if output.exists() or output.is_symlink(): - raise UnsafeArchive(f"target extraction path already exists: {output}") - output.parent.mkdir(parents=True, exist_ok=True) - if output.parent.is_symlink(): - raise UnsafeArchive(f"target extraction parent is a symbolic link: {output.parent}") - try: - if arguments.format == "zip": - with zipfile.ZipFile(archive_path) as archive: - infos = archive.infolist() - if len(infos) > MAX_ENTRIES: - raise UnsafeArchive("ZIP archive exceeds its entry-count bound") - matches = [info for info in infos if info.filename.rstrip("/") == member] - if len(matches) != 1: - raise UnsafeArchive(f"ZIP archive must contain target member exactly once: {member}") - info = matches[0] - mode = (info.external_attr >> 16) & 0xFFFF - if info.is_dir() or stat.S_IFMT(mode) not in {0, stat.S_IFREG}: - raise UnsafeArchive(f"target ZIP member is not a regular file: {member}") - if info.flag_bits & 0x1 or info.compress_type not in {zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED}: - raise UnsafeArchive(f"target ZIP member uses unsafe encoding: {member}") - if info.file_size != arguments.member_bytes: - raise UnsafeArchive(f"target ZIP member has unexpected size: {member}") - copy_regular( - archive.open(info, "r"), output, arguments.member_bytes, arguments.executable - ) - else: - scanned_entries = 0 - scanned_bytes = 0 - with open_raw_tar(archive_path, arguments.format) as stream: - while True: - header = read_exact(stream, 512, "tar header") - if not any(header): - raise UnsafeArchive(f"tar archive does not contain target member: {member}") - name, size, typeflag = checked_tar_header(header) - scanned_entries += 1 - scanned_bytes += size - if scanned_entries > MAX_TARGET_SCAN_ENTRIES or scanned_bytes > MAX_TARGET_SCAN_BYTES: - raise UnsafeArchive("target tar scan exceeds its bounded search envelope") - padded_size = ((size + 511) // 512) * 512 - if name == member: - if typeflag not in {b"0", b"\0"} or size != arguments.member_bytes: - raise UnsafeArchive(f"target tar member is not the expected regular file: {member}") - descriptor = os.open(output, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) - try: - with os.fdopen(descriptor, "wb") as sink: - descriptor = -1 - remaining = size - digest = hashlib.sha256() - while remaining: - block = stream.read(min(COPY_BYTES, remaining)) - if not block: - raise UnsafeArchive(f"target tar member is truncated: {member}") - sink.write(block) - digest.update(block) - remaining -= len(block) - finally: - if descriptor >= 0: - os.close(descriptor) - if digest.hexdigest() != arguments.member_sha256: - raise UnsafeArchive(f"target tar member checksum mismatch: {member}") - os.chmod(output, 0o755 if arguments.executable else 0o644) - return - skip_exact(stream, padded_size, f"tar member {name!r}") - if hashlib.sha256(output.read_bytes()).hexdigest() != arguments.member_sha256: - raise UnsafeArchive(f"target archive member checksum mismatch: {member}") - except BaseException: - output.unlink(missing_ok=True) - raise - - -def tree_digest(root: Path, expected_executables: set[str]) -> tuple[int, str]: - if not root.is_dir() or root.is_symlink(): - raise UnsafeArchive(f"tree root is not a real directory: {root}") - files: list[tuple[str, Path]] = [] - portable: dict[str, str] = {} - for current, directories, names in os.walk(root, followlinks=False): - current_path = Path(current) - for name in directories: - candidate = current_path / name - if candidate.is_symlink(): - raise UnsafeArchive(f"tree contains symbolic link: {candidate}") - for name in names: - candidate = current_path / name - mode = candidate.lstat().st_mode - if not stat.S_ISREG(mode) or stat.S_ISLNK(mode): - raise UnsafeArchive(f"tree contains non-regular file: {candidate}") - relative = candidate.relative_to(root).as_posix() - portable_path(relative, "tree path") - key = unicodedata.normalize("NFC", relative).casefold() - prior = portable.get(key) - if prior is not None and prior != relative: - raise UnsafeArchive(f"tree paths {prior!r} and {relative!r} collide") - portable[key] = relative - files.append((relative, candidate)) - files.sort(key=lambda item: item[0].encode("utf-8")) - actual_paths = {relative for relative, _ in files} - missing_executables = sorted(expected_executables - actual_paths) - if missing_executables: - raise UnsafeArchive( - f"tree is missing expected executable files: {', '.join(missing_executables)}" - ) - if os.name != "nt": - actual_executables = { - relative for relative, candidate in files if candidate.stat().st_mode & 0o111 - } - if actual_executables != expected_executables: - raise UnsafeArchive( - "tree executable paths mismatch: expected " - f"{sorted(expected_executables)!r}, got {sorted(actual_executables)!r}" - ) - digest = hashlib.sha256(b"oliphaunt-bootstrap-tree-v2\0") - for relative, candidate in files: - size = candidate.stat().st_size - digest.update(relative.encode("utf-8")) - digest.update(b"\0") - digest.update(str(size).encode("ascii")) - digest.update(b"\0") - digest.update(b"x" if relative in expected_executables else b"-") - digest.update(b"\0") - with candidate.open("rb") as stream: - while block := stream.read(COPY_BYTES): - digest.update(block) - digest.update(b"\0") - return len(files), digest.hexdigest() - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="command", required=True) - extract_parser = subparsers.add_parser("extract") - extract_parser.add_argument("--archive", type=Path, required=True) - extract_parser.add_argument("--format", choices=("zip", "tar.xz", "tar.gz"), required=True) - extract_parser.add_argument("--prefix", required=True) - extract_parser.add_argument("--entry-count", type=int, required=True) - extract_parser.add_argument("--expected-bytes", type=int, required=True) - extract_parser.add_argument("--expanded-bytes", type=int, required=True) - extract_parser.add_argument("--destination", type=Path, required=True) - extract_parser.add_argument("--required", action="append", default=[], required=True) - extract_parser.add_argument("--executable", action="append", default=[]) - one_parser = subparsers.add_parser("extract-file") - one_parser.add_argument("--archive", type=Path, required=True) - one_parser.add_argument("--format", choices=("zip", "tar.xz", "tar.gz"), required=True) - one_parser.add_argument("--expected-bytes", type=int, required=True) - one_parser.add_argument("--member", required=True) - one_parser.add_argument("--member-bytes", type=int, required=True) - one_parser.add_argument("--member-sha256", required=True) - one_parser.add_argument("--destination", type=Path, required=True) - one_parser.add_argument("--executable", action="store_true") - digest_parser = subparsers.add_parser("tree-digest") - digest_parser.add_argument("--root", type=Path, required=True) - digest_parser.add_argument("--executable", action="append", default=[]) - return parser.parse_args() - - -def main() -> int: - arguments = parse_args() - try: - if arguments.command == "extract": - extract(arguments) - elif arguments.command == "extract-file": - if len(arguments.member_sha256) != 64 or any( - character not in "0123456789abcdef" for character in arguments.member_sha256 - ): - raise UnsafeArchive("target member SHA-256 is not lowercase hexadecimal") - if arguments.member_bytes < 1 or arguments.member_bytes > MAX_ENTRY_BYTES: - raise UnsafeArchive("target member byte count exceeds its safety bound") - extract_one(arguments) - else: - executables = { - portable_path(value, "expected executable tree path") - for value in arguments.executable - } - count, digest = tree_digest(arguments.root, executables) - print(f"{count} {digest}") - except (OSError, UnsafeArchive, tarfile.TarError, zipfile.BadZipFile) as error: - print(f"pinned bootstrap archive rejected: {error}", file=sys.stderr) - return 1 - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/.github/actions/setup-node-bun/action.yml b/.github/actions/setup-node-bun/action.yml new file mode 100644 index 000000000..5e8f151ba --- /dev/null +++ b/.github/actions/setup-node-bun/action.yml @@ -0,0 +1,21 @@ +name: Set up Node and Bun +description: Install pinned Node.js and Bun for Oliphaunt. + +outputs: + node-execution-envelope: + description: Absolute digest-verified Node.js execution envelope. + value: ${{ steps.node_runtime.outputs.execution-envelope }} + bun-execution-envelope: + description: Absolute digest-verified Bun execution envelope. + value: ${{ steps.install.outputs.execution-envelope }} + +runs: + using: composite + steps: + - name: Set up verified Node.js + id: node_runtime + uses: ./.github/actions/setup-node-runtime + + - name: Set up verified Bun + id: install + uses: ./.github/actions/setup-bun diff --git a/.github/actions/setup-node-pnpm/action.yml b/.github/actions/setup-node-pnpm/action.yml deleted file mode 100644 index c40b8c0f8..000000000 --- a/.github/actions/setup-node-pnpm/action.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Set up Node and pnpm -description: Install the pinned Node.js and pnpm toolchain for Oliphaunt. - -inputs: - node-version: - description: Node.js version. - required: false - default: "22.22.3" - pnpm-version: - description: pnpm version. - required: false - default: "11.5.0" - -outputs: - node-execution-envelope: - description: Absolute digest-verified Node.js execution envelope. - value: ${{ steps.node_runtime.outputs.execution-envelope }} - pnpm-execution-envelope: - description: Absolute digest-verified pnpm execution envelope. - value: ${{ steps.install.outputs.execution-envelope }} - -runs: - using: composite - steps: - - name: Set up verified Node.js - id: node_runtime - uses: ./.github/actions/setup-node-runtime - with: - node-version: ${{ inputs.node-version }} - - - name: Restore verified pnpm archive - id: restore_verified_pnpm_runtime - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 - with: - path: ${{ runner.temp }}/oliphaunt-pnpm-runtime - key: verified-pnpm-runtime-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.github/actions/setup-node-pnpm/action.yml', '.github/actions/setup-node-pnpm/install-pinned-pnpm.sh', '.github/actions/setup-moon/toolchain-archive.py', 'src/sources/toolchains/pnpm.toml', 'tools/dev/curl-platform-flags.sh') }} - - - name: Install verified pnpm - id: install - shell: bash - env: - EXPECTED_NODE_VERSION: ${{ inputs.node-version }} - EXPECTED_PNPM_VERSION: ${{ inputs.pnpm-version }} - OLIPHAUNT_PNPM_CACHE_ROOT: ${{ runner.temp }}/oliphaunt-pnpm-runtime - run: | # zizmor: ignore[github-env] only a fully verified runner-temp path is exported. - set -euo pipefail - installation="$(bash .github/actions/setup-node-pnpm/install-pinned-pnpm.sh)" - observed_node="$(node --version)" - observed_pnpm="$("$installation/bin/pnpm" --version)" - if [[ "$observed_node" != "v$EXPECTED_NODE_VERSION" ]]; then - echo "Expected Node.js v${EXPECTED_NODE_VERSION}; observed ${observed_node}" >&2 - exit 1 - fi - if [[ "$observed_pnpm" != "$EXPECTED_PNPM_VERSION" ]]; then - echo "Expected pnpm ${EXPECTED_PNPM_VERSION}; observed ${observed_pnpm}" >&2 - exit 1 - fi - export_dir="$installation/bin" - output_envelope="$installation" - if [[ "${RUNNER_OS:-}" == "Windows" ]]; then - command -v cygpath >/dev/null 2>&1 - export_dir="$(cygpath -w "$export_dir")" - output_envelope="$(cygpath -w "$installation")" - fi - echo "$export_dir" >> "$GITHUB_PATH" - echo "execution-envelope=$output_envelope" >> "$GITHUB_OUTPUT" - - - name: Save verified pnpm archive - if: ${{ env.HEAVY_CACHE_SAVE_IF == 'true' && steps.restore_verified_pnpm_runtime.outputs.cache-hit != 'true' }} - continue-on-error: true - uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 - with: - path: ${{ runner.temp }}/oliphaunt-pnpm-runtime - key: verified-pnpm-runtime-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.github/actions/setup-node-pnpm/action.yml', '.github/actions/setup-node-pnpm/install-pinned-pnpm.sh', '.github/actions/setup-moon/toolchain-archive.py', 'src/sources/toolchains/pnpm.toml', 'tools/dev/curl-platform-flags.sh') }} diff --git a/.github/actions/setup-node-pnpm/install-pinned-pnpm.sh b/.github/actions/setup-node-pnpm/install-pinned-pnpm.sh deleted file mode 100755 index b6720c242..000000000 --- a/.github/actions/setup-node-pnpm/install-pinned-pnpm.sh +++ /dev/null @@ -1,449 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -fail() { - echo "install-pinned-pnpm.sh: $*" >&2 - exit 1 -} - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || - fail "must run inside the Oliphaunt checkout" -manifest="${OLIPHAUNT_PNPM_MANIFEST:-$root/src/sources/toolchains/pnpm.toml}" -proto_file="${OLIPHAUNT_PNPM_PROTO_FILE:-$root/.prototools}" -extractor="${OLIPHAUNT_PNPM_ARCHIVE_EXTRACTOR:-$root/.github/actions/setup-moon/toolchain-archive.py}" -curl_platform_flags="${OLIPHAUNT_PNPM_CURL_PLATFORM_FLAGS:-$root/tools/dev/curl-platform-flags.sh}" -cache_root="${OLIPHAUNT_PNPM_CACHE_ROOT:-${RUNNER_TEMP:-$root/target}/oliphaunt-pnpm-runtime}" -curl_command="${OLIPHAUNT_PNPM_CURL:-curl}" -testing="${OLIPHAUNT_PNPM_TESTING:-0}" - -for override in \ - OLIPHAUNT_PNPM_MANIFEST \ - OLIPHAUNT_PNPM_PROTO_FILE \ - OLIPHAUNT_PNPM_ARCHIVE_EXTRACTOR \ - OLIPHAUNT_PNPM_CURL_PLATFORM_FLAGS \ - OLIPHAUNT_PNPM_CURL; do - if [ -n "${!override:-}" ] && [ "$testing" != "1" ]; then - fail "$override is test-only" - fi -done - -windows_posix=0 -case "$(uname -s)" in - MINGW* | MSYS* | CYGWIN*) - command -v cygpath >/dev/null 2>&1 || fail "cygpath is required on Windows" - windows_posix=1 - cache_root="$(cygpath -u "$cache_root")" - ;; -esac - -for path in "$manifest" "$proto_file" "$extractor" "$curl_platform_flags"; do - if [ ! -f "$path" ] || [ -L "$path" ]; then - fail "missing regular bootstrap input: $path" - fi -done - -# shellcheck source=tools/dev/curl-platform-flags.sh -. "$curl_platform_flags" - -python="" -for candidate in python3 python; do - if command -v "$candidate" >/dev/null 2>&1; then - python="$candidate" - break - fi -done -[ -n "$python" ] || fail "python3 or python is required for safe archive extraction" -for command_name in "$curl_command" mktemp node; do - command -v "$command_name" >/dev/null 2>&1 || fail "missing required command: $command_name" -done - -manifest_value() { - local source="$1" - local section="$2" - local key="$3" - awk -v wanted_section="$section" -v wanted_key="$key" ' - /^[[:space:]]*\[[^]]+\][[:space:]]*$/ { - current=$0 - gsub(/^[[:space:]]*\[|\][[:space:]]*$/, "", current) - next - } - current == wanted_section && $0 ~ "^[[:space:]]*" wanted_key "[[:space:]]*=" { - count++ - line=$0 - sub(/^[^=]*=[[:space:]]*"/, "", line) - sub(/"[[:space:]]*$/, "", line) - value=line - } - END { - if (count != 1 || value == "") exit 1 - print value - } - ' "$source" -} - -prototool_version() { - awk -F '=' ' - $1 ~ "^[[:space:]]*pnpm[[:space:]]*$" { - count++ - value=$2 - gsub(/^[[:space:]"]+|[[:space:]"]+$/, "", value) - } - END { if (count != 1 || value == "") exit 1; print value } - ' "$proto_file" -} - -validate_version() { - [[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "invalid pnpm version: $1" -} - -validate_sha256() { - if [ "${#1}" -ne 64 ] || [[ "$1" =~ [^0-9a-f] ]]; then - fail "$2 must contain exactly 64 lowercase hexadecimal characters" - fi -} - -validate_sha512() { - if [ "${#1}" -ne 128 ] || [[ "$1" =~ [^0-9a-f] ]]; then - fail "$2 must contain exactly 128 lowercase hexadecimal characters" - fi -} - -validate_count() { - case "$1" in - '' | *[!0-9]*) fail "$2 must be a positive integer" ;; - esac - [ "$1" -gt 0 ] || fail "$2 must be a positive integer" -} - -sha256_file() { - if command -v sha256sum >/dev/null 2>&1; then - sha256sum "$1" | awk '{print $1}' - elif command -v shasum >/dev/null 2>&1; then - shasum -a 256 "$1" | awk '{print $1}' - else - "$python" - "$1" <<'PY' -import hashlib -import pathlib -import sys - -digest = hashlib.sha256() -with pathlib.Path(sys.argv[1]).open("rb") as stream: - while block := stream.read(1024 * 1024): - digest.update(block) -print(digest.hexdigest()) -PY - fi -} - -sha512_file() { - if command -v sha512sum >/dev/null 2>&1; then - sha512sum "$1" | awk '{print $1}' - elif command -v shasum >/dev/null 2>&1; then - shasum -a 512 "$1" | awk '{print $1}' - else - "$python" - "$1" <<'PY' -import hashlib -import pathlib -import sys - -digest = hashlib.sha512() -with pathlib.Path(sys.argv[1]).open("rb") as stream: - while block := stream.read(1024 * 1024): - digest.update(block) -print(digest.hexdigest()) -PY - fi -} - -version="$(manifest_value "$manifest" toolchain version)" || - fail "$manifest must contain exactly one quoted toolchain.version" -url="$(manifest_value "$manifest" package url)" || fail "$manifest is missing package.url" -archive_sha256="$(manifest_value "$manifest" package sha256)" || fail "$manifest is missing package.sha256" -archive_sha512="$(manifest_value "$manifest" package sha512)" || fail "$manifest is missing package.sha512" -archive_bytes="$(manifest_value "$manifest" package bytes)" || fail "$manifest is missing package.bytes" -expanded_bytes="$(manifest_value "$manifest" package expanded_bytes)" || fail "$manifest is missing package.expanded_bytes" -format="$(manifest_value "$manifest" package format)" || fail "$manifest is missing package.format" -prefix="$(manifest_value "$manifest" package prefix)" || fail "$manifest is missing package.prefix" -entry_count="$(manifest_value "$manifest" package entry_count)" || fail "$manifest is missing package.entry_count" -file_count="$(manifest_value "$manifest" package file_count)" || fail "$manifest is missing package.file_count" -tree_sha256="$(manifest_value "$manifest" package tree_sha256)" || fail "$manifest is missing package.tree_sha256" -executable_paths="$(manifest_value "$manifest" package executable_paths)" || fail "$manifest is missing package.executable_paths" -binary_path="$(manifest_value "$manifest" package binary_path)" || fail "$manifest is missing package.binary_path" -binary_sha256="$(manifest_value "$manifest" package binary_sha256)" || fail "$manifest is missing package.binary_sha256" -companion_path="$(manifest_value "$manifest" package companion_path)" || fail "$manifest is missing package.companion_path" -companion_sha256="$(manifest_value "$manifest" package companion_sha256)" || fail "$manifest is missing package.companion_sha256" -payload_path="$(manifest_value "$manifest" package payload_path)" || fail "$manifest is missing package.payload_path" -payload_sha256="$(manifest_value "$manifest" package payload_sha256)" || fail "$manifest is missing package.payload_sha256" - -validate_version "$version" -configured="$(prototool_version)" || fail "$proto_file must contain exactly one pnpm version" -configured="${configured#v}" -[ "$configured" = "$version" ] || - fail "$proto_file pnpm version $configured does not match pinned version $version" -if [ -n "${EXPECTED_PNPM_VERSION:-}" ]; then - validate_version "$EXPECTED_PNPM_VERSION" - [ "$EXPECTED_PNPM_VERSION" = "$version" ] || - fail "requested pnpm $EXPECTED_PNPM_VERSION does not match pinned version $version" -fi - -expected_url="https://registry.npmjs.org/pnpm/-/pnpm-$version.tgz" -expected_executable_paths="bin/pnpm.mjs,bin/pnpx.mjs,dist/node-gyp-bin/node-gyp,dist/node-gyp-bin/node-gyp.cmd,dist/node_modules/node-gyp/bin/node-gyp.js" -[ "$url" = "$expected_url" ] || fail "$manifest package.url must be $expected_url" -[ "$format" = "tar.gz" ] || fail "$manifest package.format must be tar.gz" -[ "$prefix" = "package" ] || fail "$manifest package.prefix must be package" -[ "$binary_path" = "bin/pnpm.mjs" ] || fail "$manifest package.binary_path must be bin/pnpm.mjs" -[ "$companion_path" = "bin/pnpx.mjs" ] || fail "$manifest package.companion_path must be bin/pnpx.mjs" -[ "$payload_path" = "dist/pnpm.mjs" ] || fail "$manifest package.payload_path must be dist/pnpm.mjs" -[ "$executable_paths" = "$expected_executable_paths" ] || - fail "$manifest package.executable_paths must be $expected_executable_paths" -IFS=',' read -r -a executables <<<"$executable_paths" -for digest in "$archive_sha256" "$tree_sha256" "$binary_sha256" "$companion_sha256" "$payload_sha256"; do - validate_sha256 "$digest" "$manifest package digest" -done -validate_sha512 "$archive_sha512" "$manifest package.sha512" -for value in "$archive_bytes" "$expanded_bytes" "$entry_count" "$file_count"; do - validate_count "$value" "$manifest package count" -done - -case "$cache_root" in - '' | /) fail "unsafe pnpm cache root: $cache_root" ;; -esac -if [ -L "$cache_root" ]; then - fail "pnpm cache root must not be a symbolic link: $cache_root" -fi -umask 077 -mkdir -p "$cache_root" -if [ ! -d "$cache_root" ] || [ -L "$cache_root" ]; then - fail "pnpm cache root is not a real directory: $cache_root" -fi -archive_root="$cache_root/archives" -installations_root="$cache_root/installations" -for path in "$archive_root" "$installations_root"; do - [ ! -L "$path" ] || fail "pnpm cache must not contain symbolic-link directories: $path" - mkdir -p "$path" - if [ ! -d "$path" ] || [ -L "$path" ]; then - fail "pnpm cache path is not a real directory: $path" - fi -done - -curl_tls_flag="$(oliphaunt_curl_platform_tls_flag)" -curl_common=( - --fail --location --silent --show-error - --proto '=https' --proto-redir '=https' --tlsv1.2 - --retry 5 --retry-all-errors --retry-connrefused --retry-delay 2 --retry-max-time 300 - --connect-timeout 20 --max-time 300 --speed-limit 1024 --speed-time 30 - --remove-on-error -) -if [ -n "$curl_tls_flag" ]; then - curl_common+=("$curl_tls_flag") -fi - -download_verified() { - local output="$1" - local actual_size - if [ -f "$output" ] && [ ! -L "$output" ]; then - actual_size="$(wc -c <"$output" | tr -d '[:space:]')" - if [ "$actual_size" = "$archive_bytes" ] && - [ "$(sha256_file "$output")" = "$archive_sha256" ] && - [ "$(sha512_file "$output")" = "$archive_sha512" ]; then - return 0 - fi - fi - rm -f "$output" - local partial - local rc=0 - partial="$(mktemp "$archive_root/.download.XXXXXX")" - local args=("${curl_common[@]}" --max-filesize "$archive_bytes" --output "$partial" "$url") - if "$curl_command" "${args[@]}"; then - : - else - rc=$? - rm -f "$partial" - return "$rc" - fi - actual_size="$(wc -c <"$partial" | tr -d '[:space:]')" - [ "$actual_size" = "$archive_bytes" ] || { - rm -f "$partial" - fail "downloaded byte-size mismatch for $url: expected $archive_bytes, got $actual_size" - } - [ "$(sha256_file "$partial")" = "$archive_sha256" ] || { - rm -f "$partial" - fail "downloaded SHA-256 mismatch for $url" - } - [ "$(sha512_file "$partial")" = "$archive_sha512" ] || { - rm -f "$partial" - fail "downloaded SHA-512 mismatch for $url" - } - chmod 0444 "$partial" - mv "$partial" "$output" -} - -identity="pnpm-$version-$archive_sha256" -install_parent="$installations_root/$identity" -[ ! -L "$install_parent" ] || fail "pnpm installation parent must not be a symbolic link" -mkdir -p "$install_parent" -if [ ! -d "$install_parent" ] || [ -L "$install_parent" ]; then - fail "pnpm installation parent is not a real directory" -fi -final="$install_parent/verified" -receipt_text="$(printf 'pnpm_version=%s\narchive_sha256=%s\narchive_sha512=%s\ntree_sha256=%s' \ - "$version" "$archive_sha256" "$archive_sha512" "$tree_sha256")" -# These literal lines become the cached wrapper. -# shellcheck disable=SC2016 -pnpm_wrapper_text="$(printf '%s\n' \ - '#!/usr/bin/env bash' \ - 'set -euo pipefail' \ - 'script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"' \ - 'cli_path="$script_dir/../pnpm/bin/pnpm.mjs"' \ - 'case "$(uname -s)" in' \ - ' MINGW* | MSYS* | CYGWIN*)' \ - ' command -v cygpath >/dev/null 2>&1 || { echo "pnpm: cygpath is required on Windows" >&2; exit 1; }' \ - ' cli_path="$(cygpath -aw "$cli_path")"' \ - ' ;;' \ - 'esac' \ - 'exec node "$cli_path" "$@"')" -# These literal lines become the cached wrapper. -# shellcheck disable=SC2016 -pnpx_wrapper_text="$(printf '%s\n' \ - '#!/usr/bin/env bash' \ - 'set -euo pipefail' \ - 'script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"' \ - 'cli_path="$script_dir/../pnpm/bin/pnpx.mjs"' \ - 'case "$(uname -s)" in' \ - ' MINGW* | MSYS* | CYGWIN*)' \ - ' command -v cygpath >/dev/null 2>&1 || { echo "pnpx: cygpath is required on Windows" >&2; exit 1; }' \ - ' cli_path="$(cygpath -aw "$cli_path")"' \ - ' ;;' \ - 'esac' \ - 'exec node "$cli_path" "$@"')" -pnpm_cmd_text="$(printf '%s\r\n' '@ECHO OFF' 'node "%~dp0..\pnpm\bin\pnpm.mjs" %*')" -pnpx_cmd_text="$(printf '%s\r\n' '@ECHO OFF' 'node "%~dp0..\pnpm\bin\pnpx.mjs" %*')" - -node_script_version() { - local script="$1" - if [ "$windows_posix" = "1" ]; then - script="$(cygpath -aw "$script")" || return 1 - MSYS2_ARG_CONV_EXCL='*' node "$script" --version - else - node "$script" --version - fi -} - -cache_valid() { - local candidate="$1" - [ -d "$candidate" ] && [ ! -L "$candidate" ] || return 1 - [ "$(find "$candidate" -mindepth 1 -maxdepth 1 | wc -l | tr -d '[:space:]')" = "3" ] || return 1 - [ -d "$candidate/bin" ] && [ ! -L "$candidate/bin" ] || return 1 - [ -d "$candidate/pnpm" ] && [ ! -L "$candidate/pnpm" ] || return 1 - [ "$(find "$candidate/bin" -mindepth 1 -maxdepth 1 | wc -l | tr -d '[:space:]')" = "4" ] || return 1 - for path in \ - "$candidate/pnpm/$binary_path" \ - "$candidate/pnpm/$companion_path" \ - "$candidate/pnpm/$payload_path" \ - "$candidate/bin/pnpm" \ - "$candidate/bin/pnpx" \ - "$candidate/bin/pnpm.cmd" \ - "$candidate/bin/pnpx.cmd" \ - "$candidate/receipt"; do - [ -f "$path" ] && [ ! -L "$path" ] || return 1 - done - [ "$(sha256_file "$candidate/pnpm/$binary_path")" = "$binary_sha256" ] || return 1 - [ "$(sha256_file "$candidate/pnpm/$companion_path")" = "$companion_sha256" ] || return 1 - [ "$(sha256_file "$candidate/pnpm/$payload_path")" = "$payload_sha256" ] || return 1 - [ "$(cat "$candidate/bin/pnpm")" = "$pnpm_wrapper_text" ] || return 1 - [ "$(cat "$candidate/bin/pnpx")" = "$pnpx_wrapper_text" ] || return 1 - [ "$(cat "$candidate/bin/pnpm.cmd")" = "$pnpm_cmd_text" ] || return 1 - [ "$(cat "$candidate/bin/pnpx.cmd")" = "$pnpx_cmd_text" ] || return 1 - if [ "$(uname -s)" != "Windows_NT" ]; then - [ -x "$candidate/bin/pnpm" ] && [ -x "$candidate/bin/pnpx" ] || return 1 - fi - local tree_result - local tree_args=(tree-digest --root "$candidate/pnpm") - local executable - for executable in "${executables[@]}"; do - tree_args+=(--executable "$executable") - done - tree_result="$("$python" "$extractor" "${tree_args[@]}" 2>/dev/null)" || return 1 - [ "$tree_result" = "$file_count $tree_sha256" ] || return 1 - [ "$(node_script_version "$candidate/pnpm/$binary_path" 2>/dev/null | awk 'NF { print $1; exit }')" = "$version" ] || return 1 - [ "$(cat "$candidate/receipt")" = "$receipt_text" ] || return 1 -} - -if cache_valid "$final"; then - printf '%s\n' "$final" - exit 0 -fi - -archive="$archive_root/$archive_sha256.tgz" -download_verified "$archive" - -stage="$(mktemp -d "$install_parent/.verified.stage.XXXXXX")" -backup="" -old_moved=0 -cleanup() { - local rc="$?" - trap - EXIT HUP INT TERM - if [ -n "$stage" ]; then - rm -rf "$stage" - fi - if [ "$old_moved" = "1" ] && [ -n "$backup" ] && [ -e "$backup" ] && [ ! -e "$final" ]; then - mv "$backup" "$final" || rc=1 - elif [ -n "$backup" ]; then - rm -rf "$backup" - fi - exit "$rc" -} -trap cleanup EXIT -trap 'exit 129' HUP -trap 'exit 130' INT -trap 'exit 143' TERM - -extract_args=( - extract - --archive "$archive" - --format "$format" - --prefix "$prefix" - --entry-count "$entry_count" - --expected-bytes "$archive_bytes" - --expanded-bytes "$expanded_bytes" - --destination "$stage/pnpm" - --required "$binary_path" - --required "$companion_path" - --required "$payload_path" - --required package.json -) -for executable in "${executables[@]}"; do - extract_args+=(--required "$executable" --executable "$executable") -done -"$python" "$extractor" "${extract_args[@]}" - -mkdir -p "$stage/bin" -printf '%s\n' "$pnpm_wrapper_text" >"$stage/bin/pnpm" -printf '%s\n' "$pnpx_wrapper_text" >"$stage/bin/pnpx" -printf '%s\n' "$pnpm_cmd_text" >"$stage/bin/pnpm.cmd" -printf '%s\n' "$pnpx_cmd_text" >"$stage/bin/pnpx.cmd" -chmod 0555 "$stage/bin/pnpm" "$stage/bin/pnpx" -chmod 0444 "$stage/bin/pnpm.cmd" "$stage/bin/pnpx.cmd" -printf '%s\n' "$receipt_text" >"$stage/receipt" -chmod 0444 "$stage/receipt" - -cache_valid "$stage" || fail "staged pnpm installation failed integrity or version validation" - -if [ -e "$final" ] || [ -L "$final" ]; then - backup="$(mktemp -d "$install_parent/.verified.backup.XXXXXX")" - rmdir "$backup" - mv "$final" "$backup" - old_moved=1 -fi -if [ "${OLIPHAUNT_PNPM_TEST_INTERRUPT_AFTER_BACKUP:-0}" = "1" ]; then - [ "$testing" = "1" ] || fail "OLIPHAUNT_PNPM_TEST_INTERRUPT_AFTER_BACKUP is test-only" - kill -TERM "$$" -fi -mv "$stage" "$final" -stage="" -if [ "$old_moved" = "1" ]; then - rm -rf "$backup" - backup="" - old_moved=0 -fi -printf '%s\n' "$final" diff --git a/.github/actions/setup-node-pnpm/install-pinned-pnpm.test.sh b/.github/actions/setup-node-pnpm/install-pinned-pnpm.test.sh deleted file mode 100755 index 198f327ac..000000000 --- a/.github/actions/setup-node-pnpm/install-pinned-pnpm.test.sh +++ /dev/null @@ -1,356 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -fail() { - echo "install-pinned-pnpm.test.sh: $*" >&2 - exit 1 -} - -root="$(git rev-parse --show-toplevel)" -installer="$root/.github/actions/setup-node-pnpm/install-pinned-pnpm.sh" -extractor="$root/.github/actions/setup-moon/toolchain-archive.py" -curl_flags="$root/tools/dev/curl-platform-flags.sh" -tmp="$(mktemp -d)" -trap 'rm -rf "$tmp"' EXIT HUP INT TERM - -fixture="$tmp/pnpm-11.5.0.tgz" -manifest="$tmp/pnpm.toml" -proto_file="$tmp/prototools" -metadata="$tmp/metadata.env" -"${PYTHON:-python3}" - "$fixture" "$manifest" "$metadata" <<'PY' -import hashlib -import io -import pathlib -import sys -import tarfile - -archive = pathlib.Path(sys.argv[1]) -manifest = pathlib.Path(sys.argv[2]) -metadata = pathlib.Path(sys.argv[3]) -version = "11.5.0" -files = { - "bin/pnpm.mjs": ( - b"#!/usr/bin/env node\n" - b"console.log(process.env.OLIPHAUNT_WRAPPER_ARGV_PROBE === '1' " - b"? JSON.stringify(process.argv.slice(2)) : '11.5.0');\n" - ), - "bin/pnpx.mjs": ( - b"#!/usr/bin/env node\n" - b"console.log(process.env.OLIPHAUNT_WRAPPER_ARGV_PROBE === '1' " - b"? JSON.stringify(process.argv.slice(2)) : '11.5.0');\n" - ), - "dist/node-gyp-bin/node-gyp": b"#!/usr/bin/env sh\nexit 0\n", - "dist/node-gyp-bin/node-gyp.cmd": b"@ECHO OFF\r\nEXIT /B 0\r\n", - "dist/node_modules/node-gyp/bin/node-gyp.js": b"#!/usr/bin/env node\nprocess.exit(0);\n", - "dist/pnpm.mjs": b"export const fixture = true;\n", - "package.json": b'{"name":"pnpm","version":"11.5.0"}\n', -} -executables = { - "bin/pnpm.mjs", - "bin/pnpx.mjs", - "dist/node-gyp-bin/node-gyp", - "dist/node-gyp-bin/node-gyp.cmd", - "dist/node_modules/node-gyp/bin/node-gyp.js", -} -directories = {"package"} -for relative in files: - parts = pathlib.PurePosixPath("package", relative).parts - directories.update("/".join(parts[:depth]) for depth in range(2, len(parts))) - -with tarfile.open(archive, "w:gz", format=tarfile.USTAR_FORMAT) as stream: - for directory in sorted(directories, key=lambda value: value.encode("utf-8")): - info = tarfile.TarInfo(f"{directory}/") - info.type = tarfile.DIRTYPE - info.mode = 0o755 - info.mtime = 0 - info.uid = info.gid = 0 - info.uname = info.gname = "" - stream.addfile(info) - for relative, content in sorted(files.items(), key=lambda item: item[0].encode("utf-8")): - info = tarfile.TarInfo(f"package/{relative}") - info.type = tarfile.REGTYPE - info.size = len(content) - info.mode = 0o755 if relative in executables else 0o644 - info.mtime = 0 - info.uid = info.gid = 0 - info.uname = info.gname = "" - stream.addfile(info, io.BytesIO(content)) - -archive_bytes = archive.read_bytes() -archive_sha256 = hashlib.sha256(archive_bytes).hexdigest() -archive_sha512 = hashlib.sha512(archive_bytes).hexdigest() -tree = hashlib.sha256(b"oliphaunt-bootstrap-tree-v2\0") -for relative, content in sorted(files.items(), key=lambda item: item[0].encode("utf-8")): - tree.update(relative.encode("utf-8")) - tree.update(b"\0") - tree.update(str(len(content)).encode("ascii")) - tree.update(b"\0") - tree.update(b"x" if relative in executables else b"-") - tree.update(b"\0") - tree.update(content) - tree.update(b"\0") - -executable_paths = ( - "bin/pnpm.mjs,bin/pnpx.mjs,dist/node-gyp-bin/node-gyp," - "dist/node-gyp-bin/node-gyp.cmd,dist/node_modules/node-gyp/bin/node-gyp.js" -) -manifest.write_text( - f'''[toolchain] -version = "{version}" - -[package] -url = "https://registry.npmjs.org/pnpm/-/pnpm-{version}.tgz" -sha256 = "{archive_sha256}" -sha512 = "{archive_sha512}" -bytes = "{len(archive_bytes)}" -expanded_bytes = "{sum(map(len, files.values()))}" -format = "tar.gz" -prefix = "package" -entry_count = "{len(directories) + len(files)}" -file_count = "{len(files)}" -tree_sha256 = "{tree.hexdigest()}" -executable_paths = "{executable_paths}" -binary_path = "bin/pnpm.mjs" -binary_sha256 = "{hashlib.sha256(files['bin/pnpm.mjs']).hexdigest()}" -companion_path = "bin/pnpx.mjs" -companion_sha256 = "{hashlib.sha256(files['bin/pnpx.mjs']).hexdigest()}" -payload_path = "dist/pnpm.mjs" -payload_sha256 = "{hashlib.sha256(files['dist/pnpm.mjs']).hexdigest()}" -''', - encoding="utf-8", -) -metadata.write_text( - f"ARCHIVE_SHA256={archive_sha256}\nARCHIVE_BYTES={len(archive_bytes)}\n", - encoding="utf-8", -) -PY -printf '%s\n' 'pnpm = "11.5.0"' >"$proto_file" -# shellcheck source=/dev/null -. "$metadata" - -fake_curl="$tmp/curl" -# These literal lines become the fake curl script. -# shellcheck disable=SC2016 -printf '%s\n' \ - '#!/usr/bin/env bash' \ - 'set -euo pipefail' \ - ': "${FAKE_CURL_LOG:?}" "${FAKE_CURL_SOURCE:?}"' \ - 'printf "%s\n" "" >> "$FAKE_CURL_LOG"' \ - 'for argument in "$@"; do printf "<%s>\n" "$argument" >> "$FAKE_CURL_LOG"; done' \ - 'output=""' \ - 'url=""' \ - 'bound=""' \ - 'while (( $# )); do' \ - ' case "$1" in' \ - ' --output) output="$2"; shift 2 ;;' \ - ' --max-filesize) bound="$2"; shift 2 ;;' \ - ' https://*) url="$1"; shift ;;' \ - ' *) shift ;;' \ - ' esac' \ - 'done' \ - '[[ -n "$output" && -n "$url" && -n "$bound" ]]' \ - 'case "${FAKE_CURL_MODE:-copy}" in' \ - ' copy) cp "$FAKE_CURL_SOURCE" "$output" ;;' \ - ' bad) printf "%s" bad > "$output" ;;' \ - ' corrupt) cp "$FAKE_CURL_SOURCE" "$output"; printf Z | dd of="$output" bs=1 seek=1 count=1 conv=notrunc 2>/dev/null ;;' \ - ' fail) exit 97 ;;' \ - ' *) exit 98 ;;' \ - 'esac' >"$fake_curl" -chmod 0555 "$fake_curl" - -cache="$tmp/cache with spaces" -curl_log="$tmp/curl.log" -run_install() { - local selected_cache="$1" - local mode="${2:-copy}" - local selected_manifest="${3:-$manifest}" - env \ - EXPECTED_PNPM_VERSION=11.5.0 \ - FAKE_CURL_LOG="$curl_log" \ - FAKE_CURL_MODE="$mode" \ - FAKE_CURL_SOURCE="$fixture" \ - OLIPHAUNT_PNPM_ARCHIVE_EXTRACTOR="$extractor" \ - OLIPHAUNT_PNPM_CACHE_ROOT="$selected_cache" \ - OLIPHAUNT_PNPM_CURL="$fake_curl" \ - OLIPHAUNT_PNPM_CURL_PLATFORM_FLAGS="$curl_flags" \ - OLIPHAUNT_PNPM_MANIFEST="$selected_manifest" \ - OLIPHAUNT_PNPM_PROTO_FILE="$proto_file" \ - OLIPHAUNT_PNPM_TESTING=1 \ - RUNNER_OS=Windows \ - bash "$installer" -} - -installation="$(run_install "$cache")" -[ "$("$installation/bin/pnpm" --version)" = "11.5.0" ] || fail "fixture pnpm version mismatch" -[ "$("$installation/bin/pnpx" --version)" = "11.5.0" ] || fail "fixture pnpx version mismatch" -expected_argv='["--flag","value with spaces","/path-like/argument"]' -for command_name in pnpm pnpx; do - observed_argv="$( - OLIPHAUNT_WRAPPER_ARGV_PROBE=1 \ - "$installation/bin/$command_name" --flag "value with spaces" "/path-like/argument" - )" - [ "$observed_argv" = "$expected_argv" ] || - fail "$command_name wrapper did not preserve structured caller arguments" -done -grep -Fq 'cli_path="$(cygpath -aw "$cli_path")"' "$installation/bin/pnpm" || - fail "pnpm wrapper does not explicitly convert its internal Windows script path" -grep -Fq 'cli_path="$(cygpath -aw "$cli_path")"' "$installation/bin/pnpx" || - fail "pnpx wrapper does not explicitly convert its internal Windows script path" -grep -Fq 'exec node "$cli_path" "$@"' "$installation/bin/pnpm" || - fail "pnpm wrapper does not preserve structured caller arguments" -grep -Fq 'exec node "$cli_path" "$@"' "$installation/bin/pnpx" || - fail "pnpx wrapper does not preserve structured caller arguments" -if [ -e "$installation/plugins" ] || [ -e "$installation/moon" ]; then - fail "standalone installation unexpectedly contains Moon material" -fi -[ "$(grep -Fxc '' "$curl_log")" = "1" ] || fail "initial install did not perform one download" -for expected in \ - '<--fail>' \ - '<--location>' \ - '<--proto>' \ - '<=https>' \ - '<--proto-redir>' \ - '<--tlsv1.2>' \ - '<--retry-all-errors>' \ - '<--retry-connrefused>' \ - '<--connect-timeout>' \ - '<--max-time>' \ - '<--speed-limit>' \ - '<--speed-time>' \ - '<--remove-on-error>' \ - '<--ssl-revoke-best-effort>' \ - '<--max-filesize>' \ - "<$ARCHIVE_BYTES>" \ - ''; do - grep -Fqx "$expected" "$curl_log" || fail "curl invocation omitted $expected" -done - -rm -f "$curl_log" -cached="$(run_install "$cache" fail)" -[ "$cached" = "$installation" ] || fail "cache hit changed the installation path" -[ ! -e "$curl_log" ] || fail "valid cache hit attempted network access" - -chmod 0644 "$installation/pnpm/dist/pnpm.mjs" -printf '%s\n' 'tampered payload' >"$installation/pnpm/dist/pnpm.mjs" -rm -f "$curl_log" -repaired="$(run_install "$cache" fail)" -[ "$repaired" = "$installation" ] || fail "tree repair changed the installation path" -[ ! -e "$curl_log" ] || fail "tree repair ignored the verified archive cache" -[ "$("$installation/bin/pnpm" --version)" = "11.5.0" ] || fail "tree repair did not restore pnpm" - -chmod 0644 "$installation/pnpm/bin/pnpm.mjs" -rm -f "$curl_log" -run_install "$cache" fail >/dev/null -[ ! -e "$curl_log" ] || fail "mode repair ignored the verified archive cache" -[ -x "$installation/pnpm/bin/pnpm.mjs" ] || fail "executable-mode repair did not restore pnpm" - -chmod 0755 "$installation/bin/pnpm" -printf '%s\n' '#!/usr/bin/env bash' 'echo injected' >"$installation/bin/pnpm" -rm -f "$curl_log" -run_install "$cache" fail >/dev/null -[ ! -e "$curl_log" ] || fail "wrapper repair ignored the verified archive cache" -[ "$("$installation/bin/pnpm" --version)" = "11.5.0" ] || fail "wrapper repair did not restore pnpm" - -rm -rf "$installation" -chmod 0644 "$cache/archives/$ARCHIVE_SHA256.tgz" -printf '%s\n' corrupt >"$cache/archives/$ARCHIVE_SHA256.tgz" -rm -f "$curl_log" -installation="$(run_install "$cache")" -[ "$(grep -Fxc '' "$curl_log")" = "1" ] || fail "corrupt archive was not redownloaded once" -[ "$("$installation/bin/pnpm" --version)" = "11.5.0" ] || fail "corrupt archive repair failed" - -bad_cache="$tmp/bad-cache" -rm -f "$curl_log" -if run_install "$bad_cache" bad >"$tmp/bad.out" 2>"$tmp/bad.err"; then - fail "size-invalid download was accepted" -fi -if find "$bad_cache/installations" -type d -name verified -print -quit 2>/dev/null | grep -q .; then - fail "size-invalid download committed an installation" -fi - -corrupt_cache="$tmp/corrupt-cache" -rm -f "$curl_log" -if run_install "$corrupt_cache" corrupt >"$tmp/corrupt.out" 2>"$tmp/corrupt.err"; then - fail "same-size SHA-256-invalid download was accepted" -fi -grep -Fq 'downloaded SHA-256 mismatch' "$tmp/corrupt.err" || - fail "same-size corrupt download did not fail at SHA-256 verification" -if find "$corrupt_cache/installations" -type d -name verified -print -quit 2>/dev/null | grep -q .; then - fail "SHA-256-invalid download committed an installation" -fi - -wrong_sha512_manifest="$tmp/wrong-sha512.toml" -zeros="$(printf '0%.0s' {1..128})" -sed "s/^sha512 = \".*\"$/sha512 = \"$zeros\"/" "$manifest" >"$wrong_sha512_manifest" -sha512_cache="$tmp/sha512-cache" -rm -f "$curl_log" -if run_install "$sha512_cache" copy "$wrong_sha512_manifest" >"$tmp/sha512.out" 2>"$tmp/sha512.err"; then - fail "SHA-512-invalid manifest was accepted" -fi -grep -Fq 'downloaded SHA-512 mismatch' "$tmp/sha512.err" || - fail "SHA-512 mismatch did not reach SHA-512 verification" -if find "$sha512_cache/installations" -type d -name verified -print -quit 2>/dev/null | grep -q .; then - fail "SHA-512-invalid download committed an installation" -fi - -chmod 0755 "$installation/bin/pnpm" -printf '%s\n' '#!/usr/bin/env bash' 'echo preserved-after-interrupt' >"$installation/bin/pnpm" -rm -f "$curl_log" -if env \ - EXPECTED_PNPM_VERSION=11.5.0 \ - FAKE_CURL_LOG="$curl_log" \ - FAKE_CURL_MODE=fail \ - FAKE_CURL_SOURCE="$fixture" \ - OLIPHAUNT_PNPM_ARCHIVE_EXTRACTOR="$extractor" \ - OLIPHAUNT_PNPM_CACHE_ROOT="$cache" \ - OLIPHAUNT_PNPM_CURL="$fake_curl" \ - OLIPHAUNT_PNPM_CURL_PLATFORM_FLAGS="$curl_flags" \ - OLIPHAUNT_PNPM_MANIFEST="$manifest" \ - OLIPHAUNT_PNPM_PROTO_FILE="$proto_file" \ - OLIPHAUNT_PNPM_TEST_INTERRUPT_AFTER_BACKUP=1 \ - OLIPHAUNT_PNPM_TESTING=1 \ - RUNNER_OS=Windows \ - bash "$installer" >"$tmp/interrupt.out" 2>"$tmp/interrupt.err"; then - fail "test interrupt unexpectedly succeeded" -fi -grep -Fq 'preserved-after-interrupt' "$installation/bin/pnpm" || - fail "transactional interrupt did not restore the prior installation" -[ ! -e "$curl_log" ] || fail "transactional repair ignored the verified archive cache" -if find "$(dirname "$installation")" -mindepth 1 -maxdepth 1 -name '.verified.*' -print -quit | grep -q .; then - fail "transactional interrupt left a staging or backup directory" -fi -run_install "$cache" fail >/dev/null - -wrong_manifest="$tmp/wrong-url.toml" -sed 's#https://registry.npmjs.org/pnpm/-/pnpm-11.5.0.tgz#https://example.invalid/pnpm.tgz#' \ - "$manifest" >"$wrong_manifest" -rm -f "$curl_log" -if env \ - EXPECTED_PNPM_VERSION=11.5.0 \ - FAKE_CURL_LOG="$curl_log" \ - FAKE_CURL_SOURCE="$fixture" \ - OLIPHAUNT_PNPM_CACHE_ROOT="$tmp/wrong-url-cache" \ - OLIPHAUNT_PNPM_CURL="$fake_curl" \ - OLIPHAUNT_PNPM_MANIFEST="$wrong_manifest" \ - OLIPHAUNT_PNPM_PROTO_FILE="$proto_file" \ - OLIPHAUNT_PNPM_TESTING=1 \ - bash "$installer" >"$tmp/url.out" 2>"$tmp/url.err"; then - fail "non-canonical pnpm URL was accepted" -fi -[ ! -e "$curl_log" ] || fail "non-canonical URL reached the downloader" - -if OLIPHAUNT_PNPM_MANIFEST="$manifest" bash "$installer" >"$tmp/gate.out" 2>"$tmp/gate.err"; then - fail "test manifest override was accepted outside test mode" -fi -grep -Fq 'OLIPHAUNT_PNPM_MANIFEST is test-only' "$tmp/gate.err" || - fail "test override gate failed unclearly" - -mkdir "$tmp/real-cache-root" -ln -s "$tmp/real-cache-root" "$tmp/symlink-cache" -rm -f "$curl_log" -if run_install "$tmp/symlink-cache" >"$tmp/symlink.out" 2>"$tmp/symlink.err"; then - fail "symbolic-link cache root was accepted" -fi -[ ! -e "$curl_log" ] || fail "symbolic-link cache root reached the downloader" - -printf '%s\n' "Pinned standalone pnpm bootstrap fault tests passed." diff --git a/.github/actions/setup-node-runtime/action.yml b/.github/actions/setup-node-runtime/action.yml index b250e022f..52c36fc9d 100644 --- a/.github/actions/setup-node-runtime/action.yml +++ b/.github/actions/setup-node-runtime/action.yml @@ -1,12 +1,6 @@ name: Set up verified Node.js runtime description: Install the exact digest-verified Node.js runtime pinned by Oliphaunt. -inputs: - node-version: - description: Exact Node.js version expected from the repository pin. - required: false - default: "22.22.3" - outputs: execution-envelope: description: Absolute digest-verified Node.js execution envelope. @@ -20,22 +14,16 @@ runs: uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: path: ${{ runner.temp }}/oliphaunt-node-runtime - key: verified-node-runtime-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.github/actions/setup-node-runtime/action.yml', '.github/actions/setup-moon/install-pinned-node.sh', '.github/actions/setup-moon/toolchain-archive.py', 'src/sources/toolchains/node-runtime.toml', 'tools/dev/curl-platform-flags.sh') }} + key: verified-node-runtime-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.github/actions/setup-node-runtime/action.yml', '.github/actions/setup-moon/install-pinned-node.sh', 'tools/dev/node-runtime.toml', 'tools/dev/extract-pinned-binary.sh', 'tools/dev/curl-platform-flags.sh') }} - name: Install verified Node.js runtime id: install shell: bash env: - EXPECTED_NODE_VERSION: ${{ inputs.node-version }} OLIPHAUNT_NODE_RUNTIME_CACHE_ROOT: ${{ runner.temp }}/oliphaunt-node-runtime run: | # zizmor: ignore[github-env] only a digest-verified runner-temp path is exported. set -euo pipefail binary="$(bash .github/actions/setup-moon/install-pinned-node.sh)" - observed="$($binary --version)" - if [[ "$observed" != "v$EXPECTED_NODE_VERSION" ]]; then - echo "Expected Node.js v${EXPECTED_NODE_VERSION}; observed ${observed}" >&2 - exit 1 - fi export_dir="$(dirname "$binary")" execution_envelope="$(cd "$export_dir/.." && pwd -P)" output_envelope="$execution_envelope" @@ -48,9 +36,9 @@ runs: echo "execution-envelope=$output_envelope" >> "$GITHUB_OUTPUT" - name: Save verified Node.js archive - if: ${{ env.HEAVY_CACHE_SAVE_IF == 'true' && steps.restore_verified_node_runtime.outputs.cache-hit != 'true' }} + if: ${{ steps.restore_verified_node_runtime.outputs.cache-hit != 'true' }} continue-on-error: true uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: path: ${{ runner.temp }}/oliphaunt-node-runtime - key: verified-node-runtime-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.github/actions/setup-node-runtime/action.yml', '.github/actions/setup-moon/install-pinned-node.sh', '.github/actions/setup-moon/toolchain-archive.py', 'src/sources/toolchains/node-runtime.toml', 'tools/dev/curl-platform-flags.sh') }} + key: verified-node-runtime-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.prototools', '.github/actions/setup-node-runtime/action.yml', '.github/actions/setup-moon/install-pinned-node.sh', 'tools/dev/node-runtime.toml', 'tools/dev/extract-pinned-binary.sh', 'tools/dev/curl-platform-flags.sh') }} diff --git a/.github/actions/setup-npm-publisher/action.yml b/.github/actions/setup-npm-publisher/action.yml index 3e66bad32..a2168f53b 100644 --- a/.github/actions/setup-npm-publisher/action.yml +++ b/.github/actions/setup-npm-publisher/action.yml @@ -25,7 +25,7 @@ runs: uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: path: ${{ runner.temp }}/oliphaunt-npm-publisher - key: verified-npm-publisher-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.github/actions/setup-npm-publisher/action.yml', '.github/actions/setup-npm-publisher/install.sh', '.github/actions/setup-moon/toolchain-archive.py', 'src/sources/toolchains/npm-publisher.toml', 'tools/dev/curl-platform-flags.sh') }} + key: verified-npm-publisher-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.github/actions/setup-npm-publisher/action.yml', '.github/actions/setup-npm-publisher/install.sh', '.github/actions/setup-moon/toolchain-archive.mts', 'tools/release/npm-publisher.toml', 'tools/packaging/portable-archive.mts', 'tools/dev/curl-platform-flags.sh') }} - name: Install exact npm publisher id: install @@ -42,7 +42,7 @@ runs: node_launcher="$(cygpath -u "$node_launcher")" fi npm_cli_fs="$(cd "$publisher_bin/../npm/bin" && pwd -P)/npm-cli.js" - verifier_fs="$(pwd -P)/tools/release/npm-trusted-publishing-runtime.mjs" + verifier_fs="$(pwd -P)/tools/release/npm-trusted-publishing-runtime.mts" execution_envelope="$(cd "$publisher_bin/.." && pwd -P)" if [[ "$node_launcher" != /* || ! -f "$node_launcher" || -L "$node_launcher" ]]; then echo "The verified Node.js launcher is not a regular absolute path: ${node_launcher}" >&2 @@ -59,15 +59,15 @@ runs: run_native_node() { MSYS2_ARG_CONV_EXCL='*' "$node_launcher" "$@" } - node_executable="$( - run_native_node -e 'process.stdout.write(process.execPath)' - )" npm_cli="$npm_cli_fs" verifier="$verifier_fs" + node_info="$(pwd -P)/tools/dev/node-info.mts" if [[ "${RUNNER_OS:-}" == "Windows" ]]; then npm_cli="$(cygpath -aw "$npm_cli_fs")" verifier="$(cygpath -aw "$verifier_fs")" + node_info="$(cygpath -aw "$node_info")" fi + node_executable="$(run_native_node "$node_info" executable)" node_version="$(run_native_node --version)" npm_version="$(run_native_node "$npm_cli" --version)" if [[ "$npm_version" != "$NPM_PUBLISHER_VERSION" ]]; then @@ -77,8 +77,6 @@ runs: run_native_node "$verifier" check-runtime \ --node "$node_version" \ --npm "$npm_version" - run_native_node "$verifier" check-trust-cli \ - --npm-cli "$npm_cli" export_dir="$publisher_bin" output_node="$node_executable" output_npm_cli="$npm_cli" @@ -95,9 +93,9 @@ runs: } >> "$GITHUB_OUTPUT" - name: Save verified npm publisher archive - if: ${{ env.HEAVY_CACHE_SAVE_IF == 'true' && steps.restore_verified_npm_publisher.outputs.cache-hit != 'true' }} + if: ${{ steps.restore_verified_npm_publisher.outputs.cache-hit != 'true' }} continue-on-error: true uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 with: path: ${{ runner.temp }}/oliphaunt-npm-publisher - key: verified-npm-publisher-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.github/actions/setup-npm-publisher/action.yml', '.github/actions/setup-npm-publisher/install.sh', '.github/actions/setup-moon/toolchain-archive.py', 'src/sources/toolchains/npm-publisher.toml', 'tools/dev/curl-platform-flags.sh') }} + key: verified-npm-publisher-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.github/actions/setup-npm-publisher/action.yml', '.github/actions/setup-npm-publisher/install.sh', '.github/actions/setup-moon/toolchain-archive.mts', 'tools/release/npm-publisher.toml', 'tools/packaging/portable-archive.mts', 'tools/dev/curl-platform-flags.sh') }} diff --git a/.github/actions/setup-npm-publisher/install.sh b/.github/actions/setup-npm-publisher/install.sh index 9a3d607ce..52432f18c 100755 --- a/.github/actions/setup-npm-publisher/install.sh +++ b/.github/actions/setup-npm-publisher/install.sh @@ -11,8 +11,8 @@ if [ -z "$root" ]; then root="$(git rev-parse --show-toplevel 2>/dev/null)" || fail "must run inside the Oliphaunt checkout" fi -manifest="${OLIPHAUNT_NPM_PUBLISHER_MANIFEST:-$root/src/sources/toolchains/npm-publisher.toml}" -extractor="${OLIPHAUNT_NPM_PUBLISHER_ARCHIVE_EXTRACTOR:-$root/.github/actions/setup-moon/toolchain-archive.py}" +manifest="${OLIPHAUNT_NPM_PUBLISHER_MANIFEST:-$root/tools/release/npm-publisher.toml}" +extractor="${OLIPHAUNT_NPM_PUBLISHER_ARCHIVE_EXTRACTOR:-$root/.github/actions/setup-moon/toolchain-archive.mts}" curl_platform_flags="$root/tools/dev/curl-platform-flags.sh" cache_root="${OLIPHAUNT_NPM_PUBLISHER_CACHE_ROOT:-${RUNNER_TEMP:-$root/target}/oliphaunt-npm-publisher}" @@ -30,11 +30,6 @@ done # shellcheck source=tools/dev/curl-platform-flags.sh . "$curl_platform_flags" -python="" -for candidate in python3 python; do - if command -v "$candidate" >/dev/null 2>&1; then python="$candidate"; break; fi -done -[ -n "$python" ] || fail "python3 or python is required for safe archive extraction" command -v node >/dev/null 2>&1 || fail "the verified Node.js runtime must be on PATH" manifest_value() { @@ -68,16 +63,7 @@ hash_file() { sha512) shasum -a 512 "$path" | awk '{print $1}' ;; esac else - "$python" - "$algorithm" "$path" <<'PY' -import hashlib -import pathlib -import sys -digest = hashlib.new(sys.argv[1]) -with pathlib.Path(sys.argv[2]).open("rb") as stream: - while block := stream.read(1024 * 1024): - digest.update(block) -print(digest.hexdigest()) -PY + fail "sha256sum/sha512sum or shasum is required" fi } @@ -195,7 +181,7 @@ cache_valid() { esac local args=(tree-digest --root "$candidate/npm") executable for executable in "${executables[@]}"; do args+=(--executable "$executable"); done - [ "$("$python" "$extractor" "${args[@]}" 2>/dev/null)" = "$file_count $tree_sha256" ] || return 1 + [ "$(node "$extractor" "${args[@]}" 2>/dev/null)" = "$file_count $tree_sha256" ] || return 1 [ "$(node_script_version "$candidate/npm/$binary_path" 2>/dev/null)" = "$version" ] || return 1 [ "$(cat "$candidate/receipt")" = "$receipt_text" ] || return 1 } @@ -251,7 +237,7 @@ extract_args=(extract --archive "$archive" --format "$format" --prefix "$prefix" for executable in "${executables[@]}"; do extract_args+=(--required "$executable" --executable "$executable") done -"$python" "$extractor" "${extract_args[@]}" +node "$extractor" "${extract_args[@]}" mkdir -p "$stage/bin" printf '%s\n' "$npm_wrapper_text" >"$stage/bin/npm" printf '%s\n' "$npx_wrapper_text" >"$stage/bin/npx" diff --git a/.github/actions/setup-npm-publisher/install.test.sh b/.github/actions/setup-npm-publisher/install.test.sh index 3b8e3ca62..4f2b07ca6 100755 --- a/.github/actions/setup-npm-publisher/install.test.sh +++ b/.github/actions/setup-npm-publisher/install.test.sh @@ -3,22 +3,13 @@ set -euo pipefail root="$(git rev-parse --show-toplevel)" installer="$root/.github/actions/setup-npm-publisher/install.sh" -extractor="$root/.github/actions/setup-moon/toolchain-archive.py" +extractor="$root/.github/actions/setup-moon/toolchain-archive.mts" work="$(mktemp -d)" trap 'rm -rf "$work"' EXIT mkdir -p "$work/payload/package/bin" "$work/bin" "$work/blockers" -cat >"$work/payload/package/bin/npm-cli.js" <<'EOF' -#!/usr/bin/env node -console.log(process.env.OLIPHAUNT_WRAPPER_ARGV_PROBE === "1" - ? JSON.stringify(process.argv.slice(2)) - : "11.18.0"); -EOF -cat >"$work/payload/package/bin/npx-cli.js" <<'EOF' -#!/usr/bin/env node -console.log(process.env.OLIPHAUNT_WRAPPER_ARGV_PROBE === "1" - ? JSON.stringify(process.argv.slice(2)) - : "11.18.0"); -EOF +bash "$root/tools/dev/bun.sh" build "$root/.github/actions/setup-npm-publisher/testdata/package-manager-fixture.mts" \ + --target=node --define 'FIXTURE_VERSION="11.18.0"' --outfile "$work/payload/package/bin/npm-cli.js" >/dev/null +cp "$work/payload/package/bin/npm-cli.js" "$work/payload/package/bin/npx-cli.js" printf '{"name":"npm","version":"11.18.0"}\n' >"$work/payload/package/package.json" chmod 0755 "$work/payload/package/bin/npm-cli.js" "$work/payload/package/bin/npx-cli.js" COPYFILE_DISABLE=1 tar --format ustar -C "$work/payload" -czf "$work/npm.tgz" package @@ -31,13 +22,13 @@ expanded_bytes="$( -exec sh -c 'for file do wc -c < "$file"; done' sh {} + | awk '{ total += $1 } END { print total }' )" -python3 "$extractor" extract --archive "$work/npm.tgz" --format tar.gz --prefix package \ +node "$extractor" extract --archive "$work/npm.tgz" --format tar.gz --prefix package \ --entry-count "$entry_count" --expected-bytes "$archive_bytes" \ --expanded-bytes "$expanded_bytes" --destination "$work/extracted" \ --required bin/npm-cli.js --executable bin/npm-cli.js \ --required bin/npx-cli.js --executable bin/npx-cli.js \ --required package.json -tree_result="$(python3 "$extractor" tree-digest --root "$work/extracted" \ +tree_result="$(node "$extractor" tree-digest --root "$work/extracted" \ --executable bin/npm-cli.js --executable bin/npx-cli.js)" file_count="${tree_result%% *}" tree_sha256="${tree_result#* }" @@ -117,10 +108,6 @@ for command_name in npm npx; do )" [ "$observed_argv" = "$expected_argv" ] done -grep -Fq 'cli_path="$(cygpath -aw "$cli_path")"' "$publisher_bin/npm" -grep -Fq 'cli_path="$(cygpath -aw "$cli_path")"' "$publisher_bin/npx" -grep -Fq 'exec node "$cli_path" "$@"' "$publisher_bin/npm" -grep -Fq 'exec node "$cli_path" "$@"' "$publisher_bin/npx" [ ! -e "$work/ambient.log" ] [ "$(wc -l <"$work/requests.log" | tr -d '[:space:]')" = 1 ] diff --git a/.github/actions/setup-npm-publisher/testdata/package-manager-fixture.mts b/.github/actions/setup-npm-publisher/testdata/package-manager-fixture.mts new file mode 100644 index 000000000..3e90d624c --- /dev/null +++ b/.github/actions/setup-npm-publisher/testdata/package-manager-fixture.mts @@ -0,0 +1,6 @@ +declare const FIXTURE_VERSION: string; +console.log( + process.env.OLIPHAUNT_WRAPPER_ARGV_PROBE === '1' + ? JSON.stringify(process.argv.slice(2)) + : FIXTURE_VERSION, +); diff --git a/.github/actions/setup-rust-tools/action.yml b/.github/actions/setup-rust-tools/action.yml index 694be21ef..3938ad3b2 100644 --- a/.github/actions/setup-rust-tools/action.yml +++ b/.github/actions/setup-rust-tools/action.yml @@ -21,7 +21,7 @@ inputs: cache-save-if: description: Expression string passed to Swatinem/rust-cache save-if. required: false - default: "false" + default: "${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}" tools: description: Comma-separated tools for taiki-e/install-action. required: false @@ -43,16 +43,26 @@ runs: workspaces: ${{ inputs.cache-workspaces }} save-if: ${{ inputs.cache-save-if }} - - name: Install ripgrep + - name: Find ripgrep + id: ripgrep shell: bash run: | set -euo pipefail if command -v rg >/dev/null 2>&1; then rg --version - exit 0 + echo 'installed=true' >> "$GITHUB_OUTPUT" fi - cargo install ripgrep --version 15.1.0 --locked - rg --version + + - name: Prepare Linux apt sources + if: ${{ runner.os == 'Linux' && (inputs.tools != '' || steps.ripgrep.outputs.installed != 'true') }} + shell: bash + run: .github/scripts/prepare-linux-apt.sh + + - name: Install prebuilt ripgrep + if: ${{ steps.ripgrep.outputs.installed != 'true' }} + uses: taiki-e/install-action@43aecc8d72668fbcfe75c31400bc4f890f1c5853 + with: + tool: ripgrep@15.1.0 - name: Install Cargo tools if: ${{ inputs.tools != '' }} diff --git a/.github/actions/setup-rust/action.yml b/.github/actions/setup-rust/action.yml index 5c6b616f0..e175487e5 100644 --- a/.github/actions/setup-rust/action.yml +++ b/.github/actions/setup-rust/action.yml @@ -13,7 +13,7 @@ inputs: cache-save-if: description: Expression string passed to Swatinem/rust-cache save-if. required: false - default: "false" + default: "${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}" cache: description: Whether to enable the Cargo cache. required: false diff --git a/.github/actions/setup-swift/action.yml b/.github/actions/setup-swift/action.yml new file mode 100644 index 000000000..439613c2c --- /dev/null +++ b/.github/actions/setup-swift/action.yml @@ -0,0 +1,19 @@ +name: Set up Swift +description: Install the Swift SDK owner's exact Linux compiler using upstream Swiftly setup. +runs: + using: composite + steps: + - name: Read Swift version + id: version + shell: bash + run: printf 'version=%s\n' "$(cat src/sdks/swift/.swift-version)" >> "$GITHUB_OUTPUT" + - name: Install Swift + uses: swift-actions/setup-swift@d8e84bc3a450686a95474d7d6fa4a3301498debc # v3, Swiftly 1.1.0 + with: + swift-version: ${{ steps.version.outputs.version }} + - name: Verify active compiler + shell: bash + run: | + expected="$(cat src/sdks/swift/.swift-version)" + observed="$(swift --version | sed -n 's/^Swift version \([^ ]*\).*/\1/p')" + test "$observed" = "$expected" || { echo "expected Swift $expected, got $observed" >&2; exit 1; } diff --git a/.github/actions/setup-wasmer-llvm/install.sh b/.github/actions/setup-wasmer-llvm/install.sh index edb0887dd..86574ff93 100755 --- a/.github/actions/setup-wasmer-llvm/install.sh +++ b/.github/actions/setup-wasmer-llvm/install.sh @@ -166,13 +166,13 @@ if [ -d "$install_dir" ]; then rm -rf "$install_dir" fi -for command in curl tar mktemp python3; do +for command in curl tar mktemp bun xz; do if ! command -v "$command" >/dev/null 2>&1; then echo "Wasmer LLVM installation requires $command" >&2 exit 127 fi done -if [ ! -f "$ACTION_PATH/validate-archive.py" ]; then +if [ ! -f "$ACTION_PATH/validate-archive.mts" ]; then echo "Wasmer LLVM archive validator is missing from $ACTION_PATH" >&2 exit 127 fi @@ -233,7 +233,7 @@ if [ "$actual_sha256" != "$LLVM_SHA256" ]; then exit 1 fi -python3 "$ACTION_PATH/validate-archive.py" "$archive" "$LLVM_BYTES" +xz -dc "$archive" | bun "$ACTION_PATH/validate-archive.mts" "$LLVM_BYTES" staging_dir="$(mktemp -d "$cache_root/.llvm-stage.XXXXXX")" if ! tar -xJf "$archive" -C "$staging_dir"; then diff --git a/.github/actions/setup-wasmer-llvm/install.test.sh b/.github/actions/setup-wasmer-llvm/install.test.sh new file mode 100755 index 000000000..cab124eed --- /dev/null +++ b/.github/actions/setup-wasmer-llvm/install.test.sh @@ -0,0 +1,250 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(git -C "$script_dir" rev-parse --show-toplevel)" +installer="$repo_root/.github/actions/setup-wasmer-llvm/install.sh" +curl_platform_flags="$repo_root/tools/dev/curl-platform-flags.sh" + +fail() { + echo "install.test.sh: $*" >&2 + exit 1 +} + +sha256_file() { + if command -v shasum >/dev/null 2>&1; then + shasum -a 256 "$1" | awk '{print $1}' + else + sha256sum "$1" | awk '{print $1}' + fi +} + +work_root="$(mktemp -d)" +cleanup() { + rm -rf "$work_root" +} +trap cleanup EXIT HUP INT TERM + +make_archive() { + local archive="$1" + local version="$2" + local targets="$3" + local tree + tree="$work_root/archive-tree-$(basename "$archive")" + mkdir -p "$tree/bin" + # shellcheck disable=SC2016 # These literals are emitted into the fixture script. + printf '%s\n' \ + '#!/usr/bin/env bash' \ + 'set -euo pipefail' \ + 'if [[ "${OLIPHAUNT_WASMER_LLVM_TEST_REQUIRE_FINAL_ABSENT:-}" == 1 && -e "${OLIPHAUNT_WASMER_LLVM_TEST_FINAL:?}" ]]; then' \ + ' echo "final install existed before staged validation" >&2' \ + ' exit 93' \ + 'fi' \ + 'case "${1:-}" in' \ + " --version) printf '%s\\n' '$version' ;;" \ + " --targets-built) printf '%s\\n' '$targets' ;;" \ + ' *) exit 64 ;;' \ + 'esac' > "$tree/bin/llvm-config" + chmod 755 "$tree/bin/llvm-config" + ln -s llvm-config "$tree/bin/llvm-config-link" + ln -s llvm-config-link "$tree/bin/llvm-config-link-chain" + tar -cJf "$archive" -C "$tree" . +} + +assert_no_partial_install() { + local runner_temp="$1" + local cache_key="$2" + [ ! -e "$runner_temp/wasmer-llvm/$cache_key/llvm" ] || fail "failed installation left a final llvm directory" + local leftover + leftover="$(find "$runner_temp" \( -name '.llvm-stage.*' -o -name 'wasmer-llvm-*.archive.*' \) -print -quit)" + [ -z "$leftover" ] || fail "failed installation left temporary state: $leftover" +} + +assert_archive_rejected() { + local label="$1" + local archive="$2" + local sha runner cache_key + sha="$(sha256_file "$archive")" + runner="$work_root/$label-runner" + cache_key="wasmer-llvm-Linux-X64-22.1-$label" + if run_installer "$runner" "$cache_key" "$archive" "$sha" \ + "$work_root/$label-curl.log" >/dev/null 2>&1; then + fail "$label archive unexpectedly succeeded" + fi + assert_no_partial_install "$runner" "$cache_key" +} + +run_installer() { + local runner_temp="$1" + local cache_key="$2" + local archive="$3" + local expected_sha="$4" + local log="$5" + local expected_bytes="${6:-}" + if [ -z "$expected_bytes" ]; then + expected_bytes="$(wc -c < "$archive" | tr -d '[:space:]')" + fi + mkdir -p "$runner_temp" + : > "$runner_temp/github-env" + : > "$runner_temp/github-path" + OLIPHAUNT_WASMER_LLVM_TEST_ARCHIVE="$archive" \ + OLIPHAUNT_WASMER_LLVM_TEST_LOG="$log" \ + OLIPHAUNT_WASMER_LLVM_TEST_MODE="${OLIPHAUNT_WASMER_LLVM_TEST_MODE:-copy}" \ + LLVM_URL=https://downloads.invalid/llvm.tar.xz \ + LLVM_SHA256="$expected_sha" \ + LLVM_BYTES="$expected_bytes" \ + LLVM_VERSION=22.1 \ + ACTION_PATH="$repo_root/.github/actions/setup-wasmer-llvm" \ + CACHE_KEY="$cache_key" \ + RUNNER_TEMP="$runner_temp" \ + RUNNER_OS=Linux \ + GITHUB_ENV="$runner_temp/github-env" \ + GITHUB_PATH="$runner_temp/github-path" \ + PATH="$script_dir/testdata:$PATH" \ + bash "$installer" +} + +valid_archive="$work_root/valid.tar.xz" +make_archive "$valid_archive" 22.1.0 'X86 LoongArch WebAssembly' +valid_sha="$(sha256_file "$valid_archive")" +valid_bytes="$(wc -c < "$valid_archive" | tr -d '[:space:]')" + +# Wasmer LLVM shares the bootstrap-safe shell policy with downloaders that may +# run before Bun is available. Prove both sides of the platform branch and that +# the installer actually consumes it. +# shellcheck source=tools/dev/curl-platform-flags.sh +. "$curl_platform_flags" +[ "$(RUNNER_OS=Windows oliphaunt_curl_platform_tls_flag)" = '--ssl-revoke-best-effort' ] || + fail "Windows curl policy omitted Schannel revocation-offline handling" +[ -z "$(RUNNER_OS=Linux oliphaunt_curl_platform_tls_flag)" ] || + fail "Linux curl policy unexpectedly emitted a platform TLS flag" +[ -z "$(RUNNER_OS=macOS oliphaunt_curl_platform_tls_flag)" ] || + fail "macOS curl policy unexpectedly emitted a platform TLS flag" +uname() { printf '%s\n' 'MINGW64_NT-10.0'; } +[ "$(RUNNER_OS= oliphaunt_curl_platform_tls_flag)" = '--ssl-revoke-best-effort' ] || + fail "Git Bash uname fallback omitted Schannel revocation-offline handling" +unset -f uname + +transport_runner="$work_root/transport-runner" +transport_key=wasmer-llvm-Linux-X64-22.1-transport +if OLIPHAUNT_WASMER_LLVM_TEST_MODE=transport-fail \ + run_installer "$transport_runner" "$transport_key" "$valid_archive" "$valid_sha" \ + "$work_root/transport-curl.log" >/dev/null 2>&1; then + fail "failed archive transport unexpectedly succeeded" +fi +assert_no_partial_install "$transport_runner" "$transport_key" + +bad_sha_runner="$work_root/bad-sha-runner" +bad_sha_key=wasmer-llvm-Linux-X64-22.1-bad-sha +if run_installer "$bad_sha_runner" "$bad_sha_key" "$valid_archive" \ + 0000000000000000000000000000000000000000000000000000000000000000 \ + "$work_root/bad-sha-curl.log" >/dev/null 2>&1; then + fail "incorrect archive SHA-256 unexpectedly succeeded" +fi +assert_no_partial_install "$bad_sha_runner" "$bad_sha_key" + +bad_size_runner="$work_root/bad-size-runner" +bad_size_key=wasmer-llvm-Linux-X64-22.1-bad-size +if run_installer "$bad_size_runner" "$bad_size_key" "$valid_archive" "$valid_sha" \ + "$work_root/bad-size-curl.log" "$((valid_bytes + 1))" >/dev/null 2>&1; then + fail "incorrect archive byte size unexpectedly succeeded" +fi +assert_no_partial_install "$bad_size_runner" "$bad_size_key" + +unsafe_archive="$work_root/unsafe.tar.xz" +bun "$script_dir/testdata/archive.mts" unsafe | xz -c > "$unsafe_archive" +unsafe_sha="$(sha256_file "$unsafe_archive")" +unsafe_runner="$work_root/unsafe-runner" +unsafe_key=wasmer-llvm-Linux-X64-22.1-unsafe +if run_installer "$unsafe_runner" "$unsafe_key" "$unsafe_archive" "$unsafe_sha" \ + "$work_root/unsafe-curl.log" >/dev/null 2>&1; then + fail "traversal archive unexpectedly succeeded" +fi +assert_no_partial_install "$unsafe_runner" "$unsafe_key" +[ ! -e "$unsafe_runner/wasmer-llvm/$unsafe_key/escaped" ] || fail "traversal archive wrote outside staging" + +# Exercise the validator itself: rejection must happen before LLVM executable checks. +for label in unsafe unsafe-link duplicate special oversized collision cycle ancestor privileged; do + archive="$work_root/$label.tar.xz" + bun "$script_dir/testdata/archive.mts" "$label" | xz -c > "$archive" + if xz -dc "$archive" | bun "$repo_root/.github/actions/setup-wasmer-llvm/validate-archive.mts" "$(wc -c < "$archive")" >/dev/null 2>&1; then + fail "$label passed archive validation" + fi + assert_archive_rejected "$label" "$archive" +done + +truncated_archive="$work_root/truncated.tar.xz" +head -c 64 "$valid_archive" > "$truncated_archive" +truncated_sha="$(sha256_file "$truncated_archive")" +truncated_runner="$work_root/truncated-runner" +truncated_key=wasmer-llvm-Linux-X64-22.1-truncated +if run_installer "$truncated_runner" "$truncated_key" "$truncated_archive" "$truncated_sha" \ + "$work_root/truncated-curl.log" >/dev/null 2>&1; then + fail "truncated archive unexpectedly succeeded" +fi +assert_no_partial_install "$truncated_runner" "$truncated_key" + +wrong_version_archive="$work_root/wrong-version.tar.xz" +make_archive "$wrong_version_archive" 21.1.0 'X86 LoongArch WebAssembly' +wrong_version_sha="$(sha256_file "$wrong_version_archive")" +wrong_version_runner="$work_root/wrong-version-runner" +wrong_version_key=wasmer-llvm-Linux-X64-22.1-wrong-version +if run_installer "$wrong_version_runner" "$wrong_version_key" "$wrong_version_archive" "$wrong_version_sha" \ + "$work_root/wrong-version-curl.log" >/dev/null 2>&1; then + fail "archive with the wrong LLVM version unexpectedly succeeded" +fi +assert_no_partial_install "$wrong_version_runner" "$wrong_version_key" + +wrong_targets_archive="$work_root/wrong-targets.tar.xz" +make_archive "$wrong_targets_archive" 22.1.0 'X86 WebAssembly' +wrong_targets_sha="$(sha256_file "$wrong_targets_archive")" +wrong_targets_runner="$work_root/wrong-targets-runner" +wrong_targets_key=wasmer-llvm-Linux-X64-22.1-wrong-targets +if run_installer "$wrong_targets_runner" "$wrong_targets_key" "$wrong_targets_archive" "$wrong_targets_sha" \ + "$work_root/wrong-targets-curl.log" >/dev/null 2>&1; then + fail "archive without the required LLVM targets unexpectedly succeeded" +fi +assert_no_partial_install "$wrong_targets_runner" "$wrong_targets_key" + +success_runner="$work_root/success-runner" +success_key=wasmer-llvm-Linux-X64-22.1-success +success_final="$success_runner/wasmer-llvm/$success_key/llvm" +success_log="$work_root/success-curl.log" +OLIPHAUNT_WASMER_LLVM_TEST_REQUIRE_FINAL_ABSENT=1 \ +OLIPHAUNT_WASMER_LLVM_TEST_FINAL="$success_final" \ + run_installer "$success_runner" "$success_key" "$valid_archive" "$valid_sha" "$success_log" +[ -x "$success_final/bin/llvm-config" ] || fail "verified staged install was not atomically promoted" +identity_file="$success_final/.oliphaunt-wasmer-llvm" +[ -f "$identity_file" ] || fail "promoted install omitted its pinned archive identity" +grep -Fx "sha256=$valid_sha" "$identity_file" >/dev/null || fail "cache identity omitted the archive SHA-256" +grep -Fx "bytes=$valid_bytes" "$identity_file" >/dev/null || fail "cache identity omitted the exact archive size" +grep -F "LLVM_PATH=$success_final" "$success_runner/github-env" >/dev/null || fail "LLVM_PATH omitted promoted install" +grep -F "$success_final/bin" "$success_runner/github-path" >/dev/null || fail "GITHUB_PATH omitted promoted bin directory" +for flag in \ + '--location' \ + '--fail' \ + '--retry 4' \ + '--retry-all-errors' \ + '--retry-delay 10' \ + '--retry-max-time 3600' \ + '--connect-timeout 30' \ + '--max-time 1800' \ + "--max-filesize $valid_bytes" \ + '--proto =https' \ + '--proto-redir =https' \ + '--tlsv1.2'; do + grep -F -- "$flag" "$success_log" >/dev/null || fail "curl invocation omitted $flag" +done + +curl_count="$(wc -l < "$success_log" | tr -d ' ')" +run_installer "$success_runner" "$success_key" "$work_root/does-not-exist" "$valid_sha" "$success_log" "$valid_bytes" +[ "$(wc -l < "$success_log" | tr -d ' ')" = "$curl_count" ] || fail "verified cache identity downloaded LLVM again" + +printf '%s\n' 'schema=0' > "$identity_file" +if run_installer "$success_runner" "$success_key" "$work_root/does-not-exist" "$valid_sha" \ + "$success_log" "$valid_bytes" >/dev/null 2>&1; then + fail "cache with a mismatched archive identity unexpectedly succeeded" +fi +assert_no_partial_install "$success_runner" "$success_key" + +echo "Wasmer LLVM atomic installation tests passed" diff --git a/.github/actions/setup-wasmer-llvm/testdata/archive.mts b/.github/actions/setup-wasmer-llvm/testdata/archive.mts new file mode 100644 index 000000000..edba86a76 --- /dev/null +++ b/.github/actions/setup-wasmer-llvm/testdata/archive.mts @@ -0,0 +1,28 @@ +import assert from 'node:assert/strict'; +import { gunzipSync } from 'node:zlib'; +import { tarArchive } from '../../../../tools/packaging/testdata/tar-fixture.mts'; + +const fixtures = { + unsafe: [{ name: '../escaped', data: 'unsafe' }], + 'unsafe-link': [{ name: 'bin/escape', type: '2', linkTarget: '../../escaped' }], + duplicate: [ + { name: 'bin/duplicate', data: 'first' }, + { name: 'bin/duplicate', data: 'second' }, + ], + special: [{ name: 'bin/fifo', type: '6' }], + oversized: [{ name: 'lib/oversized', size: 4 * 1024 ** 3 + 1 }], + collision: [{ name: 'Bin/one' }, { name: 'bin/two' }], + cycle: [ + { name: 'a', type: '2', linkTarget: 'b' }, + { name: 'b', type: '2', linkTarget: 'a' }, + ], + ancestor: [ + { name: 'dir', type: '2', linkTarget: 'file' }, + { name: 'file' }, + { name: 'dir/child' }, + ], + privileged: [{ name: 'bin/tool', mode: 0o4755 }], +}; +const rows = fixtures[process.argv[2]]; +assert(rows, 'unknown archive fixture'); +process.stdout.write(gunzipSync(tarArchive(rows))); diff --git a/tools/policy/testdata/setup-wasmer-llvm/curl b/.github/actions/setup-wasmer-llvm/testdata/curl similarity index 100% rename from tools/policy/testdata/setup-wasmer-llvm/curl rename to .github/actions/setup-wasmer-llvm/testdata/curl diff --git a/.github/actions/setup-wasmer-llvm/validate-archive.mts b/.github/actions/setup-wasmer-llvm/validate-archive.mts new file mode 100644 index 000000000..21dd59bc2 --- /dev/null +++ b/.github/actions/setup-wasmer-llvm/validate-archive.mts @@ -0,0 +1,58 @@ +import assert from 'node:assert/strict'; +import { posix } from 'node:path'; +import { + portableMemberName, + readPortableTarStream, +} from '../../../tools/packaging/portable-archive.mts'; + +// Shell verifies the compressed pin and feeds xz's output; no file contents are buffered here. +const bytes = Number(process.argv[2]); +assert( + Number.isSafeInteger(bytes) && bytes > 0 && bytes <= 2 * 1024 ** 3, + 'expected archive bytes must be between 1 and 2 GiB', +); +const members = await readPortableTarStream(process.stdin, 'Wasmer LLVM', { + source: true, + maxEntries: 500_000, + maxEntryBytes: 4 * 1024 ** 3, + maxExpandedBytes: Math.min(12 * 1024 ** 3, Math.max(1024 ** 3, bytes * 20)), +}); +const portable = new Map(); +const links = new Map(); +for (const entry of members.values()) { + const parts = entry.name.split('/'); + for (let depth = 1; depth <= parts.length; depth++) { + const prefix = parts.slice(0, depth).join('/'); + const key = prefix.normalize('NFC').toUpperCase().toLowerCase(); + const prior = portable.get(key); + assert( + prior === undefined || prior === prefix, + `case/Unicode-colliding paths: ${prior}, ${prefix}`, + ); + portable.set(key, prefix); + } + if (!['symlink', 'hardlink'].includes(entry.type)) continue; + const link = entry.linkTarget; + assert( + link && !/[\\\u0000-\u001f\u007f:]/.test(link) && !posix.isAbsolute(link), + `unsafe link: ${entry.name}`, + ); + const target = posix.normalize( + entry.type === 'symlink' ? posix.join(posix.dirname(entry.name), link) : link, + ); + portableMemberName(target, 'file', 'Wasmer LLVM'); + assert(members.has(target), `missing link target: ${entry.name}`); + if (entry.type === 'hardlink') + assert(members.get(target).isFile, `hard link must target a regular file: ${entry.name}`); + links.set(entry.name, target); +} +for (const name of links.keys()) { + const seen = new Set(); + let current = name; + while (links.has(current)) { + assert(!seen.has(current), `link cycle: ${name}`); + seen.add(current); + current = links.get(current)!; + } + assert(['file', 'directory'].includes(members.get(current).type), `invalid link target: ${name}`); +} diff --git a/.github/actions/setup-wasmer-llvm/validate-archive.py b/.github/actions/setup-wasmer-llvm/validate-archive.py deleted file mode 100644 index ee9c07e0e..000000000 --- a/.github/actions/setup-wasmer-llvm/validate-archive.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python3 -"""Fail-closed structural validation for a pinned Wasmer LLVM .tar.xz.""" - -from __future__ import annotations - -import argparse -import posixpath -import stat -import tarfile -import unicodedata -from pathlib import Path - - -MAX_MEMBERS = 500_000 -MAX_MEMBER_BYTES = 4 * 1024 * 1024 * 1024 -MAX_EXPANDED_BYTES = 12 * 1024 * 1024 * 1024 -MIN_EXPANDED_ALLOWANCE = 1024 * 1024 * 1024 -MAX_EXPANSION_RATIO = 20 -MAX_PATH_BYTES = 4096 -MAX_COMPONENT_BYTES = 255 -WINDOWS_RESERVED_NAMES = { - "aux", - "con", - "nul", - "prn", - *(f"com{number}" for number in range(1, 10)), - *(f"lpt{number}" for number in range(1, 10)), -} - - -class UnsafeArchive(ValueError): - pass - - -def normalized_path(value: str, label: str, *, allow_root: bool = False) -> str: - if not value or any(ord(character) < 32 or ord(character) == 127 for character in value): - raise UnsafeArchive(f"{label} is empty or contains control characters") - if "\\" in value or ":" in value or value.startswith("/"): - raise UnsafeArchive(f"{label} is absolute or non-portable: {value!r}") - while value.startswith("./"): - value = value[2:] - value = value.rstrip("/") - if value in {"", "."}: - if allow_root: - return "" - raise UnsafeArchive(f"{label} resolves to the archive root") - parts = value.split("/") - if any(part in {"", ".", ".."} for part in parts): - raise UnsafeArchive(f"{label} contains an empty, dot, or traversal component: {value!r}") - for part in parts: - encoded = part.encode("utf-8") - if len(encoded) > MAX_COMPONENT_BYTES: - raise UnsafeArchive(f"{label} contains a component longer than {MAX_COMPONENT_BYTES} UTF-8 bytes") - if part.endswith((" ", ".")): - raise UnsafeArchive(f"{label} contains a Windows-ambiguous trailing space or dot: {value!r}") - windows_stem = part.split(".", 1)[0].casefold() - if windows_stem in WINDOWS_RESERVED_NAMES: - raise UnsafeArchive(f"{label} contains reserved Windows name {part!r}") - normalized = "/".join(parts) - if len(normalized.encode("utf-8")) > MAX_PATH_BYTES: - raise UnsafeArchive(f"{label} is longer than {MAX_PATH_BYTES} UTF-8 bytes") - return normalized - - -def portable_key(value: str) -> str: - return unicodedata.normalize("NFC", value).casefold() - - -def link_target(member: tarfile.TarInfo, member_path: str) -> str: - target = member.linkname - if not target or "\\" in target or target.startswith("/") or (len(target) > 1 and target[1] == ":"): - raise UnsafeArchive(f"archive link {member.name!r} has an unsafe target {target!r}") - if any(ord(character) < 32 or ord(character) == 127 for character in target): - raise UnsafeArchive(f"archive link {member.name!r} has control characters in its target") - combined = posixpath.join(posixpath.dirname(member_path), target) if member.issym() else target - normalized = posixpath.normpath(combined) - if normalized in {"", ".", ".."} or normalized.startswith("../"): - raise UnsafeArchive(f"archive link {member.name!r} escapes the extraction root") - return normalized_path(normalized, f"archive link target for {member.name!r}") - - -def validate(archive: Path, expected_bytes: int) -> None: - if not archive.is_file() or archive.stat().st_size != expected_bytes: - actual = archive.stat().st_size if archive.exists() else "missing" - raise UnsafeArchive(f"archive byte size is {actual}; expected exactly {expected_bytes}") - expanded_limit = min( - MAX_EXPANDED_BYTES, - max(MIN_EXPANDED_ALLOWANCE, expected_bytes * MAX_EXPANSION_RATIO), - ) - members: dict[str, tarfile.TarInfo] = {} - portable_paths: dict[str, str] = {} - links: list[tuple[tarfile.TarInfo, str, str]] = [] - link_targets: dict[str, str] = {} - expanded_bytes = 0 - root_seen = False - try: - stream = tarfile.open(archive, mode="r:xz") - except (OSError, tarfile.TarError) as error: - raise UnsafeArchive(f"cannot open xz tar archive: {error}") from error - with stream: - try: - for index, member in enumerate(stream, start=1): - if index > MAX_MEMBERS: - raise UnsafeArchive(f"archive contains more than {MAX_MEMBERS} members") - path = normalized_path(member.name, f"archive member {member.name!r}", allow_root=True) - if path == "": - if not member.isdir(): - raise UnsafeArchive("the archive root entry must be a directory") - if root_seen: - raise UnsafeArchive("archive contains duplicate root directory entries") - root_seen = True - continue - if path in members: - raise UnsafeArchive(f"archive contains duplicate path {path!r}") - parts = path.split("/") - for depth in range(1, len(parts) + 1): - prefix = "/".join(parts[:depth]) - key = portable_key(prefix) - prior = portable_paths.get(key) - if prior is not None and prior != prefix: - raise UnsafeArchive( - f"archive contains Unicode/case-colliding paths {prior!r} and {prefix!r}" - ) - portable_paths[key] = prefix - if member.mode & (stat.S_ISUID | stat.S_ISGID): - raise UnsafeArchive(f"archive member {path!r} has set-id mode bits") - if not (member.isdir() or member.isreg() or member.issym() or member.islnk()): - raise UnsafeArchive(f"archive member {path!r} has unsupported type {member.type!r}") - if member.isreg(): - if member.size < 0 or member.size > MAX_MEMBER_BYTES: - raise UnsafeArchive(f"archive member {path!r} exceeds the per-file size limit") - expanded_bytes += member.size - if expanded_bytes > expanded_limit: - raise UnsafeArchive(f"archive expands beyond the {expanded_limit}-byte allowance") - members[path] = member - if member.issym() or member.islnk(): - target = link_target(member, path) - links.append((member, path, target)) - link_targets[path] = target - except (OSError, tarfile.TarError) as error: - raise UnsafeArchive(f"cannot read xz tar archive: {error}") from error - if not members: - raise UnsafeArchive("archive contains no installable members") - for path, member in members.items(): - parts = path.split("/") - for depth in range(1, len(parts)): - ancestor = members.get("/".join(parts[:depth])) - if ancestor is not None and not ancestor.isdir(): - raise UnsafeArchive(f"archive member {path!r} descends through a non-directory") - for member, path, target in links: - target_member = members.get(target) - if target_member is None: - raise UnsafeArchive(f"archive link {path!r} targets missing member {target!r}") - if member.islnk() and not target_member.isreg(): - raise UnsafeArchive(f"archive hard link {path!r} does not target a regular file") - for _, path, _ in links: - current = path - visited: set[str] = set() - while current in link_targets: - if current in visited: - raise UnsafeArchive(f"archive link {path!r} participates in a link cycle") - visited.add(current) - current = link_targets[current] - resolved = members.get(current) - if resolved is None or not (resolved.isreg() or resolved.isdir()): - raise UnsafeArchive(f"archive link {path!r} does not resolve to a regular file or directory") - - -def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument("archive", type=Path) - parser.add_argument("expected_bytes", type=int) - arguments = parser.parse_args() - if arguments.expected_bytes < 1 or arguments.expected_bytes > 2 * 1024 * 1024 * 1024: - raise UnsafeArchive("expected archive bytes must be between 1 and 2 GiB") - validate(arguments.archive, arguments.expected_bytes) - - -if __name__ == "__main__": - try: - main() - except (OSError, UnsafeArchive, tarfile.TarError) as error: - raise SystemExit(f"unsafe Wasmer LLVM archive: {error}") from error diff --git a/.github/moon.yml b/.github/moon.yml index 2b18ff265..9997f649b 100644 --- a/.github/moon.yml +++ b/.github/moon.yml @@ -4,7 +4,7 @@ id: "ci-workflows" language: "yaml" layer: "configuration" stack: "infrastructure" -tags: ["ci", "github-actions", "workflows"] +tags: ["javascript-quality", "ci", "github-actions", "workflows"] project: title: "GitHub Actions" @@ -17,9 +17,25 @@ owners: "**/*": ["@oliphaunt/core"] tasks: + verify-bash: + command: "bash --version" + toolchains: ["system"] + options: + cache: false + llvm-install-unit: + tags: ["quality", "unit"] + command: "bash .github/actions/setup-wasmer-llvm/install.test.sh" + inputs: + - "actions/setup-wasmer-llvm/**/*" + - "/tools/packaging/portable-archive.mts" + - "/tools/dev/curl-platform-flags.sh" + - "/tools/packaging/testdata/tar-fixture.mts" + options: + cache: true + runFromWorkspaceRoot: true check: tags: ["policy", "assertion", "quality", "static", "requires-maintainer-tools"] - command: "bash tools/policy/check-workflows.sh" + command: "bash tools/ci/check-workflows.sh" inputs: - "/.moon/toolchains.yml" - "/.prototools" @@ -27,31 +43,27 @@ tasks: - "/.github/scripts/**/*" - "/.github/workflows/**/*" - "/.github/zizmor.yml" - - "/src/sources/toolchains/**/*" + - "/tools/dev/*.toml" + - "/tools/ci/with-projects.sh" - "/tools/dev/bun.sh" - - "/tools/dev/capture-command-output.mjs" - "/tools/dev/curl-platform-flags.sh" - - "/tools/dev/extract-pinned-zip.sh" - - "/tools/dev/extract-pinned-zip.test.sh" - - "/tools/dev/install-pinned-js-runtime.sh" - - "/tools/dev/install-pinned-js-runtime.test.sh" - - "/tools/dev/install-pinned-winflexbison.sh" - - "/tools/dev/install-pinned-winflexbison.test.sh" - - "/tools/dev/moon-command.mjs" - - "/tools/dev/setup-android-sdk.sh" - - "/tools/dev/setup-android-sdk.test.sh" - - "/tools/dev/start-android-emulator-ci.sh" - - "/tools/dev/start-android-emulator-ci.test.sh" - - "/tools/policy/assertions/workflow-security.mjs" - - "/tools/policy/assertions/workflow-security.test.mjs" - - "/tools/policy/ci-plan-node-products.test.mjs" - - "/tools/policy/ci-plan-wasix-postmaster-release.test.mjs" - - "/tools/policy/workflow-moon-transfers.test.mjs" - - "/tools/policy/check-workflows.sh" - - "/tools/graph/affected.mjs" - - "/tools/graph/ci_plan.mjs" - - "/tools/release/release-graph.mjs" - - "/tools/release/toolchain-bootstrap.test.mjs" + - "/tools/ci/workflow-security.mts" + - "/tools/ci/workflow-security.test.mts" + - "/tools/ci/ci-plan-node-products.test.mts" + - "/tools/ci/ci-plan-wasix-postmaster-release.test.mts" + - "/tools/ci/ci-plan-test-*.mts" + - "/tools/ci/capture-ci-test-observations.sh" + - "/tools/ci/ci-release-scope.test.*" + - "/tools/ci/workflow-moon-transfers.test.mts" + - "/tools/ci/check-workflows.sh" + - "/tools/ci/affected.mts" + - "/tools/ci/ci_plan.mts" + - "/tools/ci/ci-plan.sh" + - "/src/sdks/ts/sdk/tools/published-consumer.mts" + - "/src/sdks/ts/sdk/package.json" + - "/tools/release/check_registry_publication.mts" + - "/tools/release/public-consumer-smoke.mts" + - "/tools/release/release-graph.mts" options: cache: true runFromWorkspaceRoot: true diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ee98067a6..4e6db57b0 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,6 +8,5 @@ ## Verification -- [ ] `moon run dev-tools:doctor` - [ ] Moon affected checks and tests passed. - [ ] Product-specific smoke/package/perf checks when product behavior or artifacts changed. diff --git a/.github/scripts/bootstrap-registry-credential-env.mjs b/.github/scripts/bootstrap-registry-credential-env.mjs deleted file mode 100644 index 6cec89e54..000000000 --- a/.github/scripts/bootstrap-registry-credential-env.mjs +++ /dev/null @@ -1,30 +0,0 @@ -const CARGO_CREDENTIAL_ENV = Object.freeze([ - "CARGO_REGISTRIES_CRATES_IO_TOKEN", - "CARGO_REGISTRY_TOKEN", - "CRATES_IO_BOOTSTRAP_TOKEN", - "CRATES_IO_TRUST_CONFIG_TOKEN", -]); - -const NPM_CREDENTIAL_ENV = Object.freeze([ - "NODE_AUTH_TOKEN", - "NPM_BOOTSTRAP_TOKEN", - "NPM_CONFIG__AUTH", - "NPM_CONFIG__AUTHTOKEN", - "NPM_CONFIG_USERCONFIG", - "NPM_TOKEN", -]); - -/** - * Give a bootstrap publisher only the credential family for its immutable - * registry lane. The parent orchestrator needs both families so it can run the - * lanes concurrently; a child publisher never does. - */ -export function bootstrapCarrierEnvironment(ecosystem, parentEnvironment = process.env) { - if (!new Set(["cargo", "npm"]).has(ecosystem)) { - throw new Error(`unsupported bootstrap credential ecosystem ${JSON.stringify(ecosystem)}`); - } - const environment = { ...parentEnvironment }; - const remove = ecosystem === "cargo" ? NPM_CREDENTIAL_ENV : CARGO_CREDENTIAL_ENV; - for (const name of remove) delete environment[name]; - return environment; -} diff --git a/.github/scripts/bootstrap-registry-identities.mjs b/.github/scripts/bootstrap-registry-identities.mjs deleted file mode 100644 index d7bb6045a..000000000 --- a/.github/scripts/bootstrap-registry-identities.mjs +++ /dev/null @@ -1,393 +0,0 @@ -#!/usr/bin/env bun -import { spawn } from "node:child_process"; -import { - appendFileSync, - mkdirSync, - readFileSync, - renameSync, - rmSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import process from "node:process"; - -import { bootstrapCarrierEnvironment } from "./bootstrap-registry-credential-env.mjs"; -import { bootstrapPublicationPlan } from "../../tools/release/bootstrap-publication-plan.mjs"; -import { executeBootstrapPublicationPlan } from "../../tools/release/bootstrap-publication-executor.mjs"; -import { - appendBootstrapCheckpoint, - loadBootstrapLedger, -} from "../../tools/release/bootstrap-ledger.mjs"; -import { - reconcileBootstrapRegistryState, - resolveBootstrapScope, -} from "../../tools/release/bootstrap-registry-reconciliation.mjs"; -import { - assessCratesIoBootstrapCapacity, - cratesIoCapacitySummary, - inspectCratesIoVersionState, - parseRegistryMutationDeadline, - CRATES_IO_NEW_CRATE_REFILL_SECONDS, - REGISTRY_BOOTSTRAP_INTEGRITY_CONCURRENCY, -} from "../../tools/release/crates-io-bootstrap-capacity.mjs"; -import { - decodeRegistryPublicationDeferral, - REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE, -} from "../../tools/release/registry-publication-deferral.mjs"; -import { validateBootstrapExecutionResult } from "../../tools/release/bootstrap-execution-result.mjs"; -import { inspectNpmVersionState } from "../../tools/release/frozen-npm-publish.mjs"; -import { loadPublicationLock } from "../../tools/release/publication-lock.mjs"; -import { verifyLockedRegistryIntegrity } from "../../tools/release/registry-integrity.mjs"; - -function fail(message) { - console.error(`bootstrap-registry-identities: ${message}`); - process.exit(1); -} - -function requiredEnv(name) { - const value = process.env[name]?.trim(); - if (!value) { - fail(`${name} is required`); - } - return value; -} - -const args = Bun.argv.slice(2); -if (args.length > 1 || (args.length === 1 && args[0] !== "--credential-needs")) { - fail("usage: bootstrap-registry-identities.mjs [--credential-needs]"); -} -const credentialNeedsOnly = args[0] === "--credential-needs"; - -const EXECUTION_RESULT_PATH = path.resolve( - process.env.OLIPHAUNT_BOOTSTRAP_EXECUTION_RESULT?.trim() - || "target/release/bootstrap-execution-result.json", -); -const CHILD_STDERR_TAIL_BYTES = 128 * 1024; - -function writeExecutionResult(value) { - const normalized = validateBootstrapExecutionResult(value, { - releaseCommit: value.source.commit, - releaseTree: value.source.tree, - lock: value.lock, - products: value.products, - }); - mkdirSync(path.dirname(EXECUTION_RESULT_PATH), { recursive: true }); - const temporary = `${EXECUTION_RESULT_PATH}.tmp-${process.pid}`; - rmSync(temporary, { force: true }); - writeFileSync(temporary, `${JSON.stringify(normalized, null, 2)}\n`, { flag: "wx", mode: 0o600 }); - renameSync(temporary, EXECUTION_RESULT_PATH); - if (process.env.GITHUB_OUTPUT?.trim()) { - appendFileSync( - process.env.GITHUB_OUTPUT, - `complete=${normalized.decision === "complete" ? "true" : "false"}\n` - + `deferred=${normalized.decision === "deferred" ? "true" : "false"}\n` - + `deferral_mode=${normalized.deferralMode ?? ""}\n` - + `progress_count=${normalized.newlyCompletedIds.length}\n` - + `completed_count=${normalized.completedIds.length}\n` - + `remaining_count=${normalized.remainingIds.length}\n` - + `not_before_epoch=${normalized.notBeforeEpochSeconds ?? 0}\n`, - ); - } - return normalized; -} - -let products; -try { - products = JSON.parse(requiredEnv("PRODUCTS_JSON")); -} catch (error) { - fail(`invalid PRODUCTS_JSON: ${error.message}`); -} -if (!Array.isArray(products) || products.length === 0 || products.some((product) => typeof product !== "string")) { - fail("PRODUCTS_JSON must be a non-empty product string list"); -} - -const headRef = requiredEnv("RELEASE_HEAD_SHA"); -const publicationLock = requiredEnv("PUBLICATION_LOCK_PATH"); -const bootstrapLedger = requiredEnv("BOOTSTRAP_LEDGER_PATH"); -let lock; -let plan; -try { - lock = loadPublicationLock(publicationLock); - plan = bootstrapPublicationPlan(lock, products); - rmSync(EXECUTION_RESULT_PATH, { force: true }); -} catch (error) { - fail(error instanceof Error ? error.message : String(error)); -} - -// This read-only inventory must complete before the genesis ledger is -// initialized and, critically, before npm or crates.io receives any -// publication request. -let cargoInventory; -let npmInventory; -try { - const deadlineEpochSeconds = parseRegistryMutationDeadline( - requiredEnv("REGISTRY_MUTATION_DEADLINE_EPOCH"), - ); - [cargoInventory, npmInventory] = await Promise.all([ - inspectCratesIoVersionState({ plan, deadlineEpochSeconds }), - inspectNpmVersionState({ plan, deadlineEpochSeconds }), - ]); -} catch (error) { - fail(error instanceof Error ? error.message : String(error)); -} -if (credentialNeedsOnly) { - const needsCargo = cargoInventory.missingNames.length > 0; - const needsNpm = npmInventory.missingNames.length > 0; - if (process.env.GITHUB_OUTPUT?.trim()) { - appendFileSync(process.env.GITHUB_OUTPUT, `needs_cargo_token=${needsCargo}\nneeds_npm_token=${needsNpm}\n`); - } - console.log( - `approved candidate requires bootstrap credentials for: ${[ - needsCargo ? "Cargo" : "", - needsNpm ? "npm" : "", - ].filter(Boolean).join(", ") || "none"}`, - ); - process.exit(0); -} - -// Validate a restored immutable chain before using its receipts. Inventory is -// authoritative for current public visibility; a receipt whose exact version -// disappeared is a hard pre-mutation failure. Existing names lacking the -// locked exact version remain normal trusted-publication work. -let checkpoint; -let reconciliation; -let startingCompletedIds; -let scopedPlan; -let scopedIds; -let capacityAssessment; -try { - checkpoint = loadBootstrapLedger(bootstrapLedger, lock, products, { allowEmpty: true }); - startingCompletedIds = new Set(checkpoint?.receipts.map(({ id }) => id) ?? []); - reconciliation = reconcileBootstrapRegistryState({ - plan, - cargoInventory, - npmInventory, - checkpoint, - }); - scopedPlan = resolveBootstrapScope(plan, reconciliation, checkpoint); - scopedIds = new Set(scopedPlan.map(({ id }) => id)); - - capacityAssessment = assessCratesIoBootstrapCapacity({ - inventory: cargoInventory, - npmInventory, - bootstrapPlan: scopedPlan, - cargoSecondsPerCarrier: process.env.REGISTRY_BOOTSTRAP_CARGO_SECONDS_PER_CARRIER, - npmSecondsPerCarrier: process.env.REGISTRY_BOOTSTRAP_NPM_SECONDS_PER_CARRIER, - reconciliationSecondsPerCarrier: process.env.REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_PER_CARRIER, - reserveSeconds: process.env.REGISTRY_BOOTSTRAP_RESERVE_SECONDS, - deadlineEpochSeconds: parseRegistryMutationDeadline(requiredEnv("REGISTRY_MUTATION_DEADLINE_EPOCH")), - }); - const summary = cratesIoCapacitySummary(capacityAssessment); - console.log(summary); - if (process.env.GITHUB_STEP_SUMMARY?.trim()) { - appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${summary}\n`); - } - - const missing = reconciliation.missingCarriers.filter(({ id }) => scopedIds.has(id)); - if (missing.some(({ ecosystem }) => ecosystem === "cargo") && !process.env.CARGO_REGISTRY_TOKEN?.trim()) { - throw new Error("CRATES_IO_BOOTSTRAP_TOKEN is required because the approved candidate contains absent Cargo names"); - } - if (missing.some(({ ecosystem }) => ecosystem === "npm")) { - const npmrc = process.env.NPM_CONFIG_USERCONFIG?.trim(); - let npmrcBody = ""; - try { - npmrcBody = npmrc ? readFileSync(npmrc, "utf8") : ""; - } catch {} - if (!/^\/\/registry[.]npmjs[.]org\/:_authToken=[^\r\n]+\r?\n?$/u.test(npmrcBody)) { - throw new Error("NPM_BOOTSTRAP_TOKEN is required because the approved candidate contains absent npm names"); - } - } -} catch (error) { - fail(error instanceof Error ? error.message : String(error)); -} - -// Prove every matching public version against the frozen bytes in one bounded, -// concurrent preflight. This both recovers publications accepted before an -// interrupted checkpoint and ensures public recovery skips cannot conceal an -// immutable checksum/SRI conflict. No registry mutation has happened yet. -let publicReceipts = []; -try { - const scopedPublicCarrierIds = reconciliation.publicCarrierIds.filter((id) => scopedIds.has(id)); - if (scopedPublicCarrierIds.length > 0) { - publicReceipts = await verifyLockedRegistryIntegrity(lock, { - carrierIds: scopedPublicCarrierIds, - concurrency: REGISTRY_BOOTSTRAP_INTEGRITY_CONCURRENCY, - }); - } -} catch (error) { - fail(error instanceof Error ? error.message : String(error)); -} - -// A genesis checkpoint is written only after every pre-mutation conflict and -// public-byte proof has passed. Every later file is append-only and -// content-addressed, so `if: always()` can upload a useful resume chain. -try { - if (checkpoint === null) { - checkpoint = appendBootstrapCheckpoint(bootstrapLedger, lock, products, [], { - publicationIds: scopedPlan.map(({ id }) => id), - }); - } - if (publicReceipts.length > 0) { - checkpoint = appendBootstrapCheckpoint(bootstrapLedger, lock, products, publicReceipts); - } -} catch (error) { - fail(error instanceof Error ? error.message : String(error)); -} - -// Only completely absent names reach a publisher subprocess. Cargo and npm -// each retain one sequential mutation lane, while independent lanes overlap -// and scoped dependency edges remain barriers. Node's async spawn is required -// here: spawnSync would silently serialize both lanes. -function publishCarrier(carrier) { - console.log(`reconciling pending ${carrier.ecosystem} identity ${carrier.id} (${carrier.product})`); - return new Promise((resolve, reject) => { - let stderrTail = Buffer.alloc(0); - let settled = false; - const child = spawn( - process.execPath, - [ - "tools/release/release-publish.mjs", - "publish", - "--bootstrap-identities", - "--carrier-id", - carrier.id, - "--head-ref", - headRef, - "--publication-lock", - publicationLock, - "--bootstrap-ledger", - bootstrapLedger, - ], - { - stdio: ["inherit", "inherit", "pipe"], - env: bootstrapCarrierEnvironment(carrier.ecosystem, process.env), - }, - ); - child.stderr.on("data", (chunk) => { - process.stderr.write(chunk); - stderrTail = Buffer.concat([stderrTail, Buffer.from(chunk)]).subarray(-CHILD_STDERR_TAIL_BYTES); - }); - child.once("error", (cause) => { - if (!settled) { - settled = true; - reject(cause); - } - }); - child.once("close", (code, signal) => { - if (settled) return; - settled = true; - if (code === 0) { - resolve(); - } else if (signal === null && code === REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE) { - try { - reject(decodeRegistryPublicationDeferral(stderrTail.toString("utf8"))); - } catch (cause) { - reject(cause); - } - } else { - reject(new Error(`${carrier.id} failed with ${signal === null ? `status ${String(code)}` : `signal ${signal}`}`)); - } - }); - }); -} - -let execution; -try { - if (capacityAssessment.decision === "defer") { - execution = { - deferReason: "capacity", - notBeforeEpochSeconds: capacityAssessment.notBeforeEpochSeconds, - }; - } else { - const admitted = new Set(capacityAssessment.admittedCarrierIds); - const admittedPlan = scopedPlan.filter(({ id }) => admitted.has(id)); - if (admittedPlan.length !== admitted.size) { - throw new Error("token-bucket admission contains a carrier outside the exact missing-identity inventory"); - } - execution = await executeBootstrapPublicationPlan({ - plan: admittedPlan, - satisfiedCarrierIds: reconciliation.publicCarrierIds, - publishCarrier, - checkpointCarrierIds: async (carrierIds) => { - const receipts = await verifyLockedRegistryIntegrity(lock, { - carrierIds, - concurrency: REGISTRY_BOOTSTRAP_INTEGRITY_CONCURRENCY, - }); - checkpoint = appendBootstrapCheckpoint(bootstrapLedger, lock, products, receipts); - }, - }); - } -} catch (error) { - fail(error instanceof Error ? error.message : String(error)); -} - -let result; -try { - checkpoint = loadBootstrapLedger(bootstrapLedger, lock, products, { allowEmpty: true }); - const completedSet = new Set(checkpoint?.receipts.map(({ id }) => id) ?? []); - const completedIds = scopedPlan.filter(({ id }) => completedSet.has(id)).map(({ id }) => id); - if (completedIds.length !== completedSet.size) { - throw new Error("bootstrap ledger contains a receipt outside the exact canonical plan"); - } - const remainingIds = scopedPlan.filter(({ id }) => !completedSet.has(id)).map(({ id }) => id); - const newlyCompletedIds = completedIds.filter((id) => !startingCompletedIds.has(id)); - const decision = remainingIds.length === 0 ? "complete" : "deferred"; - if (decision === "complete") { - checkpoint = loadBootstrapLedger(bootstrapLedger, lock, products, { requireComplete: true }); - } - const remainingHasCargo = scopedPlan.some(({ id, ecosystem }) => ecosystem === "cargo" && remainingIds.includes(id)); - const notBeforeEpochSeconds = decision === "complete" - ? null - : execution.notBeforeEpochSeconds - ?? Math.floor(Date.now() / 1000) + (remainingHasCargo ? CRATES_IO_NEW_CRATE_REFILL_SECONDS : 1); - const deferralMode = decision === "complete" - ? null - : newlyCompletedIds.length > 0 - ? "progress" - : execution.deferReason === "rate-limit" - ? "rate-limit" - : execution.deferReason === "capacity" - ? "pre-mutation-capacity" - : execution.deferReason === "deadline" - ? "pre-mutation-deadline" - : (() => { - throw new Error( - `zero-progress bootstrap deferral requires an explicit rate-limit or deadline reason; got ` - + `${execution.deferReason ?? "none"}`, - ); - })(); - result = writeExecutionResult({ - schema: "oliphaunt-bootstrap-execution-result-v1", - operation: "publish-bootstrap", - decision, - deferralMode, - source: { commit: lock.source.commit, tree: lock.source.tree }, - lock: { - lockDigest: lock.lockDigest, - catalogDigest: lock.catalogDigest, - packageEnvelopeDigest: lock.packageEnvelopeDigest, - }, - products: [...products].sort(), - admittedIds: scopedPlan - .filter(({ id }) => capacityAssessment.admittedCarrierIds.includes(id)) - .map(({ id }) => id), - completedIds, - newlyCompletedIds, - remainingIds, - notBeforeEpochSeconds, - }); -} catch (error) { - fail(error instanceof Error ? error.message : String(error)); -} -if (result.decision === "complete") { - console.log( - `completed ${execution.completedCarrierIds.length} dependency-ordered first-version Cargo/npm bootstrap mutation(s), ` - + `reconciled ${reconciliation.publicCarrierIds.length} lock-matching public version(s), ` - + `and sealed immutable checkpoint ${checkpoint.sequence} (${checkpoint.receipts.length}/${checkpoint.publications.length})`, - ); -} else { - console.log( - `checkpointed ${result.newlyCompletedIds.length} new exact bootstrap receipt(s); ` - + `${result.remainingIds.length} carrier(s) remain for a manual rerun no earlier than ${result.notBeforeEpochSeconds}`, - ); -} diff --git a/.github/scripts/bootstrap-registry-identities.mts b/.github/scripts/bootstrap-registry-identities.mts new file mode 100644 index 000000000..12a77cefe --- /dev/null +++ b/.github/scripts/bootstrap-registry-identities.mts @@ -0,0 +1,438 @@ +#!/usr/bin/env bun +import { + appendFileSync, + closeSync, + existsSync, + mkdirSync, + openSync, + readFileSync, + readSync, + renameSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { validateBootstrapExecutionResult } from '../../tools/release/bootstrap-execution-result.mts'; +import { + appendBootstrapCheckpoint, + loadBootstrapLedger, +} from '../../tools/release/bootstrap-ledger.mts'; +import { + bootstrapPublicationPlan, + bootstrapPublicationSchedule, +} from '../../tools/release/bootstrap-publication-plan.mts'; +import { + reconcileBootstrapRegistryState, + resolveBootstrapScope, +} from '../../tools/release/bootstrap-registry-reconciliation.mts'; +import { + assessCratesIoBootstrapCapacity, + CRATES_IO_NEW_CRATE_REFILL_SECONDS, + cratesIoCapacitySummary, + inspectCratesIoVersionState, + parseRegistryMutationDeadline, + REGISTRY_BOOTSTRAP_INTEGRITY_CONCURRENCY, +} from '../../tools/release/crates-io-bootstrap-capacity.mts'; +import { inspectNpmVersionState } from '../../tools/release/frozen-npm-publish.mts'; +import { loadPublicationLock } from '../../tools/release/publication-lock.mts'; +import { verifyLockedRegistryIntegrity } from '../../tools/release/registry-integrity.mts'; +import { + decodeRegistryPublicationDeferral, + REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE, +} from '../../tools/release/registry-publication-deferral.mts'; + +function fail(message) { + console.error(`bootstrap-registry-identities: ${message}`); + process.exit(1); +} + +function requiredEnv(name) { + const value = process.env[name]?.trim(); + if (!value) { + fail(`${name} is required`); + } + return value; +} + +const args = Bun.argv.slice(2); +const savedPhase = ['--prepare', '--checkpoint', '--finish'].includes(args[0]); +if (savedPhase ? args.length !== 2 : args.length !== 1 || args[0] !== '--credential-needs') { + fail( + 'use bash .github/scripts/bootstrap-registry-identities.sh, or --credential-needs for read-only inventory', + ); +} +const credentialNeedsOnly = args[0] === '--credential-needs'; + +const EXECUTION_RESULT_PATH = path.resolve( + process.env.OLIPHAUNT_BOOTSTRAP_EXECUTION_RESULT?.trim() || + 'target/release/bootstrap-execution-result.json', +); +const CHILD_STDERR_TAIL_BYTES = 128 * 1024; + +function writeExecutionResult(value) { + const normalized = validateBootstrapExecutionResult(value, { + releaseCommit: value.source.commit, + releaseTree: value.source.tree, + lock: value.lock, + products: value.products, + }); + mkdirSync(path.dirname(EXECUTION_RESULT_PATH), { recursive: true }); + const temporary = `${EXECUTION_RESULT_PATH}.tmp-${process.pid}`; + rmSync(temporary, { force: true }); + writeFileSync(temporary, `${JSON.stringify(normalized, null, 2)}\n`, { flag: 'wx', mode: 0o600 }); + renameSync(temporary, EXECUTION_RESULT_PATH); + if (process.env.GITHUB_OUTPUT?.trim()) { + appendFileSync( + process.env.GITHUB_OUTPUT, + `complete=${normalized.decision === 'complete' ? 'true' : 'false'}\n` + + `deferred=${normalized.decision === 'deferred' ? 'true' : 'false'}\n` + + `deferral_mode=${normalized.deferralMode ?? ''}\n` + + `progress_count=${normalized.newlyCompletedIds.length}\n` + + `completed_count=${normalized.completedIds.length}\n` + + `remaining_count=${normalized.remainingIds.length}\n` + + `not_before_epoch=${normalized.notBeforeEpochSeconds ?? 0}\n`, + ); + } + return normalized; +} + +let products; +try { + products = JSON.parse(requiredEnv('PRODUCTS_JSON')); +} catch (error) { + fail(`invalid PRODUCTS_JSON: ${error.message}`); +} +if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string') +) { + fail('PRODUCTS_JSON must be a non-empty product string list'); +} + +const headRef = requiredEnv('RELEASE_HEAD_SHA'); +const publicationLock = requiredEnv('PUBLICATION_LOCK_PATH'); +const bootstrapLedger = requiredEnv('BOOTSTRAP_LEDGER_PATH'); +let lock; +let plan; +try { + lock = loadPublicationLock(publicationLock); + plan = bootstrapPublicationPlan(lock, products); + if (args[0] === '--prepare') rmSync(EXECUTION_RESULT_PATH, { force: true }); +} catch (error) { + fail(error instanceof Error ? error.message : String(error)); +} + +if (args[0] === '--checkpoint' || args[0] === '--finish') { + try { + await savedBootstrapPhase(args[0], path.resolve(args[1])); + } catch (cause) { + fail(cause.message); + } + process.exit(0); +} + +// This read-only inventory must complete before the genesis ledger is +// initialized and, critically, before npm or crates.io receives any +// publication request. +let cargoInventory; +let npmInventory; +try { + const deadlineEpochSeconds = parseRegistryMutationDeadline( + requiredEnv('REGISTRY_MUTATION_DEADLINE_EPOCH'), + ); + [cargoInventory, npmInventory] = await Promise.all([ + inspectCratesIoVersionState({ plan, deadlineEpochSeconds }), + inspectNpmVersionState({ plan, deadlineEpochSeconds }), + ]); +} catch (error) { + fail(error instanceof Error ? error.message : String(error)); +} +if (credentialNeedsOnly) { + const needsCargo = cargoInventory.missingNames.length > 0; + const needsNpm = npmInventory.missingNames.length > 0; + if (process.env.GITHUB_OUTPUT?.trim()) { + appendFileSync( + process.env.GITHUB_OUTPUT, + `needs_cargo_token=${needsCargo}\nneeds_npm_token=${needsNpm}\n`, + ); + } + console.log( + `approved candidate requires bootstrap credentials for: ${ + [needsCargo ? 'Cargo' : '', needsNpm ? 'npm' : ''].filter(Boolean).join(', ') || 'none' + }`, + ); + process.exit(0); +} + +// Validate a restored immutable chain before using its receipts. Inventory is +// authoritative for current public visibility; a receipt whose exact version +// disappeared is a hard pre-mutation failure. Existing names lacking the +// locked exact version remain normal trusted-publication work. +let checkpoint; +let reconciliation; +let startingCompletedIds; +let scopedPlan; +let scopedIds; +let capacityAssessment; +try { + checkpoint = loadBootstrapLedger(bootstrapLedger, lock, products, { allowEmpty: true }); + startingCompletedIds = new Set(checkpoint?.receipts.map(({ id }) => id) ?? []); + reconciliation = reconcileBootstrapRegistryState({ + plan, + cargoInventory, + npmInventory, + checkpoint, + }); + scopedPlan = resolveBootstrapScope(plan, reconciliation, checkpoint); + scopedIds = new Set(scopedPlan.map(({ id }) => id)); + + capacityAssessment = assessCratesIoBootstrapCapacity({ + inventory: cargoInventory, + npmInventory, + bootstrapPlan: scopedPlan, + cargoSecondsPerCarrier: process.env.REGISTRY_BOOTSTRAP_CARGO_SECONDS_PER_CARRIER, + npmSecondsPerCarrier: process.env.REGISTRY_BOOTSTRAP_NPM_SECONDS_PER_CARRIER, + reconciliationSecondsPerCarrier: + process.env.REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_PER_CARRIER, + reserveSeconds: process.env.REGISTRY_BOOTSTRAP_RESERVE_SECONDS, + deadlineEpochSeconds: parseRegistryMutationDeadline( + requiredEnv('REGISTRY_MUTATION_DEADLINE_EPOCH'), + ), + }); + const summary = cratesIoCapacitySummary(capacityAssessment); + console.log(summary); + if (process.env.GITHUB_STEP_SUMMARY?.trim()) { + appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${summary}\n`); + } + + const missing = reconciliation.missingCarriers.filter(({ id }) => scopedIds.has(id)); + if ( + missing.some(({ ecosystem }) => ecosystem === 'cargo') && + !process.env.CARGO_REGISTRY_TOKEN?.trim() + ) { + throw new Error( + 'CRATES_IO_BOOTSTRAP_TOKEN is required because the approved candidate contains absent Cargo names', + ); + } + if (missing.some(({ ecosystem }) => ecosystem === 'npm')) { + const npmrc = process.env.NPM_CONFIG_USERCONFIG?.trim(); + let npmrcBody = ''; + try { + npmrcBody = npmrc ? readFileSync(npmrc, 'utf8') : ''; + } catch {} + if (!/^\/\/registry[.]npmjs[.]org\/:_authToken=[^\r\n]+\r?\n?$/u.test(npmrcBody)) { + throw new Error( + 'NPM_BOOTSTRAP_TOKEN is required because the approved candidate contains absent npm names', + ); + } + } +} catch (error) { + fail(error instanceof Error ? error.message : String(error)); +} + +// Prove every matching public version against the frozen bytes in one bounded, +// concurrent preflight. This both recovers publications accepted before an +// interrupted checkpoint and ensures public recovery skips cannot conceal an +// immutable checksum/SRI conflict. No registry mutation has happened yet. +let publicReceipts = []; +try { + const scopedPublicCarrierIds = reconciliation.publicCarrierIds.filter((id) => scopedIds.has(id)); + if (scopedPublicCarrierIds.length > 0) { + publicReceipts = await verifyLockedRegistryIntegrity(lock, { + carrierIds: scopedPublicCarrierIds, + concurrency: REGISTRY_BOOTSTRAP_INTEGRITY_CONCURRENCY, + }); + } +} catch (error) { + fail(error instanceof Error ? error.message : String(error)); +} + +// A genesis checkpoint is written only after every pre-mutation conflict and +// public-byte proof has passed. Every later file is append-only and +// content-addressed, so `if: always()` can upload a useful resume chain. +try { + if (checkpoint === null) { + checkpoint = appendBootstrapCheckpoint(bootstrapLedger, lock, products, [], { + publicationIds: scopedPlan.map(({ id }) => id), + }); + } + if (publicReceipts.length > 0) { + checkpoint = appendBootstrapCheckpoint(bootstrapLedger, lock, products, publicReceipts); + } +} catch (error) { + fail(error instanceof Error ? error.message : String(error)); +} + +if (args[0] === '--prepare') { + const admitted = new Set( + capacityAssessment.decision === 'defer' ? [] : capacityAssessment.admittedCarrierIds, + ); + const admittedPlan = scopedPlan.filter(({ id }) => admitted.has(id)); + if (admittedPlan.length !== admitted.size) + throw new Error('bootstrap admission contains a carrier outside its exact scope'); + const context = { + lockDigest: lock.lockDigest, + headRef, + admittedPlan, + scopedPlan, + capacityAssessment, + startingCompletedIds: [...startingCompletedIds], + publicCarrierIds: reconciliation.publicCarrierIds, + dependencies: bootstrapPublicationSchedule(admittedPlan, reconciliation.publicCarrierIds), + }; + writeFileSync(path.join(path.resolve(args[1]), 'context.json'), JSON.stringify(context), { + flag: 'wx', + mode: 0o600, + }); + process.exit(0); +} + +function stderrTail(file) { + const size = statSync(file).size; + const bytes = Buffer.alloc(Math.min(size, CHILD_STDERR_TAIL_BYTES)); + const descriptor = openSync(file, 'r'); + try { + readSync(descriptor, bytes, 0, bytes.length, size - bytes.length); + } finally { + closeSync(descriptor); + } + return bytes.toString('utf8'); +} + +async function savedBootstrapPhase(phase, directory) { + const context = JSON.parse(readFileSync(path.join(directory, 'context.json'), 'utf8')); + if (context.lockDigest !== lock.lockDigest || context.headRef !== headRef) + throw new Error('bootstrap state does not match the current frozen lock/source'); + const { scopedPlan, capacityAssessment } = context; + const startingCompletedIds = new Set(context.startingCompletedIds); + let checkpoint = loadBootstrapLedger(bootstrapLedger, lock, products, { allowEmpty: true }); + if (phase === '--checkpoint') { + const recorded = new Set(checkpoint?.receipts.map((receipt) => receipt.id) ?? []); + const receipts = []; + for (const [index, carrier] of context.admittedPlan.entries()) { + const file = path.join(directory, 'operation-' + index + '.json'); + if (!existsSync(file) || recorded.has(carrier.id)) continue; + const receipt = JSON.parse(readFileSync(file, 'utf8')); + if (receipt?.id !== carrier.id) + throw new Error('bootstrap receipt does not match its admitted carrier'); + receipts.push(receipt); + } + if (receipts.length) + checkpoint = appendBootstrapCheckpoint(bootstrapLedger, lock, products, receipts); + writeFileSync( + path.join(directory, 'checkpoint-count'), + String( + context.admittedPlan.filter((carrier) => + checkpoint?.receipts.some((receipt) => receipt.id === carrier.id), + ).length, + ), + ); + return; + } + const deferrals = []; + for (const [index, carrier] of context.admittedPlan.entries()) { + const status = path.join(directory, 'status-' + index); + if (!existsSync(status)) continue; + const code = Number(readFileSync(status, 'utf8')); + if (code === 0) continue; + if (code !== REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE) + throw new Error(carrier.id + ' bootstrap failed with exit ' + code); + deferrals.push( + decodeRegistryPublicationDeferral(stderrTail(path.join(directory, 'stderr-' + index))), + ); + } + if ( + existsSync(path.join(directory, 'checkpoint-failed')) || + existsSync(path.join(directory, 'lane-failed')) + ) + throw new Error( + 'bootstrap execution or checkpoint failed; recovered receipts remain available for resume', + ); + const execution = { + deferReason: + capacityAssessment.decision === 'defer' + ? 'capacity' + : deferrals.some((row) => row.reason === 'deadline') + ? 'deadline' + : deferrals.length + ? 'rate-limit' + : null, + notBeforeEpochSeconds: deferrals.length + ? Math.max(...deferrals.map((row) => row.notBeforeEpochSeconds)) + : capacityAssessment.decision === 'defer' + ? capacityAssessment.notBeforeEpochSeconds + : null, + }; + let result; + + checkpoint = loadBootstrapLedger(bootstrapLedger, lock, products, { allowEmpty: true }); + const completedSet = new Set(checkpoint?.receipts.map(({ id }) => id) ?? []); + const completedIds = scopedPlan.filter(({ id }) => completedSet.has(id)).map(({ id }) => id); + if (completedIds.length !== completedSet.size) { + throw new Error('bootstrap ledger contains a receipt outside the exact canonical plan'); + } + const remainingIds = scopedPlan.filter(({ id }) => !completedSet.has(id)).map(({ id }) => id); + const newlyCompletedIds = completedIds.filter((id) => !startingCompletedIds.has(id)); + const decision = remainingIds.length === 0 ? 'complete' : 'deferred'; + if (decision === 'complete') { + checkpoint = loadBootstrapLedger(bootstrapLedger, lock, products, { requireComplete: true }); + } + const remainingHasCargo = scopedPlan.some( + ({ id, ecosystem }) => ecosystem === 'cargo' && remainingIds.includes(id), + ); + const notBeforeEpochSeconds = + decision === 'complete' + ? null + : (execution.notBeforeEpochSeconds ?? + Math.floor(Date.now() / 1000) + + (remainingHasCargo ? CRATES_IO_NEW_CRATE_REFILL_SECONDS : 1)); + const deferralMode = + decision === 'complete' + ? null + : newlyCompletedIds.length > 0 + ? 'progress' + : execution.deferReason === 'rate-limit' + ? 'rate-limit' + : execution.deferReason === 'capacity' + ? 'pre-mutation-capacity' + : execution.deferReason === 'deadline' + ? 'pre-mutation-deadline' + : (() => { + throw new Error( + `zero-progress bootstrap deferral requires an explicit rate-limit or deadline reason; got ` + + `${execution.deferReason ?? 'none'}`, + ); + })(); + result = writeExecutionResult({ + schema: 'oliphaunt-bootstrap-execution-result-v1', + operation: 'publish-bootstrap', + decision, + deferralMode, + source: { commit: lock.source.commit, tree: lock.source.tree }, + lock: { + lockDigest: lock.lockDigest, + catalogDigest: lock.catalogDigest, + packageEnvelopeDigest: lock.packageEnvelopeDigest, + }, + products: [...products].sort(), + admittedIds: scopedPlan + .filter(({ id }) => capacityAssessment.admittedCarrierIds.includes(id)) + .map(({ id }) => id), + completedIds, + newlyCompletedIds, + remainingIds, + notBeforeEpochSeconds, + }); + console.log( + 'Bootstrap ' + + result.decision + + ': ' + + result.newlyCompletedIds.length + + ' new receipts, ' + + result.remainingIds.length + + ' remaining', + ); +} diff --git a/.github/scripts/bootstrap-registry-identities.sh b/.github/scripts/bootstrap-registry-identities.sh new file mode 100644 index 000000000..c06fedcef --- /dev/null +++ b/.github/scripts/bootstrap-registry-identities.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +if [[ "$#" != 0 ]]; then echo 'usage: bootstrap-registry-identities.sh (uses the approved workflow environment)' >&2; exit 2; fi +state="$(mktemp -d)" +trap 'rm -rf "$state"' EXIT +native() { bash tools/dev/bun.sh .github/scripts/bootstrap-registry-identities.mts "$1" "$state"; } +publisher() { + bash tools/release/with-source.sh "${RELEASE_HEAD_SHA:-HEAD}" bash tools/dev/bun.sh tools/release/release-publish.mts "$1" "$state" "$2" \ + --bootstrap-identities --head-ref "$RELEASE_HEAD_SHA" --publication-lock "$PUBLICATION_LOCK_PATH" \ + --bootstrap-ledger "$BOOTSTRAP_LEDGER_PATH" +} +native --prepare +if jq -e 'any(.admittedPlan[]; .ecosystem == "npm")' "$state/context.json" >/dev/null; then + transport_timeout="$(command -v timeout || command -v gtimeout)" || { echo 'GNU timeout is required for npm bootstrap' >&2; exit 1; } +fi +checkpoint() { + local files count previous status + shopt -s nullglob + files=("$state"/operation-*.json) + count="${#files[@]}" + previous=0 + [[ ! -f "$state/checkpoint-count" ]] || previous="$(cat "$state/checkpoint-count")" + (( count - previous >= 32 )) || return 0 + until mkdir "$state/checkpoint-lock" 2>/dev/null; do + [[ ! -f "$state/abort" ]] || return 0 + sleep 0.1 + done + status=0 + native --checkpoint || status=$? + if [[ "$status" != 0 ]]; then : > "$state/checkpoint-failed"; : > "$state/abort"; fi + rmdir "$state/checkpoint-lock" + return "$status" +} +publish_carrier() { + local index="$1" ecosystem="$2" admission tarball registry seconds + if [[ "$ecosystem" == cargo ]]; then publisher bootstrap-cargo "$index"; return; fi + publisher bootstrap-npm-before "$index" || return + [[ ! -f "$state/operation-$index.json" && ! -f "$state/abort" ]] || return 0 + admission="$state/npm-$index.json" + tarball="$(jq -r .tarball "$admission")" || return + registry="$(jq -r .registry "$admission")" || return + seconds="$(jq -r '.timeout / 1000 | floor' "$admission")" || return + NPM_CONFIG_FETCH_RETRIES=0 "$transport_timeout" --kill-after=5s "${seconds}s" \ + npm publish "$tarball" --access public --provenance --registry "$registry" || true + publisher bootstrap-npm-after "$index" +} +lane() ( + trap 'status=$?; if [[ "$status" != 0 ]]; then : > "$state/lane-failed"; : > "$state/abort"; fi; exit "$status"' EXIT + ecosystem="$1" + if [[ "$ecosystem" == cargo ]]; then + unset NODE_AUTH_TOKEN NPM_BOOTSTRAP_TOKEN NPM_CONFIG__AUTH NPM_CONFIG__AUTHTOKEN NPM_CONFIG_USERCONFIG NPM_TOKEN + else + unset CARGO_REGISTRIES_CRATES_IO_TOKEN CARGO_REGISTRY_TOKEN CRATES_IO_BOOTSTRAP_TOKEN CRATES_IO_TRUST_CONFIG_TOKEN + fi + for index in $(jq -r --arg ecosystem "$ecosystem" '.admittedPlan | to_entries[] | select(.value.ecosystem == $ecosystem) | .key' "$state/context.json"); do + [[ ! -f "$state/abort" ]] || break + for dependency in $(jq -r --argjson index "$index" '.dependencies[$index][]' "$state/context.json"); do + until [[ -f "$state/operation-$dependency.json" ]]; do + [[ ! -f "$state/abort" ]] || exit 0 + sleep 0.1 + done + done + [[ ! -f "$state/abort" ]] || break + status=0 + publish_carrier "$index" "$ecosystem" 2> "$state/stderr-$index" || status=$? + cat "$state/stderr-$index" >&2 + echo "$status" > "$state/status-$index" + if [[ "$status" != 0 ]]; then : > "$state/abort"; break; fi + [[ ! -f "$state/abort" ]] || break + checkpoint + done +) +lane cargo & cargo_pid=$! +lane npm & npm_pid=$! +wait "$cargo_pid" || true +wait "$npm_pid" || true +# Flush accepted uploads even after a peer or checkpoint failure. A successful +# recovery preserves receipts without erasing the original failure. +native --checkpoint || : > "$state/checkpoint-failed" +native --finish diff --git a/.github/scripts/check-ci-gate.mjs b/.github/scripts/check-ci-gate.mjs deleted file mode 100644 index f99c14a38..000000000 --- a/.github/scripts/check-ci-gate.mjs +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bun -import { env, exit } from 'node:process'; - -function fail(message) { - console.error(message); - exit(1); -} - -function parseJsonEnv(name, fallback) { - const raw = env[name]; - if (!raw) { - return fallback; - } - try { - return JSON.parse(raw); - } catch (error) { - fail(`invalid ${name} JSON: ${error.message}`); - } -} - -function selectedJobs() { - const jobs = parseJsonEnv('SELECTED_JOBS_JSON', []); - if (!Array.isArray(jobs) || jobs.some((job) => typeof job !== 'string')) { - fail('SELECTED_JOBS_JSON must be a JSON string array'); - } - return [...new Set(jobs)].sort(); -} - -function requiredJobs() { - const fromJson = parseJsonEnv('REQUIRED_JOBS_JSON', null); - if (fromJson !== null) { - if (!Array.isArray(fromJson) || fromJson.some((job) => typeof job !== 'string')) { - fail('REQUIRED_JOBS_JSON must be a JSON string array'); - } - return [...new Set(fromJson)].sort(); - } - return (env.REQUIRED_JOBS ?? '') - .split(',') - .map((job) => job.trim()) - .filter(Boolean) - .sort(); -} - -function needs() { - const parsed = parseJsonEnv('NEEDS_JSON', {}); - if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { - fail('NEEDS_JSON must be a JSON object'); - } - return parsed; -} - -function resultFor(needsByJob, job) { - const result = needsByJob[job]?.result; - return typeof result === 'string' && result.length > 0 ? result : 'missing'; -} - -function checkJobs(jobs, { label }) { - const needsByJob = needs(); - const failures = jobs - .map((job) => [job, resultFor(needsByJob, job)]) - .filter(([, result]) => result !== 'success') - .map(([job, result]) => `${job}=${result}`); - - if (failures.length > 0) { - fail(`${label} failures: ${failures.join(', ')}`); - } - - console.log(`${label} passed: ${jobs.length > 0 ? jobs.join(', ') : '(none selected)'}`); -} - -const mode = process.argv[2] ?? ''; -switch (mode) { - case 'selected': - checkJobs(selectedJobs(), { label: env.GATE_LABEL || 'selected jobs' }); - break; - case 'required': - checkJobs(requiredJobs(), { label: env.GATE_LABEL || 'required jobs' }); - break; - default: - fail('usage: check-ci-gate.mjs [selected|required]'); -} diff --git a/.github/scripts/check-ci-gate.mts b/.github/scripts/check-ci-gate.mts new file mode 100644 index 000000000..2c2f00875 --- /dev/null +++ b/.github/scripts/check-ci-gate.mts @@ -0,0 +1,81 @@ +#!/usr/bin/env bun +import { env, exit } from 'node:process'; + +function fail(message) { + console.error(message); + exit(1); +} + +function parseJsonEnv(name, fallback) { + const raw = env[name]; + if (!raw) { + return fallback; + } + try { + return JSON.parse(raw); + } catch (error) { + fail(`invalid ${name} JSON: ${error.message}`); + } +} + +function selectedJobs() { + const jobs = parseJsonEnv('SELECTED_JOBS_JSON', []); + if (!Array.isArray(jobs) || jobs.some((job) => typeof job !== 'string')) { + fail('SELECTED_JOBS_JSON must be a JSON string array'); + } + return [...new Set(jobs)].sort(); +} + +function requiredJobs() { + const fromJson = parseJsonEnv('REQUIRED_JOBS_JSON', null); + if (fromJson !== null) { + if (!Array.isArray(fromJson) || fromJson.some((job) => typeof job !== 'string')) { + fail('REQUIRED_JOBS_JSON must be a JSON string array'); + } + return [...new Set(fromJson)].sort(); + } + return (env.REQUIRED_JOBS ?? '') + .split(',') + .map((job) => job.trim()) + .filter(Boolean) + .sort(); +} + +function needs() { + const parsed = parseJsonEnv('NEEDS_JSON', {}); + if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { + fail('NEEDS_JSON must be a JSON object'); + } + return parsed; +} + +function resultFor(needsByJob, job) { + const result = needsByJob[job]?.result; + return typeof result === 'string' && result.length > 0 ? result : 'missing'; +} + +function checkJobs(jobs, { label }) { + const needsByJob = needs(); + const failures = jobs + .map((job) => [job, resultFor(needsByJob, job)]) + .filter(([, result]) => result !== 'success') + .map(([job, result]) => `${job}=${result}`); + + if (failures.length > 0) { + fail(`${label} failures: ${failures.join(', ')}`); + } + + console.log(`${label} passed: ${jobs.length > 0 ? jobs.join(', ') : '(none selected)'}`); +} + +const mode = process.argv[2] ?? ''; +switch (mode) { + case 'selected': + checkJobs(selectedJobs(), { label: env.GATE_LABEL || 'selected jobs' }); + break; + case 'required': + checkJobs(requiredJobs(), { label: env.GATE_LABEL || 'required jobs' }); + break; + default: + fail('usage: check-ci-gate.mts [selected|required]'); +} diff --git a/.github/scripts/check-ci-gate.test.sh b/.github/scripts/check-ci-gate.test.sh new file mode 100644 index 000000000..abf050d01 --- /dev/null +++ b/.github/scripts/check-ci-gate.test.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +output="$(mktemp)" +trap 'rm -f "$output"' EXIT +gate() { + env -i PATH="$PATH" HOME="$HOME" NEEDS_JSON="$2" SELECTED_JOBS_JSON="$3" \ + REQUIRED_JOBS_JSON="$3" GATE_LABEL='test gate' \ + bun .github/scripts/check-ci-gate.mts "$1" > "$output" 2>&1 +} +reject() { + local message="$1"; shift + if gate "$@"; then echo 'CI gate accepted invalid state' >&2; exit 1; fi + rg -q -F "$message" "$output" +} +gate selected '{}' '[]' +gate selected '{"android":{"result":"success"},"ios":{"result":"success"}}' '["ios","android","ios"]' +for result in skipped failure cancelled; do + reject "ios=$result" selected "{\"ios\":{\"result\":\"$result\"}}" '["ios"]' +done +reject 'ios=missing' selected '{}' '["ios"]' +reject 'must be a JSON string array' selected '{}' '"ios"' +reject 'resolve=skipped' required '{"resolve":{"result":"skipped"}}' '["resolve"]' +reject 'usage: check-ci-gate.mts [selected|required]' allow-skipped '{}' '["ios"]' +echo 'CI gate: only successful selected and required jobs pass' diff --git a/.github/scripts/check-release-intent.sh b/.github/scripts/check-release-intent.sh index 516faa548..45633a0c2 100755 --- a/.github/scripts/check-release-intent.sh +++ b/.github/scripts/check-release-intent.sh @@ -32,7 +32,7 @@ if [[ "${event_name}" == "workflow_dispatch" ]] && exit 1 fi dispatch_parents="$(git rev-list --parents -n 1 "${head_ref}^{commit}")" - read -r -a dispatch_commit_and_parents <<< "${dispatch_parents}" + read -r -a dispatch_commit_and_parents <<<"${dispatch_parents}" if [[ "${#dispatch_commit_and_parents[@]}" -ne 2 ]]; then echo "manual main qualification requires an exact one-parent commit" >&2 exit 1 @@ -54,20 +54,7 @@ fi release_types="$({ git show "${head_ref}:release-please-config.json" | - bun -e ' -const config = JSON.parse(await Bun.stdin.text()); -const sections = config["changelog-sections"]; -if (!Array.isArray(sections) || sections.length === 0) { - console.error("release-please-config.json must define changelog-sections"); - process.exit(1); -} -const types = [...new Set(sections.map((section) => section?.type))]; -if (types.some((type) => typeof type !== "string" || !/^[a-z][a-z0-9-]*$/.test(type))) { - console.error("release-please changelog section types must be conventional lowercase identifiers"); - process.exit(1); -} -console.log(types.join("|")); -' + bun "$(dirname "${BASH_SOURCE[0]}")/release-intent-data.mts" types })" if [[ -z "${release_types}" ]]; then echo "could not derive release-impact types from release-please-config.json" >&2 @@ -87,82 +74,24 @@ if [[ "${subject}" =~ ${release_pr_pattern} ]]; then fi fi -package_versions_from_ref() { - local ref="${1:?package_versions_from_ref requires a git ref}" - local files - - files="$( - git ls-tree -r --name-only "${ref}" | - grep -E '(^Cargo.toml$|^src/.*/Cargo.toml$|^tools/xtask/Cargo.toml$)' || true - )" - - while IFS= read -r file; do - [[ -z "${file}" ]] && continue - git show "${ref}:${file}" | awk -v file="${file}" ' - /^\[package\][[:space:]]*$/ { - in_package = 1 - next - } - /^\[/ && in_package { - exit - } - in_package && $0 ~ /^[[:space:]]*name[[:space:]]*=/ { - name = $0 - sub(/^[^=]*=[[:space:]]*"/, "", name) - sub(/".*$/, "", name) - } - in_package && $0 ~ /^[[:space:]]*version[[:space:]]*=/ { - line = $0 - sub(/^[^=]*=[[:space:]]*"/, "", line) - sub(/".*$/, "", line) - if (name == "") { - name = file - } - print name "=" line - exit - } - ' - done <<< "${files}" | sort -} - -base_versions="$(package_versions_from_ref "${base_ref}")" -head_versions="$(package_versions_from_ref "${head_ref}")" release_manifest_versions_from_ref() { local ref="${1:?release_manifest_versions_from_ref requires a git ref}" local manifest if ! manifest="$(git show "${ref}:.release-please-manifest.json" 2>/dev/null)"; then return 0 fi - # shellcheck disable=SC2016 printf '%s\n' "${manifest}" | - bun -e ' -let data; -try { - data = JSON.parse(await Bun.stdin.text()); -} catch { - process.exit(0); -} -for (const [path, version] of Object.entries(data).sort(([left], [right]) => - left < right ? -1 : left > right ? 1 : 0)) { - console.log(`${path}=${version}`); -} -' + bun "$(dirname "${BASH_SOURCE[0]}")/release-intent-data.mts" versions } base_release_manifest_versions="$(release_manifest_versions_from_ref "${base_ref}")" head_release_manifest_versions="$(release_manifest_versions_from_ref "${head_ref}")" -if [[ -z "${base_versions}" || -z "${head_versions}" || -z "${head_release_manifest_versions}" ]]; then - echo "could not read package versions or release-please manifest versions" >&2 +if [[ -z "${head_release_manifest_versions}" ]]; then + echo "could not read release-please manifest versions" >&2 exit 1 fi -changed_existing_versions="$( - join -t $'\t' \ - <(printf '%s\n' "${base_versions}" | sed 's/=/\t/' | sort -t $'\t' -k1,1) \ - <(printf '%s\n' "${head_versions}" | sed 's/=/\t/' | sort -t $'\t' -k1,1) | - awk -F '\t' '$2 != $3 { print $1 "=" $2 " -> " $3 }' -)" if [[ -n "${base_release_manifest_versions}" ]]; then changed_existing_release_manifest_versions="$( join -t $'\t' \ @@ -174,13 +103,12 @@ else changed_existing_release_manifest_versions="" fi -if [[ -n "${changed_existing_versions}${changed_existing_release_manifest_versions}" ]] && +if [[ -n "${changed_existing_release_manifest_versions}" ]] && [[ "${is_release_pr}" != true ]]; then cat >&2 <&2 - exit 2 -} - -configure_android=false -if [[ $# -gt 1 ]]; then - usage -fi -if [[ $# -eq 1 ]]; then - [[ "$1" == --android ]] || usage - configure_android=true -fi -if [[ "${RUNNER_OS:-}" != macOS ]]; then - echo 'macOS release toolchain configuration requires a GitHub macOS runner' >&2 - exit 1 -fi -: "${GITHUB_ENV:?GitHub must provide GITHUB_ENV}" -: "${GITHUB_PATH:?GitHub must provide GITHUB_PATH}" - -java_home_17="${JAVA_HOME_17_arm64:-${JAVA_HOME_17_X64:-}}" -if [[ -z "$java_home_17" || ! -x "$java_home_17/bin/java" ]]; then - echo 'macOS release runner does not expose a usable Java 17 toolchain' >&2 - exit 1 -fi -printf 'JAVA_HOME=%s\n' "$java_home_17" >> "$GITHUB_ENV" -printf '%s\n' "$java_home_17/bin" >> "$GITHUB_PATH" - -if [[ "$configure_android" == true ]]; then - android_home="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}" - if [[ -z "$android_home" && -d "$HOME/Library/Android/sdk" ]]; then - android_home="$HOME/Library/Android/sdk" - fi - if [[ -z "$android_home" || ! -d "$android_home" ]]; then - echo 'macOS release runner does not expose a usable Android SDK' >&2 - exit 1 - fi - printf 'ANDROID_HOME=%s\n' "$android_home" >> "$GITHUB_ENV" - printf 'ANDROID_SDK_ROOT=%s\n' "$android_home" >> "$GITHUB_ENV" -fi diff --git a/.github/scripts/configure-macos-release-toolchains.test.mjs b/.github/scripts/configure-macos-release-toolchains.test.mjs deleted file mode 100644 index 53f3602f0..000000000 --- a/.github/scripts/configure-macos-release-toolchains.test.mjs +++ /dev/null @@ -1,84 +0,0 @@ -import assert from "node:assert/strict"; -import { spawnSync } from "../../tools/test/fd-backed-spawn-sync.mjs"; -import { - chmodSync, - mkdtempSync, - mkdirSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import test from "node:test"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -const SCRIPT = path.join(ROOT, ".github/scripts/configure-macos-release-toolchains.sh"); - -function fixture(t) { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-macos-release-toolchains-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const javaHome = path.join(root, "java-17"); - const androidHome = path.join(root, "android-sdk"); - const githubEnv = path.join(root, "github-env"); - const githubPath = path.join(root, "github-path"); - mkdirSync(path.join(javaHome, "bin"), { recursive: true }); - mkdirSync(androidHome); - writeFileSync(path.join(javaHome, "bin/java"), "#!/usr/bin/env sh\nexit 0\n"); - chmodSync(path.join(javaHome, "bin/java"), 0o755); - writeFileSync(githubEnv, ""); - writeFileSync(githubPath, ""); - return { androidHome, githubEnv, githubPath, javaHome, root }; -} - -function run(value, args = [], overrides = {}) { - return spawnSync("bash", [SCRIPT, ...args], { - cwd: ROOT, - encoding: "utf8", - env: { - ...process.env, - ANDROID_HOME: "", - ANDROID_SDK_ROOT: "", - GITHUB_ENV: value.githubEnv, - GITHUB_PATH: value.githubPath, - HOME: value.root, - JAVA_HOME_17_X64: "", - JAVA_HOME_17_arm64: value.javaHome, - RUNNER_OS: "macOS", - ...overrides, - }, - }); -} - -test("configures exact Java and Android identities for publication-host validation", (t) => { - const value = fixture(t); - const result = run(value, ["--android"], { ANDROID_HOME: value.androidHome }); - assert.equal(result.status, 0, result.stderr || result.stdout); - assert.equal( - readFileSync(value.githubEnv, "utf8"), - `JAVA_HOME=${value.javaHome}\nANDROID_HOME=${value.androidHome}\nANDROID_SDK_ROOT=${value.androidHome}\n`, - ); - assert.equal(readFileSync(value.githubPath, "utf8"), `${value.javaHome}/bin\n`); -}); - -test("registry/finalization mode configures Java without widening to Android", (t) => { - const value = fixture(t); - const result = run(value); - assert.equal(result.status, 0, result.stderr || result.stdout); - assert.equal(readFileSync(value.githubEnv, "utf8"), `JAVA_HOME=${value.javaHome}\n`); - assert.equal(readFileSync(value.githubPath, "utf8"), `${value.javaHome}/bin\n`); -}); - -test("fails closed outside macOS and for missing or malformed toolchains", (t) => { - for (const [args, overrides, pattern] of [ - [[], { RUNNER_OS: "Linux" }, /requires a GitHub macOS runner/u], - [[], { JAVA_HOME_17_arm64: "/missing" }, /usable Java 17/u], - [["--android"], {}, /usable Android SDK/u], - [["--unknown"], {}, /usage:/u], - ]) { - const value = fixture(t); - const result = run(value, args, overrides); - assert.notEqual(result.status, 0, result.stdout); - assert.match(result.stderr, pattern); - } -}); diff --git a/.github/scripts/download-bootstrap-ledger.mjs b/.github/scripts/download-bootstrap-ledger.mjs deleted file mode 100644 index 35bb5d081..000000000 --- a/.github/scripts/download-bootstrap-ledger.mjs +++ /dev/null @@ -1,421 +0,0 @@ -#!/usr/bin/env node -import { createHash } from "node:crypto"; -import { - appendFileSync, - copyFileSync, - existsSync, - readFileSync, - readdirSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import process from "node:process"; -import { fileURLToPath } from "node:url"; - -import { - createSiblingStage, - promoteDirectory, - removeTemporaryPath, - stageExistingDirectory, -} from "../../tools/release/atomic-directory.mjs"; -import { - retryReadOperationSync, - runGitHubPaginatedJsonSync, - runGitHubReadSync, -} from "../../tools/release/github-read.mjs"; -import { captureCommandOutput } from "../../tools/dev/capture-command-output.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const ARTIFACT = "oliphaunt-bootstrap-ledger"; -const CHECKPOINT = /^checkpoint-[0-9]{6}-[0-9a-f]{64}[.]json$/u; -const MAX_ARTIFACT_BYTES = 128 * 1024 * 1024; - -function fail(message) { - throw new Error(`download-bootstrap-ledger: ${message}`); -} - -function required(name) { - const value = process.env[name]?.trim(); - if (!value) fail(`${name} is required`); - return value; -} - -function command(commandName, args, { stdoutTerminator = undefined } = {}) { - const result = captureCommandOutput(commandName, args, { - cwd: ROOT, - env: process.env, - label: `${commandName} ${args.join(" ")}`, - maxOutputBytes: MAX_ARTIFACT_BYTES, - stdoutTerminator, - }); - if (result.error !== undefined || result.status !== 0) { - fail( - `${commandName} ${args.join(" ")} failed: ` + - `${(result.stderr || result.stdout || result.error?.message || "").trim()}`, - ); - } - return result.stdout; -} - -function gh(args) { - return runGitHubReadSync(args, { - cwd: ROOT, - label: `bootstrap ledger GitHub ${args[0]} ${args[1]} read`, - maxBuffer: MAX_ARTIFACT_BYTES, - }).trim(); -} - -function ghBinary(args, options = {}) { - const result = runGitHubReadSync(args, { - binary: true, - cwd: ROOT, - label: options.label ?? `bootstrap ledger GitHub ${args[0]} ${args[1]} read`, - maxBuffer: MAX_ARTIFACT_BYTES, - ...options, - }); - if (!Buffer.isBuffer(result)) fail("gh artifact download did not return binary data"); - return result; -} - -function json(text, label) { - try { - return JSON.parse(text); - } catch (error) { - fail(`${label} returned invalid JSON: ${error.message}`); - } -} - -function timestamp(value, label) { - if (typeof value !== "string" || !value.endsWith("Z")) fail(`${label} must be a UTC timestamp`); - const milliseconds = Date.parse(value); - if (!Number.isFinite(milliseconds)) fail(`${label} must be a valid UTC timestamp`); - return milliseconds; -} - -function positiveIntegerString(value, label) { - const rendered = String(value ?? ""); - if (!/^[1-9][0-9]*$/u.test(rendered)) fail(`${label} must be a positive integer`); - return rendered; -} - -function attemptNumber(value) { - const rendered = positiveIntegerString(value, "GITHUB_RUN_ATTEMPT"); - const parsed = Number(rendered); - if (!Number.isSafeInteger(parsed)) fail("GITHUB_RUN_ATTEMPT must be a safe integer"); - return parsed; -} - -function ledgerArtifactInventory(repo, sha, currentRun) { - const artifacts = runGitHubPaginatedJsonSync( - `repos/${repo}/actions/artifacts?name=${encodeURIComponent(ARTIFACT)}`, - { - cwd: ROOT, - itemsField: "artifacts", - label: `repository ${ARTIFACT} inventory`, - maxBuffer: MAX_ARTIFACT_BYTES, - }, - ); - const byRun = new Map(); - for (const entry of artifacts) { - if ( - entry === null - || Array.isArray(entry) - || typeof entry !== "object" - || entry.name !== ARTIFACT - || entry.workflow_run === null - || Array.isArray(entry.workflow_run) - || typeof entry.workflow_run !== "object" - || !/^[1-9][0-9]*$/u.test(String(entry.workflow_run.id ?? "")) - || typeof entry.workflow_run.head_sha !== "string" - ) { - fail(`repository ${ARTIFACT} inventory contains malformed workflow binding`); - } - const runId = String(entry.workflow_run.id); - if (runId !== currentRun) continue; - if (entry.workflow_run.head_sha !== sha) { - fail(`current Release run ${currentRun} artifact disagrees with its exact-SHA binding`); - } - const runArtifacts = byRun.get(runId) ?? []; - runArtifacts.push(entry); - byRun.set(runId, runArtifacts); - } - return byRun; -} - -function ledgerArtifacts(artifacts, runId) { - if (!Array.isArray(artifacts)) fail(`artifact inventory for Release run ${runId} must be a list`); - const result = []; - for (const entry of artifacts) { - if (entry?.name !== ARTIFACT || entry.expired === true) continue; - if (entry === null || Array.isArray(entry) || typeof entry !== "object") { - fail(`Release run ${runId} contains malformed ${ARTIFACT} metadata`); - } - if (entry.expired !== false) fail(`${ARTIFACT} in Release run ${runId} has ambiguous expiry metadata`); - const id = positiveIntegerString(entry.id, `${ARTIFACT} artifact id in Release run ${runId}`); - if (!Number.isSafeInteger(entry.size_in_bytes) || entry.size_in_bytes <= 0) { - fail(`${ARTIFACT} artifact ${id} has an invalid immutable byte size`); - } - if (typeof entry.digest !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(entry.digest)) { - fail(`${ARTIFACT} artifact ${id} has an invalid immutable SHA-256 digest`); - } - const createdAt = timestamp(entry.created_at, `${ARTIFACT} artifact ${id} created_at`); - const updatedAt = timestamp(entry.updated_at, `${ARTIFACT} artifact ${id} updated_at`); - if (updatedAt < createdAt) fail(`${ARTIFACT} artifact ${id} was updated before it was created`); - if (entry.workflow_run?.id !== undefined && String(entry.workflow_run.id) !== runId) { - fail(`${ARTIFACT} artifact ${id} is not bound to Release run ${runId}`); - } - result.push({ createdAt, id, raw: entry, updatedAt }); - } - return result; -} - -function newest(left, right) { - if (left.updatedAt !== right.updatedAt) return right.updatedAt - left.updatedAt; - if (left.createdAt !== right.createdAt) return right.createdAt - left.createdAt; - const leftId = BigInt(left.id); - const rightId = BigInt(right.id); - return leftId < rightId ? 1 : leftId > rightId ? -1 : 0; -} - -export function selectEarlierAttemptArtifact(artifacts, { runId, currentAttemptStartedAt }) { - const normalizedRunId = positiveIntegerString(runId, "current Release run id"); - const boundary = timestamp(currentAttemptStartedAt, "current Release run attempt start"); - const candidates = ledgerArtifacts(artifacts, normalizedRunId); - const earlier = candidates - .filter(({ createdAt, updatedAt }) => createdAt < boundary && updatedAt < boundary) - .sort(newest); - const excludedCurrentAttemptIds = candidates - .filter(({ createdAt, updatedAt }) => createdAt >= boundary || updatedAt >= boundary) - .map(({ id }) => id) - .sort((left, right) => (BigInt(left) < BigInt(right) ? -1 : 1)); - return { - artifact: earlier[0]?.raw ?? null, - excludedCurrentAttemptIds, - }; -} - -export function validateAttemptMetadata(metadata, { runId, attempt, sha }) { - if (metadata === null || Array.isArray(metadata) || typeof metadata !== "object") { - fail("current Release run attempt metadata must be an object"); - } - const normalizedRunId = positiveIntegerString(runId, "current Release run id"); - if (String(metadata.id ?? "") !== normalizedRunId) fail("current attempt metadata has the wrong run id"); - if (metadata.run_attempt !== attempt) fail("current attempt metadata has the wrong attempt number"); - if (metadata.head_sha !== sha) fail("current attempt metadata has the wrong release SHA"); - if (metadata.event !== "workflow_dispatch") fail("current attempt metadata is not a workflow_dispatch run"); - timestamp(metadata.run_started_at, "current Release run attempt run_started_at"); - return metadata.run_started_at; -} - -export function validateCurrentRunMetadata(metadata, { runId, sha }) { - if (metadata === null || Array.isArray(metadata) || typeof metadata !== "object") { - fail("current Release run metadata must be an object"); - } - const normalizedRunId = positiveIntegerString(runId, "current Release run id"); - if (String(metadata.id ?? "") !== normalizedRunId) fail("current Release run metadata has the wrong run id"); - if (metadata.head_sha !== sha) fail("current Release run metadata has the wrong release SHA"); - if (metadata.event !== "workflow_dispatch") fail("current Release run metadata is not a workflow_dispatch run"); - positiveIntegerString(metadata.workflow_id, "current Release workflow id"); - timestamp(metadata.created_at, "current Release run created_at"); -} - -function files(directory) { - const result = []; - const visit = (current) => { - for (const entry of readdirSync(current, { withFileTypes: true })) { - const file = path.join(current, entry.name); - if (entry.isDirectory()) visit(file); - else if (entry.isFile()) result.push(file); - else fail(`artifact contains unsupported entry ${file}`); - } - }; - visit(directory); - return result.sort(); -} - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function same(left, right) { - return statSync(left).size === statSync(right).size && sha256(left) === sha256(right); -} - -function validateZipMembers(archive) { - const members = command("unzip", ["-Z1", archive], { stdoutTerminator: "\n" }) - .split(/\r?\n/u) - .filter(Boolean); - if (members.length === 0) fail("bootstrap ledger artifact archive is empty"); - const seen = new Set(); - for (const member of members) { - if ( - member.includes("\\") || - member.includes("/") || - member === "." || - member === ".." || - /[\u0000-\u001f\u007f]/u.test(member) || - !CHECKPOINT.test(member) - ) { - fail(`bootstrap ledger artifact contains unexpected archive member ${JSON.stringify(member)}`); - } - if (seen.has(member)) fail(`bootstrap ledger artifact repeats archive member ${member}`); - seen.add(member); - } -} - -function downloadArtifactById(repo, artifact, destination) { - const id = positiveIntegerString(artifact.id, "bootstrap ledger artifact id"); - return retryReadOperationSync( - `download bootstrap ledger artifact ${id}`, - ({ attemptTimeoutMs }) => { - const directory = createSiblingStage(destination, `artifact-${id}`); - const archive = path.join(directory, ".artifact.zip"); - try { - const bytes = ghBinary( - [ - "api", - "-H", - "X-GitHub-Api-Version: 2022-11-28", - `repos/${repo}/actions/artifacts/${id}/zip`, - ], - { - attemptTimeoutMs, - baseDelayMs: 0, - deadlineMs: attemptTimeoutMs, - label: `download bootstrap ledger artifact ${id}`, - maxAttempts: 1, - maxDelayMs: 0, - }, - ); - if (bytes.length < 4 || bytes[0] !== 0x50 || bytes[1] !== 0x4b) { - fail(`bootstrap ledger artifact ${id} did not return a ZIP archive`); - } - const digest = createHash("sha256").update(bytes).digest("hex"); - if (bytes.length !== artifact.size_in_bytes || digest !== artifact.digest.slice("sha256:".length)) { - fail( - `bootstrap ledger artifact ${id} transport identity mismatch: expected ` - + `${artifact.size_in_bytes}/${artifact.digest}, got ${bytes.length}/sha256:${digest}`, - ); - } - writeFileSync(archive, bytes, { flag: "wx" }); - validateZipMembers(archive); - command("unzip", ["-q", archive, "-d", directory]); - rmSync(archive, { force: true }); - if (files(directory).length === 0) { - fail(`bootstrap ledger artifact ${id} contains no checkpoints`); - } - return directory; - } catch (error) { - removeTemporaryPath(directory); - throw error; - } - }, - { - attemptTimeoutMs: 5 * 60_000, - deadlineMs: 15 * 60_000, - maxAttempts: 4, - }, - ); -} - -function restoreArtifact(repo, runId, artifact, destination, sourceDescription) { - const artifactId = positiveIntegerString(artifact.id, "bootstrap ledger artifact id"); - const temporary = downloadArtifactById(repo, artifact, destination); - const stage = stageExistingDirectory(destination, "restore"); - try { - const sources = files(temporary); - if (sources.length === 0) fail(`bootstrap ledger artifact ${artifactId} contains no checkpoints`); - for (const source of sources) { - const name = path.basename(source); - const relative = path.relative(temporary, source).split(path.sep).join("/"); - if (relative !== name || !CHECKPOINT.test(name)) { - fail(`bootstrap ledger artifact contains unexpected file ${relative}`); - } - const target = path.join(stage, name); - if (statSync(target, { throwIfNoEntry: false })?.isFile()) { - if (!same(source, target)) fail(`prior checkpoint conflicts with local ${name}`); - } else { - copyFileSync(source, target); - } - } - promoteDirectory(stage, destination); - } finally { - removeTemporaryPath(temporary); - if (existsSync(stage)) removeTemporaryPath(stage); - } - if (process.env.GITHUB_OUTPUT) { - appendFileSync(process.env.GITHUB_OUTPUT, `found=true\nrun_id=${runId}\n`); - } - console.log( - `restored immutable bootstrap checkpoint chain from ${sourceDescription} ` + - `(Release run ${runId}, artifact ${artifactId})`, - ); -} - -export async function main() { - const repo = required("GH_REPO"); - const sha = process.env.GITHUB_SHA || required("RELEASE_HEAD_SHA"); - if (!/^[0-9a-f]{40}$/u.test(sha)) fail("RELEASE_HEAD_SHA must be a full lowercase commit SHA"); - const destination = path.resolve( - ROOT, - process.env.BOOTSTRAP_LEDGER_PATH || "target/release/bootstrap-ledger", - ); - const currentRun = positiveIntegerString(required("GITHUB_RUN_ID"), "GITHUB_RUN_ID"); - const currentAttempt = attemptNumber(required("GITHUB_RUN_ATTEMPT")); - const currentRunMetadata = json( - gh(["api", `repos/${repo}/actions/runs/${currentRun}`]), - `current Release run ${currentRun}`, - ); - validateCurrentRunMetadata(currentRunMetadata, { - runId: currentRun, - sha, - }); - const artifactsByRun = ledgerArtifactInventory(repo, sha, currentRun); - - let excludedCurrentAttemptIds = []; - if (currentAttempt > 1) { - const metadata = json( - gh(["api", `repos/${repo}/actions/runs/${currentRun}/attempts/${currentAttempt}`]), - `Release run ${currentRun} attempt ${currentAttempt}`, - ); - const currentAttemptStartedAt = validateAttemptMetadata(metadata, { - attempt: currentAttempt, - runId: currentRun, - sha, - }); - const selected = selectEarlierAttemptArtifact(artifactsByRun.get(currentRun) ?? [], { - currentAttemptStartedAt, - runId: currentRun, - }); - excludedCurrentAttemptIds = selected.excludedCurrentAttemptIds; - if (selected.artifact !== null) { - restoreArtifact( - repo, - currentRun, - selected.artifact, - destination, - "an earlier attempt of the current run", - ); - return; - } - } - - if (excludedCurrentAttemptIds.length > 0) { - fail( - "the current rerun attempt has bootstrap ledger artifact(s), but no artifact can be proven to " + - `predate the attempt; refusing genesis ` + - `(excluded artifact ids: ${excludedCurrentAttemptIds.join(", ")})`, - ); - } - if (process.env.GITHUB_OUTPUT) appendFileSync(process.env.GITHUB_OUTPUT, "found=false\n"); - console.log("no prior bootstrap checkpoint artifact exists for this release SHA; starting a genesis chain"); -} - -if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { - main().catch((cause) => { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - }); -} diff --git a/.github/scripts/download-bootstrap-ledger.mts b/.github/scripts/download-bootstrap-ledger.mts new file mode 100644 index 000000000..4629e5544 --- /dev/null +++ b/.github/scripts/download-bootstrap-ledger.mts @@ -0,0 +1,378 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { + appendFileSync, + copyFileSync, + existsSync, + readdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; + +import { + createSiblingStage, + promoteDirectory, + removeTemporaryPath, + stageExistingDirectory, +} from '../../tools/packaging/atomic-directory.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { + boundedResponseBytes, + GitHubReadError, + requestGithubDownload, + requestGithubJsonWithRetry, + requestGithubPages, +} from '../../tools/release/github-read.mts'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); +const ARTIFACT = 'oliphaunt-bootstrap-ledger'; +const CHECKPOINT = /^checkpoint-[0-9]{6}-[0-9a-f]{64}[.]json$/u; +const MAX_ARTIFACT_BYTES = 128 * 1024 * 1024; + +function fail(message) { + throw new Error(`download-bootstrap-ledger: ${message}`); +} + +function required(name) { + const value = process.env[name]?.trim(); + if (!value) fail(`${name} is required`); + return value; +} + +function timestamp(value, label) { + if (typeof value !== 'string' || !value.endsWith('Z')) fail(`${label} must be a UTC timestamp`); + const milliseconds = Date.parse(value); + if (!Number.isFinite(milliseconds)) fail(`${label} must be a valid UTC timestamp`); + return milliseconds; +} + +function positiveIntegerString(value, label) { + const rendered = String(value ?? ''); + if (!/^[1-9][0-9]*$/u.test(rendered)) fail(`${label} must be a positive integer`); + return rendered; +} + +function attemptNumber(value) { + const rendered = positiveIntegerString(value, 'GITHUB_RUN_ATTEMPT'); + const parsed = Number(rendered); + if (!Number.isSafeInteger(parsed)) fail('GITHUB_RUN_ATTEMPT must be a safe integer'); + return parsed; +} + +async function ledgerArtifactInventory(repo, sha, currentRun) { + const artifacts = await requestGithubPages( + `repos/${repo}/actions/artifacts?name=${encodeURIComponent(ARTIFACT)}`, + { + cwd: ROOT, + itemsField: 'artifacts', + label: `repository ${ARTIFACT} inventory`, + maxBuffer: MAX_ARTIFACT_BYTES, + }, + ); + const byRun = new Map(); + for (const entry of artifacts) { + if ( + entry === null || + Array.isArray(entry) || + typeof entry !== 'object' || + entry.name !== ARTIFACT || + entry.workflow_run === null || + Array.isArray(entry.workflow_run) || + typeof entry.workflow_run !== 'object' || + !/^[1-9][0-9]*$/u.test(String(entry.workflow_run.id ?? '')) || + typeof entry.workflow_run.head_sha !== 'string' + ) { + fail(`repository ${ARTIFACT} inventory contains malformed workflow binding`); + } + const runId = String(entry.workflow_run.id); + if (runId !== currentRun) continue; + if (entry.workflow_run.head_sha !== sha) { + fail(`current Release run ${currentRun} artifact disagrees with its exact-SHA binding`); + } + const runArtifacts = byRun.get(runId) ?? []; + runArtifacts.push(entry); + byRun.set(runId, runArtifacts); + } + return byRun; +} + +function ledgerArtifacts(artifacts, runId) { + if (!Array.isArray(artifacts)) fail(`artifact inventory for Release run ${runId} must be a list`); + const result = []; + for (const entry of artifacts) { + if (entry?.name !== ARTIFACT || entry.expired === true) continue; + if (entry === null || Array.isArray(entry) || typeof entry !== 'object') { + fail(`Release run ${runId} contains malformed ${ARTIFACT} metadata`); + } + if (entry.expired !== false) + fail(`${ARTIFACT} in Release run ${runId} has ambiguous expiry metadata`); + const id = positiveIntegerString(entry.id, `${ARTIFACT} artifact id in Release run ${runId}`); + if (!Number.isSafeInteger(entry.size_in_bytes) || entry.size_in_bytes <= 0) { + fail(`${ARTIFACT} artifact ${id} has an invalid immutable byte size`); + } + if (typeof entry.digest !== 'string' || !/^sha256:[0-9a-f]{64}$/u.test(entry.digest)) { + fail(`${ARTIFACT} artifact ${id} has an invalid immutable SHA-256 digest`); + } + const createdAt = timestamp(entry.created_at, `${ARTIFACT} artifact ${id} created_at`); + const updatedAt = timestamp(entry.updated_at, `${ARTIFACT} artifact ${id} updated_at`); + if (updatedAt < createdAt) fail(`${ARTIFACT} artifact ${id} was updated before it was created`); + if (entry.workflow_run?.id !== undefined && String(entry.workflow_run.id) !== runId) { + fail(`${ARTIFACT} artifact ${id} is not bound to Release run ${runId}`); + } + result.push({ createdAt, id, raw: entry, updatedAt }); + } + return result; +} + +function newest(left, right) { + if (left.updatedAt !== right.updatedAt) return right.updatedAt - left.updatedAt; + if (left.createdAt !== right.createdAt) return right.createdAt - left.createdAt; + const leftId = BigInt(left.id); + const rightId = BigInt(right.id); + return leftId < rightId ? 1 : leftId > rightId ? -1 : 0; +} + +export function selectEarlierAttemptArtifact(artifacts, { runId, currentAttemptStartedAt }) { + const normalizedRunId = positiveIntegerString(runId, 'current Release run id'); + const boundary = timestamp(currentAttemptStartedAt, 'current Release run attempt start'); + const candidates = ledgerArtifacts(artifacts, normalizedRunId); + const earlier = candidates + .filter(({ createdAt, updatedAt }) => createdAt < boundary && updatedAt < boundary) + .sort(newest); + const excludedCurrentAttemptIds = candidates + .filter(({ createdAt, updatedAt }) => createdAt >= boundary || updatedAt >= boundary) + .map(({ id }) => id) + .sort((left, right) => (BigInt(left) < BigInt(right) ? -1 : 1)); + return { + artifact: earlier[0]?.raw ?? null, + excludedCurrentAttemptIds, + }; +} + +export function validateAttemptMetadata(metadata, { runId, attempt, sha }) { + if (metadata === null || Array.isArray(metadata) || typeof metadata !== 'object') { + fail('current Release run attempt metadata must be an object'); + } + const normalizedRunId = positiveIntegerString(runId, 'current Release run id'); + if (String(metadata.id ?? '') !== normalizedRunId) + fail('current attempt metadata has the wrong run id'); + if (metadata.run_attempt !== attempt) + fail('current attempt metadata has the wrong attempt number'); + if (metadata.head_sha !== sha) fail('current attempt metadata has the wrong release SHA'); + if (metadata.event !== 'workflow_dispatch') + fail('current attempt metadata is not a workflow_dispatch run'); + timestamp(metadata.run_started_at, 'current Release run attempt run_started_at'); + return metadata.run_started_at; +} + +export function validateCurrentRunMetadata(metadata, { runId, sha }) { + if (metadata === null || Array.isArray(metadata) || typeof metadata !== 'object') { + fail('current Release run metadata must be an object'); + } + const normalizedRunId = positiveIntegerString(runId, 'current Release run id'); + if (String(metadata.id ?? '') !== normalizedRunId) + fail('current Release run metadata has the wrong run id'); + if (metadata.head_sha !== sha) fail('current Release run metadata has the wrong release SHA'); + if (metadata.event !== 'workflow_dispatch') + fail('current Release run metadata is not a workflow_dispatch run'); + positiveIntegerString(metadata.workflow_id, 'current Release workflow id'); + timestamp(metadata.created_at, 'current Release run created_at'); +} + +function files(directory) { + const result = []; + const visit = (current) => { + for (const entry of readdirSync(current, { withFileTypes: true })) { + const file = path.join(current, entry.name); + if (entry.isDirectory()) visit(file); + else if (entry.isFile()) result.push(file); + else fail(`artifact contains unsupported entry ${file}`); + } + }; + visit(directory); + return result.sort(); +} + +function sha256(file) { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} + +function same(left, right) { + return statSync(left).size === statSync(right).size && sha256(left) === sha256(right); +} + +export async function downloadBootstrapArtifact(repo, artifact, destination) { + const id = positiveIntegerString(artifact.id, 'bootstrap ledger artifact id'); + if ( + artifact.name !== ARTIFACT || + artifact.expired !== false || + !Number.isSafeInteger(artifact.size_in_bytes) || + artifact.size_in_bytes <= 0 || + artifact.size_in_bytes > MAX_ARTIFACT_BYTES || + !/^sha256:[0-9a-f]{64}$/u.test(artifact.digest ?? '') + ) + fail('bootstrap ledger artifact has invalid immutable metadata'); + const deadline = Date.now() + 15 * 60_000; + for (let attempt = 1; attempt <= 4; attempt++) { + const remaining = deadline - Date.now(); + if (remaining <= 0) fail('bootstrap ledger download deadline expired'); + const directory = createSiblingStage(destination, `artifact-${id}`); + const archive = path.join(directory, '.artifact.zip'); + try { + const response = await requestGithubDownload( + `https://api.github.com/repos/${repo}/actions/artifacts/${id}/zip`, + { timeoutMs: Math.min(5 * 60_000, remaining) }, + ); + const bytes = await boundedResponseBytes( + response, + MAX_ARTIFACT_BYTES, + 'bootstrap ledger artifact', + ); + if (bytes.length < 4 || bytes[0] !== 0x50 || bytes[1] !== 0x4b) { + fail(`bootstrap ledger artifact ${id} did not return a ZIP archive`); + } + const digest = createHash('sha256').update(bytes).digest('hex'); + if ( + bytes.length !== artifact.size_in_bytes || + digest !== artifact.digest.slice('sha256:'.length) + ) { + fail( + `bootstrap ledger artifact ${id} transport identity mismatch: expected ` + + `${artifact.size_in_bytes}/${artifact.digest}, got ${bytes.length}/sha256:${digest}`, + ); + } + writeFileSync(archive, bytes, { flag: 'wx' }); + const entries = readPortableArchiveEntries(archive, { + maxArchiveBytes: MAX_ARTIFACT_BYTES, + }); + for (const [name, entry] of entries) { + if (!CHECKPOINT.test(name) || !entry.isFile) { + fail( + `bootstrap ledger artifact contains unexpected archive member ${JSON.stringify(name)}`, + ); + } + } + for (const [name, entry] of entries) { + writeFileSync(path.join(directory, name), entry.data(), { flag: 'wx', mode: 0o600 }); + } + rmSync(archive, { force: true }); + if (files(directory).length === 0) { + fail(`bootstrap ledger artifact ${id} contains no checkpoints`); + } + return directory; + } catch (error) { + removeTemporaryPath(directory); + if (error instanceof GitHubReadError && !error.retryable) throw error; + if (attempt === 4) fail(`bootstrap ledger retry budget exhausted: ${error.message}`); + await new Promise((resolve) => setTimeout(resolve, 750 * attempt)); + } + } +} + +async function restoreArtifact(repo, runId, artifact, destination, sourceDescription) { + const artifactId = positiveIntegerString(artifact.id, 'bootstrap ledger artifact id'); + const temporary = await downloadBootstrapArtifact(repo, artifact, destination); + const stage = stageExistingDirectory(destination, 'restore'); + try { + const sources = files(temporary); + if (sources.length === 0) + fail(`bootstrap ledger artifact ${artifactId} contains no checkpoints`); + for (const source of sources) { + const name = path.basename(source); + const relative = path.relative(temporary, source).split(path.sep).join('/'); + if (relative !== name || !CHECKPOINT.test(name)) { + fail(`bootstrap ledger artifact contains unexpected file ${relative}`); + } + const target = path.join(stage, name); + if (statSync(target, { throwIfNoEntry: false })?.isFile()) { + if (!same(source, target)) fail(`prior checkpoint conflicts with local ${name}`); + } else { + copyFileSync(source, target); + } + } + promoteDirectory(stage, destination); + } finally { + removeTemporaryPath(temporary); + if (existsSync(stage)) removeTemporaryPath(stage); + } + if (process.env.GITHUB_OUTPUT) { + appendFileSync(process.env.GITHUB_OUTPUT, `found=true\nrun_id=${runId}\n`); + } + console.log( + `restored immutable bootstrap checkpoint chain from ${sourceDescription} ` + + `(Release run ${runId}, artifact ${artifactId})`, + ); +} + +export async function main() { + const repo = required('GH_REPO'); + if (!/^[A-Za-z0-9][A-Za-z0-9_.-]*\/[A-Za-z0-9][A-Za-z0-9_.-]*$/u.test(repo)) + fail('GH_REPO must be owner/repository'); + const sha = process.env.GITHUB_SHA || required('RELEASE_HEAD_SHA'); + if (!/^[0-9a-f]{40}$/u.test(sha)) fail('RELEASE_HEAD_SHA must be a full lowercase commit SHA'); + const destination = path.resolve( + ROOT, + process.env.BOOTSTRAP_LEDGER_PATH || 'target/release/bootstrap-ledger', + ); + const currentRun = positiveIntegerString(required('GITHUB_RUN_ID'), 'GITHUB_RUN_ID'); + const currentAttempt = attemptNumber(required('GITHUB_RUN_ATTEMPT')); + const currentRunMetadata = await requestGithubJsonWithRetry( + `https://api.github.com/repos/${repo}/actions/runs/${currentRun}`, + ); + validateCurrentRunMetadata(currentRunMetadata, { + runId: currentRun, + sha, + }); + const artifactsByRun = await ledgerArtifactInventory(repo, sha, currentRun); + + let excludedCurrentAttemptIds = []; + if (currentAttempt > 1) { + const metadata = await requestGithubJsonWithRetry( + `https://api.github.com/repos/${repo}/actions/runs/${currentRun}/attempts/${currentAttempt}`, + ); + const currentAttemptStartedAt = validateAttemptMetadata(metadata, { + attempt: currentAttempt, + runId: currentRun, + sha, + }); + const selected = selectEarlierAttemptArtifact(artifactsByRun.get(currentRun) ?? [], { + currentAttemptStartedAt, + runId: currentRun, + }); + excludedCurrentAttemptIds = selected.excludedCurrentAttemptIds; + if (selected.artifact !== null) { + await restoreArtifact( + repo, + currentRun, + selected.artifact, + destination, + 'an earlier attempt of the current run', + ); + return; + } + } + + if (excludedCurrentAttemptIds.length > 0) { + fail( + 'the current rerun attempt has bootstrap ledger artifact(s), but no artifact can be proven to ' + + `predate the attempt; refusing genesis ` + + `(excluded artifact ids: ${excludedCurrentAttemptIds.join(', ')})`, + ); + } + if (process.env.GITHUB_OUTPUT) appendFileSync(process.env.GITHUB_OUTPUT, 'found=false\n'); + console.log( + 'no prior bootstrap checkpoint artifact exists for this release SHA; starting a genesis chain', + ); +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + main().catch((cause) => { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + }); +} diff --git a/.github/scripts/download-bootstrap-ledger.test.mjs b/.github/scripts/download-bootstrap-ledger.test.mjs deleted file mode 100644 index 4048b7bfa..000000000 --- a/.github/scripts/download-bootstrap-ledger.test.mjs +++ /dev/null @@ -1,403 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { - chmodSync, - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { spawnSync } from "../../tools/test/fd-backed-spawn-sync.mjs"; -import { isolatedGitHubTestEnvironment } from "../../tools/test/isolated-github-test-environment.mjs"; -import test from "node:test"; - -import { - selectEarlierAttemptArtifact, - validateAttemptMetadata, -} from "./download-bootstrap-ledger.mjs"; - -const SCRIPT = path.join(import.meta.dirname, "download-bootstrap-ledger.mjs"); -const SHA = "a".repeat(40); -const ARTIFACT_NAME = "oliphaunt-bootstrap-ledger"; -const BOOTSTRAP_LEDGER_PROCESS_TIMEOUT_MS = 20_000; - -function artifact(id, runId, createdAt, updatedAt = createdAt, extra = {}) { - return { - digest: `sha256:${"a".repeat(64)}`, - id, - name: ARTIFACT_NAME, - expired: false, - size_in_bytes: 1, - created_at: createdAt, - updated_at: updatedAt, - workflow_run: { id: runId }, - ...extra, - }; -} - -function run(command, args, options = {}) { - const result = spawnSync(command, args, { - encoding: "utf8", - timeout: BOOTSTRAP_LEDGER_PROCESS_TIMEOUT_MS, - ...options, - }); - assert.equal( - result.status, - 0, - `${command} ${args.join(" ")} failed:\n${result.stderr || result.stdout}`, - ); - return result; -} - -function checkpointName(sequence, fill) { - return `checkpoint-${String(sequence).padStart(6, "0")}-${fill.repeat(64)}.json`; -} - -function ledgerZip(root, label, sequence, fill) { - const file = path.join(root, checkpointName(sequence, fill)); - const archive = path.join(root, `${label}.zip`); - writeFileSync(file, `${JSON.stringify({ label, sequence })}\n`); - run("zip", ["-q", "-j", archive, file]); - rmSync(file); - return archive; -} - -function fakeGh(root) { - const directory = path.join(root, "bin"); - const file = path.join(directory, "gh"); - run("mkdir", ["-p", directory]); - writeFileSync( - file, - `#!/usr/bin/env node -const fs = require("node:fs"); -const crypto = require("node:crypto"); -const args = process.argv.slice(2); -fs.appendFileSync(process.env.FAKE_GH_LOG, JSON.stringify(args) + "\\n"); -if (args[0] !== "api") throw new Error("unexpected gh command " + JSON.stringify(args)); -const endpoint = args.at(-1); -const attempt = /\\/runs\\/([0-9]+)\\/attempts\\/([0-9]+)$/.exec(endpoint); -if (attempt) { - process.stdout.write(process.env.FAKE_ATTEMPT_METADATA); - process.exit(0); -} -const run = /\\/actions\\/runs\\/([0-9]+)$/.exec(endpoint); -if (run) { - if (run[1] !== "900") throw new Error("unexpected run " + run[1]); - process.stdout.write(process.env.FAKE_CURRENT_RUN); - process.exit(0); -} -if (/\\/actions\\/artifacts[?]name=/.test(endpoint)) { - const url = new URL("https://api.github.com/" + endpoint); - const page = Number(url.searchParams.get("page")); - const zips = JSON.parse(process.env.FAKE_ZIPS_BY_ARTIFACT); - const all = Object.values(JSON.parse(process.env.FAKE_ARTIFACTS_BY_RUN)) - .flat() - .map((artifact) => { - const archive = zips[String(artifact.id)]; - const bytes = archive ? fs.readFileSync(archive) : null; - return { - ...artifact, - ...(bytes === null ? {} : { - size_in_bytes: bytes.length, - digest: "sha256:" + crypto.createHash("sha256").update(bytes).digest("hex"), - }), - workflow_run: { head_sha: "${SHA}", ...artifact.workflow_run }, - }; - }); - const artifacts = all.slice((page - 1) * 100, page * 100); - let link = ""; - if (page * 100 < all.length) { - const next = new URL(url); - next.searchParams.set("page", String(page + 1)); - const last = new URL(url); - last.searchParams.set("page", String(Math.ceil(all.length / 100))); - link = \`Link: <\${next}>; rel="next", <\${last}>; rel="last"\\n\`; - } - process.stdout.write("HTTP/2.0 200 OK\\n" + link + "\\n" + JSON.stringify({ - total_count: all.length, - artifacts, - })); - process.exit(0); -} -const download = /\\/artifacts\\/([0-9]+)\\/zip$/.exec(endpoint); -if (download) { - const archive = JSON.parse(process.env.FAKE_ZIPS_BY_ARTIFACT)[download[1]]; - if (!archive) throw new Error("missing fake artifact ZIP " + download[1]); - const state = process.env.FAKE_DOWNLOAD_STATE; - const count = fs.existsSync(state) ? Number(fs.readFileSync(state, "utf8")) : 0; - fs.writeFileSync(state, String(count + 1)); - if (process.env.FAKE_DOWNLOAD_MODE === "transient" && count === 0) { - process.stderr.write("HTTP 503 unexpected EOF\\n"); - process.exit(1); - } - const bytes = fs.readFileSync(archive); - if (process.env.FAKE_DOWNLOAD_MODE === "identity-mismatch") { - const altered = Buffer.from(bytes); - altered[Math.min(10, altered.length - 1)] ^= 0x01; - process.stdout.write(altered); - } else { - process.stdout.write(process.env.FAKE_DOWNLOAD_MODE === "truncated" ? bytes.subarray(0, 3) : bytes); - } - process.exit(0); -} -throw new Error("unexpected gh api endpoint " + endpoint); -`, - ); - chmodSync(file, 0o755); - return directory; -} - -async function fixture(t, label) { - const root = mkdtempSync(path.join(os.tmpdir(), `oliphaunt-ledger-download-${label}-`)); - t.after(() => rmSync(root, { force: true, recursive: true })); - const bin = fakeGh(root); - const output = path.join(root, "github-output"); - writeFileSync(output, ""); - return { - bin, - destination: path.join(root, "destination"), - downloadState: path.join(root, "download-state"), - log: path.join(root, "gh.log"), - output, - root, - }; -} - -function invoke(fixture, { - artifactsByRun = {}, - attempt = 1, - attemptMetadata = {}, - currentRunMetadata = { - id: 900, - workflow_id: 42, - head_sha: SHA, - event: "workflow_dispatch", - created_at: "2026-07-15T10:00:00Z", - status: "in_progress", - }, - zipsByArtifact = {}, - downloadMode = "success", -} = {}) { - return spawnSync("node", [SCRIPT], { - encoding: "utf8", - timeout: BOOTSTRAP_LEDGER_PROCESS_TIMEOUT_MS, - env: isolatedGitHubTestEnvironment({ - PATH: `${fixture.bin}${path.delimiter}${process.env.PATH}`, - BOOTSTRAP_LEDGER_PATH: fixture.destination, - FAKE_ARTIFACTS_BY_RUN: JSON.stringify(artifactsByRun), - FAKE_ATTEMPT_METADATA: JSON.stringify(attemptMetadata), - FAKE_CURRENT_RUN: JSON.stringify(currentRunMetadata), - FAKE_DOWNLOAD_MODE: downloadMode, - FAKE_DOWNLOAD_STATE: fixture.downloadState, - FAKE_GH_LOG: fixture.log, - FAKE_ZIPS_BY_ARTIFACT: JSON.stringify(zipsByArtifact), - GH_REPO: "f0rr0/oliphaunt", - GH_TOKEN: "test-token", - GITHUB_OUTPUT: fixture.output, - GITHUB_REPOSITORY: "f0rr0/oliphaunt", - GITHUB_RUN_ATTEMPT: String(attempt), - GITHUB_RUN_ID: "900", - GITHUB_SHA: SHA, - RELEASE_HEAD_SHA: "b".repeat(40), // Frozen source differs from the publishing workflow SHA. - - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "0", - OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: "0", - }), - }); -} - -function calls(fixture) { - return readFileSync(fixture.log, "utf8") - .trim() - .split(/\r?\n/u) - .filter(Boolean) - .map((line) => JSON.parse(line)); -} - -function downloadedArtifactIds(fixture) { - return calls(fixture) - .map((args) => /\/artifacts\/([0-9]+)\/zip$/u.exec(args.at(-1))?.[1]) - .filter(Boolean); -} - -function restoredNames(fixture) { - return readdirSync(fixture.destination).sort(); -} - -test("rerun restores an earlier-attempt artifact by immutable artifact id and excludes current-attempt bytes", async (t) => { - const f = await fixture(t, "earlier-attempt"); - const priorZip = ledgerZip(f.root, "prior-attempt", 0, "a"); - const currentZip = ledgerZip(f.root, "current-attempt", 1, "b"); - const result = invoke(f, { - attempt: 2, - attemptMetadata: { - id: 900, - run_attempt: 2, - run_started_at: "2026-07-15T10:00:00Z", - head_sha: SHA, - event: "workflow_dispatch", - }, - artifactsByRun: { - 900: [ - artifact(202, 900, "2026-07-15T10:00:01Z"), - artifact(101, 900, "2026-07-15T09:50:00Z", "2026-07-15T09:51:00Z"), - ], - }, - zipsByArtifact: { 101: priorZip, 202: currentZip }, - }); - assert.equal(result.status, 0, result.stderr); - assert.deepEqual(downloadedArtifactIds(f), ["101"]); - assert.deepEqual(restoredNames(f), [checkpointName(0, "a")]); - assert.match(readFileSync(f.output, "utf8"), /^found=true\nrun_id=900\n$/u); - assert.equal(calls(f).some((args) => args[0] === "run" && args[1] === "list"), false); -}); - -test("the current run artifact must retain its exact-SHA binding", async (t) => { - const f = await fixture(t, "sha-disagreement"); - const result = invoke(f, { - artifactsByRun: { - 900: [artifact(5_000, 900, "2026-07-14T10:05:00Z", undefined, { - workflow_run: { id: 900, head_sha: "b".repeat(40) }, - })], - }, - }); - assert.equal(result.status, 1); - assert.match(result.stderr, /artifact disagrees with its exact-SHA binding/u); - assert.equal(readFileSync(f.output, "utf8"), ""); -}); - -test("rerun refuses genesis when only an artifact from the current attempt is visible", async (t) => { - const f = await fixture(t, "refuse-current"); - const currentZip = ledgerZip(f.root, "current-only", 6, "f"); - const result = invoke(f, { - attempt: 2, - attemptMetadata: { - id: 900, - run_attempt: 2, - run_started_at: "2026-07-15T12:00:00Z", - head_sha: SHA, - event: "workflow_dispatch", - }, - artifactsByRun: { 900: [artifact(202, 900, "2026-07-15T12:00:00Z")] }, - zipsByArtifact: { 202: currentZip }, - }); - assert.equal(result.status, 1); - assert.match(result.stderr, /no artifact can be proven to predate the attempt.*refusing genesis/u); - assert.deepEqual(downloadedArtifactIds(f), []); - assert.equal(readFileSync(f.output, "utf8"), ""); -}); - -test("attempt boundary uses both creation and update time and metadata validation fails closed", () => { - const selected = selectEarlierAttemptArtifact( - [ - artifact(101, 900, "2026-07-15T09:00:00Z", "2026-07-15T09:30:00Z"), - artifact(102, 900, "2026-07-15T09:10:00Z", "2026-07-15T10:00:00Z"), - artifact(103, 900, "2026-07-15T09:20:00Z", "2026-07-15T09:40:00Z"), - ], - { runId: "900", currentAttemptStartedAt: "2026-07-15T10:00:00Z" }, - ); - assert.equal(selected.artifact.id, 103); - assert.deepEqual(selected.excludedCurrentAttemptIds, ["102"]); - assert.throws( - () => selectEarlierAttemptArtifact( - [artifact(104, 900, "not-a-timestamp")], - { runId: "900", currentAttemptStartedAt: "2026-07-15T10:00:00Z" }, - ), - /created_at must be a UTC timestamp/u, - ); - assert.throws( - () => validateAttemptMetadata( - { - id: 900, - run_attempt: 2, - run_started_at: "2026-07-15T10:00:00Z", - head_sha: "b".repeat(40), - event: "workflow_dispatch", - }, - { runId: "900", attempt: 2, sha: SHA }, - ), - /wrong release SHA/u, - ); -}); - -test("artifact transport retries transient failure and restores only a complete checkpoint envelope", async (t) => { - const f = await fixture(t, "transient-download"); - const archive = ledgerZip(f.root, "transient", 7, "a"); - const result = invoke(f, { - attempt: 2, - attemptMetadata: { id: 900, run_attempt: 2, run_started_at: "2026-07-15T10:00:00Z", head_sha: SHA, event: "workflow_dispatch" }, - artifactsByRun: { 900: [artifact(707, 900, "2026-07-14T10:05:00Z")] }, - downloadMode: "transient", - zipsByArtifact: { 707: archive }, - }); - assert.equal(result.status, 0, result.stderr); - assert.equal(readFileSync(f.downloadState, "utf8"), "2"); - assert.deepEqual(restoredNames(f), [checkpointName(7, "a")]); - assert.equal(readdirSync(f.root).some((name) => name.startsWith(".destination.")), false); -}); - -test("repeated truncated ZIP responses preserve the durable checkpoint cache and clean all stages", async (t) => { - const f = await fixture(t, "truncated-download"); - mkdirSync(f.destination, { recursive: true }); - const existing = checkpointName(8, "b"); - writeFileSync(path.join(f.destination, existing), "durable\n"); - const archive = ledgerZip(f.root, "truncated", 9, "c"); - const result = invoke(f, { - attempt: 2, - attemptMetadata: { id: 900, run_attempt: 2, run_started_at: "2026-07-15T10:00:00Z", head_sha: SHA, event: "workflow_dispatch" }, - artifactsByRun: { 900: [artifact(808, 900, "2026-07-14T10:05:00Z")] }, - downloadMode: "truncated", - zipsByArtifact: { 808: archive }, - }); - assert.equal(result.status, 1); - assert.match(result.stderr, /retry budget exhausted/u); - assert.equal(readFileSync(f.downloadState, "utf8"), "4"); - assert.deepEqual(restoredNames(f), [existing]); - assert.equal(readFileSync(path.join(f.destination, existing), "utf8"), "durable\n"); - assert.equal(readdirSync(f.root).some((name) => name.startsWith(".destination.")), false); -}); - -test("a valid-looking ZIP with the wrong immutable digest is never restored", async (t) => { - const f = await fixture(t, "identity-mismatch"); - mkdirSync(f.destination, { recursive: true }); - const existing = checkpointName(11, "e"); - writeFileSync(path.join(f.destination, existing), "durable\n"); - const archive = ledgerZip(f.root, "identity-mismatch", 12, "f"); - const result = invoke(f, { - attempt: 2, - attemptMetadata: { id: 900, run_attempt: 2, run_started_at: "2026-07-15T10:00:00Z", head_sha: SHA, event: "workflow_dispatch" }, - artifactsByRun: { 900: [artifact(1001, 900, "2026-07-14T10:05:00Z")] }, - downloadMode: "identity-mismatch", - zipsByArtifact: { 1001: archive }, - }); - assert.equal(result.status, 1); - assert.match(result.stderr, /transport identity mismatch.*retry budget exhausted|retry budget exhausted.*transport identity mismatch/su); - assert.equal(readFileSync(f.downloadState, "utf8"), "4"); - assert.deepEqual(restoredNames(f), [existing]); - assert.equal(readdirSync(f.root).some((name) => name.startsWith(".destination.")), false); -}); - -test("checkpoint collision is validated before atomic promotion and preserves prior bytes", async (t) => { - const f = await fixture(t, "collision"); - mkdirSync(f.destination, { recursive: true }); - const name = checkpointName(10, "d"); - writeFileSync(path.join(f.destination, name), "local-different-bytes\n"); - const archive = ledgerZip(f.root, "collision", 10, "d"); - const result = invoke(f, { - attempt: 2, - attemptMetadata: { id: 900, run_attempt: 2, run_started_at: "2026-07-15T10:00:00Z", head_sha: SHA, event: "workflow_dispatch" }, - artifactsByRun: { 900: [artifact(909, 900, "2026-07-14T10:05:00Z")] }, - zipsByArtifact: { 909: archive }, - }); - assert.equal(result.status, 1); - assert.match(result.stderr, /prior checkpoint conflicts/u); - assert.equal(readFileSync(path.join(f.destination, name), "utf8"), "local-different-bytes\n"); - assert.equal(existsSync(path.join(f.destination, ".artifact.zip")), false); - assert.equal(readdirSync(f.root).some((entry) => entry.startsWith(".destination.")), false); -}); diff --git a/.github/scripts/download-build-artifacts.mjs b/.github/scripts/download-build-artifacts.mjs deleted file mode 100644 index 9f5abb2f1..000000000 --- a/.github/scripts/download-build-artifacts.mjs +++ /dev/null @@ -1,810 +0,0 @@ -#!/usr/bin/env node -import { spawnSync } from "node:child_process"; -import { createHash } from "node:crypto"; -import { - chmodSync, - closeSync, - copyFileSync, - createReadStream, - existsSync, - lstatSync, - mkdirSync, - openSync, - readFileSync, - readdirSync, - renameSync, - rmSync, - statSync, - utimesSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import process from "node:process"; - -import { - createSiblingStage, - promoteDirectory, - removeTemporaryPath, - stageExistingDirectory, -} from "../../tools/release/atomic-directory.mjs"; -import { - RetryableReadError, - isRetryableGitHubReadError, - retryReadOperationSync, - runGitHubPaginatedJsonSync, - runGitHubReadSync, -} from "../../tools/release/github-read.mjs"; -import { reserveGitHubCoreRequestSync } from "../../tools/release/github-core-request-journal.mjs"; -import { captureCommandOutput } from "../../tools/dev/capture-command-output.mjs"; - -const USAGE = - "usage: download-build-artifacts.mjs [--run-id ] [--job ] " - + "[--artifact-metadata-json ] --artifact [--artifact ...]"; -const SNAPSHOT_SCHEMA = "oliphaunt-github-actions-run-snapshot-v1"; -const FULL_SHA = /^[0-9a-f]{40}$/u; -const MAX_CAPTURE_BYTES = 128 * 1024 * 1024; -const ARTIFACT_DOWNLOAD_TOTAL_DEADLINE_MS = 65 * 60_000; -const ARTIFACT_DOWNLOAD_ATTEMPT_TIMEOUT_MS = 40 * 60_000; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function fail(message, code = 1) { - console.error(message); - process.exit(code); -} - -function parseArgs(argv) { - if (argv.length < 3) { - fail(USAGE, 2); - } - const [workflow, sha, destination, ...rest] = argv; - const args = { - workflow, - sha, - destination, - artifacts: [], - requiredJob: "", - selectedRunId: "", - artifactMetadataJson: "", - }; - for (let index = 0; index < rest.length; ) { - const arg = rest[index]; - if (arg === "--run-id") { - args.selectedRunId = valueAfter(rest, index, "--run-id requires a run id"); - index += 2; - } else if (arg === "--job") { - args.requiredJob = valueAfter(rest, index, "--job requires a name"); - index += 2; - } else if (arg === "--artifact") { - args.artifacts.push(valueAfter(rest, index, "--artifact requires a name")); - index += 2; - } else if (arg === "--artifact-metadata-json") { - args.artifactMetadataJson = valueAfter(rest, index, "--artifact-metadata-json requires JSON"); - index += 2; - } else { - fail(`unknown argument: ${arg}`, 2); - } - } - if (args.artifacts.length === 0) { - fail("at least one --artifact is required", 2); - } - if (new Set(args.artifacts).size !== args.artifacts.length) { - fail("each --artifact identity must be requested exactly once", 2); - } - args.expectedArtifactMetadata = parseExpectedArtifactMetadata(args.artifactMetadataJson, args.artifacts); - if (args.expectedArtifactMetadata !== null && args.selectedRunId === "") { - fail("--artifact-metadata-json requires --run-id so immutable artifact IDs cannot drift between runs", 2); - } - return args; -} - -function parseExpectedArtifactMetadata(raw, requested) { - if (raw === "") return null; - let rows; - try { - rows = JSON.parse(raw); - } catch (cause) { - fail(`--artifact-metadata-json must be strict JSON: ${cause.message}`, 2); - } - if (!Array.isArray(rows) || rows.length < requested.length) { - fail("--artifact-metadata-json must contain every requested artifact", 2); - } - const expectedNames = [...requested].sort(); - const normalized = rows.map((row) => { - if ( - row === null - || Array.isArray(row) - || typeof row !== "object" - || JSON.stringify(Object.keys(row).sort()) !== JSON.stringify(["digest", "id", "name", "size"]) - || typeof row.name !== "string" - || !Number.isSafeInteger(row.id) - || row.id < 1 - || !Number.isSafeInteger(row.size) - || row.size < 1 - || typeof row.digest !== "string" - || !/^sha256:[0-9a-f]{64}$/u.test(row.digest) - ) { - fail("--artifact-metadata-json contains a malformed immutable artifact identity", 2); - } - return { digest: row.digest, id: row.id, name: row.name, size: row.size }; - }).sort((left, right) => compareText(left.name, right.name)); - if (new Set(normalized.map(({ name }) => name)).size !== normalized.length) { - fail("--artifact-metadata-json must contain unique artifact names", 2); - } - const all = new Map(normalized.map((row) => [row.name, row])); - if (expectedNames.some((name) => !all.has(name))) { - fail("--artifact-metadata-json is missing a requested artifact name", 2); - } - // A gate can authorize a larger immutable artifact set than one consumer - // needs. Keep every row schema-validated while returning only the explicitly - // requested subset; this avoids re-downloading a large capsule merely to - // install its companion lock. - return new Map(expectedNames.map((name) => [name, all.get(name)])); -} - -function valueAfter(argv, index, message) { - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) { - fail(message, 2); - } - return value; -} - -function requireEnv(name) { - const value = process.env[name]; - if (value === undefined || value === "") { - fail(`${name} is required`); - } - return value; -} - -function gh(args, label, options = {}) { - return runGitHubReadSync(args, { label, ...options }); -} - -function parsedJson(text, label) { - try { - return JSON.parse(text); - } catch (error) { - throw new Error(`${label} returned invalid JSON: ${error.message}`); - } -} - -function safeRunId(value) { - const rendered = String(value ?? ""); - if (!/^[1-9][0-9]*$/u.test(rendered)) throw new Error("workflow run id must be a positive integer"); - return rendered; -} - -function snapshotFile(runId) { - const directory = process.env.OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR?.trim() ?? ""; - if (directory === "") return null; - return path.join(path.resolve(directory), `run-${safeRunId(runId)}.json`); -} - -function assertRegularSnapshotFile(file) { - const metadata = lstatSync(file, { throwIfNoEntry: false }); - if (metadata !== undefined && (!metadata.isFile() || metadata.isSymbolicLink())) { - throw new Error(`GitHub run snapshot must be an absent or regular non-symlink file: ${file}`); - } -} - -function normalizeArtifact(entry, runId) { - if ( - entry === null - || Array.isArray(entry) - || typeof entry !== "object" - || typeof entry.name !== "string" - || entry.name.length === 0 - || !Number.isSafeInteger(entry.id) - || entry.id <= 0 - || !Number.isSafeInteger(entry.size_in_bytes) - || entry.size_in_bytes < 0 - || typeof entry.expired !== "boolean" - || typeof entry.digest !== "string" - || !/^sha256:[0-9a-f]{64}$/u.test(entry.digest) - ) { - throw new Error(`artifact inventory for run ${runId} contains malformed immutable metadata`); - } - if (entry.workflow_run?.id !== undefined && String(entry.workflow_run.id) !== String(runId)) { - throw new Error(`artifact ${entry.id} is not bound to workflow run ${runId}`); - } - return { - digest: entry.digest, - expired: entry.expired, - id: entry.id, - name: entry.name, - size_in_bytes: entry.size_in_bytes, - }; -} - -function artifactRecords(repo, runId, options = {}) { - const records = runGitHubPaginatedJsonSync( - `repos/${repo}/actions/runs/${runId}/artifacts`, - { - ...options, - itemsField: "artifacts", - label: `artifact inventory for run ${runId}`, - }, - ); - return records.map((entry) => normalizeArtifact(entry, runId)); -} - -function exactArtifact(records, runId, name) { - const matches = records.filter((entry) => entry.name === name && entry.expired === false); - if (matches.length !== 1) { - throw new Error( - `${runId} must contain exactly one non-expired artifact named ${name}; found ${matches.length}`, - ); - } - return matches[0]; -} - -function exactExpectedArtifact(records, runId, name, expectedMetadata = null) { - const observed = exactArtifact(records, runId, name); - const expected = expectedMetadata?.get(name); - if ( - expected !== undefined - && ( - observed.id !== expected.id - || observed.digest !== expected.digest - || observed.size_in_bytes !== expected.size - ) - ) { - throw new Error( - `${runId}/${name} immutable identity drifted: expected id=${expected.id} size=${expected.size} digest=${expected.digest}; ` - + `observed id=${observed.id} size=${observed.size_in_bytes} digest=${observed.digest}`, - ); - } - return observed; -} - -function jobRecords(repo, runId) { - const records = runGitHubPaginatedJsonSync( - `repos/${repo}/actions/runs/${runId}/jobs?filter=latest`, - { - itemsField: "jobs", - label: `jobs for run ${runId}`, - }, - ); - const jobs = []; - for (const job of records) { - if ( - job === null - || Array.isArray(job) - || typeof job !== "object" - || !Number.isSafeInteger(job.id) - || job.id <= 0 - || typeof job.name !== "string" - || job.name.length === 0 - || typeof job.status !== "string" - || (job.conclusion !== null && typeof job.conclusion !== "string") - || !Number.isSafeInteger(job.run_attempt) - || job.run_attempt <= 0 - ) { - throw new Error(`job inventory for run ${runId} contains malformed metadata`); - } - jobs.push({ - conclusion: job.conclusion, - id: job.id, - name: job.name, - run_attempt: job.run_attempt, - status: job.status, - }); - } - return jobs; -} - -function validateSnapshot(snapshot) { - if ( - snapshot === null - || Array.isArray(snapshot) - || typeof snapshot !== "object" - || snapshot.schema !== SNAPSHOT_SCHEMA - || !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(snapshot.repo) - || !/^[1-9][0-9]*$/u.test(snapshot.runId) - || !FULL_SHA.test(snapshot.headSha) - || !Number.isSafeInteger(snapshot.workflowId) - || snapshot.workflowId <= 0 - || typeof snapshot.workflowName !== "string" - || snapshot.workflowName.length === 0 - || snapshot.status !== "completed" - || snapshot.conclusion !== "success" - || !Number.isSafeInteger(snapshot.runAttempt) - || snapshot.runAttempt <= 0 - || !Array.isArray(snapshot.jobs) - || !Array.isArray(snapshot.artifacts) - ) { - throw new Error("cached GitHub workflow run snapshot is malformed or not completed/success"); - } - const artifacts = snapshot.artifacts.map((entry) => normalizeArtifact(entry, snapshot.runId)); - const artifactIds = new Set(); - for (const artifact of artifacts) { - if (artifactIds.has(artifact.id)) throw new Error("cached GitHub workflow run snapshot repeats an artifact id"); - artifactIds.add(artifact.id); - } - for (const job of snapshot.jobs) { - if ( - job === null - || Array.isArray(job) - || typeof job !== "object" - || !Number.isSafeInteger(job.id) - || job.id <= 0 - || typeof job.name !== "string" - || typeof job.status !== "string" - || (job.conclusion !== null && typeof job.conclusion !== "string") - || job.run_attempt !== snapshot.runAttempt - ) { - throw new Error("cached GitHub workflow run snapshot contains malformed or cross-attempt jobs"); - } - } - return { ...snapshot, artifacts }; -} - -function createRunSnapshot(repo, runId) { - const data = parsedJson( - gh(["api", `repos/${repo}/actions/runs/${runId}`], `metadata for run ${runId}`), - `metadata for run ${runId}`, - ); - if ( - String(data?.id ?? "") !== String(runId) - || !FULL_SHA.test(data?.head_sha ?? "") - || !Number.isSafeInteger(data?.workflow_id) - || data.workflow_id <= 0 - || data.status !== "completed" - || data.conclusion !== "success" - || !Number.isSafeInteger(data.run_attempt) - || data.run_attempt <= 0 - ) { - throw new Error(`workflow run ${runId} is malformed or not completed/success`); - } - const workflow = parsedJson( - gh(["api", `repos/${repo}/actions/workflows/${data.workflow_id}`], `workflow ${data.workflow_id} metadata`), - `workflow ${data.workflow_id} metadata`, - ); - if (workflow?.id !== data.workflow_id || typeof workflow?.name !== "string" || workflow.name.length === 0) { - throw new Error(`workflow ${data.workflow_id} metadata is malformed`); - } - return validateSnapshot({ - artifacts: artifactRecords(repo, runId), - conclusion: data.conclusion, - headSha: data.head_sha.toLowerCase(), - jobs: jobRecords(repo, runId), - repo, - runAttempt: data.run_attempt, - runId: String(runId), - schema: SNAPSHOT_SCHEMA, - status: data.status, - workflowId: data.workflow_id, - workflowName: workflow.name, - }); -} - -function runSnapshot(repo, runId) { - const file = snapshotFile(runId); - if (file !== null && existsSync(file)) { - assertRegularSnapshotFile(file); - const snapshot = validateSnapshot(parsedJson(readFileSync(file, "utf8"), `cached run ${runId} snapshot`)); - if (snapshot.repo !== repo || snapshot.runId !== String(runId)) { - throw new Error(`cached run ${runId} snapshot belongs to a different repository or run`); - } - return snapshot; - } - const snapshot = createRunSnapshot(repo, runId); - if (file !== null) { - mkdirSync(path.dirname(file), { recursive: true }); - assertRegularSnapshotFile(file); - const temporary = `${file}.tmp-${process.pid}`; - assertRegularSnapshotFile(temporary); - try { - writeFileSync(temporary, `${JSON.stringify(snapshot)}\n`, { flag: "wx", mode: 0o600 }); - renameSync(temporary, file); - } finally { - rmSync(temporary, { force: true }); - } - } - return snapshot; -} - -function requiredJobSuccess(snapshot, requiredJob) { - if (requiredJob === "") { - return true; - } - const matches = snapshot.jobs.filter((candidate) => candidate.name === requiredJob); - return matches.length === 1 && matches[0]?.conclusion === "success"; -} - -function runMatchesRequest(snapshot, workflow, sha) { - return snapshot.headSha === sha.toLowerCase() && snapshot.workflowName === workflow; -} - -function candidateRunIds(repo, workflow, sha) { - const workflows = runGitHubPaginatedJsonSync( - `repos/${repo}/actions/workflows`, - { - itemsField: "workflows", - label: `${workflow} workflow identity inventory`, - maxBuffer: MAX_CAPTURE_BYTES, - }, - ); - const matches = workflows.filter((row) => row?.name === workflow); - if (matches.length !== 1 || !Number.isSafeInteger(matches[0]?.id) || matches[0].id < 1) { - throw new Error(`expected exactly one workflow named ${workflow}; found ${matches.length}`); - } - const runs = runGitHubPaginatedJsonSync( - `repos/${repo}/actions/workflows/${matches[0].id}/runs?head_sha=${encodeURIComponent(sha)}`, - { - itemsField: "workflow_runs", - label: `exact-SHA workflow runs for ${workflow} at ${sha}`, - maxBuffer: MAX_CAPTURE_BYTES, - }, - ); - const ids = new Set(); - const result = []; - for (const run of runs) { - const id = safeRunId(run?.id); - if ( - ids.has(id) - || run.head_sha !== sha - || run.workflow_id !== matches[0].id - || typeof run.status !== "string" - || ![null, "success", "failure", "cancelled", "timed_out", "action_required", "neutral", "skipped", "stale", "startup_failure"].includes(run.conclusion) - ) { - throw new Error(`workflow run inventory for ${workflow} at ${sha} contains malformed, duplicate, or inexact metadata`); - } - ids.add(id); - if (run.status === "completed" && run.conclusion === "success") result.push(id); - } - return result; -} - -function sortedFiles(root) { - const files = []; - function visit(directory) { - const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => - compareText(left.name, right.name), - ); - for (const entry of entries) { - const entryPath = path.join(directory, entry.name); - const entryStat = lstatSync(entryPath); - if (entryStat.isSymbolicLink()) { - throw new Error(`downloaded artifact contains symbolic link ${path.relative(root, entryPath)}`); - } - if (entryStat.isDirectory()) { - visit(entryPath); - } else if (entryStat.isFile()) { - files.push(entryPath); - } else { - throw new Error(`downloaded artifact contains special file ${path.relative(root, entryPath)}`); - } - } - } - visit(root); - return files; -} - -function fileSha256(file) { - return new Promise((resolve, reject) => { - const hash = createHash("sha256"); - const stream = createReadStream(file); - stream.on("error", reject); - stream.on("data", (chunk) => hash.update(chunk)); - stream.on("end", () => resolve(hash.digest("hex"))); - }); -} - -async function filesEqual(left, right) { - const leftStat = statSync(left); - const rightStat = statSync(right); - return leftStat.size === rightStat.size && (await fileSha256(left)) === (await fileSha256(right)); -} - -function copyPreserve(source, target) { - const sourceStat = statSync(source); - copyFileSync(source, target); - chmodSync(target, sourceStat.mode); - utimesSync(target, sourceStat.atime, sourceStat.mtime); -} - -function mergeChecksumManifest(existing, incoming) { - const result = spawnSync(process.execPath, [".github/scripts/merge-checksum-manifest.mjs", existing, incoming], { - stdio: "inherit", - env: process.env, - }); - return !result.error && result.status === 0; -} - -function validateDownloadedArtifact(artifact, directory) { - const files = sortedFiles(directory); - if (files.length === 0) { - throw new RetryableReadError(`artifact ${artifact} downloaded with an empty file envelope`); - } - for (const file of files) { - const relative = path.relative(directory, file); - if (relative.startsWith("..") || path.isAbsolute(relative)) { - throw new Error(`artifact ${artifact} escaped its download directory`); - } - const stat = lstatSync(file); - if (!stat.isFile() || stat.isSymbolicLink()) { - throw new Error(`artifact ${artifact} contains unsupported entry ${relative}`); - } - } -} - -function validateZipMembers(archive, artifact) { - const result = captureCommandOutput("unzip", ["-Z1", archive], { - env: process.env, - label: `list artifact ${artifact} ZIP`, - maxOutputBytes: MAX_CAPTURE_BYTES, - stdoutTerminator: "\n", - }); - if (result.error !== undefined || result.status !== 0) { - throw new RetryableReadError(`artifact ${artifact} is not a readable ZIP archive`, { - cause: result.error ?? new Error(result.stderr.trim()), - }); - } - const members = result.stdout.split(/\r?\n/u).filter(Boolean); - if (members.length === 0) throw new RetryableReadError(`artifact ${artifact} ZIP archive is empty`); - const seen = new Set(); - for (const member of members) { - const normalized = member.endsWith("/") ? member.slice(0, -1) : member; - if ( - normalized === "" - || member.includes("\\") - || member.startsWith("/") - || normalized.split("/").some((segment) => segment === "" || segment === "." || segment === "..") - || /[\u0000-\u001f\u007f]/u.test(member) - || seen.has(member) - ) { - throw new Error(`artifact ${artifact} ZIP contains unsafe or duplicate member ${JSON.stringify(member)}`); - } - seen.add(member); - } - const typeCheck = captureCommandOutput("python3", ["-c", ` -import stat -import sys -import zipfile - -with zipfile.ZipFile(sys.argv[1], "r") as archive: - for entry in archive.infolist(): - mode = (entry.external_attr >> 16) & 0xFFFF - kind = stat.S_IFMT(mode) - if entry.flag_bits & 0x1: - raise SystemExit("encrypted ZIP member") - if kind not in (0, stat.S_IFREG, stat.S_IFDIR): - raise SystemExit("symbolic-link or special ZIP member") -`, archive], { - env: process.env, - label: `inspect artifact ${artifact} ZIP entry types`, - maxOutputBytes: 1024 * 1024, - }); - if (typeCheck.error !== undefined || typeCheck.status !== 0) { - throw new Error( - `artifact ${artifact} ZIP contains an encrypted, symbolic-link, or special member: ` - + (typeCheck.error?.message ?? typeCheck.stderr.trim()), - ); - } -} - -function extractZip(archive, directory, artifact) { - validateZipMembers(archive, artifact); - const result = captureCommandOutput("unzip", ["-q", archive, "-d", directory], { - env: process.env, - label: `extract artifact ${artifact} ZIP`, - maxOutputBytes: MAX_CAPTURE_BYTES, - }); - if (result.error !== undefined || result.status !== 0) { - throw new RetryableReadError(`artifact ${artifact} ZIP extraction failed`, { - cause: result.error ?? new Error(result.stderr.trim()), - }); - } -} - -function downloadArchiveOnce(repo, identity, archive, attemptTimeoutMs) { - let descriptor; - try { - descriptor = openSync(archive, "wx", 0o600); - reserveGitHubCoreRequestSync({ - label: `download Actions artifact ${identity.id}`, - }); - const result = captureCommandOutput( - "gh", - [ - "api", - "-H", - "Accept: application/vnd.github+json", - "-H", - "X-GitHub-Api-Version: 2022-11-28", - `repos/${repo}/actions/artifacts/${identity.id}/zip`, - ], - { - env: process.env, - label: `download Actions artifact ${identity.id}`, - maxOutputBytes: 4 * 1024 * 1024, - stdoutDescriptor: descriptor, - timeout: attemptTimeoutMs, - windowsHide: true, - }, - ); - closeSync(descriptor); - descriptor = undefined; - if (result.error !== undefined || result.status !== 0) { - const error = new Error(`exact-ID artifact download failed: ${result.stderr?.trim() ?? ""}`); - error.code = result.error?.code; - error.status = result.status; - error.retryable = isRetryableGitHubReadError(error); - throw error; - } - } catch (error) { - if (descriptor !== undefined) closeSync(descriptor); - rmSync(archive, { force: true }); - throw error; - } -} - -async function downloadArtifact(repo, runId, artifact, expectedIdentity, destination, sharedDeadlineMs) { - let lastError; - for (let attempt = 1; attempt <= 2; attempt += 1) { - const remainingMs = sharedDeadlineMs - Date.now(); - if (remainingMs <= 0) { - throw new RetryableReadError( - `shared exact-artifact download deadline exhausted after ${attempt - 1} attempt(s)`, - { cause: lastError }, - ); - } - const temporary = createSiblingStage(destination, `download-${artifact.replace(/[^A-Za-z0-9_.-]/gu, "-")}`); - const archive = path.join(temporary, ".artifact.zip"); - try { - downloadArchiveOnce( - repo, - expectedIdentity, - archive, - Math.max(1, Math.min(ARTIFACT_DOWNLOAD_ATTEMPT_TIMEOUT_MS, remainingMs)), - ); - const actualSize = statSync(archive).size; - let actualDigest; - try { - actualDigest = await fileSha256(archive); - } catch (cause) { - throw new RetryableReadError(`could not hash artifact ${artifact} ZIP`, { cause }); - } - const expectedDigest = expectedIdentity.digest.slice("sha256:".length); - if (actualSize !== expectedIdentity.size_in_bytes || actualDigest !== expectedDigest) { - throw new RetryableReadError( - `artifact ${artifact} ZIP identity mismatch: expected ${expectedIdentity.size_in_bytes}/${expectedDigest}, ` - + `got ${actualSize}/${actualDigest}`, - ); - } - extractZip(archive, temporary, artifact); - rmSync(archive, { force: true }); - validateDownloadedArtifact(artifact, temporary); - return temporary; - } catch (error) { - removeTemporaryPath(temporary); - lastError = error; - if (!isRetryableGitHubReadError(error)) { - throw new Error(`permanent read failure for exact-ID artifact ${artifact}: ${error.message}`, { cause: error }); - } - if (attempt === 2) { - throw new RetryableReadError( - `exact-ID artifact download retry budget exhausted after ${attempt} attempts: ${error.message}`, - { cause: error }, - ); - } - } - } - throw lastError; -} - -async function mergeDownloadedArtifact(artifact, sourceDir, destination) { - for (const source of sortedFiles(sourceDir)) { - const relativePath = path.relative(sourceDir, source); - const target = path.join(destination, relativePath); - mkdirSync(path.dirname(target), { recursive: true }); - if (existsSync(target)) { - if (statSync(target).isFile() && (await filesEqual(source, target))) { - continue; - } - if ( - statSync(target).isFile() && - statSync(source).isFile() && - path.basename(target).endsWith("-release-assets.sha256") - ) { - if (!mergeChecksumManifest(target, source)) { - return false; - } - continue; - } - console.error(`artifact ${artifact} would overwrite ${relativePath} with different bytes`); - return false; - } - copyPreserve(source, target); - } - return true; -} - -function selectRunId(repo, args) { - if (args.selectedRunId !== "") { - const runId = args.selectedRunId; - const snapshot = runSnapshot(repo, runId); - if (!runMatchesRequest(snapshot, args.workflow, args.sha)) { - fail(`${args.workflow} run ${runId} does not belong to commit ${args.sha}`); - } - if (!requiredJobSuccess(snapshot, args.requiredJob)) { - fail(`${args.workflow} run ${runId} does not satisfy required job ${args.requiredJob || ""}`); - } - for (const artifact of args.artifacts) { - exactExpectedArtifact(snapshot.artifacts, runId, artifact, args.expectedArtifactMetadata); - } - return snapshot; - } - - for (const candidate of candidateRunIds(repo, args.workflow, args.sha)) { - const snapshot = runSnapshot(repo, candidate); - if (!runMatchesRequest(snapshot, args.workflow, args.sha)) { - continue; - } - if (!requiredJobSuccess(snapshot, args.requiredJob)) { - continue; - } - try { - for (const artifact of args.artifacts) exactExpectedArtifact(snapshot.artifacts, candidate, artifact); - return snapshot; - } catch { - // A successfully read inventory that lacks the exact envelope is not a matching candidate. - } - } - fail( - `no ${args.workflow} workflow run found for ${args.sha} with required job/artifacts: ${args.requiredJob || ""} / ${args.artifacts.join(" ")}`, - ); -} - -async function main() { - const args = parseArgs(process.argv.slice(2)); - requireEnv("GH_TOKEN"); - const repo = requireEnv("GH_REPO"); - const snapshot = selectRunId(repo, args); - const runId = snapshot.runId; - const identities = new Map(); - for (const artifact of args.artifacts) { - identities.set( - artifact, - exactExpectedArtifact(snapshot.artifacts, runId, artifact, args.expectedArtifactMetadata), - ); - } - const sharedDownloadDeadlineMs = Date.now() + ARTIFACT_DOWNLOAD_TOTAL_DEADLINE_MS; - - const stage = stageExistingDirectory(args.destination, "merge"); - try { - for (const artifact of args.artifacts) { - console.log(`Downloading ${args.workflow} artifact ${artifact} from run ${runId}`); - const artifactDir = await downloadArtifact( - repo, - runId, - artifact, - identities.get(artifact), - args.destination, - sharedDownloadDeadlineMs, - ); - try { - if (!(await mergeDownloadedArtifact(artifact, artifactDir, stage))) { - throw new Error(`artifact ${artifact} conflicts with the durable destination`); - } - } finally { - removeTemporaryPath(artifactDir); - } - } - promoteDirectory(stage, args.destination); - } catch (error) { - removeTemporaryPath(stage); - throw error; - } -} - -try { - await main(); -} catch (error) { - fail(error instanceof Error ? error.message : String(error)); -} diff --git a/.github/scripts/download-build-artifacts.mts b/.github/scripts/download-build-artifacts.mts new file mode 100644 index 000000000..6f1905c5c --- /dev/null +++ b/.github/scripts/download-build-artifacts.mts @@ -0,0 +1,807 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + createReadStream, + createWriteStream, + existsSync, + lstatSync, + mkdirSync, + readdirSync, + readFileSync, + renameSync, + rmSync, + statSync, + utimesSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { Readable, Transform } from 'node:stream'; +import { pipeline } from 'node:stream/promises'; +import { fileURLToPath } from 'node:url'; +import { + createSiblingStage, + promoteDirectory, + releaseTemporaryPath, + removeTemporaryPath, + stageExistingDirectory, +} from '../../tools/packaging/atomic-directory.mts'; +import { validateZipEntryTypes } from '../../tools/packaging/portable-archive.mts'; +import { + isRetryableGitHubReadError, + RetryableReadError, + requestGithubDownload, + requestGithubJsonWithRetry, + requestGithubPages, +} from '../../tools/release/github-read.mts'; +import { mergeChecksumManifest } from './merge-checksum-manifest.mts'; + +const USAGE = + 'usage: download-build-artifacts.sh [--run-id ] [--job ] ' + + '[--artifact-metadata-json ] --artifact [--artifact ...]'; +const SNAPSHOT_SCHEMA = 'oliphaunt-github-actions-run-snapshot-v1'; +const FULL_SHA = /^[0-9a-f]{40}$/u; +const MAX_CAPTURE_BYTES = 128 * 1024 * 1024; +const ARTIFACT_DOWNLOAD_TOTAL_DEADLINE_MS = 65 * 60_000; +const ARTIFACT_DOWNLOAD_ATTEMPT_TIMEOUT_MS = 40 * 60_000; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function fail(message, code = 1) { + throw Object.assign(new Error(message), { exitCode: code }); +} + +function parseArgs(argv) { + if (argv.length < 3) { + fail(USAGE, 2); + } + const [workflow, sha, destination, ...rest] = argv; + const args = { + workflow, + sha, + destination, + artifacts: [], + requiredJob: '', + selectedRunId: '', + artifactMetadataJson: '', + }; + for (let index = 0; index < rest.length; ) { + const arg = rest[index]; + if (arg === '--run-id') { + args.selectedRunId = valueAfter(rest, index, '--run-id requires a run id'); + index += 2; + } else if (arg === '--job') { + args.requiredJob = valueAfter(rest, index, '--job requires a name'); + index += 2; + } else if (arg === '--artifact') { + args.artifacts.push(valueAfter(rest, index, '--artifact requires a name')); + index += 2; + } else if (arg === '--artifact-metadata-json') { + args.artifactMetadataJson = valueAfter(rest, index, '--artifact-metadata-json requires JSON'); + index += 2; + } else { + fail(`unknown argument: ${arg}`, 2); + } + } + if (args.artifacts.length === 0) { + fail('at least one --artifact is required', 2); + } + if (new Set(args.artifacts).size !== args.artifacts.length) { + fail('each --artifact identity must be requested exactly once', 2); + } + args.expectedArtifactMetadata = parseExpectedArtifactMetadata( + args.artifactMetadataJson, + args.artifacts, + ); + if (args.expectedArtifactMetadata !== null && args.selectedRunId === '') { + fail( + '--artifact-metadata-json requires --run-id so immutable artifact IDs cannot drift between runs', + 2, + ); + } + return args; +} + +function parseExpectedArtifactMetadata(raw, requested) { + if (raw === '') return null; + let rows; + try { + rows = JSON.parse(raw); + } catch (cause) { + fail(`--artifact-metadata-json must be strict JSON: ${cause.message}`, 2); + } + if (!Array.isArray(rows) || rows.length < requested.length) { + fail('--artifact-metadata-json must contain every requested artifact', 2); + } + const expectedNames = [...requested].sort(); + const normalized = rows + .map((row) => { + if ( + row === null || + Array.isArray(row) || + typeof row !== 'object' || + JSON.stringify(Object.keys(row).sort()) !== + JSON.stringify(['digest', 'id', 'name', 'size']) || + typeof row.name !== 'string' || + !Number.isSafeInteger(row.id) || + row.id < 1 || + !Number.isSafeInteger(row.size) || + row.size < 1 || + typeof row.digest !== 'string' || + !/^sha256:[0-9a-f]{64}$/u.test(row.digest) + ) { + fail('--artifact-metadata-json contains a malformed immutable artifact identity', 2); + } + return { digest: row.digest, id: row.id, name: row.name, size: row.size }; + }) + .sort((left, right) => compareText(left.name, right.name)); + if (new Set(normalized.map(({ name }) => name)).size !== normalized.length) { + fail('--artifact-metadata-json must contain unique artifact names', 2); + } + const all = new Map(normalized.map((row) => [row.name, row])); + if (expectedNames.some((name) => !all.has(name))) { + fail('--artifact-metadata-json is missing a requested artifact name', 2); + } + // A gate can authorize a larger immutable artifact set than one consumer + // needs. Keep every row schema-validated while returning only the explicitly + // requested subset; this avoids re-downloading a large capsule merely to + // install its companion lock. + return new Map(expectedNames.map((name) => [name, all.get(name)])); +} + +function valueAfter(argv, index, message) { + const value = argv[index + 1]; + if (value === undefined || value.startsWith('--')) { + fail(message, 2); + } + return value; +} + +function requireEnv(name) { + const value = process.env[name]; + if (value === undefined || value === '') { + fail(`${name} is required`); + } + return value; +} + +function parsedJson(text, label) { + try { + return JSON.parse(text); + } catch (error) { + throw new Error(`${label} returned invalid JSON: ${error.message}`); + } +} + +function safeRunId(value) { + const rendered = String(value ?? ''); + if (!/^[1-9][0-9]*$/u.test(rendered)) + throw new Error('workflow run id must be a positive integer'); + return rendered; +} + +function snapshotFile(runId) { + const directory = process.env.OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR?.trim() ?? ''; + if (directory === '') return null; + return path.join(path.resolve(directory), `run-${safeRunId(runId)}.json`); +} + +function assertRegularSnapshotFile(file) { + const metadata = lstatSync(file, { throwIfNoEntry: false }); + if (metadata !== undefined && (!metadata.isFile() || metadata.isSymbolicLink())) { + throw new Error(`GitHub run snapshot must be an absent or regular non-symlink file: ${file}`); + } +} + +function normalizeArtifact(entry, runId) { + if ( + entry === null || + Array.isArray(entry) || + typeof entry !== 'object' || + typeof entry.name !== 'string' || + entry.name.length === 0 || + !Number.isSafeInteger(entry.id) || + entry.id <= 0 || + !Number.isSafeInteger(entry.size_in_bytes) || + entry.size_in_bytes < 0 || + typeof entry.expired !== 'boolean' || + typeof entry.digest !== 'string' || + !/^sha256:[0-9a-f]{64}$/u.test(entry.digest) + ) { + throw new Error(`artifact inventory for run ${runId} contains malformed immutable metadata`); + } + if (entry.workflow_run?.id !== undefined && String(entry.workflow_run.id) !== String(runId)) { + throw new Error(`artifact ${entry.id} is not bound to workflow run ${runId}`); + } + return { + digest: entry.digest, + expired: entry.expired, + id: entry.id, + name: entry.name, + size_in_bytes: entry.size_in_bytes, + }; +} + +async function artifactRecords(repo, runId, options = {}) { + const records = await requestGithubPages(`repos/${repo}/actions/runs/${runId}/artifacts`, { + ...options, + itemsField: 'artifacts', + label: `artifact inventory for run ${runId}`, + }); + return records.map((entry) => normalizeArtifact(entry, runId)); +} + +function exactArtifact(records, runId, name) { + const matches = records.filter((entry) => entry.name === name && entry.expired === false); + if (matches.length !== 1) { + throw new Error( + `${runId} must contain exactly one non-expired artifact named ${name}; found ${matches.length}`, + ); + } + return matches[0]; +} + +function exactExpectedArtifact(records, runId, name, expectedMetadata = null) { + const observed = exactArtifact(records, runId, name); + const expected = expectedMetadata?.get(name); + if ( + expected !== undefined && + (observed.id !== expected.id || + observed.digest !== expected.digest || + observed.size_in_bytes !== expected.size) + ) { + throw new Error( + `${runId}/${name} immutable identity drifted: expected id=${expected.id} size=${expected.size} digest=${expected.digest}; ` + + `observed id=${observed.id} size=${observed.size_in_bytes} digest=${observed.digest}`, + ); + } + return observed; +} + +async function jobRecords(repo, runId) { + const records = await requestGithubPages( + `repos/${repo}/actions/runs/${runId}/jobs?filter=latest`, + { + itemsField: 'jobs', + label: `jobs for run ${runId}`, + }, + ); + const jobs = []; + for (const job of records) { + if ( + job === null || + Array.isArray(job) || + typeof job !== 'object' || + !Number.isSafeInteger(job.id) || + job.id <= 0 || + typeof job.name !== 'string' || + job.name.length === 0 || + typeof job.status !== 'string' || + (job.conclusion !== null && typeof job.conclusion !== 'string') || + !Number.isSafeInteger(job.run_attempt) || + job.run_attempt <= 0 + ) { + throw new Error(`job inventory for run ${runId} contains malformed metadata`); + } + jobs.push({ + conclusion: job.conclusion, + id: job.id, + name: job.name, + run_attempt: job.run_attempt, + status: job.status, + }); + } + return jobs; +} + +function validateSnapshot(snapshot) { + if ( + snapshot === null || + Array.isArray(snapshot) || + typeof snapshot !== 'object' || + snapshot.schema !== SNAPSHOT_SCHEMA || + !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(snapshot.repo) || + !/^[1-9][0-9]*$/u.test(snapshot.runId) || + !FULL_SHA.test(snapshot.headSha) || + !Number.isSafeInteger(snapshot.workflowId) || + snapshot.workflowId <= 0 || + typeof snapshot.workflowName !== 'string' || + snapshot.workflowName.length === 0 || + snapshot.status !== 'completed' || + snapshot.conclusion !== 'success' || + !Number.isSafeInteger(snapshot.runAttempt) || + snapshot.runAttempt <= 0 || + !Array.isArray(snapshot.jobs) || + !Array.isArray(snapshot.artifacts) + ) { + throw new Error('cached GitHub workflow run snapshot is malformed or not completed/success'); + } + const artifacts = snapshot.artifacts.map((entry) => normalizeArtifact(entry, snapshot.runId)); + const artifactIds = new Set(); + for (const artifact of artifacts) { + if (artifactIds.has(artifact.id)) + throw new Error('cached GitHub workflow run snapshot repeats an artifact id'); + artifactIds.add(artifact.id); + } + for (const job of snapshot.jobs) { + if ( + job === null || + Array.isArray(job) || + typeof job !== 'object' || + !Number.isSafeInteger(job.id) || + job.id <= 0 || + typeof job.name !== 'string' || + typeof job.status !== 'string' || + (job.conclusion !== null && typeof job.conclusion !== 'string') || + job.run_attempt !== snapshot.runAttempt + ) { + throw new Error( + 'cached GitHub workflow run snapshot contains malformed or cross-attempt jobs', + ); + } + } + return { ...snapshot, artifacts }; +} + +async function createRunSnapshot(repo, runId) { + const data = await requestGithubJsonWithRetry( + `https://api.github.com/repos/${repo}/actions/runs/${runId}`, + ); + if ( + String(data?.id ?? '') !== String(runId) || + !FULL_SHA.test(data?.head_sha ?? '') || + !Number.isSafeInteger(data?.workflow_id) || + data.workflow_id <= 0 || + data.status !== 'completed' || + data.conclusion !== 'success' || + !Number.isSafeInteger(data.run_attempt) || + data.run_attempt <= 0 + ) { + throw new Error(`workflow run ${runId} is malformed or not completed/success`); + } + const workflow = await requestGithubJsonWithRetry( + `https://api.github.com/repos/${repo}/actions/workflows/${data.workflow_id}`, + ); + if ( + workflow?.id !== data.workflow_id || + typeof workflow?.name !== 'string' || + workflow.name.length === 0 + ) { + throw new Error(`workflow ${data.workflow_id} metadata is malformed`); + } + return validateSnapshot({ + artifacts: await artifactRecords(repo, runId), + conclusion: data.conclusion, + headSha: data.head_sha.toLowerCase(), + jobs: await jobRecords(repo, runId), + repo, + runAttempt: data.run_attempt, + runId: String(runId), + schema: SNAPSHOT_SCHEMA, + status: data.status, + workflowId: data.workflow_id, + workflowName: workflow.name, + }); +} + +async function runSnapshot(repo, runId) { + const file = snapshotFile(runId); + if (file !== null && existsSync(file)) { + assertRegularSnapshotFile(file); + const snapshot = validateSnapshot( + parsedJson(readFileSync(file, 'utf8'), `cached run ${runId} snapshot`), + ); + if (snapshot.repo !== repo || snapshot.runId !== String(runId)) { + throw new Error(`cached run ${runId} snapshot belongs to a different repository or run`); + } + return snapshot; + } + const snapshot = await createRunSnapshot(repo, runId); + if (file !== null) { + mkdirSync(path.dirname(file), { recursive: true }); + assertRegularSnapshotFile(file); + const temporary = `${file}.tmp-${process.pid}`; + assertRegularSnapshotFile(temporary); + try { + writeFileSync(temporary, `${JSON.stringify(snapshot)}\n`, { flag: 'wx', mode: 0o600 }); + renameSync(temporary, file); + } finally { + rmSync(temporary, { force: true }); + } + } + return snapshot; +} + +function requiredJobSuccess(snapshot, requiredJob) { + if (requiredJob === '') { + return true; + } + const matches = snapshot.jobs.filter((candidate) => candidate.name === requiredJob); + return matches.length === 1 && matches[0]?.conclusion === 'success'; +} + +function runMatchesRequest(snapshot, workflow, sha) { + return snapshot.headSha === sha.toLowerCase() && snapshot.workflowName === workflow; +} + +async function candidateRunIds(repo, workflow, sha) { + const workflows = await requestGithubPages(`repos/${repo}/actions/workflows`, { + itemsField: 'workflows', + label: `${workflow} workflow identity inventory`, + maxBuffer: MAX_CAPTURE_BYTES, + }); + const matches = workflows.filter((row) => row?.name === workflow); + if (matches.length !== 1 || !Number.isSafeInteger(matches[0]?.id) || matches[0].id < 1) { + throw new Error(`expected exactly one workflow named ${workflow}; found ${matches.length}`); + } + const runs = await requestGithubPages( + `repos/${repo}/actions/workflows/${matches[0].id}/runs?head_sha=${encodeURIComponent(sha)}`, + { + itemsField: 'workflow_runs', + label: `exact-SHA workflow runs for ${workflow} at ${sha}`, + maxBuffer: MAX_CAPTURE_BYTES, + }, + ); + const ids = new Set(); + const result = []; + for (const run of runs) { + const id = safeRunId(run?.id); + if ( + ids.has(id) || + run.head_sha !== sha || + run.workflow_id !== matches[0].id || + typeof run.status !== 'string' || + ![ + null, + 'success', + 'failure', + 'cancelled', + 'timed_out', + 'action_required', + 'neutral', + 'skipped', + 'stale', + 'startup_failure', + ].includes(run.conclusion) + ) { + throw new Error( + `workflow run inventory for ${workflow} at ${sha} contains malformed, duplicate, or inexact metadata`, + ); + } + ids.add(id); + if (run.status === 'completed' && run.conclusion === 'success') result.push(id); + } + return result; +} + +function sortedFiles(root) { + const files = []; + function visit(directory) { + const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => + compareText(left.name, right.name), + ); + for (const entry of entries) { + const entryPath = path.join(directory, entry.name); + const entryStat = lstatSync(entryPath); + if (entryStat.isSymbolicLink()) { + throw new Error( + `downloaded artifact contains symbolic link ${path.relative(root, entryPath)}`, + ); + } + if (entryStat.isDirectory()) { + visit(entryPath); + } else if (entryStat.isFile()) { + files.push(entryPath); + } else { + throw new Error( + `downloaded artifact contains special file ${path.relative(root, entryPath)}`, + ); + } + } + } + visit(root); + return files; +} + +function fileSha256(file) { + return new Promise((resolve, reject) => { + const hash = createHash('sha256'); + const stream = createReadStream(file); + stream.on('error', reject); + stream.on('data', (chunk) => hash.update(chunk)); + stream.on('end', () => resolve(hash.digest('hex'))); + }); +} + +async function filesEqual(left, right) { + const leftStat = statSync(left); + const rightStat = statSync(right); + return leftStat.size === rightStat.size && (await fileSha256(left)) === (await fileSha256(right)); +} + +function copyPreserve(source, target) { + const sourceStat = statSync(source); + copyFileSync(source, target); + chmodSync(target, sourceStat.mode); + utimesSync(target, sourceStat.atime, sourceStat.mtime); +} + +function validateDownloadedArtifact(artifact, directory) { + const files = sortedFiles(directory); + if (files.length === 0) { + throw new RetryableReadError(`artifact ${artifact} downloaded with an empty file envelope`); + } + for (const file of files) { + const relative = path.relative(directory, file); + if (relative.startsWith('..') || path.isAbsolute(relative)) { + throw new Error(`artifact ${artifact} escaped its download directory`); + } + const stat = lstatSync(file); + if (!stat.isFile() || stat.isSymbolicLink()) { + throw new Error(`artifact ${artifact} contains unsupported entry ${relative}`); + } + } +} + +function validateZipMembers(archive, listingFile) { + const artifact = path.basename(archive); + if (statSync(listingFile).size > MAX_CAPTURE_BYTES) + fail('ZIP member inventory exceeds its byte limit'); + const listing = new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(listingFile)); + if (!listing.endsWith('\n')) fail('ZIP inventory is missing its terminal newline'); + const members = listing.split(/\r?\n/u).filter(Boolean); + if (members.length === 0) + throw new RetryableReadError(`artifact ${artifact} ZIP archive is empty`); + const seen = new Set(); + for (const member of members) { + const normalized = member.endsWith('/') ? member.slice(0, -1) : member; + if ( + normalized === '' || + member.includes('\\') || + member.startsWith('/') || + normalized + .split('/') + .some((segment) => segment === '' || segment === '.' || segment === '..') || + /[\u0000-\u001f\u007f]/u.test(member) || + seen.has(member) + ) { + throw new Error( + `artifact ${artifact} ZIP contains unsafe or duplicate member ${JSON.stringify(member)}`, + ); + } + seen.add(member); + } + validateZipEntryTypes(archive); +} + +async function downloadArchiveOnce(repo, identity, archive, attemptTimeoutMs) { + try { + const response = await requestGithubDownload( + `https://api.github.com/repos/${repo}/actions/artifacts/${identity.id}/zip`, + { timeoutMs: attemptTimeoutMs }, + ); + let size = 0; + await pipeline( + Readable.fromWeb(response.body), + new Transform({ + transform(chunk, _encoding, callback) { + size += chunk.length; + callback( + size > identity.size_in_bytes + ? new RetryableReadError('artifact exceeds its approved byte size') + : null, + chunk, + ); + }, + }), + createWriteStream(archive, { flags: 'wx', mode: 0o600 }), + ); + } catch (error) { + rmSync(archive, { force: true }); + throw error; + } +} + +async function downloadArtifact(repo, artifact, expectedIdentity, destination, sharedDeadlineMs) { + let lastError; + for (let attempt = 1; attempt <= 2; attempt += 1) { + const remainingMs = sharedDeadlineMs - Date.now(); + if (remainingMs <= 0) { + throw new RetryableReadError( + `shared exact-artifact download deadline exhausted after ${attempt - 1} attempt(s)`, + { cause: lastError }, + ); + } + const temporary = createSiblingStage( + destination, + `download-${artifact.replace(/[^A-Za-z0-9_.-]/gu, '-')}`, + ); + const archive = path.join(temporary, '.artifact.zip'); + try { + await downloadArchiveOnce( + repo, + expectedIdentity, + archive, + Math.max(1, Math.min(ARTIFACT_DOWNLOAD_ATTEMPT_TIMEOUT_MS, remainingMs)), + ); + const actualSize = statSync(archive).size; + let actualDigest; + try { + actualDigest = await fileSha256(archive); + } catch (cause) { + throw new RetryableReadError(`could not hash artifact ${artifact} ZIP`, { cause }); + } + const expectedDigest = expectedIdentity.digest.slice('sha256:'.length); + if (actualSize !== expectedIdentity.size_in_bytes || actualDigest !== expectedDigest) { + throw new RetryableReadError( + `artifact ${artifact} ZIP identity mismatch: expected ${expectedIdentity.size_in_bytes}/${expectedDigest}, ` + + `got ${actualSize}/${actualDigest}`, + ); + } + return temporary; + } catch (error) { + removeTemporaryPath(temporary); + lastError = error; + if (!isRetryableGitHubReadError(error)) { + throw new Error( + `permanent read failure for exact-ID artifact ${artifact}: ${error.message}`, + { cause: error }, + ); + } + if (attempt === 2) { + throw new RetryableReadError( + `exact-ID artifact download retry budget exhausted after ${attempt} attempts: ${error.message}`, + { cause: error }, + ); + } + } + } + throw lastError; +} + +async function mergeDownloadedArtifact(artifact, sourceDir, destination) { + for (const source of sortedFiles(sourceDir)) { + const relativePath = path.relative(sourceDir, source); + const target = path.join(destination, relativePath); + mkdirSync(path.dirname(target), { recursive: true }); + if (existsSync(target)) { + if (statSync(target).isFile() && (await filesEqual(source, target))) { + continue; + } + if ( + statSync(target).isFile() && + statSync(source).isFile() && + path.basename(target).endsWith('-release-assets.sha256') + ) { + try { + await mergeChecksumManifest(target, source); + } catch (error) { + console.error(error.message); + return false; + } + continue; + } + console.error(`artifact ${artifact} would overwrite ${relativePath} with different bytes`); + return false; + } + copyPreserve(source, target); + } + return true; +} + +async function selectRunId(repo, args) { + if (args.selectedRunId !== '') { + const runId = args.selectedRunId; + const snapshot = await runSnapshot(repo, runId); + if (!runMatchesRequest(snapshot, args.workflow, args.sha)) { + fail(`${args.workflow} run ${runId} does not belong to commit ${args.sha}`); + } + if (!requiredJobSuccess(snapshot, args.requiredJob)) { + fail( + `${args.workflow} run ${runId} does not satisfy required job ${args.requiredJob || ''}`, + ); + } + for (const artifact of args.artifacts) { + exactExpectedArtifact(snapshot.artifacts, runId, artifact, args.expectedArtifactMetadata); + } + return snapshot; + } + + for (const candidate of await candidateRunIds(repo, args.workflow, args.sha)) { + const snapshot = await runSnapshot(repo, candidate); + if (!runMatchesRequest(snapshot, args.workflow, args.sha)) { + continue; + } + if (!requiredJobSuccess(snapshot, args.requiredJob)) { + continue; + } + try { + for (const artifact of args.artifacts) + exactExpectedArtifact(snapshot.artifacts, candidate, artifact); + return snapshot; + } catch { + // A successfully read inventory that lacks the exact envelope is not a matching candidate. + } + } + fail( + `no ${args.workflow} workflow run found for ${args.sha} with required job/artifacts: ${args.requiredJob || ''} / ${args.artifacts.join(' ')}`, + ); +} + +async function downloadArchives(argv, scratch) { + let repo; + const args = parseArgs(argv); + requireEnv('GH_TOKEN'); + repo ??= requireEnv('GH_REPO'); + if (!/^[A-Za-z0-9][A-Za-z0-9_.-]*\/[A-Za-z0-9][A-Za-z0-9_.-]*$/u.test(repo)) + fail('GH_REPO must be owner/repository'); + const snapshot = await selectRunId(repo, args); + const runId = snapshot.runId; + const identities = new Map(); + for (const artifact of args.artifacts) { + identities.set( + artifact, + exactExpectedArtifact(snapshot.artifacts, runId, artifact, args.expectedArtifactMetadata), + ); + } + const sharedDownloadDeadlineMs = Date.now() + ARTIFACT_DOWNLOAD_TOTAL_DEADLINE_MS; + + const downloads = []; + for (const [index, artifact] of args.artifacts.entries()) { + console.log(`Downloading ${args.workflow} artifact ${artifact} from run ${runId}`); + const directory = await downloadArtifact( + repo, + artifact, + identities.get(artifact), + path.join(scratch, String(index)), + sharedDownloadDeadlineMs, + ); + downloads.push({ artifact, directory }); + } + writeFileSync( + path.join(scratch, 'plan.json'), + JSON.stringify({ destination: path.resolve(args.destination), downloads }), + { flag: 'wx', mode: 0o600 }, + ); + writeFileSync( + path.join(scratch, 'archives'), + downloads.map(({ directory }) => directory + '\0').join(''), + { flag: 'wx', mode: 0o600 }, + ); + // The enclosing Shell owns scratch cleanup across the extraction phases. + for (const { directory } of downloads) releaseTemporaryPath(directory); +} + +async function mergeArchives(scratch) { + const { destination, downloads } = JSON.parse( + readFileSync(path.join(scratch, 'plan.json'), 'utf8'), + ); + const stage = stageExistingDirectory(destination, 'merge'); + try { + for (const { artifact, directory } of downloads) { + validateDownloadedArtifact(artifact, directory); + if (!(await mergeDownloadedArtifact(artifact, directory, stage))) + throw new Error(`artifact ${artifact} conflicts with the durable destination`); + } + promoteDirectory(stage, destination); + } finally { + removeTemporaryPath(stage); + } +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + try { + const [phase, scratch, ...args] = process.argv.slice(2); + if (phase === 'download') await downloadArchives(args, scratch); + else if (phase === 'validate-zip' && args.length === 1) validateZipMembers(scratch, args[0]); + else if (phase === 'merge' && args.length === 0) await mergeArchives(scratch); + else fail(USAGE, 2); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = error.exitCode ?? 1; + } +} diff --git a/.github/scripts/download-build-artifacts.sh b/.github/scripts/download-build-artifacts.sh new file mode 100644 index 000000000..875b0e998 --- /dev/null +++ b/.github/scripts/download-build-artifacts.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-artifact-download.XXXXXXXX")" +trap 'rm -rf "$scratch"' EXIT +trap 'exit 130' INT +trap 'exit 143' TERM +script=.github/scripts/download-build-artifacts.mts +bun "$script" download "$scratch" "$@" +while IFS= read -r -d '' directory; do + archive="$directory/.artifact.zip" + unzip -Z1 "$archive" > "$scratch/members" + bun "$script" validate-zip "$archive" "$scratch/members" + unzip -q "$archive" -d "$directory" + rm "$archive" +done < "$scratch/archives" +bun "$script" merge "$scratch" diff --git a/.github/scripts/download-completed-bootstrap.mjs b/.github/scripts/download-completed-bootstrap.mjs deleted file mode 100644 index d4a5c14c3..000000000 --- a/.github/scripts/download-completed-bootstrap.mjs +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env bun -import { readdirSync, readFileSync } from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { captureCommandOutput } from "../../tools/dev/capture-command-output.mjs"; -import { loadPublicationLock } from "../../tools/release/publication-lock.mjs"; -import { loadBootstrapLedger } from "../../tools/release/bootstrap-ledger.mjs"; -import { assertPublicationChanges } from "../../tools/release/publication-controller.mjs"; -import { runGitHubPaginatedJsonSync } from "../../tools/release/github-read.mjs"; -import { createSiblingStage, promoteDirectory, removeTemporaryPath } from "../../tools/release/atomic-directory.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const ARTIFACT = "oliphaunt-bootstrap-ledger"; - -export function isCompletedMainRelease(run, repo) { - return Number.isSafeInteger(run?.id) && run.id > 0 - && run.status === "completed" && run.conclusion === "success" - && run.event === "workflow_dispatch" && run.head_branch === "main" - && run.path === ".github/workflows/release.yml" - && run.repository?.full_name === repo && run.head_repository?.full_name === repo - && /^[0-9a-f]{40}$/u.test(run.head_sha ?? ""); -} - -export function matchesBootstrapLock(directory, lock) { - const files = readdirSync(directory).sort(); - if (files.length === 0 || files.some((file) => !/^checkpoint-[0-9]{6}-[0-9a-f]{64}[.]json$/u.test(file))) { - throw new Error("completed bootstrap artifact must contain only checkpoint files"); - } - const first = JSON.parse(readFileSync(path.join(directory, files[0]), "utf8")); - // Discovery only. Matching evidence still undergoes full chain/envelope validation. - return first.lockDigest === lock.lockDigest; -} - -export function restoreCompletedBootstrap({ repo, lock, destination }, { - list = runGitHubPaginatedJsonSync, - download = (run, artifact, stage) => { - const result = captureCommandOutput(process.execPath, [ - path.join(ROOT, ".github/scripts/download-build-artifacts.mjs"), - "Release", run.head_sha, stage, "--run-id", String(run.id), - "--job", "Bootstrap registry identities", "--artifact", ARTIFACT, - "--artifact-metadata-json", JSON.stringify([{ - id: artifact.id, name: artifact.name, digest: artifact.digest, size: artifact.size_in_bytes, - }]), - ], { cwd: ROOT, label: `download completed bootstrap ${run.id}` }); - if (result.error || result.status !== 0) throw new Error(result.stderr || "completed bootstrap download failed"); - }, - assertSource = (run) => assertPublicationChanges({ source: lock.source.commit, controller: run.head_sha }), -} = {}) { - if (repo !== "f0rr0/oliphaunt") throw new Error("completed bootstrap must come from the canonical repository"); - const runs = list(`repos/${repo}/actions/workflows/release.yml/runs?event=workflow_dispatch&status=success&branch=main`, { - itemsField: "workflow_runs", label: "completed main Release runs", - }).filter((run) => isCompletedMainRelease(run, repo)).sort((a, b) => b.id - a.id); - for (const run of runs) { - const artifacts = list(`repos/${repo}/actions/runs/${run.id}/artifacts`, { - itemsField: "artifacts", label: `completed bootstrap artifacts ${run.id}`, - }).filter((artifact) => artifact.name === ARTIFACT && artifact.expired === false); - if (artifacts.length === 0) continue; - if (artifacts.length !== 1) throw new Error(`run ${run.id} repeats the completed bootstrap artifact`); - const stage = createSiblingStage(destination); - try { - download(run, artifacts[0], stage); - if (!matchesBootstrapLock(stage, lock)) continue; - assertSource(run); - loadBootstrapLedger(stage, lock, lock.products.map(({ id }) => id), { requireComplete: true }); - promoteDirectory(stage, destination); - return run.id; - } finally { removeTemporaryPath(stage); } - } - throw new Error(`no completed main bootstrap matches approved lock ${lock.lockDigest}; existing bootstrap must not be restarted`); -} - -if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { - try { - const lock = loadPublicationLock(process.env.PUBLICATION_LOCK_PATH || "target/release/publication-lock.json"); - const destination = path.resolve(process.env.BOOTSTRAP_LEDGER_PATH || "target/release/bootstrap-ledger"); - const runId = restoreCompletedBootstrap({ repo: process.env.GH_REPO, lock, destination }); - console.log(`verified completed bootstrap run ${runId} for approved lock ${lock.lockDigest}`); - } catch (error) { console.error(error.message); process.exitCode = 1; } -} diff --git a/.github/scripts/download-completed-bootstrap.mts b/.github/scripts/download-completed-bootstrap.mts new file mode 100644 index 000000000..ed82bd082 --- /dev/null +++ b/.github/scripts/download-completed-bootstrap.mts @@ -0,0 +1,153 @@ +#!/usr/bin/env bun +import { mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { promoteDirectory, removeTemporaryPath } from '../../tools/packaging/atomic-directory.mts'; +import { loadBootstrapLedger } from '../../tools/release/bootstrap-ledger.mts'; +import { requestGithubPages } from '../../tools/release/github-read.mts'; +import { assertPublicationChanges } from '../../tools/release/publication-controller.mts'; +import { loadPublicationLock } from '../../tools/release/publication-lock.mts'; +import { downloadBootstrapArtifact } from './download-bootstrap-ledger.mts'; + +const ARTIFACT = 'oliphaunt-bootstrap-ledger'; + +export function isCompletedMainRelease(run, repo) { + return ( + Number.isSafeInteger(run?.id) && + run.id > 0 && + run.status === 'completed' && + run.conclusion === 'success' && + run.event === 'workflow_dispatch' && + run.head_branch === 'main' && + run.path === '.github/workflows/release.yml' && + run.repository?.full_name === repo && + run.head_repository?.full_name === repo && + /^[0-9a-f]{40}$/u.test(run.head_sha ?? '') + ); +} + +export function matchesBootstrapLock(directory, lock) { + const files = readdirSync(directory).sort(); + if ( + files.length === 0 || + files.some((file) => !/^checkpoint-[0-9]{6}-[0-9a-f]{64}[.]json$/u.test(file)) + ) { + throw new Error('completed bootstrap artifact must contain only checkpoint files'); + } + const first = JSON.parse(readFileSync(path.join(directory, files[0]), 'utf8')); + // Discovery only. Matching evidence still undergoes full chain/envelope validation. + return first.lockDigest === lock.lockDigest; +} + +export async function discoverCompletedBootstrap( + { repo, lock, stage }, + { + list = requestGithubPages, + download = async (run, artifact, stage) => { + const jobs = await requestGithubPages( + `repos/${repo}/actions/runs/${run.id}/jobs?filter=latest`, + { itemsField: 'jobs' }, + ); + const gates = jobs.filter((job) => job.name === 'Bootstrap registry identities'); + if (gates.length !== 1 || gates[0].conclusion !== 'success') + throw new Error( + `completed bootstrap run ${run.id} requires exactly one successful bootstrap job`, + ); + const downloaded = await downloadBootstrapArtifact(repo, artifact, stage); + try { + promoteDirectory(downloaded, stage); + } finally { + removeTemporaryPath(downloaded); + } + }, + } = {}, +) { + if (repo !== 'f0rr0/oliphaunt') + throw new Error('completed bootstrap must come from the canonical repository'); + const runs = ( + await list( + `repos/${repo}/actions/workflows/release.yml/runs?event=workflow_dispatch&status=success&branch=main`, + { + itemsField: 'workflow_runs', + label: 'completed main Release runs', + }, + ) + ) + .filter((run) => isCompletedMainRelease(run, repo)) + .sort((a, b) => b.id - a.id); + for (const run of runs) { + const artifacts = ( + await list(`repos/${repo}/actions/runs/${run.id}/artifacts`, { + itemsField: 'artifacts', + label: `completed bootstrap artifacts ${run.id}`, + }) + ).filter((artifact) => artifact.name === ARTIFACT && artifact.expired === false); + if (artifacts.length === 0) continue; + if (artifacts.length !== 1) + throw new Error(`run ${run.id} repeats the completed bootstrap artifact`); + if (artifacts[0].workflow_run?.id !== undefined && artifacts[0].workflow_run.id !== run.id) + throw new Error(`bootstrap artifact does not belong to run ${run.id}`); + mkdirSync(stage, { recursive: true }); + let selected = false; + try { + await download(run, artifacts[0], stage); + if (!matchesBootstrapLock(stage, lock)) continue; + selected = true; + return run; + } finally { + if (!selected) removeTemporaryPath(stage); + } + } + throw new Error( + `no completed main bootstrap matches approved lock ${lock.lockDigest}; existing bootstrap must not be restarted`, + ); +} + +export function installCompletedBootstrap({ + run, + stage, + lock, + destination, + environment = process.env, +}) { + assertPublicationChanges({ source: lock.source.commit, controller: run.head_sha, environment }); + loadBootstrapLedger( + stage, + lock, + lock.products.map(({ id }) => id), + { requireComplete: true }, + ); + promoteDirectory(stage, destination); + return run.id; +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + try { + const [command, directory] = process.argv.slice(2); + if (!['discover', 'install'].includes(command) || !directory) + throw new Error('use download-completed-bootstrap.sh'); + const lock = loadPublicationLock( + process.env.PUBLICATION_LOCK_PATH || 'target/release/publication-lock.json', + ); + const destination = path.resolve( + process.env.BOOTSTRAP_LEDGER_PATH || 'target/release/bootstrap-ledger', + ); + const stage = path.join(directory, 'ledger'); + const context = path.join(directory, 'run.json'); + if (command === 'discover') { + const run = await discoverCompletedBootstrap({ repo: process.env.GH_REPO, lock, stage }); + writeFileSync(context, JSON.stringify({ run, lockDigest: lock.lockDigest })); + console.log(lock.source.commit); + console.log(run.head_sha); + } else { + const { run, lockDigest } = JSON.parse(readFileSync(context, 'utf8')); + if (lockDigest !== lock.lockDigest) + throw new Error('completed bootstrap lock changed after discovery'); + const runId = installCompletedBootstrap({ run, stage, lock, destination }); + console.log(`verified completed bootstrap run ${runId} for approved lock ${lock.lockDigest}`); + } + } catch (error) { + console.error(error.message); + process.exitCode = 1; + } +} diff --git a/.github/scripts/download-completed-bootstrap.sh b/.github/scripts/download-completed-bootstrap.sh new file mode 100644 index 000000000..777424ef5 --- /dev/null +++ b/.github/scripts/download-completed-bootstrap.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +destination="${BOOTSTRAP_LEDGER_PATH:-target/release/bootstrap-ledger}" +mkdir -p "$(dirname "$destination")" +scratch="$(mktemp -d "${destination}.restore.XXXXXX")" +trap 'rm -rf "$scratch"' EXIT +bash tools/dev/bun.sh .github/scripts/download-completed-bootstrap.mts discover "$scratch" > "$scratch/source" +{ IFS= read -r source_sha; IFS= read -r controller_sha; } < "$scratch/source" +bash tools/release/publication-controller.sh --changes-only "$source_sha" "$controller_sha" \ + bash tools/dev/bun.sh .github/scripts/download-completed-bootstrap.mts install "$scratch" diff --git a/.github/scripts/download-wasix-runtime-build-artifacts.mjs b/.github/scripts/download-wasix-runtime-build-artifacts.mjs deleted file mode 100644 index e9360d2cd..000000000 --- a/.github/scripts/download-wasix-runtime-build-artifacts.mjs +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "node:child_process"; -import process from "node:process"; - -function fail(message, code = 1) { - console.error(message); - process.exit(code); -} - -function requireEnv(name) { - const value = process.env[name]; - if (value === undefined || value === "") { - fail(`${name} is required`); - } - return value; -} - -function run(command, args) { - const result = spawnSync(command, args, { - stdio: "inherit", - env: process.env, - }); - if (result.error) { - fail(result.error.message); - } - process.exit(result.status ?? 1); -} - -requireEnv("GITHUB_TOKEN"); -const releaseSha = - process.env.RELEASE_ARTIFACT_SHA - ?? process.env.RELEASE_HEAD_SHA - ?? process.env.GITHUB_SHA - ?? ""; -if (releaseSha === "") { - fail("RELEASE_ARTIFACT_SHA, RELEASE_HEAD_SHA, or GITHUB_SHA is required", 2); -} - -// Installs the portable and AOT WASIX runtime outputs from the selected release -// CI workflow whose artifact builder gate passed. This is a release artifact -// handoff, not a release-time runtime rebuild. -const args = ["run", "-p", "xtask", "--", "assets", "download"]; -if (process.env.CI_RUN_ID) { - args.push("--run-id", process.env.CI_RUN_ID); -} else { - args.push("--sha", releaseSha); -} -args.push("--required-job", "Builds", "--all-targets"); - -run("cargo", args); diff --git a/.github/scripts/download-wasix-runtime-build-artifacts.sh b/.github/scripts/download-wasix-runtime-build-artifacts.sh new file mode 100755 index 000000000..087f02a72 --- /dev/null +++ b/.github/scripts/download-wasix-runtime-build-artifacts.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +sha="${RELEASE_ARTIFACT_SHA:-${RELEASE_HEAD_SHA:-${GITHUB_SHA:-}}}" +: "${sha:?RELEASE_ARTIFACT_SHA, RELEASE_HEAD_SHA, or GITHUB_SHA is required}" +args=(--sha "$sha" --required-job Builds --all-targets) +[ -z "${CI_RUN_ID:-}" ] || args+=(--run-id "$CI_RUN_ID") +exec bash src/runtimes/liboliphaunt-wasix/tools/download-assets.sh "${args[@]}" diff --git a/.github/scripts/manage-release-drafts.mjs b/.github/scripts/manage-release-drafts.mjs deleted file mode 100644 index 5fc4f97bf..000000000 --- a/.github/scripts/manage-release-drafts.mjs +++ /dev/null @@ -1,931 +0,0 @@ -#!/usr/bin/env bun -import { existsSync, readFileSync } from "node:fs"; -import path from "node:path"; -import process from "node:process"; - -import { redactGitHubReadDetail } from "../../tools/release/github-read.mjs"; -import { captureCommandOutput } from "../../tools/dev/capture-command-output.mjs"; -import { - assertResumableReleaseMetadata, - createGitHubOperationBudget, - exactReleaseMetadata, - exactTagRefPayload, - GitHubReleaseSnapshotRaceError, - GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS, - GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS, - GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS, - GITHUB_RELEASE_SNAPSHOT_VISIBILITY_WINDOW_MS, - readReleaseByTagSync, - readReleaseMapSync, - readTagRefSync, - reconcileGitHubMutationSync, - releaseNotesForVersion, - remainingGitHubReadOptions, - runGitHubMutationSync, -} from "../../tools/release/github-release-mutations.mjs"; -import { loadGraph } from "../../tools/release/release-graph.mjs"; -import { - RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS, - RELEASE_PLEASE_MARK_TAGGED_WINDOW_MS, -} from "../../tools/release/release-please-pr-lifecycle.mjs"; -import { - DEFAULT_PUBLICATION_LOCK, - loadPublicationLock, -} from "../../tools/release/publication-lock.mjs"; - -const FULL_SHA = /^[0-9a-f]{40}$/u; -const DEFAULT_GIT_SNAPSHOT_TIMEOUT_MS = 60_000; -const DEFAULT_FAST_MUTATION_TIMEOUT_MS = 60_000; -export const GITHUB_RELEASE_PROMOTION_MUTATION_TIMEOUT_MS = 10_000; -export const GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS = 30_000; -const GITHUB_RELEASE_PROMOTION_LIFECYCLE_MARGIN_MS = 30_000; -const GITHUB_RELEASE_PROMOTION_STEP_WINDOW_MS = 16 * 60_000; -export const GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS = - GITHUB_RELEASE_PROMOTION_STEP_WINDOW_MS - - RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS - - RELEASE_PLEASE_MARK_TAGGED_WINDOW_MS - - GITHUB_RELEASE_PROMOTION_LIFECYCLE_MARGIN_MS; - -export { - assertResumableReleaseMetadata, - exactReleaseMetadata, - exactTagRefPayload, - releaseNotesForVersion, -}; - -function error(message, options = {}) { - return new Error(`release-drafts: ${message}`, options); -} - -function usageError() { - return error( - "usage: manage-release-drafts.mjs " - + "--products-json JSON --head-ref SHA [--state draft|public|staged]", - ); -} - -function parseArgs(argv) { - const command = argv.shift(); - const values = new Map(); - for (let index = 0; index < argv.length; index += 2) { - const key = argv[index]; - const value = argv[index + 1]; - if (!key?.startsWith("--") || value === undefined || values.has(key.slice(2))) { - throw usageError(); - } - values.set(key.slice(2), value); - } - return { command, values }; -} - -function selectedPublicationLock(command, products, headRef, environment) { - const file = path.resolve( - environment.PUBLICATION_LOCK_PATH - ?? environment.OLIPHAUNT_PUBLICATION_LOCK - ?? DEFAULT_PUBLICATION_LOCK, - ); - if (!existsSync(file)) { - if (command === "preflight") return null; - throw error(`${command} requires the frozen publication lock: ${file}`); - } - const lock = loadPublicationLock(file); - if (lock.source.commit !== headRef) { - throw error(`publication lock targets ${lock.source.commit}, not ${headRef}`); - } - const lockedProducts = lock.products.map(({ id }) => id).sort(); - const requestedProducts = [...products].sort(); - if (JSON.stringify(lockedProducts) !== JSON.stringify(requestedProducts)) { - throw error( - `publication lock products ${JSON.stringify(lockedProducts)} do not match selected products ${JSON.stringify(requestedProducts)}`, - ); - } - return lock; -} - -function selectedReleases(command, products, headRef, environment) { - const graph = loadGraph("release-drafts"); - const publicationLock = selectedPublicationLock(command, products, headRef, environment); - const lockedProducts = publicationLock === null - ? new Map() - : new Map(publicationLock.products.map((product) => [product.id, product])); - return products.map((product) => { - const config = graph.products[product]; - if (!config) throw error(`unknown release product ${product}`); - const locked = lockedProducts.get(product); - const version = locked?.version ?? config.version; - if (config.version !== version) { - throw error(`${product} graph version ${config.version} does not match publication lock version ${version}`); - } - let body; - try { - body = releaseNotesForVersion(readFileSync(config.changelog_path, "utf8"), version); - } catch (cause) { - throw error(`${product} release notes are invalid: ${cause.message}`, { cause }); - } - const tag = `${config.tag_prefix}${version}`; - return { - metadata: exactReleaseMetadata({ body, headRef, product, tag, version }), - product, - tag, - version, - }; - }); -} - -function tagReconciliationState(ref, tag, headRef) { - if (ref === null) return { kind: "absent" }; - if (ref.type !== "commit" || ref.sha !== headRef || ref.ref !== `refs/tags/${tag}`) { - return { - detail: `${tag} targets ${ref.type}:${ref.sha}, not commit:${headRef}`, - kind: "conflict", - }; - } - return { kind: "desired" }; -} - -function releaseReconciliationState(release, expected, { allowPublic, expectedId } = {}) { - if (release === null) { - return expectedId === undefined - ? { kind: "absent" } - : { detail: `${expected.tag_name} release ${expectedId} disappeared`, kind: "conflict" }; - } - try { - assertResumableReleaseMetadata(release, expected); - } catch (cause) { - return { detail: cause.message, kind: "conflict" }; - } - if (expectedId !== undefined && release.id !== expectedId) { - return { - detail: `${expected.tag_name} release id changed from ${expectedId} to ${release.id}`, - kind: "conflict", - }; - } - if (allowPublic === true) return { kind: "desired" }; - return release.draft ? { kind: "unchanged" } : { kind: "desired" }; -} - -function mutationOptions(budget, environment, overrides) { - return { budget, environment, ...overrides }; -} - -export function stageExactTagSync({ budget, environment, headRef, repo, tag }, dependencies = {}) { - const readTag = dependencies.readTagRef ?? (() => - readTagRefSync(repo, tag, remainingGitHubReadOptions(budget))); - const createTag = dependencies.createTag ?? (({ deadlineMs, now, timeoutMs }) => - runGitHubMutationSync( - ["api", `repos/${repo}/git/refs`, "-X", "POST", "--input", "-"], - { - environment, - deadlineMs, - input: `${JSON.stringify(exactTagRefPayload(tag, headRef))}\n`, - now, - timeoutMs, - }, - )); - return reconcileGitHubMutationSync({ - inspect: () => tagReconciliationState(readTag(), tag, headRef), - label: `create exact tag ${tag}`, - mutate: createTag, - options: mutationOptions(budget, environment, dependencies.mutationOptions), - }); -} - -export function stageExactDraftReleaseSync( - { budget, environment, metadata, repo, tag }, - dependencies = {}, -) { - const readRelease = dependencies.readRelease ?? (() => - readReleaseByTagSync(repo, tag, remainingGitHubReadOptions(budget))); - const createRelease = dependencies.createRelease ?? (({ deadlineMs, now, timeoutMs }) => - runGitHubMutationSync( - ["api", `repos/${repo}/releases`, "-X", "POST", "--input", "-"], - { - environment, - deadlineMs, - input: `${JSON.stringify({ ...metadata, draft: true })}\n`, - now, - timeoutMs, - }, - )); - return reconcileGitHubMutationSync({ - inspect: () => releaseReconciliationState(readRelease(), metadata, { allowPublic: true }), - label: `create exact draft release ${tag}`, - mutate: createRelease, - options: mutationOptions(budget, environment, dependencies.mutationOptions), - }); -} - -export function promoteExactReleaseSync( - { budget, environment, expectedId, metadata, repo, tag }, - dependencies = {}, -) { - const readRelease = dependencies.readRelease ?? (() => - readReleaseByTagSync(repo, tag, remainingGitHubReadOptions(budget))); - const promoteRelease = dependencies.promoteRelease ?? (({ deadlineMs, now, timeoutMs }) => - runGitHubMutationSync( - ["api", `repos/${repo}/releases/${expectedId}`, "-X", "PATCH", "--input", "-"], - { - environment, - deadlineMs, - input: `${JSON.stringify({ draft: false })}\n`, - now, - timeoutMs, - }, - )); - return reconcileGitHubMutationSync({ - inspect: () => releaseReconciliationState(readRelease(), metadata, { expectedId }), - label: `promote exact release ${tag} (${expectedId})`, - mutate: promoteRelease, - options: mutationOptions(budget, environment, dependencies.mutationOptions), - }); -} - -function validateExistingReleases(selected, releasesByTag) { - for (const { metadata, tag } of selected) { - const release = releasesByTag.get(tag); - if (release === undefined) continue; - try { - assertResumableReleaseMetadata(release, metadata); - } catch (cause) { - throw error(cause.message, { cause }); - } - } -} - -function sleepSync(milliseconds) { - if (milliseconds <= 0) return; - const cell = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)); - Atomics.wait(cell, 0, 0, milliseconds); -} - -function pendingRequiredReleases(selected, releasesByTag, requiredState) { - return selected.flatMap(({ tag }) => { - const release = releasesByTag.get(tag); - if (release === undefined) return [`${tag} (missing)`]; - if (requiredState === "public" && release.draft) return [`${tag} (still draft)`]; - if (requiredState === "draft" && !release.draft) return [`${tag} (already public)`]; - return []; - }); -} - -function validateExpectedReleaseIds(selected, releasesByTag, expectedReleaseIds) { - if (expectedReleaseIds === undefined) return; - if (!(expectedReleaseIds instanceof Map)) { - throw error("expected release identities must be a Map"); - } - for (const { tag } of selected) { - const expectedId = expectedReleaseIds.get(tag); - if (!Number.isSafeInteger(expectedId) || expectedId <= 0) { - throw error(`expected release identity for ${tag} must be a positive integer`); - } - const release = releasesByTag.get(tag); - if (release !== undefined && release.id !== expectedId) { - throw error(`${tag} release id changed from ${expectedId} to ${release.id}`); - } - } -} - -function readRequiredReleaseMapSync({ - budget, - expectedReleaseIds, - readReleaseMap, - requiredState, - selected, - sleep = sleepSync, -}) { - if (!new Set(["draft", "public", "staged"]).has(requiredState)) { - throw error("required release snapshot state must be draft, public, or staged"); - } - if (typeof readReleaseMap !== "function" || typeof sleep !== "function") { - throw error("required release snapshot reader and sleep callback are required"); - } - let lastTransientSnapshotError = null; - for ( - let attempt = 0; - attempt <= GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.length; - attempt += 1 - ) { - let pending; - try { - const releasesByTag = readReleaseMap(); - validateExistingReleases(selected, releasesByTag); - validateExpectedReleaseIds(selected, releasesByTag, expectedReleaseIds); - pending = pendingRequiredReleases(selected, releasesByTag, requiredState); - if (pending.length === 0) return releasesByTag; - lastTransientSnapshotError = null; - } catch (cause) { - if (!(cause instanceof GitHubReleaseSnapshotRaceError)) throw cause; - if (cause.observedRelease !== undefined) { - const observedReleaseMap = - new Map([[cause.observedRelease.tag_name, cause.observedRelease]]); - validateExistingReleases(selected, observedReleaseMap); - validateExpectedReleaseIds(selected, observedReleaseMap, expectedReleaseIds); - } - lastTransientSnapshotError = cause; - pending = selected.map(({ tag }) => `${tag} (inconsistent paginated snapshot)`); - } - if (attempt === GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.length) { - throw error( - `GitHub release list did not converge to ${requiredState} state within ` - + `${GITHUB_RELEASE_SNAPSHOT_VISIBILITY_WINDOW_MS}ms: ${pending.join(", ")}`, - { cause: lastTransientSnapshotError ?? undefined }, - ); - } - const remainingVisibilityWindowMs = GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS - .slice(attempt) - .reduce((total, delay) => total + delay, 0); - if (budget.deadlineMs - budget.now() < remainingVisibilityWindowMs) { - throw error( - `GitHub operation lacks the complete ${remainingVisibilityWindowMs}ms release-list ` - + `visibility window required for: ${pending.join(", ")}`, - { cause: lastTransientSnapshotError ?? undefined }, - ); - } - sleep(GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS[attempt]); - } - throw error("required release snapshot loop ended unexpectedly"); -} - -function boundedReleaseSnapshotReadOptions(budget) { - const startedAtMs = budget.now(); - const snapshotBudget = { - ...budget, - deadlineMs: Math.min( - budget.deadlineMs, - startedAtMs + GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS, - ), - }; - return remainingGitHubReadOptions(snapshotBudget, { - attemptTimeoutMs: 4_000, - baseDelayMs: 500, - maxAttempts: GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS, - maxDelayMs: 500, - }); -} - -function requireExactTags(selected, repo, headRef, budget) { - for (const { product, tag } of selected) { - const ref = readTagRefSync(repo, tag, remainingGitHubReadOptions(budget)); - const state = tagReconciliationState(ref, tag, headRef); - if (state.kind !== "desired") { - throw error( - state.kind === "absent" - ? `${product} tag ${tag} does not exist` - : state.detail, - ); - } - } -} - -function finalReleaseState(selected, releasesByTag, command, expectedState) { - const wantDraft = command === "promote" ? false : expectedState === "draft"; - for (const { tag } of selected) { - const release = releasesByTag.get(tag); - if (release === undefined) { - throw error(`GitHub release for ${tag} does not exist after ${command}`); - } - if (expectedState !== "staged" && release.draft !== wantDraft) { - throw error(`${tag} is ${release.draft ? "draft" : "public"}; expected ${wantDraft ? "draft" : "public"}`); - } - } - return wantDraft; -} - -function parseMutationJson(output, label) { - if (typeof output !== "string" || Buffer.byteLength(output, "utf8") > 4 * 1024 * 1024) { - throw error(`${label} returned an invalid bounded response`); - } - try { - return JSON.parse(output); - } catch (cause) { - throw error(`${label} returned malformed JSON`, { cause }); - } -} - -function exactTagFromMutation(output, tag, headRef) { - const value = parseMutationJson(output, `create exact tag ${tag}`); - if ( - value === null - || Array.isArray(value) - || typeof value !== "object" - || value.ref !== `refs/tags/${tag}` - || value.object === null - || Array.isArray(value.object) - || typeof value.object !== "object" - || value.object.sha !== headRef - || value.object.type !== "commit" - ) { - throw error(`create exact tag ${tag} returned a response that does not bind commit:${headRef}`); - } - return { ref: value.ref, sha: value.object.sha, type: value.object.type }; -} - -function exactReleaseFromMutation(output, metadata, { draft, expectedId } = {}) { - const value = parseMutationJson(output, `mutate exact release ${metadata.tag_name}`); - assertResumableReleaseMetadata(value, metadata); - if (value.draft !== draft) { - throw error( - `${metadata.tag_name} mutation response is ${value.draft ? "draft" : "public"}; ` - + `expected ${draft ? "draft" : "public"}`, - ); - } - if (expectedId !== undefined && value.id !== expectedId) { - throw error(`${metadata.tag_name} mutation response id changed from ${expectedId} to ${value.id}`); - } - return value; -} - -function selectedTagNames(selected) { - const tags = selected.map(({ tag }) => tag); - if ( - tags.length === 0 - || new Set(tags).size !== tags.length - || tags.some((tag) => typeof tag !== "string" || tag.length === 0 || /[\s\u0000-\u001f\u007f]/u.test(tag)) - ) { - throw error("selected release tags must be a non-empty unique printable string list"); - } - return tags; -} - -/** - * Read every selected tag in one Git protocol advertisement rather than one - * REST request per product. The canonical release repository is public, so - * this snapshot intentionally carries no credential and consumes no - * GITHUB_TOKEN REST quota. - */ -export function readSelectedRemoteTagMapSync(repo, selected, options = {}) { - if (typeof repo !== "string" || !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repo)) { - throw error("GitHub repository must be OWNER/NAME"); - } - const tags = selectedTagNames(selected); - const remainingMs = options.budget === undefined - ? DEFAULT_GIT_SNAPSHOT_TIMEOUT_MS - : options.budget.deadlineMs - options.budget.now(); - if (!Number.isSafeInteger(remainingMs) || remainingMs <= 0) { - throw error("GitHub operation deadline has been reached before the remote tag snapshot"); - } - const gitArgs = [ - "-c", - "credential.helper=", - "ls-remote", - "--refs", - "--tags", - `https://github.com/${repo}.git`, - ...tags.map((tag) => `refs/tags/${tag}`), - ]; - const environment = { - ...(options.environment ?? process.env), - GIT_ASKPASS: "", - GIT_TERMINAL_PROMPT: "0", - SSH_ASKPASS: "", - }; - const requestedTimeoutMs = - options.timeoutMs ?? DEFAULT_GIT_SNAPSHOT_TIMEOUT_MS; - if ( - !Number.isSafeInteger(requestedTimeoutMs) - || requestedTimeoutMs < 1 - || requestedTimeoutMs > DEFAULT_GIT_SNAPSHOT_TIMEOUT_MS - ) { - throw error( - `remote tag snapshot timeout must be between 1 and ${DEFAULT_GIT_SNAPSHOT_TIMEOUT_MS}ms`, - ); - } - const timeout = Math.max(1, Math.min(requestedTimeoutMs, remainingMs)); - const result = options.spawn === undefined - ? captureCommandOutput("git", gitArgs, { - allowEmptyOutput: true, - cwd: options.cwd, - env: environment, - label: "git ls-remote selected release tags", - maxOutputBytes: 4 * 1024 * 1024, - stdoutTerminator: "\n", - timeout, - }) - : options.spawn("git", gitArgs, { - cwd: options.cwd, - encoding: "utf8", - env: environment, - maxBuffer: 4 * 1024 * 1024, - stdio: ["ignore", "pipe", "pipe"], - timeout, - }); - if (result.error !== undefined || result.status !== 0) { - const detail = redactGitHubReadDetail(result.error?.message ?? result.stderr ?? ""); - throw error(`could not read the exact selected remote tag snapshot${detail ? `: ${detail}` : ""}`); - } - const wanted = new Set(tags.map((tag) => `refs/tags/${tag}`)); - const refs = new Map(); - const stdout = String(result.stdout ?? ""); - if (stdout.length > 0 && !stdout.endsWith("\n")) { - throw error("remote tag snapshot ended with a partial record"); - } - for (const line of stdout.split(/\r?\n/u).filter(Boolean)) { - const match = /^([0-9a-f]{40})\t(refs\/tags\/[^\s\u0000-\u001f\u007f]+)$/u.exec(line); - if (match === null || !wanted.has(match[2]) || refs.has(match[2])) { - throw error("remote tag snapshot contained malformed, unexpected, or duplicate output"); - } - refs.set(match[2], { ref: match[2], sha: match[1], type: "commit" }); - } - return new Map(tags.map((tag) => [tag, refs.get(`refs/tags/${tag}`) ?? null])); -} - -function requireExactTagSnapshot(selected, tagsByName, headRef) { - if (!(tagsByName instanceof Map)) throw error("remote tag snapshot must be a Map"); - for (const { product, tag } of selected) { - const state = tagReconciliationState(tagsByName.get(tag) ?? null, tag, headRef); - if (state.kind !== "desired") { - throw error(state.kind === "absent" ? `${product} tag ${tag} does not exist` : state.detail); - } - } -} - -function requireCollisionFreeTagSnapshot(selected, tagsByName, headRef) { - if (!(tagsByName instanceof Map)) throw error("remote tag snapshot must be a Map"); - for (const { tag } of selected) { - const state = tagReconciliationState(tagsByName.get(tag) ?? null, tag, headRef); - if (state.kind === "conflict") throw error(state.detail); - } -} - -function fastMutationTimeout(budget, requiredTimeoutMs = DEFAULT_FAST_MUTATION_TIMEOUT_MS) { - const remainingMs = budget.deadlineMs - budget.now(); - if (remainingMs < requiredTimeoutMs) { - throw error( - `GitHub operation requires a complete ${requiredTimeoutMs}ms mutation timeout; ` - + `${Math.max(0, remainingMs)}ms remains`, - ); - } - return requiredTimeoutMs; -} - -function defaultTagMutation({ deadlineMs, environment, headRef, now, repo, tag, timeoutMs }) { - return runGitHubMutationSync( - ["api", `repos/${repo}/git/refs`, "-X", "POST", "--input", "-"], - { - environment, - deadlineMs, - input: `${JSON.stringify(exactTagRefPayload(tag, headRef))}\n`, - now, - timeoutMs, - }, - ); -} - -function defaultReleaseMutation({ deadlineMs, environment, metadata, now, repo, timeoutMs }) { - return runGitHubMutationSync( - ["api", `repos/${repo}/releases`, "-X", "POST", "--input", "-"], - { - environment, - deadlineMs, - input: `${JSON.stringify({ ...metadata, draft: true })}\n`, - now, - timeoutMs, - }, - ); -} - -function defaultPromotionMutation({ deadlineMs, environment, expectedId, now, repo, timeoutMs }) { - return runGitHubMutationSync( - ["api", `repos/${repo}/releases/${expectedId}`, "-X", "PATCH", "--input", "-"], - { - environment, - deadlineMs, - input: `${JSON.stringify({ draft: false })}\n`, - now, - timeoutMs, - }, - ); -} - -function stageMissingTagFromSnapshot(context, dependencies) { - const mutateTag = dependencies.mutateTag ?? defaultTagMutation; - try { - const output = mutateTag({ - ...context, - deadlineMs: context.budget.deadlineMs, - now: context.budget.now, - timeoutMs: fastMutationTimeout(context.budget), - }); - exactTagFromMutation(output, context.tag, context.headRef); - return { mutationAttempts: 1, recovered: false }; - } catch (cause) { - const result = stageExactTagSync(context, { - createTag: ({ deadlineMs, now, timeoutMs }) => mutateTag({ - ...context, - deadlineMs, - now, - timeoutMs, - }), - mutationOptions: dependencies.mutationOptions, - readTagRef: dependencies.readTagRef, - }); - return { ...result, fastMutationError: cause }; - } -} - -function stageMissingReleaseFromSnapshot(context, dependencies) { - const mutateRelease = dependencies.mutateRelease ?? defaultReleaseMutation; - try { - const output = mutateRelease({ - ...context, - deadlineMs: context.budget.deadlineMs, - now: context.budget.now, - timeoutMs: fastMutationTimeout(context.budget), - }); - exactReleaseFromMutation(output, context.metadata, { draft: true }); - return { mutationAttempts: 1, recovered: false }; - } catch (cause) { - let releasesByTag; - try { - releasesByTag = readRequiredReleaseMapSync({ - budget: context.budget, - readReleaseMap: dependencies.readReleaseMap, - requiredState: "staged", - selected: [{ metadata: context.metadata, tag: context.tag }], - sleep: dependencies.releaseSnapshotSleep, - }); - } catch (observationCause) { - const mutationDetail = redactGitHubReadDetail( - cause instanceof Error ? cause.message : String(cause), - context.environment, - ); - throw error( - `${observationCause instanceof Error ? observationCause.message : String(observationCause)}; ` - + `original draft mutation failure: ${mutationDetail || "unknown failure"}`, - { cause }, - ); - } - return { - fastMutationError: cause, - mutationAttempts: 1, - recovered: releasesByTag.has(context.tag), - }; - } -} - -function promoteReleaseFromSnapshot(context, dependencies) { - const mutatePromotion = dependencies.mutatePromotion ?? defaultPromotionMutation; - try { - const output = mutatePromotion({ - ...context, - deadlineMs: context.budget.deadlineMs, - now: context.budget.now, - timeoutMs: fastMutationTimeout( - context.budget, - GITHUB_RELEASE_PROMOTION_MUTATION_TIMEOUT_MS, - ), - }); - exactReleaseFromMutation(output, context.metadata, { draft: false, expectedId: context.expectedId }); - return { mutationAttempts: 1, recovered: false }; - } catch (cause) { - // PATCH is idempotent, but replay is unnecessary and makes the bounded - // finalization proof depend on an error-shaped number of writes. Observe - // the whole selected batch once below; a rerun safely resumes any draft - // whose first PATCH was definitely not applied. - return { - fastMutationError: cause, - mutationAttempts: 1, - recovered: false, - }; - } -} - -export function reconcileSelectedReleasesSync( - { budget, command, environment, expectedState, headRef, repo, selected }, - dependencies = {}, -) { - const readReleaseMap = dependencies.readReleaseMap ?? readReleaseMapSync; - const snapshotReleaseMap = () => - readReleaseMap(repo, boundedReleaseSnapshotReadOptions(budget)); - const readTagMap = dependencies.readTagMap ?? readSelectedRemoteTagMapSync; - const snapshotTagMap = () => readTagMap(repo, selected, { - budget, - environment, - timeoutMs: command === "promote" - ? GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS - : DEFAULT_GIT_SNAPSHOT_TIMEOUT_MS, - }); - const perTagDependencies = { - ...dependencies, - readTagRef: dependencies.readTagRef ?? ((tag) => - readTagRefSync(repo, tag, remainingGitHubReadOptions(budget))), - }; - const perReleaseDependencies = { - ...dependencies, - readRelease: dependencies.readRelease ?? ((tag) => - readReleaseByTagSync(repo, tag, remainingGitHubReadOptions(budget))), - }; - const releaseSnapshotSleep = dependencies.releaseSnapshotSleep ?? sleepSync; - const requiredReleaseMap = (requiredState, { expectedReleaseIds } = {}) => - readRequiredReleaseMapSync({ - budget, - expectedReleaseIds, - readReleaseMap: snapshotReleaseMap, - requiredState, - selected, - sleep: releaseSnapshotSleep, - }); - - let releasesByTag; - if (command === "verify") { - releasesByTag = requiredReleaseMap(expectedState); - } else if (command === "promote") { - // No mutation has happened yet. A missing/stale precondition can fail and - // be rerun safely, so it does not need the post-mutation visibility wait. - releasesByTag = snapshotReleaseMap(); - validateExistingReleases(selected, releasesByTag); - } else { - releasesByTag = snapshotReleaseMap(); - validateExistingReleases(selected, releasesByTag); - } - let tagsByName = snapshotTagMap(); - requireCollisionFreeTagSnapshot(selected, tagsByName, headRef); - - if (command === "preflight") { - console.log(`${selected.length} selected product tag/release names are absent or exact-SHA resumable`); - return; - } - if (command === "stage") { - for (const { product, tag } of selected) { - if (tagsByName.get(tag) !== null) continue; - const result = stageMissingTagFromSnapshot( - { budget, environment, headRef, repo, tag }, - { - ...perTagDependencies, - readTagRef: () => perTagDependencies.readTagRef(tag), - }, - ); - if (result.mutationAttempts > 0) console.log(`reconciled exact-SHA tag ${tag} for ${product}`); - } - tagsByName = snapshotTagMap(); - requireExactTagSnapshot(selected, tagsByName, headRef); - for (const { metadata, tag } of selected) { - if (releasesByTag.has(tag)) continue; - const result = stageMissingReleaseFromSnapshot( - { budget, environment, metadata, repo, tag }, - { - ...perReleaseDependencies, - readReleaseMap: snapshotReleaseMap, - readRelease: () => perReleaseDependencies.readRelease(tag), - releaseSnapshotSleep, - }, - ); - if (result.mutationAttempts > 0) console.log(`reconciled draft GitHub release ${tag}`); - } - releasesByTag = requiredReleaseMap("staged"); - tagsByName = snapshotTagMap(); - requireExactTagSnapshot(selected, tagsByName, headRef); - } else { - requireExactTagSnapshot(selected, tagsByName, headRef); - } - - for (const { tag } of selected) { - if (!releasesByTag.has(tag)) throw error(`GitHub release for ${tag} does not exist`); - } - - if (command === "promote") { - const promotionFailures = []; - const expectedReleaseIds = new Map( - selected.map(({ tag }) => [tag, releasesByTag.get(tag).id]), - ); - for (const { metadata, tag } of selected) { - const release = releasesByTag.get(tag); - if (!release.draft) continue; - const result = promoteReleaseFromSnapshot( - { - budget, - environment, - expectedId: release.id, - metadata, - repo, - tag, - }, - { - ...perReleaseDependencies, - readRelease: () => perReleaseDependencies.readRelease(tag), - }, - ); - if (result.fastMutationError !== undefined) { - promotionFailures.push({ cause: result.fastMutationError, tag }); - } - if (result.mutationAttempts > 0) console.log(`reconciled promotion of ${tag}`); - } - try { - releasesByTag = requiredReleaseMap("public", { expectedReleaseIds }); - } catch (observationCause) { - if (promotionFailures.length === 0) throw observationCause; - const firstFailure = promotionFailures[0]; - const mutationDetail = redactGitHubReadDetail( - firstFailure.cause instanceof Error - ? firstFailure.cause.message - : String(firstFailure.cause), - environment, - ); - throw error( - `${observationCause instanceof Error ? observationCause.message : String(observationCause)}; ` - + `${promotionFailures.length} promotion mutation failure(s); first failure for ` - + `${firstFailure.tag}: ${mutationDetail || "unknown failure"}`, - { cause: firstFailure.cause }, - ); - } - tagsByName = snapshotTagMap(); - requireExactTagSnapshot(selected, tagsByName, headRef); - } - - const wantDraft = finalReleaseState(selected, releasesByTag, command, expectedState); - if (expectedState === "staged" && command !== "promote") { - console.log(`${selected.length} exact-SHA releases are staged (draft or already promoted by a resumable prior run)`); - } else { - console.log(`${selected.length} exact-SHA releases are ${wantDraft ? "draft" : "public"}`); - } -} - -function defaultWindowForCommand(command) { - if (command === "stage") return 30 * 60_000; - // Promotion count is release-plan-derived. Keep the command inside the - // mandatory finalization reserve while leaving a bounded contingency margin. - if (command === "promote") return GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS; - return 5 * 60_000; -} - -export function createReleaseDraftOperationBudget( - command, - { environment = process.env, now = Date.now } = {}, -) { - const defaultWindowMs = defaultWindowForCommand(command); - const budget = createGitHubOperationBudget({ - defaultWindowMs, - environment, - now, - }); - if (command !== "promote") return budget; - const maximumDeadlineMs = budget.startedAtMs + defaultWindowMs; - if (budget.deadlineMs <= maximumDeadlineMs) return budget; - return Object.freeze({ - ...budget, - deadlineMs: maximumDeadlineMs, - }); -} - -export function main(argv, { environment = process.env, now = Date.now } = {}) { - const { command, values } = parseArgs([...argv]); - if (![ - "preflight", - "stage", - "verify", - "promote", - ].includes(command)) { - throw error( - "command must be preflight, stage, verify, or promote", - ); - } - const repo = environment.GITHUB_REPOSITORY?.trim(); - if (!repo || !environment.GH_TOKEN) { - throw error("GITHUB_REPOSITORY and GH_TOKEN are required"); - } - - let products; - try { - products = JSON.parse(values.get("products-json") ?? ""); - } catch (cause) { - throw error(`invalid --products-json: ${cause.message}`, { cause }); - } - if ( - !Array.isArray(products) - || products.length === 0 - || products.some((product) => typeof product !== "string" || product.length === 0) - || new Set(products).size !== products.length - ) { - throw error("--products-json must be a non-empty unique product string list"); - } - - const headRef = values.get("head-ref"); - if (!headRef || !FULL_SHA.test(headRef)) { - throw error("--head-ref must be a full lowercase commit SHA"); - } - const expectedState = values.get("state") ?? "draft"; - if (!new Set(["draft", "public", "staged"]).has(expectedState)) { - throw error("--state must be draft, public, or staged"); - } - - const selected = selectedReleases(command, products, headRef, environment); - const budget = createReleaseDraftOperationBudget(command, { environment, now }); - reconcileSelectedReleasesSync({ - budget, - command, - environment: budget.environment, - expectedState, - headRef, - repo, - selected, - }); -} - -if (import.meta.main) { - try { - main(process.argv.slice(2)); - } catch (cause) { - console.error(redactGitHubReadDetail(cause instanceof Error ? cause.message : String(cause))); - process.exit(1); - } -} diff --git a/.github/scripts/manage-release-drafts.mts b/.github/scripts/manage-release-drafts.mts new file mode 100644 index 000000000..bc50ff2d9 --- /dev/null +++ b/.github/scripts/manage-release-drafts.mts @@ -0,0 +1,932 @@ +#!/usr/bin/env bun +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { setTimeout as sleepAsync } from 'node:timers/promises'; +import { loadProducts } from '../../tools/release/release-graph.mts'; +import { redactGitHubReadDetail, requestGithubGraphql } from '../../tools/release/github-read.mts'; +import { + assertResumableReleaseMetadata, + createGitHubOperationBudget, + exactReleaseMetadata, + exactTagRefPayload, + GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS, + GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS, + GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS, + GITHUB_RELEASE_SNAPSHOT_VISIBILITY_WINDOW_MS, + GitHubReleaseSnapshotRaceError, + readReleaseMap as githubReleaseMap, + readReleaseByTag, + readTagRef, + reconcileGitHubMutation, + releaseNotesForVersion, + remainingGitHubReadOptions, + requestGithubMutation, +} from '../../tools/release/github-release-mutations.mts'; +import { + DEFAULT_PUBLICATION_LOCK, + loadPublicationLock, +} from '../../tools/release/publication-lock.mts'; +import { + RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS, + RELEASE_PLEASE_MARK_TAGGED_WINDOW_MS, +} from '../../tools/release/release-please-pr-lifecycle.mts'; + +const FULL_SHA = /^[0-9a-f]{40}$/u; +const DEFAULT_TAG_SNAPSHOT_TIMEOUT_MS = 60_000; +const DEFAULT_FAST_MUTATION_TIMEOUT_MS = 60_000; +export const GITHUB_RELEASE_PROMOTION_MUTATION_TIMEOUT_MS = 10_000; +export const GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS = 30_000; +const GITHUB_RELEASE_PROMOTION_LIFECYCLE_MARGIN_MS = 30_000; +const GITHUB_RELEASE_PROMOTION_STEP_WINDOW_MS = 16 * 60_000; +export const GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS = + GITHUB_RELEASE_PROMOTION_STEP_WINDOW_MS - + RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS - + RELEASE_PLEASE_MARK_TAGGED_WINDOW_MS - + GITHUB_RELEASE_PROMOTION_LIFECYCLE_MARGIN_MS; + +export { + assertResumableReleaseMetadata, + exactReleaseMetadata, + exactTagRefPayload, + releaseNotesForVersion, +}; + +function error(message, options = {}) { + return new Error(`release-drafts: ${message}`, options); +} + +function usageError() { + return error( + 'usage: manage-release-drafts.mts ' + + '--products-json JSON --head-ref SHA [--state draft|public|staged]', + ); +} + +function parseArgs(argv) { + const command = argv.shift(); + const values = new Map(); + for (let index = 0; index < argv.length; index += 2) { + const key = argv[index]; + const value = argv[index + 1]; + if (!key?.startsWith('--') || value === undefined || values.has(key.slice(2))) { + throw usageError(); + } + values.set(key.slice(2), value); + } + return { command, values }; +} + +function selectedPublicationLock(command, products, headRef, environment) { + const file = path.resolve( + environment.PUBLICATION_LOCK_PATH ?? + environment.OLIPHAUNT_PUBLICATION_LOCK ?? + DEFAULT_PUBLICATION_LOCK, + ); + if (!existsSync(file)) { + if (command === 'preflight') return null; + throw error(`${command} requires the frozen publication lock: ${file}`); + } + const lock = loadPublicationLock(file); + if (lock.source.commit !== headRef) { + throw error(`publication lock targets ${lock.source.commit}, not ${headRef}`); + } + const lockedProducts = lock.products.map(({ id }) => id).sort(); + const requestedProducts = [...products].sort(); + if (JSON.stringify(lockedProducts) !== JSON.stringify(requestedProducts)) { + throw error( + `publication lock products ${JSON.stringify(lockedProducts)} do not match selected products ${JSON.stringify(requestedProducts)}`, + ); + } + return lock; +} + +function selectedReleases(command, products, headRef, environment) { + const productMetadata = loadProducts('release-drafts'); + const publicationLock = selectedPublicationLock(command, products, headRef, environment); + const lockedProducts = + publicationLock === null + ? new Map() + : new Map(publicationLock.products.map((product) => [product.id, product])); + return products.map((product) => { + const config = productMetadata[product]; + if (!config) throw error(`unknown release product ${product}`); + const locked = lockedProducts.get(product); + const version = locked?.version ?? config.version; + if (config.version !== version) { + throw error( + `${product} graph version ${config.version} does not match publication lock version ${version}`, + ); + } + let body; + try { + body = releaseNotesForVersion(readFileSync(config.changelog_path, 'utf8'), version); + } catch (cause) { + throw error(`${product} release notes are invalid: ${cause.message}`, { cause }); + } + const tag = `${config.tag_prefix}${version}`; + return { + metadata: exactReleaseMetadata({ body, headRef, product, tag, version }), + product, + tag, + version, + }; + }); +} + +function tagReconciliationState(ref, tag, headRef) { + if (ref === null) return { kind: 'absent' }; + if (ref.type !== 'commit' || ref.sha !== headRef || ref.ref !== `refs/tags/${tag}`) { + return { + detail: `${tag} targets ${ref.type}:${ref.sha}, not commit:${headRef}`, + kind: 'conflict', + }; + } + return { kind: 'desired' }; +} + +function releaseReconciliationState(release, expected, { allowPublic, expectedId } = {}) { + if (release === null) { + return expectedId === undefined + ? { kind: 'absent' } + : { detail: `${expected.tag_name} release ${expectedId} disappeared`, kind: 'conflict' }; + } + try { + assertResumableReleaseMetadata(release, expected); + } catch (cause) { + return { detail: cause.message, kind: 'conflict' }; + } + if (expectedId !== undefined && release.id !== expectedId) { + return { + detail: `${expected.tag_name} release id changed from ${expectedId} to ${release.id}`, + kind: 'conflict', + }; + } + if (allowPublic === true) return { kind: 'desired' }; + return release.draft ? { kind: 'unchanged' } : { kind: 'desired' }; +} + +function mutationOptions(budget, environment, overrides) { + return { budget, environment, ...overrides }; +} + +export async function stageExactTag( + { budget, environment, headRef, repo, tag }, + dependencies = {}, +) { + const readTag = + dependencies.readTagRef ?? + (async () => await readTagRef(repo, tag, remainingGitHubReadOptions(budget))); + const createTag = + dependencies.createTag ?? + (async ({ deadlineMs, now, timeoutMs }) => + await requestGithubMutation(`repos/${repo}/git/refs`, { + method: 'POST', + environment, + deadlineMs, + input: `${JSON.stringify(exactTagRefPayload(tag, headRef))}\n`, + now, + timeoutMs, + })); + return await reconcileGitHubMutation({ + inspect: async () => tagReconciliationState(await readTag(), tag, headRef), + label: `create exact tag ${tag}`, + mutate: createTag, + options: mutationOptions(budget, environment, dependencies.mutationOptions), + }); +} + +export async function stageExactDraftRelease( + { budget, environment, metadata, repo, tag }, + dependencies = {}, +) { + const readRelease = + dependencies.readRelease ?? + (async () => await readReleaseByTag(repo, tag, remainingGitHubReadOptions(budget))); + const createRelease = + dependencies.createRelease ?? + (async ({ deadlineMs, now, timeoutMs }) => + await requestGithubMutation(`repos/${repo}/releases`, { + method: 'POST', + environment, + deadlineMs, + input: `${JSON.stringify({ ...metadata, draft: true })}\n`, + now, + timeoutMs, + })); + return await reconcileGitHubMutation({ + inspect: async () => + releaseReconciliationState(await readRelease(), metadata, { allowPublic: true }), + label: `create exact draft release ${tag}`, + mutate: createRelease, + options: mutationOptions(budget, environment, dependencies.mutationOptions), + }); +} + +export async function promoteExactRelease( + { budget, environment, expectedId, metadata, repo, tag }, + dependencies = {}, +) { + const readRelease = + dependencies.readRelease ?? + (async () => await readReleaseByTag(repo, tag, remainingGitHubReadOptions(budget))); + const promoteRelease = + dependencies.promoteRelease ?? + (async ({ deadlineMs, now, timeoutMs }) => + await requestGithubMutation(`repos/${repo}/releases/${expectedId}`, { + method: 'PATCH', + environment, + deadlineMs, + input: `${JSON.stringify({ draft: false })}\n`, + now, + timeoutMs, + })); + return await reconcileGitHubMutation({ + inspect: async () => releaseReconciliationState(await readRelease(), metadata, { expectedId }), + label: `promote exact release ${tag} (${expectedId})`, + mutate: promoteRelease, + options: mutationOptions(budget, environment, dependencies.mutationOptions), + }); +} + +function validateExistingReleases(selected, releasesByTag) { + for (const { metadata, tag } of selected) { + const release = releasesByTag.get(tag); + if (release === undefined) continue; + try { + assertResumableReleaseMetadata(release, metadata); + } catch (cause) { + throw error(cause.message, { cause }); + } + } +} + +function pendingRequiredReleases(selected, releasesByTag, requiredState) { + return selected.flatMap(({ tag }) => { + const release = releasesByTag.get(tag); + if (release === undefined) return [`${tag} (missing)`]; + if (requiredState === 'public' && release.draft) return [`${tag} (still draft)`]; + if (requiredState === 'draft' && !release.draft) return [`${tag} (already public)`]; + return []; + }); +} + +function validateExpectedReleaseIds(selected, releasesByTag, expectedReleaseIds) { + if (expectedReleaseIds === undefined) return; + if (!(expectedReleaseIds instanceof Map)) { + throw error('expected release identities must be a Map'); + } + for (const { tag } of selected) { + const expectedId = expectedReleaseIds.get(tag); + if (!Number.isSafeInteger(expectedId) || expectedId <= 0) { + throw error(`expected release identity for ${tag} must be a positive integer`); + } + const release = releasesByTag.get(tag); + if (release !== undefined && release.id !== expectedId) { + throw error(`${tag} release id changed from ${expectedId} to ${release.id}`); + } + } +} + +async function readRequiredReleaseMap({ + budget, + expectedReleaseIds, + readReleaseMap, + requiredState, + selected, + sleep = sleepAsync, +}) { + if (!new Set(['draft', 'public', 'staged']).has(requiredState)) { + throw error('required release snapshot state must be draft, public, or staged'); + } + if (typeof readReleaseMap !== 'function' || typeof sleep !== 'function') { + throw error('required release snapshot reader and sleep callback are required'); + } + let lastTransientSnapshotError = null; + for ( + let attempt = 0; + attempt <= GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.length; + attempt += 1 + ) { + let pending; + try { + const releasesByTag = await readReleaseMap(); + validateExistingReleases(selected, releasesByTag); + validateExpectedReleaseIds(selected, releasesByTag, expectedReleaseIds); + pending = pendingRequiredReleases(selected, releasesByTag, requiredState); + if (pending.length === 0) return releasesByTag; + lastTransientSnapshotError = null; + } catch (cause) { + if (!(cause instanceof GitHubReleaseSnapshotRaceError)) throw cause; + if (cause.observedRelease !== undefined) { + const observedReleaseMap = new Map([ + [cause.observedRelease.tag_name, cause.observedRelease], + ]); + validateExistingReleases(selected, observedReleaseMap); + validateExpectedReleaseIds(selected, observedReleaseMap, expectedReleaseIds); + } + lastTransientSnapshotError = cause; + pending = selected.map(({ tag }) => `${tag} (inconsistent paginated snapshot)`); + } + if (attempt === GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.length) { + throw error( + `GitHub release list did not converge to ${requiredState} state within ` + + `${GITHUB_RELEASE_SNAPSHOT_VISIBILITY_WINDOW_MS}ms: ${pending.join(', ')}`, + { cause: lastTransientSnapshotError ?? undefined }, + ); + } + const remainingVisibilityWindowMs = GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice( + attempt, + ).reduce((total, delay) => total + delay, 0); + if (budget.deadlineMs - budget.now() < remainingVisibilityWindowMs) { + throw error( + `GitHub operation lacks the complete ${remainingVisibilityWindowMs}ms release-list ` + + `visibility window required for: ${pending.join(', ')}`, + { cause: lastTransientSnapshotError ?? undefined }, + ); + } + await sleep(GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS[attempt]); + } + throw error('required release snapshot loop ended unexpectedly'); +} + +function boundedReleaseSnapshotReadOptions(budget) { + const startedAtMs = budget.now(); + const snapshotBudget = { + ...budget, + deadlineMs: Math.min(budget.deadlineMs, startedAtMs + GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS), + }; + return remainingGitHubReadOptions(snapshotBudget, { + attemptTimeoutMs: 4_000, + baseDelayMs: 500, + maxAttempts: GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS, + maxDelayMs: 500, + }); +} + +async function requireExactTags(selected, repo, headRef, budget) { + for (const { product, tag } of selected) { + const ref = await readTagRef(repo, tag, remainingGitHubReadOptions(budget)); + const state = tagReconciliationState(ref, tag, headRef); + if (state.kind !== 'desired') { + throw error(state.kind === 'absent' ? `${product} tag ${tag} does not exist` : state.detail); + } + } +} + +function finalReleaseState(selected, releasesByTag, command, expectedState) { + const wantDraft = command === 'promote' ? false : expectedState === 'draft'; + for (const { tag } of selected) { + const release = releasesByTag.get(tag); + if (release === undefined) { + throw error(`GitHub release for ${tag} does not exist after ${command}`); + } + if (expectedState !== 'staged' && release.draft !== wantDraft) { + throw error( + `${tag} is ${release.draft ? 'draft' : 'public'}; expected ${wantDraft ? 'draft' : 'public'}`, + ); + } + } + return wantDraft; +} + +function parseMutationJson(output, label) { + if (typeof output !== 'string' || Buffer.byteLength(output, 'utf8') > 4 * 1024 * 1024) { + throw error(`${label} returned an invalid bounded response`); + } + try { + return JSON.parse(output); + } catch (cause) { + throw error(`${label} returned malformed JSON`, { cause }); + } +} + +function exactTagFromMutation(output, tag, headRef) { + const value = parseMutationJson(output, `create exact tag ${tag}`); + if ( + value === null || + Array.isArray(value) || + typeof value !== 'object' || + value.ref !== `refs/tags/${tag}` || + value.object === null || + Array.isArray(value.object) || + typeof value.object !== 'object' || + value.object.sha !== headRef || + value.object.type !== 'commit' + ) { + throw error(`create exact tag ${tag} returned a response that does not bind commit:${headRef}`); + } + return { ref: value.ref, sha: value.object.sha, type: value.object.type }; +} + +function exactReleaseFromMutation(output, metadata, { draft, expectedId } = {}) { + const value = parseMutationJson(output, `mutate exact release ${metadata.tag_name}`); + assertResumableReleaseMetadata(value, metadata); + if (value.draft !== draft) { + throw error( + `${metadata.tag_name} mutation response is ${value.draft ? 'draft' : 'public'}; ` + + `expected ${draft ? 'draft' : 'public'}`, + ); + } + if (expectedId !== undefined && value.id !== expectedId) { + throw error( + `${metadata.tag_name} mutation response id changed from ${expectedId} to ${value.id}`, + ); + } + return value; +} + +function selectedTagNames(selected) { + const tags = selected.map(({ tag }) => tag); + if ( + tags.length === 0 || + new Set(tags).size !== tags.length || + tags.some( + (tag) => typeof tag !== 'string' || tag.length === 0 || /[\s\u0000-\u001f\u007f]/u.test(tag), + ) + ) { + throw error('selected release tags must be a non-empty unique printable string list'); + } + return tags; +} + +// One bounded query returns only the selected refs, including explicit absences. +export async function readSelectedRemoteTagMap(repo, selected, options = {}) { + if (typeof repo !== 'string' || !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repo)) { + throw error('GitHub repository must be OWNER/NAME'); + } + const tags = selectedTagNames(selected); + const now = options.budget?.now ?? Date.now; + const timeout = options.timeoutMs ?? DEFAULT_TAG_SNAPSHOT_TIMEOUT_MS; + if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > DEFAULT_TAG_SNAPSHOT_TIMEOUT_MS) { + throw error('remote tag snapshot timeout must be between 1 and 60000ms'); + } + const deadlineMs = Math.min(options.budget?.deadlineMs ?? Infinity, now() + timeout); + if (deadlineMs <= now()) + throw error('GitHub operation deadline has been reached before the remote tag snapshot'); + const [owner, name] = repo.split('/'); + const variables = { owner, name }; + for (const [index, tag] of tags.entries()) variables['tag' + index] = 'refs/tags/' + tag; + const declarations = Object.keys(variables) + .map((key) => '$' + key + ': String!') + .join(', '); + const fields = tags + .map( + (_, index) => + 'tag' + + index + + ': ref(qualifiedName: $tag' + + index + + ') { prefix name target { __typename oid } }', + ) + .join('\n'); + const result = await requestGithubGraphql( + 'query SelectedReleaseTags(' + + declarations + + ') { repository(owner: $owner, name: $name) { nameWithOwner ' + + fields + + ' } }', + variables, + { + environment: options.environment ?? options.budget?.environment ?? process.env, + deadlineMs, + nowImpl: now, + attemptTimeoutMs: timeout, + maxAttempts: 2, + fetchImpl: options.fetchImpl, + }, + ); + const repository = result?.data?.repository; + if ( + (result?.errors !== undefined && (!Array.isArray(result.errors) || result.errors.length > 0)) || + repository?.nameWithOwner !== repo || + Object.keys(repository).length !== tags.length + 1 + ) { + throw error('remote tag snapshot returned an incomplete or unexpected repository'); + } + return new Map( + tags.map((tag, index) => { + const ref = repository['tag' + index]; + if (ref === null) return [tag, null]; + if ( + ref?.prefix !== 'refs/tags/' || + ref.name !== tag || + !FULL_SHA.test(ref.target?.oid ?? '') || + !['Commit', 'Tag', 'Tree', 'Blob'].includes(ref.target?.__typename) + ) { + throw error('remote tag snapshot contained malformed or unexpected ref data'); + } + return [ + tag, + { + ref: ref.prefix + ref.name, + sha: ref.target.oid, + type: ref.target.__typename.toLowerCase(), + }, + ]; + }), + ); +} + +function requireExactTagSnapshot(selected, tagsByName, headRef) { + if (!(tagsByName instanceof Map)) throw error('remote tag snapshot must be a Map'); + for (const { product, tag } of selected) { + const state = tagReconciliationState(tagsByName.get(tag) ?? null, tag, headRef); + if (state.kind !== 'desired') { + throw error(state.kind === 'absent' ? `${product} tag ${tag} does not exist` : state.detail); + } + } +} + +function requireCollisionFreeTagSnapshot(selected, tagsByName, headRef) { + if (!(tagsByName instanceof Map)) throw error('remote tag snapshot must be a Map'); + for (const { tag } of selected) { + const state = tagReconciliationState(tagsByName.get(tag) ?? null, tag, headRef); + if (state.kind === 'conflict') throw error(state.detail); + } +} + +function fastMutationTimeout(budget, requiredTimeoutMs = DEFAULT_FAST_MUTATION_TIMEOUT_MS) { + const remainingMs = budget.deadlineMs - budget.now(); + if (remainingMs < requiredTimeoutMs) { + throw error( + `GitHub operation requires a complete ${requiredTimeoutMs}ms mutation timeout; ` + + `${Math.max(0, remainingMs)}ms remains`, + ); + } + return requiredTimeoutMs; +} + +async function defaultTagMutation({ deadlineMs, environment, headRef, now, repo, tag, timeoutMs }) { + return await requestGithubMutation(`repos/${repo}/git/refs`, { + method: 'POST', + environment, + deadlineMs, + input: `${JSON.stringify(exactTagRefPayload(tag, headRef))}\n`, + now, + timeoutMs, + }); +} + +async function defaultReleaseMutation({ deadlineMs, environment, metadata, now, repo, timeoutMs }) { + return await requestGithubMutation(`repos/${repo}/releases`, { + method: 'POST', + environment, + deadlineMs, + input: `${JSON.stringify({ ...metadata, draft: true })}\n`, + now, + timeoutMs, + }); +} + +async function defaultPromotionMutation({ + deadlineMs, + environment, + expectedId, + now, + repo, + timeoutMs, +}) { + return await requestGithubMutation(`repos/${repo}/releases/${expectedId}`, { + method: 'PATCH', + environment, + deadlineMs, + input: `${JSON.stringify({ draft: false })}\n`, + now, + timeoutMs, + }); +} + +async function stageMissingTagFromSnapshot(context, dependencies) { + const mutateTag = dependencies.mutateTag ?? defaultTagMutation; + try { + const output = await mutateTag({ + ...context, + deadlineMs: context.budget.deadlineMs, + now: context.budget.now, + timeoutMs: fastMutationTimeout(context.budget), + }); + exactTagFromMutation(output, context.tag, context.headRef); + return { mutationAttempts: 1, recovered: false }; + } catch (cause) { + const result = await stageExactTag(context, { + createTag: async ({ deadlineMs, now, timeoutMs }) => + await mutateTag({ + ...context, + deadlineMs, + now, + timeoutMs, + }), + mutationOptions: dependencies.mutationOptions, + readTagRef: dependencies.readTagRef, + }); + return { ...result, fastMutationError: cause }; + } +} + +async function stageMissingReleaseFromSnapshot(context, dependencies) { + const mutateRelease = dependencies.mutateRelease ?? defaultReleaseMutation; + try { + const output = await mutateRelease({ + ...context, + deadlineMs: context.budget.deadlineMs, + now: context.budget.now, + timeoutMs: fastMutationTimeout(context.budget), + }); + exactReleaseFromMutation(output, context.metadata, { draft: true }); + return { mutationAttempts: 1, recovered: false }; + } catch (cause) { + let releasesByTag; + try { + releasesByTag = await readRequiredReleaseMap({ + budget: context.budget, + readReleaseMap: dependencies.readReleaseMap, + requiredState: 'staged', + selected: [{ metadata: context.metadata, tag: context.tag }], + sleep: dependencies.releaseSnapshotSleep, + }); + } catch (observationCause) { + const mutationDetail = redactGitHubReadDetail( + cause instanceof Error ? cause.message : String(cause), + context.environment, + ); + throw error( + `${observationCause instanceof Error ? observationCause.message : String(observationCause)}; ` + + `original draft mutation failure: ${mutationDetail || 'unknown failure'}`, + { cause }, + ); + } + return { + fastMutationError: cause, + mutationAttempts: 1, + recovered: releasesByTag.has(context.tag), + }; + } +} + +async function promoteReleaseFromSnapshot(context, dependencies) { + const mutatePromotion = dependencies.mutatePromotion ?? defaultPromotionMutation; + try { + const output = await mutatePromotion({ + ...context, + deadlineMs: context.budget.deadlineMs, + now: context.budget.now, + timeoutMs: fastMutationTimeout(context.budget, GITHUB_RELEASE_PROMOTION_MUTATION_TIMEOUT_MS), + }); + exactReleaseFromMutation(output, context.metadata, { + draft: false, + expectedId: context.expectedId, + }); + return { mutationAttempts: 1, recovered: false }; + } catch (cause) { + // PATCH is idempotent, but replay is unnecessary and makes the bounded + // finalization proof depend on an error-shaped number of writes. Observe + // the whole selected batch once below; a rerun safely resumes any draft + // whose first PATCH was definitely not applied. + return { + fastMutationError: cause, + mutationAttempts: 1, + recovered: false, + }; + } +} + +export async function reconcileSelectedReleases( + { budget, command, environment, expectedState, headRef, repo, selected }, + dependencies = {}, +) { + const readReleaseMap = dependencies.readReleaseMap ?? githubReleaseMap; + const snapshotReleaseMap = async () => + await readReleaseMap(repo, boundedReleaseSnapshotReadOptions(budget)); + const readTagMap = dependencies.readTagMap ?? readSelectedRemoteTagMap; + const snapshotTagMap = () => + readTagMap(repo, selected, { + budget, + environment, + timeoutMs: + command === 'promote' + ? GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS + : DEFAULT_TAG_SNAPSHOT_TIMEOUT_MS, + }); + const perTagDependencies = { + ...dependencies, + readTagRef: + dependencies.readTagRef ?? + (async (tag) => await readTagRef(repo, tag, remainingGitHubReadOptions(budget))), + }; + const perReleaseDependencies = { + ...dependencies, + readRelease: + dependencies.readRelease ?? + (async (tag) => await readReleaseByTag(repo, tag, remainingGitHubReadOptions(budget))), + }; + const releaseSnapshotSleep = dependencies.releaseSnapshotSleep ?? sleepAsync; + const requiredReleaseMap = async (requiredState, { expectedReleaseIds } = {}) => + await readRequiredReleaseMap({ + budget, + expectedReleaseIds, + readReleaseMap: snapshotReleaseMap, + requiredState, + selected, + sleep: releaseSnapshotSleep, + }); + + let releasesByTag; + if (command === 'verify') { + releasesByTag = await requiredReleaseMap(expectedState); + } else if (command === 'promote') { + // No mutation has happened yet. A missing/stale precondition can fail and + // be rerun safely, so it does not need the post-mutation visibility wait. + releasesByTag = await snapshotReleaseMap(); + validateExistingReleases(selected, releasesByTag); + } else { + releasesByTag = await snapshotReleaseMap(); + validateExistingReleases(selected, releasesByTag); + } + let tagsByName = await snapshotTagMap(); + requireCollisionFreeTagSnapshot(selected, tagsByName, headRef); + + if (command === 'preflight') { + console.log( + `${selected.length} selected product tag/release names are absent or exact-SHA resumable`, + ); + return; + } + if (command === 'stage') { + for (const { product, tag } of selected) { + if (tagsByName.get(tag) !== null) continue; + const result = await stageMissingTagFromSnapshot( + { budget, environment, headRef, repo, tag }, + { + ...perTagDependencies, + readTagRef: async () => await perTagDependencies.readTagRef(tag), + }, + ); + if (result.mutationAttempts > 0) + console.log(`reconciled exact-SHA tag ${tag} for ${product}`); + } + tagsByName = await snapshotTagMap(); + requireExactTagSnapshot(selected, tagsByName, headRef); + for (const { metadata, tag } of selected) { + if (releasesByTag.has(tag)) continue; + const result = await stageMissingReleaseFromSnapshot( + { budget, environment, metadata, repo, tag }, + { + ...perReleaseDependencies, + readReleaseMap: snapshotReleaseMap, + readRelease: async () => await perReleaseDependencies.readRelease(tag), + releaseSnapshotSleep, + }, + ); + if (result.mutationAttempts > 0) console.log(`reconciled draft GitHub release ${tag}`); + } + releasesByTag = await requiredReleaseMap('staged'); + tagsByName = await snapshotTagMap(); + requireExactTagSnapshot(selected, tagsByName, headRef); + } else { + requireExactTagSnapshot(selected, tagsByName, headRef); + } + + for (const { tag } of selected) { + if (!releasesByTag.has(tag)) throw error(`GitHub release for ${tag} does not exist`); + } + + if (command === 'promote') { + const promotionFailures = []; + const expectedReleaseIds = new Map(selected.map(({ tag }) => [tag, releasesByTag.get(tag).id])); + for (const { metadata, tag } of selected) { + const release = releasesByTag.get(tag); + if (!release.draft) continue; + const result = await promoteReleaseFromSnapshot( + { + budget, + environment, + expectedId: release.id, + metadata, + repo, + tag, + }, + { + ...perReleaseDependencies, + readRelease: async () => await perReleaseDependencies.readRelease(tag), + }, + ); + if (result.fastMutationError !== undefined) { + promotionFailures.push({ cause: result.fastMutationError, tag }); + } + if (result.mutationAttempts > 0) console.log(`reconciled promotion of ${tag}`); + } + try { + releasesByTag = await requiredReleaseMap('public', { expectedReleaseIds }); + } catch (observationCause) { + if (promotionFailures.length === 0) throw observationCause; + const firstFailure = promotionFailures[0]; + const mutationDetail = redactGitHubReadDetail( + firstFailure.cause instanceof Error + ? firstFailure.cause.message + : String(firstFailure.cause), + environment, + ); + throw error( + `${observationCause instanceof Error ? observationCause.message : String(observationCause)}; ` + + `${promotionFailures.length} promotion mutation failure(s); first failure for ` + + `${firstFailure.tag}: ${mutationDetail || 'unknown failure'}`, + { cause: firstFailure.cause }, + ); + } + tagsByName = await snapshotTagMap(); + requireExactTagSnapshot(selected, tagsByName, headRef); + } + + const wantDraft = finalReleaseState(selected, releasesByTag, command, expectedState); + if (expectedState === 'staged' && command !== 'promote') { + console.log( + `${selected.length} exact-SHA releases are staged (draft or already promoted by a resumable prior run)`, + ); + } else { + console.log(`${selected.length} exact-SHA releases are ${wantDraft ? 'draft' : 'public'}`); + } +} + +function defaultWindowForCommand(command) { + if (command === 'stage') return 30 * 60_000; + // Promotion count is release-plan-derived. Keep the command inside the + // mandatory finalization reserve while leaving a bounded contingency margin. + if (command === 'promote') return GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS; + return 5 * 60_000; +} + +export function createReleaseDraftOperationBudget( + command, + { environment = process.env, now = Date.now } = {}, +) { + const defaultWindowMs = defaultWindowForCommand(command); + const budget = createGitHubOperationBudget({ + defaultWindowMs, + environment, + now, + }); + if (command !== 'promote') return budget; + const maximumDeadlineMs = budget.startedAtMs + defaultWindowMs; + if (budget.deadlineMs <= maximumDeadlineMs) return budget; + return Object.freeze({ + ...budget, + deadlineMs: maximumDeadlineMs, + }); +} + +export async function main(argv, { environment = process.env, now = Date.now } = {}) { + const { command, values } = parseArgs([...argv]); + if (!['preflight', 'stage', 'verify', 'promote'].includes(command)) { + throw error('command must be preflight, stage, verify, or promote'); + } + const repo = environment.GITHUB_REPOSITORY?.trim(); + if (!repo || !environment.GH_TOKEN) { + throw error('GITHUB_REPOSITORY and GH_TOKEN are required'); + } + + let products; + try { + products = JSON.parse(values.get('products-json') ?? ''); + } catch (cause) { + throw error(`invalid --products-json: ${cause.message}`, { cause }); + } + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string' || product.length === 0) || + new Set(products).size !== products.length + ) { + throw error('--products-json must be a non-empty unique product string list'); + } + + const headRef = values.get('head-ref'); + if (!headRef || !FULL_SHA.test(headRef)) { + throw error('--head-ref must be a full lowercase commit SHA'); + } + const expectedState = values.get('state') ?? 'draft'; + if (!new Set(['draft', 'public', 'staged']).has(expectedState)) { + throw error('--state must be draft, public, or staged'); + } + + const selected = selectedReleases(command, products, headRef, environment); + const budget = createReleaseDraftOperationBudget(command, { environment, now }); + await reconcileSelectedReleases({ + budget, + command, + environment: budget.environment, + expectedState, + headRef, + repo, + selected, + }); +} + +if (import.meta.main) { + try { + await main(process.argv.slice(2)); + } catch (cause) { + console.error(redactGitHubReadDetail(cause instanceof Error ? cause.message : String(cause))); + process.exit(1); + } +} diff --git a/.github/scripts/merge-checksum-manifest.mjs b/.github/scripts/merge-checksum-manifest.mjs deleted file mode 100644 index 08de5702c..000000000 --- a/.github/scripts/merge-checksum-manifest.mjs +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bun -import { mkdtempSync, renameSync, rmSync, writeFileSync } from 'node:fs'; -import { readFile } from 'node:fs/promises'; -import { dirname, join } from 'node:path'; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function fail(message) { - console.error(`merge-checksum-manifest.mjs: ${message}`); - process.exit(1); -} - -function parseManifest(path, text, entries) { - for (const [index, line] of text.split(/\r?\n/).entries()) { - const lineNumber = index + 1; - const stripped = line.trim(); - if (stripped.length === 0) { - continue; - } - const match = /^([0-9a-f]{64})\s+(.+)$/.exec(stripped); - if (match === null) { - fail(`${path}: invalid checksum line ${lineNumber}: ${line}`); - } - const digest = match[1]; - const rawName = match[2].trim(); - const name = rawName.startsWith('./') ? rawName.slice(2) : rawName; - if (name.length === 0 || name.includes('/')) { - fail(`${path}: invalid checksum asset name on line ${lineNumber}: ${rawName}`); - } - const previous = entries.get(name); - if (previous !== undefined && previous !== digest) { - fail(`${path}: conflicting checksum for ${name}: ${previous} vs ${digest}`); - } - entries.set(name, digest); - } -} - -const [existing, incoming] = process.argv.slice(2); -if (existing === undefined || incoming === undefined) { - fail('usage: merge-checksum-manifest.mjs '); -} - -const entries = new Map(); -parseManifest(existing, await readFile(existing, 'utf8'), entries); -parseManifest(incoming, await readFile(incoming, 'utf8'), entries); - -const merged = [...entries] - .sort(([left], [right]) => compareText(left, right)) - .map(([name, digest]) => `${digest} ./${name}\n`) - .join(''); - -const tempDir = mkdtempSync(join(dirname(existing), '.oliphaunt-checksums-')); -const tempPath = join(tempDir, 'checksums.sha256'); -try { - writeFileSync(tempPath, merged, { encoding: 'utf8' }); - renameSync(tempPath, existing); -} finally { - rmSync(tempDir, { force: true, recursive: true }); -} diff --git a/.github/scripts/merge-checksum-manifest.mts b/.github/scripts/merge-checksum-manifest.mts new file mode 100644 index 000000000..42d7f6fc3 --- /dev/null +++ b/.github/scripts/merge-checksum-manifest.mts @@ -0,0 +1,70 @@ +#!/usr/bin/env bun +import { mkdtempSync, renameSync, rmSync, writeFileSync } from 'node:fs'; +import { readFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function fail(message) { + throw new Error(`merge-checksum-manifest.mts: ${message}`); +} + +function parseManifest(path, text, entries) { + for (const [index, line] of text.split(/\r?\n/).entries()) { + const lineNumber = index + 1; + const stripped = line.trim(); + if (stripped.length === 0) { + continue; + } + const match = /^([0-9a-f]{64})\s+(.+)$/.exec(stripped); + if (match === null) { + fail(`${path}: invalid checksum line ${lineNumber}: ${line}`); + } + const digest = match[1]; + const rawName = match[2].trim(); + const name = rawName.startsWith('./') ? rawName.slice(2) : rawName; + if (name.length === 0 || name.includes('/')) { + fail(`${path}: invalid checksum asset name on line ${lineNumber}: ${rawName}`); + } + const previous = entries.get(name); + if (previous !== undefined && previous !== digest) { + fail(`${path}: conflicting checksum for ${name}: ${previous} vs ${digest}`); + } + entries.set(name, digest); + } +} + +export async function mergeChecksumManifest(existing, incoming) { + if (existing === undefined || incoming === undefined) { + fail('usage: merge-checksum-manifest.mts '); + } + + const entries = new Map(); + parseManifest(existing, await readFile(existing, 'utf8'), entries); + parseManifest(incoming, await readFile(incoming, 'utf8'), entries); + + const merged = [...entries] + .sort(([left], [right]) => compareText(left, right)) + .map(([name, digest]) => `${digest} ./${name}\n`) + .join(''); + + const tempDir = mkdtempSync(join(dirname(existing), '.oliphaunt-checksums-')); + const tempPath = join(tempDir, 'checksums.sha256'); + try { + writeFileSync(tempPath, merged, { encoding: 'utf8' }); + renameSync(tempPath, existing); + } finally { + rmSync(tempDir, { force: true, recursive: true }); + } +} + +if (import.meta.main) { + try { + await mergeChecksumManifest(...process.argv.slice(2)); + } catch (error) { + console.error(error.message); + process.exitCode = 1; + } +} diff --git a/.github/scripts/moon-producer-receipt.mts b/.github/scripts/moon-producer-receipt.mts new file mode 100644 index 000000000..85fabfce5 --- /dev/null +++ b/.github/scripts/moon-producer-receipt.mts @@ -0,0 +1,107 @@ +import { readFileSync, appendFileSync } from 'node:fs'; +import path from 'node:path'; +import assert from 'node:assert/strict'; +import { createRequire } from 'node:module'; +import { requestGithubRepositoryJson } from '../../tools/release/github-read.mts'; + +const HASH = /^[0-9a-f]{64}$/u; + +export function producerTypescriptVersion(packageDirectory) { + const require = createRequire(path.resolve(packageDirectory, 'package.json')); + return require('typescript/package.json').version; +} + +/** Moon owns input hashing. A receipt only records a complete, observed chain. */ +export function producerHashes(report, cacheRoot, target) { + const actions = report.actions.filter((action) => action.node?.action === 'run-task'); + const action = actions.find((entry) => entry.node.params.target === target); + if (!action || !['passed', 'cached'].includes(action.status)) + return { eligible: false, reason: 'producer did not complete in this invocation' }; + const hash = action.operations.find((operation) => operation.meta?.type === 'hash-generation') + ?.meta.hash; + if (!HASH.test(hash ?? '')) return { eligible: false, reason: 'producer hashing is disabled' }; + const hashes = new Map(); + const visit = (expectedTarget, currentHash) => { + if (!HASH.test(currentHash ?? '')) + throw new Error(`incomplete producer hash: ${expectedTarget}=${currentHash}`); + if (hashes.has(expectedTarget)) { + assert.equal(hashes.get(expectedTarget).hash, currentHash, 'inconsistent producer ancestry'); + return; + } + const manifest = JSON.parse( + readFileSync(path.join(cacheRoot, 'hashes', `${currentHash}.json`), 'utf8'), + ); + const task = manifest.find((part) => part.target === expectedTarget); + assert( + task && task.deps && Array.isArray(task.toolchains), + `missing Moon task manifest: ${expectedTarget}`, + ); + hashes.set(expectedTarget, { + target: expectedTarget, + hash: currentHash, + dependencies: task.deps, + }); + for (const [dependency, dependencyHash] of Object.entries(task.deps)) + visit(dependency, dependencyHash); + }; + try { + visit(target, hash); + } catch (error) { + return { eligible: false, reason: error.message }; + } + return { + eligible: true, + taskHash: hash, + cacheHit: action.status === 'cached', + hashes: [...hashes.values()].sort((left, right) => left.target.localeCompare(right.target)), + }; +} + +if (import.meta.main) { + const [target, artifactName, packageDirectory] = process.argv.slice(2); + assert( + target && artifactName && packageDirectory, + 'usage: moon-producer-receipt.mts TARGET ARTIFACT_NAME PACKAGE_DIRECTORY', + ); + const artifactId = Number(process.env.PRODUCER_ARTIFACT_ID); + assert(Number.isSafeInteger(artifactId) && artifactId > 0, 'immutable artifact ID is required'); + const artifact = await requestGithubRepositoryJson( + `repos/${process.env.GITHUB_REPOSITORY}/actions/artifacts/${artifactId}`, + ); + assert.equal(artifact.id, artifactId); + assert.equal(artifact.name, artifactName); + assert.equal(artifact.expired, false); + const uploadDigest = (process.env.PRODUCER_ARTIFACT_DIGEST ?? '').replace(/^sha256:/u, ''); + assert(HASH.test(uploadDigest), 'upload did not return a SHA-256 digest'); + assert.equal(artifact.digest, `sha256:${uploadDigest}`); + assert.equal(String(artifact.workflow_run?.id), process.env.GITHUB_RUN_ID); + assert.equal(artifact.workflow_run?.head_sha, process.env.CI_HEAD_SHA); + const report = JSON.parse(readFileSync('.moon/cache/runReport.json', 'utf8')); + const scope = producerHashes(report, '.moon/cache', target); + const receipt = { + target, + ...scope, + producer: { + sha: process.env.CI_HEAD_SHA, + runId: process.env.GITHUB_RUN_ID, + runAttempt: Number(process.env.GITHUB_RUN_ATTEMPT), + }, + toolchain: { + moon: process.env.PRODUCER_MOON_VERSION, + bun: Bun.version, + typescript: producerTypescriptVersion(packageDirectory), + target: 'portable-typescript', + }, + artifact: { + id: artifact.id, + name: artifact.name, + digest: artifact.digest, + size: artifact.size_in_bytes, + }, + }; + assert( + receipt.toolchain.moon && receipt.toolchain.typescript, + 'actual producer toolchain is required', + ); + appendFileSync(process.env.GITHUB_OUTPUT, `receipt=${JSON.stringify(receipt)}\n`); +} diff --git a/.github/scripts/moon-task-capabilities.mjs b/.github/scripts/moon-task-capabilities.mjs deleted file mode 100644 index 9e8a62c0b..000000000 --- a/.github/scripts/moon-task-capabilities.mjs +++ /dev/null @@ -1,169 +0,0 @@ -const RUST_CAPABILITY_TAG = "requires-rust"; -const MAINTAINER_TOOLS_CAPABILITY_TAG = "requires-maintainer-tools"; -const ANDROID_SDK_CAPABILITY_TAG = "requires-android-sdk"; -const APPLE_CAPABILITY_TAG = "requires-apple"; -const WASMER_LLVM_CAPABILITY_TAG = "requires-wasmer-llvm"; - -const DISPLAY_WORDS = Object.freeze({ - abi: "ABI", - aot: "AOT", - api: "API", - ci: "CI", - e2e: "E2E", - icu: "ICU", - ios: "iOS", - js: "JavaScript", - liboliphaunt: "liboliphaunt", - macos: "macOS", - napi: "Node-API", - node: "Node.js", - npm: "npm", - sdk: "SDK", - sql: "SQL", - ts: "TypeScript", - wasm: "WebAssembly", - wasix: "WASIX", - xtask: "xtask", -}); -const DISPLAY_PARTS = Object.freeze({ - "extension-artifacts-native": "Native Extension Artifacts", -}); - -export const MAX_TARGETS_PER_JOB = 4; - -function taskTags(task) { - return new Set(Array.isArray(task?.tags) ? task.tags : []); -} - -export function taskDependencies(task) { - return (Array.isArray(task?.deps) ? task.deps : []) - .map((dependency) => { - if (typeof dependency === "string") return dependency; - if (dependency && typeof dependency === "object" && typeof dependency.target === "string") { - return dependency.target; - } - return ""; - }) - .filter(Boolean); -} - -function taskTarget(task) { - if (typeof task?.target !== "string" || task.target.length === 0) { - throw new Error("Moon task capability resolution requires a task target"); - } - return task.target; -} - -export function taskCapabilities(task, taskMap, state = {}) { - const target = taskTarget(task); - const memo = state.memo ?? new Map(); - const visiting = state.visiting ?? new Set(); - const cached = memo.get(target); - if (cached !== undefined) return cached; - if (visiting.has(target)) { - throw new Error(`Moon task capability dependency cycle through ${target}`); - } - - visiting.add(target); - const tags = taskTags(task); - let requiresMaintainerTools = tags.has(MAINTAINER_TOOLS_CAPABILITY_TAG); - let requiresRust = tags.has(RUST_CAPABILITY_TAG) || requiresMaintainerTools; - let requiresAndroidSdk = tags.has(ANDROID_SDK_CAPABILITY_TAG); - let requiresApple = tags.has(APPLE_CAPABILITY_TAG); - let requiresWasmerLlvm = tags.has(WASMER_LLVM_CAPABILITY_TAG); - let requiresWorkspace = Array.isArray(task.toolchains) && task.toolchains.includes("pnpm"); - - for (const dependency of taskDependencies(task)) { - const dependencyTask = taskMap.get(dependency); - if (dependencyTask === undefined) { - throw new Error(`${target} capability dependency ${dependency} is missing from Moon task metadata`); - } - const capabilities = taskCapabilities(dependencyTask, taskMap, { memo, visiting }); - requiresMaintainerTools ||= capabilities.requires_maintainer_tools; - requiresRust ||= capabilities.requires_rust; - requiresAndroidSdk ||= capabilities.requires_android_sdk; - requiresApple ||= capabilities.requires_apple; - requiresWasmerLlvm ||= capabilities.requires_wasmer_llvm; - requiresWorkspace ||= capabilities.requires_workspace; - } - - visiting.delete(target); - const capabilities = Object.freeze({ - requires_rust: requiresRust, - requires_maintainer_tools: requiresMaintainerTools, - requires_android_sdk: requiresAndroidSdk, - requires_apple: requiresApple, - requires_wasmer_llvm: requiresWasmerLlvm, - requires_workspace: requiresWorkspace, - }); - memo.set(target, capabilities); - return capabilities; -} - -export function matrixTarget(task, upstream, taskMap) { - return { - target: taskTarget(task), - label: taskLabel(taskTarget(task)), - upstream, - ...taskCapabilities(task, taskMap), - }; -} - -export function taskLabel(target) { - return target.split(":").map((part) => DISPLAY_PARTS[part] ?? part.split("-").map((word) => - DISPLAY_WORDS[word] ?? `${word.slice(0, 1).toUpperCase()}${word.slice(1)}` - ).join(" ")).join(" / "); -} - -function compareTargets(left, right) { - return left.target < right.target ? -1 : left.target > right.target ? 1 : 0; -} - -function groupRow(targets) { - const first = targets[0]; - return { - label: targets.map(({ label }) => label).join(" + "), - target_count: targets.length, - requires_rust: first.requires_rust, - requires_maintainer_tools: first.requires_maintainer_tools, - requires_android_sdk: first.requires_android_sdk, - requires_apple: first.requires_apple, - requires_wasmer_llvm: first.requires_wasmer_llvm, - requires_workspace: first.requires_workspace, - runner: first.requires_apple ? "macos-26" : "ubuntu-24.04", - targets_json: JSON.stringify({ - include: targets.map(({ target, upstream }) => ({ target, upstream })), - }), - }; -} - -export function groupTargets(targets, { maxTargets = MAX_TARGETS_PER_JOB } = {}) { - if (!Number.isInteger(maxTargets) || maxTargets < 1) { - throw new Error("target group size must be a positive integer"); - } - const ordered = [...targets].sort(compareTargets); - const unique = new Set(ordered.map(({ target }) => target)); - if (unique.size !== ordered.length) { - throw new Error("target group input contains duplicate Moon targets"); - } - - const byCapabilities = new Map(); - for (const target of ordered) { - const key = [ - target.requires_rust, - target.requires_maintainer_tools, - target.requires_android_sdk, - target.requires_apple, - target.requires_wasmer_llvm, - target.requires_workspace, - ].map(Number).join(""); - byCapabilities.set(key, [...(byCapabilities.get(key) ?? []), target]); - } - const groups = []; - for (const targetsWithSameSetup of [...byCapabilities.values()]) { - for (let index = 0; index < targetsWithSameSetup.length; index += maxTargets) { - groups.push(targetsWithSameSetup.slice(index, index + maxTargets)); - } - } - return groups.map(groupRow); -} diff --git a/.github/scripts/moon-task-capabilities.mts b/.github/scripts/moon-task-capabilities.mts new file mode 100644 index 000000000..ca69f49c5 --- /dev/null +++ b/.github/scripts/moon-task-capabilities.mts @@ -0,0 +1,187 @@ +const RUST_CAPABILITY_TAG = 'requires-rust'; +const MAINTAINER_TOOLS_CAPABILITY_TAG = 'requires-maintainer-tools'; +const ANDROID_SDK_CAPABILITY_TAG = 'requires-android-sdk'; +const SWIFT_CAPABILITY_TAG = 'requires-swift'; +const APPLE_CAPABILITY_TAG = 'requires-apple'; +const WASMER_LLVM_CAPABILITY_TAG = 'requires-wasmer-llvm'; + +const DISPLAY_WORDS = Object.freeze({ + abi: 'ABI', + aot: 'AOT', + api: 'API', + ci: 'CI', + e2e: 'E2E', + icu: 'ICU', + ios: 'iOS', + js: 'JavaScript', + liboliphaunt: 'liboliphaunt', + macos: 'macOS', + napi: 'Node-API', + node: 'Node.js', + npm: 'npm', + sdk: 'SDK', + sql: 'SQL', + ts: 'TypeScript', + wasm: 'WebAssembly', + wasix: 'WASIX', + xtask: 'xtask', +}); +const DISPLAY_PARTS = Object.freeze({ + 'extension-artifacts-native': 'Native Extension Artifacts', +}); + +export const MAX_TARGETS_PER_JOB = 4; + +function taskTags(task) { + return new Set(Array.isArray(task?.tags) ? task.tags : []); +} + +export function taskDependencies(task) { + return (Array.isArray(task?.deps) ? task.deps : []) + .map((dependency) => { + if (typeof dependency === 'string') return dependency; + if (dependency && typeof dependency === 'object' && typeof dependency.target === 'string') { + return dependency.target; + } + return ''; + }) + .filter(Boolean); +} + +function taskTarget(task) { + if (typeof task?.target !== 'string' || task.target.length === 0) { + throw new Error('Moon task capability resolution requires a task target'); + } + return task.target; +} + +export function taskCapabilities(task, taskMap, state = {}) { + const target = taskTarget(task); + const memo = state.memo ?? new Map(); + const visiting = state.visiting ?? new Set(); + const cached = memo.get(target); + if (cached !== undefined) return cached; + if (visiting.has(target)) { + throw new Error(`Moon task capability dependency cycle through ${target}`); + } + + visiting.add(target); + const tags = taskTags(task); + let requiresMaintainerTools = tags.has(MAINTAINER_TOOLS_CAPABILITY_TAG); + let requiresRust = tags.has(RUST_CAPABILITY_TAG) || requiresMaintainerTools; + let requiresAndroidSdk = tags.has(ANDROID_SDK_CAPABILITY_TAG); + let requiresSwift = tags.has(SWIFT_CAPABILITY_TAG); + let requiresApple = tags.has(APPLE_CAPABILITY_TAG); + let requiresWasmerLlvm = tags.has(WASMER_LLVM_CAPABILITY_TAG); + let requiresWorkspace = Array.isArray(task.toolchains) && task.toolchains.includes('bun'); + + for (const dependency of taskDependencies(task)) { + const dependencyTask = taskMap.get(dependency); + if (dependencyTask === undefined) { + throw new Error( + `${target} capability dependency ${dependency} is missing from Moon task metadata`, + ); + } + const capabilities = taskCapabilities(dependencyTask, taskMap, { memo, visiting }); + requiresMaintainerTools ||= capabilities.requires_maintainer_tools; + requiresRust ||= capabilities.requires_rust; + requiresAndroidSdk ||= capabilities.requires_android_sdk; + requiresSwift ||= capabilities.requires_swift; + requiresApple ||= capabilities.requires_apple; + requiresWasmerLlvm ||= capabilities.requires_wasmer_llvm; + requiresWorkspace ||= capabilities.requires_workspace; + } + + visiting.delete(target); + const capabilities = Object.freeze({ + requires_rust: requiresRust, + requires_maintainer_tools: requiresMaintainerTools, + requires_android_sdk: requiresAndroidSdk, + requires_apple: requiresApple, + requires_swift: requiresSwift, + requires_wasmer_llvm: requiresWasmerLlvm, + requires_workspace: requiresWorkspace, + }); + memo.set(target, capabilities); + return capabilities; +} + +export function matrixTarget(task, upstream, taskMap) { + return { + target: taskTarget(task), + label: taskLabel(taskTarget(task)), + upstream, + ...taskCapabilities(task, taskMap), + }; +} + +export function taskLabel(target) { + return target + .split(':') + .map( + (part) => + DISPLAY_PARTS[part] ?? + part + .split('-') + .map((word) => DISPLAY_WORDS[word] ?? `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`) + .join(' '), + ) + .join(' / '); +} + +function compareTargets(left, right) { + return left.target < right.target ? -1 : left.target > right.target ? 1 : 0; +} + +function groupRow(targets) { + const first = targets[0]; + return { + label: targets.map(({ label }) => label).join(' + '), + target_count: targets.length, + requires_rust: first.requires_rust, + requires_maintainer_tools: first.requires_maintainer_tools, + requires_android_sdk: first.requires_android_sdk, + requires_apple: first.requires_apple, + requires_swift: first.requires_swift, + requires_wasmer_llvm: first.requires_wasmer_llvm, + requires_workspace: first.requires_workspace, + runner: first.requires_apple ? 'macos-26' : 'ubuntu-24.04', + targets_json: JSON.stringify({ + include: targets.map(({ target, upstream }) => ({ target, upstream })), + }), + }; +} + +export function groupTargets(targets, { maxTargets = MAX_TARGETS_PER_JOB } = {}) { + if (!Number.isInteger(maxTargets) || maxTargets < 1) { + throw new Error('target group size must be a positive integer'); + } + const ordered = [...targets].sort(compareTargets); + const unique = new Set(ordered.map(({ target }) => target)); + if (unique.size !== ordered.length) { + throw new Error('target group input contains duplicate Moon targets'); + } + + const byCapabilities = new Map(); + for (const target of ordered) { + const key = [ + target.requires_rust, + target.requires_maintainer_tools, + target.requires_android_sdk, + target.requires_apple, + target.requires_swift, + target.requires_wasmer_llvm, + target.requires_workspace, + ] + .map(Number) + .join(''); + byCapabilities.set(key, [...(byCapabilities.get(key) ?? []), target]); + } + const groups = []; + for (const targetsWithSameSetup of [...byCapabilities.values()]) { + for (let index = 0; index < targetsWithSameSetup.length; index += maxTargets) { + groups.push(targetsWithSameSetup.slice(index, index + maxTargets)); + } + } + return groups.map(groupRow); +} diff --git a/.github/scripts/moon-task-capabilities.test.mjs b/.github/scripts/moon-task-capabilities.test.mjs deleted file mode 100644 index 71df01d65..000000000 --- a/.github/scripts/moon-task-capabilities.test.mjs +++ /dev/null @@ -1,98 +0,0 @@ -import { strict as assert } from "node:assert"; -import { describe, test } from "node:test"; - -import { - groupTargets, - matrixTarget, - taskCapabilities, - taskLabel, -} from "./moon-task-capabilities.mjs"; - -function tasks(...entries) { - return new Map(entries.map((task) => [task.target, task])); -} - -describe("Moon task capabilities", () => { - test("renders human-readable task labels", () => { - assert.equal( - taskLabel("oliphaunt-wasix-napi:format-check"), - "Oliphaunt WASIX Node-API / Format Check", - ); - assert.equal(taskLabel("extension-artifacts-native:unit"), "Native Extension Artifacts / Unit"); - }); - - test("propagates capabilities through dependencies and makes maintainer tools imply Rust", () => { - const taskMap = tasks( - { target: "repo:leaf", tags: ["requires-maintainer-tools", "requires-wasmer-llvm"], toolchains: ["pnpm"] }, - { target: "repo:middle", tags: ["requires-android-sdk"], deps: [{ target: "repo:leaf" }] }, - { target: "repo:root", tags: [], deps: ["repo:middle"] }, - ); - - assert.deepEqual(taskCapabilities(taskMap.get("repo:root"), taskMap), { - requires_rust: true, - requires_maintainer_tools: true, - requires_android_sdk: true, - requires_apple: false, - requires_wasmer_llvm: true, - requires_workspace: true, - }); - }); - - test("fails closed for incomplete or cyclic dependency metadata", () => { - const incomplete = tasks({ target: "repo:root", deps: ["repo:missing"] }); - assert.throws( - () => taskCapabilities(incomplete.get("repo:root"), incomplete), - /repo:missing/u, - ); - - const cyclic = tasks( - { target: "repo:first", deps: ["repo:second"] }, - { target: "repo:second", deps: ["repo:first"] }, - ); - assert.throws( - () => taskCapabilities(cyclic.get("repo:first"), cyclic), - /dependency cycle/u, - ); - }); - - test("creates bounded groups with one setup profile per job", () => { - const taskMap = tasks( - ...Array.from({ length: 9 }, (_, index) => ({ target: `plain:${index}`, tags: [] })), - { target: "rust:first", tags: ["requires-rust"] }, - { target: "rust:second", tags: ["requires-rust"] }, - { target: "android:check", tags: ["requires-android-sdk"] }, - { target: "apple:check", tags: ["requires-apple"] }, - { target: "workspace:check", tags: [], toolchains: ["pnpm"] }, - { target: "aot:check", tags: ["requires-wasmer-llvm"] }, - ); - const targets = [...taskMap.values()].map((task) => matrixTarget(task, "deep", taskMap)); - const groups = groupTargets(targets, { maxTargets: 4 }); - - assert.deepEqual(groups.map(({ target_count }) => target_count), [1, 1, 1, 4, 4, 1, 2, 1]); - assert.equal(groups[3].label, "Plain / 0 + Plain / 1 + Plain / 2 + Plain / 3"); - assert.equal(groups.filter(({ requires_rust }) => requires_rust).length, 1); - assert.equal(groups.filter(({ requires_android_sdk }) => requires_android_sdk).length, 1); - assert.equal(groups.filter(({ requires_apple }) => requires_apple).length, 1); - assert.equal(groups.filter(({ requires_workspace }) => requires_workspace).length, 1); - assert.equal(groups.filter(({ requires_wasmer_llvm }) => requires_wasmer_llvm).length, 1); - assert.equal(groups.find(({ requires_apple }) => requires_apple).runner, "macos-26"); - const selected = groups.flatMap(({ targets_json }) => - JSON.parse(targets_json).include.map(({ target }) => target)); - assert.deepEqual(selected.sort(), [...taskMap.keys()].sort()); - }); - - test("rejects duplicate targets and invalid shard limits", () => { - const row = { - target: "repo:check", - upstream: "deep", - requires_rust: false, - requires_maintainer_tools: false, - requires_android_sdk: false, - requires_apple: false, - requires_wasmer_llvm: false, - requires_workspace: false, - }; - assert.throws(() => groupTargets([row, row]), /duplicate/u); - assert.throws(() => groupTargets([row], { maxTargets: 0 }), /positive integer/u); - }); -}); diff --git a/.github/scripts/moon-task-capabilities.test.mts b/.github/scripts/moon-task-capabilities.test.mts new file mode 100644 index 000000000..44e5430ab --- /dev/null +++ b/.github/scripts/moon-task-capabilities.test.mts @@ -0,0 +1,101 @@ +import { strict as assert } from 'node:assert'; +import { describe, test } from 'bun:test'; + +import { + groupTargets, + matrixTarget, + taskCapabilities, + taskLabel, +} from './moon-task-capabilities.mts'; + +function tasks(...entries) { + return new Map(entries.map((task) => [task.target, task])); +} + +describe('Moon task capabilities', () => { + test('renders human-readable task labels', () => { + assert.equal( + taskLabel('oliphaunt-wasix-napi:format-check'), + 'Oliphaunt WASIX Node-API / Format Check', + ); + assert.equal(taskLabel('extension-artifacts-native:test'), 'Native Extension Artifacts / Test'); + }); + + test('propagates capabilities through dependencies and makes maintainer tools imply Rust', () => { + const taskMap = tasks( + { + target: 'repo:leaf', + tags: ['requires-maintainer-tools', 'requires-wasmer-llvm', 'requires-swift'], + toolchains: ['bun'], + }, + { target: 'repo:middle', tags: ['requires-android-sdk'], deps: [{ target: 'repo:leaf' }] }, + { target: 'repo:root', tags: [], deps: ['repo:middle'] }, + ); + + assert.deepEqual(taskCapabilities(taskMap.get('repo:root'), taskMap), { + requires_rust: true, + requires_maintainer_tools: true, + requires_android_sdk: true, + requires_apple: false, + requires_swift: true, + requires_wasmer_llvm: true, + requires_workspace: true, + }); + }); + + test('fails closed for incomplete or cyclic dependency metadata', () => { + const incomplete = tasks({ target: 'repo:root', deps: ['repo:missing'] }); + assert.throws(() => taskCapabilities(incomplete.get('repo:root'), incomplete), /repo:missing/u); + + const cyclic = tasks( + { target: 'repo:first', deps: ['repo:second'] }, + { target: 'repo:second', deps: ['repo:first'] }, + ); + assert.throws(() => taskCapabilities(cyclic.get('repo:first'), cyclic), /dependency cycle/u); + }); + + test('creates bounded groups with one setup profile per job', () => { + const taskMap = tasks( + ...Array.from({ length: 9 }, (_, index) => ({ target: `plain:${index}`, tags: [] })), + { target: 'rust:first', tags: ['requires-rust'] }, + { target: 'rust:second', tags: ['requires-rust'] }, + { target: 'android:check', tags: ['requires-android-sdk'] }, + { target: 'apple:check', tags: ['requires-apple'] }, + { target: 'workspace:check', tags: [], toolchains: ['bun'] }, + { target: 'aot:check', tags: ['requires-wasmer-llvm'] }, + ); + const targets = [...taskMap.values()].map((task) => matrixTarget(task, 'deep', taskMap)); + const groups = groupTargets(targets, { maxTargets: 4 }); + + assert.deepEqual( + groups.map(({ target_count }) => target_count), + [1, 1, 1, 4, 4, 1, 2, 1], + ); + assert.equal(groups[3].label, 'Plain / 0 + Plain / 1 + Plain / 2 + Plain / 3'); + assert.equal(groups.filter(({ requires_rust }) => requires_rust).length, 1); + assert.equal(groups.filter(({ requires_android_sdk }) => requires_android_sdk).length, 1); + assert.equal(groups.filter(({ requires_apple }) => requires_apple).length, 1); + assert.equal(groups.filter(({ requires_workspace }) => requires_workspace).length, 1); + assert.equal(groups.filter(({ requires_wasmer_llvm }) => requires_wasmer_llvm).length, 1); + assert.equal(groups.find(({ requires_apple }) => requires_apple).runner, 'macos-26'); + const selected = groups.flatMap(({ targets_json }) => + JSON.parse(targets_json).include.map(({ target }) => target), + ); + assert.deepEqual(selected.sort(), [...taskMap.keys()].sort()); + }); + + test('rejects duplicate targets and invalid shard limits', () => { + const row = { + target: 'repo:check', + upstream: 'deep', + requires_rust: false, + requires_maintainer_tools: false, + requires_android_sdk: false, + requires_apple: false, + requires_wasmer_llvm: false, + requires_workspace: false, + }; + assert.throws(() => groupTargets([row, row]), /duplicate/u); + assert.throws(() => groupTargets([row], { maxTargets: 0 }), /positive integer/u); + }); +}); diff --git a/.github/scripts/normalize-release-please-pr.mjs b/.github/scripts/normalize-release-please-pr.mjs deleted file mode 100644 index e792495d3..000000000 --- a/.github/scripts/normalize-release-please-pr.mjs +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env bun - -import { readFileSync } from "node:fs"; -import process from "node:process"; - -import { captureCommandOutput } from "../../tools/dev/capture-command-output.mjs"; -import releaseBot from "../../tools/release/release-bot.json" with { type: "json" }; - -const TOOL = "normalize-release-please-pr.mjs"; -const CANONICAL_REPOSITORY = "f0rr0/oliphaunt"; -const MAIN_BRANCH = "main"; -const RELEASE_BRANCH = "release-please--branches--main"; -const FULL_SHA = /^[0-9a-f]{40}$/u; -const POSITIVE_INTEGER = /^[1-9][0-9]*$/u; -const SAFE_REMOTE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/u; - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function run( - command, - args, - { allowEmptyOutput = false, cwd = process.cwd(), check = true, stdoutTerminator = undefined } = {}, -) { - const result = captureCommandOutput(command, args, { - allowEmptyOutput, - cwd, - label: `${command} ${args.join(" ")}`, - stdoutTerminator, - }); - if (result.error !== undefined) fail(`${command} failed: ${result.error.message}`); - if (check && result.status !== 0) { - const detail = (result.stderr || result.stdout || "").trim(); - fail(`${command} ${args.join(" ")} failed${detail ? `: ${detail}` : ""}`); - } - return result; -} - -function git(args, options = {}) { - return run("git", args, options); -} - -function gitText(args, options = {}) { - return git(args, options).stdout.trimEnd(); -} - -function parseArgs(argv) { - const command = argv[0]; - if (!new Set(["normalize", "push"]).has(command)) { - fail("usage: normalize-release-please-pr.mjs --pr-number N --observed-pr-number N --base main --head release-please--branches--main --head-sha SHA --head-repository f0rr0/oliphaunt --cross-repository false --state OPEN --title TITLE --main-sha SHA [--remote origin]"); - } - const values = { command, remote: "origin" }; - const known = new Set([ - "--pr-number", - "--observed-pr-number", - "--base", - "--head", - "--head-sha", - "--head-repository", - "--cross-repository", - "--state", - "--title", - "--main-sha", - "--remote", - ]); - for (let index = 1; index < argv.length; index += 2) { - const flag = argv[index]; - const value = argv[index + 1]; - if (!known.has(flag) || value === undefined) fail(`unknown or incomplete argument ${flag ?? ""}`); - const key = flag.slice(2).replaceAll(/-([a-z])/gu, (_match, letter) => letter.toUpperCase()); - if (Object.hasOwn(values, key) && key !== "remote") fail(`${flag} must be supplied exactly once`); - values[key] = value; - } - for (const key of [ - "prNumber", - "observedPrNumber", - "base", - "head", - "headSha", - "headRepository", - "crossRepository", - "state", - "title", - "mainSha", - ]) { - if (typeof values[key] !== "string" || values[key].length === 0) fail(`--${key.replace(/[A-Z]/gu, (letter) => `-${letter.toLowerCase()}`)} is required`); - } - return values; -} - -function expectedTitle(repo, base) { - let config; - try { - config = JSON.parse(readFileSync(`${repo}/release-please-config.json`, "utf8")); - } catch (cause) { - fail(`release-please-config.json is unreadable: ${cause.message}`); - } - const pattern = config?.["group-pull-request-title-pattern"]; - if (typeof pattern !== "string" || pattern.length === 0) { - fail("release-please-config.json must define group-pull-request-title-pattern"); - } - const title = pattern.replaceAll("${branch}", base); - if (title.includes("${") || !/^chore\(release\): .+/u.test(title) || /[\r\n]/u.test(title)) { - fail("group-pull-request-title-pattern must render one conventional release title using only ${branch}"); - } - return title; -} - -function validateIdentity(args, repo) { - if (!POSITIVE_INTEGER.test(args.prNumber) || !POSITIVE_INTEGER.test(args.observedPrNumber)) { - fail("release PR numbers must be positive integers"); - } - if (args.prNumber !== args.observedPrNumber) { - fail(`release PR identity changed: requested #${args.prNumber}, observed #${args.observedPrNumber}`); - } - if (args.base !== MAIN_BRANCH) fail(`release PR base must be ${MAIN_BRANCH}, got ${args.base}`); - if (args.head !== RELEASE_BRANCH) fail(`release PR head must be ${RELEASE_BRANCH}, got ${args.head}`); - if (args.headRepository !== CANONICAL_REPOSITORY) { - fail(`release PR head repository must be ${CANONICAL_REPOSITORY}, got ${args.headRepository}`); - } - if (args.crossRepository !== "false") fail("release PR must not be cross-repository"); - if (args.state !== "OPEN") fail(`release PR must be OPEN, got ${args.state}`); - if (!FULL_SHA.test(args.headSha) || !FULL_SHA.test(args.mainSha)) { - fail("release PR head and main identities must be lowercase full commit SHAs"); - } - if (!SAFE_REMOTE.test(args.remote)) fail(`unsafe Git remote name ${JSON.stringify(args.remote)}`); - const title = expectedTitle(repo, args.base); - if (args.title !== title) fail(`release PR title must be ${JSON.stringify(title)}, got ${JSON.stringify(args.title)}`); - return title; -} - -function requireClean(repo) { - const status = gitText(["status", "--porcelain", "-z", "--untracked-files=all"], { - allowEmptyOutput: true, - cwd: repo, - stdoutTerminator: "\0", - }); - if (status !== "") fail(`working tree must be clean before release PR normalization or push: ${status}`); -} - -function requireCommit(repo, ref, expected, context) { - const actual = gitText(["rev-parse", "--verify", `${ref}^{commit}`], { cwd: repo }); - if (actual !== expected) fail(`${context} is ${actual}, expected ${expected}`); - return actual; -} - -function releaseRangeShape(repo, mainSha, headRef, title) { - if (git(["merge-base", "--is-ancestor", mainSha, headRef], { cwd: repo, check: false }).status !== 0) { - fail(`release PR head is not descended from exact main ${mainSha}`); - } - const countText = gitText(["rev-list", "--count", `${mainSha}..${headRef}`], { cwd: repo }); - const count = Number(countText); - if (!Number.isSafeInteger(count) || count < 1) fail("release PR must contain at least one commit above exact main"); - const merges = gitText(["rev-list", "--merges", `${mainSha}..${headRef}`], { - allowEmptyOutput: true, - cwd: repo, - stdoutTerminator: "\n", - }); - if (merges !== "") fail("release PR history must be linear and contain no merge commits"); - const subjects = gitText(["log", "-z", "--format=%s", `${mainSha}..${headRef}`], { - cwd: repo, - stdoutTerminator: "\0", - }).split("\0").filter(Boolean); - if (subjects.length !== count || subjects.some((subject) => subject !== title)) { - fail(`every generated release PR chunk must use exact title ${JSON.stringify(title)}`); - } - const mainTree = gitText(["rev-parse", `${mainSha}^{tree}`], { cwd: repo }); - const headTree = gitText(["rev-parse", `${headRef}^{tree}`], { cwd: repo }); - if (mainTree === headTree) fail("release PR tree must differ from exact main"); - return { count, headTree }; -} - -function mergeBase(repo, left, right) { - const result = git(["merge-base", left, right], { cwd: repo, check: false }); - const base = result.stdout.trimEnd(); - if (result.status !== 0 || !FULL_SHA.test(base)) { - fail("release PR head does not share canonical main history"); - } - return base; -} - -function normalize(args, repo) { - const title = validateIdentity(args, repo); - requireClean(repo); - const mainRemoteRef = `refs/remotes/${args.remote}/${MAIN_BRANCH}`; - const headRemoteRef = `refs/remotes/${args.remote}/${RELEASE_BRANCH}`; - git(["fetch", "--no-tags", args.remote, `+refs/heads/${MAIN_BRANCH}:${mainRemoteRef}`], { cwd: repo }); - git(["fetch", "--no-tags", args.remote, `+refs/heads/${RELEASE_BRANCH}:${headRemoteRef}`], { cwd: repo }); - requireCommit(repo, mainRemoteRef, args.mainSha, "current remote main"); - requireCommit(repo, headRemoteRef, args.headSha, "inspected release PR head"); - const baseSha = mergeBase(repo, args.mainSha, headRemoteRef); - releaseRangeShape(repo, baseSha, headRemoteRef, title); - - git(["switch", "-C", RELEASE_BRANCH, headRemoteRef], { cwd: repo }); - let normalized = false; - if (baseSha !== args.mainSha) { - git([ - "-c", `user.name=${releaseBot.name}`, - "-c", `user.email=${releaseBot.email}`, - "rebase", "--onto", args.mainSha, baseSha, - ], { cwd: repo }); - normalized = true; - } - const generatedTree = gitText(["rev-parse", "HEAD^{tree}"], { cwd: repo }); - const directParent = gitText(["rev-parse", "HEAD^"], { cwd: repo, check: false }); - const count = Number(gitText(["rev-list", "--count", `${args.mainSha}..HEAD`], { cwd: repo })); - if (count !== 1 || directParent !== args.mainSha) { - git(["reset", "--soft", args.mainSha], { cwd: repo }); - if (git(["diff", "--cached", "--quiet", "--exit-code"], { cwd: repo, check: false }).status === 0) { - fail("release PR normalization produced no staged tree change"); - } - git([ - "-c", `user.name=${releaseBot.name}`, - "-c", `user.email=${releaseBot.email}`, - "commit", "-m", title, - ], { cwd: repo }); - normalized = true; - } - - const localShape = releaseRangeShape(repo, args.mainSha, "HEAD", title); - if (localShape.count !== 1 || gitText(["rev-parse", "HEAD^"], { cwd: repo }) !== args.mainSha) { - fail("normalized release PR must be exactly one commit above exact main"); - } - if (localShape.headTree !== generatedTree) fail("normalization changed the generated release PR tree"); - requireClean(repo); - console.log(`release PR #${args.prNumber} checked out at ${gitText(["rev-parse", "HEAD"], { cwd: repo })}; normalized=${normalized}`); -} - -function remoteRefSha(repo, remote, ref) { - const output = gitText(["ls-remote", "--heads", remote, ref], { - cwd: repo, - stdoutTerminator: "\n", - }); - const rows = output.split(/\r?\n/u).filter(Boolean); - if (rows.length !== 1) fail(`expected exactly one remote ref ${ref}; found ${rows.length}`); - const [sha, observedRef, ...extra] = rows[0].split(/\s+/u); - if (!FULL_SHA.test(sha) || observedRef !== ref || extra.length !== 0) fail(`remote ref ${ref} returned malformed metadata`); - return sha; -} - -function push(args, repo) { - const title = validateIdentity(args, repo); - requireClean(repo); - const branch = gitText(["branch", "--show-current"], { cwd: repo }); - if (branch !== RELEASE_BRANCH) fail(`local branch must be ${RELEASE_BRANCH}, got ${branch || ""}`); - const localShape = releaseRangeShape(repo, args.mainSha, "HEAD", title); - if (localShape.count !== 1 || gitText(["rev-parse", "HEAD^"], { cwd: repo }) !== args.mainSha) { - fail("release PR push requires exactly one local commit above exact main"); - } - const remoteMain = remoteRefSha(repo, args.remote, `refs/heads/${MAIN_BRANCH}`); - if (remoteMain !== args.mainSha) fail(`main moved before release PR push: ${remoteMain}, expected ${args.mainSha}`); - const localHead = gitText(["rev-parse", "HEAD"], { cwd: repo }); - git([ - "push", - `--force-with-lease=refs/heads/${RELEASE_BRANCH}:${args.headSha}`, - args.remote, - `HEAD:refs/heads/${RELEASE_BRANCH}`, - ], { cwd: repo }); - const remoteHead = remoteRefSha(repo, args.remote, `refs/heads/${RELEASE_BRANCH}`); - if (remoteHead !== localHead) fail(`release PR push produced ${remoteHead}, expected ${localHead}`); - console.log(`release PR #${args.prNumber} pushed as one exact release commit ${localHead}`); -} - -export function main(argv, { repo = process.cwd() } = {}) { - const args = parseArgs(argv); - if (args.command === "normalize") normalize(args, repo); - else push(args, repo); -} - -if (import.meta.main) { - try { - main(Bun.argv.slice(2)); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/.github/scripts/prepare-linux-apt.sh b/.github/scripts/prepare-linux-apt.sh index ab1e04e4a..92a785614 100755 --- a/.github/scripts/prepare-linux-apt.sh +++ b/.github/scripts/prepare-linux-apt.sh @@ -8,18 +8,18 @@ fi disabled_any=0 for file in /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do [ -f "$file" ] || continue - if ! grep -q "packages.microsoft.com" "$file"; then + if ! grep -Eq 'packages[.]microsoft[.]com|dl[.]google[.]com/linux/chrome(-stable)?/deb' "$file"; then continue fi disabled_any=1 if [ "$file" = "/etc/apt/sources.list" ]; then - sudo sed -i.bak '/packages\.microsoft\.com/s/^/# disabled by oliphaunt CI: /' "$file" + sudo sed -E -i.bak '/packages[.]microsoft[.]com|dl[.]google[.]com\/linux\/chrome(-stable)?\/deb/s/^/# disabled by oliphaunt CI: /' "$file" else sudo mv "$file" "$file.disabled" fi done if [ "$disabled_any" = "1" ]; then - echo "Disabled preinstalled packages.microsoft.com apt sources before apt-get update" + echo "Disabled unrelated preinstalled Microsoft and Chrome apt sources before apt-get update" fi diff --git a/.github/scripts/publish-release-pr.sh b/.github/scripts/publish-release-pr.sh new file mode 100644 index 000000000..c7310a46f --- /dev/null +++ b/.github/scripts/publish-release-pr.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -euo pipefail +fail() { + echo "publish-release-pr.sh: $*" >&2 + exit 1 +} +[[ $# == 1 ]] || fail 'expected candidate metadata directory' +metadata="$1" +branch=release-please--branches--main +source_sha="${GITHUB_SHA:?exact workflow source is required}" +[[ "${GITHUB_REPOSITORY:-}" == f0rr0/oliphaunt ]] || fail 'canonical repository is required' +[[ "$(cat "$metadata/required")" == true ]] || exit 0 +title="$(cat "$metadata/title")" +[[ "$title" == 'chore(release): prepare main releases' ]] || fail 'unexpected release title' +[[ -z "$(git status --porcelain --untracked-files=all)" ]] || fail 'candidate checkout is dirty' +[[ "$(git rev-parse HEAD^)" == "$source_sha" ]] || fail 'candidate parent is not the exact workflow source' +bash .github/scripts/require-current-main.sh "$source_sha" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +gh auth setup-git +gh pr list --base main --head "$branch" --state open --json number,headRefOid,headRepository,isCrossRepository,title,labels >"$scratch/pr.json" +count="$(jq length "$scratch/pr.json")" +[[ "$count" == 0 || "$count" == 1 ]] || fail 'ambiguous generated release PR' +if [[ "$count" == 1 ]]; then + jq -e --arg title "$title" --arg repo "$GITHUB_REPOSITORY" '.[0] | .title == $title and .headRepository.nameWithOwner == $repo and .isCrossRepository == false and any(.labels[]; .name == "autorelease: pending")' "$scratch/pr.json" >/dev/null || fail 'existing PR is not the canonical generated candidate' +fi +git ls-remote --heads origin "refs/heads/$branch" >"$scratch/remote" +old_sha='' +if [[ -s "$scratch/remote" ]]; then + [[ "$(wc -l <"$scratch/remote" | tr -d '[:space:]')" == 1 ]] || fail 'ambiguous generated branch' + read -r old_sha _ <"$scratch/remote" + [[ "$old_sha" =~ ^[0-9a-f]{40}$ ]] || fail 'invalid remote branch SHA' + git fetch --no-tags origin "$old_sha" + base="$(git merge-base "$source_sha" "$old_sha")" + [[ -z "$(git rev-list --merges "$base..$old_sha")" ]] || fail 'generated branch contains merge commits' + git log --format=%s "$base..$old_sha" >"$scratch/subjects" + while IFS= read -r subject; do [[ "$subject" == "$title" ]] || fail 'generated branch contains unrelated commits'; done <"$scratch/subjects" +fi +if [[ "$count" == 1 ]]; then + [[ "$(jq -r '.[0].headRefOid' "$scratch/pr.json")" == "$old_sha" ]] || fail 'PR head changed during preparation' +fi +unchanged=false +if [[ -n "$old_sha" && "$(git rev-parse "$old_sha^{tree}")" == "$(git rev-parse 'HEAD^{tree}')" && "$(git rev-parse "$old_sha^")" == "$source_sha" ]]; then + unchanged=true + expected_sha="$old_sha" +else + bash .github/scripts/require-current-main.sh "$source_sha" + git push "--force-with-lease=refs/heads/$branch:$old_sha" origin "HEAD:refs/heads/$branch" + expected_sha="$(git rev-parse HEAD)" +fi +bash .github/scripts/require-current-main.sh "$source_sha" +git ls-remote --heads origin "refs/heads/$branch" > "$scratch/published" +[[ "$(wc -l < "$scratch/published" | tr -d '[:space:]')" == 1 ]] || fail 'published branch is missing or ambiguous' +read -r published_sha _ < "$scratch/published" +[[ "$published_sha" == "$expected_sha" ]] || fail 'published branch changed before PR reconciliation' +if [[ "$count" == 0 ]]; then + gh pr create --base main --head "$branch" --title "$title" --label 'autorelease: pending' --body-file "$metadata/body.md" +else + number="$(jq -r '.[0].number' "$scratch/pr.json")" + gh pr edit "$number" --title "$title" --body-file "$metadata/body.md" +fi +echo "Release PR prepared; unchanged candidate tree=$unchanged" diff --git a/.github/scripts/reclaim-android-mobile-build-disk.mjs b/.github/scripts/reclaim-android-mobile-build-disk.mjs deleted file mode 100644 index 822b28f6a..000000000 --- a/.github/scripts/reclaim-android-mobile-build-disk.mjs +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bun -import { existsSync } from "node:fs"; -import process from "node:process"; -import { spawnSync } from "node:child_process"; - -const WORKSPACE = process.env.GITHUB_WORKSPACE || "."; - -function fail(message) { - console.error(`reclaim-android-mobile-build-disk.mjs: ${message}`); - process.exit(1); -} - -function run(command, args) { - const result = spawnSync(command, args, { stdio: "inherit" }); - if (result.error) { - fail(result.error.message); - } - if (result.status !== 0) { - process.exit(result.status ?? 1); - } -} - -if (process.env.RUNNER_OS !== "Linux") { - process.exit(0); -} - -console.log("Disk before Android mobile cleanup:"); -run("df", ["-h", WORKSPACE]); - -run("sudo", [ - "rm", - "-rf", - "/opt/ghc", - "/opt/hostedtoolcache/CodeQL", - "/usr/local/share/boost", - "/usr/share/dotnet", -]); - -const androidHome = process.env.ANDROID_HOME; -if (androidHome && existsSync(androidHome)) { - run("sudo", [ - "rm", - "-rf", - `${androidHome}/emulator`, - `${androidHome}/system-images`, - ]); -} - -console.log("Disk after Android mobile cleanup:"); -run("df", ["-h", WORKSPACE]); diff --git a/.github/scripts/reclaim-android-mobile-build-disk.sh b/.github/scripts/reclaim-android-mobile-build-disk.sh new file mode 100644 index 000000000..f526fc437 --- /dev/null +++ b/.github/scripts/reclaim-android-mobile-build-disk.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +[ "${RUNNER_OS:-}" = Linux ] || exit 0 +workspace="${GITHUB_WORKSPACE:-.}" +printf 'Disk before Android mobile cleanup:\n' +df -h "$workspace" +sudo rm -rf /opt/ghc /opt/hostedtoolcache/CodeQL /usr/local/share/boost /usr/share/dotnet +if [ -n "${ANDROID_HOME:-}" ] && [ -d "$ANDROID_HOME" ]; then + sudo rm -rf "$ANDROID_HOME/emulator" "$ANDROID_HOME/system-images" +fi +printf 'Disk after Android mobile cleanup:\n' +df -h "$workspace" diff --git a/.github/scripts/registry-bootstrap-ledger-state.mjs b/.github/scripts/registry-bootstrap-ledger-state.mjs deleted file mode 100644 index 1c6b851ef..000000000 --- a/.github/scripts/registry-bootstrap-ledger-state.mjs +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env bun -import { appendFileSync } from "node:fs"; -import path from "node:path"; -import process from "node:process"; - -import { loadPublicationLock, lockedCarriers } from "../../tools/release/publication-lock.mjs"; -import { captureCommandOutput } from "../../tools/dev/capture-command-output.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function fail(message) { - throw new Error(`registry-bootstrap-ledger-state: ${message}`); -} - -function run(command, args, { check = true } = {}) { - const result = captureCommandOutput(command, args, { - cwd: ROOT, - env: process.env, - label: `${command} ${args.join(" ")}`, - }); - if (result.error !== undefined || (check && result.status !== 0)) { - fail(`${command} ${args.join(" ")} failed: ${(result.stderr || result.stdout || result.error?.message || "").trim()}`); - } - return { status: result.status, stdout: result.stdout.trim() }; -} - -function parseProducts(raw) { - let value; - try { - value = JSON.parse(raw); - } catch (cause) { - fail(`PRODUCTS_JSON is invalid: ${cause.message}`); - } - if (!Array.isArray(value) || value.length === 0 || value.some((item) => typeof item !== "string" || item.length === 0)) { - fail("PRODUCTS_JSON must be a non-empty product string list"); - } - return [...new Set(value)].sort(); -} - -export function classifyLedgerRequirement(rows) { - const requiring = rows - .filter((row) => row.queryState !== "skipped-exact-tag" && row.published > 0 && row.tagState === "missing") - .map(({ product, ecosystem, published }) => ({ product, ecosystem, published })) - .sort((left, right) => compareText(`${left.product}:${left.ecosystem}`, `${right.product}:${right.ecosystem}`)); - const conflicting = rows.filter((row) => row.tagState === "wrong"); - if (conflicting.length > 0) { - fail(`current product tag points at another commit: ${conflicting.map(({ product }) => product).join(", ")}`); - } - return { needsLedger: requiring.length > 0, requiring }; -} - -function query(lockFile, product, ecosystem) { - const registryKind = ecosystem === "cargo" ? "crates" : "npm"; - const result = run(process.execPath, [ - "tools/release/check_registry_publication.mjs", - "query-product-publication", - "--product", product, - "--registry-kind", registryKind, - "--publication-lock", lockFile, - ]); - try { - return JSON.parse(result.stdout); - } catch (cause) { - fail(`registry query returned invalid JSON for ${product}/${ecosystem}: ${cause.message}`); - } -} - -function tagState(product, version, headCommit) { - const result = run("git", ["rev-parse", "--verify", "--quiet", `refs/tags/${product}-v${version}^{commit}`], { check: false }); - if (result.status !== 0) return "missing"; - return result.stdout === headCommit ? "exact" : "wrong"; -} - -export function collectLedgerRows({ lock, lockFile, products, headCommit }, { - carriersFor = lockedCarriers, - queryPublication = query, - resolveTagState = tagState, -} = {}) { - const rows = []; - for (const product of products) { - const productRow = lock.products.find((entry) => entry.id === product); - if (productRow === undefined) fail(`publication lock omits selected product ${product}`); - const currentTagState = resolveTagState(product, productRow.version, headCommit); - if (currentTagState === "wrong") { - fail(`current product tag points at another commit: ${product}`); - } - if (currentTagState !== "exact" && currentTagState !== "missing") { - fail(`product tag state for ${product} is invalid: ${JSON.stringify(currentTagState)}`); - } - for (const ecosystem of ["cargo", "npm"]) { - const carriers = carriersFor(lock, { product, ecosystem }); - if (carriers.length === 0) continue; - if (currentTagState === "exact") { - rows.push({ - product, - ecosystem, - published: null, - missing: null, - queryState: "skipped-exact-tag", - tagState: currentTagState, - }); - continue; - } - if (typeof lockFile !== "string" || lockFile.length === 0) { - fail("publication lock path is required before a registry query"); - } - const result = queryPublication(lockFile, product, ecosystem); - if (!Array.isArray(result.published) || !Array.isArray(result.missing)) { - fail(`registry query returned invalid publication lists for ${product}/${ecosystem}`); - } - rows.push({ - product, - ecosystem, - published: result.published.length, - missing: result.missing.length, - queryState: "queried", - tagState: currentTagState, - }); - } - } - return rows; -} - -function main() { - const lockFile = path.resolve(ROOT, process.env.PUBLICATION_LOCK_PATH || "target/release/publication-lock.json"); - const products = parseProducts(process.env.PRODUCTS_JSON || ""); - const headCommit = run("git", ["rev-parse", `${process.env.RELEASE_HEAD_SHA || "HEAD"}^{commit}`]).stdout; - const lock = loadPublicationLock(lockFile); - if (lock.source.commit !== headCommit) { - fail(`publication lock source ${lock.source.commit} does not match ${headCommit}`); - } - const rows = collectLedgerRows({ lock, lockFile, products, headCommit }); - const state = classifyLedgerRequirement(rows); - const output = process.env.GITHUB_OUTPUT; - if (output) { - appendFileSync(output, `needs_ledger=${String(state.needsLedger)}\n`); - appendFileSync(output, `state_json=${JSON.stringify(rows)}\n`); - } - console.log(JSON.stringify({ ...state, rows }, null, 2)); -} - -if (import.meta.main) { - try { - main(); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/.github/scripts/registry-bootstrap-ledger-state.mts b/.github/scripts/registry-bootstrap-ledger-state.mts new file mode 100644 index 000000000..a91822787 --- /dev/null +++ b/.github/scripts/registry-bootstrap-ledger-state.mts @@ -0,0 +1,158 @@ +#!/usr/bin/env bun +import { appendFileSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { parseTagRefs } from '../../tools/release/git-tag-state.mts'; +export { parseTagRefs } from '../../tools/release/git-tag-state.mts'; + +import { loadPublicationLock, lockedCarriers } from '../../tools/release/publication-lock.mts'; +import { + productRegistryPackagesFromLock, + queryRegistryPackages, +} from '../../tools/release/check_registry_publication.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function fail(message) { + throw new Error(`registry-bootstrap-ledger-state: ${message}`); +} + +function parseProducts(raw) { + let value; + try { + value = JSON.parse(raw); + } catch (cause) { + fail(`PRODUCTS_JSON is invalid: ${cause.message}`); + } + if ( + !Array.isArray(value) || + value.length === 0 || + value.some((item) => typeof item !== 'string' || item.length === 0) + ) { + fail('PRODUCTS_JSON must be a non-empty product string list'); + } + return [...new Set(value)].sort(); +} + +export function classifyLedgerRequirement(rows) { + const requiring = rows + .filter( + (row) => + row.queryState !== 'skipped-exact-tag' && row.published > 0 && row.tagState === 'missing', + ) + .map(({ product, ecosystem, published }) => ({ product, ecosystem, published })) + .sort((left, right) => + compareText(`${left.product}:${left.ecosystem}`, `${right.product}:${right.ecosystem}`), + ); + const conflicting = rows.filter((row) => row.tagState === 'wrong'); + if (conflicting.length > 0) { + fail( + `current product tag points at another commit: ${conflicting.map(({ product }) => product).join(', ')}`, + ); + } + return { needsLedger: requiring.length > 0, requiring }; +} + +function query(lock, product, ecosystem) { + return queryRegistryPackages( + productRegistryPackagesFromLock(lock, product, { + registryKind: ecosystem === 'cargo' ? 'crates' : 'npm', + }), + ); +} + +export function tagState(product, version, headCommit, tags) { + const ref = `refs/tags/${product}-v${version}`; + const commit = tags.get(ref + '^{}') ?? tags.get(ref); + return commit === undefined ? 'missing' : commit === headCommit ? 'exact' : 'wrong'; +} + +export async function collectLedgerRows( + { lock, products, headCommit, tags }, + { + carriersFor = lockedCarriers, + queryPublication = query, + resolveTagState = (product, version, headCommit) => + tagState(product, version, headCommit, tags), + } = {}, +) { + const rows = []; + for (const product of products) { + const productRow = lock.products.find((entry) => entry.id === product); + if (productRow === undefined) fail(`publication lock omits selected product ${product}`); + const currentTagState = resolveTagState(product, productRow.version, headCommit); + if (currentTagState === 'wrong') { + fail(`current product tag points at another commit: ${product}`); + } + if (currentTagState !== 'exact' && currentTagState !== 'missing') { + fail(`product tag state for ${product} is invalid: ${JSON.stringify(currentTagState)}`); + } + for (const ecosystem of ['cargo', 'npm']) { + const carriers = carriersFor(lock, { product, ecosystem }); + if (carriers.length === 0) continue; + if (currentTagState === 'exact') { + rows.push({ + product, + ecosystem, + published: null, + missing: null, + queryState: 'skipped-exact-tag', + tagState: currentTagState, + }); + continue; + } + const result = await queryPublication(lock, product, ecosystem); + if (!Array.isArray(result.published) || !Array.isArray(result.missing)) { + fail(`registry query returned invalid publication lists for ${product}/${ecosystem}`); + } + rows.push({ + product, + ecosystem, + published: result.published.length, + missing: result.missing.length, + queryState: 'queried', + tagState: currentTagState, + }); + } + } + return rows; +} + +async function main() { + const lockFile = path.resolve( + ROOT, + process.env.PUBLICATION_LOCK_PATH || 'target/release/publication-lock.json', + ); + const products = parseProducts(process.env.PRODUCTS_JSON || ''); + const headCommit = process.env.RELEASE_HEAD_COMMIT; + if (!/^[0-9a-f]{40}$/u.test(headCommit ?? '')) + fail('RELEASE_HEAD_COMMIT must be a full commit SHA'); + const refsFile = process.argv[2]; + if (!refsFile) fail('run registry-bootstrap-ledger-state.sh to read Git references'); + const tags = parseTagRefs(readFileSync(refsFile, 'utf8')); + const lock = loadPublicationLock(lockFile); + if (lock.source.commit !== headCommit) { + fail(`publication lock source ${lock.source.commit} does not match ${headCommit}`); + } + const rows = await collectLedgerRows({ lock, products, headCommit, tags }); + const state = classifyLedgerRequirement(rows); + const output = process.env.GITHUB_OUTPUT; + if (output) { + appendFileSync(output, `needs_ledger=${String(state.needsLedger)}\n`); + appendFileSync(output, `state_json=${JSON.stringify(rows)}\n`); + } + console.log(JSON.stringify({ ...state, rows }, null, 2)); +} + +if (import.meta.main) { + try { + await main(); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/.github/scripts/registry-bootstrap-ledger-state.sh b/.github/scripts/registry-bootstrap-ledger-state.sh new file mode 100644 index 000000000..382ceb463 --- /dev/null +++ b/.github/scripts/registry-bootstrap-ledger-state.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +RELEASE_HEAD_COMMIT="$(git rev-parse --verify --end-of-options "${RELEASE_HEAD_SHA:-HEAD}^{commit}")" +export RELEASE_HEAD_COMMIT +refs="$(mktemp)" +trap 'rm -f "$refs"' EXIT +if git show-ref --tags --dereference > "$refs"; then + : +else + status=$? + [[ "$status" == 1 ]] || exit "$status" +fi +bun .github/scripts/registry-bootstrap-ledger-state.mts "$refs" diff --git a/.github/scripts/release-candidate-lib.mjs b/.github/scripts/release-candidate-lib.mjs deleted file mode 100644 index 441f55604..000000000 --- a/.github/scripts/release-candidate-lib.mjs +++ /dev/null @@ -1,305 +0,0 @@ -import { createHash } from "node:crypto"; -import { - existsSync, - readFileSync, - readdirSync, -} from "node:fs"; -import path from "node:path"; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function assert(condition, message) { - if (!condition) { - throw new Error(message); - } -} - -function canonicalValue(value) { - if (Array.isArray(value)) { - return value.map(canonicalValue); - } - if (value !== null && typeof value === "object") { - return Object.fromEntries( - Object.keys(value).sort().map((key) => [key, canonicalValue(value[key])]), - ); - } - return value; -} - -function sha256(value) { - return `sha256:${createHash("sha256").update(value).digest("hex")}`; -} - -function strictJson(file, context) { - let bytes; - try { - bytes = readFileSync(file); - } catch (error) { - throw new Error(`${context} cannot be read at ${file}: ${error.message}`); - } - let value; - try { - value = JSON.parse(bytes.toString("utf8")); - } catch (error) { - throw new Error(`${context} is not strict JSON at ${file}: ${error.message}`); - } - assert(value !== null && !Array.isArray(value) && typeof value === "object", `${context} must be a JSON object`); - return { bytes, value }; -} - -function sortedUniqueStrings(value, context) { - assert(Array.isArray(value), `${context} must be a string list`); - assert(value.every((item) => typeof item === "string" && item.length > 0), `${context} must contain non-empty strings`); - const sorted = [...new Set(value)].sort(); - assert(sorted.length === value.length, `${context} must not contain duplicates`); - assert(JSON.stringify(sorted) === JSON.stringify(value), `${context} must be canonically sorted`); - return sorted; -} - -function uniqueStrings(value, context) { - assert(Array.isArray(value), `${context} must be a string list`); - assert(value.every((item) => typeof item === "string" && item.length > 0), `${context} must contain non-empty strings`); - assert(new Set(value).size === value.length, `${context} must not contain duplicates`); - return value; -} - -export const FULL_PAYLOAD_QUALIFICATION_MODE = "full-payload"; - -function qualificationBinding(plan) { - const fields = [ - "qualification_mode", - "qualification_base_sha", - "qualification_head_sha", - ]; - const present = fields.map((field) => Object.hasOwn(plan, field)); - if (!present.some(Boolean)) return undefined; - assert(present.every(Boolean), "affected CI plan qualification binding is incomplete"); - const mode = plan.qualification_mode; - const baseSha = plan.qualification_base_sha; - const headSha = plan.qualification_head_sha; - assert(mode === FULL_PAYLOAD_QUALIFICATION_MODE, `affected CI plan qualification mode is invalid: ${mode}`); - assert(baseSha === null && headSha === null, "full-payload CI plan must not carry an affected range"); - return { mode, baseSha, headSha }; -} - -export function candidateQualificationMode(candidate) { - return candidate?.affectedPlan?.qualification?.mode ?? FULL_PAYLOAD_QUALIFICATION_MODE; -} - -export function affectedPlanBinding(planPath, wasixReleaseRegressionRequired) { - assert(typeof wasixReleaseRegressionRequired === "boolean", "WASIX release regression requirement must be boolean"); - const { value: plan } = strictJson(planPath, "affected CI plan"); - const jobs = sortedUniqueStrings(plan.jobs, "affected CI plan jobs"); - const projects = sortedUniqueStrings(plan.projects, "affected CI plan projects"); - const extensionPackageProducts = sortedUniqueStrings( - plan.extension_package_products ?? [], - "affected CI plan extension package products", - ); - const expectedRequirement = jobs.includes("liboliphaunt-wasix-runtime"); - assert( - wasixReleaseRegressionRequired === expectedRequirement, - `affected CI plan WASIX requirement mismatch: jobs imply ${expectedRequirement}, workflow reported ${wasixReleaseRegressionRequired}`, - ); - const qualification = qualificationBinding(plan); - const canonical = JSON.stringify(canonicalValue(plan)); - return { - digest: sha256(canonical), - jobs, - projects, - extensionPackageProducts, - wasixReleaseRegressionRequired, - ...(qualification === undefined ? {} : { qualification }), - }; -} - -function jsonFiles(root) { - assert(existsSync(root), `WASIX evidence artifact root does not exist: ${root}`); - const files = []; - const visit = (directory) => { - for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareText(left.name, right.name))) { - const file = path.join(directory, entry.name); - if (entry.isDirectory()) { - visit(file); - } else if (entry.isFile() && entry.name.endsWith(".json")) { - files.push(file); - } - } - }; - visit(root); - return files; -} - -function expectedPublicExtensions(catalogPath) { - const { value: catalog } = strictJson(catalogPath, "extension catalog"); - assert(Array.isArray(catalog.extensions), "extension catalog extensions must be a list"); - return catalog.extensions - .map((extension) => extension.id) - .sort(); -} - -function same(actual, expected, context) { - assert(actual === expected, `${context} mismatch: expected ${expected}, got ${actual}`); -} - -function positiveInteger(value, context) { - assert(Number.isSafeInteger(value) && value > 0, `${context} must be a positive safe integer`); -} - -function findEvidenceRun(root) { - const matches = []; - for (const file of jsonFiles(root)) { - let value; - try { - value = JSON.parse(readFileSync(file, "utf8")); - } catch { - continue; - } - if (value?.schema === "oliphaunt-extension-evidence-v1" && value?.evidenceTier === "wasix-full-lifecycle-v1") { - matches.push({ file, value, bytes: readFileSync(file) }); - } - } - assert(matches.length === 1, `WASIX evidence artifact must contain exactly one full-lifecycle run, found ${matches.length}`); - return matches[0]; -} - -export function wasixEvidenceBinding( - evidenceRoot, - { - repository, - workflow, - runId, - runAttempt, - sha, - tree, - catalogPath = "src/extensions/generated/extensions.catalog.json", - }, -) { - const expectedRunId = Number.parseInt(String(runId), 10); - positiveInteger(expectedRunId, "expected evidence runId"); - positiveInteger(runAttempt, "candidate runAttempt"); - const root = path.resolve(evidenceRoot); - const { file, value: evidence, bytes } = findEvidenceRun(root); - same(evidence.status, "passed", "WASIX evidence status"); - same(evidence.sourceCommit, sha, "WASIX evidence sourceCommit"); - same(evidence.sourceTree, tree, "WASIX evidence sourceTree"); - assert(/^sha256:[0-9a-f]{64}$/u.test(evidence.sourceDigest), "WASIX evidence sourceDigest must be SHA-256"); - uniqueStrings(evidence.sourceDigestInputs, "WASIX evidence sourceDigestInputs"); - same(evidence.github?.repository, repository, "WASIX evidence GitHub repository"); - same(evidence.github?.workflow, workflow, "WASIX evidence GitHub workflow"); - same(evidence.github?.runId, expectedRunId, "WASIX evidence GitHub runId"); - positiveInteger(evidence.github?.runAttempt, "WASIX evidence GitHub runAttempt"); - // A failed-job rerun preserves successful run-level artifacts from an - // earlier attempt. Accept that immutable evidence, but never future evidence. - assert( - evidence.github.runAttempt <= runAttempt, - `WASIX evidence GitHub runAttempt must not be newer than the candidate attempt: expected at most ${runAttempt}, got ${evidence.github.runAttempt}`, - ); - same(evidence.github?.job, "wasix-release-regression", "WASIX evidence GitHub job"); - - assert(Array.isArray(evidence.results) && evidence.results.length > 0, "WASIX evidence results must be non-empty"); - const extensions = []; - for (const result of evidence.results) { - assert(typeof result?.extension === "string" && result.extension.length > 0, "WASIX evidence result extension is invalid"); - same(result.postgresMajor, 18, `${result.extension} PostgreSQL major`); - same(result.artifactFamily, "wasix-runtime", `${result.extension} artifact family`); - same(result.platformTarget, "portable", `${result.extension} platform target`); - for (const mode of ["direct", "server", "restart", "dump-restore"]) { - same(result.runtimeModeStatuses?.[mode], "passed", `${result.extension} ${mode} status`); - } - extensions.push(result.extension); - } - extensions.sort(); - assert(new Set(extensions).size === extensions.length, "WASIX evidence results must not repeat extensions"); - const expectedExtensions = expectedPublicExtensions(catalogPath); - assert( - JSON.stringify(extensions) === JSON.stringify(expectedExtensions), - "WASIX evidence results must cover every and only public extension", - ); - - return { - artifact: "wasix-release-regression-evidence", - file: path.relative(root, file).split(path.sep).join("/"), - digest: sha256(bytes), - id: evidence.id, - sourceDigest: evidence.sourceDigest, - sourceCommit: evidence.sourceCommit, - sourceTree: evidence.sourceTree, - github: { - repository: evidence.github.repository, - workflow: evidence.github.workflow, - runId: evidence.github.runId, - runAttempt: evidence.github.runAttempt, - job: evidence.github.job, - }, - resultCount: extensions.length, - extensionsDigest: sha256(JSON.stringify(extensions)), - }; -} - -export function assertCandidateBindingShape(candidate) { - assert(candidate?.schemaVersion === 2, `release candidate schemaVersion must be 2, got ${candidate?.schemaVersion}`); - assert(candidate.affectedPlan !== null && typeof candidate.affectedPlan === "object", "release candidate affectedPlan is missing"); - assert(/^sha256:[0-9a-f]{64}$/u.test(candidate.affectedPlan.digest), "release candidate plan digest is invalid"); - const jobs = sortedUniqueStrings(candidate.affectedPlan.jobs, "release candidate affectedPlan.jobs"); - sortedUniqueStrings(candidate.affectedPlan.projects, "release candidate affectedPlan.projects"); - sortedUniqueStrings( - candidate.affectedPlan.extensionPackageProducts, - "release candidate affectedPlan.extensionPackageProducts", - ); - assert( - typeof candidate.affectedPlan.wasixReleaseRegressionRequired === "boolean", - "release candidate affectedPlan WASIX requirement must be boolean", - ); - assert( - candidate.affectedPlan.wasixReleaseRegressionRequired === jobs.includes("liboliphaunt-wasix-runtime"), - "release candidate affectedPlan WASIX requirement is inconsistent with selected jobs", - ); - const qualification = candidate.affectedPlan.qualification; - if (qualification !== undefined) { - assert( - qualification !== null && !Array.isArray(qualification) && typeof qualification === "object", - "release candidate affectedPlan qualification is invalid", - ); - assert( - JSON.stringify(Object.keys(qualification).sort()) - === JSON.stringify(["baseSha", "headSha", "mode"]), - "release candidate affectedPlan qualification fields are invalid", - ); - assert( - qualification.mode === FULL_PAYLOAD_QUALIFICATION_MODE, - "release candidate qualification mode is invalid", - ); - assert( - qualification.baseSha === null && qualification.headSha === null, - "full-payload release candidate must not carry an affected range", - ); - } - const requirements = candidate.evidenceRequirements; - assert(requirements !== null && typeof requirements === "object", "release candidate evidenceRequirements is missing"); - assert( - requirements.wasixReleaseRegression === candidate.affectedPlan.wasixReleaseRegressionRequired, - "release candidate WASIX evidence requirement is inconsistent with affected plan", - ); - const expectedArtifacts = requirements.wasixReleaseRegression ? ["wasix-release-regression-evidence"] : []; - assert( - JSON.stringify(requirements.artifacts) === JSON.stringify(expectedArtifacts), - "release candidate evidence artifact requirements are inconsistent", - ); - if (requirements.wasixReleaseRegression) { - assert(candidate.evidence?.wasixReleaseRegression !== null, "release candidate is missing required WASIX evidence binding"); - assert(/^sha256:[0-9a-f]{64}$/u.test(candidate.evidence.wasixReleaseRegression.digest), "release candidate WASIX evidence digest is invalid"); - positiveInteger(candidate.evidence.wasixReleaseRegression.github?.runId, "release candidate WASIX evidence runId"); - positiveInteger(candidate.evidence.wasixReleaseRegression.github?.runAttempt, "release candidate WASIX evidence runAttempt"); - } else { - assert(candidate.evidence?.wasixReleaseRegression === null, "release candidate carries WASIX evidence that its plan did not require"); - } -} - -export function assertBindingMatches(actual, expected, context) { - assert( - JSON.stringify(actual) === JSON.stringify(expected), - `${context} binding does not match the recomputed same-run content`, - ); -} diff --git a/.github/scripts/release-candidate-lib.mts b/.github/scripts/release-candidate-lib.mts new file mode 100644 index 000000000..5df2166f8 --- /dev/null +++ b/.github/scripts/release-candidate-lib.mts @@ -0,0 +1,491 @@ +import { createHash } from 'node:crypto'; +import { existsSync, readFileSync, readdirSync } from 'node:fs'; +import path from 'node:path'; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function assert(condition, message) { + if (!condition) { + throw new Error(message); + } +} + +function canonicalValue(value) { + if (Array.isArray(value)) { + return value.map(canonicalValue); + } + if (value !== null && typeof value === 'object') { + return Object.fromEntries( + Object.keys(value) + .sort() + .map((key) => [key, canonicalValue(value[key])]), + ); + } + return value; +} + +function sha256(value) { + return `sha256:${createHash('sha256').update(value).digest('hex')}`; +} + +function strictJson(file, context) { + let bytes; + try { + bytes = readFileSync(file); + } catch (error) { + throw new Error(`${context} cannot be read at ${file}: ${error.message}`); + } + let value; + try { + value = JSON.parse(bytes.toString('utf8')); + } catch (error) { + throw new Error(`${context} is not strict JSON at ${file}: ${error.message}`); + } + assert( + value !== null && !Array.isArray(value) && typeof value === 'object', + `${context} must be a JSON object`, + ); + return { bytes, value }; +} + +function sortedUniqueStrings(value, context) { + assert(Array.isArray(value), `${context} must be a string list`); + assert( + value.every((item) => typeof item === 'string' && item.length > 0), + `${context} must contain non-empty strings`, + ); + const sorted = [...new Set(value)].sort(); + assert(sorted.length === value.length, `${context} must not contain duplicates`); + assert(JSON.stringify(sorted) === JSON.stringify(value), `${context} must be canonically sorted`); + return sorted; +} + +function uniqueStrings(value, context) { + assert(Array.isArray(value), `${context} must be a string list`); + assert( + value.every((item) => typeof item === 'string' && item.length > 0), + `${context} must contain non-empty strings`, + ); + assert(new Set(value).size === value.length, `${context} must not contain duplicates`); + return value; +} + +export const FULL_PAYLOAD_QUALIFICATION_MODE = 'full-payload'; +export const PRODUCT_QUALIFICATION_MODE = 'selected-products'; + +export function qualificationRequestKey(sha, products) { + assert(/^[0-9a-f]{40}$/.test(sha ?? ''), 'qualification request requires an exact SHA'); + assert( + Array.isArray(products) && + products.length > 0 && + products.every((product) => typeof product === 'string' && product.length > 0) && + new Set(products).size === products.length, + 'qualification request requires unique non-empty products', + ); + return `${sha}-${createHash('sha256') + .update(JSON.stringify([...products].sort())) + .digest('hex')}`; +} + +function qualificationBinding(plan) { + const fields = ['qualification_mode', 'qualification_base_sha', 'qualification_head_sha']; + const present = fields.map((field) => Object.hasOwn(plan, field)); + if (!present.some(Boolean)) return undefined; + assert(present.every(Boolean), 'affected CI plan qualification binding is incomplete'); + const mode = plan.qualification_mode; + const baseSha = plan.qualification_base_sha; + const headSha = plan.qualification_head_sha; + assert( + [FULL_PAYLOAD_QUALIFICATION_MODE, PRODUCT_QUALIFICATION_MODE].includes(mode), + `affected CI plan qualification mode is invalid: ${mode}`, + ); + if (mode === PRODUCT_QUALIFICATION_MODE) { + assert( + baseSha === null && /^[0-9a-f]{40}$/.test(headSha ?? ''), + 'selected-products plan requires exact candidate SHA without an affected base', + ); + const products = sortedUniqueStrings(plan.qualification_products, 'qualification products'); + const tasks = sortedUniqueStrings(plan.tasks, 'qualification tasks'); + assert( + products.length > 0 && tasks.length > 0, + 'product qualification requires products and tasks', + ); + return { mode, baseSha, headSha, products, tasks }; + } + assert( + baseSha === null && headSha === null, + 'full-payload CI plan must not carry an affected range', + ); + return { mode, baseSha, headSha }; +} + +export function candidateQualificationMode(candidate) { + return candidate?.affectedPlan?.qualification?.mode ?? FULL_PAYLOAD_QUALIFICATION_MODE; +} + +export function affectedPlanBinding(planPath, wasixReleaseRegressionRequired) { + assert( + typeof wasixReleaseRegressionRequired === 'boolean', + 'WASIX release regression requirement must be boolean', + ); + const { value: plan } = strictJson(planPath, 'affected CI plan'); + const jobs = sortedUniqueStrings(plan.jobs, 'affected CI plan jobs'); + const projects = sortedUniqueStrings(plan.projects, 'affected CI plan projects'); + const extensionPackageProducts = sortedUniqueStrings( + plan.extension_package_products ?? [], + 'affected CI plan extension package products', + ); + const expectedRequirement = jobs.includes('liboliphaunt-wasix-runtime'); + assert( + wasixReleaseRegressionRequired === expectedRequirement, + `affected CI plan WASIX requirement mismatch: jobs imply ${expectedRequirement}, workflow reported ${wasixReleaseRegressionRequired}`, + ); + const qualification = qualificationBinding(plan); + const canonical = JSON.stringify(canonicalValue(plan)); + return { + digest: sha256(canonical), + jobs, + projects, + extensionPackageProducts, + wasixReleaseRegressionRequired, + ...(qualification === undefined ? {} : { qualification }), + }; +} + +function jsonFiles(root) { + assert(existsSync(root), `WASIX evidence artifact root does not exist: ${root}`); + const files = []; + const visit = (directory) => { + for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => + compareText(left.name, right.name), + )) { + const file = path.join(directory, entry.name); + if (entry.isDirectory()) { + visit(file); + } else if (entry.isFile() && entry.name.endsWith('.json')) { + files.push(file); + } + } + }; + visit(root); + return files; +} + +function expectedPublicExtensions(catalogPath) { + const { value: catalog } = strictJson(catalogPath, 'extension catalog'); + assert(Array.isArray(catalog.extensions), 'extension catalog extensions must be a list'); + return catalog.extensions.map((extension) => extension.id).sort(); +} + +function same(actual, expected, context) { + assert(actual === expected, `${context} mismatch: expected ${expected}, got ${actual}`); +} + +function positiveInteger(value, context) { + assert(Number.isSafeInteger(value) && value > 0, `${context} must be a positive safe integer`); +} + +function findEvidenceRun(root) { + const matches = []; + for (const file of jsonFiles(root)) { + let value; + try { + value = JSON.parse(readFileSync(file, 'utf8')); + } catch { + continue; + } + if ( + value?.schema === 'oliphaunt-extension-evidence-v1' && + value?.evidenceTier === 'wasix-full-lifecycle-v1' + ) { + matches.push({ file, value, bytes: readFileSync(file) }); + } + } + assert( + matches.length === 1, + `WASIX evidence artifact must contain exactly one full-lifecycle run, found ${matches.length}`, + ); + return matches[0]; +} + +export function wasixEvidenceBinding( + evidenceRoot, + { + repository, + workflow, + runId, + runAttempt, + sha, + tree, + catalogPath = 'src/extensions/generated/extensions.catalog.json', + }, +) { + const expectedRunId = Number.parseInt(String(runId), 10); + positiveInteger(expectedRunId, 'expected evidence runId'); + positiveInteger(runAttempt, 'candidate runAttempt'); + const root = path.resolve(evidenceRoot); + const { file, value: evidence, bytes } = findEvidenceRun(root); + same(evidence.status, 'passed', 'WASIX evidence status'); + same(evidence.sourceCommit, sha, 'WASIX evidence sourceCommit'); + same(evidence.sourceTree, tree, 'WASIX evidence sourceTree'); + assert( + /^sha256:[0-9a-f]{64}$/u.test(evidence.sourceDigest), + 'WASIX evidence sourceDigest must be SHA-256', + ); + uniqueStrings(evidence.sourceDigestInputs, 'WASIX evidence sourceDigestInputs'); + same(evidence.github?.repository, repository, 'WASIX evidence GitHub repository'); + same(evidence.github?.workflow, workflow, 'WASIX evidence GitHub workflow'); + same(evidence.github?.runId, expectedRunId, 'WASIX evidence GitHub runId'); + positiveInteger(evidence.github?.runAttempt, 'WASIX evidence GitHub runAttempt'); + // A failed-job rerun preserves successful run-level artifacts from an + // earlier attempt. Accept that immutable evidence, but never future evidence. + assert( + evidence.github.runAttempt <= runAttempt, + `WASIX evidence GitHub runAttempt must not be newer than the candidate attempt: expected at most ${runAttempt}, got ${evidence.github.runAttempt}`, + ); + same(evidence.github?.job, 'wasix-release-regression', 'WASIX evidence GitHub job'); + + assert( + Array.isArray(evidence.results) && evidence.results.length > 0, + 'WASIX evidence results must be non-empty', + ); + const extensions = []; + for (const result of evidence.results) { + assert( + typeof result?.extension === 'string' && result.extension.length > 0, + 'WASIX evidence result extension is invalid', + ); + same(result.postgresMajor, 18, `${result.extension} PostgreSQL major`); + same(result.artifactFamily, 'wasix-runtime', `${result.extension} artifact family`); + same(result.platformTarget, 'portable', `${result.extension} platform target`); + // Previously frozen candidates used the ambiguous dump-restore label. + const restorationModes = Object.hasOwn(result.runtimeModeStatuses ?? {}, 'backup-restore') + ? ['backup-restore', 'materialization'] + : ['dump-restore']; + for (const mode of ['direct', 'server', 'restart', ...restorationModes]) { + same(result.runtimeModeStatuses?.[mode], 'passed', `${result.extension} ${mode} status`); + } + extensions.push(result.extension); + } + extensions.sort(); + assert( + new Set(extensions).size === extensions.length, + 'WASIX evidence results must not repeat extensions', + ); + const expectedExtensions = expectedPublicExtensions(catalogPath); + assert( + JSON.stringify(extensions) === JSON.stringify(expectedExtensions), + 'WASIX evidence results must cover every and only public extension', + ); + + return { + artifact: 'wasix-release-regression-evidence', + file: path.relative(root, file).split(path.sep).join('/'), + digest: sha256(bytes), + id: evidence.id, + sourceDigest: evidence.sourceDigest, + sourceCommit: evidence.sourceCommit, + sourceTree: evidence.sourceTree, + github: { + repository: evidence.github.repository, + workflow: evidence.github.workflow, + runId: evidence.github.runId, + runAttempt: evidence.github.runAttempt, + job: evidence.github.job, + }, + resultCount: extensions.length, + extensionsDigest: sha256(JSON.stringify(extensions)), + }; +} + +export function assertCandidateBindingShape(candidate) { + assert( + candidate?.schemaVersion === 2, + `release candidate schemaVersion must be 2, got ${candidate?.schemaVersion}`, + ); + if (candidate.producers !== undefined) { + assert(Array.isArray(candidate.producers), 'candidate producers must be a list'); + const targets = new Set(); + for (const receipt of candidate.producers) { + assert( + typeof receipt.target === 'string' && !targets.has(receipt.target), + 'duplicate or invalid producer', + ); + targets.add(receipt.target); + assert( + receipt.producer?.sha === candidate.sha && + receipt.producer?.runId === candidate.runId && + receipt.producer?.runAttempt === candidate.runAttempt, + 'producer receipt is not from the qualification run and attempt', + ); + assert( + Number.isSafeInteger(receipt.artifact?.id) && + receipt.artifact.id > 0 && + Number.isSafeInteger(receipt.artifact.size) && + receipt.artifact.size > 0 && + /^sha256:[0-9a-f]{64}$/.test(receipt.artifact.digest), + 'producer artifact identity is invalid', + ); + assert( + receipt.toolchain?.moon && + receipt.toolchain?.bun && + receipt.toolchain?.typescript && + receipt.toolchain.target === 'portable-typescript', + 'producer toolchain identity is incomplete', + ); + assert(typeof receipt.eligible === 'boolean', 'producer eligibility is missing'); + if (!receipt.eligible) { + assert( + typeof receipt.reason === 'string' && receipt.reason.length > 0, + 'ineligible producer requires a reason', + ); + continue; + } + assert( + typeof receipt.cacheHit === 'boolean' && Array.isArray(receipt.hashes), + 'producer execution evidence is missing', + ); + const hashes = new Map(receipt.hashes.map((entry) => [entry.target, entry.hash])); + assert( + /^[0-9a-f]{64}$/.test(receipt.taskHash ?? '') && + hashes.size === receipt.hashes.length && + hashes.get(receipt.target) === receipt.taskHash, + 'producer hash chain is inconsistent', + ); + for (const entry of receipt.hashes) { + assert(/^[0-9a-f]{64}$/.test(entry.hash), 'producer hash is invalid'); + for (const [dependency, hash] of Object.entries(entry.dependencies)) + assert(hashes.get(dependency) === hash, 'producer dependency hash is incomplete'); + } + } + } + assert( + candidate.affectedPlan !== null && typeof candidate.affectedPlan === 'object', + 'release candidate affectedPlan is missing', + ); + assert( + /^sha256:[0-9a-f]{64}$/u.test(candidate.affectedPlan.digest), + 'release candidate plan digest is invalid', + ); + const jobs = sortedUniqueStrings( + candidate.affectedPlan.jobs, + 'release candidate affectedPlan.jobs', + ); + sortedUniqueStrings(candidate.affectedPlan.projects, 'release candidate affectedPlan.projects'); + sortedUniqueStrings( + candidate.affectedPlan.extensionPackageProducts, + 'release candidate affectedPlan.extensionPackageProducts', + ); + assert( + typeof candidate.affectedPlan.wasixReleaseRegressionRequired === 'boolean', + 'release candidate affectedPlan WASIX requirement must be boolean', + ); + assert( + candidate.affectedPlan.wasixReleaseRegressionRequired === + jobs.includes('liboliphaunt-wasix-runtime'), + 'release candidate affectedPlan WASIX requirement is inconsistent with selected jobs', + ); + const qualification = candidate.affectedPlan.qualification; + if (qualification !== undefined) { + assert( + qualification !== null && !Array.isArray(qualification) && typeof qualification === 'object', + 'release candidate affectedPlan qualification is invalid', + ); + assert( + JSON.stringify(Object.keys(qualification).sort()) === + JSON.stringify( + qualification.mode === PRODUCT_QUALIFICATION_MODE + ? ['baseSha', 'headSha', 'mode', 'products', 'tasks'] + : ['baseSha', 'headSha', 'mode'], + ), + 'release candidate affectedPlan qualification fields are invalid', + ); + assert( + [FULL_PAYLOAD_QUALIFICATION_MODE, PRODUCT_QUALIFICATION_MODE].includes(qualification.mode), + 'release candidate qualification mode is invalid', + ); + if (qualification.mode === PRODUCT_QUALIFICATION_MODE) { + assert( + qualification.baseSha === null && qualification.headSha === candidate.sha, + 'selected-products qualification must bind the candidate SHA', + ); + assert( + sortedUniqueStrings(qualification.products, 'qualification products').length > 0, + 'qualification products must not be empty', + ); + assert( + sortedUniqueStrings(qualification.tasks, 'qualification tasks').length > 0, + 'qualification tasks must not be empty', + ); + } else + assert( + qualification.baseSha === null && qualification.headSha === null, + 'full-payload release candidate must not carry an affected range', + ); + } + const requirements = candidate.evidenceRequirements; + assert( + requirements !== null && typeof requirements === 'object', + 'release candidate evidenceRequirements is missing', + ); + assert( + requirements.wasixReleaseRegression === candidate.affectedPlan.wasixReleaseRegressionRequired, + 'release candidate WASIX evidence requirement is inconsistent with affected plan', + ); + const expectedArtifacts = requirements.wasixReleaseRegression + ? ['wasix-release-regression-evidence'] + : []; + assert( + JSON.stringify(requirements.artifacts) === JSON.stringify(expectedArtifacts), + 'release candidate evidence artifact requirements are inconsistent', + ); + if (requirements.wasixReleaseRegression) { + assert( + candidate.evidence?.wasixReleaseRegression !== null, + 'release candidate is missing required WASIX evidence binding', + ); + assert( + /^sha256:[0-9a-f]{64}$/u.test(candidate.evidence.wasixReleaseRegression.digest), + 'release candidate WASIX evidence digest is invalid', + ); + positiveInteger( + candidate.evidence.wasixReleaseRegression.github?.runId, + 'release candidate WASIX evidence runId', + ); + positiveInteger( + candidate.evidence.wasixReleaseRegression.github?.runAttempt, + 'release candidate WASIX evidence runAttempt', + ); + } else { + assert( + candidate.evidence?.wasixReleaseRegression === null, + 'release candidate carries WASIX evidence that its plan did not require', + ); + } +} + +export function assertBindingMatches(actual, expected, context) { + assert( + JSON.stringify(actual) === JSON.stringify(expected), + `${context} binding does not match the recomputed same-run content`, + ); +} + +export function assertQualificationProductCoverage(candidate, products) { + assert( + Array.isArray(products) && + products.length > 0 && + products.every((product) => typeof product === 'string' && product.length > 0) && + new Set(products).size === products.length, + 'publication products must be a non-empty unique string list', + ); + if (candidateQualificationMode(candidate) === FULL_PAYLOAD_QUALIFICATION_MODE) return; + const qualified = new Set(candidate.affectedPlan.qualification.products); + for (const product of products) + assert( + qualified.has(product), + `release candidate is missing qualification for product ${product}`, + ); +} diff --git a/.github/scripts/release-candidate.sh b/.github/scripts/release-candidate.sh new file mode 100644 index 000000000..98d110a83 --- /dev/null +++ b/.github/scripts/release-candidate.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +mode="${1:-}" +shift || true +case "$mode" in + write) + CI_CHECKED_OUT_SHA="$(git rev-parse --verify 'HEAD^{commit}')" + CI_SOURCE_TREE="$(git rev-parse --verify 'HEAD^{tree}')" + export CI_CHECKED_OUT_SHA + ;; + verify) + CI_SOURCE_TREE="$(git rev-parse --verify --end-of-options "${RELEASE_HEAD_SHA:?RELEASE_HEAD_SHA is required}^{tree}")" + ;; + *) echo 'usage: release-candidate.sh write|verify [arguments]' >&2; exit 2 ;; +esac +export CI_SOURCE_TREE +exec bun "$script_dir/$mode-release-candidate.mts" "$@" diff --git a/.github/scripts/release-intent-data.mts b/.github/scripts/release-intent-data.mts new file mode 100644 index 000000000..0edda94d3 --- /dev/null +++ b/.github/scripts/release-intent-data.mts @@ -0,0 +1,42 @@ +switch (Bun.argv[2]) { + case 'types': { + const config = JSON.parse(await Bun.stdin.text()); + const sections = config['changelog-sections']; + if (!Array.isArray(sections) || sections.length === 0) { + console.error('release-please-config.json must define changelog-sections'); + process.exit(1); + } + const types = [...new Set(sections.map((section) => section?.type))]; + if (types.some((type) => typeof type !== 'string' || !/^[a-z][a-z0-9-]*$/.test(type))) { + console.error( + 'release-please changelog section types must be conventional lowercase identifiers', + ); + process.exit(1); + } + console.log(types.join('|')); + + break; + } + case 'versions': { + let data; + try { + data = JSON.parse(await Bun.stdin.text()); + } catch { + process.exit(0); + } + for (const [path, version] of Object.entries(data).sort(([left], [right]) => + left < right ? -1 : left > right ? 1 : 0, + )) { + console.log(`${path}=${version}`); + } + + break; + } + case 'products': { + const data = JSON.parse(await Bun.stdin.text()); + console.log((data.releaseProducts ?? []).join('\n')); + break; + } + default: + throw new Error('unknown release-intent data command'); +} diff --git a/.github/scripts/release-transport-ref.mjs b/.github/scripts/release-transport-ref.mjs deleted file mode 100644 index 0f01a06ec..000000000 --- a/.github/scripts/release-transport-ref.mjs +++ /dev/null @@ -1,377 +0,0 @@ -#!/usr/bin/env node - -import { spawnSync } from "node:child_process"; -import process from "node:process"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { reserveGitHubContentWriteSync } from "../../tools/release/github-content-write-pacer.mjs"; -import { reserveGitHubCoreRequestSync } from "../../tools/release/github-core-request-journal.mjs"; -import { assertPublicationController } from "../../tools/release/publication-controller.mjs"; - -export const RELEASE_TRANSPORT_TAG_PREFIX = "oliphaunt-release-transport/"; -export const RELEASE_TRANSPORT_REQUEST_TIMEOUT_MS = 30_000; -export const RELEASE_TRANSPORT_MAX_RESPONSE_BYTES = 64 * 1024; -export const RELEASE_TRANSPORT_STEP_TIMEOUT_MINUTES = 3; - -const REPOSITORY_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const REQUIRE_CURRENT_MAIN = path.join( - REPOSITORY_ROOT, - ".github/scripts/require-current-main.sh", -); -const CURRENT_MAIN_PROOF_TIMEOUT_MS = 60_000; - -const CONTENT_WRITE_ADMISSIONS = new Set([ - "self-paced", - "pre-reserved", - "isolated-bootstrap", -]); - -const FULL_SHA = /^[0-9a-f]{40}$/u; -const REPOSITORY = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u; - -function error(message) { - return new Error(`release-transport-ref: ${message}`); -} - -export function normalizeReleaseTransportCommit(value) { - const commit = String(value ?? "").trim().toLowerCase(); - if (!FULL_SHA.test(commit)) { - throw error("release commit must be a full lowercase-compatible 40-character SHA"); - } - return commit; -} - -export function releaseTransportTagName(commit) { - return `${RELEASE_TRANSPORT_TAG_PREFIX}${normalizeReleaseTransportCommit(commit)}`; -} - -export function releaseTransportFullRef(commit) { - return `refs/tags/${releaseTransportTagName(commit)}`; -} - -export function validateReleaseTransportRef(value, commit) { - const expectedCommit = normalizeReleaseTransportCommit(commit); - const expectedRef = releaseTransportFullRef(expectedCommit); - if ( - value === null - || Array.isArray(value) - || typeof value !== "object" - || value.ref !== expectedRef - || value.object === null - || Array.isArray(value.object) - || typeof value.object !== "object" - || value.object.type !== "commit" - || value.object.sha !== expectedCommit - ) { - throw error(`transport ref ${expectedRef} does not point directly to exact release commit ${expectedCommit}`); - } - return { commit: expectedCommit, fullRef: expectedRef, tag: releaseTransportTagName(expectedCommit) }; -} - -function requiredEnvironment(environment, name) { - const value = environment[name]?.trim(); - if (!value) throw error(`${name} is required`); - return value; -} - -function safeRepository(value) { - const repo = String(value ?? "").trim(); - if (!REPOSITORY.test(repo)) throw error("GH_REPO must be OWNER/REPOSITORY"); - return repo; -} - -function safeToken(value) { - const token = String(value ?? ""); - if (token.length === 0 || token.length > 16 * 1024 || /[\u0000-\u001f\u007f]/u.test(token)) { - throw error("GH_TOKEN must be a non-empty control-free secret"); - } - return token; -} - -function rootAdmission(contentWriteAdmission, commit, environment) { - if (contentWriteAdmission === "self-paced") return { root: false, runAttempt: null }; - const expectedOperation = contentWriteAdmission === "isolated-bootstrap" - ? "publish-bootstrap" - : "publish"; - const runAttempt = String(environment.GITHUB_RUN_ATTEMPT ?? ""); - let workflowSha; - try { - workflowSha = normalizeReleaseTransportCommit(environment.GITHUB_SHA); - } catch { - throw error( - `${contentWriteAdmission} admission requires the exact root ${expectedOperation} GitHub run`, - ); - } - if ( - environment.GITHUB_ACTIONS !== "true" - || environment.RELEASE_OPERATION !== expectedOperation - || environment.GITHUB_REF !== "refs/heads/main" - || !/^[1-9][0-9]*$/u.test(runAttempt) - || !Number.isSafeInteger(Number(runAttempt)) - ) { - throw error( - `${contentWriteAdmission} admission requires the exact root ${expectedOperation} GitHub run`, - ); - } - if (workflowSha !== commit) { - try { - assertPublicationController({ source: commit, controller: workflowSha }); - } catch (cause) { - throw error(`${contentWriteAdmission} admission requires the exact root ${expectedOperation} GitHub run with a verified publication controller: ${cause.message}`); - } - } - return { root: true, runAttempt: Number(runAttempt), workflowSha }; -} - -export function proveCurrentMainSync({ commit, environment = process.env } = {}) { - const normalizedCommit = normalizeReleaseTransportCommit(commit); - const result = spawnSync("bash", [REQUIRE_CURRENT_MAIN, normalizedCommit], { - cwd: REPOSITORY_ROOT, - env: environment, - stdio: "inherit", - timeout: CURRENT_MAIN_PROOF_TIMEOUT_MS, - windowsHide: true, - }); - if (result.error !== undefined) { - throw error(`current-main proof could not execute: ${result.error.message}`); - } - if (result.status !== 0) { - const outcome = result.signal === null - ? `exit ${result.status}` - : `signal ${result.signal}`; - throw error(`current-main proof failed with ${outcome}`); - } -} - -async function boundedText(response, context) { - const declared = response.headers?.get?.("content-length"); - if (declared !== null && declared !== undefined) { - const length = Number(declared); - if (!Number.isSafeInteger(length) || length < 0 || length > RELEASE_TRANSPORT_MAX_RESPONSE_BYTES) { - await response.body?.cancel?.().catch(() => {}); - throw error(`${context} returned an invalid or oversized Content-Length`); - } - } - const reader = response.body?.getReader?.(); - if (reader === undefined) { - const text = await response.text(); - if (Buffer.byteLength(text) > RELEASE_TRANSPORT_MAX_RESPONSE_BYTES) { - throw error(`${context} exceeded ${RELEASE_TRANSPORT_MAX_RESPONSE_BYTES} bytes`); - } - return text; - } - const chunks = []; - let size = 0; - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > RELEASE_TRANSPORT_MAX_RESPONSE_BYTES) { - await reader.cancel().catch(() => {}); - throw error(`${context} exceeded ${RELEASE_TRANSPORT_MAX_RESPONSE_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - return Buffer.concat(chunks, size).toString("utf8"); -} - -async function responseJson(response, context) { - const text = await boundedText(response, context); - try { - return JSON.parse(text); - } catch (cause) { - throw error(`${context} returned invalid JSON: ${cause.message}`); - } -} - -function requestHeaders(token, json = false) { - return { - Accept: "application/vnd.github+json", - Authorization: `Bearer ${token}`, - "User-Agent": "oliphaunt-release-transport/1; https://github.com/f0rr0/oliphaunt", - "X-GitHub-Api-Version": "2022-11-28", - ...(json ? { "Content-Type": "application/json" } : {}), - }; -} - -function apiUrl(repo, suffix) { - return `https://api.github.com/repos/${repo}/${suffix}`; -} - -async function request(fetchImpl, url, options, context) { - try { - return await fetchImpl(url, { - ...options, - redirect: "error", - signal: AbortSignal.timeout(RELEASE_TRANSPORT_REQUEST_TIMEOUT_MS), - }); - } catch (cause) { - throw error(`${context} failed before a complete response: ${cause instanceof Error ? cause.message : String(cause)}`); - } -} - -async function readTransportRef({ commit, environment, fetchImpl, repo, token }) { - reserveGitHubCoreRequestSync({ - environment, - label: `release transport ref read ${commit}`, - }); - const response = await request( - fetchImpl, - apiUrl(repo, `git/ref/tags/${releaseTransportTagName(commit)}`), - { headers: requestHeaders(token), method: "GET" }, - "transport ref read", - ); - if (response.status === 404) { - await boundedText(response, "transport ref absence response"); - return null; - } - if (response.status !== 200) { - await boundedText(response, "transport ref read failure response"); - throw error(`transport ref read returned HTTP ${response.status}`); - } - return validateReleaseTransportRef(await responseJson(response, "transport ref read"), commit); -} - -export async function verifyReleaseTransportRef({ - commit, - environment = process.env, - fetchImpl = fetch, - repo = environment.GH_REPO, - token = environment.GH_TOKEN, -} = {}) { - const normalizedCommit = normalizeReleaseTransportCommit(commit); - const safeRepo = safeRepository(repo); - const secret = safeToken(token); - const observed = await readTransportRef({ - commit: normalizedCommit, - environment, - fetchImpl, - repo: safeRepo, - token: secret, - }); - if (observed === null) { - throw error(`transport ref ${releaseTransportFullRef(normalizedCommit)} does not exist`); - } - return observed; -} - -export async function ensureReleaseTransportRef({ - commit, - contentWriteAdmission = "self-paced", - environment = process.env, - fetchImpl = fetch, - proveCurrentMain = proveCurrentMainSync, - repo = environment.GH_REPO, - token = environment.GH_TOKEN, -} = {}) { - if (!CONTENT_WRITE_ADMISSIONS.has(contentWriteAdmission)) { - throw error( - "contentWriteAdmission must be self-paced, pre-reserved, or isolated-bootstrap", - ); - } - const normalizedCommit = normalizeReleaseTransportCommit(commit); - const admission = rootAdmission( - contentWriteAdmission, - normalizedCommit, - environment, - ); - const safeRepo = safeRepository(repo); - const secret = safeToken(token); - const existing = await readTransportRef({ - commit: normalizedCommit, - environment, - fetchImpl, - repo: safeRepo, - token: secret, - }); - const genuineRootRerun = admission.root && admission.runAttempt > 1; - if (existing !== null && genuineRootRerun) { - return { ...existing, created: false }; - } - - if (existing === null && contentWriteAdmission === "self-paced") { - reserveGitHubContentWriteSync({ - environment, - label: `create release transport ref ${normalizedCommit}`, - }); - } - await proveCurrentMain({ commit: admission.workflowSha ?? normalizedCommit, environment }); - if (existing !== null) return { ...existing, created: false }; - - reserveGitHubCoreRequestSync({ - environment, - label: `release transport ref create ${normalizedCommit}`, - }); - let mutationFailure; - try { - const response = await request( - fetchImpl, - apiUrl(safeRepo, "git/refs"), - { - body: JSON.stringify({ - ref: releaseTransportFullRef(normalizedCommit), - sha: normalizedCommit, - }), - headers: requestHeaders(secret, true), - method: "POST", - }, - "transport ref create", - ); - if (response.status === 201) { - const created = validateReleaseTransportRef( - await responseJson(response, "transport ref create"), - normalizedCommit, - ); - return { ...created, created: true }; - } - await boundedText(response, "transport ref create failure response"); - mutationFailure = error(`transport ref create returned HTTP ${response.status}`); - } catch (cause) { - mutationFailure = cause; - } - - // A create can take effect even when its response is lost, or another exact - // root invocation can win the race. Never replay the mutation: perform one - // read-only reconciliation and accept only the exact immutable target. - let reconciled; - try { - reconciled = await readTransportRef({ - commit: normalizedCommit, - environment, - fetchImpl, - repo: safeRepo, - token: secret, - }); - } catch (cause) { - throw new AggregateError( - [mutationFailure, cause], - "release transport ref creation failed and exact reconciliation could not be completed", - ); - } - if (reconciled === null) throw mutationFailure; - return { ...reconciled, created: true }; -} - -async function main(argv, environment = process.env) { - if (argv.length !== 2 || !new Set(["ensure", "verify"]).has(argv[0])) { - throw error("usage: release-transport-ref.mjs "); - } - const [operation, commit] = argv; - const contentWriteAdmission = environment.RELEASE_TRANSPORT_CONTENT_WRITE_ADMISSION - ?? "self-paced"; - const result = operation === "ensure" - ? await ensureReleaseTransportRef({ commit, contentWriteAdmission, environment }) - : await verifyReleaseTransportRef({ commit, environment }); - console.log( - `${operation === "ensure" ? (result.created ? "created" : "verified") : "verified"} ` - + `${result.fullRef} at ${result.commit}`, - ); -} - -if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) { - main(process.argv.slice(2)).catch((cause) => { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - }); -} diff --git a/.github/scripts/release-transport-ref.mts b/.github/scripts/release-transport-ref.mts new file mode 100644 index 000000000..09a83dcf0 --- /dev/null +++ b/.github/scripts/release-transport-ref.mts @@ -0,0 +1,397 @@ +#!/usr/bin/env bun + +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; + +import { reserveGitHubContentWrite } from '../../tools/release/github-content-write-pacer.mts'; +import { reserveGitHubCoreRequest } from '../../tools/release/github-core-request-journal.mts'; +import { assertPublicationController } from '../../tools/release/publication-controller.mts'; + +export const RELEASE_TRANSPORT_TAG_PREFIX = 'oliphaunt-release-transport/'; +export const RELEASE_TRANSPORT_REQUEST_TIMEOUT_MS = 30_000; +export const RELEASE_TRANSPORT_MAX_RESPONSE_BYTES = 64 * 1024; +export const RELEASE_TRANSPORT_STEP_TIMEOUT_MINUTES = 3; + +const CONTENT_WRITE_ADMISSIONS = new Set(['self-paced', 'pre-reserved', 'isolated-bootstrap']); + +const FULL_SHA = /^[0-9a-f]{40}$/u; +const REPOSITORY = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u; + +function error(message) { + return new Error(`release-transport-ref: ${message}`); +} + +export function normalizeReleaseTransportCommit(value) { + const commit = String(value ?? '') + .trim() + .toLowerCase(); + if (!FULL_SHA.test(commit)) { + throw error('release commit must be a full lowercase-compatible 40-character SHA'); + } + return commit; +} + +export function releaseTransportTagName(commit) { + return `${RELEASE_TRANSPORT_TAG_PREFIX}${normalizeReleaseTransportCommit(commit)}`; +} + +export function releaseTransportFullRef(commit) { + return `refs/tags/${releaseTransportTagName(commit)}`; +} + +export function validateReleaseTransportRef(value, commit) { + const expectedCommit = normalizeReleaseTransportCommit(commit); + const expectedRef = releaseTransportFullRef(expectedCommit); + if ( + value === null || + Array.isArray(value) || + typeof value !== 'object' || + value.ref !== expectedRef || + value.object === null || + Array.isArray(value.object) || + typeof value.object !== 'object' || + value.object.type !== 'commit' || + value.object.sha !== expectedCommit + ) { + throw error( + `transport ref ${expectedRef} does not point directly to exact release commit ${expectedCommit}`, + ); + } + return { + commit: expectedCommit, + fullRef: expectedRef, + tag: releaseTransportTagName(expectedCommit), + }; +} + +function requiredEnvironment(environment, name) { + const value = environment[name]?.trim(); + if (!value) throw error(`${name} is required`); + return value; +} + +function safeRepository(value) { + const repo = String(value ?? '').trim(); + if (!REPOSITORY.test(repo)) throw error('GH_REPO must be OWNER/REPOSITORY'); + return repo; +} + +function safeToken(value) { + const token = String(value ?? ''); + if (token.length === 0 || token.length > 16 * 1024 || /[\u0000-\u001f\u007f]/u.test(token)) { + throw error('GH_TOKEN must be a non-empty control-free secret'); + } + return token; +} + +function rootAdmission(contentWriteAdmission, commit, environment) { + if (contentWriteAdmission === 'self-paced') return { root: false, runAttempt: null }; + const expectedOperation = + contentWriteAdmission === 'isolated-bootstrap' ? 'publish-bootstrap' : 'publish'; + const runAttempt = String(environment.GITHUB_RUN_ATTEMPT ?? ''); + let workflowSha; + try { + workflowSha = normalizeReleaseTransportCommit(environment.GITHUB_SHA); + } catch { + throw error( + `${contentWriteAdmission} admission requires the exact root ${expectedOperation} GitHub run`, + ); + } + if ( + environment.GITHUB_ACTIONS !== 'true' || + environment.RELEASE_OPERATION !== expectedOperation || + environment.GITHUB_REF !== 'refs/heads/main' || + !/^[1-9][0-9]*$/u.test(runAttempt) || + !Number.isSafeInteger(Number(runAttempt)) + ) { + throw error( + `${contentWriteAdmission} admission requires the exact root ${expectedOperation} GitHub run`, + ); + } + if (workflowSha !== commit) { + try { + assertPublicationController({ source: commit, controller: workflowSha, environment }); + } catch (cause) { + throw error( + `${contentWriteAdmission} admission requires the exact root ${expectedOperation} GitHub run with a verified publication controller: ${cause.message}`, + ); + } + } + return { root: true, runAttempt: Number(runAttempt), workflowSha }; +} + +export async function proveCurrentMain({ + commit, + environment = process.env, + fetchImpl = fetch, + repo = environment.GH_REPO, + token = environment.GH_TOKEN, +} = {}) { + const expected = normalizeReleaseTransportCommit(commit); + if (environment.GITHUB_REF !== 'refs/heads/main') + throw error('release operations must be dispatched from main'); + const safeRepo = safeRepository(repo); + const secret = safeToken(token); + await reserveGitHubCoreRequest({ environment, label: 'release current main proof' }); + const response = await request( + fetchImpl, + apiUrl(safeRepo, 'git/ref/heads/main'), + { + headers: requestHeaders(secret), + method: 'GET', + }, + 'current main proof', + ); + if (response.status !== 200) { + await boundedText(response, 'current main proof failure'); + throw error(`current main proof returned HTTP ${response.status}`); + } + const ref = await responseJson(response, 'current main proof'); + if ( + ref?.ref !== 'refs/heads/main' || + ref?.object?.type !== 'commit' || + ref.object.sha !== expected + ) { + throw error('main moved after this workflow was dispatched or returned an invalid commit ref'); + } +} + +async function boundedText(response, context) { + const declared = response.headers?.get?.('content-length'); + if (declared !== null && declared !== undefined) { + const length = Number(declared); + if ( + !Number.isSafeInteger(length) || + length < 0 || + length > RELEASE_TRANSPORT_MAX_RESPONSE_BYTES + ) { + await response.body?.cancel?.().catch(() => {}); + throw error(`${context} returned an invalid or oversized Content-Length`); + } + } + const reader = response.body?.getReader?.(); + if (reader === undefined) { + const text = await response.text(); + if (Buffer.byteLength(text) > RELEASE_TRANSPORT_MAX_RESPONSE_BYTES) { + throw error(`${context} exceeded ${RELEASE_TRANSPORT_MAX_RESPONSE_BYTES} bytes`); + } + return text; + } + const chunks = []; + let size = 0; + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > RELEASE_TRANSPORT_MAX_RESPONSE_BYTES) { + await reader.cancel().catch(() => {}); + throw error(`${context} exceeded ${RELEASE_TRANSPORT_MAX_RESPONSE_BYTES} bytes`); + } + chunks.push(Buffer.from(value)); + } + return Buffer.concat(chunks, size).toString('utf8'); +} + +async function responseJson(response, context) { + const text = await boundedText(response, context); + try { + return JSON.parse(text); + } catch (cause) { + throw error(`${context} returned invalid JSON: ${cause.message}`); + } +} + +function requestHeaders(token, json = false) { + return { + Accept: 'application/vnd.github+json', + Authorization: `Bearer ${token}`, + 'User-Agent': 'oliphaunt-release-transport/1; https://github.com/f0rr0/oliphaunt', + 'X-GitHub-Api-Version': '2022-11-28', + ...(json ? { 'Content-Type': 'application/json' } : {}), + }; +} + +function apiUrl(repo, suffix) { + return `https://api.github.com/repos/${repo}/${suffix}`; +} + +async function request(fetchImpl, url, options, context) { + try { + return await fetchImpl(url, { + ...options, + redirect: 'error', + signal: AbortSignal.timeout(RELEASE_TRANSPORT_REQUEST_TIMEOUT_MS), + }); + } catch (cause) { + throw error( + `${context} failed before a complete response: ${cause instanceof Error ? cause.message : String(cause)}`, + ); + } +} + +async function readTransportRef({ commit, environment, fetchImpl, repo, token }) { + await reserveGitHubCoreRequest({ + environment, + label: `release transport ref read ${commit}`, + }); + const response = await request( + fetchImpl, + apiUrl(repo, `git/ref/tags/${releaseTransportTagName(commit)}`), + { headers: requestHeaders(token), method: 'GET' }, + 'transport ref read', + ); + if (response.status === 404) { + await boundedText(response, 'transport ref absence response'); + return null; + } + if (response.status !== 200) { + await boundedText(response, 'transport ref read failure response'); + throw error(`transport ref read returned HTTP ${response.status}`); + } + return validateReleaseTransportRef(await responseJson(response, 'transport ref read'), commit); +} + +export async function verifyReleaseTransportRef({ + commit, + environment = process.env, + fetchImpl = fetch, + repo = environment.GH_REPO, + token = environment.GH_TOKEN, +} = {}) { + const normalizedCommit = normalizeReleaseTransportCommit(commit); + const safeRepo = safeRepository(repo); + const secret = safeToken(token); + const observed = await readTransportRef({ + commit: normalizedCommit, + environment, + fetchImpl, + repo: safeRepo, + token: secret, + }); + if (observed === null) { + throw error(`transport ref ${releaseTransportFullRef(normalizedCommit)} does not exist`); + } + return observed; +} + +export async function ensureReleaseTransportRef({ + commit, + contentWriteAdmission = 'self-paced', + environment = process.env, + fetchImpl = fetch, + proveCurrentMain: proveMain = proveCurrentMain, + repo = environment.GH_REPO, + token = environment.GH_TOKEN, +} = {}) { + if (!CONTENT_WRITE_ADMISSIONS.has(contentWriteAdmission)) { + throw error('contentWriteAdmission must be self-paced, pre-reserved, or isolated-bootstrap'); + } + const normalizedCommit = normalizeReleaseTransportCommit(commit); + const admission = rootAdmission(contentWriteAdmission, normalizedCommit, environment); + const safeRepo = safeRepository(repo); + const secret = safeToken(token); + const existing = await readTransportRef({ + commit: normalizedCommit, + environment, + fetchImpl, + repo: safeRepo, + token: secret, + }); + const genuineRootRerun = admission.root && admission.runAttempt > 1; + if (existing !== null && genuineRootRerun) { + return { ...existing, created: false }; + } + + if (existing === null && contentWriteAdmission === 'self-paced') { + await reserveGitHubContentWrite({ + environment, + label: `create release transport ref ${normalizedCommit}`, + }); + } + await proveMain({ + commit: admission.workflowSha ?? normalizedCommit, + environment, + fetchImpl, + repo: safeRepo, + token: secret, + }); + if (existing !== null) return { ...existing, created: false }; + + await reserveGitHubCoreRequest({ + environment, + label: `release transport ref create ${normalizedCommit}`, + }); + let mutationFailure; + try { + const response = await request( + fetchImpl, + apiUrl(safeRepo, 'git/refs'), + { + body: JSON.stringify({ + ref: releaseTransportFullRef(normalizedCommit), + sha: normalizedCommit, + }), + headers: requestHeaders(secret, true), + method: 'POST', + }, + 'transport ref create', + ); + if (response.status === 201) { + const created = validateReleaseTransportRef( + await responseJson(response, 'transport ref create'), + normalizedCommit, + ); + return { ...created, created: true }; + } + await boundedText(response, 'transport ref create failure response'); + mutationFailure = error(`transport ref create returned HTTP ${response.status}`); + } catch (cause) { + mutationFailure = cause; + } + + // A create can take effect even when its response is lost, or another exact + // root invocation can win the race. Never replay the mutation: perform one + // read-only reconciliation and accept only the exact immutable target. + let reconciled; + try { + reconciled = await readTransportRef({ + commit: normalizedCommit, + environment, + fetchImpl, + repo: safeRepo, + token: secret, + }); + } catch (cause) { + throw new AggregateError( + [mutationFailure, cause], + 'release transport ref creation failed and exact reconciliation could not be completed', + ); + } + if (reconciled === null) throw mutationFailure; + return { ...reconciled, created: true }; +} + +async function main(argv, environment = process.env) { + if (argv.length !== 2 || !new Set(['ensure', 'verify']).has(argv[0])) { + throw error('usage: release-transport-ref.mts '); + } + const [operation, commit] = argv; + const contentWriteAdmission = + environment.RELEASE_TRANSPORT_CONTENT_WRITE_ADMISSION ?? 'self-paced'; + const result = + operation === 'ensure' + ? await ensureReleaseTransportRef({ commit, contentWriteAdmission, environment }) + : await verifyReleaseTransportRef({ commit, environment }); + console.log( + `${operation === 'ensure' ? (result.created ? 'created' : 'verified') : 'verified'} ` + + `${result.fullRef} at ${result.commit}`, + ); +} + +if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) { + await main(process.argv.slice(2)).catch((cause) => { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + }); +} diff --git a/.github/scripts/require-workflow-success.sh b/.github/scripts/require-workflow-success.sh index 2e85066d2..ead6efbff 100644 --- a/.github/scripts/require-workflow-success.sh +++ b/.github/scripts/require-workflow-success.sh @@ -15,11 +15,25 @@ gate_artifacts=() required_jobs=() required_events=() expected_run_id="" +release_candidate=false +qualification_products='' +qualification_plan=false +qualification_dispatch=false +qualification_wait=false selected_artifacts_json='[]' selected_gate_artifacts_json='[]' selected_run_attempt='' while [[ $# -gt 0 ]]; do case "$1" in + --plan-qualification | --dispatch-qualification | --qualification-products) + case "$1" in --plan-qualification) qualification_plan=true ;; --dispatch-qualification) qualification_dispatch=true ;; --qualification-products) qualification_wait=true ;; esac + qualification_products="${2:?qualification scope requires product JSON}" + shift 2 + ;; + --release-candidate) + release_candidate=true + shift + ;; --run-id) expected_run_id="${2:?--run-id requires a run id}" shift 2 @@ -47,24 +61,44 @@ while [[ $# -gt 0 ]]; do esac done +if [[ "$release_candidate" == true ]]; then + if [[ "$workflow" != Release || ! "$expected_run_id" =~ ^[1-9][0-9]*$ ]]; then + echo "--release-candidate requires Release and an explicit positive --run-id" >&2 + exit 2 + fi + required_events=(workflow_dispatch) +fi + : "${GH_TOKEN:?GH_TOKEN is required}" : "${GH_REPO:?GH_REPO is required}" if [[ ! "$sha" =~ ^[0-9A-Fa-f]{40}$ ]]; then echo "workflow gate SHA must be a full hexadecimal commit SHA" >&2 exit 2 fi +if [[ -n "$qualification_products" ]]; then + [[ "$workflow" == CI && -z "$expected_run_id" ]] || { + echo 'qualification selection requires CI without --run-id' >&2 + exit 2 + } + qualification_scratch="$(mktemp -d)" + trap 'rm -rf "$qualification_scratch"' EXIT + QUALIFICATION_REQUEST_KEY="$(EXPECTED_SHA="$sha" PRODUCTS_JSON="$qualification_products" bun .github/scripts/workflow-run-metadata.mts qualification-key)" + export QUALIFICATION_REQUEST_KEY + required_events=(push workflow_dispatch) +fi github_read() { local label="${1:?GitHub read label is required}" - shift - node tools/release/github-read.mjs --label "$label" -- "$@" + local response + response="$(bun tools/release/github-read.mts --label "$label" -- "$2")" || return $? + bun .github/scripts/workflow-run-metadata.mts "$3" <<<"$response" } github_paginated_json() { local label="${1:?GitHub paginated read label is required}" local field="${2:?GitHub paginated read field is required}" local endpoint="${3:?GitHub paginated read endpoint is required}" - node tools/release/github-read.mjs \ + bun tools/release/github-read.mts \ --label "$label" \ --paginate-field "$field" \ -- "$endpoint" @@ -81,10 +115,14 @@ emit_run_id() { echo "run_id=$run_id" echo "run_attempt=$selected_run_attempt" echo "artifact_metadata_json=$selected_artifacts_json" + if [[ "$release_candidate" == true ]]; then + ARTIFACTS_JSON="$selected_artifacts_json" bun .github/scripts/workflow-run-metadata.mts artifact-ids + fi echo "gate_artifact_metadata_json=$selected_gate_artifacts_json" - } >> "$GITHUB_OUTPUT" + } >>"$GITHUB_OUTPUT" fi echo "selected $workflow run $run_id" + if [[ "$qualification_plan" == true ]]; then echo 'qualification_request_required=false' >>"$GITHUB_OUTPUT"; fi } run_matches_request() { @@ -92,8 +130,7 @@ run_matches_request() { local row status row="$( github_read "$workflow run $run_id metadata" \ - api "repos/$GH_REPO/actions/runs/$run_id" \ - --jq '[.head_sha, .workflow_id, .event, .status, (.conclusion // ""), .run_attempt] | @tsv' + "repos/$GH_REPO/actions/runs/$run_id" run-row )" || { status=$? echo "failed to inspect $workflow run $run_id" >&2 @@ -101,14 +138,14 @@ run_matches_request() { } local run_sha workflow_id run_event run_status run_conclusion run_attempt workflow_name - IFS=$'\t' read -r run_sha workflow_id run_event run_status run_conclusion run_attempt <<< "$row" + IFS=$'\t' read -r run_sha workflow_id run_event run_status run_conclusion run_attempt <<<"$row" if [[ "$(printf '%s' "$run_sha" | normalize_sha)" != "$(printf '%s' "$sha" | normalize_sha)" ]]; then echo "$workflow run $run_id belongs to $run_sha, not $sha" >&2 return 1 fi workflow_name="$( github_read "workflow $workflow_id metadata" \ - api "repos/$GH_REPO/actions/workflows/$workflow_id" --jq .name + "repos/$GH_REPO/actions/workflows/$workflow_id" workflow-name )" || { status=$? return "$status" @@ -130,11 +167,11 @@ run_matches_request() { return 1 fi fi - # A successful named job is not sufficient release evidence while the - # enclosing run is still mutable or has an unsuccessful final conclusion. - # This also keeps the waiter aligned with the documented non-cancelled, - # exact-SHA qualification contract. - if [[ "$run_status" != "completed" || "$run_conclusion" != "success" ]]; then + # Publication may fail after preparation. Recovery accepts that completed run + # only when its frozen candidate producer succeeded; CI still needs success. + if [[ "$release_candidate" == true && "$run_status" == completed && "$run_conclusion" == failure ]]; then + required_jobs+=("Prepare frozen publication candidate") + elif [[ "$run_status" != "completed" || "$run_conclusion" != "success" ]]; then echo "$workflow run $run_id is $run_status/${run_conclusion:-}, not completed/success" >&2 return 1 fi @@ -168,88 +205,26 @@ required_artifacts_present() { if [[ "${#required_artifacts[@]}" -eq 0 ]]; then required_json='[]' else - required_json="$(printf '%s\n' "${required_artifacts[@]}" | bun -e ' -const names = (await Bun.stdin.text()).split(/\r?\n/u).filter(Boolean); -process.stdout.write(JSON.stringify(names)); -')" + required_json="$(printf '%s\n' "${required_artifacts[@]}" | bun .github/scripts/workflow-run-metadata.mts names)" fi local gate_json if [[ "${#gate_artifacts[@]}" -eq 0 ]]; then gate_json='[]' else - gate_json="$(printf '%s\n' "${gate_artifacts[@]}" | bun -e ' -const names = (await Bun.stdin.text()).split(/\r?\n/u).filter(Boolean); -process.stdout.write(JSON.stringify(names)); -')" + gate_json="$(printf '%s\n' "${gate_artifacts[@]}" | bun .github/scripts/workflow-run-metadata.mts names)" fi local selection status # shellcheck disable=SC2016 if selection="$( REQUIRED_ARTIFACTS_JSON="$required_json" \ - GATE_ARTIFACTS_JSON="$gate_json" \ - bun -e ' -const expected = JSON.parse(process.env.REQUIRED_ARTIFACTS_JSON); -const gates = JSON.parse(process.env.GATE_ARTIFACTS_JSON); -let records; -try { - records = JSON.parse(await Bun.stdin.text()); -} catch (cause) { - console.error(`artifact inventory is not valid JSON: ${cause.message}`); - process.exit(64); -} -if ( - !Array.isArray(expected) - || !Array.isArray(gates) - || expected.length + gates.length === 0 - || [...expected, ...gates].some((name) => typeof name !== "string" || name.length === 0) - || new Set([...expected, ...gates]).size !== expected.length + gates.length -) { - console.error("required artifact identity list is malformed"); - process.exit(64); -} -if (!Array.isArray(records) || records.some((entry) => - entry === null || Array.isArray(entry) || typeof entry !== "object" || - typeof entry.name !== "string" || typeof entry.expired !== "boolean" || - !Number.isSafeInteger(entry.id) || entry.id < 1 || - !Number.isSafeInteger(entry.size_in_bytes) || entry.size_in_bytes < 1 || - typeof entry.digest !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(entry.digest) -)) { - console.error("artifact inventory contains malformed metadata"); - process.exit(64); -} -const selected = []; -const selectedGates = []; -for (const name of [...expected, ...gates]) { - const matches = records.filter((entry) => entry.name === name && entry.expired === false); - if (matches.length !== 1) { - console.error(`expected exactly one non-expired artifact named ${name}; found ${matches.length}`); - process.exit(1); - } - const [entry] = matches; - const record = { - digest: entry.digest, - id: entry.id, - name: entry.name, - size: entry.size_in_bytes, - }; - (expected.includes(name) ? selected : selectedGates).push(record); -} -selected.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0); -selectedGates.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0); -process.stdout.write(JSON.stringify({ selected, selectedGates })); -' <<< "$artifacts_json" + GATE_ARTIFACTS_JSON="$gate_json" \ + bun .github/scripts/workflow-run-metadata.mts select-artifacts <<<"$artifacts_json" )"; then selected_artifacts_json="$( - SELECTION_JSON="$selection" bun -e ' -const value = JSON.parse(process.env.SELECTION_JSON); -process.stdout.write(JSON.stringify(value.selected)); -' + SELECTION_JSON="$selection" bun .github/scripts/workflow-run-metadata.mts selected-artifacts )" selected_gate_artifacts_json="$( - SELECTION_JSON="$selection" bun -e ' -const value = JSON.parse(process.env.SELECTION_JSON); -process.stdout.write(JSON.stringify(value.selectedGates)); -' + SELECTION_JSON="$selection" bun .github/scripts/workflow-run-metadata.mts selected-gates )" else status=$? @@ -268,8 +243,8 @@ required_jobs_success() { local jobs_file jobs_file="$(mktemp)" local status - if github_read "$workflow run $run_id jobs" \ - run view "$run_id" --repo "$GH_REPO" --json jobs > "$jobs_file"; then + if github_paginated_json "$workflow run $run_id jobs" jobs \ + "repos/$GH_REPO/actions/runs/$run_id/jobs?filter=latest" >"$jobs_file"; then : else status=$? @@ -280,26 +255,7 @@ required_jobs_success() { local conclusion # shellcheck disable=SC2016 if ! conclusion="$( - bun -e ' -const fs = require("node:fs"); -const data = JSON.parse(fs.readFileSync(Bun.argv[1], "utf8")); -const required = Bun.argv.slice(2); -if (!Array.isArray(data.jobs)) { - console.error("workflow job inventory must be a list"); - process.exit(1); -} -const failures = required - .map((name) => { - const matches = data.jobs.filter((job) => job?.name === name); - if (matches.length !== 1) return [name, `count-${matches.length}`]; - return [name, matches[0]?.conclusion ?? "missing"]; - }) - .filter(([, conclusion]) => conclusion !== "success"); -if (failures.length > 0) { - console.error(failures.map(([name, conclusion]) => `${name}=${conclusion}`).join(", ")); - process.exit(1); -} -' "$jobs_file" "${required_jobs[@]}" + bun .github/scripts/workflow-run-metadata.mts jobs "$jobs_file" "${required_jobs[@]}" )"; then rm -f "$jobs_file" return 1 @@ -329,6 +285,59 @@ candidate_satisfies_gate() { status=$? return "$status" fi + if [[ -n "$qualification_products" ]]; then + local directory="$qualification_scratch/run-$run_id" + bash .github/scripts/download-build-artifacts.sh CI "$sha" "$directory" --run-id "$run_id" --job Qualified --artifact oliphaunt-release-candidate || return 64 + EXPECTED_SHA="$sha" EXPECTED_RUN_ID="$run_id" EXPECTED_RUN_ATTEMPT="$selected_run_attempt" PRODUCTS_JSON="$qualification_products" \ + bun .github/scripts/workflow-run-metadata.mts qualification-coverage "$directory/oliphaunt-release-candidate.json" || { + status=$? + [[ "$status" == 3 ]] && return 1 + return 64 + } + fi +} + +request_missing_qualification() { + # Active work may become a covering proof; never dispatch beside it. + if awk -F '\t' '$2 != "completed" && $6 == "causal" { found=1 } END { exit found ? 0 : 1 }' <<<"$runs"; then + if [[ "$qualification_plan" == true ]]; then + echo 'qualification_request_required=false' >>"$GITHUB_OUTPUT" + exit 0 + fi + return + fi + local failed + failed="$(awk -F '\t' '$2 == "completed" && $3 != "success" && $6 == "causal" { print $4; exit }' <<<"$runs")" + if [[ -n "$failed" ]]; then + echo "candidate qualification failed: $failed; fix the cause or rerun that run, rather than dispatching another qualification" >&2 + exit 1 + fi + if [[ "$qualification_plan" == true ]]; then + echo 'qualification_request_required=true' >>"$GITHUB_OUTPUT" + exit 0 + fi + if [[ "$qualification_wait" == true ]]; then return; fi + if [[ "$qualification_dispatch" == true ]] && awk -F '\t' '$2 == "completed" && $3 == "success" && $7 == "requested" { found=1 } END { exit found ? 0 : 1 }' <<<"$runs"; then return; fi + local main_sha response requested_id row run_sha run_workflow rest + main_sha="$(github_read 'main ref before qualification request' "repos/$GH_REPO/git/ref/heads/main" main-sha)" || exit $? + if [[ "$main_sha" != "$sha" ]]; then + echo "cannot request missing qualification for $sha: main is $main_sha; reuse or rerun an existing exact-source CI run" >&2 + exit 1 + fi + EXPECTED_SHA="$sha" PRODUCTS_JSON="$qualification_products" bun .github/scripts/workflow-run-metadata.mts qualification-request >"$qualification_scratch/request.json" + # Dispatch is a mutation: never apply the read retry policy to an ambiguous POST. + if ! response="$(gh api --method POST -H 'X-GitHub-Api-Version: 2026-03-10' "repos/$GH_REPO/actions/workflows/$workflow_id/dispatches" --input "$qualification_scratch/request.json")"; then + echo "qualification dispatch outcome is unknown; inspect CI request $QUALIFICATION_REQUEST_KEY before resuming" >&2 + exit 1 + fi + requested_id="$(bun .github/scripts/workflow-run-metadata.mts dispatch-run-id <<<"$response")" || exit 1 + echo "requested qualification: https://github.com/$GH_REPO/actions/runs/$requested_id" + row="$(github_read "requested qualification run $requested_id" "repos/$GH_REPO/actions/runs/$requested_id" run-row)" || exit $? + IFS=$'\t' read -r run_sha run_workflow rest <<<"$row" + if [[ "$run_sha" != "$sha" || "$run_workflow" != "$workflow_id" ]]; then + echo "qualification dispatch source changed; refusing run $requested_id for $run_sha" >&2 + exit 1 + fi } resolve_workflow_id() { @@ -342,26 +351,7 @@ resolve_workflow_id() { # Resolve the immutable workflow id from the exact display name. This avoids # gh run list's arbitrary latest-N truncation and refuses ambiguous names. # shellcheck disable=SC2016 - WORKFLOW_NAME="$workflow" bun -e ' -const expected = process.env.WORKFLOW_NAME; -let rows; -try { - rows = JSON.parse(await Bun.stdin.text()); -} catch (cause) { - console.error(`workflow inventory is not valid JSON: ${cause.message}`); - process.exit(1); -} -if (!Array.isArray(rows)) { - console.error("workflow inventory must be a list"); - process.exit(1); -} -const matches = rows.filter((row) => row?.name === expected); -if (matches.length !== 1 || !Number.isSafeInteger(matches[0]?.id) || matches[0].id < 1) { - console.error(`expected exactly one workflow named ${expected}; found ${matches.length}`); - process.exit(1); -} -process.stdout.write(String(matches[0].id)); -' <<< "$workflows_json" || return 64 + WORKFLOW_NAME="$workflow" bun .github/scripts/workflow-run-metadata.mts workflow-id <<<"$workflows_json" || return 64 } exact_sha_workflow_runs() { @@ -374,39 +364,7 @@ exact_sha_workflow_runs() { "repos/$GH_REPO/actions/workflows/$workflow_id/runs?head_sha=$sha" )" || return $? # shellcheck disable=SC2016 - EXPECTED_SHA="$(printf '%s' "$sha" | normalize_sha)" bun -e ' -const expectedSha = process.env.EXPECTED_SHA; -let rows; -try { - rows = JSON.parse(await Bun.stdin.text()); -} catch (cause) { - console.error(`workflow run inventory is not valid JSON: ${cause.message}`); - process.exit(1); -} -if (!Array.isArray(rows)) { - console.error("workflow run inventory must be a list"); - process.exit(1); -} -const ids = new Set(); -const rendered = []; -for (const row of rows) { - const conclusion = row?.conclusion ?? ""; - if ( - row === null || Array.isArray(row) || typeof row !== "object" || - !Number.isSafeInteger(row.id) || row.id < 1 || ids.has(row.id) || - typeof row.head_sha !== "string" || row.head_sha.toLowerCase() !== expectedSha || - typeof row.status !== "string" || typeof conclusion !== "string" || - typeof row.html_url !== "string" || /[\t\r\n]/u.test(row.html_url) || - typeof row.event !== "string" || /[\t\r\n]/u.test(row.event) - ) { - console.error("workflow run inventory contains malformed, duplicate, or non-exact-SHA metadata"); - process.exit(1); - } - ids.add(row.id); - rendered.push([row.id, row.status, conclusion, row.html_url, row.event].join("\t")); -} -process.stdout.write(rendered.join("\n")); -' <<< "$runs_json" || return 64 + EXPECTED_SHA="$(printf '%s' "$sha" | normalize_sha)" bun .github/scripts/workflow-run-metadata.mts runs <<<"$runs_json" || return 64 } if [[ -n "$expected_run_id" ]]; then @@ -440,8 +398,9 @@ while true; do workflow_id="" fi fi + inventory_ready=false if [[ -n "$workflow_id" ]] && runs="$(exact_sha_workflow_runs "$workflow_id")"; then - : + inventory_ready=true else status=$? if [[ "$status" -eq 64 ]]; then @@ -455,6 +414,7 @@ while true; do echo "$runs" candidate_run_ids="$(echo "$runs" | awk -F '\t' '$2 == "completed" && $3 == "success" { print $1 }')" for run_id in $candidate_run_ids; do + [[ "$qualification_dispatch" == false ]] || break if candidate_satisfies_gate "$run_id"; then emit_run_id "$run_id" exit 0 @@ -482,6 +442,10 @@ while true; do else echo "waiting for $workflow workflow for $sha" fi + if [[ -n "$qualification_products" && "$inventory_ready" == true ]]; then + request_missing_qualification + [[ "$qualification_dispatch" == false ]] || exit 0 + fi if [ "$SECONDS" -ge "$deadline" ]; then echo "timed out waiting for successful $workflow workflow for $sha" >&2 exit 1 diff --git a/.github/scripts/resolve-mobile-e2e.mjs b/.github/scripts/resolve-mobile-e2e.mjs deleted file mode 100644 index 14cc32260..000000000 --- a/.github/scripts/resolve-mobile-e2e.mjs +++ /dev/null @@ -1,300 +0,0 @@ -#!/usr/bin/env bun -import { appendFileSync } from "node:fs"; -import { env, exit } from "node:process"; - -import { - retryReadOperationSync, - runGitHubPaginatedJsonSync, - runGitHubReadSync, -} from "../../tools/release/github-read.mjs"; -import { captureCommandOutput } from "../../tools/dev/capture-command-output.mjs"; - -const FULL_SHA = /^[0-9a-f]{40}$/u; -const FULL_SHA_INPUT = /^[0-9a-f]{40}$/iu; -const RUN_ID = /^[1-9][0-9]*$/u; -const MOBILE_ARTIFACTS = Object.freeze({ - android: "react-native-mobile-android-app-android-x86_64", - ios: "react-native-mobile-ios-app", -}); - -function run(command, args, { environment = process.env } = {}) { - const result = captureCommandOutput(command, args, { - env: environment, - label: `${command} ${args.join(" ")}`, - }); - if (result.error) { - throw new Error(result.error.message); - } - if (result.status !== 0) { - const detail = [result.stdout, result.stderr] - .map((value) => value?.trimEnd()) - .filter(Boolean) - .join("\n"); - throw new Error( - `${command} ${args.join(" ")} failed with exit code ${result.status}` + - (detail ? `:\n${detail}` : ""), - ); - } - return result.stdout; -} - -function parsedJson(output, label) { - const text = output.trim(); - if (!text) return null; - try { - return JSON.parse(text); - } catch (error) { - throw new Error(`${label} returned invalid JSON: ${error.message}`); - } -} - -function outputWriter(environment) { - return (name, value) => { - const rendered = `${name}=${value}\n`; - if (environment.GITHUB_OUTPUT) { - appendFileSync(environment.GITHUB_OUTPUT, rendered, "utf8"); - } else { - process.stdout.write(rendered); - } - }; -} - -export function mobilePlatformSelection(value = "all") { - if (!new Set(["all", "android", "ios"]).has(value)) { - throw new Error( - `unsupported mobile E2E platform ${JSON.stringify(value)}; expected all, android, or ios`, - ); - } - return { - android: value === "all" || value === "android", - ios: value === "all" || value === "ios", - }; -} - -export function githubResolverDependencies( - repo, - { execute = undefined, retryOptions = {} } = {}, -) { - const executeLocal = execute ?? ((command, args) => run(command, args)); - const ghRead = (args, label) => { - if (execute === undefined) { - return runGitHubReadSync(args, { label, ...retryOptions }); - } - return retryReadOperationSync( - label, - () => execute("gh", args), - retryOptions, - ); - }; - const paginationSpawn = execute === undefined - ? undefined - : (command, args) => { - try { - return { - status: 0, - stderr: "", - stdout: execute(command, args), - }; - } catch (error) { - return { - status: 1, - stderr: error instanceof Error ? error.message : String(error), - stdout: "", - }; - } - }; - const ghJson = (args, label) => parsedJson(ghRead(args, label), label); - return { - checkoutSha() { - return executeLocal("git", ["rev-parse", "HEAD^{commit}"]).trim(); - }, - listRuns(sha) { - return ghJson( - [ - "run", - "list", - "--repo", - repo, - "--workflow", - "ci.yml", - "--commit", - sha, - "--limit", - "100", - "--json", - "databaseId,status,conclusion,headSha", - ], - "gh run list", - ); - }, - gateSucceeded(runId, gateJobName) { - const data = ghJson( - ["run", "view", String(runId), "--repo", repo, "--json", "jobs"], - "gh run view", - ); - if (!Array.isArray(data?.jobs)) { - throw new Error(`CI run ${runId} jobs must be a list`); - } - const matches = data.jobs.filter((job) => job?.name === gateJobName); - return matches.length === 1 && matches[0]?.conclusion === "success"; - }, - artifactNames(runId) { - const label = `CI run ${runId} mobile artifact inventory`; - const artifacts = runGitHubPaginatedJsonSync( - `repos/${repo}/actions/runs/${runId}/artifacts`, - { - ...retryOptions, - itemsField: "artifacts", - label, - ...(paginationSpawn === undefined ? {} : { spawn: paginationSpawn }), - }, - ); - return artifacts - .map((artifact) => { - if ( - artifact === null - || Array.isArray(artifact) - || typeof artifact !== "object" - || typeof artifact.name !== "string" - || artifact.name.length === 0 - || typeof artifact.expired !== "boolean" - ) { - throw new Error(`${label} contains malformed artifact metadata`); - } - return artifact; - }) - .filter((artifact) => artifact.expired === false) - .map((artifact) => artifact.name); - }, - }; -} - -function stringCounts(value, label) { - if (value === null || value === undefined || typeof value[Symbol.iterator] !== "function") { - throw new Error(`${label} must be an iterable of artifact names`); - } - const result = new Map(); - for (const item of value) { - if (typeof item !== "string" || item.length === 0) { - throw new Error(`${label} contains an invalid artifact name`); - } - result.set(item, (result.get(item) ?? 0) + 1); - } - return result; -} - -export function resolveMobileE2e( - { - repo, - requestedPlatform = "all", - requestedSha, - defaultSha, - gateJobName = "Builds", - }, - dependencies, -) { - if (typeof repo !== "string" || repo.length === 0) { - throw new Error("GH_REPO is required"); - } - if (!dependencies || typeof dependencies !== "object") { - throw new Error("mobile E2E resolver dependencies are required"); - } - const requested = mobilePlatformSelection(requestedPlatform); - const inputSha = requestedSha || defaultSha; - if (!inputSha) { - throw new Error("an input SHA or default SHA is required"); - } - if (!FULL_SHA_INPUT.test(inputSha)) { - throw new Error(`mobile E2E input must be a full commit SHA: ${inputSha}`); - } - - const sha = String(dependencies.checkoutSha()).trim(); - if (!FULL_SHA.test(sha)) { - throw new Error(`checked-out mobile E2E commit is not a full SHA: ${sha}`); - } - if (sha !== inputSha.toLowerCase()) { - throw new Error(`checked-out mobile E2E commit ${sha} does not match requested SHA ${inputSha}`); - } - - const runs = dependencies.listRuns(sha); - if (runs !== null && !Array.isArray(runs)) { - throw new Error("gh run list must return a JSON array"); - } - const candidateIds = []; - const seenRunIds = new Set(); - for (const candidate of runs ?? []) { - if (candidate?.status !== "completed" || candidate?.conclusion !== "success") continue; - if (!FULL_SHA.test(candidate.headSha ?? "")) { - throw new Error("successful CI run metadata is missing a full lowercase headSha"); - } - if (candidate.headSha !== sha) continue; - const runId = String(candidate.databaseId ?? ""); - if (!RUN_ID.test(runId)) { - throw new Error(`successful CI run for ${sha} has invalid databaseId ${JSON.stringify(candidate.databaseId)}`); - } - if (!seenRunIds.has(runId)) { - seenRunIds.add(runId); - candidateIds.push(runId); - } - } - - for (const runId of candidateIds) { - if (dependencies.gateSucceeded(runId, gateJobName) !== true) continue; - const names = stringCounts(dependencies.artifactNames(runId), `CI run ${runId} artifacts`); - const selected = { - android: requested.android && names.get(MOBILE_ARTIFACTS.android) === 1, - ios: requested.ios && names.get(MOBILE_ARTIFACTS.ios) === 1, - }; - if (Object.entries(requested).every(([platform, wanted]) => !wanted || selected[platform])) { - return { - android: selected.android, - ios: selected.ios, - platformJobs: [ - ...(selected.android ? ["android"] : []), - ...(selected.ios ? ["ios"] : []), - ], - runId, - sha, - }; - } - } - - throw new Error(`No successful CI run for ${sha} contains requested mobile app artifacts.`); -} - -export function runMobileE2eResolver({ - environment = env, - dependencies = undefined, - writeOutput = undefined, -} = {}) { - const repo = environment.GH_REPO; - const resolved = resolveMobileE2e( - { - defaultSha: environment.DEFAULT_SHA, - gateJobName: environment.BUILD_GATE_JOB || "Builds", - repo, - requestedPlatform: environment.INPUT_PLATFORM || "all", - requestedSha: environment.INPUT_SHA, - }, - dependencies ?? - githubResolverDependencies(repo, { - execute: (command, args) => run(command, args, { environment }), - }), - ); - const emit = writeOutput ?? outputWriter(environment); - emit("sha", resolved.sha); - emit("run_id", resolved.runId); - emit("android", String(resolved.android)); - emit("ios", String(resolved.ios)); - emit("platform_jobs", JSON.stringify(resolved.platformJobs)); - return resolved; -} - -if (import.meta.main) { - try { - runMobileE2eResolver(); - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - exit(1); - } -} diff --git a/.github/scripts/resolve-mobile-e2e.mts b/.github/scripts/resolve-mobile-e2e.mts new file mode 100644 index 000000000..9531f3e63 --- /dev/null +++ b/.github/scripts/resolve-mobile-e2e.mts @@ -0,0 +1,234 @@ +#!/usr/bin/env bun +import { appendFileSync } from 'node:fs'; +import { env, exit } from 'node:process'; + +import { requestGithubJsonWithRetry } from '../../tools/release/github-read.mts'; + +const FULL_SHA = /^[0-9a-f]{40}$/u; +const FULL_SHA_INPUT = /^[0-9a-f]{40}$/iu; +const RUN_ID = /^[1-9][0-9]*$/u; +const MOBILE_ARTIFACTS = Object.freeze({ + android: 'react-native-mobile-android-app-android-x86_64', + ios: 'react-native-mobile-ios-app', +}); + +function outputWriter(environment) { + return (name, value) => { + const rendered = `${name}=${value}\n`; + if (environment.GITHUB_OUTPUT) { + appendFileSync(environment.GITHUB_OUTPUT, rendered, 'utf8'); + } else { + process.stdout.write(rendered); + } + }; +} + +export function mobilePlatformSelection(value = 'all') { + if (!new Set(['all', 'android', 'ios']).has(value)) { + throw new Error( + `unsupported mobile E2E platform ${JSON.stringify(value)}; expected all, android, or ios`, + ); + } + return { + android: value === 'all' || value === 'android', + ios: value === 'all' || value === 'ios', + }; +} + +export function githubResolverDependencies(repo, { environment = env, retryOptions = {} } = {}) { + if (!/^[A-Za-z0-9][A-Za-z0-9_.-]*\/[A-Za-z0-9][A-Za-z0-9_.-]*$/u.test(repo ?? '')) + throw new Error('GH_REPO must be owner/repository'); + const api = (environment.GITHUB_API_URL || 'https://api.github.com').replace(/\/$/u, ''); + const read = (endpoint) => + requestGithubJsonWithRetry(api + '/repos/' + repo + '/' + endpoint, { + ...retryOptions, + authToken: environment.GH_TOKEN || environment.GITHUB_TOKEN, + }); + async function pages(endpoint, field) { + const result = []; + let expected; + for (let page = 1; page <= 1000; page++) { + const data = await read( + endpoint + (endpoint.includes('?') ? '&' : '?') + 'per_page=100&page=' + page, + ); + if ( + !Number.isSafeInteger(data?.total_count) || + data.total_count < 0 || + !Array.isArray(data[field]) || + data[field].length > 100 + ) + throw new Error('malformed GitHub ' + field + ' inventory'); + expected ??= data.total_count; + if (data.total_count !== expected) + throw new Error('GitHub ' + field + ' inventory changed during pagination'); + result.push(...data[field]); + if (result.length === expected) return result; + if (result.length > expected || data[field].length === 0) + throw new Error('incomplete GitHub ' + field + ' inventory'); + } + throw new Error('GitHub ' + field + ' inventory exceeds 1000 pages'); + } + return { + checkoutSha: () => environment.CHECKOUT_SHA, + async listRuns(sha) { + const data = await read('actions/workflows/ci.yml/runs?head_sha=' + sha + '&per_page=100'); + if (!Array.isArray(data?.workflow_runs)) throw new Error('CI workflow runs must be a list'); + return data.workflow_runs.map((row) => ({ + databaseId: row.id, + headSha: row.head_sha, + status: row.status, + conclusion: row.conclusion, + })); + }, + async gateSucceeded(runId, gateJobName) { + const jobs = await pages('actions/runs/' + runId + '/jobs?filter=latest', 'jobs'); + const matches = jobs.filter((job) => job?.name === gateJobName); + return matches.length === 1 && matches[0]?.conclusion === 'success'; + }, + async artifactNames(runId) { + const artifacts = await pages('actions/runs/' + runId + '/artifacts', 'artifacts'); + return artifacts + .map((artifact) => { + if ( + artifact === null || + typeof artifact !== 'object' || + typeof artifact.name !== 'string' || + artifact.name.length === 0 || + typeof artifact.expired !== 'boolean' + ) + throw new Error('CI run ' + runId + ' contains malformed artifact metadata'); + return artifact; + }) + .filter((artifact) => !artifact.expired) + .map((artifact) => artifact.name); + }, + }; +} + +function stringCounts(value, label) { + if (value === null || value === undefined || typeof value[Symbol.iterator] !== 'function') { + throw new Error(`${label} must be an iterable of artifact names`); + } + const result = new Map(); + for (const item of value) { + if (typeof item !== 'string' || item.length === 0) { + throw new Error(`${label} contains an invalid artifact name`); + } + result.set(item, (result.get(item) ?? 0) + 1); + } + return result; +} + +export async function resolveMobileE2e( + { repo, requestedPlatform = 'all', requestedSha, defaultSha, gateJobName = 'Builds' }, + dependencies, +) { + if (typeof repo !== 'string' || repo.length === 0) { + throw new Error('GH_REPO is required'); + } + if (!dependencies || typeof dependencies !== 'object') { + throw new Error('mobile E2E resolver dependencies are required'); + } + const requested = mobilePlatformSelection(requestedPlatform); + const inputSha = requestedSha || defaultSha; + if (!inputSha) { + throw new Error('an input SHA or default SHA is required'); + } + if (!FULL_SHA_INPUT.test(inputSha)) { + throw new Error(`mobile E2E input must be a full commit SHA: ${inputSha}`); + } + + const sha = String(dependencies.checkoutSha()).trim(); + if (!FULL_SHA.test(sha)) { + throw new Error(`checked-out mobile E2E commit is not a full SHA: ${sha}`); + } + if (sha !== inputSha.toLowerCase()) { + throw new Error( + `checked-out mobile E2E commit ${sha} does not match requested SHA ${inputSha}`, + ); + } + + const runs = await dependencies.listRuns(sha); + if (runs !== null && !Array.isArray(runs)) { + throw new Error('gh run list must return a JSON array'); + } + const candidateIds = []; + const seenRunIds = new Set(); + for (const candidate of runs ?? []) { + if (candidate?.status !== 'completed' || candidate?.conclusion !== 'success') continue; + if (!FULL_SHA.test(candidate.headSha ?? '')) { + throw new Error('successful CI run metadata is missing a full lowercase headSha'); + } + if (candidate.headSha !== sha) continue; + const runId = String(candidate.databaseId ?? ''); + if (!RUN_ID.test(runId)) { + throw new Error( + `successful CI run for ${sha} has invalid databaseId ${JSON.stringify(candidate.databaseId)}`, + ); + } + if (!seenRunIds.has(runId)) { + seenRunIds.add(runId); + candidateIds.push(runId); + } + } + + for (const runId of candidateIds) { + if ((await dependencies.gateSucceeded(runId, gateJobName)) !== true) continue; + const names = stringCounts( + await dependencies.artifactNames(runId), + `CI run ${runId} artifacts`, + ); + const selected = { + android: requested.android && names.get(MOBILE_ARTIFACTS.android) === 1, + ios: requested.ios && names.get(MOBILE_ARTIFACTS.ios) === 1, + }; + if (Object.entries(requested).every(([platform, wanted]) => !wanted || selected[platform])) { + return { + android: selected.android, + ios: selected.ios, + platformJobs: [...(selected.android ? ['android'] : []), ...(selected.ios ? ['ios'] : [])], + runId, + sha, + }; + } + } + + throw new Error(`No successful CI run for ${sha} contains requested mobile app artifacts.`); +} + +export async function runMobileE2eResolver({ + environment = env, + dependencies = undefined, + writeOutput = undefined, +} = {}) { + const repo = environment.GH_REPO; + const resolved = await resolveMobileE2e( + { + defaultSha: environment.DEFAULT_SHA, + gateJobName: environment.BUILD_GATE_JOB || 'Builds', + repo, + requestedPlatform: environment.INPUT_PLATFORM || 'all', + requestedSha: environment.INPUT_SHA, + }, + dependencies ?? + githubResolverDependencies(repo, { + environment, + }), + ); + const emit = writeOutput ?? outputWriter(environment); + emit('sha', resolved.sha); + emit('run_id', resolved.runId); + emit('android', String(resolved.android)); + emit('ios', String(resolved.ios)); + emit('platform_jobs', JSON.stringify(resolved.platformJobs)); + return resolved; +} + +if (import.meta.main) { + try { + await runMobileE2eResolver(); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + exit(1); + } +} diff --git a/.github/scripts/resolve-mobile-e2e.test.mjs b/.github/scripts/resolve-mobile-e2e.test.mjs deleted file mode 100644 index 220a14afa..000000000 --- a/.github/scripts/resolve-mobile-e2e.test.mjs +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - githubResolverDependencies, - resolveMobileE2e, - runMobileE2eResolver, -} from "./resolve-mobile-e2e.mjs"; - -const SHA = "a".repeat(40); -const OTHER_SHA = "b".repeat(40); -const ANDROID_ARTIFACT = "react-native-mobile-android-app-android-x86_64"; -const IOS_ARTIFACT = "react-native-mobile-ios-app"; - -function successfulRun(databaseId, headSha = SHA) { - return { conclusion: "success", databaseId, headSha, status: "completed" }; -} - -function includedArtifactInventory(...names) { - return `HTTP/2.0 200 OK\n\n${JSON.stringify({ - artifacts: names.map((name) => ({ expired: false, name })), - })}`; -} - -function dependencies({ - sha = SHA, - runs = [successfulRun(101)], - gates = new Map([["101", true]]), - artifacts = new Map([["101", new Set([ANDROID_ARTIFACT, IOS_ARTIFACT])]]), -} = {}) { - const calls = { artifacts: [], gates: [], listRuns: [] }; - return { - calls, - checkoutSha: () => sha, - listRuns(value) { - calls.listRuns.push(value); - return runs; - }, - gateSucceeded(runId, gateJobName) { - calls.gates.push([runId, gateJobName]); - return gates.get(runId) ?? false; - }, - artifactNames(runId) { - calls.artifacts.push(runId); - return artifacts.get(runId) ?? new Set(); - }, - }; -} - -function resolve(options = {}, injected = dependencies()) { - return resolveMobileE2e( - { - repo: "f0rr0/oliphaunt", - requestedPlatform: "all", - requestedSha: SHA, - ...options, - }, - injected, - ); -} - -test("resolves only an exact-SHA successful run with the successful aggregate build gate", () => { - const injected = dependencies({ - runs: [ - successfulRun(1, OTHER_SHA), - { ...successfulRun(2), status: "in_progress", conclusion: null }, - { ...successfulRun(3), conclusion: "failure" }, - successfulRun(4), - successfulRun(5), - successfulRun(6), - ], - gates: new Map([ - ["4", false], - ["5", true], - ["6", true], - ]), - artifacts: new Map([ - ["5", new Set([ANDROID_ARTIFACT])], - ["6", new Set([ANDROID_ARTIFACT, IOS_ARTIFACT])], - ]), - }); - assert.deepEqual(resolve({}, injected), { - android: true, - ios: true, - platformJobs: ["android", "ios"], - runId: "6", - sha: SHA, - }); - assert.deepEqual(injected.calls.listRuns, [SHA]); - assert.deepEqual(injected.calls.gates, [ - ["4", "Builds"], - ["5", "Builds"], - ["6", "Builds"], - ]); - assert.deepEqual(injected.calls.artifacts, ["5", "6"]); -}); - -test("platform selection requires only the exact requested artifact identity", () => { - const androidOnly = dependencies({ - artifacts: new Map([["101", new Set([ANDROID_ARTIFACT, `${IOS_ARTIFACT}-near-match`])]]), - }); - assert.deepEqual(resolve({ requestedPlatform: "android" }, androidOnly).platformJobs, ["android"]); - - const iosOnly = dependencies({ - artifacts: new Map([["101", new Set([IOS_ARTIFACT, `${ANDROID_ARTIFACT}-near-match`])]]), - }); - assert.deepEqual(resolve({ requestedPlatform: "ios" }, iosOnly).platformJobs, ["ios"]); - - assert.throws( - () => resolve({}, androidOnly), - /contains requested mobile app artifacts/u, - ); - assert.throws( - () => resolve({}, iosOnly), - /contains requested mobile app artifacts/u, - ); -}); - -test("rejects abbreviated, malformed, mismatched, or non-canonical checkout SHAs", () => { - for (const requestedSha of ["a".repeat(39), `${"a".repeat(40)}0`, "not-a-sha"]) { - assert.throws( - () => resolve({ requestedSha }, dependencies()), - /input must be a full commit SHA/u, - ); - } - assert.throws( - () => resolve({ requestedSha: OTHER_SHA }, dependencies()), - /does not match requested SHA/u, - ); - assert.throws( - () => resolve({}, dependencies({ sha: SHA.toUpperCase() })), - /checked-out mobile E2E commit is not a full SHA/u, - ); - assert.equal(resolve({ requestedSha: SHA.toUpperCase() }).sha, SHA); -}); - -test("fails closed on malformed successful-run metadata and artifact responses", () => { - assert.throws( - () => resolve({}, dependencies({ runs: [successfulRun(undefined)] })), - /invalid databaseId/u, - ); - assert.throws( - () => resolve({}, dependencies({ runs: [{ ...successfulRun(1), headSha: "abc" }] })), - /missing a full lowercase headSha/u, - ); - assert.throws( - () => resolve({}, dependencies({ runs: {} })), - /gh run list must return a JSON array/u, - ); - assert.throws( - () => resolve({}, dependencies({ artifacts: new Map([["101", [ANDROID_ARTIFACT, null]]]) })), - /invalid artifact name/u, - ); -}); - -test("deduplicates repeated attempts and preserves GitHub run ordering", () => { - const injected = dependencies({ - runs: [successfulRun(201), successfulRun(201), successfulRun(202)], - gates: new Map([ - ["201", true], - ["202", true], - ]), - artifacts: new Map([ - ["201", new Set([ANDROID_ARTIFACT])], - ["202", new Set([ANDROID_ARTIFACT, IOS_ARTIFACT])], - ]), - }); - assert.equal(resolve({}, injected).runId, "202"); - assert.deepEqual(injected.calls.gates, [ - ["201", "Builds"], - ["202", "Builds"], - ]); -}); - -test("skips ambiguous duplicate gate and artifact identities", () => { - const duplicateArtifacts = dependencies({ - runs: [successfulRun(301), successfulRun(302)], - gates: new Map([ - ["301", true], - ["302", true], - ]), - artifacts: new Map([ - ["301", [ANDROID_ARTIFACT, ANDROID_ARTIFACT, IOS_ARTIFACT]], - ["302", [ANDROID_ARTIFACT, IOS_ARTIFACT]], - ]), - }); - assert.equal(resolve({}, duplicateArtifacts).runId, "302"); - - const commands = []; - const adapter = githubResolverDependencies("f0rr0/oliphaunt", { - execute(command, args) { - commands.push([command, args]); - if (command === "git") return `${SHA}\n`; - if (args[0] === "run" && args[1] === "list") return JSON.stringify([successfulRun(303)]); - if (args[0] === "run" && args[1] === "view") { - return JSON.stringify({ jobs: [ - { conclusion: "success", name: "Builds" }, - { conclusion: "success", name: "Builds" }, - ] }); - } - return `${ANDROID_ARTIFACT}\n${IOS_ARTIFACT}\n`; - }, - }); - assert.throws(() => resolve({}, adapter), /contains requested mobile app artifacts/u); - assert.equal(commands.some(([, args]) => args[0] === "api"), false); -}); - -test("environment entry point emits the complete exact resolver contract", () => { - const emitted = []; - const result = runMobileE2eResolver({ - environment: { - BUILD_GATE_JOB: "Builds", - GH_REPO: "f0rr0/oliphaunt", - INPUT_PLATFORM: "ios", - INPUT_SHA: SHA, - }, - dependencies: dependencies({ artifacts: new Map([["101", new Set([IOS_ARTIFACT])]]) }), - writeOutput: (name, value) => emitted.push([name, value]), - }); - assert.deepEqual(result.platformJobs, ["ios"]); - assert.deepEqual(emitted, [ - ["sha", SHA], - ["run_id", "101"], - ["android", "false"], - ["ios", "true"], - ["platform_jobs", '["ios"]'], - ]); -}); - -test("production adapter pins repository, exact commit, gate run, and non-expired artifacts", () => { - const commands = []; - const execute = (command, args) => { - commands.push([command, args]); - if (command === "git") return `${SHA}\n`; - if (args[0] === "run" && args[1] === "list") { - return JSON.stringify([successfulRun(901)]); - } - if (args[0] === "run" && args[1] === "view") { - return JSON.stringify({ jobs: [{ conclusion: "success", name: "Builds" }] }); - } - return includedArtifactInventory(ANDROID_ARTIFACT, IOS_ARTIFACT); - }; - const result = resolve({}, githubResolverDependencies("f0rr0/oliphaunt", { execute })); - assert.equal(result.runId, "901"); - - const list = commands.find(([command, args]) => command === "gh" && args[1] === "list")[1]; - assert.deepEqual(list.slice(0, 6), ["run", "list", "--repo", "f0rr0/oliphaunt", "--workflow", "ci.yml"]); - assert.equal(list[list.indexOf("--commit") + 1], SHA); - assert.equal(list[list.indexOf("--limit") + 1], "100"); - assert.equal(list[list.indexOf("--json") + 1], "databaseId,status,conclusion,headSha"); - - const view = commands.find(([command, args]) => command === "gh" && args[1] === "view")[1]; - assert.deepEqual(view.slice(0, 5), ["run", "view", "901", "--repo", "f0rr0/oliphaunt"]); - assert.equal(view[view.indexOf("--json") + 1], "jobs"); - - const artifacts = commands.find(([command, args]) => command === "gh" && args[0] === "api")[1]; - assert.equal(artifacts[1], "--include"); - assert.equal( - artifacts[2], - "repos/f0rr0/oliphaunt/actions/runs/901/artifacts?per_page=100&page=1", - ); -}); - -test("production adapter survives a transient GitHub read without weakening exact identity", () => { - let listAttempts = 0; - const execute = (command, args) => { - if (command === "git") return `${SHA}\n`; - if (args[0] === "run" && args[1] === "list") { - listAttempts += 1; - if (listAttempts === 1) throw new Error("HTTP 503 temporary failure"); - return JSON.stringify([successfulRun(902)]); - } - if (args[0] === "run" && args[1] === "view") { - return JSON.stringify({ jobs: [{ conclusion: "success", name: "Builds" }] }); - } - return includedArtifactInventory(ANDROID_ARTIFACT, IOS_ARTIFACT); - }; - const resolved = resolve( - {}, - githubResolverDependencies("f0rr0/oliphaunt", { - execute, - retryOptions: { - baseDelayMs: 0, - deadlineMs: 100, - maxAttempts: 2, - maxDelayMs: 0, - }, - }), - ); - assert.equal(resolved.runId, "902"); - assert.equal(resolved.sha, SHA); - assert.equal(listAttempts, 2); -}); diff --git a/.github/scripts/resolve-mobile-e2e.test.mts b/.github/scripts/resolve-mobile-e2e.test.mts new file mode 100644 index 000000000..733fdd2dd --- /dev/null +++ b/.github/scripts/resolve-mobile-e2e.test.mts @@ -0,0 +1,296 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { + githubResolverDependencies, + resolveMobileE2e, + runMobileE2eResolver, +} from './resolve-mobile-e2e.mts'; +const SHA = 'a'.repeat(40); +const OTHER_SHA = 'b'.repeat(40); +const ANDROID_ARTIFACT = 'react-native-mobile-android-app-android-x86_64'; +const IOS_ARTIFACT = 'react-native-mobile-ios-app'; +function successfulRun(databaseId, headSha = SHA) { + return { conclusion: 'success', databaseId, headSha, status: 'completed' }; +} +function dependencies({ + sha = SHA, + runs = [successfulRun(101)], + gates = new Map([['101', true]]), + artifacts = new Map([['101', new Set([ANDROID_ARTIFACT, IOS_ARTIFACT])]]), +} = {}) { + const calls = { artifacts: [], gates: [], listRuns: [] }; + return { + calls, + checkoutSha: () => sha, + listRuns(value) { + calls.listRuns.push(value); + return runs; + }, + gateSucceeded(runId, gateJobName) { + calls.gates.push([runId, gateJobName]); + return gates.get(runId) ?? false; + }, + artifactNames(runId) { + calls.artifacts.push(runId); + return artifacts.get(runId) ?? new Set(); + }, + }; +} +function resolve(options = {}, injected = dependencies()) { + return resolveMobileE2e( + { + repo: 'f0rr0/oliphaunt', + requestedPlatform: 'all', + requestedSha: SHA, + ...options, + }, + injected, + ); +} +test('resolves only an exact-SHA successful run with the successful aggregate build gate', async () => { + const injected = dependencies({ + runs: [ + successfulRun(1, OTHER_SHA), + { ...successfulRun(2), status: 'in_progress', conclusion: null }, + { ...successfulRun(3), conclusion: 'failure' }, + successfulRun(4), + successfulRun(5), + successfulRun(6), + ], + gates: new Map([ + ['4', false], + ['5', true], + ['6', true], + ]), + artifacts: new Map([ + ['5', new Set([ANDROID_ARTIFACT])], + ['6', new Set([ANDROID_ARTIFACT, IOS_ARTIFACT])], + ]), + }); + assert.deepEqual(await resolve({}, injected), { + android: true, + ios: true, + platformJobs: ['android', 'ios'], + runId: '6', + sha: SHA, + }); + assert.deepEqual(injected.calls.listRuns, [SHA]); + assert.deepEqual(injected.calls.gates, [ + ['4', 'Builds'], + ['5', 'Builds'], + ['6', 'Builds'], + ]); + assert.deepEqual(injected.calls.artifacts, ['5', '6']); +}); +test('platform selection requires only the exact requested artifact identity', async () => { + const androidOnly = dependencies({ + artifacts: new Map([['101', new Set([ANDROID_ARTIFACT, `${IOS_ARTIFACT}-near-match`])]]), + }); + assert.deepEqual((await resolve({ requestedPlatform: 'android' }, androidOnly)).platformJobs, [ + 'android', + ]); + const iosOnly = dependencies({ + artifacts: new Map([['101', new Set([IOS_ARTIFACT, `${ANDROID_ARTIFACT}-near-match`])]]), + }); + assert.deepEqual((await resolve({ requestedPlatform: 'ios' }, iosOnly)).platformJobs, ['ios']); + await assert.rejects( + async () => await resolve({}, androidOnly), + /contains requested mobile app artifacts/u, + ); + await assert.rejects( + async () => await resolve({}, iosOnly), + /contains requested mobile app artifacts/u, + ); +}); +test('rejects abbreviated, malformed, mismatched, or non-canonical checkout SHAs', async () => { + for (const requestedSha of ['a'.repeat(39), `${'a'.repeat(40)}0`, 'not-a-sha']) { + await assert.rejects( + async () => await resolve({ requestedSha }, dependencies()), + /input must be a full commit SHA/u, + ); + } + await assert.rejects( + async () => await resolve({ requestedSha: OTHER_SHA }, dependencies()), + /does not match requested SHA/u, + ); + await assert.rejects( + async () => await resolve({}, dependencies({ sha: SHA.toUpperCase() })), + /checked-out mobile E2E commit is not a full SHA/u, + ); + assert.equal((await resolve({ requestedSha: SHA.toUpperCase() })).sha, SHA); +}); +test('fails closed on malformed successful-run metadata and artifact responses', async () => { + await assert.rejects( + async () => await resolve({}, dependencies({ runs: [successfulRun(undefined)] })), + /invalid databaseId/u, + ); + await assert.rejects( + async () => + await resolve({}, dependencies({ runs: [{ ...successfulRun(1), headSha: 'abc' }] })), + /missing a full lowercase headSha/u, + ); + await assert.rejects( + async () => await resolve({}, dependencies({ runs: {} })), + /gh run list must return a JSON array/u, + ); + await assert.rejects( + async () => + await resolve({}, dependencies({ artifacts: new Map([['101', [ANDROID_ARTIFACT, null]]]) })), + /invalid artifact name/u, + ); +}); +test('deduplicates repeated attempts and preserves GitHub run ordering', async () => { + const injected = dependencies({ + runs: [successfulRun(201), successfulRun(201), successfulRun(202)], + gates: new Map([ + ['201', true], + ['202', true], + ]), + artifacts: new Map([ + ['201', new Set([ANDROID_ARTIFACT])], + ['202', new Set([ANDROID_ARTIFACT, IOS_ARTIFACT])], + ]), + }); + assert.equal((await resolve({}, injected)).runId, '202'); + assert.deepEqual(injected.calls.gates, [ + ['201', 'Builds'], + ['202', 'Builds'], + ]); +}); +test('skips ambiguous duplicate gate and artifact identities', async () => { + const duplicateArtifacts = dependencies({ + runs: [successfulRun(301), successfulRun(302)], + gates: new Map([ + ['301', true], + ['302', true], + ]), + artifacts: new Map([ + ['301', [ANDROID_ARTIFACT, ANDROID_ARTIFACT, IOS_ARTIFACT]], + ['302', [ANDROID_ARTIFACT, IOS_ARTIFACT]], + ]), + }); + assert.equal((await resolve({}, duplicateArtifacts)).runId, '302'); +}); +test('environment entry point emits the complete exact resolver contract', async () => { + const emitted = []; + const result = await runMobileE2eResolver({ + environment: { + BUILD_GATE_JOB: 'Builds', + GH_REPO: 'f0rr0/oliphaunt', + INPUT_PLATFORM: 'ios', + INPUT_SHA: SHA, + }, + dependencies: dependencies({ artifacts: new Map([['101', new Set([IOS_ARTIFACT])]]) }), + writeOutput: (name, value) => emitted.push([name, value]), + }); + assert.deepEqual(result.platformJobs, ['ios']); + assert.deepEqual(emitted, [ + ['sha', SHA], + ['run_id', '101'], + ['android', 'false'], + ['ios', 'true'], + ['platform_jobs', '["ios"]'], + ]); +}); +test('HTTP adapter retries, paginates the latest jobs and live artifacts, and rejects duplicate build gates', async () => { + const requests = [], + delays = []; + let attempts = 0; + const adapter = githubResolverDependencies('f0rr0/oliphaunt', { + environment: { CHECKOUT_SHA: SHA, GH_TOKEN: 'test-token' }, + retryOptions: { + sleepImpl: async (delay) => delays.push(delay), + fetchImpl: async (url, options) => { + const request = new URL(url); + assert.equal(request.origin, 'https://api.github.com'); + assert.equal(options.headers.Authorization, 'Bearer test-token'); + assert.equal(options.redirect, 'error'); + requests.push(request.pathname + request.search); + if (request.pathname.endsWith('/workflows/ci.yml/runs')) { + assert.equal(request.searchParams.get('head_sha'), SHA); + if (++attempts === 1) return new Response('temporary', { status: 503 }); + return Response.json({ + workflow_runs: [901, 902].map((id) => ({ + id, + head_sha: SHA, + status: 'completed', + conclusion: 'success', + })), + }); + } + if (request.pathname.includes('/901/')) { + assert.ok(request.pathname.endsWith('/jobs')); + return Response.json({ + total_count: 2, + jobs: [1, 2].map(() => ({ name: 'Builds', conclusion: 'success' })), + }); + } + assert.equal(request.searchParams.get('per_page'), '100'); + const page = Number(request.searchParams.get('page')); + if (request.pathname.endsWith('/jobs')) { + assert.equal(request.searchParams.get('filter'), 'latest'); + return Response.json({ + total_count: 101, + jobs: + page === 1 + ? Array.from({ length: 100 }, (_, index) => ({ + name: 'job-' + index, + conclusion: 'success', + })) + : [{ name: 'Builds', conclusion: 'success' }], + }); + } + assert.ok(request.pathname.endsWith('/902/artifacts')); + return Response.json({ + total_count: 102, + artifacts: + page === 1 + ? Array.from({ length: 100 }, (_, index) => ({ + name: 'expired-' + index, + expired: true, + })) + : [ANDROID_ARTIFACT, IOS_ARTIFACT].map((name) => ({ name, expired: false })), + }); + }, + }, + }); + const result = await resolve({}, adapter); + assert.equal(result.runId, '902'); + assert.deepEqual(result.platformJobs, ['android', 'ios']); + assert.equal(attempts, 2); + assert.deepEqual(delays, [250]); + assert.equal( + requests.some((request) => request.includes('/901/artifacts')), + false, + ); + assert.equal(requests.filter((request) => request.includes('/902/artifacts')).length, 2); +}); +test('HTTP adapter fails closed on incomplete or changing pagination and malformed artifact identities', async () => { + for (const [data, pattern] of [ + [{ total_count: 1, artifacts: [] }, /incomplete/], + [{ total_count: 1, artifacts: [{ name: ANDROID_ARTIFACT }] }, /malformed artifact/], + [{ total_count: 0, artifacts: [{ name: ANDROID_ARTIFACT, expired: false }] }, /incomplete/], + ]) { + const adapter = githubResolverDependencies('f0rr0/oliphaunt', { + environment: { CHECKOUT_SHA: SHA }, + retryOptions: { fetchImpl: async () => Response.json(data) }, + }); + await assert.rejects(() => adapter.artifactNames('901'), pattern); + } + let calls = 0; + const adapter = githubResolverDependencies('f0rr0/oliphaunt', { + environment: { CHECKOUT_SHA: SHA }, + retryOptions: { + fetchImpl: async () => + Response.json({ + total_count: ++calls === 1 ? 101 : 102, + artifacts: Array.from({ length: 100 }, (_, index) => ({ + name: 'artifact-' + index, + expired: true, + })), + }), + }, + }); + await assert.rejects(() => adapter.artifactNames('901'), /changed during pagination/); +}); diff --git a/.github/scripts/resolve-planned-moon-execution.mjs b/.github/scripts/resolve-planned-moon-execution.mjs deleted file mode 100644 index 27b0b903f..000000000 --- a/.github/scripts/resolve-planned-moon-execution.mjs +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env bun -import {spawnSync} from 'node:child_process'; -import process from 'node:process'; - -import {moonCommand, moonEnvironment} from '../../tools/dev/moon-command.mjs'; -import {plannedTargets} from './select-planned-moon-targets.mjs'; - -function fail(message) { - console.error(`resolve-planned-moon-execution.mjs: ${message}`); - process.exit(1); -} - -function dependencyTargets(task) { - return (task?.deps ?? []) - .map((dependency) => typeof dependency === 'string' ? dependency : dependency?.target) - .filter((target) => typeof target === 'string'); -} - -export function resolveExecution(targets, transferred, tasks) { - for (const target of targets) { - if (!tasks.has(target)) throw new Error(`selected target ${target} is missing from the Moon task graph`); - } - const roots = new Set(targets); - const transferredSet = new Set(transferred); - if (transferredSet.size === 0) { - return {localDependencies: [], targets: [...roots].sort(), transferred: []}; - } - const directDependencies = new Set( - targets.flatMap((target) => dependencyTargets(tasks.get(target))), - ); - for (const target of transferredSet) { - if (!directDependencies.has(target)) { - throw new Error(`transferred dependency ${target} is not a direct dependency of a selected root`); - } - } - - const localDependencies = [...directDependencies].filter((target) => !transferredSet.has(target)); - const pending = [...localDependencies]; - const visited = new Set(); - while (pending.length > 0) { - const target = pending.pop(); - if (visited.has(target)) continue; - visited.add(target); - if (!tasks.has(target)) throw new Error(`dependency ${target} is missing from the Moon task graph`); - if (transferredSet.has(target)) { - throw new Error(`transferred dependency ${target} is still required by a local prerequisite`); - } - pending.push(...dependencyTargets(tasks.get(target))); - } - - return { - localDependencies: localDependencies.sort(), - targets: [...roots].sort(), - transferred: [...transferredSet].sort(), - }; -} - -function parseTransferred() { - const raw = process.env.OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON ?? '[]'; - let value; - try { - value = JSON.parse(raw); - } catch (error) { - throw new Error(`invalid OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: ${error.message}`); - } - if (!Array.isArray(value) || value.some((target) => typeof target !== 'string')) { - throw new Error('OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON must be a JSON string list'); - } - return value; -} - -function taskMap() { - const result = spawnSync(moonCommand(), ['task-graph', '--json'], { - encoding: 'utf8', - env: moonEnvironment(), - maxBuffer: 64 * 1024 * 1024, - stdio: ['ignore', 'pipe', 'inherit'], - }); - if (result.error || result.status !== 0) { - throw new Error(result.error?.message ?? `moon task-graph exited ${result.status}`); - } - const graph = JSON.parse(result.stdout); - return new Map(Object.values(graph.data ?? {}).map((task) => [task.target, task])); -} - -if (import.meta.main) { - const job = process.argv[2] ?? ''; - const selectedTarget = process.argv[3]; - if (!job || process.argv.length > 4) fail('usage: resolve-planned-moon-execution.mjs [target]'); - try { - const planned = plannedTargets(job); - if (planned.length === 0) throw new Error(`CI job ${JSON.stringify(job)} has no planned Moon targets`); - if (selectedTarget !== undefined && !planned.includes(selectedTarget)) { - throw new Error(`Moon target ${selectedTarget} is not planned for CI job ${job}`); - } - const targets = selectedTarget === undefined ? planned : [selectedTarget]; - const execution = resolveExecution(targets, parseTransferred(), taskMap()); - for (const target of execution.localDependencies) console.log(`local\t${target}`); - for (const target of execution.targets) console.log(`target\t${target}`); - for (const target of execution.transferred) console.log(`transferred\t${target}`); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} diff --git a/.github/scripts/resolve-planned-moon-execution.mts b/.github/scripts/resolve-planned-moon-execution.mts new file mode 100644 index 000000000..263770171 --- /dev/null +++ b/.github/scripts/resolve-planned-moon-execution.mts @@ -0,0 +1,134 @@ +#!/usr/bin/env bun +import { readFileSync } from 'node:fs'; +import process from 'node:process'; + +import { plannedTargets } from './select-planned-moon-targets.mts'; + +function fail(message) { + console.error(`resolve-planned-moon-execution.mts: ${message}`); + process.exit(1); +} + +function dependencyTargets(task, tasks) { + return (task?.deps ?? []) + .map((dependency) => (typeof dependency === 'string' ? dependency : dependency?.target)) + .filter((target) => { + const dependency = tasks.get(target); + return ( + typeof target === 'string' && + !(dependency?.options?.internal && dependency.command === 'noop' && !dependency.script) + ); + }); +} + +export function resolveExecution(targets, transferred, tasks) { + for (const target of targets) { + if (!tasks.has(target)) + throw new Error(`selected target ${target} is missing from the Moon task graph`); + } + const roots = new Set(targets); + const transferredSet = new Set(transferred); + if (transferredSet.size === 0) { + return { localDependencies: [], targets: [...roots].sort(), transferred: [] }; + } + // Only paths touching an artifact boundary need dependency-free execution. + // Leave complete local subtrees to Moon so their normal caching still applies. + const affected = new Map(); + const visiting = new Set(); + const consumed = new Set(); + function visit(target) { + if (transferredSet.has(target)) { + consumed.add(target); + return true; + } + if (affected.has(target)) return affected.get(target); + if (visiting.has(target)) throw new Error(`task dependency cycle at ${target}`); + if (!tasks.has(target)) + throw new Error(`dependency ${target} is missing from the Moon task graph`); + visiting.add(target); + const dependencies = dependencyTargets(tasks.get(target), tasks).map(visit); + visiting.delete(target); + const needsIsolation = roots.has(target) || dependencies.some(Boolean); + affected.set(target, needsIsolation); + return needsIsolation; + } + for (const target of [...roots].sort()) visit(target); + for (const target of transferredSet) { + if (!consumed.has(target)) + throw new Error(`transferred dependency ${target} is not reachable from a selected root`); + } + + const localDependencies = new Set(); + const orderedTargets = new Set(); + function schedule(target) { + if (transferredSet.has(target) || orderedTargets.has(target)) return; + if (!affected.get(target)) { + localDependencies.add(target); + return; + } + for (const dependency of dependencyTargets(tasks.get(target), tasks)) schedule(dependency); + orderedTargets.add(target); + } + for (const target of [...roots].sort()) schedule(target); + return { + localDependencies: [...localDependencies].sort(), + targets: [...orderedTargets], + transferred: [...consumed].sort(), + }; +} + +function parseTransferred() { + const raw = process.env.OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON ?? '[]'; + let value; + try { + value = JSON.parse(raw); + } catch (error) { + throw new Error(`invalid OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: ${error.message}`); + } + if (!Array.isArray(value) || value.some((target) => typeof target !== 'string')) { + throw new Error('OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON must be a JSON string list'); + } + return value; +} + +function taskMap() { + const graph = JSON.parse(readFileSync(process.env.OLIPHAUNT_MOON_TASK_GRAPH_FILE, 'utf8')); + return new Map(Object.values(graph.data ?? {}).map((task) => [task.target, task])); +} + +if (import.meta.main) { + const job = process.argv[2] ?? ''; + const selectedTarget = process.argv[3]; + if (!job || process.argv.length > 4) + fail('usage: resolve-planned-moon-execution.mts [target]'); + try { + const planned = plannedTargets(job); + if (planned.length === 0) + throw new Error(`CI job ${JSON.stringify(job)} has no planned Moon targets`); + if (selectedTarget !== undefined && !planned.includes(selectedTarget)) { + throw new Error(`Moon target ${selectedTarget} is not planned for CI job ${job}`); + } + const targets = selectedTarget === undefined ? planned : [selectedTarget]; + const tasks = taskMap(); + const available = new Set(parseTransferred()); + const transferred = new Set(); + const visited = new Set(); + function collect(target) { + if (visited.has(target)) return; + visited.add(target); + if (available.has(target) && !targets.includes(target)) { + transferred.add(target); + return; + } + for (const dependency of dependencyTargets(tasks.get(target), tasks)) collect(dependency); + } + // A narrowed plan consumes reachable artifacts, stopping at each downloaded producer. + for (const target of targets) collect(target); + const execution = resolveExecution(targets, transferred, tasks); + for (const target of execution.localDependencies) console.log(`local\t${target}`); + for (const target of execution.targets) console.log(`target\t${target}`); + for (const target of execution.transferred) console.log(`transferred\t${target}`); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } +} diff --git a/.github/scripts/resolve-planned-moon-execution.test.mjs b/.github/scripts/resolve-planned-moon-execution.test.mjs deleted file mode 100644 index c1f21ea8f..000000000 --- a/.github/scripts/resolve-planned-moon-execution.test.mjs +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env node -import assert from 'node:assert/strict'; -import {spawnSync} from 'node:child_process'; -import {test} from 'node:test'; - -import {resolveExecution} from './resolve-planned-moon-execution.mjs'; - -const tasks = new Map([ - ['release:package', {target: 'release:package', deps: [{target: 'sdk:package'}, {target: 'native:ios'}]}], - ['sdk:package', {target: 'sdk:package', deps: [{target: 'sdk:compile'}]}], - ['sdk:compile', {target: 'sdk:compile', deps: []}], - ['native:ios', {target: 'native:ios', deps: [{target: 'source:fetch'}]}], - ['source:fetch', {target: 'source:fetch', deps: []}], -]); - -test('leaves ordinary Moon execution intact when no dependency was transferred', () => { - assert.deepEqual(resolveExecution(['release:package'], [], tasks), { - localDependencies: [], - targets: ['release:package'], - transferred: [], - }); -}); - -test('preserves local prerequisites while subtracting a transferred producer', () => { - assert.deepEqual(resolveExecution(['release:package'], ['native:ios'], tasks), { - localDependencies: ['sdk:package'], - targets: ['release:package'], - transferred: ['native:ios'], - }); -}); - -test('rejects an unrelated or transitively required transferred producer', () => { - assert.throws( - () => resolveExecution(['release:package'], ['source:fetch'], tasks), - /not a direct dependency/u, - ); - const conflicting = new Map(tasks); - conflicting.set('sdk:package', {target: 'sdk:package', deps: [{target: 'native:ios'}]}); - assert.throws( - () => resolveExecution(['release:package'], ['native:ios'], conflicting), - /still required by a local prerequisite/u, - ); -}); - -test('fails closed when the task graph is incomplete', () => { - assert.throws( - () => resolveExecution(['missing:root'], [], tasks), - /selected target missing:root is missing/u, - ); - const incomplete = new Map(tasks); - incomplete.delete('sdk:compile'); - assert.throws( - () => resolveExecution(['release:package'], ['native:ios'], incomplete), - /dependency sdk:compile is missing/u, - ); -}); - -test('resolves a real multi-root job with downloaded dependencies', () => { - const result = spawnSync(process.execPath, [ - '.github/scripts/resolve-planned-moon-execution.mjs', - 'wasix-ts-sdk-package', - ], { - encoding: 'utf8', - env: { - ...process.env, - OLIPHAUNT_CI_JOB_TARGETS_JSON: JSON.stringify({ - 'wasix-ts-sdk-package': [ - 'release-tools:wasix-ts-sdk-package', - 'wasix-ts-integration:runtime', - ], - }), - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: JSON.stringify([ - 'liboliphaunt-wasix:runtime-portable', - 'release-tools:wasix-napi-runtime', - ]), - }, - }); - assert.equal(result.status, 0, result.stderr); - assert.match(result.stdout, /^local\toliphaunt-wasix-ts:package$/mu); - assert.match(result.stdout, /^target\twasix-ts-integration:runtime$/mu); - assert.match(result.stdout, /^transferred\tliboliphaunt-wasix:runtime-portable$/mu); -}); - -test('runs one exact matrix target and rejects targets outside the plan', () => { - const env = { - ...process.env, - OLIPHAUNT_CI_JOB_TARGETS_JSON: JSON.stringify({ - 'liboliphaunt-native-android': [ - 'liboliphaunt-native:package-runtime-android-arm64-v8a', - 'liboliphaunt-native:package-runtime-android-x86_64', - ], - }), - }; - const selected = spawnSync(process.execPath, [ - '.github/scripts/resolve-planned-moon-execution.mjs', - 'liboliphaunt-native-android', - 'liboliphaunt-native:package-runtime-android-x86_64', - ], {encoding: 'utf8', env}); - assert.equal(selected.status, 0, selected.stderr); - assert.equal(selected.stdout.trim(), 'target\tliboliphaunt-native:package-runtime-android-x86_64'); - - const rejected = spawnSync(process.execPath, [ - '.github/scripts/resolve-planned-moon-execution.mjs', - 'liboliphaunt-native-android', - 'liboliphaunt-native:package-runtime-ios-xcframework', - ], {encoding: 'utf8', env}); - assert.notEqual(rejected.status, 0); - assert.match(rejected.stderr, /is not planned/u); -}); diff --git a/.github/scripts/resolve-planned-moon-execution.test.mts b/.github/scripts/resolve-planned-moon-execution.test.mts new file mode 100644 index 000000000..8c1e5bee8 --- /dev/null +++ b/.github/scripts/resolve-planned-moon-execution.test.mts @@ -0,0 +1,84 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import { test } from 'node:test'; + +import { resolveExecution } from './resolve-planned-moon-execution.mts'; + +const tasks = new Map([ + [ + 'release:package', + { + target: 'release:package', + deps: [ + { target: 'sdk:package', cacheStrategy: 'hash' }, + { target: 'native:ios', cacheStrategy: 'hash' }, + { target: 'sdk:cargo-sources', cacheStrategy: 'hash' }, + ], + }, + ], + ['sdk:package', { target: 'sdk:package', deps: [{ target: 'sdk:compile' }] }], + ['sdk:compile', { target: 'sdk:compile', deps: [] }], + ['native:ios', { target: 'native:ios', deps: [{ target: 'source:fetch' }] }], + ['source:fetch', { target: 'source:fetch', deps: [] }], + [ + 'sdk:cargo-sources', + { target: 'sdk:cargo-sources', command: 'noop', deps: [], options: { internal: true } }, + ], +]); + +test('leaves ordinary Moon execution intact when no dependency was transferred', () => { + assert.deepEqual(resolveExecution(['release:package'], [], tasks), { + localDependencies: [], + targets: ['release:package'], + transferred: [], + }); +}); + +test('preserves local prerequisites while subtracting a transferred producer', () => { + assert.deepEqual(resolveExecution(['release:package'], ['native:ios'], tasks), { + localDependencies: ['sdk:package'], + targets: ['release:package'], + transferred: ['native:ios'], + }); +}); + +test('isolates intermediate prerequisites that consume a transitive artifact', () => { + assert.deepEqual(resolveExecution(['release:package'], ['source:fetch'], tasks), { + localDependencies: ['sdk:package'], + targets: ['native:ios', 'release:package'], + transferred: ['source:fetch'], + }); + const shared = new Map(tasks); + shared.set('sdk:package', { deps: ['native:ios', 'sdk:compile'] }); + assert.deepEqual(resolveExecution(['release:package'], ['native:ios'], shared), { + localDependencies: ['sdk:compile'], + targets: ['sdk:package', 'release:package'], + transferred: ['native:ios'], + }); + assert.throws( + () => resolveExecution(['release:package'], ['unrelated:producer'], tasks), + /not reachable/u, + ); +}); + +test('fails closed when the task graph is incomplete', () => { + assert.throws( + () => resolveExecution(['missing:root'], [], tasks), + /selected target missing:root is missing/u, + ); + const incomplete = new Map(tasks); + incomplete.delete('sdk:compile'); + assert.throws( + () => resolveExecution(['release:package'], ['native:ios'], incomplete), + /dependency sdk:compile is missing/u, + ); +}); + +test('rejects cycles between selected roots instead of running an arbitrary order', () => { + const cyclic = new Map(tasks); + cyclic.set('sdk:package', { deps: ['release:package'] }); + assert.throws( + () => resolveExecution(['sdk:package', 'release:package'], ['native:ios'], cyclic), + /dependency cycle/u, + ); +}); diff --git a/.github/scripts/resolve-planned-moon-execution.test.sh b/.github/scripts/resolve-planned-moon-execution.test.sh new file mode 100644 index 000000000..806b3b28c --- /dev/null +++ b/.github/scripts/resolve-planned-moon-execution.test.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/../.." +: "${OLIPHAUNT_MOON_TASK_GRAPH_FILE:?run through tools/ci/check-workflows.sh}" +scratch=$(mktemp -d) +trap 'rm -rf "$scratch"' EXIT +bash tools/dev/bun.sh test ./.github/scripts/resolve-planned-moon-execution.test.mts +resolver=.github/scripts/resolve-planned-moon-execution.mts +export OLIPHAUNT_CI_JOB_TARGETS_JSON='{"wasix-ts-sdk-package":["oliphaunt-wasix-ts:package","oliphaunt-wasix-ts:test-consumer","oliphaunt-wasix-ts:test-browser"]}' +export OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON='["liboliphaunt-wasix:runtime-portable","oliphaunt-wasix-napi:build-release-assets","extension-artifacts-wasix:compiler-output","database-resources:build-wasix-standard","database-resources:build-wasix-icu","database-resources:package-icu"]' +bash tools/dev/bun.sh "$resolver" wasix-ts-sdk-package >"$scratch/output" +for task in package test-consumer test-browser; do grep -Fx "$(printf 'target\toliphaunt-wasix-ts:%s' "$task")" "$scratch/output"; done +grep -Fx $'target\tdatabase-resources:package-wasix' "$scratch/output" +for variant in standard icu; do + grep -Fx "$(printf 'transferred\tdatabase-resources:build-wasix-%s' "$variant")" "$scratch/output" +done +if grep -E $'^(local|target)\tdatabase-resources:build-wasix-' "$scratch/output"; then exit 1; fi +grep -Fx $'transferred\tliboliphaunt-wasix:runtime-portable' "$scratch/output" +for platform in android ios; do + job="liboliphaunt-native-$platform-abi" + root="database-resources:build-native-$platform-standard" + targets=(ios-xcframework) + [[ "$platform" != android ]] || targets=(android-arm64-v8a android-x86_64) + export OLIPHAUNT_CI_JOB_TARGETS_JSON="{\"$job\":[\"$root\"]}" + transfers='[' + printf 'target\t%s\n' "$root" >"$scratch/expected" + for target in "${targets[@]}"; do + transfers+="\"liboliphaunt-native:package-runtime-$target\",\"liboliphaunt-native:build-runtime-$target\"," + printf 'transferred\tliboliphaunt-native:build-runtime-%s\n' "$target" >>"$scratch/expected" + done + export OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON="${transfers%,}]" + bash tools/dev/bun.sh "$resolver" "$job" >"$scratch/output" + cmp "$scratch/expected" "$scratch/output" +done +export OLIPHAUNT_CI_JOB_TARGETS_JSON='{"react-native-sdk-package":["oliphaunt-react-native:test-consumer","oliphaunt-react-native:package"]}' +export OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON='["liboliphaunt-native:finalize-runtime-ios-abi"]' +bash tools/dev/bun.sh "$resolver" react-native-sdk-package >"$scratch/output" +grep $'^target\t' "$scratch/output" >"$scratch/targets" +printf 'target\toliphaunt-react-native:package\ntarget\toliphaunt-react-native:test-consumer\n' >"$scratch/expected" +cmp "$scratch/expected" "$scratch/targets" +if grep -E $'^local\t(oliphaunt-react-native:package|liboliphaunt-native:finalize-runtime-ios-abi)$' "$scratch/output"; then exit 1; fi +unset OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON +export OLIPHAUNT_CI_JOB_TARGETS_JSON='{"liboliphaunt-native-android":["liboliphaunt-native:package-runtime-android-arm64-v8a","liboliphaunt-native:package-runtime-android-x86_64"]}' +bash tools/dev/bun.sh "$resolver" liboliphaunt-native-android liboliphaunt-native:package-runtime-android-x86_64 >"$scratch/output" +printf 'target\tliboliphaunt-native:package-runtime-android-x86_64\n' >"$scratch/expected" +cmp "$scratch/expected" "$scratch/output" +if bash tools/dev/bun.sh "$resolver" liboliphaunt-native-android liboliphaunt-native:package-runtime-ios-xcframework >"$scratch/output" 2>"$scratch/error"; then + echo 'accepted a target outside the job plan' >&2; exit 1 +fi +grep -q 'is not planned' "$scratch/error" diff --git a/.github/scripts/resolve-release-head.sh b/.github/scripts/resolve-release-head.sh index 44089ea2e..422bd98f2 100755 --- a/.github/scripts/resolve-release-head.sh +++ b/.github/scripts/resolve-release-head.sh @@ -25,7 +25,7 @@ else fi fi -node tools/release/publication-controller.mjs "$release_sha" "$workflow_sha" +bash tools/release/publication-controller.sh "$release_sha" "$workflow_sha" { echo "sha=$release_sha" diff --git a/.github/scripts/resolve-release-please-pr.mjs b/.github/scripts/resolve-release-please-pr.mjs deleted file mode 100644 index e4a50f009..000000000 --- a/.github/scripts/resolve-release-please-pr.mjs +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bun - -function candidateObjectsFromEnv(name) { - const raw = process.env[name]?.trim(); - if (!raw) { - return []; - } - let value; - try { - value = JSON.parse(raw); - } catch { - return []; - } - if (Array.isArray(value)) { - return value.filter((item) => item !== null && typeof item === 'object'); - } - if (value !== null && typeof value === 'object') { - return [value]; - } - return []; -} - -function pullRequestNumber(item) { - const value = item.number ?? item.pullRequestNumber; - if (typeof value === 'number' && Number.isInteger(value) && value > 0) { - return String(value); - } - if (typeof value === 'string' && value.trim().length > 0) { - return value.trim(); - } - return undefined; -} - -const candidates = [ - ...candidateObjectsFromEnv('RELEASE_PLEASE_PR'), - ...candidateObjectsFromEnv('RELEASE_PLEASE_PRS'), -]; - -for (const item of candidates) { - const number = pullRequestNumber(item); - if (number !== undefined) { - console.log(number); - process.exit(0); - } -} diff --git a/.github/scripts/run-moon-target-matrix.mjs b/.github/scripts/run-moon-target-matrix.mjs deleted file mode 100644 index 361bc922e..000000000 --- a/.github/scripts/run-moon-target-matrix.mjs +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "node:child_process"; -import process from "node:process"; - -function fail(message) { - console.error(message); - process.exit(1); -} - -let matrix; -try { - matrix = JSON.parse(process.env.MOON_TARGET_MATRIX_JSON ?? ""); -} catch (error) { - fail(`MOON_TARGET_MATRIX_JSON is invalid JSON: ${error.message}`); -} - -if (!matrix || !Array.isArray(matrix.include)) { - fail("MOON_TARGET_MATRIX_JSON must contain an include array"); -} - -const groups = new Map(); -for (const row of matrix.include) { - if (!row || typeof row.target !== "string" || !/^[A-Za-z0-9_:@./-]+$/u.test(row.target)) { - fail(`invalid Moon target matrix row: ${JSON.stringify(row)}`); - } - const upstream = row.upstream ?? "deep"; - if (!["none", "deep"].includes(upstream)) { - fail(`unsupported Moon upstream mode ${upstream} for ${row.target}`); - } - const targets = groups.get(upstream) ?? new Set(); - targets.add(row.target); - groups.set(upstream, targets); -} - -if (groups.size === 0) { - fail("Moon target matrix must not be empty"); -} - -for (const [upstream, targets] of groups) { - const ordered = [...targets].sort(); - console.log(`running ${ordered.length} Moon targets with --upstream ${upstream}`); - const result = spawnSync( - ".github/scripts/run-moon-targets.sh", - ["--upstream", upstream, ...ordered], - { stdio: "inherit", env: process.env }, - ); - if (result.error || result.status !== 0) { - fail(result.error?.message || `Moon target group failed with status ${result.status}`); - } -} diff --git a/.github/scripts/run-moon-targets.sh b/.github/scripts/run-moon-targets.sh index 8e71645d1..f3501fa00 100755 --- a/.github/scripts/run-moon-targets.sh +++ b/.github/scripts/run-moon-targets.sh @@ -6,4 +6,12 @@ unset MOON_HEAD moon_bin="${MOON_BIN:-moon}" -exec "$moon_bin" run "$@" +if [ "${1:-}" = --matrix ]; then + groups="$(bun .github/scripts/select-moon-target-groups.mts)" + while IFS=$'\t' read -r upstream targets; do + read -r -a target_args <<<"$targets" + "$moon_bin" run --upstream "$upstream" "${target_args[@]}" + done <<<"$groups" +else + exec "$moon_bin" run "$@" +fi diff --git a/.github/scripts/run-moon-targets.test.sh b/.github/scripts/run-moon-targets.test.sh new file mode 100644 index 000000000..179ede0b1 --- /dev/null +++ b/.github/scripts/run-moon-targets.test.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +set -euo pipefail +fixture="$(mktemp -d)" +trap 'rm -rf "$fixture"' EXIT +export MOON_BIN="$fixture/moon" MOON_CALLS="$fixture/calls" +cat >"$MOON_BIN" <<'MOON' +#!/usr/bin/env bash +if [[ -v MOON_BASE || -v MOON_HEAD ]]; then + echo 'explicit task execution inherited affectedness revisions' >&2 + exit 8 +fi +printf '%s\n' "$*" >>"$MOON_CALLS" +exit "${MOON_TEST_EXIT:-0}" +MOON +chmod +x "$MOON_BIN" +MOON_BASE=missing-base MOON_HEAD=missing-head \ + bash .github/scripts/run-moon-targets.sh ci-workflows:verify-bash +printf 'run ci-workflows:verify-bash\n' >"$fixture/expected" +cmp "$MOON_CALLS" "$fixture/expected" +: >"$MOON_CALLS" +export MOON_TARGET_MATRIX_JSON='{"include":[{"target":"sdk:b"},{"target":"sdk:a"},{"target":"sdk:a"},{"target":"native:c","upstream":"none"}]}' +bash .github/scripts/run-moon-targets.sh --matrix +printf 'run --upstream deep sdk:a sdk:b\nrun --upstream none native:c\n' >"$fixture/expected" +cmp "$MOON_CALLS" "$fixture/expected" +: >"$MOON_CALLS" +if MOON_TEST_EXIT=7 bash .github/scripts/run-moon-targets.sh --matrix; then + echo 'Moon failure was ignored' >&2 + exit 1 +fi +printf 'run --upstream deep sdk:a sdk:b\n' >"$fixture/expected" +cmp "$MOON_CALLS" "$fixture/expected" +: >"$MOON_CALLS" +if MOON_TARGET_MATRIX_JSON='{"include":[{"target":"sdk:a"},{"target":"-bad target"}]}' \ + bash .github/scripts/run-moon-targets.sh --matrix; then + echo 'invalid target was accepted' >&2 + exit 1 +fi +[ ! -s "$MOON_CALLS" ] + +# Selected package roots must finish before consumers; downloaded producers never run. +cat >"$fixture/graph.json" <<'GRAPH' +{"data":{"package":{"target":"sdk:z-package","deps":[{"target":"native:ios","cacheStrategy":"hash"},{"target":"sdk:build","cacheStrategy":"hash"},{"target":"sdk:cargo-sources","cacheStrategy":"hash"}]},"consumer":{"target":"sdk:a-consumer","deps":[{"target":"sdk:z-package"}]},"build":{"target":"sdk:build","deps":[]},"native":{"target":"native:ios","deps":[]},"sources":{"target":"sdk:cargo-sources","command":"noop","deps":[],"options":{"internal":true}}}} +GRAPH +export MOON_TEST_GRAPH="$fixture/graph.json" +cat >"$MOON_BIN" <<'MOON' +#!/usr/bin/env bash +if [ "$1" = task-graph ]; then cat "$MOON_TEST_GRAPH"; exit; fi +if [[ "$*" == 'run --upstream none '* && "${MOON_CACHE:-}" != off ]]; then + echo 'transferred consumers must execute without incomplete dependency cache keys' >&2 + exit 9 +fi +printf '%s\n' "$*" >>"$MOON_CALLS" +if [ "${MOON_FAIL_TARGET:-}" = "${*: -1}" ]; then exit 7; fi +MOON +export OLIPHAUNT_CI_JOB_TARGETS_JSON='{"fixture":["sdk:a-consumer","sdk:z-package"]}' +export OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON='["native:ios"]' +bash .github/scripts/run-planned-moon-job.sh fixture +printf 'run sdk:build\nrun --upstream none sdk:z-package\nrun --upstream none sdk:a-consumer\n' >"$fixture/expected" +cmp "$MOON_CALLS" "$fixture/expected" +: >"$MOON_CALLS" +if MOON_FAIL_TARGET=sdk:z-package bash .github/scripts/run-planned-moon-job.sh fixture; then + echo 'failed package reached its consumer' >&2 + exit 1 +fi +printf 'run sdk:build\nrun --upstream none sdk:z-package\n' >"$fixture/expected" +cmp "$MOON_CALLS" "$fixture/expected" + +# A narrowed consumer still needs its intermediate package, but never its transferred producer. +: >"$MOON_CALLS" +export OLIPHAUNT_CI_JOB_TARGETS_JSON='{"fixture":["sdk:a-consumer"]}' +bash .github/scripts/run-planned-moon-job.sh fixture +printf 'run sdk:build\nrun --upstream none sdk:z-package\nrun --upstream none sdk:a-consumer\n' >"$fixture/expected" +cmp "$MOON_CALLS" "$fixture/expected" +: >"$MOON_CALLS" +if MOON_FAIL_TARGET=sdk:z-package bash .github/scripts/run-planned-moon-job.sh fixture; then + echo 'failed intermediate package reached its consumer' >&2 + exit 1 +fi +printf 'run sdk:build\nrun --upstream none sdk:z-package\n' >"$fixture/expected" +cmp "$MOON_CALLS" "$fixture/expected" diff --git a/.github/scripts/run-planned-moon-job.sh b/.github/scripts/run-planned-moon-job.sh index b09e17f6a..efd05cbc8 100755 --- a/.github/scripts/run-planned-moon-job.sh +++ b/.github/scripts/run-planned-moon-job.sh @@ -8,12 +8,15 @@ if [[ -z "$job" || "$#" -gt 2 ]]; then exit 2 fi -execution_file="$(mktemp)" -trap 'rm -f "$execution_file"' EXIT +plan_dir="$(mktemp -d)" +trap 'rm -rf "$plan_dir"' EXIT +execution_file="$plan_dir/execution" +"${MOON_BIN:-moon}" task-graph --json >"$plan_dir/graph.json" resolve_args=("$job") if [[ -n "$target" ]]; then resolve_args+=("$target"); fi -bun .github/scripts/resolve-planned-moon-execution.mjs "${resolve_args[@]}" >"$execution_file" +OLIPHAUNT_MOON_TASK_GRAPH_FILE="$plan_dir/graph.json" \ + bun .github/scripts/resolve-planned-moon-execution.mts "${resolve_args[@]}" >"$execution_file" targets=() local_dependencies=() @@ -24,7 +27,10 @@ while IFS=$'\t' read -r kind target; do local) local_dependencies+=("$target") ;; target) targets+=("$target") ;; transferred) transferred_dependencies+=("$target") ;; - *) echo "CI job '$job' has invalid execution-plan row: $kind" >&2; exit 2 ;; + *) + echo "CI job '$job' has invalid execution-plan row: $kind" >&2 + exit 2 + ;; esac done <"$execution_file" @@ -46,7 +52,12 @@ if [[ "${#transferred_dependencies[@]}" -gt 0 ]]; then if [[ "${#local_dependencies[@]}" -gt 0 ]]; then .github/scripts/run-moon-targets.sh "${local_dependencies[@]}" fi - exec .github/scripts/run-moon-targets.sh --upstream none "${targets[@]}" + for target in "${targets[@]}"; do + # Omitting transferred producers also omits their source hashes in Moon. + # Execute intermediate prerequisites and roots against the downloaded bytes. + MOON_CACHE=off .github/scripts/run-moon-targets.sh --upstream none "$target" + done + exit 0 fi if [[ "${#moon_args[@]}" -gt 0 ]]; then diff --git a/.github/scripts/select-moon-target-groups.mts b/.github/scripts/select-moon-target-groups.mts new file mode 100644 index 000000000..feda3d439 --- /dev/null +++ b/.github/scripts/select-moon-target-groups.mts @@ -0,0 +1,39 @@ +#!/usr/bin/env bun +import process from 'node:process'; + +function fail(message) { + console.error(message); + process.exit(1); +} + +let matrix; +try { + matrix = JSON.parse(process.env.MOON_TARGET_MATRIX_JSON ?? ''); +} catch (error) { + fail(`MOON_TARGET_MATRIX_JSON is invalid JSON: ${error.message}`); +} + +if (!matrix || !Array.isArray(matrix.include)) { + fail('MOON_TARGET_MATRIX_JSON must contain an include array'); +} + +const groups = new Map(); +for (const row of matrix.include) { + if (!row || typeof row.target !== 'string' || !/^[A-Za-z0-9_:@./-]+$/u.test(row.target)) { + fail(`invalid Moon target matrix row: ${JSON.stringify(row)}`); + } + const upstream = row.upstream ?? 'deep'; + if (!['none', 'deep'].includes(upstream)) { + fail(`unsupported Moon upstream mode ${upstream} for ${row.target}`); + } + const targets = groups.get(upstream) ?? new Set(); + targets.add(row.target); + groups.set(upstream, targets); +} + +if (groups.size === 0) { + fail('Moon target matrix must not be empty'); +} + +for (const [upstream, targets] of groups) + console.log(`${upstream}\t${[...targets].sort().join(' ')}`); diff --git a/.github/scripts/select-planned-moon-targets.mjs b/.github/scripts/select-planned-moon-targets.mjs deleted file mode 100644 index 1d3cfa811..000000000 --- a/.github/scripts/select-planned-moon-targets.mjs +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bun -import {existsSync, readFileSync} from 'node:fs'; -import process from 'node:process'; - -function fail(message) { - console.error(message); - process.exit(1); -} - -function parseJson(raw, source) { - try { - return JSON.parse(raw); - } catch (error) { - fail(`invalid ${source} JSON: ${error.message}`); - } -} - -function plannedTargetsJson(environment = process.env) { - const envJson = environment.OLIPHAUNT_CI_JOB_TARGETS_JSON; - if (envJson) { - return parseJson(envJson, 'OLIPHAUNT_CI_JOB_TARGETS_JSON'); - } - - const planPath = 'target/graph/ci-plan.json'; - if (!existsSync(planPath)) { - fail('missing OLIPHAUNT_CI_JOB_TARGETS_JSON or target/graph/ci-plan.json'); - } - - const plan = parseJson(readFileSync(planPath, 'utf8'), planPath); - return plan.job_targets ?? {}; -} - -export function plannedTargets(job, environment = process.env) { - const targets = plannedTargetsJson(environment)?.[job] ?? []; - if (!Array.isArray(targets) || targets.some((target) => typeof target !== 'string')) { - throw new Error(`CI job ${JSON.stringify(job)} has invalid target list`); - } - return targets; -} - -if (import.meta.main) { - const job = process.argv[2] ?? ''; - if (!job) { - fail('usage: select-planned-moon-targets.mjs '); - } - try { - for (const target of plannedTargets(job)) { - console.log(target); - } - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} diff --git a/.github/scripts/select-planned-moon-targets.mts b/.github/scripts/select-planned-moon-targets.mts new file mode 100644 index 000000000..05a6bc053 --- /dev/null +++ b/.github/scripts/select-planned-moon-targets.mts @@ -0,0 +1,53 @@ +#!/usr/bin/env bun +import { existsSync, readFileSync } from 'node:fs'; +import process from 'node:process'; + +function fail(message) { + console.error(message); + process.exit(1); +} + +function parseJson(raw, source) { + try { + return JSON.parse(raw); + } catch (error) { + fail(`invalid ${source} JSON: ${error.message}`); + } +} + +function plannedTargetsJson(environment = process.env) { + const envJson = environment.OLIPHAUNT_CI_JOB_TARGETS_JSON; + if (envJson) { + return parseJson(envJson, 'OLIPHAUNT_CI_JOB_TARGETS_JSON'); + } + + const planPath = 'target/graph/ci-plan.json'; + if (!existsSync(planPath)) { + fail('missing OLIPHAUNT_CI_JOB_TARGETS_JSON or target/graph/ci-plan.json'); + } + + const plan = parseJson(readFileSync(planPath, 'utf8'), planPath); + return plan.job_targets ?? {}; +} + +export function plannedTargets(job, environment = process.env) { + const targets = plannedTargetsJson(environment)?.[job] ?? []; + if (!Array.isArray(targets) || targets.some((target) => typeof target !== 'string')) { + throw new Error(`CI job ${JSON.stringify(job)} has invalid target list`); + } + return targets; +} + +if (import.meta.main) { + const job = process.argv[2] ?? ''; + if (!job) { + fail('usage: select-planned-moon-targets.mts '); + } + try { + for (const target of plannedTargets(job)) { + console.log(target); + } + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } +} diff --git a/.github/scripts/selected-registry-needs.mjs b/.github/scripts/selected-registry-needs.mjs deleted file mode 100644 index e7dd7fc1a..000000000 --- a/.github/scripts/selected-registry-needs.mjs +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bun -import { appendFileSync } from "node:fs"; -import process from "node:process"; - -import { loadPublicationCatalog } from "../../tools/release/publication-catalog.mjs"; - -function fail(message) { - console.error(`selected-registry-needs: ${message}`); - process.exit(1); -} - -let products; -try { - products = JSON.parse(process.env.PRODUCTS_JSON ?? ""); -} catch (error) { - fail(`invalid PRODUCTS_JSON: ${error.message}`); -} -if (!Array.isArray(products) || products.length === 0 || products.some((product) => typeof product !== "string")) { - fail("PRODUCTS_JSON must be a non-empty product string list"); -} - -const catalog = loadPublicationCatalog("selected-registry-needs", { products }); -const ecosystems = new Set(catalog.carriers.map((carrier) => carrier.ecosystem)); -for (const ecosystem of ["cargo", "npm", "maven"]) { - const line = `needs_${ecosystem}=${String(ecosystems.has(ecosystem))}`; - console.log(line); - if (process.env.GITHUB_OUTPUT) { - appendFileSync(process.env.GITHUB_OUTPUT, `${line}\n`, "utf8"); - } -} diff --git a/.github/scripts/selected-registry-needs.mts b/.github/scripts/selected-registry-needs.mts new file mode 100644 index 000000000..9b0888b4b --- /dev/null +++ b/.github/scripts/selected-registry-needs.mts @@ -0,0 +1,34 @@ +#!/usr/bin/env bun +import { appendFileSync } from 'node:fs'; +import process from 'node:process'; + +import { loadPublicationCatalog } from '../../tools/release/publication-catalog.mts'; + +function fail(message) { + console.error(`selected-registry-needs: ${message}`); + process.exit(1); +} + +let products; +try { + products = JSON.parse(process.env.PRODUCTS_JSON ?? ''); +} catch (error) { + fail(`invalid PRODUCTS_JSON: ${error.message}`); +} +if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string') +) { + fail('PRODUCTS_JSON must be a non-empty product string list'); +} + +const catalog = loadPublicationCatalog('selected-registry-needs', { products }); +const ecosystems = new Set(catalog.carriers.map((carrier) => carrier.ecosystem)); +for (const ecosystem of ['cargo', 'npm', 'maven']) { + const line = `needs_${ecosystem}=${String(ecosystems.has(ecosystem))}`; + console.log(line); + if (process.env.GITHUB_OUTPUT) { + appendFileSync(process.env.GITHUB_OUTPUT, `${line}\n`, 'utf8'); + } +} diff --git a/.github/scripts/setup-native-build-tools.sh b/.github/scripts/setup-native-build-tools.sh index a71d604eb..15ded5622 100755 --- a/.github/scripts/setup-native-build-tools.sh +++ b/.github/scripts/setup-native-build-tools.sh @@ -22,6 +22,7 @@ install_macos_tools() { require_brew_tool autoconf autoconf require_brew_tool aclocal automake require_brew_tool glibtoolize libtool + require_brew_tool gtimeout coreutils if ((${#missing_packages[@]} > 0)); then local attempt @@ -123,13 +124,6 @@ install_choco_package() { } install_windows_tools() { - python -m pip install \ - --disable-pip-version-check \ - --retries 8 \ - --timeout 60 \ - --user \ - meson==1.10.0 \ - ninja==1.13.0 if [ ! -x /c/Strawberry/perl/bin/perl.exe ]; then install_choco_package strawberryperl /c/Strawberry/perl/bin/perl.exe fi @@ -138,7 +132,7 @@ install_windows_tools() { return 1 } local winflex_dir cache_root - cache_root="${RUNNER_TEMP:-$repo_root/target}/oliphaunt-native-tools" + cache_root="$(cygpath -u "${RUNNER_TEMP:-$repo_root/target}")/oliphaunt-native-tools" winflex_dir="$( OLIPHAUNT_PINNED_NATIVE_TOOL_CACHE_ROOT="$cache_root" \ bash "$repo_root/tools/dev/install-pinned-winflexbison.sh" @@ -148,7 +142,31 @@ install_windows_tools() { return 1 } export PATH="$winflex_dir:$PATH" + local meson_root meson_scripts + meson_root="$cache_root/meson-1.10.0-ninja-1.13.0" + meson_scripts="$meson_root/Scripts" + if [ ! -x "$meson_scripts/python.exe" ]; then + local python=(python.exe) + command -v python.exe >/dev/null || python=(py.exe -3) + "${python[@]}" -m venv "$(cygpath -m "$meson_root")" + fi + if [ ! -x "$meson_scripts/meson.exe" ] || [ ! -x "$meson_scripts/ninja.exe" ]; then + "$meson_scripts/python.exe" -m pip install --disable-pip-version-check --retries 8 --timeout 60 meson==1.10.0 ninja==1.13.0 + fi + export PATH="$meson_scripts:$PATH" + [ "$(meson --version | tr -d '\r')" = 1.10.0 ] || { + echo 'setup-native-build-tools.sh: pinned Meson setup failed' >&2 + return 1 + } + # The pinned PyPI wheels report platform-specific Kitware patch suffixes. + local ninja_version + ninja_version="$(ninja --version | tr -d '\r')" + case "$ninja_version" in + 1.13.0|1.13.0.gd74ef.kitware.jobserver-pipe-1|1.13.0.git.kitware.jobserver-pipe-1) ;; + *) echo "setup-native-build-tools.sh: expected Ninja from the pinned 1.13.0 distribution, got $ninja_version" >&2; return 1 ;; + esac if [ -n "${GITHUB_PATH:-}" ]; then + cygpath -w "$meson_scripts" >>"$GITHUB_PATH" if command -v cygpath >/dev/null 2>&1; then cygpath -w "$winflex_dir" >>"$GITHUB_PATH" else diff --git a/.github/scripts/setup-native-build-tools.test.sh b/.github/scripts/setup-native-build-tools.test.sh index 933de360a..ca56a770c 100755 --- a/.github/scripts/setup-native-build-tools.test.sh +++ b/.github/scripts/setup-native-build-tools.test.sh @@ -118,3 +118,70 @@ fi [ "$(cat "$tmp/sleep-calls.log")" = $'15\n30' ] || fail "bounded retry backoff mismatch" grep -Fq 'apt tool installation failed after 3 attempts' "$tmp/failure.err" || fail "terminal apt diagnostic missing" + +# Exercise the Windows setup with executable tool shims. The official Windows +# wheel has a different Kitware suffix from the Linux wheel of the same pin. +mkdir -p "$tmp/windows/tools/dev" "$tmp/windows/flex" \ + "$tmp/windows/cache/oliphaunt-native-tools/meson-1.10.0-ninja-1.13.0/Scripts" +printf '#!/usr/bin/env bash\nprintf "%%s\\n" "$WINDOWS_FIXTURE/flex"\n' \ + >"$tmp/windows/tools/dev/install-pinned-winflexbison.sh" +windows_scripts="$tmp/windows/cache/oliphaunt-native-tools/meson-1.10.0-ninja-1.13.0/Scripts" +for tool in python.exe meson.exe ninja.exe; do + printf '#!/usr/bin/env bash\nexit 99\n' >"$windows_scripts/$tool" +done +printf '#!/usr/bin/env bash\nprintf "1.10.0\\r\\n"\n' >"$windows_scripts/meson" +printf '#!/usr/bin/env bash\nprintf "%%s\\r\\n" "$NINJA_FIXTURE_VERSION"\n' >"$windows_scripts/ninja" +printf '#!/usr/bin/env bash\nprintf "%%s\\n" "$2"\n' >"$tmp/bin/cygpath" +touch "$tmp/windows/flex/win_flex.exe" "$tmp/windows/flex/win_bison.exe" +chmod +x "$windows_scripts/"* "$tmp/bin/cygpath" "$tmp/windows/flex/"* + +# These command shims are invoked indirectly by the sourced installer. +# shellcheck disable=SC2317 +run_windows_installer() ( + # Loading the entrypoint on an unrecognized fixture host only defines its + # functions. Windows file checks are mocked solely for the fixed Perl path. + uname() { printf 'FixtureHost\n'; } + export PATH="$tmp/bin:/usr/bin:/bin" + unset CCACHE_DIR + export CCACHE_CALL_LOG="$tmp/ccache-calls.log" + # shellcheck source=.github/scripts/setup-native-build-tools.sh + source "$installer" + unset -f uname + repo_root="$tmp/windows" + export RUNNER_TEMP="$repo_root/cache" WINDOWS_FIXTURE="$repo_root" + export NINJA_FIXTURE_VERSION="$1" + unset GITHUB_PATH + function [() { + if [[ "${1:-}" == -x && "${2:-}" == /c/Strawberry/perl/bin/perl.exe ]]; then + return 0 + fi + builtin [ "$@" + } + install_windows_tools +) +run_windows_installer 1.13.0.git.kitware.jobserver-pipe-1 >"$tmp/windows.out" 2>"$tmp/windows.err" || + fail "official Windows Ninja wheel was rejected: $(cat "$tmp/windows.err")" +if run_windows_installer 1.14.0 >"$tmp/windows-wrong.out" 2>"$tmp/windows-wrong.err"; then + fail "wrong Ninja version was accepted" +fi +grep -Fq 'got 1.14.0' "$tmp/windows-wrong.err" || fail "observed Ninja version missing from diagnostic" + +# Runner-provided browser and Microsoft feeds must not block unrelated build +# packages. Exercise the real source filter against an isolated apt layout. +mkdir -p "$tmp/apt/sources.list.d" "$tmp/apt-bin" +printf '%s\n' '#!/usr/bin/env bash' 'exec "$@"' >"$tmp/apt-bin/sudo" +chmod 0555 "$tmp/apt-bin/sudo" +printf '%s\n' \ + 'deb https://archive.ubuntu.com/ubuntu noble main' \ + 'deb https://dl.google.com/linux/chrome-stable/deb stable main' \ + 'deb https://packages.microsoft.com/repos/code stable main' >"$tmp/apt/sources.list" +printf '%s\n' 'deb https://dl.google.com/linux/chrome/deb stable main' >"$tmp/apt/sources.list.d/chrome.list" +printf '%s\n' 'Types: deb' 'URIs: https://dl.google.com/linux/chrome-stable/deb' 'Suites: stable' 'Components: main' >"$tmp/apt/sources.list.d/chrome.sources" +printf '%s\n' 'deb https://archive.ubuntu.com/ubuntu noble-updates main' >"$tmp/apt/sources.list.d/ubuntu.list" +sed "s|/etc/apt|$tmp/apt|g" "$root/.github/scripts/prepare-linux-apt.sh" >"$tmp/prepare-linux-apt.sh" +PATH="$tmp/apt-bin:$tmp/bin:/usr/bin:/bin" bash "$tmp/prepare-linux-apt.sh" +[ "$(grep -c '^deb ' "$tmp/apt/sources.list")" = "1" ] || fail "unrelated apt sources remain enabled" +grep -q '^deb https://archive.ubuntu.com/' "$tmp/apt/sources.list" || fail "Ubuntu source was disabled" +[ -f "$tmp/apt/sources.list.d/ubuntu.list" ] || fail "Ubuntu source file was disabled" +[ -f "$tmp/apt/sources.list.d/chrome.list.disabled" ] || fail "Chrome list remains enabled" +[ -f "$tmp/apt/sources.list.d/chrome.sources.disabled" ] || fail "Chrome deb822 source remains enabled" diff --git a/.github/scripts/validate-release-workflow-inputs.sh b/.github/scripts/validate-release-workflow-inputs.sh index db0972113..484395f5e 100644 --- a/.github/scripts/validate-release-workflow-inputs.sh +++ b/.github/scripts/validate-release-workflow-inputs.sh @@ -1,54 +1,37 @@ #!/usr/bin/env bash set -euo pipefail - : "${GITHUB_SHA:?GITHUB_SHA is required}" : "${GITHUB_REF:?GITHUB_REF is required}" : "${RELEASE_OPERATION:?RELEASE_OPERATION is required}" - release_commit="${RELEASE_COMMIT:-}" approval_run_id="${RELEASE_APPROVAL_RUN_ID:-}" - -if [[ ! "${GITHUB_SHA}" =~ ^[0-9a-fA-F]{40}$ ]]; then - echo "GITHUB_SHA must be a full 40-character commit SHA, got: ${GITHUB_SHA}" >&2 +if [[ ! "$GITHUB_SHA" =~ ^[0-9a-fA-F]{40}$ ]]; then + echo 'GITHUB_SHA must be a full 40-character commit SHA' >&2 exit 2 fi -normalized_github_sha="$(printf '%s' "${GITHUB_SHA}" | LC_ALL=C tr '[:upper:]' '[:lower:]')" - -case "${RELEASE_OPERATION}" in - prepare-release-pr|publish-dry-run|publish-bootstrap|publish) ;; - *) - echo "Unsupported release operation: ${RELEASE_OPERATION}" >&2 - exit 2 - ;; +case "$RELEASE_OPERATION" in + prepare-release-pr|publish) ;; + *) echo "Unsupported release operation: $RELEASE_OPERATION" >&2; exit 2 ;; esac - -# Preparation stays exact-SHA. Publishers additionally prove that a supplied -# approved source is an ancestor with only permitted publication-code changes. -if [[ -n "${release_commit}" ]]; then - if [[ ! "${release_commit}" =~ ^[0-9a-fA-F]{40}$ ]]; then - echo "release_commit must be a full 40-character commit SHA, got: ${release_commit}" >&2 - exit 2 +if [[ -n "$approval_run_id" ]]; then + if [[ "$RELEASE_OPERATION" != publish || ! "$approval_run_id" =~ ^[1-9][0-9]*$ ]]; then + echo 'approval_run_id is valid only for publication recovery and must be a positive integer' >&2 + exit 1 fi - normalized_release_commit="$(printf '%s' "${release_commit}" | LC_ALL=C tr '[:upper:]' '[:lower:]')" - if [[ "${normalized_release_commit}" != "${normalized_github_sha}" && "${RELEASE_OPERATION}" != publish && "${RELEASE_OPERATION}" != publish-bootstrap ]]; then - echo "release_commit must equal the exact workflow SHA" >&2 - echo "workflow commit: ${GITHUB_SHA}" >&2 - echo "release commit: ${release_commit}" >&2 +fi +if [[ -n "$release_commit" ]]; then + if [[ ! "$release_commit" =~ ^[0-9a-fA-F]{40}$ ]]; then + echo 'release_commit must be a full 40-character commit SHA' >&2 exit 2 fi -fi - -if [[ "${RELEASE_OPERATION}" == "publish" || "${RELEASE_OPERATION}" == "publish-bootstrap" ]]; then - if [[ ! "${approval_run_id}" =~ ^[1-9][0-9]*$ ]]; then - echo "${RELEASE_OPERATION} requires approval_run_id from the exact successful publish-dry-run" >&2 - exit 1 + workflow_sha="$(printf '%s' "$GITHUB_SHA" | LC_ALL=C tr '[:upper:]' '[:lower:]')" + source_sha="$(printf '%s' "$release_commit" | LC_ALL=C tr '[:upper:]' '[:lower:]')" + if [[ "$source_sha" != "$workflow_sha" && ( "$RELEASE_OPERATION" != publish || -z "$approval_run_id" ) ]]; then + echo 'release_commit must equal the exact workflow SHA unless recovering a frozen approved candidate' >&2 + exit 2 fi -elif [[ -n "${approval_run_id}" ]]; then - echo "approval_run_id is not valid for ${RELEASE_OPERATION}" >&2 - exit 1 fi - -if [[ "${GITHUB_REF}" != "refs/heads/main" ]]; then - echo "release operations must execute from refs/heads/main; got: ${GITHUB_REF}" >&2 +if [[ "$GITHUB_REF" != refs/heads/main ]]; then + echo "release operations must execute from refs/heads/main; got: $GITHUB_REF" >&2 exit 1 fi diff --git a/.github/scripts/verify-external-publish-readiness.mjs b/.github/scripts/verify-external-publish-readiness.mjs deleted file mode 100644 index d29116152..000000000 --- a/.github/scripts/verify-external-publish-readiness.mjs +++ /dev/null @@ -1,178 +0,0 @@ -#!/usr/bin/env bun -import process from "node:process"; - -import { loadPublicationCatalog } from "../../tools/release/publication-catalog.mjs"; -import { mavenCentralAuthorization } from "../../tools/release/maven-central-auth.mjs"; - -const MAVEN_CENTRAL_API_BASE = "https://central.sonatype.com"; -const MAX_READINESS_RESPONSE_BYTES = 1024 * 1024; - -function fail(message) { - console.error(`verify-external-publish-readiness: ${message}`); - process.exit(1); -} - -function requiredEnv(name) { - const value = process.env[name]?.trim(); - if (!value) { - fail(`${name} is required`); - } - return value; -} - -function productsFromEnvironment() { - let products; - try { - products = JSON.parse(requiredEnv("PRODUCTS_JSON")); - } catch (error) { - fail(`PRODUCTS_JSON must be strict JSON: ${error.message}`); - } - if ( - !Array.isArray(products) - || products.length === 0 - || products.some((product) => typeof product !== "string" || product.length === 0) - ) { - fail("PRODUCTS_JSON must be a non-empty product string list"); - } - return products; -} - -function safeResponseMessage(body) { - return body.replace(/[\r\n\t]+/gu, " ").trim().slice(0, 300); -} - -async function boundedResponseText(response, context) { - const contentLength = response.headers.get("content-length"); - if (contentLength !== null) { - const declared = Number(contentLength); - if (!Number.isSafeInteger(declared) || declared < 0) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`${context} returned an invalid Content-Length`); - } - if (declared > MAX_READINESS_RESPONSE_BYTES) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`${context} response exceeded ${MAX_READINESS_RESPONSE_BYTES} bytes`); - } - } - const reader = response.body?.getReader?.(); - if (reader === undefined) { - const text = await response.text(); - if (Buffer.byteLength(text) > MAX_READINESS_RESPONSE_BYTES) { - throw new Error(`${context} response exceeded ${MAX_READINESS_RESPONSE_BYTES} bytes`); - } - return text; - } - const chunks = []; - let size = 0; - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > MAX_READINESS_RESPONSE_BYTES) { - await reader.cancel().catch(() => {}); - throw new Error(`${context} response exceeded ${MAX_READINESS_RESPONSE_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - } finally { - reader.releaseLock(); - } - return Buffer.concat(chunks, size).toString("utf8"); -} - -async function requestJson(url, { authorization = undefined, context }) { - let lastFailure; - for (let attempt = 1; attempt <= 3; attempt += 1) { - try { - const headers = { - Accept: "application/json", - "User-Agent": "oliphaunt-release-readiness/1; https://github.com/f0rr0/oliphaunt", - }; - if (authorization !== undefined) { - headers.Authorization = authorization; - } - const response = await fetch(url, { - headers, - redirect: "error", - signal: AbortSignal.timeout(15_000), - }); - const body = await boundedResponseText(response, context); - if (!response.ok) { - const detail = safeResponseMessage(body); - const failure = `${context} returned HTTP ${response.status}${detail ? `: ${detail}` : ""}`; - if (response.status !== 429 && response.status < 500) { - fail(failure); - } - lastFailure = failure; - } else { - try { - return JSON.parse(body); - } catch (error) { - fail(`${context} returned invalid JSON: ${error.message}`); - } - } - } catch (error) { - lastFailure = `${context} request failed: ${error.message}`; - } - if (attempt < 3) { - await Bun.sleep(attempt * 500); - } - } - fail(lastFailure ?? `${context} request failed`); -} - -function mavenNamespaces(catalog, expectedNamespace) { - const groups = new Set(); - for (const carrier of catalog.carriers.filter(({ ecosystem }) => ecosystem === "maven")) { - const separator = carrier.name.indexOf(":"); - if (separator <= 0 || separator === carrier.name.length - 1) { - fail(`invalid Maven identity in publication catalog: ${carrier.name}`); - } - const group = carrier.name.slice(0, separator); - if (group !== expectedNamespace && !group.startsWith(`${expectedNamespace}.`)) { - fail(`Maven group ${group} is outside verified namespace ${expectedNamespace}`); - } - groups.add(group); - } - return [...groups].sort(); -} - -async function verifyMavenNamespace(catalog) { - const expectedNamespace = requiredEnv("MAVEN_CENTRAL_NAMESPACE"); - const groups = mavenNamespaces(catalog, expectedNamespace); - if (groups.length === 0) { - return; - } - const username = requiredEnv("ORG_GRADLE_PROJECT_mavenCentralUsername"); - const password = requiredEnv("ORG_GRADLE_PROJECT_mavenCentralPassword"); - const authorization = mavenCentralAuthorization(username, password); - const url = new URL("/api/v1/publisher/deployments", MAVEN_CENTRAL_API_BASE); - url.searchParams.set("namespace", expectedNamespace); - url.searchParams.set("page", "0"); - url.searchParams.set("size", "1"); - const result = await requestJson(url, { - authorization, - context: `Maven Central namespace ${expectedNamespace}`, - }); - if ( - !Array.isArray(result?.deployments) - || !Number.isInteger(result?.page) - || !Number.isInteger(result?.pageSize) - || !Number.isInteger(result?.pageCount) - || !Number.isInteger(result?.totalResultCount) - ) { - fail(`Maven Central namespace ${expectedNamespace} returned an unexpected response shape`); - } - console.log( - `Maven Central readiness passed: credentials can access ${expectedNamespace}; selected groups: ${groups.join(", ")}`, - ); -} - -const products = productsFromEnvironment(); -const catalog = loadPublicationCatalog("verify-external-publish-readiness", { products }); -await verifyMavenNamespace(catalog); - -if (!catalog.carriers.some(({ ecosystem }) => ecosystem === "maven")) { - console.log("selected products do not require Maven Central external readiness checks"); -} diff --git a/.github/scripts/verify-external-publish-readiness.mts b/.github/scripts/verify-external-publish-readiness.mts new file mode 100644 index 000000000..9d4349916 --- /dev/null +++ b/.github/scripts/verify-external-publish-readiness.mts @@ -0,0 +1,181 @@ +#!/usr/bin/env bun +import process from 'node:process'; + +import { loadPublicationCatalog } from '../../tools/release/publication-catalog.mts'; +import { mavenCentralAuthorization } from '../../tools/release/maven-central-auth.mts'; + +const MAVEN_CENTRAL_API_BASE = 'https://central.sonatype.com'; +const MAX_READINESS_RESPONSE_BYTES = 1024 * 1024; + +function fail(message) { + console.error(`verify-external-publish-readiness: ${message}`); + process.exit(1); +} + +function requiredEnv(name) { + const value = process.env[name]?.trim(); + if (!value) { + fail(`${name} is required`); + } + return value; +} + +function productsFromEnvironment() { + let products; + try { + products = JSON.parse(requiredEnv('PRODUCTS_JSON')); + } catch (error) { + fail(`PRODUCTS_JSON must be strict JSON: ${error.message}`); + } + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string' || product.length === 0) + ) { + fail('PRODUCTS_JSON must be a non-empty product string list'); + } + return products; +} + +function safeResponseMessage(body) { + return body + .replace(/[\r\n\t]+/gu, ' ') + .trim() + .slice(0, 300); +} + +async function boundedResponseText(response, context) { + const contentLength = response.headers.get('content-length'); + if (contentLength !== null) { + const declared = Number(contentLength); + if (!Number.isSafeInteger(declared) || declared < 0) { + await response.body?.cancel?.().catch(() => {}); + throw new Error(`${context} returned an invalid Content-Length`); + } + if (declared > MAX_READINESS_RESPONSE_BYTES) { + await response.body?.cancel?.().catch(() => {}); + throw new Error(`${context} response exceeded ${MAX_READINESS_RESPONSE_BYTES} bytes`); + } + } + const reader = response.body?.getReader?.(); + if (reader === undefined) { + const text = await response.text(); + if (Buffer.byteLength(text) > MAX_READINESS_RESPONSE_BYTES) { + throw new Error(`${context} response exceeded ${MAX_READINESS_RESPONSE_BYTES} bytes`); + } + return text; + } + const chunks = []; + let size = 0; + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > MAX_READINESS_RESPONSE_BYTES) { + await reader.cancel().catch(() => {}); + throw new Error(`${context} response exceeded ${MAX_READINESS_RESPONSE_BYTES} bytes`); + } + chunks.push(Buffer.from(value)); + } + } finally { + reader.releaseLock(); + } + return Buffer.concat(chunks, size).toString('utf8'); +} + +async function requestJson(url, { authorization = undefined, context }) { + let lastFailure; + for (let attempt = 1; attempt <= 3; attempt += 1) { + try { + const headers = { + Accept: 'application/json', + 'User-Agent': 'oliphaunt-release-readiness/1; https://github.com/f0rr0/oliphaunt', + }; + if (authorization !== undefined) { + headers.Authorization = authorization; + } + const response = await fetch(url, { + headers, + redirect: 'error', + signal: AbortSignal.timeout(15_000), + }); + const body = await boundedResponseText(response, context); + if (!response.ok) { + const detail = safeResponseMessage(body); + const failure = `${context} returned HTTP ${response.status}${detail ? `: ${detail}` : ''}`; + if (response.status !== 429 && response.status < 500) { + fail(failure); + } + lastFailure = failure; + } else { + try { + return JSON.parse(body); + } catch (error) { + fail(`${context} returned invalid JSON: ${error.message}`); + } + } + } catch (error) { + lastFailure = `${context} request failed: ${error.message}`; + } + if (attempt < 3) { + await Bun.sleep(attempt * 500); + } + } + fail(lastFailure ?? `${context} request failed`); +} + +function mavenNamespaces(catalog, expectedNamespace) { + const groups = new Set(); + for (const carrier of catalog.carriers.filter(({ ecosystem }) => ecosystem === 'maven')) { + const separator = carrier.name.indexOf(':'); + if (separator <= 0 || separator === carrier.name.length - 1) { + fail(`invalid Maven identity in publication catalog: ${carrier.name}`); + } + const group = carrier.name.slice(0, separator); + if (group !== expectedNamespace && !group.startsWith(`${expectedNamespace}.`)) { + fail(`Maven group ${group} is outside verified namespace ${expectedNamespace}`); + } + groups.add(group); + } + return [...groups].sort(); +} + +async function verifyMavenNamespace(catalog) { + const expectedNamespace = requiredEnv('MAVEN_CENTRAL_NAMESPACE'); + const groups = mavenNamespaces(catalog, expectedNamespace); + if (groups.length === 0) { + return; + } + const username = requiredEnv('ORG_GRADLE_PROJECT_mavenCentralUsername'); + const password = requiredEnv('ORG_GRADLE_PROJECT_mavenCentralPassword'); + const authorization = mavenCentralAuthorization(username, password); + const url = new URL('/api/v1/publisher/deployments', MAVEN_CENTRAL_API_BASE); + url.searchParams.set('namespace', expectedNamespace); + url.searchParams.set('page', '0'); + url.searchParams.set('size', '1'); + const result = await requestJson(url, { + authorization, + context: `Maven Central namespace ${expectedNamespace}`, + }); + if ( + !Array.isArray(result?.deployments) || + !Number.isInteger(result?.page) || + !Number.isInteger(result?.pageSize) || + !Number.isInteger(result?.pageCount) || + !Number.isInteger(result?.totalResultCount) + ) { + fail(`Maven Central namespace ${expectedNamespace} returned an unexpected response shape`); + } + console.log( + `Maven Central readiness passed: credentials can access ${expectedNamespace}; selected groups: ${groups.join(', ')}`, + ); +} + +const products = productsFromEnvironment(); +const catalog = loadPublicationCatalog('verify-external-publish-readiness', { products }); +await verifyMavenNamespace(catalog); + +if (!catalog.carriers.some(({ ecosystem }) => ecosystem === 'maven')) { + console.log('selected products do not require Maven Central external readiness checks'); +} diff --git a/.github/scripts/verify-github-oidc-identity.mjs b/.github/scripts/verify-github-oidc-identity.mjs deleted file mode 100644 index 4be9f8610..000000000 --- a/.github/scripts/verify-github-oidc-identity.mjs +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env bun - -import process from "node:process"; - -const TOOL = "verify-github-oidc-identity"; -const OIDC_ISSUER = "https://token.actions.githubusercontent.com"; -const OIDC_AUDIENCE = "oliphaunt-release-identity-preflight"; -const MAX_OIDC_RESPONSE_BYTES = 128 * 1024; -const CALLER_WORKFLOW = "release.yml"; -const CURRENT_JOB_WORKFLOW_ALIAS_CLAIMS = Object.freeze({ - job_workflow_ref: "workflow_ref", - job_workflow_sha: "workflow_sha", -}); -const ENVIRONMENT_BY_OPERATION = Object.freeze({ publish: "release-publish" }); - -function required(environment, name) { - const value = environment[name]?.trim(); - if (!value) { - throw new Error(`${name} is required`); - } - return value; -} - -function requireFullSha(value, name) { - if (!/^[0-9a-f]{40}$/u.test(value)) { - throw new Error(`${name} must be a lowercase full commit SHA; got ${value}`); - } - return value; -} - -export function expectedOidcIdentity(environment = process.env) { - const operation = required(environment, "RELEASE_OPERATION"); - const releaseEnvironment = ENVIRONMENT_BY_OPERATION[operation]; - if (releaseEnvironment === undefined) { - throw new Error(`RELEASE_OPERATION must be publish; got ${operation}`); - } - - const repository = required(environment, "CANONICAL_RELEASE_REPOSITORY"); - if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository)) { - throw new Error(`CANONICAL_RELEASE_REPOSITORY must be owner/repository; got ${repository}`); - } - const sha = requireFullSha(required(environment, "GITHUB_SHA"), "GITHUB_SHA"); - const ref = required(environment, "GITHUB_REF"); - const expectedRef = "refs/heads/main"; - if (ref !== expectedRef) { - throw new Error( - `trusted publication ref mismatch: expected ${expectedRef}, got ${ref}`, - ); - } - const eventName = required(environment, "GITHUB_EVENT_NAME"); - if (eventName !== "workflow_dispatch") { - throw new Error(`trusted publication must originate from workflow_dispatch; got ${eventName}`); - } - - return Object.freeze({ - aud: OIDC_AUDIENCE, - environment: releaseEnvironment, - event_name: eventName, - iss: OIDC_ISSUER, - ref, - ref_type: "branch", - repository, - runner_environment: "github-hosted", - sha, - workflow_ref: `${repository}/.github/workflows/${CALLER_WORKFLOW}@${ref}`, - workflow_sha: sha, - }); -} - -function printable(value) { - return typeof value === "string" ? JSON.stringify(value) : JSON.stringify(value ?? null); -} - -export function verifyOidcClaims(claims, expected) { - if (claims === null || typeof claims !== "object" || Array.isArray(claims)) { - throw new Error("GitHub OIDC token payload must be an object"); - } - // GitHub may expose the current-job workflow ref without its SHA. A directly - // defined job aliases the canonical workflow identity; a called workflow - // does not. The SHA alone does not identify a workflow file, so accept it - // only when the exact ref alias is also present. Do not require the reverse - // undocumented co-presence relationship. - if ( - Object.hasOwn(claims, "job_workflow_sha") && - !Object.hasOwn(claims, "job_workflow_ref") - ) { - throw new Error( - "GitHub OIDC claim job_workflow_sha requires claim job_workflow_ref", - ); - } - for (const [claim, canonicalClaim] of Object.entries(CURRENT_JOB_WORKFLOW_ALIAS_CLAIMS)) { - if (Object.hasOwn(claims, claim) && claims[claim] !== expected[canonicalClaim]) { - throw new Error( - `GitHub OIDC claim ${claim} mismatch: expected ${printable(expected[canonicalClaim])}, got ${printable(claims[claim])}`, - ); - } - } - for (const [claim, value] of Object.entries(expected)) { - if (claims[claim] !== value) { - throw new Error( - `GitHub OIDC claim ${claim} mismatch: expected ${printable(value)}, got ${printable(claims[claim])}`, - ); - } - } - return claims; -} - -export function decodeJwtPayload(token) { - if (typeof token !== "string" || token.length === 0 || token.length > 100_000) { - throw new Error("GitHub OIDC response did not contain a bounded JWT"); - } - const parts = token.split("."); - if (parts.length !== 3 || parts.some((part) => part.length === 0)) { - throw new Error("GitHub OIDC response was not a three-part JWT"); - } - let payload; - try { - payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8")); - } catch (error) { - throw new Error(`GitHub OIDC JWT payload is invalid: ${error.message}`); - } - if (payload === null || typeof payload !== "object" || Array.isArray(payload)) { - throw new Error("GitHub OIDC JWT payload must be an object"); - } - return payload; -} - -export function oidcRequestUrl(rawUrl) { - let url; - try { - url = new URL(rawUrl); - } catch (error) { - throw new Error(`ACTIONS_ID_TOKEN_REQUEST_URL is invalid: ${error.message}`); - } - if (url.protocol !== "https:") { - throw new Error("ACTIONS_ID_TOKEN_REQUEST_URL must use HTTPS"); - } - url.searchParams.set("audience", OIDC_AUDIENCE); - return url; -} - -export async function readBoundedOidcResponse(response) { - const contentLength = response.headers.get("content-length"); - if (contentLength !== null) { - const declaredLength = Number(contentLength); - if (!Number.isSafeInteger(declaredLength) || declaredLength < 0) { - throw new Error("GitHub OIDC endpoint returned an invalid Content-Length"); - } - if (declaredLength > MAX_OIDC_RESPONSE_BYTES) { - throw new Error("GitHub OIDC endpoint response exceeded the byte limit"); - } - } - - if (response.body === null) { - return ""; - } - const reader = response.body.getReader(); - const chunks = []; - let total = 0; - try { - while (true) { - const { done, value } = await reader.read(); - if (done) break; - total += value.byteLength; - if (total > MAX_OIDC_RESPONSE_BYTES) { - await reader.cancel(); - throw new Error("GitHub OIDC endpoint response exceeded the byte limit"); - } - chunks.push(value); - } - } finally { - reader.releaseLock(); - } - return Buffer.concat(chunks, total).toString("utf8"); -} - -async function requestOidcToken(environment = process.env, fetchImpl = fetch) { - const url = oidcRequestUrl(required(environment, "ACTIONS_ID_TOKEN_REQUEST_URL")); - const requestToken = required(environment, "ACTIONS_ID_TOKEN_REQUEST_TOKEN"); - const response = await fetchImpl(url, { - headers: { - Accept: "application/json", - Authorization: `Bearer ${requestToken}`, - }, - redirect: "error", - signal: AbortSignal.timeout(15_000), - }); - const body = await readBoundedOidcResponse(response); - if (!response.ok) { - throw new Error(`GitHub OIDC endpoint returned HTTP ${response.status}`); - } - let result; - try { - result = JSON.parse(body); - } catch (error) { - throw new Error(`GitHub OIDC endpoint returned invalid JSON: ${error.message}`); - } - if (typeof result?.value !== "string" || result.value.length === 0) { - throw new Error("GitHub OIDC endpoint response did not contain a token value"); - } - return result.value; -} - -export async function verifyGithubOidcIdentity(environment = process.env, fetchImpl = fetch) { - const expected = expectedOidcIdentity(environment); - const token = await requestOidcToken(environment, fetchImpl); - const claims = decodeJwtPayload(token); - verifyOidcClaims(claims, expected); - return expected; -} - -async function main() { - try { - const expected = await verifyGithubOidcIdentity(); - console.log( - `GitHub OIDC identity passed: workflow=${expected.workflow_ref}, environment=${expected.environment}`, - ); - } catch (error) { - console.error(`${TOOL}: ${error.message}`); - process.exit(1); - } -} - -if (import.meta.main) { - await main(); -} diff --git a/.github/scripts/verify-github-oidc-identity.mts b/.github/scripts/verify-github-oidc-identity.mts new file mode 100644 index 000000000..43b06491a --- /dev/null +++ b/.github/scripts/verify-github-oidc-identity.mts @@ -0,0 +1,219 @@ +#!/usr/bin/env bun + +import process from 'node:process'; + +const TOOL = 'verify-github-oidc-identity'; +const OIDC_ISSUER = 'https://token.actions.githubusercontent.com'; +const OIDC_AUDIENCE = 'oliphaunt-release-identity-preflight'; +const MAX_OIDC_RESPONSE_BYTES = 128 * 1024; +const CALLER_WORKFLOW = 'release.yml'; +const CURRENT_JOB_WORKFLOW_ALIAS_CLAIMS = Object.freeze({ + job_workflow_ref: 'workflow_ref', + job_workflow_sha: 'workflow_sha', +}); +const ENVIRONMENT_BY_OPERATION = Object.freeze({ publish: 'release-publish' }); + +function required(environment, name) { + const value = environment[name]?.trim(); + if (!value) { + throw new Error(`${name} is required`); + } + return value; +} + +function requireFullSha(value, name) { + if (!/^[0-9a-f]{40}$/u.test(value)) { + throw new Error(`${name} must be a lowercase full commit SHA; got ${value}`); + } + return value; +} + +export function expectedOidcIdentity(environment = process.env) { + const operation = required(environment, 'RELEASE_OPERATION'); + const releaseEnvironment = ENVIRONMENT_BY_OPERATION[operation]; + if (releaseEnvironment === undefined) { + throw new Error(`RELEASE_OPERATION must be publish; got ${operation}`); + } + + const repository = required(environment, 'CANONICAL_RELEASE_REPOSITORY'); + if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository)) { + throw new Error(`CANONICAL_RELEASE_REPOSITORY must be owner/repository; got ${repository}`); + } + const sha = requireFullSha(required(environment, 'GITHUB_SHA'), 'GITHUB_SHA'); + const ref = required(environment, 'GITHUB_REF'); + const expectedRef = 'refs/heads/main'; + if (ref !== expectedRef) { + throw new Error(`trusted publication ref mismatch: expected ${expectedRef}, got ${ref}`); + } + const eventName = required(environment, 'GITHUB_EVENT_NAME'); + if (eventName !== 'workflow_dispatch') { + throw new Error(`trusted publication must originate from workflow_dispatch; got ${eventName}`); + } + + return Object.freeze({ + aud: OIDC_AUDIENCE, + environment: releaseEnvironment, + event_name: eventName, + iss: OIDC_ISSUER, + ref, + ref_type: 'branch', + repository, + runner_environment: 'github-hosted', + sha, + workflow_ref: `${repository}/.github/workflows/${CALLER_WORKFLOW}@${ref}`, + workflow_sha: sha, + }); +} + +function printable(value) { + return typeof value === 'string' ? JSON.stringify(value) : JSON.stringify(value ?? null); +} + +export function verifyOidcClaims(claims, expected) { + if (claims === null || typeof claims !== 'object' || Array.isArray(claims)) { + throw new Error('GitHub OIDC token payload must be an object'); + } + // GitHub may expose the current-job workflow ref without its SHA. A directly + // defined job aliases the canonical workflow identity; a called workflow + // does not. The SHA alone does not identify a workflow file, so accept it + // only when the exact ref alias is also present. Do not require the reverse + // undocumented co-presence relationship. + if (Object.hasOwn(claims, 'job_workflow_sha') && !Object.hasOwn(claims, 'job_workflow_ref')) { + throw new Error('GitHub OIDC claim job_workflow_sha requires claim job_workflow_ref'); + } + for (const [claim, canonicalClaim] of Object.entries(CURRENT_JOB_WORKFLOW_ALIAS_CLAIMS)) { + if (Object.hasOwn(claims, claim) && claims[claim] !== expected[canonicalClaim]) { + throw new Error( + `GitHub OIDC claim ${claim} mismatch: expected ${printable(expected[canonicalClaim])}, got ${printable(claims[claim])}`, + ); + } + } + for (const [claim, value] of Object.entries(expected)) { + if (claims[claim] !== value) { + throw new Error( + `GitHub OIDC claim ${claim} mismatch: expected ${printable(value)}, got ${printable(claims[claim])}`, + ); + } + } + return claims; +} + +export function decodeJwtPayload(token) { + if (typeof token !== 'string' || token.length === 0 || token.length > 100_000) { + throw new Error('GitHub OIDC response did not contain a bounded JWT'); + } + const parts = token.split('.'); + if (parts.length !== 3 || parts.some((part) => part.length === 0)) { + throw new Error('GitHub OIDC response was not a three-part JWT'); + } + let payload; + try { + payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8')); + } catch (error) { + throw new Error(`GitHub OIDC JWT payload is invalid: ${error.message}`); + } + if (payload === null || typeof payload !== 'object' || Array.isArray(payload)) { + throw new Error('GitHub OIDC JWT payload must be an object'); + } + return payload; +} + +export function oidcRequestUrl(rawUrl) { + let url; + try { + url = new URL(rawUrl); + } catch (error) { + throw new Error(`ACTIONS_ID_TOKEN_REQUEST_URL is invalid: ${error.message}`); + } + if (url.protocol !== 'https:') { + throw new Error('ACTIONS_ID_TOKEN_REQUEST_URL must use HTTPS'); + } + url.searchParams.set('audience', OIDC_AUDIENCE); + return url; +} + +export async function readBoundedOidcResponse(response) { + const contentLength = response.headers.get('content-length'); + if (contentLength !== null) { + const declaredLength = Number(contentLength); + if (!Number.isSafeInteger(declaredLength) || declaredLength < 0) { + throw new Error('GitHub OIDC endpoint returned an invalid Content-Length'); + } + if (declaredLength > MAX_OIDC_RESPONSE_BYTES) { + throw new Error('GitHub OIDC endpoint response exceeded the byte limit'); + } + } + + if (response.body === null) { + return ''; + } + const reader = response.body.getReader(); + const chunks = []; + let total = 0; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + total += value.byteLength; + if (total > MAX_OIDC_RESPONSE_BYTES) { + await reader.cancel(); + throw new Error('GitHub OIDC endpoint response exceeded the byte limit'); + } + chunks.push(value); + } + } finally { + reader.releaseLock(); + } + return Buffer.concat(chunks, total).toString('utf8'); +} + +async function requestOidcToken(environment = process.env, fetchImpl = fetch) { + const url = oidcRequestUrl(required(environment, 'ACTIONS_ID_TOKEN_REQUEST_URL')); + const requestToken = required(environment, 'ACTIONS_ID_TOKEN_REQUEST_TOKEN'); + const response = await fetchImpl(url, { + headers: { + Accept: 'application/json', + Authorization: `Bearer ${requestToken}`, + }, + redirect: 'error', + signal: AbortSignal.timeout(15_000), + }); + const body = await readBoundedOidcResponse(response); + if (!response.ok) { + throw new Error(`GitHub OIDC endpoint returned HTTP ${response.status}`); + } + let result; + try { + result = JSON.parse(body); + } catch (error) { + throw new Error(`GitHub OIDC endpoint returned invalid JSON: ${error.message}`); + } + if (typeof result?.value !== 'string' || result.value.length === 0) { + throw new Error('GitHub OIDC endpoint response did not contain a token value'); + } + return result.value; +} + +export async function verifyGithubOidcIdentity(environment = process.env, fetchImpl = fetch) { + const expected = expectedOidcIdentity(environment); + const token = await requestOidcToken(environment, fetchImpl); + const claims = decodeJwtPayload(token); + verifyOidcClaims(claims, expected); + return expected; +} + +async function main() { + try { + const expected = await verifyGithubOidcIdentity(); + console.log( + `GitHub OIDC identity passed: workflow=${expected.workflow_ref}, environment=${expected.environment}`, + ); + } catch (error) { + console.error(`${TOOL}: ${error.message}`); + process.exit(1); + } +} + +if (import.meta.main) { + await main(); +} diff --git a/.github/scripts/verify-release-candidate.mjs b/.github/scripts/verify-release-candidate.mjs deleted file mode 100644 index 8b122661d..000000000 --- a/.github/scripts/verify-release-candidate.mjs +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env bun -import { readFileSync } from "node:fs"; -import process from "node:process"; - -import { captureCommandOutput } from "../../tools/dev/capture-command-output.mjs"; - -import { - affectedPlanBinding, - assertBindingMatches, - assertCandidateBindingShape, - candidateQualificationMode, - FULL_PAYLOAD_QUALIFICATION_MODE, - wasixEvidenceBinding, -} from "./release-candidate-lib.mjs"; - -function fail(message) { - console.error(message); - process.exit(1); -} - -function requiredEnv(name) { - const value = process.env[name]?.trim(); - if (!value) { - fail(`${name} is required`); - } - return value; -} - -function git(args) { - const result = captureCommandOutput("git", args, { - label: `git ${args.join(" ")}`, - }); - if (result.error || result.status !== 0) { - fail(result.stderr?.trim() || result.error?.message || `git ${args.join(" ")} failed`); - } - return result.stdout.trim(); -} - -function parseArgs(argv) { - const candidatePath = argv[0]; - const values = new Map(); - for (let index = 1; index < argv.length; index += 1) { - const name = argv[index]; - if (![ - "--plan", - "--qualification-mode", - "--wasix-evidence-required", - "--wasix-evidence-root", - ].includes(name)) { - fail(`unknown argument: ${name}`); - } - if (index + 1 >= argv.length) { - fail(`${name} requires a value`); - } - values.set(name.slice(2), argv[index + 1]); - index += 1; - } - if (!candidatePath || !values.has("plan") || !values.has("wasix-evidence-required")) { - fail( - "usage: verify-release-candidate.mjs --plan " - + "--wasix-evidence-required true|false [--qualification-mode full-payload] " - + "[--wasix-evidence-root ]", - ); - } - const required = values.get("wasix-evidence-required"); - if (!["true", "false"].includes(required)) { - fail("--wasix-evidence-required must be true or false"); - } - if (required === "true" && !values.has("wasix-evidence-root")) { - fail("--wasix-evidence-root is required when WASIX evidence is required"); - } - const qualificationMode = values.get("qualification-mode") ?? FULL_PAYLOAD_QUALIFICATION_MODE; - if (qualificationMode !== FULL_PAYLOAD_QUALIFICATION_MODE) { - fail("--qualification-mode must be full-payload"); - } - return { - candidatePath, - planPath: values.get("plan"), - wasixEvidenceRequired: required === "true", - wasixEvidenceRoot: values.get("wasix-evidence-root"), - qualificationMode, - }; -} - -const args = parseArgs(process.argv.slice(2)); - -let candidate; -try { - candidate = JSON.parse(readFileSync(args.candidatePath, "utf8")); -} catch (error) { - fail(`invalid release candidate ${args.candidatePath}: ${error.message}`); -} - -try { - assertCandidateBindingShape(candidate); -} catch (error) { - fail(error.message); -} -if (candidateQualificationMode(candidate) !== args.qualificationMode) { - fail( - `release candidate qualification mode mismatch: expected ${args.qualificationMode}, ` - + `got ${candidateQualificationMode(candidate)}`, - ); -} - -const expected = { - repository: requiredEnv("GITHUB_REPOSITORY"), - runId: requiredEnv("CI_RUN_ID"), - sha: requiredEnv("RELEASE_HEAD_SHA").toLowerCase(), -}; -const expectedTree = git(["rev-parse", `${expected.sha}^{tree}`]).toLowerCase(); - -for (const [field, value] of Object.entries({ - schemaVersion: 2, - repository: expected.repository, - workflow: "CI", - runId: expected.runId, - ref: "refs/heads/main", - sha: expected.sha, - tree: expectedTree, -})) { - if (candidate?.[field] !== value) { - fail(`release candidate ${field} mismatch: expected ${value}, got ${candidate?.[field]}`); - } -} - -if (!["push", "workflow_dispatch"].includes(candidate.eventName)) { - fail(`release candidate event must be push or workflow_dispatch, got ${candidate.eventName}`); -} -if (!Number.isSafeInteger(candidate.runAttempt) || candidate.runAttempt < 1) { - fail(`release candidate has invalid runAttempt: ${candidate.runAttempt}`); -} -if (typeof candidate.workflowRef !== "string" || !candidate.workflowRef.includes("/.github/workflows/ci.yml@")) { - fail(`release candidate has invalid workflowRef: ${candidate.workflowRef}`); -} - -let expectedPlan; -try { - expectedPlan = affectedPlanBinding( - args.planPath, - candidate.affectedPlan.wasixReleaseRegressionRequired, - ); -} catch (error) { - fail(error.message); -} -try { - assertBindingMatches(candidate.affectedPlan, expectedPlan, "release candidate affected plan"); -} catch (error) { - fail(error.message); -} - -if (args.wasixEvidenceRequired) { - if (!candidate.evidenceRequirements.wasixReleaseRegression) { - fail("selected release products require WASIX evidence, but the qualified CI plan did not require it"); - } - let evidence; - try { - evidence = wasixEvidenceBinding(args.wasixEvidenceRoot, { - repository: expected.repository, - workflow: "CI", - runId: expected.runId, - runAttempt: candidate.runAttempt, - sha: expected.sha, - tree: expectedTree, - }); - } catch (error) { - fail(error.message); - } - try { - assertBindingMatches( - candidate.evidence.wasixReleaseRegression, - evidence, - "release candidate WASIX evidence", - ); - } catch (error) { - fail(error.message); - } -} - -console.log(`verified qualified CI run ${candidate.runId} for ${candidate.sha}`); diff --git a/.github/scripts/verify-release-candidate.mts b/.github/scripts/verify-release-candidate.mts new file mode 100644 index 000000000..9a9ba41fd --- /dev/null +++ b/.github/scripts/verify-release-candidate.mts @@ -0,0 +1,198 @@ +#!/usr/bin/env bun +import { readFileSync } from 'node:fs'; +import process from 'node:process'; + +import { + affectedPlanBinding, + assertBindingMatches, + assertCandidateBindingShape, + candidateQualificationMode, + FULL_PAYLOAD_QUALIFICATION_MODE, + PRODUCT_QUALIFICATION_MODE, + assertQualificationProductCoverage, + wasixEvidenceBinding, +} from './release-candidate-lib.mts'; + +function fail(message) { + console.error(message); + process.exit(1); +} + +function requiredEnv(name) { + const value = process.env[name]?.trim(); + if (!value) { + fail(`${name} is required`); + } + return value; +} + +function parseArgs(argv) { + const candidatePath = argv[0]; + const values = new Map(); + for (let index = 1; index < argv.length; index += 1) { + const name = argv[index]; + if ( + ![ + '--plan', + '--qualification-mode', + '--products-json', + '--wasix-evidence-required', + '--wasix-evidence-root', + ].includes(name) + ) { + fail(`unknown argument: ${name}`); + } + if (index + 1 >= argv.length) { + fail(`${name} requires a value`); + } + values.set(name.slice(2), argv[index + 1]); + index += 1; + } + if (!candidatePath || !values.has('plan') || !values.has('wasix-evidence-required')) { + fail( + 'usage: verify-release-candidate.mts --plan ' + + '--wasix-evidence-required true|false [--qualification-mode full-payload] ' + + '[--wasix-evidence-root ]', + ); + } + const required = values.get('wasix-evidence-required'); + if (!['true', 'false'].includes(required)) { + fail('--wasix-evidence-required must be true or false'); + } + if (required === 'true' && !values.has('wasix-evidence-root')) { + fail('--wasix-evidence-root is required when WASIX evidence is required'); + } + const qualificationMode = values.get('qualification-mode') ?? FULL_PAYLOAD_QUALIFICATION_MODE; + if ( + ![FULL_PAYLOAD_QUALIFICATION_MODE, PRODUCT_QUALIFICATION_MODE, 'release'].includes( + qualificationMode, + ) + ) { + fail('--qualification-mode must be full-payload, selected-products, or release'); + } + const products = values.has('products-json') + ? JSON.parse(values.get('products-json')) + : undefined; + if (qualificationMode !== FULL_PAYLOAD_QUALIFICATION_MODE && products === undefined) + fail('--products-json is required for product qualification'); + return { + candidatePath, + planPath: values.get('plan'), + wasixEvidenceRequired: required === 'true', + wasixEvidenceRoot: values.get('wasix-evidence-root'), + qualificationMode, + products, + }; +} + +const args = parseArgs(process.argv.slice(2)); + +let candidate; +try { + candidate = JSON.parse(readFileSync(args.candidatePath, 'utf8')); +} catch (error) { + fail(`invalid release candidate ${args.candidatePath}: ${error.message}`); +} + +try { + assertCandidateBindingShape(candidate); +} catch (error) { + fail(error.message); +} +if ( + args.qualificationMode !== 'release' && + candidateQualificationMode(candidate) !== args.qualificationMode +) { + fail( + `release candidate qualification mode mismatch: expected ${args.qualificationMode}, ` + + `got ${candidateQualificationMode(candidate)}`, + ); +} +if (args.products !== undefined) { + try { + assertQualificationProductCoverage(candidate, args.products); + } catch (error) { + fail(error.message); + } +} + +const expected = { + repository: requiredEnv('GITHUB_REPOSITORY'), + runId: requiredEnv('CI_RUN_ID'), + sha: requiredEnv('RELEASE_HEAD_SHA').toLowerCase(), +}; +const expectedTree = requiredEnv('CI_SOURCE_TREE').toLowerCase(); + +for (const [field, value] of Object.entries({ + schemaVersion: 2, + repository: expected.repository, + workflow: 'CI', + runId: expected.runId, + ref: 'refs/heads/main', + sha: expected.sha, + tree: expectedTree, +})) { + if (candidate?.[field] !== value) { + fail(`release candidate ${field} mismatch: expected ${value}, got ${candidate?.[field]}`); + } +} + +if (!['push', 'workflow_dispatch'].includes(candidate.eventName)) { + fail(`release candidate event must be push or workflow_dispatch, got ${candidate.eventName}`); +} +if (!Number.isSafeInteger(candidate.runAttempt) || candidate.runAttempt < 1) { + fail(`release candidate has invalid runAttempt: ${candidate.runAttempt}`); +} +if ( + typeof candidate.workflowRef !== 'string' || + !candidate.workflowRef.includes('/.github/workflows/ci.yml@') +) { + fail(`release candidate has invalid workflowRef: ${candidate.workflowRef}`); +} + +let expectedPlan; +try { + expectedPlan = affectedPlanBinding( + args.planPath, + candidate.affectedPlan.wasixReleaseRegressionRequired, + ); +} catch (error) { + fail(error.message); +} +try { + assertBindingMatches(candidate.affectedPlan, expectedPlan, 'release candidate affected plan'); +} catch (error) { + fail(error.message); +} + +if (args.wasixEvidenceRequired) { + if (!candidate.evidenceRequirements.wasixReleaseRegression) { + fail( + 'selected release products require WASIX evidence, but the qualified CI plan did not require it', + ); + } + let evidence; + try { + evidence = wasixEvidenceBinding(args.wasixEvidenceRoot, { + repository: expected.repository, + workflow: 'CI', + runId: expected.runId, + runAttempt: candidate.runAttempt, + sha: expected.sha, + tree: expectedTree, + }); + } catch (error) { + fail(error.message); + } + try { + assertBindingMatches( + candidate.evidence.wasixReleaseRegression, + evidence, + 'release candidate WASIX evidence', + ); + } catch (error) { + fail(error.message); + } +} + +console.log(`verified qualified CI run ${candidate.runId} for ${candidate.sha}`); diff --git a/.github/scripts/workflow-run-metadata.mts b/.github/scripts/workflow-run-metadata.mts new file mode 100644 index 000000000..0e43365fe --- /dev/null +++ b/.github/scripts/workflow-run-metadata.mts @@ -0,0 +1,295 @@ +import * as fs from 'node:fs'; +import { + assertCandidateBindingShape, + assertQualificationProductCoverage, + qualificationRequestKey, +} from './release-candidate-lib.mts'; + +const [command, ...args] = Bun.argv.slice(2); +switch (command) { + case 'qualification-request': { + const products = JSON.parse(process.env.PRODUCTS_JSON); + const key = qualificationRequestKey(process.env.EXPECTED_SHA, products); + console.log( + JSON.stringify({ + ref: 'main', + inputs: { + release_products_json: JSON.stringify([...products].sort()), + qualification_request: key, + wasm_target: 'all', + native_target: 'all', + mobile_target: 'all', + }, + }), + ); + break; + } + case 'qualification-key': { + console.log( + qualificationRequestKey(process.env.EXPECTED_SHA, JSON.parse(process.env.PRODUCTS_JSON)), + ); + break; + } + case 'dispatch-run-id': { + const response = await Bun.stdin.json(); + if (!Number.isSafeInteger(response.workflow_run_id) || response.workflow_run_id <= 0) + throw new Error( + 'dispatch response is missing its workflow run ID; do not repeat an ambiguous request', + ); + console.log(response.workflow_run_id); + break; + } + case 'main-sha': { + const response = await Bun.stdin.json(); + if (!/^[0-9a-f]{40}$/.test(response.object?.sha ?? '')) + throw new Error('main ref is missing its commit SHA'); + console.log(response.object.sha); + break; + } + case 'qualification-coverage': { + const candidate = JSON.parse(fs.readFileSync(args[0], 'utf8')); + assertCandidateBindingShape(candidate); + for (const [key, expected] of Object.entries({ + sha: process.env.EXPECTED_SHA, + runId: process.env.EXPECTED_RUN_ID, + repository: process.env.GH_REPO, + workflow: 'CI', + ref: 'refs/heads/main', + })) { + if (candidate[key] !== expected) + throw new Error(`qualification ${key} does not match the requested run`); + } + if ( + candidate.runAttempt !== Number(process.env.EXPECTED_RUN_ATTEMPT) || + !['push', 'workflow_dispatch'].includes(candidate.eventName) + ) + throw new Error('qualification attempt/event mismatch'); + try { + assertQualificationProductCoverage(candidate, JSON.parse(process.env.PRODUCTS_JSON)); + } catch (error) { + if (error.message.includes('missing qualification for product')) process.exit(3); + throw error; + } + break; + } + case 'run-row': { + const run = await Bun.stdin.json(); + if ( + !/^[0-9A-Fa-f]{40}$/u.test(run.head_sha ?? '') || + !Number.isSafeInteger(run.workflow_id) || + run.workflow_id <= 0 || + !Number.isSafeInteger(run.run_attempt) || + run.run_attempt <= 0 || + [run.event, run.status, run.conclusion ?? ''].some( + (value) => typeof value !== 'string' || /[^a-z_]/u.test(value), + ) + ) + throw new Error('malformed workflow run metadata'); + console.log( + [ + run.head_sha, + run.workflow_id, + run.event, + run.status, + run.conclusion ?? '', + run.run_attempt, + ].join('\t'), + ); + break; + } + case 'workflow-name': { + const workflow = await Bun.stdin.json(); + if ( + typeof workflow.name !== 'string' || + !workflow.name || + /[\u0000-\u001f\u007f]/u.test(workflow.name) + ) + throw new Error('malformed workflow name'); + console.log(workflow.name); + break; + } + case 'artifact-ids': { + console.log( + 'artifact_ids=' + + JSON.parse(process.env.ARTIFACTS_JSON) + .map((row) => row.id) + .join(','), + ); + break; + } + case 'names': { + const names = (await Bun.stdin.text()).split(/\r?\n/u).filter(Boolean); + process.stdout.write(JSON.stringify(names)); + break; + } + case 'select-artifacts': { + const expected = JSON.parse(process.env.REQUIRED_ARTIFACTS_JSON); + const gates = JSON.parse(process.env.GATE_ARTIFACTS_JSON); + let records; + try { + records = JSON.parse(await Bun.stdin.text()); + } catch (cause) { + console.error(`artifact inventory is not valid JSON: ${cause.message}`); + process.exit(64); + } + if ( + !Array.isArray(expected) || + !Array.isArray(gates) || + expected.length + gates.length === 0 || + [...expected, ...gates].some((name) => typeof name !== 'string' || name.length === 0) || + new Set([...expected, ...gates]).size !== expected.length + gates.length + ) { + console.error('required artifact identity list is malformed'); + process.exit(64); + } + if ( + !Array.isArray(records) || + records.some( + (entry) => + entry === null || + Array.isArray(entry) || + typeof entry !== 'object' || + typeof entry.name !== 'string' || + typeof entry.expired !== 'boolean' || + !Number.isSafeInteger(entry.id) || + entry.id < 1 || + !Number.isSafeInteger(entry.size_in_bytes) || + entry.size_in_bytes < 1 || + typeof entry.digest !== 'string' || + !/^sha256:[0-9a-f]{64}$/u.test(entry.digest), + ) + ) { + console.error('artifact inventory contains malformed metadata'); + process.exit(64); + } + const selected = []; + const selectedGates = []; + for (const name of [...expected, ...gates]) { + const matches = records.filter((entry) => entry.name === name && entry.expired === false); + if (matches.length !== 1) { + console.error( + `expected exactly one non-expired artifact named ${name}; found ${matches.length}`, + ); + process.exit(1); + } + const [entry] = matches; + const record = { + digest: entry.digest, + id: entry.id, + name: entry.name, + size: entry.size_in_bytes, + }; + (expected.includes(name) ? selected : selectedGates).push(record); + } + selected.sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0)); + selectedGates.sort((left, right) => + left.name < right.name ? -1 : left.name > right.name ? 1 : 0, + ); + process.stdout.write(JSON.stringify({ selected, selectedGates })); + break; + } + case 'selected-artifacts': { + const value = JSON.parse(process.env.SELECTION_JSON); + process.stdout.write(JSON.stringify(value.selected)); + break; + } + case 'selected-gates': { + const value = JSON.parse(process.env.SELECTION_JSON); + process.stdout.write(JSON.stringify(value.selectedGates)); + break; + } + case 'jobs': { + const data = JSON.parse(fs.readFileSync(args[0], 'utf8')); + const required = args.slice(1); + if (!Array.isArray(data)) { + console.error('workflow job inventory must be a list'); + process.exit(1); + } + const failures = required + .map((name) => { + const matches = data.filter((job) => job?.name === name); + if (matches.length !== 1) return [name, `count-${matches.length}`]; + return [name, matches[0]?.conclusion ?? 'missing']; + }) + .filter(([, conclusion]) => conclusion !== 'success'); + if (failures.length > 0) { + console.error(failures.map(([name, conclusion]) => `${name}=${conclusion}`).join(', ')); + process.exit(1); + } + break; + } + case 'workflow-id': { + const expected = process.env.WORKFLOW_NAME; + let rows; + try { + rows = JSON.parse(await Bun.stdin.text()); + } catch (cause) { + console.error(`workflow inventory is not valid JSON: ${cause.message}`); + process.exit(1); + } + if (!Array.isArray(rows)) { + console.error('workflow inventory must be a list'); + process.exit(1); + } + const matches = rows.filter((row) => row?.name === expected); + if (matches.length !== 1 || !Number.isSafeInteger(matches[0]?.id) || matches[0].id < 1) { + console.error(`expected exactly one workflow named ${expected}; found ${matches.length}`); + process.exit(1); + } + process.stdout.write(String(matches[0].id)); + break; + } + case 'runs': { + const expectedSha = process.env.EXPECTED_SHA; + let rows; + try { + rows = JSON.parse(await Bun.stdin.text()); + } catch (cause) { + console.error(`workflow run inventory is not valid JSON: ${cause.message}`); + process.exit(1); + } + if (!Array.isArray(rows)) { + console.error('workflow run inventory must be a list'); + process.exit(1); + } + const ids = new Set(); + const rendered = []; + for (const row of rows) { + const conclusion = row?.conclusion ?? ''; + if ( + row === null || + Array.isArray(row) || + typeof row !== 'object' || + !Number.isSafeInteger(row.id) || + row.id < 1 || + ids.has(row.id) || + typeof row.head_sha !== 'string' || + row.head_sha.toLowerCase() !== expectedSha || + typeof row.status !== 'string' || + typeof conclusion !== 'string' || + typeof row.html_url !== 'string' || + /[\t\r\n]/u.test(row.html_url) || + typeof row.event !== 'string' || + /[\t\r\n]/u.test(row.event) + ) { + console.error( + 'workflow run inventory contains malformed, duplicate, or non-exact-SHA metadata', + ); + process.exit(1); + } + ids.add(row.id); + rendered.push([row.id, row.status, conclusion, row.html_url, row.event].join('\t')); + if (process.env.QUALIFICATION_REQUEST_KEY) { + const requested = + row.display_title === `CI / qualification / ${process.env.QUALIFICATION_REQUEST_KEY}`; + const causal = (row.event === 'push' && row.head_branch === 'main') || requested; + rendered[rendered.length - 1] += + `\t${causal ? 'causal' : 'other'}\t${requested ? 'requested' : 'other'}`; + } + } + process.stdout.write(rendered.join('\n')); + break; + } + default: + throw new Error('unknown workflow metadata command: ' + command); +} diff --git a/.github/scripts/write-affected-moon-target-matrices.mjs b/.github/scripts/write-affected-moon-target-matrices.mjs deleted file mode 100644 index d069f5fe5..000000000 --- a/.github/scripts/write-affected-moon-target-matrices.mjs +++ /dev/null @@ -1,268 +0,0 @@ -#!/usr/bin/env node -import {appendFileSync} from 'node:fs'; -import {spawnSync} from 'node:child_process'; -import process from 'node:process'; - -import {moonCommand, moonEnvironment} from '../../tools/dev/moon-command.mjs'; -import { - groupTargets, - matrixTarget, - taskDependencies, -} from './moon-task-capabilities.mjs'; - -const MAX_CAPTURE_BYTES = 64 * 1024 * 1024; - -function fail(message) { - console.error(message); - process.exit(1); -} - -function output(name, value) { - const rendered = typeof value === 'string' ? value : JSON.stringify(value); - console.log(`${name}=${rendered}`); - const outputPath = process.env.GITHUB_OUTPUT; - if (outputPath) { - appendFileSync(outputPath, `${name}=${rendered}\n`, 'utf8'); - } -} - -function useAffectedQuery() { - return Boolean(process.env.MOON_BASE?.trim() && process.env.MOON_HEAD?.trim()); -} - -function moonQueryTaskArgs(taskId = '', {affected = useAffectedQuery()} = {}) { - const args = ['query', 'tasks']; - if (affected) { - args.push('--affected'); - } - if (taskId) { - args.push('--id', taskId); - } - if (affected) { - args.push('--upstream', 'none', '--downstream', 'direct'); - } - return args; -} - -function selectedScopeTaskMap() { - const result = spawnSync( - moonCommand(), - moonQueryTaskArgs(), - { - encoding: 'utf8', - env: moonEnvironment(), - stdio: ['ignore', 'pipe', 'inherit'], - maxBuffer: MAX_CAPTURE_BYTES, - }, - ); - if (result.error !== undefined || result.status !== 0) { - fail('moon query tasks failed for selected-scope tasks'); - } - let query; - try { - query = JSON.parse(result.stdout); - } catch (error) { - fail(`moon query tasks returned invalid JSON for selected-scope tasks: ${error.message}`); - } - const tasksByProject = query.tasks; - if (!tasksByProject || typeof tasksByProject !== 'object' || Array.isArray(tasksByProject)) { - fail('moon query tasks did not return a tasks object for selected-scope tasks'); - } - const tasks = new Map(); - for (const projectTasks of Object.values(tasksByProject)) { - if (!projectTasks || typeof projectTasks !== 'object' || Array.isArray(projectTasks)) { - continue; - } - for (const task of Object.values(projectTasks)) { - if (task && typeof task === 'object' && typeof task.target === 'string') { - tasks.set(task.target, task); - } - } - } - return tasks; -} - -function allTaskMap() { - const result = spawnSync( - moonCommand(), - ['task-graph', '--json'], - { - encoding: 'utf8', - env: moonEnvironment(), - stdio: ['ignore', 'pipe', 'inherit'], - maxBuffer: MAX_CAPTURE_BYTES, - }, - ); - if (result.error !== undefined || result.status !== 0) { - fail('moon task-graph failed for complete task capability metadata'); - } - let query; - try { - query = JSON.parse(result.stdout); - } catch (error) { - fail(`moon task-graph returned invalid JSON for complete task capability metadata: ${error.message}`); - } - const taskData = query.data; - if (!taskData || typeof taskData !== 'object') { - fail('moon task-graph did not return task data for complete task capability metadata'); - } - const tasks = new Map(); - for (const task of Object.values(taskData)) { - if (task && typeof task === 'object' && typeof task.target === 'string') { - tasks.set(task.target, task); - } - } - return tasks; -} - -function commandText(task) { - const parts = []; - if (typeof task?.command === 'string') { - parts.push(task.command); - } - if (Array.isArray(task?.args)) { - parts.push(...task.args.filter((arg) => typeof arg === 'string')); - } - return parts.join(' ').trim(); -} - -function tags(task) { - return new Set(Array.isArray(task?.tags) ? task.tags : []); -} - -const policyProjectIds = new Set([ - 'dev-tools', - 'perf-tools', - 'policy-tools', - 'release-tools', -]); -function projectId(target) { - return target.split(':', 1)[0] ?? ''; -} - -function isPolicyTarget(task) { - const taskTags = tags(task); - const command = commandText(task); - return ( - taskTags.has('policy') || - taskTags.has('assertion') || - command.includes('tools/policy/assertions/assert-') || - command.includes('src/extensions/tools/check-extension-') || - policyProjectIds.has(projectId(task.target)) - ); -} - -function isNoopTask(task) { - return commandText(task) === 'true'; -} - -function runsInCI(task) { - const value = task?.options?.runInCI; - return value !== false && value !== 'skip'; -} - -function addMatrixTarget(targets, task, upstream, allTasks) { - const target = task.target; - const existing = targets.get(target); - if (!existing || existing.upstream !== 'none') { - targets.set(target, matrixTarget(task, upstream, allTasks)); - } -} - -function classifyTarget(task, targets, allTasks) { - if (!runsInCI(task)) return; - if (isPolicyTarget(task)) { - addMatrixTarget(targets.policy, task, 'none', allTasks); - } else if (!isNoopTask(task)) { - addMatrixTarget(targets.check, task, 'deep', allTasks); - } -} - -function classifySelectedTask(task, targets, {selectedScopeTasks, allTasks, visiting = new Set()}) { - if (!runsInCI(task)) return; - if (!isNoopTask(task)) { - classifyTarget(task, targets, allTasks); - return; - } - if (visiting.has(task.target)) { - fail(`Moon aggregate task cycle through ${task.target}`); - } - visiting.add(task.target); - for (const dependency of taskDependencies(task)) { - const dependencyTask = selectedScopeTasks.get(dependency); - if (dependencyTask !== undefined) { - classifySelectedTask(dependencyTask, targets, {selectedScopeTasks, allTasks, visiting}); - } - } - visiting.delete(task.target); -} - -function matrix(targets) { - return { - include: targets.map((target) => { - if (typeof target === 'string') { - return {target, upstream: 'deep'}; - } - return target; - }), - }; -} - -if (process.argv.length !== 2) { - fail('usage: write-affected-moon-target-matrices.mjs'); -} - -const completeTasks = allTaskMap(); -const selectedScopeTasks = selectedScopeTaskMap(); -const checkTargets = new Map(); -const policyTargets = new Map(); -const testTargets = new Map(); -for (const task of selectedScopeTasks.values()) { - const taskTags = tags(task); - if (taskTags.has('coverage') || (taskTags.has('quality') && taskTags.has('unit'))) { - if (runsInCI(task)) testTargets.set(task.target, matrixTarget(task, 'deep', completeTasks)); - } else if ( - taskTags.has('quality') - && ['format', 'smoke', 'static'].some((role) => taskTags.has(role)) - ) { - classifySelectedTask(task, {check: checkTargets, policy: policyTargets}, { - selectedScopeTasks, - allTasks: completeTasks, - }); - } -} - -const checkGroups = groupTargets([...checkTargets.values()]); -const testGroups = groupTargets([...testTargets.values()]); -output('check_count', String(checkTargets.size)); -output('check_job_count', String(checkGroups.length)); -output('check_matrix', matrix(checkGroups)); -output('policy_count', String(policyTargets.size)); -output('policy_matrix', matrix([...policyTargets.values()])); -output( - 'policy_requires_android_sdk', - String([...policyTargets.values()].some((target) => target.requires_android_sdk)), -); -output( - 'policy_requires_rust', - String([...policyTargets.values()].some((target) => target.requires_rust)), -); -output( - 'policy_requires_maintainer_tools', - String([...policyTargets.values()].some((target) => target.requires_maintainer_tools)), -); -output( - 'policy_requires_workspace', - String([...policyTargets.values()].some((target) => target.requires_workspace)), -); -output( - 'policy_requires_wasmer_llvm', - String([...policyTargets.values()].some((target) => target.requires_wasmer_llvm)), -); -output('check_jobs', [ - ...(checkTargets.size > 0 ? ['check-targets'] : []), - ...(policyTargets.size > 0 ? ['policy-targets'] : []), -]); -output('test_count', String(testTargets.size)); -output('test_matrix', matrix(testGroups)); -output('test_jobs', testTargets.size > 0 ? ['test-targets'] : []); diff --git a/.github/scripts/write-affected-moon-target-matrices.mts b/.github/scripts/write-affected-moon-target-matrices.mts new file mode 100644 index 000000000..940051c8d --- /dev/null +++ b/.github/scripts/write-affected-moon-target-matrices.mts @@ -0,0 +1,211 @@ +#!/usr/bin/env bun +import { appendFileSync, readFileSync } from 'node:fs'; +import process from 'node:process'; + +import { groupTargets, matrixTarget, taskDependencies } from './moon-task-capabilities.mts'; + +function fail(message) { + console.error(message); + process.exit(1); +} + +function output(name, value) { + const rendered = typeof value === 'string' ? value : JSON.stringify(value); + console.log(`${name}=${rendered}`); + const outputPath = process.env.GITHUB_OUTPUT; + if (outputPath) { + appendFileSync(outputPath, `${name}=${rendered}\n`, 'utf8'); + } +} + +function readQuery(file, label) { + try { + return JSON.parse(readFileSync(file, 'utf8')); + } catch (error) { + fail(`${label} returned invalid JSON: ${error.message}`); + } +} + +function selectedScopeTaskMap() { + const query = readQuery(process.argv[2], 'moon query tasks'); + const tasksByProject = query.tasks; + if (!tasksByProject || typeof tasksByProject !== 'object' || Array.isArray(tasksByProject)) { + fail('moon query tasks did not return a tasks object for selected-scope tasks'); + } + const tasks = new Map(); + for (const projectTasks of Object.values(tasksByProject)) { + if (!projectTasks || typeof projectTasks !== 'object' || Array.isArray(projectTasks)) { + continue; + } + for (const task of Object.values(projectTasks)) { + if (task && typeof task === 'object' && typeof task.target === 'string') { + tasks.set(task.target, task); + } + } + } + if (process.env.CI_PLAN_PATH) { + const plan = readQuery(process.env.CI_PLAN_PATH, 'CI plan'); + if (plan.qualification_mode === 'selected-products') { + if (!Array.isArray(plan.tasks) || plan.tasks.length === 0) + fail('product qualification plan is missing tasks'); + const selected = new Set(plan.tasks); + return new Map([...tasks].filter(([target]) => selected.has(target))); + } + } + return tasks; +} + +function allTaskMap() { + const query = readQuery(process.argv[3], 'moon task-graph'); + const taskData = query.data; + if (!taskData || typeof taskData !== 'object') { + fail('moon task-graph did not return task data for complete task capability metadata'); + } + const tasks = new Map(); + for (const task of Object.values(taskData)) { + if (task && typeof task === 'object' && typeof task.target === 'string') { + tasks.set(task.target, task); + } + } + return tasks; +} + +function commandText(task) { + const parts = []; + if (typeof task?.command === 'string') { + parts.push(task.command); + } + if (Array.isArray(task?.args)) { + parts.push(...task.args.filter((arg) => typeof arg === 'string')); + } + return parts.join(' ').trim(); +} + +function tags(task) { + return new Set(Array.isArray(task?.tags) ? task.tags : []); +} + +function isPolicyTarget(task) { + const taskTags = tags(task); + return taskTags.has('policy') || taskTags.has('assertion'); +} + +function isNoopTask(task) { + return commandText(task) === 'true'; +} + +function runsInCI(task) { + const value = task?.options?.runInCI; + return value !== false && value !== 'skip'; +} + +function classifyTarget(task, targets, allTasks) { + if (!runsInCI(task)) return; + if (isPolicyTarget(task)) { + targets.policy.set(task.target, matrixTarget(task, 'deep', allTasks)); + } else if (!isNoopTask(task)) { + targets.check.set(task.target, matrixTarget(task, 'deep', allTasks)); + } +} + +function classifySelectedTask( + task, + targets, + { selectedScopeTasks, allTasks, visiting = new Set() }, +) { + if (!runsInCI(task)) return; + if (!isNoopTask(task)) { + classifyTarget(task, targets, allTasks); + return; + } + if (visiting.has(task.target)) { + fail(`Moon aggregate task cycle through ${task.target}`); + } + visiting.add(task.target); + for (const dependency of taskDependencies(task)) { + const dependencyTask = selectedScopeTasks.get(dependency); + if (dependencyTask !== undefined) { + classifySelectedTask(dependencyTask, targets, { selectedScopeTasks, allTasks, visiting }); + } + } + visiting.delete(task.target); +} + +function matrix(targets) { + return { + include: targets.map((target) => { + if (typeof target === 'string') { + return { target, upstream: 'deep' }; + } + return target; + }), + }; +} + +if (process.argv.length !== 4) { + fail('usage: write-affected-moon-target-matrices.mts '); +} + +const completeTasks = allTaskMap(); +const selectedScopeTasks = selectedScopeTaskMap(); +const checkTargets = new Map(); +const policyTargets = new Map(); +const testTargets = new Map(); +for (const task of selectedScopeTasks.values()) { + const taskTags = tags(task); + if (taskTags.has('coverage') || (taskTags.has('quality') && taskTags.has('unit'))) { + if (runsInCI(task)) testTargets.set(task.target, matrixTarget(task, 'deep', completeTasks)); + } else if ( + taskTags.has('quality') && + ['format', 'smoke', 'static'].some((role) => taskTags.has(role)) + ) { + classifySelectedTask( + task, + { check: checkTargets, policy: policyTargets }, + { + selectedScopeTasks, + allTasks: completeTasks, + }, + ); + } +} + +// Static checks are setup-bound; keep heavier unit suites in the smaller default groups. +const checkGroups = groupTargets([...checkTargets.values()], { maxTargets: 8 }); +const testGroups = groupTargets([...testTargets.values()]); +output('check_count', String(checkTargets.size)); +output('check_job_count', String(checkGroups.length)); +output('check_matrix', matrix(checkGroups)); +output('policy_count', String(policyTargets.size)); +output('policy_matrix', matrix([...policyTargets.values()])); +output( + 'policy_requires_swift', + String([...policyTargets.values()].some((target) => target.requires_swift)), +); +output( + 'policy_requires_android_sdk', + String([...policyTargets.values()].some((target) => target.requires_android_sdk)), +); +output( + 'policy_requires_rust', + String([...policyTargets.values()].some((target) => target.requires_rust)), +); +output( + 'policy_requires_maintainer_tools', + String([...policyTargets.values()].some((target) => target.requires_maintainer_tools)), +); +output( + 'policy_requires_workspace', + String([...policyTargets.values()].some((target) => target.requires_workspace)), +); +output( + 'policy_requires_wasmer_llvm', + String([...policyTargets.values()].some((target) => target.requires_wasmer_llvm)), +); +output('check_jobs', [ + ...(checkTargets.size > 0 ? ['check-targets'] : []), + ...(policyTargets.size > 0 ? ['policy-targets'] : []), +]); +output('test_count', String(testTargets.size)); +output('test_matrix', matrix(testGroups)); +output('test_jobs', testTargets.size > 0 ? ['test-targets'] : []); diff --git a/.github/scripts/write-affected-moon-target-matrices.sh b/.github/scripts/write-affected-moon-target-matrices.sh new file mode 100644 index 000000000..6285536f3 --- /dev/null +++ b/.github/scripts/write-affected-moon-target-matrices.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +[ "$#" = 0 ] || { + echo 'usage: write-affected-moon-target-matrices.sh' >&2 + exit 2 +} +while IFS= read -r name; do + case "$name" in PROTO_*) unset "$name" ;; esac +done < <(compgen -e) +moon_bin="${MOON_BIN:-moon}" +expected="$(sed -n 's/^moon *= *"\([^"]*\)".*/\1/p' .prototools)" +if [ -z "$expected" ] || [ "$("$moon_bin" --version)" != "moon $expected" ]; then + echo "Moon $expected is required" >&2 + exit 1 +fi +query_dir="$(mktemp -d)" +trap 'rm -rf "$query_dir"' EXIT +query_args=(query tasks) +base="${MOON_BASE:-}" +head="${MOON_HEAD:-}" +if [[ ${CI_QUALIFICATION_MODE:-} != selected-products && -n "${base//[[:space:]]/}" && -n "${head//[[:space:]]/}" ]]; then + query_args+=(--affected --upstream none --downstream deep) +fi +"$moon_bin" "${query_args[@]}" "$query_dir/selected.json" +"$moon_bin" task-graph --json >"$query_dir/graph.json" +bun .github/scripts/write-affected-moon-target-matrices.mts "$query_dir/selected.json" "$query_dir/graph.json" diff --git a/.github/scripts/write-affected-moon-target-matrices.test.mjs b/.github/scripts/write-affected-moon-target-matrices.test.mjs deleted file mode 100644 index a8edef586..000000000 --- a/.github/scripts/write-affected-moon-target-matrices.test.mjs +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { spawnSync } from "../../tools/test/fd-backed-spawn-sync.mjs"; -import test from "node:test"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -const WRITER = path.join(ROOT, ".github/scripts/write-affected-moon-target-matrices.mjs"); - -function moonStub(root, body) { - const file = path.join(root, "moon-stub.mjs"); - writeFileSync( - file, - `#!/usr/bin/env node\nif (process.argv.slice(2).join(" ") === "--version") {\n process.stdout.write("moon 2.5.4\\n");\n} else {\n${body}\n}\n`, - ); - chmodSync(file, 0o755); - return file; -} - -function invoke(stub, output) { - const env = { - ...process.env, - GITHUB_OUTPUT: output, - MOON_BASE: "", - MOON_BIN: stub, - MOON_HEAD: "", - }; - return spawnSync(process.execPath, [WRITER], { - cwd: ROOT, - encoding: "utf8", - env, - maxBuffer: 16 * 1024 * 1024, - }); -} - -test("Node planner captures Moon JSON written at the successful child's final event-loop turn", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-affected-matrices-")); - try { - const tasks = { - "aot-qualification": { args: [], command: "node aot.mjs", deps: [], id: "aot-qualification", options: {}, tags: ["quality", "static"], target: "alpha:aot-qualification" }, - "browser-qualification": { args: [], command: "node browser.mjs", deps: [], id: "browser-qualification", options: {}, tags: ["quality", "static"], target: "alpha:browser-qualification" }, - check: { args: [], command: "node check.mjs", deps: [], id: "check", options: {}, tags: ["quality", "static"], target: "alpha:check" }, - compile: { args: [], command: "node compile.mjs", deps: [], id: "compile", options: {}, tags: ["quality", "static"], target: "alpha:compile" }, - "coverage-report": { args: [], command: "node coverage.mjs", deps: [], id: "coverage-report", options: {}, tags: ["coverage"], target: "alpha:coverage-report" }, - "docs-preview": { args: [], command: "node docs.mjs", deps: [], id: "docs-preview", options: {}, tags: ["quality", "smoke"], target: "alpha:docs-preview" }, - "graph-unit": { args: [], command: "node graph-unit.mjs", deps: [], id: "graph-unit", options: {}, tags: ["quality", "unit"], target: "alpha:graph-unit" }, - "local-unit": { args: [], command: "node local-unit.mjs", deps: [], id: "local-unit", options: { runInCI: false }, tags: ["quality", "unit"], target: "alpha:local-unit" }, - "skipped-unit": { args: [], command: "node skipped-unit.mjs", deps: [], id: "skipped-unit", options: { runInCI: "skip" }, tags: ["quality", "unit"], target: "alpha:skipped-unit" }, - "tools-compile": { args: [], command: "node tools-compile.mjs", deps: [], id: "tools-compile", options: {}, tags: ["quality", "static"], target: "alpha:tools-compile" }, - test: { args: [], command: "node test.mjs", deps: [], id: "test", options: {}, tags: ["quality", "unit"], target: "alpha:test" }, - "tools-unit": { args: [], command: "node tools-unit.mjs", deps: [], id: "tools-unit", options: {}, tags: ["quality", "unit"], target: "alpha:tools-unit" }, - unit: { args: [], command: "node unit.mjs", deps: [{ target: "alpha:internal" }], id: "unit", options: {}, tags: ["quality", "unit"], target: "alpha:unit" }, - }; - const internal = { args: [], command: "node internal.mjs", deps: [], id: "internal", options: { internal: true }, tags: ["requires-rust"], target: "alpha:internal" }; - const document = JSON.stringify({ tasks: { alpha: tasks }, data: { ...tasks, internal } }); - const midpoint = Math.floor(document.length / 2); - const stub = moonStub(root, [ - `const first = ${JSON.stringify(document.slice(0, midpoint))};`, - `const last = ${JSON.stringify(document.slice(midpoint))};`, - "process.stdout.write(first);", - "setImmediate(() => process.stdout.write(last));", - "", - ].join("\n")); - const output = path.join(root, "github-output"); - const result = invoke(stub, output); - assert.equal(result.status, 0, result.stderr || result.stdout); - const values = new Map( - readFileSync(output, "utf8").trimEnd().split("\n").map((line) => { - const separator = line.indexOf("="); - return [line.slice(0, separator), line.slice(separator + 1)]; - }), - ); - assert.equal(values.get("check_count"), "6"); - assert.equal(values.get("test_count"), "5"); - const checkRows = JSON.parse(values.get("check_matrix")).include; - assert.equal(checkRows.length, 2); - assert.deepEqual(checkRows.flatMap(({ targets_json }) => - JSON.parse(targets_json).include.map(({ target }) => target)), [ - "alpha:aot-qualification", - "alpha:browser-qualification", - "alpha:check", - "alpha:compile", - "alpha:docs-preview", - "alpha:tools-compile", - ]); - assert.deepEqual(JSON.parse(values.get("test_matrix")).include.flatMap(({ targets_json }) => - JSON.parse(targets_json).include.map(({ target }) => target)), [ - "alpha:coverage-report", - "alpha:graph-unit", - "alpha:test", - "alpha:tools-unit", - "alpha:unit", - ]); - assert.equal( - JSON.parse(values.get("test_matrix")).include.find(({ targets_json }) => - JSON.parse(targets_json).include.some(({ target }) => target === "alpha:unit") - ).requires_rust, - true, - ); - assert.equal(readFileSync(output, "utf8").includes("alpha:local-unit"), false); - assert.equal(readFileSync(output, "utf8").includes("alpha:skipped-unit"), false); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("Node planner fails closed when a successful Moon child returns partial JSON", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-affected-matrices-partial-")); - try { - const stub = moonStub(root, "process.stdout.write('{\"tasks\":');\n"); - const result = invoke(stub, path.join(root, "github-output")); - assert.notEqual(result.status, 0); - assert.match(result.stderr, /returned invalid JSON/u); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); diff --git a/.github/scripts/write-affected-moon-target-matrices.test.mts b/.github/scripts/write-affected-moon-target-matrices.test.mts new file mode 100644 index 000000000..c249d58f5 --- /dev/null +++ b/.github/scripts/write-affected-moon-target-matrices.test.mts @@ -0,0 +1,115 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +const [phase, root] = process.argv.slice(2); +assert.ok(root); +if (phase === 'prepare') { + const tasks = Object.fromEntries( + [ + ['compile', ['quality', 'static'], {}], + ['smoke', ['quality', 'smoke'], {}], + ...Array.from({ length: 6 }, (_, index) => [`static-${index}`, ['quality', 'static'], {}]), + ['unit', ['quality', 'unit'], {}], + ['coverage', ['coverage'], {}], + ['local-unit', ['quality', 'unit'], { runInCI: false }], + ['skipped-unit', ['quality', 'unit'], { runInCI: 'skip' }], + ].map(([id, tags, options]) => [ + id, + { + id, + tags, + options, + target: `alpha:${id}`, + command: 'node', + args: [`${id}.mts`], + deps: id === 'unit' ? [{ target: 'alpha:internal' }] : [], + }, + ]), + ); + const internal = { + target: 'alpha:internal', + command: 'cargo', + args: ['test'], + deps: [], + options: { internal: true }, + tags: ['requires-rust'], + }; + tasks.format = { + target: 'release-tools:format-check', + command: 'bunx', + args: ['biome', 'format', '.'], + tags: ['quality', 'format'], + }; + tasks.extension = { + target: 'alpha:extension', + command: 'bash', + args: ['src/extensions/tools/check-extension-example.sh'], + tags: ['quality', 'static'], + }; + tasks.policy = { + target: 'alpha:policy', + command: 'bun', + args: ['check.mts'], + tags: ['quality', 'static', 'policy'], + deps: ['alpha:internal'], + }; + + writeFileSync(path.join(root, 'query.json'), JSON.stringify({ tasks: { alpha: tasks } })); + writeFileSync(path.join(root, 'graph.json'), JSON.stringify({ data: { ...tasks, internal } })); + writeFileSync( + path.join(root, 'plan.json'), + JSON.stringify({ qualification_mode: 'selected-products', tasks: ['alpha:unit'] }), + ); + const version = readFileSync('.prototools', 'utf8').match(/^moon\s*=\s*"([^"]+)"/mu)?.[1]; + assert.ok(version); + writeFileSync(path.join(root, 'version'), version); +} else if (phase === 'verify') { + const log = path.join(root, 'commands'); + const output = path.join(root, 'github-output'); + assert.deepEqual(readFileSync(log, 'utf8').trim().split('\n'), [ + '--version', + 'query tasks --affected --upstream none --downstream deep', + 'task-graph --json', + ]); + const values = new Map( + readFileSync(output, 'utf8') + .trim() + .split('\n') + .map((line) => { + const separator = line.indexOf('='); + return [line.slice(0, separator), line.slice(separator + 1)]; + }), + ); + assert.equal(values.get('check_count'), '10'); + const checkGroups = JSON.parse(values.get('check_matrix')).include; + assert.ok(checkGroups.some(({ target_count }) => target_count > 4)); + assert.ok(checkGroups.every(({ target_count }) => target_count <= 8)); + const checkTargets = checkGroups.flatMap(({ targets_json }) => + JSON.parse(targets_json).include.map(({ target }) => target), + ); + assert.equal(checkTargets.length, 10); + assert.equal(new Set(checkTargets).size, 10); + assert.equal(values.get('test_count'), '2'); + const policies = JSON.parse(values.get('policy_matrix')).include; + assert.deepEqual( + policies.map(({ target }) => target), + ['alpha:policy'], + ); + assert.equal(policies[0].upstream, 'deep'); + assert.equal(policies[0].requires_rust, true); + const groups = JSON.parse(values.get('test_matrix')).include; + assert.deepEqual( + groups + .flatMap(({ targets_json }) => JSON.parse(targets_json).include.map(({ target }) => target)) + .sort(), + ['alpha:coverage', 'alpha:unit'], + ); + assert.equal( + groups.find(({ targets_json }) => targets_json.includes('alpha:unit')).requires_rust, + true, + ); +} else { + throw new Error('unknown phase'); +} diff --git a/.github/scripts/write-affected-moon-target-matrices.test.sh b/.github/scripts/write-affected-moon-target-matrices.test.sh new file mode 100644 index 000000000..2abe2e5d4 --- /dev/null +++ b/.github/scripts/write-affected-moon-target-matrices.test.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/../.." +scratch=$(mktemp -d) +trap 'rm -rf "$scratch"' EXIT +fixture=.github/scripts/write-affected-moon-target-matrices.test.mts +bash tools/dev/bun.sh "$fixture" prepare "$scratch" +cat >"$scratch/moon" <<'MOON' +#!/usr/bin/env bash +set -eu +printf '%s\n' "$*" >>"$QUERY_LOG" +case "$1" in + --version) printf 'moon %s\n' "$QUERY_VERSION" ;; + query) + if read -r unexpected; then echo "query inherited stdin: $unexpected" >&2; exit 2; fi + cat "$QUERY_FILE"; exit "${QUERY_EXIT:-0}" ;; + task-graph) cat "$QUERY_GRAPH" ;; + *) exit 2 ;; +esac +MOON +chmod +x "$scratch/moon" +export GITHUB_OUTPUT="$scratch/github-output" MOON_BIN="$scratch/moon" +export QUERY_FILE="$scratch/query.json" QUERY_GRAPH="$scratch/graph.json" QUERY_LOG="$scratch/commands" +QUERY_VERSION=$(cat "$scratch/version") +export QUERY_VERSION QUERY_EXIT=0 MOON_BASE='' MOON_HEAD='' +unset CI_PLAN_PATH CI_QUALIFICATION_MODE +invoke() { + rm -f "$GITHUB_OUTPUT" "$QUERY_LOG" + bash .github/scripts/write-affected-moon-target-matrices.sh <<< 'caller input must not replace the requested commit range' +} +MOON_BASE=base MOON_HEAD=head invoke +bash tools/dev/bun.sh "$fixture" verify "$scratch" +invoke +grep -Fxq 'query tasks' "$QUERY_LOG" +CI_PLAN_PATH="$scratch/plan.json" CI_QUALIFICATION_MODE=selected-products MOON_BASE=base MOON_HEAD=head invoke +grep -Fxq 'query tasks' "$QUERY_LOG" +grep -Fxq 'check_count=0' "$GITHUB_OUTPUT" +grep -Fxq 'test_count=1' "$GITHUB_OUTPUT" +grep -q '"requires_rust":true' "$GITHUB_OUTPUT" +status=0 +QUERY_EXIT=7 invoke || status=$? +[[ "$status" == 7 ]] +if grep -q task-graph "$QUERY_LOG"; then exit 1; fi +printf '{"tasks":' >"$QUERY_FILE" +if invoke 2>"$scratch/error"; then echo 'accepted truncated Moon JSON' >&2; exit 1; fi +grep -q 'returned invalid JSON' "$scratch/error" diff --git a/.github/scripts/write-release-candidate.mjs b/.github/scripts/write-release-candidate.mjs deleted file mode 100644 index eb14f026d..000000000 --- a/.github/scripts/write-release-candidate.mjs +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env bun -import { mkdirSync, writeFileSync } from "node:fs"; -import { dirname } from "node:path"; -import process from "node:process"; - -import { captureCommandOutput } from "../../tools/dev/capture-command-output.mjs"; - -import { - affectedPlanBinding, - assertCandidateBindingShape, - candidateQualificationMode, - FULL_PAYLOAD_QUALIFICATION_MODE, - wasixEvidenceBinding, -} from "./release-candidate-lib.mjs"; - -function fail(message) { - console.error(message); - process.exit(1); -} - -function requiredEnv(name) { - const value = process.env[name]?.trim(); - if (!value) { - fail(`${name} is required`); - } - return value; -} - -function git(args) { - const result = captureCommandOutput("git", args, { - label: `git ${args.join(" ")}`, - }); - if (result.error || result.status !== 0) { - fail(result.stderr?.trim() || result.error?.message || `git ${args.join(" ")} failed`); - } - return result.stdout.trim(); -} - -const outputPath = process.argv[2] ?? "target/qualification/oliphaunt-release-candidate.json"; -const expectedSha = requiredEnv("CI_HEAD_SHA").toLowerCase(); -if (!/^[0-9a-f]{40}$/u.test(expectedSha)) { - fail(`CI_HEAD_SHA must be a full commit SHA, got ${expectedSha}`); -} - -const checkedOutSha = git(["rev-parse", "HEAD^{commit}"]).toLowerCase(); -if (checkedOutSha !== expectedSha) { - fail(`checked-out commit ${checkedOutSha} does not match CI_HEAD_SHA ${expectedSha}`); -} - -const tree = git(["rev-parse", "HEAD^{tree}"]).toLowerCase(); -const wasixRequiredRaw = requiredEnv("WASIX_RELEASE_REGRESSION_REQUIRED"); -if (!["true", "false"].includes(wasixRequiredRaw)) { - fail(`WASIX_RELEASE_REGRESSION_REQUIRED must be true or false, got ${wasixRequiredRaw}`); -} -const wasixRequired = wasixRequiredRaw === "true"; -let affectedPlan; -try { - affectedPlan = affectedPlanBinding(requiredEnv("CI_PLAN_PATH"), wasixRequired); -} catch (error) { - fail(error.message); -} -const expectedQualificationMode = requiredEnv("CI_QUALIFICATION_MODE"); -if (expectedQualificationMode !== FULL_PAYLOAD_QUALIFICATION_MODE) { - fail(`CI_QUALIFICATION_MODE is invalid: ${expectedQualificationMode}`); -} -if (candidateQualificationMode({ affectedPlan }) !== expectedQualificationMode) { - fail( - `affected CI plan qualification mode does not match workflow mode ${expectedQualificationMode}`, - ); -} - -const runAttempt = Number.parseInt(requiredEnv("GITHUB_RUN_ATTEMPT"), 10); -if (!Number.isSafeInteger(runAttempt) || runAttempt < 1) { - fail(`invalid GITHUB_RUN_ATTEMPT: ${process.env.GITHUB_RUN_ATTEMPT}`); -} - -let wasixEvidence = null; -if (wasixRequired) { - try { - wasixEvidence = wasixEvidenceBinding(requiredEnv("WASIX_EVIDENCE_ROOT"), { - repository: requiredEnv("GITHUB_REPOSITORY"), - workflow: requiredEnv("GITHUB_WORKFLOW"), - runId: requiredEnv("GITHUB_RUN_ID"), - runAttempt, - sha: checkedOutSha, - tree, - }); - } catch (error) { - fail(error.message); - } -} - -const candidate = { - schemaVersion: 2, - repository: requiredEnv("GITHUB_REPOSITORY"), - workflow: requiredEnv("GITHUB_WORKFLOW"), - workflowRef: requiredEnv("GITHUB_WORKFLOW_REF"), - runId: requiredEnv("GITHUB_RUN_ID"), - runAttempt, - eventName: requiredEnv("GITHUB_EVENT_NAME"), - ref: requiredEnv("GITHUB_REF"), - sha: checkedOutSha, - tree, - affectedPlan, - evidenceRequirements: { - wasixReleaseRegression: wasixRequired, - artifacts: wasixRequired ? ["wasix-release-regression-evidence"] : [], - }, - evidence: { - wasixReleaseRegression: wasixEvidence, - }, -}; - -try { - assertCandidateBindingShape(candidate); -} catch (error) { - fail(error.message); -} - -mkdirSync(dirname(outputPath), { recursive: true }); -writeFileSync(outputPath, `${JSON.stringify(candidate, null, 2)}\n`, "utf8"); -console.log(`wrote release qualification record for ${candidate.sha} to ${outputPath}`); diff --git a/.github/scripts/write-release-candidate.mts b/.github/scripts/write-release-candidate.mts new file mode 100644 index 000000000..1db3643e5 --- /dev/null +++ b/.github/scripts/write-release-candidate.mts @@ -0,0 +1,114 @@ +#!/usr/bin/env bun +import { mkdirSync, writeFileSync } from 'node:fs'; +import { dirname } from 'node:path'; +import process from 'node:process'; + +import { + affectedPlanBinding, + assertCandidateBindingShape, + candidateQualificationMode, + FULL_PAYLOAD_QUALIFICATION_MODE, + PRODUCT_QUALIFICATION_MODE, + wasixEvidenceBinding, +} from './release-candidate-lib.mts'; + +function fail(message) { + console.error(message); + process.exit(1); +} + +function requiredEnv(name) { + const value = process.env[name]?.trim(); + if (!value) { + fail(`${name} is required`); + } + return value; +} + +const outputPath = process.argv[2] ?? 'target/qualification/oliphaunt-release-candidate.json'; +const expectedSha = requiredEnv('CI_HEAD_SHA').toLowerCase(); +if (!/^[0-9a-f]{40}$/u.test(expectedSha)) { + fail(`CI_HEAD_SHA must be a full commit SHA, got ${expectedSha}`); +} + +const checkedOutSha = requiredEnv('CI_CHECKED_OUT_SHA').toLowerCase(); +if (checkedOutSha !== expectedSha) { + fail(`checked-out commit ${checkedOutSha} does not match CI_HEAD_SHA ${expectedSha}`); +} + +const tree = requiredEnv('CI_SOURCE_TREE').toLowerCase(); +const wasixRequiredRaw = requiredEnv('WASIX_RELEASE_REGRESSION_REQUIRED'); +if (!['true', 'false'].includes(wasixRequiredRaw)) { + fail(`WASIX_RELEASE_REGRESSION_REQUIRED must be true or false, got ${wasixRequiredRaw}`); +} +const wasixRequired = wasixRequiredRaw === 'true'; +let affectedPlan; +try { + affectedPlan = affectedPlanBinding(requiredEnv('CI_PLAN_PATH'), wasixRequired); +} catch (error) { + fail(error.message); +} +const expectedQualificationMode = requiredEnv('CI_QUALIFICATION_MODE'); +if ( + ![FULL_PAYLOAD_QUALIFICATION_MODE, PRODUCT_QUALIFICATION_MODE].includes(expectedQualificationMode) +) { + fail(`CI_QUALIFICATION_MODE is invalid: ${expectedQualificationMode}`); +} +if (candidateQualificationMode({ affectedPlan }) !== expectedQualificationMode) { + fail( + `affected CI plan qualification mode does not match workflow mode ${expectedQualificationMode}`, + ); +} + +const runAttempt = Number.parseInt(requiredEnv('GITHUB_RUN_ATTEMPT'), 10); +if (!Number.isSafeInteger(runAttempt) || runAttempt < 1) { + fail(`invalid GITHUB_RUN_ATTEMPT: ${process.env.GITHUB_RUN_ATTEMPT}`); +} + +let wasixEvidence = null; +if (wasixRequired) { + try { + wasixEvidence = wasixEvidenceBinding(requiredEnv('WASIX_EVIDENCE_ROOT'), { + repository: requiredEnv('GITHUB_REPOSITORY'), + workflow: requiredEnv('GITHUB_WORKFLOW'), + runId: requiredEnv('GITHUB_RUN_ID'), + runAttempt, + sha: checkedOutSha, + tree, + }); + } catch (error) { + fail(error.message); + } +} + +const candidate = { + schemaVersion: 2, + repository: requiredEnv('GITHUB_REPOSITORY'), + workflow: requiredEnv('GITHUB_WORKFLOW'), + workflowRef: requiredEnv('GITHUB_WORKFLOW_REF'), + runId: requiredEnv('GITHUB_RUN_ID'), + runAttempt, + eventName: requiredEnv('GITHUB_EVENT_NAME'), + ref: requiredEnv('GITHUB_REF'), + sha: checkedOutSha, + tree, + producers: JSON.parse(process.env.PRODUCER_RECEIPTS_JSON || '[]'), + affectedPlan, + evidenceRequirements: { + wasixReleaseRegression: wasixRequired, + artifacts: wasixRequired ? ['wasix-release-regression-evidence'] : [], + }, + evidence: { + wasixReleaseRegression: wasixEvidence, + }, +}; + +try { + assertCandidateBindingShape(candidate); +} catch (error) { + fail(error.message); +} + +mkdirSync(dirname(outputPath), { recursive: true }); +writeFileSync(outputPath, `${JSON.stringify(candidate, null, 2)}\n`, 'utf8'); +console.log(`wrote release qualification record for ${candidate.sha} to ${outputPath}`); diff --git a/.github/workflows/broker-runtime.yml b/.github/workflows/broker-runtime.yml new file mode 100644 index 000000000..5bdd279b4 --- /dev/null +++ b/.github/workflows/broker-runtime.yml @@ -0,0 +1,56 @@ +name: broker-runtime +on: + workflow_call: + inputs: + matrix: + required: true + type: string + job-targets: + required: true + type: string +permissions: + contents: read +env: + OLIPHAUNT_CI_JOB_TARGETS_JSON: ${{ inputs.job-targets }} + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + HEAVY_CACHE_SAVE_IF: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} +defaults: + run: + shell: bash +jobs: + build: + name: Builds / Broker Runtime (${{ matrix.target }}) + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.matrix) }} + runs-on: ${{ matrix.runner }} + timeout-minutes: 45 + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Set up Moon + uses: ./.github/actions/setup-moon + + - name: Set up Rust + uses: ./.github/actions/setup-rust + + - name: Set up MSVC + if: ${{ runner.os == 'Windows' }} + uses: ./.github/actions/setup-msvc + + - name: Build broker runtime release asset + run: .github/scripts/run-planned-moon-job.sh broker-runtime + + - name: Upload broker release assets + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: oliphaunt-broker-release-assets-${{ matrix.target }} + path: target/oliphaunt-broker/release-assets + if-no-files-found: error + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c70dcfd2d..24b6f416f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,5 @@ name: CI -run-name: CI / ${{ github.event_name == 'pull_request' && format('PR {0}', github.event.number) || github.ref_name }} +run-name: ${{ inputs.qualification_request && format('CI / qualification / {0}', inputs.qualification_request) || format('CI / {0}', github.event_name == 'pull_request' && format('PR {0}', github.event.number) || github.ref_name) }} on: pull_request: @@ -10,6 +10,16 @@ on: branches: [main] workflow_dispatch: inputs: + qualification_request: + description: Exact source and product-scope request key supplied by release preparation + required: false + default: '' + type: string + release_products_json: + description: Product IDs to qualify as a JSON array; empty array runs the exhaustive audit + required: false + default: '[]' + type: string wasm_target: description: WASM AOT target to build when WASM runtime inputs are affected required: true @@ -60,10 +70,7 @@ concurrency: env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 - NODE_VERSION: 22.22.3 - PNPM_VERSION: 11.5.0 NPM_VERSION: 11.18.0 - BUN_VERSION: 1.3.14 DENO_VERSION: v2.8.1 ACTIONLINT_VERSION: 1.7.12 ASSET_PROFILE: release @@ -91,6 +98,17 @@ jobs: runs-on: ubuntu-24.04 timeout-minutes: 10 outputs: + published_dependencies: ${{ steps.plan.outputs.published_dependencies }} + mobile_extension_package_native_targets_ios_csv: ${{ steps.plan.outputs.mobile_extension_package_native_targets_ios_csv }} + mobile_extension_package_native_targets_android_csv: ${{ steps.plan.outputs.mobile_extension_package_native_targets_android_csv }} + broker_runtime_matrix_other: ${{ steps.plan.outputs.broker_runtime_matrix_other }} + broker_runtime_matrix_linux: ${{ steps.plan.outputs.broker_runtime_matrix_linux }} + liboliphaunt_native_desktop_runtime_matrix_other: ${{ steps.plan.outputs.liboliphaunt_native_desktop_runtime_matrix_other }} + liboliphaunt_native_desktop_runtime_matrix_linux: ${{ steps.plan.outputs.liboliphaunt_native_desktop_runtime_matrix_linux }} + extension_artifacts_native_matrix_other: ${{ steps.plan.outputs.extension_artifacts_native_matrix_other }} + extension_artifacts_native_matrix_ios: ${{ steps.plan.outputs.extension_artifacts_native_matrix_ios }} + extension_artifacts_native_matrix_android: ${{ steps.plan.outputs.extension_artifacts_native_matrix_android }} + extension_artifacts_native_matrix_linux: ${{ steps.plan.outputs.extension_artifacts_native_matrix_linux }} builder_jobs: ${{ steps.plan.outputs.builder_jobs }} check_count: ${{ steps.target-matrices.outputs.check_count }} check_job_count: ${{ steps.target-matrices.outputs.check_job_count }} @@ -98,6 +116,7 @@ jobs: check_matrix: ${{ steps.target-matrices.outputs.check_matrix }} policy_count: ${{ steps.target-matrices.outputs.policy_count }} policy_matrix: ${{ steps.target-matrices.outputs.policy_matrix }} + policy_requires_swift: ${{ steps.target-matrices.outputs.policy_requires_swift }} policy_requires_android_sdk: ${{ steps.target-matrices.outputs.policy_requires_android_sdk }} policy_requires_rust: ${{ steps.target-matrices.outputs.policy_requires_rust }} policy_requires_maintainer_tools: ${{ steps.target-matrices.outputs.policy_requires_maintainer_tools }} @@ -159,14 +178,19 @@ jobs: WASM_TARGET: ${{ github.event_name == 'workflow_dispatch' && inputs.wasm_target || 'all' }} NATIVE_TARGET: ${{ github.event_name == 'workflow_dispatch' && inputs.native_target || 'all' }} MOBILE_TARGET: ${{ github.event_name == 'workflow_dispatch' && inputs.mobile_target || 'all' }} - run: tools/dev/bun.sh tools/graph/ci_plan.mjs + CI_RELEASE_PRODUCTS_JSON: ${{ inputs.release_products_json || '[]' }} + CI_QUALIFICATION_REQUEST: ${{ inputs.qualification_request || '' }} + CI_GENERATED_RELEASE_PR: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref == 'release-please--branches--main' && github.event.pull_request.head.repo.full_name == github.repository }} + run: bash tools/ci/ci-plan.sh - name: Plan check and test jobs id: target-matrices env: + CI_PLAN_PATH: target/graph/ci-plan.json + CI_QUALIFICATION_MODE: ${{ steps.plan.outputs.qualification_mode }} MOON_BASE: ${{ github.event.pull_request.base.sha || github.event.before || github.event.merge_group.base_sha }} MOON_HEAD: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha || github.sha }} - run: node .github/scripts/write-affected-moon-target-matrices.mjs + run: bash .github/scripts/write-affected-moon-target-matrices.sh - name: Upload build plan uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a @@ -214,7 +238,7 @@ jobs: - name: Require normalized generated release id: generated_release_readiness if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.ref == 'release-please--branches--main' && github.event.pull_request.head.repo.full_name == github.repository }} - run: tools/dev/bun.sh tools/release/sync-release-pr.mjs --check-generated-release + run: bash tools/release/sync-release-pr.sh --check-generated-release check-targets: name: Checks / ${{ matrix.label }} @@ -243,9 +267,19 @@ jobs: if: ${{ matrix.requires_rust }} uses: ./.github/actions/setup-rust + - name: Install Android Rust targets + if: ${{ matrix.requires_rust && matrix.requires_android_sdk }} + run: rustup target add aarch64-linux-android x86_64-linux-android + + - name: Set up Swift + if: ${{ matrix.requires_swift && !matrix.requires_apple }} + uses: ./.github/actions/setup-swift + - name: Set up Apple if: ${{ matrix.requires_apple }} uses: ./.github/actions/setup-apple + with: + install-build-dependencies: "false" - name: Set up Android if: ${{ matrix.requires_android_sdk }} @@ -262,12 +296,12 @@ jobs: - name: Install pinned maintainer tools if: ${{ matrix.requires_maintainer_tools }} - run: tools/dev/bootstrap-tools.sh + run: tools/dev/bootstrap-tools.sh --workflows - name: Run checks env: MOON_TARGET_MATRIX_JSON: ${{ matrix.targets_json }} - run: bun .github/scripts/run-moon-target-matrix.mjs + run: bash .github/scripts/run-moon-targets.sh --matrix policy-targets: name: Checks / Policy @@ -293,6 +327,10 @@ jobs: if: ${{ needs.affected.outputs.policy_requires_rust == 'true' }} uses: ./.github/actions/setup-rust + - name: Set up Swift + if: ${{ needs.affected.outputs.policy_requires_swift == 'true' }} + uses: ./.github/actions/setup-swift + - name: Set up Android if: ${{ needs.affected.outputs.policy_requires_android_sdk == 'true' }} uses: ./.github/actions/setup-android @@ -308,16 +346,16 @@ jobs: - name: Install pinned maintainer tools if: ${{ needs.affected.outputs.policy_requires_maintainer_tools == 'true' }} - run: tools/dev/bootstrap-tools.sh + run: tools/dev/bootstrap-tools.sh --workflows - name: Run selected policy targets env: MOON_TARGET_MATRIX_JSON: ${{ needs.affected.outputs.policy_matrix }} - run: bun .github/scripts/run-moon-target-matrix.mjs + run: bash .github/scripts/run-moon-targets.sh --matrix checks: name: Checks - if: ${{ always() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} + if: ${{ !cancelled() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} needs: - affected - check-targets @@ -334,8 +372,6 @@ jobs: - name: Set up Bun uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - name: Check selected check and policy jobs id: selected_checks_gate @@ -343,7 +379,7 @@ jobs: NEEDS_JSON: ${{ toJson(needs) }} SELECTED_JOBS_JSON: ${{ needs.affected.outputs.check_jobs }} GATE_LABEL: selected check and policy jobs - run: bun .github/scripts/check-ci-gate.mjs selected + run: bun .github/scripts/check-ci-gate.mts selected test-targets: name: Tests / ${{ matrix.label }} @@ -372,11 +408,17 @@ jobs: if: ${{ matrix.requires_rust }} uses: ./.github/actions/setup-rust with: - tools: cargo-nextest@0.9.137,cargo-llvm-cov@0.8.7 + tools: cargo-nextest@0.9.137 + + - name: Set up Swift + if: ${{ matrix.requires_swift && !matrix.requires_apple }} + uses: ./.github/actions/setup-swift - name: Set up Apple if: ${{ matrix.requires_apple }} uses: ./.github/actions/setup-apple + with: + install-build-dependencies: "false" - name: Set up Android if: ${{ matrix.requires_android_sdk }} @@ -393,16 +435,16 @@ jobs: - name: Install pinned maintainer tools if: ${{ matrix.requires_maintainer_tools }} - run: tools/dev/bootstrap-tools.sh + run: tools/dev/bootstrap-tools.sh --workflows - name: Run tests env: MOON_TARGET_MATRIX_JSON: ${{ matrix.targets_json }} - run: bun .github/scripts/run-moon-target-matrix.mjs + run: bash .github/scripts/run-moon-targets.sh --matrix tests: name: Tests - if: ${{ always() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} + if: ${{ !cancelled() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} needs: - affected - test-targets @@ -418,8 +460,6 @@ jobs: - name: Set up Bun uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - name: Check selected test jobs id: selected_tests_gate @@ -427,131 +467,54 @@ jobs: NEEDS_JSON: ${{ toJson(needs) }} SELECTED_JOBS_JSON: ${{ needs.affected.outputs.test_jobs }} GATE_LABEL: selected test jobs - run: bun .github/scripts/check-ci-gate.mjs selected + run: bun .github/scripts/check-ci-gate.mts selected + + extension-artifacts-native-linux: + needs: [affected, checks, tests] + if: ${{ fromJson(needs.affected.outputs.extension_artifacts_native_matrix_linux).include[0] != null }} + uses: ./.github/workflows/extension-artifacts-native.yml + with: + matrix: ${{ needs.affected.outputs.extension_artifacts_native_matrix_linux }} + job-targets: ${{ needs.affected.outputs.job_targets }} + + extension-artifacts-native-android: + needs: [affected, checks, tests] + if: ${{ fromJson(needs.affected.outputs.extension_artifacts_native_matrix_android).include[0] != null }} + uses: ./.github/workflows/extension-artifacts-native.yml + with: + matrix: ${{ needs.affected.outputs.extension_artifacts_native_matrix_android }} + job-targets: ${{ needs.affected.outputs.job_targets }} + + extension-artifacts-native-ios: + needs: [affected, checks, tests] + if: ${{ fromJson(needs.affected.outputs.extension_artifacts_native_matrix_ios).include[0] != null }} + uses: ./.github/workflows/extension-artifacts-native.yml + with: + matrix: ${{ needs.affected.outputs.extension_artifacts_native_matrix_ios }} + job-targets: ${{ needs.affected.outputs.job_targets }} + + extension-artifacts-native-other: + needs: [affected, checks, tests] + if: ${{ fromJson(needs.affected.outputs.extension_artifacts_native_matrix_other).include[0] != null }} + uses: ./.github/workflows/extension-artifacts-native.yml + with: + matrix: ${{ needs.affected.outputs.extension_artifacts_native_matrix_other }} + job-targets: ${{ needs.affected.outputs.job_targets }} extension-artifacts-native: - name: Builds / Native Extension Artifacts (${{ matrix.target }}) - needs: - - affected - if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'extension-artifacts-native') }} - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.affected.outputs.extension_artifacts_native_matrix) }} - runs-on: ${{ matrix.runner }} - timeout-minutes: 135 - env: - CCACHE_DIR: ${{ github.workspace }}/.ci-cache/ccache/native-extension/${{ matrix.target }} - CCACHE_BASEDIR: ${{ github.workspace }} - CCACHE_COMPILERCHECK: content - CCACHE_COMPRESS: "true" - OLIPHAUNT_CCACHE_MAX_SIZE: ${{ matrix.target == 'ios-xcframework' && '512M' || '2G' }} - OLIPHAUNT_CCACHE_ZERO_STATS: "1" + name: Builds / extension-artifacts-native + needs: [affected, extension-artifacts-native-linux, extension-artifacts-native-android, extension-artifacts-native-ios, extension-artifacts-native-other] + if: ${{ !cancelled() && !failure() && contains(fromJson(needs.affected.outputs.jobs), 'extension-artifacts-native') }} + runs-on: ubuntu-24.04 + timeout-minutes: 5 steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - - name: Set up Moon - uses: ./.github/actions/setup-moon - - - name: Set up Apple - if: ${{ runner.os == 'macOS' }} - uses: ./.github/actions/setup-apple - - - name: Set up Android - if: ${{ startsWith(matrix.target, 'android-') }} - uses: ./.github/actions/setup-android - with: - gradle-cache: "false" - - - name: Set up MSVC - if: ${{ runner.os == 'Windows' }} - uses: ./.github/actions/setup-msvc - - - name: Verify Windows VC runtime atomic staging - if: ${{ runner.os == 'Windows' }} - run: tools/dev/bun.sh test tools/release/windows-vc-runtime-closure.test.mjs - - - name: Set up Rust - uses: ./.github/actions/setup-rust - - - name: Prepare native compiler cache path - if: ${{ matrix.target == 'ios-xcframework' }} - run: mkdir -p "$CCACHE_DIR" - - - name: Restore native compiler cache - id: restore_ios_extension_ccache - if: ${{ matrix.target == 'ios-xcframework' }} - uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 - with: - path: ${{ env.CCACHE_DIR }} - key: liboliphaunt-native-extension-ccache-v2-${{ matrix.target }}-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.github/actions/setup-apple/**', '.github/scripts/setup-native-build-tools.sh', 'src/postgres/versions/18/**', 'src/sources/third-party/shared/**', 'src/sources/third-party/native/**', 'src/shared/extension-runtime-contract/**', 'src/extensions/catalog/extensions.source.json', 'src/extensions/catalog/native-components.toml', 'src/extensions/contrib/postgres18.toml', 'src/extensions/external/*/source.toml', 'src/extensions/external/*/recipe.toml', 'src/extensions/external/*/dependencies/**/source.toml', 'src/extensions/external/*/dependencies/**/recipe.toml', 'src/extensions/external/*/patches/**', 'src/extensions/external/*/dependencies/**/patches/**', 'src/extensions/generated/extensions.catalog.json', 'src/extensions/generated/contrib-build.tsv', 'src/extensions/generated/pgxs-build.tsv', 'src/extensions/generated/mobile/static-extensions.tsv', 'src/extensions/generated/mobile/static-registry.json', 'src/runtimes/liboliphaunt/native/bin/build-*.sh', '!src/runtimes/liboliphaunt/native/bin/*.test.sh', 'src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1', 'src/runtimes/liboliphaunt/native/bin/build-output.bash', 'src/runtimes/liboliphaunt/native/bin/common.sh', 'src/runtimes/liboliphaunt/native/bin/fetch-pinned-git-checkout.sh', 'src/runtimes/liboliphaunt/native/bin/icu.sh', 'src/runtimes/liboliphaunt/native/bin/mobile-*.sh', 'src/runtimes/liboliphaunt/native/bin/postgis-dependency-cache.sh', 'src/runtimes/liboliphaunt/native/bin/postgres-backend-objects.mk', 'src/runtimes/liboliphaunt/native/crates/tools/Cargo.toml', 'src/runtimes/liboliphaunt/native/crates/tools/build.rs', 'src/runtimes/liboliphaunt/native/crates/tools/src/**', 'src/runtimes/liboliphaunt/native/include/**', 'src/runtimes/liboliphaunt/native/patches/**', 'src/runtimes/liboliphaunt/native/portable-uuid/**', 'src/runtimes/liboliphaunt/native/postgres18/**', 'src/runtimes/liboliphaunt/native/src/**') }} - restore-keys: | - liboliphaunt-native-extension-ccache-v2-${{ matrix.target }}-${{ runner.os }}-${{ runner.arch }}- - - - name: Configure native compiler cache - run: .github/scripts/setup-native-build-tools.sh - - - name: Build native exact-extension artifacts - timeout-minutes: 120 + - name: Check selected platform producers env: - OLIPHAUNT_EXTENSION_PRODUCTS: ${{ matrix.extensions_csv }} - OLIPHAUNT_EXTENSION_TARGET: ${{ matrix.target }} - OLIPHAUNT_BISON: /opt/homebrew/opt/bison/bin/bison - run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh extension-artifacts-native - - - name: Validate produced iOS extension carriers - id: validate_ios_extension_carriers - if: ${{ matrix.target == 'ios-xcframework' }} - run: node tools/release/validate-ios-carrier-zips.mjs --root target/extensions/native/release-assets/ios-xcframework - - - name: Save bounded iOS exact-extension compiler cache - id: save_ios_extension_ccache - if: ${{ matrix.target == 'ios-xcframework' && env.HEAVY_CACHE_SAVE_IF == 'true' && steps.restore_ios_extension_ccache.outputs.cache-hit != 'true' }} - continue-on-error: true - uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 - with: - path: ${{ env.CCACHE_DIR }} - key: liboliphaunt-native-extension-ccache-v2-${{ matrix.target }}-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.github/actions/setup-apple/**', '.github/scripts/setup-native-build-tools.sh', 'src/postgres/versions/18/**', 'src/sources/third-party/shared/**', 'src/sources/third-party/native/**', 'src/shared/extension-runtime-contract/**', 'src/extensions/catalog/extensions.source.json', 'src/extensions/catalog/native-components.toml', 'src/extensions/contrib/postgres18.toml', 'src/extensions/external/*/source.toml', 'src/extensions/external/*/recipe.toml', 'src/extensions/external/*/dependencies/**/source.toml', 'src/extensions/external/*/dependencies/**/recipe.toml', 'src/extensions/external/*/patches/**', 'src/extensions/external/*/dependencies/**/patches/**', 'src/extensions/generated/extensions.catalog.json', 'src/extensions/generated/contrib-build.tsv', 'src/extensions/generated/pgxs-build.tsv', 'src/extensions/generated/mobile/static-extensions.tsv', 'src/extensions/generated/mobile/static-registry.json', 'src/runtimes/liboliphaunt/native/bin/build-*.sh', '!src/runtimes/liboliphaunt/native/bin/*.test.sh', 'src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1', 'src/runtimes/liboliphaunt/native/bin/build-output.bash', 'src/runtimes/liboliphaunt/native/bin/common.sh', 'src/runtimes/liboliphaunt/native/bin/fetch-pinned-git-checkout.sh', 'src/runtimes/liboliphaunt/native/bin/icu.sh', 'src/runtimes/liboliphaunt/native/bin/mobile-*.sh', 'src/runtimes/liboliphaunt/native/bin/postgis-dependency-cache.sh', 'src/runtimes/liboliphaunt/native/bin/postgres-backend-objects.mk', 'src/runtimes/liboliphaunt/native/crates/tools/Cargo.toml', 'src/runtimes/liboliphaunt/native/crates/tools/build.rs', 'src/runtimes/liboliphaunt/native/crates/tools/src/**', 'src/runtimes/liboliphaunt/native/include/**', 'src/runtimes/liboliphaunt/native/patches/**', 'src/runtimes/liboliphaunt/native/portable-uuid/**', 'src/runtimes/liboliphaunt/native/postgres18/**', 'src/runtimes/liboliphaunt/native/src/**') }} - - - name: Show native compiler cache stats - if: ${{ always() && runner.os != 'Windows' }} + RESULTS: ${{ join(needs.*.result, ',') }} run: | - if command -v ccache >/dev/null 2>&1; then - ccache --show-stats - else - echo "ccache was not installed before the build stopped" - fi - - - name: Upload native exact-extension artifacts - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - with: - name: liboliphaunt-native-extension-artifacts-${{ matrix.target }} - path: target/extensions/native/release-assets - if-no-files-found: error - - - name: Upload native exact-extension build logs - id: upload_native_extension_logs - if: ${{ failure() || cancelled() }} - timeout-minutes: 5 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - with: - name: liboliphaunt-native-extension-logs-${{ matrix.target }} - path: | - target/liboliphaunt-mobile-extension-ci/**/*.log - target/liboliphaunt-mobile-extension-release/**/*.log - target/liboliphaunt-mobile-extension-release/ios-xcframework/ios-simulator/*.log - target/liboliphaunt-mobile-extension-release/ios-xcframework/ios-device/*.log - target/liboliphaunt-pg18-extension-release/**/*.log - target/liboliphaunt-pg18-*-extension-release/**/*.log - /tmp/liboliphaunt-ci-*-extensions.log - /tmp/liboliphaunt-release-*-extensions.log - /tmp/liboliphaunt-ci-extension-assets-fetch.log - /tmp/liboliphaunt-release-extension-assets-fetch.log - if-no-files-found: warn + case ",$RESULTS," in + *,failure,*|*,cancelled,*) exit 1 ;; + esac extension-artifacts-wasix: name: Builds / WASIX Extension Artifacts (${{ matrix.target }}) @@ -584,11 +547,17 @@ jobs: name: liboliphaunt-wasix-runtime-portable path: . + - name: Download WASIX extension compiler outputs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: extensions-wasix-compiler-output + path: target/extensions/wasix/assets + - name: Build WASIX exact-extension artifacts env: OLIPHAUNT_EXTENSION_PRODUCTS: ${{ matrix.extensions_csv }} OLIPHAUNT_EXTENSION_TARGET: ${{ matrix.target }} - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-wasix:runtime-portable"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["extension-artifacts-wasix:compiler-output"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh extension-artifacts-wasix - name: Upload WASIX exact-extension artifacts @@ -605,7 +574,7 @@ jobs: - extension-artifacts-native - extension-artifacts-wasix - liboliphaunt-wasix-aot - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.extension-artifacts-native.result == 'success' && needs.extension-artifacts-wasix.result == 'success' && needs.liboliphaunt-wasix-aot.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'extension-packages') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.extension-artifacts-native.result == 'success' && needs.extension-artifacts-wasix.result == 'success' && needs.liboliphaunt-wasix-aot.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'extension-packages') }} runs-on: ubuntu-24.04 timeout-minutes: 30 steps: @@ -646,7 +615,7 @@ jobs: - name: Assemble exact-extension product packages env: OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS: ${{ needs.affected.outputs.extension_package_products_csv }} - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["extension-artifacts-native:build-target", "extension-artifacts-wasix:build-target", "liboliphaunt-wasix:runtime-aot"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["extension-artifacts-native:build-target", "extension-artifacts-wasix:build-target", "extension-artifacts-wasix:build-aot"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh extension-packages - name: Upload exact-extension package artifacts @@ -656,147 +625,77 @@ jobs: path: target/extension-artifacts if-no-files-found: error + mobile-extension-packages-android: + needs: [affected, extension-artifacts-native-android] + if: ${{ needs.affected.outputs.mobile_extension_package_native_targets_android_csv != '' }} + uses: ./.github/workflows/mobile-extension-packages.yml + with: + family: android + targets: ${{ needs.affected.outputs.mobile_extension_package_native_targets_android_csv }} + products: ${{ needs.affected.outputs.extension_package_products_csv }} + job-targets: ${{ needs.affected.outputs.job_targets }} + + mobile-extension-packages-ios: + needs: [affected, extension-artifacts-native-ios] + if: ${{ needs.affected.outputs.mobile_extension_package_native_targets_ios_csv != '' }} + uses: ./.github/workflows/mobile-extension-packages.yml + with: + family: ios + targets: ${{ needs.affected.outputs.mobile_extension_package_native_targets_ios_csv }} + products: ${{ needs.affected.outputs.extension_package_products_csv }} + job-targets: ${{ needs.affected.outputs.job_targets }} + mobile-extension-packages: - name: Builds / Mobile Extension Packages - needs: - - affected - - extension-artifacts-native - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.extension-artifacts-native.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'mobile-extension-packages') }} + needs: [affected, mobile-extension-packages-android, mobile-extension-packages-ios] + if: ${{ !cancelled() && !failure() && contains(fromJson(needs.affected.outputs.jobs), 'mobile-extension-packages') }} runs-on: ubuntu-24.04 - timeout-minutes: 30 + timeout-minutes: 5 steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - - name: Set up Moon - uses: ./.github/actions/setup-moon - - - name: Set up Rust - uses: ./.github/actions/setup-rust - - - name: Download native exact-extension artifacts - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c - with: - pattern: liboliphaunt-native-extension-artifacts-* - path: target/extensions/native/release-assets - merge-multiple: true - - - name: Build mobile exact-extension package artifacts + - name: Check selected mobile producers env: - OLIPHAUNT_EXTENSION_PACKAGE_NATIVE_TARGETS: ${{ needs.affected.outputs.mobile_extension_package_native_targets_csv }} - OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS: ${{ needs.affected.outputs.extension_package_products_csv }} - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["extension-artifacts-native:build-target"]' - run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh mobile-extension-packages - - - name: Upload mobile exact-extension package artifacts - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - with: - name: oliphaunt-mobile-extension-package-artifacts - path: target/mobile-extension-artifacts - if-no-files-found: error + RESULTS: ${{ join(needs.*.result, ',') }} + run: | + case ",$RESULTS," in + *,failure,*|*,cancelled,*) exit 1 ;; + esac + + liboliphaunt-native-desktop-linux: + needs: [affected, checks, tests] + if: ${{ fromJson(needs.affected.outputs.liboliphaunt_native_desktop_runtime_matrix_linux).include[0] != null }} + uses: ./.github/workflows/liboliphaunt-native-desktop.yml + with: + matrix: ${{ needs.affected.outputs.liboliphaunt_native_desktop_runtime_matrix_linux }} + job-targets: ${{ needs.affected.outputs.job_targets }} + + liboliphaunt-native-desktop-other: + needs: [affected, checks, tests] + if: ${{ fromJson(needs.affected.outputs.liboliphaunt_native_desktop_runtime_matrix_other).include[0] != null }} + uses: ./.github/workflows/liboliphaunt-native-desktop.yml + with: + matrix: ${{ needs.affected.outputs.liboliphaunt_native_desktop_runtime_matrix_other }} + job-targets: ${{ needs.affected.outputs.job_targets }} liboliphaunt-native-desktop: - name: Builds / Native Runtime (${{ matrix.target }}) - needs: - - affected - if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-native-desktop') }} - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.affected.outputs.liboliphaunt_native_desktop_runtime_matrix) }} - runs-on: ${{ matrix.runner }} - timeout-minutes: 120 - env: - CCACHE_DIR: ${{ github.workspace }}/.ci-cache/ccache/native-runtime/${{ matrix.target }} - CCACHE_BASEDIR: ${{ github.workspace }} - CCACHE_COMPILERCHECK: content - CCACHE_COMPRESS: "true" - OLIPHAUNT_CCACHE_ZERO_STATS: "1" + name: Builds / liboliphaunt-native-desktop + needs: [affected, liboliphaunt-native-desktop-linux, liboliphaunt-native-desktop-other] + if: ${{ !cancelled() && !failure() && contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-native-desktop') }} + runs-on: ubuntu-24.04 + timeout-minutes: 5 steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - - name: Set up Moon - uses: ./.github/actions/setup-moon - - - name: Set up Rust - uses: ./.github/actions/setup-rust - - - name: Set up MSVC - if: ${{ runner.os == 'Windows' }} - uses: ./.github/actions/setup-msvc - - - name: Prepare native build paths - env: - NATIVE_BUILD_ROOT: ${{ matrix.build-root }} - run: | - mkdir -p "$NATIVE_BUILD_ROOT" - if [[ "$RUNNER_OS" != "Windows" ]]; then - mkdir -p "$CCACHE_DIR" - fi - - - name: Configure native compiler cache - run: .github/scripts/setup-native-build-tools.sh 2G - - - name: Build and package liboliphaunt native runtime - env: - OLIPHAUNT_CI_TARGET: ${{ matrix.target }} - run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh liboliphaunt-native-desktop - - - name: Package portable ICU data for exact consumers - if: ${{ matrix.target == 'macos-arm64' }} - env: - NATIVE_BUILD_ROOT: ${{ matrix.build-root }} - run: | - tools/release/package-liboliphaunt-icu-data.sh \ - "$NATIVE_BUILD_ROOT/icu/share/icu" \ - target/liboliphaunt/portable-icu-assets - - - name: Upload liboliphaunt release assets - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - with: - name: liboliphaunt-native-release-assets-${{ matrix.target }} - path: target/liboliphaunt/desktop-release-assets/${{ matrix.target }} - if-no-files-found: error - - - name: Upload portable ICU data for exact consumers - if: ${{ matrix.target == 'macos-arm64' }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - with: - name: liboliphaunt-native-icu-data - path: target/liboliphaunt/portable-icu-assets - if-no-files-found: error - - - name: Show native compiler cache stats - if: ${{ always() }} + - name: Check selected platform producers env: - NATIVE_TARGET: ${{ matrix.target }} + RESULTS: ${{ join(needs.*.result, ',') }} run: | - if [[ "$NATIVE_TARGET" != windows-* ]] && command -v ccache >/dev/null 2>&1; then - ccache --show-stats - fi - - - name: Upload liboliphaunt build logs - if: ${{ failure() }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - with: - name: liboliphaunt-logs-${{ matrix.target }} - path: | - ${{ matrix.build-root }}/*.log - target/liboliphaunt/**/*.log - if-no-files-found: ignore + case ",$RESULTS," in + *,failure,*|*,cancelled,*) exit 1 ;; + esac liboliphaunt-native-android: name: Builds / Native Runtime (${{ matrix.target }}) needs: - affected + - checks + - tests if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-native-android') }} strategy: fail-fast: false @@ -834,21 +733,27 @@ jobs: - name: Build and package liboliphaunt Android target env: OLIPHAUNT_CI_JOB_TARGETS_JSON: ${{ needs.affected.outputs.job_targets }} - OLIPHAUNT_NATIVE_TASK: liboliphaunt-native:package-runtime-${{ matrix.target }} + OLIPHAUNT_NATIVE_TASK: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-android'], format('liboliphaunt-native:package-runtime-{0}', matrix.target)) && format('liboliphaunt-native:package-runtime-{0}', matrix.target) || format('liboliphaunt-native:build-runtime-{0}', matrix.target) }} run: .github/scripts/run-planned-moon-job.sh liboliphaunt-native-android "$OLIPHAUNT_NATIVE_TASK" - name: Upload liboliphaunt release assets + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-android'], format('liboliphaunt-native:package-runtime-{0}', matrix.target)) }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: liboliphaunt-native-release-assets-${{ matrix.target }} path: target/liboliphaunt/mobile-release-assets/${{ matrix.target }} if-no-files-found: error + - name: Preserve native build file modes and symlinks + env: + NATIVE_ARTIFACT_ROOT: ${{ matrix.ci-artifact-root }} + run: tar -czf "$RUNNER_TEMP/native-target.tar.gz" -C "$NATIVE_ARTIFACT_ROOT" . + - name: Upload liboliphaunt Android target artifacts uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: liboliphaunt-native-target-${{ matrix.target }} - path: ${{ matrix.ci-artifact-root }} + path: ${{ runner.temp }}/native-target.tar.gz if-no-files-found: error - name: Show native compiler cache stats @@ -872,6 +777,8 @@ jobs: name: Builds / Native Runtime (${{ matrix.target }}) needs: - affected + - checks + - tests if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-native-ios') }} strategy: fail-fast: false @@ -912,21 +819,27 @@ jobs: - name: Build and package liboliphaunt iOS target env: OLIPHAUNT_CI_JOB_TARGETS_JSON: ${{ needs.affected.outputs.job_targets }} - OLIPHAUNT_NATIVE_TASK: liboliphaunt-native:package-runtime-${{ matrix.target }} + OLIPHAUNT_NATIVE_TASK: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-ios'], format('liboliphaunt-native:package-runtime-{0}', matrix.target)) && format('liboliphaunt-native:package-runtime-{0}', matrix.target) || format('liboliphaunt-native:build-runtime-{0}', matrix.target) }} run: .github/scripts/run-planned-moon-job.sh liboliphaunt-native-ios "$OLIPHAUNT_NATIVE_TASK" - name: Upload liboliphaunt release assets + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-ios'], format('liboliphaunt-native:package-runtime-{0}', matrix.target)) }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: liboliphaunt-native-release-assets-${{ matrix.target }} path: target/liboliphaunt/mobile-release-assets/${{ matrix.target }} if-no-files-found: error + - name: Preserve native build file modes and symlinks + env: + NATIVE_ARTIFACT_ROOT: ${{ matrix.ci-artifact-root }} + run: tar -czf "$RUNNER_TEMP/native-target.tar.gz" -C "$NATIVE_ARTIFACT_ROOT" . + - name: Upload liboliphaunt iOS target artifacts uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: liboliphaunt-native-target-${{ matrix.target }} - path: ${{ matrix.ci-artifact-root }} + path: ${{ runner.temp }}/native-target.tar.gz if-no-files-found: error - name: Show native compiler cache stats @@ -957,9 +870,9 @@ jobs: needs: - affected - liboliphaunt-native-android - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.liboliphaunt-native-android.result == 'success' && (contains(fromJson(needs.affected.outputs.jobs), 'mobile-build-android') || contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-native-release-assets')) }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.liboliphaunt-native-android.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-native-android-abi') }} runs-on: ubuntu-24.04 - timeout-minutes: 15 + timeout-minutes: 30 steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd @@ -977,13 +890,26 @@ jobs: name: liboliphaunt-native-target-android-arm64-v8a path: target/liboliphaunt-native-ci/android-arm64-v8a + - name: Restore android-arm64-v8a build outputs + run: | + tar -xzf target/liboliphaunt-native-ci/android-arm64-v8a/native-target.tar.gz -C target/liboliphaunt-native-ci/android-arm64-v8a + rm target/liboliphaunt-native-ci/android-arm64-v8a/native-target.tar.gz + rsync -a target/liboliphaunt-native-ci/android-arm64-v8a/target/ target/ + - name: Download Android x86_64 ABI receipts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: name: liboliphaunt-native-target-android-x86_64 path: target/liboliphaunt-native-ci/android-x86_64 + - name: Restore android-x86_64 build outputs + run: | + tar -xzf target/liboliphaunt-native-ci/android-x86_64/native-target.tar.gz -C target/liboliphaunt-native-ci/android-x86_64 + rm target/liboliphaunt-native-ci/android-x86_64/native-target.tar.gz + rsync -a target/liboliphaunt-native-ci/android-x86_64/target/ target/ + - name: Download Android runtime-resource assets + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-android-abi'], 'liboliphaunt-native:finalize-runtime-android-abi') }} uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: name: liboliphaunt-native-release-assets-android-x86_64 @@ -991,25 +917,34 @@ jobs: - name: Prove Android Datum64 ABI-compatible runtime-resource closure env: - OLIPHAUNT_CI_JOB_TARGETS_JSON: '{"liboliphaunt-native-android-abi":["liboliphaunt-native:finalize-runtime-android-abi"]}' - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-native:package-runtime-android-arm64-v8a", "liboliphaunt-native:package-runtime-android-x86_64"]' + OLIPHAUNT_CI_JOB_TARGETS_JSON: ${{ needs.affected.outputs.job_targets }} + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-native:package-runtime-android-arm64-v8a","liboliphaunt-native:build-runtime-android-arm64-v8a","liboliphaunt-native:package-runtime-android-x86_64","liboliphaunt-native:build-runtime-android-x86_64"]' run: .github/scripts/run-planned-moon-job.sh liboliphaunt-native-android-abi - name: Upload ABI-compatible Android runtime-resource assets + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-android-abi'], 'liboliphaunt-native:finalize-runtime-android-abi') }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: liboliphaunt-native-abi-compatible-release-assets-android-datum64 path: target/liboliphaunt/abi-compatible-release-assets/android-datum64 if-no-files-found: error + - name: Upload android database seeds + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-android-abi'], 'database-resources:build-native-android-standard') || contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-android-abi'], 'database-resources:build-native-android-icu') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: database-resources-native-seeds-android-datum64 + path: target/database-resources/release-assets/*seed-native-android-datum64-* + if-no-files-found: error + liboliphaunt-native-ios-abi: name: Builds / Native Runtime ABI Compatibility (iOS) needs: - affected - liboliphaunt-native-ios - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.liboliphaunt-native-ios.result == 'success' && (contains(fromJson(needs.affected.outputs.jobs), 'mobile-build-ios') || contains(fromJson(needs.affected.outputs.jobs), 'swift-sdk-package') || contains(fromJson(needs.affected.outputs.jobs), 'react-native-sdk-package') || contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-native-release-assets')) }} - runs-on: ubuntu-24.04 - timeout-minutes: 15 + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.liboliphaunt-native-ios.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-native-ios-abi') }} + runs-on: ${{ (contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-ios-abi'], 'database-resources:build-native-ios-standard') || contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-ios-abi'], 'database-resources:build-native-ios-icu')) && 'macos-26' || 'ubuntu-24.04' }} + timeout-minutes: 30 steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd @@ -1027,7 +962,14 @@ jobs: name: liboliphaunt-native-target-ios-xcframework path: target/liboliphaunt-native-ci/ios-xcframework + - name: Restore ios-xcframework build outputs + run: | + tar -xzf target/liboliphaunt-native-ci/ios-xcframework/native-target.tar.gz -C target/liboliphaunt-native-ci/ios-xcframework + rm target/liboliphaunt-native-ci/ios-xcframework/native-target.tar.gz + rsync -a target/liboliphaunt-native-ci/ios-xcframework/target/ target/ + - name: Download iOS runtime-resource assets + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-ios-abi'], 'liboliphaunt-native:finalize-runtime-ios-abi') }} uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: name: liboliphaunt-native-release-assets-ios-xcframework @@ -1035,17 +977,26 @@ jobs: - name: Prove iOS Datum64 ABI-compatible runtime-resource closure env: - OLIPHAUNT_CI_JOB_TARGETS_JSON: '{"liboliphaunt-native-ios-abi":["liboliphaunt-native:finalize-runtime-ios-abi"]}' - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-native:package-runtime-ios-xcframework"]' + OLIPHAUNT_CI_JOB_TARGETS_JSON: ${{ needs.affected.outputs.job_targets }} + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-native:package-runtime-ios-xcframework","liboliphaunt-native:build-runtime-ios-xcframework"]' run: .github/scripts/run-planned-moon-job.sh liboliphaunt-native-ios-abi - name: Upload ABI-compatible iOS runtime-resource assets + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-ios-abi'], 'liboliphaunt-native:finalize-runtime-ios-abi') }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: liboliphaunt-native-abi-compatible-release-assets-ios-datum64 path: target/liboliphaunt/abi-compatible-release-assets/ios-datum64 if-no-files-found: error + - name: Upload ios database seeds + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-ios-abi'], 'database-resources:build-native-ios-standard') || contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-native-ios-abi'], 'database-resources:build-native-ios-icu') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: database-resources-native-seeds-ios-datum64 + path: target/database-resources/release-assets/*seed-native-ios-datum64-* + if-no-files-found: error + liboliphaunt-native-release-assets: name: Builds / Native Runtime Release Assets needs: @@ -1122,6 +1073,8 @@ jobs: name: Builds / Rust SDK Package needs: - affected + - checks + - tests if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'rust-sdk-package') }} runs-on: ubuntu-24.04 timeout-minutes: 90 @@ -1138,80 +1091,103 @@ jobs: - name: Set up Rust uses: ./.github/actions/setup-rust - with: - components: clippy,llvm-tools-preview - tools: cargo-nextest@0.9.137,cargo-llvm-cov@0.8.7 - name: Build Rust SDK package artifacts run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh rust-sdk-package - name: Upload Rust SDK package artifacts + if: ${{ contains(join(fromJson(needs.affected.outputs.job_targets)['rust-sdk-package'], ','), 'oliphaunt-rust:') }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: oliphaunt-rust-sdk-package-artifacts path: target/sdk-artifacts/oliphaunt-rust if-no-files-found: error + - name: Upload shared Rust query package + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: oliphaunt-query-sdk-package-artifacts + path: target/sdk-artifacts/oliphaunt-query + if-no-files-found: error + + - name: Upload native Rust bindings package + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: liboliphaunt-native-bindings-sdk-package-artifacts + path: target/sdk-artifacts/liboliphaunt-native-bindings + if-no-files-found: error + + - name: Upload broker source package + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: oliphaunt-broker-sdk-package-artifacts + path: target/sdk-artifacts/oliphaunt-broker + if-no-files-found: error + + - name: Upload packed Rust consumer + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['rust-sdk-package'], 'oliphaunt-rust:test-consumer') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: oliphaunt-rust-release-consumer-linux-x64-gnu + path: target/oliphaunt-rust/release-consumer/oliphaunt-rust-release-consumer + if-no-files-found: error + - name: Build native extension lifecycle proof runner - run: cargo build --offline --locked --release -p oliphaunt-native-extension-proof + if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'native-extension-lifecycle') }} + run: cargo build --locked --release -p oliphaunt-native-extension-proof - name: Stage native extension lifecycle proof runner + if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'native-extension-lifecycle') }} run: | install -D -m 0755 \ target/release/oliphaunt-native-extension-proof \ target/native-extension-proof/oliphaunt-native-extension-proof - name: Upload native extension lifecycle proof runner + if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'native-extension-lifecycle') }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: oliphaunt-native-extension-proof-linux-x64-gnu - path: | - target/native-extension-proof/oliphaunt-native-extension-proof - target/native-extension-proof/oliphaunt-rust-release-consumer + path: target/native-extension-proof/oliphaunt-native-extension-proof if-no-files-found: error + broker-runtime-linux: + needs: [affected, checks, tests] + if: ${{ fromJson(needs.affected.outputs.broker_runtime_matrix_linux).include[0] != null }} + uses: ./.github/workflows/broker-runtime.yml + with: + matrix: ${{ needs.affected.outputs.broker_runtime_matrix_linux }} + job-targets: ${{ needs.affected.outputs.job_targets }} + + broker-runtime-other: + needs: [affected, checks, tests] + if: ${{ fromJson(needs.affected.outputs.broker_runtime_matrix_other).include[0] != null }} + uses: ./.github/workflows/broker-runtime.yml + with: + matrix: ${{ needs.affected.outputs.broker_runtime_matrix_other }} + job-targets: ${{ needs.affected.outputs.job_targets }} + broker-runtime: - name: Builds / Broker Runtime (${{ matrix.target }}) - needs: - - affected - if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'broker-runtime') }} - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.affected.outputs.broker_runtime_matrix) }} - runs-on: ${{ matrix.runner }} - timeout-minutes: 45 + name: Builds / broker-runtime + needs: [affected, broker-runtime-linux, broker-runtime-other] + if: ${{ !cancelled() && !failure() && contains(fromJson(needs.affected.outputs.jobs), 'broker-runtime') }} + runs-on: ubuntu-24.04 + timeout-minutes: 5 steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - - name: Set up Moon - uses: ./.github/actions/setup-moon - - - name: Set up Rust - uses: ./.github/actions/setup-rust - - - name: Set up MSVC - if: ${{ runner.os == 'Windows' }} - uses: ./.github/actions/setup-msvc - - - name: Build broker runtime release asset - run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh broker-runtime - - - name: Upload broker release assets - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - with: - name: oliphaunt-broker-release-assets-${{ matrix.target }} - path: target/oliphaunt-broker/release-assets - if-no-files-found: error + - name: Check selected platform producers + env: + RESULTS: ${{ join(needs.*.result, ',') }} + run: | + case ",$RESULTS," in + *,failure,*|*,cancelled,*) exit 1 ;; + esac node-direct: name: Builds / Node.js Direct (${{ matrix.target }}) needs: - affected + - checks + - tests if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'node-direct') }} strategy: fail-fast: false @@ -1258,7 +1234,7 @@ jobs: needs: - affected - broker-runtime - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.broker-runtime.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'broker-release-assets') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.broker-runtime.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'broker-release-assets') }} runs-on: ubuntu-24.04 timeout-minutes: 15 steps: @@ -1282,7 +1258,7 @@ jobs: - name: Verify aggregate broker release assets id: verify_aggregate_broker_release_assets env: - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["release-tools:broker-runtime"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["oliphaunt-broker:build-release-assets"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh broker-release-assets node-direct-release-assets: @@ -1290,7 +1266,7 @@ jobs: needs: - affected - node-direct - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.node-direct.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'node-direct-release-assets') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.node-direct.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'node-direct-release-assets') }} runs-on: ubuntu-24.04 timeout-minutes: 15 steps: @@ -1321,7 +1297,7 @@ jobs: - name: Verify aggregate Node direct release assets id: verify_aggregate_node_direct_release_assets env: - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["release-tools:node-direct-runtime"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["oliphaunt-node-direct:build-release-assets"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh node-direct-release-assets wasix-napi: @@ -1331,7 +1307,7 @@ jobs: - extension-artifacts-wasix - liboliphaunt-wasix-aot - liboliphaunt-wasix-runtime - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.extension-artifacts-wasix.result == 'success' && needs.liboliphaunt-wasix-aot.result == 'success' && needs.liboliphaunt-wasix-runtime.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'wasix-napi') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.extension-artifacts-wasix.result == 'success' && needs.liboliphaunt-wasix-aot.result == 'success' && needs.liboliphaunt-wasix-runtime.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'wasix-napi') }} strategy: fail-fast: false matrix: ${{ fromJson(needs.affected.outputs.wasix_napi_runtime_matrix) }} @@ -1401,6 +1377,11 @@ jobs: mkdir -p "$destination" cp -R "$raw_target_dir/." "$destination/" + - name: Set up macOS smoke timeout + if: ${{ runner.os == 'macOS' }} + shell: bash + run: brew list coreutils >/dev/null 2>&1 || HOMEBREW_NO_AUTO_UPDATE=1 brew install coreutils + - name: Build WASIX Node-API release assets shell: bash env: @@ -1410,7 +1391,7 @@ jobs: OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT: ${{ github.workspace }}/target/extension-artifacts OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR: ${{ github.workspace }}/target/oliphaunt-wasix/assets OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["extension-artifacts-wasix:build-target", "liboliphaunt-wasix:runtime-aot"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["extension-artifacts-wasix:build-target", "extension-artifacts-wasix:build-aot", "liboliphaunt-wasix:runtime-aot"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh wasix-napi - name: Upload WASIX Node-API release assets @@ -1432,7 +1413,7 @@ jobs: needs: - affected - wasix-napi - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.wasix-napi.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'wasix-napi-release-assets') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.wasix-napi.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'wasix-napi-release-assets') }} runs-on: ubuntu-24.04 timeout-minutes: 15 steps: @@ -1463,16 +1444,51 @@ jobs: - name: Verify aggregate WASIX Node-API release assets id: verify_aggregate_wasix_napi_release_assets env: - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["release-tools:wasix-napi-runtime"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["oliphaunt-wasix-napi:build-release-assets"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh wasix-napi-release-assets + swift-bindings: + name: Builds / Swift Native Bindings + needs: [affected, checks, tests] + if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'swift-bindings') }} + runs-on: macos-26 + timeout-minutes: 30 + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Set up Moon + uses: ./.github/actions/setup-moon + - name: Set up Rust + uses: ./.github/actions/setup-rust + - name: Install Apple Rust targets + run: rustup target add aarch64-apple-ios aarch64-apple-ios-sim aarch64-apple-darwin + - name: Select Apple framework toolchain + uses: ./.github/actions/setup-apple + with: + install-build-dependencies: "false" + - name: Build Swift native bindings + run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh swift-bindings + - name: Upload Swift bindings and generated source + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: oliphaunt-swift-bindings + path: | + target/oliphaunt-swift/release-assets + target/mobile-bindings/generated + if-no-files-found: error + swift-sdk-package: name: Builds / Swift SDK Package needs: - affected - liboliphaunt-native-ios-abi + - swift-bindings if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'swift-sdk-package') }} - runs-on: macos-26 + runs-on: ubuntu-24.04 timeout-minutes: 90 steps: - name: Checkout repository @@ -1485,19 +1501,22 @@ jobs: - name: Set up Moon uses: ./.github/actions/setup-moon - - name: Set up Apple - uses: ./.github/actions/setup-apple - - name: Download Apple liboliphaunt release assets uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: name: liboliphaunt-native-abi-compatible-release-assets-ios-datum64 path: target/liboliphaunt/abi-compatible-release-assets/ios-datum64 + - name: Download Swift bindings and generated source + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: oliphaunt-swift-bindings + path: target + - name: Build Swift SDK package artifacts env: OLIPHAUNT_SWIFT_RELEASE_ASSET_DIR: ${{ github.workspace }}/target/liboliphaunt/abi-compatible-release-assets/ios-datum64 - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-native:finalize-runtime-ios-abi"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-native:finalize-runtime-ios-abi", "oliphaunt-swift:package-bindings"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh swift-sdk-package - name: Upload Swift SDK package artifacts @@ -1511,6 +1530,8 @@ jobs: name: Builds / Kotlin SDK Package needs: - affected + - checks + - tests if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'kotlin-sdk-package') }} runs-on: ubuntu-24.04 timeout-minutes: 90 @@ -1525,6 +1546,12 @@ jobs: - name: Set up Moon uses: ./.github/actions/setup-moon + - name: Set up Rust + uses: ./.github/actions/setup-rust + + - name: Install Android Rust targets + run: rustup target add aarch64-linux-android x86_64-linux-android + - name: Set up Android uses: ./.github/actions/setup-android with: @@ -1545,7 +1572,7 @@ jobs: needs: - affected - kotlin-sdk-package - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.kotlin-sdk-package.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'kotlin-maven-staging') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.kotlin-sdk-package.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'kotlin-maven-staging') }} runs-on: ubuntu-24.04 timeout-minutes: 10 steps: @@ -1568,7 +1595,7 @@ jobs: - name: Validate exact Kotlin Maven Central staging closure id: kotlin_maven_staging env: - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["release-tools:kotlin-sdk-package"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["oliphaunt-kotlin:package"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh kotlin-maven-staging react-native-sdk-package: @@ -1613,8 +1640,15 @@ jobs: js-sdk-package: name: Builds / JavaScript SDK Package + permissions: + contents: read + actions: read + outputs: + producer_receipt: ${{ steps.query_producer_receipt.outputs.receipt }} needs: - affected + - checks + - tests if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'js-sdk-package') }} runs-on: ubuntu-24.04 timeout-minutes: 60 @@ -1640,19 +1674,143 @@ jobs: run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh js-sdk-package - name: Upload JS SDK package artifacts + if: ${{ contains(join(fromJson(needs.affected.outputs.job_targets)['js-sdk-package'], ','), 'oliphaunt-js:') }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: oliphaunt-js-sdk-package-artifacts path: target/sdk-artifacts/oliphaunt-js if-no-files-found: error + - name: Upload PostgreSQL WASIX tools facade + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['js-sdk-package'], 'oliphaunt-wasix-tools-ts:package') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: postgres-tools-wasix-package-artifacts + path: target/sdk-artifacts/postgres-tools-wasix + if-no-files-found: error + + - name: Upload canonical ICU data + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['js-sdk-package'], 'database-resources:package-icu') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: database-resources-icu-data-portable + path: target/database-resources/release-assets/*-icu-data.tar.gz + if-no-files-found: error + + - name: Upload canonical ICU npm carrier + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['js-sdk-package'], 'database-resources:package-icu') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: database-resources-icu-npm + path: target/release/npm-packages/oliphaunt-icu/*.tgz + if-no-files-found: error + + - name: Upload shared TypeScript query package + id: query_package_artifact + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['js-sdk-package'], 'oliphaunt-query-ts:package') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: oliphaunt-query-ts-sdk-package-artifacts + path: target/sdk-artifacts/oliphaunt-query-ts + if-no-files-found: error + + - name: Record TypeScript query producer evidence + id: query_producer_receipt + if: ${{ steps.query_package_artifact.outcome == 'success' }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CI_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + PRODUCER_ARTIFACT_ID: ${{ steps.query_package_artifact.outputs.artifact-id }} + PRODUCER_ARTIFACT_DIGEST: ${{ steps.query_package_artifact.outputs.artifact-digest }} + run: | + PRODUCER_MOON_VERSION="$(moon --version)" + export PRODUCER_MOON_VERSION + bun .github/scripts/moon-producer-receipt.mts oliphaunt-query-ts:package oliphaunt-query-ts-sdk-package-artifacts src/sdks/ts-query + + native-consumers: + name: Builds / Native Product Consumers + needs: [affected, js-sdk-package, rust-sdk-package, liboliphaunt-native-desktop, broker-runtime, node-direct] + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'native-consumers') }} + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Set up Moon + uses: ./.github/actions/setup-moon + with: + install-workspace: "true" + - name: Set up Deno + uses: ./.github/actions/setup-deno + with: + deno-version: ${{ env.DENO_VERSION }} + - name: Set up Rust + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-broker:test-consumer') }} + uses: ./.github/actions/setup-rust + - name: Download SDK package + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-js:test-consumer') || contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-js:test-consumer-published') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: oliphaunt-js-sdk-package-artifacts + path: target/sdk-artifacts/oliphaunt-js + - name: Download query dependency package + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-js:test-consumer') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: oliphaunt-query-ts-sdk-package-artifacts + path: target/sdk-artifacts/oliphaunt-query-ts + - name: Download Linux runtime archive + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-js:test-consumer') || contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-broker:test-consumer') || contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-rust:test-consumer-runtime') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: liboliphaunt-native-release-assets-linux-x64-gnu + path: target/liboliphaunt/desktop-release-assets/linux-x64-gnu + - name: Download Linux broker archive + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-js:test-consumer') || contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-broker:test-consumer') || contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-rust:test-consumer-runtime') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: oliphaunt-broker-release-assets-linux-x64-gnu + path: target/oliphaunt-broker/release-assets + - name: Download packed Rust consumer + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-rust:test-consumer-runtime') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: oliphaunt-rust-release-consumer-linux-x64-gnu + path: target/oliphaunt-rust/release-consumer + - name: Make packed Rust consumer executable + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-rust:test-consumer-runtime') }} + run: chmod 0755 target/oliphaunt-rust/release-consumer/oliphaunt-rust-release-consumer + - name: Download Linux tools archive + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-rust:test-consumer-runtime') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: postgres-tools-native-release-assets-linux-x64-gnu + path: target/postgres-tools/native/release-assets + - name: Download Linux addon archive + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['native-consumers'], 'oliphaunt-js:test-consumer') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: oliphaunt-node-direct-release-assets-linux-x64-gnu + path: target/oliphaunt-node-direct/release-assets + - name: Exercise selected products against shipped native artifacts + env: + OLIPHAUNT_PUBLISHED_DEPENDENCIES: ${{ needs.affected.outputs.published_dependencies }} + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["oliphaunt-rust:test-consumer", "postgres-tools-native:package-assets", "oliphaunt-js:package", "oliphaunt-query-ts:package", "liboliphaunt-native:package-runtime-desktop-target", "oliphaunt-broker:build-release-assets", "oliphaunt-node-direct:build-release-assets"]' + run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh native-consumers + wasix-ts-sdk-package: name: Builds / WASIX TypeScript SDK needs: - affected - liboliphaunt-wasix-runtime - wasix-napi - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.liboliphaunt-wasix-runtime.result == 'success' && needs.wasix-napi.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'wasix-ts-sdk-package') }} + - js-sdk-package + - liboliphaunt-wasix-aot + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.liboliphaunt-wasix-runtime.result == 'success' && (!contains(fromJson(needs.affected.outputs.jobs), 'wasix-napi') || needs.wasix-napi.result == 'success') && (!contains(fromJson(needs.affected.outputs.jobs), 'js-sdk-package') || needs.js-sdk-package.result == 'success') && (!contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-wasix-aot') || needs.liboliphaunt-wasix-aot.result == 'success') && contains(fromJson(needs.affected.outputs.jobs), 'wasix-ts-sdk-package') }} runs-on: ubuntu-24.04 timeout-minutes: 120 steps: @@ -1685,17 +1843,61 @@ jobs: path: . - name: Download same-run Linux x64 WASIX Node-API carrier + if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'wasix-napi') }} uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: name: oliphaunt-wasix-napi-npm-package-linux-x64-gnu path: target/oliphaunt-wasix-napi/npm-packages + - name: Download tools facade package + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['wasix-ts-sdk-package'], 'postgres-tools-wasix:test-consumer') || contains(fromJson(needs.affected.outputs.job_targets)['wasix-ts-sdk-package'], 'postgres-tools-wasix:test-browser') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: postgres-tools-wasix-package-artifacts + path: target/sdk-artifacts/postgres-tools-wasix + + - name: Download portable PostgreSQL tools + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['wasix-ts-sdk-package'], 'postgres-tools-wasix:test-consumer') || contains(fromJson(needs.affected.outputs.job_targets)['wasix-ts-sdk-package'], 'postgres-tools-wasix:test-browser') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: postgres-tools-wasix-release-assets-portable + path: target/postgres-tools/wasix/release-assets + + - name: Download native PostgreSQL tools AOT + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['wasix-ts-sdk-package'], 'postgres-tools-wasix:test-consumer') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: postgres-tools-wasix-release-assets-linux-x64-gnu + path: target/postgres-tools/wasix/release-assets + + - name: Download same-run WASIX extension compiler outputs + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-runtime'], 'extension-artifacts-wasix:compiler-output') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: extensions-wasix-compiler-output + path: target/extensions/wasix/assets + + - name: Download same-run WASIX seeds + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-runtime'], 'database-resources:build-wasix-standard') || contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-runtime'], 'database-resources:build-wasix-icu') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: database-resources-wasix-seeds-portable + path: target/database-resources/release-assets + + - name: Download same-run ICU npm carrier + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['js-sdk-package'], 'database-resources:package-icu') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: database-resources-icu-npm + path: target/release/npm-packages/oliphaunt-icu + - name: Build, test, and package the WASIX TypeScript SDK env: - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-wasix:runtime-portable", "release-tools:wasix-napi-runtime"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-wasix:runtime-portable", "extension-artifacts-wasix:compiler-output", "database-resources:build-wasix-standard", "database-resources:build-wasix-icu", "database-resources:package-icu", "oliphaunt-wasix-napi:build-release-assets", "oliphaunt-wasix-tools-ts:package", "postgres-tools-wasix:package-portable", "postgres-tools-wasix:package-aot"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh wasix-ts-sdk-package - name: Upload WASIX TypeScript SDK package artifacts + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['wasix-ts-sdk-package'], 'oliphaunt-wasix-ts:package') }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: oliphaunt-wasix-ts-sdk-package-artifacts @@ -1706,6 +1908,8 @@ jobs: name: Builds / WASIX Rust Binding Package needs: - affected + - checks + - tests if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'wasix-rust-package') }} runs-on: ubuntu-24.04 timeout-minutes: 90 @@ -1724,38 +1928,32 @@ jobs: - name: Set up Rust uses: ./.github/actions/setup-rust - with: - components: llvm-tools-preview - tools: cargo-nextest@0.9.137,cargo-llvm-cov@0.8.7 - - - name: Install Tauri Linux dependencies - run: | - .github/scripts/prepare-linux-apt.sh - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - libayatana-appindicator3-dev \ - libglib2.0-dev \ - libgtk-3-dev \ - librsvg2-dev \ - libssl-dev \ - libwebkit2gtk-4.1-dev \ - libxdo-dev \ - pkg-config - name: Build Rust WASIX binding package artifacts run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh wasix-rust-package - name: Upload Rust WASIX binding package artifacts + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['wasix-rust-package'], 'oliphaunt-wasix-rust:package') }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: oliphaunt-wasix-rust-package-artifacts path: target/sdk-artifacts/oliphaunt-wasix-rust if-no-files-found: error + - name: Upload PGwire server package artifacts + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['wasix-rust-package'], 'oliphaunt-pgwire-server:package') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: oliphaunt-pgwire-server-sdk-package-artifacts + path: target/sdk-artifacts/oliphaunt-pgwire-server + if-no-files-found: error + liboliphaunt-wasix-runtime: name: Builds / liboliphaunt WASIX Runtime needs: - affected + - checks + - tests if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'liboliphaunt-wasix-runtime') }} runs-on: ubuntu-24.04 timeout-minutes: 360 @@ -1775,9 +1973,6 @@ jobs: with: cache-save-if: ${{ env.HEAVY_CACHE_SAVE_IF }} - - name: Verify source-controlled asset inputs - run: cargo run -p xtask -- assets verify-committed - - name: Restore WASIX compilation cache id: wasix-build-cache uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 @@ -1815,8 +2010,8 @@ jobs: if: ${{ env.HEAVY_CACHE_SAVE_IF == 'true' }} uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f with: - context: src/runtimes/liboliphaunt/wasix/assets/build/docker - file: src/runtimes/liboliphaunt/wasix/assets/build/docker/Dockerfile + context: src/runtimes/liboliphaunt-wasix/assets/build/docker + file: src/runtimes/liboliphaunt-wasix/assets/build/docker/Dockerfile tags: oliphaunt-wasix-wasix-build:ci load: true cache-from: type=gha,scope=wasix-builder @@ -1826,8 +2021,8 @@ jobs: if: ${{ env.HEAVY_CACHE_SAVE_IF != 'true' }} uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f with: - context: src/runtimes/liboliphaunt/wasix/assets/build/docker - file: src/runtimes/liboliphaunt/wasix/assets/build/docker/Dockerfile + context: src/runtimes/liboliphaunt-wasix/assets/build/docker + file: src/runtimes/liboliphaunt-wasix/assets/build/docker/Dockerfile tags: oliphaunt-wasix-wasix-build:ci load: true cache-from: type=gha,scope=wasix-builder @@ -1876,6 +2071,38 @@ jobs: target/oliphaunt-wasix/wasix-build/build key: wasix-build-${{ runner.os }}-${{ env.ASSET_PROFILE }}-${{ env.WASMER_LLVM_VERSION }}-${{ env.WASMER_LLVM_LINUX_X64_BYTES }}-${{ env.WASMER_LLVM_LINUX_X64_SHA256 }}-${{ github.event.pull_request.head.sha || github.sha }} + - name: Upload portable WASIX tools compiler outputs + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-runtime'], 'postgres-tools-wasix:compiler-output') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: postgres-tools-wasix-compiler-output + path: target/postgres-tools/wasix/assets + if-no-files-found: error + + - name: Upload portable WASIX extension compiler outputs + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-runtime'], 'extension-artifacts-wasix:compiler-output') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: extensions-wasix-compiler-output + path: target/extensions/wasix/assets + if-no-files-found: error + + - name: Upload portable PostgreSQL WASIX tools + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-runtime'], 'postgres-tools-wasix:package-portable') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: postgres-tools-wasix-release-assets-portable + path: target/postgres-tools/wasix/release-assets/*-portable.tar.gz + if-no-files-found: error + + - name: Upload independent WASIX cluster seeds + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-runtime'], 'database-resources:build-wasix-standard') || contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-runtime'], 'database-resources:build-wasix-icu') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: database-resources-wasix-seeds-portable + path: target/database-resources/release-assets/*-seed-wasix-* + if-no-files-found: error + - name: Upload portable WASIX build outputs uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: @@ -1885,7 +2112,7 @@ jobs: target/oliphaunt-wasix/wasix-build/work/icu-wasix/share/icu/** target/oliphaunt-wasix/assets/** src/extensions/generated/** - src/runtimes/liboliphaunt/wasix/assets/generated/** + src/runtimes/liboliphaunt-wasix/assets/generated/** if-no-files-found: error liboliphaunt-wasix-aot: @@ -1923,6 +2150,20 @@ jobs: name: liboliphaunt-wasix-runtime-portable path: . + - name: Download portable WASIX tools compiler outputs + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-aot'], 'postgres-tools-wasix:build-aot') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: postgres-tools-wasix-compiler-output + path: target/postgres-tools/wasix/assets + + - name: Download portable WASIX extension compiler outputs + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-aot'], 'extension-artifacts-wasix:build-aot') }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: extensions-wasix-compiler-output + path: target/extensions/wasix/assets + - name: Install Wasmer LLVM 22.1 for AOT generation uses: ./.github/actions/setup-wasmer-llvm with: @@ -1934,11 +2175,19 @@ jobs: - name: Build, validate, and smoke target AOT artifacts env: AOT_TARGET: ${{ matrix.target }} - AOT_PACKAGE: ${{ matrix.package }} - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-wasix:runtime-portable"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-wasix:runtime-portable", "postgres-tools-wasix:compiler-output", "extension-artifacts-wasix:compiler-output"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh liboliphaunt-wasix-aot + - name: Upload target PostgreSQL WASIX tools + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-aot'], 'postgres-tools-wasix:package-aot') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: postgres-tools-wasix-release-assets-${{ matrix.target_id }} + path: target/postgres-tools/wasix/release-assets/*-aot-${{ matrix.target_id }}.tar.gz + if-no-files-found: error + - name: Stage target AOT artifact envelope + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-aot'], 'liboliphaunt-wasix:runtime-aot') }} env: AOT_TARGET: ${{ matrix.target }} run: | @@ -1955,6 +2204,7 @@ jobs: printf '%s\n' "$target" >"$upload/target-triple.txt" - name: Upload target artifacts + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-aot'], 'liboliphaunt-wasix:runtime-aot') }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: liboliphaunt-wasix-runtime-aot-${{ matrix.target_id }} @@ -1962,7 +2212,16 @@ jobs: target/oliphaunt-wasix/aot-upload/** if-no-files-found: error + - name: Upload target WASIX tools compiler outputs + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-aot'], 'postgres-tools-wasix:build-aot') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: postgres-tools-wasix-aot-${{ matrix.target_id }} + path: target/postgres-tools/wasix/aot + if-no-files-found: error + - name: Upload target extension AOT artifacts + if: ${{ contains(fromJson(needs.affected.outputs.job_targets)['liboliphaunt-wasix-aot'], 'extension-artifacts-wasix:build-aot') }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: liboliphaunt-wasix-extension-aot-${{ matrix.target_id }} @@ -2040,6 +2299,8 @@ jobs: name: Builds / WASIX Postmaster / Portable + qualification needs: - affected + - checks + - tests if: ${{ contains(fromJson(needs.affected.outputs.jobs), 'wasix-postmaster') }} runs-on: ubuntu-24.04 timeout-minutes: 240 @@ -2076,12 +2337,45 @@ jobs: path: target/oliphaunt-wasix-postmaster/portable-inputs/wasix-postmaster-portable-build-inputs.tar.gz if-no-files-found: error + - name: Pack qualified Linux x64 postmaster runtime + if: ${{ contains(fromJson(needs.affected.outputs.liboliphaunt_wasix_postmaster_runtime_matrix).include.*.target_id, 'linux-x64-gnu') }} + run: | + tar -czf "$RUNNER_TEMP/postmaster-native-linux-x64.tar.gz" \ + -C target/oliphaunt-wasix-postmaster \ + runtime/build/wasmer-build.receipt \ + runtime/build/postmaster-executor-build.receipt \ + runtime/wasmer/target/release/wasmer \ + runtime/wasmer/target/release/wasmer-headless \ + runtime/postmaster-executor-target/release/oliphaunt-wasix-postmaster-executor \ + runtime/postmaster-executor-target/release/oliphaunt-wasix-start-proof \ + runtime/postmaster-executor-target/release/oliphaunt-wasix-memory-profile \ + runtime/postmaster-compiler-target/release/oliphaunt-wasix-postmaster-compiler + + - name: Upload qualified Linux x64 postmaster runtime + if: ${{ contains(fromJson(needs.affected.outputs.liboliphaunt_wasix_postmaster_runtime_matrix).include.*.target_id, 'linux-x64-gnu') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: liboliphaunt-wasix-postmaster-native-linux-x64 + path: ${{ runner.temp }}/postmaster-native-linux-x64.tar.gz + compression-level: 0 + if-no-files-found: error + + - name: Upload Postmaster failure diagnostics + if: ${{ failure() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: wasix-postmaster-portable-diagnostics + path: | + target/oliphaunt-wasix-postmaster/reports + target/oliphaunt-wasix-postmaster/runtime/reports + retention-days: 3 + wasix-postmaster-target: name: Builds / WASIX Postmaster / ${{ matrix.target_id }} + qualification needs: - affected - wasix-postmaster-portable - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.wasix-postmaster-portable.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'wasix-postmaster') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.wasix-postmaster-portable.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'wasix-postmaster') }} runs-on: ${{ matrix.os }} timeout-minutes: 360 strategy: @@ -2133,9 +2427,24 @@ jobs: tar -xzf "$archive" --strip-components=1 \ -C target/oliphaunt-wasix-postmaster + - name: Download qualified Linux x64 postmaster runtime + if: ${{ matrix.target_id == 'linux-x64-gnu' }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: liboliphaunt-wasix-postmaster-native-linux-x64 + path: target/oliphaunt-wasix-postmaster/native-input-download + + - name: Restore qualified Linux x64 postmaster runtime + if: ${{ matrix.target_id == 'linux-x64-gnu' }} + run: | + tar -xzf target/oliphaunt-wasix-postmaster/native-input-download/postmaster-native-linux-x64.tar.gz \ + -C target/oliphaunt-wasix-postmaster + - name: Build, qualify, and package target WASIX postmaster env: OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS: "1" + OLIPHAUNT_WASIX_POSTMASTER_NATIVE_INPUTS: ${{ matrix.target_id == 'linux-x64-gnu' && '1' || '0' }} + WASIX_INSTALL_DIR: ${{ github.workspace }}/target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3 run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-moon-targets.sh --upstream deep liboliphaunt-wasix-postmaster:release-assets liboliphaunt-wasix-postmaster:immediate-recovery liboliphaunt-wasix-postmaster:linear-memory-integration - name: Upload target WASIX postmaster release asset @@ -2150,7 +2459,7 @@ jobs: needs: - affected - wasix-postmaster-target - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.wasix-postmaster-target.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'wasix-postmaster') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.wasix-postmaster-target.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'wasix-postmaster') }} runs-on: ubuntu-24.04 timeout-minutes: 15 steps: @@ -2173,7 +2482,7 @@ jobs: - name: Merge target WASIX postmaster release assets env: - OLIPHAUNT_CI_JOB_TARGETS_JSON: '{"wasix-postmaster-aggregate":["release-tools:postmaster-release-assets"]}' + OLIPHAUNT_CI_JOB_TARGETS_JSON: '{"wasix-postmaster-aggregate":["liboliphaunt-wasix-postmaster:finalize-release-assets"]}' OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["liboliphaunt-wasix-postmaster:release-assets"]' run: .github/scripts/run-planned-moon-job.sh wasix-postmaster-aggregate @@ -2188,11 +2497,11 @@ jobs: name: E2E / Native Extension Lifecycle / ${{ matrix.label }} needs: - affected - - extension-artifacts-native - - liboliphaunt-native-desktop - - broker-runtime + - extension-artifacts-native-linux + - liboliphaunt-native-desktop-linux + - broker-runtime-linux - rust-sdk-package - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.extension-artifacts-native.result == 'success' && needs.liboliphaunt-native-desktop.result == 'success' && needs.broker-runtime.result == 'success' && needs.rust-sdk-package.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'native-extension-lifecycle') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.extension-artifacts-native-linux.result == 'success' && needs.liboliphaunt-native-desktop-linux.result == 'success' && needs.broker-runtime-linux.result == 'success' && needs.rust-sdk-package.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'native-extension-lifecycle') }} strategy: fail-fast: false matrix: ${{ fromJson(needs.affected.outputs.native_extension_lifecycle_matrix) }} @@ -2223,6 +2532,12 @@ jobs: name: liboliphaunt-native-release-assets-linux-x64-gnu path: target/native-extension-lifecycle/input/runtime + - name: Download same-run Linux PostgreSQL tools + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: postgres-tools-native-release-assets-linux-x64-gnu + path: target/native-extension-lifecycle/input/tools + - name: Download same-run Linux exact-extension artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: @@ -2241,15 +2556,6 @@ jobs: name: oliphaunt-native-extension-proof-linux-x64-gnu path: target/native-extension-lifecycle/input/proof-runner - - name: Run packed Rust release consumer - if: ${{ matrix.shard == 0 }} - run: | - chmod 0755 \ - target/native-extension-lifecycle/input/proof-runner/oliphaunt-rust-release-consumer - src/sdks/rust/tools/check-release-consumer.sh run \ - target/native-extension-lifecycle/input/proof-runner/oliphaunt-rust-release-consumer \ - target/native-extension-lifecycle/input/runtime - - name: Run planned native extension lifecycle proof id: native_extension_lifecycle env: @@ -2259,7 +2565,7 @@ jobs: SHARD_COUNT: ${{ matrix.shard_count }} run: | mkdir -p target/native-extension-lifecycle/evidence - tools/release/run-native-extension-lifecycle-proof.sh 2>&1 \ + src/extensions/tests/native/tools/run-native-extension-lifecycle-proof.sh 2>&1 \ | tee "target/native-extension-lifecycle/evidence/job-shard-${SHARD_INDEX}.log" - name: Upload native extension lifecycle evidence @@ -2277,7 +2583,7 @@ jobs: needs: - affected - native-extension-lifecycle - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.native-extension-lifecycle.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'native-extension-lifecycle') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.native-extension-lifecycle.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'native-extension-lifecycle') }} runs-on: ubuntu-24.04 timeout-minutes: 10 steps: @@ -2314,7 +2620,7 @@ jobs: fi candidate_tree="$(git rev-parse 'HEAD^{tree}')" mkdir -p target/native-extension-lifecycle/aggregate/output - tools/dev/bun.sh tools/release/verify-native-extension-lifecycle-receipts.mjs \ + tools/dev/bun.sh src/extensions/tests/native/tools/verify-native-extension-lifecycle-receipts.mts \ --receipts target/native-extension-lifecycle/aggregate/input \ --candidate-sha "$CI_HEAD_SHA" \ --candidate-tree "$candidate_tree" \ @@ -2339,7 +2645,7 @@ jobs: - extension-artifacts-wasix - liboliphaunt-wasix-runtime - liboliphaunt-wasix-aot - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.extension-artifacts-wasix.result == 'success' && needs.liboliphaunt-wasix-runtime.result == 'success' && needs.liboliphaunt-wasix-aot.result == 'success' && needs.affected.outputs.wasix_release_regression_required == 'true' }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.extension-artifacts-wasix.result == 'success' && needs.liboliphaunt-wasix-runtime.result == 'success' && needs.liboliphaunt-wasix-aot.result == 'success' && needs.affected.outputs.wasix_release_regression_required == 'true' }} runs-on: ubuntu-24.04 timeout-minutes: 240 steps: @@ -2353,28 +2659,7 @@ jobs: - name: Set up Moon uses: ./.github/actions/setup-moon with: - install-workspace: "false" - - - name: Warm pinned extension metadata formatter - run: | - for attempt in 1 2 3; do - if printf 'export const oliphauntFormatterProbe={ready:true};\n' \ - | pnpm --package=@biomejs/biome@2.4.16 dlx biome format \ - --stdin-file-path src/extensions/generated/sdk/react-native.ts \ - >/dev/null; then - break - fi - if (( attempt == 3 )); then - echo 'Pinned Biome formatter preflight failed after three attempts' >&2 - exit 1 - fi - sleep $((attempt * 5)) - done - printf 'export const oliphauntFormatterProbe={offline:true};\n' \ - | PNPM_CONFIG_OFFLINE=true \ - pnpm --package=@biomejs/biome@2.4.16 dlx biome format \ - --stdin-file-path src/extensions/generated/sdk/react-native.ts \ - >/dev/null + install-workspace: "true" - name: Set up Rust uses: ./.github/actions/setup-rust @@ -2394,12 +2679,30 @@ jobs: path: target/extensions/wasix/release-assets merge-multiple: true + - name: Download same-run WASIX extension compiler outputs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: extensions-wasix-compiler-output + path: target/extensions/wasix/assets + - name: Download same-run Linux extension AOT outputs uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: name: liboliphaunt-wasix-extension-aot-linux-x64-gnu path: target/extensions/wasix/aot-artifacts + - name: Download same-run portable WASIX tools compiler outputs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: postgres-tools-wasix-compiler-output + path: target/postgres-tools/wasix/assets + + - name: Download same-run Linux WASIX tools AOT outputs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: postgres-tools-wasix-aot-linux-x64-gnu + path: target/postgres-tools/wasix/aot + - name: Download same-run Linux host AOT outputs uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: @@ -2425,16 +2728,13 @@ jobs: rsync -a "$raw_target_dir/" "$destination/" - name: Stage exact-extension WASIX evidence inputs - run: tools/dev/bun.sh tools/release/build-extension-ci-artifacts.mjs --all --family wasix --require-wasix + run: tools/dev/bun.sh src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts --all --family wasix --require-wasix - name: Collect WASIX extension evidence id: regression env: CI_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT: ${{ github.workspace }}/target/extension-artifacts - # The pinned Biome package was fetched and exercised above. Keep the - # evidence mutation independent of a second registry lookup. - PNPM_CONFIG_OFFLINE: "true" run: | actual_sha="$(git rev-parse HEAD)" if [[ "$actual_sha" != "$CI_HEAD_SHA" ]]; then @@ -2475,12 +2775,13 @@ jobs: name: Builds / Android App (${{ matrix.target }}) needs: - affected - - mobile-extension-packages + - js-sdk-package + - mobile-extension-packages-android - liboliphaunt-native-android - liboliphaunt-native-android-abi - kotlin-sdk-package - react-native-sdk-package - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.mobile-extension-packages.result == 'success' && needs.liboliphaunt-native-android.result == 'success' && needs.liboliphaunt-native-android-abi.result == 'success' && needs.kotlin-sdk-package.result == 'success' && needs.react-native-sdk-package.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'mobile-build-android') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.js-sdk-package.result == 'success' && needs.mobile-extension-packages-android.result == 'success' && needs.liboliphaunt-native-android.result == 'success' && needs.liboliphaunt-native-android-abi.result == 'success' && needs.kotlin-sdk-package.result == 'success' && needs.react-native-sdk-package.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'mobile-build-android') }} strategy: fail-fast: false matrix: ${{ fromJson(needs.affected.outputs.react_native_android_mobile_app_matrix) }} @@ -2508,7 +2809,7 @@ jobs: uses: ./.github/actions/setup-rust - name: Reclaim Android mobile build disk - run: bun .github/scripts/reclaim-android-mobile-build-disk.mjs + run: bash .github/scripts/reclaim-android-mobile-build-disk.sh - name: Download Android liboliphaunt target uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c @@ -2516,46 +2817,41 @@ jobs: name: liboliphaunt-native-target-${{ matrix.target }} path: . - - name: Download ABI-compatible Android runtime-resource closure + - name: Restore Android native build outputs + run: | + tar -xzf native-target.tar.gz + rm native-target.tar.gz + + - name: Download canonical ICU data uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: - name: liboliphaunt-native-abi-compatible-release-assets-android-datum64 - path: target/liboliphaunt/android-runtime-assets + name: database-resources-icu-data-portable + path: target/database-resources/mobile-inputs - - name: Extract ABI-compatible Android runtime-resource closure - env: - OLIPHAUNT_NATIVE_TARGET: ${{ matrix.target }} + - name: Download Android database seed + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: database-resources-native-seeds-android-datum64 + path: target/database-resources/mobile-inputs + + - name: Stage selected Android ICU seed and data run: | - set -- - while IFS= read -r archive; do - [ -n "$archive" ] && set -- "$@" "$archive" - done < <(find target/liboliphaunt/android-runtime-assets -type f \ - -name 'liboliphaunt-*-runtime-resources-android-datum64.tar.gz' | LC_ALL=C sort) - if [ "$#" -ne 1 ]; then - echo "Expected exactly one Android datum64 runtime-resource closure; found $#" >&2 - exit 1 - fi - destination=target/liboliphaunt/runtime-closure/android - mkdir -p "$destination" - tar -xzf "$1" -C "$destination" - set -- - while IFS= read -r receipt; do - [ -n "$receipt" ] && set -- "$@" "$receipt" - done < <(find "$destination" -type f -path '*/oliphaunt/manifest.properties' | LC_ALL=C sort) - if [ "$#" -ne 1 ]; then - echo "Expected exactly one extracted Android runtime-carrier receipt; found $#" >&2 + shopt -s nullglob + icu_archives=(target/database-resources/mobile-inputs/*-icu-data.tar.gz) + seed_archives=(target/database-resources/mobile-inputs/*-seed-native-android-datum64-icu.tar.zst) + if [ "${#icu_archives[@]}" -ne 1 ] || [ "${#seed_archives[@]}" -ne 1 ]; then + echo 'Expected exactly one canonical ICU archive and one Android ICU seed.' >&2 exit 1 fi - closure="$(dirname "$1")" - # JavaScript template interpolation belongs inside the single-quoted Bun program. - # shellcheck disable=SC2016 - tools/dev/bun.sh -e ' - import { validateNativeRuntimeCarrier } from "./tools/release/native-runtime-carrier-contract.mjs"; - const [root, icuData] = process.argv.slice(1); - const { target } = validateNativeRuntimeCarrier(root, { icuData }); - if (target !== "android-datum64") throw new Error(`expected android-datum64, got ${target}`); - ' "$closure" "target/liboliphaunt-mobile-host/$OLIPHAUNT_NATIVE_TARGET/icu/share/icu" - echo "OLIPHAUNT_EXPO_ANDROID_SEED_CLOSURE_DIR=$GITHUB_WORKSPACE/$closure" >> "$GITHUB_ENV" + icu_root=target/database-resources/mobile-android/icu + seed_root=target/database-resources/mobile-android/cluster-seed-icu + mkdir -p "$icu_root" + tar -xzf "${icu_archives[0]}" -C "$icu_root" + tools/dev/bun.sh src/database-resources/seeds/package-mobile-carriers.mts stage \ + --archive "${seed_archives[0]}" --manifest "${seed_archives[0]%.tar.zst}.json" \ + --destination "$seed_root" --target android-datum64 --profile icu --icu-data "$icu_root/share/icu" + echo "OLIPHAUNT_EXPO_ANDROID_SEED_DIR=$GITHUB_WORKSPACE/$seed_root" >> "$GITHUB_ENV" + echo "OLIPHAUNT_EXPO_ANDROID_ICU_DATA_DIR=$GITHUB_WORKSPACE/$icu_root/share/icu" >> "$GITHUB_ENV" - name: Download Kotlin SDK package artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c @@ -2563,6 +2859,12 @@ jobs: name: oliphaunt-kotlin-sdk-package-artifacts path: target/sdk-artifacts/oliphaunt-kotlin + - name: Download query package artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: oliphaunt-query-ts-sdk-package-artifacts + path: target/sdk-artifacts/oliphaunt-query-ts + - name: Download React Native SDK package artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: @@ -2572,7 +2874,7 @@ jobs: - name: Download exact-extension package artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: - name: oliphaunt-mobile-extension-package-artifacts + name: oliphaunt-mobile-extension-package-artifacts-android path: target/extension-artifacts - name: Build Android mobile app @@ -2584,17 +2886,15 @@ jobs: OLIPHAUNT_EXPO_ANDROID_BUILD_TYPE: release OLIPHAUNT_EXPO_ANDROID_EXTENSIONS: ${{ needs.affected.outputs.extension_package_sql_names_csv }} OLIPHAUNT_EXPO_ANDROID_ICU: "1" - OLIPHAUNT_EXPO_ANDROID_ICU_DATA_DIR: ${{ github.workspace }}/target/liboliphaunt-mobile-host/${{ matrix.target }}/icu/share/icu OLIPHAUNT_EXPO_REQUIRE_PREBUILT_EXTENSIONS: "1" OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT: ${{ github.workspace }}/target/extension-artifacts OLIPHAUNT_EXPO_ANDROID_OLIPHAUNT_SO: ${{ github.workspace }}/${{ matrix.build-root }}/out/liboliphaunt.so OLIPHAUNT_EXPO_ANDROID_RUNTIME_DIR: ${{ github.workspace }}/target/liboliphaunt-mobile-host/${{ matrix.target }}/install - OLIPHAUNT_EXPO_ANDROID_INITDB: ${{ github.workspace }}/target/liboliphaunt-mobile-host/${{ matrix.target }}/install/bin/initdb - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["extension-packages:package-mobile", "liboliphaunt-native:package-runtime-android-x86_64", "release-tools:kotlin-sdk-package", "release-tools:react-native-sdk-package"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["oliphaunt-query-ts:package", "database-resources:package-icu", "database-resources:build-native-android-icu", "extension-packages:package-mobile", "liboliphaunt-native:package-runtime-android-x86_64", "liboliphaunt-native:finalize-runtime-android-abi", "oliphaunt-kotlin:package", "oliphaunt-react-native:package"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh mobile-build-android - name: Validate Android mobile app artifacts - run: tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --require-mobile android --require-mobile-prebuilt-extensions + run: tools/dev/bun.sh src/sdks/react-native/tools/check-mobile-artifacts.mts android - name: Upload Android mobile build logs if: ${{ always() }} @@ -2617,7 +2917,8 @@ jobs: name: Builds / iOS App needs: - affected - - mobile-extension-packages + - js-sdk-package + - mobile-extension-packages-ios - liboliphaunt-native-ios - liboliphaunt-native-ios-abi - react-native-sdk-package @@ -2652,61 +2953,60 @@ jobs: name: liboliphaunt-native-target-ios-xcframework path: . + - name: Restore iOS native build outputs + run: | + tar -xzf native-target.tar.gz + rm native-target.tar.gz + - name: Download ABI-compatible iOS liboliphaunt release assets uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: name: liboliphaunt-native-abi-compatible-release-assets-ios-datum64 path: target/liboliphaunt/release-assets - - name: Qualify standalone ICU CocoaPods carrier - run: | - set -- - while IFS= read -r archive; do - [ -n "$archive" ] && set -- "$@" "$archive" - done < <(find target/liboliphaunt/release-assets -maxdepth 1 -type f \ - -name 'liboliphaunt-*-icu-data.tar.gz' | LC_ALL=C sort) - if [ "$#" -ne 1 ]; then - echo "Expected exactly one ICU data release asset; found $#" >&2 - exit 1 - fi - tools/release/check-icu-npm-cocoapods-consumer.sh "$1" - icu_root=target/liboliphaunt/icu-data/ios - mkdir -p "$icu_root" - tar -xzf "$1" -C "$icu_root" share/icu - echo "OLIPHAUNT_IOS_ICU_DATA_DIR=$GITHUB_WORKSPACE/$icu_root/share/icu" >> "$GITHUB_ENV" + - name: Download canonical ICU data + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: database-resources-icu-data-portable + path: target/database-resources/release-assets + + - name: Download iOS database seed + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: database-resources-native-seeds-ios-datum64 + path: target/database-resources/release-assets - - name: Extract ABI-compatible iOS runtime-resource closure + - name: Download canonical ICU npm carrier + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: database-resources-icu-npm + path: target/release/npm-packages/oliphaunt-icu + + - name: Package selected iOS seed npm carrier + run: bash tools/ci/with-projects.sh src/database-resources/seeds/package-carriers.mts --family native --target ios-datum64 --profile icu + + - name: Stage selected iOS ICU seed and data run: | - set -- - while IFS= read -r archive; do - [ -n "$archive" ] && set -- "$@" "$archive" - done < <(find target/liboliphaunt/release-assets -type f \ - -name 'liboliphaunt-*-runtime-resources-ios-datum64.tar.gz' | LC_ALL=C sort) - if [ "$#" -ne 1 ]; then - echo "Expected exactly one iOS datum64 runtime-resource closure; found $#" >&2 - exit 1 - fi - destination=target/liboliphaunt/runtime-closure/ios - mkdir -p "$destination" - tar -xzf "$1" -C "$destination" - set -- - while IFS= read -r receipt; do - [ -n "$receipt" ] && set -- "$@" "$receipt" - done < <(find "$destination" -type f -path '*/oliphaunt/manifest.properties' | LC_ALL=C sort) - if [ "$#" -ne 1 ]; then - echo "Expected exactly one extracted iOS runtime-carrier receipt; found $#" >&2 + shopt -s nullglob + icu_archives=(target/database-resources/release-assets/*-icu-data.tar.gz) + seed_archives=(target/database-resources/release-assets/*-seed-native-ios-datum64-icu.tar.zst) + if [ "${#icu_archives[@]}" -ne 1 ] || [ "${#seed_archives[@]}" -ne 1 ]; then + echo 'Expected exactly one canonical ICU archive and one iOS ICU seed.' >&2 exit 1 fi - closure="$(dirname "$1")" - # JavaScript template interpolation belongs inside the single-quoted Bun program. - # shellcheck disable=SC2016 - tools/dev/bun.sh -e ' - import { validateNativeRuntimeCarrier } from "./tools/release/native-runtime-carrier-contract.mjs"; - const [root, icuData] = process.argv.slice(1); - const { target } = validateNativeRuntimeCarrier(root, { icuData }); - if (target !== "ios-datum64") throw new Error(`expected ios-datum64, got ${target}`); - ' "$closure" "$OLIPHAUNT_IOS_ICU_DATA_DIR" - echo "OLIPHAUNT_EXPO_IOS_SEED_CLOSURE_DIR=$GITHUB_WORKSPACE/$closure" >> "$GITHUB_ENV" + src/database-resources/icu/tools/check-icu-npm-cocoapods-consumer.sh "${icu_archives[0]}" + icu_root=target/database-resources/mobile-ios/icu + seed_root=target/database-resources/mobile-ios/cluster-seed-icu + mkdir -p "$icu_root" + tar -xzf "${icu_archives[0]}" -C "$icu_root" + tools/dev/bun.sh src/database-resources/seeds/package-mobile-carriers.mts stage \ + --archive "${seed_archives[0]}" --manifest "${seed_archives[0]%.tar.zst}.json" \ + --destination "$seed_root" --target ios-datum64 --profile icu --icu-data "$icu_root/share/icu" + { + echo "OLIPHAUNT_EXPO_IOS_SEED_DIR=$GITHUB_WORKSPACE/$seed_root" + echo "OLIPHAUNT_EXPO_IOS_ICU_DATA_DIR=$GITHUB_WORKSPACE/$icu_root/share/icu" + echo "OLIPHAUNT_IOS_ICU_DATA_DIR=$GITHUB_WORKSPACE/$icu_root/share/icu" + } >> "$GITHUB_ENV" - name: Download Swift SDK package artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c @@ -2714,6 +3014,12 @@ jobs: name: oliphaunt-swift-sdk-package-artifacts path: target/sdk-artifacts/oliphaunt-swift + - name: Download query package artifact + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: oliphaunt-query-ts-sdk-package-artifacts + path: target/sdk-artifacts/oliphaunt-query-ts + - name: Download React Native SDK package artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: @@ -2723,12 +3029,12 @@ jobs: - name: Download exact-extension package artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: - name: oliphaunt-mobile-extension-package-artifacts + name: oliphaunt-mobile-extension-package-artifacts-ios path: target/mobile-extension-artifacts - name: Render exact-SHA cache-warm iOS carrier manifest run: | - tools/dev/bun.sh tools/release/ios-carrier-manifest.mjs \ + tools/dev/bun.sh src/sdks/swift/tools/ios-carrier-manifest.mts \ --base-asset-dir target/liboliphaunt/release-assets \ --extension-root target/mobile-extension-artifacts \ --output target/release/ios-carriers/oliphaunt-react-native-ios-carriers.json \ @@ -2741,50 +3047,7 @@ jobs: IOS_CARRIER_CACHE: target/qualification/react-native-ios-carrier-cache PLANNED_EXTENSION_SQL_NAMES: ${{ needs.affected.outputs.extension_package_sql_names_csv }} run: | - extensions="$(tools/dev/bun.sh -e ' - const manifest = JSON.parse(await Bun.file(process.env.IOS_CARRIER_MANIFEST).text()); - const planned = String(process.env.PLANNED_EXTENSION_SQL_NAMES ?? "") - .split(",").filter(Boolean).sort(); - if (planned.length === 0) { - throw new Error("planner selected no exact iOS extension carriers"); - } - if (!Array.isArray(manifest.extensions) || manifest.extensions.length === 0) { - throw new Error("exact iOS carrier manifest contains no extensions"); - } - const names = manifest.extensions.map((row) => row.sqlName).sort(); - if (names.some((name) => typeof name !== "string") || new Set(names).size !== names.length) { - throw new Error("exact iOS carrier manifest has invalid or duplicate extension identities"); - } - if (JSON.stringify(names) !== JSON.stringify(planned)) { - throw new Error("exact iOS carrier manifest does not match the planner-selected extension set"); - } - process.stdout.write(names.join(",")); - ')" - node src/sdks/react-native/tools/stage-ios-app.mjs \ - --carrier "$IOS_CARRIER_MANIFEST" \ - --output-dir "$IOS_CARRIER_STAGE" \ - --extensions "$extensions" \ - --icu \ - --cache-dir "$IOS_CARRIER_CACHE" \ - --allow-file-urls - tools/dev/bun.sh -e ' - const manifest = JSON.parse(await Bun.file(process.env.IOS_CARRIER_MANIFEST).text()); - const selection = JSON.parse(await Bun.file(process.env.IOS_CARRIER_STAGE + "/selection.json").text()); - const expected = String(process.env.PLANNED_EXTENSION_SQL_NAMES ?? "") - .split(",").filter(Boolean).sort(); - const manifested = manifest.extensions.map((row) => row.sqlName).sort(); - const requested = [...selection.requestedExtensions].sort(); - const resolved = selection.extensions.map((row) => row.sqlName).sort(); - if (JSON.stringify(manifested) !== JSON.stringify(expected) || !selection.icu || JSON.stringify(requested) !== JSON.stringify(expected) || JSON.stringify(resolved) !== JSON.stringify(expected)) { - throw new Error("staged iOS carrier selection does not exactly cover every manifest extension plus ICU"); - } - ' - mkdir -p target/release/ios-carriers/qualification - cp "$IOS_CARRIER_STAGE/selection.json" \ - target/release/ios-carriers/qualification/all-extensions-selection.json - cp "$IOS_CARRIER_STAGE/resources/OliphauntReactNativeResources.bundle/oliphaunt/package-size.tsv" \ - target/release/ios-carriers/qualification/all-extensions-package-size.tsv - rm -rf "$IOS_CARRIER_STAGE" "$IOS_CARRIER_CACHE" + bash src/sdks/react-native/tools/qualify-ios-carriers.sh - name: Run exact-extension Swift release consumer env: @@ -2817,7 +3080,7 @@ jobs: echo "Planner returned an invalid exact-extension product id: $product" >&2 exit 1 fi - product_root="$(tools/dev/bun.sh tools/release/release_graph_query.mjs \ + product_root="$(tools/dev/bun.sh tools/release/query.mts \ extension-artifact-root --product "$product" --family native)" product_root="$OLIPHAUNT_EXTENSION_ARTIFACT_ROOT/${product_root#target/extension-artifacts/}" release_assets="$product_root/release-assets" @@ -2854,17 +3117,16 @@ jobs: OLIPHAUNT_EXPO_REQUIRE_PREBUILT_EXTENSIONS: "1" OLIPHAUNT_EXPO_IOS_OLIPHAUNT_XCFRAMEWORK: ${{ github.workspace }}/target/liboliphaunt-ios-xcframework/out/liboliphaunt.xcframework OLIPHAUNT_EXPO_IOS_RUNTIME_DIR: ${{ github.workspace }}/target/liboliphaunt-mobile-host/ios-xcframework/install - OLIPHAUNT_EXPO_IOS_INITDB: ${{ github.workspace }}/target/liboliphaunt-mobile-host/ios-xcframework/install/bin/initdb OLIPHAUNT_REACT_NATIVE_IOS_BASE_CARRIER: ${{ github.workspace }}/target/release/ios-carriers/oliphaunt-react-native-ios-carriers.json - OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["extension-packages:package-mobile", "liboliphaunt-native:package-runtime-ios-xcframework", "release-tools:react-native-sdk-package", "release-tools:swift-sdk-package"]' + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["oliphaunt-query-ts:package", "database-resources:package-icu", "database-resources:build-native-ios-icu", "extension-packages:package-mobile", "liboliphaunt-native:package-runtime-ios-xcframework", "oliphaunt-react-native:package", "oliphaunt-swift:package"]' run: OLIPHAUNT_CI_JOB_TARGETS_JSON='${{ needs.affected.outputs.job_targets }}' .github/scripts/run-planned-moon-job.sh mobile-build-ios - name: Validate iOS mobile app artifacts - run: tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --require-mobile ios --require-mobile-prebuilt-extensions + run: tools/dev/bun.sh src/sdks/react-native/tools/check-mobile-artifacts.mts ios - name: Pack fidelity-preserving iOS app transport run: | - node src/sdks/react-native/tools/ios-app-transport.mjs pack \ + bash src/sdks/react-native/tools/ios-app-transport.sh pack \ --app-dir target/mobile-build/react-native/ios \ --transport-dir target/mobile-build/react-native/ios-transport @@ -2897,7 +3159,7 @@ jobs: builds: name: Builds - if: ${{ always() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} + if: ${{ !cancelled() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} needs: - affected - extension-artifacts-native @@ -2905,8 +3167,10 @@ jobs: - extension-packages - mobile-extension-packages - liboliphaunt-native-android + - liboliphaunt-native-android-abi - liboliphaunt-native-desktop - liboliphaunt-native-ios + - liboliphaunt-native-ios-abi - liboliphaunt-native-release-assets - rust-sdk-package - broker-runtime @@ -2915,12 +3179,14 @@ jobs: - node-direct-release-assets - wasix-napi - wasix-napi-release-assets + - swift-bindings - swift-sdk-package - kotlin-sdk-package - kotlin-maven-staging - react-native-sdk-package - js-sdk-package - wasix-ts-sdk-package + - native-consumers - wasix-rust-package - liboliphaunt-wasix-runtime - liboliphaunt-wasix-aot @@ -2941,29 +3207,6 @@ jobs: - name: Set up Bun uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - - - name: Download native ICU release asset for cross-family validation - if: ${{ contains(fromJson(needs.affected.outputs.builder_jobs), 'liboliphaunt-native-release-assets') && contains(fromJson(needs.affected.outputs.builder_jobs), 'liboliphaunt-wasix-release-assets') }} - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c - with: - name: liboliphaunt-native-icu-data - path: target/cross-family-icu/native - - - name: Download WASIX release assets for cross-family ICU validation - if: ${{ contains(fromJson(needs.affected.outputs.builder_jobs), 'liboliphaunt-native-release-assets') && contains(fromJson(needs.affected.outputs.builder_jobs), 'liboliphaunt-wasix-release-assets') }} - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c - with: - name: liboliphaunt-wasix-release-assets - path: target/cross-family-icu/wasix - - - name: Prove native and WASIX ICU data identity - if: ${{ contains(fromJson(needs.affected.outputs.builder_jobs), 'liboliphaunt-native-release-assets') && contains(fromJson(needs.affected.outputs.builder_jobs), 'liboliphaunt-wasix-release-assets') }} - run: | - tools/dev/bun.sh tools/release/check-cross-family-icu-data.mjs \ - target/cross-family-icu/native \ - target/cross-family-icu/wasix - name: Check selected build jobs id: selected_builds_gate @@ -2971,7 +3214,7 @@ jobs: NEEDS_JSON: ${{ toJson(needs) }} SELECTED_JOBS_JSON: ${{ needs.affected.outputs.builder_jobs }} GATE_LABEL: selected build jobs - run: bun .github/scripts/check-ci-gate.mjs selected + run: bun .github/scripts/check-ci-gate.mts selected - name: Check WASIX release regression id: wasix_regression_gate @@ -2979,14 +3222,14 @@ jobs: NEEDS_JSON: ${{ toJson(needs) }} SELECTED_JOBS_JSON: ${{ needs.affected.outputs.wasix_release_regression_required == 'true' && '["wasix-release-regression"]' || '[]' }} GATE_LABEL: WASIX release regression - run: bun .github/scripts/check-ci-gate.mjs selected + run: bun .github/scripts/check-ci-gate.mts selected mobile-e2e-android: name: E2E / Android App needs: - affected - mobile-build-android - if: ${{ always() && !cancelled() && needs.affected.result == 'success' && needs.mobile-build-android.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'mobile-build-android') }} + if: ${{ !cancelled() && !failure() && needs.affected.result == 'success' && needs.mobile-build-android.result == 'success' && contains(fromJson(needs.affected.outputs.jobs), 'mobile-build-android') }} runs-on: ubuntu-24.04 timeout-minutes: 45 steps: @@ -2997,15 +3240,13 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} persist-credentials: false - - name: Set up Node + - name: Set up Node and Bun id: setup_android_e2e_node - uses: ./.github/actions/setup-node-runtime - with: - node-version: ${{ env.NODE_VERSION }} + uses: ./.github/actions/setup-node-bun - name: Reclaim Android emulator disk id: reclaim_android_emulator_disk - run: node .github/scripts/reclaim-android-mobile-build-disk.mjs + run: bash .github/scripts/reclaim-android-mobile-build-disk.sh - name: Set up Android id: setup_android_e2e @@ -3025,13 +3266,20 @@ jobs: - name: List Android app artifact run: find target/mobile-build/react-native/android -maxdepth 2 -type f -print + - name: Provision runner KVM access + run: | + test -c /dev/kvm + if [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then + sudo chmod a+rw /dev/kvm + fi + - name: Start Android emulator id: start_android_emulator env: OLIPHAUNT_ANDROID_EMULATOR_API: "35" OLIPHAUNT_ANDROID_EMULATOR_DISK_HEADROOM_MB: "2048" OLIPHAUNT_ANDROID_EMULATOR_PARTITION_SIZE_MB: "6144" - run: tools/dev/start-android-emulator-ci.sh + run: tools/ci/start-android-emulator-ci.sh - name: Run Android installed-app E2E env: @@ -3069,11 +3317,8 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} persist-credentials: false - - name: Set up Node and pnpm - uses: ./.github/actions/setup-node-pnpm - with: - node-version: ${{ env.NODE_VERSION }} - pnpm-version: ${{ env.PNPM_VERSION }} + - name: Set up Node and Bun + uses: ./.github/actions/setup-node-bun - name: Set up Apple uses: ./.github/actions/setup-apple @@ -3091,7 +3336,7 @@ jobs: id: ios_app_transport_verify run: | rm -rf target/mobile-build/react-native/ios - node src/sdks/react-native/tools/ios-app-transport.mjs verify-extract \ + bash src/sdks/react-native/tools/ios-app-transport.sh verify-extract \ --transport-dir target/mobile-build/react-native/ios-transport \ --output-dir target/mobile-build/react-native/ios @@ -3122,7 +3367,7 @@ jobs: e2e: name: E2E - if: ${{ always() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} + if: ${{ !cancelled() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} needs: - affected - native-extension-lifecycle-aggregate @@ -3140,8 +3385,6 @@ jobs: - name: Set up Bun uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - name: Check final release execution qualification id: selected_e2e_gate @@ -3149,11 +3392,11 @@ jobs: NEEDS_JSON: ${{ toJson(needs) }} SELECTED_JOBS_JSON: ${{ needs.affected.outputs.e2e_jobs }} GATE_LABEL: final release execution qualification - run: bun .github/scripts/check-ci-gate.mjs selected + run: bun .github/scripts/check-ci-gate.mts selected required: name: Required - if: ${{ always() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} + if: ${{ !cancelled() && (github.event_name != 'pull_request' || github.event.action != 'closed') }} needs: - affected - release-intent @@ -3173,8 +3416,6 @@ jobs: - name: Set up Bun uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - name: Check required jobs id: required_gate @@ -3182,14 +3423,15 @@ jobs: NEEDS_JSON: ${{ toJson(needs) }} REQUIRED_JOBS_JSON: '["affected","release-intent","checks","tests","builds","e2e"]' GATE_LABEL: required CI phases - run: bun .github/scripts/check-ci-gate.mjs required + run: bun .github/scripts/check-ci-gate.mts required qualified: name: Qualified - if: ${{ always() && github.event_name == 'workflow_dispatch' }} + if: ${{ !cancelled() && (github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.affected.outputs.qualification_mode == 'selected-products')) }} needs: - affected - required + - js-sdk-package runs-on: ubuntu-24.04 timeout-minutes: 5 steps: @@ -3218,10 +3460,8 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.sha }} persist-credentials: false - - name: Set up Node.js - uses: ./.github/actions/setup-node-runtime - with: - node-version: ${{ env.NODE_VERSION }} + - name: Set up Bun + uses: ./.github/actions/setup-bun - name: Download same-run affected plan uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c @@ -3244,7 +3484,8 @@ jobs: CI_PLAN_PATH: target/qualification/affected-plan/ci-plan.json WASIX_RELEASE_REGRESSION_REQUIRED: ${{ needs.affected.outputs.wasix_release_regression_required }} WASIX_EVIDENCE_ROOT: target/qualification/wasix-release-regression-evidence - run: node .github/scripts/write-release-candidate.mjs + PRODUCER_RECEIPTS_JSON: ${{ format('[{0}]', needs.js-sdk-package.outputs.producer_receipt || '') }} + run: bash .github/scripts/release-candidate.sh write - name: Upload exact-SHA qualification record id: qualification_evidence diff --git a/.github/workflows/extension-artifacts-native.yml b/.github/workflows/extension-artifacts-native.yml new file mode 100644 index 000000000..53e1998de --- /dev/null +++ b/.github/workflows/extension-artifacts-native.yml @@ -0,0 +1,142 @@ +name: extension-artifacts-native +on: + workflow_call: + inputs: + matrix: + required: true + type: string + job-targets: + required: true + type: string +permissions: + contents: read +env: + OLIPHAUNT_CI_JOB_TARGETS_JSON: ${{ inputs.job-targets }} + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + HEAVY_CACHE_SAVE_IF: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} +defaults: + run: + shell: bash +jobs: + build: + name: Builds / Native Extension Artifacts (${{ matrix.target }}) + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.matrix) }} + runs-on: ${{ matrix.runner }} + timeout-minutes: 135 + env: + CCACHE_DIR: ${{ github.workspace }}/.ci-cache/ccache/native-extension/${{ matrix.target }} + CCACHE_BASEDIR: ${{ github.workspace }} + CCACHE_COMPILERCHECK: content + CCACHE_COMPRESS: "true" + OLIPHAUNT_CCACHE_MAX_SIZE: ${{ matrix.target == 'ios-xcframework' && '512M' || '2G' }} + OLIPHAUNT_CCACHE_ZERO_STATS: "1" + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Set up Moon + uses: ./.github/actions/setup-moon + + - name: Set up Apple + if: ${{ runner.os == 'macOS' }} + uses: ./.github/actions/setup-apple + + - name: Set up Android + if: ${{ startsWith(matrix.target, 'android-') }} + uses: ./.github/actions/setup-android + with: + gradle-cache: "false" + + - name: Set up MSVC + if: ${{ runner.os == 'Windows' }} + uses: ./.github/actions/setup-msvc + + - name: Verify Windows VC runtime atomic staging + if: ${{ runner.os == 'Windows' }} + run: tools/dev/bun.sh test ./tools/packaging/windows-vc-runtime-closure.test.mts + + - name: Set up Rust + uses: ./.github/actions/setup-rust + + - name: Prepare native compiler cache path + if: ${{ matrix.target == 'ios-xcframework' }} + run: mkdir -p "$CCACHE_DIR" + + - name: Restore native compiler cache + id: restore_ios_extension_ccache + if: ${{ matrix.target == 'ios-xcframework' }} + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 + with: + path: ${{ env.CCACHE_DIR }} + key: liboliphaunt-native-extension-ccache-v2-${{ matrix.target }}-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.github/actions/setup-apple/**', '.github/scripts/setup-native-build-tools.sh', 'src/third-party/postgres/**', 'src/third-party/icu/**', 'src/third-party/openssl/**', 'src/runtimes/liboliphaunt-native/sources/**', 'src/extensions/contracts/**', 'src/extensions/catalog/extensions.source.json', 'src/extensions/catalog/native-components.toml', 'src/extensions/external/postgis/tools/preprocess-sql.mts', 'src/extensions/contrib/postgres18.toml', 'src/extensions/external/*/source.toml', 'src/extensions/external/*/recipe.toml', 'src/extensions/external/*/dependencies/**/source.toml', 'src/extensions/external/*/dependencies/**/recipe.toml', 'src/extensions/external/*/patches/**', 'src/extensions/external/*/dependencies/**/patches/**', 'src/extensions/generated/extensions.catalog.json', 'src/extensions/generated/contrib-build.tsv', 'src/extensions/generated/pgxs-build.tsv', 'src/extensions/generated/mobile/static-extensions.tsv', 'src/extensions/generated/mobile/static-registry.json', 'src/runtimes/liboliphaunt-native/bin/build-*.sh', '!src/runtimes/liboliphaunt-native/bin/*.test.sh', 'src/extensions/artifacts/native/tools/build-windows-extensions.sh', 'src/extensions/artifacts/native/tools/windows-extension-sources.mts', 'src/extensions/external/postgis/tools/windows/**', 'src/runtimes/liboliphaunt-native/bin/build-output.bash', 'src/runtimes/liboliphaunt-native/bin/common.sh', 'src/runtimes/liboliphaunt-native/bin/fetch-pinned-git-checkout.sh', 'src/third-party/icu/tools/build.sh', 'src/runtimes/liboliphaunt-native/bin/mobile-*.sh', 'src/runtimes/liboliphaunt-native/bin/postgis-dependency-cache.sh', 'src/runtimes/liboliphaunt-native/bin/postgres-backend-objects.mk', 'src/postgres-tools/native/crates/tools/Cargo.toml', 'src/postgres-tools/native/crates/tools/build.rs', 'src/postgres-tools/native/crates/tools/src/**', 'src/runtimes/liboliphaunt-native/include/**', 'src/runtimes/liboliphaunt-native/patches/**', 'src/runtimes/liboliphaunt-native/portable-uuid/**', 'src/runtimes/liboliphaunt-native/postgres18/**', 'src/runtimes/liboliphaunt-native/src/**') }} + restore-keys: | + liboliphaunt-native-extension-ccache-v2-${{ matrix.target }}-${{ runner.os }}-${{ runner.arch }}- + + - name: Configure native compiler cache + run: .github/scripts/setup-native-build-tools.sh + + - name: Build native exact-extension artifacts + timeout-minutes: 120 + env: + OLIPHAUNT_EXTENSION_PRODUCTS: ${{ matrix.extensions_csv }} + OLIPHAUNT_EXTENSION_TARGET: ${{ matrix.target }} + OLIPHAUNT_BISON: /opt/homebrew/opt/bison/bin/bison + run: .github/scripts/run-planned-moon-job.sh extension-artifacts-native + + - name: Validate produced iOS extension carriers + id: validate_ios_extension_carriers + if: ${{ matrix.target == 'ios-xcframework' }} + run: bun src/runtimes/liboliphaunt-native/tools/validate-ios-carrier-zips.mts --root target/extensions/native/release-assets/ios-xcframework + + - name: Save bounded iOS exact-extension compiler cache + id: save_ios_extension_ccache + if: ${{ matrix.target == 'ios-xcframework' && env.HEAVY_CACHE_SAVE_IF == 'true' && steps.restore_ios_extension_ccache.outputs.cache-hit != 'true' }} + continue-on-error: true + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 + with: + path: ${{ env.CCACHE_DIR }} + key: liboliphaunt-native-extension-ccache-v2-${{ matrix.target }}-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('.github/actions/setup-apple/**', '.github/scripts/setup-native-build-tools.sh', 'src/third-party/postgres/**', 'src/third-party/icu/**', 'src/third-party/openssl/**', 'src/runtimes/liboliphaunt-native/sources/**', 'src/extensions/contracts/**', 'src/extensions/catalog/extensions.source.json', 'src/extensions/catalog/native-components.toml', 'src/extensions/external/postgis/tools/preprocess-sql.mts', 'src/extensions/contrib/postgres18.toml', 'src/extensions/external/*/source.toml', 'src/extensions/external/*/recipe.toml', 'src/extensions/external/*/dependencies/**/source.toml', 'src/extensions/external/*/dependencies/**/recipe.toml', 'src/extensions/external/*/patches/**', 'src/extensions/external/*/dependencies/**/patches/**', 'src/extensions/generated/extensions.catalog.json', 'src/extensions/generated/contrib-build.tsv', 'src/extensions/generated/pgxs-build.tsv', 'src/extensions/generated/mobile/static-extensions.tsv', 'src/extensions/generated/mobile/static-registry.json', 'src/runtimes/liboliphaunt-native/bin/build-*.sh', '!src/runtimes/liboliphaunt-native/bin/*.test.sh', 'src/extensions/artifacts/native/tools/build-windows-extensions.sh', 'src/extensions/artifacts/native/tools/windows-extension-sources.mts', 'src/extensions/external/postgis/tools/windows/**', 'src/runtimes/liboliphaunt-native/bin/build-output.bash', 'src/runtimes/liboliphaunt-native/bin/common.sh', 'src/runtimes/liboliphaunt-native/bin/fetch-pinned-git-checkout.sh', 'src/third-party/icu/tools/build.sh', 'src/runtimes/liboliphaunt-native/bin/mobile-*.sh', 'src/runtimes/liboliphaunt-native/bin/postgis-dependency-cache.sh', 'src/runtimes/liboliphaunt-native/bin/postgres-backend-objects.mk', 'src/postgres-tools/native/crates/tools/Cargo.toml', 'src/postgres-tools/native/crates/tools/build.rs', 'src/postgres-tools/native/crates/tools/src/**', 'src/runtimes/liboliphaunt-native/include/**', 'src/runtimes/liboliphaunt-native/patches/**', 'src/runtimes/liboliphaunt-native/portable-uuid/**', 'src/runtimes/liboliphaunt-native/postgres18/**', 'src/runtimes/liboliphaunt-native/src/**') }} + + - name: Show native compiler cache stats + if: ${{ always() && runner.os != 'Windows' }} + run: | + if command -v ccache >/dev/null 2>&1; then + ccache --show-stats + else + echo "ccache was not installed before the build stopped" + fi + + - name: Upload native exact-extension artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: liboliphaunt-native-extension-artifacts-${{ matrix.target }} + path: target/extensions/native/release-assets + if-no-files-found: error + + - name: Upload native exact-extension build logs + id: upload_native_extension_logs + if: ${{ failure() || cancelled() }} + timeout-minutes: 5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: liboliphaunt-native-extension-logs-${{ matrix.target }} + path: | + target/liboliphaunt-mobile-extension-ci/**/*.log + target/liboliphaunt-mobile-extension-release/**/*.log + target/liboliphaunt-mobile-extension-release/ios-xcframework/ios-simulator/*.log + target/liboliphaunt-mobile-extension-release/ios-xcframework/ios-device/*.log + target/liboliphaunt-pg18-extension-release/**/*.log + target/liboliphaunt-pg18-*-extension-release/**/*.log + /tmp/liboliphaunt-ci-*-extensions.log + /tmp/liboliphaunt-release-*-extensions.log + /tmp/liboliphaunt-ci-extension-assets-fetch.log + /tmp/liboliphaunt-release-extension-assets-fetch.log + if-no-files-found: warn + diff --git a/.github/workflows/liboliphaunt-native-desktop.yml b/.github/workflows/liboliphaunt-native-desktop.yml new file mode 100644 index 000000000..598118fe4 --- /dev/null +++ b/.github/workflows/liboliphaunt-native-desktop.yml @@ -0,0 +1,111 @@ +name: liboliphaunt-native-desktop +on: + workflow_call: + inputs: + matrix: + required: true + type: string + job-targets: + required: true + type: string +permissions: + contents: read +env: + OLIPHAUNT_CI_JOB_TARGETS_JSON: ${{ inputs.job-targets }} + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + HEAVY_CACHE_SAVE_IF: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} +defaults: + run: + shell: bash +jobs: + build: + name: Builds / Native Runtime (${{ matrix.target }}) + strategy: + fail-fast: false + matrix: ${{ fromJson(inputs.matrix) }} + runs-on: ${{ matrix.runner }} + timeout-minutes: 120 + env: + CCACHE_DIR: ${{ github.workspace }}/.ci-cache/ccache/native-runtime/${{ matrix.target }} + CCACHE_BASEDIR: ${{ github.workspace }} + CCACHE_COMPILERCHECK: content + CCACHE_COMPRESS: "true" + OLIPHAUNT_CCACHE_ZERO_STATS: "1" + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Set up Moon + uses: ./.github/actions/setup-moon + + - name: Set up Rust + uses: ./.github/actions/setup-rust + + - name: Set up MSVC + if: ${{ runner.os == 'Windows' }} + uses: ./.github/actions/setup-msvc + + - name: Prepare native build paths + env: + NATIVE_BUILD_ROOT: ${{ matrix.build-root }} + run: | + mkdir -p "$NATIVE_BUILD_ROOT" + if [[ "$RUNNER_OS" != "Windows" ]]; then + mkdir -p "$CCACHE_DIR" + fi + + - name: Configure native compiler cache + run: .github/scripts/setup-native-build-tools.sh 2G + + - name: Build and package liboliphaunt native runtime + env: + OLIPHAUNT_CI_TARGET: ${{ matrix.target }} + run: .github/scripts/run-planned-moon-job.sh liboliphaunt-native-desktop + + - name: Upload liboliphaunt release assets + if: ${{ contains(fromJson(inputs.job-targets).liboliphaunt-native-desktop, 'liboliphaunt-native:package-runtime-desktop-target') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: liboliphaunt-native-release-assets-${{ matrix.target }} + path: target/liboliphaunt/desktop-release-assets/${{ matrix.target }} + if-no-files-found: error + + - name: Upload PostgreSQL tools release assets + if: ${{ contains(fromJson(inputs.job-targets).liboliphaunt-native-desktop, 'postgres-tools-native:package-assets') || contains(fromJson(inputs.job-targets).liboliphaunt-native-desktop, 'postgres-tools-native:test-assets') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: postgres-tools-native-release-assets-${{ matrix.target }} + path: target/postgres-tools/native/release-assets + if-no-files-found: error + + - name: Upload independent native cluster seeds + if: ${{ contains(fromJson(inputs.job-targets).liboliphaunt-native-desktop, 'database-resources:build-native-standard') || contains(fromJson(inputs.job-targets).liboliphaunt-native-desktop, 'database-resources:build-native-icu') }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: database-resources-native-seeds-${{ matrix.target }} + path: target/database-resources/release-assets/*-seed-native-${{ matrix.target }}-* + if-no-files-found: error + + - name: Show native compiler cache stats + if: ${{ always() }} + env: + NATIVE_TARGET: ${{ matrix.target }} + run: | + if [[ "$NATIVE_TARGET" != windows-* ]] && command -v ccache >/dev/null 2>&1; then + ccache --show-stats + fi + + - name: Upload liboliphaunt build logs + if: ${{ failure() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: liboliphaunt-logs-${{ matrix.target }} + path: | + ${{ matrix.build-root }}/*.log + target/liboliphaunt/**/*.log + if-no-files-found: ignore diff --git a/.github/workflows/mobile-e2e.yml b/.github/workflows/mobile-e2e.yml index f6819e851..959ce2dec 100644 --- a/.github/workflows/mobile-e2e.yml +++ b/.github/workflows/mobile-e2e.yml @@ -37,11 +37,6 @@ concurrency: group: mobile-e2e-${{ inputs.sha || github.sha }}-${{ inputs.platform || 'all' }} cancel-in-progress: false -env: - NODE_VERSION: 22.22.3 - PNPM_VERSION: 11.5.0 - BUN_VERSION: 1.3.14 - jobs: resolve: name: resolve-build-artifacts @@ -63,8 +58,6 @@ jobs: - name: Set up Bun uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - name: Resolve mobile app artifacts id: plan @@ -75,7 +68,10 @@ jobs: INPUT_PLATFORM: ${{ inputs.platform || 'all' }} DEFAULT_SHA: ${{ github.sha }} BUILD_GATE_JOB: Builds - run: bun .github/scripts/resolve-mobile-e2e.mjs + run: | + CHECKOUT_SHA="$(git rev-parse --verify 'HEAD^{commit}')" + export CHECKOUT_SHA + bun .github/scripts/resolve-mobile-e2e.mts android: name: android-installed-app @@ -92,15 +88,13 @@ jobs: ref: ${{ needs.resolve.outputs.sha }} persist-credentials: false - - name: Set up Node + - name: Set up Node and Bun id: setup_android_e2e_node - uses: ./.github/actions/setup-node-runtime - with: - node-version: ${{ env.NODE_VERSION }} + uses: ./.github/actions/setup-node-bun - name: Reclaim Android emulator disk id: reclaim_android_emulator_disk - run: node .github/scripts/reclaim-android-mobile-build-disk.mjs + run: bash .github/scripts/reclaim-android-mobile-build-disk.sh - name: Set up Android id: setup_android_e2e @@ -119,7 +113,7 @@ jobs: GH_TOKEN: ${{ github.token }} GH_REPO: ${{ github.repository }} run: | - node .github/scripts/download-build-artifacts.mjs \ + bash .github/scripts/download-build-artifacts.sh \ CI \ "$CI_HEAD_SHA" \ target/mobile-build/react-native/android \ @@ -128,13 +122,20 @@ jobs: --artifact react-native-mobile-android-app-android-x86_64 find target/mobile-build/react-native/android -maxdepth 2 -type f -print + - name: Provision runner KVM access + run: | + test -c /dev/kvm + if [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then + sudo chmod a+rw /dev/kvm + fi + - name: Start Android emulator id: start_android_emulator env: OLIPHAUNT_ANDROID_EMULATOR_API: "35" OLIPHAUNT_ANDROID_EMULATOR_DISK_HEADROOM_MB: "2048" OLIPHAUNT_ANDROID_EMULATOR_PARTITION_SIZE_MB: "6144" - run: tools/dev/start-android-emulator-ci.sh + run: tools/ci/start-android-emulator-ci.sh - name: Run Android installed-app E2E id: android_app_e2e @@ -172,11 +173,8 @@ jobs: ref: ${{ needs.resolve.outputs.sha }} persist-credentials: false - - name: Set up Node and pnpm - uses: ./.github/actions/setup-node-pnpm - with: - node-version: ${{ env.NODE_VERSION }} - pnpm-version: ${{ env.PNPM_VERSION }} + - name: Set up Node and Bun + uses: ./.github/actions/setup-node-bun - name: Set up Apple uses: ./.github/actions/setup-apple @@ -192,7 +190,7 @@ jobs: GH_TOKEN: ${{ github.token }} GH_REPO: ${{ github.repository }} run: | - node .github/scripts/download-build-artifacts.mjs \ + bash .github/scripts/download-build-artifacts.sh \ CI \ "$CI_HEAD_SHA" \ target/mobile-build/react-native/ios-transport \ @@ -204,7 +202,7 @@ jobs: id: verify_ios_app_transport run: | rm -rf target/mobile-build/react-native/ios - node src/sdks/react-native/tools/ios-app-transport.mjs verify-extract \ + bash src/sdks/react-native/tools/ios-app-transport.sh verify-extract \ --transport-dir target/mobile-build/react-native/ios-transport \ --output-dir target/mobile-build/react-native/ios find target/mobile-build/react-native/ios -maxdepth 2 -print @@ -234,7 +232,7 @@ jobs: required: name: E2E - if: ${{ always() }} + if: ${{ !cancelled() }} needs: - resolve - android @@ -251,8 +249,6 @@ jobs: - name: Set up Bun uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - name: Check resolver id: resolver_gate @@ -260,7 +256,7 @@ jobs: NEEDS_JSON: ${{ toJson(needs) }} REQUIRED_JOBS_JSON: '["resolve"]' GATE_LABEL: E2E resolver - run: bun .github/scripts/check-ci-gate.mjs required + run: bun .github/scripts/check-ci-gate.mts required - name: Check selected E2E platform jobs id: selected_platforms_gate @@ -268,4 +264,4 @@ jobs: NEEDS_JSON: ${{ toJson(needs) }} SELECTED_JOBS_JSON: ${{ needs.resolve.outputs.platform_jobs }} GATE_LABEL: selected E2E platform jobs - run: bun .github/scripts/check-ci-gate.mjs selected + run: bun .github/scripts/check-ci-gate.mts selected diff --git a/.github/workflows/mobile-extension-packages.yml b/.github/workflows/mobile-extension-packages.yml new file mode 100644 index 000000000..c814f74df --- /dev/null +++ b/.github/workflows/mobile-extension-packages.yml @@ -0,0 +1,63 @@ +name: Mobile extension packages +on: + workflow_call: + inputs: + family: + type: string + required: true + targets: + type: string + required: true + products: + type: string + required: true + job-targets: + type: string + required: true +permissions: + contents: read +env: + OLIPHAUNT_CI_JOB_TARGETS_JSON: ${{ inputs.job-targets }} +defaults: + run: + shell: bash +jobs: + package: + name: Builds / Mobile Extension Packages + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Set up Moon + uses: ./.github/actions/setup-moon + + - name: Set up Rust + uses: ./.github/actions/setup-rust + + - name: Download native exact-extension artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + pattern: liboliphaunt-native-extension-artifacts-${{ inputs.family == 'ios' && 'ios-*' || 'android-*' }} + path: target/extensions/native/release-assets + merge-multiple: true + + - name: Build mobile exact-extension package artifacts + env: + OLIPHAUNT_EXTENSION_PACKAGE_NATIVE_TARGETS: ${{ inputs.targets }} + OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS: ${{ inputs.products }} + OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON: '["extension-artifacts-native:build-target"]' + run: .github/scripts/run-planned-moon-job.sh mobile-extension-packages + + - name: Upload mobile exact-extension package artifacts + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: oliphaunt-mobile-extension-package-artifacts-${{ inputs.family }} + path: target/mobile-extension-artifacts + if-no-files-found: error + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 180e3d9d6..bff548074 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,68 +1,47 @@ name: Release run-name: Release / ${{ inputs.operation }} / ${{ github.ref_name }} - on: workflow_dispatch: inputs: operation: - description: Prepare, dry-run, publish with trusted publishers, or bootstrap first registry versions + description: Prepare the release PR, or freeze and publish the qualified candidate required: true type: choice default: prepare-release-pr options: - prepare-release-pr - - publish-dry-run - publish - - publish-bootstrap release_commit: - description: Candidate source SHA; publish/bootstrap may reuse an approved ancestor after publication-only fixes + description: Optional approved source SHA for recovery after publication-only fixes required: false type: string default: "" approval_run_id: - description: Successful publish-dry-run workflow run that froze the approved candidate (required for publish/bootstrap) + description: Optional previous Release run with a successfully prepared frozen candidate required: false type: string default: "" - permissions: contents: read - env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 CANONICAL_RELEASE_REPOSITORY: f0rr0/oliphaunt - NODE_VERSION: 22.22.3 NPM_VERSION: 11.18.0 - PNPM_VERSION: 11.5.0 - BUN_VERSION: 1.3.14 PUBLICATION_LOCK_PATH: target/release/publication-lock.json BOOTSTRAP_LEDGER_PATH: target/release/bootstrap-ledger - # Normal publication and bootstrap each run within one hosted-runner window. - # Normal publication keeps enough time after registry writes for public - # consumer verification and GitHub draft promotion. RELEASE_JOB_HARD_WINDOW_SECONDS: 21180 BOOTSTRAP_REGISTRY_MUTATION_WINDOW_SECONDS: 19800 POST_REGISTRY_RESERVE_SECONDS: 3240 - # Public consumer lanes run concurrently under one 13-minute internal - # deadline and stop with ten minutes preserved for evidence, lock proof, and - # draft promotion. The enclosing workflow step has a 15-minute hard bound. PUBLIC_CONSUMER_SMOKE_TIMEOUT_SECONDS: 780 PUBLIC_CONSUMER_FINALIZATION_RESERVE_SECONDS: 600 MAVEN_CENTRAL_NAMESPACE: dev.oliphaunt - concurrency: - # Every registry-writing or release-branch-writing operation shares one - # non-cancelling lock. GitHub permits one pending run while the active run - # completes, so maintainers must not stack mutation dispatches. Dry-runs are - # read-only and may run once per exact SHA. - group: release-${{ inputs.operation == 'publish-dry-run' && github.sha || 'mutation' }} + group: release-mutation cancel-in-progress: false - defaults: run: shell: bash - jobs: validate-inputs: name: Validate release inputs @@ -78,14 +57,12 @@ jobs: echo "Release workflow is pinned to ${CANONICAL_RELEASE_REPOSITORY}; got ${GITHUB_REPOSITORY}" >&2 exit 1 fi - - name: Checkout exact workflow commit uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: ref: ${{ github.sha }} fetch-depth: 1 persist-credentials: false - - name: Validate release workflow inputs id: validate_release_inputs env: @@ -93,23 +70,6 @@ jobs: RELEASE_COMMIT: ${{ inputs.release_commit }} RELEASE_APPROVAL_RUN_ID: ${{ inputs.approval_run_id }} run: bash .github/scripts/validate-release-workflow-inputs.sh - - - name: Set up pinned Node.js - id: setup_release_validation_node - if: ${{ inputs.operation == 'prepare-release-pr' }} - timeout-minutes: 3 - uses: ./.github/actions/setup-node-runtime - with: - node-version: ${{ env.NODE_VERSION }} - - - name: Require clear Release Please lifecycle - id: require_release_please_lifecycle - if: ${{ inputs.operation == 'prepare-release-pr' }} - timeout-minutes: 1 - env: - GH_TOKEN: ${{ github.token }} - run: node tools/release/release-please-pr-lifecycle.mjs assert-clean --base main - prepare-release-pr: name: Prepare release PR needs: validate-inputs @@ -128,18 +88,15 @@ jobs: echo "Releases must be run from main; got ${GITHUB_REF}" >&2 exit 1 fi - - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: fetch-depth: 0 persist-credentials: false - - name: Require current main id: require_current_main timeout-minutes: 1 run: bash .github/scripts/require-current-main.sh "$GITHUB_SHA" - - name: Require release PR token env: RELEASE_PR_TOKEN: ${{ secrets.RELEASE_PR_TOKEN }} @@ -149,222 +106,56 @@ jobs: echo "Configure a GitHub App or maintainer bot token in the release-pr environment." >&2 exit 1 fi - - name: Set up Moon uses: ./.github/actions/setup-moon with: install-workspace: "true" - - - name: Set up Rust - uses: ./.github/actions/setup-rust - - - name: Create or update release-please PR - id: release_please - uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 - with: - token: ${{ secrets.RELEASE_PR_TOKEN }} - target-branch: main - config-file: release-please-config.json - manifest-file: .release-please-manifest.json - skip-github-release: true - - - name: Sync derived release PR files - id: sync_release_pr + - name: Generate the Release Please candidate locally + id: prepare_candidate env: GH_TOKEN: ${{ secrets.RELEASE_PR_TOKEN }} - RELEASE_PLEASE_PR: ${{ steps.release_please.outputs.pr }} - RELEASE_PLEASE_PRS: ${{ steps.release_please.outputs.prs }} - RELEASE_PLEASE_PRS_CREATED: ${{ steps.release_please.outputs.prs_created }} - run: | - set -euo pipefail - - release_pr_number="$(bun .github/scripts/resolve-release-please-pr.mjs)" - if [[ -z "${release_pr_number}" ]]; then - if [[ "${RELEASE_PLEASE_PRS_CREATED}" == "true" ]]; then - echo "release-please reported PR changes, but no release PR number could be resolved." >&2 - exit 1 - fi - shared_contrib_status="$( - tools/dev/bun.sh tools/release/sync-release-pr.mjs --shared-contrib-status - )" - if [[ "${shared_contrib_status}" != "required=true" ]]; then - echo "Release Please produced no PR and no unreleased shared contrib source change was found." - exit 0 - fi - - release_pr_branch="release-please--branches--main" - release_pr_title="chore(release): prepare main releases" - gh auth setup-git - bash .github/scripts/require-current-main.sh "$GITHUB_SHA" - git switch -c "${release_pr_branch}" - tools/dev/bun.sh tools/release/sync-release-pr.mjs --bootstrap-shared-contrib - if [[ -n "$(git ls-files --others --exclude-standard)" ]]; then - echo "Shared contrib release bootstrap created untracked files." >&2 - git status --short >&2 - exit 1 - fi - git config user.name "$(bun -p 'require("./tools/release/release-bot.json").name')" - git config user.email "$(bun -p 'require("./tools/release/release-bot.json").email')" - git add -u - if git diff --cached --quiet --exit-code; then - echo "Shared contrib release bootstrap produced no release candidate." >&2 - exit 1 - fi - git commit -m "${release_pr_title}" - tools/dev/bun.sh tools/release/sync-release-pr.mjs --check - git push --set-upstream origin "${release_pr_branch}" - gh pr create \ - --base main \ - --head "${release_pr_branch}" \ - --title "${release_pr_title}" \ - --label "autorelease: pending" \ - --body "Runtime release candidates derived from shared PostgreSQL contrib carrier source changes." - release_pr_number="$( - gh pr view "${release_pr_branch}" --json number --jq '.number' - )" - echo "shared_contrib_pr_created=true" >> "$GITHUB_OUTPUT" - fi - - IFS=$'\t' read -r \ - release_pr_observed_number \ - release_pr_base \ - release_pr_head \ - release_pr_old_sha \ - release_pr_head_repository \ - release_pr_is_cross_repository \ - release_pr_state \ - release_pr_title \ - <<<"$( - gh pr view "${release_pr_number}" \ - --json number,baseRefName,headRefName,headRefOid,headRepository,isCrossRepository,state,title \ - --jq '[.number, .baseRefName, .headRefName, .headRefOid, .headRepository.nameWithOwner, (.isCrossRepository | tostring), .state, .title] | @tsv' - )" - - gh auth setup-git - bash .github/scripts/require-current-main.sh "$GITHUB_SHA" - - release_pr_identity_args=( - --pr-number "${release_pr_number}" - --observed-pr-number "${release_pr_observed_number}" - --base "${release_pr_base}" - --head "${release_pr_head}" - --head-sha "${release_pr_old_sha}" - --head-repository "${release_pr_head_repository}" - --cross-repository "${release_pr_is_cross_repository}" - --state "${release_pr_state}" - --title "${release_pr_title}" - --main-sha "$GITHUB_SHA" - ) - bun .github/scripts/normalize-release-please-pr.mjs \ - normalize \ - "${release_pr_identity_args[@]}" - - tools/dev/bun.sh tools/release/sync-release-pr.mjs - tools/dev/bun.sh tools/release/sync-release-pr.mjs --check - - if [[ -n "$(git ls-files --others --exclude-standard)" ]]; then - echo "Derived release synchronization created untracked files; refusing an incomplete amend." >&2 - git status --short >&2 - exit 1 - fi - - git config user.name "$(bun -p 'require("./tools/release/release-bot.json").name')" - git config user.email "$(bun -p 'require("./tools/release/release-bot.json").email')" - if [[ -n "$(git status --porcelain --untracked-files=no)" ]]; then - git add -u - git commit --amend --no-edit - else - echo "Derived release files already match the normalized Release Please tree." - fi - - release_products_json="$( - tools/dev/bun.sh tools/release/verify-release-commit.mjs \ - --derive-products \ - --head-ref HEAD - )" - tools/dev/bun.sh tools/release/verify-release-commit.mjs \ - --products-json "${release_products_json}" \ - --head-ref HEAD - tools/dev/bun.sh tools/release/release-metadata-check.mjs - bun .github/scripts/normalize-release-please-pr.mjs \ - push \ - "${release_pr_identity_args[@]}" - - - name: Report release-please PR result + run: bash tools/release/prepare-release-pr.sh "$RUNNER_TEMP/release-candidate" + - name: Set up Rust for release manifest synchronization + if: ${{ steps.prepare_candidate.outputs.required == 'true' }} + uses: ./.github/actions/setup-rust + - name: Close and validate the local release candidate + if: ${{ steps.prepare_candidate.outputs.required == 'true' }} + run: bash tools/release/close-release-candidate.sh "$RUNNER_TEMP/release-candidate" + - name: Publish the completed release PR tree + if: ${{ steps.prepare_candidate.outputs.required == 'true' }} env: - RELEASE_PLEASE_PRS_CREATED: ${{ steps.release_please.outputs.prs_created }} - SHARED_CONTRIB_PR_CREATED: ${{ steps.sync_release_pr.outputs.shared_contrib_pr_created }} - run: | - if [[ "${RELEASE_PLEASE_PRS_CREATED}" == "true" || "${SHARED_CONTRIB_PR_CREATED}" == "true" ]]; then - echo "A release PR was created or updated." - else - echo "release-please found no releasable changes." - fi - - publish-dry-run: - name: Prepare release dry run + GH_TOKEN: ${{ secrets.RELEASE_PR_TOKEN }} + run: bash .github/scripts/publish-release-pr.sh "$RUNNER_TEMP/release-candidate" + - name: Report no release changes + if: ${{ steps.prepare_candidate.outputs.required != 'true' }} + run: echo 'Release Please found no releasable changes.' + plan-candidate: + name: Plan publication and qualification needs: - validate-inputs - runs-on: macos-26 - timeout-minutes: 360 - if: ${{ inputs.operation == 'publish-dry-run' }} - environment: release-dry-run + runs-on: ubuntu-24.04 + timeout-minutes: 20 + if: ${{ inputs.operation == 'publish' }} permissions: actions: read contents: read pull-requests: read - steps: &release_candidate_steps - - name: Record release deadline - id: release_job_deadline - if: ${{ inputs.operation == 'publish' }} - run: | - if [[ ! "$RELEASE_JOB_HARD_WINDOW_SECONDS" =~ ^[1-9][0-9]*$ ]]; then - echo 'RELEASE_JOB_HARD_WINDOW_SECONDS must be a positive integer' >&2 - exit 1 - fi - hard_deadline=$(( $(date +%s) + RELEASE_JOB_HARD_WINDOW_SECONDS )) - { - echo "RELEASE_JOB_HARD_DEADLINE_EPOCH=$hard_deadline" - echo "OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH=$RUNNER_TEMP/oliphaunt-github-content-write-pacer.json" - echo "OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH=$RUNNER_TEMP/oliphaunt-github-core-request-journal.json" - echo "OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL=true" - echo "OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR=$RUNNER_TEMP/oliphaunt-github-run-snapshots" - } >> "$GITHUB_ENV" - echo "The release must finish before Unix time $hard_deadline." - + steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: fetch-depth: 0 persist-credentials: false - - name: Resolve release commit id: release_head timeout-minutes: 1 env: INPUT_RELEASE_COMMIT: ${{ inputs.release_commit }} run: .github/scripts/resolve-release-head.sh - - name: Set up Moon uses: ./.github/actions/setup-moon with: install-workspace: "true" - - - name: Require checked publishing code - if: ${{ inputs.operation == 'publish' }} - env: - GH_TOKEN: ${{ github.token }} - GH_REPO: ${{ github.repository }} - run: bash .github/scripts/require-workflow-success.sh CI "$GITHUB_SHA" 0 --job Required - - - name: Set up Rust - uses: ./.github/actions/setup-rust - - - name: Configure macOS release toolchains - id: configure_release_candidate_toolchains - if: ${{ inputs.operation == 'publish-dry-run' }} - run: bash .github/scripts/configure-macos-release-toolchains.sh --android - - name: Plan product releases id: release_plan run: | @@ -374,26 +165,16 @@ jobs: --head-ref "$RELEASE_HEAD_SHA" --format github-output ) - tools/dev/bun.sh tools/release/release_plan.mjs "${release_plan_args[@]}" >> "$GITHUB_OUTPUT" - + bash tools/release/release-plan.sh "${release_plan_args[@]}" >> "$GITHUB_OUTPUT" - name: No package release planned if: ${{ steps.release_plan.outputs.has_release_changes != 'true' }} run: echo "No release-affecting product changes were found since the last product tag." - - name: Resolve selected registry authentication needs id: registry_needs if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} env: PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: bun .github/scripts/selected-registry-needs.mjs - - - name: Verify direct-workflow OIDC identity - id: verify_oidc_identity - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - env: - RELEASE_OPERATION: ${{ inputs.operation }} - run: bun .github/scripts/verify-github-oidc-identity.mjs - + run: bun .github/scripts/selected-registry-needs.mts - name: Prove pending release identity id: verify_publication_candidate if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} @@ -401,11 +182,10 @@ jobs: env: PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} run: | - tools/dev/bun.sh tools/release/verify-publication-candidate.mjs \ + bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" "$RELEASE_HEAD_SHA" tools/dev/bun.sh tools/release/verify-publication-candidate.mts \ --products-json "$PRODUCTS_JSON" \ --head-ref "$RELEASE_HEAD_SHA" \ --github-output "$GITHUB_OUTPUT" - - name: Prove Release Please PR can complete after publication id: assert_release_please_markable if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} @@ -413,86 +193,110 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mjs \ + tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mts \ assert-markable \ --release-sha "${{ steps.verify_publication_candidate.outputs.release_sha }}" \ --base main - - - name: Preflight selected product tag and release collisions - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} + - name: Plan qualification reuse or request + id: ci_qualification + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.approval_run_id == '' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + REQUIRES_WASIX_EVIDENCE: ${{ steps.release_plan.outputs.requires_wasix_release_regression_evidence }} PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} run: | - gh auth setup-git - tools/dev/bun.sh tools/release/verify_product_tags.mjs \ - --products-json "$PRODUCTS_JSON" \ - --target "$RELEASE_HEAD_SHA" \ - --allow-missing - bun .github/scripts/manage-release-drafts.mjs preflight \ - --products-json "$PRODUCTS_JSON" \ - --head-ref "$RELEASE_HEAD_SHA" - - - name: Check release tag App permissions - id: check_release_tag_app - if: ${{ inputs.operation == 'publish' && steps.release_plan.outputs.has_release_changes == 'true' }} - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 - with: &release_tag_app - client-id: ${{ secrets.RELEASE_TAG_APP_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_TAG_APP_PRIVATE_KEY }} - owner: f0rr0 - repositories: oliphaunt - permission-contents: write - permission-workflows: write - - - name: Check publish environment - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} + qualification_args=( + CI + "$RELEASE_HEAD_SHA" + 0 + --plan-qualification "$PRODUCTS_JSON" + --event push + --event workflow_dispatch + --job Builds + --job Required + --job Qualified + --artifact artifact-build-plan + --artifact oliphaunt-release-candidate + ) + if [[ "$REQUIRES_WASIX_EVIDENCE" == true ]]; then + qualification_args+=(--artifact wasix-release-regression-evidence) + fi + if [[ "${{ steps.release_plan.outputs.has_extension_artifacts }}" == true ]]; then + qualification_args+=(--artifact oliphaunt-extension-package-artifacts) + fi + bash .github/scripts/require-workflow-success.sh "${qualification_args[@]}" + outputs: + release_plan: ${{ toJSON(steps.release_plan.outputs) }} + release_head: ${{ toJSON(steps.release_head.outputs) }} + registry_needs: ${{ toJSON(steps.registry_needs.outputs) }} + verify_publication_candidate: ${{ toJSON(steps.verify_publication_candidate.outputs) }} + qualification_request_required: ${{ steps.ci_qualification.outputs.qualification_request_required }} + request-qualification: + name: Request missing CI qualification + needs: plan-candidate + if: ${{ needs.plan-candidate.outputs.qualification_request_required == 'true' }} + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + actions: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 1 + persist-credentials: false + - name: Set up Bun + uses: ./.github/actions/setup-bun + - name: Request or reuse the candidate CI run env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} - ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} - ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} - ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MAVEN_GPG_KEY_ID }} - ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_GPG_PASSPHRASE }} - run: tools/release/check_publish_environment.mjs --products-json "${PRODUCTS_JSON}" - - - name: Verify external registry ownership and trust links - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} - ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} - run: bun .github/scripts/verify-external-publish-readiness.mjs - - - name: Import, sign, and verify Maven credentials before mutation - id: verify_maven_signing - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && steps.registry_needs.outputs.needs_maven == 'true' }} - timeout-minutes: 2 + GH_REPO: ${{ github.repository }} + RELEASE_HEAD_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} + run: bash .github/scripts/require-workflow-success.sh CI "$RELEASE_HEAD_SHA" 120 --dispatch-qualification "$PRODUCTS_JSON" + prepare-candidate: + name: Prepare frozen publication candidate + needs: + - plan-candidate + - request-qualification + runs-on: ubuntu-24.04 + timeout-minutes: 360 + if: ${{ !cancelled() && needs.plan-candidate.result == 'success' && (needs.request-qualification.result == 'success' || needs.request-qualification.result == 'skipped') && fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' }} + environment: release-dry-run + permissions: + actions: read + contents: read + pull-requests: read + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + persist-credentials: false + - name: Restore exact publication source env: - ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} - ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MAVEN_GPG_KEY_ID }} - ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_GPG_PASSPHRASE }} - run: tools/dev/bun.sh tools/release/verify-maven-signing-readiness.mjs - + INPUT_RELEASE_COMMIT: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} + run: .github/scripts/resolve-release-head.sh + - name: Set up Moon + uses: ./.github/actions/setup-moon + with: + install-workspace: "true" - name: Require qualified release-commit CI run id: ci_qualification - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - RELEASE_OPERATION: ${{ inputs.operation }} - REQUIRES_WASIX_EVIDENCE: ${{ steps.release_plan.outputs.requires_wasix_release_regression_evidence }} + REQUIRES_WASIX_EVIDENCE: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).requires_wasix_release_regression_evidence }} + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} run: | - qualification_timeout=7200 - if [[ "$RELEASE_OPERATION" != publish-dry-run ]]; then - qualification_timeout=0 - fi qualification_args=( CI "$RELEASE_HEAD_SHA" - "$qualification_timeout" + 7200 + --qualification-products "$PRODUCTS_JSON" --event push --event workflow_dispatch --job Builds @@ -504,73 +308,70 @@ jobs: if [[ "$REQUIRES_WASIX_EVIDENCE" == true ]]; then qualification_args+=(--artifact wasix-release-regression-evidence) fi - if [[ "${{ steps.release_plan.outputs.has_extension_artifacts }}" == true ]]; then + if [[ "${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_extension_artifacts }}" == true ]]; then qualification_args+=(--artifact oliphaunt-extension-package-artifacts) fi bash .github/scripts/require-workflow-success.sh "${qualification_args[@]}" - - name: Download exact-SHA qualification record - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} run: | - node .github/scripts/download-build-artifacts.mjs \ + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_HEAD_SHA" \ target/release-candidate \ --run-id "$CI_RUN_ID" \ --job Qualified \ --artifact oliphaunt-release-candidate - - name: Download exact-SHA affected plan - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} run: | - node .github/scripts/download-build-artifacts.mjs \ + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_HEAD_SHA" \ target/release-candidate/affected-plan \ --run-id "$CI_RUN_ID" \ --job "Planning / Affected Work" \ --artifact artifact-build-plan - - name: Download required exact-SHA WASIX evidence - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && steps.release_plan.outputs.requires_wasix_release_regression_evidence == 'true' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && fromJSON(needs.plan-candidate.outputs.release_plan).requires_wasix_release_regression_evidence == 'true' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} run: | - node .github/scripts/download-build-artifacts.mjs \ + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_HEAD_SHA" \ target/release-candidate/wasix-evidence \ --run-id "$CI_RUN_ID" \ --job "E2E / WASIX Release Regression" \ --artifact wasix-release-regression-evidence - - name: Verify exact-SHA qualification record id: verify_qualification - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' }} env: + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - WASIX_EVIDENCE_REQUIRED: ${{ steps.release_plan.outputs.requires_wasix_release_regression_evidence }} + WASIX_EVIDENCE_REQUIRED: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).requires_wasix_release_regression_evidence }} run: | - node .github/scripts/verify-release-candidate.mjs \ + bash .github/scripts/release-candidate.sh verify \ target/release-candidate/oliphaunt-release-candidate.json \ --plan target/release-candidate/affected-plan/ci-plan.json \ - --qualification-mode full-payload \ + --qualification-mode release \ + --products-json "$PRODUCTS_JSON" \ --wasix-evidence-required "$WASIX_EVIDENCE_REQUIRED" \ --wasix-evidence-root target/release-candidate/wasix-evidence - - - name: Require the explicitly approved dry-run candidate + - name: Require the explicitly selected prepared candidate id: approved_publication_lock - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id != '' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} @@ -587,125 +388,111 @@ jobs: "$RELEASE_HEAD_SHA" \ 0 \ --run-id "$APPROVAL_RUN_ID" \ + --release-candidate \ --event workflow_dispatch \ "${approved_artifacts[@]}" cat "$gate_output" >> "$GITHUB_OUTPUT" - - name: Download the approved lock and frozen candidate - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - RELEASE_LOCK_RUN_ID: ${{ steps.approved_publication_lock.outputs.run_id }} - APPROVED_ARTIFACT_METADATA_JSON: ${{ steps.approved_publication_lock.outputs.artifact_metadata_json }} - run: | - node .github/scripts/download-build-artifacts.mjs \ - Release \ - "$RELEASE_HEAD_SHA" \ - "$RUNNER_TEMP/approved-publication" \ - --run-id "$RELEASE_LOCK_RUN_ID" \ - --artifact-metadata-json "$APPROVED_ARTIFACT_METADATA_JSON" \ - --artifact oliphaunt-publication-lock \ - --artifact oliphaunt-publication-candidate - + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id != '' }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ steps.approved_publication_lock.outputs.run_id }} + artifact-ids: ${{ steps.approved_publication_lock.outputs.artifact_ids }} + merge-multiple: true + path: ${{ runner.temp }}/approved-publication - name: Verify and install the complete approved candidate - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id != '' }} env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} APPROVAL_RUN_ID: ${{ inputs.approval_run_id }} run: | - tools/dev/bun.sh tools/release/bootstrap-publication-capsule.mjs verify-extract \ + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/bootstrap-publication-capsule.mts verify-extract \ --transport "$RUNNER_TEMP/approved-publication/oliphaunt-publication-candidate.tar" \ --approved-lock "$RUNNER_TEMP/approved-publication/publication-lock.json" \ --products-json "$PRODUCTS_JSON" \ --head-ref "$RELEASE_HEAD_SHA" \ --approval-run-id "$APPROVAL_RUN_ID" \ --workspace-root "$GITHUB_WORKSPACE" - - name: Validate product versions and registry state id: validate_release_registry_state - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} run: | - tools/dev/bun.sh tools/release/release-check-registries.mjs \ + bash tools/release/release-check-registries.sh \ --products-json "$PRODUCTS_JSON" \ --head-ref "$RELEASE_HEAD_SHA" - - name: Download WASIX runtime build artifacts - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix') }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'liboliphaunt-wasix') }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ steps.release_head.outputs.sha }} - run: bun .github/scripts/download-wasix-runtime-build-artifacts.mjs - + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} + run: bash .github/scripts/download-wasix-runtime-build-artifacts.sh - name: Download WASIX release assets - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix') }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'liboliphaunt-wasix') }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ steps.release_head.outputs.sha }} + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} run: | - node .github/scripts/download-build-artifacts.mjs \ + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_ARTIFACT_SHA" \ target/oliphaunt-wasix/release-assets \ --run-id "$CI_RUN_ID" \ --job Builds \ --artifact liboliphaunt-wasix-release-assets - - name: Download WASIX postmaster release assets - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix-postmaster') }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'liboliphaunt-wasix-postmaster') }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ steps.release_head.outputs.sha }} + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} run: | - node .github/scripts/download-build-artifacts.mjs \ + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_ARTIFACT_SHA" \ target/oliphaunt-wasix-postmaster/release-assets \ --run-id "$CI_RUN_ID" \ --job Builds \ --artifact liboliphaunt-wasix-postmaster-release-assets - - name: Download exact-extension package artifacts - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && steps.release_plan.outputs.has_extension_artifacts == 'true' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && fromJSON(needs.plan-candidate.outputs.release_plan).has_extension_artifacts == 'true' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ steps.release_head.outputs.sha }} + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} run: | - node .github/scripts/download-build-artifacts.mjs \ + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_ARTIFACT_SHA" \ target/extension-artifacts \ --run-id "$CI_RUN_ID" \ --job Builds \ --artifact oliphaunt-extension-package-artifacts - - name: Download SDK package artifacts - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ steps.release_head.outputs.sha }} + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} run: | download_sdk_artifact() { local product="$1" local artifact_args=() while IFS= read -r artifact; do artifact_args+=(--artifact "$artifact") - done < <(tools/dev/bun.sh tools/release/release_graph_query.mjs ci-artifact-names --product "$product" --family sdk-package --format lines) - node .github/scripts/download-build-artifacts.mjs \ + done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product "$product" --family sdk-package --format lines) + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_ARTIFACT_SHA" \ "target/sdk-artifacts/$product" \ @@ -715,51 +502,55 @@ jobs: } while IFS= read -r product; do download_sdk_artifact "$product" - done < <(tools/dev/bun.sh tools/release/release_graph_query.mjs ci-products --family sdk-package --products-json "$PRODUCTS_JSON" --format lines) - + done < <(tools/dev/bun.sh tools/release/query.mts ci-products --family sdk-package --products-json "$PRODUCTS_JSON" --format lines) - name: Download liboliphaunt release assets - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-native') }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'liboliphaunt-native') }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ steps.release_head.outputs.sha }} + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} run: | - node .github/scripts/download-build-artifacts.mjs \ + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_ARTIFACT_SHA" \ target/liboliphaunt/release-assets \ --run-id "$CI_RUN_ID" \ --job Builds \ --artifact liboliphaunt-native-release-assets - - - name: Prove native and WASIX ICU data identity - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-native') && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix') }} + - name: Download canonical database resources + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'database-resources') }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} run: | - tools/dev/bun.sh tools/release/check-cross-family-icu-data.mjs \ - target/liboliphaunt/release-assets \ - target/oliphaunt-wasix/release-assets - - - name: Set up Bun for TypeScript npm consumer checks - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-js') }} - uses: ./.github/actions/setup-bun - with: - bun-version: ${{ env.BUN_VERSION }} - - - name: Install TypeScript release tooling - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-js') }} - run: pnpm install --frozen-lockfile - + artifacts=() + for kind in icu-data native-seeds wasix-seeds; do + while IFS= read -r artifact; do + artifacts+=(--artifact "$artifact") + done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product database-resources --kind "$kind" --family release-assets --format lines) + done + bash .github/scripts/download-build-artifacts.sh \ + CI \ + "$RELEASE_ARTIFACT_SHA" \ + target/database-resources/release-assets \ + --run-id "$CI_RUN_ID" \ + --job Builds \ + "${artifacts[@]}" - name: Download native helper release assets - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && (contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-broker') || contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-node-direct') || contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-wasix-napi')) }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && (contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-broker') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-node-direct') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-wasix-napi') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'postgres-tools-native') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'postgres-tools-wasix')) }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - PRODUCT_OLIPHAUNT_BROKER: ${{ contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-broker') }} - PRODUCT_OLIPHAUNT_NODE_DIRECT: ${{ contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-node-direct') }} - PRODUCT_OLIPHAUNT_WASIX_NAPI: ${{ contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-wasix-napi') }} + PRODUCT_POSTGRES_TOOLS_WASIX: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'postgres-tools-wasix') }} + PRODUCT_POSTGRES_TOOLS_NATIVE: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'postgres-tools-native') }} + PRODUCT_OLIPHAUNT_BROKER: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-broker') }} + PRODUCT_OLIPHAUNT_NODE_DIRECT: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-node-direct') }} + PRODUCT_OLIPHAUNT_WASIX_NAPI: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-wasix-napi') }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ steps.release_head.outputs.sha }} + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} run: | download_helper_artifacts() { local product="$1" @@ -768,8 +559,8 @@ jobs: local artifact_args=() while IFS= read -r artifact; do artifact_args+=(--artifact "$artifact") - done < <(tools/dev/bun.sh tools/release/release_graph_query.mjs ci-artifact-names --product "$product" --kind "$kind" --family release-assets --format lines) - node .github/scripts/download-build-artifacts.mjs \ + done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product "$product" --kind "$kind" --family release-assets --format lines) + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_ARTIFACT_SHA" \ "$destination" \ @@ -777,6 +568,13 @@ jobs: --job Builds \ "${artifact_args[@]}" } + if [ "$PRODUCT_POSTGRES_TOOLS_WASIX" = "true" ]; then + download_helper_artifacts postgres-tools-wasix wasix-tools target/postgres-tools/wasix/release-assets + download_helper_artifacts postgres-tools-wasix wasix-tools-aot target/postgres-tools/wasix/release-assets + fi + if [ "$PRODUCT_POSTGRES_TOOLS_NATIVE" = "true" ]; then + download_helper_artifacts postgres-tools-native native-tools target/postgres-tools/native/release-assets + fi if [ "$PRODUCT_OLIPHAUNT_BROKER" = "true" ]; then download_helper_artifacts \ oliphaunt-broker \ @@ -795,54 +593,50 @@ jobs: wasix-napi-addon \ target/oliphaunt-wasix-napi/release-assets fi - - name: Download Node direct optional npm packages - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-node-direct') }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-node-direct') }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ steps.release_head.outputs.sha }} + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} run: | artifact_args=() while IFS= read -r artifact; do artifact_args+=(--artifact "$artifact") - done < <(tools/dev/bun.sh tools/release/release_graph_query.mjs ci-artifact-names --product oliphaunt-node-direct --kind node-direct-addon --family npm-package --format lines) - node .github/scripts/download-build-artifacts.mjs \ + done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product oliphaunt-node-direct --kind node-direct-addon --family npm-package --format lines) + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_ARTIFACT_SHA" \ target/oliphaunt-node-direct/npm-packages \ --run-id "$CI_RUN_ID" \ --job Builds \ "${artifact_args[@]}" - - name: Download WASIX Node-API optional npm packages - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-wasix-napi') }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-wasix-napi') }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ steps.release_head.outputs.sha }} + RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} run: | artifact_args=() while IFS= read -r artifact; do artifact_args+=(--artifact "$artifact") - done < <(tools/dev/bun.sh tools/release/release_graph_query.mjs ci-artifact-names --product oliphaunt-wasix-napi --kind wasix-napi-addon --family npm-package --format lines) - node .github/scripts/download-build-artifacts.mjs \ + done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product oliphaunt-wasix-napi --kind wasix-napi-addon --family npm-package --format lines) + bash .github/scripts/download-build-artifacts.sh \ CI \ "$RELEASE_ARTIFACT_SHA" \ target/oliphaunt-wasix-napi/npm-packages \ --run-id "$CI_RUN_ID" \ --job Builds \ "${artifact_args[@]}" - - name: Freeze canonical Apple extension carrier input - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' && (contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-swift') || contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-react-native')) }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' && (contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-swift') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-react-native')) }} env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + includes_swift: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-swift') }} + includes_react_native: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-react-native') }} run: | - includes_swift="$(bun -e 'console.log(JSON.parse(process.argv[1]).includes("oliphaunt-swift"))' "$PRODUCTS_JSON")" - includes_react_native="$(bun -e 'console.log(JSON.parse(process.argv[1]).includes("oliphaunt-react-native"))' "$PRODUCTS_JSON")" swift_source_carrier=target/sdk-artifacts/oliphaunt-swift/release-tree/src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json react_native_source_carrier=target/sdk-artifacts/oliphaunt-react-native/ios-carriers/oliphaunt-react-native-ios-carriers.json extension_manifest_args=() @@ -864,7 +658,7 @@ jobs: exit 1 fi extension_carrier_args+=(--extension-carrier "${product_carriers[0]}") - done < <(tools/dev/bun.sh tools/release/release_graph_query.mjs \ + done < <(tools/dev/bun.sh tools/release/query.mts \ ci-products \ --family extension-artifacts \ --carrier-family native \ @@ -885,7 +679,7 @@ jobs: "${extension_manifest_args[@]}" --output target/release/ios-carriers/oliphaunt-react-native-ios-carriers.json ) - tools/dev/bun.sh tools/release/ios-carrier-manifest.mjs "${public_args[@]}" + tools/dev/bun.sh src/sdks/swift/tools/ios-carrier-manifest.mts "${public_args[@]}" fi if [[ "$includes_swift" == true && ${#extension_manifest_args[@]} -gt 0 ]]; then @@ -897,25 +691,22 @@ jobs: --output "$local_aggregate_carrier" --local-urls ) - tools/dev/bun.sh tools/release/ios-carrier-manifest.mjs "${local_args[@]}" - extensions_csv="$(bun -e ' - const manifest = JSON.parse(await Bun.file(process.argv[1]).text()); - console.log(manifest.extensions.map((row) => row.sqlName).sort().join(",")); - ' "$local_aggregate_carrier")" + tools/dev/bun.sh src/sdks/swift/tools/ios-carrier-manifest.mts "${local_args[@]}" + extensions_csv="$(bun src/sdks/swift/tools/ios-carrier-manifest.mts list-extensions "$local_aggregate_carrier")" if [[ -z "$extensions_csv" || ${#extension_carrier_args[@]} == 0 ]]; then echo 'Swift extension validation requires selected extension carrier assets.' >&2 exit 1 fi - swift_version="$(tools/dev/bun.sh tools/release/product-version.mjs version oliphaunt-swift)" + swift_version="$(tools/dev/bun.sh tools/release/product-version.mts version oliphaunt-swift)" cache=target/release-work/swiftpm-extension-cache - node src/sdks/swift/tools/render-extension-products.mjs \ + bun src/sdks/swift/tools/render-extension-products.mts \ --carrier "$local_aggregate_carrier" \ --extensions "$extensions_csv" \ --cache-dir "$cache" \ --allow-file-urls \ --base-package-version "$swift_version" \ --output-dir target/release-work/swiftpm-extension-cache-warm - node src/sdks/swift/tools/render-extension-products.mjs \ + bun src/sdks/swift/tools/render-extension-products.mts \ --carrier "$swift_source_carrier" \ "${extension_carrier_args[@]}" \ --extensions "$extensions_csv" \ @@ -924,38 +715,32 @@ jobs: --base-package-version "$swift_version" \ --output-dir target/release/swiftpm-extension-consumer-fixture fi - - name: Set up pinned npm publisher id: setup_github_stage_npm - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.registry_needs.outputs.needs_npm == 'true' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && fromJSON(needs.plan-candidate.outputs.registry_needs).needs_npm == 'true' }} timeout-minutes: 3 uses: ./.github/actions/setup-npm-publisher with: npm-version: ${{ env.NPM_VERSION }} - - - name: Validate selected release + - name: Verify unchanged candidate source before assembly id: validate_release - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' }} env: - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - WASIX_EVIDENCE_REQUIRED: ${{ steps.release_plan.outputs.requires_wasix_release_regression_evidence }} - run: tools/dev/bun.sh tools/release/release-publish.mjs publish-dry-run --qualified-ci --products-json "${PRODUCTS_JSON}" --head-ref "$RELEASE_HEAD_SHA" - + CANDIDATE_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} + run: bash tools/release/qualified-release-replay.sh "$CANDIDATE_SHA" "$CANDIDATE_SHA" - name: Package public release carriers - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' }} env: OLIPHAUNT_BROKER_RELEASE_ASSET_INPUT_DIRS: ${{ github.workspace }}/target/oliphaunt-broker/release-assets OLIPHAUNT_NODE_ADDON_ASSET_INPUT_DIRS: ${{ github.workspace }}/target/oliphaunt-node-direct/release-assets OLIPHAUNT_WASIX_NAPI_ASSET_INPUT_DIRS: ${{ github.workspace }}/target/oliphaunt-wasix-napi/release-assets - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: tools/dev/bun.sh tools/release/package-release-carriers.mjs --products-json "$PRODUCTS_JSON" - + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} + run: bash tools/release/package-release-carriers.sh --products-json "$PRODUCTS_JSON" - name: Freeze exhaustive publication lock id: freeze_publication_lock - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish-dry-run' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id == '' }} env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} run: | lock_args=( create @@ -968,6 +753,13 @@ jobs: target/sdk-artifacts \ target/liboliphaunt/release-assets \ target/liboliphaunt/cargo-artifacts \ + target/postgres-tools/native/release-assets \ + target/postgres-tools/native/cargo-artifacts \ + target/postgres-tools/wasix/release-assets \ + target/postgres-tools/wasix/cargo-artifacts \ + target/database-resources/release-assets \ + target/database-resources/cargo-artifacts \ + target/database-resources/seed-carriers \ target/oliphaunt-wasix/release-assets \ target/oliphaunt-wasix-postmaster/release-assets \ target/oliphaunt-broker/release-assets \ @@ -987,86 +779,36 @@ jobs: exit 1 fi lock_args+=(--artifact-root "$artifact_root") - done < <(tools/dev/bun.sh tools/release/release_graph_query.mjs \ + done < <(tools/dev/bun.sh tools/release/query.mts \ ci-products \ --family extension-artifacts \ --products-json "$PRODUCTS_JSON" \ --field artifact-root \ --format lines) - tools/dev/bun.sh tools/release/publication-lock.mjs "${lock_args[@]}" - tools/dev/bun.sh tools/release/publication-lock.mjs \ + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/publication-lock.mts "${lock_args[@]}" + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/publication-lock.mts \ verify \ --lock target/release/publication-lock.json \ --head-ref "$RELEASE_HEAD_SHA" - - - name: Assemble and sign the exact Maven Central bundle before release mutation - id: preflight_maven_bundle - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && steps.registry_needs.outputs.needs_maven == 'true' }} - timeout-minutes: 15 - env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} - ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MAVEN_GPG_KEY_ID }} - ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_GPG_PASSPHRASE }} - run: | - tools/dev/bun.sh tools/release/preflight-maven-central-bundle.mjs \ - --publication-lock "$PUBLICATION_LOCK_PATH" \ - --products-json "$PRODUCTS_JSON" \ - --release-commit "$RELEASE_HEAD_SHA" - - - name: Prove the exact SwiftPM source tag is remotely collision-free - id: preflight_swift_source_tag - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-swift') }} - timeout-minutes: 2 - run: | - tools/dev/bun.sh tools/release/preflight-swiftpm-source-tag.mjs \ - --publication-lock "$PUBLICATION_LOCK_PATH" \ - --release-commit "$RELEASE_HEAD_SHA" - - - name: Classify pre-tag registry publication state - id: bootstrap_ledger_state - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && (steps.registry_needs.outputs.needs_cargo == 'true' || steps.registry_needs.outputs.needs_npm == 'true') }} - env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - RELEASE_HEAD_SHA: ${{ steps.release_head.outputs.sha }} - run: bun .github/scripts/registry-bootstrap-ledger-state.mjs - - - name: Download immutable registry bootstrap ledger - if: ${{ steps.bootstrap_ledger_state.outputs.needs_ledger == 'true' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - run: bun .github/scripts/download-completed-bootstrap.mjs - - - name: Verify immutable bootstrap ledger and registry existence - if: ${{ steps.bootstrap_ledger_state.outputs.needs_ledger == 'true' }} - env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: | - tools/dev/bun.sh tools/release/bootstrap-ledger.mjs verify \ - --lock "$PUBLICATION_LOCK_PATH" \ - --ledger "$BOOTSTRAP_LEDGER_PATH" \ - --products-json "$PRODUCTS_JSON" \ - --require-complete \ - --verify-registries - - name: Freeze complete publication candidate id: freeze_publication_candidate - if: ${{ inputs.operation == 'publish-dry-run' && steps.release_plan.outputs.has_release_changes == 'true' }} + if: ${{ inputs.approval_run_id == '' && fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' }} env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} run: | - tools/dev/bun.sh tools/release/bootstrap-publication-capsule.mjs pack \ + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/bootstrap-publication-capsule.mts pack \ --lock "$PUBLICATION_LOCK_PATH" \ --products-json "$PRODUCTS_JSON" \ --head-ref "$RELEASE_HEAD_SHA" \ --approval-run-id "$GITHUB_RUN_ID" \ --qualification-run-id "${{ steps.ci_qualification.outputs.run_id }}" \ --output target/release/oliphaunt-publication-candidate.tar - + - name: Preserve the approved recovery capsule unchanged + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' && inputs.approval_run_id != '' }} + run: cp "$RUNNER_TEMP/approved-publication/oliphaunt-publication-candidate.tar" target/release/oliphaunt-publication-candidate.tar - name: Upload frozen publication lock id: preserve_publication_lock - if: ${{ inputs.operation == 'publish-dry-run' && steps.release_plan.outputs.has_release_changes == 'true' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: oliphaunt-publication-lock @@ -1074,10 +816,9 @@ jobs: if-no-files-found: error overwrite: true retention-days: 90 - - name: Upload complete frozen publication candidate id: preserve_publication_candidate - if: ${{ inputs.operation == 'publish-dry-run' && steps.release_plan.outputs.has_release_changes == 'true' }} + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: name: oliphaunt-publication-candidate @@ -1085,415 +826,377 @@ jobs: if-no-files-found: error overwrite: true retention-days: 90 - - - name: Upload publication lock audit evidence - if: ${{ inputs.operation == 'publish' && steps.release_plan.outputs.has_release_changes == 'true' }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - with: - name: oliphaunt-publication-lock-${{ inputs.operation }} - path: target/release/publication-lock.json - if-no-files-found: error - overwrite: true - retention-days: 90 - - - name: Create release tag token - id: release_tag_token - if: ${{ inputs.operation == 'publish' && steps.release_plan.outputs.has_release_changes == 'true' }} - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 - with: *release_tag_app - - - name: Reserve release transport content write - if: ${{ inputs.operation == 'publish' && steps.release_plan.outputs.has_release_changes == 'true' }} - timeout-minutes: 3 + - name: Check whether first registry identities need credentials + id: bootstrap_credentials + if: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' }} + timeout-minutes: 15 + env: + PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} + run: |- + export REGISTRY_MUTATION_DEADLINE_EPOCH="$(( $(date +%s) + 840 ))" + bun .github/scripts/bootstrap-registry-identities.mts --credential-needs + outputs: + has_release_changes: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes }} + lock_artifact_id: ${{ steps.preserve_publication_lock.outputs.artifact-id }} + candidate_artifact_id: ${{ steps.preserve_publication_candidate.outputs.artifact-id }} + bootstrap_required: ${{ steps.bootstrap_credentials.outputs.needs_cargo_token == 'true' || steps.bootstrap_credentials.outputs.needs_npm_token == 'true' }} + publish-bootstrap: + name: Bootstrap registry identities + needs: + - prepare-candidate + runs-on: ubuntu-24.04 + timeout-minutes: 360 + if: ${{ needs.prepare-candidate.outputs.bootstrap_required == 'true' }} + environment: release-bootstrap + permissions: + actions: read + contents: write + id-token: write + pull-requests: read + steps: + - name: Record bounded bootstrap job deadline + id: bootstrap_job_deadline run: | - tools/dev/bun.sh tools/release/github-content-write-pacer.mjs reserve \ - --label "release transport tag" - - - name: Ensure exact immutable release transport ref - id: ensure_release_transport_ref - if: ${{ inputs.operation == 'publish' && steps.release_plan.outputs.has_release_changes == 'true' }} - timeout-minutes: 3 + if [[ ! "$RELEASE_JOB_HARD_WINDOW_SECONDS" =~ ^[1-9][0-9]*$ ]]; then + echo 'RELEASE_JOB_HARD_WINDOW_SECONDS must be a positive integer' >&2 + exit 1 + fi + hard_deadline=$(( $(date +%s) + RELEASE_JOB_HARD_WINDOW_SECONDS )) + { + echo "REGISTRY_JOB_HARD_DEADLINE_EPOCH=$hard_deadline" + echo "OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR=$RUNNER_TEMP/oliphaunt-github-run-snapshots" + } >> "$GITHUB_ENV" + echo "The bootstrap job must stop registry work before Unix time $hard_deadline." + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + persist-credentials: false + - name: Resolve exact release commit + id: release_head + timeout-minutes: 1 env: - GH_TOKEN: ${{ steps.release_tag_token.outputs.token }} - GH_REPO: ${{ github.repository }} - RELEASE_OPERATION: publish - RELEASE_TRANSPORT_CONTENT_WRITE_ADMISSION: pre-reserved - run: node .github/scripts/release-transport-ref.mjs ensure "$RELEASE_HEAD_SHA" - - - name: Stage exact-SHA product tags and draft releases - id: stage_github_releases - if: ${{ inputs.operation == 'publish' && steps.release_plan.outputs.has_release_changes == 'true' }} - timeout-minutes: 31 + INPUT_RELEASE_COMMIT: ${{ inputs.release_commit }} + run: .github/scripts/resolve-release-head.sh + - name: Set up Moon + uses: ./.github/actions/setup-moon + with: + install-workspace: "false" + - name: Require checked publishing code env: - GH_TOKEN: ${{ steps.release_tag_token.outputs.token }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + run: bash .github/scripts/require-workflow-success.sh CI "$GITHUB_SHA" 0 --job Required + - name: Plan bootstrap releases + id: release_plan run: | - bun .github/scripts/manage-release-drafts.mjs stage \ - --products-json "$PRODUCTS_JSON" \ + bash tools/release/release-plan.sh \ + --from-product-tags \ + --include-current-tags \ --head-ref "$RELEASE_HEAD_SHA" \ - --state staged - - - name: Verify exact product tags - id: verify_product_tags - if: ${{ inputs.operation == 'publish' && steps.release_plan.outputs.has_release_changes == 'true' }} - timeout-minutes: 5 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: tools/dev/bun.sh tools/release/verify_product_tags.mjs --products-json "${PRODUCTS_JSON}" --target "$RELEASE_HEAD_SHA" - - - name: Verify exact-SHA GitHub release staging - id: verify_github_staging - if: ${{ inputs.operation == 'publish' && steps.release_plan.outputs.has_release_changes == 'true' }} - timeout-minutes: 5 + --format github-output \ + >> "$GITHUB_OUTPUT" + - name: No package release planned + if: ${{ steps.release_plan.outputs.has_release_changes != 'true' }} + run: echo "No release-affecting product changes were found since the last product tag." + - name: Prove Release Please PR can complete after bootstrap + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ github.token }} PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: bun .github/scripts/manage-release-drafts.mjs verify --products-json "$PRODUCTS_JSON" --head-ref "$RELEASE_HEAD_SHA" --state staged - - - name: Publish all selected GitHub release asset sets concurrently - id: publish_github_assets - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - timeout-minutes: 95 + run: | + bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" "$RELEASE_HEAD_SHA" tools/dev/bun.sh tools/release/verify-publication-candidate.mts \ + --products-json "$PRODUCTS_JSON" --head-ref "$RELEASE_HEAD_SHA" \ + --github-output "$RUNNER_TEMP/bootstrap-release-identity" + release_sha="$(sed -n 's/^release_sha=//p' "$RUNNER_TEMP/bootstrap-release-identity")" + tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mts \ + assert-markable --release-sha "$release_sha" --base main + - name: Resolve selected bootstrap authentication needs + id: registry_needs + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} env: - GITHUB_RELEASE_ASSET_UPLOAD_REPORT_PATH: ${{ runner.temp }}/oliphaunt-github-release-asset-upload-report.json - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: tools/dev/bun.sh tools/release/release-publish.mjs publish --step github-release-assets --products-json "${PRODUCTS_JSON}" --head-ref "$RELEASE_HEAD_SHA" --publication-lock "$PUBLICATION_LOCK_PATH" - - - name: Resolve exact selected extension attestation subjects - id: extension_attestation_subjects - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && steps.release_plan.outputs.has_extension_products == 'true' }} + run: bun .github/scripts/selected-registry-needs.mts + - name: Resolve registry identity bootstrap scope + id: bootstrap_scope + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} env: - EXTENSION_PRODUCTS_JSON: ${{ steps.release_plan.outputs.extension_products_json }} - run: | - tools/dev/bun.sh tools/release/locked-attestation-subjects.mjs \ - --publication-lock "$PUBLICATION_LOCK_PATH" \ - --products-json "$EXTENSION_PRODUCTS_JSON" \ - --github-output "$GITHUB_OUTPUT" - - - name: Reserve extension provenance write (batch 1) - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && steps.release_plan.outputs.has_extension_products == 'true' && steps.extension_attestation_subjects.outputs.nonempty_1 == 'true' }} - run: | - tools/dev/bun.sh tools/release/github-content-write-pacer.mjs reserve --label "extension provenance batch 1" - tools/dev/bun.sh tools/release/github-core-request-journal.mjs reserve --label "extension provenance batch 1 API attempt" - - - name: Attest extension release assets (batch 1) - id: attest_extensions_1 - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && steps.release_plan.outputs.has_extension_products == 'true' && steps.extension_attestation_subjects.outputs.nonempty_1 == 'true' }} - timeout-minutes: 5 - uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 - with: - subject-path: ${{ steps.extension_attestation_subjects.outputs.paths_1 }} - - - name: Reserve extension provenance write (batch 2) - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && steps.release_plan.outputs.has_extension_products == 'true' && steps.extension_attestation_subjects.outputs.nonempty_2 == 'true' }} + NEEDS_CARGO: ${{ steps.registry_needs.outputs.needs_cargo }} + NEEDS_NPM: ${{ steps.registry_needs.outputs.needs_npm }} run: | - tools/dev/bun.sh tools/release/github-content-write-pacer.mjs reserve --label "extension provenance batch 2" - tools/dev/bun.sh tools/release/github-core-request-journal.mjs reserve --label "extension provenance batch 2 API attempt" - - - name: Attest extension release assets (batch 2) - id: attest_extensions_2 - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && steps.release_plan.outputs.has_extension_products == 'true' && steps.extension_attestation_subjects.outputs.nonempty_2 == 'true' }} - timeout-minutes: 5 - uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 + required=false + if [[ "$NEEDS_CARGO" == true || "$NEEDS_NPM" == true ]]; then + required=true + fi + echo "required=$required" >> "$GITHUB_OUTPUT" + - name: No registry identities require bootstrap + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.bootstrap_scope.outputs.required != 'true' }} + run: echo 'The selected release has no Cargo or npm identities; bootstrap is a no-op.' + - name: Set up pinned npm publisher + id: setup_bootstrap_npm + if: ${{ steps.bootstrap_scope.outputs.required == 'true' && steps.registry_needs.outputs.needs_npm == 'true' }} + timeout-minutes: 3 + uses: ./.github/actions/setup-npm-publisher with: - subject-path: ${{ steps.extension_attestation_subjects.outputs.paths_2 }} - - - name: Reserve liboliphaunt attestation content write - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-native') }} + npm-version: ${{ env.NPM_VERSION }} + - name: Preflight selected product tag and release collisions + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} run: | - tools/dev/bun.sh tools/release/github-content-write-pacer.mjs reserve --label "liboliphaunt native attestation" - tools/dev/bun.sh tools/release/github-core-request-journal.mjs reserve --label "liboliphaunt native attestation API attempt" - - - name: Attest liboliphaunt release assets - id: attest_liboliphaunt_native - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-native') }} - timeout-minutes: 5 - uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 + bash tools/release/verify-product-tags.sh \ + --products-json "$PRODUCTS_JSON" \ + --target "$RELEASE_HEAD_SHA" \ + --allow-missing + bun .github/scripts/manage-release-drafts.mts preflight \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" + - name: Download the frozen candidate from preparation + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with: - subject-path: | - target/liboliphaunt/release-assets/*.tar.gz - target/liboliphaunt/release-assets/*.tar.zst - target/liboliphaunt/release-assets/*.zip - target/liboliphaunt/release-assets/*.tsv - target/liboliphaunt/release-assets/*.sha256 - target/extension-artifacts/liboliphaunt-native/oliphaunt-extension-contrib-pg18/release-assets/* - - - name: Create fresh SwiftPM tag token - id: swift_tag_token - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-swift') }} - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 - with: *release_tag_app - - - name: Publish Swift SDK GitHub release and SwiftPM tags - id: publish_swift_source_tag - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-swift') }} - timeout-minutes: 6 + artifact-ids: ${{ format('{0},{1}', needs.prepare-candidate.outputs.lock_artifact_id, needs.prepare-candidate.outputs.candidate_artifact_id) }} + path: ${{ runner.temp }}/approved-bootstrap + merge-multiple: true + - name: Verify and install approved publication candidate + id: verify_bootstrap_candidate + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} env: - GH_TOKEN: ${{ steps.swift_tag_token.outputs.token }} - run: tools/dev/bun.sh tools/release/release-publish.mjs publish --product oliphaunt-swift --step github-release --head-ref "$RELEASE_HEAD_SHA" --publication-lock "$PUBLICATION_LOCK_PATH" - - - name: Reserve broker attestation content write - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-broker') }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + APPROVAL_RUN_ID: ${{ inputs.approval_run_id || github.run_id }} run: | - tools/dev/bun.sh tools/release/github-content-write-pacer.mjs reserve --label "broker attestation" - tools/dev/bun.sh tools/release/github-core-request-journal.mjs reserve --label "broker attestation API attempt" - - - name: Attest broker release assets - id: attest_broker - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-broker') }} - timeout-minutes: 5 - uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 - with: - subject-path: | - target/oliphaunt-broker/release-assets/*.tar.gz - target/oliphaunt-broker/release-assets/*.zip - target/oliphaunt-broker/release-assets/*.sha256 - - - name: Reserve Node direct attestation content write - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-node-direct') }} - run: | - tools/dev/bun.sh tools/release/github-content-write-pacer.mjs reserve --label "Node direct attestation" - tools/dev/bun.sh tools/release/github-core-request-journal.mjs reserve --label "Node direct attestation API attempt" - - - name: Attest Node direct release assets - id: attest_node_direct - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-node-direct') }} - timeout-minutes: 5 - uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 - with: - subject-path: | - target/oliphaunt-node-direct/release-assets/*.tar.gz - target/oliphaunt-node-direct/release-assets/*.zip - target/oliphaunt-node-direct/release-assets/*.sha256 - - - name: Reserve WASIX Node-API attestation content write - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-wasix-napi') }} - run: | - tools/dev/bun.sh tools/release/github-content-write-pacer.mjs reserve --label "WASIX Node-API attestation" - tools/dev/bun.sh tools/release/github-core-request-journal.mjs reserve --label "WASIX Node-API attestation API attempt" - - - name: Attest WASIX Node-API release assets - id: attest_wasix_napi - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-wasix-napi') }} - timeout-minutes: 5 - uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 - with: - subject-path: | - target/oliphaunt-wasix-napi/release-assets/*.tar.gz - target/oliphaunt-wasix-napi/release-assets/*.zip - target/oliphaunt-wasix-napi/release-assets/*.sha256 - - - name: Reserve WASIX attestation content write - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix') }} - run: | - tools/dev/bun.sh tools/release/github-content-write-pacer.mjs reserve --label "WASIX attestation" - tools/dev/bun.sh tools/release/github-core-request-journal.mjs reserve --label "WASIX attestation API attempt" - - - name: Attest WASIX release assets - id: attest_wasix - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix') }} - timeout-minutes: 5 - uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 - with: - subject-path: | - target/oliphaunt-wasix/release-assets/*.tar.zst - target/oliphaunt-wasix/release-assets/*.sha256 - target/extension-artifacts/liboliphaunt-wasix/oliphaunt-extension-contrib-pg18/release-assets/* - - - name: Reserve WASIX postmaster attestation content write - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix-postmaster') }} - run: | - tools/dev/bun.sh tools/release/github-content-write-pacer.mjs reserve --label "WASIX postmaster attestation" - tools/dev/bun.sh tools/release/github-core-request-journal.mjs reserve --label "WASIX postmaster attestation API attempt" - - - name: Attest WASIX postmaster release assets - id: attest_wasix_postmaster - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix-postmaster') }} - timeout-minutes: 5 - uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 - with: - subject-path: | - target/oliphaunt-wasix-postmaster/release-assets/*.tar.zst - target/oliphaunt-wasix-postmaster/release-assets/*.sha256 - - - name: Freeze exact GitHub release asset and attestation evidence - id: freeze_github_evidence - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - timeout-minutes: 10 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - EXTENSIONS_ATTESTATION_BUNDLE_1: ${{ steps.attest_extensions_1.outputs.bundle-path }} - EXTENSIONS_ATTESTATION_BUNDLE_2: ${{ steps.attest_extensions_2.outputs.bundle-path }} - LIBOLIPHAUNT_NATIVE_ATTESTATION_BUNDLE: ${{ steps.attest_liboliphaunt_native.outputs.bundle-path }} - BROKER_ATTESTATION_BUNDLE: ${{ steps.attest_broker.outputs.bundle-path }} - NODE_DIRECT_ATTESTATION_BUNDLE: ${{ steps.attest_node_direct.outputs.bundle-path }} - WASIX_NAPI_ATTESTATION_BUNDLE: ${{ steps.attest_wasix_napi.outputs.bundle-path }} - WASIX_ATTESTATION_BUNDLE: ${{ steps.attest_wasix.outputs.bundle-path }} - WASIX_POSTMASTER_ATTESTATION_BUNDLE: ${{ steps.attest_wasix_postmaster.outputs.bundle-path }} - run: | - bundle_args=() - for bundle in \ - "$EXTENSIONS_ATTESTATION_BUNDLE_1" \ - "$EXTENSIONS_ATTESTATION_BUNDLE_2" \ - "$LIBOLIPHAUNT_NATIVE_ATTESTATION_BUNDLE" \ - "$BROKER_ATTESTATION_BUNDLE" \ - "$NODE_DIRECT_ATTESTATION_BUNDLE" \ - "$WASIX_NAPI_ATTESTATION_BUNDLE" \ - "$WASIX_ATTESTATION_BUNDLE" \ - "$WASIX_POSTMASTER_ATTESTATION_BUNDLE" - do - if [[ -n "$bundle" ]]; then - bundle_args+=(--attestation-bundle "$bundle") - fi - done - tools/dev/bun.sh tools/release/verify_github_release_attestations.mjs pre-mutation \ - --publication-lock "$PUBLICATION_LOCK_PATH" \ + if [[ -e "$GITHUB_WORKSPACE/target" ]]; then + echo 'publication candidate installation requires an absent workspace target directory' >&2 + exit 1 + fi + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/bootstrap-publication-capsule.mts verify-extract \ + --transport "$RUNNER_TEMP/approved-bootstrap/oliphaunt-publication-candidate.tar" \ + --approved-lock "$RUNNER_TEMP/approved-bootstrap/publication-lock.json" \ --products-json "$PRODUCTS_JSON" \ --head-ref "$RELEASE_HEAD_SHA" \ - --output target/release/github-release-attestation-receipt.json \ - "${bundle_args[@]}" - - - name: Open registry publication window - id: registry_publication_window - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} + --approval-run-id "$APPROVAL_RUN_ID" \ + --workspace-root "$GITHUB_WORKSPACE" + - name: Verify external lock equals installed candidate lock + id: verify_bootstrap_lock + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} run: | - for name in RELEASE_JOB_HARD_DEADLINE_EPOCH POST_REGISTRY_RESERVE_SECONDS; do - if [[ ! "${!name:-}" =~ ^[1-9][0-9]*$ ]]; then - echo "$name must be a positive integer" >&2 - exit 1 - fi - done - mutation_deadline=$(( RELEASE_JOB_HARD_DEADLINE_EPOCH - POST_REGISTRY_RESERVE_SECONDS )) - if (( $(date +%s) >= mutation_deadline )); then - echo 'Not enough time remains for registry publication and final verification; rerun this idempotent release.' >&2 + if ! cmp -s "$RUNNER_TEMP/approved-bootstrap/publication-lock.json" "$PUBLICATION_LOCK_PATH"; then + echo 'installed candidate lock differs from the separately downloaded approved publication lock' >&2 exit 1 fi - echo "REGISTRY_MUTATION_DEADLINE_EPOCH=$mutation_deadline" >> "$GITHUB_ENV" - - - name: Publish and reconcile every exact-lock registry carrier - id: publish_registries - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - timeout-minutes: 240 + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/publication-lock.mts verify \ + --lock "$PUBLICATION_LOCK_PATH" \ + --head-ref "$RELEASE_HEAD_SHA" + - name: Restore prior bootstrap checkpoint chain + id: restore_bootstrap_checkpoint + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + run: bun .github/scripts/download-bootstrap-ledger.mts + - name: Classify exact bootstrap credential needs + id: bootstrap_credential_needs + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + env: PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} - ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} - ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} - ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MAVEN_GPG_KEY_ID }} - ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + REGISTRY_MUTATION_DEADLINE_EPOCH: ${{ env.REGISTRY_JOB_HARD_DEADLINE_EPOCH }} + run: bun .github/scripts/bootstrap-registry-identities.mts --credential-needs + - name: Require bootstrap credentials before mutation + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + env: + CRATES_IO_BOOTSTRAP_TOKEN: ${{ secrets.CRATES_IO_BOOTSTRAP_TOKEN }} + NPM_BOOTSTRAP_TOKEN: ${{ secrets.NPM_BOOTSTRAP_TOKEN }} + NEEDS_CARGO_TOKEN: ${{ steps.bootstrap_credential_needs.outputs.needs_cargo_token }} + NEEDS_NPM_TOKEN: ${{ steps.bootstrap_credential_needs.outputs.needs_npm_token }} run: | - tools/dev/bun.sh tools/release/release-publish.mjs publish \ - --registry-plan \ - --products-json "$PRODUCTS_JSON" \ - --head-ref "$RELEASE_HEAD_SHA" \ - --publication-lock "$PUBLICATION_LOCK_PATH" - - - name: Verify published release - id: verify_published_release - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - timeout-minutes: 8 + if [[ "$NEEDS_CARGO_TOKEN" == true && -z "$CRATES_IO_BOOTSTRAP_TOKEN" ]]; then + echo 'approved candidate contains absent Cargo names but CRATES_IO_BOOTSTRAP_TOKEN is unavailable' >&2 + exit 1 + fi + if [[ "$NEEDS_NPM_TOKEN" == true && -z "$NPM_BOOTSTRAP_TOKEN" ]]; then + echo 'approved candidate contains absent npm names but NPM_BOOTSTRAP_TOKEN is unavailable' >&2 + exit 1 + fi + - name: Create bootstrap transport tag token + id: bootstrap_tag_token + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 + with: &release_tag_app + client-id: ${{ secrets.RELEASE_TAG_APP_CLIENT_ID }} + private-key: ${{ secrets.RELEASE_TAG_APP_PRIVATE_KEY }} + owner: f0rr0 + repositories: oliphaunt + permission-contents: write + permission-workflows: write + - name: Ensure exact immutable release transport ref + id: ensure_bootstrap_transport_ref + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + timeout-minutes: 3 env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + GH_TOKEN: ${{ steps.bootstrap_tag_token.outputs.token }} + GH_REPO: ${{ github.repository }} + RELEASE_OPERATION: publish-bootstrap + RELEASE_TRANSPORT_CONTENT_WRITE_ADMISSION: isolated-bootstrap + run: bash tools/release/publication-controller.sh "$RELEASE_HEAD_SHA" "$GITHUB_SHA" bun .github/scripts/release-transport-ref.mts ensure "$RELEASE_HEAD_SHA" + - name: Start bounded bootstrap mutation window + id: bootstrap_mutation_deadline + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} run: | - gh auth setup-git - git fetch --force --tags origin - tools/dev/bun.sh tools/release/release-verify.mjs \ - --products-json "$PRODUCTS_JSON" \ - --head-ref "$RELEASE_HEAD_SHA" \ - --publication-lock "$PUBLICATION_LOCK_PATH" \ - --registry-receipts target/release/registry-integrity-receipts.json \ - --github-release-receipt target/release/github-release-attestation-receipt.json - - - name: Resolve and install exact public consumer surfaces - id: public_consumer_smoke - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - timeout-minutes: 15 + if [[ ! "$BOOTSTRAP_REGISTRY_MUTATION_WINDOW_SECONDS" =~ ^[1-9][0-9]*$ ]]; then + echo 'BOOTSTRAP_REGISTRY_MUTATION_WINDOW_SECONDS must be a positive integer' >&2 + exit 1 + fi + if [[ ! "$REGISTRY_JOB_HARD_DEADLINE_EPOCH" =~ ^[1-9][0-9]*$ ]]; then + echo 'REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp' >&2 + exit 1 + fi + now=$(date +%s) + window_deadline=$(( now + BOOTSTRAP_REGISTRY_MUTATION_WINDOW_SECONDS )) + deadline=$window_deadline + if (( REGISTRY_JOB_HARD_DEADLINE_EPOCH < deadline )); then + deadline=$REGISTRY_JOB_HARD_DEADLINE_EPOCH + fi + echo "REGISTRY_MUTATION_DEADLINE_EPOCH=$deadline" >> "$GITHUB_ENV" + echo "Bootstrap registry mutation must stop before Unix time $deadline." + - name: Configure npm identity-bootstrap authentication + id: configure_bootstrap_npm_auth + if: ${{ steps.bootstrap_scope.outputs.required == 'true' && steps.bootstrap_credential_needs.outputs.needs_npm_token == 'true' }} env: + NPM_BOOTSTRAP_TOKEN: ${{ secrets.NPM_BOOTSTRAP_TOKEN }} + run: | + umask 077 + npmrc="$RUNNER_TEMP/oliphaunt-bootstrap.npmrc" + printf '//registry.npmjs.org/:_authToken=%s\n' "$NPM_BOOTSTRAP_TOKEN" > "$npmrc" + - name: Bootstrap missing Cargo and npm identities + id: bootstrap_registry_identities + if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + env: + CARGO_REGISTRY_TOKEN: ${{ steps.bootstrap_credential_needs.outputs.needs_cargo_token == 'true' && secrets.CRATES_IO_BOOTSTRAP_TOKEN || '' }} + NPM_CONFIG_USERCONFIG: ${{ runner.temp }}/oliphaunt-bootstrap.npmrc PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + REGISTRY_BOOTSTRAP_CARGO_SECONDS_PER_CARRIER: ${{ vars.REGISTRY_BOOTSTRAP_CARGO_SECONDS_PER_CARRIER || '30' }} + REGISTRY_BOOTSTRAP_NPM_SECONDS_PER_CARRIER: ${{ vars.REGISTRY_BOOTSTRAP_NPM_SECONDS_PER_CARRIER || '30' }} + REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_PER_CARRIER: ${{ vars.REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_PER_CARRIER || '6' }} + REGISTRY_BOOTSTRAP_RESERVE_SECONDS: ${{ vars.REGISTRY_BOOTSTRAP_RESERVE_SECONDS || '600' }} + run: bash .github/scripts/bootstrap-registry-identities.sh + - name: Require a typed bootstrap execution decision + id: require_bootstrap_execution_decision + if: ${{ steps.bootstrap_registry_identities.outcome == 'success' }} + timeout-minutes: 1 + env: + COMPLETE: ${{ steps.bootstrap_registry_identities.outputs.complete }} + DEFERRED: ${{ steps.bootstrap_registry_identities.outputs.deferred }} + DEFERRAL_MODE: ${{ steps.bootstrap_registry_identities.outputs.deferral_mode }} + PROGRESS_COUNT: ${{ steps.bootstrap_registry_identities.outputs.progress_count }} + REMAINING_COUNT: ${{ steps.bootstrap_registry_identities.outputs.remaining_count }} + NOT_BEFORE_EPOCH: ${{ steps.bootstrap_registry_identities.outputs.not_before_epoch }} run: | - tools/dev/bun.sh tools/release/public-consumer-smoke.mjs \ - --publication-lock "$PUBLICATION_LOCK_PATH" \ - --products-json "$PRODUCTS_JSON" \ - --registry-receipts target/release/registry-integrity-receipts.json \ - --github-release-receipt target/release/github-release-attestation-receipt.json \ - --output target/release/public-consumer-smoke.json - - - name: Preserve public consumer evidence - id: preserve_consumer_evidence - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - timeout-minutes: 2 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a - with: - name: public-consumer-evidence-${{ github.sha }} - path: target/release/public-consumer-smoke.json - if-no-files-found: error - overwrite: true - retention-days: 90 - - - name: Reverify exact publication lock before promotion - id: reverify_publication_lock - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - timeout-minutes: 2 + if [[ "$COMPLETE" == true && "$DEFERRED" == false ]]; then + if [[ -n "$DEFERRAL_MODE" || "$REMAINING_COUNT" != 0 ]]; then + echo 'complete bootstrap result retains a deferral mode or remaining carriers' >&2 + exit 1 + fi + elif [[ "$COMPLETE" == false && "$DEFERRED" == true ]]; then + if [[ ! "$REMAINING_COUNT" =~ ^[1-9][0-9]*$ || ! "$NOT_BEFORE_EPOCH" =~ ^[1-9][0-9]*$ ]]; then + echo 'deferred bootstrap result requires remaining work and a positive not-before time' >&2 + exit 1 + fi + if [[ "$DEFERRAL_MODE" == progress ]]; then + if [[ ! "$PROGRESS_COUNT" =~ ^[1-9][0-9]*$ ]]; then + echo 'bootstrap progress deferral requires nonzero durable progress' >&2 + exit 1 + fi + elif [[ "$DEFERRAL_MODE" == rate-limit ]]; then + if [[ "$PROGRESS_COUNT" != 0 ]]; then + echo 'bootstrap rate-limit deferral cannot claim durable progress' >&2 + exit 1 + fi + elif [[ "$DEFERRAL_MODE" == pre-mutation-capacity ]]; then + if [[ "$PROGRESS_COUNT" != 0 ]]; then + echo 'bootstrap pre-mutation capacity deferral cannot claim durable progress' >&2 + exit 1 + fi + elif [[ "$DEFERRAL_MODE" == pre-mutation-deadline ]]; then + if [[ "$PROGRESS_COUNT" != 0 ]]; then + echo 'bootstrap pre-mutation deadline deferral cannot claim durable progress' >&2 + exit 1 + fi + else + echo 'deferred bootstrap result has an unsupported deferral mode' >&2 + exit 1 + fi + else + echo 'bootstrap publisher must emit exactly one of complete or deferred' >&2 + exit 1 + fi + { + echo "complete=$COMPLETE" + echo "deferred=$DEFERRED" + echo "deferral_mode=$DEFERRAL_MODE" + echo "progress_count=$PROGRESS_COUNT" + echo "remaining_count=$REMAINING_COUNT" + echo "not_before_epoch=$NOT_BEFORE_EPOCH" + } >> "$GITHUB_OUTPUT" + - name: Record bootstrap identity result + if: ${{ steps.require_bootstrap_execution_decision.outputs.complete == 'true' }} run: | - tools/dev/bun.sh tools/release/publication-lock.mjs \ - verify \ - --lock "$PUBLICATION_LOCK_PATH" \ - --head-ref "$RELEASE_HEAD_SHA" - - - name: Preserve release evidence - id: preserve_release_evidence - if: ${{ always() && inputs.operation == 'publish' && steps.release_plan.outputs.has_release_changes == 'true' }} - continue-on-error: true - timeout-minutes: 3 + lock_sha256="$(sha256sum "$PUBLICATION_LOCK_PATH" | awk '{print $1}')" + { + echo '## Registry identity bootstrap complete' + echo + echo "- Release commit: \`$RELEASE_HEAD_SHA\`" + echo "- Publication lock SHA-256: \`$lock_sha256\`" + echo '- Scope: selected Cargo and npm identities only' + echo '- Publication continues automatically after this job. Configure trusted publishers before the next version, then revoke bootstrap tokens.' + } >> "$GITHUB_STEP_SUMMARY" + - name: Remove bootstrap npm credentials + id: remove_bootstrap_credentials + if: ${{ always() }} + run: rm -f "$RUNNER_TEMP/oliphaunt-bootstrap.npmrc" + - name: Upload bootstrap identity ledger + id: preserve_bootstrap_ledger + if: ${{ always() }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: - name: release-evidence-${{ github.sha }} - path: | - target/release/publication-lock.json - target/release/registry-integrity-receipts.json - target/release/github-release-attestation-receipt.json - target/release/public-consumer-smoke.json - ${{ runner.temp }}/oliphaunt-github-release-asset-upload-report.json + name: oliphaunt-bootstrap-ledger + path: target/release/bootstrap-ledger if-no-files-found: warn - include-hidden-files: true overwrite: true retention-days: 90 - - - name: Promote verified GitHub release drafts - id: promote_github_releases - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.operation == 'publish' }} - timeout-minutes: 16 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: | - tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mjs \ - assert-markable \ - --release-sha "${{ steps.verify_publication_candidate.outputs.release_sha }}" \ - --base main - bun .github/scripts/manage-release-drafts.mjs promote \ - --products-json "$PRODUCTS_JSON" \ - --head-ref "$RELEASE_HEAD_SHA" - tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mjs \ - mark-tagged \ - --release-sha "${{ steps.verify_publication_candidate.outputs.release_sha }}" \ - --base main - + - name: Stop incomplete bootstrap for manual rerun + if: ${{ steps.require_bootstrap_execution_decision.outputs.deferred == 'true' }} + env: + DEFERRAL_MODE: ${{ steps.require_bootstrap_execution_decision.outputs.deferral_mode }} + NOT_BEFORE_EPOCH: ${{ steps.require_bootstrap_execution_decision.outputs.not_before_epoch }} + REMAINING_COUNT: ${{ steps.require_bootstrap_execution_decision.outputs.remaining_count }} + APPROVAL_RUN_ID: ${{ inputs.approval_run_id || github.run_id }} + run: | + { + echo '## Registry identity bootstrap incomplete—rerun required' + echo + echo "- Release commit: \`$RELEASE_HEAD_SHA\`" + echo "- Approved dry-run: \`$APPROVAL_RUN_ID\`" + echo "- Remaining identities: \`$REMAINING_COUNT\`" + echo "- Reason: \`$DEFERRAL_MODE\`" + echo "- Do not rerun before Unix time: \`$NOT_BEFORE_EPOCH\`" + echo "- Resume this exact SHA and approval: \`gh run rerun $GITHUB_RUN_ID --failed\`" + } >> "$GITHUB_STEP_SUMMARY" + echo "Bootstrap is incomplete; rerun failed jobs for workflow run $GITHUB_RUN_ID after $NOT_BEFORE_EPOCH." >&2 + exit 1 + outputs: + ledger_artifact_id: ${{ steps.preserve_bootstrap_ledger.outputs.artifact-id }} publish: name: Publish release needs: - - validate-inputs + - prepare-candidate + - publish-bootstrap runs-on: macos-26 timeout-minutes: 360 - if: ${{ inputs.operation == 'publish' }} + if: ${{ always() && !cancelled() && inputs.operation == 'publish' && needs.prepare-candidate.result == 'success' && needs.prepare-candidate.outputs.has_release_changes == 'true' && (needs.publish-bootstrap.result == 'success' || needs.publish-bootstrap.result == 'skipped') }} environment: release-publish + outputs: + promoted: ${{ steps.promote_github_releases.outcome == 'success' }} permissions: actions: read artifact-metadata: write @@ -1501,24 +1204,9 @@ jobs: contents: write id-token: write pull-requests: write - steps: *release_candidate_steps - - publish-bootstrap: - name: Bootstrap registry identities - needs: - - validate-inputs - runs-on: ubuntu-24.04 - timeout-minutes: 360 - if: ${{ inputs.operation == 'publish-bootstrap' }} - environment: release-bootstrap - permissions: - actions: read - contents: write - id-token: write - pull-requests: read steps: - - name: Record bounded bootstrap job deadline - id: bootstrap_job_deadline + - name: Record release deadline + id: release_job_deadline run: | if [[ ! "$RELEASE_JOB_HARD_WINDOW_SECONDS" =~ ^[1-9][0-9]*$ ]]; then echo 'RELEASE_JOB_HARD_WINDOW_SECONDS must be a positive integer' >&2 @@ -1526,375 +1214,634 @@ jobs: fi hard_deadline=$(( $(date +%s) + RELEASE_JOB_HARD_WINDOW_SECONDS )) { - echo "REGISTRY_JOB_HARD_DEADLINE_EPOCH=$hard_deadline" + echo "RELEASE_JOB_HARD_DEADLINE_EPOCH=$hard_deadline" + echo "OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH=$RUNNER_TEMP/oliphaunt-github-content-write-pacer.json" + echo "OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH=$RUNNER_TEMP/oliphaunt-github-core-request-journal.json" + echo "OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL=true" echo "OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR=$RUNNER_TEMP/oliphaunt-github-run-snapshots" } >> "$GITHUB_ENV" - echo "The bootstrap job must stop registry work before Unix time $hard_deadline." - + echo "The release must finish before Unix time $hard_deadline." - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: fetch-depth: 0 persist-credentials: false - - - name: Resolve exact release commit + - name: Resolve release commit id: release_head timeout-minutes: 1 env: INPUT_RELEASE_COMMIT: ${{ inputs.release_commit }} run: .github/scripts/resolve-release-head.sh - - name: Set up Moon uses: ./.github/actions/setup-moon with: - install-workspace: "false" - + install-workspace: "true" - name: Require checked publishing code env: GH_TOKEN: ${{ github.token }} GH_REPO: ${{ github.repository }} run: bash .github/scripts/require-workflow-success.sh CI "$GITHUB_SHA" 0 --job Required - - - name: Plan bootstrap releases + - name: Set up Rust + uses: ./.github/actions/setup-rust + - name: Plan product releases id: release_plan run: | - tools/dev/bun.sh tools/release/release_plan.mjs \ - --from-product-tags \ - --include-current-tags \ - --head-ref "$RELEASE_HEAD_SHA" \ - --format github-output \ - >> "$GITHUB_OUTPUT" - + release_plan_args=( + --from-product-tags + --include-current-tags + --head-ref "$RELEASE_HEAD_SHA" + --format github-output + ) + bash tools/release/release-plan.sh "${release_plan_args[@]}" >> "$GITHUB_OUTPUT" - name: No package release planned if: ${{ steps.release_plan.outputs.has_release_changes != 'true' }} run: echo "No release-affecting product changes were found since the last product tag." - - - name: Prove Release Please PR can complete after bootstrap + - name: Resolve selected registry authentication needs + id: registry_needs + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + env: + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + run: bun .github/scripts/selected-registry-needs.mts + - name: Verify direct-workflow OIDC identity + id: verify_oidc_identity + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + env: + RELEASE_OPERATION: publish + run: bun .github/scripts/verify-github-oidc-identity.mts + - name: Prove pending release identity + id: verify_publication_candidate + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 2 + env: + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + run: | + bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" "$RELEASE_HEAD_SHA" tools/dev/bun.sh tools/release/verify-publication-candidate.mts \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" \ + --github-output "$GITHUB_OUTPUT" + - name: Prove Release Please PR can complete after publication + id: assert_release_please_markable + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 1 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mts \ + assert-markable \ + --release-sha "${{ steps.verify_publication_candidate.outputs.release_sha }}" \ + --base main + - name: Preflight selected product tag and release collisions + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + run: | + gh auth setup-git + bash tools/release/verify-product-tags.sh \ + --products-json "$PRODUCTS_JSON" \ + --target "$RELEASE_HEAD_SHA" \ + --allow-missing + bun .github/scripts/manage-release-drafts.mts preflight \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" + - name: Check release tag App permissions + id: check_release_tag_app + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 + with: *release_tag_app + - name: Check publish environment + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MAVEN_GPG_KEY_ID }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + run: tools/release/check_publish_environment.mts --products-json "${PRODUCTS_JSON}" + - name: Verify external registry ownership and trust links + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + env: + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} + run: bun .github/scripts/verify-external-publish-readiness.mts + - name: Import, sign, and verify Maven credentials before mutation + id: verify_maven_signing + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.registry_needs.outputs.needs_maven == 'true' }} + timeout-minutes: 2 + env: + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MAVEN_GPG_KEY_ID }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + run: bash tools/release/verify-maven-signing-readiness.sh + - name: Download the frozen candidate from preparation + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + artifact-ids: ${{ format('{0},{1}', needs.prepare-candidate.outputs.lock_artifact_id, needs.prepare-candidate.outputs.candidate_artifact_id) }} + path: ${{ runner.temp }}/approved-publication + merge-multiple: true + - name: Verify and install the complete approved candidate + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + env: + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + APPROVAL_RUN_ID: ${{ inputs.approval_run_id || github.run_id }} + run: | + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/bootstrap-publication-capsule.mts verify-extract \ + --transport "$RUNNER_TEMP/approved-publication/oliphaunt-publication-candidate.tar" \ + --approved-lock "$RUNNER_TEMP/approved-publication/publication-lock.json" \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" \ + --approval-run-id "$APPROVAL_RUN_ID" \ + --workspace-root "$GITHUB_WORKSPACE" + - name: Validate product versions and registry state + id: validate_release_registry_state + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + run: | + bash tools/release/release-check-registries.sh \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" + - name: Set up pinned npm publisher + id: setup_github_stage_npm + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.registry_needs.outputs.needs_npm == 'true' }} + timeout-minutes: 3 + uses: ./.github/actions/setup-npm-publisher + with: + npm-version: ${{ env.NPM_VERSION }} + - name: Assemble and sign the exact Maven Central bundle before release mutation + id: preflight_maven_bundle + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.registry_needs.outputs.needs_maven == 'true' }} + timeout-minutes: 15 + env: + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.MAVEN_GPG_KEY_ID }} + ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + run: | + bash tools/release/preflight-maven-central-bundle.sh \ + --publication-lock "$PUBLICATION_LOCK_PATH" \ + --products-json "$PRODUCTS_JSON" \ + --release-commit "$RELEASE_HEAD_SHA" + - name: Prove the exact SwiftPM source tag is remotely collision-free + id: preflight_swift_source_tag + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-swift') }} + timeout-minutes: 2 + run: | + bash tools/release/publish-swiftpm-source-tag.sh --preflight \ + --publication-lock "$PUBLICATION_LOCK_PATH" \ + --release-commit "$RELEASE_HEAD_SHA" + - name: Classify pre-tag registry publication state + id: bootstrap_ledger_state + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && (steps.registry_needs.outputs.needs_cargo == 'true' || steps.registry_needs.outputs.needs_npm == 'true') }} + env: + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + RELEASE_HEAD_SHA: ${{ steps.release_head.outputs.sha }} + run: bash .github/scripts/registry-bootstrap-ledger-state.sh + - name: Download the bootstrap ledger from this run + if: ${{ steps.bootstrap_ledger_state.outputs.needs_ledger == 'true' && needs.publish-bootstrap.outputs.ledger_artifact_id != '' }} + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + artifact-ids: ${{ needs.publish-bootstrap.outputs.ledger_artifact_id }} + path: ${{ env.BOOTSTRAP_LEDGER_PATH }} + - name: Restore completed bootstrap evidence for this candidate + if: ${{ steps.bootstrap_ledger_state.outputs.needs_ledger == 'true' && needs.publish-bootstrap.outputs.ledger_artifact_id == '' }} + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + run: bash .github/scripts/download-completed-bootstrap.sh + - name: Verify immutable bootstrap ledger and registry existence + if: ${{ steps.bootstrap_ledger_state.outputs.needs_ledger == 'true' }} + env: + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + run: | + tools/dev/bun.sh tools/release/bootstrap-ledger.mts verify \ + --lock "$PUBLICATION_LOCK_PATH" \ + --ledger "$BOOTSTRAP_LEDGER_PATH" \ + --products-json "$PRODUCTS_JSON" \ + --require-complete \ + --verify-registries + - name: Upload publication lock audit evidence + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: oliphaunt-publication-lock-${{ inputs.operation }} + path: target/release/publication-lock.json + if-no-files-found: error + overwrite: true + retention-days: 90 + - name: Create release tag token + id: release_tag_token + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 + with: *release_tag_app + - name: Reserve release transport content write + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 3 + run: | + tools/dev/bun.sh tools/release/github-content-write-pacer.mts reserve \ + --label "release transport tag" + - name: Ensure exact immutable release transport ref + id: ensure_release_transport_ref + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 3 + env: + GH_TOKEN: ${{ steps.release_tag_token.outputs.token }} + GH_REPO: ${{ github.repository }} + RELEASE_OPERATION: publish + RELEASE_TRANSPORT_CONTENT_WRITE_ADMISSION: pre-reserved + run: bash tools/release/publication-controller.sh "$RELEASE_HEAD_SHA" "$GITHUB_SHA" bun .github/scripts/release-transport-ref.mts ensure "$RELEASE_HEAD_SHA" + - name: Stage exact-SHA product tags and draft releases + id: stage_github_releases + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 31 + env: + GH_TOKEN: ${{ steps.release_tag_token.outputs.token }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + run: | + bun .github/scripts/manage-release-drafts.mts stage \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" \ + --state staged + - name: Verify exact product tags + id: verify_product_tags + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 5 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + run: bash tools/release/verify-product-tags.sh --products-json "${PRODUCTS_JSON}" --target "$RELEASE_HEAD_SHA" + - name: Verify exact-SHA GitHub release staging + id: verify_github_staging if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 5 env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: | - tools/dev/bun.sh tools/release/verify-publication-candidate.mjs \ - --products-json "$PRODUCTS_JSON" --head-ref "$RELEASE_HEAD_SHA" \ - --github-output "$RUNNER_TEMP/bootstrap-release-identity" - release_sha="$(sed -n 's/^release_sha=//p' "$RUNNER_TEMP/bootstrap-release-identity")" - tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mjs \ - assert-markable --release-sha "$release_sha" --base main - - - name: Resolve selected bootstrap authentication needs - id: registry_needs + run: bun .github/scripts/manage-release-drafts.mts verify --products-json "$PRODUCTS_JSON" --head-ref "$RELEASE_HEAD_SHA" --state staged + - name: Publish all selected GitHub release asset sets concurrently + id: publish_github_assets if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 95 env: + GITHUB_RELEASE_ASSET_UPLOAD_REPORT_PATH: ${{ runner.temp }}/oliphaunt-github-release-asset-upload-report.json + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: bun .github/scripts/selected-registry-needs.mjs - - - name: Resolve registry identity bootstrap scope - id: bootstrap_scope - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + run: bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/release-publish.mts publish --step github-release-assets --products-json "${PRODUCTS_JSON}" --head-ref "$RELEASE_HEAD_SHA" --publication-lock "$PUBLICATION_LOCK_PATH" + - name: Resolve exact selected extension attestation subjects + id: extension_attestation_subjects + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.release_plan.outputs.has_extension_products == 'true' }} env: - NEEDS_CARGO: ${{ steps.registry_needs.outputs.needs_cargo }} - NEEDS_NPM: ${{ steps.registry_needs.outputs.needs_npm }} + EXTENSION_PRODUCTS_JSON: ${{ steps.release_plan.outputs.extension_products_json }} run: | - required=false - if [[ "$NEEDS_CARGO" == true || "$NEEDS_NPM" == true ]]; then - required=true - fi - echo "required=$required" >> "$GITHUB_OUTPUT" - - - name: No registry identities require bootstrap - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.bootstrap_scope.outputs.required != 'true' }} - run: echo 'The selected release has no Cargo or npm identities; bootstrap is a no-op.' - - - name: Set up pinned npm publisher - id: setup_bootstrap_npm - if: ${{ steps.bootstrap_scope.outputs.required == 'true' && steps.registry_needs.outputs.needs_npm == 'true' }} - timeout-minutes: 3 - uses: ./.github/actions/setup-npm-publisher + tools/dev/bun.sh tools/release/locked-attestation-subjects.mts \ + --publication-lock "$PUBLICATION_LOCK_PATH" \ + --products-json "$EXTENSION_PRODUCTS_JSON" \ + --github-output "$GITHUB_OUTPUT" + - name: Reserve extension provenance write (batch 1) + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.release_plan.outputs.has_extension_products == 'true' && steps.extension_attestation_subjects.outputs.nonempty_1 == 'true' }} + run: | + tools/dev/bun.sh tools/release/github-content-write-pacer.mts reserve --label "extension provenance batch 1" + tools/dev/bun.sh tools/release/github-core-request-journal.mts reserve --label "extension provenance batch 1 API attempt" + - name: Attest extension release assets (batch 1) + id: attest_extensions_1 + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.release_plan.outputs.has_extension_products == 'true' && steps.extension_attestation_subjects.outputs.nonempty_1 == 'true' }} + timeout-minutes: 5 + uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 with: - npm-version: ${{ env.NPM_VERSION }} - - - name: Preflight selected product tag and release collisions - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + subject-path: ${{ steps.extension_attestation_subjects.outputs.paths_1 }} + - name: Reserve extension provenance write (batch 2) + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.release_plan.outputs.has_extension_products == 'true' && steps.extension_attestation_subjects.outputs.nonempty_2 == 'true' }} run: | - tools/dev/bun.sh tools/release/verify_product_tags.mjs \ - --products-json "$PRODUCTS_JSON" \ - --target "$RELEASE_HEAD_SHA" \ - --allow-missing - bun .github/scripts/manage-release-drafts.mjs preflight \ - --products-json "$PRODUCTS_JSON" \ - --head-ref "$RELEASE_HEAD_SHA" - - - name: Require the explicitly approved dry-run candidate - id: approved_candidate - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - APPROVAL_RUN_ID: ${{ inputs.approval_run_id }} + tools/dev/bun.sh tools/release/github-content-write-pacer.mts reserve --label "extension provenance batch 2" + tools/dev/bun.sh tools/release/github-core-request-journal.mts reserve --label "extension provenance batch 2 API attempt" + - name: Attest extension release assets (batch 2) + id: attest_extensions_2 + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && steps.release_plan.outputs.has_extension_products == 'true' && steps.extension_attestation_subjects.outputs.nonempty_2 == 'true' }} + timeout-minutes: 5 + uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 + with: + subject-path: ${{ steps.extension_attestation_subjects.outputs.paths_2 }} + - name: Reserve liboliphaunt attestation content write + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-native') }} run: | - approved_artifacts=( - --artifact oliphaunt-publication-lock - --artifact oliphaunt-publication-candidate - ) - bash .github/scripts/require-workflow-success.sh \ - Release \ - "$RELEASE_HEAD_SHA" \ - 0 \ - --run-id "$APPROVAL_RUN_ID" \ - --event workflow_dispatch \ - "${approved_artifacts[@]}" - - - name: Download approved lock and candidate from one dry-run - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + tools/dev/bun.sh tools/release/github-content-write-pacer.mts reserve --label "liboliphaunt native attestation" + tools/dev/bun.sh tools/release/github-core-request-journal.mts reserve --label "liboliphaunt native attestation API attempt" + - name: Attest liboliphaunt release assets + id: attest_liboliphaunt_native + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-native') }} + timeout-minutes: 5 + uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 + with: + subject-path: | + target/liboliphaunt/release-assets/*.tar.gz + target/liboliphaunt/release-assets/*.tar.zst + target/liboliphaunt/release-assets/*.zip + target/liboliphaunt/release-assets/*.tsv + target/liboliphaunt/release-assets/*.sha256 + target/extension-artifacts/liboliphaunt-native/oliphaunt-extension-contrib-pg18/release-assets/* + - name: Create fresh SwiftPM tag token + id: swift_tag_token + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-swift') }} + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 + with: *release_tag_app + - name: Publish Swift SDK GitHub release and SwiftPM tags + id: publish_swift_source_tag + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-swift') }} + timeout-minutes: 6 env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - DRY_RUN_ID: ${{ steps.approved_candidate.outputs.run_id }} - APPROVED_ARTIFACT_METADATA_JSON: ${{ steps.approved_candidate.outputs.artifact_metadata_json }} + GH_TOKEN: ${{ steps.swift_tag_token.outputs.token }} + run: bash tools/release/publish-swiftpm-source-tag.sh --push --target "$RELEASE_HEAD_SHA" --publication-lock "$PUBLICATION_LOCK_PATH" + - name: Reserve broker attestation content write + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-broker') }} run: | - node .github/scripts/download-build-artifacts.mjs \ - Release \ - "$RELEASE_HEAD_SHA" \ - "$RUNNER_TEMP/approved-bootstrap" \ - --run-id "$DRY_RUN_ID" \ - --artifact-metadata-json "$APPROVED_ARTIFACT_METADATA_JSON" \ - --artifact oliphaunt-publication-lock \ - --artifact oliphaunt-publication-candidate - - - name: Verify and install approved publication candidate - id: verify_bootstrap_candidate - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} - env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - APPROVAL_RUN_ID: ${{ inputs.approval_run_id }} + tools/dev/bun.sh tools/release/github-content-write-pacer.mts reserve --label "broker attestation" + tools/dev/bun.sh tools/release/github-core-request-journal.mts reserve --label "broker attestation API attempt" + - name: Attest broker release assets + id: attest_broker + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-broker') }} + timeout-minutes: 5 + uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 + with: + subject-path: | + target/oliphaunt-broker/release-assets/*.tar.gz + target/oliphaunt-broker/release-assets/*.zip + target/oliphaunt-broker/release-assets/*.sha256 + - name: Reserve Node direct attestation content write + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-node-direct') }} run: | - if [[ -e "$GITHUB_WORKSPACE/target" ]]; then - echo 'publication candidate installation requires an absent workspace target directory' >&2 - exit 1 - fi - tools/dev/bun.sh tools/release/bootstrap-publication-capsule.mjs verify-extract \ - --transport "$RUNNER_TEMP/approved-bootstrap/oliphaunt-publication-candidate.tar" \ - --approved-lock "$RUNNER_TEMP/approved-bootstrap/publication-lock.json" \ - --products-json "$PRODUCTS_JSON" \ - --head-ref "$RELEASE_HEAD_SHA" \ - --approval-run-id "$APPROVAL_RUN_ID" \ - --workspace-root "$GITHUB_WORKSPACE" - - - name: Verify external lock equals installed candidate lock - id: verify_bootstrap_lock - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + tools/dev/bun.sh tools/release/github-content-write-pacer.mts reserve --label "Node direct attestation" + tools/dev/bun.sh tools/release/github-core-request-journal.mts reserve --label "Node direct attestation API attempt" + - name: Attest Node direct release assets + id: attest_node_direct + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-node-direct') }} + timeout-minutes: 5 + uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 + with: + subject-path: | + target/oliphaunt-node-direct/release-assets/*.tar.gz + target/oliphaunt-node-direct/release-assets/*.zip + target/oliphaunt-node-direct/release-assets/*.sha256 + - name: Reserve WASIX Node-API attestation content write + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-wasix-napi') }} run: | - if ! cmp -s "$RUNNER_TEMP/approved-bootstrap/publication-lock.json" "$PUBLICATION_LOCK_PATH"; then - echo 'installed candidate lock differs from the separately downloaded approved publication lock' >&2 - exit 1 - fi - tools/dev/bun.sh tools/release/publication-lock.mjs verify \ - --lock "$PUBLICATION_LOCK_PATH" \ - --head-ref "$RELEASE_HEAD_SHA" - - - name: Restore prior bootstrap checkpoint chain - id: restore_bootstrap_checkpoint - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + tools/dev/bun.sh tools/release/github-content-write-pacer.mts reserve --label "WASIX Node-API attestation" + tools/dev/bun.sh tools/release/github-core-request-journal.mts reserve --label "WASIX Node-API attestation API attempt" + - name: Attest WASIX Node-API release assets + id: attest_wasix_napi + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'oliphaunt-wasix-napi') }} + timeout-minutes: 5 + uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 + with: + subject-path: | + target/oliphaunt-wasix-napi/release-assets/*.tar.gz + target/oliphaunt-wasix-napi/release-assets/*.zip + target/oliphaunt-wasix-napi/release-assets/*.sha256 + - name: Reserve WASIX attestation content write + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix') }} + run: | + tools/dev/bun.sh tools/release/github-content-write-pacer.mts reserve --label "WASIX attestation" + tools/dev/bun.sh tools/release/github-core-request-journal.mts reserve --label "WASIX attestation API attempt" + - name: Attest WASIX release assets + id: attest_wasix + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix') }} + timeout-minutes: 5 + uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 + with: + subject-path: | + target/oliphaunt-wasix/release-assets/*.tar.zst + target/oliphaunt-wasix/release-assets/*.sha256 + target/extension-artifacts/liboliphaunt-wasix/oliphaunt-extension-contrib-pg18/release-assets/* + - name: Reserve WASIX postmaster attestation content write + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix-postmaster') }} + run: | + tools/dev/bun.sh tools/release/github-content-write-pacer.mts reserve --label "WASIX postmaster attestation" + tools/dev/bun.sh tools/release/github-core-request-journal.mts reserve --label "WASIX postmaster attestation API attempt" + - name: Attest WASIX postmaster release assets + id: attest_wasix_postmaster + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && contains(fromJson(steps.release_plan.outputs.products_json), 'liboliphaunt-wasix-postmaster') }} + timeout-minutes: 5 + uses: actions/attest-build-provenance@43d14bc2b83dec42d39ecae14e916627a18bb661 + with: + subject-path: | + target/oliphaunt-wasix-postmaster/release-assets/*.tar.zst + target/oliphaunt-wasix-postmaster/release-assets/*.sha256 + - name: Freeze exact GitHub release asset and attestation evidence + id: freeze_github_evidence + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 10 env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - run: node .github/scripts/download-bootstrap-ledger.mjs - - - name: Classify exact bootstrap credential needs - id: bootstrap_credential_needs - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} - env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - REGISTRY_MUTATION_DEADLINE_EPOCH: ${{ env.REGISTRY_JOB_HARD_DEADLINE_EPOCH }} - run: bun .github/scripts/bootstrap-registry-identities.mjs --credential-needs - - - name: Require bootstrap credentials before mutation - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} - env: - CRATES_IO_BOOTSTRAP_TOKEN: ${{ secrets.CRATES_IO_BOOTSTRAP_TOKEN }} - NPM_BOOTSTRAP_TOKEN: ${{ secrets.NPM_BOOTSTRAP_TOKEN }} - NEEDS_CARGO_TOKEN: ${{ steps.bootstrap_credential_needs.outputs.needs_cargo_token }} - NEEDS_NPM_TOKEN: ${{ steps.bootstrap_credential_needs.outputs.needs_npm_token }} + EXTENSIONS_ATTESTATION_BUNDLE_1: ${{ steps.attest_extensions_1.outputs.bundle-path }} + EXTENSIONS_ATTESTATION_BUNDLE_2: ${{ steps.attest_extensions_2.outputs.bundle-path }} + LIBOLIPHAUNT_NATIVE_ATTESTATION_BUNDLE: ${{ steps.attest_liboliphaunt_native.outputs.bundle-path }} + BROKER_ATTESTATION_BUNDLE: ${{ steps.attest_broker.outputs.bundle-path }} + NODE_DIRECT_ATTESTATION_BUNDLE: ${{ steps.attest_node_direct.outputs.bundle-path }} + WASIX_NAPI_ATTESTATION_BUNDLE: ${{ steps.attest_wasix_napi.outputs.bundle-path }} + WASIX_ATTESTATION_BUNDLE: ${{ steps.attest_wasix.outputs.bundle-path }} + WASIX_POSTMASTER_ATTESTATION_BUNDLE: ${{ steps.attest_wasix_postmaster.outputs.bundle-path }} run: | - if [[ "$NEEDS_CARGO_TOKEN" == true && -z "$CRATES_IO_BOOTSTRAP_TOKEN" ]]; then - echo 'approved candidate contains absent Cargo names but CRATES_IO_BOOTSTRAP_TOKEN is unavailable' >&2 - exit 1 - fi - if [[ "$NEEDS_NPM_TOKEN" == true && -z "$NPM_BOOTSTRAP_TOKEN" ]]; then - echo 'approved candidate contains absent npm names but NPM_BOOTSTRAP_TOKEN is unavailable' >&2 - exit 1 - fi - - - name: Create bootstrap transport tag token - id: bootstrap_tag_token - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 - with: *release_tag_app - - - name: Ensure exact immutable release transport ref - id: ensure_bootstrap_transport_ref - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} - timeout-minutes: 3 - env: - GH_TOKEN: ${{ steps.bootstrap_tag_token.outputs.token }} - GH_REPO: ${{ github.repository }} - RELEASE_OPERATION: publish-bootstrap - RELEASE_TRANSPORT_CONTENT_WRITE_ADMISSION: isolated-bootstrap - run: node .github/scripts/release-transport-ref.mjs ensure "$RELEASE_HEAD_SHA" - - - name: Start bounded bootstrap mutation window - id: bootstrap_mutation_deadline - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + bundle_args=() + for bundle in \ + "$EXTENSIONS_ATTESTATION_BUNDLE_1" \ + "$EXTENSIONS_ATTESTATION_BUNDLE_2" \ + "$LIBOLIPHAUNT_NATIVE_ATTESTATION_BUNDLE" \ + "$BROKER_ATTESTATION_BUNDLE" \ + "$NODE_DIRECT_ATTESTATION_BUNDLE" \ + "$WASIX_NAPI_ATTESTATION_BUNDLE" \ + "$WASIX_ATTESTATION_BUNDLE" \ + "$WASIX_POSTMASTER_ATTESTATION_BUNDLE" + do + if [[ -n "$bundle" ]]; then + bundle_args+=(--attestation-bundle "$bundle") + fi + done + bash tools/release/publication-controller.sh "$RELEASE_HEAD_SHA" "$GITHUB_SHA" bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/release/verify-github-release-attestations.sh pre-mutation \ + --publication-lock "$PUBLICATION_LOCK_PATH" \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" \ + --output target/release/github-release-attestation-receipt.json \ + "${bundle_args[@]}" + - name: Open registry publication window + id: registry_publication_window + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} run: | - if [[ ! "$BOOTSTRAP_REGISTRY_MUTATION_WINDOW_SECONDS" =~ ^[1-9][0-9]*$ ]]; then - echo 'BOOTSTRAP_REGISTRY_MUTATION_WINDOW_SECONDS must be a positive integer' >&2 - exit 1 - fi - if [[ ! "$REGISTRY_JOB_HARD_DEADLINE_EPOCH" =~ ^[1-9][0-9]*$ ]]; then - echo 'REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp' >&2 + for name in RELEASE_JOB_HARD_DEADLINE_EPOCH POST_REGISTRY_RESERVE_SECONDS; do + if [[ ! "${!name:-}" =~ ^[1-9][0-9]*$ ]]; then + echo "$name must be a positive integer" >&2 + exit 1 + fi + done + mutation_deadline=$(( RELEASE_JOB_HARD_DEADLINE_EPOCH - POST_REGISTRY_RESERVE_SECONDS )) + if (( $(date +%s) >= mutation_deadline )); then + echo 'Not enough time remains for registry publication and final verification; rerun this idempotent release.' >&2 exit 1 fi - now=$(date +%s) - window_deadline=$(( now + BOOTSTRAP_REGISTRY_MUTATION_WINDOW_SECONDS )) - deadline=$window_deadline - if (( REGISTRY_JOB_HARD_DEADLINE_EPOCH < deadline )); then - deadline=$REGISTRY_JOB_HARD_DEADLINE_EPOCH - fi - echo "REGISTRY_MUTATION_DEADLINE_EPOCH=$deadline" >> "$GITHUB_ENV" - echo "Bootstrap registry mutation must stop before Unix time $deadline." - - - name: Configure npm identity-bootstrap authentication - id: configure_bootstrap_npm_auth - if: ${{ steps.bootstrap_scope.outputs.required == 'true' && steps.bootstrap_credential_needs.outputs.needs_npm_token == 'true' }} + echo "REGISTRY_MUTATION_DEADLINE_EPOCH=$mutation_deadline" >> "$GITHUB_ENV" + - name: Publish and reconcile every exact-lock registry carrier + id: publish_registries + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 240 env: - NPM_BOOTSTRAP_TOKEN: ${{ secrets.NPM_BOOTSTRAP_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }} + ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} run: | - umask 077 - npmrc="$RUNNER_TEMP/oliphaunt-bootstrap.npmrc" - printf '//registry.npmjs.org/:_authToken=%s\n' "$NPM_BOOTSTRAP_TOKEN" > "$npmrc" - - - name: Bootstrap missing Cargo and npm identities - id: bootstrap_registry_identities - if: ${{ steps.bootstrap_scope.outputs.required == 'true' }} + bash tools/release/publish-registries.sh \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" \ + --publication-lock "$PUBLICATION_LOCK_PATH" + - name: Verify published release + id: verify_published_release + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 8 env: - CARGO_REGISTRY_TOKEN: ${{ steps.bootstrap_credential_needs.outputs.needs_cargo_token == 'true' && secrets.CRATES_IO_BOOTSTRAP_TOKEN || '' }} - NPM_CONFIG_USERCONFIG: ${{ runner.temp }}/oliphaunt-bootstrap.npmrc + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - REGISTRY_BOOTSTRAP_CARGO_SECONDS_PER_CARRIER: ${{ vars.REGISTRY_BOOTSTRAP_CARGO_SECONDS_PER_CARRIER || '30' }} - REGISTRY_BOOTSTRAP_NPM_SECONDS_PER_CARRIER: ${{ vars.REGISTRY_BOOTSTRAP_NPM_SECONDS_PER_CARRIER || '30' }} - REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_PER_CARRIER: ${{ vars.REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_PER_CARRIER || '6' }} - REGISTRY_BOOTSTRAP_RESERVE_SECONDS: ${{ vars.REGISTRY_BOOTSTRAP_RESERVE_SECONDS || '600' }} - run: bun .github/scripts/bootstrap-registry-identities.mjs - - - name: Require a typed bootstrap execution decision - id: require_bootstrap_execution_decision - if: ${{ steps.bootstrap_registry_identities.outcome == 'success' }} - timeout-minutes: 1 + run: | + gh auth setup-git + git fetch --force --tags origin + bash tools/release/release-verify.sh \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" \ + --publication-lock "$PUBLICATION_LOCK_PATH" \ + --registry-receipts target/release/registry-integrity-receipts.json \ + --github-release-receipt target/release/github-release-attestation-receipt.json + - name: Resolve and install exact public consumer surfaces + id: public_consumer_smoke + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 15 env: - COMPLETE: ${{ steps.bootstrap_registry_identities.outputs.complete }} - DEFERRED: ${{ steps.bootstrap_registry_identities.outputs.deferred }} - DEFERRAL_MODE: ${{ steps.bootstrap_registry_identities.outputs.deferral_mode }} - PROGRESS_COUNT: ${{ steps.bootstrap_registry_identities.outputs.progress_count }} - REMAINING_COUNT: ${{ steps.bootstrap_registry_identities.outputs.remaining_count }} - NOT_BEFORE_EPOCH: ${{ steps.bootstrap_registry_identities.outputs.not_before_epoch }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} run: | - if [[ "$COMPLETE" == true && "$DEFERRED" == false ]]; then - if [[ -n "$DEFERRAL_MODE" || "$REMAINING_COUNT" != 0 ]]; then - echo 'complete bootstrap result retains a deferral mode or remaining carriers' >&2 - exit 1 - fi - elif [[ "$COMPLETE" == false && "$DEFERRED" == true ]]; then - if [[ ! "$REMAINING_COUNT" =~ ^[1-9][0-9]*$ || ! "$NOT_BEFORE_EPOCH" =~ ^[1-9][0-9]*$ ]]; then - echo 'deferred bootstrap result requires remaining work and a positive not-before time' >&2 - exit 1 - fi - if [[ "$DEFERRAL_MODE" == progress ]]; then - if [[ ! "$PROGRESS_COUNT" =~ ^[1-9][0-9]*$ ]]; then - echo 'bootstrap progress deferral requires nonzero durable progress' >&2 - exit 1 - fi - elif [[ "$DEFERRAL_MODE" == rate-limit ]]; then - if [[ "$PROGRESS_COUNT" != 0 ]]; then - echo 'bootstrap rate-limit deferral cannot claim durable progress' >&2 - exit 1 - fi - elif [[ "$DEFERRAL_MODE" == pre-mutation-capacity ]]; then - if [[ "$PROGRESS_COUNT" != 0 ]]; then - echo 'bootstrap pre-mutation capacity deferral cannot claim durable progress' >&2 - exit 1 - fi - elif [[ "$DEFERRAL_MODE" == pre-mutation-deadline ]]; then - if [[ "$PROGRESS_COUNT" != 0 ]]; then - echo 'bootstrap pre-mutation deadline deferral cannot claim durable progress' >&2 - exit 1 - fi - else - echo 'deferred bootstrap result has an unsupported deferral mode' >&2 - exit 1 - fi - else - echo 'bootstrap publisher must emit exactly one of complete or deferred' >&2 - exit 1 - fi - { - echo "complete=$COMPLETE" - echo "deferred=$DEFERRED" - echo "deferral_mode=$DEFERRAL_MODE" - echo "progress_count=$PROGRESS_COUNT" - echo "remaining_count=$REMAINING_COUNT" - echo "not_before_epoch=$NOT_BEFORE_EPOCH" - } >> "$GITHUB_OUTPUT" - - - name: Record bootstrap identity result - if: ${{ steps.require_bootstrap_execution_decision.outputs.complete == 'true' }} + command -v gtimeout >/dev/null || brew install coreutils + bash tools/release/public-consumer-smoke.sh \ + --publication-lock "$PUBLICATION_LOCK_PATH" \ + --products-json "$PRODUCTS_JSON" \ + --registry-receipts target/release/registry-integrity-receipts.json \ + --github-release-receipt target/release/github-release-attestation-receipt.json \ + --output target/release/public-consumer-smoke.json + - name: Preserve public consumer evidence + id: preserve_consumer_evidence + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 2 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: public-consumer-evidence-${{ github.sha }} + path: target/release/public-consumer-smoke.json + if-no-files-found: error + overwrite: true + retention-days: 90 + - name: Reverify exact publication lock before promotion + id: reverify_publication_lock + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 2 run: | - lock_sha256="$(sha256sum "$PUBLICATION_LOCK_PATH" | awk '{print $1}')" - { - echo '## Registry identity bootstrap complete' - echo - echo "- Release commit: \`$RELEASE_HEAD_SHA\`" - echo "- Publication lock SHA-256: \`$lock_sha256\`" - echo '- Scope: selected Cargo and npm identities only' - echo '- Next: configure trusted publishers, revoke bootstrap tokens, then run the normal publish operation' - } >> "$GITHUB_STEP_SUMMARY" - - - name: Remove bootstrap npm credentials - id: remove_bootstrap_credentials - if: ${{ always() }} - run: rm -f "$RUNNER_TEMP/oliphaunt-bootstrap.npmrc" - - - name: Upload bootstrap identity ledger - id: preserve_bootstrap_ledger - if: ${{ always() }} + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/publication-lock.mts \ + verify \ + --lock "$PUBLICATION_LOCK_PATH" \ + --head-ref "$RELEASE_HEAD_SHA" + - name: Preserve release evidence + id: preserve_release_evidence + if: ${{ always() && steps.release_plan.outputs.has_release_changes == 'true' }} + continue-on-error: true + timeout-minutes: 3 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with: - name: oliphaunt-bootstrap-ledger - path: target/release/bootstrap-ledger + name: release-evidence-${{ github.sha }} + path: | + target/release/publication-lock.json + target/release/registry-integrity-receipts.json + target/release/github-release-attestation-receipt.json + target/release/public-consumer-smoke.json + ${{ runner.temp }}/oliphaunt-github-release-asset-upload-report.json if-no-files-found: warn + include-hidden-files: true overwrite: true retention-days: 90 - - - name: Stop incomplete bootstrap for manual rerun - if: ${{ steps.require_bootstrap_execution_decision.outputs.deferred == 'true' }} + - name: Promote verified GitHub release drafts + id: promote_github_releases + if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} + timeout-minutes: 16 env: - DEFERRAL_MODE: ${{ steps.require_bootstrap_execution_decision.outputs.deferral_mode }} - NOT_BEFORE_EPOCH: ${{ steps.require_bootstrap_execution_decision.outputs.not_before_epoch }} - REMAINING_COUNT: ${{ steps.require_bootstrap_execution_decision.outputs.remaining_count }} - APPROVAL_RUN_ID: ${{ inputs.approval_run_id }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} + run: | + tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mts \ + assert-markable \ + --release-sha "${{ steps.verify_publication_candidate.outputs.release_sha }}" \ + --base main + bun .github/scripts/manage-release-drafts.mts promote \ + --products-json "$PRODUCTS_JSON" \ + --head-ref "$RELEASE_HEAD_SHA" + tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mts \ + mark-tagged \ + --release-sha "${{ steps.verify_publication_candidate.outputs.release_sha }}" \ + --base main + request-docs-refresh: + name: Refresh published docs + needs: publish + if: ${{ needs.publish.outputs.promoted == 'true' }} + runs-on: ubuntu-24.04 + timeout-minutes: 15 + environment: Production + permissions: + contents: read + steps: + - name: Require main + run: test "$GITHUB_REF" = refs/heads/main + - name: Checkout docs refresh command + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: ${{ github.sha }} + persist-credentials: false + - name: Set up Bun + uses: ./.github/actions/setup-bun + - name: Record completed public releases + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + mkdir -p target/docs + bun src/docs/tools/verify-live.mts snapshot target/docs/expected-products.json + - name: Request main-branch docs rebuild + id: request_docs + env: + VERCEL_DOCS_DEPLOY_HOOK: ${{ secrets.VERCEL_DOCS_DEPLOY_HOOK }} + run: bash src/docs/tools/request-refresh.sh target/docs/deploy-hook.json + - name: Verify live published versions + id: verify_docs + run: bun src/docs/tools/verify-live.mts verify target/docs/expected-products.json + - name: Preserve docs refresh evidence + if: ${{ always() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: docs-refresh-request-${{ github.run_id }}-${{ github.run_attempt }} + path: | + target/docs/deploy-hook.json + target/docs/expected-products.json + if-no-files-found: ignore + retention-days: 30 + - name: Report docs refresh separately from publication + if: ${{ always() }} + env: + REQUEST_OUTCOME: ${{ steps.request_docs.outcome }} + LIVE_OUTCOME: ${{ steps.verify_docs.outcome }} run: | { - echo '## Registry identity bootstrap incomplete—rerun required' - echo - echo "- Release commit: \`$RELEASE_HEAD_SHA\`" - echo "- Approved dry-run: \`$APPROVAL_RUN_ID\`" - echo "- Remaining identities: \`$REMAINING_COUNT\`" - echo "- Reason: \`$DEFERRAL_MODE\`" - echo "- Do not rerun before Unix time: \`$NOT_BEFORE_EPOCH\`" - echo "- Resume this exact SHA and approval: \`gh run rerun $GITHUB_RUN_ID --failed\`" + echo '### Documentation refresh' + echo 'Product publication completed successfully before this job.' + echo "Refresh request: $REQUEST_OUTCOME." + echo "Live published-version check: $LIVE_OUTCOME." + echo 'The live check requires the version page to link the expected completed public releases or newer stable releases; hook acceptance alone is insufficient.' + echo 'Retry this docs job only after checking the Vercel deployment; do not republish products to refresh documentation.' } >> "$GITHUB_STEP_SUMMARY" - echo "Bootstrap is incomplete; rerun failed jobs for workflow run $GITHUB_RUN_ID after $NOT_BEFORE_EPOCH." >&2 - exit 1 diff --git a/.gitignore b/.gitignore index 0b1015f4f..a55628ddf 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,8 @@ node_modules/ /src/docs/.source/ /src/docs/build/ /src/docs/out/ -/src/runtimes/liboliphaunt/wasix/crates/assets/assets/ -/src/runtimes/liboliphaunt/wasix/crates/aot/*/artifacts/ +/src/runtimes/liboliphaunt-wasix/crates/assets/assets/ +/src/runtimes/liboliphaunt-wasix/crates/aot/*/artifacts/ /src/sdks/react-native/ios/vendor/oliphaunt-swift/ /src/sdks/react-native/ios/vendor/liboliphaunt.xcframework/ **/.DS_Store @@ -21,7 +21,22 @@ __pycache__/ oliphaunt_wasix-*.crates.tar.gz # Exact candidate locks are generated from the qualified local Cargo registry. -/examples/tauri/src-tauri/Cargo.lock -/examples/tauri-wasix/src-tauri/Cargo.lock -/examples/electron-wasix/src-wasix/Cargo.lock -/examples/browser-wasix/dist/ +/src/examples/tauri/src-tauri/Cargo.lock +/src/examples/tauri-wasix/src-tauri/Cargo.lock +/src/examples/electron-wasix/src-wasix/Cargo.lock +/src/examples/browser-wasix/dist/ + +# JavaScript emitted from TypeScript for public package consumers. +/src/sdks/swift/tools/extension-resource-inventory.mjs +/src/sdks/swift/tools/render-extension-products.mjs +/src/sdks/swift/tools/swift-carrier-resolver.mjs +/src/sdks/react-native/tools/native-resource-closure.mjs +/src/sdks/react-native/tools/stage-ios-app.mjs +/src/sdks/react-native/tools/verify-ios-package.mjs +/src/sdks/react-native/app.plugin.js +/src/sdks/react-native/react-native.config.js +/src/sdks/react-native/tools/codegen-check.cjs +/src/postgres-tools/native/npm/index.js +/src/postgres-tools/wasix/npm/index.js +/src/database-resources/icu/npm/react-native.config.js +/src/sdks/react-native/.generated-tools/ diff --git a/.lychee.toml b/.lychee.toml deleted file mode 100644 index fafbf3509..000000000 --- a/.lychee.toml +++ /dev/null @@ -1,15 +0,0 @@ -accept = [200, 206, 429] -exclude = [ - "http://localhost", - "https://localhost", - "http://127.0.0.1", - "https://127.0.0.1", -] -exclude_path = [ - "target", - "node_modules", - "src/runtimes/liboliphaunt/wasix/assets/build", -] -max_retries = 2 -timeout = 20 -user_agent = "oliphaunt-link-check" diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc index 288b46551..ec94a49b3 100644 --- a/.markdownlint-cli2.jsonc +++ b/.markdownlint-cli2.jsonc @@ -1,12 +1,12 @@ { "globs": [ "README.md", - "docs/**/*.md", + "src/docs/**/*.md", "src/**/README.md", - "examples/react-native-expo/README.md", - "examples/tauri-wasix/README.md" + "src/examples/react-native-expo/README.md", + "src/examples/tauri-wasix/README.md" ], - "ignores": ["target/**", "**/node_modules/**", "src/runtimes/liboliphaunt/wasix/assets/build/**"], + "ignores": ["target/**", "**/node_modules/**", "src/runtimes/liboliphaunt-wasix/assets/build/**"], "config": { "default": true, "MD013": false, diff --git a/.moon/tasks/cargo.yml b/.moon/tasks/cargo.yml new file mode 100644 index 000000000..ce510714d --- /dev/null +++ b/.moon/tasks/cargo.yml @@ -0,0 +1,21 @@ +$schema: "https://moonrepo.dev/schemas/tasks.json" + +inheritedBy: + tags: ["cargo-package"] + +fileGroups: + cargo-sources: + - "src/**/*" + - "{Cargo.toml,build.rs}" + +tasks: + # Cargo owns compilation. This command-free node only carries source hashes + # through Moon's Cargo-derived project dependency graph, including transitives. + cargo-sources: + inputs: ["@group(cargo-sources)", "@group(cargo-workspace)"] + deps: + - target: "^:cargo-sources" + optional: true + cacheStrategy: hash + options: + internal: true diff --git a/.moon/tasks/inputs.yml b/.moon/tasks/inputs.yml index a0e154fdb..0901ef72d 100644 --- a/.moon/tasks/inputs.yml +++ b/.moon/tasks/inputs.yml @@ -1,5 +1,9 @@ $schema: "https://moonrepo.dev/schemas/tasks.json" +taskOptions: + unixShell: "bash" + windowsShell: "bash" + fileGroups: cargo-workspace: - "/Cargo.lock" @@ -7,61 +11,45 @@ fileGroups: - "/rust-toolchain.toml" rust-test-config: - "/.config/nextest.toml" - pnpm-workspace: - - "/package.json" - - "/pnpm-lock.yaml" - - "/pnpm-workspace.yaml" - js-quality: + bun-workspace: - "/package.json" - - "/pnpm-lock.yaml" - - "/pnpm-workspace.yaml" - - "/biome.json" - - "/renovate.json" - - "/.markdownlint-cli2.jsonc" - - "/src/docs/package.json" - - "/src/docs/next.config.mjs" - - "/src/docs/postcss.config.mjs" - - "/src/docs/proxy.ts" - - "/src/docs/source.config.ts" - - "/src/docs/src/**/*" - - "/src/docs/tools/**/*" - - "/src/bindings/wasix-ts/package.json" - - "/src/bindings/wasix-ts/src/**/*" - - "/src/bindings/wasix-ts/tools-package/**/*" - - "/src/bindings/wasix-ts/tools/**/*" - - "/examples/browser-wasix/**/*" - - "!/examples/browser-wasix/dist/**/*" - - "/src/shared/js-core/src/**/*" - - "/src/runtimes/liboliphaunt/native/tools-npm/**/*" - - "/src/runtimes/liboliphaunt/native/tools/smoke-packed-tools-npm.mjs" - - "/src/sdks/react-native/package.json" - - "/src/sdks/react-native/typedoc.json" - - "/src/sdks/react-native/react-native.config.js" - - "/src/sdks/react-native/src/**/*" - - "/src/sdks/js/package.json" - - "/src/sdks/js/typedoc.json" - - "/src/sdks/js/src/**/*" - - "/tools/integration/**/*" - - "/tools/perf/matrix/**/*" - - "/tools/perf/wasix-browser/**/*" - - "/tools/perf/wasix-node/**/*" - - "/tools/test/**/*" - - "/tools/policy/format.sh" + - "/bun.lock" + - "/bunfig.toml" legal-files: - "/LICENSE" - "/THIRD_PARTY_NOTICES.md" + upstream-licenses: + - "/src/third-party/postgres/COPYRIGHT" + - "/src/third-party/icu/LICENSE" + - "/src/third-party/openssl/LICENSE.txt" release-archive-contract: - - "/tools/release/release-directory-safety.mjs" - - "/src/shared/artifact-packaging/portable-archive.mjs" - - "/tools/release/release-notices.mjs" + - "/tools/packaging/release-directory-safety.mts" + - "/tools/packaging/portable-archive.mts" + - "/tools/packaging/release-notices.mts" + package-test-metadata: + - "/release-please-config.json" + - "/.release-please-manifest.json" + - "/**/release.toml" + - "/**/moon.yml" + - "/**/{VERSION,LIBOLIPHAUNT_VERSION,Cargo.toml,package.json,gradle.properties}" + - "/**/targets/**/*.toml" + - "/src/extensions/generated/extensions.catalog.json" + - "/src/extensions/contrib/*.toml" + - "/src/extensions/external/**/{recipe,source}.toml" + - "/src/third-party/postgres/source.toml" + - "/tools/release/release-graph.mts" + - "/tools/release/release-history.mts" + - "/src/extensions/artifacts/packages/tools/contrib-carriers.mts" + - "/src/extensions/artifacts/packages/tools/extension-registry-packages.mts" + - "/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts" release-target-contract: - - "/tools/release/platform-compatibility-policy.mjs" - - "/src/shared/extension-runtime-contract/extension-target-profiles.mjs" - - "/src/shared/extension-runtime-contract/extension-target-profiles.toml" - - "/tools/release/release-artifact-targets.mjs" + - "/tools/release/platform-compatibility-policy.mts" + - "/src/extensions/contracts/extension-target-profiles.mts" + - "/src/extensions/contracts/extension-target-profiles.toml" + - "/tools/release/release-artifact-targets.mts" # Installed dependency trees are derived state. Task invalidation comes from # tracked package manifests, workspace configuration, and lockfiles instead of -# pnpm's directory symlinks, which Moon cannot hash as files. +# Bun's directory symlinks, which Moon cannot hash as files. implicitInputs: # Changes to shared groups and universal inputs must invalidate their users. - "/.moon/tasks/inputs.yml" @@ -74,9 +62,5 @@ implicitInputs: - "/.prototools" - "!/node_modules" - "!/node_modules/**" - - "!/examples/**/node_modules" - - "!/examples/**/node_modules/**" - - "!/src/**/node_modules" - - "!/src/**/node_modules/**" - - "!/tools/**/node_modules" - - "!/tools/**/node_modules/**" + - "!/**/node_modules" + - "!/**/node_modules/**" diff --git a/.moon/tasks/javascript-quality.yml b/.moon/tasks/javascript-quality.yml new file mode 100644 index 000000000..39f70b6ae --- /dev/null +++ b/.moon/tasks/javascript-quality.yml @@ -0,0 +1,25 @@ +$schema: "https://moonrepo.dev/schemas/tasks.json" + +inheritedBy: + tags: [javascript-quality] + +fileGroups: + javascript-quality: + - "**/*.{js,mjs,cjs,ts,mts,cts,tsx,json,jsonc,css}" + - /biome.json + +tasks: + js-format-check: + tags: [quality, static, format] + command: bun x --no-install biome format --no-errors-on-unmatched . + inputs: ["@group(javascript-quality)"] + js-lint: + tags: [quality, static] + command: bun x --no-install biome lint --diagnostic-level=error --no-errors-on-unmatched . + inputs: ["@group(javascript-quality)"] + js-format: + command: bun x --no-install biome format --write --no-errors-on-unmatched . + inputs: ["@group(javascript-quality)"] + options: + cache: false + runInCI: false diff --git a/.moon/toolchains.yml b/.moon/toolchains.yml index 290cc4a2b..e7ee4b2cd 100644 --- a/.moon/toolchains.yml +++ b/.moon/toolchains.yml @@ -5,7 +5,7 @@ proto: javascript: plugin: "registry://ghcr.io/moonrepo/javascript_toolchain@sha256:81c26ebeae43fb130ad3ce0411cbdfd3bc4aa9d5e488e25b43a08fda5e790176" - packageManager: "pnpm" + packageManager: "bun" installDependencies: false syncProjectWorkspaceDependencies: false @@ -13,8 +13,8 @@ node: plugin: "registry://ghcr.io/moonrepo/node_toolchain@sha256:1ac2fab8bf5297bea9361132612b0dd70c63a9482606d06c15e48704643934ec" versionFromPrototools: true -pnpm: - plugin: "registry://ghcr.io/moonrepo/node_depman_toolchain@sha256:9337febf5b59f5a789a252179a7c2b1dd7c05be79905e311366a016d9f6f8677" +bun: + plugin: "registry://ghcr.io/moonrepo/bun_toolchain@sha256:d19bd0a3c223c8dcbcb7db71492761bc55fa799120f935289a788cb4c3c2128b" versionFromPrototools: true rust: diff --git a/.moon/workspace.yml b/.moon/workspace.yml index cc0bd1554..e768b4404 100644 --- a/.moon/workspace.yml +++ b/.moon/workspace.yml @@ -3,11 +3,9 @@ $schema: "https://moonrepo.dev/schemas/workspace.json" projects: globFormat: "source-path" globs: - - "moon.yml" - - "benchmarks/moon.yml" - - "examples/moon.yml" - - "src/**/moon.yml" - - "tools/**/moon.yml" + - "**/moon.yml" + - "!target/**" + - "!**/node_modules/**" sources: ci-workflows: ".github" @@ -15,6 +13,10 @@ pipeline: installDependencies: false logRunningCommand: true +cache: + cas: + verifyIntegrity: true + vcs: provider: "github" defaultBranch: "main" diff --git a/.prototools b/.prototools index 8535fd460..34b62ea49 100644 --- a/.prototools +++ b/.prototools @@ -1,5 +1,4 @@ moon = "2.5.4" node = "22.22.3" -pnpm = "11.5.0" -bun = "1.3.14" +bun = "1.4.2" deno = "2.8.1" diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ceb69c53e..7839d372e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,13 +1,13 @@ { - "src/runtimes/liboliphaunt/native": "0.2.0", - "src/sdks/rust": "0.2.0", - "src/runtimes/broker": "0.2.0", - "src/runtimes/node-direct": "0.2.0", - "src/runtimes/wasix-napi": "0.1.0", + "src/runtimes/liboliphaunt-native": "0.2.0", + "src/sdks/rust/sdk": "0.2.0", + "src/broker": "0.2.0", + "src/sdks/ts/node-addon": "0.2.0", + "src/sdks/ts-wasix/node-addon": "0.1.0", "src/sdks/swift": "0.7.0", "src/sdks/kotlin": "0.2.0", "src/sdks/react-native": "0.2.0", - "src/sdks/js": "0.2.0", + "src/sdks/ts/sdk": "0.2.0", "src/extensions/external/pg_hashids": "0.2.0", "src/extensions/external/pg_ivm": "0.2.0", "src/extensions/external/pg_textsearch": "0.2.0", @@ -15,8 +15,15 @@ "src/extensions/external/pgtap": "0.2.0", "src/extensions/external/postgis": "0.2.0", "src/extensions/external/vector": "0.2.0", - "src/runtimes/liboliphaunt/wasix": "0.2.0", - "src/runtimes/liboliphaunt/wasix-postmaster": "0.1.0", - "src/bindings/wasix-rust/crates/oliphaunt-wasix": "0.2.0", - "src/bindings/wasix-ts": "0.1.0" + "src/runtimes/liboliphaunt-wasix": "0.2.0", + "src/runtimes/liboliphaunt-wasix-postmaster": "0.1.0", + "src/sdks/rust-wasix": "0.2.0", + "src/sdks/ts-wasix/sdk": "0.1.0", + "src/sdks/rust-query": "0.1.0", + "src/sdks/ts-query": "0.1.0", + "src/sdks/rust/liboliphaunt-native": "0.1.0", + "src/postgres-tools/native": "0.2.1", + "src/postgres-tools/wasix": "0.2.1", + "src/database-resources": "0.2.1", + "src/pgwire-server": "0.1.0" } diff --git a/.typos.toml b/.typos.toml deleted file mode 100644 index af4309828..000000000 --- a/.typos.toml +++ /dev/null @@ -1,19 +0,0 @@ -[files] -extend-exclude = [ - "target/**", - "**/node_modules/**", - "src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/**", - "src/runtimes/liboliphaunt/native/patches/**", - "src/runtimes/liboliphaunt/native/postgres18/**", -] - -[default] -extend-ignore-re = [ - "PNPM", - "WASIX", -] - -[default.extend-words] -oliphaunt = "oliphaunt" -wasix = "wasix" -ser = "ser" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9e7cfc33..10cdc7e06 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,28 +8,29 @@ opening a PR: ```sh tools/dev/bootstrap-tools.sh moon run dev-tools:doctor -moon run policy-tools:js-format-check policy-tools:rust-format-check +moon run repo:js-format-check moon run :check :compile :format-check :lint :tools-compile --affected -moon run :test :unit :tools-unit --affected +moon run :test :tools-unit --affected ``` The runtime smoke starts embedded Postgres and is intentionally slower than unit tests. The protected `publish-dry-run` operation is a release-candidate check: run it -from the GitHub `Release` workflow after the exact release-bump commit has a -successful `Qualified` CI record. The documented same-version control recovery +from the GitHub `Release` workflow. It requires a successful, product-scoped +`Qualified` CI record for the exact release-bump commit; the workflow reuses an +eligible run or requests qualification when needed. The documented same-version control recovery uses a separately qualified linear recovery head bound to that original release-bump commit. It is not a routine source-PR check. Install local hooks with: ```sh -tools/dev/bun.sh tools/dev/install-hooks.mjs +bash tools/dev/install-hooks.sh ``` Hooks stay deliberately smaller than CI: pre-commit handles file hygiene and formatting, while commit-msg validates Conventional Commit messages. Run `moon run release-tools:metadata` for a product metadata change. Release code -uses `release-tools:unit`; repository policy uses `policy-tools:unit`; workflow +uses `release-tools:test`; workflow and planner code uses `ci-workflows:check`. CI remains the source of truth for generated AOT runtime matrices, packaging, Tauri, frontend, feature combinations, public API compatibility, and supply-chain checks. @@ -54,7 +55,7 @@ Actions `Release` workflow. Release Please manifest mode owns version bumps, changelog updates, and the generated release PR. The protected publish workflow owns exact-SHA product tags and draft GitHub releases. Product-local release metadata owns publish targets and artifact shape; Moon dependency scopes -provide release coupling. See `docs/maintainers/release.md` for release intent, +provide release coupling. See `src/docs/maintainers/release.md` for release intent, trusted publishing, and workflow details. A pure control-plane `ci:` change has no release-semantic owners, so preparing diff --git a/Cargo.lock b/Cargo.lock index ca62f66da..41636255b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,15 +100,6 @@ version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] - [[package]] name = "arrayref" version = "0.3.9" @@ -121,6 +112,59 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "askama" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6024d73179f43f15ccd2b881bfea6fee7f3a46ec53f33b52210dea749ebebaa4" +dependencies = [ + "askama_macros", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071ee5ebf2138e3ad180e0aacf6940c2cab5e6d8333741d9925c7bee2b153f39" +dependencies = [ + "askama_parser", + "basic-toml", + "glob", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "serde", + "serde_derive", + "syn 3.0.5", +] + +[[package]] +name = "askama_macros" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643e1c7cbb6aec1d920332fe51a7c0d8219e273dcb8602db03f5263e4d16487b" +dependencies = [ + "askama_derive", +] + +[[package]] +name = "askama_parser" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c5ae75772275d268b03ab8bdccdd12117b6169ee23256942b34e46c9f476583" +dependencies = [ + "rustc-hash", + "serde", + "serde_derive", + "unicode-ident", + "winnow 1.0.3", +] + [[package]] name = "async-trait" version = "0.1.89" @@ -169,10 +213,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "base64ct" -version = "1.8.3" +name = "basic-toml" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] [[package]] name = "bincode" @@ -332,6 +379,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "camino" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1307f12aa967b5a58416e87b3653360e0fd614a016b6e970db08fecbb1b80d" + [[package]] name = "cap-fs-ext" version = "4.0.2" @@ -540,12 +593,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - [[package]] name = "const-oid" version = "0.10.2" @@ -729,33 +776,6 @@ dependencies = [ "cmov", ] -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "curve25519-dalek-derive", - "digest 0.10.7", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "darling" version = "0.20.11" @@ -889,16 +909,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid 0.9.6", - "zeroize", -] - [[package]] name = "deranged" version = "0.5.8" @@ -908,17 +918,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "derive_builder" version = "0.20.2" @@ -991,7 +990,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer 0.12.0", - "const-oid 0.10.2", + "const-oid", "crypto-common 0.2.2", "ctutils", ] @@ -1055,30 +1054,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" -dependencies = [ - "curve25519-dalek", - "ed25519", - "serde", - "sha2 0.10.9", - "subtle", - "zeroize", -] - [[package]] name = "either" version = "1.16.0" @@ -1203,12 +1178,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - [[package]] name = "filetime" version = "0.2.29" @@ -1268,6 +1237,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-err" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91aa448ca50d7e79433bdf3ee8d99215430d2ec02ade5aefab2a073a1822e8a" +dependencies = [ + "autocfg", +] + [[package]] name = "fs-set-times" version = "0.20.3" @@ -1482,6 +1460,17 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "half" version = "2.7.1" @@ -1960,6 +1949,20 @@ dependencies = [ "windows-link", ] +[[package]] +name = "liboliphaunt-native-bindings" +version = "0.1.0" +dependencies = [ + "fs2", + "getrandom 0.3.4", + "libloading 0.8.9", + "serde", + "serde_json", + "sha2 0.10.9", + "tar", + "zstd", +] + [[package]] name = "liboliphaunt-wasix-aot-aarch64-apple-darwin" version = "0.2.0" @@ -2444,12 +2447,12 @@ dependencies = [ name = "oliphaunt" version = "0.2.0" dependencies = [ - "fs2", "getrandom 0.3.4", - "libloading 0.8.9", + "liboliphaunt-native-bindings", + "oliphaunt-broker", + "oliphaunt-query", "serde", "serde_json", - "sha2 0.10.9", "tokio", ] @@ -2457,7 +2460,9 @@ dependencies = [ name = "oliphaunt-broker" version = "0.2.0" dependencies = [ - "oliphaunt", + "getrandom 0.3.4", + "liboliphaunt-native-bindings", + "oliphaunt-query", ] [[package]] @@ -2472,13 +2477,23 @@ dependencies = [ [[package]] name = "oliphaunt-icu" -version = "0.2.0" +version = "0.2.1" dependencies = [ "sha2 0.10.9", "tar", "zstd", ] +[[package]] +name = "oliphaunt-mobile-bindings" +version = "0.0.0" +dependencies = [ + "liboliphaunt-native-bindings", + "oliphaunt", + "thiserror", + "uniffi", +] + [[package]] name = "oliphaunt-native-extension-proof" version = "0.0.0" @@ -2491,17 +2506,14 @@ dependencies = [ name = "oliphaunt-native-packaging" version = "0.0.0" dependencies = [ - "ed25519-dalek", "flate2", - "oliphaunt", + "liboliphaunt-native-bindings", "serde", "serde_json", "sha2 0.10.9", "tar", "tempfile", "toml 0.9.12+spec-1.1.0", - "ureq", - "zip", "zstd", ] @@ -2514,6 +2526,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "oliphaunt-node-direct" +version = "0.0.0" +dependencies = [ + "liboliphaunt-native-bindings", + "napi", + "napi-build", + "napi-derive", +] + [[package]] name = "oliphaunt-perf" version = "0.0.0" @@ -2521,7 +2543,6 @@ dependencies = [ "anyhow", "futures-util", "oliphaunt", - "oliphaunt-wasix", "rusqlite", "serde", "serde_json", @@ -2531,9 +2552,31 @@ dependencies = [ "tokio-postgres", ] +[[package]] +name = "oliphaunt-pgwire-server" +version = "0.1.0" +dependencies = [ + "anyhow", + "oliphaunt-query", + "oliphaunt-wasix", + "serde_json", + "sqlx", + "tempfile", + "tokio", + "tokio-postgres", + "tracing", +] + +[[package]] +name = "oliphaunt-query" +version = "0.1.0" + [[package]] name = "oliphaunt-tools" -version = "0.2.0" +version = "0.2.1" +dependencies = [ + "serde_json", +] [[package]] name = "oliphaunt-wasix" @@ -2553,6 +2596,7 @@ dependencies = [ "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", "liboliphaunt-wasix-portable", "oliphaunt-icu", + "oliphaunt-query", "oliphaunt-wasix-tools", "oliphaunt-wasix-tools-aot-aarch64-apple-darwin", "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu", @@ -2561,7 +2605,6 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.9", - "sqlx", "tar", "tempfile", "tokio", @@ -2589,23 +2632,35 @@ dependencies = [ "napi", "napi-build", "napi-derive", - "oliphaunt-icu", + "oliphaunt-pgwire-server", "oliphaunt-wasix", - "oliphaunt-wasix-tools", "rustix", - "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-wasix-seed-producer" +version = "0.0.0" +dependencies = [ + "anyhow", + "async-trait", + "serde", + "serde_json", + "tokio", + "wasmer", + "wasmer-wasix", + "webc", ] [[package]] name = "oliphaunt-wasix-tools" -version = "0.2.0" +version = "0.2.1" dependencies = [ "sha2 0.10.9", ] [[package]] name = "oliphaunt-wasix-tools-aot-aarch64-apple-darwin" -version = "0.2.0" +version = "0.2.1" dependencies = [ "serde_json", "sha2 0.10.9", @@ -2613,7 +2668,7 @@ dependencies = [ [[package]] name = "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu" -version = "0.2.0" +version = "0.2.1" dependencies = [ "serde_json", "sha2 0.10.9", @@ -2621,7 +2676,7 @@ dependencies = [ [[package]] name = "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc" -version = "0.2.0" +version = "0.2.1" dependencies = [ "serde_json", "sha2 0.10.9", @@ -2629,7 +2684,7 @@ dependencies = [ [[package]] name = "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu" -version = "0.2.0" +version = "0.2.1" dependencies = [ "serde_json", "sha2 0.10.9", @@ -2787,16 +2842,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.33" @@ -3186,20 +3231,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884" -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.17", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - [[package]] name = "rkyv" version = "0.8.16" @@ -3288,41 +3319,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "rustls" -version = "0.23.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" -dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - [[package]] name = "rustversion" version = "1.0.22" @@ -3409,6 +3405,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "self_cell" version = "1.2.2" @@ -3556,12 +3572,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" - [[package]] name = "simd-adler32" version = "0.3.9" @@ -3601,6 +3611,12 @@ dependencies = [ "serde", ] +[[package]] +name = "smawk" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e2fb0f499abb4d162f2bedad68f5ef91a1682b5a03596ddb67efd37768d100" + [[package]] name = "smoltcp" version = "0.13.1" @@ -3625,16 +3641,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "sqlx" version = "0.8.6" @@ -3759,6 +3765,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stringprep" version = "0.1.5" @@ -3828,6 +3840,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.13.2" @@ -3888,6 +3911,16 @@ dependencies = [ "libc", ] +[[package]] +name = "textwrap" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b81c0cb5fce14f53e49c1d4da0c508334ff12040221bb8ab01b2dabd91d04b6e" +dependencies = [ + "smawk", + "unicode-width", +] + [[package]] name = "thiserror" version = "2.0.18" @@ -4199,6 +4232,12 @@ version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -4206,38 +4245,136 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "unsafe-libyaml" -version = "0.2.11" +name = "uniffi" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +checksum = "edf78ecfb9bb8d7c4f8da11e8eb2ab6304e8ec0adb3ab32d8fc77c21a5bb0b86" +dependencies = [ + "anyhow", + "camino", + "clap", + "uniffi_bindgen", + "uniffi_core", + "uniffi_macros", + "uniffi_pipeline", +] [[package]] -name = "untrusted" -version = "0.9.0" +name = "uniffi_bindgen" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +checksum = "cdea7c4574723928bef87dfc04b203d96321d0bf34ab295a56379e633be579f3" +dependencies = [ + "anyhow", + "askama", + "camino", + "fs-err", + "glob", + "goblin", + "heck 0.5.0", + "indexmap", + "once_cell", + "serde", + "tempfile", + "textwrap", + "toml 1.1.2+spec-1.1.0", + "uniffi_internal_macros", + "uniffi_meta", + "uniffi_pipeline", + "uniffi_udl", +] [[package]] -name = "unty" -version = "0.0.4" +name = "uniffi_core" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" +checksum = "f8b1c62ee415b805f063c82e8ef6bbcaa1b87f8eed360cf217537b7724e05601" +dependencies = [ + "anyhow", + "bytes", + "once_cell", + "static_assertions", +] [[package]] -name = "ureq" -version = "2.12.1" +name = "uniffi_internal_macros" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +checksum = "c79d4a3129d6c2c15e367d3954886a0533dd3e85d445ce4d93379f62c6949d7b" dependencies = [ - "base64", - "log", + "anyhow", + "indexmap", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "uniffi_macros" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f6a9826a83f1140b2ec67c7944f562e1ef616e6eaf40e76247adccbd5b8a091" +dependencies = [ + "camino", + "fs-err", "once_cell", - "rustls", - "rustls-pki-types", - "url", - "webpki-roots 0.26.11", + "proc-macro2", + "quote", + "serde", + "syn 2.0.117", + "toml 1.1.2+spec-1.1.0", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf233eb014b595e8997c98df4ac6863b486a4ac6d54bd00230c7700753d7ef13" +dependencies = [ + "anyhow", + "siphasher", + "uniffi_internal_macros", + "uniffi_pipeline", +] + +[[package]] +name = "uniffi_pipeline" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55179706fbb6e7a23e729780d2c6165e6afe1ce725fa63754bcf217b440afc04" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap", + "tempfile", + "uniffi_internal_macros", +] + +[[package]] +name = "uniffi_udl" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421a9add7a19c5a264a2aba760514125ef3840a8b246ec88237fc91e3f2f79b1" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "weedle2", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "url" version = "2.5.8" @@ -5003,21 +5140,12 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.7", -] - -[[package]] -name = "webpki-roots" -version = "1.0.7" +name = "weedle2" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" dependencies = [ - "rustls-pki-types", + "nom 7.1.3", ] [[package]] @@ -5397,14 +5525,11 @@ dependencies = [ "serde_json", "sha2 0.10.9", "tar", - "tokio", "toml 0.9.12+spec-1.1.0", "walkdir", "wasmer", "wasmer-types", - "wasmer-wasix", "wasmparser 0.250.0", - "webc", "zstd", ] @@ -5478,12 +5603,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - [[package]] name = "zerotrie" version = "0.2.4" @@ -5517,41 +5636,12 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "zip" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" -dependencies = [ - "arbitrary", - "crc32fast", - "crossbeam-utils", - "displaydoc", - "flate2", - "indexmap", - "memchr", - "thiserror", - "zopfli", -] - [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" -[[package]] -name = "zopfli" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", -] - [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index 1cb30801a..071780e9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,27 +1,33 @@ [workspace] members = [ - "src/bindings/wasix-rust/crates/oliphaunt-wasix", - "src/sdks/rust/crates/oliphaunt-build", - "src/sdks/rust", - "src/runtimes/liboliphaunt/native/crates/tools", - "src/runtimes/broker", - "src/runtimes/liboliphaunt/icu", - "src/runtimes/liboliphaunt/wasix/crates/assets", - "src/runtimes/liboliphaunt/wasix/crates/tools", - "src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin", - "src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu", - "src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu", - "src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc", - "src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin", - "src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu", - "src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu", - "src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc", - "src/runtimes/wasix-napi", - "tools/perf/runner", - "tools/native-extension-proof", - "tools/native-packaging", - "tools/native-tools-proof", - "tools/xtask", + "src/sdks/ts/node-addon", + "src/sdks/rust/liboliphaunt-native", + "src/sdks/rust/mobile-bindings", + "src/sdks/rust-query", + "src/sdks/rust-wasix", + "src/sdks/rust/sdk/crates/oliphaunt-build", + "src/sdks/rust/sdk", + "src/postgres-tools/native/crates/tools", + "src/broker", + "src/pgwire-server", + "src/database-resources/icu/cargo", + "src/database-resources/seeds/wasix", + "src/runtimes/liboliphaunt-wasix/crates/assets", + "src/postgres-tools/wasix/crates/tools", + "src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin", + "src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu", + "src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu", + "src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc", + "src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin", + "src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu", + "src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu", + "src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc", + "src/sdks/ts-wasix/node-addon", + "src/benchmarks/perf/runner", + "src/extensions/tests/native", + "src/runtimes/liboliphaunt-native/packaging", + "src/postgres-tools/native/tests", + "src/runtimes/liboliphaunt-wasix/tools/xtask", ] resolver = "3" diff --git a/README.md b/README.md index 72de97513..901628fbc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Oliphaunt + Oliphaunt

@@ -111,19 +111,21 @@ surface: proto upgrade 0.61.3 proto install tools/dev/bootstrap-tools.sh -moon run dev-tools:doctor -moon run policy-tools:js-format-check policy-tools:rust-format-check -moon run :check :compile :format-check :lint :tools-compile --affected -moon run :test :unit :tools-unit --affected +moon query tasks --project oliphaunt-rust +moon run oliphaunt-rust:build oliphaunt-rust:test oliphaunt-rust:package ``` +Choose the project you are changing; its tasks own the required checks and +build tools. For workflow checks alone, `tools/dev/bootstrap-tools.sh --workflows` +installs Actionlint and Zizmor. The default also installs Prek and cargo-nextest. + For a product metadata change, also run the metadata gate: ```sh moon run release-tools:metadata ``` -Use `release-tools:unit`, `policy-tools:unit`, or `ci-workflows:check` when its +Use `release-tools:test` or `ci-workflows:check` when its corresponding machinery changes. Reserve `release-tools:check` for an exact release candidate. @@ -136,9 +138,9 @@ promote releases. - [Public SDK documentation](src/docs/content/sdk/index.mdx) - [Runtime support](src/docs/content/reference/capabilities.mdx) - [Exact extension model](src/docs/content/reference/extensions.mdx) -- [Source architecture](docs/architecture/final-product-source-architecture.md) -- [Maintainer documentation index](docs/maintainers/README.md) -- [Release process](docs/maintainers/release.md) +- [Source architecture](src/docs/architecture/final-product-source-architecture.md) +- [Maintainer documentation index](src/docs/maintainers/README.md) +- [Release process](src/docs/maintainers/release.md) - [Contributing](CONTRIBUTING.md) Oliphaunt is licensed under the terms recorded in [LICENSE](LICENSE). diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 731463208..bb902d42d 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -6,15 +6,15 @@ Oliphaunt source code in this repository is licensed under the MIT license in This file is the repository-level notice index. Product-specific runtime and packaging notices live next to the product that ships the relevant artifacts: -- `src/runtimes/liboliphaunt/native/THIRD_PARTY_NOTICES.md` -- `src/bindings/wasix-rust/THIRD_PARTY_NOTICES.md` +- `src/runtimes/liboliphaunt-native/THIRD_PARTY_NOTICES.md` +- `src/sdks/rust-wasix/THIRD_PARTY_NOTICES.md` Shared PostgreSQL source pins, third-party source pins, and extension metadata -are maintained in `src/postgres/versions/18/`, `src/sources/third-party/`, and +are maintained in `src/third-party/postgres/`, `src/third-party/`, and `src/extensions/`. Generated release artifacts must include the notices and exact pinned license bytes for every product and third-party component they ship. Canonical runtime license snapshots live in -`src/runtimes/liboliphaunt/licenses/`; their source pins and digests are -enforced by `tools/release/release-notices.mjs`. +`src/third-party/`; their source pins and digests are +enforced by `tools/packaging/release-notices.mts`. diff --git a/benchmarks/README.md b/benchmarks/README.md deleted file mode 100644 index d1522f112..000000000 --- a/benchmarks/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# Benchmarks - -Benchmark definitions, workload specs, baselines, and intentionally promoted -reports belong here. Executable benchmark harnesses stay under `tools/perf`. - -The long-term benchmark matrix should compare: - -- native PostgreSQL control; -- `liboliphaunt` direct mode; -- `oliphaunt` direct, broker, and server modes; -- SQLite baselines for comparable embedded workloads. - -The native `oliphaunt` matrix in -`tools/perf/matrix/run_native_oliphaunt_matrix.sh` now includes direct, broker, -server, native PostgreSQL, SQLite, streaming, direct/broker/server -prepared-update, native PostgreSQL prepared-update, resource, and artifact-size -rows. RTT report rows include p50/p90/p95/p99 tail latency. Prepared-update -report rows include fresh-process p50/p90/p95, native-PostgreSQL p90 ratios, -and command-level CPU/RSS/footprint. - -Current layout: - -- `native/sql/`: fixed SQL workloads used by native direct, broker, server, - native PostgreSQL, and SQLite comparison suites. -- `native/baselines/`: committed native baselines when promoted as release - evidence. -- `wasix/`: WASIX benchmark specs and baselines. -- `mobile/`: mobile benchmark specs and baselines. -- `reports/`: published reports promoted as release evidence. - -Tooling may live in `tools/` when it is an executable harness, but benchmark -plans, datasets, baselines, and published reports live here. diff --git a/benchmarks/mobile/README.md b/benchmarks/mobile/README.md deleted file mode 100644 index f5f9fb39e..000000000 --- a/benchmarks/mobile/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Mobile Benchmarks - -Mobile benchmark specs and baselines live here. Emulator, simulator, and device -orchestration stays under `tools/perf` and product-owned mobile tooling. diff --git a/benchmarks/native/README.md b/benchmarks/native/README.md deleted file mode 100644 index 3c9e0ce91..000000000 --- a/benchmarks/native/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Native Benchmarks - -Native benchmark specs live here. Runner code stays under `tools/perf`. - -- `sql/`: fixed SQL workload files used by native direct, broker, server, - native PostgreSQL, and SQLite comparison suites. -- `baselines/`: committed comparison baselines when a release intentionally - records them. diff --git a/benchmarks/wasix/README.md b/benchmarks/wasix/README.md deleted file mode 100644 index eb27e59c4..000000000 --- a/benchmarks/wasix/README.md +++ /dev/null @@ -1,145 +0,0 @@ -# WASIX Benchmarks - -WASIX benchmark specs and baselines live here. Runner implementations and -runtime orchestration stay under `tools/perf` and the WASIX product source tree. - -## Browser comparison - -`browser-pglite-memory-v2.json` defines two explicit comparisons against exact -PGlite 0.5.4. Oliphaunt's caller-owned root Promise API is measured against -PGlite's caller-realm API; Oliphaunt's explicit `/worker` entrypoint is measured -against PGlite's official Worker API. Both APIs in the direct pair return -promises, but Oliphaunt executes guest work in the calling realm while that -promise is pending. The plan and result record each surface's entry point, -calling contract, and execution owner separately, using the canonical `caller` -and `sdk-worker` ownership values, so Promise shape is not mistaken for -main-thread safety. - -```sh -pnpm --dir src/bindings/wasix-ts package:build -node tools/integration/wasix-ts/smoke-browser.mjs --benchmark -# or: moon run perf-tools:wasix-browser-measure -``` - -Build the portable WASIX runtime first with -`moon run liboliphaunt-wasix:runtime-portable`. Each comparison uses ephemeral -memory, rotates engine order between repetitions, performs an untimed -representative warmup, and retains every raw sample. It covers cold and warm -open, DDL, a 10,000-row set insert, parameterized point reads, indexed 100-row -ranges, aggregates, a decoded 10,000-row scan, a 100-statement transaction, -updates, deletes, and close latency. Exact row-count/checksum assertions and -PostgreSQL durability/WAL checks prevent faster-but-different work. For each -execution comparison independently, the command computes the geometric mean of -the median same-run Oliphaunt/PGlite ratios and requires it to be at most `0.80`. -The direct result therefore cannot subsidize the Worker result, or vice -versa. First cold open remains -descriptive because the implementations use different compilation caches; -close is descriptive because the public APIs make different worker-reclamation -guarantees; insert decomposition remains diagnostic so it cannot overweight the -primary insert workload. Machine-readable JSON and a compact Markdown report -are written under `target/perf`. Benchmark runs require a clean worktree and -record the exact Git commit and tree, runtime and staged host build identities, -the built SDK tree, every harness source, and the installed PGlite closure. - -For a harness smoke check without a full sample set, run: - -```sh -pnpm --dir src/bindings/wasix-ts package:build -node tools/integration/wasix-ts/smoke-browser.mjs --benchmark --quick -``` - -Quick mode still requires every workload assertion and durability/WAL parity, -but is explicitly ineligible for performance qualification. - -The explicit `/worker` OPFS path has a separate advisory comparison against -PGlite's OPFS access-handle-pool Worker path: - -```sh -node tools/integration/wasix-ts/smoke-browser.mjs --diagnostic-opfs --quick -``` - -It uses durable PostgreSQL settings on both Worker engines and prints the raw -configuration and medians. It is deliberately not evaluated with the -memory-only plan or its gate; the caller-owned direct comparison remains in -memory while the Worker comparison uses OPFS. - -## Node comparison - -`node-pglite-memory-v2.json` is the deterministic Node comparison plan for the -public `@oliphaunt/wasix-ts` package and the exact PGlite control named in the -plan. The executable harness lives in `tools/perf/wasix-node`. It compares the -real `@oliphaunt/wasix-ts/worker` entrypoint with a harness-owned PGlite Worker, -and the blocking `@oliphaunt/wasix-ts/direct` entrypoint with PGlite's -caller-realm API. Both use memory storage. The harness -alternates which engine runs first across ten fresh-process pairs per -comparison and gates them independently, so a strong isolated result cannot -hide a weak direct result or vice versa. Both Worker candidates own real Worker -threads, while Oliphaunt's Worker loads its synchronous Node-API `/direct` -placement. The direct comparison has matched execution -ownership and Promise-shaped public APIs; the plan and report separately record -that Oliphaunt performs guest work in the caller realm while its promise is -pending. - -Startup is one cold-to-first-result metric; public-open and -immediate-first-query components remain visible without receiving separate -gate weight. PGlite's published benchmark times `pg.exec()` inside a browser -worker. Its official worker library requires browser Worker and Web Locks APIs, -so this Node harness owns a deliberately small `worker_threads` RPC adapter and -times both public APIs end-to-end from the Node host, including exactly one -isolation RPC for each engine. PGlite's official benchmark methodology is -retained as provenance only: calls return public results without collecting or -serializing comparator-only internal timing. The caller-owned comparison times -both packages around their public Promise APIs and does not imply that either -implementation yields the caller realm while database work runs. - -Bulk timing sends identical PostgreSQL Simple Query bytes through both public -`execProtocolRaw` APIs and, in the Worker comparison, transfers both raw responses -across the worker edge. -The untimed verifier decodes the timed response's command tags and result rows, -then validates the resulting database state. Gate eligibility also requires -all recorded PostgreSQL settings to match across every candidate/control run. -Generated SQL is bounded by the compact row counts in the plan; upstream -generated benchmark files are not vendored. - -Validate the plan without runtime assets with -`moon run perf-tools:wasix-plan`. The uncached measurement deliberately does -not build its large native prerequisite. Stage the portable/AOT runtime, ICU, -and extension inputs, then build and smoke the optimized carrier for the -current host before running it: - -```sh -bash src/runtimes/wasix-napi/tools/build-native.sh -moon run perf-tools:wasix-node-measure -``` - -Each run writes machine-readable JSON -and a compact Markdown table under `target/perf`; it passes only when canonical -timed-response/result hashes and PostgreSQL settings agree and the geometric -mean of median paired Oliphaunt/PGlite ratios is at most `0.80`. Reports pin the -comparator tarball integrity and installed tree hash, and record the complete -resolved installed closure of each engine. The candidate package fixture also -requires its native carrier binary to match its recorded artifact provenance and -its embedded runtime module to match the canonical asset manifest and build -outputs. Reports record the carrier target, binary digest, artifact source, -payload build inputs, native Cargo profile, and full guest build-profile -signature. The checked-in plan rejects anything other than a non-incremental -one-codegen-unit native `release` build with thin LTO and the qualified guest -`release` profile with `-O2 -g0 -flto=thin`. - -For an advisory placement, raw-streaming, server, tool, event-loop, and RSS -comparison, build the staged SDK and runtime assets plus that optimized native -carrier, then run: - -```sh -pnpm --dir tools/perf/wasix-node bench:streaming -# exhaustive 1 KiB / 1 MiB / 64 MiB and 1 / 4 / 16 database profile -node tools/perf/wasix-node/streaming-quick.mjs --full --json -``` - -Its v3 report measures the default Rust actor, blocking `/direct`, and real -`/worker` placements separately. It reports p50/p95/p99 latency, actor and -Worker overhead relative to direct, streaming throughput and backpressure, and -representative event-loop and RSS observations. It is descriptive rather than -a qualification gate. This is also the canonical actor-versus-direct overhead -measurement; the PGlite gate above deliberately compares execution placements -with matched caller/Worker ownership. diff --git a/biome.json b/biome.json index 541a9a422..3f8d6eb24 100644 --- a/biome.json +++ b/biome.json @@ -2,55 +2,18 @@ "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json", "files": { "includes": [ - "package.json", - "biome.json", - "renovate.json", - ".markdownlint-cli2.jsonc", - "src/docs/package.json", - "src/docs/tsconfig.json", - "src/docs/src/**/*.ts", - "src/docs/src/**/*.tsx", - "src/docs/src/**/*.css", - "src/docs/mdx-components.tsx", - "src/docs/next.config.mjs", - "src/docs/postcss.config.mjs", - "src/docs/proxy.ts", - "src/docs/source.config.ts", - "src/docs/tools/**/*.mjs", - "src/sdks/react-native/package.json", - "src/sdks/react-native/typedoc.json", - "src/sdks/react-native/react-native.config.js", - "src/sdks/react-native/src/**/*.ts", - "src/sdks/react-native/src/**/*.tsx", - "src/sdks/js/package.json", - "src/sdks/js/typedoc.json", - "src/sdks/js/src/**/*.ts", - "src/shared/js-core/src/**/*.ts", - "src/bindings/wasix-ts/package.json", - "src/bindings/wasix-ts/src/**/*.ts", - "src/bindings/wasix-ts/tools-package/**/*.json", - "src/bindings/wasix-ts/tools-package/**/*.mjs", - "src/bindings/wasix-ts/tools-package/**/*.ts", - "examples/browser-wasix/**/*.ts", - "src/bindings/wasix-ts/tools/**/*.mjs", - "src/runtimes/liboliphaunt/native/tools-npm/package.json", - "src/runtimes/liboliphaunt/native/tools-npm/**/*.js", - "src/runtimes/liboliphaunt/native/tools-npm/**/*.ts", - "src/runtimes/liboliphaunt/native/tools/smoke-packed-tools-npm.mjs", - "tools/perf/matrix/**/*.json", - "tools/perf/matrix/**/*.ts", - "tools/perf/wasix-browser/**/*.mjs", - "tools/perf/wasix-browser/**/*.ts", - "tools/perf/wasix-node/**/*.mjs", - "tools/perf/wasix-node/package.json", - "tools/integration/**/*.mjs", - "tools/test/**/*.mjs", + "**", + "!**/generated", + "!**/vendor", "!**/node_modules", - "!**/lib", + "!**/target", "!**/dist", - "!**/.expo", - "!**/ios", - "!**/android" + "!**/.build", + "!**/.next", + "!**/.source", + "!**/Pods", + "!**/fixtures", + "!**/Fixtures" ] }, "formatter": { @@ -65,6 +28,7 @@ } }, "javascript": { + "globals": ["Bun", "Deno"], "formatter": { "quoteStyle": "single", "semicolons": "always", @@ -80,9 +44,29 @@ "enabled": true, "rules": { "recommended": true, + "correctness": { + "noUndeclaredVariables": "error" + }, "suspicious": { - "noExplicitAny": "off" + "noExplicitAny": "off", + "noImplicitAnyLet": "off", + "noControlCharactersInRegex": "off" } } - } + }, + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "overrides": [ + { + "includes": [ + "src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json" + ], + "formatter": { + "enabled": false + } + } + ] } diff --git a/bun.lock b/bun.lock new file mode 100644 index 000000000..08a35bdb4 --- /dev/null +++ b/bun.lock @@ -0,0 +1,3437 @@ +{ + "lockfileVersion": 2, + "configVersion": 1, + "workspaces": { + "": { + "name": "oliphaunt-monorepo", + "devDependencies": { + "@biomejs/biome": "2.4.16", + }, + }, + "src/benchmarks/perf/wasix-node": { + "name": "@oliphaunt/perf-wasix-node", + "version": "0.0.0", + "dependencies": { + "@electric-sql/pglite": "0.5.4", + }, + }, + "src/broker/packages/darwin-arm64": { + "name": "@oliphaunt/broker-darwin-arm64", + "version": "0.2.0", + }, + "src/broker/packages/linux-arm64-gnu": { + "name": "@oliphaunt/broker-linux-arm64-gnu", + "version": "0.2.0", + }, + "src/broker/packages/linux-x64-gnu": { + "name": "@oliphaunt/broker-linux-x64-gnu", + "version": "0.2.0", + }, + "src/broker/packages/win32-x64-msvc": { + "name": "@oliphaunt/broker-win32-x64-msvc", + "version": "0.2.0", + }, + "src/database-resources/icu/npm": { + "name": "@oliphaunt/icu", + "version": "0.2.1", + }, + "src/docs": { + "name": "@oliphaunt/docs", + "version": "0.0.0", + "dependencies": { + "@mdx-js/react": "^3.1.0", + "clsx": "^2.1.1", + "fumadocs-core": "16.9.3", + "fumadocs-mdx": "15.0.10", + "fumadocs-ui": "16.9.3", + "lucide-react": "^1.17.0", + "motion": "13.1.0", + "next": "16.2.7", + "react": "19.2.7", + "react-dom": "19.2.7", + "simple-icons": "16.28.0", + "tailwind-merge": "^3.6.0", + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.3.0", + "@types/mdx": "^2.0.13", + "@types/node": "22.19.19", + "@types/react": "19.2.16", + "@types/react-dom": "^19.2.3", + "postcss": "^8.5.15", + "tailwindcss": "4.3.0", + "typescript": "^5.9.3", + }, + }, + "src/examples/browser-wasix": { + "name": "oliphaunt-example-browser-wasix", + "version": "0.0.0", + "devDependencies": { + "@electric-sql/pglite": "0.5.4", + "@types/node": "^24.10.1", + "typescript": "catalog:", + "vite": "^6.0.3", + }, + }, + "src/examples/react-native-expo": { + "name": "react-native-oliphaunt-expo", + "version": "0.0.0", + "dependencies": { + "@oliphaunt/react-native": "workspace:*", + "expo": "~56.0.15", + "expo-dev-client": "~56.0.22", + "expo-splash-screen": "~56.0.12", + "expo-sqlite": "~56.0.5", + "expo-system-ui": "~56.0.5", + "react": "19.2.3", + "react-dom": "19.2.3", + "react-native": "0.85.3", + "react-native-safe-area-context": "~5.7.0", + "react-native-web": "~0.21.0", + }, + "devDependencies": { + "@react-native-community/cli": "20.2.0", + "@react-native-community/cli-platform-android": "20.2.0", + "@react-native-community/cli-platform-ios": "20.2.0", + "@react-native/metro-config": "0.85.3", + "@types/react": "19.2.16", + "eslint": "^9.0.0", + "eslint-config-expo": "~56.0.4", + "expo-doctor": "^1.19.7", + "expo-mcp": "~0.2.1", + "typescript": "~6.0.3", + }, + }, + "src/postgres-tools/native/npm": { + "name": "@oliphaunt/tools", + "version": "0.2.1", + "optionalDependencies": { + "@oliphaunt/tools-darwin-arm64": "workspace:0.2.0", + "@oliphaunt/tools-linux-arm64-gnu": "workspace:0.2.0", + "@oliphaunt/tools-linux-x64-gnu": "workspace:0.2.0", + "@oliphaunt/tools-win32-x64-msvc": "workspace:0.2.0", + }, + }, + "src/postgres-tools/native/npm-platforms/darwin-arm64": { + "name": "@oliphaunt/tools-darwin-arm64", + "version": "0.2.1", + }, + "src/postgres-tools/native/npm-platforms/linux-arm64-gnu": { + "name": "@oliphaunt/tools-linux-arm64-gnu", + "version": "0.2.1", + }, + "src/postgres-tools/native/npm-platforms/linux-x64-gnu": { + "name": "@oliphaunt/tools-linux-x64-gnu", + "version": "0.2.1", + }, + "src/postgres-tools/native/npm-platforms/win32-x64-msvc": { + "name": "@oliphaunt/tools-win32-x64-msvc", + "version": "0.2.1", + }, + "src/postgres-tools/wasix/npm": { + "name": "@oliphaunt/liboliphaunt-wasix-tools", + "version": "0.2.1", + "optionalDependencies": { + "@oliphaunt/liboliphaunt-wasix-tools-darwin-arm64": "workspace:*", + "@oliphaunt/liboliphaunt-wasix-tools-linux-arm64-gnu": "workspace:*", + "@oliphaunt/liboliphaunt-wasix-tools-linux-x64-gnu": "workspace:*", + "@oliphaunt/liboliphaunt-wasix-tools-win32-x64-msvc": "workspace:*", + }, + }, + "src/postgres-tools/wasix/npm-platforms/darwin-arm64": { + "name": "@oliphaunt/liboliphaunt-wasix-tools-darwin-arm64", + "version": "0.2.1", + }, + "src/postgres-tools/wasix/npm-platforms/linux-arm64-gnu": { + "name": "@oliphaunt/liboliphaunt-wasix-tools-linux-arm64-gnu", + "version": "0.2.1", + }, + "src/postgres-tools/wasix/npm-platforms/linux-x64-gnu": { + "name": "@oliphaunt/liboliphaunt-wasix-tools-linux-x64-gnu", + "version": "0.2.1", + }, + "src/postgres-tools/wasix/npm-platforms/win32-x64-msvc": { + "name": "@oliphaunt/liboliphaunt-wasix-tools-win32-x64-msvc", + "version": "0.2.1", + }, + "src/postgres-tools/wasix/ts": { + "name": "@oliphaunt/wasix-tools", + "version": "0.2.1", + "dependencies": { + "@oliphaunt/liboliphaunt-wasix-tools": "workspace:*", + }, + "devDependencies": { + "@oliphaunt/wasix-ts": "workspace:*", + "@types/bun": "catalog:", + "@types/node": "^24.10.1", + "typescript": "catalog:", + }, + "peerDependencies": { + "@oliphaunt/wasix-ts": "workspace:*", + }, + }, + "src/runtimes/liboliphaunt-native/packages/darwin-arm64": { + "name": "@oliphaunt/liboliphaunt-darwin-arm64", + "version": "0.2.0", + }, + "src/runtimes/liboliphaunt-native/packages/linux-arm64-gnu": { + "name": "@oliphaunt/liboliphaunt-linux-arm64-gnu", + "version": "0.2.0", + }, + "src/runtimes/liboliphaunt-native/packages/linux-x64-gnu": { + "name": "@oliphaunt/liboliphaunt-linux-x64-gnu", + "version": "0.2.0", + }, + "src/runtimes/liboliphaunt-native/packages/win32-x64-msvc": { + "name": "@oliphaunt/liboliphaunt-win32-x64-msvc", + "version": "0.2.0", + }, + "src/sdks/react-native": { + "name": "@oliphaunt/react-native", + "version": "0.2.0", + "dependencies": { + "@oliphaunt/ts-query": "0.1.0", + }, + "devDependencies": { + "@react-native/codegen": "^0.85.3", + "@react-native/typescript-config": "^0.85.0", + "@types/bun": "catalog:", + "@types/node": "^24.10.1", + "react": "^19.2.0", + "react-native": "^0.85.0", + "typescript": "catalog:", + }, + "peerDependencies": { + "expo": ">=56.0.0", + "react": ">=19.0.0", + "react-native": ">=0.85.0", + }, + "optionalPeers": [ + "expo", + ], + }, + "src/sdks/ts-query": { + "name": "@oliphaunt/ts-query", + "version": "0.1.0", + "devDependencies": { + "@types/node": "^24.10.1", + "typescript": "catalog:", + }, + }, + "src/sdks/ts-wasix/node-addon": { + "name": "@oliphaunt/wasix-napi", + "version": "0.1.0", + }, + "src/sdks/ts-wasix/node-addon/packages/darwin-arm64": { + "name": "@oliphaunt/wasix-napi-darwin-arm64", + "version": "0.1.0", + }, + "src/sdks/ts-wasix/node-addon/packages/linux-arm64-gnu": { + "name": "@oliphaunt/wasix-napi-linux-arm64-gnu", + "version": "0.1.0", + }, + "src/sdks/ts-wasix/node-addon/packages/linux-x64-gnu": { + "name": "@oliphaunt/wasix-napi-linux-x64-gnu", + "version": "0.1.0", + }, + "src/sdks/ts-wasix/node-addon/packages/win32-x64-msvc": { + "name": "@oliphaunt/wasix-napi-win32-x64-msvc", + "version": "0.1.0", + }, + "src/sdks/ts-wasix/sdk": { + "name": "@oliphaunt/wasix-ts", + "version": "0.1.0", + "dependencies": { + "@oliphaunt/ts-query": "0.1.0", + "fzstd": "0.1.1", + }, + "devDependencies": { + "@electric-sql/pglite": "0.5.4", + "@types/bun": "catalog:", + "@types/node": "^24.10.1", + "typescript": "catalog:", + "vite": "^6.0.3", + }, + "optionalDependencies": { + "@oliphaunt/wasix-napi-darwin-arm64": "workspace:*", + "@oliphaunt/wasix-napi-linux-arm64-gnu": "workspace:*", + "@oliphaunt/wasix-napi-linux-x64-gnu": "workspace:*", + "@oliphaunt/wasix-napi-win32-x64-msvc": "workspace:*", + }, + }, + "src/sdks/ts/node-addon": { + "name": "@oliphaunt/node-direct", + "version": "0.2.0", + }, + "src/sdks/ts/node-addon/packages/darwin-arm64": { + "name": "@oliphaunt/node-direct-darwin-arm64", + "version": "0.2.0", + }, + "src/sdks/ts/node-addon/packages/linux-arm64-gnu": { + "name": "@oliphaunt/node-direct-linux-arm64-gnu", + "version": "0.2.0", + }, + "src/sdks/ts/node-addon/packages/linux-x64-gnu": { + "name": "@oliphaunt/node-direct-linux-x64-gnu", + "version": "0.2.0", + }, + "src/sdks/ts/node-addon/packages/win32-x64-msvc": { + "name": "@oliphaunt/node-direct-win32-x64-msvc", + "version": "0.2.0", + }, + "src/sdks/ts/sdk": { + "name": "@oliphaunt/ts", + "version": "0.2.0", + "dependencies": { + "@oliphaunt/ts-query": "0.1.0", + }, + "devDependencies": { + "@types/bun": "catalog:", + "@types/node": "^24.10.1", + "@types/pg": "^8.15.6", + "pg": "^8.16.3", + "typescript": "catalog:", + }, + "optionalDependencies": { + "@oliphaunt/broker-darwin-arm64": "workspace:*", + "@oliphaunt/broker-linux-arm64-gnu": "workspace:*", + "@oliphaunt/broker-linux-x64-gnu": "workspace:*", + "@oliphaunt/broker-win32-x64-msvc": "workspace:*", + "@oliphaunt/liboliphaunt-darwin-arm64": "workspace:*", + "@oliphaunt/liboliphaunt-linux-arm64-gnu": "workspace:*", + "@oliphaunt/liboliphaunt-linux-x64-gnu": "workspace:*", + "@oliphaunt/liboliphaunt-win32-x64-msvc": "workspace:*", + "@oliphaunt/node-direct-darwin-arm64": "workspace:*", + "@oliphaunt/node-direct-linux-arm64-gnu": "workspace:*", + "@oliphaunt/node-direct-linux-x64-gnu": "workspace:*", + "@oliphaunt/node-direct-win32-x64-msvc": "workspace:*", + }, + }, + "tools/release": { + "name": "@oliphaunt/release-tools", + "dependencies": { + "release-please": "17.3.0", + }, + }, + }, + "trustedDependencies": [ + "esbuild", + "sharp", + "unrs-resolver", + ], + "overrides": { + "esbuild": "0.28.1", + "js-yaml": "4.3.0", + "postcss": "8.5.15", + "uuid": "11.1.1", + }, + "catalog": { + "@types/bun": "1.4.2", + "typescript": "^6.0.3", + }, + "packages": { + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "7.28.5", "js-tokens": "4.0.0", "picocolors": "1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + + "@babel/compat-data": ["@babel/compat-data@7.29.3", "", {}, "sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg=="], + + "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/generator": "7.29.1", "@babel/helper-compilation-targets": "7.28.6", "@babel/helper-module-transforms": "7.28.6", "@babel/helpers": "7.29.2", "@babel/parser": "7.29.3", "@babel/template": "7.28.6", "@babel/traverse": "7.29.0", "@babel/types": "7.29.0", "@jridgewell/remapping": "2.3.5", "convert-source-map": "2.0.0", "debug": "4.4.3", "gensync": "1.0.0-beta.2", "json5": "2.2.3", "semver": "6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + + "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "7.29.3", "@babel/types": "7.29.0", "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31", "jsesc": "3.1.0" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], + + "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "7.29.0" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "7.29.3", "@babel/helper-validator-option": "7.27.1", "browserslist": "4.28.2", "lru-cache": "5.1.1", "semver": "6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], + + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.29.3", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-member-expression-to-functions": "7.28.5", "@babel/helper-optimise-call-expression": "7.27.1", "@babel/helper-replace-supers": "7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "7.27.1", "@babel/traverse": "7.29.0", "semver": "6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-RpLYy2sb51oNLjuu1iD3bwBqCBWUzjO0ocp+iaCP/lJtb2CPLcnC2Fftw+4sAzaMELGeWTgExSKADbdo0GFVzA=="], + + "@babel/helper-create-regexp-features-plugin": ["@babel/helper-create-regexp-features-plugin@7.28.5", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "regexpu-core": "6.4.0", "semver": "6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw=="], + + "@babel/helper-define-polyfill-provider": ["@babel/helper-define-polyfill-provider@0.6.8", "", { "dependencies": { "@babel/helper-compilation-targets": "7.28.6", "@babel/helper-plugin-utils": "7.29.7", "debug": "4.4.3", "lodash.debounce": "4.0.8", "resolve": "1.22.12" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + + "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "7.28.6", "@babel/helper-validator-identifier": "7.28.5", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], + + "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "7.29.0" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.29.7", "", {}, "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw=="], + + "@babel/helper-remap-async-to-generator": ["@babel/helper-remap-async-to-generator@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-wrap-function": "7.28.6", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA=="], + + "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.28.6", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "7.28.5", "@babel/helper-optimise-call-expression": "7.27.1", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg=="], + + "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + + "@babel/helper-wrap-function": ["@babel/helper-wrap-function@7.28.6", "", { "dependencies": { "@babel/template": "7.28.6", "@babel/traverse": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ=="], + + "@babel/helpers": ["@babel/helpers@7.29.2", "", { "dependencies": { "@babel/template": "7.28.6", "@babel/types": "7.29.0" } }, "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw=="], + + "@babel/parser": ["@babel/parser@7.29.3", "", { "dependencies": { "@babel/types": "7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA=="], + + "@babel/plugin-proposal-decorators": ["@babel/plugin-proposal-decorators@7.29.0", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "7.29.3", "@babel/helper-plugin-utils": "7.29.7", "@babel/plugin-syntax-decorators": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA=="], + + "@babel/plugin-proposal-export-default-from": ["@babel/plugin-proposal-export-default-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw=="], + + "@babel/plugin-syntax-decorators": ["@babel/plugin-syntax-decorators@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA=="], + + "@babel/plugin-syntax-dynamic-import": ["@babel/plugin-syntax-dynamic-import@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ=="], + + "@babel/plugin-syntax-export-default-from": ["@babel/plugin-syntax-export-default-from@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Svlx1fjJFnNz0LZeUaybRukSxZI3KkpApUmIRzEdXC5k8ErTOz0OD0kNrICi5Vc3GlpP5ZCeRyRO+mfWTSz+iQ=="], + + "@babel/plugin-syntax-flow": ["@babel/plugin-syntax-flow@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew=="], + + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="], + + "@babel/plugin-syntax-nullish-coalescing-operator": ["@babel/plugin-syntax-nullish-coalescing-operator@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ=="], + + "@babel/plugin-syntax-optional-chaining": ["@babel/plugin-syntax-optional-chaining@7.8.3", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg=="], + + "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A=="], + + "@babel/plugin-transform-async-generator-functions": ["@babel/plugin-transform-async-generator-functions@7.29.0", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7", "@babel/helper-remap-async-to-generator": "7.27.1", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w=="], + + "@babel/plugin-transform-async-to-generator": ["@babel/plugin-transform-async-to-generator@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "7.28.6", "@babel/helper-plugin-utils": "7.29.7", "@babel/helper-remap-async-to-generator": "7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g=="], + + "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw=="], + + "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.28.6", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "7.29.3", "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw=="], + + "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.6", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "7.29.3", "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ=="], + + "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-compilation-targets": "7.28.6", "@babel/helper-globals": "7.28.0", "@babel/helper-plugin-utils": "7.28.6", "@babel/helper-replace-supers": "7.28.6", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q=="], + + "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="], + + "@babel/plugin-transform-export-namespace-from": ["@babel/plugin-transform-export-namespace-from@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ=="], + + "@babel/plugin-transform-flow-strip-types": ["@babel/plugin-transform-flow-strip-types@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7", "@babel/plugin-syntax-flow": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg=="], + + "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="], + + "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A=="], + + "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.28.6", "", { "dependencies": { "@babel/helper-module-transforms": "7.28.6", "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA=="], + + "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.29.0", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "7.28.5", "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ=="], + + "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg=="], + + "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.6", "", { "dependencies": { "@babel/helper-compilation-targets": "7.28.6", "@babel/helper-plugin-utils": "7.29.7", "@babel/plugin-transform-destructuring": "7.28.5", "@babel/plugin-transform-parameters": "7.27.7", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA=="], + + "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ=="], + + "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w=="], + + "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="], + + "@babel/plugin-transform-private-methods": ["@babel/plugin-transform-private-methods@7.28.6", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "7.29.3", "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg=="], + + "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-create-class-features-plugin": "7.29.3", "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA=="], + + "@babel/plugin-transform-react-display-name": ["@babel/plugin-transform-react-display-name@7.28.0", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA=="], + + "@babel/plugin-transform-react-jsx": ["@babel/plugin-transform-react-jsx@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-module-imports": "7.28.6", "@babel/helper-plugin-utils": "7.29.7", "@babel/plugin-syntax-jsx": "7.28.6", "@babel/types": "7.29.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow=="], + + "@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="], + + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw=="], + + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q=="], + + "@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="], + + "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw=="], + + "@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.29.0", "", { "dependencies": { "@babel/helper-module-imports": "7.28.6", "@babel/helper-plugin-utils": "7.29.7", "babel-plugin-polyfill-corejs2": "0.4.17", "babel-plugin-polyfill-corejs3": "0.13.0", "babel-plugin-polyfill-regenerator": "0.6.8", "semver": "6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w=="], + + "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-create-class-features-plugin": "7.29.3", "@babel/helper-plugin-utils": "7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "7.27.1", "@babel/plugin-syntax-typescript": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw=="], + + "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "7.28.5", "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="], + + "@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6", "@babel/helper-validator-option": "7.27.1", "@babel/plugin-syntax-jsx": "7.28.6", "@babel/plugin-transform-modules-commonjs": "7.28.6", "@babel/plugin-transform-typescript": "7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="], + + "@babel/runtime": ["@babel/runtime@7.29.2", "", {}, "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g=="], + + "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/parser": "7.29.3", "@babel/types": "7.29.0" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], + + "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/generator": "7.29.1", "@babel/helper-globals": "7.28.0", "@babel/parser": "7.29.3", "@babel/template": "7.28.6", "@babel/types": "7.29.0", "debug": "4.4.3" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], + + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "7.27.1", "@babel/helper-validator-identifier": "7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + + "@biomejs/biome": ["@biomejs/biome@2.4.16", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.16", "@biomejs/cli-darwin-x64": "2.4.16", "@biomejs/cli-linux-arm64": "2.4.16", "@biomejs/cli-linux-arm64-musl": "2.4.16", "@biomejs/cli-linux-x64": "2.4.16", "@biomejs/cli-linux-x64-musl": "2.4.16", "@biomejs/cli-win32-arm64": "2.4.16", "@biomejs/cli-win32-x64": "2.4.16" }, "bin": { "biome": "bin/biome" } }, "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.16", "", { "os": "win32", "cpu": "x64" }, "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw=="], + + "@conventional-commits/parser": ["@conventional-commits/parser@0.4.1", "", { "dependencies": { "unist-util-visit": "^2.0.3", "unist-util-visit-parents": "^3.1.1" } }, "sha512-H2ZmUVt6q+KBccXfMBhbBF14NlANeqHTXL4qCL6QGbMzrc4HDXyzWuxPxPNbz71f/5UkR5DrycP5VO9u7crahg=="], + + "@electric-sql/pglite": ["@electric-sql/pglite@0.5.4", "", {}, "sha512-yYZUyyXrHU7tPlCjwZQJ6hIG9DscdCCn7Uk0mYKwC1FeHX286AbcmFveMiRBEak8e9iPupjsoVImN3yJZVed2g=="], + + "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "2.8.1" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], + + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.28.1", "", { "os": "android", "cpu": "arm" }, "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.1", "", { "os": "android", "cpu": "arm64" }, "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.28.1", "", { "os": "android", "cpu": "x64" }, "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.1", "", { "os": "linux", "cpu": "arm" }, "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.1", "", { "os": "linux", "cpu": "x64" }, "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.1", "", { "os": "none", "cpu": "x64" }, "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.1", "", { "os": "win32", "cpu": "x64" }, "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "2.1.7", "debug": "4.4.3", "minimatch": "3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], + + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.5", "", { "dependencies": { "ajv": "6.15.0", "debug": "4.4.3", "espree": "10.4.0", "globals": "14.0.0", "ignore": "5.3.2", "import-fresh": "3.3.1", "js-yaml": "4.3.0", "minimatch": "3.1.5", "strip-json-comments": "3.1.1" } }, "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg=="], + + "@eslint/js": ["@eslint/js@9.39.4", "", {}, "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "0.17.0", "levn": "0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], + + "@expo/cli": ["@expo/cli@56.1.19", "", { "dependencies": { "@expo/code-signing-certificates": "0.0.6", "@expo/config": "56.0.11", "@expo/config-plugins": "56.0.12", "@expo/devcert": "1.2.1", "@expo/env": "2.3.1", "@expo/image-utils": "0.10.2", "@expo/inline-modules": "0.0.13", "@expo/json-file": "10.2.0", "@expo/log-box": "56.0.14", "@expo/metro": "56.0.0", "@expo/metro-config": "56.0.16", "@expo/metro-file-map": "56.0.3", "@expo/osascript": "2.6.0", "@expo/package-manager": "1.13.0", "@expo/plist": "0.7.0", "@expo/prebuild-config": "56.0.19", "@expo/require-utils": "56.1.4", "@expo/router-server": "56.0.16", "@expo/schema-utils": "56.0.2", "@expo/spawn-async": "1.8.0", "@expo/ws-tunnel": "2.0.0", "@expo/xcpretty": "4.4.4", "@react-native/dev-middleware": "0.85.3", "accepts": "1.3.8", "agent-cli-detector": "0.1.2", "arg": "5.0.2", "bplist-creator": "0.1.0", "bplist-parser": "0.3.2", "chalk": "4.1.2", "ci-info": "3.9.0", "compression": "1.8.1", "connect": "3.7.0", "debug": "4.4.3", "dnssd-advertise": "1.1.6", "expo-server": "56.0.5", "fetch-nodeshim": "0.4.10", "getenv": "2.0.0", "glob": "13.0.6", "lan-network": "0.2.1", "multitars": "1.0.0", "node-forge": "1.4.0", "npm-package-arg": "11.0.3", "ora": "3.4.0", "picomatch": "4.0.4", "pretty-format": "29.7.0", "progress": "2.0.3", "prompts": "2.4.2", "resolve-from": "5.0.0", "semver": "7.8.1", "send": "0.19.2", "slugify": "1.6.9", "stacktrace-parser": "0.1.11", "structured-headers": "0.4.1", "terminal-link": "2.1.1", "toqr": "0.1.1", "wrap-ansi": "7.0.0", "ws": "8.21.0", "zod": "3.25.76" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "main.js" } }, "sha512-k+oipwbu83WFnACtybvGZvDbbItarY4lfjkKgP9F5lml2ilvL/VvzsPhbhT7nRyFB3zPJq9SbNNKa45VDLoihA=="], + + "@expo/code-signing-certificates": ["@expo/code-signing-certificates@0.0.6", "", { "dependencies": { "node-forge": "1.4.0" } }, "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w=="], + + "@expo/config": ["@expo/config@56.0.11", "", { "dependencies": { "@expo/config-plugins": "56.0.12", "@expo/config-types": "56.0.7", "@expo/json-file": "10.2.0", "@expo/require-utils": "56.1.4", "deepmerge": "4.3.1", "getenv": "2.0.0", "glob": "13.0.6", "resolve-workspace-root": "2.0.1", "semver": "7.8.1", "slugify": "1.6.9" } }, "sha512-Rt3U9Rqr6midz/sDeubFN5fefR0KzHpcEEgAUnV98XsLSSTnfzIxoC1blICb7pUUscKc8TtlVyn7/Gita2wnOQ=="], + + "@expo/config-plugins": ["@expo/config-plugins@56.0.12", "", { "dependencies": { "@expo/config-types": "56.0.7", "@expo/json-file": "10.2.0", "@expo/plist": "0.7.0", "@expo/require-utils": "56.1.4", "@expo/sdk-runtime-versions": "1.0.0", "chalk": "4.1.2", "debug": "4.4.3", "getenv": "2.0.0", "glob": "13.0.6", "semver": "7.8.1", "slugify": "1.6.9", "xcode": "3.0.1", "xml2js": "0.6.0" } }, "sha512-UKjPEOkvxBzTvjghmjUECURDoJLPJIFIevB0JQCe8l9Fg4yfy2fabU5LU3Kfrmmu1/8et/93bucCnABEmoxYEw=="], + + "@expo/config-types": ["@expo/config-types@56.0.7", "", {}, "sha512-V7bxawNsNned/yMppAHdisIOxniZXgPKRWpIUiQOQBs45/A5MBd2gfDM4Ecq5gnbilnQUTaI6Zxn6JcW7L3TAA=="], + + "@expo/devcert": ["@expo/devcert@1.2.1", "", { "dependencies": { "@expo/sudo-prompt": "9.3.2", "debug": "3.2.7" } }, "sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA=="], + + "@expo/devtools": ["@expo/devtools@56.0.2", "", { "dependencies": { "chalk": "4.1.2" }, "peerDependencies": { "react": "*", "react-native": "*" }, "optionalPeers": ["react", "react-native"] }, "sha512-ANl4kPdbe0/HQYWkDEN79S6bQhI+i/ZCnPxuC853pPsB4svhINC7Ku9lmGOKPsUUWWnrHg1spkDGQBZ4sD6JxQ=="], + + "@expo/dom-webview": ["@expo/dom-webview@56.0.6", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-DQY3Tj5nrPbpIfEQiD9xbyEFTu25yEORa02Eyzl5rXszDzxDT4VkZDHkyErNQOyE1qjublJHNFhE5bDm4tRfqA=="], + + "@expo/env": ["@expo/env@2.3.1", "", { "dependencies": { "chalk": "4.1.2", "debug": "4.4.3", "getenv": "2.0.0" } }, "sha512-JvBdZa5OkTd+dGEtt3fLW9OF6RlIp9SNu9VyMSiWPV5szMDTSAYbX8Uj3cRvZcU1zzaRbqnTSsHk2AE8WXHfxQ=="], + + "@expo/expo-modules-macros-plugin": ["@expo/expo-modules-macros-plugin@0.2.2", "", {}, "sha512-4IMzPDIo/VOXREQjsJtliSfqYVZvfzU2SLFS/9sKMWF848S8CHx+e/E+Vf0TcMvpWCCKX5umyqxb13KJJ+YUzg=="], + + "@expo/fingerprint": ["@expo/fingerprint@0.19.7", "", { "dependencies": { "@expo/env": "2.4.1", "@expo/spawn-async": "1.8.0", "arg": "5.0.2", "chalk": "4.1.2", "debug": "4.4.3", "getenv": "2.0.0", "glob": "13.0.6", "ignore": "5.3.2", "minimatch": "10.2.5", "resolve-from": "5.0.0", "semver": "7.8.1" }, "bin": { "fingerprint": "bin/cli.js" } }, "sha512-Q04NyJE0E7qKGXepBjI8e0p983RrQGBWJcSICKyyLczsr5JhNuSmqw604aL7koaXG2ctrUL36qd332XiMS/s6w=="], + + "@expo/image-utils": ["@expo/image-utils@0.10.2", "", { "dependencies": { "@expo/require-utils": "56.1.4", "@expo/spawn-async": "1.8.0", "chalk": "4.1.2", "getenv": "2.0.0", "jimp-compact": "0.16.1", "parse-png": "2.1.0", "semver": "7.8.1" } }, "sha512-qQUGaacqXduoFTCUQAMceIWYzlKU0xX4/BKTyh8TdVj0uHv9/W3MfHOy5yXoOqBVrSccXk++Gm4D/NfS5HnCNA=="], + + "@expo/inline-modules": ["@expo/inline-modules@0.0.13", "", { "dependencies": { "@expo/config-plugins": "56.0.12" } }, "sha512-26RllWesRmYsAAo70cRcR9DaqXPKJct9MIGxZteS+Tkg25ljOkFeG7fYEsSazZOLpAslKBiilqtZykVYrxSzCw=="], + + "@expo/json-file": ["@expo/json-file@10.2.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "json5": "2.2.3" } }, "sha512-S6XzKe3R9GQeHiUPXc3xJjOv2VJhOEwFYf7xdC2z2cUqt3kZJ9mSO877sNQloVdnW/SUCtPY3bexlM7nwq+CAQ=="], + + "@expo/local-build-cache-provider": ["@expo/local-build-cache-provider@56.0.9", "", { "dependencies": { "@expo/config": "56.0.11", "chalk": "4.1.2" } }, "sha512-VMJC5ul7dXPfD2OO16ObPi6ym4H8vlnCBUuCM/KeKh0OvLRub35X8OB2uYrFQ+vbWkPemAEOWvk0oOptpPxbzA=="], + + "@expo/log-box": ["@expo/log-box@56.0.14", "", { "dependencies": { "@expo/dom-webview": "56.0.6", "anser": "1.4.10", "stacktrace-parser": "0.1.11" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-3Eadcxz0J2NESG2iKe8DnAggsRCWqY0mBLhgQPNzClPVjS6o4NyD0F8kuOvWNngFwpJBC08HhY2o8P1mgSgeJg=="], + + "@expo/mcp-tunnel": ["@expo/mcp-tunnel@0.2.4", "", { "dependencies": { "ws": "8.21.0", "zod": "3.25.76", "zod-to-json-schema": "3.25.2" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.26.0" } }, "sha512-hxFzqdUNKCt+8pbGV3oGcd/aBNA1mmhwh3DSeXoHReypxzsiLYLITJs1OctglaPecfMA9qFb+6z/RIkRSf5S4g=="], + + "@expo/metro": ["@expo/metro@56.0.0", "", { "dependencies": { "metro": "0.84.4", "metro-babel-transformer": "0.84.4", "metro-cache": "0.84.4", "metro-cache-key": "0.84.4", "metro-config": "0.84.4", "metro-core": "0.84.4", "metro-file-map": "0.84.4", "metro-minify-terser": "0.84.4", "metro-resolver": "0.84.4", "metro-runtime": "0.84.4", "metro-source-map": "0.84.4", "metro-symbolicate": "0.84.4", "metro-transform-plugins": "0.84.4", "metro-transform-worker": "0.84.4" } }, "sha512-5gIgQHtEpjjvsjKfVtIv23a98LLRV0/y07PDShEwYSytAMlE3FSF8RHXqtHc1sUJL6dn7hnuIBpIbrLXXuVi0A=="], + + "@expo/metro-config": ["@expo/metro-config@56.0.16", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/core": "7.29.0", "@babel/generator": "7.29.1", "@expo/config": "56.0.11", "@expo/env": "2.3.1", "@expo/json-file": "10.2.0", "@expo/metro": "56.0.0", "@expo/require-utils": "56.1.4", "@expo/spawn-async": "1.8.0", "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/remapping": "2.3.5", "@jridgewell/sourcemap-codec": "1.5.5", "browserslist": "4.28.2", "chalk": "4.1.2", "debug": "4.4.3", "getenv": "2.0.0", "glob": "13.0.6", "hermes-parser": "0.33.3", "jsc-safe-url": "0.2.4", "lightningcss": "1.32.0", "picomatch": "4.0.4", "postcss": "8.5.15", "resolve-from": "5.0.0" }, "peerDependencies": { "expo": "*" }, "optionalPeers": ["expo"] }, "sha512-mxPZ23exC6kkEpPYQOteamaiWYER3uDk2IqKys7EJwtIKc3F1207Xtsdko/DNNG04DLwpN/WM2UlNl+Ak8uPRg=="], + + "@expo/metro-file-map": ["@expo/metro-file-map@56.0.3", "", { "dependencies": { "debug": "4.4.3", "fb-watchman": "2.0.2", "invariant": "2.2.4", "jest-worker": "29.7.0", "micromatch": "4.0.8", "walker": "1.0.8" } }, "sha512-5OGW3z8LgEYgMJOR7F3pC8llFLkb1fVqwAewbCl6S4Vkha8AFQMwOjT+9Wbka+V4rmpljpGqOnMhF4xZbD961w=="], + + "@expo/osascript": ["@expo/osascript@2.6.0", "", { "dependencies": { "@expo/spawn-async": "1.8.0" } }, "sha512-QvqDBlJXa8CS2vRORJ4wEflY1m0vVI07uSJdIRgBrLxRPBcsrXxrtU7+wXRXMqfq9zLwNP9XbvRsXF2omoDylg=="], + + "@expo/package-manager": ["@expo/package-manager@1.13.0", "", { "dependencies": { "@expo/json-file": "11.0.0", "@expo/spawn-async": "1.8.0", "chalk": "4.1.2", "npm-package-arg": "11.0.3", "ora": "3.4.0", "resolve-workspace-root": "2.0.1" } }, "sha512-s3W3eZafJDEyVL7W/jxj2Nz3eONKxSCU604S5xj8ijrVaRz83x0DnZznLf/UXQEI1w+FyibH68nHeQyk767b1A=="], + + "@expo/plist": ["@expo/plist@0.7.0", "", { "dependencies": { "@xmldom/xmldom": "0.8.13", "base64-js": "1.5.1", "xmlbuilder": "15.1.1" } }, "sha512-vrpryU1GoqSIRNqRB2D3IjXDmzNYfiQpEF6AH/xknlD7eiYmEDt3mb26V7cLcedcPG8PY/1xWHdBXVQJfEAh6Q=="], + + "@expo/prebuild-config": ["@expo/prebuild-config@56.0.19", "", { "dependencies": { "@expo/config": "56.0.11", "@expo/config-plugins": "56.0.12", "@expo/config-types": "56.0.7", "@expo/image-utils": "0.10.2", "@expo/json-file": "10.2.0", "@react-native/normalize-colors": "0.85.3", "debug": "4.4.3", "expo-modules-autolinking": "56.0.19", "resolve-from": "5.0.0", "semver": "7.8.1" } }, "sha512-aP/7kGDPMmwY9C9cYMK4MfUiZk23KhN4AfnKz0eeRyg3Izw0OGdtzNDLIcchnqpDAwHsI0+LUHZhucGl1jQJ5A=="], + + "@expo/require-utils": ["@expo/require-utils@56.1.4", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/core": "7.29.0", "@babel/plugin-transform-modules-commonjs": "7.28.6" }, "peerDependencies": { "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0" }, "optionalPeers": ["typescript"] }, "sha512-IX7XXg9obnrH3ni0TClBbVKgqk0nT0bjTEPTBtbD+WgIeZ0hpcgwxMJH3j5uBsUqEAq1jqUAkJWrPcg7ZRSV7g=="], + + "@expo/router-server": ["@expo/router-server@56.0.16", "", { "dependencies": { "debug": "4.4.3" }, "peerDependencies": { "@expo/metro-runtime": "^56.0.16", "expo": "*", "expo-constants": "^56.0.20", "expo-font": "^56.0.7", "expo-router": "*", "expo-server": "^56.0.5", "react": "*", "react-dom": "*", "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" }, "optionalPeers": ["@expo/metro-runtime", "expo-router", "react-dom", "react-server-dom-webpack"] }, "sha512-df5BI5GFnSKqAhuALTPIbuHisd4CUhuYam7pwF9Dt1D6BinPctsteWWDm/sEGXdLVhsub4NPI7tvUHo/HWL7aA=="], + + "@expo/schema-utils": ["@expo/schema-utils@56.0.2", "", {}, "sha512-WcOH1E6rwxRqNwBzPOVhd5GBbMlS04+5n+ZMdhdwKOg/Kt3suV+F8F6An+z8mUJ8eSuMM3HD9Sj09t7vc/Xjkw=="], + + "@expo/sdk-runtime-versions": ["@expo/sdk-runtime-versions@1.0.0", "", {}, "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ=="], + + "@expo/spawn-async": ["@expo/spawn-async@1.8.0", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw=="], + + "@expo/sudo-prompt": ["@expo/sudo-prompt@9.3.2", "", {}, "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw=="], + + "@expo/ws-tunnel": ["@expo/ws-tunnel@2.0.0", "", { "peerDependencies": { "ws": "^8.0.0" } }, "sha512-j+JfTRdCk820J9dU0sA2SqshQIKFOMo7ED84w9MJFcebfbNQgsLztEY/SABDkGnjatrW4xGqnUhVRxSBVyCkXw=="], + + "@expo/xcpretty": ["@expo/xcpretty@4.4.4", "", { "dependencies": { "@babel/code-frame": "7.29.0", "chalk": "4.1.2", "js-yaml": "4.3.0" }, "bin": { "excpretty": "build/cli.js" } }, "sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw=="], + + "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "1.7.5", "@floating-ui/utils": "0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="], + + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.8", "", { "dependencies": { "@floating-ui/dom": "1.7.6" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + + "@fumadocs/tailwind": ["@fumadocs/tailwind@0.0.5", "", { "peerDependencies": { "@tailwindcss/oxide": "^4.0.0", "tailwindcss": "^4.0.0" }, "optionalPeers": ["@tailwindcss/oxide", "tailwindcss"] }, "sha512-ENKPWUDRmriccsrUDE4bDBq3FNr/ms3BP2rWlsAEMV1yP23pcCaan+ceGfeBUsAQjw7sj9Q3R4Kl3g/TCStPzQ=="], + + "@google-automations/git-file-utils": ["@google-automations/git-file-utils@3.2.0", "", { "dependencies": { "@octokit/rest": "^20.1.1", "minimatch": "^10.2.4" } }, "sha512-EtQD1DX17kGpckDNCdI0jvMdF98EWR/TM9uogQtnhK0ODv8z5tPSPMICv2lk54c/9ucUgbfdLDrRdDyx56Sznw=="], + + "@hapi/hoek": ["@hapi/hoek@9.3.0", "", {}, "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ=="], + + "@hapi/topo": ["@hapi/topo@5.1.0", "", { "dependencies": { "@hapi/hoek": "9.3.0" } }, "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg=="], + + "@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="], + + "@humanfs/core": ["@humanfs/core@0.19.2", "", { "dependencies": { "@humanfs/types": "0.15.0" } }, "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA=="], + + "@humanfs/node": ["@humanfs/node@0.16.8", "", { "dependencies": { "@humanfs/core": "0.19.2", "@humanfs/types": "0.15.0", "@humanwhocodes/retry": "0.4.3" } }, "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ=="], + + "@humanfs/types": ["@humanfs/types@0.15.0", "", {}, "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + + "@iarna/toml": ["@iarna/toml@3.0.0", "", {}, "sha512-td6ZUkz2oS3VeleBcN+m//Q6HlCFCPrnI0FZhrt/h4XqLEdOyYp2u21nd8MdsR+WJy5r9PTDaHTDDfhf4H4l6Q=="], + + "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], + + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], + + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "1.10.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + + "@isaacs/cliui": ["@isaacs/cliui@9.0.0", "", {}, "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg=="], + + "@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="], + + "@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "0.27.10" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], + + "@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "29.6.3", "@types/istanbul-lib-coverage": "2.0.6", "@types/istanbul-reports": "3.0.4", "@types/node": "24.12.4", "@types/yargs": "17.0.35", "chalk": "4.1.2" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@jsep-plugin/assignment": ["@jsep-plugin/assignment@1.3.0", "", { "peerDependencies": { "jsep": "^0.4.0||^1.0.0" } }, "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ=="], + + "@jsep-plugin/regex": ["@jsep-plugin/regex@1.0.4", "", { "peerDependencies": { "jsep": "^0.4.0||^1.0.0" } }, "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg=="], + + "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "1.0.9", "@types/estree-jsx": "1.0.5", "@types/hast": "3.0.4", "@types/mdx": "2.0.13", "acorn": "8.16.0", "collapse-white-space": "2.1.0", "devlop": "1.1.0", "estree-util-is-identifier-name": "3.0.0", "estree-util-scope": "1.0.0", "estree-walker": "3.0.3", "hast-util-to-jsx-runtime": "2.3.6", "markdown-extensions": "2.0.0", "recma-build-jsx": "1.0.0", "recma-jsx": "1.0.1", "recma-stringify": "1.0.0", "rehype-recma": "1.0.0", "remark-mdx": "3.1.1", "remark-parse": "11.0.0", "remark-rehype": "11.1.2", "source-map": "0.7.6", "unified": "11.0.5", "unist-util-position-from-estree": "2.0.0", "unist-util-stringify-position": "4.0.0", "unist-util-visit": "5.1.0", "vfile": "6.0.3" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="], + + "@mdx-js/react": ["@mdx-js/react@3.1.1", "", { "dependencies": { "@types/mdx": "2.0.13" }, "peerDependencies": { "@types/react": ">=16", "react": ">=16" } }, "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw=="], + + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "1.19.14", "ajv": "8.20.0", "ajv-formats": "3.0.1", "content-type": "1.0.5", "cors": "2.8.6", "cross-spawn": "7.0.6", "eventsource": "3.0.7", "eventsource-parser": "3.0.8", "express": "5.2.1", "express-rate-limit": "8.5.2", "hono": "4.12.22", "jose": "6.2.3", "json-schema-typed": "8.0.2", "pkce-challenge": "5.0.1", "raw-body": "3.0.2", "zod": "4.4.3", "zod-to-json-schema": "3.25.2" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="], + + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.4", "", { "dependencies": { "@tybys/wasm-util": "0.10.2" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow=="], + + "@next/env": ["@next/env@16.2.7", "", {}, "sha512-tMJizPlj6ZYpBMMdK8S0LJufrP4QTdR6pcv9KQ/bVETPAmg0j1mlHE9G2c38UyGHxoBapgwuj7XjbGJ2RcDFOg=="], + + "@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@16.2.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vm1EDI/pVaBNNiychmxk3fft+OhQPVD9cIM/tReLZIQ3TfQ4kqI9DwKk00dzuS1ulC7icbrzCFrmRRlk9PfNdw=="], + + "@next/swc-darwin-x64": ["@next/swc-darwin-x64@16.2.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-O3IRSv1ZBL1zs0WrIgefTEcTKFVn+ryxBNe54erJ6KsD+2f/Mmt7g2jOYh8PSBdUwPtKQJuCsTMlZ7tIu2AcsQ=="], + + "@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@16.2.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-Re6PZtjBDd0aMU+VcZcC/PrIvj4WhrjDYtMhhCVQamWN4L90EVP0pcEOBQD25prSlw7OzNw5QpHLWMilRLsRNw=="], + + "@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@16.2.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-qyogG9QtBzWxgJfeGBvOEHI3851gTfCF3wLZ5RDLTBJGAmE9p1qDwKCOdrBrvBzRvYDT+gUDp72pzlSEfAXgNA=="], + + "@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@16.2.7", "", { "os": "linux", "cpu": "x64" }, "sha512-Vhe4ZDuBpmMogrGi5D4R2Kq4JAQlj6+wvgaFYy31zfES0zPmt6TLA+cuYpM/OLrPZjo2MYQTHVqNUSCR6+fDZQ=="], + + "@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@16.2.7", "", { "os": "linux", "cpu": "x64" }, "sha512-srvian89JahFLw1YLBEuhvPJ0DO5lpUeJQMXy4xYo7g628ZlNgXdNkqoxSAv9OYrBfByh6vxISMwW/mRbzCY+g=="], + + "@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@16.2.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-GX3wvLpULFuRFJzwHaKfm7QZJ18F4ZSuxlPJ96BoBglCzBmdSjyeBKF+ZhWhvL/ckxNfLnNa7bsObO2ipYpszw=="], + + "@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@16.2.7", "", { "os": "win32", "cpu": "x64" }, "sha512-J4WlM72NMk076Qsg0jTdK3SNXatlSdnjW7L7oNGLst1tAGjHrJh/FYi+pw9wyIjEtGRKDNzD0zuiY16oWYWVaw=="], + + "@nodable/entities": ["@nodable/entities@3.0.0", "", {}, "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "1.2.0" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "1.20.1" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@nolyfill/is-core-module": ["@nolyfill/is-core-module@1.0.39", "", {}, "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA=="], + + "@octokit/auth-token": ["@octokit/auth-token@4.0.0", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="], + + "@octokit/core": ["@octokit/core@5.2.2", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg=="], + + "@octokit/endpoint": ["@octokit/endpoint@9.0.6", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw=="], + + "@octokit/graphql": ["@octokit/graphql@7.1.1", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="], + + "@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], + + "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@11.4.4-cjs.2", "", { "dependencies": { "@octokit/types": "^13.7.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw=="], + + "@octokit/plugin-request-log": ["@octokit/plugin-request-log@4.0.1", "", { "peerDependencies": { "@octokit/core": "5" } }, "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA=="], + + "@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1", "", { "dependencies": { "@octokit/types": "^13.8.0" }, "peerDependencies": { "@octokit/core": "^5" } }, "sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ=="], + + "@octokit/request": ["@octokit/request@8.4.1", "", { "dependencies": { "@octokit/endpoint": "^9.0.6", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw=="], + + "@octokit/request-error": ["@octokit/request-error@5.1.1", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="], + + "@octokit/rest": ["@octokit/rest@20.1.2", "", { "dependencies": { "@octokit/core": "^5.0.2", "@octokit/plugin-paginate-rest": "11.4.4-cjs.2", "@octokit/plugin-request-log": "^4.0.0", "@octokit/plugin-rest-endpoint-methods": "13.3.2-cjs.1" } }, "sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA=="], + + "@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + + "@oliphaunt/broker-darwin-arm64": ["@oliphaunt/broker-darwin-arm64@workspace:src/broker/packages/darwin-arm64"], + + "@oliphaunt/broker-linux-arm64-gnu": ["@oliphaunt/broker-linux-arm64-gnu@workspace:src/broker/packages/linux-arm64-gnu"], + + "@oliphaunt/broker-linux-x64-gnu": ["@oliphaunt/broker-linux-x64-gnu@workspace:src/broker/packages/linux-x64-gnu"], + + "@oliphaunt/broker-win32-x64-msvc": ["@oliphaunt/broker-win32-x64-msvc@workspace:src/broker/packages/win32-x64-msvc"], + + "@oliphaunt/docs": ["@oliphaunt/docs@workspace:src/docs"], + + "@oliphaunt/icu": ["@oliphaunt/icu@workspace:src/database-resources/icu/npm"], + + "@oliphaunt/liboliphaunt-darwin-arm64": ["@oliphaunt/liboliphaunt-darwin-arm64@workspace:src/runtimes/liboliphaunt-native/packages/darwin-arm64"], + + "@oliphaunt/liboliphaunt-linux-arm64-gnu": ["@oliphaunt/liboliphaunt-linux-arm64-gnu@workspace:src/runtimes/liboliphaunt-native/packages/linux-arm64-gnu"], + + "@oliphaunt/liboliphaunt-linux-x64-gnu": ["@oliphaunt/liboliphaunt-linux-x64-gnu@workspace:src/runtimes/liboliphaunt-native/packages/linux-x64-gnu"], + + "@oliphaunt/liboliphaunt-wasix-tools": ["@oliphaunt/liboliphaunt-wasix-tools@workspace:src/postgres-tools/wasix/npm"], + + "@oliphaunt/liboliphaunt-wasix-tools-darwin-arm64": ["@oliphaunt/liboliphaunt-wasix-tools-darwin-arm64@workspace:src/postgres-tools/wasix/npm-platforms/darwin-arm64"], + + "@oliphaunt/liboliphaunt-wasix-tools-linux-arm64-gnu": ["@oliphaunt/liboliphaunt-wasix-tools-linux-arm64-gnu@workspace:src/postgres-tools/wasix/npm-platforms/linux-arm64-gnu"], + + "@oliphaunt/liboliphaunt-wasix-tools-linux-x64-gnu": ["@oliphaunt/liboliphaunt-wasix-tools-linux-x64-gnu@workspace:src/postgres-tools/wasix/npm-platforms/linux-x64-gnu"], + + "@oliphaunt/liboliphaunt-wasix-tools-win32-x64-msvc": ["@oliphaunt/liboliphaunt-wasix-tools-win32-x64-msvc@workspace:src/postgres-tools/wasix/npm-platforms/win32-x64-msvc"], + + "@oliphaunt/liboliphaunt-win32-x64-msvc": ["@oliphaunt/liboliphaunt-win32-x64-msvc@workspace:src/runtimes/liboliphaunt-native/packages/win32-x64-msvc"], + + "@oliphaunt/node-direct": ["@oliphaunt/node-direct@workspace:src/sdks/ts/node-addon"], + + "@oliphaunt/node-direct-darwin-arm64": ["@oliphaunt/node-direct-darwin-arm64@workspace:src/sdks/ts/node-addon/packages/darwin-arm64"], + + "@oliphaunt/node-direct-linux-arm64-gnu": ["@oliphaunt/node-direct-linux-arm64-gnu@workspace:src/sdks/ts/node-addon/packages/linux-arm64-gnu"], + + "@oliphaunt/node-direct-linux-x64-gnu": ["@oliphaunt/node-direct-linux-x64-gnu@workspace:src/sdks/ts/node-addon/packages/linux-x64-gnu"], + + "@oliphaunt/node-direct-win32-x64-msvc": ["@oliphaunt/node-direct-win32-x64-msvc@workspace:src/sdks/ts/node-addon/packages/win32-x64-msvc"], + + "@oliphaunt/perf-wasix-node": ["@oliphaunt/perf-wasix-node@workspace:src/benchmarks/perf/wasix-node"], + + "@oliphaunt/react-native": ["@oliphaunt/react-native@workspace:src/sdks/react-native"], + + "@oliphaunt/release-tools": ["@oliphaunt/release-tools@workspace:tools/release"], + + "@oliphaunt/tools": ["@oliphaunt/tools@workspace:src/postgres-tools/native/npm"], + + "@oliphaunt/tools-darwin-arm64": ["@oliphaunt/tools-darwin-arm64@workspace:src/postgres-tools/native/npm-platforms/darwin-arm64"], + + "@oliphaunt/tools-linux-arm64-gnu": ["@oliphaunt/tools-linux-arm64-gnu@workspace:src/postgres-tools/native/npm-platforms/linux-arm64-gnu"], + + "@oliphaunt/tools-linux-x64-gnu": ["@oliphaunt/tools-linux-x64-gnu@workspace:src/postgres-tools/native/npm-platforms/linux-x64-gnu"], + + "@oliphaunt/tools-win32-x64-msvc": ["@oliphaunt/tools-win32-x64-msvc@workspace:src/postgres-tools/native/npm-platforms/win32-x64-msvc"], + + "@oliphaunt/ts": ["@oliphaunt/ts@workspace:src/sdks/ts/sdk"], + + "@oliphaunt/ts-query": ["@oliphaunt/ts-query@workspace:src/sdks/ts-query"], + + "@oliphaunt/wasix-napi": ["@oliphaunt/wasix-napi@workspace:src/sdks/ts-wasix/node-addon"], + + "@oliphaunt/wasix-napi-darwin-arm64": ["@oliphaunt/wasix-napi-darwin-arm64@workspace:src/sdks/ts-wasix/node-addon/packages/darwin-arm64"], + + "@oliphaunt/wasix-napi-linux-arm64-gnu": ["@oliphaunt/wasix-napi-linux-arm64-gnu@workspace:src/sdks/ts-wasix/node-addon/packages/linux-arm64-gnu"], + + "@oliphaunt/wasix-napi-linux-x64-gnu": ["@oliphaunt/wasix-napi-linux-x64-gnu@workspace:src/sdks/ts-wasix/node-addon/packages/linux-x64-gnu"], + + "@oliphaunt/wasix-napi-win32-x64-msvc": ["@oliphaunt/wasix-napi-win32-x64-msvc@workspace:src/sdks/ts-wasix/node-addon/packages/win32-x64-msvc"], + + "@oliphaunt/wasix-tools": ["@oliphaunt/wasix-tools@workspace:src/postgres-tools/wasix/ts"], + + "@oliphaunt/wasix-ts": ["@oliphaunt/wasix-ts@workspace:src/sdks/ts-wasix/sdk"], + + "@orama/orama": ["@orama/orama@3.1.18", "", {}, "sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA=="], + + "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], + + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], + + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], + + "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="], + + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA=="], + + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw=="], + + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="], + + "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "1.2.6", "react-remove-scroll": "2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], + + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], + + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], + + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], + + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], + + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], + + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], + + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "1.2.6", "react-remove-scroll": "2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], + + "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "2.1.8", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], + + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="], + + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ=="], + + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], + + "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="], + + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], + + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], + + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], + + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="], + + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="], + + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.1", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g=="], + + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="], + + "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="], + + "@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.1", "", { "dependencies": { "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w=="], + + "@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="], + + "@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.2.3", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug=="], + + "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], + + "@react-native-community/cli": ["@react-native-community/cli@20.2.0", "", { "dependencies": { "@react-native-community/cli-clean": "20.2.0", "@react-native-community/cli-config": "20.2.0", "@react-native-community/cli-doctor": "20.2.0", "@react-native-community/cli-server-api": "20.2.0", "@react-native-community/cli-tools": "20.2.0", "@react-native-community/cli-types": "20.2.0", "commander": "9.5.0", "deepmerge": "4.3.1", "execa": "5.1.1", "find-up": "5.0.0", "fs-extra": "8.1.0", "graceful-fs": "4.2.11", "picocolors": "1.1.1", "prompts": "2.4.2", "semver": "7.8.1" }, "bin": { "rnc-cli": "build/bin.js" } }, "sha512-5RZKkBeUFC4hhrzySzxWmRJwXBTc2PE3L6QUgvnJk3QDxNYMY7aGuI8Gr9eZRS1DbiY10IPWqpJfqSIplzVG6A=="], + + "@react-native-community/cli-clean": ["@react-native-community/cli-clean@20.2.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.2.0", "execa": "5.1.1", "fast-glob": "3.3.3", "picocolors": "1.1.1" } }, "sha512-krqbhFiwHN8l5wZ2XTcrNq9N+DqDWHxW8RK0bIcrK0O+fMvjYi9e/1Pnx2W0CTotOVcZpHzUbgZ4TQVF231Skw=="], + + "@react-native-community/cli-config": ["@react-native-community/cli-config@20.2.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.2.0", "cosmiconfig": "9.0.2", "deepmerge": "4.3.1", "fast-glob": "3.3.3", "joi": "17.13.4", "picocolors": "1.1.1" } }, "sha512-GF5FxgDfOSLPi/bSiE/xvOGELwzV2GLQnDED+7ArbPi01W1Vu+hD/m+J+bwX34Pocpo767eXAVxc2h9WFUTUfQ=="], + + "@react-native-community/cli-config-android": ["@react-native-community/cli-config-android@20.2.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.2.0", "fast-glob": "3.3.3", "fast-xml-parser": "5.10.1", "picocolors": "1.1.1" } }, "sha512-lASofUNBVK0Pq3VEJ1JrCfAW94Rnk38DikauycRcoHl0hWjHIN3XhsN20dEq+CaIJoq37aCg5NSSSpmkET+ShA=="], + + "@react-native-community/cli-config-apple": ["@react-native-community/cli-config-apple@20.2.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.2.0", "execa": "5.1.1", "fast-glob": "3.3.3", "picocolors": "1.1.1" } }, "sha512-oohr6BV2riWJ5PYjayi1u52bG3H95MwKPkJCZo9pnOlYTjifZQVkMxZ8VTuk392efh0bijVTYfxH8iJPi97SIQ=="], + + "@react-native-community/cli-doctor": ["@react-native-community/cli-doctor@20.2.0", "", { "dependencies": { "@react-native-community/cli-config": "20.2.0", "@react-native-community/cli-platform-android": "20.2.0", "@react-native-community/cli-platform-apple": "20.2.0", "@react-native-community/cli-platform-ios": "20.2.0", "@react-native-community/cli-tools": "20.2.0", "command-exists": "1.2.9", "deepmerge": "4.3.1", "envinfo": "7.21.0", "execa": "5.1.1", "node-stream-zip": "1.15.0", "ora": "5.4.1", "picocolors": "1.1.1", "semver": "7.8.1", "wcwidth": "1.0.1", "yaml": "2.9.0" } }, "sha512-eZjlwmjPoBXgyD6nV5oDDocL1VH5UW4LxZcMAqyN3rQw5vq3CeJikFpNedKTtSl3P6JizIkInyIHpfrW+9qfJA=="], + + "@react-native-community/cli-platform-android": ["@react-native-community/cli-platform-android@20.2.0", "", { "dependencies": { "@react-native-community/cli-config-android": "20.2.0", "@react-native-community/cli-tools": "20.2.0", "execa": "5.1.1", "logkitty": "0.7.1", "picocolors": "1.1.1" } }, "sha512-fRglzcf/Yq5lnIkqdA8uf1GvlG18x3Dm48Yvo+l7KiWgh/SVtfVhfvalrtX5rmx+KeJkDA534bGoPvi5+ruWjw=="], + + "@react-native-community/cli-platform-apple": ["@react-native-community/cli-platform-apple@20.2.0", "", { "dependencies": { "@react-native-community/cli-config-apple": "20.2.0", "@react-native-community/cli-tools": "20.2.0", "execa": "5.1.1", "fast-xml-parser": "5.10.1", "picocolors": "1.1.1" } }, "sha512-jkEPLAd8C/ZRu39a3nhxwSXe0iisUiJC808GExnrnTcViLtg3sad2ciQ/HjjvbdsPCS9sT+Jr7xh3MzBsPojsQ=="], + + "@react-native-community/cli-platform-ios": ["@react-native-community/cli-platform-ios@20.2.0", "", { "dependencies": { "@react-native-community/cli-platform-apple": "20.2.0" } }, "sha512-bCKlBt2HoD7WTl/HX60+4HFhR1lKY64Y9MPWu7yWQwOCEqYRMi6MkRxLimiONj9M2/lNf0z9BPHDzdDe5HM2ag=="], + + "@react-native-community/cli-server-api": ["@react-native-community/cli-server-api@20.2.0", "", { "dependencies": { "@react-native-community/cli-tools": "20.2.0", "body-parser": "2.2.2", "compression": "1.8.1", "connect": "3.7.0", "errorhandler": "1.5.2", "nocache": "3.0.4", "open": "6.4.0", "pretty-format": "29.7.0", "serve-static": "1.16.3", "ws": "6.2.6" } }, "sha512-AI1fsl+6LNuOoDcdWsnF3s9ozqminGCUlbFcrgdZIJWyOuFBeQclNydI22VO3vWaO4dHQkfVa3Zo10AncWQvwA=="], + + "@react-native-community/cli-tools": ["@react-native-community/cli-tools@20.2.0", "", { "dependencies": { "@vscode/sudo-prompt": "9.3.2", "appdirsjs": "1.2.8", "execa": "5.1.1", "find-up": "5.0.0", "launch-editor": "2.14.1", "mime": "2.6.0", "ora": "5.4.1", "picocolors": "1.1.1", "prompts": "2.4.2", "semver": "7.8.1" } }, "sha512-A5W2nqlTidPzGyXzS57jvHsMpQd8iOGSjePj4H318uMbhIdeIHQ5e59fNbdHahS62ISs+2p9s78sVHMbGVa1bg=="], + + "@react-native-community/cli-types": ["@react-native-community/cli-types@20.2.0", "", { "dependencies": { "joi": "17.13.4" } }, "sha512-K60zY/ly8G9rGJQzZ+bFRyLEckAUzyF8Fu9a2Kw6JipCrOl7SiVRBVqjvOr/XnCRKuOpH8i9y7RVg07wkSGRBQ=="], + + "@react-native/assets-registry": ["@react-native/assets-registry@0.85.3", "", {}, "sha512-u9ZiYP23vA2IFtdFQFmetzSmk6SM0xgKIoiOsr1hXNHjHaLhOm+/Ph1ud57wX6+Dbwdzx8coJgnzSKL3W21PCg=="], + + "@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.85.3", "", { "dependencies": { "@babel/traverse": "7.29.0", "@react-native/codegen": "0.85.3" } }, "sha512-Wc94zGfeFG8Njf9SHMPfYZP04kjigkOps6F1TYTvd7ZVXuGxqseCDgxc50LWcOhOCLypI9n3oVVqz81C3p44ZA=="], + + "@react-native/babel-preset": ["@react-native/babel-preset@0.85.3", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/plugin-proposal-export-default-from": "7.27.1", "@babel/plugin-syntax-dynamic-import": "7.8.3", "@babel/plugin-syntax-export-default-from": "7.28.6", "@babel/plugin-syntax-nullish-coalescing-operator": "7.8.3", "@babel/plugin-syntax-optional-chaining": "7.8.3", "@babel/plugin-transform-async-generator-functions": "7.29.0", "@babel/plugin-transform-async-to-generator": "7.28.6", "@babel/plugin-transform-block-scoping": "7.28.6", "@babel/plugin-transform-class-properties": "7.28.6", "@babel/plugin-transform-classes": "7.28.6", "@babel/plugin-transform-destructuring": "7.28.5", "@babel/plugin-transform-flow-strip-types": "7.27.1", "@babel/plugin-transform-for-of": "7.27.1", "@babel/plugin-transform-modules-commonjs": "7.28.6", "@babel/plugin-transform-named-capturing-groups-regex": "7.29.0", "@babel/plugin-transform-nullish-coalescing-operator": "7.28.6", "@babel/plugin-transform-optional-catch-binding": "7.28.6", "@babel/plugin-transform-optional-chaining": "7.28.6", "@babel/plugin-transform-private-methods": "7.28.6", "@babel/plugin-transform-private-property-in-object": "7.28.6", "@babel/plugin-transform-react-display-name": "7.28.0", "@babel/plugin-transform-react-jsx": "7.28.6", "@babel/plugin-transform-react-jsx-self": "7.29.7", "@babel/plugin-transform-react-jsx-source": "7.29.7", "@babel/plugin-transform-regenerator": "7.29.7", "@babel/plugin-transform-runtime": "7.29.0", "@babel/plugin-transform-typescript": "7.28.6", "@babel/plugin-transform-unicode-regex": "7.27.1", "@react-native/babel-plugin-codegen": "0.85.3", "babel-plugin-syntax-hermes-parser": "0.33.3", "babel-plugin-transform-flow-enums": "0.0.2", "react-refresh": "0.14.2" } }, "sha512-fD7fxEhkJB/aF57tWoXjaAWpklfrExYZS3k6aXPP3BQ77DZY7gvf/b7dbirwjID6NVnP1JDRJyTuPBGr0K/vlw=="], + + "@react-native/codegen": ["@react-native/codegen@0.85.3", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/parser": "7.29.3", "hermes-parser": "0.33.3", "invariant": "2.2.4", "nullthrows": "1.1.1", "tinyglobby": "0.2.16", "yargs": "17.7.2" } }, "sha512-/JkS1lGLyzBWP1FbgDwaqEf7qShIC6pUC1M0a/YMAd/v4iqR24MRkQWe7jkYvcBQ2LpEhs5NGE9InhxSv21zCA=="], + + "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.85.3", "", { "dependencies": { "@react-native/dev-middleware": "0.85.3", "debug": "4.4.3", "invariant": "2.2.4", "metro": "0.84.4", "metro-config": "0.84.4", "metro-core": "0.84.4", "semver": "7.8.1" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "0.85.3" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-fs85dmbIqNmtzEixDb0g+q6R3Vt4H9eAt8/inIZdDKfjN76+sUJA2r1nxODQ76bU23MrIbz8sI7KFBPaWk/zQw=="], + + "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.85.3", "", {}, "sha512-uAu7rM5o/Np1zgp6fi5zM1sP1aB8DcS7DdOLcj/TkSutOAjkMqqd2lWt1/+3S7qXexRHVK5XcP+o3VXo4L/V0A=="], + + "@react-native/debugger-shell": ["@react-native/debugger-shell@0.85.3", "", { "dependencies": { "cross-spawn": "7.0.6", "debug": "4.4.3", "fb-dotslash": "0.5.8" } }, "sha512-/jRAaT9boiCttIcEwS02WPwYkUihqsjSaK/TMtHz05vT6uMgac9PaQt5kzBQLIABv5aEIa5gtrMmKVz49MjkjQ=="], + + "@react-native/dev-middleware": ["@react-native/dev-middleware@0.85.3", "", { "dependencies": { "@isaacs/ttlcache": "1.4.1", "@react-native/debugger-frontend": "0.85.3", "@react-native/debugger-shell": "0.85.3", "chrome-launcher": "0.15.2", "chromium-edge-launcher": "0.3.0", "connect": "3.7.0", "debug": "4.4.3", "invariant": "2.2.4", "nullthrows": "1.1.1", "open": "7.4.2", "serve-static": "1.16.3", "ws": "7.5.11" } }, "sha512-JYzBiT4A8w+KQt+dOD5v+ti+tDrGoPnsSTuApq3Ls4RB5sfWbDlYMyz3dbc8qBIHz9tv0sQ5+eOu6Xwqzr5AQA=="], + + "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.85.3", "", {}, "sha512-39dY2j50Q1pntejzwt3XL7vwXtrj8jcIfHq6E+gyu3jzYxZJVvMkMutQ39vSg6zinIQOX36oQDhidXUbCXzgoA=="], + + "@react-native/js-polyfills": ["@react-native/js-polyfills@0.85.3", "", {}, "sha512-U2+aMshIXf1uFn77tpBb/xhHWB9vkVrMpt7kkucAugF8hJKYTDGB587X7WwelHduK2KBfhl4giSv0rzZGoef9A=="], + + "@react-native/metro-babel-transformer": ["@react-native/metro-babel-transformer@0.85.3", "", { "dependencies": { "@babel/core": "7.29.0", "@react-native/babel-preset": "0.85.3", "hermes-parser": "0.33.3", "nullthrows": "1.1.1" } }, "sha512-omuKq+r7jM4XvCMIlNMPP7Up3SyB8o5EAdZtF7YXniKyq7UOMBqhYHFqgsdOXr0lT+3ADf7VCJG3sb82jlBrrQ=="], + + "@react-native/metro-config": ["@react-native/metro-config@0.85.3", "", { "dependencies": { "@react-native/js-polyfills": "0.85.3", "@react-native/metro-babel-transformer": "0.85.3", "metro-config": "0.84.4", "metro-runtime": "0.84.4" } }, "sha512-sVo6HepUmCcpdfozEf91lA0FjpLNNZYu/Zi9FiYiAQTK8pzATXDVTqhvdxpFrQn435p5eUTSbllvbH/KN+bnyA=="], + + "@react-native/normalize-colors": ["@react-native/normalize-colors@0.85.3", "", {}, "sha512-hj0PScZEhIbcOvQV5yMKX3ha4XEIOy/SVE1Rrpp0beW0dpNLOgSC7KDxGewmDnIHK9YdQUXGY9eMEfShUMIaZw=="], + + "@react-native/typescript-config": ["@react-native/typescript-config@0.85.3", "", {}, "sha512-F2Ign3lv/99R5HMDiaQE6NpRdopn87VuXgfHABSk0iwzouLFk1fcwaMkJUmjhnxrQagsUwxOWp4WTPwEvRRazQ=="], + + "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.85.3", "", { "dependencies": { "invariant": "2.2.4", "nullthrows": "1.1.1" }, "peerDependencies": { "@types/react": "^19.2.0", "react": "*", "react-native": "0.85.3" }, "optionalPeers": ["@types/react"] }, "sha512-dsCjI//OIPEUJMyNHp4l7zNLVjCx7bcaRUceOCkU+IB17hkbtbGWvi7HjGFSzy7FJGmS/MOlcfpb72xXiy1Oig=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.4", "", { "os": "android", "cpu": "arm" }, "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.4", "", { "os": "android", "cpu": "arm64" }, "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.4", "", { "os": "linux", "cpu": "arm" }, "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.4", "", { "os": "linux", "cpu": "arm" }, "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.4", "", { "os": "linux", "cpu": "none" }, "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.4", "", { "os": "linux", "cpu": "x64" }, "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.4", "", { "os": "none", "cpu": "arm64" }, "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.4", "", { "os": "win32", "cpu": "x64" }, "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.4", "", { "os": "win32", "cpu": "x64" }, "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw=="], + + "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], + + "@shikijs/core": ["@shikijs/core@4.1.0", "", { "dependencies": { "@shikijs/primitive": "4.1.0", "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "10.0.2", "@types/hast": "3.0.4", "hast-util-to-html": "9.0.5" } }, "sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ=="], + + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "10.0.2", "oniguruma-to-es": "4.3.6" } }, "sha512-YquhawCUgaBfhsS72e2Y/dI59gCBNPHu3fEO/tvLaXrTssxZrY5ddjtNLTwndrMgPo8b3IscE+xoICDzpTmlFQ=="], + + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "10.0.2" } }, "sha512-axLpjVs45YBvvINa+dJF+NPW+KtFkNXsFr4SDw2BMj9GdeMnGxVB9PQb2xXlJYovslt/nz6giedAyOANkfc7hg=="], + + "@shikijs/langs": ["@shikijs/langs@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0" } }, "sha512-nwOMruEkbgdZfQ/b8CgpNBVOpvG1k0N5tbmgiFeqsan401+x3ILqlzZJowSla4Agmq4hG2Uf2wh5jLTEhR8VSg=="], + + "@shikijs/primitive": ["@shikijs/primitive@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "10.0.2", "@types/hast": "3.0.4" } }, "sha512-zx2/2Uwj2q9X3KSyYREEhXO23xBw5WUhP4orK2lE4r+t9JGITmEe0JH+wPmJhqHpOT2bRRs6lAL945+LDvOAGw=="], + + "@shikijs/themes": ["@shikijs/themes@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0" } }, "sha512-emCcTnUM7yO2wltYbaxm+yLvcCI4+h8XBKc4KmJ7EZUXoSGjcCHifkI//R4OFit9ewpg7H2/9tjOuXrT2v/Knw=="], + + "@shikijs/types": ["@shikijs/types@4.1.0", "", { "dependencies": { "@shikijs/vscode-textmate": "10.0.2", "@types/hast": "3.0.4" } }, "sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA=="], + + "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + + "@sideway/address": ["@sideway/address@4.1.5", "", { "dependencies": { "@hapi/hoek": "9.3.0" } }, "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q=="], + + "@sideway/formula": ["@sideway/formula@3.0.1", "", {}, "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg=="], + + "@sideway/pinpoint": ["@sideway/pinpoint@2.0.0", "", {}, "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ=="], + + "@sinclair/typebox": ["@sinclair/typebox@0.27.10", "", {}, "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], + + "@tailwindcss/node": ["@tailwindcss/node@4.3.0", "", { "dependencies": { "@jridgewell/remapping": "2.3.5", "enhanced-resolve": "5.22.1", "jiti": "2.7.0", "lightningcss": "1.32.0", "magic-string": "0.30.21", "source-map-js": "1.2.1", "tailwindcss": "4.3.0" } }, "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g=="], + + "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.0", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.0", "@tailwindcss/oxide-darwin-arm64": "4.3.0", "@tailwindcss/oxide-darwin-x64": "4.3.0", "@tailwindcss/oxide-freebsd-x64": "4.3.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0", "@tailwindcss/oxide-linux-arm64-musl": "4.3.0", "@tailwindcss/oxide-linux-x64-gnu": "4.3.0", "@tailwindcss/oxide-linux-x64-musl": "4.3.0", "@tailwindcss/oxide-wasm32-wasi": "4.3.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0", "@tailwindcss/oxide-win32-x64-msvc": "4.3.0" } }, "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg=="], + + "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.0", "", { "os": "android", "cpu": "arm64" }, "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng=="], + + "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ=="], + + "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA=="], + + "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ=="], + + "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0", "", { "os": "linux", "cpu": "arm" }, "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA=="], + + "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg=="], + + "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ=="], + + "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ=="], + + "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg=="], + + "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.0", "", { "cpu": "none" }, "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA=="], + + "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ=="], + + "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA=="], + + "@tailwindcss/postcss": ["@tailwindcss/postcss@4.3.0", "", { "dependencies": { "@alloc/quick-lru": "5.2.0", "@tailwindcss/node": "4.3.0", "@tailwindcss/oxide": "4.3.0", "postcss": "8.5.15", "tailwindcss": "4.3.0" } }, "sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w=="], + + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.2", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg=="], + + "@types/bun": ["@types/bun@1.4.2", "", { "dependencies": { "bun-types": "1.4.2" } }, "sha512-GimotNn7+ZV0uVArItBbriZsR1oNf0+WTzPkdcFrzShI7k2norL0uzEaJT8T33dWr7O/c9ZDuAFQrctKCi72oQ=="], + + "@types/debug": ["@types/debug@4.1.13", "", { "dependencies": { "@types/ms": "2.1.0" } }, "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw=="], + + "@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], + + "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "1.0.9" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + + "@types/istanbul-lib-coverage": ["@types/istanbul-lib-coverage@2.0.6", "", {}, "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="], + + "@types/istanbul-lib-report": ["@types/istanbul-lib-report@3.0.3", "", { "dependencies": { "@types/istanbul-lib-coverage": "2.0.6" } }, "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA=="], + + "@types/istanbul-reports": ["@types/istanbul-reports@3.0.4", "", { "dependencies": { "@types/istanbul-lib-report": "3.0.3" } }, "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], + + "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], + + "@types/mdx": ["@types/mdx@2.0.13", "", {}, "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw=="], + + "@types/minimist": ["@types/minimist@1.2.5", "", {}, "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag=="], + + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + + "@types/node": ["@types/node@22.19.19", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew=="], + + "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="], + + "@types/npm-package-arg": ["@types/npm-package-arg@6.1.4", "", {}, "sha512-vDgdbMy2QXHnAruzlv68pUtXCjmqUk3WrBAsRboRovsOmxbfn/WiYCjmecyKjGztnMps5dWp4Uq2prp+Ilo17Q=="], + + "@types/pg": ["@types/pg@8.23.1", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A=="], + + "@types/react": ["@types/react@19.2.16", "", { "dependencies": { "csstype": "3.2.3" } }, "sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w=="], + + "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], + + "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + + "@types/yargs": ["@types/yargs@16.0.11", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-sbtvk8wDN+JvEdabmZExoW/HNr1cB7D/j4LT08rMiuikfA7m/JNJg7ATQcgzs34zHnoScDkY0ZRSl29Fkmk36g=="], + + "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.59.4", "", { "dependencies": { "@eslint-community/regexpp": "4.12.2", "@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/type-utils": "8.59.4", "@typescript-eslint/utils": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4", "ignore": "7.0.5", "natural-compare": "1.4.0", "ts-api-utils": "2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.59.4", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.59.4", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/types": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4", "debug": "4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.59.4", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "8.59.4", "@typescript-eslint/types": "8.59.4", "debug": "4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.59.4", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4" } }, "sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.59.4", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.59.4", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4", "@typescript-eslint/utils": "8.59.4", "debug": "4.4.3", "ts-api-utils": "2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.59.4", "", {}, "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.59.4", "", { "dependencies": { "@typescript-eslint/project-service": "8.59.4", "@typescript-eslint/tsconfig-utils": "8.59.4", "@typescript-eslint/types": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4", "debug": "4.4.3", "minimatch": "10.2.5", "semver": "7.8.1", "tinyglobby": "0.2.16", "ts-api-utils": "2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.59.4", "", { "dependencies": { "@eslint-community/eslint-utils": "4.9.1", "@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/types": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.59.4", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "eslint-visitor-keys": "5.0.1" } }, "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ=="], + + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.1", "", {}, "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ=="], + + "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.12.2", "", { "os": "android", "cpu": "arm" }, "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w=="], + + "@unrs/resolver-binding-android-arm64": ["@unrs/resolver-binding-android-arm64@1.12.2", "", { "os": "android", "cpu": "arm64" }, "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ=="], + + "@unrs/resolver-binding-darwin-arm64": ["@unrs/resolver-binding-darwin-arm64@1.12.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w=="], + + "@unrs/resolver-binding-darwin-x64": ["@unrs/resolver-binding-darwin-x64@1.12.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA=="], + + "@unrs/resolver-binding-freebsd-x64": ["@unrs/resolver-binding-freebsd-x64@1.12.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg=="], + + "@unrs/resolver-binding-linux-arm-gnueabihf": ["@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A=="], + + "@unrs/resolver-binding-linux-arm-musleabihf": ["@unrs/resolver-binding-linux-arm-musleabihf@1.12.2", "", { "os": "linux", "cpu": "arm" }, "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g=="], + + "@unrs/resolver-binding-linux-arm64-gnu": ["@unrs/resolver-binding-linux-arm64-gnu@1.12.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg=="], + + "@unrs/resolver-binding-linux-arm64-musl": ["@unrs/resolver-binding-linux-arm64-musl@1.12.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA=="], + + "@unrs/resolver-binding-linux-loong64-gnu": ["@unrs/resolver-binding-linux-loong64-gnu@1.12.2", "", { "os": "linux", "cpu": "none" }, "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q=="], + + "@unrs/resolver-binding-linux-loong64-musl": ["@unrs/resolver-binding-linux-loong64-musl@1.12.2", "", { "os": "linux", "cpu": "none" }, "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew=="], + + "@unrs/resolver-binding-linux-ppc64-gnu": ["@unrs/resolver-binding-linux-ppc64-gnu@1.12.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg=="], + + "@unrs/resolver-binding-linux-riscv64-gnu": ["@unrs/resolver-binding-linux-riscv64-gnu@1.12.2", "", { "os": "linux", "cpu": "none" }, "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A=="], + + "@unrs/resolver-binding-linux-riscv64-musl": ["@unrs/resolver-binding-linux-riscv64-musl@1.12.2", "", { "os": "linux", "cpu": "none" }, "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w=="], + + "@unrs/resolver-binding-linux-s390x-gnu": ["@unrs/resolver-binding-linux-s390x-gnu@1.12.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw=="], + + "@unrs/resolver-binding-linux-x64-gnu": ["@unrs/resolver-binding-linux-x64-gnu@1.12.2", "", { "os": "linux", "cpu": "x64" }, "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ=="], + + "@unrs/resolver-binding-linux-x64-musl": ["@unrs/resolver-binding-linux-x64-musl@1.12.2", "", { "os": "linux", "cpu": "x64" }, "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A=="], + + "@unrs/resolver-binding-openharmony-arm64": ["@unrs/resolver-binding-openharmony-arm64@1.12.2", "", { "os": "none", "cpu": "arm64" }, "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ=="], + + "@unrs/resolver-binding-wasm32-wasi": ["@unrs/resolver-binding-wasm32-wasi@1.12.2", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "1.1.4" }, "cpu": "none" }, "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A=="], + + "@unrs/resolver-binding-win32-arm64-msvc": ["@unrs/resolver-binding-win32-arm64-msvc@1.12.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g=="], + + "@unrs/resolver-binding-win32-ia32-msvc": ["@unrs/resolver-binding-win32-ia32-msvc@1.12.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g=="], + + "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.12.2", "", { "os": "win32", "cpu": "x64" }, "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA=="], + + "@vscode/sudo-prompt": ["@vscode/sudo-prompt@9.3.2", "", {}, "sha512-gcXoCN00METUNFeQOFJ+C9xUI0DKB+0EGMVg7wbVYRHBw2Eq3fKisDZOkRdOz3kqXRKOENMfShPOmypw1/8nOw=="], + + "@xmldom/xmldom": ["@xmldom/xmldom@0.8.13", "", {}, "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw=="], + + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "5.0.1" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + + "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "2.1.35", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], + + "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "agent-cli-detector": ["agent-cli-detector@0.1.2", "", { "bin": { "agent-cli-detector": "dist/cli.js" } }, "sha512-qdZ/9JFORtTKJNhT/IczMeEfEUbUU0K5umYeiIQHX+AjHs+Y9SXVzSgaYlpZeyNMrvuh2HpZiOTpvS57iPfBkQ=="], + + "ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "3.1.3", "fast-json-stable-stringify": "2.1.0", "json-schema-traverse": "0.4.1", "uri-js": "4.4.1" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], + + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "8.20.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], + + "anser": ["anser@1.4.10", "", {}, "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww=="], + + "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], + + "ansi-fragments": ["ansi-fragments@0.2.1", "", { "dependencies": { "colorette": "1.4.0", "slice-ansi": "2.1.0", "strip-ansi": "5.2.0" } }, "sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w=="], + + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "anynum": ["anynum@1.0.1", "", {}, "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A=="], + + "appdirsjs": ["appdirsjs@1.2.8", "", {}, "sha512-8zl1xlxeS4a0/36CT6LOaVioPOL8TeLT1b9OHk0j9xSbzmPBuM7lUgWMSTh6SbuF8fbwjcP1rr30OCLpd1fl+A=="], + + "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + + "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "is-array-buffer": "3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], + + "array-ify": ["array-ify@1.0.0", "", {}, "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng=="], + + "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-object-atoms": "1.1.2", "get-intrinsic": "1.3.0", "is-string": "1.1.1", "math-intrinsics": "1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], + + "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "1.0.9", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-errors": "1.3.0", "es-object-atoms": "1.1.2", "es-shim-unscopables": "1.1.0" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], + + "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-errors": "1.3.0", "es-object-atoms": "1.1.2", "es-shim-unscopables": "1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="], + + "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "1.0.9", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-shim-unscopables": "1.1.0" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], + + "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "1.0.9", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-shim-unscopables": "1.1.0" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], + + "array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "1.0.9", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-errors": "1.3.0", "es-shim-unscopables": "1.1.0" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="], + + "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "1.0.2", "call-bind": "1.0.9", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "is-array-buffer": "3.0.5" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], + + "arrify": ["arrify@1.0.1", "", {}, "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA=="], + + "asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="], + + "astral-regex": ["astral-regex@1.0.0", "", {}, "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="], + + "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="], + + "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], + + "async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="], + + "async-retry": ["async-retry@1.3.3", "", { "dependencies": { "retry": "0.13.1" } }, "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw=="], + + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "1.1.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + + "await-lock": ["await-lock@2.2.2", "", {}, "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw=="], + + "babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.17", "", { "dependencies": { "@babel/compat-data": "7.29.3", "@babel/helper-define-polyfill-provider": "0.6.8", "semver": "6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w=="], + + "babel-plugin-polyfill-corejs3": ["babel-plugin-polyfill-corejs3@0.13.0", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "0.6.8", "core-js-compat": "3.49.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A=="], + + "babel-plugin-polyfill-regenerator": ["babel-plugin-polyfill-regenerator@0.6.8", "", { "dependencies": { "@babel/helper-define-polyfill-provider": "0.6.8" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg=="], + + "babel-plugin-react-compiler": ["babel-plugin-react-compiler@1.0.0", "", { "dependencies": { "@babel/types": "7.29.0" } }, "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw=="], + + "babel-plugin-react-native-web": ["babel-plugin-react-native-web@0.21.2", "", {}, "sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA=="], + + "babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.33.3", "", { "dependencies": { "hermes-parser": "0.33.3" } }, "sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA=="], + + "babel-plugin-transform-flow-enums": ["babel-plugin-transform-flow-enums@0.0.2", "", { "dependencies": { "@babel/plugin-syntax-flow": "7.28.6" } }, "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ=="], + + "babel-preset-expo": ["babel-preset-expo@56.0.17", "", { "dependencies": { "@babel/generator": "7.29.1", "@babel/helper-module-imports": "7.28.6", "@babel/plugin-proposal-decorators": "7.29.0", "@babel/plugin-proposal-export-default-from": "7.27.1", "@babel/plugin-syntax-dynamic-import": "7.8.3", "@babel/plugin-syntax-export-default-from": "7.28.6", "@babel/plugin-syntax-nullish-coalescing-operator": "7.8.3", "@babel/plugin-syntax-optional-chaining": "7.8.3", "@babel/plugin-transform-async-generator-functions": "7.29.0", "@babel/plugin-transform-async-to-generator": "7.28.6", "@babel/plugin-transform-block-scoping": "7.28.6", "@babel/plugin-transform-class-properties": "7.28.6", "@babel/plugin-transform-class-static-block": "7.28.6", "@babel/plugin-transform-classes": "7.28.6", "@babel/plugin-transform-destructuring": "7.28.5", "@babel/plugin-transform-export-namespace-from": "7.27.1", "@babel/plugin-transform-flow-strip-types": "7.27.1", "@babel/plugin-transform-for-of": "7.27.1", "@babel/plugin-transform-logical-assignment-operators": "7.28.6", "@babel/plugin-transform-modules-commonjs": "7.28.6", "@babel/plugin-transform-named-capturing-groups-regex": "7.29.0", "@babel/plugin-transform-nullish-coalescing-operator": "7.28.6", "@babel/plugin-transform-object-rest-spread": "7.28.6", "@babel/plugin-transform-optional-catch-binding": "7.28.6", "@babel/plugin-transform-optional-chaining": "7.28.6", "@babel/plugin-transform-parameters": "7.27.7", "@babel/plugin-transform-private-methods": "7.28.6", "@babel/plugin-transform-private-property-in-object": "7.28.6", "@babel/plugin-transform-react-display-name": "7.28.0", "@babel/plugin-transform-react-jsx": "7.28.6", "@babel/plugin-transform-react-jsx-development": "7.27.1", "@babel/plugin-transform-react-pure-annotations": "7.27.1", "@babel/plugin-transform-runtime": "7.29.0", "@babel/plugin-transform-typescript": "7.28.6", "@babel/plugin-transform-unicode-regex": "7.27.1", "@babel/preset-typescript": "7.28.5", "@react-native/babel-plugin-codegen": "0.85.3", "babel-plugin-react-compiler": "1.0.0", "babel-plugin-react-native-web": "0.21.2", "babel-plugin-syntax-hermes-parser": "0.33.3", "babel-plugin-transform-flow-enums": "0.0.2", "debug": "4.4.3" }, "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", "expo-widgets": "^56.0.22", "react-refresh": ">=0.14.0 <1.0.0" }, "optionalPeers": ["@babel/runtime", "expo", "expo-widgets"] }, "sha512-yanAlbzaMMNqnju/uMnZsf3ltgssG71UubkfD+2iMaoXGNIj+TODEs9hF12jrTX2lzq/zH0HWSuRLZLNalf8fw=="], + + "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.32", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg=="], + + "before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="], + + "big-integer": ["big-integer@1.6.52", "", {}, "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg=="], + + "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "5.7.1", "inherits": "2.0.4", "readable-stream": "3.6.2" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + + "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "3.1.2", "content-type": "1.0.5", "debug": "4.4.3", "http-errors": "2.0.1", "iconv-lite": "0.7.2", "on-finished": "2.4.1", "qs": "6.15.2", "raw-body": "3.0.2", "type-is": "2.1.0" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "bplist-creator": ["bplist-creator@0.1.0", "", { "dependencies": { "stream-buffers": "2.2.0" } }, "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg=="], + + "bplist-parser": ["bplist-parser@0.3.2", "", { "dependencies": { "big-integer": "1.6.52" } }, "sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ=="], + + "brace-expansion": ["brace-expansion@1.1.14", "", { "dependencies": { "balanced-match": "1.0.2", "concat-map": "0.0.1" } }, "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "browserslist": ["browserslist@4.28.2", "", { "dependencies": { "baseline-browser-mapping": "2.10.32", "caniuse-lite": "1.0.30001793", "electron-to-chromium": "1.5.361", "node-releases": "2.0.46", "update-browserslist-db": "1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg=="], + + "bser": ["bser@2.1.1", "", { "dependencies": { "node-int64": "0.4.0" } }, "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ=="], + + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "1.5.1", "ieee754": "1.2.1" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + + "bun-types": ["bun-types@1.4.2", "", { "dependencies": { "@types/node": "*" } }, "sha512-bxV1FgK7yBIzjRe5zBozIM4Bem11ZJcCXSrjWRG3YWLt8yFDePu4cLjpebO8OvPeIE9trbyPF4fuj3Cia4Fj3w=="], + + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "call-bind": ["call-bind@1.0.9", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-define-property": "1.0.1", "get-intrinsic": "1.3.0", "set-function-length": "1.2.2" } }, "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "1.3.0", "function-bind": "1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "get-intrinsic": "1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], + + "camelcase-keys": ["camelcase-keys@6.2.2", "", { "dependencies": { "camelcase": "^5.3.1", "map-obj": "^4.0.0", "quick-lru": "^4.0.1" } }, "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001793", "", {}, "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA=="], + + "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "4.3.0", "supports-color": "7.2.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], + + "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], + + "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], + + "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], + + "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + + "chrome-launcher": ["chrome-launcher@0.15.2", "", { "dependencies": { "@types/node": "24.12.4", "escape-string-regexp": "4.0.0", "is-wsl": "2.2.0", "lighthouse-logger": "1.4.2" }, "bin": { "print-chrome-path": "bin/print-chrome-path.js" } }, "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ=="], + + "chromium-edge-launcher": ["chromium-edge-launcher@0.3.0", "", { "dependencies": { "@types/node": "24.12.4", "escape-string-regexp": "4.0.0", "is-wsl": "2.2.0", "lighthouse-logger": "1.4.2", "mkdirp": "1.0.4" } }, "sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA=="], + + "ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], + + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], + + "cli-cursor": ["cli-cursor@2.1.0", "", { "dependencies": { "restore-cursor": "2.0.0" } }, "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw=="], + + "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], + + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "4.2.3", "strip-ansi": "6.0.1", "wrap-ansi": "7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "code-suggester": ["code-suggester@5.0.1", "", { "dependencies": { "@octokit/rest": "^20.1.2", "@types/yargs": "^16.0.0", "async-retry": "^1.3.1", "diff": "^8.0.3", "glob": "^7.1.6", "parse-diff": "^0.11.0", "yargs": "^16.0.0" }, "bin": { "code-suggester": "build/src/bin/code-suggester.js" } }, "sha512-8qJiiSCfkbPNWvjEFzdG1UW3axL+Bs0ldV1/TdlBKmF9I/a/WooSQZQCi9M44HoXbVTQesn/IQr6+nIWNnVIWA=="], + + "collapse-white-space": ["collapse-white-space@2.1.0", "", {}, "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "colorette": ["colorette@1.4.0", "", {}, "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g=="], + + "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + + "command-exists": ["command-exists@1.2.9", "", {}, "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w=="], + + "commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], + + "compare-func": ["compare-func@2.0.0", "", { "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" } }, "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA=="], + + "compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": "1.54.0" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="], + + "compression": ["compression@1.8.1", "", { "dependencies": { "bytes": "3.1.2", "compressible": "2.0.18", "debug": "2.6.9", "negotiator": "0.6.4", "on-headers": "1.1.0", "safe-buffer": "5.2.1", "vary": "1.1.2" } }, "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w=="], + + "compute-scroll-into-view": ["compute-scroll-into-view@3.1.1", "", {}, "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "connect": ["connect@3.7.0", "", { "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", "parseurl": "1.3.3", "utils-merge": "1.0.1" } }, "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ=="], + + "content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + + "conventional-changelog-conventionalcommits": ["conventional-changelog-conventionalcommits@6.1.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw=="], + + "conventional-changelog-writer": ["conventional-changelog-writer@6.0.1", "", { "dependencies": { "conventional-commits-filter": "^3.0.0", "dateformat": "^3.0.3", "handlebars": "^4.7.7", "json-stringify-safe": "^5.0.1", "meow": "^8.1.2", "semver": "^7.0.0", "split": "^1.0.1" }, "bin": { "conventional-changelog-writer": "cli.js" } }, "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ=="], + + "conventional-commits-filter": ["conventional-commits-filter@3.0.0", "", { "dependencies": { "lodash.ismatch": "^4.4.0", "modify-values": "^1.0.1" } }, "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q=="], + + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + + "core-js-compat": ["core-js-compat@3.49.0", "", { "dependencies": { "browserslist": "4.28.2" } }, "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA=="], + + "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "4.1.1", "vary": "1.1.2" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], + + "cosmiconfig": ["cosmiconfig@9.0.2", "", { "dependencies": { "env-paths": "2.2.1", "import-fresh": "3.3.1", "js-yaml": "4.3.0", "parse-json": "5.2.0" }, "peerDependencies": { "typescript": ">=4.9.5" }, "optionalPeers": ["typescript"] }, "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg=="], + + "cross-fetch": ["cross-fetch@3.2.0", "", { "dependencies": { "node-fetch": "2.7.0" } }, "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "3.1.1", "shebang-command": "2.0.0", "which": "2.0.2" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "css-in-js-utils": ["css-in-js-utils@3.1.0", "", { "dependencies": { "hyphenate-style-name": "1.1.0" } }, "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A=="], + + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], + + "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], + + "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], + + "dateformat": ["dateformat@3.0.3", "", {}, "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q=="], + + "dayjs": ["dayjs@1.11.21", "", {}, "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], + + "decamelize-keys": ["decamelize-keys@1.1.1", "", { "dependencies": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" } }, "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg=="], + + "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "2.0.2" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + + "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "1.0.4" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], + + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "1.0.1", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "1.1.4", "has-property-descriptors": "1.0.2", "object-keys": "1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="], + + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + + "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], + + "detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], + + "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "2.0.3" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + + "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + + "dnssd-advertise": ["dnssd-advertise@1.1.6", "", {}, "sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg=="], + + "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "2.0.3" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], + + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "dot-prop": ["dot-prop@5.3.0", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.361", "", {}, "sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + + "enhanced-resolve": ["enhanced-resolve@5.22.1", "", { "dependencies": { "graceful-fs": "4.2.11", "tapable": "2.3.3" } }, "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww=="], + + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + + "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + + "envinfo": ["envinfo@7.21.0", "", { "bin": { "envinfo": "dist/cli.js" } }, "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow=="], + + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + + "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], + + "errorhandler": ["errorhandler@1.5.2", "", { "dependencies": { "accepts": "1.3.8", "escape-html": "1.0.3" } }, "sha512-kNAL7hESndBCrWwS72QyV3IVOTrVmj9D062FV5BQswNL5zEdeRmz/WJFyh6Aj/plvvSOrzddkxW57HgkZcR9Fw=="], + + "es-abstract": ["es-abstract@1.24.2", "", { "dependencies": { "array-buffer-byte-length": "1.0.2", "arraybuffer.prototype.slice": "1.0.4", "available-typed-arrays": "1.0.7", "call-bind": "1.0.9", "call-bound": "1.0.4", "data-view-buffer": "1.0.2", "data-view-byte-length": "1.0.2", "data-view-byte-offset": "1.0.1", "es-define-property": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.2", "es-set-tostringtag": "2.1.0", "es-to-primitive": "1.3.0", "function.prototype.name": "1.1.8", "get-intrinsic": "1.3.0", "get-proto": "1.0.1", "get-symbol-description": "1.1.0", "globalthis": "1.0.4", "gopd": "1.2.0", "has-property-descriptors": "1.0.2", "has-proto": "1.2.0", "has-symbols": "1.1.0", "hasown": "2.0.3", "internal-slot": "1.1.0", "is-array-buffer": "3.0.5", "is-callable": "1.2.7", "is-data-view": "1.0.2", "is-negative-zero": "2.0.3", "is-regex": "1.2.1", "is-set": "2.0.3", "is-shared-array-buffer": "1.0.4", "is-string": "1.1.1", "is-typed-array": "1.1.15", "is-weakref": "1.1.1", "math-intrinsics": "1.1.0", "object-inspect": "1.13.4", "object-keys": "1.1.1", "object.assign": "4.1.7", "own-keys": "1.0.1", "regexp.prototype.flags": "1.5.4", "safe-array-concat": "1.1.4", "safe-push-apply": "1.0.0", "safe-regex-test": "1.1.0", "set-proto": "1.0.0", "stop-iteration-iterator": "1.1.0", "string.prototype.trim": "1.2.10", "string.prototype.trimend": "1.0.9", "string.prototype.trimstart": "1.0.8", "typed-array-buffer": "1.0.3", "typed-array-byte-length": "1.0.3", "typed-array-byte-offset": "1.0.4", "typed-array-length": "1.0.7", "unbox-primitive": "1.1.0", "which-typed-array": "1.1.20" } }, "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-iterator-helpers": ["es-iterator-helpers@1.3.2", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-errors": "1.3.0", "es-set-tostringtag": "2.1.0", "function-bind": "1.1.2", "get-intrinsic": "1.3.0", "globalthis": "1.0.4", "gopd": "1.2.0", "has-property-descriptors": "1.0.2", "has-proto": "1.2.0", "has-symbols": "1.1.0", "internal-slot": "1.1.0", "iterator.prototype": "1.1.5", "math-intrinsics": "1.1.0" } }, "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw=="], + + "es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "has-tostringtag": "1.0.2", "hasown": "2.0.3" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "2.0.3" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], + + "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "1.2.7", "is-date-object": "1.1.0", "is-symbol": "1.1.1" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + + "esast-util-from-estree": ["esast-util-from-estree@2.0.0", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "devlop": "1.1.0", "estree-util-visit": "2.0.0", "unist-util-position-from-estree": "2.0.0" } }, "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ=="], + + "esast-util-from-js": ["esast-util-from-js@2.0.1", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "acorn": "8.16.0", "esast-util-from-estree": "2.0.0", "vfile-message": "4.0.3" } }, "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw=="], + + "esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.39.4", "", { "dependencies": { "@eslint-community/eslint-utils": "4.9.1", "@eslint-community/regexpp": "4.12.2", "@eslint/config-array": "0.21.2", "@eslint/config-helpers": "0.4.2", "@eslint/core": "0.17.0", "@eslint/eslintrc": "3.3.5", "@eslint/js": "9.39.4", "@eslint/plugin-kit": "0.4.1", "@humanfs/node": "0.16.8", "@humanwhocodes/module-importer": "1.0.1", "@humanwhocodes/retry": "0.4.3", "@types/estree": "1.0.9", "ajv": "6.15.0", "chalk": "4.1.2", "cross-spawn": "7.0.6", "debug": "4.4.3", "escape-string-regexp": "4.0.0", "eslint-scope": "8.4.0", "eslint-visitor-keys": "4.2.1", "espree": "10.4.0", "esquery": "1.7.0", "esutils": "2.0.3", "fast-deep-equal": "3.1.3", "file-entry-cache": "8.0.0", "find-up": "5.0.0", "glob-parent": "6.0.2", "ignore": "5.3.2", "imurmurhash": "0.1.4", "is-glob": "4.0.3", "json-stable-stringify-without-jsonify": "1.0.1", "lodash.merge": "4.6.2", "minimatch": "3.1.5", "natural-compare": "1.4.0", "optionator": "0.9.4" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ=="], + + "eslint-config-expo": ["eslint-config-expo@56.0.4", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.4", "@typescript-eslint/parser": "8.59.4", "eslint-import-resolver-typescript": "3.10.1", "eslint-plugin-expo": "1.0.3", "eslint-plugin-import": "2.32.0", "eslint-plugin-react": "7.37.5", "eslint-plugin-react-hooks": "7.1.1", "globals": "16.5.0" }, "peerDependencies": { "eslint": ">=8.10" } }, "sha512-1OD7rJMxCchKHxq+U+OQsAxVtzAxeUb9875g6+15KsSD9fqKTgq7DEEWYwunzU9r9E8kYJ+mh7+j86vF9m9NMw=="], + + "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.10", "", { "dependencies": { "debug": "3.2.7", "is-core-module": "2.16.2", "resolve": "2.0.0-next.7" } }, "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ=="], + + "eslint-import-resolver-typescript": ["eslint-import-resolver-typescript@3.10.1", "", { "dependencies": { "@nolyfill/is-core-module": "1.0.39", "debug": "4.4.3", "get-tsconfig": "4.14.0", "is-bun-module": "2.0.0", "stable-hash": "0.0.5", "tinyglobby": "0.2.16", "unrs-resolver": "1.12.2" }, "peerDependencies": { "eslint": "*", "eslint-plugin-import": "*", "eslint-plugin-import-x": "*" }, "optionalPeers": ["eslint-plugin-import", "eslint-plugin-import-x"] }, "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ=="], + + "eslint-module-utils": ["eslint-module-utils@2.12.1", "", { "dependencies": { "debug": "3.2.7" }, "peerDependencies": { "@typescript-eslint/parser": "*", "eslint": "*", "eslint-import-resolver-node": "*", "eslint-import-resolver-typescript": "*", "eslint-import-resolver-webpack": "*" }, "optionalPeers": ["@typescript-eslint/parser", "eslint", "eslint-import-resolver-node", "eslint-import-resolver-typescript", "eslint-import-resolver-webpack"] }, "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw=="], + + "eslint-plugin-expo": ["eslint-plugin-expo@1.0.3", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "@typescript-eslint/utils": "8.59.4" }, "peerDependencies": { "eslint": ">=8.10" } }, "sha512-C1v9NPvpDET36+7Klpp/+53Jl+VzOfpbDxpKtL/pAPhCDwTX0kW6Swo425PT0uc4AMT5jpQbB7hSKFjKOGMl4A=="], + + "eslint-plugin-import": ["eslint-plugin-import@2.32.0", "", { "dependencies": { "@rtsao/scc": "1.1.0", "array-includes": "3.1.9", "array.prototype.findlastindex": "1.2.6", "array.prototype.flat": "1.3.3", "array.prototype.flatmap": "1.3.3", "debug": "3.2.7", "doctrine": "2.1.0", "eslint-import-resolver-node": "0.3.10", "eslint-module-utils": "2.12.1", "hasown": "2.0.3", "is-core-module": "2.16.2", "is-glob": "4.0.3", "minimatch": "3.1.5", "object.fromentries": "2.0.8", "object.groupby": "1.0.3", "object.values": "1.2.1", "semver": "6.3.1", "string.prototype.trimend": "1.0.9", "tsconfig-paths": "3.15.0" }, "peerDependencies": { "@typescript-eslint/parser": "*", "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" }, "optionalPeers": ["@typescript-eslint/parser"] }, "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA=="], + + "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "3.1.9", "array.prototype.findlast": "1.2.5", "array.prototype.flatmap": "1.3.3", "array.prototype.tosorted": "1.1.4", "doctrine": "2.1.0", "es-iterator-helpers": "1.3.2", "estraverse": "5.3.0", "hasown": "2.0.3", "jsx-ast-utils": "3.3.5", "minimatch": "3.1.5", "object.entries": "1.1.9", "object.fromentries": "2.0.8", "object.values": "1.2.1", "prop-types": "15.8.1", "resolve": "2.0.0-next.7", "semver": "6.3.1", "string.prototype.matchall": "4.0.12", "string.prototype.repeat": "1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], + + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@7.1.1", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/parser": "7.29.3", "hermes-parser": "0.25.1", "zod": "4.4.3", "zod-validation-error": "4.0.2" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g=="], + + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "4.3.0", "estraverse": "5.3.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "8.16.0", "acorn-jsx": "5.3.2", "eslint-visitor-keys": "4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "5.3.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "5.3.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "estree-util-attach-comments": ["estree-util-attach-comments@3.0.0", "", { "dependencies": { "@types/estree": "1.0.9" } }, "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw=="], + + "estree-util-build-jsx": ["estree-util-build-jsx@3.0.1", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "devlop": "1.1.0", "estree-util-is-identifier-name": "3.0.0", "estree-walker": "3.0.3" } }, "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ=="], + + "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="], + + "estree-util-scope": ["estree-util-scope@1.0.0", "", { "dependencies": { "@types/estree": "1.0.9", "devlop": "1.1.0" } }, "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ=="], + + "estree-util-to-js": ["estree-util-to-js@2.0.0", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "astring": "1.9.0", "source-map": "0.7.6" } }, "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg=="], + + "estree-util-value-to-estree": ["estree-util-value-to-estree@3.5.0", "", { "dependencies": { "@types/estree": "1.0.9" } }, "sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ=="], + + "estree-util-visit": ["estree-util-visit@2.0.0", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "@types/unist": "3.0.3" } }, "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww=="], + + "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "1.0.9" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], + + "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "3.0.8" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], + + "eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], + + "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "7.0.6", "get-stream": "6.0.1", "human-signals": "2.1.0", "is-stream": "2.0.1", "merge-stream": "2.0.0", "npm-run-path": "4.0.1", "onetime": "5.1.2", "signal-exit": "3.0.7", "strip-final-newline": "2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], + + "expo": ["expo@56.0.15", "", { "dependencies": { "@babel/runtime": "7.29.2", "@expo/cli": "56.1.19", "@expo/config": "56.0.11", "@expo/config-plugins": "56.0.12", "@expo/devtools": "56.0.2", "@expo/dom-webview": "56.0.6", "@expo/fingerprint": "0.19.7", "@expo/local-build-cache-provider": "56.0.9", "@expo/log-box": "56.0.14", "@expo/metro": "56.0.0", "@expo/metro-config": "56.0.16", "@ungap/structured-clone": "1.3.1", "babel-preset-expo": "56.0.17", "expo-asset": "56.0.19", "expo-constants": "56.0.20", "expo-file-system": "56.0.8", "expo-font": "56.0.7", "expo-keep-awake": "56.0.3", "expo-modules-autolinking": "56.0.19", "expo-modules-core": "56.0.20", "pretty-format": "29.7.0", "react-refresh": "0.14.2", "whatwg-url-minimum": "0.1.2" }, "peerDependencies": { "@expo/metro-runtime": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-web": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/metro-runtime", "react-dom", "react-native-web", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-Tnas9Sq1fDY865rhSQ4266Kd4GULEUyBEBEchbNLQsiY6U+AAt4MgCKJUsRvUkNHdaZwnGzexy6hdnOjsgvNcA=="], + + "expo-asset": ["expo-asset@56.0.19", "", { "dependencies": { "@expo/image-utils": "0.10.2", "expo-constants": "56.0.20" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-huGY0bVfYUivNOir+iUEjjW9IbNHzLFNo8d6FGh22u1OsXcFR7Za3vpu5V1gMp0dc31wiqmsXkTazjm+Rro3vA=="], + + "expo-constants": ["expo-constants@56.0.20", "", { "dependencies": { "@expo/env": "2.3.1" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-4HgoVvUiMvcqujr/CUj7L1tumLWj8WX0PLM77OriDPoaJrMEwUHd841m4o4IoUyMPVT8XTiTiPFwJtGali8+9Q=="], + + "expo-dev-client": ["expo-dev-client@56.0.22", "", { "dependencies": { "expo-dev-launcher": "56.0.23", "expo-dev-menu": "56.0.19", "expo-dev-menu-interface": "56.0.1", "expo-manifests": "56.0.4", "expo-updates-interface": "56.0.2" }, "peerDependencies": { "expo": "*" } }, "sha512-LKhgIlMu8DkmhTtfurpX9YMPsnv4QI1hCcDZqcFn+jlB+s6yE1THB9UWZ+BVtef8kYMzsw+BH3ClXvNkRd0vXw=="], + + "expo-dev-launcher": ["expo-dev-launcher@56.0.23", "", { "dependencies": { "@expo/schema-utils": "56.0.2", "expo-dev-menu": "56.0.19", "expo-manifests": "56.0.4" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-OKgLAn6m15Lu+Qyg8WA0HPurFR9pxhsrHUvvafv8pTZHspB0BbOvBwhOJdxgiMfR2LHq4032cnMf8164Vzqeng=="], + + "expo-dev-menu": ["expo-dev-menu@56.0.19", "", { "dependencies": { "expo-dev-menu-interface": "56.0.1" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-sm6dfnkq3lgbn39Kd4yjFFm7UQAZqm6Hn3OpjagGtWBoWByQae3nKh1MF5K4Peh172TqUPJTOhjRasnZSkUkOQ=="], + + "expo-dev-menu-interface": ["expo-dev-menu-interface@56.0.1", "", { "peerDependencies": { "expo": "*" } }, "sha512-odATx0ZL/Kis10sKSBiKiGQxAB6coSi/KQtKcMhnQVNno6FkRh5/4e5BqcEvpq2rNMTiQp4ytNAQHtdwbPXvGA=="], + + "expo-doctor": ["expo-doctor@1.19.8", "", { "bin": { "expo-doctor": "bin/expo-doctor.js" } }, "sha512-ZHpQM+BfJe1DNaA+/ObtLYazC2x78tIV3kkfoSGR46Tj1EvzOFh1p9gFHsILI9TOyXPEcgxCkFw9AVvf8C4c1g=="], + + "expo-file-system": ["expo-file-system@56.0.8", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-NrH41/8snGIBSbYicwVLB4txPdgCATd7ZYhMAGS3YJZ9GbnduhlAoV4/YCbGayjrbpE9bJb/6wegPL/zmvRMnQ=="], + + "expo-font": ["expo-font@56.0.7", "", { "dependencies": { "fontfaceobserver": "2.3.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-hpU/vRwPzsby9lPGkA4blDqLIIXYzoWnCZHr6PxvcWbY/uPObAiyhh6q+e0WYsB65SthK+PLH95jEnVag7fwEg=="], + + "expo-json-utils": ["expo-json-utils@56.0.0", "", {}, "sha512-lUqyv9aIGDbYTQ5Nux2FnH2/Dz0w5uJ8Pr080eS0StXi2jr5OmuMNErpzUnpfnYOU55xKotd4AHv68PfV/ludg=="], + + "expo-keep-awake": ["expo-keep-awake@56.0.3", "", { "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-CLMJXtEiMKknD3Rpm8CRwE6ZJUzu2yCEmRk1sgfHAJ1zIbuEWY3dpPDubtsnuzWm+2k6Sru+yaFbYsvPWmTiBA=="], + + "expo-manifests": ["expo-manifests@56.0.4", "", { "dependencies": { "expo-json-utils": "56.0.0" }, "peerDependencies": { "expo": "*" } }, "sha512-Fokawl2UkiExIF0bqGoblRFA8lYpROVD+EpvDwSW4LgqQyPwNua1gLSgHZjdl5GsVugfRMMWE3LHaibDyX93hw=="], + + "expo-mcp": ["expo-mcp@0.2.4", "", { "dependencies": { "@expo/mcp-tunnel": "0.2.4", "@modelcontextprotocol/sdk": "1.29.0", "debug": "4.4.3", "glob": "11.1.0", "jimp-compact": "0.16.1", "resolve-from": "5.0.0", "ws": "8.21.0", "xml2js": "0.6.2", "zod": "3.25.76", "zx": "8.8.5" }, "bin": { "expo-mcp": "bin/expo-mcp.mjs" } }, "sha512-rBomlm+085wNa+UF9YC3bXGZR6LlYPfOlUXwKBB5R7+dnASk0VjWFETuxyApdtXw9OItmOsAXolUxrAlEYfqSA=="], + + "expo-modules-autolinking": ["expo-modules-autolinking@56.0.19", "", { "dependencies": { "@expo/require-utils": "56.1.4", "@expo/spawn-async": "1.8.0", "chalk": "4.1.2", "commander": "7.2.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "sha512-ztzTzS21fbq4oJQItSgT+WWJMZXGsC0GdX/cDN/GBhCTPiZz8foHkVa14DiLa5CWd7pEZ9EeSMdHDcAEc2dZ5Q=="], + + "expo-modules-core": ["expo-modules-core@56.0.20", "", { "dependencies": { "@expo/expo-modules-macros-plugin": "0.2.2", "expo-modules-jsi": "56.0.12", "invariant": "2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-worklets": "^0.7.4 || ^0.8.0" }, "optionalPeers": ["react-native-worklets"] }, "sha512-Xagwt/gC6sV1jiSnlFrYxLooZr90adLrpV64YlkXZjgZ6Kot89FF62e457RyejLtyDm2pOdy6FZphF1ReyK2Jw=="], + + "expo-modules-jsi": ["expo-modules-jsi@56.0.12", "", { "peerDependencies": { "react-native": "*" } }, "sha512-OnXiNbXzYybZPh5QnJyIIwQjQfN7PP4Di/2Hz0xQHKLgQmCfn/zAQziOjbUXVeL3cAyZ8+uDnTDYmDAc3B2qhQ=="], + + "expo-server": ["expo-server@56.0.5", "", {}, "sha512-SmM2p2g3Jrktpiazcst+OxhjSzOHXKAY4BPURHYHXvApzzoybMmrNF4IEZ8DKZ145BhSe4ydAmlEFCRTsdtgUQ=="], + + "expo-splash-screen": ["expo-splash-screen@56.0.12", "", { "dependencies": { "@expo/config-plugins": "56.0.12", "@expo/image-utils": "0.10.2", "xml2js": "0.6.0" }, "peerDependencies": { "expo": "*" } }, "sha512-RvEtJ78aNpuxdVD8TCe9viKtlYGzS9hW20fbvqvkeXDN6WAaYo1CRitPdjWNkaNNSPKOolp3zfha4EGdhXOtxg=="], + + "expo-sqlite": ["expo-sqlite@56.0.5", "", { "dependencies": { "await-lock": "2.2.2" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-wHYRVLS5nUFEtli45wHaO+RjlRY8sQXyOSgENVk6I4zq7+FgySqjOk3YOYW6IKIMwhj5XzjMJO+pY8xKUy73Kw=="], + + "expo-system-ui": ["expo-system-ui@56.0.5", "", { "dependencies": { "@react-native/normalize-colors": "0.85.3", "debug": "4.4.3" }, "peerDependencies": { "expo": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-n1MmnUArV4cc3gVed9fGtluPme00PE9axKVx+NHbKxHFMam5l4GcOI7PxbYKFNx8o7WA1LRD7eLW33agmZrxGg=="], + + "expo-updates-interface": ["expo-updates-interface@56.0.2", "", { "peerDependencies": { "expo": "*" } }, "sha512-eWTwSZ9y8vrULG2oBn2TQSSIwBGSq/TxGJ3jY6tuVS2FWH/ASRIiKs3zkUZTRoC3ZuV2alz0mUClYV7nNrFx8g=="], + + "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], + + "express": ["express@5.2.1", "", { "dependencies": { "accepts": "2.0.0", "body-parser": "2.2.2", "content-disposition": "1.1.0", "content-type": "1.0.5", "cookie": "0.7.2", "cookie-signature": "1.2.2", "debug": "4.4.3", "depd": "2.0.0", "encodeurl": "2.0.0", "escape-html": "1.0.3", "etag": "1.8.1", "finalhandler": "2.1.1", "fresh": "2.0.0", "http-errors": "2.0.1", "merge-descriptors": "2.0.0", "mime-types": "3.0.2", "on-finished": "2.4.1", "once": "1.4.0", "parseurl": "1.3.3", "proxy-addr": "2.0.7", "qs": "6.15.2", "range-parser": "1.2.1", "router": "2.2.0", "send": "1.2.1", "serve-static": "2.2.1", "statuses": "2.0.2", "type-is": "2.1.0", "vary": "1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], + + "express-rate-limit": ["express-rate-limit@8.5.2", "", { "dependencies": { "ip-address": "10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A=="], + + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "@nodelib/fs.walk": "1.2.8", "glob-parent": "5.1.2", "merge2": "1.4.1", "micromatch": "4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="], + + "fast-xml-builder": ["fast-xml-builder@1.3.0", "", { "dependencies": { "path-expression-matcher": "1.6.2", "xml-naming": "0.3.0" } }, "sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ=="], + + "fast-xml-parser": ["fast-xml-parser@5.10.1", "", { "dependencies": { "@nodable/entities": "3.0.0", "fast-xml-builder": "1.3.0", "is-unsafe": "2.0.0", "path-expression-matcher": "1.6.2", "strnum": "2.4.1", "xml-naming": "0.3.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw=="], + + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "1.1.0" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + + "fb-dotslash": ["fb-dotslash@0.5.8", "", { "bin": { "dotslash": "bin/dotslash" } }, "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA=="], + + "fb-watchman": ["fb-watchman@2.0.2", "", { "dependencies": { "bser": "2.1.1" } }, "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA=="], + + "fbjs": ["fbjs@3.0.5", "", { "dependencies": { "cross-fetch": "3.2.0", "fbjs-css-vars": "1.0.2", "loose-envify": "1.4.0", "object-assign": "4.1.1", "promise": "7.3.1", "setimmediate": "1.0.5", "ua-parser-js": "1.0.41" } }, "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg=="], + + "fbjs-css-vars": ["fbjs-css-vars@1.0.2", "", {}, "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fetch-nodeshim": ["fetch-nodeshim@0.4.10", "", {}, "sha512-m6I8ALe4L4XpdETy7MJZWs6L1IVMbjs99bwbpIKphxX+0CTns4IKDWJY0LWfr4YsFjfg+z1TjzTMU8lKl8rG0w=="], + + "figures": ["figures@3.2.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "4.0.1" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "finalhandler": ["finalhandler@1.1.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "1.0.2", "escape-html": "1.0.3", "on-finished": "2.3.0", "parseurl": "1.3.3", "statuses": "1.5.0", "unpipe": "1.0.0" } }, "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "6.0.0", "path-exists": "4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "3.4.2", "keyv": "4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="], + + "flow-enums-runtime": ["flow-enums-runtime@0.0.6", "", {}, "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw=="], + + "fontfaceobserver": ["fontfaceobserver@2.3.0", "", {}, "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg=="], + + "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "7.0.6", "signal-exit": "4.1.0" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "framer-motion": ["framer-motion@13.1.0", "", { "dependencies": { "motion-dom": "13.0.0", "motion-utils": "13.0.0", "tslib": "2.8.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-QSZrF0Id3QGuHJ+OL+9PSY9pk86C8ERFalwAGSchzTm65+ZoGH/RM26lmEARLljcHj2lqhv0jZOOks+EI3COOw=="], + + "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], + + "fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "4.2.11", "jsonfile": "4.0.0", "universalify": "0.1.2" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "fumadocs-core": ["fumadocs-core@16.9.3", "", { "dependencies": { "@orama/orama": "3.1.18", "estree-util-value-to-estree": "3.5.0", "github-slugger": "2.0.0", "hast-util-to-estree": "3.1.3", "hast-util-to-jsx-runtime": "2.3.6", "js-yaml": "4.3.0", "mdast-util-mdx": "3.0.0", "mdast-util-to-markdown": "2.1.2", "remark": "15.0.1", "remark-gfm": "4.0.1", "remark-rehype": "11.1.2", "scroll-into-view-if-needed": "3.1.0", "shiki": "4.1.0", "tinyglobby": "0.2.16", "unified": "11.0.5", "unist-util-visit": "5.1.0", "vfile": "6.0.3" }, "peerDependencies": { "@mdx-js/mdx": "*", "@mixedbread/sdk": "0.x.x", "@orama/core": "1.x.x", "@oramacloud/client": "2.x.x", "@tanstack/react-router": "1.x.x", "@types/estree-jsx": "*", "@types/hast": "*", "@types/mdast": "*", "@types/react": "*", "algoliasearch": "5.x.x", "flexsearch": "*", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "*", "zod": "4.x.x" }, "optionalPeers": ["@mdx-js/mdx", "@mixedbread/sdk", "@orama/core", "@oramacloud/client", "@tanstack/react-router", "@types/estree-jsx", "@types/hast", "@types/mdast", "@types/react", "algoliasearch", "flexsearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-8RVzKnzBJR5o+tJCccY28ntekfMQYBoYiz7alnYb/d9YJc+XpnsINzTl63lQ1eBMZ9gdhm2MqRtgUjh/8rUrbw=="], + + "fumadocs-mdx": ["fumadocs-mdx@15.0.10", "", { "dependencies": { "@mdx-js/mdx": "3.1.1", "@standard-schema/spec": "1.1.0", "chokidar": "5.0.0", "esbuild": "0.28.1", "estree-util-value-to-estree": "3.5.0", "js-yaml": "4.3.0", "mdast-util-mdx": "3.0.0", "picocolors": "1.1.1", "picomatch": "4.0.4", "tinyexec": "1.2.4", "tinyglobby": "0.2.16", "unified": "11.0.5", "unist-util-remove-position": "5.0.0", "unist-util-visit": "5.1.0", "vfile": "6.0.3", "zod": "4.4.3" }, "peerDependencies": { "@types/mdast": "*", "@types/mdx": "*", "@types/react": "*", "fumadocs-core": "^16.7.0", "mdast-util-directive": "*", "next": "^15.3.0 || ^16.0.0", "react": "^19.2.0", "rolldown": "*", "vite": "7.x.x || 8.x.x" }, "optionalPeers": ["@types/mdast", "@types/mdx", "@types/react", "mdast-util-directive", "next", "react", "rolldown", "vite"], "bin": { "fumadocs-mdx": "./bin.js" } }, "sha512-kH3S7ESS9yXTAaCkA8dDugsCK/MbnpgyZ5qBEL7cWoavV0O/T4+4YTYFkvNknz7cw+T/r+OG0p2BvlVhkk4fww=="], + + "fumadocs-ui": ["fumadocs-ui@16.9.3", "", { "dependencies": { "@fumadocs/tailwind": "0.0.5", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-slot": "1.2.4", "@radix-ui/react-tabs": "1.1.13", "class-variance-authority": "0.7.1", "lucide-react": "1.17.0", "motion": "12.40.0", "next-themes": "0.4.6", "react-remove-scroll": "2.7.2", "rehype-raw": "7.0.0", "scroll-into-view-if-needed": "3.1.0", "shiki": "4.1.0", "tailwind-merge": "3.6.0", "unist-util-visit": "5.1.0" }, "peerDependencies": { "@takumi-rs/image-response": "*", "@types/mdx": "*", "@types/react": "*", "fumadocs-core": "16.9.3", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0" }, "optionalPeers": ["@takumi-rs/image-response", "@types/mdx", "@types/react", "next"] }, "sha512-eoVKj1H+ATut0su+WIoPWBLRqzPMGD0hekIBr4GopWvUg1lS997HL4kP+Leyf+3CYlZtFgyXb6ylbvRLFtEj6Q=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-properties": "1.2.1", "functions-have-names": "1.2.3", "hasown": "2.0.3", "is-callable": "1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], + + "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], + + "fzstd": ["fzstd@0.1.1", "", {}, "sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA=="], + + "generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-define-property": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.2", "function-bind": "1.1.2", "get-proto": "1.0.1", "gopd": "1.2.0", "has-symbols": "1.1.0", "hasown": "2.0.3", "math-intrinsics": "1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "1.0.1", "es-object-atoms": "1.1.2" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + + "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "get-intrinsic": "1.3.0" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], + + "get-tsconfig": ["get-tsconfig@4.14.0", "", { "dependencies": { "resolve-pkg-maps": "1.0.0" } }, "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA=="], + + "getenv": ["getenv@2.0.0", "", {}, "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ=="], + + "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], + + "glob": ["glob@11.1.0", "", { "dependencies": { "foreground-child": "3.3.1", "jackspeak": "4.2.3", "minimatch": "10.2.5", "minipass": "7.1.3", "package-json-from-dist": "1.0.1", "path-scurry": "2.0.2" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="], + + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "1.2.1", "gopd": "1.2.0" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "handlebars": ["handlebars@4.7.9", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ=="], + + "hard-rejection": ["hard-rejection@2.1.0", "", {}, "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA=="], + + "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "1.0.1" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "1.0.1" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "1.1.0" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.3", "", { "dependencies": { "function-bind": "1.1.2" } }, "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg=="], + + "hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "3.0.4", "@types/unist": "3.0.3", "devlop": "1.1.0", "hastscript": "9.0.1", "property-information": "7.1.0", "vfile": "6.0.3", "vfile-location": "5.0.3", "web-namespaces": "2.0.1" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="], + + "hast-util-parse-selector": ["hast-util-parse-selector@4.0.0", "", { "dependencies": { "@types/hast": "3.0.4" } }, "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A=="], + + "hast-util-raw": ["hast-util-raw@9.1.0", "", { "dependencies": { "@types/hast": "3.0.4", "@types/unist": "3.0.3", "@ungap/structured-clone": "1.3.1", "hast-util-from-parse5": "8.0.3", "hast-util-to-parse5": "8.0.1", "html-void-elements": "3.0.0", "mdast-util-to-hast": "13.2.1", "parse5": "7.3.0", "unist-util-position": "5.0.0", "unist-util-visit": "5.1.0", "vfile": "6.0.3", "web-namespaces": "2.0.1", "zwitch": "2.0.4" } }, "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw=="], + + "hast-util-to-estree": ["hast-util-to-estree@3.1.3", "", { "dependencies": { "@types/estree": "1.0.9", "@types/estree-jsx": "1.0.5", "@types/hast": "3.0.4", "comma-separated-tokens": "2.0.3", "devlop": "1.1.0", "estree-util-attach-comments": "3.0.0", "estree-util-is-identifier-name": "3.0.0", "hast-util-whitespace": "3.0.0", "mdast-util-mdx-expression": "2.0.1", "mdast-util-mdx-jsx": "3.2.0", "mdast-util-mdxjs-esm": "2.0.1", "property-information": "7.1.0", "space-separated-tokens": "2.0.2", "style-to-js": "1.1.21", "unist-util-position": "5.0.0", "zwitch": "2.0.4" } }, "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w=="], + + "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "3.0.4", "@types/unist": "3.0.3", "ccount": "2.0.1", "comma-separated-tokens": "2.0.3", "hast-util-whitespace": "3.0.0", "html-void-elements": "3.0.0", "mdast-util-to-hast": "13.2.1", "property-information": "7.1.0", "space-separated-tokens": "2.0.2", "stringify-entities": "4.0.4", "zwitch": "2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], + + "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "1.0.9", "@types/hast": "3.0.4", "@types/unist": "3.0.3", "comma-separated-tokens": "2.0.3", "devlop": "1.1.0", "estree-util-is-identifier-name": "3.0.0", "hast-util-whitespace": "3.0.0", "mdast-util-mdx-expression": "2.0.1", "mdast-util-mdx-jsx": "3.2.0", "mdast-util-mdxjs-esm": "2.0.1", "property-information": "7.1.0", "space-separated-tokens": "2.0.2", "style-to-js": "1.1.21", "unist-util-position": "5.0.0", "vfile-message": "4.0.3" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="], + + "hast-util-to-parse5": ["hast-util-to-parse5@8.0.1", "", { "dependencies": { "@types/hast": "3.0.4", "comma-separated-tokens": "2.0.3", "devlop": "1.1.0", "property-information": "7.1.0", "space-separated-tokens": "2.0.2", "web-namespaces": "2.0.1", "zwitch": "2.0.4" } }, "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA=="], + + "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "3.0.4" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], + + "hastscript": ["hastscript@9.0.1", "", { "dependencies": { "@types/hast": "3.0.4", "comma-separated-tokens": "2.0.3", "hast-util-parse-selector": "4.0.0", "property-information": "7.1.0", "space-separated-tokens": "2.0.2" } }, "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w=="], + + "he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], + + "hermes-compiler": ["hermes-compiler@250829098.0.10", "", {}, "sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w=="], + + "hermes-estree": ["hermes-estree@0.33.3", "", {}, "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg=="], + + "hermes-parser": ["hermes-parser@0.33.3", "", { "dependencies": { "hermes-estree": "0.33.3" } }, "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA=="], + + "hono": ["hono@4.12.22", "", {}, "sha512-7fvVPbB92zNRsQke+uiRGwtTuef0tB2Dg4hWxYfFNvkQhIltWoyi0ONReM5LWA+jJWS3nfT5lTq+qbsIpX0IQw=="], + + "hosted-git-info": ["hosted-git-info@7.0.2", "", { "dependencies": { "lru-cache": "10.4.3" } }, "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w=="], + + "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], + + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.2", "toidentifier": "1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "7.1.4", "debug": "4.4.3" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + + "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + + "hyphenate-style-name": ["hyphenate-style-name@1.1.0", "", {}, "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw=="], + + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": "2.1.2" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "1.0.1", "resolve-from": "4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], + + "inline-style-prefixer": ["inline-style-prefixer@7.0.1", "", { "dependencies": { "css-in-js-utils": "3.1.0" } }, "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw=="], + + "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "hasown": "2.0.3", "side-channel": "1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + + "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "1.4.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], + + "ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="], + + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], + + "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "2.0.1", "is-decimal": "2.0.1" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], + + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "get-intrinsic": "1.3.0" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], + + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + + "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "1.0.0", "call-bound": "1.0.4", "get-proto": "1.0.1", "has-tostringtag": "1.0.2", "safe-regex-test": "1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], + + "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "1.1.0" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], + + "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], + + "is-bun-module": ["is-bun-module@2.0.0", "", { "dependencies": { "semver": "7.8.1" } }, "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ=="], + + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + + "is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="], + + "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "get-intrinsic": "1.3.0", "is-typed-array": "1.1.15" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], + + "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], + + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], + + "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "1.0.4" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "1.0.4", "generator-function": "2.0.1", "get-proto": "1.0.1", "has-tostringtag": "1.0.2", "safe-regex-test": "1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], + + "is-interactive": ["is-interactive@1.0.0", "", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="], + + "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], + + "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], + + "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], + + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + + "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "1.0.4", "gopd": "1.2.0", "has-tostringtag": "1.0.2", "hasown": "2.0.3" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], + + "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], + + "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "1.0.4" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], + + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], + + "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "1.0.4", "has-symbols": "1.1.0", "safe-regex-test": "1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], + + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "1.1.20" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], + + "is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], + + "is-unsafe": ["is-unsafe@2.0.0", "", {}, "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA=="], + + "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], + + "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "1.0.4" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], + + "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "1.0.4", "get-intrinsic": "1.3.0" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], + + "is-wsl": ["is-wsl@1.1.0", "", {}, "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw=="], + + "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "1.1.4", "es-object-atoms": "1.1.2", "get-intrinsic": "1.3.0", "get-proto": "1.0.1", "has-symbols": "1.1.0", "set-function-name": "2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], + + "jackspeak": ["jackspeak@4.2.3", "", { "dependencies": { "@isaacs/cliui": "9.0.0" } }, "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg=="], + + "jest-get-type": ["jest-get-type@29.6.3", "", {}, "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw=="], + + "jest-util": ["jest-util@29.7.0", "", { "dependencies": { "@jest/types": "29.6.3", "@types/node": "24.12.4", "chalk": "4.1.2", "ci-info": "3.9.0", "graceful-fs": "4.2.11", "picomatch": "2.3.2" } }, "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA=="], + + "jest-validate": ["jest-validate@29.7.0", "", { "dependencies": { "@jest/types": "29.6.3", "camelcase": "6.3.0", "chalk": "4.1.2", "jest-get-type": "29.6.3", "leven": "3.1.0", "pretty-format": "29.7.0" } }, "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw=="], + + "jest-worker": ["jest-worker@29.7.0", "", { "dependencies": { "@types/node": "24.12.4", "jest-util": "29.7.0", "merge-stream": "2.0.0", "supports-color": "8.1.1" } }, "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw=="], + + "jimp-compact": ["jimp-compact@0.16.1", "", {}, "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww=="], + + "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + + "joi": ["joi@17.13.4", "", { "dependencies": { "@hapi/hoek": "9.3.0", "@hapi/topo": "5.1.0", "@sideway/address": "4.1.5", "@sideway/formula": "3.0.1", "@sideway/pinpoint": "2.0.0" } }, "sha512-1RuuER6kmt8K8I3nIWvPZKi5RQCb568ZPyY4Pwjlua+yo+63ZTmIwxLZH0heBmiKN4uxjvCiarDrjaeH84xicQ=="], + + "jose": ["jose@6.2.3", "", {}, "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@4.3.0", "", { "dependencies": { "argparse": "2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q=="], + + "jsc-safe-url": ["jsc-safe-url@0.2.4", "", {}, "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q=="], + + "jsep": ["jsep@1.4.0", "", {}, "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + + "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "4.2.11" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + + "jsonpath-plus": ["jsonpath-plus@10.4.0", "", { "dependencies": { "@jsep-plugin/assignment": "^1.3.0", "@jsep-plugin/regex": "^1.0.4", "jsep": "^1.4.0" }, "bin": { "jsonpath": "bin/jsonpath-cli.js", "jsonpath-plus": "bin/jsonpath-cli.js" } }, "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA=="], + + "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "3.1.9", "array.prototype.flat": "1.3.3", "object.assign": "4.1.7", "object.values": "1.2.1" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], + + "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], + + "lan-network": ["lan-network@0.2.1", "", { "bin": { "lan-network": "dist/lan-network-cli.js" } }, "sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A=="], + + "launch-editor": ["launch-editor@2.14.1", "", { "dependencies": { "picocolors": "1.1.1", "shell-quote": "1.8.4" } }, "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA=="], + + "leven": ["leven@3.1.0", "", {}, "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "1.2.1", "type-check": "0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "lighthouse-logger": ["lighthouse-logger@1.4.2", "", { "dependencies": { "debug": "2.6.9", "marky": "1.3.0" } }, "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g=="], + + "lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], + + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], + + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="], + + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="], + + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="], + + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="], + + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="], + + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="], + + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="], + + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="], + + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="], + + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash.debounce": ["lodash.debounce@4.0.8", "", {}, "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="], + + "lodash.ismatch": ["lodash.ismatch@4.4.0", "", {}, "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "lodash.throttle": ["lodash.throttle@4.1.1", "", {}, "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="], + + "log-symbols": ["log-symbols@2.2.0", "", { "dependencies": { "chalk": "2.4.2" } }, "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg=="], + + "logkitty": ["logkitty@0.7.1", "", { "dependencies": { "ansi-fragments": "0.2.1", "dayjs": "1.11.21", "yargs": "15.4.1" }, "bin": { "logkitty": "bin/logkitty.js" } }, "sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ=="], + + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], + + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "3.1.1" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "lucide-react": ["lucide-react@1.17.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "makeerror": ["makeerror@1.0.12", "", { "dependencies": { "tmpl": "1.0.5" } }, "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="], + + "map-obj": ["map-obj@4.3.0", "", {}, "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ=="], + + "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], + + "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], + + "marky": ["marky@1.3.0", "", {}, "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "4.0.4", "escape-string-regexp": "5.0.0", "unist-util-is": "6.0.1", "unist-util-visit-parents": "6.0.2" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="], + + "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.3", "", { "dependencies": { "@types/mdast": "4.0.4", "@types/unist": "3.0.3", "decode-named-character-reference": "1.3.0", "devlop": "1.1.0", "mdast-util-to-string": "4.0.0", "micromark": "4.0.2", "micromark-util-decode-numeric-character-reference": "2.0.2", "micromark-util-decode-string": "2.0.1", "micromark-util-normalize-identifier": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2", "unist-util-stringify-position": "4.0.0" } }, "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q=="], + + "mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "2.0.3", "mdast-util-gfm-autolink-literal": "2.0.1", "mdast-util-gfm-footnote": "2.1.0", "mdast-util-gfm-strikethrough": "2.0.0", "mdast-util-gfm-table": "2.0.0", "mdast-util-gfm-task-list-item": "2.0.0", "mdast-util-to-markdown": "2.1.2" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="], + + "mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "4.0.4", "ccount": "2.0.1", "devlop": "1.1.0", "mdast-util-find-and-replace": "3.0.2", "micromark-util-character": "2.1.1" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="], + + "mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "4.0.4", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.3", "mdast-util-to-markdown": "2.1.2", "micromark-util-normalize-identifier": "2.0.1" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="], + + "mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "mdast-util-from-markdown": "2.0.3", "mdast-util-to-markdown": "2.1.2" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="], + + "mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "devlop": "1.1.0", "markdown-table": "3.0.4", "mdast-util-from-markdown": "2.0.3", "mdast-util-to-markdown": "2.1.2" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="], + + "mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.3", "mdast-util-to-markdown": "2.1.2" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="], + + "mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "2.0.3", "mdast-util-mdx-expression": "2.0.1", "mdast-util-mdx-jsx": "3.2.0", "mdast-util-mdxjs-esm": "2.0.1", "mdast-util-to-markdown": "2.1.2" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="], + + "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.3", "mdast-util-to-markdown": "2.1.2" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="], + + "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "@types/unist": "3.0.3", "ccount": "2.0.1", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.3", "mdast-util-to-markdown": "2.1.2", "parse-entities": "4.0.2", "stringify-entities": "4.0.4", "unist-util-stringify-position": "4.0.0", "vfile-message": "4.0.3" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="], + + "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.3", "mdast-util-to-markdown": "2.1.2" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="], + + "mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "4.0.4", "unist-util-is": "6.0.1" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="], + + "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "@ungap/structured-clone": "1.3.1", "devlop": "1.1.0", "micromark-util-sanitize-uri": "2.0.1", "trim-lines": "3.0.1", "unist-util-position": "5.0.0", "unist-util-visit": "5.1.0", "vfile": "6.0.3" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="], + + "mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "4.0.4", "@types/unist": "3.0.3", "longest-streak": "3.1.0", "mdast-util-phrasing": "4.1.0", "mdast-util-to-string": "4.0.0", "micromark-util-classify-character": "2.0.1", "micromark-util-decode-string": "2.0.1", "unist-util-visit": "5.1.0", "zwitch": "2.0.4" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="], + + "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "4.0.4" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], + + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + + "memoize-one": ["memoize-one@5.2.1", "", {}, "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="], + + "meow": ["meow@8.1.2", "", { "dependencies": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", "decamelize-keys": "^1.1.0", "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", "normalize-package-data": "^3.0.0", "read-pkg-up": "^7.0.1", "redent": "^3.0.0", "trim-newlines": "^3.0.0", "type-fest": "^0.18.0", "yargs-parser": "^20.2.3" } }, "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q=="], + + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "metro": ["metro@0.84.4", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/core": "7.29.0", "@babel/generator": "7.29.1", "@babel/parser": "7.29.3", "@babel/template": "7.28.6", "@babel/traverse": "7.29.0", "@babel/types": "7.29.0", "accepts": "2.0.0", "ci-info": "2.0.0", "connect": "3.7.0", "debug": "4.4.3", "error-stack-parser": "2.1.4", "flow-enums-runtime": "0.0.6", "graceful-fs": "4.2.11", "hermes-parser": "0.35.0", "image-size": "1.2.1", "invariant": "2.2.4", "jest-worker": "29.7.0", "jsc-safe-url": "0.2.4", "lodash.throttle": "4.1.1", "metro-babel-transformer": "0.84.4", "metro-cache": "0.84.4", "metro-cache-key": "0.84.4", "metro-config": "0.84.4", "metro-core": "0.84.4", "metro-file-map": "0.84.4", "metro-resolver": "0.84.4", "metro-runtime": "0.84.4", "metro-source-map": "0.84.4", "metro-symbolicate": "0.84.4", "metro-transform-plugins": "0.84.4", "metro-transform-worker": "0.84.4", "mime-types": "3.0.2", "nullthrows": "1.1.1", "serialize-error": "2.1.0", "source-map": "0.5.7", "throat": "5.0.0", "ws": "7.5.11", "yargs": "17.7.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA=="], + + "metro-babel-transformer": ["metro-babel-transformer@0.84.4", "", { "dependencies": { "@babel/core": "7.29.0", "flow-enums-runtime": "0.0.6", "hermes-parser": "0.35.0", "metro-cache-key": "0.84.4", "nullthrows": "1.1.1" } }, "sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g=="], + + "metro-cache": ["metro-cache@0.84.4", "", { "dependencies": { "exponential-backoff": "3.1.3", "flow-enums-runtime": "0.0.6", "https-proxy-agent": "7.0.6", "metro-core": "0.84.4" } }, "sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg=="], + + "metro-cache-key": ["metro-cache-key@0.84.4", "", { "dependencies": { "flow-enums-runtime": "0.0.6" } }, "sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw=="], + + "metro-config": ["metro-config@0.84.4", "", { "dependencies": { "connect": "3.7.0", "flow-enums-runtime": "0.0.6", "jest-validate": "29.7.0", "metro": "0.84.4", "metro-cache": "0.84.4", "metro-core": "0.84.4", "metro-runtime": "0.84.4", "yaml": "2.9.0" } }, "sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q=="], + + "metro-core": ["metro-core@0.84.4", "", { "dependencies": { "flow-enums-runtime": "0.0.6", "lodash.throttle": "4.1.1", "metro-resolver": "0.84.4" } }, "sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ=="], + + "metro-file-map": ["metro-file-map@0.84.4", "", { "dependencies": { "debug": "4.4.3", "fb-watchman": "2.0.2", "flow-enums-runtime": "0.0.6", "graceful-fs": "4.2.11", "invariant": "2.2.4", "jest-worker": "29.7.0", "micromatch": "4.0.8", "nullthrows": "1.1.1", "walker": "1.0.8" } }, "sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ=="], + + "metro-minify-terser": ["metro-minify-terser@0.84.4", "", { "dependencies": { "flow-enums-runtime": "0.0.6", "terser": "5.48.0" } }, "sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ=="], + + "metro-resolver": ["metro-resolver@0.84.4", "", { "dependencies": { "flow-enums-runtime": "0.0.6" } }, "sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A=="], + + "metro-runtime": ["metro-runtime@0.84.4", "", { "dependencies": { "@babel/runtime": "7.29.2", "flow-enums-runtime": "0.0.6" } }, "sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q=="], + + "metro-source-map": ["metro-source-map@0.84.4", "", { "dependencies": { "@babel/traverse": "7.29.0", "@babel/types": "7.29.0", "flow-enums-runtime": "0.0.6", "invariant": "2.2.4", "metro-symbolicate": "0.84.4", "nullthrows": "1.1.1", "ob1": "0.84.4", "source-map": "0.5.7", "vlq": "1.0.1" } }, "sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g=="], + + "metro-symbolicate": ["metro-symbolicate@0.84.4", "", { "dependencies": { "flow-enums-runtime": "0.0.6", "invariant": "2.2.4", "metro-source-map": "0.84.4", "nullthrows": "1.1.1", "source-map": "0.5.7", "vlq": "1.0.1" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA=="], + + "metro-transform-plugins": ["metro-transform-plugins@0.84.4", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/generator": "7.29.1", "@babel/template": "7.28.6", "@babel/traverse": "7.29.0", "flow-enums-runtime": "0.0.6", "nullthrows": "1.1.1" } }, "sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow=="], + + "metro-transform-worker": ["metro-transform-worker@0.84.4", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/generator": "7.29.1", "@babel/parser": "7.29.3", "@babel/types": "7.29.0", "flow-enums-runtime": "0.0.6", "metro": "0.84.4", "metro-babel-transformer": "0.84.4", "metro-cache": "0.84.4", "metro-cache-key": "0.84.4", "metro-minify-terser": "0.84.4", "metro-source-map": "0.84.4", "metro-transform-plugins": "0.84.4", "nullthrows": "1.1.1" } }, "sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg=="], + + "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "4.1.13", "debug": "4.4.3", "decode-named-character-reference": "1.3.0", "devlop": "1.1.0", "micromark-core-commonmark": "2.0.3", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-chunked": "2.0.1", "micromark-util-combine-extensions": "2.0.1", "micromark-util-decode-numeric-character-reference": "2.0.2", "micromark-util-encode": "2.0.1", "micromark-util-normalize-identifier": "2.0.1", "micromark-util-resolve-all": "2.0.1", "micromark-util-sanitize-uri": "2.0.1", "micromark-util-subtokenize": "2.1.0", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], + + "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "1.3.0", "devlop": "1.1.0", "micromark-factory-destination": "2.0.1", "micromark-factory-label": "2.0.1", "micromark-factory-space": "2.0.1", "micromark-factory-title": "2.0.1", "micromark-factory-whitespace": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-chunked": "2.0.1", "micromark-util-classify-character": "2.0.1", "micromark-util-html-tag-name": "2.0.1", "micromark-util-normalize-identifier": "2.0.1", "micromark-util-resolve-all": "2.0.1", "micromark-util-subtokenize": "2.1.0", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], + + "micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "2.1.0", "micromark-extension-gfm-footnote": "2.1.0", "micromark-extension-gfm-strikethrough": "2.1.0", "micromark-extension-gfm-table": "2.1.1", "micromark-extension-gfm-tagfilter": "2.0.0", "micromark-extension-gfm-task-list-item": "2.1.0", "micromark-util-combine-extensions": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="], + + "micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-sanitize-uri": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="], + + "micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "1.1.0", "micromark-core-commonmark": "2.0.3", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-normalize-identifier": "2.0.1", "micromark-util-sanitize-uri": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="], + + "micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "1.1.0", "micromark-util-chunked": "2.0.1", "micromark-util-classify-character": "2.0.1", "micromark-util-resolve-all": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="], + + "micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "dependencies": { "devlop": "1.1.0", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="], + + "micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "2.0.2" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="], + + "micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "1.1.0", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="], + + "micromark-extension-mdx-expression": ["micromark-extension-mdx-expression@3.0.1", "", { "dependencies": { "@types/estree": "1.0.9", "devlop": "1.1.0", "micromark-factory-mdx-expression": "2.0.3", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-events-to-acorn": "2.0.3", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q=="], + + "micromark-extension-mdx-jsx": ["micromark-extension-mdx-jsx@3.0.2", "", { "dependencies": { "@types/estree": "1.0.9", "devlop": "1.1.0", "estree-util-is-identifier-name": "3.0.0", "micromark-factory-mdx-expression": "2.0.3", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-events-to-acorn": "2.0.3", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2", "vfile-message": "4.0.3" } }, "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ=="], + + "micromark-extension-mdx-md": ["micromark-extension-mdx-md@2.0.0", "", { "dependencies": { "micromark-util-types": "2.0.2" } }, "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ=="], + + "micromark-extension-mdxjs": ["micromark-extension-mdxjs@3.0.0", "", { "dependencies": { "acorn": "8.16.0", "acorn-jsx": "5.3.2", "micromark-extension-mdx-expression": "3.0.1", "micromark-extension-mdx-jsx": "3.0.2", "micromark-extension-mdx-md": "2.0.0", "micromark-extension-mdxjs-esm": "3.0.0", "micromark-util-combine-extensions": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ=="], + + "micromark-extension-mdxjs-esm": ["micromark-extension-mdxjs-esm@3.0.0", "", { "dependencies": { "@types/estree": "1.0.9", "devlop": "1.1.0", "micromark-core-commonmark": "2.0.3", "micromark-util-character": "2.1.1", "micromark-util-events-to-acorn": "2.0.3", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2", "unist-util-position-from-estree": "2.0.0", "vfile-message": "4.0.3" } }, "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A=="], + + "micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="], + + "micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "1.1.0", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="], + + "micromark-factory-mdx-expression": ["micromark-factory-mdx-expression@2.0.3", "", { "dependencies": { "@types/estree": "1.0.9", "devlop": "1.1.0", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-events-to-acorn": "2.0.3", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2", "unist-util-position-from-estree": "2.0.0", "vfile-message": "4.0.3" } }, "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ=="], + + "micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-types": "2.0.2" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="], + + "micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="], + + "micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="], + + "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], + + "micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "2.0.1" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="], + + "micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="], + + "micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="], + + "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "2.0.1" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="], + + "micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "1.3.0", "micromark-util-character": "2.1.1", "micromark-util-decode-numeric-character-reference": "2.0.2", "micromark-util-symbol": "2.0.1" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="], + + "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], + + "micromark-util-events-to-acorn": ["micromark-util-events-to-acorn@2.0.3", "", { "dependencies": { "@types/estree": "1.0.9", "@types/unist": "3.0.3", "devlop": "1.1.0", "estree-util-visit": "2.0.0", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2", "vfile-message": "4.0.3" } }, "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg=="], + + "micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="], + + "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "2.0.1" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="], + + "micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "2.0.2" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="], + + "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-encode": "2.0.1", "micromark-util-symbol": "2.0.1" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="], + + "micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "1.1.0", "micromark-util-chunked": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="], + + "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], + + "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "3.0.3", "picomatch": "2.3.2" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + + "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="], + + "minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "1.1.14" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "minimist-options": ["minimist-options@4.1.0", "", { "dependencies": { "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", "kind-of": "^6.0.3" } }, "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A=="], + + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "modify-values": ["modify-values@1.0.1", "", {}, "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw=="], + + "motion": ["motion@13.1.0", "", { "dependencies": { "framer-motion": "13.1.0", "tslib": "2.8.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-qtvscq59uCPdWnNW4SdSkrxR+BS/QYsa923bx7ocA+4p+ZGNbbVQwkSnG4aukB81QWjtl3AxX36plxNyZLmHCA=="], + + "motion-dom": ["motion-dom@13.0.0", "", { "dependencies": { "motion-utils": "13.0.0" } }, "sha512-Xk+SJas70uMAUIApg+m3lZDShxI3LBFHq7mFGbBKoRXc2PVPDyAKmzN64Bbzt4CZdP/CItTiJxWtn4TA0v53Ng=="], + + "motion-utils": ["motion-utils@13.0.0", "", {}, "sha512-7DnN7TmbLcYXcG4RVadXIihWlyuM9afoUww8Y5Agg431kGKiuL2/OMyP4mJ5wLz+pvN3t5ySClLOaVXJ+wekRQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "multitars": ["multitars@1.0.0", "", {}, "sha512-H/J4fMLedtudftaYMOg7ajzLYgT3/rwbWVJbqr/iUgB8DQztn38ys5HOqI1CzSxx8QhXXwOOnnBvd4v3jG5+Mg=="], + + "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], + + "napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + + "next": ["next@16.2.7", "", { "dependencies": { "@next/env": "16.2.7", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "2.10.32", "caniuse-lite": "1.0.30001793", "postcss": "8.5.15", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.7", "@next/swc-darwin-x64": "16.2.7", "@next/swc-linux-arm64-gnu": "16.2.7", "@next/swc-linux-arm64-musl": "16.2.7", "@next/swc-linux-x64-gnu": "16.2.7", "@next/swc-linux-x64-musl": "16.2.7", "@next/swc-win32-arm64-msvc": "16.2.7", "@next/swc-win32-x64-msvc": "16.2.7", "sharp": "0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-eMJxgjRzBaj3olkP4cBamHDXL79A8FC6u1GcsO1D1Tsx8bw/LLXUJCaoajVxtnhD3A1IJqIT8IcRJjgBIPJq4w=="], + + "next-themes": ["next-themes@0.4.6", "", { "peerDependencies": { "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" } }, "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA=="], + + "nocache": ["nocache@3.0.4", "", {}, "sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw=="], + + "node-exports-info": ["node-exports-info@1.6.0", "", { "dependencies": { "array.prototype.flatmap": "1.3.3", "es-errors": "1.3.0", "object.entries": "1.1.9", "semver": "6.3.1" } }, "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw=="], + + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + + "node-forge": ["node-forge@1.4.0", "", {}, "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ=="], + + "node-html-parser": ["node-html-parser@6.1.13", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg=="], + + "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], + + "node-releases": ["node-releases@2.0.46", "", {}, "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ=="], + + "node-stream-zip": ["node-stream-zip@1.15.0", "", {}, "sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw=="], + + "normalize-package-data": ["normalize-package-data@3.0.3", "", { "dependencies": { "hosted-git-info": "^4.0.1", "is-core-module": "^2.5.0", "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" } }, "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA=="], + + "npm-package-arg": ["npm-package-arg@11.0.3", "", { "dependencies": { "hosted-git-info": "7.0.2", "proc-log": "4.2.0", "semver": "7.8.1", "validate-npm-package-name": "5.0.1" } }, "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw=="], + + "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "3.1.1" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "nullthrows": ["nullthrows@1.1.1", "", {}, "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw=="], + + "ob1": ["ob1@0.84.4", "", { "dependencies": { "flow-enums-runtime": "0.0.6" } }, "sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.2", "has-symbols": "1.1.0", "object-keys": "1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], + + "object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.2" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="], + + "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "1.0.9", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-object-atoms": "1.1.2" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], + + "object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "1.0.9", "define-properties": "1.2.1", "es-abstract": "1.24.2" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="], + + "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.2" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], + + "oliphaunt-example-browser-wasix": ["oliphaunt-example-browser-wasix@workspace:src/examples/browser-wasix"], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "on-headers": ["on-headers@1.1.0", "", {}, "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1.0.2" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + + "oniguruma-parser": ["oniguruma-parser@0.12.2", "", {}, "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="], + + "oniguruma-to-es": ["oniguruma-to-es@4.3.6", "", { "dependencies": { "oniguruma-parser": "0.12.2", "regex": "6.1.0", "regex-recursion": "6.0.2" } }, "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA=="], + + "open": ["open@6.4.0", "", { "dependencies": { "is-wsl": "1.1.0" } }, "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "0.1.4", "fast-levenshtein": "2.0.6", "levn": "0.4.1", "prelude-ls": "1.2.1", "type-check": "0.4.0", "word-wrap": "1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "ora": ["ora@3.4.0", "", { "dependencies": { "chalk": "2.4.2", "cli-cursor": "2.1.0", "cli-spinners": "2.9.2", "log-symbols": "2.2.0", "strip-ansi": "5.2.0", "wcwidth": "1.0.1" } }, "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg=="], + + "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "1.3.0", "object-keys": "1.1.1", "safe-push-apply": "1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "3.1.0" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + + "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "3.1.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "parse-diff": ["parse-diff@0.11.1", "", {}, "sha512-Oq4j8LAOPOcssanQkIjxosjATBIEJhCxMCxPhMu+Ci4wdNmAEdx0O+a7gzbR2PyKXgKPvRLIN5g224+dJAsKHA=="], + + "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "2.0.11", "character-entities-legacy": "3.0.0", "character-reference-invalid": "2.0.1", "decode-named-character-reference": "1.3.0", "is-alphanumerical": "2.0.1", "is-decimal": "2.0.1", "is-hexadecimal": "2.0.1" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], + + "parse-github-repo-url": ["parse-github-repo-url@1.4.1", "", {}, "sha512-bSWyzBKqcSL4RrncTpGsEKoJ7H8a4L3++ifTAbTFeMHyq2wRV+42DGmQcHIrJIvdcacjIOxEuKH/w4tthF17gg=="], + + "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "error-ex": "1.3.4", "json-parse-even-better-errors": "2.3.1", "lines-and-columns": "1.2.4" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], + + "parse-png": ["parse-png@2.1.0", "", { "dependencies": { "pngjs": "3.4.0" } }, "sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ=="], + + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "6.0.1" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-expression-matcher": ["path-expression-matcher@1.6.2", "", {}, "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ=="], + + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "11.5.0", "minipass": "7.1.3" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + + "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], + + "pg": ["pg@8.23.0", "", { "dependencies": { "pg-connection-string": "^2.14.0", "pg-pool": "^3.14.0", "pg-protocol": "^1.16.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.4.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-Ip2EQCngowJLGOfCwkFhPXU7/ljlhn6Rxlmy4XYfL2Y+vyRM59+8uR2xqRWKdYmbXmxCFOAmKxBuSUCdF34qLg=="], + + "pg-cloudflare": ["pg-cloudflare@1.4.0", "", {}, "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A=="], + + "pg-connection-string": ["pg-connection-string@2.14.0", "", {}, "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg=="], + + "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], + + "pg-pool": ["pg-pool@3.14.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw=="], + + "pg-protocol": ["pg-protocol@1.16.0", "", {}, "sha512-sILXutLVjCLjcDuOmvhX5e2Z4cS5qG/6Bu3VkpFwdf/633ElGLpEh9bgmuI5I4sqKqkifQiGyiCcx1HdtrK7tg=="], + + "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], + + "pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + + "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], + + "plist": ["plist@3.1.1", "", { "dependencies": { "@xmldom/xmldom": "0.9.10", "base64-js": "1.5.1", "xmlbuilder": "15.1.1" } }, "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA=="], + + "pngjs": ["pngjs@3.4.0", "", {}, "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="], + + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + + "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "3.3.12", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], + + "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], + + "postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], + + "postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="], + + "postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="], + + "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "29.6.3", "ansi-styles": "5.2.0", "react-is": "18.3.1" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], + + "proc-log": ["proc-log@4.2.0", "", {}, "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA=="], + + "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="], + + "promise": ["promise@8.3.0", "", { "dependencies": { "asap": "2.0.6" } }, "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg=="], + + "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "3.0.3", "sisteransi": "1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], + + "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "1.4.0", "object-assign": "4.1.1", "react-is": "16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "qs": ["qs@6.15.2", "", { "dependencies": { "side-channel": "1.1.0" } }, "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw=="], + + "queue": ["queue@6.0.2", "", { "dependencies": { "inherits": "2.0.4" } }, "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "quick-lru": ["quick-lru@4.0.1", "", {}, "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.1", "iconv-lite": "0.7.2", "unpipe": "1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], + + "react": ["react@19.2.7", "", {}, "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ=="], + + "react-devtools-core": ["react-devtools-core@6.1.5", "", { "dependencies": { "shell-quote": "1.8.4", "ws": "7.5.11" } }, "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA=="], + + "react-dom": ["react-dom@19.2.7", "", { "dependencies": { "scheduler": "0.27.0" }, "peerDependencies": { "react": "^19.2.7" } }, "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ=="], + + "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "react-native": ["react-native@0.85.3", "", { "dependencies": { "@react-native/assets-registry": "0.85.3", "@react-native/codegen": "0.85.3", "@react-native/community-cli-plugin": "0.85.3", "@react-native/gradle-plugin": "0.85.3", "@react-native/js-polyfills": "0.85.3", "@react-native/normalize-colors": "0.85.3", "@react-native/virtualized-lists": "0.85.3", "abort-controller": "3.0.0", "anser": "1.4.10", "ansi-regex": "5.0.1", "babel-plugin-syntax-hermes-parser": "0.33.3", "base64-js": "1.5.1", "commander": "12.1.0", "flow-enums-runtime": "0.0.6", "hermes-compiler": "250829098.0.10", "invariant": "2.2.4", "memoize-one": "5.2.1", "metro-runtime": "0.84.4", "metro-source-map": "0.84.4", "nullthrows": "1.1.1", "pretty-format": "29.7.0", "promise": "8.3.0", "react-devtools-core": "6.1.5", "react-refresh": "0.14.2", "regenerator-runtime": "0.13.11", "scheduler": "0.27.0", "semver": "7.8.1", "stacktrace-parser": "0.1.11", "tinyglobby": "0.2.16", "whatwg-fetch": "3.6.20", "ws": "7.5.11", "yargs": "17.7.2" }, "peerDependencies": { "@react-native/jest-preset": "0.85.3", "@types/react": "^19.1.1", "react": "^19.2.3" }, "optionalPeers": ["@react-native/jest-preset", "@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-HN/fGC+3nZVcDNcw7gfbM/DuqZAvI9Mz+/SxuhODaua4JY0BPzhfTzWXRyTR4mRgMHmShTPpH2PYMTxvZrsdZA=="], + + "react-native-oliphaunt-expo": ["react-native-oliphaunt-expo@workspace:src/examples/react-native-expo"], + + "react-native-safe-area-context": ["react-native-safe-area-context@5.7.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ=="], + + "react-native-web": ["react-native-web@0.21.2", "", { "dependencies": { "@babel/runtime": "7.29.2", "@react-native/normalize-colors": "0.74.89", "fbjs": "3.0.5", "inline-style-prefixer": "7.0.1", "memoize-one": "6.0.0", "nullthrows": "1.1.1", "postcss-value-parser": "4.2.0", "styleq": "0.1.3" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg=="], + + "react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="], + + "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "2.3.8", "react-style-singleton": "2.2.3", "tslib": "2.8.1", "use-callback-ref": "1.3.3", "use-sidecar": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], + + "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "2.2.3", "tslib": "2.8.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "1.0.1", "tslib": "2.8.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], + + "read-pkg": ["read-pkg@5.2.0", "", { "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", "parse-json": "^5.0.0", "type-fest": "^0.6.0" } }, "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg=="], + + "read-pkg-up": ["read-pkg-up@7.0.1", "", { "dependencies": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", "type-fest": "^0.8.1" } }, "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg=="], + + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "2.0.4", "string_decoder": "1.3.0", "util-deprecate": "1.0.2" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], + + "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "1.0.9", "estree-util-build-jsx": "3.0.1", "vfile": "6.0.3" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="], + + "recma-jsx": ["recma-jsx@1.0.1", "", { "dependencies": { "acorn-jsx": "5.3.2", "estree-util-to-js": "2.0.0", "recma-parse": "1.0.0", "recma-stringify": "1.0.0", "unified": "11.0.5" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w=="], + + "recma-parse": ["recma-parse@1.0.0", "", { "dependencies": { "@types/estree": "1.0.9", "esast-util-from-js": "2.0.1", "unified": "11.0.5", "vfile": "6.0.3" } }, "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ=="], + + "recma-stringify": ["recma-stringify@1.0.0", "", { "dependencies": { "@types/estree": "1.0.9", "estree-util-to-js": "2.0.0", "unified": "11.0.5", "vfile": "6.0.3" } }, "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g=="], + + "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="], + + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "1.0.9", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-errors": "1.3.0", "es-object-atoms": "1.1.2", "get-intrinsic": "1.3.0", "get-proto": "1.0.1", "which-builtin-type": "1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], + + "regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="], + + "regenerate-unicode-properties": ["regenerate-unicode-properties@10.2.2", "", { "dependencies": { "regenerate": "1.4.2" } }, "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g=="], + + "regenerator-runtime": ["regenerator-runtime@0.13.11", "", {}, "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="], + + "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], + + "regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="], + + "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], + + "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "1.0.9", "define-properties": "1.2.1", "es-errors": "1.3.0", "get-proto": "1.0.1", "gopd": "1.2.0", "set-function-name": "2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], + + "regexpu-core": ["regexpu-core@6.4.0", "", { "dependencies": { "regenerate": "1.4.2", "regenerate-unicode-properties": "10.2.2", "regjsgen": "0.8.0", "regjsparser": "0.13.1", "unicode-match-property-ecmascript": "2.0.0", "unicode-match-property-value-ecmascript": "2.2.1" } }, "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA=="], + + "regjsgen": ["regjsgen@0.8.0", "", {}, "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q=="], + + "regjsparser": ["regjsparser@0.13.1", "", { "dependencies": { "jsesc": "3.1.0" }, "bin": { "regjsparser": "bin/parser" } }, "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw=="], + + "rehype-raw": ["rehype-raw@7.0.0", "", { "dependencies": { "@types/hast": "3.0.4", "hast-util-raw": "9.1.0", "vfile": "6.0.3" } }, "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww=="], + + "rehype-recma": ["rehype-recma@1.0.0", "", { "dependencies": { "@types/estree": "1.0.9", "@types/hast": "3.0.4", "hast-util-to-estree": "3.1.3" } }, "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw=="], + + "release-please": ["release-please@17.3.0", "", { "dependencies": { "@conventional-commits/parser": "^0.4.1", "@google-automations/git-file-utils": "^3.0.0", "@iarna/toml": "^3.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.3.1", "@octokit/request-error": "^5.1.0", "@octokit/rest": "^20.1.1", "@types/npm-package-arg": "^6.1.0", "@xmldom/xmldom": "^0.8.4", "chalk": "^4.0.0", "code-suggester": "^5.0.0", "conventional-changelog-conventionalcommits": "^6.0.0", "conventional-changelog-writer": "^6.0.0", "conventional-commits-filter": "^3.0.0", "detect-indent": "^6.1.0", "diff": "^8.0.3", "figures": "^3.0.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "js-yaml": "^4.0.0", "jsonpath-plus": "^10.0.0", "node-html-parser": "^6.0.0", "parse-github-repo-url": "^1.4.1", "semver": "^7.5.3", "type-fest": "^3.0.0", "typescript": "^4.6.4", "unist-util-visit": "^2.0.3", "unist-util-visit-parents": "^3.1.1", "xpath": "^0.0.34", "yaml": "^2.2.2", "yargs": "^17.0.0" }, "bin": { "release-please": "build/src/bin/release-please.js" } }, "sha512-dB7HsFUpAvU1Wj9RGCINUz8Zi2qQDZiGbDEEVnJ7baNfJmk5XdYhuUFL6RcuDGjReGhp1gzY8Tc2g7vHlM4zpg=="], + + "remark": ["remark@15.0.1", "", { "dependencies": { "@types/mdast": "4.0.4", "remark-parse": "11.0.0", "remark-stringify": "11.0.0", "unified": "11.0.5" } }, "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A=="], + + "remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "4.0.4", "mdast-util-gfm": "3.1.0", "micromark-extension-gfm": "3.0.0", "remark-parse": "11.0.0", "remark-stringify": "11.0.0", "unified": "11.0.5" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="], + + "remark-mdx": ["remark-mdx@3.1.1", "", { "dependencies": { "mdast-util-mdx": "3.0.0", "micromark-extension-mdxjs": "3.0.0" } }, "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg=="], + + "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "mdast-util-from-markdown": "2.0.3", "micromark-util-types": "2.0.2", "unified": "11.0.5" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], + + "remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "mdast-util-to-hast": "13.2.1", "unified": "11.0.5", "vfile": "6.0.3" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="], + + "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "mdast-util-to-markdown": "2.1.2", "unified": "11.0.5" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + + "require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="], + + "resolve": ["resolve@2.0.0-next.7", "", { "dependencies": { "es-errors": "1.3.0", "is-core-module": "2.16.2", "node-exports-info": "1.6.0", "object-keys": "1.1.1", "path-parse": "1.0.7", "supports-preserve-symlinks-flag": "1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ=="], + + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "resolve-workspace-root": ["resolve-workspace-root@2.0.1", "", {}, "sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w=="], + + "restore-cursor": ["restore-cursor@2.0.0", "", { "dependencies": { "onetime": "2.0.1", "signal-exit": "3.0.7" } }, "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q=="], + + "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "rollup": ["rollup@4.60.4", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.4", "@rollup/rollup-android-arm64": "4.60.4", "@rollup/rollup-darwin-arm64": "4.60.4", "@rollup/rollup-darwin-x64": "4.60.4", "@rollup/rollup-freebsd-arm64": "4.60.4", "@rollup/rollup-freebsd-x64": "4.60.4", "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", "@rollup/rollup-linux-arm-musleabihf": "4.60.4", "@rollup/rollup-linux-arm64-gnu": "4.60.4", "@rollup/rollup-linux-arm64-musl": "4.60.4", "@rollup/rollup-linux-loong64-gnu": "4.60.4", "@rollup/rollup-linux-loong64-musl": "4.60.4", "@rollup/rollup-linux-ppc64-gnu": "4.60.4", "@rollup/rollup-linux-ppc64-musl": "4.60.4", "@rollup/rollup-linux-riscv64-gnu": "4.60.4", "@rollup/rollup-linux-riscv64-musl": "4.60.4", "@rollup/rollup-linux-s390x-gnu": "4.60.4", "@rollup/rollup-linux-x64-gnu": "4.60.4", "@rollup/rollup-linux-x64-musl": "4.60.4", "@rollup/rollup-openbsd-x64": "4.60.4", "@rollup/rollup-openharmony-arm64": "4.60.4", "@rollup/rollup-win32-arm64-msvc": "4.60.4", "@rollup/rollup-win32-ia32-msvc": "4.60.4", "@rollup/rollup-win32-x64-gnu": "4.60.4", "@rollup/rollup-win32-x64-msvc": "4.60.4", "fsevents": "2.3.3" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g=="], + + "router": ["router@2.2.0", "", { "dependencies": { "debug": "4.4.3", "depd": "2.0.0", "is-promise": "4.0.0", "parseurl": "1.3.3", "path-to-regexp": "8.4.2" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "1.2.3" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "safe-array-concat": ["safe-array-concat@1.1.4", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "get-intrinsic": "1.3.0", "has-symbols": "1.1.0", "isarray": "2.0.5" } }, "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "1.3.0", "isarray": "2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], + + "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-regex": "1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="], + + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + + "scroll-into-view-if-needed": ["scroll-into-view-if-needed@3.1.0", "", { "dependencies": { "compute-scroll-into-view": "3.1.1" } }, "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ=="], + + "semver": ["semver@7.8.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg=="], + + "send": ["send@0.19.2", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "2.0.0", "escape-html": "1.0.3", "etag": "1.8.1", "fresh": "0.5.2", "http-errors": "2.0.1", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "1.2.1", "statuses": "2.0.2" } }, "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg=="], + + "serialize-error": ["serialize-error@2.1.0", "", {}, "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw=="], + + "serve-static": ["serve-static@1.16.3", "", { "dependencies": { "encodeurl": "2.0.0", "escape-html": "1.0.3", "parseurl": "1.3.3", "send": "0.19.2" } }, "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA=="], + + "set-blocking": ["set-blocking@2.0.0", "", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], + + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "1.1.4", "es-errors": "1.3.0", "function-bind": "1.1.2", "get-intrinsic": "1.3.0", "gopd": "1.2.0", "has-property-descriptors": "1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + + "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "1.1.4", "es-errors": "1.3.0", "functions-have-names": "1.2.3", "has-property-descriptors": "1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], + + "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.2" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], + + "setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "1.1.0", "detect-libc": "2.1.2", "semver": "7.8.1" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "shell-quote": ["shell-quote@1.8.4", "", {}, "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ=="], + + "shiki": ["shiki@4.1.0", "", { "dependencies": { "@shikijs/core": "4.1.0", "@shikijs/engine-javascript": "4.1.0", "@shikijs/engine-oniguruma": "4.1.0", "@shikijs/langs": "4.1.0", "@shikijs/themes": "4.1.0", "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "10.0.2", "@types/hast": "3.0.4" } }, "sha512-l/ABZPUR5v70jI10EzqfMS/I96vjSGv2y0ihUV+WYFzv0EfvW4s54m0Lg8wCrrL+2IkwBzFTuxkZjPf8b2NX9Q=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "object-inspect": "1.13.4", "side-channel-list": "1.0.1", "side-channel-map": "1.0.1", "side-channel-weakmap": "1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.1", "", { "dependencies": { "es-errors": "1.3.0", "object-inspect": "1.13.4" } }, "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "object-inspect": "1.13.4" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "object-inspect": "1.13.4", "side-channel-map": "1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "simple-icons": ["simple-icons@16.28.0", "", {}, "sha512-sQPR5AtK/ijRjou7zw7mlLp08oB6FH7i0lOy5XJ2zp9mJs/yejgiOn7KvQoe2q4YJIx6VmgUSW5AOefebPt5kg=="], + + "simple-plist": ["simple-plist@1.3.1", "", { "dependencies": { "bplist-creator": "0.1.0", "bplist-parser": "0.3.1", "plist": "3.1.1" } }, "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw=="], + + "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], + + "slice-ansi": ["slice-ansi@2.1.0", "", { "dependencies": { "ansi-styles": "3.2.1", "astral-regex": "1.0.0", "is-fullwidth-code-point": "2.0.0" } }, "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ=="], + + "slugify": ["slugify@1.6.9", "", {}, "sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg=="], + + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "1.1.2", "source-map": "0.6.1" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + + "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], + + "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], + + "spdx-license-ids": ["spdx-license-ids@3.0.23", "", {}, "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw=="], + + "split": ["split@1.0.1", "", { "dependencies": { "through": "2" } }, "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg=="], + + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + + "stable-hash": ["stable-hash@0.0.5", "", {}, "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA=="], + + "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], + + "stacktrace-parser": ["stacktrace-parser@0.1.11", "", { "dependencies": { "type-fest": "0.7.1" } }, "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg=="], + + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "internal-slot": "1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], + + "stream-buffers": ["stream-buffers@2.2.0", "", {}, "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "8.0.0", "is-fullwidth-code-point": "3.0.0", "strip-ansi": "6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-errors": "1.3.0", "es-object-atoms": "1.1.2", "get-intrinsic": "1.3.0", "gopd": "1.2.0", "has-symbols": "1.1.0", "internal-slot": "1.1.0", "regexp.prototype.flags": "1.5.4", "set-function-name": "2.0.2", "side-channel": "1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], + + "string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "1.2.1", "es-abstract": "1.24.2" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="], + + "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-data-property": "1.1.4", "define-properties": "1.2.1", "es-abstract": "1.24.2", "es-object-atoms": "1.1.2", "has-property-descriptors": "1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], + + "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "1.0.9", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.2" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], + + "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "1.0.9", "define-properties": "1.2.1", "es-object-atoms": "1.1.2" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], + + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "2.1.0", "character-entities-legacy": "3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + + "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], + + "strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "strnum": ["strnum@2.4.1", "", { "dependencies": { "anynum": "1.0.1" } }, "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg=="], + + "structured-headers": ["structured-headers@0.4.1", "", {}, "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg=="], + + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], + + "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + + "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "@babel/core": "*", "babel-plugin-macros": "*", "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" }, "optionalPeers": ["@babel/core", "babel-plugin-macros"] }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], + + "styleq": ["styleq@0.1.3", "", {}, "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "supports-hyperlinks": ["supports-hyperlinks@2.3.0", "", { "dependencies": { "has-flag": "4.0.0", "supports-color": "7.2.0" } }, "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="], + + "tailwindcss": ["tailwindcss@4.3.0", "", {}, "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q=="], + + "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], + + "terminal-link": ["terminal-link@2.1.1", "", { "dependencies": { "ansi-escapes": "4.3.2", "supports-hyperlinks": "2.3.0" } }, "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ=="], + + "terser": ["terser@5.48.0", "", { "dependencies": { "@jridgewell/source-map": "0.3.11", "acorn": "8.16.0", "commander": "2.20.3", "source-map-support": "0.5.21" }, "bin": { "terser": "bin/terser" } }, "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q=="], + + "throat": ["throat@5.0.0", "", {}, "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA=="], + + "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], + + "tinyexec": ["tinyexec@1.2.4", "", {}, "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg=="], + + "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "6.5.0", "picomatch": "4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], + + "tmpl": ["tmpl@1.0.5", "", {}, "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "toqr": ["toqr@0.1.1", "", {}, "sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA=="], + + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + + "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], + + "trim-newlines": ["trim-newlines@3.0.1", "", {}, "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw=="], + + "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], + + "ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="], + + "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "0.0.29", "json5": "1.0.2", "minimist": "1.2.8", "strip-bom": "3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "type-fest": ["type-fest@3.13.1", "", {}, "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g=="], + + "type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "2.0.0", "media-typer": "1.1.0", "mime-types": "3.0.2" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="], + + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-typed-array": "1.1.15" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + + "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "1.0.9", "for-each": "0.3.5", "gopd": "1.2.0", "has-proto": "1.2.0", "is-typed-array": "1.1.15" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], + + "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "1.0.7", "call-bind": "1.0.9", "for-each": "0.3.5", "gopd": "1.2.0", "has-proto": "1.2.0", "is-typed-array": "1.1.15", "reflect.getprototypeof": "1.0.10" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], + + "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "1.0.9", "for-each": "0.3.5", "gopd": "1.2.0", "is-typed-array": "1.1.15", "possible-typed-array-names": "1.1.0", "reflect.getprototypeof": "1.0.10" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "ua-parser-js": ["ua-parser-js@1.0.41", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug=="], + + "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], + + "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "has-bigints": "1.1.0", "has-symbols": "1.1.0", "which-boxed-primitive": "1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], + + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + + "unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="], + + "unicode-match-property-ecmascript": ["unicode-match-property-ecmascript@2.0.0", "", { "dependencies": { "unicode-canonical-property-names-ecmascript": "2.0.1", "unicode-property-aliases-ecmascript": "2.2.0" } }, "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q=="], + + "unicode-match-property-value-ecmascript": ["unicode-match-property-value-ecmascript@2.2.1", "", {}, "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg=="], + + "unicode-property-aliases-ecmascript": ["unicode-property-aliases-ecmascript@2.2.0", "", {}, "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ=="], + + "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "3.0.3", "bail": "2.0.2", "devlop": "1.1.0", "extend": "3.0.2", "is-plain-obj": "4.1.0", "trough": "2.2.0", "vfile": "6.0.3" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], + + "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], + + "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], + + "unist-util-position-from-estree": ["unist-util-position-from-estree@2.0.0", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ=="], + + "unist-util-remove-position": ["unist-util-remove-position@5.0.0", "", { "dependencies": { "@types/unist": "3.0.3", "unist-util-visit": "5.1.0" } }, "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q=="], + + "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], + + "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "3.0.3", "unist-util-is": "6.0.1", "unist-util-visit-parents": "6.0.2" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="], + + "unist-util-visit-parents": ["unist-util-visit-parents@3.1.1", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0" } }, "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg=="], + + "universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + + "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "unrs-resolver": ["unrs-resolver@1.12.2", "", { "dependencies": { "napi-postinstall": "0.3.4" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.12.2", "@unrs/resolver-binding-android-arm64": "1.12.2", "@unrs/resolver-binding-darwin-arm64": "1.12.2", "@unrs/resolver-binding-darwin-x64": "1.12.2", "@unrs/resolver-binding-freebsd-x64": "1.12.2", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", "@unrs/resolver-binding-linux-x64-musl": "1.12.2", "@unrs/resolver-binding-openharmony-arm64": "1.12.2", "@unrs/resolver-binding-wasm32-wasi": "1.12.2", "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" } }, "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ=="], + + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "3.2.0", "picocolors": "1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "2.3.1" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "2.8.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], + + "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "1.1.0", "tslib": "2.8.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], + + "uuid": ["uuid@11.1.1", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ=="], + + "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], + + "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], + + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "3.0.3", "vfile-message": "4.0.3" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], + + "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "3.0.3", "vfile": "6.0.3" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], + + "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "3.0.3", "unist-util-stringify-position": "4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], + + "vite": ["vite@6.4.2", "", { "dependencies": { "esbuild": "0.28.1", "fdir": "6.5.0", "picomatch": "4.0.4", "postcss": "8.5.15", "rollup": "4.60.4", "tinyglobby": "0.2.16" }, "optionalDependencies": { "fsevents": "2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ=="], + + "vlq": ["vlq@1.0.1", "", {}, "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="], + + "walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="], + + "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "1.0.4" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], + + "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], + + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="], + + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "0.0.3", "webidl-conversions": "3.0.1" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + + "whatwg-url-minimum": ["whatwg-url-minimum@0.1.2", "", {}, "sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "1.1.0", "is-boolean-object": "1.2.2", "is-number-object": "1.1.1", "is-string": "1.1.1", "is-symbol": "1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], + + "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "1.0.4", "function.prototype.name": "1.1.8", "has-tostringtag": "1.0.2", "is-async-function": "2.1.1", "is-date-object": "1.1.0", "is-finalizationregistry": "1.1.1", "is-generator-function": "1.1.2", "is-regex": "1.2.1", "is-weakref": "1.1.1", "isarray": "2.0.5", "which-boxed-primitive": "1.1.1", "which-collection": "1.0.2", "which-typed-array": "1.1.20" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], + + "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "2.0.3", "is-set": "2.0.3", "is-weakmap": "2.0.2", "is-weakset": "2.0.4" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], + + "which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="], + + "which-typed-array": ["which-typed-array@1.1.20", "", { "dependencies": { "available-typed-arrays": "1.0.7", "call-bind": "1.0.9", "call-bound": "1.0.4", "for-each": "0.3.5", "get-proto": "1.0.1", "gopd": "1.2.0", "has-tostringtag": "1.0.2" } }, "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], + + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "ws": ["ws@7.5.11", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA=="], + + "xcode": ["xcode@3.0.1", "", { "dependencies": { "simple-plist": "1.3.1", "uuid": "11.1.1" } }, "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA=="], + + "xml-naming": ["xml-naming@0.3.0", "", {}, "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ=="], + + "xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": "1.6.0", "xmlbuilder": "11.0.1" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="], + + "xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], + + "xpath": ["xpath@0.0.34", "", {}, "sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA=="], + + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], + + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "8.0.1", "escalade": "3.2.0", "get-caller-file": "2.0.5", "require-directory": "2.1.1", "string-width": "4.2.3", "y18n": "5.0.8", "yargs-parser": "21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + + "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], + + "zod-validation-error": ["zod-validation-error@4.0.2", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ=="], + + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + + "zx": ["zx@8.8.5", "", { "bin": { "zx": "build/cli.js" } }, "sha512-SNgDF5L0gfN7FwVOdEFguY3orU5AkfFZm9B5YSHog/UDHv+lvmd82ZAsOenOkQixigwH2+yyH198AwNdKhj+RA=="], + + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-create-regexp-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "1.3.0", "is-core-module": "2.16.2", "path-parse": "1.0.7", "supports-preserve-symlinks-flag": "1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="], + + "@babel/plugin-syntax-jsx/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/plugin-syntax-typescript/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/plugin-transform-class-properties/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/plugin-transform-classes/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/plugin-transform-modules-commonjs/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/plugin-transform-nullish-coalescing-operator/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/plugin-transform-optional-chaining/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/plugin-transform-runtime/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/plugin-transform-typescript/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/plugin-transform-unicode-regex/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/preset-typescript/@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@conventional-commits/parser/unist-util-visit": ["unist-util-visit@2.0.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0", "unist-util-visit-parents": "^3.0.0" } }, "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "@expo/cli/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "10.2.5", "minipass": "7.1.3", "path-scurry": "2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + + "@expo/cli/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], + + "@expo/cli/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@expo/config/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "10.2.5", "minipass": "7.1.3", "path-scurry": "2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + + "@expo/config-plugins/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "10.2.5", "minipass": "7.1.3", "path-scurry": "2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + + "@expo/config-plugins/xml2js": ["xml2js@0.6.0", "", { "dependencies": { "sax": "1.6.0", "xmlbuilder": "11.0.1" } }, "sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w=="], + + "@expo/devcert/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "@expo/fingerprint/@expo/env": ["@expo/env@2.4.1", "", { "dependencies": { "chalk": "4.1.2", "debug": "4.4.3", "getenv": "2.0.0" } }, "sha512-3c9Mg9x0HmGPEsVrGAGyEDJsNUOZ55cZvZ47/HLmXh7MHV9Zv7My73wThklKrObaBBoMfE4YqpKjYKDRzojpjQ=="], + + "@expo/fingerprint/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "10.2.5", "minipass": "7.1.3", "path-scurry": "2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + + "@expo/fingerprint/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@expo/mcp-tunnel/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], + + "@expo/mcp-tunnel/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "@expo/metro-config/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "10.2.5", "minipass": "7.1.3", "path-scurry": "2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + + "@expo/package-manager/@expo/json-file": ["@expo/json-file@11.0.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "json5": "2.2.3" } }, "sha512-pHJCETqFL5x5BzNV6cEPwjwuECgGmnl0bNmfHIJ6LM1tlh2eVXi5HEdit3zby/JO/B8Otk5cgcqtJXgvvUat3A=="], + + "@expo/plist/xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], + + "@expo/ws-tunnel/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], + + "@google-automations/git-file-utils/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@jest/types/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "@jest/types/@types/yargs": ["@types/yargs@17.0.35", "", { "dependencies": { "@types/yargs-parser": "21.0.3" } }, "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg=="], + + "@modelcontextprotocol/sdk/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "3.1.3", "fast-uri": "3.1.2", "json-schema-traverse": "1.0.0", "require-from-string": "2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + + "@oliphaunt/react-native/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "@oliphaunt/react-native/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "@oliphaunt/ts/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "@oliphaunt/ts/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "@oliphaunt/ts-query/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "@oliphaunt/ts-query/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "@oliphaunt/wasix-tools/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "@oliphaunt/wasix-tools/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "@oliphaunt/wasix-ts/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "@oliphaunt/wasix-ts/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-popover/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@react-native-community/cli/commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="], + + "@react-native-community/cli-doctor/ora": ["ora@5.4.1", "", { "dependencies": { "bl": "4.1.0", "chalk": "4.1.2", "cli-cursor": "3.1.0", "cli-spinners": "2.9.2", "is-interactive": "1.0.0", "is-unicode-supported": "0.1.0", "log-symbols": "4.1.0", "strip-ansi": "6.0.1", "wcwidth": "1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], + + "@react-native-community/cli-server-api/ws": ["ws@6.2.6", "", { "dependencies": { "async-limiter": "1.0.1" }, "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-XTrf1gv7kXoVf1hbC3PAyAiPgR8Wz1blcrYIjEsUmr08BLksT41R8KbjmS9408C2ERx7v1JDLD/BkpLEttjfKA=="], + + "@react-native-community/cli-tools/ora": ["ora@5.4.1", "", { "dependencies": { "bl": "4.1.0", "chalk": "4.1.2", "cli-cursor": "3.1.0", "cli-spinners": "2.9.2", "is-interactive": "1.0.0", "is-unicode-supported": "0.1.0", "log-symbols": "4.1.0", "strip-ansi": "6.0.1", "wcwidth": "1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], + + "@react-native/dev-middleware/open": ["open@7.4.2", "", { "dependencies": { "is-docker": "2.2.1", "is-wsl": "2.2.0" } }, "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="], + + "@types/pg/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + + "accepts/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "ajv-formats/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "3.1.3", "fast-uri": "3.1.2", "json-schema-traverse": "1.0.0", "require-from-string": "2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + + "ansi-escapes/type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], + + "ansi-fragments/strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "4.1.1" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], + + "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "bun-types/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "camelcase-keys/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "chrome-launcher/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "chrome-launcher/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "2.2.1" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "chromium-edge-launcher/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "chromium-edge-launcher/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "2.2.1" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "code-suggester/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "code-suggester/yargs": ["yargs@16.2.2", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w=="], + + "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "compression/negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], + + "connect/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "decamelize-keys/map-obj": ["map-obj@1.0.1", "", {}, "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg=="], + + "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "eslint-plugin-react-hooks/hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="], + + "expo-mcp/ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], + + "expo-mcp/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + + "expo-splash-screen/xml2js": ["xml2js@0.6.0", "", { "dependencies": { "sax": "1.6.0", "xmlbuilder": "11.0.1" } }, "sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w=="], + + "express/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "3.0.2", "negotiator": "1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + + "express/finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "4.4.3", "encodeurl": "2.0.0", "escape-html": "1.0.3", "on-finished": "2.4.1", "parseurl": "1.3.3", "statuses": "2.0.2" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], + + "express/fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + + "express/send": ["send@1.2.1", "", { "dependencies": { "debug": "4.4.3", "encodeurl": "2.0.0", "escape-html": "1.0.3", "etag": "1.8.1", "fresh": "2.0.0", "http-errors": "2.0.1", "mime-types": "3.0.2", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "1.2.1", "statuses": "2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + + "express/serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "2.0.0", "escape-html": "1.0.3", "parseurl": "1.3.3", "send": "1.2.1" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "4.0.3" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "fbjs/promise": ["promise@7.3.1", "", { "dependencies": { "asap": "2.0.6" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="], + + "figures/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "finalhandler/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + + "finalhandler/on-finished": ["on-finished@2.3.0", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww=="], + + "finalhandler/statuses": ["statuses@1.5.0", "", {}, "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="], + + "foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "fumadocs-ui/motion": ["motion@12.40.0", "", { "dependencies": { "framer-motion": "12.40.0", "tslib": "2.8.1" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-yjrHUrBFW6kQvjJwRsoiPSAhC5tRwRqNGJWmiJ4CrGnbKp0V88AdzkhBmDoqIsIPfarOe0Uddd37Xq43/gIocA=="], + + "glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "handlebars/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "jest-util/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "jest-util/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + + "jest-worker/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "lighthouse-logger/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "log-symbols/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", "supports-color": "5.5.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], + + "logkitty/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "6.0.0", "decamelize": "1.2.0", "find-up": "4.1.0", "get-caller-file": "2.0.5", "require-directory": "2.1.1", "require-main-filename": "2.0.0", "set-blocking": "2.0.0", "string-width": "4.2.3", "which-module": "2.0.1", "y18n": "4.0.3", "yargs-parser": "18.1.3" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], + + "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "mdast-util-find-and-replace/unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "3.0.3", "unist-util-is": "6.0.1" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], + + "meow/type-fest": ["type-fest@0.18.1", "", {}, "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw=="], + + "meow/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + + "metro/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "3.0.2", "negotiator": "1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + + "metro/ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="], + + "metro/hermes-parser": ["hermes-parser@0.35.0", "", { "dependencies": { "hermes-estree": "0.35.0" } }, "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA=="], + + "metro/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], + + "metro-babel-transformer/hermes-parser": ["hermes-parser@0.35.0", "", { "dependencies": { "hermes-estree": "0.35.0" } }, "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA=="], + + "metro-source-map/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], + + "metro-symbolicate/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], + + "micromatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + + "minimist-options/is-plain-obj": ["is-plain-obj@1.1.0", "", {}, "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg=="], + + "node-exports-info/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "normalize-package-data/hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], + + "oliphaunt-example-browser-wasix/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "oliphaunt-example-browser-wasix/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "ora/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", "supports-color": "5.5.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], + + "ora/strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "4.1.1" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], + + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "path-scurry/lru-cache": ["lru-cache@11.5.0", "", {}, "sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA=="], + + "plist/@xmldom/xmldom": ["@xmldom/xmldom@0.9.10", "", {}, "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw=="], + + "plist/xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], + + "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-native-oliphaunt-expo/react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="], + + "react-native-oliphaunt-expo/react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="], + + "react-native-oliphaunt-expo/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "react-native-web/@react-native/normalize-colors": ["@react-native/normalize-colors@0.74.89", "", {}, "sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg=="], + + "react-native-web/memoize-one": ["memoize-one@6.0.0", "", {}, "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="], + + "read-pkg/normalize-package-data": ["normalize-package-data@2.5.0", "", { "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA=="], + + "read-pkg/type-fest": ["type-fest@0.6.0", "", {}, "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="], + + "read-pkg-up/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "5.0.0", "path-exists": "4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "read-pkg-up/type-fest": ["type-fest@0.8.1", "", {}, "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="], + + "release-please/typescript": ["typescript@4.9.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g=="], + + "release-please/unist-util-visit": ["unist-util-visit@2.0.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0", "unist-util-visit-parents": "^3.0.0" } }, "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q=="], + + "restore-cursor/onetime": ["onetime@2.0.1", "", { "dependencies": { "mimic-fn": "1.2.0" } }, "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ=="], + + "rollup/@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "send/mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + + "simple-plist/bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.52" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="], + + "slice-ansi/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "1.9.3" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + + "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@2.0.0", "", {}, "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w=="], + + "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "stacktrace-parser/type-fest": ["type-fest@0.7.1", "", {}, "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="], + + "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "1.2.8" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], + + "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + + "unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "3.0.3", "unist-util-is": "6.0.1" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], + + "unist-util-visit-parents/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "unist-util-visit-parents/unist-util-is": ["unist-util-is@4.1.0", "", {}, "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "@conventional-commits/parser/unist-util-visit/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "@conventional-commits/parser/unist-util-visit/unist-util-is": ["unist-util-is@4.1.0", "", {}, "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg=="], + + "@expo/cli/glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@expo/config-plugins/glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@expo/config/glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@expo/fingerprint/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "@expo/metro-config/glob/minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "5.0.6" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "@google-automations/git-file-utils/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "@jest/types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "@oliphaunt/react-native/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@oliphaunt/ts-query/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@oliphaunt/ts/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@oliphaunt/wasix-tools/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@oliphaunt/wasix-ts/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@react-native-community/cli-doctor/ora/cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], + + "@react-native-community/cli-doctor/ora/log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "4.1.2", "is-unicode-supported": "0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], + + "@react-native-community/cli-tools/ora/cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], + + "@react-native-community/cli-tools/ora/log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "4.1.2", "is-unicode-supported": "0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], + + "@react-native/dev-middleware/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "2.2.1" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "@types/pg/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "accepts/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "ansi-fragments/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], + + "bun-types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "chrome-launcher/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "chromium-edge-launcher/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "code-suggester/yargs/cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], + + "code-suggester/yargs/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + + "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "connect/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "eslint-plugin-react-hooks/hermes-parser/hermes-estree": ["hermes-estree@0.25.1", "", {}, "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw=="], + + "express/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "fumadocs-ui/motion/framer-motion": ["framer-motion@12.40.0", "", { "dependencies": { "motion-dom": "12.40.0", "motion-utils": "12.39.0", "tslib": "2.8.1" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg=="], + + "glob/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "jest-util/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "jest-worker/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "log-symbols/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "1.9.3" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + + "log-symbols/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "log-symbols/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "logkitty/yargs/cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "4.2.3", "strip-ansi": "6.0.1", "wrap-ansi": "6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="], + + "logkitty/yargs/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "5.0.0", "path-exists": "4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "logkitty/yargs/y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], + + "logkitty/yargs/yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "5.3.1", "decamelize": "1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="], + + "metro-babel-transformer/hermes-parser/hermes-estree": ["hermes-estree@0.35.0", "", {}, "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg=="], + + "metro/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "metro/hermes-parser/hermes-estree": ["hermes-estree@0.35.0", "", {}, "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg=="], + + "normalize-package-data/hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + + "oliphaunt-example-browser-wasix/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "ora/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "1.9.3" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + + "ora/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "ora/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "ora/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], + + "read-pkg-up/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "read-pkg/normalize-package-data/hosted-git-info": ["hosted-git-info@2.8.9", "", {}, "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="], + + "read-pkg/normalize-package-data/resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "1.3.0", "is-core-module": "2.16.2", "path-parse": "1.0.7", "supports-preserve-symlinks-flag": "1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="], + + "read-pkg/normalize-package-data/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + + "release-please/unist-util-visit/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "release-please/unist-util-visit/unist-util-is": ["unist-util-is@4.1.0", "", {}, "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg=="], + + "restore-cursor/onetime/mimic-fn": ["mimic-fn@1.2.0", "", {}, "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="], + + "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "slice-ansi/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "@expo/cli/glob/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "@expo/config-plugins/glob/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "@expo/config/glob/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "@expo/fingerprint/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@expo/metro-config/glob/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "4.0.4" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], + + "@google-automations/git-file-utils/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@react-native-community/cli-doctor/ora/cli-cursor/restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "5.1.2", "signal-exit": "3.0.7" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + + "@react-native-community/cli-tools/ora/cli-cursor/restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "5.1.2", "signal-exit": "3.0.7" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "fumadocs-ui/motion/framer-motion/motion-dom": ["motion-dom@12.40.0", "", { "dependencies": { "motion-utils": "12.39.0" } }, "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg=="], + + "fumadocs-ui/motion/framer-motion/motion-utils": ["motion-utils@12.39.0", "", {}, "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ=="], + + "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "log-symbols/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "log-symbols/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + + "logkitty/yargs/cliui/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + + "logkitty/yargs/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "logkitty/yargs/yargs-parser/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "normalize-package-data/hosted-git-info/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "ora/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "ora/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + + "read-pkg-up/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "2.3.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "slice-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "@expo/cli/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@expo/config-plugins/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@expo/config/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "@expo/metro-config/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "log-symbols/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "logkitty/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "logkitty/yargs/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "2.3.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "ora/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "read-pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "2.2.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "logkitty/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "2.2.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + } +} diff --git a/bunfig.toml b/bunfig.toml new file mode 100644 index 000000000..20c4b301a --- /dev/null +++ b/bunfig.toml @@ -0,0 +1,5 @@ +[install] +linker = "isolated" +# Match the existing one-day resolution policy; Bun uses seconds. +minimumReleaseAge = 86400 +peer = false diff --git a/coverage/baseline.toml b/coverage/baseline.toml deleted file mode 100644 index 1b372a1c1..000000000 --- a/coverage/baseline.toml +++ /dev/null @@ -1,370 +0,0 @@ -# `line_threshold` is the blocking aggregate gate. `per_file_line_warning` -# keeps weak files visible without blocking otherwise healthy coverage. - -[policy] -fail_on_unmeasured_product = true - -[products.oliphaunt-rust] -tool = "cargo-llvm-cov" -line_threshold = 80.0 -summary = "target/coverage/oliphaunt-rust/summary.json" -reports = ["target/coverage/oliphaunt-rust/lcov.info"] -source_globs = ["src/sdks/rust/src/*.rs"] -exclude_globs = [ - "src/sdks/rust/tests/**", - "src/runtimes/liboliphaunt/native/**", - "src/postgres/versions/18/**", - "target/**", -] -per_file_line_warning = 50.0 - -[[products.oliphaunt-rust.waivers]] -path = "src/sdks/rust/src/broker.rs" -reason = "broker process orchestration is runtime/integration evidence, not deterministic unit coverage yet" -evidence = "oliphaunt-rust smoke/regression lanes and TypeScript broker helper tests" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-rust.waivers]] -path = "src/sdks/rust/src/broker_support.rs" -reason = "unpublished broker-helper boundary is compiled only for the packaged broker executable" -evidence = "broker helper build plus native broker smoke/regression lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-rust.waivers]] -path = "src/sdks/rust/src/ipc.rs" -reason = "local IPC framing is exercised through broker integration tests and shared protocol fixtures" -evidence = "oliphaunt-rust broker tests plus src/shared/fixtures/protocol/query-response-cases.json consumers" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-rust.waivers]] -path = "src/sdks/rust/src/lib.rs" -reason = "crate root is a re-export surface with no durable executable behavior to line-cover" -evidence = "cargo doctests and SDK package-shape checks" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-rust.waivers]] -path = "src/sdks/rust/src/pgwire.rs" -reason = "external wire compatibility is regression evidence rather than SDK wrapper unit coverage" -evidence = "server/client compatibility regression lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-rust.waivers]] -path = "src/sdks/rust/src/server.rs" -reason = "server process lifecycle requires runtime artifacts and belongs in smoke/regression lanes" -evidence = "oliphaunt-rust smoke/regression server tests" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[products.oliphaunt-swift] -tool = "swift test --enable-code-coverage" -line_threshold = 80.0 -summary = "target/coverage/oliphaunt-swift/summary.json" -reports = ["target/coverage/oliphaunt-swift/swift-coverage.json"] -source_globs = [ - "src/sdks/swift/Sources/Oliphaunt/*.swift", - "src/sdks/swift/Sources/Oliphaunt/**/*.swift", -] -exclude_globs = [ - "src/sdks/swift/Sources/COliphaunt/**", - "src/sdks/swift/Tests/**", - "target/**", -] -per_file_line_warning = 50.0 - -[[products.oliphaunt-swift.waivers]] -path = "src/sdks/swift/Sources/Oliphaunt/OliphauntNativeDirect.swift" -reason = "native direct FFI shell is validated by runtime smoke/XCTest paths rather than pure Swift line coverage" -evidence = "Swift smoke, iOS/macOS packaging, and liboliphaunt C ABI tests" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-swift.waivers]] -path = "src/sdks/swift/Sources/Oliphaunt/OliphauntRuntimeResources.swift" -reason = "packaged runtime discovery and filesystem materialization are qualified by real carrier and installed-consumer lanes" -evidence = "Swift resource composition tests, Swift release consumer, and iOS mobile app qualification" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[products.oliphaunt-kotlin] -tool = "kover" -line_threshold = 80.0 -summary = "target/coverage/oliphaunt-kotlin/summary.json" -reports = ["target/coverage/oliphaunt-kotlin/kover.xml"] -source_globs = ["src/sdks/kotlin/oliphaunt/src/**/*.kt"] -exclude_globs = [ - "src/sdks/kotlin/oliphaunt/src/*Test/**", - "src/sdks/kotlin/oliphaunt/src/**/*Test.kt", - "src/sdks/kotlin/**/build/**", - "src/sdks/kotlin/**/.cxx/**", - "src/sdks/kotlin/**/generated/**", - "target/**", -] -per_file_line_warning = 50.0 - -[[products.oliphaunt-kotlin.waivers]] -path = "src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/AndroidNativeDirectEngine.kt" -reason = "Android JNI-backed direct engine is runtime/device evidence, not JVM/Kover unit coverage" -evidence = "Android unit/resource tests, native smoke, and mobile E2E lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-kotlin.waivers]] -path = "src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroid.kt" -reason = "Android app-facing facade binds packaged resources and is covered by Android resource/package tests" -evidence = "OliphauntAndroidRuntimeAssetsTest and package-shape checks" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-kotlin.waivers]] -path = "src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroidNativeBridge.kt" -reason = "JNI bridge shell is validated by native runtime smoke and bridge compile checks" -evidence = "Android CMake compile, JNI smoke, and liboliphaunt C ABI tests" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[products.oliphaunt-js] -tool = "vitest-v8" -line_threshold = 80.0 -summary = "target/coverage/oliphaunt-js/summary.json" -reports = [ - "target/coverage/oliphaunt-js/coverage-summary.json", - "target/coverage/oliphaunt-js/lcov.info", -] -source_globs = [ - "src/sdks/js/src/*.ts", - "src/sdks/js/src/**/*.ts", -] -exclude_globs = [ - "src/sdks/js/src/__tests__/**", - "src/sdks/js/src/**/*.d.ts", - "src/sdks/js/src/**/types.ts", - "src/sdks/js/src/protocol.ts", - "src/sdks/js/src/query.ts", - "src/sdks/js/lib/**", - "src/sdks/js/node_modules/**", -] -per_file_line_warning = 50.0 - -[[products.oliphaunt-js.waivers]] -path = "src/sdks/js/src/native/assets-deno.ts" -reason = "Deno native asset resolution is covered by Deno package/runtime checks, not Node Vitest line coverage" -evidence = "TypeScript Deno package-shape and smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-js.waivers]] -path = "src/sdks/js/src/native/default.ts" -reason = "runtime selector depends on host runtime and is covered through Node/Bun/Deno package checks" -evidence = "TypeScript package and native smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-js.waivers]] -path = "src/sdks/js/src/native/deno.ts" -reason = "Deno FFI binding is covered by Deno runtime checks, not Node Vitest line coverage" -evidence = "TypeScript Deno package-shape and smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-js.waivers]] -path = "src/sdks/js/src/native/node-addon.ts" -reason = "Node native addon loader is validated by package-shape, artifact-resolution, and native smoke lanes" -evidence = "native-bindings tests, package checks, and TypeScript native smoke" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-js.waivers]] -path = "src/sdks/js/src/native/tar.ts" -reason = "tar extraction helpers are covered through asset resolver tests and release artifact checks" -evidence = "asset-resolver.test.ts and release artifact validation" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-js.waivers]] -path = "src/sdks/js/src/runtime/broker.ts" -reason = "broker helper lifecycle requires Rust helper/runtime artifacts and belongs in smoke/regression evidence" -evidence = "runtime-adapters.test.ts, broker-frames.test.ts, and TypeScript native broker smoke" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-js.waivers]] -path = "src/sdks/js/src/runtime/node-adapter.ts" -reason = "Node process adapter is partially exercised but runtime process behavior belongs in smoke lanes" -evidence = "runtime-adapters.test.ts and broker/server smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-js.waivers]] -path = "src/sdks/js/src/runtime/pgwire.ts" -reason = "external PostgreSQL wire compatibility is regression evidence rather than unit line coverage" -evidence = "server-wire tests and external client regression lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-js.waivers]] -path = "src/sdks/js/src/runtime/server.ts" -reason = "server process lifecycle requires runtime artifacts and belongs in smoke/regression evidence" -evidence = "runtime-adapters.test.ts, root-descriptor.test.ts, and TypeScript native server smoke" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[products.oliphaunt-react-native] -tool = "vitest-v8" -line_threshold = 80.0 -summary = "target/coverage/oliphaunt-react-native/summary.json" -reports = [ - "target/coverage/oliphaunt-react-native/coverage-summary.json", - "target/coverage/oliphaunt-react-native/lcov.info", -] -source_globs = [ - "src/sdks/react-native/src/*.ts", - "src/sdks/react-native/src/**/*.ts", - "src/sdks/react-native/app*.js", -] -exclude_globs = [ - "src/sdks/react-native/src/__tests__/**", - "src/sdks/react-native/src/generated/**", - "src/sdks/react-native/src/protocol.ts", - "src/sdks/react-native/src/query.ts", - "src/sdks/react-native/lib/**", - "src/sdks/react-native/node_modules/**", -] -per_file_line_warning = 50.0 - -[[products.oliphaunt-react-native.waivers]] -path = "src/sdks/react-native/src/specs/NativeOliphaunt.ts" -reason = "React Native TurboModule Codegen spec is validated by Codegen/package checks, not runtime JS line coverage" -evidence = "codegen:check, package-shape checks, and RN native adapter compile lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-react-native.waivers]] -path = "src/sdks/react-native/app.plugin.js" -reason = "Expo prebuild filesystem mutation is qualified against staged native carriers and generated apps" -evidence = "config-plugin unit tests plus Android and iOS mobile app qualification" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[products.oliphaunt-wasix-rust] -tool = "cargo-llvm-cov" -line_threshold = 80.0 -summary = "target/coverage/oliphaunt-wasix-rust/summary.json" -reports = ["target/coverage/oliphaunt-wasix-rust/lcov.info"] -source_globs = [ - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/error.rs", - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/assets.rs", - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/builder.rs", - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/config.rs", - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/data_dir.rs", - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/database_root_descriptor.rs", - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/query.rs", - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/storage.rs", -] -exclude_globs = [ - "src/runtimes/liboliphaunt/wasix/assets/generated/**", - "src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/**", - "src/runtimes/liboliphaunt/wasix/crates/aot/**", - "target/**", -] -per_file_line_warning = 50.0 -waivers = [] - -[products.oliphaunt-wasix-ts] -tool = "vitest-v8" -line_threshold = 80.0 -summary = "target/coverage/oliphaunt-wasix-ts/summary.json" -reports = [ - "target/coverage/oliphaunt-wasix-ts/coverage-summary.json", - "target/coverage/oliphaunt-wasix-ts/lcov.info", -] -source_globs = [ - "src/bindings/wasix-ts/src/*.ts", - "src/bindings/wasix-ts/src/storage/*.ts", -] -exclude_globs = [ - "src/bindings/wasix-ts/src/__tests__/**", - "src/bindings/wasix-ts/src/**/*.d.ts", - "src/bindings/wasix-ts/src/direct.node.ts", - "src/bindings/wasix-ts/src/server.node.ts", - "src/bindings/wasix-ts/src/types.ts", - "src/bindings/wasix-ts/src/public.ts", - "src/bindings/wasix-ts/src/protocol.ts", - "src/bindings/wasix-ts/src/query.ts", - "src/bindings/wasix-ts/src/index.ts", - "src/bindings/wasix-ts/src/index.*.ts", - "src/bindings/wasix-ts/src/worker-entry.ts", - "src/bindings/wasix-ts/src/worker-entry.*.ts", - "src/bindings/wasix-ts/src/storage/bun.ts", - "src/bindings/wasix-ts/src/storage/deno.ts", - "src/bindings/wasix-ts/lib/**", - "src/bindings/wasix-ts/node_modules/**", -] -per_file_line_warning = 50.0 - -[[products.oliphaunt-wasix-ts.waivers]] -path = "src/bindings/wasix-ts/src/client.ts" -reason = "browser entrypoint lifecycle requires the packaged WASIX runtime and browser host" -evidence = "browser direct and Worker smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-wasix-ts.waivers]] -path = "src/bindings/wasix-ts/src/node-client.ts" -reason = "native host root lifecycle requires the packaged Node-API carrier and Rust owner actor" -evidence = "Node, Bun, Deno, and Electron package smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-wasix-ts.waivers]] -path = "src/bindings/wasix-ts/src/node-direct.ts" -reason = "direct native host startup requires the packaged Node-API carrier" -evidence = "Node direct package smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-wasix-ts.waivers]] -path = "src/bindings/wasix-ts/src/node-worker.ts" -reason = "native host isolated-entrypoint lifecycle requires a real Worker lane and packaged Node-API carrier" -evidence = "Node, Bun, Deno, and Electron Worker package smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-wasix-ts.waivers]] -path = "src/bindings/wasix-ts/src/worker.ts" -reason = "browser Worker entrypoint lifecycle requires a real WASIX runtime and browser worker host" -evidence = "browser Worker smoke and package lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-wasix-ts.waivers]] -path = "src/bindings/wasix-ts/src/internal.ts" -reason = "browser tool-worker construction requires a real packaged browser Worker host" -evidence = "browser tool lifecycle and packaged browser smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-wasix-ts.waivers]] -path = "src/bindings/wasix-ts/src/internal.node.ts" -reason = "native tool dispatch requires the packaged WASIX Node-API carrier" -evidence = "Node, Bun, Deno, and Electron packaged tool smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-wasix-ts.waivers]] -path = "src/bindings/wasix-ts/src/tool-worker.ts" -reason = "browser Worker bootstrap is exercised only inside the packaged Worker host" -evidence = "browser tool lifecycle and packaged browser smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" - -[[products.oliphaunt-wasix-ts.waivers]] -path = "src/bindings/wasix-ts/src/worker-node-client.ts" -reason = "Node Worker creation and embedded carrier stripping require the packaged Node-API runtime" -evidence = "Node, Bun, Deno, and Electron Worker package smoke lanes" -owner = "@oliphaunt/core" -expires = "before-0.2.0" diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 6c10ccc8d..000000000 --- a/docs/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Repository Docs - -This directory is for maintainer, architecture, and internal documentation. -Public product documentation lives in `src/docs`; SDK pages are -centralized under `src/docs/content/sdk`. Product roots keep only -package README/CHANGELOG files and source-adjacent API comments. - -- `architecture/`: design rationale and product-boundary decisions. The status - banner in each investigation determines whether it is current or historical. -- `maintainers/`: repository, tooling, release, testing, and benchmark process. -- `internal/`: archived progress notes, audits, and implementation history. - These files are non-normative; start with `maintainers/README.md`. diff --git a/docs/architecture/cluster-seeds-and-icu.md b/docs/architecture/cluster-seeds-and-icu.md deleted file mode 100644 index d0b1ae9ca..000000000 --- a/docs/architecture/cluster-seeds-and-icu.md +++ /dev/null @@ -1,426 +0,0 @@ -# Cluster seeds and ICU - -Status: locked architecture and implemented contract, updated 2026-08-24. - -This document is the source of truth for preinitialized PostgreSQL clusters, -ICU data, their public selection, and their release qualification. - -## Names - -The public and manifest vocabulary is deliberately small: - -| Name | Meaning | -| --- | --- | -| `standard` | A cluster seed created without optional ICU data. | -| `icu` | A cluster seed created by `initdb` with the exact packaged ICU data available. | -| `icu-data` | The independently packaged ICU runtime data files. | - -The corresponding artifact roles are `cluster-seed-standard`, -`cluster-seed-icu`, and `icu-data`. - -Do not call these profiles `base` or `icu-full`. `base` is ambiguous with a -base runtime/package and says nothing about the catalog. `full` falsely -suggests that smaller public ICU editions exist. Oliphaunt ships one optional -ICU data form, so `icu` is the complete and accurate name. - -“Prepopulated filesystem” is acceptable when comparing with PGlite. -“Preinitialized PGDATA” is acceptable in explanatory prose. Code, manifests, -package metadata, and architecture use **cluster seed**. - -## Simple model - -A cluster seed and ICU data are independent concepts: - -- A cluster seed is immutable initialization state. Oliphaunt copies it only - when creating a new, empty database root. -- ICU data is a runtime capability. PostgreSQL needs those files whenever it - executes ICU locale or collation operations. -- Extensions are a third independent layer. Seeds contain no optional - extensions or application data. - -They overlap in one place: PostgreSQL's ICU-aware `initdb` imports predefined -ICU collations into each bootstrap database. Adding ICU data after copying a -standard seed does not repeat that catalog work. Therefore a newly seeded ICU -database needs both `icu-data` and the matching `icu` seed. - -The four conceptual cases are: - -| Initialization | ICU data | Result | -| --- | --- | --- | -| `standard` seed | absent | Fast ordinary new database. | -| `icu` seed | present | Fast new database with the predefined ICU catalog. | -| `initdb` | absent | Correct ordinary database; slower initialization. | -| `initdb` | present | Correct ICU database; slower initialization. | - -The last case is important for explicit or locally built runtimes. ICU does not -require a seed. A seed is an optimization; ICU data is a capability. Published -package-managed defaults use a seed so users normally avoid `initdb`. - -## User-visible behavior - -There is no public initialization-mode enum and no raw seed/archive injection -API. Package-managed SDKs resolve the correct seed transitively. - -- Installing/selecting the ordinary runtime resolves the `standard` seed. -- Selecting the language-native ICU package or feature resolves `icu-data` and - the matching `icu` seed as one checked closure. -- Every seed and `initdb` fallback creates PostgreSQL's fixed `postgres` - bootstrap role. Public `username` options consistently select an existing - connection role; they never create a superuser as a side effect. -- Opening a new root as another username fails before seed loading or PGDATA - mutation/publication. The - application can first open as `postgres`, create the role, and then reopen as - that role. -- An explicit native runtime may run `initdb`. If ICU data is explicitly - supplied, that `initdb` receives the exact internal ICU-readiness signal and - produces the normal ICU catalog. -- Existing nonempty roots are opened as they are. They are never replaced, - re-seeded, or silently catalog-migrated. - -WASIX TypeScript uses an explicit descriptor, following the useful part of -PGlite's end-user shape without exposing a raw filesystem option: - -```ts -import Oliphaunt from '@oliphaunt/wasix-ts'; -import icu from '@oliphaunt/wasix-icu'; - -const db = await Oliphaunt.open({ icu }); -``` - -Without `icu`, the matching runtime package supplies the `standard` seed. -With `icu`, `@oliphaunt/wasix-icu` supplies the shared ICU data and the WASIX -`icu` seed. Its descriptor is versioned and runtime-bound; arbitrary paths and -untyped objects are not accepted. - -Other SDKs retain language-native package selection: - -| SDK | Ordinary selection | ICU selection | -| --- | --- | --- | -| Native Rust | target runtime artifact selected by `oliphaunt-build` | Cargo ICU feature/artifact stages `oliphaunt-icu` | -| Native TypeScript | target runtime npm package | optional `@oliphaunt/icu` package | -| Swift | ordinary runtime resources | `OliphauntICU` SwiftPM/CocoaPods resources | -| Kotlin | ordinary Maven runtime resources | Gradle ICU dependency/selection | -| React Native | ordinary generated native carrier | `@oliphaunt/icu` native resource carrier | -| Rust WASIX | portable runtime artifact | Cargo ICU feature/artifact | -| WASIX TypeScript | default runtime descriptor | explicit `@oliphaunt/wasix-icu` descriptor | - -This is semantic parity, not identical signatures. - -## Why the catalog matters - -PostgreSQL initializes `template1`, imports system collations into it, and then -copies it to create `template0` and `postgres`. `pg_collation` is per-database. -Consequently: - -- loading ICU bytes after a standard seed does not create the predefined - `*-x-icu` rows; -- importing into one application database changes only that database; -- importing into `template1` later affects future databases but does not repair - the already-created `postgres`, `template0`, or other databases; -- explicit `CREATE COLLATION ... provider = icu` can still work when ICU data - is present; and -- enabling ICU does not silently change the cluster's default locale provider. - -Oliphaunt never rewrites PostgreSQL catalog files or injects hidden SQL to -pretend that a standard seed was ICU-initialized. That is the correctness rule -behind “do not silently rewrite the seed's catalog.” For a new root the SDK -uses the right seed. For an existing root, catalog changes remain explicit -application migration work. - -## Runtime and data distribution - -ICU has two physical components: - -1. target-compiled ICU code is linked into each native or WASIX runtime; and -2. the large files-data tree is distributed separately as `icu-data`. - -Compiled code cannot be shared between native machine code and wasm32-WASIX. -The data files are shared from ICU's pinned official 76.1 little-endian data -archive. Every producer expands that same verified `icudt76l.dat` into the -same 4,136 paths and 31,723,424 content bytes; native and WASIX builds do not -regenerate separate target-dependent trees. Carriers normalize files to -`0644`, directories to `0755`, reject links/special files, and bind the logical -tree (`0523cc164d698d95d844e3683bbe23d415b575b84f4a04287d372e1c132cf1d1`) -with -`SHA-256(path NUL size NUL bytes LF)` in bytewise path order. - -There is one logical `icu-data` artifact. Ecosystem wrappers may differ: - -- `@oliphaunt/icu`, SwiftPM resources, Maven resources, and the shared Rust - `oliphaunt-icu` crate carry native-consumable data; -- `@oliphaunt/wasix-icu` and the WASIX Cargo assembly carry the same logical - data behind WASIX-specific descriptors/archives; and -- every wrapper must prove the same logical tree digest. - -The shared Rust `oliphaunt-icu` crate and other platform-neutral native ICU -wrappers remain data-only. They cannot safely carry one native physical seed -for every operating system and architecture. Each target-specific native -runtime carrier transports its own small matching `icu` seed as -`cluster-seed-icu`; the runtime resolver pairs it with the independently staged -`icu-data` artifact. - -The data-only carrier exposes one canonical `manifest.properties` containing -only its `oliphaunt-icu-data-v1` schema, `icu-data` role, ICU version/form, and -logical tree SHA-256. A target seed repeats that digest in its own manifest. -Comparing the two receipts binds the closure without rereading 31.7 MB on every -open; full tree hashing remains a producer check and an unmanaged-path check. -Release qualification compares that native receipt with the canonical WASIX -runtime and ICU seed manifests after both release families have been assembled; -single-family focused builds do not manufacture a cross-family proof. - -The native ICU release asset records only `icu-data`. Each target runtime report -records `cluster-seed` and `cluster-seed-icu` separately from runtime bytes. -Cargo and npm package limits continue to apply to the final carrier bytes. - -## Seed compatibility - -A physical cluster seed is more restrictive than ICU data. PostgreSQL records -ABI facts in `global/pg_control` and refuses incompatible clusters. - -Oliphaunt has two compatibility domains: - -| Runtime family | Compatibility identity | Reason | -| --- | --- | --- | -| native | Target-qualified PostgreSQL 18 native identity | Physical files are qualified for the declared native target and ABI; distributed seeds intentionally contain no imported host libc collation rows. | -| wasm32-WASIX | `wasix-pg18-datum32-v1` | Four-byte pointer/`Datum`; `float8` is passed by reference. | - -WASIX extends WASI with operating-system APIs but does not change wasm32 linear -memory to 64-bit. PostgreSQL defines `Datum` from `uintptr_t`, so forcing a -64-bit `Datum` into today's wasm32 build would create an incompatible -PostgreSQL and extension ABI. A local cross-runtime experiment confirmed that -PostgreSQL rejects the other family's seed with the explicit -`USE_FLOAT8_BYVAL` mismatch. - -Every desktop native target and WASIX therefore receive separately qualified -`standard` and `icu` seed bytes. Mobile domains receive a producer-built -candidate only after exact ABI receipts prove equality across the producer and -both target builds; the carrier then binds it to that mobile domain. No seed is -silently relabelled on pointer-width or operating-system assumptions alone. -The ICU files-data tree remains shared. - -The v1 native compatibility targets are deliberately finite: - -| Target | Compatibility key | -| --- | --- | -| `macos-arm64` | `native-pg18-macos-arm64-v1` | -| `linux-x64-gnu` | `native-pg18-linux-x64-gnu-v1` | -| `linux-arm64-gnu` | `native-pg18-linux-arm64-gnu-v1` | -| `windows-x64-msvc` | `native-pg18-windows-x64-msvc-v1` | -| `ios-datum64` | `native-pg18-ios-datum64-v1` | -| `android-datum64` | `native-pg18-android-datum64-v1` | - -Before app packaging, Android x86_64, Android arm64, and the Linux producer must -have identical compile/header ABI receipts. The equivalent iOS gate compares -the simulator, device, and macOS producer receipts. This admits an -**ABI-compatible candidate closure**; the embedded provenance records do not -claim that the seed executed on every target. - -The receipt compares PostgreSQL's independent physical-compatibility inputs: -byte order, `Datum` width, maximum alignment, `float8` passing, block and -relation-segment sizes, `NAMEDATALEN`, `INDEX_MAX_KEYS`, and catalog/control -versions. PostgreSQL 18 derives `LOBLKSIZE` from the block size and derives its -TOAST chunk size from the same block/alignment inputs and pinned source; integer -datetimes are unconditional. Repeating those derived values would not add -independent evidence. The finite arm64/x86_64 target set uses the platforms' -standard floating-point ABI, and the installed-app E2E remains the execution -proof. - -The x86_64 emulator and iOS simulator then execute the packaged representative -candidate, verify its selected catalog profile, and reopen the same persistent -root. Those installed-app checks feed the required top-level E2E gate, which is -the final mobile release execution qualification. These are explicit -compatibility domains, not inferences from pointer width. - -## Architecture and DRY boundary - -The implementation has four layers: - -1. **Producer** — an ordinary native bootstrap PostgreSQL process runs - `initdb`, rather than loading embedded consumer substitutions. The pipeline - validates catalog and shutdown invariants, cleans transient PGDATA, and - emits a deterministic seed plus manifest. Compile/header ABI receipts admit - the candidate closure before packaging; representative installed-app E2E - admits it for release. -2. **Release graph** — generated metadata binds runtime, profile, seed, ICU - data, target ABI, source lane, and ecosystem carrier by exact identity. -3. **Resolved runtime closure** — each SDK resolves runtime, catalog profile, - optional ICU data, matching seed, and extensions before seed loading or - PGDATA mutation/publication. -4. **Provider-local hydrator** — native filesystems, WASIX memory, IndexedDB, - OPFS, and host directories copy/extract into private staging and publish - through their honest durability boundary. Directory SDKs publish PGDATA and - then the descriptor durably; interruption between them fails closed rather - than pretending that multiple filesystem entries are one atomic operation. - -The cross-language contract lives in -`src/shared/cluster-seed-contract/contract.json`. It owns profile names, -artifact roles, ICU form/version, readiness signal, physical formats, -compatibility keys, and the logical digest algorithm. The independently -scheduled `sdk-contracts:cluster-seeds` gate validates canonical fixtures and -is included in the local `sdk-contracts:all` aggregate. Release tools -reuse one native manifest/digest validator rather than reimplementing it. - -Filesystem hot paths deliberately remain provider-local. A universal -filesystem abstraction would hide different atomicity, locking, and cloning -semantics and would harm performance. The shared abstraction is the validated -`ResolvedRuntimeClosure`, not a universal file API. - -## Correctness rules - -These rules are locked: - -- A seed contains only ordinary `initdb` bootstrap state. It contains no user - schema/data, secrets, selected optional extensions, or migrations. -- Seeds and explicit `initdb` fallback always bootstrap the fixed `postgres` - role. Connection username is not an initialization option. -- `standard` generation clears ambient ICU variables. `icu` generation requires - the exact verified data tree. -- PostgreSQL trusts only `OLIPHAUNT_INTERNAL_ICU_READY=1` during controlled - `initdb`; ambient `ICU_DATA` alone cannot select a catalog profile. -- The internal readiness variable is removed or set deterministically for every - runtime instance. It is not a public feature switch. -- A published package with a missing, malformed, wrong-profile, or incompatible - seed fails closed. Maintainer/source builds may use the explicit local - `initdb` fallback. -- Manifest cache keys are single portable path components; `.` and `..` are - invalid even though dot is otherwise allowed in an identifier. -- A seed is copied into a private destination. Hydration never hardlinks mutable - database files to package contents or another database. -- Native hydration normalizes host-dependent shared-memory settings after the - copy. WASIX hydration retains its provider-specific overlay/extraction path. -- Existing roots are never implicitly reinitialized or reseeded. -- ICU upgrades never trigger hidden `REINDEX` or - `ALTER COLLATION ... REFRESH VERSION`; applications follow PostgreSQL's - per-database upgrade procedure. -- The five-field `.oliphaunt.json` storage descriptor and physical backup - formats do not gain a seed-profile field. The database catalog is the - resulting state; seed provenance is not durable root identity. -- Embedded seed clones retain the producer database-system identifier in v1 and - do not expose physical replication or WAL-archive identity semantics. New - native server roots use normal server `initdb` so every server receives a - unique system identifier. Oliphaunt does not byte-patch `pg_control`. - -## PGlite comparison - -PGlite's `@electric-sql/pglite-prepopulatedfs` demonstrates the startup value -of shipping initialized PGDATA. Its public helper returns an archive through -`loadDataDir`, while ICU is supplied separately through `icuDataDir`. - -Oliphaunt adopts runtime-bound preinitialization but makes two stricter choices: - -- users do not manually align or inject a raw seed archive; the runtime carrier - supplies it; and -- selecting packaged ICU also selects a seed whose catalog was initialized - with that exact ICU data. - -PGlite's separate `loadDataDir` and `icuDataDir` concepts are valid. The risky -combination is an arbitrary prepopulated archive plus ICU data when the archive -was initialized without ICU: the bytes are available, but the predefined -catalog is not retroactively created. Oliphaunt prevents that mismatch in its -package-managed path. - -## Implemented shipment checklist - -The repository implementation must keep every item below true: - -- [x] Canonical names are `standard`, `icu`, and `icu-data`; artifact roles are - `cluster-seed-standard`, `cluster-seed-icu`, and `icu-data`. -- [x] Each native target and WASIX Datum32 use separately qualified physical - seed products. -- [x] Native and WASIX PostgreSQL patch stacks use the same exact internal ICU - readiness rule during `initdb`. -- [x] Native and WASIX producers generate both profiles through one - parameterized pipeline per runtime family. -- [x] Producers clear ambient ICU selection, require exact data for `icu`, and - emit extension-free, clean-shutdown seeds. -- [x] WASIX runtime manifests use format v2 and carry both seed descriptors and - archives under `cluster-seeds/`. -- [x] Native target release assets carry target-qualified `standard` and `icu` - seeds. -- [x] Target-specific native runtime assets carry their matching `icu` seed; - platform-neutral native ICU data assets stay data-only and carry an exact - logical tree binding. -- [x] The WASIX ICU carrier carries shared ICU data plus the WASIX `icu` seed; - it never carries a native seed. -- [x] Every native carrier declares `clusterSeedTarget` and the fixed sibling - paths `cluster-seed` and `cluster-seed-icu`. A SwiftPM application receives - the closure embedded in its selected XCFramework slice; React Native stages - the one app-selected closure and removes embedded copies from its staged base - framework. -- [x] Native Cargo target carriers aggregate both native seeds while the shared - `oliphaunt-icu` crate and every other platform-neutral ICU wrapper stay - data-only. -- [x] npm, Cargo, SwiftPM, Maven, Kotlin, React Native, Rust, native TypeScript, - Rust WASIX, and WASIX TypeScript carrier/resolver paths reject missing or - wrong-profile closure members. -- [x] Every SDK treats `username` as an existing connection role, bootstraps - only `postgres`, and rejects a fresh non-`postgres` open before seed loading - or PGDATA mutation/publication. -- [x] Native Rust, native TypeScript, Swift, Kotlin, React Native, Rust WASIX, - and WASIX TypeScript hydrate only new/empty roots and leave existing roots - untouched. -- [x] Hydration copies mutable files, rejects unsafe archive members, uses - private staging, and publishes through provider-appropriate atomicity. -- [x] ICU data composition occurs before extensions; extension selection remains - independent and generated from the canonical extension model. -- [x] Release validators compare exact manifest fields and ICU logical tree - digests instead of accepting directory names or substring matches. -- [x] Release notice closures include PostgreSQL for derived seed files and ICU - for data files. -- [x] Package footprint reports separate runtime, standard seed, ICU seed, and - ICU data bytes where those products are assembled. -- [x] The cluster-seed contract is wired into `sdk-contracts:cluster-seeds`; source-free - asset and release checks cover the generated graph. -- [x] Negative tests cover profile mismatches, missing members, changed data - digests, unsafe inputs, and fail-closed package resolution. - -## Per-release qualification checklist - -These are recurring release gates, not unfinished architecture: - -- [ ] Generate all seeds from the exact release runtime/source commit in trusted - CI; never reuse an unbound developer cache. -- [ ] Verify `PG_VERSION`, `pg_control`, clean shutdown, bootstrap databases, - empty extension selection, and exact catalog expectations for both profiles. -- [ ] Compare all target and producer compile/header ABI receipts before mobile - app packaging, then require representative emulator/simulator installed-app - E2E before final release execution qualification. -- [ ] Compare the native and WASIX ICU logical tree digests and run - representative locale/collation probes against the exact released data. -- [ ] Pack and reinstall every Cargo, npm, SwiftPM, Maven, and React Native - carrier; verify no source-tree or sibling-package fallback is possible. -- [ ] Exercise memory, host-directory, IndexedDB, OPFS, direct, broker, server, - and mobile paths that are available on the release matrix. -- [ ] Prove first-open success, reopen stability, crash-safe unpublished staging, - concurrent-open exclusion, and nonempty-root nonmutation. -- [ ] Benchmark paired cold/warm `initdb` versus seed hydration and first query; - publish medians, tails, bytes, CPU, I/O, and decompression costs. -- [ ] Audit the standard and ICU size rows and enforce registry/package limits. -- [ ] Run repository release, committed-asset, extension-model, SDK-contract, and - affected-target qualification at the exact candidate SHA. - -## Performance policy - -Performance is a feature, but it does not weaken correctness: - -- standard users do not download the 31.7 MB uncompressed ICU data tree; -- package-managed new roots avoid end-user `initdb`; -- seed manifests and descriptor hashes are validated before seed loading or - PGDATA mutation/publication; -- persistent WASIX stores are inspected before seed archives are fetched or - expanded; -- package-managed immutable ICU identities are not recomputed by reading the - complete data tree on every open; -- PostgreSQL frontend tools do not mount backend-only ICU data; -- hot provider operations use their existing copy-on-write, reflink, archive, - journal, or direct-OPFS mechanisms; -- immutable source package files are never made mutable through hardlinks; and -- claims use reproducible cold/warm benchmarks on final carrier bytes, not a - one-off producer-tree timing. - -If a future consumer cannot use the canonical ICU data form because of ICU -major, endianness, charset family, or a different data filter, it receives a -new compatibility identity only after an executable consumer gate proves the -difference. If a future wasm64-WASIX runtime changes PostgreSQL's `Datum` ABI, -it likewise receives a new seed compatibility key rather than reusing today's -wasm32 seed. diff --git a/docs/internal/OLIPHAUNT_PATCH_STACK.md b/docs/internal/OLIPHAUNT_PATCH_STACK.md deleted file mode 100644 index 404f7fded..000000000 --- a/docs/internal/OLIPHAUNT_PATCH_STACK.md +++ /dev/null @@ -1,155 +0,0 @@ - -# liboliphaunt PostgreSQL 18 Patch Stack Review - -This source-only review artifact keeps the native PostgreSQL patch stack deterministic and reviewable without rebuilding PostgreSQL. - -Regenerate with: - -```sh -src/runtimes/liboliphaunt/native/tools/check-patch-stack.mjs --write -``` - -## Source Pin - -- PostgreSQL: `18.4` -- URL: `https://ftp.postgresql.org/pub/source/v18.4/postgresql-18.4.tar.bz2` -- SHA-256: `81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094` -- Patch directory: `../patches/postgresql-18.4` - -## Patch Series - -| Order | Patch | Author | Subject | -| --- | --- | --- | --- | -| 1 | `0001-liboliphaunt-add-backend-host-io.patch` | liboliphaunt | liboliphaunt: add backend host I/O callbacks | -| 2 | `0002-liboliphaunt-add-embedded-entrypoint.patch` | liboliphaunt | liboliphaunt: add embedded backend entrypoint | -| 3 | `0003-liboliphaunt-return-from-embedded-frontend-terminate.patch` | liboliphaunt | liboliphaunt: return from embedded frontend terminate | -| 4 | `0004-liboliphaunt-run-embedded-exit-cleanup.patch` | liboliphaunt | liboliphaunt: run embedded exit cleanup without exiting | -| 5 | `0005-liboliphaunt-restore-host-cwd.patch` | liboliphaunt | liboliphaunt: restore host cwd after embedded shutdown | -| 6 | `0006-liboliphaunt-add-static-extension-loader.patch` | liboliphaunt | liboliphaunt: add static extension loader | -| 7 | `0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch` | liboliphaunt | liboliphaunt: disable shell commands on Apple mobile targets | -| 8 | `0008-liboliphaunt-clean-embedded-symbols.patch` | liboliphaunt | liboliphaunt: clean embedded symbols | -| 9 | `0009-liboliphaunt-guard-embedded-proc-exit.patch` | liboliphaunt | liboliphaunt: guard embedded proc_exit failures | -| 10 | `0010-liboliphaunt-use-host-runtime-paths.patch` | liboliphaunt | liboliphaunt: use host-provided embedded runtime paths | -| 11 | `0011-liboliphaunt-add-android-embedded-shared-memory.patch` | liboliphaunt | liboliphaunt: add embedded mobile shared memory and semaphores | -| 12 | `0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch` | liboliphaunt | liboliphaunt: enable event triggers in embedded backend sessions | -| 13 | `0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch` | liboliphaunt | liboliphaunt: fix embedded BackendMain return contract | -| 14 | `0014-liboliphaunt-use-portable-embedded-socketpair.patch` | liboliphaunt | liboliphaunt: use portable embedded socketpair | -| 15 | `0015-liboliphaunt-add-embedded-meson-option.patch` | liboliphaunt | liboliphaunt: add embedded meson option | -| 16 | `0016-liboliphaunt-control-initdb-collation-discovery.patch` | liboliphaunt | liboliphaunt: control initdb collation discovery | -| 17 | `0017-liboliphaunt-namespace-dynahash-host-collisions.patch` | liboliphaunt | liboliphaunt: namespace Apple dynahash host collisions | -| 18 | `0018-liboliphaunt-contain-embedded-proc-signals.patch` | liboliphaunt | liboliphaunt: contain embedded process signals | -| 19 | `0019-liboliphaunt-link-windows-embedded-modules-to-host.patch` | liboliphaunt | liboliphaunt: link Windows embedded modules to host | -| 20 | `0020-liboliphaunt-enforce-embedded-signal-boundary.patch` | liboliphaunt | liboliphaunt: enforce embedded signal boundary | - -## Changed Upstream Files - -- `meson.build` (`0015-liboliphaunt-add-embedded-meson-option.patch`) -- `meson_options.txt` (`0015-liboliphaunt-add-embedded-meson-option.patch`, `0019-liboliphaunt-link-windows-embedded-modules-to-host.patch`) -- `src/backend/access/transam/xlogarchive.c` (`0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch`) -- `src/backend/archive/shell_archive.c` (`0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch`) -- `src/backend/commands/collationcmds.c` (`0016-liboliphaunt-control-initdb-collation-discovery.patch`) -- `src/backend/commands/event_trigger.c` (`0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch`) -- `src/backend/libpq/be-secure.c` (`0001-liboliphaunt-add-backend-host-io.patch`) -- `src/backend/libpq/pqcomm.c` (`0001-liboliphaunt-add-backend-host-io.patch`) -- `src/backend/meson.build` (`0019-liboliphaunt-link-windows-embedded-modules-to-host.patch`) -- `src/backend/port/Makefile` (`0011-liboliphaunt-add-android-embedded-shared-memory.patch`) -- `src/backend/port/meson.build` (`0011-liboliphaunt-add-android-embedded-shared-memory.patch`) -- `src/backend/port/oliphaunt_embedded_sema.c` (`0011-liboliphaunt-add-android-embedded-shared-memory.patch`) -- `src/backend/port/oliphaunt_embedded_shmem.c` (`0011-liboliphaunt-add-android-embedded-shared-memory.patch`) -- `src/backend/storage/ipc/ipc.c` (`0004-liboliphaunt-run-embedded-exit-cleanup.patch`, `0009-liboliphaunt-guard-embedded-proc-exit.patch`) -- `src/backend/storage/ipc/procsignal.c` (`0018-liboliphaunt-contain-embedded-proc-signals.patch`) -- `src/backend/tcop/postgres.c` (`0002-liboliphaunt-add-embedded-entrypoint.patch`, `0003-liboliphaunt-return-from-embedded-frontend-terminate.patch`, `0004-liboliphaunt-run-embedded-exit-cleanup.patch`, `0005-liboliphaunt-restore-host-cwd.patch`, `0009-liboliphaunt-guard-embedded-proc-exit.patch`, `0010-liboliphaunt-use-host-runtime-paths.patch`, `0014-liboliphaunt-use-portable-embedded-socketpair.patch`, `0018-liboliphaunt-contain-embedded-proc-signals.patch`) -- `src/backend/utils/fmgr/dfmgr.c` (`0006-liboliphaunt-add-static-extension-loader.patch`, `0008-liboliphaunt-clean-embedded-symbols.patch`) -- `src/bin/initdb/initdb.c` (`0016-liboliphaunt-control-initdb-collation-discovery.patch`) -- `src/include/libpq/libpq-be.h` (`0001-liboliphaunt-add-backend-host-io.patch`) -- `src/include/port.h` (`0011-liboliphaunt-add-android-embedded-shared-memory.patch`, `0020-liboliphaunt-enforce-embedded-signal-boundary.patch`) -- `src/include/storage/dsm_impl.h` (`0011-liboliphaunt-add-android-embedded-shared-memory.patch`) -- `src/include/storage/ipc.h` (`0004-liboliphaunt-run-embedded-exit-cleanup.patch`, `0009-liboliphaunt-guard-embedded-proc-exit.patch`) -- `src/include/tcop/backend_startup.h` (`0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch`) -- `src/include/tcop/tcopprot.h` (`0003-liboliphaunt-return-from-embedded-frontend-terminate.patch`, `0008-liboliphaunt-clean-embedded-symbols.patch`) -- `src/include/utils/hsearch.h` (`0017-liboliphaunt-namespace-dynahash-host-collisions.patch`) -- `src/port/chklocale.c` (`0011-liboliphaunt-add-android-embedded-shared-memory.patch`) -- `src/port/pqsignal.c` (`0020-liboliphaunt-enforce-embedded-signal-boundary.patch`) - -## Expected Upstream Touchpoints - -| File | Rationale | -| --- | --- | -| `meson.build` | Meson-hosted embedded builds enable OLIPHAUNT_EMBEDDED through an explicit opt-in build option. | -| `meson_options.txt` | Meson-hosted embedded builds declare opt-in backend and Windows module-provider options without changing default PostgreSQL builds. | -| `src/backend/access/transam/xlogarchive.c` | Apple mobile embedded builds compile out optional archive shell commands. | -| `src/backend/archive/shell_archive.c` | Apple mobile embedded builds compile out optional archive shell commands. | -| `src/backend/commands/collationcmds.c` | System-collation import preserves host providers except during deliberate deterministic distributed-seed production; verified ICU readiness independently gates only the ICU provider. | -| `src/backend/commands/event_trigger.c` | Embedded FE/BE protocol sessions can run event triggers without changing standalone recovery behavior. | -| `src/backend/libpq/be-secure.c` | Backend secure read/write path delegates to a host I/O vtable only when OLIPHAUNT_EMBEDDED is set. | -| `src/backend/libpq/pqcomm.c` | Standalone embedded sessions avoid waiting on a non-existent postmaster death latch. | -| `src/backend/meson.build` | Embedded MSVC extension modules link to the oliphaunt host import library instead of the standalone postgres executable. | -| `src/backend/port/Makefile` | Embedded mobile builds swap unavailable SysV shared memory and semaphores for process-local implementations. | -| `src/backend/port/meson.build` | Android embedded builds swap unavailable SysV shared memory and semaphores for process-local implementations. | -| `src/backend/port/oliphaunt_embedded_sema.c` | Embedded mobile semaphore implementation for one backend in one process. | -| `src/backend/port/oliphaunt_embedded_shmem.c` | Embedded mobile shared memory implementation for one backend in one process. | -| `src/backend/storage/ipc/ipc.c` | Embedded backend cleanup and proc_exit unwinding stay at PostgreSQL lifecycle boundaries. | -| `src/backend/storage/ipc/procsignal.c` | The one-backend embedded runtime dispatches ProcSignal flags without sending process-directed host signals. | -| `src/backend/tcop/postgres.c` | Embedded backend entrypoint, protocol lifecycle, cwd restoration, host runtime paths, and host-owned SIGUSR1 disposition. | -| `src/backend/utils/fmgr/dfmgr.c` | Static extension lookup reuses PostgreSQL dynamic function manager semantics. | -| `src/bin/initdb/initdb.c` | Controlled seed production selects standard or verified ICU collation discovery without changing ordinary initdb semantics. | -| `src/include/libpq/libpq-be.h` | Host I/O vtable is attached to PostgreSQL Port state under OLIPHAUNT_EMBEDDED. | -| `src/include/port.h` | Embedded mobile builds avoid POSIX shared memory declarations and route embedded backend signal calls through the host-safe provider boundary. | -| `src/include/storage/dsm_impl.h` | Embedded mobile builds keep DSM on mmap instead of POSIX or SysV shared memory. | -| `src/include/storage/ipc.h` | Embedded cleanup and proc_exit guard declarations. | -| `src/include/tcop/backend_startup.h` | Embedded BackendMain may return after its returning PostgresMain call without retaining an invalid pg_noreturn declaration. | -| `src/include/tcop/tcopprot.h` | Embedded entrypoint and returning PostgresMain declarations. | -| `src/include/utils/hsearch.h` | Apple builds namespace PostgreSQL dynahash symbols that otherwise bind to unrelated libSystem exports. | -| `src/port/chklocale.c` | Android embedded builds avoid unsupported locale-environment mutation. | -| `src/port/pqsignal.c` | Embedded backend signal registration and emission preserve the host-owned SIGUSR1 disposition while delegating other signals. | - -## PostgreSQL Patch Symbols - -- `oliphaunt_embedded_kill` (`0020-liboliphaunt-enforce-embedded-signal-boundary.patch`) -- `oliphaunt_embedded_main` (`0002-liboliphaunt-add-embedded-entrypoint.patch`, `0008-liboliphaunt-clean-embedded-symbols.patch`) -- `oliphaunt_embedded_proc_exit` (`0004-liboliphaunt-run-embedded-exit-cleanup.patch`) -- `oliphaunt_embedded_proc_exit_handler` (`0009-liboliphaunt-guard-embedded-proc-exit.patch`) -- `oliphaunt_embedded_raise` (`0020-liboliphaunt-enforce-embedded-signal-boundary.patch`) -- `oliphaunt_embedded_set_proc_exit_handler` (`0009-liboliphaunt-guard-embedded-proc-exit.patch`) -- `oliphaunt_static_extension_init` (`0006-liboliphaunt-add-static-extension-loader.patch`) -- `oliphaunt_static_extension_lookup` (`0006-liboliphaunt-add-static-extension-loader.patch`) -- `oliphaunt_static_extension_magic` (`0006-liboliphaunt-add-static-extension-loader.patch`) -- `oliphaunt_static_extension_symbol` (`0006-liboliphaunt-add-static-extension-loader.patch`) - -## Audit Checklist - -| Requirement | Owning Patch | Required Evidence | Review Posture | -| --- | --- | --- | --- | -| Host-owned protocol I/O vtable | `0001-liboliphaunt-add-backend-host-io.patch` | `OliphauntEmbeddedIO`, `secure_raw_read`, `secure_raw_write` | Generic libpq backend hook; normal socket I/O remains untouched. | -| Standalone backend waitset guard | `0001-liboliphaunt-add-backend-host-io.patch` | `WL_POSTMASTER_DEATH`, `if (IsUnderPostmaster)` | Embedded standalone sessions avoid a postmaster-death wait handle that cannot exist. | -| Explicit embedded backend entrypoint | `0002-liboliphaunt-add-embedded-entrypoint.patch` | `oliphaunt_embedded_main`, `pq_init(&client_sock)`, `PostgresMain(dbname, username)` | Uses PostgreSQL backend initialization and FE/BE protocol instead of single-user query transport. | -| Embedded BackendMain may return without violating its declaration | `0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch` | `#ifdef OLIPHAUNT_EMBEDDED`, `extern void BackendMain`, `pg_noreturn extern void BackendMain` | Only embedded builds drop pg_noreturn; normal PostgreSQL server builds retain the upstream non-returning contract. | -| Frontend Terminate returns to host owner | `0003-liboliphaunt-return-from-embedded-frontend-terminate.patch` | `frontend sends Terminate`, `return;`, `proc_exit(0)` | Only OLIPHAUNT_EMBEDDED changes backend termination into a returning thread lifecycle. | -| PostgreSQL exit callbacks still run | `0004-liboliphaunt-run-embedded-exit-cleanup.patch` | `oliphaunt_embedded_proc_exit`, `proc_exit_prepare(code)` | Keeps upstream cleanup ordering for shmem, locks, callbacks, and backend-local state. | -| Startup FATAL does not exit the host process | `0009-liboliphaunt-guard-embedded-proc-exit.patch` | `oliphaunt_embedded_set_proc_exit_handler`, `siglongjmp`, `proc_exit_handler` | Embedded startup failures unwind to liboliphaunt after PostgreSQL cleanup callbacks run. | -| Embedded proc_exit guard is cleared before returning to host | `0009-liboliphaunt-guard-embedded-proc-exit.patch` | `embedded_cleanup:`, `oliphaunt_embedded_set_proc_exit_handler(NULL, NULL)`, `chdir(original_cwd)` | Normal and FATAL startup paths share one cleanup label so thread-local exit guards and host cwd are restored before returning. | -| Host working directory is restored | `0005-liboliphaunt-restore-host-cwd.patch` | `original_cwd`, `getcwd(original_cwd`, `chdir(original_cwd)` | Contains PostgreSQL standalone ChangeToDataDir side effects inside the backend lifetime. | -| Static extension registry uses PostgreSQL dfmgr path | `0006-liboliphaunt-add-static-extension-loader.patch` | `oliphaunt_static_extension_lookup`, `lookup_library_symbol`, `oliphaunt_static_extension_symbol` | CREATE EXTENSION/LOAD semantics stay in PostgreSQL; hosts only provide module symbols. | -| MSVC PostgreSQL tools link without static extension providers | `0006-liboliphaunt-add-static-extension-loader.patch` | `defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))`, `/alternatename:oliphaunt_static_extension_lookup=oliphaunt_static_extension_lookup_default`, `oliphaunt_static_extension_symbol_default` | Meson-built PostgreSQL tools get no-op static extension hooks on MSVC; liboliphaunt still overrides them by linking the real registry provider. | -| Portable PostgreSQL tools link without static extension providers | `0006-liboliphaunt-add-static-extension-loader.patch` | `#define OLIPHAUNT_OPTIONAL_HOOK __attribute__((weak))`, `oliphaunt_static_extension_lookup(const char *filename)`, `oliphaunt_static_extension_init(const OliphauntStaticExtension *extension)` | Non-MSVC embedded PostgreSQL tool links get weak no-op static extension hooks; liboliphaunt overrides them by linking the real registry provider. | -| Static extension ABI magic is validated | `0006-liboliphaunt-add-static-extension-loader.patch`, `0008-liboliphaunt-clean-embedded-symbols.patch` | `oliphaunt_static_extension_magic`, `Pg_magic_struct`, `memcmp(&magic_data_ptr->abi_fields` | Static modules still pass PostgreSQL ABI checks before symbols are used. | -| Runtime paths come from host-packaged resources | `0010-liboliphaunt-use-host-runtime-paths.patch` | `oliphaunt_embedded_set_runtime_paths`, `OLIPHAUNT_EMBEDDED_MODULE_DIR`, `my_exec_path`, `PGSYSCONFDIR` | Avoids executable-bit assumptions for mobile resources while preserving runtime path derivation and using host-packaged embedded modules for pkglib_path. | -| Apple mobile builds do not call system(3) | `0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch` | `OLIPHAUNT_EMBEDDED_NO_SHELL_COMMANDS`, `TARGET_OS_IPHONE`, `archive_command cannot be executed` | Mobile direct mode fails optional shell archive/restore hooks explicitly instead of compiling unavailable APIs. | -| Embedded mobile shared memory and semaphores are process-local | `0011-liboliphaunt-add-android-embedded-shared-memory.patch` | `oliphaunt_embedded_shmem.c`, `oliphaunt_embedded_sema.c`, `OLIPHAUNT_EMBEDDED_MOBILE_SHMEM` | Android and Apple mobile builds avoid unavailable SysV shared memory and semaphores while direct mode remains one backend per process. | -| Event triggers run in embedded protocol sessions | `0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch` | `EventTriggersHaveRunnableBackend`, `OLIPHAUNT_EMBEDDED`, `event_triggers` | Keeps upstream single-user escape hatch outside OLIPHAUNT_EMBEDDED but treats embedded protocol sessions as runnable backends. | -| Meson builds expose an explicit embedded backend option | `0015-liboliphaunt-add-embedded-meson-option.patch` | `oliphaunt_embedded`, `add_project_arguments`, `-DOLIPHAUNT_EMBEDDED` | Windows and other Meson-hosted embedded builds enable the backend entrypoint through PostgreSQL build configuration while default server builds remain unchanged. | -| Optional ICU data stays optional during initdb | `0016-liboliphaunt-control-initdb-collation-discovery.patch` | `OLIPHAUNT_INTERNAL_ICU_READY`, `OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY`, `OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY`, `strcmp`, `pg_collation_actual_version`, `pg_import_system_collations` | Ordinary initdb and public collation import retain PostgreSQL host discovery. Distributed standard seeds suppress OS and ICU discovery; ICU seeds suppress only OS discovery and verify ICU readiness for initdb's unicode-version probe. | -| Apple builds namespace PostgreSQL dynahash symbols that collide with libSystem | `0017-liboliphaunt-namespace-dynahash-host-collisions.patch` | `#ifdef __APPLE__`, `oliphaunt_pg_hash_create`, `oliphaunt_pg_hash_destroy`, `oliphaunt_pg_hash_search` | Apple backend and extension objects share collision-free dynahash names; non-Apple PostgreSQL binary names remain unchanged. | -| Embedded ProcSignal delivery cannot escape into the host process | `0018-liboliphaunt-contain-embedded-proc-signals.patch` | `oliphaunt_send_proc_signal`, `pid != MyProcPid`, `procsignal_sigusr1_handler(SIGUSR1)`, `host owns SIGUSR1` | The one-backend embedded runtime dispatches ProcSignal flags synchronously, rejects foreign PIDs, and leaves the host SIGUSR1 disposition untouched; normal PostgreSQL server builds retain upstream signal delivery. | -| Windows embedded extension modules link to the host DLL provider | `0019-liboliphaunt-link-windows-embedded-modules-to-host.patch` | `oliphaunt_embedded_module_provider`, `requires an embedded MSVC Windows build`, `pg_mod_link_args += oliphaunt_embedded_module_provider`, `oliphaunt_embedded_module_provider == ''` | Embedded MSVC extension modules resolve PostgreSQL backend symbols from the oliphaunt host import library; ordinary PostgreSQL modules retain the upstream postgres executable link contract. | -| Embedded backend and extension signal calls preserve host SIGUSR1 ownership | `0020-liboliphaunt-enforce-embedded-signal-boundary.patch` | `oliphaunt_embedded_kill`, `oliphaunt_embedded_raise`, `!defined(FRONTEND)`, `if (signo == SIGUSR1)` | Embedded backend and extension calls cannot replace or emit host-owned SIGUSR1; other signals delegate to the platform implementation, while frontend tools and normal PostgreSQL builds retain upstream behavior. | - -## Guardrails - -- `source.toml` patch series exactly matches the patch directory. -- Every patch has a deterministic `From: liboliphaunt ` header. -- Every patch has a deterministic `Subject: [PATCH] liboliphaunt: ...` header. -- Entire patch files are checked for trailing whitespace; added PostgreSQL lines are also checked for space-before-tab indentation and SDK/runtime/product-specific terms that belong above PostgreSQL. -- Changed upstream files must exactly match the expected touchpoint table above; new upstream touchpoints need an explicit rationale before landing. -- Required audit checks prove their evidence in the named owning patch or patches, keeping host I/O, embedded lifecycle, cleanup, cwd restore, runtime paths, static extensions, host-signal containment, Windows module linkage, mobile shell exclusion, embedded mobile shared memory, and event triggers reviewable independently. -- Changed upstream files and patch-introduced `oliphaunt_*` symbols are listed here for release review. diff --git a/docs/internal/README.md b/docs/internal/README.md deleted file mode 100644 index 71d203bc6..000000000 --- a/docs/internal/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Internal documents - -Status: archived implementation history and evidence. - -These files record earlier plans, completed work, investigations, and migration details. They are not current maintainer policy. Start with `docs/maintainers/README.md`, then inspect executable configuration and generated catalogs. A current maintainer document may link to a specific internal artifact as supporting evidence; that does not make the rest of the internal document normative. diff --git a/docs/internal/WASIX_PATCH_STACK.md b/docs/internal/WASIX_PATCH_STACK.md deleted file mode 100644 index 81693b1bf..000000000 --- a/docs/internal/WASIX_PATCH_STACK.md +++ /dev/null @@ -1,217 +0,0 @@ - -# oliphaunt-wasix PostgreSQL 18 WASIX Patch Stack Review - -This source-only review artifact keeps the WASIX PostgreSQL patch stack deterministic and reviewable without rebuilding PostgreSQL. - -Regenerate with: - -```sh -src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs --write -``` - -## Source Pin - -- PostgreSQL: `18.4` -- URL: `https://ftp.postgresql.org/pub/source/v18.4/postgresql-18.4.tar.bz2` -- SHA-256: `81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094` -- Patch directory: `src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches` -- Experiment disposition policy: `do-not-port-experiment-patches-without-a-recorded-wasix-runtime-rationale` - -## Patch Series - -| Order | Patch | Author | Subject | -| --- | --- | --- | --- | -| 1 | `0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch` | Oliphaunt Maintainers | oliphaunt-wasix: add wasix-dl build spine | -| 2 | `0002-oliphaunt-wasix-add-backend-host-io-hooks.patch` | Oliphaunt Maintainers | oliphaunt-wasix: add backend host I/O hooks | -| 3 | `0003-oliphaunt-wasix-export-startup-packet-parser.patch` | Oliphaunt Maintainers | oliphaunt-wasix: export startup packet parser | -| 4 | `0004-oliphaunt-wasix-add-host-lifecycle-exports.patch` | Oliphaunt Maintainers | oliphaunt-wasix: add host lifecycle exports | -| 5 | `0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch` | Oliphaunt Maintainers | oliphaunt-wasix: add loop-pumped protocol exports | -| 6 | `0006-oliphaunt-wasix-report-copy-protocol-state.patch` | Oliphaunt Maintainers | oliphaunt-wasix: report COPY protocol state | -| 7 | `0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch` | Oliphaunt Maintainers | oliphaunt-wasix: add wasix PGXS side-module support | -| 8 | `0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch` | Oliphaunt Maintainers | oliphaunt-wasix: reset copy state on error recovery | -| 9 | `0009-oliphaunt-wasix-route-process-identity-through-port.patch` | Oliphaunt Maintainers | oliphaunt-wasix: route process identity through port | -| 10 | `0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch` | Oliphaunt Maintainers | oliphaunt-wasix: route sysv shmem through port | -| 11 | `0011-oliphaunt-wasix-prefer-posix-semaphores.patch` | Oliphaunt Maintainers | oliphaunt-wasix: prefer POSIX semaphores | -| 12 | `0012-oliphaunt-wasix-capture-startup-errors.patch` | Oliphaunt Maintainers | oliphaunt-wasix: capture startup errors | -| 13 | `0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch` | Oliphaunt Maintainers | oliphaunt-wasix: fail active portals on host recovery | -| 14 | `0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch` | Oliphaunt Maintainers | oliphaunt-wasix: speed up hash_bytes unaligned loads | -| 15 | `0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch` | Oliphaunt Maintainers | oliphaunt-wasix: add top xid current transaction fast path | -| 16 | `0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch` | Oliphaunt Maintainers | oliphaunt-wasix: add btree int4 compare fast path | -| 17 | `0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch` | Oliphaunt Maintainers | oliphaunt-wasix: keep btree delete scratch on stack | -| 18 | `0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch` | Oliphaunt Maintainers | oliphaunt-wasix: avoid pg_dump executeQuery LTO collision | -| 19 | `0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch` | Oliphaunt Maintainers | oliphaunt-wasix: schedule ready after host recovery | -| 20 | `0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch` | Oliphaunt Maintainers | oliphaunt-wasix: rearm exception stack after host recovery | -| 21 | `0021-oliphaunt-wasix-declare-wasix-fork.patch` | Oliphaunt Maintainers | oliphaunt-wasix: stub fork_process in embedded WASIX runtime | -| 22 | `0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch` | Oliphaunt Maintainers | oliphaunt-wasix: use wasm-ld for backend core | -| 23 | `0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch` | Oliphaunt Maintainers | oliphaunt-wasix: skip data-dir ownership check under embedded WASIX | -| 24 | `0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch` | Oliphaunt Maintainers | oliphaunt-wasix: add like literal substring fast path | -| 25 | `0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch` | Oliphaunt Maintainers | oliphaunt-wasix: stub pg_dump parallel fork | -| 26 | `0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch` | Oliphaunt Maintainers | oliphaunt-wasix: add first int4 leaf compare fast path | -| 27 | `0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch` | Oliphaunt Maintainers | oliphaunt-wasix: avoid XLog-size checkpoint requests | -| 28 | `0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch` | Oliphaunt Maintainers | oliphaunt-wasix: use lightweight embedded runtime paths | -| 29 | `0029-oliphaunt-wasix-set-embedded-postmaster-environment.patch` | Oliphaunt Maintainers | oliphaunt-wasix: set embedded postmaster environment | -| 30 | `0030-oliphaunt-wasix-avoid-xlogwrite-prevseg-division.patch` | Oliphaunt Maintainers | oliphaunt-wasix: avoid xlogwrite prevseg division | -| 31 | `0031-oliphaunt-wasix-skip-activity-id-reporting.patch` | Oliphaunt Maintainers | oliphaunt-wasix: skip activity id reporting | -| 32 | `0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch` | Oliphaunt Maintainers | oliphaunt-wasix: treat directory fsync EISDIR as unsupported | -| 33 | `0033-oliphaunt-wasix-control-initdb-collation-discovery.patch` | Oliphaunt Maintainers | oliphaunt-wasix: control initdb collation discovery | -| 34 | `0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch` | Oliphaunt Maintainers | oliphaunt-wasix: declare hybrid protocol transport | -| 35 | `0035-oliphaunt-wasix-use-single-backend-spinlocks.patch` | Oliphaunt Maintainers | oliphaunt-wasix: use single-backend spinlocks | -| 36 | `0036-oliphaunt-wasix-specialize-single-backend-atomics.patch` | Oliphaunt Maintainers | oliphaunt-wasix: specialize single-backend atomics | -| 37 | `0037-oliphaunt-wasix-buffer-strong-random.patch` | Oliphaunt Maintainers | oliphaunt-wasix: buffer strong random | -| 38 | `0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch` | Oliphaunt Maintainers | oliphaunt-wasix: disable unsupported writeback hints | -| 39 | `0039-oliphaunt-wasix-inline-sigsetjmp.patch` | Oliphaunt Maintainers | oliphaunt-wasix: inline sigsetjmp | -| 40 | `0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch` | Oliphaunt Maintainers | oliphaunt-wasix: set libpq sockets nonblocking | -| 41 | `0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch` | Oliphaunt Maintainers | oliphaunt-wasix: honor noninteractive psql invocations | -| 42 | `0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch` | Oliphaunt Maintainers | oliphaunt-wasix: use explicit WAL sync operations | -| 43 | `0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch` | Oliphaunt Maintainers | oliphaunt-wasix: cache jsonb_build_object metadata | - -## Changed Upstream Files - -| File | Owning Patch(es) | Rationale | -| --- | --- | --- | -| `src/Makefile.shlib` | `0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch`, `0039-oliphaunt-wasix-inline-sigsetjmp.patch` | Defines the WASIX dynamic-link shared-library shape. | -| `src/backend/Makefile` | `0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch`, `0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch` | Builds the dynamic-main backend module without changing other ports. | -| `src/backend/access/nbtree/nbtdedup.c` | `0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch` | Keeps btree delete scratch storage on stack under embedded WASIX. | -| `src/backend/access/nbtree/nbtinsert.c` | `0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch` | Adds the guarded int4 insert fast path. | -| `src/backend/access/nbtree/nbtsearch.c` | `0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch`, `0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch` | Adds guarded int4 leaf fast paths. | -| `src/backend/access/transam/xact.c` | `0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch` | Adds top-level current-transaction shortcut for embedded WASIX. | -| `src/backend/access/transam/xlog.c` | `0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch`, `0030-oliphaunt-wasix-avoid-xlogwrite-prevseg-division.patch`, `0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch` | Keeps checkpoint work local, avoids expensive segment division, and exposes only explicit WAL sync operations under embedded WASIX. | -| `src/backend/commands/collationcmds.c` | `0033-oliphaunt-wasix-control-initdb-collation-discovery.patch` | System-collation import preserves PostgreSQL semantics unless a controlled seed producer suppresses discovery. | -| `src/backend/commands/copyfromparse.c` | `0006-oliphaunt-wasix-report-copy-protocol-state.patch` | Reports COPY protocol state to the host. | -| `src/backend/commands/copyto.c` | `0006-oliphaunt-wasix-report-copy-protocol-state.patch` | Reports COPY protocol state to the host. | -| `src/backend/common.mk` | `0036-oliphaunt-wasix-specialize-single-backend-atomics.patch` | Scopes scalar atomics to PostgreSQL backend objects instead of PGXS side modules. | -| `src/backend/libpq/be-secure.c` | `0002-oliphaunt-wasix-add-backend-host-io-hooks.patch` | Routes embedded protocol reads and writes through host-owned callbacks. | -| `src/backend/libpq/pqcomm.c` | `0002-oliphaunt-wasix-add-backend-host-io-hooks.patch` | Skips unavailable postmaster-death wait handles in embedded WASIX. | -| `src/backend/main/main.c` | `0036-oliphaunt-wasix-specialize-single-backend-atomics.patch` | Rejects concurrent postmaster and fork-child dispatch in the scalar-atomic runtime. | -| `src/backend/optimizer/plan/planner.c` | `0031-oliphaunt-wasix-skip-activity-id-reporting.patch` | Suppresses activity identifier reporting in embedded WASIX. | -| `src/backend/port/posix_sema.c` | `0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch` | Uses POSIX semaphore behavior selected by the WASIX template. | -| `src/backend/postmaster/checkpointer.c` | `0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch` | Keeps checkpoint requests local to embedded WASIX. | -| `src/backend/postmaster/fork_process.c` | `0021-oliphaunt-wasix-declare-wasix-fork.patch` | Declares the WASIX fork boundary without enabling postmaster concurrency. | -| `src/backend/replication/walsender.c` | `0006-oliphaunt-wasix-report-copy-protocol-state.patch` | Suppresses activity identifier reporting in embedded WASIX. | -| `src/backend/storage/file/fd.c` | `0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch`, `0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch` | Keeps real fsync while narrowing unsupported WASIX directory and writeback-hint behavior. | -| `src/backend/tcop/backend_startup.c` | `0003-oliphaunt-wasix-export-startup-packet-parser.patch` | Exports the startup packet parser for host-driven startup. | -| `src/backend/tcop/postgres.c` | `0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`, `0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch`, `0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch`, `0012-oliphaunt-wasix-capture-startup-errors.patch`, `0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch`, `0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch`, `0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch`, `0029-oliphaunt-wasix-set-embedded-postmaster-environment.patch`, `0031-oliphaunt-wasix-skip-activity-id-reporting.patch` | Owns embedded lifecycle, protocol loop, and error recovery. | -| `src/backend/utils/adt/jsonb.c` | `0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch` | Caches immutable jsonb_build_object expression metadata while preserving PostgreSQL cast and VARIADIC semantics. | -| `src/backend/utils/adt/like.c` | `0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch` | Adds guarded LIKE literal fast path for embedded WASIX. | -| `src/backend/utils/adt/like_match.c` | `0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch` | Adds guarded LIKE literal fast path for embedded WASIX. | -| `src/backend/utils/init/miscinit.c` | `0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch` | Routes process identity through the WASIX port layer. | -| `src/backend/utils/init/postinit.c` | `0004-oliphaunt-wasix-add-host-lifecycle-exports.patch` | Skips data-directory ownership checks under embedded WASIX. | -| `src/backend/utils/misc/guc.c` | `0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch` | Uses the embedded WASIX postmaster-style environment. | -| `src/backend/utils/mmgr/portalmem.c` | `0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch` | Fails active portals on host-forced recovery. | -| `src/bin/initdb/initdb.c` | `0033-oliphaunt-wasix-control-initdb-collation-discovery.patch` | Controlled seed producers may suppress host discovery while verified ICU readiness gates the unicode-version probe. | -| `src/bin/pg_dump/connectdb.c` | `0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch` | Avoids pg_dump LTO symbol collisions. | -| `src/bin/pg_dump/connectdb.h` | `0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch` | Avoids pg_dump LTO symbol collisions. | -| `src/bin/pg_dump/parallel.c` | `0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch` | Stubs unavailable pg_dump parallel fork behavior under WASIX. | -| `src/bin/pg_dump/pg_dumpall.c` | `0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch` | Avoids pg_dump LTO symbol collisions. | -| `src/bin/psql/startup.c` | `0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch` | Keeps captured Oliphaunt psql invocations noninteractive despite WASIX virtual descriptor types. | -| `src/common/file_utils.c` | `0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch`, `0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch` | Keeps real fsync while narrowing unsupported WASIX directory and writeback-hint behavior. | -| `src/common/hashfn.c` | `0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch` | Uses defined unaligned load fast path under WASIX. | -| `src/include/access/xlog.h` | `0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch` | Exposes the embedded idle-boundary checkpoint handoff within PostgreSQL. | -| `src/include/libpq/libpq-be.h` | `0002-oliphaunt-wasix-add-backend-host-io-hooks.patch` | Adds the host I/O callback table to Port only for embedded WASIX. | -| `src/include/port/atomics.h` | `0036-oliphaunt-wasix-specialize-single-backend-atomics.patch` | Selects scalar atomics only for the explicitly single-backend WASIX build. | -| `src/include/port/atomics/arch-wasix-single.h` | `0036-oliphaunt-wasix-specialize-single-backend-atomics.patch` | Preserves PostgreSQL atomic layouts and contracts without guest atomic instructions. | -| `src/include/port/wasix-dl.h` | `0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch`, `0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`, `0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch`, `0006-oliphaunt-wasix-report-copy-protocol-state.patch`, `0009-oliphaunt-wasix-route-process-identity-through-port.patch`, `0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch`, `0012-oliphaunt-wasix-capture-startup-errors.patch`, `0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch`, `0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch`, `0039-oliphaunt-wasix-inline-sigsetjmp.patch`, `0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch` | Defines the embedded WASIX port header, durability default, ABI redirects, and call-site SJLJ contract. | -| `src/include/port/wasix-dl/sys/ipc.h` | `0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch` | Provides the WASIX SysV IPC shim surface. | -| `src/include/port/wasix-dl/sys/shm.h` | `0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch` | Provides the WASIX SysV shared-memory shim surface. | -| `src/include/storage/s_lock.h` | `0035-oliphaunt-wasix-use-single-backend-spinlocks.patch` | Specializes spinlocks only for the enforced single-backend WASIX runtime. | -| `src/interfaces/libpq/fe-connect.c` | `0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch` | Makes libpq socket nonblocking state explicit where WASIX socket creation ignores type flags. | -| `src/makefiles/Makefile.wasix-dl` | `0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch` | Builds side modules and PGXS artifacts for WASIX dynamic linking. | -| `src/makefiles/pgxs.mk` | `0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch`, `0039-oliphaunt-wasix-inline-sigsetjmp.patch` | Installs PGXS extension artifacts for WASIX packaging. | -| `src/port/pg_strong_random.c` | `0037-oliphaunt-wasix-buffer-strong-random.patch` | Uses checked direct WASI entropy reads and batches them only for the single-backend runtime. | -| `src/template/wasix-dl` | `0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch`, `0011-oliphaunt-wasix-prefer-posix-semaphores.patch` | Keeps the WASIX template and atomics invariants source-controlled. | -| `src/test/regress/expected/jsonb.out` | `0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch` | Records fixed, VARIADIC, Param, null, error, and mutable user-cast JSONB constructor semantics. | -| `src/test/regress/sql/jsonb.sql` | `0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch` | Covers fixed, VARIADIC, Param, null, error, and mutable user-cast JSONB constructor semantics. | - -## Audit Checklist - -| Requirement | Owning Patch(es) | Required Evidence | Review Posture | -| --- | --- | --- | --- | -| WASIX dynamic-main build spine is isolated | `0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch` | `PORTNAME), wasix-dl`, `oliphaunt: $(OBJS)` | Build plumbing lands before lifecycle behavior, so linker changes are reviewable alone. | -| Backend protocol I/O is host-owned without touching normal sockets | `0002-oliphaunt-wasix-add-backend-host-io-hooks.patch` | `OliphauntWasmHostIO`, `secure_raw_read`, `secure_raw_write` | Only OLIPHAUNT_WASM_SINGLE_USER installs the callback table. | -| Startup packet parsing remains PostgreSQL-owned | `0003-oliphaunt-wasix-export-startup-packet-parser.patch` | `ProcessStartupPacket`, `OLIPHAUNT_WASM_HOST_EXPORT("ProcessStartupPacket")` | The host can call the parser, but PostgreSQL still validates the startup packet. | -| Host lifecycle exports stay explicit | `0004-oliphaunt-wasix-add-host-lifecycle-exports.patch` | `oliphaunt_wasix_start`, `oliphaunt_wasix_pq_flush`, `oliphaunt_wasix_get_proc_port` | Host-visible entry points are named exports instead of broad syscall remaps. | -| Protocol loop recovery remains at the PostgresMain boundary | `0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch`, `0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch`, `0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch` | `PostgresMainLoopOnce`, `PostgresMainLongJmp`, `send_ready_for_query = true` | The host pumps PostgreSQL one loop at a time and recovery re-enters the upstream exception stack. | -| COPY protocol state is host-observable | `0006-oliphaunt-wasix-report-copy-protocol-state.patch`, `0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch` | `oliphaunt_wasix_protocol_report_copy_response`, `OLIPHAUNT_WASIX_PROTOCOL_COPY_NONE` | COPY state is reported and cleared around PostgreSQL error recovery. | -| PGXS side modules use the WASIX dynamic-link contract | `0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch`, `0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch` | `PGXS`, `WASM_LD ?= $(shell $(CC) -print-prog-name=wasm-ld)` | Extension and backend side-module behavior is source-reviewed with the linker path. | -| Process identity and shared memory stay behind the port header | `0009-oliphaunt-wasix-route-process-identity-through-port.patch`, `0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch`, `0011-oliphaunt-wasix-prefer-posix-semaphores.patch` | `oliphaunt_wasix_geteuid`, `oliphaunt_wasix_shmget`, `PREFERRED_SEMAPHORES=UNNAMED_POSIX` | WASIX platform gaps are explicit port-layer dependencies, not scattered runtime guesses. | -| Tool/runtime platform stubs fail closed | `0021-oliphaunt-wasix-declare-wasix-fork.patch`, `0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch`, `0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch` | `fork_process`, `oliphaunt_wasix_pgdump_fork`, `errno == EISDIR` | Unavailable WASIX behavior is explicit and narrow instead of silently emulated. | -| Controlled initdb collation discovery | `0033-oliphaunt-wasix-control-initdb-collation-discovery.patch` | `OLIPHAUNT_INTERNAL_ICU_READY`, `OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY`, `OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY`, `strcmp`, `pg_collation_actual_version`, `pg_import_system_collations` | Public collation import retains PostgreSQL semantics. Distributed standard seeds suppress OS and ICU discovery; ICU seeds suppress only OS discovery and verify ICU readiness for initdb's unicode-version probe. | -| COPY streaming keeps an explicit hybrid transport ABI | `0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch` | `oliphaunt_wasix_set_protocol_transport(int mode)`, `oliphaunt_wasix_protocol_stream_active(void)` | Only COPY switches an embedded host from buffered protocol I/O to its attached stream; Rust and TypeScript provide language-native bounded stream adapters over the same guest ABI. | -| Single-backend WASIX spinlocks preserve their ABI and scope | `0035-oliphaunt-wasix-use-single-backend-spinlocks.patch` | `defined(__wasi__) && defined(OLIPHAUNT_WASM_SINGLE_USER)`, `OLIPHAUNT_WASM_SINGLE_BACKEND_ATOMICS`, `typedef int slock_t;`, `oliphaunt_wasix_single_user_tas` | The shared guest lets Rust AOT and every TypeScript placement replace atomic exchange; all concurrent PostgreSQL builds retain upstream spinlocks. | -| Single-backend WASIX atomics preserve ABI and operation contracts | `0036-oliphaunt-wasix-specialize-single-backend-atomics.patch` | `override CPPFLAGS += -DOLIPHAUNT_WASM_SINGLE_BACKEND_ATOMICS`, `postmaster mode is unavailable in the single-backend WASIX runtime`, `PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY`, `volatile uint64 value pg_attribute_aligned(8)`, `*expected = current` | Shared guest backend objects use scalar operations for Rust and TypeScript hosts; frontends, extensions, and every concurrent PostgreSQL build retain normal atomics. | -| WASIX strong randomness avoids descriptor pressure and forked state | `0037-oliphaunt-wasix-buffer-strong-random.patch` | `#elif defined(__wasi__)`, `wasix_strong_random_fill(void *buf, size_t len)`, `#if defined(OLIPHAUNT_WASM_SINGLE_USER)`, `wasix_strong_random_fill(wasix_strong_random_pool`, `if (errno == EINTR)`, `wasix_strong_random_used += copy_len`, `No guest-side state in a process that may fork.` | Every WASIX backend bypasses the virtual random device. The embedded backend amortizes host calls, while fork-capable backends keep no duplicable random state. | -| Unsupported writeback hints stay separate from real durability | `0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch` | `#if defined(OLIPHAUNT_WASM_SINGLE_USER)`, `Actual fsync/fdatasync durability remains enabled.`, `#elif defined(HAVE_SYNC_FILE_RANGE)` | The single-backend guest omits only pg_flush_data hints that WASIX rejects on read-only descriptors; PostgreSQL fsync and fdatasync remain active. | -| WASIX WAL durability exposes only explicit sync operations | `0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch` | `PLATFORM_DEFAULT_WAL_SYNC_METHOD`, `WAL_SYNC_METHOD_FDATASYNC`, `OLIPHAUNT_WASM_EXPLICIT_WAL_SYNC_ONLY`, `explicit fd_datasync operation` | The shared PostgreSQL port selects fdatasync and removes open_sync/open_datasync from the WASIX GUC choices because Wasmer does not honor their open flags. | -| Fixed JSONB constructor metadata preserves PostgreSQL semantics | `0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch` | `JsonbBuildObjectState`, `get_fn_expr_variadic`, `FirstNormalObjectId`, `jsonb_build_object_cache_drop_cast` | Ordinary calls reuse immutable expression metadata; explicit VARIADIC arrays keep the generic path and user-defined types are recategorized so cast DDL remains visible. | -| PostgreSQL side modules own their SJLJ catch frames | `0039-oliphaunt-wasix-inline-sigsetjmp.patch` | `-DOLIPHAUNT_WASM_SIDE_MODULE`, `WebAssembly SJLJ requires setjmp to be visible at the protected call site.`, `defined(__wasm_exception_handling__) && defined(OLIPHAUNT_WASM_SIDE_MODULE)`, `#undef sigsetjmp`, `#define sigsetjmp(env, savesigs) ((void) (savesigs), setjmp(env))` | PG_TRY expands to a compiler-recognized setjmp in every PostgreSQL side module, so nested errors unwind to the live module-local handler. | -| Standalone WASIX libpq sockets are actually nonblocking | `0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch` | `defined(SOCK_NONBLOCK) && !defined(__wasi__)`, `!defined(SOCK_NONBLOCK) || defined(__wasi__)`, `pg_set_noblock(conn->sock)` | WASIX uses PostgreSQL's existing fcntl fallback because Wasmer ignores socket type flags; native platforms retain upstream atomic socket creation. | -| Captured Oliphaunt psql scripts remain noninteractive | `0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch` | `OLIPHAUNT_PSQL_NONINTERACTIVE`, `strcmp(oliphaunt_noninteractive, "1") == 0`, `!isatty(fileno(stdin)) || !isatty(fileno(stdout))` | Only the private exact-value marker overrides virtual terminal detection; ordinary WASIX psql retains upstream isatty semantics. | - -## PostgreSQL Patch Symbols - -- `OLIPHAUNT_WASM_EXIT_ALIVE` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`, `0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch`) -- `OLIPHAUNT_WASM_EXPLICIT_WAL_SYNC_ONLY` (`0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch`) -- `OLIPHAUNT_WASM_HOST_EXPORT` (`0003-oliphaunt-wasix-export-startup-packet-parser.patch`, `0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`, `0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch`) -- `OLIPHAUNT_WASM_SIDE_MODULE` (`0039-oliphaunt-wasix-inline-sigsetjmp.patch`) -- `OLIPHAUNT_WASM_SINGLE_BACKEND_ATOMICS` (`0035-oliphaunt-wasix-use-single-backend-spinlocks.patch`, `0036-oliphaunt-wasix-specialize-single-backend-atomics.patch`) -- `OLIPHAUNT_WASM_SINGLE_USER` (`0002-oliphaunt-wasix-add-backend-host-io-hooks.patch`, `0003-oliphaunt-wasix-export-startup-packet-parser.patch`, `0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`, `0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch`, `0006-oliphaunt-wasix-report-copy-protocol-state.patch`, `0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch`, `0012-oliphaunt-wasix-capture-startup-errors.patch`, `0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch`, `0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch`, `0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch`, `0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch`, `0021-oliphaunt-wasix-declare-wasix-fork.patch`, `0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch`, `0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch`, `0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch`, `0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch`, `0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch`, `0031-oliphaunt-wasix-skip-activity-id-reporting.patch`, `0035-oliphaunt-wasix-use-single-backend-spinlocks.patch`, `0036-oliphaunt-wasix-specialize-single-backend-atomics.patch`, `0037-oliphaunt-wasix-buffer-strong-random.patch`, `0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch`, `0039-oliphaunt-wasix-inline-sigsetjmp.patch`) -- `PostgresMainLongJmp` (`0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch`) -- `PostgresMainLoopOnce` (`0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch`) -- `ProcessStartupPacket` (`0003-oliphaunt-wasix-export-startup-packet-parser.patch`) -- `oliphaunt_wasix_begin_startup_error_capture` (`0012-oliphaunt-wasix-capture-startup-errors.patch`) -- `oliphaunt_wasix_checkpoint_deferred` (`0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch`) -- `oliphaunt_wasix_end_startup_error_capture` (`0012-oliphaunt-wasix-capture-startup-errors.patch`) -- `oliphaunt_wasix_get_proc_port` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`) -- `oliphaunt_wasix_getegid` (`0009-oliphaunt-wasix-route-process-identity-through-port.patch`) -- `oliphaunt_wasix_geteuid` (`0009-oliphaunt-wasix-route-process-identity-through-port.patch`) -- `oliphaunt_wasix_getgid` (`0009-oliphaunt-wasix-route-process-identity-through-port.patch`) -- `oliphaunt_wasix_getpwuid` (`0009-oliphaunt-wasix-route-process-identity-through-port.patch`) -- `oliphaunt_wasix_getpwuid_r` (`0009-oliphaunt-wasix-route-process-identity-through-port.patch`) -- `oliphaunt_wasix_getuid` (`0009-oliphaunt-wasix-route-process-identity-through-port.patch`) -- `oliphaunt_wasix_hash_load32` (`0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch`) -- `oliphaunt_wasix_host_read` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`) -- `oliphaunt_wasix_host_write` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`) -- `oliphaunt_wasix_init_protocol_port` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`, `0012-oliphaunt-wasix-capture-startup-errors.patch`) -- `oliphaunt_wasix_io` (`0002-oliphaunt-wasix-add-backend-host-io-hooks.patch`, `0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`) -- `oliphaunt_wasix_pgdump_fork` (`0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch`) -- `oliphaunt_wasix_pq_flush` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`) -- `oliphaunt_wasix_process_startup_options` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`) -- `oliphaunt_wasix_protocol_io` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`) -- `oliphaunt_wasix_protocol_report_copy_response` (`0006-oliphaunt-wasix-report-copy-protocol-state.patch`, `0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch`) -- `oliphaunt_wasix_protocol_stream_active` (`0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch`) -- `oliphaunt_wasix_send_conn_data` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`) -- `oliphaunt_wasix_set_protocol_transport` (`0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch`) -- `oliphaunt_wasix_shmat` (`0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch`) -- `oliphaunt_wasix_shmctl` (`0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch`) -- `oliphaunt_wasix_shmdt` (`0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch`) -- `oliphaunt_wasix_shmget` (`0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch`) -- `oliphaunt_wasix_single_user_tas` (`0035-oliphaunt-wasix-use-single-backend-spinlocks.patch`) -- `oliphaunt_wasix_start` (`0004-oliphaunt-wasix-add-host-lifecycle-exports.patch`) -- `oliphaunt_wasix_startup_error_capture_active` (`0012-oliphaunt-wasix-capture-startup-errors.patch`) -- `oliphaunt_wasix_startup_error_saved_dest` (`0012-oliphaunt-wasix-capture-startup-errors.patch`) - -## Experiment Patch Disposition - -| Experiment Patch | Status | WASIX Runtime Decision | Rationale | -| --- | --- | --- | --- | -| `0001-wasix-use-posix-dsm-not-sysv.patch` | `not-carried` | replaced where relevant by 0010 and 0011 | The experiment patch changes full-concurrent PostgreSQL dynamic shared memory selection. The embedded WASIX runtime does not take postmaster DSM as a product constraint; it instead routes SysV shmem through the wasix-dl port header and explicitly selects POSIX semaphores. | -| `0003-wasix-libpq-static-encoding-shim.patch` | `covered-by-build-spine` | covered by the WASIX bridge aliases and standalone pg_dump build path | The released-lane bridge already provides weak pg_char_to_encoding and pg_encoding_to_char aliases for static pg_dump/libpq linkage. No PG18 source patch is needed unless a future configured build proves a tool-specific gap. | -| `0004-wasix-core-execbackend-initdb-runtime.patch` | `not-carried` | full-concurrent runtime blocker patch, not embedded product shape | The patch addresses EXEC_BACKEND, fork/exec, root checks, locale command probing, and directory fsync behavior for proper concurrent PostgreSQL under WASIX. The embedded WASIX runtime avoids the postmaster/fork lifecycle; any tool blocker found later should become a smaller tool-specific patch. | -| `0005-pg-dump-avoid-lto-executequery-collision.patch` | `ported` | ported as 0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch | This is a narrow pg_dump source hygiene patch that supports standalone WASIX tool builds under thin LTO without changing query behavior. | -| `0006-like-literal-substring-fast-path.patch` | `ported-with-tighter-guards` | ported as 0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch | The PG18 patch narrows the experiment shortcut to deterministic, case-sensitive LIKE matching for the simple %literal% shape and rejects escapes, _, inner %, lower/case-insensitive variants, and nondeterministic collations before using memchr/memcmp. | -| `0007-top-xid-current-transaction-fast-path.patch` | `ported` | ported as 0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch | The final PG18 patch keeps the upstream parallel and subtransaction paths and only short-circuits the ordinary top-level case after all alternate current-XID sources are absent. | -| `0008-btree-int4-compare-fast-path.patch` | `ported-with-tighter-guards` | ported as 0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch | The PG18 patch keeps index_getattr(), requires the built-in integer btree family, int4 input type, int4 or InvalidOid subtype, and InvalidOid collation. It does not assume every int4 opclass has the built-in ordering. | -| `0009-btree-delete-stack-state.patch` | `ported-with-single-user-gate` | ported as 0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch | The PG18 patch is restricted to __wasi__ and OLIPHAUNT_WASM_SINGLE_USER. It keeps deletion policy and tableam behavior unchanged while avoiding page-local allocator churn. | -| `0010-btree-bottomup-delete-runtime-toggle.patch` | `rejected-for-default-lane` | diagnostic toggle was tested with Oliphaunt env names but not kept in the patch stack | Disabling bottom-up deletion changes PostgreSQL's index maintenance behavior. A local PG18 WASIX port of the diagnostic hook made the default release-profile 9/10 run much slower before any override was enabled, so it is not a defensible carried patch. | -| `0011-btree-first-int4-compare-fast-path.patch` | `ported-with-tighter-guards` | ported as 0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch | The PG18 patch keeps the direct tuple-data read only for embedded WASIX, leaf pages, one-key non-null non-posting non-pivot tuples, built-in int4 btree family, int4 input type, InvalidOid collation, and non-DESC scan keys. Equal values still fall through to PostgreSQL's existing heap-TID and truncated-key tie-break logic. | -| `0012-hash-bytes-unaligned-load-fast-path.patch` | `ported` | ported as 0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch | The PG18 patch uses memcpy-based little-endian 32-bit loads under __wasi__ only, preserving defined C behavior while giving LLVM a wasm-load lowering opportunity. | - -## Guardrails - -- `source.toml` patch series exactly matches the patch directory. -- Every patch has a deterministic `From: Oliphaunt Maintainers ` header. -- Every patch has a deterministic `Subject: [PATCH] oliphaunt-wasix: ...` header and a rationale before the diff. -- Added PostgreSQL lines are checked for trailing whitespace and space-before-tab indentation. -- Changed upstream files must exactly match the expected touchpoint table above; new upstream touchpoints need an explicit rationale before landing. -- Required audit checks prove their evidence in the named owning patch or patches. -- Experiment patches can only be ported, rejected, or replaced with a recorded WASIX runtime decision and rationale. diff --git a/docs/maintainers/README.md b/docs/maintainers/README.md deleted file mode 100644 index 2a86c54ec..000000000 --- a/docs/maintainers/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Maintainer documentation - -Status: index. Last verified: 2026-08-15. Owner: repository maintainers. - -Executable configuration is authoritative. Documentation explains intent and operation; it must not invent workflow names, package identities, targets, or release state. When prose conflicts with the sources below, fix the prose in the same change. - -| Topic | Maintainer entry point | Executable source | -| --- | --- | --- | -| Release products, versions, tags, and recovery | `release.md` | `release-please-config.json`, `.release-please-manifest.json`, active-product `release.toml`, `tools/release/publication-catalog.mjs`, `.github/scripts/manage-release-drafts.mjs` | -| Registry and GitHub environment setup | `release-setup.md` | `.github/workflows/release.yml`, `tools/release/check_publish_environment.mjs` | -| CI gates and test selection | `testing.md`, `tooling.md` | `.github/workflows/ci.yml`, `tools/graph/ci_plan.mjs`, Moon project files | -| Binary artifacts and WASIX provenance | `assets.md`, `compiler-caching.md` | runtime target metadata, exact producer SHA, runtime/AOT manifests and checksums, `tools/xtask` | -| WASIX host APIs and storage | `wasix-usage.md` | WASIX binding source, host pins/patches, and product Moon tasks | -| WASIX postmaster runtime and carrier | `wasix-postmaster.md` | `src/runtimes/liboliphaunt/wasix-postmaster`, its Moon project, sealed-carrier policy, and release metadata | -| Extension support and packaging | `extension-packaging-policy.md` | extension catalog, global target profiles, native-component contract, release catalog | -| SDK contracts | `sdk-products-policy.md`, `sdk-parity-policy.md`, `sdk-api-surface.md` | SDK manifests, package manifests, generated extension metadata, clean-consumer tests | -| Product, task, qualification, and release boundaries | `../architecture/final-product-source-architecture.md` | Moon graph, release metadata, and workflows | -| Repository layout | `repo-structure.md` | Moon projects and ecosystem manifests | - -The repository-local skills under `.codex/skills/` are the procedural entry -points for agents: - -- `release-oliphaunt` owns release preparation, bootstrap, publish, recovery, - and registry setup; -- `qualify-oliphaunt-change` owns affected local feedback and exact-SHA GitHub - qualification; -- `add-oliphaunt-extension` owns extension catalog, version, target, - carrier, and package changes. - -Those skills route to executable checks and the focused references above; they -do not replace the executable sources of truth. - -`consumer-dx-release-blueprint.md` is archived design history. Files under `docs/internal/` are implementation history, investigations, or evidence snapshots unless a current maintainer document links to a specific section. They are not policy and must not be used to override the executable sources above. - -When changing a workflow or contract: - -1. update the executable source and behavior tests; -2. update the relevant maintainer entry point and its verified date; -3. regenerate derived tables instead of hand-editing them; -4. avoid policy assertions that depend on YAML step order, display text, or helper filenames unless the string itself is an external API. diff --git a/docs/maintainers/development.md b/docs/maintainers/development.md deleted file mode 100644 index 7d311dcce..000000000 --- a/docs/maintainers/development.md +++ /dev/null @@ -1,381 +0,0 @@ -# Maintainer Development Guide - -Status: normative local-development guide. Last verified: 2026-09-03. Owner: repository maintainers. - -This page is maintainer documentation for repository validation, generated -artifacts, and local release metadata checks. It is not end-user product -documentation. - -Bootstrap the pinned local toolchain once: - -```sh -moon run dev-tools:doctor -tools/dev/bootstrap-tools.sh -``` - -For each change, follow `.codex/skills/qualify-oliphaunt-change/SKILL.md`: -inspect Moon affectedness, run focused checks first, and expand only when the -changed contract requires it. A normal affected source feedback pass is: - -```sh -moon query affected --upstream none --downstream direct -moon run :check :compile :format-check :js-format-check :rust-format-check :lint :tools-compile --affected -moon run :test :unit :tools-unit --affected -``` - -Run `moon run ci-workflows:check` for workflow changes and -`tools/dev/bun.sh tools/policy/check-supply-chain.mjs` for dependency or -supply-chain policy changes; neither is an unconditional pre-PR ceremony. - -Tool versions for Moon, Node, pnpm, Bun, and Deno are pinned in `.prototools`. -Bun is required for the TypeScript SDK checks because `@oliphaunt/ts` supports -Bun through the npm artifact; local checks use `tools/dev/bun.sh` when the shell -does not already provide the pinned Bun. Deno is optional for normal local checks -and uses `tools/dev/deno.sh` on demand for Deno npm-package validation. - -Windows native builds obtain WinFlexBison from the exact upstream archive pinned -in `src/sources/toolchains/winflexbison.toml`. The shared native setup verifies -the archive size and digest, safe ZIP layout, complete extracted-tree digest, -and both executable digests before adding the atomic cache payload to `PATH`. -Do not replace this path with a live Chocolatey lookup; Chocolatey is retained -only for Strawberry Perl when the hosted image does not already provide it, and -that fallback must prove the expected executable after every install attempt. - -Tool choices and rejected alternatives are recorded in -[tooling.md](tooling.md). Update that decision record before adding a new -repo-wide tool or hand-rolled release helper. - -Moon is the product graph and affected-task entrypoint. A fresh checkout should -install the pinned proto/Moon toolchain from `.prototools`, then call Moon -directly: - -```sh -moon query projects -moon query affected --upstream none --downstream direct -moon run :coverage --affected -``` - -Use `moon query affected` to inspect affectedness and `moon run ` for -explicit local targets. GitHub CI executes the exact planned target list with -Moon so jobs do not expand into unrelated downstream work. Normal commands use -Moon's own concurrency instead of a forced single-worker debug mode. - -The validation entrypoint is split by maintainer workflow: - -- `moon run liboliphaunt-native:host-smoke`: no-build host C ABI/runtime smoke for the - current native target. It compiles and runs the consumer-style ABI harness and - the full C smoke against the release-runtime artifact for macOS, Linux, or - Windows. `OLIPHAUNT_TRACK_BUILD=never` makes missing or stale artifacts fail - immediately instead of entering any build path; -- `moon run liboliphaunt-native:host-smoke`: release-shaped, no-build host - C ABI/runtime smoke. It depends on the native release-runtime producer and - refuses any implicit rebuild inside the smoke; -- `moon run repo:check`: file hygiene and formatting; -- `moon run liboliphaunt-wasix:assets-verify`: source-controlled asset input verification - plus AOT crate template checks; -- `tools/dev/bun.sh tools/policy/check-rust-lint.mjs`: dependency invariants - and clippy; -- `moon run ci-workflows:check`: workflow syntax and security checks plus the - behavior tests for helpers invoked by Actions; -- `moon run liboliphaunt-wasix:smoke`: hard-requires portable assets plus host AOT, - installs them into ignored paths, and runs the real runtime tests; -- `moon run liboliphaunt-wasix:runtime-portable oliphaunt-wasix-ts:package`, then - `node tools/integration/wasix-ts/smoke-browser.mjs`: local browser proof. It serves - COOP/COEP headers and requires Chrome/Chromium to exercise `pgtap`, recover two - PostgreSQL error paths, return `42`, and exit cleanly. Add `--pg-uuidv7` for the - private native-module canary; -- `moon run integration-examples:check`: Tauri/Rust/frontend example checks; -- `moon run liboliphaunt-native:lint liboliphaunt-native:unit`: cached native - patch-stack and source-level tests without building a runtime; -- `moon run oliphaunt-rust:regression`: native direct, broker, and server - behavior against the current host runtime. Extension behavior remains the - separate `oliphaunt-rust:extension-regression` lane; -- `moon run perf-tools:native-plan`: validates the native benchmark plan without - building or measuring a runtime; -- `pnpm --dir tools/perf/wasix-node bench:streaming`: quick local WASIX - TypeScript transport benchmark. It reuses staged packages and portable assets, - compares the root direct and explicit `/worker` contracts, exercises bounded COPY, - backpressure, event-loop delay, process RSS, the local server, `pg_dump`, and - `psql`, and prints a readable report (`-- --json` prints the complete JSON). - Process RSS deltas are descriptive because the quick run reuses one process. - If inputs are absent, first run - `moon run oliphaunt-wasix-tools-ts:package liboliphaunt-wasix:runtime-portable`; -- `moon run oliphaunt-rust:compile`: static Cargo checks for `oliphaunt` and - `oliphaunt-build`. Artifact-relay build-script behavior is owned by `unit`; - package and native runtime evidence remain separate `package` and `regression` - targets; -- `moon run oliphaunt-rust:unit`: the hosted-equivalent Rust source-test lane. - It runs documentation tests, `oliphaunt-build` tests, and all `oliphaunt` - library, executable, and integration tests. A focused command such as - `cargo test -p oliphaunt --lib` is useful while iterating, but excludes the - executable tests under `src/bin/**` and is not qualification evidence; -- `moon run oliphaunt-rust:package`: creates and inspects the publishable Rust - SDK package only. Run `compile`, `unit`, and `package` together for the compact - pre-push gate; none silently owns the others; -- `moon run sdk-contracts:all`: local aggregate for generated API, SDK registry, - C ABI header-copy, fixture, and native-boundary validation. Hosted CI schedules - those checks independently from their own inputs. Use - product `compile`, `unit`, and `package` targets for behavior and package proof; -- `moon run oliphaunt-swift:compile`: SwiftPM package description and build checks - for the SDK package and repository root package; -- `moon run oliphaunt-swift:smoke`: Swift SDK tests against the current native - host runtime; on macOS it also requires the iOS simulator preflight; -- `moon run oliphaunt-swift:package`: validates the Swift source package - shape without building platform release artifacts; -- `moon run liboliphaunt-native:build-runtime-ios-xcframework`: explicitly builds and - freshness-checks iOS simulator and device `liboliphaunt.dylib` slices from - the same PostgreSQL 18 patch stack, then packages them as - `liboliphaunt.xcframework`; -- `moon run oliphaunt-kotlin:smoke`: builds and freshness-checks the selected - Android ABI's `liboliphaunt.so` artifact, then runs the Android SDK smoke; -- `moon run oliphaunt-kotlin:check`: Kotlin formatting, lint, common/JVM and - Android compilation, and Android-only Maven publication-shape checks. Unit - tests remain in `oliphaunt-kotlin:unit`; -- `moon run oliphaunt-react-native:smoke-android`: Android React Native - installed-app harness over the Expo development-client sample; -- `moon run oliphaunt-react-native:smoke-ios`: iOS React Native - installed-app harness over the Expo development-client sample; -- `moon run oliphaunt-react-native:compile`: React Native TypeScript build and - typecheck, Codegen, and native source-contract checks. Package-shape work is - owned by `oliphaunt-react-native:package`; -- `moon run oliphaunt-react-native:smoke`: aggregate local Expo - development-client installed-app lane. It runs both platform-specific smokes - against the packed SDK and real native artifacts; -- `pnpm --dir examples/react-native-expo run smoke:android`: real Android Expo - development-client smoke for the installed React Native package. It reuses - current native artifacts, generates the ignored Expo `android/` project only - when missing, packages `liboliphaunt.so` plus runtime/cluster-seed resources, starts - Metro when needed, installs the app, and waits for - `OLIPHAUNT_EXPO_SMOKE_PASS`; -- `pnpm --dir examples/react-native-expo run smoke:ios`: real iOS Expo - development-client build/smoke harness for the installed React Native package. - For simulator builds it produces or reuses the current iOS simulator - `liboliphaunt.dylib` automatically when no explicit artifact override is set, - packages the same runtime/cluster-seed resources, patches only the ignored - generated `ios/` Podfile for local Swift pods, rejects macOS dylibs, and can - run in `OLIPHAUNT_EXPO_IOS_BUILD_ONLY=1` mode when CoreSimulator is - unavailable; -- `tools/policy/check-crate-package.sh`: package all published crates and enforce - crates.io size limits; -- `tools/dev/bun.sh tools/policy/check-feature-powerset.mjs`: cargo-hack - feature combination checks; -- `tools/dev/bun.sh tools/policy/check-semver.mjs`: cargo-semver-checks public - API compatibility; -- `tools/dev/bun.sh tools/policy/check-supply-chain.mjs`: cargo-deny dependency - policy checks; -- `moon run :check :compile :format-check :js-format-check :rust-format-check :lint :tools-compile && moon run :test :unit :tools-unit && moon run :package && moon run :coverage`: - explicit full local parity lane, including measured coverage; -- `moon run :check :compile :format-check :js-format-check :rust-format-check :lint :tools-compile && moon run :test :unit :tools-unit && moon run :smoke`: full source/runtime lane for repo, lint, source - tests, and examples; -- `moon run :regression`: broader SQL, protocol, extension, and runtime regression suites; -- `moon run release-tools:check`: the canonical full local release-policy gate. - The direct equivalent is - `tools/dev/bun.sh tools/release/release-check.mjs`. This release-owned - metadata and mutation gate does not replace affected product `compile`, `unit`, - or `package` tasks; -- `tools/dev/bun.sh tools/release/release-metadata-check.mjs`: internal - protected-workflow replay after a generated release commit has passed its - structured verifier or after the exact hosted `Qualified` record has been - reverified against a clean checkout. It is not a replacement for the full - local gate. Candidate artifact dry-runs run only through the protected GitHub - `Release` workflow after exact-SHA qualification. - -Moon caches deterministic task results when their declared source inputs and -task dependencies have not changed. Local `:smoke` targets use `cache: local`, -so repeated `moon run :smoke` runs can return a cached result for the same source -graph. Use `moon run :smoke --cache off` when you need a live -device, simulator, or runtime probe regardless of the cache. Generated report -aggregates, such as `repo:coverage`, depend on upstream task outputs with Moon -2.3 `cacheStrategy: outputs`, so downstream cache invalidation follows the -artifact contract instead of every private upstream source edit. - -Kotlin and React Native Android SDK validation uses Gradle's configuration -cache by default so repeated local runs do not reconfigure the same Android/KMP -graphs. Set `OLIPHAUNT_GRADLE_CONFIGURATION_CACHE=0` only when diagnosing -Gradle configuration-cache behavior itself. - -The hook split is intentionally small: - -- pre-commit: file hygiene and formatting -- release readiness: `tools/dev/bun.sh tools/policy/check-rust-lint.mjs` and - `moon run liboliphaunt-wasix:assets-verify` -- CI/release: path-aware combinations of the same validation modes, workflow - linting, feature powerset, public API compatibility, crate packaging, - native AOT runtime tests, frozen Cargo publication dry-runs, and supply-chain - policy - -Install local hooks and pinned CLI tools when needed. Maintainer bootstrap -release assets are an explicit source contract in -`src/sources/toolchains/maintainer-tools.toml`: every supported Linux and macOS -host has an exact URL, archive SHA-256, extracted-binary SHA-256, archive -layout, and size bound. The installer accepts only bounded HTTPS downloads, -checks the complete archive before extraction, rejects unexpected or non-file -members, and promotes a staged binary and its identity marker atomically. A -matching version string alone is not a cache hit. - -`cargo-binstall` may fall back only after a transport failure or an unsupported -binary host. That fallback is an isolated, exact-version `cargo install ---locked` build and is promoted through the same rollback-safe path; it never -reuses a partial download. `actionlint` has no source fallback because the -repository does not pin a Go toolchain. Update the manifest and the fault tests -together when either maintainer tool is upgraded. - -```sh -tools/dev/bootstrap-tools.sh -tools/dev/bun.sh tools/dev/install-hooks.mjs -``` - -`src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/runtime_smoke.rs` starts the real WASIX backend and -is intentionally slower than the protocol unit tests. - -## Maintenance Utilities - -The repository includes maintenance commands: - -- `oliphaunt-wasix-dump` is the logical dump CLI entry point. Its typed - `--database`, `--username`, and repeatable `--extension` options configure - the embedded server; arguments after `--` shape `pg_dump` output. -- `oliphaunt-wasix-proxy` exposes a local PostgreSQL socket backed by the embedded - runtime. -- `xtask assets cluster-seeds` generates the architecture-independent PGDATA - seeds from the split WASIX `initdb` module. Portable WASIX, cluster seeds, - and native AOT payloads remain generated-only. - -Asset and source checks: - -```sh -cargo run -p xtask -- assets verify-committed -cargo run -p xtask -- assets fetch -cargo run -p xtask -- assets check --strict-local -cargo run -p xtask -- assets check --strict-generated -cargo run -p xtask --features cluster-seed-runner -- assets cluster-seeds -cargo run -p xtask -- assets source-spine --check-patch-applies -cargo run -p xtask -- assets audit-upstream --strict -moon run repo:package -``` - -## Local Runtime Development - -Local development has three supported modes. - -Fast contributor mode does not require Docker, upstream source checkouts, or -generated native AOT payloads. Use it for ordinary Rust, docs, tests, examples, -and workflow edits: - -```sh -moon run :check :compile :format-check :js-format-check :rust-format-check :lint :tools-compile --affected && moon run :test :unit :tools-unit --affected -``` - -For native liboliphaunt work, run only the product boundary you changed: - -```sh -moon run liboliphaunt-native:host-smoke -moon run oliphaunt-rust:regression -moon run extension-artifacts-native:build-target oliphaunt-rust:extension-regression -``` - -`liboliphaunt-native:host-smoke` proves the C ABI. The Rust regression uses the basic native -runtime and runs SQL/protocol regression across direct, broker, and server mode. -`moon run oliphaunt-rust:extension-regression` is the separate -extension-artifact lane; it depends on `extension-artifacts-native:build-target` and is -intentionally not part of normal PR CI. The host artifact builder uses -the build script's no-build freshness probe before running the matrix, which avoids both -unnecessary rebuilds and the failure mode where a core-only runtime is -accidentally treated as extension ready. `sdks` validates SDK ownership/parity, -then runs the Rust, Swift, Kotlin, and React Native package checks. See -[`docs/maintainers/sdk-parity-policy.md`](../../docs/maintainers/sdk-parity-policy.md) for the SDK ownership contract. `full` enables -native extension artifacts and the extension matrix in addition to the SDK -checks. Use -`OLIPHAUNT_TRACK_BUILD=never` when you want to prove the harness is not -rebuilding anything. - -Host-platform artifact mode is for runtime work on the current machine. It -builds or packages only the current host target, leaves all generated payloads -in ignored paths, and then runs the real runtime tests: - -```sh -host="$(rustc -vV | awk '/^host:/{print $2}')" -cargo run -p xtask -- assets fetch -cargo run -p xtask --features aot-serializer -- assets build-host -moon run liboliphaunt-wasix:smoke -``` - -Local AOT generation requires the Wasmer LLVM 22.1.x build for the -maintainer-only serializer. That build includes the LLVM target set Wasmer's -LLVM backend expects, including LoongArch and WebAssembly. Set -`LLVM_SYS_221_PREFIX` to an extracted -`wasmerio/llvm-custom-builds` 22.x archive, or use downloaded-artifact mode to -avoid local LLVM setup. - -When the portable WASIX assets are already current and only the host AOT crate -needs to be refreshed, skip the source/Docker build and generate host AOT from -the existing generated portable assets: - -```sh -host="$(rustc -vV | awk '/^host:/{print $2}')" -cargo run -p xtask -- assets aot --target-triple "$host" -cargo run -p xtask -- assets package-aot --target-triple "$host" -moon run liboliphaunt-wasix:smoke -``` - -Downloaded-artifact mode is the intended way to test a CI-produced runtime -locally without rebuilding Postgres/WASIX. Select either the exact successful -`CI` workflow run or the full 40-character commit SHA and install the host -target payloads into the same ignored generated locations used by the local -build path: - -```sh -host="$(rustc -vV | awk '/^host:/{print $2}')" -cargo run -p xtask -- assets download --run-id --target-triple "$host" -# Or select the successful CI run for one exact commit: -cargo run -p xtask -- assets download --sha --target-triple "$host" -moon run liboliphaunt-wasix:smoke -``` - -Workflow-run downloads require the authenticated GitHub CLI. The downloader -accepts only the requested run or exact SHA and validates the packaged runtime -and AOT manifests and checksums before installation. - -Released artifact bundles can be installed without the GitHub CLI because they -are public GitHub release assets: - -```sh -host="$(rustc -vV | awk '/^host:/{print $2}')" -cargo run -p xtask -- assets download --release --target-triple "$host" -moon run liboliphaunt-wasix:smoke -``` - -Release downloads validate the published checksum manifest, archive checksums, -and packaged runtime/AOT manifests before installation. - -Release validation can download every supported target from the exact `CI` -workflow SHA: - -```sh -cargo run -p xtask -- assets download --sha --all-targets -tools/dev/bun.sh tools/release/release-check.mjs -``` - -Developers should not be expected to build every target locally. Local runtime -work validates the host target; the `CI` workflow's WASIX runtime/AOT lane is -the authority for the full macOS, Linux, and Windows AOT matrix. - -Contributors do not need upstream source checkouts for normal Rust, docs, -examples, or package validation. Maintainers fetch sources only when rebuilding -the portable WASIX runtime, extensions, `initdb`, `pg_dump`, `psql`, or the generated -cluster seed. Portable WASIX artifacts, generated cluster seeds, and -native AOT artifacts are generated under `target/oliphaunt-wasix/**` locally or by -CI; they are not committed to git. - -The `CI` pull-request job uses Moon affectedness over `postgres18`, `third-party`, -`source-toolchains`, `extensions`, and the WASIX artifact inputs, plus a small producer path -allowlist, to decide whether the expensive asset build is required. Non-asset -PRs become an explicit no-op after source-controlled input checks. -Asset-producing PRs verify source pins, extension catalog metadata, generated -metadata policy, and then run the full portable/AOT producer workflow before -merge. `main` and explicit maintainer dispatches remain trusted producer lanes -for release artifacts. - -Release process details are tracked in [release.md](release.md). Historical -progress notes under `docs/internal/` are archived and non-normative; they are -not the current backlog or release checklist. diff --git a/docs/maintainers/performance-evidence.md b/docs/maintainers/performance-evidence.md deleted file mode 100644 index 417f84bfd..000000000 --- a/docs/maintainers/performance-evidence.md +++ /dev/null @@ -1,464 +0,0 @@ -# Performance - -`oliphaunt-wasix` is built to stay close to native Postgres while keeping the -database embedded in the Rust process. - -This page tracks the repo benchmark matrix. The main comparison uses SQLx on -each wire-protocol path: - -- native Postgres with SQLx; -- `oliphaunt-wasix + SQLx`; -- vanilla `@electric/wasm` persisted with NodeFS and reached through - `@electric/wasm-socket`, then measured with SQLx. - -The native `oliphaunt` track has its own matrix for PostgreSQL 18 direct, -broker, and server modes. That matrix is the release gate for the native SDK and -must be used before claiming native parity: - -```sh -tools/perf/matrix/run_native_oliphaunt_matrix.sh -``` - -Native server mode keeps the public PostgreSQL-compatible TCP connection string, -but SDK-owned protocol traffic uses Unix-domain sockets on Unix by default. Set -`OLIPHAUNT_SERVER_SDK_TRANSPORT=tcp` only when explicitly diagnosing TCP -transport behavior. - -It records p50/p90/p95/p99 latency, suite totals, throughput, `/usr/bin/time` -CPU/RSS/footprint metrics, child-process RSS for broker/server modes, artifact -sizes, native PostgreSQL controls, a SQLite embedded speed control, -prepared-update rows, and backup/restore timings for native PostgreSQL, SQLite, -NativeDirect, and NativeBroker. NativeServer participates only in workloads its -public server API supports. The speed and backup/restore -sections report p50 elapsed time, p90 elapsed time, p95 elapsed time, median -throughput, tail throughput, p99 tail latency, native-PostgreSQL p90 ratios, -and command-level CPU/RSS/footprint p90/p99 so transport and persistence -regressions are visible without opening the raw JSON files. - -When NativeDirect misses a native PostgreSQL gate, the generated report includes -a `Native Direct Regression Diagnostics` section with the missed gate, the -matching focused matrix command, and a repeated speed-case diagnostic wrapper -that runs NativeDirect as one fresh process per case/repeat before comparing it -with the native PostgreSQL control. The lower-level `perf diagnose-speed-cases` -commands remain available for one-off inspection. - -The native matrix is native-only by default. The script builds `xtask` with -the `perf` feature explicitly enabled and builds the native broker helper: - -```sh -tools/perf/matrix/run_native_oliphaunt_matrix.sh \ - --rtt-repeats 1 \ - --speed-repeats 1 -``` - -For an even faster no-build sanity check of the benchmark plan: - -```sh -tools/perf/matrix/run_native_oliphaunt_matrix.sh --quick --plan-only -tools/perf/matrix/run_native_oliphaunt_matrix.sh \ - --quick --plan-only --engines broker --suites streaming -moon run perf-tools:native-plan -``` - -Use `--engines direct|broker|server|all` and -`--suites rtt|speed|streaming|prepared|backup|all` for focused diagnostic runs. -Focused runs still include the relevant native PostgreSQL control for the -selected suite, but the generated report marks them as partial coverage. They -are not release evidence. - -Use repeated `--startup-guc name=value` flags for native footprint experiments. -The same explicit settings are passed to NativeDirect, NativeBroker, -NativeServer, and the native PostgreSQL control, and the -JSON/report/provenance files record the overrides: - -```sh -tools/perf/matrix/run_native_oliphaunt_matrix.sh \ - --quick \ - --startup-guc shared_buffers=32MB \ - --startup-guc wal_buffers=-1 -``` - -The PostgreSQL 18 mobile cluster seeds use standard 16MB WAL segments, so -`min_wal_size=8MB` and `min_wal_size=16MB` are invalid. WAL segment size is a -physical cluster property, not a startup GUC; the performance harness does not -regenerate or relabel release seeds. Mobile sweeps therefore select valid -startup settings only: - -```sh -tools/perf/matrix/run_mobile_footprint_matrix.sh --quick --platform android \ - --min-wal-size 32MB,80MB \ - --max-wal-size 32MB,64MB \ - --crash-recovery off -``` - -The benchmark report captures PostgreSQL's effective read-only -`wal_segment_size` setting alongside the startup GUCs. - -For Android/iOS device sweeps, use the Expo dev-client matrix wrapper. It emits -or runs explicit shared-buffer, WAL-buffer, WAL-minimum, and WAL-maximum -combinations against the installed React Native app. -Non-plan runs store every case in its own scratch directory and write -`summary.json` plus `summary.md` under `target/perf/mobile-footprint-/` -with open time, typed and parameterized query p50/p90/p95/p99, set-based insert throughput, background -checkpoint latency, Android PSS/RSS, and iOS resident memory where the platform -harness can collect them. Package footprint is reported for the built Android -APK or iOS app bundle and the local React Native package tarball used by the -dev-client app. Benchmark reports also include a same-device Expo SQLite WAL -baseline, including simple-query, parameterized-query, indexed lookup, indexed -aggregate, update, checkpoint, large-result, and insert-throughput measurements -using an explicitly SQLite-specific durability profile, so mobile SQLite -comparison is device evidence instead of inferred from the host matrix. Each -native benchmark report also -records effective PostgreSQL settings through `current_setting(..., true)`, and -the matrix summary surfaces the core effective GUCs next to the intended startup -overrides. Treat measurements without those effective settings as incomplete -tuning evidence. Process memory is harness evidence rather than SDK API: -Android uses `adb`/`dumpsys meminfo`, while iOS uses the installed-app runner's -process report. Missing process-memory data remains blank rather than recording -a false zero. By default every matrix case also runs the installed-app -process-death recovery lane. The app verifies effective PostgreSQL `fsync`, -`full_page_writes`, and `synchronous_commit` are `on` before producing crash -evidence. -Use `--crash-recovery off` only for a diagnostic latency-only sweep: - -```sh -tools/perf/matrix/run_mobile_footprint_matrix.sh --plan-only --platform android -tools/perf/matrix/run_mobile_footprint_matrix.sh --quick --platform android \ - --shared-buffers 8MB,32MB,128MB \ - --wal-buffers -1 \ - --min-wal-size 32MB \ - --max-wal-size 64MB \ - --crash-recovery off -tools/perf/matrix/run_mobile_footprint_matrix.sh --quick --platform ios --crash-recovery off -tools/perf/matrix/run_mobile_footprint_matrix.sh --platform ios -``` - -`--quick` keeps the same GUC axes but passes -`OLIPHAUNT_EXPO_MOBILE_BENCHMARK_PRESET=quick` into the Expo dev-client app so -the installed-app workload uses fewer warmup, latency, checkpoint, and insert -iterations. Use it for harness validation and emulator/simulator -sanity checks; use the default full preset for reportable numbers. -Use `--shared-buffers`, `--wal-buffers`, `--min-wal-size`, and `--max-wal-size` -to run a small slice with the same -installed-app harness before committing to the full device matrix. - -Current diagnostic Android emulator slice: - -- run id: `android-guc-slice-20260524T1750` -- report: `target/perf/mobile-footprint-android-guc-slice-20260524T1750/summary.md` -- platform: Android API 34 emulator through the Expo dev-client harness -- benchmark preset: `quick` -- fixed settings: `wal_buffers=-1`, `min_wal_size=32MB`, - `max_wal_size=64MB` - -| shared_buffers | Android PSS | Android RSS | Open ms | Param p90 ms | Insert rows/s | Checkpoint p90 ms | -| ---: | ---: | ---: | ---: | ---: | ---: | ---: | -| 8MB | 253.7 MB | 383.1 MB | 7695.68 | 39.38 | 57 | 1457.90 | -| 32MB | 256.6 MB | 386.3 MB | 6347.87 | 41.92 | 77 | 1480.58 | - -This is diagnostic emulator evidence, not a release claim. It does show that -lowering `shared_buffers` from 32MB to 8MB does not currently buy a proportional -resident-memory reduction in the React Native app process; fixed mappings, -runtime/cluster-seed assets, extension registry, or other PostgreSQL/React Native -process costs are still dominating the measured PSS/RSS. Keep the full device -matrix and source/build-cut investigations separate from this quick slice. - -Latest Android emulator retry caveat: - -- run id: `android-emulator-shared-minwal-slice-20260525T0325` -- report: - `target/perf/mobile-footprint-android-emulator-shared-minwal-slice-20260525T0325/summary.md` -- result: one quick `shared_buffers=8MB,min_wal_size=8MB` case passed with - Android harness process evidence; the matching `min_wal_size=32MB` - case did not produce benchmark evidence. -- passed case: `271,565 KB` app PSS, `396,424 KB` host RSS, `41,415.89 ms` - open, `286.18 ms` parameterized p90, `7.98 rows/s` insert throughput, - and `126.77 ms` checkpoint p90. - -A focused `min_wal_size=32MB` retry after adding a bounded -`Linking.getInitialURL()` path in the Expo example still failed before the -React Native app attached: Android killed the app process for `failed to attach` -/ `start timeout`, and Metro never served a bundle. Treat this as local AVD -instability, not PostgreSQL tuning evidence. Physical Android device evidence is -still required before Android defaults can be selected. - -It is simulator evidence only. Physical iOS benchmark runs additionally require -a valid Apple Development signing identity or a working Xcode account that can -create one through automatic provisioning. - -Current iPhoneOS build-only device-artifact evidence: - -- scratch: `target/oliphaunt-expo-ios-device-buildonly-20260524T1615` -- mode: `OLIPHAUNT_EXPO_IOS_SDK=iphoneos`, - `OLIPHAUNT_EXPO_IOS_BUILD_ONLY=1`, - `OLIPHAUNT_EXPO_IOS_CODE_SIGNING_ALLOWED=NO` -- result: Xcode `Debug-iphoneos` build succeeded using the local - `liboliphaunt.xcframework` iPhoneOS slice -- bundled Oliphaunt resources: 1,874 files, 35,800,256 bytes -- iOS app bundle: 184,075,464 bytes -- packed React Native package: 14,015,379 bytes - -This is compile/package evidence only. It proves the iPhoneOS artifact, -resource bundle, React Native local iOS pod integration, and New Architecture -generated code compile without relying on a runnable device. It is not runtime -performance evidence; physical install/launch still requires Developer Mode, -Developer Disk Image services, and valid signing on the paired phone. - -Current physical iPhone install/runtime/benchmark evidence: - -- scratch: `target/oliphaunt-expo-ios-device-crash-safe-smallwal-20260524T174847` -- runtime smoke scratch: - `target/oliphaunt-expo-ios-device-smoke-autolifecycle-20260524T0018` -- latest reuse-installed runtime smoke: - `target/oliphaunt-expo-ios-smoke/reports/smoke-report.json` -- quick footprint matrix scratch: - `target/perf/mobile-footprint-ios-physical-memory-retry-20260525T0230` -- full candidate footprint matrix scratch: - `target/perf/mobile-footprint-ios-physical-full-candidate-20260525T0200` -- device: iPhone 14 Pro, UDID `7C01EC26-8B01-56E6-872D-82BB72421567` -- mode: `OLIPHAUNT_EXPO_IOS_SDK=iphoneos` -- startup GUCs: - `shared_buffers=32MB,wal_buffers=-1,min_wal_size=8MB,max_wal_size=32MB` -- result: Xcode `Debug-iphoneos` build succeeded and `devicectl device install - app` installed bundle ID `dev.oliphaunt.reactnative.example` -- bundled Oliphaunt resources: 1,871 files, 35,799,044 bytes -- selected extension: `vector`, 38 files, 63,478 bytes -- iOS app bundle: 183,420,535 bytes -- packed React Native package: 14,008,184 bytes -- crash recovery: passed on the physical iPhone with app-private - explicit React Native `applicationData` storage; verify reopened the recovered database in - `146.99 ms` and read back `crash-ios-12452656` -- smoke/runtime: passed on the physical iPhone after the harness automatically - backgrounded the app through Safari and foregrounded it again. The smoke - covered `SELECT 1`, parameterized query, DDL, DDL event triggers, pgvector, - extension selection, transaction/savepoint recovery, constraint error - recovery, JSONB/arrays, recursive CTE/window functions, raw protocol - streaming, query cancellation/recovery, checkpoint/physical backup, and - background/foreground resume SQL. -- smoke timings: open `1360.33 ms`, select p50/p90/p99 - `0.23/0.25/0.57 ms`, backup payload `33,425,920` bytes, lifecycle SQL - after foreground `27.43 ms` -- latest reuse-installed smoke after the bounded launch-URL change opened in - `1357.67 ms`, reported select p90 `0.245 ms`, passed the - `active -> inactive -> background -> active` lifecycle SQL check. -- the historical full candidate predates the explicit-GUC-only report shape; - rerun it before using its performance or process-memory measurements as - current evidence. - -Current physical iPhone shared-buffer/min-WAL tuning slice: - -- run id: `ios-physical-shared-minwal-slice-20260525T0300` -- report: - `target/perf/mobile-footprint-ios-physical-shared-minwal-slice-20260525T0300/summary.md` -- device: same iPhone 14 Pro physical dev-client install -- platform: iPhoneOS through the Expo dev-client harness -- benchmark preset: `quick` -- fixed settings: `wal_buffers=-1`, `max_wal_size=32MB`, process-death recovery off -- varied settings: `shared_buffers=8/16/32/64/128MB` -- result: historical cases passed. Rerun the slice with qualified release seeds - before making a current memory claim. - -The iPhoneOS `liboliphaunt.xcframework` used for this run also has a stricter -artifact gate: the device and simulator slices are rejected if they import -mobile-forbidden SysV/POSIX shared-memory or semaphore APIs (`shm*`, -`shm_open`, or external `sem*`). This was added after a real-device `SIGSYS` -crash report showed PostgreSQL reaching `shmget` during embedded startup. - -The wrapper skips `min_wal_size` values below two fixed 16MB WAL segments, so -8MB and 16MB are negative-only cases. Pass `--include-invalid-wal-min` only for -negative validation. The wrapper also skips -impossible WAL ranges such as `max_wal_size=32MB` with `min_wal_size=80MB`, -while preserving a `max_wal_size=default` baseline for the current -throughput-sized WAL ceiling. - -Crash recovery after process death is measured by the installed-app crash lanes, -which write to a persistent app-private root, terminate the app without closing -the direct-mode database, relaunch, and verify committed data through -PostgreSQL recovery. The app accepts crash evidence only after observing -PostgreSQL `fsync=on`, `full_page_writes=on`, and `synchronous_commit=on`: - -```sh -pnpm --dir examples/react-native-expo run crash:android -pnpm --dir examples/react-native-expo run crash:ios -``` - -Use the default script invocation for release evidence. Native release gates are -read against native PostgreSQL controls. The matrix plan labels runs with -`releaseEvidence`, `partialReport`, and `diagnosticRun` before any expensive -work starts. Default runs must meet the current release minimums: 100 RTT -samples, 10 fresh-process RTT repeats, 25,000 prepared-update rows, 10 -fresh-process prepared repeats, 20 fresh-process speed repeats, and 10 -fresh-process backup/restore repeats for direct and broker alongside the -supported direct/broker/server RTT, speed, streaming, and prepared workloads. -Quick or focused runs are diagnostic -evidence only, even when they are useful for investigating a regression. - -Each native matrix run writes `provenance.json` next to `report.md`. The -provenance file records the benchmark source set, PostgreSQL patch/build inputs, -Rust SDK sources, `xtask`, and native artifacts by SHA-256. Verify an existing -run before using it as release evidence: - -```sh -OLIPHAUNT_PERF_RUN_DIR="$PWD/target/perf/native-liboliphaunt-" \ -tools/perf/check-native-perf-report.sh -``` - -This validation rejects diagnostic and partial reports by default. To verify -only the source/artifact provenance of a focused diagnostic run, set -`OLIPHAUNT_PERF_ALLOW_DIAGNOSTIC=1`; do not use that mode for release -claims or updates to the latest complete matrix section. - -Use the focused native diagnostic when a specific speed case misses the native -control and needs repeat evidence: - -```sh -tools/perf/matrix/run_native_speed_diagnostics.sh --ids 1,2,2.1 --repeats 10 --skip-build -``` - -It writes `summary.json` and `summary.md` under -`target/perf/native-speed-diagnostics-/`. Use the lower-level command -when you need a single raw diagnostic case: - -```sh -LIBOLIPHAUNT_PATH="$PWD/target/liboliphaunt-pg18/out/liboliphaunt.dylib" \ -OLIPHAUNT_INSTALL_DIR="$PWD/target/liboliphaunt-pg18/install" \ -cargo run -p oliphaunt-perf -- \ - diagnose-speed-cases --engine native-liboliphaunt --ids 3 -``` - -Native direct diagnostics run one case per process because the embedded backend -has a single safe process lifetime. Diagnostic output includes the engine -process model and key PostgreSQL GUCs so direct-mode misses can be separated -from control mismatch. The same command supports `--engine native-postgres`; it -uses `OLIPHAUNT_POSTGRES` / `OLIPHAUNT_INITDB` or the repo's -`target/liboliphaunt-pg18/install/bin` tools when present, with `--postgres-bin` -and `--initdb-bin` available for explicit overrides. Cluster-seed hydration -defaults to physical byte-copy because local matrix evidence showed better p90 -stability than APFS clone-on-write. Set -`OLIPHAUNT_PGDATA_COPY_MODE=prefer-clone` only when investigating -clone-on-write behavior explicitly. - -The SQLite control is part of the same matrix by default and can be run -directly for a quick embedded baseline: - -```sh -cargo run -p oliphaunt-perf -- \ - sqlite --suite speed --speed-source oliphaunt --durability safe -``` - -`safe`, `balanced`, and `fast-dev` map to explicit SQLite PRAGMAs inside `oliphaunt-perf`, -so SQLite numbers are recorded as product comparison data rather than inferred -from a separate tool. - -## Snapshot - -Snapshot run: `20260507T113000Z` - -Environment: - -- OS: `macOS 26.4.1 (Darwin 25.4.0 arm64)` -- CPU: `Apple M1 Pro` -- RAM: `16 GB` -- Logical cores: `10` -- Node: `v24.13.0` -- Node packages: `@electric/wasm@0.4.5`, - `@electric/wasm-socket@0.1.5` -- Native Postgres: `18.3 (Homebrew)` -- RTT iterations: `100` -- Speed source: exact upstream SQL from - `target/oliphaunt-sources/checkouts/oliphaunt/packages/benchmark/src` - -Every mode was run serially. - -## Representative Operations - -Lower is better. - -| Operation | native pg + SQLx | oliphaunt-wasix + SQLx | vanilla Oliphaunt + SQLx | -|---|---:|---:|---:| -| 25,000 INSERTs in one transaction | 132.36 ms | 149.54 ms | 257.02 ms | -| 25,000 INSERTs in one statement | 46.14 ms | 59.39 ms | 117.19 ms | -| 25,000 INSERTs into an indexed table | 188.72 ms | 253.38 ms | 352.64 ms | -| 5,000 indexed SELECTs | 81.39 ms | 125.31 ms | 203.05 ms | -| 25,000 indexed UPDATEs | 351.05 ms | 578.96 ms | 720.63 ms | - -## Full Operation Table - -| ID | Test | native pg + SQLx | oliphaunt-wasix + SQLx | vanilla Oliphaunt + SQLx | -|---|---|---:|---:|---:| -| 1 | Test 1: 1000 INSERTs | 9.13 ms | 19.76 ms | 15.66 ms | -| 2 | Test 2: 25000 INSERTs in a transaction | 132.36 ms | 149.54 ms | 257.02 ms | -| 2.1 | Test 2.1: 25000 INSERTs in single statement | 46.14 ms | 59.39 ms | 117.19 ms | -| 3 | Test 3: 25000 INSERTs into an indexed table | 188.72 ms | 253.38 ms | 352.64 ms | -| 3.1 | Test 3.1: 25000 INSERTs into an indexed table in single statement | 66.41 ms | 95.12 ms | 93.88 ms | -| 4 | Test 4: 100 SELECTs without an index | 107.63 ms | 162.89 ms | 242.03 ms | -| 5 | Test 5: 100 SELECTs on a string comparison | 305.38 ms | 338.01 ms | 434.63 ms | -| 6 | Test 6: Creating indexes | 9.94 ms | 13.08 ms | 17.12 ms | -| 7 | Test 7: 5000 SELECTs with an index | 81.39 ms | 125.31 ms | 203.05 ms | -| 8 | Test 8: 1000 UPDATEs without an index | 47.91 ms | 74.42 ms | 103.66 ms | -| 9 | Test 9: 25000 UPDATEs with an index | 351.05 ms | 578.96 ms | 720.63 ms | -| 10 | Test 10: 25000 text UPDATEs with an index | 471.74 ms | 712.38 ms | 858.95 ms | -| 11 | Test 11: INSERTs from a SELECT | 65.64 ms | 97.43 ms | 112.87 ms | -| 12 | Test 12: DELETE without an index | 7.54 ms | 9.74 ms | 11.69 ms | -| 13 | Test 13: DELETE with an index | 9.31 ms | 26.58 ms | 27.7 ms | -| 14 | Test 14: A big INSERT after a big DELETE | 53 ms | 71.6 ms | 87.72 ms | -| 15 | Test 15: A big DELETE followed by 12000 small INSERTs | 58.98 ms | 74.49 ms | 112.18 ms | -| 16 | Test 16: DROP TABLE | 3.43 ms | 10.17 ms | 6.74 ms | - -## Reproduce - -Run the native matrix plan locally: - -```sh -tools/perf/matrix/run_native_oliphaunt_matrix.sh --plan-only -``` - -Run measured native results when the native runtime artifacts are present: - -```sh -tools/perf/matrix/run_native_oliphaunt_matrix.sh --engines direct,broker,server -``` - -That command covers: - -1. native direct, broker, and server Oliphaunt paths; -2. native PostgreSQL control runs; -3. SQLite embedded control runs for the speed suite; -4. p50/p90/p95 latency, throughput, RSS, CPU, and footprint report generation. - -The repository performance tooling owns the shared WASIX browser and Node -benchmark plans: - -```sh -moon run perf-tools:wasix-plan -``` - -Run measured Node or browser evidence explicitly with -`moon run perf-tools:wasix-node-measure` or -`moon run perf-tools:wasix-browser-measure`. - -Outputs land under `target/perf/`: - -- `bench-native-postgres-sqlx-.json` -- `bench-oliphaunt-native-direct-.json` -- `bench-oliphaunt-native-broker-.json` -- `bench-oliphaunt-native-server-.json` -- `bench-sqlite-.json` -- `bench-comparison-.md` - -Override the native Postgres binaries when needed: - -```sh -OLIPHAUNT_POSTGRES=/path/to/postgres \ -OLIPHAUNT_INITDB=/path/to/initdb \ -tools/perf/matrix/run_native_oliphaunt_matrix.sh --engines direct,broker,server -``` - -## Reading The Matrix - -- `oliphaunt-wasix + SQLx` is the product-style path for apps that connect through - standard Postgres clients. -- `vanilla Oliphaunt + SQLx` keeps upstream Oliphaunt on NodeFS, but uses the same Rust - SQLx client path as the other wire-protocol rows. -- These are machine-local numbers. Re-run the matrix before quoting them in a - release note or public comparison. diff --git a/docs/maintainers/repo-structure.md b/docs/maintainers/repo-structure.md deleted file mode 100644 index f9f8f5671..000000000 --- a/docs/maintainers/repo-structure.md +++ /dev/null @@ -1,325 +0,0 @@ -# Repository Structure - -This repository is organized as a multi-product workspace, not as one Rust crate -with adjacent experiments. - -## Evidence - -- Cargo supports a virtual workspace when the root `Cargo.toml` has - `[workspace]` and no `[package]`. Cargo documents this as useful when there - is no primary package or packages should be kept in separate directories: - https://doc.rust-lang.org/cargo/reference/workspaces.html -- Cargo workspaces share one lockfile and one target directory, which keeps - cross-crate Rust development coherent while letting each package own its own - manifest and public boundary: - https://doc.rust-lang.org/cargo/reference/workspaces.html -- Swift Package Manager expects each package to own a `Package.swift`, products, - targets, and target-scoped resources. The normal development package lives - under `src/sdks/swift`; the root `Package.swift` is the public tag entrypoint - and points at those same product-owned source directories: - https://docs.swift.org/package-manager/PackageDescription/PackageDescription.html -- Gradle's multi-project model uses a root build plus isolated subprojects - declared from settings, which maps to the Kotlin/Android SDK under - `src/sdks/kotlin`: - https://docs.gradle.org/current/userguide/multi_project_builds.html -- moon provides the product graph, affected-CI selection, and task discovery. - It does not replace package-native tools; Cargo, SwiftPM/Xcode, Gradle, - pnpm/Expo, PostgreSQL build scripts, and shell harnesses remain authoritative: - https://moonrepo.dev/docs - -## Top-Level Policy - -The repository root should contain shared metadata and entrypoints only. Product -source lives under `src//`. - -The root `Cargo.toml`, `package.json`, `pnpm-workspace.yaml`, `moon.yml`, and -`Package.swift` are workspace or public package-manager entrypoints, not product -source. Product-native manifests remain beside their source. - -- `src/runtimes/liboliphaunt/native/` owns the C ABI and PostgreSQL patch stack. -- `src/sdks/rust/` owns the Rust SDK and Cargo package. -- `src/sdks/swift/`, `src/sdks/kotlin/`, - `src/sdks/react-native/`, and `src/sdks/js/` own platform and - runtime SDKs. -- `src/bindings/wasix-rust/` owns the released Rust WASIX binding. -- `src/bindings/wasix-ts/` owns the public browser, Node, Bun, Deno, and Electron WASIX TypeScript - binding and its optional `tools-package/` `pg_dump`/`psql` facade. It is a - peer binding, not part of the native TypeScript SDK; portable program bytes - remain owned by `liboliphaunt-wasix`. -- `src/runtimes/liboliphaunt/wasix-postmaster/` owns the released concurrent - PostgreSQL postmaster runtime and its sealed WASIX backend carrier. It reuses - canonical source and toolchain inputs where semantics agree, while owning - its concurrency-specific patches, carrier, release metadata, and support - claims. -- `src/*/moon.yml` is the canonical product graph. `tools/policy/sdk-manifest.toml` - is a small SDK parity ownership registry and must agree with Moon metadata. -- Tooling lives under `tools/`. -- Benchmarks live under `benchmarks/`. -- `src/docs/` is the public documentation product. It owns public SDK - docs under `src/docs/content/sdk`, generated matrices, tested - snippets, API-reference stubs, and LLM docs rendered into - `target/docs`. -- Cross-product architecture, performance, release, and maintainer source docs - live under `docs/`. -- Shared fixture corpora consumed by at least two product-native test suites - live under `src/shared/fixtures/`. -- Pinned PostgreSQL source metadata, runtime-level third-party source pins, - toolchain pins, extension-owned source pins, and generated extension catalogs - live under `src/postgres/versions/18`, `src/sources/third-party`, - `src/sources/toolchains`, and `src/extensions`. -- Postmaster-specific Wasmer and wasix-libc pins live under - `src/sources/third-party/wasix-postmaster/`. The default `production-all` - source scope includes every released product input; the focused - `wasix-postmaster-runtime` scope acquires only this product's runtime inputs. - -There should be no tracked product source under retired roots such as -`crates/`, `sdks/`, root `liboliphaunt/`, or root product examples. - -Tests, fixtures, and benchmarks follow the consumer surface instead of a single -synthetic root: - -- Product-native tests live in each product's package-native test root: - `src/sdks/rust/tests/`, `src/sdks/swift/Tests/`, - `src/sdks/kotlin/oliphaunt/src/*Test/`, - `src/sdks/react-native/src/__tests__/`, - `src/sdks/js/src/__tests__/`, and - `src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/`, plus - `src/bindings/wasix-ts/src/__tests__/` for the WASIX TypeScript binding, and - `src/bindings/wasix-ts/tools-package/src/__tests__/` for its optional tools facade. -- Rust SDK tests are split by contract: deliberate public vocabulary stays in - `src/sdks/rust/tests/public_api.rs`, native-environment smokes stay in - `src/sdks/rust/tests/native_smoke.rs`, and extension coverage stays in - `src/sdks/rust/tests/native_extensions.rs` and - `src/sdks/rust/tests/sdk_extensions.rs`. -- Product-private fixtures stay beside those tests. Shared fixtures move to - `src/shared/fixtures/` only when the contract is consumed by multiple - products, or when a product-specific boundary fixture needs central policy - enforcement. `src/shared/fixtures/protocol/query-response-cases.json` is the - current shared PostgreSQL backend-response corpus consumed from product-native - Rust, Swift, Kotlin, TypeScript, React Native, and WASIX query-decoding tests. -- Benchmark plans, datasets, and published reports live in `benchmarks/`. - Executable benchmark harnesses live in `tools/perf/` unless the harness is a - deliberate product API. - -## Product Boundaries - -- `liboliphaunt` is the native C boundary. It owns PostgreSQL source pins, patches, - exported headers, and native build harnesses. -- `src/sdks/rust` is the Rust-native SDK for Tauri and Rust desktop - apps. It should depend on `liboliphaunt` artifacts through explicit - runtime/build configuration, not on `oliphaunt-wasix` internals. -- `docs/maintainers/rust-sdk-policy.md` is the Rust SDK policy entrypoint. The package - source, tests, and release metadata live in `src/sdks/rust`. -- `src/bindings/wasix-rust/crates/oliphaunt-wasix` is the existing WASIX package. It stays intact as a - release lane and comparison target. It should not expose native engine - selection or link/load `liboliphaunt`; native Rust work belongs in - `src/sdks/rust`. -- `src/bindings/wasix-ts` is the public browser, Node, Bun, Deno, and Electron - binding over the same portable WASIX runtime. It owns browser module Workers, - native-host Rust actor/direct/Worker placement, archive-to-memory mounts, - the patched package-relative browser Wasmer host, and the direct pgwire - client. It must not depend on `src/sdks/js`, native runtime carriers other - than its exact WASIX Node-API carriers, Node direct, or the broker. Conditional - exports select the browser or native host without changing package identity. -- `src/runtimes/liboliphaunt/wasix-postmaster` is a peer release product, not an - implementation directory of `liboliphaunt-wasix`. It owns a distinct Moon - release component and sealed carrier because its concurrent process and - shared-memory semantics differ from the single-backend runtime. Generated - checkouts, builds, carriers, caches, and reports stay under - `target/oliphaunt-wasix-postmaster/`. -- `src/runtimes/liboliphaunt/wasix/assets/build` is source-only: scripts, patches, - Docker inputs, and shims. Generated WASIX build and work trees live under - `target/oliphaunt-wasix/wasix-build`. -- `src/sdks/swift` is a normal Swift package for iOS and macOS apps. It owns - `Oliphaunt`, a C header target, and Swift tests. -- `src/sdks/kotlin` is a Gradle multi-project build for the Android SDK. It owns - the common suspend implementation, JVM contract tests, Android wrapper, and - Android runtime tests; only its Android AAR/plugin/ABI surfaces are published. -- `src/sdks/react-native` is a React Native New Architecture package. It owns the - TypeScript DX layer and TurboModule Codegen spec. Platform runtime behavior - belongs to the Swift and Kotlin SDKs; React Native native code should be - adapter glue, not a parallel PostgreSQL lifecycle implementation. -- `src/sdks/js` is the SDK for Node.js, Bun, and Deno. Tauri apps currently - use the Rust SDK behind narrow app-owned commands. The TypeScript SDK owns - JavaScript runtime FFI adapters, npm package metadata, and - broker/server client orchestration. Its broker implementation depends on the - published `oliphaunt-broker` runtime and the shared `PGOB` protocol, - so that dependency must remain modeled in Moon and product-local release - metadata. - -Native SDKs are product peers over the native `liboliphaunt` PostgreSQL -boundary. Rust WASIX and WASIX TypeScript are peers over the separate portable -WASIX runtime boundary. All should have parity wherever their target can -support behavior honestly; gaps must be explicit and justified in -`docs/maintainers/sdk-parity-policy.md`. - -## Internal Organization Rules - -- Product bindings own their own host code. Rust WASIX may consume Cargo WASIX - asset crates and WASIX TypeScript may consume the generated host-neutral - portable runtime carrier plus separately selected WASIX extension npm leaves; - `oliphaunt` may load `liboliphaunt`. None should call another public - product's private modules. -- `moon run sdk-contracts:native-boundaries` enforces the native/WASIX split: - the Rust-native SDK and Swift/Kotlin/React Native package manifests must not - depend on `oliphaunt-wasix`, WASIX AOT payload crates, or Wasmer runtime - packages. -- `tools/xtask` is shared repo automation for WASIX assets, release staging, - and optional performance diagnostics. Its default feature set is intentionally - empty; template running and AOT serializers must be enabled with explicit - feature flags. -- `tools/xtask/src/main.rs` is the command router plus shared helpers. WASIX - asset build, packaging, generated manifest, AOT packaging, and staged metadata - orchestration lives in `tools/xtask/src/asset_pipeline.rs`. Source-controlled - asset verification, canonical generated-asset layout checks, AOT target - catalog checks, and upstream-fix audits live in - `tools/xtask/src/asset_checks.rs`. Generated asset manifest DTOs, AOT - manifest DTOs, asset packaging descriptors, and WASM link-metadata parsing - live in - `tools/xtask/src/asset_manifest.rs`. Asset download/install code lives in - `tools/xtask/src/asset_io.rs`, shared filesystem/archive/hash helpers live in - `tools/xtask/src/fs_utils.rs`, - release workspace assembly lives in `tools/xtask/src/release_workspace.rs`, - source-pin and source-spine handling lives in - `tools/xtask/src/source_spine.rs`, PostgreSQL source/patch-surface guards - live in `tools/xtask/src/postgres_guard.rs`, cluster-seed execution lives in - `tools/xtask/src/cluster_seed_runner.rs`, and AOT serialization lives in - `tools/xtask/src/aot_serializer.rs`. Performance benchmark workload/result - construction lives in `tools/perf/runner/src/benchmarks.rs`, and report DTOs - live in `tools/perf/runner/src/report.rs`. Native liboliphaunt execution, - child-process entrypoints, and SDK-backed diagnostics live in - `tools/perf/runner/src/native_liboliphaunt.rs`. Native PostgreSQL process, - protocol, and backup/restore controls live in - `tools/perf/runner/src/native_postgres.rs`. Prepared-update benchmark - parsing, transport variants, gates, and native comparison live in - `tools/perf/runner/src/prepared_updates.rs`. Indexed-update, speed-hotspot, - and buffer-cache diagnostics live in `tools/perf/runner/src/diagnostics.rs`. - Benchmark execution should continue to split under `tools/perf/runner/src/` - by collection, aggregation, transport family, diagnostics, and report - rendering. -- Native C ABI concerns are split by layer: - - `src/runtimes/liboliphaunt/native/` for C, PostgreSQL patches, and platform build scripts. - - `src/sdks/rust/src/liboliphaunt/ffi.rs` for Rust symbol loading and - ABI structs. - - `src/sdks/rust/src/liboliphaunt/root.rs` for native root locking, - runtime materialization, and opt-in extension asset copying. - - `src/sdks/rust/src/liboliphaunt/root/runtime/` for runtime installation and - discovery. - - `src/sdks/rust/src/liboliphaunt/mod.rs` for the Rust runtime/session - implementation. -- Native runtime-resource packaging is maintainer-only and split by release - artifact concern under the unpublished `oliphaunt-native-packaging` tool: - - `tools/native-packaging/src/lib.rs` for resource package orchestration and - selected extension resolution. - - `tools/native-packaging/src/manifest.rs` for portable - manifest parsing, identifier validation, and runtime artifact path rules. - - `tools/native-packaging/src/package.rs` for resource-tree - writing, portable tree copying, package manifests, and size reports. - - `tools/native-packaging/src/extension_artifact.rs` for exact - prebuilt extension artifact creation, archive extraction, and artifact - manifest writing. - - `tools/native-packaging/src/extension_index.rs` for external - extension artifact index creation, resolution, signing, download, and - checksum verification. - - `tools/native-packaging/src/static_registry.rs` for iOS and - Android static extension registry metadata, generated C source, and mobile - static archive staging. -- WASIX runtime internals should keep VM orchestration separate from - reusable host adapters: - - `src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/base.rs` for - install/root preparation, runtime layout selection, archive validation, and - cluster-seed orchestration. - - `src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/base/cluster_seed_clone.rs` - for cluster-seed copy/clone mechanics, runtime-state exclusion, reflink - fallback, and symlink handling. - - `src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod.rs` - for PostgreSQL WASIX module lifecycle, exported function wiring, startup - protocol, and split-initdb command orchestration. - - `src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod/stdio.rs` - for WASIX virtual stdio adapters, protocol stream attachment, and bounded - process-output capture. - - `src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod/wasix_fs.rs` - for host filesystem wrapping and `/dev` mounting. Persistent PGDATA is a - standalone managed directory; only immutable runtime files may be shared - through the runtime cache. -- Public runtime and build controls should use `OLIPHAUNT_*`. Use - `LIBOLIPHAUNT_PATH` only for the literal native C library artifact path. -- Large files should have a reason. Once a module mixes lifecycle, packaging, - protocol, and CLI orchestration, split it along those responsibilities before - adding more behavior. - -## Tooling Rules - -- `.moon/` owns product graph, affected task selection, and shared toolchain - pins. Do not duplicate release dependency rules in ad hoc scripts when moon - metadata can express them. -- `package.json` owns JavaScript workspace metadata only. Do not add root - workflow aliases; run product and repo work through Moon targets directly. -- Release Please owns product versions, changelogs, and the generated release - PR. Bun release entrypoints under `tools/release/*.mjs` own the public and - protected check, dry-run, publish, exact-SHA tag, and draft-release command - surface. -- Cargo publication runs through `tools/dev/bun.sh - tools/release/release-publish.mjs publish` in the protected Release workflow. - Release packaging freezes each `.crate`, and the exact-byte registry uploader - sends that lock-matching file through crates.io's Registry Web API. Do not - replace it with `cargo publish`, which would repackage the source and break - the frozen-byte contract, or add a Rust-only release orchestrator beside - Release Please. -- `tools/xtask` owns Rust-heavy automation and release asset orchestration. -- `tools/policy`, `tools/dev`, `tools/perf`, and `tools/release` own - shell/Python/Node entrypoints by responsibility. CI is thin workflow - orchestration over Moon tasks and the release CLI. -- `sdk-contracts:all` is the local aggregate for generated API, SDK registry, - C ABI header-copy, fixtures, cluster seeds, shared Rust, and native-boundary - contracts; hosted CI schedules its children independently. Exact extension catalogs belong to - `extensions:lint`, while - SDK behavior, React Native delegation, package contents, and installed-app - evidence belong to product-local Moon tasks. Stable CI does not infer those - contracts from prose, test names, or implementation-source spellings. -- `prek` owns Git hooks as a language-neutral runner for whitespace, format, - and commit-message guards. Heavy asset, lockfile, and workspace checks belong - in Moon tasks, product-local tools, release CLI subcommands, and CI, not - automatic pre-push hooks. -- `actionlint` and `zizmor` are intentionally paired: actionlint validates - GitHub Actions syntax and expression semantics; zizmor audits workflow - security posture. Do not add a third workflow linter without removing overlap. -- Package-native tools stay native: Cargo for Rust, SwiftPM/Xcode tooling for - Swift, Gradle for Kotlin/Android, and React Native's own Codegen/build flow - for React Native. - -## Current Tree - -```text -. -├── Cargo.toml -├── Package.swift -├── package.json -├── moon.yml -├── benchmarks/ -├── docs/{architecture,internal,maintainers}/ -├── examples/{browser-wasix,electron,electron-wasix,react-native-expo,tauri,tauri-wasix}/ -├── src/ -│ ├── bindings/{wasix-rust,wasix-ts}/ -│ ├── docs/ -│ ├── extensions/{artifacts,catalog,contrib,external,generated,model}/ -│ ├── postgres/versions/18/ -│ ├── runtimes/{broker,liboliphaunt,node-direct,wasix-napi}/ -│ ├── sdks/{js,kotlin,react-native,rust,swift}/ -│ ├── shared/{cluster-seed-contract,extension-runtime-contract,fixtures,js-core,rust-query-core}/ -│ └── sources/{third-party,toolchains}/ -└── tools/ - ├── coverage/ - ├── dev/ - ├── graph/ - ├── native-extension-proof/ - ├── native-packaging/ - ├── native-tools-proof/ - ├── perf/ - ├── policy/ - ├── release/ - ├── runtime/ - ├── sdk-contracts/ - ├── test/ - └── xtask/ -``` diff --git a/docs/maintainers/sdk-api-surface.md b/docs/maintainers/sdk-api-surface.md deleted file mode 100644 index dcad09643..000000000 --- a/docs/maintainers/sdk-api-surface.md +++ /dev/null @@ -1,2188 +0,0 @@ - -# SDK API Surface Inventory - -This no-build inventory records exported type names and statically named public members that its source extractors can resolve: named Rust fields, inherent members, and trait requirements; Swift public members and public-protocol requirements; Kotlin explicit public members and public primary-constructor properties; and TypeScript declared members. It intentionally does not model complete signatures, enum variants, unnamed Rust tuple fields, inherited or synthesized members, or JavaScript default exports. Compile-time public-API tests and package-shape checks own those contracts; this inventory is not a replacement for full language reference documentation. - -Regenerate with: - -```sh -node tools/policy/generate-sdk-api-surface.mjs --write -``` - -## Rust: oliphaunt - -- `oliphaunt::AsyncOliphaunt` -- `oliphaunt::AsyncOliphaunt.backup()` -- `oliphaunt::AsyncOliphaunt.builder()` -- `oliphaunt::AsyncOliphaunt.cancel()` -- `oliphaunt::AsyncOliphaunt.close()` -- `oliphaunt::AsyncOliphaunt.describe()` -- `oliphaunt::AsyncOliphaunt.exec()` -- `oliphaunt::AsyncOliphaunt.exec_protocol_raw()` -- `oliphaunt::AsyncOliphaunt.exec_protocol_raw_stream()` -- `oliphaunt::AsyncOliphaunt.execute()` -- `oliphaunt::AsyncOliphaunt.execute_with_params()` -- `oliphaunt::AsyncOliphaunt.is_closed()` -- `oliphaunt::AsyncOliphaunt.open()` -- `oliphaunt::AsyncOliphaunt.query()` -- `oliphaunt::AsyncOliphaunt.query_with_params()` -- `oliphaunt::AsyncOliphaunt.restore()` -- `oliphaunt::AsyncOliphaunt.sql()` -- `oliphaunt::AsyncOliphaunt.transaction()` -- `oliphaunt::AsyncOliphauntBuilder` -- `oliphaunt::AsyncOliphauntBuilder.broker()` -- `oliphaunt::AsyncOliphauntBuilder.broker_executable()` -- `oliphaunt::AsyncOliphauntBuilder.database()` -- `oliphaunt::AsyncOliphauntBuilder.direct()` -- `oliphaunt::AsyncOliphauntBuilder.extension()` -- `oliphaunt::AsyncOliphauntBuilder.extensions()` -- `oliphaunt::AsyncOliphauntBuilder.new()` -- `oliphaunt::AsyncOliphauntBuilder.open()` -- `oliphaunt::AsyncOliphauntBuilder.startup_guc()` -- `oliphaunt::AsyncOliphauntBuilder.startup_gucs()` -- `oliphaunt::AsyncOliphauntBuilder.storage()` -- `oliphaunt::AsyncOliphauntBuilder.username()` -- `oliphaunt::AsyncOliphauntServer` -- `oliphaunt::AsyncOliphauntServer.builder()` -- `oliphaunt::AsyncOliphauntServer.close()` -- `oliphaunt::AsyncOliphauntServer.connection_string()` -- `oliphaunt::AsyncOliphauntServer.is_closed()` -- `oliphaunt::AsyncOliphauntServerBuilder` -- `oliphaunt::AsyncOliphauntServerBuilder.database()` -- `oliphaunt::AsyncOliphauntServerBuilder.extension()` -- `oliphaunt::AsyncOliphauntServerBuilder.extensions()` -- `oliphaunt::AsyncOliphauntServerBuilder.listen()` -- `oliphaunt::AsyncOliphauntServerBuilder.new()` -- `oliphaunt::AsyncOliphauntServerBuilder.server_executable()` -- `oliphaunt::AsyncOliphauntServerBuilder.start()` -- `oliphaunt::AsyncOliphauntServerBuilder.startup_guc()` -- `oliphaunt::AsyncOliphauntServerBuilder.startup_gucs()` -- `oliphaunt::AsyncOliphauntServerBuilder.storage()` -- `oliphaunt::AsyncOliphauntServerBuilder.username()` -- `oliphaunt::AsyncSql` -- `oliphaunt::AsyncSql.bind()` -- `oliphaunt::AsyncSql.bind_parameter()` -- `oliphaunt::AsyncSql.describe()` -- `oliphaunt::AsyncSql.execute()` -- `oliphaunt::AsyncSql.query()` -- `oliphaunt::AsyncSql.result_format()` -- `oliphaunt::AsyncTransaction` -- `oliphaunt::AsyncTransaction.describe()` -- `oliphaunt::AsyncTransaction.exec()` -- `oliphaunt::AsyncTransaction.execute()` -- `oliphaunt::AsyncTransaction.execute_with_params()` -- `oliphaunt::AsyncTransaction.is_closed()` -- `oliphaunt::AsyncTransaction.query()` -- `oliphaunt::AsyncTransaction.query_with_params()` -- `oliphaunt::AsyncTransaction.rollback()` -- `oliphaunt::AsyncTransaction.sql()` -- `oliphaunt::CancelHandle` -- `oliphaunt::CancelHandle.cancel()` -- `oliphaunt::CommandResult` -- `oliphaunt::CommandResult.command_tag()` -- `oliphaunt::CommandResult.notices()` -- `oliphaunt::CommandResult.row_count()` -- `oliphaunt::DatabaseStorage` -- `oliphaunt::DecodeError` -- `oliphaunt::Error` -- `oliphaunt::Error.kind()` -- `oliphaunt::Error.postgres_error()` -- `oliphaunt::Error.transaction_callback_database_errors()` -- `oliphaunt::Error.transaction_rollback_errors()` -- `oliphaunt::ErrorKind` -- `oliphaunt::ExecResult` -- `oliphaunt::ExecResult.notices()` -- `oliphaunt::ExecResult.statements()` -- `oliphaunt::Extension` -- `oliphaunt::Extension.ALL` -- `oliphaunt::Extension.AMCHECK` -- `oliphaunt::Extension.AUTO_EXPLAIN` -- `oliphaunt::Extension.BLOOM` -- `oliphaunt::Extension.BTREE_GIN` -- `oliphaunt::Extension.BTREE_GIST` -- `oliphaunt::Extension.CITEXT` -- `oliphaunt::Extension.CUBE` -- `oliphaunt::Extension.DICT_INT` -- `oliphaunt::Extension.DICT_XSYN` -- `oliphaunt::Extension.EARTHDISTANCE` -- `oliphaunt::Extension.FILE_FDW` -- `oliphaunt::Extension.FUZZYSTRMATCH` -- `oliphaunt::Extension.HSTORE` -- `oliphaunt::Extension.INTARRAY` -- `oliphaunt::Extension.ISN` -- `oliphaunt::Extension.LO` -- `oliphaunt::Extension.LTREE` -- `oliphaunt::Extension.PAGEINSPECT` -- `oliphaunt::Extension.PGCRYPTO` -- `oliphaunt::Extension.PGTAP` -- `oliphaunt::Extension.PG_BUFFERCACHE` -- `oliphaunt::Extension.PG_FREESPACEMAP` -- `oliphaunt::Extension.PG_HASHIDS` -- `oliphaunt::Extension.PG_IVM` -- `oliphaunt::Extension.PG_SURGERY` -- `oliphaunt::Extension.PG_TEXTSEARCH` -- `oliphaunt::Extension.PG_TRGM` -- `oliphaunt::Extension.PG_UUIDV7` -- `oliphaunt::Extension.PG_VISIBILITY` -- `oliphaunt::Extension.PG_WALINSPECT` -- `oliphaunt::Extension.POSTGIS` -- `oliphaunt::Extension.SEG` -- `oliphaunt::Extension.TABLEFUNC` -- `oliphaunt::Extension.TCN` -- `oliphaunt::Extension.TSM_SYSTEM_ROWS` -- `oliphaunt::Extension.TSM_SYSTEM_TIME` -- `oliphaunt::Extension.UNACCENT` -- `oliphaunt::Extension.UUID_OSSP` -- `oliphaunt::Extension.VECTOR` -- `oliphaunt::Extension.by_sql_name()` -- `oliphaunt::Extension.sql_name()` -- `oliphaunt::FromSql` -- `oliphaunt::FromSql.check_type()` -- `oliphaunt::FromSql.from_sql()` -- `oliphaunt::IntoParameter` -- `oliphaunt::IntoParameter.TYPE_OID` -- `oliphaunt::IntoParameter.into_parameter()` -- `oliphaunt::Oliphaunt` -- `oliphaunt::Oliphaunt.backup()` -- `oliphaunt::Oliphaunt.builder()` -- `oliphaunt::Oliphaunt.cancel()` -- `oliphaunt::Oliphaunt.cancel_handle()` -- `oliphaunt::Oliphaunt.close()` -- `oliphaunt::Oliphaunt.describe()` -- `oliphaunt::Oliphaunt.exec()` -- `oliphaunt::Oliphaunt.exec_protocol_raw()` -- `oliphaunt::Oliphaunt.exec_protocol_raw_stream()` -- `oliphaunt::Oliphaunt.execute()` -- `oliphaunt::Oliphaunt.execute_with_params()` -- `oliphaunt::Oliphaunt.is_closed()` -- `oliphaunt::Oliphaunt.open()` -- `oliphaunt::Oliphaunt.query()` -- `oliphaunt::Oliphaunt.query_with_params()` -- `oliphaunt::Oliphaunt.restore()` -- `oliphaunt::Oliphaunt.sql()` -- `oliphaunt::Oliphaunt.transaction()` -- `oliphaunt::OliphauntBuilder` -- `oliphaunt::OliphauntBuilder.broker()` -- `oliphaunt::OliphauntBuilder.broker_executable()` -- `oliphaunt::OliphauntBuilder.database()` -- `oliphaunt::OliphauntBuilder.direct()` -- `oliphaunt::OliphauntBuilder.extension()` -- `oliphaunt::OliphauntBuilder.extensions()` -- `oliphaunt::OliphauntBuilder.new()` -- `oliphaunt::OliphauntBuilder.open()` -- `oliphaunt::OliphauntBuilder.startup_guc()` -- `oliphaunt::OliphauntBuilder.startup_gucs()` -- `oliphaunt::OliphauntBuilder.storage()` -- `oliphaunt::OliphauntBuilder.username()` -- `oliphaunt::OliphauntServer` -- `oliphaunt::OliphauntServer.builder()` -- `oliphaunt::OliphauntServer.close()` -- `oliphaunt::OliphauntServer.connection_string()` -- `oliphaunt::OliphauntServer.is_closed()` -- `oliphaunt::OliphauntServerBuilder` -- `oliphaunt::OliphauntServerBuilder.database()` -- `oliphaunt::OliphauntServerBuilder.extension()` -- `oliphaunt::OliphauntServerBuilder.extensions()` -- `oliphaunt::OliphauntServerBuilder.listen()` -- `oliphaunt::OliphauntServerBuilder.new()` -- `oliphaunt::OliphauntServerBuilder.server_executable()` -- `oliphaunt::OliphauntServerBuilder.start()` -- `oliphaunt::OliphauntServerBuilder.startup_guc()` -- `oliphaunt::OliphauntServerBuilder.startup_gucs()` -- `oliphaunt::OliphauntServerBuilder.storage()` -- `oliphaunt::OliphauntServerBuilder.username()` -- `oliphaunt::Parameter` -- `oliphaunt::Parameter.binary()` -- `oliphaunt::Parameter.format()` -- `oliphaunt::Parameter.null()` -- `oliphaunt::Parameter.text()` -- `oliphaunt::Parameter.type_oid()` -- `oliphaunt::Parameter.typed_binary()` -- `oliphaunt::Parameter.typed_null()` -- `oliphaunt::Parameter.typed_text()` -- `oliphaunt::Parameter.value()` -- `oliphaunt::Parameter.with_type_oid()` -- `oliphaunt::PostgresError` -- `oliphaunt::PostgresError.column_name` -- `oliphaunt::PostgresError.constraint_name` -- `oliphaunt::PostgresError.data_type_name` -- `oliphaunt::PostgresError.detail` -- `oliphaunt::PostgresError.fields` -- `oliphaunt::PostgresError.file` -- `oliphaunt::PostgresError.hint` -- `oliphaunt::PostgresError.internal_position` -- `oliphaunt::PostgresError.internal_query` -- `oliphaunt::PostgresError.line` -- `oliphaunt::PostgresError.localized_severity` -- `oliphaunt::PostgresError.message` -- `oliphaunt::PostgresError.nonlocalized_severity` -- `oliphaunt::PostgresError.notices` -- `oliphaunt::PostgresError.position` -- `oliphaunt::PostgresError.routine` -- `oliphaunt::PostgresError.schema_name` -- `oliphaunt::PostgresError.severity` -- `oliphaunt::PostgresError.sqlstate` -- `oliphaunt::PostgresError.table_name` -- `oliphaunt::PostgresError.where_` -- `oliphaunt::PostgresErrorField` -- `oliphaunt::PostgresErrorField.code` -- `oliphaunt::PostgresErrorField.value` -- `oliphaunt::PostgresNotice` -- `oliphaunt::PostgresNotice.column_name` -- `oliphaunt::PostgresNotice.constraint_name` -- `oliphaunt::PostgresNotice.data_type_name` -- `oliphaunt::PostgresNotice.detail` -- `oliphaunt::PostgresNotice.fields` -- `oliphaunt::PostgresNotice.file` -- `oliphaunt::PostgresNotice.hint` -- `oliphaunt::PostgresNotice.internal_position` -- `oliphaunt::PostgresNotice.internal_query` -- `oliphaunt::PostgresNotice.line` -- `oliphaunt::PostgresNotice.localized_severity` -- `oliphaunt::PostgresNotice.message` -- `oliphaunt::PostgresNotice.nonlocalized_severity` -- `oliphaunt::PostgresNotice.position` -- `oliphaunt::PostgresNotice.routine` -- `oliphaunt::PostgresNotice.schema_name` -- `oliphaunt::PostgresNotice.severity` -- `oliphaunt::PostgresNotice.sqlstate` -- `oliphaunt::PostgresNotice.table_name` -- `oliphaunt::PostgresNotice.where_` -- `oliphaunt::QueryField` -- `oliphaunt::QueryField.format` -- `oliphaunt::QueryField.name` -- `oliphaunt::QueryField.table_attribute` -- `oliphaunt::QueryField.table_oid` -- `oliphaunt::QueryField.type_modifier` -- `oliphaunt::QueryField.type_oid` -- `oliphaunt::QueryField.type_oid_value()` -- `oliphaunt::QueryField.type_size` -- `oliphaunt::QueryFormat` -- `oliphaunt::QueryResult` -- `oliphaunt::QueryResult.command_tag()` -- `oliphaunt::QueryResult.fields()` -- `oliphaunt::QueryResult.get_text()` -- `oliphaunt::QueryResult.notices()` -- `oliphaunt::QueryResult.row_count()` -- `oliphaunt::QueryResult.rows()` -- `oliphaunt::QueryRow` -- `oliphaunt::QueryRow.fields()` -- `oliphaunt::QueryRow.is_empty()` -- `oliphaunt::QueryRow.len()` -- `oliphaunt::QueryRow.text()` -- `oliphaunt::QueryRow.try_get()` -- `oliphaunt::QueryRow.try_get_raw()` -- `oliphaunt::QueryRow.values()` -- `oliphaunt::RawStreamCallbackOutput` -- `oliphaunt::RawStreamCallbackOutput.Error` -- `oliphaunt::RawStreamError` -- `oliphaunt::RawStreamError.callback_error()` -- `oliphaunt::RawStreamError.callback_panic_error()` -- `oliphaunt::RawStreamError.database_error()` -- `oliphaunt::RawStreamResult` -- `oliphaunt::Result` -- `oliphaunt::RowIndex` -- `oliphaunt::RowIndex.resolve()` -- `oliphaunt::ServerListen` -- `oliphaunt::ServerListen.tcp()` -- `oliphaunt::ServerListen.tcp_port()` -- `oliphaunt::ServerListen.unix()` -- `oliphaunt::ServerListen.unix_port()` -- `oliphaunt::Sql` -- `oliphaunt::Sql.bind()` -- `oliphaunt::Sql.bind_parameter()` -- `oliphaunt::Sql.describe()` -- `oliphaunt::Sql.execute()` -- `oliphaunt::Sql.query()` -- `oliphaunt::Sql.result_format()` -- `oliphaunt::StatementDescription` -- `oliphaunt::StatementDescription.fields()` -- `oliphaunt::StatementDescription.notices()` -- `oliphaunt::StatementDescription.parameter_types()` -- `oliphaunt::StatementResult` -- `oliphaunt::Transaction` -- `oliphaunt::Transaction.describe()` -- `oliphaunt::Transaction.exec()` -- `oliphaunt::Transaction.execute()` -- `oliphaunt::Transaction.execute_with_params()` -- `oliphaunt::Transaction.is_closed()` -- `oliphaunt::Transaction.query()` -- `oliphaunt::Transaction.query_with_params()` -- `oliphaunt::Transaction.rollback()` -- `oliphaunt::Transaction.sql()` -- `oliphaunt::TransactionError` -- `oliphaunt::TransactionError.callback()` -- `oliphaunt::TransactionError.callback_error()` -- `oliphaunt::TransactionError.database_error()` -- `oliphaunt::TransactionError.rollback_error()` -- `oliphaunt::TransactionResult` -- `oliphaunt::TypeOid` -- `oliphaunt::TypeOid.BOOL` -- `oliphaunt::TypeOid.BOOL_ARRAY` -- `oliphaunt::TypeOid.BPCHAR` -- `oliphaunt::TypeOid.BPCHAR_ARRAY` -- `oliphaunt::TypeOid.BYTEA` -- `oliphaunt::TypeOid.BYTEA_ARRAY` -- `oliphaunt::TypeOid.CHAR` -- `oliphaunt::TypeOid.CHAR_ARRAY` -- `oliphaunt::TypeOid.DATE` -- `oliphaunt::TypeOid.DATE_ARRAY` -- `oliphaunt::TypeOid.FLOAT4` -- `oliphaunt::TypeOid.FLOAT4_ARRAY` -- `oliphaunt::TypeOid.FLOAT8` -- `oliphaunt::TypeOid.FLOAT8_ARRAY` -- `oliphaunt::TypeOid.INT2` -- `oliphaunt::TypeOid.INT2_ARRAY` -- `oliphaunt::TypeOid.INT4` -- `oliphaunt::TypeOid.INT4_ARRAY` -- `oliphaunt::TypeOid.INT8` -- `oliphaunt::TypeOid.INT8_ARRAY` -- `oliphaunt::TypeOid.INTERVAL` -- `oliphaunt::TypeOid.INTERVAL_ARRAY` -- `oliphaunt::TypeOid.JSON` -- `oliphaunt::TypeOid.JSONB` -- `oliphaunt::TypeOid.JSONB_ARRAY` -- `oliphaunt::TypeOid.JSON_ARRAY` -- `oliphaunt::TypeOid.NAME` -- `oliphaunt::TypeOid.NAME_ARRAY` -- `oliphaunt::TypeOid.NUMERIC` -- `oliphaunt::TypeOid.NUMERIC_ARRAY` -- `oliphaunt::TypeOid.OID` -- `oliphaunt::TypeOid.OID_ARRAY` -- `oliphaunt::TypeOid.TEXT` -- `oliphaunt::TypeOid.TEXT_ARRAY` -- `oliphaunt::TypeOid.TIME` -- `oliphaunt::TypeOid.TIMESTAMP` -- `oliphaunt::TypeOid.TIMESTAMPTZ` -- `oliphaunt::TypeOid.TIMESTAMPTZ_ARRAY` -- `oliphaunt::TypeOid.TIMESTAMP_ARRAY` -- `oliphaunt::TypeOid.TIMETZ` -- `oliphaunt::TypeOid.TIMETZ_ARRAY` -- `oliphaunt::TypeOid.TIME_ARRAY` -- `oliphaunt::TypeOid.UNKNOWN` -- `oliphaunt::TypeOid.UUID` -- `oliphaunt::TypeOid.UUID_ARRAY` -- `oliphaunt::TypeOid.VARCHAR` -- `oliphaunt::TypeOid.VARCHAR_ARRAY` -- `oliphaunt::TypeOid.XML` -- `oliphaunt::TypeOid.XML_ARRAY` -- `oliphaunt::TypeOid.get()` -- `oliphaunt::TypeOid.new()` -- `oliphaunt::ValueFormat` -- `oliphaunt::ValueRef` -- `oliphaunt::ValueRef.as_bytes()` -- `oliphaunt::ValueRef.column()` -- `oliphaunt::ValueRef.field()` -- `oliphaunt::ValueRef.format()` -- `oliphaunt::ValueRef.is_null()` -- `oliphaunt::ValueRef.type_oid()` -- `oliphaunt::register_build_resources!` -- `oliphaunt::register_build_resources_dir` - -### Version-locked broker seam (not application API) - -The separately built `oliphaunt-broker` executable enables `__internal-broker-helper` and consumes this exact-version seam. It is absent from default builds and may change only in lockstep with that executable. - -- `oliphaunt::__private::BrokerCancel` -- `oliphaunt::__private::BrokerCancel.cancel()` -- `oliphaunt::__private::BrokerIpcRequest` -- `oliphaunt::__private::BrokerSession` -- `oliphaunt::__private::BrokerSession.backup()` -- `oliphaunt::__private::BrokerSession.cancel_handle()` -- `oliphaunt::__private::BrokerSession.close()` -- `oliphaunt::__private::BrokerSession.exec_protocol_raw()` -- `oliphaunt::__private::BrokerSession.exec_protocol_raw_stream()` -- `oliphaunt::__private::BrokerSession.execute()` -- `oliphaunt::__private::BrokerStreamOutcome` -- `oliphaunt::__private::broker_ipc_read_request()` -- `oliphaunt::__private::broker_ipc_write_chunk()` -- `oliphaunt::__private::broker_ipc_write_error()` -- `oliphaunt::__private::broker_ipc_write_ok()` -- `oliphaunt::__private::broker_ipc_write_stream_callback_aborted()` -- `oliphaunt::__private::open()` -- `oliphaunt::__private::restore()` - -### Version-locked native packaging seam (not application API) - -The unpublished workspace packaging tool enables `internal-native-packaging` and consumes `oliphaunt::__private::packaging`. It is absent from default builds and may change only in lockstep with that tool. - -- `oliphaunt::__private::packaging::NativePackagingCatalogProfile` -- `oliphaunt::__private::packaging::NativePackagingResources` -- `oliphaunt::__private::packaging::NativePackagingRuntime` -- `oliphaunt::__private::packaging::materialize_native_packaging_resources()` - -## Rust build integration: oliphaunt-build - -- `oliphaunt_build::BuildOutput` -- `oliphaunt_build::BuildOutput.cargo_instructions` -- `oliphaunt_build::BuildOutput.generated_rust` -- `oliphaunt_build::BuildOutput.lock_file` -- `oliphaunt_build::BuildOutput.resources_dir` -- `oliphaunt_build::Error` -- `oliphaunt_build::configure()` -- `oliphaunt_build::try_configure()` - -## Native Rust tools: oliphaunt-tools - -- `oliphaunt_tools::KIND` -- `oliphaunt_tools::PRODUCT` -- `oliphaunt_tools::PgDumpOptions` -- `oliphaunt_tools::PgDumpOptions.arg()` -- `oliphaunt_tools::PgDumpOptions.args()` -- `oliphaunt_tools::PgDumpOptions.new()` -- `oliphaunt_tools::PostgresToolError` -- `oliphaunt_tools::PostgresToolError.exit_code` -- `oliphaunt_tools::PostgresToolError.stderr` -- `oliphaunt_tools::PostgresToolError.stdout` -- `oliphaunt_tools::PostgresToolError.tool` -- `oliphaunt_tools::PsqlOptions` -- `oliphaunt_tools::PsqlOptions.arg()` -- `oliphaunt_tools::PsqlOptions.args()` -- `oliphaunt_tools::PsqlOptions.command()` -- `oliphaunt_tools::PsqlOptions.new()` -- `oliphaunt_tools::PsqlOptions.script()` -- `oliphaunt_tools::pg_dump()` -- `oliphaunt_tools::psql()` - -## Rust WASIX: oliphaunt-wasix - -### Default Cargo features (cross-target union) - -These symbols require no optional Cargo feature. Target-gated symbols (for example Unix-domain listener helpers) remain a cross-target union; consumer compile tests own target availability. - -- `oliphaunt_wasix::AsyncOliphaunt` -- `oliphaunt_wasix::AsyncOliphaunt.backup()` -- `oliphaunt_wasix::AsyncOliphaunt.builder()` -- `oliphaunt_wasix::AsyncOliphaunt.close()` -- `oliphaunt_wasix::AsyncOliphaunt.describe()` -- `oliphaunt_wasix::AsyncOliphaunt.exec()` -- `oliphaunt_wasix::AsyncOliphaunt.exec_protocol_raw()` -- `oliphaunt_wasix::AsyncOliphaunt.exec_protocol_raw_stream()` -- `oliphaunt_wasix::AsyncOliphaunt.execute()` -- `oliphaunt_wasix::AsyncOliphaunt.execute_with_params()` -- `oliphaunt_wasix::AsyncOliphaunt.is_closed()` -- `oliphaunt_wasix::AsyncOliphaunt.open()` -- `oliphaunt_wasix::AsyncOliphaunt.query()` -- `oliphaunt_wasix::AsyncOliphaunt.query_with_params()` -- `oliphaunt_wasix::AsyncOliphaunt.restore()` -- `oliphaunt_wasix::AsyncOliphaunt.sql()` -- `oliphaunt_wasix::AsyncOliphaunt.transaction()` -- `oliphaunt_wasix::AsyncOliphauntBuilder` -- `oliphaunt_wasix::AsyncOliphauntBuilder.database()` -- `oliphaunt_wasix::AsyncOliphauntBuilder.new()` -- `oliphaunt_wasix::AsyncOliphauntBuilder.open()` -- `oliphaunt_wasix::AsyncOliphauntBuilder.startup_guc()` -- `oliphaunt_wasix::AsyncOliphauntBuilder.startup_gucs()` -- `oliphaunt_wasix::AsyncOliphauntBuilder.storage()` -- `oliphaunt_wasix::AsyncOliphauntBuilder.username()` -- `oliphaunt_wasix::AsyncOliphauntServer` -- `oliphaunt_wasix::AsyncOliphauntServer.builder()` -- `oliphaunt_wasix::AsyncOliphauntServer.close()` -- `oliphaunt_wasix::AsyncOliphauntServer.connection_string()` -- `oliphaunt_wasix::AsyncOliphauntServer.is_closed()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.database()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.listen()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.new()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.start()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.startup_guc()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.startup_gucs()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.storage()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.username()` -- `oliphaunt_wasix::AsyncSql` -- `oliphaunt_wasix::AsyncSql.bind()` -- `oliphaunt_wasix::AsyncSql.bind_parameter()` -- `oliphaunt_wasix::AsyncSql.describe()` -- `oliphaunt_wasix::AsyncSql.execute()` -- `oliphaunt_wasix::AsyncSql.query()` -- `oliphaunt_wasix::AsyncSql.result_format()` -- `oliphaunt_wasix::AsyncTransaction` -- `oliphaunt_wasix::AsyncTransaction.describe()` -- `oliphaunt_wasix::AsyncTransaction.exec()` -- `oliphaunt_wasix::AsyncTransaction.execute()` -- `oliphaunt_wasix::AsyncTransaction.execute_with_params()` -- `oliphaunt_wasix::AsyncTransaction.is_closed()` -- `oliphaunt_wasix::AsyncTransaction.query()` -- `oliphaunt_wasix::AsyncTransaction.query_with_params()` -- `oliphaunt_wasix::AsyncTransaction.rollback()` -- `oliphaunt_wasix::AsyncTransaction.sql()` -- `oliphaunt_wasix::CommandResult` -- `oliphaunt_wasix::CommandResult.command_tag()` -- `oliphaunt_wasix::CommandResult.notices()` -- `oliphaunt_wasix::CommandResult.row_count()` -- `oliphaunt_wasix::DatabaseStorage` -- `oliphaunt_wasix::DecodeError` -- `oliphaunt_wasix::Error` -- `oliphaunt_wasix::Error.kind()` -- `oliphaunt_wasix::Error.postgres_error()` -- `oliphaunt_wasix::Error.storage_error()` -- `oliphaunt_wasix::Error.transaction_callback_database_errors()` -- `oliphaunt_wasix::Error.transaction_rollback_errors()` -- `oliphaunt_wasix::ErrorKind` -- `oliphaunt_wasix::ExecResult` -- `oliphaunt_wasix::ExecResult.notices()` -- `oliphaunt_wasix::ExecResult.statements()` -- `oliphaunt_wasix::FromSql` -- `oliphaunt_wasix::FromSql.check_type()` -- `oliphaunt_wasix::FromSql.from_sql()` -- `oliphaunt_wasix::IntoParameter` -- `oliphaunt_wasix::IntoParameter.TYPE_OID` -- `oliphaunt_wasix::IntoParameter.into_parameter()` -- `oliphaunt_wasix::Oliphaunt` -- `oliphaunt_wasix::Oliphaunt.backup()` -- `oliphaunt_wasix::Oliphaunt.builder()` -- `oliphaunt_wasix::Oliphaunt.close()` -- `oliphaunt_wasix::Oliphaunt.describe()` -- `oliphaunt_wasix::Oliphaunt.exec()` -- `oliphaunt_wasix::Oliphaunt.exec_protocol_raw()` -- `oliphaunt_wasix::Oliphaunt.exec_protocol_raw_stream()` -- `oliphaunt_wasix::Oliphaunt.execute()` -- `oliphaunt_wasix::Oliphaunt.execute_with_params()` -- `oliphaunt_wasix::Oliphaunt.is_closed()` -- `oliphaunt_wasix::Oliphaunt.open()` -- `oliphaunt_wasix::Oliphaunt.query()` -- `oliphaunt_wasix::Oliphaunt.query_with_params()` -- `oliphaunt_wasix::Oliphaunt.restore()` -- `oliphaunt_wasix::Oliphaunt.sql()` -- `oliphaunt_wasix::Oliphaunt.transaction()` -- `oliphaunt_wasix::OliphauntBuilder` -- `oliphaunt_wasix::OliphauntBuilder.database()` -- `oliphaunt_wasix::OliphauntBuilder.new()` -- `oliphaunt_wasix::OliphauntBuilder.open()` -- `oliphaunt_wasix::OliphauntBuilder.startup_guc()` -- `oliphaunt_wasix::OliphauntBuilder.startup_gucs()` -- `oliphaunt_wasix::OliphauntBuilder.storage()` -- `oliphaunt_wasix::OliphauntBuilder.username()` -- `oliphaunt_wasix::OliphauntServer` -- `oliphaunt_wasix::OliphauntServer.builder()` -- `oliphaunt_wasix::OliphauntServer.close()` -- `oliphaunt_wasix::OliphauntServer.connection_string()` -- `oliphaunt_wasix::OliphauntServer.is_closed()` -- `oliphaunt_wasix::OliphauntServerBuilder` -- `oliphaunt_wasix::OliphauntServerBuilder.database()` -- `oliphaunt_wasix::OliphauntServerBuilder.listen()` -- `oliphaunt_wasix::OliphauntServerBuilder.new()` -- `oliphaunt_wasix::OliphauntServerBuilder.start()` -- `oliphaunt_wasix::OliphauntServerBuilder.startup_guc()` -- `oliphaunt_wasix::OliphauntServerBuilder.startup_gucs()` -- `oliphaunt_wasix::OliphauntServerBuilder.storage()` -- `oliphaunt_wasix::OliphauntServerBuilder.username()` -- `oliphaunt_wasix::Parameter` -- `oliphaunt_wasix::Parameter.binary()` -- `oliphaunt_wasix::Parameter.format()` -- `oliphaunt_wasix::Parameter.null()` -- `oliphaunt_wasix::Parameter.text()` -- `oliphaunt_wasix::Parameter.type_oid()` -- `oliphaunt_wasix::Parameter.typed_binary()` -- `oliphaunt_wasix::Parameter.typed_null()` -- `oliphaunt_wasix::Parameter.typed_text()` -- `oliphaunt_wasix::Parameter.value()` -- `oliphaunt_wasix::Parameter.with_type_oid()` -- `oliphaunt_wasix::PostgresError` -- `oliphaunt_wasix::PostgresError.column_name` -- `oliphaunt_wasix::PostgresError.constraint_name` -- `oliphaunt_wasix::PostgresError.data_type_name` -- `oliphaunt_wasix::PostgresError.detail` -- `oliphaunt_wasix::PostgresError.fields` -- `oliphaunt_wasix::PostgresError.file` -- `oliphaunt_wasix::PostgresError.hint` -- `oliphaunt_wasix::PostgresError.internal_position` -- `oliphaunt_wasix::PostgresError.internal_query` -- `oliphaunt_wasix::PostgresError.line` -- `oliphaunt_wasix::PostgresError.localized_severity` -- `oliphaunt_wasix::PostgresError.message` -- `oliphaunt_wasix::PostgresError.nonlocalized_severity` -- `oliphaunt_wasix::PostgresError.notices` -- `oliphaunt_wasix::PostgresError.position` -- `oliphaunt_wasix::PostgresError.routine` -- `oliphaunt_wasix::PostgresError.schema_name` -- `oliphaunt_wasix::PostgresError.severity` -- `oliphaunt_wasix::PostgresError.sqlstate` -- `oliphaunt_wasix::PostgresError.table_name` -- `oliphaunt_wasix::PostgresError.where_` -- `oliphaunt_wasix::PostgresErrorField` -- `oliphaunt_wasix::PostgresErrorField.code` -- `oliphaunt_wasix::PostgresErrorField.value` -- `oliphaunt_wasix::PostgresNotice` -- `oliphaunt_wasix::PostgresNotice.column_name` -- `oliphaunt_wasix::PostgresNotice.constraint_name` -- `oliphaunt_wasix::PostgresNotice.data_type_name` -- `oliphaunt_wasix::PostgresNotice.detail` -- `oliphaunt_wasix::PostgresNotice.fields` -- `oliphaunt_wasix::PostgresNotice.file` -- `oliphaunt_wasix::PostgresNotice.hint` -- `oliphaunt_wasix::PostgresNotice.internal_position` -- `oliphaunt_wasix::PostgresNotice.internal_query` -- `oliphaunt_wasix::PostgresNotice.line` -- `oliphaunt_wasix::PostgresNotice.localized_severity` -- `oliphaunt_wasix::PostgresNotice.message` -- `oliphaunt_wasix::PostgresNotice.nonlocalized_severity` -- `oliphaunt_wasix::PostgresNotice.position` -- `oliphaunt_wasix::PostgresNotice.routine` -- `oliphaunt_wasix::PostgresNotice.schema_name` -- `oliphaunt_wasix::PostgresNotice.severity` -- `oliphaunt_wasix::PostgresNotice.sqlstate` -- `oliphaunt_wasix::PostgresNotice.table_name` -- `oliphaunt_wasix::PostgresNotice.where_` -- `oliphaunt_wasix::QueryField` -- `oliphaunt_wasix::QueryField.format` -- `oliphaunt_wasix::QueryField.name` -- `oliphaunt_wasix::QueryField.table_attribute` -- `oliphaunt_wasix::QueryField.table_oid` -- `oliphaunt_wasix::QueryField.type_modifier` -- `oliphaunt_wasix::QueryField.type_oid` -- `oliphaunt_wasix::QueryField.type_oid_value()` -- `oliphaunt_wasix::QueryField.type_size` -- `oliphaunt_wasix::QueryFormat` -- `oliphaunt_wasix::QueryResult` -- `oliphaunt_wasix::QueryResult.command_tag()` -- `oliphaunt_wasix::QueryResult.fields()` -- `oliphaunt_wasix::QueryResult.get_text()` -- `oliphaunt_wasix::QueryResult.notices()` -- `oliphaunt_wasix::QueryResult.row_count()` -- `oliphaunt_wasix::QueryResult.rows()` -- `oliphaunt_wasix::QueryRow` -- `oliphaunt_wasix::QueryRow.fields()` -- `oliphaunt_wasix::QueryRow.is_empty()` -- `oliphaunt_wasix::QueryRow.len()` -- `oliphaunt_wasix::QueryRow.text()` -- `oliphaunt_wasix::QueryRow.try_get()` -- `oliphaunt_wasix::QueryRow.try_get_raw()` -- `oliphaunt_wasix::QueryRow.values()` -- `oliphaunt_wasix::RawStreamCallbackOutput` -- `oliphaunt_wasix::RawStreamCallbackOutput.Error` -- `oliphaunt_wasix::RawStreamError` -- `oliphaunt_wasix::RawStreamError.callback_error()` -- `oliphaunt_wasix::RawStreamError.callback_panic_error()` -- `oliphaunt_wasix::RawStreamError.database_error()` -- `oliphaunt_wasix::RawStreamResult` -- `oliphaunt_wasix::Result` -- `oliphaunt_wasix::RowIndex` -- `oliphaunt_wasix::RowIndex.resolve()` -- `oliphaunt_wasix::ServerListen` -- `oliphaunt_wasix::ServerListen.tcp()` -- `oliphaunt_wasix::ServerListen.tcp_port()` -- `oliphaunt_wasix::ServerListen.unix()` -- `oliphaunt_wasix::ServerListen.unix_port()` -- `oliphaunt_wasix::Sql` -- `oliphaunt_wasix::Sql.bind()` -- `oliphaunt_wasix::Sql.bind_parameter()` -- `oliphaunt_wasix::Sql.describe()` -- `oliphaunt_wasix::Sql.execute()` -- `oliphaunt_wasix::Sql.query()` -- `oliphaunt_wasix::Sql.result_format()` -- `oliphaunt_wasix::StatementDescription` -- `oliphaunt_wasix::StatementDescription.fields()` -- `oliphaunt_wasix::StatementDescription.notices()` -- `oliphaunt_wasix::StatementDescription.parameter_types()` -- `oliphaunt_wasix::StatementResult` -- `oliphaunt_wasix::StorageCommitState` -- `oliphaunt_wasix::StorageErrorCode` -- `oliphaunt_wasix::StorageErrorDetails` -- `oliphaunt_wasix::StorageErrorDetails.code()` -- `oliphaunt_wasix::StorageErrorDetails.commit_state()` -- `oliphaunt_wasix::StorageErrorDetails.phase()` -- `oliphaunt_wasix::StorageErrorPhase` -- `oliphaunt_wasix::Transaction` -- `oliphaunt_wasix::Transaction.describe()` -- `oliphaunt_wasix::Transaction.exec()` -- `oliphaunt_wasix::Transaction.execute()` -- `oliphaunt_wasix::Transaction.execute_with_params()` -- `oliphaunt_wasix::Transaction.is_closed()` -- `oliphaunt_wasix::Transaction.query()` -- `oliphaunt_wasix::Transaction.query_with_params()` -- `oliphaunt_wasix::Transaction.rollback()` -- `oliphaunt_wasix::Transaction.sql()` -- `oliphaunt_wasix::TransactionError` -- `oliphaunt_wasix::TransactionError.callback()` -- `oliphaunt_wasix::TransactionError.callback_error()` -- `oliphaunt_wasix::TransactionError.database_error()` -- `oliphaunt_wasix::TransactionError.rollback_error()` -- `oliphaunt_wasix::TransactionResult` -- `oliphaunt_wasix::TypeOid` -- `oliphaunt_wasix::TypeOid.BOOL` -- `oliphaunt_wasix::TypeOid.BOOL_ARRAY` -- `oliphaunt_wasix::TypeOid.BPCHAR` -- `oliphaunt_wasix::TypeOid.BPCHAR_ARRAY` -- `oliphaunt_wasix::TypeOid.BYTEA` -- `oliphaunt_wasix::TypeOid.BYTEA_ARRAY` -- `oliphaunt_wasix::TypeOid.CHAR` -- `oliphaunt_wasix::TypeOid.CHAR_ARRAY` -- `oliphaunt_wasix::TypeOid.DATE` -- `oliphaunt_wasix::TypeOid.DATE_ARRAY` -- `oliphaunt_wasix::TypeOid.FLOAT4` -- `oliphaunt_wasix::TypeOid.FLOAT4_ARRAY` -- `oliphaunt_wasix::TypeOid.FLOAT8` -- `oliphaunt_wasix::TypeOid.FLOAT8_ARRAY` -- `oliphaunt_wasix::TypeOid.INT2` -- `oliphaunt_wasix::TypeOid.INT2_ARRAY` -- `oliphaunt_wasix::TypeOid.INT4` -- `oliphaunt_wasix::TypeOid.INT4_ARRAY` -- `oliphaunt_wasix::TypeOid.INT8` -- `oliphaunt_wasix::TypeOid.INT8_ARRAY` -- `oliphaunt_wasix::TypeOid.INTERVAL` -- `oliphaunt_wasix::TypeOid.INTERVAL_ARRAY` -- `oliphaunt_wasix::TypeOid.JSON` -- `oliphaunt_wasix::TypeOid.JSONB` -- `oliphaunt_wasix::TypeOid.JSONB_ARRAY` -- `oliphaunt_wasix::TypeOid.JSON_ARRAY` -- `oliphaunt_wasix::TypeOid.NAME` -- `oliphaunt_wasix::TypeOid.NAME_ARRAY` -- `oliphaunt_wasix::TypeOid.NUMERIC` -- `oliphaunt_wasix::TypeOid.NUMERIC_ARRAY` -- `oliphaunt_wasix::TypeOid.OID` -- `oliphaunt_wasix::TypeOid.OID_ARRAY` -- `oliphaunt_wasix::TypeOid.TEXT` -- `oliphaunt_wasix::TypeOid.TEXT_ARRAY` -- `oliphaunt_wasix::TypeOid.TIME` -- `oliphaunt_wasix::TypeOid.TIMESTAMP` -- `oliphaunt_wasix::TypeOid.TIMESTAMPTZ` -- `oliphaunt_wasix::TypeOid.TIMESTAMPTZ_ARRAY` -- `oliphaunt_wasix::TypeOid.TIMESTAMP_ARRAY` -- `oliphaunt_wasix::TypeOid.TIMETZ` -- `oliphaunt_wasix::TypeOid.TIMETZ_ARRAY` -- `oliphaunt_wasix::TypeOid.TIME_ARRAY` -- `oliphaunt_wasix::TypeOid.UNKNOWN` -- `oliphaunt_wasix::TypeOid.UUID` -- `oliphaunt_wasix::TypeOid.UUID_ARRAY` -- `oliphaunt_wasix::TypeOid.VARCHAR` -- `oliphaunt_wasix::TypeOid.VARCHAR_ARRAY` -- `oliphaunt_wasix::TypeOid.XML` -- `oliphaunt_wasix::TypeOid.XML_ARRAY` -- `oliphaunt_wasix::TypeOid.get()` -- `oliphaunt_wasix::TypeOid.new()` -- `oliphaunt_wasix::ValueFormat` -- `oliphaunt_wasix::ValueRef` -- `oliphaunt_wasix::ValueRef.as_bytes()` -- `oliphaunt_wasix::ValueRef.column()` -- `oliphaunt_wasix::ValueRef.field()` -- `oliphaunt_wasix::ValueRef.format()` -- `oliphaunt_wasix::ValueRef.is_null()` -- `oliphaunt_wasix::ValueRef.type_oid()` - -### `extensions` feature - -- `oliphaunt_wasix::AsyncOliphauntBuilder.extension()` -- `oliphaunt_wasix::AsyncOliphauntBuilder.extensions()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.extension()` -- `oliphaunt_wasix::AsyncOliphauntServerBuilder.extensions()` -- `oliphaunt_wasix::Extension` -- `oliphaunt_wasix::Extension.ALL` -- `oliphaunt_wasix::Extension.by_sql_name()` -- `oliphaunt_wasix::Extension.sql_name()` -- `oliphaunt_wasix::OliphauntBuilder.extension()` -- `oliphaunt_wasix::OliphauntBuilder.extensions()` -- `oliphaunt_wasix::OliphauntServerBuilder.extension()` -- `oliphaunt_wasix::OliphauntServerBuilder.extensions()` - -### `tools` feature - -- `oliphaunt_wasix::AsyncOliphaunt.pg_dump()` -- `oliphaunt_wasix::AsyncOliphaunt.psql()` -- `oliphaunt_wasix::Error.tool_error()` -- `oliphaunt_wasix::Oliphaunt.pg_dump()` -- `oliphaunt_wasix::Oliphaunt.pg_dump_output()` -- `oliphaunt_wasix::Oliphaunt.psql()` -- `oliphaunt_wasix::Oliphaunt.psql_output()` -- `oliphaunt_wasix::tools::PgDumpOptions` -- `oliphaunt_wasix::tools::PgDumpOptions.arg()` -- `oliphaunt_wasix::tools::PgDumpOptions.args()` -- `oliphaunt_wasix::tools::PgDumpOptions.new()` -- `oliphaunt_wasix::tools::PostgresToolError` -- `oliphaunt_wasix::tools::PostgresToolError.exit_code()` -- `oliphaunt_wasix::tools::PostgresToolError.stderr()` -- `oliphaunt_wasix::tools::PostgresToolError.stderr_bytes()` -- `oliphaunt_wasix::tools::PostgresToolError.stdout()` -- `oliphaunt_wasix::tools::PostgresToolError.stdout_bytes()` -- `oliphaunt_wasix::tools::PostgresToolError.tool()` -- `oliphaunt_wasix::tools::PostgresToolOutput` -- `oliphaunt_wasix::tools::PostgresToolOutput.into_parts()` -- `oliphaunt_wasix::tools::PostgresToolOutput.stderr()` -- `oliphaunt_wasix::tools::PostgresToolOutput.stdout()` -- `oliphaunt_wasix::tools::PsqlOptions` -- `oliphaunt_wasix::tools::PsqlOptions.arg()` -- `oliphaunt_wasix::tools::PsqlOptions.args()` -- `oliphaunt_wasix::tools::PsqlOptions.command()` -- `oliphaunt_wasix::tools::PsqlOptions.new()` -- `oliphaunt_wasix::tools::PsqlOptions.script()` - -### Individual `extension-*` features - -Each leaf feature also enables `extensions`; the constant below additionally requires the feature shown. - -- `extension-amcheck`: `oliphaunt_wasix::Extension.AMCHECK` -- `extension-auto-explain`: `oliphaunt_wasix::Extension.AUTO_EXPLAIN` -- `extension-bloom`: `oliphaunt_wasix::Extension.BLOOM` -- `extension-btree-gin`: `oliphaunt_wasix::Extension.BTREE_GIN` -- `extension-btree-gist`: `oliphaunt_wasix::Extension.BTREE_GIST` -- `extension-citext`: `oliphaunt_wasix::Extension.CITEXT` -- `extension-cube`: `oliphaunt_wasix::Extension.CUBE` -- `extension-dict-int`: `oliphaunt_wasix::Extension.DICT_INT` -- `extension-dict-xsyn`: `oliphaunt_wasix::Extension.DICT_XSYN` -- `extension-earthdistance`: `oliphaunt_wasix::Extension.EARTHDISTANCE` -- `extension-file-fdw`: `oliphaunt_wasix::Extension.FILE_FDW` -- `extension-fuzzystrmatch`: `oliphaunt_wasix::Extension.FUZZYSTRMATCH` -- `extension-hstore`: `oliphaunt_wasix::Extension.HSTORE` -- `extension-intarray`: `oliphaunt_wasix::Extension.INTARRAY` -- `extension-isn`: `oliphaunt_wasix::Extension.ISN` -- `extension-lo`: `oliphaunt_wasix::Extension.LO` -- `extension-ltree`: `oliphaunt_wasix::Extension.LTREE` -- `extension-pageinspect`: `oliphaunt_wasix::Extension.PAGEINSPECT` -- `extension-pg-buffercache`: `oliphaunt_wasix::Extension.PG_BUFFERCACHE` -- `extension-pg-freespacemap`: `oliphaunt_wasix::Extension.PG_FREESPACEMAP` -- `extension-pg-hashids`: `oliphaunt_wasix::Extension.PG_HASHIDS` -- `extension-pg-ivm`: `oliphaunt_wasix::Extension.PG_IVM` -- `extension-pg-surgery`: `oliphaunt_wasix::Extension.PG_SURGERY` -- `extension-pg-textsearch`: `oliphaunt_wasix::Extension.PG_TEXTSEARCH` -- `extension-pg-trgm`: `oliphaunt_wasix::Extension.PG_TRGM` -- `extension-pg-uuidv7`: `oliphaunt_wasix::Extension.PG_UUIDV7` -- `extension-pg-visibility`: `oliphaunt_wasix::Extension.PG_VISIBILITY` -- `extension-pg-walinspect`: `oliphaunt_wasix::Extension.PG_WALINSPECT` -- `extension-pgcrypto`: `oliphaunt_wasix::Extension.PGCRYPTO` -- `extension-pgtap`: `oliphaunt_wasix::Extension.PGTAP` -- `extension-postgis`: `oliphaunt_wasix::Extension.POSTGIS` -- `extension-seg`: `oliphaunt_wasix::Extension.SEG` -- `extension-tablefunc`: `oliphaunt_wasix::Extension.TABLEFUNC` -- `extension-tcn`: `oliphaunt_wasix::Extension.TCN` -- `extension-tsm-system-rows`: `oliphaunt_wasix::Extension.TSM_SYSTEM_ROWS` -- `extension-tsm-system-time`: `oliphaunt_wasix::Extension.TSM_SYSTEM_TIME` -- `extension-unaccent`: `oliphaunt_wasix::Extension.UNACCENT` -- `extension-uuid-ossp`: `oliphaunt_wasix::Extension.UUID_OSSP` -- `extension-vector`: `oliphaunt_wasix::Extension.VECTOR` - -## Native C ABI: liboliphaunt - -### Types - -- `OliphauntConfig` -- `OliphauntErrorCapture` -- `OliphauntHandle` -- `OliphauntResponse` -- `OliphauntRestoreOptions` -- `OliphauntStaticExtension` -- `OliphauntStaticExtensionSymbol` -- `OliphauntStreamCallback` - -### Constants - -- `OLIPHAUNT_ABI_VERSION` -- `OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK` -- `OLIPHAUNT_ERROR_CAPTURE_CAPACITY` -- `OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION` -- `OLIPHAUNT_STREAM_CALLBACK_ABORTED` - -### Functions - -- `oliphaunt_backup()` -- `oliphaunt_backup_with_error()` -- `oliphaunt_cancel()` -- `oliphaunt_close()` -- `oliphaunt_close_if_generation()` -- `oliphaunt_copy_last_error()` -- `oliphaunt_detach()` -- `oliphaunt_detach_with_error()` -- `oliphaunt_exec_protocol()` -- `oliphaunt_exec_protocol_raw_stream()` -- `oliphaunt_exec_protocol_raw_stream_with_error()` -- `oliphaunt_exec_protocol_with_error()` -- `oliphaunt_exec_simple_query()` -- `oliphaunt_exec_simple_query_with_error()` -- `oliphaunt_free_response()` -- `oliphaunt_init()` -- `oliphaunt_init_with_error()` -- `oliphaunt_logical_generation()` -- `oliphaunt_register_static_extensions()` -- `oliphaunt_restore()` -- `oliphaunt_restore_with_error()` -- `oliphaunt_version()` - -## Swift: Oliphaunt - -- `OliphauntCommandResult.commandTag` -- `OliphauntCommandResult.init` -- `OliphauntCommandResult.notices` -- `OliphauntCommandResult.rowCount` -- `OliphauntConfiguration.database` -- `OliphauntConfiguration.extensions` -- `OliphauntConfiguration.init` -- `OliphauntConfiguration.startupGUCs` -- `OliphauntConfiguration.storage` -- `OliphauntConfiguration.username` -- `OliphauntDatabase.backup()` -- `OliphauntDatabase.cancel()` -- `OliphauntDatabase.close()` -- `OliphauntDatabase.describe()` -- `OliphauntDatabase.exec()` -- `OliphauntDatabase.execProtocolRaw()` -- `OliphauntDatabase.execProtocolRawStream()` -- `OliphauntDatabase.execute()` -- `OliphauntDatabase.isClosed` -- `OliphauntDatabase.open()` -- `OliphauntDatabase.query()` -- `OliphauntDatabase.restore()` -- `OliphauntDatabase.transaction()` -- `OliphauntError.description` -- `OliphauntExecResult.init` -- `OliphauntExecResult.notices` -- `OliphauntExecResult.statements` -- `OliphauntPostgresDecodable.decodePostgres()` -- `OliphauntPostgresDiagnostic.columnName` -- `OliphauntPostgresDiagnostic.constraintName` -- `OliphauntPostgresDiagnostic.dataTypeName` -- `OliphauntPostgresDiagnostic.description` -- `OliphauntPostgresDiagnostic.detail` -- `OliphauntPostgresDiagnostic.fields` -- `OliphauntPostgresDiagnostic.file` -- `OliphauntPostgresDiagnostic.hint` -- `OliphauntPostgresDiagnostic.init` -- `OliphauntPostgresDiagnostic.internalPosition` -- `OliphauntPostgresDiagnostic.internalQuery` -- `OliphauntPostgresDiagnostic.line` -- `OliphauntPostgresDiagnostic.localizedSeverity` -- `OliphauntPostgresDiagnostic.message` -- `OliphauntPostgresDiagnostic.nonlocalizedSeverity` -- `OliphauntPostgresDiagnostic.position` -- `OliphauntPostgresDiagnostic.routine` -- `OliphauntPostgresDiagnostic.schemaName` -- `OliphauntPostgresDiagnostic.severity` -- `OliphauntPostgresDiagnostic.sqlstate` -- `OliphauntPostgresDiagnostic.tableName` -- `OliphauntPostgresDiagnostic.whereText` -- `OliphauntPostgresError.columnName` -- `OliphauntPostgresError.constraintName` -- `OliphauntPostgresError.dataTypeName` -- `OliphauntPostgresError.description` -- `OliphauntPostgresError.detail` -- `OliphauntPostgresError.diagnostic` -- `OliphauntPostgresError.fields` -- `OliphauntPostgresError.file` -- `OliphauntPostgresError.hint` -- `OliphauntPostgresError.init` -- `OliphauntPostgresError.internalPosition` -- `OliphauntPostgresError.internalQuery` -- `OliphauntPostgresError.line` -- `OliphauntPostgresError.localizedSeverity` -- `OliphauntPostgresError.message` -- `OliphauntPostgresError.nonlocalizedSeverity` -- `OliphauntPostgresError.notices` -- `OliphauntPostgresError.position` -- `OliphauntPostgresError.routine` -- `OliphauntPostgresError.schemaName` -- `OliphauntPostgresError.severity` -- `OliphauntPostgresError.sqlstate` -- `OliphauntPostgresError.tableName` -- `OliphauntPostgresError.whereText` -- `OliphauntPostgresErrorField.code` -- `OliphauntPostgresErrorField.init` -- `OliphauntPostgresErrorField.value` -- `OliphauntPostgresOID.bool` -- `OliphauntPostgresOID.boolArray` -- `OliphauntPostgresOID.bpchar` -- `OliphauntPostgresOID.bpcharArray` -- `OliphauntPostgresOID.bytea` -- `OliphauntPostgresOID.byteaArray` -- `OliphauntPostgresOID.char` -- `OliphauntPostgresOID.charArray` -- `OliphauntPostgresOID.date` -- `OliphauntPostgresOID.dateArray` -- `OliphauntPostgresOID.description` -- `OliphauntPostgresOID.float4` -- `OliphauntPostgresOID.float4Array` -- `OliphauntPostgresOID.float8` -- `OliphauntPostgresOID.float8Array` -- `OliphauntPostgresOID.init` -- `OliphauntPostgresOID.int2` -- `OliphauntPostgresOID.int2Array` -- `OliphauntPostgresOID.int4` -- `OliphauntPostgresOID.int4Array` -- `OliphauntPostgresOID.int8` -- `OliphauntPostgresOID.int8Array` -- `OliphauntPostgresOID.interval` -- `OliphauntPostgresOID.intervalArray` -- `OliphauntPostgresOID.json` -- `OliphauntPostgresOID.jsonArray` -- `OliphauntPostgresOID.jsonb` -- `OliphauntPostgresOID.jsonbArray` -- `OliphauntPostgresOID.name` -- `OliphauntPostgresOID.nameArray` -- `OliphauntPostgresOID.numeric` -- `OliphauntPostgresOID.numericArray` -- `OliphauntPostgresOID.oid` -- `OliphauntPostgresOID.oidArray` -- `OliphauntPostgresOID.rawValue` -- `OliphauntPostgresOID.text` -- `OliphauntPostgresOID.textArray` -- `OliphauntPostgresOID.time` -- `OliphauntPostgresOID.timeArray` -- `OliphauntPostgresOID.timestamp` -- `OliphauntPostgresOID.timestampArray` -- `OliphauntPostgresOID.timestamptz` -- `OliphauntPostgresOID.timestamptzArray` -- `OliphauntPostgresOID.timetz` -- `OliphauntPostgresOID.timetzArray` -- `OliphauntPostgresOID.unknown` -- `OliphauntPostgresOID.uuid` -- `OliphauntPostgresOID.uuidArray` -- `OliphauntPostgresOID.varchar` -- `OliphauntPostgresOID.varcharArray` -- `OliphauntPostgresOID.xml` -- `OliphauntPostgresOID.xmlArray` -- `OliphauntQueryDescription.fields` -- `OliphauntQueryDescription.init` -- `OliphauntQueryDescription.notices` -- `OliphauntQueryDescription.parameterTypes` -- `OliphauntQueryField.format` -- `OliphauntQueryField.name` -- `OliphauntQueryField.tableAttribute` -- `OliphauntQueryField.tableOID` -- `OliphauntQueryField.typeModifier` -- `OliphauntQueryField.typeOID` -- `OliphauntQueryField.typeSize` -- `OliphauntQueryParam.binary()` -- `OliphauntQueryParam.bool()` -- `OliphauntQueryParam.bytes` -- `OliphauntQueryParam.bytes()` -- `OliphauntQueryParam.double()` -- `OliphauntQueryParam.float()` -- `OliphauntQueryParam.format` -- `OliphauntQueryParam.init` -- `OliphauntQueryParam.int16()` -- `OliphauntQueryParam.int32()` -- `OliphauntQueryParam.int64()` -- `OliphauntQueryParam.null` -- `OliphauntQueryParam.string()` -- `OliphauntQueryParam.text()` -- `OliphauntQueryParam.typeOID` -- `OliphauntQueryParam.typedNull()` -- `OliphauntQueryParam.uuid()` -- `OliphauntQueryResult.commandTag` -- `OliphauntQueryResult.fields` -- `OliphauntQueryResult.getText()` -- `OliphauntQueryResult.notices` -- `OliphauntQueryResult.rowCount` -- `OliphauntQueryResult.rows` -- `OliphauntQueryRow.raw()` -- `OliphauntQueryRow.text()` -- `OliphauntQueryRow.value()` -- `OliphauntQueryRow.values` -- `OliphauntStartupGUC.init` -- `OliphauntStartupGUC.name` -- `OliphauntStartupGUC.value` -- `OliphauntTransaction.describe()` -- `OliphauntTransaction.exec()` -- `OliphauntTransaction.execute()` -- `OliphauntTransaction.isClosed` -- `OliphauntTransaction.query()` -- `OliphauntTransaction.rollback()` -- `OliphauntTransactionDatabaseError.callbackError` -- `OliphauntTransactionDatabaseError.databaseError` -- `OliphauntTransactionDatabaseError.description` -- `OliphauntTransactionRollbackError.callbackError` -- `OliphauntTransactionRollbackError.description` -- `OliphauntTransactionRollbackError.rollbackError` -- `actor OliphauntDatabase` -- `enum OliphauntDatabaseStorage` -- `enum OliphauntError` -- `enum OliphauntQueryFormat` -- `enum OliphauntStatementResult` -- `enum OliphauntValueFormat` -- `extension OliphauntDatabase` -- `extension OliphauntTransaction` -- `protocol OliphauntPostgresDecodable` -- `struct OliphauntCommandResult` -- `struct OliphauntConfiguration` -- `struct OliphauntExecResult` -- `struct OliphauntPostgresDiagnostic` -- `struct OliphauntPostgresError` -- `struct OliphauntPostgresErrorField` -- `struct OliphauntPostgresOID` -- `struct OliphauntQueryDescription` -- `struct OliphauntQueryField` -- `struct OliphauntQueryParam` -- `struct OliphauntQueryResult` -- `struct OliphauntQueryRow` -- `struct OliphauntStartupGUC` -- `struct OliphauntTransaction` -- `struct OliphauntTransactionDatabaseError` -- `struct OliphauntTransactionRollbackError` -- `typealias OliphauntPostgresNotice` - -## Swift: OliphauntExtensionSupport - -This version-locked carrier seam is consumed by generated Swift extension products. It is not ordinary application API; applications select extensions by SQL name through `Oliphaunt`. See [SDK parity policy](./sdk-parity-policy.md). - -- `OliphauntExtensionSupport.register()` -- `enum OliphauntExtensionSupport` - -## Kotlin: oliphaunt - -### commonMain - -- `CommandResult.commandTag` -- `CommandResult.notices` -- `CommandResult.rowCount` -- `ExecResult.notices` -- `ExecResult.statements` -- `OliphauntDatabase.backup()` -- `OliphauntDatabase.cancel()` -- `OliphauntDatabase.close()` -- `OliphauntDatabase.describe()` -- `OliphauntDatabase.exec()` -- `OliphauntDatabase.execProtocolRaw()` -- `OliphauntDatabase.execProtocolRawStream()` -- `OliphauntDatabase.execute()` -- `OliphauntDatabase.isClosed` -- `OliphauntDatabase.query()` -- `OliphauntDatabase.transaction()` -- `OliphauntTransaction.describe()` -- `OliphauntTransaction.exec()` -- `OliphauntTransaction.execute()` -- `OliphauntTransaction.isClosed` -- `OliphauntTransaction.query()` -- `OliphauntTransaction.rollback()` -- `OliphauntTransactionDatabaseException.callbackError` -- `OliphauntTransactionDatabaseException.databaseError` -- `OliphauntTransactionRollbackException.callbackError` -- `OliphauntTransactionRollbackException.rollbackError` -- `PostgresDecoder.decode()` -- `PostgresDecoders.boolean` -- `PostgresDecoders.bytes` -- `PostgresDecoders.double` -- `PostgresDecoders.float` -- `PostgresDecoders.int` -- `PostgresDecoders.long` -- `PostgresDecoders.short` -- `PostgresDecoders.string` -- `PostgresDecoders.uuidString` -- `PostgresDiagnostic.columnName` -- `PostgresDiagnostic.constraintName` -- `PostgresDiagnostic.dataTypeName` -- `PostgresDiagnostic.detail` -- `PostgresDiagnostic.fields` -- `PostgresDiagnostic.file` -- `PostgresDiagnostic.hint` -- `PostgresDiagnostic.internalPosition` -- `PostgresDiagnostic.internalQuery` -- `PostgresDiagnostic.line` -- `PostgresDiagnostic.localizedSeverity` -- `PostgresDiagnostic.message` -- `PostgresDiagnostic.nonlocalizedSeverity` -- `PostgresDiagnostic.position` -- `PostgresDiagnostic.routine` -- `PostgresDiagnostic.schemaName` -- `PostgresDiagnostic.severity` -- `PostgresDiagnostic.sqlstate` -- `PostgresDiagnostic.tableName` -- `PostgresDiagnostic.whereText` -- `PostgresError.columnName` -- `PostgresError.constraintName` -- `PostgresError.dataTypeName` -- `PostgresError.detail` -- `PostgresError.diagnostic` -- `PostgresError.fields` -- `PostgresError.file` -- `PostgresError.hint` -- `PostgresError.internalPosition` -- `PostgresError.internalQuery` -- `PostgresError.line` -- `PostgresError.localizedSeverity` -- `PostgresError.message` -- `PostgresError.nonlocalizedSeverity` -- `PostgresError.notices` -- `PostgresError.position` -- `PostgresError.routine` -- `PostgresError.schemaName` -- `PostgresError.severity` -- `PostgresError.sqlstate` -- `PostgresError.tableName` -- `PostgresError.whereText` -- `PostgresErrorField.code` -- `PostgresErrorField.value` -- `PostgresException.postgresError` -- `PostgresNotice.columnName` -- `PostgresNotice.constraintName` -- `PostgresNotice.dataTypeName` -- `PostgresNotice.detail` -- `PostgresNotice.diagnostic` -- `PostgresNotice.fields` -- `PostgresNotice.file` -- `PostgresNotice.hint` -- `PostgresNotice.internalPosition` -- `PostgresNotice.internalQuery` -- `PostgresNotice.line` -- `PostgresNotice.localizedSeverity` -- `PostgresNotice.message` -- `PostgresNotice.nonlocalizedSeverity` -- `PostgresNotice.position` -- `PostgresNotice.routine` -- `PostgresNotice.schemaName` -- `PostgresNotice.severity` -- `PostgresNotice.sqlstate` -- `PostgresNotice.tableName` -- `PostgresNotice.whereText` -- `PostgresOid.bool` -- `PostgresOid.boolArray` -- `PostgresOid.bpchar` -- `PostgresOid.bpcharArray` -- `PostgresOid.bytea` -- `PostgresOid.byteaArray` -- `PostgresOid.char` -- `PostgresOid.charArray` -- `PostgresOid.date` -- `PostgresOid.dateArray` -- `PostgresOid.float4` -- `PostgresOid.float4Array` -- `PostgresOid.float8` -- `PostgresOid.float8Array` -- `PostgresOid.int2` -- `PostgresOid.int2Array` -- `PostgresOid.int4` -- `PostgresOid.int4Array` -- `PostgresOid.int8` -- `PostgresOid.int8Array` -- `PostgresOid.interval` -- `PostgresOid.intervalArray` -- `PostgresOid.json` -- `PostgresOid.jsonArray` -- `PostgresOid.jsonb` -- `PostgresOid.jsonbArray` -- `PostgresOid.name` -- `PostgresOid.nameArray` -- `PostgresOid.numeric` -- `PostgresOid.numericArray` -- `PostgresOid.oid` -- `PostgresOid.oidArray` -- `PostgresOid.text` -- `PostgresOid.textArray` -- `PostgresOid.time` -- `PostgresOid.timeArray` -- `PostgresOid.timestamp` -- `PostgresOid.timestampArray` -- `PostgresOid.timestamptz` -- `PostgresOid.timestamptzArray` -- `PostgresOid.timetz` -- `PostgresOid.timetzArray` -- `PostgresOid.unknown` -- `PostgresOid.uuid` -- `PostgresOid.uuidArray` -- `PostgresOid.value` -- `PostgresOid.varchar` -- `PostgresOid.varcharArray` -- `PostgresOid.xml` -- `PostgresOid.xmlArray` -- `PostgresStartupGuc.name` -- `PostgresStartupGuc.value` -- `QueryDescription.fields` -- `QueryDescription.notices` -- `QueryDescription.parameterTypes` -- `QueryField.format` -- `QueryField.name` -- `QueryField.tableAttribute` -- `QueryField.tableOid` -- `QueryField.typeModifier` -- `QueryField.typeOid` -- `QueryField.typeSize` -- `QueryFormat.Other.code` -- `QueryParam.Binary.value` -- `QueryParam.Text.value` -- `QueryParam.binary()` -- `QueryParam.boolean()` -- `QueryParam.bytes` -- `QueryParam.bytes()` -- `QueryParam.double()` -- `QueryParam.float()` -- `QueryParam.format` -- `QueryParam.int()` -- `QueryParam.long()` -- `QueryParam.short()` -- `QueryParam.string()` -- `QueryParam.text()` -- `QueryParam.typeOid` -- `QueryParam.typedNull()` -- `QueryParam.uuid()` -- `QueryResult.commandTag` -- `QueryResult.fields` -- `QueryResult.getText()` -- `QueryResult.notices` -- `QueryResult.rowCount` -- `QueryResult.rows` -- `QueryRow.raw()` -- `QueryRow.text()` -- `QueryRow.value()` -- `QueryRow.values` -- `StatementResult.Command.result` -- `StatementResult.Rows.result` -- `class CommandResult` -- `class ExecResult` -- `class OliphauntDatabase` -- `class OliphauntException` -- `class OliphauntTransaction` -- `class OliphauntTransactionDatabaseException` -- `class OliphauntTransactionRollbackException` -- `class PostgresDiagnostic` -- `class PostgresError` -- `class PostgresErrorField` -- `class PostgresException` -- `class PostgresNotice` -- `class PostgresStartupGuc` -- `class QueryDescription` -- `class QueryField` -- `class QueryFormat` -- `class QueryFormat.Other` -- `class QueryParam` -- `class QueryParam.Binary` -- `class QueryParam.Text` -- `class QueryResult` -- `class QueryRow` -- `class StatementResult.Command` -- `class StatementResult.Rows` -- `enum class ValueFormat` -- `fun interface PostgresDecoder` -- `interface StatementResult` -- `object PostgresDecoders` -- `object QueryFormat.Binary` -- `object QueryFormat.Text` -- `object QueryParam.Null` -- `value class PostgresOid` - -### androidMain - -- `DatabaseStorage.Directory.path` -- `Oliphaunt.open()` -- `Oliphaunt.restore()` -- `OliphauntConfig.database` -- `OliphauntConfig.extensions` -- `OliphauntConfig.startupGucs` -- `OliphauntConfig.storage` -- `OliphauntConfig.username` -- `class DatabaseStorage.Directory` -- `class OliphauntConfig` -- `interface DatabaseStorage` -- `object DatabaseStorage.TemporaryDirectory` -- `object Oliphaunt` - -### jvmMain - -- none - -## Kotlin Android Gradle plugin - -- `OliphauntAndroidExtension.getAndroidAbis()` -- `OliphauntAndroidExtension.getExtensionVersions()` -- `OliphauntAndroidExtension.getIcu()` -- `OliphauntAndroidExtension.getLiboliphauntVersion()` -- `OliphauntAndroidExtension.getSelectedExtensions()` -- `class OliphauntAndroidExtension` -- `plugin dev.oliphaunt.android` - -## React Native: @oliphaunt/react-native - -### Package exports - -- `. = {"types":"./lib/typescript/index.d.ts","react-native":"./lib/module/index.js","import":"./lib/module/index.js","require":"./lib/commonjs/index.js","default":"./lib/module/index.js"}` -- `./package.json = "./package.json"` - -### Types - -- `BinaryInput` -- `BinaryQueryParameter` -- `CommandResult` -- `DatabaseStorage` -- `DescribeResult` -- `EncodedQueryParameter` -- `ExecResult` -- `InferQueryRow` -- `NullQueryParameter` -- `OliphauntClient` -- `OliphauntDatabase` -- `OliphauntTransaction` -- `OpenConfig` -- `ParameterOptions` -- `PostgresErrorField` -- `PostgresNotice` -- `QueryArrayRow` -- `QueryBinaryInput` -- `QueryDecoderMap` -- `QueryField` -- `QueryFormat` -- `QueryObjectRow` -- `QueryOptions` -- `QueryParam` -- `QueryParameterEncoder` -- `QueryResult` -- `QueryRowMode` -- `QueryValue` -- `QueryValueDecoder` -- `RawQueryResult` -- `RawQueryRow` -- `RestoreDestination` -- `TextQueryParameter` -- `TransactionStatus` - -### Values - -- `Oliphaunt` -- `PostgresError` -- `array` -- `binary` -- `json` -- `postgresOids` -- `text` -- `typedNull` - -### Members - -- `BinaryQueryParameter.format` -- `BinaryQueryParameter.typeOid` -- `BinaryQueryParameter.value` -- `CommandResult.commandTag` -- `CommandResult.notices` -- `CommandResult.rowCount` -- `DescribeResult.fields` -- `DescribeResult.notices` -- `DescribeResult.parameterTypeOids` -- `ExecResult.notices` -- `ExecResult.statements` -- `NullQueryParameter.format` -- `NullQueryParameter.typeOid` -- `OliphauntClient.open()` -- `OliphauntClient.restore()` -- `OliphauntDatabase.[Symbol.asyncDispose]()` -- `OliphauntDatabase.backup()` -- `OliphauntDatabase.cancel()` -- `OliphauntDatabase.close()` -- `OliphauntDatabase.closed` -- `OliphauntDatabase.describe()` -- `OliphauntDatabase.exec()` -- `OliphauntDatabase.execProtocolRaw()` -- `OliphauntDatabase.execProtocolRawStream()` -- `OliphauntDatabase.execute()` -- `OliphauntDatabase.query()` -- `OliphauntDatabase.queryRaw()` -- `OliphauntDatabase.transaction()` -- `OliphauntTransaction.closed` -- `OliphauntTransaction.describe()` -- `OliphauntTransaction.exec()` -- `OliphauntTransaction.execute()` -- `OliphauntTransaction.query()` -- `OliphauntTransaction.queryRaw()` -- `OliphauntTransaction.rollback()` -- `OpenConfig.database` -- `OpenConfig.extensions` -- `OpenConfig.startupGUCs` -- `OpenConfig.storage` -- `OpenConfig.username` -- `ParameterOptions.encoders` -- `PostgresError.columnName` -- `PostgresError.constraintName` -- `PostgresError.constructor()` -- `PostgresError.dataTypeName` -- `PostgresError.detail` -- `PostgresError.fields` -- `PostgresError.file` -- `PostgresError.hint` -- `PostgresError.internalPosition` -- `PostgresError.internalQuery` -- `PostgresError.line` -- `PostgresError.localizedSeverity` -- `PostgresError.nonlocalizedSeverity` -- `PostgresError.notices` -- `PostgresError.position` -- `PostgresError.routine` -- `PostgresError.schemaName` -- `PostgresError.severity` -- `PostgresError.sqlstate` -- `PostgresError.tableName` -- `PostgresError.whereText` -- `PostgresErrorField.code` -- `PostgresErrorField.value` -- `PostgresNotice.columnName` -- `PostgresNotice.constraintName` -- `PostgresNotice.dataTypeName` -- `PostgresNotice.detail` -- `PostgresNotice.fields` -- `PostgresNotice.file` -- `PostgresNotice.hint` -- `PostgresNotice.internalPosition` -- `PostgresNotice.internalQuery` -- `PostgresNotice.line` -- `PostgresNotice.localizedSeverity` -- `PostgresNotice.message` -- `PostgresNotice.nonlocalizedSeverity` -- `PostgresNotice.position` -- `PostgresNotice.routine` -- `PostgresNotice.schemaName` -- `PostgresNotice.severity` -- `PostgresNotice.sqlstate` -- `PostgresNotice.tableName` -- `PostgresNotice.whereText` -- `QueryField.format` -- `QueryField.name` -- `QueryField.tableAttribute` -- `QueryField.tableOid` -- `QueryField.typeModifier` -- `QueryField.typeOid` -- `QueryField.typeSize` -- `QueryOptions.decoders` -- `QueryOptions.encoders` -- `QueryOptions.rowMode` -- `QueryOptions.valueMode` -- `QueryResult.commandTag` -- `QueryResult.fields` -- `QueryResult.kind` -- `QueryResult.notices` -- `QueryResult.rowCount` -- `QueryResult.rows` -- `RawQueryResult.commandTag` -- `RawQueryResult.fields` -- `RawQueryResult.getText()` -- `RawQueryResult.kind` -- `RawQueryResult.notices` -- `RawQueryResult.rowCount` -- `RawQueryResult.rows` -- `RawQueryRow.text()` -- `RawQueryRow.values` -- `TextQueryParameter.format` -- `TextQueryParameter.typeOid` -- `TextQueryParameter.value` - -## TypeScript: @oliphaunt/ts - -### Package exports - -- `. = {"types":"./lib/index.d.ts","default":"./lib/index.js"}` -- `./package.json = {"default":"./package.json"}` - -### Types - -- `BinaryInput` -- `BinaryQueryParameter` -- `CommandResult` -- `DatabaseStorage` -- `DescribeResult` -- `EncodedQueryParameter` -- `ExecResult` -- `InferQueryRow` -- `NullQueryParameter` -- `OliphauntClient` -- `OliphauntDatabase` -- `OliphauntServer` -- `OliphauntTransaction` -- `OpenConfig` -- `ParameterOptions` -- `PostgresErrorField` -- `PostgresNotice` -- `QueryArrayRow` -- `QueryBinaryInput` -- `QueryDecoderMap` -- `QueryField` -- `QueryFormat` -- `QueryObjectRow` -- `QueryOptions` -- `QueryParam` -- `QueryParameterEncoder` -- `QueryResult` -- `QueryRowMode` -- `QueryValue` -- `QueryValueDecoder` -- `RawQueryResult` -- `RawQueryRow` -- `RestoreOptions` -- `ServerListen` -- `ServerOpenConfig` -- `TextQueryParameter` -- `TransactionStatus` - -### Values - -- `Oliphaunt` -- `PostgresError` -- `array` -- `binary` -- `json` -- `postgresOids` -- `text` -- `typedNull` - -### Members - -- `BinaryQueryParameter.format` -- `BinaryQueryParameter.typeOid` -- `BinaryQueryParameter.value` -- `CommandResult.commandTag` -- `CommandResult.notices` -- `CommandResult.rowCount` -- `DescribeResult.fields` -- `DescribeResult.notices` -- `DescribeResult.parameterTypeOids` -- `ExecResult.notices` -- `ExecResult.statements` -- `NullQueryParameter.format` -- `NullQueryParameter.typeOid` -- `OliphauntClient.open()` -- `OliphauntClient.openServer()` -- `OliphauntClient.restore()` -- `OliphauntDatabase.[Symbol.asyncDispose]()` -- `OliphauntDatabase.backup()` -- `OliphauntDatabase.cancel()` -- `OliphauntDatabase.close()` -- `OliphauntDatabase.closed` -- `OliphauntDatabase.describe()` -- `OliphauntDatabase.exec()` -- `OliphauntDatabase.execProtocolRaw()` -- `OliphauntDatabase.execProtocolRawStream()` -- `OliphauntDatabase.execute()` -- `OliphauntDatabase.query()` -- `OliphauntDatabase.queryRaw()` -- `OliphauntDatabase.transaction()` -- `OliphauntServer.[Symbol.asyncDispose]()` -- `OliphauntServer.close()` -- `OliphauntServer.closed` -- `OliphauntServer.connectionString` -- `OliphauntTransaction.closed` -- `OliphauntTransaction.describe()` -- `OliphauntTransaction.exec()` -- `OliphauntTransaction.execute()` -- `OliphauntTransaction.query()` -- `OliphauntTransaction.queryRaw()` -- `OliphauntTransaction.rollback()` -- `OpenConfig.brokerExecutable` -- `OpenConfig.database` -- `OpenConfig.extensions` -- `OpenConfig.libraryPath` -- `OpenConfig.runtimeDirectory` -- `OpenConfig.startupGUCs` -- `OpenConfig.storage` -- `OpenConfig.topology` -- `OpenConfig.username` -- `ParameterOptions.encoders` -- `PostgresError.columnName` -- `PostgresError.constraintName` -- `PostgresError.constructor()` -- `PostgresError.dataTypeName` -- `PostgresError.detail` -- `PostgresError.fields` -- `PostgresError.file` -- `PostgresError.hint` -- `PostgresError.internalPosition` -- `PostgresError.internalQuery` -- `PostgresError.line` -- `PostgresError.localizedSeverity` -- `PostgresError.nonlocalizedSeverity` -- `PostgresError.notices` -- `PostgresError.position` -- `PostgresError.routine` -- `PostgresError.schemaName` -- `PostgresError.severity` -- `PostgresError.sqlstate` -- `PostgresError.tableName` -- `PostgresError.whereText` -- `PostgresErrorField.code` -- `PostgresErrorField.value` -- `PostgresNotice.columnName` -- `PostgresNotice.constraintName` -- `PostgresNotice.dataTypeName` -- `PostgresNotice.detail` -- `PostgresNotice.fields` -- `PostgresNotice.file` -- `PostgresNotice.hint` -- `PostgresNotice.internalPosition` -- `PostgresNotice.internalQuery` -- `PostgresNotice.line` -- `PostgresNotice.localizedSeverity` -- `PostgresNotice.message` -- `PostgresNotice.nonlocalizedSeverity` -- `PostgresNotice.position` -- `PostgresNotice.routine` -- `PostgresNotice.schemaName` -- `PostgresNotice.severity` -- `PostgresNotice.sqlstate` -- `PostgresNotice.tableName` -- `PostgresNotice.whereText` -- `QueryField.format` -- `QueryField.name` -- `QueryField.tableAttribute` -- `QueryField.tableOid` -- `QueryField.typeModifier` -- `QueryField.typeOid` -- `QueryField.typeSize` -- `QueryOptions.decoders` -- `QueryOptions.encoders` -- `QueryOptions.rowMode` -- `QueryOptions.valueMode` -- `QueryResult.commandTag` -- `QueryResult.fields` -- `QueryResult.kind` -- `QueryResult.notices` -- `QueryResult.rowCount` -- `QueryResult.rows` -- `RawQueryResult.commandTag` -- `RawQueryResult.fields` -- `RawQueryResult.getText()` -- `RawQueryResult.kind` -- `RawQueryResult.notices` -- `RawQueryResult.rowCount` -- `RawQueryResult.rows` -- `RawQueryRow.text()` -- `RawQueryRow.values` -- `RestoreOptions.libraryPath` -- `ServerOpenConfig.listen` -- `ServerOpenConfig.serverExecutable` -- `TextQueryParameter.format` -- `TextQueryParameter.typeOid` -- `TextQueryParameter.value` - -## Native TypeScript tools: @oliphaunt/tools - -### Package exports - -- `. = {"types":"./index.d.ts","default":"./index.js"}` -- `./package.json = "./package.json"` - -### Types - -- `PgDumpOptions` -- `PsqlOptions` - -### Values - -- `PostgresToolError` -- `pgDump` -- `psql` - -### Members - -- `PgDumpOptions.args` -- `PostgresToolError.exitCode` -- `PostgresToolError.signal` -- `PostgresToolError.stderr` -- `PostgresToolError.stdout` -- `PostgresToolError.tool` -- `PsqlOptions.args` -- `PsqlOptions.command` -- `PsqlOptions.script` - -## WASIX TypeScript: @oliphaunt/wasix-ts - -### Package exports - -- `. = {"types":"./lib/index.d.ts","deno":"./lib/index.deno.js","bun":"./lib/index.bun.js","node":"./lib/index.node.js","browser":"./lib/index.js","default":"./lib/index.js"}` -- `./worker = {"types":"./lib/worker-entry.d.ts","deno":"./lib/worker-entry.deno.js","bun":"./lib/worker-entry.bun.js","node":"./lib/worker-entry.node.js","browser":"./lib/worker-entry.js","default":"./lib/worker-entry.js"}` -- `./direct = {"types":"./lib/direct.node.d.ts","deno":"./lib/direct.node.js","bun":"./lib/direct.node.js","node":"./lib/direct.node.js"}` -- `./internal/tools = {"types":"./lib/internal.d.ts","deno":"./lib/internal.node.js","bun":"./lib/internal.node.js","node":"./lib/internal.node.js","browser":"./lib/internal.js","default":"./lib/internal.js"}` -- `./server = {"types":"./lib/server.node.d.ts","deno":"./lib/server.node.js","bun":"./lib/server.node.js","node":"./lib/server.node.js"}` -- `./storage/indexed-db = {"types":"./lib/storage/indexed-db.d.ts","default":"./lib/storage/indexed-db.js"}` -- `./storage/opfs = {"types":"./lib/storage/opfs.d.ts","default":"./lib/storage/opfs.js"}` -- `./storage/node = {"types":"./lib/storage/node.d.ts","node":"./lib/storage/node.js"}` -- `./storage/bun = {"types":"./lib/storage/bun.d.ts","bun":"./lib/storage/bun.js"}` -- `./storage/deno = {"types":"./lib/storage/deno.d.ts","deno":"./lib/storage/deno.js"}` -- `./package.json = {"default":"./package.json"}` - -### Types - -- `BinaryInput` -- `BinaryQueryParameter` -- `CommandResult` -- `DescribeResult` -- `EncodedQueryParameter` -- `ExecResult` -- `InferQueryRow` -- `NullQueryParameter` -- `OliphauntClient` -- `OliphauntDatabase` -- `OliphauntTransaction` -- `OpenConfig` -- `ParameterOptions` -- `PersistentWasixStorage` -- `PostgresErrorField` -- `PostgresNotice` -- `QueryArrayRow` -- `QueryBinaryInput` -- `QueryDecoderMap` -- `QueryField` -- `QueryFormat` -- `QueryObjectRow` -- `QueryOptions` -- `QueryParam` -- `QueryParameterEncoder` -- `QueryResult` -- `QueryRowMode` -- `QueryValue` -- `QueryValueDecoder` -- `RawQueryResult` -- `RawQueryRow` -- `TextQueryParameter` -- `TransactionStatus` -- `WasixAssetSource` -- `WasixExtensionDescriptor` -- `WasixStorage` -- `WasixStorageCommitState` -- `WasixStorageErrorCode` -- `WasixStoragePhase` - -### Values - -- `Oliphaunt` -- `PostgresError` -- `WasixStorageError` -- `array` -- `binary` -- `json` -- `memory` -- `postgresOids` -- `text` -- `typedNull` - -### Members - -- `BinaryQueryParameter.format` -- `BinaryQueryParameter.typeOid` -- `BinaryQueryParameter.value` -- `CommandResult.commandTag` -- `CommandResult.notices` -- `CommandResult.rowCount` -- `DescribeResult.fields` -- `DescribeResult.notices` -- `DescribeResult.parameterTypeOids` -- `ExecResult.notices` -- `ExecResult.statements` -- `NullQueryParameter.format` -- `NullQueryParameter.typeOid` -- `OliphauntClient.open()` -- `OliphauntClient.restore()` -- `OliphauntDatabase.[Symbol.asyncDispose]()` -- `OliphauntDatabase.backup()` -- `OliphauntDatabase.close()` -- `OliphauntDatabase.closed` -- `OliphauntDatabase.describe()` -- `OliphauntDatabase.exec()` -- `OliphauntDatabase.execProtocolRaw()` -- `OliphauntDatabase.execProtocolRawStream()` -- `OliphauntDatabase.execute()` -- `OliphauntDatabase.query()` -- `OliphauntDatabase.queryRaw()` -- `OliphauntDatabase.transaction()` -- `OliphauntTransaction.closed` -- `OliphauntTransaction.describe()` -- `OliphauntTransaction.exec()` -- `OliphauntTransaction.execute()` -- `OliphauntTransaction.query()` -- `OliphauntTransaction.queryRaw()` -- `OliphauntTransaction.rollback()` -- `OpenConfig.database` -- `OpenConfig.extensions` -- `OpenConfig.icu` -- `OpenConfig.startupGUCs` -- `OpenConfig.storage` -- `OpenConfig.username` -- `ParameterOptions.encoders` -- `PostgresError.columnName` -- `PostgresError.constraintName` -- `PostgresError.constructor()` -- `PostgresError.dataTypeName` -- `PostgresError.detail` -- `PostgresError.fields` -- `PostgresError.file` -- `PostgresError.hint` -- `PostgresError.internalPosition` -- `PostgresError.internalQuery` -- `PostgresError.line` -- `PostgresError.localizedSeverity` -- `PostgresError.nonlocalizedSeverity` -- `PostgresError.notices` -- `PostgresError.position` -- `PostgresError.routine` -- `PostgresError.schemaName` -- `PostgresError.severity` -- `PostgresError.sqlstate` -- `PostgresError.tableName` -- `PostgresError.whereText` -- `PostgresErrorField.code` -- `PostgresErrorField.value` -- `PostgresNotice.columnName` -- `PostgresNotice.constraintName` -- `PostgresNotice.dataTypeName` -- `PostgresNotice.detail` -- `PostgresNotice.fields` -- `PostgresNotice.file` -- `PostgresNotice.hint` -- `PostgresNotice.internalPosition` -- `PostgresNotice.internalQuery` -- `PostgresNotice.line` -- `PostgresNotice.localizedSeverity` -- `PostgresNotice.message` -- `PostgresNotice.nonlocalizedSeverity` -- `PostgresNotice.position` -- `PostgresNotice.routine` -- `PostgresNotice.schemaName` -- `PostgresNotice.severity` -- `PostgresNotice.sqlstate` -- `PostgresNotice.tableName` -- `PostgresNotice.whereText` -- `QueryField.format` -- `QueryField.name` -- `QueryField.tableAttribute` -- `QueryField.tableOid` -- `QueryField.typeModifier` -- `QueryField.typeOid` -- `QueryField.typeSize` -- `QueryOptions.decoders` -- `QueryOptions.encoders` -- `QueryOptions.rowMode` -- `QueryOptions.valueMode` -- `QueryResult.commandTag` -- `QueryResult.fields` -- `QueryResult.kind` -- `QueryResult.notices` -- `QueryResult.rowCount` -- `QueryResult.rows` -- `RawQueryResult.commandTag` -- `RawQueryResult.fields` -- `RawQueryResult.getText()` -- `RawQueryResult.kind` -- `RawQueryResult.notices` -- `RawQueryResult.rowCount` -- `RawQueryResult.rows` -- `RawQueryRow.text()` -- `RawQueryRow.values` -- `TextQueryParameter.format` -- `TextQueryParameter.typeOid` -- `TextQueryParameter.value` -- `WasixStorageError.code` -- `WasixStorageError.commitState` -- `WasixStorageError.constructor()` -- `WasixStorageError.phase` - -### Worker subpath: @oliphaunt/wasix-ts/worker - -#### Types - -- `BinaryInput` -- `BinaryQueryParameter` -- `CommandResult` -- `DescribeResult` -- `EncodedQueryParameter` -- `ExecResult` -- `InferQueryRow` -- `NullQueryParameter` -- `OliphauntClient` -- `OliphauntDatabase` -- `OliphauntTransaction` -- `OpenConfig` -- `ParameterOptions` -- `PersistentWasixStorage` -- `PostgresErrorField` -- `PostgresNotice` -- `QueryArrayRow` -- `QueryBinaryInput` -- `QueryDecoderMap` -- `QueryField` -- `QueryFormat` -- `QueryObjectRow` -- `QueryOptions` -- `QueryParam` -- `QueryParameterEncoder` -- `QueryResult` -- `QueryRowMode` -- `QueryValue` -- `QueryValueDecoder` -- `RawQueryResult` -- `RawQueryRow` -- `TextQueryParameter` -- `TransactionStatus` -- `WasixAssetSource` -- `WasixExtensionDescriptor` -- `WasixStorage` -- `WasixStorageCommitState` -- `WasixStorageErrorCode` -- `WasixStoragePhase` - -#### Values - -- `Oliphaunt` -- `PostgresError` -- `WasixStorageError` -- `array` -- `binary` -- `json` -- `memory` -- `postgresOids` -- `text` -- `typedNull` - -#### Members - -- `BinaryQueryParameter.format` -- `BinaryQueryParameter.typeOid` -- `BinaryQueryParameter.value` -- `CommandResult.commandTag` -- `CommandResult.notices` -- `CommandResult.rowCount` -- `DescribeResult.fields` -- `DescribeResult.notices` -- `DescribeResult.parameterTypeOids` -- `ExecResult.notices` -- `ExecResult.statements` -- `NullQueryParameter.format` -- `NullQueryParameter.typeOid` -- `OliphauntClient.open()` -- `OliphauntClient.restore()` -- `OliphauntDatabase.[Symbol.asyncDispose]()` -- `OliphauntDatabase.backup()` -- `OliphauntDatabase.close()` -- `OliphauntDatabase.closed` -- `OliphauntDatabase.describe()` -- `OliphauntDatabase.exec()` -- `OliphauntDatabase.execProtocolRaw()` -- `OliphauntDatabase.execProtocolRawStream()` -- `OliphauntDatabase.execute()` -- `OliphauntDatabase.query()` -- `OliphauntDatabase.queryRaw()` -- `OliphauntDatabase.transaction()` -- `OliphauntTransaction.closed` -- `OliphauntTransaction.describe()` -- `OliphauntTransaction.exec()` -- `OliphauntTransaction.execute()` -- `OliphauntTransaction.query()` -- `OliphauntTransaction.queryRaw()` -- `OliphauntTransaction.rollback()` -- `OpenConfig.database` -- `OpenConfig.extensions` -- `OpenConfig.icu` -- `OpenConfig.startupGUCs` -- `OpenConfig.storage` -- `OpenConfig.username` -- `ParameterOptions.encoders` -- `PostgresError.columnName` -- `PostgresError.constraintName` -- `PostgresError.constructor()` -- `PostgresError.dataTypeName` -- `PostgresError.detail` -- `PostgresError.fields` -- `PostgresError.file` -- `PostgresError.hint` -- `PostgresError.internalPosition` -- `PostgresError.internalQuery` -- `PostgresError.line` -- `PostgresError.localizedSeverity` -- `PostgresError.nonlocalizedSeverity` -- `PostgresError.notices` -- `PostgresError.position` -- `PostgresError.routine` -- `PostgresError.schemaName` -- `PostgresError.severity` -- `PostgresError.sqlstate` -- `PostgresError.tableName` -- `PostgresError.whereText` -- `PostgresErrorField.code` -- `PostgresErrorField.value` -- `PostgresNotice.columnName` -- `PostgresNotice.constraintName` -- `PostgresNotice.dataTypeName` -- `PostgresNotice.detail` -- `PostgresNotice.fields` -- `PostgresNotice.file` -- `PostgresNotice.hint` -- `PostgresNotice.internalPosition` -- `PostgresNotice.internalQuery` -- `PostgresNotice.line` -- `PostgresNotice.localizedSeverity` -- `PostgresNotice.message` -- `PostgresNotice.nonlocalizedSeverity` -- `PostgresNotice.position` -- `PostgresNotice.routine` -- `PostgresNotice.schemaName` -- `PostgresNotice.severity` -- `PostgresNotice.sqlstate` -- `PostgresNotice.tableName` -- `PostgresNotice.whereText` -- `QueryField.format` -- `QueryField.name` -- `QueryField.tableAttribute` -- `QueryField.tableOid` -- `QueryField.typeModifier` -- `QueryField.typeOid` -- `QueryField.typeSize` -- `QueryOptions.decoders` -- `QueryOptions.encoders` -- `QueryOptions.rowMode` -- `QueryOptions.valueMode` -- `QueryResult.commandTag` -- `QueryResult.fields` -- `QueryResult.kind` -- `QueryResult.notices` -- `QueryResult.rowCount` -- `QueryResult.rows` -- `RawQueryResult.commandTag` -- `RawQueryResult.fields` -- `RawQueryResult.getText()` -- `RawQueryResult.kind` -- `RawQueryResult.notices` -- `RawQueryResult.rowCount` -- `RawQueryResult.rows` -- `RawQueryRow.text()` -- `RawQueryRow.values` -- `TextQueryParameter.format` -- `TextQueryParameter.typeOid` -- `TextQueryParameter.value` -- `WasixStorageError.code` -- `WasixStorageError.commitState` -- `WasixStorageError.constructor()` -- `WasixStorageError.phase` - -### Storage subpath: @oliphaunt/wasix-ts/storage/indexed-db - -- `indexedDB` - -### Storage subpath: @oliphaunt/wasix-ts/storage/opfs - -- `opfs` - -### Storage subpath: @oliphaunt/wasix-ts/storage/node - -- `directory` - -### Storage subpath: @oliphaunt/wasix-ts/storage/bun - -- `directory` - -### Storage subpath: @oliphaunt/wasix-ts/storage/deno - -- `directory` - -### Server subpath: @oliphaunt/wasix-ts/server - -- `OliphauntServer` -- `ServerListen` -- `ServerOpenConfig` -- `openServer` - -## WASIX TypeScript tools: @oliphaunt/wasix-tools - -### Package exports - -- `. = {"types":"./lib/index.d.ts","default":"./lib/index.js"}` -- `./package.json = "./package.json"` - -### Types - -- `PgDumpOptions` -- `PsqlOptions` - -### Values - -- `PostgresToolError` -- `pgDump` -- `psql` - -### Members - -- `PgDumpOptions.args` -- `PostgresToolError.constructor()` -- `PostgresToolError.exitCode` -- `PostgresToolError.stderr` -- `PostgresToolError.stdout` -- `PostgresToolError.tool` -- `PsqlOptions.args` -- `PsqlOptions.command` -- `PsqlOptions.script` diff --git a/docs/maintainers/sdk-products-policy.md b/docs/maintainers/sdk-products-policy.md deleted file mode 100644 index e58f08271..000000000 --- a/docs/maintainers/sdk-products-policy.md +++ /dev/null @@ -1,145 +0,0 @@ -# SDK Products - -SDK source lives under `src/` with the product it releases. This document is -the cross-SDK policy and parity contract. - -These are product SDKs, not auxiliary bindings. Native Rust, Rust WASIX, Swift, -Kotlin, React Native, native TypeScript, and WASIX TypeScript should expose the -same product concepts where the target platform can do so honestly: - -- Native Rust is the SDK for Tauri and Rust desktop apps using `liboliphaunt`. -- Rust WASIX is the portable/AOT SDK for Tauri and Rust desktop apps that embed - the WASIX runtime. -- Swift is the SDK for iOS and macOS apps. -- Kotlin is the SDK for Android apps. Only the Android AAR, Gradle plugin and - marker, and declared Android ABI carriers are public release surfaces. -- React Native is the TypeScript/TurboModule SDK over the Swift and Kotlin SDKs. -- TypeScript is the SDK for Node.js, Bun, and Deno. Tauri apps use the Rust SDK - behind narrow app-owned commands. -- WASIX TypeScript is the SDK for browser, Node.js, Bun, Deno, and Electron - applications. Browser root is caller-owned; the native-host root uses a Rust actor, - with explicit `/direct` and package-Worker placements. - -`tools/policy/sdk-manifest.toml` is the repo-level SDK registry. The canonical -product graph lives in `src/*/moon.yml`; `sdk-contracts:manifest` parses both and -rejects ownership or package-identity drift. Product tests and package checks, -not source-text assertions, prove runtime delegation and consumer behavior. - -- `src/sdks/rust/`: canonical native Rust SDK for Tauri and Rust desktop apps. -- `src/bindings/wasix-rust/crates/oliphaunt-wasix/`: Rust SDK over the portable - and host-AOT `liboliphaunt-wasix` runtime products. -- `src/bindings/wasix-ts/`: TypeScript SDK over the browser portable WASIX - carrier and the Node/Bun/Deno/Electron Rust Node-API carrier. Its native-host root - uses a Rust owner actor, `/direct` opts into caller-realm execution, and - `/worker` owns a JavaScript Worker on every runtime. `tools-package/` owns the optional - TypeScript facade for `pg_dump` against root, direct, or Worker handles and - non-interactive `psql` against browser Worker or any native-host placement. Browser tool - modules are a separate `liboliphaunt-wasix` carrier; native tools are embedded - in the Node-API carrier. -- `src/sdks/swift/`: Swift package with an actor-first `Oliphaunt` API and a - native-direct C ABI product boundary over `liboliphaunt`; it can materialize - packaged runtime/cluster-seed resources for iOS and macOS apps. -- `src/sdks/kotlin/`: Android SDK with a suspend-first common implementation, - JVM contract tests, and the Android native-direct JNI engine. Maven - publication is deliberately limited to the Android consumer surface. -- `src/sdks/react-native/`: React Native New Architecture package. Its product contract - is a typed TypeScript/TurboModule layer over the Swift and Kotlin SDKs, with - no independent database semantics. -- `src/sdks/js/`: desktop JavaScript SDK for Node.js, Bun, and Deno. - Tauri apps expose narrow app-owned commands from the Rust SDK. Direct topology - is the default across supported JavaScript - runtimes; Node.js and Bun use the package-owned prebuilt Node direct adapter, - while Deno uses nonblocking runtime FFI. TypeScript broker mode consumes the - published `oliphaunt-broker` runtime and the shared `PGOB` protocol - instead of inventing another broker runtime; app developers get verified - release assets by default instead of building Rust locally. The npm package - is the native-runtime distribution for Node, Bun, and Deno. - -The native Rust SDK is canonical for native mode and resource terminology; -Swift, Kotlin, React Native, and native TypeScript mirror it unless a platform -restriction is documented. Rust WASIX and WASIX TypeScript use the same raw -protocol, typed query, transaction, structured PostgreSQL error, backup, -restore, and exact-extension vocabulary where their runtime supports the -behavior honestly. PostgreSQL `CHECKPOINT` is explicit SQL through `execute`, -not a separate SDK method. Native-only process modes are not WASIX requirements. -React Native must not duplicate database runtime behavior: iOS calls flow -through `Oliphaunt`, and Android calls flow through the `oliphaunt` -`Oliphaunt` facade. -Unsupported product features are absent from an SDK unless -[`sdk-parity-policy.md`](sdk-parity-policy.md) explicitly documents a current -runtime error. Silent drift between SDKs is a release blocker. - -Validation is package-native: - -```sh -moon run oliphaunt-rust:compile -moon run oliphaunt-wasix-rust:compile -moon run oliphaunt-wasix-ts:compile -moon run oliphaunt-wasix-tools-ts:compile -moon run oliphaunt-swift:compile -moon run oliphaunt-kotlin:check -moon run oliphaunt-react-native:compile -moon run oliphaunt-js:compile -moon run sdk-contracts:all -moon run extensions:lint -``` - -The Kotlin and React Native Android validation scripts opt into Gradle -configuration cache by default. Set `OLIPHAUNT_GRADLE_CONFIGURATION_CACHE=0` -when debugging Gradle task configuration itself. - -When a local `target/liboliphaunt-pg18` build exists, the Swift and Kotlin lanes -automatically run their native-direct C ABI tests against that library and -runtime tree. - -Build app-bundle resources from the Rust/native track with: - -```sh -cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources -- \ - --output target/oliphaunt-resources \ - --extension vector \ - --force -``` - -Extension selection is exact-name only. SDKs accept exact PostgreSQL extension -names; `vector` means only the SQL extension `vector`, and names like `core`, -`search`, or `geo` must not resolve to hidden extension sets. - -The generated `target/oliphaunt-resources/oliphaunt` directory is the resource -root consumed by Swift bundles, Android assets, and React Native apps. Android -Gradle builds also accept the parent directory through -`-PoliphauntRuntimeResourcesDir=target/oliphaunt-resources`. - -For iOS and Android release artifacts, build runtime resources with -`--require-mobile-static-registry` once the selected extension modules have -platform static registry rows. Swift, Kotlin, and React Native reject requested -extensions whose packaged runtime advertises pending mobile registry work. -The platform resource build must also pass each linked registry module stem with -`--mobile-static-module `; the Rust runtime-resource CLI rejects stems -that are not selected by the runtime resources. Those stems are declarations for -validation; mobile-ready output includes -`oliphaunt/static-registry/oliphaunt_static_registry.c`, which exports -`liboliphaunt_selected_static_extensions`. Platform bridges discover that symbol -and register the returned rows through `oliphaunt_register_static_extensions` -before the first database open. -Every SDK consumes the resulting runtime resources through the same manifest -fields. Generated manifests record -`schema=oliphaunt-runtime-resources-v1`, per-package `layout`, -the full dependency-closed `selectedExtensions` domain, its exact -`creates-extension=true` subset in `extensions`, `runtimeFeatures`, and -`sharedPreloadLibraries`. Mobile manifests additionally bind the exact native -SQL-name domain in `mobileStaticRegistryRegistered` and its exact module stems -in `nativeModuleStems`; the static-registry manifest must agree. All domains -are sorted and duplicate-free. SDK resource-availability checks use -`selectedExtensions`, including for selected module-only extensions, so -SDK-bound artifacts can be audited independently of the local build path. -Swift and Kotlin reject unknown package layouts rather than silently accepting -stale app resources; React Native inherits those checks through the platform -SDKs. -The resource root also carries `package-size.tsv` for packaging and release -audits. It is maintainer evidence, not a database SDK API. - -Android packages the native C ABI library separately from runtime resources. -Pass a `jniLibs`-style directory with ABI subdirectories through -`-PoliphauntAndroidJniLibsDir=/path/to/jniLibs`; each packaged ABI must include -`liboliphaunt.so`. diff --git a/docs/maintainers/tooling.md b/docs/maintainers/tooling.md deleted file mode 100644 index c88cfc5a3..000000000 --- a/docs/maintainers/tooling.md +++ /dev/null @@ -1,357 +0,0 @@ -# Tooling Decisions - -Status: normative tooling decision record. Last verified: 2026-09-03. Owner: repository maintainers. - -Oliphaunt is a polyglot product monorepo. Tooling has to make product work -predictable without hiding ecosystem-native behavior. - -## Roles - -- Moon is the product/task graph, affectedness engine, local cache, and CI task - executor. -- Release Please manifest mode owns release PRs, versions, and changelogs. -- The protected release workflow owns exact-SHA product tags and draft GitHub - releases. -- Product-local `release.toml` files activate a public product and own package - metadata Release Please does not model: owner, kind, publish targets, - registry packages, release artifacts, exact published compatibility pins, and - derived version files. Incomplete extension work stays on a branch. -- Runtime products select target presets in Moon - `project.release.artifactTargets`; the global extension target-profile - contract applies those concrete targets to every catalogued SQL extension. -- Product-native build tools own product behavior: Cargo, SwiftPM/Xcode, - Gradle, npm, Expo, React Native Codegen, and PostgreSQL build scripts. -- Bun helpers under `tools/release/*.mjs` and `.github/scripts/*.mjs` own the - public and protected release check, dry-run, publish, tag, and draft-release - command surface. - -Do not add a second source graph, release graph, or root alias layer over Moon. -Do not add a repo-wide tool because it is popular in one language ecosystem. - -## Moon - -Install Moon through Proto from `.prototools` and run `moon` directly. Moon's -current plugins require the Proto version pinned in -`src/sources/toolchains/proto.toml` (currently 0.61.3): - -```sh -proto upgrade 0.61.3 -proto install -moon query projects -moon query tasks -moon query affected --upstream none --downstream direct -moon run :check :compile :format-check :js-format-check :rust-format-check :lint :tools-compile -moon run :test :unit :tools-unit -moon run :coverage -``` - -Moon task names carry stable intent: - -- `check`, `compile`, `format-check`, `js-format-check`, `rust-format-check`, - and `lint`: distinct static validation. -- `test` and `unit`: product-native unit or contract tests. -- `package`: assemble or inspect a carrier; it never publishes. -- `smoke`: one runtime happy path. -- `regression`: broader SQL, protocol, extension, lifecycle, or runtime - regressions. -- `perf-tools:*-plan`: benchmark plan/report validation. -- `perf-tools:*-measure`: measured benchmark execution. -- `coverage-tools:`: measured product-native line coverage. -- `qualify`: an explicit local/release aggregate, never an ordinary CI leaf. - -Every task must declare explicit inputs. Tasks with deterministic output that -other tasks consume must declare outputs. Use Moon tags for CI lanes and ad-hoc -selection; do not create root script aliases for new lanes. - -Moon dependency scopes describe local source relationships: - -- `production` and `peer` mean a local consumer uses the dependency's code or - artifact. -- `build` is for tests, fixtures, generated metadata, and package-shape checks. - -Release propagation stops at the first publishable product boundary. Exact -published dependency versions live in product-local `compatibility_versions`; -Moon edges qualify direct consumers but never invent downstream releases. - -## pnpm - -pnpm is not the global build orchestrator. Its repo-level role is: - -- install JavaScript-family workspace dependencies from `pnpm-lock.yaml`; -- provide JavaScript package-manager commands for docs, TypeScript, and React - Native packages. - -The root `package.json` intentionally has no scripts. Run the corresponding -Moon target or the product-native package command; a second alias layer makes -affectedness, cache behavior, and ownership harder to inspect. - -Cargo, Gradle, SwiftPM, Xcode, npm publish, Expo, and PostgreSQL build -scripts stay product-owned and are invoked through Moon tasks where repository -or CI orchestration is needed. `node_modules/` directories are normal ignored -local install state; they must never be tracked. - -## Scripts - -Use shell for setup, process orchestration, platform packaging glue, and thin -CI wrappers. Policy code that parses repository files and asserts invariants -should live under `tools/policy/assertions/assert-*.mjs` and run with Bun. Keep -`check-*` scripts as Moon/CI entrypoints when they aggregate checks or wrap -ecosystem-native tools. - -## Bootstrap toolchain sources - -The manifests in `src/sources/toolchains/` are the source of truth for -downloaded maintainer toolchains. `bun.toml` and `deno.toml` pin both the -official archive SHA-256 and the extracted executable SHA-256 for every -supported macOS, Linux, and Windows host target. `android-sdk.toml` pins the -Linux and macOS command-line-tools archives and the exact SDK package -identities used by builds. Version inputs in composite actions are compatibility -guards: they must agree with the manifest; they do not select arbitrary bytes. - -CI does not delegate Node, Moon, or pnpm acquisition to `actions/setup-node`, -Corepack, or `moonrepo/setup-toolchain`. `node-runtime.toml` pins the official -Node archive and extracted runtime binary for every supported host. -`moon-cli.toml` and `pnpm.toml` pin their archives, component hashes, executable -modes, and extracted-tree identities. `moon-plugins.toml` pins both each OCI -manifest digest and the manifest-bound WASM blob. `npm-publisher.toml` applies -the same archive and complete-tree contract to the npm CLI used by publication. -The proto version in Moon configuration is -a compatibility contract only; CI does not hydrate tools through proto. - -Bootstrap downloads are HTTPS-only, bounded, checksum-verified, validated for -archive layout and entry type, extracted into private staging directories, and -promoted by a same-filesystem rename. A valid local executable is preserved. A -corrupt or wrong-version cache is repaired, and an interrupted replacement -restores the prior directory. Do not add `continue-on-error` setup-action or -unchecked `curl | unzip` fallbacks. - -GitHub cache entries are acceleration only. Every restored binary, wrapper, -plugin, component, mode inventory, and complete package tree is revalidated -before its path is exported. Moon plugins are copied into a fresh private -`MOON_HOME`, and `MOON_TOOLCHAIN_FORCE_GLOBALS=true` prevents Moon from -silently hydrating another runtime. On Windows, composite actions convert -Git-Bash paths back to native paths before writing `GITHUB_PATH`. - -Verified Node.js, Moon, pnpm, and npm-publisher archives use explicit cache -restore and save actions with one exact key per runner OS and architecture. -Every save happens only after complete payload verification, only after an -exact-key miss, and only under CI's main-branch `HEAVY_CACHE_SAVE_IF` gate; -cache-save failures are non-blocking. Release and mobile workflows are -restore-only. Do not use the monolithic `actions/cache` action in reachable -workflows or composites, and do not cache the pnpm content-addressable store: -the standalone setup action runs before caller dependency installation, so it -cannot produce a complete store entry. - -Android command-line-tools are byte-pinned. Packages installed through -`sdkmanager` are not immutable repository blobs: the bootstrap requests the -exact NDK, CMake, build-tools, and platform package identities, then validates -their installed `source.properties` and build-critical executables/resources. -`platform-tools` is an intentionally -unversioned moving Android repository package and is validated by the presence -of an executable `adb`; do not describe it as byte-reproducible. - -The Android setup action restores the Gradle dependency cache only for -Gradle/Expo consumers. It uses the same dependency-derived key and paths as -`actions/setup-java`, but defaults to an explicit restore-only action. The -fixed Linux `kotlin-sdk-package` job is the sole caller allowed to enable -setup-java's cache writer, and only under CI's bounded main-branch heavy-cache -policy. Native-only Android artifact jobs pass `gradle-cache: "false"` and do -not restore or write Gradle state. Do not add a per-consumer Gradle cache scope -unless the bounded producer is also designed to populate that exact key; -restore-only keys with no producer remain permanently cold. - -When native ccache is enabled, the Android action creates and configures a -target-owned directory for reuse within the job. Native runtime build trees -and compiler caches are not restored across runs, because stale generated -files and mtimes are build correctness inputs rather than dependency caches. - -Kotlin plugin and dependency resolution try Google Cloud's fixed, hosted Maven -Central mirror before canonical Maven Central. The mirror is an availability -path for valid Central coordinates when a shared GitHub-hosted runner IP is -temporarily refused; canonical Central remains the missing-module fallback. -Do not add retries for an HTTP 403, a mutable repository override, or another -uncontrolled repository. A mirror or cache change must be proven from a fresh -Gradle home, and mirror payloads used as evidence must match canonical Central -by checksum. Gradle dependency verification should be introduced only as one -complete, reviewed rollout covering every supported host and configuration; -an incomplete host-generated metadata file is not a release safeguard. - -## CI - -GitHub Actions owns runners, credentials, artifact upload, and platform matrix -fan-out. Moon owns which tasks are affected and how tasks depend on each other. -Every GitHub-hosted runner uses an explicit OS-version label. Mutable -`ubuntu-latest`, `macos-latest`, and `windows-latest` aliases are forbidden by -workflow policy, including suffixed variants. A runner-image upgrade is an -intentional dependency change: inspect the image/toolchain delta, rerun the -platform binary compatibility contract, and qualify every affected release -target before changing the pin. -The repository build toolchain is exact Rust 1.93.1 in -`rust-toolchain.toml`; crate `rust-version = "1.93"` fields are the distinct -consumer MSRV contract and must not be used as a mutable CI toolchain selector. -Linux broker packaging also pins the official Rust 1.93.1 Bookworm OCI index -by digest because the final glibc symbol bindings are a linker-input contract, -not a property guaranteed by `rust-toolchain.toml`. Its sealed build is -networkless and read-only. The separate digest-pinned Fedora 39 image is used -only to rehearse the glibc 2.38 ABI after verifying the container's observed -glibc version; Fedora 39's end-of-life security status is not a production OS -support claim. -Windows jobs configure the runner-owned Visual Studio developer shell through -`.github/scripts/setup-msvc.ps1`; they do not depend on a third-party Node -action for compiler environment discovery. The setup accepts only Visual Studio -installation major 18, selects x64 tools from `HostX64/x64`, and verifies the -VC145 redistributable closure. It records the observed Visual Studio, VC tools, -Windows SDK, compiler/linker, and runner-image versions without patch-pinning a -runner-owned toolchain that GitHub may service in place. Apple jobs select the -exact `/Applications/Xcode_26.5.app/Contents/Developer` bundle and require the -observed Xcode minor to remain 26.5. The Xcode build identifier, Apple SDK -versions, and runner-image version are evidence rather than patch pins. macOS -setup removes the unused runner-provided `aws/tap` before formula lookup instead -of disabling Homebrew's tap-trust enforcement. - -CI flow: - -1. The affected job uses Moon queries to select stable job names from task tags - named `ci-` and to emit the exact Moon task targets for each job. -2. The affected job emits dynamic `Checks / ` and `Tests / ` - matrices plus one compact `Policy` task batch from Moon-selected targets. - Each visible entry lists and runs at most four tasks with identical setup. - `Checks` are normal static/lint/typecheck-style package or tool checks. - Policy targets are invariant assertions that parse repository files, - workflow YAML, release metadata, generated graphs, or package topology. - Package checks and tests keep task inheritance; the policy batch runs its - selected targets with `--upstream none` so it does not re-run package - prerequisites that already have their own visible jobs. A task that truly - needs the Android SDK declares the `requires-android-sdk` Moon tag. The planner - projects that capability into runner setup, so unrelated check, policy, and - test groups do not install Android tooling. -3. Product build jobs call `.github/scripts/run-planned-moon-job.sh `. -4. The planned-job wrapper reads the affected job target map, then delegates to - `.github/scripts/run-moon-targets.sh`, which runs - `moon run` with the selected targets. This is for planned artifact targets - whose producer jobs may be selected by release-product implications rather - than by direct file affectedness. Jobs that consume downloaded artifacts pass - their direct producer targets through - `OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON`; the wrapper validates those edges, - runs remaining local prerequisites, and suppresses only the transferred - producers. `release-tools:-sdk-package` tasks consume product - `package` outputs instead of hiding release assembly in source projects. -5. GitHub matrix fans out only target dimensions such as OS, CPU, ABI, native - runtime target, broker target, Node direct target, WASIX AOT target, Android - emulator, and iOS simulator. - -The required PR gate is thin: visible `Checks / `, `Policy`, -`Tests / `, `Builds / `, and installed-app -`E2E` jobs all fan out from the affected plan, while Moon models package-local -prerequisites. The final `Required` job aggregates the `Checks`, `Tests`, -`Builds`, and `E2E` phase gates plus `release-intent`; the selected `Policy` -batch is included in the `Checks` gate. Mobile installed-app `E2E` -consumes built app artifacts from the same CI run and does not rebuild runtimes, -SDKs, or extension packages. - -Mobile CI target fan-out is derived from published -`liboliphaunt-native` artifact rows generated from the product's Moon -`artifactTargets` declaration and the release target preset. Android jobs use -rows whose surfaces include `react-native-android`; iOS jobs use rows whose -surfaces include `react-native-ios`. Do not hardcode mobile ABI target lists in -CI planners. - -Keep workflow names and job names product-oriented. Put implementation details -in step names. - -## Moon Cache Policy - -Moon is allowed to cache task results when inputs, dependency task outputs, -toolchain-sensitive files, environment variables, and outputs represent the -work. It does not know about simulator/device state, installed apps, local -ports, Docker daemon state, code-signing identities, registry state, or copied -runtime artifacts unless those are modeled as inputs. - -Cache deterministic static checks, package-shape checks, generated freshness, -docs builds, unit tests, and coverage reports when they declare inputs and -outputs. - -Use `cache: local` for developer smoke tasks that are useful to replay when -local source inputs have not changed. - -Set `cache: false` on CI/mobile/device proof tasks; those lanes prove the -current runner, simulator/device, signing environment, app artifact, and -runtime artifact. Keep Moon caching enabled so deterministic prerequisites can -still be restored. - -Cache benchmark plan checks, never measured benchmark runs. `*-plan` validates -matrix and report shape; `*-measure` measures current hardware and runtime -state. - -Use `runInCI: skip` for expensive dependency-only tasks that must stay valid in -CI action graphs but must not run as broad CI work. Use `runInCI: false` only -for tasks CI must never invoke. - -## Release Tooling - -Release Please owns the generated release PR, product-version bumps, and -changelogs without forcing non-JavaScript products into fake `package.json` -files. It supplies the reviewed component/version state used to derive tag -names, but it does not create tags or GitHub releases. - -What release-please does not own: - -- platform binary builds; -- extension artifact builds; -- checksums and attestations; -- registry credential checks; -- package-native publish commands; -- verifying already-published GitHub release assets; -- exact-SHA product tags and draft GitHub releases. - -Those stay behind the Bun release entrypoints, the protected workflow, and -product-native release tasks. - -Do not reintroduce release-plz, git-cliff product changelog ownership, a central -release graph, or broad clean-registry reinstall gates as routine CI policy. - -## Debugging - -Use Moon's graph and cache diagnostics before adding scripts: - -```sh -moon project-graph -moon action-graph release-tools:react-native-sdk-package -moon hash -moon run --cache off --log trace -``` - -If a task is slow, first check whether its inputs are too broad, outputs are -missing, dependency scopes are wrong, or CI is proving runner state that cannot -be safely cached. - -## Policy Design - -Policy checks protect externally meaningful contracts, not the current spelling -of an implementation. Prefer these forms, in order: - -1. parse a manifest, package, workflow, lock, checksum, or evidence record and - assert a stable invariant; -2. execute a package-shape, clean-consumer, failure-path, or runtime test; -3. use a narrow security scan when the unsafe behavior is itself textual. - -Do not assert function names, step display names, source line order, prose -fragments, or exhaustive file inventories. Refactoring should fail policy only -when it changes a contract. Focused checks own release, SDK, extension, -workflow, dependency, and evidence behavior. - -The repository-local skills under `.codex/skills/` are the operational runbooks -for agent-built changes. Use `qualify-oliphaunt-change` for selecting proof, -`add-oliphaunt-extension` for extension metadata and carriers, and -`release-oliphaunt` for candidate qualification and publication. Update the -relevant skill when an operational workflow changes; do not encode a tutorial -as source-text assertions in CI. - -## Tool Ownership - -Keep code in the narrowest owning domain: product behavior beside the product, -shared source/asset operations in `tools/xtask`, performance behavior in -`tools/perf`, CI selection in `tools/graph`, release contracts in -`tools/release`, and repository invariants in `tools/policy`. Split a module -when it has independent inputs, outputs, or failure modes. File names and helper -boundaries are implementation details, not policy APIs. diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 3118ec2a4..000000000 --- a/examples/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Oliphaunt Examples - -The desktop examples keep the same todo schema across shells: - -- `tauri`: Tauri v2 with the native Rust SDK. -- `tauri-wasix`: Tauri v2 with `oliphaunt-wasix` and SQLx. -- `electron`: Electron with the TypeScript SDK and native server mode. -- `electron-wasix`: Electron with a Rust WASIX sidecar exposing a PostgreSQL URL. - -Additional platform examples live here as well: - -- `browser-wasix`: the caller-realm root and explicit `/worker` WASIX - TypeScript entrypoints with browser storage. -- `react-native-expo`: the React Native SDK in an Expo development build. - -Each app opts into `hstore`, `pg_trgm`, and `unaccent`, then uses `hstore` -tags plus trigram/accent-insensitive search for the todo list. Native examples -load `postgres`, `initdb`, and `pg_ctl` from `liboliphaunt-native-*`. Native -tool carriers separately package `pg_basebackup`, `pg_dump`, and `psql`. -WASIX examples load `postgres` and `initdb` from the runtime crates and enable the -`oliphaunt-wasix` `tools` feature, which resolves `pg_dump`/`psql` from -`oliphaunt-wasix-tools`; WASIX intentionally has no `pg_ctl`. - -Example dependencies resolve from npm and crates.io. Cargo manifests pin the -current Oliphaunt release versions and do not commit nested lockfiles. - -Run the static Cargo manifest checks with: - -```sh -tools/dev/bun.sh tools/release/example-cargo-policy.mjs --check -``` -The native examples exercise their configured database path during startup; -native tool compatibility is qualified separately against the local server. -The WASIX examples exercise the optional `tools` namespace only in their -explicit Rust smoke tests; ordinary application startup does not run or load -`pg_dump` or `psql`. - -Run Tauri GUI smoke tests through WebDriver on Linux: - -```sh -examples/tools/run-tauri-webdriver-smoke.sh examples/tauri -examples/tools/run-tauri-webdriver-smoke.sh examples/tauri-wasix -``` - -The WebDriver smoke builds the selected Tauri app in debug mode, launches it -through `tauri-driver`, creates a todo through the real UI, toggles it done, and -asserts the done filter. It expects `WebKitWebDriver`; on Debian/Ubuntu install -`webkit2gtk-driver`. In headless environments it uses `xvfb-run` when present. - -Run Electron GUI smoke tests through the IPC test driver on Linux: - -```sh -examples/tools/run-electron-driver-smoke.sh examples/electron -examples/tools/run-electron-driver-smoke.sh examples/electron-wasix -``` - -The Electron smoke builds the selected app, launches the packaged Electron -binary with a test-driver IPC channel, creates a todo through the real renderer, -toggles it done, and asserts the done filter. In headless environments it uses -`xvfb-run` when present. - -On Linux, SwiftPM artifacts are staged for inspection and skipped for registry -publish when `swift` is not installed. diff --git a/examples/browser-wasix/README.md b/examples/browser-wasix/README.md deleted file mode 100644 index f6f219cfd..000000000 --- a/examples/browser-wasix/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Browser WASIX - -This example exercises both public execution surfaces: the direct caller-realm -root entrypoint and the explicit package-owned `/worker` entrypoint. It also -demonstrates IndexedDB and OPFS persistence and verifies that the root -constructs no hidden Worker. - -Build the WASIX runtime assets, then run: - -```sh -pnpm --dir src/bindings/wasix-ts dev -``` - -The browser smoke and benchmark commands in `src/bindings/wasix-ts/package.json` -use the same example so there is only one browser integration surface to keep -current. diff --git a/examples/browser-wasix/carriers.d.ts b/examples/browser-wasix/carriers.d.ts deleted file mode 100644 index 2dc586fc4..000000000 --- a/examples/browser-wasix/carriers.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -declare module '@oliphaunt/extension-pgtap-wasix' { - const extension: import('../../src/bindings/wasix-ts/src/types.js').WasixExtensionDescriptor; - export default extension; -} - -declare module '@oliphaunt/extension-pg-uuidv7-wasix' { - const extension: import('../../src/bindings/wasix-ts/src/types.js').WasixExtensionDescriptor; - export default extension; -} - -declare module '@oliphaunt/extension-postgis-wasix' { - const extension: import('../../src/bindings/wasix-ts/src/types.js').WasixExtensionDescriptor; - export default extension; -} diff --git a/examples/browser-wasix/main.ts b/examples/browser-wasix/main.ts deleted file mode 100644 index 229b4596b..000000000 --- a/examples/browser-wasix/main.ts +++ /dev/null @@ -1,702 +0,0 @@ -import pgtap from '@oliphaunt/extension-pgtap-wasix'; -import Oliphaunt, { - type OliphauntDatabase, - PostgresError, - type QueryParam, - type WasixExtensionDescriptor, - type WasixStorage, - WasixStorageError, -} from '@oliphaunt/wasix-ts'; -import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker'; -import { indexedDB } from '@oliphaunt/wasix-ts/storage/indexed-db'; -import { opfs } from '@oliphaunt/wasix-ts/storage/opfs'; -import { pgDump, psql } from '@oliphaunt/wasix-tools'; - -import logicalToolsFixtureJson from '../../src/shared/fixtures/postgres/logical-tools.json?raw'; -import logicalToolsSeed from '../../src/shared/fixtures/postgres/logical-tools-seed.sql?raw'; -import logicalToolsVerify from '../../src/shared/fixtures/postgres/logical-tools-verify.sql?raw'; -import { expectDirectPgDump } from './direct-pg-dump-smoke.js'; -import { expectStructuredApi } from './structured-api-smoke.js'; - -const logicalToolsFixture = JSON.parse(logicalToolsFixtureJson) as { - expected: { - rows: number; - sum: number; - sequenceLastValue: number; - quotedValue: string; - normalizedMatches: number; - extensionLoaded: boolean; - }; -}; - -const status = requireElement('status'); -const sql = requireElement('sql'); -const run = requireElement('run'); -const output = requireElement('output'); -const searchParams = new URL(globalThis.location.href).searchParams; -const smoke = searchParams.has('smoke'); -const pgUuidv7Canary = searchParams.has('pg_uuidv7'); -const postgisWorkerCanary = searchParams.has('postgis_worker'); -const directWorkerAudit = smoke ? auditDirectWorkerConstruction() : undefined; - -try { - const extensions: WasixExtensionDescriptor[] = [pgtap]; - if (pgUuidv7Canary) { - const { default: pgUuidv7 } = await import('@oliphaunt/extension-pg-uuidv7-wasix'); - extensions.push(pgUuidv7); - } - if (smoke) { - expectOwnedMemoryCopyAcrossGrowth(); - await expectFailedDirectOpenRecovery(); - } - const storage = indexedDB('browser-smoke'); - let database = await (smoke ? Oliphaunt : WorkerOliphaunt).open({ - extensions, - ...(smoke ? { storage } : {}), - }); - status.textContent = `PostgreSQL 18 is running through the ${smoke ? 'direct root' : 'Worker-owned'} entrypoint.`; - if (smoke) { - await installSelectedExtensions(database, extensions); - await expectStructuredApi(database, 'browser direct'); - await expectConcurrentDirectExecution(database); - await expectExclusiveOwnership(storage, extensions, 'IndexedDB'); - const pgtapVersion = await exercisePgtap(database); - const firstUuid = pgUuidv7Canary ? await readPgUuidv7(database) : undefined; - await database.queryRaw('CREATE TABLE browser_reopen_probe (answer integer NOT NULL)'); - await database.queryRaw('INSERT INTO browser_reopen_probe VALUES (42)'); - await database.execute('CHECKPOINT'); - // This row is intentionally newer than the explicit checkpoint. Its query - // Promise includes an operation storage boundary; clean close also drains - // the journal before releasing ownership. - await database.queryRaw('INSERT INTO browser_reopen_probe VALUES (43)'); - await expectSqlstate(database, 'SELEC 1', '42601'); - await expectAnswer(database); - await expectSqlstate(database, 'SELECT 1 / $1::int', '22012', [0]); - await expectAnswer(database); - await expectTransaction(database); - await expectClockConsistency(database); - const recoveredPgtapVersion = await readPgtapVersion(database); - if (recoveredPgtapVersion !== pgtapVersion) { - throw new Error('browser smoke observed a different pgtap version after recovery'); - } - if (pgUuidv7Canary) { - await readPgUuidv7(database); - } - await expectDirectPgDump(database); - await database.close(); - - directWorkerAudit?.assertNoneAndRestore(); - await expectDirectWithoutWorker(); - await expectFailedWorkerOpenRecovery(); - - database = await WorkerOliphaunt.open({ storage, extensions }); - await expectStructuredApi(database, 'browser Worker'); - await expectSqlstate(database, 'SELEC 1', '42601'); - await expectAnswer(database); - await expectSqlstate(database, 'SELECT 1 / $1::int', '22012', [0]); - await expectAnswer(database); - await expectOwnedRawProtocolResponse(database); - await expectClockConsistency(database); - const reopened = await database.queryRaw( - 'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM browser_reopen_probe', - [','], - ); - if (reopened.getText(0, 'answers') !== '42,43') { - throw new Error('browser smoke did not reopen operation-persisted PGDATA'); - } - if ((await readPgtapVersion(database)) !== pgtapVersion) { - throw new Error('browser smoke did not reconstruct the selected pgtap carrier on reopen'); - } - if (pgUuidv7Canary) { - await readPgUuidv7(database); - } - await database.close(); - const logicalTools = await expectLogicalTools(); - const opfsAnswers = await expectOpfsPersistence(extensions); - const opfsCrash = await expectOpfsCrashRecovery(); - const postgisVersion = postgisWorkerCanary ? await expectLargePostgisWorkerModule() : undefined; - status.textContent = 'Browser smoke passed.'; - output.textContent = JSON.stringify({ - answers: [42, 43], - opfsAnswers, - pgtap: pgtapVersion, - startupSqlstate: '3D000', - directWorkers: 0, - directPgDump: true, - opfsTransport: 'synchronous-access', - opfsCrashAnswer: opfsCrash.answer, - opfsCrashRelations: opfsCrash.relations, - logicalTools, - ...(firstUuid === undefined ? {} : { pg_uuidv7: firstUuid }), - ...(postgisVersion === undefined ? {} : { postgis: postgisVersion }), - }); - document.documentElement.dataset.oliphauntSmoke = 'passed'; - } else { - run.disabled = false; - run.addEventListener('click', async () => { - run.disabled = true; - output.textContent = ''; - try { - const result = await database.queryRaw(sql.value); - output.textContent = JSON.stringify( - result.rows.map((row) => - Object.fromEntries(result.fields.map((field, index) => [field.name, row.text(index)])), - ), - null, - 2, - ); - } catch (error) { - output.textContent = describeError(error); - } finally { - run.disabled = false; - } - }); - } -} catch (error) { - status.textContent = 'Startup failed.'; - output.textContent = describeError(error); - document.documentElement.dataset.oliphauntSmoke = 'failed'; -} finally { - directWorkerAudit?.restore(); -} - -function simpleQuery(sql: string): Uint8Array { - if (sql.includes('\0')) throw new Error('simple query SQL must not contain NUL bytes'); - const body = new TextEncoder().encode(`${sql}\0`); - const message = new Uint8Array(body.length + 5); - message[0] = 0x51; - new DataView(message.buffer).setUint32(1, body.length + 4); - message.set(body, 5); - return message; -} - -async function expectLargePostgisWorkerModule(): Promise { - const { default: postgis } = await import('@oliphaunt/extension-postgis-wasix'); - const dependencyModule = postgis.carriers - .flatMap((carrier) => carrier.install.nativeModules) - .find((module) => module.name === 'postgis_deps'); - if (dependencyModule === undefined || dependencyModule.size <= 8 * 1024 * 1024) { - throw new Error('browser worker canary requires a PostGIS side module larger than 8 MiB'); - } - - const database = await WorkerOliphaunt.open({ extensions: [postgis] }); - try { - await database.execute('CREATE EXTENSION postgis'); - const version = await readPostgisVersion(database); - await database.queryRaw('CREATE TEMP TABLE postgis_nested_error_catch(value integer)'); - await database.queryRaw( - `DO $$ BEGIN - BEGIN - PERFORM ST_GeomFromText('POINT('); - EXCEPTION WHEN OTHERS THEN - INSERT INTO postgis_nested_error_catch VALUES (1); - END; - END $$`, - ); - const caught = await database.queryRaw( - 'SELECT count(*)::int AS count FROM postgis_nested_error_catch', - ); - if (caught.getText(0, 'count') !== '1') { - throw new Error('browser worker did not catch an error crossing PostGIS side modules'); - } - try { - await database.queryRaw("SELECT ST_GeomFromText('POINT(')"); - throw new Error('browser worker expected malformed PostGIS geometry to fail'); - } catch (error) { - if (!(error instanceof PostgresError)) { - throw error; - } - } - if ((await readPostgisVersion(database)) !== version) { - throw new Error('browser worker did not recover its PostGIS session after an error'); - } - return version; - } finally { - await database.close(); - } -} - -async function readPostgisVersion(database: OliphauntDatabase): Promise { - const result = await database.queryRaw('SELECT postgis_full_version()::text AS version'); - const version = result.getText(0, 'version'); - if (version === null || !version.includes('POSTGIS=')) { - throw new Error( - `browser worker returned an invalid PostGIS version: ${JSON.stringify(version)}`, - ); - } - return version; -} - -function expectOwnedMemoryCopyAcrossGrowth(): void { - const memory = new WebAssembly.Memory({ initial: 1, maximum: 2 }); - const guest = new Uint8Array(memory.buffer, 0, 4); - guest.set([1, 2, 3, 4]); - const owned = guest.slice(); - const previousBuffer = memory.buffer; - memory.grow(1); - if (memory.buffer === previousBuffer) { - throw new Error('WebAssembly memory growth did not replace its backing buffer'); - } - new Uint8Array(memory.buffer, 0, 4).fill(9); - if (!owned.every((byte, index) => byte === index + 1)) { - throw new Error('owned protocol bytes changed after explicit WebAssembly memory growth'); - } -} - -async function expectConcurrentDirectExecution(first: OliphauntDatabase): Promise { - const attempts = await Promise.allSettled([Oliphaunt.open(), Oliphaunt.open()]); - const opened = attempts.flatMap((attempt) => - attempt.status === 'fulfilled' ? [attempt.value] : [], - ); - const failed = attempts.find( - (attempt): attempt is PromiseRejectedResult => attempt.status === 'rejected', - ); - if (failed !== undefined) { - await Promise.allSettled(opened.map((database) => database.close())); - throw failed.reason; - } - const [second, third] = opened; - if (second === undefined || third === undefined) { - throw new Error('direct concurrent-open smoke produced an incomplete result'); - } - try { - await expectAnswer(first); - await expectAnswer(second); - await expectAnswer(third); - } finally { - await Promise.all([second.close(), third.close()]); - } -} - -async function expectDirectWithoutWorker(): Promise { - const workerDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'Worker'); - Object.defineProperty(globalThis, 'Worker', { - configurable: true, - writable: true, - value: undefined, - }); - try { - const database = await Oliphaunt.open(); - try { - await expectAnswer(database); - await expectOwnedRawProtocolResponse(database); - } finally { - await database.close(); - } - } finally { - if (workerDescriptor === undefined) { - Reflect.deleteProperty(globalThis, 'Worker'); - } else { - Object.defineProperty(globalThis, 'Worker', workerDescriptor); - } - } -} - -async function expectTransaction(database: OliphauntDatabase): Promise { - const answer = await database.transaction(async (transaction) => { - const result = await transaction.queryRaw('SELECT $1::int + 1 AS answer', [41]); - return result.getText(0, 'answer'); - }); - if (answer !== '42') { - throw new Error(`browser smoke transaction expected 42, received ${JSON.stringify(answer)}`); - } -} - -async function expectOwnedRawProtocolResponse(database: OliphauntDatabase): Promise { - const retained = await database.execProtocolRaw( - simpleQuery("SELECT repeat('a', 10240) AS retained_payload"), - ); - const snapshot = retained.slice(); - const large = await database.execProtocolRaw( - simpleQuery("SELECT repeat('z', 1048576) AS large_payload"), - ); - if (large.byteLength < 1048576) { - throw new Error( - `browser worker returned a truncated large PGWire response: ${large.byteLength}`, - ); - } - if ( - retained.byteLength !== snapshot.byteLength || - !retained.every((byte, index) => byte === snapshot[index]) - ) { - throw new Error('browser worker response changed after the guest reused its output memory'); - } -} - -async function expectLogicalTools(): Promise { - const source = await WorkerOliphaunt.open({ extensions: [pgtap] }); - let sql: string; - try { - await psql(source, { script: logicalToolsSeed }); - sql = await pgDump(source); - if (!sql.includes('COPY public.logical_items') || sql.includes('--inserts')) { - throw new Error('browser pg_dump did not preserve standard plain COPY output'); - } - } finally { - await source.close(); - } - - const target = await WorkerOliphaunt.open({ extensions: [pgtap] }); - try { - await psql(target, { script: sql }); - const result = await target.queryRaw(logicalToolsVerify); - const actual = { - rows: Number(result.getText(0, 'rows')), - sum: Number(result.getText(0, 'sum')), - sequenceLastValue: Number(result.getText(0, 'sequence_last_value')), - quotedValue: result.getText(0, 'quoted_value'), - normalizedMatches: Number(result.getText(0, 'normalized_matches')), - extensionLoaded: result.getText(0, 'extension_loaded') === 't', - }; - if (JSON.stringify(actual) !== JSON.stringify(logicalToolsFixture.expected)) { - throw new Error( - `browser logical tool round trip differed from the shared fixture: ${JSON.stringify(actual)}`, - ); - } - return `${actual.rows}:${actual.sum}:${actual.sequenceLastValue}`; - } finally { - await target.close(); - } -} - -async function expectClockConsistency(database: OliphauntDatabase): Promise { - const wallClock = await database.queryRaw( - 'SELECT (extract(epoch FROM clock_timestamp()) * 1000)::bigint AS millis', - ); - const wallClockMillis = Number(wallClock.getText(0, 'millis')); - if (!Number.isFinite(wallClockMillis) || Math.abs(Date.now() - wallClockMillis) > 5_000) { - throw new Error(`browser WASI realtime clock drifted: ${wallClockMillis}`); - } - const plan = await database.queryRaw('EXPLAIN (ANALYZE, FORMAT JSON) SELECT pg_sleep(0.05)'); - const explain = JSON.parse(plan.getText(0, 'QUERY PLAN') ?? 'null'); - const elapsed = explain?.[0]?.['Execution Time']; - if (!Number.isFinite(elapsed) || elapsed < 25 || elapsed > 5_000) { - throw new Error(`browser WASI monotonic clock returned invalid elapsed time: ${elapsed}`); - } -} - -async function expectStartupSqlstate( - database: string, - sqlstate: string, - client: typeof Oliphaunt, -): Promise { - try { - const unexpected = await client.open({ database }); - await unexpected.close(); - throw new Error( - `browser smoke unexpectedly opened missing database ${JSON.stringify(database)}`, - ); - } catch (error) { - if ( - !(error instanceof PostgresError) || - error.sqlstate !== sqlstate || - error.severity !== 'FATAL' - ) { - throw error; - } - } -} - -async function expectFailedDirectOpenRecovery(): Promise { - await expectStartupSqlstate('oliphaunt_browser_smoke_missing_database', '3D000', Oliphaunt); - const reopened = await Oliphaunt.open(); - try { - await expectAnswer(reopened); - } finally { - await reopened.close(); - } -} - -async function expectFailedWorkerOpenRecovery(): Promise { - await expectStartupSqlstate( - 'oliphaunt_browser_worker_missing_database', - '3D000', - WorkerOliphaunt, - ); - const reopened = await WorkerOliphaunt.open(); - try { - await expectAnswer(reopened); - } finally { - await reopened.close(); - } -} - -async function expectExclusiveOwnership( - storage: WasixStorage, - extensions: readonly WasixExtensionDescriptor[], - provider: string, -): Promise { - try { - const duplicate = await Oliphaunt.open({ storage, extensions }); - await duplicate.close(); - throw new Error(`browser smoke opened one ${provider} database twice`); - } catch (error) { - if (!(error instanceof WasixStorageError) || error.code !== 'busy') { - throw error; - } - } -} - -async function expectOpfsPersistence( - extensions: readonly WasixExtensionDescriptor[], -): Promise { - const storage = opfs('browser-smoke'); - let database = await Oliphaunt.open({ storage, extensions }); - await expectExclusiveOwnership(storage, extensions, 'OPFS'); - await database.queryRaw('CREATE TABLE opfs_reopen_probe (answer integer NOT NULL)'); - await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (1)'); - // PostgreSQL normally retains the relation and WAL descriptors. This second - // operation proves that the host journal observes writes after initial open. - await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (2)'); - await database.close(); - - database = await WorkerOliphaunt.open({ storage, extensions }); - try { - await expectSynchronousOpfsTransport('browser-smoke'); - const reopened = await database.queryRaw( - 'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM opfs_reopen_probe', - [','], - ); - const answers = reopened.getText(0, 'answers'); - if (answers !== '1,2') { - throw new Error(`browser smoke did not reopen OPFS state: ${answers}`); - } - await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (3)'); - await database.queryRaw('CREATE TABLE opfs_sync_create_probe (answer integer NOT NULL)'); - await database.queryRaw('INSERT INTO opfs_sync_create_probe VALUES (99)'); - await database.execute('CHECKPOINT'); - } finally { - await database.close(); - } - - database = await Oliphaunt.open({ storage, extensions }); - try { - const reopened = await database.queryRaw( - 'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM opfs_reopen_probe', - [','], - ); - const answers = reopened.getText(0, 'answers'); - if (answers !== '1,2,3') { - throw new Error(`browser smoke did not reopen synchronous OPFS writes: ${answers}`); - } - const created = await database.queryRaw('SELECT answer FROM opfs_sync_create_probe'); - if (created.getText(0, 'answer') !== '99') { - throw new Error('browser smoke did not reopen a relation created through synchronous OPFS'); - } - return answers; - } finally { - await database.close(); - } -} - -async function expectSynchronousOpfsTransport(name: string): Promise { - const worker = new Worker(new URL('./opfs-transport-probe-worker.ts', import.meta.url), { - type: 'module', - }); - try { - const response = await new Promise< - { ok: true; transport: 'synchronous-access' | 'portable' } | { ok: false; error: string } - >((resolve, reject) => { - const timeout = setTimeout(() => reject(new Error('OPFS transport probe timed out')), 10_000); - worker.addEventListener( - 'error', - (event) => { - clearTimeout(timeout); - reject(event.error ?? new Error(event.message)); - }, - { once: true }, - ); - worker.addEventListener( - 'message', - (event: MessageEvent) => { - clearTimeout(timeout); - resolve( - event.data as - | { ok: true; transport: 'synchronous-access' | 'portable' } - | { ok: false; error: string }, - ); - }, - { once: true }, - ); - worker.postMessage({ name }); - }); - if (!response.ok) throw new Error(`OPFS transport probe failed: ${response.error}`); - if (response.transport !== 'synchronous-access') { - throw new Error( - 'browser smoke selected portable OPFS instead of the synchronous-access Worker path', - ); - } - } finally { - worker.terminate(); - } -} - -async function expectOpfsCrashRecovery(): Promise> { - const name = `browser-crash-${crypto.randomUUID()}`; - const worker = new Worker(new URL('./opfs-crash-probe-worker.ts', import.meta.url), { - type: 'module', - }); - try { - const response = await new Promise< - Readonly<{ ok: true }> | Readonly<{ ok: false; error: string }> - >((resolve, reject) => { - const timeout = setTimeout( - () => reject(new Error('OPFS crash-recovery setup timed out')), - 60_000, - ); - worker.addEventListener( - 'error', - (event) => { - clearTimeout(timeout); - reject(event.error ?? new Error(event.message)); - }, - { once: true }, - ); - worker.addEventListener( - 'message', - (event: MessageEvent) => { - clearTimeout(timeout); - resolve(event.data as Readonly<{ ok: true }> | Readonly<{ ok: false; error: string }>); - }, - { once: true }, - ); - worker.postMessage({ name }); - }); - if (!response.ok) throw new Error(`OPFS crash-recovery setup failed: ${response.error}`); - } finally { - worker.terminate(); - } - - const database = await Oliphaunt.open({ storage: opfs(name) }); - try { - const result = await database.queryRaw('SELECT answer FROM opfs_crash_probe'); - const answer = result.getText(0, 'answer'); - if (answer !== '73') { - throw new Error(`OPFS crash recovery returned an unexpected answer: ${answer}`); - } - const relationResult = await database.queryRaw(` - SELECT count(*)::text AS count - FROM pg_class - WHERE relname LIKE 'opfs_crash_burst_%' - `); - const relations = relationResult.getText(0, 'count'); - if (relations !== '48') { - throw new Error(`OPFS crash recovery returned an unexpected relation count: ${relations}`); - } - return { answer, relations }; - } finally { - await database.close(); - } -} - -async function exercisePgtap(database: OliphauntDatabase): Promise { - const version = await readPgtapVersion(database); - const plan = await database.queryRaw('SELECT plan(1)::text AS tap'); - if (plan.getText(0, 'tap') !== '1..1') { - throw new Error('browser smoke expected pgtap plan(1) to return 1..1'); - } - const assertion = await database.queryRaw("SELECT ok(true, 'browser pgtap')::text AS tap"); - if (assertion.getText(0, 'tap') !== 'ok 1 - browser pgtap') { - throw new Error('browser smoke expected pgtap ok() to report a passing assertion'); - } - await database.queryRaw('SELECT * FROM finish()'); - return version; -} - -async function installSelectedExtensions( - database: OliphauntDatabase, - extensions: readonly WasixExtensionDescriptor[], -): Promise { - for (const extension of extensions) { - const sqlName = `"${extension.sqlName.replaceAll('"', '""')}"`; - await database.execute(`CREATE EXTENSION IF NOT EXISTS ${sqlName}`); - } -} - -async function readPgtapVersion(database: OliphauntDatabase): Promise { - const pgtap = await database.queryRaw('SELECT pgtap_version()::text AS version'); - const version = pgtap.getText(0, 'version'); - if (version === null || version.length === 0) { - throw new Error('browser smoke expected pgtap_version() to return a version'); - } - return version; -} - -async function readPgUuidv7(database: OliphauntDatabase): Promise { - const result = await database.queryRaw('SELECT uuid_generate_v7()::text AS uuid'); - const uuid = result.getText(0, 'uuid'); - if ( - uuid === null || - !/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(uuid) - ) { - throw new Error(`browser smoke expected a version 7 UUID, received ${JSON.stringify(uuid)}`); - } - return uuid; -} - -async function expectSqlstate( - database: OliphauntDatabase, - query: string, - sqlstate: string, - parameters: ReadonlyArray = [], -): Promise { - try { - await database.queryRaw(query, parameters); - throw new Error(`browser smoke expected SQLSTATE ${sqlstate}`); - } catch (error) { - if (!(error instanceof PostgresError) || error.sqlstate !== sqlstate) { - throw error; - } - } -} - -async function expectAnswer(database: OliphauntDatabase): Promise { - const result = await database.queryRaw('SELECT 40 + 2 AS answer'); - const answer = result.getText(0, 'answer'); - if (answer !== '42') { - throw new Error(`browser smoke expected 42, received ${JSON.stringify(answer)}`); - } -} - -function requireElement(id: string): ElementType { - const element = document.getElementById(id); - if (element === null) { - throw new Error(`missing #${id}`); - } - return element as ElementType; -} - -function describeError(error: unknown): string { - return error instanceof Error ? (error.stack ?? error.message) : String(error); -} - -function auditDirectWorkerConstruction(): { - assertNoneAndRestore(): void; - restore(): void; -} { - const NativeWorker = globalThis.Worker; - let constructed = 0; - let restored = false; - class AuditedWorker extends NativeWorker { - constructor(scriptURL: string | URL, options?: WorkerOptions) { - constructed += 1; - super(scriptURL, options); - } - } - globalThis.Worker = AuditedWorker; - const restore = () => { - if (!restored) { - globalThis.Worker = NativeWorker; - restored = true; - } - }; - return { - assertNoneAndRestore() { - restore(); - if (constructed !== 0) { - throw new Error(`root entrypoint constructed ${constructed} Web Worker(s)`); - } - }, - restore, - }; -} diff --git a/examples/browser-wasix/package-smoke.ts b/examples/browser-wasix/package-smoke.ts deleted file mode 100644 index 8e83f16c3..000000000 --- a/examples/browser-wasix/package-smoke.ts +++ /dev/null @@ -1,152 +0,0 @@ -import pgtap from '@oliphaunt/extension-pgtap-wasix'; -import Oliphaunt, { type OliphauntDatabase } from '@oliphaunt/wasix-ts'; -import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker'; -import { indexedDB } from '@oliphaunt/wasix-ts/storage/indexed-db'; -import { pgDump, psql } from '@oliphaunt/wasix-tools'; - -import logicalToolsFixtureJson from './logical-tools.json?raw'; -import logicalToolsSeed from './logical-tools-seed.sql?raw'; -import logicalToolsVerify from './logical-tools-verify.sql?raw'; -import { expectDirectPgDump } from './direct-pg-dump-smoke.js'; -import { expectStructuredApi } from './structured-api-smoke.js'; - -const logicalToolsFixture = JSON.parse(logicalToolsFixtureJson) as { - expected: { - rows: number; - sum: number; - sequenceLastValue: number; - quotedValue: string; - normalizedMatches: number; - extensionLoaded: boolean; - }; -}; - -const status = requireElement('status'); -const output = requireElement('output'); - -try { - const storage = indexedDB('packed-browser-smoke'); - let database = await Oliphaunt.open({ - storage, - extensions: [pgtap], - }); - let pgtapVersion: string; - try { - await database.execute('CREATE EXTENSION pgtap'); - await expectAnswer(database); - await expectStructuredApi(database, 'packed browser direct'); - pgtapVersion = await readPgtapVersion(database); - await database.transaction(async (transaction) => { - await transaction.execute('CREATE TABLE packed_reopen_probe (answer integer NOT NULL)'); - await transaction.execute('INSERT INTO packed_reopen_probe VALUES ($1)', [42]); - }); - await database.execute('CHECKPOINT'); - await expectDirectPgDump(database); - } finally { - await database.close(); - } - - database = await WorkerOliphaunt.open({ - storage, - extensions: [pgtap], - }); - try { - await expectAnswer(database); - await expectStructuredApi(database, 'packed browser Worker'); - const reopened = await database.queryRaw('SELECT answer FROM packed_reopen_probe'); - const answer = reopened.getText(0, 'answer'); - if (answer !== '42') { - throw new Error(`packed browser package did not reopen IndexedDB state: ${answer}`); - } - if ((await readPgtapVersion(database)) !== pgtapVersion) { - throw new Error('packed browser package changed its pgtap carrier on worker reopen'); - } - await database.transaction(async (transaction) => { - await transaction.execute('INSERT INTO packed_reopen_probe VALUES ($1)', [43]); - }); - const count = ( - await database.queryRaw('SELECT count(*) AS count FROM packed_reopen_probe') - ).getText(0, 'count'); - if (count !== '2') { - throw new Error(`packed browser worker transaction produced ${count} rows`); - } - await database.execute('CHECKPOINT'); - const logicalTools = await expectLogicalTools(); - status.textContent = 'Packed browser package smoke passed.'; - output.textContent = JSON.stringify({ - direct: 42, - directPgDump: true, - worker: 42, - indexedDB: answer, - transactionRows: count, - pgtap: pgtapVersion, - logicalTools, - }); - document.documentElement.dataset.oliphauntSmoke = 'passed'; - } finally { - await database.close(); - } -} catch (error) { - status.textContent = 'Packed browser package smoke failed.'; - output.textContent = error instanceof Error ? (error.stack ?? error.message) : String(error); - document.documentElement.dataset.oliphauntSmoke = 'failed'; -} - -async function expectLogicalTools(): Promise { - const source = await WorkerOliphaunt.open({ extensions: [pgtap] }); - let sql: string; - try { - await psql(source, { script: logicalToolsSeed }); - sql = await pgDump(source); - if (!sql.includes('COPY public.logical_items') || sql.includes('--inserts')) { - throw new Error('packed browser pg_dump did not preserve standard plain COPY output'); - } - } finally { - await source.close(); - } - - const target = await WorkerOliphaunt.open({ extensions: [pgtap] }); - try { - await psql(target, { script: sql }); - const result = await target.queryRaw(logicalToolsVerify); - const actual = { - rows: Number(result.getText(0, 'rows')), - sum: Number(result.getText(0, 'sum')), - sequenceLastValue: Number(result.getText(0, 'sequence_last_value')), - quotedValue: result.getText(0, 'quoted_value'), - normalizedMatches: Number(result.getText(0, 'normalized_matches')), - extensionLoaded: result.getText(0, 'extension_loaded') === 't', - }; - if (JSON.stringify(actual) !== JSON.stringify(logicalToolsFixture.expected)) { - throw new Error( - `packed browser logical tool round trip differed from the shared fixture: ${JSON.stringify(actual)}`, - ); - } - return `${actual.rows}:${actual.sum}:${actual.sequenceLastValue}`; - } finally { - await target.close(); - } -} - -async function expectAnswer(database: OliphauntDatabase): Promise { - const result = await database.queryRaw('SELECT 40 + 2 AS answer'); - const answer = result.getText(0, 'answer'); - if (answer !== '42') { - throw new Error(`packed browser package expected 42, received ${JSON.stringify(answer)}`); - } -} - -async function readPgtapVersion(database: OliphauntDatabase): Promise { - const result = await database.queryRaw('SELECT pgtap_version()::text AS version'); - const version = result.getText(0, 'version'); - if (version === null || version.length === 0) { - throw new Error('packed browser package returned no pgtap version'); - } - return version; -} - -function requireElement(id: string): ElementType { - const element = document.getElementById(id); - if (element === null) throw new Error(`missing #${id}`); - return element as ElementType; -} diff --git a/examples/browser-wasix/tsconfig.json b/examples/browser-wasix/tsconfig.json deleted file mode 100644 index 4e6454003..000000000 --- a/examples/browser-wasix/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "../../src/bindings/wasix-ts/tsconfig.json", - "compilerOptions": { - "module": "ESNext", - "moduleResolution": "Bundler", - "noEmit": true, - "paths": { - "@oliphaunt/liboliphaunt-wasix": ["../../src/bindings/wasix-ts/src/runtime-carrier-shim.d.ts"], - "@oliphaunt/liboliphaunt-wasix-tools": ["../../src/bindings/wasix-ts/tools-package/src/runtime-carrier-shim.d.ts"], - "@oliphaunt/wasix-ts": ["../../src/bindings/wasix-ts/src/index.ts"], - "@oliphaunt/wasix-ts/worker": ["../../src/bindings/wasix-ts/src/worker-entry.ts"], - "@oliphaunt/wasix-ts/internal/tools": ["../../src/bindings/wasix-ts/src/internal.ts"], - "@oliphaunt/wasix-tools": ["../../src/bindings/wasix-ts/tools-package/src/index.ts"], - "@oliphaunt/wasix-ts/*": ["../../src/bindings/wasix-ts/src/*"] - }, - "rootDir": "../..", - "types": ["node", "vite/client"] - }, - "include": ["./**/*.ts"] -} diff --git a/examples/browser-wasix/vite.config.ts b/examples/browser-wasix/vite.config.ts deleted file mode 100644 index 1c51b8695..000000000 --- a/examples/browser-wasix/vite.config.ts +++ /dev/null @@ -1,462 +0,0 @@ -import { createHash } from 'node:crypto'; -import { readFile } from 'node:fs/promises'; -import { createRequire } from 'node:module'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { defineConfig, type Plugin } from 'vite'; - -const exampleRoot = dirname(fileURLToPath(import.meta.url)); -const repositoryRoot = resolve(exampleRoot, '../..'); -const bindingRoot = resolve(repositoryRoot, 'src/bindings/wasix-ts'); -const bindingLibRoot = resolve(bindingRoot, 'lib'); -const assetRoot = resolve(repositoryRoot, 'target/oliphaunt-wasix/assets'); -const pgliteAssetRoot = resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist'); -const databaseRootContractFile = resolve( - repositoryRoot, - 'src/shared/fixtures/storage/database-root.json', -); -const packedConsumerRoot = process.env.OLIPHAUNT_WASIX_BROWSER_PACKAGE_ROOT; -const packedConsumer = packedConsumerRoot === undefined ? undefined : resolve(packedConsumerRoot); -export default defineConfig({ - root: packedConsumer ?? exampleRoot, - resolve: { - ...(packedConsumer === undefined - ? { - alias: [ - { - find: /^@oliphaunt\/wasix-tools$/, - replacement: resolve( - repositoryRoot, - 'src/bindings/wasix-ts/tools-package/src/index.ts', - ), - }, - { - find: /^@oliphaunt\/wasix-ts\/internal\/tools$/, - replacement: resolve(bindingLibRoot, 'internal.js'), - }, - { - find: /^@oliphaunt\/wasix-ts$/, - replacement: resolve(bindingLibRoot, 'index.js'), - }, - { - find: /^@oliphaunt\/wasix-ts\/worker$/, - replacement: resolve(bindingLibRoot, 'worker-entry.js'), - }, - { - find: /^@oliphaunt\/wasix-ts\/(.+)$/, - replacement: `${bindingLibRoot}/$1.js`, - }, - ], - } - : { - alias: [ - { - find: /^fzstd$/, - replacement: createRequire( - resolve(packedConsumer, 'node_modules/@oliphaunt/wasix-ts/package.json'), - ).resolve('fzstd'), - }, - ], - dedupe: [ - '@oliphaunt/wasix-ts', - '@oliphaunt/liboliphaunt-wasix', - '@oliphaunt/wasix-tools', - '@oliphaunt/liboliphaunt-wasix-tools', - '@oliphaunt/extension-pgtap-wasix', - 'fzstd', - ], - }), - }, - optimizeDeps: { - ...(packedConsumer === undefined - ? {} - : { - exclude: [ - '@oliphaunt/wasix-ts', - '@oliphaunt/liboliphaunt-wasix', - '@oliphaunt/wasix-tools', - '@oliphaunt/liboliphaunt-wasix-tools', - '@oliphaunt/extension-pgtap-wasix', - ], - }), - esbuildOptions: { - target: 'esnext', - }, - }, - build: { - target: 'esnext', - }, - worker: { - format: 'es', - }, - server: { - fs: { - allow: [repositoryRoot, ...(packedConsumer === undefined ? [] : [packedConsumer])], - }, - headers: { - 'Cross-Origin-Embedder-Policy': 'require-corp', - 'Cross-Origin-Opener-Policy': 'same-origin', - }, - }, - plugins: - packedConsumer === undefined ? [wasixAssets()] : [packedBrowserPackageExports(packedConsumer)], -}); - -function packedBrowserPackageExports(consumerRoot: string): Plugin { - const expected = new Map([ - ['@oliphaunt/wasix-ts', '/@oliphaunt/wasix-ts/lib/index.js'], - ['@oliphaunt/wasix-ts/worker', '/@oliphaunt/wasix-ts/lib/worker-entry.js'], - ['@oliphaunt/wasix-ts/storage/indexed-db', '/@oliphaunt/wasix-ts/lib/storage/indexed-db.js'], - ['@oliphaunt/liboliphaunt-wasix', '/@oliphaunt/liboliphaunt-wasix/index.js'], - ['@oliphaunt/wasix-tools', '/@oliphaunt/wasix-tools/lib/index.js'], - ['@oliphaunt/liboliphaunt-wasix-tools', '/@oliphaunt/liboliphaunt-wasix-tools/index.js'], - ['@oliphaunt/extension-pgtap-wasix', '/@oliphaunt/extension-pgtap-wasix/index.js'], - ]); - return { - name: 'oliphaunt-packed-browser-package-exports', - enforce: 'pre', - async resolveId(source, importer) { - const suffix = expected.get(source); - if (suffix === undefined) return undefined; - const resolved = await this.resolve(source, importer, { skipSelf: true }); - if (resolved === null) { - throw new Error(`packed browser consumer could not resolve ${source}`); - } - const id = resolved.id.split('?')[0]?.split('\\').join('/'); - if (id === undefined || !id.endsWith(suffix)) { - throw new Error( - `packed browser consumer resolved ${source} to ${resolved.id}, expected ${suffix}`, - ); - } - if (!id.includes('/node_modules/')) { - throw new Error(`packed browser consumer did not load ${source} from its install`); - } - return resolved; - }, - configResolved(config) { - if (resolve(config.root) !== consumerRoot) { - throw new Error('packed browser consumer did not become the Vite project root'); - } - }, - }; -} - -function wasixAssets(): Plugin { - const virtualModules = new Map([ - ['@oliphaunt/liboliphaunt-wasix', '\0oliphaunt:liboliphaunt-wasix'], - ['@oliphaunt/liboliphaunt-wasix-tools', '\0oliphaunt:liboliphaunt-wasix-tools'], - ['@oliphaunt/extension-pgtap-wasix', '\0oliphaunt:extension-pgtap-wasix'], - ['@oliphaunt/extension-pg-uuidv7-wasix', '\0oliphaunt:extension-pg-uuidv7-wasix'], - ['@oliphaunt/extension-postgis-wasix', '\0oliphaunt:extension-postgis-wasix'], - ]); - const packageByVirtualModule = new Map( - [...virtualModules].map(([packageName, virtualModule]) => [virtualModule, packageName]), - ); - const descriptorPromises = new Map>>(); - let runtimeIdentityPromise: - | Promise<{ postgresMajor: number; physicalFormat: string }> - | undefined; - const routes = new Map([ - ['/runtime', resolve(assetRoot, 'oliphaunt.wasix.tar.zst')], - ['/cluster-seed-standard', resolve(assetRoot, 'cluster-seeds/standard.tar.zst')], - ['/cluster-seed-standard-manifest', resolve(assetRoot, 'cluster-seeds/standard.json')], - ['/manifest', resolve(assetRoot, 'manifest.json')], - ['/tools/pg_dump', resolve(assetRoot, 'bin/pg_dump.wasix.wasm')], - ['/tools/psql', resolve(assetRoot, 'bin/psql.wasix.wasm')], - ['/extensions/pgtap', resolve(assetRoot, 'extensions/pgtap.tar.zst')], - ['/extensions/pg_uuidv7', resolve(assetRoot, 'extensions/pg_uuidv7.tar.zst')], - ['/extensions/postgis', resolve(assetRoot, 'extensions/postgis.tar.zst')], - ['/pglite.data', resolve(pgliteAssetRoot, 'pglite.data')], - ['/pglite.wasm', resolve(pgliteAssetRoot, 'pglite.wasm')], - ['/initdb.wasm', resolve(pgliteAssetRoot, 'initdb.wasm')], - ]); - return { - name: 'oliphaunt-wasix-assets', - enforce: 'pre', - resolveId(id) { - return virtualModules.get(id); - }, - async load(id) { - const packageName = packageByVirtualModule.get(id); - if (packageName === undefined) { - return undefined; - } - let descriptorPromise = descriptorPromises.get(packageName); - if (descriptorPromise === undefined) { - descriptorPromise = developmentDescriptor(packageName); - descriptorPromises.set(packageName, descriptorPromise); - } - const descriptor = await descriptorPromise; - let namedRuntimeExports = ''; - if (packageName === '@oliphaunt/liboliphaunt-wasix') { - runtimeIdentityPromise ??= developmentWasixIdentity(); - const identity = await runtimeIdentityPromise; - namedRuntimeExports = - `export const POSTGRES_MAJOR = ${JSON.stringify(identity.postgresMajor)};\n` + - `export const PHYSICAL_FORMAT = ${JSON.stringify(identity.physicalFormat)};\n`; - } - return ( - namedRuntimeExports + - `const descriptor = Object.freeze(${JSON.stringify(descriptor)});\n` + - 'export { descriptor };\nexport default descriptor;\n' - ); - }, - configureServer(server) { - server.middlewares.use('/wasix-assets', async (request, response, next) => { - const path = routes.get(request.url ?? ''); - if (path === undefined) { - next(); - return; - } - try { - const source = await readFile(path); - const bytes = path.endsWith('manifest.json') ? coreManifest(source) : source; - response.statusCode = 200; - const contentType = path.endsWith('.json') - ? 'application/json' - : path.endsWith('.wasm') - ? 'application/wasm' - : path.endsWith('.data') - ? 'application/octet-stream' - : 'application/zstd'; - response.setHeader('Content-Type', contentType); - response.setHeader('Cross-Origin-Resource-Policy', 'same-origin'); - response.end(bytes); - } catch (error) { - response.statusCode = 500; - response.end( - `Missing WASIX assets. Run liboliphaunt-wasix:runtime-portable first.\n${String(error)}`, - ); - } - }); - }, - }; -} - -async function developmentWasixIdentity(): Promise<{ - postgresMajor: number; - physicalFormat: string; -}> { - const contract = JSON.parse(await readFile(databaseRootContractFile, 'utf8')) as Record< - string, - unknown - >; - const families = requireRecord(contract.families, 'database-root families'); - const wasix = requireRecord(families.wasix, 'database-root WASIX family'); - const postgresMajor = contract.postgresMajor; - const physicalFormat = wasix.physicalFormat; - if (!Number.isInteger(postgresMajor) || typeof physicalFormat !== 'string' || !physicalFormat) { - throw new Error('shared database-root fixture has no valid WASIX physical identity'); - } - return { postgresMajor: postgresMajor as number, physicalFormat }; -} - -async function developmentDescriptor(packageName: string): Promise> { - const manifestBytes = await readFile(resolve(assetRoot, 'manifest.json')); - const manifest = JSON.parse(manifestBytes.toString('utf8')) as Record; - const versions = JSON.parse( - await readFile(resolve(repositoryRoot, '.release-please-manifest.json'), 'utf8'), - ) as Record; - const runtimeVersion = requireVersion(versions, 'src/runtimes/liboliphaunt/wasix'); - - if (packageName === '@oliphaunt/liboliphaunt-wasix') { - const runtime = requireRecord(manifest.runtime, 'runtime manifest entry'); - const clusterSeeds = requireRecord(manifest['cluster-seeds'], 'cluster seed manifest entry'); - const standardSeed = requireRecord(clusterSeeds.standard, 'standard cluster seed entry'); - const runtimeBytes = await readFile(resolve(assetRoot, String(runtime.archive))); - const standardSeedBytes = await readFile(resolve(assetRoot, String(standardSeed.archive))); - const standardSeedManifestBytes = await readFile( - resolve(assetRoot, String(standardSeed.manifest)), - ); - const projectedManifest = coreManifest(manifestBytes); - return { - schema: 'oliphaunt-wasix-runtime-v2', - runtime: 'wasix', - product: 'liboliphaunt-wasix', - version: runtimeVersion, - runtimeArchive: { - archive: runtime.archive, - sha256: sha256(runtimeBytes), - size: runtimeBytes.length, - source: '/wasix-assets/runtime', - }, - standardSeedArchive: { - archive: standardSeed.archive, - sha256: sha256(standardSeedBytes), - size: standardSeedBytes.length, - source: '/wasix-assets/cluster-seed-standard', - }, - standardSeedManifest: { - sha256: sha256(standardSeedManifestBytes), - size: standardSeedManifestBytes.length, - source: '/wasix-assets/cluster-seed-standard-manifest', - }, - manifest: { - sha256: sha256(projectedManifest), - size: projectedManifest.length, - source: '/wasix-assets/manifest', - }, - }; - } - - if (packageName === '@oliphaunt/liboliphaunt-wasix-tools') { - const pgDump = requireRecord(manifest['pg-dump'], 'pg_dump manifest entry'); - const psql = requireRecord(manifest.psql, 'psql manifest entry'); - return { - schema: 'oliphaunt-wasix-tools-v1', - product: 'oliphaunt-wasix-tools', - version: runtimeVersion, - runtimeProduct: 'liboliphaunt-wasix', - runtimeVersion, - pgDump: { - name: 'pg_dump', - sha256: pgDump.sha256, - size: pgDump.size, - source: '/wasix-assets/tools/pg_dump', - }, - psql: { - name: 'psql', - sha256: psql.sha256, - size: psql.size, - source: '/wasix-assets/tools/psql', - }, - }; - } - - const extension = extensionPackage(packageName); - const rows = manifest.extensions; - if (!Array.isArray(rows)) { - throw new Error('canonical development manifest has no extension rows'); - } - const row = rows.find( - (candidate) => - candidate !== null && - typeof candidate === 'object' && - (candidate as Record)['sql-name'] === extension.sqlName, - ); - const metadata = requireRecord(row, `${extension.sqlName} manifest entry`); - const lifecycle = requireRecord(metadata.lifecycle, `${extension.sqlName} lifecycle`); - const version = requireVersion(versions, extension.releasePath); - const carrier = { - product: extension.product, - version, - sqlName: extension.sqlName, - archive: metadata.archive, - sha256: metadata.sha256, - size: metadata.size, - source: `/wasix-assets/extensions/${extension.sqlName}`, - install: { - schema: 'oliphaunt-wasix-extension-install-v1', - name: metadata.name, - nativeModule: metadata['native-module'] ?? null, - nativeModules: requireArray(metadata['native-modules'], 'native modules').map((value) => { - const module = requireRecord(value, 'native module'); - return { - name: module.name, - path: module.path, - sha256: module.sha256, - moduleSha256: module['module-sha256'], - size: module.size, - }; - }), - dependencies: metadata.dependencies, - coreExportsRequired: metadata['core-exports-required'], - loadOrder: metadata['load-order'], - lifecycle: { - createExtension: lifecycle['create-extension'], - createSchema: lifecycle['create-schema'], - loadSql: lifecycle['load-sql'], - postCreateSql: lifecycle['post-create-sql'], - startupConfig: lifecycle['startup-config'], - preloadRequired: lifecycle['preload-required'], - restartRequired: lifecycle['restart-required'], - sharedMemoryRequired: lifecycle['shared-memory-required'], - }, - installedFiles: metadata['installed-files'], - unresolvedImports: requireArray(metadata['unresolved-imports'], 'unresolved imports').map( - (value) => { - const entry = requireRecord(value, 'unresolved import'); - return { module: entry.module, name: entry.name, kind: entry.kind }; - }, - ), - }, - }; - return { - schema: 'oliphaunt-wasix-extension-v1', - runtime: 'wasix', - product: extension.product, - version, - compatibility: { - extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1', - postgresMajor: '18', - wasixRuntimeProduct: 'liboliphaunt-wasix', - wasixRuntimeVersion: runtimeVersion, - }, - sqlName: extension.sqlName, - carriers: [carrier], - }; -} - -function extensionPackage(packageName: string): { - product: string; - releasePath: string; - sqlName: string; -} { - switch (packageName) { - case '@oliphaunt/extension-pgtap-wasix': - return { - product: 'oliphaunt-extension-pgtap', - releasePath: 'src/extensions/external/pgtap', - sqlName: 'pgtap', - }; - case '@oliphaunt/extension-pg-uuidv7-wasix': - return { - product: 'oliphaunt-extension-pg-uuidv7', - releasePath: 'src/extensions/external/pg_uuidv7', - sqlName: 'pg_uuidv7', - }; - case '@oliphaunt/extension-postgis-wasix': - return { - product: 'oliphaunt-extension-postgis', - releasePath: 'src/extensions/external/postgis', - sqlName: 'postgis', - }; - default: - throw new Error(`unsupported development WASIX package ${packageName}`); - } -} - -function requireRecord(value: unknown, label: string): Record { - if (value === null || typeof value !== 'object' || Array.isArray(value)) { - throw new Error(`${label} must be an object`); - } - return value as Record; -} - -function requireArray(value: unknown, label: string): unknown[] { - if (!Array.isArray(value)) { - throw new Error(`${label} must be an array`); - } - return value; -} - -function requireVersion(versions: Record, productPath: string): string { - const version = versions[productPath]; - if (version === undefined) { - throw new Error(`missing release version for ${productPath}`); - } - return version; -} - -function sha256(bytes: Uint8Array): string { - return createHash('sha256').update(bytes).digest('hex'); -} - -function coreManifest(bytes: Uint8Array): Uint8Array { - const manifest = JSON.parse(new TextDecoder().decode(bytes)) as Record; - manifest.extensions = []; - delete manifest['pg-dump']; - delete manifest.psql; - return new TextEncoder().encode(`${JSON.stringify(manifest, null, 2)}\n`); -} diff --git a/examples/electron-wasix/README.md b/examples/electron-wasix/README.md deleted file mode 100644 index 1e8c0ecc4..000000000 --- a/examples/electron-wasix/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Electron WASIX Todo - -Electron keeps WASIX in a Rust sidecar. The sidecar starts -the root `AsyncOliphauntServer`, prints a local PostgreSQL URL, and stays alive until -Electron exits. The Electron main process uses `pg` with a single connection -and exposes the same preload API as the native Electron example. Its explicit -Rust smoke test covers `pg_dump` and `psql` through the direct -`oliphaunt_wasix` API; normal sidecar startup does not run either -tool. - -```sh -pnpm --dir examples/electron-wasix install -pnpm --dir examples/electron-wasix start -``` - -For packaged apps, build the `src-wasix` binary and set -`OLIPHAUNT_WASIX_TODO_SIDECAR` to its path before launching Electron. diff --git a/examples/electron-wasix/package.json b/examples/electron-wasix/package.json deleted file mode 100644 index ec66302af..000000000 --- a/examples/electron-wasix/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "oliphaunt-example-electron-wasix", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "build": "tsc -p tsconfig.main.json && vite build", - "start": "pnpm run build && electron dist/main/main-process.js", - "dev:renderer": "vite" - }, - "dependencies": { - "kysely": "^0.29.2", - "pg": "^8.16.3" - }, - "devDependencies": { - "@types/node": "^24.10.1", - "@types/pg": "^8.15.6", - "electron": "^39.2.5", - "typescript": "^5.9.3", - "vite": "^6.0.3" - } -} diff --git a/examples/electron-wasix/src-wasix/Cargo.toml b/examples/electron-wasix/src-wasix/Cargo.toml deleted file mode 100644 index 39990d546..000000000 --- a/examples/electron-wasix/src-wasix/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "oliphaunt-electron-wasix-sidecar" -version = "0.0.0" -edition = "2021" -publish = false - -[workspace] - -[dependencies] -anyhow = "1" -oliphaunt-wasix = { version = "=0.2.0", features = [ - "extension-hstore", - "extension-pg-trgm", - "extension-unaccent", -] } -serde_json = "1" -tokio = { version = "1", features = ["rt-multi-thread"] } - -[dev-dependencies] -oliphaunt-wasix = { version = "=0.2.0", features = ["tools"] } -oliphaunt-wasix-tools = { version = "=0.2.0" } - -[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dependencies] -liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu = { version = "=0.2.0" } - -[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dev-dependencies] -oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu = { version = "=0.2.0" } diff --git a/examples/electron-wasix/src-wasix/src/main.rs b/examples/electron-wasix/src-wasix/src/main.rs deleted file mode 100644 index 971925df5..000000000 --- a/examples/electron-wasix/src-wasix/src/main.rs +++ /dev/null @@ -1,91 +0,0 @@ -use std::env; -use std::io::{self, Write}; -use std::path::PathBuf; -use std::thread; - -use anyhow::{Context, Result, bail}; -use oliphaunt_wasix::{AsyncOliphauntServer, DatabaseStorage, Extension}; -#[cfg(test)] -use oliphaunt_wasix::{Oliphaunt, tools}; -use serde_json::json; - -fn main() -> Result<()> { - let directory = parse_directory()?; - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .context("build WASIX sidecar Tokio runtime")?; - let server = runtime.block_on(start_server(directory))?; - println!("{}", json!({ "databaseUrl": server.connection_string() })); - io::stdout().flush()?; - let _server = server; - loop { - thread::park(); - } -} - -async fn start_server(directory: PathBuf) -> Result { - let server = AsyncOliphauntServer::builder() - .storage(DatabaseStorage::Directory(directory)) - .extensions([ - Extension::HSTORE, - Extension::PG_TRGM, - Extension::UNACCENT, - ]) - .start() - .await - .context("start oliphaunt-wasix server")?; - Ok(server) -} - -#[cfg(test)] -fn validate_wasix_tools() -> Result<()> { - let mut database = Oliphaunt::open()?; - let dump = database.pg_dump(tools::PgDumpOptions::new().arg("--schema-only"))?; - anyhow::ensure!( - dump.contains("PostgreSQL database dump"), - "pg_dump SQL backup smoke did not look like a PostgreSQL dump" - ); - let psql = database.psql(tools::PsqlOptions::new().arg("-tA").command("SELECT 1"))?; - anyhow::ensure!( - psql.lines().any(|line| line.trim() == "1"), - "psql smoke did not return SELECT 1 output" - ); - database.close()?; - Ok(()) -} - -fn parse_directory() -> Result { - let mut args = env::args().skip(1); - while let Some(arg) = args.next() { - if arg == "--directory" { - let value = args.next().context("--directory requires a path")?; - return Ok(PathBuf::from(value)); - } - } - bail!("usage: oliphaunt-electron-wasix-sidecar --directory ") -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn startup_smoke_runs_split_wasix_tools() { - let directory = std::env::temp_dir().join(format!( - "oliphaunt-electron-wasix-sidecar-smoke-{}", - std::process::id() - )); - let _ = std::fs::remove_dir_all(&directory); - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .expect("build WASIX sidecar smoke runtime"); - validate_wasix_tools().expect("run explicit split WASIX tools smoke"); - let server = runtime - .block_on(start_server(directory.clone())) - .expect("start sidecar server after split WASIX tools smoke"); - drop(server); - let _ = std::fs::remove_dir_all(directory); - } -} diff --git a/examples/electron-wasix/src/main-process.ts b/examples/electron-wasix/src/main-process.ts deleted file mode 100644 index b62be4670..000000000 --- a/examples/electron-wasix/src/main-process.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { app, BrowserWindow, ipcMain } from "electron"; -import { dirname, join } from "node:path"; -import { fileURLToPath, pathToFileURL } from "node:url"; - -import { closeStore, createTodo, deleteTodo, listTodos, toggleTodo } from "./todos.js"; -import type { CreateTodoInput, StatusFilter } from "./types.js"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -if (process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER) { - process.send?.({ event: "main-start", cwd: process.cwd(), send: typeof process.send }); -} - -function createWindow() { - const window = new BrowserWindow({ - width: 1100, - height: 760, - title: "Oliphaunt Electron WASIX Todo", - webPreferences: { - preload: join(__dirname, "preload.cjs"), - contextIsolation: true, - nodeIntegration: false, - }, - }); - - const devServer = process.env.VITE_DEV_SERVER_URL; - if (devServer) { - void window.loadURL(devServer); - } else { - void window.loadFile(join(__dirname, "../renderer/index.html")); - } - return window; -} - -async function installTestDriver(window: BrowserWindow) { - if (!process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER) return; - console.error("Installing Electron todo e2e driver"); - const driver = await import( - pathToFileURL(join(process.cwd(), "../tools/electron-test-driver.mjs")).href - ); - driver.installElectronTodoTestDriver({ app, window, close: closeStore }); -} - -ipcMain.handle( - "todos:list", - (_event, filter: { search: string; status: StatusFilter }) => listTodos(app.getPath("userData"), filter), -); -ipcMain.handle("todos:create", (_event, input: CreateTodoInput) => - createTodo(app.getPath("userData"), input), -); -ipcMain.handle("todos:toggle", (_event, id: number) => toggleTodo(app.getPath("userData"), id)); -ipcMain.handle("todos:delete", (_event, id: number) => deleteTodo(app.getPath("userData"), id)); - -process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER && - process.send?.({ event: "before-when-ready" }); -void app - .whenReady() - .then(async () => { - process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER && - process.send?.({ event: "after-when-ready" }); - await installTestDriver(createWindow()); - }) - .catch((error) => { - console.error(error); - app.exit(1); - }); - -app.on("activate", () => { - if (BrowserWindow.getAllWindows().length === 0) createWindow(); -}); - -app.on("window-all-closed", () => { - if (process.platform !== "darwin") app.quit(); -}); - -app.on("before-quit", (event) => { - event.preventDefault(); - closeStore() - .catch((error) => console.error(error)) - .finally(() => app.exit(0)); -}); diff --git a/examples/electron-wasix/src/preload.cts b/examples/electron-wasix/src/preload.cts deleted file mode 100644 index 0cebe0537..000000000 --- a/examples/electron-wasix/src/preload.cts +++ /dev/null @@ -1,19 +0,0 @@ -import { contextBridge, ipcRenderer } from "electron"; -import type { CreateTodoInput, StatusFilter, TodoApi } from "./types.js"; - -const api: TodoApi = { - listTodos(filter: { search: string; status: StatusFilter }) { - return ipcRenderer.invoke("todos:list", filter); - }, - createTodo(input: CreateTodoInput) { - return ipcRenderer.invoke("todos:create", input); - }, - toggleTodo(id: number) { - return ipcRenderer.invoke("todos:toggle", id); - }, - deleteTodo(id: number) { - return ipcRenderer.invoke("todos:delete", id); - }, -}; - -contextBridge.exposeInMainWorld("todos", api); diff --git a/examples/electron-wasix/src/renderer.ts b/examples/electron-wasix/src/renderer.ts deleted file mode 100644 index 2dd749fcd..000000000 --- a/examples/electron-wasix/src/renderer.ts +++ /dev/null @@ -1 +0,0 @@ -import "../../electron/src/renderer.ts"; diff --git a/examples/electron-wasix/src/sidecar.ts b/examples/electron-wasix/src/sidecar.ts deleted file mode 100644 index faf081c4c..000000000 --- a/examples/electron-wasix/src/sidecar.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { spawn, type ChildProcess } from "node:child_process"; -import { existsSync } from "node:fs"; -import { join } from "node:path"; -import { createInterface } from "node:readline"; - -export type WasixSidecar = { - databaseUrl: string; - process: ChildProcess; -}; - -export async function startWasixSidecar(directory: string): Promise { - const configured = process.env.OLIPHAUNT_WASIX_TODO_SIDECAR; - const command = configured || "cargo"; - const args = configured - ? ["--directory", directory] - : [ - "run", - "--quiet", - "--manifest-path", - join(process.cwd(), "src-wasix/Cargo.toml"), - "--", - "--directory", - directory, - ]; - if (configured && !existsSync(configured)) { - throw new Error(`OLIPHAUNT_WASIX_TODO_SIDECAR does not exist: ${configured}`); - } - - const child = spawn(command, args, { - cwd: process.cwd(), - stdio: ["ignore", "pipe", "pipe"], - }); - child.stderr.on("data", (chunk) => { - process.stderr.write(chunk); - }); - - const lines = createInterface({ input: child.stdout }); - const firstLine = await new Promise((resolve, reject) => { - const timer = setTimeout(() => reject(new Error("timed out waiting for WASIX sidecar")), 60_000); - child.once("exit", (code) => { - clearTimeout(timer); - reject(new Error(`WASIX sidecar exited before ready: ${code ?? "signal"}`)); - }); - lines.once("line", (line) => { - clearTimeout(timer); - resolve(line); - }); - }); - const payload = JSON.parse(firstLine) as { databaseUrl?: string }; - if (!payload.databaseUrl) throw new Error("WASIX sidecar did not print databaseUrl"); - return { - databaseUrl: payload.databaseUrl, - process: child, - }; -} diff --git a/examples/electron-wasix/src/todos.ts b/examples/electron-wasix/src/todos.ts deleted file mode 100644 index 40ce9e837..000000000 --- a/examples/electron-wasix/src/todos.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { join } from "node:path"; - -import { Kysely, PostgresDialect, sql, type Generated } from "kysely"; -import pg from "pg"; - -import { startWasixSidecar, type WasixSidecar } from "./sidecar.js"; -import type { CreateTodoInput, StatusFilter, Todo } from "./types.js"; - -const { Pool } = pg; - -type TodoTable = { - id: Generated; - title: string; - notes: string; - tags: string; - done: Generated; - priority: number; - created_at: Generated; - updated_at: Generated; -}; - -type TodoDatabase = { - todos: TodoTable; -}; - -type TodoRecord = { - id: string; - title: string; - notes: string; - area: string; - context: string; - done: string; - priority: string; - created_at: string; - updated_at: string; -}; - -const schemaStatements = [ - "CREATE EXTENSION IF NOT EXISTS hstore", - "CREATE EXTENSION IF NOT EXISTS pg_trgm", - "CREATE EXTENSION IF NOT EXISTS unaccent", - `CREATE TABLE IF NOT EXISTS todos ( - id bigserial PRIMARY KEY, - title text NOT NULL, - notes text NOT NULL DEFAULT '', - tags hstore NOT NULL DEFAULT ''::hstore, - done boolean NOT NULL DEFAULT false, - priority integer NOT NULL DEFAULT 2 CHECK (priority BETWEEN 1 AND 3), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now() - )`, - "CREATE INDEX IF NOT EXISTS todos_title_trgm ON todos USING gin (title gin_trgm_ops)", -]; - -type Store = { - db: Kysely; - sidecar: WasixSidecar; -}; - -let storePromise: Promise | undefined; - -async function getStore(userData: string) { - storePromise ??= openStore(userData); - return storePromise; -} - -async function openStore(userData: string): Promise { - const sidecar = await startWasixSidecar(join(userData, "oliphaunt-wasix-todos")); - const db = new Kysely({ - dialect: new PostgresDialect({ - pool: new Pool({ - connectionString: sidecar.databaseUrl, - max: 1, - }), - }), - }); - for (const statement of schemaStatements) { - await sql.raw(statement).execute(db); - } - return { db, sidecar }; -} - -export async function listTodos( - userData: string, - filter: { search: string; status: StatusFilter }, -) { - const { db } = await getStore(userData); - const rows = await db - .selectFrom("todos") - .select(todoColumns) - .where(searchPredicate(filter.search)) - .where(statusPredicate(filter.status)) - .orderBy("done", "asc") - .orderBy("priority", "asc") - .orderBy("updated_at", "desc") - .orderBy("id", "desc") - .execute(); - return rows.map(todoFromRow); -} - -export async function createTodo(userData: string, input: CreateTodoInput) { - const { db } = await getStore(userData); - const row = await db - .insertInto("todos") - .values({ - title: input.title, - notes: input.notes, - tags: sql`hstore(ARRAY['area', ${input.area}, 'context', ${input.context}])`, - priority: clampPriority(input.priority), - }) - .returning(todoColumns) - .executeTakeFirstOrThrow(); - return todoFromRow(row); -} - -export async function toggleTodo(userData: string, id: number) { - const { db } = await getStore(userData); - const row = await db - .updateTable("todos") - .set({ - done: sql`NOT done`, - updated_at: sql`now()`, - }) - .where("id", "=", String(id)) - .returning(todoColumns) - .executeTakeFirstOrThrow(); - return todoFromRow(row); -} - -export async function deleteTodo(userData: string, id: number) { - const { db } = await getStore(userData); - await db.deleteFrom("todos").where("id", "=", String(id)).execute(); -} - -export async function closeStore() { - if (!storePromise) return; - const store = await storePromise; - await store.db.destroy(); - store.sidecar.process.kill(); - storePromise = undefined; -} - -function todoColumns() { - return [ - sql`id::text`.as("id"), - "title", - "notes", - sql`COALESCE(tags -> 'area', '')`.as("area"), - sql`COALESCE(tags -> 'context', '')`.as("context"), - sql`done::text`.as("done"), - sql`priority::text`.as("priority"), - sql`to_char(created_at, 'YYYY-MM-DD HH24:MI')`.as("created_at"), - sql`to_char(updated_at, 'YYYY-MM-DD HH24:MI')`.as("updated_at"), - ] as const; -} - -function searchPredicate(search: string) { - return sql`( - ${search}::text = '' - OR unaccent(title || ' ' || notes) ILIKE '%' || unaccent(${search}::text) || '%' - OR COALESCE(tags -> 'area', '') ILIKE '%' || ${search}::text || '%' - OR COALESCE(tags -> 'context', '') ILIKE '%' || ${search}::text || '%' - OR tags ? ${search}::text - )`; -} - -function statusPredicate(status: StatusFilter) { - return sql`( - ${status}::text = 'all' - OR (${status}::text = 'open' AND NOT done) - OR (${status}::text = 'done' AND done) - )`; -} - -function todoFromRow(row: TodoRecord): Todo { - return { - id: Number(row.id), - title: row.title, - notes: row.notes, - area: row.area, - context: row.context, - priority: Number(row.priority), - done: row.done === "true", - createdAt: row.created_at, - updatedAt: row.updated_at, - }; -} - -function clampPriority(value: number) { - return Math.min(Math.max(Math.trunc(value) || 2, 1), 3); -} diff --git a/examples/electron-wasix/src/types.ts b/examples/electron-wasix/src/types.ts deleted file mode 100644 index 94e07d303..000000000 --- a/examples/electron-wasix/src/types.ts +++ /dev/null @@ -1,28 +0,0 @@ -export type Todo = { - id: number; - title: string; - notes: string; - area: string; - context: string; - priority: number; - done: boolean; - createdAt: string; - updatedAt: string; -}; - -export type CreateTodoInput = { - title: string; - notes: string; - area: string; - context: string; - priority: number; -}; - -export type StatusFilter = "open" | "all" | "done"; - -export type TodoApi = { - listTodos(filter: { search: string; status: StatusFilter }): Promise; - createTodo(input: CreateTodoInput): Promise; - toggleTodo(id: number): Promise; - deleteTodo(id: number): Promise; -}; diff --git a/examples/electron-wasix/tsconfig.main.json b/examples/electron-wasix/tsconfig.main.json deleted file mode 100644 index 4e16471e9..000000000 --- a/examples/electron-wasix/tsconfig.main.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "NodeNext", - "moduleResolution": "NodeNext", - "lib": ["ES2022", "DOM"], - "outDir": "dist/main", - "rootDir": "src", - "strict": true, - "skipLibCheck": true, - "sourceMap": true - }, - "include": ["src/main-process.ts", "src/preload.cts", "src/sidecar.ts", "src/todos.ts", "src/types.ts"] -} diff --git a/examples/electron-wasix/vite.config.ts b/examples/electron-wasix/vite.config.ts deleted file mode 100644 index 27152134b..000000000 --- a/examples/electron-wasix/vite.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from "vite"; - -export default defineConfig({ - root: ".", - base: "./", - clearScreen: false, - server: { - port: 5175, - strictPort: true, - }, - build: { - outDir: "dist/renderer", - emptyOutDir: false, - }, -}); diff --git a/examples/electron/README.md b/examples/electron/README.md deleted file mode 100644 index 110c9dc59..000000000 --- a/examples/electron/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Electron Native Todo - -Electron owns the Oliphaunt TypeScript SDK in the main process and exposes a -small IPC surface to the renderer through preload. The app calls -`Oliphaunt.openServer` with persistent storage under Electron's user data -directory and owns the returned server handle. The explicit Electron E2E smoke -also exercises the optional `@oliphaunt/tools` facade with a schema-only -`pg_dump` and a non-interactive `psql` query; ordinary application startup does -not run PostgreSQL client tools. - -```sh -pnpm --dir examples/electron install -pnpm --dir examples/electron start -``` diff --git a/examples/electron/package.json b/examples/electron/package.json deleted file mode 100644 index 3ea74f270..000000000 --- a/examples/electron/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "oliphaunt-example-electron", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "build": "tsc -p tsconfig.main.json && vite build", - "start": "pnpm run build && electron dist/main/main-process.js", - "dev:renderer": "vite" - }, - "dependencies": { - "@oliphaunt/extension-contrib-pg18": "0.2.0", - "@oliphaunt/tools": "0.2.0", - "@oliphaunt/ts": "0.2.0", - "kysely": "^0.29.2", - "pg": "^8.16.3" - }, - "devDependencies": { - "@types/node": "^24.10.1", - "@types/pg": "^8.15.6", - "electron": "^39.2.5", - "typescript": "^5.9.3", - "vite": "^6.0.3" - } -} diff --git a/examples/electron/src/main-process.ts b/examples/electron/src/main-process.ts deleted file mode 100644 index 6d6085296..000000000 --- a/examples/electron/src/main-process.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { app, BrowserWindow, ipcMain } from "electron"; -import { dirname, join } from "node:path"; -import { fileURLToPath, pathToFileURL } from "node:url"; - -import { closeDatabase, createTodo, deleteTodo, listTodos, toggleTodo } from "./todos.js"; -import type { CreateTodoInput, StatusFilter } from "./types.js"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -if (process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER) { - process.send?.({ event: "main-start", cwd: process.cwd(), send: typeof process.send }); -} - -function createWindow() { - const window = new BrowserWindow({ - width: 1100, - height: 760, - title: "Oliphaunt Electron Todo", - webPreferences: { - preload: join(__dirname, "preload.cjs"), - contextIsolation: true, - nodeIntegration: false, - }, - }); - - const devServer = process.env.VITE_DEV_SERVER_URL; - if (devServer) { - void window.loadURL(devServer); - } else { - void window.loadFile(join(__dirname, "../renderer/index.html")); - } - return window; -} - -async function installTestDriver(window: BrowserWindow) { - if (!process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER) return; - console.error("Installing Electron todo e2e driver"); - const driver = await import( - pathToFileURL(join(process.cwd(), "../tools/electron-test-driver.mjs")).href - ); - driver.installElectronTodoTestDriver({ app, window, close: closeDatabase }); -} - -ipcMain.handle( - "todos:list", - (_event, filter: { search: string; status: StatusFilter }) => listTodos(app.getPath("userData"), filter), -); -ipcMain.handle("todos:create", (_event, input: CreateTodoInput) => - createTodo(app.getPath("userData"), input), -); -ipcMain.handle("todos:toggle", (_event, id: number) => toggleTodo(app.getPath("userData"), id)); -ipcMain.handle("todos:delete", (_event, id: number) => deleteTodo(app.getPath("userData"), id)); - -process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER && - process.send?.({ event: "before-when-ready" }); -void app - .whenReady() - .then(async () => { - process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER && - process.send?.({ event: "after-when-ready" }); - await installTestDriver(createWindow()); - }) - .catch((error) => { - console.error(error); - app.exit(1); - }); - -app.on("activate", () => { - if (BrowserWindow.getAllWindows().length === 0) createWindow(); -}); - -app.on("window-all-closed", () => { - if (process.platform !== "darwin") app.quit(); -}); - -app.on("before-quit", (event) => { - event.preventDefault(); - closeDatabase() - .catch((error) => console.error(error)) - .finally(() => app.exit(0)); -}); diff --git a/examples/electron/src/preload.cts b/examples/electron/src/preload.cts deleted file mode 100644 index 0cebe0537..000000000 --- a/examples/electron/src/preload.cts +++ /dev/null @@ -1,19 +0,0 @@ -import { contextBridge, ipcRenderer } from "electron"; -import type { CreateTodoInput, StatusFilter, TodoApi } from "./types.js"; - -const api: TodoApi = { - listTodos(filter: { search: string; status: StatusFilter }) { - return ipcRenderer.invoke("todos:list", filter); - }, - createTodo(input: CreateTodoInput) { - return ipcRenderer.invoke("todos:create", input); - }, - toggleTodo(id: number) { - return ipcRenderer.invoke("todos:toggle", id); - }, - deleteTodo(id: number) { - return ipcRenderer.invoke("todos:delete", id); - }, -}; - -contextBridge.exposeInMainWorld("todos", api); diff --git a/examples/electron/src/renderer.ts b/examples/electron/src/renderer.ts deleted file mode 100644 index a38885b2b..000000000 --- a/examples/electron/src/renderer.ts +++ /dev/null @@ -1,135 +0,0 @@ -import type { CreateTodoInput, StatusFilter, Todo, TodoApi } from "./types"; - -declare global { - interface Window { - todos: TodoApi; - } -} - -const form = document.querySelector("#todo-form"); -const list = document.querySelector("#todo-list"); -const status = document.querySelector("#status"); -const search = document.querySelector("#search"); -const openCount = document.querySelector("#open-count"); -const doneCount = document.querySelector("#done-count"); -const highCount = document.querySelector("#high-count"); -let activeStatus: StatusFilter = "open"; -let todos: Todo[] = []; - -async function listTodos() { - todos = await window.todos.listTodos({ - search: search?.value.trim() ?? "", - status: activeStatus, - }); - render(); -} - -function setStatus(message: string) { - if (status) status.value = message; -} - -function priorityLabel(priority: number) { - if (priority === 1) return "High"; - if (priority === 3) return "Low"; - return "Normal"; -} - -function render() { - const open = todos.filter((todo) => !todo.done).length; - const done = todos.filter((todo) => todo.done).length; - const high = todos.filter((todo) => !todo.done && todo.priority === 1).length; - if (openCount) openCount.value = `${open} open`; - if (doneCount) doneCount.value = `${done} done`; - if (highCount) highCount.value = `${high} high priority`; - if (!list) return; - if (todos.length === 0) { - const empty = document.createElement("p"); - empty.className = "empty"; - empty.textContent = "No todos match the current filter."; - list.replaceChildren(empty); - return; - } - list.replaceChildren(...todos.map(renderTodo)); -} - -function renderTodo(todo: Todo) { - const row = document.createElement("article"); - row.className = todo.done ? "todo done" : "todo"; - - const checkbox = document.createElement("input"); - checkbox.type = "checkbox"; - checkbox.checked = todo.done; - checkbox.addEventListener("change", () => { - void window.todos.toggleTodo(todo.id).then(listTodos).catch((error) => setStatus(String(error))); - }); - - const body = document.createElement("div"); - const title = document.createElement("h2"); - title.textContent = todo.title; - const notes = document.createElement("p"); - notes.textContent = todo.notes || "No notes"; - const meta = document.createElement("div"); - meta.className = "meta"; - for (const value of [ - priorityLabel(todo.priority), - todo.area ? `area:${todo.area}` : "", - todo.context ? `context:${todo.context}` : "", - `updated ${todo.updatedAt}`, - ]) { - if (!value) continue; - const pill = document.createElement("span"); - pill.className = "pill"; - pill.textContent = value; - meta.append(pill); - } - body.append(title, notes, meta); - - const remove = document.createElement("button"); - remove.className = "secondary"; - remove.type = "button"; - remove.textContent = "Delete"; - remove.addEventListener("click", () => { - void window.todos.deleteTodo(todo.id).then(listTodos).catch((error) => setStatus(String(error))); - }); - - row.append(checkbox, body, remove); - return row; -} - -form?.addEventListener("submit", (event) => { - event.preventDefault(); - const data = new FormData(form); - const input: CreateTodoInput = { - title: String(data.get("title") ?? "").trim(), - notes: String(data.get("notes") ?? "").trim(), - area: String(data.get("area") ?? "").trim(), - context: String(data.get("context") ?? "").trim(), - priority: Number(data.get("priority") ?? 2), - }; - if (!input.title) return; - setStatus("Saving"); - window.todos - .createTodo(input) - .then(() => { - form.reset(); - setStatus("Saved"); - return listTodos(); - }) - .catch((error) => setStatus(String(error))); -}); - -search?.addEventListener("input", () => { - void listTodos().catch((error) => setStatus(String(error))); -}); - -document.querySelectorAll("[data-status]").forEach((button) => { - button.addEventListener("click", () => { - activeStatus = button.dataset.status as StatusFilter; - document - .querySelectorAll("[data-status]") - .forEach((candidate) => candidate.classList.toggle("active", candidate === button)); - void listTodos().catch((error) => setStatus(String(error))); - }); -}); - -void listTodos().catch((error) => setStatus(String(error))); diff --git a/examples/electron/src/todos.ts b/examples/electron/src/todos.ts deleted file mode 100644 index 6f4010ec9..000000000 --- a/examples/electron/src/todos.ts +++ /dev/null @@ -1,213 +0,0 @@ -import { join } from "node:path"; - -import { Oliphaunt, type OliphauntServer } from "@oliphaunt/ts"; -import { pgDump, psql } from "@oliphaunt/tools"; -import { Kysely, PostgresDialect, sql, type Generated } from "kysely"; -import pg from "pg"; - -import type { CreateTodoInput, StatusFilter, Todo } from "./types.js"; - -const { Pool } = pg; - -type TodoTable = { - id: Generated; - title: string; - notes: string; - tags: string; - done: Generated; - priority: number; - created_at: Generated; - updated_at: Generated; -}; - -type TodoDatabase = { - todos: TodoTable; -}; - -type TodoRecord = { - id: string; - title: string; - notes: string; - area: string; - context: string; - done: string; - priority: string; - created_at: string; - updated_at: string; -}; - -type Store = { - native: OliphauntServer; - db: Kysely; -}; - -const schemaStatements = [ - "CREATE EXTENSION IF NOT EXISTS hstore", - "CREATE EXTENSION IF NOT EXISTS pg_trgm", - "CREATE EXTENSION IF NOT EXISTS unaccent", - `CREATE TABLE IF NOT EXISTS todos ( - id bigserial PRIMARY KEY, - title text NOT NULL, - notes text NOT NULL DEFAULT '', - tags hstore NOT NULL DEFAULT ''::hstore, - done boolean NOT NULL DEFAULT false, - priority integer NOT NULL DEFAULT 2 CHECK (priority BETWEEN 1 AND 3), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now() - )`, - "CREATE INDEX IF NOT EXISTS todos_title_trgm ON todos USING gin (title gin_trgm_ops)", -]; - -let storePromise: Promise | undefined; - -export function getDatabase(userData: string) { - storePromise ??= openDatabase(userData); - return storePromise; -} - -async function openDatabase(userData: string): Promise { - const native = await Oliphaunt.openServer({ - storage: { kind: "directory", path: join(userData, "oliphaunt-native-todos") }, - extensions: ["hstore", "pg_trgm", "unaccent"], - }); - const connectionString = native.connectionString; - const db = new Kysely({ - dialect: new PostgresDialect({ - pool: new Pool({ - connectionString, - max: 2, - }), - }), - }); - for (const statement of schemaStatements) { - await sql.raw(statement).execute(db); - } - if (process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER) { - await validatePostgresTools(connectionString); - } - return { native, db }; -} - -async function validatePostgresTools(connectionString: string): Promise { - const dump = await pgDump(connectionString, { args: ["--schema-only"] }); - if (!dump.includes("PostgreSQL database dump")) { - throw new Error("pg_dump schema smoke did not return a PostgreSQL dump"); - } - const output = await psql(connectionString, { - args: ["-tA"], - command: "SELECT 1", - }); - if (!output.split("\n").some((line) => line.trim() === "1")) { - throw new Error("psql smoke did not return SELECT 1 output"); - } -} - -export async function listTodos( - userData: string, - filter: { search: string; status: StatusFilter }, -) { - const { db } = await getDatabase(userData); - const rows = await db - .selectFrom("todos") - .select(todoColumns) - .where(searchPredicate(filter.search)) - .where(statusPredicate(filter.status)) - .orderBy("done", "asc") - .orderBy("priority", "asc") - .orderBy("updated_at", "desc") - .orderBy("id", "desc") - .execute(); - return rows.map(todoFromRow); -} - -export async function createTodo(userData: string, input: CreateTodoInput) { - const { db } = await getDatabase(userData); - const row = await db - .insertInto("todos") - .values({ - title: input.title, - notes: input.notes, - tags: sql`hstore(ARRAY['area', ${input.area}, 'context', ${input.context}])`, - priority: clampPriority(input.priority), - }) - .returning(todoColumns) - .executeTakeFirstOrThrow(); - return todoFromRow(row); -} - -export async function toggleTodo(userData: string, id: number) { - const { db } = await getDatabase(userData); - const row = await db - .updateTable("todos") - .set({ - done: sql`NOT done`, - updated_at: sql`now()`, - }) - .where("id", "=", String(id)) - .returning(todoColumns) - .executeTakeFirstOrThrow(); - return todoFromRow(row); -} - -export async function deleteTodo(userData: string, id: number) { - const { db } = await getDatabase(userData); - await db.deleteFrom("todos").where("id", "=", String(id)).execute(); -} - -export async function closeDatabase() { - if (!storePromise) return; - const store = await storePromise; - await store.db.destroy(); - await store.native.close(); - storePromise = undefined; -} - -function todoColumns() { - return [ - sql`id::text`.as("id"), - "title", - "notes", - sql`COALESCE(tags -> 'area', '')`.as("area"), - sql`COALESCE(tags -> 'context', '')`.as("context"), - sql`done::text`.as("done"), - sql`priority::text`.as("priority"), - sql`to_char(created_at, 'YYYY-MM-DD HH24:MI')`.as("created_at"), - sql`to_char(updated_at, 'YYYY-MM-DD HH24:MI')`.as("updated_at"), - ] as const; -} - -function searchPredicate(search: string) { - return sql`( - ${search}::text = '' - OR unaccent(title || ' ' || notes) ILIKE '%' || unaccent(${search}::text) || '%' - OR COALESCE(tags -> 'area', '') ILIKE '%' || ${search}::text || '%' - OR COALESCE(tags -> 'context', '') ILIKE '%' || ${search}::text || '%' - OR tags ? ${search}::text - )`; -} - -function statusPredicate(status: StatusFilter) { - return sql`( - ${status}::text = 'all' - OR (${status}::text = 'open' AND NOT done) - OR (${status}::text = 'done' AND done) - )`; -} - -function todoFromRow(row: TodoRecord): Todo { - return { - id: Number(row.id), - title: row.title, - notes: row.notes, - area: row.area, - context: row.context, - priority: Number(row.priority), - done: row.done === "true", - createdAt: row.created_at, - updatedAt: row.updated_at, - }; -} - -function clampPriority(value: number) { - return Math.min(Math.max(Math.trunc(value) || 2, 1), 3); -} diff --git a/examples/electron/src/types.ts b/examples/electron/src/types.ts deleted file mode 100644 index 94e07d303..000000000 --- a/examples/electron/src/types.ts +++ /dev/null @@ -1,28 +0,0 @@ -export type Todo = { - id: number; - title: string; - notes: string; - area: string; - context: string; - priority: number; - done: boolean; - createdAt: string; - updatedAt: string; -}; - -export type CreateTodoInput = { - title: string; - notes: string; - area: string; - context: string; - priority: number; -}; - -export type StatusFilter = "open" | "all" | "done"; - -export type TodoApi = { - listTodos(filter: { search: string; status: StatusFilter }): Promise; - createTodo(input: CreateTodoInput): Promise; - toggleTodo(id: number): Promise; - deleteTodo(id: number): Promise; -}; diff --git a/examples/electron/vite.config.ts b/examples/electron/vite.config.ts deleted file mode 100644 index f822c83a5..000000000 --- a/examples/electron/vite.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineConfig } from "vite"; - -export default defineConfig({ - root: ".", - base: "./", - clearScreen: false, - server: { - port: 5174, - strictPort: true, - }, - build: { - outDir: "dist/renderer", - emptyOutDir: false, - }, -}); diff --git a/examples/moon.yml b/examples/moon.yml deleted file mode 100644 index 2d215d55f..000000000 --- a/examples/moon.yml +++ /dev/null @@ -1,200 +0,0 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "integration-examples" -language: "typescript" -layer: "application" -stack: "frontend" -tags: ["examples", "integration"] -dependsOn: - - id: "extension-packages" - scope: "build" - - id: "extensions" - scope: "build" - - "liboliphaunt-native" - - "oliphaunt-broker" - - "oliphaunt-js" - - "oliphaunt-kotlin" - - "oliphaunt-node-direct" - - "oliphaunt-react-native" - - "oliphaunt-swift" - - "oliphaunt-wasix-ts" - - "release-tools" - -project: - title: "Integration Examples" - description: "Cross-product examples and installed-app validation entrypoints." - owner: "oliphaunt" - -owners: - defaultOwner: "@oliphaunt/core" - paths: - "**/*": ["@oliphaunt/core"] - -tasks: - js-sdk-smoke: - tags: ["runtime", "smoke", "node", "bun", "deno"] - command: "sh tools/smoke-js-sdk.sh" - deps: - - "liboliphaunt-native:build-runtime-desktop-target" - - "oliphaunt-broker:build" - - "release-tools:node-direct-runtime" - inputs: - - project: "oliphaunt-js" - group: "code" - - "/src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh" - - "tools/smoke-js-sdk.sh" - options: - cache: local - runFromWorkspaceRoot: true - runInCI: false - - browser-wasix-compile: - tags: ["quality", "static", "browser", "wasix"] - command: "pnpm --dir examples/browser-wasix typecheck" - deps: - - "shared-js-core:build" - inputs: - - "browser-wasix/**/*" - - project: "oliphaunt-wasix-ts" - group: "code" - - "@group(pnpm-workspace)" - options: - cache: true - runFromWorkspaceRoot: true - - check: - tags: ["quality", "static"] - command: "bun examples/tools/check-examples.mjs" - inputs: - - "**/*" - - "@group(pnpm-workspace)" - - "!/examples/**/node_modules" - - "!/examples/**/node_modules/**" - - "/src/**/examples/**/*" - - "/examples/tools/check-examples.mjs" - options: - cache: true - runFromWorkspaceRoot: true - react-native-android-build: - tags: ["mobile", "build", "android", "ci-mobile-build-android"] - script: | - export OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT="${OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT:-$PWD/target/mobile-extension-artifacts}" - exec pnpm --dir examples/react-native-expo run mobile-build:android - deps: - - "extension-packages:package-mobile" - - "liboliphaunt-native:package-runtime-android-x86_64" - - "release-tools:kotlin-sdk-package" - - "release-tools:react-native-sdk-package" - inputs: - - "react-native-expo/**/*" - - project: "oliphaunt-kotlin" - group: "code" - - project: "oliphaunt-react-native" - group: "code" - - project: "extensions" - group: "build" - - "/target/mobile-extension-artifacts/**/*" - - "/target/sdk-artifacts/oliphaunt-kotlin/**/*" - - "/target/sdk-artifacts/oliphaunt-react-native/**/*" - - "/tools/native-packaging/**/*" - outputs: - - "/target/mobile-build/react-native/android/**/*" - options: - cache: false - runFromWorkspaceRoot: true - react-native-android-e2e: - tags: ["mobile", "e2e", "android"] - command: "pnpm --dir examples/react-native-expo run mobile-e2e:android" - deps: - - "integration-examples:react-native-android-build" - inputs: - - "react-native-expo/src/**/*" - - "react-native-expo/maestro/**/*" - - "react-native-expo/package.json" - - project: "oliphaunt-react-native" - group: "code" - - "/src/sources/toolchains/android-emulator-runner.toml" - - "/src/sources/toolchains/maestro.toml" - - "/tools/dev/setup-maestro.sh" - - "/target/mobile-build/react-native/android/**/*" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: skip - react-native-android-drill: - tags: ["mobile", "drill", "android"] - command: "pnpm --dir examples/react-native-expo run mobile-drill:android" - inputs: - - "react-native-expo/**/*" - - project: "oliphaunt-kotlin" - group: "code" - - project: "oliphaunt-react-native" - group: "code" - - project: "extensions" - group: "build" - - "/tools/native-packaging/**/*" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false - react-native-ios-build: - tags: ["mobile", "build", "ios", "ci-mobile-build-ios"] - script: | - export OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT="${OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT:-$PWD/target/mobile-extension-artifacts}" - exec pnpm --dir examples/react-native-expo run mobile-build:ios - deps: - - "extension-packages:package-mobile" - - "liboliphaunt-native:package-runtime-ios-xcframework" - - "release-tools:react-native-sdk-package" - - "release-tools:swift-sdk-package" - inputs: - - "react-native-expo/**/*" - - project: "oliphaunt-react-native" - group: "code" - - project: "oliphaunt-swift" - group: "code" - - project: "extensions" - group: "build" - - "/target/mobile-extension-artifacts/**/*" - - "/target/sdk-artifacts/oliphaunt-react-native/**/*" - - "/target/sdk-artifacts/oliphaunt-swift/**/*" - - "/tools/native-packaging/**/*" - outputs: - - "/target/mobile-build/react-native/ios/**/*" - options: - cache: false - runFromWorkspaceRoot: true - react-native-ios-e2e: - tags: ["mobile", "e2e", "ios"] - command: "pnpm --dir examples/react-native-expo run mobile-e2e:ios" - deps: - - "integration-examples:react-native-ios-build" - inputs: - - "react-native-expo/src/**/*" - - "react-native-expo/maestro/**/*" - - "react-native-expo/package.json" - - project: "oliphaunt-react-native" - group: "code" - - "/src/sources/toolchains/maestro.toml" - - "/tools/dev/setup-maestro.sh" - - "/target/mobile-build/react-native/ios/**/*" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: skip - react-native-ios-drill: - tags: ["mobile", "drill", "ios"] - command: "pnpm --dir examples/react-native-expo run mobile-drill:ios" - inputs: - - "react-native-expo/**/*" - - project: "oliphaunt-react-native" - group: "code" - - project: "oliphaunt-swift" - group: "code" - - project: "extensions" - group: "build" - - "/tools/native-packaging/**/*" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false diff --git a/examples/react-native-expo/README.md b/examples/react-native-expo/README.md deleted file mode 100644 index fbefaa478..000000000 --- a/examples/react-native-expo/README.md +++ /dev/null @@ -1,220 +0,0 @@ -# React Native Oliphaunt Expo Example - -This is a real Expo development-build app for validating -`@oliphaunt/react-native` against the Kotlin Android SDK and the New -Architecture JSI `ArrayBuffer` transport. - -The first screen is a small field-ops task board rather than a static smoke -screen. On launch it opens one direct database, creates a -project/task/event schema, seeds 240 tasks in a transaction, updates work items -in a second transaction, runs parameterized aggregate/search queries, and logs -latency percentiles through `OLIPHAUNT_EXPO_SMOKE_PASS`. - -The installed-app smoke activates the generated mobile extension set and runs -the extension-specific runtime proofs, including the pgvector HNSW query. - -Fast Android smoke: - -```sh -pnpm run smoke -pnpm run smoke:android -``` - -`pnpm run smoke` is the default installed-app harness: it runs the Android and -iOS Expo development-client smokes through the repository validation script. -Use `smoke:android` or `smoke:ios` when only one simulator/device stack is -available. - -The default local dev command is the Expo development-client harness with local -Expo MCP capabilities enabled, not Expo Go: - -```sh -pnpm start -pnpm run android:start -pnpm run ios:start -``` - -The automated smoke, benchmark, and crash scripts start their own -development-client Metro server with local MCP enabled by default so the native -runner receives the same env on every machine. If port 8081 is busy, they choose -a free port in 8082-8099 unless `OLIPHAUNT_EXPO_*_METRO_PORT` is set explicitly. -Set `OLIPHAUNT_EXPO_*_REUSE_METRO=1` only when manually attaching to a Metro -process that already has the desired `EXPO_PUBLIC_OLIPHAUNT_*` env. - -Device benchmark runs use the same native build/package path but launch the app -with the benchmark runner. They emit `OLIPHAUNT_EXPO_BENCH_PASS` and write the -parsed JSON report under `target/oliphaunt-expo--benchmark/reports/`. -The report includes typed and parameterized RTT, set-based insert throughput, -JS timer liveness, effective PostgreSQL settings, and checkpoint latency. The -platform harness records process memory and built artifact sizes separately. A -same-device Expo SQLite WAL baseline uses its own explicit SQLite durability -profile so comparisons do not invent an Oliphaunt durability mode: - -```sh -pnpm run bench:android -pnpm run bench:ios -``` - -Process-death recovery runs use the same dev-client build but launch a -two-phase crash harness. The write phase opens persistent app-private storage, -writes committed data, and leaves the database open. The platform script then -force-stops/terminates the app process and relaunches the verify phase against -the same storage with a fresh phase-specific dev-client bundle, expecting -PostgreSQL recovery to make the committed row visible. Before writing, the app -verifies the effective PostgreSQL `fsync`, `full_page_writes`, and -`synchronous_commit` settings are all `on`: - -```sh -pnpm run crash:android -pnpm run crash:ios -``` - -The runners choose isolated persistent storage by default. Set -`OLIPHAUNT_EXPO_ANDROID_CRASH_STORAGE` or -`OLIPHAUNT_EXPO_IOS_CRASH_STORAGE` to override it; the iOS runner accepts an -`app-data:` selector for the public `applicationData` storage case. - -The smoke script: - -- packs the current React Native SDK when sources changed; -- installs the packed SDK into this Expo app when needed; -- runs Expo prebuild for Android when the ignored generated `android/` project - is missing; -- builds clean Android `liboliphaunt` runtime resources with runtime files, - a standard cluster seed, package-size evidence, and `liboliphaunt.so`; -- builds and installs the dev-client APK; -- launches through Expo dev-client and waits for - `OLIPHAUNT_EXPO_SMOKE_PASS` from logcat. - -Useful overrides: - -```sh -OLIPHAUNT_EXPO_MOBILE_STARTUP_GUCS=shared_buffers=8MB,wal_buffers=-1 pnpm run bench:android -OLIPHAUNT_EXPO_MOBILE_BENCHMARK_PRESET=quick pnpm run bench:android -OLIPHAUNT_EXPO_ANDROID_SKIP_BUILD=1 pnpm run smoke:android -OLIPHAUNT_EXPO_ANDROID_KEEP_METRO=1 pnpm run smoke:android -OLIPHAUNT_EXPO_ANDROID_REPACKAGE_ASSETS=1 pnpm run smoke:android -OLIPHAUNT_EXPO_ANDROID_GRADLE_CONFIGURATION_CACHE=1 pnpm run smoke:android -OLIPHAUNT_EXPO_ANDROID_RUNTIME_DIR=/path/to/runtime pnpm run smoke:android -OLIPHAUNT_EXPO_ANDROID_SEED_CLOSURE_DIR=/path/to/android-datum64-runtime-closure pnpm run smoke:android -OLIPHAUNT_EXPO_ANDROID_OLIPHAUNT_SO=/path/to/liboliphaunt.so pnpm run smoke:android -``` - -Expo smoke and benchmark tuning uses explicit PostgreSQL startup GUCs through -`OLIPHAUNT_EXPO_MOBILE_STARTUP_GUCS`. -`tools/perf/matrix/run_mobile_footprint_matrix.sh` -prints or runs the full Android/iOS device matrix, stores each case in its own -scratch directory, and writes `summary.json` plus `summary.md` under -`target/perf/mobile-footprint-/`. Matrix cases run the benchmark and, -by default, process-death recovery lanes under the same explicit GUCs and -PostgreSQL safe defaults. -Pass `--quick` to the matrix wrapper, or set -`OLIPHAUNT_EXPO_MOBILE_BENCHMARK_PRESET=quick` directly, when validating harness -changes; leave the default full preset for reportable performance numbers. -Use the matrix axis filters for iterative tuning slices, for example: - -```sh -../../../../../tools/perf/matrix/run_mobile_footprint_matrix.sh --quick --platform android \ - --shared-buffers 8MB,32MB,128MB \ - --wal-buffers -1 \ - --min-wal-size 32MB \ - --max-wal-size 64MB \ - --crash-recovery off -``` - -The harness defaults to `--no-configuration-cache` for the Expo app because the -generated Expo Gradle files currently resolve React Native/Expo paths through -Node during configuration. Keep configuration cache opt-in until that upstream -behavior changes. - -Fast iOS build/smoke harness: - -```sh -OLIPHAUNT_EXPO_IOS_OLIPHAUNT_XCFRAMEWORK=/path/to/liboliphaunt.xcframework \ -OLIPHAUNT_EXPO_IOS_RUNTIME_DIR=/path/to/postgres-runtime \ -OLIPHAUNT_EXPO_IOS_SEED_CLOSURE_DIR=/path/to/ios-datum64-runtime-closure \ -pnpm run smoke:ios -``` - -Use `OLIPHAUNT_EXPO_IOS_BUILD_ONLY=1` when you only want the generated Expo iOS -project, CocoaPods integration, bundled resources, and Xcode build checked. The -script rejects macOS `liboliphaunt.dylib` artifacts; iOS validation needs an iOS -simulator/device build of `liboliphaunt`. For an unsigned generic iPhoneOS -compile/package check, set `OLIPHAUNT_EXPO_IOS_SDK=iphoneos`, -`OLIPHAUNT_EXPO_IOS_BUILD_ONLY=1`, and -`OLIPHAUNT_EXPO_IOS_CODE_SIGNING_ALLOWED=NO`; install/launch benchmarks still -require a runnable paired phone and valid signing. - -Physical iOS runs use Xcode's `devicectl` path: - -```sh -OLIPHAUNT_EXPO_IOS_SDK=iphoneos \ -OLIPHAUNT_EXPO_IOS_OLIPHAUNT_XCFRAMEWORK=/path/to/liboliphaunt.xcframework \ -OLIPHAUNT_EXPO_IOS_RUNTIME_DIR=/path/to/postgres-runtime \ -OLIPHAUNT_EXPO_IOS_SEED_CLOSURE_DIR=/path/to/ios-datum64-runtime-closure \ -pnpm run bench:ios -``` - -Set `OLIPHAUNT_EXPO_IOS_DEVICE_ID` to pick a specific paired device, and -`OLIPHAUNT_EXPO_IOS_METRO_URL` if the device cannot reach the host address that -the harness auto-detects. Device crash-recovery runs default to the public -`{ kind: 'applicationData', name }` storage case, which the platform SDK -resolves inside the app sandbox and which survives process death. - -Physical-device runs require a working Apple Development signing setup. The -harness first checks that the paired phone has Developer Mode and Developer Disk -Image services available through `devicectl`, then uses -`OLIPHAUNT_EXPO_IOS_DEVELOPMENT_TEAM` when set, otherwise it uses the single -team configured in Xcode. If Xcode has multiple teams configured, set -`OLIPHAUNT_EXPO_IOS_DEVELOPMENT_TEAM` explicitly. If no local signing identity -is installed the harness fails before doing the expensive Expo/CocoaPods work; set -`OLIPHAUNT_EXPO_IOS_ALLOW_PROVISIONING_UPDATES=1` to explicitly allow -`xcodebuild -allowProvisioningUpdates` and device registration when the Xcode -account session is valid. Override with `OLIPHAUNT_EXPO_IOS_CODE_SIGN_IDENTITY`, -`OLIPHAUNT_EXPO_IOS_PROVISIONING_PROFILE_SPECIFIER`, or -`OLIPHAUNT_EXPO_IOS_ALLOW_PROVISIONING_UPDATES=0` for locked-down local/CI -signing. - -The iPhone must be unlocked and awake when `devicectl` launches the development -client. If a physical run already built and installed the app but launch failed -because the device was locked, retry without rebuilding: - -```sh -OLIPHAUNT_EXPO_IOS_REUSE_INSTALLED_APP=1 \ -OLIPHAUNT_EXPO_IOS_SDK=iphoneos \ -OLIPHAUNT_EXPO_IOS_DEVICE_ID= \ -pnpm run crash:ios -``` - -The physical iOS smoke harness exercises background/foreground automatically: -after the app reaches `lifecycle:ready`, it opens Safari, waits -`OLIPHAUNT_EXPO_IOS_BACKGROUND_SECONDS` seconds, then foregrounds the same -installed app and verifies SQL still works on the resumed database. - -Expo local MCP capabilities are installed through `expo-mcp`: - -```sh -pnpm run mcp:version -pnpm run mcp:start -``` - -`mcp:start` is an alias for the default `pnpm start` dev-client/MCP harness, -which is the local tool path for screenshots, app logs, DevTools, and automation -from MCP-capable agents. Expo's remote MCP server requires Expo OAuth/EAS -access, so the repo keeps local CLI/dev-client validation as the default -reproducible path. - -EAS CLI is intentionally used through `npx eas-cli@latest` for build-service -operations so the example does not pin a stale global CLI: - -```sh -npx eas-cli@latest --version -``` - -Baseline local checks: - -```sh -pnpm run typecheck -pnpm run lint -- --max-warnings=0 -npx expo-doctor -``` diff --git a/examples/react-native-expo/assets/expo.icon/icon.json b/examples/react-native-expo/assets/expo.icon/icon.json deleted file mode 100644 index 18ae68769..000000000 --- a/examples/react-native-expo/assets/expo.icon/icon.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "fill" : { - "automatic-gradient" : "extended-srgb:0.00000,0.47843,1.00000,1.00000" - }, - "groups" : [ - { - "layers" : [ - { - "image-name" : "expo-symbol 2.svg", - "name" : "expo-symbol 2", - "position" : { - "scale" : 1, - "translation-in-points" : [ - 1.1008400065293245e-05, - -16.046875 - ] - } - }, - { - "image-name" : "grid.png", - "name" : "grid" - } - ], - "shadow" : { - "kind" : "neutral", - "opacity" : 0.5 - }, - "translucency" : { - "enabled" : true, - "value" : 0.5 - } - } - ], - "supported-platforms" : { - "circles" : [ - "watchOS" - ], - "squares" : "shared" - } -} diff --git a/examples/react-native-expo/eslint.config.js b/examples/react-native-expo/eslint.config.js deleted file mode 100644 index ba708ed9f..000000000 --- a/examples/react-native-expo/eslint.config.js +++ /dev/null @@ -1,10 +0,0 @@ -// https://docs.expo.dev/guides/using-eslint/ -const { defineConfig } = require('eslint/config'); -const expoConfig = require("eslint-config-expo/flat"); - -module.exports = defineConfig([ - expoConfig, - { - ignores: ["dist/*"], - } -]); diff --git a/examples/react-native-expo/package.json b/examples/react-native-expo/package.json deleted file mode 100644 index 26679b3d7..000000000 --- a/examples/react-native-expo/package.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "react-native-oliphaunt-expo", - "main": "index.js", - "version": "0.0.0", - "dependencies": { - "@oliphaunt/react-native": "workspace:*", - "expo": "~56.0.15", - "expo-dev-client": "~56.0.22", - "expo-splash-screen": "~56.0.12", - "expo-sqlite": "~56.0.5", - "expo-system-ui": "~56.0.5", - "react": "19.2.3", - "react-dom": "19.2.3", - "react-native": "0.85.3", - "react-native-safe-area-context": "~5.7.0", - "react-native-web": "~0.21.0" - }, - "devDependencies": { - "@react-native-community/cli": "20.2.0", - "@react-native-community/cli-platform-android": "20.2.0", - "@react-native-community/cli-platform-ios": "20.2.0", - "@react-native/metro-config": "0.85.3", - "@types/react": "19.2.16", - "eslint": "^9.0.0", - "eslint-config-expo": "~56.0.4", - "expo-doctor": "^1.19.7", - "expo-mcp": "~0.2.1", - "typescript": "~6.0.3" - }, - "scripts": { - "start": "EXPO_UNSTABLE_MCP_SERVER=1 expo start --dev-client", - "android": "expo run:android", - "android:start": "EXPO_UNSTABLE_MCP_SERVER=1 expo start --dev-client --android", - "doctor": "expo-doctor", - "ios": "expo run:ios", - "ios:start": "EXPO_UNSTABLE_MCP_SERVER=1 expo start --dev-client --ios", - "mcp:version": "expo-mcp --version", - "mcp:start": "pnpm start", - "prebuild:android": "expo prebuild --platform android", - "prebuild:ios": "expo prebuild --platform ios", - "smoke": "pnpm run smoke:android && pnpm run smoke:ios", - "mobile-build:android": "../../src/sdks/react-native/tools/mobile-build.sh android", - "mobile-build:ios": "../../src/sdks/react-native/tools/mobile-build.sh ios", - "mobile-e2e": "pnpm run mobile-e2e:android && pnpm run mobile-e2e:ios", - "mobile-e2e:android": "../../src/sdks/react-native/tools/mobile-e2e.sh android", - "mobile-e2e:ios": "../../src/sdks/react-native/tools/mobile-e2e.sh ios", - "mobile-drill:android": "../../src/sdks/react-native/tools/mobile-drill.sh android", - "mobile-drill:ios": "../../src/sdks/react-native/tools/mobile-drill.sh ios", - "bench:android": "../../src/sdks/react-native/tools/mobile-drill.sh android benchmark", - "bench:ios": "../../src/sdks/react-native/tools/mobile-drill.sh ios benchmark", - "crash:android": "../../src/sdks/react-native/tools/mobile-drill.sh android crash", - "crash:ios": "../../src/sdks/react-native/tools/mobile-drill.sh ios crash", - "smoke:android": "pnpm run mobile-build:android && pnpm run mobile-e2e:android", - "smoke:ios": "pnpm run mobile-build:ios && pnpm run mobile-e2e:ios", - "typecheck": "tsc --noEmit", - "web": "expo start --web", - "lint": "expo lint" - }, - "private": true -} diff --git a/examples/react-native-expo/tools/mobile-extension-proof.test.mjs b/examples/react-native-expo/tools/mobile-extension-proof.test.mjs deleted file mode 100644 index e61cfde19..000000000 --- a/examples/react-native-expo/tools/mobile-extension-proof.test.mjs +++ /dev/null @@ -1,101 +0,0 @@ -import assert from "node:assert/strict"; -import { mock, test } from "bun:test"; - -class FixturePostgresError extends Error {} - -mock.module("@oliphaunt/react-native", () => ({ - PostgresError: FixturePostgresError, - simpleQuery() { - throw new Error("simpleQuery is outside the extension-proof fixture"); - }, -})); - -const { runMobileReleaseExtensionProof } = await import( - "../src/mobile-smoke.ts" -); -const { serializeExpoSmokePassReceipt } = await import( - "../src/smoke-pass-receipt.ts" -); - -function queryResult(values) { - return { - getText(_row, column) { - return values[column] ?? null; - }, - rowCount: 1, - rows: [values], - }; -} - -test("the successful pg_textsearch producer supplies every semantic PASS fact", async () => { - const executed = []; - const queried = []; - const db = { - async execute(sql) { - executed.push(sql); - }, - async query(sql) { - queried.push(sql); - if (sql === "SELECT 1") { - return queryResult({ "?column?": "1" }); - } - if (sql.includes("WHERE extname = $1")) { - return queryResult({ name: "pg_textsearch", version: "0.3.1" }); - } - if (sql.includes("to_bm25query")) { - return queryResult({ id: "1" }); - } - if (sql.includes("string_agg")) { - return queryResult({ value: "pg_textsearch" }); - } - throw new Error(`unexpected extension-proof query: ${sql}`); - }, - }; - const proof = await runMobileReleaseExtensionProof(db, [{ - sqlName: "pg_textsearch", - createsExtension: true, - nativeModuleStem: "pg_textsearch", - selectedExtensionDependencies: [], - activationSql: ["CREATE EXTENSION pg_textsearch"], - smokeStatements: ["SELECT 1"], - }]); - - assert.deepEqual(proof.activatedExtensions, ["pg_textsearch"]); - assert.equal(proof.extensionCatalogComplete, true); - assert.equal(proof.pgTextsearchEnglishBm25, true); - assert.deepEqual(executed, [ - "CREATE EXTENSION pg_textsearch", - "DROP TABLE IF EXISTS oliphaunt_mobile_pg_textsearch_english", - "CREATE TABLE oliphaunt_mobile_pg_textsearch_english (id bigint PRIMARY KEY, body text NOT NULL)", - `INSERT INTO oliphaunt_mobile_pg_textsearch_english (id, body) VALUES - (1, 'PostgreSQL databases support reliable runners'), - (2, 'An unrelated document about walking')`, - `CREATE INDEX oliphaunt_mobile_pg_textsearch_english_bm25 - ON oliphaunt_mobile_pg_textsearch_english - USING bm25 (body) - WITH (text_config = 'pg_catalog.english')`, - "DROP TABLE IF EXISTS oliphaunt_mobile_pg_textsearch_english", - ]); - assert.equal(queried[0], "SELECT 1"); - assert.deepEqual(proof.checks.map((check) => check.name), [ - "extension activation: pg_textsearch", - "extension functional proof: pg_textsearch English BM25", - "extension activation catalog completeness", - ]); - - const receipt = JSON.parse(serializeExpoSmokePassReceipt({ - platform: "ios", - extensions: ["pg_textsearch"], - activatedExtensions: proof.activatedExtensions, - extensionCatalogComplete: proof.extensionCatalogComplete, - pgTextsearchEnglishBm25: proof.pgTextsearchEnglishBm25, - extensionCatalogSha256: "a".repeat(64), - catalogProfile: "icu", - icuRuntimeProof: true, - })); - assert.equal(receipt.schema, "oliphaunt-expo-smoke-pass-v4"); - assert.equal(receipt.catalogProfile, "icu"); - assert.equal(receipt.allExtensionsActivated, true); - assert.equal(receipt.extensionCatalogComplete, true); - assert.equal(receipt.pgTextsearchEnglishBm25, true); -}); diff --git a/examples/react-native-expo/tools/smoke-pass-receipt.test.mjs b/examples/react-native-expo/tools/smoke-pass-receipt.test.mjs deleted file mode 100644 index 703a0727b..000000000 --- a/examples/react-native-expo/tools/smoke-pass-receipt.test.mjs +++ /dev/null @@ -1,107 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - EXPO_SMOKE_PASS_EVENT_MAX_BYTES, - EXPO_SMOKE_PASS_TAG, - serializeExpoSmokePassReceipt, -} from "../src/smoke-pass-receipt.ts"; -import { - GENERATED_MOBILE_EXTENSION_METADATA_SHA256, - GENERATED_MOBILE_EXTENSION_PLAN, -} from "../src/generated/extension-smoke.ts"; - -function platformExtensions() { - return GENERATED_MOBILE_EXTENSION_PLAN - .map((extension) => extension.sqlName) - .sort(); -} - -function receiptInput(platform, overrides = {}) { - const extensions = platformExtensions(); - return { - platform, - extensions, - activatedExtensions: extensions, - extensionCatalogComplete: true, - pgTextsearchEnglishBm25: extensions.includes("pg_textsearch"), - extensionCatalogSha256: GENERATED_MOBILE_EXTENSION_METADATA_SHA256, - catalogProfile: "icu", - icuRuntimeProof: true, - ...overrides, - }; -} - -test("the exact mobile catalog produces a bounded authoritative receipt", () => { - for (const platform of ["android", "ios"]) { - const extensions = platformExtensions(); - const serialized = serializeExpoSmokePassReceipt(receiptInput(platform)); - const event = `${EXPO_SMOKE_PASS_TAG} ${serialized}`; - assert(Buffer.byteLength(event) <= EXPO_SMOKE_PASS_EVENT_MAX_BYTES); - assert.deepEqual(Object.keys(JSON.parse(serialized)).sort(), [ - "allExtensionsActivated", - "catalogProfile", - "extensionCatalogComplete", - "extensionCatalogSha256", - "extensionCount", - "icuRuntimeProof", - "pgTextsearchEnglishBm25", - "platform", - "runner", - "schema", - ]); - } -}); - -test("receipt serialization fails closed on proof drift and remains constant-size as catalogs grow", () => { - const extensions = platformExtensions(); - assert.throws( - () => serializeExpoSmokePassReceipt(receiptInput("ios", { - activatedExtensions: extensions.slice(1), - })), - /activated extension mismatch/u, - ); - assert.throws( - () => serializeExpoSmokePassReceipt(receiptInput("ios", { - activatedExtensions: [...extensions, extensions[0]], - })), - /activated extension mismatch/u, - ); - assert.throws( - () => serializeExpoSmokePassReceipt(receiptInput("ios", { - extensionCatalogComplete: false, - })), - /catalog completeness/u, - ); - assert.throws( - () => serializeExpoSmokePassReceipt(receiptInput("ios", { - pgTextsearchEnglishBm25: false, - })), - /pg_textsearch English BM25 proof mismatch/u, - ); - assert.throws( - () => serializeExpoSmokePassReceipt(receiptInput("ios", { - icuRuntimeProof: "yes", - })), - /ICU runtime proof boolean/u, - ); - assert.throws( - () => serializeExpoSmokePassReceipt(receiptInput("ios", { - catalogProfile: "standard", - })), - /ICU proof must match its catalog profile/u, - ); - const largeCatalog = Array.from({ length: 500 }, (_, index) => `extension_${index}`); - const serialized = serializeExpoSmokePassReceipt({ - platform: "ios", - extensions: largeCatalog, - activatedExtensions: largeCatalog, - extensionCatalogComplete: true, - pgTextsearchEnglishBm25: false, - extensionCatalogSha256: GENERATED_MOBILE_EXTENSION_METADATA_SHA256, - catalogProfile: "standard", - icuRuntimeProof: false, - }); - assert(Buffer.byteLength(`${EXPO_SMOKE_PASS_TAG} ${serialized}`) <= EXPO_SMOKE_PASS_EVENT_MAX_BYTES); - assert.equal(Object.hasOwn(JSON.parse(serialized), "extensions"), false); -}); diff --git a/examples/react-native-expo/tsconfig.json b/examples/react-native-expo/tsconfig.json deleted file mode 100644 index d6da3c90d..000000000 --- a/examples/react-native-expo/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "expo/tsconfig.base", - "compilerOptions": { - "strict": true, - "paths": { - "@/*": [ - "./src/*" - ], - "@/assets/*": [ - "./assets/*" - ] - } - }, - "include": [ - "**/*.ts", - "**/*.tsx" - ] -} diff --git a/examples/tauri-wasix/README.md b/examples/tauri-wasix/README.md deleted file mode 100644 index 4beea0581..000000000 --- a/examples/tauri-wasix/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Tauri WASIX Todo - -Tauri owns a Rust backend that asynchronously starts -root `AsyncOliphauntServer` from `oliphaunt-wasix`, then uses a one-connection -SQLx pool against the local -PostgreSQL URL. The webview receives app-specific commands only. The explicit -Rust smoke test covers `pg_dump` and `psql` through the direct -`oliphaunt_wasix` API; ordinary application startup does not run -PostgreSQL client tools. - -```sh -pnpm --dir examples/tauri-wasix install -pnpm --dir examples/tauri-wasix tauri dev -``` diff --git a/examples/tauri-wasix/src-tauri/Cargo.toml b/examples/tauri-wasix/src-tauri/Cargo.toml deleted file mode 100644 index 74110be42..000000000 --- a/examples/tauri-wasix/src-tauri/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "oliphaunt-example-tauri-wasix" -version = "0.0.0" -description = "Tauri todo app backed by oliphaunt-wasix and SQLx" -edition = "2021" -publish = false - -[workspace] - -[lib] -name = "oliphaunt_example_tauri_wasix_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -[build-dependencies] -tauri-build = { version = "2", features = [] } - -[dependencies] -anyhow = "1" -oliphaunt-wasix = { version = "=0.2.0", features = [ - "extension-hstore", - "extension-pg-trgm", - "extension-unaccent", -] } -serde = { version = "1", features = ["derive"] } -sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio-rustls", "postgres"] } -tauri = { version = "2", features = [] } -thiserror = "2" -tokio = { version = "1", features = ["rt-multi-thread", "sync"] } - -[dev-dependencies] -oliphaunt-wasix = { version = "=0.2.0", features = ["tools"] } -oliphaunt-wasix-tools = { version = "=0.2.0" } - -[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dependencies] -liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu = { version = "=0.2.0" } - -[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dev-dependencies] -oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu = { version = "=0.2.0" } diff --git a/examples/tauri-wasix/src-tauri/src/lib.rs b/examples/tauri-wasix/src-tauri/src/lib.rs deleted file mode 100644 index be04d20e7..000000000 --- a/examples/tauri-wasix/src-tauri/src/lib.rs +++ /dev/null @@ -1,310 +0,0 @@ -use std::path::PathBuf; -use std::time::Duration; - -use anyhow::{Context, Result}; -#[cfg(test)] -use oliphaunt_wasix::{tools, Oliphaunt}; -use oliphaunt_wasix::{AsyncOliphauntServer, Extension}; -use serde::ser::Serializer; -use serde::{Deserialize, Serialize}; -use sqlx::postgres::PgPoolOptions; -use sqlx::{PgPool, Row}; -use tauri::Manager; -use tokio::sync::Mutex; - -const CREATE_EXTENSIONS: &[&str] = &[ - "CREATE EXTENSION IF NOT EXISTS hstore", - "CREATE EXTENSION IF NOT EXISTS pg_trgm", - "CREATE EXTENSION IF NOT EXISTS unaccent", -]; - -const CREATE_TABLE: &str = r#" -CREATE TABLE IF NOT EXISTS todos ( - id bigserial PRIMARY KEY, - title text NOT NULL, - notes text NOT NULL DEFAULT '', - tags hstore NOT NULL DEFAULT ''::hstore, - done boolean NOT NULL DEFAULT false, - priority integer NOT NULL DEFAULT 2 CHECK (priority BETWEEN 1 AND 3), - created_at timestamptz NOT NULL DEFAULT now(), - updated_at timestamptz NOT NULL DEFAULT now() -) -"#; - -const CREATE_INDEX: &str = - "CREATE INDEX IF NOT EXISTS todos_title_trgm ON todos USING gin (title gin_trgm_ops)"; - -const SELECT_TODOS: &str = r#" -SELECT - id, - title, - notes, - COALESCE(tags -> 'area', '') AS area, - COALESCE(tags -> 'context', '') AS context, - done, - priority, - to_char(created_at, 'YYYY-MM-DD HH24:MI') AS created_at, - to_char(updated_at, 'YYYY-MM-DD HH24:MI') AS updated_at -FROM todos -WHERE - ( - $1::text = '' - OR unaccent(title || ' ' || notes) ILIKE '%' || unaccent($1::text) || '%' - OR COALESCE(tags -> 'area', '') ILIKE '%' || $1::text || '%' - OR COALESCE(tags -> 'context', '') ILIKE '%' || $1::text || '%' - OR tags ? $1::text - ) - AND ( - $2::text = 'all' - OR ($2::text = 'open' AND NOT done) - OR ($2::text = 'done' AND done) - ) -ORDER BY done ASC, priority ASC, updated_at DESC, id DESC -"#; - -const RETURNING_TODO: &str = r#" -RETURNING - id, - title, - notes, - COALESCE(tags -> 'area', '') AS area, - COALESCE(tags -> 'context', '') AS context, - done, - priority, - to_char(created_at, 'YYYY-MM-DD HH24:MI') AS created_at, - to_char(updated_at, 'YYYY-MM-DD HH24:MI') AS updated_at -"#; - -struct TodoStore { - inner: Mutex, -} - -struct TodoDatabase { - pool: PgPool, - _server: AsyncOliphauntServer, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -struct CreateTodo { - title: String, - notes: String, - area: String, - context: String, - priority: i32, -} - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -struct Todo { - id: i64, - title: String, - notes: String, - area: String, - context: String, - priority: i32, - done: bool, - created_at: String, - updated_at: String, -} - -#[derive(Debug, thiserror::Error)] -enum CommandError { - #[error("{0}")] - Runtime(String), -} - -impl serde::Serialize for CommandError { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl From for CommandError { - fn from(value: anyhow::Error) -> Self { - Self::Runtime(format!("{value:#}")) - } -} - -impl From for CommandError { - fn from(value: sqlx::Error) -> Self { - Self::Runtime(value.to_string()) - } -} - -fn open_database(directory: PathBuf) -> Result { - let runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .context("build WASIX example Tokio runtime")?; - runtime.block_on(async { - let server = start_database_server(directory).await?; - connect_database(server).await - }) -} - -async fn start_database_server(directory: PathBuf) -> Result { - let server = AsyncOliphauntServer::builder() - .storage(oliphaunt_wasix::DatabaseStorage::Directory(directory)) - .extensions([Extension::HSTORE, Extension::PG_TRGM, Extension::UNACCENT]) - .start() - .await - .context("start oliphaunt-wasix server")?; - Ok(server) -} - -async fn connect_database(server: AsyncOliphauntServer) -> Result { - let pool = PgPoolOptions::new() - .max_connections(1) - .acquire_timeout(Duration::from_secs(30)) - .connect(&server.connection_string()) - .await - .context("connect SQLx pool to oliphaunt-wasix server")?; - init_schema(&pool).await?; - Ok(TodoDatabase { - pool, - _server: server, - }) -} - -async fn init_schema(pool: &PgPool) -> Result<()> { - for statement in CREATE_EXTENSIONS { - sqlx::query(statement).execute(pool).await?; - } - sqlx::query(CREATE_TABLE).execute(pool).await?; - sqlx::query(CREATE_INDEX).execute(pool).await?; - Ok(()) -} - -#[cfg(test)] -fn validate_wasix_tools() -> Result<()> { - let mut database = Oliphaunt::open()?; - let dump = database.pg_dump(tools::PgDumpOptions::new().arg("--schema-only"))?; - anyhow::ensure!( - dump.contains("PostgreSQL database dump"), - "pg_dump SQL backup smoke did not look like a PostgreSQL dump" - ); - let psql = database.psql(tools::PsqlOptions::new().arg("-tA").command("SELECT 1"))?; - anyhow::ensure!( - psql.lines().any(|line| line.trim() == "1"), - "psql smoke did not return SELECT 1 output" - ); - database.close()?; - Ok(()) -} - -#[tauri::command] -async fn list_todos( - state: tauri::State<'_, TodoStore>, - search: String, - status: String, -) -> Result, CommandError> { - let db = state.inner.lock().await; - let rows = sqlx::query(SELECT_TODOS) - .bind(search) - .bind(status) - .fetch_all(&db.pool) - .await?; - rows.into_iter() - .map(|row| todo_from_row(&row).map_err(CommandError::from)) - .collect() -} - -#[tauri::command] -async fn create_todo( - state: tauri::State<'_, TodoStore>, - input: CreateTodo, -) -> Result { - let db = state.inner.lock().await; - let sql = format!( - "INSERT INTO todos (title, notes, tags, priority) - VALUES ($1, $2, hstore(ARRAY['area', $3, 'context', $4]), $5) - {RETURNING_TODO}" - ); - let row = sqlx::query(&sql) - .bind(input.title) - .bind(input.notes) - .bind(input.area) - .bind(input.context) - .bind(input.priority.clamp(1, 3)) - .fetch_one(&db.pool) - .await?; - todo_from_row(&row).map_err(CommandError::from) -} - -#[tauri::command] -async fn toggle_todo(state: tauri::State<'_, TodoStore>, id: i64) -> Result { - let db = state.inner.lock().await; - let sql = format!( - "UPDATE todos SET done = NOT done, updated_at = now() WHERE id = $1 {RETURNING_TODO}" - ); - let row = sqlx::query(&sql).bind(id).fetch_one(&db.pool).await?; - todo_from_row(&row).map_err(CommandError::from) -} - -#[tauri::command] -async fn delete_todo(state: tauri::State<'_, TodoStore>, id: i64) -> Result<(), CommandError> { - let db = state.inner.lock().await; - sqlx::query("DELETE FROM todos WHERE id = $1") - .bind(id) - .execute(&db.pool) - .await?; - Ok(()) -} - -fn todo_from_row(row: &sqlx::postgres::PgRow) -> Result { - Ok(Todo { - id: row.try_get("id")?, - title: row.try_get("title")?, - notes: row.try_get("notes")?, - area: row.try_get("area")?, - context: row.try_get("context")?, - priority: row.try_get("priority")?, - done: row.try_get("done")?, - created_at: row.try_get("created_at")?, - updated_at: row.try_get("updated_at")?, - }) -} - -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - tauri::Builder::default() - .setup(|app| { - let directory = app.path().app_data_dir()?.join("oliphaunt-wasix-todos"); - let db = open_database(directory)?; - app.manage(TodoStore { - inner: Mutex::new(db), - }); - Ok(()) - }) - .invoke_handler(tauri::generate_handler![ - list_todos, - create_todo, - toggle_todo, - delete_todo - ]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn startup_smoke_runs_split_wasix_tools() { - let directory = std::env::temp_dir().join(format!( - "oliphaunt-example-tauri-wasix-smoke-{}", - std::process::id() - )); - let _ = std::fs::remove_dir_all(&directory); - validate_wasix_tools().expect("run explicit split WASIX tools smoke"); - let db = open_database(directory.clone()) - .expect("start oliphaunt-wasix example database after tools smoke"); - drop(db); - let _ = std::fs::remove_dir_all(directory); - } -} diff --git a/examples/tauri-wasix/src-tauri/tauri.conf.json b/examples/tauri-wasix/src-tauri/tauri.conf.json deleted file mode 100644 index 9727b6d31..000000000 --- a/examples/tauri-wasix/src-tauri/tauri.conf.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2", - "productName": "Oliphaunt Tauri WASIX Todo", - "version": "0.1.0", - "identifier": "dev.oliphaunt.examples.tauri.wasix.todo", - "build": { - "beforeDevCommand": "pnpm run dev", - "devUrl": "http://localhost:1422", - "beforeBuildCommand": "pnpm run build", - "frontendDist": "../dist" - }, - "app": { - "windows": [ - { - "title": "Oliphaunt Tauri WASIX Todo", - "width": 1100, - "height": 760 - } - ], - "security": { - "csp": null - } - }, - "bundle": { - "active": false, - "icon": [ - "../../assets/tauri-icon.png" - ] - } -} diff --git a/examples/tauri-wasix/src/main.ts b/examples/tauri-wasix/src/main.ts deleted file mode 100644 index 876c4d84d..000000000 --- a/examples/tauri-wasix/src/main.ts +++ /dev/null @@ -1 +0,0 @@ -import "../../tauri/src/main.ts"; diff --git a/examples/tauri-wasix/vite.config.ts b/examples/tauri-wasix/vite.config.ts deleted file mode 100644 index 93eef2a3c..000000000 --- a/examples/tauri-wasix/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from "vite"; - -export default defineConfig({ - clearScreen: false, - server: { - port: 1422, - strictPort: true, - }, -}); diff --git a/examples/tauri/README.md b/examples/tauri/README.md deleted file mode 100644 index c2778da3c..000000000 --- a/examples/tauri/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Tauri Native Todo - -Tauri v2 owns an `oliphaunt` Rust SDK handle in backend state and exposes -app-specific commands to the webview. The native runtime is selected in Rust, -the persistent storage lives under the app data directory, and the exact extension -set is declared in `src-tauri/Cargo.toml`. - -```sh -pnpm --dir examples/tauri install -pnpm --dir examples/tauri tauri dev -``` diff --git a/examples/tauri/src-tauri/tauri.conf.json b/examples/tauri/src-tauri/tauri.conf.json deleted file mode 100644 index f2690072d..000000000 --- a/examples/tauri/src-tauri/tauri.conf.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2", - "productName": "Oliphaunt Tauri Todo", - "version": "0.1.0", - "identifier": "dev.oliphaunt.examples.tauri.todo", - "build": { - "beforeDevCommand": "pnpm run dev", - "devUrl": "http://localhost:1421", - "beforeBuildCommand": "pnpm run build", - "frontendDist": "../dist" - }, - "app": { - "windows": [ - { - "title": "Oliphaunt Tauri Todo", - "width": 1100, - "height": 760 - } - ], - "security": { - "csp": null - } - }, - "bundle": { - "active": false, - "icon": [ - "../../assets/tauri-icon.png" - ] - } -} diff --git a/examples/tauri/src/main.ts b/examples/tauri/src/main.ts deleted file mode 100644 index 09ce97348..000000000 --- a/examples/tauri/src/main.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { invoke } from "@tauri-apps/api/core"; - -type Todo = { - id: number; - title: string; - notes: string; - area: string; - context: string; - priority: number; - done: boolean; - createdAt: string; - updatedAt: string; -}; - -type CreateTodoInput = { - title: string; - notes: string; - area: string; - context: string; - priority: number; -}; - -type StatusFilter = "open" | "all" | "done"; - -const form = document.querySelector("#todo-form"); -const list = document.querySelector("#todo-list"); -const status = document.querySelector("#status"); -const search = document.querySelector("#search"); -const openCount = document.querySelector("#open-count"); -const doneCount = document.querySelector("#done-count"); -const highCount = document.querySelector("#high-count"); -let activeStatus: StatusFilter = "open"; -let todos: Todo[] = []; - -async function listTodos() { - todos = await invoke("list_todos", { - search: search?.value.trim() ?? "", - status: activeStatus, - }); - render(); -} - -async function createTodo(input: CreateTodoInput) { - await invoke("create_todo", { input }); - await listTodos(); -} - -async function toggleTodo(id: number) { - await invoke("toggle_todo", { id }); - await listTodos(); -} - -async function deleteTodo(id: number) { - await invoke("delete_todo", { id }); - await listTodos(); -} - -function setStatus(message: string) { - if (status) status.value = message; -} - -function priorityLabel(priority: number) { - if (priority === 1) return "High"; - if (priority === 3) return "Low"; - return "Normal"; -} - -function render() { - const open = todos.filter((todo) => !todo.done).length; - const done = todos.filter((todo) => todo.done).length; - const high = todos.filter((todo) => !todo.done && todo.priority === 1).length; - if (openCount) openCount.value = `${open} open`; - if (doneCount) doneCount.value = `${done} done`; - if (highCount) highCount.value = `${high} high priority`; - if (!list) return; - if (todos.length === 0) { - const empty = document.createElement("p"); - empty.className = "empty"; - empty.textContent = "No todos match the current filter."; - list.replaceChildren(empty); - return; - } - list.replaceChildren(...todos.map(renderTodo)); -} - -function renderTodo(todo: Todo) { - const row = document.createElement("article"); - row.className = todo.done ? "todo done" : "todo"; - - const checkbox = document.createElement("input"); - checkbox.type = "checkbox"; - checkbox.checked = todo.done; - checkbox.addEventListener("change", () => void toggleTodo(todo.id)); - - const body = document.createElement("div"); - const title = document.createElement("h2"); - title.textContent = todo.title; - const notes = document.createElement("p"); - notes.textContent = todo.notes || "No notes"; - const meta = document.createElement("div"); - meta.className = "meta"; - for (const value of [ - priorityLabel(todo.priority), - todo.area ? `area:${todo.area}` : "", - todo.context ? `context:${todo.context}` : "", - `updated ${todo.updatedAt}`, - ]) { - if (!value) continue; - const pill = document.createElement("span"); - pill.className = "pill"; - pill.textContent = value; - meta.append(pill); - } - body.append(title, notes, meta); - - const remove = document.createElement("button"); - remove.className = "secondary"; - remove.type = "button"; - remove.textContent = "Delete"; - remove.addEventListener("click", () => void deleteTodo(todo.id)); - - row.append(checkbox, body, remove); - return row; -} - -form?.addEventListener("submit", (event) => { - event.preventDefault(); - const data = new FormData(form); - const input: CreateTodoInput = { - title: String(data.get("title") ?? "").trim(), - notes: String(data.get("notes") ?? "").trim(), - area: String(data.get("area") ?? "").trim(), - context: String(data.get("context") ?? "").trim(), - priority: Number(data.get("priority") ?? 2), - }; - if (!input.title) return; - setStatus("Saving"); - createTodo(input) - .then(() => { - form.reset(); - setStatus("Saved"); - }) - .catch((error) => setStatus(String(error))); -}); - -search?.addEventListener("input", () => { - void listTodos().catch((error) => setStatus(String(error))); -}); - -document.querySelectorAll("[data-status]").forEach((button) => { - button.addEventListener("click", () => { - activeStatus = button.dataset.status as StatusFilter; - document - .querySelectorAll("[data-status]") - .forEach((candidate) => candidate.classList.toggle("active", candidate === button)); - void listTodos().catch((error) => setStatus(String(error))); - }); -}); - -void listTodos().catch((error) => setStatus(String(error))); diff --git a/examples/tauri/vite.config.ts b/examples/tauri/vite.config.ts deleted file mode 100644 index 0deb512b4..000000000 --- a/examples/tauri/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from "vite"; - -export default defineConfig({ - clearScreen: false, - server: { - port: 1421, - strictPort: true, - }, -}); diff --git a/examples/tools/check-examples.mjs b/examples/tools/check-examples.mjs deleted file mode 100644 index c771c8572..000000000 --- a/examples/tools/check-examples.mjs +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env node -import { execFileSync, spawnSync } from "node:child_process"; - -const root = execFileSync("git", ["rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim(); -process.chdir(root); - -function run(command, args) { - const result = spawnSync(command, args, { cwd: root, stdio: "inherit" }); - if (result.error) throw result.error; - if (result.status !== 0) process.exit(result.status ?? 1); -} - -function tracked(...pathspecs) { - return execFileSync("git", ["ls-files", "-z", "--", ...pathspecs], { encoding: "utf8" }) - .split("\0") - .filter(Boolean); -} - -run("bash", ["examples/tools/stage-tauri-webdriver-app.test.sh"]); -run("bun", ["test", "examples/react-native-expo/tools/smoke-pass-receipt.test.mjs"]); -run("bun", ["test", "examples/react-native-expo/tools/mobile-extension-proof.test.mjs"]); - -const allowed = /^(examples\/(moon\.yml|README\.md|assets\/[^/]+|tools\/[^/]+|(tauri|tauri-wasix|electron|electron-wasix|browser-wasix|react-native-expo)(\/.*)?))$/u; -const misplaced = tracked("examples").filter((file) => !allowed.test(file)); -const vendored = tracked("examples/**/node_modules/**", "src/**/examples/**/node_modules/**"); -const productExamples = tracked("src/**/examples/**"); -if (misplaced.length || vendored.length || productExamples.length) { - throw new Error([ - ...misplaced.map((file) => `unsupported root example path: ${file}`), - ...vendored.map((file) => `tracked example dependency: ${file}`), - ...productExamples.map((file) => `product-local example must move under examples/: ${file}`), - ].join("\n")); -} - -console.log("example behavior and ownership verified"); diff --git a/examples/tools/electron-driver-smoke.mjs b/examples/tools/electron-driver-smoke.mjs deleted file mode 100755 index 37927325c..000000000 --- a/examples/tools/electron-driver-smoke.mjs +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env node -import { spawn } from "node:child_process"; -import { mkdtempSync, rmSync } from "node:fs"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; - -const electron = process.env.OLIPHAUNT_E2E_ELECTRON; -const appDir = process.env.OLIPHAUNT_E2E_ELECTRON_APP; -if (!electron || !appDir) { - throw new Error("OLIPHAUNT_E2E_ELECTRON and OLIPHAUNT_E2E_ELECTRON_APP are required"); -} - -const userData = mkdtempSync(join(tmpdir(), "oliphaunt-electron-e2e-")); -const child = spawn( - electron, - [ - "--no-sandbox", - `--user-data-dir=${userData}`, - "dist/main/main-process.js", - ], - { - cwd: appDir, - env: { - ...process.env, - OLIPHAUNT_ELECTRON_E2E_DRIVER: "1", - }, - stdio: ["ignore", "pipe", "pipe", "ipc"], - }, -); - -let nextId = 1; -let driverReady = false; -const pending = new Map(); - -child.stdout.on("data", (chunk) => process.stdout.write(chunk)); -child.stderr.on("data", (chunk) => process.stderr.write(chunk)); -child.on("message", (message) => { - if (!message || typeof message !== "object") return; - if (message.event && process.env.OLIPHAUNT_E2E_DEBUG) { - console.error(`electron event ${JSON.stringify(message)}`); - } - if (message.event === "driver-ready") { - driverReady = true; - pending.get(0)?.resolve("driver-ready"); - pending.delete(0); - return; - } - const id = message.id; - if (typeof id !== "number") return; - const request = pending.get(id); - if (!request) return; - pending.delete(id); - if (message.ok) { - request.resolve(message.value); - } else { - request.reject(new Error(message.error || `Electron driver command ${id} failed`)); - } -}); - -try { - await waitForDriverReady(); - await rpc("ready", 30_000); - await rpc("runTodoSmoke", 150_000); - console.log("electron driver todo smoke passed"); - await rpc("shutdown", 30_000).catch(() => undefined); - await waitForExit(10_000); -} finally { - await stopChild(); - rmSync(userData, { recursive: true, force: true, maxRetries: 5, retryDelay: 250 }); -} - -function waitForDriverReady() { - if (driverReady) return Promise.resolve("driver-ready"); - return withTimeout( - new Promise((resolve, reject) => { - pending.set(0, { resolve, reject }); - child.once("exit", (code, signal) => { - pending.delete(0); - reject(new Error(`Electron exited before driver was ready: ${code ?? signal}`)); - }); - }), - 30_000, - "timed out waiting for Electron test driver", - ); -} - -function rpc(command, timeoutMs) { - if (!child.connected) { - throw new Error("Electron IPC channel is not connected"); - } - const id = nextId++; - const result = withTimeout( - new Promise((resolve, reject) => { - pending.set(id, { resolve, reject }); - }), - timeoutMs, - `timed out waiting for Electron driver command ${command}`, - ).finally(() => pending.delete(id)); - child.send({ id, command }); - return result; -} - -function waitForExit(timeoutMs) { - if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve(); - return withTimeout( - new Promise((resolve) => child.once("exit", resolve)), - timeoutMs, - "timed out waiting for Electron to exit", - ); -} - -async function stopChild() { - if (child.exitCode !== null || child.signalCode !== null) return; - child.kill("SIGTERM"); - try { - await waitForExit(3_000); - } catch { - child.kill("SIGKILL"); - } -} - -function withTimeout(promise, timeoutMs, message) { - let timer; - const timeout = new Promise((_resolve, reject) => { - timer = setTimeout(() => reject(new Error(message)), timeoutMs); - }); - return Promise.race([promise, timeout]).finally(() => clearTimeout(timer)); -} diff --git a/examples/tools/electron-test-driver.mjs b/examples/tools/electron-test-driver.mjs deleted file mode 100755 index deed4dffe..000000000 --- a/examples/tools/electron-test-driver.mjs +++ /dev/null @@ -1,113 +0,0 @@ -const webdriverTimeoutMs = 90_000; - -export function installElectronTodoTestDriver({ app, window, close }) { - if (!process.send) { - throw new Error("Electron test driver requires an IPC stdio channel"); - } - - process.on("message", async (message) => { - if (!message || typeof message !== "object") return; - const { id, command } = message; - if (typeof id !== "number" || typeof command !== "string") return; - - try { - let value; - if (command === "ready") { - await waitForWindowLoad(window); - value = window.webContents.getURL(); - } else if (command === "runTodoSmoke") { - await waitForWindowLoad(window); - value = await runTodoSmoke(window); - } else if (command === "shutdown") { - await close(); - process.send?.({ id, ok: true, value: "closed" }); - app.exit(0); - return; - } else { - throw new Error(`unknown Electron test driver command: ${command}`); - } - process.send?.({ id, ok: true, value }); - } catch (error) { - process.send?.({ - id, - ok: false, - error: error instanceof Error ? error.stack || error.message : String(error), - }); - } - }); - - process.send({ event: "driver-ready" }); -} - -async function waitForWindowLoad(window) { - if (!window.webContents.isLoading()) return; - await new Promise((resolve, reject) => { - const timer = setTimeout(() => reject(new Error("timed out waiting for window load")), 30_000); - window.webContents.once("did-finish-load", () => { - clearTimeout(timer); - resolve(); - }); - window.webContents.once("did-fail-load", (_event, _code, description) => { - clearTimeout(timer); - reject(new Error(`window failed to load: ${description}`)); - }); - }); -} - -async function runTodoSmoke(window) { - return window.webContents.executeJavaScript( - `(${rendererTodoSmoke.toString()})(${JSON.stringify(webdriverTimeoutMs)})`, - true, - ); -} - -async function rendererTodoSmoke(timeoutMs) { - const title = `Ship Electron e2e ${Date.now()}`; - const notes = "created by Electron test driver"; - - const required = (selector) => { - const element = document.querySelector(selector); - if (!element) throw new Error(`missing selector: ${selector}`); - return element; - }; - const setValue = (selector, value) => { - const element = required(selector); - element.value = value; - element.dispatchEvent(new Event("input", { bubbles: true })); - element.dispatchEvent(new Event("change", { bubbles: true })); - }; - const waitFor = async (predicate, label) => { - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - if (predicate()) return; - await new Promise((resolve) => setTimeout(resolve, 250)); - } - throw new Error(`timed out waiting for ${label}; body was: ${document.body.innerText}`); - }; - - await waitFor(() => Boolean(window.todos), "preload todo API"); - await waitFor( - () => required("#todo-list").textContent?.includes("No todos match the current filter."), - "initial todo list", - ); - - setValue("#title", title); - setValue("#notes", notes); - setValue("#area", "examples"); - setValue("#context", "public packages"); - setValue("#priority", "1"); - required("button[type='submit']").click(); - - await waitFor(() => document.body.innerText.includes(title), "created todo title"); - await waitFor(() => document.body.innerText.includes(notes), "created todo notes"); - - required("article.todo input[type='checkbox']").click(); - await waitFor(() => required("#open-count").textContent?.includes("0 open"), "todo toggle"); - required("[data-status='done']").click(); - await waitFor( - () => document.querySelector("article.todo.done")?.textContent?.includes(notes) === true, - "done todo filter", - ); - - return document.body.innerText; -} diff --git a/examples/tools/example-release-dependencies.mjs b/examples/tools/example-release-dependencies.mjs deleted file mode 100644 index c1a2cd10d..000000000 --- a/examples/tools/example-release-dependencies.mjs +++ /dev/null @@ -1,110 +0,0 @@ -import { readFileSync } from "node:fs"; -import path from "node:path"; -import { pathToFileURL } from "node:url"; - -const ELECTRON_RELEASE_DEPENDENCIES = [ - { - packageName: "@oliphaunt/ts", - versionSource: { type: "json", path: "src/sdks/js/package.json", keys: ["version"] }, - }, - { - packageName: "@oliphaunt/tools", - versionSource: { - type: "json", - path: "src/runtimes/liboliphaunt/native/tools-npm/package.json", - keys: ["version"], - }, - }, - { - packageName: "@oliphaunt/extension-contrib-pg18", - versionSource: { type: "text", path: "src/runtimes/liboliphaunt/native/VERSION" }, - }, -]; - -const ELECTRON_SMOKE_PACKAGES = [ - { - packageName: "@oliphaunt/liboliphaunt-linux-x64-gnu", - versionSource: { - type: "json", - path: "src/runtimes/liboliphaunt/native/packages/linux-x64-gnu/package.json", - keys: ["version"], - }, - }, -]; - -function fail(message) { - console.error(`example-release-dependencies.mjs: ${message}`); - process.exit(2); -} - -function readJsonObject(root, relativePath) { - const file = path.join(root, relativePath); - const value = JSON.parse(readFileSync(file, "utf8")); - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw new Error(`${relativePath} must contain a JSON object`); - } - return value; -} - -function readVersion(root, source, context) { - if (source.type === "text") { - const version = readFileSync(path.join(root, source.path), "utf8").trim(); - if (!version) { - throw new Error(`${source.path} does not define a version for ${context}`); - } - return version; - } - if (source.type === "json") { - let current = readJsonObject(root, source.path); - for (const key of source.keys) { - if (current === null || Array.isArray(current) || typeof current !== "object") { - throw new Error(`${source.path} has no JSON object at ${source.keys.join(".")} for ${context}`); - } - current = current[key]; - } - if (typeof current !== "string" || !current) { - throw new Error(`${source.path} does not define a string version for ${context}`); - } - return current; - } - throw new Error(`${context} uses unsupported version source ${JSON.stringify(source.type)}`); -} - -export function electronReleaseDependencies(root) { - return ELECTRON_RELEASE_DEPENDENCIES.map((entry) => ({ - packageName: entry.packageName, - version: readVersion(root, entry.versionSource, entry.packageName), - })); -} - -export function electronPackageVersion(root, packageName) { - const entry = [...ELECTRON_RELEASE_DEPENDENCIES, ...ELECTRON_SMOKE_PACKAGES].find( - (candidate) => candidate.packageName === packageName, - ); - if (entry === undefined) { - throw new Error(`unknown Electron example package ${JSON.stringify(packageName)}`); - } - return readVersion(root, entry.versionSource, packageName); -} - -function printElectronPackageVersion(argv) { - const packageName = argv[0]; - if (typeof packageName !== "string" || packageName.length === 0) { - fail("usage: example-release-dependencies.mjs electron-package-version "); - } - try { - process.stdout.write(`${electronPackageVersion(process.cwd(), packageName)}\n`); - } catch (error) { - fail(error.message); - } -} - -const mainUrl = process.argv[1] ? pathToFileURL(path.resolve(process.argv[1])).href : ""; -if (import.meta.url === mainUrl) { - const [command, ...args] = process.argv.slice(2); - if (command === "electron-package-version") { - printElectronPackageVersion(args); - } else { - fail("usage: example-release-dependencies.mjs electron-package-version "); - } -} diff --git a/examples/tools/run-electron-driver-smoke.sh b/examples/tools/run-electron-driver-smoke.sh deleted file mode 100755 index dd7cff97c..000000000 --- a/examples/tools/run-electron-driver-smoke.sh +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -fail() { - echo "run-electron-driver-smoke.sh: $*" >&2 - exit 1 -} - -app_dir="${1:-}" -if [ -z "$app_dir" ]; then - fail "usage: examples/tools/run-electron-driver-smoke.sh " -fi -if [ ! -f "$app_dir/package.json" ] || [ ! -f "$app_dir/src/main-process.ts" ]; then - fail "$app_dir does not look like an Electron example directory" -fi - -command -v node >/dev/null 2>&1 || fail "missing node" -command -v pnpm >/dev/null 2>&1 || fail "missing pnpm" - -assert_npm_package() { - local package_name="$1" - local expected_version="$2" - local resolver_package="${3:-}" - pnpm --dir "$app_dir" exec node - "$package_name" "$expected_version" "$resolver_package" <<'NODE' -const fs = require('node:fs'); -const path = require('node:path'); - -const [packageName, expectedVersion, resolverPackage] = process.argv.slice(2); -const resolvePaths = [process.cwd()]; -if (resolverPackage) { - const resolverPackageJson = require.resolve(`${resolverPackage}/package.json`, { - paths: [process.cwd()], - }); - resolvePaths.unshift(path.dirname(resolverPackageJson)); -} -const packageJson = require.resolve(`${packageName}/package.json`, { - paths: resolvePaths, -}); -const data = JSON.parse(fs.readFileSync(packageJson, 'utf8')); -if (data.version !== expectedVersion) { - throw new Error(`${packageName} resolved version ${data.version}, expected ${expectedVersion}`); -} -const normalized = packageJson.split(path.sep).join('/'); -if (!normalized.includes('/node_modules/')) { - throw new Error(`${packageName} resolved outside node_modules: ${packageJson}`); -} -NODE -} - -example_package_version() { - local package_name="$1" - node "$root/examples/tools/example-release-dependencies.mjs" electron-package-version "$package_name" -} - -electron_relative_path() { - local platform="$1" - local arch="$2" - case "$platform/$arch" in - linux/*) - printf '%s\n' "electron" - ;; - darwin/*) - printf '%s\n' "Electron.app/Contents/MacOS/Electron" - ;; - win32/*) - printf '%s\n' "electron.exe" - ;; - *) - fail "unsupported Electron e2e platform: $platform/$arch" - ;; - esac -} - -repair_electron_install() { - local electron_pkg="$1" - local platform="$2" - local arch="$3" - local relative_path="$4" - local electron_path="$electron_pkg/dist/$relative_path" - - if [ -x "$electron_path" ]; then - return - fi - command -v unzip >/dev/null 2>&1 || fail "missing unzip required to repair Electron binary install" - - local version - version="$(node -e 'process.stdout.write(require(process.argv[1]).version)' "$electron_pkg/package.json")" - local archive_name="electron-v$version-$platform-$arch.zip" - local archive="" - for cache_root in "${electron_config_cache:-}" "$HOME/.cache/electron"; do - if [ -n "$cache_root" ] && [ -d "$cache_root" ]; then - archive="$(find "$cache_root" -name "$archive_name" -type f | sort | tail -n 1)" - [ -n "$archive" ] && break - fi - done - if [ -z "$archive" ]; then - fail "Electron installed without $relative_path and cached $archive_name was not found" - fi - - rm -rf "$electron_pkg/dist" - mkdir -p "$electron_pkg/dist" - unzip -q "$archive" -d "$electron_pkg/dist" - printf '%s' "$relative_path" > "$electron_pkg/path.txt" - if [ -f "$electron_pkg/dist/electron.d.ts" ]; then - mv "$electron_pkg/dist/electron.d.ts" "$electron_pkg/electron.d.ts" - fi -} - -wasix_sidecar_env=() -prepare_wasix_sidecar() { - if [ ! -f "$app_dir/src-wasix/Cargo.toml" ]; then - return - fi - - local scratch="$root/target/e2e/electron-sidecars/${app_dir//\//-}" - rm -rf "$scratch" - mkdir -p "$scratch" - cp -R "$root/$app_dir/src-wasix/." "$scratch/" - rm -f "$scratch/Cargo.lock" - - cargo build \ - --quiet \ - --manifest-path "$scratch/Cargo.toml" \ - --target-dir "$scratch/target" - - local package_name - package_name="$( - awk -F'"' ' - $0 ~ /^\[package\]/ { in_package = 1; next } - $0 ~ /^\[/ && $0 !~ /^\[package\]/ { in_package = 0 } - in_package && $1 ~ /^name = / { print $2; exit } - ' "$scratch/Cargo.toml" - )" - if [ -z "$package_name" ]; then - fail "could not read package name from $scratch/Cargo.toml" - fi - local sidecar="$scratch/target/debug/$package_name" - if [ ! -x "$sidecar" ]; then - fail "missing built WASIX sidecar: $sidecar" - fi - wasix_sidecar_env=("OLIPHAUNT_WASIX_TODO_SIDECAR=$sidecar") -} - -pnpm --dir "$app_dir" install --no-frozen-lockfile -electron_pkg="$root/$app_dir/node_modules/electron" -electron_platform="$(node -p 'process.platform')" -electron_arch="$(node -p 'process.arch')" -electron_relative="$(electron_relative_path "$electron_platform" "$electron_arch")" -repair_electron_install "$electron_pkg" "$electron_platform" "$electron_arch" "$electron_relative" -electron="$electron_pkg/dist/$electron_relative" -if [ ! -x "$electron" ]; then - fail "missing Electron executable at $electron after example install" -fi -if [ "$app_dir" = "examples/electron" ]; then - typescript_version="$(example_package_version "@oliphaunt/ts")" - liboliphaunt_linux_version="$(example_package_version "@oliphaunt/liboliphaunt-linux-x64-gnu")" - hstore_version="$(example_package_version "@oliphaunt/extension-hstore")" - - assert_npm_package "@oliphaunt/ts" "$typescript_version" - assert_npm_package "@oliphaunt/liboliphaunt-linux-x64-gnu" "$liboliphaunt_linux_version" "@oliphaunt/ts" - assert_npm_package "@oliphaunt/extension-hstore" "$hstore_version" -fi -pnpm --dir "$app_dir" build -prepare_wasix_sidecar - -run_smoke=( - env - "OLIPHAUNT_E2E_ELECTRON=$electron" - "OLIPHAUNT_E2E_ELECTRON_APP=$root/$app_dir" - "${wasix_sidecar_env[@]}" - node - "$root/examples/tools/electron-driver-smoke.mjs" -) - -if command -v xvfb-run >/dev/null 2>&1; then - xvfb-run -a "${run_smoke[@]}" -else - "${run_smoke[@]}" -fi diff --git a/examples/tools/run-tauri-webdriver-smoke.sh b/examples/tools/run-tauri-webdriver-smoke.sh deleted file mode 100755 index 5e37bad3e..000000000 --- a/examples/tools/run-tauri-webdriver-smoke.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -fail() { - echo "run-tauri-webdriver-smoke.sh: $*" >&2 - exit 1 -} - -source_app_dir="${1:-}" -if [ -z "$source_app_dir" ]; then - fail "usage: examples/tools/run-tauri-webdriver-smoke.sh " -fi -if [[ "$source_app_dir" = /* ]]; then - source_app_path="$(realpath -m "$source_app_dir")" -else - source_app_path="$(realpath -m "$root/$source_app_dir")" -fi -case "$source_app_path" in - "$root"/*) ;; - *) fail "example path must remain inside the repository: $source_app_dir" ;; -esac -if [ ! -f "$source_app_path/src-tauri/Cargo.toml" ]; then - fail "$source_app_dir does not look like a Tauri example directory" -fi - -command -v node >/dev/null 2>&1 || fail "missing node" -command -v pnpm >/dev/null 2>&1 || fail "missing pnpm" -command -v WebKitWebDriver >/dev/null 2>&1 || - fail "missing WebKitWebDriver; install webkit2gtk-driver on Debian/Ubuntu" - -driver="$root/target/e2e-tools/bin/tauri-driver" -if [ ! -x "$driver" ]; then - cargo install tauri-driver --locked --version 2.0.6 --root "$root/target/e2e-tools" -fi - -source_app_relative="${source_app_path#"$root"/}" -scratch="$root/target/e2e/tauri-apps/${source_app_relative//\//-}/$$" -trap 'rm -rf "$scratch"' EXIT -rm -rf "$scratch" -app_dir="$(examples/tools/stage-tauri-webdriver-app.sh "$source_app_path" "$scratch")" -rm -f "$app_dir/src-tauri/Cargo.lock" - -pnpm --dir "$app_dir" install --no-frozen-lockfile -pnpm --dir "$app_dir" tauri build --debug - -package_name="$( - awk -F'"' ' - $0 ~ /^\[package\]/ { in_package = 1; next } - $0 ~ /^\[/ && $0 !~ /^\[package\]/ { in_package = 0 } - in_package && $1 ~ /^name = / { print $2; exit } - ' "$app_dir/src-tauri/Cargo.toml" -)" -if [ -z "$package_name" ]; then - fail "could not read package name from $app_dir/src-tauri/Cargo.toml" -fi -application="$app_dir/src-tauri/target/debug/$package_name" -if [ ! -x "$application" ]; then - fail "missing built Tauri application: $application" -fi - -run_smoke=( - env - "OLIPHAUNT_E2E_TAURI_DRIVER=$driver" - "OLIPHAUNT_E2E_TAURI_APP=$application" - node - "$root/examples/tools/tauri-webdriver-smoke.mjs" -) - -if command -v xvfb-run >/dev/null 2>&1; then - xvfb-run -a "${run_smoke[@]}" -else - "${run_smoke[@]}" -fi diff --git a/examples/tools/smoke-js-sdk.sh b/examples/tools/smoke-js-sdk.sh deleted file mode 100755 index 9f824d52e..000000000 --- a/examples/tools/smoke-js-sdk.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env sh -set -eu - -root="$(git rev-parse --show-toplevel)" -cd "$root" - -. src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh -oliphaunt_runtime_native_host_export_defaults -oliphaunt_runtime_native_host_require basic - -case "$(uname -s)" in - MINGW*|MSYS*|CYGWIN*) broker_name="oliphaunt-broker.exe" ;; - *) broker_name="oliphaunt-broker" ;; -esac -export OLIPHAUNT_BROKER="${OLIPHAUNT_BROKER:-$root/target/moon/oliphaunt-broker/build/debug/$broker_name}" -export OLIPHAUNT_NODE_ADDON="${OLIPHAUNT_NODE_ADDON:-$root/target/oliphaunt-artifacts/node-direct/$(oliphaunt_runtime_native_host_target_id)/oliphaunt_node.node}" - -test -x "$OLIPHAUNT_BROKER" -test -f "$OLIPHAUNT_NODE_ADDON" -pnpm --dir src/sdks/js exec tsx src/__tests__/native-smoke.ts -deno run --allow-all src/sdks/js/src/__tests__/deno-native-smoke.mjs diff --git a/examples/tools/stage-tauri-webdriver-app.sh b/examples/tools/stage-tauri-webdriver-app.sh deleted file mode 100755 index 98cfa58ea..000000000 --- a/examples/tools/stage-tauri-webdriver-app.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "stage-tauri-webdriver-app.sh: must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -fail() { - echo "stage-tauri-webdriver-app.sh: $*" >&2 - exit 1 -} - -source_app_dir="${1:-}" -destination_root="${2:-}" -if [[ -z "$source_app_dir" || -z "$destination_root" ]]; then - fail "usage: examples/tools/stage-tauri-webdriver-app.sh " -fi -for command_name in node realpath rsync; do - command -v "$command_name" >/dev/null 2>&1 || fail "missing required command: $command_name" -done - -if [[ "$source_app_dir" = /* ]]; then - source_app_path="$(realpath -m "$source_app_dir")" -else - source_app_path="$(realpath -m "$root/$source_app_dir")" -fi -case "$source_app_path" in - "$root/examples/"*) ;; - *) fail "Tauri webdriver examples must live under $root/examples: $source_app_dir" ;; -esac -[[ -f "$source_app_path/package.json" && -f "$source_app_path/src-tauri/Cargo.toml" ]] || - fail "$source_app_dir does not look like a Tauri example directory" -source_app_relative="${source_app_path#"$root"/}" -case "$source_app_relative" in - examples/tauri|examples/tauri-wasix) ;; - *) fail "unsupported Tauri webdriver example: $source_app_relative" ;; -esac - -destination_root="$(realpath -m "$destination_root")" -case "$destination_root" in - /|"$root"|"$root/examples"|"$root/examples/"*) - fail "destination must not overlap the checkout or its example sources: $destination_root" - ;; -esac -worktree="$destination_root/worktree" -rm -rf "$worktree" -mkdir -p "$worktree/examples" - -# Keep the bounded example family at its repository-relative location. The -# Tauri variants deliberately share frontend sources, and relocating only one -# app silently breaks those relative imports. -for example in tauri tauri-wasix; do - mkdir -p "$worktree/examples/$example" - rsync -a --delete \ - --exclude node_modules \ - --exclude dist \ - --exclude src-tauri/gen \ - --exclude src-tauri/target \ - "$root/examples/$example/" "$worktree/examples/$example/" -done - -# Tauri resolves bundle icons relative to src-tauri/tauri.conf.json. Copy each -# selected app icon as a regular file at the same repository-relative path so -# the scratch build has no symlink or live-checkout dependency. -config="$source_app_path/src-tauri/tauri.conf.json" -if [[ -f "$config" ]]; then - while IFS= read -r asset_relative; do - [[ -n "$asset_relative" ]] || continue - mkdir -p "$worktree/$(dirname "$asset_relative")" - cp -p "$root/$asset_relative" "$worktree/$asset_relative" - done < <( - node - "$config" "$root" <<'NODE' -const fs = require("node:fs"); -const path = require("node:path"); - -const [configFile, root] = process.argv.slice(2); -const config = JSON.parse(fs.readFileSync(configFile, "utf8")); -const icons = config?.bundle?.icon ?? []; -if (!Array.isArray(icons) || !icons.every((value) => typeof value === "string")) { - throw new Error(`${configFile}: bundle.icon must be an array of paths`); -} -for (const icon of icons) { - const source = path.resolve(path.dirname(configFile), icon); - const relative = path.relative(root, source); - if (relative === "" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { - throw new Error(`${configFile}: bundle icon escapes the repository: ${icon}`); - } - if (/[\r\n\0]/u.test(relative)) { - throw new Error(`${configFile}: bundle icon has an unsafe path: ${icon}`); - } - if (!fs.statSync(source).isFile()) { - throw new Error(`${configFile}: bundle icon is not a regular file: ${icon}`); - } - process.stdout.write(`${relative.split(path.sep).join("/")}\n`); -} -NODE - ) -fi - -app_dir="$worktree/$source_app_relative" -[[ -f "$app_dir/package.json" && -f "$app_dir/src-tauri/Cargo.toml" ]] || - fail "staged Tauri example is incomplete: $app_dir" -printf '%s\n' "$app_dir" diff --git a/examples/tools/stage-tauri-webdriver-app.test.sh b/examples/tools/stage-tauri-webdriver-app.test.sh deleted file mode 100755 index e51061c92..000000000 --- a/examples/tools/stage-tauri-webdriver-app.test.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "stage-tauri-webdriver-app.test.sh: must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -fail() { - echo "stage-tauri-webdriver-app.test.sh: $*" >&2 - exit 1 -} - -scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-tauri-stage-test.XXXXXX")" -trap 'rm -rf "$scratch"' EXIT - -stage_and_verify() { - example="$1" - destination="$scratch/$example" - actual="$(examples/tools/stage-tauri-webdriver-app.sh "examples/$example" "$destination")" - expected="$destination/worktree/examples/$example" - [[ "$actual" = "$expected" ]] || - fail "$example staged at $actual, expected $expected" - cmp "$root/examples/$example/package.json" "$actual/package.json" >/dev/null || - fail "$example package.json changed while staging" - cmp "$root/examples/$example/src-tauri/Cargo.toml" "$actual/src-tauri/Cargo.toml" >/dev/null || - fail "$example Cargo.toml changed while staging" - [[ -z "$(find "$destination/worktree" -type l -print -quit)" ]] || - fail "$example scratch closure contains a symlink into external state" - [[ -z "$(find "$destination/worktree/examples" -type d \ - \( -name node_modules -o -name dist -o -path '*/src-tauri/gen' -o -path '*/src-tauri/target' \) \ - -print -quit)" ]] || fail "$example scratch closure contains generated dependencies or build output" - printf '%s\n' "$actual" -} - -tauri="$(stage_and_verify tauri)" -tauri_wasix="$(stage_and_verify tauri-wasix)" - -shared_main="$tauri_wasix/src/../../tauri/src/main.ts" -shared_styles="$tauri_wasix/src/../../tauri/src/styles.css" -cmp "$root/examples/tauri/src/main.ts" "$shared_main" >/dev/null || - fail "tauri-wasix scratch tree is missing its shared TypeScript source" -cmp "$root/examples/tauri/src/styles.css" "$shared_styles" >/dev/null || - fail "tauri-wasix scratch tree is missing its shared stylesheet" - -icon_relative='../../assets/tauri-icon.png' -for app in "$tauri" "$tauri_wasix"; do - icon="$app/src-tauri/$icon_relative" - [[ -f "$icon" ]] || fail "$(basename "$app") scratch tree is missing its configured icon" - cmp "$root/examples/assets/tauri-icon.png" "$icon" >/dev/null || - fail "$(basename "$app") scratch icon differs from its declared source" -done - -if examples/tools/stage-tauri-webdriver-app.sh "$scratch" "$scratch/outside-source" >/dev/null 2>&1; then - fail "stager accepted a source outside examples/" -fi - -echo "Tauri webdriver clean-scratch staging passed" diff --git a/examples/tools/tauri-webdriver-smoke.mjs b/examples/tools/tauri-webdriver-smoke.mjs deleted file mode 100755 index c98251401..000000000 --- a/examples/tools/tauri-webdriver-smoke.mjs +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env node -import { spawn } from "node:child_process"; -import { mkdtempSync, rmSync } from "node:fs"; -import { tmpdir } from "node:os"; -import { join } from "node:path"; -import { createServer } from "node:net"; - -const driverPath = process.env.OLIPHAUNT_E2E_TAURI_DRIVER; -const application = process.env.OLIPHAUNT_E2E_TAURI_APP; - -if (!driverPath || !application) { - throw new Error("OLIPHAUNT_E2E_TAURI_DRIVER and OLIPHAUNT_E2E_TAURI_APP are required"); -} - -const webdriverElement = "element-6066-11e4-a52e-4f735466cecf"; -const port = await freePort(); -const nativePort = await freePort(); -const appData = mkdtempSync(join(tmpdir(), "oliphaunt-tauri-e2e-")); -let driver; -let sessionId; - -try { - driver = spawn(driverPath, ["--port", String(port), "--native-port", String(nativePort)], { - env: { - ...process.env, - XDG_DATA_HOME: appData, - XDG_CONFIG_HOME: appData, - XDG_CACHE_HOME: appData, - }, - detached: process.platform !== "win32", - stdio: ["ignore", "pipe", "pipe"], - }); - driver.stdout.on("data", (chunk) => process.stdout.write(chunk)); - driver.stderr.on("data", (chunk) => process.stderr.write(chunk)); - - await waitForDriver(port); - const session = await request(port, "POST", "/session", { - capabilities: { - alwaysMatch: { - "tauri:options": { application }, - }, - }, - }); - sessionId = session.sessionId ?? session.value?.sessionId; - if (!sessionId) { - throw new Error(`session response did not include sessionId: ${JSON.stringify(session)}`); - } - - await setValue(port, sessionId, "#title", `Ship Tauri e2e ${Date.now()}`); - await setValue(port, sessionId, "#notes", "created by raw WebDriver"); - await setValue(port, sessionId, "#area", "examples"); - await setValue(port, sessionId, "#context", "public packages"); - await click(port, sessionId, "button[type='submit']"); - await waitForText(port, sessionId, "article.todo", "created by raw WebDriver", 60_000); - await click(port, sessionId, "article.todo input[type='checkbox']"); - await click(port, sessionId, "[data-status='done']"); - await waitForText(port, sessionId, "article.todo.done", "created by raw WebDriver", 60_000); - console.log("tauri webdriver todo smoke passed"); -} finally { - if (sessionId) { - await request(port, "DELETE", `/session/${sessionId}`).catch(() => undefined); - } - await stopDriver(driver); - rmSync(appData, { recursive: true, force: true, maxRetries: 5, retryDelay: 250 }); -} - -async function stopDriver(driver) { - if (!driver || driver.exitCode !== null || driver.signalCode !== null) return; - const exited = new Promise((resolve) => driver.once("exit", resolve)); - try { - if (process.platform !== "win32" && driver.pid) { - process.kill(-driver.pid, "SIGTERM"); - } else { - driver.kill("SIGTERM"); - } - } catch { - return; - } - const stopped = await Promise.race([exited.then(() => true), sleep(3_000).then(() => false)]); - if (stopped) return; - try { - if (process.platform !== "win32" && driver.pid) { - process.kill(-driver.pid, "SIGKILL"); - } else { - driver.kill("SIGKILL"); - } - } catch { - // Process already exited. - } -} - -async function setValue(port, sessionId, selector, value) { - const id = await element(port, sessionId, selector); - await request(port, "POST", `/session/${sessionId}/element/${id}/clear`, {}); - await request(port, "POST", `/session/${sessionId}/element/${id}/value`, { - text: value, - value: [...value], - }); -} - -async function click(port, sessionId, selector) { - const id = await element(port, sessionId, selector); - await request(port, "POST", `/session/${sessionId}/element/${id}/click`, {}); -} - -async function element(port, sessionId, selector) { - const response = await request(port, "POST", `/session/${sessionId}/element`, { - using: "css selector", - value: selector, - }); - const value = response.value ?? response; - const id = value[webdriverElement] ?? value.ELEMENT; - if (!id) { - throw new Error(`element ${selector} response missing element id: ${JSON.stringify(response)}`); - } - return id; -} - -async function waitForText(port, sessionId, selector, expected, timeoutMs) { - const deadline = Date.now() + timeoutMs; - while (Date.now() < deadline) { - const text = await execute( - port, - sessionId, - `return document.querySelector(${JSON.stringify(selector)})?.textContent ?? "";`, - ); - if (String(text).includes(expected)) return; - await sleep(500); - } - const body = await execute(port, sessionId, "return document.body?.innerText ?? '';"); - throw new Error(`timed out waiting for ${selector} to contain ${expected}; body was: ${body}`); -} - -async function execute(port, sessionId, script) { - const response = await request(port, "POST", `/session/${sessionId}/execute/sync`, { - script, - args: [], - }); - return response.value; -} - -async function request(port, method, path, body) { - const response = await fetch(`http://127.0.0.1:${port}${path}`, { - method, - headers: { "content-type": "application/json" }, - body: body === undefined ? undefined : JSON.stringify(body), - }); - const text = await response.text(); - const json = text ? JSON.parse(text) : {}; - if (!response.ok) { - throw new Error(`${method} ${path} failed ${response.status}: ${text}`); - } - if (json.value?.error) { - throw new Error(`${method} ${path} failed: ${JSON.stringify(json.value)}`); - } - return json; -} - -async function waitForDriver(port) { - const deadline = Date.now() + 30_000; - while (Date.now() < deadline) { - try { - await request(port, "GET", "/status"); - return; - } catch { - await sleep(250); - } - } - throw new Error("timed out waiting for tauri-driver"); -} - -function freePort() { - return new Promise((resolve, reject) => { - const server = createServer(); - server.listen(0, "127.0.0.1", () => { - const address = server.address(); - if (address && typeof address === "object") { - server.close(() => resolve(address.port)); - } else { - server.close(() => reject(new Error("could not allocate a local port"))); - } - }); - server.on("error", reject); - }); -} - -function sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} diff --git a/moon.yml b/moon.yml index 741234d57..0de2aadd0 100644 --- a/moon.yml +++ b/moon.yml @@ -4,7 +4,7 @@ id: "repo" language: "unknown" layer: "configuration" stack: "infrastructure" -tags: ["repo", "hygiene", "monorepo"] +tags: ["javascript-quality", "repo", "hygiene", "monorepo"] project: title: "Repository" @@ -17,157 +17,26 @@ owners: "*": ["@oliphaunt/core"] tasks: - check: - tags: ["policy", "aggregate", "quality", "static"] - command: "true" - deps: - - "repo:tooling" - - "ci-workflows:check" - - "repo:docs-policy" - - "repo:release-metadata" - - "release-tools:broker-dependency-license-audit" - options: - cache: true - runFromWorkspaceRoot: true - tooling: - tags: ["policy", "assertion", "quality", "static"] - command: "bash tools/policy/check-tooling-stack.sh" - inputs: - - "/.github/**/*" - - "/.moon/workspace.yml" - - "/.moon/toolchains.yml" - - "/docs/maintainers/tooling.md" - - "/moon.yml" - - "@group(pnpm-workspace)" - - "/src/**/moon.yml" - - "/tools/**/*" - options: - cache: true - runFromWorkspaceRoot: true - docs-policy: - tags: ["policy", "assertion", "quality", "static"] - command: "bash tools/policy/check-docs.sh" - inputs: - - "/docs/**/*" - - "/src/docs/**/*" - - "!/src/docs/node_modules" - - "!/src/docs/node_modules/**" - - "!/src/docs/.next/**" - - "/tools/policy/check-docs.sh" - options: - cache: true - runFromWorkspaceRoot: true - release-metadata: - tags: ["policy", "assertion", "quality", "static"] - command: "tools/dev/bun.sh tools/release/check-release-metadata.mjs" - inputs: - - "/README.md" - - "/docs/**/*" - - "/Package.swift" - - "/src/**/*" - - "!/src/**/node_modules" - - "!/src/**/node_modules/**" - - "!/src/**/.build" - - "!/src/**/.build/**" - - "!/src/**/.gradle/**" - - "!/src/**/.cxx/**" - - "!/src/**/.next/**" - - "!/src/**/.source/**" - - "!/src/**/build/**" - - "!/src/**/out/**" - - "!/src/**/Pods/**" - - "!/src/**/DerivedData/**" - - "/tools/dev/bun.sh" - - "/tools/dev/capture-command-output.mjs" - - "/tools/dev/moon-command.mjs" - - "/tools/release/**/*" - options: - cache: true - runFromWorkspaceRoot: true - # The macOS publication-host job owns this exact proof in hosted CI. - runInCI: skip prek: tags: ["policy", "assertion", "quality", "static", "requires-maintainer-tools"] - command: "bash tools/policy/check-prek.sh" + command: "bash tools/dev/check-prek.sh" inputs: - - "/.config/nextest.toml" - - "/.lychee.toml" - - "/.markdownlint-cli2.jsonc" - - "/.typos.toml" - - "/biome.json" - - "/deny.toml" - - "/package.json" - - "/pnpm-lock.yaml" - - "/prek.toml" - - "/renovate.json" - - "/rust-toolchain.toml" - - "/src/**/*" - - "!/src/**/node_modules" - - "!/src/**/node_modules/**" - - "!/src/**/.build" - - "!/src/**/.build/**" - - "!/src/**/.gradle/**" - - "!/src/**/.cxx/**" - - "!/src/**/.next/**" - - "!/src/**/.source/**" - - "!/src/**/build/**" - - "!/src/**/out/**" - - "!/src/**/Pods/**" - - "!/src/**/DerivedData/**" - - "/tools/policy/check-prek.sh" + - "/**/*" options: cache: true runFromWorkspaceRoot: true # Local hook validation only; hosted checks already run the owned format # and policy tasks without bootstrapping every maintainer binary. runInCI: false - package: - tags: ["package"] - command: "bash tools/policy/check-crate-package.sh --allow-dirty" - inputs: - - "/Cargo.lock" - - "/Cargo.toml" - - "/src/**/Cargo.toml" - - "/src/**/*.rs" - - "/tools/policy/check-crate-size.sh" - options: - cache: true - runFromWorkspaceRoot: true - runInCI: false - coverage: - tags: ["coverage", "quality"] - command: "tools/coverage/summarize" - deps: - - target: "coverage-tools:rust" - cacheStrategy: "outputs" - - target: "coverage-tools:swift" - cacheStrategy: "outputs" - - target: "coverage-tools:kotlin" - cacheStrategy: "outputs" - - target: "coverage-tools:js" - cacheStrategy: "outputs" - - target: "coverage-tools:react-native" - cacheStrategy: "outputs" - - target: "coverage-tools:wasix-rust" - cacheStrategy: "outputs" - - target: "coverage-tools:wasix-ts" - cacheStrategy: "outputs" - inputs: - - "/coverage/baseline.toml" - - "/tools/coverage/**/*" - outputs: - - "/target/coverage/summary.json" - - "/target/coverage/summary.md" - options: - cache: true - runFromWorkspaceRoot: true - runInCI: false - coverage-policy: - tags: ["coverage", "policy"] - command: "bun tools/policy/check-coverage-baseline.mjs all" - inputs: - - "/coverage/baseline.toml" - - "/tools/policy/check-coverage-baseline.mjs" - options: - cache: true - runFromWorkspaceRoot: true + js-format-check: + command: "bun x --no-install biome format package.json biome.json renovate.json .markdownlint-cli2.jsonc" + inputs: ["/package.json", "/biome.json", "/renovate.json", "/.markdownlint-cli2.jsonc"] + options: + mergeArgs: replace + mergeInputs: replace + js-lint: + command: "bun x --no-install biome lint --diagnostic-level=error package.json biome.json renovate.json .markdownlint-cli2.jsonc" + inputs: ["/package.json", "/biome.json", "/renovate.json", "/.markdownlint-cli2.jsonc"] + options: + mergeArgs: replace + mergeInputs: replace diff --git a/package.json b/package.json index 25195de1d..8a4a1884a 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,55 @@ { "name": "oliphaunt-monorepo", "private": true, - "packageManager": "pnpm@11.5.0", + "packageManager": "bun@1.4.2", "engines": { "node": ">=22.13 <25", - "pnpm": "11.5.0" + "bun": "1.4.2" }, - "scripts": {} + "scripts": {}, + "devDependencies": { + "@biomejs/biome": "2.4.16" + }, + "workspaces": { + "packages": [ + "tools/release", + "src/sdks/ts-query", + "src/docs", + "src/sdks/ts/sdk", + "src/database-resources/icu/npm", + "src/runtimes/liboliphaunt-native/packages/*", + "src/postgres-tools/native/npm-platforms/*", + "src/postgres-tools/native/npm", + "src/broker/packages/*", + "src/sdks/ts/node-addon", + "src/sdks/ts/node-addon/packages/*", + "src/sdks/ts-wasix/node-addon", + "src/sdks/ts-wasix/node-addon/packages/*", + "src/sdks/react-native", + "src/examples/browser-wasix", + "src/examples/react-native-expo", + "src/sdks/ts-wasix/sdk", + "src/postgres-tools/wasix/ts", + "src/postgres-tools/wasix/npm", + "src/postgres-tools/wasix/npm-platforms/*", + "src/benchmarks/perf/wasix-node" + ], + "catalog": { + "typescript": "^6.0.3", + "@types/bun": "1.4.2" + } + }, + "overrides": { + "esbuild": "0.28.1", + "js-yaml": "4.3.0", + "postcss": "8.5.15", + "uuid": "11.1.1" + }, + "trustedDependencies": [ + "electron", + "esbuild", + "msgpackr-extract", + "sharp", + "unrs-resolver" + ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index c76e571bb..000000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,13449 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: false - excludeLinksFromLockfile: false - -catalogs: - default: - '@vitest/coverage-v8': - specifier: ^4.1.8 - version: 4.1.8 - tsx: - specifier: ^4.20.6 - version: 4.22.3 - typedoc: - specifier: ^0.28.16 - version: 0.28.19 - typescript: - specifier: ^6.0.3 - version: 6.0.3 - vitest: - specifier: ^4.1.8 - version: 4.1.8 - -overrides: - esbuild: 0.28.1 - js-yaml: 4.3.0 - postcss: 8.5.15 - uuid: 11.1.1 - -importers: - - .: {} - - examples/browser-wasix: - devDependencies: - '@electric-sql/pglite': - specifier: 0.5.4 - version: 0.5.4 - '@types/node': - specifier: ^24.10.1 - version: 24.12.4 - typescript: - specifier: 'catalog:' - version: 6.0.3 - vite: - specifier: ^6.0.3 - version: 6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0) - - examples/react-native-expo: - dependencies: - '@oliphaunt/react-native': - specifier: workspace:* - version: link:../../src/sdks/react-native - expo: - specifier: ~56.0.15 - version: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-dev-client: - specifier: ~56.0.22 - version: 56.0.22(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - expo-splash-screen: - specifier: ~56.0.12 - version: 56.0.12(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(typescript@6.0.3) - expo-sqlite: - specifier: ~56.0.5 - version: 56.0.5(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - expo-system-ui: - specifier: ~56.0.5 - version: 56.0.5(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - react: - specifier: 19.2.3 - version: 19.2.3 - react-dom: - specifier: 19.2.3 - version: 19.2.3(react@19.2.3) - react-native: - specifier: 0.85.3 - version: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - react-native-safe-area-context: - specifier: ~5.7.0 - version: 5.7.0(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - react-native-web: - specifier: ~0.21.0 - version: 0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - devDependencies: - '@react-native-community/cli': - specifier: 20.2.0 - version: 20.2.0(typescript@6.0.3) - '@react-native-community/cli-platform-android': - specifier: 20.2.0 - version: 20.2.0 - '@react-native-community/cli-platform-ios': - specifier: 20.2.0 - version: 20.2.0 - '@react-native/metro-config': - specifier: 0.85.3 - version: 0.85.3 - '@types/react': - specifier: 19.2.16 - version: 19.2.16 - eslint: - specifier: ^9.0.0 - version: 9.39.4(jiti@2.7.0) - eslint-config-expo: - specifier: ~56.0.4 - version: 56.0.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - expo-doctor: - specifier: ^1.19.7 - version: 1.19.8 - expo-mcp: - specifier: ~0.2.1 - version: 0.2.4 - typescript: - specifier: ~6.0.3 - version: 6.0.3 - - src/bindings/wasix-ts: - dependencies: - '@oliphaunt/js-core': - specifier: workspace:* - version: link:../../shared/js-core - fzstd: - specifier: 0.1.1 - version: 0.1.1 - devDependencies: - '@electric-sql/pglite': - specifier: 0.5.4 - version: 0.5.4 - '@types/node': - specifier: ^24.10.1 - version: 24.12.4 - typedoc: - specifier: 'catalog:' - version: 0.28.19(typescript@6.0.3) - typescript: - specifier: 'catalog:' - version: 6.0.3 - vite: - specifier: ^6.0.3 - version: 6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0) - vitest: - specifier: 'catalog:' - version: 4.1.8(@types/node@24.12.4)(@vitest/coverage-v8@4.1.8)(vite@6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0)) - optionalDependencies: - '@oliphaunt/wasix-napi-darwin-arm64': - specifier: workspace:* - version: link:../../runtimes/wasix-napi/packages/darwin-arm64 - '@oliphaunt/wasix-napi-linux-arm64-gnu': - specifier: workspace:* - version: link:../../runtimes/wasix-napi/packages/linux-arm64-gnu - '@oliphaunt/wasix-napi-linux-x64-gnu': - specifier: workspace:* - version: link:../../runtimes/wasix-napi/packages/linux-x64-gnu - '@oliphaunt/wasix-napi-win32-x64-msvc': - specifier: workspace:* - version: link:../../runtimes/wasix-napi/packages/win32-x64-msvc - - src/bindings/wasix-ts/tools-package: - dependencies: - '@oliphaunt/liboliphaunt-wasix-tools': - specifier: workspace:* - version: link:../../../runtimes/liboliphaunt/wasix/tools-npm - devDependencies: - '@oliphaunt/wasix-ts': - specifier: workspace:* - version: link:.. - '@types/node': - specifier: ^24.10.1 - version: 24.12.4 - typescript: - specifier: 'catalog:' - version: 6.0.3 - vitest: - specifier: 'catalog:' - version: 4.1.8(@types/node@24.12.4)(@vitest/coverage-v8@4.1.8)(vite@6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0)) - - src/docs: - dependencies: - '@mdx-js/react': - specifier: ^3.1.0 - version: 3.1.1(@types/react@19.2.16)(react@19.2.7) - '@oliphaunt/react-native': - specifier: workspace:* - version: link:../sdks/react-native - '@oliphaunt/ts': - specifier: workspace:* - version: link:../sdks/js - clsx: - specifier: ^2.1.1 - version: 2.1.1 - fumadocs-core: - specifier: 16.9.3 - version: 16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.16)(lucide-react@1.17.0(react@19.2.7))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3) - fumadocs-mdx: - specifier: 15.0.10 - version: 15.0.10(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.16)(fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.16)(lucide-react@1.17.0(react@19.2.7))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7) - fumadocs-ui: - specifier: 16.9.3 - version: 16.9.3(@tailwindcss/oxide@4.3.0)(@types/mdx@2.0.13)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.16)(lucide-react@1.17.0(react@19.2.7))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@4.3.0) - lucide-react: - specifier: ^1.17.0 - version: 1.17.0(react@19.2.7) - motion: - specifier: 13.1.0 - version: 13.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - next: - specifier: 16.2.7 - version: 16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - react: - specifier: 19.2.7 - version: 19.2.7 - react-dom: - specifier: 19.2.7 - version: 19.2.7(react@19.2.7) - simple-icons: - specifier: 16.28.0 - version: 16.28.0 - smol-toml: - specifier: ^1.4.2 - version: 1.6.1 - tailwind-merge: - specifier: ^3.6.0 - version: 3.6.0 - devDependencies: - '@biomejs/biome': - specifier: ^2.4.16 - version: 2.4.16 - '@tailwindcss/postcss': - specifier: ^4.3.0 - version: 4.3.0 - '@types/mdx': - specifier: ^2.0.13 - version: 2.0.13 - '@types/node': - specifier: 22.19.19 - version: 22.19.19 - '@types/react': - specifier: 19.2.16 - version: 19.2.16 - '@types/react-dom': - specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.16) - postcss: - specifier: 8.5.15 - version: 8.5.15 - tailwindcss: - specifier: 4.3.0 - version: 4.3.0 - typescript: - specifier: ^5.9.3 - version: 5.9.3 - - src/runtimes/broker/packages/darwin-arm64: {} - - src/runtimes/broker/packages/linux-arm64-gnu: {} - - src/runtimes/broker/packages/linux-x64-gnu: {} - - src/runtimes/broker/packages/win32-x64-msvc: {} - - src/runtimes/liboliphaunt/native/icu-npm: {} - - src/runtimes/liboliphaunt/native/packages/darwin-arm64: {} - - src/runtimes/liboliphaunt/native/packages/linux-arm64-gnu: {} - - src/runtimes/liboliphaunt/native/packages/linux-x64-gnu: {} - - src/runtimes/liboliphaunt/native/packages/win32-x64-msvc: {} - - src/runtimes/liboliphaunt/native/tools-npm: - optionalDependencies: - '@oliphaunt/tools-darwin-arm64': - specifier: workspace:0.2.0 - version: link:../tools-packages/darwin-arm64 - '@oliphaunt/tools-linux-arm64-gnu': - specifier: workspace:0.2.0 - version: link:../tools-packages/linux-arm64-gnu - '@oliphaunt/tools-linux-x64-gnu': - specifier: workspace:0.2.0 - version: link:../tools-packages/linux-x64-gnu - '@oliphaunt/tools-win32-x64-msvc': - specifier: workspace:0.2.0 - version: link:../tools-packages/win32-x64-msvc - - src/runtimes/liboliphaunt/native/tools-packages/darwin-arm64: {} - - src/runtimes/liboliphaunt/native/tools-packages/linux-arm64-gnu: {} - - src/runtimes/liboliphaunt/native/tools-packages/linux-x64-gnu: {} - - src/runtimes/liboliphaunt/native/tools-packages/win32-x64-msvc: {} - - src/runtimes/liboliphaunt/wasix/tools-npm: {} - - src/runtimes/node-direct: - devDependencies: - node-api-headers: - specifier: 1.9.0 - version: 1.9.0 - - src/runtimes/node-direct/packages/darwin-arm64: {} - - src/runtimes/node-direct/packages/linux-arm64-gnu: {} - - src/runtimes/node-direct/packages/linux-x64-gnu: {} - - src/runtimes/node-direct/packages/win32-x64-msvc: {} - - src/runtimes/wasix-napi: {} - - src/runtimes/wasix-napi/packages/darwin-arm64: {} - - src/runtimes/wasix-napi/packages/linux-arm64-gnu: {} - - src/runtimes/wasix-napi/packages/linux-x64-gnu: {} - - src/runtimes/wasix-napi/packages/win32-x64-msvc: {} - - src/sdks/js: - dependencies: - '@oliphaunt/js-core': - specifier: workspace:* - version: link:../../shared/js-core - devDependencies: - '@types/node': - specifier: ^24.10.1 - version: 24.12.4 - '@vitest/coverage-v8': - specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) - tsx: - specifier: 'catalog:' - version: 4.22.3 - typedoc: - specifier: 'catalog:' - version: 0.28.19(typescript@6.0.3) - typescript: - specifier: 'catalog:' - version: 6.0.3 - vitest: - specifier: 'catalog:' - version: 4.1.8(@types/node@24.12.4)(@vitest/coverage-v8@4.1.8)(vite@6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0)) - optionalDependencies: - '@oliphaunt/broker-darwin-arm64': - specifier: workspace:* - version: link:../../runtimes/broker/packages/darwin-arm64 - '@oliphaunt/broker-linux-arm64-gnu': - specifier: workspace:* - version: link:../../runtimes/broker/packages/linux-arm64-gnu - '@oliphaunt/broker-linux-x64-gnu': - specifier: workspace:* - version: link:../../runtimes/broker/packages/linux-x64-gnu - '@oliphaunt/broker-win32-x64-msvc': - specifier: workspace:* - version: link:../../runtimes/broker/packages/win32-x64-msvc - '@oliphaunt/liboliphaunt-darwin-arm64': - specifier: workspace:* - version: link:../../runtimes/liboliphaunt/native/packages/darwin-arm64 - '@oliphaunt/liboliphaunt-linux-arm64-gnu': - specifier: workspace:* - version: link:../../runtimes/liboliphaunt/native/packages/linux-arm64-gnu - '@oliphaunt/liboliphaunt-linux-x64-gnu': - specifier: workspace:* - version: link:../../runtimes/liboliphaunt/native/packages/linux-x64-gnu - '@oliphaunt/liboliphaunt-win32-x64-msvc': - specifier: workspace:* - version: link:../../runtimes/liboliphaunt/native/packages/win32-x64-msvc - '@oliphaunt/node-direct-darwin-arm64': - specifier: workspace:* - version: link:../../runtimes/node-direct/packages/darwin-arm64 - '@oliphaunt/node-direct-linux-arm64-gnu': - specifier: workspace:* - version: link:../../runtimes/node-direct/packages/linux-arm64-gnu - '@oliphaunt/node-direct-linux-x64-gnu': - specifier: workspace:* - version: link:../../runtimes/node-direct/packages/linux-x64-gnu - '@oliphaunt/node-direct-win32-x64-msvc': - specifier: workspace:* - version: link:../../runtimes/node-direct/packages/win32-x64-msvc - - src/sdks/react-native: - dependencies: - '@oliphaunt/js-core': - specifier: workspace:* - version: link:../../shared/js-core - devDependencies: - '@react-native/codegen': - specifier: ^0.85.3 - version: 0.85.3 - '@react-native/typescript-config': - specifier: ^0.85.0 - version: 0.85.3 - '@types/node': - specifier: ^24.10.1 - version: 24.12.4 - '@vitest/coverage-v8': - specifier: 'catalog:' - version: 4.1.8(vitest@4.1.8) - react: - specifier: ^19.2.0 - version: 19.2.3 - react-native: - specifier: ^0.85.0 - version: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - tsx: - specifier: 'catalog:' - version: 4.22.3 - typedoc: - specifier: 'catalog:' - version: 0.28.19(typescript@6.0.3) - typescript: - specifier: 'catalog:' - version: 6.0.3 - vitest: - specifier: 'catalog:' - version: 4.1.8(@types/node@24.12.4)(@vitest/coverage-v8@4.1.8)(vite@6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0)) - - src/shared/js-core: - devDependencies: - '@types/node': - specifier: ^24.10.1 - version: 24.12.4 - typescript: - specifier: 'catalog:' - version: 6.0.3 - - tools/perf/wasix-node: - dependencies: - '@electric-sql/pglite': - specifier: 0.5.4 - version: 0.5.4 - -packages: - - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.3': - resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-create-class-features-plugin@7.29.3': - resolution: {integrity: sha512-RpLYy2sb51oNLjuu1iD3bwBqCBWUzjO0ocp+iaCP/lJtb2CPLcnC2Fftw+4sAzaMELGeWTgExSKADbdo0GFVzA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-create-regexp-features-plugin@7.28.5': - resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-define-polyfill-provider@0.6.8': - resolution: {integrity: sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-member-expression-to-functions@7.28.5': - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.29.7': - resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-remap-async-to-generator@7.27.1': - resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-replace-supers@7.28.6': - resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-wrap-function@7.28.6': - resolution: {integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.3': - resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-proposal-decorators@7.29.0': - resolution: {integrity: sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-proposal-export-default-from@7.27.1': - resolution: {integrity: sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-decorators@7.28.6': - resolution: {integrity: sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-dynamic-import@7.8.3': - resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-export-default-from@7.28.6': - resolution: {integrity: sha512-Svlx1fjJFnNz0LZeUaybRukSxZI3KkpApUmIRzEdXC5k8ErTOz0OD0kNrICi5Vc3GlpP5ZCeRyRO+mfWTSz+iQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-flow@7.28.6': - resolution: {integrity: sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-jsx@7.28.6': - resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-optional-chaining@7.8.3': - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-typescript@7.28.6': - resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-async-generator-functions@7.29.0': - resolution: {integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-async-to-generator@7.28.6': - resolution: {integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-block-scoping@7.28.6': - resolution: {integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-class-properties@7.28.6': - resolution: {integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-class-static-block@7.28.6': - resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.12.0 - - '@babel/plugin-transform-classes@7.28.6': - resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-destructuring@7.28.5': - resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-export-namespace-from@7.27.1': - resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-flow-strip-types@7.27.1': - resolution: {integrity: sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-for-of@7.27.1': - resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-logical-assignment-operators@7.28.6': - resolution: {integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-commonjs@7.28.6': - resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-named-capturing-groups-regex@7.29.0': - resolution: {integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-nullish-coalescing-operator@7.28.6': - resolution: {integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-object-rest-spread@7.28.6': - resolution: {integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-catch-binding@7.28.6': - resolution: {integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-chaining@7.28.6': - resolution: {integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-parameters@7.27.7': - resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-methods@7.28.6': - resolution: {integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-property-in-object@7.28.6': - resolution: {integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-display-name@7.28.0': - resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-development@7.27.1': - resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-self@7.29.7': - resolution: {integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.29.7': - resolution: {integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx@7.28.6': - resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-pure-annotations@7.27.1': - resolution: {integrity: sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-regenerator@7.29.7': - resolution: {integrity: sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-runtime@7.29.0': - resolution: {integrity: sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typescript@7.28.6': - resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-regex@7.27.1': - resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-typescript@7.28.5': - resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.29.2': - resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@bcoe/v8-coverage@1.0.2': - resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} - engines: {node: '>=18'} - - '@biomejs/biome@2.4.16': - resolution: {integrity: sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA==} - engines: {node: '>=14.21.3'} - hasBin: true - - '@biomejs/cli-darwin-arm64@2.4.16': - resolution: {integrity: sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [darwin] - - '@biomejs/cli-darwin-x64@2.4.16': - resolution: {integrity: sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [darwin] - - '@biomejs/cli-linux-arm64-musl@2.4.16': - resolution: {integrity: sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@biomejs/cli-linux-arm64@2.4.16': - resolution: {integrity: sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@biomejs/cli-linux-x64-musl@2.4.16': - resolution: {integrity: sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@biomejs/cli-linux-x64@2.4.16': - resolution: {integrity: sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@biomejs/cli-win32-arm64@2.4.16': - resolution: {integrity: sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [win32] - - '@biomejs/cli-win32-x64@2.4.16': - resolution: {integrity: sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [win32] - - '@electric-sql/pglite@0.5.4': - resolution: {integrity: sha512-yYZUyyXrHU7tPlCjwZQJ6hIG9DscdCCn7Uk0mYKwC1FeHX286AbcmFveMiRBEak8e9iPupjsoVImN3yJZVed2g==} - - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - - '@emnapi/runtime@1.10.0': - resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - - '@esbuild/aix-ppc64@0.28.1': - resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.28.1': - resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.28.1': - resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.28.1': - resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.28.1': - resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.28.1': - resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.28.1': - resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.28.1': - resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.28.1': - resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.28.1': - resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.28.1': - resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.28.1': - resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.28.1': - resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.28.1': - resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.28.1': - resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.28.1': - resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.28.1': - resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.28.1': - resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.28.1': - resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.28.1': - resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.28.1': - resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.28.1': - resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.28.1': - resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.28.1': - resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.28.1': - resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.28.1': - resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.21.2': - resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.3.5': - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.39.4': - resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@expo/cli@56.1.19': - resolution: {integrity: sha512-k+oipwbu83WFnACtybvGZvDbbItarY4lfjkKgP9F5lml2ilvL/VvzsPhbhT7nRyFB3zPJq9SbNNKa45VDLoihA==} - hasBin: true - peerDependencies: - expo: '*' - expo-router: '*' - react-native: '*' - peerDependenciesMeta: - expo-router: - optional: true - react-native: - optional: true - - '@expo/code-signing-certificates@0.0.6': - resolution: {integrity: sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==} - - '@expo/config-plugins@56.0.12': - resolution: {integrity: sha512-UKjPEOkvxBzTvjghmjUECURDoJLPJIFIevB0JQCe8l9Fg4yfy2fabU5LU3Kfrmmu1/8et/93bucCnABEmoxYEw==} - - '@expo/config-types@56.0.7': - resolution: {integrity: sha512-V7bxawNsNned/yMppAHdisIOxniZXgPKRWpIUiQOQBs45/A5MBd2gfDM4Ecq5gnbilnQUTaI6Zxn6JcW7L3TAA==} - - '@expo/config@56.0.11': - resolution: {integrity: sha512-Rt3U9Rqr6midz/sDeubFN5fefR0KzHpcEEgAUnV98XsLSSTnfzIxoC1blICb7pUUscKc8TtlVyn7/Gita2wnOQ==} - - '@expo/devcert@1.2.1': - resolution: {integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==} - - '@expo/devtools@56.0.2': - resolution: {integrity: sha512-ANl4kPdbe0/HQYWkDEN79S6bQhI+i/ZCnPxuC853pPsB4svhINC7Ku9lmGOKPsUUWWnrHg1spkDGQBZ4sD6JxQ==} - peerDependencies: - react: '*' - react-native: '*' - peerDependenciesMeta: - react: - optional: true - react-native: - optional: true - - '@expo/dom-webview@56.0.6': - resolution: {integrity: sha512-DQY3Tj5nrPbpIfEQiD9xbyEFTu25yEORa02Eyzl5rXszDzxDT4VkZDHkyErNQOyE1qjublJHNFhE5bDm4tRfqA==} - peerDependencies: - expo: '*' - react: '*' - react-native: '*' - - '@expo/env@2.3.1': - resolution: {integrity: sha512-JvBdZa5OkTd+dGEtt3fLW9OF6RlIp9SNu9VyMSiWPV5szMDTSAYbX8Uj3cRvZcU1zzaRbqnTSsHk2AE8WXHfxQ==} - engines: {node: '>=20.12.0'} - - '@expo/env@2.4.1': - resolution: {integrity: sha512-3c9Mg9x0HmGPEsVrGAGyEDJsNUOZ55cZvZ47/HLmXh7MHV9Zv7My73wThklKrObaBBoMfE4YqpKjYKDRzojpjQ==} - engines: {node: '>=20.12.0'} - - '@expo/expo-modules-macros-plugin@0.2.2': - resolution: {integrity: sha512-4IMzPDIo/VOXREQjsJtliSfqYVZvfzU2SLFS/9sKMWF848S8CHx+e/E+Vf0TcMvpWCCKX5umyqxb13KJJ+YUzg==} - - '@expo/fingerprint@0.19.7': - resolution: {integrity: sha512-Q04NyJE0E7qKGXepBjI8e0p983RrQGBWJcSICKyyLczsr5JhNuSmqw604aL7koaXG2ctrUL36qd332XiMS/s6w==} - hasBin: true - - '@expo/image-utils@0.10.2': - resolution: {integrity: sha512-qQUGaacqXduoFTCUQAMceIWYzlKU0xX4/BKTyh8TdVj0uHv9/W3MfHOy5yXoOqBVrSccXk++Gm4D/NfS5HnCNA==} - - '@expo/inline-modules@0.0.13': - resolution: {integrity: sha512-26RllWesRmYsAAo70cRcR9DaqXPKJct9MIGxZteS+Tkg25ljOkFeG7fYEsSazZOLpAslKBiilqtZykVYrxSzCw==} - - '@expo/json-file@10.2.0': - resolution: {integrity: sha512-S6XzKe3R9GQeHiUPXc3xJjOv2VJhOEwFYf7xdC2z2cUqt3kZJ9mSO877sNQloVdnW/SUCtPY3bexlM7nwq+CAQ==} - - '@expo/json-file@11.0.0': - resolution: {integrity: sha512-pHJCETqFL5x5BzNV6cEPwjwuECgGmnl0bNmfHIJ6LM1tlh2eVXi5HEdit3zby/JO/B8Otk5cgcqtJXgvvUat3A==} - - '@expo/local-build-cache-provider@56.0.9': - resolution: {integrity: sha512-VMJC5ul7dXPfD2OO16ObPi6ym4H8vlnCBUuCM/KeKh0OvLRub35X8OB2uYrFQ+vbWkPemAEOWvk0oOptpPxbzA==} - - '@expo/log-box@56.0.14': - resolution: {integrity: sha512-3Eadcxz0J2NESG2iKe8DnAggsRCWqY0mBLhgQPNzClPVjS6o4NyD0F8kuOvWNngFwpJBC08HhY2o8P1mgSgeJg==} - peerDependencies: - expo: '*' - react: '*' - react-native: '*' - - '@expo/mcp-tunnel@0.2.4': - resolution: {integrity: sha512-hxFzqdUNKCt+8pbGV3oGcd/aBNA1mmhwh3DSeXoHReypxzsiLYLITJs1OctglaPecfMA9qFb+6z/RIkRSf5S4g==} - peerDependencies: - '@modelcontextprotocol/sdk': ^1.26.0 - - '@expo/metro-config@56.0.16': - resolution: {integrity: sha512-mxPZ23exC6kkEpPYQOteamaiWYER3uDk2IqKys7EJwtIKc3F1207Xtsdko/DNNG04DLwpN/WM2UlNl+Ak8uPRg==} - peerDependencies: - expo: '*' - peerDependenciesMeta: - expo: - optional: true - - '@expo/metro-file-map@56.0.3': - resolution: {integrity: sha512-5OGW3z8LgEYgMJOR7F3pC8llFLkb1fVqwAewbCl6S4Vkha8AFQMwOjT+9Wbka+V4rmpljpGqOnMhF4xZbD961w==} - - '@expo/metro@56.0.0': - resolution: {integrity: sha512-5gIgQHtEpjjvsjKfVtIv23a98LLRV0/y07PDShEwYSytAMlE3FSF8RHXqtHc1sUJL6dn7hnuIBpIbrLXXuVi0A==} - - '@expo/osascript@2.6.0': - resolution: {integrity: sha512-QvqDBlJXa8CS2vRORJ4wEflY1m0vVI07uSJdIRgBrLxRPBcsrXxrtU7+wXRXMqfq9zLwNP9XbvRsXF2omoDylg==} - engines: {node: '>=12'} - - '@expo/package-manager@1.13.0': - resolution: {integrity: sha512-s3W3eZafJDEyVL7W/jxj2Nz3eONKxSCU604S5xj8ijrVaRz83x0DnZznLf/UXQEI1w+FyibH68nHeQyk767b1A==} - - '@expo/plist@0.7.0': - resolution: {integrity: sha512-vrpryU1GoqSIRNqRB2D3IjXDmzNYfiQpEF6AH/xknlD7eiYmEDt3mb26V7cLcedcPG8PY/1xWHdBXVQJfEAh6Q==} - - '@expo/prebuild-config@56.0.19': - resolution: {integrity: sha512-aP/7kGDPMmwY9C9cYMK4MfUiZk23KhN4AfnKz0eeRyg3Izw0OGdtzNDLIcchnqpDAwHsI0+LUHZhucGl1jQJ5A==} - - '@expo/require-utils@56.1.4': - resolution: {integrity: sha512-IX7XXg9obnrH3ni0TClBbVKgqk0nT0bjTEPTBtbD+WgIeZ0hpcgwxMJH3j5uBsUqEAq1jqUAkJWrPcg7ZRSV7g==} - peerDependencies: - typescript: ^5.0.0 || ^5.0.0-0 || ^6.0.0 - peerDependenciesMeta: - typescript: - optional: true - - '@expo/router-server@56.0.16': - resolution: {integrity: sha512-df5BI5GFnSKqAhuALTPIbuHisd4CUhuYam7pwF9Dt1D6BinPctsteWWDm/sEGXdLVhsub4NPI7tvUHo/HWL7aA==} - peerDependencies: - '@expo/metro-runtime': ^56.0.16 - expo: '*' - expo-constants: ^56.0.20 - expo-font: ^56.0.7 - expo-router: '*' - expo-server: ^56.0.5 - react: '*' - react-dom: '*' - react-server-dom-webpack: ~19.0.1 || ~19.1.2 || ~19.2.1 - peerDependenciesMeta: - '@expo/metro-runtime': - optional: true - expo-router: - optional: true - react-dom: - optional: true - react-server-dom-webpack: - optional: true - - '@expo/schema-utils@56.0.2': - resolution: {integrity: sha512-WcOH1E6rwxRqNwBzPOVhd5GBbMlS04+5n+ZMdhdwKOg/Kt3suV+F8F6An+z8mUJ8eSuMM3HD9Sj09t7vc/Xjkw==} - - '@expo/sdk-runtime-versions@1.0.0': - resolution: {integrity: sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==} - - '@expo/spawn-async@1.8.0': - resolution: {integrity: sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==} - engines: {node: '>=12'} - - '@expo/sudo-prompt@9.3.2': - resolution: {integrity: sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==} - - '@expo/ws-tunnel@2.0.0': - resolution: {integrity: sha512-j+JfTRdCk820J9dU0sA2SqshQIKFOMo7ED84w9MJFcebfbNQgsLztEY/SABDkGnjatrW4xGqnUhVRxSBVyCkXw==} - peerDependencies: - ws: ^8.0.0 - - '@expo/xcpretty@4.4.4': - resolution: {integrity: sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw==} - hasBin: true - - '@floating-ui/core@1.7.5': - resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - - '@floating-ui/dom@1.7.6': - resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - - '@floating-ui/react-dom@2.1.8': - resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/utils@0.2.11': - resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - - '@fumadocs/tailwind@0.0.5': - resolution: {integrity: sha512-ENKPWUDRmriccsrUDE4bDBq3FNr/ms3BP2rWlsAEMV1yP23pcCaan+ceGfeBUsAQjw7sj9Q3R4Kl3g/TCStPzQ==} - peerDependencies: - '@tailwindcss/oxide': ^4.0.0 - tailwindcss: ^4.0.0 - peerDependenciesMeta: - '@tailwindcss/oxide': - optional: true - tailwindcss: - optional: true - - '@gerrit0/mini-shiki@3.23.0': - resolution: {integrity: sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==} - - '@hapi/hoek@9.3.0': - resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} - - '@hapi/topo@5.1.0': - resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} - - '@hono/node-server@1.19.14': - resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - - '@humanfs/core@0.19.2': - resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.8': - resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} - engines: {node: '>=18.18.0'} - - '@humanfs/types@0.15.0': - resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@img/colour@1.1.0': - resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} - engines: {node: '>=18'} - - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [darwin] - - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} - cpu: [arm64] - os: [darwin] - - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [wasm32] - - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [win32] - - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ia32] - os: [win32] - - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [win32] - - '@isaacs/cliui@9.0.0': - resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} - engines: {node: '>=18'} - - '@isaacs/ttlcache@1.4.1': - resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} - engines: {node: '>=12'} - - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/types@29.6.3': - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/source-map@0.3.11': - resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@mdx-js/mdx@3.1.1': - resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} - - '@mdx-js/react@3.1.1': - resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==} - peerDependencies: - '@types/react': '>=16' - react: '>=16' - - '@modelcontextprotocol/sdk@1.29.0': - resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} - engines: {node: '>=18'} - peerDependencies: - '@cfworker/json-schema': ^4.1.1 - peerDependenciesMeta: - '@cfworker/json-schema': - optional: true - - '@napi-rs/wasm-runtime@1.1.4': - resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - - '@next/env@16.2.7': - resolution: {integrity: sha512-tMJizPlj6ZYpBMMdK8S0LJufrP4QTdR6pcv9KQ/bVETPAmg0j1mlHE9G2c38UyGHxoBapgwuj7XjbGJ2RcDFOg==} - - '@next/swc-darwin-arm64@16.2.7': - resolution: {integrity: sha512-vm1EDI/pVaBNNiychmxk3fft+OhQPVD9cIM/tReLZIQ3TfQ4kqI9DwKk00dzuS1ulC7icbrzCFrmRRlk9PfNdw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@16.2.7': - resolution: {integrity: sha512-O3IRSv1ZBL1zs0WrIgefTEcTKFVn+ryxBNe54erJ6KsD+2f/Mmt7g2jOYh8PSBdUwPtKQJuCsTMlZ7tIu2AcsQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@16.2.7': - resolution: {integrity: sha512-Re6PZtjBDd0aMU+VcZcC/PrIvj4WhrjDYtMhhCVQamWN4L90EVP0pcEOBQD25prSlw7OzNw5QpHLWMilRLsRNw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@next/swc-linux-arm64-musl@16.2.7': - resolution: {integrity: sha512-qyogG9QtBzWxgJfeGBvOEHI3851gTfCF3wLZ5RDLTBJGAmE9p1qDwKCOdrBrvBzRvYDT+gUDp72pzlSEfAXgNA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@next/swc-linux-x64-gnu@16.2.7': - resolution: {integrity: sha512-Vhe4ZDuBpmMogrGi5D4R2Kq4JAQlj6+wvgaFYy31zfES0zPmt6TLA+cuYpM/OLrPZjo2MYQTHVqNUSCR6+fDZQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@next/swc-linux-x64-musl@16.2.7': - resolution: {integrity: sha512-srvian89JahFLw1YLBEuhvPJ0DO5lpUeJQMXy4xYo7g628ZlNgXdNkqoxSAv9OYrBfByh6vxISMwW/mRbzCY+g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@next/swc-win32-arm64-msvc@16.2.7': - resolution: {integrity: sha512-GX3wvLpULFuRFJzwHaKfm7QZJ18F4ZSuxlPJ96BoBglCzBmdSjyeBKF+ZhWhvL/ckxNfLnNa7bsObO2ipYpszw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-x64-msvc@16.2.7': - resolution: {integrity: sha512-J4WlM72NMk076Qsg0jTdK3SNXatlSdnjW7L7oNGLst1tAGjHrJh/FYi+pw9wyIjEtGRKDNzD0zuiY16oWYWVaw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@nodable/entities@3.0.0': - resolution: {integrity: sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@nolyfill/is-core-module@1.0.39': - resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} - engines: {node: '>=12.4.0'} - - '@orama/orama@3.1.18': - resolution: {integrity: sha512-a61ljmRVVyG5MC/698C8/FfFDw5a8LOIvyOLW5fztgUXqUpc1jOfQzOitSCbge657OgXXThmY3Tk8fpiDb4UcA==} - engines: {node: '>= 20.0.0'} - - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-accordion@1.2.12': - resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collapsible@1.1.12': - resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dialog@1.1.15': - resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-navigation-menu@1.2.14': - resolution: {integrity: sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popover@1.1.15': - resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popper@1.2.8': - resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-scroll-area@1.2.10': - resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-slot@1.2.4': - resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-tabs@1.1.13': - resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-visually-hidden@1.2.3': - resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - - '@react-native-community/cli-clean@20.2.0': - resolution: {integrity: sha512-krqbhFiwHN8l5wZ2XTcrNq9N+DqDWHxW8RK0bIcrK0O+fMvjYi9e/1Pnx2W0CTotOVcZpHzUbgZ4TQVF231Skw==} - - '@react-native-community/cli-config-android@20.2.0': - resolution: {integrity: sha512-lASofUNBVK0Pq3VEJ1JrCfAW94Rnk38DikauycRcoHl0hWjHIN3XhsN20dEq+CaIJoq37aCg5NSSSpmkET+ShA==} - - '@react-native-community/cli-config-apple@20.2.0': - resolution: {integrity: sha512-oohr6BV2riWJ5PYjayi1u52bG3H95MwKPkJCZo9pnOlYTjifZQVkMxZ8VTuk392efh0bijVTYfxH8iJPi97SIQ==} - - '@react-native-community/cli-config@20.2.0': - resolution: {integrity: sha512-GF5FxgDfOSLPi/bSiE/xvOGELwzV2GLQnDED+7ArbPi01W1Vu+hD/m+J+bwX34Pocpo767eXAVxc2h9WFUTUfQ==} - - '@react-native-community/cli-doctor@20.2.0': - resolution: {integrity: sha512-eZjlwmjPoBXgyD6nV5oDDocL1VH5UW4LxZcMAqyN3rQw5vq3CeJikFpNedKTtSl3P6JizIkInyIHpfrW+9qfJA==} - - '@react-native-community/cli-platform-android@20.2.0': - resolution: {integrity: sha512-fRglzcf/Yq5lnIkqdA8uf1GvlG18x3Dm48Yvo+l7KiWgh/SVtfVhfvalrtX5rmx+KeJkDA534bGoPvi5+ruWjw==} - - '@react-native-community/cli-platform-apple@20.2.0': - resolution: {integrity: sha512-jkEPLAd8C/ZRu39a3nhxwSXe0iisUiJC808GExnrnTcViLtg3sad2ciQ/HjjvbdsPCS9sT+Jr7xh3MzBsPojsQ==} - - '@react-native-community/cli-platform-ios@20.2.0': - resolution: {integrity: sha512-bCKlBt2HoD7WTl/HX60+4HFhR1lKY64Y9MPWu7yWQwOCEqYRMi6MkRxLimiONj9M2/lNf0z9BPHDzdDe5HM2ag==} - - '@react-native-community/cli-server-api@20.2.0': - resolution: {integrity: sha512-AI1fsl+6LNuOoDcdWsnF3s9ozqminGCUlbFcrgdZIJWyOuFBeQclNydI22VO3vWaO4dHQkfVa3Zo10AncWQvwA==} - - '@react-native-community/cli-tools@20.2.0': - resolution: {integrity: sha512-A5W2nqlTidPzGyXzS57jvHsMpQd8iOGSjePj4H318uMbhIdeIHQ5e59fNbdHahS62ISs+2p9s78sVHMbGVa1bg==} - - '@react-native-community/cli-types@20.2.0': - resolution: {integrity: sha512-K60zY/ly8G9rGJQzZ+bFRyLEckAUzyF8Fu9a2Kw6JipCrOl7SiVRBVqjvOr/XnCRKuOpH8i9y7RVg07wkSGRBQ==} - - '@react-native-community/cli@20.2.0': - resolution: {integrity: sha512-5RZKkBeUFC4hhrzySzxWmRJwXBTc2PE3L6QUgvnJk3QDxNYMY7aGuI8Gr9eZRS1DbiY10IPWqpJfqSIplzVG6A==} - engines: {node: '>=20.19.4'} - hasBin: true - - '@react-native/assets-registry@0.85.3': - resolution: {integrity: sha512-u9ZiYP23vA2IFtdFQFmetzSmk6SM0xgKIoiOsr1hXNHjHaLhOm+/Ph1ud57wX6+Dbwdzx8coJgnzSKL3W21PCg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/babel-plugin-codegen@0.85.3': - resolution: {integrity: sha512-Wc94zGfeFG8Njf9SHMPfYZP04kjigkOps6F1TYTvd7ZVXuGxqseCDgxc50LWcOhOCLypI9n3oVVqz81C3p44ZA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/babel-preset@0.85.3': - resolution: {integrity: sha512-fD7fxEhkJB/aF57tWoXjaAWpklfrExYZS3k6aXPP3BQ77DZY7gvf/b7dbirwjID6NVnP1JDRJyTuPBGr0K/vlw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/codegen@0.85.3': - resolution: {integrity: sha512-/JkS1lGLyzBWP1FbgDwaqEf7qShIC6pUC1M0a/YMAd/v4iqR24MRkQWe7jkYvcBQ2LpEhs5NGE9InhxSv21zCA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/community-cli-plugin@0.85.3': - resolution: {integrity: sha512-fs85dmbIqNmtzEixDb0g+q6R3Vt4H9eAt8/inIZdDKfjN76+sUJA2r1nxODQ76bU23MrIbz8sI7KFBPaWk/zQw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - peerDependencies: - '@react-native-community/cli': '*' - '@react-native/metro-config': 0.85.3 - peerDependenciesMeta: - '@react-native-community/cli': - optional: true - '@react-native/metro-config': - optional: true - - '@react-native/debugger-frontend@0.85.3': - resolution: {integrity: sha512-uAu7rM5o/Np1zgp6fi5zM1sP1aB8DcS7DdOLcj/TkSutOAjkMqqd2lWt1/+3S7qXexRHVK5XcP+o3VXo4L/V0A==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/debugger-shell@0.85.3': - resolution: {integrity: sha512-/jRAaT9boiCttIcEwS02WPwYkUihqsjSaK/TMtHz05vT6uMgac9PaQt5kzBQLIABv5aEIa5gtrMmKVz49MjkjQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/dev-middleware@0.85.3': - resolution: {integrity: sha512-JYzBiT4A8w+KQt+dOD5v+ti+tDrGoPnsSTuApq3Ls4RB5sfWbDlYMyz3dbc8qBIHz9tv0sQ5+eOu6Xwqzr5AQA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/gradle-plugin@0.85.3': - resolution: {integrity: sha512-39dY2j50Q1pntejzwt3XL7vwXtrj8jcIfHq6E+gyu3jzYxZJVvMkMutQ39vSg6zinIQOX36oQDhidXUbCXzgoA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/js-polyfills@0.85.3': - resolution: {integrity: sha512-U2+aMshIXf1uFn77tpBb/xhHWB9vkVrMpt7kkucAugF8hJKYTDGB587X7WwelHduK2KBfhl4giSv0rzZGoef9A==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/metro-babel-transformer@0.85.3': - resolution: {integrity: sha512-omuKq+r7jM4XvCMIlNMPP7Up3SyB8o5EAdZtF7YXniKyq7UOMBqhYHFqgsdOXr0lT+3ADf7VCJG3sb82jlBrrQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/metro-config@0.85.3': - resolution: {integrity: sha512-sVo6HepUmCcpdfozEf91lA0FjpLNNZYu/Zi9FiYiAQTK8pzATXDVTqhvdxpFrQn435p5eUTSbllvbH/KN+bnyA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - '@react-native/normalize-colors@0.74.89': - resolution: {integrity: sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==} - - '@react-native/normalize-colors@0.85.3': - resolution: {integrity: sha512-hj0PScZEhIbcOvQV5yMKX3ha4XEIOy/SVE1Rrpp0beW0dpNLOgSC7KDxGewmDnIHK9YdQUXGY9eMEfShUMIaZw==} - - '@react-native/typescript-config@0.85.3': - resolution: {integrity: sha512-F2Ign3lv/99R5HMDiaQE6NpRdopn87VuXgfHABSk0iwzouLFk1fcwaMkJUmjhnxrQagsUwxOWp4WTPwEvRRazQ==} - - '@react-native/virtualized-lists@0.85.3': - resolution: {integrity: sha512-dsCjI//OIPEUJMyNHp4l7zNLVjCx7bcaRUceOCkU+IB17hkbtbGWvi7HjGFSzy7FJGmS/MOlcfpb72xXiy1Oig==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - peerDependencies: - '@types/react': ^19.2.0 - react: '*' - react-native: 0.85.3 - peerDependenciesMeta: - '@types/react': - optional: true - - '@rollup/rollup-android-arm-eabi@4.60.4': - resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.60.4': - resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.60.4': - resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.60.4': - resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.60.4': - resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.60.4': - resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': - resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm-musleabihf@4.60.4': - resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.60.4': - resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm64-musl@4.60.4': - resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-loong64-gnu@4.60.4': - resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loong64-musl@4.60.4': - resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-ppc64-gnu@4.60.4': - resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-ppc64-musl@4.60.4': - resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} - cpu: [ppc64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-gnu@4.60.4': - resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-musl@4.60.4': - resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-s390x-gnu@4.60.4': - resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.60.4': - resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-musl@4.60.4': - resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rollup/rollup-openbsd-x64@4.60.4': - resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.60.4': - resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.60.4': - resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.60.4': - resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.60.4': - resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.60.4': - resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} - cpu: [x64] - os: [win32] - - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@shikijs/core@4.1.0': - resolution: {integrity: sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ==} - engines: {node: '>=20'} - - '@shikijs/engine-javascript@4.1.0': - resolution: {integrity: sha512-YquhawCUgaBfhsS72e2Y/dI59gCBNPHu3fEO/tvLaXrTssxZrY5ddjtNLTwndrMgPo8b3IscE+xoICDzpTmlFQ==} - engines: {node: '>=20'} - - '@shikijs/engine-oniguruma@3.23.0': - resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} - - '@shikijs/engine-oniguruma@4.1.0': - resolution: {integrity: sha512-axLpjVs45YBvvINa+dJF+NPW+KtFkNXsFr4SDw2BMj9GdeMnGxVB9PQb2xXlJYovslt/nz6giedAyOANkfc7hg==} - engines: {node: '>=20'} - - '@shikijs/langs@3.23.0': - resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} - - '@shikijs/langs@4.1.0': - resolution: {integrity: sha512-nwOMruEkbgdZfQ/b8CgpNBVOpvG1k0N5tbmgiFeqsan401+x3ILqlzZJowSla4Agmq4hG2Uf2wh5jLTEhR8VSg==} - engines: {node: '>=20'} - - '@shikijs/primitive@4.1.0': - resolution: {integrity: sha512-zx2/2Uwj2q9X3KSyYREEhXO23xBw5WUhP4orK2lE4r+t9JGITmEe0JH+wPmJhqHpOT2bRRs6lAL945+LDvOAGw==} - engines: {node: '>=20'} - - '@shikijs/themes@3.23.0': - resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} - - '@shikijs/themes@4.1.0': - resolution: {integrity: sha512-emCcTnUM7yO2wltYbaxm+yLvcCI4+h8XBKc4KmJ7EZUXoSGjcCHifkI//R4OFit9ewpg7H2/9tjOuXrT2v/Knw==} - engines: {node: '>=20'} - - '@shikijs/types@3.23.0': - resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} - - '@shikijs/types@4.1.0': - resolution: {integrity: sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==} - engines: {node: '>=20'} - - '@shikijs/vscode-textmate@10.0.2': - resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - - '@sideway/address@4.1.5': - resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} - - '@sideway/formula@3.0.1': - resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} - - '@sideway/pinpoint@2.0.0': - resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} - - '@sinclair/typebox@0.27.10': - resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} - - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - - '@tailwindcss/node@4.3.0': - resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} - - '@tailwindcss/oxide-android-arm64@4.3.0': - resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.3.0': - resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.3.0': - resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.3.0': - resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': - resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': - resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-arm64-musl@4.3.0': - resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-linux-x64-gnu@4.3.0': - resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-x64-musl@4.3.0': - resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-wasm32-wasi@4.3.0': - resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': - resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.3.0': - resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.3.0': - resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} - engines: {node: '>= 20'} - - '@tailwindcss/postcss@4.3.0': - resolution: {integrity: sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==} - - '@tybys/wasm-util@0.10.2': - resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/debug@4.1.13': - resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - - '@types/estree-jsx@1.0.5': - resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - - '@types/istanbul-lib-coverage@2.0.6': - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - - '@types/istanbul-lib-report@3.0.3': - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - - '@types/istanbul-reports@3.0.4': - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - - '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - - '@types/mdx@2.0.13': - resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} - - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/node@22.19.19': - resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} - - '@types/node@24.12.4': - resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==} - - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.16': - resolution: {integrity: sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==} - - '@types/unist@2.0.11': - resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} - - '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - - '@types/yargs-parser@21.0.3': - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - - '@types/yargs@17.0.35': - resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - - '@typescript-eslint/eslint-plugin@8.59.4': - resolution: {integrity: sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.59.4 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/parser@8.59.4': - resolution: {integrity: sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/project-service@8.59.4': - resolution: {integrity: sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/scope-manager@8.59.4': - resolution: {integrity: sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.59.4': - resolution: {integrity: sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/type-utils@8.59.4': - resolution: {integrity: sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/types@8.59.4': - resolution: {integrity: sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.59.4': - resolution: {integrity: sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/utils@8.59.4': - resolution: {integrity: sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - '@typescript-eslint/visitor-keys@8.59.4': - resolution: {integrity: sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@ungap/structured-clone@1.3.1': - resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} - - '@unrs/resolver-binding-android-arm-eabi@1.12.2': - resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} - cpu: [arm] - os: [android] - - '@unrs/resolver-binding-android-arm64@1.12.2': - resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} - cpu: [arm64] - os: [android] - - '@unrs/resolver-binding-darwin-arm64@1.12.2': - resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} - cpu: [arm64] - os: [darwin] - - '@unrs/resolver-binding-darwin-x64@1.12.2': - resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} - cpu: [x64] - os: [darwin] - - '@unrs/resolver-binding-freebsd-x64@1.12.2': - resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} - cpu: [x64] - os: [freebsd] - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': - resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': - resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': - resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-arm64-musl@1.12.2': - resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': - resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-loong64-musl@1.12.2': - resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': - resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': - resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': - resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': - resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-x64-gnu@1.12.2': - resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@unrs/resolver-binding-linux-x64-musl@1.12.2': - resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@unrs/resolver-binding-openharmony-arm64@1.12.2': - resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} - cpu: [arm64] - os: [openharmony] - - '@unrs/resolver-binding-wasm32-wasi@1.12.2': - resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': - resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} - cpu: [arm64] - os: [win32] - - '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': - resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} - cpu: [ia32] - os: [win32] - - '@unrs/resolver-binding-win32-x64-msvc@1.12.2': - resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} - cpu: [x64] - os: [win32] - - '@vitest/coverage-v8@4.1.8': - resolution: {integrity: sha512-lt3kovsyHwYe00wq4D1ti0Z974fWj4NLp6siqiyEufUpyFwK9Yhi7rBhac9JL5aA0zoMrJqc4vYPZRUnI7l7nw==} - peerDependencies: - '@vitest/browser': 4.1.8 - vitest: 4.1.8 - peerDependenciesMeta: - '@vitest/browser': - optional: true - - '@vitest/expect@4.1.8': - resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} - - '@vitest/mocker@4.1.8': - resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} - peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@4.1.8': - resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} - - '@vitest/runner@4.1.8': - resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} - - '@vitest/snapshot@4.1.8': - resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} - - '@vitest/spy@4.1.8': - resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} - - '@vitest/utils@4.1.8': - resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} - - '@vscode/sudo-prompt@9.3.2': - resolution: {integrity: sha512-gcXoCN00METUNFeQOFJ+C9xUI0DKB+0EGMVg7wbVYRHBw2Eq3fKisDZOkRdOz3kqXRKOENMfShPOmypw1/8nOw==} - - '@xmldom/xmldom@0.8.13': - resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} - engines: {node: '>=10.0.0'} - deprecated: this version has critical issues, please update to the latest version - - '@xmldom/xmldom@0.9.10': - resolution: {integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==} - engines: {node: '>=14.6'} - deprecated: this version has critical issues, please update to the latest version - - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} - - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} - - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - agent-cli-detector@0.1.2: - resolution: {integrity: sha512-qdZ/9JFORtTKJNhT/IczMeEfEUbUU0K5umYeiIQHX+AjHs+Y9SXVzSgaYlpZeyNMrvuh2HpZiOTpvS57iPfBkQ==} - engines: {node: '>=18.18'} - hasBin: true - - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - - anser@1.4.10: - resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} - - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - - ansi-fragments@0.2.1: - resolution: {integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==} - - ansi-regex@4.1.1: - resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} - engines: {node: '>=6'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - anynum@1.0.1: - resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} - - appdirsjs@1.2.8: - resolution: {integrity: sha512-8zl1xlxeS4a0/36CT6LOaVioPOL8TeLT1b9OHk0j9xSbzmPBuM7lUgWMSTh6SbuF8fbwjcP1rr30OCLpd1fl+A==} - - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} - - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} - - array-includes@3.1.9: - resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} - engines: {node: '>= 0.4'} - - array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} - - array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} - - array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} - - array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} - - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} - - asap@2.0.6: - resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - ast-v8-to-istanbul@1.0.3: - resolution: {integrity: sha512-jCMQ6ZylLPudp0CDfBmQBZUsrh1/8psbmu9ibeVWKuHWD0YrH9YABwlKu5kVEFoT0GCQQW9Z/SxfuEbbkGQCRg==} - - astral-regex@1.0.0: - resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} - engines: {node: '>=4'} - - astring@1.9.0: - resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} - hasBin: true - - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} - - async-limiter@1.0.1: - resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - await-lock@2.2.2: - resolution: {integrity: sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==} - - babel-plugin-polyfill-corejs2@0.4.17: - resolution: {integrity: sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - babel-plugin-polyfill-corejs3@0.13.0: - resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - babel-plugin-polyfill-regenerator@0.6.8: - resolution: {integrity: sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - babel-plugin-react-compiler@1.0.0: - resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} - - babel-plugin-react-native-web@0.21.2: - resolution: {integrity: sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA==} - - babel-plugin-syntax-hermes-parser@0.33.3: - resolution: {integrity: sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==} - - babel-plugin-transform-flow-enums@0.0.2: - resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} - - babel-preset-expo@56.0.17: - resolution: {integrity: sha512-yanAlbzaMMNqnju/uMnZsf3ltgssG71UubkfD+2iMaoXGNIj+TODEs9hF12jrTX2lzq/zH0HWSuRLZLNalf8fw==} - peerDependencies: - '@babel/runtime': ^7.20.0 - expo: '*' - expo-widgets: ^56.0.22 - react-refresh: '>=0.14.0 <1.0.0' - peerDependenciesMeta: - '@babel/runtime': - optional: true - expo: - optional: true - expo-widgets: - optional: true - - bail@2.0.2: - resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - baseline-browser-mapping@2.10.32: - resolution: {integrity: sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==} - engines: {node: '>=6.0.0'} - hasBin: true - - big-integer@1.6.52: - resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} - engines: {node: '>=0.6'} - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} - engines: {node: '>=18'} - - bplist-creator@0.1.0: - resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} - - bplist-parser@0.3.1: - resolution: {integrity: sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==} - engines: {node: '>= 5.10.0'} - - bplist-parser@0.3.2: - resolution: {integrity: sha512-apC2+fspHGI3mMKj+dGevkGo/tCqVB8jMb6i+OX+E29p0Iposz07fABkRIfVUPNd5A5VbuOz1bZbnmkKLYF+wQ==} - engines: {node: '>= 5.10.0'} - - brace-expansion@1.1.14: - resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.9: - resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - - caniuse-lite@1.0.30001793: - resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} - - ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} - engines: {node: '>=18'} - - chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - - character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - - character-entities@2.0.2: - resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - - character-reference-invalid@2.0.1: - resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} - - chokidar@5.0.0: - resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} - engines: {node: '>= 20.19.0'} - - chrome-launcher@0.15.2: - resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} - engines: {node: '>=12.13.0'} - hasBin: true - - chromium-edge-launcher@0.3.0: - resolution: {integrity: sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==} - - ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} - - cli-cursor@2.1.0: - resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} - engines: {node: '>=4'} - - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} - - cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - - collapse-white-space@2.1.0: - resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} - - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - colorette@1.4.0: - resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - - comma-separated-tokens@2.0.3: - resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - - command-exists@1.2.9: - resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} - - commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} - engines: {node: '>=18'} - - commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - - commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} - - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - - compressible@2.0.18: - resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} - engines: {node: '>= 0.6'} - - compression@1.8.1: - resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} - engines: {node: '>= 0.8.0'} - - compute-scroll-into-view@3.1.1: - resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - connect@3.7.0: - resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} - engines: {node: '>= 0.10.0'} - - content-disposition@1.1.0: - resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} - engines: {node: '>=18'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - content-type@2.0.0: - resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} - engines: {node: '>=18'} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - core-js-compat@3.49.0: - resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} - - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} - - cosmiconfig@9.0.2: - resolution: {integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true - - cross-fetch@3.2.0: - resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - css-in-js-utils@3.1.0: - resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} - - data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} - - dayjs@1.11.21: - resolution: {integrity: sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==} - - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - - decode-named-character-reference@1.3.0: - resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - - devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - - dnssd-advertise@1.1.6: - resolution: {integrity: sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg==} - - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - electron-to-chromium@1.5.361: - resolution: {integrity: sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - enhanced-resolve@5.22.1: - resolution: {integrity: sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==} - engines: {node: '>=10.13.0'} - - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} - - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - - envinfo@7.21.0: - resolution: {integrity: sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==} - engines: {node: '>=4'} - hasBin: true - - error-ex@1.3.4: - resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - - error-stack-parser@2.1.4: - resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - - errorhandler@1.5.2: - resolution: {integrity: sha512-kNAL7hESndBCrWwS72QyV3IVOTrVmj9D062FV5BQswNL5zEdeRmz/WJFyh6Aj/plvvSOrzddkxW57HgkZcR9Fw==} - engines: {node: '>= 0.8'} - - es-abstract@1.24.2: - resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} - engines: {node: '>= 0.4'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-iterator-helpers@1.3.2: - resolution: {integrity: sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==} - engines: {node: '>= 0.4'} - - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - - es-object-atoms@1.1.2: - resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} - engines: {node: '>= 0.4'} - - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} - - esast-util-from-estree@2.0.0: - resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} - - esast-util-from-js@2.0.1: - resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} - - esbuild@0.28.1: - resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - - eslint-config-expo@56.0.4: - resolution: {integrity: sha512-1OD7rJMxCchKHxq+U+OQsAxVtzAxeUb9875g6+15KsSD9fqKTgq7DEEWYwunzU9r9E8kYJ+mh7+j86vF9m9NMw==} - peerDependencies: - eslint: '>=8.10' - - eslint-import-resolver-node@0.3.10: - resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} - - eslint-import-resolver-typescript@3.10.1: - resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - eslint-plugin-import-x: '*' - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true - - eslint-module-utils@2.12.1: - resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-expo@1.0.3: - resolution: {integrity: sha512-C1v9NPvpDET36+7Klpp/+53Jl+VzOfpbDxpKtL/pAPhCDwTX0kW6Swo425PT0uc4AMT5jpQbB7hSKFjKOGMl4A==} - engines: {node: '>=18.0.0'} - peerDependencies: - eslint: '>=8.10' - - eslint-plugin-import@2.32.0: - resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - - eslint-plugin-react-hooks@7.1.1: - resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 - - eslint-plugin-react@7.37.5: - resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@5.0.1: - resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@9.39.4: - resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-util-attach-comments@3.0.0: - resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} - - estree-util-build-jsx@3.0.1: - resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} - - estree-util-is-identifier-name@3.0.0: - resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} - - estree-util-scope@1.0.0: - resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==} - - estree-util-to-js@2.0.0: - resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} - - estree-util-value-to-estree@3.5.0: - resolution: {integrity: sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==} - - estree-util-visit@2.0.0: - resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} - - eventsource-parser@3.0.8: - resolution: {integrity: sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==} - engines: {node: '>=18.0.0'} - - eventsource@3.0.7: - resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} - engines: {node: '>=18.0.0'} - - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} - - expo-asset@56.0.19: - resolution: {integrity: sha512-huGY0bVfYUivNOir+iUEjjW9IbNHzLFNo8d6FGh22u1OsXcFR7Za3vpu5V1gMp0dc31wiqmsXkTazjm+Rro3vA==} - peerDependencies: - expo: '*' - react: '*' - react-native: '*' - - expo-constants@56.0.20: - resolution: {integrity: sha512-4HgoVvUiMvcqujr/CUj7L1tumLWj8WX0PLM77OriDPoaJrMEwUHd841m4o4IoUyMPVT8XTiTiPFwJtGali8+9Q==} - peerDependencies: - expo: '*' - react-native: '*' - - expo-dev-client@56.0.22: - resolution: {integrity: sha512-LKhgIlMu8DkmhTtfurpX9YMPsnv4QI1hCcDZqcFn+jlB+s6yE1THB9UWZ+BVtef8kYMzsw+BH3ClXvNkRd0vXw==} - peerDependencies: - expo: '*' - - expo-dev-launcher@56.0.23: - resolution: {integrity: sha512-OKgLAn6m15Lu+Qyg8WA0HPurFR9pxhsrHUvvafv8pTZHspB0BbOvBwhOJdxgiMfR2LHq4032cnMf8164Vzqeng==} - peerDependencies: - expo: '*' - react-native: '*' - - expo-dev-menu-interface@56.0.1: - resolution: {integrity: sha512-odATx0ZL/Kis10sKSBiKiGQxAB6coSi/KQtKcMhnQVNno6FkRh5/4e5BqcEvpq2rNMTiQp4ytNAQHtdwbPXvGA==} - peerDependencies: - expo: '*' - - expo-dev-menu@56.0.19: - resolution: {integrity: sha512-sm6dfnkq3lgbn39Kd4yjFFm7UQAZqm6Hn3OpjagGtWBoWByQae3nKh1MF5K4Peh172TqUPJTOhjRasnZSkUkOQ==} - peerDependencies: - expo: '*' - react-native: '*' - - expo-doctor@1.19.8: - resolution: {integrity: sha512-ZHpQM+BfJe1DNaA+/ObtLYazC2x78tIV3kkfoSGR46Tj1EvzOFh1p9gFHsILI9TOyXPEcgxCkFw9AVvf8C4c1g==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - hasBin: true - - expo-file-system@56.0.8: - resolution: {integrity: sha512-NrH41/8snGIBSbYicwVLB4txPdgCATd7ZYhMAGS3YJZ9GbnduhlAoV4/YCbGayjrbpE9bJb/6wegPL/zmvRMnQ==} - peerDependencies: - expo: '*' - react-native: '*' - - expo-font@56.0.7: - resolution: {integrity: sha512-hpU/vRwPzsby9lPGkA4blDqLIIXYzoWnCZHr6PxvcWbY/uPObAiyhh6q+e0WYsB65SthK+PLH95jEnVag7fwEg==} - peerDependencies: - expo: '*' - react: '*' - react-native: '*' - - expo-json-utils@56.0.0: - resolution: {integrity: sha512-lUqyv9aIGDbYTQ5Nux2FnH2/Dz0w5uJ8Pr080eS0StXi2jr5OmuMNErpzUnpfnYOU55xKotd4AHv68PfV/ludg==} - - expo-keep-awake@56.0.3: - resolution: {integrity: sha512-CLMJXtEiMKknD3Rpm8CRwE6ZJUzu2yCEmRk1sgfHAJ1zIbuEWY3dpPDubtsnuzWm+2k6Sru+yaFbYsvPWmTiBA==} - peerDependencies: - expo: '*' - react: '*' - - expo-manifests@56.0.4: - resolution: {integrity: sha512-Fokawl2UkiExIF0bqGoblRFA8lYpROVD+EpvDwSW4LgqQyPwNua1gLSgHZjdl5GsVugfRMMWE3LHaibDyX93hw==} - peerDependencies: - expo: '*' - - expo-mcp@0.2.4: - resolution: {integrity: sha512-rBomlm+085wNa+UF9YC3bXGZR6LlYPfOlUXwKBB5R7+dnASk0VjWFETuxyApdtXw9OItmOsAXolUxrAlEYfqSA==} - hasBin: true - - expo-modules-autolinking@56.0.19: - resolution: {integrity: sha512-ztzTzS21fbq4oJQItSgT+WWJMZXGsC0GdX/cDN/GBhCTPiZz8foHkVa14DiLa5CWd7pEZ9EeSMdHDcAEc2dZ5Q==} - hasBin: true - - expo-modules-core@56.0.20: - resolution: {integrity: sha512-Xagwt/gC6sV1jiSnlFrYxLooZr90adLrpV64YlkXZjgZ6Kot89FF62e457RyejLtyDm2pOdy6FZphF1ReyK2Jw==} - peerDependencies: - react: '*' - react-native: '*' - react-native-worklets: ^0.7.4 || ^0.8.0 - peerDependenciesMeta: - react-native-worklets: - optional: true - - expo-modules-jsi@56.0.12: - resolution: {integrity: sha512-OnXiNbXzYybZPh5QnJyIIwQjQfN7PP4Di/2Hz0xQHKLgQmCfn/zAQziOjbUXVeL3cAyZ8+uDnTDYmDAc3B2qhQ==} - peerDependencies: - react-native: '*' - - expo-server@56.0.5: - resolution: {integrity: sha512-SmM2p2g3Jrktpiazcst+OxhjSzOHXKAY4BPURHYHXvApzzoybMmrNF4IEZ8DKZ145BhSe4ydAmlEFCRTsdtgUQ==} - engines: {node: '>=20.16.0'} - - expo-splash-screen@56.0.12: - resolution: {integrity: sha512-RvEtJ78aNpuxdVD8TCe9viKtlYGzS9hW20fbvqvkeXDN6WAaYo1CRitPdjWNkaNNSPKOolp3zfha4EGdhXOtxg==} - peerDependencies: - expo: '*' - - expo-sqlite@56.0.5: - resolution: {integrity: sha512-wHYRVLS5nUFEtli45wHaO+RjlRY8sQXyOSgENVk6I4zq7+FgySqjOk3YOYW6IKIMwhj5XzjMJO+pY8xKUy73Kw==} - peerDependencies: - expo: '*' - react: '*' - react-native: '*' - - expo-system-ui@56.0.5: - resolution: {integrity: sha512-n1MmnUArV4cc3gVed9fGtluPme00PE9axKVx+NHbKxHFMam5l4GcOI7PxbYKFNx8o7WA1LRD7eLW33agmZrxGg==} - peerDependencies: - expo: '*' - react-native: '*' - react-native-web: '*' - peerDependenciesMeta: - react-native-web: - optional: true - - expo-updates-interface@56.0.2: - resolution: {integrity: sha512-eWTwSZ9y8vrULG2oBn2TQSSIwBGSq/TxGJ3jY6tuVS2FWH/ASRIiKs3zkUZTRoC3ZuV2alz0mUClYV7nNrFx8g==} - peerDependencies: - expo: '*' - - expo@56.0.15: - resolution: {integrity: sha512-Tnas9Sq1fDY865rhSQ4266Kd4GULEUyBEBEchbNLQsiY6U+AAt4MgCKJUsRvUkNHdaZwnGzexy6hdnOjsgvNcA==} - hasBin: true - peerDependencies: - '@expo/metro-runtime': '*' - react: '*' - react-dom: '*' - react-native: '*' - react-native-web: '*' - react-native-webview: '*' - peerDependenciesMeta: - '@expo/metro-runtime': - optional: true - react-dom: - optional: true - react-native-web: - optional: true - react-native-webview: - optional: true - - exponential-backoff@3.1.3: - resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} - - express-rate-limit@8.5.2: - resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} - engines: {node: '>= 16'} - peerDependencies: - express: '>= 4.11' - - express@5.2.1: - resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} - engines: {node: '>= 18'} - - extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - - fast-xml-builder@1.3.0: - resolution: {integrity: sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==} - - fast-xml-parser@5.10.1: - resolution: {integrity: sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==} - hasBin: true - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - - fb-dotslash@0.5.8: - resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} - engines: {node: '>=20'} - hasBin: true - - fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - - fbjs-css-vars@1.0.2: - resolution: {integrity: sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==} - - fbjs@3.0.5: - resolution: {integrity: sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - fetch-nodeshim@0.4.10: - resolution: {integrity: sha512-m6I8ALe4L4XpdETy7MJZWs6L1IVMbjs99bwbpIKphxX+0CTns4IKDWJY0LWfr4YsFjfg+z1TjzTMU8lKl8rG0w==} - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - finalhandler@1.1.2: - resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} - engines: {node: '>= 0.8'} - - finalhandler@2.1.1: - resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} - engines: {node: '>= 18.0.0'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - flow-enums-runtime@0.0.6: - resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} - - fontfaceobserver@2.3.0: - resolution: {integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==} - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - framer-motion@12.40.0: - resolution: {integrity: sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==} - peerDependencies: - '@emotion/is-prop-valid': '*' - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true - react: - optional: true - react-dom: - optional: true - - framer-motion@13.1.0: - resolution: {integrity: sha512-QSZrF0Id3QGuHJ+OL+9PSY9pk86C8ERFalwAGSchzTm65+ZoGH/RM26lmEARLljcHj2lqhv0jZOOks+EI3COOw==} - peerDependencies: - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - fumadocs-core@16.9.3: - resolution: {integrity: sha512-8RVzKnzBJR5o+tJCccY28ntekfMQYBoYiz7alnYb/d9YJc+XpnsINzTl63lQ1eBMZ9gdhm2MqRtgUjh/8rUrbw==} - peerDependencies: - '@mdx-js/mdx': '*' - '@mixedbread/sdk': 0.x.x - '@orama/core': 1.x.x - '@oramacloud/client': 2.x.x - '@tanstack/react-router': 1.x.x - '@types/estree-jsx': '*' - '@types/hast': '*' - '@types/mdast': '*' - '@types/react': '*' - algoliasearch: 5.x.x - flexsearch: '*' - lucide-react: '*' - next: 16.x.x - react: ^19.2.0 - react-dom: ^19.2.0 - react-router: 7.x.x - waku: '*' - zod: 4.x.x - peerDependenciesMeta: - '@mdx-js/mdx': - optional: true - '@mixedbread/sdk': - optional: true - '@orama/core': - optional: true - '@oramacloud/client': - optional: true - '@tanstack/react-router': - optional: true - '@types/estree-jsx': - optional: true - '@types/hast': - optional: true - '@types/mdast': - optional: true - '@types/react': - optional: true - algoliasearch: - optional: true - flexsearch: - optional: true - lucide-react: - optional: true - next: - optional: true - react: - optional: true - react-dom: - optional: true - react-router: - optional: true - waku: - optional: true - zod: - optional: true - - fumadocs-mdx@15.0.10: - resolution: {integrity: sha512-kH3S7ESS9yXTAaCkA8dDugsCK/MbnpgyZ5qBEL7cWoavV0O/T4+4YTYFkvNknz7cw+T/r+OG0p2BvlVhkk4fww==} - hasBin: true - peerDependencies: - '@types/mdast': '*' - '@types/mdx': '*' - '@types/react': '*' - fumadocs-core: ^16.7.0 - mdast-util-directive: '*' - next: ^15.3.0 || ^16.0.0 - react: ^19.2.0 - rolldown: '*' - vite: 7.x.x || 8.x.x - peerDependenciesMeta: - '@types/mdast': - optional: true - '@types/mdx': - optional: true - '@types/react': - optional: true - mdast-util-directive: - optional: true - next: - optional: true - react: - optional: true - rolldown: - optional: true - vite: - optional: true - - fumadocs-ui@16.9.3: - resolution: {integrity: sha512-eoVKj1H+ATut0su+WIoPWBLRqzPMGD0hekIBr4GopWvUg1lS997HL4kP+Leyf+3CYlZtFgyXb6ylbvRLFtEj6Q==} - peerDependencies: - '@takumi-rs/image-response': '*' - '@types/mdx': '*' - '@types/react': '*' - fumadocs-core: 16.9.3 - next: 16.x.x - react: ^19.2.0 - react-dom: ^19.2.0 - peerDependenciesMeta: - '@takumi-rs/image-response': - optional: true - '@types/mdx': - optional: true - '@types/react': - optional: true - next: - optional: true - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - - fzstd@0.1.1: - resolution: {integrity: sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA==} - - generator-function@2.0.1: - resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} - engines: {node: '>= 0.4'} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - - get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} - - get-tsconfig@4.14.0: - resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} - - getenv@2.0.0: - resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} - engines: {node: '>=6'} - - github-slugger@2.0.0: - resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@11.1.0: - resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} - engines: {node: 20 || >=22} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - - glob@13.0.6: - resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} - engines: {node: 18 || 20 || >=22} - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@16.5.0: - resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} - engines: {node: '>=18'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} - - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} - engines: {node: '>= 0.4'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.3: - resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} - engines: {node: '>= 0.4'} - - hast-util-from-parse5@8.0.3: - resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} - - hast-util-parse-selector@4.0.0: - resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - - hast-util-raw@9.1.0: - resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} - - hast-util-to-estree@3.1.3: - resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} - - hast-util-to-html@9.0.5: - resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} - - hast-util-to-jsx-runtime@2.3.6: - resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} - - hast-util-to-parse5@8.0.1: - resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} - - hast-util-whitespace@3.0.0: - resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - - hastscript@9.0.1: - resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} - - hermes-compiler@250829098.0.10: - resolution: {integrity: sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w==} - - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - - hermes-estree@0.33.3: - resolution: {integrity: sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==} - - hermes-estree@0.35.0: - resolution: {integrity: sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==} - - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - - hermes-parser@0.33.3: - resolution: {integrity: sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==} - - hermes-parser@0.35.0: - resolution: {integrity: sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==} - - hono@4.12.22: - resolution: {integrity: sha512-7fvVPbB92zNRsQke+uiRGwtTuef0tB2Dg4hWxYfFNvkQhIltWoyi0ONReM5LWA+jJWS3nfT5lTq+qbsIpX0IQw==} - engines: {node: '>=16.9.0'} - - hosted-git-info@7.0.2: - resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} - engines: {node: ^16.14.0 || >=18.0.0} - - html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - - html-void-elements@3.0.0: - resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - - hyphenate-style-name@1.1.0: - resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} - - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - image-size@1.2.1: - resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} - engines: {node: '>=16.x'} - hasBin: true - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - inline-style-parser@0.2.7: - resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} - - inline-style-prefixer@7.0.1: - resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==} - - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} - - invariant@2.2.4: - resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - - ip-address@10.2.0: - resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} - engines: {node: '>= 12'} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - is-alphabetical@2.0.1: - resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} - - is-alphanumerical@2.0.1: - resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} - - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} - - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} - - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} - - is-bun-module@2.0.0: - resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-core-module@2.16.2: - resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} - engines: {node: '>= 0.4'} - - is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} - - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} - - is-decimal@2.0.1: - resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - - is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} - - is-fullwidth-code-point@2.0.0: - resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} - engines: {node: '>=4'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-generator-function@1.1.2: - resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-hexadecimal@2.0.1: - resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} - - is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-plain-obj@4.1.0: - resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} - engines: {node: '>=12'} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} - - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - is-unsafe@2.0.0: - resolution: {integrity: sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} - - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} - - is-wsl@1.1.0: - resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} - engines: {node: '>=4'} - - is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - - istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} - - istanbul-reports@3.2.0: - resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} - engines: {node: '>=8'} - - iterator.prototype@1.1.5: - resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} - engines: {node: '>= 0.4'} - - jackspeak@4.2.3: - resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} - engines: {node: 20 || >=22} - - jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jimp-compact@0.16.1: - resolution: {integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==} - - jiti@2.7.0: - resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} - hasBin: true - - joi@17.13.4: - resolution: {integrity: sha512-1RuuER6kmt8K8I3nIWvPZKi5RQCb568ZPyY4Pwjlua+yo+63ZTmIwxLZH0heBmiKN4uxjvCiarDrjaeH84xicQ==} - - jose@6.2.3: - resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} - - js-tokens@10.0.0: - resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.3.0: - resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} - hasBin: true - - jsc-safe-url@0.2.4: - resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json-schema-typed@8.0.2: - resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - - jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - - lan-network@0.2.1: - resolution: {integrity: sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==} - hasBin: true - - launch-editor@2.14.1: - resolution: {integrity: sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==} - - leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - lighthouse-logger@1.4.2: - resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} - - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} - engines: {node: '>= 12.0.0'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - linkify-it@5.0.1: - resolution: {integrity: sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash.throttle@4.1.1: - resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} - - log-symbols@2.2.0: - resolution: {integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==} - engines: {node: '>=4'} - - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - - logkitty@0.7.1: - resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==} - hasBin: true - - longest-streak@3.1.0: - resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@11.5.0: - resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==} - engines: {node: 20 || >=22} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lucide-react@1.17.0: - resolution: {integrity: sha512-9FA9evdox/JQL5PT57fdA1x/yg8T7knJ98+zjTL3UfKza6pflQUUh3XtaQIHKvnsJw1lmsEyHVlt5jchYxOQ5w==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - lunr@2.3.9: - resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - magicast@0.5.3: - resolution: {integrity: sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==} - - make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} - - makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - - markdown-extensions@2.0.0: - resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} - engines: {node: '>=16'} - - markdown-it@14.2.0: - resolution: {integrity: sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==} - hasBin: true - - markdown-table@3.0.4: - resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - - marky@1.3.0: - resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mdast-util-find-and-replace@3.0.2: - resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - - mdast-util-from-markdown@2.0.3: - resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} - - mdast-util-gfm-autolink-literal@2.0.1: - resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} - - mdast-util-gfm-footnote@2.1.0: - resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} - - mdast-util-gfm-strikethrough@2.0.0: - resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} - - mdast-util-gfm-table@2.0.0: - resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} - - mdast-util-gfm-task-list-item@2.0.0: - resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} - - mdast-util-gfm@3.1.0: - resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} - - mdast-util-mdx-expression@2.0.1: - resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} - - mdast-util-mdx-jsx@3.2.0: - resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} - - mdast-util-mdx@3.0.0: - resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} - - mdast-util-mdxjs-esm@2.0.1: - resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} - - mdast-util-phrasing@4.1.0: - resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} - - mdast-util-to-hast@13.2.1: - resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} - - mdast-util-to-markdown@2.1.2: - resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} - - mdast-util-to-string@4.0.0: - resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} - - mdurl@2.0.0: - resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - - memoize-one@5.2.1: - resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} - - memoize-one@6.0.0: - resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - metro-babel-transformer@0.84.4: - resolution: {integrity: sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-cache-key@0.84.4: - resolution: {integrity: sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-cache@0.84.4: - resolution: {integrity: sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-config@0.84.4: - resolution: {integrity: sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-core@0.84.4: - resolution: {integrity: sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-file-map@0.84.4: - resolution: {integrity: sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-minify-terser@0.84.4: - resolution: {integrity: sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-resolver@0.84.4: - resolution: {integrity: sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-runtime@0.84.4: - resolution: {integrity: sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-source-map@0.84.4: - resolution: {integrity: sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-symbolicate@0.84.4: - resolution: {integrity: sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - hasBin: true - - metro-transform-plugins@0.84.4: - resolution: {integrity: sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-transform-worker@0.84.4: - resolution: {integrity: sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro@0.84.4: - resolution: {integrity: sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - hasBin: true - - micromark-core-commonmark@2.0.3: - resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} - - micromark-extension-gfm-autolink-literal@2.1.0: - resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} - - micromark-extension-gfm-footnote@2.1.0: - resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} - - micromark-extension-gfm-strikethrough@2.1.0: - resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} - - micromark-extension-gfm-table@2.1.1: - resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} - - micromark-extension-gfm-tagfilter@2.0.0: - resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} - - micromark-extension-gfm-task-list-item@2.1.0: - resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} - - micromark-extension-gfm@3.0.0: - resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} - - micromark-extension-mdx-expression@3.0.1: - resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} - - micromark-extension-mdx-jsx@3.0.2: - resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} - - micromark-extension-mdx-md@2.0.0: - resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} - - micromark-extension-mdxjs-esm@3.0.0: - resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} - - micromark-extension-mdxjs@3.0.0: - resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} - - micromark-factory-destination@2.0.1: - resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} - - micromark-factory-label@2.0.1: - resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} - - micromark-factory-mdx-expression@2.0.3: - resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} - - micromark-factory-space@2.0.1: - resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} - - micromark-factory-title@2.0.1: - resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} - - micromark-factory-whitespace@2.0.1: - resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} - - micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - - micromark-util-chunked@2.0.1: - resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} - - micromark-util-classify-character@2.0.1: - resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} - - micromark-util-combine-extensions@2.0.1: - resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} - - micromark-util-decode-numeric-character-reference@2.0.2: - resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} - - micromark-util-decode-string@2.0.1: - resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} - - micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - - micromark-util-events-to-acorn@2.0.3: - resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} - - micromark-util-html-tag-name@2.0.1: - resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} - - micromark-util-normalize-identifier@2.0.1: - resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} - - micromark-util-resolve-all@2.0.1: - resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} - - micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - - micromark-util-subtokenize@2.1.0: - resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} - - micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - - micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - - micromark@4.0.2: - resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime-types@3.0.2: - resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} - engines: {node: '>=18'} - - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - - mime@2.6.0: - resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} - engines: {node: '>=4.0.0'} - hasBin: true - - mimic-fn@1.2.0: - resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} - engines: {node: '>=4'} - - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} - engines: {node: 18 || 20 || >=22} - - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@7.1.3: - resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} - engines: {node: '>=16 || 14 >=14.17'} - - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - - motion-dom@12.40.0: - resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==} - - motion-dom@13.0.0: - resolution: {integrity: sha512-Xk+SJas70uMAUIApg+m3lZDShxI3LBFHq7mFGbBKoRXc2PVPDyAKmzN64Bbzt4CZdP/CItTiJxWtn4TA0v53Ng==} - - motion-utils@12.39.0: - resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==} - - motion-utils@13.0.0: - resolution: {integrity: sha512-7DnN7TmbLcYXcG4RVadXIihWlyuM9afoUww8Y5Agg431kGKiuL2/OMyP4mJ5wLz+pvN3t5ySClLOaVXJ+wekRQ==} - - motion@12.40.0: - resolution: {integrity: sha512-yjrHUrBFW6kQvjJwRsoiPSAhC5tRwRqNGJWmiJ4CrGnbKp0V88AdzkhBmDoqIsIPfarOe0Uddd37Xq43/gIocA==} - peerDependencies: - '@emotion/is-prop-valid': '*' - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true - react: - optional: true - react-dom: - optional: true - - motion@13.1.0: - resolution: {integrity: sha512-qtvscq59uCPdWnNW4SdSkrxR+BS/QYsa923bx7ocA+4p+ZGNbbVQwkSnG4aukB81QWjtl3AxX36plxNyZLmHCA==} - peerDependencies: - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - multitars@1.0.0: - resolution: {integrity: sha512-H/J4fMLedtudftaYMOg7ajzLYgT3/rwbWVJbqr/iUgB8DQztn38ys5HOqI1CzSxx8QhXXwOOnnBvd4v3jG5+Mg==} - - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - napi-postinstall@0.3.4: - resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} - - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - - next-themes@0.4.6: - resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} - peerDependencies: - react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - - next@16.2.7: - resolution: {integrity: sha512-eMJxgjRzBaj3olkP4cBamHDXL79A8FC6u1GcsO1D1Tsx8bw/LLXUJCaoajVxtnhD3A1IJqIT8IcRJjgBIPJq4w==} - engines: {node: '>=20.9.0'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.51.1 - babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true - - nocache@3.0.4: - resolution: {integrity: sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw==} - engines: {node: '>=12.0.0'} - - node-api-headers@1.9.0: - resolution: {integrity: sha512-2oNILP4jXwRB4ywnYKjVk1YyJ96n2D4EOVJO6S3oYZ5PtbJrw3Yt9TpAuX3nBLMuzn74rnfGQrv13pS9vC+YiA==} - - node-exports-info@1.6.0: - resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} - engines: {node: '>= 0.4'} - - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-forge@1.4.0: - resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==} - engines: {node: '>= 6.13.0'} - - node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - - node-releases@2.0.46: - resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} - engines: {node: '>=18'} - - node-stream-zip@1.15.0: - resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} - engines: {node: '>=0.12.0'} - - npm-package-arg@11.0.3: - resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} - engines: {node: ^16.14.0 || >=18.0.0} - - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - - nullthrows@1.1.1: - resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} - - ob1@0.84.4: - resolution: {integrity: sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} - - object.entries@1.1.9: - resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} - engines: {node: '>= 0.4'} - - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} - - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} - - object.values@1.2.1: - resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} - engines: {node: '>= 0.4'} - - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - - on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - on-headers@1.1.0: - resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@2.0.1: - resolution: {integrity: sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==} - engines: {node: '>=4'} - - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - - oniguruma-parser@0.12.2: - resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} - - oniguruma-to-es@4.3.6: - resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} - - open@6.4.0: - resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==} - engines: {node: '>=8'} - - open@7.4.2: - resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} - engines: {node: '>=8'} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - ora@3.4.0: - resolution: {integrity: sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==} - engines: {node: '>=6'} - - ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-entities@4.0.2: - resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} - - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - - parse-png@2.1.0: - resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} - engines: {node: '>=10'} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-expression-matcher@1.6.2: - resolution: {integrity: sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==} - engines: {node: '>=14.0.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-scurry@2.0.2: - resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} - engines: {node: 18 || 20 || >=22} - - path-to-regexp@8.4.2: - resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - pkce-challenge@5.0.1: - resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} - engines: {node: '>=16.20.0'} - - plist@3.1.1: - resolution: {integrity: sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==} - engines: {node: '>=10.4.0'} - - pngjs@3.4.0: - resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} - engines: {node: '>=4.0.0'} - - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} - engines: {node: ^10 || ^12 || >=14} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - proc-log@4.2.0: - resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - - promise@7.3.1: - resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} - - promise@8.3.0: - resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} - - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - - property-information@7.1.0: - resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - punycode.js@2.3.1: - resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} - engines: {node: '>=6'} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - qs@6.15.2: - resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} - engines: {node: '>=0.6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - queue@6.0.2: - resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} - engines: {node: '>= 0.10'} - - react-devtools-core@6.1.5: - resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} - - react-dom@19.2.3: - resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} - peerDependencies: - react: ^19.2.3 - - react-dom@19.2.7: - resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} - peerDependencies: - react: ^19.2.7 - - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - react-native-safe-area-context@5.7.0: - resolution: {integrity: sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ==} - peerDependencies: - react: '*' - react-native: '*' - - react-native-web@0.21.2: - resolution: {integrity: sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==} - peerDependencies: - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - - react-native@0.85.3: - resolution: {integrity: sha512-HN/fGC+3nZVcDNcw7gfbM/DuqZAvI9Mz+/SxuhODaua4JY0BPzhfTzWXRyTR4mRgMHmShTPpH2PYMTxvZrsdZA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - hasBin: true - peerDependencies: - '@react-native/jest-preset': 0.85.3 - '@types/react': ^19.1.1 - react: ^19.2.3 - peerDependenciesMeta: - '@react-native/jest-preset': - optional: true - '@types/react': - optional: true - - react-refresh@0.14.2: - resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} - engines: {node: '>=0.10.0'} - - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.2: - resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react@19.2.3: - resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} - engines: {node: '>=0.10.0'} - - react@19.2.7: - resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} - engines: {node: '>=0.10.0'} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - readdirp@5.0.0: - resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} - engines: {node: '>= 20.19.0'} - - recma-build-jsx@1.0.0: - resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} - - recma-jsx@1.0.1: - resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - recma-parse@1.0.0: - resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} - - recma-stringify@1.0.0: - resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} - - reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} - - regenerate-unicode-properties@10.2.2: - resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} - engines: {node: '>=4'} - - regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} - - regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - - regex-recursion@6.0.2: - resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} - - regex-utilities@2.3.0: - resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - - regex@6.1.0: - resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} - - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} - - regexpu-core@6.4.0: - resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} - engines: {node: '>=4'} - - regjsgen@0.8.0: - resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - - regjsparser@0.13.1: - resolution: {integrity: sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==} - hasBin: true - - rehype-raw@7.0.0: - resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} - - rehype-recma@1.0.0: - resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} - - remark-gfm@4.0.1: - resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} - - remark-mdx@3.1.1: - resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} - - remark-parse@11.0.0: - resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} - - remark-rehype@11.1.2: - resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} - - remark-stringify@11.0.0: - resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} - - remark@15.0.1: - resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - resolve-workspace-root@2.0.1: - resolution: {integrity: sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==} - - resolve@1.22.12: - resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} - engines: {node: '>= 0.4'} - hasBin: true - - resolve@2.0.0-next.7: - resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} - engines: {node: '>= 0.4'} - hasBin: true - - restore-cursor@2.0.0: - resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} - engines: {node: '>=4'} - - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rollup@4.60.4: - resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-array-concat@1.1.4: - resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} - engines: {node: '>=0.4'} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - sax@1.6.0: - resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} - engines: {node: '>=11.0.0'} - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - scroll-into-view-if-needed@3.1.0: - resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.8.1: - resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} - engines: {node: '>=10'} - hasBin: true - - send@0.19.2: - resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} - engines: {node: '>= 0.8.0'} - - send@1.2.1: - resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} - engines: {node: '>= 18'} - - serialize-error@2.1.0: - resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} - engines: {node: '>=0.10.0'} - - serve-static@1.16.3: - resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} - engines: {node: '>= 0.8.0'} - - serve-static@2.2.1: - resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} - engines: {node: '>= 18'} - - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} - - setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shell-quote@1.8.4: - resolution: {integrity: sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==} - engines: {node: '>= 0.4'} - - shiki@4.1.0: - resolution: {integrity: sha512-l/ABZPUR5v70jI10EzqfMS/I96vjSGv2y0ihUV+WYFzv0EfvW4s54m0Lg8wCrrL+2IkwBzFTuxkZjPf8b2NX9Q==} - engines: {node: '>=20'} - - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-icons@16.28.0: - resolution: {integrity: sha512-sQPR5AtK/ijRjou7zw7mlLp08oB6FH7i0lOy5XJ2zp9mJs/yejgiOn7KvQoe2q4YJIx6VmgUSW5AOefebPt5kg==} - engines: {node: '>=0.12.18'} - - simple-plist@1.3.1: - resolution: {integrity: sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - slice-ansi@2.1.0: - resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} - engines: {node: '>=6'} - - slugify@1.6.9: - resolution: {integrity: sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==} - engines: {node: '>=8.0.0'} - - smol-toml@1.6.1: - resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} - engines: {node: '>= 18'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - - space-separated-tokens@2.0.2: - resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - - stable-hash@0.0.5: - resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - stackframe@1.3.4: - resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} - - stacktrace-parser@0.1.11: - resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} - engines: {node: '>=6'} - - statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} - - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} - - stream-buffers@2.2.0: - resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==} - engines: {node: '>= 0.10.0'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} - engines: {node: '>= 0.4'} - - string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - - strip-ansi@5.2.0: - resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} - engines: {node: '>=6'} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - strnum@2.4.1: - resolution: {integrity: sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==} - - structured-headers@0.4.1: - resolution: {integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==} - - style-to-js@1.1.21: - resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} - - style-to-object@1.0.14: - resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} - - styled-jsx@5.1.6: - resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true - - styleq@0.1.3: - resolution: {integrity: sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==} - - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - supports-hyperlinks@2.3.0: - resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} - engines: {node: '>=8'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tailwind-merge@3.6.0: - resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} - - tailwindcss@4.3.0: - resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} - - tapable@2.3.3: - resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} - engines: {node: '>=6'} - - terminal-link@2.1.1: - resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} - engines: {node: '>=8'} - - terser@5.48.0: - resolution: {integrity: sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==} - engines: {node: '>=10'} - hasBin: true - - throat@5.0.0: - resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@1.2.4: - resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} - engines: {node: '>=18'} - - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} - engines: {node: '>=12.0.0'} - - tinyrainbow@3.1.0: - resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} - engines: {node: '>=14.0.0'} - - tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - toqr@0.1.1: - resolution: {integrity: sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA==} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - trim-lines@3.0.1: - resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - - trough@2.2.0: - resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tsx@4.22.3: - resolution: {integrity: sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==} - engines: {node: '>=18.0.0'} - hasBin: true - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - - type-fest@0.7.1: - resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} - engines: {node: '>=8'} - - type-is@2.1.0: - resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} - engines: {node: '>= 18'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} - - typedoc@0.28.19: - resolution: {integrity: sha512-wKh+lhdmMFivMlc6vRRcMGXeGEHGU2g8a2CkPTJjJlwRf1iXbimWIPcFolCqe4E0d/FRtGszpIrsp3WLpDB8Pw==} - engines: {node: '>= 18', pnpm: '>= 10'} - hasBin: true - peerDependencies: - typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - typescript@6.0.3: - resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} - engines: {node: '>=14.17'} - hasBin: true - - ua-parser-js@1.0.41: - resolution: {integrity: sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==} - hasBin: true - - uc.micro@2.1.0: - resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - - unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - - unicode-canonical-property-names-ecmascript@2.0.1: - resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} - engines: {node: '>=4'} - - unicode-match-property-ecmascript@2.0.0: - resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} - engines: {node: '>=4'} - - unicode-match-property-value-ecmascript@2.2.1: - resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} - engines: {node: '>=4'} - - unicode-property-aliases-ecmascript@2.2.0: - resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} - engines: {node: '>=4'} - - unified@11.0.5: - resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} - - unist-util-is@6.0.1: - resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} - - unist-util-position-from-estree@2.0.0: - resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} - - unist-util-position@5.0.0: - resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} - - unist-util-remove-position@5.0.0: - resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} - - unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - - unist-util-visit-parents@6.0.2: - resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - - unist-util-visit@5.1.0: - resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} - - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - unrs-resolver@1.12.2: - resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} - - uuid@11.1.1: - resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} - hasBin: true - - validate-npm-package-name@5.0.1: - resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - vfile-location@5.0.3: - resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} - - vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} - - vfile@6.0.3: - resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - - vite@6.4.2: - resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vitest@4.1.8: - resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.8 - '@vitest/browser-preview': 4.1.8 - '@vitest/browser-webdriverio': 4.1.8 - '@vitest/coverage-istanbul': 4.1.8 - '@vitest/coverage-v8': 4.1.8 - '@vitest/ui': 4.1.8 - happy-dom: '*' - jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/coverage-istanbul': - optional: true - '@vitest/coverage-v8': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - vlq@1.0.1: - resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} - - walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - - wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - - web-namespaces@2.0.1: - resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-fetch@3.6.20: - resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} - - whatwg-url-minimum@0.1.2: - resolution: {integrity: sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} - - which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - - which-typed-array@1.1.20: - resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - ws@6.2.6: - resolution: {integrity: sha512-XTrf1gv7kXoVf1hbC3PAyAiPgR8Wz1blcrYIjEsUmr08BLksT41R8KbjmS9408C2ERx7v1JDLD/BkpLEttjfKA==} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@7.5.11: - resolution: {integrity: sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@8.21.0: - resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - xcode@3.0.1: - resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==} - engines: {node: '>=10.0.0'} - - xml-naming@0.3.0: - resolution: {integrity: sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==} - engines: {node: '>=16.0.0'} - - xml2js@0.6.0: - resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==} - engines: {node: '>=4.0.0'} - - xml2js@0.6.2: - resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} - engines: {node: '>=4.0.0'} - - xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - - xmlbuilder@15.1.1: - resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} - engines: {node: '>=8.0'} - - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yaml@2.9.0: - resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} - engines: {node: '>= 14.6'} - hasBin: true - - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zod-to-json-schema@3.25.2: - resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} - peerDependencies: - zod: ^3.25.28 || ^4 - - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - - zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - - zx@8.8.5: - resolution: {integrity: sha512-SNgDF5L0gfN7FwVOdEFguY3orU5AkfFZm9B5YSHog/UDHv+lvmd82ZAsOenOkQixigwH2+yyH198AwNdKhj+RA==} - engines: {node: '>= 12.17.0'} - hasBin: true - -snapshots: - - '@alloc/quick-lru@5.2.0': {} - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.3': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-annotate-as-pure@7.27.3': - dependencies: - '@babel/types': 7.29.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.3 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.2 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-create-class-features-plugin@7.29.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.29.0 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - regexpu-core: 6.4.0 - semver: 6.3.1 - - '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.29.7 - debug: 4.4.3 - lodash.debounce: 4.0.8 - resolve: 1.22.12 - transitivePeerDependencies: - - supports-color - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-member-expression-to-functions@7.28.5': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-optimise-call-expression@7.27.1': - dependencies: - '@babel/types': 7.29.0 - - '@babel/helper-plugin-utils@7.28.6': {} - - '@babel/helper-plugin-utils@7.29.7': {} - - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.28.6 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helper-wrap-function@7.28.6': - dependencies: - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.3': - dependencies: - '@babel/types': 7.29.0 - - '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-proposal-export-default-from@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-syntax-export-default-from@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-syntax-flow@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-flow-strip-types@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-flow': 7.28.6(@babel/core@7.29.0) - - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-runtime@7.29.0(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-plugin-utils': 7.29.7 - babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.0) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.29.0) - babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.0) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.29.3(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/runtime@7.29.2': {} - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@bcoe/v8-coverage@1.0.2': {} - - '@biomejs/biome@2.4.16': - optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.4.16 - '@biomejs/cli-darwin-x64': 2.4.16 - '@biomejs/cli-linux-arm64': 2.4.16 - '@biomejs/cli-linux-arm64-musl': 2.4.16 - '@biomejs/cli-linux-x64': 2.4.16 - '@biomejs/cli-linux-x64-musl': 2.4.16 - '@biomejs/cli-win32-arm64': 2.4.16 - '@biomejs/cli-win32-x64': 2.4.16 - - '@biomejs/cli-darwin-arm64@2.4.16': - optional: true - - '@biomejs/cli-darwin-x64@2.4.16': - optional: true - - '@biomejs/cli-linux-arm64-musl@2.4.16': - optional: true - - '@biomejs/cli-linux-arm64@2.4.16': - optional: true - - '@biomejs/cli-linux-x64-musl@2.4.16': - optional: true - - '@biomejs/cli-linux-x64@2.4.16': - optional: true - - '@biomejs/cli-win32-arm64@2.4.16': - optional: true - - '@biomejs/cli-win32-x64@2.4.16': - optional: true - - '@electric-sql/pglite@0.5.4': {} - - '@emnapi/core@1.10.0': - dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.10.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@esbuild/aix-ppc64@0.28.1': - optional: true - - '@esbuild/android-arm64@0.28.1': - optional: true - - '@esbuild/android-arm@0.28.1': - optional: true - - '@esbuild/android-x64@0.28.1': - optional: true - - '@esbuild/darwin-arm64@0.28.1': - optional: true - - '@esbuild/darwin-x64@0.28.1': - optional: true - - '@esbuild/freebsd-arm64@0.28.1': - optional: true - - '@esbuild/freebsd-x64@0.28.1': - optional: true - - '@esbuild/linux-arm64@0.28.1': - optional: true - - '@esbuild/linux-arm@0.28.1': - optional: true - - '@esbuild/linux-ia32@0.28.1': - optional: true - - '@esbuild/linux-loong64@0.28.1': - optional: true - - '@esbuild/linux-mips64el@0.28.1': - optional: true - - '@esbuild/linux-ppc64@0.28.1': - optional: true - - '@esbuild/linux-riscv64@0.28.1': - optional: true - - '@esbuild/linux-s390x@0.28.1': - optional: true - - '@esbuild/linux-x64@0.28.1': - optional: true - - '@esbuild/netbsd-arm64@0.28.1': - optional: true - - '@esbuild/netbsd-x64@0.28.1': - optional: true - - '@esbuild/openbsd-arm64@0.28.1': - optional: true - - '@esbuild/openbsd-x64@0.28.1': - optional: true - - '@esbuild/openharmony-arm64@0.28.1': - optional: true - - '@esbuild/sunos-x64@0.28.1': - optional: true - - '@esbuild/win32-arm64@0.28.1': - optional: true - - '@esbuild/win32-ia32@0.28.1': - optional: true - - '@esbuild/win32-x64@0.28.1': - optional: true - - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': - dependencies: - eslint: 9.39.4(jiti@2.7.0) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.21.2': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.2': - dependencies: - '@eslint/core': 0.17.0 - - '@eslint/core@0.17.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.5': - dependencies: - ajv: 6.15.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.3.0 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.4': {} - - '@eslint/object-schema@2.1.7': {} - - '@eslint/plugin-kit@0.4.1': - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - - '@expo/cli@56.1.19(30a5a05425671f97adee3495721168f0)': - dependencies: - '@expo/code-signing-certificates': 0.0.6 - '@expo/config': 56.0.11(typescript@6.0.3) - '@expo/config-plugins': 56.0.12(typescript@6.0.3) - '@expo/devcert': 1.2.1 - '@expo/env': 2.3.1 - '@expo/image-utils': 0.10.2(typescript@6.0.3) - '@expo/inline-modules': 0.0.13(typescript@6.0.3) - '@expo/json-file': 10.2.0 - '@expo/log-box': 56.0.14(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - '@expo/metro': 56.0.0 - '@expo/metro-config': 56.0.16(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(typescript@6.0.3) - '@expo/metro-file-map': 56.0.3 - '@expo/osascript': 2.6.0 - '@expo/package-manager': 1.13.0 - '@expo/plist': 0.7.0 - '@expo/prebuild-config': 56.0.19(typescript@6.0.3) - '@expo/require-utils': 56.1.4(typescript@6.0.3) - '@expo/router-server': 56.0.16(f832d381ce87ad6165edd769db17dde7) - '@expo/schema-utils': 56.0.2 - '@expo/spawn-async': 1.8.0 - '@expo/ws-tunnel': 2.0.0(ws@8.21.0) - '@expo/xcpretty': 4.4.4 - '@react-native/dev-middleware': 0.85.3 - accepts: 1.3.8 - agent-cli-detector: 0.1.2 - arg: 5.0.2 - bplist-creator: 0.1.0 - bplist-parser: 0.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - compression: 1.8.1 - connect: 3.7.0 - debug: 4.4.3 - dnssd-advertise: 1.1.6 - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-server: 56.0.5 - fetch-nodeshim: 0.4.10 - getenv: 2.0.0 - glob: 13.0.6 - lan-network: 0.2.1 - multitars: 1.0.0 - node-forge: 1.4.0 - npm-package-arg: 11.0.3 - ora: 3.4.0 - picomatch: 4.0.4 - pretty-format: 29.7.0 - progress: 2.0.3 - prompts: 2.4.2 - resolve-from: 5.0.0 - semver: 7.8.1 - send: 0.19.2 - slugify: 1.6.9 - stacktrace-parser: 0.1.11 - structured-headers: 0.4.1 - terminal-link: 2.1.1 - toqr: 0.1.1 - wrap-ansi: 7.0.0 - ws: 8.21.0 - zod: 3.25.76 - optionalDependencies: - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - transitivePeerDependencies: - - '@expo/metro-runtime' - - bufferutil - - expo-constants - - expo-font - - react - - react-dom - - react-server-dom-webpack - - supports-color - - typescript - - utf-8-validate - - '@expo/code-signing-certificates@0.0.6': - dependencies: - node-forge: 1.4.0 - - '@expo/config-plugins@56.0.12(typescript@6.0.3)': - dependencies: - '@expo/config-types': 56.0.7 - '@expo/json-file': 10.2.0 - '@expo/plist': 0.7.0 - '@expo/require-utils': 56.1.4(typescript@6.0.3) - '@expo/sdk-runtime-versions': 1.0.0 - chalk: 4.1.2 - debug: 4.4.3 - getenv: 2.0.0 - glob: 13.0.6 - semver: 7.8.1 - slugify: 1.6.9 - xcode: 3.0.1 - xml2js: 0.6.0 - transitivePeerDependencies: - - supports-color - - typescript - - '@expo/config-types@56.0.7': {} - - '@expo/config@56.0.11(typescript@6.0.3)': - dependencies: - '@expo/config-plugins': 56.0.12(typescript@6.0.3) - '@expo/config-types': 56.0.7 - '@expo/json-file': 10.2.0 - '@expo/require-utils': 56.1.4(typescript@6.0.3) - deepmerge: 4.3.1 - getenv: 2.0.0 - glob: 13.0.6 - resolve-workspace-root: 2.0.1 - semver: 7.8.1 - slugify: 1.6.9 - transitivePeerDependencies: - - supports-color - - typescript - - '@expo/devcert@1.2.1': - dependencies: - '@expo/sudo-prompt': 9.3.2 - debug: 3.2.7 - transitivePeerDependencies: - - supports-color - - '@expo/devtools@56.0.2(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)': - dependencies: - chalk: 4.1.2 - optionalDependencies: - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - '@expo/dom-webview@56.0.6(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)': - dependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - '@expo/env@2.3.1': - dependencies: - chalk: 4.1.2 - debug: 4.4.3 - getenv: 2.0.0 - transitivePeerDependencies: - - supports-color - - '@expo/env@2.4.1': - dependencies: - chalk: 4.1.2 - debug: 4.4.3 - getenv: 2.0.0 - transitivePeerDependencies: - - supports-color - - '@expo/expo-modules-macros-plugin@0.2.2': {} - - '@expo/fingerprint@0.19.7': - dependencies: - '@expo/env': 2.4.1 - '@expo/spawn-async': 1.8.0 - arg: 5.0.2 - chalk: 4.1.2 - debug: 4.4.3 - getenv: 2.0.0 - glob: 13.0.6 - ignore: 5.3.2 - minimatch: 10.2.5 - resolve-from: 5.0.0 - semver: 7.8.1 - transitivePeerDependencies: - - supports-color - - '@expo/image-utils@0.10.2(typescript@6.0.3)': - dependencies: - '@expo/require-utils': 56.1.4(typescript@6.0.3) - '@expo/spawn-async': 1.8.0 - chalk: 4.1.2 - getenv: 2.0.0 - jimp-compact: 0.16.1 - parse-png: 2.1.0 - semver: 7.8.1 - transitivePeerDependencies: - - supports-color - - typescript - - '@expo/inline-modules@0.0.13(typescript@6.0.3)': - dependencies: - '@expo/config-plugins': 56.0.12(typescript@6.0.3) - transitivePeerDependencies: - - supports-color - - typescript - - '@expo/json-file@10.2.0': - dependencies: - '@babel/code-frame': 7.29.0 - json5: 2.2.3 - - '@expo/json-file@11.0.0': - dependencies: - '@babel/code-frame': 7.29.0 - json5: 2.2.3 - - '@expo/local-build-cache-provider@56.0.9(typescript@6.0.3)': - dependencies: - '@expo/config': 56.0.11(typescript@6.0.3) - chalk: 4.1.2 - transitivePeerDependencies: - - supports-color - - typescript - - '@expo/log-box@56.0.14(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)': - dependencies: - '@expo/dom-webview': 56.0.6(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - anser: 1.4.10 - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - stacktrace-parser: 0.1.11 - - '@expo/mcp-tunnel@0.2.4(@modelcontextprotocol/sdk@1.29.0)': - dependencies: - '@modelcontextprotocol/sdk': 1.29.0 - ws: 8.21.0 - zod: 3.25.76 - zod-to-json-schema: 3.25.2(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@expo/metro-config@56.0.16(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(typescript@6.0.3)': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@expo/config': 56.0.11(typescript@6.0.3) - '@expo/env': 2.3.1 - '@expo/json-file': 10.2.0 - '@expo/metro': 56.0.0 - '@expo/require-utils': 56.1.4(typescript@6.0.3) - '@expo/spawn-async': 1.8.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/remapping': 2.3.5 - '@jridgewell/sourcemap-codec': 1.5.5 - browserslist: 4.28.2 - chalk: 4.1.2 - debug: 4.4.3 - getenv: 2.0.0 - glob: 13.0.6 - hermes-parser: 0.33.3 - jsc-safe-url: 0.2.4 - lightningcss: 1.32.0 - picomatch: 4.0.4 - postcss: 8.5.15 - resolve-from: 5.0.0 - optionalDependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - transitivePeerDependencies: - - bufferutil - - supports-color - - typescript - - utf-8-validate - - '@expo/metro-file-map@56.0.3': - dependencies: - debug: 4.4.3 - fb-watchman: 2.0.2 - invariant: 2.2.4 - jest-worker: 29.7.0 - micromatch: 4.0.8 - walker: 1.0.8 - transitivePeerDependencies: - - supports-color - - '@expo/metro@56.0.0': - dependencies: - metro: 0.84.4 - metro-babel-transformer: 0.84.4 - metro-cache: 0.84.4 - metro-cache-key: 0.84.4 - metro-config: 0.84.4 - metro-core: 0.84.4 - metro-file-map: 0.84.4 - metro-minify-terser: 0.84.4 - metro-resolver: 0.84.4 - metro-runtime: 0.84.4 - metro-source-map: 0.84.4 - metro-symbolicate: 0.84.4 - metro-transform-plugins: 0.84.4 - metro-transform-worker: 0.84.4 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@expo/osascript@2.6.0': - dependencies: - '@expo/spawn-async': 1.8.0 - - '@expo/package-manager@1.13.0': - dependencies: - '@expo/json-file': 11.0.0 - '@expo/spawn-async': 1.8.0 - chalk: 4.1.2 - npm-package-arg: 11.0.3 - ora: 3.4.0 - resolve-workspace-root: 2.0.1 - - '@expo/plist@0.7.0': - dependencies: - '@xmldom/xmldom': 0.8.13 - base64-js: 1.5.1 - xmlbuilder: 15.1.1 - - '@expo/prebuild-config@56.0.19(typescript@6.0.3)': - dependencies: - '@expo/config': 56.0.11(typescript@6.0.3) - '@expo/config-plugins': 56.0.12(typescript@6.0.3) - '@expo/config-types': 56.0.7 - '@expo/image-utils': 0.10.2(typescript@6.0.3) - '@expo/json-file': 10.2.0 - '@react-native/normalize-colors': 0.85.3 - debug: 4.4.3 - expo-modules-autolinking: 56.0.19(typescript@6.0.3) - resolve-from: 5.0.0 - semver: 7.8.1 - transitivePeerDependencies: - - supports-color - - typescript - - '@expo/require-utils@56.1.4(typescript@6.0.3)': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/core': 7.29.0 - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) - optionalDependencies: - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@expo/router-server@56.0.16(f832d381ce87ad6165edd769db17dde7)': - dependencies: - debug: 4.4.3 - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-constants: 56.0.20(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - expo-font: 56.0.7(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - expo-server: 56.0.5 - react: 19.2.3 - optionalDependencies: - react-dom: 19.2.3(react@19.2.3) - transitivePeerDependencies: - - supports-color - - '@expo/schema-utils@56.0.2': {} - - '@expo/sdk-runtime-versions@1.0.0': {} - - '@expo/spawn-async@1.8.0': - dependencies: - cross-spawn: 7.0.6 - - '@expo/sudo-prompt@9.3.2': {} - - '@expo/ws-tunnel@2.0.0(ws@8.21.0)': - dependencies: - ws: 8.21.0 - - '@expo/xcpretty@4.4.4': - dependencies: - '@babel/code-frame': 7.29.0 - chalk: 4.1.2 - js-yaml: 4.3.0 - - '@floating-ui/core@1.7.5': - dependencies: - '@floating-ui/utils': 0.2.11 - - '@floating-ui/dom@1.7.6': - dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/utils': 0.2.11 - - '@floating-ui/react-dom@2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@floating-ui/dom': 1.7.6 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - - '@floating-ui/utils@0.2.11': {} - - '@fumadocs/tailwind@0.0.5(@tailwindcss/oxide@4.3.0)(tailwindcss@4.3.0)': - optionalDependencies: - '@tailwindcss/oxide': 4.3.0 - tailwindcss: 4.3.0 - - '@gerrit0/mini-shiki@3.23.0': - dependencies: - '@shikijs/engine-oniguruma': 3.23.0 - '@shikijs/langs': 3.23.0 - '@shikijs/themes': 3.23.0 - '@shikijs/types': 3.23.0 - '@shikijs/vscode-textmate': 10.0.2 - - '@hapi/hoek@9.3.0': {} - - '@hapi/topo@5.1.0': - dependencies: - '@hapi/hoek': 9.3.0 - - '@hono/node-server@1.19.14(hono@4.12.22)': - dependencies: - hono: 4.12.22 - - '@humanfs/core@0.19.2': - dependencies: - '@humanfs/types': 0.15.0 - - '@humanfs/node@0.16.8': - dependencies: - '@humanfs/core': 0.19.2 - '@humanfs/types': 0.15.0 - '@humanwhocodes/retry': 0.4.3 - - '@humanfs/types@0.15.0': {} - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@img/colour@1.1.0': - optional: true - - '@img/sharp-darwin-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 - optional: true - - '@img/sharp-darwin-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 - optional: true - - '@img/sharp-libvips-darwin-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-darwin-x64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm@1.2.4': - optional: true - - '@img/sharp-libvips-linux-ppc64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-riscv64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-s390x@1.2.4': - optional: true - - '@img/sharp-libvips-linux-x64@1.2.4': - optional: true - - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - optional: true - - '@img/sharp-linux-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 - optional: true - - '@img/sharp-linux-arm@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 - optional: true - - '@img/sharp-linux-ppc64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 - optional: true - - '@img/sharp-linux-riscv64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 - optional: true - - '@img/sharp-linux-s390x@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 - optional: true - - '@img/sharp-linux-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 - optional: true - - '@img/sharp-linuxmusl-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - optional: true - - '@img/sharp-linuxmusl-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - optional: true - - '@img/sharp-wasm32@0.34.5': - dependencies: - '@emnapi/runtime': 1.10.0 - optional: true - - '@img/sharp-win32-arm64@0.34.5': - optional: true - - '@img/sharp-win32-ia32@0.34.5': - optional: true - - '@img/sharp-win32-x64@0.34.5': - optional: true - - '@isaacs/cliui@9.0.0': {} - - '@isaacs/ttlcache@1.4.1': {} - - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.10 - - '@jest/types@29.6.3': - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 24.12.4 - '@types/yargs': 17.0.35 - chalk: 4.1.2 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/source-map@0.3.11': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@mdx-js/mdx@3.1.1': - dependencies: - '@types/estree': 1.0.9 - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdx': 2.0.13 - acorn: 8.16.0 - collapse-white-space: 2.1.0 - devlop: 1.1.0 - estree-util-is-identifier-name: 3.0.0 - estree-util-scope: 1.0.0 - estree-walker: 3.0.3 - hast-util-to-jsx-runtime: 2.3.6 - markdown-extensions: 2.0.0 - recma-build-jsx: 1.0.0 - recma-jsx: 1.0.1(acorn@8.16.0) - recma-stringify: 1.0.0 - rehype-recma: 1.0.0 - remark-mdx: 3.1.1 - remark-parse: 11.0.0 - remark-rehype: 11.1.2 - source-map: 0.7.6 - unified: 11.0.5 - unist-util-position-from-estree: 2.0.0 - unist-util-stringify-position: 4.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@mdx-js/react@3.1.1(@types/react@19.2.16)(react@19.2.7)': - dependencies: - '@types/mdx': 2.0.13 - '@types/react': 19.2.16 - react: 19.2.7 - - '@modelcontextprotocol/sdk@1.29.0': - dependencies: - '@hono/node-server': 1.19.14(hono@4.12.22) - ajv: 8.20.0 - ajv-formats: 3.0.1 - content-type: 1.0.5 - cors: 2.8.6 - cross-spawn: 7.0.6 - eventsource: 3.0.7 - eventsource-parser: 3.0.8 - express: 5.2.1 - express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.22 - jose: 6.2.3 - json-schema-typed: 8.0.2 - pkce-challenge: 5.0.1 - raw-body: 3.0.2 - zod: 4.4.3 - zod-to-json-schema: 3.25.2(zod@4.4.3) - transitivePeerDependencies: - - supports-color - - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 - optional: true - - '@next/env@16.2.7': {} - - '@next/swc-darwin-arm64@16.2.7': - optional: true - - '@next/swc-darwin-x64@16.2.7': - optional: true - - '@next/swc-linux-arm64-gnu@16.2.7': - optional: true - - '@next/swc-linux-arm64-musl@16.2.7': - optional: true - - '@next/swc-linux-x64-gnu@16.2.7': - optional: true - - '@next/swc-linux-x64-musl@16.2.7': - optional: true - - '@next/swc-win32-arm64-msvc@16.2.7': - optional: true - - '@next/swc-win32-x64-msvc@16.2.7': - optional: true - - '@nodable/entities@3.0.0': {} - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - - '@nolyfill/is-core-module@1.0.39': {} - - '@orama/orama@3.1.18': {} - - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.16)(react@19.2.7)': - dependencies: - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-context@1.1.2(@types/react@19.2.16)(react@19.2.7)': - dependencies: - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.7) - aria-hidden: 1.2.6 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - react-remove-scroll: 2.7.2(@types/react@19.2.16)(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-direction@1.1.1(@types/react@19.2.16)(react@19.2.7)': - dependencies: - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.16)(react@19.2.7)': - dependencies: - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-id@1.1.1(@types/react@19.2.16)(react@19.2.7)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.7) - aria-hidden: 1.2.6 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - react-remove-scroll: 2.7.2(@types/react@19.2.16)(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/rect': 1.1.1 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.16)(react@19.2.7)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-slot@1.2.4(@types/react@19.2.16)(react@19.2.7)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.16)(react@19.2.7)': - dependencies: - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.16)(react@19.2.7)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.16)(react@19.2.7)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.16)(react@19.2.7)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.16)(react@19.2.7)': - dependencies: - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.16)(react@19.2.7)': - dependencies: - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.16)(react@19.2.7)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.16)(react@19.2.7)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.7) - react: 19.2.7 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/rect@1.1.1': {} - - '@react-native-community/cli-clean@20.2.0': - dependencies: - '@react-native-community/cli-tools': 20.2.0 - execa: 5.1.1 - fast-glob: 3.3.3 - picocolors: 1.1.1 - - '@react-native-community/cli-config-android@20.2.0': - dependencies: - '@react-native-community/cli-tools': 20.2.0 - fast-glob: 3.3.3 - fast-xml-parser: 5.10.1 - picocolors: 1.1.1 - - '@react-native-community/cli-config-apple@20.2.0': - dependencies: - '@react-native-community/cli-tools': 20.2.0 - execa: 5.1.1 - fast-glob: 3.3.3 - picocolors: 1.1.1 - - '@react-native-community/cli-config@20.2.0(typescript@6.0.3)': - dependencies: - '@react-native-community/cli-tools': 20.2.0 - cosmiconfig: 9.0.2(typescript@6.0.3) - deepmerge: 4.3.1 - fast-glob: 3.3.3 - joi: 17.13.4 - picocolors: 1.1.1 - transitivePeerDependencies: - - typescript - - '@react-native-community/cli-doctor@20.2.0(typescript@6.0.3)': - dependencies: - '@react-native-community/cli-config': 20.2.0(typescript@6.0.3) - '@react-native-community/cli-platform-android': 20.2.0 - '@react-native-community/cli-platform-apple': 20.2.0 - '@react-native-community/cli-platform-ios': 20.2.0 - '@react-native-community/cli-tools': 20.2.0 - command-exists: 1.2.9 - deepmerge: 4.3.1 - envinfo: 7.21.0 - execa: 5.1.1 - node-stream-zip: 1.15.0 - ora: 5.4.1 - picocolors: 1.1.1 - semver: 7.8.1 - wcwidth: 1.0.1 - yaml: 2.9.0 - transitivePeerDependencies: - - typescript - - '@react-native-community/cli-platform-android@20.2.0': - dependencies: - '@react-native-community/cli-config-android': 20.2.0 - '@react-native-community/cli-tools': 20.2.0 - execa: 5.1.1 - logkitty: 0.7.1 - picocolors: 1.1.1 - - '@react-native-community/cli-platform-apple@20.2.0': - dependencies: - '@react-native-community/cli-config-apple': 20.2.0 - '@react-native-community/cli-tools': 20.2.0 - execa: 5.1.1 - fast-xml-parser: 5.10.1 - picocolors: 1.1.1 - - '@react-native-community/cli-platform-ios@20.2.0': - dependencies: - '@react-native-community/cli-platform-apple': 20.2.0 - - '@react-native-community/cli-server-api@20.2.0': - dependencies: - '@react-native-community/cli-tools': 20.2.0 - body-parser: 2.2.2 - compression: 1.8.1 - connect: 3.7.0 - errorhandler: 1.5.2 - nocache: 3.0.4 - open: 6.4.0 - pretty-format: 29.7.0 - serve-static: 1.16.3 - ws: 6.2.6 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native-community/cli-tools@20.2.0': - dependencies: - '@vscode/sudo-prompt': 9.3.2 - appdirsjs: 1.2.8 - execa: 5.1.1 - find-up: 5.0.0 - launch-editor: 2.14.1 - mime: 2.6.0 - ora: 5.4.1 - picocolors: 1.1.1 - prompts: 2.4.2 - semver: 7.8.1 - - '@react-native-community/cli-types@20.2.0': - dependencies: - joi: 17.13.4 - - '@react-native-community/cli@20.2.0(typescript@6.0.3)': - dependencies: - '@react-native-community/cli-clean': 20.2.0 - '@react-native-community/cli-config': 20.2.0(typescript@6.0.3) - '@react-native-community/cli-doctor': 20.2.0(typescript@6.0.3) - '@react-native-community/cli-server-api': 20.2.0 - '@react-native-community/cli-tools': 20.2.0 - '@react-native-community/cli-types': 20.2.0 - commander: 9.5.0 - deepmerge: 4.3.1 - execa: 5.1.1 - find-up: 5.0.0 - fs-extra: 8.1.0 - graceful-fs: 4.2.11 - picocolors: 1.1.1 - prompts: 2.4.2 - semver: 7.8.1 - transitivePeerDependencies: - - bufferutil - - supports-color - - typescript - - utf-8-validate - - '@react-native/assets-registry@0.85.3': {} - - '@react-native/babel-plugin-codegen@0.85.3': - dependencies: - '@babel/traverse': 7.29.0 - '@react-native/codegen': 0.85.3 - transitivePeerDependencies: - - supports-color - - '@react-native/babel-preset@0.85.3': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-export-default-from': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) - '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) - '@react-native/babel-plugin-codegen': 0.85.3 - babel-plugin-syntax-hermes-parser: 0.33.3 - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.0) - react-refresh: 0.14.2 - transitivePeerDependencies: - - supports-color - - '@react-native/codegen@0.85.3': - dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 - hermes-parser: 0.33.3 - invariant: 2.2.4 - nullthrows: 1.1.1 - tinyglobby: 0.2.16 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - - '@react-native/community-cli-plugin@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)': - dependencies: - '@react-native/dev-middleware': 0.85.3 - debug: 4.4.3 - invariant: 2.2.4 - metro: 0.84.4 - metro-config: 0.84.4 - metro-core: 0.84.4 - semver: 7.8.1 - optionalDependencies: - '@react-native-community/cli': 20.2.0(typescript@6.0.3) - '@react-native/metro-config': 0.85.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native/debugger-frontend@0.85.3': {} - - '@react-native/debugger-shell@0.85.3': - dependencies: - cross-spawn: 7.0.6 - debug: 4.4.3 - fb-dotslash: 0.5.8 - transitivePeerDependencies: - - supports-color - - '@react-native/dev-middleware@0.85.3': - dependencies: - '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.85.3 - '@react-native/debugger-shell': 0.85.3 - chrome-launcher: 0.15.2 - chromium-edge-launcher: 0.3.0 - connect: 3.7.0 - debug: 4.4.3 - invariant: 2.2.4 - nullthrows: 1.1.1 - open: 7.4.2 - serve-static: 1.16.3 - ws: 7.5.11 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native/gradle-plugin@0.85.3': {} - - '@react-native/js-polyfills@0.85.3': {} - - '@react-native/metro-babel-transformer@0.85.3': - dependencies: - '@babel/core': 7.29.0 - '@react-native/babel-preset': 0.85.3 - hermes-parser: 0.33.3 - nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color - - '@react-native/metro-config@0.85.3': - dependencies: - '@react-native/js-polyfills': 0.85.3 - '@react-native/metro-babel-transformer': 0.85.3 - metro-config: 0.84.4 - metro-runtime: 0.84.4 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@react-native/normalize-colors@0.74.89': {} - - '@react-native/normalize-colors@0.85.3': {} - - '@react-native/typescript-config@0.85.3': {} - - '@react-native/virtualized-lists@0.85.3(@types/react@19.2.16)(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)': - dependencies: - invariant: 2.2.4 - nullthrows: 1.1.1 - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.16 - - '@rollup/rollup-android-arm-eabi@4.60.4': - optional: true - - '@rollup/rollup-android-arm64@4.60.4': - optional: true - - '@rollup/rollup-darwin-arm64@4.60.4': - optional: true - - '@rollup/rollup-darwin-x64@4.60.4': - optional: true - - '@rollup/rollup-freebsd-arm64@4.60.4': - optional: true - - '@rollup/rollup-freebsd-x64@4.60.4': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.60.4': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-x64-musl@4.60.4': - optional: true - - '@rollup/rollup-openbsd-x64@4.60.4': - optional: true - - '@rollup/rollup-openharmony-arm64@4.60.4': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.60.4': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.60.4': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.60.4': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.60.4': - optional: true - - '@rtsao/scc@1.1.0': {} - - '@shikijs/core@4.1.0': - dependencies: - '@shikijs/primitive': 4.1.0 - '@shikijs/types': 4.1.0 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - hast-util-to-html: 9.0.5 - - '@shikijs/engine-javascript@4.1.0': - dependencies: - '@shikijs/types': 4.1.0 - '@shikijs/vscode-textmate': 10.0.2 - oniguruma-to-es: 4.3.6 - - '@shikijs/engine-oniguruma@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - '@shikijs/vscode-textmate': 10.0.2 - - '@shikijs/engine-oniguruma@4.1.0': - dependencies: - '@shikijs/types': 4.1.0 - '@shikijs/vscode-textmate': 10.0.2 - - '@shikijs/langs@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - - '@shikijs/langs@4.1.0': - dependencies: - '@shikijs/types': 4.1.0 - - '@shikijs/primitive@4.1.0': - dependencies: - '@shikijs/types': 4.1.0 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - '@shikijs/themes@3.23.0': - dependencies: - '@shikijs/types': 3.23.0 - - '@shikijs/themes@4.1.0': - dependencies: - '@shikijs/types': 4.1.0 - - '@shikijs/types@3.23.0': - dependencies: - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - '@shikijs/types@4.1.0': - dependencies: - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - '@shikijs/vscode-textmate@10.0.2': {} - - '@sideway/address@4.1.5': - dependencies: - '@hapi/hoek': 9.3.0 - - '@sideway/formula@3.0.1': {} - - '@sideway/pinpoint@2.0.0': {} - - '@sinclair/typebox@0.27.10': {} - - '@standard-schema/spec@1.1.0': {} - - '@swc/helpers@0.5.15': - dependencies: - tslib: 2.8.1 - - '@tailwindcss/node@4.3.0': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.22.1 - jiti: 2.7.0 - lightningcss: 1.32.0 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.3.0 - - '@tailwindcss/oxide-android-arm64@4.3.0': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.3.0': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.3.0': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.3.0': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.3.0': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.3.0': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.3.0': - optional: true - - '@tailwindcss/oxide@4.3.0': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.3.0 - '@tailwindcss/oxide-darwin-arm64': 4.3.0 - '@tailwindcss/oxide-darwin-x64': 4.3.0 - '@tailwindcss/oxide-freebsd-x64': 4.3.0 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 - '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 - '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 - '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 - '@tailwindcss/oxide-linux-x64-musl': 4.3.0 - '@tailwindcss/oxide-wasm32-wasi': 4.3.0 - '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 - '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 - - '@tailwindcss/postcss@4.3.0': - dependencies: - '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.3.0 - '@tailwindcss/oxide': 4.3.0 - postcss: 8.5.15 - tailwindcss: 4.3.0 - - '@tybys/wasm-util@0.10.2': - dependencies: - tslib: 2.8.1 - optional: true - - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - - '@types/debug@4.1.13': - dependencies: - '@types/ms': 2.1.0 - - '@types/deep-eql@4.0.2': {} - - '@types/estree-jsx@1.0.5': - dependencies: - '@types/estree': 1.0.9 - - '@types/estree@1.0.8': {} - - '@types/estree@1.0.9': {} - - '@types/hast@3.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/istanbul-lib-coverage@2.0.6': {} - - '@types/istanbul-lib-report@3.0.3': - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - - '@types/istanbul-reports@3.0.4': - dependencies: - '@types/istanbul-lib-report': 3.0.3 - - '@types/json-schema@7.0.15': {} - - '@types/json5@0.0.29': {} - - '@types/mdast@4.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/mdx@2.0.13': {} - - '@types/ms@2.1.0': {} - - '@types/node@22.19.19': - dependencies: - undici-types: 6.21.0 - - '@types/node@24.12.4': - dependencies: - undici-types: 7.16.0 - - '@types/react-dom@19.2.3(@types/react@19.2.16)': - dependencies: - '@types/react': 19.2.16 - - '@types/react@19.2.16': - dependencies: - csstype: 3.2.3 - - '@types/unist@2.0.11': {} - - '@types/unist@3.0.3': {} - - '@types/yargs-parser@21.0.3': {} - - '@types/yargs@17.0.35': - dependencies: - '@types/yargs-parser': 21.0.3 - - '@typescript-eslint/eslint-plugin@8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.59.4 - '@typescript-eslint/type-utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.59.4 - eslint: 9.39.4(jiti@2.7.0) - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.59.4 - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.59.4 - debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.59.4(typescript@6.0.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@6.0.3) - '@typescript-eslint/types': 8.59.4 - debug: 4.4.3 - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.59.4': - dependencies: - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/visitor-keys': 8.59.4 - - '@typescript-eslint/tsconfig-utils@8.59.4(typescript@6.0.3)': - dependencies: - typescript: 6.0.3 - - '@typescript-eslint/type-utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': - dependencies: - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) - '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.59.4': {} - - '@typescript-eslint/typescript-estree@8.59.4(typescript@6.0.3)': - dependencies: - '@typescript-eslint/project-service': 8.59.4(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@6.0.3) - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/visitor-keys': 8.59.4 - debug: 4.4.3 - minimatch: 10.2.5 - semver: 7.8.1 - tinyglobby: 0.2.16 - ts-api-utils: 2.5.0(typescript@6.0.3) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@typescript-eslint/scope-manager': 8.59.4 - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/typescript-estree': 8.59.4(typescript@6.0.3) - eslint: 9.39.4(jiti@2.7.0) - typescript: 6.0.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.59.4': - dependencies: - '@typescript-eslint/types': 8.59.4 - eslint-visitor-keys: 5.0.1 - - '@ungap/structured-clone@1.3.1': {} - - '@unrs/resolver-binding-android-arm-eabi@1.12.2': - optional: true - - '@unrs/resolver-binding-android-arm64@1.12.2': - optional: true - - '@unrs/resolver-binding-darwin-arm64@1.12.2': - optional: true - - '@unrs/resolver-binding-darwin-x64@1.12.2': - optional: true - - '@unrs/resolver-binding-freebsd-x64@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-arm64-musl@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-loong64-musl@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-x64-gnu@1.12.2': - optional: true - - '@unrs/resolver-binding-linux-x64-musl@1.12.2': - optional: true - - '@unrs/resolver-binding-openharmony-arm64@1.12.2': - optional: true - - '@unrs/resolver-binding-wasm32-wasi@1.12.2': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - optional: true - - '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': - optional: true - - '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': - optional: true - - '@unrs/resolver-binding-win32-x64-msvc@1.12.2': - optional: true - - '@vitest/coverage-v8@4.1.8(vitest@4.1.8)': - dependencies: - '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.1.8 - ast-v8-to-istanbul: 1.0.3 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-report: 3.0.1 - istanbul-reports: 3.2.0 - magicast: 0.5.3 - obug: 2.1.1 - std-env: 4.1.0 - tinyrainbow: 3.1.0 - vitest: 4.1.8(@types/node@24.12.4)(@vitest/coverage-v8@4.1.8)(vite@6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0)) - - '@vitest/expect@4.1.8': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 - chai: 6.2.2 - tinyrainbow: 3.1.0 - - '@vitest/mocker@4.1.8(vite@6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0))': - dependencies: - '@vitest/spy': 4.1.8 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0) - - '@vitest/pretty-format@4.1.8': - dependencies: - tinyrainbow: 3.1.0 - - '@vitest/runner@4.1.8': - dependencies: - '@vitest/utils': 4.1.8 - pathe: 2.0.3 - - '@vitest/snapshot@4.1.8': - dependencies: - '@vitest/pretty-format': 4.1.8 - '@vitest/utils': 4.1.8 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@4.1.8': {} - - '@vitest/utils@4.1.8': - dependencies: - '@vitest/pretty-format': 4.1.8 - convert-source-map: 2.0.0 - tinyrainbow: 3.1.0 - - '@vscode/sudo-prompt@9.3.2': {} - - '@xmldom/xmldom@0.8.13': {} - - '@xmldom/xmldom@0.9.10': {} - - abort-controller@3.0.0: - dependencies: - event-target-shim: 5.0.1 - - accepts@1.3.8: - dependencies: - mime-types: 2.1.35 - negotiator: 0.6.3 - - accepts@2.0.0: - dependencies: - mime-types: 3.0.2 - negotiator: 1.0.0 - - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - agent-base@7.1.4: {} - - agent-cli-detector@0.1.2: {} - - ajv-formats@3.0.1: - dependencies: - ajv: 8.20.0 - - ajv@6.15.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@8.20.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - anser@1.4.10: {} - - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - - ansi-fragments@0.2.1: - dependencies: - colorette: 1.4.0 - slice-ansi: 2.1.0 - strip-ansi: 5.2.0 - - ansi-regex@4.1.1: {} - - ansi-regex@5.0.1: {} - - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@5.2.0: {} - - anynum@1.0.1: {} - - appdirsjs@1.2.8: {} - - arg@5.0.2: {} - - argparse@2.0.1: {} - - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - - array-buffer-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - is-array-buffer: 3.0.5 - - array-includes@3.1.9: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-object-atoms: 1.1.2 - get-intrinsic: 1.3.0 - is-string: 1.1.1 - math-intrinsics: 1.1.0 - - array.prototype.findlast@1.2.5: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - es-shim-unscopables: 1.1.0 - - array.prototype.findlastindex@1.2.6: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - es-shim-unscopables: 1.1.0 - - array.prototype.flat@1.3.3: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-shim-unscopables: 1.1.0 - - array.prototype.flatmap@1.3.3: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-shim-unscopables: 1.1.0 - - array.prototype.tosorted@1.1.4: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-shim-unscopables: 1.1.0 - - arraybuffer.prototype.slice@1.0.4: - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - is-array-buffer: 3.0.5 - - asap@2.0.6: {} - - assertion-error@2.0.1: {} - - ast-v8-to-istanbul@1.0.3: - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - estree-walker: 3.0.3 - js-tokens: 10.0.0 - - astral-regex@1.0.0: {} - - astring@1.9.0: {} - - async-function@1.0.0: {} - - async-limiter@1.0.1: {} - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - await-lock@2.2.2: {} - - babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.0): - dependencies: - '@babel/compat-data': 7.29.3 - '@babel/core': 7.29.0 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.29.0): - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0) - core-js-compat: 3.49.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.0): - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - babel-plugin-react-compiler@1.0.0: - dependencies: - '@babel/types': 7.29.0 - - babel-plugin-react-native-web@0.21.2: {} - - babel-plugin-syntax-hermes-parser@0.33.3: - dependencies: - hermes-parser: 0.33.3 - - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.29.0): - dependencies: - '@babel/plugin-syntax-flow': 7.28.6(@babel/core@7.29.0) - transitivePeerDependencies: - - '@babel/core' - - babel-preset-expo@56.0.17(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-refresh@0.14.2): - dependencies: - '@babel/generator': 7.29.1 - '@babel/helper-module-imports': 7.28.6 - '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-export-default-from': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) - '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) - '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-runtime': 7.29.0(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) - '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) - '@react-native/babel-plugin-codegen': 0.85.3 - babel-plugin-react-compiler: 1.0.0 - babel-plugin-react-native-web: 0.21.2 - babel-plugin-syntax-hermes-parser: 0.33.3 - babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.0) - debug: 4.4.3 - react-refresh: 0.14.2 - optionalDependencies: - '@babel/runtime': 7.29.2 - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - transitivePeerDependencies: - - '@babel/core' - - supports-color - - bail@2.0.2: {} - - balanced-match@1.0.2: {} - - balanced-match@4.0.4: {} - - base64-js@1.5.1: {} - - baseline-browser-mapping@2.10.32: {} - - big-integer@1.6.52: {} - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - - body-parser@2.2.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - on-finished: 2.4.1 - qs: 6.15.2 - raw-body: 3.0.2 - type-is: 2.1.0 - transitivePeerDependencies: - - supports-color - - bplist-creator@0.1.0: - dependencies: - stream-buffers: 2.2.0 - - bplist-parser@0.3.1: - dependencies: - big-integer: 1.6.52 - - bplist-parser@0.3.2: - dependencies: - big-integer: 1.6.52 - - brace-expansion@1.1.14: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@5.0.6: - dependencies: - balanced-match: 4.0.4 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.2: - dependencies: - baseline-browser-mapping: 2.10.32 - caniuse-lite: 1.0.30001793 - electron-to-chromium: 1.5.361 - node-releases: 2.0.46 - update-browserslist-db: 1.2.3(browserslist@4.28.2) - - bser@2.1.1: - dependencies: - node-int64: 0.4.0 - - buffer-from@1.1.2: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bytes@3.1.2: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.9: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - callsites@3.1.0: {} - - camelcase@5.3.1: {} - - camelcase@6.3.0: {} - - caniuse-lite@1.0.30001793: {} - - ccount@2.0.1: {} - - chai@6.2.2: {} - - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - character-entities-html4@2.1.0: {} - - character-entities-legacy@3.0.0: {} - - character-entities@2.0.2: {} - - character-reference-invalid@2.0.1: {} - - chokidar@5.0.0: - dependencies: - readdirp: 5.0.0 - - chrome-launcher@0.15.2: - dependencies: - '@types/node': 24.12.4 - escape-string-regexp: 4.0.0 - is-wsl: 2.2.0 - lighthouse-logger: 1.4.2 - transitivePeerDependencies: - - supports-color - - chromium-edge-launcher@0.3.0: - dependencies: - '@types/node': 24.12.4 - escape-string-regexp: 4.0.0 - is-wsl: 2.2.0 - lighthouse-logger: 1.4.2 - mkdirp: 1.0.4 - transitivePeerDependencies: - - supports-color - - ci-info@2.0.0: {} - - ci-info@3.9.0: {} - - class-variance-authority@0.7.1: - dependencies: - clsx: 2.1.1 - - cli-cursor@2.1.0: - dependencies: - restore-cursor: 2.0.0 - - cli-cursor@3.1.0: - dependencies: - restore-cursor: 3.1.0 - - cli-spinners@2.9.2: {} - - client-only@0.0.1: {} - - cliui@6.0.0: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - clone@1.0.4: {} - - clsx@2.1.1: {} - - collapse-white-space@2.1.0: {} - - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.3: {} - - color-name@1.1.4: {} - - colorette@1.4.0: {} - - comma-separated-tokens@2.0.3: {} - - command-exists@1.2.9: {} - - commander@12.1.0: {} - - commander@2.20.3: {} - - commander@7.2.0: {} - - commander@9.5.0: {} - - compressible@2.0.18: - dependencies: - mime-db: 1.54.0 - - compression@1.8.1: - dependencies: - bytes: 3.1.2 - compressible: 2.0.18 - debug: 2.6.9 - negotiator: 0.6.4 - on-headers: 1.1.0 - safe-buffer: 5.2.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - compute-scroll-into-view@3.1.1: {} - - concat-map@0.0.1: {} - - connect@3.7.0: - dependencies: - debug: 2.6.9 - finalhandler: 1.1.2 - parseurl: 1.3.3 - utils-merge: 1.0.1 - transitivePeerDependencies: - - supports-color - - content-disposition@1.1.0: {} - - content-type@1.0.5: {} - - content-type@2.0.0: {} - - convert-source-map@2.0.0: {} - - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - - core-js-compat@3.49.0: - dependencies: - browserslist: 4.28.2 - - cors@2.8.6: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - - cosmiconfig@9.0.2(typescript@6.0.3): - dependencies: - env-paths: 2.2.1 - import-fresh: 3.3.1 - js-yaml: 4.3.0 - parse-json: 5.2.0 - optionalDependencies: - typescript: 6.0.3 - - cross-fetch@3.2.0: - dependencies: - node-fetch: 2.7.0 - transitivePeerDependencies: - - encoding - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - css-in-js-utils@3.1.0: - dependencies: - hyphenate-style-name: 1.1.0 - - csstype@3.2.3: {} - - data-view-buffer@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - data-view-byte-offset@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-data-view: 1.0.2 - - dayjs@1.11.21: {} - - debug@2.6.9: - dependencies: - ms: 2.0.0 - - debug@3.2.7: - dependencies: - ms: 2.1.3 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decamelize@1.2.0: {} - - decode-named-character-reference@1.3.0: - dependencies: - character-entities: 2.0.2 - - deep-is@0.1.4: {} - - deepmerge@4.3.1: {} - - defaults@1.0.4: - dependencies: - clone: 1.0.4 - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - depd@2.0.0: {} - - dequal@2.0.3: {} - - destroy@1.2.0: {} - - detect-libc@2.1.2: {} - - detect-node-es@1.1.0: {} - - devlop@1.1.0: - dependencies: - dequal: 2.0.3 - - dnssd-advertise@1.1.6: {} - - doctrine@2.1.0: - dependencies: - esutils: 2.0.3 - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - ee-first@1.1.1: {} - - electron-to-chromium@1.5.361: {} - - emoji-regex@8.0.0: {} - - encodeurl@1.0.2: {} - - encodeurl@2.0.0: {} - - enhanced-resolve@5.22.1: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.3 - - entities@4.5.0: {} - - entities@6.0.1: {} - - env-paths@2.2.1: {} - - envinfo@7.21.0: {} - - error-ex@1.3.4: - dependencies: - is-arrayish: 0.2.1 - - error-stack-parser@2.1.4: - dependencies: - stackframe: 1.3.4 - - errorhandler@1.5.2: - dependencies: - accepts: 1.3.8 - escape-html: 1.0.3 - - es-abstract@1.24.2: - dependencies: - array-buffer-byte-length: 1.0.2 - arraybuffer.prototype.slice: 1.0.4 - available-typed-arrays: 1.0.7 - call-bind: 1.0.9 - call-bound: 1.0.4 - data-view-buffer: 1.0.2 - data-view-byte-length: 1.0.2 - data-view-byte-offset: 1.0.1 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - get-symbol-description: 1.1.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.3 - internal-slot: 1.1.0 - is-array-buffer: 3.0.5 - is-callable: 1.2.7 - is-data-view: 1.0.2 - is-negative-zero: 2.0.3 - is-regex: 1.2.1 - is-set: 2.0.3 - is-shared-array-buffer: 1.0.4 - is-string: 1.1.1 - is-typed-array: 1.1.15 - is-weakref: 1.1.1 - math-intrinsics: 1.1.0 - object-inspect: 1.13.4 - object-keys: 1.1.1 - object.assign: 4.1.7 - own-keys: 1.0.1 - regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.4 - safe-push-apply: 1.0.0 - safe-regex-test: 1.1.0 - set-proto: 1.0.0 - stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.3 - typed-array-byte-length: 1.0.3 - typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 - unbox-primitive: 1.1.0 - which-typed-array: 1.1.20 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-iterator-helpers@1.3.2: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-set-tostringtag: 2.1.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - globalthis: 1.0.4 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - has-proto: 1.2.0 - has-symbols: 1.1.0 - internal-slot: 1.1.0 - iterator.prototype: 1.1.5 - math-intrinsics: 1.1.0 - - es-module-lexer@2.1.0: {} - - es-object-atoms@1.1.2: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.3 - - es-shim-unscopables@1.1.0: - dependencies: - hasown: 2.0.3 - - es-to-primitive@1.3.0: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.1.0 - is-symbol: 1.1.1 - - esast-util-from-estree@2.0.0: - dependencies: - '@types/estree-jsx': 1.0.5 - devlop: 1.1.0 - estree-util-visit: 2.0.0 - unist-util-position-from-estree: 2.0.0 - - esast-util-from-js@2.0.1: - dependencies: - '@types/estree-jsx': 1.0.5 - acorn: 8.16.0 - esast-util-from-estree: 2.0.0 - vfile-message: 4.0.3 - - esbuild@0.28.1: - optionalDependencies: - '@esbuild/aix-ppc64': 0.28.1 - '@esbuild/android-arm': 0.28.1 - '@esbuild/android-arm64': 0.28.1 - '@esbuild/android-x64': 0.28.1 - '@esbuild/darwin-arm64': 0.28.1 - '@esbuild/darwin-x64': 0.28.1 - '@esbuild/freebsd-arm64': 0.28.1 - '@esbuild/freebsd-x64': 0.28.1 - '@esbuild/linux-arm': 0.28.1 - '@esbuild/linux-arm64': 0.28.1 - '@esbuild/linux-ia32': 0.28.1 - '@esbuild/linux-loong64': 0.28.1 - '@esbuild/linux-mips64el': 0.28.1 - '@esbuild/linux-ppc64': 0.28.1 - '@esbuild/linux-riscv64': 0.28.1 - '@esbuild/linux-s390x': 0.28.1 - '@esbuild/linux-x64': 0.28.1 - '@esbuild/netbsd-arm64': 0.28.1 - '@esbuild/netbsd-x64': 0.28.1 - '@esbuild/openbsd-arm64': 0.28.1 - '@esbuild/openbsd-x64': 0.28.1 - '@esbuild/openharmony-arm64': 0.28.1 - '@esbuild/sunos-x64': 0.28.1 - '@esbuild/win32-arm64': 0.28.1 - '@esbuild/win32-ia32': 0.28.1 - '@esbuild/win32-x64': 0.28.1 - - escalade@3.2.0: {} - - escape-html@1.0.3: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@4.0.0: {} - - escape-string-regexp@5.0.0: {} - - eslint-config-expo@56.0.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - eslint: 9.39.4(jiti@2.7.0) - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-expo: 1.0.3(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) - eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) - globals: 16.5.0 - transitivePeerDependencies: - - eslint-import-resolver-webpack - - eslint-plugin-import-x - - supports-color - - typescript - - eslint-import-resolver-node@0.3.10: - dependencies: - debug: 3.2.7 - is-core-module: 2.16.2 - resolve: 2.0.0-next.7 - transitivePeerDependencies: - - supports-color - - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.3 - eslint: 9.39.4(jiti@2.7.0) - get-tsconfig: 4.14.0 - is-bun-module: 2.0.0 - stable-hash: 0.0.5 - tinyglobby: 0.2.16 - unrs-resolver: 1.12.2 - optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - eslint: 9.39.4(jiti@2.7.0) - eslint-import-resolver-node: 0.3.10 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) - transitivePeerDependencies: - - supports-color - - eslint-plugin-expo@1.0.3(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3): - dependencies: - '@typescript-eslint/types': 8.59.4 - '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - eslint: 9.39.4(jiti@2.7.0) - transitivePeerDependencies: - - supports-color - - typescript - - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.9 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 9.39.4(jiti@2.7.0) - eslint-import-resolver-node: 0.3.10 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) - hasown: 2.0.3 - is-core-module: 2.16.2 - is-glob: 4.0.3 - minimatch: 3.1.5 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@6.0.3) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - - eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): - dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 - eslint: 9.39.4(jiti@2.7.0) - hermes-parser: 0.25.1 - zod: 4.4.3 - zod-validation-error: 4.0.2(zod@4.4.3) - transitivePeerDependencies: - - supports-color - - eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)): - dependencies: - array-includes: 3.1.9 - array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.3 - array.prototype.tosorted: 1.1.4 - doctrine: 2.1.0 - es-iterator-helpers: 1.3.2 - eslint: 9.39.4(jiti@2.7.0) - estraverse: 5.3.0 - hasown: 2.0.3 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.5 - object.entries: 1.1.9 - object.fromentries: 2.0.8 - object.values: 1.2.1 - prop-types: 15.8.1 - resolve: 2.0.0-next.7 - semver: 6.3.1 - string.prototype.matchall: 4.0.12 - string.prototype.repeat: 1.0.0 - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint-visitor-keys@5.0.1: {} - - eslint@9.39.4(jiti@2.7.0): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.39.4 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.8 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.9 - ajv: 6.15.0 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.7.0 - transitivePeerDependencies: - - supports-color - - espree@10.4.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 4.2.1 - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - estree-util-attach-comments@3.0.0: - dependencies: - '@types/estree': 1.0.9 - - estree-util-build-jsx@3.0.1: - dependencies: - '@types/estree-jsx': 1.0.5 - devlop: 1.1.0 - estree-util-is-identifier-name: 3.0.0 - estree-walker: 3.0.3 - - estree-util-is-identifier-name@3.0.0: {} - - estree-util-scope@1.0.0: - dependencies: - '@types/estree': 1.0.9 - devlop: 1.1.0 - - estree-util-to-js@2.0.0: - dependencies: - '@types/estree-jsx': 1.0.5 - astring: 1.9.0 - source-map: 0.7.6 - - estree-util-value-to-estree@3.5.0: - dependencies: - '@types/estree': 1.0.9 - - estree-util-visit@2.0.0: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/unist': 3.0.3 - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.9 - - esutils@2.0.3: {} - - etag@1.8.1: {} - - event-target-shim@5.0.1: {} - - eventsource-parser@3.0.8: {} - - eventsource@3.0.7: - dependencies: - eventsource-parser: 3.0.8 - - execa@5.1.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - - expect-type@1.3.0: {} - - expo-asset@56.0.19(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3): - dependencies: - '@expo/image-utils': 0.10.2(typescript@6.0.3) - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-constants: 56.0.20(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - transitivePeerDependencies: - - supports-color - - typescript - - expo-constants@56.0.20(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)): - dependencies: - '@expo/env': 2.3.1 - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - transitivePeerDependencies: - - supports-color - - expo-dev-client@56.0.22(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)): - dependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-dev-launcher: 56.0.23(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - expo-dev-menu: 56.0.19(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - expo-dev-menu-interface: 56.0.1(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3)) - expo-manifests: 56.0.4(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3)) - expo-updates-interface: 56.0.2(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3)) - transitivePeerDependencies: - - react-native - - expo-dev-launcher@56.0.23(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)): - dependencies: - '@expo/schema-utils': 56.0.2 - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-dev-menu: 56.0.19(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - expo-manifests: 56.0.4(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3)) - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - expo-dev-menu-interface@56.0.1(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3)): - dependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - - expo-dev-menu@56.0.19(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)): - dependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-dev-menu-interface: 56.0.1(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3)) - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - expo-doctor@1.19.8: {} - - expo-file-system@56.0.8(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)): - dependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - expo-font@56.0.7(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): - dependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - fontfaceobserver: 2.3.0 - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - expo-json-utils@56.0.0: {} - - expo-keep-awake@56.0.3(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react@19.2.3): - dependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - react: 19.2.3 - - expo-manifests@56.0.4(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3)): - dependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-json-utils: 56.0.0 - - expo-mcp@0.2.4: - dependencies: - '@expo/mcp-tunnel': 0.2.4(@modelcontextprotocol/sdk@1.29.0) - '@modelcontextprotocol/sdk': 1.29.0 - debug: 4.4.3 - glob: 11.1.0 - jimp-compact: 0.16.1 - resolve-from: 5.0.0 - ws: 8.21.0 - xml2js: 0.6.2 - zod: 3.25.76 - zx: 8.8.5 - transitivePeerDependencies: - - '@cfworker/json-schema' - - bufferutil - - supports-color - - utf-8-validate - - expo-modules-autolinking@56.0.19(typescript@6.0.3): - dependencies: - '@expo/require-utils': 56.1.4(typescript@6.0.3) - '@expo/spawn-async': 1.8.0 - chalk: 4.1.2 - commander: 7.2.0 - transitivePeerDependencies: - - supports-color - - typescript - - expo-modules-core@56.0.20(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): - dependencies: - '@expo/expo-modules-macros-plugin': 0.2.2 - expo-modules-jsi: 56.0.12(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - invariant: 2.2.4 - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - expo-modules-jsi@56.0.12(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)): - dependencies: - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - expo-server@56.0.5: {} - - expo-splash-screen@56.0.12(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(typescript@6.0.3): - dependencies: - '@expo/config-plugins': 56.0.12(typescript@6.0.3) - '@expo/image-utils': 0.10.2(typescript@6.0.3) - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - xml2js: 0.6.0 - transitivePeerDependencies: - - supports-color - - typescript - - expo-sqlite@56.0.5(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): - dependencies: - await-lock: 2.2.2 - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - expo-system-ui@56.0.5(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)): - dependencies: - '@react-native/normalize-colors': 0.85.3 - debug: 4.4.3 - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - optionalDependencies: - react-native-web: 0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - transitivePeerDependencies: - - supports-color - - expo-updates-interface@56.0.2(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3)): - dependencies: - expo: 56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - - expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3): - dependencies: - '@babel/runtime': 7.29.2 - '@expo/cli': 56.1.19(30a5a05425671f97adee3495721168f0) - '@expo/config': 56.0.11(typescript@6.0.3) - '@expo/config-plugins': 56.0.12(typescript@6.0.3) - '@expo/devtools': 56.0.2(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - '@expo/dom-webview': 56.0.6(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - '@expo/fingerprint': 0.19.7 - '@expo/local-build-cache-provider': 56.0.9(typescript@6.0.3) - '@expo/log-box': 56.0.14(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - '@expo/metro': 56.0.0 - '@expo/metro-config': 56.0.16(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(typescript@6.0.3) - '@ungap/structured-clone': 1.3.1 - babel-preset-expo: 56.0.17(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-refresh@0.14.2) - expo-asset: 56.0.19(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3) - expo-constants: 56.0.20(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - expo-file-system: 56.0.8(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3)) - expo-font: 56.0.7(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - expo-keep-awake: 56.0.3(expo@56.0.15(@babel/core@7.29.0)(react-dom@19.2.3(react@19.2.3))(react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3)(typescript@6.0.3))(react@19.2.3) - expo-modules-autolinking: 56.0.19(typescript@6.0.3) - expo-modules-core: 56.0.20(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - pretty-format: 29.7.0 - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - react-refresh: 0.14.2 - whatwg-url-minimum: 0.1.2 - optionalDependencies: - react-dom: 19.2.3(react@19.2.3) - react-native-web: 0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - transitivePeerDependencies: - - '@babel/core' - - bufferutil - - expo-router - - expo-widgets - - react-native-worklets - - react-server-dom-webpack - - supports-color - - typescript - - utf-8-validate - - exponential-backoff@3.1.3: {} - - express-rate-limit@8.5.2(express@5.2.1): - dependencies: - express: 5.2.1 - ip-address: 10.2.0 - - express@5.2.1: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.2 - content-disposition: 1.1.0 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.3 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.1 - fresh: 2.0.0 - http-errors: 2.0.1 - merge-descriptors: 2.0.0 - mime-types: 3.0.2 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.15.2 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 - statuses: 2.0.2 - type-is: 2.1.0 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - extend@3.0.2: {} - - fast-deep-equal@3.1.3: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fast-uri@3.1.2: {} - - fast-xml-builder@1.3.0: - dependencies: - path-expression-matcher: 1.6.2 - xml-naming: 0.3.0 - - fast-xml-parser@5.10.1: - dependencies: - '@nodable/entities': 3.0.0 - fast-xml-builder: 1.3.0 - is-unsafe: 2.0.0 - path-expression-matcher: 1.6.2 - strnum: 2.4.1 - xml-naming: 0.3.0 - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - - fb-dotslash@0.5.8: {} - - fb-watchman@2.0.2: - dependencies: - bser: 2.1.1 - - fbjs-css-vars@1.0.2: {} - - fbjs@3.0.5: - dependencies: - cross-fetch: 3.2.0 - fbjs-css-vars: 1.0.2 - loose-envify: 1.4.0 - object-assign: 4.1.1 - promise: 7.3.1 - setimmediate: 1.0.5 - ua-parser-js: 1.0.41 - transitivePeerDependencies: - - encoding - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - fetch-nodeshim@0.4.10: {} - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - finalhandler@1.1.2: - dependencies: - debug: 2.6.9 - encodeurl: 1.0.2 - escape-html: 1.0.3 - on-finished: 2.3.0 - parseurl: 1.3.3 - statuses: 1.5.0 - unpipe: 1.0.0 - transitivePeerDependencies: - - supports-color - - finalhandler@2.1.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - - flatted@3.4.2: {} - - flow-enums-runtime@0.0.6: {} - - fontfaceobserver@2.3.0: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - forwarded@0.2.0: {} - - framer-motion@12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): - dependencies: - motion-dom: 12.40.0 - motion-utils: 12.39.0 - tslib: 2.8.1 - optionalDependencies: - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - - framer-motion@13.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): - dependencies: - motion-dom: 13.0.0 - motion-utils: 13.0.0 - tslib: 2.8.1 - optionalDependencies: - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - - fresh@0.5.2: {} - - fresh@2.0.0: {} - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fsevents@2.3.3: - optional: true - - fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.16)(lucide-react@1.17.0(react@19.2.7))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3): - dependencies: - '@orama/orama': 3.1.18 - estree-util-value-to-estree: 3.5.0 - github-slugger: 2.0.0 - hast-util-to-estree: 3.1.3 - hast-util-to-jsx-runtime: 2.3.6 - js-yaml: 4.3.0 - mdast-util-mdx: 3.0.0 - mdast-util-to-markdown: 2.1.2 - remark: 15.0.1 - remark-gfm: 4.0.1 - remark-rehype: 11.1.2 - scroll-into-view-if-needed: 3.1.0 - shiki: 4.1.0 - tinyglobby: 0.2.16 - unified: 11.0.5 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - optionalDependencies: - '@mdx-js/mdx': 3.1.1 - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@types/react': 19.2.16 - lucide-react: 1.17.0(react@19.2.7) - next: 16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - zod: 4.4.3 - transitivePeerDependencies: - - supports-color - - fumadocs-mdx@15.0.10(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.16)(fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.16)(lucide-react@1.17.0(react@19.2.7))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7): - dependencies: - '@mdx-js/mdx': 3.1.1 - '@standard-schema/spec': 1.1.0 - chokidar: 5.0.0 - esbuild: 0.28.1 - estree-util-value-to-estree: 3.5.0 - fumadocs-core: 16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.16)(lucide-react@1.17.0(react@19.2.7))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3) - js-yaml: 4.3.0 - mdast-util-mdx: 3.0.0 - picocolors: 1.1.1 - picomatch: 4.0.4 - tinyexec: 1.2.4 - tinyglobby: 0.2.16 - unified: 11.0.5 - unist-util-remove-position: 5.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - zod: 4.4.3 - optionalDependencies: - '@types/mdast': 4.0.4 - '@types/mdx': 2.0.13 - '@types/react': 19.2.16 - next: 16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - react: 19.2.7 - transitivePeerDependencies: - - supports-color - - fumadocs-ui@16.9.3(@tailwindcss/oxide@4.3.0)(@types/mdx@2.0.13)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(fumadocs-core@16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.16)(lucide-react@1.17.0(react@19.2.7))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@4.3.0): - dependencies: - '@fumadocs/tailwind': 0.0.5(@tailwindcss/oxide@4.3.0)(tailwindcss@4.3.0) - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.16)(react@19.2.7) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - class-variance-authority: 0.7.1 - fumadocs-core: 16.9.3(@mdx-js/mdx@3.1.1)(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.16)(lucide-react@1.17.0(react@19.2.7))(next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.4.3) - lucide-react: 1.17.0(react@19.2.7) - motion: 12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - next-themes: 0.4.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - react-remove-scroll: 2.7.2(@types/react@19.2.16)(react@19.2.7) - rehype-raw: 7.0.0 - scroll-into-view-if-needed: 3.1.0 - shiki: 4.1.0 - tailwind-merge: 3.6.0 - unist-util-visit: 5.1.0 - optionalDependencies: - '@types/mdx': 2.0.13 - '@types/react': 19.2.16 - next: 16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - transitivePeerDependencies: - - '@emotion/is-prop-valid' - - '@tailwindcss/oxide' - - '@types/react-dom' - - tailwindcss - - function-bind@1.1.2: {} - - function.prototype.name@1.1.8: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - functions-have-names: 1.2.3 - hasown: 2.0.3 - is-callable: 1.2.7 - - functions-have-names@1.2.3: {} - - fzstd@0.1.1: {} - - generator-function@2.0.1: {} - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.3 - math-intrinsics: 1.1.0 - - get-nonce@1.0.1: {} - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.2 - - get-stream@6.0.1: {} - - get-symbol-description@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - - get-tsconfig@4.14.0: - dependencies: - resolve-pkg-maps: 1.0.0 - - getenv@2.0.0: {} - - github-slugger@2.0.0: {} - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob@11.1.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 4.2.3 - minimatch: 10.2.5 - minipass: 7.1.3 - package-json-from-dist: 1.0.1 - path-scurry: 2.0.2 - - glob@13.0.6: - dependencies: - minimatch: 10.2.5 - minipass: 7.1.3 - path-scurry: 2.0.2 - - globals@14.0.0: {} - - globals@16.5.0: {} - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} - - has-bigints@1.1.0: {} - - has-flag@3.0.0: {} - - has-flag@4.0.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-proto@1.2.0: - dependencies: - dunder-proto: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.3: - dependencies: - function-bind: 1.1.2 - - hast-util-from-parse5@8.0.3: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - devlop: 1.1.0 - hastscript: 9.0.1 - property-information: 7.1.0 - vfile: 6.0.3 - vfile-location: 5.0.3 - web-namespaces: 2.0.1 - - hast-util-parse-selector@4.0.0: - dependencies: - '@types/hast': 3.0.4 - - hast-util-raw@9.1.0: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - '@ungap/structured-clone': 1.3.1 - hast-util-from-parse5: 8.0.3 - hast-util-to-parse5: 8.0.1 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - parse5: 7.3.0 - unist-util-position: 5.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - - hast-util-to-estree@3.1.3: - dependencies: - '@types/estree': 1.0.9 - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - estree-util-attach-comments: 3.0.0 - estree-util-is-identifier-name: 3.0.0 - hast-util-whitespace: 3.0.0 - mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 - mdast-util-mdxjs-esm: 2.0.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - style-to-js: 1.1.21 - unist-util-position: 5.0.0 - zwitch: 2.0.4 - transitivePeerDependencies: - - supports-color - - hast-util-to-html@9.0.5: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - comma-separated-tokens: 2.0.3 - hast-util-whitespace: 3.0.0 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - stringify-entities: 4.0.4 - zwitch: 2.0.4 - - hast-util-to-jsx-runtime@2.3.6: - dependencies: - '@types/estree': 1.0.9 - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - estree-util-is-identifier-name: 3.0.0 - hast-util-whitespace: 3.0.0 - mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 - mdast-util-mdxjs-esm: 2.0.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - style-to-js: 1.1.21 - unist-util-position: 5.0.0 - vfile-message: 4.0.3 - transitivePeerDependencies: - - supports-color - - hast-util-to-parse5@8.0.1: - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - - hast-util-whitespace@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hastscript@9.0.1: - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - hast-util-parse-selector: 4.0.0 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - - hermes-compiler@250829098.0.10: {} - - hermes-estree@0.25.1: {} - - hermes-estree@0.33.3: {} - - hermes-estree@0.35.0: {} - - hermes-parser@0.25.1: - dependencies: - hermes-estree: 0.25.1 - - hermes-parser@0.33.3: - dependencies: - hermes-estree: 0.33.3 - - hermes-parser@0.35.0: - dependencies: - hermes-estree: 0.35.0 - - hono@4.12.22: {} - - hosted-git-info@7.0.2: - dependencies: - lru-cache: 10.4.3 - - html-escaper@2.0.2: {} - - html-void-elements@3.0.0: {} - - http-errors@2.0.1: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - human-signals@2.1.0: {} - - hyphenate-style-name@1.1.0: {} - - iconv-lite@0.7.2: - dependencies: - safer-buffer: 2.1.2 - - ieee754@1.2.1: {} - - ignore@5.3.2: {} - - ignore@7.0.5: {} - - image-size@1.2.1: - dependencies: - queue: 6.0.2 - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - imurmurhash@0.1.4: {} - - inherits@2.0.4: {} - - inline-style-parser@0.2.7: {} - - inline-style-prefixer@7.0.1: - dependencies: - css-in-js-utils: 3.1.0 - - internal-slot@1.1.0: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.3 - side-channel: 1.1.0 - - invariant@2.2.4: - dependencies: - loose-envify: 1.4.0 - - ip-address@10.2.0: {} - - ipaddr.js@1.9.1: {} - - is-alphabetical@2.0.1: {} - - is-alphanumerical@2.0.1: - dependencies: - is-alphabetical: 2.0.1 - is-decimal: 2.0.1 - - is-array-buffer@3.0.5: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - is-arrayish@0.2.1: {} - - is-async-function@2.1.1: - dependencies: - async-function: 1.0.0 - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-bigint@1.1.0: - dependencies: - has-bigints: 1.1.0 - - is-boolean-object@1.2.2: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-bun-module@2.0.0: - dependencies: - semver: 7.8.1 - - is-callable@1.2.7: {} - - is-core-module@2.16.2: - dependencies: - hasown: 2.0.3 - - is-data-view@1.0.2: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - is-typed-array: 1.1.15 - - is-date-object@1.1.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-decimal@2.0.1: {} - - is-docker@2.2.1: {} - - is-extglob@2.1.1: {} - - is-finalizationregistry@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-fullwidth-code-point@2.0.0: {} - - is-fullwidth-code-point@3.0.0: {} - - is-generator-function@1.1.2: - dependencies: - call-bound: 1.0.4 - generator-function: 2.0.1 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-hexadecimal@2.0.1: {} - - is-interactive@1.0.0: {} - - is-map@2.0.3: {} - - is-negative-zero@2.0.3: {} - - is-number-object@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-number@7.0.0: {} - - is-plain-obj@4.1.0: {} - - is-promise@4.0.0: {} - - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.3 - - is-set@2.0.3: {} - - is-shared-array-buffer@1.0.4: - dependencies: - call-bound: 1.0.4 - - is-stream@2.0.1: {} - - is-string@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-symbol@1.1.1: - dependencies: - call-bound: 1.0.4 - has-symbols: 1.1.0 - safe-regex-test: 1.1.0 - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.20 - - is-unicode-supported@0.1.0: {} - - is-unsafe@2.0.0: {} - - is-weakmap@2.0.2: {} - - is-weakref@1.1.1: - dependencies: - call-bound: 1.0.4 - - is-weakset@2.0.4: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - is-wsl@1.1.0: {} - - is-wsl@2.2.0: - dependencies: - is-docker: 2.2.1 - - isarray@2.0.5: {} - - isexe@2.0.0: {} - - istanbul-lib-coverage@3.2.2: {} - - istanbul-lib-report@3.0.1: - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - - istanbul-reports@3.2.0: - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - - iterator.prototype@1.1.5: - dependencies: - define-data-property: 1.1.4 - es-object-atoms: 1.1.2 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - has-symbols: 1.1.0 - set-function-name: 2.0.2 - - jackspeak@4.2.3: - dependencies: - '@isaacs/cliui': 9.0.0 - - jest-get-type@29.6.3: {} - - jest-util@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/node': 24.12.4 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.2 - - jest-validate@29.7.0: - dependencies: - '@jest/types': 29.6.3 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 29.6.3 - leven: 3.1.0 - pretty-format: 29.7.0 - - jest-worker@29.7.0: - dependencies: - '@types/node': 24.12.4 - jest-util: 29.7.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - - jimp-compact@0.16.1: {} - - jiti@2.7.0: {} - - joi@17.13.4: - dependencies: - '@hapi/hoek': 9.3.0 - '@hapi/topo': 5.1.0 - '@sideway/address': 4.1.5 - '@sideway/formula': 3.0.1 - '@sideway/pinpoint': 2.0.0 - - jose@6.2.3: {} - - js-tokens@10.0.0: {} - - js-tokens@4.0.0: {} - - js-yaml@4.3.0: - dependencies: - argparse: 2.0.1 - - jsc-safe-url@0.2.4: {} - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-parse-even-better-errors@2.3.1: {} - - json-schema-traverse@0.4.1: {} - - json-schema-traverse@1.0.0: {} - - json-schema-typed@8.0.2: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@1.0.2: - dependencies: - minimist: 1.2.8 - - json5@2.2.3: {} - - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - - jsx-ast-utils@3.3.5: - dependencies: - array-includes: 3.1.9 - array.prototype.flat: 1.3.3 - object.assign: 4.1.7 - object.values: 1.2.1 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - kleur@3.0.3: {} - - lan-network@0.2.1: {} - - launch-editor@2.14.1: - dependencies: - picocolors: 1.1.1 - shell-quote: 1.8.4 - - leven@3.1.0: {} - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - lighthouse-logger@1.4.2: - dependencies: - debug: 2.6.9 - marky: 1.3.0 - transitivePeerDependencies: - - supports-color - - lightningcss-android-arm64@1.32.0: - optional: true - - lightningcss-darwin-arm64@1.32.0: - optional: true - - lightningcss-darwin-x64@1.32.0: - optional: true - - lightningcss-freebsd-x64@1.32.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.32.0: - optional: true - - lightningcss-linux-arm64-gnu@1.32.0: - optional: true - - lightningcss-linux-arm64-musl@1.32.0: - optional: true - - lightningcss-linux-x64-gnu@1.32.0: - optional: true - - lightningcss-linux-x64-musl@1.32.0: - optional: true - - lightningcss-win32-arm64-msvc@1.32.0: - optional: true - - lightningcss-win32-x64-msvc@1.32.0: - optional: true - - lightningcss@1.32.0: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 - - lines-and-columns@1.2.4: {} - - linkify-it@5.0.1: - dependencies: - uc.micro: 2.1.0 - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.debounce@4.0.8: {} - - lodash.merge@4.6.2: {} - - lodash.throttle@4.1.1: {} - - log-symbols@2.2.0: - dependencies: - chalk: 2.4.2 - - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - logkitty@0.7.1: - dependencies: - ansi-fragments: 0.2.1 - dayjs: 1.11.21 - yargs: 15.4.1 - - longest-streak@3.1.0: {} - - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - - lru-cache@10.4.3: {} - - lru-cache@11.5.0: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lucide-react@1.17.0(react@19.2.7): - dependencies: - react: 19.2.7 - - lunr@2.3.9: {} - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - magicast@0.5.3: - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - source-map-js: 1.2.1 - - make-dir@4.0.0: - dependencies: - semver: 7.8.1 - - makeerror@1.0.12: - dependencies: - tmpl: 1.0.5 - - markdown-extensions@2.0.0: {} - - markdown-it@14.2.0: - dependencies: - argparse: 2.0.1 - entities: 4.5.0 - linkify-it: 5.0.1 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - - markdown-table@3.0.4: {} - - marky@1.3.0: {} - - math-intrinsics@1.1.0: {} - - mdast-util-find-and-replace@3.0.2: - dependencies: - '@types/mdast': 4.0.4 - escape-string-regexp: 5.0.0 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - mdast-util-from-markdown@2.0.3: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - mdast-util-to-string: 4.0.0 - micromark: 4.0.2 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-decode-string: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - unist-util-stringify-position: 4.0.0 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-autolink-literal@2.0.1: - dependencies: - '@types/mdast': 4.0.4 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-find-and-replace: 3.0.2 - micromark-util-character: 2.1.1 - - mdast-util-gfm-footnote@2.1.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - micromark-util-normalize-identifier: 2.0.1 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-strikethrough@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-table@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm-task-list-item@2.0.0: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-gfm@3.1.0: - dependencies: - mdast-util-from-markdown: 2.0.3 - mdast-util-gfm-autolink-literal: 2.0.1 - mdast-util-gfm-footnote: 2.1.0 - mdast-util-gfm-strikethrough: 2.0.0 - mdast-util-gfm-table: 2.0.0 - mdast-util-gfm-task-list-item: 2.0.0 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-mdx-expression@2.0.1: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-mdx-jsx@3.2.0: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - parse-entities: 4.0.2 - stringify-entities: 4.0.4 - unist-util-stringify-position: 4.0.0 - vfile-message: 4.0.3 - transitivePeerDependencies: - - supports-color - - mdast-util-mdx@3.0.0: - dependencies: - mdast-util-from-markdown: 2.0.3 - mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 - mdast-util-mdxjs-esm: 2.0.1 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-mdxjs-esm@2.0.1: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - devlop: 1.1.0 - mdast-util-from-markdown: 2.0.3 - mdast-util-to-markdown: 2.1.2 - transitivePeerDependencies: - - supports-color - - mdast-util-phrasing@4.1.0: - dependencies: - '@types/mdast': 4.0.4 - unist-util-is: 6.0.1 - - mdast-util-to-hast@13.2.1: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.1 - devlop: 1.1.0 - micromark-util-sanitize-uri: 2.0.1 - trim-lines: 3.0.1 - unist-util-position: 5.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - - mdast-util-to-markdown@2.1.2: - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - longest-streak: 3.1.0 - mdast-util-phrasing: 4.1.0 - mdast-util-to-string: 4.0.0 - micromark-util-classify-character: 2.0.1 - micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.1.0 - zwitch: 2.0.4 - - mdast-util-to-string@4.0.0: - dependencies: - '@types/mdast': 4.0.4 - - mdurl@2.0.0: {} - - media-typer@1.1.0: {} - - memoize-one@5.2.1: {} - - memoize-one@6.0.0: {} - - merge-descriptors@2.0.0: {} - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - metro-babel-transformer@0.84.4: - dependencies: - '@babel/core': 7.29.0 - flow-enums-runtime: 0.0.6 - hermes-parser: 0.35.0 - metro-cache-key: 0.84.4 - nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color - - metro-cache-key@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - - metro-cache@0.84.4: - dependencies: - exponential-backoff: 3.1.3 - flow-enums-runtime: 0.0.6 - https-proxy-agent: 7.0.6 - metro-core: 0.84.4 - transitivePeerDependencies: - - supports-color - - metro-config@0.84.4: - dependencies: - connect: 3.7.0 - flow-enums-runtime: 0.0.6 - jest-validate: 29.7.0 - metro: 0.84.4 - metro-cache: 0.84.4 - metro-core: 0.84.4 - metro-runtime: 0.84.4 - yaml: 2.9.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - metro-core@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - lodash.throttle: 4.1.1 - metro-resolver: 0.84.4 - - metro-file-map@0.84.4: - dependencies: - debug: 4.4.3 - fb-watchman: 2.0.2 - flow-enums-runtime: 0.0.6 - graceful-fs: 4.2.11 - invariant: 2.2.4 - jest-worker: 29.7.0 - micromatch: 4.0.8 - nullthrows: 1.1.1 - walker: 1.0.8 - transitivePeerDependencies: - - supports-color - - metro-minify-terser@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - terser: 5.48.0 - - metro-resolver@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - - metro-runtime@0.84.4: - dependencies: - '@babel/runtime': 7.29.2 - flow-enums-runtime: 0.0.6 - - metro-source-map@0.84.4: - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - flow-enums-runtime: 0.0.6 - invariant: 2.2.4 - metro-symbolicate: 0.84.4 - nullthrows: 1.1.1 - ob1: 0.84.4 - source-map: 0.5.7 - vlq: 1.0.1 - transitivePeerDependencies: - - supports-color - - metro-symbolicate@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - invariant: 2.2.4 - metro-source-map: 0.84.4 - nullthrows: 1.1.1 - source-map: 0.5.7 - vlq: 1.0.1 - transitivePeerDependencies: - - supports-color - - metro-transform-plugins@0.84.4: - dependencies: - '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - flow-enums-runtime: 0.0.6 - nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color - - metro-transform-worker@0.84.4: - dependencies: - '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - flow-enums-runtime: 0.0.6 - metro: 0.84.4 - metro-babel-transformer: 0.84.4 - metro-cache: 0.84.4 - metro-cache-key: 0.84.4 - metro-minify-terser: 0.84.4 - metro-source-map: 0.84.4 - metro-transform-plugins: 0.84.4 - nullthrows: 1.1.1 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - metro@0.84.4: - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/core': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - accepts: 2.0.0 - ci-info: 2.0.0 - connect: 3.7.0 - debug: 4.4.3 - error-stack-parser: 2.1.4 - flow-enums-runtime: 0.0.6 - graceful-fs: 4.2.11 - hermes-parser: 0.35.0 - image-size: 1.2.1 - invariant: 2.2.4 - jest-worker: 29.7.0 - jsc-safe-url: 0.2.4 - lodash.throttle: 4.1.1 - metro-babel-transformer: 0.84.4 - metro-cache: 0.84.4 - metro-cache-key: 0.84.4 - metro-config: 0.84.4 - metro-core: 0.84.4 - metro-file-map: 0.84.4 - metro-resolver: 0.84.4 - metro-runtime: 0.84.4 - metro-source-map: 0.84.4 - metro-symbolicate: 0.84.4 - metro-transform-plugins: 0.84.4 - metro-transform-worker: 0.84.4 - mime-types: 3.0.2 - nullthrows: 1.1.1 - serialize-error: 2.1.0 - source-map: 0.5.7 - throat: 5.0.0 - ws: 7.5.11 - yargs: 17.7.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - micromark-core-commonmark@2.0.3: - dependencies: - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-factory-destination: 2.0.1 - micromark-factory-label: 2.0.1 - micromark-factory-space: 2.0.1 - micromark-factory-title: 2.0.1 - micromark-factory-whitespace: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-classify-character: 2.0.1 - micromark-util-html-tag-name: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-autolink-literal@2.1.0: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-footnote@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-strikethrough@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-util-chunked: 2.0.1 - micromark-util-classify-character: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-table@2.1.1: - dependencies: - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm-tagfilter@2.0.0: - dependencies: - micromark-util-types: 2.0.2 - - micromark-extension-gfm-task-list-item@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-gfm@3.0.0: - dependencies: - micromark-extension-gfm-autolink-literal: 2.1.0 - micromark-extension-gfm-footnote: 2.1.0 - micromark-extension-gfm-strikethrough: 2.1.0 - micromark-extension-gfm-table: 2.1.1 - micromark-extension-gfm-tagfilter: 2.0.0 - micromark-extension-gfm-task-list-item: 2.1.0 - micromark-util-combine-extensions: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-mdx-expression@3.0.1: - dependencies: - '@types/estree': 1.0.9 - devlop: 1.1.0 - micromark-factory-mdx-expression: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-events-to-acorn: 2.0.3 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-extension-mdx-jsx@3.0.2: - dependencies: - '@types/estree': 1.0.9 - devlop: 1.1.0 - estree-util-is-identifier-name: 3.0.0 - micromark-factory-mdx-expression: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-events-to-acorn: 2.0.3 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - vfile-message: 4.0.3 - - micromark-extension-mdx-md@2.0.0: - dependencies: - micromark-util-types: 2.0.2 - - micromark-extension-mdxjs-esm@3.0.0: - dependencies: - '@types/estree': 1.0.9 - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-util-character: 2.1.1 - micromark-util-events-to-acorn: 2.0.3 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - unist-util-position-from-estree: 2.0.0 - vfile-message: 4.0.3 - - micromark-extension-mdxjs@3.0.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - micromark-extension-mdx-expression: 3.0.1 - micromark-extension-mdx-jsx: 3.0.2 - micromark-extension-mdx-md: 2.0.0 - micromark-extension-mdxjs-esm: 3.0.0 - micromark-util-combine-extensions: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-destination@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-label@2.0.1: - dependencies: - devlop: 1.1.0 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-mdx-expression@2.0.3: - dependencies: - '@types/estree': 1.0.9 - devlop: 1.1.0 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-events-to-acorn: 2.0.3 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - unist-util-position-from-estree: 2.0.0 - vfile-message: 4.0.3 - - micromark-factory-space@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-types: 2.0.2 - - micromark-factory-title@2.0.1: - dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-factory-whitespace@2.0.1: - dependencies: - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-character@2.1.1: - dependencies: - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-chunked@2.0.1: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-classify-character@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-combine-extensions@2.0.1: - dependencies: - micromark-util-chunked: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-decode-numeric-character-reference@2.0.2: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-decode-string@2.0.1: - dependencies: - decode-named-character-reference: 1.3.0 - micromark-util-character: 2.1.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-symbol: 2.0.1 - - micromark-util-encode@2.0.1: {} - - micromark-util-events-to-acorn@2.0.3: - dependencies: - '@types/estree': 1.0.9 - '@types/unist': 3.0.3 - devlop: 1.1.0 - estree-util-visit: 2.0.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - vfile-message: 4.0.3 - - micromark-util-html-tag-name@2.0.1: {} - - micromark-util-normalize-identifier@2.0.1: - dependencies: - micromark-util-symbol: 2.0.1 - - micromark-util-resolve-all@2.0.1: - dependencies: - micromark-util-types: 2.0.2 - - micromark-util-sanitize-uri@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-encode: 2.0.1 - micromark-util-symbol: 2.0.1 - - micromark-util-subtokenize@2.1.0: - dependencies: - devlop: 1.1.0 - micromark-util-chunked: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-symbol@2.0.1: {} - - micromark-util-types@2.0.2: {} - - micromark@4.0.2: - dependencies: - '@types/debug': 4.1.13 - debug: 4.4.3 - decode-named-character-reference: 1.3.0 - devlop: 1.1.0 - micromark-core-commonmark: 2.0.3 - micromark-factory-space: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-chunked: 2.0.1 - micromark-util-combine-extensions: 2.0.1 - micromark-util-decode-numeric-character-reference: 2.0.2 - micromark-util-encode: 2.0.1 - micromark-util-normalize-identifier: 2.0.1 - micromark-util-resolve-all: 2.0.1 - micromark-util-sanitize-uri: 2.0.1 - micromark-util-subtokenize: 2.1.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - transitivePeerDependencies: - - supports-color - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.2 - - mime-db@1.52.0: {} - - mime-db@1.54.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime-types@3.0.2: - dependencies: - mime-db: 1.54.0 - - mime@1.6.0: {} - - mime@2.6.0: {} - - mimic-fn@1.2.0: {} - - mimic-fn@2.1.0: {} - - minimatch@10.2.5: - dependencies: - brace-expansion: 5.0.6 - - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.14 - - minimist@1.2.8: {} - - minipass@7.1.3: {} - - mkdirp@1.0.4: {} - - motion-dom@12.40.0: - dependencies: - motion-utils: 12.39.0 - - motion-dom@13.0.0: - dependencies: - motion-utils: 13.0.0 - - motion-utils@12.39.0: {} - - motion-utils@13.0.0: {} - - motion@12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): - dependencies: - framer-motion: 12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - tslib: 2.8.1 - optionalDependencies: - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - - motion@13.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): - dependencies: - framer-motion: 13.1.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - tslib: 2.8.1 - optionalDependencies: - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - - ms@2.0.0: {} - - ms@2.1.3: {} - - multitars@1.0.0: {} - - nanoid@3.3.12: {} - - napi-postinstall@0.3.4: {} - - natural-compare@1.4.0: {} - - negotiator@0.6.3: {} - - negotiator@0.6.4: {} - - negotiator@1.0.0: {} - - next-themes@0.4.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7): - dependencies: - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - - next@16.2.7(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): - dependencies: - '@next/env': 16.2.7 - '@swc/helpers': 0.5.15 - baseline-browser-mapping: 2.10.32 - caniuse-lite: 1.0.30001793 - postcss: 8.5.15 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - styled-jsx: 5.1.6(react@19.2.7) - optionalDependencies: - '@next/swc-darwin-arm64': 16.2.7 - '@next/swc-darwin-x64': 16.2.7 - '@next/swc-linux-arm64-gnu': 16.2.7 - '@next/swc-linux-arm64-musl': 16.2.7 - '@next/swc-linux-x64-gnu': 16.2.7 - '@next/swc-linux-x64-musl': 16.2.7 - '@next/swc-win32-arm64-msvc': 16.2.7 - '@next/swc-win32-x64-msvc': 16.2.7 - babel-plugin-react-compiler: 1.0.0 - sharp: 0.34.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - nocache@3.0.4: {} - - node-api-headers@1.9.0: {} - - node-exports-info@1.6.0: - dependencies: - array.prototype.flatmap: 1.3.3 - es-errors: 1.3.0 - object.entries: 1.1.9 - semver: 6.3.1 - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-forge@1.4.0: {} - - node-int64@0.4.0: {} - - node-releases@2.0.46: {} - - node-stream-zip@1.15.0: {} - - npm-package-arg@11.0.3: - dependencies: - hosted-git-info: 7.0.2 - proc-log: 4.2.0 - semver: 7.8.1 - validate-npm-package-name: 5.0.1 - - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - - nullthrows@1.1.1: {} - - ob1@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - object-keys@1.1.1: {} - - object.assign@4.1.7: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.2 - has-symbols: 1.1.0 - object-keys: 1.1.1 - - object.entries@1.1.9: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.2 - - object.fromentries@2.0.8: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-object-atoms: 1.1.2 - - object.groupby@1.0.3: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - - object.values@1.2.1: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.2 - - obug@2.1.1: {} - - on-finished@2.3.0: - dependencies: - ee-first: 1.1.1 - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - on-headers@1.1.0: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@2.0.1: - dependencies: - mimic-fn: 1.2.0 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - oniguruma-parser@0.12.2: {} - - oniguruma-to-es@4.3.6: - dependencies: - oniguruma-parser: 0.12.2 - regex: 6.1.0 - regex-recursion: 6.0.2 - - open@6.4.0: - dependencies: - is-wsl: 1.1.0 - - open@7.4.2: - dependencies: - is-docker: 2.2.1 - is-wsl: 2.2.0 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - ora@3.4.0: - dependencies: - chalk: 2.4.2 - cli-cursor: 2.1.0 - cli-spinners: 2.9.2 - log-symbols: 2.2.0 - strip-ansi: 5.2.0 - wcwidth: 1.0.1 - - ora@5.4.1: - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - - own-keys@1.0.1: - dependencies: - get-intrinsic: 1.3.0 - object-keys: 1.1.1 - safe-push-apply: 1.0.0 - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - p-try@2.2.0: {} - - package-json-from-dist@1.0.1: {} - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-entities@4.0.2: - dependencies: - '@types/unist': 2.0.11 - character-entities-legacy: 3.0.0 - character-reference-invalid: 2.0.1 - decode-named-character-reference: 1.3.0 - is-alphanumerical: 2.0.1 - is-decimal: 2.0.1 - is-hexadecimal: 2.0.1 - - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.29.0 - error-ex: 1.3.4 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - - parse-png@2.1.0: - dependencies: - pngjs: 3.4.0 - - parse5@7.3.0: - dependencies: - entities: 6.0.1 - - parseurl@1.3.3: {} - - path-exists@4.0.0: {} - - path-expression-matcher@1.6.2: {} - - path-key@3.1.1: {} - - path-parse@1.0.7: {} - - path-scurry@2.0.2: - dependencies: - lru-cache: 11.5.0 - minipass: 7.1.3 - - path-to-regexp@8.4.2: {} - - pathe@2.0.3: {} - - picocolors@1.1.1: {} - - picomatch@2.3.2: {} - - picomatch@4.0.4: {} - - pkce-challenge@5.0.1: {} - - plist@3.1.1: - dependencies: - '@xmldom/xmldom': 0.9.10 - base64-js: 1.5.1 - xmlbuilder: 15.1.1 - - pngjs@3.4.0: {} - - possible-typed-array-names@1.1.0: {} - - postcss-value-parser@4.2.0: {} - - postcss@8.5.15: - dependencies: - nanoid: 3.3.12 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prelude-ls@1.2.1: {} - - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - proc-log@4.2.0: {} - - progress@2.0.3: {} - - promise@7.3.1: - dependencies: - asap: 2.0.6 - - promise@8.3.0: - dependencies: - asap: 2.0.6 - - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - - prop-types@15.8.1: - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - - property-information@7.1.0: {} - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - punycode.js@2.3.1: {} - - punycode@2.3.1: {} - - qs@6.15.2: - dependencies: - side-channel: 1.1.0 - - queue-microtask@1.2.3: {} - - queue@6.0.2: - dependencies: - inherits: 2.0.4 - - range-parser@1.2.1: {} - - raw-body@3.0.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - unpipe: 1.0.0 - - react-devtools-core@6.1.5: - dependencies: - shell-quote: 1.8.4 - ws: 7.5.11 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - react-dom@19.2.3(react@19.2.3): - dependencies: - react: 19.2.3 - scheduler: 0.27.0 - - react-dom@19.2.7(react@19.2.7): - dependencies: - react: 19.2.7 - scheduler: 0.27.0 - - react-is@16.13.1: {} - - react-is@18.3.1: {} - - react-native-safe-area-context@5.7.0(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3): - dependencies: - react: 19.2.3 - react-native: 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3) - - react-native-web@0.21.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - '@babel/runtime': 7.29.2 - '@react-native/normalize-colors': 0.74.89 - fbjs: 3.0.5 - inline-style-prefixer: 7.0.1 - memoize-one: 6.0.0 - nullthrows: 1.1.1 - postcss-value-parser: 4.2.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - styleq: 0.1.3 - transitivePeerDependencies: - - encoding - - react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3): - dependencies: - '@react-native/assets-registry': 0.85.3 - '@react-native/codegen': 0.85.3 - '@react-native/community-cli-plugin': 0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3) - '@react-native/gradle-plugin': 0.85.3 - '@react-native/js-polyfills': 0.85.3 - '@react-native/normalize-colors': 0.85.3 - '@react-native/virtualized-lists': 0.85.3(@types/react@19.2.16)(react-native@0.85.3(@react-native-community/cli@20.2.0(typescript@6.0.3))(@react-native/metro-config@0.85.3)(@types/react@19.2.16)(react@19.2.3))(react@19.2.3) - abort-controller: 3.0.0 - anser: 1.4.10 - ansi-regex: 5.0.1 - babel-plugin-syntax-hermes-parser: 0.33.3 - base64-js: 1.5.1 - commander: 12.1.0 - flow-enums-runtime: 0.0.6 - hermes-compiler: 250829098.0.10 - invariant: 2.2.4 - memoize-one: 5.2.1 - metro-runtime: 0.84.4 - metro-source-map: 0.84.4 - nullthrows: 1.1.1 - pretty-format: 29.7.0 - promise: 8.3.0 - react: 19.2.3 - react-devtools-core: 6.1.5 - react-refresh: 0.14.2 - regenerator-runtime: 0.13.11 - scheduler: 0.27.0 - semver: 7.8.1 - stacktrace-parser: 0.1.11 - tinyglobby: 0.2.16 - whatwg-fetch: 3.6.20 - ws: 7.5.11 - yargs: 17.7.2 - optionalDependencies: - '@types/react': 19.2.16 - transitivePeerDependencies: - - '@react-native-community/cli' - - '@react-native/metro-config' - - bufferutil - - supports-color - - utf-8-validate - - react-refresh@0.14.2: {} - - react-remove-scroll-bar@2.3.8(@types/react@19.2.16)(react@19.2.7): - dependencies: - react: 19.2.7 - react-style-singleton: 2.2.3(@types/react@19.2.16)(react@19.2.7) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.16 - - react-remove-scroll@2.7.2(@types/react@19.2.16)(react@19.2.7): - dependencies: - react: 19.2.7 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.16)(react@19.2.7) - react-style-singleton: 2.2.3(@types/react@19.2.16)(react@19.2.7) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.16)(react@19.2.7) - use-sidecar: 1.1.3(@types/react@19.2.16)(react@19.2.7) - optionalDependencies: - '@types/react': 19.2.16 - - react-style-singleton@2.2.3(@types/react@19.2.16)(react@19.2.7): - dependencies: - get-nonce: 1.0.1 - react: 19.2.7 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.16 - - react@19.2.3: {} - - react@19.2.7: {} - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - - readdirp@5.0.0: {} - - recma-build-jsx@1.0.0: - dependencies: - '@types/estree': 1.0.9 - estree-util-build-jsx: 3.0.1 - vfile: 6.0.3 - - recma-jsx@1.0.1(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - estree-util-to-js: 2.0.0 - recma-parse: 1.0.0 - recma-stringify: 1.0.0 - unified: 11.0.5 - - recma-parse@1.0.0: - dependencies: - '@types/estree': 1.0.9 - esast-util-from-js: 2.0.1 - unified: 11.0.5 - vfile: 6.0.3 - - recma-stringify@1.0.0: - dependencies: - '@types/estree': 1.0.9 - estree-util-to-js: 2.0.0 - unified: 11.0.5 - vfile: 6.0.3 - - reflect.getprototypeof@1.0.10: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - get-intrinsic: 1.3.0 - get-proto: 1.0.1 - which-builtin-type: 1.2.1 - - regenerate-unicode-properties@10.2.2: - dependencies: - regenerate: 1.4.2 - - regenerate@1.4.2: {} - - regenerator-runtime@0.13.11: {} - - regex-recursion@6.0.2: - dependencies: - regex-utilities: 2.3.0 - - regex-utilities@2.3.0: {} - - regex@6.1.0: - dependencies: - regex-utilities: 2.3.0 - - regexp.prototype.flags@1.5.4: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-errors: 1.3.0 - get-proto: 1.0.1 - gopd: 1.2.0 - set-function-name: 2.0.2 - - regexpu-core@6.4.0: - dependencies: - regenerate: 1.4.2 - regenerate-unicode-properties: 10.2.2 - regjsgen: 0.8.0 - regjsparser: 0.13.1 - unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.2.1 - - regjsgen@0.8.0: {} - - regjsparser@0.13.1: - dependencies: - jsesc: 3.1.0 - - rehype-raw@7.0.0: - dependencies: - '@types/hast': 3.0.4 - hast-util-raw: 9.1.0 - vfile: 6.0.3 - - rehype-recma@1.0.0: - dependencies: - '@types/estree': 1.0.9 - '@types/hast': 3.0.4 - hast-util-to-estree: 3.1.3 - transitivePeerDependencies: - - supports-color - - remark-gfm@4.0.1: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-gfm: 3.1.0 - micromark-extension-gfm: 3.0.0 - remark-parse: 11.0.0 - remark-stringify: 11.0.0 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - - remark-mdx@3.1.1: - dependencies: - mdast-util-mdx: 3.0.0 - micromark-extension-mdxjs: 3.0.0 - transitivePeerDependencies: - - supports-color - - remark-parse@11.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.3 - micromark-util-types: 2.0.2 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - - remark-rehype@11.1.2: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - mdast-util-to-hast: 13.2.1 - unified: 11.0.5 - vfile: 6.0.3 - - remark-stringify@11.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-to-markdown: 2.1.2 - unified: 11.0.5 - - remark@15.0.1: - dependencies: - '@types/mdast': 4.0.4 - remark-parse: 11.0.0 - remark-stringify: 11.0.0 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - - require-directory@2.1.1: {} - - require-from-string@2.0.2: {} - - require-main-filename@2.0.0: {} - - resolve-from@4.0.0: {} - - resolve-from@5.0.0: {} - - resolve-pkg-maps@1.0.0: {} - - resolve-workspace-root@2.0.1: {} - - resolve@1.22.12: - dependencies: - es-errors: 1.3.0 - is-core-module: 2.16.2 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - resolve@2.0.0-next.7: - dependencies: - es-errors: 1.3.0 - is-core-module: 2.16.2 - node-exports-info: 1.6.0 - object-keys: 1.1.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - restore-cursor@2.0.0: - dependencies: - onetime: 2.0.1 - signal-exit: 3.0.7 - - restore-cursor@3.1.0: - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - - reusify@1.1.0: {} - - rollup@4.60.4: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.4 - '@rollup/rollup-android-arm64': 4.60.4 - '@rollup/rollup-darwin-arm64': 4.60.4 - '@rollup/rollup-darwin-x64': 4.60.4 - '@rollup/rollup-freebsd-arm64': 4.60.4 - '@rollup/rollup-freebsd-x64': 4.60.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 - '@rollup/rollup-linux-arm-musleabihf': 4.60.4 - '@rollup/rollup-linux-arm64-gnu': 4.60.4 - '@rollup/rollup-linux-arm64-musl': 4.60.4 - '@rollup/rollup-linux-loong64-gnu': 4.60.4 - '@rollup/rollup-linux-loong64-musl': 4.60.4 - '@rollup/rollup-linux-ppc64-gnu': 4.60.4 - '@rollup/rollup-linux-ppc64-musl': 4.60.4 - '@rollup/rollup-linux-riscv64-gnu': 4.60.4 - '@rollup/rollup-linux-riscv64-musl': 4.60.4 - '@rollup/rollup-linux-s390x-gnu': 4.60.4 - '@rollup/rollup-linux-x64-gnu': 4.60.4 - '@rollup/rollup-linux-x64-musl': 4.60.4 - '@rollup/rollup-openbsd-x64': 4.60.4 - '@rollup/rollup-openharmony-arm64': 4.60.4 - '@rollup/rollup-win32-arm64-msvc': 4.60.4 - '@rollup/rollup-win32-ia32-msvc': 4.60.4 - '@rollup/rollup-win32-x64-gnu': 4.60.4 - '@rollup/rollup-win32-x64-msvc': 4.60.4 - fsevents: 2.3.3 - - router@2.2.0: - dependencies: - debug: 4.4.3 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.4.2 - transitivePeerDependencies: - - supports-color - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-array-concat@1.1.4: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - isarray: 2.0.5 - - safe-buffer@5.2.1: {} - - safe-push-apply@1.0.0: - dependencies: - es-errors: 1.3.0 - isarray: 2.0.5 - - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - - safer-buffer@2.1.2: {} - - sax@1.6.0: {} - - scheduler@0.27.0: {} - - scroll-into-view-if-needed@3.1.0: - dependencies: - compute-scroll-into-view: 3.1.1 - - semver@6.3.1: {} - - semver@7.8.1: {} - - send@0.19.2: - dependencies: - debug: 2.6.9 - depd: 2.0.0 - destroy: 1.2.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 0.5.2 - http-errors: 2.0.1 - mime: 1.6.0 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - send@1.2.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.1 - mime-types: 3.0.2 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - serialize-error@2.1.0: {} - - serve-static@1.16.3: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 0.19.2 - transitivePeerDependencies: - - supports-color - - serve-static@2.2.1: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.1 - transitivePeerDependencies: - - supports-color - - set-blocking@2.0.0: {} - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - - set-proto@1.0.0: - dependencies: - dunder-proto: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - - setimmediate@1.0.5: {} - - setprototypeof@1.2.0: {} - - sharp@0.34.5: - dependencies: - '@img/colour': 1.1.0 - detect-libc: 2.1.2 - semver: 7.8.1 - optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 - optional: true - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - shell-quote@1.8.4: {} - - shiki@4.1.0: - dependencies: - '@shikijs/core': 4.1.0 - '@shikijs/engine-javascript': 4.1.0 - '@shikijs/engine-oniguruma': 4.1.0 - '@shikijs/langs': 4.1.0 - '@shikijs/themes': 4.1.0 - '@shikijs/types': 4.1.0 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - side-channel-list@1.0.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.1 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - siginfo@2.0.0: {} - - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - simple-icons@16.28.0: {} - - simple-plist@1.3.1: - dependencies: - bplist-creator: 0.1.0 - bplist-parser: 0.3.1 - plist: 3.1.1 - - sisteransi@1.0.5: {} - - slice-ansi@2.1.0: - dependencies: - ansi-styles: 3.2.1 - astral-regex: 1.0.0 - is-fullwidth-code-point: 2.0.0 - - slugify@1.6.9: {} - - smol-toml@1.6.1: {} - - source-map-js@1.2.1: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.5.7: {} - - source-map@0.6.1: {} - - source-map@0.7.6: {} - - space-separated-tokens@2.0.2: {} - - stable-hash@0.0.5: {} - - stackback@0.0.2: {} - - stackframe@1.3.4: {} - - stacktrace-parser@0.1.11: - dependencies: - type-fest: 0.7.1 - - statuses@1.5.0: {} - - statuses@2.0.2: {} - - std-env@4.1.0: {} - - stop-iteration-iterator@1.1.0: - dependencies: - es-errors: 1.3.0 - internal-slot: 1.1.0 - - stream-buffers@2.2.0: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string.prototype.matchall@4.0.12: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-symbols: 1.1.0 - internal-slot: 1.1.0 - regexp.prototype.flags: 1.5.4 - set-function-name: 2.0.2 - side-channel: 1.1.0 - - string.prototype.repeat@1.0.0: - dependencies: - define-properties: 1.2.1 - es-abstract: 1.24.2 - - string.prototype.trim@1.2.10: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-data-property: 1.1.4 - define-properties: 1.2.1 - es-abstract: 1.24.2 - es-object-atoms: 1.1.2 - has-property-descriptors: 1.0.2 - - string.prototype.trimend@1.0.9: - dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.2 - - string.prototype.trimstart@1.0.8: - dependencies: - call-bind: 1.0.9 - define-properties: 1.2.1 - es-object-atoms: 1.1.2 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - stringify-entities@4.0.4: - dependencies: - character-entities-html4: 2.1.0 - character-entities-legacy: 3.0.0 - - strip-ansi@5.2.0: - dependencies: - ansi-regex: 4.1.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-bom@3.0.0: {} - - strip-final-newline@2.0.0: {} - - strip-json-comments@3.1.1: {} - - strnum@2.4.1: - dependencies: - anynum: 1.0.1 - - structured-headers@0.4.1: {} - - style-to-js@1.1.21: - dependencies: - style-to-object: 1.0.14 - - style-to-object@1.0.14: - dependencies: - inline-style-parser: 0.2.7 - - styled-jsx@5.1.6(react@19.2.7): - dependencies: - client-only: 0.0.1 - react: 19.2.7 - - styleq@0.1.3: {} - - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - - supports-hyperlinks@2.3.0: - dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - tailwind-merge@3.6.0: {} - - tailwindcss@4.3.0: {} - - tapable@2.3.3: {} - - terminal-link@2.1.1: - dependencies: - ansi-escapes: 4.3.2 - supports-hyperlinks: 2.3.0 - - terser@5.48.0: - dependencies: - '@jridgewell/source-map': 0.3.11 - acorn: 8.16.0 - commander: 2.20.3 - source-map-support: 0.5.21 - - throat@5.0.0: {} - - tinybench@2.9.0: {} - - tinyexec@1.2.4: {} - - tinyglobby@0.2.16: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - tinyrainbow@3.1.0: {} - - tmpl@1.0.5: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - toidentifier@1.0.1: {} - - toqr@0.1.1: {} - - tr46@0.0.3: {} - - trim-lines@3.0.1: {} - - trough@2.2.0: {} - - ts-api-utils@2.5.0(typescript@6.0.3): - dependencies: - typescript: 6.0.3 - - tsconfig-paths@3.15.0: - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - - tslib@2.8.1: {} - - tsx@4.22.3: - dependencies: - esbuild: 0.28.1 - optionalDependencies: - fsevents: 2.3.3 - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - type-fest@0.21.3: {} - - type-fest@0.7.1: {} - - type-is@2.1.0: - dependencies: - content-type: 2.0.0 - media-typer: 1.1.0 - mime-types: 3.0.2 - - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - - typed-array-byte-length@1.0.3: - dependencies: - call-bind: 1.0.9 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - - typed-array-byte-offset@1.0.4: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.9 - for-each: 0.3.5 - gopd: 1.2.0 - has-proto: 1.2.0 - is-typed-array: 1.1.15 - reflect.getprototypeof: 1.0.10 - - typed-array-length@1.0.7: - dependencies: - call-bind: 1.0.9 - for-each: 0.3.5 - gopd: 1.2.0 - is-typed-array: 1.1.15 - possible-typed-array-names: 1.1.0 - reflect.getprototypeof: 1.0.10 - - typedoc@0.28.19(typescript@6.0.3): - dependencies: - '@gerrit0/mini-shiki': 3.23.0 - lunr: 2.3.9 - markdown-it: 14.2.0 - minimatch: 10.2.5 - typescript: 6.0.3 - yaml: 2.9.0 - - typescript@5.9.3: {} - - typescript@6.0.3: {} - - ua-parser-js@1.0.41: {} - - uc.micro@2.1.0: {} - - unbox-primitive@1.1.0: - dependencies: - call-bound: 1.0.4 - has-bigints: 1.1.0 - has-symbols: 1.1.0 - which-boxed-primitive: 1.1.1 - - undici-types@6.21.0: {} - - undici-types@7.16.0: {} - - unicode-canonical-property-names-ecmascript@2.0.1: {} - - unicode-match-property-ecmascript@2.0.0: - dependencies: - unicode-canonical-property-names-ecmascript: 2.0.1 - unicode-property-aliases-ecmascript: 2.2.0 - - unicode-match-property-value-ecmascript@2.2.1: {} - - unicode-property-aliases-ecmascript@2.2.0: {} - - unified@11.0.5: - dependencies: - '@types/unist': 3.0.3 - bail: 2.0.2 - devlop: 1.1.0 - extend: 3.0.2 - is-plain-obj: 4.1.0 - trough: 2.2.0 - vfile: 6.0.3 - - unist-util-is@6.0.1: - dependencies: - '@types/unist': 3.0.3 - - unist-util-position-from-estree@2.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-position@5.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-remove-position@5.0.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-visit: 5.1.0 - - unist-util-stringify-position@4.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-visit-parents@6.0.2: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - - unist-util-visit@5.1.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - universalify@0.1.2: {} - - unpipe@1.0.0: {} - - unrs-resolver@1.12.2: - dependencies: - napi-postinstall: 0.3.4 - optionalDependencies: - '@unrs/resolver-binding-android-arm-eabi': 1.12.2 - '@unrs/resolver-binding-android-arm64': 1.12.2 - '@unrs/resolver-binding-darwin-arm64': 1.12.2 - '@unrs/resolver-binding-darwin-x64': 1.12.2 - '@unrs/resolver-binding-freebsd-x64': 1.12.2 - '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 - '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 - '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 - '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 - '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 - '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 - '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 - '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 - '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 - '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 - '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 - '@unrs/resolver-binding-linux-x64-musl': 1.12.2 - '@unrs/resolver-binding-openharmony-arm64': 1.12.2 - '@unrs/resolver-binding-wasm32-wasi': 1.12.2 - '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 - '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 - '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 - - update-browserslist-db@1.2.3(browserslist@4.28.2): - dependencies: - browserslist: 4.28.2 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - use-callback-ref@1.3.3(@types/react@19.2.16)(react@19.2.7): - dependencies: - react: 19.2.7 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.16 - - use-sidecar@1.1.3(@types/react@19.2.16)(react@19.2.7): - dependencies: - detect-node-es: 1.1.0 - react: 19.2.7 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.16 - - util-deprecate@1.0.2: {} - - utils-merge@1.0.1: {} - - uuid@11.1.1: {} - - validate-npm-package-name@5.0.1: {} - - vary@1.1.2: {} - - vfile-location@5.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile: 6.0.3 - - vfile-message@4.0.3: - dependencies: - '@types/unist': 3.0.3 - unist-util-stringify-position: 4.0.0 - - vfile@6.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile-message: 4.0.3 - - vite@6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0): - dependencies: - esbuild: 0.28.1 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - postcss: 8.5.15 - rollup: 4.60.4 - tinyglobby: 0.2.16 - optionalDependencies: - '@types/node': 24.12.4 - fsevents: 2.3.3 - jiti: 2.7.0 - lightningcss: 1.32.0 - terser: 5.48.0 - tsx: 4.22.3 - yaml: 2.9.0 - - vitest@4.1.8(@types/node@24.12.4)(@vitest/coverage-v8@4.1.8)(vite@6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0)): - dependencies: - '@vitest/expect': 4.1.8 - '@vitest/mocker': 4.1.8(vite@6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.8 - '@vitest/runner': 4.1.8 - '@vitest/snapshot': 4.1.8 - '@vitest/spy': 4.1.8 - '@vitest/utils': 4.1.8 - es-module-lexer: 2.1.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.1.0 - tinybench: 2.9.0 - tinyexec: 1.2.4 - tinyglobby: 0.2.16 - tinyrainbow: 3.1.0 - vite: 6.4.2(@types/node@24.12.4)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)(yaml@2.9.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 24.12.4 - '@vitest/coverage-v8': 4.1.8(vitest@4.1.8) - transitivePeerDependencies: - - msw - - vlq@1.0.1: {} - - walker@1.0.8: - dependencies: - makeerror: 1.0.12 - - wcwidth@1.0.1: - dependencies: - defaults: 1.0.4 - - web-namespaces@2.0.1: {} - - webidl-conversions@3.0.1: {} - - whatwg-fetch@3.6.20: {} - - whatwg-url-minimum@0.1.2: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - which-boxed-primitive@1.1.1: - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.2 - is-number-object: 1.1.1 - is-string: 1.1.1 - is-symbol: 1.1.1 - - which-builtin-type@1.2.1: - dependencies: - call-bound: 1.0.4 - function.prototype.name: 1.1.8 - has-tostringtag: 1.0.2 - is-async-function: 2.1.1 - is-date-object: 1.1.0 - is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.2 - is-regex: 1.2.1 - is-weakref: 1.1.1 - isarray: 2.0.5 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.20 - - which-collection@1.0.2: - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.4 - - which-module@2.0.1: {} - - which-typed-array@1.1.20: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.9 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - word-wrap@1.2.5: {} - - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrappy@1.0.2: {} - - ws@6.2.6: - dependencies: - async-limiter: 1.0.1 - - ws@7.5.11: {} - - ws@8.21.0: {} - - xcode@3.0.1: - dependencies: - simple-plist: 1.3.1 - uuid: 11.1.1 - - xml-naming@0.3.0: {} - - xml2js@0.6.0: - dependencies: - sax: 1.6.0 - xmlbuilder: 11.0.1 - - xml2js@0.6.2: - dependencies: - sax: 1.6.0 - xmlbuilder: 11.0.1 - - xmlbuilder@11.0.1: {} - - xmlbuilder@15.1.1: {} - - y18n@4.0.3: {} - - y18n@5.0.8: {} - - yallist@3.1.1: {} - - yaml@2.9.0: {} - - yargs-parser@18.1.3: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - - yargs-parser@21.1.1: {} - - yargs@15.4.1: - dependencies: - cliui: 6.0.0 - decamelize: 1.2.0 - find-up: 4.1.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 4.2.3 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 18.1.3 - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yocto-queue@0.1.0: {} - - zod-to-json-schema@3.25.2(zod@3.25.76): - dependencies: - zod: 3.25.76 - - zod-to-json-schema@3.25.2(zod@4.4.3): - dependencies: - zod: 4.4.3 - - zod-validation-error@4.0.2(zod@4.4.3): - dependencies: - zod: 4.4.3 - - zod@3.25.76: {} - - zod@4.4.3: {} - - zwitch@2.0.4: {} - - zx@8.8.5: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index 3d8c685f7..000000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,54 +0,0 @@ -packages: - - "src/shared/js-core" - - "src/docs" - - "src/sdks/js" - - "src/runtimes/liboliphaunt/native/icu-npm" - - "src/runtimes/liboliphaunt/native/packages/*" - - "src/runtimes/liboliphaunt/native/tools-packages/*" - - "src/runtimes/liboliphaunt/native/tools-npm" - - "src/runtimes/broker/packages/*" - - "src/runtimes/node-direct" - - "src/runtimes/node-direct/packages/*" - - "src/runtimes/wasix-napi" - - "src/runtimes/wasix-napi/packages/*" - - "src/sdks/react-native" - - "examples/browser-wasix" - - "examples/react-native-expo" - - "src/bindings/wasix-ts" - - "src/bindings/wasix-ts/tools-package" - - "src/runtimes/liboliphaunt/wasix/tools-npm" - - "tools/perf/wasix-node" - -catalog: - "@vitest/coverage-v8": ^4.1.8 - tsx: ^4.20.6 - typedoc: ^0.28.16 - typescript: ^6.0.3 - vitest: ^4.1.8 - -minimumReleaseAge: 1440 -nodeLinker: isolated -# The source-only ICU workspace has no payload until packaging. Do not let -# pnpm's hidden hoist make it appear installed in ordinary SDK consumers. -hoistPattern: - - "*" - - "!@oliphaunt/icu" -confirmModulesPurge: false -autoInstallPeers: false -saveWorkspaceProtocol: rolling -updateNotifier: false -verifyDepsBeforeRun: false - -overrides: - esbuild: 0.28.1 - js-yaml: 4.3.0 - postcss: 8.5.15 - uuid: 11.1.1 - -allowBuilds: - core-js: false - electron: true - esbuild: true - msgpackr-extract: true - sharp: true - unrs-resolver: true diff --git a/prek.toml b/prek.toml index 30de41502..bd364052f 100644 --- a/prek.toml +++ b/prek.toml @@ -3,9 +3,9 @@ default_install_hook_types = ["pre-commit", "commit-msg"] fail_fast = true exclude = { glob = [ "target/**", - "examples/**/node_modules/**", - "examples/**/dist/**", - "examples/**/src-tauri/target/**", + "src/examples/**/node_modules/**", + "src/examples/**/dist/**", + "src/examples/**/src-tauri/target/**", ] } [[repos]] @@ -29,10 +29,3 @@ rev = "v1.1.11" hooks = [ { id = "committed", args = ["--fixup", "--commit-file"], stages = ["commit-msg"] }, ] - -[[repos]] -repo = "local" -hooks = [ - { id = "cargo-fmt", name = "cargo fmt", language = "system", entry = "cargo fmt --check", pass_filenames = false, files = "\\.(rs|toml)$", stages = ["pre-commit"] }, - { id = "tauri-rustfmt", name = "Tauri rustfmt", language = "system", entry = "tools/policy/check-tauri-example-rustfmt.sh", pass_filenames = false, files = "^examples/(tauri|tauri-wasix)/src-tauri/.*\\.(rs|toml)$", stages = ["pre-commit"] }, -] diff --git a/release-please-config.json b/release-please-config.json index b466c8c22..94c899b68 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -42,7 +42,7 @@ } ], "packages": { - "src/runtimes/liboliphaunt/native": { + "src/runtimes/liboliphaunt-native": { "release-type": "simple", "component": "liboliphaunt-native", "package-name": "liboliphaunt-native", @@ -69,52 +69,13 @@ "path": "packages/win32-x64-msvc/package.json", "jsonpath": "$.version" }, - { - "type": "json", - "path": "tools-packages/darwin-arm64/package.json", - "jsonpath": "$.version" - }, - { - "type": "json", - "path": "tools-packages/linux-arm64-gnu/package.json", - "jsonpath": "$.version" - }, - { - "type": "json", - "path": "tools-packages/linux-x64-gnu/package.json", - "jsonpath": "$.version" - }, - { - "type": "json", - "path": "tools-packages/win32-x64-msvc/package.json", - "jsonpath": "$.version" - }, - { - "type": "json", - "path": "tools-npm/package.json", - "jsonpath": "$.version" - }, - { - "type": "toml", - "path": "crates/tools/Cargo.toml", - "jsonpath": "$.package.version" - }, - { - "type": "json", - "path": "icu-npm/package.json", - "jsonpath": "$.version" - }, - { - "type": "generic", - "path": "icu-npm/OliphauntICU.podspec" - }, { "type": "generic", "path": "src/liboliphaunt_native.c" } ] }, - "src/sdks/rust": { + "src/sdks/rust/sdk": { "release-type": "rust", "component": "oliphaunt-rust", "package-name": "oliphaunt", @@ -127,7 +88,7 @@ } ] }, - "src/runtimes/broker": { + "src/broker": { "release-type": "rust", "component": "oliphaunt-broker", "package-name": "oliphaunt-broker", @@ -175,7 +136,7 @@ } ] }, - "src/runtimes/node-direct": { + "src/sdks/ts/node-addon": { "release-type": "node", "component": "oliphaunt-node-direct", "package-name": "@oliphaunt/node-direct", @@ -203,7 +164,7 @@ } ] }, - "src/runtimes/wasix-napi": { + "src/sdks/ts-wasix/node-addon": { "release-type": "node", "component": "oliphaunt-wasix-napi", "package-name": "@oliphaunt/wasix-napi", @@ -264,7 +225,7 @@ "package-name": "@oliphaunt/react-native", "changelog-path": "CHANGELOG.md" }, - "src/sdks/js": { + "src/sdks/ts/sdk": { "release-type": "node", "component": "oliphaunt-js", "package-name": "@oliphaunt/ts", @@ -319,7 +280,7 @@ "version-file": "VERSION", "changelog-path": "CHANGELOG.md" }, - "src/runtimes/liboliphaunt/wasix": { + "src/runtimes/liboliphaunt-wasix": { "release-type": "simple", "component": "liboliphaunt-wasix", "package-name": "liboliphaunt-wasix", @@ -333,74 +294,195 @@ }, { "type": "toml", - "path": "crates/tools/Cargo.toml", + "path": "crates/aot/aarch64-apple-darwin/Cargo.toml", "jsonpath": "$.package.version" }, { "type": "toml", - "path": "crates/aot/aarch64-apple-darwin/Cargo.toml", + "path": "crates/aot/aarch64-unknown-linux-gnu/Cargo.toml", "jsonpath": "$.package.version" }, { "type": "toml", - "path": "crates/tools-aot/aarch64-apple-darwin/Cargo.toml", + "path": "crates/aot/x86_64-pc-windows-msvc/Cargo.toml", "jsonpath": "$.package.version" }, { "type": "toml", - "path": "crates/aot/aarch64-unknown-linux-gnu/Cargo.toml", + "path": "crates/aot/x86_64-unknown-linux-gnu/Cargo.toml", "jsonpath": "$.package.version" + } + ] + }, + "src/runtimes/liboliphaunt-wasix-postmaster": { + "release-type": "simple", + "component": "liboliphaunt-wasix-postmaster", + "package-name": "liboliphaunt-wasix-postmaster", + "version-file": "VERSION", + "changelog-path": "CHANGELOG.md" + }, + "src/sdks/rust-wasix": { + "release-type": "rust", + "component": "oliphaunt-wasix-rust", + "package-name": "oliphaunt-wasix", + "changelog-path": "CHANGELOG.md" + }, + "src/sdks/ts-wasix/sdk": { + "release-type": "node", + "component": "oliphaunt-wasix-ts", + "package-name": "@oliphaunt/wasix-ts", + "changelog-path": "CHANGELOG.md" + }, + "src/sdks/rust-query": { + "release-type": "rust", + "component": "oliphaunt-query", + "package-name": "oliphaunt-query", + "changelog-path": "CHANGELOG.md" + }, + "src/sdks/ts-query": { + "release-type": "node", + "component": "oliphaunt-query-ts", + "package-name": "@oliphaunt/ts-query", + "changelog-path": "CHANGELOG.md" + }, + "src/sdks/rust/liboliphaunt-native": { + "release-type": "rust", + "component": "liboliphaunt-native-bindings", + "package-name": "liboliphaunt-native-bindings", + "changelog-path": "CHANGELOG.md" + }, + "src/postgres-tools/native": { + "release-type": "simple", + "component": "postgres-tools-native", + "version-file": "VERSION", + "changelog-path": "CHANGELOG.md", + "initial-version": "0.2.1", + "extra-files": [ + { + "type": "json", + "path": "npm-platforms/darwin-arm64/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "npm-platforms/linux-arm64-gnu/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "npm-platforms/linux-x64-gnu/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "npm-platforms/win32-x64-msvc/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "npm/package.json", + "jsonpath": "$.version" }, { "type": "toml", - "path": "crates/tools-aot/aarch64-unknown-linux-gnu/Cargo.toml", + "path": "crates/tools/Cargo.toml", + "jsonpath": "$.package.version" + } + ] + }, + "src/postgres-tools/wasix": { + "release-type": "simple", + "component": "postgres-tools-wasix", + "version-file": "VERSION", + "changelog-path": "CHANGELOG.md", + "initial-version": "0.2.1", + "extra-files": [ + { + "type": "toml", + "path": "crates/tools/Cargo.toml", "jsonpath": "$.package.version" }, { "type": "toml", - "path": "crates/aot/x86_64-pc-windows-msvc/Cargo.toml", + "path": "crates/aot/aarch64-apple-darwin/Cargo.toml", "jsonpath": "$.package.version" }, { "type": "toml", - "path": "crates/tools-aot/x86_64-pc-windows-msvc/Cargo.toml", + "path": "crates/aot/aarch64-unknown-linux-gnu/Cargo.toml", "jsonpath": "$.package.version" }, { "type": "toml", - "path": "crates/aot/x86_64-unknown-linux-gnu/Cargo.toml", + "path": "crates/aot/x86_64-pc-windows-msvc/Cargo.toml", "jsonpath": "$.package.version" }, { "type": "toml", - "path": "crates/tools-aot/x86_64-unknown-linux-gnu/Cargo.toml", + "path": "crates/aot/x86_64-unknown-linux-gnu/Cargo.toml", "jsonpath": "$.package.version" }, { "type": "json", - "path": "tools-npm/package.json", + "path": "npm/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "ts/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "npm-platforms/linux-arm64-gnu/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "npm-platforms/linux-x64-gnu/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "npm-platforms/darwin-arm64/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "npm-platforms/win32-x64-msvc/package.json", "jsonpath": "$.version" } ] }, - "src/runtimes/liboliphaunt/wasix-postmaster": { + "src/database-resources": { "release-type": "simple", - "component": "liboliphaunt-wasix-postmaster", - "package-name": "liboliphaunt-wasix-postmaster", + "component": "database-resources", "version-file": "VERSION", - "changelog-path": "CHANGELOG.md" + "changelog-path": "CHANGELOG.md", + "initial-version": "0.2.1", + "extra-files": [ + { + "type": "json", + "path": "icu/npm/package.json", + "jsonpath": "$.version" + }, + { + "type": "generic", + "path": "icu/npm/OliphauntICU.podspec" + }, + { + "type": "toml", + "path": "icu/cargo/Cargo.toml", + "jsonpath": "$.package.version" + } + ] }, - "src/bindings/wasix-rust/crates/oliphaunt-wasix": { + "src/pgwire-server": { "release-type": "rust", - "component": "oliphaunt-wasix-rust", - "package-name": "oliphaunt-wasix", - "changelog-path": "CHANGELOG.md" - }, - "src/bindings/wasix-ts": { - "release-type": "node", - "component": "oliphaunt-wasix-ts", - "package-name": "@oliphaunt/wasix-ts", - "changelog-path": "CHANGELOG.md" + "component": "oliphaunt-pgwire-server", + "package-name": "oliphaunt-pgwire-server", + "changelog-path": "CHANGELOG.md", + "initial-version": "0.1.0" } } } diff --git a/renovate.json b/renovate.json index eb3c4ea56..469ce5f5e 100644 --- a/renovate.json +++ b/renovate.json @@ -13,56 +13,18 @@ "gradle", "gradle-wrapper", "npm", - "pep621", - "regex", "swift" ], "packageRules": [ - { - "matchManagers": ["github-actions"], - "groupName": "GitHub Actions" - }, { "matchManagers": ["cargo"], - "groupName": "Rust crates" - }, - { - "matchManagers": ["gradle", "gradle-wrapper"], - "groupName": "Android and Kotlin" + "matchPackageNames": ["napi", "napi-derive", "napi-build"], + "groupName": "Node-API bindings" }, { "matchManagers": ["npm"], - "groupName": "JavaScript and React Native" - }, - { - "matchManagers": ["swift", "cocoapods"], - "groupName": "Apple SDK" - } - ], - "customManagers": [ - { - "customType": "regex", - "description": "Pinned Moon CLI", - "managerFilePatterns": ["/^\\.prototools$/"], - "matchStrings": ["moon = \"(?[^\"]+)\""], - "datasourceTemplate": "npm", - "depNameTemplate": "@moonrepo/cli" - }, - { - "customType": "regex", - "description": "Pinned Node runtime", - "managerFilePatterns": ["/^\\.prototools$/"], - "matchStrings": ["node = \"(?[^\"]+)\""], - "datasourceTemplate": "node-version", - "depNameTemplate": "node" - }, - { - "customType": "regex", - "description": "Pinned pnpm runtime", - "managerFilePatterns": ["/^\\.prototools$/"], - "matchStrings": ["pnpm = \"(?[^\"]+)\""], - "datasourceTemplate": "npm", - "depNameTemplate": "pnpm" + "matchPackageNames": ["react", "react-dom", "@types/react", "@types/react-dom"], + "groupName": "React" } ] } diff --git a/src/benchmarks/README.md b/src/benchmarks/README.md new file mode 100644 index 000000000..00c818ca9 --- /dev/null +++ b/src/benchmarks/README.md @@ -0,0 +1,18 @@ +# Benchmarks + +Fixed SQL workloads, benchmark specs, baselines, and promoted reports live here. +The native runner compares direct, broker, and server modes with PostgreSQL and +SQLite. WASIX Node/browser and mobile workloads retain their own runners. + +Use `src/benchmarks/perf/run-native.sh OUTPUT_DIRECTORY COMMAND [OPTIONS...]` for one +native measurement with source/build identity and raw JSON. See +[measurement instructions](../docs/maintainers/performance-evidence.md) for commands +and comparison requirements. Optional matrices, generated verdicts, and report +verification gates have been retired. + +- `native/sql/`: fixed native SQL workloads. +- `native/baselines/`: historical native baselines. +- `wasix/`: WASIX specs and baselines. +- `mobile/`: mobile specs and baselines. +- `reports/`: retained published measurements. +- `perf/`: executable benchmark runners. diff --git a/src/benchmarks/mobile/README.md b/src/benchmarks/mobile/README.md new file mode 100644 index 000000000..88e06627d --- /dev/null +++ b/src/benchmarks/mobile/README.md @@ -0,0 +1,7 @@ +# Mobile Benchmarks + +The Expo app owns mobile benchmark workloads and device measurements. Run +`bun run --cwd src/examples/react-native-expo bench:android` or `bench:ios`; +use the matching `crash:android` or `crash:ios` command for durability evidence. +See [performance evidence](../../docs/maintainers/performance-evidence.md) for +startup settings and focused comparisons. Promoted reports belong in benchmarks. diff --git a/benchmarks/moon.yml b/src/benchmarks/moon.yml similarity index 100% rename from benchmarks/moon.yml rename to src/benchmarks/moon.yml diff --git a/src/benchmarks/native/README.md b/src/benchmarks/native/README.md new file mode 100644 index 000000000..e9abb686e --- /dev/null +++ b/src/benchmarks/native/README.md @@ -0,0 +1,8 @@ +# Native Benchmarks + +Native benchmark specs live here. Runner code stays under `src/benchmarks/perf`. + +- `sql/`: fixed SQL workload files used by native direct, broker, server, + native PostgreSQL, and SQLite comparison suites. +- `baselines/`: committed comparison baselines when a release intentionally + records them. diff --git a/benchmarks/native/baselines/README.md b/src/benchmarks/native/baselines/README.md similarity index 100% rename from benchmarks/native/baselines/README.md rename to src/benchmarks/native/baselines/README.md diff --git a/benchmarks/native/sql/benchmark1.sql b/src/benchmarks/native/sql/benchmark1.sql similarity index 100% rename from benchmarks/native/sql/benchmark1.sql rename to src/benchmarks/native/sql/benchmark1.sql diff --git a/benchmarks/native/sql/benchmark10.sql b/src/benchmarks/native/sql/benchmark10.sql similarity index 100% rename from benchmarks/native/sql/benchmark10.sql rename to src/benchmarks/native/sql/benchmark10.sql diff --git a/benchmarks/native/sql/benchmark11.sql b/src/benchmarks/native/sql/benchmark11.sql similarity index 100% rename from benchmarks/native/sql/benchmark11.sql rename to src/benchmarks/native/sql/benchmark11.sql diff --git a/benchmarks/native/sql/benchmark12.sql b/src/benchmarks/native/sql/benchmark12.sql similarity index 100% rename from benchmarks/native/sql/benchmark12.sql rename to src/benchmarks/native/sql/benchmark12.sql diff --git a/benchmarks/native/sql/benchmark13.sql b/src/benchmarks/native/sql/benchmark13.sql similarity index 100% rename from benchmarks/native/sql/benchmark13.sql rename to src/benchmarks/native/sql/benchmark13.sql diff --git a/benchmarks/native/sql/benchmark14.sql b/src/benchmarks/native/sql/benchmark14.sql similarity index 100% rename from benchmarks/native/sql/benchmark14.sql rename to src/benchmarks/native/sql/benchmark14.sql diff --git a/benchmarks/native/sql/benchmark15.sql b/src/benchmarks/native/sql/benchmark15.sql similarity index 100% rename from benchmarks/native/sql/benchmark15.sql rename to src/benchmarks/native/sql/benchmark15.sql diff --git a/benchmarks/native/sql/benchmark16.sql b/src/benchmarks/native/sql/benchmark16.sql similarity index 100% rename from benchmarks/native/sql/benchmark16.sql rename to src/benchmarks/native/sql/benchmark16.sql diff --git a/benchmarks/native/sql/benchmark2.sql b/src/benchmarks/native/sql/benchmark2.sql similarity index 100% rename from benchmarks/native/sql/benchmark2.sql rename to src/benchmarks/native/sql/benchmark2.sql diff --git a/benchmarks/native/sql/benchmark3.sql b/src/benchmarks/native/sql/benchmark3.sql similarity index 100% rename from benchmarks/native/sql/benchmark3.sql rename to src/benchmarks/native/sql/benchmark3.sql diff --git a/benchmarks/native/sql/benchmark4.sql b/src/benchmarks/native/sql/benchmark4.sql similarity index 100% rename from benchmarks/native/sql/benchmark4.sql rename to src/benchmarks/native/sql/benchmark4.sql diff --git a/benchmarks/native/sql/benchmark5.sql b/src/benchmarks/native/sql/benchmark5.sql similarity index 100% rename from benchmarks/native/sql/benchmark5.sql rename to src/benchmarks/native/sql/benchmark5.sql diff --git a/benchmarks/native/sql/benchmark6.sql b/src/benchmarks/native/sql/benchmark6.sql similarity index 100% rename from benchmarks/native/sql/benchmark6.sql rename to src/benchmarks/native/sql/benchmark6.sql diff --git a/benchmarks/native/sql/benchmark7.sql b/src/benchmarks/native/sql/benchmark7.sql similarity index 100% rename from benchmarks/native/sql/benchmark7.sql rename to src/benchmarks/native/sql/benchmark7.sql diff --git a/benchmarks/native/sql/benchmark8.sql b/src/benchmarks/native/sql/benchmark8.sql similarity index 100% rename from benchmarks/native/sql/benchmark8.sql rename to src/benchmarks/native/sql/benchmark8.sql diff --git a/benchmarks/native/sql/benchmark9.sql b/src/benchmarks/native/sql/benchmark9.sql similarity index 100% rename from benchmarks/native/sql/benchmark9.sql rename to src/benchmarks/native/sql/benchmark9.sql diff --git a/src/benchmarks/perf/moon.yml b/src/benchmarks/perf/moon.yml new file mode 100644 index 000000000..c34d584c8 --- /dev/null +++ b/src/benchmarks/perf/moon.yml @@ -0,0 +1,151 @@ +$schema: "https://moonrepo.dev/schemas/project.json" + +id: "perf-tools" +language: "rust" +layer: "tool" +stack: "systems" +tags: ["javascript-quality", "tools", "performance", "bench"] +dependsOn: + - id: "oliphaunt-rust" + scope: "development" + - id: "oliphaunt-wasix-rust" + scope: "development" + - id: "liboliphaunt-wasix" + scope: "development" + - id: "shared-test-fixtures" + scope: "development" + - id: "oliphaunt-query" + scope: "development" + - id: "benchmarks" + scope: "build" + +project: + title: "Performance Tools" + description: "Native, WASM, mobile, and SQLite benchmark orchestration and reporting." + owner: "oliphaunt" + +owners: + defaultOwner: "@oliphaunt/perf" + paths: + "**/*": ["@oliphaunt/perf"] + +tasks: + native-measure: + tags: ["bench", "measured"] + script: | + bash src/benchmarks/perf/run-native.sh "target/perf/native-$(date -u +%Y%m%dT%H%M%SZ)" native-liboliphaunt --suite rtt + deps: + - "liboliphaunt-native:build-runtime-desktop-target" + inputs: + - "@group(cargo-workspace)" + - "/src/runtimes/liboliphaunt-native/**/*" + - "/src/sdks/rust/sdk/**/*" + - project: "shared-test-fixtures" + group: "fixtures" + - "/src/benchmarks/perf/run-native.sh" + - "/src/benchmarks/perf/runner/**/*" + - project: "benchmarks" + group: "native-sql" + options: + cache: false + runFromWorkspaceRoot: true + runInCI: false + wasix-plan: + tags: ["bench", "plan"] + script: | + set -e + node --test src/benchmarks/perf/wasix-browser/plan.test.mts + node --test src/benchmarks/perf/wasix-node/plan.test.mts + node --check src/benchmarks/perf/wasix-browser/plan.mts + node --check src/benchmarks/perf/wasix-node/engine-runner.mts + node --check src/benchmarks/perf/wasix-node/benchmark.mts + node --check src/benchmarks/perf/wasix-node/pglite-node-worker.mts + node --check src/sdks/ts-wasix/sdk/tools/pgwire-client.mts + node src/benchmarks/perf/wasix-node/benchmark.mts --validate + inputs: + - "@group(bun-workspace)" + - "/src/benchmarks/wasix/**/*" + - "/src/runtimes/wasix-browser-host/**/*" + - "/src/sdks/ts-wasix/sdk/package.json" + - "/src/sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts" + - "/src/sdks/ts-wasix/sdk/tools/pgwire-client.mts" + - "/src/sdks/ts-wasix/node-addon/package.json" + - "/src/benchmarks/perf/wasix-browser/*.{mjs,mts}" + - "/src/benchmarks/perf/wasix-node/*.{mts,sh}" + - "/src/benchmarks/perf/wasix-node/package.json" + - "@group(release-archive-contract)" + - "/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-*.mts" + - "/src/postgres-tools/wasix/ts/tools/wasix-tools-typescript-package.mts" + - "/src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.mts" + options: + cache: true + runFromWorkspaceRoot: true + runInCI: false + wasix-node-measure: + tags: ["bench", "measured", "local-only"] + script: | + set -e + bun run --cwd src/sdks/ts-wasix/sdk build + bun src/sdks/ts-wasix/sdk/tools/stage-host.mts + bash src/benchmarks/perf/wasix-node/benchmark.sh --run + deps: + - "perf-tools:wasix-plan" + - "liboliphaunt-wasix:runtime-portable" + - "database-resources:package-wasix" + - "wasix-browser-host:build" + inputs: + - "@group(legal-files)" + - "@group(bun-workspace)" + - "/src/benchmarks/wasix/node-pglite-memory-v2.json" + - "/src/sdks/ts-wasix/sdk/**/*" + - "/src/sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts" + - "/src/benchmarks/perf/wasix-node/*.{mts,sh}" + - "/src/benchmarks/perf/wasix-node/package.json" + - "@group(release-archive-contract)" + - "/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-*.mts" + - "/src/postgres-tools/wasix/ts/tools/wasix-tools-typescript-package.mts" + - "/src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.mts" + options: + cache: false + runFromWorkspaceRoot: true + runInCI: false + wasix-browser-measure: + tags: ["bench", "measured", "browser", "local-only"] + script: | + set -e + bun run --cwd src/sdks/ts-wasix/sdk build + bun src/sdks/ts-wasix/sdk/tools/stage-host.mts + bash src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh --benchmark + deps: + - "perf-tools:wasix-plan" + - "liboliphaunt-wasix:runtime-portable" + - "database-resources:build-wasix-standard" + - "wasix-browser-host:build" + inputs: + - "@group(legal-files)" + - "@group(bun-workspace)" + - "/src/benchmarks/wasix/browser-pglite-memory-v2.json" + - "/src/sdks/ts-wasix/sdk/**/*" + - "/src/sdks/ts-wasix/sdk/tools/integration/*.{mts,sh}" + - "/src/benchmarks/perf/wasix-browser/*.{mjs,mts}" + - "/src/benchmarks/perf/wasix-node/installed-closure.mts" + - "/src/benchmarks/perf/wasix-node/plan.mts" + options: + cache: false + runFromWorkspaceRoot: true + runInCI: false + + rust-format-check: + tags: ["quality", "static", "format", "requires-rust"] + command: "cargo fmt -p oliphaunt-perf --check" + inputs: ["/src/benchmarks/perf/runner/**/*.rs","/src/benchmarks/perf/runner/Cargo.toml","/clippy.toml","@group(cargo-workspace)"] + options: + runFromWorkspaceRoot: true + rust-lint: + tags: ["quality", "static", "requires-rust"] + command: "cargo clippy -p oliphaunt-perf --all-targets --locked -- -D warnings" + env: + CARGO_TARGET_DIR: "target" + inputs: ["/src/benchmarks/perf/runner/**/*.rs","/src/benchmarks/perf/runner/Cargo.toml","/clippy.toml","@group(cargo-workspace)"] + options: + runFromWorkspaceRoot: true diff --git a/src/benchmarks/perf/run-native.sh b/src/benchmarks/perf/run-native.sh new file mode 100755 index 000000000..878223566 --- /dev/null +++ b/src/benchmarks/perf/run-native.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail +[ "$#" -ge 2 ] || { echo 'usage: run-native.sh OUTPUT_DIRECTORY native-liboliphaunt|native-postgres|sqlite|diagnose-speed-cases [OPTIONS...]' >&2; exit 2; } +case "$1" in /*) output="$1" ;; *) output="$PWD/$1" ;; esac +shift +root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +cd "$root" +mkdir -p "$(dirname "$output")" +mkdir "$output" # Never mix measurements from different invocations. +if command -v sha256sum >/dev/null; then hash=(sha256sum); else hash=(shasum -a 256); fi +{ + git rev-parse HEAD + git status --short -- src/sdks/rust/sdk src/sdks/rust-query src/benchmarks/perf src/benchmarks/native/sql Cargo.toml Cargo.lock rust-toolchain.toml .cargo + rustc -Vv + uname -a + date -u +} >"$output/context.txt" + +{ + for name in LIBOLIPHAUNT_PATH OLIPHAUNT_POSTGRES OLIPHAUNT_INITDB OLIPHAUNT_BROKER_PATH; do + value="${!name:-}" + if [ -n "$value" ]; then + [ -f "$value" ] || value="$(command -v "$value")" + "${hash[@]}" "$value" + fi + done + while IFS= read -r -d '' file; do + [ ! -f "$file" ] || "${hash[@]}" "$file" + done < <(git ls-files -z --cached --others --exclude-standard -- src/sdks/rust/sdk src/sdks/rust-query src/benchmarks/perf/runner src/benchmarks/perf/run-native.sh src/benchmarks/native/sql Cargo.toml Cargo.lock rust-toolchain.toml .cargo) +} >"$output/inputs.sha256" +CARGO_TARGET_DIR="$root/target" cargo build --release --locked -p oliphaunt-perf >"$output/build.log" 2>&1 +runner="$root/target/release/oliphaunt-perf" +[ ! -f "$runner.exe" ] || runner="$runner.exe" +"${hash[@]}" "$runner" >>"$output/inputs.sha256" +printf '%q ' "$runner" "$@" >"$output/command.sh" +printf '\n' >>"$output/command.sh" +"$runner" "$@" >"$output/report.json.partial" 2>"$output/stderr.log" +"${hash[@]}" -c "$output/inputs.sha256" >"$output/verification.log" +mv "$output/report.json.partial" "$output/report.json" +printf 'Benchmark report: %s/report.json\n' "$output" diff --git a/src/benchmarks/perf/runner/Cargo.toml b/src/benchmarks/perf/runner/Cargo.toml new file mode 100644 index 000000000..b55105edf --- /dev/null +++ b/src/benchmarks/perf/runner/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "oliphaunt-perf" +version = "0.0.0" +edition = "2024" +rust-version = "1.93" +license.workspace = true +publish = false +default-run = "oliphaunt-perf" + +[features] +default = [] + +[dependencies] +anyhow = "1" +futures-util = "0.3" +oliphaunt = { path = "../../../sdks/rust/sdk" } +rusqlite = { version = "0.37", features = ["bundled"] } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +sqlx = { version = "0.8", default-features = false, features = [ + "postgres", + "runtime-tokio", +] } +tar = "0.4" +tokio = { version = "1", features = ["rt-multi-thread"] } +tokio-postgres = "0.7" + diff --git a/tools/perf/runner/src/benchmarks.rs b/src/benchmarks/perf/runner/src/benchmarks.rs similarity index 99% rename from tools/perf/runner/src/benchmarks.rs rename to src/benchmarks/perf/runner/src/benchmarks.rs index b8095e939..a5cd37787 100644 --- a/tools/perf/runner/src/benchmarks.rs +++ b/src/benchmarks/perf/runner/src/benchmarks.rs @@ -38,7 +38,7 @@ impl SpeedSqlSource { "Mirrors the two Oliphaunt benchmark families documented at https://oliphaunt.dev/benchmarks: trimmed-average CRUD round-trip microbenchmarks and a SQLite speedtest-style SQL suite. The speed suite is generated locally instead of vendoring Oliphaunt's generated SQL files." } SpeedSqlSource::OliphauntFixture => { - "Mirrors the two Oliphaunt benchmark families documented at https://oliphaunt.dev/benchmarks: trimmed-average CRUD round-trip microbenchmarks and the exact SQL files from benchmarks/native/sql." + "Mirrors the two Oliphaunt benchmark families documented at https://oliphaunt.dev/benchmarks: trimmed-average CRUD round-trip microbenchmarks and the exact SQL files from src/benchmarks/native/sql." } } } diff --git a/tools/perf/runner/src/diagnostics.rs b/src/benchmarks/perf/runner/src/diagnostics.rs similarity index 99% rename from tools/perf/runner/src/diagnostics.rs rename to src/benchmarks/perf/runner/src/diagnostics.rs index 3e262be0b..b45061d62 100644 --- a/tools/perf/runner/src/diagnostics.rs +++ b/src/benchmarks/perf/runner/src/diagnostics.rs @@ -128,7 +128,7 @@ fn perf_diagnose_speed_ids(ids: &[&str], options: &SpeedDiagnosticOptions) -> Re } let report = SpeedHotspotDiagnosticReport { - source_model: "Exact Oliphaunt fixture benchmark SQL files from benchmarks/native/sql.", + source_model: "Exact Oliphaunt fixture benchmark SQL files from src/benchmarks/native/sql.", measurement_model: "Each case opens a fresh disposable database, runs all earlier Oliphaunt speed tests outside the measured section, then records the selected speed-test SQL. Native direct diagnostics run one case per process. Native PostgreSQL diagnostics start a fresh temporary cluster per case and use the same database target as liboliphaunt.", cases: diagnostics, }; diff --git a/src/benchmarks/perf/runner/src/main.rs b/src/benchmarks/perf/runner/src/main.rs new file mode 100644 index 000000000..945ec2861 --- /dev/null +++ b/src/benchmarks/perf/runner/src/main.rs @@ -0,0 +1,752 @@ +use std::env; +use std::fs; +use std::io::{BufReader, Cursor, Read, Write}; +use std::net::TcpListener; +#[cfg(not(unix))] +use std::net::TcpStream; +#[cfg(unix)] +use std::os::unix::net::UnixStream; +use std::path::{Component, Path, PathBuf}; +use std::process::{Child, Command, Stdio}; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +use anyhow::{Context, Result, anyhow, bail, ensure}; +use futures_util::future::try_join_all; +use serde::{Deserialize, Serialize}; +use sqlx::postgres::{PgConnectOptions, PgSslMode}; +use sqlx::{Connection, Executor}; +use tar::{Archive, Builder as TarBuilder, Header as TarHeader}; + +use crate::process_rss::ProcessTreeRssSampler; + +mod benchmarks; +mod diagnostics; +mod native_liboliphaunt; +mod native_postgres; +mod prepared_updates; +mod process_rss; +mod report; +mod shared; +mod sqlite; + +use benchmarks::*; +use diagnostics::*; +use native_liboliphaunt::*; +use native_postgres::*; +use prepared_updates::*; +use report::*; +use shared::*; +use sqlite::*; + +const NATIVE_BENCHMARK_DATABASE: &str = "template1"; +const OLIPHAUNT_BENCHMARK_SQL_DIR: &str = "src/benchmarks/native/sql"; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum NativeDurabilityProfile { + Safe, + Balanced, + FastDev, +} + +impl NativeDurabilityProfile { + fn postgres_gucs(self) -> &'static [(&'static str, &'static str)] { + match self { + Self::Safe => &[ + ("fsync", "on"), + ("full_page_writes", "on"), + ("synchronous_commit", "on"), + ], + Self::Balanced => &[ + ("fsync", "on"), + ("full_page_writes", "on"), + ("synchronous_commit", "off"), + ], + Self::FastDev => &[ + ("fsync", "off"), + ("full_page_writes", "off"), + ("synchronous_commit", "off"), + ], + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum RuntimeFootprintProfile { + Throughput, + BalancedMobile, + SmallMobile, +} + +impl RuntimeFootprintProfile { + fn postgres_gucs(self) -> &'static [(&'static str, &'static str)] { + match self { + Self::Throughput => &[ + ("shared_buffers", "128MB"), + ("wal_buffers", "4MB"), + ("min_wal_size", "80MB"), + ], + Self::BalancedMobile => &[ + ("max_connections", "1"), + ("shared_buffers", "32MB"), + ("min_wal_size", "32MB"), + ("max_wal_size", "64MB"), + ], + Self::SmallMobile => &[ + ("max_connections", "1"), + ("shared_buffers", "8MB"), + ("wal_buffers", "256kB"), + ("min_wal_size", "32MB"), + ("max_wal_size", "64MB"), + ], + } + } +} + +impl std::fmt::Display for RuntimeFootprintProfile { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(match self { + Self::Throughput => "throughput", + Self::BalancedMobile => "balanced-mobile", + Self::SmallMobile => "small-mobile", + }) + } +} + +#[derive(Debug, Clone)] +struct PostgresStartupGuc { + name: String, + value: String, +} + +impl PostgresStartupGuc { + fn new(name: impl Into, value: impl Into) -> Self { + Self { + name: name.into(), + value: value.into(), + } + } +} + +fn main() -> Result<()> { + perf(env::args().skip(1).collect()) +} + +pub(crate) fn perf(args: Vec) -> Result<()> { + match args.first().map(String::as_str) { + Some("diagnose-speed-cases") => perf_diagnose_speed_cases(&args[1..]), + Some("native-postgres") => perf_native_postgres(&args[1..]), + Some("native-liboliphaunt") => perf_native_liboliphaunt(&args[1..]), + Some("native-liboliphaunt-prepared-child") => { + perf_native_liboliphaunt_prepared_child(&args[1..]) + } + Some("native-liboliphaunt-restore-verify-child") => { + perf_native_liboliphaunt_restore_verify_child(&args[1..]) + } + Some("sqlite") => perf_sqlite(&args[1..]), + Some(other) => bail!("unknown perf subcommand: {other}"), + None => bail!( + "usage: cargo run -p oliphaunt-perf -- " + ), + } +} + +fn now_micros() -> Result { + Ok(SystemTime::now() + .duration_since(UNIX_EPOCH) + .context("system clock is before UNIX_EPOCH")? + .as_micros()) +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum BenchmarkSuiteFilter { + All, + Rtt, + Speed, + Streaming, + PreparedUpdates, + BackupRestore, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum NativePostgresClientMode { + TokioPostgresSimple, + Sqlx, +} + +impl BenchmarkSuiteFilter { + fn includes(self, suite: &'static str) -> bool { + matches!( + (self, suite), + (Self::All, "rtt" | "speed") + | (Self::Rtt, "rtt") + | (Self::Speed, "speed") + | (Self::Streaming, "streaming") + | (Self::PreparedUpdates, "prepared-updates") + | (Self::BackupRestore, "backup-restore") + ) + } +} + +fn default_native_postgres_tool(tool: &str, env_names: &[&str]) -> PathBuf { + for env_name in env_names { + if let Ok(value) = env::var(env_name) + && !value.is_empty() + { + return PathBuf::from(value); + } + } + if let Ok(root) = env::current_dir() { + let repo_pinned = root + .join("target") + .join("liboliphaunt-pg18") + .join("install") + .join("bin") + .join(tool); + if repo_pinned.is_file() { + return repo_pinned; + } + } + PathBuf::from(tool) +} + +fn perf_native_postgres(args: &[String]) -> Result<()> { + let mut postgres_bin = default_native_postgres_tool("postgres", &["OLIPHAUNT_POSTGRES"]); + let mut initdb_bin = default_native_postgres_tool("initdb", &["OLIPHAUNT_INITDB"]); + let mut suite = BenchmarkSuiteFilter::Speed; + let mut speed_sql_source = SpeedSqlSource::OliphauntFixture; + let mut rtt_iterations = 100usize; + let mut prepared_rows = 25_000usize; + let mut client_mode = NativePostgresClientMode::TokioPostgresSimple; + let mut tuning = NativeBenchmarkTuning::default(); + let mut cursor = 0usize; + while cursor < args.len() { + match args[cursor].as_str() { + "--postgres-bin" => { + cursor += 1; + postgres_bin = PathBuf::from( + args.get(cursor) + .ok_or_else(|| anyhow!("--postgres-bin requires a value"))?, + ); + } + "--initdb-bin" => { + cursor += 1; + initdb_bin = PathBuf::from( + args.get(cursor) + .ok_or_else(|| anyhow!("--initdb-bin requires a value"))?, + ); + } + "--suite" => { + cursor += 1; + let value = args + .get(cursor) + .ok_or_else(|| anyhow!("--suite requires a value"))?; + suite = match value.as_str() { + "all" => BenchmarkSuiteFilter::All, + "rtt" | "roundtrip" | "round-trip" => BenchmarkSuiteFilter::Rtt, + "speed" | "sqlite" | "sqlite-suite" => BenchmarkSuiteFilter::Speed, + "stream" | "streaming" | "large-results" => BenchmarkSuiteFilter::Streaming, + "prepared" | "prepared-updates" => BenchmarkSuiteFilter::PreparedUpdates, + "backup" | "backup-restore" | "backup_restore" => { + BenchmarkSuiteFilter::BackupRestore + } + other => { + bail!( + "unknown --suite value {other:?}; use all, rtt, speed, streaming, prepared-updates, or backup-restore" + ) + } + }; + } + "--iterations" => { + cursor += 1; + let value = args + .get(cursor) + .ok_or_else(|| anyhow!("--iterations requires a value"))?; + rtt_iterations = value + .parse() + .with_context(|| format!("parse --iterations value {value:?}"))?; + } + "--rows" => { + cursor += 1; + let value = args + .get(cursor) + .ok_or_else(|| anyhow!("--rows requires a value"))?; + prepared_rows = value + .parse() + .with_context(|| format!("parse --rows value {value:?}"))?; + } + "--speed-source" => { + cursor += 1; + let value = args + .get(cursor) + .ok_or_else(|| anyhow!("--speed-source requires a value"))?; + speed_sql_source = match value.as_str() { + "generated" | "local" => SpeedSqlSource::Generated, + "oliphaunt" | "oliphaunt-vendored" | "upstream" => { + SpeedSqlSource::OliphauntFixture + } + other => { + bail!("unknown --speed-source value {other:?}; use generated or oliphaunt") + } + }; + } + "--client" => { + cursor += 1; + let value = args + .get(cursor) + .ok_or_else(|| anyhow!("--client requires a value"))?; + client_mode = match value.as_str() { + "tokio-postgres-simple" + | "tokio_postgres_simple" + | "tokio-postgres" + | "tokio_postgres" + | "simple" + | "simple-query" => NativePostgresClientMode::TokioPostgresSimple, + "sqlx" => NativePostgresClientMode::Sqlx, + other => { + bail!("unknown --client value {other:?}; use tokio-postgres-simple or sqlx") + } + }; + } + "--durability" => { + cursor += 1; + tuning.durability = parse_native_durability( + args.get(cursor) + .ok_or_else(|| anyhow!("--durability requires a value"))?, + )?; + } + "--runtime-footprint" => { + cursor += 1; + tuning.runtime_footprint = parse_runtime_footprint( + args.get(cursor) + .ok_or_else(|| anyhow!("--runtime-footprint requires a value"))?, + )?; + } + "--startup-guc" => { + cursor += 1; + tuning.startup_gucs.push(parse_startup_guc( + args.get(cursor) + .ok_or_else(|| anyhow!("--startup-guc requires a value"))?, + )?); + } + other => bail!("unknown perf native-postgres flag: {other}"), + } + cursor += 1; + } + ensure!(rtt_iterations > 0, "--iterations must be greater than zero"); + ensure!(prepared_rows > 0, "--rows must be greater than zero"); + + if suite == BenchmarkSuiteFilter::PreparedUpdates { + return perf_native_postgres_prepared_updates( + &postgres_bin, + &initdb_bin, + prepared_rows, + tuning, + ); + } + + let native_open_started = Instant::now(); + let native = NativePostgres::start(&postgres_bin, &initdb_bin, &tuning)?; + let native_open_micros = native_open_started.elapsed().as_micros(); + let mut runs = Vec::new(); + if suite.includes("rtt") || suite.includes("speed") { + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .context("create native Postgres benchmark Tokio runtime")?; + let mut client_runs = runtime.block_on(async { + match client_mode { + NativePostgresClientMode::TokioPostgresSimple => { + let mut config = tokio_postgres::Config::new(); + configure_native_postgres_client(&mut config, &native); + let connect_started = Instant::now(); + let (client, connection) = config + .connect(tokio_postgres::NoTls) + .await + .context("connect to native Postgres benchmark cluster")?; + let connection_task = tokio::spawn(async move { + if let Err(err) = connection.await { + eprintln!("native Postgres benchmark connection error: {err}"); + } + }); + let connect_micros = connect_started.elapsed().as_micros(); + let server_pid = native.child.id(); + + let mut runs = Vec::new(); + if suite.includes("rtt") { + let mut sampler = ProcessTreeRssSampler::new(server_pid); + runs.push( + run_native_postgres_rtt_benchmark( + &client, + rtt_iterations, + native_open_micros, + connect_micros, + &mut sampler, + ) + .await?, + ); + } + if suite.includes("speed") { + let mut sampler = ProcessTreeRssSampler::new(server_pid); + runs.push( + run_native_postgres_speed_benchmark( + &client, + speed_sql_source, + native_open_micros, + connect_micros, + &mut sampler, + ) + .await?, + ); + } + drop(client); + connection_task.await.ok(); + Ok::<_, anyhow::Error>(runs) + } + NativePostgresClientMode::Sqlx => { + let connect_started = Instant::now(); + let mut conn = + sqlx::PgConnection::connect_with(&native_postgres_sqlx_options(&native)) + .await + .context("connect SQLx native Postgres benchmark client")?; + let connect_micros = connect_started.elapsed().as_micros(); + let server_pid = native.child.id(); + + let mut runs = Vec::new(); + if suite.includes("rtt") { + let mut sampler = ProcessTreeRssSampler::new(server_pid); + runs.push( + run_native_postgres_rtt_sqlx_benchmark( + &mut conn, + rtt_iterations, + native_open_micros, + connect_micros, + &mut sampler, + ) + .await?, + ); + } + if suite.includes("speed") { + let mut sampler = ProcessTreeRssSampler::new(server_pid); + runs.push( + run_native_postgres_speed_sqlx_benchmark( + &mut conn, + speed_sql_source, + native_open_micros, + connect_micros, + &mut sampler, + ) + .await?, + ); + } + conn.close() + .await + .context("close SQLx native Postgres benchmark client")?; + Ok::<_, anyhow::Error>(runs) + } + } + })?; + runs.append(&mut client_runs); + } + if suite.includes("streaming") { + let mut sampler = ProcessTreeRssSampler::new(native.child.id()); + runs.push(run_native_postgres_streaming_benchmark( + &native, + native_open_micros, + &mut sampler, + )?); + } + if suite.includes("backup-restore") { + let mut sampler = ProcessTreeRssSampler::new(native.child.id()); + runs.push(run_native_postgres_physical_backup_restore_benchmark( + &native, + &postgres_bin, + native_open_micros, + &mut sampler, + &tuning, + )?); + runs.push(run_native_postgres_backup_restore_benchmark( + &native, + &postgres_bin, + native_open_micros, + &mut sampler, + )?); + } + ensure!( + !runs.is_empty(), + "selected native Postgres suite produced no runs" + ); + + let report = BenchmarkReport { + engine: "native-postgres", + source_model: speed_sql_source.source_model(), + measurement_model: match client_mode { + NativePostgresClientMode::TokioPostgresSimple => { + "Native Postgres control. xtask starts a temporary local cluster with the selected durability profile and Oliphaunt-parity startup GUCs, connects to the same template1 database target used by liboliphaunt, then sends each benchmark SQL file as one simple-query buffer through tokio-postgres simple_query. This intentionally avoids psql -f because psql splits files client-side." + } + NativePostgresClientMode::Sqlx => { + "Native Postgres control. xtask starts a temporary local cluster with the selected durability profile and Oliphaunt-parity startup GUCs, connects to the same template1 database target used by liboliphaunt, then runs the benchmark SQL through one long-lived SQLx connection." + } + }, + native_tuning: Some(tuning.report()), + rtt_iterations, + speed_scale: 1.0, + runs, + }; + println!("{}", serde_json::to_string_pretty(&report)?); + Ok(()) +} + +fn perf_native_postgres_prepared_updates( + postgres_bin: &Path, + initdb_bin: &Path, + rows: usize, + tuning: NativeBenchmarkTuning, +) -> Result<()> { + let numeric_updates = parsed_numeric_updates(rows)?; + let text_updates = parsed_text_updates(rows)?; + let runs = vec![ + PreparedUpdateRun { + mode: "native_postgres_tokio_prepared".to_owned(), + description: "Native PostgreSQL control using tokio-postgres with one prepared statement and one Execute await per update.".to_owned(), + tests: run_native_prepared_update_tests( + postgres_bin, + initdb_bin, + &tuning, + &numeric_updates, + &text_updates, + PreparedExecution::Sequential, + )?, + }, + PreparedUpdateRun { + mode: "native_postgres_tokio_pipelined_prepared".to_owned(), + description: "Native PostgreSQL control using tokio-postgres with one prepared statement and pipelined Execute futures inside one transaction.".to_owned(), + tests: run_native_prepared_update_tests( + postgres_bin, + initdb_bin, + &tuning, + &numeric_updates, + &text_updates, + PreparedExecution::Pipelined, + )?, + }, + ]; + + let report = PreparedUpdateReport { + source_model: "Exact Oliphaunt fixture benchmark2/benchmark6 setup plus update values parsed from benchmark9 and benchmark10.", + measurement_model: "Native PostgreSQL prepared-update control. Each test starts a fresh temporary local PostgreSQL cluster with the selected durability profile and Oliphaunt-parity startup GUCs, connects through tokio-postgres, prepares one statement, then executes N updates inside one transaction.", + native_tuning: Some(tuning.report()), + rows, + runs, + }; + println!("{}", serde_json::to_string_pretty(&report)?); + Ok(()) +} + +async fn run_native_postgres_rtt_benchmark( + client: &tokio_postgres::Client, + iterations: usize, + open_micros: u128, + connect_micros: u128, + server_rss: &mut ProcessTreeRssSampler, +) -> Result { + let setup_started = Instant::now(); + client + .simple_query(rtt_setup_sql()) + .await + .context("execute native Postgres RTT setup")?; + let setup_micros = setup_started.elapsed().as_micros(); + server_rss.sample(); + + let mut tests = Vec::new(); + for case in rtt_cases() { + let mut samples = Vec::with_capacity(iterations); + for _ in 0..iterations { + let started = Instant::now(); + client + .simple_query(&case.sql) + .await + .with_context(|| format!("execute native Postgres RTT benchmark {}", case.id))?; + samples.push(started.elapsed().as_micros()); + } + tests.push(samples_result( + case.id, + format!("Test {}: {}", case.id, case.label), + "milliseconds", + iterations, + samples, + )); + server_rss.sample(); + } + + Ok(BenchmarkRun { + suite: "rtt", + mode: "native_postgres", + description: "Native Postgres over Unix socket using tokio-postgres simple_query against the liboliphaunt-matched template1 database target.", + open_micros, + connect_micros: Some(connect_micros), + setup_micros, + observed_server_peak_rss_bytes: server_rss.peak_bytes(), + tests, + }) +} + +async fn run_native_postgres_speed_benchmark( + client: &tokio_postgres::Client, + sql_source: SpeedSqlSource, + open_micros: u128, + connect_micros: u128, + server_rss: &mut ProcessTreeRssSampler, +) -> Result { + client + .simple_query( + "DROP TABLE IF EXISTS t1 CASCADE;\ + DROP TABLE IF EXISTS t2 CASCADE;\ + DROP TABLE IF EXISTS t2_1 CASCADE;\ + DROP TABLE IF EXISTS t3 CASCADE;\ + DROP TABLE IF EXISTS t3_1 CASCADE;", + ) + .await + .context("clear native Postgres speed benchmark tables")?; + server_rss.sample(); + + let mut tests = Vec::new(); + for case in speed_cases(1.0, sql_source)? { + let started = Instant::now(); + client + .simple_query(&case.sql) + .await + .with_context(|| format!("execute native Postgres speed benchmark {}", case.id))?; + tests.push(single_sample_result( + case.id, + case.label, + "seconds", + case.operation_count, + started.elapsed(), + )); + server_rss.sample(); + } + Ok(BenchmarkRun { + suite: "speed", + mode: "native_postgres", + description: "Native Postgres speed suite over Unix socket using tokio-postgres simple_query against the liboliphaunt-matched template1 database target.", + open_micros, + connect_micros: Some(connect_micros), + setup_micros: 0, + observed_server_peak_rss_bytes: server_rss.peak_bytes(), + tests, + }) +} + +async fn run_native_postgres_rtt_sqlx_benchmark( + conn: &mut sqlx::PgConnection, + iterations: usize, + open_micros: u128, + connect_micros: u128, + server_rss: &mut ProcessTreeRssSampler, +) -> Result { + let setup_started = Instant::now(); + conn.execute(rtt_setup_sql()) + .await + .context("execute native Postgres RTT setup over SQLx")?; + let setup_micros = setup_started.elapsed().as_micros(); + server_rss.sample(); + + let mut tests = Vec::new(); + for case in rtt_cases() { + let mut samples = Vec::with_capacity(iterations); + for _ in 0..iterations { + let started = Instant::now(); + conn.execute(case.sql.as_str()).await.with_context(|| { + format!( + "execute native Postgres RTT benchmark {} over SQLx", + case.id + ) + })?; + samples.push(started.elapsed().as_micros()); + } + tests.push(samples_result( + case.id, + format!("Test {}: {}", case.id, case.label), + "milliseconds", + iterations, + samples, + )); + server_rss.sample(); + } + + Ok(BenchmarkRun { + suite: "rtt", + mode: "native_postgres_sqlx", + description: "Native Postgres over TCP using one long-lived SQLx connection against the liboliphaunt-matched template1 database target.", + open_micros, + connect_micros: Some(connect_micros), + setup_micros, + observed_server_peak_rss_bytes: server_rss.peak_bytes(), + tests, + }) +} + +async fn run_native_postgres_speed_sqlx_benchmark( + conn: &mut sqlx::PgConnection, + sql_source: SpeedSqlSource, + open_micros: u128, + connect_micros: u128, + server_rss: &mut ProcessTreeRssSampler, +) -> Result { + conn.execute( + "DROP TABLE IF EXISTS t1 CASCADE;\ + DROP TABLE IF EXISTS t2 CASCADE;\ + DROP TABLE IF EXISTS t2_1 CASCADE;\ + DROP TABLE IF EXISTS t3 CASCADE;\ + DROP TABLE IF EXISTS t3_1 CASCADE;", + ) + .await + .context("clear native Postgres speed benchmark tables over SQLx")?; + server_rss.sample(); + + let mut tests = Vec::new(); + for case in speed_cases(1.0, sql_source)? { + let started = Instant::now(); + conn.execute(case.sql.as_str()).await.with_context(|| { + format!( + "execute native Postgres speed benchmark {} over SQLx", + case.id + ) + })?; + tests.push(single_sample_result( + case.id, + case.label, + "seconds", + case.operation_count, + started.elapsed(), + )); + server_rss.sample(); + } + Ok(BenchmarkRun { + suite: "speed", + mode: "native_postgres_sqlx", + description: "Native Postgres speed suite over TCP using one SQLx connection against the liboliphaunt-matched template1 database target.", + open_micros, + connect_micros: Some(connect_micros), + setup_micros: 0, + observed_server_peak_rss_bytes: server_rss.peak_bytes(), + tests, + }) +} + +fn unique_perf_root(name: &str) -> Result { + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .context("read system clock for perf root")? + .as_nanos(); + let root = env::temp_dir().join(format!( + "oliphaunt-perf-{name}-{}-{now}", + std::process::id() + )); + if root.exists() { + fs::remove_dir_all(&root) + .with_context(|| format!("remove stale perf root {}", root.display()))?; + } + fs::create_dir_all(&root).with_context(|| format!("create perf root {}", root.display()))?; + Ok(root) +} diff --git a/tools/perf/runner/src/native_liboliphaunt.rs b/src/benchmarks/perf/runner/src/native_liboliphaunt.rs similarity index 100% rename from tools/perf/runner/src/native_liboliphaunt.rs rename to src/benchmarks/perf/runner/src/native_liboliphaunt.rs diff --git a/tools/perf/runner/src/native_postgres.rs b/src/benchmarks/perf/runner/src/native_postgres.rs similarity index 100% rename from tools/perf/runner/src/native_postgres.rs rename to src/benchmarks/perf/runner/src/native_postgres.rs diff --git a/tools/perf/runner/src/prepared_updates.rs b/src/benchmarks/perf/runner/src/prepared_updates.rs similarity index 100% rename from tools/perf/runner/src/prepared_updates.rs rename to src/benchmarks/perf/runner/src/prepared_updates.rs diff --git a/tools/perf/runner/src/process_rss.rs b/src/benchmarks/perf/runner/src/process_rss.rs similarity index 100% rename from tools/perf/runner/src/process_rss.rs rename to src/benchmarks/perf/runner/src/process_rss.rs diff --git a/tools/perf/runner/src/report.rs b/src/benchmarks/perf/runner/src/report.rs similarity index 100% rename from tools/perf/runner/src/report.rs rename to src/benchmarks/perf/runner/src/report.rs diff --git a/tools/perf/runner/src/shared.rs b/src/benchmarks/perf/runner/src/shared.rs similarity index 100% rename from tools/perf/runner/src/shared.rs rename to src/benchmarks/perf/runner/src/shared.rs diff --git a/tools/perf/runner/src/sqlite.rs b/src/benchmarks/perf/runner/src/sqlite.rs similarity index 100% rename from tools/perf/runner/src/sqlite.rs rename to src/benchmarks/perf/runner/src/sqlite.rs diff --git a/src/benchmarks/perf/wasix-browser/benchmark.mts b/src/benchmarks/perf/wasix-browser/benchmark.mts new file mode 100644 index 000000000..1493d9780 --- /dev/null +++ b/src/benchmarks/perf/wasix-browser/benchmark.mts @@ -0,0 +1,293 @@ +import { createHash } from 'node:crypto'; +import { lstat, mkdir, readFile, writeFile } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import { arch, cpus, hostname, platform, release, totalmem } from 'node:os'; +import { dirname, relative, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { isDeepStrictEqual } from 'node:util'; +import { loadHostBuildContract } from '../../../runtimes/wasix-browser-host/build-provenance.mts'; +import { directoryTreeSha256, installedPackageClosure } from '../wasix-node/installed-closure.mts'; +import { assertRuntimeBuildConfiguration, runtimeBuildProvenance } from '../wasix-node/plan.mts'; +import { + browserPlanSummary, + defaultBrowserPlanFile, + loadBrowserPlan, + qualifyingGitProvenance, + summarizeBrowserResult, +} from './plan.mts'; + +const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../../..'); +const bindingRoot = resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk'); +const [phase, scratch] = process.argv.slice(2); +if (!scratch || !['--prepare', '--report', '--diagnostic'].includes(phase)) + throw new Error('usage: benchmark.mts --prepare|--report|--diagnostic SCRATCH'); +if (phase === '--prepare') { + const configuration = JSON.parse(await readFile(resolve(scratch, 'browser.json'), 'utf8')); + const planSource = await loadBrowserPlan(configuration.config ?? defaultBrowserPlanFile); + const git = await gitProvenance(scratch); + const output = resolve(configuration.output ?? defaultBenchmarkOutput(git.commit)); + await requireAbsent(output, 'benchmark output'); + await writeFile(resolve(scratch, 'benchmark.json'), JSON.stringify({ planSource, git, output })); +} else { + const result = JSON.parse(await readFile(resolve(scratch, 'browser-result.json'), 'utf8')); + if (phase === '--diagnostic') { + console.log( + 'wasix-ts OPFS diagnostic benchmark: PASS\n' + + JSON.stringify( + { + configuration: result.configuration, + postgresProfiles: result.postgresProfiles, + worker: Object.fromEntries( + Object.entries(result.summary.workload).map(([metric, value]) => [ + metric, + value.worker, + ]), + ), + insertDiagnostic: result.insertDiagnostic.summary, + }, + null, + 2, + ), + ); + } else { + const { planSource, git, output } = JSON.parse( + await readFile(resolve(scratch, 'benchmark.json'), 'utf8'), + ); + const finalGit = await gitProvenance(scratch, '-after'); + if (finalGit.commit !== git.commit || finalGit.tree !== git.tree) + throw new Error('Git commit or tree changed while the browser benchmark was running'); + const summary = summarizeBrowserResult(planSource, result); + const report = { + schema: 'oliphaunt-wasix-browser-benchmark-report-v2', + createdAt: new Date().toISOString(), + plan: browserPlanSummary(planSource), + provenance: { + git, + machine: machineProvenance(), + candidate: await candidateProvenance(planSource.plan), + comparison: await comparisonProvenance(planSource.plan), + tools: await toolProvenance(planSource.file), + }, + result, + summary, + }; + await mkdir(dirname(output), { recursive: true }); + await mkdir(output); + await writeFile(resolve(output, 'report.json'), JSON.stringify(report, null, 2) + '\n', { + flag: 'wx', + }); + console.log( + `wasix-ts browser benchmark: ${summary.passed ? 'PASS' : 'FAIL'} direct=${summary.comparisons.direct.geomeanRatio.toFixed(4)} worker=${summary.comparisons.worker.geomeanRatio.toFixed(4)} gate<=${summary.gate.maxGeomeanRatio.toFixed(2)} report=${relative(repositoryRoot, output)}`, + ); + if (!summary.passed) process.exitCode = 1; + } +} + +async function gitProvenance(scratch, suffix = '') { + const [commit, tree, status] = await Promise.all( + ['commit', 'tree', 'status'].map((name) => + readFile(resolve(scratch, 'git-' + name + suffix), 'utf8'), + ), + ); + return qualifyingGitProvenance({ + commit: commit.trim(), + tree: tree.trim(), + status: status.trimEnd(), + }); +} + +async function candidateProvenance(plan) { + const packageFile = resolve(bindingRoot, 'package.json'); + const packageBytes = await readFile(packageFile); + const packageJson = JSON.parse(packageBytes.toString('utf8')); + if (packageJson.name !== '@oliphaunt/wasix-ts') { + throw new Error(`browser benchmark loaded unexpected candidate ${packageJson.name}`); + } + if (packageJson.dependencies?.fzstd !== plan.engines.candidate.dependencies.fzstd) { + throw new Error( + `browser benchmark loaded unexpected fzstd specifier ${packageJson.dependencies?.fzstd}`, + ); + } + const manifestBytes = await readFile( + resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/manifest.json'), + ); + const manifest = JSON.parse(manifestBytes.toString('utf8')); + const runtime = manifest.runtime; + if (runtime === null || typeof runtime !== 'object') { + throw new Error('canonical WASIX manifest has no runtime entry'); + } + const clusterSeed = manifest['cluster-seeds']?.standard; + if (clusterSeed === null || typeof clusterSeed !== 'object') { + throw new Error('canonical WASIX manifest has no standard cluster seed entry'); + } + const archiveBytes = await readFile( + resolve(repositoryRoot, 'target/oliphaunt-wasix/assets', runtime.archive), + ); + const archiveSha256 = sha256(archiveBytes); + if (archiveSha256 !== runtime.sha256) { + throw new Error('canonical WASIX runtime archive does not match its manifest'); + } + const clusterSeedBytes = await readFile( + resolve(repositoryRoot, 'target/oliphaunt-wasix/assets', clusterSeed.archive), + ); + const clusterSeedSha256 = sha256(clusterSeedBytes); + if (clusterSeedSha256 !== clusterSeed.sha256) { + throw new Error('canonical WASIX standard cluster seed does not match its manifest'); + } + const hostBuild = await installedHostBuildProvenance( + packageFile, + (await loadHostBuildContract()).provenance, + ); + const runtimeBuild = await runtimeBuildProvenance(manifest); + assertRuntimeBuildConfiguration( + runtimeBuild.configuration, + plan.engines.candidate.runtimeBuild, + 'browser candidate runtime build', + ); + const require = createRequire(packageFile); + const fzstdClosure = await installedPackageClosure(require.resolve('fzstd'), 'fzstd'); + const libDirectory = resolve(bindingRoot, 'lib'); + return { + package: packageJson.name, + version: packageJson.version, + packageJsonSha256: sha256(packageBytes), + build: { + treeHashSchema: 'oliphaunt-path-size-content-sha256-v1', + libTreeSha256: await directoryTreeSha256(libDirectory), + hostBuild, + hostArtifacts: await fileProvenance([ + resolve(libDirectory, 'host/index.mjs'), + resolve(libDirectory, 'host/worker.mjs'), + resolve(libDirectory, 'host/wasmer_js_bg.wasm'), + resolve(libDirectory, 'host/provenance.json'), + ]), + runtimeBuild, + }, + dependencies: { fzstd: fzstdClosure }, + runtime: { + manifestSha256: sha256(manifestBytes), + archive: runtime.archive, + archiveSha256, + archiveSize: archiveBytes.length, + moduleSha256: runtime['module-sha256'], + postgresVersion: runtime['postgres-version'], + sourceFingerprint: manifest['source-fingerprint'], + sourceLane: manifest['source-lane'], + }, + clusterSeed: { + profile: 'standard', + archive: clusterSeed.archive, + archiveSha256: clusterSeedSha256, + archiveSize: clusterSeedBytes.length, + }, + }; +} + +async function installedHostBuildProvenance(packageManifestFile, expected) { + const file = resolve(dirname(packageManifestFile), 'lib/host/provenance.json'); + let provenance; + try { + provenance = JSON.parse(await readFile(file, 'utf8')); + } catch (error) { + throw new Error('installed @oliphaunt/wasix-ts host provenance is unreadable', { + cause: error, + }); + } + if (!isDeepStrictEqual(provenance, expected)) { + throw new Error( + 'installed @oliphaunt/wasix-ts host provenance does not match the source build contract', + ); + } + return provenance; +} + +async function toolProvenance(plan) { + return fileProvenance([ + plan, + resolve(repositoryRoot, 'src/benchmarks/perf/wasix-browser/plan.mts'), + resolve(repositoryRoot, 'src/benchmarks/perf/wasix-node/installed-closure.mts'), + resolve(repositoryRoot, 'src/benchmarks/perf/wasix-node/plan.mts'), + resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.mts'), + resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh'), + resolve(repositoryRoot, 'src/benchmarks/perf/wasix-browser/benchmark.mts'), + resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts'), + resolve(repositoryRoot, 'src/examples/browser-wasix/benchmark.html'), + resolve(repositoryRoot, 'src/examples/browser-wasix/benchmark.ts'), + resolve(repositoryRoot, 'src/examples/browser-wasix/pglite-worker.ts'), + resolve(repositoryRoot, 'src/examples/browser-wasix/vite.config.ts'), + ]); +} + +async function fileProvenance(files) { + const records = []; + for (const file of [...new Set(files.map((entry) => resolve(entry)))].sort()) { + const bytes = await readFile(file); + records.push({ + path: relative(repositoryRoot, file).split('\\').join('/'), + sha256: sha256(bytes), + size: bytes.length, + }); + } + return records; +} + +async function comparisonProvenance(plan) { + const entry = resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist/index.js'); + const installedClosure = await installedPackageClosure(entry, plan.engines.comparison.package); + const root = installedClosure.packages.find( + (candidate) => candidate.id === installedClosure.root, + ); + if (root === undefined) throw new Error('installed PGlite closure lost its root package'); + if ( + root.version !== plan.engines.comparison.version || + root.installedTreeSha256 !== plan.engines.comparison.installedTreeSha256 + ) { + throw new Error( + `installed PGlite is ${root.version}#${root.installedTreeSha256}, expected ` + + `${plan.engines.comparison.version}#${plan.engines.comparison.installedTreeSha256}`, + ); + } + return { ...plan.engines.comparison, installedClosure }; +} + +function machineProvenance() { + const processors = cpus(); + return { + hostname: hostname(), + platform: platform(), + release: release(), + arch: arch(), + node: process.version, + v8: process.versions.v8, + cpuModel: processors[0]?.model ?? 'unknown', + logicalCpus: processors.length, + totalMemoryBytes: totalmem(), + }; +} + +async function requireAbsent(path, label) { + try { + await lstat(path); + } catch (error) { + if (error?.code === 'ENOENT') return; + throw error; + } + throw new Error(`${label} already exists: ${path}`); +} + +function defaultBenchmarkOutput(commit) { + const timestamp = new Date() + .toISOString() + .replaceAll(':', '') + .replaceAll('-', '') + .replace(/\.\d{3}Z$/u, 'Z'); + return resolve( + repositoryRoot, + 'target/perf', + `wasix-browser-${timestamp}-${commit.slice(0, 12)}`, + ); +} + +function sha256(value) { + return createHash('sha256').update(value).digest('hex'); +} diff --git a/src/benchmarks/perf/wasix-browser/plan.mts b/src/benchmarks/perf/wasix-browser/plan.mts new file mode 100644 index 000000000..3b049a533 --- /dev/null +++ b/src/benchmarks/perf/wasix-browser/plan.mts @@ -0,0 +1,517 @@ +import { readFile } from 'node:fs/promises'; +import { dirname, relative, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { + comfortableWinGate, + median, + pairedRatioSummary, + sha256, + validateComparisonIdentity, +} from '../wasix-node/plan.mts'; + +export const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../../..'); +export const defaultBrowserPlanFile = resolve( + repositoryRoot, + 'src/benchmarks/wasix/browser-pglite-memory-v2.json', +); + +const PLAN_SCHEMA = 'oliphaunt-wasix-browser-benchmark-plan-v2'; +const RESULT_SCHEMA = 'oliphaunt-wasix-browser-engine-result-v2'; +const PLAN_ID = 'browser-pglite-memory-v2'; +const CANDIDATE_PACKAGE = '@oliphaunt/wasix-ts'; +const ENGINE_NAMES = ['wasixDirect', 'wasixWorker', 'pgliteDirect', 'pgliteWorker']; +const PROFILE_FIELDS = [ + 'startupRuns', + 'workloadRuns', + 'insertDiagnosticRuns', + 'pointSamples', + 'rangeSamples', + 'aggregateSamples', + 'transactionInserts', + 'qualificationEligible', +]; +const MEASUREMENT = { + rows: 10_000, + storage: 'ephemeral-memory', + order: 'rotating-engines-with-same-run-pairing', + warmup: 'one-untimed-representative-workload-per-fresh-database', + timingBoundary: 'browser-caller-end-to-end-around-public-api', + pairing: 'same-run-oliphaunt-over-pglite', + percentileMethod: 'nearest-rank', +}; +const GATE_METRICS = [ + 'startup.warmReadyMs', + 'workload.createTableMs', + 'workload.insert10kMs', + 'workload.pointMedianMs', + 'workload.pointP95Ms', + 'workload.range100MedianMs', + 'workload.range100P95Ms', + 'workload.aggregateMedianMs', + 'workload.aggregateP95Ms', + 'workload.scanAndDecode10kMs', + 'workload.transactionInsertBatchMs', + 'workload.update1kMs', + 'workload.delete1kMs', +]; +const SURFACE_COMPARISONS = { + direct: ['wasixDirect', 'pgliteDirect'], + worker: ['wasixWorker', 'pgliteWorker'], +}; +const CANDIDATE_EXECUTION_SURFACES = { + direct: { + entrypoint: '@oliphaunt/wasix-ts', + callingContract: 'async', + executionOwner: 'caller', + }, + worker: { + entrypoint: '@oliphaunt/wasix-ts/worker', + callingContract: 'async', + executionOwner: 'sdk-worker', + }, +}; + +export async function loadBrowserPlan(file = defaultBrowserPlanFile) { + const bytes = await readFile(file); + let plan; + try { + plan = JSON.parse(bytes.toString('utf8')); + } catch (error) { + throw new Error(`${relative(repositoryRoot, file)} must contain JSON`, { cause: error }); + } + validateBrowserPlan(plan); + return { plan, file: resolve(file), sha256: sha256(bytes), size: bytes.length }; +} + +export function validateBrowserPlan(plan) { + requireRecord(plan, 'plan'); + requireEqual(plan.schema, PLAN_SCHEMA, 'plan.schema'); + validatePlanEnvelope(plan); + + const engines = requireRecord(plan.engines, 'plan.engines'); + requireExactKeys(engines, ['candidate', 'comparison'], 'plan.engines'); + const candidate = requireRecord(engines.candidate, 'plan.engines.candidate'); + const comparison = requireRecord(engines.comparison, 'plan.engines.comparison'); + requireExactKeys( + candidate, + ['package', 'storage', 'surfaces', 'dependencies', 'runtimeBuild'], + 'plan.engines.candidate', + ); + requireEqual(candidate.package, CANDIDATE_PACKAGE, 'plan.engines.candidate.package'); + requireEqual(candidate.storage, 'memory', 'plan.engines.candidate.storage'); + requireExactRecord( + requireRecord(candidate.surfaces, 'plan.engines.candidate.surfaces').direct, + { + engine: 'wasixDirect', + ...CANDIDATE_EXECUTION_SURFACES.direct, + }, + 'plan.engines.candidate.surfaces.direct', + ); + requireExactRecord( + candidate.surfaces.worker, + { + engine: 'wasixWorker', + ...CANDIDATE_EXECUTION_SURFACES.worker, + }, + 'plan.engines.candidate.surfaces.worker', + ); + requireExactKeys(candidate.surfaces, ['direct', 'worker'], 'plan.engines.candidate.surfaces'); + requireExactRecord( + candidate.dependencies, + { fzstd: '0.1.1' }, + 'plan.engines.candidate.dependencies', + ); + requireRecord(candidate.runtimeBuild, 'plan.engines.candidate.runtimeBuild'); + + validateComparisonIdentity(comparison); + const comparisonSurfaces = requireRecord(comparison.surfaces, 'plan.engines.comparison.surfaces'); + requireExactKeys( + comparisonSurfaces, + ['callerRealm', 'worker'], + 'plan.engines.comparison.surfaces', + ); + requireExactRecord( + comparisonSurfaces.callerRealm, + { + engine: 'pgliteDirect', + entrypoint: '@electric-sql/pglite', + callingContract: 'async', + executionOwner: 'caller', + }, + 'plan.engines.comparison.surfaces.callerRealm', + ); + requireExactRecord( + comparisonSurfaces.worker, + { + engine: 'pgliteWorker', + entrypoint: '@electric-sql/pglite/worker', + callingContract: 'async', + executionOwner: 'caller-provided-worker', + }, + 'plan.engines.comparison.surfaces.worker', + ); + + validateCommonPlan(plan); +} + +function validatePlanEnvelope(plan) { + requireExactKeys( + plan, + ['schema', 'id', 'description', 'engines', 'profiles', 'measurement', 'gate', 'postgres'], + 'plan', + ); + requireEqual(plan.id, PLAN_ID, 'plan.id'); + requireNonEmptyString(plan.description, 'plan.description'); +} + +function validateCommonPlan(plan) { + const profiles = requireRecord(plan.profiles, 'plan.profiles'); + requireExactKeys(profiles, ['quick', 'full'], 'plan.profiles'); + for (const name of ['quick', 'full']) { + const profile = requireRecord(profiles[name], `plan.profiles.${name}`); + requireExactKeys(profile, PROFILE_FIELDS, `plan.profiles.${name}`); + for (const field of PROFILE_FIELDS.filter((field) => field !== 'qualificationEligible')) { + requirePositiveInteger(profile[field], `plan.profiles.${name}.${field}`); + } + if (profile.startupRuns < 2) throw new Error('startupRuns must include cold and warm samples'); + requireEqual( + profile.qualificationEligible, + name === 'full', + `plan.profiles.${name}.qualificationEligible`, + ); + } + const full = profiles.full; + if ( + full.workloadRuns < ENGINE_NAMES.length * 2 || + full.workloadRuns % ENGINE_NAMES.length !== 0 + ) { + throw new Error('plan.profiles.full.workloadRuns must be a multiple of 4 and at least 8'); + } + + requireExactRecord(plan.measurement, MEASUREMENT, 'plan.measurement'); + const gate = requireRecord(plan.gate, 'plan.gate'); + requireExactKeys( + gate, + [ + 'maxGeomeanRatio', + 'requiresCorrectness', + 'requiresBothExecutionSurfaces', + 'metric', + 'metrics', + 'excluded', + ], + 'plan.gate', + ); + requireEqual(gate.maxGeomeanRatio, 0.8, 'plan.gate.maxGeomeanRatio'); + requireEqual(gate.requiresCorrectness, true, 'plan.gate.requiresCorrectness'); + requireEqual(gate.requiresBothExecutionSurfaces, true, 'plan.gate.requiresBothExecutionSurfaces'); + requireEqual( + gate.metric, + 'geometric-mean-of-median-paired-oliphaunt-over-pglite-ratios-lower-is-better', + 'plan.gate.metric', + ); + requireExactStringList(gate.metrics, GATE_METRICS, 'plan.gate.metrics'); + for (const metric of gate.metrics) validateMetricId(metric); + + const postgres = requireRecord(plan.postgres, 'plan.postgres'); + requireExactKeys( + postgres, + ['major', 'settings', 'indexedInsertWalTolerancePercent'], + 'plan.postgres', + ); + requireEqual(postgres.major, 18, 'plan.postgres.major'); + requireExactKeys( + requireRecord(postgres.settings, 'plan.postgres.settings'), + ['fsync', 'synchronousCommit', 'fullPageWrites', 'walLevel'], + 'plan.postgres.settings', + ); + requireEqual( + postgres.indexedInsertWalTolerancePercent, + 0.1, + 'plan.postgres.indexedInsertWalTolerancePercent', + ); +} + +export function qualifyingGitProvenance({ commit, tree, status }) { + if (!/^[0-9a-f]{40}$/u.test(commit)) { + throw new Error('browser benchmark qualification requires an exact Git commit'); + } + if (!/^[0-9a-f]{40}$/u.test(tree)) { + throw new Error('browser benchmark qualification requires an exact Git tree'); + } + if (typeof status !== 'string') { + throw new Error('browser benchmark qualification requires Git porcelain status text'); + } + if (status !== '') { + throw new Error('browser benchmark qualification requires a clean Git worktree'); + } + return { commit, tree, dirty: false }; +} + +export function summarizeBrowserResult(planSource, result) { + const plan = planSource.plan; + validateBrowserResult(plan, result); + const correctness = summarizeCorrectness(plan, result); + const comparisons = Object.fromEntries( + Object.entries(SURFACE_COMPARISONS).map(([surface, [candidate, comparison]]) => { + const metrics = plan.gate.metrics.map((id) => { + const candidateSamplesMs = metricSamples(result, candidate, id); + const comparisonSamplesMs = metricSamples(result, comparison, id); + const paired = pairedRatioSummary(candidateSamplesMs, comparisonSamplesMs); + return { + id, + candidateSamplesMs, + comparisonSamplesMs, + candidateMedianMs: median(candidateSamplesMs), + comparisonMedianMs: median(comparisonSamplesMs), + pairs: paired.pairedRatios.map((ratio, repeat) => ({ + repeat, + candidateMs: candidateSamplesMs[repeat], + comparisonMs: comparisonSamplesMs[repeat], + ratio, + })), + pairedRatioMedian: paired.medianRatio, + }; + }); + const aggregate = comfortableWinGate( + metrics.map((metric) => metric.pairedRatioMedian), + plan.gate.maxGeomeanRatio, + correctness.passed, + ); + return [surface, { metrics, ...aggregate }]; + }), + ); + const qualificationEligible = plan.profiles[result.mode].qualificationEligible; + const performancePassed = Object.values(comparisons).every( + (comparison) => comparison.gate.passed, + ); + return { + correctness, + comparisons, + gate: { + required: qualificationEligible, + passed: qualificationEligible ? performancePassed && correctness.passed : null, + maxGeomeanRatio: plan.gate.maxGeomeanRatio, + requiresBothExecutionSurfaces: true, + metric: plan.gate.metric, + excluded: plan.gate.excluded, + }, + passed: correctness.passed && (!qualificationEligible || performancePassed), + }; +} + +export function browserPlanSummary(source) { + return { + id: source.plan.id, + schema: source.plan.schema, + sha256: source.sha256, + size: source.size, + engines: source.plan.engines, + profiles: source.plan.profiles, + measurement: source.plan.measurement, + gate: source.plan.gate, + postgres: source.plan.postgres, + }; +} + +function validateBrowserResult(plan, result) { + requireRecord(result, 'browser result'); + requireEqual(result.schema, RESULT_SCHEMA, 'result.schema'); + requireEqual(result.plan, plan.id, 'result.plan'); + if (!['quick', 'full'].includes(result.mode)) throw new Error('result.mode is invalid'); + const expected = plan.profiles[result.mode]; + const configuration = requireRecord(result.configuration, 'result.configuration'); + for (const field of [ + 'startupRuns', + 'workloadRuns', + 'insertDiagnosticRuns', + 'pointSamples', + 'rangeSamples', + 'aggregateSamples', + 'transactionInserts', + ]) { + requireEqual(configuration[field], expected[field], `result.configuration.${field}`); + } + requireEqual(configuration.rows, plan.measurement.rows, 'result.configuration.rows'); + requireEqual(configuration.storage, plan.measurement.storage, 'result.configuration.storage'); + requireNestedExactRecord( + configuration.executionSurfaces, + CANDIDATE_EXECUTION_SURFACES, + 'result.configuration.executionSurfaces', + ); + requireEqual(result.correctness?.assertionsPassed, true, 'result correctness'); + requireEqual(result.environment?.crossOriginIsolated, true, 'cross-origin isolation'); + + for (const engine of ENGINE_NAMES) { + requireArrayLength( + result.samples?.startup?.[engine], + expected.startupRuns, + `${engine} startup`, + ); + requireArrayLength( + result.samples?.workload?.[engine], + expected.workloadRuns, + `${engine} workloads`, + ); + requireArrayLength( + result.insertDiagnostic?.samples?.[engine], + expected.insertDiagnosticRuns, + `${engine} insert diagnostics`, + ); + } +} + +function summarizeCorrectness(plan, result) { + const settings = plan.postgres.settings; + const durability = Object.fromEntries( + Object.entries(SURFACE_COMPARISONS).map(([surface, [candidate, comparison]]) => { + const candidateProfile = result.postgresProfiles[candidate]; + const comparisonProfile = result.postgresProfiles[comparison]; + const candidateValid = profileMatches(candidateProfile, settings, plan.postgres.major); + const comparisonValid = profileMatches(comparisonProfile, settings, plan.postgres.major); + const parity = Object.keys(settings).every( + (setting) => candidateProfile?.[setting] === comparisonProfile?.[setting], + ); + return [ + surface, + { + passed: candidateValid && comparisonValid && parity, + candidateProfile, + comparisonProfile, + }, + ]; + }), + ); + durability.passed = durability.direct.passed && durability.worker.passed; + + const wal = result.insertDiagnostic.summary.indexedInsertWalBytes; + const indexedInsertWal = Object.fromEntries( + Object.entries(SURFACE_COMPARISONS).map(([surface, [candidate, comparison]]) => { + const candidateBytes = positiveNumber(wal[candidate], `${candidate} WAL bytes`); + const comparisonBytes = positiveNumber(wal[comparison], `${comparison} WAL bytes`); + const deltaPercent = (Math.abs(candidateBytes - comparisonBytes) / comparisonBytes) * 100; + return [ + surface, + { + passed: deltaPercent <= plan.postgres.indexedInsertWalTolerancePercent, + candidateBytes, + comparisonBytes, + deltaBytes: candidateBytes - comparisonBytes, + deltaPercent, + tolerancePercent: plan.postgres.indexedInsertWalTolerancePercent, + }, + ]; + }), + ); + indexedInsertWal.passed = indexedInsertWal.direct.passed && indexedInsertWal.worker.passed; + const workloadAssertionsPassed = result.correctness.assertionsPassed === true; + return { + passed: workloadAssertionsPassed && durability.passed && indexedInsertWal.passed, + workloadAssertionsPassed, + durability, + indexedInsertWal, + }; +} + +function metricSamples(result, engine, id) { + if (id === 'startup.warmReadyMs') { + return result.samples.startup[engine] + .slice(1) + .map((value, index) => positiveNumber(value, `${engine} ${id} sample ${index}`)); + } + const match = /^workload\.([A-Za-z][A-Za-z0-9]*)$/u.exec(id); + if (match === null) throw new Error(`unsupported browser benchmark metric ${id}`); + return result.samples.workload[engine].map((run, index) => + positiveNumber(run?.metrics?.[match[1]], `${engine} ${id} sample ${index}`), + ); +} + +function validateMetricId(id) { + if (id === 'startup.warmReadyMs') return; + if (!/^workload\.(?!readyMs$|closeMs$)[A-Za-z][A-Za-z0-9]*$/u.test(id)) { + throw new Error(`unsupported gated browser benchmark metric ${JSON.stringify(id)}`); + } +} + +function profileMatches(profile, settings, major) { + return ( + profile !== null && + typeof profile === 'object' && + new RegExp(`^${major}\\.`).test(profile.version) && + Object.entries(settings).every(([name, expected]) => profile[name] === expected) + ); +} + +function requireArrayLength(value, length, label) { + if (!Array.isArray(value) || value.length !== length) { + throw new Error(`${label} must contain exactly ${length} entries`); + } +} + +function requireRecord(value, label) { + if (value === null || typeof value !== 'object' || Array.isArray(value)) { + throw new Error(`${label} must be an object`); + } + return value; +} + +function requireExactRecord(value, expected, label) { + const record = requireRecord(value, label); + requireExactKeys(record, Object.keys(expected), label); + for (const [field, expectedValue] of Object.entries(expected)) { + requireEqual(record[field], expectedValue, `${label}.${field}`); + } + return record; +} + +function requireNestedExactRecord(value, expected, label) { + const record = requireRecord(value, label); + requireExactKeys(record, Object.keys(expected), label); + for (const [field, expectedValue] of Object.entries(expected)) { + requireExactRecord(record[field], expectedValue, `${label}.${field}`); + } + return record; +} + +function requireExactKeys(value, expected, label) { + const actual = Object.keys(value).sort(); + const required = [...expected].sort(); + if (JSON.stringify(actual) !== JSON.stringify(required)) { + throw new Error(`${label} must contain exactly ${JSON.stringify(required)}`); + } +} + +function requireExactStringList(value, expected, label) { + if (!Array.isArray(value) || value.length !== expected.length) { + throw new Error(`${label} must contain exactly ${expected.length} entries`); + } + for (let index = 0; index < expected.length; index += 1) { + requireEqual(value[index], expected[index], `${label}[${index}]`); + } +} + +function requireNonEmptyString(value, label) { + if (typeof value !== 'string' || value.trim() === '') { + throw new Error(`${label} must be a non-empty string`); + } +} + +function requirePositiveInteger(value, label) { + if (!Number.isSafeInteger(value) || value <= 0) throw new Error(`${label} must be positive`); +} + +function positiveNumber(value, label) { + if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) { + throw new Error(`${label} must be a positive finite number`); + } + return value; +} + +function requireEqual(actual, expected, label) { + if (actual !== expected) { + throw new Error( + `${label} must be ${JSON.stringify(expected)}, received ${JSON.stringify(actual)}`, + ); + } +} diff --git a/src/benchmarks/perf/wasix-browser/plan.test.mts b/src/benchmarks/perf/wasix-browser/plan.test.mts new file mode 100644 index 000000000..1a4e7d470 --- /dev/null +++ b/src/benchmarks/perf/wasix-browser/plan.test.mts @@ -0,0 +1,205 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + loadBrowserPlan, + qualifyingGitProvenance, + summarizeBrowserResult, + validateBrowserPlan, +} from './plan.mts'; + +const source = await loadBrowserPlan(); + +test('balances full workload rotation across all four engines', () => { + assert.equal(source.plan.profiles.full.workloadRuns, 8); + assert.equal(source.plan.profiles.full.workloadRuns % 4, 0); + + for (const workloadRuns of [4, 6, 7, 9]) { + const plan = structuredClone(source.plan); + plan.profiles.full.workloadRuns = workloadRuns; + assert.throws( + () => validateBrowserPlan(plan), + /workloadRuns must be a multiple of 4 and at least 8/u, + ); + } + + const strongerPlan = structuredClone(source.plan); + strongerPlan.profiles.full.workloadRuns = 12; + assert.doesNotThrow(() => validateBrowserPlan(strongerPlan)); +}); + +test('requires a clean exact Git commit and tree for benchmark qualification', () => { + const clean = { + commit: 'a'.repeat(40), + tree: 'b'.repeat(40), + status: '', + }; + assert.deepEqual(qualifyingGitProvenance(clean), { + commit: clean.commit, + tree: clean.tree, + dirty: false, + }); + assert.throws( + () => qualifyingGitProvenance({ ...clean, status: ' M benchmark.ts' }), + /requires a clean Git worktree/u, + ); +}); + +test('requires a comfortable aggregate win independently on both execution surfaces', () => { + const result = fixture('full', { directRatio: 0.6, workerRatio: 0.5 }); + const summary = summarizeBrowserResult(source, result); + assert.ok(Math.abs(summary.comparisons.direct.geomeanRatio - 0.6) < 1e-12); + assert.ok(Math.abs(summary.comparisons.worker.geomeanRatio - 0.5) < 1e-12); + assert.equal(summary.correctness.passed, true); + assert.equal(summary.gate.required, true); + assert.equal(summary.gate.passed, true); + assert.equal(summary.passed, true); +}); + +test('requires independent calling-contract and execution-owner fields in v2 results', () => { + const result = fixture('quick', { directRatio: 0.6, workerRatio: 0.5 }); + assert.doesNotThrow(() => summarizeBrowserResult(source, result)); + + const flattened = structuredClone(result); + flattened.configuration.executionSurfaces = ['direct', 'worker']; + assert.throws( + () => summarizeBrowserResult(source, flattened), + /result\.configuration\.executionSurfaces must be an object/u, + ); + + const wrongOwner = structuredClone(result); + wrongOwner.configuration.executionSurfaces.worker.executionOwner = 'caller'; + assert.throws( + () => summarizeBrowserResult(source, wrongOwner), + /result\.configuration\.executionSurfaces\.worker\.executionOwner/u, + ); +}); + +test('does not let one execution surface subsidize a losing surface', () => { + const summary = summarizeBrowserResult( + source, + fixture('full', { directRatio: 0.5, workerRatio: 0.9 }), + ); + assert.equal(summary.comparisons.direct.gate.passed, true); + assert.equal(summary.comparisons.worker.gate.passed, false); + assert.equal(summary.gate.passed, false); + assert.equal(summary.passed, false); +}); + +test('makes quick runs correctness smoke evidence rather than performance qualification', () => { + const summary = summarizeBrowserResult( + source, + fixture('quick', { directRatio: 0.95, workerRatio: 0.95 }), + ); + assert.equal(summary.gate.required, false); + assert.equal(summary.gate.passed, null); + assert.equal(summary.passed, true); +}); + +test('rejects durability drift even when both performance gates win', () => { + const result = fixture('full', { directRatio: 0.5, workerRatio: 0.5 }); + result.postgresProfiles.pgliteWorker.fsync = 'on'; + const summary = summarizeBrowserResult(source, result); + assert.equal(summary.correctness.durability.worker.passed, false); + assert.equal(summary.correctness.passed, false); + assert.equal(summary.gate.passed, false); + assert.equal(summary.passed, false); +}); + +test('rejects WAL-volume drift even when workload results and speed agree', () => { + const result = fixture('full', { directRatio: 0.5, workerRatio: 0.5 }); + result.insertDiagnostic.summary.indexedInsertWalBytes.wasixDirect = 1100; + const summary = summarizeBrowserResult(source, result); + assert.equal(summary.correctness.indexedInsertWal.direct.passed, false); + assert.equal(summary.correctness.passed, false); + assert.equal(summary.gate.passed, false); + assert.equal(summary.passed, false); +}); + +function fixture(mode, { directRatio, workerRatio }) { + const profile = source.plan.profiles[mode]; + const metrics = source.plan.gate.metrics + .filter((id) => id.startsWith('workload.')) + .map((id) => id.slice('workload.'.length)); + const runs = (ratio) => + Array.from({ length: profile.workloadRuns }, () => ({ + metrics: Object.fromEntries([ + ...metrics.map((metric) => [metric, 10 * ratio]), + ['readyMs', 10 * ratio], + ['closeMs', 1_000_000], + ]), + })); + const startup = (ratio) => [ + 10, + ...Array.from({ length: profile.startupRuns - 1 }, () => 10 * ratio), + ]; + const diagnostics = () => + Array.from({ length: profile.insertDiagnosticRuns }, () => ({ indexedInsertWalBytes: 1000 })); + const postgres = () => ({ + version: '18.4', + fsync: 'off', + synchronousCommit: 'on', + fullPageWrites: 'on', + walLevel: 'replica', + }); + return { + schema: 'oliphaunt-wasix-browser-engine-result-v2', + plan: source.plan.id, + mode, + environment: { crossOriginIsolated: true }, + configuration: { + ...profile, + executionSurfaces: { + direct: { + entrypoint: '@oliphaunt/wasix-ts', + callingContract: 'async', + executionOwner: 'caller', + }, + worker: { + entrypoint: '@oliphaunt/wasix-ts/worker', + callingContract: 'async', + executionOwner: 'sdk-worker', + }, + }, + rows: source.plan.measurement.rows, + storage: source.plan.measurement.storage, + }, + correctness: { assertionsPassed: true }, + postgresProfiles: { + wasixDirect: postgres(), + wasixWorker: postgres(), + pgliteDirect: postgres(), + pgliteWorker: postgres(), + }, + samples: { + startup: { + wasixDirect: startup(directRatio), + wasixWorker: startup(workerRatio), + pgliteDirect: startup(1), + pgliteWorker: startup(1), + }, + workload: { + wasixDirect: runs(directRatio), + wasixWorker: runs(workerRatio), + pgliteDirect: runs(1), + pgliteWorker: runs(1), + }, + }, + insertDiagnostic: { + summary: { + indexedInsertWalBytes: { + wasixDirect: 1000, + wasixWorker: 1000, + pgliteDirect: 1000, + pgliteWorker: 1000, + }, + }, + samples: { + wasixDirect: diagnostics(), + wasixWorker: diagnostics(), + pgliteDirect: diagnostics(), + pgliteWorker: diagnostics(), + }, + }, + }; +} diff --git a/src/benchmarks/perf/wasix-node/benchmark.mts b/src/benchmarks/perf/wasix-node/benchmark.mts new file mode 100644 index 000000000..bf3320263 --- /dev/null +++ b/src/benchmarks/perf/wasix-node/benchmark.mts @@ -0,0 +1,630 @@ +import { lstat, mkdir, readFile, writeFile } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import { arch, cpus, freemem, homedir, hostname, platform, release, totalmem } from 'node:os'; +import { dirname, relative, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { stagePackedWasixConsumer } from '../../../sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts'; +import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts'; +import { installedPackageClosure } from './installed-closure.mts'; +import { + assertNativeArtifactProvenance, + assertRuntimeBuildConfiguration, + comfortableWinGate, + defaultPlanFile, + findPackageManifest, + loadPlan, + median, + metricIds, + pairedRatioSummary, + planSummary, + postgresSettingsParity, + repositoryRoot, + runtimeBuildProvenance, + sha256, +} from './plan.mts'; + +const toolRoot = dirname(fileURLToPath(import.meta.url)); +const engineRunner = resolve(toolRoot, 'engine-runner.mts'); +const phase = ['--prepare', '--inspect', '--report'].includes(process.argv[2]) + ? process.argv[2] + : undefined; +const scratch = phase ? resolve(process.argv[3]) : undefined; +const args = parseArguments(process.argv.slice(phase ? 4 : 2)); +const source = await loadPlan(args.config); + +if (args.mode === 'plan') { + console.log(JSON.stringify(planSummary(source.plan, source), null, 2)); +} else if (args.mode === 'validate') { + const installedControl = await comparisonProvenance(source.plan); + console.log( + JSON.stringify( + { + status: 'PASS', + validation: + 'plan, native addon contract, package identity, private comparator pin, and generated SQL', + installedControl, + ...planSummary(source.plan, source), + }, + null, + 2, + ), + ); +} else { + if (isCiEnvironment()) + throw new Error('measured WASIX Node benchmarks are local-only and refuse CI environments'); + if (phase === '--prepare') await prepareBenchmark(source, args, scratch); + else if (phase === '--inspect') await inspectBenchmark(scratch); + else if (phase === '--report') await reportBenchmark(scratch); + else + throw new Error('run measurements with bash src/benchmarks/perf/wasix-node/benchmark.sh --run'); +} + +async function prepareBenchmark(planSource, options, scratch) { + const commit = (await readFile(resolve(scratch, 'git-commit'), 'utf8')).trim(); + const porcelain = (await readFile(resolve(scratch, 'git-status'), 'utf8')).trimEnd(); + if (!/^[0-9a-f]{40}$/u.test(commit)) throw new Error('invalid Git source commit'); + const git = { commit, dirty: porcelain.length > 0, statusSha256: sha256(porcelain) }; + const output = options.output ?? defaultOutputDirectory(git.commit); + await requireAbsent(output, 'benchmark output directory'); + const fixture = await createBenchmarkFixture({ + scratch, + consumerName: 'oliphaunt-wasix-node-benchmark-consumer', + }); + const runtimeManifest = readPortableArchiveEntries(fixture.packages.runtime.file).get( + 'package/assets/manifest.json', + ); + if (!runtimeManifest?.isFile) throw new Error('packed runtime is missing its manifest'); + fixture.packages.runtime.build = await runtimeBuildProvenance( + JSON.parse(Buffer.from(runtimeManifest.data()).toString('utf8')), + ); + const sequence = []; + for (const phase of ['worker', 'direct']) { + for (let repeat = 0; repeat < planSource.plan.measurement.pairedRepeats; repeat += 1) { + const order = repeat % 2 === 0 ? ['candidate', 'comparison'] : ['comparison', 'candidate']; + for (const engine of order) sequence.push({ phase, repeat, engine: `${engine}-${phase}` }); + } + } + await mkdir(resolve(scratch, 'runs')); + await writeFile( + resolve(scratch, 'measurement.json'), + JSON.stringify({ planSource, git, fixture, output, sequence }), + ); +} + +async function inspectBenchmark(scratch) { + const file = resolve(scratch, 'measurement.json'); + const state = JSON.parse(await readFile(file, 'utf8')); + const { planSource, git, fixture } = state; + state.provenance = { + git, + machine: machineProvenance(), + tools: await toolProvenance(planSource.file), + candidate: { + packages: stripTemporaryPaths(fixture.packages), + closure: await candidateClosureProvenance( + fixture.consumer, + planSource.plan, + fixture.packages.runtime, + fixture.packages.nativeCarrier, + git.commit, + ), + }, + comparison: await comparisonProvenance(planSource.plan), + }; + await writeFile(file, JSON.stringify(state)); +} + +async function reportBenchmark(scratch) { + const { planSource, provenance, output, sequence } = JSON.parse( + await readFile(resolve(scratch, 'measurement.json'), 'utf8'), + ); + if (!provenance) throw new Error('benchmark inputs must be inspected before measurement'); + const runs = { + 'candidate-direct': [], + 'candidate-worker': [], + 'comparison-direct': [], + 'comparison-worker': [], + }; + const pids = new Set(); + for (const row of sequence) { + const result = JSON.parse( + await readFile(resolve(scratch, 'runs', `${row.repeat}-${row.engine}.json`), 'utf8'), + ); + validateEngineReport(result, row.engine, row.repeat, planSource); + if (pids.has(result.process.pid)) + throw new Error(`engine process ${result.process.pid} was not fresh`); + pids.add(result.process.pid); + row.pid = result.process.pid; + runs[row.engine].push(result); + } + const summary = summarizeRuns(planSource.plan, runs); + const report = { + schema: 'oliphaunt-wasix-node-benchmark-report-v2', + createdAt: new Date().toISOString(), + plan: planSummary(planSource.plan, planSource), + provenance, + execution: { policy: planSource.plan.measurement.processOrder, sequence }, + runs, + summary, + }; + await mkdir(dirname(output), { recursive: true }); + await mkdir(output); + await writeFile(resolve(output, 'report.json'), `${JSON.stringify(report, null, 2)}\n`, { + flag: 'wx', + }); + console.log( + `wasix-node benchmark: ${summary.gate.passed ? 'PASS' : 'FAIL'} worker=${summary.comparisons.worker.geomeanRatio.toFixed(4)} direct=${summary.comparisons.direct.geomeanRatio.toFixed(4)} gate<=${summary.gate.maxGeomeanRatio.toFixed(2)} report=${relative(repositoryRoot, output)}`, + ); + if (!summary.gate.passed) process.exitCode = 1; +} + +async function requireAbsent(path, label) { + try { + await lstat(path); + } catch (error) { + if (error?.code === 'ENOENT') return; + throw error; + } + throw new Error(`${label} already exists: ${path}`); +} + +async function createBenchmarkFixture(options) { + try { + return await stagePackedWasixConsumer({ ...options, includeSeed: true }); + } catch (cause) { + throwNativeCarrierPreflight(cause, 'measured WASIX Node benchmark'); + throw cause; + } +} + +function throwNativeCarrierPreflight(cause, consumer) { + const detail = cause instanceof Error ? cause.message : String(cause); + if ( + /native carrier|Node-API carrier|native artifact provenance|oliphaunt_wasix_napi|wasix-napi-/iu.test( + detail, + ) + ) { + throw new Error( + `${consumer} requires one optimized current-host WASIX Node-API carrier. ` + + 'After staging the portable/AOT runtime, ICU, and extension inputs, run ' + + '`bash src/sdks/ts-wasix/node-addon/tools/build-native.sh`, then retry. ' + + `Carrier preflight: ${detail}`, + { cause }, + ); + } +} + +function validateEngineReport(report, engine, repeat, planSource) { + if ( + report.schema !== 'oliphaunt-wasix-node-engine-run-v2' || + report.plan?.id !== planSource.plan.id || + report.plan?.sha256 !== planSource.sha256 || + report.engine?.kind !== engine || + report.repeat !== repeat || + report.correctness?.passed !== true + ) { + throw new Error(`${engine} repeat ${repeat} returned an invalid engine report`); + } + const candidate = engine.startsWith('candidate'); + const expectedEngine = candidate + ? planSource.plan.engines.candidate + : planSource.plan.engines.comparison; + const surface = + engine === 'candidate-direct' + ? expectedEngine.surfaces.direct + : engine === 'candidate-worker' + ? expectedEngine.surfaces.worker + : engine === 'comparison-worker' + ? expectedEngine.surfaces.worker + : expectedEngine.surfaces.callerRealm; + if ( + report.engine.package !== expectedEngine.package || + report.engine.storage !== expectedEngine.storage || + report.engine.entrypoint !== surface.entrypoint || + report.engine.callingContract !== surface.callingContract || + report.engine.executionOwner !== surface.executionOwner || + report.engine.executionBoundary !== surface.executionBoundary || + report.engine.isolationImplementation !== surface.isolationImplementation || + report.engine.timingBoundary !== surface.timingBoundary + ) { + throw new Error(`${engine} repeat ${repeat} used an unexpected engine identity`); + } + if (!candidate && report.engine.version !== expectedEngine.version) { + throw new Error(`${engine} repeat ${repeat} used version ${report.engine.version}`); + } +} + +function summarizeRuns(plan, runs) { + const correctness = summarizeCorrectness(runs, plan); + const worker = summarizePlacement( + plan, + runs['candidate-worker'], + 'candidate-worker', + runs['comparison-worker'], + 'comparison-worker', + correctness.passed, + ); + const direct = summarizePlacement( + plan, + runs['candidate-direct'], + 'candidate-direct', + runs['comparison-direct'], + 'comparison-direct', + correctness.passed, + ); + return { + correctness, + comparisons: { direct, worker }, + gate: { + passed: worker.gate.passed && direct.gate.passed, + correctnessPassed: correctness.passed, + maxGeomeanRatio: plan.gate.maxGeomeanRatio, + comparisons: { + worker: worker.gate.passed, + direct: direct.gate.passed, + }, + }, + }; +} + +function summarizePlacement( + plan, + candidateInput, + candidateEngine, + comparisonInput, + comparisonEngine, + correctnessPassed, +) { + const candidateRuns = orderedRuns( + candidateInput, + candidateEngine, + plan.measurement.pairedRepeats, + ); + const comparisonRuns = orderedRuns( + comparisonInput, + comparisonEngine, + plan.measurement.pairedRepeats, + ); + const metrics = metricIds(plan).map((id) => { + const candidateSamples = candidateRuns.map((run) => metricValue(run, id)); + const comparisonSamples = comparisonRuns.map((run) => metricValue(run, id)); + const candidateMedianMs = median(candidateSamples); + const comparisonMedianMs = median(comparisonSamples); + const paired = pairedRatioSummary(candidateSamples, comparisonSamples); + return { + id, + candidateSamplesMs: candidateSamples, + comparisonSamplesMs: comparisonSamples, + candidateMedianMs, + comparisonMedianMs, + pairs: paired.pairedRatios.map((ratio, repeat) => ({ + repeat, + candidateMs: candidateSamples[repeat], + comparisonMs: comparisonSamples[repeat], + ratio, + })), + pairedRatioMedian: paired.medianRatio, + }; + }); + const { geomeanRatio, gate } = comfortableWinGate( + metrics.map((metric) => metric.pairedRatioMedian), + plan.gate.maxGeomeanRatio, + correctnessPassed, + ); + return { + metrics, + startupComponents: summarizeStartupComponents(candidateRuns, comparisonRuns), + geomeanRatio, + gate, + }; +} + +function orderedRuns(runs, engine, expectedCount) { + if (!Array.isArray(runs) || runs.length !== expectedCount) { + throw new Error(`${engine} must provide exactly ${expectedCount} paired repeats`); + } + const byRepeat = new Map(); + for (const run of runs) { + if ( + !Number.isSafeInteger(run.repeat) || + run.repeat < 0 || + run.repeat >= expectedCount || + byRepeat.has(run.repeat) + ) { + throw new Error(`${engine} returned duplicate or invalid paired repeat ${run.repeat}`); + } + byRepeat.set(run.repeat, run); + } + return Array.from({ length: expectedCount }, (_, repeat) => { + const run = byRepeat.get(repeat); + if (run === undefined) throw new Error(`${engine} omitted paired repeat ${repeat}`); + return run; + }); +} + +function summarizeStartupComponents(candidateRuns, comparisonRuns) { + return { + separatelyGated: false, + components: startupComponentIds().map((id) => { + const candidateSamplesMs = candidateRuns.map((run) => startupComponentValue(run, id)); + const comparisonSamplesMs = comparisonRuns.map((run) => startupComponentValue(run, id)); + return { + id, + candidateSamplesMs, + comparisonSamplesMs, + candidateMedianMs: median(candidateSamplesMs), + comparisonMedianMs: median(comparisonSamplesMs), + }; + }), + }; +} + +function summarizeCorrectness(runs, plan) { + const all = Object.values(runs).flat(); + const expected = new Set(all.map((run) => run.correctness.expectedSha256)); + const responses = new Set(all.map((run) => run.correctness.responseSha256)); + const postgresSettings = postgresSettingsParity( + all, + plan.postgres.settings, + plan.postgres.expectedSettings, + ); + return { + passed: + all.length > 0 && + all.every((run) => run.correctness.passed) && + expected.size === 1 && + responses.size === 1 && + [...expected][0] === [...responses][0] && + postgresSettings.passed, + expectedSha256: expected.size === 1 ? [...expected][0] : null, + responseSha256: responses.size === 1 ? [...responses][0] : null, + postgresSettings, + }; +} + +function metricValue(run, id) { + if (id === 'cold-to-first-result') { + const openMs = startupComponentValue(run, 'public-open'); + const firstQueryMs = startupComponentValue(run, 'immediate-first-query'); + const composite = positiveTiming(run.timings.coldToFirstResultMs, id); + if (Math.abs(composite - (openMs + firstQueryMs)) > Number.EPSILON * composite * 4) { + throw new Error(`${id} must equal its reported startup components`); + } + return composite; + } + if (id.startsWith('warm-rtt/') && id.endsWith('/p50')) { + const benchmarkId = id.slice('warm-rtt/'.length, -'/p50'.length); + const row = run.timings.warmRtt.find((entry) => entry.id === benchmarkId); + return positiveTiming(row?.latency?.p50Ms, id); + } + if (id.startsWith('bulk/') && id.endsWith('/elapsed')) { + const benchmarkId = id.slice('bulk/'.length, -'/elapsed'.length); + const row = run.timings.bulk.find((entry) => entry.id === benchmarkId); + return positiveTiming(row?.elapsedMs, id); + } + throw new Error(`unsupported metric ${id}`); +} + +function startupComponentIds() { + return ['public-open', 'immediate-first-query']; +} + +function startupComponentValue(run, id) { + if (id === 'public-open') return positiveTiming(run.timings.openMs, id); + if (id === 'immediate-first-query') { + return positiveTiming(run.timings.firstQueryMs, id); + } + throw new Error(`unsupported startup component ${id}`); +} + +function positiveTiming(value, label) { + if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) { + throw new Error(`${label} must be a positive finite timing`); + } + return value; +} + +async function comparisonProvenance(plan) { + const require = createRequire(import.meta.url); + const { manifest } = await findPackageManifest( + require.resolve(plan.engines.comparison.package), + plan.engines.comparison.package, + ); + if (manifest.version !== plan.engines.comparison.version) { + throw new Error( + `installed ${manifest.name}@${manifest.version}, expected ${plan.engines.comparison.version}`, + ); + } + const lock = await readFile(resolve(repositoryRoot, 'bun.lock'), 'utf8'); + if (!lock.includes(plan.engines.comparison.integrity)) { + throw new Error('bun.lock does not contain the comparator integrity from the plan'); + } + const closure = await installedPackageClosure( + require.resolve(plan.engines.comparison.package), + plan.engines.comparison.package, + ); + const root = closure.packages.find((candidate) => candidate.id === closure.root); + if ( + closure.treeHashSchema !== plan.engines.comparison.installedTreeHashSchema || + root?.installedTreeSha256 !== plan.engines.comparison.installedTreeSha256 + ) { + throw new Error( + `installed ${manifest.name}@${manifest.version} tree is ${root?.installedTreeSha256 ?? 'missing'}, ` + + `expected ${plan.engines.comparison.installedTreeSha256}`, + ); + } + return { + package: manifest.name, + version: manifest.version, + homepage: plan.engines.comparison.homepage, + integrity: plan.engines.comparison.integrity, + sourceRepository: plan.engines.comparison.sourceRepository, + sourceCommit: plan.engines.comparison.sourceCommit, + installedClosure: closure, + }; +} + +async function candidateClosureProvenance( + consumer, + plan, + runtimePackage, + nativeCarrier, + artifactSourceSha, +) { + const require = createRequire(resolve(consumer, 'package.json')); + const { manifest } = await findPackageManifest( + require.resolve(plan.engines.candidate.package), + plan.engines.candidate.package, + ); + const nativeAddon = assertNativeArtifactProvenance( + nativeCarrier, + plan.engines.candidate.nativeAddon, + artifactSourceSha, + ); + for (const field of [ + 'dependencies', + 'devDependencies', + 'optionalDependencies', + 'peerDependencies', + ]) { + if (manifest[field]?.[plan.engines.comparison.package] !== undefined) { + throw new Error(`packed candidate ${field} includes benchmark-only PGlite`); + } + } + const installedClosure = await installedPackageClosure( + require.resolve(plan.engines.candidate.package), + plan.engines.candidate.package, + ); + const seedClosure = await installedPackageClosure( + require.resolve('@oliphaunt/seed-wasix-standard/manifest.json'), + '@oliphaunt/seed-wasix-standard', + ); + if (manifest.dependencies?.fzstd !== '0.1.1') { + throw new Error(`packed candidate fzstd dependency is ${manifest.dependencies?.fzstd}`); + } + const build = runtimePackage?.build; + if ( + build?.schema !== 'oliphaunt-wasix-build-provenance-v1' || + build.configuration === undefined || + typeof build.buildProfile?.sha256 !== 'string' || + typeof build.outputs?.sha256 !== 'string' + ) { + throw new Error('packed candidate runtime build provenance is incomplete'); + } + try { + assertRuntimeBuildConfiguration( + build.configuration, + plan.engines.candidate.runtimeBuild, + 'packed candidate runtime build', + ); + } catch (error) { + throw new Error( + `packed candidate runtime build is ${JSON.stringify(build.configuration)}, ` + + `expected ${JSON.stringify(plan.engines.candidate.runtimeBuild)}`, + { cause: error }, + ); + } + return { + package: manifest.name, + version: manifest.version, + dependencies: manifest.dependencies ?? {}, + nativeAddon, + runtimeBuild: build, + installedClosure, + seedClosure, + }; +} + +async function toolProvenance(planFile) { + const files = [ + resolve(toolRoot, 'benchmark.mts'), + resolve(toolRoot, 'benchmark.sh'), + engineRunner, + resolve(toolRoot, 'installed-closure.mts'), + resolve(toolRoot, 'plan.mts'), + resolve(toolRoot, 'pglite-node-worker.mts'), + resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts'), + resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.mts'), + planFile, + ]; + const records = []; + for (const file of files) { + const bytes = await readFile(file); + records.push({ + path: relative(repositoryRoot, file).split('\\').join('/'), + sha256: sha256(bytes), + size: bytes.length, + }); + } + return records; +} + +function machineProvenance() { + const processors = cpus(); + return { + hostname: hostname(), + platform: platform(), + release: release(), + arch: arch(), + node: process.version, + v8: process.versions.v8, + cpuModel: processors[0]?.model ?? 'unknown', + logicalCpus: processors.length, + totalMemoryBytes: totalmem(), + freeMemoryBytesAtStart: freemem(), + }; +} + +function stripTemporaryPaths(packages) { + return Object.fromEntries( + Object.entries(packages).map(([kind, descriptor]) => { + const { file: _, ...portable } = descriptor; + return [kind, portable]; + }), + ); +} + +function defaultOutputDirectory(commit) { + const timestamp = new Date() + .toISOString() + .replaceAll(':', '') + .replaceAll('-', '') + .replace(/\.\d{3}Z$/u, 'Z'); + return resolve(repositoryRoot, 'target/perf', `wasix-node-${timestamp}-${commit.slice(0, 12)}`); +} + +function isCiEnvironment() { + return ['BUILDKITE', 'CI', 'CIRCLECI', 'GITHUB_ACTIONS', 'JENKINS_URL', 'TF_BUILD'].some( + (name) => { + const value = process.env[name]; + return value !== undefined && !['', '0', 'false'].includes(value.toLowerCase()); + }, + ); +} + +function parseArguments(argv) { + let mode; + let config = defaultPlanFile; + let output; + for (let index = 0; index < argv.length; index += 1) { + const flag = argv[index]; + if (['--plan', '--run', '--validate'].includes(flag)) { + if (mode !== undefined) throw new Error('choose exactly one of --plan, --validate, or --run'); + mode = flag.slice(2); + } else if (flag === '--config' || flag === '--output') { + const value = argv[index + 1]; + if (value === undefined) throw new Error(`${flag} requires a value`); + if (flag === '--config') config = resolve(value); + else output = resolve(value); + index += 1; + } else { + throw new Error(`unknown benchmark option ${JSON.stringify(flag)}`); + } + } + mode ??= 'plan'; + if (mode !== 'run' && output !== undefined) throw new Error('--output is only valid with --run'); + if (output === homedir() || output === repositoryRoot) { + throw new Error('--output must not be a home or repository root'); + } + return { mode, config, output }; +} diff --git a/src/benchmarks/perf/wasix-node/benchmark.sh b/src/benchmarks/perf/wasix-node/benchmark.sh new file mode 100644 index 000000000..ecd4fcc16 --- /dev/null +++ b/src/benchmarks/perf/wasix-node/benchmark.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +cd "$root" +tool="$root/src/benchmarks/perf/wasix-node/benchmark.mts" +measured=false +for argument in "$@"; do + if [ "$argument" = --run ]; then measured=true; fi +done +if [ "$measured" = false ]; then exec node "$tool" "$@"; fi +deadline="$(command -v gtimeout || command -v timeout)" +command -v jq >/dev/null +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +git rev-parse HEAD > "$scratch/git-commit" +git status --porcelain=v1 --untracked-files=all > "$scratch/git-status" +node "$tool" --prepare "$scratch" "$@" +( + cd "$scratch/consumer" + NPM_CONFIG_IGNORE_SCRIPTS=true \ + "$deadline" --kill-after=3s 120s bun install --ignore-scripts +) +node "$tool" --inspect "$scratch" "$@" +plan="$(jq -r '.planSource.file' "$scratch/measurement.json")" +jq -r '.sequence[] | [.repeat, .engine] | @tsv' "$scratch/measurement.json" > "$scratch/order" +while IFS=$'\t' read -r repeat engine; do + extra=() + if [[ "$engine" = candidate-* ]]; then extra=(--candidate-root "$scratch/consumer"); fi + "$deadline" --kill-after=3s 900s node src/benchmarks/perf/wasix-node/engine-runner.mts \ + --engine "$engine" --repeat "$repeat" --plan "$plan" \ + --output "$scratch/runs/$repeat-$engine.json" "${extra[@]}" +done < "$scratch/order" +node "$tool" --report "$scratch" "$@" diff --git a/src/benchmarks/perf/wasix-node/engine-runner.mts b/src/benchmarks/perf/wasix-node/engine-runner.mts new file mode 100644 index 000000000..ced79b545 --- /dev/null +++ b/src/benchmarks/perf/wasix-node/engine-runner.mts @@ -0,0 +1,481 @@ +import { createHash } from 'node:crypto'; +import { readFile, writeFile } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import { dirname, relative, resolve } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { Worker } from 'node:worker_threads'; + +import { + assertExpectedRawProtocolResponse, + assertExpectedResult, + bulkSql, + canonicalResult, + expandExpectedResult, + expectedBulkProtocol, + findPackageManifest, + latencySummary, + loadPlan, + sha256, + simpleQueryMessage, + stableJson, +} from './plan.mts'; + +const args = parseArguments(process.argv.slice(2)); +const source = await loadPlan(args.plan); +const expectedStream = createHash('sha256'); +const responseStream = createHash('sha256'); +let database; + +try { + const opened = await timed(() => openEngine(args.engine, source.plan, args.candidateRoot)); + database = opened.value; + const first = await database.measureQuery(source.plan.firstQuery.sql, []); + const firstExpectedSha256 = recordResult( + first.result, + source.plan.firstQuery.expectedResult, + 'first query', + ); + const postgres = await postgresMetadata(database, source.plan); + + await database.execute(source.plan.warmSetupSql); + const warmRtt = []; + for (const benchmark of source.plan.warmRtt) { + const expectedHash = createHash('sha256'); + const responseHash = createHash('sha256'); + const samples = []; + const total = + source.plan.measurement.warmupIterations + source.plan.measurement.sampleIterations; + for (let iteration = 0; iteration < total; iteration += 1) { + const measured = await database.measureQuery(benchmark.sql, benchmark.parameters); + const expected = expectedWarmResult(benchmark, iteration); + assertExpectedResult( + measured.result, + expected, + `warm RTT ${benchmark.id} iteration ${iteration}`, + ); + recordStream(expectedHash, expected); + recordStream(responseHash, measured.result); + recordStream(expectedStream, expected); + recordStream(responseStream, measured.result); + if (iteration >= source.plan.measurement.warmupIterations) { + samples.push(measured.elapsedMs); + } + } + warmRtt.push({ + id: benchmark.id, + latency: latencySummary(samples, source.plan.measurement.trimFraction), + correctness: { + expectedSha256: expectedHash.digest('hex'), + responseSha256: responseHash.digest('hex'), + }, + }); + } + + const warmValidationExpected = expandExpectedResult(source.plan.warmValidation.expectedResult, { + $totalIterations: + source.plan.measurement.warmupIterations + source.plan.measurement.sampleIterations, + }); + const warmValidation = await database.query(source.plan.warmValidation.sql, []); + const warmValidationSha256 = recordResult( + warmValidation, + warmValidationExpected, + 'warm fixture validation', + ); + + const bulk = []; + for (const benchmark of source.plan.bulk) { + const sql = bulkSql(benchmark); + const measured = await database.measureRawProtocol(simpleQueryMessage(sql)); + const expectedProtocol = expectedBulkProtocol(benchmark); + const protocolOutcome = assertExpectedRawProtocolResponse( + measured.response, + expectedProtocol, + `bulk ${benchmark.id}`, + ); + recordStream(expectedStream, expectedProtocol); + recordStream(responseStream, protocolOutcome); + const result = await database.query(benchmark.validationSql ?? sql, []); + const expectedSha256 = recordResult(result, benchmark.expectedResult, `bulk ${benchmark.id}`); + bulk.push({ + id: benchmark.id, + elapsedMs: measured.elapsedMs, + correctness: { + expectedSha256, + protocolExpectedSha256: sha256(stableJson(expectedProtocol)), + protocolOutcomeSha256: sha256(stableJson(protocolOutcome)), + protocolResponseSha256: sha256(measured.response), + responseSha256: sha256(stableJson(result)), + }, + }); + } + + const expectedSha256 = expectedStream.digest('hex'); + const responseSha256 = responseStream.digest('hex'); + const correctness = { + passed: expectedSha256 === responseSha256, + expectedSha256, + responseSha256, + firstQuerySha256: firstExpectedSha256, + warmValidationSha256, + }; + if (!correctness.passed) throw new Error('correctness result-stream hashes differ'); + + const report = { + schema: 'oliphaunt-wasix-node-engine-run-v2', + plan: { id: source.plan.id, sha256: source.sha256 }, + engine: database.identity, + repeat: args.repeat, + process: { pid: process.pid, node: process.version }, + postgres, + timings: { + openMs: opened.elapsedMs, + firstQueryMs: first.elapsedMs, + coldToFirstResultMs: opened.elapsedMs + first.elapsedMs, + warmRtt, + bulk, + }, + correctness, + }; + await writeFile(args.output, `${JSON.stringify(report, null, 2)}\n`, { flag: 'wx' }); + console.log(`wasix-node engine run: PASS ${args.engine} repeat ${args.repeat}`); +} finally { + await database?.close(); +} + +async function openEngine(engine, plan, candidateRoot) { + if (engine === 'candidate-direct') return openCandidate(plan, candidateRoot, 'direct'); + if (engine === 'candidate-worker') return openCandidate(plan, candidateRoot, 'worker'); + if (engine === 'comparison-direct') return openComparisonCallerRealm(plan); + if (engine === 'comparison-worker') return openComparisonWorker(plan); + throw new Error(`unsupported benchmark engine ${JSON.stringify(engine)}`); +} + +async function openCandidate(plan, candidateRoot, surfaceName) { + if (candidateRoot === undefined) + throw new Error('--candidate-root is required for candidate runs'); + const require = createRequire(resolve(candidateRoot, 'package.json')); + const surface = plan.engines.candidate.surfaces[surfaceName]; + const entry = require.resolve(surface.entrypoint); + const { manifest } = await findPackageManifest(entry, plan.engines.candidate.package); + const expectedFile = surfaceName === 'worker' ? 'worker-entry.node.js' : 'direct.node.js'; + if (!entry.split('\\').join('/').endsWith(`/lib/${expectedFile}`)) { + throw new Error( + `${surface.entrypoint} resolved ${entry}, expected the conditional Node entrypoint lib/${expectedFile}`, + ); + } + const module = await import(pathToFileURL(entry).href); + const client = module.default; + if (typeof client?.open !== 'function') { + throw new Error(`${plan.engines.candidate.package} has no default open() client`); + } + if (typeof module.memory !== 'function') { + throw new Error(`${plan.engines.candidate.package} has no explicit memory storage selector`); + } + const instance = await client.open({ + storage: module.memory(), + seed: { + archive: await readFile(require.resolve('@oliphaunt/seed-wasix-standard/seed.tar.zst')), + manifest: await readFile(require.resolve('@oliphaunt/seed-wasix-standard/manifest.json')), + }, + }); + return { + identity: { + kind: surface.engine, + package: manifest.name, + version: manifest.version, + resolvedEntry: relative(candidateRoot, entry).split('\\').join('/'), + entrypoint: surface.entrypoint, + callingContract: surface.callingContract, + executionOwner: surface.executionOwner, + executionBoundary: surface.executionBoundary, + isolationImplementation: surface.isolationImplementation, + timingBoundary: surface.timingBoundary, + storage: plan.engines.candidate.storage, + }, + query: async (sql, parameters) => + canonicalCandidate( + await instance.query(sql, parameters, { rowMode: 'array', valueMode: 'text' }), + ), + execute: (sql) => instance.execute(sql), + measureQuery: async (sql, parameters) => { + const measured = await timed(() => + instance.query(sql, parameters, { rowMode: 'array', valueMode: 'text' }), + ); + return { result: canonicalCandidate(measured.value), elapsedMs: measured.elapsedMs }; + }, + measureRawProtocol: async (input) => { + const measured = await timed(() => instance.execProtocolRaw(input)); + return { response: measured.value, elapsedMs: measured.elapsedMs }; + }, + close: () => instance.close(), + }; +} + +async function openComparisonWorker(plan) { + const surface = plan.engines.comparison.surfaces.worker; + const resolved = await comparisonPackage(plan); + const rpc = benchmarkWorkerRpc( + new Worker(new URL('./pglite-node-worker.mts', import.meta.url), { + name: 'oliphaunt-pglite-benchmark', + }), + ); + await rpc.ready; + return { + identity: { + kind: surface.engine, + package: resolved.manifest.name, + version: resolved.manifest.version, + resolvedEntry: resolved.entry, + entrypoint: surface.entrypoint, + callingContract: surface.callingContract, + executionOwner: surface.executionOwner, + executionBoundary: surface.executionBoundary, + isolationImplementation: surface.isolationImplementation, + isolationAdapter: 'src/benchmarks/perf/wasix-node/pglite-node-worker.mts', + timingBoundary: surface.timingBoundary, + storage: plan.engines.comparison.storage, + }, + query: async (sql, parameters) => + canonicalComparison((await rpc.request('query', [sql, parameters])).result), + execute: async (sql) => { + await rpc.request('execute', [sql]); + }, + measureQuery: async (sql, parameters) => { + const measured = await timed(() => rpc.request('query', [sql, parameters])); + return { + result: canonicalComparison(measured.value.result), + elapsedMs: measured.elapsedMs, + }; + }, + measureRawProtocol: async (input) => { + const measured = await timed(() => + rpc.request('rawProtocol', [input, plan.bulkTransport.pgliteSyncToFs], [input.buffer]), + ); + return { + response: measured.value.response, + elapsedMs: measured.elapsedMs, + }; + }, + close: () => rpc.close(), + }; +} + +async function openComparisonCallerRealm(plan) { + const surface = plan.engines.comparison.surfaces.callerRealm; + const resolved = await comparisonPackage(plan); + const { PGlite } = await import(plan.engines.comparison.package); + const instance = await PGlite.create('memory://'); + return { + identity: { + kind: surface.engine, + package: resolved.manifest.name, + version: resolved.manifest.version, + resolvedEntry: resolved.entry, + entrypoint: surface.entrypoint, + callingContract: surface.callingContract, + executionOwner: surface.executionOwner, + executionBoundary: surface.executionBoundary, + isolationImplementation: surface.isolationImplementation, + timingBoundary: surface.timingBoundary, + storage: plan.engines.comparison.storage, + }, + query: async (sql, parameters) => canonicalComparison(await instance.query(sql, parameters)), + execute: (sql) => instance.exec(sql), + measureQuery: async (sql, parameters) => { + const measured = await timed(() => instance.query(sql, parameters)); + return { result: canonicalComparison(measured.value), elapsedMs: measured.elapsedMs }; + }, + measureRawProtocol: async (input) => { + const measured = await timed(() => + instance.execProtocolRaw(input, { syncToFs: plan.bulkTransport.pgliteSyncToFs }), + ); + return { response: measured.value, elapsedMs: measured.elapsedMs }; + }, + close: () => instance.close(), + }; +} + +async function comparisonPackage(plan) { + const require = createRequire(import.meta.url); + const requireEntry = require.resolve(plan.engines.comparison.package); + const { file: manifestFile, manifest } = await findPackageManifest( + requireEntry, + plan.engines.comparison.package, + ); + if (manifest.version !== plan.engines.comparison.version) { + throw new Error( + `${plan.engines.comparison.package} resolved ${manifest.version}, expected ${plan.engines.comparison.version}`, + ); + } + const resolvedEntry = fileURLToPath(import.meta.resolve(plan.engines.comparison.package)); + return { + manifest, + entry: relative(dirname(manifestFile), resolvedEntry).split('\\').join('/'), + }; +} + +function benchmarkWorkerRpc(worker) { + let closing = false; + let nextId = 1; + let terminalError; + let resolveReady; + let rejectReady; + const pending = new Map(); + const ready = new Promise((resolvePromise, rejectPromise) => { + resolveReady = resolvePromise; + rejectReady = rejectPromise; + }); + worker.on('message', (message) => { + if (message?.type === 'ready') { + resolveReady(); + return; + } + if (message?.type !== 'response') return; + const request = pending.get(message.id); + if (request === undefined) return; + pending.delete(message.id); + if (message.error === undefined) { + request.resolve(message.result); + } else { + const error = new Error(message.error.message); + error.name = message.error.name; + error.stack = message.error.stack; + request.reject(error); + } + }); + worker.on('error', fail); + worker.on('exit', (code) => { + if (!closing) fail(new Error(`PGlite benchmark worker exited with code ${code}`)); + }); + + function fail(error) { + terminalError ??= error; + rejectReady(error); + for (const request of pending.values()) request.reject(error); + pending.clear(); + } + + function request(method, args, transfer = []) { + if (terminalError !== undefined) return Promise.reject(terminalError); + if (closing) return Promise.reject(new Error('PGlite benchmark worker is closing')); + const id = nextId; + nextId += 1; + return new Promise((resolvePromise, rejectPromise) => { + pending.set(id, { resolve: resolvePromise, reject: rejectPromise }); + worker.postMessage({ id, method, args }, transfer); + }); + } + + return { + ready, + request, + async close() { + const closed = request('close', []); + closing = true; + try { + await closed; + } finally { + await worker.terminate(); + } + }, + }; +} + +function canonicalCandidate(result) { + return canonicalResult( + result.fields.map((field) => field.name), + result.rows.map((row) => [...row]), + ); +} + +function canonicalComparison(result) { + const fields = result.fields.map((field) => field.name); + return canonicalResult( + fields, + result.rows.map((row) => + Array.isArray(row) ? row : fields.map((field) => row[field] ?? null), + ), + ); +} + +async function postgresMetadata(database, plan) { + const settingColumns = plan.postgres.settings + .map((setting) => `current_setting('${setting}')::text AS ${setting}`) + .join(', '); + const result = await database.query(`SELECT version()::text AS version, ${settingColumns}`, []); + const version = result.rows[0]?.[0]; + if (typeof version !== 'string' || !version.startsWith(`PostgreSQL ${plan.postgres.major}.`)) { + throw new Error( + `engine reported ${JSON.stringify(version)}, expected PostgreSQL ${plan.postgres.major}`, + ); + } + return { + version, + settings: Object.fromEntries( + plan.postgres.settings.map((setting, index) => [setting, result.rows[0][index + 1]]), + ), + }; +} + +function expectedWarmResult(benchmark, iteration) { + if (benchmark.expectation.kind === 'exact') return benchmark.expectation.result; + return { + fields: [benchmark.expectation.field], + rows: [[String(iteration + 1)]], + }; +} + +function recordResult(actual, expected, label) { + const expectedSha256 = assertExpectedResult(actual, expected, label); + recordStream(expectedStream, expected); + recordStream(responseStream, actual); + return expectedSha256; +} + +function recordStream(hash, result) { + hash.update(stableJson(result)); + hash.update('\n'); +} + +async function timed(operation) { + const started = process.hrtime.bigint(); + const value = await operation(); + const ended = process.hrtime.bigint(); + return { value, elapsedMs: Number(ended - started) / 1_000_000 }; +} + +function parseArguments(argv) { + const values = {}; + for (let index = 0; index < argv.length; index += 2) { + const flag = argv[index]; + const value = argv[index + 1]; + if (!['--candidate-root', '--engine', '--output', '--plan', '--repeat'].includes(flag)) { + throw new Error(`unknown engine runner option ${JSON.stringify(flag)}`); + } + if (value === undefined) throw new Error(`${flag} requires a value`); + if (values[flag] !== undefined) throw new Error(`${flag} may only be provided once`); + values[flag] = value; + } + if ( + !['candidate-direct', 'candidate-worker', 'comparison-direct', 'comparison-worker'].includes( + values['--engine'], + ) + ) { + throw new Error( + '--engine must be candidate-direct, candidate-worker, comparison-direct, or comparison-worker', + ); + } + const repeat = Number(values['--repeat']); + if (!Number.isSafeInteger(repeat) || repeat < 0) { + throw new Error('--repeat must be a non-negative integer'); + } + if (values['--output'] === undefined) throw new Error('--output is required'); + return { + engine: values['--engine'], + output: resolve(values['--output']), + plan: values['--plan'] === undefined ? undefined : resolve(values['--plan']), + repeat, + candidateRoot: + values['--candidate-root'] === undefined ? undefined : resolve(values['--candidate-root']), + }; +} diff --git a/src/benchmarks/perf/wasix-node/installed-closure.mts b/src/benchmarks/perf/wasix-node/installed-closure.mts new file mode 100644 index 000000000..2ff3e761e --- /dev/null +++ b/src/benchmarks/perf/wasix-node/installed-closure.mts @@ -0,0 +1,162 @@ +import { createHash } from 'node:crypto'; +import { access, lstat, readdir, readFile, readlink, realpath } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import { resolve } from 'node:path'; + +import { findPackageManifest, sha256, stableJson } from './plan.mts'; + +const DEPENDENCY_FIELDS = [ + ['dependencies', true], + ['optionalDependencies', false], + ['peerDependencies', false], +]; + +export async function installedPackageClosure(entry, expectedName) { + const rootPackage = await installedPackage(entry, expectedName); + const pending = [rootPackage]; + const packagesByDirectory = new Map(); + + while (pending.length > 0) { + const current = pending.shift(); + if (packagesByDirectory.has(current.directory)) continue; + packagesByDirectory.set(current.directory, current); + const dependencies = declaredDependencies(current.manifest); + const require = createRequire(current.manifestFile); + for (const dependency of dependencies) { + let dependencyEntry; + // A dependency may expose only subpaths, with no root or package.json export. + for (const directory of require.resolve.paths(dependency.name) ?? []) { + const manifest = resolve(directory, dependency.name, 'package.json'); + try { + await access(manifest); + dependencyEntry = manifest; + break; + } catch (error) { + if (error?.code !== 'ENOENT') throw error; + } + } + if (dependencyEntry === undefined) { + if (!dependency.required) { + dependency.installed = false; + continue; + } + throw new Error( + `${current.manifest.name}@${current.manifest.version} cannot resolve installed dependency ${dependency.name}`, + ); + } + const installed = await installedPackage(dependencyEntry, dependency.name); + dependency.installed = true; + dependency.targetDirectory = installed.directory; + pending.push(installed); + } + current.dependencies = dependencies; + } + + for (const current of packagesByDirectory.values()) { + current.treeSha256 = await directoryTreeSha256(current.directory); + current.id = packageId(current.manifest, current.treeSha256); + } + const packages = [...packagesByDirectory.values()] + .map((current) => ({ + id: current.id, + name: current.manifest.name, + version: current.manifest.version, + installedTreeSha256: current.treeSha256, + dependencies: current.dependencies.map((dependency) => ({ + name: dependency.name, + specifier: dependency.specifier, + kinds: dependency.kinds, + installed: dependency.installed, + target: + dependency.targetDirectory === undefined + ? null + : packagesByDirectory.get(dependency.targetDirectory).id, + })), + })) + .sort((left, right) => left.id.localeCompare(right.id)); + const root = packages.find((candidate) => candidate.id === rootPackage.id); + if (root === undefined) throw new Error(`installed closure lost root package ${expectedName}`); + return { + schema: 'oliphaunt-installed-node-package-closure-v1', + treeHashSchema: 'oliphaunt-path-size-content-sha256-v1', + root: root.id, + sha256: sha256(stableJson(packages)), + packages, + }; +} + +export async function directoryTreeSha256(root) { + const hash = createHash('sha256'); + await visit(await realpath(root), ''); + return hash.digest('hex'); + + async function visit(directory, prefix) { + const names = (await readdir(directory)).sort(); + for (const name of names) { + const absolute = resolve(directory, name); + const child = prefix === '' ? name : `${prefix}/${name}`; + const stats = await lstat(absolute); + if (stats.isDirectory()) { + hash.update(`d ${child}\n`); + await visit(absolute, child); + } else if (stats.isSymbolicLink()) { + hash.update(`l ${child} ${await readlink(absolute)}\n`); + } else if (stats.isFile()) { + hash.update(`f ${child} ${stats.size}\n`); + hash.update(await readFile(absolute)); + hash.update('\n'); + } else { + throw new Error(`unsupported installed package member ${absolute}`); + } + } + } +} + +async function installedPackage(entry, expectedName) { + const { file: manifestFile, manifest } = await findPackageManifest(entry, expectedName); + if ( + typeof manifest.name !== 'string' || + typeof manifest.version !== 'string' || + manifest.name !== expectedName + ) { + throw new Error(`installed package from ${entry} has an invalid ${expectedName} identity`); + } + return { + directory: await realpath(resolve(manifestFile, '..')), + manifestFile: await realpath(manifestFile), + manifest, + }; +} + +function declaredDependencies(manifest) { + const dependencies = new Map(); + for (const [field, required] of DEPENDENCY_FIELDS) { + for (const [name, specifier] of Object.entries(manifest[field] ?? {})) { + if ( + !/^(?:@[a-z0-9_.-]+\/)?[a-z0-9_.-]+$/iu.test(name) || + name.split('/').some((part) => part === '.' || part === '..') + ) { + throw new Error(`invalid dependency name ${JSON.stringify(name)}`); + } + const existing = dependencies.get(name) ?? { + name, + specifier, + kinds: [], + required: false, + }; + if (existing.specifier !== specifier) { + throw new Error( + `${manifest.name}@${manifest.version} declares conflicting ${name} dependency specifiers`, + ); + } + existing.kinds.push(field); + existing.required ||= required; + dependencies.set(name, existing); + } + } + return [...dependencies.values()].sort((left, right) => left.name.localeCompare(right.name)); +} + +function packageId(manifest, treeSha256) { + return `${manifest.name}@${manifest.version}#${treeSha256.slice(0, 16)}`; +} diff --git a/src/benchmarks/perf/wasix-node/package.json b/src/benchmarks/perf/wasix-node/package.json new file mode 100644 index 000000000..56362c694 --- /dev/null +++ b/src/benchmarks/perf/wasix-node/package.json @@ -0,0 +1,12 @@ +{ + "name": "@oliphaunt/perf-wasix-node", + "version": "0.0.0", + "private": true, + "type": "module", + "dependencies": { + "@electric-sql/pglite": "0.5.4" + }, + "engines": { + "node": ">=22.13 <25" + } +} diff --git a/tools/perf/wasix-node/pglite-node-worker.mjs b/src/benchmarks/perf/wasix-node/pglite-node-worker.mts similarity index 100% rename from tools/perf/wasix-node/pglite-node-worker.mjs rename to src/benchmarks/perf/wasix-node/pglite-node-worker.mts diff --git a/src/benchmarks/perf/wasix-node/plan.mts b/src/benchmarks/perf/wasix-node/plan.mts new file mode 100644 index 000000000..0e83ae321 --- /dev/null +++ b/src/benchmarks/perf/wasix-node/plan.mts @@ -0,0 +1,1158 @@ +import { createHash } from 'node:crypto'; +import { readFile } from 'node:fs/promises'; +import { dirname, isAbsolute, relative as relativePath, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +export const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../../..'); +export const defaultPlanFile = resolve( + repositoryRoot, + 'src/benchmarks/wasix/node-pglite-memory-v2.json', +); + +const PLAN_SCHEMA = 'oliphaunt-wasix-node-benchmark-plan-v2'; +const PLAN_ID = 'node-pglite-memory-v2'; +const PACKAGE_NAME = '@oliphaunt/wasix-ts'; +const COMPARISON_PACKAGE = '@electric-sql/pglite'; +const GATED_TIMING_BOUNDARY = 'host-end-to-end-around-one-isolation-rpc'; +const LOWER_GIT_SHA = /^[0-9a-f]{40}$/u; +const SAFE_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u; +const SAFE_SETTING = /^[a-z][a-z0-9_]*$/u; +const BULK_OPERATIONS = new Set([ + 'aggregate-query', + 'create-and-insert-series', + 'create-payload-index', + 'reverse-indexed-prefix', +]); +const UTF8_ENCODER = new TextEncoder(); +const UTF8_DECODER = new TextDecoder(); + +export async function loadPlan(file = defaultPlanFile) { + const bytes = await readFile(file); + let plan; + try { + plan = JSON.parse(bytes.toString('utf8')); + } catch (error) { + throw new Error(`${relative(file)} must contain JSON: ${describeError(error)}`); + } + validatePlan(plan); + return { plan, file: resolve(file), sha256: sha256(bytes), size: bytes.length }; +} + +function validateEngines(plan) { + equal(plan.id, PLAN_ID, 'plan.id'); + const engines = object(plan.engines, 'plan.engines'); + exactKeys(engines, ['candidate', 'comparison'], 'plan.engines'); + const candidate = object(engines.candidate, 'plan.engines.candidate'); + exactKeys( + candidate, + ['nativeAddon', 'package', 'runtimeBuild', 'storage', 'surfaces'], + 'plan.engines.candidate', + ); + validateCandidateIdentity(candidate); + const candidateSurfaces = object(candidate.surfaces, 'plan.engines.candidate.surfaces'); + exactKeys(candidateSurfaces, ['direct', 'worker'], 'plan.engines.candidate.surfaces'); + exactRecord( + candidateSurfaces.worker, + { + callingContract: 'async', + engine: 'candidate-worker', + entrypoint: '@oliphaunt/wasix-ts/worker', + executionBoundary: 'node-worker-thread', + executionOwner: 'sdk-worker', + isolationImplementation: 'package-owned-worker-rpc', + timingBoundary: GATED_TIMING_BOUNDARY, + }, + 'plan.engines.candidate.surfaces.worker', + ); + exactRecord( + candidateSurfaces.direct, + { + callingContract: 'async', + engine: 'candidate-direct', + entrypoint: '@oliphaunt/wasix-ts/direct', + executionBoundary: 'node-caller-realm', + executionOwner: 'caller', + isolationImplementation: 'none-caller-realm', + timingBoundary: 'caller-around-public-api', + }, + 'plan.engines.candidate.surfaces.direct', + ); + + const comparison = object(engines.comparison, 'plan.engines.comparison'); + exactKeys( + comparison, + [ + 'homepage', + 'installedTreeHashSchema', + 'installedTreeSha256', + 'integrity', + 'package', + 'sourceCommit', + 'sourceRepository', + 'storage', + 'surfaces', + 'version', + ], + 'plan.engines.comparison', + ); + validateComparisonIdentity(comparison); + const comparisonSurfaces = object(comparison.surfaces, 'plan.engines.comparison.surfaces'); + exactKeys(comparisonSurfaces, ['callerRealm', 'worker'], 'plan.engines.comparison.surfaces'); + exactRecord( + comparisonSurfaces.worker, + { + benchmarkMethodology: 'official-browser-worker-timer-reference-only-not-collected', + benchmarkMethodologySource: 'packages/benchmark/src/benchmarks-worker.js', + callingContract: 'async', + engine: 'comparison-worker', + entrypoint: 'src/benchmarks/perf/wasix-node/pglite-node-worker.mts', + executionBoundary: 'node-worker-thread', + executionOwner: 'harness-worker', + gatedResponsePayload: 'public-result-only-no-comparator-telemetry', + isolationImplementation: 'harness-owned-worker-threads-rpc', + officialWorkerModule: 'browser-worker-only', + timingBoundary: GATED_TIMING_BOUNDARY, + }, + 'plan.engines.comparison.surfaces.worker', + ); + exactRecord( + comparisonSurfaces.callerRealm, + { + callingContract: 'async', + engine: 'comparison-direct', + entrypoint: '@electric-sql/pglite', + executionBoundary: 'node-main-thread', + executionOwner: 'caller', + isolationImplementation: 'none-caller-realm', + timingBoundary: 'caller-around-public-api', + }, + 'plan.engines.comparison.surfaces.callerRealm', + ); +} + +function validateCandidateIdentity(candidate) { + equal(candidate.package, PACKAGE_NAME, 'plan.engines.candidate.package'); + equal(candidate.storage, 'memory', 'plan.engines.candidate.storage'); + assertNativeAddonContract( + candidate.nativeAddon, + candidate.nativeAddon, + 'plan.engines.candidate.nativeAddon', + ); + object(candidate.runtimeBuild, 'plan.engines.candidate.runtimeBuild'); +} + +export function validateComparisonIdentity(comparison) { + equal(comparison.package, COMPARISON_PACKAGE, 'plan.engines.comparison.package'); + if (typeof comparison.version !== 'string' || !/^\d+\.\d+\.\d+$/u.test(comparison.version)) { + fail('plan.engines.comparison.version must be an exact release version'); + } + if ( + typeof comparison.integrity !== 'string' || + !/^sha512-[A-Za-z0-9+/]{86}==$/u.test(comparison.integrity) + ) { + fail('plan.engines.comparison.integrity must be one exact SHA-512 SRI'); + } + if (!LOWER_GIT_SHA.test(comparison.sourceCommit ?? '')) { + fail('plan.engines.comparison.sourceCommit must be a full lowercase Git commit'); + } + equal(comparison.storage, 'memory', 'plan.engines.comparison.storage'); + equal( + comparison.installedTreeHashSchema, + 'oliphaunt-path-size-content-sha256-v1', + 'plan.engines.comparison.installedTreeHashSchema', + ); + if (!/^[0-9a-f]{64}$/u.test(comparison.installedTreeSha256 ?? '')) { + fail('plan.engines.comparison.installedTreeSha256 must be a SHA-256 digest'); + } +} + +function exactRecord(actual, expected, label) { + const record = object(actual, label); + exactKeys(record, Object.keys(expected), label); + for (const [field, value] of Object.entries(expected)) { + equal(record[field], value, `${label}.${field}`); + } +} + +export function validatePlan(plan) { + object(plan, 'plan'); + exactKeys( + plan, + [ + 'bulk', + 'bulkTransport', + 'description', + 'engines', + 'firstQuery', + 'gate', + 'id', + 'measurement', + 'postgres', + 'schema', + 'warmRtt', + 'warmSetupSql', + 'warmValidation', + ], + 'plan', + ); + equal(plan.schema, PLAN_SCHEMA, 'plan.schema'); + validateEngines(plan); + safeId(plan.id, 'plan.id'); + nonEmptyString(plan.description, 'plan.description'); + + const measurement = object(plan.measurement, 'plan.measurement'); + exactKeys( + measurement, + [ + 'pairedRepeats', + 'pairing', + 'percentileMethod', + 'processOrder', + 'sampleIterations', + 'startupMetric', + 'startupMetricIncludes', + 'trimFraction', + 'warmupIterations', + ], + 'plan.measurement', + ); + positiveInteger(measurement.pairedRepeats, 'plan.measurement.pairedRepeats', 9); + if (measurement.pairedRepeats % 2 !== 0) { + fail('plan.measurement.pairedRepeats must be even to balance gated engine launch order'); + } + positiveInteger(measurement.warmupIterations, 'plan.measurement.warmupIterations', 1); + positiveInteger(measurement.sampleIterations, 'plan.measurement.sampleIterations', 20); + if ( + typeof measurement.trimFraction !== 'number' || + measurement.trimFraction < 0 || + measurement.trimFraction >= 0.5 + ) { + fail('plan.measurement.trimFraction must be a number from 0 up to, but not including, 0.5'); + } + equal( + measurement.processOrder, + 'alternating-worker-pairs-then-alternating-direct-pairs-fresh-processes', + 'plan.measurement.processOrder', + ); + equal(measurement.pairing, 'same-repeat-candidate-over-comparison', 'plan.measurement.pairing'); + equal(measurement.percentileMethod, 'nearest-rank', 'plan.measurement.percentileMethod'); + equal(measurement.startupMetric, 'cold-to-first-result', 'plan.measurement.startupMetric'); + exactStringList( + measurement.startupMetricIncludes, + ['public-open', 'immediate-first-query'], + 'plan.measurement.startupMetricIncludes', + ); + + const gate = object(plan.gate, 'plan.gate'); + exactKeys( + gate, + ['comparisons', 'includes', 'maxGeomeanRatio', 'metric', 'requiresCorrectness'], + 'plan.gate', + ); + if ( + typeof gate.maxGeomeanRatio !== 'number' || + gate.maxGeomeanRatio <= 0 || + gate.maxGeomeanRatio > 0.8 + ) { + fail('plan.gate.maxGeomeanRatio must be positive and no greater than 0.80'); + } + equal(gate.requiresCorrectness, true, 'plan.gate.requiresCorrectness'); + exactStringList(gate.comparisons, ['worker', 'direct'], 'plan.gate.comparisons'); + equal( + gate.metric, + 'geometric-mean-of-median-paired-candidate-over-comparison-ratios-lower-is-better', + 'plan.gate.metric', + ); + exactStringList( + gate.includes, + ['cold-to-first-result', 'warm-rtt-p50', 'bulk-elapsed'], + 'plan.gate.includes', + ); + + const bulkTransport = object(plan.bulkTransport, 'plan.bulkTransport'); + exactKeys( + bulkTransport, + ['pgliteSyncToFs', 'publicApi', 'request', 'response', 'validation'], + 'plan.bulkTransport', + ); + equal(bulkTransport.publicApi, 'execProtocolRaw', 'plan.bulkTransport.publicApi'); + equal(bulkTransport.request, 'postgres-simple-query-message', 'plan.bulkTransport.request'); + equal(bulkTransport.response, 'raw-postgres-protocol-bytes', 'plan.bulkTransport.response'); + equal(bulkTransport.pgliteSyncToFs, false, 'plan.bulkTransport.pgliteSyncToFs'); + equal( + bulkTransport.validation, + 'timed-response-semantics-and-canonical-state-validation', + 'plan.bulkTransport.validation', + ); + + const postgres = object(plan.postgres, 'plan.postgres'); + exactKeys(postgres, ['expectedSettings', 'major', 'settings'], 'plan.postgres'); + positiveInteger(postgres.major, 'plan.postgres.major', 1); + nonEmptyArray(postgres.settings, 'plan.postgres.settings'); + const settings = new Set(); + for (const [index, setting] of postgres.settings.entries()) { + if (typeof setting !== 'string' || !SAFE_SETTING.test(setting) || settings.has(setting)) { + fail(`plan.postgres.settings[${index}] must be a unique safe PostgreSQL setting name`); + } + settings.add(setting); + } + const expectedSettings = object(postgres.expectedSettings, 'plan.postgres.expectedSettings'); + exactKeys(expectedSettings, postgres.settings, 'plan.postgres.expectedSettings'); + for (const setting of postgres.settings) { + nonEmptyString(expectedSettings[setting], `plan.postgres.expectedSettings.${setting}`); + } + + validateQuery(plan.firstQuery, 'plan.firstQuery'); + nonEmptyString(plan.warmSetupSql, 'plan.warmSetupSql'); + validateWarmCases(plan.warmRtt); + validateQuery(plan.warmValidation, 'plan.warmValidation', { allowPlaceholder: true }); + validateBulk(plan.bulk); + return plan; +} + +export function planSummary(plan, source) { + return { + schema: plan.schema, + id: plan.id, + source: { + path: relative(source.file), + sha256: source.sha256, + size: source.size, + }, + engines: plan.engines, + measurement: plan.measurement, + gate: plan.gate, + bulkTransport: plan.bulkTransport, + postgres: plan.postgres, + metrics: metricIds(plan), + generatedSql: plan.bulk.map((entry) => ({ + id: entry.id, + operation: entry.operation, + sha256: sha256(bulkSql(entry)), + bytes: Buffer.byteLength(bulkSql(entry)), + })), + }; +} + +export function assertRuntimeBuildConfiguration(actual, expected, label = 'runtime build') { + object(actual, label); + object(expected, `${label} expectation`); + exactKeys(actual, Object.keys(expected), label); + for (const [field, value] of Object.entries(expected)) { + equal(actual[field], value, `${label}.${field}`); + } +} + +export function assertNativeAddonContract(actual, expected, label = 'native addon') { + const fields = [ + 'addonAbiVersion', + 'binary', + 'build', + 'nodeApiVersion', + 'product', + 'profiles', + 'schema', + ]; + const actualAddon = object(actual, label); + const expectedAddon = object(expected, `${label} expectation`); + exactKeys(actualAddon, fields, label); + exactKeys(expectedAddon, fields, `${label} expectation`); + for (const addon of [actualAddon, expectedAddon]) { + equal(addon.schema, 'oliphaunt-wasix-napi-host-v1', `${label}.schema`); + equal(addon.product, 'oliphaunt-wasix-napi', `${label}.product`); + equal(addon.binary, 'oliphaunt_wasix_napi.node', `${label}.binary`); + positiveInteger(addon.addonAbiVersion, `${label}.addonAbiVersion`, 1); + positiveInteger(addon.nodeApiVersion, `${label}.nodeApiVersion`, 8); + exactStringList(addon.profiles, ['standard', 'icu'], `${label}.profiles`); + const build = object(addon.build, `${label}.build`); + exactKeys( + build, + ['cargoProfile', 'codegenUnits', 'features', 'incremental', 'lto', 'strip'], + `${label}.build`, + ); + equal(build.cargoProfile, 'release', `${label}.build.cargoProfile`); + equal(build.incremental, false, `${label}.build.incremental`); + equal(build.codegenUnits, 1, `${label}.build.codegenUnits`); + equal(build.lto, 'thin', `${label}.build.lto`); + equal(build.strip, 'symbols', `${label}.build.strip`); + exactStringList(build.features, ['release'], `${label}.build.features`); + } + for (const field of ['schema', 'product', 'binary', 'addonAbiVersion', 'nodeApiVersion']) { + equal(actualAddon[field], expectedAddon[field], `${label}.${field}`); + } + exactStringList(actualAddon.profiles, expectedAddon.profiles, `${label}.profiles`); + for (const field of ['cargoProfile', 'incremental', 'codegenUnits', 'lto', 'strip']) { + equal(actualAddon.build[field], expectedAddon.build[field], `${label}.build.${field}`); + } + exactStringList( + actualAddon.build.features, + expectedAddon.build.features, + `${label}.build.features`, + ); + return actualAddon; +} + +export function assertNativeArtifactProvenance(carrier, expectedAddon, expectedArtifactSourceSha) { + assertNativeAddonContract(expectedAddon, expectedAddon, 'benchmark native addon contract'); + if (!LOWER_GIT_SHA.test(expectedArtifactSourceSha ?? '')) { + fail('benchmark artifact source must be a full lowercase Git commit'); + } + if (carrier === undefined) fail('packed candidate has no native carrier'); + const provenance = carrier.artifactProvenance; + const manifest = carrier.manifest; + const buildInputs = provenance?.buildInputs; + if ( + provenance?.schema !== 'oliphaunt-wasix-napi-provenance-v1' || + provenance.product !== expectedAddon.product || + provenance.target !== carrier.target || + provenance.artifactSourceSha !== expectedArtifactSourceSha || + provenance.binary?.filename !== expectedAddon.binary || + !/^[0-9a-f]{64}$/u.test(provenance.binary?.sha256 ?? '') || + buildInputs?.schema !== 'oliphaunt-wasix-napi-build-inputs-v1' || + buildInputs.target !== carrier.target || + manifest?.oliphaunt?.target !== carrier.target || + manifest.oliphaunt.addonAbiVersion !== expectedAddon.addonAbiVersion || + manifest.oliphaunt.nodeApiVersion !== expectedAddon.nodeApiVersion || + stableJson(manifest.oliphaunt.profiles) !== stableJson(expectedAddon.profiles) + ) { + fail('packed candidate native carrier differs from the benchmark addon/source contract'); + } + const build = provenance.build; + const { targetTriple, ...portableBuild } = build ?? {}; + if ( + typeof targetTriple !== 'string' || + targetTriple.length === 0 || + stableJson(portableBuild) !== stableJson(expectedAddon.build) || + targetTriple !== buildInputs.targetTriple + ) { + fail('packed candidate native carrier has incompatible optimized build provenance'); + } + return { + carrier: carrier.name, + version: carrier.version, + target: carrier.target, + artifactProvenanceMember: carrier.artifactProvenanceMember, + artifactProvenance: provenance, + }; +} + +export function metricIds(plan) { + return [ + 'cold-to-first-result', + ...plan.warmRtt.map((entry) => `warm-rtt/${entry.id}/p50`), + ...plan.bulk.map((entry) => `bulk/${entry.id}/elapsed`), + ]; +} + +export function bulkSql(entry) { + switch (entry.operation.kind) { + case 'create-and-insert-series': + return `CREATE TABLE bench_bulk (id integer PRIMARY KEY, payload text NOT NULL, revision integer NOT NULL DEFAULT 0); INSERT INTO bench_bulk (id, payload) SELECT i, md5(i::text) FROM generate_series(1, ${entry.operation.rows}) AS i;`; + case 'create-payload-index': + return 'CREATE INDEX bench_bulk_payload_idx ON bench_bulk(payload);'; + case 'reverse-indexed-prefix': + return `UPDATE bench_bulk SET payload = reverse(payload), revision = revision + 1 WHERE id <= ${entry.operation.rows};`; + case 'aggregate-query': + return 'SELECT count(*)::bigint AS rows, sum(id)::bigint AS sum_id, sum(octet_length(payload))::bigint AS total_bytes FROM bench_bulk'; + default: + throw new Error(`unsupported bulk operation ${JSON.stringify(entry.operation.kind)}`); + } +} + +export function simpleQueryMessage(sql) { + if (typeof sql !== 'string' || sql.includes('\0')) { + throw new Error('simple query SQL must be a string without NUL bytes'); + } + const body = UTF8_ENCODER.encode(sql); + const packet = new Uint8Array(body.length + 6); + packet[0] = 0x51; + writeI32(packet, 1, body.length + 5); + packet.set(body, 5); + return packet; +} + +export function assertSuccessfulRawProtocolResponse(bytes, label) { + decodeRawProtocolOutcome(bytes, label); +} + +export function assertExpectedRawProtocolResponse(bytes, expected, label) { + const actual = decodeRawProtocolOutcome(bytes, label); + if (stableJson(actual) !== stableJson(expected)) { + throw new Error( + `${label} returned protocol outcome ${stableJson(actual)}, expected ${stableJson(expected)}`, + ); + } + return actual; +} + +export function expectedBulkProtocol(entry) { + switch (entry.operation.kind) { + case 'create-and-insert-series': + return { + commandTags: ['CREATE TABLE', `INSERT 0 ${entry.operation.rows}`], + results: [], + transactionStatus: 'idle', + }; + case 'create-payload-index': + return { commandTags: ['CREATE INDEX'], results: [], transactionStatus: 'idle' }; + case 'reverse-indexed-prefix': + return { + commandTags: [`UPDATE ${entry.operation.rows}`], + results: [], + transactionStatus: 'idle', + }; + case 'aggregate-query': + return { + commandTags: ['SELECT 1'], + results: [entry.expectedResult], + transactionStatus: 'idle', + }; + default: + throw new Error(`unsupported bulk operation ${JSON.stringify(entry.operation.kind)}`); + } +} + +export function decodeRawProtocolOutcome(bytes, label) { + if (!(bytes instanceof Uint8Array)) { + throw new Error(`${label} must return raw PostgreSQL protocol bytes`); + } + let offset = 0; + let sawReady = false; + let transactionStatus; + let fields; + let rows = []; + const commandTags = []; + const results = []; + while (offset < bytes.length) { + if (bytes.length - offset < 5) { + throw new Error(`${label} returned a truncated PostgreSQL protocol frame`); + } + const tag = bytes[offset]; + const length = readI32(bytes, offset + 1); + const end = offset + 1 + length; + if (length < 4 || end > bytes.length) { + throw new Error(`${label} returned an invalid PostgreSQL protocol frame length ${length}`); + } + const body = bytes.subarray(offset + 5, end); + if (tag === 0x45) throw rawProtocolError(body, label); + if (tag === 0x54) { + if (fields !== undefined) throw new Error(`${label} returned nested RowDescription frames`); + fields = parseRawRowDescription(body, label); + rows = []; + } else if (tag === 0x44) { + if (fields === undefined) throw new Error(`${label} returned DataRow before RowDescription`); + rows.push(parseRawDataRow(body, fields.length, label)); + } else if (tag === 0x43) { + commandTags.push(parseRawCommandTag(body, label)); + if (fields !== undefined) { + results.push(canonicalResult(fields, rows)); + fields = undefined; + rows = []; + } + } else if (tag === 0x5a) { + if (length !== 5 || ![0x45, 0x49, 0x54].includes(bytes[offset + 5]) || fields !== undefined) { + throw new Error(`${label} returned an invalid ReadyForQuery frame`); + } + sawReady = true; + transactionStatus = { 69: 'failed', 73: 'idle', 84: 'transaction' }[bytes[offset + 5]]; + if (end !== bytes.length) throw new Error(`${label} returned bytes after ReadyForQuery`); + } else if (tag === 0x53) { + validateRawParameterStatus(body, label); + } else if (tag === 0x4e) { + validateRawFieldResponse(body, 'NoticeResponse', label); + } else { + throw new Error(`${label} returned unexpected PostgreSQL protocol tag 0x${tag.toString(16)}`); + } + offset = end; + } + if (!sawReady) throw new Error(`${label} ended before ReadyForQuery`); + return { commandTags, results, transactionStatus }; +} + +export function postgresSettingsParity(reports, expectedNames, expectedSettings) { + const expectedKeys = [...expectedNames].sort(); + const observations = reports.map((report) => { + const source = report?.postgres?.settings; + const validRecord = source !== null && !Array.isArray(source) && typeof source === 'object'; + const keys = validRecord ? Object.keys(source).sort() : []; + const valid = + validRecord && + stableJson(keys) === stableJson(expectedKeys) && + expectedNames.every((name) => typeof source[name] === 'string'); + const settings = valid + ? Object.fromEntries(expectedNames.map((name) => [name, source[name]])) + : null; + return { + engine: report?.engine?.kind ?? null, + repeat: report?.repeat ?? null, + settings, + contract: settings === null ? null : stableJson(settings), + }; + }); + const contracts = new Set(observations.map(({ contract }) => contract)); + const parityPassed = observations.length > 0 && !contracts.has(null) && contracts.size === 1; + const sharedSettings = parityPassed ? observations[0]?.settings : null; + const expectedPassed = + expectedSettings === undefined || stableJson(sharedSettings) === stableJson(expectedSettings); + const passed = parityPassed && expectedPassed; + return { + passed, + parityPassed, + expectedPassed, + expectedNames: [...expectedNames], + expectedSettings: expectedSettings ?? null, + sharedSettings, + mismatches: passed + ? [] + : observations.map(({ engine, repeat, settings }) => ({ engine, repeat, settings })), + }; +} + +export function pairedRatioSummary(candidateSamples, comparisonSamples) { + if ( + !Array.isArray(candidateSamples) || + !Array.isArray(comparisonSamples) || + candidateSamples.length === 0 || + candidateSamples.length !== comparisonSamples.length + ) { + throw new Error('paired ratio summary requires equally sized non-empty sample arrays'); + } + const pairedRatios = candidateSamples.map((candidate, index) => { + const comparison = comparisonSamples[index]; + if ( + typeof candidate !== 'number' || + !Number.isFinite(candidate) || + candidate <= 0 || + typeof comparison !== 'number' || + !Number.isFinite(comparison) || + comparison <= 0 + ) { + throw new Error('paired ratio samples must be positive finite numbers'); + } + return candidate / comparison; + }); + return { pairedRatios, medianRatio: median(pairedRatios) }; +} + +export function canonicalResult(fields, rows) { + if (!Array.isArray(fields) || !Array.isArray(rows)) { + fail('database result must contain field and row arrays'); + } + return { + fields: fields.map((field, index) => nonEmptyString(field, `result.fields[${index}]`)), + rows: rows.map((row, rowIndex) => { + if (!Array.isArray(row) || row.length !== fields.length) { + fail(`result.rows[${rowIndex}] must contain exactly ${fields.length} values`); + } + return row.map((value) => (value === null ? null : String(value))); + }), + }; +} + +export function expandExpectedResult(result, replacements = {}) { + return { + fields: [...result.fields], + rows: result.rows.map((row) => + row.map((value) => + typeof value === 'string' && Object.hasOwn(replacements, value) + ? String(replacements[value]) + : value, + ), + ), + }; +} + +export function assertExpectedResult(actual, expected, label) { + const left = stableJson(actual); + const right = stableJson(expected); + if (left !== right) { + throw new Error(`${label} returned ${left}, expected ${right}`); + } + return sha256(right); +} + +export function latencySummary(samples, trimFraction) { + if (!Array.isArray(samples) || samples.length === 0) { + throw new Error('latency summary requires samples'); + } + if ( + samples.some((sample) => typeof sample !== 'number' || !Number.isFinite(sample) || sample <= 0) + ) { + throw new Error('latency samples must be positive finite numbers'); + } + const sorted = [...samples].sort((left, right) => left - right); + const trim = Math.floor(sorted.length * trimFraction); + const trimmed = sorted.slice(trim, sorted.length - trim); + return { + samples: sorted.length, + trimmedSamples: trimmed.length, + minMs: sorted[0], + p50Ms: nearestRank(sorted, 0.5), + p90Ms: nearestRank(sorted, 0.9), + p95Ms: nearestRank(sorted, 0.95), + p99Ms: nearestRank(sorted, 0.99), + maxMs: sorted.at(-1), + trimmedMeanMs: trimmed.reduce((sum, value) => sum + value, 0) / trimmed.length, + }; +} + +export function median(values) { + if ( + !Array.isArray(values) || + values.length === 0 || + values.some((value) => typeof value !== 'number' || !Number.isFinite(value)) + ) { + throw new Error('median requires finite numeric values'); + } + const sorted = [...values].sort((left, right) => left - right); + const midpoint = Math.floor(sorted.length / 2); + return sorted.length % 2 === 0 ? (sorted[midpoint - 1] + sorted[midpoint]) / 2 : sorted[midpoint]; +} + +export function geomean(values) { + if ( + !Array.isArray(values) || + values.length === 0 || + values.some((value) => typeof value !== 'number' || !Number.isFinite(value) || value <= 0) + ) { + throw new Error('geomean requires positive finite numeric values'); + } + return Math.exp(values.reduce((sum, value) => sum + Math.log(value), 0) / values.length); +} + +export function comfortableWinGate(ratios, maxGeomeanRatio, correctnessPassed) { + if ( + typeof maxGeomeanRatio !== 'number' || + !Number.isFinite(maxGeomeanRatio) || + maxGeomeanRatio <= 0 + ) { + throw new Error('comfortable-win gate requires a positive finite maximum ratio'); + } + const geomeanRatio = geomean(ratios); + return { + geomeanRatio, + gate: { + passed: correctnessPassed && geomeanRatio <= maxGeomeanRatio, + correctnessPassed, + maxGeomeanRatio, + requiredMinimumWinPercent: (1 - maxGeomeanRatio) * 100, + observedWinPercent: (1 - geomeanRatio) * 100, + }, + }; +} + +export function sha256(value) { + return createHash('sha256').update(value).digest('hex'); +} + +export function stableJson(value) { + if (Array.isArray(value)) { + return `[${value.map(stableJson).join(',')}]`; + } + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort() + .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +export async function findPackageManifest(entry, expectedName) { + let directory = dirname(resolve(entry)); + for (;;) { + const file = resolve(directory, 'package.json'); + try { + const manifest = JSON.parse(await readFile(file, 'utf8')); + if (manifest.name === expectedName) return { file, manifest }; + } catch (error) { + if (error?.code !== 'ENOENT') throw error; + } + const parent = dirname(directory); + if (parent === directory) break; + directory = parent; + } + throw new Error(`could not locate ${expectedName} package.json from ${entry}`); +} + +function validateWarmCases(value) { + nonEmptyArray(value, 'plan.warmRtt'); + const ids = new Set(); + for (const [index, entryValue] of value.entries()) { + const label = `plan.warmRtt[${index}]`; + const entry = object(entryValue, label); + exactKeys(entry, ['expectation', 'id', 'parameters', 'sql'], label); + safeId(entry.id, `${label}.id`); + if (ids.has(entry.id)) fail(`${label}.id must be unique`); + ids.add(entry.id); + nonEmptyString(entry.sql, `${label}.sql`); + if (!Array.isArray(entry.parameters)) fail(`${label}.parameters must be an array`); + for (const [parameterIndex, parameter] of entry.parameters.entries()) { + if (!['boolean', 'number', 'string'].includes(typeof parameter) && parameter !== null) { + fail(`${label}.parameters[${parameterIndex}] must be a JSON scalar`); + } + } + const expectation = object(entry.expectation, `${label}.expectation`); + if (expectation.kind === 'exact') { + exactKeys(expectation, ['kind', 'result'], `${label}.expectation`); + validateExpectedResult(expectation.result, `${label}.expectation.result`); + } else if (expectation.kind === 'one-based-counter') { + exactKeys(expectation, ['field', 'kind'], `${label}.expectation`); + nonEmptyString(expectation.field, `${label}.expectation.field`); + } else { + fail(`${label}.expectation.kind is unsupported`); + } + } +} + +function validateBulk(value) { + nonEmptyArray(value, 'plan.bulk'); + const ids = new Set(); + let sourceRows; + for (const [index, entryValue] of value.entries()) { + const label = `plan.bulk[${index}]`; + const entry = object(entryValue, label); + const expectedKeys = + entry.operation?.kind === 'aggregate-query' + ? ['expectedResult', 'id', 'operation'] + : ['expectedResult', 'id', 'operation', 'validationSql']; + exactKeys(entry, expectedKeys, label); + safeId(entry.id, `${label}.id`); + if (ids.has(entry.id)) fail(`${label}.id must be unique`); + ids.add(entry.id); + const operation = object(entry.operation, `${label}.operation`); + if (!BULK_OPERATIONS.has(operation.kind)) fail(`${label}.operation.kind is unsupported`); + if (operation.kind === 'create-and-insert-series') { + exactKeys(operation, ['kind', 'rows'], `${label}.operation`); + positiveInteger(operation.rows, `${label}.operation.rows`, 1000); + sourceRows = operation.rows; + } else if (operation.kind === 'reverse-indexed-prefix') { + exactKeys(operation, ['kind', 'rows'], `${label}.operation`); + positiveInteger(operation.rows, `${label}.operation.rows`, 1); + if (sourceRows === undefined || operation.rows > sourceRows) { + fail(`${label}.operation.rows must not exceed the preceding inserted row count`); + } + } else { + exactKeys(operation, ['kind'], `${label}.operation`); + } + if (entry.validationSql !== undefined) { + nonEmptyString(entry.validationSql, `${label}.validationSql`); + } + validateExpectedResult(entry.expectedResult, `${label}.expectedResult`); + nonEmptyString(bulkSql(entry), `${label} generated SQL`); + } + if (sourceRows === undefined) fail('plan.bulk must create its deterministic source table'); +} + +function validateQuery(value, label, { allowPlaceholder = false } = {}) { + const query = object(value, label); + exactKeys(query, ['expectedResult', 'sql'], label); + nonEmptyString(query.sql, `${label}.sql`); + validateExpectedResult(query.expectedResult, `${label}.expectedResult`, { allowPlaceholder }); +} + +function validateExpectedResult(value, label, { allowPlaceholder = false } = {}) { + const result = object(value, label); + exactKeys(result, ['fields', 'rows'], label); + nonEmptyArray(result.fields, `${label}.fields`); + for (const [index, field] of result.fields.entries()) { + nonEmptyString(field, `${label}.fields[${index}]`); + } + if (!Array.isArray(result.rows)) fail(`${label}.rows must be an array`); + for (const [rowIndex, row] of result.rows.entries()) { + if (!Array.isArray(row) || row.length !== result.fields.length) { + fail(`${label}.rows[${rowIndex}] must contain exactly ${result.fields.length} values`); + } + for (const [columnIndex, column] of row.entries()) { + if (column !== null && typeof column !== 'string') { + fail(`${label}.rows[${rowIndex}][${columnIndex}] must be a string or null`); + } + if (typeof column === 'string' && column.startsWith('$') && !allowPlaceholder) { + fail(`${label}.rows[${rowIndex}][${columnIndex}] must not contain a placeholder`); + } + } + } +} + +function writeI32(bytes, offset, value) { + bytes[offset] = (value >>> 24) & 0xff; + bytes[offset + 1] = (value >>> 16) & 0xff; + bytes[offset + 2] = (value >>> 8) & 0xff; + bytes[offset + 3] = value & 0xff; +} + +function readI32(bytes, offset) { + return ( + bytes[offset] * 0x1000000 + + bytes[offset + 1] * 0x10000 + + bytes[offset + 2] * 0x100 + + bytes[offset + 3] + ); +} + +function readI16(bytes, offset) { + return bytes[offset] * 0x100 + bytes[offset + 1]; +} + +function readSignedI32(bytes, offset) { + const value = readI32(bytes, offset); + return value > 0x7fffffff ? value - 0x100000000 : value; +} + +function parseRawRowDescription(body, label) { + if (body.length < 2) throw new Error(`${label} returned a truncated RowDescription`); + const count = readI16(body, 0); + const fields = []; + let offset = 2; + for (let index = 0; index < count; index += 1) { + const field = readRawCString(body, offset, `${label} RowDescription field ${index}`); + fields.push(field.value); + offset = field.next; + if (offset + 18 > body.length) { + throw new Error(`${label} returned a truncated RowDescription field`); + } + const format = readI16(body, offset + 16); + if (format !== 0) throw new Error(`${label} returned a non-text RowDescription field`); + offset += 18; + } + if (offset !== body.length) throw new Error(`${label} returned trailing RowDescription bytes`); + return fields; +} + +function parseRawDataRow(body, expectedColumns, label) { + if (body.length < 2) throw new Error(`${label} returned a truncated DataRow`); + const count = readI16(body, 0); + if (count !== expectedColumns) { + throw new Error(`${label} returned ${count} DataRow columns, expected ${expectedColumns}`); + } + const row = []; + let offset = 2; + for (let index = 0; index < count; index += 1) { + if (offset + 4 > body.length) throw new Error(`${label} returned a truncated DataRow length`); + const length = readSignedI32(body, offset); + offset += 4; + if (length === -1) { + row.push(null); + continue; + } + if (length < 0 || offset + length > body.length) { + throw new Error(`${label} returned an invalid DataRow value length ${length}`); + } + row.push(decodeRawText(body.subarray(offset, offset + length), `${label} DataRow value`)); + offset += length; + } + if (offset !== body.length) throw new Error(`${label} returned trailing DataRow bytes`); + return row; +} + +function parseRawCommandTag(body, label) { + const command = readRawCString(body, 0, `${label} CommandComplete`); + if (command.next !== body.length) { + throw new Error(`${label} returned trailing CommandComplete bytes`); + } + return command.value; +} + +function validateRawParameterStatus(body, label) { + const name = readRawCString(body, 0, `${label} ParameterStatus name`); + if (name.value.length === 0) throw new Error(`${label} returned an empty ParameterStatus name`); + const value = readRawCString(body, name.next, `${label} ParameterStatus value`); + if (value.next !== body.length) { + throw new Error(`${label} returned trailing ParameterStatus bytes`); + } +} + +function validateRawFieldResponse(body, kind, label) { + let offset = 0; + for (;;) { + if (offset >= body.length) throw new Error(`${label} returned unterminated ${kind}`); + const code = body[offset]; + offset += 1; + if (code === 0) { + if (offset !== body.length) throw new Error(`${label} returned trailing ${kind} bytes`); + return; + } + const field = readRawCString(body, offset, `${label} ${kind} field 0x${code.toString(16)}`); + offset = field.next; + } +} + +function readRawCString(bytes, offset, label) { + const end = bytes.indexOf(0, offset); + if (end < 0) throw new Error(`${label} is missing its NUL terminator`); + return { value: decodeRawText(bytes.subarray(offset, end), label), next: end + 1 }; +} + +function decodeRawText(bytes, label) { + try { + return new TextDecoder('utf-8', { fatal: true }).decode(bytes); + } catch (error) { + throw new Error(`${label} is not valid UTF-8: ${describeError(error)}`); + } +} + +function rawProtocolError(body, label) { + let offset = 0; + let message = 'PostgreSQL ErrorResponse'; + let sqlstate; + while (offset < body.length) { + const code = body[offset]; + offset += 1; + if (code === 0) break; + const end = body.indexOf(0, offset); + if (end < 0) return new Error(`${label} returned a malformed PostgreSQL ErrorResponse`); + const value = UTF8_DECODER.decode(body.subarray(offset, end)); + if (code === 0x43) sqlstate = value; + if (code === 0x4d) message = value; + offset = end + 1; + } + return new Error( + `${label} returned PostgreSQL error${sqlstate === undefined ? '' : ` ${sqlstate}`}: ${message}`, + ); +} + +function nearestRank(sorted, percentile) { + return sorted[Math.max(0, Math.ceil(sorted.length * percentile) - 1)]; +} + +function object(value, label) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(`${label} must be an object`); + } + return value; +} + +function exactKeys(value, keys, label) { + const actual = Object.keys(value).sort(); + const expected = [...keys].sort(); + if (stableJson(actual) !== stableJson(expected)) { + fail(`${label} fields are ${stableJson(actual)}, expected ${stableJson(expected)}`); + } +} + +function exactStringList(value, expected, label) { + if (!Array.isArray(value) || stableJson(value) !== stableJson(expected)) { + fail(`${label} must be ${stableJson(expected)}`); + } +} + +function nonEmptyArray(value, label) { + if (!Array.isArray(value) || value.length === 0) fail(`${label} must be a non-empty array`); + return value; +} + +function nonEmptyString(value, label) { + if (typeof value !== 'string' || value.length === 0 || value.includes('\0')) { + fail(`${label} must be a non-empty string without NUL bytes`); + } + return value; +} + +function positiveInteger(value, label, minimum) { + if (!Number.isSafeInteger(value) || value < minimum) { + fail(`${label} must be an integer of at least ${minimum}`); + } + return value; +} + +function safeId(value, label) { + if (typeof value !== 'string' || !SAFE_ID.test(value)) + fail(`${label} must be a safe kebab-case id`); +} + +function equal(actual, expected, label) { + if (actual !== expected) + fail(`${label} is ${JSON.stringify(actual)}, expected ${JSON.stringify(expected)}`); +} + +function fail(message) { + throw new Error(`wasix-node benchmark plan: ${message}`); +} + +function relative(file) { + const value = relativePath(repositoryRoot, resolve(file)); + return value === '' || value.startsWith('..') || isAbsolute(value) + ? resolve(file) + : value.split('\\').join('/'); +} + +function describeError(error) { + return error instanceof Error ? error.message : String(error); +} + +const buildOutputsFile = resolve( + repositoryRoot, + 'target/oliphaunt-wasix/wasix-build/build/outputs.json', +); +export async function runtimeBuildProvenance(manifest) { + const bytes = await readFile(buildOutputsFile); + let outputs; + try { + outputs = JSON.parse(bytes.toString('utf8')); + } catch (error) { + throw new Error(`WASIX build outputs are invalid JSON: ${describeError(error)}`); + } + const runtimeRows = Array.isArray(outputs.modules) + ? outputs.modules.filter((row) => row?.kind === 'runtime' && row?.name === 'runtime:oliphaunt') + : []; + const runtime = runtimeRows.length === 1 ? runtimeRows[0] : undefined; + const profileText = outputs['build-profile']; + const profile = parseBuildProfile(profileText); + if ( + outputs['format-version'] !== 1 || + outputs['source-fingerprint'] !== manifest['source-fingerprint'] || + outputs['source-lane'] !== manifest['source-lane'] || + outputs['postgres-version'] !== manifest.runtime?.['postgres-version'] || + runtime?.sha256 !== manifest.runtime?.['module-sha256'] || + manifest['cluster-seeds']?.standard?.['runtime-module-sha256'] !== runtime?.sha256 + ) { + throw new Error('WASIX build outputs do not describe the packaged runtime assets'); + } + return { + schema: 'oliphaunt-wasix-build-provenance-v1', + outputs: { sha256: sha256(bytes), size: bytes.length }, + formatVersion: outputs['format-version'], + postgresVersion: outputs['postgres-version'], + sourceLane: outputs['source-lane'], + sourceFingerprint: outputs['source-fingerprint'], + runtimeModuleSha256: runtime.sha256, + configuration: profile, + buildProfile: { + text: profileText, + sha256: sha256(Buffer.from(profileText)), + size: Buffer.byteLength(profileText), + }, + }; +} + +export function parseBuildProfile(value) { + if (typeof value !== 'string' || value.length === 0) { + throw new Error('WASIX build outputs have no build-profile signature'); + } + const fields = new Map(); + for (const line of value.split('\n')) { + if (line.length === 0) continue; + const separator = line.indexOf('='); + if (separator < 1) throw new Error('WASIX build-profile signature is malformed'); + const key = line.slice(0, separator); + if (fields.has(key)) throw new Error(`WASIX build-profile repeats ${key}`); + fields.set(key, line.slice(separator + 1)); + } + const configuration = {}; + for (const [field, key] of Object.entries({ + profile: 'profile', + cflags: 'cflags', + ldflags: 'ldflags', + configureWasmOpt: 'configure_wasm_opt', + buildWasmOpt: 'build_wasm_opt', + wasmOptFlags: 'wasm_opt_flags', + wasmOptSuppressDefault: 'wasm_opt_suppress_default', + wasmOptPreserveUnoptimized: 'wasm_opt_preserve_unoptimized', + compilerFlags: 'compiler_flags', + linkerFlags: 'linker_flags', + })) { + if (!fields.has(key)) throw new Error(`WASIX build-profile omits ${key}`); + configuration[field] = fields.get(key); + } + return configuration; +} diff --git a/src/benchmarks/perf/wasix-node/plan.test.mts b/src/benchmarks/perf/wasix-node/plan.test.mts new file mode 100644 index 000000000..a151237d9 --- /dev/null +++ b/src/benchmarks/perf/wasix-node/plan.test.mts @@ -0,0 +1,452 @@ +import assert from 'node:assert/strict'; +import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import test from 'node:test'; + +import { installedPackageClosure } from './installed-closure.mts'; +import { dispatchPgliteRequest } from './pglite-node-worker.mts'; +import { + assertExpectedRawProtocolResponse, + assertNativeAddonContract, + assertNativeArtifactProvenance, + assertRuntimeBuildConfiguration, + assertSuccessfulRawProtocolResponse, + bulkSql, + comfortableWinGate, + defaultPlanFile, + expandExpectedResult, + expectedBulkProtocol, + geomean, + latencySummary, + loadPlan, + median, + pairedRatioSummary, + postgresSettingsParity, + simpleQueryMessage, + validatePlan, +} from './plan.mts'; + +test('installed package identities include dependencies with only subpath exports', async () => { + const root = await mkdtemp(join(tmpdir(), 'oliphaunt-closure-')); + try { + const dependency = join(root, 'node_modules', '@oliphaunt', 'core'); + await mkdir(dependency, { recursive: true }); + await writeFile( + join(root, 'package.json'), + JSON.stringify({ + name: 'consumer', + version: '1.0.0', + dependencies: { '@oliphaunt/core': '1.0.0' }, + optionalDependencies: { 'absent-test-package': '1.0.0' }, + }), + ); + await writeFile( + join(dependency, 'package.json'), + JSON.stringify({ + name: '@oliphaunt/core', + version: '1.0.0', + exports: { './query': './query.mts' }, + }), + ); + await writeFile(join(dependency, 'query.mts'), 'export const answer: number = 42;'); + const closure = await installedPackageClosure(join(root, 'package.json'), 'consumer'); + assert.deepEqual( + closure.packages.map(({ name }) => name), + ['@oliphaunt/core', 'consumer'], + ); + const consumer = closure.packages.find(({ name }) => name === 'consumer'); + assert.equal( + consumer.dependencies.find(({ name }) => name === '@oliphaunt/core').installed, + true, + ); + assert.equal( + consumer.dependencies.find(({ name }) => name === 'absent-test-package').installed, + false, + ); + await rm(dependency, { recursive: true }); + await assert.rejects( + installedPackageClosure(join(root, 'package.json'), 'consumer'), + /cannot resolve installed dependency/, + ); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + +test('the gated comparator worker returns public results without private timing telemetry', async () => { + const rawResponse = Uint8Array.of(1, 2, 3); + const calls = []; + const database = { + async query(sql, parameters) { + calls.push(['query', sql, parameters]); + return { fields: [{ name: 'answer' }], rows: [{ answer: 42 }] }; + }, + async exec(sql) { + calls.push(['execute', sql]); + }, + async execProtocolRaw(input, options) { + calls.push(['rawProtocol', [...input], options]); + return rawResponse; + }, + async close() { + calls.push(['close']); + }, + }; + + const query = await dispatchPgliteRequest(database, { + id: 1, + method: 'query', + args: ['SELECT $1', [42]], + }); + assert.deepEqual(query.result, { + result: { fields: [{ name: 'answer' }], rows: [{ answer: 42 }] }, + }); + assert.deepEqual(Object.keys(query.result), ['result']); + + const raw = await dispatchPgliteRequest(database, { + id: 2, + method: 'rawProtocol', + args: [Uint8Array.of(9), false], + }); + assert.deepEqual(raw.result, { response: rawResponse }); + assert.deepEqual(Object.keys(raw.result), ['response']); + assert.deepEqual(raw.transfer, [rawResponse.buffer]); + + const execute = await dispatchPgliteRequest(database, { + id: 3, + method: 'execute', + args: ['SELECT 1'], + }); + assert.deepEqual(execute.result, {}); + assert.equal( + JSON.stringify([query.result, raw.result, execute.result]).includes('Elapsed'), + false, + ); + assert.deepEqual(calls, [ + ['query', 'SELECT $1', [42]], + ['rawProtocol', [9], { syncToFs: false }], + ['execute', 'SELECT 1'], + ]); +}); + +test('the exact installed comparator tree matches the plan byte pin', async () => { + const { plan } = await loadPlan(defaultPlanFile); + const require = createRequire(import.meta.url); + const closure = await installedPackageClosure( + require.resolve(plan.engines.comparison.package), + plan.engines.comparison.package, + ); + const root = closure.packages.find((candidate) => candidate.id === closure.root); + assert.equal(closure.treeHashSchema, plan.engines.comparison.installedTreeHashSchema); + assert.equal(root.installedTreeSha256, plan.engines.comparison.installedTreeSha256); + assert.deepEqual(root.dependencies, []); +}); + +test('candidate native addon contract rejects ABI, profile, and optimization drift', async () => { + const { plan } = await loadPlan(defaultPlanFile); + assert.deepEqual( + assertNativeAddonContract( + plan.engines.candidate.nativeAddon, + plan.engines.candidate.nativeAddon, + ), + plan.engines.candidate.nativeAddon, + ); + const drifts = [ + ['addon ABI', (value) => (value.addonAbiVersion = 2), /addonAbiVersion/u], + ['Node-API floor', (value) => (value.nodeApiVersion = 9), /nodeApiVersion/u], + ['profiles', (value) => value.profiles.reverse(), /profiles/u], + ['Cargo profile', (value) => (value.build.cargoProfile = 'debug'), /cargoProfile/u], + ['incremental', (value) => (value.build.incremental = true), /incremental/u], + ['codegen units', (value) => (value.build.codegenUnits = 16), /codegenUnits/u], + ['LTO', (value) => (value.build.lto = false), /build\.lto/u], + ['features', (value) => value.build.features.push('icu'), /build\.features/u], + ]; + for (const [label, mutate, error] of drifts) { + const drifted = structuredClone(plan.engines.candidate.nativeAddon); + mutate(drifted); + assert.throws( + () => assertNativeAddonContract(drifted, plan.engines.candidate.nativeAddon), + error, + label, + ); + } +}); + +test('candidate native artifact provenance must match the benchmark commit and target', async () => { + const { plan } = await loadPlan(defaultPlanFile); + const artifactSourceSha = 'a'.repeat(40); + const target = 'linux-x64-gnu'; + const targetTriple = 'x86_64-unknown-linux-gnu'; + const carrier = { + name: '@oliphaunt/wasix-napi-linux-x64-gnu', + version: '0.0.0', + target, + artifactProvenanceMember: 'package/artifact-provenance.json', + manifest: { + oliphaunt: { + target, + addonAbiVersion: plan.engines.candidate.nativeAddon.addonAbiVersion, + nodeApiVersion: plan.engines.candidate.nativeAddon.nodeApiVersion, + profiles: plan.engines.candidate.nativeAddon.profiles, + }, + }, + artifactProvenance: { + schema: 'oliphaunt-wasix-napi-provenance-v1', + product: 'oliphaunt-wasix-napi', + target, + artifactSourceSha, + build: { ...plan.engines.candidate.nativeAddon.build, targetTriple }, + buildInputs: { + schema: 'oliphaunt-wasix-napi-build-inputs-v1', + target, + targetTriple, + }, + binary: { + filename: plan.engines.candidate.nativeAddon.binary, + sha256: 'b'.repeat(64), + }, + }, + }; + + assert.equal( + assertNativeArtifactProvenance(carrier, plan.engines.candidate.nativeAddon, artifactSourceSha) + .artifactProvenance, + carrier.artifactProvenance, + ); + assert.throws( + () => + assertNativeArtifactProvenance(carrier, plan.engines.candidate.nativeAddon, 'c'.repeat(40)), + /addon\/source contract/u, + ); + const wrongBuildTarget = structuredClone(carrier); + wrongBuildTarget.artifactProvenance.buildInputs.target = 'linux-arm64-gnu'; + assert.throws( + () => + assertNativeArtifactProvenance( + wrongBuildTarget, + plan.engines.candidate.nativeAddon, + artifactSourceSha, + ), + /addon\/source contract/u, + ); +}); + +test('plan validation rejects malformed identity and a weaker performance claim', async () => { + const { plan } = await loadPlan(defaultPlanFile); + + const versionDrift = structuredClone(plan); + versionDrift.engines.comparison.version = '^0.5.4'; + assert.throws(() => validatePlan(versionDrift), /exact release version/u); + + const integrityDrift = structuredClone(plan); + integrityDrift.engines.comparison.integrity = `sha512-${'A'.repeat(88)}`; + assert.throws(() => validatePlan(integrityDrift), /comparison\.integrity/u); + + const weakerGate = structuredClone(plan); + weakerGate.gate.maxGeomeanRatio = 0.81; + assert.throws(() => validatePlan(weakerGate), /no greater than 0\.80/u); + + const tooFewSamples = structuredClone(plan); + tooFewSamples.measurement.sampleIterations = 19; + assert.throws(() => validatePlan(tooFewSamples), /integer of at least 20/u); + + const tooFewPairs = structuredClone(plan); + tooFewPairs.measurement.pairedRepeats = 8; + assert.throws(() => validatePlan(tooFewPairs), /integer of at least 9/u); + + const comparatorTelemetry = structuredClone(plan); + comparatorTelemetry.engines.comparison.surfaces.worker.gatedResponsePayload = + 'public-result-plus-internal-timing'; + assert.throws(() => validatePlan(comparatorTelemetry), /gatedResponsePayload/u); + + const workerEntrypointDrift = structuredClone(plan); + workerEntrypointDrift.engines.candidate.surfaces.worker.entrypoint = '@oliphaunt/wasix-ts'; + assert.throws(() => validatePlan(workerEntrypointDrift), /surfaces\.worker\.entrypoint/u); + + const directOwnerDrift = structuredClone(plan); + directOwnerDrift.engines.candidate.surfaces.direct.executionOwner = 'sdk-worker'; + assert.throws(() => validatePlan(directOwnerDrift), /surfaces\.direct\.executionOwner/u); + + const invalidGateLabel = structuredClone(plan); + invalidGateLabel.gate.comparisons[1] = 'inline'; + assert.throws(() => validatePlan(invalidGateLabel), /gate\.comparisons/u); + + const unbalancedPairs = structuredClone(plan); + unbalancedPairs.measurement.pairedRepeats = 9; + assert.throws(() => validatePlan(unbalancedPairs), /must be even/u); + + const optimizedOutsideThePlan = structuredClone(plan.engines.candidate.runtimeBuild); + optimizedOutsideThePlan.compilerFlags = '-O3'; + assert.throws( + () => + assertRuntimeBuildConfiguration(optimizedOutsideThePlan, plan.engines.candidate.runtimeBuild), + /compilerFlags/u, + ); + + const hostWithoutLto = structuredClone(plan); + hostWithoutLto.engines.candidate.nativeAddon.build.lto = 'off'; + assert.throws(() => validatePlan(hostWithoutLto), /nativeAddon\.build\.lto/u); +}); + +test('summary math and correctness placeholders are deterministic', () => { + assert.deepEqual(latencySummary([9, 1, 5, 3, 7], 0.2), { + samples: 5, + trimmedSamples: 3, + minMs: 1, + p50Ms: 5, + p90Ms: 9, + p95Ms: 9, + p99Ms: 9, + maxMs: 9, + trimmedMeanMs: 5, + }); + assert.equal(median([7, 1, 5, 3]), 4); + assert.deepEqual(pairedRatioSummary([6, 4, 10], [3, 8, 5]), { + pairedRatios: [2, 0.5, 2], + medianRatio: 2, + }); + assert.ok(Math.abs(geomean([0.5, 0.8]) - Math.sqrt(0.4)) < Number.EPSILON); + assert.equal(comfortableWinGate([0.8], 0.8, true).gate.passed, true); + assert.equal(comfortableWinGate([0.81], 0.8, true).gate.passed, false); + assert.equal(comfortableWinGate([0.5], 0.8, false).gate.passed, false); + assert.deepEqual( + expandExpectedResult( + { fields: ['counter'], rows: [['$totalIterations']] }, + { $totalIterations: 110 }, + ), + { fields: ['counter'], rows: [['110']] }, + ); + assert.deepEqual( + [...simpleQueryMessage('SELECT 1')], + [0x51, 0, 0, 0, 13, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x20, 0x31, 0], + ); + assert.doesNotThrow(() => + assertSuccessfulRawProtocolResponse( + Uint8Array.from([ + 0x43, 0, 0, 0, 11, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0, 0x5a, 0, 0, 0, 5, 0x49, + ]), + 'test response', + ), + ); + const createIndex = expectedBulkProtocol({ operation: { kind: 'create-payload-index' } }); + const readyOnly = protocolFrame(0x5a, Uint8Array.of(0x49)); + assert.throws( + () => assertExpectedRawProtocolResponse(readyOnly, createIndex, 'bulk create-index'), + /expected/u, + ); + const createIndexResponse = concatenate([ + protocolFrame(0x53, new TextEncoder().encode('in_hot_standby\0off\0')), + protocolFrame(0x43, new TextEncoder().encode('CREATE INDEX\0')), + protocolFrame(0x4e, new TextEncoder().encode('SNOTICE\0Mvalidated notice\0\0')), + readyOnly, + ]); + assert.deepEqual( + assertExpectedRawProtocolResponse(createIndexResponse, createIndex, 'bulk create-index'), + createIndex, + ); + assert.throws( + () => + assertExpectedRawProtocolResponse( + concatenate([ + protocolFrame(0x53, new TextEncoder().encode('in_hot_standby\0off')), + protocolFrame(0x43, new TextEncoder().encode('CREATE INDEX\0')), + readyOnly, + ]), + createIndex, + 'malformed parameter status', + ), + /ParameterStatus value is missing its NUL terminator/u, + ); + const aggregate = { + commandTags: ['SELECT 1'], + results: [{ fields: ['answer'], rows: [['42']] }], + transactionStatus: 'idle', + }; + const aggregateResponse = concatenate([ + protocolFrame(0x54, rowDescription(['answer'])), + protocolFrame(0x44, dataRow(['42'])), + protocolFrame(0x43, new TextEncoder().encode('SELECT 1\0')), + readyOnly, + ]); + assert.deepEqual( + assertExpectedRawProtocolResponse(aggregateResponse, aggregate, 'bulk aggregate'), + aggregate, + ); + + const settingNames = ['fsync', 'shared_buffers']; + const reports = [ + reportSettings('candidate', 0, { fsync: 'off', shared_buffers: '128MB' }), + reportSettings('comparison', 0, { fsync: 'off', shared_buffers: '128MB' }), + ]; + assert.equal(postgresSettingsParity(reports, settingNames).passed, true); + assert.equal( + postgresSettingsParity(reports, settingNames, { + fsync: 'off', + shared_buffers: '128MB', + }).passed, + true, + ); + assert.equal( + postgresSettingsParity(reports, settingNames, { + fsync: 'on', + shared_buffers: '128MB', + }).passed, + false, + ); + reports[1].postgres.settings.fsync = 'on'; + assert.equal(postgresSettingsParity(reports, settingNames).passed, false); +}); + +function protocolFrame(tag, body) { + const frame = new Uint8Array(body.length + 5); + frame[0] = tag; + new DataView(frame.buffer).setUint32(1, body.length + 4); + frame.set(body, 5); + return frame; +} + +function concatenate(chunks) { + const output = new Uint8Array(chunks.reduce((size, chunk) => size + chunk.length, 0)); + let offset = 0; + for (const chunk of chunks) { + output.set(chunk, offset); + offset += chunk.length; + } + return output; +} + +function rowDescription(fields) { + const encoder = new TextEncoder(); + const names = fields.map((field) => encoder.encode(`${field}\0`)); + const body = new Uint8Array(2 + names.reduce((size, name) => size + name.length + 18, 0)); + const view = new DataView(body.buffer); + view.setUint16(0, fields.length); + let offset = 2; + for (const name of names) { + body.set(name, offset); + offset += name.length + 18; + } + return body; +} + +function dataRow(values) { + const encoder = new TextEncoder(); + const encoded = values.map((value) => encoder.encode(value)); + const body = new Uint8Array(2 + encoded.reduce((size, value) => size + 4 + value.length, 0)); + const view = new DataView(body.buffer); + view.setUint16(0, values.length); + let offset = 2; + for (const value of encoded) { + view.setInt32(offset, value.length); + offset += 4; + body.set(value, offset); + offset += value.length; + } + return body; +} + +function reportSettings(kind, repeat, settings) { + return { engine: { kind }, repeat, postgres: { settings } }; +} diff --git a/benchmarks/reports/README.md b/src/benchmarks/reports/README.md similarity index 100% rename from benchmarks/reports/README.md rename to src/benchmarks/reports/README.md diff --git a/src/benchmarks/wasix/README.md b/src/benchmarks/wasix/README.md new file mode 100644 index 000000000..baaa55745 --- /dev/null +++ b/src/benchmarks/wasix/README.md @@ -0,0 +1,131 @@ +# WASIX Benchmarks + +WASIX benchmark specs and baselines live here. Runner implementations and +runtime orchestration stay under `src/benchmarks/perf` and the WASIX product source tree. + +## Browser comparison + +`browser-pglite-memory-v2.json` defines two explicit comparisons against exact +PGlite 0.5.4. Oliphaunt's caller-owned root Promise API is measured against +PGlite's caller-realm API; Oliphaunt's explicit `/worker` entrypoint is measured +against PGlite's official Worker API. Both APIs in the direct pair return +promises, but Oliphaunt executes guest work in the calling realm while that +promise is pending. The plan and result record each surface's entry point, +calling contract, and execution owner separately, using the canonical `caller` +and `sdk-worker` ownership values, so Promise shape is not mistaken for +main-thread safety. + +```sh +bun run --cwd src/sdks/ts-wasix/sdk package:build +bash src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh --benchmark +# or: moon run perf-tools:wasix-browser-measure +``` + +Build the portable WASIX runtime first with +`moon run liboliphaunt-wasix:runtime-portable`. Each comparison uses ephemeral +memory, rotates engine order between repetitions, performs an untimed +representative warmup, and retains every raw sample. It covers cold and warm +open, DDL, a 10,000-row set insert, parameterized point reads, indexed 100-row +ranges, aggregates, a decoded 10,000-row scan, a 100-statement transaction, +updates, deletes, and close latency. Exact row-count/checksum assertions and +PostgreSQL durability/WAL checks prevent faster-but-different work. For each +execution comparison independently, the command computes the geometric mean of +the median same-run Oliphaunt/PGlite ratios and requires it to be at most `0.80`. +The direct result therefore cannot subsidize the Worker result, or vice +versa. First cold open remains +descriptive because the implementations use different compilation caches; +close is descriptive because the public APIs make different worker-reclamation +guarantees; insert decomposition remains diagnostic so it cannot overweight the +primary insert workload. Machine-readable JSON is written under `target/perf`. Benchmark runs require a clean worktree and +record the exact Git commit and tree, runtime and staged host build identities, +the built SDK tree, every harness source, and the installed PGlite closure. + +For a harness smoke check without a full sample set, run: + +```sh +bun run --cwd src/sdks/ts-wasix/sdk package:build +bash src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh --benchmark --quick +``` + +Quick mode still requires every workload assertion and durability/WAL parity, +but is explicitly ineligible for performance qualification. + +The explicit `/worker` OPFS path has a separate advisory comparison against +PGlite's OPFS access-handle-pool Worker path: + +```sh +bash src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh --diagnostic-opfs --quick +``` + +It uses durable PostgreSQL settings on both Worker engines and prints the raw +configuration and medians. It is deliberately not evaluated with the +memory-only plan or its gate; the caller-owned direct comparison remains in +memory while the Worker comparison uses OPFS. + +## Node comparison + +`node-pglite-memory-v2.json` is the deterministic Node comparison plan for the +public `@oliphaunt/wasix-ts` package and the exact PGlite control named in the +plan. The executable harness lives in `src/benchmarks/perf/wasix-node`. It compares the +real `@oliphaunt/wasix-ts/worker` entrypoint with a harness-owned PGlite Worker, +and the blocking `@oliphaunt/wasix-ts/direct` entrypoint with PGlite's +caller-realm API. Both use memory storage. The harness +alternates which engine runs first across ten fresh-process pairs per +comparison and gates them independently, so a strong isolated result cannot +hide a weak direct result or vice versa. Both Worker candidates own real Worker +threads, while Oliphaunt's Worker loads its synchronous Node-API `/direct` +placement. The direct comparison has matched execution +ownership and Promise-shaped public APIs; the plan and report separately record +that Oliphaunt performs guest work in the caller realm while its promise is +pending. + +Startup is one cold-to-first-result metric; public-open and +immediate-first-query components remain visible without receiving separate +gate weight. PGlite's published benchmark times `pg.exec()` inside a browser +worker. Its official worker library requires browser Worker and Web Locks APIs, +so this Node harness owns a deliberately small `worker_threads` RPC adapter and +times both public APIs end-to-end from the Node host, including exactly one +isolation RPC for each engine. PGlite's official benchmark methodology is +retained as provenance only: calls return public results without collecting or +serializing comparator-only internal timing. The caller-owned comparison times +both packages around their public Promise APIs and does not imply that either +implementation yields the caller realm while database work runs. + +Bulk timing sends identical PostgreSQL Simple Query bytes through both public +`execProtocolRaw` APIs and, in the Worker comparison, transfers both raw responses +across the worker edge. +The untimed verifier decodes the timed response's command tags and result rows, +then validates the resulting database state. Gate eligibility also requires +all recorded PostgreSQL settings to match across every candidate/control run. +Generated SQL is bounded by the compact row counts in the plan; upstream +generated benchmark files are not vendored. + +Validate the plan without runtime assets with +`moon run perf-tools:wasix-plan`. The uncached measurement deliberately does +not build its large native prerequisite. Stage the portable/AOT runtime, ICU, +and extension inputs, then build and smoke the optimized carrier for the +current host before running it: + +```sh +bash src/sdks/ts-wasix/node-addon/tools/build-native.sh +moon run perf-tools:wasix-node-measure +# Or, after building the TypeScript SDK: +bash src/benchmarks/perf/wasix-node/benchmark.sh --run +``` + +Each run writes machine-readable JSON under `target/perf`; it passes only when canonical +timed-response/result hashes and PostgreSQL settings agree and the geometric +mean of median paired Oliphaunt/PGlite ratios is at most `0.80`. Reports pin the +comparator tarball integrity and installed tree hash, and record the complete +resolved installed closure of each engine. The candidate package fixture also +requires its native carrier binary to match its recorded artifact provenance and +its embedded runtime module to match the canonical asset manifest and build +outputs. Reports record the carrier target, binary digest, artifact source, +payload build inputs, native Cargo profile, and full guest build-profile +signature. Execution verifies those inputs against the checked-in plan, which +specifies a non-incremental one-codegen-unit native `release` build with thin +LTO and the guest `release` profile with `-O2 -g0 -flto=thin`. + +The local runners require GNU coreutils (`timeout`, or `gtimeout` on macOS) +and `jq`. Shell owns package installation, process deadlines and cleanup; +benchmark source/build provenance is required only for measurements. diff --git a/benchmarks/wasix/browser-pglite-memory-v1.json b/src/benchmarks/wasix/browser-pglite-memory-v1.json similarity index 100% rename from benchmarks/wasix/browser-pglite-memory-v1.json rename to src/benchmarks/wasix/browser-pglite-memory-v1.json diff --git a/benchmarks/wasix/browser-pglite-memory-v2.json b/src/benchmarks/wasix/browser-pglite-memory-v2.json similarity index 100% rename from benchmarks/wasix/browser-pglite-memory-v2.json rename to src/benchmarks/wasix/browser-pglite-memory-v2.json diff --git a/benchmarks/wasix/node-pglite-memory-v1.json b/src/benchmarks/wasix/node-pglite-memory-v1.json similarity index 76% rename from benchmarks/wasix/node-pglite-memory-v1.json rename to src/benchmarks/wasix/node-pglite-memory-v1.json index 928c3a25d..dbf51be3c 100644 --- a/benchmarks/wasix/node-pglite-memory-v1.json +++ b/src/benchmarks/wasix/node-pglite-memory-v1.json @@ -15,11 +15,7 @@ "cargoProfile": "release", "rustOptLevel": 3, "lto": true, - "wasmOpt": [ - "--enable-threads", - "--enable-bulk-memory", - "-O3" - ] + "wasmOpt": ["--enable-threads", "--enable-bulk-memory", "-O3"] } }, "runtimeBuild": { @@ -73,24 +69,14 @@ "pairing": "same-repeat-candidate-over-comparison", "percentileMethod": "nearest-rank", "startupMetric": "cold-to-first-result", - "startupMetricIncludes": [ - "public-open", - "immediate-first-query" - ] + "startupMetricIncludes": ["public-open", "immediate-first-query"] }, "gate": { "maxGeomeanRatio": 0.8, "requiresCorrectness": true, - "placements": [ - "worker", - "direct" - ], + "placements": ["worker", "direct"], "metric": "geometric-mean-of-median-paired-candidate-over-comparison-ratios-lower-is-better", - "includes": [ - "cold-to-first-result", - "warm-rtt-p50", - "bulk-elapsed" - ] + "includes": ["cold-to-first-result", "warm-rtt-p50", "bulk-elapsed"] }, "bulkTransport": { "publicApi": "execProtocolRaw", @@ -123,14 +109,8 @@ "firstQuery": { "sql": "SELECT 42::int4 AS answer", "expectedResult": { - "fields": [ - "answer" - ], - "rows": [ - [ - "42" - ] - ] + "fields": ["answer"], + "rows": [["42"]] } }, "warmSetupSql": "CREATE TABLE bench_rtt (id integer PRIMARY KEY, payload text NOT NULL); INSERT INTO bench_rtt SELECT i, 'row-' || lpad(i::text, 6, '0') FROM generate_series(1, 1024) AS i; CREATE TABLE bench_counter (value integer NOT NULL); INSERT INTO bench_counter VALUES (0);", @@ -138,40 +118,24 @@ { "id": "parameter-scalar", "sql": "SELECT $1::int4 + 1 AS answer", - "parameters": [ - 41 - ], + "parameters": [41], "expectation": { "kind": "exact", "result": { - "fields": [ - "answer" - ], - "rows": [ - [ - "42" - ] - ] + "fields": ["answer"], + "rows": [["42"]] } } }, { "id": "indexed-lookup", "sql": "SELECT payload FROM bench_rtt WHERE id = $1::int4", - "parameters": [ - 513 - ], + "parameters": [513], "expectation": { "kind": "exact", "result": { - "fields": [ - "payload" - ], - "rows": [ - [ - "row-000513" - ] - ] + "fields": ["payload"], + "rows": [["row-000513"]] } } }, @@ -188,20 +152,8 @@ "warmValidation": { "sql": "SELECT count(*)::bigint AS fixture_rows, min(id)::bigint AS min_id, max(id)::bigint AS max_id, (SELECT value::bigint FROM bench_counter) AS counter FROM bench_rtt", "expectedResult": { - "fields": [ - "fixture_rows", - "min_id", - "max_id", - "counter" - ], - "rows": [ - [ - "1024", - "1", - "1024", - "$totalIterations" - ] - ] + "fields": ["fixture_rows", "min_id", "max_id", "counter"], + "rows": [["1024", "1", "1024", "$totalIterations"]] } }, "bulk": [ @@ -213,22 +165,8 @@ }, "validationSql": "SELECT count(*)::bigint AS rows, min(id)::bigint AS min_id, max(id)::bigint AS max_id, sum(id)::bigint AS sum_id, sum(octet_length(payload))::bigint AS total_bytes FROM bench_bulk", "expectedResult": { - "fields": [ - "rows", - "min_id", - "max_id", - "sum_id", - "total_bytes" - ], - "rows": [ - [ - "25000", - "1", - "25000", - "312512500", - "800000" - ] - ] + "fields": ["rows", "min_id", "max_id", "sum_id", "total_bytes"], + "rows": [["25000", "1", "25000", "312512500", "800000"]] } }, { @@ -238,20 +176,8 @@ }, "validationSql": "SELECT count(*)::bigint AS rows, sum(octet_length(payload))::bigint AS total_bytes, to_regclass('bench_bulk_payload_idx')::text AS index_name, (SELECT indisvalid::text FROM pg_index WHERE indexrelid = to_regclass('bench_bulk_payload_idx')) AS index_valid FROM bench_bulk", "expectedResult": { - "fields": [ - "rows", - "total_bytes", - "index_name", - "index_valid" - ], - "rows": [ - [ - "25000", - "800000", - "bench_bulk_payload_idx", - "true" - ] - ] + "fields": ["rows", "total_bytes", "index_name", "index_valid"], + "rows": [["25000", "800000", "bench_bulk_payload_idx", "true"]] } }, { @@ -262,18 +188,8 @@ }, "validationSql": "SELECT count(*)::bigint AS rows, count(*) FILTER (WHERE id <= 12500 AND payload = reverse(md5(id::text)))::bigint AS reversed, sum(octet_length(payload))::bigint AS total_bytes FROM bench_bulk", "expectedResult": { - "fields": [ - "rows", - "reversed", - "total_bytes" - ], - "rows": [ - [ - "25000", - "12500", - "800000" - ] - ] + "fields": ["rows", "reversed", "total_bytes"], + "rows": [["25000", "12500", "800000"]] } }, { @@ -282,18 +198,8 @@ "kind": "aggregate-query" }, "expectedResult": { - "fields": [ - "rows", - "sum_id", - "total_bytes" - ], - "rows": [ - [ - "25000", - "312512500", - "800000" - ] - ] + "fields": ["rows", "sum_id", "total_bytes"], + "rows": [["25000", "312512500", "800000"]] } } ] diff --git a/benchmarks/wasix/node-pglite-memory-v2.json b/src/benchmarks/wasix/node-pglite-memory-v2.json similarity index 78% rename from benchmarks/wasix/node-pglite-memory-v2.json rename to src/benchmarks/wasix/node-pglite-memory-v2.json index 633b49f08..c6e7a9945 100644 --- a/benchmarks/wasix/node-pglite-memory-v2.json +++ b/src/benchmarks/wasix/node-pglite-memory-v2.json @@ -12,19 +12,14 @@ "binary": "oliphaunt_wasix_napi.node", "addonAbiVersion": 1, "nodeApiVersion": 8, - "profiles": [ - "standard", - "icu" - ], + "profiles": ["standard", "icu"], "build": { "cargoProfile": "release", "incremental": false, "codegenUnits": 1, "lto": "thin", "strip": "symbols", - "features": [ - "release" - ] + "features": ["release"] } }, "runtimeBuild": { @@ -73,7 +68,7 @@ "surfaces": { "worker": { "engine": "comparison-worker", - "entrypoint": "tools/perf/wasix-node/pglite-node-worker.mjs", + "entrypoint": "src/benchmarks/perf/wasix-node/pglite-node-worker.mts", "callingContract": "async", "executionOwner": "harness-worker", "executionBoundary": "node-worker-thread", @@ -105,24 +100,14 @@ "pairing": "same-repeat-candidate-over-comparison", "percentileMethod": "nearest-rank", "startupMetric": "cold-to-first-result", - "startupMetricIncludes": [ - "public-open", - "immediate-first-query" - ] + "startupMetricIncludes": ["public-open", "immediate-first-query"] }, "gate": { "maxGeomeanRatio": 0.8, "requiresCorrectness": true, - "comparisons": [ - "worker", - "direct" - ], + "comparisons": ["worker", "direct"], "metric": "geometric-mean-of-median-paired-candidate-over-comparison-ratios-lower-is-better", - "includes": [ - "cold-to-first-result", - "warm-rtt-p50", - "bulk-elapsed" - ] + "includes": ["cold-to-first-result", "warm-rtt-p50", "bulk-elapsed"] }, "bulkTransport": { "publicApi": "execProtocolRaw", @@ -155,14 +140,8 @@ "firstQuery": { "sql": "SELECT 42::int4 AS answer", "expectedResult": { - "fields": [ - "answer" - ], - "rows": [ - [ - "42" - ] - ] + "fields": ["answer"], + "rows": [["42"]] } }, "warmSetupSql": "CREATE TABLE bench_rtt (id integer PRIMARY KEY, payload text NOT NULL); INSERT INTO bench_rtt SELECT i, 'row-' || lpad(i::text, 6, '0') FROM generate_series(1, 1024) AS i; CREATE TABLE bench_counter (value integer NOT NULL); INSERT INTO bench_counter VALUES (0);", @@ -170,40 +149,24 @@ { "id": "parameter-scalar", "sql": "SELECT $1::int4 + 1 AS answer", - "parameters": [ - 41 - ], + "parameters": [41], "expectation": { "kind": "exact", "result": { - "fields": [ - "answer" - ], - "rows": [ - [ - "42" - ] - ] + "fields": ["answer"], + "rows": [["42"]] } } }, { "id": "indexed-lookup", "sql": "SELECT payload FROM bench_rtt WHERE id = $1::int4", - "parameters": [ - 513 - ], + "parameters": [513], "expectation": { "kind": "exact", "result": { - "fields": [ - "payload" - ], - "rows": [ - [ - "row-000513" - ] - ] + "fields": ["payload"], + "rows": [["row-000513"]] } } }, @@ -220,20 +183,8 @@ "warmValidation": { "sql": "SELECT count(*)::bigint AS fixture_rows, min(id)::bigint AS min_id, max(id)::bigint AS max_id, (SELECT value::bigint FROM bench_counter) AS counter FROM bench_rtt", "expectedResult": { - "fields": [ - "fixture_rows", - "min_id", - "max_id", - "counter" - ], - "rows": [ - [ - "1024", - "1", - "1024", - "$totalIterations" - ] - ] + "fields": ["fixture_rows", "min_id", "max_id", "counter"], + "rows": [["1024", "1", "1024", "$totalIterations"]] } }, "bulk": [ @@ -245,22 +196,8 @@ }, "validationSql": "SELECT count(*)::bigint AS rows, min(id)::bigint AS min_id, max(id)::bigint AS max_id, sum(id)::bigint AS sum_id, sum(octet_length(payload))::bigint AS total_bytes FROM bench_bulk", "expectedResult": { - "fields": [ - "rows", - "min_id", - "max_id", - "sum_id", - "total_bytes" - ], - "rows": [ - [ - "25000", - "1", - "25000", - "312512500", - "800000" - ] - ] + "fields": ["rows", "min_id", "max_id", "sum_id", "total_bytes"], + "rows": [["25000", "1", "25000", "312512500", "800000"]] } }, { @@ -270,20 +207,8 @@ }, "validationSql": "SELECT count(*)::bigint AS rows, sum(octet_length(payload))::bigint AS total_bytes, to_regclass('bench_bulk_payload_idx')::text AS index_name, (SELECT indisvalid::text FROM pg_index WHERE indexrelid = to_regclass('bench_bulk_payload_idx')) AS index_valid FROM bench_bulk", "expectedResult": { - "fields": [ - "rows", - "total_bytes", - "index_name", - "index_valid" - ], - "rows": [ - [ - "25000", - "800000", - "bench_bulk_payload_idx", - "true" - ] - ] + "fields": ["rows", "total_bytes", "index_name", "index_valid"], + "rows": [["25000", "800000", "bench_bulk_payload_idx", "true"]] } }, { @@ -294,18 +219,8 @@ }, "validationSql": "SELECT count(*)::bigint AS rows, count(*) FILTER (WHERE id <= 12500 AND payload = reverse(md5(id::text)))::bigint AS reversed, sum(octet_length(payload))::bigint AS total_bytes FROM bench_bulk", "expectedResult": { - "fields": [ - "rows", - "reversed", - "total_bytes" - ], - "rows": [ - [ - "25000", - "12500", - "800000" - ] - ] + "fields": ["rows", "reversed", "total_bytes"], + "rows": [["25000", "12500", "800000"]] } }, { @@ -314,18 +229,8 @@ "kind": "aggregate-query" }, "expectedResult": { - "fields": [ - "rows", - "sum_id", - "total_bytes" - ], - "rows": [ - [ - "25000", - "312512500", - "800000" - ] - ] + "fields": ["rows", "sum_id", "total_bytes"], + "rows": [["25000", "312512500", "800000"]] } } ] diff --git a/src/bindings/wasix-rust/THIRD_PARTY_NOTICES.md b/src/bindings/wasix-rust/THIRD_PARTY_NOTICES.md deleted file mode 100644 index ac4987a39..000000000 --- a/src/bindings/wasix-rust/THIRD_PARTY_NOTICES.md +++ /dev/null @@ -1,24 +0,0 @@ -# oliphaunt-wasix Third-Party Notices - -`oliphaunt-wasix` ships WASIX PostgreSQL runtime assets, selected SQL extensions, -and target-specific Wasmer AOT artifacts. - -The PostgreSQL runtime is derived from PostgreSQL 18 source pinned under -`src/postgres/versions/18/` and built with the WASM/WASIX patch stack owned by -`src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/`. Selected -runtime and extension carriers also embed ICU 76.1 and OpenSSL 3.5.6. - -Every carrier that embeds these components includes their exact pinned license -bytes under `THIRD_PARTY_LICENSES/`: - -- `PostgreSQL-COPYRIGHT` — PostgreSQL 18.4, source SHA-256 - `81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094`. -- `ICU-LICENSE` — ICU commit `8eca245c7484ac6cc179e3e5f7c1ea7680810f39`. -- `OpenSSL-LICENSE.txt` — OpenSSL commit - `286ddeaac037533bbdce65b3c689e3f7ffebf0f6`. - -Third-party source pins for optional external extensions are maintained in -`src/sources/third-party/`, and WASIX toolchain inputs are maintained in -`src/sources/toolchains/`. Exact SQL extension selection is modeled in -`src/extensions/`; generated WASM assets must include only the -extension artifacts explicitly selected for the release payload. diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml b/src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml deleted file mode 100644 index dce698dd1..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml +++ /dev/null @@ -1,169 +0,0 @@ -[package] -name = "oliphaunt-wasix" -version = "0.2.0" -edition = "2024" -rust-version = "1.93" -description = "Embedded PostgreSQL 18 for Rust with synchronous and asynchronous APIs." -readme = "README.md" -repository = "https://github.com/f0rr0/oliphaunt" -homepage = "https://oliphaunt.dev" -documentation = "https://docs.rs/oliphaunt-wasix" -keywords = ["postgres", "oliphaunt", "wasm", "database", "embedded"] -categories = ["database-implementations", "wasm", "development-tools::testing"] -license = "MIT" -links = "oliphaunt_artifact_wasix_relay" -build = "build.rs" -exclude = [ - "Cargo.toml.orig", - "release.toml", -] - -[package.metadata.oliphaunt] -runtime-version = "0.2.0" - -[features] -default = [] -__internal-napi = [] -extensions = [] -tools = [ - "dep:oliphaunt-wasix-tools", - "dep:oliphaunt-wasix-tools-aot-aarch64-apple-darwin", - "dep:oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu", - "dep:oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc", - "dep:oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", -] -extension-amcheck = ["extensions", "liboliphaunt-wasix-portable/extension-amcheck"] -extension-auto-explain = ["extensions", "liboliphaunt-wasix-portable/extension-auto-explain"] -extension-bloom = ["extensions", "liboliphaunt-wasix-portable/extension-bloom"] -extension-btree-gin = ["extensions", "liboliphaunt-wasix-portable/extension-btree-gin"] -extension-btree-gist = ["extensions", "liboliphaunt-wasix-portable/extension-btree-gist"] -extension-citext = ["extensions", "liboliphaunt-wasix-portable/extension-citext"] -extension-cube = ["extensions", "liboliphaunt-wasix-portable/extension-cube"] -extension-dict-int = ["extensions", "liboliphaunt-wasix-portable/extension-dict-int"] -extension-dict-xsyn = ["extensions", "liboliphaunt-wasix-portable/extension-dict-xsyn"] -extension-earthdistance = [ - "extensions", - "extension-cube", - "liboliphaunt-wasix-portable/extension-earthdistance", -] -extension-file-fdw = ["extensions", "liboliphaunt-wasix-portable/extension-file-fdw"] -extension-fuzzystrmatch = ["extensions", "liboliphaunt-wasix-portable/extension-fuzzystrmatch"] -extension-hstore = ["extensions", "liboliphaunt-wasix-portable/extension-hstore"] -extension-intarray = ["extensions", "liboliphaunt-wasix-portable/extension-intarray"] -extension-isn = ["extensions", "liboliphaunt-wasix-portable/extension-isn"] -extension-lo = ["extensions", "liboliphaunt-wasix-portable/extension-lo"] -extension-ltree = ["extensions", "liboliphaunt-wasix-portable/extension-ltree"] -extension-pageinspect = ["extensions", "liboliphaunt-wasix-portable/extension-pageinspect"] -extension-pg-buffercache = ["extensions", "liboliphaunt-wasix-portable/extension-pg-buffercache"] -extension-pg-freespacemap = ["extensions", "liboliphaunt-wasix-portable/extension-pg-freespacemap"] -extension-pg-hashids = ["extensions", "liboliphaunt-wasix-portable/extension-pg-hashids"] -extension-pg-ivm = ["extensions", "liboliphaunt-wasix-portable/extension-pg-ivm"] -extension-pg-surgery = ["extensions", "liboliphaunt-wasix-portable/extension-pg-surgery"] -extension-pg-textsearch = ["extensions", "liboliphaunt-wasix-portable/extension-pg-textsearch"] -extension-pg-trgm = ["extensions", "liboliphaunt-wasix-portable/extension-pg-trgm"] -extension-pg-uuidv7 = ["extensions", "liboliphaunt-wasix-portable/extension-pg-uuidv7"] -extension-pg-visibility = ["extensions", "liboliphaunt-wasix-portable/extension-pg-visibility"] -extension-pg-walinspect = ["extensions", "liboliphaunt-wasix-portable/extension-pg-walinspect"] -extension-pgcrypto = ["extensions", "liboliphaunt-wasix-portable/extension-pgcrypto"] -extension-pgtap = ["extensions", "liboliphaunt-wasix-portable/extension-pgtap"] -extension-postgis = ["extensions", "liboliphaunt-wasix-portable/extension-postgis"] -extension-seg = ["extensions", "liboliphaunt-wasix-portable/extension-seg"] -extension-tablefunc = ["extensions", "liboliphaunt-wasix-portable/extension-tablefunc"] -extension-tcn = ["extensions", "liboliphaunt-wasix-portable/extension-tcn"] -extension-tsm-system-rows = ["extensions", "liboliphaunt-wasix-portable/extension-tsm-system-rows"] -extension-tsm-system-time = ["extensions", "liboliphaunt-wasix-portable/extension-tsm-system-time"] -extension-unaccent = ["extensions", "liboliphaunt-wasix-portable/extension-unaccent"] -extension-uuid-ossp = ["extensions", "liboliphaunt-wasix-portable/extension-uuid-ossp"] -extension-vector = ["extensions", "liboliphaunt-wasix-portable/extension-vector"] -icu = ["dep:oliphaunt-icu"] - -[package.metadata.oliphaunt-wasix.assets] -postgres-version = "18.4" -postgres-source-url = "https://ftp.postgresql.org/pub/source/v18.4/postgresql-18.4.tar.bz2" -postgres-source-sha256 = "81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094" -postgres-patch-count = "41" -oliphaunt-npm-version-checked = "0.4.5" -runtime-archive-sha256 = "5f0bf0c84af3313e479a62358edb3872452e42ab8ae827781c025b34c820277b" -oliphaunt-wasix-sha256 = "fced1f11b12bd3d8849b76bd6ad52623ab3540b0bf52cffd60b7c5c893687d2a" -cluster-seed-standard-archive-sha256 = "5036966275469d39b665d99ccd59d208fe6e77bcb250909369f46afd907b7577" -cluster-seed-icu-archive-sha256 = "5036966275469d39b665d99ccd59d208fe6e77bcb250909369f46afd907b7577" -initdb-wasix-sha256 = "c2438dd844943811da9de5dd5c2786c7b2cb1b03df41d8b71108dce1d632758b" - -[dependencies] -anyhow = "1" -async-trait = "0.1" -cap-fs-ext = "4" -cap-std = "4" -tar = "0.4" -zstd = { version = "0.13", default-features = false } -directories = "6" -tracing = "0.1" -flate2 = "1" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -tempfile = "3" -sha2 = "0.10" -dunce = "1" -filetime = "0.2" -liboliphaunt-wasix-portable = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/assets" } -oliphaunt-wasix-tools = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/tools", optional = true } -oliphaunt-icu = { version = "*", path = "../../../../runtimes/liboliphaunt/icu", optional = true } -tokio = { version = "1", features = ["io-util", "rt-multi-thread", "sync"] } -wasmer = { version = "=7.2.1", default-features = false, features = [ - "sys", - "headless", - "compiler", - "wasmer-artifact-load", -] } -# Wasmer-WASIX 0.x crates use compatible ranges for packages in their own -# release family. Keep the complete family constrained here so a fresh -# consumer cannot silently mix a later patch generation with the runtime and -# AOT artifacts built against this exact toolchain. -wasmer-config = { version = "=0.702.1", default-features = false } -wasmer-journal = { version = "=0.702.1", default-features = false } -wasmer-package = { version = "=0.702.1", default-features = false } -wasmer-types = "=7.2.1" -wasmer-wasix = { version = "=0.702.1", default-features = false, features = [ - "sys-minimal", - "sys-poll", - "host-vnet", - "time", -] } -wasmer-wasix-types = { version = "=0.702.1", default-features = false } -virtual-fs = { version = "=0.702.1", default-features = false } -virtual-mio = { version = "=0.702.1", default-features = false } -virtual-net = { version = "=0.702.1", default-features = false } -webc = "=12.0.0" - -[target.'cfg(all(target_os = "macos", target_arch = "aarch64"))'.dependencies] -liboliphaunt-wasix-aot-aarch64-apple-darwin = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin" } -oliphaunt-wasix-tools-aot-aarch64-apple-darwin = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin", optional = true } - -[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dependencies] -liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu" } -oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu", optional = true } - -[target.'cfg(all(target_os = "linux", target_arch = "aarch64", target_env = "gnu"))'.dependencies] -liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu" } -oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu", optional = true } - -[target.'cfg(all(target_os = "windows", target_arch = "x86_64", target_env = "msvc"))'.dependencies] -liboliphaunt-wasix-aot-x86_64-pc-windows-msvc = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc" } -oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc = { version = "*", path = "../../../../runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc", optional = true } - -[dev-dependencies] -sqlx = { version = "0.8", default-features = false, features = [ - "postgres", - "runtime-tokio", -] } -tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] } -tokio-postgres = "0.7" - -[[bin]] -name = "oliphaunt-wasix-dump" -path = "src/bin/oliphaunt_wasix_dump.rs" -required-features = ["tools"] - -[[bin]] -name = "oliphaunt-wasix-proxy" -path = "src/bin/oliphaunt_wasix_proxy.rs" diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/README.md b/src/bindings/wasix-rust/crates/oliphaunt-wasix/README.md deleted file mode 100644 index fa5dc3128..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/README.md +++ /dev/null @@ -1,306 +0,0 @@ -# `oliphaunt-wasix` - -Embedded PostgreSQL 18 for Rust through the canonical `liboliphaunt-wasix` -runtime. The root API is synchronous and runs PostgreSQL directly on the -calling thread. Its retained Wasmer store is thread-affine, so root `Oliphaunt` -is `!Send + !Sync` and must be created, used, closed, and dropped on one OS -thread. Applications that need a movable/shared handle or need to keep an async -executor responsive use the cloneable `Send + Sync` root `AsyncOliphaunt` -handle, which owns a dedicated database thread. - -You can also start a one-client local PostgreSQL endpoint. Narrow in-tree SQLx -and `tokio-postgres` smokes cover ordinary connections and queries; this is not -a blanket compatibility claim for PostgreSQL clients or ORMs. - -```sh -cargo add oliphaunt-wasix -``` - -## Direct API - -```rust,no_run -use oliphaunt_wasix::{DatabaseStorage, Error, Oliphaunt}; - -fn main() -> anyhow::Result<()> { - let mut database = Oliphaunt::builder() - .storage(DatabaseStorage::Directory("./data/main".into())) - .startup_guc("work_mem", "8MB") - .open()?; - - database.execute("CREATE TABLE items(id integer PRIMARY KEY, value text NOT NULL)")?; - database - .sql("INSERT INTO items VALUES ($1, $2)") - .bind(1_i32) - .bind("hello") - .execute()?; - let result = database.query_with_params( - "SELECT value FROM items WHERE id = $1", - [1_i32], - )?; - assert_eq!(result.get_text(0, "value")?, Some("hello")); - - database.transaction(|transaction| { - transaction.execute("UPDATE items SET value = 'committed' WHERE id = 1")?; - Ok::<(), Error>(()) - })?; - database.close()?; - Ok(()) -} -``` - -The root `Oliphaunt` is the no-hop database. Opening, queries, transactions, -backup, restore, and close run synchronously on the calling thread. The handle -is deliberately thread-affine and exclusive: it is `!Send + !Sync`, database -methods take `&mut self`, and a transaction borrows that handle. Create, use, -close, and drop it on one OS thread. This makes execution placement and ordering -explicit without an internal queue or message boundary. - -Starting close permanently retires the handle. `is_closed()` becomes true, -later work is rejected, and repeated close calls replay the first terminal -result. A transaction callback panic is caught long enough to attempt rollback; -the original panic is then resumed. If rollback or commit cannot be confirmed, -the database is poisoned until close. - -`execute` and `query` are the parameter-free forms; -`execute_with_params` and `query_with_params` use PostgreSQL positional -parameters. Query rows retain ordered raw bytes and expose OID-aware typed -access through `FromSql`. Natural Rust values use `IntoParameter` and carry -their PostgreSQL type OID and preferred encoding. `Parameter` provides -explicit OID, format, and nullable bytes; its `text`, `binary`, and `null` -constructors leave the OID for PostgreSQL to infer. An explicit OID 0 is -accepted by `describe` because it is PostgreSQL's wire-level inference -sentinel; an absent OID is the single execution spelling for inference. `exec` -returns ordered simple-query -results, `describe` resolves -wire metadata without executing, and the database and transaction publish -`is_closed()`. `query` also accepts command-only statements, returning empty -fields and rows while retaining the command tag and affected-row count. A -transaction mirrors the structured methods and supports explicit `rollback()` -without a later commit. - -Managed transaction handles intentionally omit raw-protocol methods. Do not -send transaction lifecycle SQL (`BEGIN`, `COMMIT`, `END`, `ROLLBACK`, or -`AND CHAIN`) through their structured methods; use callback completion or -`rollback()` instead. Savepoints, including `ROLLBACK TO SAVEPOINT`, remain -ordinary transaction work. Use the root database's raw-protocol adapter only -when the application deliberately owns the full PostgreSQL session state. - -Transaction callbacks return ordinary `Result` with `E: From`, so -database work uses `?` while typed business aborts stay application-owned. The -outer `TransactionResult` distinguishes callback failure, an actually -attempted rollback failure, and an independent database/protocol failure for -which no rollback was sent. - -`exec_protocol_raw` is the buffered escape hatch for callers that need -PostgreSQL frontend-protocol bytes. `exec_protocol_raw_stream` delivers -bounded callback chunks and streams COPY output through the guest protocol -pump instead of accumulating the complete response. Ordinary fallible methods -return the crate-owned `Result`; transactions and streams use the generic -`TransactionResult` and `RawStreamResult` wrappers. The opaque -`Error` implements `std::error::Error`, exposes a stable non-exhaustive -`ErrorKind` through `kind()`, and offers `postgres_error()`; PostgreSQL failures return the exported -`PostgresError` details, notices, and SQLSTATE. Failed rollback or an uncertain -COMMIT poisons the database and never sends a misleading second control command. -Streaming callbacks execute synchronously before the direct method returns and -provide backpressure to PostgreSQL. The retained WASIX stdio attachment requires -the callback to own `Send + 'static` captures; use `Arc>` for mutable -state. Return `()` for infallible delivery or `Result<(), E>` for a typed stop. -A callback error or panic is surfaced only after a successful guest protocol -pump confirms recovery. Direct callback panics then resume; async owner-thread -panics become `RawStreamError::CallbackPanicked` without poisoning. If the pump -fails, `RawStreamError::Database` is authoritative, the database becomes -close-only, and a retained callback panic is not resumed into an unknown session -state. WASIX query cancellation is intentionally absent -until the guest runtime can interrupt execution and prove protocol recovery. - -The builder also supports `username`, `database`, `startup_gucs`, and bundled -`extension`/`extensions` when the corresponding crate features are enabled. -Selecting an extension makes its artifact and required pre-start configuration -available; it never runs `CREATE EXTENSION`, `LOAD`, or migration SQL. Install -database-local objects explicitly through your normal migrations. Each -associated selector is compiled only by its matching `extension-*` feature; -`Extension::ALL` and `Extension::by_sql_name` therefore describe exactly the -artifacts enabled in the current Cargo build, not the full packaging catalog. - -## Storage and physical backup - -`DatabaseStorage::Memory` is the default and keeps mutable PGDATA in Wasmer's -memory filesystem. `DatabaseStorage::Directory(path)` persists a managed root; -the caller-supplied Rust path must be nonempty and contain no NUL bytes: - -```text -data/main/ -├── .oliphaunt.json -└── pgdata/ -``` - -A new empty root is initialized from the matching packaged cluster seed. An -existing root must contain an exact descriptor and complete PostgreSQL 18 PGDATA; -incomplete or unexpected contents fail without being adopted, deleted, or -reinitialized. - -Rust uses one stable sibling advisory lock for both open and restore. It -coordinates Rust WASIX and native-host WASIX TypeScript owners of that path, -including before a new root exists, because the Node-API path delegates -directory ownership to this Rust runtime. Sequential cross-binding root handoff -is not yet a supported or qualified workflow. - -Physical backup is a PostgreSQL online backup in a plain tar archive: - -```rust,no_run -use oliphaunt_wasix::{DatabaseStorage, Oliphaunt}; - -fn main() -> anyhow::Result<()> { - let mut source = Oliphaunt::open()?; - let backup = source.backup()?; - source.close()?; - - Oliphaunt::restore("./data/restored", backup)?; - let mut restored = Oliphaunt::builder() - .storage(DatabaseStorage::Directory("./data/restored".into())) - .open()?; - restored.close()?; - Ok(()) -} -``` - -`restore` accepts an absent or empty directory, validates and stages the whole -archive, then publishes the managed root. The archive contains `pgdata/**` and -`.oliphaunt/backup-manifest.properties`; it does not contain the destination's -`.oliphaunt.json` descriptor. Physical archives are for the same PostgreSQL -major and WASIX physical format. Restore is synchronous; once publication -starts, it runs to completion or returns an error. Use logical dump/restore for -upgrades. - -## Standard PostgreSQL clients and tools - -The endpoint uses loopback TCP on every supported host; Unix hosts may instead -select a Unix-domain socket. It uses PostgreSQL trust authentication, refuses -TLS and GSS negotiation, and owns one connected client at a time. Its current -`CancelRequest` path does not authenticate or interrupt the guest backend, so -client cancellation is unsupported. Treat the example below as the covered -SQLx connection shape, not proof of pool, COPY, cancellation, or -arbitrary-driver conformance. - -```rust,no_run -use oliphaunt_wasix::OliphauntServer; -use sqlx::{Connection, Row}; - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let mut server = OliphauntServer::builder().start()?; - let mut connection = sqlx::PgConnection::connect(&server.connection_string()).await?; - let row = sqlx::query("SELECT 42::int AS answer") - .fetch_one(&mut connection) - .await?; - assert_eq!(row.try_get::("answer")?, 42); - connection.close().await?; - server.close()?; - Ok(()) -} -``` - -With the `tools` feature, an open database gains fluent methods for the matching -packaged WASIX PostgreSQL programs. The optional `tools` namespace contains -their options and structured error type: - -```rust,no_run -# #[cfg(feature = "tools")] -use oliphaunt_wasix::{Oliphaunt, tools}; - -# #[cfg(feature = "tools")] -fn main() -> anyhow::Result<()> { - let mut source = Oliphaunt::open()?; - let sql = source.pg_dump(tools::PgDumpOptions::new().arg("--schema-only"))?; - source.close()?; - let mut target = Oliphaunt::open()?; - target.psql(tools::PsqlOptions::new().script(sql))?; - target.close()?; - Ok(()) -} - -# #[cfg(not(feature = "tools"))] -# fn main() {} -``` - -`pg_dump` returns standard plain PostgreSQL SQL unchanged. `psql` is -non-interactive and accepts a command, a script, or ordinary passthrough -arguments. Connection, file input/output, format, compression, encoding, and -parallel-job flags are managed and rejected from passthrough arguments. Direct -tools are exclusive operations on the database and reset session state before -and after the tool run. - -## Asynchronous API - -Use `AsyncOliphaunt` when PostgreSQL must not block the calling async executor: - -```rust,no_run -use oliphaunt_wasix::AsyncOliphaunt; - -#[tokio::main] -async fn main() -> oliphaunt_wasix::Result<()> { - let database = AsyncOliphaunt::open().await?; - let rows = database.query("SELECT 42::int4 AS answer").await?; - assert_eq!(rows.get_text(0, "answer")?, Some("42")); - database.close().await -} -``` - -`AsyncOliphaunt` is `Clone + Send + Sync`. Every clone targets one -PostgreSQL session whose Wasmer store is constructed and retained on an -SDK-owned thread. Database work therefore does not block the calling executor -thread. All admitted operations, transaction boundaries, and close are placed -into one FIFO. Ordinary work awaits fair, bounded admission; saturation applies -async backpressure instead of returning a queue-full error. Lifecycle controls -do not consume ordinary capacity but never overtake earlier admitted work. -Individual futures are `Send` only when their captured inputs, callbacks, and -outputs also satisfy the applicable `Send` bounds. -Starting close establishes an atomic cutoff: work already in the owner FIFO -drains, while capacity waiters and later work are rejected. A retryable close -does not resurrect waiters that missed its cutoff. - -Dropping an ordinary operation before it starts removes its database effect. -After asynchronous execution begins, it runs to a PostgreSQL readiness boundary -even if its future is abandoned. Dropping an active transaction future queues -best-effort rollback in the same order. While a callback transaction is active, -unpinned work is rejected. Concurrent `close().await` callers join one close -attempt and receive the same result. - -An async transaction-body panic unwinds the awaiting task immediately. Its -active transaction is dropped and queues best-effort rollback in the owner -FIFO. The unwind does not wait for rollback to finish, but later database work -cannot overtake that cleanup. This differs from the direct callback transaction, -which settles synchronously before resuming the panic. - -The `Async*` root types mirror the direct database, SQL builder, transaction, -backup/restore, raw-protocol, server, and optional tools surfaces with async -methods. Streaming callbacks run synchronously on the database owner and must -not reenter the same database; reentrancy is rejected instead of deadlocking. -Their captures must also be owned `Send + 'static`; use `Arc>` for -shared mutable state. -`database.pg_dump(options).await` and `database.psql(options).await` queue the -packaged tools on that same owner. - -The direct local server has a synchronous lifecycle API, but its listener -thread owns the wire-protocol backend. The handle is `Send + !Sync`; move its -exclusive ownership between threads rather than sharing references. Its -`close(&mut self)` preserves the handle so `is_closed()` can report terminal -retirement and repeated close calls can replay the first result. The async -server handle is cloneable `Send + Sync`. -Server `is_closed()` reports SDK lifecycle state only. It does not poll the -proxy listener or guarantee that the published PostgreSQL endpoint is -reachable; use the connected driver or pool for connection health. - -TCP endpoints are loopback-only because the embedded proxy uses PostgreSQL -trust authentication. The default listener uses an automatically assigned -loopback port on every supported host. `ServerListen::tcp_port` selects a fixed -TCP port. On Unix hosts only, `ServerListen::unix` or -`ServerListen::unix_port` selects a PostgreSQL-style Unix socket directory. -The resolved directory must be valid UTF-8 so the returned connection string -preserves its exact path across Rust drivers and ORMs. -The server deliberately owns one connected client at a time; use the separate -postmaster product for concurrent sessions. - -The crate packages no mutable runtime downloads. Cargo resolves the matching -runtime, AOT, tool, and selected extension artifacts built from the same -`liboliphaunt-wasix` source identity. diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/build.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/build.rs deleted file mode 100644 index 0afda2681..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/build.rs +++ /dev/null @@ -1,249 +0,0 @@ -use std::collections::BTreeMap; -use std::env; -use std::fs; -use std::path::{Path, PathBuf}; - -const ARTIFACT_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_"; -const ARTIFACT_ENV_SUFFIX: &str = "_MANIFEST"; -const RELAY_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_"; -const QUERY_CORE_ENV: &str = "OLIPHAUNT_QUERY_CORE_RS"; -const QUERY_CORE_OUTPUT: &str = "query_core.rs"; -const PACKAGED_QUERY_CORE: &str = "src/oliphaunt/query_core.rs"; -const CHECKOUT_QUERY_CORE: &str = "../../../../../src/shared/rust-query-core/query_core.rs"; - -fn main() { - match build_instructions(env::vars()) { - Ok(instructions) => { - for instruction in instructions { - println!("{instruction}"); - } - } - Err(error) => { - println!("cargo::error={error}"); - panic!("oliphaunt-wasix artifact relay failed: {error}"); - } - } -} - -fn build_instructions(vars: I) -> Result, String> -where - I: IntoIterator, -{ - let vars = vars.into_iter().collect::>(); - let manifest_dir = required_path(&vars, "CARGO_MANIFEST_DIR")?; - let out_dir = required_path(&vars, "OUT_DIR")?; - let mut instructions = relay_manifest_instructions(vars)?; - instructions.extend(stage_query_core(&manifest_dir, &out_dir)?); - Ok(instructions) -} - -fn required_path(vars: &BTreeMap, name: &str) -> Result { - vars.get(name) - .filter(|value| !value.is_empty()) - .map(PathBuf::from) - .ok_or_else(|| format!("Cargo did not provide {name}")) -} - -fn stage_query_core(manifest_dir: &Path, out_dir: &Path) -> Result, String> { - let packaged = manifest_dir.join(PACKAGED_QUERY_CORE); - let checkout = manifest_dir.join(CHECKOUT_QUERY_CORE); - let packaged_exists = packaged.is_file(); - let checkout_exists = checkout.is_file(); - let source = match (packaged_exists, checkout_exists) { - (true, true) => { - let packaged_bytes = fs::read(&packaged).map_err(|error| { - format!( - "read packaged Rust query core {}: {error}", - packaged.display() - ) - })?; - let checkout_bytes = fs::read(&checkout).map_err(|error| { - format!( - "read canonical Rust query core {}: {error}", - checkout.display() - ) - })?; - if packaged_bytes != checkout_bytes { - return Err(format!( - "packaged Rust query core {} is stale relative to {}", - packaged.display(), - checkout.display() - )); - } - packaged.as_path() - } - (true, false) => packaged.as_path(), - (false, true) => checkout.as_path(), - (false, false) => { - return Err(format!( - "missing canonical Rust query core; checked {} and {}", - packaged.display(), - checkout.display() - )); - } - }; - let source = fs::canonicalize(source) - .map_err(|error| format!("resolve Rust query core {}: {error}", source.display()))?; - let output = out_dir.join(QUERY_CORE_OUTPUT); - fs::copy(&source, &output).map_err(|error| { - format!( - "stage Rust query core {} at {}: {error}", - source.display(), - output.display() - ) - })?; - let mut instructions = [(&packaged, packaged_exists), (&checkout, checkout_exists)] - .into_iter() - .filter(|(_, exists)| *exists) - .map(|(candidate, _)| { - fs::canonicalize(candidate) - .map(|candidate| format!("cargo::rerun-if-changed={}", candidate.display())) - .map_err(|error| { - format!( - "resolve watched Rust query core {}: {error}", - candidate.display() - ) - }) - }) - .collect::, _>>()?; - instructions.push(format!( - "cargo::rustc-env={QUERY_CORE_ENV}={}", - output.display() - )); - Ok(instructions) -} - -fn relay_manifest_instructions(vars: I) -> Result, String> -where - I: IntoIterator, -{ - let mut manifests = BTreeMap::new(); - let mut instructions = Vec::new(); - for (key, value) in vars { - let Some(metadata_key) = relay_metadata_key(&key) else { - continue; - }; - if value.is_empty() { - continue; - } - if let Some(existing) = manifests.insert(metadata_key.clone(), value.clone()) - && existing != value - { - return Err(format!( - "conflicting Cargo artifact manifests for metadata key {metadata_key}: {existing} and {value}" - )); - } - instructions.push(format!("cargo::rerun-if-changed={value}")); - } - for (metadata_key, manifest) in manifests { - instructions.push(format!("cargo::metadata={metadata_key}={manifest}")); - } - Ok(instructions) -} - -fn relay_metadata_key(env_key: &str) -> Option { - if env_key.starts_with(RELAY_ENV_PREFIX) { - return None; - } - let stem = env_key - .strip_prefix(ARTIFACT_ENV_PREFIX)? - .strip_suffix(ARTIFACT_ENV_SUFFIX)?; - if stem.is_empty() { - return None; - } - Some(format!("{}_manifest", stem.to_ascii_lowercase())) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn query_core_fixture() -> (PathBuf, PathBuf, PathBuf) { - let root = std::env::temp_dir().join(format!( - "oliphaunt-wasix-query-core-{}-{}", - std::process::id(), - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_nanos() - )); - let manifest = root.join("src/bindings/wasix-rust/crates/oliphaunt-wasix"); - let canonical = root.join("src/shared/rust-query-core/query_core.rs"); - let out = root.join("out"); - fs::create_dir_all(canonical.parent().unwrap()).unwrap(); - fs::create_dir_all(manifest.join("src/oliphaunt")).unwrap(); - fs::create_dir_all(&out).unwrap(); - fs::write(&canonical, b"canonical query core\n").unwrap(); - (root, manifest, out) - } - - #[test] - fn re_emits_runtime_and_aot_manifests() { - let instructions = relay_manifest_instructions([ - ( - "DEP_OLIPHAUNT_ARTIFACT_LIBOLIPHAUNT_WASIX_RUNTIME_MANIFEST".to_owned(), - "/tmp/runtime.toml".to_owned(), - ), - ( - "DEP_OLIPHAUNT_ARTIFACT_LIBOLIPHAUNT_WASIX_AOT_LINUX_X64_GNU_MANIFEST".to_owned(), - "/tmp/aot.toml".to_owned(), - ), - ]) - .unwrap(); - assert!(instructions.contains( - &"cargo::metadata=liboliphaunt_wasix_runtime_manifest=/tmp/runtime.toml".to_owned() - )); - assert!( - instructions.contains( - &"cargo::metadata=liboliphaunt_wasix_aot_linux_x64_gnu_manifest=/tmp/aot.toml" - .to_owned() - ) - ); - } - - #[test] - fn ignores_own_downstream_metadata() { - let instructions = relay_manifest_instructions([( - "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_LIBOLIPHAUNT_WASIX_RUNTIME_MANIFEST".to_owned(), - "/tmp/runtime.toml".to_owned(), - )]) - .unwrap(); - assert!(instructions.is_empty()); - } - - #[test] - fn stages_checkout_query_core_and_rejects_a_stale_packaged_copy() { - let (root, manifest, out) = query_core_fixture(); - let instructions = stage_query_core(&manifest, &out).unwrap(); - assert_eq!( - fs::read(out.join(QUERY_CORE_OUTPUT)).unwrap(), - b"canonical query core\n" - ); - assert!( - instructions - .iter() - .any(|line| line.starts_with("cargo::rerun-if-changed=")) - ); - assert!( - instructions - .iter() - .any(|line| line.starts_with(&format!("cargo::rustc-env={QUERY_CORE_ENV}="))) - ); - - let packaged = manifest.join(PACKAGED_QUERY_CORE); - let checkout = manifest.join(CHECKOUT_QUERY_CORE); - fs::write(&packaged, b"canonical query core\n").unwrap(); - let instructions = stage_query_core(&manifest, &out).unwrap(); - for candidate in [&packaged, &checkout] { - let candidate = fs::canonicalize(candidate).unwrap(); - assert!( - instructions.contains(&format!("cargo::rerun-if-changed={}", candidate.display())) - ); - } - - fs::write(packaged, b"stale query core\n").unwrap(); - let error = stage_query_core(&manifest, &out).unwrap_err(); - assert!(error.contains("is stale relative to")); - fs::remove_dir_all(root).unwrap(); - } -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/release.toml b/src/bindings/wasix-rust/crates/oliphaunt-wasix/release.toml deleted file mode 100644 index 1d00ea8ce..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/release.toml +++ /dev/null @@ -1,11 +0,0 @@ -id = "oliphaunt-wasix-rust" -owner = "@oliphaunt/wasix-rust" -kind = "sdk" -publish_targets = ["crates-io"] -registry_packages = ["crates:oliphaunt-wasix"] -release_artifacts = ["cargo-crate"] - -[compatibility_versions.runtime] -source_product = "liboliphaunt-wasix" -path = "src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml" -parser = "toml:package.metadata.oliphaunt.runtime-version" diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/bin/oliphaunt_wasix_proxy.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/bin/oliphaunt_wasix_proxy.rs deleted file mode 100644 index a1c5bce87..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/bin/oliphaunt_wasix_proxy.rs +++ /dev/null @@ -1,153 +0,0 @@ -use anyhow::{Result, bail}; -#[cfg(feature = "extensions")] -use oliphaunt_wasix::Extension; -use oliphaunt_wasix::{DatabaseStorage, OliphauntServer, ServerListen}; -use std::env; -use std::path::PathBuf; - -#[derive(Debug)] -enum Bind { - Tcp(u16), - #[cfg(unix)] - Unix { - directory: PathBuf, - port: u16, - }, -} - -#[derive(Debug)] -struct Args { - storage: DatabaseStorage, - bind: Bind, - print_uri: bool, - postgres_config: Vec<(String, String)>, - extensions: Vec, -} - -fn main() -> Result<()> { - let args = parse_args()?; - let mut builder = OliphauntServer::builder().storage(args.storage); - - builder = match args.bind { - Bind::Tcp(0) => builder.listen(ServerListen::tcp()), - Bind::Tcp(port) => builder.listen(ServerListen::tcp_port(port)), - #[cfg(unix)] - Bind::Unix { directory, port } => builder.listen(ServerListen::unix_port(directory, port)), - }; - builder = builder.startup_gucs(args.postgres_config); - - #[cfg(feature = "extensions")] - { - for name in &args.extensions { - let extension = Extension::by_sql_name(name) - .ok_or_else(|| anyhow::anyhow!("unknown extension: {name}"))?; - builder = builder.extension(extension); - } - } - #[cfg(not(feature = "extensions"))] - if !args.extensions.is_empty() { - bail!("this oliphaunt-wasix-proxy build was compiled without extension support"); - } - - let server = builder.start()?; - if args.print_uri { - println!("{}", server.connection_string()); - } else { - eprintln!("listening: {}", server.connection_string()); - } - - loop { - std::thread::park(); - } -} - -fn parse_args() -> Result { - let mut storage = DatabaseStorage::Memory; - let mut print_uri = false; - let mut postgres_config = Vec::new(); - let mut extensions = Vec::new(); - let mut bind = Bind::Tcp(0); - - let mut args = env::args().skip(1); - while let Some(arg) = args.next() { - match arg.as_str() { - "--memory" => storage = DatabaseStorage::Memory, - "--directory" => { - let value = args - .next() - .ok_or_else(|| anyhow::anyhow!("--directory requires a path"))?; - storage = DatabaseStorage::Directory(PathBuf::from(value)); - } - "--tcp" => { - let value = args - .next() - .ok_or_else(|| anyhow::anyhow!("--tcp requires a port"))?; - bind = Bind::Tcp(parse_port("--tcp", &value)?); - } - #[cfg(unix)] - "--unix" | "--uds" => { - let directory = args - .next() - .ok_or_else(|| anyhow::anyhow!("--unix requires a directory"))?; - bind = Bind::Unix { - directory: PathBuf::from(directory), - port: 5432, - }; - } - "--print-uri" => print_uri = true, - "--startup-guc" => { - let value = args - .next() - .ok_or_else(|| anyhow::anyhow!("--startup-guc requires name=value"))?; - let (name, value) = value - .split_once('=') - .ok_or_else(|| anyhow::anyhow!("--startup-guc requires name=value"))?; - postgres_config.push((name.to_owned(), value.to_owned())); - } - "--extension" => { - let value = args - .next() - .ok_or_else(|| anyhow::anyhow!("--extension requires a name"))?; - extensions.push(value); - } - "--help" | "-h" => { - print_usage(); - std::process::exit(0); - } - other => bail!("unknown argument: {other}"), - } - } - - Ok(Args { - storage, - bind, - print_uri, - postgres_config, - extensions, - }) -} - -fn parse_port(flag: &str, value: &str) -> Result { - let port = value - .parse::() - .map_err(|_| anyhow::anyhow!("{flag} requires a port in the range 1..=65535"))?; - if port == 0 { - bail!("{flag} requires a port in the range 1..=65535"); - } - Ok(port) -} - -fn print_usage() { - eprintln!( - "Usage: oliphaunt-wasix-proxy [--memory | --directory PATH] [--tcp PORT | --unix DIRECTORY] [--print-uri] [--startup-guc NAME=VALUE] [--extension NAME]" - ); - eprintln!(" --memory Store PGDATA in memory. This is the default"); - eprintln!(" --directory PATH Store PGDATA in a retained host directory"); - eprintln!(" --tcp PORT Listen on IPv4 loopback using PORT"); - #[cfg(unix)] - eprintln!(" --unix DIRECTORY Listen on DIRECTORY/.s.PGSQL.5432"); - eprintln!(" --print-uri Print the PostgreSQL connection URI to stdout"); - eprintln!(" --startup-guc NAME=VALUE"); - eprintln!(" Set a PostgreSQL startup GUC on the embedded backend"); - eprintln!(" --extension NAME Select an extension artifact by SQL name"); -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/error.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/error.rs deleted file mode 100644 index 4f9329bed..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/error.rs +++ /dev/null @@ -1,770 +0,0 @@ -use std::{convert::Infallible, error, fmt, sync::Arc}; - -/// Stable, programmatically useful classification for an Oliphaunt failure. -/// -/// The concrete [`Error`] remains opaque so implementation and platform -/// details can evolve without breaking callers. Match this non-exhaustive enum -/// with a wildcard arm. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub enum ErrorKind { - /// A builder option, storage descriptor, or extension selection is invalid. - InvalidConfiguration, - /// The database or server is closing, closed, or its owner has stopped. - Lifecycle, - /// An operation conflicts with an active managed transaction. - TransactionActive, - /// PostgreSQL returned a structured backend `ErrorResponse`. - Postgres, - /// Managed storage ownership, validation, publication, or durability failed. - Storage, - /// A transport, runtime, protocol, callback, or other failure. - Other, -} - -/// Stable classification for a managed-storage failure. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub enum StorageErrorCode { - /// Another database or server owns the selected managed root. - Busy, - /// Stored bytes or metadata are malformed or unsafe. - Corrupt, - /// A managed root contains only part of a valid database. - Incomplete, - /// Stored data belongs to an incompatible runtime or physical format. - Incompatible, - /// Publication crossed or may have crossed its atomic commit point but durability failed. - PublicationFailed, - /// The storage provider or host filesystem operation was unavailable. - Unavailable, -} - -/// What is known about the stored generation after a storage failure. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub enum StorageCommitState { - /// The attempted generation was not published. - NotPersisted, - /// The attempted generation was published and made durable. - Persisted, - /// The pre-operation generation is known to be unchanged. - Unchanged, - /// Publication or durability may have happened before the failure. - Unknown, -} - -/// Stable operation phase at which managed storage failed. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub enum StorageErrorPhase { - /// Acquiring exclusive ownership of a managed directory root. - Ownership, - /// Inspecting or opening an existing managed root. - Open, - /// Publishing a newly initialized managed root. - OpenPublication, - /// Persisting one database protocol operation. - Operation, - /// Reading or materializing a physical backup. - Backup, - /// Shutting down and durably closing a database or server. - Close, - /// Validating a physical restore archive and destination. - RestoreValidation, - /// Materializing a validated restore in private staging. - RestoreStaging, - /// Atomically publishing a staged restore. - RestorePublication, - /// Making an already-published restore durable. - RestoreDurability, -} - -/// Programmatically useful details carried by a managed-storage failure. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct StorageErrorDetails { - code: StorageErrorCode, - commit_state: StorageCommitState, - phase: StorageErrorPhase, -} - -impl StorageErrorDetails { - /// Stable storage classification suitable for branching. - pub const fn code(self) -> StorageErrorCode { - self.code - } - - /// What is known about the stored generation after the failure. - pub const fn commit_state(self) -> StorageCommitState { - self.commit_state - } - - /// Storage operation phase which failed. - pub const fn phase(self) -> StorageErrorPhase { - self.phase - } -} - -/// Error returned by the Oliphaunt Rust WASIX API. -#[derive(Clone)] -pub struct Error { - kind: ErrorKind, - inner: Arc, -} - -#[derive(Debug)] -struct ClassifiedCause { - kind: ErrorKind, - message: String, -} - -#[derive(Debug)] -struct StorageCause { - details: StorageErrorDetails, - source: anyhow::Error, -} - -#[derive(Debug, Clone)] -struct TransactionRollbackCause { - callback: Box, - rollback: Box, -} - -#[derive(Debug, Clone)] -struct TransactionCallbackAndDatabaseCause { - callback: Box, - database: Box, -} - -/// Result returned by the Oliphaunt Rust WASIX API. -pub type Result = std::result::Result; - -/// Result returned by a callback-scoped transaction. -/// -/// `E` is the callback's application error type. The default keeps callbacks -/// which use only SDK errors concise. -pub type TransactionResult = std::result::Result>; - -/// Result returned by raw protocol streaming. -/// -/// `E` is the callback's parser or application error type. The default is -/// [`Infallible`] for callbacks which cannot fail deliberately. -pub type RawStreamResult = std::result::Result>; - -mod raw_stream_callback_output { - pub trait Sealed {} - - impl Sealed for () {} - impl Sealed for std::result::Result<(), E> {} -} - -/// Supported return values from a raw protocol stream callback. -/// -/// Return `()` for an infallible callback or `Result<(), E>` to stop delivery -/// with a typed parser or application error. This trait is sealed so the two -/// stable callback forms remain exhaustive. -pub trait RawStreamCallbackOutput: raw_stream_callback_output::Sealed { - /// Typed callback failure, or [`Infallible`] for a callback returning `()`. - type Error; - - /// Convert the callback output into its typed result. - #[doc(hidden)] - fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error>; -} - -impl RawStreamCallbackOutput for () { - type Error = Infallible; - - fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error> { - Ok(()) - } -} - -impl RawStreamCallbackOutput for std::result::Result<(), E> { - type Error = E; - - fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error> { - self - } -} - -/// Error from a callback-scoped transaction. -/// -/// Callback code follows the Diesel/sqlx convention `E: From`, allowing -/// SQL operations to use `?` while deliberate business aborts remain the -/// caller's concrete `E`. If both the callback and rollback fail, both typed -/// causes remain available. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum TransactionError { - /// `BEGIN`, `COMMIT`, explicit settlement, or another SDK operation failed. - Database(Error), - /// The callback deliberately aborted with an application error. - Callback(E), - /// The callback returned an error and an attempted rollback failed, possibly - /// together with releasing the transaction's owner pin. - CallbackAndRollback { - /// Error returned by the callback. - callback: E, - /// Error returned while rolling back or releasing the transaction pin. - rollback: Error, - }, - /// The callback returned an error after an independent database, transport, - /// or protocol-recovery failure had already expired the transaction. No - /// rollback was attempted. - CallbackAndDatabase { - /// Error returned by the callback. - callback: E, - /// Independent SDK, database, transport, or recovery failure. - database: Error, - }, -} - -impl TransactionError { - /// Wrap a deliberate application-level transaction abort. - pub fn callback(error: E) -> Self { - Self::Callback(error) - } - - /// Return the application error, including when rollback also failed. - pub fn callback_error(&self) -> Option<&E> { - match self { - Self::Callback(error) => Some(error), - Self::CallbackAndRollback { callback, .. } => Some(callback), - Self::CallbackAndDatabase { callback, .. } => Some(callback), - Self::Database(_) => None, - } - } - - /// Return the SDK failure which occurred before callback settlement. - pub fn database_error(&self) -> Option<&Error> { - match self { - Self::Database(error) - | Self::CallbackAndDatabase { - database: error, .. - } => Some(error), - Self::Callback(_) | Self::CallbackAndRollback { .. } => None, - } - } - - /// Return the attempted rollback or transaction-pin release failure. - pub fn rollback_error(&self) -> Option<&Error> { - match self { - Self::CallbackAndRollback { rollback, .. } => Some(rollback), - Self::Database(_) | Self::Callback(_) | Self::CallbackAndDatabase { .. } => None, - } - } -} - -impl From for TransactionError { - fn from(error: Error) -> Self { - Self::Database(error) - } -} - -impl From> for Error { - fn from(error: TransactionError) -> Self { - match error { - TransactionError::Database(error) => error, - TransactionError::Callback(error) => error, - TransactionError::CallbackAndRollback { callback, rollback } => { - Self::transaction_rollback(callback, rollback) - } - TransactionError::CallbackAndDatabase { callback, database } => { - Self::transaction_callback_and_database(callback, database) - } - } - } -} - -impl fmt::Display for TransactionError -where - E: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Database(error) => error.fmt(f), - Self::Callback(error) => error.fmt(f), - Self::CallbackAndRollback { callback, rollback } => write!( - f, - "transaction callback failed: {callback}; rollback also failed: {rollback}" - ), - Self::CallbackAndDatabase { callback, database } => write!( - f, - "transaction callback failed: {callback}; an independent database failure also occurred: {database}" - ), - } - } -} - -impl error::Error for TransactionError -where - E: error::Error + 'static, -{ - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match self { - Self::Database(error) => Some(error), - Self::Callback(error) => Some(error), - Self::CallbackAndRollback { callback, .. } - | Self::CallbackAndDatabase { callback, .. } => Some(callback), - } - } -} - -/// Error from raw PostgreSQL protocol streaming. -/// -/// A callback error is returned only after the runtime confirms recovery to -/// `ReadyForQuery`. An independent runtime or transport failure is represented -/// by [`Self::Database`] and remains authoritative. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum RawStreamError { - /// The SDK, runtime, transport, or recovery operation failed. - Database(Error), - /// The runtime recovered successfully after the callback returned this - /// parser or application error. - Callback(E), - /// An owner-thread callback panicked after the runtime confirmed - /// `ReadyForQuery`. Blocking APIs resume the original unwind instead. - CallbackPanicked(Error), -} - -impl RawStreamError { - /// Return the recovered callback error. - pub fn callback_error(&self) -> Option<&E> { - match self { - Self::Callback(error) => Some(error), - Self::Database(_) | Self::CallbackPanicked(_) => None, - } - } - - /// Return the authoritative SDK or recovery failure. - pub fn database_error(&self) -> Option<&Error> { - match self { - Self::Database(error) => Some(error), - Self::Callback(_) | Self::CallbackPanicked(_) => None, - } - } - - /// Return a recovered owner-thread callback panic. This is distinct from - /// an independent database/recovery failure and does not imply poisoning. - pub fn callback_panic_error(&self) -> Option<&Error> { - match self { - Self::CallbackPanicked(error) => Some(error), - Self::Database(_) | Self::Callback(_) => None, - } - } -} - -impl From for RawStreamError { - fn from(error: Error) -> Self { - Self::Database(error) - } -} - -impl From> for Error { - fn from(error: RawStreamError) -> Self { - match error { - RawStreamError::Database(error) => error, - RawStreamError::Callback(never) => match never {}, - RawStreamError::CallbackPanicked(error) => error, - } - } -} - -impl From> for Error { - fn from(error: RawStreamError) -> Self { - match error { - RawStreamError::Database(error) - | RawStreamError::Callback(error) - | RawStreamError::CallbackPanicked(error) => error, - } - } -} - -impl fmt::Display for RawStreamError -where - E: fmt::Display, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Database(error) => error.fmt(f), - Self::Callback(error) => error.fmt(f), - Self::CallbackPanicked(error) => error.fmt(f), - } - } -} - -impl error::Error for RawStreamError -where - E: error::Error + 'static, -{ - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match self { - Self::Database(error) => Some(error), - Self::Callback(error) => Some(error), - Self::CallbackPanicked(error) => Some(error), - } - } -} - -impl Error { - /// Return the stable category of this failure. - pub const fn kind(&self) -> ErrorKind { - self.kind - } - - /// Return structured PostgreSQL error details when the failure came from - /// a backend `ErrorResponse`. - pub fn postgres_error(&self) -> Option<&crate::PostgresError> { - self.inner.downcast_ref() - } - - /// Return structured managed-storage details without inspecting error text. - pub fn storage_error(&self) -> Option { - self.inner - .downcast_ref::() - .map(|cause| cause.details) - } - - /// Return both failures when a transaction callback and rollback failed. - pub fn transaction_rollback_errors(&self) -> Option<(&Error, &Error)> { - self.inner - .downcast_ref::() - .map(|error| (error.callback.as_ref(), error.rollback.as_ref())) - } - - /// Return both failures when a callback error follows an independent - /// database or protocol failure. This pair never implies that rollback ran. - pub fn transaction_callback_database_errors(&self) -> Option<(&Error, &Error)> { - self.inner - .downcast_ref::() - .map(|error| (error.callback.as_ref(), error.database.as_ref())) - } - - /// Return structured frontend-program failure details for `pg_dump` or `psql`. - #[cfg(feature = "tools")] - pub fn tool_error(&self) -> Option<&crate::tools::PostgresToolError> { - self.inner.downcast_ref() - } - - pub(crate) fn from_anyhow(inner: anyhow::Error) -> Self { - let kind = inner - .downcast_ref::() - .map(|_| ErrorKind::Storage) - .or_else(|| { - inner - .downcast_ref::() - .map(|cause| cause.kind) - }) - .or_else(|| { - inner - .downcast_ref::() - .map(|_| ErrorKind::Postgres) - }) - .unwrap_or(ErrorKind::Other); - Self { - kind, - inner: Arc::new(inner), - } - } - - pub(crate) fn message(message: impl fmt::Display + fmt::Debug + Send + Sync + 'static) -> Self { - Self::from_anyhow(anyhow::Error::msg(message)) - } - - pub(crate) fn lifecycle(message: impl fmt::Display + Send + Sync + 'static) -> Self { - Self::classified(ErrorKind::Lifecycle, message) - } - - pub(crate) fn transaction_active(message: impl fmt::Display + Send + Sync + 'static) -> Self { - Self::classified(ErrorKind::TransactionActive, message) - } - - fn classified(kind: ErrorKind, message: impl fmt::Display + Send + Sync + 'static) -> Self { - Self::from_anyhow(classified_anyhow(kind, message)) - } - - pub(crate) fn transaction_rollback(callback: Self, rollback: Self) -> Self { - Self::from_anyhow(anyhow::Error::new(TransactionRollbackCause { - callback: Box::new(callback), - rollback: Box::new(rollback), - })) - } - - pub(crate) fn transaction_callback_and_database(callback: Self, database: Self) -> Self { - Self::from_anyhow(anyhow::Error::new(TransactionCallbackAndDatabaseCause { - callback: Box::new(callback), - database: Box::new(database), - })) - } -} - -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.inner.fmt(f) - } -} - -impl error::Error for Error { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - Some(self.inner.as_ref().as_ref()) - } -} - -impl fmt::Display for ClassifiedCause { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.message.fmt(f) - } -} - -impl error::Error for ClassifiedCause {} - -impl fmt::Display for StorageCause { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.source.fmt(f) - } -} - -impl error::Error for StorageCause { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - Some(self.source.as_ref()) - } -} - -pub(crate) fn classified_anyhow( - kind: ErrorKind, - message: impl fmt::Display + Send + Sync + 'static, -) -> anyhow::Error { - anyhow::Error::new(ClassifiedCause { - kind, - message: message.to_string(), - }) -} - -pub(crate) fn invalid_configuration( - message: impl fmt::Display + Send + Sync + 'static, -) -> anyhow::Error { - classified_anyhow(ErrorKind::InvalidConfiguration, message) -} - -pub(crate) fn lifecycle(message: impl fmt::Display + Send + Sync + 'static) -> anyhow::Error { - classified_anyhow(ErrorKind::Lifecycle, message) -} - -pub(crate) fn transaction_active( - message: impl fmt::Display + Send + Sync + 'static, -) -> anyhow::Error { - classified_anyhow(ErrorKind::TransactionActive, message) -} - -pub(crate) fn storage_error( - source: anyhow::Error, - code: StorageErrorCode, - commit_state: StorageCommitState, - phase: StorageErrorPhase, -) -> anyhow::Error { - if source.downcast_ref::().is_some() { - return source; - } - anyhow::Error::new(StorageCause { - details: StorageErrorDetails { - code, - commit_state, - phase, - }, - source, - }) -} - -pub(crate) fn storage_message( - message: impl fmt::Display + fmt::Debug + Send + Sync + 'static, - code: StorageErrorCode, - commit_state: StorageCommitState, - phase: StorageErrorPhase, -) -> anyhow::Error { - storage_error(anyhow::Error::msg(message), code, commit_state, phase) -} - -impl fmt::Display for TransactionRollbackCause { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "transaction callback failed: {}; rollback also failed: {}", - self.callback, self.rollback - ) - } -} - -impl error::Error for TransactionRollbackCause { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - Some(self.callback.as_ref()) - } -} - -impl fmt::Display for TransactionCallbackAndDatabaseCause { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "transaction callback failed: {}; an independent database failure also occurred: {}", - self.callback, self.database - ) - } -} - -impl error::Error for TransactionCallbackAndDatabaseCause { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - Some(self.callback.as_ref()) - } -} - -pub(crate) fn public_result(result: anyhow::Result) -> Result { - result.map_err(Error::from_anyhow) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{PostgresError, PostgresErrorField}; - - #[test] - fn postgres_error_finds_structured_backend_error() { - let postgres = PostgresError { - severity: Some("ERROR".to_owned()), - localized_severity: None, - nonlocalized_severity: Some("ERROR".to_owned()), - sqlstate: Some("23505".to_owned()), - message: "duplicate key".to_owned(), - detail: None, - hint: None, - position: None, - internal_position: None, - internal_query: None, - where_: None, - schema_name: None, - table_name: None, - column_name: None, - data_type_name: None, - constraint_name: None, - file: None, - line: None, - routine: None, - fields: vec![PostgresErrorField { - code: b'C', - value: "23505".to_owned(), - }], - notices: Vec::new(), - }; - let error = Error::from_anyhow(anyhow::Error::new(postgres)); - assert_eq!(error.kind(), ErrorKind::Postgres); - assert_eq!( - error - .postgres_error() - .and_then(|error| error.sqlstate.as_deref()), - Some("23505") - ); - assert!(error::Error::source(&error).is_some()); - - let replay = error.clone(); - assert_eq!(replay.postgres_error(), error.postgres_error()); - assert_eq!(replay.to_string(), error.to_string()); - } - - #[test] - fn typed_classification_survives_anyhow_context_without_message_inference() { - use anyhow::Context as _; - - let invalid = Err::<(), _>(invalid_configuration("invalid storage")) - .context("open database") - .unwrap_err(); - assert_eq!( - Error::from_anyhow(invalid).kind(), - ErrorKind::InvalidConfiguration - ); - - let same_words = Error::message("invalid storage"); - assert_eq!(same_words.kind(), ErrorKind::Other); - assert_eq!(Error::lifecycle("closed").kind(), ErrorKind::Lifecycle); - assert_eq!( - Error::transaction_active("active transaction").kind(), - ErrorKind::TransactionActive - ); - - let storage = Err::<(), _>(storage_message( - "misleading words: corrupt but actually owned", - StorageErrorCode::Busy, - StorageCommitState::Unchanged, - StorageErrorPhase::Ownership, - )) - .context("open database") - .unwrap_err(); - let storage = Error::from_anyhow(storage); - assert_eq!(storage.kind(), ErrorKind::Storage); - assert_eq!( - storage.storage_error(), - Some(StorageErrorDetails { - code: StorageErrorCode::Busy, - commit_state: StorageCommitState::Unchanged, - phase: StorageErrorPhase::Ownership, - }) - ); - - let same_storage_words = Error::message("database root is already in use"); - assert_eq!(same_storage_words.kind(), ErrorKind::Other); - assert_eq!(same_storage_words.storage_error(), None); - } - - #[test] - fn transaction_rollback_error_preserves_both_typed_errors() { - let error = Error::transaction_rollback( - Error::message("callback failed"), - Error::message("rollback failed"), - ); - - assert_eq!( - error.to_string(), - "transaction callback failed: callback failed; rollback also failed: rollback failed" - ); - let (callback, rollback) = error - .transaction_rollback_errors() - .expect("callback and rollback failures remain typed"); - assert_eq!(callback.to_string(), "callback failed"); - assert_eq!(rollback.to_string(), "rollback failed"); - - let transaction = TransactionError::CallbackAndDatabase { - callback: Error::message("callback failed"), - database: Error::message("stream recovery failed"), - }; - assert!(transaction.rollback_error().is_none()); - assert_eq!( - transaction - .database_error() - .map(ToString::to_string) - .as_deref(), - Some("stream recovery failed") - ); - let flattened: Error = transaction.into(); - let (callback, database) = flattened - .transaction_callback_database_errors() - .expect("callback and independent database failure remain typed"); - assert_eq!(callback.to_string(), "callback failed"); - assert_eq!(database.to_string(), "stream recovery failed"); - - let panic = - RawStreamError::::CallbackPanicked(Error::message("callback panicked")); - assert!(panic.database_error().is_none()); - assert_eq!( - panic - .callback_panic_error() - .map(ToString::to_string) - .as_deref(), - Some("callback panicked") - ); - } -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/lib.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/lib.rs deleted file mode 100644 index f1ff833e6..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/lib.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![doc = include_str!("../README.md")] -#![deny(unsafe_code)] - -mod async_api; -mod error; -mod oliphaunt; - -#[cfg(feature = "extensions")] -pub use oliphaunt::extensions::Extension; - -pub use async_api::{ - AsyncOliphaunt, AsyncOliphauntBuilder, AsyncOliphauntServer, AsyncOliphauntServerBuilder, - AsyncSql, AsyncTransaction, -}; -pub use error::{ - Error, ErrorKind, RawStreamCallbackOutput, RawStreamError, RawStreamResult, Result, - StorageCommitState, StorageErrorCode, StorageErrorDetails, StorageErrorPhase, TransactionError, - TransactionResult, -}; -#[cfg(any(feature = "__internal-napi", test))] -#[doc(hidden)] -pub use oliphaunt::CatalogProfile; -pub use oliphaunt::{ - CommandResult, DatabaseStorage, DecodeError, ExecResult, FromSql, IntoParameter, Oliphaunt, - OliphauntBuilder, OliphauntServer, OliphauntServerBuilder, Parameter, PostgresError, - PostgresErrorField, PostgresNotice, QueryField, QueryFormat, QueryResult, QueryRow, RowIndex, - ServerListen, Sql, StatementDescription, StatementResult, Transaction, TypeOid, ValueFormat, - ValueRef, -}; - -/// Options and structured errors for packaged PostgreSQL frontend programs. -#[cfg(feature = "tools")] -pub mod tools { - pub use crate::oliphaunt::tools::{ - PgDumpOptions, PostgresToolError, PostgresToolOutput, PsqlOptions, - }; -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/assets.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/assets.rs deleted file mode 100644 index 5e1f881c5..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/assets.rs +++ /dev/null @@ -1,277 +0,0 @@ -use anyhow::{Context, Result, ensure}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct AssetManifestMetadata { - pub source_lane: Option, - pub source_fingerprint: Option, - pub postgres_version: String, - pub runtime_module_sha256: String, - pub cluster_seed_source_lane: Option, - pub cluster_seed_source_fingerprint: Option, - pub cluster_seed_postgres_version: Option, - pub cluster_seed_profile: String, - pub cluster_seed_compatibility_key: String, -} - -/// Packaged PostgreSQL initialization and runtime-data profile. -#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum CatalogProfile { - /// The standard PostgreSQL catalog without packaged ICU data. - Standard, - /// The ICU catalog with its matching packaged ICU data. - Icu, -} - -impl CatalogProfile { - pub const fn as_str(self) -> &'static str { - match self { - Self::Standard => "standard", - Self::Icu => "icu", - } - } - - pub(crate) fn validate_available(self) -> Result<()> { - if self == Self::Icu && !cfg!(feature = "icu") { - return Err(crate::error::invalid_configuration( - "the ICU catalog profile requires the oliphaunt-wasix `icu` feature", - )); - } - Ok(()) - } -} - -impl Default for CatalogProfile { - fn default() -> Self { - default_catalog_profile() - } -} - -pub(crate) const fn default_catalog_profile() -> CatalogProfile { - if cfg!(feature = "icu") { - CatalogProfile::Icu - } else { - CatalogProfile::Standard - } -} - -pub fn asset_manifest_metadata() -> Result { - asset_manifest_metadata_for(default_catalog_profile()) -} - -pub(crate) fn asset_manifest_metadata_for( - selected_profile: CatalogProfile, -) -> Result { - let manifest = - liboliphaunt_wasix_portable::manifest().context("parse oliphaunt-wasix asset manifest")?; - if liboliphaunt_wasix_portable::HAS_EMBEDDED_ASSETS { - let seed = manifest - .cluster_seeds - .get(selected_profile.as_str()) - .context("embedded WASIX assets are missing the selected cluster seed entry")?; - validate_embedded_source_fingerprints( - manifest.source_fingerprint.as_deref(), - seed.source_fingerprint.as_deref(), - )?; - } - let seed = manifest.cluster_seeds.get(selected_profile.as_str()); - Ok(AssetManifestMetadata { - source_lane: manifest.source_lane, - source_fingerprint: manifest.source_fingerprint, - postgres_version: manifest.runtime.postgres_version, - runtime_module_sha256: manifest.runtime.module_sha256, - cluster_seed_source_lane: seed.and_then(|seed| seed.source_lane.clone()), - cluster_seed_source_fingerprint: seed.and_then(|seed| seed.source_fingerprint.clone()), - cluster_seed_postgres_version: seed.map(|seed| seed.postgres_version.clone()), - cluster_seed_profile: selected_profile.as_str().to_owned(), - cluster_seed_compatibility_key: seed - .map(|seed| seed.compatibility_key.clone()) - .unwrap_or_default(), - }) -} - -fn validate_embedded_source_fingerprints( - asset_fingerprint: Option<&str>, - seed_fingerprint: Option<&str>, -) -> Result<()> { - let asset_fingerprint = asset_fingerprint - .filter(|value| !value.trim().is_empty()) - .context("embedded WASIX asset manifest is missing source-fingerprint metadata")?; - let seed_fingerprint = seed_fingerprint - .filter(|value| !value.trim().is_empty()) - .context("embedded WASIX cluster seed is missing source-fingerprint metadata")?; - ensure!( - seed_fingerprint == asset_fingerprint, - "embedded WASIX runtime and cluster seed source fingerprints differ" - ); - Ok(()) -} - -pub(crate) fn runtime_archive() -> Option<&'static [u8]> { - liboliphaunt_wasix_portable::runtime_archive() -} - -pub(crate) fn expected_runtime_archive_sha256() -> Result { - let manifest = - liboliphaunt_wasix_portable::manifest().context("parse oliphaunt-wasix asset manifest")?; - Ok(manifest.runtime.sha256) -} - -pub(crate) fn cluster_seed_archive(profile: CatalogProfile) -> Option<&'static [u8]> { - match profile { - CatalogProfile::Standard => liboliphaunt_wasix_portable::standard_cluster_seed_archive(), - CatalogProfile::Icu => { - #[cfg(feature = "icu")] - { - liboliphaunt_wasix_portable::icu_cluster_seed_archive() - } - #[cfg(not(feature = "icu"))] - { - None - } - } - } -} - -pub(crate) fn cluster_seed_manifest(profile: CatalogProfile) -> Option<&'static [u8]> { - match profile { - CatalogProfile::Standard => liboliphaunt_wasix_portable::standard_cluster_seed_manifest(), - CatalogProfile::Icu => { - #[cfg(feature = "icu")] - { - liboliphaunt_wasix_portable::icu_cluster_seed_manifest() - } - #[cfg(not(feature = "icu"))] - { - None - } - } - } -} - -#[cfg(feature = "tools")] -pub(crate) fn pg_dump_wasm() -> Option<&'static [u8]> { - oliphaunt_wasix_tools::pg_dump_wasm() -} - -#[cfg(feature = "tools")] -pub(crate) fn psql_wasm() -> Option<&'static [u8]> { - oliphaunt_wasix_tools::psql_wasm() -} - -pub(crate) fn icu_data_archive(profile: CatalogProfile) -> Option<&'static [u8]> { - if profile == CatalogProfile::Standard { - return None; - } - #[cfg(feature = "icu")] - { - oliphaunt_icu::icu_data_archive() - } - #[cfg(not(feature = "icu"))] - { - None - } -} - -pub(crate) fn expected_icu_data_archive_sha256() -> Option<&'static str> { - #[cfg(feature = "icu")] - { - oliphaunt_icu::ICU_DATA_ARCHIVE_SHA256 - } - #[cfg(not(feature = "icu"))] - { - None - } -} - -pub(crate) fn expected_icu_data_tree_sha256() -> Option<&'static str> { - #[cfg(feature = "icu")] - { - oliphaunt_icu::ICU_DATA_TREE_SHA256 - } - #[cfg(not(feature = "icu"))] - { - None - } -} - -#[cfg(feature = "extensions")] -pub(crate) fn extension_archive(sql_name: &str) -> Option<&'static [u8]> { - liboliphaunt_wasix_portable::extension_archive(sql_name) -} - -#[cfg(feature = "extensions")] -pub(crate) fn expected_extension_archive_sha256(sql_name: &str) -> Result { - liboliphaunt_wasix_portable::expected_extension_archive_sha256(sql_name) - .map(str::to_owned) - .ok_or_else(|| { - crate::error::invalid_configuration(format!( - "extension asset '{sql_name}' is not embedded in this oliphaunt-wasix build" - )) - }) -} - -#[cfg(feature = "extensions")] -pub(crate) fn extension_aot_manifest_json(target: &str, sql_name: &str) -> Option<&'static str> { - liboliphaunt_wasix_portable::extension_aot_manifest_json(target, sql_name) -} - -#[cfg(feature = "extensions")] -pub(crate) fn extension_aot_artifact_bytes(target: &str, name: &str) -> Option<&'static [u8]> { - liboliphaunt_wasix_portable::extension_aot_artifact_bytes(target, name) -} - -#[cfg(test)] -mod tests { - use super::{ - CatalogProfile, asset_manifest_metadata, cluster_seed_archive, cluster_seed_manifest, - expected_icu_data_archive_sha256, expected_icu_data_tree_sha256, - expected_runtime_archive_sha256, icu_data_archive, runtime_archive, - validate_embedded_source_fingerprints, - }; - - #[test] - fn asset_helpers_expose_a_consistent_feature_contract() { - let default_profile = if cfg!(feature = "icu") { - CatalogProfile::Icu - } else { - CatalogProfile::Standard - }; - assert_eq!(CatalogProfile::default(), default_profile); - CatalogProfile::Standard.validate_available().unwrap(); - assert_eq!( - CatalogProfile::Icu.validate_available().is_ok(), - cfg!(feature = "icu") - ); - - let metadata = asset_manifest_metadata().unwrap(); - assert_eq!(metadata.cluster_seed_profile, default_profile.as_str()); - let has_embedded_assets = liboliphaunt_wasix_portable::HAS_EMBEDDED_ASSETS; - assert_eq!( - !expected_runtime_archive_sha256().unwrap().is_empty(), - has_embedded_assets - ); - assert_eq!(runtime_archive().is_some(), has_embedded_assets); - assert_eq!( - cluster_seed_archive(CatalogProfile::Standard).is_some(), - has_embedded_assets - ); - assert_eq!( - cluster_seed_manifest(CatalogProfile::Standard).is_some(), - has_embedded_assets - ); - assert!(icu_data_archive(CatalogProfile::Standard).is_none()); - let has_icu_assets = icu_data_archive(CatalogProfile::Icu).is_some(); - assert_eq!(expected_icu_data_archive_sha256().is_some(), has_icu_assets); - assert_eq!(expected_icu_data_tree_sha256().is_some(), has_icu_assets); - } - - #[test] - fn embedded_source_fingerprints_are_required_and_equal() { - validate_embedded_source_fingerprints(Some("source-key"), Some("source-key")) - .expect("matching identities"); - assert!(validate_embedded_source_fingerprints(None, Some("source-key")).is_err()); - assert!(validate_embedded_source_fingerprints(Some("source-key"), Some(" ")).is_err()); - assert!(validate_embedded_source_fingerprints(Some("runtime"), Some("seed")).is_err()); - } -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/builder.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/builder.rs deleted file mode 100644 index 31590041e..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/builder.rs +++ /dev/null @@ -1,271 +0,0 @@ -use anyhow::Result; - -use crate::oliphaunt::assets::{CatalogProfile, default_catalog_profile}; -#[cfg(feature = "extensions")] -use crate::oliphaunt::base::install_missing_extension_archives; -use crate::oliphaunt::base::{DatabasePlan, PreparedDatabase, prepare_database}; -use crate::oliphaunt::client::Oliphaunt; -use crate::oliphaunt::config::{PostgresConfig, StartupConfig}; -#[cfg(feature = "extensions")] -use crate::oliphaunt::extensions::{ - Extension, postgres_config_with_extension_startup, resolve_extension_set, -}; -use crate::oliphaunt::storage::DatabaseStorage; - -/// Builder for opening [`Oliphaunt`] databases. -#[derive(Debug, Clone)] -pub struct OliphauntBuilder { - storage: DatabaseStorage, - catalog_profile: CatalogProfile, - postgres_config: PostgresConfig, - startup_config: StartupConfig, - #[cfg(feature = "extensions")] - extensions: Vec, -} - -impl Default for OliphauntBuilder { - fn default() -> Self { - Self { - storage: DatabaseStorage::Memory, - catalog_profile: default_catalog_profile(), - postgres_config: PostgresConfig::default(), - startup_config: StartupConfig::default(), - #[cfg(feature = "extensions")] - extensions: Vec::new(), - } - } -} - -impl OliphauntBuilder { - /// Create a builder for a memory database initialized from the packaged - /// cluster seed. - pub fn new() -> Self { - Self::default() - } - - /// Select where PostgreSQL stores its mutable database files. - pub fn storage(mut self, storage: DatabaseStorage) -> Self { - self.storage = storage; - self - } - - /// Select the packaged standard or ICU catalog and matching runtime data. - #[cfg(any(feature = "__internal-napi", test))] - #[doc(hidden)] - pub fn catalog_profile(mut self, profile: CatalogProfile) -> Self { - self.catalog_profile = profile; - self - } - - /// Set a PostgreSQL startup GUC for this embedded backend. - pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self { - self.postgres_config.insert(name, value); - self - } - - /// Set multiple PostgreSQL startup GUCs for this embedded backend. - pub fn startup_gucs(mut self, settings: impl IntoIterator) -> Self - where - K: Into, - V: Into, - { - for (name, value) in settings { - self.postgres_config.insert(name, value); - } - self - } - - /// Connect as a PostgreSQL role. The role must already exist in the - /// cluster. - pub fn username(mut self, username: impl Into) -> Self { - self.startup_config.username = username.into(); - self - } - - /// Connect to a PostgreSQL database. The database must already exist in the - /// cluster. - pub fn database(mut self, database: impl Into) -> Self { - self.startup_config.database = database.into(); - self - } - - /// Make one bundled PostgreSQL extension artifact available to the database. - /// Database-local installation remains the application's migration concern. - #[cfg(feature = "extensions")] - pub fn extension(mut self, extension: Extension) -> Self { - self.extensions.push(extension); - self - } - - /// Make bundled PostgreSQL extension artifacts available to the database. - /// Database-local installation remains the application's migration concern. - #[cfg(feature = "extensions")] - pub fn extensions(mut self, extensions: impl IntoIterator) -> Self { - self.extensions.extend(extensions); - self - } - - /// Install, initialize, and start the selected database. - pub fn open(self) -> crate::Result { - crate::error::public_result(self.open_inner()) - } - - pub(crate) fn open_inner(self) -> Result { - #[cfg(feature = "extensions")] - let (extensions, postgres_config) = self.resolved_extension_startup()?; - #[cfg(not(feature = "extensions"))] - let postgres_config = self.postgres_config.clone(); - postgres_config.validate()?; - self.storage.validate()?; - self.startup_config.validate()?; - let plan = DatabasePlan::new(self.storage.clone(), self.catalog_profile); - let prepared = prepare_database(plan, &self.startup_config.username)?; - #[cfg(feature = "extensions")] - { - self.open_prepared_database(prepared, extensions, postgres_config) - } - #[cfg(not(feature = "extensions"))] - { - self.open_prepared_database(prepared, postgres_config) - } - } - - #[cfg(feature = "extensions")] - fn resolved_extension_startup(&self) -> Result<(Vec, PostgresConfig)> { - let extensions = resolve_extension_set(&self.extensions)?; - let postgres_config = - postgres_config_with_extension_startup(self.postgres_config.clone(), &extensions)?; - Ok((extensions, postgres_config)) - } - - fn open_prepared_database( - self, - prepared: PreparedDatabase, - #[cfg(feature = "extensions")] extensions: Vec, - postgres_config: PostgresConfig, - ) -> Result { - let PreparedDatabase { - workspace, - directory_lock, - outcome, - } = prepared; - #[cfg(feature = "extensions")] - install_missing_extension_archives(&outcome, &extensions)?; - #[cfg(feature = "extensions")] - let mut instance = Oliphaunt::new_prepared_with_config_and_extension_preload( - outcome, - postgres_config, - self.startup_config, - &extensions, - )?; - #[cfg(not(feature = "extensions"))] - let mut instance = - Oliphaunt::new_prepared_with_config(outcome, postgres_config, self.startup_config)?; - if let Some(lock) = directory_lock { - instance.attach_directory_lock(lock); - } - if let Some(workspace) = workspace { - instance.attach_workspace(workspace); - } - Ok(instance) - } -} - -#[cfg(test)] -mod storage_tests { - use super::*; - - #[test] - fn default_builder_selects_memory() { - let builder = OliphauntBuilder::default(); - assert_eq!(builder.storage, DatabaseStorage::Memory); - assert_eq!(builder.catalog_profile, CatalogProfile::default()); - } - - #[test] - fn catalog_profile_is_an_immutable_builder_value() { - let standard = OliphauntBuilder::new().catalog_profile(CatalogProfile::Standard); - let icu = standard.clone().catalog_profile(CatalogProfile::Icu); - - assert_eq!(standard.catalog_profile, CatalogProfile::Standard); - assert_eq!(icu.catalog_profile, CatalogProfile::Icu); - } - - #[cfg(not(feature = "icu"))] - #[test] - fn unavailable_icu_profile_is_rejected_before_storage_mutation() { - let parent = tempfile::tempdir().expect("temporary parent"); - let root = parent.path().join("database"); - let error = OliphauntBuilder::new() - .storage(DatabaseStorage::Directory(root.clone())) - .catalog_profile(CatalogProfile::Icu) - .open() - .err() - .expect("ICU profile requires its packaging feature"); - - assert_eq!(error.kind(), crate::ErrorKind::InvalidConfiguration); - assert!(error.to_string().contains("requires")); - assert!(!root.exists()); - } - - #[test] - fn fluent_configuration_preserves_postgres_vocabulary() { - let directory = std::path::PathBuf::from("database-root"); - let builder = OliphauntBuilder::new() - .storage(DatabaseStorage::Directory(directory.clone())) - .startup_guc("work_mem", "16MB") - .startup_gucs([("application_name", "builder-test")]) - .username("app_user") - .database("app_database"); - - assert_eq!(builder.storage, DatabaseStorage::Directory(directory)); - assert_eq!( - builder.postgres_config.iter().collect::>(), - vec![("application_name", "builder-test"), ("work_mem", "16MB")] - ); - assert_eq!(builder.startup_config.username, "app_user"); - assert_eq!(builder.startup_config.database, "app_database"); - } - - #[test] - fn open_rejects_invalid_startup_configuration_before_runtime_work() { - let error = OliphauntBuilder::new() - .startup_guc("bad=name", "value") - .open() - .err() - .expect("invalid GUCs must fail before preparing a database"); - - assert!(error.to_string().contains("must not contain")); - } -} - -#[cfg(all(test, feature = "extension-pg-textsearch"))] -mod tests { - use super::*; - use crate::oliphaunt::extensions::Extension; - - #[test] - fn direct_path_merges_pg_textsearch_preload_once_before_open() { - let builder = OliphauntBuilder::new() - .startup_guc("shared_preload_libraries", "auto_explain") - .startup_guc("work_mem", "16MB") - .extensions([Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH]); - - let (_, postgres_config) = builder.resolved_extension_startup().unwrap(); - - assert_eq!( - postgres_config.get("shared_preload_libraries"), - Some("auto_explain,pg_textsearch") - ); - assert_eq!(postgres_config.get("work_mem"), Some("16MB")); - assert_eq!( - postgres_config - .get("shared_preload_libraries") - .unwrap() - .split(',') - .filter(|library| *library == "pg_textsearch") - .count(), - 1 - ); - } -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/config.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/config.rs deleted file mode 100644 index 9d0b244f6..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/config.rs +++ /dev/null @@ -1,274 +0,0 @@ -use std::collections::BTreeMap; - -use anyhow::Result; - -use crate::error::invalid_configuration; - -pub(crate) const SINGLE_BACKEND_STARTUP_GUCS: &[(&str, &str)] = &[ - ("exit_on_error", "false"), - ("max_wal_senders", "0"), - ("max_worker_processes", "0"), - ("max_parallel_workers", "0"), - ("max_parallel_workers_per_gather", "0"), - ("max_parallel_maintenance_workers", "0"), - ("io_method", "sync"), -]; - -/// PostgreSQL startup GUCs applied through normal `postgres -c` handling before -/// the embedded backend starts. -/// -/// Settings added here override `oliphaunt-wasix`'s default startup profile because -/// they are appended after the defaults in the generated PostgreSQL argv. Settings -/// that enforce the embedded single-backend runtime shape accept only their -/// canonical value and are omitted from the user-specific configuration. -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub(crate) struct PostgresConfig { - settings: BTreeMap, -} - -impl PostgresConfig { - #[cfg(test)] - fn new() -> Self { - Self::default() - } - - #[cfg(test)] - fn set(mut self, name: impl Into, value: impl Into) -> Self { - self.insert(name, value); - self - } - - pub(crate) fn insert(&mut self, name: impl Into, value: impl Into) { - let name = name.into(); - self.settings - .insert(name.trim().to_ascii_lowercase(), value.into()); - } - - #[cfg(feature = "extensions")] - pub(crate) fn get(&self, name: &str) -> Option<&str> { - self.settings.get(name).map(String::as_str) - } - - pub(crate) fn validate(&self) -> Result<()> { - for (name, value) in &self.settings { - validate_guc_name(name)?; - if matches!(name.as_str(), "config_file" | "data_directory") { - return Err(invalid_configuration(format!( - "Oliphaunt owns PostgreSQL startup GUC '{name}'; configure the database through Oliphaunt's storage API" - ))); - } - if let Some(required) = single_backend_guc_value(name) - && value != required - { - return Err(invalid_configuration(format!( - "PostgreSQL startup GUC '{name}' is managed by oliphaunt-wasix and must remain '{required}'" - ))); - } - if value.contains('\0') { - return Err(invalid_configuration(format!( - "PostgreSQL startup GUC value for '{name}' must not contain NUL bytes" - ))); - } - } - Ok(()) - } - - pub(crate) fn iter(&self) -> impl Iterator { - self.settings - .iter() - .filter(|(name, _)| single_backend_guc_value(name).is_none()) - .map(|(name, value)| (name.as_str(), value.as_str())) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) struct StartupConfig { - pub(crate) username: String, - pub(crate) database: String, -} - -impl Default for StartupConfig { - fn default() -> Self { - Self { - username: "postgres".to_owned(), - database: "postgres".to_owned(), - } - } -} - -impl StartupConfig { - pub(crate) fn validate(&self) -> Result<()> { - validate_startup_value("username", &self.username)?; - validate_startup_value("database", &self.database)?; - Ok(()) - } -} - -fn validate_guc_name(name: &str) -> Result<()> { - if name.is_empty() { - return Err(invalid_configuration( - "PostgreSQL startup GUC name must not be empty", - )); - } - if name.contains('\0') || name.contains('=') { - return Err(invalid_configuration(format!( - "PostgreSQL startup GUC name '{name}' must not contain NUL bytes or '='" - ))); - } - - for part in name.split('.') { - if part.is_empty() { - return Err(invalid_configuration(format!( - "PostgreSQL startup GUC name '{name}' contains an empty identifier part" - ))); - } - let mut chars = part.chars(); - let first = chars.next().expect("part is non-empty"); - if !(first == '_' || first.is_ascii_alphabetic()) { - return Err(invalid_configuration(format!( - "PostgreSQL startup GUC name '{name}' must start each component with a letter or '_'" - ))); - } - if chars.any(|ch| !(ch == '_' || ch == '$' || ch.is_ascii_alphanumeric())) { - return Err(invalid_configuration(format!( - "PostgreSQL startup GUC name '{name}' may only contain letters, digits, '_', '$', and '.'" - ))); - } - } - - Ok(()) -} - -fn single_backend_guc_value(name: &str) -> Option<&'static str> { - let normalized = name.trim().replace('-', "_"); - SINGLE_BACKEND_STARTUP_GUCS - .iter() - .find_map(|(managed, value)| normalized.eq_ignore_ascii_case(managed).then_some(*value)) -} - -fn validate_startup_value(name: &str, value: &str) -> Result<()> { - if value.trim().is_empty() { - return Err(invalid_configuration(format!("{name} must not be empty"))); - } - if value.contains('\0') { - return Err(invalid_configuration(format!( - "{name} must not contain NUL bytes" - ))); - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::{PostgresConfig, StartupConfig}; - - #[test] - fn validates_builtin_and_extension_guc_names() { - PostgresConfig::new() - .set("synchronous_commit", "off") - .set("pg_stat_statements.track", "all") - .set("_name", "") - .set("ext.name$1", "value") - .set(" trimmed_name ", " ") - .validate() - .unwrap(); - } - - #[test] - fn rejects_invalid_guc_names_before_startup() { - for name in [ - "1name", - ".foo", - "a..b", - "a.1b", - "ext.$name", - "bad=name", - "bad\0name", - ] { - PostgresConfig::new() - .set(name, "off") - .validate() - .expect_err("invalid GUC name should be rejected"); - } - } - - #[test] - fn rejects_managed_single_backend_gucs() { - let err = PostgresConfig::new() - .set("MAX_WORKER_PROCESSES", "1") - .validate() - .expect_err("managed GUC should be rejected"); - assert!(err.to_string().contains("must remain '0'")); - } - - #[test] - fn accepts_and_canonicalizes_matching_single_backend_gucs() { - let config = PostgresConfig::new().set("MAX_WORKER_PROCESSES", "0"); - config.validate().unwrap(); - assert!(config.iter().next().is_none()); - } - - #[test] - fn guc_names_are_case_insensitive_and_last_insertion_wins() { - let config = PostgresConfig::new() - .set("work_mem", "1MB") - .set("WORK_MEM", "2MB"); - config.validate().unwrap(); - assert_eq!(config.iter().collect::>(), [("work_mem", "2MB")]); - } - - #[test] - fn rejects_storage_redirection_gucs_case_insensitively() { - for name in ["CONFIG_FILE", "data_directory"] { - let error = PostgresConfig::new() - .set(name, "/tmp/other") - .validate() - .expect_err("storage is SDK-owned"); - assert!(error.to_string().contains("Oliphaunt owns")); - } - } - - #[test] - fn startup_values_match_native_rust_identity_validation() { - for (username, database, expected_name) in [ - ("", "postgres", "username"), - (" \t\n", "postgres", "username"), - ("postgres", "", "database"), - ("postgres", " \t\n", "database"), - ] { - let error = StartupConfig { - username: username.to_owned(), - database: database.to_owned(), - } - .validate() - .expect_err("empty and whitespace-only startup identities must be rejected"); - assert_eq!( - error.to_string(), - format!("{expected_name} must not be empty") - ); - } - - for (username, database, expected_name) in [ - ("bad\0user", "postgres", "username"), - ("postgres", "bad\0database", "database"), - ] { - let error = StartupConfig { - username: username.to_owned(), - database: database.to_owned(), - } - .validate() - .expect_err("NUL cannot be encoded in a startup cstring"); - assert_eq!( - error.to_string(), - format!("{expected_name} must not contain NUL bytes") - ); - } - - StartupConfig { - username: " application user ".to_owned(), - database: " application database ".to_owned(), - } - .validate() - .expect("nonempty PostgreSQL identities are preserved rather than trimmed"); - } -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/extensions.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/extensions.rs deleted file mode 100644 index 234dfa8c1..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/extensions.rs +++ /dev/null @@ -1,729 +0,0 @@ -use std::collections::BTreeSet; - -use anyhow::Result; -#[cfg(all(test, feature = "extension-pg-textsearch"))] -use anyhow::bail; - -use crate::oliphaunt::config::PostgresConfig; - -const SHARED_PRELOAD_LIBRARIES: &str = "shared_preload_libraries"; - -#[path = "generated_extensions.rs"] -mod generated; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct ExtensionNativeModule { - runtime_path: &'static str, - aot_name: Option<&'static str>, -} - -impl ExtensionNativeModule { - pub(crate) const fn runtime_path(self) -> &'static str { - self.runtime_path - } - - pub(crate) const fn aot_name(self) -> Option<&'static str> { - self.aot_name - } -} - -/// A bundled PostgreSQL extension artifact that Oliphaunt can make available. -/// -/// Selecting an extension does not run `CREATE EXTENSION`, `LOAD`, or other -/// database-local SQL. Applications retain ordinary migration ownership. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Extension { - sql_name: &'static str, - native_support_modules: &'static [ExtensionNativeModule], - native_module_file: Option<&'static str>, - aot_name: Option<&'static str>, - dependencies: &'static [&'static str], - startup_config: &'static [&'static str], -} - -impl Extension { - /// SQL extension name used in `CREATE EXTENSION`. - pub const fn sql_name(self) -> &'static str { - self.sql_name - } - - /// Resolve a known extension artifact by its SQL name. - pub fn by_sql_name(sql_name: &str) -> Option { - Self::ALL - .iter() - .copied() - .find(|extension| extension.sql_name == sql_name) - } - - pub(crate) const fn aot_name(self) -> Option<&'static str> { - self.aot_name - } - - pub(crate) const fn native_module_file(self) -> Option<&'static str> { - self.native_module_file - } - - pub(crate) const fn native_support_modules(self) -> &'static [ExtensionNativeModule] { - self.native_support_modules - } - - pub(crate) const fn dependencies(self) -> &'static [&'static str] { - self.dependencies - } - - pub(crate) const fn startup_config(self) -> &'static [&'static str] { - self.startup_config - } -} - -pub(crate) fn resolve_extension_set(extensions: &[Extension]) -> Result> { - let mut visiting = BTreeSet::new(); - let mut visited = BTreeSet::new(); - let mut resolved = Vec::new(); - let mut requested = extensions.to_vec(); - requested.sort_by_key(|extension| extension.sql_name()); - for extension in requested { - visit_extension(extension, &mut visiting, &mut visited, &mut resolved)?; - } - Ok(resolved) -} - -/// Merge startup settings required by selected extensions into the caller's -/// PostgreSQL configuration before either a cluster seed or a backend is started. -/// -/// `shared_preload_libraries` is a list-valued GUC, so caller-provided and -/// extension-required entries are unioned in stable first-seen order. Other -/// extension startup settings may reuse an identical caller value, but a -/// conflicting value is rejected instead of silently weakening the extension -/// contract. -pub(crate) fn postgres_config_with_extension_startup( - mut postgres_config: PostgresConfig, - extensions: &[Extension], -) -> Result { - let mut shared_preload_libraries = Vec::new(); - let mut seen_shared_preload_libraries = BTreeSet::new(); - if let Some(configured) = postgres_config.get(SHARED_PRELOAD_LIBRARIES) { - append_unique_csv_values( - configured, - &mut shared_preload_libraries, - &mut seen_shared_preload_libraries, - ); - } - - for extension in extensions { - for assignment in extension.startup_config() { - let (name, value) = parse_startup_config_assignment(*extension, assignment)?; - - if name == SHARED_PRELOAD_LIBRARIES { - append_unique_csv_values( - value, - &mut shared_preload_libraries, - &mut seen_shared_preload_libraries, - ); - continue; - } - - if let Some(configured) = postgres_config.get(name) { - if configured != value { - return Err(crate::error::invalid_configuration(format!( - "extension '{}' requires PostgreSQL startup config {name}={value}, but the caller configured {name}={configured}", - extension.sql_name() - ))); - } - } else { - postgres_config.insert(name, value); - } - } - } - - if !shared_preload_libraries.is_empty() { - postgres_config.insert(SHARED_PRELOAD_LIBRARIES, shared_preload_libraries.join(",")); - } - postgres_config.validate()?; - Ok(postgres_config) -} - -#[cfg(all(test, feature = "extension-pg-textsearch"))] -pub(crate) fn ensure_extension_startup_config_is_active( - postgres_config: &PostgresConfig, - extension: Extension, -) -> Result<()> { - for assignment in extension.startup_config() { - let (name, required) = parse_startup_config_assignment(extension, assignment)?; - let configured = postgres_config.get(name); - let satisfied = if name == SHARED_PRELOAD_LIBRARIES { - let configured_values = configured - .into_iter() - .flat_map(comma_separated_values) - .collect::>(); - comma_separated_values(required).all(|value| configured_values.contains(value)) - } else { - configured == Some(required) - }; - - if !satisfied { - let configured = configured - .filter(|value| !value.trim().is_empty()) - .unwrap_or(""); - bail!( - "extension '{}' requires PostgreSQL startup config {name}={required} before PostgreSQL starts, but the already-running backend has {name}={configured}; reopen the database with this extension selected on OliphauntBuilder (call .extension(...) before .open()), because it cannot be enabled safely after startup", - extension.sql_name() - ); - } - } - Ok(()) -} - -fn parse_startup_config_assignment(extension: Extension, assignment: &str) -> Result<(&str, &str)> { - let (name, value) = assignment.split_once('=').ok_or_else(|| { - crate::error::invalid_configuration(format!( - "extension '{}' has invalid startup config assignment '{assignment}'; expected name=value", - extension.sql_name() - )) - })?; - let name = name.trim(); - let value = value.trim(); - if name.is_empty() { - return Err(crate::error::invalid_configuration(format!( - "extension '{}' has an empty startup config name in assignment '{assignment}'", - extension.sql_name() - ))); - } - if value.is_empty() { - return Err(crate::error::invalid_configuration(format!( - "extension '{}' has an empty startup config value in assignment '{assignment}'", - extension.sql_name() - ))); - } - Ok((name, value)) -} - -fn append_unique_csv_values(value: &str, ordered: &mut Vec, seen: &mut BTreeSet) { - for item in comma_separated_values(value) { - if seen.insert(item.to_owned()) { - ordered.push(item.to_owned()); - } - } -} - -fn comma_separated_values(value: &str) -> impl Iterator { - value - .split(',') - .map(str::trim) - .filter(|item| !item.is_empty()) -} - -fn visit_extension( - extension: Extension, - visiting: &mut BTreeSet<&'static str>, - visited: &mut BTreeSet<&'static str>, - resolved: &mut Vec, -) -> Result<()> { - if visited.contains(extension.sql_name()) { - return Ok(()); - } - if !visiting.insert(extension.sql_name()) { - return Err(crate::error::invalid_configuration(format!( - "cyclic bundled extension dependency involving '{}'", - extension.sql_name() - ))); - } - for dependency in extension.dependencies() { - let dependency_extension = Extension::by_sql_name(dependency).ok_or_else(|| { - crate::error::invalid_configuration(format!( - "selected extension '{}' depends on missing catalog extension '{}'", - extension.sql_name(), - dependency - )) - })?; - visit_extension(dependency_extension, visiting, visited, resolved)?; - } - visiting.remove(extension.sql_name()); - visited.insert(extension.sql_name()); - resolved.push(extension); - Ok(()) -} - -#[cfg(test)] -pub(crate) fn extension_smoke_sql(sql_name: &str) -> String { - crate::oliphaunt::test_fixtures::text(&format!("extensions/{sql_name}.sql")) -} - -#[cfg(test)] -pub(crate) fn extension_smoke_statements(sql: &str) -> impl Iterator { - sql.split("-- oliphaunt-statement") - .map(str::trim) - .filter(|statement| !statement.is_empty()) -} - -#[cfg(test)] -fn extension_activation_sql_for_test(extension: Extension) -> Result> { - Ok(resolve_extension_set(&[extension])? - .into_iter() - .flat_map(|resolved| generated::activation_sql_for_test(resolved).iter().copied()) - .collect()) -} - -#[cfg(all(test, feature = "extension-pg-textsearch"))] -mod startup_config_tests { - use super::*; - - #[test] - fn late_pg_textsearch_enable_requires_active_preload() { - let error = ensure_extension_startup_config_is_active( - &PostgresConfig::default(), - Extension::PG_TEXTSEARCH, - ) - .unwrap_err(); - let message = error.to_string(); - - assert!(message.contains("shared_preload_libraries=pg_textsearch")); - assert!(message.contains("already-running backend")); - assert!(message.contains(".extension(...) before .open()")); - - let mut active = PostgresConfig::default(); - active.insert( - "shared_preload_libraries", - "auto_explain, pg_textsearch,pg_textsearch", - ); - ensure_extension_startup_config_is_active(&active, Extension::PG_TEXTSEARCH).unwrap(); - } -} - -#[cfg(all(test, feature = "extensions"))] -mod extension_tests { - use super::*; - use crate::Oliphaunt; - use crate::{AsyncOliphauntServer, DatabaseStorage}; - use anyhow::{Context, Result, ensure}; - use sqlx::{Connection, PgConnection}; - use std::collections::BTreeSet; - use std::path::{Path, PathBuf}; - - #[test] - fn public_extensions_pass_direct_and_restart_smoke() -> Result<()> { - run_direct_and_restart_smoke_set(Extension::ALL) - } - - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn public_extensions_pass_server_smoke() -> Result<()> { - run_server_smoke_set(Extension::ALL).await - } - - #[test] - fn public_extensions_materialize_only_requested_libraries() -> Result<()> { - run_lifecycle_materialization_set(Extension::ALL) - } - - #[test] - #[cfg(all(feature = "extension-cube", feature = "extension-earthdistance"))] - fn dependent_extension_activation_includes_dependencies_first() -> Result<()> { - let activation = extension_activation_sql_for_test(Extension::EARTHDISTANCE)?; - assert_eq!(activation.len(), 2); - assert!(activation[0].contains("\"cube\"")); - assert!(activation[1].contains("\"earthdistance\"")); - Ok(()) - } - - #[test] - #[cfg(feature = "extension-uuid-ossp")] - fn uuid_ossp_aot_direct_and_restart_smoke() -> Result<()> { - run_direct_and_restart_smoke_set(&[Extension::UUID_OSSP]) - } - - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - #[cfg(feature = "extension-uuid-ossp")] - async fn uuid_ossp_aot_server_smoke() -> Result<()> { - run_server_smoke_set(&[Extension::UUID_OSSP]).await - } - - #[test] - #[cfg(feature = "extension-uuid-ossp")] - fn uuid_ossp_aot_materialization_smoke() -> Result<()> { - run_lifecycle_materialization_set(&[Extension::UUID_OSSP]) - } - - #[cfg(all(feature = "tools", feature = "extension-uuid-ossp"))] - #[test] - fn uuid_ossp_aot_dump_restore_smoke() -> Result<()> { - use crate::tools::{PgDumpOptions, PsqlOptions}; - - let mut source = Oliphaunt::builder() - .extension(Extension::UUID_OSSP) - .open() - .context("open UUID-OSSP AOT dump source")?; - source - .psql(PsqlOptions::new().script( - "CREATE EXTENSION \"uuid-ossp\";\ - CREATE TABLE uuid_ossp_aot_items(\ - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),\ - label text NOT NULL\ - );\ - INSERT INTO uuid_ossp_aot_items(label) VALUES ('first'), ('second');", - )) - .context("seed UUID-OSSP AOT dump source through psql")?; - let dump = source - .pg_dump(PgDumpOptions::new()) - .context("dump UUID-OSSP AOT source through pg_dump")?; - ensure!( - dump.contains("COPY public.uuid_ossp_aot_items"), - "UUID-OSSP AOT dump should retain PostgreSQL COPY output" - ); - source.close().context("close UUID-OSSP AOT dump source")?; - - let mut restored = Oliphaunt::builder() - .extension(Extension::UUID_OSSP) - .open() - .context("open UUID-OSSP AOT restore target")?; - restored - .psql(PsqlOptions::new().script(dump)) - .context("restore UUID-OSSP AOT dump through psql")?; - let result = restored.query( - "SELECT count(*)::int4 AS rows,\ - count(DISTINCT id)::int4 AS ids,\ - bool_and(length(id::text) = 36) AS valid_ids,\ - length(uuid_generate_v4()::text)::int4 AS generated_length \ - FROM uuid_ossp_aot_items", - )?; - ensure!(result.get_text(0, "rows")? == Some("2")); - ensure!(result.get_text(0, "ids")? == Some("2")); - ensure!(result.get_text(0, "valid_ids")? == Some("t")); - ensure!(result.get_text(0, "generated_length")? == Some("36")); - restored - .close() - .context("close UUID-OSSP AOT restore target")?; - Ok(()) - } - - fn embedded_extension_archives(extensions: &[Extension]) -> Result> { - let embedded: Vec<_> = extensions - .iter() - .copied() - .filter(|extension| { - crate::oliphaunt::assets::extension_archive(extension.sql_name()).is_some() - }) - .collect(); - let embedded_names: BTreeSet<_> = embedded - .iter() - .map(|extension| extension.sql_name()) - .collect(); - let missing: Vec<_> = extensions - .iter() - .map(|extension| extension.sql_name()) - .filter(|name| !embedded_names.contains(name)) - .collect(); - ensure!( - missing.is_empty(), - "required WASIX extension archives are not embedded: {}", - missing.join(", ") - ); - Ok(embedded) - } - - fn run_direct_and_restart_smoke_set(extensions: &[Extension]) -> Result<()> { - let extensions = embedded_extension_archives(extensions)?; - let mut failures = Vec::new(); - for extension in extensions { - if let Err(error) = run_one_direct_and_restart_smoke(extension) { - failures.push(format!("{}: {error:?}", extension.sql_name())); - } - } - ensure!( - failures.is_empty(), - "extension direct/restart smoke failures:\n{}", - failures.join("\n\n") - ); - Ok(()) - } - - fn run_one_direct_and_restart_smoke(extension: Extension) -> Result<()> { - let name = extension.sql_name(); - { - let mut db = Oliphaunt::builder() - .extension(extension) - .open() - .with_context(|| format!("open temporary database with extension {name}"))?; - assert_extension_not_installed(&mut db, extension)?; - run_direct_smoke(&mut db, extension)?; - db.close() - .with_context(|| format!("close temporary database with extension {name}"))?; - } - - let root = tempfile::TempDir::new() - .with_context(|| format!("create restart root for extension {name}"))?; - { - let mut db = Oliphaunt::builder() - .storage(DatabaseStorage::Directory(root.path().to_path_buf())) - .extension(extension) - .open() - .with_context(|| { - format!("open persistent database with extension {name} before restart") - })?; - assert_extension_not_installed(&mut db, extension)?; - run_direct_smoke(&mut db, extension)?; - assert_extension_catalog_state(&mut db, extension)?; - db.close() - .with_context(|| format!("close persistent database with extension {name}"))?; - } - { - let mut db = Oliphaunt::builder() - .storage(DatabaseStorage::Directory(root.path().to_path_buf())) - .extension(extension) - .open() - .with_context(|| { - format!("reopen persistent database with extension {name} after restart") - })?; - assert_extension_catalog_state(&mut db, extension)?; - db.close() - .with_context(|| format!("close restarted database with extension {name}"))?; - } - Ok(()) - } - - async fn run_server_smoke_set(extensions: &[Extension]) -> Result<()> { - let extensions = embedded_extension_archives(extensions)?; - let mut failures = Vec::new(); - for extension in extensions { - if let Err(error) = run_one_server_smoke(extension).await { - failures.push(format!("{}: {error:?}", extension.sql_name())); - } - } - ensure!( - failures.is_empty(), - "extension server smoke failures:\n{}", - failures.join("\n\n") - ); - Ok(()) - } - - async fn run_one_server_smoke(extension: Extension) -> Result<()> { - let name = extension.sql_name(); - let server = AsyncOliphauntServer::builder() - .extension(extension) - .start() - .await - .with_context(|| format!("start server with extension {name}"))?; - let mut conn = PgConnection::connect(server.connection_string()) - .await - .with_context(|| format!("connect server with extension {name}"))?; - assert_server_extension_not_installed(&mut conn, extension).await?; - run_server_smoke(&mut conn, extension).await?; - drop(conn); - server - .close() - .await - .with_context(|| format!("shutdown server with extension {name}"))?; - Ok(()) - } - - fn run_lifecycle_materialization_set(extensions: &[Extension]) -> Result<()> { - let extensions = embedded_extension_archives(extensions)?; - let mut failures = Vec::new(); - for extension in extensions { - if let Err(error) = run_one_lifecycle_materialization(extension) { - failures.push(format!("{}: {error:?}", extension.sql_name())); - } - } - ensure!( - failures.is_empty(), - "extension lifecycle/materialization failures:\n{}", - failures.join("\n\n") - ); - Ok(()) - } - - fn run_one_lifecycle_materialization(extension: Extension) -> Result<()> { - let name = extension.sql_name(); - let root = tempfile::TempDir::new() - .with_context(|| format!("create lifecycle root for extension {name}"))?; - { - let mut db = Oliphaunt::builder() - .storage(DatabaseStorage::Directory(root.path().to_path_buf())) - .extension(extension) - .open() - .with_context(|| format!("open lifecycle database with extension {name}"))?; - let runtime_root = db - .runtime_storage() - .host_path() - .context("directory database should use a host runtime workspace")?; - assert_only_resolved_extension_libraries_are_materialized(runtime_root, extension)?; - db.close() - .with_context(|| format!("close lifecycle database with extension {name}"))?; - } - Ok(()) - } - - fn run_direct_smoke(db: &mut Oliphaunt, extension: Extension) -> Result<()> { - for statement in extension_activation_sql_for_test(extension)? { - let request = crate::oliphaunt::query::simple_query(statement)?; - db.exec_protocol_raw(request).with_context(|| { - format!( - "explicit activation failed for extension {} while running:\n{}", - extension.sql_name(), - statement - ) - })?; - } - let smoke_sql = extension_smoke_sql(extension.sql_name()); - for statement in extension_smoke_statements(&smoke_sql) { - let request = crate::oliphaunt::query::simple_query(statement)?; - db.exec_protocol_raw(request).with_context(|| { - format!( - "direct smoke failed for extension {} while running:\n{}", - extension.sql_name(), - statement - ) - })?; - } - Ok(()) - } - - async fn run_server_smoke(conn: &mut PgConnection, extension: Extension) -> Result<()> { - for statement in extension_activation_sql_for_test(extension)? { - sqlx::query(statement) - .execute(&mut *conn) - .await - .with_context(|| { - format!( - "explicit server activation failed for extension {} while running:\n{}", - extension.sql_name(), - statement - ) - })?; - } - let smoke_sql = extension_smoke_sql(extension.sql_name()); - for statement in extension_smoke_statements(&smoke_sql) { - sqlx::query(statement) - .fetch_all(&mut *conn) - .await - .with_context(|| { - format!( - "server smoke failed for extension {} while running:\n{}", - extension.sql_name(), - statement - ) - })?; - } - Ok(()) - } - - fn assert_extension_not_installed(db: &mut Oliphaunt, extension: Extension) -> Result<()> { - if !generated::creates_database_object_for_test(extension) { - return Ok(()); - } - let result = db.query_with_params( - "SELECT count(*)::int4 AS count FROM pg_extension WHERE extname = $1", - [extension.sql_name()], - )?; - ensure!( - result.get_text(0, "count")? == Some("0"), - "selecting extension {} must not install it in pg_extension", - extension.sql_name() - ); - Ok(()) - } - - async fn assert_server_extension_not_installed( - conn: &mut PgConnection, - extension: Extension, - ) -> Result<()> { - if !generated::creates_database_object_for_test(extension) { - return Ok(()); - } - let installed: i64 = - sqlx::query_scalar("SELECT count(*)::int8 FROM pg_extension WHERE extname = $1") - .bind(extension.sql_name()) - .fetch_one(&mut *conn) - .await?; - ensure!( - installed == 0, - "selecting server extension {} must not install it in pg_extension", - extension.sql_name() - ); - Ok(()) - } - - fn assert_extension_catalog_state(db: &mut Oliphaunt, extension: Extension) -> Result<()> { - if generated::creates_database_object_for_test(extension) { - let result = db.query_with_params( - "SELECT count(*)::int4 AS count FROM pg_extension WHERE extname = $1", - [extension.sql_name()], - )?; - ensure!( - result.get_text(0, "count")? == Some("1"), - "extension {} should survive restart in pg_extension", - extension.sql_name() - ); - } else { - let result = db.query("SELECT 1::int4 AS ok")?; - ensure!( - result.get_text(0, "ok")? == Some("1"), - "extension {} should reopen cleanly", - extension.sql_name() - ); - } - Ok(()) - } - - fn assert_only_resolved_extension_libraries_are_materialized( - runtime_root: &Path, - extension: Extension, - ) -> Result<()> { - let expected = resolve_extension_set(&[extension])? - .into_iter() - .flat_map(|extension| { - let mut modules = extension - .native_support_modules() - .iter() - .map(|module| { - PathBuf::from(module.runtime_path()) - .strip_prefix("lib/postgresql") - .map(PathBuf::from) - .unwrap_or_else(|_| PathBuf::from(module.runtime_path())) - }) - .collect::>(); - if let Some(module) = extension.native_module_file() { - modules.push(PathBuf::from(module)); - } - modules - }) - .collect::>(); - let actual = relative_files(&runtime_root.join("lib/postgresql")) - .into_iter() - .collect::>(); - ensure!( - actual == expected, - "upper runtime library layer for {} should contain only resolved requested libraries; expected {:?}, got {:?}", - extension.sql_name(), - expected, - actual - ); - Ok(()) - } - - fn relative_files(root: &Path) -> Vec { - fn walk(base: &Path, current: &Path, files: &mut Vec) { - let Ok(entries) = std::fs::read_dir(current) else { - return; - }; - for entry in entries { - let entry = entry.expect("read runtime test directory entry"); - let path = entry.path(); - if path.is_dir() { - walk(base, &path, files); - } else if path.is_file() { - files.push( - path.strip_prefix(base) - .expect("relative extension library path") - .to_path_buf(), - ); - } - } - } - - let mut files = Vec::new(); - walk(root, root, &mut files); - files.sort(); - files - } -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/lifecycle.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/lifecycle.rs deleted file mode 100644 index 9ad217bd9..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/lifecycle.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::mem::ManuallyDrop; -use std::ops::{Deref, DerefMut}; -use std::panic::{AssertUnwindSafe, catch_unwind}; - -use anyhow::Result; - -use crate::Error; - -pub(crate) type TerminalCloseResult = crate::Result<()>; - -/// Ownership which may only be released after teardown is known to have -/// succeeded. -/// -/// Dropping this wrapper deliberately does not run `T`'s destructor. This is -/// the conservative terminal-failure path: once destructive PostgreSQL -/// teardown has started and returned an error, running ordinary Rust -/// destructors could release a managed-root lock or partially destroy a WASIX -/// backend whose state is no longer known. [`Self::release`] is therefore the -/// only way to destroy the value, and callers invoke it only after successful -/// teardown. -#[derive(Debug)] -pub(crate) struct TeardownOwnership { - value: Option>, -} - -impl TeardownOwnership { - pub(crate) fn new(value: T) -> Self { - Self { - value: Some(ManuallyDrop::new(value)), - } - } - - /// Release this ownership exactly once after successful teardown. - pub(crate) fn release(&mut self) { - if let Some(value) = self.value.take() { - // `take` gives this call the sole remaining path to the value. - // Leaving `None` makes repeated release safe. - drop(ManuallyDrop::into_inner(value)); - } - } - - #[cfg(test)] - pub(crate) fn is_released(&self) -> bool { - self.value.is_none() - } -} - -impl Deref for TeardownOwnership { - type Target = T; - - fn deref(&self) -> &Self::Target { - self.value - .as_deref() - .expect("teardown ownership was already released") - } -} - -impl DerefMut for TeardownOwnership { - fn deref_mut(&mut self) -> &mut Self::Target { - self.value - .as_deref_mut() - .expect("teardown ownership was already released") - } -} - -/// Run a destructive close boundary once and retain its exact public outcome. -pub(crate) fn terminal_close( - outcome: &mut Option, - owner: &'static str, - close: impl FnOnce() -> Result<()>, -) -> TerminalCloseResult { - if let Some(outcome) = outcome { - return outcome.clone(); - } - let result = teardown_result(owner, close); - *outcome = Some(result.clone()); - result -} - -/// Contain teardown panics at the ownership boundary. A panic means teardown -/// began without proving completion, so callers quarantine ownership just as -/// they do for an ordinary returned error. -pub(crate) fn teardown_result( - owner: &'static str, - close: impl FnOnce() -> Result<()>, -) -> TerminalCloseResult { - match catch_unwind(AssertUnwindSafe(close)) { - Ok(result) => result.map_err(Error::from_anyhow), - Err(panic) => Err(Error::message(format!( - "{owner} panicked during teardown: {}", - panic_message(panic.as_ref()) - ))), - } -} - -fn panic_message(panic: &(dyn std::any::Any + Send)) -> &str { - panic - .downcast_ref::() - .map(String::as_str) - .or_else(|| panic.downcast_ref::<&'static str>().copied()) - .unwrap_or("unknown panic payload") -} - -#[cfg(test)] -mod tests { - use std::cell::Cell; - use std::rc::Rc; - - use super::*; - - #[test] - fn terminal_failure_is_executed_once_and_replayed_exactly() { - let calls = Cell::new(0); - let mut outcome = None; - - for _ in 0..2 { - let result = terminal_close(&mut outcome, "test owner", || { - calls.set(calls.get() + 1); - anyhow::bail!("injected teardown failure") - }); - assert_eq!( - result.expect_err("teardown fails").to_string(), - "injected teardown failure" - ); - } - assert_eq!(calls.get(), 1); - } - - #[test] - fn terminal_panic_is_contained_and_replayed_without_retry() { - let calls = Cell::new(0); - let mut outcome = None; - - for _ in 0..2 { - let error = terminal_close(&mut outcome, "test owner", || { - calls.set(calls.get() + 1); - panic!("injected teardown panic") - }) - .expect_err("teardown panic becomes a terminal error"); - assert_eq!( - error.to_string(), - "test owner panicked during teardown: injected teardown panic" - ); - } - assert_eq!(calls.get(), 1); - } - - #[test] - fn teardown_ownership_releases_only_on_explicit_success_path() { - struct DropProbe(Rc>); - - impl Drop for DropProbe { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } - } - - let successful_drops = Rc::new(Cell::new(0)); - { - let mut successful = TeardownOwnership::new(DropProbe(Rc::clone(&successful_drops))); - successful.release(); - successful.release(); - } - assert_eq!(successful_drops.get(), 1); - - let quarantined_drops = Rc::new(Cell::new(0)); - { - let _quarantined = TeardownOwnership::new(DropProbe(Rc::clone(&quarantined_drops))); - } - assert_eq!(quarantined_drops.get(), 0); - } -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/mod.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/mod.rs deleted file mode 100644 index aedd91bd3..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/mod.rs +++ /dev/null @@ -1,40 +0,0 @@ -pub(crate) mod aot; -pub(crate) mod assets; -pub(crate) mod backend; -pub(crate) mod base; -pub(crate) mod builder; -pub(crate) mod client; -pub(crate) mod config; -pub(crate) mod data_dir; -pub(crate) mod database_root_descriptor; -#[cfg(feature = "extensions")] -pub(crate) mod extensions; -pub(crate) mod lifecycle; -pub(crate) mod postgres_mod; -pub(crate) mod proxy; -pub(crate) mod query; -pub(crate) mod query_core { - include!(env!("OLIPHAUNT_QUERY_CORE_RS")); -} -pub(crate) mod server; -pub(crate) mod sql; -pub(crate) mod storage; -pub(crate) mod sync_host_fs; -#[cfg(test)] -pub(crate) mod test_fixtures; -#[cfg(feature = "tools")] -pub mod tools; -pub(crate) mod transport; -pub(crate) mod wire; - -#[cfg(any(feature = "__internal-napi", test))] -pub use assets::CatalogProfile; -pub use builder::OliphauntBuilder; -pub use client::{Oliphaunt, Sql, Transaction}; -pub use query::{ - CommandResult, DecodeError, ExecResult, FromSql, IntoParameter, Parameter, PostgresError, - PostgresErrorField, PostgresNotice, QueryField, QueryFormat, QueryResult, QueryRow, RowIndex, - StatementDescription, StatementResult, TypeOid, ValueFormat, ValueRef, -}; -pub use server::{OliphauntServer, OliphauntServerBuilder, ServerListen}; -pub use storage::DatabaseStorage; diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/query.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/query.rs deleted file mode 100644 index 18bc8b73e..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/query.rs +++ /dev/null @@ -1,937 +0,0 @@ -use std::str; -#[cfg(test)] -use std::sync::Arc; - -use anyhow::{Result, anyhow}; - -#[cfg(test)] -use anyhow::{Context, ensure}; - -use crate::oliphaunt::query_core; - -pub(crate) use crate::oliphaunt::query_core::ReadyStatus; -pub use crate::oliphaunt::query_core::{ - CommandResult, DecodeError, ExecResult, FromSql, IntoParameter, Parameter, PostgresError, - PostgresErrorField, PostgresNotice, QueryField, QueryFormat, QueryResult, QueryRow, RowIndex, - StatementDescription, StatementResult, TypeOid, ValueFormat, ValueRef, -}; - -pub(crate) fn simple_query(sql: &str) -> Result> { - query_core_result(query_core::simple_query(sql)) -} - -impl QueryResult { - /// Read a text-format value by row index and column name. - pub fn get_text(&self, row: usize, column: &str) -> crate::Result> { - crate::error::public_result(self.get_text_inner(row, column)) - } - - fn get_text_inner(&self, row: usize, column: &str) -> Result> { - let column = column.resolve(self.fields()).map_err(anyhow::Error::new)?; - let row = self - .row(row) - .ok_or_else(|| anyhow!("query result has no row at index {row}"))?; - row.text_inner(column) - } -} - -impl QueryRow { - /// Read a text-format value by column index. - pub fn text(&self, column: usize) -> crate::Result> { - crate::error::public_result(self.text_inner(column)) - } - - pub(crate) fn text_inner(&self, column: usize) -> Result> { - let value = self - .value(column) - .ok_or_else(|| anyhow!("query row has no column at index {column}"))?; - value - .as_deref() - .map(|bytes| str::from_utf8(bytes).map_err(anyhow::Error::from)) - .transpose() - } -} -fn query_core_result(result: query_core::Result) -> Result { - result.map_err(query_core_error) -} - -fn query_core_error(error: query_core::Error) -> anyhow::Error { - match error { - query_core::Error::Protocol(message) => anyhow!(message), - query_core::Error::Postgres { - diagnostic, - notices, - } => { - let mut error = PostgresError::from_core(*diagnostic); - error.notices = notices.into_iter().map(PostgresNotice::from_core).collect(); - anyhow::Error::new(error) - } - } -} - -#[cfg(test)] -pub(crate) fn parse_command_response(bytes: &[u8]) -> Result { - query_core_result(query_core::parse_command_response( - bytes, - query_core::ExpectedProtocol::Either, - )) -} - -pub(crate) fn parse_extended_command_response(bytes: &[u8]) -> Result { - query_core_result(query_core::parse_command_response( - bytes, - query_core::ExpectedProtocol::Extended, - )) -} - -pub(crate) fn parse_simple_command_response(bytes: &[u8]) -> Result { - query_core_result(query_core::parse_command_response( - bytes, - query_core::ExpectedProtocol::Simple, - )) -} - -#[cfg(test)] -pub(crate) fn parse_query_response(bytes: &[u8]) -> Result { - query_core_result(query_core::parse_query_response( - bytes, - query_core::ExpectedProtocol::Either, - )) -} - -pub(crate) fn parse_extended_query_response(bytes: &[u8]) -> Result { - query_core_result(query_core::parse_query_response( - bytes, - query_core::ExpectedProtocol::Extended, - )) -} - -pub(crate) fn parse_exec_response(bytes: &[u8]) -> Result { - query_core_result(query_core::parse_exec_response(bytes)) -} - -pub(crate) fn parse_statement_description(bytes: &[u8]) -> Result { - query_core_result(query_core::parse_statement_description(bytes)) -} - -pub(crate) fn extended_statement( - sql: &str, - params: &[Parameter], - result_format: ValueFormat, -) -> Result> { - query_core_result(query_core::extended_statement( - sql, - params, - result_format.code(), - )) -} - -pub(crate) fn describe_statement(sql: &str, params: &[Parameter]) -> Result> { - query_core_result(query_core::describe_statement(sql, params)) -} - -pub(crate) fn reject_copy_statements(sql: &str) -> Result<()> { - query_core_result(query_core::reject_copy_statements(sql)) -} - -pub(crate) fn reject_transaction_chain(sql: &str) -> Result<()> { - query_core_result(query_core::reject_transaction_chain(sql)) -} - -pub(crate) fn validate_managed_transaction_response(response: &[u8]) -> Result { - query_core_result(query_core::validate_managed_transaction_response(response)) -} - -pub(crate) fn response_ready_status(bytes: &[u8]) -> Result { - query_core_result(query_core::response_ready_status(bytes)) -} - -#[cfg(test)] -fn parse_postgres_error(body: &[u8]) -> Result { - let fields = query_core_result(query_core::parse_diagnostic_fields(body, "ErrorResponse"))?; - Ok(PostgresError::from_core(query_core::diagnostic( - fields, - "PostgreSQL ErrorResponse", - ))) -} - -#[cfg(test)] -fn parse_notice_response(body: &[u8]) -> Result { - let fields = query_core_result(query_core::parse_diagnostic_fields(body, "NoticeResponse"))?; - Ok(PostgresNotice::from_core(query_core::diagnostic( - fields, - "PostgreSQL NoticeResponse", - ))) -} - -#[cfg(test)] -fn read_u32(input: &mut &[u8], label: &str) -> Result { - Ok(u32::from_be_bytes( - take(input, 4, label)?.try_into().expect("four bytes"), - )) -} - -#[cfg(test)] -fn read_i32(input: &mut &[u8], label: &str) -> Result { - Ok(i32::from_be_bytes( - take(input, 4, label)?.try_into().expect("four bytes"), - )) -} - -#[cfg(test)] -fn read_i16(input: &mut &[u8], label: &str) -> Result { - Ok(i16::from_be_bytes( - take(input, 2, label)?.try_into().expect("two bytes"), - )) -} - -#[cfg(test)] -fn read_cstring<'a>(input: &mut &'a [u8], label: &str) -> Result<&'a str> { - let nul = input - .iter() - .position(|byte| *byte == 0) - .with_context(|| format!("{label} is missing null terminator"))?; - let value = str::from_utf8(&input[..nul]).with_context(|| format!("{label} is not UTF-8"))?; - *input = &input[nul + 1..]; - Ok(value) -} - -#[cfg(test)] -fn take<'a>(input: &mut &'a [u8], length: usize, label: &str) -> Result<&'a [u8]> { - ensure!(input.len() >= length, "truncated {label}"); - let (head, tail) = input.split_at(length); - *input = tail; - Ok(head) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn simple_query_encodes_one_postgres_message() { - assert_eq!( - simple_query("SELECT 1").expect("valid simple query"), - b"Q\0\0\0\rSELECT 1\0".as_slice() - ); - } - - #[test] - fn simple_query_rejects_embedded_nul() { - assert_eq!( - simple_query("SELECT\0 1") - .expect_err("embedded NUL must be rejected") - .to_string(), - "simple query SQL must not contain NUL bytes" - ); - } - - #[test] - fn postgres_error_preserves_ordered_fields() { - let error = parse_postgres_error( - b"SERREUR\0VERROR\0C23505\0Mduplicate key\0DKey already exists\0titems\0p12\0qSELECT broken\0Fparse_expr.c\0L123\0RtransformExpr\0\0", - ) - .expect("valid ErrorResponse"); - - assert_eq!(error.severity.as_deref(), Some("ERREUR")); - assert_eq!(error.localized_severity.as_deref(), Some("ERREUR")); - assert_eq!(error.nonlocalized_severity.as_deref(), Some("ERROR")); - assert_eq!(error.sqlstate.as_deref(), Some("23505")); - assert_eq!(error.message, "duplicate key"); - assert_eq!(error.detail.as_deref(), Some("Key already exists")); - assert_eq!(error.table_name.as_deref(), Some("items")); - assert_eq!(error.internal_position.as_deref(), Some("12")); - assert_eq!(error.internal_query.as_deref(), Some("SELECT broken")); - assert_eq!(error.file.as_deref(), Some("parse_expr.c")); - assert_eq!(error.line.as_deref(), Some("123")); - assert_eq!(error.routine.as_deref(), Some("transformExpr")); - assert_eq!( - error - .fields - .iter() - .map(|field| field.code) - .collect::>(), - [ - b'S', b'V', b'C', b'M', b'D', b't', b'p', b'q', b'F', b'L', b'R' - ] - ); - assert_eq!(error.to_string(), "ERREUR [23505]: duplicate key"); - } - - #[test] - fn postgres_notice_exposes_finite_standard_diagnostic_fields() { - let notice = parse_notice_response( - b"SAVERTISSEMENT\0VWARNING\0Mcheck value\0p12\0qSELECT broken\0Fparse_expr.c\0L123\0RtransformExpr\0\0", - ) - .expect("valid NoticeResponse"); - - assert_eq!(notice.severity.as_deref(), Some("AVERTISSEMENT")); - assert_eq!(notice.localized_severity.as_deref(), Some("AVERTISSEMENT")); - assert_eq!(notice.nonlocalized_severity.as_deref(), Some("WARNING")); - assert_eq!(notice.internal_position.as_deref(), Some("12")); - assert_eq!(notice.internal_query.as_deref(), Some("SELECT broken")); - assert_eq!(notice.file.as_deref(), Some("parse_expr.c")); - assert_eq!(notice.line.as_deref(), Some("123")); - assert_eq!(notice.routine.as_deref(), Some("transformExpr")); - assert_eq!( - notice - .fields - .iter() - .map(|field| field.code) - .collect::>(), - [b'S', b'V', b'M', b'p', b'q', b'F', b'L', b'R'] - ); - } - - #[test] - fn postgres_error_display_handles_partial_identity() { - let error = |severity: Option<&str>, sqlstate: Option<&str>| PostgresError { - severity: severity.map(str::to_owned), - localized_severity: severity.map(str::to_owned), - nonlocalized_severity: None, - sqlstate: sqlstate.map(str::to_owned), - message: "failed".to_owned(), - detail: None, - hint: None, - position: None, - internal_position: None, - internal_query: None, - where_: None, - schema_name: None, - table_name: None, - column_name: None, - data_type_name: None, - constraint_name: None, - file: None, - line: None, - routine: None, - fields: Vec::new(), - notices: Vec::new(), - }; - - assert_eq!(error(Some("ERROR"), None).to_string(), "ERROR: failed"); - assert_eq!(error(None, Some("XX000")).to_string(), "[XX000]: failed"); - assert_eq!(error(None, None).to_string(), "failed"); - } - - #[test] - fn parameter_conversions_feed_the_extended_protocol() { - let owned = "owned".to_owned(); - let params = vec![ - Parameter::text("text"), - Parameter::binary([1_u8, 2]), - "borrowed".into_parameter(), - owned.clone().into_parameter(), - (&owned).into_parameter(), - 1_i16.into_parameter(), - 2_i32.into_parameter(), - 3_i64.into_parameter(), - 4.5_f32.into_parameter(), - 6.25_f64.into_parameter(), - true.into_parameter(), - (&[7_u8, 8][..]).into_parameter(), - vec![9_u8].into_parameter(), - Some("optional").into_parameter(), - None::<&str>.into_parameter(), - ]; - - let packet = extended_statement("SELECT $1", ¶ms, ValueFormat::Text) - .expect("valid extended query"); - assert_eq!(packet.first(), Some(&b'P')); - assert!(packet.contains(&b'B')); - assert!(extended_statement("SELECT\0$1", &[], ValueFormat::Text).is_err()); - let too_many = vec![Parameter::null(); i16::MAX as usize + 1]; - assert!(extended_statement("SELECT 1", &too_many, ValueFormat::Text).is_err()); - } - - #[test] - fn typed_parameters_encode_oids_formats_nulls_and_result_format() { - let params = [ - Parameter::typed_null(TypeOid::INT4), - 7_i32.into_parameter(), - Parameter::text("hello"), - ]; - let packet = extended_statement("SELECT $1, $2, $3", ¶ms, ValueFormat::Binary) - .expect("valid typed statement"); - let messages = frontend_messages(&packet); - assert_eq!( - messages.iter().map(|(tag, _)| *tag).collect::>(), - [b'P', b'B', b'D', b'E', b'S'] - ); - - let mut parse = messages[0].1; - assert_eq!(read_cstring(&mut parse, "statement").unwrap(), ""); - assert_eq!( - read_cstring(&mut parse, "SQL").unwrap(), - "SELECT $1, $2, $3" - ); - assert_eq!(read_i16(&mut parse, "OID count").unwrap(), 3); - assert_eq!(read_u32(&mut parse, "OID").unwrap(), TypeOid::INT4.get()); - assert_eq!(read_u32(&mut parse, "OID").unwrap(), TypeOid::INT4.get()); - assert_eq!(read_u32(&mut parse, "OID").unwrap(), 0); - assert!(parse.is_empty()); - - let mut bind = messages[1].1; - assert_eq!(read_cstring(&mut bind, "portal").unwrap(), ""); - assert_eq!(read_cstring(&mut bind, "statement").unwrap(), ""); - assert_eq!(read_i16(&mut bind, "format count").unwrap(), 3); - assert_eq!(read_i16(&mut bind, "format").unwrap(), 0); - assert_eq!(read_i16(&mut bind, "format").unwrap(), 1); - assert_eq!(read_i16(&mut bind, "format").unwrap(), 0); - assert_eq!(read_i16(&mut bind, "value count").unwrap(), 3); - assert_eq!(read_i32(&mut bind, "null length").unwrap(), -1); - assert_eq!(read_i32(&mut bind, "int length").unwrap(), 4); - assert_eq!(take(&mut bind, 4, "int").unwrap(), &7_i32.to_be_bytes()); - assert_eq!(read_i32(&mut bind, "text length").unwrap(), 5); - assert_eq!(take(&mut bind, 5, "text").unwrap(), b"hello"); - assert_eq!(read_i16(&mut bind, "result format count").unwrap(), 1); - assert_eq!(read_i16(&mut bind, "result format").unwrap(), 1); - assert!(bind.is_empty()); - } - - #[test] - fn explicit_oid_zero_is_describe_only() { - let parameter = Parameter::typed_text(TypeOid::new(0), "infer me"); - let error = extended_statement( - "SELECT $1", - std::slice::from_ref(¶meter), - ValueFormat::Text, - ) - .expect_err("execution rejects explicit OID 0"); - assert!( - error - .to_string() - .contains("explicitly declares PostgreSQL type OID 0") - ); - - let packet = describe_statement("SELECT $1", &[parameter]) - .expect("describe permits OID 0 as PostgreSQL inference"); - let messages = frontend_messages(&packet); - let mut parse = messages[0].1; - assert_eq!(read_cstring(&mut parse, "statement").unwrap(), ""); - assert_eq!(read_cstring(&mut parse, "SQL").unwrap(), "SELECT $1"); - assert_eq!(read_i16(&mut parse, "OID count").unwrap(), 1); - assert_eq!(read_u32(&mut parse, "OID").unwrap(), 0); - } - - #[test] - fn query_result_accessors_report_postgres_shapes() { - let fields: Arc<[QueryField]> = vec![QueryField { - name: "value".to_owned(), - table_oid: 0, - table_attribute: 0, - type_oid: 25, - type_size: -1, - type_modifier: -1, - format: QueryFormat::Text, - }] - .into(); - let result = QueryResult { - fields: Arc::clone(&fields), - rows: vec![QueryRow { - fields, - values: vec![Some(b"ok".to_vec())], - }], - command_tag: Some("SELECT 1".to_owned()), - row_count: Some(1), - notices: Vec::new(), - ready_status: ReadyStatus::Idle, - }; - - assert_eq!(result.get_text(0, "value").expect("text value"), Some("ok")); - assert!(result.get_text(0, "missing").is_err()); - assert!(result.get_text(1, "value").is_err()); - assert_eq!(result.rows()[0].values(), &[Some(b"ok".to_vec())]); - assert_eq!(result.rows()[0].text(0).expect("row text"), Some("ok")); - assert!(result.rows()[0].text(1).is_err()); - assert!( - QueryRow { - fields: Arc::from([]), - values: vec![Some(vec![0xff])], - } - .text(0) - .is_err() - ); - assert_eq!(QueryFormat::from(0), QueryFormat::Text); - assert_eq!(QueryFormat::from(1), QueryFormat::Binary); - assert_eq!(QueryFormat::from(7), QueryFormat::Other(7)); - } - - #[test] - fn typed_rows_validate_oids_nulls_and_duplicate_names() { - let fields: Arc<[QueryField]> = vec![ - test_field("same", TypeOid::INT4, QueryFormat::Text), - test_field("same", TypeOid::TEXT, QueryFormat::Text), - test_field("bytes", TypeOid::BYTEA, QueryFormat::Binary), - test_field("nullable", TypeOid::INT4, QueryFormat::Text), - ] - .into(); - let row = QueryRow { - fields, - values: vec![ - Some(b"42".to_vec()), - Some(b"label".to_vec()), - Some(vec![0, 255]), - None, - ], - }; - assert_eq!(row.try_get::(0).unwrap(), 42); - assert_eq!(row.try_get::(1).unwrap(), "label"); - assert_eq!(row.try_get::<&[u8], _>("bytes").unwrap(), &[0, 255]); - assert_eq!(row.try_get::, _>("nullable").unwrap(), None); - assert!(matches!( - row.try_get::, _>("nullable"), - Err(DecodeError::TypeMismatch { type_oid, .. }) if type_oid == TypeOid::INT4 - )); - assert!(matches!( - row.try_get::("same"), - Err(DecodeError::AmbiguousColumn(name)) if name == "same" - )); - - let result = QueryResult { - fields: Arc::clone(&row.fields), - rows: vec![row], - command_tag: Some("SELECT 1".to_owned()), - row_count: Some(1), - notices: Vec::new(), - ready_status: ReadyStatus::Idle, - }; - assert!( - result - .get_text(0, "same") - .expect_err("text lookup must reject duplicate names") - .to_string() - .contains("more than one column") - ); - } - - #[test] - fn error_parser_drains_ready_and_attaches_notices() { - let mut response = backend_message(b'N', b"SNOTICE\0Mbefore failure\0\0"); - response.extend(backend_message(b'E', b"SERROR\0C23505\0Mduplicate\0\0")); - response.extend(backend_message(b'Z', b"I")); - let error = parse_command_response(&response).unwrap_err(); - let postgres = error - .downcast_ref::() - .expect("PostgreSQL error"); - assert_eq!(postgres.sqlstate.as_deref(), Some("23505")); - assert_eq!(postgres.notices[0].message, "before failure"); - - let missing_ready = backend_message(b'E', b"SERROR\0C42601\0Msyntax\0\0"); - assert!( - parse_command_response(&missing_ready) - .unwrap_err() - .to_string() - .contains("before ReadyForQuery") - ); - } - - #[test] - fn exec_preserves_ordered_command_and_row_results() { - let mut response = backend_message(b'N', b"SNOTICE\0Minserted\0\0"); - response.extend(backend_message(b'C', b"INSERT 0 1\0")); - response.extend(backend_message(b'N', b"SNOTICE\0Mselected\0\0")); - response.extend(backend_message( - b'T', - &row_description_body(&[("answer", TypeOid::INT4)]), - )); - let mut row = 1_i16.to_be_bytes().to_vec(); - row.extend_from_slice(&2_i32.to_be_bytes()); - row.extend_from_slice(b"42"); - response.extend(backend_message(b'D', &row)); - response.extend(backend_message(b'C', b"SELECT 1\0")); - response.extend(backend_message(b'Z', b"I")); - - let result = parse_exec_response(&response).expect("valid multi-statement response"); - assert_eq!(result.statements().len(), 2); - let StatementResult::Command(command) = &result.statements()[0] else { - panic!("INSERT result must remain a command"); - }; - assert_eq!(command.command_tag(), Some("INSERT 0 1")); - assert_eq!(command.row_count(), Some(1)); - assert_eq!(command.notices()[0].message, "inserted"); - match &result.statements()[1] { - StatementResult::Rows(query) => { - assert_eq!(query.command_tag(), Some("SELECT 1")); - assert_eq!(query.rows()[0].try_get::("answer").unwrap(), 42); - assert_eq!(query.notices()[0].message, "selected"); - } - StatementResult::Command(_) => panic!("SELECT result must retain its rows"), - } - assert_eq!(result.notices()[0].message, "inserted"); - assert_eq!(result.notices()[1].message, "selected"); - } - - #[test] - fn extended_query_accepts_command_only_statement_as_empty_rows() { - let mut response = backend_message(b'1', b""); - response.extend(backend_message(b'2', b"")); - response.extend(backend_message(b'n', b"")); - response.extend(backend_message(b'C', b"UPDATE 2\0")); - response.extend(backend_message(b'Z', b"I")); - - let result = - parse_extended_query_response(&response).expect("command is a valid query result"); - assert!(result.fields().is_empty()); - assert!(result.rows().is_empty()); - assert_eq!(result.command_tag(), Some("UPDATE 2")); - assert_eq!(result.row_count(), Some(2)); - } - - #[test] - fn describe_returns_parameter_oids_fields_and_notices() { - let mut parameters = 2_i16.to_be_bytes().to_vec(); - parameters.extend_from_slice(&TypeOid::INT4.get().to_be_bytes()); - parameters.extend_from_slice(&TypeOid::TEXT.get().to_be_bytes()); - let mut response = backend_message(b'1', b""); - response.extend(backend_message(b't', ¶meters)); - response.extend(backend_message( - b'T', - &row_description_body(&[("answer", TypeOid::INT8)]), - )); - response.extend(backend_message(b'N', b"SNOTICE\0Mdescribed\0\0")); - response.extend(backend_message(b'Z', b"I")); - - let description = - parse_statement_description(&response).expect("valid statement description"); - assert_eq!( - description.parameter_types(), - &[TypeOid::INT4, TypeOid::TEXT] - ); - assert_eq!( - description.fields().expect("row description")[0].type_oid_value(), - TypeOid::INT8 - ); - assert_eq!(description.notices()[0].message, "described"); - } - - #[test] - fn single_statement_parsers_reject_duplicate_or_incomplete_completion() { - let mut duplicate = backend_message(b'C', b"UPDATE 1\0"); - duplicate.extend(backend_message(b'C', b"UPDATE 1\0")); - duplicate.extend(backend_message(b'Z', b"I")); - assert!( - parse_command_response(&duplicate) - .unwrap_err() - .to_string() - .contains("multiple CommandComplete") - ); - - let mut incomplete = Vec::new(); - let mut description = Vec::new(); - description.extend_from_slice(&1_i16.to_be_bytes()); - description.extend_from_slice(b"value\0"); - description.extend_from_slice(&0_u32.to_be_bytes()); - description.extend_from_slice(&0_i16.to_be_bytes()); - description.extend_from_slice(&TypeOid::INT4.get().to_be_bytes()); - description.extend_from_slice(&(-1_i16).to_be_bytes()); - description.extend_from_slice(&(-1_i32).to_be_bytes()); - description.extend_from_slice(&0_i16.to_be_bytes()); - incomplete.extend(backend_message(b'T', &description)); - incomplete.extend(backend_message(b'Z', b"I")); - assert!( - parse_query_response(&incomplete) - .unwrap_err() - .to_string() - .contains("before CommandComplete") - ); - } - - #[test] - fn single_statement_parsers_require_exactly_one_completion_mode() { - let ready_only = backend_message(b'Z', b"I"); - assert!( - parse_command_response(&ready_only) - .unwrap_err() - .to_string() - .contains("before CommandComplete or EmptyQueryResponse") - ); - assert!( - parse_query_response(&ready_only) - .unwrap_err() - .to_string() - .contains("before CommandComplete or EmptyQueryResponse") - ); - - let mut empty = backend_message(b'I', b""); - empty.extend(backend_message(b'Z', b"I")); - assert_eq!(parse_command_response(&empty).unwrap().command_tag(), None); - let query = parse_query_response(&empty).unwrap(); - assert_eq!(query.command_tag(), None); - assert!(query.fields().is_empty()); - assert!(query.rows().is_empty()); - - let mut command_then_empty = backend_message(b'C', b"UPDATE 1\0"); - command_then_empty.extend(backend_message(b'I', b"")); - command_then_empty.extend(backend_message(b'Z', b"I")); - assert!( - parse_query_response(&command_then_empty) - .unwrap_err() - .to_string() - .contains("EmptyQueryResponse after CommandComplete") - ); - - let mut empty_then_command = backend_message(b'I', b""); - empty_then_command.extend(backend_message(b'C', b"UPDATE 1\0")); - empty_then_command.extend(backend_message(b'Z', b"I")); - assert!( - parse_command_response(&empty_then_command) - .unwrap_err() - .to_string() - .contains("CommandComplete after EmptyQueryResponse") - ); - - let mut duplicate_empty = backend_message(b'I', b""); - duplicate_empty.extend(backend_message(b'I', b"")); - duplicate_empty.extend(backend_message(b'Z', b"I")); - assert!( - parse_query_response(&duplicate_empty) - .unwrap_err() - .to_string() - .contains("multiple EmptyQueryResponse") - ); - } - - #[test] - fn query_rejects_messages_after_completion_and_invalid_extended_order() { - let mut response = - backend_message(b'T', &row_description_body(&[("answer", TypeOid::INT4)])); - response.extend(backend_message(b'C', b"SELECT 0\0")); - let mut row = 1_i16.to_be_bytes().to_vec(); - row.extend_from_slice(&2_i32.to_be_bytes()); - row.extend_from_slice(b"42"); - response.extend(backend_message(b'D', &row)); - response.extend(backend_message(b'Z', b"I")); - assert!( - parse_query_response(&response) - .unwrap_err() - .to_string() - .contains("DataRow after statement completion") - ); - - let mut parse_after_completion = backend_message(b'C', b"UPDATE 1\0"); - parse_after_completion.extend(backend_message(b'1', b"")); - parse_after_completion.extend(backend_message(b'Z', b"I")); - assert!( - parse_query_response(&parse_after_completion) - .unwrap_err() - .to_string() - .contains("ParseComplete out of order") - ); - - let mut bind_before_parse = backend_message(b'2', b""); - bind_before_parse.extend(backend_message(b'n', b"")); - bind_before_parse.extend(backend_message(b'C', b"UPDATE 1\0")); - bind_before_parse.extend(backend_message(b'Z', b"I")); - assert!( - parse_query_response(&bind_before_parse) - .unwrap_err() - .to_string() - .contains("BindComplete out of order") - ); - - let mut error_after_command = backend_message(b'C', b"UPDATE 1\0"); - error_after_command.extend(backend_message(b'E', b"SERROR\0CXX000\0Mtoo late\0\0")); - error_after_command.extend(backend_message(b'Z', b"I")); - assert!( - parse_query_response(&error_after_command) - .unwrap_err() - .to_string() - .contains("ErrorResponse after statement completion") - ); - - let mut error_after_empty = backend_message(b'I', b""); - error_after_empty.extend(backend_message(b'E', b"SERROR\0CXX000\0Mtoo late\0\0")); - error_after_empty.extend(backend_message(b'Z', b"I")); - assert!( - parse_command_response(&error_after_empty) - .unwrap_err() - .to_string() - .contains("ErrorResponse after statement completion") - ); - - let mut close_complete = backend_message(b'3', b""); - close_complete.extend(backend_message(b'C', b"UPDATE 1\0")); - close_complete.extend(backend_message(b'Z', b"I")); - assert!( - parse_query_response(&close_complete) - .unwrap_err() - .to_string() - .contains("unexpected backend message tag 0x33") - ); - assert!( - parse_command_response(&close_complete) - .unwrap_err() - .to_string() - .contains("unexpected backend message tag 0x33") - ); - } - - #[test] - fn exec_accepts_but_omits_empty_statements_and_requires_a_completion() { - let mut response = backend_message(b'I', b""); - response.extend(backend_message(b'C', b"UPDATE 1\0")); - response.extend(backend_message(b'I', b"")); - response.extend(backend_message(b'Z', b"I")); - - let result = parse_exec_response(&response).unwrap(); - assert_eq!(result.statements().len(), 1); - assert!(matches!( - &result.statements()[0], - StatementResult::Command(command) if command.command_tag() == Some("UPDATE 1") - )); - - let mut empty = backend_message(b'I', b""); - empty.extend(backend_message(b'Z', b"I")); - assert!(parse_exec_response(&empty).unwrap().statements().is_empty()); - - assert!( - parse_exec_response(&backend_message(b'Z', b"I")) - .unwrap_err() - .to_string() - .contains("before CommandComplete or EmptyQueryResponse") - ); - - for tag in [b'1', b'2', b'3', b't', b'n'] { - let mut extended_control = backend_message(tag, b""); - extended_control.extend(backend_message(b'C', b"UPDATE 1\0")); - extended_control.extend(backend_message(b'Z', b"I")); - assert!( - parse_exec_response(&extended_control) - .unwrap_err() - .to_string() - .contains("unexpected backend message tag") - ); - } - } - - #[test] - fn describe_requires_parse_complete_and_protocol_order() { - assert!( - parse_statement_description(&backend_message(b'Z', b"I")) - .unwrap_err() - .to_string() - .contains("omitted ParseComplete") - ); - - let parameters = 0_i16.to_be_bytes(); - let mut parameter_before_parse = backend_message(b't', ¶meters); - parameter_before_parse.extend(backend_message(b'1', b"")); - parameter_before_parse.extend(backend_message(b'n', b"")); - parameter_before_parse.extend(backend_message(b'Z', b"I")); - assert!( - parse_statement_description(¶meter_before_parse) - .unwrap_err() - .to_string() - .contains("ParameterDescription out of order") - ); - - let mut duplicate_parse = backend_message(b'1', b""); - duplicate_parse.extend(backend_message(b'1', b"")); - duplicate_parse.extend(backend_message(b't', ¶meters)); - duplicate_parse.extend(backend_message(b'n', b"")); - duplicate_parse.extend(backend_message(b'Z', b"I")); - assert!( - parse_statement_description(&duplicate_parse) - .unwrap_err() - .to_string() - .contains("ParseComplete out of order") - ); - - let mut result_before_parameters = backend_message(b'1', b""); - result_before_parameters.extend(backend_message( - b'T', - &row_description_body(&[("answer", TypeOid::INT4)]), - )); - result_before_parameters.extend(backend_message(b't', ¶meters)); - result_before_parameters.extend(backend_message(b'Z', b"I")); - assert!( - parse_statement_description(&result_before_parameters) - .unwrap_err() - .to_string() - .contains("RowDescription out of order") - ); - - let mut error_after_result = backend_message(b'1', b""); - error_after_result.extend(backend_message(b't', ¶meters)); - error_after_result.extend(backend_message(b'n', b"")); - error_after_result.extend(backend_message(b'E', b"SERROR\0CXX000\0Mtoo late\0\0")); - error_after_result.extend(backend_message(b'Z', b"I")); - assert!( - parse_statement_description(&error_after_result) - .unwrap_err() - .to_string() - .contains("ErrorResponse after result description") - ); - } - - #[test] - fn structured_sql_preflight_matches_shared_corpus() { - let source = crate::oliphaunt::test_fixtures::text("protocol/structured-sql-cases.json"); - let fixture: serde_json::Value = serde_json::from_str(&source).unwrap(); - assert_eq!(fixture["schemaVersion"], 2); - for case in fixture["cases"].as_array().unwrap() { - let name = case["name"].as_str().unwrap(); - let sql = case["sql"].as_str().unwrap(); - let expected = case["containsTopLevelCopy"].as_bool().unwrap(); - assert_eq!(reject_copy_statements(sql).is_err(), expected, "{name}"); - let expected = case["containsTransactionChain"].as_bool().unwrap(); - assert_eq!(reject_transaction_chain(sql).is_err(), expected, "{name}"); - } - } - - #[test] - fn describe_allows_copy_because_it_does_not_execute() { - describe_statement("COPY public.items TO STDOUT", &[]) - .expect("Parse + Describe + Sync cannot enter COPY mode"); - } - - fn test_field(name: &str, type_oid: TypeOid, format: QueryFormat) -> QueryField { - QueryField { - name: name.to_owned(), - table_oid: 0, - table_attribute: 0, - type_oid: type_oid.get(), - type_size: -1, - type_modifier: -1, - format, - } - } - - fn row_description_body(fields: &[(&str, TypeOid)]) -> Vec { - let mut body = (fields.len() as i16).to_be_bytes().to_vec(); - for (name, type_oid) in fields { - body.extend_from_slice(name.as_bytes()); - body.push(0); - body.extend_from_slice(&0_u32.to_be_bytes()); - body.extend_from_slice(&0_i16.to_be_bytes()); - body.extend_from_slice(&type_oid.get().to_be_bytes()); - body.extend_from_slice(&(-1_i16).to_be_bytes()); - body.extend_from_slice(&(-1_i32).to_be_bytes()); - body.extend_from_slice(&0_i16.to_be_bytes()); - } - body - } - - fn frontend_messages(mut packet: &[u8]) -> Vec<(u8, &[u8])> { - let mut messages = Vec::new(); - while !packet.is_empty() { - let tag = packet[0]; - let length = i32::from_be_bytes(packet[1..5].try_into().unwrap()) as usize; - messages.push((tag, &packet[5..length + 1])); - packet = &packet[length + 1..]; - } - messages - } - - fn backend_message(tag: u8, body: &[u8]) -> Vec { - let mut message = Vec::new(); - message.push(tag); - message.extend_from_slice(&((body.len() + 4) as i32).to_be_bytes()); - message.extend_from_slice(body); - message - } -} - -#[cfg(test)] -mod query_fixture_tests; diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/server.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/server.rs deleted file mode 100644 index 94aff0bee..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/server.rs +++ /dev/null @@ -1,1170 +0,0 @@ -use std::cell::Cell; -use std::marker::PhantomData; -use std::net::{SocketAddr, TcpListener, TcpStream}; -#[cfg(unix)] -use std::os::unix::ffi::OsStrExt; -#[cfg(unix)] -use std::os::unix::fs::{FileTypeExt, MetadataExt}; -#[cfg(unix)] -use std::os::unix::net::{UnixListener, UnixStream}; -use std::path::{Path, PathBuf}; -use std::sync::{ - Arc, - atomic::{AtomicBool, Ordering}, - mpsc::{Receiver, sync_channel}, -}; -use std::thread::{self, JoinHandle}; - -use anyhow::{Context, Result, anyhow}; -use tempfile::TempDir; - -use crate::oliphaunt::assets::{CatalogProfile, default_catalog_profile}; -use crate::oliphaunt::base::{DatabasePlan, DirectoryLock, PreparedDatabase, prepare_database}; -use crate::oliphaunt::config::{PostgresConfig, StartupConfig}; -#[cfg(feature = "extensions")] -use crate::oliphaunt::extensions::{ - Extension, postgres_config_with_extension_startup, resolve_extension_set, -}; -use crate::oliphaunt::lifecycle::{TeardownOwnership, TerminalCloseResult, teardown_result}; -use crate::oliphaunt::proxy::{ActiveConnection, OliphauntProxy}; -use crate::oliphaunt::storage::DatabaseStorage; -#[cfg(unix)] -use crate::oliphaunt::storage::validate_host_path; - -/// A supervised local PostgreSQL socket backed by one embedded Oliphaunt runtime. -/// -/// Use this entry point for code that expects a PostgreSQL URI, such as -/// `tokio-postgres`, SQLx, or tools that speak the wire protocol. The -/// server owns one embedded backend, so downstream pools should use a single -/// connection. -#[derive(Debug)] -pub struct OliphauntServer { - // The listener is owned and stopped by one blocking caller. Moving that - // ownership to another thread is safe; sharing references concurrently is - // deliberately unsupported. AsyncOliphauntServer provides a Sync handle. - _not_sync: PhantomData>, - _workspace: TeardownOwnership>, - _directory_lock: TeardownOwnership>, - endpoint: ServerEndpoint, - connection_string: String, - shutdown: Arc, - active_connection: Arc, - handle: Option>>, - close_result: Option, - #[cfg(all(test, feature = "icu"))] - catalog_profile: CatalogProfile, - #[cfg(all(test, feature = "icu"))] - runtime_root: PathBuf, - #[cfg(unix)] - owned_unix_socket: Option, -} - -#[derive(Debug, Clone)] -enum ServerEndpoint { - Tcp(SocketAddr), - #[cfg(unix)] - Unix(UnixSocketEndpoint), -} - -#[cfg(unix)] -#[derive(Debug, Clone)] -struct UnixSocketEndpoint { - path: PathBuf, - port: u16, -} - -#[cfg(unix)] -#[derive(Debug)] -struct OwnedUnixSocket { - path: PathBuf, - identity: Option<(u64, u64)>, -} - -impl OliphauntServer { - /// Build a local Oliphaunt server. The default is an in-memory database - /// served on IPv4 loopback with an automatically assigned port. - pub fn builder() -> OliphauntServerBuilder { - OliphauntServerBuilder::new() - } - - /// Return a PostgreSQL connection URI for the local server. - pub fn connection_string(&self) -> &str { - &self.connection_string - } - - /// Whether this direct server is permanently retired. - /// - /// The value becomes true when shutdown begins, including when terminal - /// cleanup later reports an error. Repeated [`Self::close`] calls replay - /// that first terminal result. - /// - /// This is lifecycle state, not a health check. `false` does not poll the - /// proxy listener or prove that the published endpoint is reachable. - pub fn is_closed(&self) -> bool { - self.shutdown.load(Ordering::SeqCst) || self.close_result.is_some() - } - - /// Request shutdown and wait for the listener thread to exit. - /// - /// Any active client connection is closed before the listener thread is - /// joined. Once stop begins, the server is terminal even when cleanup - /// reports an error. Successful teardown releases managed-root ownership; - /// failed teardown retains it until process exit. - pub fn close(&mut self) -> crate::Result<()> { - self.owner_close() - } - - /// Terminal close boundary used by the asynchronous owner thread. - /// - /// Once stop begins, later calls replay its exact success or failure. - pub(crate) fn owner_close(&mut self) -> crate::Result<()> { - if let Some(result) = &self.close_result { - return result.clone(); - } - let result = teardown_result("WASIX server", || self.stop()); - self.close_result = Some(result.clone()); - result - } - - fn stop(&mut self) -> Result<()> { - self.shutdown.store(true, Ordering::SeqCst); - self.active_connection.shutdown(); - { - wake_listener(&self.endpoint); - } - let worker_result = if let Some(handle) = self.handle.take() { - match handle.join() { - Ok(result) => result, - Err(_) => Err(anyhow!("oliphaunt server thread panicked")), - } - } else { - Ok(()) - }; - #[cfg(unix)] - let socket_result = if let Some(mut socket) = self.owned_unix_socket.take() { - socket.cleanup() - } else { - Ok(()) - }; - #[cfg(not(unix))] - let socket_result = Ok::<(), anyhow::Error>(()); - - let result = match (worker_result, socket_result) { - (Ok(()), Ok(())) => Ok(()), - (Err(error), Ok(())) | (Ok(()), Err(error)) => Err(error), - (Err(worker), Err(socket)) => Err(anyhow!( - "Oliphaunt server worker failed: {worker:#}; Unix socket cleanup also failed: {socket:#}" - )), - }; - if result.is_ok() { - // Keep the managed-root lock until every other owned resource has - // been destroyed. `owner_close` contains a destructor panic and - // caches it as a terminal failure without a second cleanup. - self._workspace.release(); - self._directory_lock.release(); - } - result - } -} - -impl Drop for OliphauntServer { - fn drop(&mut self) { - if self.close_result.is_none() - && let Err(err) = self.owner_close() - { - tracing::warn!("oliphaunt server shutdown during drop failed: {err:#}"); - } - } -} - -#[cfg(test)] -pub(crate) fn server_with_worker_result_for_test( - result: Result<()>, - directory_lock: Option, -) -> OliphauntServer { - OliphauntServer { - _not_sync: PhantomData, - _workspace: TeardownOwnership::new(None), - _directory_lock: TeardownOwnership::new(directory_lock), - endpoint: ServerEndpoint::Tcp(SocketAddr::from(([127, 0, 0, 1], 0))), - connection_string: tcp_connection_string( - SocketAddr::from(([127, 0, 0, 1], 0)), - &StartupConfig::default(), - ), - shutdown: Arc::new(AtomicBool::new(false)), - active_connection: Arc::new(ActiveConnection::default()), - handle: Some(thread::spawn(move || result)), - close_result: None, - #[cfg(feature = "icu")] - catalog_profile: CatalogProfile::default(), - #[cfg(feature = "icu")] - runtime_root: PathBuf::new(), - #[cfg(unix)] - owned_unix_socket: None, - } -} - -/// Builder for [`OliphauntServer`]. -#[derive(Debug, Clone)] -pub struct OliphauntServerBuilder { - storage: DatabaseStorage, - catalog_profile: CatalogProfile, - listen: ServerListen, - postgres_config: PostgresConfig, - startup_config: StartupConfig, - #[cfg(feature = "extensions")] - extensions: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ServerListen { - /// Listen on IPv4 loopback on any supported host. An omitted port asks the - /// operating system for one. - Tcp { port: Option }, - #[cfg(unix)] - /// Listen on a Unix host in a directory using PostgreSQL's - /// `.s.PGSQL.` filename. The directory path must be nonempty and - /// valid UTF-8, and contain no NUL bytes. UTF-8 keeps the published - /// connection string lossless across Rust drivers and ORMs. - Unix { directory: PathBuf, port: u16 }, -} - -impl ServerListen { - /// Listen on IPv4 loopback on any supported host and let the operating - /// system choose the port. - pub const fn tcp() -> Self { - Self::Tcp { port: None } - } - - /// Listen on IPv4 loopback on any supported host at an explicit port. - pub const fn tcp_port(port: u16) -> Self { - Self::Tcp { port: Some(port) } - } - - /// Listen on a Unix host in a UTF-8 Unix-domain socket directory using - /// PostgreSQL port 5432. - #[cfg(unix)] - pub fn unix(directory: impl Into) -> Self { - Self::Unix { - directory: directory.into(), - port: 5432, - } - } - - /// Listen on a Unix host in a UTF-8 Unix-domain socket directory using an - /// explicit PostgreSQL port. - #[cfg(unix)] - pub fn unix_port(directory: impl Into, port: u16) -> Self { - Self::Unix { - directory: directory.into(), - port, - } - } -} - -impl Default for ServerListen { - fn default() -> Self { - Self::tcp() - } -} - -impl Default for OliphauntServerBuilder { - fn default() -> Self { - Self { - storage: DatabaseStorage::Memory, - catalog_profile: default_catalog_profile(), - listen: ServerListen::tcp(), - postgres_config: PostgresConfig::default(), - startup_config: StartupConfig::default(), - #[cfg(feature = "extensions")] - extensions: Vec::new(), - } - } -} - -impl OliphauntServerBuilder { - /// Create a builder. Defaults to a memory database on IPv4 loopback with - /// an automatically assigned port. - pub fn new() -> Self { - Self::default() - } - - /// Select where PostgreSQL stores its mutable database files. - pub fn storage(mut self, storage: DatabaseStorage) -> Self { - self.storage = storage; - self - } - - /// Select the packaged standard or ICU catalog and matching runtime data. - #[cfg(any(feature = "__internal-napi", test))] - #[doc(hidden)] - pub fn catalog_profile(mut self, profile: CatalogProfile) -> Self { - self.catalog_profile = profile; - self - } - - /// Select a loopback TCP listener on any supported host or a PostgreSQL - /// Unix-domain listener on a Unix host. - pub fn listen(mut self, listen: ServerListen) -> Self { - self.listen = listen; - self - } - - /// Set a PostgreSQL startup GUC for the embedded backend used by this - /// server. - pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self { - self.postgres_config.insert(name, value); - self - } - - /// Set multiple PostgreSQL startup GUCs for the embedded backend used by - /// this server. - pub fn startup_gucs(mut self, settings: impl IntoIterator) -> Self - where - K: Into, - V: Into, - { - for (name, value) in settings { - self.postgres_config.insert(name, value); - } - self - } - - /// Default user encoded in [`OliphauntServer::connection_string`]. - pub fn username(mut self, username: impl Into) -> Self { - self.startup_config.username = username.into(); - self - } - - /// Default database encoded in [`OliphauntServer::connection_string`]. - pub fn database(mut self, database: impl Into) -> Self { - self.startup_config.database = database.into(); - self - } - - /// Make one bundled PostgreSQL extension artifact available to clients. - /// Database-local installation remains the application's migration concern. - #[cfg(feature = "extensions")] - pub fn extension(mut self, extension: Extension) -> Self { - self.extensions.push(extension); - self - } - - /// Make bundled PostgreSQL extension artifacts available to clients. - /// Database-local installation remains the application's migration concern. - #[cfg(feature = "extensions")] - pub fn extensions(mut self, extensions: impl IntoIterator) -> Self { - self.extensions.extend(extensions); - self - } - - /// Install the runtime if needed, initialize the cluster, and start serving. - pub fn start(self) -> crate::Result { - crate::error::public_result(self.start_inner()) - } - - fn start_inner(self) -> Result { - if matches!(self.listen, ServerListen::Tcp { port: Some(0) }) { - return Err(crate::error::invalid_configuration( - "TCP port must be in the range 1..=65535; omit it to allocate one", - )); - } - #[cfg(unix)] - let unix_endpoint = match &self.listen { - ServerListen::Unix { directory, port } => { - Some(resolve_unix_socket_endpoint(directory, *port)?) - } - ServerListen::Tcp { .. } => None, - }; - - #[cfg(feature = "extensions")] - let (extensions, postgres_config) = self.resolved_extension_startup()?; - #[cfg(not(feature = "extensions"))] - let postgres_config = self.postgres_config.clone(); - postgres_config.validate()?; - self.storage.validate()?; - self.startup_config.validate()?; - let startup_config = self.startup_config.clone(); - - let prepared_database = { - let plan = DatabasePlan::new(self.storage.clone(), self.catalog_profile); - prepare_database(plan, &startup_config.username)? - }; - let PreparedDatabase { - workspace, - directory_lock, - outcome, - } = prepared_database; - #[cfg(all(test, feature = "icu"))] - let catalog_profile = outcome.runtime_layout.catalog_profile; - #[cfg(all(test, feature = "icu"))] - let runtime_root = outcome.runtime_layout.module_root.clone(); - - let shutdown = Arc::new(AtomicBool::new(false)); - let active_connection = Arc::new(ActiveConnection::default()); - let proxy = { OliphauntProxy::from_prepared_database(outcome) }; - let proxy = proxy - .with_postgres_config(postgres_config) - .with_startup_config(startup_config.clone()); - #[cfg(feature = "extensions")] - let proxy = proxy.with_extensions(extensions); - - #[cfg(unix)] - let (endpoint, handle, owned_unix_socket) = match self.listen { - ServerListen::Tcp { port } => { - let addr = SocketAddr::from(([127, 0, 0, 1], port.unwrap_or(0))); - let (endpoint, handle) = - start_tcp(proxy, addr, shutdown.clone(), active_connection.clone())?; - (endpoint, handle, None) - } - ServerListen::Unix { .. } => { - let (endpoint, handle, socket) = start_unix( - proxy, - unix_endpoint.expect("Unix endpoint was resolved before database preparation"), - shutdown.clone(), - active_connection.clone(), - )?; - (endpoint, handle, Some(socket)) - } - }; - #[cfg(not(unix))] - let (endpoint, handle) = match self.listen { - ServerListen::Tcp { port } => { - let addr = SocketAddr::from(([127, 0, 0, 1], port.unwrap_or(0))); - start_tcp(proxy, addr, shutdown.clone(), active_connection.clone())? - } - }; - let connection_string = match &endpoint { - ServerEndpoint::Tcp(addr) => tcp_connection_string(*addr, &startup_config), - #[cfg(unix)] - ServerEndpoint::Unix(endpoint) => unix_connection_string(endpoint, &startup_config), - }; - - Ok(OliphauntServer { - _not_sync: PhantomData, - _workspace: TeardownOwnership::new(workspace), - _directory_lock: TeardownOwnership::new(directory_lock), - endpoint, - connection_string, - shutdown, - active_connection, - handle: Some(handle), - close_result: None, - #[cfg(all(test, feature = "icu"))] - catalog_profile, - #[cfg(all(test, feature = "icu"))] - runtime_root, - #[cfg(unix)] - owned_unix_socket, - }) - } - - #[cfg(feature = "extensions")] - fn resolved_extension_startup(&self) -> Result<(Vec, PostgresConfig)> { - let extensions = resolve_extension_set(&self.extensions)?; - let postgres_config = - postgres_config_with_extension_startup(self.postgres_config.clone(), &extensions)?; - Ok((extensions, postgres_config)) - } -} - -fn start_tcp( - proxy: OliphauntProxy, - addr: SocketAddr, - shutdown: Arc, - active_connection: Arc, -) -> Result<(ServerEndpoint, JoinHandle>)> { - let listener = TcpListener::bind(addr).context("bind Oliphaunt TCP server")?; - let addr = { - listener - .local_addr() - .context("read Oliphaunt TCP address")? - }; - let (ready_tx, ready_rx) = sync_channel(1); - let handle = thread::spawn(move || { - proxy.serve_tcp_listener_until_ready(listener, shutdown, active_connection, Some(ready_tx)) - }); - { - wait_until_ready(&ready_rx)?; - } - Ok((ServerEndpoint::Tcp(addr), handle)) -} - -fn tcp_connection_string(addr: SocketAddr, startup: &StartupConfig) -> String { - let username = percent_encode_uri_component(&startup.username); - let database = percent_encode_uri_component(&startup.database); - match addr { - SocketAddr::V4(addr) => { - format!( - "postgresql://{}@{}:{}/{}?sslmode=disable", - username, - addr.ip(), - addr.port(), - database - ) - } - SocketAddr::V6(addr) => { - format!( - "postgresql://{}@[{}]:{}/{}?sslmode=disable", - username, - addr.ip(), - addr.port(), - database - ) - } - } -} - -#[cfg(unix)] -fn unix_connection_string(endpoint: &UnixSocketEndpoint, startup: &StartupConfig) -> String { - let host = endpoint - .path - .parent() - .expect("resolved Unix socket path is absolute"); - let host = host - .to_str() - .expect("resolved Unix socket directory was validated as UTF-8"); - format!( - "postgresql:///{database}?host={host}&port={port}&user={user}&sslmode=disable", - database = percent_encode_uri_component(&startup.database), - host = percent_encode_uri_component(host), - port = endpoint.port, - user = percent_encode_uri_component(&startup.username), - ) -} - -#[cfg(unix)] -fn start_unix( - proxy: OliphauntProxy, - endpoint: UnixSocketEndpoint, - shutdown: Arc, - active_connection: Arc, -) -> Result<(ServerEndpoint, JoinHandle>, OwnedUnixSocket)> { - let path = endpoint.path.clone(); - prepare_unix_socket_directory(&path)?; - ensure_unix_socket_path_available(&path)?; - - let listener = { - UnixListener::bind(&path) - .with_context(|| format!("bind Oliphaunt Unix socket {}", path.display()))? - }; - let mut owned_socket = match OwnedUnixSocket::capture(&path) { - Ok(socket) => socket, - Err(error) => { - cleanup_new_unix_socket(&path); - return Err(error); - } - }; - let server_endpoint = ServerEndpoint::Unix(endpoint); - let (ready_tx, ready_rx) = sync_channel(1); - let worker_shutdown = shutdown.clone(); - let handle = thread::spawn(move || { - proxy.serve_unix_listener_until_ready( - listener, - worker_shutdown, - active_connection, - Some(ready_tx), - ) - }); - let ready_result = { wait_until_ready(&ready_rx) }; - if let Err(error) = ready_result { - shutdown.store(true, Ordering::SeqCst); - let _ = UnixStream::connect(&path); - let worker_result = handle - .join() - .map_err(|_| anyhow!("oliphaunt Unix server thread panicked during startup"))?; - owned_socket.cleanup()?; - worker_result?; - return Err(error); - } - Ok((server_endpoint, handle, owned_socket)) -} - -#[cfg(unix)] -impl OwnedUnixSocket { - fn capture(path: &Path) -> Result { - let metadata = std::fs::symlink_metadata(path) - .with_context(|| format!("inspect bound Unix socket {}", path.display()))?; - if !metadata.file_type().is_socket() { - return Err(anyhow!( - "bound Unix endpoint {} is not a socket", - path.display() - )); - } - Ok(Self { - path: path.to_path_buf(), - identity: Some((metadata.dev(), metadata.ino())), - }) - } - - fn cleanup(&mut self) -> Result<()> { - let Some(expected) = self.identity else { - return Ok(()); - }; - let metadata = match std::fs::symlink_metadata(&self.path) { - Ok(metadata) => metadata, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => { - self.identity = None; - return Ok(()); - } - Err(error) => { - return Err(error) - .with_context(|| format!("inspect owned Unix socket {}", self.path.display())); - } - }; - let actual = (metadata.dev(), metadata.ino()); - if !metadata.file_type().is_socket() || actual != expected { - self.identity = None; - return Err(anyhow!( - "refusing to remove replaced Unix endpoint {}", - self.path.display() - )); - } - std::fs::remove_file(&self.path) - .with_context(|| format!("remove owned Unix socket {}", self.path.display()))?; - self.identity = None; - Ok(()) - } -} - -#[cfg(unix)] -impl Drop for OwnedUnixSocket { - fn drop(&mut self) { - if let Err(error) = self.cleanup() { - tracing::warn!("Oliphaunt Unix socket cleanup during drop failed: {error:#}"); - } - } -} - -#[cfg(unix)] -fn cleanup_new_unix_socket(path: &Path) { - match std::fs::remove_file(path) { - Ok(()) => {} - Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} - Err(error) => tracing::warn!( - "Oliphaunt Unix socket cleanup after startup failure failed for {}: {error:#}", - path.display() - ), - } -} - -#[cfg(unix)] -fn ensure_unix_socket_path_available(path: &Path) -> Result<()> { - let metadata = match std::fs::symlink_metadata(path) { - Ok(metadata) => metadata, - Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(()), - Err(error) => { - return Err(error).with_context(|| format!("inspect Unix socket {}", path.display())); - } - }; - let kind = if metadata.file_type().is_socket() { - "socket" - } else { - "non-socket endpoint" - }; - Err(anyhow!( - "refusing to replace existing Unix {kind} {}; remove it explicitly if it is stale", - path.display() - )) -} - -#[cfg(unix)] -fn prepare_unix_socket_directory(path: &Path) -> Result<()> { - let parent = path.parent().ok_or_else(|| { - crate::error::invalid_configuration(format!( - "Unix socket path has no parent: {}", - path.display() - )) - })?; - std::fs::create_dir_all(parent) - .with_context(|| format!("create socket directory {}", parent.display()))?; - let metadata = std::fs::symlink_metadata(parent) - .with_context(|| format!("inspect socket directory {}", parent.display()))?; - if metadata.file_type().is_symlink() || !metadata.is_dir() { - return Err(crate::error::invalid_configuration(format!( - "Unix socket directory must be a real directory, not a symlink: {}", - parent.display() - ))); - } - if path.as_os_str().as_bytes().len() >= 100 { - return Err(crate::error::invalid_configuration(format!( - "Unix socket path is too long: {}", - path.display() - ))); - } - Ok(()) -} - -fn wait_until_ready(ready_rx: &Receiver>) -> Result<()> { - ready_rx - .recv() - .context("Oliphaunt server thread exited before reporting readiness")? -} - -fn wake_listener(endpoint: &ServerEndpoint) { - match endpoint { - ServerEndpoint::Tcp(addr) => { - let _ = TcpStream::connect(addr); - } - #[cfg(unix)] - ServerEndpoint::Unix(endpoint) => { - let _ = UnixStream::connect(&endpoint.path); - } - } -} - -#[cfg(unix)] -fn resolve_unix_socket_endpoint(directory: &Path, port: u16) -> Result { - let current_directory = if directory.is_absolute() { - None - } else { - Some( - std::env::current_dir() - .context("resolve current directory for Unix socket directory")?, - ) - }; - resolve_unix_socket_endpoint_at(directory, port, current_directory.as_deref()) -} - -#[cfg(unix)] -fn resolve_unix_socket_endpoint_at( - directory: &Path, - port: u16, - current_directory: Option<&Path>, -) -> Result { - validate_host_path("Unix socket directory", directory)?; - if port == 0 { - return Err(crate::error::invalid_configuration( - "Unix socket port must be in the range 1..=65535", - )); - } - let directory = if directory.is_absolute() { - directory.to_path_buf() - } else { - current_directory - .expect("relative Unix socket directory resolution provides a current directory") - .join(directory) - }; - if directory.to_str().is_none() { - return Err(crate::error::invalid_configuration( - "Unix socket directory must be valid UTF-8 so the published PostgreSQL connection string preserves the exact path", - )); - } - let path = directory.join(format!(".s.PGSQL.{port}")); - if path.as_os_str().as_bytes().len() >= 100 { - return Err(crate::error::invalid_configuration(format!( - "Unix socket path is too long: {}", - path.display() - ))); - } - Ok(UnixSocketEndpoint { path, port }) -} - -fn percent_encode_uri_component(value: &str) -> String { - percent_encode_bytes(value.as_bytes()) -} - -fn percent_encode_bytes(value: &[u8]) -> String { - const HEX: &[u8; 16] = b"0123456789ABCDEF"; - let mut encoded = String::with_capacity(value.len()); - for &byte in value { - if matches!( - byte, - b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'.' | b'_' | b'~' - ) { - encoded.push(byte as char); - } else { - encoded.push('%'); - encoded.push(HEX[usize::from(byte >> 4)] as char); - encoded.push(HEX[usize::from(byte & 0x0f)] as char); - } - } - encoded -} - -#[cfg(test)] -mod tests { - use super::*; - #[cfg(feature = "extension-pg-textsearch")] - use crate::oliphaunt::extensions::Extension; - - #[cfg(feature = "icu")] - fn both_catalog_profiles_are_packaged() -> bool { - crate::oliphaunt::assets::runtime_archive().is_some() - && [CatalogProfile::Standard, CatalogProfile::Icu] - .into_iter() - .all(|profile| { - crate::oliphaunt::assets::cluster_seed_archive(profile).is_some() - && crate::oliphaunt::assets::cluster_seed_manifest(profile).is_some() - }) - && crate::oliphaunt::assets::icu_data_archive(CatalogProfile::Icu).is_some() - } - - #[cfg(feature = "icu")] - fn assert_server_profile(server: &OliphauntServer, expected: CatalogProfile) { - assert_eq!(server.catalog_profile, expected); - assert_eq!( - server.runtime_root.join("share/icu").is_dir(), - expected == CatalogProfile::Icu - ); - } - - #[cfg(unix)] - #[test] - fn unix_socket_uri_host_is_query_encoded() { - assert_eq!( - percent_encode_bytes(b"/tmp/Application Support/oliphaunt"), - "%2Ftmp%2FApplication%20Support%2Foliphaunt" - ); - } - - #[test] - fn tcp_connection_string_encodes_username_and_database_components() { - let startup = StartupConfig { - username: "role@example:admin".to_string(), - database: "tenant/a?mode=#100%".to_string(), - }; - - assert_eq!( - tcp_connection_string(SocketAddr::from(([127, 0, 0, 1], 6543)), &startup), - "postgresql://role%40example%3Aadmin@127.0.0.1:6543/tenant%2Fa%3Fmode%3D%23100%25?sslmode=disable" - ); - } - - #[cfg(unix)] - #[test] - fn unix_connection_string_encodes_every_caller_controlled_component() { - use std::str::FromStr; - - let startup = StartupConfig { - username: "role name".to_string(), - database: "tenant/db#1".to_string(), - }; - - let endpoint = - resolve_unix_socket_endpoint(Path::new("/tmp/Application Support/db?slot"), 6543) - .unwrap(); - let connection_string = unix_connection_string(&endpoint, &startup); - assert_eq!( - connection_string, - "postgresql:///tenant%2Fdb%231?host=%2Ftmp%2FApplication%20Support%2Fdb%3Fslot&port=6543&user=role%20name&sslmode=disable" - ); - - let options = sqlx::postgres::PgConnectOptions::from_str(&connection_string) - .expect("the published URI must retain its exact SQLx connection shape"); - assert_eq!( - options.get_socket().map(|path| path.as_path()), - Some(Path::new("/tmp/Application Support/db?slot")) - ); - assert_eq!(options.get_port(), 6543); - assert_eq!(options.get_username(), "role name"); - assert_eq!(options.get_database(), Some("tenant/db#1")); - } - - #[cfg(unix)] - #[test] - fn unix_socket_endpoint_rejects_non_utf8_directory_without_mutation() { - use std::ffi::OsStr; - use std::os::unix::ffi::OsStrExt; - - let temp = tempfile::TempDir::new().unwrap(); - let directory = temp.path().join(OsStr::from_bytes(b"db-\xFF")); - assert!(!directory.exists()); - - let error = resolve_unix_socket_endpoint(&directory, 6543) - .expect_err("a String connection URI cannot preserve a non-UTF-8 socket path"); - - assert!(error.to_string().contains("must be valid UTF-8")); - assert!(!directory.exists()); - } - - #[cfg(unix)] - #[test] - fn unix_socket_endpoint_rejects_zero_port() { - let error = resolve_unix_socket_endpoint(Path::new("/tmp"), 0).unwrap_err(); - assert!(error.to_string().contains("range 1..=65535")); - } - - #[cfg(unix)] - #[test] - fn unix_socket_endpoint_rejects_too_long_path_without_mutation() { - let directory = std::env::temp_dir().join(format!( - "oliphaunt-wasix-socket-{}-{}", - std::process::id(), - "x".repeat(120) - )); - assert!(!directory.exists()); - - let error = resolve_unix_socket_endpoint(&directory, 6543).expect_err( - "Unix socket sockaddr length must be validated before database preparation", - ); - - assert!(error.to_string().contains("socket path is too long")); - assert!(!directory.exists()); - } - - #[cfg(unix)] - #[test] - fn unix_socket_endpoint_resolves_relative_paths() -> Result<()> { - let current_directory = Path::new("/tmp/oliphaunt-relative-base"); - let endpoint = - resolve_unix_socket_endpoint_at(Path::new("run"), 6543, Some(current_directory))?; - assert_eq!(endpoint.path, current_directory.join("run/.s.PGSQL.6543")); - assert_eq!(endpoint.port, 6543); - Ok(()) - } - - #[cfg(unix)] - #[test] - fn unix_socket_preparation_rejects_regular_files_and_symlinks() -> Result<()> { - use std::os::unix::fs::symlink; - - let temp = tempfile::TempDir::new()?; - let regular = temp.path().join("regular"); - std::fs::write(®ular, b"keep")?; - let error = ensure_unix_socket_path_available(®ular).unwrap_err(); - assert!( - error - .to_string() - .contains("refusing to replace existing Unix non-socket") - ); - assert_eq!(std::fs::read(®ular)?, b"keep"); - - let link = temp.path().join("link"); - symlink(®ular, &link)?; - let error = ensure_unix_socket_path_available(&link).unwrap_err(); - assert!( - error - .to_string() - .contains("refusing to replace existing Unix non-socket") - ); - assert!(link.symlink_metadata()?.file_type().is_symlink()); - Ok(()) - } - - #[cfg(unix)] - #[test] - fn unix_socket_preparation_rejects_active_and_stale_sockets() -> Result<()> { - let temp = tempfile::TempDir::new()?; - let socket = temp.path().join(".s.PGSQL.6543"); - let listener = UnixListener::bind(&socket)?; - - let error = ensure_unix_socket_path_available(&socket).unwrap_err(); - assert!( - error - .to_string() - .contains("refusing to replace existing Unix socket") - ); - assert!(socket.exists()); - - drop(listener); - let error = ensure_unix_socket_path_available(&socket).unwrap_err(); - assert!( - error - .to_string() - .contains("remove it explicitly if it is stale") - ); - assert!(socket.exists()); - Ok(()) - } - - #[cfg(unix)] - #[test] - fn unix_socket_cleanup_removes_only_the_owned_inode() -> Result<()> { - let temp = tempfile::TempDir::new()?; - let socket = temp.path().join(".s.PGSQL.6543"); - let listener = UnixListener::bind(&socket)?; - let mut owned = OwnedUnixSocket::capture(&socket)?; - - std::fs::remove_file(&socket)?; - std::fs::write(&socket, b"replacement")?; - let error = owned.cleanup().unwrap_err(); - assert!( - error - .to_string() - .contains("refusing to remove replaced Unix endpoint") - ); - assert_eq!(std::fs::read(&socket)?, b"replacement"); - drop(listener); - Ok(()) - } - - #[test] - fn default_server_builder_selects_memory() { - let builder = OliphauntServerBuilder::default(); - assert_eq!(builder.storage, DatabaseStorage::Memory); - assert_eq!(builder.catalog_profile, CatalogProfile::default()); - } - - #[cfg(feature = "icu")] - #[test] - fn server_profiles_remain_isolated_in_both_construction_orders() -> Result<()> { - if !both_catalog_profiles_are_packaged() { - return Ok(()); - } - - for profiles in [ - [CatalogProfile::Standard, CatalogProfile::Icu], - [CatalogProfile::Icu, CatalogProfile::Standard], - ] { - let mut first = OliphauntServerBuilder::new() - .catalog_profile(profiles[0]) - .start() - .map_err(|error| anyhow!(error.to_string()))?; - let mut second = OliphauntServerBuilder::new() - .catalog_profile(profiles[1]) - .start() - .map_err(|error| anyhow!(error.to_string()))?; - - assert_server_profile(&first, profiles[0]); - assert_server_profile(&second, profiles[1]); - assert_ne!(first.runtime_root, second.runtime_root); - - second.close().map_err(|error| anyhow!(error.to_string()))?; - first.close().map_err(|error| anyhow!(error.to_string()))?; - } - Ok(()) - } - - #[cfg(feature = "icu")] - #[test] - fn server_profiles_start_concurrently_without_contamination() -> Result<()> { - if !both_catalog_profiles_are_packaged() { - return Ok(()); - } - - let barrier = Arc::new(std::sync::Barrier::new(2)); - let start = |profile| { - let barrier = Arc::clone(&barrier); - std::thread::spawn(move || -> Result<(CatalogProfile, PathBuf, bool)> { - let mut server = OliphauntServerBuilder::new() - .catalog_profile(profile) - .start() - .map_err(|error| anyhow!(error.to_string()))?; - barrier.wait(); - let snapshot = ( - server.catalog_profile, - server.runtime_root.clone(), - server.runtime_root.join("share/icu").is_dir(), - ); - server.close().map_err(|error| anyhow!(error.to_string()))?; - Ok(snapshot) - }) - }; - let standard = start(CatalogProfile::Standard); - let icu = start(CatalogProfile::Icu); - let standard = standard - .join() - .map_err(|_| anyhow!("standard server startup panicked"))??; - let icu = icu - .join() - .map_err(|_| anyhow!("ICU server startup panicked"))??; - - assert_eq!(standard.0, CatalogProfile::Standard); - assert!(!standard.2); - assert_eq!(icu.0, CatalogProfile::Icu); - assert!(icu.2); - assert_ne!(standard.1, icu.1); - Ok(()) - } - - #[test] - fn direct_server_close_keeps_observable_terminal_state_and_replays_failure() { - let mut server = - server_with_worker_result_for_test(Err(anyhow!("injected server stop failure")), None); - assert!(!server.is_closed()); - - let first = server.close().unwrap_err().to_string(); - assert!(server.is_closed()); - let second = server.close().unwrap_err().to_string(); - - assert_eq!(first, second); - assert!(first.contains("injected server stop failure")); - } - - #[test] - fn failed_direct_server_close_quarantines_managed_root_ownership() -> Result<()> { - let parent = TempDir::new()?; - let root = parent.path().join("failed-server-root"); - let lock = DirectoryLock::acquire(&root)?; - let mut server = server_with_worker_result_for_test( - Err(anyhow!("injected server stop failure")), - Some(lock), - ); - - server.close().expect_err("server teardown fails"); - assert!(!server._directory_lock.is_released()); - drop(server); - - let reopen = DirectoryLock::acquire(&root) - .expect_err("failed teardown must retain the managed root until process exit"); - assert!(format!("{reopen:#}").contains("database root is already in use")); - Ok(()) - } - - #[test] - fn successful_direct_server_close_releases_managed_root_ownership() -> Result<()> { - let parent = TempDir::new()?; - let root = parent.path().join("successful-server-root"); - let lock = DirectoryLock::acquire(&root)?; - let mut server = server_with_worker_result_for_test(Ok(()), Some(lock)); - - server.close()?; - assert!(server._directory_lock.is_released()); - drop(server); - - let reopened = DirectoryLock::acquire(&root)?; - drop(reopened); - Ok(()) - } - - #[test] - fn server_listen_contract_cannot_express_a_remote_tcp_bind() { - let fixture: serde_json::Value = serde_json::from_str( - &crate::oliphaunt::test_fixtures::text("postgres/server-listen.json"), - ) - .unwrap(); - assert_eq!(fixture["tcp"]["host"], "127.0.0.1"); - assert_eq!(fixture["unix"]["defaultPort"], 5432); - assert_eq!(fixture["unix"]["filePrefix"], ".s.PGSQL."); - assert_eq!(ServerListen::tcp(), ServerListen::Tcp { port: None }); - assert_eq!( - ServerListen::tcp_port(15432), - ServerListen::Tcp { port: Some(15432) } - ); - } - - #[test] - fn explicit_zero_tcp_port_is_rejected_before_runtime_work() { - let error = OliphauntServer::builder() - .listen(ServerListen::tcp_port(0)) - .start() - .unwrap_err(); - assert_eq!(error.kind(), crate::ErrorKind::InvalidConfiguration); - assert!(error.to_string().contains("omit it to allocate one")); - } - - #[cfg(feature = "extension-pg-textsearch")] - #[test] - fn server_path_merges_pg_textsearch_preload_once_before_start() { - let builder = OliphauntServerBuilder::new() - .startup_guc("shared_preload_libraries", "auto_explain,pg_textsearch") - .extensions([Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH]); - - let (_, postgres_config) = builder.resolved_extension_startup().unwrap(); - - assert_eq!( - postgres_config.get("shared_preload_libraries"), - Some("auto_explain,pg_textsearch") - ); - assert_eq!( - postgres_config - .get("shared_preload_libraries") - .unwrap() - .split(',') - .filter(|library| *library == "pg_textsearch") - .count(), - 1 - ); - } -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/test_fixtures.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/test_fixtures.rs deleted file mode 100644 index 1a4c6ed24..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/test_fixtures.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::fs; -use std::path::Path; - -pub(crate) fn text(relative: &str) -> String { - source_text( - &format!("shared/fixtures/{relative}"), - &format!("src/testdata/{relative}"), - ) -} - -pub(crate) fn source_text(src_relative: &str, packaged_name: &str) -> String { - let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); - let shared = manifest_dir.join("../../../../").join(src_relative); - let packaged = manifest_dir.join(packaged_name); - fs::read_to_string(&shared) - .or_else(|shared_error| { - fs::read_to_string(&packaged).map_err(|packaged_error| { - std::io::Error::new( - packaged_error.kind(), - format!( - "read shared fixture {} ({shared_error}) or packaged fixture {} ({packaged_error})", - shared.display(), - packaged.display() - ), - ) - }) - }) - .unwrap_or_else(|error| panic!("{error}")) -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/wire.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/wire.rs deleted file mode 100644 index 169c18074..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/wire.rs +++ /dev/null @@ -1,234 +0,0 @@ -use anyhow::{Context, Result, anyhow, bail}; - -use crate::oliphaunt::config::StartupConfig; - -pub(crate) const SSL_REQUEST_CODE: i32 = 80_877_103; -pub(crate) const GSSENC_REQUEST_CODE: i32 = 80_877_104; -pub(crate) const CANCEL_REQUEST_CODE: i32 = 80_877_102; -pub(crate) const PROTOCOL_3: i32 = 196_608; -pub(crate) const MAX_FRONTEND_MESSAGE: usize = 128 * 1024 * 1024; - -#[derive(Default)] -pub(crate) struct FrontendFrameReader { - buffer: Vec, -} - -impl FrontendFrameReader { - pub(crate) fn append(&mut self, input: &[u8]) { - self.buffer.extend_from_slice(input); - } - - pub(crate) fn next_frame(&mut self) -> Result>> { - let Some(message_len) = frontend_message_len_if_complete(&self.buffer)? else { - return Ok(None); - }; - Ok(Some(self.buffer.drain(..message_len).collect())) - } - - pub(crate) fn push(&mut self, input: &[u8]) -> Result>> { - self.append(input); - let mut messages = Vec::new(); - while let Some(message) = self.next_frame()? { - messages.push(message); - } - Ok(messages) - } - - pub(crate) fn pending(&self) -> &[u8] { - &self.buffer - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum FrontendFrameKind { - Protocol, - Startup, - SslOrGssRequest, - CancelRequest, - Terminate, -} - -pub(crate) fn frontend_message_len_if_complete(buffer: &[u8]) -> Result> { - if buffer.len() < 4 { - return Ok(None); - } - - if buffer[0] == 0 { - let len = i32::from_be_bytes(buffer[0..4].try_into().unwrap()); - if len < 8 { - bail!("invalid startup packet length {len}"); - } - let len = len as usize; - if len > MAX_FRONTEND_MESSAGE { - bail!("startup/control packet length {len} exceeds limit"); - } - return Ok((buffer.len() >= len).then_some(len)); - } - - if buffer.len() < 5 { - return Ok(None); - } - let len = i32::from_be_bytes(buffer[1..5].try_into().unwrap()); - if len < 4 { - bail!("invalid frontend message length {len}"); - } - let total = 1usize - .checked_add(len as usize) - .ok_or_else(|| anyhow!("frontend message length overflow"))?; - if total > MAX_FRONTEND_MESSAGE { - bail!("frontend message length {total} exceeds limit"); - } - Ok((buffer.len() >= total).then_some(total)) -} - -pub(crate) fn classify_frontend_message(message: &[u8]) -> Result { - if message.is_empty() { - bail!("empty frontend message"); - } - - if message[0] == 0 { - if message.len() < 8 { - bail!("startup/control packet is too short"); - } - let code = i32::from_be_bytes(message[4..8].try_into().unwrap()); - return Ok(match code { - SSL_REQUEST_CODE | GSSENC_REQUEST_CODE => FrontendFrameKind::SslOrGssRequest, - CANCEL_REQUEST_CODE => FrontendFrameKind::CancelRequest, - PROTOCOL_3 => FrontendFrameKind::Startup, - other => bail!("unsupported startup/control packet code {other}"), - }); - } - - if message[0] == b'X' { - return Ok(FrontendFrameKind::Terminate); - } - - Ok(FrontendFrameKind::Protocol) -} - -pub(crate) fn startup_parameter<'a>(message: &'a [u8], wanted: &str) -> Result> { - if message.len() < 8 { - bail!("startup packet is too short"); - } - let mut cursor = 8usize; - while cursor < message.len() { - if message[cursor] == 0 { - break; - } - let key_end = message[cursor..] - .iter() - .position(|byte| *byte == 0) - .map(|offset| cursor + offset) - .ok_or_else(|| anyhow!("startup parameter key is not nul-terminated"))?; - let key = std::str::from_utf8(&message[cursor..key_end]) - .context("startup parameter key is not UTF-8")?; - cursor = key_end + 1; - - let value_end = message[cursor..] - .iter() - .position(|byte| *byte == 0) - .map(|offset| cursor + offset) - .ok_or_else(|| anyhow!("startup parameter value is not nul-terminated"))?; - let value = std::str::from_utf8(&message[cursor..value_end]) - .context("startup parameter value is not UTF-8")?; - cursor = value_end + 1; - if key == wanted { - return Ok(Some(value)); - } - } - Ok(None) -} - -pub(crate) fn startup_config_for_message( - base: &StartupConfig, - message: &[u8], -) -> Result { - let mut config = base.clone(); - if let Some(user) = startup_parameter(message, "user")? { - config.username = user.to_owned(); - } - if let Some(database) = startup_parameter(message, "database")? { - config.database = database.to_owned(); - } - config.validate()?; - Ok(config) -} - -pub(crate) fn response_contains_error(response: &[u8]) -> bool { - response_contains_tag(response, b'E') -} - -pub(crate) fn response_contains_tag(response: &[u8], expected: u8) -> bool { - let mut cursor = 0usize; - while cursor + 5 <= response.len() { - let tag = response[cursor]; - let len = i32::from_be_bytes(response[cursor + 1..cursor + 5].try_into().unwrap()); - if len < 4 { - return false; - } - let total = 1usize.saturating_add(len as usize); - if cursor + total > response.len() { - return false; - } - if tag == expected { - return true; - } - cursor += total; - } - false -} - -pub(crate) fn error_response(severity: &str, code: &str, message: &str) -> Vec { - let mut body = Vec::new(); - push_error_field(&mut body, b'S', severity); - push_error_field(&mut body, b'V', severity); - push_error_field(&mut body, b'C', code); - push_error_field(&mut body, b'M', message); - body.push(0); - - let mut response = Vec::with_capacity(body.len() + 5); - response.push(b'E'); - response.extend_from_slice(&((body.len() + 4) as i32).to_be_bytes()); - response.extend_from_slice(&body); - response -} - -fn push_error_field(body: &mut Vec, tag: u8, value: &str) { - body.push(tag); - body.extend_from_slice(value.as_bytes()); - body.push(0); -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn frame_reader_buffers_split_messages() -> Result<()> { - let query = b"Q\0\0\0\rSELECT 1\0"; - let mut reader = FrontendFrameReader::default(); - assert!(reader.push(&query[..3])?.is_empty()); - assert_eq!(reader.push(&query[3..])?, vec![query.to_vec()]); - Ok(()) - } - - #[test] - fn classifies_startup_and_control_packets() -> Result<()> { - let mut startup = Vec::new(); - startup.extend_from_slice(&8_i32.to_be_bytes()); - startup.extend_from_slice(&PROTOCOL_3.to_be_bytes()); - assert_eq!( - classify_frontend_message(&startup)?, - FrontendFrameKind::Startup - ); - - let mut ssl = Vec::new(); - ssl.extend_from_slice(&8_i32.to_be_bytes()); - ssl.extend_from_slice(&SSL_REQUEST_CODE.to_be_bytes()); - assert_eq!( - classify_frontend_message(&ssl)?, - FrontendFrameKind::SslOrGssRequest - ); - Ok(()) - } -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/testdata/wasix-toolchain.toml b/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/testdata/wasix-toolchain.toml deleted file mode 100644 index 1dc976bff..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/testdata/wasix-toolchain.toml +++ /dev/null @@ -1,52 +0,0 @@ -[toolchain] -wasmer = "7.2.1" -wasmer-wasix = "0.702.1" -webc = "12.0.0" -wasmer_llvm = "22.1" -assets_manifest = "src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv" -assets_manifest_sha256 = "9b0ee1aabcfecda1be72c94a9f14a16c9d8a2fc020f3dc471394d5335766c519" - -[toolchain.wasixcc] -version = "0.4.3" -target = "x86_64-unknown-linux-gnu" -asset = "wasixcc-x86_64-unknown-linux-gnu.tar.gz" -sha256 = "3c55abbe0490d0a4736dfe0caaf0763597ae3e50e587c447bf6397b841a0b096" - -[toolchain.sysroots] -version = "2026-03-02.1" -sysroot_sha256 = "ec1c4286fae0c70d4ac4e71acfa2d28d439b1270fe65b4ee266df48dc10076a7" -sysroot_eh_sha256 = "0714ee07316d9a0bf9e1b1ec66acc15fee302b7bd23254680298554e75c2a74b" -sysroot_ehpic_sha256 = "2ddbdc145ca8278c0599afdfe10218d1cf88571bf1a8d5dfe95e05becb6a0429" -sysroot_exnref_eh_sha256 = "612f5c94c8d5972279b8f5728342f238b9da7a2ecc8ce5fb86090295f7a87026" -sysroot_exnref_ehpic_sha256 = "bff94209738358f50f18c85b9446d84a65282690826ad88cc6b67d1795d9ce2f" - -[toolchain.llvm] -release = "21.1.204" -reported_version = "21.1.2" -asset = "LLVM-Linux-x86_64.tar.gz" -sha256 = "a94a2e550aea0081b31005e9fe18cacda4606c4cb98bc557b12f13cb0c06f6e2" - -[toolchain.binaryen] -release = "version_130" -reported_version = "130" -asset = "binaryen-version_130-x86_64-linux.tar.gz" -sha256 = "0a18362361ad05465118cd8eeb72edaeec89de6894bc283576ef4e07aa3babcc" - -[builder] -base_image = "ubuntu:24.04" -base_image_digest = "sha256:c4a8d5503dfb2a3eb8ab5f807da5bc69a85730fb49b5cfca2330194ebcc41c7b" -dockerfile_frontend = "docker/dockerfile:1.7@sha256:a57df69d0ea827fb7266491f2813635de6f17269be881f696fbfdf2d83dda33e" -apt_snapshot = "20260715T000000Z" -apt_snapshot_retention = "Ubuntu documents archive snapshots as available for at least two years. Preserve or advance this pin through an explicitly qualified toolchain update before that retention window expires." -snapshot_tls_root = "src/runtimes/liboliphaunt/wasix/assets/build/docker/isrg-root-x1.pem" -snapshot_tls_root_sha256 = "22b557a27055b33606b6559f37703928d3e4ad79f110b407d04986e1843543d1" -snapshot_tls_root_not_after = "2035-06-04T11:04:38Z" - -[build] -postgres_prefix = "/" -postgres_pkglibdir = "/lib/postgresql" -postgres_sharedir = "/share/postgresql" -main_flags = ["-fwasm-exceptions"] -extension_flags = ["-fwasm-exceptions", "-fPIC", "-Wl,-shared"] -archive_format = "tar.zst" -deterministic_archives = true diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/cli_smoke.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/cli_smoke.rs deleted file mode 100644 index c15e4a8d0..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/cli_smoke.rs +++ /dev/null @@ -1,91 +0,0 @@ -#![cfg(feature = "extensions")] - -use anyhow::{Context, Result}; -use oliphaunt_wasix::Oliphaunt; -use sqlx::{Connection, Row}; -use std::io::{BufRead, BufReader}; -use std::process::{Command, Stdio}; -use tokio::time::{Duration, timeout}; - -mod support; -use support::{ChildGuard, TestTrace, trace_step}; - -fn direct_open_diagnostic() -> String { - match Oliphaunt::builder().open() { - Ok(mut pg) => match pg.close() { - Ok(()) => "direct memory Oliphaunt open succeeded".to_owned(), - Err(err) => format!("direct memory Oliphaunt open succeeded, close failed: {err:#}"), - }, - Err(err) => format!("direct memory Oliphaunt open failed: {err:#}"), - } -} - -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn oliphaunt_proxy_print_uri_accepts_sqlx_connection() -> Result<()> { - let _trace = TestTrace::new("oliphaunt_proxy_print_uri_accepts_sqlx_connection"); - let process = Command::new(env!("CARGO_BIN_EXE_oliphaunt-wasix-proxy")) - .args(["--memory", "--print-uri"]) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn() - .context("spawn oliphaunt-wasix-proxy")?; - let mut child = ChildGuard::new(process, "oliphaunt-wasix-proxy")?; - - let stdout = child - .child_mut() - .stdout - .take() - .context("oliphaunt-wasix-proxy stdout pipe")?; - let read_uri = tokio::task::spawn_blocking(move || { - let mut reader = BufReader::new(stdout); - let mut uri = String::new(); - let bytes = reader - .read_line(&mut uri) - .context("read oliphaunt-wasix-proxy printed URI")?; - Ok::<_, anyhow::Error>((bytes, uri)) - }); - let (bytes, uri) = match timeout(Duration::from_secs(30), read_uri).await { - Ok(Ok(Ok(result))) => result, - Ok(Ok(Err(err))) => return Err(err), - Ok(Err(err)) => return Err(err).context("join URI reader task"), - Err(err) => { - let stderr = child.collect_stderr(); - anyhow::bail!( - "timed out waiting for oliphaunt-wasix-proxy URI: {err}\n\nstderr:\n{stderr}" - ); - } - }; - if bytes == 0 { - let stderr = child.collect_stderr(); - anyhow::bail!("oliphaunt-wasix-proxy exited before printing URI\n\nstderr:\n{stderr}"); - } - let uri = uri.trim(); - assert!(uri.starts_with("postgresql://"), "unexpected URI: {uri}"); - trace_step("oliphaunt_proxy printed URI"); - - let mut conn = match timeout(Duration::from_secs(30), sqlx::PgConnection::connect(uri)).await { - Ok(Ok(conn)) => conn, - Ok(Err(err)) => { - let stderr = child.collect_stderr(); - let direct = direct_open_diagnostic(); - anyhow::bail!( - "connect to oliphaunt-wasix-proxy failed: {err:#}\n\nstderr:\n{stderr}\n\ndirect backend diagnostic:\n{direct}" - ); - } - Err(err) => { - let stderr = child.collect_stderr(); - let direct = direct_open_diagnostic(); - anyhow::bail!( - "timed out connecting to oliphaunt-wasix-proxy: {err}\n\nstderr:\n{stderr}\n\ndirect backend diagnostic:\n{direct}" - ); - } - }; - let row = sqlx::query("SELECT $1::int4 + 1 AS answer") - .bind(41_i32) - .fetch_one(&mut conn) - .await?; - assert_eq!(row.try_get::("answer")?, 42); - - conn.close().await?; - Ok(()) -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/extensions_smoke.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/extensions_smoke.rs deleted file mode 100644 index 4cef5ca59..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/extensions_smoke.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![cfg(feature = "extension-vector")] - -use anyhow::Result; -use oliphaunt_wasix::{AsyncOliphauntServer, Extension, Oliphaunt}; -use sqlx::{Connection, Row}; - -#[test] -fn vector_extension_works_in_direct_mode() -> Result<()> { - let mut database = Oliphaunt::builder().extension(Extension::VECTOR).open()?; - let selected_only = database - .query("SELECT count(*)::int4 AS count FROM pg_extension WHERE extname = 'vector'")?; - assert_eq!(selected_only.get_text(0, "count")?, Some("0")); - database.execute("CREATE EXTENSION vector")?; - let result = database.query("SELECT '[1,2,3]'::vector <-> '[1,2,4]'::vector AS distance")?; - assert_eq!(result.get_text(0, "distance")?, Some("1")); - database.close()?; - Ok(()) -} - -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn vector_extension_works_through_server() -> Result<()> { - let server = AsyncOliphauntServer::builder() - .extension(Extension::VECTOR) - .start() - .await?; - let mut connection = sqlx::PgConnection::connect(server.connection_string()).await?; - let installed: i64 = - sqlx::query_scalar("SELECT count(*)::int8 FROM pg_extension WHERE extname = 'vector'") - .fetch_one(&mut connection) - .await?; - assert_eq!(installed, 0); - sqlx::query("CREATE EXTENSION vector") - .execute(&mut connection) - .await?; - let row = sqlx::query("SELECT '[1,2,3]'::vector <-> '[1,2,4]'::vector AS distance") - .fetch_one(&mut connection) - .await?; - assert_eq!(row.try_get::("distance")?, 1.0); - connection.close().await?; - server.close().await?; - Ok(()) -} diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/public_api.rs b/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/public_api.rs deleted file mode 100644 index b1429e95e..000000000 --- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/public_api.rs +++ /dev/null @@ -1,630 +0,0 @@ -use std::error::Error as _; -use std::path::PathBuf; - -#[cfg(unix)] -use oliphaunt_wasix::ServerListen; -use oliphaunt_wasix::{ - AsyncOliphaunt, AsyncOliphauntBuilder, AsyncOliphauntServer, AsyncOliphauntServerBuilder, - AsyncSql, AsyncTransaction, DatabaseStorage, DecodeError, Error, ErrorKind, FromSql, - IntoParameter, Oliphaunt, Parameter, PostgresError, PostgresNotice, RawStreamCallbackOutput, - RawStreamError, RawStreamResult, Result, Transaction, TransactionError, TransactionResult, - TypeOid, ValueFormat, ValueRef, -}; - -#[cfg(unix)] -fn non_utf8_unix_socket_directory() -> PathBuf { - use std::ffi::OsString; - use std::os::unix::ffi::OsStringExt; - - let mut leaf = format!("oliphaunt-wasix-socket-{}-", std::process::id()).into_bytes(); - leaf.push(0xff); - std::env::temp_dir().join(OsString::from_vec(leaf)) -} - -#[derive(Debug, Clone)] -enum ApplicationError { - Database(Error), - Abort, -} - -impl From for ApplicationError { - fn from(error: Error) -> Self { - Self::Database(error) - } -} - -impl std::fmt::Display for ApplicationError { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Database(error) => error.fmt(formatter), - Self::Abort => formatter.write_str("application aborted the transaction"), - } - } -} - -impl std::error::Error for ApplicationError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Self::Database(error) => Some(error), - Self::Abort => None, - } - } -} - -#[derive(Debug, Clone)] -struct ParserError; - -impl std::fmt::Display for ParserError { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str("parser stopped the stream") - } -} - -impl std::error::Error for ParserError {} - -fn sdk_only_blocking_callbacks(database: &mut Oliphaunt) -> Result<()> { - database.transaction(|transaction| { - transaction.execute("SELECT 1")?; - Ok(()) - })?; - database.exec_protocol_raw_stream([], |_| ())?; - database.exec_protocol_raw_stream([], |_| -> Result<()> { Ok(()) })?; - Ok(()) -} - -fn typed_blocking_transaction(database: &mut Oliphaunt) -> TransactionResult<(), ApplicationError> { - database.transaction(|transaction| { - transaction.execute("SELECT 1")?; - Err(ApplicationError::Abort) - }) -} - -fn typed_blocking_stream(database: &mut Oliphaunt) -> RawStreamResult<(), ParserError> { - database.exec_protocol_raw_stream([], |_| Err(ParserError)) -} - -async fn sdk_only_async_callbacks(database: &AsyncOliphaunt) -> Result<()> { - database - .transaction(async |transaction| { - transaction.execute("SELECT 1").await?; - Ok(()) - }) - .await?; - database.exec_protocol_raw_stream([], |_| ()).await?; - database - .exec_protocol_raw_stream([], |_| -> Result<()> { Ok(()) }) - .await?; - Ok(()) -} - -async fn typed_async_transaction( - database: &AsyncOliphaunt, -) -> TransactionResult<(), ApplicationError> { - database - .transaction(async |transaction| { - transaction.execute("SELECT 1").await?; - Err(ApplicationError::Abort) - }) - .await -} - -async fn typed_async_stream(database: &AsyncOliphaunt) -> RawStreamResult<(), ParserError> { - database - .exec_protocol_raw_stream([], |_| Err(ParserError)) - .await -} - -fn assert_invalid_startup_identity(error: Error, name: &str) { - assert_invalid_configuration(error, &format!("{name} must not be empty")); -} - -fn assert_invalid_configuration(error: Error, expected_message: &str) { - assert_eq!(error.kind(), ErrorKind::InvalidConfiguration); - assert_eq!(error.to_string(), expected_message); -} - -fn expect_sdk_error(result: Result, message: &str) -> Error { - match result { - Ok(_) => panic!("{message}"), - Err(error) => error, - } -} - -macro_rules! assert_not_impl { - ($type:ty: $bound:path) => { - const _: fn() = || { - trait AmbiguousIfImpl { - fn marker() {} - } - struct Invalid; - impl AmbiguousIfImpl<()> for T {} - impl AmbiguousIfImpl for T {} - let _ = <$type as AmbiguousIfImpl<_>>::marker; - }; - }; -} - -assert_not_impl!(Oliphaunt: Send); -assert_not_impl!(Oliphaunt: Sync); -assert_not_impl!(oliphaunt_wasix::OliphauntServer: Clone); -assert_not_impl!(oliphaunt_wasix::OliphauntServer: Sync); -assert_not_impl!(AsyncTransaction: Sync); - -struct PublicParameter; - -impl IntoParameter for PublicParameter { - const TYPE_OID: Option = Some(TypeOid::INT4); - - fn into_parameter(self) -> Parameter { - Parameter::typed_binary(TypeOid::INT4, 7_i32.to_be_bytes()) - } -} - -struct PublicDecoder; - -impl<'a> FromSql<'a> for PublicDecoder { - fn from_sql(_value: ValueRef<'a>) -> std::result::Result { - Ok(Self) - } -} - -#[test] -fn fallible_public_api_uses_the_sdk_result() { - fn assert_result(_: Result<()>) {} - fn assert_error() {} - fn assert_error_kind() {} - - assert_error::(); - assert_error_kind::(); - assert_error::>(); - assert_error::>(); - let destination = tempfile::tempdir() - .expect("temporary directory") - .path() - .join("restored"); - let result = Oliphaunt::restore(destination, b"not a physical archive"); - let error = result.expect_err("invalid archive must fail"); - assert!(!error.to_string().is_empty()); - assert!(error.postgres_error().is_none()); - assert!(error.transaction_rollback_errors().is_none()); - assert!(error.transaction_callback_database_errors().is_none()); - assert!(error.source().is_some()); - assert_result(Err(error)); - - fn transaction_rollback_tuple_surface(error: &Error) { - let _: ErrorKind = error.kind(); - let _stable_match = match error.kind() { - ErrorKind::InvalidConfiguration => "invalid-configuration", - ErrorKind::Lifecycle => "lifecycle", - ErrorKind::TransactionActive => "transaction-active", - ErrorKind::Postgres => "postgres", - _ => "other-or-future", - }; - let _: Option<(&Error, &Error)> = error.transaction_rollback_errors(); - let _: Option<(&Error, &Error)> = error.transaction_callback_database_errors(); - } - let _: fn(&Error) = transaction_rollback_tuple_surface; - - fn generic_error_surface( - transaction: &TransactionError, - stream: &RawStreamError, - ) { - let _: Option<&ApplicationError> = transaction.callback_error(); - let _: Option<&Error> = transaction.database_error(); - let _: Option<&Error> = transaction.rollback_error(); - let _: Option<&ParserError> = stream.callback_error(); - let _: Option<&Error> = stream.database_error(); - let _: Option<&Error> = stream.callback_panic_error(); - } - let _: fn(&TransactionError, &RawStreamError) = - generic_error_surface; - - fn flatten_sdk_errors( - transaction: TransactionError, - stream: RawStreamError, - infallible: RawStreamError, - ) { - let _: Error = transaction.into(); - let _: Error = stream.into(); - let _: Error = infallible.into(); - } - let _ = flatten_sdk_errors; - - fn postgres_diagnostic_surface(error: &PostgresError, notice: &PostgresNotice) { - let _: (&Option, &Option) = - (&error.localized_severity, ¬ice.localized_severity); - let _: (&Option, &Option) = - (&error.nonlocalized_severity, ¬ice.nonlocalized_severity); - let _: (&Option, &Option) = - (&error.internal_position, ¬ice.internal_position); - let _: (&Option, &Option) = (&error.internal_query, ¬ice.internal_query); - let _: (&Option, &Option) = (&error.file, ¬ice.file); - let _: (&Option, &Option) = (&error.line, ¬ice.line); - let _: (&Option, &Option) = (&error.routine, ¬ice.routine); - } - let _: fn(&PostgresError, &PostgresNotice) = postgres_diagnostic_surface; -} - -#[test] -fn direct_builders_reject_empty_startup_identities_before_runtime_work() { - for value in ["", " \t\n"] { - let error = expect_sdk_error( - Oliphaunt::builder().username(value).open(), - "empty username must fail before runtime setup", - ); - assert_invalid_startup_identity(error, "username"); - - let error = expect_sdk_error( - Oliphaunt::builder().database(value).open(), - "empty database must fail before runtime setup", - ); - assert_invalid_startup_identity(error, "database"); - - let error = expect_sdk_error( - oliphaunt_wasix::OliphauntServer::builder() - .username(value) - .start(), - "empty server username must fail before runtime setup", - ); - assert_invalid_startup_identity(error, "username"); - - let error = expect_sdk_error( - oliphaunt_wasix::OliphauntServer::builder() - .database(value) - .start(), - "empty server database must fail before runtime setup", - ); - assert_invalid_startup_identity(error, "database"); - } -} - -#[tokio::test] -async fn async_builders_preserve_startup_identity_validation() { - let error = expect_sdk_error( - AsyncOliphaunt::builder().username(" \t\n").open().await, - "async database must preserve direct username validation", - ); - assert_invalid_startup_identity(error, "username"); - - let error = expect_sdk_error( - AsyncOliphauntServer::builder().database("").start().await, - "async server must preserve direct database validation", - ); - assert_invalid_startup_identity(error, "database"); -} - -#[test] -fn sync_builders_reject_invalid_host_paths_before_filesystem_work() { - for (path, reason) in [ - (PathBuf::new(), "must not be empty"), - (PathBuf::from("invalid\0path"), "must not contain NUL bytes"), - ] { - let error = expect_sdk_error( - Oliphaunt::builder() - .storage(DatabaseStorage::Directory(path.clone())) - .open(), - "invalid storage path must fail before runtime setup", - ); - assert_invalid_configuration(error, &format!("database storage directory {reason}")); - - let error = expect_sdk_error( - oliphaunt_wasix::OliphauntServer::builder() - .storage(DatabaseStorage::Directory(path.clone())) - .start(), - "invalid server storage path must fail before runtime setup", - ); - assert_invalid_configuration(error, &format!("database storage directory {reason}")); - - #[cfg(unix)] - { - let error = expect_sdk_error( - oliphaunt_wasix::OliphauntServer::builder() - .listen(ServerListen::unix(path)) - .start(), - "invalid Unix listener path must fail before runtime setup", - ); - assert_invalid_configuration(error, &format!("Unix socket directory {reason}")); - } - } - - #[cfg(unix)] - { - let path = non_utf8_unix_socket_directory(); - assert!(!path.exists()); - let error = expect_sdk_error( - oliphaunt_wasix::OliphauntServer::builder() - .listen(ServerListen::unix(path.clone())) - .start(), - "non-UTF-8 Unix listener path must fail before runtime setup", - ); - assert_invalid_configuration( - error, - "Unix socket directory must be valid UTF-8 so the published PostgreSQL connection string preserves the exact path", - ); - assert!(!path.exists()); - } -} - -#[tokio::test] -async fn async_builders_preserve_host_path_validation() { - for (path, reason) in [ - (PathBuf::new(), "must not be empty"), - (PathBuf::from("invalid\0path"), "must not contain NUL bytes"), - ] { - let error = expect_sdk_error( - AsyncOliphaunt::builder() - .storage(DatabaseStorage::Directory(path.clone())) - .open() - .await, - "async database must preserve storage path validation", - ); - assert_invalid_configuration(error, &format!("database storage directory {reason}")); - - let error = expect_sdk_error( - AsyncOliphauntServer::builder() - .storage(DatabaseStorage::Directory(path.clone())) - .start() - .await, - "async server must preserve storage path validation", - ); - assert_invalid_configuration(error, &format!("database storage directory {reason}")); - - #[cfg(unix)] - { - let error = expect_sdk_error( - AsyncOliphauntServer::builder() - .listen(ServerListen::unix(path)) - .start() - .await, - "async server must preserve Unix listener path validation", - ); - assert_invalid_configuration(error, &format!("Unix socket directory {reason}")); - } - } - - #[cfg(unix)] - { - let path = non_utf8_unix_socket_directory(); - assert!(!path.exists()); - let error = expect_sdk_error( - AsyncOliphauntServer::builder() - .listen(ServerListen::unix(path.clone())) - .start() - .await, - "async non-UTF-8 Unix listener path must fail before runtime setup", - ); - assert_invalid_configuration( - error, - "Unix socket directory must be valid UTF-8 so the published PostgreSQL connection string preserves the exact path", - ); - assert!(!path.exists()); - } -} - -#[test] -fn typed_and_fluent_database_api_is_public() { - fn assert_decoder() - where - for<'a> T: FromSql<'a>, - { - } - assert_decoder::(); - assert_decoder::(); - assert_decoder::(); - - let parameter = Parameter::null().with_type_oid(TypeOid::UUID); - assert_eq!(parameter.type_oid(), Some(TypeOid::UUID)); - assert_eq!(parameter.format(), ValueFormat::Text); - assert_eq!(TypeOid::TIMETZ.get(), 1266); - assert_eq!(TypeOid::CHAR_ARRAY.get(), 1002); - assert_eq!(TypeOid::NAME_ARRAY.get(), 1003); - assert_eq!(TypeOid::XML_ARRAY.get(), 143); - assert_eq!(TypeOid::TIMETZ_ARRAY.get(), 1270); - assert_eq!( - IntoParameter::into_parameter(None::).type_oid(), - Some(TypeOid::INT8) - ); - assert_eq!( - IntoParameter::into_parameter(PublicParameter).type_oid(), - Some(TypeOid::INT4) - ); - - fn assert_send_sync() {} - fn assert_send_type() {} - fn assert_clone() {} - fn assert_debug() {} - fn assert_send(_: T) {} - fn assert_raw_callback_output() {} - // The direct database owns a caller-thread Wasmer store, but the direct - // server's database already lives on its supervised listener thread. - assert_send_type::(); - assert_send_sync::(); - assert_clone::(); - assert_debug::(); - assert_send_sync::(); - assert_clone::(); - assert_send_type::(); - assert_send_sync::(); - assert_clone::(); - assert_send_sync::(); - assert_clone::(); - assert_debug::(); - assert_send(AsyncOliphaunt::open()); - assert_send(AsyncOliphaunt::builder().open()); - assert_send(AsyncOliphaunt::restore("unused", b"")); - assert_send(AsyncOliphauntServer::builder().start()); - assert_raw_callback_output::<()>(); - assert_raw_callback_output::>(); - - fn async_sql_is_send<'db, 'q>(statement: AsyncSql<'db, 'q>) { - assert_send(statement); - } - let _: for<'db, 'q> fn(AsyncSql<'db, 'q>) = async_sql_is_send; - - fn direct_construction_surface() { - let _: Result<_> = Oliphaunt::open(); - let _: Result<_> = Oliphaunt::builder().open(); - let _: Result<_> = oliphaunt_wasix::OliphauntServer::builder().start(); - } - let _: fn() = direct_construction_surface; - - fn direct_database_surface(database: &mut Oliphaunt) { - let _: Result<_> = database.query("SELECT 1"); - let _query = database - .sql("SELECT $1::int4") - .bind(1_i32) - .result_format(ValueFormat::Binary) - .query(); - let _execute = database - .sql("UPDATE items SET value = $1") - .bind("value") - .execute(); - let _typed_query = database.query_with_params("SELECT $1::int4", [1_i32]); - let _typed_execute = database.execute_with_params("SELECT $1::bool", [true]); - let _describe = database - .sql("SELECT $1::uuid") - .bind_parameter(Parameter::typed_null(TypeOid::UUID)) - .describe(); - let _exec = database.exec("SELECT 1; SELECT 2"); - let _description = database.describe("SELECT $1::uuid"); - let _raw = database.exec_protocol_raw([]); - let streamed_bytes = std::sync::Arc::new(std::sync::Mutex::new(0_usize)); - let callback_bytes = std::sync::Arc::clone(&streamed_bytes); - let _owned_raw_stream = database.exec_protocol_raw_stream([], move |chunk| { - *callback_bytes.lock().expect("stream byte counter") += chunk.len(); - }); - let _ = streamed_bytes; - let _raw_stream = database.exec_protocol_raw_stream([], |_| ()); - let _backup = database.backup(); - let _ = database.is_closed(); - let _close = database.close(); - } - fn direct_transaction_surface(transaction: &mut Transaction<'_>) { - let _ = transaction.is_closed(); - let _query = transaction.sql("SELECT $1::int4").bind(1_i32).query(); - let _execute = transaction - .sql("UPDATE items SET value = $1") - .bind("value") - .execute(); - let _typed_query = transaction.query_with_params("SELECT $1::int8", [1_i64]); - let _describe = transaction.sql("SELECT 1").describe(); - let _: Result<_> = transaction.exec("SELECT 1"); - let _ = transaction.rollback(); - } - fn direct_server_surface(server: &mut oliphaunt_wasix::OliphauntServer) { - let _: &str = server.connection_string(); - let _ = server.is_closed(); - let _: Result<_> = server.close(); - } - let _: fn(&mut Oliphaunt) = direct_database_surface; - let _: fn(&mut Oliphaunt) -> Result<()> = sdk_only_blocking_callbacks; - let _: fn(&mut Oliphaunt) -> TransactionResult<(), ApplicationError> = - typed_blocking_transaction; - let _: fn(&mut Oliphaunt) -> RawStreamResult<(), ParserError> = typed_blocking_stream; - let _: fn(&mut Transaction<'_>) = direct_transaction_surface; - let _: fn(&mut oliphaunt_wasix::OliphauntServer) = direct_server_surface; - - fn async_database_surface(database: &AsyncOliphaunt) { - let _clone = database.clone(); - assert_send(database.query("SELECT 1")); - let _query = database - .sql("SELECT $1::int4") - .bind(1_i32) - .result_format(ValueFormat::Binary) - .query(); - let _execute = database - .sql("UPDATE items SET value = $1") - .bind("value") - .execute(); - let _typed_query = database.query_with_params("SELECT $1::int4", [1_i32]); - let _typed_execute = database.execute_with_params("SELECT $1::bool", [true]); - let _describe = database - .sql("SELECT $1::uuid") - .bind_parameter(Parameter::typed_null(TypeOid::UUID)) - .describe(); - let _exec = database.exec("SELECT 1; SELECT 2"); - let _description = database.describe("SELECT $1::uuid"); - let _raw = database.exec_protocol_raw([]); - let _raw_stream = database.exec_protocol_raw_stream([], |_| ()); - let _backup = database.backup(); - let _ = database.is_closed(); - let _close = database.close(); - std::mem::drop(sdk_only_async_callbacks(database)); - std::mem::drop(typed_async_transaction(database)); - assert_send(typed_async_stream(database)); - } - fn async_transaction_surface(transaction: &mut AsyncTransaction) { - let _ = transaction.is_closed(); - std::mem::drop(transaction.sql("SELECT $1::int4").bind(1_i32).query()); - std::mem::drop( - transaction - .sql("UPDATE items SET value = $1") - .bind("value") - .execute(), - ); - std::mem::drop(transaction.query_with_params("SELECT $1::int8", [1_i64])); - std::mem::drop(transaction.sql("SELECT 1").describe()); - std::mem::drop(transaction.exec("SELECT 1")); - std::mem::drop(transaction.rollback()); - } - fn async_server_surface(server: &AsyncOliphauntServer) { - let _clone = server.clone(); - let _: &str = server.connection_string(); - let _ = server.is_closed(); - assert_send(server.close()); - } - let _: fn(&AsyncOliphaunt) = async_database_surface; - let _: fn(&mut AsyncTransaction) = async_transaction_surface; - let _: fn(&AsyncOliphauntServer) = async_server_surface; -} - -#[cfg(feature = "extension-vector")] -#[test] -fn extensions_expose_only_the_selection_contract() { - use oliphaunt_wasix::Extension; - - fn assert_extension_traits() {} - assert_extension_traits::(); - - let extension: Extension = Extension::VECTOR; - assert_eq!(extension.sql_name(), "vector"); - assert_eq!(Extension::by_sql_name("vector"), Some(extension)); - assert!(Extension::ALL.contains(&extension)); -} - -#[cfg(feature = "extension-earthdistance")] -#[test] -fn extension_features_expose_required_dependency_selectors() { - use oliphaunt_wasix::Extension; - - assert_eq!( - Extension::by_sql_name("earthdistance"), - Some(Extension::EARTHDISTANCE) - ); - assert_eq!(Extension::by_sql_name("cube"), Some(Extension::CUBE)); - assert!(Extension::ALL.contains(&Extension::EARTHDISTANCE)); - assert!(Extension::ALL.contains(&Extension::CUBE)); -} - -#[cfg(feature = "tools")] -#[test] -fn packaged_psql_accepts_standard_script_input() { - let options = oliphaunt_wasix::tools::PsqlOptions::new().script("SELECT 1;"); - let _: oliphaunt_wasix::tools::PsqlOptions = options; - fn assert_tool_error() {} - assert_tool_error::(); - - fn direct_tool_surface(database: &mut Oliphaunt) { - let _: Result<_> = database.pg_dump(oliphaunt_wasix::tools::PgDumpOptions::new()); - let _: Result<_> = - database.psql(oliphaunt_wasix::tools::PsqlOptions::new().command("SELECT 1")); - } - fn async_tool_surface(database: &AsyncOliphaunt) { - std::mem::drop(database.pg_dump(oliphaunt_wasix::tools::PgDumpOptions::new())); - std::mem::drop( - database.psql(oliphaunt_wasix::tools::PsqlOptions::new().command("SELECT 1")), - ); - } - let _: fn(&mut Oliphaunt) = direct_tool_surface; - let _: fn(&AsyncOliphaunt) = async_tool_surface; -} diff --git a/src/bindings/wasix-rust/moon.yml b/src/bindings/wasix-rust/moon.yml deleted file mode 100644 index 6d9884277..000000000 --- a/src/bindings/wasix-rust/moon.yml +++ /dev/null @@ -1,144 +0,0 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "oliphaunt-wasix-rust" -language: "rust" -layer: "library" -stack: "systems" -tags: ["binding", "wasix", "rust", "postgres", "sdk", "release-product"] -dependsOn: - - id: "shared-test-fixtures" - scope: "development" - - "liboliphaunt-wasix" - - "shared-rust-query-core" - -project: - title: "Oliphaunt Rust WASIX" - description: "Rust binding over the liboliphaunt WASIX runtime." - owner: "oliphaunt" - release: - component: "oliphaunt-wasix-rust" - packagePath: "src/bindings/wasix-rust/crates/oliphaunt-wasix" - -owners: - defaultOwner: "@oliphaunt/wasix-rust" - paths: - "**/*.rs": ["@oliphaunt/wasix-rust"] - "crates/oliphaunt-wasix/**": ["@oliphaunt/wasix-rust"] - "tools/**": ["@oliphaunt/wasix-rust"] - -fileGroups: - code: - - "**/*" - - "!**/*.md" - - "!moon.yml" - - "!release.toml" - -tasks: - compile: - tags: ["quality", "static", "requires-rust"] - command: "cargo check -p oliphaunt-wasix --locked" - env: - CARGO_TARGET_DIR: "target/moon/oliphaunt-wasix-rust/check" - inputs: - - "@group(cargo-workspace)" - - project: "shared-rust-query-core" - group: "sources" - - "@group(code)" - - project: "liboliphaunt-wasix" - group: "crates" - options: - cache: true - runFromWorkspaceRoot: true - - unit-distinct: - tags: ["quality", "unit", "requires-rust"] - script: | - set -e - cargo test -p oliphaunt-wasix --doc --locked - cargo test -p oliphaunt-wasix --doc --locked --features tools - cargo nextest run -p oliphaunt-wasix --locked --profile ci --no-default-features --features extensions,tools,extension-vector --test public_api --no-tests=fail --test-threads=1 - cargo test -p oliphaunt-wasix --locked --no-default-features --features extensions --test runtime_smoke --test client_compat --no-run - env: - CARGO_TARGET_DIR: "target/moon/oliphaunt-wasix-rust/test" - inputs: - - "@group(cargo-workspace)" - - "@group(rust-test-config)" - - project: "shared-test-fixtures" - group: "fixtures" - - project: "shared-rust-query-core" - group: "sources" - - "@group(code)" - - project: "liboliphaunt-wasix" - group: "crates" - options: - cache: true - runFromWorkspaceRoot: true - - unit-shared: - command: "cargo nextest run -p oliphaunt-wasix --locked --profile ci --no-default-features --lib --no-tests=fail --test-threads=1" - env: - CARGO_TARGET_DIR: "target/moon/oliphaunt-wasix-rust/test" - inputs: - - "@group(cargo-workspace)" - - "@group(rust-test-config)" - - project: "shared-test-fixtures" - group: "fixtures" - - project: "shared-rust-query-core" - group: "sources" - - "@group(code)" - - project: "liboliphaunt-wasix" - group: "crates" - options: - cache: true - runFromWorkspaceRoot: true - runInCI: false - - unit: - command: "true" - deps: - - "oliphaunt-wasix-rust:unit-distinct" - - "oliphaunt-wasix-rust:unit-shared" - inputs: [] - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false - - package: - tags: ["package"] - script: | - set -e - rm -rf target/oliphaunt-wasix-rust/package - node src/bindings/wasix-rust/tools/package-source.mjs target/oliphaunt-wasix-rust/package/source - cargo package --manifest-path target/oliphaunt-wasix-rust/package/source/Cargo.toml --allow-dirty --no-verify - cargo package --manifest-path target/oliphaunt-wasix-rust/package/source/Cargo.toml --allow-dirty --list > target/oliphaunt-wasix-rust/package/oliphaunt-wasix.package-files.txt - env: - CARGO_TARGET_DIR: "target/moon/oliphaunt-wasix-rust/package" - inputs: - - "@group(cargo-workspace)" - - "**/*" - - project: "shared-test-fixtures" - group: "fixtures" - - project: "shared-rust-query-core" - group: "sources" - - project: "liboliphaunt-wasix" - group: "crates" - - "/src/sources/toolchains/wasix.toml" - - "/src/bindings/wasix-rust/tools/package-source.mjs" - outputs: - - "/target/oliphaunt-wasix-rust/package/**/*" - options: - cache: true - runFromWorkspaceRoot: true - - qualify: - tags: ["release", "package"] - command: "true" - deps: - - "oliphaunt-wasix-rust:compile" - - "oliphaunt-wasix-rust:unit-distinct" - - "oliphaunt-wasix-rust:package" - inputs: [] - options: - cache: true - runFromWorkspaceRoot: true diff --git a/src/bindings/wasix-rust/tools/package-source.mjs b/src/bindings/wasix-rust/tools/package-source.mjs deleted file mode 100755 index 0b43d7dff..000000000 --- a/src/bindings/wasix-rust/tools/package-source.mjs +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env node -import { cp, copyFile, mkdir, readFile, rm, writeFile } from "node:fs/promises"; -import path from "node:path"; - -export const ROOT = path.resolve(import.meta.dirname, "../../../.."); - -async function copy(source, destination) { - await mkdir(path.dirname(destination), { recursive: true }); - await copyFile(source, destination); -} - -export async function stageWasixRustPackageSource(outputDir) { - const destination = path.resolve(ROOT, outputDir); - const relative = path.relative(ROOT, destination); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - throw new Error(`WASIX Rust package stage must stay inside the repository: ${outputDir}`); - } - - await rm(destination, { recursive: true, force: true }); - await cp( - path.join(ROOT, "src/bindings/wasix-rust/crates/oliphaunt-wasix"), - destination, - { recursive: true, filter: (source) => path.basename(source) !== "target" }, - ); - await cp(path.join(ROOT, "src/shared/fixtures"), path.join(destination, "src/testdata"), { - recursive: true, - filter: (source) => path.basename(source) !== "moon.yml", - }); - await copy( - path.join(ROOT, "src/shared/rust-query-core/query_core.rs"), - path.join(destination, "src/oliphaunt/query_core.rs"), - ); - await copy( - path.join(ROOT, "src/sources/toolchains/wasix.toml"), - path.join(destination, "src/testdata/wasix-toolchain.toml"), - ); - await copy(path.join(ROOT, "LICENSE"), path.join(destination, "LICENSE")); - await copy( - path.join(ROOT, "THIRD_PARTY_NOTICES.md"), - path.join(destination, "THIRD_PARTY_NOTICES.md"), - ); - - const manifest = path.join(destination, "Cargo.toml"); - const text = `${(await readFile(manifest, "utf8")).replace( - /,\s*path\s*=\s*"[^"]+"/gu, - "", - ).trimEnd()}\n\n[workspace]\n`; - await writeFile(manifest, text, "utf8"); - return manifest; -} - -if (import.meta.main) { - const output = process.argv[2] ?? "target/oliphaunt-wasix-rust/package/source"; - console.log(path.relative(ROOT, await stageWasixRustPackageSource(output))); -} diff --git a/src/bindings/wasix-ts/ARCHITECTURE.md b/src/bindings/wasix-ts/ARCHITECTURE.md deleted file mode 100644 index b468a7ee7..000000000 --- a/src/bindings/wasix-ts/ARCHITECTURE.md +++ /dev/null @@ -1,655 +0,0 @@ -# WASIX TypeScript binding architecture - -## Boundary - -`src/bindings/wasix-ts` is one public TypeScript API over two host adapters. -The package export conditions, not a runtime option, select the adapter: - -```text -browser/default node/bun/deno/electron - | | - v v -patched Wasmer JavaScript host napi-rs, Node-API 8 addon - | | -portable liboliphaunt-wasix Rust actor, direct, Worker, server - `---------------------+----------------' - v - shared TypeScript database API -``` - -The browser adapter owns the portable runtime/seed descriptors and dynamic -extension carrier installation. The server adapter owns no Wasmer JavaScript -fallback: it loads one exact, prebuilt platform carrier whose Rust dependency -embeds the runtime, AOT objects, cluster seed, tools, and supported extension -catalog. Both execute the canonical WASIX guest and preserve its physical -database and backup formats. - -This boundary deliberately does not depend on `src/sdks/js`, -`liboliphaunt-native`, `node-direct`, or the broker. The N-API product wraps the -WASIX Rust binding; it is not a route into the native PostgreSQL SDK. - -Protocol and typed-query helpers are exact mirrors of `src/shared/js-core`. -That is a shared semantic source, not a dependency on the native TypeScript -product. - -The patched Wasmer host under `host/` is a browser-only implementation -dependency of this binding, not another Oliphaunt runtime product. Browser -PostgreSQL binaries, PGDATA, and the canonical runtime manifest remain owned by -`liboliphaunt-wasix`; each extension product owns its separately versioned -portable carrier envelope. The N-API release embeds the corresponding frozen -artifacts instead of resolving those bytes during application startup. - -The canonical guest also owns the backend-only single-backend spinlock and -scalar-atomic specializations carried by PostgreSQL patches 0035 and 0036. -They follow the guest into the Rust binding's AOT artifacts and the portable -module used by the browser. They are not a TypeScript host optimization. -Frontends, PGXS side modules, and concurrent PostgreSQL builds retain the normal -atomic implementation. Each adapter asserts the shared -`OLIPHAUNT_WASIX_SINGLE_BACKEND=1` concurrency invariant and denies guest -process and thread creation under it. Browser root and `/worker` use the same -Oliphaunt export driver. Native-host root, `/direct`, `/worker`, and `/server` use the -same Rust WASIX semantics with different explicit owners. Placement changes -ownership and hop count, not the PostgreSQL protocol contract. - -## Browser lifecycle - -`Oliphaunt.open()` from the root package uses the host driver in the importing -realm: setup is asynchronous, but PostgreSQL lifecycle and protocol exports run -in that realm and may monopolize its event loop while active. `Oliphaunt.open()` from -`@oliphaunt/wasix-ts/worker` creates one package-owned module Worker around the -same driver. There is no public placement option and neither entrypoint falls -back to the other. Both share one database state machine, mount -construction, PostgreSQL configuration, extension/role setup, and storage -contract. Immutable preparation and compiled modules are cached by verified -runtime identity, while writable `Directory` mounts and storage leases are -recreated for every open. Each handle remains one serialized PostgreSQL -session. Only the root entrypoint contends for its caller's event loop. - -The pinned host currently instantiates dynamically loaded native side modules -synchronously. Chromium refuses Window-realm modules above 8 MiB, so the root -entrypoint fails early there for a selected carrier above that threshold. The -explicit `/worker` entrypoint and the root imported from a Dedicated Worker are -outside that Window restriction and apply descriptor-declared native -load order; a real Chrome canary loads PostGIS there and verifies recovery -across its large dependency module. The core guest uses the asynchronous path; -smaller qualified side modules remain supported in a direct Window. - -1. The root entrypoint imports the package-relative host lazily in the caller - realm and creates no Worker. `/worker` creates one module Web Worker per open - and a temporary Worker for restore. -2. The binding resolves the default `@oliphaunt/liboliphaunt-wasix` descriptor - internally. The selected realm fetches or receives its canonical manifest, runtime, - and cluster-seed `.tar.zst` artifacts as one product/version identity. Each - uncached identity verifies descriptor sizes and hashes plus the manifest's - core/module and PostgreSQL/source identity; every open uses that exact - verified identity. Imported extension descriptors add their exact carrier - closure. -3. The selected realm safely expands the core artifacts and overlays only each - extension carrier's install-contract files into separate `/bin`, `/lib`, `/share`, - writable `/base`, `/home`, and `/tmp` Wasmer memory mounts. Before `/base` is - materialized, a storage provider lease supplies either the packaged cluster - seed or an exact-compatible persistent PGDATA. The source-pinned - host adds ephemeral `/dev/shm` and a real Wasmer `RandomFile` at - `/dev/urandom`. Its narrow `Directory` mutation journal records successful - writes and truncates through already-open descriptors as well as file, - directory, remove, and rename paths for either execution surface and every provider. - Both execution surfaces pass the verified precompiled main module and its original - bytes to `instantiateOliphauntDirect`. The root keeps the resulting Store in - the caller realm; `/worker` keeps it in its package Worker. -4. Both execution surfaces push protocol bytes through guest-owned reusable input - and output buffers. The host writes requests directly into canonical guest - memory and returns one owned JavaScript response copy, so PostgreSQL can - safely reuse or grow its memory after the call. Startup preserves an - `ErrorResponse` and its SQLSTATE even when startup terminates the guest. -5. The direct export driver completes the exported startup transition before - exposing the session. Selected carriers contribute verified artifacts and - required startup/preload configuration only; database-local extension SQL is - application/ORM-owned. A requested non-default user is selected from existing - roles with `SET ROLE`; standalone bootstrap remains the fixed `postgres` - identity. -6. The binding frames later responses through `ReadyForQuery` and exposes - serialized `query`, `execute`, buffered `execProtocolRaw`, callback - `execProtocolRawStream`, and callback-scoped `transaction` calls - through one database contract. The same contract supports explicit - `close()` and `await using` disposal. - Every successfully completed protocol operation reaches `ReadyForQuery`, then - asks a persistent provider to publish only journaled `/base` paths before the - Promise resolves. A callback transaction defers publication for `BEGIN`, its - body, and `COMMIT`/`ROLLBACK`, then publishes exactly once after the confirmed - final boundary. A new persistent synchronous-OPFS root uses a separate internal - full-publication boundary after initialization; it is not a public database - operation. PostgreSQL `CHECKPOINT` remains available through ordinary - `execute`. If a - PostgreSQL `ERROR` crosses the host boundary, the direct host - invokes `PostgresMainLongJmp`, sends and flushes readiness, and continues - through `PostgresMainLoopOnce`. Normal ErrorResponse returns receive the same - top-level cleanup as trapping errors. -7. `close` establishes a terminal admission cutoff and lets already accepted - database work drain. The direct owner - sends PostgreSQL Terminate through the same direct bridge, deactivates the - embedded lifecycle, and runs its atexit exports synchronously in the owning - realm. A successful close completes the - provider's final persistence boundary. Every outcome attempts provider close, - exclusive-lease release, and entrypoint-owned host-resource release. The - browser `/worker` waits for that close reply and then terminates its already - quiescent Worker; a Node-compatible `/worker` closes its native handle, posts - the reply, and exits itself. The public - handle memoizes that single outcome and becomes closed after teardown settles; - a rejected close never advertises the destroyed owner or guest as reusable. - If the isolated owner terminates independently, shared session state makes the - public handle closed immediately and prevents later work from crossing the - dead transport. An explicit close still memoizes and reports that terminal - failure while completing package-owned resource cleanup. -8. Each public database handle registers an opaque generation token for - best-effort forgotten-handle recovery. The finalizer holds no reference to - the public owner and only schedules work after returning. It atomically - claims the exact still-active generation, then schedules the same best-effort - close for that root, direct, or `/worker` generation. Explicit close - unregisters the generation before teardown, so queued stale finalizers are - harmless and cannot affect a later database. - -Stock Wasmer's public browser API exposes streams and process completion, but -not arbitrary guest exports. The source-pinned host deliberately adds only the -narrow Oliphaunt export driver needed to match the Rust WASIX lifecycle; it is -not a general synchronous WASIX process API. Generic Wasmer process streams -remain upstream behavior and are not part of the TypeScript database surface. - -## Node, Bun, Deno, and Electron lifecycle - -Native-host conditions load one Node-API 8 addon. The root constructs -`NativeWasixActorDatabase`, which directly owns the Rust `AsyncOliphaunt` -database actor. Bounded admission is synchronous, PostgreSQL runs on its one -Rust owner thread, and completion settles the existing Promise on the importing -JavaScript thread. This is the responsive default and adds one native queue hop. - -The conditional `/direct` export constructs `NativeWasixDatabase` around -synchronous `oliphaunt_wasix::Oliphaunt` on the importing JavaScript thread. It -has the fewest hops and can block that event loop. The conditional `/worker` -export creates one real package-owned Node-compatible Worker, which loads the -same `/direct` implementation inside that Worker. It adds the requested -JavaScript RPC hop and realm isolation without a child process or a second Rust -owner thread. Native direct handles remain creator-thread-affine. - -Close establishes one admission cutoff. The actor drains accepted work and -settles its terminal completion. Direct close runs on its owning thread. A -package Worker closes its native database at quiescence, posts the close reply, -then closes its parent port and exits itself; the parent does not terminate a -Worker across an active Node-API frame. An unexpected Worker exit rejects -pending work and leaves the public handle terminal. - -Query serialization, close semantics, the memory default, storage identity, -and public errors remain TypeScript-owned. Descriptor validation also remains -shared, but native release addons resolve validated extension SQL names against -their compile-time catalog instead of expanding portable extension archives at -open. - -IndexedDB and OPFS remain browser-only and are rejected before a native-host -actor, direct, or Worker session starts. Directory persistence is exposed through matching -`storage/node`, `storage/bun`, and `storage/deno` entrypoints. They preserve the -shared managed-root descriptor and exclusive path ownership while Rust owns -the database bytes and durability. No host falls back to native -`@oliphaunt/ts`. Direct and explicit `/worker` entrypoints may themselves -be imported from an application-owned worker thread. Rust holds one OS advisory -lock for the managed-root lifetime, shared with direct Rust owners. There is no -JavaScript marker lock to recover. Callers should still close before externally -terminating their own realm. - -## Protocol streams, tools, and local endpoints - -The public callback stream reuses the guest's COPY-aware synchronous transport -and emits at most 64 KiB per callback. Browser root and native `/direct` invoke -the callback in their owning JavaScript realm. Browser and native-host -Workers block only their Worker with a shared-memory acknowledgement until the -importing-realm callback returns. The native actor uses a napi-rs thread-safe -function with queue size one and waits for each JavaScript acknowledgement. -Every path therefore preserves bounded backpressure and callback ordering. - -Direct native requests borrow JavaScript input for the duration of their -synchronous call. Actor requests copy into owned Rust admission data before the -call returns. All native responses, backup archives, chunks, and tool output are -ordinary V8-owned typed arrays with predictable detach and lifetime behavior. -The Worker transport transfers eligible response `ArrayBuffer` values directly; -there is no external-buffer finalizer crossing an isolate or environment exit. - -A callback returning a Promise or thenable is rejected: asynchronous -completion cannot acknowledge this synchronous backpressure contract, and the -PostgreSQL session is poisoned conservatively. The callback is also an -ownership boundary: it cannot queue work through the same database or -transaction while that database is waiting for the chunk acknowledgement. Such -reentry fails immediately instead of creating a hidden post-stream operation. - -`@oliphaunt/wasix-tools` remains the optional public facade. In a browser it -resolves the separately published `@oliphaunt/liboliphaunt-wasix-tools` asset -carrier. `pg_dump` runs in the realm that already owns the database; `psql` -uses a separate persistent browser tool worker because COPY input is genuinely -full duplex. Its private pgwire connection has fixed, bounded shared-memory -rings. - -Native release addons compile both frontends and the current extension catalog -into every platform binary. Node.js, Bun, Deno, and Electron route `pg_dump` and -`psql` through the existing Rust database owner on root, `/direct`, or `/worker` and do -not resolve portable tool bytes at invocation time. This intentionally trades -larger platform packages and a coordinated carrier release for fewer startup -reads, decompressions, compilation steps, and runtime compatibility edges. - -The package export `@oliphaunt/wasix-ts/internal/tools` exists only so the -version-matched `@oliphaunt/wasix-tools` package can reach this bridge. It is not -an application API or part of the stable SDK surface, is undocumented for app -consumers, and may change only in lockstep with that companion package. Package -checks reject any other low-level query or protocol subpath exports. - -The database session is exclusively serialized. It resets PostgreSQL with -`ROLLBACK`, `DISCARD ALL`, and the configured role before and after a tool, then -publishes storage once after the final safe cleanup boundary. An uncertain tool -transport outcome poisons the handle after making its stored state safe. The -tools remain outside the core public database surface on both adapters. - -The host-only `/server` subpath uses conditions to export the same implementation -for Node, Bun, Deno, and Electron. It has no browser or default condition. The implementation -constructs the Rust `OliphauntServer` through the same addon rather than -adapting a JavaScript socket relay. It binds one loopback TCP or -PostgreSQL-named Unix listener and serves one active client. Another connection -may wait in the operating-system backlog, so consumers configure pools with a -maximum size of one. Each admitted connection receives a fresh embedded -backend. Server state, listener lifetime, and storage publication are -Rust-owned; the TypeScript facade retains the -existing Promise-shaped open/close and `closed` contract. The concurrent WASIX -postmaster remains a separate runtime product rather than a mode of this -single-backend SDK. - -## Browser storage boundary - -Storage is a binding-owned provider/lease contract rather than runtime asset -configuration: - -```text -opaque storage descriptor - | - v - acquire provider lease ---- exact physical compatibility - | - +---- synchronous OPFS /base ---- exact-range file I/O - | - `---- portable /base ------ journaled publication - | - v - PostgreSQL boundary + release -``` - -The main package owns the fresh-memory descriptor and default. IndexedDB and -OPFS are selective `./storage/indexed-db` and `./storage/opfs` entrypoints whose -implementations load only when an opaque descriptor reaches the owning -realm. Raw serialized descriptors are not accepted from consumers. The -internal lease exposes `state`, one initial PGDATA mount, -an optional synchronous PGDATA materializer, `sync(directory, boundary)`, and -`close(directory, outcome)`; it does not own runtime or extension assets. - -The source-pinned Wasmer `Directory` exposes a compact current-state mutation -journal. Write-capable files are wrapped so a PostgreSQL descriptor retained -across multiple operations records every later write, not only its initial -open. The shared portable delta layer drains the journal only at -PostgreSQL-safe host boundaries, collapses overlapping paths, reads changed -files and subtrees, and expresses removals explicitly. A provider without that -host capability falls back to a full scan, so correctness does not depend on -the optimization. Synchronous OPFS mounts bypass mutation tracking and serve the -guest synchronously in its owning worker. Process-lifetime `postmaster.pid` and -`postmaster.opts` never enter persistent storage. - -Each logical IndexedDB name owns a separate physical IndexedDB database with -fixed metadata and one row per PGDATA path. Each boundary applies upserts and -removals in one atomic read-write transaction using the browser's default -commitState policy; an aborted write leaves the preceding generation intact, -and distinct logical databases do not share an object-store transaction. OPFS -stores a strict logical namespace and physical identity over flat backing files. -`/worker`, and the root inside a Dedicated Worker, preopen synchronous access -handles and perform exact-range guest I/O without a mailbox or nested worker. A -direct Window uses the portable path. Guest file flushes are immediate; -operation boundaries drain WAL; internal full-publication, close, and namespace publication -flush WAL before ordinary files and `global/pg_control`. The portable path uses -copy-on-write backing files and atomically replaces namespace state last. OPFS -has PostgreSQL recovery ordering but no cross-file transaction, so a failed -publication reports unknown state instead of claiming that nothing changed. -The synchronous path keeps a bounded private reserve of preopened backing files for -the synchronous hot path. Overflow is staged only until the mandatory host -boundary, which allocates, writes, and flushes every staged file before -publishing namespace state. A failure leaves the previous namespace -authoritative and poisons the live handle. The reserve is replenished -best-effort after successful boundaries, and hosts that cannot establish its -initial capacity use the portable path. Its size is an implementation detail, -not a public database-capacity limit. - -Compatibility uses the PostgreSQL major and versioned WASIX physical format. -Runtime hashes and source fingerprints still reject mixed runtime, cluster-seed, -AOT, and extension build outputs, while package and carrier changes do not -rewrite the managed-root descriptor or reject an unchanged physical format. -Safe extension upgrade or removal remains an explicit migration concern rather -than a reason to reject every change in the available carrier set. -Cross-binding root handoff is not a supported or qualified workflow. - -Persistent databases use an origin-scoped exclusive Web Lock. This preserves -the single-owner invariant rather than suggesting that one single-user -PostgreSQL backend represents independent connections. There is no leader -proxy or multi-tab transaction ownership yet. - -Provider acquisition and PGDATA materialization happen before PostgreSQL -starts. Provider boundaries happen only after pgwire recovery returns -`ReadyForQuery`, so ordinary PostgreSQL errors retain their existing -`PostgresError` identity. A host persistence failure is instead a typed storage -error and poisons the live handle: guest state may be ahead of confirmed durable -storage, so retrying the application operation is not known to be safe. - -## Selective extension descriptor contract - -The consumer API accepts exact structural values rather than SQL strings: - -```ts -type WasixExtensionDescriptor = { - schema: 'oliphaunt-wasix-extension-v1'; - runtime: 'wasix'; - product: string; - version: string; - compatibility: { - extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1'; - postgresMajor: string; - wasixRuntimeProduct: 'liboliphaunt-wasix'; - wasixRuntimeVersion: string; - }; - sqlName: string; - carriers: readonly { - product: string; - version: string; - sqlName: string; - archive: string; - sha256: string; - size: number; - source: string | URL | ArrayBuffer | Uint8Array; - install: { - schema: 'oliphaunt-wasix-extension-install-v1'; - dependencies: readonly string[]; - coreExportsRequired: readonly string[]; - // exact native-module, lifecycle, and installed-file projections - }; - }[]; -}; -``` - -This is structural rather than nominal so a generated extension package can be -dependency-free; it does not import the host binding merely to acquire a brand. -The literal `runtime: 'wasix'` still makes native descriptors statically -incompatible with non-WASIX extension descriptors, and the client -runtime-validates the complete shape. -The binding keeps an internal validation/freezing helper for fixtures. It is not -part of the consumer entrypoint and generated packages do not depend on it. - -Generated leaf packages can point at their package-owned payload without any -host conditional: - -```ts -const carrier = { - source: new URL('./extensions/pgtap/extension.tar.zst', import.meta.url), - // product, version, SQL identity, archive key, hash, and size -} as const; -``` - -The development Vite harness derives virtual package descriptors from the current -canonical target outputs and uses development route strings while serving those -exact artifacts directly. - -Each descriptor selects only its root `sqlName`. Its carrier array is a -dependency-complete byte closure, not an alternate dependency declaration. The -client validates each root's exact dependency closure, unions closures in -deterministic SQL-name order, deduplicates shared rows only when their complete -identity/install/compatibility metadata agrees, and rejects repeated rows, -duplicate roots, or conflicts. The selected realm resolves dependencies solely from -the imported install contracts, treating only the stripped core manifest's -`runtime-support` entries as runtime-provided. Before reading extension bytes, -it gates every carrier on the selected WASIX runtime version, PostgreSQL major, -extension-runtime contract, and required names in `runtime.link.exports`. It -then verifies each archive's declared size/hash and overlays exactly its -carrier-owned installed-file inventory. The core manifest is required to have -`extensions: []` so it cannot quietly reclaim optional extension ownership. - -That byte-closure processing is the browser implementation. Node.js, Bun, Deno, -and Electron retain the same public descriptor and perform its structural/runtime -validation, but pass only the validated, dependency-ordered SQL names across -the N-API boundary. The Rust runtime resolves those names against the exact -extension features compiled into the release carrier. Unknown names fail; the -addon never treats arbitrary descriptor bytes as native code. A new or upgraded -extension can ship independently for browsers, but it becomes available to -native-host consumers only after the N-API product is rebuilt and released -with that feature. - -## Host compatibility - -The host is rebuilt from source rather than maintained as hand-edited generated -JavaScript/WASM. `host/source.toml` pins the Wasmer JS Git source and Cargo -crates; the adjacent patches are the reviewable compatibility delta. The build -lands first in `target/oliphaunt-wasix-ts/host`. Public package staging copies -the exact JS module, worker module, WebAssembly module, license, and provenance -into `lib/host`; the browser root imports the host in the caller realm, while -the browser `/worker` imports it in its package Worker. Node.js, Bun, Deno, and Electron -conditions do not import this module. - -This is not a general backport of WASIX 0.702 to Wasmer 0.601. The authoritative -patch order is the `series` in `host/source.toml`; this document records the -resulting invariants instead of duplicating that filename inventory. Together, -the patches: - -- honor configured args, environment, mounts, cwd, and stdio; preserve original - module bytes where the generic blocking worker needs them; and repair the - pinned npm/toolchain inputs without mutating their lock; -- provide only the 0.702 compatibility imports and runtime devices required by - the shipped guests, reject unavailable fork/context/thread/process behavior, - remove the retired Rust target, and recognize standard WebAssembly exception - reference types; -- make oversized main-module construction asynchronous through the builder and - linker while keeping the returned database driver synchronous and rejecting - unsupported oversized side modules before open; -- enforce the single-backend profile, use correct realtime and monotonic clocks, - amortize bounded pending-work checks, and avoid turning synchronous-file POSIX - close into an implicit fsync that bypasses PostgreSQL durability policy; -- expose the current-state mutation journal and the narrow caller-realm - synchronous filesystem bridge used by synchronous OPFS, without reviving the old - mailbox transport; -- provide the caller-realm PostgreSQL lifecycle and reusable-memory pgwire - driver, including COPY-aware callback streaming, top-level error recovery, - and a bounded 16 KiB failure-only stderr tail; and -- run only the packaged PostgreSQL frontend tools through a fresh caller-realm - WASIX process with captured stdio and synchronous pgwire callbacks. This path - uses neither the generic Wasmer scheduler worker nor a Web Streams pump. - -The clock specialization is intentionally narrower than a general syscall -shortcut. Realtime uses the JavaScript epoch clock, while monotonic reads -calibrate the host's monotonic clock against the canonical Rust fallback epoch, -so fast and fallback reads cannot jump between domains. Process and thread CPU -clocks remain on the canonical fallback because wall time is not an equivalent -clock. Synthetic clock offsets remain honored by declining the direct import -for guests that import `clock_time_set`, and pending WASIX operations are -checked on a real-time bound. Invalid clock IDs, pointers, or host values use -the complete Rust syscall. Other WASIX programs retain the complete upstream -per-call path. - -The exact pairing is qualified for the single-process direct Oliphaunt export -path in both execution surfaces, including repeated PostgreSQL `ERROR` recovery. The -direct driver treats every `PostgresMainLoopOnce` trap as the guest's exported -top-level recovery boundary and also cleans up non-trapping ErrorResponses. -Its JavaScript memory bridge is limited to the direct Oliphaunt driver: generic -WASIX streams keep their normal ownership and scheduling semantics. Copy failures -are caught before guest buffers are released, and protocol responses are copied -once into owned JavaScript storage rather than exposed as mutable guest views. -Browser qualification loads and calls PostGIS in a real worker and asserts that -its dependency side module exceeds Chromium's 8 MiB main-thread compilation -limit; the exemption is therefore attached to the worker realm, not to an -extension name or a benchmark payload size. -This remains an integration contract with the pinned Oliphaunt runtime rather -than a generic Wasmer guarantee. -Missing WASIX context switching is a broader compatibility gap, but is not part -of this PostgreSQL recovery path. Ordinary package resolution never selects -stock `@wasmer/sdk`; the published binding owns the source-pinned host. A larger -current-Wasmer JS port is outside this host's compatibility contract. - -The version skew is upstream-owned rather than a loose Oliphaunt dependency. -The commit referenced by the latest npm `@wasmer/sdk` 0.10.0 release identifies -its checked-in source as 0.8.0 and embeds Wasmer 6.1 with the 0.601 Wasmer -support family. `wasmer-wasix` 0.702.1 embeds Wasmer 7.2.1 and -matching 0.702.1 virtual filesystem/network, package, configuration, backend, -and types contracts. A coordinated compile probe exposed incompatible -`FileSystem` mounting, `TaskWasm`, wasm-bindgen conversion, registry calls, -module hashing, and binary-package construction before the Oliphaunt runner and -recovery changes could be reapplied. Consequently 0.702.1 adoption is a full -source-host port plus browser qualification, not an isolated crate bump. -`host/source.toml` records the intentionally coherent 0.601 source family until -that port exists. - -## PGlite reference, not product inheritance - -PGlite independently validates the recovery shape used here. Its Emscripten -guest turns the active PostgreSQL top-level `longjmp` into a known exit status; -the TypeScript host then calls `PostgresMainLongJmp`, sends readiness, flushes, -and resumes `PostgresMainLoopOnce`. Its public database error is separately -decoded from pgwire. See PGlite's -[runtime loop](https://github.com/electric-sql/pglite/blob/67872123b637ba132cceb8dbb3f739a09685ee87/packages/pglite/src/pglite.ts#L932-L965) -and [guest shim](https://github.com/electric-sql/postgres-pglite/blob/7b4ee5086055dc5e54ae1e13e487888249438e68/pglite/src/pglitec/pglitec.c#L52-L84). -Oliphaunt deliberately uses an environment-gated Wasmer exception discriminator -instead of Emscripten's numeric sentinel, but preserves the same separation -between control-flow recovery and the pgwire `PostgresError` seen by callers. -Lifecycle SQL for a selectively imported extension runs in the owning realm. -Isolated-host errors are serialized by PostgreSQL field and rebuilt in the caller; -direct errors retain the same `PostgresError` identity in place. Generic -transport errors retain their name, message, and owner-side stack. Neither path -collapses SQLSTATE and diagnostics into a generic error. - -PGlite is also a useful ordering reference: it stages extension archives and -precompiles Emscripten side modules before PostgreSQL starts. Those -`MAIN_MODULE`/`SIDE_MODULE` binaries are not WASIX carriers, however, and its -filesystem persistence is coupled to Emscripten FS. - -The browser benchmark also exposed a preparation asymmetry: PGlite reused -precompiled modules while each WASIX open recompiled the verified guest bytes. -Caller-realm execution now bounds and keys immutable preparation and compiled-module -caches by exact runtime/carrier/GUC identity. Mutable directories and storage -leases never enter those caches. The checked-in insert benchmark compares WAL -volume alongside timing; separate root-cause diagnostics compare buffer -activity and relation sizes. Both keep host/runtime overhead visible without -changing PostgreSQL work or commitState settings. - -This binding keeps the following deliberate divergences: - -- extension lifecycle and install metadata comes from each selectively imported - `-wasix` package; the stripped runtime manifest cannot override it; -- runtime/PGDATA/manifest hashes, carrier hashes, required core exports, exact - installed-file inventories, dependencies, and collisions are checked before - startup; -- selecting an extension stages its verified artifacts and startup configuration; - applications explicitly run ordinary `CREATE EXTENSION`, `LOAD`, schema, or - migration SQL, matching the ownership expected by ORMs; and -- IndexedDB and OPFS now use source-pinned dirty-path synchronization at each - completed protocol operation, matching PGlite's useful commitState boundary - without importing Emscripten FS. Oliphaunt keeps explicit provider-specific - atomicity and exclusive ownership; multi-tab leadership remains unsupported. - -The host validates every native `load-order` entry against the carrier's exact -installed-file inventory but does not execute it as SQL. Applications explicitly -issue any required `LOAD`/`CREATE EXTENSION` lifecycle, after which PostgreSQL and -Wasmer's dynamic linker remain responsible for each module's declared -`dylink-needed` closure. `shared-memory-required` contracts remain rejected -because the single-backend runtime has not qualified that capability. - -## Asset ownership - -The `@oliphaunt/wasix-ts` tarball does not contain PostgreSQL binaries. Browser -conditions import `@oliphaunt/liboliphaunt-wasix`, whose generated descriptor -points at package-owned runtime, PGDATA, and manifest assets. There is no public -raw runtime-source override. Development reads -`target/oliphaunt-wasix/assets`, produced by -`liboliphaunt-wasix:runtime-portable`, through the browser example's Vite -plugin, which models that generated carrier. - -Node.js, Bun, Deno, and Electron also receive one target-filtered optional dependency. -The public carriers are -`@oliphaunt/wasix-napi-darwin-arm64`, -`@oliphaunt/wasix-napi-linux-arm64-gnu`, -`@oliphaunt/wasix-napi-linux-x64-gnu`, and -`@oliphaunt/wasix-napi-win32-x64-msvc`. Each has no install script and contains -one `oliphaunt_wasix_napi.node` binary with both standard and ICU profiles. The private -`@oliphaunt/wasix-napi` product coordinates the Rust build and carrier release; -applications never import it. - -Linux carriers are GNU/glibc-only. The adapter identifies libc from the -runtime diagnostic report before resolving package-adjacent, optional, or -explicit addon paths; known musl and unknown libc identities fail closed. - -Native release builds embed the runtime, seed, AOT objects, frontend tools, and -complete currently supported extension feature set. Optional extensions remain -exact, separately imported `-wasix` packages at the public TypeScript boundary, -but native hosts use their descriptor identity to select compiled-in artifacts -instead of copying the carrier bytes. Their availability is consequently a -release-time N-API contract. - -The source workspace manifest deliberately does not resolve that generated -carrier from npm: the carrier exists only after same-candidate runtime assets -are frozen. SDK release staging injects the exact dependency recorded by -`oliphaunt.runtimeVersion`, validates it, and publishes only that staged -manifest. This keeps fresh frozen workspace installs independent of an -unpublished candidate while making the consumer tarball's browser runtime edge -exact. The same staging step rewrites every native optional dependency to the -exact N-API product version. The loader rejects a carrier whose package name, -version, target, WASIX runtime, addon ABI, Node-API level, or profile inventory do -not match the SDK metadata; the addon then self-reports its runtime and exact -supported profile inventory before open. - -The release runtime carrier owns a stripped core manifest (`extensions: []`). -The development Vite plugin projects the same core-only bytes from the build -pipeline's qualification manifest and derives separate exact extension install -contracts from its extension rows. The binding rejects a nonempty core manifest, -so the runtime carrier cannot become the authority for independently versioned -extensions. - -The first browser smoke selects the SQL-only `pgtap` carrier and explicitly runs -`CREATE EXTENSION`. That isolates manifest verification, dependency ordering, archive overlay, and lifecycle SQL -from dynamic linking. The separate `smoke-browser.mjs --pg-uuidv7` profile selects the -native carrier, calls `uuid_generate_v7()` before and after the two error -recovery cases, verifies both results are UUIDv7 values, and checks clean -process exit. That proves one exact `.so` against the pinned package-owned host; it -does not add or widen a canonical extension target claim. Generic native-module -support remains gated on a safer loader boundary and broader qualification. - -The example's virtual Vite modules model the intended -`@oliphaunt/extension-pgtap-wasix` and -`@oliphaunt/extension-pg-uuidv7-wasix` package roots from current target -outputs. Its asset middleware and COOP/COEP headers are development-only. -Production hosting, cache policy, and asset integrity are application/carrier -concerns; the binding does not silently copy target-owned assets into its npm -bundle. - -## Public package and qualification - -`@oliphaunt/wasix-ts` is a separately versioned public SDK product. It has its own -release metadata and changelog, declares an exact browser dependency on the -published `@oliphaunt/liboliphaunt-wasix` runtime carrier, and declares the four -exact native packages as optional dependencies. It publishes the patched host -under `lib/host` for browser/default conditions. Conditional package exports -choose browser, Node.js, Bun, Deno, or Electron adapters. Browser root remains -caller-owned; the native-host root uses the Rust actor, `/direct` is caller-owned, and -the conditional `/worker` subpath is owned by its isolated Worker. - -The browser smoke proves the exact runtime/host pairing can start PostgreSQL, -explicitly activate `pgtap`, retain SQLSTATE across repeated PostgreSQL error recovery, -continue with `42` on the same handle, persist through IndexedDB operation -boundaries, run an explicit `CHECKPOINT` through `execute`, and close with a -successful zero exit status. Each Node.js, Bun, Deno, and Electron host smoke installs the -packed SDK and matching packed platform carrier into a fresh external project, -verifies conditional-export and profile selection, starts the embedded -WASIX Rust runtime, activates a compiled extension, recovers from an error, and -closes cleanly. Each carrier also runs a real actor Simple Query roundtrip and -proves its V8-owned response buffer is transferable; Node additionally proves -direct and local-server lifecycles. The Deno proof uses local `node_modules` -with explicit read, environment, and FFI permissions and qualifies the declared -Deno CLI range, not managed Deno Deploy. Electron additionally qualifies the -ASAR-unpacked native-addon layout. The opt-in native browser profile -additionally loads and calls the canonical `pg_uuidv7.so`; it remains a narrow -canary rather than a generic dynamic-extension claim. - -The intentional host, persistence, extension, and Wasmer compatibility limits -remain listed in [README.md](./README.md). They are explicit product boundaries, -not compatibility aliases or fallbacks to a native SDK. diff --git a/src/bindings/wasix-ts/README.md b/src/bindings/wasix-ts/README.md deleted file mode 100644 index 095a6f9ff..000000000 --- a/src/bindings/wasix-ts/README.md +++ /dev/null @@ -1,404 +0,0 @@ -# `@oliphaunt/wasix-ts` - -Portable PostgreSQL 18 for TypeScript. Browser conditions run the canonical -`liboliphaunt-wasix` guest through the patched Wasmer JavaScript host. Node.js, -Bun, Deno, and Electron conditions run the same WASIX runtime through a Rust -Oliphaunt Node-API addon. The public TypeScript API is shared by both hosts. - -In browsers the root owns PostgreSQL in the importing JavaScript realm. On -native hosts the root uses a dedicated Rust owner thread. The explicit -`/direct` import runs synchronously in the importing realm, while `/worker` -uses a separate JavaScript Worker on every runtime. - -## Install - -```sh -pnpm add @oliphaunt/wasix-ts -``` - -The published SDK is one universal browser-and-server package. Its browser host -files and exact `@oliphaunt/liboliphaunt-wasix` dependency are therefore -installed on Node.js, Bun, Deno, and Electron too, although native export -conditions never load them. The matching target-filtered optional platform -package embeds the runtime, both cluster profiles, tools, and qualified -extension catalog used on those hosts. Carrier packages have no install scripts -and do not download a binary at install or first use. Applications do not -configure raw runtime assets. - -Published Node-API 8 carriers currently cover: - -- macOS arm64; -- Linux arm64 and x64 with glibc; and -- Windows x64 with MSVC. - -There is no published carrier yet for macOS x64, Linux musl, or Windows arm64. -The native loader detects Linux libc before resolving a carrier and explicitly -rejects musl or an unidentifiable libc; it cannot load a `-gnu` carrier through -an override on an unsupported host. Opening a database on another server target -fails with an explicit unsupported-platform error rather than falling back to -the browser Wasmer host. - -Deno must resolve the npm package through a local `node_modules` directory and -must be granted `--allow-ffi`, `--allow-read`, and `--allow-env` in addition to any filesystem -permissions the application needs. The `/worker` entrypoint uses Deno's -Node-compatible Worker implementation and does not spawn a process. The package -smoke uses explicit host permissions. The qualified Deno surface is -the Deno CLI version declared by this package; managed Deno Deploy is not -currently a qualified distribution target. - -Electron applications that use ASAR should leave `**/prebuilds/**` unpacked and -ship the generated `app.asar.unpacked` directory beside `app.asar`. This keeps -the addon and any platform loader companions, including the Windows app-local -VC runtime, in one loadable directory. Electron can temporarily extract a -packed native module, but the unpacked layout avoids that startup overhead and -antivirus interaction. Carrier qualification loads the addon from this -packaged layout and proves that a missing unpacked companion fails explicitly. - -Optional ICU data and its matching `icu` seed are selected explicitly: - -```ts -import Oliphaunt from '@oliphaunt/wasix-ts'; -import icu from '@oliphaunt/wasix-icu'; - -await using database = await Oliphaunt.open({ icu }); -``` - -Browser conditions load the ICU assets from their portable carrier. Each -native platform carrier contains one addon with both `standard` and `icu` -profiles, and the existing `icu` option selects the database profile. The loader checks -the exact SDK/carrier version, WASIX runtime version, addon ABI, Node-API level, -target, and ICU profile before running native code. - -## Query PostgreSQL - -```ts -import Oliphaunt from '@oliphaunt/wasix-ts'; - -await using database = await Oliphaunt.open(); - -await database.execute('create table todo (title text not null)'); -await database.execute('insert into todo values ($1)', ['ship it']); - -const result = await database.query( - 'select title from todo where title = $1', - ['ship it'], -); -console.log(result.rows[0]?.title); -``` - -`execute` asserts one command with no rows. `query` accepts command-only or -row-producing SQL and defaults to decoded object rows; array rows, text value -mode, and immutable per-query OID codecs are available. Object mode rejects -duplicate field names; use `rowMode: 'array'` to preserve them positionally. -`queryRaw` retains ordered nullable bytes and complete field metadata. `exec` returns ordered -simple-query results, while `describe` resolves parameter OIDs and optional -result fields without executing. Structured operations preserve command -metadata and ordered notices. - -Safe scalar parameters are resolved and encoded inside one owned operation. -Use `text`, `binary`, `typedNull`, `json`, or `array` with `postgresOids` for a -deterministic type, or an immutable per-query encoder for an extension OID. -Unsupported and mismatched values fail rather than being guessed. - -`execProtocolRaw` is the buffered PostgreSQL frontend-protocol escape hatch. -`execProtocolRawStream` delivers the same response through a synchronous -callback. Every surface invokes it serially with at most 64 KiB per chunk and -waits for it to return before producing the next chunk. Direct sessions invoke -the callback inline; the native actor and Worker paths use bounded -acknowledgements across their existing thread boundary. COPY-sized responses -therefore need not be retained as one JavaScript value. A thrown callback, including -the deterministic error for returning a Promise or thenable, is rethrown -unchanged only after the guest confirms recovery to `ReadyForQuery`; the -recovered database remains reusable. An asynchronous callback cannot provide -this backpressure contract. -The callback also cannot reenter the same database or transaction; -fire-and-forget calls are rejected instead of being queued behind the stream. -Neither method interprets responses for the caller. A buffered raw rejection, -or a streamed execution, transport, or recovery failure, poisons the handle and -takes precedence over a simultaneous callback error; close it and open a new -database instead of assuming the physical session recovered. - -PostgreSQL `ErrorResponse` values reject with `PostgresError`, including the -SQLSTATE and structured diagnostic fields. - -## Transactions - -```ts -await database.transaction(async (transaction) => { - await transaction.execute('insert into todo values ($1)', ['inside transaction']); - return transaction.query('select count(*)::int4 as count from todo'); -}); -``` - -The callback exclusively owns the session from `BEGIN` through its final -boundary. It mirrors query/raw query, execute, exec, and describe; database-level -operations reject while it is active. One-shot `rollback()` closes the -transaction and lets the callback return without a later commit. - -Raw protocol is database-only and deliberately absent from the callback handle. -Do not issue manual `BEGIN`, `START TRANSACTION`, `COMMIT`, `END`, `ABORT`, -`PREPARE TRANSACTION`, or `AND CHAIN` inside the callback; return/throw or call -`rollback()` instead. `SAVEPOINT` and `ROLLBACK TO` are supported. `ROLLBACK AND -CHAIN` is unsupported contract misuse and has the same PostgreSQL wire -tag/readiness state as `ROLLBACK TO`, so the SDK rejects `ROLLBACK`/`ABORT ... -AND CHAIN` before dispatch and still validates every actual protocol boundary. -A proven ownership escape makes the database close-only and never causes a -speculative SDK `COMMIT` or `ROLLBACK`. - -Callback failures trigger a best-effort `ROLLBACK`. Once `COMMIT` has been -sent, the binding never sends a second rollback. PostgreSQL's clean `ROLLBACK` -response is a known aborted outcome; a transport failure or malformed response -after `COMMIT` makes the outcome unknown and poisons the handle until close. -Persistent publication completes before a successful transaction resolves. -After rollback and its required publication succeed, the original callback -failure is rethrown unchanged. If the callback and rollback both fail, an -`AggregateError` preserves the callback failure followed by the rollback -failure. If an earlier independent database or protocol failure has already -poisoned or expired transaction ownership and the callback then throws a -different value, an `AggregateError` preserves the callback failure followed by -that database failure; the database is close-only. Ordinary PostgreSQL statement -errors that remain safely rollbackable are not automatically aggregated. - -## Storage - -Omitting `storage` creates a fresh true-memory database. Persistent adapters -are explicit, host-specific imports: - -```ts -import Oliphaunt from '@oliphaunt/wasix-ts'; -import { directory } from '@oliphaunt/wasix-ts/storage/node'; - -const storage = directory('./data/todos'); -let database = await Oliphaunt.open({ storage }); -await database.execute('create table if not exists todo (title text not null)'); -await database.close(); - -database = await Oliphaunt.open({ storage }); -await database.close(); -``` - -Use `storage/bun` or `storage/deno` for those runtimes, and -`storage/indexed-db` or `storage/opfs` in browsers. - -A Node, Bun, Deno, or Electron directory is a managed root with exactly: - -```text -.oliphaunt.json -pgdata/ -``` - -The descriptor records the shared database-root schema, PostgreSQL major, and -WASIX physical format. Runtime source fingerprints and package hashes validate -the asset graph; they are not physical-reopen identity. Native and WASIX roots -are not rejected merely because of the originating family. - -Rust and WASIX TypeScript bindings use the same root and physical-archive -contracts. On Node.js, Bun, Deno, and Electron the Rust runtime holds the managed -root's OS advisory lock for the database lifetime. The same lock protects actor, -direct, Worker, and Rust owners. Always close the current owner before handing a -root to another process, Worker, or binding. - -The Rust host owns directory durability for Node.js, Bun, Deno, and Electron. IndexedDB -publishes a delta in one transaction. OPFS uses synchronous backing files for -`/worker` and when the root entrypoint is imported inside an application-owned -Dedicated Worker. -The root entrypoint in a browser Window uses the same opaque format through a -copy-on-write portable path. Both OPFS paths flush or publish in -PostgreSQL-safe order. A -publication failure rejects with `WasixStorageError`; an uncertain state -poisons the live database handle. - -All native-host entrypoints may be used inside an application-owned Worker, -including with directory storage. Close the database before terminating that -Worker. The lock is owned by the Rust runtime rather than a JavaScript marker -directory, and an orderly package Worker close waits for native quiescence, -posts its terminal reply, and then lets the Worker exit itself. - -`close()` is one terminal, idempotent teardown attempt. It stops admitting new -work and lets work already accepted by the database FIFO finish. The root actor -and `/server` await their Rust owner teardown. `/direct` closes synchronously at -the native boundary. `/worker` closes its direct native session at quiescence, -replies, and self-exits; it is never force-terminated across an active Node-API -frame. Concurrent and later calls return the same promise. Provider, host, and -Worker transport failures are preserved. -If teardown rejects, `closed` still becomes `true`: cleanup was attempted and -a destroyed isolated owner or guest is never treated as a retryable live session. -An unexpected `/worker` crash also makes `closed` true as soon as the transport -observes ownership loss. Later operations fail without posting more work; -`close()` remains idempotent and reports that terminal transport failure while -finishing any remaining package-owned cleanup. - -Forgetting a database handle schedules generation-guarded best-effort cleanup -of only that handle's actor, direct session, or Worker generation. A stale -finalizer cannot affect a later open. Finalizers are not prompt or observable, -so applications must still use `close()` or `await using` when ownership release -matters. - -## Backup and restore - -```ts -const backup = await database.backup(); -await database.close(); - -await Oliphaunt.restore(directory('./data/restored'), backup); -``` - -`backup()` performs PostgreSQL online physical backup without replacing the -session. The archive is the shared strict ustar format containing -`pgdata/**` and `.oliphaunt/backup-manifest.properties`. `restore` accepts only -an absent or empty persistent destination, validates the complete archive -before publication, and creates the receiving storage provider's outer -identity. Browser root restores in its importing realm. On native hosts the -root uses the Rust owner actor, `/direct` restores on the importing JavaScript -thread, and `/worker` uses a temporary package-owned Worker. - -## Extensions - -Import package-authored WASIX extension descriptors and pass them at open: - -```ts -import Oliphaunt from '@oliphaunt/wasix-ts'; -import pgtap from '@oliphaunt/extension-pgtap-wasix'; - -await using database = await Oliphaunt.open({ extensions: [pgtap] }); -await database.execute('CREATE EXTENSION pgtap'); -const version = await database.query('select pgtap_version()'); -``` - -The call shape and lifecycle ownership are host-independent. A browser verifies -the selected carrier and its dependency closure, installs its artifacts before -startup, and applies required startup/preload settings. Node.js, Bun, Deno, and Electron -validate the same descriptor but resolve its SQL name against the extension -catalog compiled into the platform addon. Release addons contain the complete -currently supported extension catalog; they do not load arbitrary side-module -bytes from npm at runtime. Adding or upgrading a server extension therefore -requires a matching N-API carrier release. This increases the carrier size in -exchange for eliminating runtime archive expansion and dynamic linking on the -native path. - -Neither host runs database-local `CREATE EXTENSION`, `LOAD`, schema, -post-create, upgrade, or migration SQL. Applications and ORM migrations own -those ordinary PostgreSQL statements explicitly; selecting a descriptor makes -its code available but leaves the extension uninstalled in the database. - -## Calling shape and execution placement - -The normal import keeps the public API consistent while selecting the safest -default placement for the host: - -```ts -import Oliphaunt from '@oliphaunt/wasix-ts'; - -await using database = await Oliphaunt.open(); -``` - -On Node.js, Bun, Deno, and Electron, use `/direct` only when the lowest-hop path -is more important than keeping the importing event loop responsive: - -```ts -import DirectOliphaunt from '@oliphaunt/wasix-ts/direct'; - -await using database = await DirectOliphaunt.open(); -``` - -Use the explicit Worker import when a separate JavaScript realm is part of the -application's isolation or placement model: - -```ts -import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker'; - -await using database = await WorkerOliphaunt.open(); -``` - -All imports expose the same PostgreSQL interface and retain the promise-shaped -public API. A Promise does not itself imply off-thread execution. In a browser, -the root steps the Wasmer guest in the importing realm. On native hosts, the -root uses one Rust owner actor so PostgreSQL does not block the importing event -loop. `/direct` calls the synchronous Rust database on the importing thread and -removes that actor hop. `/worker` uses a real package-owned JavaScript Worker on -every runtime and loads the direct implementation inside it. - -Importing the browser root or `/direct` from an application Worker blocks only -that Worker; importing the browser root in a Window can block the page. Browser -Worker use requires cross-origin isolation. Chromium Window compilation -of native side modules larger than 8 MiB requires `/worker`. - -## Optional PostgreSQL tools - -Install `@oliphaunt/wasix-tools` when the application needs standard plain -`pg_dump` or non-interactive `psql`: - -```ts -import Oliphaunt from '@oliphaunt/wasix-ts'; -import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker'; -import { pgDump, psql } from '@oliphaunt/wasix-tools'; - -await using source = await Oliphaunt.open(); -const sql = await pgDump(source, { args: ['--schema-only'] }); -await using target = await WorkerOliphaunt.open(); -await psql(target, { script: sql }); -``` - -`pgDump()` runs with the database's existing owner, so it supports root, -`/direct`, and `/worker` entrypoints where available. In browsers, `psql()` requires `/worker` -because restoring COPY input is full duplex. Node.js, Bun, Deno, and Electron route both -tools through the frontend binaries compiled into the native carrier, so -`psql()` works with root, `/direct`, and `/worker` on those hosts. The optional -`@oliphaunt/wasix-tools` package remains the public opt-in API even though the -native carrier includes the tool code at build time. Adding or changing a tool -requires a matching N-API carrier release. - -The package preserves PostgreSQL's normal plain SQL and COPY output. It does -not support interactive psql, custom dump archives, parallel jobs, or -pg_restore. - -## Optional local server - -Node, Bun, Deno, and Electron may import `openServer` from the shared host-only server -subpath. Package export conditions select the runtime; browsers cannot resolve -this entrypoint: - -```ts -import { openServer } from '@oliphaunt/wasix-ts/server'; - -await using server = await openServer({ - listen: { transport: 'tcp' }, -}); -console.log(server.connectionString); -``` - -The lightweight compatibility endpoint binds IPv4 loopback with an automatic -port when `port` is omitted. Unix hosts may instead pass -`{ transport: 'unix', directory, port? }`; the socket follows PostgreSQL's -`.s.PGSQL.` convention. One complete client connection owns the single -embedded backend at a time; another connection may wait in the operating-system -backlog, so configure client pools with a maximum size of one. The server -entrypoint wraps the Rust `OliphauntServer` directly; it does not create a -JavaScript socket relay or managed Worker. The listener and storage lease -persist, while each admitted client receives a fresh backend. -Use the separate WASIX postmaster product for concurrent PostgreSQL sessions. -The server's read-only `closed` property remains `false` while terminal teardown -is running and becomes `true` when that memoized attempt settles, including when -cleanup rejects. - -## Scope - -The core database surface remains limited to open, execute/query/queryRaw, -exec/describe, buffered and callback-streamed raw protocol, callback -transaction, physical backup/restore, read-only `closed`, and close. -Tools and local sockets stay in optional packages or host-only subpaths. -Cancellation and a dedicated typed COPY reader/writer are not exposed today. - -## Qualification - -```sh -pnpm --dir src/bindings/wasix-ts typecheck -pnpm --dir src/bindings/wasix-ts test -moon run oliphaunt-wasix-ts:package -pnpm --dir src/runtimes/wasix-napi check -``` - -Runtime carrier and browser/Node/Bun/Deno/Electron host smokes are defined in the -packages' Moon tasks. Native-host smokes install the packed SDK and matching -packed optional carrier into a fresh external project; they never use a -developer-machine adjacent addon as the release proof. diff --git a/src/bindings/wasix-ts/host/build-provenance.mjs b/src/bindings/wasix-ts/host/build-provenance.mjs deleted file mode 100644 index 2afb7e5e2..000000000 --- a/src/bindings/wasix-ts/host/build-provenance.mjs +++ /dev/null @@ -1,115 +0,0 @@ -import { createHash } from 'node:crypto'; -import { readFile } from 'node:fs/promises'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const hostDirectory = dirname(fileURLToPath(import.meta.url)); -const repositoryRoot = resolve(hostDirectory, '../../../..'); -const sourceManifestPath = 'src/bindings/wasix-ts/host/source.toml'; -const buildScriptPath = 'src/bindings/wasix-ts/host/build-sdk.sh'; -const provenanceScriptPath = 'src/bindings/wasix-ts/host/build-provenance.mjs'; -const safePatchName = /^\d{4}-wasmer-(?:(?:js|wasix)-)?[a-z0-9-]+\.patch$/u; - -export async function loadHostBuildContract() { - const source = await readFile(resolve(repositoryRoot, sourceManifestPath), 'utf8'); - const patchSeries = tomlStringArray(source, 'patches', 'series'); - if (patchSeries.length === 0 || new Set(patchSeries).size !== patchSeries.length) { - throw new Error('WASIX host patch series must be non-empty and unique'); - } - for (const patch of patchSeries) { - if (!safePatchName.test(patch)) { - throw new Error(`WASIX host patch name is unsafe: ${JSON.stringify(patch)}`); - } - } - - const inputs = Object.freeze([ - sourceManifestPath, - ...patchSeries.map((patch) => `src/bindings/wasix-ts/host/patches/${patch}`), - buildScriptPath, - provenanceScriptPath, - ]); - const digests = []; - for (const input of inputs) { - const bytes = await readFile(resolve(repositoryRoot, input)); - digests.push(`${sha256(bytes)}\n`); - } - - const provenance = deepFreeze({ - wasmerJsCommit: tomlString(source, 'wasmer-js', 'commit'), - wasmerWasixVersion: tomlString(source, 'wasmer-wasix', 'version'), - inputsSha256: sha256(digests.join('')), - guestConcurrency: 'denied-for-oliphaunt-single-backend', - optimization: { - cargoProfile: 'release', - rustOptLevel: 3, - lto: true, - wasmOpt: ['--enable-threads', '--enable-bulk-memory', '-O3'], - }, - }); - return Object.freeze({ inputs, patchSeries: Object.freeze(patchSeries), provenance }); -} - -function tomlString(source, section, key) { - const body = tomlSection(source, section); - const match = body.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]+)"\\s*$`, 'mu')); - if (match === null) { - throw new Error(`WASIX host source manifest is missing [${section}].${key}`); - } - return match[1]; -} - -function tomlStringArray(source, section, key) { - const body = tomlSection(source, section); - const match = body.match( - new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*\\[([\\s\\S]*?)\\]\\s*$`, 'mu'), - ); - if (match === null) { - throw new Error(`WASIX host source manifest is missing [${section}].${key}`); - } - const values = []; - const item = /"([^"]+)"\s*,?/gu; - for (const entry of match[1].matchAll(item)) values.push(entry[1]); - const residue = match[1].replace(item, '').replace(/#[^\n]*/gu, '').trim(); - if (residue !== '') { - throw new Error(`WASIX host source manifest has malformed [${section}].${key}`); - } - return values; -} - -function tomlSection(source, section) { - const escaped = escapeRegExp(section); - const match = source.match( - new RegExp(`^\\[${escaped}\\][ \\t]*\\r?\\n([\\s\\S]*?)(?=^\\[|(?![\\s\\S]))`, 'mu'), - ); - if (match === null) throw new Error(`WASIX host source manifest is missing [${section}]`); - return match[1]; -} - -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&'); -} - -function sha256(value) { - return createHash('sha256').update(value).digest('hex'); -} - -function deepFreeze(value) { - Object.freeze(value); - for (const child of Object.values(value)) { - if (child !== null && typeof child === 'object' && !Object.isFrozen(child)) deepFreeze(child); - } - return value; -} - -if (process.argv[1] !== undefined && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { - const contract = await loadHostBuildContract(); - if (process.argv[2] === '--inputs-sha256') { - console.log(contract.provenance.inputsSha256); - } else if (process.argv[2] === '--patch-series') { - console.log(contract.patchSeries.join('\n')); - } else if (process.argv[2] === '--json') { - console.log(JSON.stringify(contract.provenance, null, 2)); - } else { - throw new Error('usage: build-provenance.mjs --inputs-sha256|--patch-series|--json'); - } -} diff --git a/src/bindings/wasix-ts/moon.yml b/src/bindings/wasix-ts/moon.yml deleted file mode 100644 index e976dad3a..000000000 --- a/src/bindings/wasix-ts/moon.yml +++ /dev/null @@ -1,116 +0,0 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "oliphaunt-wasix-ts" -language: "typescript" -layer: "library" -stack: "frontend" -tags: ["binding", "wasix", "wasm", "typescript", "browser", "node", "bun", "deno", "sdk", "release-product"] -dependsOn: - - id: "cluster-seed-contract" - scope: "development" - - id: "shared-test-fixtures" - scope: "development" - - "liboliphaunt-wasix" - - "oliphaunt-wasix-napi" - -project: - title: "Oliphaunt WASIX TypeScript binding" - description: "Universal WASIX TypeScript binding with browser and native host placements." - owner: "oliphaunt" - release: - component: "oliphaunt-wasix-ts" - packagePath: "src/bindings/wasix-ts" - -owners: - defaultOwner: "@oliphaunt/sdk-js" - -fileGroups: - code: - - "**/*" - - "!**/*.md" - - "!moon.yml" - - "!release.toml" - -tasks: - compile: - tags: ["quality", "static"] - command: "pnpm --dir src/bindings/wasix-ts typecheck" - deps: - - "shared-js-core:build" - inputs: - - "@group(pnpm-workspace)" - - project: "shared-js-core" - group: "sources" - - "@group(code)" - options: - cache: true - runFromWorkspaceRoot: true - - unit: - tags: ["quality", "unit"] - command: "pnpm --dir src/bindings/wasix-ts test" - deps: - - "shared-js-core:build" - inputs: - - "@group(pnpm-workspace)" - - project: "shared-js-core" - group: "sources" - - project: "shared-test-fixtures" - group: "fixtures" - - project: "cluster-seed-contract" - group: "contract" - - "@group(code)" - options: - cache: true - runFromWorkspaceRoot: true - runInCI: false - - browser-host: - tags: ["artifact", "build", "requires-rust"] - command: "bash src/bindings/wasix-ts/host/build-sdk.sh" - env: - WASM_PACK_VERSION: "0.15.0" - inputs: - - "host/**/*" - - "@group(cargo-workspace)" - outputs: - - "/target/oliphaunt-wasix-ts/host/wasmer-sdk/**/*" - options: - cache: true - runFromWorkspaceRoot: true - - package: - tags: ["package"] - script: | - set -e - pnpm --dir src/bindings/wasix-ts build - node src/bindings/wasix-ts/tools/stage-host.mjs - node src/bindings/wasix-ts/tools/package.mjs target/oliphaunt-wasix-ts/package - deps: - - "oliphaunt-wasix-ts:browser-host" - - "shared-js-core:build" - inputs: - - "@group(legal-files)" - - "@group(pnpm-workspace)" - - project: "shared-js-core" - group: "sources" - - "**/*" - outputs: - - "/target/oliphaunt-wasix-ts/package/**/*" - - "/src/bindings/wasix-ts/lib/**/*" - options: - cache: true - runFromWorkspaceRoot: true - - qualify: - tags: ["release", "package"] - command: "true" - deps: - - "oliphaunt-wasix-ts:compile" - - "oliphaunt-wasix-ts:unit" - - "oliphaunt-wasix-ts:package" - inputs: [] - options: - cache: true - runFromWorkspaceRoot: true - runInCI: false diff --git a/src/bindings/wasix-ts/package.json b/src/bindings/wasix-ts/package.json deleted file mode 100644 index 4ac1cf1bd..000000000 --- a/src/bindings/wasix-ts/package.json +++ /dev/null @@ -1,140 +0,0 @@ -{ - "name": "@oliphaunt/wasix-ts", - "version": "0.1.0", - "description": "Portable Oliphaunt WASIX TypeScript SDK for browsers, Node.js, Bun, Deno, and Electron.", - "license": "MIT", - "type": "module", - "sideEffects": false, - "repository": { - "type": "git", - "url": "git+https://github.com/f0rr0/oliphaunt.git", - "directory": "src/bindings/wasix-ts" - }, - "bugs": { - "url": "https://github.com/f0rr0/oliphaunt/issues" - }, - "homepage": "https://oliphaunt.dev", - "oliphaunt": { - "runtimeProduct": "liboliphaunt-wasix", - "runtimeVersion": "0.2.0", - "wasixNapiProduct": "oliphaunt-wasix-napi", - "wasixNapiVersion": "0.1.0", - "wasixAddonAbiVersion": 1, - "nodeApiVersion": 8, - "browserHost": "wasmer-js-patched", - "serverHost": "wasix-rust-napi" - }, - "publishConfig": { - "access": "public", - "provenance": true - }, - "exports": { - ".": { - "types": "./lib/index.d.ts", - "deno": "./lib/index.deno.js", - "bun": "./lib/index.bun.js", - "node": "./lib/index.node.js", - "browser": "./lib/index.js", - "default": "./lib/index.js" - }, - "./worker": { - "types": "./lib/worker-entry.d.ts", - "deno": "./lib/worker-entry.deno.js", - "bun": "./lib/worker-entry.bun.js", - "node": "./lib/worker-entry.node.js", - "browser": "./lib/worker-entry.js", - "default": "./lib/worker-entry.js" - }, - "./direct": { - "types": "./lib/direct.node.d.ts", - "deno": "./lib/direct.node.js", - "bun": "./lib/direct.node.js", - "node": "./lib/direct.node.js" - }, - "./internal/tools": { - "types": "./lib/internal.d.ts", - "deno": "./lib/internal.node.js", - "bun": "./lib/internal.node.js", - "node": "./lib/internal.node.js", - "browser": "./lib/internal.js", - "default": "./lib/internal.js" - }, - "./server": { - "types": "./lib/server.node.d.ts", - "deno": "./lib/server.node.js", - "bun": "./lib/server.node.js", - "node": "./lib/server.node.js" - }, - "./storage/indexed-db": { - "types": "./lib/storage/indexed-db.d.ts", - "default": "./lib/storage/indexed-db.js" - }, - "./storage/opfs": { - "types": "./lib/storage/opfs.d.ts", - "default": "./lib/storage/opfs.js" - }, - "./storage/node": { - "types": "./lib/storage/node.d.ts", - "node": "./lib/storage/node.js" - }, - "./storage/bun": { - "types": "./lib/storage/bun.d.ts", - "bun": "./lib/storage/bun.js" - }, - "./storage/deno": { - "types": "./lib/storage/deno.d.ts", - "deno": "./lib/storage/deno.js" - }, - "./package.json": { - "default": "./package.json" - } - }, - "main": "lib/index.js", - "module": "lib/index.js", - "types": "lib/index.d.ts", - "files": [ - "lib", - "README.md", - "ARCHITECTURE.md", - "CHANGELOG.md", - "LICENSE", - "THIRD_PARTY_NOTICES.md" - ], - "scripts": { - "build": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\" && tsc -p tsconfig.build.json", - "dev": "pnpm run package:build && vite --config ../../../examples/browser-wasix/vite.config.ts", - "host:build": "bash host/build-sdk.sh", - "package:build": "pnpm run host:build && pnpm run build && node tools/stage-host.mjs", - "package:build:closure": "pnpm run package:build && pnpm --dir tools-package build", - "docs:api": "typedoc --options typedoc.json", - "test": "vitest run --pool=forks --fileParallelism=false --dir=src/__tests__", - "typecheck": "tsc --noEmit", - "clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"" - }, - "dependencies": { - "@oliphaunt/js-core": "workspace:*", - "fzstd": "0.1.1" - }, - "bundledDependencies": [ - "@oliphaunt/js-core" - ], - "optionalDependencies": { - "@oliphaunt/wasix-napi-darwin-arm64": "workspace:*", - "@oliphaunt/wasix-napi-linux-arm64-gnu": "workspace:*", - "@oliphaunt/wasix-napi-linux-x64-gnu": "workspace:*", - "@oliphaunt/wasix-napi-win32-x64-msvc": "workspace:*" - }, - "devDependencies": { - "@electric-sql/pglite": "0.5.4", - "@types/node": "^24.10.1", - "typedoc": "catalog:", - "typescript": "catalog:", - "vite": "^6.0.3", - "vitest": "catalog:" - }, - "engines": { - "node": ">=22.13 <25", - "bun": ">=1.3.14", - "deno": ">=2.8.1" - } -} diff --git a/src/bindings/wasix-ts/release.toml b/src/bindings/wasix-ts/release.toml deleted file mode 100644 index b42164b3a..000000000 --- a/src/bindings/wasix-ts/release.toml +++ /dev/null @@ -1,30 +0,0 @@ -id = "oliphaunt-wasix-ts" -owner = "@oliphaunt/sdk-js" -kind = "sdk" -publish_targets = ["npm"] -registry_packages = [ - "npm:@oliphaunt/wasix-ts", - "npm:@oliphaunt/wasix-tools", -] -release_artifacts = [ - "npm-package", - "browser-worker", - "node-bun-deno-electron-node-api", - "node-bun-deno-electron-native-actor", - "node-bun-deno-electron-worker", -] - -[compatibility_versions.oliphaunt-wasix-ts-runtime] -source_product = "liboliphaunt-wasix" -path = "src/bindings/wasix-ts/package.json" -parser = "json:oliphaunt.runtimeVersion" - -[compatibility_versions.oliphaunt-wasix-ts-napi] -source_product = "oliphaunt-wasix-napi" -path = "src/bindings/wasix-ts/package.json" -parser = "json:oliphaunt.wasixNapiVersion" - -[compatibility_versions.oliphaunt-wasix-tools-runtime] -source_product = "liboliphaunt-wasix" -path = "src/bindings/wasix-ts/tools-package/package.json" -parser = "json:oliphaunt.runtimeVersion" diff --git a/src/bindings/wasix-ts/src/__tests__/client-common.test.ts b/src/bindings/wasix-ts/src/__tests__/client-common.test.ts deleted file mode 100644 index 6d3fb380f..000000000 --- a/src/bindings/wasix-ts/src/__tests__/client-common.test.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; - -vi.mock('@oliphaunt/liboliphaunt-wasix', () => ({ - POSTGRES_MAJOR: 18, - PHYSICAL_FORMAT: 'wasix-pg18-v1', - default: { - schema: 'oliphaunt-wasix-runtime-v2', - runtime: 'wasix', - product: 'liboliphaunt-wasix', - version: '0.1.1', - runtimeArchive: { - archive: 'oliphaunt.wasix.tar.zst', - sha256: '1'.repeat(64), - size: 1, - source: Uint8Array.of(1), - }, - standardSeedArchive: { - archive: 'cluster-seeds/standard.tar.zst', - sha256: '2'.repeat(64), - size: 1, - source: Uint8Array.of(2), - }, - standardSeedManifest: { - sha256: '4'.repeat(64), - size: 1, - source: Uint8Array.of(4), - }, - manifest: { - sha256: '3'.repeat(64), - size: 1, - source: Uint8Array.of(3), - }, - }, -})); - -import { restoreWasix, serializeOpenConfig } from '../client-common.js'; -import { indexedDB } from '../storage/indexed-db.js'; -import type { WasixIcuDescriptor, WasixRuntimeDescriptor } from '../types.js'; -import { openWasixWithWorker, restoreWasixWithWorker } from '../worker-rpc.js'; -import { FakeWorkerPort, workerOpenOptions } from './worker-helpers.js'; - -describe('WASIX shared client orchestration', () => { - it('serializes the explicit ICU data and matching seed as one closure', () => { - const options = serializeOpenConfig( - { icu: icuDescriptor() }, - runtimeDescriptor(Uint8Array.of(1)), - ); - - expect(options.icu).toMatchObject({ - schema: 'oliphaunt-wasix-icu-v1', - product: 'oliphaunt-icu', - compatibility: { - runtimeProduct: 'liboliphaunt-wasix', - compatibilityKey: 'wasix-pg18-datum32-v1', - dataTreeSha256: 'a'.repeat(64), - }, - }); - }); - - it('serializes caller configuration without retaining mutable asset buffers', () => { - const runtimeBytes = new Uint8Array(4).fill(1); - const options = serializeOpenConfig( - { - username: 'app', - database: 'todos', - startupGUCs: { search_path: 'app, public' }, - }, - runtimeDescriptor(runtimeBytes), - ); - - runtimeBytes[0] = 9; - expect(options).toMatchObject({ - username: 'app', - database: 'todos', - startupGUCs: { search_path: 'app, public' }, - storage: { schema: 'oliphaunt-wasix-storage-v1', kind: 'memory' }, - }); - expect(options.runtime.runtimeArchive.source).toEqual(Uint8Array.of(1, 1, 1, 1)); - }); - - it('canonicalizes case-insensitive GUCs and rejects storage redirection before open', () => { - const options = serializeOpenConfig( - { startupGUCs: { work_mem: '1MB', WORK_MEM: '2MB' } }, - runtimeDescriptor(Uint8Array.of(1)), - ); - expect(options.startupGUCs).toEqual({ work_mem: '2MB' }); - - for (const name of ['CONFIG_FILE', 'data_directory']) { - expect(() => - serializeOpenConfig( - { startupGUCs: { [name]: '/tmp/other' } }, - runtimeDescriptor(Uint8Array.of(1)), - ), - ).toThrow('owns PostgreSQL startup GUC'); - } - }); - - it('validates before opening and transfers each distinct runtime buffer once', async () => { - const port = new FakeWorkerPort(); - const options = workerOpenOptions(); - const shared = Uint8Array.of(1, 2); - const manifest = Uint8Array.of(3); - options.runtime.runtimeArchive.source = shared; - options.runtime.standardSeedArchive.source = shared; - options.runtime.manifest.source = manifest; - const validate = vi.fn(); - const opening = openWasixWithWorker( - (received) => { - expect(received).toBe(options); - return port; - }, - options, - validate, - ); - - expect(validate).toHaveBeenCalledWith(options); - const open = port.requests[0]; - expect(open?.message.method).toBe('open'); - expect(open?.transfer).toEqual([shared.buffer, manifest.buffer]); - if (open === undefined) throw new Error('open request was not posted'); - port.respond({ id: open.message.id, ok: true }); - const database = await opening; - - const closing = database.close(); - await Promise.resolve(); - const close = port.requests[1]?.message; - if (close === undefined) throw new Error('close request was not posted'); - port.respond({ id: close.id, ok: true }); - await closing; - }); - - it('rejects restore without an explicit persistent storage target', async () => { - await expect(restoreWasix(undefined, Uint8Array.of())).rejects.toThrow( - 'WASIX restore requires persistent storage', - ); - }); - - it('runs Worker restore without detaching caller bytes', async () => { - const port = new FakeWorkerPort(); - const bytes = Uint8Array.of(1, 2, 3); - const restoring = restoreWasixWithWorker(() => port, indexedDB('restore-target'), bytes); - const request = port.requests[0]; - expect(request?.message).toMatchObject({ method: 'restore' }); - if (request?.message.method !== 'restore') throw new Error('restore request was not posted'); - expect(request.message.bytes).toEqual(bytes); - expect(request.message.bytes).not.toBe(bytes); - expect(request.transfer).toEqual([request.message.bytes.buffer]); - expect(bytes).toEqual(Uint8Array.of(1, 2, 3)); - port.respond({ id: request.message.id, ok: true }); - - await expect(restoring).resolves.toBeUndefined(); - expect(port.terminations).toBe(1); - }); - - it('preserves both Worker restore and termination failures', async () => { - const port = new FakeWorkerPort(); - port.terminate = () => { - port.terminations += 1; - throw new Error('worker termination failed'); - }; - const restoring = restoreWasixWithWorker( - () => port, - indexedDB('restore-failure-target'), - Uint8Array.of(1), - ); - const request = port.requests[0]?.message; - if (request === undefined) throw new Error('restore request was not posted'); - port.respond({ - id: request.id, - ok: false, - error: { name: 'Error', message: 'restore failed' }, - }); - - const failure = await restoring.catch((error: unknown) => error); - expect(failure).toBeInstanceOf(AggregateError); - if (!(failure instanceof AggregateError)) throw new Error('expected aggregate restore failure'); - expect(failure.errors).toEqual([ - expect.objectContaining({ message: 'restore failed' }), - expect.objectContaining({ message: 'worker termination failed' }), - ]); - expect(port.terminations).toBe(1); - }); -}); - -function runtimeDescriptor(runtimeBytes: Uint8Array): WasixRuntimeDescriptor { - return { - schema: 'oliphaunt-wasix-runtime-v2', - runtime: 'wasix', - product: 'liboliphaunt-wasix', - version: '0.1.1', - runtimeArchive: { - archive: 'oliphaunt.wasix.tar.zst', - sha256: '1'.repeat(64), - size: runtimeBytes.byteLength, - source: runtimeBytes, - }, - standardSeedArchive: { - archive: 'cluster-seeds/standard.tar.zst', - sha256: '2'.repeat(64), - size: 1, - source: Uint8Array.of(2), - }, - standardSeedManifest: { - sha256: '4'.repeat(64), - size: 1, - source: Uint8Array.of(4), - }, - manifest: { - sha256: '3'.repeat(64), - size: 1, - source: Uint8Array.of(3), - }, - }; -} - -function icuDescriptor(): WasixIcuDescriptor { - return { - schema: 'oliphaunt-wasix-icu-v1', - runtime: 'wasix', - product: 'oliphaunt-icu', - version: '0.1.1', - compatibility: { - runtimeProduct: 'liboliphaunt-wasix', - runtimeVersion: '0.1.1', - postgresMajor: '18', - physicalFormat: 'wasix-pg18-v1', - compatibilityKey: 'wasix-pg18-datum32-v1', - dataVersion: '76.1', - dataForm: 'files-le', - dataTreeSha256: 'a'.repeat(64), - }, - dataArchive: { - archive: 'icu-data/icu-data.tar.zst', - sha256: 'b'.repeat(64), - size: 1, - source: Uint8Array.of(1), - }, - clusterSeedArchive: { - archive: 'cluster-seeds/icu.tar.zst', - sha256: 'c'.repeat(64), - size: 1, - source: Uint8Array.of(2), - }, - clusterSeedManifest: { - sha256: 'd'.repeat(64), - size: 1, - source: Uint8Array.of(3), - }, - }; -} diff --git a/src/bindings/wasix-ts/src/__tests__/client.test.ts b/src/bindings/wasix-ts/src/__tests__/client.test.ts deleted file mode 100644 index a92be0f33..000000000 --- a/src/bindings/wasix-ts/src/__tests__/client.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; - -const directMocks = vi.hoisted(() => ({ - openWasixDirect: vi.fn(), - openNodeActor: vi.fn(), - openNodeDirect: vi.fn(), -})); - -vi.mock('../direct-client-common.js', () => ({ - openWasixDirect: directMocks.openWasixDirect, -})); -vi.mock('../node-direct.js', () => ({ - openNodeDirect: directMocks.openNodeDirect, -})); -vi.mock('../node-actor.js', () => ({ - openNodeActor: directMocks.openNodeActor, -})); -vi.mock('../worker-rpc.js', () => { - throw new Error('root entrypoint loaded Worker RPC machinery'); -}); -vi.mock('../native-session.js', () => ({ - restoreNativeWasix: vi.fn(), - restoreNativeWasixDirect: vi.fn(), -})); - -import { openWasixWithHost } from '../client.js'; -import type { OliphauntDatabase } from '../types.js'; - -let crossOriginDescriptor: PropertyDescriptor | undefined; -let workerDescriptor: PropertyDescriptor | undefined; - -beforeEach(() => { - crossOriginDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'crossOriginIsolated'); - workerDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'Worker'); - Object.defineProperty(globalThis, 'crossOriginIsolated', { - configurable: true, - value: true, - }); - Object.defineProperty(globalThis, 'Worker', { - configurable: true, - value: class ForbiddenWorker { - constructor() { - throw new Error('root entrypoint constructed a Worker'); - } - }, - }); - directMocks.openWasixDirect.mockReset(); - directMocks.openWasixDirect.mockResolvedValue({} as OliphauntDatabase); - directMocks.openNodeDirect.mockReset(); - directMocks.openNodeDirect.mockResolvedValue({} as OliphauntDatabase); - directMocks.openNodeActor.mockReset(); - directMocks.openNodeActor.mockResolvedValue({} as OliphauntDatabase); -}); - -describe('WASIX Node-compatible root execution surface', () => { - it('opens through the Rust actor without loading Worker RPC machinery', async () => { - const { openWasix } = await import('../node-client.js'); - - const database = await openWasix(); - - expect(database).toBe(await directMocks.openNodeActor.mock.results[0]?.value); - expect(directMocks.openNodeActor).toHaveBeenCalledOnce(); - expect(directMocks.openNodeDirect).not.toHaveBeenCalled(); - }); - - it('keeps the explicit direct placement in the importing realm', async () => { - const { openWasix } = await import('../direct-client.js'); - - const database = await openWasix(); - - expect(database).toBe(await directMocks.openNodeDirect.mock.results[0]?.value); - expect(directMocks.openNodeDirect).toHaveBeenCalledOnce(); - expect(directMocks.openNodeActor).not.toHaveBeenCalled(); - }); -}); - -afterEach(() => { - restoreGlobal('crossOriginIsolated', crossOriginDescriptor); - restoreGlobal('Worker', workerDescriptor); -}); - -describe('WASIX browser root execution surface', () => { - it('opens through the caller-realm engine and never constructs a Worker', async () => { - const database = await openWasixWithHost( - { username: 'application' }, - async () => ({}) as never, - ); - - expect(database).toBe(await directMocks.openWasixDirect.mock.results[0]?.value); - expect(directMocks.openWasixDirect).toHaveBeenCalledOnce(); - expect(directMocks.openWasixDirect.mock.calls[0]?.[2]).toBe('browser-main'); - }); -}); - -function restoreGlobal(name: string, descriptor: PropertyDescriptor | undefined): void { - if (descriptor === undefined) Reflect.deleteProperty(globalThis, name); - else Object.defineProperty(globalThis, name, descriptor); -} diff --git a/src/bindings/wasix-ts/src/__tests__/host-runtime.test.ts b/src/bindings/wasix-ts/src/__tests__/host-runtime.test.ts deleted file mode 100644 index 0a0b47c0b..000000000 --- a/src/bindings/wasix-ts/src/__tests__/host-runtime.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest'; - -import { hostRuntime, hostRuntimeName } from '../host-runtime.js'; - -afterEach(() => vi.unstubAllGlobals()); - -describe('WASIX JavaScript host identity', () => { - it('uses explicit runtime globals and stable diagnostic names', () => { - vi.stubGlobal('Bun', {}); - expect(hostRuntime()).toBe('bun'); - expect(hostRuntimeName()).toBe('Bun'); - - vi.stubGlobal('Bun', undefined); - vi.stubGlobal('Deno', {}); - expect(hostRuntime()).toBe('deno'); - expect(hostRuntimeName()).toBe('Deno'); - - vi.stubGlobal('Deno', undefined); - expect(hostRuntime()).toBe('node'); - expect(hostRuntimeName()).toBe('Node'); - }); -}); diff --git a/src/bindings/wasix-ts/src/__tests__/public-api.test.ts b/src/bindings/wasix-ts/src/__tests__/public-api.test.ts deleted file mode 100644 index 2079654ed..000000000 --- a/src/bindings/wasix-ts/src/__tests__/public-api.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { - array, - binary, - json, - Oliphaunt, - PostgresError, - postgresOids, - text, - typedNull, - type BinaryQueryParameter, - type DescribeResult, - type EncodedQueryParameter, - type ExecResult, - type NullQueryParameter, - type OliphauntDatabase, - type OpenConfig, - type OliphauntTransaction, - type QueryArrayRow, - type QueryObjectRow, - type QueryResult, - type QueryParam, - type QueryValue, - type RawQueryResult, - type TextQueryParameter, -} from '../index.js'; -import WorkerOliphaunt, { Oliphaunt as NamedWorkerOliphaunt } from '../worker-entry.js'; - -describe('WASIX public ORM surface', () => { - it('publishes codecs and PostgreSQL metadata from the root entrypoint', () => { - expect(typeof Oliphaunt.open).toBe('function'); - expect(WorkerOliphaunt).toBe(NamedWorkerOliphaunt); - expect(typeof WorkerOliphaunt.open).toBe('function'); - expect(typeof PostgresError).toBe('function'); - expect(postgresOids.jsonb).toBe(3802); - expect(text('value', postgresOids.text).format).toBe('text'); - expect(binary(Uint8Array.of(1), postgresOids.bytea).format).toBe('binary'); - expect(json({ ok: true }).typeOid).toBe(postgresOids.jsonb); - expect(array([1, 2], postgresOids.int4Array).typeOid).toBe(postgresOids.int4Array); - expect(typedNull(postgresOids.uuid).format).toBe('null'); - }); -}); - -const canonicalPostgresError = new PostgresError([ - { code: 0x43, value: '22000' }, - { code: 0x4d, value: 'invalid value' }, -]); -const canonicalSqlstate: string | undefined = canonicalPostgresError.sqlstate; -const canonicalMessage: string = canonicalPostgresError.message; -void [canonicalSqlstate, canonicalMessage]; - -function assertPublicDatabaseTypes( - database: OliphauntDatabase, - transaction: OliphauntTransaction, -): void { - const decoded: Promise> = database.query<{ - value: number; - }>('SELECT $1::int4 AS value', [1], { rowMode: 'object' }); - const raw: Promise = database.queryRaw('SELECT $1::bytea', [ - binary(Uint8Array.of(1), postgresOids.bytea), - ]); - const execResults: Promise> = database.exec( - 'SELECT 1', - { rowMode: 'array' }, - ); - const inferredArrays: Promise> = transaction.query('SELECT 1', [], { - rowMode: 'array', - }); - const inferredDecoder: Promise>> = database.query( - 'SELECT now()', - [], - { decoders: { [postgresOids.timestamptz]: (value) => new Date(value) } }, - ); - const description: Promise = database.describe('SELECT $1', [postgresOids.int4]); - const streamed: Promise = database.execProtocolRawStream(Uint8Array.of(1), () => undefined); - // @ts-expect-error Stream callbacks are synchronous backpressure acknowledgements. - const asyncStreamed = database.execProtocolRawStream(Uint8Array.of(1), async () => {}); - const widenedAsyncCallback: (chunk: Uint8Array) => unknown = async () => {}; - const widenedAsyncStreamed = database.execProtocolRawStream( - Uint8Array.of(1), - // @ts-expect-error Widening an async callback must not bypass the synchronous contract. - widenedAsyncCallback, - ); - // @ts-expect-error Raw protocol is root-only; it bypasses callback transaction ownership. - const transactionBuffered = transaction.execProtocolRaw(Uint8Array.of(1)); - // @ts-expect-error Raw protocol is root-only; it bypasses callback transaction ownership. - const transactionStreamed = transaction.execProtocolRawStream(Uint8Array.of(1), () => undefined); - const rollback: Promise = transaction.rollback(); - const closed: boolean = database.closed || transaction.closed; - void [ - decoded, - raw, - execResults, - inferredArrays, - inferredDecoder, - description, - streamed, - asyncStreamed, - widenedAsyncStreamed, - transactionBuffered, - transactionStreamed, - rollback, - closed, - ]; -} - -void assertPublicDatabaseTypes; - -const publicHelperTypes: [TextQueryParameter, BinaryQueryParameter, NullQueryParameter] = [ - text('value'), - binary(Uint8Array.of(1)), - typedNull(postgresOids.text), -]; -void publicHelperTypes; - -const plainJsonParameter: QueryParam = { - format: 'text', - value: 'plain JSON data', -}; -// @ts-expect-error Encoded parameters must be created by an exported helper. -const forgedEncodedParameter: EncodedQueryParameter = { - format: 'text', - value: 'forged', -}; -void [plainJsonParameter, forgedEncodedParameter]; - -const openConfig: OpenConfig = { username: 'application' }; -void openConfig; diff --git a/src/bindings/wasix-ts/src/__tests__/query.test.ts b/src/bindings/wasix-ts/src/__tests__/query.test.ts deleted file mode 100644 index dd1055126..000000000 --- a/src/bindings/wasix-ts/src/__tests__/query.test.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { - binary, - extendedQuery, - parseDescribeResponse, - parseExecResponse, - parseQueryRawResponse, - parseSimpleQueryRawResponse, - postgresOids, - text, -} from '../query.js'; - -describe('WASIX query protocol codec', () => { - it('writes the exact PostgreSQL extended-query packet', () => { - const packet = extendedQuery('SELECT $1::text, $2::bytea, $3::bool', [ - text('hé', postgresOids.text), - binary(Uint8Array.of(0, 255, 1), postgresOids.bytea), - text(true, postgresOids.bool), - ]); - - expect(Buffer.from(packet).toString('hex')).toBe( - '50000000380053454c4543542024313a3a746578742c2024323a3a62797465612c2024333a3a626f6f6c000003000000190000001100000010' + - '420000002a0000000300000001000000030000000368c3a90000000300ff01000000047472756500010000' + - '44000000065000450000000900000000005300000004', - ); - }); - - it('writes large binary parameters without argument spreading', () => { - const value = new Uint8Array(256 * 1024).fill(0xab); - const packet = extendedQuery('SELECT $1::bytea', [binary(value, postgresOids.bytea)]); - const messages = frontendMessages(packet); - - expect(messages.map(({ tag }) => tag)).toEqual(['P', 'B', 'D', 'E', 'S']); - const bind = messages[1]?.body; - if (bind === undefined) throw new Error('extended query omitted Bind'); - const parameterLengthOffset = 2 + 2 + 2 + 2; - expect(readU32(bind, parameterLengthOffset)).toBe(value.length); - expect( - bind.subarray(parameterLengthOffset + 4, parameterLengthOffset + 4 + value.length), - ).toEqual(value); - }); - - it('parses integers without copies and keeps row values as response views', () => { - const response = queryResponse(new TextEncoder().encode('λ-value')); - const result = parseSimpleQueryRawResponse(response); - - expect(result.fields).toEqual([ - { - name: 'value', - tableOid: 0x01020304, - tableAttribute: -2, - typeOid: 25, - typeSize: -1, - typeModifier: -1, - format: 'text', - }, - ]); - expect(result.getText(0, 'value')).toBe('λ-value'); - expect(result.rows[0]?.values[0]?.buffer).toBe(response.buffer); - }); - - it('retains exact invalid UTF-8 field-name byte-offset diagnostics', () => { - const malformedDescription = concatenate(Uint8Array.of(0, 1, 0xc0, 0), new Uint8Array(18)); - - expect(() => parseSimpleQueryRawResponse(backendMessage('T', malformedDescription))).toThrow( - 'field name is not valid UTF-8 at byte 0', - ); - }); - - it('retains exact invalid UTF-8 row-value byte-offset diagnostics', () => { - const result = parseSimpleQueryRawResponse( - queryResponse(Uint8Array.of(0x61, 0xe2, 0x28, 0xa1)), - ); - - expect(() => result.rows[0]?.text(0)).toThrow('query value is not valid UTF-8 at byte 2'); - }); - - it('retains truncated integer and body diagnostics', () => { - expect(() => parseSimpleQueryRawResponse(Uint8Array.of(0x54, 0, 0))).toThrow( - 'truncated backend message length', - ); - expect(() => parseSimpleQueryRawResponse(Uint8Array.of(0x54, 0, 0, 0, 6, 0))).toThrow( - 'truncated backend message body', - ); - }); - - it('rejects incomplete and out-of-order completions while exec admits empty statements', () => { - const ready = backendMessage('Z', Uint8Array.of('I'.charCodeAt(0))); - expect(() => parseSimpleQueryRawResponse(ready)).toThrow( - 'omitted CommandComplete or EmptyQueryResponse', - ); - expect(() => - parseSimpleQueryRawResponse( - concatenate( - backendMessage('C', new TextEncoder().encode('SELECT 1\0')), - backendMessage('D', Uint8Array.of(0, 0)), - ready, - ), - ), - ).toThrow('DataRow arrived after statement completion'); - expect(() => - parseDescribeResponse( - concatenate( - backendMessage('t', Uint8Array.of(0, 0)), - backendMessage('n', new Uint8Array()), - ready, - ), - ), - ).toThrow(/before ParseComplete|omitted ParseComplete/); - - const result = parseExecResponse( - concatenate( - backendMessage('C', new TextEncoder().encode('UPDATE 1\0')), - backendMessage('I', new Uint8Array()), - backendMessage('C', new TextEncoder().encode('DELETE 2\0')), - ready, - ), - ); - expect(result.statements.map((statement) => statement.commandTag)).toEqual([ - 'UPDATE 1', - 'DELETE 2', - ]); - - for (const completion of [ - backendMessage('C', new TextEncoder().encode('UPDATE 1\0')), - backendMessage('I', new Uint8Array()), - ]) { - expect(() => parseQueryRawResponse(concatenate(completion, ready))).toThrow( - 'before the extended-query result description', - ); - } - expect(() => - parseQueryRawResponse( - concatenate( - backendMessage('2', new Uint8Array()), - backendMessage('n', new Uint8Array()), - backendMessage('C', new TextEncoder().encode('UPDATE 1\0')), - ready, - ), - ), - ).toThrow('BindComplete arrived before ParseComplete'); - expect(() => - parseExecResponse( - concatenate( - backendMessage('1', new Uint8Array()), - backendMessage('C', new TextEncoder().encode('UPDATE 1\0')), - ready, - ), - ), - ).toThrow('simple-query response contained ParseComplete'); - }); -}); - -function frontendMessages(packet: Uint8Array): Array<{ tag: string; body: Uint8Array }> { - const messages: Array<{ tag: string; body: Uint8Array }> = []; - let offset = 0; - while (offset < packet.length) { - const length = readU32(packet, offset + 1); - messages.push({ - tag: String.fromCharCode(packet[offset] ?? 0), - body: packet.subarray(offset + 5, offset + 1 + length), - }); - offset += length + 1; - } - return messages; -} - -function queryResponse(value: Uint8Array): Uint8Array { - const fieldName = new TextEncoder().encode('value'); - const rowDescription = new Uint8Array(2 + fieldName.length + 1 + 4 + 2 + 4 + 2 + 4 + 2); - const rowView = new DataView( - rowDescription.buffer, - rowDescription.byteOffset, - rowDescription.byteLength, - ); - let offset = 0; - rowView.setInt16(offset, 1); - offset += 2; - rowDescription.set(fieldName, offset); - offset += fieldName.length; - rowDescription[offset] = 0; - offset += 1; - rowView.setUint32(offset, 0x01020304); - offset += 4; - rowView.setInt16(offset, -2); - offset += 2; - rowView.setUint32(offset, 25); - offset += 4; - rowView.setInt16(offset, -1); - offset += 2; - rowView.setInt32(offset, -1); - offset += 4; - rowView.setInt16(offset, 0); - - const dataRow = new Uint8Array(2 + 4 + value.length); - const dataView = new DataView(dataRow.buffer, dataRow.byteOffset, dataRow.byteLength); - dataView.setInt16(0, 1); - dataView.setInt32(2, value.length); - dataRow.set(value, 6); - - return concatenate( - backendMessage('T', rowDescription), - backendMessage('D', dataRow), - backendMessage('C', new TextEncoder().encode('SELECT 1\0')), - backendMessage('Z', Uint8Array.of('I'.charCodeAt(0))), - ); -} - -function backendMessage(tag: string, body: Uint8Array): Uint8Array { - const message = new Uint8Array(body.length + 5); - message[0] = tag.charCodeAt(0); - new DataView(message.buffer).setUint32(1, body.length + 4); - message.set(body, 5); - return message; -} - -function readU32(bytes: Uint8Array, offset: number): number { - return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(offset); -} - -function concatenate(...parts: Uint8Array[]): Uint8Array { - const result = new Uint8Array(parts.reduce((length, part) => length + part.length, 0)); - let offset = 0; - for (const part of parts) { - result.set(part, offset); - offset += part.length; - } - return result; -} diff --git a/src/bindings/wasix-ts/src/__tests__/runtime-carrier.ts b/src/bindings/wasix-ts/src/__tests__/runtime-carrier.ts deleted file mode 100644 index 50f6ae9b0..000000000 --- a/src/bindings/wasix-ts/src/__tests__/runtime-carrier.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { WasixRuntimeDescriptor } from '../types.js'; - -export const POSTGRES_MAJOR = 18 as const; -export const PHYSICAL_FORMAT = 'wasix-pg18-v1' as const; - -const runtime: WasixRuntimeDescriptor = { - schema: 'oliphaunt-wasix-runtime-v2', - runtime: 'wasix', - product: 'liboliphaunt-wasix', - version: '0.1.1', - runtimeArchive: { - archive: 'oliphaunt.wasix.tar.zst', - sha256: '1'.repeat(64), - size: 1, - source: Uint8Array.of(1), - }, - standardSeedArchive: { - archive: 'cluster-seeds/standard.tar.zst', - sha256: '2'.repeat(64), - size: 1, - source: Uint8Array.of(2), - }, - standardSeedManifest: { - sha256: '4'.repeat(64), - size: 1, - source: Uint8Array.of(4), - }, - manifest: { - sha256: '3'.repeat(64), - size: 1, - source: Uint8Array.of(3), - }, -}; -export default runtime; diff --git a/src/bindings/wasix-ts/src/__tests__/storage.test.ts b/src/bindings/wasix-ts/src/__tests__/storage.test.ts deleted file mode 100644 index 3def57cc6..000000000 --- a/src/bindings/wasix-ts/src/__tests__/storage.test.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { fileURLToPath } from 'node:url'; - -import { describe, expect, it } from 'vitest'; - -import { WasixStorageError } from '../errors.js'; -import { PostgresError } from '../query.js'; -import type { PersistentWasixStorage } from '../public.js'; -import { deserializeWorkerError, serializeWorkerError } from '../rpc.js'; -import { indexedDB } from '../storage/indexed-db.js'; -import { directory } from '../storage/node.js'; -import { opfs } from '../storage/opfs.js'; -import { memory, serializeWasixStorage, type WasixStorage } from '../storage.js'; - -const persistentStorageProof: PersistentWasixStorage[] = [ - indexedDB('type-proof'), - opfs('type-proof'), - directory('/type-proof'), -]; -// @ts-expect-error Memory storage cannot be a physical-restore destination. -const memoryIsNotPersistent: PersistentWasixStorage = memory(); -void persistentStorageProof; -void memoryIsNotPersistent; - -type MainPackage = typeof import('../index.js'); -const mainPackageOmitsIndexedDb: 'indexedDB' extends keyof MainPackage ? false : true = true; - -describe('WASIX storage descriptors', () => { - it('defaults to memory and keeps storage values opaque', () => { - expect(serializeWasixStorage(undefined)).toEqual({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'memory', - }); - - const descriptor = memory(); - expect(Object.isFrozen(descriptor)).toBe(true); - expect(Object.keys(descriptor)).toEqual([]); - expect(serializeWasixStorage(descriptor)).toEqual({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'memory', - }); - }); - - it('requires selective IndexedDB construction and validates its database name', () => { - expect(mainPackageOmitsIndexedDb).toBe(true); - const descriptor = indexedDB('todos'); - expect(Object.keys(descriptor)).toEqual([]); - expect(serializeWasixStorage(descriptor)).toEqual({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'indexed-db', - name: 'todos', - }); - - expect(() => indexedDB('')).toThrow('must be 1-200 characters'); - expect(() => indexedDB('x'.repeat(201))).toThrow('must be 1-200 characters'); - expect(() => indexedDB('bad\0name')).toThrow('without NUL bytes'); - }); - - it('constructs an OPFS descriptor with a path-safe database name', () => { - const descriptor = opfs('todos-v2'); - expect(Object.keys(descriptor)).toEqual([]); - expect(serializeWasixStorage(descriptor)).toEqual({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'opfs', - name: 'todos-v2', - }); - - expect(() => opfs('')).toThrow('must be 1-100 ASCII'); - expect(() => opfs('../escape')).toThrow('must be 1-100 ASCII'); - expect(() => opfs('space name')).toThrow('must be 1-100 ASCII'); - }); - - it('requires selective Node directory construction and validates its path', () => { - const descriptor = directory('./data/with spaces'); - expect(Object.keys(descriptor)).toEqual([]); - expect(serializeWasixStorage(descriptor)).toEqual({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'directory', - path: './data/with spaces', - }); - const fileUrl = new URL('file:///tmp/data%20space'); - expect(serializeWasixStorage(directory(fileUrl))).toEqual({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'directory', - path: fileURLToPath(fileUrl), - }); - expect(() => directory(new URL('https://example.com/data'))).toThrow( - 'URL must be of scheme file', - ); - expect(() => directory('')).toThrow('non-empty string'); - expect(() => directory('bad\0path')).toThrow('without NUL bytes'); - }); - - it('rejects user-authored and structured-cloned lookalikes', () => { - expect(() => - serializeWasixStorage({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'memory', - } as unknown as WasixStorage), - ).toThrow('must come from @oliphaunt/wasix-ts'); - - expect(() => serializeWasixStorage(structuredClone(memory()))).toThrow( - 'must come from @oliphaunt/wasix-ts', - ); - }); - - it('preserves typed storage failures across the worker boundary', () => { - const original = new WasixStorageError('the prior generation is still current', { - code: 'publication-failed', - commitState: 'not-persisted', - phase: 'open-publication', - }); - - const roundTrip = deserializeWorkerError(serializeWorkerError(original)); - - expect(roundTrip).toBeInstanceOf(WasixStorageError); - expect(roundTrip).toMatchObject({ - name: 'WasixStorageError', - message: 'the prior generation is still current', - code: 'publication-failed', - commitState: 'not-persisted', - phase: 'open-publication', - }); - }); - - it('preserves exact native tool diagnostics across the worker boundary', () => { - const original = Object.assign(new Error('pg_dump reported an impossible success error'), { - name: 'OliphauntWasixToolError', - oliphauntWasixError: 'tool' as const, - oliphauntWasixAddonAbi: 1 as const, - code: 'tool-error' as const, - tool: 'pg_dump', - exitCode: 0, - stdout: Uint8Array.of(0xff, 0), - stderr: Uint8Array.of(0x80, 0xfe), - }); - - const roundTrip = deserializeWorkerError(serializeWorkerError(original)); - - expect(roundTrip).toMatchObject({ - name: 'OliphauntWasixToolError', - oliphauntWasixError: 'tool', - oliphauntWasixAddonAbi: 1, - code: 'tool-error', - tool: 'pg_dump', - exitCode: 0, - stdout: Uint8Array.of(0xff, 0), - stderr: Uint8Array.of(0x80, 0xfe), - }); - }); - - it('preserves extension bootstrap PostgreSQL errors across the worker boundary', () => { - const original = new PostgresError([ - { code: 0x53, value: 'ERROR' }, - { code: 0x43, value: '42710' }, - { code: 0x4d, value: 'extension already exists' }, - ]); - - const roundTrip = deserializeWorkerError(serializeWorkerError(original)); - - expect(roundTrip).toBeInstanceOf(PostgresError); - expect(roundTrip).toMatchObject({ - name: 'PostgresError', - sqlstate: '42710', - message: 'extension already exists', - fields: original.fields, - }); - }); - - it('preserves generic error identity and owner-side diagnostics across the worker boundary', () => { - const original = new TypeError('invalid owner request'); - original.stack = 'TypeError: invalid owner request\n at owner-worker.js:1:1'; - - const roundTrip = deserializeWorkerError(serializeWorkerError(original)); - - expect(roundTrip).toBeInstanceOf(Error); - expect(roundTrip).toMatchObject({ - name: 'TypeError', - message: 'invalid owner request', - stack: original.stack, - }); - }); -}); diff --git a/src/bindings/wasix-ts/src/client-common.ts b/src/bindings/wasix-ts/src/client-common.ts deleted file mode 100644 index cd3506558..000000000 --- a/src/bindings/wasix-ts/src/client-common.ts +++ /dev/null @@ -1,51 +0,0 @@ -import defaultWasixRuntime from '@oliphaunt/liboliphaunt-wasix'; - -import { serializeWasixExtensionDescriptors } from './extension-descriptor.js'; -import { serializeWasixIcuDescriptor } from './icu-descriptor.js'; -import { decodePhysicalArchive } from './physical-archive.js'; -import { toUint8Array } from './query.js'; -import type { SerializedOpenOptions } from './rpc.js'; -import { serializeWasixRuntimeDescriptor } from './runtime-descriptor.js'; -import { serializeWasixStorage } from './storage.js'; -import { restoreWasixStorage, WASIX_PHYSICAL_IDENTITY } from './storage-provider.js'; -import { normalizeWasixStartupGUCs } from './startup-config.js'; -import type { BinaryInput, OpenConfig, WasixRuntimeDescriptor } from './types.js'; - -export function serializeOpenConfig( - config: OpenConfig = {}, - runtimeDescriptor: WasixRuntimeDescriptor = defaultWasixRuntime, -): SerializedOpenOptions { - const extensions = serializeWasixExtensionDescriptors(config.extensions ?? []); - const runtime = serializeWasixRuntimeDescriptor(runtimeDescriptor); - const storage = serializeWasixStorage(config.storage); - return { - runtime, - ...(config.icu === undefined ? {} : { icu: serializeWasixIcuDescriptor(config.icu) }), - extensionCarriers: extensions.carriers, - extensions: extensions.selectedSqlNames, - username: config.username ?? 'postgres', - database: config.database ?? 'postgres', - startupGUCs: normalizeWasixStartupGUCs(config.startupGUCs ?? {}), - storage, - }; -} - -export async function restoreWasix( - storage: OpenConfig['storage'], - bytes: BinaryInput, - validate?: (options: SerializedOpenOptions) => void, -): Promise { - if (storage === undefined) throw new TypeError('WASIX restore requires persistent storage'); - const openOptions = serializeOpenConfig({ storage }); - validate?.(openOptions); - await restoreWasixSerialized(openOptions.storage, toUint8Array(bytes).slice()); -} - -/** @internal Restore already-owned archive bytes inside the selected realm. */ -export async function restoreWasixSerialized( - storage: SerializedOpenOptions['storage'], - bytes: Uint8Array, -): Promise { - const snapshot = decodePhysicalArchive(bytes); - await restoreWasixStorage(storage, snapshot, WASIX_PHYSICAL_IDENTITY); -} diff --git a/src/bindings/wasix-ts/src/client.ts b/src/bindings/wasix-ts/src/client.ts deleted file mode 100644 index 763cf26da..000000000 --- a/src/bindings/wasix-ts/src/client.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { restoreWasix, serializeOpenConfig } from './client-common.js'; -import { - openWasixDirect, - type DirectWasixEnvironment, - type DirectWasixHost, -} from './direct-client-common.js'; -import type { OliphauntClient, OliphauntDatabase, OpenConfig } from './types.js'; - -/** Open PostgreSQL in the importing browser realm. Guest execution may block that realm. */ -export async function openWasix(config: OpenConfig = {}): Promise { - return openWasixWithHost(config, () => import('./host/index.mjs')); -} - -/** @internal Dependency seam for root-entrypoint contract qualification. */ -export async function openWasixWithHost( - config: OpenConfig, - loadHost: () => Promise, -): Promise { - const openOptions = serializeOpenConfig(config); - if (globalThis.crossOriginIsolated !== true) { - throw new Error( - '@oliphaunt/wasix-ts requires COOP: same-origin and COEP: require-corp response headers', - ); - } - const host = await loadHost(); - return openWasixDirect(openOptions, host, browserRealm()); -} - -export const Oliphaunt: OliphauntClient = { - open: openWasix, - restore: restoreWasix, -}; - -function browserRealm(): DirectWasixEnvironment { - return typeof WorkerGlobalScope !== 'undefined' && globalThis instanceof WorkerGlobalScope - ? 'browser-worker' - : 'browser-main'; -} diff --git a/src/bindings/wasix-ts/src/direct.node.ts b/src/bindings/wasix-ts/src/direct.node.ts deleted file mode 100644 index f242cb4f2..000000000 --- a/src/bindings/wasix-ts/src/direct.node.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Oliphaunt, Oliphaunt as default } from './direct-client.js'; -export * from './public.js'; diff --git a/src/bindings/wasix-ts/src/extensions.ts b/src/bindings/wasix-ts/src/extensions.ts deleted file mode 100644 index 1afe2aab7..000000000 --- a/src/bindings/wasix-ts/src/extensions.ts +++ /dev/null @@ -1,1183 +0,0 @@ -import { - clusterSeedMount, - decompressIfNeeded, - type ExtractedArchive, - extractTar, - layoutRuntimeSupport, - loadAsset, - type WasixDirectoryMount, - type WasixRuntimeLayout, -} from './archive.js'; -import type { - SerializedOpenOptions, - SerializedRuntimeDescriptor, - SerializedToolRuntimeDescriptor, -} from './rpc.js'; -import { WASIX_PHYSICAL_IDENTITY, type WasixPhysicalIdentity } from './storage-provider.js'; -import type { WasixAssetManifest } from './types.js'; - -const decoder = new TextDecoder('utf-8', { fatal: true }); -const SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/; -const SHA256 = /^[a-f0-9]{64}$/; -const SHARED_PRELOAD_LIBRARIES = 'shared_preload_libraries'; - -type CatalogProfile = 'standard' | 'icu'; - -type ClusterSeedManifest = { - schema: 'oliphaunt-cluster-seed-v1'; - artifactRole: 'cluster-seed-standard' | 'cluster-seed-icu'; - catalogProfile: CatalogProfile; - runtime: { - product: string; - version: string; - engineFamily: string; - physicalFormat: string; - postgresMajor: number; - compatibilityKey: string; - consumerSha256: string; - producerSha256: string; - initdbSha256: string; - }; - source: { - fingerprint: string; - catalogVersion: string; - lane: string; - producer: string; - }; - initProfile: string; - archive: { - path: string; - sha256: string; - compressedBytes: number; - expandedBytes: number; - regularFiles: number; - directories: number; - }; - requiredRuntimeFeatures: string[]; - extensions: { - selected: string[]; - startupConfiguration: string[]; - }; - icu: null | { - artifactRole: string; - upstreamVersion: string; - sourceCommit: string; - dataTreeSha256: string; - dataVersion: string; - dataForm: string; - }; -}; - -/** Internal kebab-case projection used while installing an imported carrier. */ -type ProjectedExtensionLifecycle = { - 'create-extension': boolean; - 'create-schema'?: string | null; - 'load-sql': readonly string[]; - 'post-create-sql': readonly string[]; - 'startup-config': readonly string[]; - 'shared-memory-required': boolean; -}; - -/** Internal install shape projected solely from extension-owned carrier metadata. */ -type ProjectedExtensionInstall = { - name: string; - 'sql-name': string; - archive: string; - sha256: string; - size: number; - 'native-module'?: string | null; - 'native-modules': readonly unknown[]; - dependencies: readonly string[]; - 'load-order': readonly string[]; - lifecycle: ProjectedExtensionLifecycle; - 'installed-files': readonly string[]; - 'unresolved-imports': readonly unknown[]; -}; - -export type ResolvedWasixExtensions = { - extensions: ProjectedExtensionInstall[]; - runtimeDependencies: string[]; -}; - -export type PreparedWasixRuntime = { - layout: WasixRuntimeLayout; - loadClusterSeed(): Promise; - moduleSha256: string; - catalogProfile: 'standard' | 'icu'; - icuEnabled: boolean; - startupGUCs: Record; - physicalIdentity: WasixPhysicalIdentity; -}; - -/** - * Loads and verifies one exact runtime/ICU/extension closure. The matching - * cluster seed stays lazy until an exclusively leased storage provider reports - * a new root. Selection materializes exact artifacts and required startup - * configuration; database-local installation remains explicit application SQL. - */ -export async function prepareWasixRuntime( - options: SerializedOpenOptions, -): Promise { - const descriptor = options.runtime; - const profile = options.icu === undefined ? 'standard' : 'icu'; - const seedArchiveDescriptor = options.icu?.clusterSeedArchive ?? descriptor.standardSeedArchive; - const seedManifestDescriptor = - options.icu?.clusterSeedManifest ?? descriptor.standardSeedManifest; - const prefetchedSeedAssets = - options.storage.kind === 'memory' - ? loadClusterSeedAssets(profile, seedArchiveDescriptor, seedManifestDescriptor) - : undefined; - // Memory storage is always new, so overlap its required seed download with - // the runtime closure. Persistent providers must inspect storage first. - void prefetchedSeedAssets?.catch(() => undefined); - const [manifestBytes, runtimeBytes, icuDataBytes] = await Promise.all([ - loadAsset(descriptor.manifest.source, 'WASIX asset manifest'), - loadAsset(descriptor.runtimeArchive.source, 'WASIX runtime archive'), - options.icu === undefined - ? Promise.resolve(undefined) - : loadAsset(options.icu.dataArchive.source, 'WASIX ICU data archive'), - ]); - await Promise.all([ - assertDeclaredAssetBytes( - manifestBytes, - descriptor.manifest.size, - descriptor.manifest.sha256, - 'WASIX asset manifest', - ), - assertDeclaredAssetBytes( - runtimeBytes, - descriptor.runtimeArchive.size, - descriptor.runtimeArchive.sha256, - 'WASIX runtime archive', - ), - ...(options.icu === undefined || icuDataBytes === undefined - ? [] - : [ - assertDeclaredAssetBytes( - icuDataBytes, - options.icu.dataArchive.size, - options.icu.dataArchive.sha256, - 'WASIX ICU data archive', - ), - ]), - ]); - const manifest = parseWasixAssetManifest(manifestBytes); - assertRuntimeDescriptorMatchesManifest(descriptor, manifest); - const selectedSeed = manifest['cluster-seeds'][profile]; - assertRuntimeArchiveMatchesManifest( - seedArchiveDescriptor, - selectedSeed, - `WASIX ${profile} cluster seed archive`, - ); - if (options.icu !== undefined) { - assertIcuDescriptorMatchesRuntime(options.runtime, options.icu, manifest); - } - const eagerClusterSeed = - prefetchedSeedAssets === undefined - ? undefined - : loadClusterSeed( - options, - manifest, - selectedSeed, - profile, - seedArchiveDescriptor, - seedManifestDescriptor, - prefetchedSeedAssets, - ); - void eagerClusterSeed?.catch(() => undefined); - const runtime = extractTar(decompressIfNeeded(runtimeBytes)); - if (options.icu !== undefined && icuDataBytes !== undefined) { - const icuArchive = extractTar(decompressIfNeeded(icuDataBytes)); - overlayIcuArchive(runtime, icuArchive); - } - const layout = layoutRuntimeSupport(runtime); - assertExtensionCarriersCompatible(descriptor, manifest, options.extensionCarriers); - - const resolved = resolveWasixExtensions(manifest, options.extensionCarriers, options.extensions); - assertExactCarrierClosure(resolved.extensions, options.extensionCarriers); - const loaded = await Promise.all( - resolved.extensions.map(async (extension) => { - if (extension['unresolved-imports'].length > 0) { - throw new Error( - `WASIX extension '${extension['sql-name']}' carrier has unresolved imports`, - ); - } - const carrier = Object.hasOwn(options.extensionCarriers, extension['sql-name']) - ? options.extensionCarriers[extension['sql-name']] - : undefined; - if (carrier === undefined) { - throw new Error( - `selected WASIX extension '${extension['sql-name']}' requires exact carrier ${extension.archive}`, - ); - } - const bytes = await loadAsset( - carrier.source, - `WASIX extension ${extension['sql-name']} from ${carrier.product}@${carrier.version}`, - ); - if (bytes.length !== extension.size) { - throw new Error( - `WASIX extension '${extension['sql-name']}' carrier size mismatch: expected ${extension.size}, received ${bytes.length}`, - ); - } - await assertSha256( - bytes, - extension.sha256, - `WASIX extension '${extension['sql-name']}' carrier`, - ); - return [extension, extractTar(decompressIfNeeded(bytes))] as const; - }), - ); - for (const [extension, archive] of loaded) { - overlayExtensionArchive(layout, archive, extension); - } - - return { - layout, - loadClusterSeed: lazyClusterSeedLoader( - options, - manifest, - selectedSeed, - profile, - seedArchiveDescriptor, - seedManifestDescriptor, - eagerClusterSeed, - ), - moduleSha256: manifest.runtime['module-sha256'], - catalogProfile: profile, - icuEnabled: options.icu !== undefined, - startupGUCs: mergeExtensionStartupGUCs(options.startupGUCs, resolved.extensions), - physicalIdentity: WASIX_PHYSICAL_IDENTITY, - }; -} - -function lazyClusterSeedLoader( - options: SerializedOpenOptions, - manifest: WasixAssetManifest, - selectedSeed: WasixAssetManifest['cluster-seeds'][CatalogProfile], - profile: CatalogProfile, - archiveDescriptor: SerializedRuntimeDescriptor['standardSeedArchive'], - manifestDescriptor: SerializedRuntimeDescriptor['standardSeedManifest'], - eager?: Promise, -): () => Promise { - let cached = eager; - const forgetRejectedAttempt = (attempt: Promise) => { - void attempt.catch(() => { - if (cached === attempt) cached = undefined; - }); - }; - if (cached !== undefined) forgetRejectedAttempt(cached); - return () => { - if (cached === undefined) { - const attempt = loadClusterSeed( - options, - manifest, - selectedSeed, - profile, - archiveDescriptor, - manifestDescriptor, - ); - cached = attempt; - forgetRejectedAttempt(attempt); - } - return cached; - }; -} - -type ClusterSeedAssets = readonly [archive: Uint8Array, manifest: Uint8Array]; - -function loadClusterSeedAssets( - profile: CatalogProfile, - archiveDescriptor: SerializedRuntimeDescriptor['standardSeedArchive'], - manifestDescriptor: SerializedRuntimeDescriptor['standardSeedManifest'], -): Promise { - return Promise.all([ - loadAsset(archiveDescriptor.source, `WASIX ${profile} cluster seed`), - loadAsset(manifestDescriptor.source, `WASIX ${profile} cluster seed manifest`), - ]); -} - -async function loadClusterSeed( - options: SerializedOpenOptions, - manifest: WasixAssetManifest, - selectedSeed: WasixAssetManifest['cluster-seeds'][CatalogProfile], - profile: CatalogProfile, - archiveDescriptor: SerializedRuntimeDescriptor['standardSeedArchive'], - manifestDescriptor: SerializedRuntimeDescriptor['standardSeedManifest'], - assets?: Promise, -): Promise { - const [archiveBytes, manifestBytes] = await (assets ?? - loadClusterSeedAssets(profile, archiveDescriptor, manifestDescriptor)); - await Promise.all([ - assertDeclaredAssetBytes( - archiveBytes, - archiveDescriptor.size, - archiveDescriptor.sha256, - `WASIX ${profile} cluster seed`, - ), - assertDeclaredAssetBytes( - manifestBytes, - manifestDescriptor.size, - manifestDescriptor.sha256, - `WASIX ${profile} cluster seed manifest`, - ), - ]); - const seedManifest = parseClusterSeedManifest(manifestBytes, profile); - verifyClusterSeedIdentity(options, manifest, selectedSeed, seedManifest, archiveDescriptor); - const seed = extractTar(decompressIfNeeded(archiveBytes)); - verifyPostgresIdentity(manifest, selectedSeed, seed.files.get('PG_VERSION')); - return clusterSeedMount(seed); -} - -/** Require the package-authored archive identities to match the canonical manifest. */ -export function assertRuntimeDescriptorMatchesManifest( - descriptor: SerializedRuntimeDescriptor, - manifest: WasixAssetManifest, -): void { - assertToolRuntimeDescriptorMatchesManifest(descriptor, manifest); - assertRuntimeArchiveMatchesManifest( - descriptor.standardSeedArchive, - manifest['cluster-seeds'].standard, - 'WASIX standard cluster seed archive', - ); -} - -/** Verify only the runtime assets consumed by PostgreSQL frontend tools. */ -export function assertToolRuntimeDescriptorMatchesManifest( - descriptor: SerializedToolRuntimeDescriptor, - manifest: WasixAssetManifest, -): void { - assertRuntimeArchiveMatchesManifest( - descriptor.runtimeArchive, - manifest.runtime, - 'WASIX runtime archive', - ); -} - -export function assertExactCarrierClosure( - resolved: readonly ProjectedExtensionInstall[], - carriers: SerializedOpenOptions['extensionCarriers'], -): void { - const expected = new Set(resolved.map((extension) => extension['sql-name'])); - const actual = new Set(Object.keys(carriers)); - const missing = [...expected].filter((sqlName) => !actual.has(sqlName)).sort(); - const unexpected = [...actual].filter((sqlName) => !expected.has(sqlName)).sort(); - if (missing.length > 0 || unexpected.length > 0) { - throw new Error( - 'WASIX extension carrier closure does not match imported dependency resolution' + - `${missing.length > 0 ? `; missing ${missing.join(', ')}` : ''}` + - `${unexpected.length > 0 ? `; unexpected ${unexpected.join(', ')}` : ''}`, - ); - } -} - -export function parseWasixAssetManifest(bytes: Uint8Array): WasixAssetManifest { - let parsed: unknown; - try { - parsed = JSON.parse(decodeUtf8(bytes)); - } catch (error) { - throw new Error(`WASIX asset manifest is not valid UTF-8 JSON: ${describeError(error)}`); - } - const manifest = requireObject(parsed, 'WASIX asset manifest'); - if (manifest['format-version'] !== 2) { - throw new Error('WASIX asset manifest must use format-version 2'); - } - - const runtime = requireObject(manifest.runtime, 'WASIX asset manifest runtime'); - requireAssetPath(runtime.archive, 'WASIX runtime archive'); - requireSha256(runtime.sha256, 'WASIX runtime archive'); - if (runtime.size !== undefined) { - requireSafeInteger(runtime.size, 'WASIX runtime archive size'); - } - requireSha256(runtime['module-sha256'], 'WASIX runtime module'); - requireString(runtime['postgres-version'], 'WASIX runtime PostgreSQL version'); - const link = requireObject(runtime.link, 'WASIX runtime link metadata'); - const exports = requireArray(link.exports, 'WASIX runtime exports'); - for (const [index, value] of exports.entries()) { - const entry = requireObject(value, `WASIX runtime export ${index}`); - requireString(entry.name, `WASIX runtime export ${index} name`); - requireString(entry.kind, `WASIX runtime export ${index} kind`); - } - - const seeds = requireObject(manifest['cluster-seeds'], 'WASIX asset manifest cluster-seeds'); - requireExactKeys(seeds, ['icu', 'standard'], 'WASIX asset manifest cluster-seeds'); - for (const profile of ['standard', 'icu'] as const) { - const seed = requireObject(seeds[profile], `WASIX ${profile} cluster seed`); - const expectedRole = profile === 'standard' ? 'cluster-seed-standard' : 'cluster-seed-icu'; - if (seed['catalog-profile'] !== profile || seed['artifact-role'] !== expectedRole) { - throw new Error(`WASIX ${profile} cluster seed has a mismatched profile or artifact role`); - } - requireAssetPath(seed.archive, `WASIX ${profile} cluster seed archive`); - requireAssetPath(seed.manifest, `WASIX ${profile} cluster seed manifest`); - requireSha256(seed.sha256, `WASIX ${profile} cluster seed archive`); - requireSafeInteger(seed.size, `WASIX ${profile} cluster seed archive size`); - requireSha256(seed['runtime-module-sha256'], `WASIX ${profile} seed runtime module`); - requireString(seed['postgres-version'], `WASIX ${profile} seed PostgreSQL version`); - requireString(seed['source-fingerprint'], `WASIX ${profile} seed source fingerprint`); - if ( - seed['physical-format'] !== 'wasix-pg18-v1' || - seed['compatibility-key'] !== 'wasix-pg18-datum32-v1' - ) { - throw new Error(`WASIX ${profile} cluster seed has an incompatible physical identity`); - } - if (profile === 'icu') { - requireSha256(seed['icu-data-tree-sha256'], 'WASIX ICU seed data tree'); - } else if (seed['icu-data-tree-sha256'] !== undefined) { - throw new Error('WASIX standard cluster seed must not identify ICU data'); - } - } - requireString(manifest['source-fingerprint'], 'WASIX asset source fingerprint'); - - const runtimeSupport = requireArray(manifest['runtime-support'], 'WASIX runtime-support entries'); - for (const [index, value] of runtimeSupport.entries()) { - const support = requireObject(value, `WASIX runtime-support entry ${index}`); - requireSqlName(support.name, `WASIX runtime-support entry ${index} name`); - requireInstallPath(support.path, `WASIX runtime-support entry ${index} path`); - requireSha256(support.sha256, `WASIX runtime-support entry ${index}`); - } - - const extensions = requireArray(manifest.extensions, 'WASIX extension entries'); - if (extensions.length !== 0) { - throw new Error( - 'WASIX core asset manifest must not contain extension rows; import extension carriers explicitly', - ); - } - - return parsed as WasixAssetManifest; -} - -export function resolveWasixExtensions( - manifest: WasixAssetManifest, - carriers: SerializedOpenOptions['extensionCarriers'], - requested: readonly string[], -): ResolvedWasixExtensions { - const runtimeSupport = new Set(manifest['runtime-support'].map((entry) => entry.name)); - const bySqlName = new Map( - Object.entries(carriers).map(([sqlName, carrier]) => { - if (carrier.sqlName !== sqlName) { - throw new Error( - `WASIX extension carrier map key '${sqlName}' does not match carrier SQL name '${carrier.sqlName}'`, - ); - } - if (runtimeSupport.has(sqlName)) { - throw new Error( - `WASIX extension carrier '${sqlName}' cannot replace runtime-provided support`, - ); - } - return [sqlName, extensionFromCarrier(carrier)] as const; - }), - ); - const visiting = new Set(); - const visited = new Set(); - const runtimeDependencies = new Set(); - const resolved: ProjectedExtensionInstall[] = []; - - const visit = (extension: ProjectedExtensionInstall): void => { - const sqlName = extension['sql-name']; - if (visited.has(sqlName)) { - return; - } - if (extension.lifecycle['shared-memory-required']) { - throw new Error( - `selected WASIX extension '${sqlName}' requires shared-memory behavior that the @oliphaunt/wasix-ts host has not qualified`, - ); - } - if (visiting.has(sqlName)) { - throw new Error(`cyclic WASIX extension dependency involving '${sqlName}'`); - } - visiting.add(sqlName); - for (const dependency of extension.dependencies) { - if (runtimeSupport.has(dependency)) { - runtimeDependencies.add(dependency); - } else { - const dependencyExtension = bySqlName.get(dependency); - if (dependencyExtension !== undefined) { - visit(dependencyExtension); - continue; - } - throw new Error( - `selected WASIX extension '${sqlName}' depends on unavailable extension '${dependency}'`, - ); - } - } - visiting.delete(sqlName); - visited.add(sqlName); - resolved.push(extension); - }; - - for (const sqlName of [...new Set(requested)].sort()) { - requireSqlName(sqlName, 'selected WASIX extension'); - const extension = bySqlName.get(sqlName); - if (extension === undefined) { - throw new Error(`selected WASIX extension '${sqlName}' has no imported carrier`); - } - visit(extension); - } - return { - extensions: resolved, - runtimeDependencies: [...runtimeDependencies].sort(), - }; -} - -function extensionFromCarrier( - carrier: SerializedOpenOptions['extensionCarriers'][string], -): ProjectedExtensionInstall { - const lifecycle = carrier.install.lifecycle; - return { - name: carrier.install.name, - 'sql-name': carrier.sqlName, - archive: carrier.archive, - sha256: carrier.sha256, - size: carrier.size, - 'native-module': carrier.install.nativeModule, - 'native-modules': carrier.install.nativeModules, - dependencies: carrier.install.dependencies, - 'load-order': carrier.install.loadOrder, - lifecycle: { - 'create-extension': lifecycle.createExtension, - ...(lifecycle.createSchema === undefined ? {} : { 'create-schema': lifecycle.createSchema }), - 'load-sql': lifecycle.loadSql, - 'post-create-sql': lifecycle.postCreateSql, - 'startup-config': lifecycle.startupConfig, - 'shared-memory-required': lifecycle.sharedMemoryRequired, - }, - 'installed-files': carrier.install.installedFiles, - 'unresolved-imports': carrier.install.unresolvedImports, - }; -} - -export function assertExtensionCarriersCompatible( - runtime: SerializedRuntimeDescriptor, - manifest: WasixAssetManifest, - carriers: SerializedOpenOptions['extensionCarriers'], -): void { - const postgresMajor = manifest.runtime['postgres-version'].split('.')[0]; - for (const carrier of Object.values(carriers)) { - const compatibility = carrier.compatibility; - if (compatibility.extensionRuntimeContract !== 'oliphaunt-extension-runtime-contract-v1') { - throw new Error( - `WASIX extension '${carrier.sqlName}' has an unsupported extension runtime contract`, - ); - } - if ( - compatibility.wasixRuntimeProduct !== runtime.product || - compatibility.wasixRuntimeVersion !== runtime.version - ) { - throw new Error( - `WASIX extension '${carrier.sqlName}' targets ${compatibility.wasixRuntimeProduct}@${compatibility.wasixRuntimeVersion}, not ${runtime.product}@${runtime.version}`, - ); - } - if (compatibility.postgresMajor !== postgresMajor) { - throw new Error( - `WASIX extension '${carrier.sqlName}' targets PostgreSQL ${compatibility.postgresMajor}, not ${postgresMajor}`, - ); - } - } - const coreExports = new Set( - manifest.runtime.link.exports - .filter((entry) => entry.kind === 'func' || entry.kind === 'global') - .map((entry) => entry.name), - ); - for (const carrier of Object.values(carriers)) { - const missing = carrier.install.coreExportsRequired.filter((name) => !coreExports.has(name)); - if (missing.length > 0) { - throw new Error( - `WASIX extension '${carrier.sqlName}' requires exports absent from the selected core runtime: ${missing.join(', ')}`, - ); - } - } -} - -export function overlayExtensionArchive( - layout: WasixRuntimeLayout, - archive: ExtractedArchive, - extension: ProjectedExtensionInstall, -): void { - const sqlName = extension['sql-name']; - const expected = new Set(extension['installed-files']); - if (expected.size !== extension['installed-files'].length) { - throw new Error(`WASIX extension '${sqlName}' manifest repeats installed file paths`); - } - const actual = new Set(archive.files.keys()); - const missing = [...expected].filter((path) => !actual.has(path)); - const unexpected = [...actual].filter((path) => !expected.has(path)); - if (missing.length > 0 || unexpected.length > 0) { - throw new Error( - `WASIX extension '${sqlName}' archive contents do not match installed-files` + - `${missing.length > 0 ? `; missing ${missing.join(', ')}` : ''}` + - `${unexpected.length > 0 ? `; unexpected ${unexpected.join(', ')}` : ''}`, - ); - } - - for (const [path, bytes] of archive.files) { - const { mountPath, relative } = extensionMountTarget(path, sqlName); - const mount = layout.mounts[mountPath]; - if (mount === undefined) { - throw new Error(`WASIX runtime is missing extension mount ${mountPath}`); - } - if (Object.hasOwn(mount.files, relative)) { - throw new Error(`WASIX extension '${sqlName}' collides with installed file ${path}`); - } - mount.files[relative] = bytes; - } - for (const path of archive.directories) { - if (path === 'lib' || path === 'share') { - continue; - } - const { mountPath, relative } = extensionMountTarget(path, sqlName, true); - const mount = layout.mounts[mountPath]; - if (mount === undefined) { - throw new Error(`WASIX runtime is missing extension mount ${mountPath}`); - } - if (!mount.directories.includes(relative)) { - mount.directories.push(relative); - } - } -} - -export function mergeExtensionStartupGUCs( - configured: Readonly>, - extensions: readonly ProjectedExtensionInstall[], -): Record { - const merged = { ...configured }; - const sharedPreloads: string[] = []; - const seenSharedPreloads = new Set(); - appendCsv(merged[SHARED_PRELOAD_LIBRARIES], sharedPreloads, seenSharedPreloads); - - for (const extension of extensions) { - for (const assignment of extension.lifecycle['startup-config']) { - const equals = assignment.indexOf('='); - const name = assignment.slice(0, equals).trim(); - const value = assignment.slice(equals + 1).trim(); - if (equals <= 0 || !/^[A-Za-z][A-Za-z0-9_.]*$/.test(name) || value.length === 0) { - throw new Error( - `WASIX extension '${extension['sql-name']}' has invalid startup config '${assignment}'`, - ); - } - if (name === SHARED_PRELOAD_LIBRARIES) { - appendCsv(value, sharedPreloads, seenSharedPreloads); - continue; - } - const existing = merged[name]; - if (existing !== undefined && existing !== value) { - throw new Error( - `WASIX extension '${extension['sql-name']}' requires ${name}=${value}, but the caller configured ${name}=${existing}`, - ); - } - merged[name] = value; - } - } - if (sharedPreloads.length > 0) { - merged[SHARED_PRELOAD_LIBRARIES] = sharedPreloads.join(','); - } - return merged; -} - -function parseClusterSeedManifest( - bytes: Uint8Array, - expectedProfile: CatalogProfile, -): ClusterSeedManifest { - let parsed: unknown; - try { - parsed = JSON.parse(decodeUtf8(bytes)); - } catch (error) { - throw new Error( - `WASIX ${expectedProfile} cluster seed manifest is not valid UTF-8 JSON: ${describeError(error)}`, - ); - } - const label = `WASIX ${expectedProfile} cluster seed manifest`; - const root = requireObject(parsed, label); - requireExactKeys( - root, - [ - 'archive', - 'artifactRole', - 'catalogProfile', - 'extensions', - 'icu', - 'initProfile', - 'requiredRuntimeFeatures', - 'runtime', - 'schema', - 'source', - ], - label, - ); - assertClusterSeedProfileContract(root, expectedProfile); - requireString(root.initProfile, `${label} init profile`); - - const runtime = requireObject(root.runtime, `${label} runtime`); - requireExactKeys( - runtime, - [ - 'compatibilityKey', - 'consumerSha256', - 'engineFamily', - 'initdbSha256', - 'physicalFormat', - 'postgresMajor', - 'producerSha256', - 'product', - 'version', - ], - `${label} runtime`, - ); - for (const field of [ - 'product', - 'version', - 'engineFamily', - 'physicalFormat', - 'compatibilityKey', - ] as const) { - requireString(runtime[field], `${label} runtime ${field}`); - } - requirePositiveInteger(runtime.postgresMajor, `${label} runtime PostgreSQL major`); - for (const field of ['consumerSha256', 'producerSha256', 'initdbSha256'] as const) { - requireSha256(runtime[field], `${label} runtime ${field}`); - } - - const source = requireObject(root.source, `${label} source`); - requireExactKeys( - source, - ['catalogVersion', 'fingerprint', 'lane', 'producer'], - `${label} source`, - ); - for (const field of ['catalogVersion', 'fingerprint', 'lane', 'producer'] as const) { - requireString(source[field], `${label} source ${field}`); - } - - const archive = requireObject(root.archive, `${label} archive`); - requireExactKeys( - archive, - ['compressedBytes', 'directories', 'expandedBytes', 'path', 'regularFiles', 'sha256'], - `${label} archive`, - ); - requireAssetPath(archive.path, `${label} archive path`); - requireSha256(archive.sha256, `${label} archive`); - for (const field of [ - 'compressedBytes', - 'directories', - 'expandedBytes', - 'regularFiles', - ] as const) { - requirePositiveInteger(archive[field], `${label} archive ${field}`); - } - - const extensions = requireObject(root.extensions, `${label} extensions`); - requireExactKeys(extensions, ['selected', 'startupConfiguration'], `${label} extensions`); - const selected = requireStringArray(extensions.selected, `${label} selected extensions`); - const startupConfiguration = requireStringArray( - extensions.startupConfiguration, - `${label} startup configuration`, - ); - if (selected.length !== 0 || startupConfiguration.length !== 0) { - throw new Error(`${label} must be extension-free`); - } - - return parsed as ClusterSeedManifest; -} - -/** @internal Validate the host-independent standard/ICU seed profile contract. */ -export function assertClusterSeedProfileContract( - value: unknown, - expectedProfile: CatalogProfile, -): void { - const label = `WASIX ${expectedProfile} cluster seed manifest`; - const root = requireObject(value, label); - if (root.schema !== 'oliphaunt-cluster-seed-v1') { - throw new Error(`${label} has an unsupported schema`); - } - if (root.catalogProfile !== expectedProfile) { - throw new Error( - `${label} profile mismatch: expected ${expectedProfile}, got ${String(root.catalogProfile)}`, - ); - } - const expectedRole = - expectedProfile === 'standard' ? 'cluster-seed-standard' : 'cluster-seed-icu'; - if (root.artifactRole !== expectedRole) { - throw new Error( - `${label} profile mismatch: expected role ${expectedRole}, got ${String(root.artifactRole)}`, - ); - } - - const requiredFeatures = requireStringArray( - root.requiredRuntimeFeatures, - `${label} required features`, - ); - if (expectedProfile === 'standard') { - if (requiredFeatures.length !== 0 || root.icu !== null) { - throw new Error(`${label} must not require or identify ICU data`); - } - return; - } - if (requiredFeatures.length !== 1 || requiredFeatures[0] !== 'icu') { - throw new Error(`${label} must require exactly the ICU runtime feature`); - } - const icu = requireObject(root.icu, `${label} ICU identity`); - requireExactKeys( - icu, - [ - 'artifactRole', - 'dataForm', - 'dataTreeSha256', - 'dataVersion', - 'sourceCommit', - 'upstreamVersion', - ], - `${label} ICU identity`, - ); - for (const field of [ - 'artifactRole', - 'dataForm', - 'dataVersion', - 'sourceCommit', - 'upstreamVersion', - ] as const) { - requireString(icu[field], `${label} ICU ${field}`); - } - requireSha256(icu.dataTreeSha256, `${label} ICU data tree`); - if ( - icu.artifactRole !== 'icu-data' || - icu.upstreamVersion !== '76.1' || - icu.dataVersion !== '76.1' || - icu.dataForm !== 'files-le' - ) { - throw new Error(`${label} has an incompatible ICU identity`); - } -} - -/** @internal Verify that a separately distributed ICU carrier belongs to this runtime. */ -export function assertIcuDescriptorMatchesRuntime( - runtime: SerializedRuntimeDescriptor, - icu: NonNullable, - manifest: WasixAssetManifest, -): void { - if ( - icu.compatibility.runtimeProduct !== runtime.product || - icu.compatibility.runtimeVersion !== runtime.version - ) { - throw new Error( - `WASIX ICU carrier targets ${icu.compatibility.runtimeProduct}@${icu.compatibility.runtimeVersion}, not ${runtime.product}@${runtime.version}`, - ); - } - if (icu.compatibility.dataTreeSha256 !== manifest['cluster-seeds'].icu['icu-data-tree-sha256']) { - throw new Error('WASIX ICU data and ICU cluster seed identify different logical data trees'); - } -} - -function verifyClusterSeedIdentity( - options: SerializedOpenOptions, - outer: WasixAssetManifest, - selected: WasixAssetManifest['cluster-seeds'][CatalogProfile], - seed: ClusterSeedManifest, - archive: SerializedRuntimeDescriptor['runtimeArchive'], -): void { - const profile = seed.catalogProfile; - if ( - seed.runtime.product !== options.runtime.product || - seed.runtime.version !== options.runtime.version || - seed.runtime.engineFamily !== 'wasix' || - seed.runtime.physicalFormat !== 'wasix-pg18-v1' || - seed.runtime.compatibilityKey !== 'wasix-pg18-datum32-v1' || - seed.runtime.postgresMajor !== 18 - ) { - throw new Error(`WASIX ${profile} cluster seed has an incompatible runtime identity`); - } - if ( - seed.runtime.consumerSha256 !== seed.runtime.producerSha256 || - seed.runtime.consumerSha256 !== outer.runtime['module-sha256'] || - seed.runtime.consumerSha256 !== selected['runtime-module-sha256'] - ) { - throw new Error(`WASIX ${profile} cluster seed was produced by a different runtime module`); - } - if ( - seed.source.fingerprint !== outer['source-fingerprint'] || - seed.source.fingerprint !== selected['source-fingerprint'] - ) { - throw new Error(`WASIX ${profile} cluster seed has a different source fingerprint`); - } - if ( - seed.archive.path !== archive.archive || - seed.archive.path !== selected.archive || - seed.archive.sha256 !== archive.sha256 || - seed.archive.sha256 !== selected.sha256 || - seed.archive.compressedBytes !== archive.size || - seed.archive.compressedBytes !== selected.size - ) { - throw new Error(`WASIX ${profile} cluster seed archive identity is inconsistent`); - } - if (seed.archive.path !== `cluster-seeds/${profile}.tar.zst`) { - throw new Error(`WASIX ${profile} cluster seed has a non-canonical archive path`); - } - if (profile === 'icu') { - const icu = options.icu; - if ( - icu === undefined || - seed.icu === null || - seed.icu.artifactRole !== 'icu-data' || - seed.icu.upstreamVersion !== icu.compatibility.dataVersion || - seed.icu.dataVersion !== icu.compatibility.dataVersion || - seed.icu.dataForm !== icu.compatibility.dataForm || - seed.icu.dataTreeSha256 !== icu.compatibility.dataTreeSha256 - ) { - throw new Error('WASIX ICU cluster seed does not match the selected ICU data carrier'); - } - } -} - -/** @internal Validate and add exact-archive-verified ICU files to the runtime tree. */ -export function overlayIcuArchive(runtime: ExtractedArchive, icu: ExtractedArchive): void { - const prefix = 'share/icu/'; - const rows: { path: string; bytes: Uint8Array }[] = []; - const directories: string[] = []; - let hasDataFile = false; - for (const [path, bytes] of icu.files) { - if (!path.startsWith(prefix) || path.length === prefix.length) { - throw new Error(`WASIX ICU data archive contains a file outside share/icu: ${path}`); - } - const relative = path.slice(prefix.length); - if (relative.split('/').some((segment) => segment.startsWith('icudt'))) hasDataFile = true; - rows.push({ path: relative, bytes }); - const target = `oliphaunt/${path}`; - if (runtime.files.has(target) || runtime.directories.has(target)) { - throw new Error(`WASIX ICU data collides with runtime path ${target}`); - } - } - if (rows.length === 0 || !hasDataFile) { - throw new Error('WASIX ICU data archive contains no ICU data files under share/icu'); - } - for (const path of icu.directories) { - if (path !== 'share' && path !== 'share/icu' && !path.startsWith(prefix)) { - throw new Error(`WASIX ICU data archive contains a directory outside share/icu: ${path}`); - } - if (path === 'share') continue; - const target = `oliphaunt/${path}`; - if (runtime.files.has(target)) { - throw new Error(`WASIX ICU data collides with runtime path ${target}`); - } - directories.push(target); - } - for (const { path, bytes } of rows) runtime.files.set(`oliphaunt/share/icu/${path}`, bytes); - for (const path of directories) runtime.directories.add(path); -} - -function assertRuntimeArchiveMatchesManifest( - descriptor: SerializedRuntimeDescriptor['runtimeArchive'], - manifest: { archive: string; sha256: string; size?: number }, - label: string, -): void { - if (descriptor.archive !== manifest.archive) { - throw new Error( - `${label} path does not match the canonical manifest: expected ${manifest.archive}, received ${descriptor.archive}`, - ); - } - if (descriptor.sha256 !== manifest.sha256) { - throw new Error(`${label} SHA-256 does not match the canonical manifest`); - } - if (manifest.size !== undefined && descriptor.size !== manifest.size) { - throw new Error( - `${label} size does not match the canonical manifest: expected ${manifest.size}, received ${descriptor.size}`, - ); - } -} - -async function assertDeclaredAssetBytes( - bytes: Uint8Array, - expectedSize: number, - expectedSha256: string, - label: string, -): Promise { - if (bytes.length !== expectedSize) { - throw new Error(`${label} size mismatch: expected ${expectedSize}, received ${bytes.length}`); - } - await assertSha256(bytes, expectedSha256, label); -} - -function verifyPostgresIdentity( - manifest: WasixAssetManifest, - seed: WasixAssetManifest['cluster-seeds'][CatalogProfile], - pgVersionBytes: Uint8Array | undefined, -): void { - if (pgVersionBytes === undefined) { - throw new Error('WASIX cluster seed is missing PG_VERSION'); - } - const pgVersion = decodeUtf8(pgVersionBytes).trim(); - const runtimeMajor = manifest.runtime['postgres-version'].split('.')[0]; - const seedMajor = seed['postgres-version'].split('.')[0]; - if (pgVersion !== runtimeMajor || pgVersion !== seedMajor) { - throw new Error( - `WASIX runtime/cluster seed PostgreSQL major mismatch: runtime ${runtimeMajor}, seed ${seedMajor}, PG_VERSION ${pgVersion}`, - ); - } -} - -function decodeUtf8(bytes: Uint8Array): string { - const input = - typeof SharedArrayBuffer !== 'undefined' && bytes.buffer instanceof SharedArrayBuffer - ? Uint8Array.from(bytes) - : bytes; - return decoder.decode(input); -} - -/** @internal Shared verification for separately carried WASIX tool modules. */ -export async function assertSha256( - bytes: Uint8Array, - expected: string, - label: string, -): Promise { - if (globalThis.crypto?.subtle === undefined) { - throw new Error(`Web Crypto is required to verify ${label}`); - } - const actual = await sha256Hex(bytes); - if (actual !== expected) { - throw new Error(`${label} SHA-256 mismatch: expected ${expected}, received ${actual}`); - } -} - -async function sha256Hex(bytes: Uint8Array): Promise { - if (globalThis.crypto?.subtle === undefined) { - throw new Error('Web Crypto is required to calculate SHA-256'); - } - const source = - bytes.buffer instanceof ArrayBuffer - ? new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength) - : bytes.slice().buffer; - const digest = new Uint8Array(await globalThis.crypto.subtle.digest('SHA-256', source)); - return [...digest].map((byte) => byte.toString(16).padStart(2, '0')).join(''); -} - -function extensionMountTarget( - path: string, - sqlName: string, - directory = false, -): { mountPath: '/lib' | '/share'; relative: string } { - const allowed = [ - 'lib/postgresql/', - 'share/proj/', - 'share/postgresql/extension/', - 'share/postgresql/tsearch_data/', - ]; - const allowedDirectory = new Set([ - 'lib/postgresql', - 'share/proj', - 'share/postgresql', - 'share/postgresql/extension', - 'share/postgresql/tsearch_data', - ]); - if ( - !allowed.some((prefix) => path.startsWith(prefix)) && - !(directory && allowedDirectory.has(path)) - ) { - throw new Error(`WASIX extension '${sqlName}' contains non-canonical install path ${path}`); - } - const slash = path.indexOf('/'); - return { - mountPath: path.slice(0, slash) === 'lib' ? '/lib' : '/share', - relative: path.slice(slash + 1), - }; -} - -function appendCsv(value: string | undefined, ordered: string[], seen: Set): void { - for (const item of value?.split(',') ?? []) { - const trimmed = item.trim(); - if (trimmed.length > 0 && !seen.has(trimmed)) { - seen.add(trimmed); - ordered.push(trimmed); - } - } -} - -function requireObject(value: unknown, label: string): Record { - if (value === null || typeof value !== 'object' || Array.isArray(value)) { - throw new Error(`${label} must be an object`); - } - return value as Record; -} - -function requireArray(value: unknown, label: string): unknown[] { - if (!Array.isArray(value)) { - throw new Error(`${label} must be an array`); - } - return value; -} - -function requireExactKeys( - value: Record, - expected: readonly string[], - label: string, -): void { - const actual = Object.keys(value).sort(); - const canonical = [...expected].sort(); - if (actual.length !== canonical.length || actual.some((key, index) => key !== canonical[index])) { - const missing = canonical.filter((key) => !Object.hasOwn(value, key)); - const unexpected = actual.filter((key) => !canonical.includes(key)); - throw new Error( - `${label} fields do not match the contract` + - `${missing.length > 0 ? `; missing ${missing.join(', ')}` : ''}` + - `${unexpected.length > 0 ? `; unexpected ${unexpected.join(', ')}` : ''}`, - ); - } -} - -function requireStringArray(value: unknown, label: string): string[] { - const values = requireArray(value, label); - return values.map((entry, index) => requireString(entry, `${label} entry ${index}`)); -} - -function requireString(value: unknown, label: string): string { - if (typeof value !== 'string' || value.length === 0 || value.includes('\0')) { - throw new Error(`${label} must be a non-empty string without NUL bytes`); - } - return value; -} - -function requireSqlName(value: unknown, label: string): string { - const name = requireString(value, label); - if (!SQL_NAME.test(name)) { - throw new Error(`${label} must be a portable PostgreSQL extension name`); - } - return name; -} - -function requireSha256(value: unknown, label: string): string { - const hash = requireString(value, `${label} SHA-256`); - if (!SHA256.test(hash)) { - throw new Error(`${label} SHA-256 must be 64 lowercase hexadecimal characters`); - } - return hash; -} - -function requireSafeInteger(value: unknown, label: string): number { - if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) { - throw new Error(`${label} must be a non-negative safe integer`); - } - return value; -} - -function requirePositiveInteger(value: unknown, label: string): number { - const integer = requireSafeInteger(value, label); - if (integer === 0) throw new Error(`${label} must be positive`); - return integer; -} - -function requireAssetPath(value: unknown, label: string): string { - const path = requireString(value, label); - const segments = path.replaceAll('\\', '/').split('/'); - if ( - path.startsWith('/') || - path.includes('\\') || - segments.some((segment) => segment.length === 0 || segment === '.' || segment === '..') - ) { - throw new Error(`${label} must be a safe relative asset path`); - } - return path; -} - -function requireInstallPath(value: unknown, label: string): string { - const path = requireAssetPath(value, label); - extensionMountTarget(path, label); - return path; -} - -function describeError(error: unknown): string { - return error instanceof Error ? error.message : String(error); -} diff --git a/src/bindings/wasix-ts/src/icu-descriptor.ts b/src/bindings/wasix-ts/src/icu-descriptor.ts deleted file mode 100644 index 03fde64bf..000000000 --- a/src/bindings/wasix-ts/src/icu-descriptor.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { - requireAssetSource, - requireExactObject, - requireSafeRelativeAssetPath, - requireSha256, - requireSize, - requireVersion, - serializeAssetSource, -} from './descriptor-validation.js'; -import type { SerializedIcuDescriptor, SerializedRuntimeArchive } from './rpc.js'; -import type { WasixIcuDescriptor, WasixRuntimeArchive, WasixRuntimeManifest } from './types.js'; - -const DESCRIPTOR_FIELDS = [ - 'clusterSeedArchive', - 'clusterSeedManifest', - 'compatibility', - 'dataArchive', - 'product', - 'runtime', - 'schema', - 'version', -] as const; -const COMPATIBILITY_FIELDS = [ - 'compatibilityKey', - 'dataForm', - 'dataTreeSha256', - 'dataVersion', - 'physicalFormat', - 'postgresMajor', - 'runtimeProduct', - 'runtimeVersion', -] as const; -const ARCHIVE_FIELDS = ['archive', 'sha256', 'size', 'source'] as const; -const MANIFEST_FIELDS = ['sha256', 'size', 'source'] as const; - -/** Validate an explicitly imported ICU carrier before bytes cross a worker boundary. */ -export function serializeWasixIcuDescriptor(value: unknown): SerializedIcuDescriptor { - validateWasixIcuDescriptor(value, 'WASIX ICU descriptor'); - return { - schema: value.schema, - runtime: value.runtime, - product: value.product, - version: value.version, - compatibility: { ...value.compatibility }, - dataArchive: serializeArchive(value.dataArchive), - clusterSeedArchive: serializeArchive(value.clusterSeedArchive), - clusterSeedManifest: serializeManifest(value.clusterSeedManifest), - }; -} - -function validateWasixIcuDescriptor( - value: unknown, - label: string, -): asserts value is WasixIcuDescriptor { - const descriptor = requireExactObject(value, DESCRIPTOR_FIELDS, label); - if (descriptor.schema !== 'oliphaunt-wasix-icu-v1') - throw new Error(`${label} has unsupported schema`); - if (descriptor.runtime !== 'wasix') throw new Error(`${label} must target runtime 'wasix'`); - if (descriptor.product !== 'oliphaunt-icu') - throw new Error(`${label} product must be 'oliphaunt-icu'`); - requireVersion(descriptor.version, `${label} version`); - const compatibility = requireExactObject( - descriptor.compatibility, - COMPATIBILITY_FIELDS, - `${label} compatibility`, - ); - if ( - compatibility.runtimeProduct !== 'liboliphaunt-wasix' || - compatibility.postgresMajor !== '18' || - compatibility.physicalFormat !== 'wasix-pg18-v1' || - compatibility.compatibilityKey !== 'wasix-pg18-datum32-v1' || - compatibility.dataVersion !== '76.1' || - compatibility.dataForm !== 'files-le' - ) { - throw new Error(`${label} has an incompatible WASIX/ICU identity`); - } - requireVersion(compatibility.runtimeVersion, `${label} compatible runtime version`); - requireSha256(compatibility.dataTreeSha256, `${label} ICU data tree SHA-256`); - validateArchive(descriptor.dataArchive, `${label} ICU data archive`); - validateArchive(descriptor.clusterSeedArchive, `${label} ICU cluster seed archive`); - validateManifest(descriptor.clusterSeedManifest, `${label} ICU cluster seed manifest`); - if (descriptor.dataArchive.archive === descriptor.clusterSeedArchive.archive) { - throw new Error(`${label} ICU data and cluster seed archives must have distinct paths`); - } -} - -function validateArchive(value: unknown, label: string): asserts value is WasixRuntimeArchive { - const archive = requireExactObject(value, ARCHIVE_FIELDS, label); - requireSafeRelativeAssetPath(archive.archive, `${label} path`); - requireSha256(archive.sha256, `${label} SHA-256`); - const size = requireSize(archive.size, `${label} size`); - requireAssetSource(archive.source, `${label} source`, size); -} - -function validateManifest(value: unknown, label: string): asserts value is WasixRuntimeManifest { - const manifest = requireExactObject(value, MANIFEST_FIELDS, label); - requireSha256(manifest.sha256, `${label} SHA-256`); - const size = requireSize(manifest.size, `${label} size`); - requireAssetSource(manifest.source, `${label} source`, size); -} - -function serializeArchive(archive: WasixRuntimeArchive): SerializedRuntimeArchive { - return { - archive: archive.archive, - sha256: archive.sha256, - size: archive.size, - source: serializeAssetSource(archive.source), - }; -} - -function serializeManifest( - manifest: WasixRuntimeManifest, -): SerializedIcuDescriptor['clusterSeedManifest'] { - return { - sha256: manifest.sha256, - size: manifest.size, - source: serializeAssetSource(manifest.source), - }; -} diff --git a/src/bindings/wasix-ts/src/index.bun.ts b/src/bindings/wasix-ts/src/index.bun.ts deleted file mode 100644 index a99646a35..000000000 --- a/src/bindings/wasix-ts/src/index.bun.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Oliphaunt, Oliphaunt as default } from './node-client.js'; -export * from './public.js'; diff --git a/src/bindings/wasix-ts/src/index.deno.ts b/src/bindings/wasix-ts/src/index.deno.ts deleted file mode 100644 index a99646a35..000000000 --- a/src/bindings/wasix-ts/src/index.deno.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Oliphaunt, Oliphaunt as default } from './node-client.js'; -export * from './public.js'; diff --git a/src/bindings/wasix-ts/src/index.node.ts b/src/bindings/wasix-ts/src/index.node.ts deleted file mode 100644 index a99646a35..000000000 --- a/src/bindings/wasix-ts/src/index.node.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Oliphaunt, Oliphaunt as default } from './node-client.js'; -export * from './public.js'; diff --git a/src/bindings/wasix-ts/src/index.ts b/src/bindings/wasix-ts/src/index.ts deleted file mode 100644 index a1bc19102..000000000 --- a/src/bindings/wasix-ts/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Oliphaunt, Oliphaunt as default } from './client.js'; -export * from './public.js'; diff --git a/src/bindings/wasix-ts/src/internal.ts b/src/bindings/wasix-ts/src/internal.ts deleted file mode 100644 index 1327db88d..000000000 --- a/src/bindings/wasix-ts/src/internal.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { OliphauntDatabase } from './types.js'; -import { - runWasixToolProcess as runTool, - type WasixToolProcessOptions, - type WasixToolProcessResult, - type WasixToolWorkerPort, -} from './internal-common.js'; -import type { WasixToolWorkerRequest, WasixToolWorkerResponse } from './tool-worker-common.js'; - -export { getWasixDatabaseIdentity } from './database.js'; - -export type { - WasixToolDescriptor, - WasixToolProcessOptions, - WasixToolProcessResult, -} from './internal-common.js'; - -export function runWasixToolProcess( - database: OliphauntDatabase, - options: WasixToolProcessOptions, -): Promise { - return runTool(database, options, createBrowserToolWorker); -} - -function createBrowserToolWorker(): WasixToolWorkerPort { - if (typeof Worker === 'undefined') { - throw new Error('WASIX tools require Web Workers'); - } - const worker = new Worker(new URL('./tool-worker.js', import.meta.url), { - type: 'module', - name: 'oliphaunt-wasix-tool', - }); - let messageListener: ((response: WasixToolWorkerResponse) => void) | undefined; - let fatalListener: ((error: Error) => void) | undefined; - let fatalDelivered = false; - worker.addEventListener('message', (event: MessageEvent) => { - messageListener?.(event.data); - }); - worker.addEventListener('error', (event) => { - if (fatalDelivered) return; - fatalDelivered = true; - fatalListener?.(new Error(event.message || 'Oliphaunt WASIX tool worker crashed')); - }); - worker.addEventListener('messageerror', () => { - if (fatalDelivered) return; - fatalDelivered = true; - fatalListener?.(new Error('Oliphaunt WASIX tool worker returned an unreadable response')); - }); - return { - postMessage: (request: WasixToolWorkerRequest, transfer: ArrayBuffer[] = []) => - worker.postMessage(request, transfer), - onMessage: (listener) => { - messageListener = listener; - }, - onFatal: (listener) => { - fatalListener = listener; - }, - terminate: () => worker.terminate(), - }; -} diff --git a/src/bindings/wasix-ts/src/protocol.ts b/src/bindings/wasix-ts/src/protocol.ts deleted file mode 100644 index f23f4bdb1..000000000 --- a/src/bindings/wasix-ts/src/protocol.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '@oliphaunt/js-core/protocol'; diff --git a/src/bindings/wasix-ts/src/query.ts b/src/bindings/wasix-ts/src/query.ts deleted file mode 100644 index a297830c0..000000000 --- a/src/bindings/wasix-ts/src/query.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '@oliphaunt/js-core/query'; diff --git a/src/bindings/wasix-ts/src/storage.ts b/src/bindings/wasix-ts/src/storage.ts deleted file mode 100644 index 5634a9476..000000000 --- a/src/bindings/wasix-ts/src/storage.ts +++ /dev/null @@ -1,136 +0,0 @@ -declare const storageDescriptorBrand: unique symbol; -declare const persistentStorageDescriptorBrand: unique symbol; - -/** - * An opaque storage selection created by this package's storage factories. - * The descriptor is deliberately not a bag of user-authored paths or assets. - */ -export type WasixStorage = Readonly<{ - [storageDescriptorBrand]: 'oliphaunt-wasix-storage'; -}>; - -/** Opaque persistent storage accepted by static physical restore. */ -export type PersistentWasixStorage = WasixStorage & - Readonly<{ - [persistentStorageDescriptorBrand]: 'oliphaunt-wasix-persistent-storage'; - }>; - -export type SerializedWasixStorage = - | Readonly<{ - schema: 'oliphaunt-wasix-storage-v1'; - kind: 'memory'; - }> - | Readonly<{ - schema: 'oliphaunt-wasix-storage-v1'; - kind: 'indexed-db'; - name: string; - }> - | Readonly<{ - schema: 'oliphaunt-wasix-storage-v1'; - kind: 'opfs'; - name: string; - }> - | Readonly<{ - schema: 'oliphaunt-wasix-storage-v1'; - kind: 'directory'; - path: string; - }>; - -const descriptorValues = new WeakMap(); - -/** - * Select a fresh in-memory database. This is also the default when `storage` - * is omitted. Reusing the descriptor does not preserve data. - */ -export function memory(): WasixStorage { - return defineStorage({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'memory', - }); -} - -/** @internal Used by the selectively imported IndexedDB adapter. */ -export function defineIndexedDbStorage(name: string): PersistentWasixStorage { - validateIndexedDbDatabaseName(name); - return defineStorage({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'indexed-db', - name, - }) as PersistentWasixStorage; -} - -/** @internal Used by the selectively imported OPFS adapter. */ -export function defineOpfsStorage(name: string): PersistentWasixStorage { - validateOpfsDatabaseName(name); - return defineStorage({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'opfs', - name, - }) as PersistentWasixStorage; -} - -/** @internal Used by the selectively imported Node directory adapter. */ -export function defineDirectoryStorage(path: string): PersistentWasixStorage { - validateHostDirectoryPath(path); - return defineStorage({ - schema: 'oliphaunt-wasix-storage-v1', - kind: 'directory', - path, - }) as PersistentWasixStorage; -} - -/** @internal Validate and project the opaque main-thread value for the worker. */ -export function serializeWasixStorage(storage: WasixStorage | undefined): SerializedWasixStorage { - if (storage === undefined) { - return { schema: 'oliphaunt-wasix-storage-v1', kind: 'memory' }; - } - const value = descriptorValues.get(storage as object); - if (value === undefined) { - throw new TypeError( - 'storage must come from @oliphaunt/wasix-ts or one of its storage adapter subpaths', - ); - } - switch (value.kind) { - case 'memory': - return { ...value }; - case 'indexed-db': - return { ...value, name: value.name }; - case 'opfs': - return { ...value, name: value.name }; - case 'directory': - return { ...value, path: value.path }; - } -} - -export function validateIndexedDbDatabaseName(name: unknown): asserts name is string { - if (typeof name !== 'string' || name.length === 0 || name.length > 200 || name.includes('\0')) { - throw new TypeError('IndexedDB storage name must be 1-200 characters without NUL bytes'); - } -} - -export function validateOpfsDatabaseName(name: unknown): asserts name is string { - if ( - typeof name !== 'string' || - name.length === 0 || - name.length > 100 || - name === '.' || - name === '..' || - !/^[A-Za-z0-9._-]+$/.test(name) - ) { - throw new TypeError( - 'OPFS storage name must be 1-100 ASCII letters, digits, dot, dash, or underscore', - ); - } -} - -export function validateHostDirectoryPath(path: unknown): asserts path is string { - if (typeof path !== 'string' || path.length === 0 || path.includes('\0')) { - throw new TypeError('host directory storage path must be a non-empty string without NUL bytes'); - } -} - -function defineStorage(value: SerializedWasixStorage): WasixStorage { - const descriptor = Object.freeze({}); - descriptorValues.set(descriptor, Object.freeze(value)); - return descriptor as WasixStorage; -} diff --git a/src/bindings/wasix-ts/src/storage/node.ts b/src/bindings/wasix-ts/src/storage/node.ts deleted file mode 100644 index 020d54060..000000000 --- a/src/bindings/wasix-ts/src/storage/node.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { fileURLToPath } from 'node:url'; - -import { defineDirectoryStorage, type PersistentWasixStorage } from '../storage.js'; - -/** - * Persist a managed database below a Node.js host directory. - * - * Rust opens the selected managed root directly, owns its OS advisory lock, - * and performs PostgreSQL-safe durable writes at each native operation - * boundary. Network and cross-host shared filesystems are unsupported. - */ -export function directory(path: string | URL): PersistentWasixStorage { - return defineDirectoryStorage(typeof path === 'string' ? path : fileURLToPath(path)); -} - -export default directory; diff --git a/src/bindings/wasix-ts/src/types.ts b/src/bindings/wasix-ts/src/types.ts deleted file mode 100644 index 53bb2a99f..000000000 --- a/src/bindings/wasix-ts/src/types.ts +++ /dev/null @@ -1,294 +0,0 @@ -import type { - CommandResult, - DescribeResult, - ExecResult, - InferQueryRow, - ParameterOptions, - QueryOptions, - QueryParam, - QueryResult, - RawQueryResult, -} from './query.js'; -import type { PersistentWasixStorage, WasixStorage } from './storage.js'; - -type QueryReadOptions = Omit; - -export type BinaryInput = ArrayBuffer | ArrayBufferView | Uint8Array | ReadonlyArray; -/** A synchronous, serial raw-protocol consumer used as the backpressure acknowledgement. */ -export type ProtocolChunkCallback = (chunk: Uint8Array) => undefined; - -/** A host-neutral asset reference accepted by the portable WASIX carrier contract. */ -export type WasixAssetSource = string | URL | ArrayBuffer | Uint8Array; - -/** One exact archive carried by the portable WASIX runtime package. */ -export type WasixRuntimeArchive = Readonly<{ - /** Canonical path recorded by the generated runtime manifest. */ - archive: string; - sha256: string; - size: number; - source: WasixAssetSource; -}>; - -/** The canonical generated manifest carried alongside the runtime archives. */ -export type WasixRuntimeManifest = Readonly<{ - sha256: string; - size: number; - source: WasixAssetSource; -}>; - -/** - * A package-authored runtime identity. The default value comes from - * `@oliphaunt/liboliphaunt-wasix`; callers normally never handle it directly. - */ -export type WasixRuntimeDescriptor = Readonly<{ - schema: 'oliphaunt-wasix-runtime-v2'; - runtime: 'wasix'; - product: 'liboliphaunt-wasix'; - version: string; - runtimeArchive: WasixRuntimeArchive; - standardSeedArchive: WasixRuntimeArchive; - standardSeedManifest: WasixRuntimeManifest; - manifest: WasixRuntimeManifest; -}>; - -/** Explicit optional ICU closure authored by `@oliphaunt/wasix-icu`. */ -export type WasixIcuDescriptor = Readonly<{ - schema: 'oliphaunt-wasix-icu-v1'; - runtime: 'wasix'; - product: 'oliphaunt-icu'; - version: string; - compatibility: Readonly<{ - runtimeProduct: 'liboliphaunt-wasix'; - runtimeVersion: string; - postgresMajor: '18'; - physicalFormat: 'wasix-pg18-v1'; - compatibilityKey: 'wasix-pg18-datum32-v1'; - dataVersion: '76.1'; - dataForm: 'files-le'; - dataTreeSha256: string; - }>; - dataArchive: WasixRuntimeArchive; - clusterSeedArchive: WasixRuntimeArchive; - clusterSeedManifest: WasixRuntimeManifest; -}>; - -export type WasixExtensionCarrier = Readonly<{ - /** Owning Oliphaunt release product, not the PostgreSQL SQL name. */ - product: string; - /** Oliphaunt product version; upstream provenance stays release/evidence metadata. */ - version: string; - sqlName: string; - /** Exact canonical manifest archive key, for example `extensions/pgtap.tar.zst`. */ - archive: string; - sha256: string; - size: number; - /** Portable archive URL or bytes. The same descriptor can be hosted by Node or a browser. */ - source: WasixAssetSource; - /** Exact install contract owned by this independently versioned carrier. */ - install: WasixExtensionInstall; -}>; - -export type WasixExtensionCompatibility = Readonly<{ - extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1'; - postgresMajor: string; - wasixRuntimeProduct: 'liboliphaunt-wasix'; - wasixRuntimeVersion: string; -}>; - -export type WasixExtensionInstall = Readonly<{ - schema: 'oliphaunt-wasix-extension-install-v1'; - name: string; - nativeModule: string | null; - nativeModules: readonly WasixExtensionNativeModule[]; - dependencies: readonly string[]; - coreExportsRequired: readonly string[]; - loadOrder: readonly string[]; - lifecycle: WasixExtensionLifecycle; - installedFiles: readonly string[]; - unresolvedImports: readonly WasixExtensionImport[]; -}>; - -export type WasixExtensionImport = Readonly<{ - module: string; - name: string; - kind: string; -}>; - -export type WasixExtensionNativeModule = Readonly<{ - name: string; - path: string; - sha256: string; - moduleSha256: string; - size: number; -}>; - -export type WasixExtensionDescriptorInput = Readonly<{ - schema: 'oliphaunt-wasix-extension-v1'; - runtime: 'wasix'; - /** Product and version of the root carrier selected by `sqlName`. */ - product: string; - version: string; - /** Exact WASIX runtime identity against which this descriptor was qualified. */ - compatibility: WasixExtensionCompatibility; - sqlName: string; - /** Root carrier plus any extension carrier dependencies required by this import. */ - carriers: readonly WasixExtensionCarrier[]; -}>; - -/** - * A package-authored, runtime-validated WASIX extension import. Applications - * obtain these from extension packages instead of constructing SQL strings. - * The schema and runtime literals discriminate it structurally, so generated - * carrier packages do not need a dependency on this binding. - */ -export type WasixExtensionDescriptor = WasixExtensionDescriptorInput; - -/** Lifecycle fields owned by an independently versioned extension carrier. */ -export type WasixExtensionLifecycle = { - createExtension: boolean; - createSchema: string | null; - loadSql: readonly string[]; - postCreateSql: readonly string[]; - startupConfig: readonly string[]; - preloadRequired: boolean; - restartRequired: boolean; - sharedMemoryRequired: boolean; -}; - -/** Host-relevant subset of the generated liboliphaunt WASIX asset manifest. */ -export type WasixAssetManifest = { - 'format-version': 2; - 'source-fingerprint': string; - runtime: { - archive: string; - sha256: string; - /** Present when the canonical producer records the outer archive size. */ - size?: number; - 'module-sha256': string; - 'postgres-version': string; - link: { - exports: readonly { - name: string; - kind: string; - }[]; - }; - }; - 'runtime-support': readonly { - name: string; - path: string; - sha256: string; - }[]; - 'cluster-seeds': Readonly< - Record< - 'standard' | 'icu', - { - 'artifact-role': 'cluster-seed-standard' | 'cluster-seed-icu'; - 'catalog-profile': 'standard' | 'icu'; - archive: string; - manifest: string; - sha256: string; - size: number; - 'runtime-module-sha256': string; - 'source-fingerprint': string; - 'postgres-version': string; - 'physical-format': 'wasix-pg18-v1'; - 'compatibility-key': 'wasix-pg18-datum32-v1'; - 'icu-data-tree-sha256'?: string; - } - > - >; - /** The core runtime carrier is intentionally extension-free. */ - extensions: readonly []; -}; - -export type OpenConfig = { - /** Existing PostgreSQL role selected after the fixed superuser bootstrap. */ - username?: string; - database?: string; - /** PostgreSQL `-c name=value` settings applied before the database opens. */ - startupGUCs?: Readonly>; - /** Optional ICU data plus the matching PostgreSQL ICU-catalog cluster seed. */ - icu?: WasixIcuDescriptor; - /** Selectively imported WASIX carriers. SQL strings are intentionally not accepted. */ - extensions?: readonly WasixExtensionDescriptor[]; - /** Fresh memory by default, or an explicitly imported host storage adapter. */ - storage?: WasixStorage; -}; - -export type OliphauntDatabase = { - /** - * True after the terminal close attempt settles, including when teardown - * rejects, or as soon as a package-owned isolated host terminates unexpectedly. - */ - readonly closed: boolean; - execute( - sql: string, - parameters?: ReadonlyArray, - options?: ParameterOptions, - ): Promise; - query( - sql: string, - parameters?: ReadonlyArray, - options?: Options & QueryOptions, - ): Promise>>; - queryRaw( - sql: string, - parameters?: ReadonlyArray, - options?: ParameterOptions, - ): Promise; - exec( - sql: string, - options?: Options & QueryReadOptions, - ): Promise>>; - describe(sql: string, parameterTypeOids?: ReadonlyArray): Promise; - execProtocolRaw(input: BinaryInput): Promise; - execProtocolRawStream(input: BinaryInput, onChunk: ProtocolChunkCallback): Promise; - /** Create a session-preserving PostgreSQL online physical backup. */ - backup(): Promise; - /** - * Own the session for one callback. Use callback return/throw or rollback() - * for lifecycle; manual BEGIN/START/COMMIT/END/ABORT/PREPARE TRANSACTION and - * AND CHAIN are unsupported. SAVEPOINT and ROLLBACK TO are allowed. - */ - transaction(body: (transaction: OliphauntTransaction) => Promise | T): Promise; - /** - * Stop admitting work and perform one terminal teardown attempt. - * Concurrent and later calls return the same promise. A rejection reports - * cleanup failure; it does not make the handle reusable. Calling from an - * active transaction callback rejects before teardown begins; close the - * database after that callback settles. - */ - close(): Promise; - [Symbol.asyncDispose](): Promise; -}; - -/** A database session pinned to one callback-scoped PostgreSQL transaction. */ -export type OliphauntTransaction = { - readonly closed: boolean; - execute( - sql: string, - parameters?: ReadonlyArray, - options?: ParameterOptions, - ): Promise; - query( - sql: string, - parameters?: ReadonlyArray, - options?: Options & QueryOptions, - ): Promise>>; - queryRaw( - sql: string, - parameters?: ReadonlyArray, - options?: ParameterOptions, - ): Promise; - exec( - sql: string, - options?: Options & QueryReadOptions, - ): Promise>>; - describe(sql: string, parameterTypeOids?: ReadonlyArray): Promise; - rollback(): Promise; -}; - -export type OliphauntClient = { - open(config?: OpenConfig): Promise; - restore(storage: PersistentWasixStorage, bytes: BinaryInput): Promise; -}; diff --git a/src/bindings/wasix-ts/src/worker-entry.bun.ts b/src/bindings/wasix-ts/src/worker-entry.bun.ts deleted file mode 100644 index e8cee532b..000000000 --- a/src/bindings/wasix-ts/src/worker-entry.bun.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Oliphaunt, Oliphaunt as default } from './worker-node-client.js'; -export * from './public.js'; diff --git a/src/bindings/wasix-ts/src/worker-entry.deno.ts b/src/bindings/wasix-ts/src/worker-entry.deno.ts deleted file mode 100644 index e8cee532b..000000000 --- a/src/bindings/wasix-ts/src/worker-entry.deno.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Oliphaunt, Oliphaunt as default } from './worker-node-client.js'; -export * from './public.js'; diff --git a/src/bindings/wasix-ts/src/worker-entry.node.ts b/src/bindings/wasix-ts/src/worker-entry.node.ts deleted file mode 100644 index e8cee532b..000000000 --- a/src/bindings/wasix-ts/src/worker-entry.node.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Oliphaunt, Oliphaunt as default } from './worker-node-client.js'; -export * from './public.js'; diff --git a/src/bindings/wasix-ts/src/worker-entry.ts b/src/bindings/wasix-ts/src/worker-entry.ts deleted file mode 100644 index 2b4be042c..000000000 --- a/src/bindings/wasix-ts/src/worker-entry.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { Oliphaunt, Oliphaunt as default } from './worker-client.js'; -export * from './public.js'; diff --git a/src/bindings/wasix-ts/src/worker-node-client.ts b/src/bindings/wasix-ts/src/worker-node-client.ts deleted file mode 100644 index 45d3956b3..000000000 --- a/src/bindings/wasix-ts/src/worker-node-client.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Worker } from 'node:worker_threads'; - -import { serializeOpenConfig } from './client-common.js'; -import { hostRuntimeName } from './host-runtime.js'; -import { requireNodeStorage } from './node-client-common.js'; -import { nodeWorkerExecArgv } from './node-worker-options.js'; -import { nodeWorkerPort } from './node-worker-port.js'; -import type { SerializedOpenOptions } from './rpc.js'; -import type { PersistentWasixStorage } from './storage.js'; -import type { BinaryInput, OliphauntClient, OliphauntDatabase, OpenConfig } from './types.js'; -import { openWasixWithWorker, restoreWasixWithWorker, type WasixWorkerPort } from './worker-rpc.js'; - -/** Open PostgreSQL in a package-owned Node-compatible Worker realm. */ -export async function openWasix(config: OpenConfig = {}): Promise { - // The native Worker owns release-embedded runtime assets. Do not structured- - // clone caller-provided WebAssembly archives that the N-API path will never - // read; retain their exact identity metadata for compatibility validation. - const openOptions = withoutNativeAssetPayloads(serializeOpenConfig(config)); - return openWasixWithWorker(createNodeWorker, openOptions, requireNodeStorage, false); -} - -export const Oliphaunt: OliphauntClient = { - open: openWasix, - restore: restoreNodeWasixWithWorker, -}; - -async function restoreNodeWasixWithWorker( - storage: PersistentWasixStorage, - bytes: BinaryInput, -): Promise { - return restoreWasixWithWorker(createNodeWorker, storage, bytes, requireNodeStorage); -} - -function createNodeWorker(_options: SerializedOpenOptions): WasixWorkerPort { - return nodeWorkerPort( - new Worker(new URL('./node-worker.js', import.meta.url), { - execArgv: nodeWorkerExecArgv(), - name: 'oliphaunt-wasix', - }), - hostRuntimeName(), - ); -} - -function withoutNativeAssetPayloads(options: SerializedOpenOptions): SerializedOpenOptions { - const source = 'oliphaunt:wasix-napi-embedded'; - return { - ...options, - runtime: { - ...options.runtime, - runtimeArchive: { ...options.runtime.runtimeArchive, source }, - standardSeedArchive: { ...options.runtime.standardSeedArchive, source }, - standardSeedManifest: { ...options.runtime.standardSeedManifest, source }, - manifest: { ...options.runtime.manifest, source }, - }, - ...(options.icu === undefined - ? {} - : { - icu: { - ...options.icu, - dataArchive: { ...options.icu.dataArchive, source }, - clusterSeedArchive: { ...options.icu.clusterSeedArchive, source }, - clusterSeedManifest: { ...options.icu.clusterSeedManifest, source }, - }, - }), - extensionCarriers: Object.fromEntries( - Object.entries(options.extensionCarriers).map(([sqlName, carrier]) => [ - sqlName, - { ...carrier, source }, - ]), - ), - }; -} diff --git a/src/bindings/wasix-ts/tools-package/README.md b/src/bindings/wasix-ts/tools-package/README.md deleted file mode 100644 index 4d941cef8..000000000 --- a/src/bindings/wasix-ts/tools-package/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# @oliphaunt/wasix-tools - -Optional standard PostgreSQL `pg_dump` and non-interactive `psql` runners for -an open `@oliphaunt/wasix-ts` database. This package remains the public opt-in -facade on every host. Browsers load separately carried portable tool binaries; -Node.js, Bun, Deno, and Electron call the copies compiled into the matching Node-API -platform carrier. - -`pgDump()` returns PostgreSQL's ordinary plain SQL dump, including normal -`COPY` data. `psql()` accepts a command or script and can restore that output. -Both operations exclusively own the database session until they finish. -They reset PostgreSQL session state before and after running, so raw-protocol -callers must not expect prepared statements or session settings to survive. - -```sh -pnpm add @oliphaunt/wasix-ts @oliphaunt/wasix-tools -``` - -```ts -import Oliphaunt from '@oliphaunt/wasix-ts'; -import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker'; -import { pgDump, psql } from '@oliphaunt/wasix-tools'; - -await using source = await Oliphaunt.open(); -const sql = await pgDump(source, { args: ['--schema-only'] }); -await using target = await WorkerOliphaunt.open(); -await psql(target, { script: sql }); -``` - -`pgDump()` supports databases from the root, `/direct`, and `/worker` entrypoints. -In browsers, `psql()` requires `/worker` because COPY restore is full duplex. -On Node.js, Bun, Deno, and Electron the Rust tool bridge supports `psql()` on -all three entrypoints. -Ordinary PostgreSQL -arguments are passed through, except connection, input/output, encoding, dump -format, compression, and parallel-job arguments owned by the runner. -`pgDump()` always uses plain UTF-8 output and rejects custom formats; it does -not force `--inserts` or rewrite valid dump SQL. `psql()` accepts `command` or -`script`, uses no user psqlrc, and stops on the first SQL error. Interactive -input and `pg_restore` are not part of this package. - -Tool failures throw `PostgresToolError` with `tool`, `exitCode`, `stdout`, and -`stderr` fields. diff --git a/src/bindings/wasix-ts/tools-package/moon.yml b/src/bindings/wasix-ts/tools-package/moon.yml deleted file mode 100644 index 05f51bd12..000000000 --- a/src/bindings/wasix-ts/tools-package/moon.yml +++ /dev/null @@ -1,78 +0,0 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "oliphaunt-wasix-tools-ts" -language: "typescript" -layer: "library" -stack: "frontend" -tags: ["binding", "wasix", "typescript", "tools", "package"] -dependsOn: - - id: "liboliphaunt-wasix" - scope: "production" - - id: "shared-test-fixtures" - scope: "development" - -project: - title: "Oliphaunt WASIX TypeScript tools" - description: "TypeScript pg_dump and psql facade for the WASIX runtime." - owner: "oliphaunt" - -owners: - defaultOwner: "@oliphaunt/sdk-js" - -fileGroups: - code: - - "**/*" - - "!**/*.md" - - "!moon.yml" - -tasks: - compile: - tags: ["quality", "static"] - command: "pnpm --dir src/bindings/wasix-ts/tools-package typecheck" - inputs: - - "@group(pnpm-workspace)" - - "@group(code)" - options: - cache: true - runFromWorkspaceRoot: true - - unit: - tags: ["quality", "unit"] - command: "pnpm --dir src/bindings/wasix-ts/tools-package test" - inputs: - - "@group(pnpm-workspace)" - - "@group(code)" - - project: "shared-test-fixtures" - group: "fixtures" - options: - cache: true - runFromWorkspaceRoot: true - - package: - tags: ["package"] - script: | - set -e - pnpm --dir src/bindings/wasix-ts/tools-package build - node src/bindings/wasix-ts/tools-package/tools/package.mjs target/oliphaunt-wasix-tools-ts/package - inputs: - - "@group(legal-files)" - - "@group(pnpm-workspace)" - - "**/*" - - "/src/bindings/wasix-ts/package.json" - outputs: - - "/target/oliphaunt-wasix-tools-ts/package/**/*" - options: - cache: true - runFromWorkspaceRoot: true - - qualify: - tags: ["release", "package"] - command: "true" - deps: - - "oliphaunt-wasix-tools-ts:compile" - - "oliphaunt-wasix-tools-ts:unit" - - "oliphaunt-wasix-tools-ts:package" - inputs: [] - options: - cache: true - runFromWorkspaceRoot: true diff --git a/src/bindings/wasix-ts/tools-package/package.json b/src/bindings/wasix-ts/tools-package/package.json deleted file mode 100644 index 6e71b3b87..000000000 --- a/src/bindings/wasix-ts/tools-package/package.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "@oliphaunt/wasix-tools", - "version": "0.0.0", - "description": "Optional in-process PostgreSQL pg_dump and psql runners for Oliphaunt WASIX.", - "license": "MIT", - "type": "module", - "sideEffects": false, - "repository": { - "type": "git", - "url": "git+https://github.com/f0rr0/oliphaunt.git", - "directory": "src/bindings/wasix-ts/tools-package" - }, - "bugs": { - "url": "https://github.com/f0rr0/oliphaunt/issues" - }, - "homepage": "https://oliphaunt.dev", - "publishConfig": { - "access": "public", - "provenance": true - }, - "oliphaunt": { - "runtimeProduct": "liboliphaunt-wasix", - "runtimeVersion": "0.2.0" - }, - "exports": { - ".": { - "types": "./lib/index.d.ts", - "default": "./lib/index.js" - }, - "./package.json": "./package.json" - }, - "main": "lib/index.js", - "types": "lib/index.d.ts", - "files": [ - "lib", - "README.md", - "CHANGELOG.md", - "LICENSE", - "THIRD_PARTY_NOTICES.md" - ], - "scripts": { - "build": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\" && tsc -p tsconfig.build.json", - "typecheck": "tsc --noEmit", - "test": "vitest run --pool=forks --fileParallelism=false --dir=src/__tests__", - "clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"" - }, - "dependencies": { - "@oliphaunt/liboliphaunt-wasix-tools": "workspace:*" - }, - "peerDependencies": { - "@oliphaunt/wasix-ts": "workspace:*" - }, - "devDependencies": { - "@oliphaunt/wasix-ts": "workspace:*", - "@types/node": "^24.10.1", - "typescript": "catalog:", - "vitest": "catalog:" - }, - "engines": { - "node": ">=22.13 <25", - "bun": ">=1.3.14", - "deno": ">=2.8.1" - } -} diff --git a/src/bindings/wasix-ts/tools-package/src/__tests__/wasix-ts-runtime.ts b/src/bindings/wasix-ts/tools-package/src/__tests__/wasix-ts-runtime.ts deleted file mode 100644 index 15bc47f25..000000000 --- a/src/bindings/wasix-ts/tools-package/src/__tests__/wasix-ts-runtime.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const toolRuntimeCalls: Array> = []; -export const toolRuntimeResponses: Array< - Readonly<{ exitCode: number; stdout: Uint8Array; stderr: Uint8Array }> -> = []; - -export function getWasixDatabaseIdentity(): Readonly<{ username: string; database: string }> { - return { username: '-application user', database: '-application database' }; -} - -export async function runWasixToolProcess( - _database: unknown, - options: Readonly<{ args: readonly string[] }>, -): Promise> { - toolRuntimeCalls.push(options); - const response = toolRuntimeResponses.shift(); - if (response !== undefined) return response; - throw new Error('unexpected WASIX tool runtime call in validation test'); -} diff --git a/src/bindings/wasix-ts/tools-package/src/index.ts b/src/bindings/wasix-ts/tools-package/src/index.ts deleted file mode 100644 index 5bda6b52c..000000000 --- a/src/bindings/wasix-ts/tools-package/src/index.ts +++ /dev/null @@ -1,346 +0,0 @@ -import tools from '@oliphaunt/liboliphaunt-wasix-tools'; -import type { OliphauntDatabase } from '@oliphaunt/wasix-ts'; -import { getWasixDatabaseIdentity, runWasixToolProcess } from '@oliphaunt/wasix-ts/internal/tools'; - -assertToolsCarrier(); - -const VIRTUAL_TOOL_HOST = '127.0.0.1'; -const VIRTUAL_TOOL_PORT = '65432'; -// PostgreSQL 18 getopt_long optstrings. A value-taking option owns the rest -// of its token, so a managed-looking character inside that value stays data. -const PG_DUMP_SHORT_OPTIONS = 'abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:'; -const PSQL_SHORT_OPTIONS = 'aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01'; -const PG_DUMP_VALUE_OPTIONS = [ - '--extension', - '--schema', - '--exclude-schema', - '--superuser', - '--table', - '--exclude-table', - '--exclude-table-data', - '--extra-float-digits', - '--lock-wait-timeout', - '--role', - '--section', - '--snapshot', - '--rows-per-insert', - '--include-foreign-data', - '--table-and-children', - '--exclude-table-and-children', - '--exclude-table-data-and-children', - '--sync-method', - '--exclude-extension', - '--restrict-key', -] as const; -const PSQL_VALUE_OPTIONS = [ - '--field-separator', - '--pset', - '--record-separator', - '--table-attr', - '--set', - '--variable', -] as const; - -export type PgDumpOptions = Readonly<{ - /** Ordinary PostgreSQL pg_dump arguments. Connection, file input/output, format, compression, encoding, and job flags are managed. */ - args?: readonly string[]; -}>; - -export type PsqlOptions = Readonly<{ - /** Ordinary PostgreSQL psql arguments. Connection, input, and output are managed. */ - args?: readonly string[]; - command?: string; - script?: string; -}>; - -export class PostgresToolError extends Error { - readonly tool: 'pg_dump' | 'psql'; - readonly exitCode: number | null; - readonly stdout: string; - readonly stderr: string; - - constructor( - tool: 'pg_dump' | 'psql', - message: string, - options: { - exitCode?: number | null; - stdout?: string; - stderr?: string; - cause?: unknown; - } = {}, - ) { - super(message, { cause: options.cause }); - this.name = 'PostgresToolError'; - this.tool = tool; - this.exitCode = options.exitCode ?? null; - this.stdout = options.stdout ?? ''; - this.stderr = options.stderr ?? ''; - } -} - -/** Run standard PostgreSQL plain pg_dump against an open WASIX database. */ -export async function pgDump( - database: OliphauntDatabase, - options: PgDumpOptions = {}, -): Promise { - const args = validatedArguments( - 'pg_dump', - options.args, - pgDumpManagedArgument, - PG_DUMP_SHORT_OPTIONS, - PG_DUMP_VALUE_OPTIONS, - ); - const identity = getWasixDatabaseIdentity(database); - return runTool('pg_dump', database, [ - ...args, - '--encoding=UTF8', - '--no-password', - `--username=${identity.username}`, - `--host=${VIRTUAL_TOOL_HOST}`, - `--port=${VIRTUAL_TOOL_PORT}`, - `--dbname=${identity.database}`, - ]); -} - -/** - * Run standard non-interactive psql. Browsers require a `/worker` database; - * Node.js, Bun, Deno, and Electron support root, `/direct`, and `/worker` databases. - */ -export async function psql( - database: OliphauntDatabase, - options: PsqlOptions = {}, -): Promise { - const args = validatedArguments( - 'psql', - options.args, - psqlManagedArgument, - PSQL_SHORT_OPTIONS, - PSQL_VALUE_OPTIONS, - ); - if (options.command !== undefined && options.script !== undefined) { - throw new TypeError('psql accepts command or script, not both'); - } - const command = validatedInput(options.command, 'psql command'); - const script = validatedInput(options.script, 'psql script'); - if (command === undefined && script === undefined && args.length === 0) { - throw new TypeError('psql requires non-interactive input through command, script, or args'); - } - const inputArgs = - command !== undefined ? ['--command', command] : script !== undefined ? ['--file=-'] : []; - const identity = getWasixDatabaseIdentity(database); - return runTool( - 'psql', - database, - [ - ...args, - '--no-psqlrc', - '--no-password', - '--set=ON_ERROR_STOP=1', - `--username=${identity.username}`, - `--host=${VIRTUAL_TOOL_HOST}`, - `--port=${VIRTUAL_TOOL_PORT}`, - `--dbname=${identity.database}`, - ...inputArgs, - ], - script === undefined ? undefined : new TextEncoder().encode(script), - ); -} - -async function runTool( - name: 'pg_dump' | 'psql', - database: OliphauntDatabase, - args: string[], - stdin?: Uint8Array, -): Promise { - const descriptor = name === 'pg_dump' ? tools.pgDump : tools.psql; - let result: Awaited>; - try { - result = await runWasixToolProcess(database, { - runtimeVersion: tools.runtimeVersion, - tool: descriptor, - args, - stdin, - }); - } catch (cause) { - const detail = cause instanceof Error ? cause.message : String(cause); - throw new PostgresToolError(name, `could not run ${name}: ${detail}`, { cause }); - } - if (result.exitCode !== 0) { - // Diagnostics are best-effort text just like native process output. Keep - // the structured failure even if either stream contains invalid UTF-8. - const stdout = decodeDiagnostics(result.stdout); - const stderr = decodeDiagnostics(result.stderr); - throw new PostgresToolError( - name, - `${name} exited with status ${result.exitCode}${stderr.trim() === '' ? '' : `: ${stderr.trim()}`}`, - { exitCode: result.exitCode, stdout, stderr }, - ); - } - try { - return decode(result.stdout, `${name} output`); - } catch (cause) { - throw new PostgresToolError(name, `${name} output is not valid UTF-8`, { - exitCode: result.exitCode, - stdout: decodeDiagnostics(result.stdout), - stderr: decodeDiagnostics(result.stderr), - cause, - }); - } -} - -function validatedInput(value: string | undefined, label: string): string | undefined { - if (value === undefined) return undefined; - if (typeof value !== 'string') throw new TypeError(`${label} must be a string`); - if (value.includes('\0')) throw new TypeError(`${label} must not contain NUL bytes`); - return value; -} - -function validatedArguments( - tool: 'pg_dump' | 'psql', - value: readonly string[] | undefined, - managed: (argument: string) => string | undefined, - shortOptions: string, - valueOptions: readonly string[], -): string[] { - if (value === undefined) return []; - if (!Array.isArray(value)) throw new TypeError(`${tool} args must be an array of strings`); - let expectsValue = false; - const validated = value.map((argument) => { - if (typeof argument !== 'string') throw new TypeError(`${tool} argument must be a string`); - if (argument.includes('\0')) throw new TypeError(`${tool} argument must not contain NUL bytes`); - if (expectsValue) { - expectsValue = false; - return argument; - } - const label = managed(argument); - if (label !== undefined) { - throw new TypeError( - `${tool} argument ${JSON.stringify(argument)} conflicts with Oliphaunt's managed ${label}`, - ); - } - if (argument === '-' || !argument.startsWith('-')) { - throw new TypeError( - `${tool} argument ${JSON.stringify(argument)} conflicts with Oliphaunt's managed database or username`, - ); - } - expectsValue = optionConsumesNext(argument, shortOptions, valueOptions); - return argument; - }); - if (expectsValue) { - throw new TypeError(`${tool} argument ${JSON.stringify(validated.at(-1))} requires a value`); - } - return validated; -} - -function pgDumpManagedArgument(argument: string): string | undefined { - if (argument === '--') return 'option terminator'; - return managedArgument( - argument, - [ - ['--password', '-W', 'password prompting'], - ['--filter', '', 'input file'], - ['--file', '-f', 'output file'], - ['--format', '-F', 'output format'], - ['--compress', '-Z', 'output compression'], - ['--encoding', '-E', 'output encoding'], - ['--host', '-h', 'host'], - ['--port', '-p', 'port'], - ['--username', '-U', 'username'], - ['--dbname', '-d', 'database'], - ['--jobs', '-j', 'job count'], - ], - PG_DUMP_SHORT_OPTIONS, - ); -} - -function optionConsumesNext( - argument: string, - shortOptions: string, - valueOptions: readonly string[], -): boolean { - if (argument.startsWith('--')) { - if (argument.includes('=')) return false; - return valueOptions.some((option) => option.startsWith(argument)); - } - for (let index = 1; index < argument.length; index += 1) { - const option = argument[index]; - if (option === undefined) return false; - const position = shortOptions.indexOf(option); - if (position < 0) return false; - if (shortOptions[position + 1] === ':') return index === argument.length - 1; - } - return false; -} - -function psqlManagedArgument(argument: string): string | undefined { - if (argument === '--') return 'option terminator'; - return managedArgument( - argument, - [ - ['--password', '-W', 'password prompting'], - ['--single-step', '-s', 'interactive prompting'], - ['--host', '-h', 'host'], - ['--port', '-p', 'port'], - ['--username', '-U', 'username'], - ['--dbname', '-d', 'database'], - ['--output', '-o', 'stdout capture'], - ['--log-file', '-L', 'stderr capture'], - ['--command', '-c', 'input'], - ['--file', '-f', 'input'], - ], - PSQL_SHORT_OPTIONS, - ); -} - -function managedArgument( - argument: string, - flags: readonly (readonly [long: string, short: string, label: string])[], - shortOptions: string, -): string | undefined { - const longName = argument.split('=', 1)[0]; - if (longName !== undefined && longName.length > 2 && longName.startsWith('--')) { - for (const [long, , label] of flags) { - // Native getopt_long accepts unique prefixes while PostgreSQL's bundled - // fallback requires exact names. Reject either spelling consistently so - // a managed option cannot become host-dependent. - if (long.startsWith(longName)) return label; - } - } - if (argument.length < 2 || argument[0] !== '-' || argument[1] === '-') { - return undefined; - } - for (let index = 1; index < argument.length; index += 1) { - const option = argument[index]; - if (option === undefined) return undefined; - const position = shortOptions.indexOf(option); - if (position < 0) return undefined; - const managed = flags.find(([, short]) => short === `-${option}`); - if (managed !== undefined) return managed[2]; - if (shortOptions[position + 1] === ':') return undefined; - } - return undefined; -} - -function decode(bytes: Uint8Array, label: string): string { - try { - return new TextDecoder('utf-8', { fatal: true }).decode(bytes); - } catch (cause) { - throw new Error(`${label} is not valid UTF-8`, { cause }); - } -} - -function decodeDiagnostics(bytes: Uint8Array): string { - return new TextDecoder().decode(bytes); -} - -function assertToolsCarrier(): void { - if ( - tools.schema !== 'oliphaunt-wasix-tools-v1' || - tools.product !== 'oliphaunt-wasix-tools' || - tools.runtimeProduct !== 'liboliphaunt-wasix' || - typeof tools.runtimeVersion !== 'string' || - tools.runtimeVersion.length === 0 - ) { - throw new Error('@oliphaunt/liboliphaunt-wasix-tools has an invalid descriptor'); - } -} diff --git a/src/bindings/wasix-ts/tools-package/src/runtime-carrier-shim.d.ts b/src/bindings/wasix-ts/tools-package/src/runtime-carrier-shim.d.ts deleted file mode 100644 index e972aa265..000000000 --- a/src/bindings/wasix-ts/tools-package/src/runtime-carrier-shim.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -declare module '@oliphaunt/liboliphaunt-wasix-tools' { - export type WasixToolModule = Readonly<{ - name: 'pg_dump' | 'psql'; - sha256: string; - size: number; - source: string; - }>; - - export type WasixToolsDescriptor = Readonly<{ - schema: 'oliphaunt-wasix-tools-v1'; - product: 'oliphaunt-wasix-tools'; - version: string; - runtimeProduct: 'liboliphaunt-wasix'; - runtimeVersion: string; - pgDump: WasixToolModule; - psql: WasixToolModule; - }>; - - const descriptor: WasixToolsDescriptor; - export default descriptor; -} diff --git a/src/bindings/wasix-ts/tools-package/src/wasix-ts-internal-shim.d.ts b/src/bindings/wasix-ts/tools-package/src/wasix-ts-internal-shim.d.ts deleted file mode 100644 index 855b58756..000000000 --- a/src/bindings/wasix-ts/tools-package/src/wasix-ts-internal-shim.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { OliphauntDatabase } from '@oliphaunt/wasix-ts'; - -export type WasixToolProcessResult = Readonly<{ - exitCode: number; - stdout: Uint8Array; - stderr: Uint8Array; -}>; - -export function getWasixDatabaseIdentity(database: OliphauntDatabase): Readonly<{ - username: string; - database: string; -}>; - -export function runWasixToolProcess( - database: OliphauntDatabase, - options: Readonly<{ - runtimeVersion: string; - tool: Readonly<{ - name: 'pg_dump' | 'psql'; - sha256: string; - size: number; - source: string | Uint8Array; - }>; - args: readonly string[]; - stdin?: Uint8Array; - }>, -): Promise; diff --git a/src/bindings/wasix-ts/tools-package/src/wasix-ts-public-shim.d.ts b/src/bindings/wasix-ts/tools-package/src/wasix-ts-public-shim.d.ts deleted file mode 100644 index 2f7bf6e85..000000000 --- a/src/bindings/wasix-ts/tools-package/src/wasix-ts-public-shim.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -/** Typecheck-only package-boundary shim. Published declarations import the real SDK type. */ -export interface OliphauntDatabase { - readonly transaction: unknown; - close(): Promise; -} diff --git a/src/bindings/wasix-ts/tools-package/tools/package.mjs b/src/bindings/wasix-ts/tools-package/tools/package.mjs deleted file mode 100755 index 21a029dd0..000000000 --- a/src/bindings/wasix-ts/tools-package/tools/package.mjs +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env node -import { spawnSync } from 'node:child_process'; -import { - copyFileSync, - cpSync, - existsSync, - mkdirSync, - readFileSync, - rmSync, - writeFileSync, -} from 'node:fs'; -import path from 'node:path'; - -export const ROOT = path.resolve(import.meta.dirname, '../../../../..'); -const SOURCE = path.join(ROOT, 'src/bindings/wasix-ts/tools-package'); -const CARRIER = '@oliphaunt/liboliphaunt-wasix-tools'; -const BINDING = '@oliphaunt/wasix-ts'; - -export function prepareWasixToolsTypescriptPackage(packageDir, bindingVersion) { - if (!/^\d+\.\d+\.\d+$/u.test(bindingVersion)) throw new Error('binding version must be exact'); - const manifestFile = path.join(packageDir, 'package.json'); - const manifest = JSON.parse(readFileSync(manifestFile, 'utf8')); - const runtimeVersion = manifest.oliphaunt?.runtimeVersion; - if (!/^\d+\.\d+\.\d+$/u.test(runtimeVersion)) throw new Error('runtime version must be exact'); - manifest.version = bindingVersion; - manifest.dependencies = { [CARRIER]: runtimeVersion }; - manifest.peerDependencies = { [BINDING]: bindingVersion }; - delete manifest.scripts; - delete manifest.devDependencies; - writeFileSync(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`); - copyFileSync(path.join(ROOT, 'LICENSE'), path.join(packageDir, 'LICENSE')); - copyFileSync( - path.join(ROOT, 'THIRD_PARTY_NOTICES.md'), - path.join(packageDir, 'THIRD_PARTY_NOTICES.md'), - ); - return manifest; -} - -export function stageWasixToolsTypescriptPackage(outputDir, bindingVersion) { - const destination = path.resolve(ROOT, outputDir); - const relative = path.relative(ROOT, destination); - if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) { - throw new Error(`WASIX tools package stage must stay inside the repository: ${outputDir}`); - } - rmSync(destination, { recursive: true, force: true }); - mkdirSync(destination, { recursive: true }); - const manifest = JSON.parse(readFileSync(path.join(SOURCE, 'package.json'), 'utf8')); - copyFileSync(path.join(SOURCE, 'package.json'), path.join(destination, 'package.json')); - for (const name of manifest.files ?? []) { - const source = path.join(SOURCE, name); - if (existsSync(source)) cpSync(source, path.join(destination, name), { recursive: true }); - } - copyFileSync( - path.join(ROOT, 'src/bindings/wasix-ts/CHANGELOG.md'), - path.join(destination, 'CHANGELOG.md'), - ); - return prepareWasixToolsTypescriptPackage(destination, bindingVersion); -} - -if (import.meta.main) { - const output = process.argv[2] ?? 'target/oliphaunt-wasix-tools-ts/package'; - const binding = JSON.parse( - readFileSync(path.join(ROOT, 'src/bindings/wasix-ts/package.json'), 'utf8'), - ); - stageWasixToolsTypescriptPackage(output, binding.version); - const packages = path.resolve(ROOT, output, 'packages'); - mkdirSync(packages); - const result = spawnSync('pnpm', ['--silent', 'pack', '--pack-destination', packages], { - cwd: path.resolve(ROOT, output), - stdio: ['ignore', 'ignore', 'inherit'], - }); - if (result.error) throw result.error; - if (result.status !== 0) process.exit(result.status ?? 1); -} diff --git a/src/bindings/wasix-ts/tools-package/tsconfig.json b/src/bindings/wasix-ts/tools-package/tsconfig.json deleted file mode 100644 index ca81db4c1..000000000 --- a/src/bindings/wasix-ts/tools-package/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "declaration": true, - "declarationMap": false, - "lib": ["ES2023", "DOM", "WebWorker"], - "module": "NodeNext", - "moduleResolution": "NodeNext", - "noEmit": true, - "noUncheckedIndexedAccess": true, - "outDir": "lib", - "paths": { - "@oliphaunt/liboliphaunt-wasix-tools": ["./src/runtime-carrier-shim.d.ts"], - "@oliphaunt/wasix-ts": ["./src/wasix-ts-public-shim.d.ts"], - "@oliphaunt/wasix-ts/internal/tools": ["./src/wasix-ts-internal-shim.d.ts"] - }, - "rootDir": "src", - "skipLibCheck": true, - "strict": true, - "target": "ES2022", - "types": ["node", "vitest/globals"] - }, - "include": ["src/**/*"], - "exclude": ["lib", "node_modules"] -} diff --git a/src/bindings/wasix-ts/tools-package/vitest.config.ts b/src/bindings/wasix-ts/tools-package/vitest.config.ts deleted file mode 100644 index 1f8701a49..000000000 --- a/src/bindings/wasix-ts/tools-package/vitest.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { fileURLToPath } from 'node:url'; -import { defineConfig } from 'vitest/config'; - -export default defineConfig({ - resolve: { - alias: { - '@oliphaunt/wasix-ts/internal/tools': fileURLToPath( - new URL('./src/__tests__/wasix-ts-runtime.ts', import.meta.url), - ), - }, - }, -}); diff --git a/src/bindings/wasix-ts/tools/package.mjs b/src/bindings/wasix-ts/tools/package.mjs deleted file mode 100755 index 97cc7cb11..000000000 --- a/src/bindings/wasix-ts/tools/package.mjs +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env node -import { spawnSync } from 'node:child_process'; -import { - copyFileSync, - cpSync, - existsSync, - mkdirSync, - readFileSync, - rmSync, - writeFileSync, -} from 'node:fs'; -import path from 'node:path'; - -import { - JS_CORE_PACKAGE, - stageJsCoreBundle, -} from '../../../shared/js-core/tools/stage-package.mjs'; - -export const ROOT = path.resolve(import.meta.dirname, '../../../..'); -const SOURCE = path.join(ROOT, 'src/bindings/wasix-ts'); -const RUNTIME = '@oliphaunt/liboliphaunt-wasix'; -const NATIVE = [ - '@oliphaunt/wasix-napi-darwin-arm64', - '@oliphaunt/wasix-napi-linux-arm64-gnu', - '@oliphaunt/wasix-napi-linux-x64-gnu', - '@oliphaunt/wasix-napi-win32-x64-msvc', -]; - -export function prepareWasixTypescriptPackage(packageDir) { - const manifestFile = path.join(packageDir, 'package.json'); - const manifest = JSON.parse(readFileSync(manifestFile, 'utf8')); - const runtimeVersion = manifest.oliphaunt?.runtimeVersion; - const nativeVersion = manifest.oliphaunt?.wasixNapiVersion; - if (![runtimeVersion, nativeVersion].every((version) => /^\d+\.\d+\.\d+$/u.test(version))) { - throw new Error('WASIX TypeScript package requires exact runtime and Node-API versions'); - } - const { manifest: coreManifest } = stageJsCoreBundle( - packageDir, - path.join(ROOT, 'src/shared/js-core'), - ); - manifest.dependencies = Object.fromEntries( - Object.entries({ - ...(manifest.dependencies ?? {}), - [JS_CORE_PACKAGE]: coreManifest.version, - [RUNTIME]: runtimeVersion, - }).sort(), - ); - manifest.optionalDependencies = Object.fromEntries(NATIVE.map((name) => [name, nativeVersion])); - delete manifest.devDependencies; - delete manifest.scripts; - writeFileSync(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`); - copyFileSync(path.join(ROOT, 'LICENSE'), path.join(packageDir, 'LICENSE')); - copyFileSync( - path.join(ROOT, 'THIRD_PARTY_NOTICES.md'), - path.join(packageDir, 'THIRD_PARTY_NOTICES.md'), - ); - return manifest; -} - -export function stageWasixTypescriptPackage(outputDir) { - const destination = path.resolve(ROOT, outputDir); - const relative = path.relative(ROOT, destination); - if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) { - throw new Error(`WASIX TypeScript package stage must stay inside the repository: ${outputDir}`); - } - rmSync(destination, { recursive: true, force: true }); - mkdirSync(destination, { recursive: true }); - const manifest = JSON.parse(readFileSync(path.join(SOURCE, 'package.json'), 'utf8')); - copyFileSync(path.join(SOURCE, 'package.json'), path.join(destination, 'package.json')); - for (const name of manifest.files ?? []) { - const source = path.join(SOURCE, name); - if (existsSync(source)) cpSync(source, path.join(destination, name), { recursive: true }); - } - return prepareWasixTypescriptPackage(destination); -} - -if (import.meta.main) { - const output = process.argv[2] ?? 'target/oliphaunt-wasix-ts/package'; - stageWasixTypescriptPackage(output); - const packages = path.resolve(ROOT, output, 'packages'); - mkdirSync(packages); - const result = spawnSync('pnpm', ['--silent', 'pack', '--pack-destination', packages], { - cwd: path.resolve(ROOT, output), - env: { ...process.env, PNPM_CONFIG_NODE_LINKER: 'hoisted' }, - stdio: ['ignore', 'inherit', 'inherit'], - }); - if (result.error) throw result.error; - if (result.status !== 0) process.exit(result.status ?? 1); -} diff --git a/src/bindings/wasix-ts/tools/stage-host.mjs b/src/bindings/wasix-ts/tools/stage-host.mjs deleted file mode 100644 index 3844872d5..000000000 --- a/src/bindings/wasix-ts/tools/stage-host.mjs +++ /dev/null @@ -1,77 +0,0 @@ -import { copyFile, mkdir, rm } from 'node:fs/promises'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import ts from 'typescript'; - -const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); -const repositoryRoot = resolve(packageRoot, '../../..'); -const source = resolve(repositoryRoot, 'target/oliphaunt-wasix-ts/host/wasmer-sdk'); -const destination = resolve(packageRoot, 'lib/host'); - -assertHostDeclarationCompatibility(); - -await rm(destination, { force: true, recursive: true }); -await mkdir(destination, { recursive: true }); - -for (const [sourcePath, name] of [ - [resolve(source, 'dist/index.mjs'), 'index.mjs'], - [resolve(source, 'dist/worker.mjs'), 'worker.mjs'], - [resolve(source, 'dist/wasmer_js_bg.wasm'), 'wasmer_js_bg.wasm'], - [resolve(packageRoot, 'src/host/index.d.mts'), 'index.d.mts'], - [resolve(source, 'LICENSE'), 'LICENSE'], - [resolve(source, 'provenance.json'), 'provenance.json'], -]) { - await copyFile(sourcePath, resolve(destination, name)); -} - -console.log(`wasix-ts host stage: wrote package-relative host to ${destination}`); - -function assertHostDeclarationCompatibility() { - const virtualFile = resolve(packageRoot, '.host-abi-check.mts'); - const sourceText = [ - "import * as generated from '../../../target/oliphaunt-wasix-ts/host/wasmer-sdk/dist/index.mjs';", - "import * as curated from './src/host/index.mjs';", - 'const compatible: typeof curated = generated;', - 'void compatible;', - '// @ts-expect-error Instance handles are created by runWasix.', - 'new curated.Instance();', - '// @ts-expect-error Direct handles are created by instantiateOliphauntDirect.', - 'new curated.OliphauntDirectInstance();', - ].join('\n'); - const compilerOptions = { - noEmit: true, - strict: true, - skipLibCheck: true, - target: ts.ScriptTarget.ES2022, - module: ts.ModuleKind.NodeNext, - moduleResolution: ts.ModuleResolutionKind.NodeNext, - lib: ['lib.es2023.d.ts', 'lib.dom.d.ts', 'lib.dom.iterable.d.ts', 'lib.webworker.d.ts'], - types: [], - }; - const defaultHost = ts.createCompilerHost(compilerOptions); - const isVirtual = (path) => resolve(path) === virtualFile; - const compilerHost = { - ...defaultHost, - fileExists: (path) => isVirtual(path) || defaultHost.fileExists(path), - readFile: (path) => (isVirtual(path) ? sourceText : defaultHost.readFile(path)), - getSourceFile: (path, languageVersion, onError, shouldCreateNewSourceFile) => - isVirtual(path) - ? ts.createSourceFile(path, sourceText, languageVersion, true, ts.ScriptKind.TS) - : defaultHost.getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile), - }; - const program = ts.createProgram([virtualFile], compilerOptions, compilerHost); - const diagnostics = ts.getPreEmitDiagnostics(program); - if (diagnostics.length > 0) { - throw new Error( - `curated WASIX host declaration is incompatible with generated host ABI:\n${ts.formatDiagnosticsWithColorAndContext( - diagnostics, - { - getCanonicalFileName: (path) => path, - getCurrentDirectory: () => packageRoot, - getNewLine: () => '\n', - }, - )}`, - ); - } -} diff --git a/src/bindings/wasix-ts/tsconfig.json b/src/bindings/wasix-ts/tsconfig.json deleted file mode 100644 index a840cb7c3..000000000 --- a/src/bindings/wasix-ts/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compilerOptions": { - "declaration": true, - "declarationMap": false, - "lib": ["ES2023", "ESNext.Disposable", "DOM", "DOM.Iterable", "WebWorker"], - "module": "NodeNext", - "moduleResolution": "NodeNext", - "noEmit": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noUncheckedIndexedAccess": true, - "outDir": "lib", - "paths": { - "@oliphaunt/liboliphaunt-wasix": ["./src/runtime-carrier-shim.d.ts"] - }, - "rootDir": "src", - "skipLibCheck": true, - "strict": true, - "target": "ES2022", - "types": ["node", "vitest/globals"] - }, - "include": ["src/**/*"], - "exclude": ["lib", "node_modules"] -} diff --git a/src/bindings/wasix-ts/typedoc.json b/src/bindings/wasix-ts/typedoc.json deleted file mode 100644 index bad8a4b78..000000000 --- a/src/bindings/wasix-ts/typedoc.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["src/index.ts", "src/worker-entry.ts"], - "exclude": ["src/__tests__/**"], - "excludeInternal": true, - "excludePrivate": true, - "excludeProtected": true, - "gitRevision": "main", - "json": "../../../target/docs/generated/api/wasix-typescript/typedoc.json", - "name": "Oliphaunt WASIX TypeScript SDK", - "out": "../../../target/docs/generated/api/wasix-typescript/html", - "plugin": [], - "readme": "README.md", - "tsconfig": "tsconfig.build.json" -} diff --git a/src/bindings/wasix-ts/vitest.config.ts b/src/bindings/wasix-ts/vitest.config.ts deleted file mode 100644 index a46fbc5fd..000000000 --- a/src/bindings/wasix-ts/vitest.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { fileURLToPath } from "node:url"; -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - resolve: { - alias: { - "@oliphaunt/liboliphaunt-wasix": fileURLToPath( - new URL("./src/__tests__/runtime-carrier.ts", import.meta.url), - ), - }, - }, -}); diff --git a/src/broker/CHANGELOG.md b/src/broker/CHANGELOG.md new file mode 100644 index 000000000..04814e77f --- /dev/null +++ b/src/broker/CHANGELOG.md @@ -0,0 +1,35 @@ +# Changelog + +## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-broker-v0.1.1...oliphaunt-broker-v0.2.0) (2026-09-05) + + +### ⚠ BREAKING CHANGES + +* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) +* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) + +### Features + +* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e)) +* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790)) + + +### Code Refactoring + +* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe)) +* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121)) +* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc)) + +## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-broker-v0.1.0...oliphaunt-broker-v0.1.1) (2026-08-08) + + +### Bug Fixes + +* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22)) + +## 0.1.0 (2026-07-28) + + +### Features + +* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114)) diff --git a/src/broker/Cargo.toml b/src/broker/Cargo.toml new file mode 100644 index 000000000..46e3c86e1 --- /dev/null +++ b/src/broker/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "oliphaunt-broker" +version = "0.2.0" +edition = "2024" +rust-version = "1.93" +description = "Oliphaunt broker helper process for process-isolated embedded PostgreSQL." +readme = "README.md" +repository.workspace = true +homepage.workspace = true +license = "MIT" +include = ["src/**", "Cargo.toml", "README.md", "LICENSE", "THIRD_PARTY_NOTICES.md"] + +[[bin]] +name = "oliphaunt-broker" +path = "src/main.rs" + +[dependencies] +liboliphaunt-native-bindings = { path = "../sdks/rust/liboliphaunt-native", version = "0.1.0" } +oliphaunt-query = { path = "../sdks/rust-query", version = "0.1.0" } +getrandom = "0.3" diff --git a/src/broker/LICENSE b/src/broker/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/src/broker/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/src/broker/README.md b/src/broker/README.md new file mode 100644 index 000000000..473951a1b --- /dev/null +++ b/src/broker/README.md @@ -0,0 +1,82 @@ +# oliphaunt-broker + +`oliphaunt-broker` is the helper process used by broker mode. It owns one +native database root per process, serves PostgreSQL protocol 3.0, and +is packaged as platform-specific release assets for SDKs that need process +isolation. + +Seeds and ICU data are optional, separate resources. New roots use `initdb` +unless `--seed-directory` and `--seed-manifest` select an unpacked native seed. +`--icu-data-directory` and `--icu-data-manifest` select ICU data. Each pair is +validated together by the shared Rust native bindings before initialization. +Existing roots do not read seed contents again. The broker bundles neither +resource; SDKs supply these arguments when explicitly selected. + +The same package exports the transport library consumed by the Rust SDK. +Its executable uses `liboliphaunt-native-bindings` directly for native execution; +it does not depend on the public Rust SDK. + +The SQL endpoint accepts one authenticated connection at a time. Ordinary +PostgreSQL drivers can use its user/database and the process password supplied +through `OLIPHAUNT_BROKER_AUTH_TOKEN`; query results, incremental Flush/Sync, +COPY and cancellation use PostgreSQL's protocol. This remains one embedded +backend, not a concurrent PostgreSQL server. + +SDKs also hold a separate authenticated management connection for physical +backup and process shutdown. Its EOF retires the helper when the owning +application dies. SQL Terminate resets the native session and permits a new +SQL connection; it does not shut down the management owner. Backend cancellation +keys change on each connection. If a disconnected client abandons an incomplete +protocol batch that cannot drain within three seconds, the helper exits and the +application must explicitly reopen its database. No request is replayed and no +missing Sync is manufactured. + +## Release licensing + +The source-only `oliphaunt-broker` crate is Oliphaunt code under MIT. The four +compiled target carriers also contain the exact normal +Rust dependency graph selected for their OS target. Those binary carriers +therefore declare the complete payload expression and carry a target-specific +`THIRD_PARTY_LICENSES/rust/DEPENDENCIES.json` plus its byte-pinned license +texts. + +`dependency-licenses.json` binds every registry dependency to its Cargo.lock +name, version, checksum, declared license, selected redistribution branch, +target set, and complete LICENSE/UNLICENSE/COPYING/NOTICE/COPYRIGHT plus +author, credit, patent, and third-party attribution inventory. +`src/broker/tools/broker-dependency-license-contract.mts check-contract` verifies +the self-contained contract and committed canonical blobs without consulting +Cargo or a registry cache. The connected production audit runs +`bash src/broker/tools/audit-dependency-licenses.sh`: Cargo fetches any +missing locked dependencies, then supplies all four target graphs offline. The +audit checks every legal file against its committed bytes and SHA-256, including +files already in the Cargo cache. A dependency update is incomplete until that audit passes and +all four packed target carriers reopen the exact updated closure. + +## Maintainer commands + +Run these commands from this directory with the repository-pinned Rust toolchain, Moon and Bun available. Cargo resolves versioned workspace dependencies itself; no runtime build is needed for source tests. Bash is required for package staging (Git Bash on Windows). The initial locked Cargo fetch needs network access. + +| Command | Result | +| --- | --- | +| `moon run oliphaunt-broker:format` | Rewrite Rust formatting. | +| `moon run oliphaunt-broker:format-check` | Check formatting without changing files. | +| `moon run oliphaunt-broker:lint` | Clippy diagnostics for all targets; no database execution. | +| `moon run oliphaunt-broker:build` | Compile this project and its Cargo dependencies. | +| `moon run oliphaunt-broker:test` | Run source tests; Cargo compiles the required test targets. | +| `moon run oliphaunt-broker:test-integration` | Build the native runtime and exercise the real broker's SQL and management endpoints. | +| `moon run oliphaunt-broker:package` | Stage distributable source crates under target/sdk-artifacts/oliphaunt-broker; repeated runs replace this owner’s candidates. | + +With `LIBOLIPHAUNT_PATH`, `OLIPHAUNT_INSTALL_DIR` and (when needed) +`OLIPHAUNT_EMBEDDED_MODULE_DIR` pointing to a prepared runtime, run +`cargo test --locked --test postgres_client -- --ignored`. These tests launch the +actual broker and exercise large parameters after Flush, simultaneous large +requests and responses, COPY, cancellation, callback recovery, connection reset, +backup/shutdown, abrupt disconnect, and parent death. They fail when required +runtime inputs are missing; source-only tests report them as ignored. + +Native Cargo entry points remain available: `cargo build -p oliphaunt-broker --locked`, `cargo test -p oliphaunt-broker --locked`, `cargo clippy -p oliphaunt-broker --all-targets --locked -- -D warnings`, and `cargo fmt -p oliphaunt-broker --check`. Moon supplies the additional source-test feature matrix and artifact staging where defined. `package` assembles bytes; it does not run the project test suite. + +The native SDK’s `moon run oliphaunt-rust:test-consumer` installs the real packed query, bindings and broker crates together with the SDK. This tests their public dependency closure without duplicate per-crate consumer harnesses. + +`build-release-assets` and `finalize-release-assets` remain explicit target-specific binary-carrier production tasks. They require the matching target toolchain and licensing inputs; source-crate packaging does not build those binaries. diff --git a/src/broker/THIRD_PARTY_NOTICES.md b/src/broker/THIRD_PARTY_NOTICES.md new file mode 120000 index 000000000..fd0a6bc2c --- /dev/null +++ b/src/broker/THIRD_PARTY_NOTICES.md @@ -0,0 +1 @@ +../../THIRD_PARTY_NOTICES.md \ No newline at end of file diff --git a/src/broker/crates/linux-arm64-gnu/Cargo.toml b/src/broker/crates/linux-arm64-gnu/Cargo.toml new file mode 100644 index 000000000..e74805af8 --- /dev/null +++ b/src/broker/crates/linux-arm64-gnu/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "oliphaunt-broker-linux-arm64-gnu" +version = "0.2.0" +edition = "2024" +rust-version = "1.93" +description = "Cargo artifact crate for the linux-arm64-gnu oliphaunt-broker helper binary." +readme = "README.md" +repository = "https://github.com/f0rr0/oliphaunt" +homepage = "https://oliphaunt.dev" +license = "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause" +links = "oliphaunt_artifact_broker_linux_arm64_gnu" +build = "build.rs" +include = ["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_LICENSES/**"] + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/src/runtimes/broker/crates/linux-arm64-gnu/README.md b/src/broker/crates/linux-arm64-gnu/README.md similarity index 100% rename from src/runtimes/broker/crates/linux-arm64-gnu/README.md rename to src/broker/crates/linux-arm64-gnu/README.md diff --git a/src/runtimes/broker/crates/linux-arm64-gnu/build.rs b/src/broker/crates/linux-arm64-gnu/build.rs similarity index 100% rename from src/runtimes/broker/crates/linux-arm64-gnu/build.rs rename to src/broker/crates/linux-arm64-gnu/build.rs diff --git a/src/runtimes/broker/crates/linux-arm64-gnu/src/lib.rs b/src/broker/crates/linux-arm64-gnu/src/lib.rs similarity index 100% rename from src/runtimes/broker/crates/linux-arm64-gnu/src/lib.rs rename to src/broker/crates/linux-arm64-gnu/src/lib.rs diff --git a/src/broker/crates/linux-x64-gnu/Cargo.toml b/src/broker/crates/linux-x64-gnu/Cargo.toml new file mode 100644 index 000000000..342c6e131 --- /dev/null +++ b/src/broker/crates/linux-x64-gnu/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "oliphaunt-broker-linux-x64-gnu" +version = "0.2.0" +edition = "2024" +rust-version = "1.93" +description = "Cargo artifact crate for the linux-x64-gnu oliphaunt-broker helper binary." +readme = "README.md" +repository = "https://github.com/f0rr0/oliphaunt" +homepage = "https://oliphaunt.dev" +license = "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause" +links = "oliphaunt_artifact_broker_linux_x64_gnu" +build = "build.rs" +include = ["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_LICENSES/**"] + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/src/runtimes/broker/crates/linux-x64-gnu/README.md b/src/broker/crates/linux-x64-gnu/README.md similarity index 100% rename from src/runtimes/broker/crates/linux-x64-gnu/README.md rename to src/broker/crates/linux-x64-gnu/README.md diff --git a/src/runtimes/broker/crates/linux-x64-gnu/build.rs b/src/broker/crates/linux-x64-gnu/build.rs similarity index 100% rename from src/runtimes/broker/crates/linux-x64-gnu/build.rs rename to src/broker/crates/linux-x64-gnu/build.rs diff --git a/src/runtimes/broker/crates/linux-x64-gnu/src/lib.rs b/src/broker/crates/linux-x64-gnu/src/lib.rs similarity index 100% rename from src/runtimes/broker/crates/linux-x64-gnu/src/lib.rs rename to src/broker/crates/linux-x64-gnu/src/lib.rs diff --git a/src/broker/crates/macos-arm64/Cargo.toml b/src/broker/crates/macos-arm64/Cargo.toml new file mode 100644 index 000000000..a86c30ffe --- /dev/null +++ b/src/broker/crates/macos-arm64/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "oliphaunt-broker-macos-arm64" +version = "0.2.0" +edition = "2024" +rust-version = "1.93" +description = "Cargo artifact crate for the macos-arm64 oliphaunt-broker helper binary." +readme = "README.md" +repository = "https://github.com/f0rr0/oliphaunt" +homepage = "https://oliphaunt.dev" +license = "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause" +links = "oliphaunt_artifact_broker_macos_arm64" +build = "build.rs" +include = ["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_LICENSES/**"] + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/src/runtimes/broker/crates/macos-arm64/README.md b/src/broker/crates/macos-arm64/README.md similarity index 100% rename from src/runtimes/broker/crates/macos-arm64/README.md rename to src/broker/crates/macos-arm64/README.md diff --git a/src/runtimes/broker/crates/macos-arm64/build.rs b/src/broker/crates/macos-arm64/build.rs similarity index 100% rename from src/runtimes/broker/crates/macos-arm64/build.rs rename to src/broker/crates/macos-arm64/build.rs diff --git a/src/runtimes/broker/crates/macos-arm64/src/lib.rs b/src/broker/crates/macos-arm64/src/lib.rs similarity index 100% rename from src/runtimes/broker/crates/macos-arm64/src/lib.rs rename to src/broker/crates/macos-arm64/src/lib.rs diff --git a/src/broker/crates/windows-x64-msvc/Cargo.toml b/src/broker/crates/windows-x64-msvc/Cargo.toml new file mode 100644 index 000000000..1455ef461 --- /dev/null +++ b/src/broker/crates/windows-x64-msvc/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "oliphaunt-broker-windows-x64-msvc" +version = "0.2.0" +edition = "2024" +rust-version = "1.93" +description = "Cargo artifact crate for the windows-x64-msvc oliphaunt-broker helper binary." +readme = "README.md" +repository = "https://github.com/f0rr0/oliphaunt" +homepage = "https://oliphaunt.dev" +license = "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause" +links = "oliphaunt_artifact_broker_windows_x64_msvc" +build = "build.rs" +include = ["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_LICENSES/**"] + +[lib] +path = "src/lib.rs" + +[workspace] diff --git a/src/runtimes/broker/crates/windows-x64-msvc/README.md b/src/broker/crates/windows-x64-msvc/README.md similarity index 100% rename from src/runtimes/broker/crates/windows-x64-msvc/README.md rename to src/broker/crates/windows-x64-msvc/README.md diff --git a/src/runtimes/broker/crates/windows-x64-msvc/build.rs b/src/broker/crates/windows-x64-msvc/build.rs similarity index 100% rename from src/runtimes/broker/crates/windows-x64-msvc/build.rs rename to src/broker/crates/windows-x64-msvc/build.rs diff --git a/src/runtimes/broker/crates/windows-x64-msvc/src/lib.rs b/src/broker/crates/windows-x64-msvc/src/lib.rs similarity index 100% rename from src/runtimes/broker/crates/windows-x64-msvc/src/lib.rs rename to src/broker/crates/windows-x64-msvc/src/lib.rs diff --git a/src/runtimes/broker/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64 b/src/broker/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64 rename to src/broker/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64 diff --git a/src/broker/dependency-license-blobs/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594.base64 b/src/broker/dependency-license-blobs/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594.base64 new file mode 100644 index 000000000..3cea07385 --- /dev/null +++ b/src/broker/dependency-license-blobs/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594.base64 @@ -0,0 +1,179 @@ +CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAg +ICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAg +ICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5E +IENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAx +LiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQg +Y29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24g +YXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAg +ICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1 +dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRo +ZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2Yg +dGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRy +b2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wg +d2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAg +ICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRv +IGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwg +d2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlw +IG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcg +c2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAg +ICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBF +bnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5z +ZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y +IG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRv +IHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNv +bmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZv +cm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFu +c2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVk +IHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAg +YW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxs +IG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAg +T2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0 +ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0 +YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFw +cGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3 +b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNl +ZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBl +ZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBt +b2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29y +ayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwg +RGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAg +ICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhl +IGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJl +b2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNo +aXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg +YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJp +dmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0 +ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0 +IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6 +ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3Ig +dGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMg +YW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24g +c2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVk +aW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMg +bWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNz +dWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2Ys +IHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1w +cm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBp +cyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3 +cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgog +ICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFs +IG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBo +YXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29y +cG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5z +ZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNl +bnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAog +ICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBp +cnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUg +RGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy +Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2gg +RGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBv +ZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YK +ICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91 +IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwg +cm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlz +IHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBv +ZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdv +cmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50 +IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVj +ZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBv +ciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUg +V29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UK +ICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5j +bHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkg +YWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0 +ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRv +cnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdy +YW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1p +bmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0 +LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVz +IG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVk +aXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv +ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5n +IGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50 +cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhp +cyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmls +ZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3Ug +Y2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhl +IFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBk +aXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAg +ICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAog +ICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBh +bnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQp +IElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRz +CiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZ +b3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0 +aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5P +VElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAg +cGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qg +b25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRl +eHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBX +b3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwg +aWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAg +ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg +YW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkg +YXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9y +IGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkg +dGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBu +b3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25n +c2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20g +dGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1 +dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0 +aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1l +bnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFs +IG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2Us +IHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IK +ICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQg +WW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29y +ayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4g +dGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3Mg +WW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGlu +dGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkg +WW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlv +bnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9y +IGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVy +ZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh +cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBM +aWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4g +VGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQog +ICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBv +ZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBh +bmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdv +cmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcu +IERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxh +dyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdv +cmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25z +KSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElU +SU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVk +aW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAg +ICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVT +UyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNp +YmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9y +IHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29j +aWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5z +ZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIg +bm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdl +bmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFw +cGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGln +ZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3Ig +YmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs +IGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRh +bWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMg +TGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBX +b3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29v +ZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rp +b24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3Nz +ZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0 +aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5 +IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUg +V29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVy +LAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJy +YW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5k +L29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBp +biBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZ +b3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJl +aGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3Jl +ZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBo +YXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFz +c2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIg +YWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAg +RU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCg== diff --git a/src/runtimes/broker/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64 b/src/broker/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64 rename to src/broker/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64 b/src/broker/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64 rename to src/broker/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64 diff --git a/src/broker/dependency-license-blobs/129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8.base64 b/src/broker/dependency-license-blobs/129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8.base64 new file mode 100644 index 000000000..e11847ef7 --- /dev/null +++ b/src/broker/dependency-license-blobs/129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8.base64 @@ -0,0 +1,19 @@ +VGhlIE1JVCBMaWNlbnNlIChNSVQpCkNvcHlyaWdodCAoYykgMjAxNiBBbGV4YW5kcmUgQnVyeQoK +UGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJz +b24gb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3Vt +ZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUg +d2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmln +aHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3Vi +bGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1p +dCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3Vi +amVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5v +dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwg +Y29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZU +V0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBF +WFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJB +TlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9T +RSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBD +T1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhF +UiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9U +SEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBT +T0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K diff --git a/src/runtimes/broker/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64 b/src/broker/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64 rename to src/broker/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64 diff --git a/src/broker/dependency-license-blobs/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.base64 b/src/broker/dependency-license-blobs/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.base64 new file mode 100644 index 000000000..bc239132a --- /dev/null +++ b/src/broker/dependency-license-blobs/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.base64 @@ -0,0 +1,215 @@ +CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAg +ICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAg +ICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5E +IENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAx +LiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQg +Y29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24g +YXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAg +ICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1 +dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRo +ZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2Yg +dGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRy +b2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wg +d2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAg +ICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRv +IGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwg +d2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlw +IG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcg +c2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAg +ICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBF +bnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5z +ZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y +IG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRv +IHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNv +bmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZv +cm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFu +c2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVk +IHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAg +YW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxs +IG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAg +T2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0 +ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0 +YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFw +cGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3 +b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNl +ZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBl +ZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBt +b2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29y +ayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwg +RGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAg +ICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhl +IGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJl +b2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNo +aXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg +YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJp +dmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0 +ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0 +IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6 +ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3Ig +dGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMg +YW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24g +c2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVk +aW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMg +bWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNz +dWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2Ys +IHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1w +cm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBp +cyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3 +cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgog +ICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFs +IG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBo +YXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29y +cG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5z +ZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNl +bnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAog +ICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBp +cnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUg +RGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy +Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2gg +RGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBv +ZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YK +ICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91 +IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwg +cm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlz +IHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBv +ZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdv +cmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50 +IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVj +ZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBv +ciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUg +V29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UK +ICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5j +bHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkg +YWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0 +ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRv +cnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdy +YW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1p +bmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0 +LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVz +IG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVk +aXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv +ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5n +IGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50 +cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhp +cyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmls +ZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3Ug +Y2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhl +IFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBk +aXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAg +ICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAog +ICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBh +bnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQp +IElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRz +CiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZ +b3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0 +aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5P +VElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAg +cGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qg +b25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRl +eHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBX +b3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwg +aWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAg +ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg +YW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkg +YXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9y +IGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkg +dGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBu +b3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25n +c2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20g +dGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1 +dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0 +aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1l +bnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFs +IG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2Us +IHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IK +ICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQg +WW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29y +ayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4g +dGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3Mg +WW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGlu +dGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkg +WW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlv +bnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9y +IGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVy +ZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh +cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBM +aWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4g +VGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQog +ICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBv +ZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBh +bmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdv +cmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcu +IERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxh +dyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdv +cmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25z +KSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElU +SU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVk +aW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAg +ICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVT +UyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNp +YmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9y +IHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29j +aWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5z +ZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIg +bm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdl +bmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFw +cGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGln +ZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3Ig +YmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs +IGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRh +bWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMg +TGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBX +b3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29v +ZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rp +b24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3Nz +ZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0 +aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5 +IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUg +V29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVy +LAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJy +YW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5k +L29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBp +biBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZ +b3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJl +aGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3Jl +ZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBo +YXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFz +c2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIg +YWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAg +RU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRo +ZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hl +IExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJw +bGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAg +ICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24n +dCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9z +ZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBm +b3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUg +YW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUg +InByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBp +ZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQg +W3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBB +cGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5v +dCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAg +IFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93 +d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5 +IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0 +cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJB +U0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0 +aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lm +aWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRl +ciB0aGUgTGljZW5zZS4KCgotLS0gTExWTSBFeGNlcHRpb25zIHRvIHRoZSBBcGFjaGUgMi4wIExp +Y2Vuc2UgLS0tLQoKQXMgYW4gZXhjZXB0aW9uLCBpZiwgYXMgYSByZXN1bHQgb2YgeW91ciBjb21w +aWxpbmcgeW91ciBzb3VyY2UgY29kZSwgcG9ydGlvbnMKb2YgdGhpcyBTb2Z0d2FyZSBhcmUgZW1i +ZWRkZWQgaW50byBhbiBPYmplY3QgZm9ybSBvZiBzdWNoIHNvdXJjZSBjb2RlLCB5b3UKbWF5IHJl +ZGlzdHJpYnV0ZSBzdWNoIGVtYmVkZGVkIHBvcnRpb25zIGluIHN1Y2ggT2JqZWN0IGZvcm0gd2l0 +aG91dCBjb21wbHlpbmcKd2l0aCB0aGUgY29uZGl0aW9ucyBvZiBTZWN0aW9ucyA0KGEpLCA0KGIp +IGFuZCA0KGQpIG9mIHRoZSBMaWNlbnNlLgoKSW4gYWRkaXRpb24sIGlmIHlvdSBjb21iaW5lIG9y +IGxpbmsgY29tcGlsZWQgZm9ybXMgb2YgdGhpcyBTb2Z0d2FyZSB3aXRoCnNvZnR3YXJlIHRoYXQg +aXMgbGljZW5zZWQgdW5kZXIgdGhlIEdQTHYyICgiQ29tYmluZWQgU29mdHdhcmUiKSBhbmQgaWYg +YQpjb3VydCBvZiBjb21wZXRlbnQganVyaXNkaWN0aW9uIGRldGVybWluZXMgdGhhdCB0aGUgcGF0 +ZW50IHByb3Zpc2lvbiAoU2VjdGlvbgozKSwgdGhlIGluZGVtbml0eSBwcm92aXNpb24gKFNlY3Rp +b24gOSkgb3Igb3RoZXIgU2VjdGlvbiBvZiB0aGUgTGljZW5zZQpjb25mbGljdHMgd2l0aCB0aGUg +Y29uZGl0aW9ucyBvZiB0aGUgR1BMdjIsIHlvdSBtYXkgcmV0cm9hY3RpdmVseSBhbmQKcHJvc3Bl +Y3RpdmVseSBjaG9vc2UgdG8gZGVlbSB3YWl2ZWQgb3Igb3RoZXJ3aXNlIGV4Y2x1ZGUgc3VjaCBT +ZWN0aW9uKHMpIG9mCnRoZSBMaWNlbnNlLCBidXQgb25seSBpbiB0aGVpciBlbnRpcmV0eSBhbmQg +b25seSB3aXRoIHJlc3BlY3QgdG8gdGhlIENvbWJpbmVkClNvZnR3YXJlLgoK diff --git a/src/runtimes/broker/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64 b/src/broker/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64 rename to src/broker/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64 diff --git a/src/broker/dependency-license-blobs/3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b.base64 b/src/broker/dependency-license-blobs/3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b.base64 new file mode 100644 index 000000000..41dcc5852 --- /dev/null +++ b/src/broker/dependency-license-blobs/3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b.base64 @@ -0,0 +1,16 @@ +U2hvcnQgdmVyc2lvbiBmb3Igbm9uLWxhd3llcnM6CgpgbGludXgtcmF3LXN5c2AgaXMgdHJpcGxl +LWxpY2Vuc2VkIHVuZGVyIEFwYWNoZSAyLjAgd2l0aCB0aGUgTExWTSBFeGNlcHRpb24sCkFwYWNo +ZSAyLjAsIGFuZCBNSVQgdGVybXMuCgoKTG9uZ2VyIHZlcnNpb246CgpDb3B5cmlnaHRzIGluIHRo +ZSBgbGludXgtcmF3LXN5c2AgcHJvamVjdCBhcmUgcmV0YWluZWQgYnkgdGhlaXIgY29udHJpYnV0 +b3JzLgpObyBjb3B5cmlnaHQgYXNzaWdubWVudCBpcyByZXF1aXJlZCB0byBjb250cmlidXRlIHRv +IHRoZSBgbGludXgtcmF3LXN5c2AKcHJvamVjdC4KClNvbWUgZmlsZXMgaW5jbHVkZSBjb2RlIGRl +cml2ZWQgZnJvbSBSdXN0J3MgYGxpYnN0ZGA7IHNlZSB0aGUgY29tbWVudHMgaW4KdGhlIGNvZGUg +Zm9yIGRldGFpbHMuCgpFeGNlcHQgYXMgb3RoZXJ3aXNlIG5vdGVkIChiZWxvdyBhbmQvb3IgaW4g +aW5kaXZpZHVhbCBmaWxlcyksIGBsaW51eC1yYXctc3lzYAppcyBsaWNlbnNlZCB1bmRlcjoKCiAt +IHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAsIHdpdGggdGhlIExMVk0gRXhjZXB0aW9u +CiAgIDxMSUNFTlNFLUFwYWNoZS0yLjBfV0lUSF9MTFZNLWV4Y2VwdGlvbj4gb3IKICAgPGh0dHA6 +Ly9sbHZtLm9yZy9mb3VuZGF0aW9uL3JlbGljZW5zaW5nL0xJQ0VOU0UudHh0PgogLSB0aGUgQXBh +Y2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wCiAgIDxMSUNFTlNFLUFQQUNIRT4gb3IKICAgPGh0dHA6 +Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMD4sCiAtIG9yIHRoZSBNSVQgbGlj +ZW5zZQogICA8TElDRU5TRS1NSVQ+IG9yCiAgIDxodHRwOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5z +ZXMvTUlUPiwKCmF0IHlvdXIgb3B0aW9uLgo= diff --git a/src/runtimes/broker/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64 b/src/broker/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64 rename to src/broker/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64 diff --git a/src/broker/dependency-license-blobs/377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9.base64 b/src/broker/dependency-license-blobs/377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9.base64 new file mode 100644 index 000000000..435dc2fa0 --- /dev/null +++ b/src/broker/dependency-license-blobs/377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9.base64 @@ -0,0 +1,15 @@ +U2hvcnQgdmVyc2lvbiBmb3Igbm9uLWxhd3llcnM6CgpgcnVzdGl4YCBpcyB0cmlwbGUtbGljZW5z +ZWQgdW5kZXIgQXBhY2hlIDIuMCB3aXRoIHRoZSBMTFZNIEV4Y2VwdGlvbiwKQXBhY2hlIDIuMCwg +YW5kIE1JVCB0ZXJtcy4KCgpMb25nZXIgdmVyc2lvbjoKCkNvcHlyaWdodHMgaW4gdGhlIGBydXN0 +aXhgIHByb2plY3QgYXJlIHJldGFpbmVkIGJ5IHRoZWlyIGNvbnRyaWJ1dG9ycy4KTm8gY29weXJp +Z2h0IGFzc2lnbm1lbnQgaXMgcmVxdWlyZWQgdG8gY29udHJpYnV0ZSB0byB0aGUgYHJ1c3RpeGAK +cHJvamVjdC4KClNvbWUgZmlsZXMgaW5jbHVkZSBjb2RlIGRlcml2ZWQgZnJvbSBSdXN0J3MgYGxp +YnN0ZGA7IHNlZSB0aGUgY29tbWVudHMgaW4KdGhlIGNvZGUgZm9yIGRldGFpbHMuCgpFeGNlcHQg +YXMgb3RoZXJ3aXNlIG5vdGVkIChiZWxvdyBhbmQvb3IgaW4gaW5kaXZpZHVhbCBmaWxlcyksIGBy +dXN0aXhgCmlzIGxpY2Vuc2VkIHVuZGVyOgoKIC0gdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9u +IDIuMCwgd2l0aCB0aGUgTExWTSBFeGNlcHRpb24KICAgPExJQ0VOU0UtQXBhY2hlLTIuMF9XSVRI +X0xMVk0tZXhjZXB0aW9uPiBvcgogICA8aHR0cDovL2xsdm0ub3JnL2ZvdW5kYXRpb24vcmVsaWNl +bnNpbmcvTElDRU5TRS50eHQ+CiAtIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAKICAg +PExJQ0VOU0UtQVBBQ0hFPiBvcgogICA8aHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJ +Q0VOU0UtMi4wPiwKIC0gb3IgdGhlIE1JVCBsaWNlbnNlCiAgIDxMSUNFTlNFLU1JVD4gb3IKICAg +PGh0dHA6Ly9vcGVuc291cmNlLm9yZy9saWNlbnNlcy9NSVQ+LAoKYXQgeW91ciBvcHRpb24uCg== diff --git a/src/runtimes/broker/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64 b/src/broker/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64 rename to src/broker/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64 diff --git a/src/broker/dependency-license-blobs/48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd.base64 b/src/broker/dependency-license-blobs/48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd.base64 new file mode 100644 index 000000000..d8a50af44 --- /dev/null +++ b/src/broker/dependency-license-blobs/48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd.base64 @@ -0,0 +1,28 @@ +VGhlIGF1dG8tZ2VuZXJhdGVkIGJpbmRpbmdzIGFyZSB1bmRlciB0aGUgMy1jbGF1c2UgQlNEIGxp +Y2Vuc2U6CgpCU0QgTGljZW5zZQoKRm9yIFpzdGFuZGFyZCBzb2Z0d2FyZQoKQ29weXJpZ2h0IChj +KSAyMDE2LXByZXNlbnQsIEZhY2Vib29rLCBJbmMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgpSZWRp +c3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdp +dGhvdXQgbW9kaWZpY2F0aW9uLAphcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxv +d2luZyBjb25kaXRpb25zIGFyZSBtZXQ6CgogKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNv +ZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsIHRoaXMKICAgbGlzdCBv +ZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgogKiBSZWRpc3RyaWJ1 +dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodCBu +b3RpY2UsCiAgIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2Ns +YWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb24KICAgYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92 +aWRlZCB3aXRoIHRoZSBkaXN0cmlidXRpb24uCgogKiBOZWl0aGVyIHRoZSBuYW1lIEZhY2Vib29r +IG5vciB0aGUgbmFtZXMgb2YgaXRzIGNvbnRyaWJ1dG9ycyBtYXkgYmUgdXNlZCB0bwogICBlbmRv +cnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZCBmcm9tIHRoaXMgc29mdHdhcmUgd2l0aG91 +dCBzcGVjaWZpYwogICBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgpUSElTIFNPRlRXQVJFIElT +IFBST1ZJREVEIEJZIFRIRSBDT1BZUklHSFQgSE9MREVSUyBBTkQgQ09OVFJJQlVUT1JTICJBUyBJ +UyIgQU5ECkFOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQg +Tk9UIExJTUlURUQgVE8sIFRIRSBJTVBMSUVECldBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZ +IEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUKRElTQ0xBSU1FRC4gSU4g +Tk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVCBIT0xERVIgT1IgQ09OVFJJQlVUT1JTIEJFIExJ +QUJMRSBGT1IKQU5ZIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsIFNQRUNJQUwsIEVYRU1Q +TEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTCihJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRF +RCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUzsKTE9TUyBP +RiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikgSE9XRVZF +UiBDQVVTRUQgQU5EIE9OCkFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRS +QUNULCBTVFJJQ1QgTElBQklMSVRZLCBPUiBUT1JUCihJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBP +VEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRiBUSElTClNPRlRX +QVJFLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLgo= diff --git a/src/runtimes/broker/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64 b/src/broker/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64 rename to src/broker/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64 b/src/broker/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64 rename to src/broker/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64 diff --git a/src/broker/dependency-license-blobs/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.base64 b/src/broker/dependency-license-blobs/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.base64 new file mode 100644 index 000000000..63f5ccfa7 --- /dev/null +++ b/src/broker/dependency-license-blobs/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.base64 @@ -0,0 +1,19 @@ +Q29weXJpZ2h0IChjKSAyMDE0IFRoZSBSdXN0IFByb2plY3QgRGV2ZWxvcGVycwoKUGVybWlzc2lv +biBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWlu +aW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24g +ZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCBy +ZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVz +ZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwg +YW5kL29yIHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25z +IHRvIHdob20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0 +aGUgZm9sbG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQg +dGhpcyBwZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9y +IHN1YnN0YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQ +Uk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9S +IElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0Yg +TUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9O +SU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQg +SE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJ +VFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwg +QVJJU0lORyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBP +UiBUSEUgVVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K diff --git a/src/broker/dependency-license-blobs/7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8.base64 b/src/broker/dependency-license-blobs/7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8.base64 new file mode 100644 index 000000000..3ea11f2c8 --- /dev/null +++ b/src/broker/dependency-license-blobs/7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8.base64 @@ -0,0 +1,28 @@ +QlNEIExpY2Vuc2UKCkZvciBac3RhbmRhcmQgc29mdHdhcmUKCkNvcHlyaWdodCAoYykgTWV0YSBQ +bGF0Zm9ybXMsIEluYy4gYW5kIGFmZmlsaWF0ZXMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgpSZWRp +c3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdp +dGhvdXQgbW9kaWZpY2F0aW9uLAphcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxv +d2luZyBjb25kaXRpb25zIGFyZSBtZXQ6CgogKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNv +ZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsIHRoaXMKICAgbGlzdCBv +ZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgogKiBSZWRpc3RyaWJ1 +dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodCBu +b3RpY2UsCiAgIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2Ns +YWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb24KICAgYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92 +aWRlZCB3aXRoIHRoZSBkaXN0cmlidXRpb24uCgogKiBOZWl0aGVyIHRoZSBuYW1lIEZhY2Vib29r +LCBub3IgTWV0YSwgbm9yIHRoZSBuYW1lcyBvZiBpdHMgY29udHJpYnV0b3JzIG1heQogICBiZSB1 +c2VkIHRvIGVuZG9yc2Ugb3IgcHJvbW90ZSBwcm9kdWN0cyBkZXJpdmVkIGZyb20gdGhpcyBzb2Z0 +d2FyZSB3aXRob3V0CiAgIHNwZWNpZmljIHByaW9yIHdyaXR0ZW4gcGVybWlzc2lvbi4KClRISVMg +U09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORCBDT05UUklC +VVRPUlMgIkFTIElTIiBBTkQKQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNM +VURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQKV0FSUkFOVElFUyBPRiBNRVJD +SEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRQpESVND +TEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQ09QWVJJR0hUIEhPTERFUiBPUiBDT05UUklC +VVRPUlMgQkUgTElBQkxFIEZPUgpBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BF +Q0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMKKElOQ0xVRElORywgQlVU +IE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJ +Q0VTOwpMT1NTIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBU +SU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT04KQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRI +RVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQKKElOQ0xVRElORyBORUdM +SUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgVVNFIE9G +IFRISVMKU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VD +SCBEQU1BR0UuCg== diff --git a/src/runtimes/broker/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64 b/src/broker/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64 rename to src/broker/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64 b/src/broker/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64 rename to src/broker/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64 diff --git a/src/broker/dependency-license-blobs/8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2.base64 b/src/broker/dependency-license-blobs/8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2.base64 new file mode 100644 index 000000000..8ca7d5553 --- /dev/null +++ b/src/broker/dependency-license-blobs/8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2.base64 @@ -0,0 +1,19 @@ +Q29weXJpZ2h0IChjKSAyMDE0IENocmlzIFdvbmcKClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50 +ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhp +cyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3 +YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1 +ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwg +bWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGll +cyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0 +d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZwpjb25k +aXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBu +b3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0 +aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwg +V0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJ +TkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwg +RklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4g +Tk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxF +IEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFO +IEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VU +IE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhF +UgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg== diff --git a/src/broker/dependency-license-blobs/8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36.base64 b/src/broker/dependency-license-blobs/8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36.base64 new file mode 100644 index 000000000..7744e2c5b --- /dev/null +++ b/src/broker/dependency-license-blobs/8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36.base64 @@ -0,0 +1,19 @@ +Q29weXJpZ2h0IChjKSAyMDE1IFN0ZXZlbiBBbGxlbgoKUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3Jh +bnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWluaW5nIGEgY29weSBvZiB0 +aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29m +dHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5j +bHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5 +LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29w +aWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNv +ZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nCmNv +bmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9u +IG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBv +cnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMi +LCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xV +RElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZ +LCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJ +TiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFC +TEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4g +QU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBP +VVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9U +SEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K diff --git a/src/broker/dependency-license-blobs/8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077.base64 b/src/broker/dependency-license-blobs/8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077.base64 new file mode 100644 index 000000000..66df04367 --- /dev/null +++ b/src/broker/dependency-license-blobs/8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077.base64 @@ -0,0 +1,19 @@ +Q29weXJpZ2h0IChjKSBUaGUgdGFyLXJzIFByb2plY3QgQ29udHJpYnV0b3JzCgpQZXJtaXNzaW9u +IGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRhaW5p +bmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlvbiBm +aWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0IHJl +c3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNl +LCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBh +bmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMg +dG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRo +ZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0 +aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Ig +c3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElTIFBS +T1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1MgT1Ig +SU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBPRiBN +RVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05J +TkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBI +T0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElU +WSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBB +UklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9S +IFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo= diff --git a/src/runtimes/broker/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64 b/src/broker/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64 rename to src/broker/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64 b/src/broker/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64 rename to src/broker/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64 diff --git a/src/broker/dependency-license-blobs/a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63.base64 b/src/broker/dependency-license-blobs/a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63.base64 new file mode 100644 index 000000000..078caa305 --- /dev/null +++ b/src/broker/dependency-license-blobs/a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63.base64 @@ -0,0 +1 @@ +TUlUIG9yIEFwYWNoZS0yLjAK diff --git a/src/runtimes/broker/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64 b/src/broker/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64 rename to src/broker/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64 b/src/broker/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64 rename to src/broker/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64 b/src/broker/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64 rename to src/broker/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64 b/src/broker/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64 rename to src/broker/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64 b/src/broker/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64 rename to src/broker/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1.base64 b/src/broker/dependency-license-blobs/b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1.base64 rename to src/broker/dependency-license-blobs/b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64 b/src/broker/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64 rename to src/broker/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64 b/src/broker/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64 rename to src/broker/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b.base64 b/src/broker/dependency-license-blobs/c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b.base64 rename to src/broker/dependency-license-blobs/c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383.base64 b/src/broker/dependency-license-blobs/c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383.base64 rename to src/broker/dependency-license-blobs/c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b.base64 b/src/broker/dependency-license-blobs/ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b.base64 rename to src/broker/dependency-license-blobs/ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64 b/src/broker/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64 rename to src/broker/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64 b/src/broker/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64 rename to src/broker/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64 diff --git a/src/runtimes/broker/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64 b/src/broker/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64 similarity index 100% rename from src/runtimes/broker/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64 rename to src/broker/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64 diff --git a/src/broker/dependency-license-blobs/f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505.base64 b/src/broker/dependency-license-blobs/f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505.base64 new file mode 100644 index 000000000..f598c992e --- /dev/null +++ b/src/broker/dependency-license-blobs/f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505.base64 @@ -0,0 +1,318 @@ +ICAgICAgICAgICAgICAgICAgICBHTlUgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAgICAgICAg +ICAgICAgICAgICAgIFZlcnNpb24gMiwgSnVuZSAxOTkxCgogQ29weXJpZ2h0IChDKSAxOTg5LCAx +OTkxIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiwKIDUxIEZyYW5rbGluIFN0cmVldCwg +RmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgMDIxMTAtMTMwMSBVU0EKIEV2ZXJ5b25lIGlzIHBlcm1p +dHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNvcGllcwogb2YgdGhpcyBsaWNl +bnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFsbG93ZWQuCgogICAgICAgICAg +ICAgICAgICAgICAgICAgICAgUHJlYW1ibGUKCiAgVGhlIGxpY2Vuc2VzIGZvciBtb3N0IHNvZnR3 +YXJlIGFyZSBkZXNpZ25lZCB0byB0YWtlIGF3YXkgeW91cgpmcmVlZG9tIHRvIHNoYXJlIGFuZCBj +aGFuZ2UgaXQuICBCeSBjb250cmFzdCwgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYwpMaWNlbnNlIGlz +IGludGVuZGVkIHRvIGd1YXJhbnRlZSB5b3VyIGZyZWVkb20gdG8gc2hhcmUgYW5kIGNoYW5nZSBm +cmVlCnNvZnR3YXJlLS10byBtYWtlIHN1cmUgdGhlIHNvZnR3YXJlIGlzIGZyZWUgZm9yIGFsbCBp +dHMgdXNlcnMuICBUaGlzCkdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXBwbGllcyB0byBtb3N0IG9m +IHRoZSBGcmVlIFNvZnR3YXJlCkZvdW5kYXRpb24ncyBzb2Z0d2FyZSBhbmQgdG8gYW55IG90aGVy +IHByb2dyYW0gd2hvc2UgYXV0aG9ycyBjb21taXQgdG8KdXNpbmcgaXQuICAoU29tZSBvdGhlciBG +cmVlIFNvZnR3YXJlIEZvdW5kYXRpb24gc29mdHdhcmUgaXMgY292ZXJlZCBieQp0aGUgR05VIExl +c3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGluc3RlYWQuKSAgWW91IGNhbiBhcHBseSBpdCB0 +bwp5b3VyIHByb2dyYW1zLCB0b28uCgogIFdoZW4gd2Ugc3BlYWsgb2YgZnJlZSBzb2Z0d2FyZSwg +d2UgYXJlIHJlZmVycmluZyB0byBmcmVlZG9tLCBub3QKcHJpY2UuICBPdXIgR2VuZXJhbCBQdWJs +aWMgTGljZW5zZXMgYXJlIGRlc2lnbmVkIHRvIG1ha2Ugc3VyZSB0aGF0IHlvdQpoYXZlIHRoZSBm +cmVlZG9tIHRvIGRpc3RyaWJ1dGUgY29waWVzIG9mIGZyZWUgc29mdHdhcmUgKGFuZCBjaGFyZ2Ug +Zm9yCnRoaXMgc2VydmljZSBpZiB5b3Ugd2lzaCksIHRoYXQgeW91IHJlY2VpdmUgc291cmNlIGNv +ZGUgb3IgY2FuIGdldCBpdAppZiB5b3Ugd2FudCBpdCwgdGhhdCB5b3UgY2FuIGNoYW5nZSB0aGUg +c29mdHdhcmUgb3IgdXNlIHBpZWNlcyBvZiBpdAppbiBuZXcgZnJlZSBwcm9ncmFtczsgYW5kIHRo +YXQgeW91IGtub3cgeW91IGNhbiBkbyB0aGVzZSB0aGluZ3MuCgogIFRvIHByb3RlY3QgeW91ciBy +aWdodHMsIHdlIG5lZWQgdG8gbWFrZSByZXN0cmljdGlvbnMgdGhhdCBmb3JiaWQKYW55b25lIHRv +IGRlbnkgeW91IHRoZXNlIHJpZ2h0cyBvciB0byBhc2sgeW91IHRvIHN1cnJlbmRlciB0aGUgcmln +aHRzLgpUaGVzZSByZXN0cmljdGlvbnMgdHJhbnNsYXRlIHRvIGNlcnRhaW4gcmVzcG9uc2liaWxp +dGllcyBmb3IgeW91IGlmIHlvdQpkaXN0cmlidXRlIGNvcGllcyBvZiB0aGUgc29mdHdhcmUsIG9y +IGlmIHlvdSBtb2RpZnkgaXQuCgogIEZvciBleGFtcGxlLCBpZiB5b3UgZGlzdHJpYnV0ZSBjb3Bp +ZXMgb2Ygc3VjaCBhIHByb2dyYW0sIHdoZXRoZXIKZ3JhdGlzIG9yIGZvciBhIGZlZSwgeW91IG11 +c3QgZ2l2ZSB0aGUgcmVjaXBpZW50cyBhbGwgdGhlIHJpZ2h0cyB0aGF0CnlvdSBoYXZlLiAgWW91 +IG11c3QgbWFrZSBzdXJlIHRoYXQgdGhleSwgdG9vLCByZWNlaXZlIG9yIGNhbiBnZXQgdGhlCnNv +dXJjZSBjb2RlLiAgQW5kIHlvdSBtdXN0IHNob3cgdGhlbSB0aGVzZSB0ZXJtcyBzbyB0aGV5IGtu +b3cgdGhlaXIKcmlnaHRzLgoKICBXZSBwcm90ZWN0IHlvdXIgcmlnaHRzIHdpdGggdHdvIHN0ZXBz +OiAoMSkgY29weXJpZ2h0IHRoZSBzb2Z0d2FyZSwgYW5kCigyKSBvZmZlciB5b3UgdGhpcyBsaWNl +bnNlIHdoaWNoIGdpdmVzIHlvdSBsZWdhbCBwZXJtaXNzaW9uIHRvIGNvcHksCmRpc3RyaWJ1dGUg +YW5kL29yIG1vZGlmeSB0aGUgc29mdHdhcmUuCgogIEFsc28sIGZvciBlYWNoIGF1dGhvcidzIHBy +b3RlY3Rpb24gYW5kIG91cnMsIHdlIHdhbnQgdG8gbWFrZSBjZXJ0YWluCnRoYXQgZXZlcnlvbmUg +dW5kZXJzdGFuZHMgdGhhdCB0aGVyZSBpcyBubyB3YXJyYW50eSBmb3IgdGhpcyBmcmVlCnNvZnR3 +YXJlLiAgSWYgdGhlIHNvZnR3YXJlIGlzIG1vZGlmaWVkIGJ5IHNvbWVvbmUgZWxzZSBhbmQgcGFz +c2VkIG9uLCB3ZQp3YW50IGl0cyByZWNpcGllbnRzIHRvIGtub3cgdGhhdCB3aGF0IHRoZXkgaGF2 +ZSBpcyBub3QgdGhlIG9yaWdpbmFsLCBzbwp0aGF0IGFueSBwcm9ibGVtcyBpbnRyb2R1Y2VkIGJ5 +IG90aGVycyB3aWxsIG5vdCByZWZsZWN0IG9uIHRoZSBvcmlnaW5hbAphdXRob3JzJyByZXB1dGF0 +aW9ucy4KCiAgRmluYWxseSwgYW55IGZyZWUgcHJvZ3JhbSBpcyB0aHJlYXRlbmVkIGNvbnN0YW50 +bHkgYnkgc29mdHdhcmUKcGF0ZW50cy4gIFdlIHdpc2ggdG8gYXZvaWQgdGhlIGRhbmdlciB0aGF0 +IHJlZGlzdHJpYnV0b3JzIG9mIGEgZnJlZQpwcm9ncmFtIHdpbGwgaW5kaXZpZHVhbGx5IG9idGFp +biBwYXRlbnQgbGljZW5zZXMsIGluIGVmZmVjdCBtYWtpbmcgdGhlCnByb2dyYW0gcHJvcHJpZXRh +cnkuICBUbyBwcmV2ZW50IHRoaXMsIHdlIGhhdmUgbWFkZSBpdCBjbGVhciB0aGF0IGFueQpwYXRl +bnQgbXVzdCBiZSBsaWNlbnNlZCBmb3IgZXZlcnlvbmUncyBmcmVlIHVzZSBvciBub3QgbGljZW5z +ZWQgYXQgYWxsLgoKICBUaGUgcHJlY2lzZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgY29weWlu +ZywgZGlzdHJpYnV0aW9uIGFuZAptb2RpZmljYXRpb24gZm9sbG93LgoKICAgICAgICAgICAgICAg +ICAgICBHTlUgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICBURVJNUyBBTkQgQ09ORElUSU9OUyBG +T1IgQ09QWUlORywgRElTVFJJQlVUSU9OIEFORCBNT0RJRklDQVRJT04KCiAgMC4gVGhpcyBMaWNl +bnNlIGFwcGxpZXMgdG8gYW55IHByb2dyYW0gb3Igb3RoZXIgd29yayB3aGljaCBjb250YWlucwph +IG5vdGljZSBwbGFjZWQgYnkgdGhlIGNvcHlyaWdodCBob2xkZXIgc2F5aW5nIGl0IG1heSBiZSBk +aXN0cmlidXRlZAp1bmRlciB0aGUgdGVybXMgb2YgdGhpcyBHZW5lcmFsIFB1YmxpYyBMaWNlbnNl +LiAgVGhlICJQcm9ncmFtIiwgYmVsb3csCnJlZmVycyB0byBhbnkgc3VjaCBwcm9ncmFtIG9yIHdv +cmssIGFuZCBhICJ3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtIgptZWFucyBlaXRoZXIgdGhlIFBy +b2dyYW0gb3IgYW55IGRlcml2YXRpdmUgd29yayB1bmRlciBjb3B5cmlnaHQgbGF3Ogp0aGF0IGlz +IHRvIHNheSwgYSB3b3JrIGNvbnRhaW5pbmcgdGhlIFByb2dyYW0gb3IgYSBwb3J0aW9uIG9mIGl0 +LAplaXRoZXIgdmVyYmF0aW0gb3Igd2l0aCBtb2RpZmljYXRpb25zIGFuZC9vciB0cmFuc2xhdGVk +IGludG8gYW5vdGhlcgpsYW5ndWFnZS4gIChIZXJlaW5hZnRlciwgdHJhbnNsYXRpb24gaXMgaW5j +bHVkZWQgd2l0aG91dCBsaW1pdGF0aW9uIGluCnRoZSB0ZXJtICJtb2RpZmljYXRpb24iLikgIEVh +Y2ggbGljZW5zZWUgaXMgYWRkcmVzc2VkIGFzICJ5b3UiLgoKQWN0aXZpdGllcyBvdGhlciB0aGFu +IGNvcHlpbmcsIGRpc3RyaWJ1dGlvbiBhbmQgbW9kaWZpY2F0aW9uIGFyZSBub3QKY292ZXJlZCBi +eSB0aGlzIExpY2Vuc2U7IHRoZXkgYXJlIG91dHNpZGUgaXRzIHNjb3BlLiAgVGhlIGFjdCBvZgpy +dW5uaW5nIHRoZSBQcm9ncmFtIGlzIG5vdCByZXN0cmljdGVkLCBhbmQgdGhlIG91dHB1dCBmcm9t +IHRoZSBQcm9ncmFtCmlzIGNvdmVyZWQgb25seSBpZiBpdHMgY29udGVudHMgY29uc3RpdHV0ZSBh +IHdvcmsgYmFzZWQgb24gdGhlClByb2dyYW0gKGluZGVwZW5kZW50IG9mIGhhdmluZyBiZWVuIG1h +ZGUgYnkgcnVubmluZyB0aGUgUHJvZ3JhbSkuCldoZXRoZXIgdGhhdCBpcyB0cnVlIGRlcGVuZHMg +b24gd2hhdCB0aGUgUHJvZ3JhbSBkb2VzLgoKICAxLiBZb3UgbWF5IGNvcHkgYW5kIGRpc3RyaWJ1 +dGUgdmVyYmF0aW0gY29waWVzIG9mIHRoZSBQcm9ncmFtJ3MKc291cmNlIGNvZGUgYXMgeW91IHJl +Y2VpdmUgaXQsIGluIGFueSBtZWRpdW0sIHByb3ZpZGVkIHRoYXQgeW91CmNvbnNwaWN1b3VzbHkg +YW5kIGFwcHJvcHJpYXRlbHkgcHVibGlzaCBvbiBlYWNoIGNvcHkgYW4gYXBwcm9wcmlhdGUKY29w +eXJpZ2h0IG5vdGljZSBhbmQgZGlzY2xhaW1lciBvZiB3YXJyYW50eTsga2VlcCBpbnRhY3QgYWxs +IHRoZQpub3RpY2VzIHRoYXQgcmVmZXIgdG8gdGhpcyBMaWNlbnNlIGFuZCB0byB0aGUgYWJzZW5j +ZSBvZiBhbnkgd2FycmFudHk7CmFuZCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRoZSBQ +cm9ncmFtIGEgY29weSBvZiB0aGlzIExpY2Vuc2UKYWxvbmcgd2l0aCB0aGUgUHJvZ3JhbS4KCllv +dSBtYXkgY2hhcmdlIGEgZmVlIGZvciB0aGUgcGh5c2ljYWwgYWN0IG9mIHRyYW5zZmVycmluZyBh +IGNvcHksIGFuZAp5b3UgbWF5IGF0IHlvdXIgb3B0aW9uIG9mZmVyIHdhcnJhbnR5IHByb3RlY3Rp +b24gaW4gZXhjaGFuZ2UgZm9yIGEgZmVlLgoKICAyLiBZb3UgbWF5IG1vZGlmeSB5b3VyIGNvcHkg +b3IgY29waWVzIG9mIHRoZSBQcm9ncmFtIG9yIGFueSBwb3J0aW9uCm9mIGl0LCB0aHVzIGZvcm1p +bmcgYSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtLCBhbmQgY29weSBhbmQKZGlzdHJpYnV0ZSBz +dWNoIG1vZGlmaWNhdGlvbnMgb3Igd29yayB1bmRlciB0aGUgdGVybXMgb2YgU2VjdGlvbiAxCmFi +b3ZlLCBwcm92aWRlZCB0aGF0IHlvdSBhbHNvIG1lZXQgYWxsIG9mIHRoZXNlIGNvbmRpdGlvbnM6 +CgogICAgYSkgWW91IG11c3QgY2F1c2UgdGhlIG1vZGlmaWVkIGZpbGVzIHRvIGNhcnJ5IHByb21p +bmVudCBub3RpY2VzCiAgICBzdGF0aW5nIHRoYXQgeW91IGNoYW5nZWQgdGhlIGZpbGVzIGFuZCB0 +aGUgZGF0ZSBvZiBhbnkgY2hhbmdlLgoKICAgIGIpIFlvdSBtdXN0IGNhdXNlIGFueSB3b3JrIHRo +YXQgeW91IGRpc3RyaWJ1dGUgb3IgcHVibGlzaCwgdGhhdCBpbgogICAgd2hvbGUgb3IgaW4gcGFy +dCBjb250YWlucyBvciBpcyBkZXJpdmVkIGZyb20gdGhlIFByb2dyYW0gb3IgYW55CiAgICBwYXJ0 +IHRoZXJlb2YsIHRvIGJlIGxpY2Vuc2VkIGFzIGEgd2hvbGUgYXQgbm8gY2hhcmdlIHRvIGFsbCB0 +aGlyZAogICAgcGFydGllcyB1bmRlciB0aGUgdGVybXMgb2YgdGhpcyBMaWNlbnNlLgoKICAgIGMp +IElmIHRoZSBtb2RpZmllZCBwcm9ncmFtIG5vcm1hbGx5IHJlYWRzIGNvbW1hbmRzIGludGVyYWN0 +aXZlbHkKICAgIHdoZW4gcnVuLCB5b3UgbXVzdCBjYXVzZSBpdCwgd2hlbiBzdGFydGVkIHJ1bm5p +bmcgZm9yIHN1Y2gKICAgIGludGVyYWN0aXZlIHVzZSBpbiB0aGUgbW9zdCBvcmRpbmFyeSB3YXks +IHRvIHByaW50IG9yIGRpc3BsYXkgYW4KICAgIGFubm91bmNlbWVudCBpbmNsdWRpbmcgYW4gYXBw +cm9wcmlhdGUgY29weXJpZ2h0IG5vdGljZSBhbmQgYQogICAgbm90aWNlIHRoYXQgdGhlcmUgaXMg +bm8gd2FycmFudHkgKG9yIGVsc2UsIHNheWluZyB0aGF0IHlvdSBwcm92aWRlCiAgICBhIHdhcnJh +bnR5KSBhbmQgdGhhdCB1c2VycyBtYXkgcmVkaXN0cmlidXRlIHRoZSBwcm9ncmFtIHVuZGVyCiAg +ICB0aGVzZSBjb25kaXRpb25zLCBhbmQgdGVsbGluZyB0aGUgdXNlciBob3cgdG8gdmlldyBhIGNv +cHkgb2YgdGhpcwogICAgTGljZW5zZS4gIChFeGNlcHRpb246IGlmIHRoZSBQcm9ncmFtIGl0c2Vs +ZiBpcyBpbnRlcmFjdGl2ZSBidXQKICAgIGRvZXMgbm90IG5vcm1hbGx5IHByaW50IHN1Y2ggYW4g +YW5ub3VuY2VtZW50LCB5b3VyIHdvcmsgYmFzZWQgb24KICAgIHRoZSBQcm9ncmFtIGlzIG5vdCBy +ZXF1aXJlZCB0byBwcmludCBhbiBhbm5vdW5jZW1lbnQuKQoKVGhlc2UgcmVxdWlyZW1lbnRzIGFw +cGx5IHRvIHRoZSBtb2RpZmllZCB3b3JrIGFzIGEgd2hvbGUuICBJZgppZGVudGlmaWFibGUgc2Vj +dGlvbnMgb2YgdGhhdCB3b3JrIGFyZSBub3QgZGVyaXZlZCBmcm9tIHRoZSBQcm9ncmFtLAphbmQg +Y2FuIGJlIHJlYXNvbmFibHkgY29uc2lkZXJlZCBpbmRlcGVuZGVudCBhbmQgc2VwYXJhdGUgd29y +a3MgaW4KdGhlbXNlbHZlcywgdGhlbiB0aGlzIExpY2Vuc2UsIGFuZCBpdHMgdGVybXMsIGRvIG5v +dCBhcHBseSB0byB0aG9zZQpzZWN0aW9ucyB3aGVuIHlvdSBkaXN0cmlidXRlIHRoZW0gYXMgc2Vw +YXJhdGUgd29ya3MuICBCdXQgd2hlbiB5b3UKZGlzdHJpYnV0ZSB0aGUgc2FtZSBzZWN0aW9ucyBh +cyBwYXJ0IG9mIGEgd2hvbGUgd2hpY2ggaXMgYSB3b3JrIGJhc2VkCm9uIHRoZSBQcm9ncmFtLCB0 +aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB3aG9sZSBtdXN0IGJlIG9uIHRoZSB0ZXJtcyBvZgp0aGlz +IExpY2Vuc2UsIHdob3NlIHBlcm1pc3Npb25zIGZvciBvdGhlciBsaWNlbnNlZXMgZXh0ZW5kIHRv +IHRoZQplbnRpcmUgd2hvbGUsIGFuZCB0aHVzIHRvIGVhY2ggYW5kIGV2ZXJ5IHBhcnQgcmVnYXJk +bGVzcyBvZiB3aG8gd3JvdGUgaXQuCgpUaHVzLCBpdCBpcyBub3QgdGhlIGludGVudCBvZiB0aGlz +IHNlY3Rpb24gdG8gY2xhaW0gcmlnaHRzIG9yIGNvbnRlc3QKeW91ciByaWdodHMgdG8gd29yayB3 +cml0dGVuIGVudGlyZWx5IGJ5IHlvdTsgcmF0aGVyLCB0aGUgaW50ZW50IGlzIHRvCmV4ZXJjaXNl +IHRoZSByaWdodCB0byBjb250cm9sIHRoZSBkaXN0cmlidXRpb24gb2YgZGVyaXZhdGl2ZSBvcgpj +b2xsZWN0aXZlIHdvcmtzIGJhc2VkIG9uIHRoZSBQcm9ncmFtLgoKSW4gYWRkaXRpb24sIG1lcmUg +YWdncmVnYXRpb24gb2YgYW5vdGhlciB3b3JrIG5vdCBiYXNlZCBvbiB0aGUgUHJvZ3JhbQp3aXRo +IHRoZSBQcm9ncmFtIChvciB3aXRoIGEgd29yayBiYXNlZCBvbiB0aGUgUHJvZ3JhbSkgb24gYSB2 +b2x1bWUgb2YKYSBzdG9yYWdlIG9yIGRpc3RyaWJ1dGlvbiBtZWRpdW0gZG9lcyBub3QgYnJpbmcg +dGhlIG90aGVyIHdvcmsgdW5kZXIKdGhlIHNjb3BlIG9mIHRoaXMgTGljZW5zZS4KCiAgMy4gWW91 +IG1heSBjb3B5IGFuZCBkaXN0cmlidXRlIHRoZSBQcm9ncmFtIChvciBhIHdvcmsgYmFzZWQgb24g +aXQsCnVuZGVyIFNlY3Rpb24gMikgaW4gb2JqZWN0IGNvZGUgb3IgZXhlY3V0YWJsZSBmb3JtIHVu +ZGVyIHRoZSB0ZXJtcyBvZgpTZWN0aW9ucyAxIGFuZCAyIGFib3ZlIHByb3ZpZGVkIHRoYXQgeW91 +IGFsc28gZG8gb25lIG9mIHRoZSBmb2xsb3dpbmc6CgogICAgYSkgQWNjb21wYW55IGl0IHdpdGgg +dGhlIGNvbXBsZXRlIGNvcnJlc3BvbmRpbmcgbWFjaGluZS1yZWFkYWJsZQogICAgc291cmNlIGNv +ZGUsIHdoaWNoIG11c3QgYmUgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIHRlcm1zIG9mIFNlY3Rpb25z +CiAgICAxIGFuZCAyIGFib3ZlIG9uIGEgbWVkaXVtIGN1c3RvbWFyaWx5IHVzZWQgZm9yIHNvZnR3 +YXJlIGludGVyY2hhbmdlOyBvciwKCiAgICBiKSBBY2NvbXBhbnkgaXQgd2l0aCBhIHdyaXR0ZW4g +b2ZmZXIsIHZhbGlkIGZvciBhdCBsZWFzdCB0aHJlZQogICAgeWVhcnMsIHRvIGdpdmUgYW55IHRo +aXJkIHBhcnR5LCBmb3IgYSBjaGFyZ2Ugbm8gbW9yZSB0aGFuIHlvdXIKICAgIGNvc3Qgb2YgcGh5 +c2ljYWxseSBwZXJmb3JtaW5nIHNvdXJjZSBkaXN0cmlidXRpb24sIGEgY29tcGxldGUKICAgIG1h +Y2hpbmUtcmVhZGFibGUgY29weSBvZiB0aGUgY29ycmVzcG9uZGluZyBzb3VyY2UgY29kZSwgdG8g +YmUKICAgIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiBTZWN0aW9ucyAxIGFuZCAyIGFi +b3ZlIG9uIGEgbWVkaXVtCiAgICBjdXN0b21hcmlseSB1c2VkIGZvciBzb2Z0d2FyZSBpbnRlcmNo +YW5nZTsgb3IsCgogICAgYykgQWNjb21wYW55IGl0IHdpdGggdGhlIGluZm9ybWF0aW9uIHlvdSBy +ZWNlaXZlZCBhcyB0byB0aGUgb2ZmZXIKICAgIHRvIGRpc3RyaWJ1dGUgY29ycmVzcG9uZGluZyBz +b3VyY2UgY29kZS4gIChUaGlzIGFsdGVybmF0aXZlIGlzCiAgICBhbGxvd2VkIG9ubHkgZm9yIG5v +bmNvbW1lcmNpYWwgZGlzdHJpYnV0aW9uIGFuZCBvbmx5IGlmIHlvdQogICAgcmVjZWl2ZWQgdGhl +IHByb2dyYW0gaW4gb2JqZWN0IGNvZGUgb3IgZXhlY3V0YWJsZSBmb3JtIHdpdGggc3VjaAogICAg +YW4gb2ZmZXIsIGluIGFjY29yZCB3aXRoIFN1YnNlY3Rpb24gYiBhYm92ZS4pCgpUaGUgc291cmNl +IGNvZGUgZm9yIGEgd29yayBtZWFucyB0aGUgcHJlZmVycmVkIGZvcm0gb2YgdGhlIHdvcmsgZm9y +Cm1ha2luZyBtb2RpZmljYXRpb25zIHRvIGl0LiAgRm9yIGFuIGV4ZWN1dGFibGUgd29yaywgY29t +cGxldGUgc291cmNlCmNvZGUgbWVhbnMgYWxsIHRoZSBzb3VyY2UgY29kZSBmb3IgYWxsIG1vZHVs +ZXMgaXQgY29udGFpbnMsIHBsdXMgYW55CmFzc29jaWF0ZWQgaW50ZXJmYWNlIGRlZmluaXRpb24g +ZmlsZXMsIHBsdXMgdGhlIHNjcmlwdHMgdXNlZCB0bwpjb250cm9sIGNvbXBpbGF0aW9uIGFuZCBp +bnN0YWxsYXRpb24gb2YgdGhlIGV4ZWN1dGFibGUuICBIb3dldmVyLCBhcyBhCnNwZWNpYWwgZXhj +ZXB0aW9uLCB0aGUgc291cmNlIGNvZGUgZGlzdHJpYnV0ZWQgbmVlZCBub3QgaW5jbHVkZQphbnl0 +aGluZyB0aGF0IGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIChpbiBlaXRoZXIgc291cmNlIG9yIGJp +bmFyeQpmb3JtKSB3aXRoIHRoZSBtYWpvciBjb21wb25lbnRzIChjb21waWxlciwga2VybmVsLCBh +bmQgc28gb24pIG9mIHRoZQpvcGVyYXRpbmcgc3lzdGVtIG9uIHdoaWNoIHRoZSBleGVjdXRhYmxl +IHJ1bnMsIHVubGVzcyB0aGF0IGNvbXBvbmVudAppdHNlbGYgYWNjb21wYW5pZXMgdGhlIGV4ZWN1 +dGFibGUuCgpJZiBkaXN0cmlidXRpb24gb2YgZXhlY3V0YWJsZSBvciBvYmplY3QgY29kZSBpcyBt +YWRlIGJ5IG9mZmVyaW5nCmFjY2VzcyB0byBjb3B5IGZyb20gYSBkZXNpZ25hdGVkIHBsYWNlLCB0 +aGVuIG9mZmVyaW5nIGVxdWl2YWxlbnQKYWNjZXNzIHRvIGNvcHkgdGhlIHNvdXJjZSBjb2RlIGZy +b20gdGhlIHNhbWUgcGxhY2UgY291bnRzIGFzCmRpc3RyaWJ1dGlvbiBvZiB0aGUgc291cmNlIGNv +ZGUsIGV2ZW4gdGhvdWdoIHRoaXJkIHBhcnRpZXMgYXJlIG5vdApjb21wZWxsZWQgdG8gY29weSB0 +aGUgc291cmNlIGFsb25nIHdpdGggdGhlIG9iamVjdCBjb2RlLgoKICA0LiBZb3UgbWF5IG5vdCBj +b3B5LCBtb2RpZnksIHN1YmxpY2Vuc2UsIG9yIGRpc3RyaWJ1dGUgdGhlIFByb2dyYW0KZXhjZXB0 +IGFzIGV4cHJlc3NseSBwcm92aWRlZCB1bmRlciB0aGlzIExpY2Vuc2UuICBBbnkgYXR0ZW1wdApv +dGhlcndpc2UgdG8gY29weSwgbW9kaWZ5LCBzdWJsaWNlbnNlIG9yIGRpc3RyaWJ1dGUgdGhlIFBy +b2dyYW0gaXMKdm9pZCwgYW5kIHdpbGwgYXV0b21hdGljYWxseSB0ZXJtaW5hdGUgeW91ciByaWdo +dHMgdW5kZXIgdGhpcyBMaWNlbnNlLgpIb3dldmVyLCBwYXJ0aWVzIHdobyBoYXZlIHJlY2VpdmVk +IGNvcGllcywgb3IgcmlnaHRzLCBmcm9tIHlvdSB1bmRlcgp0aGlzIExpY2Vuc2Ugd2lsbCBub3Qg +aGF2ZSB0aGVpciBsaWNlbnNlcyB0ZXJtaW5hdGVkIHNvIGxvbmcgYXMgc3VjaApwYXJ0aWVzIHJl +bWFpbiBpbiBmdWxsIGNvbXBsaWFuY2UuCgogIDUuIFlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIGFj +Y2VwdCB0aGlzIExpY2Vuc2UsIHNpbmNlIHlvdSBoYXZlIG5vdApzaWduZWQgaXQuICBIb3dldmVy +LCBub3RoaW5nIGVsc2UgZ3JhbnRzIHlvdSBwZXJtaXNzaW9uIHRvIG1vZGlmeSBvcgpkaXN0cmli +dXRlIHRoZSBQcm9ncmFtIG9yIGl0cyBkZXJpdmF0aXZlIHdvcmtzLiAgVGhlc2UgYWN0aW9ucyBh +cmUKcHJvaGliaXRlZCBieSBsYXcgaWYgeW91IGRvIG5vdCBhY2NlcHQgdGhpcyBMaWNlbnNlLiAg +VGhlcmVmb3JlLCBieQptb2RpZnlpbmcgb3IgZGlzdHJpYnV0aW5nIHRoZSBQcm9ncmFtIChvciBh +bnkgd29yayBiYXNlZCBvbiB0aGUKUHJvZ3JhbSksIHlvdSBpbmRpY2F0ZSB5b3VyIGFjY2VwdGFu +Y2Ugb2YgdGhpcyBMaWNlbnNlIHRvIGRvIHNvLCBhbmQKYWxsIGl0cyB0ZXJtcyBhbmQgY29uZGl0 +aW9ucyBmb3IgY29weWluZywgZGlzdHJpYnV0aW5nIG9yIG1vZGlmeWluZwp0aGUgUHJvZ3JhbSBv +ciB3b3JrcyBiYXNlZCBvbiBpdC4KCiAgNi4gRWFjaCB0aW1lIHlvdSByZWRpc3RyaWJ1dGUgdGhl +IFByb2dyYW0gKG9yIGFueSB3b3JrIGJhc2VkIG9uIHRoZQpQcm9ncmFtKSwgdGhlIHJlY2lwaWVu +dCBhdXRvbWF0aWNhbGx5IHJlY2VpdmVzIGEgbGljZW5zZSBmcm9tIHRoZQpvcmlnaW5hbCBsaWNl +bnNvciB0byBjb3B5LCBkaXN0cmlidXRlIG9yIG1vZGlmeSB0aGUgUHJvZ3JhbSBzdWJqZWN0IHRv +CnRoZXNlIHRlcm1zIGFuZCBjb25kaXRpb25zLiAgWW91IG1heSBub3QgaW1wb3NlIGFueSBmdXJ0 +aGVyCnJlc3RyaWN0aW9ucyBvbiB0aGUgcmVjaXBpZW50cycgZXhlcmNpc2Ugb2YgdGhlIHJpZ2h0 +cyBncmFudGVkIGhlcmVpbi4KWW91IGFyZSBub3QgcmVzcG9uc2libGUgZm9yIGVuZm9yY2luZyBj +b21wbGlhbmNlIGJ5IHRoaXJkIHBhcnRpZXMgdG8KdGhpcyBMaWNlbnNlLgoKICA3LiBJZiwgYXMg +YSBjb25zZXF1ZW5jZSBvZiBhIGNvdXJ0IGp1ZGdtZW50IG9yIGFsbGVnYXRpb24gb2YgcGF0ZW50 +CmluZnJpbmdlbWVudCBvciBmb3IgYW55IG90aGVyIHJlYXNvbiAobm90IGxpbWl0ZWQgdG8gcGF0 +ZW50IGlzc3VlcyksCmNvbmRpdGlvbnMgYXJlIGltcG9zZWQgb24geW91ICh3aGV0aGVyIGJ5IGNv +dXJ0IG9yZGVyLCBhZ3JlZW1lbnQgb3IKb3RoZXJ3aXNlKSB0aGF0IGNvbnRyYWRpY3QgdGhlIGNv +bmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLCB0aGV5IGRvIG5vdApleGN1c2UgeW91IGZyb20gdGhl +IGNvbmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLiAgSWYgeW91IGNhbm5vdApkaXN0cmlidXRlIHNv +IGFzIHRvIHNhdGlzZnkgc2ltdWx0YW5lb3VzbHkgeW91ciBvYmxpZ2F0aW9ucyB1bmRlciB0aGlz +CkxpY2Vuc2UgYW5kIGFueSBvdGhlciBwZXJ0aW5lbnQgb2JsaWdhdGlvbnMsIHRoZW4gYXMgYSBj +b25zZXF1ZW5jZSB5b3UKbWF5IG5vdCBkaXN0cmlidXRlIHRoZSBQcm9ncmFtIGF0IGFsbC4gIEZv +ciBleGFtcGxlLCBpZiBhIHBhdGVudApsaWNlbnNlIHdvdWxkIG5vdCBwZXJtaXQgcm95YWx0eS1m +cmVlIHJlZGlzdHJpYnV0aW9uIG9mIHRoZSBQcm9ncmFtIGJ5CmFsbCB0aG9zZSB3aG8gcmVjZWl2 +ZSBjb3BpZXMgZGlyZWN0bHkgb3IgaW5kaXJlY3RseSB0aHJvdWdoIHlvdSwgdGhlbgp0aGUgb25s +eSB3YXkgeW91IGNvdWxkIHNhdGlzZnkgYm90aCBpdCBhbmQgdGhpcyBMaWNlbnNlIHdvdWxkIGJl +IHRvCnJlZnJhaW4gZW50aXJlbHkgZnJvbSBkaXN0cmlidXRpb24gb2YgdGhlIFByb2dyYW0uCgpJ +ZiBhbnkgcG9ydGlvbiBvZiB0aGlzIHNlY3Rpb24gaXMgaGVsZCBpbnZhbGlkIG9yIHVuZW5mb3Jj +ZWFibGUgdW5kZXIKYW55IHBhcnRpY3VsYXIgY2lyY3Vtc3RhbmNlLCB0aGUgYmFsYW5jZSBvZiB0 +aGUgc2VjdGlvbiBpcyBpbnRlbmRlZCB0bwphcHBseSBhbmQgdGhlIHNlY3Rpb24gYXMgYSB3aG9s +ZSBpcyBpbnRlbmRlZCB0byBhcHBseSBpbiBvdGhlcgpjaXJjdW1zdGFuY2VzLgoKSXQgaXMgbm90 +IHRoZSBwdXJwb3NlIG9mIHRoaXMgc2VjdGlvbiB0byBpbmR1Y2UgeW91IHRvIGluZnJpbmdlIGFu +eQpwYXRlbnRzIG9yIG90aGVyIHByb3BlcnR5IHJpZ2h0IGNsYWltcyBvciB0byBjb250ZXN0IHZh +bGlkaXR5IG9mIGFueQpzdWNoIGNsYWltczsgdGhpcyBzZWN0aW9uIGhhcyB0aGUgc29sZSBwdXJw +b3NlIG9mIHByb3RlY3RpbmcgdGhlCmludGVncml0eSBvZiB0aGUgZnJlZSBzb2Z0d2FyZSBkaXN0 +cmlidXRpb24gc3lzdGVtLCB3aGljaCBpcwppbXBsZW1lbnRlZCBieSBwdWJsaWMgbGljZW5zZSBw +cmFjdGljZXMuICBNYW55IHBlb3BsZSBoYXZlIG1hZGUKZ2VuZXJvdXMgY29udHJpYnV0aW9ucyB0 +byB0aGUgd2lkZSByYW5nZSBvZiBzb2Z0d2FyZSBkaXN0cmlidXRlZAp0aHJvdWdoIHRoYXQgc3lz +dGVtIGluIHJlbGlhbmNlIG9uIGNvbnNpc3RlbnQgYXBwbGljYXRpb24gb2YgdGhhdApzeXN0ZW07 +IGl0IGlzIHVwIHRvIHRoZSBhdXRob3IvZG9ub3IgdG8gZGVjaWRlIGlmIGhlIG9yIHNoZSBpcyB3 +aWxsaW5nCnRvIGRpc3RyaWJ1dGUgc29mdHdhcmUgdGhyb3VnaCBhbnkgb3RoZXIgc3lzdGVtIGFu +ZCBhIGxpY2Vuc2VlIGNhbm5vdAppbXBvc2UgdGhhdCBjaG9pY2UuCgpUaGlzIHNlY3Rpb24gaXMg +aW50ZW5kZWQgdG8gbWFrZSB0aG9yb3VnaGx5IGNsZWFyIHdoYXQgaXMgYmVsaWV2ZWQgdG8KYmUg +YSBjb25zZXF1ZW5jZSBvZiB0aGUgcmVzdCBvZiB0aGlzIExpY2Vuc2UuCgogIDguIElmIHRoZSBk +aXN0cmlidXRpb24gYW5kL29yIHVzZSBvZiB0aGUgUHJvZ3JhbSBpcyByZXN0cmljdGVkIGluCmNl +cnRhaW4gY291bnRyaWVzIGVpdGhlciBieSBwYXRlbnRzIG9yIGJ5IGNvcHlyaWdodGVkIGludGVy +ZmFjZXMsIHRoZQpvcmlnaW5hbCBjb3B5cmlnaHQgaG9sZGVyIHdobyBwbGFjZXMgdGhlIFByb2dy +YW0gdW5kZXIgdGhpcyBMaWNlbnNlCm1heSBhZGQgYW4gZXhwbGljaXQgZ2VvZ3JhcGhpY2FsIGRp +c3RyaWJ1dGlvbiBsaW1pdGF0aW9uIGV4Y2x1ZGluZwp0aG9zZSBjb3VudHJpZXMsIHNvIHRoYXQg +ZGlzdHJpYnV0aW9uIGlzIHBlcm1pdHRlZCBvbmx5IGluIG9yIGFtb25nCmNvdW50cmllcyBub3Qg +dGh1cyBleGNsdWRlZC4gIEluIHN1Y2ggY2FzZSwgdGhpcyBMaWNlbnNlIGluY29ycG9yYXRlcwp0 +aGUgbGltaXRhdGlvbiBhcyBpZiB3cml0dGVuIGluIHRoZSBib2R5IG9mIHRoaXMgTGljZW5zZS4K +CiAgOS4gVGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiBtYXkgcHVibGlzaCByZXZpc2VkIGFu +ZC9vciBuZXcgdmVyc2lvbnMKb2YgdGhlIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZnJvbSB0aW1l +IHRvIHRpbWUuICBTdWNoIG5ldyB2ZXJzaW9ucyB3aWxsCmJlIHNpbWlsYXIgaW4gc3Bpcml0IHRv +IHRoZSBwcmVzZW50IHZlcnNpb24sIGJ1dCBtYXkgZGlmZmVyIGluIGRldGFpbCB0bwphZGRyZXNz +IG5ldyBwcm9ibGVtcyBvciBjb25jZXJucy4KCkVhY2ggdmVyc2lvbiBpcyBnaXZlbiBhIGRpc3Rp +bmd1aXNoaW5nIHZlcnNpb24gbnVtYmVyLiAgSWYgdGhlIFByb2dyYW0Kc3BlY2lmaWVzIGEgdmVy +c2lvbiBudW1iZXIgb2YgdGhpcyBMaWNlbnNlIHdoaWNoIGFwcGxpZXMgdG8gaXQgYW5kICJhbnkK +bGF0ZXIgdmVyc2lvbiIsIHlvdSBoYXZlIHRoZSBvcHRpb24gb2YgZm9sbG93aW5nIHRoZSB0ZXJt +cyBhbmQgY29uZGl0aW9ucwplaXRoZXIgb2YgdGhhdCB2ZXJzaW9uIG9yIG9mIGFueSBsYXRlciB2 +ZXJzaW9uIHB1Ymxpc2hlZCBieSB0aGUgRnJlZQpTb2Z0d2FyZSBGb3VuZGF0aW9uLiAgSWYgdGhl +IFByb2dyYW0gZG9lcyBub3Qgc3BlY2lmeSBhIHZlcnNpb24gbnVtYmVyIG9mCnRoaXMgTGljZW5z +ZSwgeW91IG1heSBjaG9vc2UgYW55IHZlcnNpb24gZXZlciBwdWJsaXNoZWQgYnkgdGhlIEZyZWUg +U29mdHdhcmUKRm91bmRhdGlvbi4KCiAgMTAuIElmIHlvdSB3aXNoIHRvIGluY29ycG9yYXRlIHBh +cnRzIG9mIHRoZSBQcm9ncmFtIGludG8gb3RoZXIgZnJlZQpwcm9ncmFtcyB3aG9zZSBkaXN0cmli +dXRpb24gY29uZGl0aW9ucyBhcmUgZGlmZmVyZW50LCB3cml0ZSB0byB0aGUgYXV0aG9yCnRvIGFz +ayBmb3IgcGVybWlzc2lvbi4gIEZvciBzb2Z0d2FyZSB3aGljaCBpcyBjb3B5cmlnaHRlZCBieSB0 +aGUgRnJlZQpTb2Z0d2FyZSBGb3VuZGF0aW9uLCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZSBG +b3VuZGF0aW9uOyB3ZSBzb21ldGltZXMKbWFrZSBleGNlcHRpb25zIGZvciB0aGlzLiAgT3VyIGRl +Y2lzaW9uIHdpbGwgYmUgZ3VpZGVkIGJ5IHRoZSB0d28gZ29hbHMKb2YgcHJlc2VydmluZyB0aGUg +ZnJlZSBzdGF0dXMgb2YgYWxsIGRlcml2YXRpdmVzIG9mIG91ciBmcmVlIHNvZnR3YXJlIGFuZApv +ZiBwcm9tb3RpbmcgdGhlIHNoYXJpbmcgYW5kIHJldXNlIG9mIHNvZnR3YXJlIGdlbmVyYWxseS4K +CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBOTyBXQVJSQU5UWQoKICAxMS4gQkVDQVVTRSBU +SEUgUFJPR1JBTSBJUyBMSUNFTlNFRCBGUkVFIE9GIENIQVJHRSwgVEhFUkUgSVMgTk8gV0FSUkFO +VFkKRk9SIFRIRSBQUk9HUkFNLCBUTyBUSEUgRVhURU5UIFBFUk1JVFRFRCBCWSBBUFBMSUNBQkxF +IExBVy4gIEVYQ0VQVCBXSEVOCk9USEVSV0lTRSBTVEFURUQgSU4gV1JJVElORyBUSEUgQ09QWVJJ +R0hUIEhPTERFUlMgQU5EL09SIE9USEVSIFBBUlRJRVMKUFJPVklERSBUSEUgUFJPR1JBTSAiQVMg +SVMiIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVJVEhFUiBFWFBSRVNTRUQKT1IgSU1Q +TElFRCwgSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJ +RVMgT0YKTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9T +RS4gIFRIRSBFTlRJUkUgUklTSyBBUwpUTyBUSEUgUVVBTElUWSBBTkQgUEVSRk9STUFOQ0UgT0Yg +VEhFIFBST0dSQU0gSVMgV0lUSCBZT1UuICBTSE9VTEQgVEhFClBST0dSQU0gUFJPVkUgREVGRUNU +SVZFLCBZT1UgQVNTVU1FIFRIRSBDT1NUIE9GIEFMTCBORUNFU1NBUlkgU0VSVklDSU5HLApSRVBB +SVIgT1IgQ09SUkVDVElPTi4KCiAgMTIuIElOIE5PIEVWRU5UIFVOTEVTUyBSRVFVSVJFRCBCWSBB +UFBMSUNBQkxFIExBVyBPUiBBR1JFRUQgVE8gSU4gV1JJVElORwpXSUxMIEFOWSBDT1BZUklHSFQg +SE9MREVSLCBPUiBBTlkgT1RIRVIgUEFSVFkgV0hPIE1BWSBNT0RJRlkgQU5EL09SClJFRElTVFJJ +QlVURSBUSEUgUFJPR1JBTSBBUyBQRVJNSVRURUQgQUJPVkUsIEJFIExJQUJMRSBUTyBZT1UgRk9S +IERBTUFHRVMsCklOQ0xVRElORyBBTlkgR0VORVJBTCwgU1BFQ0lBTCwgSU5DSURFTlRBTCBPUiBD +T05TRVFVRU5USUFMIERBTUFHRVMgQVJJU0lORwpPVVQgT0YgVEhFIFVTRSBPUiBJTkFCSUxJVFkg +VE8gVVNFIFRIRSBQUk9HUkFNIChJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIExPU1MgT0Yg +REFUQSBPUiBEQVRBIEJFSU5HIFJFTkRFUkVEIElOQUNDVVJBVEUgT1IgTE9TU0VTIFNVU1RBSU5F +RCBCWQpZT1UgT1IgVEhJUkQgUEFSVElFUyBPUiBBIEZBSUxVUkUgT0YgVEhFIFBST0dSQU0gVE8g +T1BFUkFURSBXSVRIIEFOWSBPVEhFUgpQUk9HUkFNUyksIEVWRU4gSUYgU1VDSCBIT0xERVIgT1Ig +T1RIRVIgUEFSVFkgSEFTIEJFRU4gQURWSVNFRCBPRiBUSEUKUE9TU0lCSUxJVFkgT0YgU1VDSCBE +QU1BR0VTLgoKICAgICAgICAgICAgICAgICAgICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05T +CgogICAgICAgICAgICBIb3cgdG8gQXBwbHkgVGhlc2UgVGVybXMgdG8gWW91ciBOZXcgUHJvZ3Jh +bXMKCiAgSWYgeW91IGRldmVsb3AgYSBuZXcgcHJvZ3JhbSwgYW5kIHlvdSB3YW50IGl0IHRvIGJl +IG9mIHRoZSBncmVhdGVzdApwb3NzaWJsZSB1c2UgdG8gdGhlIHB1YmxpYywgdGhlIGJlc3Qgd2F5 +IHRvIGFjaGlldmUgdGhpcyBpcyB0byBtYWtlIGl0CmZyZWUgc29mdHdhcmUgd2hpY2ggZXZlcnlv +bmUgY2FuIHJlZGlzdHJpYnV0ZSBhbmQgY2hhbmdlIHVuZGVyIHRoZXNlIHRlcm1zLgoKICBUbyBk +byBzbywgYXR0YWNoIHRoZSBmb2xsb3dpbmcgbm90aWNlcyB0byB0aGUgcHJvZ3JhbS4gIEl0IGlz +IHNhZmVzdAp0byBhdHRhY2ggdGhlbSB0byB0aGUgc3RhcnQgb2YgZWFjaCBzb3VyY2UgZmlsZSB0 +byBtb3N0IGVmZmVjdGl2ZWx5CmNvbnZleSB0aGUgZXhjbHVzaW9uIG9mIHdhcnJhbnR5OyBhbmQg +ZWFjaCBmaWxlIHNob3VsZCBoYXZlIGF0IGxlYXN0CnRoZSAiY29weXJpZ2h0IiBsaW5lIGFuZCBh +IHBvaW50ZXIgdG8gd2hlcmUgdGhlIGZ1bGwgbm90aWNlIGlzIGZvdW5kLgoKICAgIDxvbmUgbGlu +ZSB0byBnaXZlIHRoZSBwcm9ncmFtJ3MgbmFtZSBhbmQgYSBicmllZiBpZGVhIG9mIHdoYXQgaXQg +ZG9lcy4+CiAgICBDb3B5cmlnaHQgKEMpIDx5ZWFyPiAgPG5hbWUgb2YgYXV0aG9yPgoKICAgIFRo +aXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQv +b3IgbW9kaWZ5CiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1Ymxp +YyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieQogICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlv +bjsgZWl0aGVyIHZlcnNpb24gMiBvZiB0aGUgTGljZW5zZSwgb3IKICAgIChhdCB5b3VyIG9wdGlv +bikgYW55IGxhdGVyIHZlcnNpb24uCgogICAgVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGlu +IHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCiAgICBidXQgV0lUSE9VVCBBTlkgV0FS +UkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgogICAgTUVSQ0hBTlRB +QklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQogICAg +R05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KCiAgICBZb3Ugc2hv +dWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5z +ZSBhbG9uZwogICAgd2l0aCB0aGlzIHByb2dyYW07IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUg +U29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiwKICAgIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGgg +Rmxvb3IsIEJvc3RvbiwgTUEgMDIxMTAtMTMwMSBVU0EuCgpBbHNvIGFkZCBpbmZvcm1hdGlvbiBv +biBob3cgdG8gY29udGFjdCB5b3UgYnkgZWxlY3Ryb25pYyBhbmQgcGFwZXIgbWFpbC4KCklmIHRo +ZSBwcm9ncmFtIGlzIGludGVyYWN0aXZlLCBtYWtlIGl0IG91dHB1dCBhIHNob3J0IG5vdGljZSBs +aWtlIHRoaXMKd2hlbiBpdCBzdGFydHMgaW4gYW4gaW50ZXJhY3RpdmUgbW9kZToKCiAgICBHbm9t +b3Zpc2lvbiB2ZXJzaW9uIDY5LCBDb3B5cmlnaHQgKEMpIHllYXIgbmFtZSBvZiBhdXRob3IKICAg +IEdub21vdmlzaW9uIGNvbWVzIHdpdGggQUJTT0xVVEVMWSBOTyBXQVJSQU5UWTsgZm9yIGRldGFp +bHMgdHlwZSBgc2hvdyB3Jy4KICAgIFRoaXMgaXMgZnJlZSBzb2Z0d2FyZSwgYW5kIHlvdSBhcmUg +d2VsY29tZSB0byByZWRpc3RyaWJ1dGUgaXQKICAgIHVuZGVyIGNlcnRhaW4gY29uZGl0aW9uczsg +dHlwZSBgc2hvdyBjJyBmb3IgZGV0YWlscy4KClRoZSBoeXBvdGhldGljYWwgY29tbWFuZHMgYHNo +b3cgdycgYW5kIGBzaG93IGMnIHNob3VsZCBzaG93IHRoZSBhcHByb3ByaWF0ZQpwYXJ0cyBvZiB0 +aGUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZS4gIE9mIGNvdXJzZSwgdGhlIGNvbW1hbmRzIHlvdSB1 +c2UgbWF5CmJlIGNhbGxlZCBzb21ldGhpbmcgb3RoZXIgdGhhbiBgc2hvdyB3JyBhbmQgYHNob3cg +Yyc7IHRoZXkgY291bGQgZXZlbiBiZQptb3VzZS1jbGlja3Mgb3IgbWVudSBpdGVtcy0td2hhdGV2 +ZXIgc3VpdHMgeW91ciBwcm9ncmFtLgoKWW91IHNob3VsZCBhbHNvIGdldCB5b3VyIGVtcGxveWVy +IChpZiB5b3Ugd29yayBhcyBhIHByb2dyYW1tZXIpIG9yIHlvdXIKc2Nob29sLCBpZiBhbnksIHRv +IHNpZ24gYSAiY29weXJpZ2h0IGRpc2NsYWltZXIiIGZvciB0aGUgcHJvZ3JhbSwgaWYKbmVjZXNz +YXJ5LiAgSGVyZSBpcyBhIHNhbXBsZTsgYWx0ZXIgdGhlIG5hbWVzOgoKICBZb3lvZHluZSwgSW5j +LiwgaGVyZWJ5IGRpc2NsYWltcyBhbGwgY29weXJpZ2h0IGludGVyZXN0IGluIHRoZSBwcm9ncmFt +CiAgYEdub21vdmlzaW9uJyAod2hpY2ggbWFrZXMgcGFzc2VzIGF0IGNvbXBpbGVycykgd3JpdHRl +biBieSBKYW1lcyBIYWNrZXIuCgogIDxzaWduYXR1cmUgb2YgVHkgQ29vbj4sIDEgQXByaWwgMTk4 +OQogIFR5IENvb24sIFByZXNpZGVudCBvZiBWaWNlCgpUaGlzIEdlbmVyYWwgUHVibGljIExpY2Vu +c2UgZG9lcyBub3QgcGVybWl0IGluY29ycG9yYXRpbmcgeW91ciBwcm9ncmFtIGludG8KcHJvcHJp +ZXRhcnkgcHJvZ3JhbXMuICBJZiB5b3VyIHByb2dyYW0gaXMgYSBzdWJyb3V0aW5lIGxpYnJhcnks +IHlvdSBtYXkKY29uc2lkZXIgaXQgbW9yZSB1c2VmdWwgdG8gcGVybWl0IGxpbmtpbmcgcHJvcHJp +ZXRhcnkgYXBwbGljYXRpb25zIHdpdGggdGhlCmxpYnJhcnkuICBJZiB0aGlzIGlzIHdoYXQgeW91 +IHdhbnQgdG8gZG8sIHVzZSB0aGUgR05VIExlc3NlciBHZW5lcmFsClB1YmxpYyBMaWNlbnNlIGlu +c3RlYWQgb2YgdGhpcyBMaWNlbnNlLg== diff --git a/src/broker/dependency-licenses.json b/src/broker/dependency-licenses.json new file mode 100644 index 000000000..2aba460b2 --- /dev/null +++ b/src/broker/dependency-licenses.json @@ -0,0 +1,895 @@ +{ + "schema": "oliphaunt-broker-dependency-license-contract-v1", + "product": "oliphaunt-broker", + "cargoSource": "registry+https://github.com/rust-lang/crates.io-index", + "payloadLicense": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause", + "targets": { + "linux-x64-gnu": { + "cargoTarget": "x86_64-unknown-linux-gnu", + "packages": [ + "bitflags@2.12.1", + "block-buffer@0.10.4", + "cfg-if@1.0.4", + "cpufeatures@0.2.17", + "crypto-common@0.1.7", + "digest@0.10.7", + "filetime@0.2.29", + "fs2@0.4.3", + "generic-array@0.14.7", + "getrandom@0.3.4", + "itoa@1.0.18", + "libc@0.2.186", + "libloading@0.8.9", + "linux-raw-sys@0.12.1", + "memchr@2.8.1", + "proc-macro2@1.0.106", + "quote@1.0.45", + "rustix@1.1.4", + "serde@1.0.228", + "serde_core@1.0.228", + "serde_derive@1.0.228", + "serde_json@1.0.150", + "sha2@0.10.9", + "syn@2.0.117", + "tar@0.4.46", + "typenum@1.20.1", + "unicode-ident@1.0.24", + "xattr@1.6.1", + "zmij@1.0.21", + "zstd-safe@7.2.4", + "zstd-sys@2.0.16+zstd.1.5.7", + "zstd@0.13.3" + ] + }, + "linux-arm64-gnu": { + "cargoTarget": "aarch64-unknown-linux-gnu", + "packages": [ + "bitflags@2.12.1", + "block-buffer@0.10.4", + "cfg-if@1.0.4", + "cpufeatures@0.2.17", + "crypto-common@0.1.7", + "digest@0.10.7", + "filetime@0.2.29", + "fs2@0.4.3", + "generic-array@0.14.7", + "getrandom@0.3.4", + "itoa@1.0.18", + "libc@0.2.186", + "libloading@0.8.9", + "linux-raw-sys@0.12.1", + "memchr@2.8.1", + "proc-macro2@1.0.106", + "quote@1.0.45", + "rustix@1.1.4", + "serde@1.0.228", + "serde_core@1.0.228", + "serde_derive@1.0.228", + "serde_json@1.0.150", + "sha2@0.10.9", + "syn@2.0.117", + "tar@0.4.46", + "typenum@1.20.1", + "unicode-ident@1.0.24", + "xattr@1.6.1", + "zmij@1.0.21", + "zstd-safe@7.2.4", + "zstd-sys@2.0.16+zstd.1.5.7", + "zstd@0.13.3" + ] + }, + "macos-arm64": { + "cargoTarget": "aarch64-apple-darwin", + "packages": [ + "bitflags@2.12.1", + "block-buffer@0.10.4", + "cfg-if@1.0.4", + "cpufeatures@0.2.17", + "crypto-common@0.1.7", + "digest@0.10.7", + "errno@0.3.14", + "filetime@0.2.29", + "fs2@0.4.3", + "generic-array@0.14.7", + "getrandom@0.3.4", + "itoa@1.0.18", + "libc@0.2.186", + "libloading@0.8.9", + "memchr@2.8.1", + "proc-macro2@1.0.106", + "quote@1.0.45", + "rustix@1.1.4", + "serde@1.0.228", + "serde_core@1.0.228", + "serde_derive@1.0.228", + "serde_json@1.0.150", + "sha2@0.10.9", + "syn@2.0.117", + "tar@0.4.46", + "typenum@1.20.1", + "unicode-ident@1.0.24", + "xattr@1.6.1", + "zmij@1.0.21", + "zstd-safe@7.2.4", + "zstd-sys@2.0.16+zstd.1.5.7", + "zstd@0.13.3" + ] + }, + "windows-x64-msvc": { + "cargoTarget": "x86_64-pc-windows-msvc", + "packages": [ + "block-buffer@0.10.4", + "cfg-if@1.0.4", + "cpufeatures@0.2.17", + "crypto-common@0.1.7", + "digest@0.10.7", + "filetime@0.2.29", + "fs2@0.4.3", + "generic-array@0.14.7", + "getrandom@0.3.4", + "itoa@1.0.18", + "libloading@0.8.9", + "memchr@2.8.1", + "proc-macro2@1.0.106", + "quote@1.0.45", + "serde@1.0.228", + "serde_core@1.0.228", + "serde_derive@1.0.228", + "serde_json@1.0.150", + "sha2@0.10.9", + "syn@2.0.117", + "tar@0.4.46", + "typenum@1.20.1", + "unicode-ident@1.0.24", + "winapi@0.3.9", + "windows-link@0.2.1", + "zmij@1.0.21", + "zstd-safe@7.2.4", + "zstd-sys@2.0.16+zstd.1.5.7", + "zstd@0.13.3" + ] + } + }, + "packages": [ + { + "name": "bitflags", + "version": "2.12.1", + "checksum": "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2", + "bytes": 10847 + }, + { + "name": "LICENSE-MIT", + "sha256": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb", + "bytes": 1071 + } + ] + }, + { + "name": "block-buffer", + "version": "0.10.4", + "checksum": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5", + "bytes": 10849 + }, + { + "name": "LICENSE-MIT", + "sha256": "d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef", + "bytes": 1082 + } + ] + }, + { + "name": "cfg-if", + "version": "1.0.4", + "checksum": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2", + "bytes": 10847 + }, + { + "name": "LICENSE-MIT", + "sha256": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397", + "bytes": 1057 + } + ] + }, + { + "name": "cpufeatures", + "version": "0.2.17", + "checksum": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5", + "bytes": 10849 + }, + { + "name": "LICENSE-MIT", + "sha256": "ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985", + "bytes": 1082 + } + ] + }, + { + "name": "crypto-common", + "version": "0.1.7", + "checksum": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5", + "bytes": 10849 + }, + { + "name": "LICENSE-MIT", + "sha256": "3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897", + "bytes": 1065 + } + ] + }, + { + "name": "digest", + "version": "0.10.7", + "checksum": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5", + "bytes": 10849 + }, + { + "name": "LICENSE-MIT", + "sha256": "9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba", + "bytes": 1057 + } + ] + }, + { + "name": "errno", + "version": "0.3.14", + "checksum": "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["macos-arm64"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2", + "bytes": 10847 + }, + { + "name": "LICENSE-MIT", + "sha256": "8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2", + "bytes": 1054 + } + ] + }, + { + "name": "filetime", + "version": "0.2.29", + "checksum": "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759", + "declaredLicense": "MIT/Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2", + "bytes": 10847 + }, + { + "name": "LICENSE-MIT", + "sha256": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397", + "bytes": 1057 + } + ] + }, + { + "name": "fs2", + "version": "0.4.3", + "checksum": "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213", + "declaredLicense": "MIT/Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2", + "bytes": 10847 + }, + { + "name": "LICENSE-MIT", + "sha256": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0", + "bytes": 1071 + } + ] + }, + { + "name": "generic-array", + "version": "0.14.7", + "checksum": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a", + "declaredLicense": "MIT", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE", + "sha256": "c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583", + "bytes": 1107 + } + ] + }, + { + "name": "getrandom", + "version": "0.3.4", + "checksum": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf", + "bytes": 10849 + }, + { + "name": "LICENSE-MIT", + "sha256": "29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4", + "bytes": 1130 + } + ] + }, + { + "name": "itoa", + "version": "1.0.18", + "checksum": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "libc", + "version": "0.2.186", + "checksum": "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e", + "bytes": 1066 + } + ] + }, + { + "name": "libloading", + "version": "0.8.9", + "checksum": "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55", + "declaredLicense": "ISC", + "selectedLicense": "ISC", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE", + "sha256": "b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f", + "bytes": 736 + } + ] + }, + { + "name": "linux-raw-sys", + "version": "0.12.1", + "checksum": "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53", + "declaredLicense": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu"], + "licenseFiles": [ + { + "name": "COPYRIGHT", + "sha256": "3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b", + "bytes": 881 + }, + { + "name": "LICENSE-APACHE", + "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2", + "bytes": 10847 + }, + { + "name": "LICENSE-Apache-2.0_WITH_LLVM-exception", + "sha256": "268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5", + "bytes": 12243 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "memchr", + "version": "2.8.1", + "checksum": "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8", + "declaredLicense": "Unlicense OR MIT", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "COPYING", + "sha256": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f", + "bytes": 126 + }, + { + "name": "LICENSE-MIT", + "sha256": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f", + "bytes": 1081 + }, + { + "name": "UNLICENSE", + "sha256": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c", + "bytes": 1211 + } + ] + }, + { + "name": "proc-macro2", + "version": "1.0.106", + "checksum": "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "quote", + "version": "1.0.45", + "checksum": "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "rustix", + "version": "1.1.4", + "checksum": "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190", + "declaredLicense": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64"], + "licenseFiles": [ + { + "name": "COPYRIGHT", + "sha256": "377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9", + "bytes": 853 + }, + { + "name": "LICENSE-APACHE", + "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2", + "bytes": 10847 + }, + { + "name": "LICENSE-Apache-2.0_WITH_LLVM-exception", + "sha256": "268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5", + "bytes": 12243 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "serde", + "version": "1.0.228", + "checksum": "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "serde_core", + "version": "1.0.228", + "checksum": "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "serde_derive", + "version": "1.0.228", + "checksum": "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "serde_json", + "version": "1.0.150", + "checksum": "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "sha2", + "version": "0.10.9", + "checksum": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5", + "bytes": 10849 + }, + { + "name": "LICENSE-MIT", + "sha256": "b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1", + "bytes": 1138 + } + ] + }, + { + "name": "syn", + "version": "2.0.117", + "checksum": "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "tar", + "version": "0.4.46", + "checksum": "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2", + "bytes": 10847 + }, + { + "name": "LICENSE-MIT", + "sha256": "8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077", + "bytes": 1070 + } + ] + }, + { + "name": "typenum", + "version": "1.20.1", + "checksum": "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE", + "sha256": "db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a", + "bytes": 17 + }, + { + "name": "LICENSE-APACHE", + "sha256": "516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406", + "bytes": 10835 + }, + { + "name": "LICENSE-MIT", + "sha256": "a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f", + "bytes": 1083 + } + ] + }, + { + "name": "unicode-ident", + "version": "1.0.24", + "checksum": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75", + "declaredLicense": "(MIT OR Apache-2.0) AND Unicode-3.0", + "selectedLicense": "MIT AND Unicode-3.0", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a", + "bytes": 9723 + }, + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + }, + { + "name": "LICENSE-UNICODE", + "sha256": "f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1", + "bytes": 1995 + } + ] + }, + { + "name": "winapi", + "version": "0.3.9", + "checksum": "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419", + "declaredLicense": "MIT/Apache-2.0", + "selectedLicense": "MIT", + "targets": ["windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1", + "bytes": 11357 + }, + { + "name": "LICENSE-MIT", + "sha256": "ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b", + "bytes": 1073 + } + ] + }, + { + "name": "windows-link", + "version": "0.2.1", + "checksum": "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["windows-x64-msvc"], + "licenseFiles": [ + { + "name": "license-apache-2.0", + "sha256": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b", + "bytes": 11351 + }, + { + "name": "license-mit", + "sha256": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383", + "bytes": 1141 + } + ] + }, + { + "name": "xattr", + "version": "1.6.1", + "checksum": "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64"], + "licenseFiles": [ + { + "name": "LICENSE-APACHE", + "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2", + "bytes": 10847 + }, + { + "name": "LICENSE-MIT", + "sha256": "8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36", + "bytes": 1056 + } + ] + }, + { + "name": "zmij", + "version": "1.0.21", + "checksum": "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa", + "declaredLicense": "MIT", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE-MIT", + "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3", + "bytes": 1023 + } + ] + }, + { + "name": "zstd-safe", + "version": "7.2.4", + "checksum": "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d", + "declaredLicense": "MIT OR Apache-2.0", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE", + "sha256": "a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63", + "bytes": 18 + }, + { + "name": "LICENSE.Apache-2.0", + "sha256": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594", + "bytes": 10174 + }, + { + "name": "LICENSE.Mit", + "sha256": "129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8", + "bytes": 1080 + } + ] + }, + { + "name": "zstd-sys", + "version": "2.0.16+zstd.1.5.7", + "checksum": "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748", + "declaredLicense": "MIT/Apache-2.0", + "selectedLicense": "MIT AND BSD-3-Clause", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE", + "sha256": "a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63", + "bytes": 18 + }, + { + "name": "LICENSE.Apache-2.0", + "sha256": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594", + "bytes": 10174 + }, + { + "name": "LICENSE.BSD-3-Clause", + "sha256": "48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd", + "bytes": 1595 + }, + { + "name": "LICENSE.Mit", + "sha256": "129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8", + "bytes": 1080 + }, + { + "name": "zstd/COPYING", + "sha256": "f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505", + "bytes": 18091 + }, + { + "name": "zstd/LICENSE", + "sha256": "7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8", + "bytes": 1549 + } + ] + }, + { + "name": "zstd", + "version": "0.13.3", + "checksum": "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a", + "declaredLicense": "MIT", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE", + "sha256": "129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8", + "bytes": 1080 + } + ] + } + ] +} diff --git a/src/broker/moon.yml b/src/broker/moon.yml new file mode 100644 index 000000000..e6745a583 --- /dev/null +++ b/src/broker/moon.yml @@ -0,0 +1,262 @@ +$schema: "https://moonrepo.dev/schemas/project.json" + +id: "oliphaunt-broker" +language: "rust" +layer: "library" +stack: "systems" +tags: ["cargo-package", "javascript-quality", "runtime", "broker", "native", "postgres", "release-product"] +dependsOn: + - id: "oliphaunt-query" + scope: "build" + - id: "liboliphaunt-native-bindings" + scope: "build" + - "liboliphaunt-native" + +project: + title: "Oliphaunt Broker" + description: "Process-isolated broker helper runtime used by Rust and TypeScript SDKs." + owner: "oliphaunt" + release: + component: "oliphaunt-broker" + packagePath: "src/broker" + artifactTargets: + preset: "broker-helper" + targets: + - "linux-arm64-gnu" + - "linux-x64-gnu" + - "macos-arm64" + - "windows-x64-msvc" + +owners: + defaultOwner: "@oliphaunt/broker" + +fileGroups: + code: + - "**/*" + - "!**/*.md" + - "!moon.yml" + - "!release.toml" + - "!tools/*.test.mts" + - "!tools/create-release-fixture.mts" + +tasks: + test-consumer: + tags: [consumer, integration, ci-native-consumers, platform-linux-x64-gnu] + deps: [{target: "cargo-sources", cacheStrategy: hash}, "liboliphaunt-native:package-runtime-desktop-target", "build-release-assets"] + command: "bash src/broker/tools/test-consumer.sh" + inputs: + - "tests/postgres_client.rs" + - "tools/test-consumer.sh" + - "/Cargo.lock" + - "/Cargo.toml" + options: + cache: false + runFromWorkspaceRoot: true + test-integration: + deps: [{target: "cargo-sources", cacheStrategy: hash}, "liboliphaunt-native:build-runtime-desktop-target"] + script: | + set -eu + . src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh + oliphaunt_runtime_native_host_require basic + cargo test -p oliphaunt-broker --locked --test postgres_client -- --ignored + inputs: + - "@group(code)" + - "/Cargo.toml" + - "/Cargo.lock" + - "/src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh" + options: + cache: local + runFromWorkspaceRoot: true + + format: + command: "cargo fmt -p oliphaunt-broker" + options: + cache: false + runInCI: false + runFromWorkspaceRoot: true + + package: + deps: ["liboliphaunt-native-bindings:package", "oliphaunt-query:package"] + tags: ["release", "artifact-package", "ci-rust-sdk-package"] + script: | + set -eu + version="$(bun tools/release/product-version.mts version oliphaunt-broker)" + bindings_version="$(bun tools/release/product-version.mts version liboliphaunt-native-bindings)" + query_version="$(bun tools/release/product-version.mts version oliphaunt-query)" + rm -f "target/package/oliphaunt-broker-$version.crate" "target/package/liboliphaunt-native-bindings-$bindings_version.crate" "target/package/oliphaunt-query-$query_version.crate" + cargo package -p oliphaunt-query -p liboliphaunt-native-bindings -p oliphaunt-broker --locked --allow-dirty --no-verify + rm -rf target/sdk-artifacts/oliphaunt-broker + mkdir -p target/sdk-artifacts/oliphaunt-broker + cp "target/package/oliphaunt-broker-$version.crate" target/sdk-artifacts/oliphaunt-broker/ + bun tools/packaging/staging.mts target/sdk-artifacts/oliphaunt-broker + inputs: ["@group(code)", "/Cargo.toml", "/Cargo.lock", "/LICENSE", "/THIRD_PARTY_NOTICES.md"] + outputs: ["/target/sdk-artifacts/oliphaunt-broker/**/*"] + options: + runFromWorkspaceRoot: true + + build: + deps: + - target: cargo-sources + cacheStrategy: hash + tags: ["build", "requires-rust"] + command: "cargo build -p oliphaunt-broker --locked" + env: + CARGO_TARGET_DIR: "target" + inputs: + - "@group(cargo-workspace)" + - "@group(code)" + outputs: + - "/target/debug/oliphaunt-broker*" + - "/target/debug/liboliphaunt_broker.rlib" + options: + cache: true + runFromWorkspaceRoot: true + + test: + deps: + - target: cargo-sources + cacheStrategy: hash + tags: ["quality", "unit", "requires-rust"] + command: "cargo test -p oliphaunt-broker --locked" + env: + CARGO_TARGET_DIR: "target" + inputs: + - "@group(cargo-workspace)" + - "@group(code)" + options: + cache: true + runFromWorkspaceRoot: true + + format-check: + tags: ["quality", "static", "format", "requires-rust"] + command: "cargo fmt -p oliphaunt-broker --check" + inputs: ["/src/broker/**/*.rs","/src/broker/Cargo.toml","/clippy.toml","@group(cargo-workspace)"] + options: + runFromWorkspaceRoot: true + lint: + deps: + - target: cargo-sources + cacheStrategy: hash + tags: ["quality", "static", "requires-rust"] + command: "cargo clippy -p oliphaunt-broker --all-targets --locked -- -D warnings" + env: + CARGO_TARGET_DIR: "target" + inputs: ["/src/broker/**/*.rs","/src/broker/Cargo.toml","/clippy.toml","@group(cargo-workspace)"] + options: + runFromWorkspaceRoot: true + + dependency-license-audit: + tags: ["policy", "assertion", "quality", "static", "requires-rust"] + command: "bash src/broker/tools/audit-dependency-licenses.sh" + inputs: + - "@group(cargo-workspace)" + - "/src/benchmarks/**/Cargo.toml" + - "/src/examples/**/Cargo.toml" + - "/**/Cargo.toml" + - "/tools/**/Cargo.toml" + - "/src/broker/dependency-licenses.json" + - "/src/broker/dependency-license-blobs/**/*" + - "/src/broker/tools/broker-dependency-license-contract.mts" + - "/tools/packaging/rust-dependency-license-contract.mts" + - "/src/broker/tools/audit-dependency-licenses.sh" + - "/tools/packaging/audit-rust-dependency-licenses.sh" + - "/tools/packaging/release-directory-safety.mts" + options: + cache: false + runFromWorkspaceRoot: true + + + build-release-assets: + deps: + - target: cargo-sources + cacheStrategy: hash + tags: ["release", "artifact", "in-place-finalizer-input", "ci-broker-runtime"] + command: "bash src/broker/tools/package-broker-assets.sh" + env: + CARGO_TARGET_DIR: "target/moon/oliphaunt-broker/build-release-assets" + OLIPHAUNT_RELEASE_ASSET_PARTIAL: "1" + inputs: + - "@group(legal-files)" + - "@group(cargo-workspace)" + - "@group(code)" + - "/src/broker/tools/build-linux-broker-baseline.sh" + - "/src/broker/tools/broker-dependency-license-contract.mts" + - "/tools/packaging/rust-dependency-license-contract.mts" + - "/tools/packaging/check-linux-consumer-baseline.sh" + - "/tools/packaging/linux-abi-baseline.test.sh" + - "/src/broker/tools/package-broker-assets.sh" + - "/src/broker/tools/check-release-assets.mts" + - "/tools/release/platform-compatibility-policy.mts" + - "/tools/release/platform-compatibility-policy.test.mts" + - "/tools/packaging/platform-binary-contract.mts" + - "/tools/packaging/strip-native-binaries.sh" + - "/tools/packaging/platform-binary-contract.test.mts" + - "/tools/packaging/release-asset-validation.mts" + - "/src/extensions/contracts/extension-target-profiles.mts" + - "/tools/release/release-artifact-targets.mts" + - "@group(release-archive-contract)" + - "/tools/release/artifact-target-matrix.mts" + - "/release-please-config.json" + outputs: + - "/target/oliphaunt-broker/release-assets/**/*" + options: + cache: false + runFromWorkspaceRoot: true + + + finalize-release-assets: + tags: ["release", "artifact-package", "in-place-finalizer", "ci-broker-release-assets"] + command: "tools/dev/bun.sh src/broker/tools/check-release-assets.mts --aggregate" + deps: + - "oliphaunt-broker:build-release-assets" + inputs: + - "@group(legal-files)" + - "@group(cargo-workspace)" + - "@group(code)" + - project: "liboliphaunt-native-bindings" + group: "code" + - "/tools/release/artifact-target-matrix.mts" + - "/src/broker/tools/broker-dependency-license-contract.mts" + - "/tools/packaging/rust-dependency-license-contract.mts" + - "/src/broker/tools/build-linux-broker-baseline.sh" + - "/src/broker/tools/check-release-assets.mts" + - "/tools/packaging/check-linux-consumer-baseline.sh" + - "/tools/packaging/finalize-helper-assets.mts" + - "/tools/packaging/linux-abi-baseline.test.sh" + - "/src/broker/tools/package-broker-assets.sh" + - "/tools/release/platform-compatibility-policy.mts" + - "/tools/release/platform-compatibility-policy.test.mts" + - "/tools/packaging/platform-binary-contract.mts" + - "/tools/packaging/strip-native-binaries.sh" + - "/tools/packaging/platform-binary-contract.test.mts" + - "/tools/packaging/release-asset-validation.mts" + - "/src/extensions/contracts/extension-target-profiles.mts" + - "/tools/release/release-artifact-targets.mts" + - "@group(release-archive-contract)" + - "/tools/packaging/write-checksum-manifest.mts" + - "/release-please-config.json" + - "/target/oliphaunt-broker/release-assets/**/*" + outputs: + - "/target/oliphaunt-broker/release-assets/**/*" + options: + cache: false + runFromWorkspaceRoot: true + + + packaging-unit: + tags: ["quality", "unit", "requires-rust"] + command: "bash src/broker/tools/broker-dependency-license-contract.test.sh" + inputs: + - "@group(release-target-contract)" + - "@group(package-test-metadata)" + - "@group(code)" + - "tools/broker-dependency-license-contract.test.mts" + - "tools/broker-dependency-license-contract.test.sh" + - "tools/create-release-fixture.mts" + - "/tools/packaging/testdata/**/*" + - "/tools/dev/bun.sh" + - "/tools/packaging/*.{mts,sh}" + - "/tools/release/*.{mjs,mts}" + options: + cache: true + runFromWorkspaceRoot: true diff --git a/src/runtimes/broker/packages/darwin-arm64/README.md b/src/broker/packages/darwin-arm64/README.md similarity index 100% rename from src/runtimes/broker/packages/darwin-arm64/README.md rename to src/broker/packages/darwin-arm64/README.md diff --git a/src/broker/packages/darwin-arm64/package.json b/src/broker/packages/darwin-arm64/package.json new file mode 100644 index 000000000..0018d6b5e --- /dev/null +++ b/src/broker/packages/darwin-arm64/package.json @@ -0,0 +1,41 @@ +{ + "name": "@oliphaunt/broker-darwin-arm64", + "version": "0.2.0", + "description": "macOS arm64 oliphaunt-broker helper binary.", + "license": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/f0rr0/oliphaunt.git", + "directory": "src/broker/packages/darwin-arm64" + }, + "os": [ + "darwin" + ], + "cpu": [ + "arm64" + ], + "optional": true, + "oliphaunt": { + "brokerHelper": "oliphaunt-broker", + "target": "macos-arm64", + "executableRelativePath": "bin/oliphaunt-broker" + }, + "publishConfig": { + "access": "public", + "provenance": true, + "executableFiles": [ + "./bin/oliphaunt-broker" + ] + }, + "files": [ + "bin", + "README.md", + "LICENSE", + "THIRD_PARTY_NOTICES.md", + "THIRD_PARTY_LICENSES" + ], + "exports": { + "./package.json": "./package.json" + } +} diff --git a/src/runtimes/broker/packages/linux-arm64-gnu/README.md b/src/broker/packages/linux-arm64-gnu/README.md similarity index 100% rename from src/runtimes/broker/packages/linux-arm64-gnu/README.md rename to src/broker/packages/linux-arm64-gnu/README.md diff --git a/src/broker/packages/linux-arm64-gnu/package.json b/src/broker/packages/linux-arm64-gnu/package.json new file mode 100644 index 000000000..803bb057f --- /dev/null +++ b/src/broker/packages/linux-arm64-gnu/package.json @@ -0,0 +1,44 @@ +{ + "name": "@oliphaunt/broker-linux-arm64-gnu", + "version": "0.2.0", + "description": "Linux arm64 glibc oliphaunt-broker helper binary.", + "license": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/f0rr0/oliphaunt.git", + "directory": "src/broker/packages/linux-arm64-gnu" + }, + "os": [ + "linux" + ], + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "optional": true, + "oliphaunt": { + "brokerHelper": "oliphaunt-broker", + "target": "linux-arm64-gnu", + "executableRelativePath": "bin/oliphaunt-broker" + }, + "publishConfig": { + "access": "public", + "provenance": true, + "executableFiles": [ + "./bin/oliphaunt-broker" + ] + }, + "files": [ + "bin", + "README.md", + "LICENSE", + "THIRD_PARTY_NOTICES.md", + "THIRD_PARTY_LICENSES" + ], + "exports": { + "./package.json": "./package.json" + } +} diff --git a/src/runtimes/broker/packages/linux-x64-gnu/README.md b/src/broker/packages/linux-x64-gnu/README.md similarity index 100% rename from src/runtimes/broker/packages/linux-x64-gnu/README.md rename to src/broker/packages/linux-x64-gnu/README.md diff --git a/src/broker/packages/linux-x64-gnu/package.json b/src/broker/packages/linux-x64-gnu/package.json new file mode 100644 index 000000000..d0542d92f --- /dev/null +++ b/src/broker/packages/linux-x64-gnu/package.json @@ -0,0 +1,44 @@ +{ + "name": "@oliphaunt/broker-linux-x64-gnu", + "version": "0.2.0", + "description": "Linux x64 glibc oliphaunt-broker helper binary.", + "license": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/f0rr0/oliphaunt.git", + "directory": "src/broker/packages/linux-x64-gnu" + }, + "os": [ + "linux" + ], + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "optional": true, + "oliphaunt": { + "brokerHelper": "oliphaunt-broker", + "target": "linux-x64-gnu", + "executableRelativePath": "bin/oliphaunt-broker" + }, + "publishConfig": { + "access": "public", + "provenance": true, + "executableFiles": [ + "./bin/oliphaunt-broker" + ] + }, + "files": [ + "bin", + "README.md", + "LICENSE", + "THIRD_PARTY_NOTICES.md", + "THIRD_PARTY_LICENSES" + ], + "exports": { + "./package.json": "./package.json" + } +} diff --git a/src/runtimes/broker/packages/win32-x64-msvc/README.md b/src/broker/packages/win32-x64-msvc/README.md similarity index 100% rename from src/runtimes/broker/packages/win32-x64-msvc/README.md rename to src/broker/packages/win32-x64-msvc/README.md diff --git a/src/broker/packages/win32-x64-msvc/package.json b/src/broker/packages/win32-x64-msvc/package.json new file mode 100644 index 000000000..5172e5cdc --- /dev/null +++ b/src/broker/packages/win32-x64-msvc/package.json @@ -0,0 +1,41 @@ +{ + "name": "@oliphaunt/broker-win32-x64-msvc", + "version": "0.2.0", + "description": "Windows x64 MSVC oliphaunt-broker helper binary.", + "license": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/f0rr0/oliphaunt.git", + "directory": "src/broker/packages/win32-x64-msvc" + }, + "os": [ + "win32" + ], + "cpu": [ + "x64" + ], + "optional": true, + "oliphaunt": { + "brokerHelper": "oliphaunt-broker", + "target": "windows-x64-msvc", + "executableRelativePath": "bin/oliphaunt-broker.exe" + }, + "publishConfig": { + "access": "public", + "provenance": true, + "executableFiles": [ + "./bin/oliphaunt-broker.exe" + ] + }, + "files": [ + "bin", + "README.md", + "LICENSE", + "THIRD_PARTY_NOTICES.md", + "THIRD_PARTY_LICENSES" + ], + "exports": { + "./package.json": "./package.json" + } +} diff --git a/src/broker/release.toml b/src/broker/release.toml new file mode 100644 index 000000000..ad84e8745 --- /dev/null +++ b/src/broker/release.toml @@ -0,0 +1,26 @@ +id = "oliphaunt-broker" +owner = "@oliphaunt/broker" +kind = "runtime" +publish_targets = ["github-release-assets", "npm", "crates-io"] +registry_packages = [ + "crates:oliphaunt-broker", + "crates:oliphaunt-broker-linux-arm64-gnu", + "crates:oliphaunt-broker-linux-x64-gnu", + "crates:oliphaunt-broker-macos-arm64", + "crates:oliphaunt-broker-windows-x64-msvc", + "npm:@oliphaunt/broker-darwin-arm64", + "npm:@oliphaunt/broker-linux-x64-gnu", + "npm:@oliphaunt/broker-linux-arm64-gnu", + "npm:@oliphaunt/broker-win32-x64-msvc", +] +release_artifacts = ["broker-helper-binary", "cargo-crate"] + +[compatibility_versions.broker_native_bindings] +source_product = "liboliphaunt-native-bindings" +path = "src/broker/Cargo.toml" +parser = "toml:dependencies.liboliphaunt-native-bindings.version" + +[compatibility_versions.broker_query] +source_product = "oliphaunt-query" +path = "src/broker/Cargo.toml" +parser = "toml:dependencies.oliphaunt-query.version" diff --git a/src/broker/src/ipc.rs b/src/broker/src/ipc.rs new file mode 100644 index 000000000..249722d21 --- /dev/null +++ b/src/broker/src/ipc.rs @@ -0,0 +1,144 @@ +use std::io::{Read, Write}; + +use liboliphaunt_native_bindings::{Error, Result}; + +const MAGIC: &[u8; 4] = b"PGOB"; +const HEADER_LEN: usize = 13; +const MAX_FRAME_LEN: u64 = 128 * 1024 * 1024; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum RequestFrame { + Authenticate(String), + Close, + Backup, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ResponseFrame { + Ok(Vec), + Error(String), +} + +pub fn write_request(writer: &mut impl Write, frame: RequestFrame) -> Result<()> { + match frame { + RequestFrame::Authenticate(token) => write_frame(writer, 6, token.as_bytes()), + RequestFrame::Close => write_frame(writer, 3, &[]), + RequestFrame::Backup => write_frame(writer, 5, &[]), + } +} + +pub fn read_request(reader: &mut impl Read) -> Result { + let (kind, payload) = read_frame(reader)?; + match kind { + 6 => String::from_utf8(payload) + .map(RequestFrame::Authenticate) + .map_err(|err| Error::Engine(format!("broker auth frame is not UTF-8: {err}"))), + 3 => empty_payload(payload, RequestFrame::Close), + 5 => empty_payload(payload, RequestFrame::Backup), + _ => Err(Error::Engine(format!( + "unknown broker request frame {kind}" + ))), + } +} + +pub fn write_response(writer: &mut impl Write, frame: ResponseFrame) -> Result<()> { + match frame { + ResponseFrame::Ok(bytes) => write_frame(writer, 101, &bytes), + ResponseFrame::Error(message) => write_frame(writer, 102, message.as_bytes()), + } +} + +pub fn read_response(reader: &mut impl Read) -> Result { + let (kind, payload) = read_frame(reader)?; + match kind { + 101 => Ok(ResponseFrame::Ok(payload)), + 102 => String::from_utf8(payload) + .map(ResponseFrame::Error) + .map_err(|err| Error::Engine(format!("broker error frame is not UTF-8: {err}"))), + _ => Err(Error::Engine(format!( + "unknown broker response frame {kind}" + ))), + } +} + +fn empty_payload(payload: Vec, frame: RequestFrame) -> Result { + if payload.is_empty() { + Ok(frame) + } else { + Err(Error::Engine( + "broker control frame unexpectedly had a payload".to_owned(), + )) + } +} + +fn write_frame(writer: &mut impl Write, kind: u8, payload: &[u8]) -> Result<()> { + let len = u64::try_from(payload.len()) + .map_err(|_| Error::Engine("broker frame payload is too large".to_owned()))?; + let mut header = [0_u8; HEADER_LEN]; + header[..4].copy_from_slice(MAGIC); + header[4] = kind; + header[5..].copy_from_slice(&len.to_be_bytes()); + writer + .write_all(&header) + .and_then(|()| writer.write_all(payload)) + .and_then(|()| writer.flush()) + .map_err(|err| Error::Engine(format!("write broker frame: {err}"))) +} + +fn read_frame(reader: &mut impl Read) -> Result<(u8, Vec)> { + let mut header = [0_u8; HEADER_LEN]; + reader + .read_exact(&mut header) + .map_err(|err| Error::Engine(format!("read broker frame header: {err}")))?; + if &header[..4] != MAGIC { + return Err(Error::Engine("broker frame magic mismatch".to_owned())); + } + let kind = header[4]; + let len = u64::from_be_bytes( + header[5..] + .try_into() + .expect("frame header contains an 8-byte payload length"), + ); + if len > MAX_FRAME_LEN { + return Err(Error::Engine(format!( + "broker frame payload length {len} exceeds limit {MAX_FRAME_LEN}" + ))); + } + let mut payload = vec![0_u8; len as usize]; + reader + .read_exact(&mut payload) + .map_err(|err| Error::Engine(format!("read broker frame payload: {err}")))?; + Ok((kind, payload)) +} + +#[cfg(test)] +mod tests { + use std::io::Cursor; + + use super::*; + + #[test] + fn auth_frame_round_trips() { + let mut bytes = Vec::new(); + write_request( + &mut bytes, + RequestFrame::Authenticate("token-123".to_owned()), + ) + .unwrap(); + + let mut cursor = Cursor::new(bytes); + assert_eq!( + read_request(&mut cursor).unwrap(), + RequestFrame::Authenticate("token-123".to_owned()) + ); + } + + #[test] + fn backup_frame_still_round_trips() { + let mut bytes = Vec::new(); + write_request(&mut bytes, RequestFrame::Backup).unwrap(); + + let mut cursor = Cursor::new(bytes); + assert_eq!(read_request(&mut cursor).unwrap(), RequestFrame::Backup); + } +} diff --git a/src/broker/src/lib.rs b/src/broker/src/lib.rs new file mode 100644 index 000000000..d1153fe28 --- /dev/null +++ b/src/broker/src/lib.rs @@ -0,0 +1,3 @@ +//! Broker transport shared by the broker executable and native SDK client. +pub mod ipc; +pub mod pgwire; diff --git a/src/broker/src/main.rs b/src/broker/src/main.rs new file mode 100644 index 000000000..ce388b0e4 --- /dev/null +++ b/src/broker/src/main.rs @@ -0,0 +1,357 @@ +use std::env; +use std::error::Error as StdError; +use std::ffi::OsString; +use std::fmt; +use std::io; +use std::net::TcpListener; +#[cfg(unix)] +use std::os::unix::net::UnixListener; +use std::process; + +use liboliphaunt_native_bindings::Extension; +mod server; + +const ENV_BROKER_AUTH_TOKEN: &str = "OLIPHAUNT_BROKER_AUTH_TOKEN"; +const DEFAULT_USERNAME: &str = "postgres"; +const DEFAULT_DATABASE: &str = "postgres"; + +type BrokerResult = std::result::Result; + +#[derive(Debug)] +enum BrokerError { + Configuration(String), + Runtime(String), + Oliphaunt(liboliphaunt_native_bindings::Error), +} + +impl BrokerError { + fn configuration(message: impl Into) -> Self { + Self::Configuration(message.into()) + } + + fn runtime(message: impl Into) -> Self { + Self::Runtime(message.into()) + } +} + +impl fmt::Display for BrokerError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Configuration(message) | Self::Runtime(message) => formatter.write_str(message), + Self::Oliphaunt(error) => error.fmt(formatter), + } + } +} + +impl StdError for BrokerError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + Self::Oliphaunt(error) => Some(error), + Self::Configuration(_) | Self::Runtime(_) => None, + } + } +} + +impl From for BrokerError { + fn from(error: liboliphaunt_native_bindings::Error) -> Self { + Self::Oliphaunt(error) + } +} + +fn main() { + if let Err(error) = run() { + println!("OLIPHAUNT_BROKER_ERROR {error}"); + process::exit(2); + } +} + +fn run() -> BrokerResult<()> { + let args = BrokerArgs::parse(env::args_os().skip(1).collect())?; + server::serve(args).map_err(|error| BrokerError::runtime(error.to_string())) +} + +struct BrokerArgs { + root: std::path::PathBuf, + endpoint: BrokerListenEndpoint, + control_endpoint: BrokerListenEndpoint, + startup_gucs: Vec<(String, String)>, + username: String, + database: String, + extensions: Vec, + auth_token: String, + seed: Option, + icu_data: Option, +} + +impl BrokerArgs { + fn parse(args: Vec) -> BrokerResult { + let auth_token = env::var(ENV_BROKER_AUTH_TOKEN).map_err(|_| { + BrokerError::configuration(format!("{ENV_BROKER_AUTH_TOKEN} is required")) + })?; + Self::parse_with_auth_token(args, auth_token) + } + + fn parse_with_auth_token(args: Vec, auth_token: String) -> BrokerResult { + let mut root = None; + let mut endpoint = BrokerListenEndpoint::Tcp("127.0.0.1:0".to_owned()); + let mut control_endpoint = BrokerListenEndpoint::Tcp("127.0.0.1:0".to_owned()); + let mut startup_gucs = Vec::new(); + let mut username = DEFAULT_USERNAME.to_owned(); + let mut database = DEFAULT_DATABASE.to_owned(); + let mut extensions = Vec::new(); + let mut seed_directory = None; + let mut seed_manifest = None; + let mut icu_directory = None; + let mut icu_manifest = None; + let mut iter = args.into_iter(); + while let Some(arg) = iter.next() { + let arg = arg.into_string().map_err(|_| { + BrokerError::configuration("broker argument names must be valid UTF-8") + })?; + match arg.as_str() { + "--seed-directory" => { + seed_directory = + Some(next_broker_arg(&mut iter, &arg, "a filesystem path")?.into()) + } + "--seed-manifest" => { + seed_manifest = + Some(next_broker_arg(&mut iter, &arg, "a filesystem path")?.into()) + } + "--icu-data-directory" => { + icu_directory = + Some(next_broker_arg(&mut iter, &arg, "a filesystem path")?.into()) + } + "--icu-data-manifest" => { + icu_manifest = + Some(next_broker_arg(&mut iter, &arg, "a filesystem path")?.into()) + } + "--root" => { + root = Some(next_broker_arg(&mut iter, "--root", "a filesystem path")?.into()) + } + "--listen" => { + let listen = next_utf8_broker_arg(&mut iter, "--listen", "an address")?; + endpoint = BrokerListenEndpoint::Tcp(listen); + } + "--control-listen" => { + let listen = next_utf8_broker_arg(&mut iter, "--control-listen", "an address")?; + control_endpoint = BrokerListenEndpoint::Tcp(listen); + } + "--socket" => { + let socket = next_broker_arg(&mut iter, "--socket", "a filesystem path")?; + endpoint = BrokerListenEndpoint::unix(socket)?; + } + "--control-socket" => { + let socket = + next_broker_arg(&mut iter, "--control-socket", "a filesystem path")?; + control_endpoint = BrokerListenEndpoint::unix(socket)?; + } + "--startup-guc" => { + let assignment = + next_utf8_broker_arg(&mut iter, "--startup-guc", "name=value")?; + startup_gucs.push(parse_startup_guc(&assignment)?); + } + "--username" => { + username = next_utf8_broker_arg(&mut iter, "--username", "a PostgreSQL role")?; + } + "--database" => { + database = next_utf8_broker_arg( + &mut iter, + "--database", + "a PostgreSQL database name", + )?; + } + "--extension" => { + let sql_name = + next_utf8_broker_arg(&mut iter, "--extension", "a SQL extension name")?; + let extension = Extension::by_sql_name(&sql_name).ok_or_else(|| { + BrokerError::configuration(format!( + "unsupported native extension '{sql_name}'" + )) + })?; + extensions.push(extension); + } + _ => { + return Err(BrokerError::configuration(format!( + "unknown broker argument '{arg}'" + ))); + } + } + } + if auth_token.is_empty() { + return Err(BrokerError::configuration(format!( + "{ENV_BROKER_AUTH_TOKEN} must not be empty" + ))); + } + + Ok(Self { + root: root.ok_or_else(|| BrokerError::configuration("--root is required"))?, + endpoint, + control_endpoint, + startup_gucs, + username, + database, + extensions, + auth_token, + seed: resource_directory(seed_directory, seed_manifest, "seed")?, + icu_data: resource_directory(icu_directory, icu_manifest, "ICU data")?, + }) + } +} + +fn resource_directory( + directory: Option, + manifest: Option, + name: &str, +) -> BrokerResult> { + match (directory, manifest) { + (None, None) => Ok(None), + (Some(directory), Some(manifest)) => Ok(Some( + liboliphaunt_native_bindings::NativeResourceDirectory { + directory, + manifest, + }, + )), + _ => Err(BrokerError::configuration(format!( + "{name} requires both directory and manifest paths" + ))), + } +} + +fn next_broker_arg( + iter: &mut impl Iterator, + option: &str, + expected: &str, +) -> BrokerResult { + iter.next() + .ok_or_else(|| BrokerError::configuration(format!("{option} requires {expected}"))) +} + +fn next_utf8_broker_arg( + iter: &mut impl Iterator, + option: &str, + expected: &str, +) -> BrokerResult { + next_broker_arg(iter, option, expected)? + .into_string() + .map_err(|_| { + BrokerError::configuration(format!( + "{option} requires {expected} encoded as valid UTF-8" + )) + }) +} + +fn parse_startup_guc(value: &str) -> BrokerResult<(String, String)> { + let Some((name, guc_value)) = value.split_once('=') else { + return Err(BrokerError::configuration( + "--startup-guc requires name=value", + )); + }; + Ok((name.to_owned(), guc_value.to_owned())) +} + +enum BrokerListenEndpoint { + Tcp(String), + #[cfg(unix)] + Unix(std::path::PathBuf), +} + +impl BrokerListenEndpoint { + #[cfg(unix)] + fn unix(path: impl Into) -> BrokerResult { + Ok(Self::Unix(path.into())) + } + + #[cfg(not(unix))] + fn unix(_path: impl Into) -> BrokerResult { + Err(BrokerError::configuration( + "Unix-domain broker sockets are not supported on this platform", + )) + } +} + +enum BrokerListener { + Tcp(TcpListener), + #[cfg(unix)] + Unix { + listener: UnixListener, + path: std::path::PathBuf, + }, +} + +impl BrokerListener { + fn bind(endpoint: BrokerListenEndpoint) -> BrokerResult { + match endpoint { + BrokerListenEndpoint::Tcp(listen) => { + TcpListener::bind(&listen).map(Self::Tcp).map_err(|err| { + BrokerError::runtime(format!("bind broker TCP listener {listen}: {err}")) + }) + } + #[cfg(unix)] + BrokerListenEndpoint::Unix(path) => { + if path.exists() { + std::fs::remove_file(&path).map_err(|err| { + BrokerError::runtime(format!( + "remove stale broker socket {}: {err}", + path.display() + )) + })?; + } + UnixListener::bind(&path) + .map(|listener| Self::Unix { listener, path }) + .map_err(|err| BrokerError::runtime(format!("bind broker Unix socket: {err}"))) + } + } + } + + fn ready_endpoint(&self) -> String { + match self { + Self::Tcp(listener) => listener + .local_addr() + .map(|addr| format!("tcp:{addr}")) + .unwrap_or_else(|_| "tcp:".to_owned()), + #[cfg(unix)] + Self::Unix { path, .. } => format!("unix:{}", path.display()), + } + } + + fn accept(&self) -> io::Result { + match self { + Self::Tcp(listener) => listener + .accept() + .map(|(stream, _)| server::Socket::Tcp(stream)), + #[cfg(unix)] + Self::Unix { listener, .. } => listener + .accept() + .map(|(stream, _)| server::Socket::Unix(stream)), + } + } + + fn nonblocking(&self) -> io::Result<()> { + match self { + Self::Tcp(listener) => listener.set_nonblocking(true), + #[cfg(unix)] + Self::Unix { listener, .. } => listener.set_nonblocking(true), + } + } +} + +#[cfg(all(test, unix))] +mod tests { + use std::os::unix::ffi::OsStringExt; + use std::path::PathBuf; + + use super::*; + + #[test] + fn broker_arguments_preserve_non_utf8_database_roots() { + let root = PathBuf::from(OsString::from_vec( + b"/tmp/oliphaunt-broker-root-\xff".to_vec(), + )); + let args = vec![OsString::from("--root"), root.clone().into_os_string()]; + + let parsed = BrokerArgs::parse_with_auth_token(args, "test-token".to_owned()) + .expect("non-UTF-8 filesystem paths remain valid broker roots"); + + assert_eq!(parsed.root, root); + } +} diff --git a/src/broker/src/pgwire.rs b/src/broker/src/pgwire.rs new file mode 100644 index 000000000..dec17d320 --- /dev/null +++ b/src/broker/src/pgwire.rs @@ -0,0 +1,218 @@ +//! Raw PostgreSQL transport for the broker's embedded backend. +use oliphaunt_query::wire::{CANCEL_REQUEST_CODE, MAX_FRONTEND_MESSAGE, PROTOCOL_3}; +use std::io::{self, Read, Write}; + +/// A local SQL socket whose write half can progress while results are drained. +pub trait Connection: Read + Write + Send { + fn clone_connection(&self) -> io::Result>; + fn shutdown(&self); +} + +impl Connection for std::net::TcpStream { + fn clone_connection(&self) -> io::Result> { + Ok(Box::new(self.try_clone()?)) + } + fn shutdown(&self) { + let _ = self.shutdown(std::net::Shutdown::Both); + } +} +#[cfg(unix)] +impl Connection for std::os::unix::net::UnixStream { + fn clone_connection(&self) -> io::Result> { + Ok(Box::new(self.try_clone()?)) + } + fn shutdown(&self) { + let _ = self.shutdown(std::net::Shutdown::Both); + } +} + +fn invalid(message: impl Into) -> io::Error { + io::Error::new(io::ErrorKind::InvalidData, message.into()) +} + +fn frame(tag: u8, body: &[u8]) -> Vec { + let mut bytes = vec![tag]; + bytes.extend_from_slice(&((body.len() + 4) as u32).to_be_bytes()); + bytes.extend_from_slice(body); + bytes +} + +/// Perform startup with the broker's per-process password and retain the fresh +/// BackendKeyData for independent CancelRequest connections. +pub fn authenticate( + stream: &mut (impl Read + Write), + username: &str, + database: &str, + password: &str, +) -> io::Result<[u8; 8]> { + if [username, database, password] + .iter() + .any(|value| value.contains('\0')) + { + return Err(invalid("PostgreSQL startup values must not contain NUL")); + } + let mut startup = PROTOCOL_3.to_be_bytes().to_vec(); + startup.extend_from_slice( + format!("user\0{username}\0database\0{database}\0client_encoding\0UTF8\0\0").as_bytes(), + ); + stream.write_all(&((startup.len() + 4) as u32).to_be_bytes())?; + stream.write_all(&startup)?; + let mut key = None; + let mut authenticated = false; + let mut password_sent = false; + loop { + let bytes = read_backend(stream)?; + let body = &bytes[5..]; + match bytes[0] { + b'R' if body == 3_i32.to_be_bytes() && !password_sent => { + stream.write_all(&frame(b'p', format!("{password}\0").as_bytes()))?; + password_sent = true; + } + b'R' if body == 0_i32.to_be_bytes() && password_sent => authenticated = true, + b'R' => return Err(invalid("unsupported broker authentication request")), + b'K' if body.len() == 8 => key = Some(body.try_into().unwrap()), + b'E' => { + let fields = oliphaunt_query::parse_diagnostic_fields(body, "ErrorResponse") + .map_err(|error| invalid(error.to_string()))?; + return Err(invalid( + oliphaunt_query::diagnostic(fields, "broker startup failed").message, + )); + } + b'Z' if body == b"I" && authenticated => { + return key.ok_or_else(|| invalid("broker omitted BackendKeyData")); + } + b'Z' => { + return Err(invalid( + "broker became ready before authentication completed", + )); + } + b'S' | b'N' => {} + _ => return Err(invalid("unexpected broker startup frame")), + } + } +} + +/// Send the standard independent cancellation packet. PostgreSQL sends no reply. +pub fn cancel(stream: &mut impl Write, key: &[u8; 8]) -> io::Result<()> { + stream.write_all(&16_i32.to_be_bytes())?; + stream.write_all(&CANCEL_REQUEST_CODE.to_be_bytes())?; + stream.write_all(key) +} + +/// Count actual ReadyForQuery boundaries before any bytes are written. An +/// incomplete batch cannot be submitted to this complete-request API. +pub fn completion_count(request: &[u8]) -> io::Result { + if request.len() > MAX_FRONTEND_MESSAGE { + return Err(invalid("broker request exceeds size limit")); + } + let mut remaining = request; + let mut count = 0; + let mut last = 0; + while !remaining.is_empty() { + if remaining.len() < 5 { + return Err(invalid("truncated frontend frame")); + } + let length = u32::from_be_bytes(remaining[1..5].try_into().unwrap()) as usize; + if length < 4 || length >= remaining.len() { + return Err(invalid("invalid frontend frame length")); + } + last = remaining[0]; + if matches!(last, b'Q' | b'S') { + count += 1; + } + if matches!(last, b'X' | b'p') { + return Err(invalid("connection control is not a query request")); + } + remaining = &remaining[length + 1..]; + } + if count == 0 || !matches!(last, b'Q' | b'S' | b'c' | b'f') { + return Err(invalid( + "broker request must include a complete Query or Sync boundary", + )); + } + Ok(count) +} + +/// Forward raw backend frames, retaining the first callback error while draining +/// all promised ReadyForQuery boundaries. A transport error supersedes a callback +/// error because recovery could not be established. +pub fn exchange( + stream: &mut (impl Connection + ?Sized), + request: &[u8], + callback: &mut impl FnMut(&[u8]) -> Result<(), E>, +) -> io::Result> { + let boundaries = completion_count(request)?; + let mut writer = stream.clone_connection()?; + std::thread::scope(|scope| { + let writing = scope.spawn(|| { + let result = writer.write_all(request); + if result.is_err() { + writer.shutdown(); + } + result + }); + let reading = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + receive(stream, boundaries, callback) + })); + if !matches!(&reading, Ok(Ok(_))) { + stream.shutdown(); + } + let written = writing.join(); + match reading { + Err(payload) => std::panic::resume_unwind(payload), + Ok(Err(error)) => Err(error), + Ok(Ok(callback_error)) => { + written.map_err(|_| invalid("broker request writer panicked"))??; + Ok(callback_error) + } + } + }) +} + +fn receive( + stream: &mut (impl Read + ?Sized), + mut boundaries: usize, + callback: &mut impl FnMut(&[u8]) -> Result<(), E>, +) -> io::Result> { + let mut callback_error = None; + while boundaries != 0 { + let bytes = read_backend(stream)?; + if callback_error.is_none() { + callback_error = callback(&bytes).err(); + } + if bytes[0] == b'Z' { + if bytes.len() != 6 || !matches!(bytes[5], b'I' | b'T' | b'E') { + return Err(invalid("invalid ReadyForQuery frame")); + } + boundaries -= 1; + } + } + Ok(callback_error) +} + +fn read_backend(reader: &mut (impl Read + ?Sized)) -> io::Result> { + let mut header = [0; 5]; + reader.read_exact(&mut header)?; + let length = u32::from_be_bytes(header[1..].try_into().unwrap()) as usize; + if !(4..MAX_FRONTEND_MESSAGE).contains(&length) { + return Err(invalid("invalid backend message length")); + } + let mut bytes = vec![0; length + 1]; + bytes[..5].copy_from_slice(&header); + reader.read_exact(&mut bytes[5..])?; + Ok(bytes) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn complete_batches_preserve_every_ready_boundary() { + let mut bytes = oliphaunt_query::simple_query("SELECT 1").unwrap(); + bytes.extend(oliphaunt_query::simple_query("SELECT 2").unwrap()); + assert_eq!(completion_count(&bytes).unwrap(), 2); + assert!(completion_count(&frame(b'H', b"")).is_err()); + bytes.pop(); + assert!(completion_count(&bytes).is_err()); + } +} diff --git a/src/broker/src/server.rs b/src/broker/src/server.rs new file mode 100644 index 000000000..37a0d4a64 --- /dev/null +++ b/src/broker/src/server.rs @@ -0,0 +1,617 @@ +use std::io::{self, Read, Write}; +use std::net::{Shutdown, TcpStream}; +#[cfg(unix)] +use std::os::unix::net::UnixStream; +use std::sync::{ + Arc, Mutex, + atomic::{AtomicBool, AtomicUsize, Ordering}, + mpsc, +}; +use std::thread; +use std::time::Duration; + +use liboliphaunt_native_bindings::{ + DatabaseStorage, NativeConfig, NativeProtocolInput, NativeSession, PostgresStartupGuc, + ProtocolStreamOutcome, +}; +use oliphaunt_broker::ipc::{self, RequestFrame, ResponseFrame}; +use oliphaunt_query::{ExpectedProtocol, parse_query_response, wire}; + +use crate::{BrokerArgs, BrokerListener}; + +pub(super) enum Socket { + Tcp(TcpStream), + #[cfg(unix)] + Unix(UnixStream), +} + +macro_rules! socket_call { + ($self:expr, $method:ident $(, $arg:expr)*) => { + match $self { + Socket::Tcp(stream) => stream.$method($($arg),*), + #[cfg(unix)] + Socket::Unix(stream) => stream.$method($($arg),*), + } + }; +} + +impl Socket { + fn clone_socket(&self) -> io::Result { + match self { + Self::Tcp(stream) => stream.try_clone().map(Self::Tcp), + #[cfg(unix)] + Self::Unix(stream) => stream.try_clone().map(Self::Unix), + } + } + fn shutdown(&self) { + let _ = socket_call!(self, shutdown, Shutdown::Both); + } + fn read_timeout(&self, timeout: Option) -> io::Result<()> { + socket_call!(self, set_read_timeout, timeout) + } + fn write_timeout(&self, timeout: Option) -> io::Result<()> { + socket_call!(self, set_write_timeout, timeout) + } +} +impl Read for Socket { + fn read(&mut self, bytes: &mut [u8]) -> io::Result { + socket_call!(self, read, bytes) + } +} +impl Write for Socket { + fn write(&mut self, bytes: &[u8]) -> io::Result { + socket_call!(self, write, bytes) + } + fn flush(&mut self) -> io::Result<()> { + socket_call!(self, flush) + } +} + +type Reply = mpsc::Sender>; +enum Command { + Startup(String, Reply>), + Execute(Vec, Socket, Reply<()>), + Reset(Reply<()>), + Backup(Reply>), + Shutdown(Reply<()>), +} + +struct Shared { + commands: mpsc::SyncSender, + native: Mutex<( + liboliphaunt_native_bindings::NativeCancel, + NativeProtocolInput, + )>, + closing: AtomicBool, + executing: AtomicBool, + stopping: AtomicBool, + occupied: AtomicBool, + owner_connected: AtomicBool, + connection_count: AtomicUsize, + active: Mutex>, + password: String, + username: String, + database: String, +} + +fn other(error: impl std::fmt::Display) -> io::Error { + io::Error::other(error.to_string()) +} + +pub(super) fn serve(args: BrokerArgs) -> io::Result<()> { + let config = NativeConfig { + storage: DatabaseStorage::Directory(args.root), + startup_gucs: args + .startup_gucs + .into_iter() + .map(|(key, value)| PostgresStartupGuc::new(key, value)) + .collect(), + username: args.username.clone(), + database: args.database.clone(), + extensions: args.extensions, + seed: args + .seed + .map(liboliphaunt_native_bindings::NativeClusterSeed::Directory), + icu_data: args.icu_data, + }; + let session = NativeSession::open(config.clone()).map_err(other)?; + let sql = BrokerListener::bind(args.endpoint).map_err(other)?; + let control = BrokerListener::bind(args.control_endpoint).map_err(other)?; + sql.nonblocking()?; + control.nonblocking()?; + let (commands, receiver) = mpsc::sync_channel(1); + let shared = Arc::new(Shared { + commands, + native: Mutex::new(( + session.cancel_handle(), + session.protocol_input().map_err(other)?, + )), + closing: AtomicBool::new(false), + executing: AtomicBool::new(false), + stopping: AtomicBool::new(false), + occupied: AtomicBool::new(false), + owner_connected: AtomicBool::new(false), + connection_count: AtomicUsize::new(0), + active: Mutex::new(None), + password: args.auth_token, + username: args.username, + database: args.database, + }); + let worker_state = Arc::clone(&shared); + let worker = thread::Builder::new() + .name("oliphaunt-broker-backend".into()) + .spawn(move || run_backend(session, config, receiver, &worker_state))?; + println!( + "OLIPHAUNT_BROKER_READY {} control={}", + sql.ready_endpoint(), + control.ready_endpoint() + ); + io::stdout().flush()?; + while !shared.stopping.load(Ordering::Acquire) { + for (listener, management) in [(&control, true), (&sql, false)] { + match listener.accept() { + Ok(socket) => { + if shared.connection_count.fetch_add(1, Ordering::AcqRel) >= 16 { + shared.connection_count.fetch_sub(1, Ordering::AcqRel); + socket.shutdown(); + continue; + } + let state = Arc::clone(&shared); + thread::Builder::new() + .name("oliphaunt-broker-client".into()) + .spawn(move || { + let result = if management { + management_client(socket, &state) + } else { + sql_client(socket, &state) + }; + if let Err(error) = result + && !matches!( + error.kind(), + io::ErrorKind::UnexpectedEof + | io::ErrorKind::ConnectionReset + | io::ErrorKind::BrokenPipe + | io::ErrorKind::ConnectionAborted + ) + { + eprintln!("OLIPHAUNT_BROKER_CLIENT_ERROR {error}"); + } + state.connection_count.fetch_sub(1, Ordering::AcqRel); + })?; + } + Err(error) if error.kind() == io::ErrorKind::WouldBlock => {} + Err(error) => { + stop(&shared); + return Err(error); + } + } + } + thread::sleep(Duration::from_millis(2)); + } + stop(&shared); + let (reply, done) = mpsc::channel(); + let _ = shared.commands.send(Command::Shutdown(reply)); + let _ = done.recv(); + worker + .join() + .map_err(|_| other("broker backend panicked"))? +} + +fn stop(shared: &Shared) { + shared.closing.store(true, Ordering::Release); + shared.stopping.store(true, Ordering::Release); + cancel_execution(shared); + if let Some((socket, _)) = shared.active.lock().unwrap().as_ref() { + socket.shutdown(); + } +} + +fn cancel_execution(shared: &Shared) { + if shared.executing.load(Ordering::Acquire) { + let cancel = shared.native.lock().unwrap().0.clone(); + let _ = cancel.cancel(); + } +} + +fn run_backend( + mut session: NativeSession, + config: NativeConfig, + receiver: mpsc::Receiver, + shared: &Shared, +) -> io::Result<()> { + for command in receiver { + match command { + Command::Startup(application, reply) => { + let _ = reply.send(startup_parameters(&mut session, &application)); + } + Command::Execute(request, mut socket, reply) => { + if shared.closing.load(Ordering::Acquire) { + shared.executing.store(false, Ordering::Release); + let _ = reply.send(Err(other("broker is closing"))); + continue; + } + let outcome = session.exec_protocol_raw_stream(&request, &mut |bytes| { + socket.write_all(bytes).map_err(|error| { + liboliphaunt_native_bindings::Error::Engine(error.to_string()) + }) + }); + let result = match outcome { + ProtocolStreamOutcome::ReadyForQuery(Ok(())) => Ok(()), + ProtocolStreamOutcome::ReadyForQuery(Err(error)) + | ProtocolStreamOutcome::SessionStateUnknown(error) => Err(other(error)), + }; + shared.executing.store(false, Ordering::Release); + let _ = reply.send(result); + } + Command::Reset(reply) => { + if shared.closing.load(Ordering::Acquire) { + let _ = reply.send(Ok(())); + continue; + } + let result = session + .close() + .and_then(|()| NativeSession::open(config.clone())) + .and_then(|next| { + *shared.native.lock().unwrap() = + (next.cancel_handle(), next.protocol_input()?); + session = next; + Ok(()) + }) + .map_err(other); + if result.is_err() { + stop(shared); + } + let _ = reply.send(result); + } + Command::Backup(reply) => { + let _ = reply.send(session.backup().map_err(other)); + } + Command::Shutdown(reply) => { + let result = session.close_terminal().map_err(other); + let failed = result.is_err(); + let _ = reply.send(result); + return if failed { + Err(other("native terminal shutdown failed")) + } else { + Ok(()) + }; + } + } + } + session.close_terminal().map_err(other) +} + +fn startup_parameters(session: &mut NativeSession, application: &str) -> io::Result> { + let request = oliphaunt_query::extended_statement( + "SELECT set_config('application_name', $1, false)", + &[oliphaunt_query::Parameter::text(application)], + 0, + ) + .map_err(other)?; + parse_query_response( + &session.exec_protocol_raw(&request).map_err(other)?, + ExpectedProtocol::Extended, + ) + .map_err(other)?; + let bytes = session.exec_simple_query("SELECT name, setting FROM pg_settings WHERE name IN ('server_version','server_encoding','client_encoding','application_name','DateStyle','IntervalStyle','TimeZone','integer_datetimes','standard_conforming_strings')").map_err(other)?; + let result = parse_query_response(&bytes, ExpectedProtocol::Simple).map_err(other)?; + let mut response = backend_frame(b'R', &0_i32.to_be_bytes()); + for index in 0..result.rows().len() { + let name = result + .get_text(index, "name") + .map_err(other)? + .ok_or_else(|| other("null parameter name"))?; + let value = result + .get_text(index, "setting") + .map_err(other)? + .ok_or_else(|| other("null parameter setting"))?; + response.extend(backend_frame(b'S', format!("{name}\0{value}\0").as_bytes())); + } + Ok(response) +} + +fn management_client(mut socket: Socket, shared: &Shared) -> io::Result<()> { + socket.read_timeout(Some(Duration::from_secs(5)))?; + socket.write_timeout(Some(Duration::from_secs(5)))?; + match ipc::read_request(&mut socket).map_err(other)? { + RequestFrame::Authenticate(token) if token == shared.password => {} + _ => { + ipc::write_response( + &mut socket, + ResponseFrame::Error("invalid broker authentication token".into()), + ) + .map_err(other)?; + return Ok(()); + } + } + if shared.owner_connected.swap(true, Ordering::AcqRel) { + ipc::write_response( + &mut socket, + ResponseFrame::Error("broker already has an owner".into()), + ) + .map_err(other)?; + return Ok(()); + } + let result = (|| { + ipc::write_response(&mut socket, ResponseFrame::Ok(Vec::new())).map_err(other)?; + socket.read_timeout(None)?; + loop { + let command = ipc::read_request(&mut socket).map_err(other)?; + match command { + RequestFrame::Backup => { + let (reply, done) = mpsc::channel(); + shared + .commands + .send(Command::Backup(reply)) + .map_err(other)?; + let response = match done.recv().map_err(other)? { + Ok(bytes) => ResponseFrame::Ok(bytes), + Err(error) => ResponseFrame::Error(error.to_string()), + }; + ipc::write_response(&mut socket, response).map_err(other)?; + } + RequestFrame::Close => { + shared.closing.store(true, Ordering::Release); + cancel_execution(shared); + if let Some((active, _)) = shared.active.lock().unwrap().as_ref() { + active.shutdown(); + } + let (reply, done) = mpsc::channel(); + shared + .commands + .send(Command::Shutdown(reply)) + .map_err(other)?; + let response = match done.recv().map_err(other)? { + Ok(()) => ResponseFrame::Ok(Vec::new()), + Err(error) => ResponseFrame::Error(error.to_string()), + }; + ipc::write_response(&mut socket, response).map_err(other)?; + return Ok(()); + } + _ => return Err(other("management accepts only backup or shutdown")), + } + } + })(); + stop(shared); + result +} + +fn sql_client(mut socket: Socket, shared: &Shared) -> io::Result<()> { + socket.read_timeout(Some(Duration::from_secs(5)))?; + socket.write_timeout(Some(Duration::from_secs(5)))?; + let mut startup = read_startup(&mut socket)?; + while matches!( + wire::classify_frontend_message(&startup)?, + wire::FrontendFrameKind::SslOrGssRequest + ) { + if startup.len() != 8 { + return Err(other("invalid encryption request")); + } + socket.write_all(b"N")?; + startup = read_startup(&mut socket)?; + } + if wire::classify_frontend_message(&startup)? == wire::FrontendFrameKind::CancelRequest { + if startup.len() != 16 { + return Err(other("invalid CancelRequest length")); + } + let active = shared.active.lock().unwrap(); + if let Some((_, key)) = active.as_ref() + && startup[8..] == *key + { + let cancel = shared.native.lock().unwrap().0.clone(); + if shared.executing.load(Ordering::Acquire) { + cancel.cancel().map_err(other)?; + } + } + return Ok(()); + } + let parameters = wire::startup_parameters(&startup)?; + if parameters.get("user").copied() != Some(shared.username.as_str()) + || parameters + .get("database") + .copied() + .unwrap_or(&shared.username) + != shared.database + { + socket.write_all(&wire::error_response( + "FATAL", + "28000", + "broker user or database does not match", + ))?; + return Ok(()); + } + for (key, value) in ¶meters { + if !matches!( + *key, + "user" | "database" | "application_name" | "client_encoding" + ) || (*key == "client_encoding" + && !value.eq_ignore_ascii_case("UTF8") + && !value.eq_ignore_ascii_case("UTF-8")) + { + socket.write_all(&wire::error_response( + "FATAL", + "0A000", + "unsupported broker startup parameter", + ))?; + return Ok(()); + } + } + socket.write_all(&backend_frame(b'R', &3_i32.to_be_bytes()))?; + let password = read_frontend(&mut socket)?; + if password.first() != Some(&b'p') + || password.get(5..) != Some(format!("{}\0", shared.password).as_bytes()) + { + socket.write_all(&wire::error_response( + "FATAL", + "28P01", + "invalid broker password", + ))?; + return Ok(()); + } + if shared.occupied.swap(true, Ordering::AcqRel) { + socket.write_all(&wire::error_response( + "FATAL", + "53300", + "broker already has an active SQL connection", + ))?; + return Ok(()); + } + let result = connected_sql( + &mut socket, + shared, + parameters.get("application_name").copied().unwrap_or(""), + ); + shared.active.lock().unwrap().take(); + let (reply, done) = mpsc::channel(); + if shared.commands.send(Command::Reset(reply)).is_ok() { + let _ = done.recv(); + } + shared.occupied.store(false, Ordering::Release); + result +} + +fn connected_sql(socket: &mut Socket, shared: &Shared, application: &str) -> io::Result<()> { + let (reply, done) = mpsc::channel(); + shared + .commands + .send(Command::Startup(application.to_owned(), reply)) + .map_err(other)?; + let mut response = done.recv().map_err(other)??; + let mut key = [0; 8]; + key[..4].copy_from_slice(&std::process::id().to_be_bytes()); + getrandom::fill(&mut key[4..]).map_err(other)?; + response.extend(backend_frame(b'K', &key)); + response.extend(backend_frame(b'Z', b"I")); + *shared.active.lock().unwrap() = Some((socket.clone_socket()?, key)); + socket.write_all(&response)?; + socket.read_timeout(None)?; + let result = exchange(socket, shared); + if result.is_err() { + cancel_execution(shared); + socket.shutdown(); + } + result +} + +fn exchange(socket: &mut Socket, shared: &Shared) -> io::Result<()> { + let mut running: Option>> = None; + let mut closed_input = false; + let result = (|| { + loop { + let frame = read_frontend(socket)?; + let tag = frame[0]; + if tag == b'X' { + if frame.len() != 5 { + return Err(other("invalid Terminate frame")); + } + return Ok(()); + } + if let Some(done) = running.as_ref() { + match done.try_recv() { + Ok(result) => { + result?; + running = None; + } + Err(mpsc::TryRecvError::Disconnected) => { + return Err(other("native worker stopped")); + } + Err(mpsc::TryRecvError::Empty) => {} + } + } + if closed_input + && !matches!(tag, b'd' | b'c' | b'f') + && let Some(done) = running.take() + { + done.recv().map_err(other)??; + } + if running.is_none() { + let (reply, done) = mpsc::channel(); + shared.executing.store(true, Ordering::Release); + shared + .commands + .send(Command::Execute(frame, socket.clone_socket()?, reply)) + .map_err(other)?; + running = Some(done); + } else { + loop { + if shared.stopping.load(Ordering::Acquire) { + return Err(other("broker shutting down")); + } + let input = shared.native.lock().unwrap().1.clone(); + if let Some(token) = input.active_token().map_err(other)? + && input.feed(token, &frame).map_err(other)? + { + break; + } + if let Some(done) = running.as_ref() { + match done.try_recv() { + Ok(result) => { + result?; + return Err(other( + "protocol stream completed before input was accepted", + )); + } + Err(mpsc::TryRecvError::Disconnected) => { + return Err(other("native worker stopped")); + } + Err(mpsc::TryRecvError::Empty) => {} + } + } + thread::sleep(Duration::from_millis(1)); + } + } + closed_input = matches!(tag, b'Q' | b'S' | b'c' | b'f'); + } + })(); + if let Some(done) = running { + cancel_execution(shared); + socket.shutdown(); + if matches!( + done.recv_timeout(Duration::from_secs(3)), + Err(mpsc::RecvTimeoutError::Timeout) + ) { + // A disconnected peer can abandon Parse/Flush or COPY before its + // completion frame. Cancellation cannot manufacture that missing + // protocol input. Retire the helper instead of replaying a query, + // inventing Sync, or leaving native close blocked indefinitely. + eprintln!( + "OLIPHAUNT_BROKER_ERROR disconnected protocol stream did not drain; reopen the database" + ); + std::process::exit(2); + } + } + result +} + +fn read_startup(socket: &mut Socket) -> io::Result> { + let mut header = [0; 4]; + socket.read_exact(&mut header)?; + let length = u32::from_be_bytes(header) as usize; + if !(8..=10_000).contains(&length) { + return Err(other("invalid PostgreSQL startup length")); + } + let mut frame = vec![0; length]; + frame[..4].copy_from_slice(&header); + socket.read_exact(&mut frame[4..])?; + Ok(frame) +} + +fn read_frontend(socket: &mut Socket) -> io::Result> { + let mut header = [0; 5]; + socket.read_exact(&mut header)?; + let length = u32::from_be_bytes(header[1..].try_into().unwrap()) as usize; + if !(4..wire::MAX_FRONTEND_MESSAGE).contains(&length) { + return Err(other("invalid frontend frame length")); + } + let mut frame = vec![0; length + 1]; + frame[..5].copy_from_slice(&header); + socket.read_exact(&mut frame[5..])?; + Ok(frame) +} + +fn backend_frame(tag: u8, body: &[u8]) -> Vec { + let mut frame = vec![tag]; + frame.extend_from_slice(&((body.len() + 4) as u32).to_be_bytes()); + frame.extend_from_slice(body); + frame +} diff --git a/src/broker/tests/postgres_client.rs b/src/broker/tests/postgres_client.rs new file mode 100644 index 000000000..a8afc35fa --- /dev/null +++ b/src/broker/tests/postgres_client.rs @@ -0,0 +1,355 @@ +use oliphaunt_broker::{ + ipc::{self, RequestFrame, ResponseFrame}, + pgwire, +}; +use std::{ + fs, + io::{BufRead, BufReader, Read, Write}, + net::TcpStream, + path::PathBuf, + process::{Child, Command, Stdio}, + thread, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +struct Broker { + child: Child, + root: PathBuf, + sql: String, + control: String, +} +impl Broker { + fn start() -> Self { + for key in ["LIBOLIPHAUNT_PATH", "OLIPHAUNT_INSTALL_DIR"] { + std::env::var_os(key).unwrap_or_else(|| panic!("{key} is required")); + } + let root = std::env::temp_dir().join(format!( + "broker-pgwire-{}-{}", + std::process::id(), + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_nanos() + )); + let executable = std::env::var_os("OLIPHAUNT_BROKER") + .unwrap_or_else(|| env!("CARGO_BIN_EXE_oliphaunt-broker").into()); + let mut child = Command::new(executable) + .args([ + "--root", + root.to_str().unwrap(), + "--listen", + "127.0.0.1:0", + "--control-listen", + "127.0.0.1:0", + ]) + .env("OLIPHAUNT_BROKER_AUTH_TOKEN", "actual-consumer-test-secret") + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .spawn() + .unwrap(); + let mut ready = String::new(); + BufReader::new(child.stdout.take().unwrap()) + .read_line(&mut ready) + .unwrap(); + let mut parts = ready + .trim() + .strip_prefix("OLIPHAUNT_BROKER_READY ") + .expect(&ready) + .split_whitespace(); + let sql = parts + .next() + .unwrap() + .strip_prefix("tcp:") + .unwrap() + .to_owned(); + let control = parts + .next() + .unwrap() + .strip_prefix("control=tcp:") + .unwrap() + .to_owned(); + Self { + child, + root, + sql, + control, + } + } + fn owner(&self) -> TcpStream { + let mut stream = connect(&self.control); + ipc::write_request( + &mut stream, + RequestFrame::Authenticate("actual-consumer-test-secret".into()), + ) + .unwrap(); + assert_eq!( + ipc::read_response(&mut stream).unwrap(), + ResponseFrame::Ok(Vec::new()) + ); + stream + } + fn client(&self) -> (TcpStream, [u8; 8]) { + let mut stream = connect(&self.sql); + let key = pgwire::authenticate( + &mut stream, + "postgres", + "postgres", + "actual-consumer-test-secret", + ) + .unwrap(); + (stream, key) + } + fn reconnect(&self) -> (TcpStream, [u8; 8]) { + let deadline = std::time::Instant::now() + Duration::from_secs(5); + loop { + let mut socket = connect(&self.sql); + match pgwire::authenticate( + &mut socket, + "postgres", + "postgres", + "actual-consumer-test-secret", + ) { + Ok(key) => return (socket, key), + Err(error) + if error + .to_string() + .contains("already has an active SQL connection") + && std::time::Instant::now() < deadline => + { + thread::sleep(Duration::from_millis(5)) + } + Err(error) => panic!("reconnect failed: {error}"), + } + } + } +} +impl Drop for Broker { + fn drop(&mut self) { + let _ = self.child.kill(); + let _ = self.child.wait(); + let _ = fs::remove_dir_all(&self.root); + } +} +fn connect(address: &str) -> TcpStream { + let stream = TcpStream::connect(address).unwrap(); + stream + .set_read_timeout(Some(Duration::from_secs(10))) + .unwrap(); + stream + .set_write_timeout(Some(Duration::from_secs(10))) + .unwrap(); + stream +} +fn frame(tag: u8, body: &[u8]) -> Vec { + let mut bytes = vec![tag]; + bytes.extend_from_slice(&((body.len() + 4) as u32).to_be_bytes()); + bytes.extend_from_slice(body); + bytes +} +fn response(stream: &mut TcpStream) -> Vec { + let mut header = [0; 5]; + stream.read_exact(&mut header).unwrap(); + let length = u32::from_be_bytes(header[1..].try_into().unwrap()) as usize; + let mut bytes = header.to_vec(); + bytes.resize(length + 1, 0); + stream.read_exact(&mut bytes[5..]).unwrap(); + bytes +} +fn query(stream: &mut TcpStream, sql: &str) -> Vec { + let mut result = Vec::new(); + assert!( + pgwire::exchange( + stream, + &oliphaunt_query::simple_query(sql).unwrap(), + &mut |chunk| { + result.extend_from_slice(chunk); + Ok::<_, ()>(()) + } + ) + .unwrap() + .is_none() + ); + result +} + +#[test] +#[ignore = "requires a prepared native runtime; runs the actual broker executable"] +fn postgres_protocol_and_management_are_independent() { + let mut broker = Broker::start(); + let mut owner = broker.owner(); + let (mut client, first_key) = broker.client(); + assert!(String::from_utf8_lossy(&query(&mut client, "SELECT 42")).contains("42")); + let mut other = connect(&broker.sql); + assert!( + pgwire::authenticate( + &mut other, + "postgres", + "postgres", + "actual-consumer-test-secret" + ) + .is_err() + ); + drop(other); + + // Flush produces ParseComplete before the large parameter even exists. + let mut parse = frame(b'P', b"\0SELECT length($1::text)\0\0\0"); + parse.extend(frame(b'H', b"")); + client.write_all(&parse).unwrap(); + assert_eq!(response(&mut client)[0], b'1'); + let parameter = vec![b'x'; 5 * 1024 * 1024]; + let mut bind = b"\0\0\0\0\0\x01".to_vec(); + bind.extend_from_slice(&(parameter.len() as u32).to_be_bytes()); + bind.extend(parameter); + bind.extend_from_slice(&[0, 0]); + let mut rest = frame(b'B', &bind); + rest.extend(frame(b'E', &[0, 0, 0, 0, 0])); + rest.extend(frame(b'S', b"")); + let mut result = Vec::new(); + pgwire::exchange(&mut client, &rest, &mut |chunk| { + result.extend_from_slice(chunk); + Ok::<_, ()>(()) + }) + .unwrap(); + assert!(String::from_utf8_lossy(&result).contains("5242880")); + + // Neither socket direction may depend on the other being fully drained. + let mut pipeline = oliphaunt_query::simple_query("SELECT repeat('x', 6000000)").unwrap(); + pipeline.extend( + oliphaunt_query::extended_statement( + "SELECT length($1::text)", + &[oliphaunt_query::Parameter::text( + "x".repeat(5 * 1024 * 1024), + )], + 0, + ) + .unwrap(), + ); + let failure = std::sync::Arc::new(()); + let retained = pgwire::exchange(&mut client, &pipeline, &mut |_| { + Err(std::sync::Arc::clone(&failure)) + }) + .unwrap() + .unwrap(); + assert!(std::sync::Arc::ptr_eq(&failure, &retained)); + assert!(String::from_utf8_lossy(&query(&mut client, "SELECT 42")).contains("42")); + + query(&mut client, "CREATE TABLE copy_input(value integer)"); + let mut copy = oliphaunt_query::simple_query("COPY copy_input FROM STDIN").unwrap(); + copy.extend(frame(b'd', b"7\n8\n")); + copy.extend(frame(b'c', b"")); + pgwire::exchange(&mut client, ©, &mut |_| Ok::<_, ()>(())).unwrap(); + assert!( + String::from_utf8_lossy(&query(&mut client, "SELECT sum(value) FROM copy_input")) + .contains("15") + ); + + let address = broker.sql.clone(); + let cancel = thread::spawn(move || { + thread::sleep(Duration::from_millis(100)); + pgwire::cancel(&mut connect(&address), &first_key).unwrap(); + }); + let cancelled = query(&mut client, "SELECT pg_sleep(60)"); + cancel.join().unwrap(); + assert!(oliphaunt_query::wire::response_contains_error(&cancelled)); + assert!(String::from_utf8_lossy(&query(&mut client, "SELECT 42")).contains("42")); + + query(&mut client, "CREATE TEMP TABLE transient(value integer)"); + query(&mut client, "BEGIN"); + client.write_all(&frame(b'X', b"")).unwrap(); + drop(client); + // Reconnect retries only the documented single-client admission window. + let deadline = std::time::Instant::now() + Duration::from_secs(5); + let (mut client, second_key) = loop { + let mut socket = connect(&broker.sql); + match pgwire::authenticate( + &mut socket, + "postgres", + "postgres", + "actual-consumer-test-secret", + ) { + Ok(key) => break (socket, key), + Err(_) if std::time::Instant::now() < deadline => { + thread::sleep(Duration::from_millis(5)) + } + Err(error) => panic!("reconnect failed: {error}"), + } + }; + assert_ne!(first_key, second_key); + pgwire::cancel(&mut connect(&broker.sql), &first_key).unwrap(); + assert!(!oliphaunt_query::wire::response_contains_error(&query( + &mut client, + "SELECT pg_sleep(0.1)" + ))); + assert!(oliphaunt_query::wire::response_contains_error(&query( + &mut client, + "SELECT * FROM transient" + ))); + ipc::write_request(&mut owner, RequestFrame::Backup).unwrap(); + assert!( + matches!(ipc::read_response(&mut owner).unwrap(), ResponseFrame::Ok(bytes) if !bytes.is_empty()) + ); + ipc::write_request(&mut owner, RequestFrame::Close).unwrap(); + assert_eq!( + ipc::read_response(&mut owner).unwrap(), + ResponseFrame::Ok(Vec::new()) + ); + assert!(broker.child.wait().unwrap().success()); +} + +#[test] +#[ignore = "requires a prepared native runtime; runs the actual broker executable"] +fn disconnect_and_parent_death_drain_active_native_work() { + let mut broker = Broker::start(); + let owner = broker.owner(); + let (mut client, _) = broker.client(); + client + .write_all( + &oliphaunt_query::simple_query( + "SELECT repeat('x', 10000) FROM generate_series(1, 1000000)", + ) + .unwrap(), + ) + .unwrap(); + assert_eq!(response(&mut client)[0], b'T'); + drop(client); + let (mut client, _) = broker.reconnect(); + assert!(String::from_utf8_lossy(&query(&mut client, "SELECT 42")).contains("42")); + client + .write_all(&oliphaunt_query::simple_query("SELECT pg_sleep(60)").unwrap()) + .unwrap(); + thread::sleep(Duration::from_millis(100)); + drop(owner); + let deadline = std::time::Instant::now() + Duration::from_secs(5); + loop { + if let Some(status) = broker.child.try_wait().unwrap() { + assert!(status.success()); + break; + } + assert!( + std::time::Instant::now() < deadline, + "owner death did not stop active native work" + ); + thread::sleep(Duration::from_millis(5)); + } + + let mut incomplete = Broker::start(); + let _owner = incomplete.owner(); + let (mut client, _) = incomplete.client(); + let mut partial = frame(b'P', b"\0SELECT 42\0\0\0"); + partial.extend(frame(b'H', b"")); + client.write_all(&partial).unwrap(); + assert_eq!(response(&mut client)[0], b'1'); + drop(client); + let deadline = std::time::Instant::now() + Duration::from_secs(5); + loop { + if let Some(status) = incomplete.child.try_wait().unwrap() { + assert!(!status.success()); + break; + } + assert!( + std::time::Instant::now() < deadline, + "abandoned partial protocol must retire the helper" + ); + thread::sleep(Duration::from_millis(5)); + } +} diff --git a/src/broker/tools/audit-dependency-licenses.sh b/src/broker/tools/audit-dependency-licenses.sh new file mode 100644 index 000000000..129961451 --- /dev/null +++ b/src/broker/tools/audit-dependency-licenses.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail +[[ $# == 0 ]] || { echo 'usage: audit-dependency-licenses.sh' >&2; exit 2; } +exec bash "$(dirname "${BASH_SOURCE[0]}")/../../../tools/packaging/audit-rust-dependency-licenses.sh" \ + src/broker/tools/broker-dependency-license-contract.mts oliphaunt-broker diff --git a/src/broker/tools/broker-dependency-license-contract.mts b/src/broker/tools/broker-dependency-license-contract.mts new file mode 100644 index 000000000..280edac71 --- /dev/null +++ b/src/broker/tools/broker-dependency-license-contract.mts @@ -0,0 +1,23 @@ +#!/usr/bin/env bun +import { createRustDependencyLicenseContract } from '../../../tools/packaging/rust-dependency-license-contract.mts'; +const contract = createRustDependencyLicenseContract({ + owner: 'src/broker', + product: 'oliphaunt-broker', + payloadLicense: 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause', + noticeProfile: 'broker', +}); +export const { + RUST_DEPENDENCY_LICENSE_ROOT: BROKER_DEPENDENCY_LICENSE_ROOT, + RUST_PAYLOAD_LICENSE: BROKER_PAYLOAD_LICENSE, + isAllowedRustPathPackageMetadataRow: isAllowedBrokerPathPackageMetadataRow, + hasCanonicalRustFilesystemMode: hasCanonicalBrokerFilesystemMode, + hasSafeRustSourceFilesystemMode: hasSafeBrokerSourceFilesystemMode, + loadRustDependencyLicenseContract: loadBrokerDependencyLicenseContract, + rustDependencyLicenseMembers: brokerDependencyLicenseMembers, + normalizeRustDependencyLicenseModes: normalizeBrokerDependencyLicenseModes, + stageRustDependencyLicenses: stageBrokerDependencyLicenses, + assertRustDependencyLicensesInDirectory: assertBrokerDependencyLicensesInDirectory, + assertRustDependencyLicensesInEntries: assertBrokerDependencyLicensesInEntries, + assertRustDependencyLicensesInArchive: assertBrokerDependencyLicensesInArchive, +} = contract; +if (import.meta.main) contract.runCli(); diff --git a/src/broker/tools/broker-dependency-license-contract.test.mts b/src/broker/tools/broker-dependency-license-contract.test.mts new file mode 100644 index 000000000..8db511b4e --- /dev/null +++ b/src/broker/tools/broker-dependency-license-contract.test.mts @@ -0,0 +1,390 @@ +import assert from 'node:assert/strict'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { archiveDirectory } from '../../../tools/packaging/archive-directory.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../../tools/packaging/release-notices.mts'; +import { currentProductVersionSync } from '../../../tools/release/release-artifact-targets.mts'; +import { + assertBrokerDependencyLicensesInArchive, + assertBrokerDependencyLicensesInDirectory, + assertBrokerDependencyLicensesInEntries, + BROKER_DEPENDENCY_LICENSE_ROOT, + BROKER_PAYLOAD_LICENSE, + brokerDependencyLicenseMembers, + hasCanonicalBrokerFilesystemMode, + hasSafeBrokerSourceFilesystemMode, + isAllowedBrokerPathPackageMetadataRow, + loadBrokerDependencyLicenseContract, + normalizeBrokerDependencyLicenseModes, + stageBrokerDependencyLicenses, +} from './broker-dependency-license-contract.mts'; +import { brokerNpmTarballs } from './package-carriers.mts'; + +const ROOT = path.resolve(import.meta.dirname, '../../..'); +const CONTRACT = path.join(ROOT, 'src/broker/dependency-licenses.json'); +const BROKER_VERSION = currentProductVersionSync( + 'oliphaunt-broker', + 'broker-dependency-license-contract.test.mts', +); +const TARGETS = ['linux-x64-gnu', 'linux-arm64-gnu', 'macos-arm64', 'windows-x64-msvc']; +const TIMEOUT = 120_000; + +function scratch(t, label) { + const directory = realpathSync( + mkdtempSync(path.join(os.tmpdir(), `oliphaunt-broker-license-${label}-`)), + ); + chmodSync(directory, 0o755); + t.after(() => rmSync(directory, { recursive: true, force: true })); + return directory; +} + +function stageCarrier(t, target) { + const directory = scratch(t, target); + stageReleaseNotices(directory, { profile: 'broker' }); + stageBrokerDependencyLicenses(directory, target); + return directory; +} + +function writeMutatedContract(t, mutate) { + const directory = scratch(t, 'contract'); + const contract = JSON.parse(readFileSync(CONTRACT, 'utf8')); + mutate(contract); + const file = path.join(directory, 'dependency-licenses.json'); + writeFileSync(file, `${JSON.stringify(contract, null, 2)}\n`, { mode: 0o644 }); + chmodSync(file, 0o644); + return file; +} + +async function archive(directory, extension) { + const output = `${directory}.${extension}`; + await archiveDirectory(directory, output); + return output; +} + +const packageFixture = process.env.OLIPHAUNT_BROKER_LICENSE_TEST_ROOT; +if (!packageFixture) + throw new Error('Run bash src/broker/tools/broker-dependency-license-contract.test.sh'); + +test('broker local dependency licenses follow Cargo workspace membership', () => { + const row = { + id: 'workspace-bindings', + name: 'liboliphaunt-native-bindings', + version: '17.23.401', + source: null, + license: 'MIT', + manifest_path: path.join(ROOT, 'src/sdks/rust/liboliphaunt-native/Cargo.toml'), + }; + const members = new Set([row.id]); + assert.equal(isAllowedBrokerPathPackageMetadataRow(row, members), true); + for (const changed of [ + { ...row, source: 'registry+https://github.com/rust-lang/crates.io-index' }, + { ...row, id: 'external-path-dependency' }, + { ...row, license: 'Apache-2.0' }, + { ...row, manifest_path: path.join(ROOT, '../external/Cargo.toml') }, + ]) + assert.equal(isAllowedBrokerPathPackageMetadataRow(changed, members), false); +}); + +test('treats direct filesystem modes as POSIX-only metadata', () => { + assert.equal(hasCanonicalBrokerFilesystemMode(0o666, 0o644, 'win32'), true); + assert.equal(hasCanonicalBrokerFilesystemMode(0o666, 0o755, 'win32'), true); + assert.equal(hasCanonicalBrokerFilesystemMode(0o644, 0o644, 'linux'), true); + assert.equal(hasCanonicalBrokerFilesystemMode(0o755, 0o755, 'darwin'), true); + assert.equal(hasCanonicalBrokerFilesystemMode(0o666, 0o644, 'linux'), false); + assert.equal(hasCanonicalBrokerFilesystemMode(0o666, 0o755, 'darwin'), false); + assert.equal(hasSafeBrokerSourceFilesystemMode(0o600, 'linux'), true); + assert.equal(hasSafeBrokerSourceFilesystemMode(0o640, 'darwin'), true); + assert.equal(hasSafeBrokerSourceFilesystemMode(0o644, 'linux'), true); + assert.equal(hasSafeBrokerSourceFilesystemMode(0o664, 'linux'), true); + assert.equal(hasSafeBrokerSourceFilesystemMode(0o666, 'linux'), true); + assert.equal(hasSafeBrokerSourceFilesystemMode(0o755, 'darwin'), false); + assert.equal(hasSafeBrokerSourceFilesystemMode(0o000, 'linux'), false); + assert.equal(hasSafeBrokerSourceFilesystemMode(0o666, 'win32'), true); +}); + +test("target indexes exclude other operating systems' conditional dependencies", { + timeout: TIMEOUT, +}, (t) => { + const indexes = new Map(); + for (const target of TARGETS) { + const directory = stageCarrier(t, target); + assertBrokerDependencyLicensesInDirectory(directory, { target }); + const index = JSON.parse( + readFileSync( + path.join(directory, ...BROKER_DEPENDENCY_LICENSE_ROOT.split('/'), 'DEPENDENCIES.json'), + 'utf8', + ), + ); + assert.equal(index.target, target); + assert.equal(index.payloadLicense, BROKER_PAYLOAD_LICENSE); + indexes.set(target, new Set(index.packages.map(({ name }) => name))); + } + assert.ok(indexes.get('linux-x64-gnu').has('libc')); + assert.ok(!indexes.get('linux-x64-gnu').has('windows-link')); + assert.ok(indexes.get('macos-arm64').has('libc')); + assert.ok(!indexes.get('macos-arm64').has('windows-link')); + assert.ok(indexes.get('windows-x64-msvc').has('windows-link')); + assert.ok(indexes.get('windows-x64-msvc').has('winapi')); + assert.ok(!indexes.get('windows-x64-msvc').has('libc')); +}); + +test('staged and packed closures preserve exact bytes, modes, and members', { + timeout: TIMEOUT, +}, async (t) => { + for (const [target, extension] of [ + ['linux-x64-gnu', 'tar.gz'], + ['windows-x64-msvc', 'zip'], + ]) { + const directory = stageCarrier(t, target); + const packed = await archive(directory, extension); + t.after(() => rmSync(packed, { force: true })); + assertBrokerDependencyLicensesInArchive(packed, { target }); + const expected = brokerDependencyLicenseMembers(target); + assert.ok(expected.includes(`${BROKER_DEPENDENCY_LICENSE_ROOT}/DEPENDENCIES.json`)); + assert.ok( + expected.some((member) => member.startsWith(`${BROKER_DEPENDENCY_LICENSE_ROOT}/licenses/`)), + ); + } + + const extraDirectory = stageCarrier(t, 'linux-x64-gnu'); + writeFileSync( + path.join(extraDirectory, ...BROKER_DEPENDENCY_LICENSE_ROOT.split('/'), 'licenses/extra.txt'), + 'undeclared\n', + { mode: 0o644 }, + ); + const extraArchive = await archive(extraDirectory, 'tar.gz'); + t.after(() => rmSync(extraArchive, { force: true })); + assert.throws( + () => assertBrokerDependencyLicensesInArchive(extraArchive, { target: 'linux-x64-gnu' }), + /unexpected dependency license member/u, + ); +}); + +test('portable archive dependency licenses accept synthetic modes and reject inaccessible modes', { + timeout: TIMEOUT, +}, async (t) => { + const target = 'windows-x64-msvc'; + const directory = stageCarrier(t, target); + const packed = await archive(directory, 'zip'); + t.after(() => rmSync(packed, { force: true })); + const entries = readPortableArchiveEntries(packed); + + const syntheticModes = new Map( + [...entries].map(([member, entry]) => [ + member, + { ...entry, mode: entry.isDirectory ? 0o777 : 0o666 }, + ]), + ); + assertBrokerDependencyLicensesInEntries(syntheticModes, { target }); + + const fileMember = `${BROKER_DEPENDENCY_LICENSE_ROOT}/DEPENDENCIES.json`; + const fileModeDrift = new Map(entries); + fileModeDrift.set(fileMember, { ...entries.get(fileMember), mode: 0o600 }); + assert.throws( + () => assertBrokerDependencyLicensesInEntries(fileModeDrift, { target }), + /dependency license member .* readable.*special permission bits/u, + ); + + const directoryMember = `${BROKER_DEPENDENCY_LICENSE_ROOT}/licenses`; + const directoryModeDrift = new Map(entries); + directoryModeDrift.set(directoryMember, { ...entries.get(directoryMember), mode: 0o700 }); + assert.throws( + () => assertBrokerDependencyLicensesInEntries(directoryModeDrift, { target }), + /dependency license directory .* readable and searchable/u, + ); +}); + +test('real npm target tarballs reopen the exact target-specific dependency closure', { + timeout: TIMEOUT, +}, () => { + const assetDir = path.join(packageFixture, 'assets'); + const packageTargets = new Map([ + ['@oliphaunt/broker-darwin-arm64', 'macos-arm64'], + ['@oliphaunt/broker-linux-arm64-gnu', 'linux-arm64-gnu'], + ['@oliphaunt/broker-linux-x64-gnu', 'linux-x64-gnu'], + ['@oliphaunt/broker-win32-x64-msvc', 'windows-x64-msvc'], + ]); + const tarballs = brokerNpmTarballs(BROKER_VERSION, { assetDir }); + assert.equal(tarballs.length, packageTargets.size); + for (const [packageName, tarball] of tarballs) { + for (const [name, entry] of readPortableArchiveEntries(tarball)) { + assert.ok(entry.mode === 0o644 || entry.mode === 0o755, `${packageName} ${name} mode`); + } + assertBrokerDependencyLicensesInArchive(tarball, { + target: packageTargets.get(packageName), + prefix: 'package', + }); + } +}); + +test('concurrent real Cargo payload packagers are isolated and reopen exact target closures', { + timeout: TIMEOUT, +}, () => { + const outputDirs = ['a', 'b'].map((id) => path.join(packageFixture, `cargo-${id}`)); + const targets = new Map( + TARGETS.map((target) => [`oliphaunt-broker-${target}-${BROKER_VERSION}.crate`, target]), + ); + for (const outputDir of outputDirs) { + const crates = readdirSync(outputDir) + .filter((name) => name.endsWith('.crate')) + .sort(); + assert.deepEqual(crates, [...targets.keys()].sort()); + for (const crate of crates) { + assertBrokerDependencyLicensesInArchive(path.join(outputDir, crate), { + target: targets.get(crate), + prefix: crate.replace(/\.crate$/u, ''), + }); + } + } + for (const crate of targets.keys()) { + assert.deepEqual( + readFileSync(path.join(outputDirs[0], crate)), + readFileSync(path.join(outputDirs[1], crate)), + `${crate} must not depend on its staging directory`, + ); + } +}); + +test('directory closure rejects missing, changed, extra, executable, and symlinked legal members', { + timeout: TIMEOUT, +}, (t) => { + const mutations = [ + ['missing', (directory, member) => rmSync(path.join(directory, ...member.split('/')))], + [ + 'changed', + (directory, member) => writeFileSync(path.join(directory, ...member.split('/')), 'changed\n'), + ], + [ + 'executable', + (directory, member) => chmodSync(path.join(directory, ...member.split('/')), 0o755), + ], + [ + 'extra', + (directory) => + writeFileSync( + path.join(directory, ...BROKER_DEPENDENCY_LICENSE_ROOT.split('/'), 'licenses/extra.txt'), + 'extra\n', + { mode: 0o644 }, + ), + ], + ]; + for (const [label, mutate] of mutations) { + const directory = stageCarrier(t, 'linux-x64-gnu'); + const member = brokerDependencyLicenseMembers('linux-x64-gnu').find((value) => + value.endsWith('.txt'), + ); + mutate(directory, member); + assert.throws( + () => assertBrokerDependencyLicensesInDirectory(directory, { target: 'linux-x64-gnu' }), + /broker dependency license|canonical|mode 0644|unexpected|missing/u, + label, + ); + } + + const directory = stageCarrier(t, 'linux-x64-gnu'); + const licenses = path.join(directory, ...BROKER_DEPENDENCY_LICENSE_ROOT.split('/'), 'licenses'); + const replacement = path.join(directory, 'replacement'); + mkdirSync(replacement, { mode: 0o755 }); + rmSync(licenses, { recursive: true }); + symlinkSync(replacement, licenses, 'dir'); + assert.throws( + () => assertBrokerDependencyLicensesInDirectory(directory, { target: 'linux-x64-gnu' }), + /symlink|missing/u, + ); +}); + +test('staging rejects a symlinked legal namespace ancestor without touching its target', { + timeout: TIMEOUT, +}, (t) => { + const directory = scratch(t, 'symlink-parent-stage'); + const external = scratch(t, 'symlink-parent-external'); + const externalRust = path.join(external, 'rust'); + mkdirSync(externalRust, { mode: 0o755 }); + const sentinel = path.join(externalRust, 'sentinel.txt'); + writeFileSync(sentinel, 'must survive\n', { mode: 0o644 }); + symlinkSync(external, path.join(directory, 'THIRD_PARTY_LICENSES'), 'dir'); + + assert.throws( + () => stageBrokerDependencyLicenses(directory, 'linux-x64-gnu'), + /symlink|non-directory ancestor/u, + ); + assert.throws( + () => normalizeBrokerDependencyLicenseModes(directory, 'linux-x64-gnu'), + /symlink/u, + ); + assert.throws( + () => assertBrokerDependencyLicensesInDirectory(directory, { target: 'linux-x64-gnu' }), + /symlink/u, + ); + assert.equal(readFileSync(sentinel, 'utf8'), 'must survive\n'); +}); + +test('contract mutations cannot omit legal files, change lock identity, lie about a selected branch, or skew target claims', { + timeout: TIMEOUT, +}, (t) => { + { + const file = writeMutatedContract(t, (contract) => { + const legal = contract.packages[0].licenseFiles[0]; + contract.packages[0].licenseFiles[0] = Object.fromEntries(Object.entries(legal).reverse()); + }); + assert.doesNotThrow(() => loadBrokerDependencyLicenseContract({ contractPath: file })); + } + + { + const file = writeMutatedContract(t, (contract) => { + const memchr = contract.packages.find(({ name }) => name === 'memchr'); + memchr.licenseFiles = memchr.licenseFiles.filter(({ name }) => name !== 'UNLICENSE'); + }); + assert.throws( + () => loadBrokerDependencyLicenseContract({ contractPath: file }), + /license blobs differ/u, + ); + } + + { + const file = writeMutatedContract(t, (contract) => { + contract.packages[0].checksum = '0'.repeat(64); + }); + assert.throws( + () => loadBrokerDependencyLicenseContract({ contractPath: file, auditLock: true }), + /Cargo\.lock identity changed/u, + ); + } + + { + const file = writeMutatedContract(t, (contract) => { + contract.packages.find(({ name }) => name === 'libloading').selectedLicense = 'MIT'; + }); + assert.throws( + () => loadBrokerDependencyLicenseContract({ contractPath: file }), + /selects MIT but declares ISC/u, + ); + } + + { + const file = writeMutatedContract(t, (contract) => { + const { name, version } = contract.packages.find(({ name }) => name === 'libc'); + const key = `${name}@${version}`; + contract.targets['linux-x64-gnu'].packages = contract.targets[ + 'linux-x64-gnu' + ].packages.filter((value) => value !== key); + }); + assert.throws( + () => loadBrokerDependencyLicenseContract({ contractPath: file }), + /package graph and package target claims disagree/u, + ); + } +}); diff --git a/src/broker/tools/broker-dependency-license-contract.test.sh b/src/broker/tools/broker-dependency-license-contract.test.sh new file mode 100644 index 000000000..5906499a9 --- /dev/null +++ b/src/broker/tools/broker-dependency-license-contract.test.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +bun="$(command -v bun)" +export OLIPHAUNT_BROKER_LICENSE_TEST_ROOT +OLIPHAUNT_BROKER_LICENSE_TEST_ROOT="$(mktemp -d)" +trap 'rm -rf "$OLIPHAUNT_BROKER_LICENSE_TEST_ROOT"' EXIT +scratch="$OLIPHAUNT_BROKER_LICENSE_TEST_ROOT" +mkdir -p "$scratch/empty-path" "$scratch/empty-cargo-home" "$scratch/offline" +contract=src/broker/tools/broker-dependency-license-contract.mts +PATH="$scratch/empty-path" CARGO_HOME="$scratch/empty-cargo-home" \ + "$bun" "$contract" stage "$scratch/offline" --target linux-x64-gnu +"$bun" "$contract" check-directory "$scratch/offline" --target linux-x64-gnu + +version="$("$bun" tools/release/product-version.mts version oliphaunt-broker)" +"$bun" src/broker/tools/create-release-fixture.mts --asset-dir "$scratch/assets" --version "$version" +package() { + PATH="$scratch/empty-path" CARGO_HOME="$scratch/empty-cargo-home" \ + "$bun" src/broker/tools/package_broker_cargo_artifacts.mts \ + --asset-dir "$scratch/assets" --output-dir "$scratch/cargo-$1" \ + --source-output-dir "$scratch/source-$1" --version "$version" \ + > "$scratch/package-$1.log" 2>&1 +} +package a & first=$! +package b & second=$! +status=0 +wait "$first" || status=1 +wait "$second" || status=1 +if [ "$status" -ne 0 ]; then + cat "$scratch/package-a.log" "$scratch/package-b.log" >&2 + exit "$status" +fi +mkdir -p "$scratch/extracted" +for crate in "$scratch/cargo-a/"*.crate; do + tar -xzf "$crate" -C "$scratch/extracted" + package_name="$(basename "$crate" .crate)" + OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD=1 cargo check --offline \ + --manifest-path "$scratch/extracted/$package_name/Cargo.toml" \ + --target-dir "$scratch/cargo-check" +done +"$bun" test --timeout=30000 ./src/broker/tools/broker-dependency-license-contract.test.mts diff --git a/tools/release/build-linux-broker-baseline.sh b/src/broker/tools/build-linux-broker-baseline.sh similarity index 97% rename from tools/release/build-linux-broker-baseline.sh rename to src/broker/tools/build-linux-broker-baseline.sh index fd635f69f..0f1983add 100755 --- a/tools/release/build-linux-broker-baseline.sh +++ b/src/broker/tools/build-linux-broker-baseline.sh @@ -16,7 +16,7 @@ require() { } if [ "$#" -ne 1 ]; then - fail "usage: tools/release/build-linux-broker-baseline.sh TARGET_DIR" + fail "usage: src/broker/tools/build-linux-broker-baseline.sh TARGET_DIR" fi if [ "$(uname -s)" != "Linux" ]; then fail "the Linux broker baseline build must run on Linux" @@ -42,6 +42,8 @@ case "$target_dir" in /*) ;; *) target_dir="$root/$target_dir" ;; esac +require realpath +target_dir="$(realpath -m "$target_dir")" case "$target_dir" in "$root/target"/*) ;; *) fail "TARGET_DIR must be below $root/target" ;; diff --git a/src/broker/tools/check-release-assets.mts b/src/broker/tools/check-release-assets.mts new file mode 100644 index 000000000..b1455e324 --- /dev/null +++ b/src/broker/tools/check-release-assets.mts @@ -0,0 +1,237 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import path from 'node:path'; +import { finalizeHelperAssets } from '../../../tools/packaging/finalize-helper-assets.mts'; +import { inspectPlatformBinaryEntries } from '../../../tools/packaging/platform-binary-contract.mts'; +import { + assertFileExists, + checksumManifest, + readArchiveEntries, + sha256, +} from '../../../tools/packaging/release-asset-validation.mts'; +import { + inspectPortableExecutable, + WINDOWS_VC_RUNTIME_DLLS, + WINDOWS_VC_RUNTIME_RECEIPT, + windowsVcRuntimeImports, +} from '../../../tools/packaging/windows-vc-runtime-closure.mts'; +import { + artifactTargets, + compareText, + currentProductVersion, + expectedAssets, + fail, + ROOT, +} from '../../../tools/release/release-artifact-targets.mts'; +import { assertBrokerDependencyLicensesInEntries } from './broker-dependency-license-contract.mts'; + +const PREFIX = 'check-broker-release-assets.mts'; +const PRODUCT = 'oliphaunt-broker'; +const KIND = 'broker-helper'; + +function parseArgs(argv) { + const args = { + assetDir: path.join(ROOT, 'target/oliphaunt-broker/release-assets'), + allowPartial: false, + }; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--asset-dir') { + const value = argv[index + 1]; + if (!value) { + fail(PREFIX, '--asset-dir requires a value'); + } + args.assetDir = path.resolve(value); + index += 1; + } else if (arg === '--allow-partial') { + args.allowPartial = true; + } else { + fail(PREFIX, `unknown argument ${arg}`); + } + } + return args; +} + +async function validateArchive(file, target) { + const entries = await readArchiveEntries(file, fail, PREFIX, 'broker'); + try { + assertBrokerDependencyLicensesInEntries(entries, { + target: target.target, + label: path.basename(file), + }); + } catch (error) { + fail(PREFIX, error instanceof Error ? error.message : String(error)); + } + const executable = target.executableRelativePath; + if (!entries.has(executable)) { + fail(PREFIX, `${path.basename(file)} is missing ${executable}`); + } + if (!entries.has('manifest.properties')) { + fail(PREFIX, `${path.basename(file)} is missing manifest.properties`); + } + const broker = entries.get(executable); + if (!broker.isFile) { + fail(PREFIX, `${path.basename(file)} ${executable} is not a regular file`); + } + if (file.endsWith('.tar.gz') && (broker.mode & 0o111) === 0) { + fail(PREFIX, `${path.basename(file)} ${executable} is not executable`); + } + if (path.extname(file) === '.zip' && broker.size === 0) { + fail(PREFIX, `${path.basename(file)} ${executable} is empty`); + } + if (target.target === 'windows-x64-msvc') { + const allowed = new Set(WINDOWS_VC_RUNTIME_DLLS); + const required = new Set(); + const pending = windowsVcRuntimeImports( + Buffer.from(broker.data()), + `${path.basename(file)}:${executable}`, + ).map((name) => name.toLowerCase()); + while (pending.length > 0) { + const name = pending.shift(); + if (!allowed.has(name)) { + fail(PREFIX, `${path.basename(file)} imports undeclared or debug VC runtime ${name}`); + } + if (required.has(name)) continue; + const member = `bin/${name}`; + const entry = entries.get(member); + if (!entry?.isFile || entry.size <= 0) { + fail(PREFIX, `${path.basename(file)} is missing import-derived app-local ${member}`); + } + let inspected; + try { + inspected = inspectPortableExecutable( + Buffer.from(entry.data()), + `${path.basename(file)}:${member}`, + ); + } catch (error) { + fail(PREFIX, error instanceof Error ? error.message : String(error)); + } + if (inspected.machine !== 0x8664 || inspected.magic !== 0x20b) { + fail(PREFIX, `${path.basename(file)} ${member} is not an x64 PE32+ image`); + } + required.add(name); + pending.push( + ...windowsVcRuntimeImports( + Buffer.from(entry.data()), + `${path.basename(file)}:${member}`, + ).map((value) => value.toLowerCase()), + ); + pending.sort(compareText); + } + const actual = WINDOWS_VC_RUNTIME_DLLS.filter((name) => entries.has(`bin/${name}`)); + if (actual.join('\0') !== [...required].sort(compareText).join('\0')) { + fail( + PREFIX, + `${path.basename(file)} app-local VC runtime members must exactly match its PE import closure`, + ); + } + const receiptMember = `bin/${WINDOWS_VC_RUNTIME_RECEIPT}`; + const receiptEntry = entries.get(receiptMember); + if (!receiptEntry?.isFile) { + fail(PREFIX, `${path.basename(file)} is missing ${receiptMember}`); + } + const receipt = Buffer.from(receiptEntry.data()).toString('utf8'); + const expectedReceipt = [...required] + .sort(compareText) + .map((name) => { + const digest = createHash('sha256') + .update(Buffer.from(entries.get(`bin/${name}`).data())) + .digest('hex'); + return `${digest} ${name}\n`; + }) + .join(''); + if (receipt !== expectedReceipt) { + fail( + PREFIX, + `${path.basename(file)} ${receiptMember} does not exactly bind its app-local VC runtime bytes`, + ); + } + const manifest = Buffer.from(entries.get('manifest.properties').data()).toString('utf8'); + const expectedLine = `windowsVcRuntimeDlls=${[...required].sort(compareText).join(',')}`; + if (!manifest.split(/\r?\n/u).includes(expectedLine)) { + fail(PREFIX, `${path.basename(file)} manifest.properties must declare ${expectedLine}`); + } + } + inspectPlatformBinaryEntries( + [...entries].map(([name, entry]) => ({ name, ...entry })), + { target: target.target, rootLabel: path.basename(file) }, + ); +} + +export async function checkBrokerReleaseAssets(argv = Bun.argv.slice(2)) { + if (argv.includes('--aggregate')) + argv = await finalizeHelperAssets(PRODUCT, KIND, argv, { + assetDir: + process.env.OLIPHAUNT_BROKER_RELEASE_ASSETS ?? + path.join(ROOT, 'target/oliphaunt-broker/release-assets'), + npmPackageDir: undefined, + }); + const args = parseArgs(argv); + const version = await currentProductVersion(PRODUCT, PREFIX); + const requiredAssets = expectedAssets(PRODUCT, KIND, version, PREFIX); + const targets = artifactTargets(PRODUCT, KIND, PREFIX); + const targetsByAsset = new Map( + targets.map((target) => [target.asset.replaceAll('{version}', version), target]), + ); + const missing = []; + for (const asset of requiredAssets) { + if (!(await assertFileExists(path.join(args.assetDir, asset)))) { + missing.push(asset); + } + } + if (missing.length > 0) { + if (!args.allowPartial) { + fail(PREFIX, `missing oliphaunt-broker release asset(s): ${missing.join(', ')}`); + } + let presentBrokerAssets = 0; + for (const target of targets) { + if ( + await assertFileExists( + path.join(args.assetDir, target.asset.replaceAll('{version}', version)), + ) + ) { + presentBrokerAssets += 1; + } + } + if (presentBrokerAssets === 0) { + fail( + PREFIX, + 'partial oliphaunt-broker release asset validation requires at least one broker asset', + ); + } + } + + const checksumAsset = `oliphaunt-broker-${version}-release-assets.sha256`; + const checksumPath = path.join(args.assetDir, checksumAsset); + if (!(await assertFileExists(checksumPath))) { + fail(PREFIX, `missing checksum manifest: ${checksumAsset}`); + } + const checksums = await checksumManifest(checksumPath, fail, PREFIX); + for (const asset of requiredAssets.sort(compareText)) { + const assetPath = path.join(args.assetDir, asset); + if (args.allowPartial && !(await assertFileExists(assetPath))) { + continue; + } + if (asset === checksumAsset) { + continue; + } + const expected = checksums.get(asset); + if (!expected) { + fail(PREFIX, `${checksumAsset} does not cover ${asset}`); + } + const actual = await sha256(assetPath); + if (actual !== expected) { + fail(PREFIX, `checksum mismatch for ${asset}: expected ${expected}, got ${actual}`); + } + } + for (const [asset, target] of targetsByAsset) { + const assetPath = path.join(args.assetDir, asset); + if (args.allowPartial && !(await assertFileExists(assetPath))) { + continue; + } + await validateArchive(assetPath, target); + } + console.log(`oliphaunt-broker release assets validated: ${args.assetDir}`); +} + +if (import.meta.main) await checkBrokerReleaseAssets(); diff --git a/src/broker/tools/create-release-fixture.mts b/src/broker/tools/create-release-fixture.mts new file mode 100644 index 000000000..8a34219d6 --- /dev/null +++ b/src/broker/tools/create-release-fixture.mts @@ -0,0 +1,123 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import fs from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; + +import { stageBrokerDependencyLicenses } from './broker-dependency-license-contract.mts'; +import { stageReleaseNotices } from '../../../tools/packaging/release-notices.mts'; + +import { + elfFixture, + machoFixture, + parseCommonArgs, + windowsPeFixture, + writeChecksumManifest, + writeEntriesArchive, +} from '../../../tools/packaging/testdata/release-fixture-utils.mts'; + +function brokerBinary(target) { + if (target === 'macos-arm64') { + return machoFixture({ platform: 1, minos: [11, 0, 0] }); + } + if (target === 'linux-x64-gnu') { + return elfFixture({ machine: 62, requiredVersions: ['GLIBC_2.17'] }); + } + if (target === 'linux-arm64-gnu') { + return elfFixture({ machine: 183, requiredVersions: ['GLIBC_2.17'] }); + } + throw new Error(`unsupported broker release fixture target ${target}`); +} + +async function carrierLegalEntries(target) { + const stage = await fs.realpath( + await fs.mkdtemp(path.join(os.tmpdir(), 'oliphaunt-broker-fixture-legal-')), + ); + await fs.chmod(stage, 0o755); + try { + stageReleaseNotices(stage, { profile: 'broker' }); + stageBrokerDependencyLicenses(stage, target); + const entries = {}; + async function walk(directory, relative = '') { + for (const entry of await fs.readdir(directory, { withFileTypes: true })) { + const member = relative ? `${relative}/${entry.name}` : entry.name; + const file = path.join(directory, entry.name); + if (entry.isDirectory()) { + await walk(file, member); + } else if (entry.isFile()) { + entries[member] = await fs.readFile(file); + } else { + throw new Error(`unexpected broker legal fixture entry ${file}`); + } + } + } + await walk(stage); + return entries; + } finally { + await fs.rm(stage, { recursive: true, force: true }); + } +} + +async function brokerEntries(target, executable) { + return { + ...(await carrierLegalEntries(target)), + [executable]: brokerBinary(target), + 'manifest.properties': [ + 'schema=oliphaunt-broker-release-assets-v1', + 'product=oliphaunt-broker', + `target=${target}`, + `binary=${executable}`, + '', + ].join('\n'), + }; +} + +async function windowsBrokerEntries() { + const runtimeName = 'vcruntime140.dll'; + const executable = windowsPeFixture({ imports: ['VCRUNTIME140.dll'] }); + const runtime = windowsPeFixture({ imports: ['KERNEL32.dll'] }); + const digest = createHash('sha256').update(runtime).digest('hex'); + return { + ...(await carrierLegalEntries('windows-x64-msvc')), + 'bin/oliphaunt-broker.exe': executable, + [`bin/${runtimeName}`]: runtime, + 'bin/windows-vc-runtime.sha256': `${digest} ${runtimeName}\n`, + 'manifest.properties': [ + 'schema=oliphaunt-broker-release-assets-v1', + 'product=oliphaunt-broker', + 'target=windows-x64-msvc', + 'binary=bin/oliphaunt-broker.exe', + `windowsVcRuntimeDlls=${runtimeName}`, + '', + ].join('\n'), + }; +} + +async function writeFixtureAssets(assetDir, version) { + await fs.mkdir(assetDir, { recursive: true }); + const executableModes = { + 'bin/oliphaunt-broker': 0o755, + 'bin/oliphaunt-broker.exe': 0o755, + }; + + for (const target of ['macos-arm64', 'linux-x64-gnu', 'linux-arm64-gnu']) { + await writeEntriesArchive( + path.join(assetDir, `oliphaunt-broker-${version}-${target}.tar.gz`), + await brokerEntries(target, 'bin/oliphaunt-broker'), + executableModes, + ); + } + + await writeEntriesArchive( + path.join(assetDir, `oliphaunt-broker-${version}-windows-x64-msvc.zip`), + await windowsBrokerEntries(), + executableModes, + ); + await writeChecksumManifest(assetDir, `oliphaunt-broker-${version}-release-assets.sha256`); +} + +const { assetDir, version } = parseCommonArgs( + Bun.argv.slice(2), + 'Create small oliphaunt-broker release-shaped assets for SDK checks.', +); +await writeFixtureAssets(assetDir, version); diff --git a/tools/release/package-broker-assets.sh b/src/broker/tools/package-broker-assets.sh similarity index 78% rename from tools/release/package-broker-assets.sh rename to src/broker/tools/package-broker-assets.sh index e5f7ceebe..d7611f31b 100755 --- a/tools/release/package-broker-assets.sh +++ b/src/broker/tools/package-broker-assets.sh @@ -7,7 +7,7 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)" || { } cd "$root" -version="$(tools/dev/bun.sh tools/release/product-version.mjs version oliphaunt-broker)" +version="$(tools/dev/bun.sh tools/release/product-version.mts version oliphaunt-broker)" out_dir="${OLIPHAUNT_BROKER_RELEASE_ASSETS:-$root/target/oliphaunt-broker/release-assets}" stage_root="$root/target/oliphaunt-broker/release-stage" host_os="$(uname -s)" @@ -52,7 +52,7 @@ mkdir -p "$stage/bin" "$out_dir" if [[ "$target_id" == linux-*-gnu ]]; then cargo_target_dir="$cargo_target_dir/linux-abi-baseline" broker_bin="$cargo_target_dir/release/$broker_stage_name" - tools/release/build-linux-broker-baseline.sh "$cargo_target_dir" + src/broker/tools/build-linux-broker-baseline.sh "$cargo_target_dir" else cargo build -p oliphaunt-broker --release --locked fi @@ -60,20 +60,20 @@ fi cp "$broker_bin" "$stage/bin/$broker_stage_name" chmod 0755 "$stage/bin/$broker_stage_name" -tools/dev/bun.sh tools/release/strip_native_release_binaries.mjs "$stage" +bash tools/packaging/strip-native-binaries.sh "$stage" vc_runtime_dlls="" if [ "$target_id" = "windows-x64-msvc" ]; then - vc_runtime_dlls="$(bun tools/release/windows-vc-runtime-closure.mjs stage \ + vc_runtime_dlls="$(bun tools/packaging/windows-vc-runtime-closure.mts stage \ --root "$stage" \ --destination "$stage/bin" \ --print-required)" - bun tools/release/windows-vc-runtime-closure.mjs verify \ + bun tools/packaging/windows-vc-runtime-closure.mts verify \ --root "$stage" \ --search-root "$stage/bin" fi -tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target_id" --root "$stage" +tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target_id" --root "$stage" if [[ "$target_id" == linux-*-gnu ]]; then - tools/release/check-linux-consumer-baseline.sh --target "$target_id" --root "$stage" + tools/packaging/check-linux-consumer-baseline.sh --target "$target_id" --root "$stage" fi cat >"$stage/manifest.properties" <>"$stage/manifest.properties" fi -tools/dev/bun.sh tools/release/release-notices.mjs stage "$stage" --profile broker -tools/dev/bun.sh tools/release/broker-dependency-license-contract.mjs stage \ +tools/dev/bun.sh tools/packaging/release-notices.mts stage "$stage" --profile broker +tools/dev/bun.sh src/broker/tools/broker-dependency-license-contract.mts stage \ "$stage" \ --target "$target_id" -src/shared/artifact-packaging/archive-directory.mjs "$stage" "$out_dir/$asset" -tools/dev/bun.sh tools/release/broker-dependency-license-contract.mjs check-archive \ +tools/packaging/archive-directory.mts "$stage" "$out_dir/$asset" +tools/dev/bun.sh src/broker/tools/broker-dependency-license-contract.mts check-archive \ "$out_dir/$asset" \ --target "$target_id" @@ -110,7 +110,7 @@ if [ -n "$input_dirs" ]; then fi ( - tools/release/write_checksum_manifest.mjs \ + tools/packaging/write-checksum-manifest.mts \ --asset-dir "$out_dir" \ --output "$checksum_asset" \ --pattern 'oliphaunt-broker-*.tar.gz' \ @@ -120,5 +120,5 @@ check_args=(--asset-dir "$out_dir") if [ "${OLIPHAUNT_RELEASE_ASSET_PARTIAL:-0}" = "1" ]; then check_args+=(--allow-partial) fi -bun tools/release/check-broker-release-assets.mjs "${check_args[@]}" +bun src/broker/tools/check-release-assets.mts "${check_args[@]}" echo "oliphauntBrokerReleaseAssetDir=$out_dir" diff --git a/src/broker/tools/package-carriers.mts b/src/broker/tools/package-carriers.mts new file mode 100644 index 000000000..8e7533bfb --- /dev/null +++ b/src/broker/tools/package-carriers.mts @@ -0,0 +1,149 @@ +#!/usr/bin/env bun +import path from 'node:path'; +import { + ROOT, + currentProductVersionSync, +} from '../../../tools/release/release-artifact-targets.mts'; +import { + TOOL, + artifactNpmPackageTargets, + copyStagedRuntimeAssets, + extractReleaseArchiveFile, + fail, + isDirectory, + packStagedNpmCarrier, + rel, + stageNpmPackageDescriptor, + stageWindowsVcRuntimeMembers, + validatePackedNpmPackage, +} from '../../../tools/packaging/release-carrier.mts'; +import { readdirSync } from 'node:fs'; +import { writeChecksumManifest } from '../../../tools/packaging/write-checksum-manifest.mts'; +import { checkBrokerReleaseAssets } from './check-release-assets.mts'; +import { + assertReleaseNoticesInDirectory, + releaseNoticeRows, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { + BROKER_PAYLOAD_LICENSE, + assertBrokerDependencyLicensesInArchive, + assertBrokerDependencyLicensesInDirectory, + brokerDependencyLicenseMembers, + normalizeBrokerDependencyLicenseModes, +} from './broker-dependency-license-contract.mts'; +import { extractPortableArchiveTree } from '../../../tools/packaging/portable-archive.mts'; + +export const BROKER_PRODUCT = 'oliphaunt-broker'; + +const BROKER_KIND = 'broker-helper'; + +const BROKER_PACKAGE_ROOT = path.join(ROOT, 'src/broker/packages'); + +function hasBrokerReleaseArchive(assetDir) { + if (!isDirectory(assetDir)) { + return false; + } + return readdirSync(assetDir).some( + (name) => + name.startsWith('oliphaunt-broker-') && (name.endsWith('.tar.gz') || name.endsWith('.zip')), + ); +} + +async function ensureBrokerReleaseAssets() { + const assetDir = path.join(ROOT, 'target/oliphaunt-broker/release-assets'); + if (!hasBrokerReleaseArchive(assetDir)) { + copyStagedRuntimeAssets({ + product: BROKER_PRODUCT, + destination: assetDir, + envName: 'OLIPHAUNT_BROKER_RELEASE_ASSET_INPUT_DIRS', + patterns: ['oliphaunt-broker-*.tar.gz', 'oliphaunt-broker-*.zip'], + }); + } + const version = currentProductVersionSync(BROKER_PRODUCT, TOOL); + await writeChecksumManifest([ + '--asset-dir', + rel(assetDir), + '--output', + `oliphaunt-broker-${version}-release-assets.sha256`, + '--pattern', + 'oliphaunt-broker-*.tar.gz', + '--pattern', + 'oliphaunt-broker-*.zip', + ]); + await checkBrokerReleaseAssets(['--asset-dir', rel(assetDir)]); +} + +function brokerNpmPackageTargets(version) { + return artifactNpmPackageTargets({ + product: BROKER_PRODUCT, + kind: BROKER_KIND, + surface: 'typescript-broker', + packageRoot: BROKER_PACKAGE_ROOT, + version, + }); +} + +export function brokerNpmTarballs( + version, + { assetDir = path.join(ROOT, 'target/oliphaunt-broker/release-assets') } = {}, +) { + const tarballs = []; + for (const [packageName, packageDir, target] of brokerNpmPackageTargets(version)) { + const executableRelativePath = target.executable_relative_path; + if (typeof executableRelativePath !== 'string' || executableRelativePath.length === 0) { + fail( + `${target.id} must declare executable_relative_path for npm artifact package publication`, + ); + } + const stageDir = stageNpmPackageDescriptor(packageName, packageDir, version, { + target: target.target, + }); + stageReleaseNotices(stageDir, { profile: 'broker' }); + assertReleaseNoticesInDirectory(stageDir, { profile: 'broker' }); + const archive = path.join(assetDir, target.asset.replaceAll('{version}', version)); + assertBrokerDependencyLicensesInArchive(archive, { target: target.target }); + extractReleaseArchiveFile( + archive, + executableRelativePath, + path.join(stageDir, executableRelativePath), + { mode: 0o755 }, + ); + extractPortableArchiveTree( + archive, + path.join(stageDir, 'THIRD_PARTY_LICENSES/rust'), + 'THIRD_PARTY_LICENSES/rust', + ); + normalizeBrokerDependencyLicenseModes(stageDir, target.target); + assertBrokerDependencyLicensesInDirectory(stageDir, { target: target.target }); + const vcRuntimeMembers = stageWindowsVcRuntimeMembers(archive, stageDir, target.target, 'bin'); + const tarball = packStagedNpmCarrier(stageDir); + const requiredMembers = [ + `package/${executableRelativePath}`, + ...vcRuntimeMembers.map((member) => `package/${member}`), + ...releaseNoticeRows({ profile: 'broker' }).map((row) => `package/${row.member}`), + ...brokerDependencyLicenseMembers(target.target, { prefix: 'package' }), + ]; + const manifest = validatePackedNpmPackage({ + packageName, + version, + tarball, + requiredMembers, + executableMembers: [`package/${executableRelativePath}`], + }); + if (manifest.license !== BROKER_PAYLOAD_LICENSE) { + fail(`${rel(tarball)} package license must be ${BROKER_PAYLOAD_LICENSE}`); + } + assertBrokerDependencyLicensesInArchive(tarball, { target: target.target, prefix: 'package' }); + tarballs.push([packageName, tarball]); + } + return tarballs; +} + +export async function packageBrokerCarriers() { + const version = currentProductVersionSync(BROKER_PRODUCT, TOOL); + await ensureBrokerReleaseAssets(); + brokerNpmTarballs(version); +} + +if (import.meta.main) await packageBrokerCarriers(); diff --git a/src/broker/tools/package_broker_cargo_artifacts.mts b/src/broker/tools/package_broker_cargo_artifacts.mts new file mode 100644 index 000000000..b9de636bb --- /dev/null +++ b/src/broker/tools/package_broker_cargo_artifacts.mts @@ -0,0 +1,369 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { chmod, cp, mkdir, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { packageGeneratedCargoSource } from '../../../tools/packaging/cargo-source-package.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { + assertReleaseNoticesInDirectory, + releaseNoticeRows, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { + parseWindowsVcRuntimeReceipt, + WINDOWS_VC_RUNTIME_RECEIPT, +} from '../../../tools/packaging/windows-vc-runtime-closure.mts'; +import { + assertBrokerDependencyLicensesInDirectory, + assertBrokerDependencyLicensesInEntries, + BROKER_PAYLOAD_LICENSE, + brokerDependencyLicenseMembers, + normalizeBrokerDependencyLicenseModes, +} from './broker-dependency-license-contract.mts'; + +const ROOT = path.resolve(import.meta.dir, '../../..'); +const PRODUCT = 'oliphaunt-broker'; +const BROKER_CARRIER_LICENSE = BROKER_PAYLOAD_LICENSE; +const BROKER_NOTICE_OPTIONS = Object.freeze({ profile: 'broker' }); +const CRATES_IO_MAX_BYTES = 10 * 1024 * 1024; +const TARGETS = ['linux-arm64-gnu', 'linux-x64-gnu', 'macos-arm64', 'windows-x64-msvc']; + +function fail(message) { + throw new Error(`package_broker_cargo_artifacts.mts: ${message}`); +} + +function rel(file) { + const relative = path.relative(ROOT, file); + return relative.startsWith('..') ? file : relative; +} + +function usage() { + fail( + 'usage: package_broker_cargo_artifacts.mts [--asset-dir DIR] [--output-dir DIR] [--source-output-dir DIR] [--target TARGET]... [--version VERSION]', + ); +} + +function optionValue(argv, index) { + const value = argv[index + 1]; + if (value === undefined || value.startsWith('--')) { + usage(); + } + return value; +} + +async function parseArgs(argv) { + const args = { + assetDir: 'target/oliphaunt-broker/release-assets', + outputDir: 'target/oliphaunt-broker/cargo-artifacts', + sourceOutputDir: undefined, + targets: [], + version: undefined, + }; + let index = 0; + while (index < argv.length) { + const arg = argv[index]; + if (arg === '--asset-dir') { + args.assetDir = optionValue(argv, index); + index += 2; + } else if (arg === '--output-dir') { + args.outputDir = optionValue(argv, index); + index += 2; + } else if (arg === '--source-output-dir') { + args.sourceOutputDir = optionValue(argv, index); + index += 2; + } else if (arg === '--target') { + args.targets.push(optionValue(argv, index)); + index += 2; + } else if (arg === '--version') { + args.version = optionValue(argv, index); + index += 2; + } else { + usage(); + } + } + return { + assetDir: repoPath(args.assetDir), + outputDir: repoPath(args.outputDir), + sourceOutputDir: + args.sourceOutputDir === undefined ? undefined : repoPath(args.sourceOutputDir), + targets: args.targets, + version: args.version ?? (await currentVersion()), + }; +} + +function repoPath(value) { + return path.isAbsolute(value) ? value : path.join(ROOT, value); +} + +async function currentVersion() { + const manifest = JSON.parse( + await readFile(path.join(ROOT, '.release-please-manifest.json'), 'utf8'), + ); + const version = manifest['broker']; + if (typeof version !== 'string' || version.length === 0) { + fail('.release-please-manifest.json is missing broker'); + } + return version; +} + +function cargoPackageName(targetId) { + return `${PRODUCT}-${targetId}`; +} + +function cargoLinksName(targetId) { + return `oliphaunt_artifact_broker_${targetId.replaceAll('-', '_')}`; +} + +function sourceCrateDir(targetId) { + return path.join(ROOT, 'src/broker/crates', targetId); +} + +async function isDirectory(file) { + try { + return (await stat(file)).isDirectory(); + } catch { + return false; + } +} + +async function isFile(file) { + try { + return (await stat(file)).isFile(); + } catch { + return false; + } +} + +async function extractMember(entries, memberName, destination) { + const entry = entries.get(memberName); + if (!entry?.isFile || entry.isSymbolicLink) fail(`missing regular archive member ${memberName}`); + if (entry.size > 32 * 1024 * 1024) fail(`archive member exceeds 32 MiB: ${memberName}`); + await mkdir(path.dirname(destination), { recursive: true }); + await writeFile(destination, entry.data()); +} + +function targetFromSource(targetId, version) { + return { + target: targetId, + packageName: cargoPackageName(targetId), + sourceDir: sourceCrateDir(targetId), + archiveName: `${PRODUCT}-${version}-${targetId}.${targetId === 'windows-x64-msvc' ? 'zip' : 'tar.gz'}`, + }; +} + +async function copySourceCrate(target, crateDir, version) { + if (!(await isDirectory(target.sourceDir))) { + fail(`${target.target} source Cargo artifact crate is missing: ${rel(target.sourceDir)}`); + } + await rm(crateDir, { recursive: true, force: true }); + await cp(target.sourceDir, crateDir, { recursive: true }); + const cargoTomlPath = path.join(crateDir, 'Cargo.toml'); + const cargoToml = await readFile(cargoTomlPath, 'utf8'); + const metadata = Bun.TOML.parse(cargoToml); + const expectedLinks = cargoLinksName(target.target); + if (metadata?.package?.name !== target.packageName) { + fail( + `${rel(path.join(target.sourceDir, 'Cargo.toml'))} has package.name=${JSON.stringify(metadata?.package?.name)}, expected ${target.packageName}`, + ); + } + if (metadata?.package?.version !== version) { + fail( + `${rel(path.join(target.sourceDir, 'Cargo.toml'))} has package.version=${JSON.stringify(metadata?.package?.version)}, expected ${version}`, + ); + } + if (metadata?.package?.license !== BROKER_CARRIER_LICENSE) { + fail( + `${rel(path.join(target.sourceDir, 'Cargo.toml'))} has package.license=${JSON.stringify(metadata?.package?.license)}, ` + + `expected ${BROKER_CARRIER_LICENSE}`, + ); + } + if (metadata?.package?.links !== expectedLinks) { + fail( + `${rel(path.join(target.sourceDir, 'Cargo.toml'))} has package.links=${JSON.stringify(metadata?.package?.links)}, expected ${expectedLinks}`, + ); + } + if (metadata?.package?.build !== 'build.rs') { + fail(`${rel(path.join(target.sourceDir, 'Cargo.toml'))} must declare build = "build.rs"`); + } + const libRsPath = path.join(crateDir, 'src/lib.rs'); + const libRs = await readFile(libRsPath, 'utf8'); + const constants = Object.fromEntries( + [...libRs.matchAll(/pub const ([A-Z_]+): &str = "([^"]+)";/g)].map((match) => [ + match[1], + match[2], + ]), + ); + for (const [key, value] of Object.entries({ + PRODUCT, + KIND: 'broker-helper', + RELEASE_TARGET: target.target, + })) { + if (constants[key] !== value) { + fail( + `${rel(path.join(target.sourceDir, 'src/lib.rs'))} has ${key}=${JSON.stringify(constants[key])}, expected ${value}`, + ); + } + } + if (typeof constants.CARGO_TARGET !== 'string' || constants.CARGO_TARGET.length === 0) { + fail(`${rel(path.join(target.sourceDir, 'src/lib.rs'))} must declare CARGO_TARGET`); + } + if ( + typeof constants.EXECUTABLE_RELATIVE_PATH !== 'string' || + constants.EXECUTABLE_RELATIVE_PATH.length === 0 + ) { + fail(`${rel(path.join(target.sourceDir, 'src/lib.rs'))} must declare EXECUTABLE_RELATIVE_PATH`); + } + target.executableRelativePath = constants.EXECUTABLE_RELATIVE_PATH; + stageReleaseNotices(crateDir, BROKER_NOTICE_OPTIONS); + assertReleaseNoticesInDirectory(crateDir, BROKER_NOTICE_OPTIONS); +} + +async function sha256File(file) { + const digest = createHash('sha256'); + for await (const chunk of Bun.file(file).stream()) { + digest.update(chunk); + } + return digest.digest('hex'); +} + +async function validateCrate(cratePath, packageName, version, payloadMembers, targetId) { + if (!(await isFile(cratePath))) { + fail(`missing generated Cargo crate ${rel(cratePath)}`); + } + const size = (await stat(cratePath)).size; + if (size > CRATES_IO_MAX_BYTES) { + fail(`${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit`); + } + const expected = new Set([ + `${packageName}-${version}/Cargo.toml`, + `${packageName}-${version}/README.md`, + `${packageName}-${version}/build.rs`, + `${packageName}-${version}/src/lib.rs`, + `${packageName}-${version}/payload/sha256`, + ...releaseNoticeRows(BROKER_NOTICE_OPTIONS).map( + (row) => `${packageName}-${version}/${row.member}`, + ), + ...brokerDependencyLicenseMembers(targetId, { prefix: `${packageName}-${version}` }), + ...payloadMembers.map((member) => `${packageName}-${version}/payload/${member}`), + ]); + const entries = readPortableArchiveEntries(cratePath); + const names = new Set([...entries].filter(([, entry]) => entry.isFile).map(([name]) => name)); + const missing = [...expected].filter((name) => !names.has(name)).sort(); + if (missing.length > 0) { + fail(`${rel(cratePath)} is missing package members: ${missing.join(', ')}`); + } + assertBrokerDependencyLicensesInEntries(entries, { + target: targetId, + prefix: `${packageName}-${version}`, + }); +} + +async function prepareTarget(target, { version, assetDir, sourceRoot }) { + const crateDir = path.join(sourceRoot, target.packageName); + await copySourceCrate(target, crateDir, version); + const archive = path.join(assetDir, target.archiveName); + if (!(await isFile(archive))) { + fail(`missing broker release asset: ${rel(archive)}`); + } + const entries = readPortableArchiveEntries(archive); + assertBrokerDependencyLicensesInEntries(entries, { target: target.target, label: rel(archive) }); + for (const member of brokerDependencyLicenseMembers(target.target)) { + const destination = path.join(crateDir, ...member.split('/')); + await extractMember(entries, member, destination); + await chmod(destination, 0o644); + } + normalizeBrokerDependencyLicenseModes(crateDir, target.target); + assertBrokerDependencyLicensesInDirectory(crateDir, { target: target.target }); + const payload = path.join(crateDir, 'payload', target.executableRelativePath); + await extractMember(entries, target.executableRelativePath, payload); + if ((await stat(payload)).size <= 0) { + fail(`${rel(payload)} must be a non-empty broker helper payload`); + } + await chmod(payload, 0o755); + const payloadMembers = [target.executableRelativePath]; + if (target.target === 'windows-x64-msvc') { + const receiptRelativePath = `bin/${WINDOWS_VC_RUNTIME_RECEIPT}`; + const receiptPath = path.join(crateDir, 'payload', receiptRelativePath); + await extractMember(entries, receiptRelativePath, receiptPath); + const receipt = parseWindowsVcRuntimeReceipt( + await readFile(receiptPath), + `${rel(archive)}:${receiptRelativePath}`, + ); + payloadMembers.push(receiptRelativePath); + for (const [name, digest] of receipt) { + const relativePath = `bin/${name}`; + const destination = path.join(crateDir, 'payload', relativePath); + await extractMember(entries, relativePath, destination); + if ((await sha256File(destination)) !== digest) { + fail(`${rel(archive)} ${relativePath} does not match ${receiptRelativePath}`); + } + payloadMembers.push(relativePath); + } + } + payloadMembers.sort(); + const checksumText = + target.target === 'windows-x64-msvc' + ? `${(await Promise.all(payloadMembers.map(async (member) => `${await sha256File(path.join(crateDir, 'payload', member))} ${member}`))).join('\n')}\n` + : `${await sha256File(payload)}\n`; + await writeFile(path.join(crateDir, 'payload/sha256'), checksumText, 'utf8'); + return { ...target, crateDir, payloadMembers }; +} + +export async function packageBrokerCargoArtifacts(argv = []) { + const args = await parseArgs(argv); + if (!(await isDirectory(args.assetDir))) + fail(`broker release asset directory does not exist: ${rel(args.assetDir)}`); + const unknown = args.targets.filter((target) => !TARGETS.includes(target)); + if (unknown.length) fail(`unsupported broker target(s): ${unknown.join(', ')}`); + const workParent = path.join(ROOT, 'target/oliphaunt-broker/cargo-package-runs'); + await mkdir(workParent, { recursive: true }); + const workRoot = await mkdtemp(path.join(workParent, 'run-')); + try { + const sourceRoot = args.sourceOutputDir ?? path.join(workRoot, 'sources'); + for (const directory of [args.outputDir, sourceRoot]) { + for (const input of [ROOT, args.assetDir]) { + const relative = path.relative(directory, input); + if ( + relative === '' || + (!relative.startsWith('..' + path.sep) && relative !== '..' && !path.isAbsolute(relative)) + ) + fail(`output directory must not contain repository or input assets: ${directory}`); + } + } + await mkdir(sourceRoot, { recursive: true }); + await rm(args.outputDir, { recursive: true, force: true }); + await mkdir(args.outputDir, { recursive: true }); + for (const targetId of TARGETS.filter( + (target) => !args.targets.length || args.targets.includes(target), + )) { + const target = await prepareTarget(targetFromSource(targetId, args.version), { + ...args, + sourceRoot, + }); + const packaged = packageGeneratedCargoSource( + path.join(target.crateDir, 'Cargo.toml'), + args.outputDir, + { fail, rel }, + ); + await validateCrate( + packaged, + target.packageName, + args.version, + target.payloadMembers, + target.target, + ); + console.log(rel(packaged)); + } + } finally { + await rm(workRoot, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + try { + await packageBrokerCargoArtifacts(Bun.argv.slice(2)); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } +} diff --git a/src/broker/tools/test-consumer.sh b/src/broker/tools/test-consumer.sh new file mode 100644 index 000000000..353b7be63 --- /dev/null +++ b/src/broker/tools/test-consumer.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +[[ "$(uname -s):$(uname -m)" == Linux:x86_64 ]] || { + echo 'packed broker consumer uses Linux x64 archives; test-integration supports local source builds' >&2 + exit 2 +} +native_archives=(target/liboliphaunt/desktop-release-assets/linux-x64-gnu/liboliphaunt-*-linux-x64-gnu.tar.gz) +broker_archives=(target/oliphaunt-broker/release-assets/oliphaunt-broker-*-linux-x64-gnu.tar.gz) +[[ ${#native_archives[@]} == 1 && -f "${native_archives[0]}" && ${#broker_archives[@]} == 1 && -f "${broker_archives[0]}" ]] || { + echo 'expected one native runtime and one broker Linux archive from owner package tasks' >&2 + exit 1 +} +consumer="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-broker-consumer.XXXXXX")" +trap 'rm -rf "$consumer"' EXIT HUP INT TERM +mkdir -p "$consumer/native" "$consumer/broker" +tar -xzf "${native_archives[0]}" -C "$consumer/native" --no-same-owner +tar -xzf "${broker_archives[0]}" -C "$consumer/broker" --no-same-owner +export LIBOLIPHAUNT_PATH="$consumer/native/lib/liboliphaunt.so" +export OLIPHAUNT_INSTALL_DIR="$consumer/native/runtime" +export OLIPHAUNT_EMBEDDED_MODULE_DIR="$consumer/native/lib/modules" +export OLIPHAUNT_BROKER="$consumer/broker/bin/oliphaunt-broker" +cargo test -p oliphaunt-broker --locked --test postgres_client -- --ignored diff --git a/src/database-resources/CHANGELOG.md b/src/database-resources/CHANGELOG.md new file mode 100644 index 000000000..6f107ed55 --- /dev/null +++ b/src/database-resources/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +Previous ICU data releases remain available under their original runtime release histories. Database resources become independently versioned from 0.2.1. diff --git a/src/database-resources/README.md b/src/database-resources/README.md new file mode 100644 index 000000000..c971214fb --- /dev/null +++ b/src/database-resources/README.md @@ -0,0 +1,93 @@ +# Database resources + +This product owns PostgreSQL cluster seeds and canonical ICU data. A seed is an +initialized database directory; it contains neither a PostgreSQL runtime nor ICU +data. Existing databases do not need a seed. + +The four selectable profiles are native standard, native ICU, WASIX standard, +and WASIX ICU. Native seeds additionally have a physical target: a seed for +`linux-x64-gnu` is not declared compatible with another architecture or mobile +layout. The compatibility keys are in [contracts/contract.json](contracts/contract.json). +Both ICU profiles reference the same pinned `icudt76l.dat` by its tree digest. +Producing this data carrier copies the verified upstream file; it does not build +PostgreSQL or ICU libraries. + +Android selects `dev.oliphaunt.runtime:oliphaunt-seed-native-android-datum64-standard` +or `dev.oliphaunt.runtime:oliphaunt-seed-native-android-datum64-icu`. The existing +Gradle plugin merges the selected carrier; neither seed is a default dependency. +ICU selection also uses the independently versioned canonical ICU carrier. + +The resource-owned Swift source archive exposes `OliphauntSeedNativeIOSStandard`, +`OliphauntSeedNativeIOSICU`, and `OliphauntICU`. Only the ICU seed target depends on +the ICU data target. These products belong to the resource package, not the SDK. +The archive can be used as a local SwiftPM dependency; automated remote SwiftPM +distribution requires a separate repository identity from the SDK. Downloading +the resource source archive includes both seed profiles, while target selection +controls the resources built into the application. + +From the repository root: + +```sh +moon run database-resources:package-icu +moon run database-resources:build-native-standard +moon run database-resources:build-native-icu +moon run database-resources:build-wasix-standard +moon run database-resources:build-wasix-icu +``` + +The same Moon commands work from this product directory. `moon run +database-resources:test` runs seed and ICU packaging tests +once, without compiling PostgreSQL. Packaging and seed creation use the explicit +profile tasks above; there is no default command that builds every profile. +Android seed production requires the Android NDK; iOS seed and carrier production +requires macOS and Apple SDKs. Existing compiler outputs can be used locally as +shown below without pretending to be a GitHub runner. + +Each seed command produces only the requested profile. To use an existing +compiler output directly, bypass the build prerequisite and provide its prepared +runtime directory: + +```sh +OLIPHAUNT_SEED_RUNTIME_DIR=/path/to/runtime bash src/database-resources/seeds/build.sh native standard +OLIPHAUNT_SEED_RUNTIME_DIR=/path/to/wasix/runtime bash src/database-resources/seeds/build.sh wasix standard +``` + +For ICU profiles, `OLIPHAUNT_ICU_DATA_DIR` can select an existing canonical files +tree. Otherwise the default is `target/database-resources/icu/data/share/icu`. +The standalone WASIX producer is an ordinary private Cargo project in +`seeds/wasix`; its CLI accepts a prepared runtime directory, a new working +directory, one profile, and an ICU directory only for the ICU profile. + +Artifacts are written to `target/database-resources/release-assets`. Each seed +archive contains PGDATA directly and has an adjacent JSON manifest recording its +profile, physical compatibility, producer/initdb hashes, archive checksum, +and required ICU identity. These are frozen outputs of the actual `initdb` run; +two independent initializations are not assumed to have identical bytes. + +The canonical ICU archive contains only `share/icu`, its manifest, size report, +and license notices. Cargo and npm carriers preserve that data-only payload. +The initial independent owner version is 0.2.1, above the completed 0.2.0 ICU +carrier histories; existing published versions remain immutable. + +`package-native`, `package-wasix`, `package-android`, and `package-ios` create +separate npm and Cargo leaves for the corresponding physical targets and profiles. +Each leaf contains one seed. ICU leaves depend on the same canonical ICU carrier; +standard leaves have no ICU dependency. There is no package that installs every +seed, and data packages do not restrict the installation host's OS or CPU. + +Native npm leaves contain unpacked PGDATA and expose `./pgdata/PG_VERSION` and +`./manifest.json`; the manifest includes the digest of the complete directory. +Cargo and WASIX npm leaves retain their compressed seed archive. The iOS npm +leaves also expose a resource-only CocoaPod. The React Native plugin registers +the selected `seedProfile` and ICU pods; resource packages opt out of automatic +linking. Install the selected iOS profile; its seed bundle is separate from the +SDK and canonical ICU data. + +WASIX seed production uses `liboliphaunt-wasix:compiler-output`, whose prepared +runtime lives at `target/oliphaunt-wasix/wasix-build/build/install`. Runtime +packaging uses a separate staging directory so it cannot delete a seed producer's +input while the tasks run concurrently. + +The consumer migration is still in progress. Mobile consumers now select resource +carriers independently, while actual Apple and Android installed applications +remain part of platform qualification. diff --git a/src/database-resources/VERSION b/src/database-resources/VERSION new file mode 100644 index 000000000..0c62199f1 --- /dev/null +++ b/src/database-resources/VERSION @@ -0,0 +1 @@ +0.2.1 diff --git a/src/database-resources/contracts/contract.json b/src/database-resources/contracts/contract.json new file mode 100644 index 000000000..62f1cfc68 --- /dev/null +++ b/src/database-resources/contracts/contract.json @@ -0,0 +1,75 @@ +{ + "schema": "oliphaunt-cluster-seed-contract-v1", + "icuDataSchema": "oliphaunt-icu-data-v1", + "manifests": { + "native": { + "schema": "oliphaunt-runtime-resources-v1", + "layout": "oliphaunt-cluster-seed-v1", + "cacheKeyPattern": "^[A-Za-z0-9._-]{1,128}$", + "cacheKeyDisallowedValues": [".", ".."] + }, + "wasix": { + "schema": "oliphaunt-cluster-seed-v1" + } + }, + "profiles": { + "standard": { + "artifactRole": "cluster-seed-standard", + "requiredRuntimeFeatures": [] + }, + "icu": { + "artifactRole": "cluster-seed-icu", + "requiredRuntimeFeatures": ["icu"] + } + }, + "icu": { + "artifactRole": "icu-data", + "dataForm": "files-le", + "dataVersion": "76.1", + "internalReadinessEnvironment": "OLIPHAUNT_INTERNAL_ICU_READY", + "internalReadinessValue": "1", + "logicalTreeDigest": "sha256(path-nul-size-nul-bytes-lf)", + "runtimePath": "share/icu" + }, + "compatibilityKeys": { + "native": { + "android-datum64": "native-pg18-android-datum64-v1", + "ios-datum64": "native-pg18-ios-datum64-v1", + "linux-arm64-gnu": "native-pg18-linux-arm64-gnu-v1", + "linux-x64-gnu": "native-pg18-linux-x64-gnu-v1", + "macos-arm64": "native-pg18-macos-arm64-v1", + "windows-x64-msvc": "native-pg18-windows-x64-msvc-v1" + }, + "wasixDatum32": "wasix-pg18-datum32-v1" + }, + "pgdataDirectories": [ + "global", + "pg_wal", + "pg_wal/archive_status", + "pg_wal/summaries", + "pg_commit_ts", + "pg_dynshmem", + "pg_notify", + "pg_serial", + "pg_snapshots", + "pg_subtrans", + "pg_twophase", + "pg_multixact", + "pg_multixact/members", + "pg_multixact/offsets", + "base", + "base/1", + "pg_replslot", + "pg_tblspc", + "pg_stat", + "pg_stat_tmp", + "pg_xact", + "pg_logical", + "pg_logical/snapshots", + "pg_logical/mappings" + ], + "physicalFormats": { + "native": "native-pg18-v1", + "wasix": "wasix-pg18-v1" + } +} diff --git a/src/shared/cluster-seed-contract/fixtures/icu.valid.json b/src/database-resources/contracts/fixtures/icu.valid.json similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/icu.valid.json rename to src/database-resources/contracts/fixtures/icu.valid.json diff --git a/src/shared/cluster-seed-contract/fixtures/native-cache-key.invalid.properties b/src/database-resources/contracts/fixtures/native-cache-key.invalid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-cache-key.invalid.properties rename to src/database-resources/contracts/fixtures/native-cache-key.invalid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/native-dot-cache-key.invalid.properties b/src/database-resources/contracts/fixtures/native-dot-cache-key.invalid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-dot-cache-key.invalid.properties rename to src/database-resources/contracts/fixtures/native-dot-cache-key.invalid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/native-dotdot-cache-key.invalid.properties b/src/database-resources/contracts/fixtures/native-dotdot-cache-key.invalid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-dotdot-cache-key.invalid.properties rename to src/database-resources/contracts/fixtures/native-dotdot-cache-key.invalid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/native-extra-field.invalid.properties b/src/database-resources/contracts/fixtures/native-extra-field.invalid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-extra-field.invalid.properties rename to src/database-resources/contracts/fixtures/native-extra-field.invalid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/native-icu.valid.properties b/src/database-resources/contracts/fixtures/native-icu.valid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-icu.valid.properties rename to src/database-resources/contracts/fixtures/native-icu.valid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/native-malformed.invalid.properties b/src/database-resources/contracts/fixtures/native-malformed.invalid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-malformed.invalid.properties rename to src/database-resources/contracts/fixtures/native-malformed.invalid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/native-profile-mismatch.invalid.properties b/src/database-resources/contracts/fixtures/native-profile-mismatch.invalid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-profile-mismatch.invalid.properties rename to src/database-resources/contracts/fixtures/native-profile-mismatch.invalid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/native-standard.valid.properties b/src/database-resources/contracts/fixtures/native-standard.valid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-standard.valid.properties rename to src/database-resources/contracts/fixtures/native-standard.valid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/native-target-mismatch.invalid.properties b/src/database-resources/contracts/fixtures/native-target-mismatch.invalid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-target-mismatch.invalid.properties rename to src/database-resources/contracts/fixtures/native-target-mismatch.invalid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/native-whitespace.invalid.properties b/src/database-resources/contracts/fixtures/native-whitespace.invalid.properties similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/native-whitespace.invalid.properties rename to src/database-resources/contracts/fixtures/native-whitespace.invalid.properties diff --git a/src/shared/cluster-seed-contract/fixtures/profile-mismatch.invalid.json b/src/database-resources/contracts/fixtures/profile-mismatch.invalid.json similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/profile-mismatch.invalid.json rename to src/database-resources/contracts/fixtures/profile-mismatch.invalid.json diff --git a/src/shared/cluster-seed-contract/fixtures/standard.valid.json b/src/database-resources/contracts/fixtures/standard.valid.json similarity index 100% rename from src/shared/cluster-seed-contract/fixtures/standard.valid.json rename to src/database-resources/contracts/fixtures/standard.valid.json diff --git a/src/database-resources/contracts/icu-data.mts b/src/database-resources/contracts/icu-data.mts new file mode 100644 index 000000000..3c7a8f462 --- /dev/null +++ b/src/database-resources/contracts/icu-data.mts @@ -0,0 +1,84 @@ +#!/usr/bin/env bun + +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +import { filesystemTreeRows, logicalTreeSha256, parseProperties } from './native-manifest.mts'; + +export const NATIVE_ICU_DATA_SCHEMA = 'oliphaunt-icu-data-v1'; +export const ICU_DATA_VERSION = '76.1'; +export const ICU_DATA_FORM = 'files-le'; + +const LOWER_SHA256 = /^[0-9a-f]{64}$/u; + +export function parseNativeIcuDataIdentity(bytes, label = 'native ICU data manifest') { + const actual = parseProperties(bytes, label); + const expected = new Map([ + ['schema', NATIVE_ICU_DATA_SCHEMA], + ['artifactRole', 'icu-data'], + ['icuDataVersion', ICU_DATA_VERSION], + ['icuDataForm', ICU_DATA_FORM], + ]); + if (actual.size !== expected.size + 1) throw new Error(`${label}: unexpected fields`); + for (const [key, value] of expected) { + if (actual.get(key) !== value) { + throw new Error( + `${label}: ${key} must be ${JSON.stringify(value)}, got ${JSON.stringify(actual.get(key))}`, + ); + } + } + const dataTreeSha256 = actual.get('icuDataTreeSha256'); + if (!LOWER_SHA256.test(dataTreeSha256 ?? '')) { + throw new Error(`${label}: icuDataTreeSha256 must be a lowercase SHA-256 digest`); + } + return Object.freeze({ + dataVersion: ICU_DATA_VERSION, + dataForm: ICU_DATA_FORM, + dataTreeSha256, + }); +} + +export function nativeIcuDataManifestFromRows(rows) { + const entries = [...rows]; + if (entries.length === 0) throw new Error('native ICU data tree is empty'); + const digest = logicalTreeSha256(entries); + return Buffer.from( + [ + `schema=${NATIVE_ICU_DATA_SCHEMA}`, + 'artifactRole=icu-data', + `icuDataVersion=${ICU_DATA_VERSION}`, + `icuDataForm=${ICU_DATA_FORM}`, + `icuDataTreeSha256=${digest}`, + '', + ].join('\n'), + ); +} + +export function nativeIcuDataManifest(icuData) { + return nativeIcuDataManifestFromRows(filesystemTreeRows(icuData)); +} + +export function validateNativeIcuDataManifestRows(bytes, rows, label = 'native ICU data manifest') { + const identity = parseNativeIcuDataIdentity(bytes, label); + const expected = logicalTreeSha256([...rows]); + if (identity.dataTreeSha256 !== expected) { + throw new Error( + `${label}: icuDataTreeSha256 must be ${JSON.stringify(expected)}, got ${JSON.stringify(identity.dataTreeSha256)}`, + ); + } + return Object.freeze({ icuDataTreeSha256: identity.dataTreeSha256 }); +} + +export function validateNativeIcuDataManifest(bytes, icuData, label = 'native ICU data manifest') { + return validateNativeIcuDataManifestRows(bytes, filesystemTreeRows(icuData), label); +} + +if (import.meta.main) { + const [icuData, output] = process.argv.slice(2); + if (!icuData || !output || process.argv.length !== 4) { + throw new Error('usage: icu-data.mts ICU_DATA_DIR OUTPUT'); + } + const manifest = nativeIcuDataManifest(path.resolve(icuData)); + writeFileSync(path.resolve(output), manifest); + validateNativeIcuDataManifest(readFileSync(path.resolve(output)), path.resolve(icuData), output); +} diff --git a/src/database-resources/contracts/icu-data.test.mts b/src/database-resources/contracts/icu-data.test.mts new file mode 100644 index 000000000..2b8e69575 --- /dev/null +++ b/src/database-resources/contracts/icu-data.test.mts @@ -0,0 +1,28 @@ +import { expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { + nativeIcuDataManifest, + nativeIcuDataManifestFromRows, + validateNativeIcuDataManifest, +} from './icu-data.mts'; + +test('binds the data-only native ICU carrier to its logical tree', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-icu-contract-')); + try { + mkdirSync(path.join(root, 'icudt76l')); + writeFileSync(path.join(root, 'icudt76l/root.res'), 'root\n'); + const manifest = nativeIcuDataManifest(root); + expect(validateNativeIcuDataManifest(manifest, root).icuDataTreeSha256).toHaveLength(64); + writeFileSync(path.join(root, 'icudt76l/root.res'), 'changed\n'); + expect(() => validateNativeIcuDataManifest(manifest, root)).toThrow(/icuDataTreeSha256/u); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('rejects an empty ICU data identity', () => { + expect(() => nativeIcuDataManifestFromRows([])).toThrow(/tree is empty/u); +}); diff --git a/src/database-resources/contracts/moon.yml b/src/database-resources/contracts/moon.yml new file mode 100644 index 000000000..b244e096a --- /dev/null +++ b/src/database-resources/contracts/moon.yml @@ -0,0 +1,31 @@ +$schema: "https://moonrepo.dev/schemas/project.json" + +id: "cluster-seed-contract" +language: "typescript" +layer: "configuration" +stack: "systems" +tags: ["javascript-quality", "postgres", "contract", "runtime"] + +project: + title: "Cluster Seed Contract" + description: "Canonical standard/ICU seed and portable ICU-data identity contract." + owner: "oliphaunt" + +owners: + defaultOwner: "@oliphaunt/core" + paths: + "**/*": ["@oliphaunt/core"] + +fileGroups: + contract: + - "**/*" + - "!moon.yml" + - "!*.test.mts" + +tasks: + test: + tags: ["quality", "unit"] + command: "bun test ./src/database-resources/contracts" + inputs: ["**/*"] + options: + runFromWorkspaceRoot: true diff --git a/src/database-resources/contracts/native-manifest.mts b/src/database-resources/contracts/native-manifest.mts new file mode 100644 index 000000000..16915c49c --- /dev/null +++ b/src/database-resources/contracts/native-manifest.mts @@ -0,0 +1,328 @@ +#!/usr/bin/env bun + +import { createHash } from 'node:crypto'; +import { lstatSync, readdirSync, readFileSync } from 'node:fs'; +import path from 'node:path'; + +const CONTRACT = JSON.parse(readFileSync(new URL('./contract.json', import.meta.url), 'utf8')); +const SHA256 = /^[0-9a-f]{64}$/u; +const CACHE_KEY = new RegExp(CONTRACT.manifests.native.cacheKeyPattern, 'u'); +const DISALLOWED_CACHE_KEYS = new Set(CONTRACT.manifests.native.cacheKeyDisallowedValues); +export const NATIVE_PGDATA_DIRECTORIES: readonly string[] = Object.freeze( + CONTRACT.pgdataDirectories, +); + +/** Package installers may discard empty tar directories; retain their actual paths. */ +export function emptyDirectoryPaths(root) { + const directories = []; + for (const entry of readdirSync(root, { recursive: true, withFileTypes: true })) { + if (!entry.isDirectory()) continue; + const directory = path.join(entry.parentPath, entry.name); + if (readdirSync(directory).length === 0) + directories.push(path.relative(root, directory).split(path.sep).join('/')); + } + return directories.sort(); +} + +export function validNativeCacheKey(value) { + return CACHE_KEY.test(value) && !DISALLOWED_CACHE_KEYS.has(value); +} + +export const NATIVE_CLUSTER_SEED_TARGETS = Object.freeze( + Object.keys(CONTRACT.compatibilityKeys.native).sort(), +); + +export const NATIVE_CLUSTER_SEED_MANIFEST_KEYS = Object.freeze([ + 'schema', + 'layout', + 'artifactRole', + 'catalogProfile', + 'target', + 'postgresMajor', + 'physicalFormat', + 'compatibilityKey', + 'initialSuperuser', + 'icuDataVersion', + 'icuDataForm', + 'icuDataTreeSha256', + 'runtimeFeatures', + 'cacheKey', +]); + +export function nativeClusterSeedCompatibilityKey(target) { + const key = CONTRACT.compatibilityKeys.native[target]; + if (typeof key !== 'string') { + throw new Error(`unsupported native cluster-seed target ${JSON.stringify(target)}`); + } + return key; +} + +export function bindNativeClusterSeedManifest(bytes, target, profile) { + const source = parseProperties(bytes, 'native cluster seed producer manifest'); + const profileContract = CONTRACT.profiles[profile]; + if (profileContract === undefined) { + throw new Error(`native cluster seed producer manifest: unsupported profile ${profile}`); + } + const expectedSource = new Map([ + ['schema', CONTRACT.manifests.native.schema], + ['layout', CONTRACT.manifests.native.layout], + ['artifactRole', profileContract.artifactRole], + ['catalogProfile', profile], + ['postgresMajor', '18'], + ['physicalFormat', CONTRACT.physicalFormats.native], + ['initialSuperuser', 'postgres'], + ['icuDataVersion', profile === 'icu' ? CONTRACT.icu.dataVersion : ''], + ['icuDataForm', profile === 'icu' ? CONTRACT.icu.dataForm : ''], + ['runtimeFeatures', profileContract.requiredRuntimeFeatures.join(',')], + ]); + const expectedSourceKeys = new Set([...expectedSource.keys(), 'icuDataTreeSha256', 'cacheKey']); + if ( + source.size !== expectedSourceKeys.size || + [...source.keys()].some((key) => !expectedSourceKeys.has(key)) + ) { + throw new Error( + 'native cluster seed producer manifest: expected the exact unbound producer field set', + ); + } + for (const [key, value] of expectedSource) { + if (source.get(key) !== value) { + throw new Error( + `native cluster seed producer manifest: ${key} must be ${JSON.stringify(value)}`, + ); + } + } + const cacheKey = source.get('cacheKey'); + if (typeof cacheKey !== 'string' || !validNativeCacheKey(cacheKey)) { + throw new Error( + 'native cluster seed producer manifest: cacheKey must be a portable identifier', + ); + } + const values = new Map([ + ...expectedSource, + ['target', target], + ['compatibilityKey', nativeClusterSeedCompatibilityKey(target)], + ['icuDataTreeSha256', source.get('icuDataTreeSha256') ?? ''], + ['cacheKey', cacheKey], + ]); + return Buffer.from( + `${NATIVE_CLUSTER_SEED_MANIFEST_KEYS.map((key) => `${key}=${values.get(key)}`).join('\n')}\n`, + ); +} + +export function parseProperties(bytes, label) { + const text = Buffer.from(bytes).toString('utf8'); + if (!Buffer.from(text, 'utf8').equals(Buffer.from(bytes))) { + throw new Error(`${label} is not canonical UTF-8`); + } + const values = new Map(); + for (const [index, line] of text.split(/\r?\n/u).entries()) { + if (line.length === 0) continue; + const separator = line.indexOf('='); + if (separator <= 0) throw new Error(`${label}:${index + 1} is not key=value`); + const key = line.slice(0, separator); + if (values.has(key)) throw new Error(`${label}:${index + 1} repeats ${key}`); + values.set(key, line.slice(separator + 1)); + } + return values; +} + +export function validateNativeClusterSeedManifest(bytes, profile, options = {}) { + const label = options.label ?? `${profile} native cluster seed manifest`; + const target = options.target; + const compatibilityKey = nativeClusterSeedCompatibilityKey(target); + const profileContract = CONTRACT.profiles[profile]; + if (profileContract === undefined) throw new Error(`${label}: unsupported profile ${profile}`); + const values = parseProperties(bytes, label); + const expected = new Map([ + ['schema', CONTRACT.manifests.native.schema], + ['layout', CONTRACT.manifests.native.layout], + ['artifactRole', profileContract.artifactRole], + ['catalogProfile', profile], + ['postgresMajor', '18'], + ['physicalFormat', CONTRACT.physicalFormats.native], + ['target', target], + ['compatibilityKey', compatibilityKey], + ['initialSuperuser', 'postgres'], + ['runtimeFeatures', profileContract.requiredRuntimeFeatures.join(',')], + ['icuDataVersion', profile === 'icu' ? CONTRACT.icu.dataVersion : ''], + ['icuDataForm', profile === 'icu' ? CONTRACT.icu.dataForm : ''], + ['icuDataTreeSha256', profile === 'icu' ? options.icuDataTreeSha256 : ''], + ]); + if ( + values.size !== NATIVE_CLUSTER_SEED_MANIFEST_KEYS.length || + NATIVE_CLUSTER_SEED_MANIFEST_KEYS.some((key) => !values.has(key)) + ) { + throw new Error( + `${label}: fields must be exactly ${NATIVE_CLUSTER_SEED_MANIFEST_KEYS.join(',')}`, + ); + } + if (!validNativeCacheKey(values.get('cacheKey') ?? '')) { + throw new Error(`${label}: cacheKey must be a portable identifier`); + } + if (profile === 'icu' && !SHA256.test(options.icuDataTreeSha256 ?? '')) { + throw new Error(`${label}: requires the exact lowercase ICU data tree SHA-256`); + } + for (const [key, value] of expected) { + if (values.get(key) !== value) { + throw new Error( + `${label}: ${key} must be ${JSON.stringify(value)}, got ${JSON.stringify(values.get(key))}`, + ); + } + } + return values; +} + +export function logicalTreeSha256(rows) { + const normalized = [...rows].map(({ path: relative, bytes }) => { + if (typeof relative !== 'string' || relative.length === 0 || relative.includes('\0')) { + throw new Error(`logical tree contains an invalid path: ${JSON.stringify(relative)}`); + } + const normalizedPath = relative.replaceAll('\\', '/'); + const components = normalizedPath.split('/'); + if ( + normalizedPath.startsWith('/') || + components.some( + (component) => component.length === 0 || component === '.' || component === '..', + ) + ) { + throw new Error(`logical tree contains an unsafe path: ${JSON.stringify(relative)}`); + } + return { path: normalizedPath, bytes: Buffer.from(bytes) }; + }); + normalized.sort((left, right) => Buffer.compare(Buffer.from(left.path), Buffer.from(right.path))); + for (let index = 1; index < normalized.length; index += 1) { + if (normalized[index - 1].path === normalized[index].path) { + throw new Error(`logical tree repeats path ${JSON.stringify(normalized[index].path)}`); + } + } + const digest = createHash('sha256'); + for (const row of normalized) { + digest.update(row.path); + digest.update(Buffer.of(0)); + digest.update(String(row.bytes.length)); + digest.update(Buffer.of(0)); + digest.update(row.bytes); + digest.update('\n'); + } + return digest.digest('hex'); +} + +export function filesystemTreeRows(root) { + const absoluteRoot = path.resolve(root); + const rows = []; + visitRegularFileTree(absoluteRoot, 'logical tree', (file) => { + rows.push({ + path: path.relative(absoluteRoot, file).split(path.sep).join('/'), + bytes: readFileSync(file), + }); + }); + return rows; +} + +function visitRegularFileTree(root, label, onFile) { + const visit = (entry) => { + const metadata = lstatSync(entry); + if (metadata.isSymbolicLink()) throw new Error(`${label} contains a symlink: ${entry}`); + if (metadata.isFile()) { + onFile(entry); + return; + } + if (!metadata.isDirectory()) throw new Error(`${label} contains a special file: ${entry}`); + for (const name of readdirSync(entry).sort()) visit(path.join(entry, name)); + }; + visit(root); +} + +export function validatePgdataDirectories(pgdata) { + for (const directory of NATIVE_PGDATA_DIRECTORIES) { + const metadata = lstatSync(path.join(pgdata, directory)); + if (!metadata.isDirectory()) throw new Error(`${pgdata} has an unsafe or missing ${directory}`); + } +} + +export function validateNativeClusterSeedDirectory(seed, profile, options = {}) { + validatePgdataDirectories(path.join(seed, 'files')); + for (const relative of [ + 'files', + 'files/PG_VERSION', + 'files/global/pg_control', + 'manifest.properties', + ]) { + const file = path.join(seed, ...relative.split('/')); + const expectedDirectory = relative === 'files'; + const metadata = lstatSync(file); + if ( + metadata.isSymbolicLink() || + (expectedDirectory ? !metadata.isDirectory() : !metadata.isFile()) + ) { + throw new Error(`${seed} has an unsafe or missing ${relative}`); + } + } + const pgVersion = readFileSync(path.join(seed, 'files/PG_VERSION'), 'utf8').trim(); + if (pgVersion !== '18') + throw new Error(`${seed} has PostgreSQL ${JSON.stringify(pgVersion)}, expected 18`); + if (lstatSync(path.join(seed, 'files/global/pg_control')).size === 0) { + throw new Error(`${seed} has an empty files/global/pg_control`); + } + const files = path.join(seed, 'files'); + const rootEntries = new Set(readdirSync(files)); + for (const transient of ['postmaster.pid', 'postmaster.opts']) { + if (rootEntries.has(transient)) throw new Error(`${seed} contains transient ${transient}`); + } + visitRegularFileTree(files, 'native cluster seed', () => {}); + const icuDataTreeSha256 = + options.icuData === undefined + ? undefined + : logicalTreeSha256(filesystemTreeRows(options.icuData)); + validateNativeClusterSeedManifest(readFileSync(path.join(seed, 'manifest.properties')), profile, { + target: options.target, + icuDataTreeSha256, + label: path.join(seed, 'manifest.properties'), + }); + return { icuDataTreeSha256 }; +} + +function main(args) { + const values = new Map(); + for (let index = 0; index < args.length; index += 2) { + const key = args[index]; + const value = args[index + 1]; + if (!key?.startsWith('--') || value === undefined) { + throw new Error( + 'usage: native-cluster-seed-contract.mts --profile standard|icu --target TARGET --seed DIR [--icu-data DIR]', + ); + } + values.set(key.slice(2), value); + } + const profile = values.get('profile'); + const target = values.get('target'); + const seed = values.get('seed'); + if ( + !(profile === 'standard' || profile === 'icu') || + target === undefined || + seed === undefined + ) { + throw new Error( + 'usage: native-cluster-seed-contract.mts --profile standard|icu --target TARGET --seed DIR [--icu-data DIR]', + ); + } + const icuData = values.get('icu-data'); + const { icuDataTreeSha256 } = validateNativeClusterSeedDirectory(seed, profile, { + icuData, + target, + }); + process.stdout.write( + `profile=${profile}\ntarget=${target}\nicuDataTreeSha256=${icuDataTreeSha256 ?? ''}\n`, + ); +} + +if (import.meta.main) { + try { + main(process.argv.slice(2)); + } catch (error) { + console.error( + `native-cluster-seed-contract.mts: ${error instanceof Error ? error.message : String(error)}`, + ); + process.exit(2); + } +} diff --git a/src/database-resources/contracts/native-manifest.test.mts b/src/database-resources/contracts/native-manifest.test.mts new file mode 100644 index 000000000..f1aaf6fb2 --- /dev/null +++ b/src/database-resources/contracts/native-manifest.test.mts @@ -0,0 +1,179 @@ +import { expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { + bindNativeClusterSeedManifest, + logicalTreeSha256, + NATIVE_PGDATA_DIRECTORIES, + validateNativeClusterSeedDirectory, + validateNativeClusterSeedManifest, +} from './native-manifest.mts'; + +function fixture(name) { + return readFileSync(new URL(`./fixtures/${name}`, import.meta.url)); +} + +test('keeps process-argument profile probes independent of the host code page', () => { + const probe = readFileSync(new URL('./profile-probe.json', import.meta.url)); + expect(probe.every((byte) => byte <= 0x7f)).toBe(true); +}); + +test('validates independent standard and ICU native cluster seed roles', () => { + const target = 'linux-x64-gnu'; + const digest = logicalTreeSha256([ + { path: 'icudt76l/coll/en.res', bytes: Buffer.from('en\n') }, + { path: 'icudt76l/root.res', bytes: Buffer.from('root\n') }, + ]); + expect(() => + validateNativeClusterSeedManifest(fixture('native-standard.valid.properties'), 'standard', { + target, + }), + ).not.toThrow(); + expect(() => + validateNativeClusterSeedManifest(fixture('native-icu.valid.properties'), 'icu', { + target, + icuDataTreeSha256: 'a'.repeat(64), + }), + ).not.toThrow(); + expect(() => + validateNativeClusterSeedManifest(fixture('native-icu.valid.properties'), 'icu', { + target, + icuDataTreeSha256: digest, + }), + ).toThrow(/icuDataTreeSha256/u); +}); + +test('rejects the shared malformed, extra-field, cache-key, target, and profile vectors', () => { + for (const name of [ + 'native-malformed.invalid.properties', + 'native-whitespace.invalid.properties', + 'native-cache-key.invalid.properties', + 'native-dot-cache-key.invalid.properties', + 'native-dotdot-cache-key.invalid.properties', + 'native-extra-field.invalid.properties', + 'native-target-mismatch.invalid.properties', + 'native-profile-mismatch.invalid.properties', + ]) { + expect( + () => + validateNativeClusterSeedManifest(fixture(name), 'standard', { + target: 'linux-x64-gnu', + }), + name, + ).toThrow(); + } +}); + +test('canonicalizes producer manifests and rejects extra public fields', () => { + const producer = Buffer.from( + [ + 'schema=oliphaunt-runtime-resources-v1', + 'layout=oliphaunt-cluster-seed-v1', + 'artifactRole=cluster-seed-standard', + 'catalogProfile=standard', + 'postgresMajor=18', + 'physicalFormat=native-pg18-v1', + 'initialSuperuser=postgres', + 'icuDataVersion=', + 'icuDataForm=', + 'icuDataTreeSha256=', + 'runtimeFeatures=', + 'cacheKey=0123456789abcdef', + '', + ].join('\n'), + ); + const canonical = bindNativeClusterSeedManifest(producer, 'ios-datum64', 'standard'); + expect(() => + validateNativeClusterSeedManifest(canonical, 'standard', { + target: 'ios-datum64', + }), + ).not.toThrow(); + expect(canonical.toString('utf8')).not.toContain('mode='); + expect(() => + bindNativeClusterSeedManifest( + Buffer.concat([producer, Buffer.from('mode=native-server\n')]), + 'ios-datum64', + 'standard', + ), + ).toThrow(/exact unbound producer field set/u); + expect(() => + validateNativeClusterSeedManifest( + Buffer.concat([canonical, Buffer.from('extra=value\n')]), + 'standard', + { + target: 'ios-datum64', + }, + ), + ).toThrow(/fields must be exactly/u); +}); + +test('logical ICU digest is metadata-independent and path-sensitive', () => { + const one = logicalTreeSha256([{ path: 'a.res', bytes: Buffer.from('x') }]); + const reordered = logicalTreeSha256([ + { path: 'b.res', bytes: Buffer.from('y') }, + { path: 'a.res', bytes: Buffer.from('x') }, + ]); + const canonical = logicalTreeSha256([ + { path: 'a.res', bytes: Buffer.from('x') }, + { path: 'b.res', bytes: Buffer.from('y') }, + ]); + expect(reordered).toBe(canonical); + expect(one).not.toBe(canonical); + expect(() => + logicalTreeSha256([ + { path: 'a/b', bytes: Buffer.from('x') }, + { path: 'a\\b', bytes: Buffer.from('x') }, + ]), + ).toThrow(/repeats path/u); + expect(() => logicalTreeSha256([{ path: '../outside', bytes: Buffer.from('x') }])).toThrow( + /unsafe path/u, + ); +}); + +test('requires a complete regular native PGDATA seed tree', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-seed-contract-')); + const seed = path.join(root, 'seed'); + try { + for (const directory of NATIVE_PGDATA_DIRECTORIES) + mkdirSync(path.join(seed, 'files', directory), { recursive: true }); + writeFileSync(path.join(seed, 'files/PG_VERSION'), '18\n'); + writeFileSync(path.join(seed, 'files/global/pg_control'), 'control\n'); + writeFileSync( + path.join(seed, 'manifest.properties'), + fixture('native-standard.valid.properties'), + ); + expect(() => + validateNativeClusterSeedDirectory(seed, 'standard', { + target: 'linux-x64-gnu', + }), + ).not.toThrow(); + + for (const directory of ['pg_notify', 'pg_wal/archive_status', 'pg_multixact/offsets']) { + rmSync(path.join(seed, 'files', directory), { recursive: true }); + expect(() => + validateNativeClusterSeedDirectory(seed, 'standard', { target: 'linux-x64-gnu' }), + ).toThrow(); + mkdirSync(path.join(seed, 'files', directory)); + } + writeFileSync(path.join(seed, 'files/postmaster.pid'), '1\n'); + expect(() => + validateNativeClusterSeedDirectory(seed, 'standard', { + target: 'linux-x64-gnu', + }), + ).toThrow(/transient postmaster[.]pid/u); + rmSync(path.join(seed, 'files/postmaster.pid')); + + if (process.platform !== 'win32') { + symlinkSync('PG_VERSION', path.join(seed, 'files/linked-version')); + expect(() => + validateNativeClusterSeedDirectory(seed, 'standard', { + target: 'linux-x64-gnu', + }), + ).toThrow(/symlink/u); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/src/shared/cluster-seed-contract/profile-probe.json b/src/database-resources/contracts/profile-probe.json similarity index 100% rename from src/shared/cluster-seed-contract/profile-probe.json rename to src/database-resources/contracts/profile-probe.json diff --git a/src/database-resources/icu/cargo/Cargo.toml b/src/database-resources/icu/cargo/Cargo.toml new file mode 100644 index 000000000..9183727a0 --- /dev/null +++ b/src/database-resources/icu/cargo/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "oliphaunt-icu" +version = "0.2.1" +edition = "2024" +rust-version = "1.93" +description = "Optional ICU data files for Oliphaunt runtimes." +readme = "README.md" +repository = "https://github.com/f0rr0/oliphaunt" +homepage = "https://oliphaunt.dev" +documentation = "https://docs.rs/oliphaunt-icu" +license = "MIT AND Unicode-3.0" +links = "oliphaunt_artifact_oliphaunt_icu" +build = "build.rs" +include = [ + "Cargo.toml", + "README.md", + "build.rs", + "build-support.rs", + "src/**", + "payload/**", + "LICENSE", + "THIRD_PARTY_NOTICES.md", + "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", + "THIRD_PARTY_LICENSES/ICU-LICENSE", +] + +[lib] +path = "src/lib.rs" + +[build-dependencies] +sha2 = "0.10" +tar = "0.4" +zstd = { version = "0.13", default-features = false } diff --git a/src/runtimes/liboliphaunt/icu/README.md b/src/database-resources/icu/cargo/README.md similarity index 100% rename from src/runtimes/liboliphaunt/icu/README.md rename to src/database-resources/icu/cargo/README.md diff --git a/src/database-resources/icu/cargo/build-support.rs b/src/database-resources/icu/cargo/build-support.rs new file mode 100644 index 000000000..e1e70aef3 --- /dev/null +++ b/src/database-resources/icu/cargo/build-support.rs @@ -0,0 +1,348 @@ +use std::env; +use std::fs; +use std::io::{self, Read}; +use std::path::{Component, Path, PathBuf}; + +use sha2::{Digest, Sha256}; + +const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1"; +const ARTIFACT_PRODUCT: &str = "oliphaunt-icu"; +const ARTIFACT_KIND: &str = "icu-data"; +const ARTIFACT_TARGET: &str = "portable"; +const PACKAGED_ICU_ARCHIVE: &str = "payload/icu-data.tar.zst"; + +fn main() { + println!("cargo:rerun-if-env-changed=OLIPHAUNT_ICU_DATA_DIR"); + println!("cargo:rerun-if-env-changed=OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD"); + + let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo")); + let out = out_dir.join("generated_icu.rs"); + if let Some(archive) = find_packaged_icu_archive() { + println!("cargo:rerun-if-changed={}", archive.display()); + let extracted_root = unpack_icu_archive(&archive, &out_dir.join("icu-data-expanded")); + emit_icu_artifact(&out, &out_dir, &archive, &extracted_root); + } else if PACKAGE_LOCAL { + panic!("published ICU carrier requires package-local data archive"); + } else if let Some(icu_root) = find_icu_data_root() { + emit_rerun_directives(&icu_root); + let archive = out_dir.join("icu-data.tar.zst"); + write_icu_archive(&icu_root, &archive); + emit_icu_artifact(&out, &out_dir, &archive, &icu_root); + } else { + if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() { + panic!( + "release packaging requires package-local ICU data under payload/icu-data.tar.zst or payload/share/icu" + ); + } + write_generated_icu(&out, None); + } +} + +fn emit_icu_artifact(out: &Path, out_dir: &Path, archive: &Path, icu_root: &Path) { + let archive_sha256 = sha256_file(archive).expect("digest ICU data archive"); + let data_tree_sha256 = logical_tree_sha256(icu_root).expect("digest ICU logical data tree"); + write_generated_icu(out, Some((archive, &archive_sha256, &data_tree_sha256))); + emit_artifact_manifest(out_dir, icu_root, &data_tree_sha256); +} + +fn find_packaged_icu_archive() -> Option { + let manifest_dir = + PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set")); + let archive = manifest_dir.join(PACKAGED_ICU_ARCHIVE); + archive.is_file().then_some(archive) +} + +fn find_icu_data_root() -> Option { + let manifest_dir = + PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set")); + for candidate in icu_candidates(&manifest_dir) { + if let Some(root) = canonical_icu_data_root(&candidate) { + return Some(root); + } + } + None +} + +fn icu_candidates(manifest_dir: &Path) -> Vec { + let mut candidates = Vec::new(); + candidates.push(manifest_dir.join("payload/share/icu")); + if let Some(path) = env::var_os("OLIPHAUNT_ICU_DATA_DIR") { + candidates.push(PathBuf::from(path)); + } + candidates +} + +fn unpack_icu_archive(archive: &Path, destination: &Path) -> PathBuf { + if destination.exists() { + fs::remove_dir_all(destination).expect("remove previously unpacked ICU data archive"); + } + fs::create_dir_all(destination).expect("create ICU data archive destination"); + let file = fs::File::open(archive).expect("open packaged ICU data archive"); + let decoder = zstd::stream::read::Decoder::new(file).expect("decode packaged ICU data archive"); + let mut archive_reader = tar::Archive::new(decoder); + let entries = archive_reader + .entries() + .expect("read packaged ICU data archive entries"); + let mut entry_count = 0_usize; + for entry in entries { + entry_count += 1; + assert!( + entry_count <= 8192, + "packaged ICU data archive has too many entries" + ); + let mut entry = entry.expect("read packaged ICU data archive entry"); + let path = entry + .path() + .expect("read packaged ICU data archive entry path") + .into_owned(); + let relative = icu_archive_relative_path(&path); + let destination_path = destination.join(&relative); + let entry_type = entry.header().entry_type(); + if entry_type.is_dir() { + fs::create_dir_all(&destination_path).expect("create ICU data archive directory"); + continue; + } + if !entry_type.is_file() { + panic!( + "packaged ICU data archive entry {} has unsupported type {:?}", + path.display(), + entry_type + ); + } + if let Some(parent) = destination_path.parent() { + fs::create_dir_all(parent).expect("create ICU data archive entry parent"); + } + entry + .unpack(&destination_path) + .expect("unpack packaged ICU data archive entry"); + } + let root = destination.join("share/icu"); + canonical_icu_data_root(&root).expect("packaged ICU data archive contains share/icu data") +} + +fn icu_archive_relative_path(path: &Path) -> PathBuf { + let mut relative = PathBuf::new(); + let mut components = Vec::new(); + for component in path.components() { + match component { + Component::CurDir => {} + Component::Normal(part) => { + relative.push(part); + components.push(part.to_owned()); + } + _ => panic!("unsafe packaged ICU data archive entry {}", path.display()), + } + } + let under_share_icu = components.first().and_then(|part| part.to_str()) == Some("share") + && components.get(1).and_then(|part| part.to_str()) == Some("icu"); + if !under_share_icu { + panic!( + "packaged ICU data archive entry {} must stay under share/icu", + path.display() + ); + } + relative +} + +fn canonical_icu_data_root(candidate: &Path) -> Option { + if icu_root_contains_data(candidate) { + return Some(candidate.to_path_buf()); + } + let entries = fs::read_dir(candidate).ok()?; + let mut dirs = entries + .filter_map(Result::ok) + .map(|entry| entry.path()) + .filter(|path| path.is_dir()) + .collect::>(); + dirs.sort(); + dirs.into_iter().find(|path| icu_root_contains_data(path)) +} + +fn icu_root_contains_data(root: &Path) -> bool { + let Ok(entries) = fs::read_dir(root) else { + return false; + }; + for entry in entries.flatten() { + let path = entry.path(); + let name = entry.file_name().to_string_lossy().into_owned(); + if path.is_file() && name.starts_with("icudt") && name.ends_with(".dat") { + return true; + } + if path.is_dir() && name.starts_with("icudt") && directory_has_file(&path) { + return true; + } + } + false +} + +fn directory_has_file(path: &Path) -> bool { + fs::read_dir(path) + .ok() + .into_iter() + .flatten() + .flatten() + .any(|entry| entry.path().is_file()) +} + +fn emit_rerun_directives(root: &Path) { + println!("cargo:rerun-if-changed={}", root.display()); + for path in collect_files(root).expect("collect ICU data files for rerun tracking") { + println!("cargo:rerun-if-changed={}", path.display()); + } +} + +fn write_icu_archive(icu_root: &Path, archive: &Path) { + let file = fs::File::create(archive).expect("create ICU data archive"); + let encoder = zstd::stream::write::Encoder::new(file, 19).expect("create zstd encoder"); + let mut builder = tar::Builder::new(encoder); + for source in collect_files(icu_root).expect("collect ICU data files") { + let relative = source + .strip_prefix(icu_root) + .expect("ICU file stays under ICU root"); + let archive_path = Path::new("share/icu").join(relative); + let bytes = fs::read(&source).expect("read ICU data file"); + let mut header = tar::Header::new_gnu(); + header.set_size(bytes.len() as u64); + header.set_mode(0o644); + header.set_uid(0); + header.set_gid(0); + header.set_mtime(0); + header.set_cksum(); + builder + .append_data(&mut header, &archive_path, bytes.as_slice()) + .expect("append ICU data file"); + } + let encoder = builder.into_inner().expect("finish ICU tar archive"); + encoder.finish().expect("finish ICU zstd archive"); +} + +fn write_generated_icu(out: &Path, archive: Option<(&Path, &str, &str)>) { + let text = match archive { + Some((archive, archive_sha256, data_tree_sha256)) => format!( + "pub const HAS_ICU_DATA: bool = true;\n\ + pub const ICU_DATA_ARCHIVE_SHA256: Option<&str> = Some({archive_sha256:?});\n\ + pub const ICU_DATA_TREE_SHA256: Option<&str> = Some({data_tree_sha256:?});\n\ + pub fn icu_data_archive() -> Option<&'static [u8]> {{ Some(include_bytes!({archive:?})) }}\n", + archive = archive.to_string_lossy(), + ), + None => "pub const HAS_ICU_DATA: bool = false;\n\ + pub const ICU_DATA_ARCHIVE_SHA256: Option<&str> = None;\n\ + pub const ICU_DATA_TREE_SHA256: Option<&str> = None;\n\ + pub fn icu_data_archive() -> Option<&'static [u8]> { None }\n" + .to_owned(), + }; + fs::write(out, text).expect("write generated ICU data module"); +} + +fn emit_artifact_manifest(out_dir: &Path, icu_root: &Path, data_tree_sha256: &str) { + let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo"); + let manifest_path = out_dir.join("oliphaunt-artifact.toml"); + let files = collect_files(icu_root).expect("collect ICU data files for manifest"); + let mut text = format!( + "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {ARTIFACT_TARGET:?}\ndata_tree_sha256 = {data_tree_sha256:?}\ndata_version = \"76.1\"\ndata_form = \"files-le\"\n" + ); + for file in files { + let relative = file + .strip_prefix(icu_root) + .expect("ICU file stays under ICU root") + .to_string_lossy() + .replace('\\', "/"); + let sha256 = sha256_file(&file).expect("hash ICU data file"); + text.push_str(&format!( + "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n", + file.display().to_string(), + format!("share/icu/{relative}"), + sha256, + )); + } + fs::write(&manifest_path, text).expect("write ICU Cargo artifact manifest"); + println!("cargo::metadata=manifest={}", manifest_path.display()); +} + +fn collect_files(root: &Path) -> io::Result> { + let mut files = Vec::new(); + collect_files_inner(root, &mut files)?; + let mut files = files + .into_iter() + .map(|file| { + let relative = file + .strip_prefix(root) + .expect("ICU file stays under ICU root") + .to_str() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "ICU path is not UTF-8"))? + .replace('\\', "/"); + Ok((relative, file)) + }) + .collect::>>()?; + files.sort_by(|left, right| left.0.as_bytes().cmp(right.0.as_bytes())); + Ok(files.into_iter().map(|(_, file)| file).collect()) +} + +fn collect_files_inner(path: &Path, files: &mut Vec) -> io::Result<()> { + if !path.is_dir() { + return Ok(()); + } + for entry in fs::read_dir(path)? { + let entry = entry?; + let path = entry.path(); + let metadata = fs::symlink_metadata(&path)?; + if metadata.file_type().is_symlink() { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!("ICU data must not contain symlinks: {}", path.display()), + )); + } + if metadata.is_dir() { + collect_files_inner(&path, files)?; + } else if metadata.is_file() { + files.push(path); + } else { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + format!("ICU data contains an unsupported entry: {}", path.display()), + )); + } + } + Ok(()) +} + +fn logical_tree_sha256(root: &Path) -> io::Result { + let files = collect_files(root)?; + if files.is_empty() { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "ICU data tree is empty", + )); + } + let mut digest = Sha256::new(); + for file in files { + let relative = file + .strip_prefix(root) + .expect("ICU file stays below logical root") + .to_str() + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "ICU path is not UTF-8"))? + .replace('\\', "/"); + let bytes = fs::read(&file)?; + digest.update(relative.as_bytes()); + digest.update([0]); + digest.update(bytes.len().to_string().as_bytes()); + digest.update([0]); + digest.update(bytes); + digest.update([b'\n']); + } + Ok(format!("{:x}", digest.finalize())) +} + +fn sha256_file(path: &Path) -> io::Result { + let mut file = fs::File::open(path)?; + let mut hasher = Sha256::new(); + let mut buffer = [0_u8; 128 * 1024]; + loop { + let read = file.read(&mut buffer)?; + if read == 0 { + break; + } + hasher.update(&buffer[..read]); + } + Ok(format!("{:x}", hasher.finalize())) +} diff --git a/src/database-resources/icu/cargo/build.rs b/src/database-resources/icu/cargo/build.rs new file mode 100644 index 000000000..1b5c6bfc3 --- /dev/null +++ b/src/database-resources/icu/cargo/build.rs @@ -0,0 +1,2 @@ +const PACKAGE_LOCAL: bool = false; +include!("build-support.rs"); diff --git a/src/runtimes/liboliphaunt/icu/src/lib.rs b/src/database-resources/icu/cargo/src/lib.rs similarity index 100% rename from src/runtimes/liboliphaunt/icu/src/lib.rs rename to src/database-resources/icu/cargo/src/lib.rs diff --git a/src/runtimes/liboliphaunt/native/icu-npm/OliphauntICU.podspec b/src/database-resources/icu/npm/OliphauntICU.podspec similarity index 88% rename from src/runtimes/liboliphaunt/native/icu-npm/OliphauntICU.podspec rename to src/database-resources/icu/npm/OliphauntICU.podspec index 1dba9a47d..e4a980131 100644 --- a/src/runtimes/liboliphaunt/native/icu-npm/OliphauntICU.podspec +++ b/src/database-resources/icu/npm/OliphauntICU.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'OliphauntICU' - s.version = '0.2.0' # x-release-please-version + s.version = '0.2.1' # x-release-please-version s.summary = 'Portable ICU data files for Oliphaunt runtimes.' s.homepage = 'https://oliphaunt.dev' s.license = { :type => 'MIT AND Unicode-3.0' } diff --git a/src/runtimes/liboliphaunt/native/icu-npm/README.md b/src/database-resources/icu/npm/README.md similarity index 100% rename from src/runtimes/liboliphaunt/native/icu-npm/README.md rename to src/database-resources/icu/npm/README.md diff --git a/src/database-resources/icu/npm/package.json b/src/database-resources/icu/npm/package.json new file mode 100644 index 000000000..4260949ee --- /dev/null +++ b/src/database-resources/icu/npm/package.json @@ -0,0 +1,43 @@ +{ + "name": "@oliphaunt/icu", + "version": "0.2.1", + "description": "Portable ICU data files for Oliphaunt runtimes.", + "license": "MIT AND Unicode-3.0", + "type": "commonjs", + "repository": { + "type": "git", + "url": "git+https://github.com/f0rr0/oliphaunt.git", + "directory": "src/database-resources/icu/npm" + }, + "bugs": { + "url": "https://github.com/f0rr0/oliphaunt/issues" + }, + "homepage": "https://oliphaunt.dev", + "oliphaunt": { + "product": "oliphaunt-icu", + "kind": "icu-data", + "target": "portable", + "dataRelativePath": "OliphauntICU.bundle/share/icu", + "manifestRelativePath": "OliphauntICU.bundle/manifest.properties", + "icuDataTreeSha256": "x-release-icu-data-tree-sha256" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "files": [ + "OliphauntICU.bundle", + "OliphauntICU.podspec", + "react-native.config.js", + "README.md", + "LICENSE", + "THIRD_PARTY_NOTICES.md", + "THIRD_PARTY_NOTICES.liboliphaunt-native.md", + "THIRD_PARTY_LICENSES/ICU-LICENSE" + ], + "exports": { + "./data": "./OliphauntICU.bundle/share/icu/icudt76l.dat", + "./manifest": "./OliphauntICU.bundle/manifest.properties", + "./package.json": "./package.json" + } +} diff --git a/src/runtimes/liboliphaunt/native/icu-npm/react-native.config.js b/src/database-resources/icu/npm/react-native.config.cts similarity index 100% rename from src/runtimes/liboliphaunt/native/icu-npm/react-native.config.js rename to src/database-resources/icu/npm/react-native.config.cts diff --git a/src/sources/third-party/shared/icu-data.toml b/src/database-resources/icu/source.toml similarity index 100% rename from src/sources/third-party/shared/icu-data.toml rename to src/database-resources/icu/source.toml diff --git a/src/database-resources/icu/tools/build-data.sh b/src/database-resources/icu/tools/build-data.sh new file mode 100644 index 000000000..e98a37d8b --- /dev/null +++ b/src/database-resources/icu/tools/build-data.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +cd "$root" +source src/database-resources/icu/tools/data.sh +oliphaunt_icu_install_canonical_data \ + "${OLIPHAUNT_ICU_DATA_ARCHIVE:-$root/target/oliphaunt-sources/checkouts/icu-data/icudt76l.dat}" \ + "$root/target/database-resources/icu/data/share/icu" diff --git a/src/database-resources/icu/tools/check-icu-npm-cocoapods-consumer.sh b/src/database-resources/icu/tools/check-icu-npm-cocoapods-consumer.sh new file mode 100755 index 000000000..d6c340406 --- /dev/null +++ b/src/database-resources/icu/tools/check-icu-npm-cocoapods-consumer.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env bash +set -euo pipefail + +tool="check-icu-npm-cocoapods-consumer.sh" + +fail() { + echo "$tool: $*" >&2 + exit 1 +} + +require() { + command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1" +} + +[ "$#" -eq 1 ] || fail "usage: src/runtimes/liboliphaunt-native/tools/$tool LIBOLIPHAUNT_ICU_DATA.tar.gz" +[ "$(uname -s)" = "Darwin" ] || fail "this regression check requires macOS" + +for command in cp diff find git grep mktemp pod ruby tail xcodebuild; do + require "$command" +done + +root="$(git rev-parse --show-toplevel 2>/dev/null)" || + fail "must run inside the Oliphaunt git checkout" +podspec_source="$root/src/database-resources/icu/npm/OliphauntICU.podspec" +[ -f "$podspec_source" ] || fail "missing source podspec: $podspec_source" + +archive_input="$1" +[ -f "$archive_input" ] || fail "missing ICU data archive: $archive_input" +archive_directory="$(cd "$(dirname "$archive_input")" && pwd -P)" +archive="$archive_directory/$(basename "$archive_input")" +case "$archive" in + *.tar.gz) + ;; + *) + fail "ICU data archive must end in .tar.gz: $archive" + ;; +esac + +cd "$root" + +scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-icu-cocoapods.XXXXXX")" +scratch="$(cd "$scratch" && pwd -P)" +cleanup() { + rm -rf "$scratch" +} +trap cleanup EXIT +trap 'exit 130' INT +trap 'exit 143' TERM HUP + +work="$scratch/consumer" +pod_root="$work/OliphauntICU" +bundle_root="$pod_root/OliphauntICU.bundle" +source_icu="$bundle_root/share/icu" +derived_data="$scratch/DerivedData" +pod_log="$scratch/pod-install.log" +xcode_log="$scratch/xcodebuild.log" +mkdir -p "$bundle_root" "$work" "$scratch/cocoapods-home" "$scratch/swiftpm-cache" +cp "$podspec_source" "$pod_root/OliphauntICU.podspec" +"$root/tools/dev/bun.sh" -e ' + import { extractPortableArchiveTree } from "./tools/packaging/portable-archive.mts"; + extractPortableArchiveTree(process.argv[1], process.argv[2], "share/icu"); +' "$archive" "$source_icu" + +ruby - "$work" <<'RUBY' +require "fileutils" +require "xcodeproj" + +root = File.expand_path(ARGV.fetch(0)) +project_path = File.join(root, "OliphauntICUSmoke.xcodeproj") + +File.write(File.join(root, "main.c"), <<~SOURCE) + int main(int argc, char **argv) { + return argc > 0 && argv[0] != 0 ? 0 : 1; + } +SOURCE + +File.write(File.join(root, "Info.plist"), <<~PLIST) + + + + + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + + +PLIST + +File.write(File.join(root, "Podfile"), <<~PODFILE) + platform :ios, '17.0' + install! 'cocoapods', :deterministic_uuids => true + + target 'OliphauntICUSmoke' do + pod 'OliphauntICU', :path => 'OliphauntICU' + end +PODFILE + +project = Xcodeproj::Project.new(project_path) +project.root_object.attributes["LastUpgradeCheck"] = "1600" +target = project.new_target(:application, "OliphauntICUSmoke", :ios, "17.0") +source = project.main_group.new_file("main.c") +target.add_file_references([source]) + +target.build_configurations.each do |configuration| + settings = configuration.build_settings + settings["CODE_SIGNING_ALLOWED"] = "NO" + settings["CODE_SIGNING_REQUIRED"] = "NO" + settings["CURRENT_PROJECT_VERSION"] = "1" + settings["ENABLE_USER_SCRIPT_SANDBOXING"] = "NO" + settings["GENERATE_INFOPLIST_FILE"] = "NO" + settings["INFOPLIST_FILE"] = "Info.plist" + settings["IPHONEOS_DEPLOYMENT_TARGET"] = "17.0" + settings["MARKETING_VERSION"] = "1.0" + settings["PRODUCT_BUNDLE_IDENTIFIER"] = "dev.oliphaunt.icu-cocoapods-smoke" + settings["PRODUCT_NAME"] = "$(TARGET_NAME)" + settings["SUPPORTED_PLATFORMS"] = "iphonesimulator" + settings["TARGETED_DEVICE_FAMILY"] = "1,2" +end + +project.save +scheme = Xcodeproj::XCScheme.new +scheme.add_build_target(target) +scheme.set_launch_target(target) +scheme.save_as(project_path, "OliphauntICUSmoke", true) +RUBY + +if ! ( + cd "$work" + env \ + COCOAPODS_DISABLE_STATS=true \ + COCOAPODS_SKIP_UPDATE_MESSAGE=true \ + CP_HOME_DIR="$scratch/cocoapods-home" \ + LANG=en_US.UTF-8 \ + LC_ALL=en_US.UTF-8 \ + pod install +) >"$pod_log" 2>&1; then + tail -200 "$pod_log" >&2 + fail "CocoaPods installation failed" +fi + +machine_arch="$(uname -m)" +case "$machine_arch" in + arm64|x86_64) + ;; + *) + fail "unsupported macOS runner architecture: $machine_arch" + ;; +esac + +if ! xcodebuild \ + -workspace "$work/OliphauntICUSmoke.xcworkspace" \ + -scheme OliphauntICUSmoke \ + -configuration Release \ + -sdk iphonesimulator \ + -destination 'generic/platform=iOS Simulator' \ + -derivedDataPath "$derived_data" \ + -clonedSourcePackagesDirPath "$scratch/swiftpm-cache" \ + -disableAutomaticPackageResolution \ + -skipPackageUpdates \ + ARCHS="$machine_arch" \ + ONLY_ACTIVE_ARCH=YES \ + CODE_SIGNING_ALLOWED=NO \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGN_IDENTITY= \ + COMPILER_INDEX_STORE_ENABLE=NO \ + build >"$xcode_log" 2>&1; then + grep -n -E 'error:|Multiple commands produce|BUILD FAILED|The following build commands failed' "$xcode_log" | tail -160 >&2 || + tail -200 "$xcode_log" >&2 + fail "xcodebuild failed" +fi + +app="$derived_data/Build/Products/Release-iphonesimulator/OliphauntICUSmoke.app" +built_icu="$app/OliphauntICU.bundle/share/icu" +[ -d "$app" ] || fail "xcodebuild did not produce the expected app: $app" +[ -d "$built_icu" ] || fail "built app is missing OliphauntICU.bundle/share/icu" + +unsupported="$(find "$built_icu" ! -type f ! -type d -print -quit)" +[ -z "$unsupported" ] || fail "built ICU tree contains an unsupported entry: $unsupported" +diff -r "$source_icu" "$built_icu" || fail "built ICU tree does not byte-match the staged source tree" + +echo "$tool: PASS ($archive)" diff --git a/src/database-resources/icu/tools/data.sh b/src/database-resources/icu/tools/data.sh new file mode 100644 index 000000000..40256c761 --- /dev/null +++ b/src/database-resources/icu/tools/data.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env bash + +oliphaunt_icu_canonical_data_archive() { + local source_dir="${1:?ICU source dir is required}" + printf '%s\n' "${OLIPHAUNT_ICU_DATA_ARCHIVE:-$source_dir/../../../icu-data/icudt76l.dat}" +} + +oliphaunt_icu_canonical_data_sha256() { + printf '%s\n' 'dbc14e1c48ef209f230adc2aa6854bd4d6bba8f5e6733e75897a4263d97920f0' +} + +oliphaunt_icu_sha256() { + local digest + if command -v sha256sum >/dev/null 2>&1; then + digest="$(sha256sum "$@")" || return 1 + elif command -v shasum >/dev/null 2>&1; then + digest="$(shasum -a 256 "$@")" || return 1 + else + echo "ICU hashing requires sha256sum or shasum" >&2 + return 127 + fi + printf '%s\n' "${digest%% *}" +} + +oliphaunt_icu_require_canonical_data() { + local archive="${1:?ICU data archive is required}" + [ -f "$archive" ] || { + echo "missing pinned ICU 76.1 data archive at $archive; run \`bash src/third-party/tools/fetch-sources.sh native-runtime --force\` first" >&2 + return 1 + } + local actual + actual="$(oliphaunt_icu_sha256 < "$archive")" || return 1 + [ "$actual" = "$(oliphaunt_icu_canonical_data_sha256)" ] || { + echo "ICU data archive checksum mismatch: expected $(oliphaunt_icu_canonical_data_sha256), got $actual" >&2 + return 1 + } +} + +oliphaunt_icu_data_root_contains_data() { + local data_root="${1:?ICU data root is required}" + [ -d "$data_root" ] || return 1 + local root_name + root_name="$(basename "$data_root")" + if [[ "$root_name" == icudt* ]] && + find "$data_root" -mindepth 1 -type f -print -quit 2>/dev/null | grep -q .; then + return 0 + fi + if compgen -G "$data_root/icudt*.dat" >/dev/null; then + return 0 + fi + local child + while IFS= read -r child; do + if find "$child" -type f -print -quit 2>/dev/null | grep -q .; then + return 0 + fi + done < <(find "$data_root" -mindepth 1 -maxdepth 1 -type d -name 'icudt*' 2>/dev/null | LC_ALL=C sort) + return 1 +} + +oliphaunt_icu_files_data_ready() { + local data_root="${1:?ICU data root is required}" + oliphaunt_icu_data_root_contains_data "$data_root" && return 0 + local child + while IFS= read -r child; do + if oliphaunt_icu_data_root_contains_data "$child"; then + return 0 + fi + done < <(find "$data_root" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | LC_ALL=C sort) + return 1 +} + +oliphaunt_icu_install_canonical_data() { + local archive="${1:?pinned ICU data archive is required}" + local destination="${2:?ICU data destination is required}" + oliphaunt_icu_require_canonical_data "$archive" || return 1 + local tmp_destination="$destination.tmp" + + rm -rf "$tmp_destination" + mkdir -p "$tmp_destination" + cp "$archive" "$tmp_destination/icudt76l.dat" + rm -rf "$destination" + mv "$tmp_destination" "$destination" + oliphaunt_icu_files_data_ready "$destination" +} + +oliphaunt_icu_data_source_dir() { + local prefix="${1:?ICU prefix is required}" + local installed_icu="$prefix/share/icu" + if oliphaunt_icu_data_root_contains_data "$installed_icu"; then + printf '%s\n' "$installed_icu" + return 0 + fi + + local child + while IFS= read -r child; do + if [ -d "$child" ] && oliphaunt_icu_data_root_contains_data "$child"; then + printf '%s\n' "$child" + return 0 + fi + done < <(find "$installed_icu" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | LC_ALL=C sort) + return 1 +} + +oliphaunt_icu_stage_data() { + local prefix="${1:?ICU prefix is required}" + local destination="${2:?destination ICU data root is required}" + local source + source="$(oliphaunt_icu_data_source_dir "$prefix")" || return 1 + oliphaunt_icu_copy_files_data "$source" "$destination" +} + +oliphaunt_icu_copy_files_data() { + local source="${1:?source ICU data root is required}" + local destination="${2:?destination ICU data root is required}" + [ -d "$source" ] || return 1 + if find "$source" -type l -print -quit | grep -q .; then + echo "ICU files-data source must not contain symbolic links: $source" >&2 + return 1 + fi + rm -rf "$destination" + mkdir -p "$destination" + local copied=0 + local child name + while IFS= read -r child; do + name="$(basename "$child")" + if [ -f "$child" ] && [[ "$name" =~ ^icudt[0-9]+[a-z]*[.]dat$ ]]; then + cp -p "$child" "$destination/$name" + copied=$((copied + 1)) + elif [ -d "$child" ] && [[ "$name" =~ ^icudt[0-9]+[a-z]*$ ]] && + find "$child" -type f -print -quit | grep -q .; then + cp -pR "$child" "$destination/$name" + copied=$((copied + 1)) + fi + done < <(find "$source" -mindepth 1 -maxdepth 1 -print | LC_ALL=C sort) + if [ "$copied" -ne 1 ]; then + echo "ICU data root must contain exactly one canonical icudt files-data payload: $source" >&2 + rm -rf "$destination" + return 1 + fi + oliphaunt_icu_files_data_ready "$destination" +} diff --git a/src/database-resources/icu/tools/data.test.sh b/src/database-resources/icu/tools/data.test.sh new file mode 100644 index 000000000..fb4a6d5a6 --- /dev/null +++ b/src/database-resources/icu/tools/data.test.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/../../../.." +source src/database-resources/icu/tools/data.sh +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +archive="${OLIPHAUNT_ICU_DATA_ARCHIVE:-$scratch/canonical.dat}" +if [ -z "${OLIPHAUNT_ICU_DATA_ARCHIVE:-}" ]; then + printf abc > "$archive" + oliphaunt_icu_canonical_data_sha256() { + printf '%s\n' 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' + } +fi +mkdir -p "$scratch/checkouts/icu/icu4c/source" "$scratch/checkouts/icu-data" +cp "$archive" "$scratch/checkouts/icu-data/icudt76l.dat" +( + unset OLIPHAUNT_ICU_DATA_ARCHIVE + oliphaunt_icu_require_canonical_data \ + "$(oliphaunt_icu_canonical_data_archive "$scratch/checkouts/icu/icu4c/source")" +) +mkdir "$scratch/bin" +for tool in basename find grep sort rm mkdir cp mv; do + ln -s "$(command -v "$tool")" "$scratch/bin/$tool" +done +printf corrupt > "$scratch/corrupt.dat" +for hasher in sha256sum shasum; do + command -v "$hasher" >/dev/null || continue + ln -s "$(command -v "$hasher")" "$scratch/bin/$hasher" + ( + export PATH="$scratch/bin" + oliphaunt_icu_require_canonical_data "$archive" + oliphaunt_icu_install_canonical_data "$archive" "$scratch/installed" + for invalid in "$scratch/missing.dat" "$scratch/corrupt.dat"; do + if oliphaunt_icu_install_canonical_data "$invalid" "$scratch/installed" > "$scratch/error" 2>&1; then + echo "Invalid archive accepted: $invalid" >&2; exit 1 + fi + oliphaunt_icu_require_canonical_data "$scratch/installed/icudt76l.dat" + done + if oliphaunt_icu_sha256 "$scratch/missing.dat" 2>/dev/null; then + echo "Hashing a missing file succeeded" >&2; exit 1 + fi + ) + rm "$scratch/bin/$hasher" +done +if PATH="$scratch/bin" oliphaunt_icu_require_canonical_data "$archive" 2> "$scratch/error"; then + echo "Hashing succeeded without a hash command" >&2; exit 1 +fi +grep -q "requires sha256sum or shasum" "$scratch/error" diff --git a/src/database-resources/icu/tools/icu-npm-carrier-contract.mts b/src/database-resources/icu/tools/icu-npm-carrier-contract.mts new file mode 100644 index 000000000..f58d95318 --- /dev/null +++ b/src/database-resources/icu/tools/icu-npm-carrier-contract.mts @@ -0,0 +1,295 @@ +#!/usr/bin/env bun + +import { createHash } from 'node:crypto'; +import { validateNativeIcuDataManifestRows } from '../../contracts/icu-data.mts'; + +export const ICU_BUNDLE_DIRECTORY = 'OliphauntICU.bundle'; +export const ICU_DATA_RELATIVE_PATH = `${ICU_BUNDLE_DIRECTORY}/share/icu`; +export const ICU_MANIFEST_RELATIVE_PATH = `${ICU_BUNDLE_DIRECTORY}/manifest.properties`; +export const ICU_UNSTAGED_TREE_SHA256 = 'x-release-icu-data-tree-sha256'; +export const ICU_REACT_NATIVE_CONFIG = 'react-native.config.js'; +export const ICU_PODSPEC = 'OliphauntICU.podspec'; + +const PACKED_ROOT = 'package'; +const PACKED_DATA_ROOT = `${PACKED_ROOT}/${ICU_DATA_RELATIVE_PATH}`; +const LEGACY_PACKED_DATA_ROOT = `${PACKED_ROOT}/share/icu`; +function contractError(label, message) { + throw new Error(label + ': ' + message); +} + +export function assertIcuPackageManifest( + packageJson, + label = '@oliphaunt/icu package.json', + { allowUnstagedDigest = false } = {}, +) { + if (packageJson === null || typeof packageJson !== 'object' || Array.isArray(packageJson)) { + contractError(label, 'must be an object'); + } + if (packageJson.type !== 'commonjs') { + contractError(label, `type must be "commonjs", got ${JSON.stringify(packageJson.type)}`); + } + const metadata = packageJson.oliphaunt; + if ( + metadata?.product !== 'oliphaunt-icu' || + metadata?.kind !== 'icu-data' || + metadata?.target !== 'portable' || + metadata?.dataRelativePath !== ICU_DATA_RELATIVE_PATH || + metadata?.manifestRelativePath !== ICU_MANIFEST_RELATIVE_PATH || + !( + /^[0-9a-f]{64}$/u.test(metadata?.icuDataTreeSha256 ?? '') || + (allowUnstagedDigest && metadata?.icuDataTreeSha256 === ICU_UNSTAGED_TREE_SHA256) + ) + ) { + contractError( + label, + 'must declare portable oliphaunt-icu metadata with matching ICU data, manifest, and tree digest', + ); + } + if (!Array.isArray(packageJson.files)) { + contractError(label, 'files must be an array'); + } + if (new Set(packageJson.files).size !== packageJson.files.length) { + contractError(label, 'files must not contain duplicate entries'); + } + for (const member of [ICU_BUNDLE_DIRECTORY, ICU_PODSPEC, ICU_REACT_NATIVE_CONFIG]) { + if (!packageJson.files.includes(member)) { + contractError(label, `files must include ${member}`); + } + } + const legacyEntries = packageJson.files.filter( + (member) => typeof member === 'string' && (member === 'share' || member.startsWith('share/')), + ); + if (legacyEntries.length > 0) { + contractError(label, `files must not include the legacy ICU tree: ${legacyEntries.join(', ')}`); + } +} + +function normalizeEntries(entries, label) { + const normalized = []; + const seen = new Set(); + for (const entry of entries) { + const name = typeof entry === 'string' ? entry : entry?.name; + const isFile = typeof entry === 'string' ? !entry.endsWith('/') : entry?.isFile === true; + if (typeof name !== 'string' || name.length === 0) { + contractError(label, 'archive inventory contains an invalid member name'); + } + const normalizedName = name.replace(/\/$/u, ''); + if (seen.has(normalizedName)) { + contractError(label, `archive inventory repeats member ${normalizedName}`); + } + seen.add(normalizedName); + normalized.push({ name: normalizedName, isFile }); + } + return normalized; +} + +function isAtOrBelow(member, root) { + return member === root || member.startsWith(`${root}/`); +} + +function archiveFileManifest(entries, root, label) { + const rows = + entries instanceof Map + ? [...entries].map(([name, entry]) => ({ ...entry, name })) + : [...entries]; + const manifest = []; + const seen = new Set(); + for (const entry of rows) { + const name = entry?.name; + if (typeof name !== 'string' || !isAtOrBelow(name.replace(/\/$/u, ''), root)) { + continue; + } + const normalizedName = name.replace(/\/$/u, ''); + if (normalizedName === root || entry?.isFile !== true) { + continue; + } + const relative = normalizedName.slice(`${root}/`.length); + if (!relative || seen.has(relative)) { + contractError( + label, + `contains an invalid or repeated ICU data file ${relative || normalizedName}`, + ); + } + seen.add(relative); + const value = typeof entry.data === 'function' ? entry.data() : entry.data; + if (!(Buffer.isBuffer(value) || value instanceof Uint8Array)) { + contractError(label, `cannot read ICU data file ${normalizedName}`); + } + const bytes = Buffer.from(value); + if (entry.size !== undefined && entry.size !== bytes.length) { + contractError( + label, + `ICU data file ${normalizedName} declares ${entry.size} bytes but contains ${bytes.length}`, + ); + } + manifest.push({ + path: relative, + sha256: createHash('sha256').update(bytes).digest('hex'), + size: bytes.length, + type: 'file', + }); + } + if (manifest.length === 0) { + contractError(label, `contains no readable ICU data files below ${root}`); + } + return manifest.sort((left, right) => Buffer.from(left.path).compare(Buffer.from(right.path))); +} + +export function assertIcuPackedDataMatchesSource({ + packedEntries, + sourceEntries, + label = '@oliphaunt/icu npm tarball', + sourceLabel = 'liboliphaunt ICU data release asset', +}) { + const packed = archiveFileManifest(packedEntries, PACKED_DATA_ROOT, label); + const source = archiveFileManifest(sourceEntries, 'share/icu', sourceLabel); + if (JSON.stringify(packed) === JSON.stringify(source)) { + return; + } + + const packedByPath = new Map(packed.map((entry) => [entry.path, entry])); + const sourceByPath = new Map(source.map((entry) => [entry.path, entry])); + const missing = source + .filter((entry) => !packedByPath.has(entry.path)) + .map((entry) => entry.path); + const unexpected = packed + .filter((entry) => !sourceByPath.has(entry.path)) + .map((entry) => entry.path); + const changed = source + .filter((entry) => { + const candidate = packedByPath.get(entry.path); + return ( + candidate !== undefined && + (candidate.size !== entry.size || candidate.sha256 !== entry.sha256) + ); + }) + .map((entry) => entry.path); + contractError( + label, + `ICU data differs from ${sourceLabel}` + + ` (missing=${JSON.stringify(missing.slice(0, 5))}` + + `, unexpected=${JSON.stringify(unexpected.slice(0, 5))}` + + `, changed=${JSON.stringify(changed.slice(0, 5))})`, + ); +} + +export function assertIcuPackedClosureMatchesSource({ + packedEntries, + sourceEntries, + packageJson, + label = '@oliphaunt/icu npm tarball', + sourceLabel = 'liboliphaunt ICU data release asset', +}) { + assertIcuPackedDataMatchesSource({ packedEntries, sourceEntries, label, sourceLabel }); + const packedManifest = packedEntries.get(`${PACKED_ROOT}/${ICU_MANIFEST_RELATIVE_PATH}`)?.data(); + const sourceManifest = sourceEntries.get('manifest.properties')?.data(); + if (packedManifest === undefined || sourceManifest === undefined) { + contractError(label, 'ICU data closure is missing its manifest'); + } + if (!Buffer.from(packedManifest).equals(Buffer.from(sourceManifest))) { + contractError(label, `ICU data manifest differs from ${sourceLabel}`); + } + try { + const sourceDataRows = [...sourceEntries] + .filter(([name, entry]) => entry.isFile === true && name.startsWith('share/icu/')) + .map(([name, entry]) => ({ + path: name.slice('share/icu/'.length), + bytes: entry.data(), + })); + const receipt = validateNativeIcuDataManifestRows( + packedManifest, + sourceDataRows, + `${label} ${ICU_MANIFEST_RELATIVE_PATH}`, + ); + if (packageJson?.oliphaunt?.icuDataTreeSha256 !== receipt.icuDataTreeSha256) { + contractError( + label, + 'package metadata and ICU data manifest identify different logical trees', + ); + } + } catch (error) { + contractError(label, error instanceof Error ? error.message : String(error)); + } +} + +function icuTreeRoots(member) { + const segments = member.split('/').filter(Boolean); + const roots = []; + for (let index = 0; index + 1 < segments.length; index += 1) { + if (segments[index] === 'share' && segments[index + 1] === 'icu') { + roots.push(segments.slice(0, index + 2).join('/')); + } + } + return roots; +} + +export function assertIcuPackedInventory(entries, label = '@oliphaunt/icu npm tarball') { + const inventory = normalizeEntries(entries, label); + const byName = new Map(inventory.map((entry) => [entry.name, entry])); + for (const member of [ + `${PACKED_ROOT}/package.json`, + `${PACKED_ROOT}/${ICU_PODSPEC}`, + `${PACKED_ROOT}/${ICU_REACT_NATIVE_CONFIG}`, + ]) { + if (byName.get(member)?.isFile !== true) { + contractError(label, `is missing file ${member}`); + } + } + + for (const { name } of inventory) { + if (isAtOrBelow(name, LEGACY_PACKED_DATA_ROOT)) { + contractError(label, `contains forbidden legacy ICU data member ${name}`); + } + for (const root of icuTreeRoots(name)) { + if (root !== PACKED_DATA_ROOT) { + contractError(label, `contains unexpected additional ICU data tree ${root}`); + } + } + } + + const dataFiles = inventory.filter( + ({ name, isFile }) => isFile && name.startsWith(`${PACKED_DATA_ROOT}/`), + ); + if (dataFiles.length === 0) { + contractError(label, `is missing ICU data files under ${PACKED_DATA_ROOT}`); + } + if ( + !dataFiles.some(({ name }) => { + const relative = name.slice(`${PACKED_DATA_ROOT}/`.length).split('/').filter(Boolean); + return relative.length > 0 && relative[0].startsWith('icudt'); + }) + ) { + contractError(label, `is missing ${PACKED_DATA_ROOT}/icudt* data files`); + } + const manifest = `${PACKED_ROOT}/${ICU_MANIFEST_RELATIVE_PATH}`; + if (byName.get(manifest)?.isFile !== true) { + contractError(label, `is missing ICU data manifest ${manifest}`); + } + const seedMembers = inventory.filter(({ name }) => /(?:^|\/)cluster-seed(?:\/|$)/u.test(name)); + if (seedMembers.length > 0) { + contractError(label, `must not contain a target-specific cluster seed: ${seedMembers[0].name}`); + } +} + +function assertSameBytes(actual, expected, label) { + const actualBytes = Buffer.isBuffer(actual) ? actual : Buffer.from(actual); + const expectedBytes = Buffer.isBuffer(expected) ? expected : Buffer.from(expected); + if (!actualBytes.equals(expectedBytes)) { + contractError(label, 'packed bytes differ from the reviewed source descriptor'); + } +} + +export function assertPackedIcuCarrier({ + entries, + packageJson, + packedConfig, + packedPodspec, + sourceConfig, + sourcePodspec, + label = '@oliphaunt/icu npm tarball', +}) { + assertIcuPackageManifest(packageJson, `${label} package/package.json`); + assertIcuPackedInventory(entries, label); + assertSameBytes(packedConfig, sourceConfig, `${label} package/${ICU_REACT_NATIVE_CONFIG}`); + assertSameBytes(packedPodspec, sourcePodspec, `${label} package/${ICU_PODSPEC}`); +} diff --git a/src/database-resources/icu/tools/icu-npm-carrier-contract.test.mts b/src/database-resources/icu/tools/icu-npm-carrier-contract.test.mts new file mode 100644 index 000000000..360bcff0c --- /dev/null +++ b/src/database-resources/icu/tools/icu-npm-carrier-contract.test.mts @@ -0,0 +1,221 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { cpSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { gunzipSync, gzipSync } from 'node:zlib'; +import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts'; +import { nativeIcuDataManifest } from '../../contracts/icu-data.mts'; +import { + assertIcuPackageManifest, + assertIcuPackedDataMatchesSource, + assertIcuPackedInventory, + assertPackedIcuCarrier, + ICU_DATA_RELATIVE_PATH, + ICU_MANIFEST_RELATIVE_PATH, +} from './icu-npm-carrier-contract.mts'; + +const ROOT = path.resolve(import.meta.dirname, '../../../..'); +const ICU_PACKAGE_ROOT = path.join(ROOT, 'src/database-resources/icu/npm'); +const manifest = JSON.parse(readFileSync(path.join(ICU_PACKAGE_ROOT, 'package.json'), 'utf8')); +const stagedManifest = { + ...manifest, + oliphaunt: { ...manifest.oliphaunt, icuDataTreeSha256: 'a'.repeat(64) }, +}; +const config = readFileSync(path.join(ICU_PACKAGE_ROOT, 'react-native.config.cts')); +const podspec = readFileSync(path.join(ICU_PACKAGE_ROOT, 'OliphauntICU.podspec')); +const canonicalEntries = [ + { name: 'package/package.json', isFile: true }, + { name: 'package/react-native.config.js', isFile: true }, + { name: 'package/OliphauntICU.podspec', isFile: true }, + { name: 'package/OliphauntICU.bundle/', isFile: false }, + { name: 'package/OliphauntICU.bundle/share/icu/icudt77l/root.res', isFile: true }, + { name: 'package/OliphauntICU.bundle/manifest.properties', isFile: true }, +]; + +function stageIcuReceipt(root) { + const data = path.join(root, ...ICU_DATA_RELATIVE_PATH.split('/')); + const receipt = nativeIcuDataManifest(data); + writeFileSync(path.join(root, ...ICU_MANIFEST_RELATIVE_PATH.split('/')), receipt); + const packageJson = JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8')); + packageJson.oliphaunt.icuDataTreeSha256 = /^icuDataTreeSha256=([0-9a-f]{64})$/mu.exec( + receipt.toString('utf8'), + )[1]; + writeFileSync(path.join(root, 'package.json'), `${JSON.stringify(packageJson, null, 2)}\n`); +} + +if (process.argv[2] === 'prepare') { + const root = process.argv[3]; + const stage = path.join(root, 'stage'); + const output = path.join(root, 'packed'); + cpSync(ICU_PACKAGE_ROOT, stage, { recursive: true }); + writeFileSync(path.join(stage, 'react-native.config.js'), config); + mkdirSync(path.join(stage, ...ICU_DATA_RELATIVE_PATH.split('/'), 'icudt-test'), { + recursive: true, + }); + writeFileSync( + path.join(stage, ...ICU_DATA_RELATIVE_PATH.split('/'), 'icudt-test', 'root.res'), + 'fixture\n', + ); + stageIcuReceipt(stage); + stageReleaseNotices(stage, { profile: 'native-icu-data' }); + mkdirSync(output); + process.exit(0); +} +if (process.argv[2] === 'extract-config') { + const root = process.argv[3]; + const entries = readPortableArchiveEntries(path.join(root, 'packed/package.tgz')); + const consumer = path.join(root, 'consumer'); + mkdirSync(consumer); + writeFileSync(path.join(consumer, 'package.json'), entries.get('package/package.json').data()); + const packedConfigFile = path.join(consumer, 'react-native.config.js'); + writeFileSync(packedConfigFile, entries.get('package/react-native.config.js').data()); + process.exit(0); +} + +test('ICU npm pack includes one canonical bundle and preserves both native descriptors byte-for-byte', () => { + const root = process.env.OLIPHAUNT_ICU_NPM_TEST_ROOT; + if (!root) + throw new Error('Run bash src/database-resources/icu/tools/icu-npm-carrier-contract.test.sh'); + const tarball = path.join(root, 'packed/package.tgz'); + const entries = readPortableArchiveEntries(tarball); + assert.deepEqual(JSON.parse(readFileSync(path.join(root, 'config.json'), 'utf8')), { + dependency: { platforms: { ios: null, android: null } }, + }); + assert.equal(entries.has('package/share/icu/icudt-test/root.res'), false); + assert.equal(entries.has('package/OliphauntICU.bundle/share/icu/icudt-test/root.res'), true); + assertPackedIcuCarrier({ + entries: [...entries].map(([name, entry]) => ({ name, isFile: entry.isFile })), + packageJson: JSON.parse( + Buffer.from(entries.get('package/package.json').data()).toString('utf8'), + ), + packedConfig: Buffer.from(entries.get('package/react-native.config.js').data()), + packedPodspec: Buffer.from(entries.get('package/OliphauntICU.podspec').data()), + sourceConfig: config, + sourcePodspec: podspec, + }); + const sourceEntries = new Map([ + [ + 'share/icu/icudt-test/root.res', + { + data: () => Buffer.from('fixture\n'), + isFile: true, + size: Buffer.byteLength('fixture\n'), + }, + ], + ]); + assert.doesNotThrow(() => + assertIcuPackedDataMatchesSource({ + packedEntries: entries, + sourceEntries, + }), + ); + assert.throws( + () => + assertIcuPackedDataMatchesSource({ + packedEntries: entries, + sourceEntries: new Map([ + [ + 'share/icu/icudt-test/root.res', + { + data: () => Buffer.from('changed\n'), + isFile: true, + size: Buffer.byteLength('changed\n'), + }, + ], + ]), + }), + /ICU data differs/u, + ); + + const tar = gunzipSync(readFileSync(tarball)); + const firstSize = Number.parseInt( + tar.subarray(124, 136).toString('ascii').replace(/\0.*$/u, '').trim() || '0', + 8, + ); + const firstSpan = 512 + Math.ceil(firstSize / 512) * 512; + let endOffset = 0; + while (endOffset + 512 <= tar.length) { + const header = tar.subarray(endOffset, endOffset + 512); + if (header.every((byte) => byte === 0)) break; + const size = Number.parseInt( + header.subarray(124, 136).toString('ascii').replace(/\0.*$/u, '').trim() || '0', + 8, + ); + endOffset += 512 + Math.ceil(size / 512) * 512; + } + const duplicateArchive = path.join(root, 'duplicate-member.tgz'); + writeFileSync( + duplicateArchive, + gzipSync( + Buffer.concat([ + tar.subarray(0, endOffset), + tar.subarray(0, firstSpan), + tar.subarray(endOffset), + ]), + ), + ); + assert.throws(() => readPortableArchiveEntries(duplicateArchive), /repeats archive member/u); +}); + +test('ICU npm manifest rejects ESM autolinking and the legacy payload selector', () => { + assert.throws( + () => assertIcuPackageManifest({ ...stagedManifest, type: 'module' }), + /type must be "commonjs"/u, + ); + assert.throws( + () => assertIcuPackageManifest({ ...stagedManifest, files: [...manifest.files, 'share'] }), + /must not include the legacy ICU tree/u, + ); +}); + +test('ICU packed inventory accepts one data-only bundle and rejects legacy, additional, or duplicate trees', () => { + assert.doesNotThrow(() => assertIcuPackedInventory(canonicalEntries)); + assert.throws( + () => + assertIcuPackedInventory([ + ...canonicalEntries, + { name: 'package/share/icu/icudt77l/root.res', isFile: true }, + ]), + /forbidden legacy ICU data member/u, + ); + assert.throws( + () => + assertIcuPackedInventory([ + ...canonicalEntries, + { name: 'package/duplicate/share/icu/icudt77l/root.res', isFile: true }, + ]), + /unexpected additional ICU data tree/u, + ); + assert.throws( + () => assertIcuPackedInventory([...canonicalEntries, canonicalEntries.at(-1)]), + /repeats member/u, + ); +}); + +test('ICU packed carrier preserves the reviewed config and podspec bytes exactly', () => { + assert.throws( + () => + assertPackedIcuCarrier({ + entries: canonicalEntries, + packageJson: stagedManifest, + packedConfig: Buffer.concat([config, Buffer.from('\n')]), + packedPodspec: podspec, + sourceConfig: config, + sourcePodspec: podspec, + }), + /packed bytes differ from the reviewed source descriptor/u, + ); + assert.throws( + () => + assertPackedIcuCarrier({ + entries: canonicalEntries, + packageJson: stagedManifest, + packedConfig: config, + packedPodspec: Buffer.concat([podspec, Buffer.from('\n')]), + sourceConfig: config, + sourcePodspec: podspec, + }), + /packed bytes differ from the reviewed source descriptor/u, + ); +}); diff --git a/src/database-resources/icu/tools/icu-npm-carrier-contract.test.sh b/src/database-resources/icu/tools/icu-npm-carrier-contract.test.sh new file mode 100644 index 000000000..d618eaeaa --- /dev/null +++ b/src/database-resources/icu/tools/icu-npm-carrier-contract.test.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/../../../.." +root="$PWD" +scratch="$(mktemp -d)" +scratch="$(cd "$scratch" && pwd -P)" +trap 'rm -rf "$scratch"' EXIT +test_file=src/database-resources/icu/tools/icu-npm-carrier-contract.test.mts +bun "$test_file" prepare "$scratch" +(cd "$scratch/stage" && bun pm pack --filename "$scratch/packed/package.tgz") +bun "$test_file" extract-config "$scratch" +node -e 'process.stdout.write(JSON.stringify(require(process.argv[1])))' \ + "$scratch/consumer/react-native.config.js" > "$scratch/config.json" +OLIPHAUNT_ICU_NPM_TEST_ROOT="$scratch" bun test "$root/$test_file" diff --git a/src/database-resources/icu/tools/package-cargo.mts b/src/database-resources/icu/tools/package-cargo.mts new file mode 100644 index 000000000..5cbea026b --- /dev/null +++ b/src/database-resources/icu/tools/package-cargo.mts @@ -0,0 +1,96 @@ +#!/usr/bin/env bun +import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { parseArgs } from 'node:util'; +import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts'; +import { + extractPortableArchiveTree, + releaseZstdCompressSync, +} from '../../../../tools/packaging/portable-archive.mts'; +import { packageSpec } from '../../../../tools/packaging/wasix-cargo-payload.mts'; +import { currentProductVersionSync } from '../../../../tools/release/release-artifact-targets.mts'; +import { validateNativeIcuDataManifest } from '../../contracts/icu-data.mts'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..'); +function fail(message) { + throw new Error(message); +} + +export function packageIcuCargo(argv) { + const { values } = parseArgs({ + args: argv, + options: { + version: { type: 'string', default: currentProductVersionSync('database-resources') }, + asset: { type: 'string' }, + 'output-dir': { type: 'string', default: 'target/database-resources/cargo-artifacts' }, + 'work-dir': { type: 'string', default: 'target/database-resources' }, + }, + }); + const prefix = `database-resources-${values.version}-icu-data`; + const archive = path.resolve( + ROOT, + values.asset ?? `target/database-resources/release-assets/${prefix}.tar.gz`, + ); + const work = path.resolve(ROOT, values['work-dir']); + const extracted = path.join(work, 'icu-cargo-extracted'); + const sourceRoot = path.join(work, 'cargo-package-sources'); + const outputDir = path.resolve(ROOT, values['output-dir']); + // Own only this crate's scratch: future resource carriers share the output directory. + for (const directory of [extracted, path.join(sourceRoot, 'oliphaunt-icu')]) + rmSync(directory, { recursive: true, force: true }); + mkdirSync(outputDir, { recursive: true }); + extractPortableArchiveTree(archive, extracted); + const dataRoot = path.join(extracted, 'share/icu'); + validateNativeIcuDataManifest( + readFileSync(path.join(extracted, 'manifest.properties')), + dataRoot, + ); + const payloadRoot = path.join(extracted, 'cargo-payload'); + mkdirSync(payloadRoot); + writeFileSync( + path.join(payloadRoot, 'icu-data.tar.zst'), + releaseZstdCompressSync( + createDeterministicTar(dataRoot, 'share/icu', { fail, fixedFileMode: 0o644 }), + ), + ); + const packaged = packageSpec( + { + name: 'oliphaunt-icu', + target: 'portable', + kind: 'icu-data', + templateDir: path.join(ROOT, 'src/database-resources/icu/cargo'), + payloadRoot, + payloadDirName: 'payload', + }, + { + version: values.version, + sourceRoot, + outputDir, + cargoTargetDir: path.join(work, 'cargo-package-target'), + }, + ); + const relative = (value) => path.relative(ROOT, value).split(path.sep).join('/'); + writeFileSync( + path.join(outputDir, 'packages.json'), + `${JSON.stringify( + { + schema: 'oliphaunt-liboliphaunt-wasix-cargo-artifacts-v2', + product: 'database-resources', + packages: [ + { + ...packaged, + role: 'artifact', + manifestPath: relative(packaged.manifestPath), + cratePath: relative(packaged.cratePath), + }, + ], + }, + null, + 2, + )}\n`, + ); + return packaged; +} + +if (import.meta.main) packageIcuCargo(Bun.argv.slice(2)); diff --git a/src/database-resources/icu/tools/package-liboliphaunt-icu-data.sh b/src/database-resources/icu/tools/package-liboliphaunt-icu-data.sh new file mode 100755 index 000000000..d12393427 --- /dev/null +++ b/src/database-resources/icu/tools/package-liboliphaunt-icu-data.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -euo pipefail + +root="$(git rev-parse --show-toplevel 2>/dev/null)" || { + echo "package-liboliphaunt-icu-data.sh: must run inside the Oliphaunt git checkout" >&2 + exit 1 +} +cd "$root" + +fail() { + echo "package-liboliphaunt-icu-data.sh: $*" >&2 + exit 1 +} + +require() { + command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1" +} + +source_dir="${1:-}" +out_dir="${2:-}" +[ -n "$source_dir" ] && [ -n "$out_dir" ] || + fail "usage: src/database-resources/icu/tools/package-liboliphaunt-icu-data.sh SOURCE_DIR OUTPUT_DIR" +[ -d "$source_dir" ] || fail "missing portable ICU data directory: $source_dir" + +require mktemp +require bun + +source "$root/src/database-resources/icu/tools/data.sh" +if find "$source_dir" -type l -print -quit | grep -q .; then + fail "portable ICU data directory must not contain symbolic links: $source_dir" +fi +oliphaunt_icu_files_data_ready "$source_dir" || + fail "portable ICU data directory has no ICU files payload: $source_dir" +[ "$#" -eq 2 ] || fail "expected SOURCE_DIR OUTPUT_DIR" +version="$(tools/dev/bun.sh tools/release/product-version.mts version database-resources)" +stem=database-resources +asset="${stem}-${version}-icu-data.tar.gz" +mkdir -p "$out_dir" + +stage_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-icu-data.XXXXXX")" +partial="$out_dir/.${asset}.tmp.$$.tar.gz" +cleanup() { + rm -rf "$stage_root" + rm -f "$partial" +} +trap cleanup EXIT INT TERM HUP + +# macOS exposes its per-user temporary directory through /var, which is a +# system-owned symlink to /private/var. Resolve only the fresh directory that +# mktemp created for this process; release-notices can then retain its strict +# rejection of arbitrary symlink ancestors supplied by callers. +stage_root="$(cd "$stage_root" && pwd -P)" +stage="$stage_root/${stem}-${version}-icu-data" + +oliphaunt_icu_copy_files_data "$source_dir" "$stage/share/icu" || + fail "portable ICU data directory does not contain one canonical files-data payload" +oliphaunt_icu_files_data_ready "$stage/share/icu" || + fail "staged portable ICU data payload is incomplete" +tools/dev/bun.sh src/database-resources/contracts/icu-data.mts \ + "$stage/share/icu" \ + "$stage/manifest.properties" +tools/dev/bun.sh src/database-resources/icu/tools/write-icu-package-size-report.mts \ + "$stage/share/icu" \ + "$stage/package-size.tsv" + +tools/dev/bun.sh tools/packaging/release-notices.mts stage "$stage" --profile native-icu-data + +tools/packaging/archive-directory.mts "$stage" "$partial" +tools/dev/bun.sh tools/packaging/release-notices.mts check-archive "$partial" --profile native-icu-data +mv -f "$partial" "$out_dir/$asset" +echo "liboliphauntIcuDataReleaseAsset=$out_dir/$asset" diff --git a/src/database-resources/icu/tools/package-liboliphaunt-icu-data.test.mts b/src/database-resources/icu/tools/package-liboliphaunt-icu-data.test.mts new file mode 100644 index 000000000..04a5ef30e --- /dev/null +++ b/src/database-resources/icu/tools/package-liboliphaunt-icu-data.test.mts @@ -0,0 +1,33 @@ +import { expect, test } from 'bun:test'; +import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts'; +import { parseProperties } from '../../contracts/native-manifest.mts'; + +test('portable ICU archive preserves selected data, receipt and notices', () => { + const archive = process.env.OLIPHAUNT_ICU_TEST_ARCHIVE; + if (!archive) + throw new Error( + 'Run bash src/database-resources/icu/tools/package-liboliphaunt-icu-data.test.sh', + ); + const entries = readPortableArchiveEntries(archive); + expect(entries.get('share/icu/icudt76l/root.res')?.data().toString()).toBe('root\n'); + expect(entries.get('share/icu/icudt76l/coll/en.res')?.data().toString()).toBe('en\n'); + expect([...entries.keys()].some((name) => name.startsWith('share/icu/76.1'))).toBe(false); + expect(entries.has('share/icu/LICENSE')).toBe(false); + expect([...entries.keys()].some((name) => name.startsWith('cluster-seed'))).toBe(false); + expect(entries.has('THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT')).toBe(false); + expect(entries.has('THIRD_PARTY_LICENSES/ICU-LICENSE')).toBe(true); + expect( + Object.fromEntries( + parseProperties(entries.get('manifest.properties').data().toString(), 'ICU receipt'), + ), + ).toEqual({ + schema: 'oliphaunt-icu-data-v1', + artifactRole: 'icu-data', + icuDataVersion: '76.1', + icuDataForm: 'files-le', + icuDataTreeSha256: expect.stringMatching(/^[0-9a-f]{64}$/u), + }); + expect(entries.get('package-size.tsv').data().toString()).toMatch( + /^kind\tid\textensions\tfiles\tbytes\npackage\ttotal\t-\t-\t[0-9]+\npackage\ticu-data\t-\t-\t[0-9]+\n$/u, + ); +}); diff --git a/src/database-resources/icu/tools/package-liboliphaunt-icu-data.test.sh b/src/database-resources/icu/tools/package-liboliphaunt-icu-data.test.sh new file mode 100644 index 000000000..d39141e85 --- /dev/null +++ b/src/database-resources/icu/tools/package-liboliphaunt-icu-data.test.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/../../../.." +scratch="$(mktemp -d)" +scratch="$(cd "$scratch" && pwd -P)" +trap 'rm -rf "$scratch"' EXIT +source_dir="$scratch/source" +mkdir -p "$source_dir/icudt76l/coll" "$source_dir/76.1/config" "$scratch/empty" +printf 'root\n' > "$source_dir/icudt76l/root.res" +printf 'en\n' > "$source_dir/icudt76l/coll/en.res" +printf 'build-only\n' > "$source_dir/76.1/config/mh-darwin" +printf 'scaffolding\n' > "$source_dir/LICENSE" +script=src/database-resources/icu/tools/package-liboliphaunt-icu-data.sh +version="$(bun tools/release/product-version.mts version database-resources)" +archive="$scratch/output/database-resources-$version-icu-data.tar.gz" +bash "$script" "$source_dir" "$scratch/output" +cp "$archive" "$scratch/first.tar.gz" +bash "$script" "$source_dir" "$scratch/output" +cmp "$archive" "$scratch/first.tar.gz" +OLIPHAUNT_ICU_TEST_ARCHIVE="$archive" bun test ./src/database-resources/icu/tools/package-liboliphaunt-icu-data.test.mts +if bash "$script" "$scratch/empty" "$scratch/output" > "$scratch/empty.log" 2>&1; then + echo 'Empty ICU input was accepted' >&2; exit 1 +fi +mkdir -p "$scratch/linked/icudt76l" +ln -s "$source_dir/icudt76l/root.res" "$scratch/linked/icudt76l/root.res" +if bash "$script" "$scratch/linked" "$scratch/output" > "$scratch/linked.log" 2>&1; then + echo 'Symlinked ICU input was accepted' >&2; exit 1 +fi +grep -q 'must not contain symbolic links' "$scratch/linked.log" +cmp "$archive" "$scratch/first.tar.gz" +mkdir "$scratch/real-temp" +ln -s "$scratch/real-temp" "$scratch/temp-alias" +TMPDIR="$scratch/temp-alias" bash "$script" "$source_dir" "$scratch/output" +cmp "$archive" "$scratch/first.tar.gz" diff --git a/src/database-resources/icu/tools/package-npm.mts b/src/database-resources/icu/tools/package-npm.mts new file mode 100644 index 000000000..a0e6ae68e --- /dev/null +++ b/src/database-resources/icu/tools/package-npm.mts @@ -0,0 +1,164 @@ +#!/usr/bin/env bun +import { copyFileSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../../tools/packaging/portable-archive.mts'; +import { + extractReleaseArchiveFile, + fail, + packStagedNpmCarrier, + rel, + stageNpmPackageDescriptor, +} from '../../../../tools/packaging/release-carrier.mts'; +import { + assertReleaseNoticesInArchive, + assertReleaseNoticesInDirectory, + stageReleaseNotices, +} from '../../../../tools/packaging/release-notices.mts'; +import { + currentProductVersionSync, + ROOT, +} from '../../../../tools/release/release-artifact-targets.mts'; +import { + assertIcuPackageManifest, + assertIcuPackedClosureMatchesSource, + assertPackedIcuCarrier, + ICU_DATA_RELATIVE_PATH, + ICU_MANIFEST_RELATIVE_PATH, + ICU_PODSPEC, + ICU_REACT_NATIVE_CONFIG, +} from './icu-npm-carrier-contract.mts'; + +const LIBOLIPHAUNT_ICU_PACKAGE_NAME = '@oliphaunt/icu'; +const LIBOLIPHAUNT_ICU_PACKAGE_ROOT = path.join(ROOT, 'src/database-resources/icu/npm'); +function stageLiboliphauntIcuNpmPayload(version) { + const stage = stageNpmPackageDescriptor( + LIBOLIPHAUNT_ICU_PACKAGE_NAME, + LIBOLIPHAUNT_ICU_PACKAGE_ROOT, + version, + { + extraDescriptors: [ICU_PODSPEC], + target: 'portable', + }, + ); + copyFileSync( + path.join(LIBOLIPHAUNT_ICU_PACKAGE_ROOT, 'react-native.config.cts'), + path.join(stage, ICU_REACT_NATIVE_CONFIG), + ); + const sourceArchive = path.join( + ROOT, + 'target/database-resources/release-assets', + `database-resources-${version}-icu-data.tar.gz`, + ); + extractPortableArchiveTree( + sourceArchive, + path.join(stage, ...ICU_DATA_RELATIVE_PATH.split('/')), + 'share/icu', + ); + extractReleaseArchiveFile( + sourceArchive, + 'manifest.properties', + path.join(stage, ...ICU_MANIFEST_RELATIVE_PATH.split('/')), + ); + const manifestFile = path.join(stage, 'package.json'); + const packageJson = JSON.parse(readFileSync(manifestFile, 'utf8')); + const icuReceipt = readFileSync( + path.join(stage, ...ICU_MANIFEST_RELATIVE_PATH.split('/')), + 'utf8', + ); + const digest = /^icuDataTreeSha256=([0-9a-f]{64})$/mu.exec(icuReceipt)?.[1]; + if (digest === undefined) { + fail(`${rel(sourceArchive)} has no canonical ICU data tree digest`); + } + packageJson.oliphaunt.icuDataTreeSha256 = digest; + writeFileSync(manifestFile, `${JSON.stringify(packageJson, null, 2)}\n`); + stageReleaseNotices(stage, { profile: 'native-icu-data' }); + assertReleaseNoticesInDirectory(stage, { profile: 'native-icu-data' }); + try { + assertIcuPackageManifest( + JSON.parse(readFileSync(path.join(stage, 'package.json'), 'utf8')), + `${rel(stage)} package.json`, + ); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } + return stage; +} + +function validatePackedIcuPackage(packageName, version, tarball, sourceArchive) { + let entries; + let sourceEntries; + try { + entries = readPortableArchiveEntries(tarball); + sourceEntries = readPortableArchiveEntries(sourceArchive); + } catch (error) { + fail(`ICU carrier archives are invalid: ${error.message}`); + } + if (!entries.has('package/package.json')) { + fail(`${rel(tarball)} is missing package/package.json`); + } + let packageJson; + try { + const packageData = entries.get('package/package.json')?.data(); + if (packageData === undefined) { + fail(`${rel(tarball)} package/package.json could not be read`); + } + packageJson = JSON.parse(Buffer.from(packageData).toString('utf8')); + } catch (error) { + fail(`${rel(tarball)} package/package.json is not valid JSON: ${error.message}`); + } + if (packageJson.name !== packageName) { + fail( + `${rel(tarball)} package name must be ${packageName}, got ${JSON.stringify(packageJson.name)}`, + ); + } + if (packageJson.version !== version) { + fail( + `${rel(tarball)} package version must be ${version}, got ${JSON.stringify(packageJson.version)}`, + ); + } + try { + assertPackedIcuCarrier({ + entries: [...entries].map(([name, entry]) => ({ name, isFile: entry.isFile })), + packageJson, + packedConfig: entries.get(`package/${ICU_REACT_NATIVE_CONFIG}`)?.data(), + packedPodspec: entries.get(`package/${ICU_PODSPEC}`)?.data(), + sourceConfig: readFileSync( + path.join(LIBOLIPHAUNT_ICU_PACKAGE_ROOT, 'react-native.config.cts'), + ), + sourcePodspec: readFileSync(path.join(LIBOLIPHAUNT_ICU_PACKAGE_ROOT, ICU_PODSPEC)), + label: rel(tarball), + }); + assertIcuPackedClosureMatchesSource({ + packedEntries: entries, + sourceEntries, + packageJson, + label: rel(tarball), + sourceLabel: rel(sourceArchive), + }); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } + assertReleaseNoticesInArchive(tarball, { profile: 'native-icu-data', prefix: 'package' }); +} + +export function resourceNpmTarballs(version = currentProductVersionSync('database-resources')) { + const stage = stageLiboliphauntIcuNpmPayload(version); + const tarball = packStagedNpmCarrier(stage); + validatePackedIcuPackage( + LIBOLIPHAUNT_ICU_PACKAGE_NAME, + version, + tarball, + path.join( + ROOT, + 'target/database-resources/release-assets', + `database-resources-${version}-icu-data.tar.gz`, + ), + ); + return [[LIBOLIPHAUNT_ICU_PACKAGE_NAME, tarball]]; +} +if (import.meta.main) { + for (const [name, tarball] of resourceNpmTarballs()) console.log(`${name}\t${tarball}`); +} diff --git a/src/database-resources/icu/tools/package.sh b/src/database-resources/icu/tools/package.sh new file mode 100644 index 000000000..17810a0f8 --- /dev/null +++ b/src/database-resources/icu/tools/package.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +cd "$root" +data="${OLIPHAUNT_ICU_DATA_DIR:-$root/target/database-resources/icu/data/share/icu}" +bash src/database-resources/icu/tools/package-liboliphaunt-icu-data.sh "$data" "$root/target/database-resources/release-assets" +bun src/database-resources/tools/package-carriers.mts diff --git a/src/database-resources/icu/tools/write-icu-package-size-report.mts b/src/database-resources/icu/tools/write-icu-package-size-report.mts new file mode 100644 index 000000000..4c323a1c0 --- /dev/null +++ b/src/database-resources/icu/tools/write-icu-package-size-report.mts @@ -0,0 +1,28 @@ +#!/usr/bin/env bun + +import { writeFileSync } from 'node:fs'; +import path from 'node:path'; + +import { filesystemTreeRows } from '../../contracts/native-manifest.mts'; + +function treeBytes(root) { + return filesystemTreeRows(root).reduce((total, row) => total + row.bytes.length, 0); +} + +export function icuPackageSizeReport(icuData) { + const icuDataBytes = treeBytes(icuData); + return [ + 'kind\tid\textensions\tfiles\tbytes', + `package\ttotal\t-\t-\t${icuDataBytes}`, + `package\ticu-data\t-\t-\t${icuDataBytes}`, + '', + ].join('\n'); +} + +if (import.meta.main) { + const [icuData, output] = process.argv.slice(2); + if (!icuData || !output) { + throw new Error('usage: write-icu-package-size-report.mts ICU_DATA_DIR OUTPUT'); + } + writeFileSync(path.resolve(output), icuPackageSizeReport(path.resolve(icuData))); +} diff --git a/src/database-resources/moon.yml b/src/database-resources/moon.yml new file mode 100644 index 000000000..dbde40e0a --- /dev/null +++ b/src/database-resources/moon.yml @@ -0,0 +1,151 @@ +$schema: "https://moonrepo.dev/schemas/project.json" +id: "database-resources" +language: "unknown" +layer: "library" +tags: ["javascript-quality", "resources", "release-product"] +dependsOn: + - id: "cluster-seed-contract" + scope: "development" +project: + title: "Database resources" + description: "Selectable PostgreSQL cluster seeds and shared ICU data." + release: + component: "database-resources" + packagePath: "src/database-resources" +fileGroups: + cargo-carrier-sources: ["icu/cargo/**/*.rs", "icu/cargo/Cargo.toml"] +tasks: + seed-producer-test: + tags: ["quality", "unit", "requires-rust"] + command: "cargo test -p oliphaunt-wasix-seed-producer --locked" + inputs: ["seeds/wasix/**/*", "contracts/contract.json", "@group(cargo-workspace)"] + options: + runFromWorkspaceRoot: true + format-check: + tags: ["quality", "static", "format", "requires-rust"] + command: "cargo fmt -p oliphaunt-icu --check" + inputs: ["icu/cargo/**/*.rs", "icu/cargo/Cargo.toml", "@group(cargo-workspace)"] + options: + runFromWorkspaceRoot: true + lint: + tags: ["quality", "static", "requires-rust"] + command: "cargo clippy -p oliphaunt-icu --all-targets --locked -- -D warnings" + inputs: ["icu/cargo/**/*", "/clippy.toml", "@group(cargo-workspace)"] + options: + runFromWorkspaceRoot: true + test: + tags: ["quality", "unit"] + deps: ["cluster-seed-contract:test", "seed-producer-test"] + command: "bash test.sh" + inputs: ["test.sh", "seeds/*.mts", "icu/tools/**/*", "icu/npm/**/*", "contracts/**/*", "/tools/packaging/**/*.mts", "!/tools/packaging/**/*.test.*"] + package-native: + deps: ["database-resources:build-native-standard", "database-resources:build-native-icu"] + command: "bash src/database-resources/seeds/package.sh native" + inputs: ["seeds/**/*", "VERSION", "$OLIPHAUNT_CI_TARGET"] + outputs: ["/target/database-resources/seed-carriers/npm/*native*/*.tgz", "/target/database-resources/seed-carriers/cargo/*native*.crate"] + options: + runFromWorkspaceRoot: true + package-wasix: + deps: ["database-resources:build-wasix-standard", "database-resources:build-wasix-icu"] + command: "bash src/database-resources/seeds/package.sh wasix" + inputs: ["seeds/**/*", "VERSION"] + outputs: ["/target/database-resources/seed-carriers/npm/*wasix*/*.tgz", "/target/database-resources/seed-carriers/cargo/*wasix*.crate"] + options: + runFromWorkspaceRoot: true + package-android: + deps: ["database-resources:build-native-android-standard", "database-resources:build-native-android-icu", "database-resources:package-icu"] + command: "bash src/database-resources/seeds/package.sh native android-datum64" + inputs: ["seeds/**/*", "VERSION"] + outputs: ["/target/database-resources/seed-carriers/npm/*android-datum64*/*.tgz", "/target/database-resources/seed-carriers/cargo/*android-datum64*.crate", "/target/database-resources/release-assets/*android-datum64*-maven.tar.gz", "/target/release/maven-staging/database-resources-seeds/**/*"] + options: + runFromWorkspaceRoot: true + package-ios: + deps: ["database-resources:build-native-ios-standard", "database-resources:build-native-ios-icu", "database-resources:package-icu"] + command: "bash src/database-resources/seeds/package.sh native ios-datum64" + inputs: ["seeds/**/*", "VERSION"] + outputs: ["/target/database-resources/seed-carriers/npm/*ios-datum64*/*.tgz", "/target/database-resources/seed-carriers/cargo/*ios-datum64*.crate", "/target/database-resources/release-assets/*-swift.zip"] + options: + runFromWorkspaceRoot: true + build-icu-data: + deps: ["source-inputs:source-fetch-icu-data"] + command: "bash src/database-resources/icu/tools/build-data.sh" + inputs: ["icu/source.toml", "icu/tools/data.sh", "icu/tools/build-data.sh"] + outputs: ["/target/database-resources/icu/data/share/icu/**/*"] + options: + runFromWorkspaceRoot: true + package-icu: + tags: ["release", "artifact-package", "ci-js-sdk-package"] + deps: ["database-resources:build-icu-data"] + command: "bash src/database-resources/icu/tools/package.sh" + inputs: ["icu/**/*", "tools/**/*", "contracts/**/*", "!**/*.test.*", "VERSION", "/tools/packaging/**/*.mts", "!/tools/packaging/**/*.test.*"] + outputs: ["/target/database-resources/release-assets/*icu-data.tar.gz", "/target/database-resources/cargo-artifacts/**/*", "/target/release/npm-packages/oliphaunt-icu/*.tgz", "/target/release/maven-manifests/database-resources.tsv", "/target/release/maven-staging/database-resources/**/*"] + options: + runFromWorkspaceRoot: true + build-native-standard: + tags: ["artifact-package", "ci-liboliphaunt-native-desktop"] + deps: ["liboliphaunt-native:build-runtime-desktop-target"] + command: "bash src/database-resources/seeds/build.sh native standard" + inputs: ["seeds/**/*", "contracts/**/*", "VERSION", "$OLIPHAUNT_CI_TARGET", "$OLIPHAUNT_SEED_RUNTIME_DIR"] + outputs: ["/target/database-resources/release-assets/*seed-native-*-standard.*"] + options: + runFromWorkspaceRoot: true + build-native-icu: + tags: ["artifact-package", "ci-liboliphaunt-native-desktop"] + deps: ["liboliphaunt-native:build-runtime-desktop-target", "database-resources:build-icu-data"] + command: "bash src/database-resources/seeds/build.sh native icu" + inputs: ["seeds/**/*", "contracts/**/*", "VERSION", "$OLIPHAUNT_CI_TARGET", "$OLIPHAUNT_SEED_RUNTIME_DIR", "$OLIPHAUNT_ICU_DATA_DIR"] + outputs: ["/target/database-resources/release-assets/*seed-native-*-icu.*"] + options: + runFromWorkspaceRoot: true + build-wasix-standard: + tags: ["artifact-package", "ci-liboliphaunt-wasix-runtime"] + deps: ["liboliphaunt-wasix:compiler-output"] + command: "bash src/database-resources/seeds/build.sh wasix standard" + inputs: ["seeds/**/*", "contracts/**/*", "VERSION", "@group(cargo-workspace)"] + outputs: ["/target/database-resources/release-assets/*seed-wasix-standard.*"] + options: + runFromWorkspaceRoot: true + build-wasix-icu: + tags: ["artifact-package", "ci-liboliphaunt-wasix-runtime"] + deps: ["liboliphaunt-wasix:compiler-output", "database-resources:build-icu-data"] + command: "bash src/database-resources/seeds/build.sh wasix icu" + inputs: ["seeds/**/*", "contracts/**/*", "VERSION", "@group(cargo-workspace)"] + outputs: ["/target/database-resources/release-assets/*seed-wasix-icu.*"] + options: + runFromWorkspaceRoot: true + + build-native-android-standard: + tags: ["artifact-package", "ci-liboliphaunt-native-android-abi"] + deps: ["liboliphaunt-native:build-runtime-android-arm64-v8a","liboliphaunt-native:build-runtime-android-x86_64"] + command: "env OLIPHAUNT_CI_TARGET=android-datum64 bash src/database-resources/seeds/build.sh native standard" + inputs: ["seeds/**/*", "contracts/**/*", "VERSION", "/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts"] + outputs: ["/target/database-resources/release-assets/*seed-native-android-datum64-standard.*"] + options: + runFromWorkspaceRoot: true + + build-native-android-icu: + tags: ["artifact-package", "ci-liboliphaunt-native-android-abi"] + deps: ["liboliphaunt-native:build-runtime-android-arm64-v8a","liboliphaunt-native:build-runtime-android-x86_64"] + command: "env OLIPHAUNT_CI_TARGET=android-datum64 bash src/database-resources/seeds/build.sh native icu" + inputs: ["seeds/**/*", "icu/tools/data.sh", "contracts/**/*", "VERSION", "/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts"] + outputs: ["/target/database-resources/release-assets/*seed-native-android-datum64-icu.*"] + options: + runFromWorkspaceRoot: true + + build-native-ios-standard: + tags: ["artifact-package", "ci-liboliphaunt-native-ios-abi"] + deps: ["liboliphaunt-native:build-runtime-ios-xcframework"] + command: "env OLIPHAUNT_CI_TARGET=ios-datum64 bash src/database-resources/seeds/build.sh native standard" + inputs: ["seeds/**/*", "contracts/**/*", "VERSION", "/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts"] + outputs: ["/target/database-resources/release-assets/*seed-native-ios-datum64-standard.*"] + options: + runFromWorkspaceRoot: true + + build-native-ios-icu: + tags: ["artifact-package", "ci-liboliphaunt-native-ios-abi"] + deps: ["liboliphaunt-native:build-runtime-ios-xcframework"] + command: "env OLIPHAUNT_CI_TARGET=ios-datum64 bash src/database-resources/seeds/build.sh native icu" + inputs: ["seeds/**/*", "icu/tools/data.sh", "contracts/**/*", "VERSION", "/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts"] + outputs: ["/target/database-resources/release-assets/*seed-native-ios-datum64-icu.*"] + options: + runFromWorkspaceRoot: true diff --git a/src/database-resources/release.toml b/src/database-resources/release.toml new file mode 100644 index 000000000..393356389 --- /dev/null +++ b/src/database-resources/release.toml @@ -0,0 +1,40 @@ +id = "database-resources" +owner = "@oliphaunt/core" +kind = "database-resources" +publish_targets = ["github-release-assets", "npm", "crates-io", "maven-central"] +registry_packages = [ + "npm:@oliphaunt/icu", + "crates:oliphaunt-icu", + "maven:dev.oliphaunt.runtime:oliphaunt-icu", + "maven:dev.oliphaunt.runtime:oliphaunt-seed-native-android-datum64-standard", + "maven:dev.oliphaunt.runtime:oliphaunt-seed-native-android-datum64-icu", + "npm:@oliphaunt/seed-native-android-datum64-standard", + "crates:oliphaunt-seed-native-android-datum64-standard", + "npm:@oliphaunt/seed-native-android-datum64-icu", + "crates:oliphaunt-seed-native-android-datum64-icu", + "npm:@oliphaunt/seed-native-ios-datum64-standard", + "crates:oliphaunt-seed-native-ios-datum64-standard", + "npm:@oliphaunt/seed-native-ios-datum64-icu", + "crates:oliphaunt-seed-native-ios-datum64-icu", + "npm:@oliphaunt/seed-native-linux-arm64-gnu-standard", + "crates:oliphaunt-seed-native-linux-arm64-gnu-standard", + "npm:@oliphaunt/seed-native-linux-arm64-gnu-icu", + "crates:oliphaunt-seed-native-linux-arm64-gnu-icu", + "npm:@oliphaunt/seed-native-linux-x64-gnu-standard", + "crates:oliphaunt-seed-native-linux-x64-gnu-standard", + "npm:@oliphaunt/seed-native-linux-x64-gnu-icu", + "crates:oliphaunt-seed-native-linux-x64-gnu-icu", + "npm:@oliphaunt/seed-native-macos-arm64-standard", + "crates:oliphaunt-seed-native-macos-arm64-standard", + "npm:@oliphaunt/seed-native-macos-arm64-icu", + "crates:oliphaunt-seed-native-macos-arm64-icu", + "npm:@oliphaunt/seed-native-windows-x64-msvc-standard", + "crates:oliphaunt-seed-native-windows-x64-msvc-standard", + "npm:@oliphaunt/seed-native-windows-x64-msvc-icu", + "crates:oliphaunt-seed-native-windows-x64-msvc-icu", + "npm:@oliphaunt/seed-wasix-standard", + "crates:oliphaunt-seed-wasix-standard", + "npm:@oliphaunt/seed-wasix-icu", + "crates:oliphaunt-seed-wasix-icu", +] +release_artifacts = ["icu-data", "cluster-seeds"] diff --git a/src/database-resources/seeds/build.sh b/src/database-resources/seeds/build.sh new file mode 100644 index 000000000..a7882dcb7 --- /dev/null +++ b/src/database-resources/seeds/build.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +cd "$root" +family="${1:?native or wasix is required}" +profile="${2:?standard or icu is required}" +shift 2 +runtime="${OLIPHAUNT_SEED_RUNTIME_DIR:-}" +icu="${OLIPHAUNT_ICU_DATA_DIR:-}" +target="${OLIPHAUNT_CI_TARGET:-}" +case "$family" in + native) + source src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh + target="${target:-$(oliphaunt_runtime_native_host_target_id)}" + case "$target" in + linux-*) work_root="${OLIPHAUNT_LINUX_WORK_ROOT:-$root/target/liboliphaunt-pg18-$target}" ;; + macos-arm64) work_root="${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18}" ;; + windows-x64-msvc) work_root="${OLIPHAUNT_WINDOWS_WORK_ROOT:-${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18-$target}}" ;; + android-datum64) + work_root="$root/target/liboliphaunt-mobile-host/android-x86_64" + bun src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts compare --domain android-datum64 \ + --receipt "${OLIPHAUNT_ANDROID_ARM64_ROOT:-$root/target/liboliphaunt-pg18-android-arm64}/out/native-mobile-abi.properties" \ + --receipt "${OLIPHAUNT_ANDROID_X86_64_ROOT:-$root/target/liboliphaunt-pg18-android-x86_64}/out/native-mobile-abi.properties" \ + --receipt "${OLIPHAUNT_ANDROID_X86_64_ROOT:-$root/target/liboliphaunt-pg18-android-x86_64}/out/native-mobile-abi-producer.properties" + ;; + ios-datum64) + work_root="$root/target/liboliphaunt-mobile-host/ios-xcframework" + bun src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts compare --domain ios-datum64 \ + --receipt "${OLIPHAUNT_IOS_DEVICE_ROOT:-$root/target/liboliphaunt-ios-device}/out/native-mobile-abi.properties" \ + --receipt "${OLIPHAUNT_IOS_SIMULATOR_ROOT:-$root/target/liboliphaunt-ios-simulator}/out/native-mobile-abi.properties" \ + --receipt "${OLIPHAUNT_IOS_XCFRAMEWORK_ROOT:-$root/target/liboliphaunt-ios-xcframework}/out/native-mobile-abi-producer.properties" + ;; + *) echo "unsupported native seed target: $target" >&2; exit 2 ;; + esac + if [[ "$target" == *-datum64 && -n "$runtime" && "$runtime" != "$work_root/install" ]]; then + echo 'mobile seed runtime override is not covered by the checked producer ABI receipts' >&2 + exit 2 + fi + runtime="${runtime:-$work_root/install}" + if [[ "$target" == *-datum64 && "$profile" == icu ]]; then + icu="${icu:-$work_root/icu/share/icu}" + source src/database-resources/icu/tools/data.sh + oliphaunt_icu_require_canonical_data "$icu/icudt76l.dat" + fi + ;; + wasix) + target=portable + runtime="${runtime:-$root/target/oliphaunt-wasix/wasix-build/build/install}" + ;; + *) echo 'family must be native or wasix' >&2; exit 2 ;; +esac +case "$profile" in + standard) icu="" ;; + icu) icu="${icu:-$root/target/database-resources/icu/data/share/icu}" ;; + *) echo 'profile must be standard or icu' >&2; exit 2 ;; +esac +work="$(mktemp -d)" +trap 'rm -rf "$work"' EXIT +if [ "$family" = native ]; then + bash src/database-resources/seeds/native/tools/stage-native-cluster-seed.sh \ + --runtime "$runtime" --destination "$work/seed" --target "$target" --profile "$profile" ${icu:+--icu-data} ${icu:+"$icu"} + pgdata="$work/seed/files" +else + cargo run -p oliphaunt-wasix-seed-producer --features cluster-seed-runner --locked -- \ + "$runtime" "$work/seed" "$profile" ${icu:+"$icu"} + pgdata="$work/seed/pgdata" +fi +bash tools/ci/with-projects.sh src/database-resources/seeds/package.mts --family "$family" --profile "$profile" --target "$target" \ + --pgdata "$pgdata" --runtime "$runtime" ${icu:+--icu-data} ${icu:+"$icu"} "$@" diff --git a/src/database-resources/seeds/carrier-identities.mts b/src/database-resources/seeds/carrier-identities.mts new file mode 100644 index 000000000..fe3f9037c --- /dev/null +++ b/src/database-resources/seeds/carrier-identities.mts @@ -0,0 +1,27 @@ +import { readFileSync } from 'node:fs'; + +const contract = JSON.parse( + readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), +); + +export function seedCarrierIdentities() { + return [ + ...Object.keys(contract.compatibilityKeys.native).map((target) => ({ + family: 'native', + target, + })), + { family: 'wasix', target: 'portable' }, + ].flatMap(({ family, target }) => + Object.keys(contract.profiles).map((profile) => { + const suffix = `${family}${family === 'native' ? `-${target}` : ''}-${profile}`; + return { + family, + target, + profile, + suffix, + npm: `@oliphaunt/seed-${suffix}`, + cargo: `oliphaunt-seed-${suffix}`, + }; + }), + ); +} diff --git a/src/database-resources/seeds/native/tools/stage-native-cluster-seed.mts b/src/database-resources/seeds/native/tools/stage-native-cluster-seed.mts new file mode 100644 index 000000000..152d9cb38 --- /dev/null +++ b/src/database-resources/seeds/native/tools/stage-native-cluster-seed.mts @@ -0,0 +1,145 @@ +#!/usr/bin/env bun + +import { cpSync, existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + bindNativeClusterSeedManifest, + filesystemTreeRows, + logicalTreeSha256, + NATIVE_CLUSTER_SEED_TARGETS, + validateNativeClusterSeedDirectory, +} from '../../../contracts/native-manifest.mts'; + +const TOOL = 'stage-native-cluster-seed.mts'; +function fail(message) { + throw new Error(`${TOOL}: ${message}`); +} + +function parseArgs(argv) { + const values = new Map(); + for (let index = 0; index < argv.length; index += 2) { + const key = argv[index]; + const value = argv[index + 1]; + if (!key?.startsWith('--') || value === undefined || value.startsWith('--')) { + fail( + 'usage: stage-native-cluster-seed.mts --runtime DIR --destination DIR --target TARGET --profile standard|icu [--icu-data DIR]', + ); + } + if (values.has(key)) fail(`repeated argument ${key}`); + values.set(key, value); + } + const allowed = new Set(['--runtime', '--destination', '--target', '--profile', '--icu-data']); + for (const key of values.keys()) if (!allowed.has(key)) fail(`unknown argument ${key}`); + const runtime = values.get('--runtime'); + const destination = values.get('--destination'); + const target = values.get('--target'); + const profile = values.get('--profile'); + const icuData = values.get('--icu-data'); + if (!runtime || !destination || !target || !['standard', 'icu'].includes(profile)) { + fail('runtime, destination, target, and profile=standard|icu are required'); + } + if (profile === 'icu' && !icuData) fail('profile=icu requires --icu-data DIR'); + if (profile === 'standard' && icuData) fail('profile=standard must not receive --icu-data'); + return Object.freeze({ + runtime: path.resolve(runtime), + destination: path.resolve(destination), + target, + profile, + icuData: icuData === undefined ? undefined : path.resolve(icuData), + }); +} + +function requireDirectory(directory, label) { + if (!existsSync(directory)) fail(`${label} does not exist: ${directory}`); +} + +const [mode, ...argv] = process.argv.slice(2); +const source = mode === 'install' ? argv.shift() : undefined; +if (!['prepare', 'install'].includes(mode) || (mode === 'install' && !source)) { + fail('usage: stage-native-cluster-seed.mts prepare|install [prepared-seed] '); +} +const args = parseArgs(argv); +requireDirectory(args.runtime, 'native runtime'); +if (args.icuData !== undefined) requireDirectory(args.icuData, 'ICU data'); +if (!NATIVE_CLUSTER_SEED_TARGETS.includes(args.target)) + fail('unsupported native cluster-seed target'); +if (args.destination === path.parse(args.destination).root) + fail('destination must not be a filesystem root'); +if (mode === 'prepare') { + for (const value of [ + args.runtime, + args.destination, + args.target, + args.profile, + args.icuData ?? '', + ]) { + if (value.includes('\0')) fail('cluster-seed paths must not contain NUL'); + process.stdout.write(`${value}\0`); + } +} else { + const contract = JSON.parse( + readFileSync(new URL('../../../contracts/contract.json', import.meta.url), 'utf8'), + ); + const files = path.join(source, 'files'); + for (const name of ['postmaster.pid', 'postmaster.opts']) + rmSync(path.join(files, name), { force: true }); + const memory = args.target.startsWith('windows-') ? 'windows' : 'mmap'; + const settings = new Map([ + ['shared_memory_type', memory], + ['dynamic_shared_memory_type', memory], + ['log_timezone', "'UTC'"], + ['timezone', "'UTC'"], + ...['lc_messages', 'lc_monetary', 'lc_numeric', 'lc_time'].map((key) => [key, "'C'"]), + ]); + const conf = path.join(files, 'postgresql.conf'); + const written = new Set(); + const lines = readFileSync(conf, 'utf8') + .trimEnd() + .split('\n') + .map((line) => { + const key = /^\s*([a-z_]+)\s*=/u.exec(line)?.[1]; + if (key === undefined || !settings.has(key)) return line; + const value = settings.get(key); + written.add(key); + return `${key} = ${value}`; + }); + for (const [key, value] of settings) if (!written.has(key)) lines.push(`${key} = ${value}`); + writeFileSync(conf, `${lines.join('\n')}\n`); + const profile = contract.profiles[args.profile]; + const properties = { + schema: contract.manifests.native.schema, + layout: contract.manifests.native.layout, + artifactRole: profile.artifactRole, + catalogProfile: args.profile, + postgresMajor: '18', + physicalFormat: contract.physicalFormats.native, + initialSuperuser: 'postgres', + icuDataVersion: args.icuData ? contract.icu.dataVersion : '', + icuDataForm: args.icuData ? contract.icu.dataForm : '', + icuDataTreeSha256: args.icuData ? logicalTreeSha256(filesystemTreeRows(args.icuData)) : '', + runtimeFeatures: profile.requiredRuntimeFeatures.join(','), + cacheKey: logicalTreeSha256(filesystemTreeRows(files)), + }; + const manifestPath = path.join(source, 'manifest.properties'); + writeFileSync( + manifestPath, + bindNativeClusterSeedManifest( + Buffer.from( + `${Object.entries(properties) + .map(([key, value]) => `${key}=${value}`) + .join('\n')}\n`, + ), + args.target, + args.profile, + ), + ); + validateNativeClusterSeedDirectory(source, args.profile, { + target: args.target, + icuData: args.icuData, + }); + rmSync(args.destination, { recursive: true, force: true }); + cpSync(source, args.destination, { recursive: true, errorOnExist: true }); + console.log( + `clusterSeed=${args.destination}\ncatalogProfile=${args.profile}\ntarget=${args.target}`, + ); +} diff --git a/src/database-resources/seeds/native/tools/stage-native-cluster-seed.sh b/src/database-resources/seeds/native/tools/stage-native-cluster-seed.sh new file mode 100644 index 000000000..148f2c0bf --- /dev/null +++ b/src/database-resources/seeds/native/tools/stage-native-cluster-seed.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +helper=src/database-resources/seeds/native/tools/stage-native-cluster-seed.mts +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +bun "$helper" prepare "$@" > "$scratch/arguments" +{ + IFS= read -r -d '' runtime + IFS= read -r -d '' destination + IFS= read -r -d '' target + IFS= read -r -d '' profile + IFS= read -r -d '' icu_data +} < "$scratch/arguments" +# Distributed seeds must not depend on the release runner's locale list. +unset OLIPHAUNT_EMBEDDED_MODULE_DIR ICU_DATA OLIPHAUNT_INTERNAL_ICU_READY +unset OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY OLIPHAUNT_ICU_DATA_DIR +export OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY=1 +if [ "$profile" = icu ]; then + export ICU_DATA="$icu_data" + export OLIPHAUNT_INTERNAL_ICU_READY=1 +else + export OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY=1 +fi +case "$(uname -s)" in + Linux) export LD_LIBRARY_PATH="$runtime/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" ;; + Darwin) export DYLD_LIBRARY_PATH="$runtime/lib${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}" ;; + MINGW*|MSYS*|CYGWIN*) export PATH="$runtime/bin:$runtime/lib:$PATH" ;; +esac +mkdir -p "$scratch/seed" +"$runtime/bin/initdb" -D "$scratch/seed/files" -U postgres --auth=trust \ + --locale-provider=libc --locale=C --encoding=UTF8 -L "$runtime/share/postgresql" +bun "$helper" install "$scratch/seed" \ + --runtime "$runtime" --destination "$destination" --target "$target" --profile "$profile" \ + ${icu_data:+--icu-data} ${icu_data:+"$icu_data"} diff --git a/src/database-resources/seeds/package-carriers.mts b/src/database-resources/seeds/package-carriers.mts new file mode 100644 index 000000000..0b23a50ff --- /dev/null +++ b/src/database-resources/seeds/package-carriers.mts @@ -0,0 +1,204 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + readFileSync, + readdirSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { packageGeneratedCargoSource } from '../../../tools/packaging/cargo-source-package.mts'; +import { packGeneratedNpmCarrier } from '../../../tools/packaging/npm-package.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { + emptyDirectoryPaths, + filesystemTreeRows, + logicalTreeSha256, +} from '../contracts/native-manifest.mts'; +import { stageMobileSeed } from './package-mobile-carriers.mts'; +import { + releaseProfilePackageLicense, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { + currentProductVersionSync, + ROOT, +} from '../../../tools/release/release-artifact-targets.mts'; +import { seedCarrierIdentities } from './carrier-identities.mts'; + +export function packageSeedCarriers(argv = [], { assetDir, outputDir, sourceDir } = {}) { + const { values } = parseArgs({ + args: argv, + options: { + family: { type: 'string' }, + target: { type: 'string' }, + profile: { type: 'string' }, + }, + }); + const selected = seedCarrierIdentities().filter((item) => + Object.entries(values).every(([key, value]) => item[key] === value), + ); + if (!selected.length) throw new Error('no declared seed carrier matches the selection'); + const version = currentProductVersionSync('database-resources'); + const output = path.resolve( + outputDir ?? path.join(ROOT, 'target/database-resources/seed-carriers'), + ); + const assets = path.resolve( + assetDir ?? path.join(ROOT, 'target/database-resources/release-assets'), + ); + mkdirSync(output, { recursive: true }); + const results = []; + for (const identity of selected) { + const stem = `database-resources-${version}-seed-${identity.suffix}`; + const archive = path.join(assets, `${stem}.tar.zst`); + const manifestFile = path.join(assets, `${stem}.json`); + const manifest = JSON.parse(readFileSync(manifestFile, 'utf8')); + const archiveBytes = readFileSync(archive); + const entries = readPortableArchiveEntries(archive); + if ( + entries.get('PG_VERSION')?.data().toString('utf8').trim() !== + String(manifest.runtime.postgresMajor) || + !entries.get('global/pg_control')?.isFile + ) + throw new Error(`${stem} is not an importable PostgreSQL cluster archive`); + if ( + manifest.catalogProfile !== identity.profile || + manifest.runtime.engineFamily !== identity.family || + manifest.runtime.target !== identity.target || + manifest.archive.sha256 !== createHash('sha256').update(archiveBytes).digest('hex') + ) + throw new Error(`${stem} does not match the selected seed or its checksum`); + const stage = path.join( + sourceDir ?? path.join(ROOT, 'target/database-resources/seed-package-sources'), + identity.suffix, + ); + rmSync(stage, { recursive: true, force: true }); + mkdirSync(stage, { recursive: true }); + copyFileSync(archive, path.join(stage, 'seed.tar.zst')); + copyFileSync(manifestFile, path.join(stage, 'manifest.json')); + const noticeProfile = 'native-runtime-resources'; + const license = releaseProfilePackageLicense(noticeProfile).spdx; + stageReleaseNotices(stage, { profile: noticeProfile }); + writeFileSync( + path.join(stage, 'README.md'), + `# ${identity.npm}\n\nOne ${identity.profile} ${identity.family} PostgreSQL cluster seed for ${identity.target}.\nSee manifest.json for physical compatibility and producer identity.\n${identity.profile === 'icu' ? 'ICU data comes from the separate canonical ICU dependency.\n' : ''}`, + ); + const npm = { + name: identity.npm, + version, + description: `PostgreSQL ${identity.family} ${identity.profile} cluster seed for ${identity.target}.`, + license, + repository: { + type: 'git', + url: 'git+https://github.com/f0rr0/oliphaunt.git', + directory: 'database-resources', + }, + publishConfig: { access: 'public', provenance: true }, + files: ['seed.tar.zst', 'manifest.json', 'LICENSE', 'THIRD_PARTY*'], + exports: { + './seed.tar.zst': './seed.tar.zst', + './manifest.json': './manifest.json', + './package.json': './package.json', + }, + ...(identity.profile === 'icu' ? { dependencies: { '@oliphaunt/icu': version } } : {}), + }; + if (identity.family === 'native') { + let directory = 'pgdata'; + if (identity.target === 'ios-datum64') { + const name = `OliphauntSeedNativeIOS${identity.profile === 'icu' ? 'ICU' : 'Standard'}`; + const resource = identity.profile === 'icu' ? 'cluster-seed-icu' : 'cluster-seed'; + const bundle = `${name}.bundle`; + let icuData; + const icuStage = path.join(stage, '.icu-validation'); + if (identity.profile === 'icu') { + extractPortableArchiveTree( + path.join(assets, `database-resources-${version}-icu-data.tar.gz`), + icuStage, + ); + icuData = path.join(icuStage, 'share/icu'); + } + stageMobileSeed({ + archive, + manifest: manifestFile, + destination: path.join(stage, bundle, resource), + target: identity.target, + profile: identity.profile, + icuData, + }); + rmSync(icuStage, { recursive: true, force: true }); + directory = `${bundle}/${resource}/files`; + writeFileSync( + path.join(stage, bundle, 'Info.plist'), + `CFBundleIdentifierdev.oliphaunt.seed.ios.${identity.profile}CFBundleName${name}CFBundlePackageTypeBNDL\n`, + ); + writeFileSync( + path.join(stage, `${name}.podspec`), + `Pod::Spec.new do |s|\n s.name = '${name}'\n s.version = '${version}'\n s.summary = 'Selectable native PostgreSQL ${identity.profile} seed for iOS.'\n s.homepage = 'https://oliphaunt.dev'\n s.license = { :type => '${license}' }\n s.author = { 'Oliphaunt Maintainers' => 'https://github.com/f0rr0' }\n s.source = { :path => '.' }\n s.platforms = { :ios => '17.0' }\n s.resources = '${bundle}'\nend\n`, + ); + // The React Native plugin registers only the selected resource pods. + writeFileSync( + path.join(stage, 'react-native.config.js'), + `module.exports = { dependency: { platforms: { ios: null, android: null } } };\n`, + ); + npm.files.push(bundle, `${name}.podspec`, 'react-native.config.js'); + } else { + extractPortableArchiveTree(archive, path.join(stage, directory)); + npm.files.push(directory); + } + const treeSha256 = logicalTreeSha256(filesystemTreeRows(path.join(stage, directory))); + writeFileSync( + path.join(stage, 'manifest.json'), + `${JSON.stringify({ ...manifest, directory: { path: directory, treeSha256, emptyDirectories: emptyDirectoryPaths(path.join(stage, directory)) } }, null, 2)}\n`, + ); + npm.files = npm.files.filter((file) => file !== 'seed.tar.zst'); + delete npm.exports['./seed.tar.zst']; + npm.exports['./pgdata/PG_VERSION'] = `./${directory}/PG_VERSION`; + rmSync(path.join(stage, 'seed.tar.zst')); + } + writeFileSync(path.join(stage, 'package.json'), `${JSON.stringify(npm, null, 2)}\n`); + const npmArchive = packGeneratedNpmCarrier(stage, path.join(output, 'npm')); + // Cargo preserves its existing compressed include_bytes interface. + if (identity.family === 'native') { + for (const name of readdirSync(stage)) { + if ( + name === 'pgdata' || + name.endsWith('.bundle') || + name.endsWith('.podspec') || + name === 'react-native.config.js' + ) + rmSync(path.join(stage, name), { recursive: true, force: true }); + } + } + copyFileSync(archive, path.join(stage, 'seed.tar.zst')); + copyFileSync(manifestFile, path.join(stage, 'manifest.json')); + rmSync(path.join(stage, 'package.json')); + mkdirSync(path.join(stage, 'src')); + writeFileSync( + path.join(stage, 'src/lib.rs'), + `#![deny(unsafe_code)]\npub fn seed_archive() -> &'static [u8] { include_bytes!("../seed.tar.zst") }\npub fn seed_manifest() -> &'static str { include_str!("../manifest.json") }\n${identity.profile === 'icu' ? 'pub use oliphaunt_icu as icu;\n' : ''}`, + ); + writeFileSync( + path.join(stage, 'Cargo.toml'), + `[package]\nname = ${JSON.stringify(identity.cargo)}\nversion = ${JSON.stringify(version)}\nedition = "2024"\nrust-version = "1.93"\ndescription = ${JSON.stringify(npm.description)}\nlicense = ${JSON.stringify(license)}\nrepository = "https://github.com/f0rr0/oliphaunt"\ninclude = ["src/**", "seed.tar.zst", "manifest.json", "README.md", "LICENSE", "THIRD_PARTY*"]\n${identity.profile === 'icu' ? `\n[dependencies]\noliphaunt-icu = "=${version}"\n` : ''}\n[workspace]\n`, + ); + const crate = packageGeneratedCargoSource( + path.join(stage, 'Cargo.toml'), + path.join(output, 'cargo'), + { root: ROOT }, + ); + if (statSync(crate).size > 10 * 1024 * 1024) + throw new Error(`${identity.cargo} exceeds the registry package limit`); + results.push({ ...identity, version, npmArchive, crate }); + } + return results; +} + +if (import.meta.main) + console.log(JSON.stringify(packageSeedCarriers(process.argv.slice(2)), null, 2)); diff --git a/src/database-resources/seeds/package-mobile-carriers.mts b/src/database-resources/seeds/package-mobile-carriers.mts new file mode 100644 index 000000000..dea9fcc2b --- /dev/null +++ b/src/database-resources/seeds/package-mobile-carriers.mts @@ -0,0 +1,243 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { copyFileSync, cpSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { gzipSync } from 'node:zlib'; +import { + createDeterministicTar, + createDeterministicZip, +} from '../../../tools/packaging/archive-directory.mts'; +import { extractPortableArchiveTree } from '../../../tools/packaging/portable-archive.mts'; +import { + releaseProfileMavenLicenses, + releaseProfilePackageLicense, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { stageMavenArtifactManifest } from '../../../tools/packaging/maven-artifact-staging.mts'; +import { + currentProductVersionSync, + ROOT, +} from '../../../tools/release/release-artifact-targets.mts'; +import { + bindNativeClusterSeedManifest, + filesystemTreeRows, + logicalTreeSha256, + nativeClusterSeedCompatibilityKey, + validateNativeClusterSeedDirectory, +} from '../contracts/native-manifest.mts'; +import { validateNativeIcuDataManifest } from '../contracts/icu-data.mts'; + +const contract = JSON.parse( + readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), +); + +/** Adapt the canonical seed into the existing native mobile resource contract. */ +export function stageMobileSeed({ archive, manifest, destination, target, profile, icuData }) { + if ( + !['android-datum64', 'ios-datum64'].includes(target) || + !['standard', 'icu'].includes(profile) + ) + throw new Error('a declared mobile seed target and profile are required'); + const metadata = JSON.parse(readFileSync(manifest, 'utf8')); + const digest = createHash('sha256').update(readFileSync(archive)).digest('hex'); + if ( + metadata.schema !== contract.manifests.wasix.schema || + metadata.catalogProfile !== profile || + metadata.artifactRole !== contract.profiles[profile].artifactRole || + metadata.runtime?.engineFamily !== 'native' || + metadata.runtime.target !== target || + metadata.runtime.postgresMajor !== 18 || + metadata.runtime.physicalFormat !== contract.physicalFormats.native || + metadata.runtime.compatibilityKey !== nativeClusterSeedCompatibilityKey(target) || + metadata.archive?.sha256 !== digest + ) + throw new Error( + 'mobile seed does not match its target, profile, native compatibility or checksum', + ); + if ((profile === 'icu') !== (metadata.icu !== null)) + throw new Error('mobile seed ICU selection mismatch'); + rmSync(destination, { recursive: true, force: true }); + const files = path.join(destination, 'files'); + mkdirSync(files, { recursive: true }); + extractPortableArchiveTree(archive, files); + const properties = { + schema: contract.manifests.native.schema, + layout: contract.manifests.native.layout, + artifactRole: metadata.artifactRole, + catalogProfile: profile, + postgresMajor: '18', + physicalFormat: contract.physicalFormats.native, + initialSuperuser: 'postgres', + icuDataVersion: metadata.icu?.dataVersion ?? '', + icuDataForm: metadata.icu?.dataForm ?? '', + runtimeFeatures: contract.profiles[profile].requiredRuntimeFeatures.join(','), + icuDataTreeSha256: metadata.icu?.dataTreeSha256 ?? '', + cacheKey: logicalTreeSha256(filesystemTreeRows(files)), + }; + const unbound = Buffer.from( + Object.entries(properties) + .map(([key, value]) => `${key}=${value}`) + .join('\n') + '\n', + ); + writeFileSync( + path.join(destination, 'manifest.properties'), + bindNativeClusterSeedManifest(unbound, target, profile), + ); + validateNativeClusterSeedDirectory(destination, profile, { target, icuData }); + return metadata; +} + +export async function packageMobileSeedCarriers({ + targets = ['android-datum64', 'ios-datum64'], + profiles = ['standard', 'icu'], + assetDir, + workDir, + mavenDir, +} = {}) { + const version = currentProductVersionSync('database-resources'); + const assets = path.resolve( + assetDir ?? path.join(ROOT, 'target/database-resources/release-assets'), + ); + const work = path.resolve( + workDir ?? path.join(ROOT, 'target/database-resources/mobile-carriers'), + ); + const rows = []; + const results = []; + const swiftRoot = path.join(work, 'oliphaunt-database-resources'); + const extractedIcu = path.join(work, 'icu'); + if (profiles.includes('icu') || targets.includes('ios-datum64')) { + rmSync(extractedIcu, { recursive: true, force: true }); + extractPortableArchiveTree( + path.join(assets, `database-resources-${version}-icu-data.tar.gz`), + extractedIcu, + ); + validateNativeIcuDataManifest( + readFileSync(path.join(extractedIcu, 'manifest.properties')), + path.join(extractedIcu, 'share/icu'), + 'canonical mobile ICU data', + ); + } + const swiftProducts = []; + const swiftTargets = []; + if (targets.includes('ios-datum64')) rmSync(swiftRoot, { recursive: true, force: true }); + for (const target of targets) + for (const profile of profiles) { + const suffix = `native-${target}-${profile}`; + const stage = path.join(work, suffix); + rmSync(stage, { recursive: true, force: true }); + const swift = target === 'ios-datum64'; + const name = `OliphauntSeedNativeIOS${profile === 'icu' ? 'ICU' : 'Standard'}`; + const resource = profile === 'icu' ? 'cluster-seed-icu' : 'cluster-seed'; + const resourceRoot = swift ? path.join(swiftRoot, 'Sources', name) : stage; + const stem = `database-resources-${version}-seed-${suffix}`; + stageMobileSeed({ + archive: path.join(assets, `${stem}.tar.zst`), + manifest: path.join(assets, `${stem}.json`), + destination: path.join(resourceRoot, resource), + target, + profile, + icuData: profile === 'icu' ? path.join(extractedIcu, 'share/icu') : undefined, + }); + stageReleaseNotices(swift ? swiftRoot : stage, { profile: 'native-runtime-resources' }); + if (swift) { + writeFileSync( + path.join(resourceRoot, 'Resources.swift'), + `import Foundation\npublic enum ${name} {\n public static var resourceRoot: URL { Bundle.module.resourceURL! }\n}\n`, + ); + swiftProducts.push(`.library(name: "${name}", targets: ["${name}"])`); + swiftTargets.push( + `.target(name: "${name}", dependencies: [${profile === 'icu' ? '"OliphauntICU"' : ''}], resources: [.copy("${resource}")])`, + ); + } else { + const output = path.join(assets, `${stem}-maven.tar.gz`); + writeFileSync(output, gzipSync(await createDeterministicTar(stage), { level: 9 })); + rows.push( + [ + 'dev.oliphaunt.runtime', + `oliphaunt-seed-${suffix}`, + version, + output, + `Oliphaunt ${profile} Android cluster seed`, + `Selectable PostgreSQL native ${profile} cluster seed for Android.`, + '', + '', + releaseProfilePackageLicense('native-runtime-resources').spdx, + JSON.stringify( + releaseProfileMavenLicenses('native-runtime-resources', { + product: 'database-resources', + version, + }), + ), + ].join('\t'), + ); + results.push(output); + } + } + if (swiftProducts.length) { + const icu = path.join(swiftRoot, 'Sources/OliphauntICU'); + mkdirSync(icu, { recursive: true }); + cpSync(path.join(extractedIcu, 'share'), path.join(icu, 'share'), { recursive: true }); + copyFileSync( + path.join(extractedIcu, 'manifest.properties'), + path.join(icu, 'manifest.properties'), + ); + rmSync(extractedIcu, { recursive: true, force: true }); + validateNativeIcuDataManifest( + readFileSync(path.join(icu, 'manifest.properties')), + path.join(icu, 'share/icu'), + 'Swift ICU resource', + ); + writeFileSync( + path.join(icu, 'Resources.swift'), + 'import Foundation\npublic enum OliphauntICUResources { public static var resourceRoot: URL { Bundle.module.resourceURL! } }\n', + ); + swiftProducts.push('.library(name: "OliphauntICU", targets: ["OliphauntICU"])'); + swiftTargets.push( + '.target(name: "OliphauntICU", resources: [.copy("share"), .copy("manifest.properties")])', + ); + writeFileSync( + path.join(swiftRoot, 'Package.swift'), + `// swift-tools-version: 6.0\nimport PackageDescription\nlet package = Package(name: "OliphauntDatabaseResources", products: [${swiftProducts.join(', ')}], targets: [${swiftTargets.join(', ')}])\n`, + ); + const output = path.join(assets, `database-resources-${version}-swift.zip`); + writeFileSync(output, await createDeterministicZip(swiftRoot)); + results.push(output); + } + if (rows.length) { + const manifest = path.join(work, 'maven.tsv'); + writeFileSync(manifest, rows.join('\n') + '\n'); + await stageMavenArtifactManifest( + manifest, + mavenDir ?? path.join(ROOT, 'target/release/maven-staging/database-resources-seeds'), + ); + } + return results; +} + +if (import.meta.main) { + if (process.argv[2] === 'stage') { + const options = {}; + const allowed = new Set([ + 'archive', + 'manifest', + 'destination', + 'target', + 'profile', + 'icu-data', + ]); + const args = process.argv.slice(3); + for (let i = 0; i < args.length; i += 2) { + const key = args[i].replace(/^--/, ''); + if (!args[i].startsWith('--') || !allowed.has(key) || !args[i + 1] || options[key]) + throw new Error( + 'usage: stage --archive FILE --manifest FILE --destination DIR --target TARGET --profile PROFILE [--icu-data DIR]', + ); + options[key] = args[i + 1]; + } + for (const key of ['archive', 'manifest', 'destination', 'target', 'profile']) + if (!options[key]) throw new Error(`stage requires --${key}`); + stageMobileSeed({ ...options, icuData: options['icu-data'] }); + } else { + await packageMobileSeedCarriers(process.argv[2] ? { targets: [process.argv[2]] } : {}); + } +} diff --git a/src/database-resources/seeds/package-mobile-carriers.test.mts b/src/database-resources/seeds/package-mobile-carriers.test.mts new file mode 100644 index 000000000..3e0781da8 --- /dev/null +++ b/src/database-resources/seeds/package-mobile-carriers.test.mts @@ -0,0 +1,70 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { createDeterministicTar } from '../../../tools/packaging/archive-directory.mts'; +import { releaseZstdCompressSync } from '../../../tools/packaging/portable-archive.mts'; +import { + NATIVE_PGDATA_DIRECTORIES, + nativeClusterSeedCompatibilityKey, + parseProperties, +} from '../contracts/native-manifest.mts'; +import { stageMobileSeed } from './package-mobile-carriers.mts'; + +test('mobile carrier preserves seed bytes and rejects wrong target, profile and digest', async () => { + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-mobile-carrier-')); + try { + const source = path.join(scratch, 'fixture'); + for (const directory of NATIVE_PGDATA_DIRECTORIES) + mkdirSync(path.join(source, directory), { recursive: true }); + writeFileSync(path.join(source, 'PG_VERSION'), '18\n'); + writeFileSync(path.join(source, 'global/pg_control'), 'archive-layout-fixture-only'); + const archive = path.join(scratch, 'seed.tar.zst'); + const bytes = releaseZstdCompressSync(await createDeterministicTar(source)); + writeFileSync(archive, bytes); + const contract = JSON.parse( + readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), + ); + const metadata = { + schema: contract.manifests.wasix.schema, + catalogProfile: 'standard', + artifactRole: 'cluster-seed-standard', + runtime: { + engineFamily: 'native', + target: 'android-datum64', + postgresMajor: 18, + physicalFormat: contract.physicalFormats.native, + compatibilityKey: nativeClusterSeedCompatibilityKey('android-datum64'), + }, + archive: { sha256: createHash('sha256').update(bytes).digest('hex') }, + icu: null, + }; + const manifest = path.join(scratch, 'seed.json'); + writeFileSync(manifest, JSON.stringify(metadata)); + const destination = path.join(scratch, 'carrier/cluster-seed'); + const options = { + archive, + manifest, + destination, + target: 'android-datum64', + profile: 'standard', + }; + stageMobileSeed(options); + expect(readFileSync(path.join(destination, 'files/global/pg_control'), 'utf8')).toBe( + 'archive-layout-fixture-only', + ); + const properties = parseProperties( + readFileSync(path.join(destination, 'manifest.properties')), + 'test carrier', + ); + expect(properties.get('target')).toBe('android-datum64'); + expect(properties.get('icuDataTreeSha256')).toBe(''); + expect(() => stageMobileSeed({ ...options, target: 'ios-datum64' })).toThrow('does not match'); + expect(() => stageMobileSeed({ ...options, profile: 'icu' })).toThrow('does not match'); + writeFileSync(archive, Buffer.from('corrupt')); + expect(() => stageMobileSeed(options)).toThrow('checksum'); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); diff --git a/src/database-resources/seeds/package.mts b/src/database-resources/seeds/package.mts new file mode 100644 index 000000000..c6b46e7d5 --- /dev/null +++ b/src/database-resources/seeds/package.mts @@ -0,0 +1,108 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { createDeterministicTar } from '../../../tools/packaging/archive-directory.mts'; +import { releaseZstdCompressSync } from '../../../tools/packaging/portable-archive.mts'; +import { currentProductVersionSync } from '../../../tools/release/release-artifact-targets.mts'; +import { + filesystemTreeRows, + logicalTreeSha256, + nativeClusterSeedCompatibilityKey, + validatePgdataDirectories, +} from '../contracts/native-manifest.mts'; + +const { values } = parseArgs({ + options: Object.fromEntries( + ['family', 'profile', 'target', 'pgdata', 'runtime', 'icu-data', 'output-dir'].map((name) => [ + name, + { type: 'string' }, + ]), + ), +}); +const { family, profile, target, pgdata, runtime } = values; +if ( + !['native', 'wasix'].includes(family) || + !['standard', 'icu'].includes(profile) || + !pgdata || + !runtime || + !target +) + throw new Error('family, profile, target, pgdata and runtime are required'); +if ((profile === 'icu') !== Boolean(values['icu-data'])) + throw new Error('only ICU seeds require --icu-data'); +const contract = JSON.parse( + readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), +); +const postgresMajor = Number(readFileSync(path.join(pgdata, 'PG_VERSION'), 'utf8').trim()); +validatePgdataDirectories(pgdata); +if (postgresMajor !== 18 || statSync(path.join(pgdata, 'global/pg_control')).size === 0) + throw new Error('seed is not a complete PostgreSQL 18 cluster'); +const digest = (bytes) => createHash('sha256').update(bytes).digest('hex'); +const executable = (name) => + path.join(runtime, 'bin', `${name}${target.startsWith('windows-') ? '.exe' : ''}`); +const runtimeDigest = digest(readFileSync(executable('postgres'))); +const initdbDigest = digest(readFileSync(executable('initdb'))); +const version = currentProductVersionSync('database-resources'); +const name = `database-resources-${version}-seed-${family}${family === 'native' ? `-${target}` : ''}-${profile}`; +const output = path.resolve(values['output-dir'] ?? 'target/database-resources/release-assets'); +const rows = filesystemTreeRows(pgdata); +let directories = 0; +function countDirectories(root) { + for (const entry of readdirSync(root, { withFileTypes: true })) + if (entry.isDirectory()) { + directories++; + countDirectories(path.join(root, entry.name)); + } +} +countDirectories(pgdata); +const archive = releaseZstdCompressSync(await createDeterministicTar(pgdata)); +const icu = + profile === 'icu' + ? { + artifactRole: contract.icu.artifactRole, + dataVersion: contract.icu.dataVersion, + dataForm: contract.icu.dataForm, + dataTreeSha256: logicalTreeSha256(filesystemTreeRows(values['icu-data'])), + } + : null; +const manifest = { + schema: contract.manifests.wasix.schema, + artifactRole: contract.profiles[profile].artifactRole, + catalogProfile: profile, + runtime: { + product: `liboliphaunt-${family}`, + version: currentProductVersionSync(`liboliphaunt-${family}`), + engineFamily: family, + target, + physicalFormat: contract.physicalFormats[family], + postgresMajor, + compatibilityKey: + family === 'native' + ? nativeClusterSeedCompatibilityKey(target) + : contract.compatibilityKeys.wasixDatum32, + ...(family === 'wasix' + ? { consumerSha256: runtimeDigest, producerSha256: runtimeDigest, initdbSha256: initdbDigest } + : {}), + }, + source: { + producer: `${family}-initdb`, + ...(family === 'native' ? { postgresSha256: runtimeDigest, initdbSha256: initdbDigest } : {}), + }, + archive: { + path: `${name}.tar.zst`, + sha256: digest(archive), + compressedBytes: archive.length, + expandedBytes: rows.reduce((sum, row) => sum + row.bytes.length, 0), + regularFiles: rows.length, + directories, + }, + requiredRuntimeFeatures: contract.profiles[profile].requiredRuntimeFeatures, + extensions: { selected: [], startupConfiguration: [] }, + icu, +}; +mkdirSync(output, { recursive: true }); +writeFileSync(path.join(output, `${name}.tar.zst`), archive); +writeFileSync(path.join(output, `${name}.json`), `${JSON.stringify(manifest, null, 2)}\n`); +console.log(path.join(output, `${name}.tar.zst`)); diff --git a/src/database-resources/seeds/package.sh b/src/database-resources/seeds/package.sh new file mode 100644 index 000000000..0f7d6f3b4 --- /dev/null +++ b/src/database-resources/seeds/package.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +cd "$root" +family="${1:?native or wasix is required}" +target="${2:-${OLIPHAUNT_CI_TARGET:-}}" +if [ "$family" = wasix ]; then target=portable; fi +if [ -z "$target" ]; then + source src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh + target="$(oliphaunt_runtime_native_host_target_id)" +fi +bash tools/ci/with-projects.sh src/database-resources/seeds/package-carriers.mts --family "$family" --target "$target" +case "$target" in + android-datum64|ios-datum64) + bash tools/ci/with-projects.sh src/database-resources/seeds/package-mobile-carriers.mts "$target" + ;; +esac diff --git a/src/database-resources/seeds/wasix/Cargo.toml b/src/database-resources/seeds/wasix/Cargo.toml new file mode 100644 index 000000000..d47bbd121 --- /dev/null +++ b/src/database-resources/seeds/wasix/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "oliphaunt-wasix-seed-producer" +version = "0.0.0" +edition = "2024" +rust-version = "1.93" +license.workspace = true +publish = false + +[[bin]] +name = "oliphaunt-wasix-seed-producer" +path = "src/main.rs" +required-features = ["cluster-seed-runner"] + +[features] +default = [] +cluster-seed-runner = ["dep:wasmer", "dep:wasmer-wasix", "dep:tokio", "dep:webc", "dep:async-trait"] + +[dependencies] +anyhow = "1" +async-trait = { version = "0.1", optional = true } +serde = { version = "1", features = ["derive"] } +serde_json = "1" +tokio = { version = "1", features = ["rt-multi-thread"], optional = true } +wasmer = { version = "=7.2.1", default-features = false, features = ["sys", "llvm"], optional = true } +wasmer-wasix = { version = "=0.702.1", default-features = false, features = ["sys-minimal", "sys-poll", "sys-thread", "time", "host-fs"], optional = true } +webc = { version = "=12.0.0", optional = true } diff --git a/src/database-resources/seeds/wasix/src/lib.rs b/src/database-resources/seeds/wasix/src/lib.rs new file mode 100644 index 000000000..7aada9464 --- /dev/null +++ b/src/database-resources/seeds/wasix/src/lib.rs @@ -0,0 +1,631 @@ +use std::fs; +use std::path::Path; + +use anyhow::{Context, Result, bail}; + +#[cfg(feature = "cluster-seed-runner")] +pub const INTERNAL_ICU_READY_ENV: &str = "OLIPHAUNT_INTERNAL_ICU_READY"; +#[cfg(feature = "cluster-seed-runner")] +pub const INTERNAL_ICU_READY_VALUE: &str = "1"; +#[cfg(feature = "cluster-seed-runner")] +const SKIP_SYSTEM_COLLATION_DISCOVERY_ENV: &str = + "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY"; +#[cfg(feature = "cluster-seed-runner")] +const SKIP_ICU_COLLATION_DISCOVERY_ENV: &str = "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY"; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CatalogProfile { + Standard, + Icu, +} + +impl CatalogProfile { + pub const ALL: [Self; 2] = [Self::Standard, Self::Icu]; + + pub const fn as_str(self) -> &'static str { + match self { + Self::Standard => "standard", + Self::Icu => "icu", + } + } + + pub const fn artifact_role(self) -> &'static str { + match self { + Self::Standard => "cluster-seed-standard", + Self::Icu => "cluster-seed-icu", + } + } +} + +pub fn default_initdb_profile() -> &'static str { + "allow-group-access,encoding=UTF8,locale=C.UTF-8,locale-provider=libc,auth=trust,no-sync" +} + +pub fn clean_generated_cluster_seed(pgdata: &Path) -> Result<()> { + #[derive(serde::Deserialize)] + #[serde(rename_all = "camelCase")] + struct Contract { + pgdata_directories: Vec, + } + let contract: Contract = + serde_json::from_str(include_str!("../../../contracts/contract.json"))?; + for directory in contract.pgdata_directories { + let metadata = fs::symlink_metadata(pgdata.join(&directory)).with_context(|| { + format!("cluster seed is missing required PostgreSQL directory {directory}") + })?; + anyhow::ensure!( + metadata.is_dir(), + "cluster seed has an unsafe PostgreSQL directory {directory}" + ); + } + for name in ["postmaster.pid", "postmaster.opts"] { + let path = pgdata.join(name); + if path.exists() { + fs::remove_file(&path).with_context(|| format!("remove {}", path.display()))?; + } + } + Ok(()) +} + +#[cfg(feature = "cluster-seed-runner")] +pub fn run_wasix_initdb_cluster_seed( + runtime_stage: &Path, + work_root: &Path, + profile: CatalogProfile, + icu_data_root: Option<&Path>, +) -> Result<()> { + use std::env; + use std::sync::Arc; + + use wasmer::Engine; + use wasmer_wasix::bin_factory::BinaryPackage; + use wasmer_wasix::runners::wasi::{RuntimeOrEngine, WasiRunner}; + use wasmer_wasix::runtime::task_manager::tokio::TokioTaskManager; + use wasmer_wasix::runtime::{PluggableRuntime, Runtime}; + use wasmer_wasix::virtual_fs; + use wasmer_wasix::virtual_fs::null_file::NullFile; + + let package_dir = work_root.join("package"); + let package_root = work_root.join("root"); + let pgdata_root = work_root.join("pgdata"); + fs::create_dir_all(package_dir.join("modules")) + .with_context(|| format!("create {}", package_dir.join("modules").display()))?; + fs::create_dir_all(&pgdata_root) + .with_context(|| format!("create {}", pgdata_root.display()))?; + copy_tree(runtime_stage, &package_root)?; + let staged_icu_data = package_root.join("share/icu"); + if staged_icu_data.exists() { + fs::remove_dir_all(&staged_icu_data) + .with_context(|| format!("remove {}", staged_icu_data.display()))?; + } + match (profile, icu_data_root) { + (CatalogProfile::Standard, None) => {} + (CatalogProfile::Standard, Some(_)) => { + bail!("standard cluster-seed generation must not receive ICU data") + } + (CatalogProfile::Icu, Some(icu_data_root)) => { + copy_tree(icu_data_root, &staged_icu_data)?; + } + (CatalogProfile::Icu, None) => { + bail!("ICU cluster-seed generation requires verified ICU data") + } + } + copy_file( + &runtime_stage.join("bin/initdb"), + &package_dir.join("modules/initdb.wasm"), + )?; + copy_file( + &runtime_stage.join("bin/postgres"), + &package_dir.join("modules/postgres.wasm"), + )?; + let wasmer_toml = r#" +[package] +name = "oliphaunt-wasix/cluster-seed-producer" +version = "0.0.0" +description = "Oliphaunt WASIX cluster seed producer" + +[[module]] +name = "initdb" +source = "modules/initdb.wasm" +abi = "wasi" + +[[module]] +name = "postgres" +source = "modules/postgres.wasm" +abi = "wasi" + +[[command]] +name = "initdb" +module = "initdb" + +[[command]] +name = "postgres" +module = "postgres" +"#; + fs::write(package_dir.join("wasmer.toml"), wasmer_toml) + .with_context(|| format!("write {}", package_dir.join("wasmer.toml").display()))?; + + let tokio_runtime = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .context("create Tokio runtime for WASIX cluster-seed generation")?; + let _guard = tokio_runtime.enter(); + let engine = Engine::default(); + let task_manager = Arc::new(TokioTaskManager::new(tokio_runtime.handle().clone())); + let mut runtime = PluggableRuntime::new(task_manager); + runtime.set_engine(engine.clone()); + runtime.set_package_loader(LocalOnlyPackageLoader); + let runtime: Arc = Arc::new(runtime); + let package = tokio_runtime + .block_on(BinaryPackage::from_dir(&package_dir, runtime.as_ref())) + .context("load WASIX initdb package")?; + let root_fs = Arc::new( + virtual_fs::host_fs::FileSystem::new(tokio_runtime.handle().clone(), &package_root) + .with_context(|| { + format!( + "create WASIX cluster-seed root filesystem at {}", + package_root.display() + ) + })?, + ) as Arc; + let pgdata_fs = Arc::new( + virtual_fs::host_fs::FileSystem::new(tokio_runtime.handle().clone(), &pgdata_root) + .with_context(|| { + format!( + "create WASIX cluster-seed PGDATA filesystem at {}", + pgdata_root.display() + ) + })?, + ) as Arc; + + let (stdout_file, stdout_capture) = TailCaptureFile::new(64 * 1024); + let (stderr_file, stderr_capture) = TailCaptureFile::new(64 * 1024); + let run_result = { + let mut runner = WasiRunner::new(); + runner.with_current_dir("/"); + runner.with_mount("/".to_owned(), root_fs.clone()); + runner.with_mount("/base".to_owned(), pgdata_fs.clone()); + runner.with_args(default_initdb_args()); + runner.with_envs(cluster_seed_producer_environment(profile)); + runner.with_stdin(Box::::default()); + runner.with_stdout(Box::new(stdout_file)); + runner.with_stderr(Box::new(stderr_file)); + runner.run_command( + "initdb", + &package, + RuntimeOrEngine::Runtime(runtime.clone()), + ) + }; + let stdout = stdout_capture.text(); + let stderr = stderr_capture.text(); + if env::var_os("OLIPHAUNT_WASM_CLUSTER_SEED_LOG").is_some() || run_result.is_err() { + print_captured_wasix_output("initdb stdout", &stdout); + print_captured_wasix_output("initdb stderr", &stderr); + } + run_result.context("run WASIX initdb to generate cluster seed")?; + verify_wasix_cluster_seed_profile(&package, runtime, root_fs, pgdata_fs, profile) +} + +#[cfg(not(feature = "cluster-seed-runner"))] +pub fn run_wasix_initdb_cluster_seed( + _runtime_stage: &Path, + _work_root: &Path, + _profile: CatalogProfile, + _icu_data_root: Option<&Path>, +) -> Result<()> { + bail!( + "WASIX seed generation requires the seed producer's `cluster-seed-runner` feature; run `bash src/database-resources/seeds/build.sh`" + ) +} + +#[cfg_attr(not(feature = "cluster-seed-runner"), allow(dead_code))] +fn default_initdb_args() -> Vec<&'static str> { + vec![ + "--allow-group-access", + "--encoding", + "UTF8", + "--locale=C.UTF-8", + "--locale-provider=libc", + "--auth=trust", + "--no-sync", + "-D", + "/base", + ] +} + +#[cfg(feature = "cluster-seed-runner")] +fn cluster_seed_environment(profile: CatalogProfile) -> Vec<(&'static str, &'static str)> { + let mut environment = vec![ + ("PGDATA", "/base"), + ("PGSYSCONFDIR", "/base"), + ("HOME", "/home/postgres"), + ("USER", "postgres"), + ("LOGNAME", "postgres"), + ("PGCLIENTENCODING", "UTF8"), + ("PATH", "/bin"), + ("LC_CTYPE", "C.UTF-8"), + ("TZ", "UTC"), + ("PGTZ", "UTC"), + ("PG_COLOR", "never"), + ]; + if profile == CatalogProfile::Icu { + environment.push(("ICU_DATA", "/share/icu")); + } + environment +} + +#[cfg(feature = "cluster-seed-runner")] +fn cluster_seed_producer_environment(profile: CatalogProfile) -> Vec<(&'static str, &'static str)> { + let mut environment = cluster_seed_environment(profile); + environment.push((SKIP_SYSTEM_COLLATION_DISCOVERY_ENV, "1")); + if profile == CatalogProfile::Standard { + environment.push((SKIP_ICU_COLLATION_DISCOVERY_ENV, "1")); + } else { + environment.push((INTERNAL_ICU_READY_ENV, INTERNAL_ICU_READY_VALUE)); + } + environment +} + +#[cfg(feature = "cluster-seed-runner")] +fn verify_wasix_cluster_seed_profile( + package: &wasmer_wasix::bin_factory::BinaryPackage, + runtime: std::sync::Arc, + root_fs: std::sync::Arc, + pgdata_fs: std::sync::Arc, + profile: CatalogProfile, +) -> Result<()> { + use wasmer_wasix::runners::wasi::{RuntimeOrEngine, WasiRunner}; + use wasmer_wasix::virtual_fs; + + const CONTRACT_JSON: &str = include_str!("../../../contracts/profile-probe.json"); + + let contract: ClusterSeedProfileProbeContract = + serde_json::from_str(CONTRACT_JSON).context("parse shared cluster-seed profile probe")?; + if contract.schema != "oliphaunt-cluster-seed-profile-probe-v1" { + bail!( + "unsupported shared cluster-seed profile probe schema {}", + contract.schema + ); + } + let probe = match profile { + CatalogProfile::Standard => &contract.profiles.standard, + CatalogProfile::Icu => &contract.profiles.icu, + }; + + for attempt in 1..=2 { + let (stdout_file, stdout_capture) = TailCaptureFile::new(64 * 1024); + let (stderr_file, stderr_capture) = TailCaptureFile::new(64 * 1024); + let mut runner = WasiRunner::new(); + runner.with_current_dir("/"); + runner.with_mount("/".to_owned(), root_fs.clone()); + runner.with_mount("/base".to_owned(), pgdata_fs.clone()); + runner.with_args(vec!["--single", "-D", "/base", "postgres"]); + runner.with_envs(cluster_seed_environment(profile)); + runner.with_stdin(Box::new(virtual_fs::StaticFile::new( + format!("{};\n", probe.sql).into_bytes(), + ))); + runner.with_stdout(Box::new(stdout_file)); + runner.with_stderr(Box::new(stderr_file)); + let result = runner.run_command( + "postgres", + package, + RuntimeOrEngine::Runtime(runtime.clone()), + ); + let stdout = stdout_capture.text(); + let stderr = stderr_capture.text(); + let failed = result.is_err() || !stdout.contains(&probe.expected); + if std::env::var_os("OLIPHAUNT_WASM_CLUSTER_SEED_LOG").is_some() || failed { + print_captured_wasix_output("profile probe stdout", &stdout); + print_captured_wasix_output("profile probe stderr", &stderr); + } + result.with_context(|| { + format!( + "run {} WASIX cluster-seed profile probe (attempt {attempt})", + profile.as_str() + ) + })?; + if !stdout.contains(&probe.expected) { + bail!( + "{} WASIX cluster-seed profile probe attempt {attempt} did not emit {:?}", + profile.as_str(), + probe.expected + ); + } + } + Ok(()) +} + +#[cfg(feature = "cluster-seed-runner")] +#[derive(Debug, serde::Deserialize)] +struct ClusterSeedProfileProbeContract { + schema: String, + profiles: ClusterSeedProfileProbes, +} + +#[cfg(feature = "cluster-seed-runner")] +#[derive(Debug, serde::Deserialize)] +struct ClusterSeedProfileProbes { + standard: ClusterSeedProfileProbe, + icu: ClusterSeedProfileProbe, +} + +#[cfg(feature = "cluster-seed-runner")] +#[derive(Debug, serde::Deserialize)] +struct ClusterSeedProfileProbe { + sql: String, + expected: String, +} + +#[cfg(feature = "cluster-seed-runner")] +fn print_captured_wasix_output(label: &str, output: &str) { + if output.trim().is_empty() { + eprintln!("{label}: "); + } else { + eprintln!("--- {label} ---"); + eprint!("{output}"); + if !output.ends_with('\n') { + eprintln!(); + } + eprintln!("--- end {label} ---"); + } +} + +#[cfg(feature = "cluster-seed-runner")] +#[derive(Debug, Default)] +struct LocalOnlyPackageLoader; + +#[cfg(feature = "cluster-seed-runner")] +#[derive(Debug, Clone)] +struct TailCaptureFile { + inner: std::sync::Arc>, + limit: usize, +} + +#[cfg(feature = "cluster-seed-runner")] +#[derive(Debug, Default)] +struct TailCaptureState { + bytes: std::collections::VecDeque, +} + +#[cfg(feature = "cluster-seed-runner")] +#[derive(Debug, Clone)] +struct TailCaptureHandle { + inner: std::sync::Arc>, +} + +#[cfg(feature = "cluster-seed-runner")] +impl TailCaptureFile { + fn new(limit: usize) -> (Self, TailCaptureHandle) { + let inner = std::sync::Arc::new(std::sync::Mutex::new(TailCaptureState::default())); + ( + Self { + inner: inner.clone(), + limit, + }, + TailCaptureHandle { inner }, + ) + } + + fn push_tail(&self, bytes: &[u8]) { + let Ok(mut state) = self.inner.lock() else { + return; + }; + for byte in bytes { + state.bytes.push_back(*byte); + while state.bytes.len() > self.limit { + state.bytes.pop_front(); + } + } + } +} + +#[cfg(feature = "cluster-seed-runner")] +impl TailCaptureHandle { + fn text(&self) -> String { + let Ok(state) = self.inner.lock() else { + return "".to_owned(); + }; + let bytes = state.bytes.iter().copied().collect::>(); + String::from_utf8_lossy(&bytes).into_owned() + } +} + +#[cfg(feature = "cluster-seed-runner")] +impl wasmer_wasix::virtual_fs::AsyncSeek for TailCaptureFile { + fn start_seek( + self: std::pin::Pin<&mut Self>, + _position: std::io::SeekFrom, + ) -> std::io::Result<()> { + Ok(()) + } + + fn poll_complete( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(0)) + } +} + +#[cfg(feature = "cluster-seed-runner")] +impl wasmer_wasix::virtual_fs::AsyncRead for TailCaptureFile { + fn poll_read( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + _buf: &mut wasmer_wasix::virtual_fs::ReadBuf<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(())) + } +} + +#[cfg(feature = "cluster-seed-runner")] +impl wasmer_wasix::virtual_fs::AsyncWrite for TailCaptureFile { + fn poll_write( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + self.push_tail(buf); + std::task::Poll::Ready(Ok(buf.len())) + } + + fn poll_flush( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(())) + } + + fn poll_shutdown( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(())) + } + + fn poll_write_vectored( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + bufs: &[std::io::IoSlice<'_>], + ) -> std::task::Poll> { + let mut total = 0; + for buf in bufs { + self.push_tail(buf); + total += buf.len(); + } + std::task::Poll::Ready(Ok(total)) + } + + fn is_write_vectored(&self) -> bool { + true + } +} + +#[cfg(feature = "cluster-seed-runner")] +impl wasmer_wasix::virtual_fs::VirtualFile for TailCaptureFile { + fn last_accessed(&self) -> u64 { + 0 + } + + fn last_modified(&self) -> u64 { + 0 + } + + fn created_time(&self) -> u64 { + 0 + } + + fn size(&self) -> u64 { + self.inner + .lock() + .map(|state| state.bytes.len() as u64) + .unwrap_or(0) + } + + fn set_len(&mut self, _new_size: u64) -> wasmer_wasix::virtual_fs::Result<()> { + Ok(()) + } + + fn unlink(&mut self) -> wasmer_wasix::virtual_fs::Result<()> { + Ok(()) + } + + fn poll_read_ready( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(0)) + } + + fn poll_write_ready( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + std::task::Poll::Ready(Ok(self.limit)) + } +} + +#[cfg(feature = "cluster-seed-runner")] +#[async_trait::async_trait] +impl wasmer_wasix::runtime::package_loader::PackageLoader for LocalOnlyPackageLoader { + async fn load( + &self, + summary: &wasmer_wasix::runtime::resolver::PackageSummary, + ) -> Result { + bail!( + "WASIX cluster-seed generation only supports local packages; unexpected dependency {}", + summary.pkg.id + ) + } + + async fn load_package_tree( + &self, + root: &webc::Container, + resolution: &wasmer_wasix::runtime::resolver::Resolution, + root_is_local_dir: bool, + ) -> Result { + wasmer_wasix::runtime::package_loader::load_package_tree( + root, + self, + resolution, + root_is_local_dir, + ) + .await + } +} + +#[cfg(feature = "cluster-seed-runner")] +fn copy_file(source: &Path, destination: &Path) -> Result<()> { + if let Some(parent) = destination.parent() { + fs::create_dir_all(parent)?; + } + fs::copy(source, destination).with_context(|| format!("copy {}", source.display()))?; + Ok(()) +} + +#[cfg(feature = "cluster-seed-runner")] +fn copy_tree(source: &Path, destination: &Path) -> Result<()> { + fs::create_dir_all(destination)?; + for entry in fs::read_dir(source)? { + let entry = entry?; + let kind = entry.file_type()?; + if kind.is_dir() { + copy_tree(&entry.path(), &destination.join(entry.file_name()))?; + } else if kind.is_file() { + copy_file(&entry.path(), &destination.join(entry.file_name()))?; + } else { + bail!( + "seed input must contain only regular files and directories: {}", + entry.path().display() + ); + } + } + Ok(()) +} + +#[cfg(test)] +mod layout_tests { + use super::*; + + #[test] + fn rejects_missing_empty_pgdata_directory() -> Result<()> { + let nonce = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH)? + .as_nanos(); + let root = std::env::temp_dir().join(format!( + "oliphaunt-seed-layout-{}-{nonce}", + std::process::id() + )); + let contract: serde_json::Value = + serde_json::from_str(include_str!("../../../contracts/contract.json"))?; + for directory in contract["pgdataDirectories"].as_array().unwrap() { + fs::create_dir_all(root.join(directory.as_str().unwrap()))?; + } + clean_generated_cluster_seed(&root)?; + fs::remove_dir(root.join("pg_notify"))?; + let error = clean_generated_cluster_seed(&root).unwrap_err(); + fs::remove_dir_all(root)?; + assert!(error.to_string().contains("pg_notify")); + Ok(()) + } +} diff --git a/src/database-resources/seeds/wasix/src/main.rs b/src/database-resources/seeds/wasix/src/main.rs new file mode 100644 index 000000000..fd8bf4827 --- /dev/null +++ b/src/database-resources/seeds/wasix/src/main.rs @@ -0,0 +1,28 @@ +use std::path::PathBuf; + +use anyhow::{Result, bail}; +use oliphaunt_wasix_seed_producer::{ + CatalogProfile, clean_generated_cluster_seed, run_wasix_initdb_cluster_seed, +}; + +fn main() -> Result<()> { + let mut args = std::env::args_os().skip(1); + let runtime = args.next().map(PathBuf::from); + let output = args.next().map(PathBuf::from); + let profile = match args.next().as_deref().and_then(|arg| arg.to_str()) { + Some("standard") => CatalogProfile::Standard, + Some("icu") => CatalogProfile::Icu, + _ => bail!( + "usage: oliphaunt-wasix-seed-producer RUNTIME_DIR WORK_DIR standard|icu [ICU_DATA_DIR]" + ), + }; + let icu = args.next().map(PathBuf::from); + let (Some(runtime), Some(output)) = (runtime, output) else { + bail!("runtime and work directories are required") + }; + if args.next().is_some() || output.exists() { + bail!("work directory must be new; no extra arguments are accepted"); + } + run_wasix_initdb_cluster_seed(&runtime, &output, profile, icu.as_deref())?; + clean_generated_cluster_seed(&output.join("pgdata")) +} diff --git a/src/database-resources/test.sh b/src/database-resources/test.sh new file mode 100644 index 000000000..ef25af34d --- /dev/null +++ b/src/database-resources/test.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/../.." +bun test ./src/database-resources/seeds/package-mobile-carriers.test.mts +bash src/database-resources/icu/tools/data.test.sh +bash src/database-resources/icu/tools/package-liboliphaunt-icu-data.test.sh +bash src/database-resources/icu/tools/icu-npm-carrier-contract.test.sh diff --git a/src/database-resources/tools/package-carriers.mts b/src/database-resources/tools/package-carriers.mts new file mode 100644 index 000000000..c5d9129e8 --- /dev/null +++ b/src/database-resources/tools/package-carriers.mts @@ -0,0 +1,42 @@ +#!/usr/bin/env bun +import { buildMavenArtifactManifest } from '../../../tools/packaging/build-maven-artifact-manifest.mts'; +import { stageMavenArtifactManifest } from '../../../tools/packaging/maven-artifact-staging.mts'; +import { writeChecksumManifest } from '../../../tools/packaging/write-checksum-manifest.mts'; +import { currentProductVersionSync } from '../../../tools/release/release-artifact-targets.mts'; +import { packageIcuCargo } from '../icu/tools/package-cargo.mts'; +import { resourceNpmTarballs } from '../icu/tools/package-npm.mts'; +import { packageSeedCarriers } from '../seeds/package-carriers.mts'; +import { packageMobileSeedCarriers } from '../seeds/package-mobile-carriers.mts'; + +export async function packageIcuCarriers() { + packageIcuCargo([]); + const packages = resourceNpmTarballs(); + const manifest = await buildMavenArtifactManifest( + 'target/release/maven-manifests/database-resources.tsv', + { + artifactProduct: 'database-resources', + artifactIds: ['oliphaunt-icu'], + runtimeAssetRoot: 'target/database-resources/release-assets', + }, + ); + await stageMavenArtifactManifest(manifest, 'target/release/maven-staging/database-resources'); + return packages; +} + +export async function packageDatabaseResourceCarriers() { + const packages = await packageIcuCarriers(); + await packageSeedCarriers([]); + await packageMobileSeedCarriers(); + const version = currentProductVersionSync('database-resources'); + await writeChecksumManifest([ + '--asset-dir', + 'target/database-resources/release-assets', + '--output', + `database-resources-${version}-release-assets.sha256`, + '--pattern', + `database-resources-${version}-*`, + ]); + return packages; +} + +if (import.meta.main) await packageIcuCarriers(); diff --git a/src/docs/DESIGN_GROUNDING.md b/src/docs/DESIGN_GROUNDING.md index b86bd43d5..2f3864f57 100644 --- a/src/docs/DESIGN_GROUNDING.md +++ b/src/docs/DESIGN_GROUNDING.md @@ -1,7 +1,7 @@ # Oliphaunt Docs Design Grounding This file keeps the docs-site work scoped to the visual and UX foundation for -`src/docs`. +`docs`. ## Goal @@ -59,13 +59,13 @@ Observed from `https://motion.dev/docs`, `/docs/react`, and deeper docs pages: ## Review Protocol - Revisit the docs app on mobile and desktop after substantial layout edits. -- Run `pnpm --dir src/docs check` before handing off docs changes. -- Use `pnpm --dir src/docs build` when changes touch route composition, +- Run `bun run --cwd docs check` before handing off docs changes. +- Use `bun run --cwd docs build` when changes touch route composition, metadata, generated content, or Next.js boundaries. ## Implementation Checklist -- [x] Scope remains inside `src/docs`. +- [x] Scope remains inside `docs`. - [ ] Landing page and every docs route reach Motion-level cleanliness on mobile and desktop. - [x] Light and dark mode both have intentional contrast and texture. @@ -76,13 +76,13 @@ Observed from `https://motion.dev/docs`, `/docs/react`, and deeper docs pages: - [x] Browser screenshots reviewed full-page on mobile and desktop after each major slice. - [x] Motion reference pages reviewed during each active implementation turn. -- [x] `pnpm --dir src/docs run check` or best available equivalent is +- [x] `bun run --cwd docs check` or best available equivalent is run before final handoff. ## Current Slice Notes - Landing was reduced to hero, SDK choices, and reference paths; standalone - landing code comparisons and repeated runtime/docs/CTA sections were removed. + landing code comparisons and repeated runtime/src/docs/CTA sections were removed. - `/docs/start` was reduced to quickstart, first-query comparison, and next steps; redundant outcome and verify panels were removed. - `/docs/learn` was converted from card-heavy maps/tabs to divider rows and diff --git a/src/docs/README.md b/src/docs/README.md index f344aeceb..f404a5fc9 100644 --- a/src/docs/README.md +++ b/src/docs/README.md @@ -1,41 +1,69 @@ -# docs +# Oliphaunt documentation -This is a Next.js application generated with -[Create Fumadocs](https://github.com/fuma-nama/fumadocs). +The site at oliphaunt.dev contains latest-product guides, maintained on main. +It has no documentation-version archives or SDK API generation dependencies. +Authored SDK API maps remain ordinary guides. -Run the development server from the repository root: +From this directory after installing the root Bun workspace: -```bash -pnpm docs:dev -``` +- `bun run dev`: prepare content and start Next.js. +- `bun run check`: check internal links and TypeScript. +- `bun run test`: exercise published-release selection and refresh-request handling. +- `bun run build`: resolve fresh completed releases and export the site. +- `bun run smoke`: check exported routes and text endpoints. -Open http://localhost:3000 with your browser to see the result. +Published versions come from GitHub's completed, non-prerelease product releases, +never the Release Please candidate manifest. Unreleased resource and package +separation examples carry an explicit development label; remove that label only +after the corresponding products are publicly available. Kotlin's plugin and library use +the same product version. SDK packages own their compatible runtime dependencies; +guides do not independently select a newer runtime. -## Explore +Each preparation resolves GitHub metadata anew and fails on network errors. +For an explicit offline build set `OLIPHAUNT_DOCS_RELEASES_FILE` to a previously +resolved `target/docs/published-releases.json` (absolute path recommended), or +a fixture containing GitHub release records. This is an opt-in snapshot, not +automatic stale fallback. `GITHUB_TOKEN` is optional for GitHub rate limits. -In the project, you can see: +Vercel should build main for documentation changes, and rebuild once after an +entire product release operation has finalized. Build from this project with +`bun run build`; the export is `out` and the repository qualification copy +is `target/docs/build`. Deployment-hook credentials and actual deployment +status monitoring are release-integration responsibilities. No remote Vercel +configuration is changed by local builds. -- `lib/source.ts`: Code for content source adapter, [`loader()`](https://fumadocs.dev/docs/headless/source-api) provides the interface to access your content. -- `lib/layout.shared.tsx`: Shared options for layouts, optional but preferred to keep. +## Release-triggered refresh -| Route | Description | -| ------------------------- | ------------------------------------------------------ | -| `app/(home)` | The route group for your landing page and other pages. | -| `app/docs` | The documentation layout and pages. | -| `app/api/search/route.ts` | The Route Handler for search. | +After the complete `publish` job successfully promotes a nonempty public release batch, the Release workflow runs a separate +`Refresh published docs` job in the `Production` environment. It snapshots completed +public releases, sends one POST, and checks the live version page for links to +those releases (or newer stable releases). The check waits up to ten minutes and +fails on stale content or persistent HTTP errors; hook acceptance is insufficient. +The expected releases and hook receipt are retained for diagnosis. +A failed refresh does not rerun registry publication. Retry only +the docs job after inspecting Vercel; an ambiguous HTTP failure may already have +queued a deployment, so the command does not automatically retry POST requests. -### Fumadocs MDX +Read-only inspection on 2026-09-14 confirmed the existing `oliphaunt-docs` +project uses `src/docs`, Next.js, Node 24, automatic build/install/output +settings and production branch `main`. The restored source layout matches its +root setting. No deploy hook exists and GitHub's `Production` environment has +no hook secret or branch restriction. No remote settings were changed. -A `source.config.ts` config file has been included, you can customise different options like frontmatter schema. +External prerequisites still required: -Read the [Introduction](https://fumadocs.dev/docs/mdx) for further details. +- Create/select one deploy hook for the oliphaunt.dev project targeting `main`; + store its URL as `VERCEL_DOCS_DEPLOY_HOOK` in GitHub's protected `Production` + environment, with deployment restricted to `main`. +- Confirm Vercel's project root is `src/docs`, its build command is + `bun run build`, and output is `out`. Root workspace files and the extension + catalog must remain accessible. Installation must use the pinned root Bun + lockfile. Normal Git deployments should follow docs inputs; hook-triggered + builds must not be skipped merely because the source commit is unchanged. +- Exercise a real release refresh and a docs-only main update. The live check + verifies advertised product versions rather than guessing a provider API from + the hook's job ID. Vercel's Git integration owns guide deployment status; + verify its production promotion and ordering in the project dashboard. -## Learn More - -To learn more about Next.js and Fumadocs, take a look at the following -resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js - features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. -- [Fumadocs](https://fumadocs.dev) - learn about Fumadocs +Task 23a remains partial until those prerequisites and deployment verification +are complete. See [Vercel's deploy-hook contract](https://vercel.com/docs/deploy-hooks). diff --git a/src/docs/architecture/cluster-seeds-and-icu.md b/src/docs/architecture/cluster-seeds-and-icu.md new file mode 100644 index 000000000..21d26a1fa --- /dev/null +++ b/src/docs/architecture/cluster-seeds-and-icu.md @@ -0,0 +1,366 @@ +# Cluster seeds and ICU + +Status: current split-resource architecture, updated 2026-09-15. + +This document is the source of truth for preinitialized PostgreSQL clusters, +ICU data, their public selection, and their release qualification. + +## Names + +The public and manifest vocabulary is deliberately small: + +| Name | Meaning | +| --- | --- | +| `standard` | A cluster seed created without optional ICU data. | +| `icu` | A cluster seed created by `initdb` with the exact packaged ICU data available. | +| `icu-data` | The independently packaged ICU runtime data files. | + +The corresponding artifact roles are `cluster-seed-standard`, +`cluster-seed-icu`, and `icu-data`. + +Do not call these profiles `base` or `icu-full`. `base` is ambiguous with a +base runtime/package and says nothing about the catalog. `full` falsely +suggests that smaller public ICU editions exist. Oliphaunt ships one optional +ICU data form, so `icu` is the complete and accurate name. + +“Prepopulated filesystem” is acceptable when comparing with PGlite. +“Preinitialized PGDATA” is acceptable in explanatory prose. Code, manifests, +package metadata, and architecture use **cluster seed**. + +## Simple model + +A cluster seed and ICU data are independent concepts: + +- A cluster seed is immutable initialization state. Oliphaunt copies it only + when creating a new, empty database root. +- ICU data is a runtime capability. PostgreSQL needs those files whenever it + executes ICU locale or collation operations. +- Extensions are a third independent layer. Seeds contain no optional + extensions or application data. + +They overlap in one place: PostgreSQL's ICU-aware `initdb` imports predefined +ICU collations into each bootstrap database. Adding ICU data after copying a +standard seed does not repeat that catalog work. Therefore a newly seeded ICU +database needs both `icu-data` and the matching `icu` seed. + +The four conceptual cases are: + +| Initialization | ICU data | Result | +| --- | --- | --- | +| `standard` seed | absent | Fast ordinary new database. | +| `icu` seed | present | Fast new database with the predefined ICU catalog. | +| `initdb` | absent | Correct ordinary database; slower initialization. | +| `initdb` | present | Correct ICU database; slower initialization. | + +The last case is important for explicit or locally built runtimes. ICU does not +require a seed. A seed is an optimization; ICU data is a capability. +Desktop SDKs can initialize without downloading a seed. New browser and mobile +databases require an explicitly selected seed; existing databases do not need one. + +## User-visible behavior + +Runtime, seed, and ICU data are selected independently. Installing a runtime +does not install either seed profile or ICU data. A seed package contains one +profile for one compatibility domain. + +- Selecting a standard seed avoids `initdb` and has no ICU dependency. +- Selecting an ICU seed also requires the exact canonical ICU data. Selecting + ICU data alone does not implicitly select a seed. +- Every seed and `initdb` fallback creates PostgreSQL's fixed `postgres` + bootstrap role. Public `username` options consistently select an existing + connection role; they never create a superuser as a side effect. +- Opening a new root as another username fails before seed loading or PGDATA + mutation/publication. The + application can first open as `postgres`, create the role, and then reopen as + that role. +- An explicit native runtime may run `initdb`. If ICU data is explicitly + supplied, that `initdb` receives the exact internal ICU-readiness signal and + produces the normal ICU catalog. +- Existing nonempty roots are opened as they are. They are never replaced, + re-seeded, or silently catalog-migrated. + +WASIX TypeScript accepts an explicit archive/manifest pair. For a browser bundler: + +```ts +import Oliphaunt from '@oliphaunt/wasix-ts'; +import archive from '@oliphaunt/seed-wasix-standard/seed.tar.zst?url'; +import manifest from '@oliphaunt/seed-wasix-standard/manifest.json?url'; + +const db = await Oliphaunt.open({ seed: { archive, manifest } }); +``` + +For ICU, select `@oliphaunt/seed-wasix-icu` and pass `icu: { data, manifest }`, +using `@oliphaunt/icu/data` and `@oliphaunt/icu/manifest`. Node, Bun, and Deno +can initialize without a seed; new browser storage requires one. Incomplete +archive/manifest pairs fail closed rather than silently selecting `initdb`. + +Other SDKs retain language-native package selection: + +| SDK | Ordinary selection | ICU selection | +| --- | --- | --- | +| Native Rust | separately selected runtime and optional seed resources | independently selected `oliphaunt-icu` data | +| Native TypeScript | optional `seed` resource directory; desktop `initdb` when absent | `icuData` resource directory | +| Swift | explicit `OliphauntSeedNativeIOSStandard` resource target | `OliphauntSeedNativeIOSICU` and `OliphauntICU` | +| Kotlin | explicit Android standard seed Maven dependency | Android ICU seed and canonical ICU data dependencies | +| React Native | explicit mobile `seedProfile` and resource package | ICU profile and `@oliphaunt/icu` resource carrier | +| Rust WASIX | optional `.seed(ClusterSeed::new(archive, manifest))` | `.icu_data(IcuData::new(data_bytes, manifest_bytes)?)` | +| WASIX TypeScript | explicit `seed: { archive, manifest }` | independent `icu: { data, manifest }` | + +Rust WASIX memory/directory stores support split `initdb` when no seed is +selected. Mobile applications still select a seed; this does not imply a +seed-free mobile initialization path. Existing ICU databases continue to need +their ICU data on reopen. Resource package names and exports are maintained in +[database-resources](../../database-resources/README.md). + +## Why the catalog matters + +PostgreSQL initializes `template1`, imports system collations into it, and then +copies it to create `template0` and `postgres`. `pg_collation` is per-database. +Consequently: + +- loading ICU bytes after a standard seed does not create the predefined + `*-x-icu` rows; +- importing into one application database changes only that database; +- importing into `template1` later affects future databases but does not repair + the already-created `postgres`, `template0`, or other databases; +- explicit `CREATE COLLATION ... provider = icu` can still work when ICU data + is present; and +- enabling ICU does not silently change the cluster's default locale provider. + +Oliphaunt never rewrites PostgreSQL catalog files or injects hidden SQL to +pretend that a standard seed was ICU-initialized. That is the correctness rule +behind “do not silently rewrite the seed's catalog.” For a new root the SDK +uses the right seed. For an existing root, catalog changes remain explicit +application migration work. + +## Runtime and data distribution + +Target-compiled ICU code is linked into each native or WASIX runtime. The +canonical little-endian ICU 76.1 data file, `icudt76l.dat`, is packaged +separately by `database-resources`. Its producer copies the verified upstream +file into `share/icu`; it does not expand thousands of resource files or build +PostgreSQL or ICU libraries. + +Native and WASIX consumers use the same canonical data. `@oliphaunt/icu` and +`oliphaunt-icu` are data-only. Standard seed leaves have no ICU dependency; +ICU seed leaves reference the exact canonical data identity and depend on that +carrier. Neither seed profile is bundled into the runtime carrier. + +The ICU `manifest.properties` records its schema, artifact role, version/form, +and logical tree SHA-256. The digest remains +`SHA-256(path NUL size NUL bytes LF)` in bytewise path order. Seed manifests +bind the required ICU digest separately from their physical runtime identity. +Producer and unmanaged-resource checks verify actual bytes. + +Native npm seed leaves expose `./pgdata/PG_VERSION` and `./manifest.json`. +The manifest preserves empty-directory paths through package installation. +Cargo and WASIX npm leaves retain the compressed seed archive; Cargo leaves +expose `seed_archive()` and `seed_manifest()`. Each carrier contains one +profile and compatibility domain. The resource-owned Swift source archive +contains both iOS profiles, while target selection controls app resources. + +Database-resource release assets account for standard seed, ICU seed, and ICU +data independently of runtime bytes. Registry limits apply to final carriers. + +## Seed compatibility + +A physical cluster seed is more restrictive than ICU data. PostgreSQL records +ABI facts in `global/pg_control` and refuses incompatible clusters. + +Oliphaunt has two compatibility domains: + +| Runtime family | Compatibility identity | Reason | +| --- | --- | --- | +| native | Target-qualified PostgreSQL 18 native identity | Physical files are qualified for the declared native target and ABI; distributed seeds intentionally contain no imported host libc collation rows. | +| wasm32-WASIX | `wasix-pg18-datum32-v1` | Four-byte pointer/`Datum`; `float8` is passed by reference. | + +WASIX extends WASI with operating-system APIs but does not change wasm32 linear +memory to 64-bit. PostgreSQL defines `Datum` from `uintptr_t`, so forcing a +64-bit `Datum` into today's wasm32 build would create an incompatible +PostgreSQL and extension ABI. A local cross-runtime experiment confirmed that +PostgreSQL rejects the other family's seed with the explicit +`USE_FLOAT8_BYVAL` mismatch. + +Every desktop native target and WASIX therefore receive separately qualified +`standard` and `icu` seed bytes. Mobile domains receive a producer-built +candidate only after exact ABI receipts prove equality across the producer and +both target builds; the carrier then binds it to that mobile domain. No seed is +silently relabelled on pointer-width or operating-system assumptions alone. +The canonical ICU data remains shared. + +The v1 native compatibility targets are deliberately finite: + +| Target | Compatibility key | +| --- | --- | +| `macos-arm64` | `native-pg18-macos-arm64-v1` | +| `linux-x64-gnu` | `native-pg18-linux-x64-gnu-v1` | +| `linux-arm64-gnu` | `native-pg18-linux-arm64-gnu-v1` | +| `windows-x64-msvc` | `native-pg18-windows-x64-msvc-v1` | +| `ios-datum64` | `native-pg18-ios-datum64-v1` | +| `android-datum64` | `native-pg18-android-datum64-v1` | + +Before app packaging, Android x86_64, Android arm64, and the Linux producer must +have identical compile/header ABI receipts. The equivalent iOS gate compares +the simulator, device, and macOS producer receipts. This admits an +**ABI-compatible candidate closure**; the embedded provenance records do not +claim that the seed executed on every target. + +The receipt compares PostgreSQL's independent physical-compatibility inputs: +byte order, `Datum` width, maximum alignment, `float8` passing, block and +relation-segment sizes, `NAMEDATALEN`, `INDEX_MAX_KEYS`, and catalog/control +versions. PostgreSQL 18 derives `LOBLKSIZE` from the block size and derives its +TOAST chunk size from the same block/alignment inputs and pinned source; integer +datetimes are unconditional. Repeating those derived values would not add +independent evidence. The finite arm64/x86_64 target set uses the platforms' +standard floating-point ABI, and the installed-app E2E remains the execution +proof. + +The x86_64 emulator and iOS simulator then execute the packaged representative +candidate, verify its selected catalog profile, and reopen the same persistent +root. Those installed-app checks feed the required top-level E2E gate, which is +the final mobile release execution qualification. These are explicit +compatibility domains, not inferences from pointer width. + +## Architecture and DRY boundary + +The implementation has four layers: + +1. **Producer** — an ordinary native bootstrap PostgreSQL process runs + `initdb`, rather than loading embedded consumer substitutions. The pipeline + validates catalog and shutdown invariants, cleans transient PGDATA, and + emits a deterministic seed plus manifest. Compile/header ABI receipts admit + the candidate closure before packaging; representative installed-app E2E + admits it for release. +2. **Release graph** — generated metadata binds runtime, profile, seed, ICU + data, target ABI, source lane, and ecosystem carrier by exact identity. +3. **Resolved runtime closure** — each SDK resolves runtime, catalog profile, + optional ICU data, optional matching seed, and extensions before seed loading or + PGDATA mutation/publication. +4. **Provider-local hydrator** — native filesystems, WASIX memory, IndexedDB, + OPFS, and host directories copy/extract into private staging and publish + through their honest durability boundary. Directory SDKs publish PGDATA and + then the descriptor durably; interruption between them fails closed rather + than pretending that multiple filesystem entries are one atomic operation. + +The cross-language contract lives in +`src/database-resources/contracts/contract.json`. It owns profile names, +artifact roles, ICU form/version, readiness signal, physical formats, +compatibility keys, required PGDATA directories, and the logical digest algorithm. +The product tests validate canonical fixtures through the real seed readers. Release tools +reuse one native manifest/digest validator rather than reimplementing it. + +Filesystem hot paths deliberately remain provider-local. A universal +filesystem abstraction would hide different atomicity, locking, and cloning +semantics and would harm performance. The shared abstraction is the validated +`ResolvedRuntimeClosure`, not a universal file API. + +## Correctness rules + +These rules are locked: + +- A seed contains only ordinary `initdb` bootstrap state. It contains no user + schema/data, secrets, selected optional extensions, or migrations. +- Seeds and explicit `initdb` fallback always bootstrap the fixed `postgres` + role. Connection username is not an initialization option. +- `standard` generation clears ambient ICU variables. `icu` generation requires + the exact verified data tree. +- PostgreSQL trusts only `OLIPHAUNT_INTERNAL_ICU_READY=1` during controlled + `initdb`; ambient `ICU_DATA` alone cannot select a catalog profile. +- The internal readiness variable is removed or set deterministically for every + runtime instance. It is not a public feature switch. +- A selected seed with missing members, malformed metadata, the wrong profile, + or incompatible physical identity fails closed. Omitting a seed selects + `initdb` only on SDK/provider paths that support it. +- Manifest cache keys are single portable path components; `.` and `..` are + invalid even though dot is otherwise allowed in an identifier. +- A seed is copied into a private destination. Hydration never hardlinks mutable + database files to package contents or another database. +- Native hydration normalizes host-dependent shared-memory settings after the + copy. WASIX hydration retains its provider-specific overlay/extraction path. +- Existing roots are never implicitly reinitialized or reseeded. +- ICU upgrades never trigger hidden `REINDEX` or + `ALTER COLLATION ... REFRESH VERSION`; applications follow PostgreSQL's + per-database upgrade procedure. +- The five-field `.oliphaunt.json` storage descriptor and physical backup + formats do not gain a seed-profile field. The database catalog is the + resulting state; seed provenance is not durable root identity. +- Embedded seed clones retain the producer database-system identifier in v1 and + do not expose physical replication or WAL-archive identity semantics. New + native server roots use normal server `initdb` so every server receives a + unique system identifier. Oliphaunt does not byte-patch `pg_control`. + +## PGlite comparison + +PGlite's `@electric-sql/pglite-prepopulatedfs` demonstrates the startup value +of shipping initialized PGDATA. Its public helper returns an archive through +`loadDataDir`, while ICU is supplied separately through `icuDataDir`. + +Oliphaunt also keeps seed state and ICU data separate. Applications may select +a packaged archive and manifest explicitly, while SDKs validate physical +compatibility, profile, archive integrity, and the required ICU identity. +Adding ICU bytes to a standard seed does not retroactively create its predefined +ICU catalog; catalog changes to existing databases remain explicit. + +## Distribution boundaries + +- `database-resources` owns seed profiles and canonical ICU data; runtime + packages contain executable runtime assets. +- Each seed carrier contains one qualified profile and physical domain. There + is no default carrier that installs every seed. +- Producers and archive packaging validate the shared PGDATA directory + contract, including empty directories. Carrier transport preserves them. +- Seeds are copied into private mutable storage; package files are never + hardlinked into PGDATA. Existing databases do not need seed downloads. +- Selected resources are checked for compatibility and integrity before use. + Installed-app qualification remains required for Android and iOS. + +## Per-release qualification checklist + +These are recurring release gates, not unfinished architecture: + +- [ ] Generate all seeds from the exact release runtime/source commit in trusted + CI; never reuse an unbound developer cache. +- [ ] Verify `PG_VERSION`, `pg_control`, clean shutdown, bootstrap databases, + empty extension selection, and exact catalog expectations for both profiles. +- [ ] Compare all target and producer compile/header ABI receipts before mobile + app packaging, then require representative emulator/simulator installed-app + E2E before final release execution qualification. +- [ ] Compare the native and WASIX ICU logical tree digests and run + representative locale/collation probes against the exact released data. +- [ ] Pack and reinstall every Cargo, npm, SwiftPM, Maven, and React Native + carrier; verify no source-tree or sibling-package fallback is possible. +- [ ] Exercise memory, host-directory, IndexedDB, OPFS, direct, broker, server, + and mobile paths that are available on the release matrix. +- [ ] Prove first-open success, reopen stability, crash-safe unpublished staging, + concurrent-open exclusion, and nonempty-root nonmutation. +- [ ] Benchmark paired cold/warm `initdb` versus seed hydration and first query; + publish medians, tails, bytes, CPU, I/O, and decompression costs. +- [ ] Audit the standard and ICU size rows and enforce registry/package limits. +- [ ] Run repository release, committed-asset, extension-model, SDK-contract, and + affected-target qualification at the exact candidate SHA. + +## Performance policy + +Performance is a feature, but it does not weaken correctness: + +- standard users do not download optional ICU data; +- selecting a seed avoids `initdb`; supported seed-free paths avoid its download; +- seed manifests and descriptor hashes are validated before seed loading or + PGDATA mutation/publication; +- persistent WASIX stores are inspected before seed archives are fetched or + expanded; +- package-managed immutable ICU identities are not recomputed by reading the + complete data tree on every open; +- PostgreSQL frontend tools do not mount backend-only ICU data; +- hot provider operations use their existing copy-on-write, reflink, archive, + journal, or direct-OPFS mechanisms; +- immutable source package files are never made mutable through hardlinks; and +- claims use reproducible cold/warm benchmarks on final carrier bytes, not a + one-off producer-tree timing. + +If a future consumer cannot use the canonical ICU data form because of ICU +major, endianness, charset family, or a different data filter, it receives a +new compatibility identity only after an executable consumer gate proves the +difference. If a future wasm64-WASIX runtime changes PostgreSQL's `Datum` ABI, +it likewise receives a new seed compatibility key rather than reusing today's +wasm32 seed. diff --git a/docs/architecture/database-storage.md b/src/docs/architecture/database-storage.md similarity index 100% rename from docs/architecture/database-storage.md rename to src/docs/architecture/database-storage.md diff --git a/docs/architecture/final-product-source-architecture.md b/src/docs/architecture/final-product-source-architecture.md similarity index 81% rename from docs/architecture/final-product-source-architecture.md rename to src/docs/architecture/final-product-source-architecture.md index a9b364d57..1f76814a8 100644 --- a/docs/architecture/final-product-source-architecture.md +++ b/src/docs/architecture/final-product-source-architecture.md @@ -1,9 +1,11 @@ # Oliphaunt Source Architecture Status: canonical product, task, qualification, and release-boundary model. -Last verified: 2026-09-05. Owner: repository maintainers. +Last reviewed: 2026-09-11. Owner: repository maintainers. This document describes the active repository model. It is not a migration log. +The remaining target layout and implementation progress are tracked in +[the simplification plan](repository-simplification-plan.md). ## Authority Boundaries @@ -20,9 +22,12 @@ Oliphaunt uses one source graph and one release identity system: does not model: owner, kind, publish targets, registry coordinates, release artifacts, and exact published-product compatibility pins. - Product-local `targets/*.toml` files own platform artifact metadata. -- Bun entrypoints under `tools/release/*.mjs` own release checks, dry-runs, - publication routing, checksums, attestations, registry checks, and artifact - verification. +- Product-owned tools assemble and validate their packages. Shared archive and + metadata contracts live under `src/shared/`. +- Shell entrypoints under `tools/release/` own release command execution; + TypeScript handles metadata, native HTTP, frozen publication identities and + receipts. Committed scripting source uses TypeScript or Shell; published + JavaScript assets retain their customer-facing entrypoints. There is no separate release graph, release-input graph, CI jobs graph, or consumer lockfile. If a relationship affects source, task execution, or release @@ -33,26 +38,29 @@ coupling, it must be visible in Moon or release-please/product-local metadata. Source products and shared domains live under `src/`: ```text -src/postgres/versions/18/ PostgreSQL 18 source pin and validation +src/third-party/postgres/ PostgreSQL 18 source pin and validation src/sources/ shared source and toolchain pins src/extensions/ exact SQL extension catalog, recipes, evidence -src/runtimes/liboliphaunt/native native C ABI runtime -src/runtimes/liboliphaunt/wasix WASIX runtime and AOT assets -src/runtimes/broker Rust broker helper runtime -src/runtimes/node-direct Node direct native runtime -src/sdks/rust Rust SDK +src/runtimes/liboliphaunt-native native C ABI runtime +src/runtimes/liboliphaunt-wasix WASIX runtime and AOT assets +src/sdks/ts-wasix/node-addon WASIX Node-API runtime adapter +broker Rust broker helper runtime +src/sdks/ts/node-addon Node direct native runtime +src/sdks/rust/sdk Rust SDK src/sdks/swift Swift SDK src/sdks/kotlin Kotlin/Android SDK src/sdks/react-native React Native SDK -src/sdks/js TypeScript SDK -src/bindings/wasix-rust Rust binding for the WASIX runtime -src/bindings/wasix-ts TypeScript browser and Node/Bun/Deno/Electron WASIX binding with optional tools -src/shared/js-core shared JavaScript query and protocol code -src/shared/rust-query-core shared Rust query code -src/shared/extension-runtime-contract extension/runtime ABI contract -src/shared/cluster-seed-contract shared cluster-seed format contract -src/shared/fixtures shared semantic test fixtures -src/docs public docs site +src/sdks/ts/sdk TypeScript SDK +src/sdks/rust-wasix Rust binding for the WASIX runtime +src/sdks/ts-wasix/sdk TypeScript browser and Node/Bun/Deno/Electron WASIX binding with optional tools +src/sdks/ts-query published TypeScript query and protocol package +src/sdks/rust-query published Rust query crate +src/extensions/contracts extension/runtime ABI contract +src/database-resources/contracts shared cluster-seed format contract +tools/packaging shared archive and package contracts +tools/release shared product and compatibility readers +test-fixtures shared semantic test fixtures +docs public docs site ``` Generated local state lives outside source roots or in ignored product build @@ -102,13 +110,20 @@ Use Moon queries for graph inspection: ```sh moon query projects moon query tasks -moon query affected --upstream none --downstream direct +moon query affected --upstream none --downstream deep moon project-graph -moon action-graph oliphaunt-rust:unit +moon action-graph oliphaunt-rust:test ``` Do not add a second graph format to answer questions Moon already answers. +Cargo schedules Rust compilation. The internal `cargo-sources` task carries +source hashes through Cargo-derived Moon dependencies without executing a +command. Compiler and test tasks consume that hash, so a transitive crate edit +invalidates their cached results. Swift and Kotlin consume the mobile bindings' +source hash as well as their generated outputs. Formatting stays local to its +owner; source checks do not acquire a runtime build dependency through this node. + Native SDK and WASIX SDK database lifetimes use the shared vocabulary in [`database-storage.md`](database-storage.md). That contract aligns public names and behavior without merging the two product families or their runtime @@ -135,9 +150,8 @@ The flow is: `Tests / ` matrices plus one compact `Policy` batch from Moon-selected targets. Each matrix entry groups at most four tasks with the same runner capabilities, and its label lists those tasks. `Checks` is for normal - static/lint/typecheck-style work. `Policy` is for repository assertions that - parse code, workflows, release metadata, or generated graphs and enforce - invariants. Check and test matrix jobs delegate one compatible target group + static/lint/typecheck-style work. `Policy` checks shared workflow and release + contracts. Check and test matrix jobs delegate one compatible target group to `moon run --upstream deep`, so task inheritance and target dependencies stay in Moon without pulling unrelated affected tests into the checks phase. The policy batch runs its exact selected targets with `--upstream none`, because @@ -169,22 +183,22 @@ The flow is: to `.github/scripts/run-planned-moon-job.sh`; it runs remaining local prerequisites normally, then runs the consumer roots with upstream traversal disabled so transferred producers are not rebuilt. - `release-tools:-sdk-package` tasks consume the product `package` - outputs instead of hiding release assembly in source projects. + Product-owned `release-package` tasks consume their `package` outputs. + Root release tooling coordinates publication of those finished artifacts. 10. Expensive runtime, mobile, benchmark, publish, registry, and provenance jobs are selected by affectedness, but they execute live when current runner state matters. Mobile build jobs do not own ABI lists. They request target surfaces such as `react-native-android` and `react-native-ios`; the selected native runtime -target IDs come from `src/runtimes/liboliphaunt/native/targets/*.toml`. Mobile +target IDs come from `src/runtimes/liboliphaunt-native/targets/*.toml`. Mobile E2E is a separate installed-app phase that consumes the app artifacts from the same CI run; it must not rebuild runtimes, SDKs, or extension packages. Moon task options must be semantic: - cache deterministic checks, tests, package-shape checks, generated freshness, - docs builds, and measured unit coverage with declared inputs and outputs. + and docs builds with declared inputs and outputs. - use `runInCI: skip` for expensive dependency tasks that should remain valid in CI action graphs but should not run as broad affected work. - use `runInCI: false` only for local/manual tasks that CI must never invoke. @@ -199,7 +213,7 @@ and product-local compatibility pins: 1. Release Please identifies product components, versions, and changelogs and prepares the generated release PR. 2. Product-local `release.toml` adds publish and artifact metadata. -3. `tools/dev/bun.sh tools/release/release_plan.mjs` maps changed paths to +3. `bash tools/release/release-plan.sh` maps changed paths to owning Moon projects. 4. A changed non-publishable source project follows `production` and `peer` edges only until the first publishable product boundary. @@ -268,7 +282,7 @@ versioned product. - Complex external extensions keep dependency source pins under their own extension folder, for example PostGIS dependency pins under `src/extensions/external/postgis/dependencies/`. -- `src/shared/extension-runtime-contract/` defines the runtime contract shared +- `src/extensions/contracts/` defines the runtime contract shared by native and WASIX extension artifacts. - `src/extensions/artifacts/native/` and `src/extensions/artifacts/wasix/` validate publishable exact-extension artifact shape. @@ -293,26 +307,22 @@ checks must prove unselected extension files do not enter app artifacts. ## Tool Entrypoints -Use Moon directly for repository tasks: +Use the affected product's local commands. Moon resolves declared prerequisites +when running a product task, for example: ```sh -moon run :check :compile :format-check :js-format-check :rust-format-check :lint :tools-compile -moon run :test :unit :tools-unit -moon run :coverage -moon run :package -moon run :smoke --cache off -moon query affected --upstream none --downstream direct +moon run oliphaunt-rust:build oliphaunt-rust:test oliphaunt-rust:package +moon run oliphaunt-swift:test-packaging +moon query affected --upstream none --downstream deep ``` -`moon run :package` is the workspace-wide carrier assembly/inspection lane and -may require platform artifacts produced earlier. For a fast check, run the -affected product's exact `package` task. Package tasks must not build platform -runtimes or mobile apps; publishable artifacts are produced by explicit -release-tool, runtime, extension, and mobile builder tasks selected by -the `CI` workflow. +Package tasks declare the compilation and artifact inputs they consume. +Runtime, extension and mobile producers have separate tasks; downloaded +artifacts satisfy those dependencies in CI. Product packaging does not rerun +source qualification. Coverage and benchmarks are optional local tasks. -Use pnpm only for JavaScript dependency installation and package-manager -commands. Use Cargo, SwiftPM/Xcode, Gradle, npm, and Expo through +Use pinned Bun for workspace installation, TypeScript scripting, tests and npm +package assembly. Use Cargo, SwiftPM/Xcode, Gradle, npm publication, and Expo through product-local Moon tasks or product-owned scripts. Do not add root alias layers over Moon. @@ -343,5 +353,5 @@ These surfaces are retired and must not reappear: - custom affected task runners that bypass Moon. - broad registry reinstall gates as routine CI policy. - extension packs, aliases, or grouped selectors. -- root product aliases such as `crates/`, `sdks/`, root `assets/`, and +- root product aliases such as `crates/`, `src/sdks/`, root `assets/`, and root-level runtime build trees. diff --git a/docs/architecture/ios.md b/src/docs/architecture/ios.md similarity index 100% rename from docs/architecture/ios.md rename to src/docs/architecture/ios.md diff --git a/docs/architecture/native-liboliphaunt.md b/src/docs/architecture/native-liboliphaunt.md similarity index 94% rename from docs/architecture/native-liboliphaunt.md rename to src/docs/architecture/native-liboliphaunt.md index 145672c5a..3cbd60a94 100644 --- a/docs/architecture/native-liboliphaunt.md +++ b/src/docs/architecture/native-liboliphaunt.md @@ -13,8 +13,8 @@ lifecycle, archive parser, or root validation. ## Public C boundary -ABI version 10 exports one fixed surface from -`src/runtimes/liboliphaunt/native/include/oliphaunt.h`: +The unreleased checkout ABI version 11 exports one fixed surface from +`src/runtimes/liboliphaunt-native/include/oliphaunt.h`: - `oliphaunt_init`, `oliphaunt_detach`, `oliphaunt_close`, generation-guarded close, version access, and atomic caller-owned error copies; @@ -33,6 +33,12 @@ acquires that lease itself. Every other bit is rejected. Fixed runtime behavior is not represented as a profile enum, archive-format enum, replacement policy, or initialization mode. +The v11 config appends nullable `const char *icu_data_dir`. Host bindings pass +canonical ICU data explicitly rather than relying on JavaScript environment +mutation reaching libc. The ABI bump prevents an older, shorter config from +being read with the new layout. Published v10 release records remain historical +and do not imply that v11 is already available. + ## Direct lifecycle One PostgreSQL backend may be resident in a process. The first successful init @@ -167,6 +173,6 @@ SDK package and smoke lanes then prove their adapters against the same artifact. ```sh moon run liboliphaunt-native:host-smoke -moon run oliphaunt-rust:regression -moon run extension-artifacts-native:build-target oliphaunt-rust:extension-regression +moon run oliphaunt-rust:test-integration +moon run extension-artifacts-native:build-target oliphaunt-rust:test-extensions ``` diff --git a/docs/architecture/orm-integration-report.md b/src/docs/architecture/orm-integration-report.md similarity index 98% rename from docs/architecture/orm-integration-report.md rename to src/docs/architecture/orm-integration-report.md index 966ce81d9..fc9b5519d 100644 --- a/docs/architecture/orm-integration-report.md +++ b/src/docs/architecture/orm-integration-report.md @@ -75,7 +75,7 @@ correctness limitations. | Rust server qualification | Stock SQLx, Diesel, diesel-async, SeaORM, and tokio-postgres APIs | Exercise the existing dedicated native and WASIX server builders through connection strings | Add reproducible per-library suites; use pool size one on WASIX | | `OliphauntSeaQueryExecutor` | Small, truly socketless Rust query-builder integration | Statement/value codecs over the existing direct API | Build independently of server qualification | | Constrained `pg-compat` facade | Knex and TypeORM first; possibly Sequelize, Slonik, and Zapatos later | Single-session compatibility over the stable core, with any required lease kept adapter-private | Defer until the first three JavaScript integrations pass | -| Duplex operation ABI | Interactive COPY, pull row streams, and advanced socketless client emulation | New C/Rust/broker/TypeScript/WASIX exchange path | Start only for a proven feature requirement | +| Duplex operation ABI | Interactive COPY, pull row streams, and advanced socketless client emulation | New C/Rust/src/broker/TypeScript/WASIX exchange path | Start only for a proven feature requirement | Do not build a custom SQLx database implementation or a direct Prisma adapter. Do not put per-ORM SQL codecs, transaction schedulers, or browser ownership @@ -1015,7 +1015,7 @@ sizes above one fail, and unsupported `pg` APIs fail deterministically. such direct-mode client emulation as proven demand justifies. Acceptance: bounded backpressure, cancel recovery, no unread frames across -readiness, and broker/Worker crash cleanup are proven before enabling an ORM +readiness, and src/broker/Worker crash cleanup are proven before enabling an ORM feature. ## Recommended end-state experience @@ -1074,18 +1074,18 @@ Users should need to learn only three Oliphaunt-specific facts: ## Repository evidence -- [Native TypeScript database state machine](../../src/sdks/js/src/client.ts) -- [Native TypeScript query codec](../../src/sdks/js/src/query.ts) -- [Native broker runtime](../../src/sdks/js/src/runtime/broker.ts) -- [Native Rust executor](../../src/sdks/rust/src/executor.rs) -- [Native Rust database API](../../src/sdks/rust/src/database.rs) -- [Native C protocol ABI](../../src/runtimes/liboliphaunt/native/include/oliphaunt.h) -- [WASIX TypeScript database](../../src/bindings/wasix-ts/src/database.ts) -- [WASIX TypeScript query codec](../../src/bindings/wasix-ts/src/query.ts) -- [WASIX TypeScript architecture](../../src/bindings/wasix-ts/ARCHITECTURE.md) -- [WASIX Rust one-client proxy](../../src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/proxy.rs) -- [WASIX Rust wire framing](../../src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/wire.rs) -- [Public capability matrix](../../src/docs/content/reference/capabilities.mdx) +- [Native TypeScript database state machine](../../sdks/ts/sdk/src/client.ts) +- [Native TypeScript query codec](../../sdks/ts/sdk/src/query.ts) +- [Native broker runtime](../../sdks/ts/sdk/src/runtime/broker.ts) +- [Native Rust executor](../../sdks/rust/sdk/src/executor.rs) +- [Native Rust database API](../../sdks/rust/sdk/src/database.rs) +- [Native C protocol ABI](../../runtimes/liboliphaunt-native/include/oliphaunt.h) +- [WASIX TypeScript database](../../sdks/ts-wasix/sdk/src/database.ts) +- [WASIX TypeScript query codec](../../sdks/ts-wasix/sdk/src/query.ts) +- [WASIX TypeScript architecture](../../sdks/ts-wasix/sdk/ARCHITECTURE.md) +- [WASIX Rust one-client proxy](../../sdks/rust-wasix/src/oliphaunt/proxy.rs) +- [WASIX Rust wire framing](../../sdks/rust-wasix/src/oliphaunt/wire.rs) +- [Public capability matrix](../content/reference/capabilities.mdx) ## Primary upstream sources diff --git a/docs/architecture/pglite-public-api-comparison.md b/src/docs/architecture/pglite-public-api-comparison.md similarity index 100% rename from docs/architecture/pglite-public-api-comparison.md rename to src/docs/architecture/pglite-public-api-comparison.md diff --git a/src/docs/architecture/release-owner-migration-lineage.md b/src/docs/architecture/release-owner-migration-lineage.md new file mode 100644 index 000000000..a6d604d15 --- /dev/null +++ b/src/docs/architecture/release-owner-migration-lineage.md @@ -0,0 +1,459 @@ +# Release owner migration lineage + +This is one-time cutover review material, not another release registry. Snapshot: +HEAD `e425160984872b725debd82961aaef0d9054813b`; origin/main +`f4b7a5c71c8e244f77cc08d474e06e47fe336287`. Uncommitted implementation changes +are absent; refresh the capture at the final pre-move commit. + +Review on 2026-09-14: the working tree retains the published baselines and +configures the three transferred resource/tools owners with a 0.2.1 initial +floor. The pinned Release Please candidate checks and disposable directory-swap +and release-commit histories pass. The notes below remain the original capture, +not a generated candidate for the uncommitted consolidation at HEAD `80cda37c`. +Refresh and carry them once in the first clean post-move candidate before +claiming the final versions or changelogs reviewed. + +All 20 local component tags below resolve to +`bfa867aa52b1e1bcf45f8107c072940e2a120dd6`. No owner has pending +path-local commits between its tag and this origin/main. The pending column +records commits between that tag and HEAD. Local tags establish lineage; this +is not a fresh audit of registry availability or remote pending release PRs. + +## Existing owners + +Move each owner's CHANGELOG.md with its source; rekey both release configuration +and manifest baseline without changing component, package identity or tag. +The floor comes from the pinned Release Please version strategy applied to +existing branch history. A dash means no path-local release selected. + +| Current owner | Final owner | Stable component / tag prefix | Baseline | Pending version floor | Pending commits | +| --- | --- | --- | --- | --- | --- | +| src/runtimes/liboliphaunt/native | src/runtimes/liboliphaunt-native | liboliphaunt-native | 0.2.0 | 0.2.1 | 183ff83, 96de165 | +| src/sdks/rust | src/sdks/rust/sdk | oliphaunt-rust | 0.2.0 | 0.2.1 | 05906fc, 183ff83, 96de165 | +| src/runtimes/broker | src/broker | oliphaunt-broker | 0.2.0 | 0.2.1 | 9609530, 183ff83, 96de165 | +| src/runtimes/node-direct | src/sdks/ts/node-addon | oliphaunt-node-direct | 0.2.0 | 0.2.1 | 183ff83, 96de165 | +| src/runtimes/wasix-napi | src/sdks/ts-wasix/node-addon | oliphaunt-wasix-napi | 0.1.0 | 0.1.1 | 5ee8fec, 2c77120, 183ff83, 96de165 | +| src/sdks/swift | src/sdks/swift | oliphaunt-swift | 0.7.0 | 0.7.1 | 183ff83, 96de165 | +| src/sdks/kotlin | src/sdks/kotlin | oliphaunt-kotlin | 0.2.0 | 0.2.1 | 9609530, 183ff83, 96de165 | +| src/sdks/react-native | src/sdks/react-native | oliphaunt-react-native | 0.2.0 | 0.2.1 | 2c77120, 183ff83, 96de165 | +| src/sdks/js | src/sdks/ts/sdk | oliphaunt-js | 0.2.0 | 0.2.1 | c14972f, 96de165 | +| src/extensions/external/pg_hashids | src/extensions/external/pg_hashids | oliphaunt-extension-pg-hashids | 0.2.0 | — | — | +| src/extensions/external/pg_ivm | src/extensions/external/pg_ivm | oliphaunt-extension-pg-ivm | 0.2.0 | — | — | +| src/extensions/external/pg_textsearch | src/extensions/external/pg_textsearch | oliphaunt-extension-pg-textsearch | 0.2.0 | 0.2.1 | 96de165 | +| src/extensions/external/pg_uuidv7 | src/extensions/external/pg_uuidv7 | oliphaunt-extension-pg-uuidv7 | 0.2.0 | — | — | +| src/extensions/external/pgtap | src/extensions/external/pgtap | oliphaunt-extension-pgtap | 0.2.0 | — | — | +| src/extensions/external/postgis | src/extensions/external/postgis | oliphaunt-extension-postgis | 0.2.0 | 0.2.1 | 9609530, 183ff83, 96de165 | +| src/extensions/external/vector | src/extensions/external/vector | oliphaunt-extension-vector | 0.2.0 | — | — | +| src/runtimes/liboliphaunt/wasix | src/runtimes/liboliphaunt-wasix | liboliphaunt-wasix | 0.2.0 | 0.2.1 | 183ff83, 96de165 | +| src/runtimes/liboliphaunt/wasix-postmaster | src/runtimes/liboliphaunt-wasix-postmaster | liboliphaunt-wasix-postmaster | 0.1.0 | 0.1.1 | e425160, 5ee8fec, 2c77120, 41b04b6, 05906fc, 183ff83, 96de165 | +| src/bindings/wasix-rust/crates/oliphaunt-wasix | src/sdks/rust-wasix | oliphaunt-wasix-rust | 0.2.0 | 0.2.1 | 41b04b6, 96de165 | +| src/bindings/wasix-ts | src/sdks/ts-wasix/sdk | oliphaunt-wasix-ts | 0.1.0 | 0.1.1 | 183ff83, 96de165 | + +## One-time pending release carry + +1. At the final old-path commit, capture the actual Release Please candidate + versions and notes. Preserve published manifest baselines. Capture pending + release PR intent too; do not mark merged but unpublished releases tagged. +2. Move source/changelogs and rekey manifest/config together. Keep component IDs + and registry names. New query packages are new owners, not aliases. +3. In the first post-move release PR, apply captured pending notes once to the + corresponding component's candidate entry. Deduplicate by original commit + SHA. Do not prepend a second heading for the same version. Preserve newer + post-move notes and released historical notes verbatim. +4. If path loss chooses a lower version, use Release Please's native temporary + release-as input for that component with its captured candidate version. + A higher post-move candidate wins. Remove temporary inputs after consumption. + Verify repeated preparation retains the same notes and versions before + merging. This is reviewed one-time preparation, not permanent path aliases. +5. Refresh this capture before cutover; retain it until the first publication + receipt completes. An unattended first post-move prepare is not ready until + the carry is applied: plain rekeying loses pending changes. + +## Verification and limits + +Used the actual Release Please 17.3.0 bundle in pinned action +`5c625bfb5d1ff62eadeeb3772007f7f66fdcf071`. A disposable simulation of all +20 components verified stable tag/baseline lookup and exact equality of candidate +versions and notes before and after a one-time history-path rekey. Without the +carry, the real CommitSplit omits all old-path pending commits. + +The initial simulation uses the common simple strategy to isolate path splitting, +conventional versions and notes. Additional actual ecosystem updater and workspace +simulations are described below. These checks do not publish anything or replace +the first candidate's normal validation. The disposable harness, inputs and logs are at +`/tmp/oliphaunt-release-lineage` on the implementation machine. The captured +pending notes follow, so they survive removal of that temporary directory. + +## Transferred resources and PostgreSQL tools + +Read-only registry capture: **2026-09-11T12:36Z**, against the active checkout. +The publication catalog identifies 22 relevant Cargo/npm/Maven identities; +crates.io additionally exposes four generated native tool payload-part crates. +All 26 direct metadata requests returned HTTP 200. All have highest published +stable version **0.2.0**, except `@oliphaunt/wasix-tools`, which has **0.1.0**. +No source manifest sentinel was used as publication evidence. + +**Each of the three new owners has a minimum next-version floor of 0.2.1.** +This is a collision/history floor, not a decision that a breaking resource/API +change merits only a patch. Release Please may select a higher version. New +seed identities join the resource owner's version; they do not restart at +0.1.0. Recheck these mutable registries before the actual cutover/publication. + +| Existing registry identity | Previous release owner | Final owner | Public maximum | Minimum for next publication | +| --- | --- | --- | --- | --- | +| Cargo `oliphaunt-icu` | `liboliphaunt-wasix` | `database-resources` | 0.2.0 | 0.2.1 | +| npm `@oliphaunt/icu` | `liboliphaunt-native` | `database-resources`, canonical shared ICU data | 0.2.0 | 0.2.1 | +| npm `@oliphaunt/wasix-icu` | `liboliphaunt-wasix` | `database-resources` history; retire new publication of this combined data/seed carrier | 0.2.0 | No new duplicate payload; any exceptional reuse must exceed 0.2.0 | +| Maven `dev.oliphaunt.runtime:oliphaunt-icu` | `liboliphaunt-native` | `database-resources` | 0.2.0 | 0.2.1 | +| Maven `dev.oliphaunt.runtime:liboliphaunt-runtime-resources-android-datum64` | `liboliphaunt-native` | `database-resources` | 0.2.0 | 0.2.1 | +| Cargo `oliphaunt-tools` | `liboliphaunt-native` | `src/postgres-tools/native` | 0.2.0 | 0.2.1 | +| Cargo `oliphaunt-tools-linux-arm64-gnu`, `oliphaunt-tools-linux-x64-gnu`, `oliphaunt-tools-macos-arm64`, `oliphaunt-tools-windows-x64-msvc` | `liboliphaunt-native` | `src/postgres-tools/native` | 0.2.0 each | 0.2.1 each | +| Cargo `oliphaunt-tools-linux-arm64-gnu-part-001`, `oliphaunt-tools-linux-x64-gnu-part-001`, `oliphaunt-tools-macos-arm64-part-001`, `oliphaunt-tools-windows-x64-msvc-part-001` | `liboliphaunt-native` generated payload parts | `src/postgres-tools/native` | 0.2.0 each | 0.2.1 each | +| npm `@oliphaunt/tools` | `liboliphaunt-native` | `src/postgres-tools/native` | 0.2.0 | 0.2.1 | +| npm `@oliphaunt/tools-darwin-arm64`, `@oliphaunt/tools-linux-arm64-gnu`, `@oliphaunt/tools-linux-x64-gnu`, `@oliphaunt/tools-win32-x64-msvc` | `liboliphaunt-native` | `src/postgres-tools/native` | 0.2.0 each | 0.2.1 each | +| Cargo `oliphaunt-wasix-tools` | `liboliphaunt-wasix` | `src/postgres-tools/wasix` | 0.2.0 | 0.2.1 | +| Cargo `oliphaunt-wasix-tools-aot-aarch64-apple-darwin`, `oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu`, `oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc`, `oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu` | `liboliphaunt-wasix` | `src/postgres-tools/wasix` | 0.2.0 each | 0.2.1 each | +| npm `@oliphaunt/liboliphaunt-wasix-tools` | `liboliphaunt-wasix` | `src/postgres-tools/wasix` | 0.2.0 | 0.2.1 | +| npm `@oliphaunt/wasix-tools` | `oliphaunt-wasix-ts` | `src/postgres-tools/wasix` | 0.1.0 | 0.2.1 with its new owner; its individual collision floor is 0.1.1 | +| npm `@oliphaunt/liboliphaunt-wasix-tools-linux-arm64-gnu`, `@oliphaunt/liboliphaunt-wasix-tools-linux-x64-gnu`, `@oliphaunt/liboliphaunt-wasix-tools-darwin-arm64`, `@oliphaunt/liboliphaunt-wasix-tools-win32-x64-msvc` | New optional AOT carriers | `src/postgres-tools/wasix` | No previous publication identified | 0.2.1 with the tools owner | + +The four payload-part crates each have published 0.1.0, 0.1.1 and 0.2.0 +versions. A move must not lose them merely because the base catalog generates +part identities only while packaging. Future required parts inherit the tool +owner; do not create separate release owners for them. + +### GitHub archives, Swift products, and seeds + +The completed [native 0.2.0 release](https://github.com/f0rr0/oliphaunt/releases/tag/liboliphaunt-native-v0.2.0) +contains `liboliphaunt-0.2.0-icu-data.tar.gz` and both +`liboliphaunt-0.2.0-runtime-resources-{android,ios}-datum64.tar.gz` archives. +Their future production belongs to `database-resources`, with the same 0.2.1 +minimum floor. The older unsuffixed `runtime-resources.tar.gz` archives at +0.1.0/0.1.1 remain immutable historical assets, not another new carrier. +The native release's four `oliphaunt-tools-0.2.0-{linux-arm64-gnu,linux-x64-gnu,macos-arm64,windows-x64-msvc}` +archives move to `src/postgres-tools/native` (tar.gz on Unix, zip on Windows). + +The completed [WASIX 0.2.0 release](https://github.com/f0rr0/oliphaunt/releases/tag/liboliphaunt-wasix-v0.2.0) +contains `liboliphaunt-wasix-0.2.0-icu-data.tar.zst`; future ICU data production +belongs to `database-resources`. It has no separately named PostgreSQL-tools +archive in its public asset list. Tools are nevertheless published in the Cargo +and npm identities above; do not invent an existing GitHub tools-archive history. + +The public [Swift 0.7.0 Package.swift](https://github.com/f0rr0/oliphaunt/blob/0.7.0/Package.swift) +exports `OliphauntICU` inside the existing `Oliphaunt` SwiftPM package, backed by +`generated/swiftpm/OliphauntICU` resources. **This is not an independently +versioned Swift package.** Its source wrapper/package history stays with the +Swift SDK (0.7.0 baseline); its data producer transfers to database-resources. +Do not either reset the Swift package to 0.2.1 or incorrectly raise the data +owner's floor to 0.7.1. The new selectable Swift resource delivery still needs +task 16 implementation; publishing a new data owner alone cannot avoid fetching +resources already embedded in old Swift source tags. No separate Swift or Maven +PostgreSQL-tools identity appears in the catalog/public Swift manifest. + +There are currently **no independently declared seed registry identities**. +Native desktop runtime packages contain standard and ICU seed directories; +native mobile resource archives carry seed/resources. The WASIX runtime npm +carrier contains the standard seed; `@oliphaunt/wasix-icu` combines ICU data with +the ICU seed. WASIX Cargo/runtime packaging also carries seeds. Transfer those +payload producers, not the entire native/WASIX runtime package identities, to +database-resources. Runtime identities stay with their runtimes and old versions +keep their existing bundled payloads. Four logical native/WASIX × standard/ICU +seed families, plus required physical target variants, become independently +selectable carriers at the new resource owner's version. + +Carry both existing ICU histories into the new owner's migration notes. +New WASIX consumers use canonical `@oliphaunt/icu` plus a separate ICU seed; +do not publish another data copy under `@oliphaunt/wasix-icu` or add a permanent +compatibility facade merely to retain that spelling. Existing published versions +and their exact dependency URLs remain available. Separate resource versioning +also requires explicit runtime/physical-format compatibility; version 0.2.1 +itself proves no seed compatibility. + +### Evidence and remaining boundaries + +Registry evidence came from every listed crate's +`https://crates.io/api/v1/crates/` metadata, every listed npm package's +`https://registry.npmjs.org/` metadata, and Maven Central's +[ICU metadata](https://repo.maven.apache.org/maven2/dev/oliphaunt/runtime/oliphaunt-icu/maven-metadata.xml) +and [Android resources metadata](https://repo.maven.apache.org/maven2/dev/oliphaunt/runtime/liboliphaunt-runtime-resources-android-datum64/maven-metadata.xml). +All version arrays were inspected; npm dist-tags alone were not the floor. +Crates.io searches for `oliphaunt-tools` and `oliphaunt-wasix-tools` returned +11 and 6 results respectively (below their 100-result page limit), exposing the +four additional parts; each part then received a direct metadata read. + +The disposable read-only capture is `/tmp/oliphaunt-carrier-lineage/`: +`catalog.json`, `registries.json`, `cargo-search.json`, `cargo-parts.json`, +`github.json`, and `Package-0.7.0.swift`. No selected registry was inaccessible. +This establishes names, ownership lineage and version floors, not downloaded +payload integrity, publisher permissions, or a complete first post-move release. +New seed carrier names/distribution metadata, the shared ICU package conversion, +Swift resource delivery, pending-change carry and the final exact-lock registry +recheck remain cutover work. Do not mark all of task 02a complete from this table +alone or add these observations as a second machine-maintained release catalog. + +### Actual ecosystem updater results + +The pinned bundle also ran the current per-package release configuration and +real owner files through the actual Rust, Node and simple strategies. Applying +their emitted updaters before and after the proposed path rekey produced exactly +equal versioned file contents and changelog notes: + +| Owner | Candidate | Verified updater outputs | +| --- | --- | --- | +| Rust SDK | 0.2.1 | Cargo.toml, build-helper Cargo.toml extra version, changelog | +| TypeScript SDK | 0.2.1 | package.json with unchanged registry name, changelog | +| Swift SDK | 0.7.1 | VERSION, changelog, including its explicit pre-1.0 options | +| Kotlin SDK | 0.2.1 | VERSION, Gradle VERSION_NAME marker, changelog | + +Rust's unrelated query dependency version stayed unchanged. Missing optional +owner Cargo.lock/npm lockfiles are not created by these updaters. Root lock +regeneration remains the existing native package-manager release preparation +step. Rehoming the build helper requires updating its extra-file reference in +the same move; the test verifies the existing reference's version update. + +A separate actual node-workspace plugin simulation used the query/SDK package +identities with a synthetic already-published query baseline. A query fix bumped +its consumer and exact dependency from 0.1.0 to 0.1.1; disabling the plugin lost +that consumer release. Keep the plugin with merge:false. The plugin also bumps +dev-only dependents, but none of the six currently configured Node products has +another configured product in devDependencies. Thus this behavior is not a +current release blocker. Do not place unrelated maintainer tooling there as a +release-managed local product. Cargo release owners must stay individual crates: +the Rust strategy intentionally bumps every member if pointed at a workspace. + +### Remote pending-release reconciliation + +Read-only GitHub checks on 2026-09-11 confirmed remote main still equals the +snapshot above. All 20 baseline tags in the table exist remotely at the recorded +commit and have public, non-draft, non-prerelease GitHub releases, published on +2026-09-08. The latest merged release preparation is +[PR 186](https://github.com/f0rr0/oliphaunt/pull/186), merged at +`5fdd03ac5bd6b7fb5f3cc471014b4313379de32e`, labeled autorelease: tagged. +Its publication tags resolve to the later release source commit already recorded +above; do not substitute the PR merge SHA for those immutable tag targets. + +There are no open release preparation PRs and no newer merged release +preparation awaiting publication. Pending-labeled PRs 179, 177, 167, 78, 76 and +58 are all closed and unmerged; their labels are stale, not unpublished intent. +Leave those historical PRs alone. No remote pending candidate needs an extra +carry at this snapshot; preserve the branch's captured notes below. Repeat the +read-only reconciliation at cutover because PR/release state can change. + +## Captured pending notes + +### liboliphaunt-native + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-native-v0.2.0...liboliphaunt-native-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-rust + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-rust-v0.2.0...oliphaunt-rust-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* exercise LLVM installation and share lifecycle test support ([05906fc](https://github.com/f0rr0/oliphaunt/commit/05906fca19cd4561b23fa18c4d0b3aa517e6a50e)) +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-broker + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-broker-v0.2.0...oliphaunt-broker-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) +* remove oversized fixtures and keep tests with their owners ([9609530](https://github.com/f0rr0/oliphaunt/commit/96095307126f14c35ed965501d2f3e07d77f621c)) + +### oliphaunt-node-direct + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-node-direct-v0.2.0...oliphaunt-node-direct-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-wasix-napi + +#### [0.1.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-wasix-napi-v0.1.0...oliphaunt-wasix-napi-v0.1.1) (2026-09-11) + + +##### Bug Fixes + +* **ci:** qualify unprivileged carriers and provision evidence dependencies ([5ee8fec](https://github.com/f0rr0/oliphaunt/commit/5ee8fecf00bbb41c1fa31f9501ad2c16070e6783)) +* **ci:** repair cache restores and carrier qualification ([2c77120](https://github.com/f0rr0/oliphaunt/commit/2c771205fda376acb4b81a89d3d510e2b48838a3)) +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-swift + +#### [0.7.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-swift-v0.7.0...oliphaunt-swift-v0.7.1) (2026-09-11) + + +##### Bug Fixes + +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-kotlin + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-kotlin-v0.2.0...oliphaunt-kotlin-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) +* remove oversized fixtures and keep tests with their owners ([9609530](https://github.com/f0rr0/oliphaunt/commit/96095307126f14c35ed965501d2f3e07d77f621c)) + +### oliphaunt-react-native + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-react-native-v0.2.0...oliphaunt-react-native-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* **ci:** repair cache restores and carrier qualification ([2c77120](https://github.com/f0rr0/oliphaunt/commit/2c771205fda376acb4b81a89d3d510e2b48838a3)) +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-js + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-js-v0.2.0...oliphaunt-js-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* avoid duplicate docs checks and type native SDK smoke helpers ([c14972f](https://github.com/f0rr0/oliphaunt/commit/c14972f457a0bdcca2b97910a710e9b5e6495afb)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-extension-pg-textsearch + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-extension-pg-textsearch-v0.2.0...oliphaunt-extension-pg-textsearch-v0.2.1) (2026-09-11) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-extension-postgis + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-extension-postgis-v0.2.0...oliphaunt-extension-postgis-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) +* remove oversized fixtures and keep tests with their owners ([9609530](https://github.com/f0rr0/oliphaunt/commit/96095307126f14c35ed965501d2f3e07d77f621c)) + +### liboliphaunt-wasix + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-wasix-v0.2.0...liboliphaunt-wasix-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### liboliphaunt-wasix-postmaster + +#### [0.1.1](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-wasix-postmaster-v0.1.0...liboliphaunt-wasix-postmaster-v0.1.1) (2026-09-11) + + +##### Bug Fixes + +* **ci:** qualify unprivileged carriers and provision evidence dependencies ([5ee8fec](https://github.com/f0rr0/oliphaunt/commit/5ee8fecf00bbb41c1fa31f9501ad2c16070e6783)) +* **ci:** repair cache restores and carrier qualification ([2c77120](https://github.com/f0rr0/oliphaunt/commit/2c771205fda376acb4b81a89d3d510e2b48838a3)) +* **ci:** repair cold client builds and Windows backup paths ([41b04b6](https://github.com/f0rr0/oliphaunt/commit/41b04b630ed4aa3014cee23758bd3f7c312fbbe7)) +* exercise LLVM installation and share lifecycle test support ([05906fc](https://github.com/f0rr0/oliphaunt/commit/05906fca19cd4561b23fa18c4d0b3aa517e6a50e)) +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) +* **postmaster:** include release asset finalizer in source checkout ([e425160](https://github.com/f0rr0/oliphaunt/commit/e425160984872b725debd82961aaef0d9054813b)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-wasix-rust + +#### [0.2.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-wasix-rust-v0.2.0...oliphaunt-wasix-rust-v0.2.1) (2026-09-11) + + +##### Bug Fixes + +* **ci:** repair cold client builds and Windows backup paths ([41b04b6](https://github.com/f0rr0/oliphaunt/commit/41b04b630ed4aa3014cee23758bd3f7c312fbbe7)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) + +### oliphaunt-wasix-ts + +#### [0.1.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-wasix-ts-v0.1.0...oliphaunt-wasix-ts-v0.1.1) (2026-09-11) + + +##### Bug Fixes + +* isolate owner tests and repair native build setup ([183ff83](https://github.com/f0rr0/oliphaunt/commit/183ff8311da860f719118046ceca8d6906ec07c1)) + + +##### Code Refactoring + +* localize product tooling and simplify release qualification ([96de165](https://github.com/f0rr0/oliphaunt/commit/96de16598206f05ca52867d36ff0c0e109bba782)) diff --git a/src/docs/architecture/repository-simplification-contracts.md b/src/docs/architecture/repository-simplification-contracts.md new file mode 100644 index 000000000..4adce31d2 --- /dev/null +++ b/src/docs/architecture/repository-simplification-contracts.md @@ -0,0 +1,270 @@ +# Repository simplification: product and completion contracts + +Planning companion to [the implementation plan](repository-simplification-plan.md). +These are target contracts, not claims that the commands or packages already +exist. The implementation plan owns task status and user decisions. This is +one-time migration review material; do not turn these tables into a second +dependency database, generated policy suite, or publishing framework. + +## Coverage of the current checkout + +On 2026-09-11, `git ls-files` enumerated 2,287 tracked paths, 55 `moon.yml` +files and 20 product `release.toml` declarations. Every tracked path falls in +one of the domains below. Counts include tracked paths regardless of rg ignore +rules. This establishes inventory coverage, not line-by-line correctness or +permission to delete unread implementations. Re-read exact callers and inputs +when implementing each disposition; account for later main changes in task 01. + +| Current domain | Paths | Planned owner / disposition | Tasks | +| --- | ---: | --- | --- | +| `src/sdks/rust-wasix` | 53 | Rust WASIX SDK; extract proxy; share query crate | 07,11,22 | +| `src/sdks/ts-wasix/sdk` | 183 | TS WASIX SDK; browser host; tools facade; local integration tests | 08,12,14,23 | +| `docs` | 82 | One docs project, remove API-generation/version scaffolding | 23,23a | +| `extensions` | 139 | Contrib, seven external products, producer/consumer tests and owned metadata | 19,25 | +| `src/postgres` | 5 | Shared pinned PostgreSQL source | 06 | +| `broker` | 68 | Broker product and its carriers | 09,10 | +| `src/runtimes/liboliphaunt-native` | 172 | Native runtime, extracted tools/resources, local binary helpers | 06,14–19,22 | +| `src/runtimes/liboliphaunt-wasix` | 180 | WASIX runtime, extracted tools/resources, retained AOT compiler work | 06,14–19,22 | +| `src/runtimes/liboliphaunt-wasix-postmaster` | 156 | Postmaster runtime, executor, Wasmer preparation and binary analysis | 06,13,22 | +| `src/database-resources/icu/cargo` | 4 | Resource-owned Cargo data carrier | 15,16 | +| `src/runtimes/liboliphaunt/licenses` | 3 | Notices owned by actual producers/pinned sources | 06,19,21 | +| `src/sdks/ts/node-addon` | 27 | `src/sdks/ts/node-addon`; replace C++ implementation with napi-rs | 04,09a,09b,17,22 | +| `src/sdks/ts-wasix/node-addon` | 31 | `src/sdks/ts-wasix/node-addon` | 04,17,22 | +| `src/sdks/ts/sdk` | 65 | `src/sdks/ts/sdk`; consolidate host adapters/resolution | 04,08,09b,17 | +| `src/sdks/rust/sdk` | 63 | Rust SDK, shared embedding/query crates, legitimate build helper | 07,09,10,22 | +| `src/sdks/swift` | 103 | Swift SDK and native package integration | 20 | +| `src/sdks/kotlin` | 56 | Kotlin SDK/plugin; move runtime Maven assembly to producers | 20 | +| `src/sdks/react-native` | 99 | RN package/plugin/codegen; product-local app adapters | 20,23 | +| `src/shared` | 183 | Eight domains explicitly mapped in the plan; no generic shared owner | 07–09,15,19,21–23 | +| `src/sources` | 40 | Common PG/ICU pins, product-specific pins, minimal common fetch/install | 06 | +| `tools/dev` | 21 | Minimal local setup and optional hooks | 06,22,25; M01–03 | +| `tools/graph` | 4 | Moon-to-CI adapter; remove second scheduler | 24 | +| `tools/policy` | 14 | Delete low-signal checks; localize meaningful checks | 22,24,25 | +| `tools/release` | 169 | Version preparation, candidate coordination, registry transports/recovery | 27–29 | +| `tools/test` | 12 | Fixtures beside actual surviving consumers | 21,22,25 | +| `examples` | 119 | Single-SDK examples local; cross-product apps remain integration projects | 23 | +| `benchmarks` | 51 | Deliberate optional benchmarks; remove abandoned scaffolding | 23,25 | +| `docs` | 50 | Merge maintainer/architecture content into docs owner; retain planning records | 23,23a | +| `.github` | 97 | Seven workflows, local actions/scripts, security configuration and issue templates | 24–29 | +| `.moon` | 4 | One task/dependency graph and supported inference | 05,24 | +| `.codex` | 8 | Update three skills and references with implemented commands | 23,26,29 | +| `.config` | 1 | nextest settings retained only where Rust tests need them | 05,25 | +| Root files | 25 | Workspace manifests/locks, tool/quality config, release config, Swift entrypoint, src/docs/notices | 04–06,20,23–29 | + +Root scope includes `.gitignore`, `.gitattributes`, `.prototools`, Rust toolchain, +Cargo/current pnpm workspace and locks (migrate pnpm to Bun in 06b), root package/Moon files, Biome/rustfmt/clippy/ +markdownlint/deny configuration, prek/committed/Renovate, Release Please files, +root SwiftPM, README/CONTRIBUTING and license/notices. Preserve useful settings; +remove stale paths, overrides and dependencies only after finding their consumers. +Review executable bits, case-only renames and line endings during the move. +Generated extension metadata, native headers, test reports and upstream patches +are accounted for by their owning domains; generated output is not automatically +dead code. Upstream patches must be applied and exercised, not just relocated. + +## Local command contract + +Every buildable leaf has `moon run :build`, usable from its directory, with +declared producer edges. There is one explicit workspace tool bootstrap; +individual builds do not install every ecosystem. Native commands below run +after their declared dependencies are prepared. No custom dependency walker. +Project README instructions state required host, setup, outputs and mutations. + +| Profile | Native commands executed by the corresponding Moon tasks | +| --- | --- | +| TypeScript library | `format` / `format-check`: Biome format write/check; `lint`: Biome lint; `typecheck`: `tsc --noEmit`; `build`: `tsc -p ` or the existing necessary bundler; `test`: `bun test` for retained source behaviour; `package`: `bun pm pack`; `test-consumer`: clean packed-package fixture | +| Rust crate/binary | `format` / `format-check`: `cargo fmt` / `cargo fmt --check`; `lint`: `cargo clippy --locked` for declared targets/features; `build`: `cargo build --locked`; `test`: `cargo test --locked` for the actual library/binary/integration/doc surfaces; `package`: `cargo package --locked` where publishable, or owned binary assembly; `test-consumer`: clean Cargo consumer | +| Native C/C++ runtime/extension | `format` / `lint`: retain applicable existing compiler/style tools only; `build`: local Bash invokes the existing necessary compiler/configure/make steps; `test`: focused source/helper tests; `test-integration`: built ABI/load/lifecycle behavior; `package`: owned assembly over finished binaries | +| Rust Node-API addon | Rust crate build/lint/test using existing pinned napi-rs; local Shell assembles the cdylib as the target .node carrier; TS handles metadata; common frozen-package consumer tests run under Node/Bun/Deno; no direct Node headers/C++ compiler setup for the adapter itself | +| Swift | `format` / `lint`: retained Swift tool configuration; `build`: `swift build` on supported macOS, `xcodebuild` for iOS/simulator schemes; `test`: `swift test`; `package`: owned SwiftPM/Apple artifact assembly; `test-consumer` / `test-device`: clean public SwiftPM and relevant simulator/device execution | +| Kotlin/Gradle | `format` / `format-check`: retained Gradle formatting tasks; `lint`: Android/plugin diagnostics; `build`: module `assemble`; `test`: JVM/unit Gradle tasks; `package`: Gradle publications assembled into local staging; `test-consumer`: isolated Gradle resolution/build; `test-device`: installed Android tests | +| React Native | TS format/lint/typecheck/build, `bun test` and `bun pm pack`; keep installed RN codegen CLI; native compile uses Kotlin/Swift producer outputs; Expo prebuild and platform build belong to the app; `test-device` consumes that built app | +| Docs | `dev`: Next dev; `format` / `lint`: Biome; `typecheck`: TypeScript after required Next/MDX type generation; `build`: Next build; `test-integration`: built routes/links; no SDK API-generator or compiler dependency | +| Data/upstream inputs | `prepare`: bounded verified source/tool acquisition; `build`: owned recipe if it produces data; `test`: contract/real initialization as appropriate; `package`: selected data archive/carrier; no fabricated lint/typecheck for data-only leaves | +| Integration app | Ecosystem-native app build, then separate `test-browser` / `test-device` / desktop `test-integration`; package-consumer setup explicitly chooses frozen candidates; retry never rebuilds the app | +| Tooling | Bash for command orchestration; TS for filesystem/data/HTTP; Rust for actual binary/compiler work. Focused tests only for retained behavior. No registry publication for maintainer helpers | + +The profile is a vocabulary, not mandatory boilerplate. Do not create every task +on every project, duplicate Cargo compilation as a universal typecheck, or run +`bun pm pack` as a lint check. Bun owns maintainer TypeScript/source tests; +preserve native-language and real host/browser/device execution. Shell wrappers orchestrate CLI consumers; TS tests +do not launch Shell. All target/candidate arguments are explicit at the owning +task, not hidden in CI environment defaults. + +## Product contracts + +Each row owns its source, tests, local commands and outputs. Independent release +owners have one changelog and one version authority. Carriers inherit that +version and never acquire independent changelogs. Existing registry names and +product tag components are preserved through directory moves. New public names +below are planned identifiers subject to a read-only collision check before +publication; no public identity is reserved now. + +| Leaf / group | Build dependencies and outputs | Release/version authority | Required proof and host scope | +| --- | --- | --- | --- | +| `src/runtimes/liboliphaunt-native` | PG source + native patches + compiled ICU; shared library, headers, server executable and required support files | Existing `liboliphaunt-native`, local VERSION; GitHub/npm/Cargo/Maven runtime carriers | Native C profile; ABI, direct lifecycle, server concurrency; desktop and Android/Apple declared binaries | +| `src/runtimes/liboliphaunt-wasix` | PG + WASIX toolchain/patches + compiled ICU where used; portable guest and declared AOT outputs | Existing `liboliphaunt-wasix`, VERSION; GitHub/npm/Cargo | Guest build on supported builder; portable guest execution, AOT compatibility and extension loading on declared hosts | +| `src/runtimes/liboliphaunt-wasix-postmaster` | PG + postmaster patches + pinned Wasmer/libc; sealed guest and compiler-free executor bundle | Existing runtime VERSION and GitHub assets | Concurrent clients, backend/process/shared-memory/recovery behavior; Linux x64/arm64 and macOS arm64 | +| `.../wasix-postmaster/executor` | Explicit prepared Wasmer dependencies + final guest; Cargo build/test | Internal build project, version follows postmaster; no extra registry release | Executor tests plus runtime integration; no compiler tools in consumer bundle | +| `.../wasix-postmaster/wasmer` | Pinned upstream/patches/compiler inputs; prepared source, sysroot and build tools | Internal upstream preparation, upstream identity separate from product SemVer | Patch/capability regressions when affected; compiler-bearing tools stay producer-only | +| `src/runtimes/wasix-browser-host` | Patched Rust/WASM host + wasm-pack; WASM/generated JS glue | Build project bundled by TS WASIX SDK; no separate public release/changelog | Host build and actual browser storage/query/worker lifecycle; edits release the consuming SDK | +| `src/sdks/ts/sdk` | TS query package + native addon/src/broker/runtime as required by entrypoints; JS/types | Existing `@oliphaunt/ts`, package.json | TS profile; packaged Node/Bun/Deno entrypoints and existing direct/broker/server behavior; relevant desktop embedding apps | +| `src/sdks/ts/node-addon` | Shared native Rust bindings + napi-rs; target `.node` files using the external native runtime | Existing `oliphaunt-node-direct` release owner, package.json; derive private Cargo version; target npm carriers | One addon per target under Node/Bun/Deno; ABI/error/cancel/stream/close, worker termination and generation cleanup; no runtime/resource embedding | +| `src/sdks/ts-wasix/sdk` | TS query package; browser host for browser, WASIX addon for server JS; JS/types/glue | Existing `@oliphaunt/wasix-ts`, package.json | TS profile; Node/Bun/Deno/Electron exports, browser worker and supported storage adapters; no native addon pulled into browser bundle | +| `src/sdks/ts-wasix/node-addon` | Rust WASIX SDK + Node-API adapter; target `.node` files | Existing `@oliphaunt/wasix-napi`, package.json; derive Cargo version | Cargo/Node-API build and clean target consumer; standard/ICU resources selected externally | +| `src/sdks/rust/sdk` | Rust query + shared native bindings + declared src/broker/runtime integration; Rust library | Existing `oliphaunt`, Cargo.toml | Rust profile; direct/broker/server semantics, public consumer and examples; desktop targets | +| `src/sdks/rust/sdk/crates/oliphaunt-build` if needed | Only necessary Cargo consumer integration; no producer orchestration | Existing `oliphaunt-build` identity/version follows Rust SDK; no independent notes | Clean downstream build proves retained metadata/link integration is needed; delete if no caller remains | +| `src/sdks/rust-wasix` | Rust query + runtime/AOT + supported Wasmer executor dependencies; Rust library | Existing `oliphaunt-wasix`, Cargo.toml | Rust profile; sync/async API, storage/recovery/cancel and selected assets on desktop targets | +| `src/sdks/ts-query` | TypeScript query/protocol source; JS/types | Normal published npm dependency, package.json, own notes; planned `@oliphaunt/ts-query` | Source cases and all actual SDK consumers; no bundled-source copy/version propagation engine | +| `src/sdks/rust-query` | Shared Rust query/protocol code; Rust crate | Normal Cargo dependency, Cargo.toml, own notes; planned `oliphaunt-query` | Rust tests plus both SDK type/behavior consumers | +| `src/sdks/rust/liboliphaunt-native` | Native C runtime + Rust bindings with embedded lifecycle handling; Rust crate | Normal Cargo dependency, Cargo.toml, own notes; planned `liboliphaunt-native-bindings` | Rust direct SDK, native napi-rs addon and broker share implementation; no public SDK dependency or transport/server spawning | +| `broker` | Shared embedded Rust crate + native runtime; child process executable | Existing `oliphaunt-broker` release owner/Cargo version and binary carriers | Authentication, IPC query/cancel/error, child death and shutdown; desktop targets | +| `pgwire-server` | Wire adapter library and WASIX CLI; native broker reuses proven common protocol code without pulling in Wasmer (10a/10b) | New Cargo product, Cargo.toml, own notes; planned `oliphaunt-pgwire-server`; no extra native broker executable | Ordinary PostgreSQL client query/error/reconnect/stop; real cancellation when advertised; retain backend-specific scheduling limits and desktop host support | +| `src/postgres-tools/native` | Matching PG/native build inputs; selected initdb and logical dump/restore binaries | Separate tools release owner, VERSION; preserve existing `oliphaunt-tools` / `@oliphaunt/tools` carrier identities | Actual initialize/dump/restore from clean desktop consumer; no tools in default SDK | +| `src/postgres-tools/wasix` | Matching guest/toolchain/AOT inputs; WASIX tools and TS facade | Separate tools release owner, VERSION; existing WASIX tools Cargo/npm identities derive this version | Actual tools execution through supported hosts; TS facade behavior on Node/Bun/Deno/browser where currently exposed | +| `database-resources` | Seed recipes use matching initialization tools; ICU data uses canonical data pin | One resource product, VERSION and one changelog; separately selectable seed/data carriers, preserve existing ICU identities | Four logical seeds, declared physical variants, shared compatible ICU data, safe initialization/reopen and no unselected downloads | +| `src/sdks/swift` | Native headers/binaries + selected resources/extensions through native package integration; Swift sources | Existing Swift VERSION/tag history; required root Package.swift; no second SDK-local public surface | Swift profile; macOS and iOS device/simulator declared surfaces; selected extension composition | +| `src/sdks/kotlin` | Native Android runtime + selected resources/extensions; AAR and integration plugin | Existing Kotlin VERSION; derive Gradle/module/plugin versions; Maven library/plugin/marker identities retained | Gradle profile; clean consumer, API floor, Android arm64-v8a/x86_64 | +| `src/sdks/kotlin/oliphaunt-android-gradle-plugin` | Gradle APIs and product-owned artifact configuration | Kotlin release-owned subproject, no independent version/changelog | Repeated configuration/build, ABI/resource selection, plugin marker resolution | +| `src/sdks/react-native` | TS query + Swift/Kotlin integration + RN codegen; package/plugin/native bindings | Existing `@oliphaunt/react-native`, package.json; derive podspec fields | TS/RN profile; Expo prebuild twice, add/remove assets, installed Android/iOS behavior | +| `src/extensions/contrib` | PG contrib source + matching runtime ABI; exact selectable members | Runtime-owned native/WASIX versions; no independent contrib/member release | Required actual extension lifecycle; selected-member packaging; shared changes select shipping runtimes | +| `src/extensions/external/pg_hashids` | Pinned extension source + compatible runtime | Existing independent VERSION/component | Build/package and actual load/lifecycle on each declared target | +| `src/extensions/external/pg_ivm` | Pinned extension source + compatible runtime | Existing independent VERSION/component | Same product-owned extension contract | +| `src/extensions/external/pg_textsearch` | Pinned extension source + compatible runtime | Existing independent VERSION/component | Same contract, including extension-specific operational constraints | +| `src/extensions/external/pg_uuidv7` | Pinned extension source + compatible runtime | Existing independent VERSION/component | Same product-owned extension contract | +| `src/extensions/external/pgtap` | Pinned extension source + compatible runtime | Existing independent VERSION/component | Same contract, including SQL-only behavior where applicable | +| `src/extensions/external/postgis` | Pinned PostGIS and native dependencies + compatible runtime | Existing independent VERSION/component | Same contract plus actual spatial operations and required dependency/notice closure | +| `src/extensions/external/vector` | Pinned vector source + compatible runtime | Existing independent VERSION/component | Same contract plus actual vector operations | +| `docs` | Written guides, site dependencies, explicit published-version input | Private site build/deploy; no docs-version archive, product SemVer, or package-release ceremony | Local site/type/link checks, actual Vercel refresh, no SDK compilation | + +`oliphaunt-build` is a release-owned subproject only if its downstream purpose +survives; task 09/22 must record its retained caller or delete it. No other new +product is conditional on speculative future use. Packaging directories and +carrier manifests are build/distribution details, not additional products. +`src/sdks/rust` is a group with no package manifest; its SDK and bindings are sibling +Cargo workspace members. The bare liboliphaunt-native registry name is reserved +for the actual runtime distribution, not these Rust bindings. No new runtime +facade package is required merely to occupy that name. + +## Supporting projects and ownership + +| Owner | Contents / commands | Release effect | +| --- | --- | --- | +| `src/third-party/postgres` | One PG pin and common/WASIX-shared patches; each runtime owns its lane deltas and complete ordered series; `prepare` applies only that lane's explicit inputs | Actual changed producer inputs select shipping runtime/tool/extension products; no postmaster dependency on the embedded runtime's patch directory | +| `src/third-party/icu` | Shared compiled-library pin/recipe; target build variants explicit; ICU data recipe belongs to resources | Compiled library changes affect embedding runtime binaries; data changes affect resource product | +| Other third-party inputs | OpenSSL shared only where truly consumed; Windows ICU toolchain local to native; Wasmer/libc/testsuite pins owned by actual executor/browser/AOT consumers | No independently released upstream-source wrapper; dependency edges follow actual use | +| `src/extensions/tools` / `src/extensions/tests` | Only truly common catalog/selection/build helpers and cross-extension behavioral fixtures | Tests/tools alone do not bump products; shipping-byte recipe changes do | +| `test-fixtures` | Shared protocol/storage/SQL data used by multiple projects; single-consumer fixtures local | No release; dependency edges select tests, not SDK versions | +| Integration applications | Existing browser, Expo, Electron/native, Electron/WASIX, Tauri/native, Tauri/WASIX; single-SDK samples move local | No public release; owning app build plus installed execution, not every example on every SDK change | +| `benchmarks` | SQL/data, native runner, WASIX Node/browser comparisons; optional measure tasks | No release or mandatory performance gate | +| `tools/dev` | Thin setup/install/hook commands | No product version bump unless a changed pinned producer input changes shipped outputs | +| `tools/ci` / `.github` | Moon task projection, runner provisioning, artifact transfer, required aggregate and credentials | No hidden product check or second affectedness graph | +| `tools/packaging` | Only surviving multi-product archive/notice helpers | Input edges select affected packaging and releases when shipped bytes change | +| `tools/release` | Release Please adapter, dependency closure, frozen candidate, registry transports and recovery | No compilation; controller-only fix can resume original candidate under explicit recovery rules | +| Root / skills / contributor docs | Native workspace/lock/tool configuration; documented commands and operational contracts | No general repository version or blanket all-project task | + +Internal Rust helpers such as AOT serialization, native packaging and sealing +remain with the producer that requires them. Remove empty Moon pseudo-projects +that only repeat file lists when native dependency declarations/task inputs cover +them. A shared recipe that embeds bytes in multiple products selects those +products; a normal published dependency update does not automatically release +every consumer. An explicit consumer dependency upgrade does release that consumer. + +## Target preservation and capability proof + +Preserve current declared support; do not expand or silently narrow it during +cleanup. Baseline authority: current product target metadata and +`src/docs/maintainers/release.md` Artifact and OS policy. Native desktop targets are +Linux x64/arm64 GNU, macOS arm64 and Windows x64 MSVC. Existing native ELF floors +are glibc 2.38 / GLIBCXX_3.4.30; direct macOS binaries target 11.0. Android uses +arm64-v8a/x86_64, API 24. Apple XCFrameworks have macOS arm64, iOS device arm64, +iOS simulator arm64; Swift SDK floors are macOS 14/iOS 17. WASIX portable/AOT +surfaces retain their declared desktop hosts. Postmaster currently declares +Linux x64/arm64 and macOS arm64, not Windows. TS facade host coverage includes +Node/Bun/Deno; WASIX also has browser and Electron entrypoints. + +These are separate product floors, not a universal minimum. Preserve current +Node engine ranges and Node-API requirements per manifest; validate the final +supported minimum as well as the CI toolchain. Do not infer browser/mobile +support for a product from another product's target list. No new macOS x64, +Windows ARM64, musl, Android 32-bit or other Apple slices are in scope. + +| Behavior | Required evidence | When selected | +| --- | --- | --- | +| Direct/native and WASIX semantics | Actual queries/parameters/results/errors, supported transactions, cancellation, close, persistence/reopen and existing backup/restore behavior | Owning execution/query/storage changes and changed runtime compatibility | +| Broker | Same shared execution plus authenticated IPC, process death, no ambiguous replay, shutdown | Broker/transport/shared execution changes | +| Native server / postmaster | Ordinary driver, multiple connections, process/backend lifecycle and recovery | Respective runtime/server changes | +| Optional resources/extensions | Standard/ICU selection, incompatible/corrupt data rejection before PGDATA mutation; selected extensions load and survive required lifecycle | Resource/extension/selection changes and dependent compatibility | +| Browser | Worker startup, query/cancel/close and implemented IndexedDB/OPFS storage behavior | Host/browser SDK/storage/build changes | +| Mobile | Real installed application, codegen/native integration, asset add/remove and existing isolation semantics | Native SDK/plugin/platform/resource changes | +| ABI/platform | Inspect final binary floors/exports/dependency closure plus actual target load/execute | Relevant binary/toolchain/target/packaging change | +| Package publication | Clean source/binary consumer, complete dependency closure, exact frozen payload identity | Every selected final package; reuse evidence only for identical package and relevant environment | + +The source inventory supplies detailed existing capabilities rather than +inventing new ones. Task 01 records the concrete existing test/example that +demonstrates each supported behavior; task 30 cannot substitute a happy-path +query for cancellation, recovery or existing storage functionality. + +## Completion record + +For each numbered task and M01–M18, record in the main plan: final owner/paths, +responsibility removed or simplified, affected callers, exact commands and +results, and any unavailable platform/public-state evidence. A retained helper +needs a concrete consumer and failure it prevents. A deletion needs caller +review and either replacement behavior proof or evidence that it had no user. +Do not add tests merely to enforce this record. + +Completion requires the final dependency graph, all product rows, every baseline +domain and the acceptance matrix to agree. Sample affectedness probes supplement +the graph/input review; they do not prove every possible path by themselves. +Tests required by the new contract must pass on the final candidate; unavailable +host/registry/deployment evidence remains incomplete. No removed feature or +weakened guarantee can be hidden by renaming a task or marking it optional. + +No implementation, registry reservation, workflow dispatch or production deploy +is authorized merely by completing this planning document. + +## Binding amendment — resource, query, patch and Bun consolidation + +The plan's 2026-09-11 consolidation contracts are required acceptance criteria. +Tasks 15–20 move immutable resource composition into producers/app builds and +delete redundant SDK resource assemblers while preserving custom inputs and +safe mutable PGDATA initialization. Tasks 07/08 own shared query methods/errors; +23/25 use independent PostgreSQL behaviour where applicable, retaining only +necessary malformed-input and product-specific expectations. Task 11a replaces +the private native server smoke query client with an ordinary consumer and +narrows production readiness. Task 06 owns three ordered PostgreSQL patch lanes +and shared common/WASIX deltas, preserving current semantics and optimizations. +Task 06b migrates maintenance to Bun 1.4.2 (or a newly verified exact stable pin +at implementation start), Bun workspaces/lock, bun:test and Bun packing; removes +pnpm machinery; and proves Moon, installation policy, package consumers, docs +and release-PR lock refresh before cutover. Cargo/Swift/Gradle stay native. +Tasks 24–29 test shared behaviour once, boundary differences at their adapters +and actual final packages/platforms only where needed, without a second scheduler. + +Issues #212 (browser-host vendor-patch extraction) and #213 (Wasmer family +alignment) are explicitly parked and do not block final acceptance. Task 12's +existing build ownership work remains required. Optimization tuning/deletion +is not added to this implementation scope. + +## Binding amendment — broker PG wire, UniFFI and React Native + +Tasks 10a/10b add native broker PG wire proof and cutover: ordinary query/result/ +error/stream/cancel traffic uses PG wire; only necessary authenticated backup/ +process shutdown management remains private. Preserve one-backend semantics, +real incremental protocol progress and native cancellation; the current WASIX +proxy's CancelRequest branch is not sufficient proof. The plan specifies the +native pump, protocol/auth boundaries, independent clients and cutover/deletion +criteria. No new HTTP/RPC service or pretend concurrent server. + +Tasks 09c/09d prove then adopt UniFFI over the real Rust direct session/query +implementation, or take the minimal existing C _with_error fallback. A successful +path adds private src/sdks/rust/mobile-bindings, whose generated code/native artifacts +ship under Swift/Kotlin versions, with actual Cargo/Moon/Gradle/Swift input edges +and no independent release. Resolve linked Apple symbols/static extensions, +Android JNA/ABI loading, Swift strict concurrency, cancellation, disposal versus +shutdown, streaming and final consumer packaging before deleting the old bridge. +No unused UniFFI implementation remains after fallback. Task 20a shares RN JSI +mechanics under its own cpp directory with runtime-scoped ownership and thin +platform adapters, retaining actual SDK integration. Final task20 and acceptance +depend on these tasks. Generated bindings do not themselves implement mobile +process isolation or replace platform-specific application integration. diff --git a/src/docs/architecture/repository-simplification-plan.md b/src/docs/architecture/repository-simplification-plan.md new file mode 100644 index 000000000..5f9212664 --- /dev/null +++ b/src/docs/architecture/repository-simplification-plan.md @@ -0,0 +1,3813 @@ +# Repository simplification implementation plan + +Status: implementation in progress. The `src/` migration is committed in +`e15e05d0`; final hosted qualification remains pending. +Product/resource separation, shared Rust/query/mobile implementations, broker +PostgreSQL wire transport, Bun tooling, and CI/release machinery are implemented. +Deno addon teardown, native cross-commit reuse, release-scope narrowing, final +acceptance review and external cutover remain open. See the current checkpoint +below; older dated checkpoints describe evidence available at that time. +Unchecked acceptance items must not be inferred complete from source changes. +Baseline inspected: 2026-09-11. This document records the current discussion's +decisions and supersedes conflicting proposed layouts in that discussion. The +existing source-architecture document continues to describe current behavior +until the corresponding implementation changes land. + +## Current completion checkpoint — 2026-09-14 + +The detailed checkboxes are acceptance gates, not a count of unimplemented +features. Several combine completed code with final platform or publication +evidence. Do not estimate remaining work from their checked percentage. + +Implemented and verified locally: + +- Task 04: all twelve project/input groups now live under `src/`; workspaces, + locks, root SwiftPM entrypoint, CI and maintenance tools retain root ownership. + Bun frozen installation, Cargo locked metadata, Moon discovery, source-pin + validation and Rust formatting pass. No committed JavaScript/Python scripts + remain; the sole PowerShell file is the explicit MSVC setup boundary. +- Shared query/native Rust crates, Rust Node-API addon, PG-wire broker, + standalone pgwire-server, generated mobile bindings, shared RN JSI, resource + separation and PostgreSQL patch ownership are implemented. Deno's separate + FFI implementation remains intentionally until its worker cleanup is correct. +- Post-move SDK source/type/lint checks, targeted native/WASIX packaging and + consumer fixtures, extension model generation, full workflow and release + aggregates, Release Please candidate tests, and historical-tag lookup pass. + Docs build/check and all 49 exported HTML pages pass from `src/docs`. +- On pre-move commit `d46ceef2`, CI run `34834976587` passed the iOS app build, + iOS E2E and WASIX TypeScript browser job. Its build aggregate failed because + two successful ABI jobs were omitted from the gate's direct dependencies. + Commit `80cda37c` fixes that omission. This is not evidence for the new tree. +- The near-successful run took 96.5 wall-clock minutes and 781 cumulative + runner-minutes. Its 121 source checks spent 1,419 seconds in setup versus + 111 seconds executing. Compatible check grouping now uses 20 jobs instead of + 34, preserving every task and capability boundary; test grouping is unchanged. + Linux postmaster imports its same-run native binaries and validates existing + source/host/hash receipts instead of repeating a measured 12-minute compile. + This saves runner time, not necessarily critical-path time. Local workflow, + grouping, artifact-transfer and receipt checks pass. Ripgrep installation uses + a pinned prebuilt release instead of compiling it during runner setup. +- Source fetching now separates runtime and extension inputs. The libiconv + acquisition failure has a checksum-verified GNU-listed mirror fallback with + bounded retries; actual mirror bytes and corrupt/unavailable fallback cases + pass. Required Android PostGIS inputs remain included. +- Vercel's preview build passed for `e15e05d0`. Its first CI run exposed three + missed migration paths, including the shared external-extension recipe lookup + that dropped ancillary SQL metadata. The corrected source-test matrix also + caught a fourth path in the database-resources launcher. These are corrected + at their existing owners; no compatibility directories or new path checks + were added. A forced local pass covers 175 selected source/unit/policy targets + and 21 prerequisite tasks, without Moon result-cache reuse. All pass after the + fixes and a one-time clean of relocated Kotlin/Swift generated caches, in + about 15 minutes total. Swift's 94 tests pass. Existing compiler outputs were + retained where valid; this is not a cold native rebuild. Only the Apple-only + Swift test is unavailable locally; product/platform builds remain hosted proof. +- The subsequent hosted run passed the corrected extension/resource groups but + six jobs failed before source checks when Bun/Moon downloads returned HTTP + 504. Verified Moon/Bun, Node and npm tool caches now save on PRs using GitHub's + existing cache isolation, rather than inheriting the heavy-build cache gate. + Existing installers still verify restored bytes. Bun/Moon downloaders use + curl's bounded exponential backoff instead of exhausting retries in ten seconds. + No alternate download service or cache framework was added. +- Hosted setup on `daded1e4` recovered from six HTTP 504s, then saved verified + tools; later jobs restored the same PR-scoped caches. All source/test gates + passed. Product builds exposed the shared ICU data lookup climbing one parent + too far, and pgwire packaging copying a stale notice. The ICU lookup is fixed + and validates data before host compilation; pgwire stages canonical notices + and deletes its stale duplicate. Forward review corrected the iOS packaging + task's old path. Actual local Android x86_64 build, Linux native rebuild/package/ + extracted-artifact tests, and WASIX core compile/link/package checks pass. + Real Rust, WASIX Rust, pgwire, TS SDK, Swift source and rebuilt Kotlin package + checks pass. Old Apple artifacts correctly reject changed notices and require + current hosted producers; they were not rewritten to appear qualified. +- Run `34861280576` exposed archive-relative broker paths incorrectly prefixed + with `src/`, three stale WASIX extension recipe/source lookups, and a mobile + resolver expecting the pre-move contract path. These are corrected at their + existing owners. Restored external source discovery also exposed an outdated + WASIX validator rejecting the fetcher's supported pinned archive mirrors. + Mobile fixtures now consume producer metadata instead of repeating stale + compatibility expectations. The run's actual artifacts pass all 39 native + extension lifecycle cases across direct/broker/server, including restart and + backup/restore, plus packed Rust and pinned Node/Bun/Deno consumers locally. + All 39 same-run extensions materialize for both Android ABIs, and the complete + Android runtime resource package stages with ICU and all extensions. Rust + tooling tests/format/lint and mobile resolver/carrier tests pass. + The actual Android x86_64 release APK build passes with pinned Node 22.22.3 + and same-run SDK/runtime inputs, including all 39 static extension links, + APK alignment/signature and packaged Kotlin bytecode verification. No device + execution is claimed by this local build. + Actual WASIX extension compilation, including PostGIS and its dependencies, + and downstream packaging of all 39 extension artifacts also pass locally. + The hosted iOS extension producer and Linux x64 postmaster qualification pass; + the latter confirms receipt-validated import of same-run native binaries. + The relocated hosted proof binary needed a temporary local fixture-path + symlink, removed after testing; no production lookup behavior was changed. + These local results do not constitute hosted qualification of the fixes. +- Run `34868625206` passed 112 jobs; its sole underlying failure was the final + WASIX runtime release packager reading the old `extensions/generated` path. + The corrected task passes locally with that run's portable and four-platform + AOT artifacts, including archive validation. Two uncached executions produce + identical release checksums. Hosted qualification of this correction is pending. + +### PR #210 reconciliation — 2026-09-15 + +Reviewed `5a7ed4ca` from PR #210 against the current split-resource tree; +port behavior rather than its old paths and bundled-runtime seed format. + +- Native Rust: share registered resource discovery with the dynamic library + loader and make exported resource-macro error construction callable by external + crates. Keep that implementation in the current shared native Rust package. + Forward the registered root to broker children; the normal packed consumer + now tests registration without a library-path override. +- Native TypeScript and Android: reject links/special files while copying seed + input and publish Android PGDATA with owner-only permissions. TypeScript and + WASIX already apply private root permissions; keep the corresponding tests. +- Seed production: native and WASIX validate the same complete PostgreSQL + directory layout, including empty directories. Preserve the current carrier + `emptyDirectories` manifest/archive transport instead of adding the PR's + separate `directories-v1.txt` format or bundling seeds back into runtimes. +- WASIX initialization: explicit seed selection, seed-free memory/directory + creation, and existing-root preservation already implement the PR's behavior. + Extend the existing resource integration test to prove durable rows after + reopening seed-free storage; reuse the restore permission helper for seed copies. + Runtime assets no longer own seed archive/manifest pairs, so the old runtime + build-script assertion is superseded by resource-owned validation. +- The optional-download intent belongs to tasks 15–18 below. Native mobile still + requires an explicitly selected seed; do not imply seed-free mobile support. + Swift source archive download granularity remains an explicit limitation. + No old JavaScript release tools, package identities, or duplicate meta-checks + are restored from PR #210. + +Local validation passes: the fresh packed Rust consumer exercises direct, +broker and server behavior with backup/restore/restart; native Rust tests, +Android resource tests, TypeScript initialization/type/lint checks, WASIX's +148 unit tests and standard/ICU resource integration tests pass. Actual native +seed npm/Cargo packaging preserves empty directories. The separate ICU-fetch +race in run `34881596962` is fixed with per-source serialization and a real +concurrent-fetch regression. Hosted qualification of this combined tree remains +pending; these checks do not claim installed Android/iOS execution. + +### PR #211 reconciliation — 2026-09-15 + +Reviewed PR #211 through `9608b2da`, including its follow-up fixes, against +the current product owners. This is a selective integration, not adoption of +the PR's alternative bundled-resource architecture. + +- TypeScript: add native `/direct` and `/broker` entrypoints, explicit WASIX + `/browser`, and host-specific storage types. Native entrypoints no longer + load browser storage/archive providers. Installed-package consumers check + the exported declarations. Preserve the existing default APIs. +- Binary inputs: normalize Buffer views before deferred query snapshots and + copy descriptor bytes correctly, including nonzero offsets. WASIX N-API + snapshots seed/ICU views before moving validation and preparation onto the + database/server owner thread. Async resource failures reject promises. +- WASIX tools: pass user arguments directly to native execution; append browser + connection/input flags at the browser execution boundary. Delete the reverse + parser for managed argument suffixes. Retain independent validated tool/AOT + assets. Component-wise backup paths reject traversal and remain portable. +- Mobile: add the Java blocking facade over the existing Kotlin session and + an RN directory/file-URI helper. Swift native-only extensions explicitly + declare an empty resource payload, so source archives need not preserve + empty directories. Missing declared payloads and empty SQL-extension payloads + remain errors. +- CI/public consumers: isolate unrelated APT feeds and inherited local + Cargo/Rust/runtime/Node/loader settings. Preserve prebuilt ripgrep setup. +- Already covered: ABI 2, tools AOT carriers and packed-consumer selection, + explicit independent seeds/ICU, PR #210 discovery/permissions, verified Android + artifact versions, and Swift native dependency linkage/registration rollback. + Keep UUID's feature selection: the current AOT proof still needs that feature. +- Not adopted: bundled standard seeds/contrib, runtime-owned duplicate ICU + products, old paths/tooling, wholesale provenance removal, or weaker Cargo + version checks. The PR's automatic Rust embedding and cross-SDK descriptor + API replacement are separate API designs, not required fixes to these ports. +- Deferred external cutover: standalone Swift repository publication requires + explicit repository identities and publisher permissions aligned with the + current resource products. The PR's generic anonymous database-execution + publication probe is not implemented here; existing packed runtime consumers + and public installation checks retain their separate responsibilities. + +Local evidence includes the full WASIX TypeScript suite, native TypeScript +tests/package checks, shared query tests, Swift tests/carrier composition, +Android unit tests and a Java consumer compiled against the AAR, RN checks, +WASIX/pgwire/N-API Rust tests and Clippy, and a rebuilt addon's asynchronous +resource regression. The full pinned workflow gate and public-consumer +environment tests pass. These results do not claim hosted qualification, +Apple device execution, or implementation of the deferred API/publication work. + +Robustness follow-up: run `34957705991` at `224ba8d1` exposed an incomplete +local RN validation: the new storage tests passed, but the full suite rejected +the additive export through a handwritten exact-name list. Replace that list +with public-entrypoint directory/open/close behavior and run the full RN task, +including its packaging/transport Shell tests. Native TypeScript's existing +clean installed-consumer task also compiles and executes the new subpaths; +packaging itself does not acquire another test phase. Fresh browser packages +pass actual pg_dump/psql execution. The rebuilt WASIX addon passes its complete +integration suite, and registered Rust resources and concurrent source fetching +pass their behavioral checks. Mixed local runtime/extension/addon artifacts +were correctly rejected; they are not qualifying evidence for installed hosts. +After restoring matching producer artifacts and rebuilding the full-feature +release addon, the installed WASIX SDK passes Node, Bun, Deno and Electron +actor/direct/worker/server, extension, persistence and backup/restore checks. +Native TypeScript's clean packed consumer passes Node/Bun/Deno; the full RN +suite, lint/codegen/typecheck/build and Kotlin's both-ABI Maven packaging pass. +These local results close the missed test coverage; hosted qualification of +the follow-up commit remains required. + +Remaining execution checklist (grouped from the detailed tasks below): + +- [ ] **Current-tree qualification (03,06,24b,30):** commit the reviewed move and + consolidation, then qualify its exact tree once. The GNU availability failure + in pre-move run `34846430536` is corrected locally; no green hosted aggregate + exists yet for the completed migration. +- [ ] **Deno consolidation (09b):** resolve terminated-worker stream cleanup + through the shared addon, then remove Deno FFI/ABI duplication. Ordinary Deno + query success through the existing fallback does not satisfy this task. + Pinned Deno 2.8.1 also fails to invoke native cleanup when terminating a worker + in a plain JavaScript busy loop, without a stream; idle-worker cleanup succeeds. + This isolates an upstream lifecycle blocker. Node 22.22.3 and Bun 1.4.2 each + pass all 60 cleanup cases, including waiting for native close acknowledgement. +- [ ] **Release dependency scope/reuse (26–26b):** narrow Rust-only release + fanout, finish verified native cross-commit producer reuse, and qualify the + native TS published-dependency path once its public inventory is complete. + Product-scoped selection, same-run transfers and qualification request/reuse + logic already exist; they do not need to be implemented again. + Rust mobile fanout follows a real compiled dependency on the SDK's mobile + bindings, so removing its selection edge would be incorrect. The native + cross-commit broker pilot would add a provenance/artifact lookup mechanism to + save about 92 seconds across Linux builds; it remains unimplemented rather + than adding that maintenance cost without a worthwhile producer target. +- [ ] **Product acceptance/cost evidence (09a–20, M05,M10,M12,M16–17):** reconcile + existing Windows/Apple/Android/browser results against the final carriers; + fill uncovered lifecycle, clean-consumer and host edge cases. Record the + requested addon/mobile package-size, copying and build-cost comparison. + Preserve the declared device/ABI support boundaries when recording coverage. +- [ ] **Final ownership/simplification review (01–02,05–06b,23–25b, + M02–03,M08–09,M11,M13–15,M18):** close the domain and retained-check disposition + ledger, leaf command/prerequisite documentation, affectedness precision and + cold/warm/concurrent execution review. Broad ecosystem Renovate groups were + removed; only coordinated React and Node-API dependencies remain grouped. + Representative dependency-update qualification and supported-host installer + proof remain. This is a one-time review, not a new meta-check suite. +- [ ] **Release candidate/history review (02a,27,27a,27d):** refresh publication + lineage/version floors, review real candidate notes, and prove the hosted bot + PR lifecycle including closed/reopened PRs and final-head-only CI. Different + installed product-version transitions and the retained Release Please engine + already have completed local proof (27b/27c). +- [ ] **Public release/recovery cutover (24c,28–29a,M07):** verify actual required + checks, publisher identities and environments; prove clean public installs, + SwiftPM tag/asset visibility, conditional bootstrap and interrupted recovery. + Ninety-day retention and local recovery fault tests already exist. Registry, + deployment and remote-settings mutations require their own authorization. + Read-only inspection confirms main requires `Required`, restricted release + environments and read-only default Actions permissions. Bootstrap credentials + are still configured and current registry trust has not been proved against + an approved current publication lock; historical successful releases do not + establish current publication readiness. +- [ ] **Docs freshness/final audit (23a,30a):** Vercel's existing root is confirmed + as `src/docs`. The release job now snapshots completed public versions and + verifies their links on the live page after requesting a rebuild; parser and + stale/error cases pass locally. The deploy hook and GitHub secret are absent. + Configure them and prove actual release refresh, docs-only main deployment + and failed-deployment recovery. Guides stay on main, versions from public releases. + +Issues #212 (browser-host extraction) and #213 (Wasmer convergence), and optional +PostgreSQL optimization changes, remain deliberately outside this completion scope. + +## Objective and scope + +Preserve product capabilities while removing unnecessary tooling, hidden +dependencies, bundled optional payloads, duplicated checks, and release steps. +Make each product understandable and buildable through its own ecosystem; +Moon supplies cross-project task ordering and affectedness. This work does not +merge the native and WASIX SDK APIs, remove the desktop broker, rename the +three runtimes, add postmaster direct mode, or ship the mobile isolation spike. + +The user subsequently authorized implementation of this plan. Production code, +local package metadata and workflows are now being changed in the working tree; +no publication, tag push or deployment is implied by these local changes. +The [product and completion contracts](repository-simplification-contracts.md) +are part of this plan: they enumerate the current domains, define commands and +release ownership for the target leaves, and preserve supported target behavior. + +## Verified starting point + +- Branch: `f0rr0/simplify-product-tooling`. +- HEAD: `e425160984872b725debd82961aaef0d9054813b`. +- Freshly fetched `origin/main`: `f4b7a5c71c8e244f77cc08d474e06e47fe336287`. +- Before this document: 38 modified tracked files, 295 insertions and 337 + deletions. These include partial task normalization and postmaster asset + finalization changes. Preserve and review them; do not reset or count them as + validated completion of this plan. +- [CI for HEAD](https://github.com/f0rr0/oliphaunt/actions/runs/34370136091) + failed. The two failing producer jobs are WASIX TypeScript SDK and iOS App; + E2E, Builds and Required also failed as aggregate consequences. +- Browser log: `browser endpoint did not become ready` for Chromium's + `/json/list` endpoint. Root cause remains to be fixed, not assumed to be a + timeout setting. +- iOS log: Hermes compilation cannot find `facebook::jsi::TypedArray`. + React Native/Hermes/Expo dependency coherence needs a targeted fix. +- Tracked `*.js`, `*.mjs`, `*.cjs`, and `*.py` inventory returned no files. + The remaining language violation includes TypeScript launching commands in + release implementation and tests. Generated/upstream JavaScript remains + permitted; do not convert upstream dependencies solely for language purity. +- `tools/release` currently has 169 files, `src/shared/artifact-packaging` 61, + `src/shared/product-metadata` 17, and `tools/policy` 14 (file counts, not LOC + or a deletion estimate). There is significant tooling left to review. + +Specific source findings: + +| Area | Current evidence | Gap | +| --- | --- | --- | +| Native runtime | `src/runtimes/liboliphaunt/native` | Source, resources, tools and release carriers share one owner | +| WASIX runtime | `src/runtimes/liboliphaunt/wasix/tools/wasix-runtime-npm-carrier.mts` | Standard seed is part of runtime packaging | +| WASIX addon | `src/runtimes/wasix-napi/Cargo.toml`, `build.rs` | Unconditional ICU dependency; both seeds required; release enables tools/extensions | +| ICU | Native and WASIX `release.toml`; `native/bin/icu.sh` | npm/Maven and Cargo owners differ; WASIX imports native-owned common helper | +| Rust query sharing | Both SDK `build.rs`, `src/shared/rust-query-core/query_core.rs` | Source copying/include mechanism instead of a registry dependency | +| Broker | `src/runtimes/src/broker/Cargo.toml`; native SDK `broker*.rs` | Executable depends on public SDK internal feature | +| Socket server | WASIX Rust `Cargo.toml`, `src/bin/oliphaunt_wasix_proxy.rs`, `src/oliphaunt/proxy.rs` | Existing library/CLI behavior is embedded in SDK ownership | +| Browser host | `src/bindings/wasix-ts/host/build-sdk.sh`, `patches/0007-*` | Patches Rust, builds with wasm-pack, emits WASM and JS; wrongly placed under TypeScript | +| Postmaster executor | `runtime/executor/Cargo.toml.in` | Injected into upstream Wasmer workspace; cannot simply run Cargo in source directory | +| Swift | Root and SDK-local `Package.swift` | Different public product surfaces; potential development/publication drift | +| Qualification | `.github/workflows/ci.yml` job `qualified` | Requires manual dispatch with all native/WASM/mobile selectors, regardless of selected release products | +| Release | `.github/workflows/release.yml` | Already exposes only prepare-release-pr and publish; publish already conditionally bootstraps missing identities | + +Follow-up workflow review identified additional implementation obligations: + +- CI listens to PR open/synchronize/reopen/close, merge-group, main push and + manual dispatch. Each event needs explicit immutable base/head semantics. +- Planning currently waits for release-intent validation. Release PRs have a + generated-metadata admission check before expensive planning; keep its useful + behavior without making source PR testing depend on publication readiness. +- Release PR preparation creates/updates the bot PR, normalizes it to a single + commit and pushes with a lease. A transient raw PR update can otherwise cause + duplicate expensive CI or stale results. +- Six reusable/secondary workflows accompany ci.yml: broker-runtime, + liboliphaunt-native-desktop, extension-artifacts-native, + mobile-extension-packages, mobile-e2e and release. Their paths, permissions, + artifact interfaces and gate semantics must change together where affected. +- Candidate/ledger retention is explicitly 90 days at several release upload + points. Safe retries depend on those bytes remaining available. +- The release-controls implementation expects `Required` as the sole protected + branch check. This is source policy, not a fresh verification of remote + settings; task 24c includes that read-only inventory before cutover. + +The planning coverage pass enumerated all 2,287 tracked paths, 55 Moon manifests +and 20 release declarations; the companion contracts account for every domain, +including root/hidden configuration and generated-source/tooling seams. This +is not a claim that every implementation line or platform has been validated. +Task 01 refreshes this ledger against the implementation checkout; each task +must read the exact code/callers it changes before deletion. + +## Decisions and names + +Agreed: + +- Keep `liboliphaunt-native`, `liboliphaunt-wasix`, and + `liboliphaunt-wasix-postmaster`. +- Keep broker; extract its shared native Rust implementation cleanly. +- One project owns database seeds and ICU data; neither payload belongs in a + default runtime/SDK/addon package. Compiled ICU libraries are a different, + runtime-build dependency. +- Four logical seeds: native standard, native ICU, WASIX standard, WASIX ICU. + Native physical compatibility variants remain explicit. No postmaster seed + support is promised until produced and verified. +- ICU seeds reference the same compatible ICU data package; standard seeds do + not depend on it. ICU data can also be selected without a seed. +- Publish shared Rust crates needed by published crates. Eliminate bespoke + source copying used solely to avoid publishing dependencies. +- Name the SDKs `src/sdks/ts`, `src/sdks/ts-wasix`, `src/sdks/rust`, and + `src/sdks/rust-wasix`. Unsuffixed SDKs use the native runtime. +- `src/sdks/rust` is a grouping directory: `sdk/` owns the public Rust SDK and + `liboliphaunt-native/` owns its shared native Rust bindings. Both are normal + Cargo workspace members; the group itself has no Cargo.toml. Reserve the bare + `liboliphaunt-native` package name for runtime distribution; the bindings crate + is `liboliphaunt-native-bindings`, subject to registry availability. +- Each TypeScript product group contains `sdk/` and `node-addon/`. Keep the + addon beside its consuming API regardless of implementation language; + grouping directories are not packages. Remove `bindings` and the + miscellaneous `shared` grouping. +- Browser users consume `src/sdks/ts-wasix/sdk`; there is no separate browser SDK. + Its execution host lives at `src/runtimes/wasix-browser-host`, outside SDKs. + Placement follows responsibility, not implementation language alone. +- Keep ordinary root workspaces/lockfiles and the required Swift publication + entrypoint. Target Bun workspaces/bun.lock for TypeScript and Cargo for Rust; + Bun is the maintainer TypeScript runtime and test runner. Preserve + platform-native tooling inside each SDK. Task 06b owns pnpm retirement. +- No committed JavaScript/Python scripting. Shell runs commands; TypeScript + processes data. Product Rust/C/C++/Swift/Kotlin remains appropriate. Sudo is + allowed only in explicit CI machine setup. + +Names approved in the follow-up planning review; the shared Rust name applies +the user's requirement to include liboliphaunt-native: + +| Name | Meaning and limit | +| --- | --- | +| `database-resources` | One owner for `seeds/` and `icu/`; no unrelated assets. Public seed descriptions say “pre-initialized PostgreSQL data directory.” | +| `pgwire-server` | PostgreSQL wire-protocol server library and CLI over the existing WASIX SDK. It does not promise native support or postmaster concurrency. | +| `src/sdks/ts-query`, `src/sdks/rust-query` | Approved shared query package folders beside their consuming SDKs. | +| `src/sdks/rust/liboliphaunt-native` | Rust bindings to the native C runtime used by direct SDK and broker: open, execute, cancellation, backup and close; excludes server spawning and broker transport. Cargo name: `liboliphaunt-native-bindings`, subject to registry availability. | + +Folder names do not automatically rename existing registry packages. Check +existing public identities before introducing new ones. No compatibility +aliases are required merely for this research project's old API, but immutable +public versions/tags must never be overwritten. + +Decisions resolved for implementation without another architecture-selection phase: + +- Retain Release Please as the sole candidate version/changelog/PR engine. + Use native strategies and minimal derived-file updates. Task 27b verifies the + pinned integration, rather than launching an open-ended replacement project. + Shared shipped-byte impact is computed from the declared producer graph and + supplied to that one candidate path; no second SemVer/changelog writer. +- Publish TS query code as a normal npm dependency, and the shared Rust query + and embedded-operation code as normal Cargo dependencies. Stop bundling source + merely to avoid publishing these dependencies. Preserve consumer behavior. +- Consolidate native Node/Bun/Deno direct execution through one Rust napi-rs + addon at src/sdks/ts/node-addon, depending on src/sdks/rust/liboliphaunt-native. + Rust direct SDK and broker use that same bindings crate directly. Remove the + C++ addon and Deno-specific FFI implementation after replacement behavior is + proven. Use Node-API 8 and the existing pinned napi-rs family initially. + Keep native and WASIX addons as separate products; share small proven adapter + facilities only where semantics coincide, never a universal backend framework. + Deno uses npm with a local node_modules directory and explicit FFI permission; + document this installation change rather than retaining a second FFI backend. +- Browser host is its own build project and is bundled/released with the WASIX + TS SDK. It gets no independent public package/version/changelog in this scope. +- Native and WASIX PostgreSQL tools are separate release owners. Their existing + carrier names are transferred deliberately; old published versions stay intact. +- Database resources are one release product/version/changelog, with separate + seed/profile/target and shared ICU-data carriers. Do not create an all-assets + facade. Native and WASIX ICU seeds reference one compatible ICU-data identity. +- Keep normal root workspaces/locks. Local native manifests represent language + dependencies; Moon edges represent cross-language build outputs. Shared data + and build recipes have declared owners, not a parallel file-impact whitelist. +- Use existing supported tool managers and archive facilities first. Choosing + the smallest platform-compatible implementation is routine engineering; it + does not require user approval. Keep narrow custom handling only with a + demonstrated constraint and a meaningful behavior check. +- User approved docs from main on docs changes and after product releases, + with installation versions taken only from completed public releases. No + historical src/docs/version selector. See the explicit deployment contract below. +- No target/API capability is dropped to simplify CI. Optional assets become + explicit inputs; migration examples explain that intentional API/install change. + +User decisions resolved: database-resources, pgwire-server, ts-query and rust-query +were approved; the shared Rust package must include liboliphaunt-native in its +name and live inside the Rust group, implemented here as +src/sdks/rust/liboliphaunt-native with Cargo name liboliphaunt-native-bindings. +The bare liboliphaunt-native identity remains reserved for runtime distribution. +Docs use main guides and +published versions. No unanswered user preference currently blocks this plan. + +Registry availability, actual Vercel settings, native-host results and publication +permissions are facts to verify, not preference questions. If access is missing, +record the exact missing evidence; never silently mark the corresponding task done. + +## Target shape + +The agreed `src/` grouping contains projects and their source inputs. Repository +maintenance tools, workspace manifests and locks remain at root; generated +outputs remain under `target/`. Docs live at `src/docs`; Vercel should use that +project root. + +```text +/ + Cargo.toml, Cargo.lock + package.json, bun.lock, bunfig.toml + Package.swift + .moon/, .github/ + src/ + runtimes/ + liboliphaunt-native/ + liboliphaunt-wasix/ + liboliphaunt-wasix-postmaster/ + executor/ + wasmer/ # pins, patches, host production + wasix-browser-host/ # Rust/WASM execution host, not an SDK + database-resources/ + seeds/native/ + seeds/wasix/ + icu/ + packaging/{cargo,npm,swift,maven}/ + sdks/ + ts/ + sdk/ + node-addon/ + ts-wasix/ + sdk/ # browser and supported server-side JS + node-addon/ + rust/ # grouping directory, not a package + sdk/ # Cargo package: oliphaunt + liboliphaunt-native/ # Cargo: liboliphaunt-native-bindings + mobile-bindings/ # private UniFFI adapter shared by Swift/Kotlin + rust-wasix/ + ts-query/ + rust-query/ + swift/ + kotlin/ + react-native/ + broker/ + pgwire-server/ + postgres-tools/{native,wasix}/ + extensions/{contrib,external,tests,tools}/ + third-party/{postgres,icu,...}/ + docs/{src,content,public}/ + examples/ + benchmarks/ + test-fixtures/ + tools/{dev,ci,packaging,release}/ +``` + +Grouping directories are not packages. Leaf projects own relevant native +manifests, source/tests/examples, README and Moon tasks. Only real public +release boundaries own release metadata and changelogs. Generated registry +staging trees, archives, upstream worktrees and caches are ignored outputs. +The browser host is a build project released as part of the WASIX TS SDK. +Grouping directories such as src/sdks/ts, src/sdks/rust and postgres-tools have no package +manifest. Shared Rust query code remains at src/sdks/rust-query because both native +and WASIX SDKs consume it. + +Path disposition, beyond the obvious SDK/runtime moves: + +| Current path | Destination or action | +| --- | --- | +| `src/sdks/js` | `src/sdks/ts/sdk` | +| `src/runtimes/node-direct` | `src/sdks/ts/node-addon` | +| `src/bindings/wasix-ts` SDK source | `src/sdks/ts-wasix/sdk` | +| `src/runtimes/wasix-napi` | `src/sdks/ts-wasix/node-addon` | +| `src/bindings/wasix-ts/host` | `src/runtimes/wasix-browser-host` | +| `src/sdks/rust` | `src/sdks/rust/sdk`, with native bindings extracted to `src/sdks/rust/liboliphaunt-native` | +| `src/bindings/wasix-rust` | `src/sdks/rust-wasix`, removing unnecessary wrapper nesting | +| `src/sdks/rust/crates/oliphaunt-build` | `src/sdks/rust/sdk/crates/oliphaunt-build` if still needed for consumer build integration; remove asset-production responsibilities | +| `src/bindings/wasix-ts/tools-package` | `src/postgres-tools/wasix` owns product; language facade stays with its packaging | +| Native/WASIX runtime tools crates and npm packages | `src/postgres-tools/native` and `src/postgres-tools/wasix` | +| Native resource packager | Split seed/data production to database-resources; extension selection to extensions; app assembly remains consumer-owned | +| `src/postgres/versions/18` and common PG source pins | `src/third-party/postgres`; one upstream identity | +| `src/sources/third-party` | Common pins to third-party; product-only pins/patches to their owner | +| `src/sources/toolchains` | Product-only toolchains local; common installer entrypoints in tools/dev | +| `src/shared/js-core`, `rust-query-core` | `src/sdks/ts-query` and `src/sdks/rust-query` packages | +| `src/shared/cluster-seed-contract` | database-resources | +| `src/shared/extension-runtime-contract` | extensions | +| `src/shared/artifact-packaging` | Product-specific files local; proven reusable remainder in tools/packaging | +| `src/shared/product-metadata` | Native package manifests plus minimal release-only readers in tools/release | +| `src/shared/mobile-tools` | SDK-owned local launchers; CI provisioning only in tools/ci | +| `src/shared/fixtures` | test-fixtures, after moving single-consumer data locally | +| `tools/graph`, workflow policy/fixtures | Minimal CI adapter in tools/ci; delete duplicate graph logic where Moon suffices | +| `tools/test` | Tests/fixtures beside the release/CI/packaging code that uses them | +| `tools/perf`, `src/benchmarks/perf` | One benchmarks owner; keep only maintained measurement tools | +| `src/docs` plus root `docs` | One docs project; preserve URLs and maintainer content | +| Root examples | Keep multi-product applications; move single-product examples to their SDK | +| `.codex/skills` and contributor docs | Update commands and contracts with their implementation, not ahead of it | + +## Dependency and task contract + +Use package/Cargo/Gradle/Swift manifests for dependencies they can represent. +Use explicit Moon task edges for cross-language artifacts. Do not build another +task scheduler or encode all dependencies in release metadata. Every product +must have one documented command that builds its required dependency outputs +automatically. `moon run :build` is the common checkout entrypoint, +usable from the product directory. Native ecosystem commands use their own +declared prerequisites; they must not pretend to provide orchestration they do +not implement. `bun run build` alone does not magically traverse Moon edges. +Where a package script exposes the orchestrated build, it delegates directly to +Moon and Moon invokes a distinct native compiler command, avoiding recursion. +No custom dependency walker or manual list of prerequisite builds is acceptable. + +Required directions (arrows mean “requires”): + +```text +runtime build → pinned PostgreSQL + selected patches + compiled ICU where used +seed build → matching runtime initialization tools + seed recipe +ICU seed build → compatible ICU data +SDK → selected runtime + shared query/embedding libraries +application → SDK + explicitly selected seed/data/src/extensions/tools +src/sdks/rust/sdk → src/sdks/rust/liboliphaunt-native → src/runtimes/liboliphaunt-native +broker → src/sdks/rust/liboliphaunt-native → src/runtimes/liboliphaunt-native +pgwire-server → WASIX Rust SDK → WASIX runtime +src/sdks/ts-wasix/sdk (browser) → src/runtimes/wasix-browser-host + liboliphaunt-wasix +src/sdks/ts-wasix/sdk (Node-API) → src/sdks/ts-wasix/node-addon → src/sdks/rust-wasix +src/sdks/ts/sdk (Node/Bun/Deno direct) → src/sdks/ts/node-addon (Rust napi-rs) + → src/sdks/rust/liboliphaunt-native → src/runtimes/liboliphaunt-native +src/sdks/ts/sdk (broker) → TypeScript IPC client → broker executable +React Native → Swift/Kotlin SDKs + TypeScript query code +``` + +No runtime-to-seed build edge, no SDK-to-pgwire-server edge, no broker-to-public +SDK edge. Browser host compiler prerequisites must not pull seed production into +its build. Platform-specific Wasmer versions remain explicit. + +| Task | Behavior | +| --- | --- | +| format / format-check | Rewrite / check formatting | +| lint | Static diagnostics, no package installation smoke tests | +| typecheck | Separate type analysis when useful; do not duplicate Rust build work without benefit | +| build | Produce project outputs with necessary producer prerequisites | +| test | Project tests; compilation is allowed where required by the ecosystem | +| test-integration | Built product against actual dependencies | +| test-artifacts | Verify the final distributable with its owning product's harness | +| test-consumer | Install packaged public surface in a clean consumer | +| test-browser / test-device | Real browser or mobile application behavior | +| package | Assemble distributable outputs; no hidden whole-product qualification | +| publish | Upload prepared, verified bytes; no compiler invocation | + +Map these to Cargo, package scripts, SwiftPM and Gradle without manufacturing +empty tasks. Internal target-specific names may be more precise. Document what +each command produces, requires, modifies and needs from its host. + +## Ordered implementation backlog + +The checklist below tracks final-state completion; the implementation log records +completed chunks whose wider prerequisites remain open. Each task must record changed paths and actual check +results when completed. A plan, moved directory or passing metadata check is +not implementation evidence. Dependencies use task IDs. +The machinery dispositions below are part of their linked tasks, not a second +implementation phase. Close each disposition with its owner task and include +the resulting evidence in task 30. + +### Phase A — close the inventory and settle boundaries + +- [ ] **01 — Complete the baseline ledger.** Inspect every tracked source, + workflow, package/build manifest, product registry surface and remaining + tooling caller. Classify product code, necessary production tooling, test, + generated output, duplicate or deletion candidate. Record supported product + behavior and shipped asset inventory before changes. Read existing partial + diff and preserve useful work. **Done:** every current product/source domain + has an owner and destination; deletions cite callers and replacement proof. + Do not create a permanent file-by-file policy checker from this ledger. + Start from the companion's complete domain enumeration; refresh it for main + movement and the existing partial diff, and record concrete behavior witnesses + before moving their owners. Implementation reads happen at each changing seam. +- [ ] **02 — Finalize names and release boundaries.** Depends 01. Use the + names and ownership decisions above; report an actual registry collision + before altering a public identity. Preserve the agreed SDK/browser-host paths. Inventory + existing public identities read-only. Fix product vs + carrier classification; list exact manifests/derived version fields. Keep + native and WASIX SDKs separate for this migration. **Done:** one reviewed + current-to-target map, dependency graph and version authority per product; + no unresolved placeholder in the implementation tree. +- [ ] **02a — Map existing publication history to final owners.** Depends 02. + Existing-component lineage and captured pending notes are recorded in + [release-owner-migration-lineage.md](release-owner-migration-lineage.md). + Refresh the one-time capture at cutover; carrier transfers and ecosystem + updater qualification remain open as specified there. + Preserve the 20 current release components, immutable tags and public versions; + record transfers of tools/ICU/resource carriers and new shared/proxy products. + Keep existing registry names where possible. Initialize a transferred owner's + next version above already-published carrier versions; do not restart at 0.1.0 + or replay all pre-move history. Record source/tag/changelog lineage explicitly. + **Done:** every existing carrier has exactly one final owner, new identities + have collision checks, and a disposable first post-move release selects the + right products without duplicate notes, forgotten pending releases or version + reuse. No actual registry mutation is needed to complete the mapping. +- [ ] **03 — Capture minimal failing reproductions.** Depends 01. Browser: + trace startup/process stderr/endpoint lifecycle on the actual browser lane. + iOS: trace Expo/RN/Hermes/JSI dependency and header selection. **Done:** each + failure has a causal diagnosis and narrow reproduction, without raising + timeouts or launching another exhaustive CI run as the diagnostic method. + +### Phase B — establish the readable ownership layout once + +- [x] **04 — Move existing products and update references.** Depends 02a,27b. + Apply the target tree in a coordinated structural pass. Update workspace + members, local package paths, Moon roots, release paths, native build paths, + include paths, source pins, workflows and docs links together. Do not leave + forwarding script forests or compatibility directories. **Done:** manifests + parse, native dependency queries and Moon project/task discovery resolve; + no active build reference points at a removed path. Deeper extraction follows + below; a moved product is not marked functionally complete yet. +- [ ] **05 — Normalize project commands and task edges.** Depends 04,06b. Replace + ambiguous compile/unit/smoke/regression/release-package aliases with the + vocabulary above after inspecting actual commands. Keep necessary internal + tasks. Fix ordering at data dependencies, not via global prerequisites. + **Done:** each leaf README has exact local commands and prerequisites; + action-graph inspection shows producer-before-consumer and no duplicate + inherited checks. Repeat build/package invocations have explicit semantics. +- [ ] **06 — Consolidate source/toolchain preparation.** Depends 04. Keep one + immutable PG source authority, common ICU library build helper, product-local + Wasmer/toolchain pins. Preserve exact-pin and transactional fetch behavior. + Remove guessed mirrors and silent PATH fallback. **Done:** clean/repeated/ + interrupted preparation tested at the owning boundary; missing prerequisites + fail clearly; no product command needs sudo or all-repo setup. + Apply the three-lane PostgreSQL patch hierarchy below: one common source and + shared patch authority, explicit ordered lane series, no postmaster borrowing + files from the embedded WASIX product. Preserve the selected deltas and their + build guards; classification is not permission to drop optimizations. + ICU checkpoint: native and WASIX now consume + `src/third-party/icu/tools/build.sh` through the existing ICU source dependency. + Native tools retain their configured absolute path and restore the previous + build on failure; target installs validate a `DESTDIR` stage before replacing + the installed prefix. The owner test proves repeat/changed-input behavior and + configure/build/install failure retention; real cached Linux ICU installation + preserves library bytes. This does not establish crash-safe concurrent cache + publication or replace the remaining platform qualification. +- [ ] **06b — Consolidate TypeScript tooling on Bun and retire pnpm.** Depends + 04. Follow the Bun migration contract below. Bun is the maintainer TypeScript + runtime and test runner; target Bun workspaces, one root bun.lock and no pnpm + machinery. Pin stable 1.4.2 as verified on 2026-09-11; reassess the latest stable + release at implementation start, then freeze one exact version for the change. + **Done:** clean/frozen/repeated installs, leaf commands, Moon dependency + discovery, packed workspace/catalog dependencies, docs and native integration + consumers work. Remove pnpm installers/scoped-workspace writers/configuration, + stale locks, caches and CI steps; migrate useful Vitest tests to bun:test and + delete redundant ones. Keep required browser/device harnesses and host-specific + product execution. Record an actual blocker before retaining any exception; + do not implement a package-manager compatibility layer. + +### Phase C — fix genuine package boundaries + +- [x] **07 — Create the shared Rust query crate.** Depends 04–05. Replace + include/copy build-script paths in both SDKs with a versioned path+registry + dependency. Publish as a normal dependency; retain public type behavior. + **Done:** both SDKs build/test; clean packaged consumers resolve the crate; + source-copy infrastructure is deleted and cross-SDK types are intentional. + Move QueryResult/QueryRow inherent methods into the owning query crate: + consumers cannot add inherent methods after these types become external. + Use shared query/decode errors and direct SDK-boundary conversion; delete + duplicate text accessors and unnecessary anyhow/public-error round trips. + Preserve meaningful behaviour, not the existing arrangement of wrappers. + Apply the behaviour-based query proof contract below with 08,23,25. +- [x] **08 — Finish the TypeScript query package.** Depends 04–05. Keep only + reusable query/protocol code. Native/WASIX/RN consume the declared workspace + package as a normal published npm dependency; remove bundled-source copies; + no invisible unpublished dependency in a published package. **Done:** clean + packed consumers work; shared changes select all actual consumers; no SDK + copies a parallel hand-maintained query implementation. + Use the same behaviour-based query proof contract as 07. Browser/RN adapters + keep only their conversion and host-specific checks; no duplicate decoder + suite in every SDK or assertions against implementation source text. +- [x] **09 — Extract shared native Rust execution.** Depends 07. Move the + minimal actual native embedded lifecycle/session API out of the public SDK. + Keep server spawning and broker transport out. Trace config/error/resources + and cancellation types before extraction to avoid circular dependencies. + **Done:** direct SDK and broker both use the new publishable crate; preserve + close, cancellation, error behavior, resource lifetimes and data persistence. + Include the Node/Deno lifecycle requirements identified in the consolidation + review below: generation-aware cleanup, resident-library lifetime, operation + error capture and raw-stream completion. Do not extract an SDK-dependent API + that forces the addon or broker to import the public SDK again. +- [ ] **09a — Replace the native C++ addon with a Rust napi-rs boundary.** + Depends 09. Add a normal Cargo cdylib manifest to src/sdks/ts/node-addon and consume + liboliphaunt-native-bindings. Keep JS conversion/promises/callbacks/environment + cleanup in the addon; shared native operations belong to the bindings crate. + Reuse the existing napi/napi-derive/napi-build versions and Node-API 8 target; + avoid another per-adapter executor, Tokio runtime or generic backend framework. + **Done:** existing native behavior tests pass through the new addon, including + long-query responsiveness/cancel, raw streaming/error recovery, close/reopen, + forgotten/stale handles and worker termination with pending work. No callbacks + access a destroyed environment, stale generation closes a new session, or + runtime image unloads while native work remains. Package per existing desktop + target; compare installed closure/build cost to the old addon. This task closes + the replacement adapter implementation and focused native proof. Task 09b owns + final cross-host cutover and deletion of the old implementation; temporary + comparison fixtures are not a shipped fallback or an extra permanent backend. +- [ ] **09b — Consolidate Node/Bun/Deno loading and retire duplicate native FFI.** + Depends 09a,18,19. One TypeScript package resolver and one napi-rs addon per + native target serve all three hosts. Remove Deno.dlopen/UnsafePointer/callback + code and handwritten ABI layouts; migrate broker/server callers before removing + assets-deno.ts. Use node: filesystem/module/process/socket compatibility APIs + where they work; keep only demonstrated host differences. Keep broker/server + clients addon-free and preserve explicit local runtime/asset overrides. + **Done:** frozen native packages install and execute under pinned Node/Bun/Deno + on each declared desktop target, without Rust/C++ compilation or postinstall + downloads. Document/test Deno node_modules and scoped permissions, missing-addon + errors, optional resources/extensions and package exports. Existing supported + behavior survives; no silent fallback to the deleted FFI backend. Port actual + lifecycle/failure tests instead of retaining source-spelling assertions. Delete + the C++ addon, Node-header acquisition and exclusive build/tests after parity; + preserve any C ABI fault fixture still needed by the shared bindings. Apply + the CI/release/version and browser/mobile separation rules in the review below. +- [ ] **09c — Prove generated Swift/Kotlin bindings over shared Rust.** Depends + 09. Run the bounded UniFFI feasibility work specified below before rewriting + mobile bridges. **Done:** record actual Android/Apple build and behavioural + evidence, packaging/dependency/size costs, and a go/no-go decision per supported + surface. A generated hello-world or desktop Rust test does not close this task. + **Implemented/proven:** shared Rust owner, request-scoped cancellation, + generated Swift 6 strict-concurrency and Kotlin public-facade execution on + Linux; both shipped Android ABI libraries and actual Maven carriers build. + **Remaining:** Apple framework/installed SwiftPM execution, Android device/R8 + qualification, and the requested shipping size/copy/build-cost comparison. +- [ ] **09d — Consolidate mobile execution or apply the minimal C fallback.** + Depends 09c,18,19. On successful proof, replace handwritten native bridges and + duplicated proven-shareable query/session behaviour with Rust plus generated + Swift/Kotlin bindings. Otherwise retain the minimal platform bridges and + migrate operations to the existing _with_error C ABI. **Done:** the chosen + path preserves all declared mobile/desktop SDK behaviour, uses ordinary + manifests and final carriers, and deletes the superseded implementation/tests. + No permanent dual backend, platform-wide rewrite or extra generated SDK layer. + **Implemented:** production Swift/Kotlin use the private UniFFI adapter; + handwritten Swift C/JNI session bridges are deleted. Shared Rust owns execution, + shutdown and cancellation, while idiomatic facades retain admission and resource + preparation. Android carriers include generated bindings and per-target legal + inventories; Swift generated source and framework publication are wired. + **Remaining:** the unavailable Apple and Android device gates in 09c; do not + repeat the completed bridge migration or mark platform parity proven by Linux. +- [ ] **10a — Prove PG wire for the native broker.** Depends 09,11. Follow the + broker contract below: native incremental protocol boundary, standard startup/ + auth/cancel, one active backend and a tiny separate management channel. + **Done:** independent ordinary clients, fragmented extended-query/Flush/Sync + traffic, streaming/backpressure/cancel and malformed/disconnect cases work on + the real native engine. Record maintained-code/dependency cost versus current + framing. Do not treat the existing WASIX proxy as a working native adapter. + **Implemented/proven on Linux:** production broker and Rust/TypeScript clients + use standard startup/password authentication, BackendKeyData/CancelRequest and + SQL PG wire, with separate lifecycle management. Native incremental input is + bounded at 128 MiB to preserve the prior request limit; real clients pass + >4 MiB Bind, later Flush/Sync, COPY/CopyFail recovery and cancellation. + Stream tokens reject stale feeds. Completed disconnects reset safely; partial + batch disconnects terminally close the helper instead of hanging or replaying + uncertain work. Native Linux cancellation wakeups use PostgreSQL's self-pipe. + Final Linux src/broker/native archive consumers and Node/Bun/Deno direct/broker + query and backup/restore contracts pass. + **Remaining:** shipped Windows/macOS transport qualification and the requested + maintained-code/dependency comparison. Do not repeat the completed prototype + or consumer cutover. +- [ ] **10 — Clean the retained desktop broker.** Depends 09,10a. Remove public + SDK internal-feature dependency. Keep the child executable and necessary + authenticated IPC operations; review redundant framing/adapters. Do not + introduce a new RPC stack without a demonstrated reduction. **Done:** direct + and broker semantic checks pass; invalid authentication, cancellation, + child death and shutdown remain correct; no ambiguous SQL replay. + **Implemented:** shared native bindings replace the public SDK internal-feature + dependency, and production SQL traffic uses PG wire. Final Linux archive + consumers pass; Windows/macOS shipped transport qualification remains open. +- [ ] **10b — Cut broker consumers over to PG wire and remove query envelopes.** + Depends 10. Use the proven protocol boundary and common pgwire-server library + where it actually removes duplication; keep broker process/config/control + ownership local. Migrate Rust/TS clients, package/version dependencies and + standard-client qualification. **Done:** delete PGOB query/chunk/cancel paths + and duplicate adapters after equivalent public behaviour; retain only required + management operations. No second binary, HTTP/RPC framework or falsely + advertised concurrent server is introduced by the protocol change. + **Implemented:** Rust and TypeScript clients use the production PG wire path; + SQL/query/chunk/cancel envelopes are removed. Lifecycle control stays separate. + **Remaining:** final supported-platform packaged consumer qualification; Linux + and its Node/Bun/Deno host matrix already pass. +- [x] **11 — Extract pgwire-server library and CLI.** Depends 07. Move the + existing WASIX proxy and CLI under one independently versioned owner. Remove + SDK back-dependencies by passing existing public/runtime facilities. Preserve + the currently supported connection scheduling, protocol and storage behavior. + **Done:** a standard PostgreSQL client connects to the installed CLI; query, + disconnect/reconnect, error and shutdown tests pass; no concurrency claims + beyond observed behavior. No extra standalone daemon framework. +- [ ] **11a — Simplify native server readiness and consumer proof.** Depends + 14. Trace Rust/TS readiness and smoke-client callers. Keep only the bounded + connection/child-lifecycle behaviour production needs; remove the TS private + query client path after moving server smoke queries to an ordinary PostgreSQL + driver (reuse an existing dev dependency where possible). Do not introduce a + production driver just for tests or weaken readiness to an open-port probe. + **Done:** a clean packaged server is queried by a standard external client; + requested database/user readiness, child exit, timeout, endpoint ownership + and cleanup failures retain meaningful coverage. No published query machinery + exists solely to serve a smoke test; server mode still exposes its endpoint. +- [ ] **12 — Make the browser host a real owned build project.** Depends + 03,05,06. Put it under src/runtimes/wasix-browser-host, retain its Rust/WASM pins and + JS packaging. Make preparation and build inputs visible; keep consumption by + src/sdks/ts-wasix/sdk explicit. Do not create another browser SDK. Fix the browser + failure diagnosed in 03 at its actual owner. + **Done:** standalone host build produces pinned WASM/glue; SDK browser test + consumes it; failed browser startup surfaces process failure immediately; + storage/query/close behavior is checked in the supported browser lane. + Deeper extraction of implementation from vendor patches is parked in #212; + Wasmer family convergence is parked in #213. Neither blocks this task. +- [ ] **13 — Make the postmaster executor locally buildable.** Depends 06. + Replace or minimize workspace injection through Cargo.toml.in. Prefer an + ordinary product-owned manifest with explicit prepared Wasmer dependencies; + keep any unavoidable generated path configuration minimal and documented. + Preserve compiler-free executor versus compiler-bearing producer separation. + **Done:** documented preparation then Cargo/Moon build works from its owner; + packaged executor excludes compiler tools; concurrent backend behavior and + required host capabilities pass their focused behavioral checks. +- [ ] **14 — Separate PostgreSQL tools ownership.** Depends 04–06. Move + native/WASIX tool packages and TypeScript tools facade to their owning products; + retain initdb/dump/restore and supported targets. Remove automatic SDK/addon + inclusion. **Done:** clean selected tools consumer can initialize and perform + logical dump/restore; default SDK install excludes utility binaries. + - [x] Native and WASIX utility archives, Rust carriers and npm carriers have + independent `src/postgres-tools/native` and `src/postgres-tools/wasix` owners. + Existing registry identities retain their history; transferred versions + start at 0.2.1. Runtime compatibility versions remain separate. + - [x] Native tools archive carries its own shared-library closure. Linux + packaged consumers completed logical roundtrips on Node, Bun and Deno + without borrowing runtime libraries; repeated archive bytes matched. + - [x] WASIX addon exposes execution-only tooling through ABI 2. Optional + tools supply portable bytes plus trusted target AOT bytes/manifest; + Rust checks module hashes, engine, target and source identity. Default + addon dependency closure excludes utility asset crates. + - [x] Portable npm descriptors derive hashes and sizes from owner archives. + Four optional target npm carriers supply native AOT; browser exports use + portable bytes. SDK/facade versions are no longer coupled. + - [x] Tools facade package and host/browser behavior tests have their own + tasks. SDK tests no longer pull utilities; tools tests depend on SDK + outputs. Browser logical roundtrip duplication is removed and its direct + and Worker cases remain in the tools-owned browser entry. + - [x] CI and release preparation transfer separately owned tool artifacts; + publication reuses existing carrier assembly and source-package downloads + instead of adding a tools aggregate job or another release procedure. + - [ ] Rebuild matching WASIX portable/AOT outputs after structural changes + settle, then run the tools owner's native and browser consumer tasks. + Cached pre-move WASIX artifacts currently fail the preserved source + fingerprint guard; source/package fixtures do not replace this proof. + - [ ] Complete target artifact qualification on macOS/Windows and the final + publication-lock/dry-run aggregate with the independently owned archives. + +### Phase D — selectable database resources and extensions + +- [ ] **15 — Establish the database-resources producer.** Depends 06,14. + Move seed recipes/contracts and ICU data pin/packaging under one owner. + Decouple native resource packager responsibilities. Define one asset manifest + with profile, physical compatibility, producer identity, ICU requirement and + checksum. **Done:** seed production requires runtime tools, never vice versa; + standard/ICU seeds can be produced independently; one canonical ICU data tree. + - [x] Mobile CI transfers the existing native build outputs and ABI receipts + into seed tasks without selecting runtime packages or recompiling native + code. iOS seed execution uses macOS; receipt-only validation stays on Linux. + Target handoffs preserve executable modes and symlinks in tar envelopes. + The local workflow aggregate passes, including real handoff execution and + Android/iOS seed-only dependency plans; actual mobile seed qualification + still requires the corresponding native runner outputs. +- [ ] **16 — Package independently selectable resources.** Depends 15. Produce + separate installable seed carriers by runtime/profile/required target plus + one compatible shared ICU data carrier per ecosystem. ICU seed depends on + data, without copying it. Add no default all-assets package. **Done:** clean + consumers install standard only, ICU only, and native+WASIX ICU selections; + package/download/application sizes demonstrate absence of unselected assets + and reuse of identical ICU data. Record Swift source-fetch limitations rather + than calling linker omission “selective download.” +- [ ] **17 — Remove runtime and addon payload embedding.** Depends 16. + Update native/WASIX Cargo/npm carriers, WASIX addon build.rs and mobile + resource assembly. SDK initialization consumes explicit seed/data inputs. + Existing databases need no seed; supported desktop initdb paths remain. + **Done:** default SDK/runtime/addon artifacts contain neither seed nor ICU + data; missing required seed/data gives a useful error; standard and ICU + initialization/reopen work on declared surfaces without runtime downloads. + Apply the resource-consumption contract below: move immutable composition to + producers and native application build integration, delete SDK-local package + assemblers/duplicated catalog-cache logic, and retain only necessary runtime + location, compatibility and mutable-storage operations. Trace explicit custom + resources/extensions as well as defaults before deleting any branch. +- [ ] **18 — Preserve compatibility and safe initialization.** Depends 17. + Reject wrong runtime/physical format/ICU data and corrupted archives before + touching existing PGDATA. Preserve staging, concurrency locks and interrupted + initialization recovery. Do not assume postmaster accepts lightweight seeds. + **Done:** real packaged seeds boot, persist, reopen and support ICU collations + as selected; wrong/corrupt inputs preserve existing data. Repeated producer + invocations do not duplicate publication work. Freeze verified seed bytes; + do not assert byte-reproducible initdb without demonstrating it. +- [ ] **19 — Localize extension model and selection.** Depends 04,16–17. + Move extension contracts and product-specific packaging from shared/root + tooling. Preserve contrib distribution versus independent external products, + upstream-bound versions, source pins and per-product notices. Remove addon + defaults that include every extension. **Done:** two selected contrib members + plus an external member stage only selected members; every declared carrier + exists and loads on its promised target; unsupported selection fails clearly. + Follow add-oliphaunt-extension evidence requirements when changing support. + +### Phase E — ecosystem consumers and repository cleanup + +- [ ] **20a — Share React Native JSI mechanics.** Depends 03,08,09d. Apply the RN + contract below after deciding the mobile boundary. Share platform-independent + buffer/promise/stream acknowledgement/teardown logic in RN-owned C++; keep + JNI/Objective-C++ and actual platform SDK calls thin. **Done:** final Android/ + iOS RN apps prove binary ranges/lifetimes, callback abort, cancellation, + shutdown and JS runtime destruction. Remove duplicated machinery and tests; + retain platform differences supported by source and actual behaviour. + **Implemented:** Android and iOS include RN-owned `cpp/Jsi.h` and + `cpp/Lifecycle.h`; common lifecycle behavior has one C++ test owner. + **Remaining:** final Android/iOS/Hermes application tests for callback waits, + cancellation, reload and runtime destruction. Shared helper tests alone do not + close the platform integration acceptance. +- [ ] **20 — Finish Swift, Kotlin and React Native integration.** Depends + 08,09b,09d,20a,17–19. Reconcile root/local Swift public products from one authority; + preserve required root SwiftPM publication. Move Maven artifact assembly out + of the SDK where it is runtime-owned; retain useful Gradle integration. + Fix the actual RN/Hermes/JSI inconsistency diagnosed in 03. **Done:** packaged + Swift/Gradle/RN consumers build; real simulator/device tests exercise selected + assets. Current direct-mode mobile behavior is preserved; PR #126 isolation + research remains documented separately, not silently advertised as shipped. + **Implemented:** Swift source/binary carrier wiring and root manifest rendering, + Android Maven carrier integration, and separately selected mobile seed/ICU + resources. APK reporting accepts one matching seed or seedless existing storage; + actual archive fixtures and seedless Gradle resolver tests pass. + Kotlin source qualification now excludes Android native payload builds; + real AAR tasks retain both ABI producers before resource merging. UniFFI's + existing JNA cleaner preserves Android API 24 support. Lint, JVM/Android unit + tests, configuration-cache serialization and native binding behavior pass + locally; these do not substitute for installed-device qualification. + **Remaining:** installed Apple SwiftPM/app and Android/iOS RN device qualification, + including the shared JSI lifecycle gates in 20a. No new process isolation claim. +- [x] **21 — Delete remaining generic shared ownership.** Depends 07–20. + Apply every shared-domain disposition above. Review all import/call sites; + localize single-consumer helpers; retain only proven common packaging code. + **Done:** no miscellaneous shared product holds unrelated policy, product + behavior and packaging. Necessary shared code has normal declared consumers. +- [x] **22 — Remove command orchestration from TypeScript and excess xtask.** + Depends 21. Include test setup and child_process calls, not only production + scripts. Shell fixtures invoke commands and pass data to TS checks; TS uses + native filesystem/HTTP APIs. Keep Rust where it implements actual compiler, + runtime or binary-format work. **Done:** no TS-through-Shell orchestration or + owned JS/Python source; deleted wrappers have a verified replacement or no + remaining caller. Do not wrap every command in a new helper library. + **Local completion:** maintainer/test commands run from Shell; shared archive, + Git and release checks use owner-local data assertions. The complete release + aggregate and source-fetch archive/Git fault suite pass. Remaining TypeScript + process calls implement product runtime/tool execution or isolated Node addon + lifecycle consumers, not maintenance orchestration. +- [ ] **23 — Consolidate docs, examples, fixtures and benchmarks.** Depends + 04,20–22. Move single-owner src/examples/tests local, retain real integration apps + at root, combine docs source and maintainer content without changing URLs. + Remove abandoned benchmarks and fixture frameworks only after caller review. + Update architecture documents and skills to actual new commands/contracts. + **Done:** docs build, relevant examples build/run, relative links resolve; + no old architecture is still labelled canonical after its replacement lands. +- [ ] **23a — Simplify the docs product and release freshness.** Depends 23,29a. + Local cleanup can start after 23; close the release/deploy integration after + 29a. Follow the docs review below: remove API-generation + coupling and docs-version scaffolding, retain useful written guides, and + define published-version lookup and Vercel deployment behavior. **Done:** + local docs tasks need no SDK build; each remaining input has an actual + consumer; release candidates cannot masquerade as published product versions; + guide updates reach oliphaunt.dev through a documented, retryable process. +- [ ] **30a — Re-audit docs against the final repository and principles.** + Depends 23a,29a. Run after implementation and before final acceptance task 30. + Re-read the final + docs manifests, task graph, release PR updater, CI and Vercel configuration. + Verify that later refactoring has not restored SDK compilation dependencies, + duplicated checks, version snapshots, hardcoded candidate-version drift, or + an independent docs release bureaucracy. Exercise local build and exported + links, representative affectedness, a product release and a docs-only update, + and failed-deployment recovery. Reuse existing meaningful checks and release + evidence; this is a completion review, not a new permanent meta-check suite. + **Done:** record evidence and unresolved limitations against the final state; + an earlier docs build or directory move alone does not close this task. + +### Phase F — predictable local checks and CI + +- [ ] **24 — Replace duplicated CI graph machinery.** Depends 05,21–22. + Reduce tools/graph to projecting Moon-selected tasks onto required runner + capabilities and artifact transfers. Move workflow behavior tests beside that + adapter. Keep stable required job names and correct skipped/failed behavior. + **Done:** representative changes select exactly required producers/consumers; + no path-regex second scheduler; downloaded qualified artifacts are consumed + without producer rebuilds; cold and warm runs have the same semantics. +- [ ] **24a — Define every PR/main event and comparison.** Depends 24. Cover + normal and fork PRs, release PRs, merge groups, main pushes, manual diagnostics + and PR closure. Bind the planned tree and checked-out tree to the same exact + revision. Use a valid immutable comparison base; handle shallow history, + initial/all-zero push bases, renames/deletions and generated changes. Separate + PR integration proof from release eligibility: PR-head success does not prove + a different merge SHA. **Done:** event tests cover base movement, fork PR, + merge-group revision, docs-only/empty selection and invalid comparison; no + accidental self-comparison or false-empty plan. Ordinary PR checks require + no release credentials, registry setup or publication-ready history. +- [ ] **24b — Make workflow execution and artifacts predictable.** Depends + 24a. Review all seven workflow files, local actions and .github/scripts; remove + duplicate builders between reusable workflows and parent jobs. Declare runner + setup at the narrowest task, isolate concurrent output directories, and keep + cache keys tied to actual compiler/target/input identities. Cancel superseded + PR work and make PR closure allocate no runners; avoid duplicate main-push and + manual qualification for one candidate. **Done:** cold/warm and concurrent + runs agree; failed/missing artifacts cannot appear successful; consumer jobs + never rebuild transferred producers; useful failure logs survive failure. + Source-failure checkpoint: producer jobs wait for source checks and tests; + downstream platform aggregates and consumers also reject failed ancestors, + while allowing intentionally unselected platform jobs to remain skipped. + This removes the observed missing-artifact cascades after source failures. + Offline Cargo consumers seed resolution from the candidate lockfile instead + of selecting newer registry versions; isolated locked-version caches pass. +- [ ] **24c — Migrate required checks and trust settings together.** Depends + 24a–24b. Inspect actual remote branch/ruleset settings, bot permissions, + protected release environments and trusted-publisher workflow identities. + Preserve read-only untrusted PR execution, isolate privileged publication, + and do not use elevated PR events to run untrusted source. Keep `Required` + stable unless an intentional settings migration is necessary. **Done:** + required jobs fail on failed/cancelled/missing selected work, accept only + intentionally unselected jobs, and do not wait forever on removed checks. + Prepare any necessary remote-setting change as a concrete cutover step; + deleting a local policy test does not silently weaken remote controls. +- [ ] **24d — Make Windows product orchestration Bash-based.** Depends 06,14, + 17,24b. Split build-postgres18-windows.ps1 and + package-liboliphaunt-windows-assets.ps1 by actual responsibilities, then move + shared orchestration to Bash and data processing to TypeScript. Retain the + supported MSVC target, Windows SDK, import libraries and VC runtime closure; + do not switch to MinGW/MSYS-linked products to simplify scripts. Initialize + Visual Studio once through its provided developer command launcher; prefer a + minimal cmd-to-Bash setup boundary over reimplementing the environment. + Remove the separate PowerShell build-time MSVC discovery path. **Done:** + native Windows build and clean packaged-consumer tests pass with no Bash, + Git/MSYS or WSL dependency for the end user; no new runtime DLL dependency. + Exercise spaces/Unicode paths, slash-prefixed compiler arguments, PATH tool + collisions, native exit codes and repeated setup. Any remaining setup-only + PowerShell shim must have an explicit necessary purpose and minimal scope. +- [ ] **24e — Split host-neutral work from native host proof.** Depends 24d, + 15–20. Inventory every Windows/macOS task and subcommand by its actual need: + native compiler/SDK, target execution, OS semantics, or portable processing. + Move portable packaging, metadata, checksums, archive/binary inspection and + release coordination to Linux. Keep native compilation/Apple SDK builds, + Windows/macOS runtime tests and simulator/device tests on their required + hosts. Package consumes finished outputs and never runs native smoke/initdb + implicitly. **Done:** narrow native producers feed Linux assembly/inspection, + followed by native consumer proof of the final package when needed; no OS + test is claimed complete because a binary parser succeeded. Local Linux + commands run the same portable logic, using explicitly supplied native + artifacts where required. No new mandatory cross-compilation project. +- [ ] **24f — Align local capabilities with hosted setup.** Depends 24e. + Remove GITHUB_ENV/ImageOS/ImageVersion requirements from ordinary local + toolchain selection and verification; CI adapters record hosted provenance. + Keep precise runner/toolchain pins for hosted release evidence. Distinguish + Windows/macOS execution, Apple SDK, Android SDK/KVM, compiler and packaging + capabilities in existing Moon metadata only where real tasks need them. + **Done:** a Linux maintainer can run all portable checks without pretending + to be GitHub Actions; unsupported native checks report their exact prerequisite; + command capability and resulting runner selection agree. A Windows/macOS + contributor can use locally installed supported tools without runner-image + variables. Sudo remains confined to explicit CI provisioning. +- [ ] **24g — Repair affectedness precision and missing setup edges.** Depends + 04–06,24,24f. Replace detached CI project allowlists and command-string + classification with declared task/project relationships. Localize broad + mixed-platform source groups and reference shared owners rather than duplicate + individual file lists. Declare actual setup/toolchain consumption for native + proof. Prefer ecosystem dependency inference where supported, but explicitly + declare cross-language inputs that cannot be inferred. **Done:** the probe + cases below select necessary consumers without unrelated target builds; a + new source file under an owned source directory is covered without editing a + whitelist; shared-input and setup changes cannot silently skip their consumers. + Exercise rename/deletion and exact Git-range selection as well as direct-file + probes. Inspect unowned changed files through existing graph diagnostics; + do not add a parallel permanent file-to-product classification database. +- [ ] **25 — Remove low-value and duplicate checks.** Depends 24g. Inventory + every task/test's failure it prevents. Delete source-spelling, document/task + existence and duplicate metadata assertions; retain behavioral tests around + data loss, package selection, invalid external inputs and publication. Run + source checks before expensive builds, consumer/device checks after outputs. + **Done:** one appropriate owner per guarantee; no release automatically runs + every benchmark/example/coverage job. Removed checks have recorded rationale. +- [ ] **25a — Justify and place every blocking check.** Depends 25. Make a + one-time review ledger of CI/release assertions: consequential failure caught, + owning project/task, actual inputs, earliest useful execution point and later + consumers of its result. Delete rules about incidental layout/source spelling + unless an actual external consumer requires that exact shape. Narrow real + package-shape checks to public archives/interfaces. Move example validation + to example tasks and source acquisition tests to source preparation owners. + **Done:** every retained blocking check has a meaningful failure and defined + task; workflow steps introduce no hidden product validation. Hosted-only gate, + credential and artifact-transfer operations remain small explicit CI adapters. + This ledger is migration review material, not a new permanent checker for + check ownership or a new test policy framework. +- [ ] **25b — Reuse proof at the right boundary.** Depends 25a,26a. Run source + formatting/lint/unit/tooling tests when their actual inputs change, before + expensive product work. Verify final package bytes after assembly. Publish + consumes these results for the frozen candidate and does not rerun repository + layout checks or all release-tool unit tests. Revalidate only facts that can + change after qualification, or bytes crossing a trust/transfer boundary. + **Done:** an execution trace shows each selected source check once; changing + an unrelated example cannot block an SDK publication; publishing reruns no + compiler/source suite; corrupted transferred artifacts and conflicting public + versions still fail. Do not infer evidence validity from a cache hit alone. +- [ ] **26 — Make release qualification product-scoped.** Depends 19–20,24g,25a. + Replace the unconditional all-platform manual gate with exact-candidate + qualification of selected products, required dependencies, affected consumer + compatibility and each selected product's declared target surface. Keep a + separately runnable exhaustive audit. Reuse unchanged published dependencies + by verified identity; don't accept arbitrary old green runs for changed code. + **Done:** SDK-only release does not rebuild unrelated src/runtimes/mobile apps; + runtime changes select dependent behavior; extension source changes retain + required same-run lifecycle evidence; missing selected target proof blocks + publication. Update qualify/release skills and branch protection expectations + together; their current all-target requirements describe the old contract. +- [ ] **26a — Bind artifact reuse to the release candidate.** Depends 26. + Extend existing candidate/qualification records rather than add a second + provenance system. Record selected products, exact candidate SHA/tree, + required tasks/targets, immutable artifact IDs/digests and producer run/attempt. + Distinguish source changes, unchanged published dependencies and envelope-only + changes. Cross-commit producer reuse requires verified unchanged producer + inputs/toolchain and compatibility, not merely a matching branch or version. + **Done:** stale/missing/mismatched/wrong-attempt evidence blocks release; + valid unchanged binary reuse avoids recompilation; package-consumer checks + still cover the final envelope. Preserve extension same-run evidence rules. + + **Reuse investigation:** pinned Moon 2.5.4 was exercised in a disposable Git + project with a real producer dependency. Unchanged task inputs across commits + retain the same hash; changing a declared compiler input changes it. However, + `--upstream none` records the dependency hash as literal `passthrough`, and + `cache: false` native compiler tasks have an empty last-run hash. System tasks + do not implicitly fingerprint OS, architecture or installed compiler versions. + Therefore a reusable receipt must reject empty/passthrough ancestry, bind the + actual target/compiler identity and the original immutable artifact/run/attempt, + and retain candidate-side consumer checks. An old task hash or published version + alone is insufficient. No cross-commit SHA check was relaxed. Before enabling + reuse, opt a concrete producer into complete native Moon hashing and receipt + capture; do not introduce a parallel file whitelist or accept cache presence as + qualification. The disposable proof is local evidence, not hosted qualification. + + **Portable producer receipt pilot:** the existing shared TypeScript query SDK + package job now records its complete Moon build/package hash ancestry, actual + Moon/Bun/TypeScript versions, whether execution ran or restored from CAS, and + the uploaded artifact's immutable ID, digest, size, source SHA and run attempt. + Qualified embeds that receipt in the existing candidate record. Missing, + failed, unhashed or passthrough chains report a non-reusable reason; candidate + validation rejects incomplete chains and wrong attempts. No alternate artifact + restore engine or cross-SHA downloader exception was added. The real package + build completed in 2.4 seconds and an unchanged repeat restored both tasks in + 175 milliseconds with identical hashes. Twelve receipt/candidate tests pass. + This pilots the existing Moon CAS path only: it does not prove native compiler + reuse, original execution provenance for arbitrary historical cache entries, + or hosted release qualification. + + **Product-scope checkpoint:** CI accepts `release_products_json` with known + stable product IDs. Moon owner tasks, downstream consumers and producer + dependencies determine selected builder tasks; source-check matrices use the + same scope. The existing qualification record binds product IDs, tasks and + candidate SHA, and publication rejects uncovered requested products. An empty + selection retains the exhaustive audit. Unpublished or selected producer + dependencies still run in the same candidate run; cross-commit binary + producer reuse is not implemented. + Generated same-repository Release PRs and merged main release commits now + derive the same selection from Release Please's actual manifest transition. + Main push writes qualification only after Plan and Required succeed; PRs + cannot create publishable evidence. Missing-run request/reuse is implemented + below; no hosted qualification has been claimed from local graph tests. + + **Native TypeScript published-dependency slice:** for a release selecting only + `oliphaunt-js`, existing npm publication lookup verifies the exact query, + Linux runtime, broker and addon pins and SHA-512 registry integrity. A complete + inventory selects the SDK's release-only consumer task and is retained in the + candidate plan. That task installs the newly packed SDK with those public + dependencies, checks Bun's resolved identities and integrity against the + inventory, and runs the existing Node/Bun/Deno native and server contracts. + Registry lookup uses the existing bounded retry/error behavior; an outage + cannot substitute current-tree bytes for unverified published dependencies. + Missing publications, incompatible inventory or mixed selected products keep + the ordinary producer chain. Normal PR affectedness and exhaustive audit + continue to select freshly produced dependencies. Actual Moon graph tests + prove six jobs reduce to three only with a complete inventory; installer + mutation checks reject wrong versions, changed integrity and private sources. + Current public inventory is incomplete, so a complete public-byte native + consumer run remains pending publication. Rust-only releases still reach real + mobile binding consumers and their artifact dependencies; that separation + remains unfinished. This slice does not close 26 or the native receipt work + in 26a. + Local evidence: disposable Git histories prove identical PR/main product + selection and rejection of an unknown manifest owner; 52 workflow/task-graph + tests pass, as do 20 candidate/matrix/gate tests, seven strict release-history + tests and four release-intent tests. The obsolete Cargo-only version scan + was removed from release intent; manifest transition ownership and canonical + package-version/publication validation remain at their existing seams. +- [ ] **26b — Remove the mandatory manual qualification ceremony.** Depends + 26a,27a. Final main-candidate qualification should run automatically for its + selected release scope. If publish finds required evidence absent, it can + request the existing CI workflow for that exact candidate and await it once, + before entering credential-bearing publication. Reuse an already running or + completed eligible run; fail with its causal log instead of an infinite wait. + **Done:** the maintainer needs prepare-release-pr, review/merge, then publish; + no obligatory separate full-qualification or dry-run dispatch. Missing + qualification never authorizes publishing, and publishers never compile. + + **Request/reuse checkpoint:** readonly planning inspects exact-source CI and + digest-verified product coverage. A small Actions-write job, with no cross-run + artifact consumption, dispatches missing qualification; readonly preparation + waits for and verifies the result. The request binds the candidate SHA and + sorted product set. Running causal work is reused; failed work reports its URL; + an ambiguous dispatch is not retried. The returned run ID and SHA are checked, + and CI checks the request binding before builders execute. Requests require + main to still equal the candidate: historical candidates must reuse or rerun + their existing exact-source run. The existing release concurrency group + serializes requests. Local three-phase fixtures cover reuse, active work, + absence, uncovered products, failed CI, advanced main, ambiguous dispatch and + a dispatch ref race. Fourteen waiter tests pass, including actual ZIP digest + and candidate coverage validation. Actionlint, zizmor and permission checks + pass; no hosted dispatch or publication was performed. Cross-commit reuse and + final hosted qualification remain open, so this checklist item stays open. + +### Phase G — release and bootstrap simplification + +Implementation checkpoint: candidate preparation no longer calls the overloaded +`release-dry-run.sh` wrapper. Its qualification-record and registry checks were +duplicates of earlier steps in the same job; those earlier checks remain. The +separate clean exact-source check remains immediately before carrier assembly, +and publication still rechecks mutable registry state at its mutation boundary. +The wrapper never generated packages: local equivalents are the existing +release metadata/tool-test command and selected registry preflight, with owner +package/artifact tasks for actual package rehearsal. Removed the wrapper's +routing-only fixture and obsolete hosted-only argument; exact SHA, dirty-tree, +index-suppression and frozen-candidate behavior tests remain. The historical +`release-dry-run` environment name is retained; no remote environment migration +or publication operation was performed. +Validation: the full workflow aggregate passes, and eight focused source-state +and CLI tests pass. The release mutation aggregate ran 532 tests: 531 passed; +the sole failure was an old ICU-owner expectation left after the resources move. +That expectation was corrected to the actual independent resources owner and +its complete seven-test publication-plan file passes. This does not complete +product-scoped qualification or automatic qualification dispatch (26–26b). + +- [ ] **27 — Make version preparation converge once.** Depends 23,27b,27c,27d. + Use Release Please as the candidate version authority. + Remove independent mirrored + version authorities and unnecessary string surgery. Use native manifest + versions where supported; derive unavoidable carriers/POM/podspec fields. + Shared source bundled into a consumer must select that consumer for release; + ordinary independent dependency edges alone must not bump every consumer. + **Done:** prepare twice produces no second diff; locks/dependencies resolve; + new resources/query/server products are modeled once; a metadata-only release + does not recompile unchanged PostgreSQL/WASIX artifacts without need. + **Implemented:** one pinned Release Please candidate authority and a derived + compatibility/lock closer; local repeat preparation and source-package + transition tests pass. Task 27c's deliberately different product-version + consumer proof is complete. **Remaining:** 27d's reviewed candidate product + notes and the native reuse acceptance tracked in 26–26a. +- [ ] **27a — Make the entire release-PR lifecycle converge.** Depends 27,24a. + Cover creation, repeat preparation, new main commits, dependency/lock updates, + PR conflicts, closed-unmerged/reopened PRs and merged-but-unpublished releases. + Retain only necessary normalization; do not require an exact commit count for + aesthetics. Ensure the bot's final update actually triggers required CI and + obsolete raw/generated heads do not launch duplicate heavy qualification. + Reconcile `autorelease: pending`/`tagged` only against verified publication. + **Done:** preparation has one stable final tree; no-op prepare neither pushes + nor restarts CI; no releasable changes creates no PR; main movement cannot + overwrite unrelated edits; merged release PRs cannot be lost or marked + published prematurely. Update release-intent checks for moved/new products. + **Local proof:** disposable Git/PR fixtures cover no-op SHA reuse, main movement, + lost-response recovery, reserved-branch conflicts and pending publication; the + full release aggregate passes. **Remaining:** hosted bot-token creation/update, + closed/reopened PR handling and proof that only the final candidate triggers + the configured required checks. No remote mutation has been performed. +- [x] **27b — Verify the retained Release Please integration.** Depends + 02a. Before structural moves, verify the minimal retained configuration with + representative Rust, TypeScript, Swift, Gradle, runtime-carrier and shared-source + updates using disposable inputs. Consult + the pinned action's actual bundled implementation, not only latest upstream + docs. Evaluate workspace plugins against independent-release semantics rather + than blindly enabling dependent bumps. **Done:** one authority for + candidate versions/notes; no two independent engines editing the same version + or changelog; shared source selects the correct released consumers. A + source-bound compatibility closer may derive fields but never choose an + independent version or write a second changelog. A demonstrated blocker is + reported with a minimal reproduction; do not silently introduce another engine. + **Verified locally:** the pinned Release Please library handles Rust/npm/Swift/ + Gradle updates, shared shipped-source selection and repeat output. The separate + contrib bump/changelog engine is deleted; the closer only derives compatibility + and lock fields. Actual library and disposable Git lifecycle tests pass. +- [x] **27c — Remove live-version literals and prove version transitions.** + Depends 07–20,27b. Inventory every version-bearing manifest, generated file, + source constant, example, test and public install snippet. Classify product + version, dependency compatibility, immutable upstream pin, protocol/data + schema, historical fixture or synthetic fixture. Generate package-internal + version constants from the authoritative manifest; consume candidate metadata + in live consumer checks. Keep intentionally independent fixture expectations. + Prefer native lock regeneration over text surgery where compatible with the + staged publication graph. **Done:** a disposable representative release bump + uses deliberately different SDK/runtime/extension/resource versions, runs + actual affected tests and package consumers, and prepares twice with no + second diff. Wrong-version negative tests still fail. Do not update all + numbers by regex or derive both actual and expected from the same helper. + **Verified locally:** a disposable pinned Release Please candidate used TS + SDK 2.3.4, native runtime 3.4.5, pgTAP packaging 4.5.6 and ICU resources 5.6.7. + Actual installed packages passed SQL, pgTAP and ICU operations on Node 22, + Bun 1.4.2 and Deno 2.8.1. A Cargo consumer compiled the 2.4.6 build helper + with runtime 3.4.5 and independently versioned tools 0.2.1. Repeated metadata + and lock preparation produced identical Git trees; repository versions were + unchanged. Existing wrong-version and failed-transition checks remain. + The rehearsal fixed Linux-only extension staging unnecessarily requiring + Apple metadata, and the SDK rejecting Bun's ordinary 0664 license-file mode. + Full meta carriers still require their Apple records; license digests and + unsafe executable/special/world-writable mode rejection remain. This is a + representative Linux consumer proof, not multi-platform publication. +- [ ] **27d — Fix product changelog ownership and relevance.** Depends 27b. + Preserve existing published history and identify inaccurate existing entries + explicitly. New release notes describe product-visible behavior and scoped + dependency changes, not arbitrary shared commit bodies or CI churn. Review + multi-product/breaking changes per product. **Done:** one changelog per real + release product, no per-carrier/contrib-member changelogs; Swift/vector notes + do not inherit unrelated browser/Rust storage warnings. A cross-product + change has accurate product-specific notes and correct version impact. + Prefer a reviewed release-PR editorial step or supported tooling over a + custom semantic changelog classifier or regex assertions of prose. + **Implemented:** release products own changelogs and Release Please is the sole + candidate version-note writer. All 27 owner/config/history mappings were reviewed; + each has one changelog and there are no extra carrier/contrib-member changelogs. + Four newly extracted products label their working notes Unreleased instead of + implying publication. The copied Rust WASIX/browser storage warning was removed + from 17 unrelated owners' current changelogs; the two affected SDKs retain it. + This editorial correction changes no other notes, headers, dates or commit links, + and leaves immutable historical tags and published release assets untouched. + **Remaining:** editorial review of the actual cross-product release candidate's + product-specific notes and version impact. No semantic prose-checking engine. +- [ ] **28 — Shrink candidate assembly and publication.** Depends 25b,26b,27a. + Preserve existing prepare-release-pr/publish operations. Publish stages one + candidate from producer outputs with eligible producer evidence, freezes exact + package bytes, qualifies those packages, then publishes in dependency order, + verifies public consumers and promotes last. Follow the sequence below; never + treat producer proof as final-package qualification. Remove duplicate + dry-run/preparation/check layers only after tracing all callers. **Done:** + no routine manual dry-run/bootstrap chain, no compiler in publication, and + all ecosystem carriers derive from the same staged verified bytes. + **Local proof:** preparation consumes qualified outputs on Linux without Rust + or Apple/Android toolchains, freezes exact bytes and preserves dependency-order + publication. Duplicate dry-run and setup layers are removed; the complete + release aggregate passes. **Remaining:** final selected-product qualification + and public distribution/visibility evidence in 26b/28a; no hosted publication + is inferred from local transport fixtures. +- [ ] **28a — Finish distribution and release finalization boundaries.** + Depends 28,26b,27a. Keep source package tags, binary GitHub assets, npm tags, + Cargo dependencies and Maven visibility coherent with the selected candidate. + Explicitly resolve SwiftPM's source-tag/binary-asset availability order; draft + assets must not be treated as anonymously downloadable. Stage required + headers/notices/checksums and preserve consumer selection for the new products. + **Done:** every declared registry entry installs from a clean consumer when + advertised available; no dependency points at an unpublished version; a + partial public release is reported accurately and final PR labels/promotion + happen only after their required evidence. Registry publication remains + resumable, not an invented all-registry atomic transaction. +- [ ] **29 — Simplify bootstrap and retry without losing recovery.** Depends + 28a. Retain conditional first-name bootstrap already present. Audit the 169 + release-tool files and both normal/bootstrap state machines for duplicate + ledgers, transport wrappers, speculative pacing and rechecks. Keep registry + authentication, immutable byte reconciliation, dependency ordering, valid + Retry-After handling and necessary interruption state. **Done:** fault tests + cover no-op rerun, partial success, ambiguous upload and conflicting public + bytes; only missing exact versions upload; mismatch stops; scoped credentials + are used only for required missing identities. Do not promise atomic + publication across independent registries or remove checkpoints blindly. + **Local proof:** conditional missing-name bootstrap, no-op/partial-success + recovery, ambiguous uploads, conflicting public bytes, dependency ordering and + credential isolation pass the complete release aggregate. M06's bounded state + has separate concurrency/recovery proof. **Remaining:** 29a's final retention + and hosted recovery cutover. +- [ ] **29a — Define retention, main movement and recovery cutover.** Depends + 29,28a. Keep the candidate immutable after any public mutation. Document the + supported rerun window and retain candidate/lock/receipts for that window; + expired evidence is an explicit stop, never permission to rebuild different + bytes under an existing version. Preserve distinction between product fixes + requiring a new version and publication-controller fixes using an unchanged + approved candidate. **Done:** retry after main advances, credentials expire, + artifacts disappear, or a final promotion fails is deterministic; concurrent + release dispatches cannot replace the active candidate. First-name bootstrap + followed by ordinary trusted publication is covered, including newly created + carrier names, exact publisher identities and credential cleanup. + +### Phase H — close the gap with actual evidence + +- [ ] **30 — Run the migration acceptance matrix.** Depends 29a,30a and all + preceding implementation tasks/dispositions in the execution order below. + Use the + matrix below, first local/targeted, then hosted platform proof. Record outputs, + graph closures, elapsed time, artifact sizes, compiler invocations and repeat + behavior. **Done:** both baseline CI defects are fixed and verified, all + retained products/functions have evidence, no unaccounted source domain or + carrier is left behind, documentation matches actual commands, and the final + exact commit passes the new required qualification contract. Report any + unavailable device/registry proof as incomplete, never inferred green. + +## Execution order and prerequisites + +This table is the authoritative prerequisite order. Task numbers identify scope; +their numeric order alone is not a schedule. A range in descriptive prose means +numbered tasks only, never an implicit dependency on all their lettered follow-ups. +The early 27b checkpoint exercises existing configuration with disposable inputs; +the final post-move version transition is proven by 27c/27. M01–M18 close with +their linked owner tasks and are all reviewed by 30. No dependency points from +implementation back to final acceptance. This is a planning table, not a runner. + +| Task | Prerequisites | +| --- | --- | +| 01 | none | +| 02 | 01 | +| 02a | 02 | +| 03 | 01 | +| 27b | 02a | +| 04 | 02a,27b | +| 06b | 04 | +| 05 | 04,06b | +| 06 | 04 | +| 07 | 05 | +| 08 | 05 | +| 09 | 07 | +| 09a | 09 | +| 09c | 09 | +| 09d | 09c,18,19 | +| 10a | 09,11 | +| 10 | 09,10a | +| 10b | 10 | +| 11 | 07 | +| 12 | 03,05,06 | +| 13 | 06 | +| 14 | 05,06 | +| 11a | 14 | +| 15 | 06,14 | +| 16 | 15 | +| 17 | 16 | +| 18 | 17 | +| 19 | 04,16,17 | +| 09b | 09a,18,19 | +| 20a | 03,08,09d | +| 20 | 03,08,09b,09d,20a,18,19 | +| 21 | 07,08,09,10,10b,11,11a,12,13,14,15,16,17,18,19,20 | +| 22 | 21 | +| 23 | 04,20,22 | +| 24 | 05,21,22 | +| 24a | 24 | +| 24b | 24a | +| 24c | 24a,24b | +| 24d | 06,14,17,24b | +| 24e | 15,16,17,18,19,20,24d | +| 24f | 24e | +| 24g | 05,06,24,24f | +| 25 | 24g | +| 25a | 25 | +| 26 | 19,20,24g,25a | +| 26a | 26 | +| 25b | 25a,26a | +| 27c | 07,08,09,10,11,12,13,14,15,16,17,18,19,20,27b | +| 27d | 27b | +| 27 | 23,27b,27c,27d | +| 27a | 27,24a | +| 26b | 26a,27a | +| 28 | 25b,26b,27a | +| 28a | 28,26b,27a | +| 29 | 28a | +| 29a | 29,28a | +| 23a | 23,29a | +| 30a | 23a,29a | +| 30 | 24c,25b,29a,30a | + +The listed transitive closure covers every numbered task. Work independent of +an unfinished prerequisite may be prepared early, but the task cannot close +until its full contract and prerequisite evidence exist. Local docs cleanup can +begin after 23; 23a closes only after release/deployment integration is verified. +Remote setting changes and public publication remain separate explicitly +authorized operations during implementation, not actions performed for this plan. + +## Exact release and qualification sequence + +The same product tasks serve local development, PR checks and release work. +Qualification is an aggregation of applicable evidence, not a new test suite. +Use existing candidate records; do not implement a second provenance platform. + +1. **Prepare the release PR.** Release Please selects product versions and + notes. The narrow closer derives compatibility fields, carrier versions and + native locks once. No-change preparation exits before platform setup. The + final PR tree receives affected checks; public versions remain unchanged. +2. **Fix the merged candidate identity.** On merge, record the exact SHA/tree, + selected products, dependency versions and declared target surface. A PR head + is not a substitute for this merge. Unchanged published dependencies retain + their verified identities; a newly selected dependency must be produced. +3. **Run applicable source checks and producers.** Reuse eligible evidence for + unchanged inputs; build missing outputs through the declared project graph. + Run actual producer ABI/runtime checks where needed. These results alone do + not establish that a final registry package is usable. +4. **Assemble the final packages.** Owning package tasks consume producer outputs + and create Cargo/npm/Maven/Swift/GitHub distributions, resources, headers and + notices. Apply any required payload-changing signing before freezing. Pure + packaging runs on Linux where possible; necessary native signing stays on + its required host. Unpublished sibling candidates use a narrow local + dependency source/overlay for testing, never an accidental public fallback. +5. **Freeze the candidate bytes.** Record exact files/digests, versions, + dependencies and target identity. The complete candidate is immutable from + here. Registry envelopes must already be prepared; any registry-mandated + transformation needs a defined ecosystem integrity comparison. No uncontrolled + repacking or modification may occur between package tests and upload. +6. **Qualify those packages.** Install the frozen packages in clean consumers; + test the applicable browser/device/native surfaces with those payloads. + Consumer compilation is legitimate here; rebuilding the frozen runtime or + SDK package is not. Bind successful source/producer/package evidence to the + exact candidate and its required targets. Failure blocks publication. If + package bytes change, form a new pre-publication candidate and repeat affected + checks; never relabel old results as proof of different bytes. +7. **Publish the qualified bytes.** The publish operation requests or reuses + missing exact-candidate CI before entering mutation. Protected upload jobs + only reconcile remote state and upload absent matching artifacts in dependency + order. Conditional first-name bootstrap uses these same bytes. Authentication, + current remote availability and conflicting versions are checked at mutation; + source/compiler/whole-repo suites are not replayed inside publishers. When + dependent packages require public GitHub binary URLs, expose frozen assets + through a public prerelease before uploading those dependent packages. That + is already irreversible public state and follows the same reconciliation + rules. Draft URLs are never treated as anonymously downloadable dependencies. +8. **Verify public resolution and finalize.** Separate small consumer jobs may + compile a fresh application to prove real registry resolution. They never + rebuild packages to publish. For SwiftPM, the assets exposed in step 7 must + precede dependent source-tag/manifest availability. Verify the public prerelease + mechanism against actual GitHub/Swift behavior in 28a. Finalize notes/labels/stable promotion + only after required public-consumer evidence. Registry-specific automatic + tags/visibility mean there is no all-registry atomic visibility promise. +9. **Refresh docs independently.** After completed product publication, refresh + published-version inputs and request the docs deployment once for the release + operation. A docs failure is reported/retried separately and never republishes + packages or falsely marks their publication incomplete. + +If interrupted after any public mutation, keep the same candidate; reconcile +and skip matching versions, upload only missing versions, and stop on conflict. +Use the existing 90-day retained-candidate window as the initial recovery +contract; expired or missing evidence requires explicit recovery investigation, +never a rebuild under an already-public version. A product fix requires a new +version. A controller-only fix records its own execution identity while retaining +the approved product candidate. Concurrent release attempts cannot substitute +each other's candidate or checkpoint. + +Public consumer compilation in step 8 is verification with read-only credentials, +separate from step 7 upload jobs. This resolves the distinction between +compiler-free publication and proving that a real consumer can install packages. +Local no-upload rehearsal covers steps 1–6 using disposable version inputs and +appropriate native artifacts; it is optional and is not another mandatory +maintainer dispatch between preparing the PR and publishing. + +## Native Rust / Node / Bun / Deno consolidation + +Decision: viable and included in 09,09a,09b. Use the existing napi-rs approach +for the native addon and remove duplicate C++/Deno FFI maintenance after parity +proof. This is an architectural decision with implementation acceptance gates; +the replacement has not been written or qualified. No additional user decision +is needed for the documented Deno npm/Node-API installation requirement. + +Evidence from the current source: + +| Current implementation | What it establishes / required change | +| --- | --- | +| `src/sdks/js/src/native/default.ts` | Bun already selects the Node addon; Deno alone selects a separate FFI implementation | +| `src/runtimes/wasix-napi/Cargo.toml`, `src/lib.rs` | Existing Rust cdylib uses napi 3.12.2, napi-derive 3.6.3, napi-build 2.4.1 and Node-API 8; this toolchain is already a repo dependency | +| Native `oliphaunt_node.cc` (2,444 lines at review) | Library loading, raw C operations, request bridges, generation-aware handles, worker/environment teardown; replace with shared Rust operations plus a small JS boundary, not a line-for-line translation | +| `native/deno.ts` (540 lines), `ffi-layout.ts` (143) | Separate symbols, pointers, packed structs, nonblocking FFI, callback/error/free-response and cleanup logic; remove after common addon parity | +| `native/assets-deno.ts` (534 lines) | Separate package/asset resolver also used by broker and server; migrate every caller, not just direct mode | +| Rust `liboliphaunt/ffi.rs` and `mod.rs` | Captured operation errors, retained library lifetime, handle locking and logical detach exist; generation-safe environment cleanup is not yet the same contract as the Node/Deno paths | +| WASIX integration `smoke-node.sh` and `verify-host.mts` | Existing packed Node/Bun/Deno/Electron host harness provides a starting point; do not add a second unrelated test-runner framework | + +Local viability probe on Linux x64: the same existing +`target/oliphaunt-wasix-napi/prebuilds/linux-x64-gnu/oliphaunt_wasix_napi.node` +loaded successfully under Node **22.22.3**, Bun **1.4.2** and Deno **2.8.1**. +Each opened a standard in-memory database through NativeWasixActorDatabase, +executed `SELECT 42::int AS answer`, validated the PostgreSQL DataRow and +ReadyForQuery messages, awaited close and exited successfully. The binary's +SHA-256 was `950a6f8f6904ce0262387d53d5ee6587d577d66110fe68019a7f498ae6f56abd`. +Shell invoked a disposable `/tmp/oliphaunt-napi-viability.mts` using each pinned +executable and a 40-second timeout. Deno used `--no-config --allow-env --allow-read +--allow-ffi`; no network access was needed. No addon or runtime was rebuilt. + +This proves a working Rust Node-API path through all three installed hosts, +including promises and byte-buffer results. It does not prove native-runtime +parity, npm installation, worker termination, unsupported/older host versions, +or Windows/macOS correctness. The pre-existing artifact's build provenance was +not requalified. Do not mark 09a/09b complete using this probe alone. + +Target responsibilities: + +- Shared bindings own C ABI access, runtime/session lifetimes, native operation + error capture, cancellation, raw request/stream completion, backup/restore and + safe close/reopen. Resource preparation is consumed through the resource + project's contract; package-manager discovery is not moved into Rust. +- Node addon owns JS argument/result conversion, asynchronous completion, + streaming delivery and environment cleanup. Keep blocking database work off + the JS thread and cancellation available during it. Reuse proven napi-rs + facilities; do not recreate the C++ threadsafe-function implementation in Rust + or create multiple stacked executors merely to settle promises. +- C runtime remains authoritative for process-global lifecycle. Multiple Node + workers/addon instances must not gain conflicting ownership because each Rust + library image has its own static state. A stale finalizer cannot close a newer + generation; teardown cannot unload code while threads/callbacks can execute it. + Rust bindings must expose the narrow lifecycle operations needed to prove this. +- Node/Bun/Deno use one native package loader and normal node: module/filesystem + APIs. Unify resource selection and validation across direct/broker/server + callers. Preserve explicit path/PGDATA overrides and corruption checks. Remove + Deno-only restrictions on automatic extension assembly only after the common + path demonstrates it; do not advertise new support based on removing a guard. +- Broker/server remain TypeScript process/socket clients with no addon required + to launch the executable. Direct executable spawn is product functionality; + invoking Shell scripts from TS for build/test orchestration remains prohibited. +- Rust callers use the bindings crate directly and acquire no napi/JS runtime + dependency. Swift/Kotlin/RN retain their platform-native C integration. Browser + still uses the Rust/WASM browser host. Native and WASIX addons stay separate; + reuse small proven Promise/byte/error helpers only if it reduces total code. + Query APIs remain ecosystem-owned; routing every query through Rust would make + src/broker/browser consumers unnecessarily depend on a native addon. + +Required cutover evidence (extend existing tests at their meaningful boundaries): + +| Boundary | Acceptance | +| --- | --- | +| Operations | Parameter/result/error parity, raw streaming, callback exception recovery, backup/restore, persistence, close/reopen and existing initialization safety | +| Concurrency/lifetime | Timers remain responsive during a long query; out-of-band cancellation completes; concurrent close/cancel and worker termination during pending operation/stream do not deadlock, crash or call into a destroyed JS environment | +| Ownership | Forgotten handle recovery, stale generation token and later reopen; process-global direct admission, library pinning, callback buffer lifetime and response freeing remain correct | +| Native consumers | Same final target addon under pinned Node/Bun/Deno, supported minimum versions and relevant Electron embedding; Linux x64/arm64, macOS arm64 and Windows x64 MSVC | +| Installation | Clean npm/pnpm/Deno consumers select correct target and versions; Deno local node_modules and --allow-ffi are explicit; required read/write/env/run/net permissions follow actual chosen operations, with no blanket -A requirement | +| Distribution | Prebuilt addon; no consumer Rust/C++ compiler, Shell setup, header download or postinstall build; correct DLL/shared-library closure and ABI floors; default resources remain absent | +| Independent modes | Broker/server can run with the direct addon omitted; a missing direct addon fails clearly; no fallback to old Deno FFI or a different topology | +| Cost | Record old/new maintained adapter code/dependencies and target build/installed size; compare basic query/startup behavior and long-query responsiveness. No claimed deletion or performance win solely from changing language | + +CI/release integration: compile one native addon per OS/architecture/ABI, then +reuse that exact file across host tests; do not build separate Node/Bun/Deno +variants. Pure TS query changes do not rebuild the addon. Bindings changes select +Rust/src/broker/addon compatibility checks and releases of binaries that embed the +changed Rust code. Normal published Rust dependency edges do not automatically +bump every SDK; an explicit SDK dependency upgrade selects that SDK. The existing +oliphaunt-node-direct release owner/npm carrier names remain, with one canonical +package version and derived private Cargo version; no new public addon crate. +Final-package host tests occur after candidate freezing and before publication. +Update Moon inputs, Cargo locks, producer actions, notices, release preparation, +consumer fixtures and docs together. Delete old C++ build/header-fetch commands, +Deno FFI exports and exclusive tests only after their last callers and necessary +guarantees have moved. An incompatible host result is a blocking implementation +finding, not permission to silently retain two permanent backends or drop support. + +Primary references: [Deno Node-API requirements](https://docs.deno.com/runtime/fundamentals/node/) +and [Bun Node-API support](https://bun.sh/docs/runtime/node-api). These document +the supported mechanism; the concrete repo-version Linux probe provides narrower +execution evidence. Recheck exact napi-rs/host capabilities when implementing +cleanup behavior rather than assuming nominal Node-API support proves parity. + +## Additional machinery dispositions + +Status: incorporated after the source review and the user's broad agreement. +These are planned dispositions, not completed changes or blanket approval of +every replacement choice. Verify the remaining choices against actual callers, +platform support and consumer behavior before selecting an implementation. +Use the established task order; remove obsolete tests with their mechanisms. + +- [x] **M01 — Local hooks (05,25).** Keep optional cheap correctness/security + checks; scope formatting to owning projects and reuse their commands. Root + prek is already local-only; do not add a hosted all-hooks gate. Review commit + conventions against the actual squash/release input. **Done:** unrelated + changes do not run global format suites; useful local checks remain available. +- [ ] **M02 — Dependency updates (06,24,27).** Keep Renovate, group only actual + coordinated dependencies, and consolidate version/digest authorities. Use + native managers first; custom pin updates must update all required hashes + coherently. **Done:** representative ordinary and special-tool updates resolve + and select appropriate checks; no half-updated pin or unrelated ecosystem + failure blocks an independent update. + **Checkpoint:** removed the Moon/Node version-only Renovate managers: they + changed `.prototools` without the installers' verified archive manifests. + Tool updates remain explicit coherent version/digest changes; native ecosystem + managers remain enabled. Broad per-ecosystem groups and the unused Python + manager were removed; only coordinated React and Node-API packages are grouped. + Representative update qualification remains outstanding. +- [ ] **M03 — Tool installation (06,22).** Replace ordinary custom installers + with existing Moon/proto or ecosystem mechanisms where supported. Retain + narrow verified installation for special toolchains. Remove upstream README + inventory contracts and redundant installation receipts; preserve download + integrity and safe interrupted installation. **Done:** clean/repeated/failed + setup works on supported hosts, installs only requested prerequisites, and + uses the same underlying mechanism locally and in CI. + **Checkpoint:** Moon, Node, Bun and Deno installation versions now come only + from `.prototools`; verified asset manifests retain URLs, hashes, sizes and + executable metadata, without another version field. Composite setup actions + and workflow callers no longer repeat those pins. Installers still reject + mismatched URLs or executable versions and corrupted payloads. Native Node, + Moon and Bun/Deno installer fault suites pass, and the real cached Node, Bun + and Moon binaries pass verification with downloads disabled. Root Bun + `packageManager`/`engines` remain ecosystem declarations. Supported-host + installation qualification and broader installer simplification remain open. +- [x] **M04 — Machinery tests (21,22,25).** Retain tests for corrupt inputs, + failed extraction, partial publication and conflicting public bytes. Delete + source-layout, duplicate-copy and obsolete receipt-protocol assertions with + their owners. Localize fixtures; share only proven multiple-consumer helpers. + **Done:** surviving tests exercise consequential behavior at its owner; + removed helpers have no callers and no orphan fixture framework remains. + **Completed locally:** generic policy/test projects and orphan wrappers are + removed; fixture helpers live with their owner or the shared archive layer. + Release, packaging, SDK-carrier and source-fetch suites retain actual corrupt + bytes, unsafe paths, failed promotion, retry and publication conflict checks. +- [ ] **M05 — Consumer workspaces (15–20,23,25).** Remove host-runtime builds, + seed normalization and permission repair from Expo/test setup. Consume declared + producer outputs. Separate normal workspace integration from clean packaged + consumers; the latter cannot borrow checkout node_modules. **Done:** candidate + installation uses locked external dependencies, missing package dependencies + fail, and repeated tests neither mutate source nor silently resolve new inputs. +- [x] **M06 — GitHub transport state (28,29).** Consolidate request ownership + before removing cross-process pacing. Retain bounded retries, server-directed + backoff and publication recovery; reduce persistent per-request histories, + arbitrary budgets and repeated reads. **Done:** throttling and interruption + recover predictably; concurrent callers remain coordinated; public artifact + reconciliation does not depend on a verbose request-history protocol. + **Implemented:** content pacing stores only the latest slot/sequence; core + accounting stores at most 900 timestamps within its rolling hour and a total + sequence. Production callers require no full history. Existing process locks, + atomic replacement, lineage checks and deadline/retry behavior remain; expired + attempts are removed on reservation. Five-process reservation/upload tests and + read/mutation reconciliation tests pass. These runner-temporary schemas reject + incompatible/corrupt state rather than silently resetting admission accounting. +- [ ] **M07 — Repository-controls audit (24,29).** Keep minimal setup diagnostics + for publication trust, permissions and necessary environments; prefer native + GitHub enforcement. Remove unnecessary custom governance rules. The current + audit was found as a maintainer setup tool, not established as an every-release + gate. **Done:** actionable setup failures remain visible without introducing + a second release-policy engine or weakening credential/ref boundaries. + **Read-only checkpoint, 2026-09-14:** the existing collector confirms classic + `main` protection with strict `Required`, squash-only linear history, resolved + conversations, no force-push/deletion or actor-specific bypass, and read-only + default Actions permissions. No rulesets or repository secrets are configured; + all four release environments allow only the `main` branch. Both registry + bootstrap secret names are still present, so neither idle nor retired is + established; imminent lock-scoped readiness has not been verified. No secret + values or remote settings were changed. Current main `f4b7a5c7` has successful + `Required` in run `34247055051`, but `Qualified` was skipped. The historical + published lock from run `34249155596` belongs to source `bfa867aa` and the old + catalog; current tooling correctly rejects it as a current candidate lock. + Lock-scoped registry trust audit and final-candidate qualification remain open. +- [ ] **M08 — Notices (19–22,28).** Derive shipped notices from locked target + dependencies and pinned sources, with explicit exceptions only where metadata + is insufficient. Package and verify them at their producer. Reduce duplicate + license inventories and filename/version/mode ceremony. **Done:** actual + distributions retain required notice contents; canonical archive modes have + one owner and source-only checks do not fetch every target unnecessarily. + Cargo audit checkpoint: an isolated cold-cache proof showed that scoped + `cargo tree` fetches only the selected dependency closure but omits registry + source paths; filtered `cargo metadata` still fetches unrelated workspace + dependencies, while `--no-deps` omits required registry metadata. Retain full + metadata acquisition for actual source-license and VCS-provenance verification; + no custom Cargo-cache locator or synthetic workspace mechanism was added. +- [ ] **M09 — Cargo build scripts (07,09,15–17,22).** Remove query-source copying + through real crate dependencies. Retain necessary linking and artifact metadata + propagation until a working replacement exists. Remove published-package + fallbacks to the surrounding checkout. Replace generated handwritten hashing + with an established implementation where hashing remains necessary. **Done:** + clean published consumers work with declared dependencies and no hidden runtime + producer build; required payload integrity checks still reject corruption. + Carrier checkpoint: packaged WASIX runtime, PostgreSQL-tool and ICU crates use a + strict package-local build entrypoint. Missing payloads or declared AOT files + fail even when environment overrides and ancestor checkouts contain usable + alternatives. Source builds retain lightweight checks and explicit local + inputs. Five extracted carrier-family proofs and source-carrier Clippy checks + pass; actual Moon queries propagate support changes to SDK consumers without + selecting PostgreSQL compilation. Fixtures acquire their own standalone Cargo + closure from workspace lock versions before locked offline assertions; an + empty Cargo cache and subsequent entirely offline repeat both pass. + Generated native/WASIX extension carriers now use `sha2` instead of handwritten + SHA-256 rounds. Extracted split/unsplit Cargo consumers compile, native payload + hashes match an independent implementation, and modified WASIX chunks fail + digest validation. Unrelated native linking and metadata propagation remain. +- [ ] **M10 — Source packages and splitting (16,20,22,27,28).** Prefer native + package commands and one source manifest authority. Resolve unpublished sibling + candidate dependencies explicitly before deleting staging transformations; + cargo --no-verify alone is not a solution. Keep size-driven splitting and + required Swift public manifests only where demonstrated necessary. **Done:** + clean consumers use the tested frozen package bytes; no shadow SDK definition + or unnecessary carrier layer remains. + **Implemented:** ordinary Bun/Cargo source packaging and explicit unpublished + sibling candidate closure; binary carriers no longer invoke Cargo during + central assembly. Frozen-byte and clean local consumer tests pass. + **Remaining:** final Apple/mobile and public-registry consumer closure for the + selected frozen candidate; keep only demonstrated size/root-SwiftPM exceptions. +- [ ] **M11 — Archives/filesystems (21,22,28).** Prefer native Shell packaging + tools for producers and suitable existing ecosystem libraries for consumer + extraction. Review platform support before choosing replacements. Keep thin + trust-boundary validation and safe extraction. **Done:** corrupt/traversing/ + unsafe-link archives fail without damaging existing data; required consumers + gain no new platform-shell dependency; custom format code is minimized. + Archive checkpoint: retain the streaming ZIP64 type validator used by GitHub + artifact downloads; the sparse >4GiB test and clean-checkout downloader suite + cover this separate large-archive boundary. Other consumers retain the full + bounded archive parser. + ZIP production and validation use the existing `node:zlib.crc32` implementation + instead of two handwritten CRC loops. Existing corruption/traversal, + executable-mode, empty-directory and extraction-preservation tests pass. + A wholesale `Bun.Archive` producer substitution is not proven: the current + API probe writes an empty-directory key as a regular file and defaults to + current timestamps and non-executable modes. + Swift resolver and React Native iOS stager checkpoint: extraction now validates + once in private staging; + rejected replacements preserve the existing output and tree manifest. Removed + its redundant archive inventory pass, retaining actual extracted-tree hashes + for cache validation. The bootstrap capsule reuses the existing tar-header + writer without changing its streaming payload or canonical-byte contract. + Swift and React Native hostile-archive/cache/consumer tests and capsule + integrity/repeat tests pass; + 24 old/new header comparisons are byte-identical. This does not claim atomic + directory-plus-manifest publication across forced crashes or concurrent writers. + Extension bundle qualification now checks the actual mobile consumer subset: + regular 0644 files, POSIX ustar, a single gzip stream without optional header + sections, bounded safe members and an exact two-block terminator. Removed full + tar-byte reconstruction and its duplicate encoder; archive hashes still freeze + exact release bytes, and producer tests retain deterministic output. Different + gzip OS metadata, valid owner names and file order are accepted by the real + consumers and no longer fail qualification. Nested extension leaf contracts + remain unchanged. +- [ ] **M12 — WASIX export sealing (13,22,25).** Keep Rust binary analysis and + required dynamic-linkage/ABI checks. Remove the requirement that DCE must remove + at least one function/global; a justified size budget is a separate concern. + Prefer completed immutable output generations over live-prefix transaction + machinery. Migrate executor receipt consumers with the producer; choose a + promotion mechanism that works on each host. **Done:** actual extension loading + passes and interrupted publication exposes no mixed bundle; unchanged-size + valid binaries do not fail correctness qualification. + **Implemented and proven locally:** private PostgreSQL build/sealing followed + by whole-prefix content-addressed publication and atomic selection replaces + live-prefix rollback journals. Existing receipt/ABI admission remains intact; + imported portable inputs select their exact directory. Linux actual build and + repeat produce the same generation; concurrent SQL (two backend PIDs), + PL/pgSQL/Snowball loading, and PostgreSQL boolean/CASE/COPY regressions pass. + Interrupted/concurrent publication and header corruption tests pass; the + unchanged-size export proof remains covered. Owner syntax checking now needs + only Shell inputs, without Rust setup. **Remaining:** execute generation + publication and consumer qualification on macOS; local Linux evidence does + not establish that host guarantee. +- [ ] **M13 — Capability probes (13,25,26).** Retain concrete patched-runtime + regressions with the executor/sysroot owner; separate probe builds from runs. + Scope expensive probes to their real dependencies. capabilities.tsv was found + to be documentation; Shell owns probe selection. **Done:** relevant runtime + changes exercise meaningful capabilities, unrelated SDK/docs changes do not, + and no new capability-inventory enforcement system is introduced. +- [ ] **M14 — Headers and symbols (04,19,20,25).** Consume one canonical header + through declared dependencies and copy into distribution outputs as needed; + delete committed-copy equality checks when duplicates disappear. Retain actual + symbol-provider/ABI checks and extension loading in an embedding application. + **Done:** packaged consumers compile against the correct header and required + binaries link/load without relying solely on source-spelling assertions. +- [ ] **M15 — Reproducibility/caches (06,19,24).** Keep source-derived timestamps + and narrowly necessary upstream workarounds. Prefer immutable completed cache + outputs keyed by compiler/target/flags/dependency inputs; remove reuse-time + mutation and completion-stamp ceremony where unnecessary. **Done:** cold, warm, + interrupted and changed-input cases behave correctly; safe reuse does not + require invalidating the previously valid cache. + Native PostGIS checkpoint: a fully hash-validated warm cache now keeps its + completion marker, so interruption during reuse does not discard valid + libraries on the next attempt. Existing changed-input/corrupt-output + invalidation remains; owner tests pass under Bash 3.2 and current Bash. + WASIX OpenSSL/GEOS/PROJ checkpoint: upstream `DESTDIR` installs now validate + staged prefixes before replacing usable dependencies. All three recipes pass + repeat/changed-input and configure/build/install failure-retention tests; + real cached installs in the existing builder image preserve library bytes. + Forced-crash/concurrent publication remains outside this bounded fix. +- [ ] **M16 — Native consumer integration (20).** Retain Expo, Gradle, CocoaPods + and RN integration as product behavior. Kotlin/Swift own native dependencies; + RN composes them without another complete artifact resolver. Keep idiomatic + Java Gradle integration and TypeScript-generated distribution JavaScript. + **Done:** repeated prebuild is idempotent, adding/removing extensions leaves no + stale assets, correct ABIs build, and optional resources remain unbundled. +- [ ] **M17 — Installed-app runners (20,23–26).** Separate built-app production + from install/run tasks; retries consume the same artifact. Keep readiness, + timeout, cleanup and sufficient run identity to reject stale success. Reduce + duplicate report interpretation; scope broad suites to actual dependencies. + **Done:** narrow native-platform tests remain runnable independently and detect + real failures; Android/iOS-specific semantics retain their own necessary proof. +- [ ] **M18 — Benchmarks (23,25).** Keep purposeful experiments and provenance; + preserve their existing exclusion from ordinary CI. Lock comparison inputs, + separate setup from measured work, and delete abandoned scaffolding only after + caller review. **Done:** retained benchmarks answer a stated question with raw + results and reproducible inputs; no noisy automatic release gate is added. + +Task 30 must review every disposition above against the final task graph and +package/release flow. Record any deferred replacement and its concrete reason; +do not count directory moves or renamed wrappers as simplification evidence. +This checklist is migration review material, not a permanent policy checker. + +## Versioning and changelog review + +Current release-please-config.json contains 20 products and 43 extra-file +updates. Strategies are Rust, Node and simple; Swift and Kotlin use simple, +not a native Apple/Gradle release mechanism. Only node-workspace is configured; +cargo-workspace is absent. Upstream Release Please documents that Rust manifest +releases need cargo-workspace for dependency updates. The repo instead supplies +substantial custom synchronization; absence of the plugin alone is not proof +the current final pins are wrong. + +Version flow today: + +1. Release Please selects path-associated Conventional Commits and updates + candidate versions/changelogs, canonical files and configured extra-files. +2. sync-release-pr.mts (1224 lines at review) adds shared contrib candidates, + syncs compatibility pins, extension registry metadata, npm optional deps, + src/examples/install snippets, Cargo dependency pins, Cargo/Bun lock content and + extension evidence summaries. +3. release-candidate-sync.mts can independently create/merge changelog sections + for custom shared-source/dependency candidates. The workflow normalizes and + amends the bot PR, then checks the resulting tree. + +This is more than a small version-file adapter. Native runtime versions are +mirrored across carriers and C source; the Rust broker version exists in both +Cargo metadata and BROKER_RELEASE_VERSION (declared in release.toml for sync). +Declared synchronization reduces drift but does not eliminate the duplicate +authority or prove arbitrary future tests are version-independent. + +Changelog findings are concrete: the Swift 0.7.0, vector 0.2.0 and postmaster +0.1.0 changelogs include a breaking note about Rust WASIX storage variants and +browser IndexedDB v3. These are product-irrelevant claims in those locations. +The broad commit fae2bd7 contains cross-product release text, explaining the +path-selected commit-body contamination. CI/refactor bullets also appear as +product release notes. There are 20 tracked changelogs matching the 20 configured +products; this inspection did not find extra orphan changelog files. The +verified problem is relevance/content and ownership boundaries, not evidence +of randomly created changelog files. + +Version literals sampled in release unit tests and Swift resource composition +tests are largely self-contained fixtures; they should not follow every real +release. The failure pattern to eliminate is mixing fixed fixture versions with +live repository or downloaded candidate metadata. This source review does not +establish that a particular current test is failing from that pattern. Task 27c +requires an actual disposable candidate version-change exercise to prove it. + +Focused verification: ran release-candidate-sync.test.mts and +sync-release-pr.test.mts through the existing with-projects.sh harness; the +resulting run reported 30 passing tests across six files, zero failures. This +verifies existing synchronization scenarios, not every real product under a +new release version, and does not validate changelog prose relevance. + +Tool assessment: Release Please supports polyglot manifest releases and is not +a Rust-only tool. The final decision retains it as the candidate/PR generator; it must +not become a second cross-language build/release graph. Changesets' explicit +change descriptions address note relevance but do not by themselves eliminate +Rust/Swift/Gradle/carrier adapters. Replacing the tool without simplifying those +boundaries can preserve the same maintenance problem. Task 27b verifies the +minimal pinned integration and shared-source selection before moves; the later +version-transition exercise proves the migrated configuration. No tool switch +or second release engine is planned. + +References: + +- [Release Please manifest and workspace plugins](https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md) +- [Release Please strategies and extra files](https://github.com/googleapis/release-please/blob/main/docs/customizing.md) +- [Changesets change-description model](https://github.com/changesets/changesets) + +## Affectedness audit: observed selection + +Ran the installed pinned Moon 2.5.4 with one file path supplied on stdin to +`moon query affected --upstream none --downstream deep`, extracted directly +affected tasks using the same criteria as affected.mts, and passed them to the +actual ci_plan.mts jobs-for-affected command using a real Moon task graph. +Probes used the current dirty workspace configuration; no source edits or +product builds were needed. These test file-to-task/builder selection, not +Git event comparison, hosted matrix execution or timing. The results below +describe builder jobs; check/test matrices are a separate existing path. + +| Simulated changed path | Observed result | +| --- | --- | +| `src/docs/maintainers/development.md` | No product builder selected; only base affected job | +| `src/shared/rust-query-core/query_core.rs` | Both Rust SDK unit/typecheck tasks selected; also runtime AOT and native/WASIX extension producer jobs through current coupling | +| New path `src/sdks/rust/src/new_affected_probe.rs` | Native SDK unit/typecheck and package work selected without adding a file entry; source globs cover additions | +| `src/runtimes/liboliphaunt/native/bin/icu.sh` | Native and WASIX producers selected, consistent with the helper's cross-runtime use, but very broad downstream fan-out | +| `src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1` | Android and iOS build tasks directly affected; native mobile apps and WASIX producers selected as well. Windows-only orchestration is mixed into broad groups | +| `.github/actions/setup-msvc/action.yml` | Only workflow check directly affected; no native producer selected. Changed Windows setup lacks a Windows build proof edge | +| `src/shared/artifact-packaging/portable-archive.mts` | 67 directly affected tasks and broad native/mobile/WASIX/postmaster builder selection; review actual fetch/packaging uses before narrowing | +| `Cargo.lock` | 74 directly affected tasks and broad native/mobile/WASIX/postmaster selection; conservative workspace input, not proof every lock entry affects every product | + +Manual selection machinery still exists: + +- .moon/tasks/inputs.yml has shared file inventories and broad workspace inputs. +- Individual Moon tasks contain long cross-project input lists; the native + runtime mixes platform-specific scripts into groups used by several targets. +- ci_plan.mts has BROAD_EXTENSION_INPUT_PROJECTS and explicit job/target sets, + and performs additional downstream/prerequisite traversal. Some runner mapping + is necessary; product impact should come from the declared dependency graph. +- write-affected-moon-target-matrices.mts classifies policy through a fixed + policyProjectIds set and command.includes checks, alongside proper task tags. +- GitHub cache keys separately enumerate source paths. Those lists affect cache + identity, not job selection, but must agree with actual producer inputs. + +Conclusion: Moon is the starting graph, not evidence that the selection is +already clean or entirely inferred. There is observed over-selection and a +missing native-build selection for setup changes. Not every explicit input is +bad: a shell script sourcing another file or an external tool consuming a pin +must declare that dependency if the ecosystem cannot infer it. The target is +one product-owned dependency declaration, no detached CI whitelist of the same +relationship, and normal source-directory globs for newly added files. Do not +claim that a task runner can infer arbitrary shell/file/environment dependencies. + +## Check value and ownership review + +The plan previously required deletion of low-value checks, but the current CI +has not been proven free of them. Concrete source findings from this review: + +| Current path | Finding | Disposition | +| --- | --- | --- | +| `tools/policy/check-policy-tools.sh` | A task named lint syntax-checks shell and bundles scripts across .github/scripts, src/examples/tools, policy and graph | Put syntax/type/build validation in the actual tooling owners; do not hide a cross-domain build behind lint | +| `tools/release/release-check.sh` | Discovers almost every test in tools/release and tools/policy, with a growing exclusion list; execution scope follows storage location | Group actual release/CI/packaging behavior under their own tasks with narrow inputs, remove unrelated tests from release qualification | +| `tools/release/release-metadata-check.sh` | Combines product metadata, generated release-PR state, version synchronization and example Cargo policy | Retain selected-candidate package/dependency validation; move example checks out of the publication prerequisite and eliminate redundant metadata authorities | +| `tools/release/moon.yml` metadata task | Broad cross-repo input list and cache:false, despite mixing static facts with history/state reads | Split necessary stateful preflight from deterministic metadata processing; scope inputs instead of invalidating all checks for unrelated files | +| `tools/release/native-script-self-identity.test.mts` | Extension source lookup test freezes target directory spellings and lives under release tooling | Preserve meaningful lookup/unknown-extension behavior at source ownership; avoid making an internal directory name a release contract | +| `tools/policy/check-workflows.sh` | Includes actionlint/zizmor plus security, shell runner, capability and planner behavior tests | Retain consequential workflow/selection/security behavior when its implementation changes; do not rerun this suite merely because a product is being published | + +Not every exact assertion is low value: a package manifest pointing at a missing +public file, an invalid dependency version or a wrong runtime ABI is a real +consumer failure. Prefer one real packaged-consumer check or focused validation +at that boundary over several checks of source spelling and duplicated models. +Likewise, a test proving planner failure cannot become a green Required gate +earns its place; a test demanding an arbitrary YAML layout does not. + +Phase ownership: + +| Phase | Checks that belong | Checks that do not belong | +| --- | --- | --- | +| Source PR | Affected format/lint/type/tests; affected tooling behavior | Unrelated examples, release registry readiness, aesthetic repo layout rules | +| Build/package | Required compile/integration and final package interfaces/bytes | Repeating all source tests through package aliases | +| Release PR | Selected version/dependency/lock closure and final consumer envelope | Unrelated source-policy sweep or mandatory unchanged runtime rebuild | +| Qualification | Aggregate required selected evidence for exact candidate | A second copy of every test already executed on those inputs | +| Publish/retry | Candidate identity, transferred bytes, current registry/auth state, public consumers | Source formatting, repository layout, all tooling test suites | + +Tasks 25a/25b close this gap by review and deletion, not by adding another +policy-enforcement layer. No claim of removed work or measured savings is made +until actual execution traces and deleted checks demonstrate it. + +## Windows/Bash and host-placement review + +Source review on 2026-09-11 found three tracked PowerShell files: + +| File | Lines | Responsibility | +| --- | ---: | --- | +| `.github/scripts/setup-msvc.ps1` | 225 | VS discovery, developer environment, tool validation, hosted provenance | +| `src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1` | 3109 | MSVC setup plus sources, dependencies, generated Meson configuration and product compilation | +| `src/runtimes/liboliphaunt/native/tools/package-liboliphaunt-windows-assets.ps1` | 308 | Optional build, seed generation, native smoke, staging and archives | + +Most reusable Windows workflows already specify `shell: bash`. GitHub supports +this using Git for Windows Bash. Bash can invoke native MSVC executables; it +does not require changing the compiled product ABI. MSVC still needs the +environment established by Visual Studio's developer launcher. + +The current Windows builder deliberately removes MSYS tool directories when +selecting cl/link/lib/dumpbin. That is evidence that tool selection needs care, +not that PowerShell is intrinsically required. Preserve the intended MSVC +selection when migrating; Git's link.exe must not shadow the MSVC linker. +MSYS path conversion and slash-prefixed MSVC switches need explicit handling +at native command boundaries; do not disable conversion globally by habit. + +Current positive examples: CI already assembles native release assets on Linux, +has Linux Apple ABI-finalization jobs, and platform-binary-contract.mts reads +PE/Mach-O/ELF using portable data processing. Reuse these capabilities before +adding LLVM tooling or another binary parser. + +| Work | Proposed execution host | Limit | +| --- | --- | --- | +| TS analysis, ordinary unit tests, metadata/version/release planning | Linux | Real platform-specific behavior tests remain native | +| Notices, resource selection, archives, checksums and registry assembly | Linux | Preserve executable bits, symlinks, case and package layout in transfer | +| PE/Mach-O imports, exports, architecture and declared minimum OS inspection | Linux | Does not prove loader compatibility or runtime behavior | +| Windows MSVC compile/link, SDK/CRT discovery | Windows for the supported build | Cross-compiling is not a prerequisite for this cleanup | +| Windows DLL loading, Node addon, broker/server, filesystem/process semantics | Windows | Run final consumer without Git Bash/MSYS on its runtime PATH | +| Apple SDK compile/link, XCFramework production, Apple signing verification where used | macOS | Ordinary ZIP assembly and metadata checks need not inherit macOS | +| Swift Apple SDK integration, macOS runtime, iOS simulator/device | macOS/device | Linux Swift checks cannot replace Apple-platform validation | +| Android assembly/emulator | Linux with required Android/KVM setup | Android does not inherently require macOS | +| Target-specific seed generation | Host capable of executing that initializer | Seed packaging/checksum work is portable; do not execute Windows initdb on Linux by assumption | +| WASIX portable production | Linux where supported by current toolchain | AOT generation split is subject to actual compiler/target capability; keep target execution native | +| Registry upload and candidate coordination | Linux unless an actual operation requires another host | Extract necessary signing/Apple consumer verification rather than moving the entire release to macOS | + +Acceptance is behavioral and ABI compatibility, not byte-identical output +between old and new compilers/scripts. This investigation does not claim a +Windows build has been run from Linux or that current Windows failures have +been repaired. + +Primary references: + +- [GitHub workflow shell behavior](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax) +- [MSVC command-line environment](https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line) +- [MSYS path conversion](https://www.msys2.org/docs/filesystem-paths/) +- [LLVM object inspection capabilities](https://llvm.org/docs/CommandGuide/llvm-readobj.html) +- [Apple XCFramework production](https://developer.apple.com/documentation/xcode/creating-a-multi-platform-binary-framework-bundle) + +## Release-path alignment review + +Reviewed the actual release.yml job sequence, release PR normalization/sync, +release-dry-run.sh, package-release-carriers, candidate locking, bootstrap plan, +normal publication executor, Maven signing and final promotion. This is a +source review, not a live release or a claim that every transport helper has +been exhaustively audited. Overall: frozen publication and retry semantics +align; preparation scope, naming and product ownership still do not. + +| Finding | Evidence and consequence | Required change / task | +| --- | --- | --- | +| Release Please is not the sole candidate-generation path | release.yml has a no-PR fallback that creates a shared-contrib release branch/PR; sync-release-pr.mts also has bootstrap-shared-contrib. Shared changes need releases, but a special alternative PR creator duplicates authority | Model shared shipped-byte changes in one candidate selection path; keep required derived manifest closure, remove the contrib-only alternate PR construction. 27,27a | +| Exact single-commit normalization adds history coupling | normalize-release-please-pr.sh resets/amends a generated branch and insists on one commit above exact main | Judge candidate tree, versions and safe update identity; retain lease protection, remove commit-count restrictions unless a real consumer requires them. 27a | +| Preparation provisions too much before knowing scope | prepare-candidate selects macos-26, installs workspace/Rust and configures Java plus Android before release planning; no-change/TS-only selection still passes setup | Plan selected products and required capabilities first; skip setup for no-op, isolate genuinely Apple/Android-dependent preparation. No new generic provisioning framework. 24b,28 | +| Qualified wait cannot itself create the required evidence | prepare-candidate waits up to 7200 seconds for Builds/Required/Qualified; Qualified is currently manual-all-target only | Product-scoped automatic qualification and an explicit request-or-reuse path; never spend two hours waiting for a workflow nobody started. 26,26b | +| Dry-run is an inaccurate and overloaded name | release-dry-run.sh without qualified-ci runs release-check.sh; qualified-ci verifies an existing candidate; arguments add live registry checks. Packaging/freezing happens later in the workflow | Separate existing local checks, candidate verification, and live registry preflight by their real responsibilities. Remove obsolete publish-dry-run operation strings; migrate the release-dry-run environment deliberately if renamed. A no-upload rehearsal must exercise actual assembly, not imply these checks prove it. 28 | +| Root packaging still knows every product | package-release-carriers.mts imports individual native, WASIX, broker, addon and extension implementations; its shell wrapper adds a broker-only packaging branch | Products emit finished package outputs through their declared tasks. Coordinator selects/invokes those tasks and consumes their outputs; do not replace the switch with a bespoke plugin framework. 14–19,24,28 | +| Same facts are recomputed across jobs | prepare, bootstrap and publish re-plan products and revalidate release identity/registry state | Compute immutable selection once and use the frozen candidate across jobs. Keep verification on artifact transfer and fresh mutable-state checks at public mutation boundaries; delete repeated whole-source planning and unrelated qualification. 28–29 | +| Bootstrap and ordinary publication have overlapping work | Both plan registry carriers, order dependencies, reconcile identities and publish; bootstrap additionally has credentials and an interruption ledger | Reuse existing ordering/reconciliation primitives where that reduces code. Keep distinct credential scope and necessary durable bootstrap state; no deletion of recovery guarantees just to merge jobs. 29 | +| “Publish frozen bytes” needs a signing-envelope qualification | preflight-maven-central-bundle.sh signs frozen payloads and constructs a ZIP inside publish. This is not product compilation, but signatures/envelope bytes can change on retry | State precisely which payload bytes are immutable and which signing envelope is created later. Preserve/reconcile signed transport identity when required; do not claim complete byte-reproducibility without proof. 28a,29a | +| “Promote last” does not mean nothing was public earlier | Product tags/assets and Swift publication occur before registry verification and final draft promotion | Document partial visibility and per-ecosystem availability; ensure Swift consumers can resolve required public assets. Final labels describe completed publication, never atomicity across registries. 28a,29a | + +Keep the following existing guarantees unless a simpler implementation proves +the same behavior: exact candidate/tree identity, dependency-ordered publication, +conditional absent-name bootstrap, checksum/SRI reconciliation, mismatch +rejection, bounded handling of transient registry failures, and final public +consumer verification. Checkpoint/lock size alone does not prove dispensability. +Conversely, package checks should not validate prose or incidental source +spelling, and no runtime build is justified merely by release label changes. + +Additional completion examples for the mapped tasks: + +- Preparing a TS-only release with no native package assembly requirement does + not configure Android or Java; no-release selection does no package setup. +- A shared contrib source change produces the correct runtime candidates through + the same release-PR mechanism as other shared shipped-source changes. +- Local deterministic checks work without registry credentials; live registry + preflight is explicitly identified and scoped to selected ecosystems. +- Bootstrap and publish consume the same locked product set even if main moves; + public-state checks are refreshed where they can change, not mechanically + deleted as duplicates. +- Maven retry verifies identical payloads and handles signed envelope identity + explicitly; final Swift availability is tested with anonymous access. + +## PR-to-release operating model + +These are acceptance requirements for the existing workflows, not new services +or an additional handwritten task graph. + +| Event | Required behavior | Must not happen | +| --- | --- | --- | +| Normal/fork source PR | Plan exact changed tree; run affected checks/builds/consumer tests in dependency order; expose stable Required result | Registry-readiness prerequisite, secrets in untrusted builds, unrelated full qualification | +| New PR revision | Cancel obsolete PR execution and qualify the new planned tree | Previous green head accepted for new source | +| PR closes | Cancel obsolete execution without scheduling builders | Runner allocation by always-on aggregate jobs | +| Merge queue | Qualify the actual merge-group tree against its correct base | Qualify only an individual PR head and claim integration success | +| Main push | Evaluate exact merged commit and produce needed evidence; release candidate scope includes selected products even when the diff only changes versions | Assume PR SHA equals merge SHA, or run an exhaustive matrix for every push | +| Prepare release PR | Select candidates from release history, close versions/dependencies/locks once, publish one stable bot PR update | Manual version surgery, duplicate heavy CI on transient generated heads | +| Release PR CI | Check final package versions/compatibility/consumer envelopes and required changed producers | Rebuild unchanged binaries solely because a changelog changed | +| Merge release PR | Establish the final candidate SHA and selected release scope; obtain exact candidate evidence | Treat bot PR qualification as unconditional evidence for a different merge | +| Publish | Reuse or request exact-candidate assembly/freezing/package qualification once, then bootstrap if needed, upload the same dependency-ordered bytes, verify public consumers and finalize | Separate obligatory dry-run/bootstrap/full-qualification ceremonies, compilation inside upload jobs | +| Retry partial publish | Reconcile public bytes and continue the original immutable candidate | Republish conflicting bytes, follow moving main, restart all successful uploads | +| Exhaustive audit | Explicit optional diagnostic/migration audit across the full supported surface | Hidden universal prerequisite for an unrelated product release | + +Selected-release scope and affected-PR scope are not interchangeable. For +example, a release PR changing only versions still needs every selected output +accounted for, while it may reuse verified unchanged producer bytes. A shared +runtime change needs dependent compatibility proof even when those consumers +are not themselves receiving new releases. + +## Acceptance matrix + +| Scenario | Required observation | +| --- | --- | +| Clean checkout, one SDK | One documented build command traverses required dependency builds; native ecosystem commands remain available; no unrelated language/OS setup | +| Same build twice | Inputs unchanged; no unnecessary producer execution or source mutation | +| Cache absent | Correct build, no hidden dependency on old artifacts | +| Interrupted source/seed/package preparation | Retry recovers or fails clearly; existing valid data/output preserved | +| Native direct and broker | Query/error/cancel/close/persistence retained; broker isolation and death behavior retained | +| Native Node/Bun/Deno consolidation | One frozen Rust napi-rs addon per target passes all host consumers; generation/worker cleanup and cancellation preserved; no C++ addon or Deno FFI fallback | +| Addon-free broker/server | Process/socket modes work without loading or installing the direct addon; no topology fallback | +| Native server | Packaged PostgreSQL launch, multiple connections and clean stop retained | +| WASIX Rust and Node | Runtime-only/default excludes optional assets; selected resources initialize and persist | +| Browser | Built Rust/WASM host loads, endpoint startup succeeds, selected assets and storage work | +| Postmaster | Multiple backends and required shared-memory/process capabilities; compiler-free executor | +| Swift/Kotlin/RN | Packaged consumer builds plus relevant simulator/device behavior; consistent native dependency versions | +| Resources | Four logical seeds plus required target variants; same compatible ICU data; wrong-format rejection; no unselected payload | +| Extensions | Contrib subset plus external carrier, load/create/restart/dump-restore where promised | +| PostgreSQL tools | Separately installed initialization and logical dump/restore | +| pgwire-server | Installed CLI accepts an ordinary driver; sequential limitations documented | +| Shared source edit | Actual consumers tested; bundled-byte consumers selected for release; unrelated products unchanged | +| Pure docs edit | Docs checks only, no binary producer | +| Source pin or patch edit | Relevant runtime/extension rebuild and downstream compatibility checks | +| Version/envelope-only edit | Package/version checks; immutable binary reuse only with verified unchanged producer identity | +| Release preparation twice | No second source diff or new candidate identity | +| Publication retry | Byte-matching public versions skipped; absent versions published; conflicts rejected | +| Fork PR | Useful Required result without release secrets or registry setup | +| PR revision/closure | Obsolete work cancelled; closure allocates no new runner | +| Merge group / main merge | Correct immutable tree/base selected; no PR-head substitution | +| Release PR no-op/rebase/conflict | Stable final tree; no duplicate CI; unrelated edits preserved | +| Bot PR update | Required CI runs on the normalized head; obsolete head cannot satisfy it | +| Selected job skipped/cancelled/missing | Required fails; legitimately unselected work does not block | +| New selected product/carrier | Complete manifests, dependency ordering and conditional first-name bootstrap | +| Publish without pre-existing qualification | One exact-candidate CI request before publication, or reuse of eligible in-flight run | +| Stale/wrong-attempt/expired artifact | Reject reuse with actionable diagnosis; never substitute branch-latest output | +| Post-publication main movement | Resume original candidate using retained verified bytes | +| Swift source tag and binary assets | Public consumer works at the declared availability point; no dependence on draft asset access | +| Partial publication/finalization failure | Public state accurately reported; labels/tags/promotion reconciled on retry | +| Protected-check migration | Required remains enforceable; no obsolete required job or accidental bypass | +| Windows Bash build | MSVC/CRT ABI preserved; no Git Bash/MSYS/WSL runtime requirement for consumers | +| Windows path/tool boundary | Spaces/Unicode paths and compiler switches survive; correct link.exe; native failures propagate | +| Linux packaging of Windows/Apple outputs | Archive structure/modes/checksums valid; final native consumer still passes | +| Local toolchain preparation | No GitHub-only environment variables required; precise missing capability reported | + +No wall-clock improvement or line reduction is claimed until measured. Keep +only measurements needed to establish that the new workflow removed work; +do not add a permanent performance/policy platform for this migration. + +## Execution discipline + +1. Complete baseline and names, then one coordinated layout/reference pass. +2. Implement ownership/extraction tasks in dependency order; make small local + checks after each actual behavior change. Do not alternate speculative moves + and whole-repository CI runs. +3. Use narrow hosted jobs when a platform-only problem needs resolution; + reserve the integrated full migration proof for the coherent final state. +4. Do not skip correctness checks in the name of doing the visual pass first. +5. Keep a short completed-task log here with exact commands/results; never mark + a phase complete because its directories exist. +6. Registry publication is not necessary to finish the planning or structural + work. Prepare concrete packages and local consumers before any real release. + +### Implementation log — 2026-09-11 + +Implementation is now authorized. The first parallel batch established real +dependency boundaries and removed obsolete tooling; the coordinated product move +is applied. Final-state task boxes remain open until their complete contracts +are met; these results do not qualify every platform or a production release. + +- **06, partial:** PostgreSQL patches now have an explicit common/WASIX hierarchy + under `src/third-party/postgres/patches`, with ordered series for all three runtime + lanes. The hierarchy-only change preserved all three PostgreSQL 18.4 source + postimages byte-for-byte. Source preparation passed clean, repeated and + interrupted-recovery checks. Other source/toolchain consolidation remains. +- **06b, implemented tooling batch:** Bun 1.4.2 replaces pnpm workspace installation, + locks, packing and CI setup. Deleted the scoped pnpm workspace writer and duplicate + lock editor. The Node/Bun action reuses the existing verified Bun installer. + Bun frozen installation and Moon 2.5.4 project discovery pass. WASIX SDK tests + pass 338 cases, React Native 11, and the WASIX tools SDK 9; their typechecks pass. + Host-specific execution and final affected/task integration remain separate proof. +- **07–08, implemented package boundaries:** `src/sdks/rust-query` and `src/sdks/ts-query` + own normal published dependencies (`oliphaunt-query`, `@oliphaunt/ts-query`). + Rust include/copy and TS bundled-source staging were removed. Query release + manifests, compatibility updates and publication ordering are present. Native + Rust tests (198), shared Rust tests (3), WASIX query tests (19), WASIX test-target + compilation, native/query Clippy, TS build/typecheck and query/package tests + (41) passed. Both real shared package archives were staged and exercised through + candidate creation and freezing. CI uploads now include their exact artifact + names; query-only runs skip unrelated SDK uploads and native lifecycle work. + The SDK path migration is applied; later checks are recorded below. + Follow-up test consolidation deleted 539 lines of duplicate TS decoder suites + and moved parser-only Rust cases to their actual owner. Final checks passed + 26 TS query tests, 28 Rust query tests, 177 native Rust tests, two WASIX adapter + tests, and Clippy for all three Rust packages. SDK host/error conversion checks + remain. The actual Moon release-package tasks built both shared archives; + repeating them succeeded with two cached prerequisites. +- **11a, implemented readiness fix:** the native server owner now enforces startup + timeout even when a peer accepts TCP but sends nothing, closing the socket on + expiry. Sixteen adapter tests and real PostgreSQL server queries pass. The smoke + uses the existing standard `pg` driver instead of a second handwritten query + implementation. Direct restore proof uses a fresh host process, while same-root + logical reopening remains covered; it now checks a row persisted before backup. + The complete `bash src/examples/tools/smoke-js-sdk.sh` passed Bun direct/broker, + standard-driver server and Deno direct phases with the original native artifacts. +- **09, shared native Rust ownership:** `src/sdks/rust/liboliphaunt-native` now owns + sessions, FFI, resource preparation, cancellation and backup/restore. The Rust + SDK and broker depend on this crate; the broker owns its IPC implementation. + The bindings' 63 tests pass both in the workspace and from its packaged crate; + SDK 109 and broker five tests pass, with all three owners Clippy-clean. + CI uploads and catalog-driven candidate downloads include both source crates. + A consumer built from the actual SDK/query/bindings/broker archives; platform + binary carriers alone were placeholders in that compile-only proof. Publication + discovery verified both new source archives and their dependency edge. +- **09a, proof only:** the same napi-rs prototype passed query, streaming, + callback-error recovery, cancellation, backup/restore and generation-safe + cleanup on Node 22, Bun 1.4.2 and Deno 2.8.1. Terminating a Node worker during + pending work aborts generic napi `AsyncTask` promise completion. Existing C++ + remains until shutdown behavior and installation/platform contracts pass. + Subsequent Node/Bun proof uses an asynchronous reaper and owner-thread cleanup + acknowledgement, preserving the existing off-thread native teardown contract. + Initialization, active/queued query, stream, forgotten-handle and copied-addon + stale-owner cases pass, as do callback exception identity and backup-before-close. + Deno's supported FFI adapter remains: both existing C++ and the async prototype + reproduce a Deno V8 cleanup failure. Production Node/Bun adoption is underway; + these prototype checks are not a claim of completed platform qualification. +- **02a/27b, migration prerequisites:** the pinned Release Please simulation + established stable component/version preservation, but directory changes lose + old-path unreleased notes unless captured once at cutover. The lineage ledger + records existing tags and transferred registry version floors. Transition and + historical artifact lookup now map through current/historical configurations + by component, including swapped paths; real Git history tests reject missing + mapped pins. Product metadata tests (21) and transition tests (16) pass. + Applying the one-time notes at the actual global move remains pending. +- **23, implemented docs cleanup:** removed generated SDK API dependencies and docs + version scaffolding. Main guides resolve installation versions from completed + public releases. Docs typecheck, 44 internal links, 139 static outputs and 49 HTML + export checks passed. Vercel release-triggered refresh and verification are task + 23a; successful local export is not a deployment claim. A separate post-promotion + CI job now requests one refresh and preserves its receipt. The protected Vercel + hook secret/settings and actual deployment correlation are still unavailable; + an accepted POST is explicitly not reported as a successful deployment. +- **27–29, partial integration:** Bun itself refreshes/verifies its lockfile after + release PR metadata synchronization; release-commit validation permits the exact + derived Bun workspace version changes. All six release-commit tests passed + through the release-state wrapper. `bash tools/policy/check-workflows.sh` passed + actionlint, zizmor, workflow security and runner checks, plus all 45 affectedness + and artifact-transfer tests. The release aggregate passed 527/528 cases; its sole + failing TTY fixture inherited local shell startup files, and its corrected suite + subsequently passed all 14 cases. Eight archive/carrier tests also passed. The + metadata gate exposed historical release validation incorrectly applying current + Bun/docs rules to an old release. Tagged compatibility now uses its immutable + version facts; pending candidates retain strict validation. Removed the duplicate + release-PR wrapper from ordinary metadata checks: the release workflow already + verifies its exact candidate before pushing. The complete metadata gate now passes + for 22 products, 354 artifact targets and 42 compatibility fields, including Bun + lock convergence and example Cargo policy. The pre-move Release Please history + simulation passed; applying its one-time carry of unreleased notes at cutover + remains task 02a/27b work. The combined workflow gate passed again after adding + source crate uploads. Release metadata and the 21 publication-lock tests also + pass with the shared bindings and broker source carrier present. + +- **05/25, partial packaging cleanup:** removed native TS's intermediate + `package-shape` task and second copy. Its final packager stages built output once. + WASIX retains its actual package task, with an explicit source-build dependency; + packaging stages the browser host inside its own output rather than modifying + source-build output. Both real archives passed final validators; all 28 focused + affectedness tests passed after the task changes. + Packed consumer fixtures now install the actual WASIX SDK archive instead of + making another SDK copy. `smoke-browser.sh --package-only` passed in Chrome + (direct/worker SQL, IndexedDB, transactions, pgTAP and logical tools), and the + packed Node condition smoke passed. Browser fixture query-archive placement and + its stale source-host prerequisite were corrected; its controller runs on Bun. + +- **04, product move applied:** 1,465 files moved to the agreed runtime, SDK, + broker, extension, PostgreSQL and docs owners, with no destination collisions. + Existing dirty source was snapshotted before application. Obsolete ignored + outputs were preserved under `target/pre-layout-build-outputs`, not left as + apparent source in retired directories. Moon discovers projects without a + manually enumerated owner list; package manifests and Bun links resolve. + Remaining shared helpers and resource/tools ownership are separate unfinished + work; no compatibility source directories were introduced. +- **04/12, post-move proof:** Rust's five library suites pass 381 tests, six + crates pass Clippy, and actual source-package/packed-consumer tasks pass. + Four TS/query/RN builds and typechecks pass with 434 source tests, plus 42 + packaging/tool tests (nine macOS-only skips). Real packed WASIX Node and Chrome + consumers pass. Docs export, 49-page HTML checks and 44-route link/type checks + pass. The browser host now owns its build task and the SDK declares that + producer dependency. Kotlin formatting, two shared protocol fixture tests and + 50 Android runtime-resource unit tests pass; missing fixtures can no longer + silently turn those JVM tests into successful no-ops. +- **24, affected-task correction:** CI selects actual task closure rather than + every target sharing a job label. Full qualification remains explicit. An + Android ABI receipt dependency missing from Moon is now declared, and uploads + follow selected package targets. The post-move workflow aggregate passes all + 48 graph/transfer tests plus actionlint, zizmor and execution checks. Transport + test files no longer invalidate PostgreSQL runtime builds merely because the + tests moved beside shared source preparation. + +- **05/06/25, task normalization:** Rust SDK/query/bindings/broker owners now + expose consistent format, lint, build, test, package and consumer tasks. + Packaging no longer hides consumer compilation. Five real packaging tasks, + four builds, 66 bindings tests and 32 graph checks pass. TS/query/RN owners + use the same public taxonomy through Moon's native inherited-task renaming; + all four builds, typechecks, formatting and linting pass, with 476 tests and + nine macOS skips. Query/native/WASIX archives validate. RN's final archive + still requires genuine Apple artifacts; no placeholder is accepted. +- **09a, shipping Linux addon:** Node/Bun use the Rust napi-rs adapter and shared + native sessions. The 2,444-line C++ implementation and Node-header installer + machinery are removed. The optimized release build passes 57 lifecycle cases, + actual Node source/restore and Bun direct/broker/server consumers; Deno's + existing FFI path also passes. Deno addon teardown remains a demonstrated host + incompatibility, so its FFI implementation is retained. macOS/Windows shipping + execution is not yet qualified. Package/build and lifecycle qualification are + separate tasks sharing the same Cargo output/profile. +- **13, postmaster executor:** ordinary owner Cargo.toml/Cargo.lock replace + workspace injection and source copying. Preparation emits only Cargo patch + paths for prepared Wasmer; the upstream CLI references owner source directly. + Fresh/repeated preparation, release builds, 36 executor tests, version output, + receipt checks and locked CLI resolution pass. Executor normal dependencies + contain neither LLVM nor Cranelift. Full sealed-carrier concurrency proof is + still required in the aggregate pass. +- **14, native tools:** independent archive/Cargo/npm producers use the new + `postgres-tools-native` owner, retaining registry identities at version 0.2.1. + Runtime packagers no longer emit utility archives. Corrected a real consumer + defect: tools omitted libpq while the old Linux check borrowed runtime-package + libraries. The tools archive now includes only its local dynamic dependency + closure. Its isolated glibc 2.38 consumer passes with four ELF files and three + executables, without a runtime package mount; repeated packaging has identical + SHA-256. Disjoint runtime/tools Cargo packaging and real extracted Rust consumer + pass, as do packed npm logical dump/restore on Node, Bun and Deno. Native CI + uploads follow selected runtime/tools tasks. Central release dispatch and the + WASIX optional execution/assets split are being completed separately. +- **21/22/25, helper ownership and deletion:** 77 metadata/packaging helpers moved + to tools/release, tools/packaging and actual native/Swift/ICU/extension owners; + 130 tests pass, with one Darwin skip. Android/Maestro installers now belong to + tools/dev, CI emulator provisioning to tools/ci; all three Shell suites pass. + Native source lookup/PostGIS cache behavior now runs as small owner Shell + tests, replacing release-owned TS subprocess harnesses. Deleted the manual + example Cargo dependency graph and unused lock validator: release bindings + follow source manifests (including aliases/scopes), while real WASIX package + pin validation stays with its producer. Four focused tests pass; full version + transition checks await the in-progress tools catalog/lock checkpoint. +- **24, transferred producer ordering:** real Moon 2.5.4 experiments show + `--upstream none` drops ordering even between explicitly selected roots and + runs a consumer after its producer fails. The CI handoff therefore orders only + those selected roots and runs them sequentially, preserving downloaded + dependencies without a second general scheduler. Actual RN producer/package/ + consumer graph, failure propagation and cycle tests pass. Workflow aggregate: + eight helper checks, 17 CLI cases and 49 affected/transfer cases pass. +- **24/25, declared CI checks:** removed project-name and command-substring + heuristics from policy classification. Task tags select the lane, and both + check lanes execute declared Moon dependencies. Deleted the cross-project + policy bundling/parser pass; owner lint and executable tests remain. Six + focused classifier/capability tests, both owner lint tasks and the complete + workflow check pass (49 affected/transfer cases, plus CLI/security checks, + actionlint and zizmor). + +The earlier `bun install --frozen-lockfile` checkpoint passed with lifecycle +scripts enabled. Refresh and repeat it after the new tools carriers and removed +addon dependency settle. No active pnpm/Vitest executable references or committed +JavaScript/Python files remain. + +No registry publication or production deployment has been performed. Whole-repo +remaining ownership moves, mobile bindings, broker PG wire, resource ownership, +cross-platform qualification and the remaining CI/release redesign are pending. + +## Docs review and planned cleanup + +Status: implementation authorized; see the current implementation log above. +The earlier premature implementation was reverted, preserving the pre-existing +work. Earlier experimental build results do not establish that +the current or eventual final repository meets these requirements. + +Observed issues: docs declare SDK workspace dependencies, generate API summaries, +and carry TypeDoc/Dokka/DocC/Doxygen integration and extensive cross-project task +inputs. Test-marker checks establish only that strings exist, not that examples +work. The source-version matrix reads release-candidate metadata; the releases +page promises historical docs without a working archive. Kotlin installation +examples contain mismatched plugin/library versions, and release PR rewriting +does not cover every displayed version. + +Planned work: + +- Remove generated SDK API references for now, their exclusive tools/dependencies, + dead navigation and duplicate checks. Preserve written guides and actual SDK + behavior tests. Review callers before deleting shared facilities. +- Remove docs versioning, applicability/version scaffolding and historical-docs + promises. Keep independent product versions and release identities intact. + The site should describe the latest available products. +- Retain only useful product metadata inputs, explicitly owned in the task + graph. Prove docs can build locally without native SDK toolchains and SDK + implementation-only edits do not unnecessarily rebuild the site. +- Resolve each product's latest completed, non-prerelease GitHub release at + docs preparation time, using existing stable component identities. Render + installation commands from that explicit generated input; do not use the + Release Please candidate manifest or one repository-wide latest tag. Product + finalization guarantees public dependency availability. Pin related runtime, + Kotlin plugin/library and Swift installation examples to the compatible + versions of the selected published product, not independently latest values. + A product with no completed release is unavailable, never version 0.0.0. + Cache the resolved input as an ignored build artifact; local builds may consume + it explicitly, tests use a fixture. Network failure does not invent a version + or silently advertise a stale build as newly refreshed. No committed mirrored + version constants, SDK builds or cross-SDK API generation are required. +- Hosting is **oliphaunt.dev on Vercel**. User approved production guides from + main with versions from completed releases. Use existing Vercel Git deployment + for docs changes and one protected main-branch deploy hook after an entire + release operation completes. Inspect the actual root/build/ignore settings and + record only the required changes; avoid one deployment per product tag. + Resolve fresh published metadata on the triggered build even when normal + dependency/build caches hit. Correlate the requested deployment with its actual + status and the live guides; hook HTTP acceptance alone is insufficient. + A failed refresh preserves the existing live site and has a docs-only retry. + Concurrent/main-advancing builds must not let an older deployment replace + newer guides or published-version data. Main guides must describe available + features; future-only prose stays off production or is explicitly labelled. + This editorial rule is not a source-text policy checker. Hook secret/access + and existing Vercel settings are implementation prerequisites, not new user + architecture decisions. +- After the full plan is implemented, perform task 30a's principles review + against the final graph and release flow. Keep only consequential checks, + ecosystem-native local commands, necessary dependencies and clear ownership. + +Research: [Apache ADBC's versioning](https://github.com/apache/arrow-adbc/blob/main/docs/source/format/versioning.rst) +and [docs configuration](https://github.com/apache/arrow-adbc/blob/main/docs/source/conf.py) +illustrate separating source/development state from published versions, without +requiring us to adopt its docs-version system. [Vercel deploy hooks](https://vercel.com/docs/deploy-hooks) +target a configured branch; [Git integration](https://vercel.com/docs/git) can +deploy on pushes independently of product publication. Recheck these mechanisms +when implementing rather than assuming a hook alone guarantees latest-released +documentation. + +## Planning closure and remaining implementation evidence + +Planning validation: a disposable local check found 59 unique numbered tasks, +an acyclic prerequisite graph whose final task reaches all 59, all 18 machinery +items, and an inventory total matching 2,287 tracked paths. Relative document +links, code-fence balance and trailing whitespace passed. The check was not +added to the repository or CI; no product qualification was run for this edit. + +- [x] Enumerated all tracked source/configuration domains and mapped them to + owners/tasks in the companion contracts; included all 20 current release + declarations and their carriers, plus the new products and internal projects. +- [x] Defined native command profiles, target preservation, dependency/output + contracts and meaningful source/package/platform proof for every leaf family. +- [x] Incorporated all 18 machinery dispositions with removal/replacement criteria. +- [x] Resolved naming and docs preferences; retained Release Please, normal query + dependencies and explicit browser-host/tools/resource release ownership. +- [x] Added history/carrier transfer task 02a, including version floors and + first post-move release behavior; no registry reset is permitted. +- [x] Defined an acyclic execution order with docs review before final acceptance. +- [x] Fixed release ordering: assemble, freeze, qualify final packages, publish + those bytes, verify public consumers, finalize, then independently refresh docs. +- [x] Defined completion evidence and made unavailable platform/registry/deploy + verification explicitly incomplete; no directory move closes a behavior task. + +Read-only GitHub inspection during planning confirmed main as the default +branch, squash-only merging and published releases for all 20 current release +components. Latest listed examples included native/WASIX runtime 0.2.0, +postmaster 0.1.0, Swift 0.7.0 and WASIX TS/addon 0.1.0. Legacy contrib and +unscoped Swift tags remain public history. These observations are not proof of +every registry package's bytes. An earlier crates.io lookup for the now-reserved +bare liboliphaunt-native name was blocked by HTTP 403. The final bindings name is +liboliphaunt-native-bindings; its availability must be checked in 02a before any +reservation or publication. Reserving a name in this plan creates no registry +package. Actual Vercel settings/access, registry trust settings and native +execution remain evidence to obtain during the owning implementation tasks. + +This completes planning for the defined scope, not implementation qualification. +Unexpected source/platform constraints must be recorded with their minimal +reproduction and a plan adjustment; they are not permission to silently remove +functionality or expand the architecture. Routine replacement choices belong to +the implementer under the existing principles. Ask the user only if a discovered +constraint changes product scope, naming, public behavior or another agreed policy. + +## Consolidation decisions and completion contracts — 2026-09-11 + +This amendment is part of the implementation plan. Tasks 06,06b,07,08,11a, +15–20,23–29 and final acceptance 30 must satisfy it. It supersedes earlier +references that retain pnpm for repository maintenance. No runtime behaviour +or optimization has been changed during planning. The source evidence is the +current planning checkout, not a claim that overlapping upstream PRs are merged. + +### Resource production and consumption (15–20) + +Current Swift OliphauntRuntimeResources.swift/OliphauntExtensionResources.swift +and Kotlin OliphauntAndroidRuntimeAssets.kt contain substantial resolution, +extraction, cache and publication logic. Moving these files is not completion. + +1. Inventory each current input and caller: installed carriers, explicit local + resource paths, custom runtime/extension overrides, static mobile extension + registration, standard/ICU initialization, existing databases and restore. + Record the replacement for each supported path before deleting its code. +2. Producers own immutable payloads and their authoritative metadata. Gradle, + Swift packaging and application integration select and stage the final + resource closure before application launch. Resolve selection once; do not + recreate a package catalog/resolver inside each SDK. Keep one resource product + and its selectable carriers; do not add a new public resource-manager SDK. +3. Move compatible immutable assembly, digest calculation and installation + receipts to the build/install boundary. Remove redundant SDK caches, catalog + copies, manifests and extraction engines after their callers migrate. Retain + a small platform extractor/cache only when the actual bundle format or + supported explicit input needs it; no universal filesystem framework. +4. Runtime code locates selected assets, validates necessary runtime/physical/ + ICU compatibility, and creates mutable database storage safely. Read-only + application bundles cannot become live PGDATA. Preserve private seed copies, + concurrent initialization exclusion, descriptor-last publication, interrupted + recovery, create-only restore and useful missing-resource errors. Existing + databases do not require a seed merely to reopen. Do not erase validation at + an untrusted/custom-input boundary because build-owned assets were validated. +5. ICU data exists once in the selected closure; standard profiles exclude it. + Native and WASIX ICU seeds remain distinct while sharing compatible ICU data. + Keep four logical seed profiles plus necessary physical target variants. + Extensions remain explicitly selected, with correct native static/dynamic + and WASIX side-module handling. A selection change must remove stale staged + files; repeated application builds must not duplicate or accumulate assets. +6. Acceptance uses actual final packages/apps: inspect selection and installed + size, initialize/query/close/reopen, restore, exercise ICU collation, reject a + wrong/corrupt resource without modifying existing data, and interrupt/retry + initialization at a meaningful publication boundary. Compare first versus + repeated preparation. No application-time download or package graph traversal + for preselected bundled assets. Custom inputs get the smallest equivalent + validation path. Delete obsolete tests of the removed cache implementation. + +### Query ownership and behavioural proof (07,08,23,25) + +Both Rust query.rs adapters currently implement QueryResult/QueryRow inherent +methods on copied query-core types. Moving the methods and their error ownership +into src/sdks/rust-query is required for a real Cargo dependency. Prefer a single +query/decode error contract and a small boundary conversion over duplicate +wrappers or extension traits added only to preserve today's source layout. +Remove the build.rs source-copy/include fallback and packaged duplicate sources. +Shared TS query behaviour similarly belongs to src/sdks/ts-query; native/WASIX/RN +consumers do not each need a duplicate parser test suite. + +The simplest useful oracle for PostgreSQL-compatible semantics is ordinary +PostgreSQL at the pinned major/version, queried through an independent standard +driver. Reuse existing shared SQL scenarios and consumer harnesses. For the +focused compatibility integration task, run the same deterministic scenarios +against the reference and selected Oliphaunt implementations and compare public +results, types, SQLSTATE and transaction outcomes where contracts agree. Fix +locale/timezone/encoding/session inputs; do not compare unstable backend IDs, +timestamps, whole error strings, private representations or arbitrary OID values. +Normalize only documented incidental differences, not genuine failures. + +Do not make every source unit test start PostgreSQL or compile every runtime. +Run pure decoder/type tests once at their package and focused reference-backed +integration when relevant behaviour changes. Reuse one reference server for a +qualification job; keep each scenario's database/session state isolated. Use +already-required client tools/driver support before adding a new harness. + +Keep a small set of handwritten semantic expectations where an independent +PostgreSQL oracle cannot express the product contract: malformed/truncated input +rejection, buffer bounds, unsupported COPY/transaction combinations, callback +abort, cancellation/close ownership, and language-specific value conversion. +Handcrafted protocol bytes are justified for malformed-input tests. Do not +snapshot the implementation's own output as truth, read source to predict +behaviour, mass-generate golden files, or add a schema/test-generation framework. +Correctly shared fixtures are test inputs, not another implementation of SQL. + +Acceptance: both packaged Rust SDKs resolve the shared crate and expose usable +common types; TS consumers resolve their normal package dependency; reference +comparisons detect a deliberately incorrect result during implementation review; +remaining adapter checks exercise actual conversion/lifecycle differences. +Remove temporary perturbations after this one-time proof. No permanent mutation +testing machinery or new all-platform conformance mega-job is required. + +### Native server readiness (11a) + +src/sdks/js/src/runtime/pgwire.ts currently combines startup readiness and a +query operation consumed by native-smoke.ts. The production server adapter +does not expose that query path. Replace test-only querying with an ordinary +PostgreSQL client and remove its otherwise unnecessary production protocol code. +Apply the same caller review to Rust readiness. Preserve the requested user/ +database startup handshake, bounded wait, observed child exit, exact endpoint +and cleanup semantics. pg_isready or a port probe is not automatically an +equivalent replacement. The standard-client smoke proves a real downstream +connection/query, not just agreement between two private Oliphaunt helpers. + +### PostgreSQL patch hierarchy (06) + +There are three product lanes: native, embedded WASIX, and concurrent WASIX +postmaster. Today postmaster applies its own series and then +postgres/main-optimizations.series, whose files live inside the embedded WASIX +product. Native/WASIX also duplicate the collation-discovery change. Replace +that cross-product ownership with: + +```text +src/third-party/postgres/ + source.toml + patches/ + common/ # existing deltas truly applicable to all lanes + wasix/ # identical deltas consumed by both WASIX lanes +src/runtimes/liboliphaunt-native/postgres/ + patches/ # native-only deltas + series # explicit complete ordered patch references +src/runtimes/liboliphaunt-wasix/postgres/ + patches/ # embedded WASIX-only deltas + series +src/runtimes/liboliphaunt-wasix-postmaster/postgres/ + patches/ # concurrent process/shared-memory deltas + series +``` + +These are source/build ownership directories, not separately released packages. +Use the same pinned upstream source and a small Shell series applicator. Lists +are explicit build recipes, not manual CI affected-path lists. Declare selected +patch files/series and overlays as real producer inputs in Moon. Do not use glob +order, duplicate patch bodies, copied shared directories, or a dynamic patch +resolver. Ordered series can interleave layers when necessary; hierarchy must +not silently reorder dependent hunks. Each build gets its own prepared tree. + +Lift existing common identity/branding/default build configuration where it +actually exists and has the same meaning. Configure flags belong in shared build +configuration rather than unnecessary PostgreSQL patches. Do not invent new +branding work, alter PostgreSQL wire/server_version compatibility, remove legal +notices, or enable an embedded setting in postmaster just for visual symmetry. +No dedicated branding delta was identified in the targeted patch search; verify +overlays/build substitutions before concluding there is none. The two existing +collation patches are a consolidation candidate; do not newly apply their +behaviour to postmaster without evidence that it belongs there. A shared patch +may be selected by two lanes only; common storage does not mean mandatory use. + +Reconcile current main, PR #202 and issues #201/#203 before migration: some local +optimization patches may already have been superseded. Preserve each lane's +effective preprocessed behaviour and resulting source postimage when only +reorganizing. Record a concise rationale/base/consumers in existing patch headers +and series comments, avoiding a second metadata ledger. Verify clean apply, +repeat/interrupted preparation and the affected build/behaviour at their owners. +Keep true concurrent atomics/spinlocks in postmaster; never import the embedded +single-backend specializations into it. Remove obsolete patch provenance/selection +files only after their meaningful information and consumers have migrated. + +Optimization deletion/tuning is explicitly deferred. In the current checkout, +performance-oriented deltas include 0014 hash loads, 0015 top-XID lookup, 0016/ +0026 integer B-tree comparisons, 0017 scratch allocation, 0024 LIKE substring, +0030 WAL segment arithmetic and 0043 JSONB metadata caching. These are not user +configuration switches and are not proven safe deletions. Some are compiled out +in particular lanes despite appearing in a selected series. 0037 combines a +single-backend entropy buffer with a descriptor-exhaustion correctness fix; +0039 sigsetjmp is error recovery, not an optional optimization. 0018 pg_dump LTO +collision is build correctness despite appearing in main-optimizations.series. +0035/0036 have single-backend execution assumptions. Preserve all required +semantics and existing performance choices during organizational changes. + +### Bun maintenance toolchain and pnpm retirement (06b,05,22–29) + +Decision: Bun-specific maintainer TypeScript and bun:test. The package-manager +target is Bun workspaces, not parallel pnpm/Bun maintenance. Stable 1.4.2 was +verified from oven-sh/bun releases/latest on 2026-09-11 and is already pinned in +.prototools. Use an exact reviewed pin, never a floating latest in CI. Shell +still owns command orchestration; Bun's shell API is not a workaround. Native +language test runners remain native; real Node/Deno/browser/device execution +is still required for those advertised product surfaces. Node can remain for +third-party tooling and publication transports that require it. + +Bun documents workspaces, catalogs, isolated linking, frozen installs, overrides, +filtered installs and packing workspace/catalog references. Moon documents Bun +dependency discovery and task inference. This establishes a plausible migration, +not evidence that this repository already passes it. During implementation: + +- Convert root workspaces/catalogs to package.json; use one bun.lock and explicit + isolated linker settings. Keep independent standalone consumer fixtures only + where they prove installation outside the workspace. No duplicate local locks + for ordinary workspace members or generated scoped-workspace manifests. +- Audit every pnpm setting. Current minimumReleaseAge 1440 is minutes; Bun's + equivalent uses seconds (86400). Carry justified overrides and explicit trusted + dependency build scripts, including Electron/esbuild/sharp consumers. Bun's + peer auto-install default differs from current autoInstallPeers:false: prove + the chosen policy and required consumer peers rather than silently inheriting + a new default. Remove the ICU hidden-hoist workaround only when explicit + resource ownership makes it unnecessary. No blanket trust-all or hoisting fix. +- Trial migration in a disposable copy, compare resolved versions and resulting + package closures, and review intentional lock changes. Test filtered cold/warm + frozen installs, missing dependency errors, platform optional packages, lifecycle + scripts and workspace/catalog substitution in final tarballs. Verify actual + pinned Moon plugin support; do not assume current website configuration matches + the pinned plugin. Upgrade the plugin only with a focused graph/install proof. +- Migrate meaningful Vitest tests to bun:test without preserving tests of deleted + machinery. Keep real Playwright/device/host processes for integration. Establish + Bun type declarations and retain tsc typechecking; bun test is not a typecheck. + Verify worker/mocking/timers/isolation differences used by surviving tests. +- Delete pnpm tool acquisition, scoped workspace writer, package-manager pins, + lock/config/cache paths and documentation after caller migration. Update docs + Vercel install configuration, examples, packaging, release-PR lock refresh, + qualification and contributor commands together. A release PR must update the + Bun lock consistently with workspace versions, with an idempotent second run. +- Package once, qualify and freeze those bytes. Do not switch publication + transports merely to brand them Bun: verify registry auth/OIDC/provenance and + frozen-tarball support before replacing a working npm transport. Ordinary npm + consumers must keep working and do not need Bun. No publication-time rebuild. + +Sources: [Bun install](https://bun.com/docs/pm/cli/install), +[catalogs](https://bun.com/docs/pm/catalogs), +[workspaces](https://bun.com/docs/pm/workspaces), +[Moon Bun support](https://moonrepo.dev/docs/guides/javascript/bun-handbook), +[verified stable release](https://github.com/oven-sh/bun/releases/tag/bun-v1.4.2). + +### Qualification follows responsibility (24–29) + +Test substantive shared logic once at its owner, adapters for conversions and +host lifecycle, installed packages for consumer compatibility, and platforms +for their actual platform behaviour. Input edges select affected tasks; do not +propagate a shared unit change into every downstream device test by default. +Conversely, a changed native lifecycle/resource adapter cannot be excused by a +shared Linux unit pass. Keep producer-before-consumer edges at required artifacts. +Do not introduce a parallel path whitelist or scenario-to-file scheduler. + +For every retained task, identify the consequence it detects and the artifact/ +source inputs needed to detect it. Delete repository-layout/source-spelling +checks, repeated decoder suites, unused-client tests and checks of removed cache +machinery. Do not replace these with new policy tests asserting the taxonomy. +Use representative changes as a one-time graph acceptance review, including a +query-core change, resource selection, common patch, lane-only patch and release +metadata-only change. Package compatibility still needs proof when dependency +bytes change, but not every unrelated lifecycle/stress scenario. + +Release qualification consumes the final candidate once, then publication +promotes it. PR/source proof is reusable only for the same relevant inputs and +outputs; a different merged SHA or changed packaged dependency is not covered by +an earlier assertion. Preserve task-local reproduction commands and avoid an +extra full qualification before an already-equivalent release qualification. + +### Explicitly parked work + +- [#212 — Browser-host implementation extraction](https://github.com/f0rr0/oliphaunt/issues/212). +- [#213 — Wasmer dependency-family/backport convergence](https://github.com/f0rr0/oliphaunt/issues/213). + +Both issues contain bounded investigation and acceptance criteria, reference +overlapping existing work, and are excluded from task 30 completion. Existing +browser-host ownership/build fixes remain in task 12. Optimization changes are +deferred, not a hidden acceptance requirement. The subsequent src/broker/mobile +amendment below adds scoped PG wire and UniFFI investigation and migration work; +it does not unpark #212/#213 or authorize optimization changes. + +## Broker PG wire and generated mobile bindings — follow-up decision + +The user authorized deeper delegated UniFFI investigation, PG wire broker +planning, the C-error fallback and RN consolidation. These are now tasks +09c/09d,10a/10b and 20a, not unassigned future suggestions. Planning does not +claim that prototypes or platform qualification have run. The following +contracts supersede the earlier broker-preservation-only scope. + +### Broker: standard PostgreSQL traffic plus minimal management (10a,10,10b) + +Preferred target: + +```text +Rust/TS SDK or ordinary PostgreSQL driver + → PostgreSQL wire endpoint → broker-owned embedded native session +Owning SDK + → small private management endpoint → backup / process shutdown +``` + +The current PGOB envelope already carries PostgreSQL request/response bytes. +Remove that envelope from SQL traffic. PostgreSQL supplies startup negotiation, +authentication messages, parameters/results/errors, streaming message sequences, +transaction status, Terminate and a separate-connection CancelRequest mechanism. +Cancellation therefore belongs on PG wire, not in a parallel custom cancel RPC. +Termination of a SQL connection is distinct from terminal shutdown of the owned +broker process; preserve that distinction explicitly. + +Reuse the existing management transport narrowed to authenticated backup and +shutdown, with bounded payload/error handling. This avoids inventing HTTP/gRPC, +another schema generator, or a second query protocol. Startup configuration and +resource selection remain process-launch inputs; endpoint readiness remains an +owned startup result. No generic admin API or remote management service. Current +broker IPC has no restore request: TS restore uses the native binding separately. +Trace Rust/TS restoration before claiming addon-free restore; preserve the +existing operation or use a narrowly scoped pre-open broker helper if required +by the final installation contract. Do not invent a live restore command merely +to fill a management API. Do not equate the native physical archive with the +standard PostgreSQL replication BASE_BACKUP protocol, or disguise process +commands as SQL statements/extensions. + +This remains embedded execution with one active backend. Initially admit one +SQL client and reject a second promptly rather than interleaving sessions or +silently pooling transactions. A subsequent connection may reuse the process +only after proved session reset; otherwise end/restart that broker instance. +Preserve existing reopen/persistence behaviour through the owning SDK. Do not +advertise independent concurrent sessions, replication or full server feature +parity merely because ordinary drivers can connect. + +Concrete source gaps to prove before cutover: + +- native liboliphaunt_protocol.c validates a supplied request, streams output and + waits for ReadyForQuery. An ordinary driver can send Parse/Describe/Flush and + wait for a reply before sending Sync. A complete-buffer API cannot be assumed + to support this incremental exchange. Demonstrate a bounded native protocol + pump with input/output progress and real message boundaries; make the smallest + necessary native ABI addition if required. Never append fake Sync messages or + buffer indefinitely, since that changes transaction/protocol behaviour. +- The current WASIX proxy has startup/protocol-pump machinery, but its + CancelRequest branch closes the connection without routing cancellation. + Reuse only proven portions. Supply valid per-session BackendKeyData, validate + CancelRequest secrets and invalidate stale keys on teardown; route cancel + independently of a busy SQL worker. Negotiate an explicit protocol version + and implement its matching key format (PG18 supports newer minor negotiation; + do not advertise it while assuming every cancel key is four bytes). +- Preserve private endpoint binding and fresh process credentials. Use standard + PG authentication for SQL and retain authenticated management. A supported + local-only password exchange can carry the existing ephemeral credential; + do not add a homegrown password scheme, expose credentials in logs, or claim + internet-facing TLS/server authentication support. Validate requested database, + user and startup settings against the owned session rather than acknowledging + unsupported changes. ParameterStatus must reflect actual settings. +- PG errors remain PG errors and transaction status is preserved. Transport or + native failures that leave session state unknown close the session; no query + replay. A client callback failure remains local: drain to a confirmed protocol + boundary (or cancel/close when needed) before reuse, then return the callback + error. Normal SQL streaming no longer needs a custom callback-aborted frame. + +Task 11's pgwire-server extraction is the initial reuse point. Share real +framing/startup/socket plumbing between native broker and WASIX proxy when it +removes duplication; make the existing WASIX engine dependency optional so a +native broker cannot pull in Wasmer/compiler assets. Keep runtime-specific +execution behind narrow real adapter functions, not a new universal executor. +Evaluate the low-level codec/startup facilities of sunng87/pgwire against this +existing code before choosing a new dependency. Its full SQL-handler server +framework is not automatically useful when PostgreSQL already processes SQL; +avoid decoding and rebuilding every result through a second query engine. + +Proof uses an installed broker with psql and independent Rust/TS clients: +simple/parameterized/prepared queries, transactions and rollback, notices/errors, +fragmented/coalesced packets, Flush before Sync, supported pipelining and clear +rejection of unsupported COPY/features without hanging. Exercise slow readers, +bounded buffers, cancellation during saturation, stale/invalid auth/cancel keys, +disconnect during transaction/stream, second-client rejection, backup ordering, +shutdown and parent death. Preserve every existing supported raw-protocol +behaviour; document extensions to support only after demonstrated. Run focused +Linux proof early, then Unix/macOS and Windows packaged transports on their +actual hosts. Compare maintained code/dependencies and final package size before +removing the old path. Temporary A/B fixtures are deleted after cutover. + +If the necessary native pump cannot preserve behaviour without disproportionate +runtime redesign, report the concrete blocker and revise this plan before +cutover; do not claim 10b complete while shipping two permanent query protocols. +This is a product-boundary experiment, not permission to silently reduce scope. + +Sources: [PostgreSQL message flow](https://www.postgresql.org/docs/18/protocol-flow.html), +[pgwire implementation](https://github.com/sunng87/pgwire). + +### UniFFI shared mobile implementation, with C fallback (09c,09d) + +The source/docs review led to the implemented shared mobile bridge below. +The platform acceptance gates remain distinct from the completed migration: + +```text +src/sdks/rust/ + liboliphaunt-native/ # shared native operations/error/lifetime; linked + dynamic + sdk/ # existing serialized session/query API + mobile-bindings/ # private Cargo build project: UniFFI exports +src/sdks/swift/ # generated binding + thin idiomatic/platform facade +src/sdks/kotlin/ # generated binding + thin idiomatic/platform facade +``` + +mobile-bindings consumes the actual direct Rust implementation and shared query +crate; it does not reimplement queues, SQL conversion or database operations. +Use direct-only Cargo features to exclude desktop broker/server/carriers from +mobile builds. Keep the native bindings crate independent of the public SDK. +No extra public registry identity/changelog: generated code and native interop +artifacts ship with the consuming Swift/Kotlin products. Use Rust proc-macro +exports as the interface authority, not a second hand-maintained UDL definition. + +Required feasibility work: + +- Rust's existing ffi.rs dynamically loads symbols; Apple's C bridge also uses + linked symbols and static extension registration. Implement/prove the explicit + linked route in the shared bindings; preserve dynamic/custom paths on supported + platforms. Keep mobile resource lookup at its native integration boundary. +- UniFFI exports need Send + Sync objects. Wrap the existing serialized owner + session, not raw native pointers with unsafe marker traits. Native execution + remains on the owner thread. Use foreign-driven futures where sufficient; + no second Tokio runtime or executor merely for binding generation. +- Foreign future/task cancellation must reach PostgreSQL's independent cancel + path and reconcile admitted work before allowing another operation. A dropped + future alone is not cancellation or evidence of a reusable session. Preserve + queue admission, transaction exclusivity, rollback, streaming backpressure and + callback failure. Async borrowed buffers must not outlive the original call; + use owned bounded chunks and measure copies rather than claiming zero-copy. +- Kotlin wrapper disposal/close is not safe database shutdown. Give the internal + operation a distinct name such as shutdown; public SDK close awaits it before + disposing the binding. Keep generation-safe stale calls, concurrent close, + terminal session handling and reopen/persistence semantics. +- Account for stable Kotlin/JNA Android AAR dependencies and callback-thread + attachment, supported ABIs, API floor, native load order, R8, notices and size. + Do not quietly switch to an experimental generator to evade packaging cost. + Verify the exact pinned generator with this repo's Swift 6 strict-concurrency + settings; documented async/Sendable limitations need actual compiler evidence, + not blanket warning suppression. + +Prototype acceptance uses existing behavioural scenarios and minimal clean +Swift/Kotlin consumers, not a new test framework: parameterized queries and +SQLSTATE, transactions, streaming with a slow/rejecting callback, cancellation +before/after admission and under queue saturation, shutdown/reopen/stale objects, +backup/restore and terminal failures. Prove selected static src/extensions/resources, +Android arm64 plus remaining declared ABI packaging, and Apple device/simulator +and macOS support on the relevant hosts. Measure query/stream/backup allocations, +copying, binary size and dependency/build cost versus the current bridge. +Linux-only generation cannot close Apple/Android behaviour acceptance. + +On success, delete the replaced Swift C bridge, Android JNI native bridge and +duplicated proven-shareable query/session implementation. Keep idiomatic public +facades and real platform integration. On failure, record the reproducible +constraint and take the already-authorized fallback: use existing _with_error +operations in the surviving bridges and delete redundant error-copy/storage +logic. Cancel has no _with_error entry point; retain correct immediate error +capture for that call and bridge-originated errors. If UniFFI succeeds, it +inherits Rust's error capture and no separate cleanup of deleted bridges is +needed. Permit a different outcome per platform only with concrete evidence; +never keep two interchangeable implementations for one target. + +Generated source and native binaries must use the same pinned generator/interface +inputs and freeze together. Declare Cargo/Moon and Swift/Gradle producer edges; +shared implementation changes select affected SDK builds/releases, while the +private adapter has no independent release ceremony. Prove clean packaged +consumers and idempotent release-PR dependency/version updates. Build consumers +never secretly regenerate a different binding from a published binary. + +UniFFI is in-process FFI, not process isolation. The reviewed RN +NativeDirectProcessOwner is not proof of Android Binder/services or an Apple +extension implementation. Preserve actual shipped direct behaviour and reconcile +PR #126/research separately before asserting an isolation implementation exists. + +Sources: [UniFFI async](https://mozilla.github.io/uniffi-rs/latest/futures.html), +[object constraints](https://mozilla.github.io/uniffi-rs/latest/types/interfaces.html), +[Kotlin lifetimes](https://mozilla.github.io/uniffi-rs/latest/kotlin/lifetimes.html), +[Gradle/JNA](https://mozilla.github.io/uniffi-rs/latest/kotlin/gradle.html), +[Swift](https://mozilla.github.io/uniffi-rs/latest/swift/overview.html), +[buffers](https://mozilla.github.io/uniffi-rs/latest/types/bytes.html). + +### React Native common JSI mechanics (20a,20) + +Both ios/Oliphaunt.mm and android/src/main/cpp/OliphauntJsiBindings.cpp implement +similar acknowledgement mutex/condition-variable/error state, buffer validation, +promises and stream teardown. Share those mechanics in src/sdks/react-native/cpp, +included directly by CocoaPods and CMake. No separately published common-bridge +package or new framework. Keep JNI/Objective-C++ conversion and actual Swift/ +Kotlin SDK integration platform-specific; RN does not go through desktop napi-rs. + +Do not simply copy iOS's global weak acknowledgement registry into common code: +Android's pending-stream ownership differs. Make pending callbacks/promises and +acknowledgements belong to the actual RN runtime/stream lifetime, so one runtime +invalidating cannot abort another's work. Use real existing RN lifecycle hooks. +Prove JS-thread-only JSI access, exact ArrayBuffer/view ranges, owned async bytes, +settle-once promises, cancel/rejection, invalidation during acknowledgement wait, +reload, bounded slow-consumer memory and no access after runtime destruction. +Share source tests of the common mechanics once; retain final Android/iOS/Hermes +tests for their integration differences, not two copies of the same helper suite. +Do not advertise legacy architecture or new process isolation as part of this +cleanup. Existing RN codegen stays where it covers the real API; do not assume +it replaces binary streaming merely because it generates open/cancel/close. + +### Swift/Kotlin platform ownership checkpoint — 2026-09-11 + +Swift build/source tests/coverage are portable and use a separate requires-swift +capability. Linux CI provisions Swift 6.3.3 from src/sdks/swift/.swift-version through +setup-swift commit d8e84bc3a450686a95474d7d6fa4a3301498debc; upstream labels +v3 beta. The pinned implementation uses signature-verified Swiftly 1.1.0 on Linux. +Apple jobs retain pinned Xcode. Compiler-free source archiving and release metadata +staging run on Linux; Apple bundle behavior and native first-open remain Apple +tasks. Native first-open currently requires macOS initdb or a packaged seed. +Kotlin native bridge tests now run independently of Gradle/Android SDK setup. +Linux proof: 95 Swift tests with coverage, Swift checkout/extracted archive builds, +full JNI translation-unit compilation, C/C++ owner tests. Real Apple package/app +qualification still requires the platform artifacts and runner. + +### Native broker PGwire checkpoint — 2026-09-11 + +The ignored `target/broker-pgwire-proof` standard-startup proof now admits real +`pg` and packaged `psql` clients with fresh process authentication, actual backend +ParameterStatus values, per-session BackendKeyData and independent standard +CancelRequest routing. Verified behavior includes prompt second-client rejection, +parameterized SQL, cancellation/recovery, stale cancellation rejection, sequential +transaction/temp reset, malformed startup, explicit protocol3.2 rejection, +COPY output/input, and a stalled Node socket reader followed by successful reuse. + +Interactive COPY exposed a real native boundary gap: preassembled COPY requests +worked, but Query closed incremental input before a client could answer +CopyInResponse. The native scanner now opens bounded COPY-only input after that +response and closes it after CopyDone/CopyFail. It does not reopen ordinary +commands. The rebuilt native library passes the full host C aggregate, including +new successful incremental COPY and CopyFail recovery cases, and actual psql +interactive COPY insertion followed by SELECT. + +This supports continuing PGwire consolidation; it does not authorize deleting +the existing broker yet. The authenticated startup proof and earlier Flush/feed +proof still need a single bounded input/output lifecycle, management operations, +parent-death cleanup and supported-platform validation. The disposable COPY +callback blocks on client input and is explicitly unsuitable as the final +transport. Reuse common framing and forward native response bytes; do not add +another SQL execution/result-encoding framework. The proof's small line count +does not include those remaining production obligations and is not a claimed +maintenance reduction. Detailed commands/evidence and limitations are retained +in the ignored proof README and `/tmp/oliphaunt-patch-proof/native-copy-smoke.log`. + +### Resource release and Windows packaging checkpoint — 2026-09-11 + +The resources owner now has independent CI upload groups for canonical ICU, +desktop/mobile native seeds and portable WASIX seeds. Release collection selects +these artifacts from the qualified commit/run, packages registry carriers and +freezes their actual archives with the publication lock. Seed archives and their +compatibility manifests are public resource assets; the full producer requires +every declared physical target/profile before writing the release checksum. +Local ICU packaging remains independent of seed production. Shared Maven staging +now lives under tools/packaging; Kotlin retains its own publication integration. +Maven manifest/staging, checksum and publication catalog tests pass (15 tests). +This does not establish a complete multi-platform resource release: real mobile, +macOS and Windows seed production and installed consumers remain qualification gates. + +Windows runtime packaging now uses Bash and the existing common extension guard, +VC closure, payload, compatibility and archive tools instead of a 276-line +PowerShell implementation. Native build/package dispatch, shared guard behavior +and Shell syntax pass locally. The 3102-line Windows compiler has also been +replaced with Bash orchestration and extension-owned TypeScript source generation; +only explicit Visual Studio machine setup retains PowerShell. Native commands +remain Shell commands, and both server and embedded modules retain the MSVC +provider/import-library and app-local VC runtime checks. Pinned Meson/Ninja +installation belongs to machine setup. Compiler/source identity changes invalidate +the Windows dependency prefixes as well as PostgreSQL outputs. + +The actual pinned pgcrypto, uuid-ossp, pg_hashids, pg_ivm, pg_uuidv7, +pg_textsearch, vector, PostGIS and pgTAP sources pass local source/SQL generation; +Meson 1.10.0 parses the generated recipes, and repeating source/SQL generation +produces byte-identical trees. This caught and corrected a broken +PostGIS source-list template before cutover. Build/package dispatch preserves a +Windows compiler's failing exit status; seven VC runtime closure tests and Shell +syntax/lint pass. These host-neutral checks do not prove compilation: task 24d +remains open until actual MSVC builds, Windows spaces/Unicode/PATH/setup behavior, +and clean installed consumers pass on Windows. + +The Windows compiler reads PostgreSQL version, archive checksum and URL from the +canonical PostgreSQL source manifest; its cache includes that reader and fetch +implementation. The combined workflow checks pass after cutover, including +50 graph/handoff tests. Mobile app jobs now download their explicitly declared +ICU seed and canonical ICU archive from `database-resources`, rather than looking +for a seed inside the runtime carrier. Their task graph retains ABI proofs and +the selected resource producers; the seed staging CLI validates the archive, +target, profile and ICU digest. Actual mobile app execution remains outstanding. + +Release compatibility synchronization now handles equivalent inline and table +Cargo dependency syntax through the existing dependency editor. Nine release +sync tests pass, including retained fields, repeated synchronization and the +generated release fixed point. + +### Native archive validation ownership — 2026-09-11 + +Desktop runtime `package-runtime-desktop-target` now assembles and statically +checks the distributable without starting PostgreSQL or running the C suite. +`test-artifacts-desktop-target` depends on that package, extracts the final bytes, +and runs the existing ABI/runtime harness and Linux glibc baseline execution. +The harness still uses internal PostgreSQL headers, so this is explicitly an +artifact test rather than a clean public consumer test. Its existing native CI +lane retains this qualification. The local built-runtime command is named +`test-integration`; no forwarding `host-smoke` alias remains. +Rust SDK integration consumes the native build directly rather than rerunning +the native C suite as a prerequisite. Native tests retain their own task/CI owner. + +Removed the macOS smoke harness's handwritten subset of iOS source syntax checks: +actual iOS target compilation covers those sources and more. Removed duplicated +native/WASIX ICU uploads and their CI/release byte-comparison helper: resources +now produces one canonical data artifact, and real native/WASIX collation probes +exercise it. Canonical resource upload and release collection remain intact. +Removed the central native npm notice fixture, which restaged fake payloads and +assumed tools/ICU lived under the runtime; the runtime, tools and resources +packagers already validate notices in their actual final npm archives. Packaging +inputs no longer include unrelated compatibility/binary-contract test files. +The complete workflow aggregate passes after this split (50 graph/handoff tests), +as does ordinary release metadata and frozen-lock validation. An additional +affectedness case confirms smoke-source edits select the artifact test without +marking the compiler or packager inputs changed; the required final package +remains in the execution dependency graph. Native execution evidence is recorded +separately from these portable checks. + +### Selectable mobile resource checkpoint — 2026-09-11 + +`src/database-resources/seeds/package-mobile-carriers.mts` adapts canonical raw seed +archives into the existing bound mobile resource layout. It validates target, +profile, archive digest, physical compatibility and canonical ICU tree binding. +Android standard/ICU seeds use independent `dev.oliphaunt.runtime` Maven carriers; +the existing plugin selects at most one seed profile and resolves the resource +version independently of the native runtime. Existing PGDATA and runtime cache +materialization no longer require an initialization seed. + +Swift resources now belong to a separate source package exposing +`OliphauntSeedNativeIOSStandard`, `OliphauntSeedNativeIOSICU`, and `OliphauntICU`. +The SDK source package contains none of those payloads. A real local SwiftPM +consumer builds the SDK and all selectable resource products and reads their +bundles. This proves package composition with fixture PGDATA, not Apple runtime +execution. The resource source archive includes both profiles; the selected +targets determine application bundle contents. + +Remote SwiftPM needs a distinct repository identity from the SDK. The existing +source-tag publisher now accepts an explicit resource product/repository and +projects its frozen source ZIP into a standalone Git tree, retaining notices and +source commit/tree provenance. It uses the existing bounded push/reconciliation +mechanism. Local bare-repository tests prove deterministic projection, semantic +tags and resumption, while preserving SDK source-tag behavior. No remote resource +repository or tag has been created; the distribution decision is pending. + +Validated: 96 Swift owner tests, Android SDK unit tests, Java/Kotlin compilation, +mobile archive adaptation/rejection tests, resource Maven staging, the local +SwiftPM consumer, and all three source-tag publisher behavior tests. The Android +plugin aggregate now passes after the generated legal receipt was refreshed. +Native npm leaves carry one unpacked PGDATA tree and its logical tree digest; +Cargo leaves retain the compressed include-bytes interface. The iOS npm leaf +contains one resource bundle and resource-only CocoaPod, discovered from the +actual packed fixture by both React Native CLI and Expo autolinking. ICU remains +the existing separately composed canonical data dependency. + +The obsolete runtime root receipt and its Swift/Kotlin/Gradle readers are gone. +Runtime target/static-registry binding stays in the actual runtime manifest. +Expo runners take one explicit resource seed directory and reuse its owner +validator, replacing the duplicated Shell contract checks and mandatory two-seed +copy. The selected archive staging CLI and runner composition pass locally. +Actual mobile seed production, Apple CocoaPods installation and Android installed +consumers remain aggregate qualification gates; packaging fixtures do not prove +that PostgreSQL can open those fixture databases. + +### Seedless Linux archive checkpoint — 2026-09-11 + +The current Linux runtime packages without initialization seeds, ICU data or the +obsolete root seed receipt. The consumer task extracts the finished archive and +passes the glibc 2.38 baseline plus the existing native ABI and C lifecycle suite, +including incremental COPY, repeated cancellation recovery, backup/restore, +detach/reopen and terminal shutdown. Packaging and consumer execution now have +separate task ownership. + +The actual npm carrier passes payload, executable-mode and notice validation. +The actual Cargo parts and aggregator install from extracted `.crate` files in +an isolated offline consumer; its reconstructed payload matches the tested +release archive byte for byte. Native npm packaging accepts an explicit target +and asset directory so this Linux check needs no fabricated platform artifacts. +Mobile release validation retains semantic target/mode/static-registry and ABI +checks, without restoring removed seed receipts or exact-text size reports. + +### UniFFI feasibility checkpoint — 2026-09-11 + +The ignored `target/uniffi-native-proof` pins UniFFI 0.32.1 and consumes the real +shared Rust NativeSession. Generated Swift compiles with Swift 6.3.3, language +mode 6, complete strict concurrency and warnings as errors. Generated Kotlin +compiles with the SDK's Kotlin 2.2.21 and coroutines 1.10.2 plus JNA 5.14.0. +A private error field named `message` conflicted with Kotlin Throwable; `detail` +avoids that generator collision without modifying generated code. + +Actual Swift and Kotlin host consumers pass SQLSTATE propagation, transactions, +slow and rejecting stream callbacks with recovery, independent cancellation, +backup, detach/reopen, stale shutdown and terminal shutdown. Shared bindings now +accept explicit current-process symbols for host-prepared Unix inputs, using the +same typed symbol table and lifetime/generation machinery. The same Swift proof +passes with liboliphaunt linked into the executable and no runtime library path. +This proves Linux dynamic/current-process loading, not Apple static linking. + +This initial synchronous prototype was superseded by the production shared async +owner described in the 09d checkpoint below. Rust owner integration, request-scoped +cancellation/rollback, shared static registration and Android AAR/ABI packaging +are implemented and tested. Remaining qualification covers Android device/R8, +Apple application execution, and measured shipping size/copy/build cost; it does +not require another bridge implementation or retaining the deleted C/JNI bridges. + +### Task 17/18 checkpoint — explicit WASIX ICU input (2026-09-11) + +Rust WASIX accepts `IcuData::new(data_bytes, manifest_bytes)` through synchronous, +asynchronous and prepared-session APIs. Construction verifies the canonical data +identity and logical tree digest once; clones share immutable bytes. Explicit data +requires no Cargo `icu` feature. That feature remains an optional resource-carrier +convenience for Rust applications. Runtime caches use the selected data digest, +replacing the old profile-only global selection; seed compatibility checks compare +the actual installed ICU tree rather than assuming a particular package carrier. + +The existing resource integration task now extracts the independently packaged ICU +artifact and runs without the `icu` feature. Both real standard/ICU scenarios pass: +seeded memory/directory storage, unusable-seed-free reopen, unseeded initdb, persisted +SQL and ICU collation ordering. Tampered data is rejected before opening storage. +Also passed: 148 library tests and all-target Clippy with optional Cargo ICU enabled. +The two removed tests exercised a deleted profile-only cache helper and a deleted +test-only ICU receipt helper. TS/browser/addon adaptation remains a separate active +checkpoint; these results do not close all runtime carrier cleanup. + +Ownership correction: ICU/tool Rust formatting and Clippy now belong to +`database-resources` and `src/postgres-tools/native`; native runtime packaging no longer +invokes ICU packaging tests. The actual seedless native Cargo carrier fixture passes +extracted-consumer compilation and repeat-byte checks. Desktop archive behavior is +being checked against real compiled outputs, separately from this Rust WASIX proof. + +### Tasks 17/18/21 checkpoint — producer and owner boundaries (2026-09-11) + +The WASIX runtime producer no longer invokes the seed generator, declares seed +manifest entries, or exposes bundled seed accessors from its portable Cargo crate. +Its maintainer xtask no longer depends on the seed runner, Tokio, WebC or +wasmer-wasix; AOT serialization retains only the Wasmer compiler dependencies it +uses. Runtime/initdb modules and artifact/source integrity checks remain. +Portable release/npm staging excludes independently owned seeds, ICU and tools. +The old runtime-owned ICU npm producer is deleted. The Cargo payload check now +accepts the actual seedless runtime closure. Producer/portable Rust tests and AOT +serializer compilation pass; 13 Cargo/npm/release staging tests pass. A fresh +compiler build is required: the old prepared-source fingerprint was correctly +rejected. That build also exposed a removed ICU helper call; the WASIX builder now +uses the same canonical raw-data installer as native. Fresh build and final AOT +qualification are still in progress, not covered by fixture package tests. + +Extension contracts now live in `src/extensions/contracts`. Real cross-language +behavior data lives in `test-fixtures`; the native-only archive fixture lives +with native C smoke tests. The unused descriptive fixture manifest was deleted. +Imports, package fixture projection, Gradle resources, evidence paths and Moon +inputs follow those owners. Existing extension/catalog package tests (16) and +shared native Rust tests (60) pass, and Moon resolves the changed project graph. +Four previously compressed SDK Moon files are readable block YAML with identical +parsed task definitions. Running the SDK-owned Bun commands (which load their +declared test setup) passes 349 WASIX SDK tests and 11 WASIX tools tests without +compiling a runtime. Root-level ad hoc test invocation bypassed that setup; it is +not a substitute for those package commands. Actual installed-carrier integration +continues separately against rebuilt artifacts. + +Native desktop packaging and Windows compilation read the canonical extension +file inventory through Bun instead of compiling the Rust SDK and packaging CLI +to print it. The obsolete Rust workspace/xtask/packaging source inputs are removed +from the desktop compiler task. The existing extension-exclusion guard still +rejects installed optional control, module and data files. This does not remove +the mobile resource packager or its actual runtime resource assembly. + +### 2026-09-11 native addon shutdown correction + +Actual installed standard-seed consumers exposed an intermittent Bun 1.4.2 +shutdown fatal banner despite successful queries and exit status zero. The +pinned upstream `NapiEnv::cleanup` aborts threadsafe functions after invoking +async hooks without waiting for their completion signal. The production addon +now uses one synchronous native cleanup hook: quiesce callback admission and +acknowledgements, cancel/drain native operations, join their worker threads, +then perform generation-owned terminal close. Native operations need no +JavaScript progress here; competing opens acquire their lease immediately or +fail. Completed operation threads are reaped at subsequent admission. The +async hook/acknowledgement reaper is removed, not ignored on shutdown errors. + +The shipping release-profile addon passes all 57 lifecycle cases independently +on Node and Bun. Actual ABI11 PostgreSQL workers pass termination during open, +query, queued query, stream callback and stale copied-addon ownership on both +hosts; backup finishes before terminal close. Twelve repeated real Bun standard +seed close/reopen/exit consumers finish without the prior banner. The regular +addon lifecycle task now runs both hosts and rejects Bun fatal banners even +when a child exits zero. The final installed resource matrix is validated after +this rebuild separately; no Apple or Windows execution is implied. + +### 2026-09-11 UniFFI shared async owner and cancellation proof + +The SDK now has a gated `mobile-bindings` entry for prepared native inputs that +opens the existing `EngineExecutor`; generated mobile calls no longer need the +prototype mutex or a second queue/runtime. Default `desktop` features retain +the existing Rust SDK behavior, while disabling defaults excludes broker, +server/process/socket modules and the broker dependency from mobile compilation. +The direct-only library passes Clippy and 95 owner/source tests; the default +desktop build with the mobile entry enabled passes 110 tests. + +`mobile::Request` provides one-use request cancellation through that same owner. +Queued/active/finished authority prevents old or queued cancellation from +targeting later SQL. Dropping its admitted future cancels only that request; +abandoned queued requests are never executed. Existing ordinary Rust future +drop behavior is unchanged. Streaming reuses the existing callback/error and +ReadyForQuery recovery path. The focused owner test covers cancellation and +abandoned queued work without source/layout assertions. + +Actual generated Swift 6 strict-concurrency and Kotlin/JNA consumers pass async +query, SQLSTATE, transaction, slow/rejected streaming with recovery, explicit +cancellation, backup and detach/reopen against ABI11. Real Swift Task.cancel and +Kotlin coroutine cancelAndJoin stop a 60-second sleep within three seconds, +preserve the subsequent request, and prevent a cancelled queued CREATE TABLE. +UniFFI 0.32.1 Swift does not propagate Task cancellation into Rust automatically: +the thin Swift facade must use withTaskCancellationHandler and the generated +request handle. Kotlin abandons the Rust future through its generated finally +path. No generated source is patched to obtain these results. + +The generated consumer remains an ignored proof until private mobile Cargo +packaging, selected static extension registration, typed facade migration and +actual Android/Apple application gates are complete. Existing C/JNI bridges +remain; hosted Linux Swift/JNA execution is not mobile installation proof. + +### Implementation checkpoint: TypeScript broker and native test ownership + +- The TypeScript broker now uses PostgreSQL startup/password authentication, + raw SQL/result frames, BackendKeyData and standard CancelRequest. Its separate + PGOB management channel has only authentication, backup and terminal close; + SQL/chunk/callback-abort/cancellation RPC variants were deleted. +- A callback failure drains every promised ReadyForQuery boundary and preserves + the original callback error. Transport failure retires the handle. Concurrent + socket writing/reading prevents large pipelined requests from deadlocking. +- `oliphaunt-js:test-native` and `bun run test-native` own the native SDK contract; + the old examples-owned task/script and duplicate Deno entrypoint are removed. + Moon builds the SDK/query, native runtime, broker and addon before this test; + the shell recipe also runs against already built inputs. The same built SDK + runs on Node, Bun and Deno in direct/broker modes, source/restored processes, + with typed queries, backup/restore, persisted reopen and callback-abort recovery. + The PostgreSQL driver checks server connections separately in that recipe. +- Linux verification: 69 SDK source tests, typecheck and lint pass; the complete + SDK-owned native recipe passes all host/topology/restore combinations plus + the server test. An earlier fresh packed-SDK resource matrix passed all 18 + host/topology/resource combinations; its teardown diagnostics led to a broker + reset fix, so final packaged evidence must be refreshed after the daemon work. +- This checkpoint does not qualify Windows/macOS, unfinished partial-protocol + disconnect handling, final carriers, or publication. Those remain explicit + integration gates; no release or hosted workflow was dispatched. + +### Native installed-consumer CI checkpoint (2026-09-11) + +`oliphaunt-js:test-consumer` installs the packed SDK and query dependency in a +temporary consumer, extracts the Linux runtime/src/broker/addon candidates, and runs +the existing Node/Bun/Deno direct, broker and server behavior. The same archived +broker is exercised by `oliphaunt-broker:test-consumer`, including the ordinary +PostgreSQL client, incremental Flush/Sync, COPY, cancellation and disconnect +tests. Both owner tasks share the Linux `native-consumers` job and consume +downloaded producer outputs without recompiling native artifacts. The installed +SDK recipe and both broker protocol tests pass locally against ABI 11 artifacts. +The addon and broker owner packagers separately validate their corrected Rust +dependency notices, SPDX metadata and exact upstream source provenance; the last +notice-only refresh preserves the binaries exercised by these consumer tests. + +Explicit platform requirements live on these consumer tasks. The planner derives +dependency-only producer host requirements from Moon edges; an SDK-only change +or SDK qualification needs Linux candidates, while directly selected native, +broker or addon producers retain their platform matrices. Consumers without an +explicit platform bound retain existing coverage. No source-path whitelist is +introduced. Hosted platform qualification and cross-commit native reuse remain +unproven. The TypeScript producer pilot uses Moon CAS with integrity verification +enabled and records actual task hashes and current uploaded artifact identity; +it does not bypass exact-source candidate checks. + +### Swift binary producer handoff checkpoint (2026-09-11) + +`oliphaunt-swift:package-bindings` runs on the macOS `swift-bindings` job with +the three Apple Rust targets installed. It uploads its XCFramework, canonical +checksums and generated bindings source. Linux `swift-sdk-package` downloads +these outputs and explicitly transfers that producer dependency before source +and release assembly. Swift's fixed public asset catalog now includes the +bindings ZIP and checksum manifest; publication freezes both from the SDK's +single `release-assets` directory. The 21 publication-lock tests pass, including +these asset identities. Actual XCFramework construction still requires macOS +qualification; Linux graph and publication tests do not prove Apple binaries. + +### Final carrier and docs checks (2026-09-11) + +- Native packaging now calls `liboliphaunt-native-bindings` directly. The public + Rust SDK no longer exposes a private packaging feature/reexport bridge. All + 72 existing packaging tests and Clippy pass before the unused-tooling prune. +- Linux baseline command tests now run from Shell and do not duplicate pinned + version strings. They exposed a broker output-path escape: canonicalization + now precedes the target-directory guard and deletion. Parent traversal and + symlink tests preserve an outside sentinel; bad image digests are rejected. +- Extension legal tests retain actual staged/archive byte, SPDX, and corruption + checks; copied whole-catalog lists, fixed product counts and repository-layout + assertions are removed. The remaining 11 legal behavior tests pass. +- The real WASIX contrib bundle packages all 32 members and passes the existing + carrier validator. Its canonical tar excludes directory records; Cargo seed + archives retain empty directories. This fixes the shared archive writer at + the producer option without weakening either consumer contract. +- Final broker and addon archives include target-specific Rust notices and + exact source-download links. Current broker legal tests pass; object key order + is irrelevant, while missing/extra keys and altered legal bytes still fail. +- Docs check, production build, exported-site smoke and published-version/ + refresh-request tests pass from `docs`. Current guides use completed public + releases. No Vercel deployment or production-settings change was performed. +- Swift/Kotlin public facade integration, React Native JSI ownership, remaining + Shell test orchestration, and single-tree release PR preparation continue. + Apple/Windows/device execution and the final exact-commit hosted qualification + remain required; these local results do not close task 30. + +### Deno shared-addon retest: task 09b remains blocked (2026-09-11) + +The existing Deno FFI path was still selected during earlier installed-SDK +checks. Those results must not be described as Deno addon qualification. +With the current synchronous-cleanup Rust addon selected experimentally, the +complete native SDK source/restored recipe passes on Deno 2.8.1. The shipping +addon lifecycle harness nevertheless fails `worker-terminate-stream-delivery-wait`: +its process exits zero after `init`, `stream-started`, `stream-callback-blocked`, +without the required `stream-aborted` and terminal `close`. No timeout or missing +method assertion was substituted for that native cleanup observation. + +The default keeps Deno FFI until this lifecycle case passes. Its old duplicate +Bun selection branch is removed. The existing lifecycle harness can now run +under Deno with its actual CLI flags and `parentPort.unref()` (Deno's Node port +has no `close()` method); it provides a repeatable migration diagnostic without +introducing a second suite or a knowingly failing supported-product CI gate. +See the [pinned Deno worker implementation](https://github.com/denoland/deno/blob/v2.8.1/ext/node/polyfills/worker_threads.ts). +Logs: `/tmp/deno-shared-addon-native-consumer.log` (ordinary behavior passes), +`/tmp/deno-current-addon-cleanup.log` (required cleanup fails). FFI source and +its existing behavioral tests remain; task 09b is not complete. + +### 2026-09-11 production Swift/Kotlin shared bridge checkpoint (09d) + +Swift and Kotlin now use private `src/sdks/rust/mobile-bindings` UniFFI bindings and +the existing Rust executor/session implementation. The old Swift C session bridge, +Kotlin JNI session bridge, and queue/cleanup-only tests are removed. Public query +and transaction APIs and resource preparation remain intact; this is an in-process +binding migration, not evidence of mobile process isolation. Request-scoped +cancellation drains started work, skips abandoned queued +work, and cannot cancel later requests. Transaction cleanup runs independently of +the canceled user request. + +Linux proofs pass: 94 Swift source tests; Swift public native SQL, parameters, +SQL error recovery, callback identity, cancellation, canceled transaction rollback, +backup/restore; Kotlin public facade through generated JNI with SQL, cancellation, +transaction rollback, callback recovery and backup. Kotlin source tests and +Spotless pass with Gradle configuration cache. Both published Android ABIs compile; +actual Maven AAR/source/Javadoc carriers pass validation with their exact 61-crate +Rust license closure. Existing shipping Node/Bun addon lifecycle suites pass 60 +cases each, including shared selected-extension registration and rejection before +initialization. + +The Swift recipe builds three Apple static-library framework slices with the same +per-target Rust license closure, freezes their ZIP/checksum, and stages generated +Swift source in the SDK source carrier. The renderer validates these inventories. +A minimal C link anchor retains the runtime resolved dynamically by Rust; an +actual Linux `--as-needed` link/current-process lookup proves that mechanism. +Eleven focused Swift carrier tests pass. + +Apple framework compilation and installed SwiftPM execution, and Android device +qualification, remain explicit platform gates. Linux proofs do not close them. +The existing language-side typed query implementations remain; this checkpoint +consolidates native execution and ownership, not every public facade operation. + +### Task 27a/27b implementation checkpoint — one local release candidate + +Release Please 17.3.0 is now a pinned private maintainer dependency. Its library +generates the candidate locally; the existing graph supplies shared shipped-source +ownership to its normal commit processing. Release Please alone chooses versions, +changelog entries and native ecosystem updates. The separate shared-contrib +candidate creator and handwritten bump/changelog engine have been removed. +Changelog dates use the exact source commit date through the library's template +option. Native updater composition and optional missing workspace lockfile +semantics are preserved; the existing derived closer owns compatibility fields +and real workspace lock regeneration. + +`prepare-release-pr.sh` checks the existing merged-but-unpublished lifecycle and +creates local updates. `close-release-candidate.sh` closes derived metadata and +validates the complete tree before `.github/scripts/publish-release-pr.sh` writes +anything remotely. The publisher retains canonical PR identity, exact main SHA, +and lease checks. It reuses an unchanged candidate commit, reconciles an ambiguous +PR creation on retry, and refuses unrelated work on the reserved branch. There is +no intermediate generated PR head to trigger redundant qualification. A no-change +candidate skips Rust setup and publication. Publication remains the authority for +pending/tagged labels; preparation does not mark a release published. + +Local evidence: three tests use the actual pinned Release Please implementation +for shared-source history boundaries, repeat output, and current Rust/npm/Swift/ +Gradle updater inputs. A real disposable Git remote proves no-op SHA reuse, +ambiguous-create recovery, new-main updates and preservation of unrelated commits. +The full release source aggregate and frozen Bun install pass. These proofs do +not claim a hosted bot-token run, remote branch-protection behavior or completed +publication; those remain external qualification requirements. + +### Resource and orchestration cleanup checkpoint — 2026-09-11 + +The database-resources product now owns one Shell test entrypoint. Its seed +tests and ICU archive/npm tests execute once; Shell runs packaging and the +actual Node CommonJS consumer, while Bun asserts receipt, data and descriptor +behavior. Repeated ICU packaging produces identical bytes, rejects empty or +symlinked source without replacing valid output, and supports a symlinked OS +temporary-directory alias. The redundant ICU-only Moon project is removed. + +The packaging aggregate passes with Shell-owned command execution, including +actual Cargo archive consumers, native stripping and the Windows CRT fixture +closure. Release-intent ancestry tests now execute Git directly from Shell, +using isolated object storage; exact-parent and sibling-commit rejection pass. +No committed JavaScript or Python remains in the tracked source inventory; +generated consumer JavaScript remains an intentional build output. + +Native packaging no longer depends on the public Rust SDK, generates unused +cluster seeds, supports unused broker/server packaging modes, or emits a legacy +runtime-owned ICU archive. Its real React Native ICU assembly and existing +mobile carrier finalizer pass. Mobile device/static-link proof and final iOS +resource consumer migration remain separate requirements, not inferred from +these Linux checks. + +### 2026-09-11 WASIX final consumer input audit + +Rust `test-aot` now depends on the separate extension and PostgreSQL tool AOT +producers it actually executes. Browser and Node SDK tests depend on extension +compiler outputs and read their manifest/archive paths from that owner, rather +than the core runtime output. Default SDK/runtime builds gain no optional payload. +CI transfers the same-run extension outputs, WASIX seed archives and ICU npm +carrier; local seed packaging reuses the frozen producers. The execution resolver +test covers these transitive transfers without inventing redundant direct edges. + +Actual final-module proof passes: standard/ICU resource initialization, memory and +directory storage/reopen; three UUID-OSSP AOT direct/restart, dump/restore and +materialization cases; browser PostGIS worker, OPFS crash recovery and pgtap; +packed browser direct/worker/IndexedDB/transaction/resource selection; and the +fresh ABI 2 release addon's Node SDK actor/direct/worker/server, persistence, +backup/restore and corrupt-restore preservation. The shipping addon was rebuilt +through its Linux baseline producer, not substituted with a debug library. +Its complete installed-carrier matrix passes: Node/npm, Node/Bun, Bun, Deno and +Electron, including worker unload and actor/direct/server-wire round trips. +Nine resolver tests, three transfer tests, the full task graph and actionlint pass. + +These runs first rejected stale seed/module hashes and old SDK notice bytes. +Regenerating only the resource and archive producers resolved both. Two obsolete +embedded-seed helper tests that failed the extension-feature build were removed; +explicit resource integration and existing atomic seed-publication tests retain +the corresponding behavior coverage. + +### Tasks 05/24f/17 checkpoint — local commands and mobile resource boundary + +The released SDK/resource/tools leaf commands were compared with their native +manifests and resolved Moon producers. The WASIX TypeScript tools facade now +builds and typechecks against the SDK's real declarations; two handwritten +declaration shims were deleted. Its `build` task depends on SDK compilation, +and `package` depends on that build instead of compiling inside its packaging +recipe. The actual six-task query → SDK → tools build/typecheck/test/package +closure passes without a PostgreSQL, Wasmer or addon build. Native tools `build` +now compiles both Rust and npm facades and records both outputs. Resource tests +have one owner, with the existing canonical contract test as a prerequisite; +the redundant ICU test-only Moon project was removed. + +Maintainer instructions distinguish direct commands using prepared inputs from +Moon commands that build their dependencies. Kotlin AAR assembly remains runnable +on Linux with Android SDK/NDK, Java, Bun and the two declared Rust Android targets. +Swift source checks remain portable with Swift/Rust/Bun; Apple XCFramework +production and installed iOS/device execution still require their actual hosts. + +The artifact inventory audit exposed retired native/WASIX ICU archives still +required by release and Swift/RN carrier code. Those expectations and the +runtime-owned ICU copy were removed; the canonical database-resources carrier +remains. Swift and RN base carriers now contain the native framework and runtime +resources only. The RN app-owned payload validates the seedless runtime target, +extension closure and legal bytes. Explicit `seedProfile` selects a separate +resource CocoaPod; ICU selects the separate `OliphauntICU` pod. Neither seed nor +ICU bytes are copied into the base payload, and omitting a seed profile does not +create a default seed dependency. The Swift initializer retains compatibility +validation of separately installed resources. + +Evidence: actual RN archive/cache-tamper/malicious-ZIP/app-payload staging passes; +RN typecheck and source tests pass; the Swift owner packaging aggregate passes +its resolver/inventory scenarios and 19 tests; publication freezing passes all +21 tests with the seedless base carrier. These use real archive/filesystem +operations and synthetic Apple binaries, not an Apple link or installed-device +qualification. The latter remain explicit platform gates. + +### Tasks 26–29 checkpoint — portable frozen-candidate assembly + +The final caller audit found one compiler hidden inside candidate assembly: +broker Cargo payload packaging invoked `cargo package` for all four targets. +It now uses the same deterministic Cargo archive producer as the other binary +carriers. The two-phase Shell wrapper and its temporary plan were deleted. +The broker owner test still compiles each extracted, normalized carrier with +payload verification enabled and offline Cargo; parallel packaging also proves +identical bytes across independent staging directories and exact target notices. + +Candidate preparation now runs on Linux without installing Rust, Apple or +Android build toolchains. Duplicate Bun/workspace setup and the obsolete macOS +toolchain configuration helper/test were removed. This job consumes qualified +outputs, assembles carriers and freezes the existing publication lock/capsule. +The publishing job retains macOS because it executes a real public Swift +consumer. Public-consumer compilation is distinct from rebuilding product bytes. + +Qualification request/reuse remains bound to the exact source and covering +product evidence. Bootstrap remains conditional on missing initial registry +identities; recovery restores the original frozen capsule. Registry-race checks, +immutable version/byte reconciliation and controller trust checks remain at +publication. No hosted dispatch, registry mutation or platform qualification +was performed in this audit. Native cross-commit producer reuse and the final +hosted/platform proofs remain open rather than being inferred from source checks. + +Validation: broker assembly succeeds with an empty executable search path and +Cargo home, all four extracted carriers compile offline, and ten owner tests +pass. The complete workflow aggregate passes, including 55 graph/selection +tests, transferred-dependency cases, actionlint and security checks. + +### Tasks 05/24f checkpoint — transitive Cargo source hashes and local checks + +Project dependencies alone did not invalidate native Rust SDK test caches. An +actual bindings-source comment left the SDK test hash unchanged at `6fdd17ff` +and reused cached results. The shared internal `cargo-sources` task now carries +hashes through native Moon dependency edges. SDK compiler/test tasks consume +that node and include the locally compiled `oliphaunt-build` helper. With the +fix, the same source-only change changed SDK test hash `0e50780e` to `bb3ec969` +and reran all 121 tests successfully. Probe comments were restored. Formatting +remains owner-local; CI uses deep downstream traversal for transitive consumers. +Existing affectedness observations cover the regression without a separate +hash engine. + +Swift and Kotlin binding consumers depend on the same source hash, independently +of their generated-file preparation. A bindings-source edit changed the actual +Swift test hash and reran all 94 tests without building PostgreSQL. Formatting +and archive-only tests remain local. Mobile compilation/generation use Cargo's +incremental cache rather than claiming declarations alone restore native binaries. + +Transferred-artifact jobs omit already produced dependencies. Moon also omits +their hashes with `--upstream none`, so those consumer invocations disable Moon +caching and execute against the downloaded bytes. Normal source checks retain +transitive caching. The CI adapter skips internal command-free hash nodes when +choosing explicit executable prerequisites; it preserves real producer edges. +Actual before/after probes and Shell handoff checks prove these distinctions. + +Optional pre-commit hooks no longer run duplicate workspace/Tauri rustfmt checks +on unrelated TOML edits. Cheap file/security hooks remain, and the hook config +validates. Maintainer examples inspect affectedness and run explicit owner +tasks: query-only or wildcard Moon run commands do not safely express the +intended local selection. This checkpoint does not qualify Windows, Apple or +mobile artifacts. + +### Query and extraction acceptance audit — 2026-09-11 + +Tasks 09 and 11 satisfy their extraction acceptance: the public native SDK, +broker and addon consume the shared native bindings without a public-SDK +backedge; lifecycle, cancellation, generation and persistence checks pass on +Linux. The separately packaged pgwire-server CLI accepts an ordinary sqlx +client, and six real socket startup, malformed-input, reconnect and shutdown +checks pass. These completed boundaries do not close the separate Windows, +Apple or mobile qualification tasks. + +Tasks 07/08 have normal shared dependencies, packed consumer and transitive +affectedness evidence. A disposable reference comparison now also runs the +existing PostgreSQL behavior corpus against a separately started PostgreSQL 18 +server through `pg` and the installed native TS SDK through its shared query +package. Six comparisons cover typed values, arrays/JSON, views and aggregates; +SQLSTATE 23505, recovery and transaction rollback agree. The same comparator +rejects an intentionally changed result (42 to 43), then accepts the original. +The same corpus now passes through the native Rust SDK and its shared query +crate against separately captured `pg` results from that PostgreSQL server. +Rust checks nullable/text and typed boolean/integer/float/Unicode decoding, +SQLSTATE 23505, recovery and callback-scoped transaction rollback. Its comparator +also rejects the deliberately changed integer, then accepts the unchanged +result. Both temporary harnesses live outside the repository; no source +perturbation or permanent mutation framework remains. Together with the existing +packed Rust/TS dependency closures and source-affectedness checks, this closes +07/08. It does not qualify platform-specific execution adapters or final mobile +artifacts. + +Hosted Windows broker packaging exposed native child lookup selecting the WSL +launcher instead of Git Bash. The common Moon setup now publishes Git's real +`bin` path. Windows addon packaging separately exposed a missing app-local +VCRUNTIME DLL; its raw and npm carriers now stage the existing verified VC +closure before validation. Hosted rerun is required to qualify these fixes. + +Standalone Kotlin generation had a separate freshness gap: after changing a +transitive Rust dependency, Gradle reported `generateNativeBindings UP-TO-DATE`. +Gradle now always invokes the existing generator and lets Cargo's native +dependency fingerprints decide whether compilation is needed; it no longer +maintains an incomplete Rust input list. The same source-only change then rebuilt +the affected Rust chain through a reused Gradle configuration cache. Moon's +generation task also no longer builds the library separately before the +generator's own `cargo build --features bindgen`. Combined Kotlin lint, JVM and +Android unit tests, plugin checks and formatting pass; an unchanged repeat takes +3 seconds, with all Kotlin compilation up to date and Cargo completing in +0.14 seconds. This proves local freshness and incremental compilation, not +Android device or Apple artifact qualification. + +M05 resource preparation checkpoint: Expo's Android/iOS resource assemblers no +longer compile a desktop PostgreSQL runtime implicitly or repair permissions in +producer outputs. Removed the unused seed-normalization helper and obsolete +initdb parameter/CI environment forwarding. Missing runtime data names the +corresponding native Moon producer and explicit runtime-directory override; +existing example build tasks retain their native package dependencies. A Linux +assembly using existing PostgreSQL data and a validated selected Android seed +passes without executing or copying initdb. The owner Shell regression proves +source bytes and non-executable tool permissions stay unchanged and missing +data fails with producer guidance. Clean packaged-workspace dependency isolation +and actual device qualification remain separate M05 acceptance work. + +Clean-runner checkpoint (2026-09-12): CI run `34661770025` at `fa99f617` +passed Kotlin lint/unit checks and Apple Swift source tests. Its two underlying +failures were test prerequisites: the dependency-prefix fixture assumed `target` +already existed, and extracted Cargo carrier tests assumed locked registry +dependencies were cached. The prefix fixture now creates its own parent and +passes from a fresh Git tree. Cargo carrier fixtures explicitly acquire their +locked dependency closure before offline execution; an empty Cargo cache and +an offline repeat both pass. Failed source tests blocked expensive producers +and their artifact consumers; later aggregate failures did not introduce missing +artifact cascades. This run is failed qualification, not publishable evidence. + +Packed Rust consumer checkpoint: its runtime invocation now belongs to the +SDK's `test-consumer-runtime` task and native-consumer job, rather than the +extension lifecycle shard. The package job supplies the compiled consumer; +declared runtime, broker and PostgreSQL-tool producers supply its inputs. The +same packed executable passes direct/broker parameter, transaction, query, +backup/restore checks and the existing server/base-backup checks against newly +packaged local artifacts. Missing archives and an obsolete broker protocol fail. +Native runtime packaging defaults to the detected host when no CI target is +provided; actual Linux packaging, binary compatibility and notices checks pass +without that environment variable. This proves the local packed runtime seam; +Rust-only release fanout and unchanged published dependency reuse remain open. + +M05 packed Expo dependency checkpoint: artifact mode now uses an app-only +workspace with an explicit packaged query dependency; it never copies the query +source project. Mobile Moon build tasks and CI handoffs declare the query package +producer. Before installation, actual RN/query tarball manifests must identify +the expected packages and the query version must satisfy RN's declared +dependency. Source integration keeps its ordinary workspace behavior. +The owner-local lock projection removes checkout workspace references while +retaining locked external dependency descriptors and registry records; Bun +reconciles candidate file dependencies. A neutral-root projection was rejected +because the real Expo graph refreshed transitive versions. The corrected real +graph retains all 972 registry version/integrity identities and repeats with an +identical lock. Installed-package, missing-artifact, undeclared-dependency and +wrong-version checks pass, and the permanent fixture exercises the real Expo +dependency graph without a native build. This is dependency-closure evidence, +not final Apple/Android package or device qualification. diff --git a/docs/architecture/stable-database-api.md b/src/docs/architecture/stable-database-api.md similarity index 100% rename from docs/architecture/stable-database-api.md rename to src/docs/architecture/stable-database-api.md diff --git a/docs/architecture/wasix-typescript-napi.md b/src/docs/architecture/wasix-typescript-napi.md similarity index 99% rename from docs/architecture/wasix-typescript-napi.md rename to src/docs/architecture/wasix-typescript-napi.md index 4a6e0b811..79ec1a686 100644 --- a/docs/architecture/wasix-typescript-napi.md +++ b/src/docs/architecture/wasix-typescript-napi.md @@ -529,9 +529,9 @@ Phase 1 acceptance: - [x] Run `moon run oliphaunt-wasix-napi:qualify`, `moon run oliphaunt-wasix-napi:qualify`, `moon run oliphaunt-wasix-rust:compile`, - `moon run oliphaunt-wasix-ts:unit`, + `moon run oliphaunt-wasix-ts:test`, `moon run oliphaunt-wasix-ts:compile`, and the product package checks. -- [x] Run `moon run sdk-contracts:check` for public-surface changes. +- [x] Run the affected SDK compile, unit, and package tasks for public-surface changes. - [x] Run workflow-policy, release-check, committed-asset, extension-model, WASIX source/patch, portable/AOT, carrier, license, provenance, and Linux ABI checks selected by the repository qualification graph. diff --git a/docs/assets/oliphaunt.png b/src/docs/assets/oliphaunt.png similarity index 100% rename from docs/assets/oliphaunt.png rename to src/docs/assets/oliphaunt.png diff --git a/docs/assets/pglite-oxide.png b/src/docs/assets/pglite-oxide.png similarity index 100% rename from docs/assets/pglite-oxide.png rename to src/docs/assets/pglite-oxide.png diff --git a/src/docs/content/learn/native-runtime.mdx b/src/docs/content/learn/native-runtime.mdx index aca1ba29d..52aefe50e 100644 --- a/src/docs/content/learn/native-runtime.mdx +++ b/src/docs/content/learn/native-runtime.mdx @@ -30,8 +30,11 @@ Native defaults to an SDK-owned temporary directory. Persistent storage is an explicit application-owned managed root with `.oliphaunt.json` and `pgdata`. Native does not label a temporary directory as memory storage. -SDKs initialize new roots from the packaged cluster seed and publish the descriptor -last. The low-level C runtime only validates a complete managed root; it never +In the development checkout, desktop SDKs initialize new roots with initdb or an +explicitly selected seed from the independent database-resources product, then +publish the descriptor last. Mobile applications select their platform resource +carrier. These resource-package changes are unreleased; completed releases retain +their packaged initialization behavior. The low-level C runtime only validates a complete managed root; it never runs `initdb`, adopts raw PGDATA, or creates a descriptor during open. Application-owned storage survives close. A direct close may detach the logical diff --git a/src/docs/content/reference/api-reference.mdx b/src/docs/content/reference/api-reference.mdx new file mode 100644 index 000000000..4a18bfca6 --- /dev/null +++ b/src/docs/content/reference/api-reference.mdx @@ -0,0 +1,12 @@ +# SDK API maps + +These handwritten guides summarize each SDK. Generated API documentation is not currently published. + +- [rust](/docs/sdk/rust/api-reference) +- [swift](/docs/sdk/swift/api-reference) +- [kotlin](/docs/sdk/kotlin/api-reference) +- [react-native](/docs/sdk/react-native/api-reference) +- [typescript](/docs/sdk/typescript/api-reference) +- [wasix-rust](/docs/sdk/wasix-rust/api-reference) +- [wasix-typescript](/docs/sdk/wasix-typescript/api-reference) +- [c-abi](/docs/sdk/c-abi/api-reference) diff --git a/src/docs/content/reference/extensions.mdx b/src/docs/content/reference/extensions.mdx index 3a006146a..2dc8e027d 100644 --- a/src/docs/content/reference/extensions.mdx +++ b/src/docs/content/reference/extensions.mdx @@ -50,7 +50,7 @@ still install database-local objects explicitly: ```toml [dependencies] -oliphaunt-wasix = { version = "0.1", features = ["extension-pgtap"] } +oliphaunt-wasix = { version = "={{release:oliphaunt-wasix-rust}}", features = ["extension-pgtap"] } ``` ```rust diff --git a/src/docs/content/reference/index.mdx b/src/docs/content/reference/index.mdx index 6d9644d32..3a953870a 100644 --- a/src/docs/content/reference/index.mdx +++ b/src/docs/content/reference/index.mdx @@ -44,7 +44,7 @@ details. ### Verify release fit - Use [Performance](/docs/reference/performance), the generated version matrix, + Use [Performance](/docs/reference/performance), the published products page, and SDK API maps when preparing a release candidate. diff --git a/src/docs/content/reference/releases.mdx b/src/docs/content/reference/releases.mdx index 48482586f..590a70475 100644 --- a/src/docs/content/reference/releases.mdx +++ b/src/docs/content/reference/releases.mdx @@ -1,7 +1,7 @@ --- sidebar_position: 1 title: Releases -description: Match SDK versions, runtime artifacts, selected extensions, release notes, and docs versions. +description: Match SDK versions, runtime artifacts, selected extensions, release notes. --- # Releases @@ -12,24 +12,19 @@ expects. -## First Release Boundary +The [published products](/docs/reference/version-matrix) page lists completed public releases. A product without a completed release is not available for installation. -Before the first public release, tracked product versions remain `0.0.0`. That -is an unreleased source sentinel, not a registry version. The generated release -PR advances new products to `0.1.0`, except Swift, which starts at `0.6.0` -because legacy unscoped SwiftPM tags already occupy `0.1.0` through `0.5.1`. - -An install command is a package contract, not proof that a registry identity -exists. Check the product's promoted tag/release and registry page before using -it in an application. +Unreleased checkout APIs are explicitly labelled in the guides. A development +example using a new resource or socket package is not an installation promise. +Published installation versions remain independent of those source changes. ## Version Relationships | Relationship | Products | Rule | | --- | --- | --- | -| Independently versioned | Native, WASIX, external extensions, SDKs, and helper runtimes | Release Please selects changed product paths; each product owns its SemVer, and native and WASIX do not move together | +| Independently versioned | Native, WASIX, external extensions, SDKs, database resources, PostgreSQL tools, and socket adapters | Release Please selects changed product paths; each product owns its SemVer, and native and WASIX do not move together | | Runtime-owned distribution | PostgreSQL contrib | Native and WASIX carriers inherit their owning runtime's version; contrib has no independent release identity | -| Exact compatibility | Products with dependency or runtime compatibility fields | The consumer pins an exact published product version; dependency changes do not create consumer releases | +| Exact compatibility | Products with dependency or runtime compatibility fields | The consumer declares its compatible product versions; release preparation propagates changed dependency pins to affected consumers | | Upstream-bound | External exact-extension products | Packaging SemVer is independent; immutable upstream version/commit and compatible runtime versions are recorded separately | | Documentation | Public documentation site | Guides and references can change without a package release | @@ -96,13 +91,6 @@ Release notes answer these questions: backup, and restore support; - migration or rebuild steps for app developers. -## Docs Versioning - -The docs site has a `latest` channel for the current product shape. Package -versions, compatibility notes, and release notes tell developers which docs -match the SDK installed in an app. Versioned docs remain available by released -product version when a package line needs stable historical documentation. +## Documentation -Documentation changes can update the docs site without changing Rust, Swift, -Kotlin, React Native, TypeScript, C ABI, Rust WASIX, or WASIX TypeScript -package versions. +These guides describe the latest available products. Documentation fixes deploy from main independently of product releases. Completed releases refresh the installation versions displayed in these guides. Historical documentation versions are not maintained. diff --git a/src/docs/content/sdk/c-abi/api-reference.md b/src/docs/content/sdk/c-abi/api-reference.md index fe0051765..855558c61 100644 --- a/src/docs/content/sdk/c-abi/api-reference.md +++ b/src/docs/content/sdk/c-abi/api-reference.md @@ -5,7 +5,7 @@ description: C ABI API map for native runtime initialization, protocol execution # API Reference -Use the Doxygen reference for exact declarations. This page maps the C ABI by +This page maps the C ABI by task. | Area | Public surface | Use it for | @@ -26,7 +26,14 @@ Most app developers use a language SDK instead of calling the C ABI directly. The C ABI is primarily for binding authors and applications that need the native runtime boundary itself. -ABI v10 retains the optional embedded module directory at +**Unreleased checkout ABI v11:** `OliphauntConfig` appends the nullable +`const char *icu_data_dir` field. Binding authors must use the matching v11 +header and ABI version; an older struct must not be passed as v11. Supply the +selected canonical ICU data directory explicitly for an ICU database. The field +is optional for configurations that do not select external ICU data. This is a +checkout change, not a claim that ABI v11 has been publicly released. + +The optional embedded module directory remains at `OliphauntConfig.module_dir`. A non-empty path is copied into the handle and is authoritative over process environment and release-layout discovery. Set it to `NULL` for the sensible default: a valid `OLIPHAUNT_EMBEDDED_MODULE_DIR`, then diff --git a/src/docs/content/sdk/c-abi/guide.mdx b/src/docs/content/sdk/c-abi/guide.mdx index deeb0850e..876c57095 100644 --- a/src/docs/content/sdk/c-abi/guide.mdx +++ b/src/docs/content/sdk/c-abi/guide.mdx @@ -35,8 +35,6 @@ read backend messages, and close the handle. The C runtime validates an exact `.oliphaunt.json`, PostgreSQL 18 `PG_VERSION`, a real `global` directory with nonempty `pg_control`, and a real `pg_wal`; it does not initialize an empty root. - - ```c #include #include @@ -71,6 +69,9 @@ selection, and lifecycle integration. `OliphauntConfig` contains the PGDATA path, optional runtime and module directories, username, database, and PostgreSQL startup arguments. +The unreleased v11 header also appends nullable `icu_data_dir` for explicitly +selected ICU data. Use the matching header and ABI version together; do not +reuse an older binary struct with the new version number. Set `flags` to zero for normal ownership, or to `OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK` when the host already owns the managed root lock for the lifetime of the handle. A detached resident runtime accepts a diff --git a/src/docs/content/sdk/kotlin/api-reference.md b/src/docs/content/sdk/kotlin/api-reference.md index fe07d7e23..e9b93c246 100644 --- a/src/docs/content/sdk/kotlin/api-reference.md +++ b/src/docs/content/sdk/kotlin/api-reference.md @@ -5,7 +5,7 @@ description: Kotlin and Android SDK API map for configuration, coroutine executi # API Reference -Use the Dokka reference for exact declarations. This page maps the Kotlin SDK +This page maps the Kotlin SDK surface by task. | Area | Public surface | Use it for | @@ -30,7 +30,7 @@ val answer = result.rows.first().value("answer", PostgresDecoders.int) ``` The cross-SDK behavior follows the -[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/docs/architecture/stable-database-api.md). +[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md). Managed transaction callbacks must not issue outer-lifecycle SQL: `BEGIN`/`START TRANSACTION`, `COMMIT`/`END`, a full `ROLLBACK`/`ABORT` (with or without `AND diff --git a/src/docs/content/sdk/kotlin/guide.mdx b/src/docs/content/sdk/kotlin/guide.mdx index 3dc07cbc5..d168228ad 100644 --- a/src/docs/content/sdk/kotlin/guide.mdx +++ b/src/docs/content/sdk/kotlin/guide.mdx @@ -28,11 +28,11 @@ packages native runtime artifacts, Android ABIs, and exact extension files. ```kotlin plugins { id("com.android.application") - id("dev.oliphaunt.android") version "0.1.1" + id("dev.oliphaunt.android") version "{{release:oliphaunt-kotlin}}" } dependencies { - implementation("dev.oliphaunt:oliphaunt-android:0.2.0") + implementation("dev.oliphaunt:oliphaunt-android:{{release:oliphaunt-kotlin}}") } oliphaunt { @@ -51,8 +51,6 @@ directory when data must persist. Create an `OliphauntConfig`, open a database, run SQL, and close it from coroutines. - - ```kotlin val database = Oliphaunt.open( @@ -203,3 +201,22 @@ rejects nonempty data without mutation. Check app storage permissions, storage ownership, missing native libraries, missing runtime resources, runtime errors, selected-extension artifacts, and SQLSTATE-bearing PostgreSQL errors. + +## Development resource packaging + +These resource-package changes are unreleased. The published installation +versions above do not include this new package arrangement; use a coordinated +checkout for this section. + +The Android Gradle plugin selects initialization resources at build time: + +```kotlin +oliphaunt { + seedProfile.set("standard") // Or "icu" for an ICU seed and canonical ICU data. +} +``` + +The default includes no seed. Select one for first-open initialization, or omit +it when opening existing storage or supplying application-owned resources. +Runtime libraries, seed carriers, and canonical ICU data are separate packages. +Actual device qualification of the new seed carriers remains pending. diff --git a/src/docs/content/sdk/kotlin/index.mdx b/src/docs/content/sdk/kotlin/index.mdx index 1a4826cce..3c2ee0e55 100644 --- a/src/docs/content/sdk/kotlin/index.mdx +++ b/src/docs/content/sdk/kotlin/index.mdx @@ -20,11 +20,11 @@ Add the Android package to your app: ```kotlin plugins { id("com.android.application") - id("dev.oliphaunt.android") version "0.1.1" + id("dev.oliphaunt.android") version "{{release:oliphaunt-kotlin}}" } dependencies { - implementation("dev.oliphaunt:oliphaunt-android:0.2.0") + implementation("dev.oliphaunt:oliphaunt-android:{{release:oliphaunt-kotlin}}") } oliphaunt { diff --git a/src/docs/content/sdk/react-native/api-reference.md b/src/docs/content/sdk/react-native/api-reference.md index 40c5873e1..950ef2863 100644 --- a/src/docs/content/sdk/react-native/api-reference.md +++ b/src/docs/content/sdk/react-native/api-reference.md @@ -5,7 +5,7 @@ description: React Native SDK API map for TypeScript, config plugin, TurboModule # API Reference -Use the TypeDoc reference for exact declarations. This page maps the React Native +This page maps the React Native SDK by task. | Area | Public surface | Use it for | @@ -29,7 +29,7 @@ const fields = (await db.describe('SELECT $1::uuid', [2950])).fields; ``` The cross-SDK behavior follows the -[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/docs/architecture/stable-database-api.md). +[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md). Inside a callback transaction, do not issue manual `BEGIN`, `START TRANSACTION`, `COMMIT`, `END`, `ABORT`, `PREPARE TRANSACTION`, or `AND CHAIN`. diff --git a/src/docs/content/sdk/react-native/guide.mdx b/src/docs/content/sdk/react-native/guide.mdx index 3e0366f5f..dc19ee51b 100644 --- a/src/docs/content/sdk/react-native/guide.mdx +++ b/src/docs/content/sdk/react-native/guide.mdx @@ -31,7 +31,7 @@ resources before JavaScript calls `Oliphaunt.open()`. Expo apps: ```sh -npx expo install @oliphaunt/react-native +npx expo install @oliphaunt/react-native@{{release:oliphaunt-react-native}} npx expo prebuild npx expo run:ios npx expo run:android @@ -68,8 +68,6 @@ installed app binary. Open a database from TypeScript, run SQL, and close it when the app no longer needs the handle. - - ```ts import Oliphaunt from '@oliphaunt/react-native'; @@ -210,3 +208,22 @@ Check the development build, Expo config plugin output, autolinking, TurboModule codegen, native module availability, selected extension artifacts, and platform SDK errors. For database runtime behavior, follow the Swift or Kotlin SDK page for the target platform. + +## Development resource packaging + +These resource-package changes are unreleased. The published installation +versions above do not include this new package arrangement; use a coordinated +checkout for this section. + +For Android, the Expo plugin selects one resource profile at build time: + +```json +{ "plugins": [["@oliphaunt/react-native", { "seedProfile": "icu", "icu": true }]] } +``` + +For iOS, select exactly one development npm carrier: +`@oliphaunt/seed-native-ios-datum64-standard` or +`@oliphaunt/seed-native-ios-datum64-icu`. Its resource-only CocoaPod autolinks; +keep `icu: true` for an ICU database. These are app packaging choices, not +JavaScript database-open modes. Existing storage does not require a seed. +Mobile device qualification of the new seed carriers remains pending. diff --git a/src/docs/content/sdk/react-native/index.mdx b/src/docs/content/sdk/react-native/index.mdx index cde28ada8..d84e8dbd9 100644 --- a/src/docs/content/sdk/react-native/index.mdx +++ b/src/docs/content/sdk/react-native/index.mdx @@ -20,7 +20,7 @@ installed-app integration. Install the package and build a development client or native app binary: ```sh -npx expo install @oliphaunt/react-native +npx expo install @oliphaunt/react-native@{{release:oliphaunt-react-native}} ``` Oliphaunt includes native Swift and Kotlin code, so React Native apps run it diff --git a/src/docs/content/sdk/rust/api-reference.md b/src/docs/content/sdk/rust/api-reference.md index 42987f0f1..981dc5ef8 100644 --- a/src/docs/content/sdk/rust/api-reference.md +++ b/src/docs/content/sdk/rust/api-reference.md @@ -72,7 +72,7 @@ a root raw-protocol adapter that owns the complete lifecycle. Savepoints and `ROLLBACK TO SAVEPOINT` remain valid. The cross-SDK behavior follows the -[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/docs/architecture/stable-database-api.md). +[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md). The Rust SDK is the full native topology surface for Tauri and Rust desktop apps. Use server mode when you need independent PostgreSQL clients. Choosing an diff --git a/src/docs/content/sdk/rust/guide.mdx b/src/docs/content/sdk/rust/guide.mdx index 6a2e0c9d6..104cabbbe 100644 --- a/src/docs/content/sdk/rust/guide.mdx +++ b/src/docs/content/sdk/rust/guide.mdx @@ -34,7 +34,7 @@ through configuration: ```toml [dependencies] -oliphaunt = "0.1" +oliphaunt = "={{release:oliphaunt-rust}}" ``` @@ -45,8 +45,6 @@ oliphaunt = "0.1" Create a builder, choose storage, select exact extensions, open, query, and close. - - ```rust use oliphaunt::{DatabaseStorage, Extension, Oliphaunt}; @@ -275,3 +273,19 @@ design, while independent sessions require server mode. If the issue is a blocked async executor rather than database topology, confirm the type: `oliphaunt::Oliphaunt` blocks its caller and `oliphaunt::AsyncOliphaunt` owns a dedicated SDK thread. + +## Development resource inputs + +The resource separation is unreleased. In the coordinated checkout, direct and +async builders accept `.seed(NativeClusterSeed)` and +`.icu_data(NativeResourceDirectory)`. These types are exported by `oliphaunt`: +applications do not need to install an internal adapter crate to configure them. + +Select a Cargo carrier's archive and manifest with +`NativeClusterSeed::new(archive, manifest)`, or an explicitly unpacked native +seed directory. The shared native binding validates those inputs before it +initializes the managed root. Supported desktop opens can initialize without a +seed; reopening an existing root needs no seed. ICU roots still require ICU data. +Runtime libraries, seeds, and optional PostgreSQL tools have separate ownership +and versions. The installation commands above continue to use completed public +releases, not these unpublished resource candidates. diff --git a/src/docs/content/sdk/rust/index.mdx b/src/docs/content/sdk/rust/index.mdx index edad01128..66e2f4e64 100644 --- a/src/docs/content/sdk/rust/index.mdx +++ b/src/docs/content/sdk/rust/index.mdx @@ -23,7 +23,7 @@ Add the crate to your Rust app: ```toml [dependencies] -oliphaunt = "0.1" +oliphaunt = "={{release:oliphaunt-rust}}" ``` ## Open And Query diff --git a/src/docs/content/sdk/swift/api-reference.md b/src/docs/content/sdk/swift/api-reference.md index 06291c010..a9bbb4cc6 100644 --- a/src/docs/content/sdk/swift/api-reference.md +++ b/src/docs/content/sdk/swift/api-reference.md @@ -5,7 +5,7 @@ description: Swift SDK API map for Apple app storage, async database calls, life # API Reference -Use the Swift DocC reference for exact declarations. This page maps the Apple +This page maps the Apple SDK surface by task. | Area | Public surface | Use it for | @@ -29,7 +29,7 @@ let answer: Int32? = try result.rows[0].value(named: "answer") ``` The cross-SDK behavior follows the -[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/docs/architecture/stable-database-api.md). +[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md). Managed transaction callbacks must not issue outer-lifecycle SQL: `BEGIN`/`START TRANSACTION`, `COMMIT`/`END`, a full `ROLLBACK`/`ABORT` (with or without `AND diff --git a/src/docs/content/sdk/swift/guide.mdx b/src/docs/content/sdk/swift/guide.mdx index b9d77f0a7..5e60f4d16 100644 --- a/src/docs/content/sdk/swift/guide.mdx +++ b/src/docs/content/sdk/swift/guide.mdx @@ -25,7 +25,7 @@ Swift API plus the platform runtime artifacts required for the selected target. ```swift dependencies: [ - .package(url: "https://github.com/f0rr0/oliphaunt.git", from: "0.7.0") + .package(url: "https://github.com/f0rr0/oliphaunt.git", exact: "{{release:oliphaunt-swift}}") ] ``` @@ -40,8 +40,6 @@ SDK package carries the runtime files it needs. Open an `OliphauntDatabase` with a persistent file URL, run SQL with async calls, and close when the app no longer needs the handle. - - ```swift let appSupport = FileManager.default.urls( for: .applicationSupportDirectory, @@ -107,7 +105,8 @@ database actor. Configure storage, selected exact extensions, startup identity, and PostgreSQL startup GUCs through the Swift configuration API. Storage defaults to `.temporaryDirectory`; choose `.directory(url)` for persistence. Advanced -resource overrides retain packaged defaults for normal apps. +resource overrides allow app-owned resources. Released versions retain their +packaged defaults; the development resource selection is described below. @@ -190,3 +189,17 @@ data without mutation. Most Apple failures come from invalid file URLs, missing runtime resources, storage locks, runtime errors, or extension selection mismatches. PostgreSQL errors preserve SQLSTATE where the backend returns it. + +## Development resource packaging + +These resource-package changes are unreleased. The published installation +versions above do not include this new package arrangement; use a coordinated +checkout for this section. + +Select `OliphauntSeedNativeIOSStandard` or `OliphauntSeedNativeIOSICU` from the +independent database-resources Swift source package for a new iOS database. The +ICU product depends on `OliphauntICU`; an existing ICU database still needs that +data even when the seed is omitted. The SDK discovers the selected bundles. +The resource archive can be added as a local Swift package; no separate remote +Swift repository URL has been published. Device qualification of the new seed +carriers remains pending. diff --git a/src/docs/content/sdk/swift/index.mdx b/src/docs/content/sdk/swift/index.mdx index 5e8299f13..41a1dc6eb 100644 --- a/src/docs/content/sdk/swift/index.mdx +++ b/src/docs/content/sdk/swift/index.mdx @@ -18,7 +18,7 @@ this SDK, so the Swift lifecycle model is the Apple behavior source. Add the Swift package from Xcode or `Package.swift`: ```swift -.package(url: "https://github.com/f0rr0/oliphaunt.git", from: "0.7.0") +.package(url: "https://github.com/f0rr0/oliphaunt.git", exact: "{{release:oliphaunt-swift}}") ``` The package carries the Swift API and the native runtime artifacts for supported diff --git a/src/docs/content/sdk/typescript/api-reference.md b/src/docs/content/sdk/typescript/api-reference.md index e532b7ed0..9fcb52f69 100644 --- a/src/docs/content/sdk/typescript/api-reference.md +++ b/src/docs/content/sdk/typescript/api-reference.md @@ -5,7 +5,7 @@ description: TypeScript API map for desktop JavaScript, native engines, SQL, lif # TypeScript API Reference -Use the TypeDoc reference for exact declarations. This page maps native +This page maps native `@oliphaunt/ts` by task; WASIX TypeScript is documented separately. | Area | Public surface | Use it for | @@ -30,7 +30,7 @@ const description = await db.describe('SELECT $1::uuid', [2950]); ``` The cross-SDK behavior follows the -[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/docs/architecture/stable-database-api.md). +[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md). Inside a callback transaction, do not issue manual `BEGIN`, `START TRANSACTION`, `COMMIT`, `END`, `ABORT`, `PREPARE TRANSACTION`, or `AND CHAIN`. diff --git a/src/docs/content/sdk/typescript/guide.mdx b/src/docs/content/sdk/typescript/guide.mdx index 344ac5a9e..0047962dd 100644 --- a/src/docs/content/sdk/typescript/guide.mdx +++ b/src/docs/content/sdk/typescript/guide.mdx @@ -42,7 +42,7 @@ Install the npm package. Runtime assets and helper executables resolve through package configuration. ```sh -npm install @oliphaunt/ts +npm install @oliphaunt/ts@{{release:oliphaunt-js}} ``` @@ -53,8 +53,6 @@ npm install @oliphaunt/ts Open the package client, choose persistent storage, run SQL, and close the database. - - ```ts import { Oliphaunt } from '@oliphaunt/ts'; @@ -221,3 +219,23 @@ const sql = await pgDump(server.connectionString, { Check runtime asset resolution, helper executable availability, storage ownership, unsupported-mode errors, extension selection, and SQLSTATE-bearing PostgreSQL errors. + +## Development resource inputs + +The following options describe the unreleased checkout API. They do not imply +that new database-resource packages are available with the published version +in the installation command above. + +Native Node/Bun/Deno use the same seed-validation and initialization rules. +Pass `seed: { directory, manifestPath }` for an independently selected native +seed directory and its producer receipt. Pass +`icuData: { directory, manifestPath }` for the canonical ICU data directory +and receipt. Keep these immutable resources separate from mutable database +storage. Without a seed, supported desktop paths initialize with initdb; an +existing database does not need its initialization seed again. ICU databases +still require their selected ICU data. The server API uses its ordinary +PostgreSQL initializer and does not accept a seed option. + +Node and Bun share the Rust-backed Node-API adapter. Deno retains its FFI host +boundary; all three consume the same resource contract rather than separate +package-discovery rules. diff --git a/src/docs/content/sdk/typescript/index.mdx b/src/docs/content/sdk/typescript/index.mdx index bbda367b5..ecd9b2d9e 100644 --- a/src/docs/content/sdk/typescript/index.mdx +++ b/src/docs/content/sdk/typescript/index.mdx @@ -24,7 +24,7 @@ delegates through Swift and Kotlin. Install the package from npm: ```sh -npm install @oliphaunt/ts +npm install @oliphaunt/ts@{{release:oliphaunt-js}} ``` npm is the native-runtime distribution for Node.js, Bun, and Deno. Deno imports diff --git a/src/docs/content/sdk/wasix-rust/api-reference.md b/src/docs/content/sdk/wasix-rust/api-reference.md index fcd633496..59c57ade8 100644 --- a/src/docs/content/sdk/wasix-rust/api-reference.md +++ b/src/docs/content/sdk/wasix-rust/api-reference.md @@ -3,16 +3,20 @@ title: Rust WASIX API Reference description: Rust WASIX API map for protocol types, storage, extensions, and dump/restore. --- +> **Development checkout:** This section describes unreleased package separation. Published installation versions elsewhere on this site refer only to completed public releases. + + + # Rust WASIX API Reference -Use the `oliphaunt-wasix` rustdoc reference for exact declarations. This page +This page maps the Rust binding by task; it does not describe the separate [`@oliphaunt/wasix-ts` TypeScript API](/docs/sdk/wasix-typescript/api-reference). | Area | Public surface | Use it for | | --- | --- | --- | | Direct opening | root `Oliphaunt`, `OliphauntBuilder`, `OliphauntServerBuilder` | Open a `!Send + !Sync` database on the calling thread with memory storage by default | -| Asynchronous handles | root `AsyncOliphaunt`, `AsyncOliphauntBuilder`, `AsyncOliphauntServer`, `AsyncOliphauntServerBuilder` | Keep an async executor responsive through cloneable handles backed by dedicated owner threads | +| Asynchronous handles | root `AsyncOliphaunt`, `AsyncOliphauntBuilder` | Keep an async executor responsive through cloneable handles backed by dedicated owner threads | | Storage | `DatabaseStorage` | Select memory or a caller-supplied host directory | | Single-statement SQL | `query`, `execute`, parameterized variants, fluent `sql(...).bind(...)` | Run one extended-query command and return decoded rows or a command result | | Multi-statement and metadata | `exec`, `describe`, fluent `describe` | Return ordered simple-query results or parameter/result OIDs without executing | @@ -20,7 +24,7 @@ maps the Rust binding by task; it does not describe the separate | Raw protocol | `exec_protocol_raw`, `exec_protocol_raw_stream`, `RawStreamResult`, `RawStreamError` | Send PostgreSQL protocol bytes or feed bounded chunks to `()` / typed `Result<(), E>` callbacks; COPY output uses the guest stream pump | | Transactions | synchronous or async callback `transaction`, `TransactionResult`, `TransactionError`, `rollback`, `is_closed` | Pin the physical session, use `?` through `E: From`, and retain typed callback plus settlement failures; managed handles omit raw protocol and reject manual lifecycle ownership | | Lifecycle | synchronous `is_closed`, `close`; async `Clone + Send + Sync`, async `close` | Choose exclusive caller ownership or one shared FIFO, with replayable terminal teardown | -| Server/proxy | root `OliphauntServer` or `AsyncOliphauntServer`, `connection_string`, `is_closed`, `close` | Use an exclusive `Send + !Sync` blocking server handle or cloneable `Send + Sync` async lifecycle handle | +| Server/proxy | separate `oliphaunt-pgwire-server` package: `OliphauntServer` or `AsyncOliphauntServer`, `connection_string`, `is_closed`, `close` | Use an exclusive `Send + !Sync` blocking server handle or cloneable `Send + Sync` async lifecycle handle | | Extensions | root `Extension`, per-feature associated constants, enabled-set `ALL`, `by_sql_name` | Select WASIX-built extension artifacts by SQL name; unavailable selectors do not compile and migrations still own `CREATE EXTENSION` | | Backup/restore | `Oliphaunt::backup` / `restore`; `AsyncOliphaunt::backup` / `restore` | Move the one WASIX physical archive between compatible stores | | Tools | database `pg_dump` / `psql`; root `tools::{PgDumpOptions, PsqlOptions, PostgresToolError}` | Run packaged PostgreSQL logical dump and non-interactive psql synchronously or asynchronously through the selected handle | @@ -99,7 +103,7 @@ Transaction callbacks return ordinary `Result` with `E: From`. the transaction and host ownership was retired without sending rollback. The cross-SDK behavior follows the -[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/docs/architecture/stable-database-api.md). +[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md). The Rust WASIX binding owns its packaged PostgreSQL runtime assets and Rust host behavior. Native direct, broker, and server topologies are documented in the diff --git a/src/docs/content/sdk/wasix-rust/dump-restore.mdx b/src/docs/content/sdk/wasix-rust/dump-restore.mdx index 0e28b2cfd..dc4806e4d 100644 --- a/src/docs/content/sdk/wasix-rust/dump-restore.mdx +++ b/src/docs/content/sdk/wasix-rust/dump-restore.mdx @@ -5,8 +5,15 @@ description: Use the Rust binding's logical dumps, physical archives, CLI export # Rust WASIX Dump, Restore, And Upgrade -`oliphaunt-wasix` uses the WASIX `pg_dump` binary from the shipped portable -runtime asset for portable SQL exports, restores, and version-to-version + +The resource and package separation shown below is unreleased. Installation +versions on this site come from completed public releases; they do not make the +new seed, resource, or pgwire packages available. Use a coordinated source +checkout for these examples until those products are published. + + +`oliphaunt-wasix` uses the WASIX `pg_dump` binary from the separately owned +PostgreSQL tools product for portable SQL exports, restores, and version-to-version upgrades. @@ -35,7 +42,7 @@ Enable the `tools` feature for fluent database tool methods and the optional ```toml [dependencies] -oliphaunt-wasix = { version = "0.1", features = ["tools"] } +oliphaunt-wasix = { version = "={{release:oliphaunt-wasix-rust}}", features = ["tools"] } ``` Run the tools directly against an open database: diff --git a/src/docs/content/sdk/wasix-rust/guide.mdx b/src/docs/content/sdk/wasix-rust/guide.mdx index 3a3ccac74..0f22c8a41 100644 --- a/src/docs/content/sdk/wasix-rust/guide.mdx +++ b/src/docs/content/sdk/wasix-rust/guide.mdx @@ -5,6 +5,13 @@ description: Use the Rust WASIX binding with memory by default, explicit persist # Build With Rust WASIX + +The resource and package separation shown below is unreleased. Installation +versions on this site come from completed public releases; they do not make the +new seed, resource, or pgwire packages available. Use a coordinated source +checkout for these examples until those products are published. + + Use `oliphaunt-wasix` when Rust owns the WASIX host. This crate is separate from every native SDK and from the WASIX TypeScript binding. @@ -29,7 +36,7 @@ Add the Rust binding. The package resolves its matching portable runtime and host AOT artifacts; application code does not configure archive URLs. ```sh -cargo add oliphaunt-wasix +cargo add oliphaunt-wasix@={{release:oliphaunt-wasix-rust}} ``` @@ -37,12 +44,9 @@ cargo add oliphaunt-wasix ### Open and query -Omitting storage opens a fresh in-memory database initialized from the packaged -cluster seed. The crate root returns an exclusive direct handle; fallible +Omitting storage opens a fresh in-memory database initialized with initdb when no seed is selected. The crate root returns an exclusive direct handle; fallible database operations are synchronous and take `&mut self`. - - ```rust use oliphaunt_wasix::Oliphaunt; @@ -98,7 +102,14 @@ let mut database = Oliphaunt::builder() `DatabaseStorage::Memory` is the default. `Directory` uses a caller-owned host directory; its Rust path must be nonempty and contain no NUL bytes. Applications resolve temporary or platform app-data paths with their preferred -host library. New stores use the packaged cluster seed. +host library. New stores use initdb unless the caller supplies a separately selected seed. + +In this development checkout, supply `.seed(ClusterSeed::new(archive, manifest))` +to either builder. Independent seed Cargo carriers expose `seed_archive()` and +`seed_manifest()`. Supply raw canonical ICU data and its receipt through +`.icu_data(IcuData::new(data, manifest)?)`; this validates the data and selects +ICU. Standard opens do not require ICU. Existing roots do not need a seed, +but ICU roots still require their ICU data on every open. @@ -137,7 +148,9 @@ The handle's auto-traits do not make every user-created future unconditionally `Send`: a future is `Send` only when the values, callback captures, and output types it carries across suspension points are also `Send`. -Use the root `OliphauntServer` only when an existing PostgreSQL client library +The development checkout moves the socket adapter into the separate +`oliphaunt-pgwire-server` crate; it is not yet a published install target. +Use `oliphaunt_pgwire_server::OliphauntServer` only when an existing PostgreSQL client library needs a local connection URL. Its `start()` and `close()` lifecycle is synchronous, while its listener thread owns the single-backend wire server. The blocking handle is movable (`Send`) but exclusive (`!Sync`). @@ -189,7 +202,7 @@ runtime. ```toml [dependencies] -oliphaunt-wasix = { version = "0.1", features = ["extension-pgtap"] } +oliphaunt-wasix = { version = "={{release:oliphaunt-wasix-rust}}", features = ["extension-pgtap"] } ``` ```rust @@ -276,8 +289,8 @@ An independent pump/recovery failure is ## Troubleshooting -Check whether the selected managed root is new or complete, the packaged -cluster seed and exact runtime/AOT asset pair, enabled extension features, +Check whether the selected managed root is new or complete, any explicitly selected +seed and exact runtime/AOT asset pair, enabled extension features, directory ownership, and SQLSTATE-bearing PostgreSQL errors. Browser, Node, Bun, Deno, and Electron actor/direct/Worker behavior, the explicit `/worker` entry point, IndexedDB, and recovery behavior are documented diff --git a/src/docs/content/sdk/wasix-rust/index.mdx b/src/docs/content/sdk/wasix-rust/index.mdx index c92c933f5..c41bd0409 100644 --- a/src/docs/content/sdk/wasix-rust/index.mdx +++ b/src/docs/content/sdk/wasix-rust/index.mdx @@ -3,6 +3,10 @@ title: Rust WASIX SDK description: Host the portable Oliphaunt WASIX runtime from Rust with memory by default and explicit persistence. --- +> **Development checkout:** This section describes unreleased package separation. Published installation versions elsewhere on this site refer only to completed public releases. + + + `oliphaunt-wasix` is the Rust binding for the portable WASIX runtime. It keeps @@ -31,7 +35,7 @@ portable runtime and target AOT artifacts through package-manager dependencies. For Rust hosts: ```sh -cargo add oliphaunt-wasix +cargo add oliphaunt-wasix@={{release:oliphaunt-wasix-rust}} ``` ## Open And Query diff --git a/src/docs/content/sdk/wasix-rust/runtime.mdx b/src/docs/content/sdk/wasix-rust/runtime.mdx index 7e85a0548..51d600288 100644 --- a/src/docs/content/sdk/wasix-rust/runtime.mdx +++ b/src/docs/content/sdk/wasix-rust/runtime.mdx @@ -5,6 +5,13 @@ description: Rust WASIX memory, persistent storage, startup, server, tools, and # Rust WASIX Runtime Guide + +The resource and package separation shown below is unreleased. Installation +versions on this site come from completed public releases; they do not make the +new seed, resource, or pgwire packages available. Use a coordinated source +checkout for these examples until those products are published. + + `oliphaunt-wasix` is the Rust host for the portable runtime. It shares the PostgreSQL guest and physical contracts with [`@oliphaunt/wasix-ts`](/docs/sdk/wasix-typescript), while keeping Rust-native @@ -26,7 +33,7 @@ Sync` handle. Open constructs the direct database on a dedicated owner thread; every clone submits work to that same session through `&self` and awaits the result. -Use the root `OliphauntServer` when an existing PostgreSQL client library needs +Use `oliphaunt_pgwire_server::OliphauntServer` when an existing PostgreSQL client library needs a local endpoint. Loopback TCP is available on every supported host; Unix-domain sockets are available only on Unix hosts. Its `start()` and `close()` lifecycle is synchronous; `AsyncOliphauntServer` provides async @@ -43,7 +50,8 @@ PostgreSQL-style Unix socket directory. ## Explicit asynchronous surface -Use the root `AsyncOliphaunt` or `AsyncOliphauntServer` type when the application +Use `oliphaunt_wasix::AsyncOliphaunt` or the separate +`oliphaunt_pgwire_server::AsyncOliphauntServer` type when the application deliberately wants a dedicated execution owner. The async database and server wrap the same direct implementations with async methods. Database clones share one physical session and one ordered FIFO. Do not mix synchronous and async handles or infer that @@ -57,7 +65,7 @@ only in ownership and calling semantics. `DatabaseStorage::Memory` is the default true Wasmer memory filesystem. `DatabaseStorage::Directory(path)` is a caller-owned managed root. A new store -is hydrated from the packaged cluster seed; reopening validates the descriptor +uses initdb or an explicitly selected seed; reopening needs no seed and validates the descriptor and minimal PostgreSQL markers. The caller-supplied Rust path must be nonempty and contain no NUL bytes. Incomplete or descriptorless nonempty roots fail without mutation. @@ -67,8 +75,7 @@ Physical restore on the root surface is the synchronous static destination and returns after publication finishes or fails. The async `AsyncOliphaunt::restore(...).await` performs the same work on a temporary owner thread; once publication starts, abandoning the future does not promise -cancellation. Tests that specifically need `initdb` invoke the packaged tool -instead of selecting an initialization mode. +cancellation. The runtime retains its initializer, so omitting a seed is a supported new-store path. ## Startup and extensions diff --git a/src/docs/content/sdk/wasix-typescript/api-reference.md b/src/docs/content/sdk/wasix-typescript/api-reference.md index 05d2fbce7..29fca449c 100644 --- a/src/docs/content/sdk/wasix-typescript/api-reference.md +++ b/src/docs/content/sdk/wasix-typescript/api-reference.md @@ -3,9 +3,12 @@ title: WASIX TypeScript API Reference description: Public API map for portable TypeScript database, storage, query, and physical archive operations. --- +> **Development checkout:** This section describes unreleased package separation. Published installation versions elsewhere on this site refer only to completed public releases. + + + # WASIX TypeScript API Reference -Use the generated TypeDoc reference for exact declarations. | Area | Public surface | Purpose | | --- | --- | --- | @@ -21,6 +24,7 @@ Use the generated TypeDoc reference for exact declarations. | Storage | `memory`, plus the `storage/indexed-db`, `storage/opfs`, `storage/node`, `storage/bun`, and `storage/deno` subpaths | Select one host-appropriate storage provider | | Query values | `QueryParam`, `QueryResult`, `RawQueryResult`, `QueryField`, `CommandResult`, `ExecResult`, `DescribeResult` | Use decoded or lossless PostgreSQL parameter and result values | | Diagnostics | query-scoped `notices`, `PostgresError`, `WasixStorageError` | Distinguish PostgreSQL diagnostics from host persistence failures | +| Initialization resources | `OpenConfig.seed`, `WasixSeed`, `OpenConfig.icu` | Select independent archive/manifest inputs; new browser storage requires a seed, reopening does not, and ICU data remains required for ICU roots | | Extensions | `WasixExtensionDescriptor` | Materialize an exact independently packaged WASIX extension and its startup config; run normal database-local `CREATE EXTENSION`/`LOAD` explicitly in app or ORM migrations | | Optional tools | `pgDump`, `psql`, `PostgresToolError` from `@oliphaunt/wasix-tools` | Run a standard plain logical dump against root, direct, or Worker handles; non-interactive psql accepts any native-host placement and requires a Worker handle in browsers | | Optional local server | `openServer`, `ServerListen`, `OliphauntServer.connectionString`, read-only `OliphauntServer.closed`, `close`, and `Symbol.asyncDispose` from `@oliphaunt/wasix-ts/server` | Publish and lifecycle-manage one loopback TCP or PostgreSQL-named Unix endpoint on Node, Bun, Deno, or Electron | @@ -32,7 +36,7 @@ const raw = await database.queryRaw('select $1::bytea as payload', [new Uint8Arr ``` The cross-SDK behavior follows the -[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/docs/architecture/stable-database-api.md). +[stable database API](https://github.com/f0rr0/oliphaunt/blob/main/src/docs/architecture/stable-database-api.md). Inside a callback transaction, do not issue manual `BEGIN`, `START TRANSACTION`, `COMMIT`, `END`, `ABORT`, `PREPARE TRANSACTION`, or `AND CHAIN`. diff --git a/src/docs/content/sdk/wasix-typescript/guide.mdx b/src/docs/content/sdk/wasix-typescript/guide.mdx index 39d784d7d..d07fe5926 100644 --- a/src/docs/content/sdk/wasix-typescript/guide.mdx +++ b/src/docs/content/sdk/wasix-typescript/guide.mdx @@ -5,6 +5,13 @@ description: Open, persist, transact, back up, and restore portable PostgreSQL f # Build With WASIX TypeScript + +The resource and package separation shown below is unreleased. Installation +versions on this site come from completed public releases; they do not make the +new seed, resource, or pgwire packages available. Use a coordinated source +checkout for these examples until those products are published. + + @@ -15,7 +22,7 @@ description: Open, persist, transact, back up, and restore portable PostgreSQL f Install the same package for browsers, Node.js, Bun, Deno, and Electron: ```sh -pnpm add @oliphaunt/wasix-ts +bun add @oliphaunt/wasix-ts@{{release:oliphaunt-wasix-ts}} ``` Deno uses the same npm package as browsers, Node.js, Bun, and Electron: @@ -36,16 +43,28 @@ companions in one directory. ### Open and query - - ```ts import Oliphaunt from '@oliphaunt/wasix-ts'; +import archive from '@oliphaunt/seed-wasix-standard/seed.tar.zst?url'; +import manifest from '@oliphaunt/seed-wasix-standard/manifest.json?url'; -await using database = await Oliphaunt.open(); +const seed = { archive, manifest }; +await using database = await Oliphaunt.open({ seed }); const result = await database.query('select $1::int + 1 as answer', [41]); console.log(result.rows[0]?.answer); ``` +New browser storage requires a seed. The imports above use a browser bundler's +asset URL support; seed packages are independently installed development +carriers, not part of the SDK. Existing IndexedDB or OPFS storage reopens without +`seed`. Node/Bun/Deno can initialize without a seed using the runtime's initdb. + +For ICU, use `@oliphaunt/seed-wasix-icu` instead and pass +`icu: { data, manifest }`, where `data` is the raw `@oliphaunt/icu/data` +asset and `manifest` is `@oliphaunt/icu/manifest`. Load both with `?url` +in a browser bundler, or pass their bytes on a native host. ICU data remains +required when reopening an ICU database; the seed does not. + Browser pages must send these response headers. Bundlers using the explicit Worker surface must also preserve its module Worker asset: @@ -96,6 +115,7 @@ import { indexedDB } from '@oliphaunt/wasix-ts/storage/indexed-db'; const database = await Oliphaunt.open({ storage: indexedDB('notes'), + seed, startupGUCs: { application_name: 'notes' }, }); ``` @@ -128,7 +148,7 @@ lowest dispatch overhead, or `/worker` for a separate JavaScript realm: import OliphauntWorker from '@oliphaunt/wasix-ts/worker'; import OliphauntDirect from '@oliphaunt/wasix-ts/direct'; -const database = await OliphauntWorker.open(); +const database = await OliphauntWorker.open({ seed }); ``` All placements return the same Promise-shaped `OliphauntDatabase` contract. @@ -181,7 +201,7 @@ Import exact WASIX extension descriptors and pass them to `open()`: ```ts import pgtap from '@oliphaunt/extension-pgtap-wasix'; -const database = await Oliphaunt.open({ extensions: [pgtap] }); +const database = await Oliphaunt.open({ seed, extensions: [pgtap] }); await database.execute('CREATE EXTENSION pgtap'); ``` @@ -219,10 +239,12 @@ descriptor; `.oliphaunt.json` is not carried in the archive. ### Use PostgreSQL tools -Add the optional package when standard logical SQL is needed: +The tools package now has its own `postgres-tools-wasix` release owner. Until +that owner has a completed release, use the checkout carrier for the examples +below; do not substitute the SDK version. Add it when standard logical SQL is needed: ```sh -pnpm add @oliphaunt/wasix-tools +bun add @oliphaunt/wasix-tools@{{release:postgres-tools-wasix}} ``` ```ts @@ -230,9 +252,9 @@ import Oliphaunt from '@oliphaunt/wasix-ts'; import OliphauntWorker from '@oliphaunt/wasix-ts/worker'; import { pgDump, psql } from '@oliphaunt/wasix-tools'; -await using source = await Oliphaunt.open(); +await using source = await Oliphaunt.open({ seed }); const sql = await pgDump(source, { args: ['--schema-only'] }); -await using target = await OliphauntWorker.open(); +await using target = await OliphauntWorker.open({ seed }); await psql(target, { script: sql }); ``` diff --git a/src/docs/content/sdk/wasix-typescript/index.mdx b/src/docs/content/sdk/wasix-typescript/index.mdx index f57f09769..39ce75b4e 100644 --- a/src/docs/content/sdk/wasix-typescript/index.mdx +++ b/src/docs/content/sdk/wasix-typescript/index.mdx @@ -3,6 +3,10 @@ title: WASIX TypeScript SDK description: Run portable PostgreSQL in browsers, Node.js, Bun, Deno, and Electron with one small asynchronous API. --- +> **Development checkout:** This section describes unreleased package separation. Published installation versions elsewhere on this site refer only to completed public releases. + + + # WASIX TypeScript SDK @@ -14,7 +18,7 @@ browser, Node.js, Bun, Deno, or Electron. It is a separate product from native ## Install ```sh -pnpm add @oliphaunt/wasix-ts +bun add @oliphaunt/wasix-ts@{{release:oliphaunt-wasix-ts}} ``` Deno uses the same npm package through an `npm:` import. @@ -52,6 +56,9 @@ absent. ## App Responsibilities +- In the development API, supply an independent seed for new browser storage. + Reopening existing storage needs no seed; ICU roots still need their ICU data. + - Import only the persistent-storage adapter and exact WASIX extension packages the application uses. - Keep the same extension selection when reopening a persistent database. diff --git a/src/docs/docs-manifest.toml b/src/docs/docs-manifest.toml index 7079c7580..b89a1dd6c 100644 --- a/src/docs/docs-manifest.toml +++ b/src/docs/docs-manifest.toml @@ -3,56 +3,12 @@ generated_root = "target/docs" site_docs_root = "target/docs/site-docs" static_root = "target/docs/static" -[api_reference] -generated_root = "target/docs/generated/api" -summary = "target/docs/generated/api/summary.json" -strict_env = "OLIPHAUNT_DOCS_REQUIRE_NATIVE_API" - -[api_reference.c] -header = "src/runtimes/liboliphaunt/native/include/oliphaunt.h" -doxygen_config = "src/docs/reference/doxygen/Doxyfile" - -[api_reference.rust] -package = "oliphaunt" -docs_entry = "target/docs/generated/api/rust/doc/oliphaunt/index.html" - -[api_reference.swift] -package_path = "src/sdks/swift" -target = "Oliphaunt" -docs_entry = "target/docs/generated/api/swift/Oliphaunt.doccarchive" - -[api_reference.kotlin] -project_path = "src/sdks/kotlin" -task = ":oliphaunt:dokkaGeneratePublicationHtml" -docs_entry = "target/docs/generated/api/kotlin/html/index.html" - -[api_reference.typescript] -package_path = "src/sdks/js" -docs_entry = "target/docs/generated/api/typescript/html/index.html" - -[api_reference.wasix_typescript] -package_path = "src/bindings/wasix-ts" -docs_entry = "target/docs/generated/api/wasix-typescript/html/index.html" - -[api_reference.react_native] -package_path = "src/sdks/react-native" -docs_entry = "target/docs/generated/api/react-native/html/index.html" - -# Rust WASIX rustdoc artifact. -[api_reference.wasix_rust] -package = "oliphaunt-wasix" -docs_entry = "target/docs/generated/api/wasix-rust/doc/oliphaunt_wasix/index.html" - [[routes]] id = "start" title = "Start" kind = "public" route = "start" source = "src/docs/content/start" -version_source = "current" -reference_kind = "none" -tested_snippet_path = "" -tested_snippet_marker = "" page_order = ["index"] [[routes]] @@ -61,10 +17,6 @@ title = "SDKs" kind = "public" route = "sdk" source = "src/docs/content/sdk" -version_source = "current" -reference_kind = "none" -tested_snippet_path = "" -tested_snippet_marker = "" page_order = ["index"] [[routes]] @@ -73,10 +25,6 @@ title = "Learn" kind = "public" route = "learn" source = "src/docs/content/learn" -version_source = "current" -reference_kind = "none" -tested_snippet_path = "" -tested_snippet_marker = "" page_order = [ "index", "embedded-postgres", @@ -92,10 +40,6 @@ title = "Reference" kind = "public" route = "reference" source = "src/docs/content/reference" -version_source = "current" -reference_kind = "none" -tested_snippet_path = "" -tested_snippet_marker = "" page_order = [ "index", "sdk-products", @@ -121,10 +65,6 @@ title = "Rust SDK" kind = "sdk" route = "sdk/rust" source = "src/docs/content/sdk/rust" -version_source = "src/sdks/rust/release.toml:id" -reference_kind = "rustdoc" -tested_snippet_path = "src/sdks/rust/tests/public_api.rs" -tested_snippet_marker = "OLIPHAUNT_DOCS_SNIPPET rust-quickstart" required_pages = [ "index", "guide", @@ -139,8 +79,6 @@ sidebar_pages = [ "index", "guide", ] -reference_artifact = "target/docs/generated/api/rust/doc/oliphaunt/index.html" -snippet_language = "rust" [[routes]] id = "oliphaunt-swift" @@ -149,10 +87,6 @@ title = "Swift SDK" kind = "sdk" route = "sdk/swift" source = "src/docs/content/sdk/swift" -version_source = "src/sdks/swift/release.toml:id" -reference_kind = "swift-docc" -tested_snippet_path = "src/sdks/swift/Tests/OliphauntTests/OliphauntTests.swift" -tested_snippet_marker = "OLIPHAUNT_DOCS_SNIPPET swift-quickstart" required_pages = [ "index", "guide", @@ -167,8 +101,6 @@ sidebar_pages = [ "index", "guide", ] -reference_artifact = "target/docs/generated/api/swift/Oliphaunt.doccarchive" -snippet_language = "swift" [[routes]] id = "oliphaunt-kotlin" @@ -177,10 +109,6 @@ title = "Kotlin SDK" kind = "sdk" route = "sdk/kotlin" source = "src/docs/content/sdk/kotlin" -version_source = "src/sdks/kotlin/release.toml:id" -reference_kind = "dokka" -tested_snippet_path = "src/sdks/kotlin/oliphaunt/src/commonTest/kotlin/dev/oliphaunt/OliphauntDatabaseTest.kt" -tested_snippet_marker = "liboliphaunt-doc-example:kotlin-typed-query" required_pages = [ "index", "guide", @@ -195,8 +123,6 @@ sidebar_pages = [ "index", "guide", ] -reference_artifact = "target/docs/generated/api/kotlin/html/index.html" -snippet_language = "kotlin" [[routes]] id = "oliphaunt-react-native" @@ -205,10 +131,6 @@ title = "React Native SDK" kind = "sdk" route = "sdk/react-native" source = "src/docs/content/sdk/react-native" -version_source = "src/sdks/react-native/release.toml:id" -reference_kind = "typedoc" -tested_snippet_path = "src/sdks/react-native/src/__tests__/client.test.ts" -tested_snippet_marker = "OLIPHAUNT_DOCS_SNIPPET react-native-quickstart" required_pages = [ "index", "guide", @@ -225,8 +147,6 @@ sidebar_pages = [ "guide", "architecture", ] -reference_artifact = "target/docs/generated/api/react-native/html/index.html" -snippet_language = "typescript" [[routes]] id = "oliphaunt-js" @@ -235,10 +155,6 @@ title = "TypeScript SDK" kind = "sdk" route = "sdk/typescript" source = "src/docs/content/sdk/typescript" -version_source = "src/sdks/js/release.toml:id" -reference_kind = "typedoc" -tested_snippet_path = "src/sdks/js/src/__tests__/client.test.ts" -tested_snippet_marker = "OLIPHAUNT_DOCS_SNIPPET typescript-quickstart" required_pages = [ "index", "guide", @@ -253,8 +169,6 @@ sidebar_pages = [ "index", "guide", ] -reference_artifact = "target/docs/generated/api/typescript/html/index.html" -snippet_language = "typescript" [[routes]] id = "oliphaunt-wasix-rust" @@ -263,10 +177,6 @@ title = "Rust WASIX SDK" kind = "sdk" route = "sdk/wasix-rust" source = "src/docs/content/sdk/wasix-rust" -version_source = "src/bindings/wasix-rust/crates/oliphaunt-wasix/release.toml:id" -reference_kind = "rustdoc" -tested_snippet_path = "src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/runtime_smoke.rs" -tested_snippet_marker = "OLIPHAUNT_DOCS_SNIPPET wasix-rust-quickstart" required_pages = [ "index", "guide", @@ -285,8 +195,6 @@ sidebar_pages = [ "runtime", "dump-restore", ] -reference_artifact = "target/docs/generated/api/wasix-rust/doc/oliphaunt_wasix/index.html" -snippet_language = "rust" [[routes]] id = "oliphaunt-wasix-typescript" @@ -295,10 +203,6 @@ title = "WASIX TypeScript SDK" kind = "sdk" route = "sdk/wasix-typescript" source = "src/docs/content/sdk/wasix-typescript" -version_source = "src/bindings/wasix-ts/release.toml:id" -reference_kind = "typedoc" -tested_snippet_path = "tools/integration/wasix-ts/smoke-node.mjs" -tested_snippet_marker = "OLIPHAUNT_DOCS_SNIPPET wasix-typescript-quickstart" required_pages = [ "index", "guide", @@ -313,8 +217,6 @@ sidebar_pages = [ "index", "guide", ] -reference_artifact = "target/docs/generated/api/wasix-typescript/html/index.html" -snippet_language = "typescript" [[routes]] id = "liboliphaunt-native" @@ -323,10 +225,6 @@ title = "C ABI" kind = "sdk" route = "sdk/c-abi" source = "src/docs/content/sdk/c-abi" -version_source = "src/runtimes/liboliphaunt/native/release.toml:id" -reference_kind = "doxygen" -tested_snippet_path = "src/runtimes/liboliphaunt/native/smoke/liboliphaunt_smoke.c" -tested_snippet_marker = "OLIPHAUNT_DOCS_SNIPPET liboliphaunt-quickstart" required_pages = [ "index", "guide", @@ -341,5 +239,3 @@ sidebar_pages = [ "index", "guide", ] -reference_artifact = "target/docs/generated/api/c/xml" -snippet_language = "c" diff --git a/docs/internal/CI_RELEASE_PROCESS_AUDIT_2026-09-02.md b/src/docs/internal/CI_RELEASE_PROCESS_AUDIT_2026-09-02.md similarity index 98% rename from docs/internal/CI_RELEASE_PROCESS_AUDIT_2026-09-02.md rename to src/docs/internal/CI_RELEASE_PROCESS_AUDIT_2026-09-02.md index 61d436eb7..733f53494 100644 --- a/docs/internal/CI_RELEASE_PROCESS_AUDIT_2026-09-02.md +++ b/src/docs/internal/CI_RELEASE_PROCESS_AUDIT_2026-09-02.md @@ -27,8 +27,8 @@ fair technical description. The planner ignores affected scope on non-PR runs and selects every builder/runtime job with the reason `non-PR full CI/runtime run`. -The latest `main` change touched only `tools/perf/runner/Cargo.toml` and -`tools/policy/check-native-boundaries.mjs`, but GitHub run +The latest `main` change touched only `src/benchmarks/perf/runner/Cargo.toml` and +`tools/policy/check-native-boundaries.mts`, but GitHub run launched 100 jobs, used approximately 879 raw runner-minutes, took 103 minutes wall-clock, and failed. @@ -71,7 +71,7 @@ in the visible Tests phase. ### 4. “Validate release metadata” is a large unit-test suite -`tools/release/release-check.mjs` first runs metadata validation and then +`tools/release/release-check.sh` first runs metadata validation and then dynamically discovers every `*.test.mjs` under `tools/policy` and `tools/release`. It currently discovers 165 files, excludes one dedicated test, and launches 164 fresh Bun subprocesses per invocation. @@ -107,7 +107,7 @@ gate cannot validate the generated versions or changelog state. ### 6. The “dry run” is candidate assembly, not publication simulation -`release-publish.mjs publish-dry-run` validates metadata and registries and +`release-dry-run.sh` validates metadata and registries and exits before any publication transport executes. The surrounding workflow downloads qualified artifacts, packages public carriers, and creates a publication lock. Its accurate name would be **Assemble and approve release @@ -140,7 +140,7 @@ security principles but is factually unreliable in important places: - It names `graph-tools:check` and `graph-tools:generate`; no `graph-tools` Moon project or task exists at the audited revision. - It says `graph-tools:generate` is the sole writer of `target/graph`, while - `tools/graph/ci_plan.mjs` directly writes `target/graph/ci-plan.json`. + `tools/graph/ci_plan.mts` directly writes `target/graph/ci-plan.json`. - Its opening advice says expensive producers and E2E should run only when relevant inputs change, while hosted CI deliberately does the opposite on every `main` push and every workflow-only PR. @@ -256,8 +256,8 @@ either execute ShellCheck/SwiftLint or stop claiming/bootstrapping them. | Boundary | What it actually does | Judgment and change | | --- | --- | --- | -| `policy-tools:tools-compile` | Shell syntax-checks policy scripts, Bun-compiles every `.mjs` under GitHub scripts/examples/policy/graph, compiles one native CI script, and Python-compiles policy files. | Accurate after replacing the vague `check` name. It now fills CI's existing `tools-compile` task class instead of inventing another class. | -| `policy-tools:fmt`, `js-format-check`, `rust-format-check` | Formats the workspace or checks selected JS/TS/docs/tool paths and Rust separately. | The read-only task names are accurate. The developer guide no longer refers to a nonexistent combined `format-check`; duplicated Cargo formatting in `prek` remains a separate cleanup. | +| `policy-tools:tools-compile` | Shell syntax-checks policy scripts, Bun-compiles every `.mjs` under GitHub scripts/src/examples/policy/graph, compiles one native CI script, and Python-compiles policy files. | Accurate after replacing the vague `check` name. It now fills CI's existing `tools-compile` task class instead of inventing another class. | +| `policy-tools:fmt`, `js-format-check`, `rust-format-check` | Formats the workspace or checks selected JS/TS/src/docs/tool paths and Rust separately. | The read-only task names are accurate. The developer guide no longer refers to a nonexistent combined `format-check`; duplicated Cargo formatting in `prek` remains a separate cleanup. | | `ci-workflows:check` | Runs actionlint, zizmor, workflow-security assertions, three GitHub helper tests, one CI-plan test, and the toolchain-bootstrap test. | Useful and mostly accurate. Stop rerunning its policy tests through the dynamic release suite. | | `repo:check` | A no-op aggregate over tooling semantics, workflow checks, documentation grep policy, release metadata, all-file pre-commit hooks, broker licensing, and native-tools tests. | Accurate only as an aggregate. Do not schedule it beside its children. Rename child tasks precisely and reserve the aggregate for local `qualify-repo`. | | `repo:prek` | Validates Prek config and applies basic file hygiene, TOML/YAML/JSON parsing, secret/size checks, and Cargo formatting to every tracked file. | Useful hygiene, but all-files execution is unnecessary for most PRs. Use affected files and remove its duplicate Cargo-format hook. | @@ -395,7 +395,7 @@ unchanged while changing task ownership: no longer expose identical leaf `package` wrappers; shared native, WASIX, and carrier projects own the actual work. - Generic Moon `release-check` tasks and one-dependency aliases are gone. - The repository-wide `tools/release/release-check.mjs` executable remains, but + The repository-wide `tools/release/release-check.sh` executable remains, but is documented as release-policy validation rather than a product gate. - Rust package qualification no longer greps test-function names to claim coverage. The actual unit/smoke/regression tasks retain those behavior proofs. @@ -538,7 +538,7 @@ Task edges now have an executable invariant: | `outputs` | 11 | Consumer hydrates a producer's declared outputs | All producers declare outputs | | `ignored` | 101 | Ordering/qualification only; no artifact data is consumed | No producer declares outputs | -`product-task-model.test.mjs` now checks this for the entire task graph, the five +`product-task-model.test.mts` now checks this for the entire task graph, the five SDK carrier tasks that consume product package staging, and the absence of `src/ -> tools/` project edges. Moon itself rejects missing targets and cycles while constructing the graph. @@ -838,7 +838,7 @@ coverage, release assembly, and registry checks stay outside the product. Changes: - deleted the five SDK `check-sdk.sh` dispatchers, the native `check-track.sh`, - the broker/Node Direct/WASIX Node-API package dispatchers, three WASIX Rust + the src/broker/Node Direct/WASIX Node-API package dispatchers, three WASIX Rust check dispatchers, the React Native runner source-assertion tests, and the 925-line performance source-string harness; - replaced those dispatchers with ecosystem commands in Moon. The only new @@ -953,7 +953,7 @@ Native release staging now default their carrier input to the same canonical target path used by CI, while retaining CI overrides for downloaded cross-runner artifacts. -The cold local `release-tools:wasix-ts-sdk-package` path then passed end to end +The cold local `oliphaunt-wasix-ts:release-package` path then passed end to end in 39m36s. The portable runtime producer consumed 38m35s (PostgreSQL, ICU, PostGIS, remaining extensions, and package validation); the SDK staging plus real packed browser/database/tools smoke consumed 57s. This establishes both @@ -995,7 +995,7 @@ command/libc tests and four Rust behavior tests. Residual root-tool boundary: SDK, binding, broker, Node Direct, and WASIX Node-API product tasks no longer invoke repository release/performance/coverage machinery. Native, WASIX, Postmaster, extension-artifact, extension-catalog, and -source-input projects still execute root `tools/xtask` or release-contract +source-input projects still execute root `src/runtimes/liboliphaunt/wasix/tools/xtask` or release-contract helpers. The source-fetch implementation itself now lives with its owner under `src/sources/tools`; it still reuses the root process-capture and extension license libraries. The remaining calls are pre-existing production build @@ -1017,7 +1017,7 @@ miniature CI systems: type-check, run their own unit tests, and build/package their own npm source. The root integration task consumes those package outputs plus the separately built portable and Node-API runtime carriers. -- `release-tools:wasix-ts-sdk-package` now only validates and stages release +- `oliphaunt-wasix-ts:release-package` now only validates and stages release artifacts. Browser behavior is no longer concealed inside a task named `package`. - The WASIX Node-API producer was missing the AOT runtime and WASIX extension @@ -1102,7 +1102,7 @@ miniature CI systems: fixtures are excluded from the separate policy mutation suite, and the local guide no longer advertises a nonexistent combined format-check task. - Native implementation edits no longer invalidate `oliphaunt-broker:compile`: - that task checks only broker/Rust SDK code and does not consume or link a + that task checks only src/broker/Rust SDK code and does not consume or link a native artifact. Runtime regressions retain the real dependency. Native and WASIX patch-stack lint now watches only the manifests, patches, consumers, and generated audit document it reads; stale extension/toolchain/`xtask` diff --git a/docs/internal/DONE.md b/src/docs/internal/DONE.md similarity index 98% rename from docs/internal/DONE.md rename to src/docs/internal/DONE.md index cbe7c2d03..5ba0f6e7c 100644 --- a/docs/internal/DONE.md +++ b/src/docs/internal/DONE.md @@ -1,7 +1,7 @@ # Done (Maintainers) > Archived completion log; non-normative. Start with -> `docs/maintainers/README.md` and executable configuration. +> `src/docs/maintainers/README.md` and executable configuration. This was the chronological status log for implementation work completed during the original build-out. It is retained as maintainer-facing history and is @@ -42,7 +42,7 @@ Implemented: validating and copying the full archive in Rust afterward. The C tar writer also uses direct `read(2)` file reads, per-entry buffer reservation, and opt-in `OLIPHAUNT_TRACE_BACKUP=1` phase diagnostics. -- `tools/perf/matrix/run_native_speed_diagnostics.sh` runs repeated +- `src/benchmarks/perf/matrix/run_native_speed_diagnostics.sh` runs repeated fresh-process native-direct and native-PostgreSQL speed-case diagnostics and writes versioned `oliphaunt.native-speed-diagnostics.v1` summaries. The first current-source follow-up run for `20260524T090412Z` reproduced speed misses @@ -89,14 +89,14 @@ Implemented: PostgreSQL 18.4 native release matrix with direct, broker, server, native PostgreSQL, and SQLite rows for RTT, speed, streaming, prepared updates, and backup/restore. Strict - `tools/perf/check-native-perf-report.sh` provenance + `src/benchmarks/perf/check-native-perf-report.sh` provenance verification passed against that recorded source/artifact set; later backup ABI/tar-writer changes require a refreshed full matrix before current-source release claims. The report shows NativeDirect passing RTT, open, and RSS gates while still missing speed-suite p90, speed tail throughput, physical backup/restore p90, and physical backup throughput, so those misses remain tracked work instead of parity claims. -- `tools/xtask` now keeps `wasmer-types` behind the AOT serializer feature. +- `src/runtimes/liboliphaunt/wasix/tools/xtask` now keeps `wasmer-types` behind the AOT serializer feature. Native no-default-feature builds no longer compile that legacy runtime crate, and `sdk-contracts:native-boundaries` guards the feature boundary. @@ -126,7 +126,7 @@ Implemented: package sizing, upstream audits, and source-spine validation; - upstream checkouts are no longer tracked; maintainers fetch pinned sources on demand into ignored `target/oliphaunt-sources/checkouts`; -- source pins live in `src/sources/third-party/**`; +- source pins live in `src/sources/src/third-party/**`; - root packages exclude upstream checkouts from published crates. - `xtask assets verify-committed` validates source-controlled asset inputs, source pins, package metadata, AOT crate templates, and generated extension @@ -467,12 +467,12 @@ Implemented coverage: every packaged candidate. AGE now uses its upstream 32-bit `SIZEOF_DATUM=4` SQL generation path, passes direct/server/restart/lifecycle gates, and is exposed as `extensions::AGE`; -- extension discovery now merges Oliphaunt docs/REPL exports, Oliphaunt package +- extension discovery now merges Oliphaunt src/docs/REPL exports, Oliphaunt package exports, PostgreSQL contrib metadata, `postgres-oliphaunt` `other_extensions` pins, Oliphaunt tests, and the packaged asset manifest into `src/extensions/generated/extensions.catalog.json`; - `xtask assets fetch` now clones/fetches every pinned source from - `src/sources/third-party/**` into ignored `target/oliphaunt-sources/checkouts/**` directories, + `src/sources/src/third-party/**` into ignored `target/oliphaunt-sources/checkouts/**` directories, including the external extension sources for pgtap, pg_ivm, pg_uuidv7, pg_hashids, AGE, PostGIS, and pg_textsearch; - extension build intent now lives in `src/extensions/catalog/extensions.promoted.toml` instead @@ -1004,7 +1004,7 @@ Latest local release work: - Rust product validation runs in product-owned tasks. `pnpm moon run liboliphaunt-wasix:smoke` is the hard runtime gate and requires portable assets plus the host AOT pack; -- `.github/scripts/download-wasix-runtime-build-artifacts.mjs` is a thin wrapper +- `.github/scripts/download-wasix-runtime-build-artifacts.mts` is a thin wrapper over `xtask assets download`; exact-SHA, host-target, and all-target WASIX runtime artifact downloads share one implementation; - AOT serialization is now owned by a maintainer-only `xtask` feature. The @@ -1070,12 +1070,12 @@ following completed work was removed from `TODO.md`: The native SDK parity track now has a no-build public surface inventory: -- `tools/policy/generate-sdk-api-surface.mjs --write` regenerates +- `tools/policy/generate-sdk-api-surface.mts --write` regenerates `src/docs/content/reference/sdk-api-surface.md` from the current Rust, Swift, Kotlin, and React Native SDK sources; - `sdk-contracts:check` runs the generator in `--check` mode so accidental public symbol drift is visible in the fast parity gate; -- `docs/maintainers/sdk-parity-policy.md` links the inventory next to `docs/products/sdk-manifest.toml`, so +- `src/docs/maintainers/sdk-parity-policy.md` links the inventory next to `src/docs/products/sdk-manifest.toml`, so ownership, supported platform shape, and public API review evidence stay together. @@ -1204,8 +1204,8 @@ of the portable Swift/Kotlin/React Native handoff: The native PostgreSQL 18 patch stack now has deterministic source-only release evidence: -- `src/runtimes/liboliphaunt/native/tools/check-patch-stack.mjs --write` generates - `docs/internal/OLIPHAUNT_PATCH_STACK.md` from `src/runtimes/liboliphaunt/native/postgres18/source.toml` +- `src/runtimes/liboliphaunt/native/tools/check-patch-stack.mts --write` generates + `src/docs/internal/OLIPHAUNT_PATCH_STACK.md` from `src/runtimes/liboliphaunt/native/postgres18/source.toml` and the maintained patch directory; - `src/runtimes/liboliphaunt/native/tools/check-track.sh` runs the same script in `--check` mode before native Rust or SDK checks, so stale patch review evidence fails @@ -1234,7 +1234,7 @@ links against only `src/runtimes/liboliphaunt/native/include/oliphaunt.h`: - `oliphaunt/smoke/liboliphaunt_abi_conformance.c` verifies ABI/version constants, capability bits, public struct field types, exported function prototypes, and safe global/no-handle calls without including PostgreSQL server headers; -- `src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs --abi-only` +- `src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mts --abi-only` builds the conformance program with strict C11 warnings and links it to the current `liboliphaunt` shared library; - `src/runtimes/liboliphaunt/native/tools/check-track.sh quick` now runs that @@ -1407,7 +1407,7 @@ expensive work: The native perf report validator now rejects weak evidence by default: -- `tools/perf/check-native-perf-report.sh` passes +- `src/benchmarks/perf/check-native-perf-report.sh` passes `--require-release-evidence` to the provenance verifier; - release verification requires `releaseEvidence=true`, `partialReport=false`, `diagnosticRun=false`, all native engines, all benchmark suites, SQLite and @@ -1658,7 +1658,7 @@ infer recovery behavior from process isolation: React Native now has a repeatable real-app Android validation path instead of only package-level checks: -- `src/sdks/react-native/examples/expo` is an Expo SDK 56 development-build +- `src/sdks/react-native/src/examples/expo` is an Expo SDK 56 development-build app pinned to React Native 0.85 and the local packed `@oliphaunt/react-native` SDK, and its app smoke now calls the installed package runner directly before attaching the example's CRUD/perf workload via @@ -1672,7 +1672,7 @@ only package-level checks: - the smoke generates the ignored Expo `android/` project on demand, so a clean checkout does not need committed native project output before app-level validation can run; -- `pnpm --dir src/sdks/react-native/examples/expo run smoke:android` exposes the same +- `pnpm --dir src/sdks/react-native/src/examples/expo run smoke:android` exposes the same installed-app gate as a named validation lane, and SDK parity checks require the harness, docs, example command, and machine-readable pass signal to stay present; @@ -1701,7 +1701,7 @@ Expo MCP tool path: packaged resource root or app frameworks when `libraryPath` is not supplied, so app developers do not need host-environment library overrides for normal packaged builds; -- `src/sdks/react-native/examples/expo` installs `expo-mcp` and exposes +- `src/sdks/react-native/src/examples/expo` installs `expo-mcp` and exposes `npm run mcp:start`, which runs `EXPO_UNSTABLE_MCP_SERVER=1 expo start --dev-client` for Codex/MCP-driven local logs, DevTools, screenshots, and automation. @@ -1716,7 +1716,7 @@ PostgreSQL artifact lane exists: no `PG_VERSION`; - macOS keeps the direct `initdb` tooling fallback, so desktop smoke and local native iteration continue to work from an empty PGDATA root; -- `src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs --abi-only` now +- `src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mts --abi-only` now performs a fast iOS simulator syntax check over the liboliphaunt C shim files, catching forbidden mobile C APIs without rebuilding PostgreSQL for iOS. @@ -1785,7 +1785,7 @@ The native perf harness now accepts the same tuning shape: streaming, and native-PostgreSQL control runs; - Expo Android/iOS smoke and benchmark harnesses forward durability, runtime footprint, and startup GUCs through Metro env and dev-client links; -- `tools/perf/matrix/run_mobile_footprint_matrix.sh` enumerates the requested +- `src/benchmarks/perf/matrix/run_mobile_footprint_matrix.sh` enumerates the requested Android/iOS shared-buffer, WAL-buffer, WAL-minimum, and Safe/Balanced device sweep. It skips `min_wal_size=8MB/16MB` by default because the current PG18 artifact uses 16MB WAL segments and PostgreSQL rejects those GUC-only minima. diff --git a/docs/internal/IMPLEMENTATION_CHECKLIST.md b/src/docs/internal/IMPLEMENTATION_CHECKLIST.md similarity index 93% rename from docs/internal/IMPLEMENTATION_CHECKLIST.md rename to src/docs/internal/IMPLEMENTATION_CHECKLIST.md index d70d07f62..afad3660e 100644 --- a/docs/internal/IMPLEMENTATION_CHECKLIST.md +++ b/src/docs/internal/IMPLEMENTATION_CHECKLIST.md @@ -6,14 +6,14 @@ > executable sources it identifies. This was the implementation checklist used while making the repository match -`docs/architecture/final-product-source-architecture.md`. Its checked state is +`src/docs/architecture/final-product-source-architecture.md`. Its checked state is historical evidence, not a statement about the current tree. Use the current maintainer index and executable validation for present-day decisions. In -particular, derive CI selection from [`tools/graph/ci_plan.mjs`](../../tools/graph/ci_plan.mjs), +particular, derive CI selection from [`tools/graph/ci_plan.mts`](../../../tools/graph/ci_plan.mts), extension membership from the -[`src/extensions/catalog`](../../src/extensions/catalog) and product target +[`src/extensions/catalog`](../../extensions/catalog) and product target manifests, artifact/package targets from -[`tools/release/release-artifact-targets.mjs`](../../tools/release/release-artifact-targets.mjs), +[`src/shared/product-metadata/release-artifact-targets.mts`](../../shared/product-metadata/release-artifact-targets.mts), and release procedure from the [release runbook](../maintainers/release.md). Numbers such as the historical 39-extension total are snapshots and are intentionally not maintained here. @@ -32,7 +32,7 @@ intentionally not maintained here. - `src/extensions/` - `src/runtimes/liboliphaunt/native/` - `src/runtimes/liboliphaunt/wasix/` - - `src/runtimes/broker/` + - `src/runtimes/src/broker/` - `src/runtimes/node-direct/` - `src/sdks/rust/` - `src/sdks/swift/` @@ -46,7 +46,7 @@ intentionally not maintained here. - `src/docs/` - [x] Generated local state is ignored and untracked. Evidence: `bash tools/policy/check-repo-structure.sh` passes, and tracked-file scans - find no root `assets/`, root `crates/`, root `sdks/`, root runtime build + find no root `assets/`, root `crates/`, root `src/sdks/`, root runtime build trees, or generated local state under product source roots. - [x] Retired root aliases and old product roots are rejected. Evidence: `bash tools/policy/check-repo-structure.sh` passes, `find . -maxdepth 2` @@ -59,7 +59,7 @@ intentionally not maintained here. `tools/dev/bun.sh tools/graph/graph.mjs check` passes and reports Moon projects/release products. - [x] Stable CI job names are derived from Moon task `ci-*` tags. Evidence: - `tools/graph/ci_plan.mjs` and `tools/policy/check-moon-product-graph.mjs`. + `tools/graph/ci_plan.mts` and `tools/policy/check-moon-product-graph.mjs`. - [x] Runtime target fan-out is metadata-driven, not hardcoded in mobile jobs. Evidence: focused mobile planner output selects complete native runtime and native extension compatibility domains by surface, and `tools/policy/check-release-policy.py` @@ -67,7 +67,7 @@ intentionally not maintained here. `android-x86_64` extension artifacts while iOS mobile builds request only `ios-xcframework`. - [x] Moon dependency scopes encode source/qualification impact; product-local compatibility metadata encodes published dependencies. - Evidence: `tools/dev/bun.sh tools/release/release_plan.mjs --changed-file ... --format json` + Evidence: `bash tools/release/release-plan.sh --changed-file ... --format json` probes prove extension catalog changes run affected CI without releases, exact extension target changes release only that extension product, native runtime patches release only native, and WASIX patches release only @@ -124,7 +124,7 @@ intentionally not maintained here. release-wide `extension-packages` path may stage all exact-extension products. - [x] Builds workflow has a builder-only aggregate. Evidence: - `tools/graph/ci_plan.mjs` emits `builder_jobs`, and the `Builds` GitHub job + `tools/graph/ci_plan.mts` emits `builder_jobs`, and the `Builds` GitHub job fails if any selected runtime, helper runtime, SDK package, exact-extension artifact/package, or mobile app builder fails. Local planner probe confirms a full run selects runtime, WASIX, helper, SDK, extension, and mobile app @@ -176,7 +176,7 @@ intentionally not maintained here. the platform app artifact path. They do not build WASIX extension artifacts and do not start emulator/simulator E2E jobs in the `Builds` workflow. - [x] Mobile-focused extension artifact builders are target-scoped. Evidence: - direct `tools/graph/ci_plan.mjs` probes show Android mobile builds select + direct `tools/graph/ci_plan.mts` probes show Android mobile builds select native extension artifacts for `android-arm64-v8a` and `android-x86_64` only, iOS mobile builds select `ios-xcframework` only, and standalone extension-package builds still select every published native @@ -200,7 +200,7 @@ intentionally not maintained here. Swift source archive for CocoaPods. - [x] Mobile build jobs inspect the produced app artifact for selected-extension correctness. Evidence: CI runs - `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --require-mobile android + `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-mobile android --require-mobile-prebuilt-extensions` and the corresponding iOS command after app build, so the app package must contain only selected extension files and must have matching prebuilt exact-extension package inputs. @@ -211,7 +211,7 @@ intentionally not maintained here. unpacking exact-extension artifacts; `src/sdks/react-native/tools/expo-ios-runner.sh` stages generated registry C under compile-only `ios/generated/static-registry/`; and - `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --require-mobile ios + `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-mobile ios --require-mobile-prebuilt-extensions` now requires Xcode link evidence for selected extension frameworks while rejecting build-only registry source or extension-framework inputs inside the final `.app` resource bundle. @@ -222,7 +222,7 @@ intentionally not maintained here. `oliphaunt-android-static-extension-link-v1` rows for ABI, liboliphaunt, each selected static extension archive, and dependency archives. React Native Android passes the same property through its builder and - `bun test src/sdks/react-native/tools/validate-android-link-evidence.test.mjs` asserts that + `bun test src/sdks/react-native/tools/validate-android-link-evidence.test.mts` asserts that vector's `liboliphaunt_extension_vector.a` was linked for the selected ABI. The staged mobile artifact checker now requires this Android link evidence whenever `--require-mobile android --require-mobile-prebuilt-extensions` is @@ -236,7 +236,7 @@ intentionally not maintained here. `swift-sdk-package` depends on `liboliphaunt-native-ios-abi`, downloads `liboliphaunt-native-abi-compatible-release-assets-ios-datum64`, sets `OLIPHAUNT_SWIFT_RELEASE_ASSET_DIR`, and - `release-tools:swift-sdk-package` fails closed unless that + `oliphaunt-swift:release-package` fails closed unless that directory contains a real `liboliphaunt--apple-spm-xcframework.zip` with macOS, iOS device, and iOS simulator slices. @@ -259,7 +259,7 @@ intentionally not maintained here. the package boundary. Evidence: `tools/dev/bun.sh tools/release/build-sdk-ci-artifacts.mjs` stages `target/sdk-artifacts/oliphaunt-kotlin/maven` only, React Native Android derives the Kotlin dependency from that staged Maven repo, and - `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs` now requires the Maven repository + `tools/dev/bun.sh tools/release/check-staged-artifacts.mts` now requires the Maven repository instead of loose top-level AAR/JAR files. - [x] CI keeps build, check, test, and installed-app E2E phases separate. Evidence: `.github/workflows/ci.yml` has distinct `Checks`, `Tests`, `Builds`, @@ -273,7 +273,7 @@ intentionally not maintained here. the release artifact gate because it depends on the staged mobile app artifacts that `Builds` validates. - [x] Full non-PR Builds runs are deliverable builders by default. Evidence: - `tools/graph/ci_plan.mjs::planForFullRun()` starts from `BUILDER_JOBS` + `tools/graph/ci_plan.mts::planForFullRun()` starts from `BUILDER_JOBS` plus the WASIX AOT target planner dependency, and `tools/policy/check-release-policy.py` rejects full-run plans that select non-builder side lanes such as `repo`, `release-intent`, docs, regressions, @@ -286,7 +286,7 @@ intentionally not maintained here. `OLIPHAUNT_EXPO_ALLOW_NATIVE_BUILDS=0`, `OLIPHAUNT_EXPO_REQUIRE_SDK_ARTIFACTS=1`, and `OLIPHAUNT_EXPO_REQUIRE_PREBUILT_EXTENSIONS=1`; and run strict - `check-staged-artifacts.mjs --require-mobile-*-prebuilt-extensions` + `check-staged-artifacts.mts --require-mobile-*-prebuilt-extensions` validation after app build. Android and iOS mobile builders now force release-mode app artifacts (`OLIPHAUNT_EXPO_ANDROID_BUILD_TYPE=release`, `OLIPHAUNT_EXPO_IOS_CONFIGURATION=Release`, and @@ -299,7 +299,7 @@ intentionally not maintained here. `react-native-mobile-android-app-android-x86_64` and `react-native-mobile-ios-app`, run the pinned Maestro path through `src/sdks/react-native/tools/mobile-e2e.sh`, start Android with - `tools/dev/start-android-emulator-ci.sh`, and do not invoke + `tools/ci/start-android-emulator-ci.sh`, and do not invoke `run-planned-moon-job.sh`, `mobile-build:*`, or native/source-build fallback paths. `tools/policy/check-release-policy.py` enforces these invariants. - [x] React Native mobile task semantics match the Moon CI model. Evidence: @@ -318,12 +318,12 @@ intentionally not maintained here. changelogs, and tags. Evidence: `release-please-config.json` and `.release-please-manifest.json`. - [x] Product-local `release.toml` files own registry/package metadata. - Release code imports it directly from `release-graph.mjs` and - `release-artifact-targets.mjs`; the workflow query wrapper exposes only the + Release code imports it directly from `release-graph.mts` and + `release-artifact-targets.mts`; the workflow query wrapper exposes only the four projections consumed across process boundaries. - [x] There is no active `release-graph.toml`, `release-inputs.toml`, or `tools/graph/jobs.toml` release brain. -- [x] `tools/dev/bun.sh tools/release/release_plan.mjs` uses Moon project ownership and dependency +- [x] `bash tools/release/release-plan.sh` uses Moon project ownership and dependency scopes for release closure. Evidence: direct release-plan probes for extension catalog, PostGIS target metadata, native runtime patch, and WASIX runtime patch paths. @@ -345,7 +345,7 @@ intentionally not maintained here. not shadow earlier complete runs. - [x] WASIX runtime release download filters same-SHA CI runs by the `Builds` job before installing portable/AOT runtime outputs. Evidence: - `.github/scripts/download-wasix-runtime-build-artifacts.mjs` invokes + `.github/scripts/download-wasix-runtime-build-artifacts.mts` invokes `xtask assets download --required-job Builds`, `xtask` verifies the required job conclusion before trying a run, and `tools/release/check_artifact_targets.py` enforces the handoff. @@ -396,35 +396,35 @@ intentionally not maintained here. a stale `target/extensions/native/release-assets/test-mobile` directory no longer creates duplicate vector package rows. - [x] Exact-extension package assembly has no broad native-index fallback. - Evidence: `tools/release/build-extension-ci-artifacts.mjs` now requires + Evidence: `src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts` now requires product-scoped target indexes from `target/extensions/native/release-assets///...` and fails when required target artifacts are missing. - [x] Mobile exact-extension package assembly filters to the requested mobile native targets instead of carrying every downloaded desktop/native artifact into mobile build handoff artifacts. Evidence: - `tools/dev/bun.sh tools/release/build-extension-ci-artifacts.mjs + `tools/dev/bun.sh src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts oliphaunt-extension-vector --output-root target/extension-artifacts-mobile-validate --require-native-target android-x86_64 --require-native-target ios-xcframework` stages only `android-x86_64` and `ios-xcframework` vector assets. - [x] Exact-extension release packages emit JSON manifest, ecosystem-friendly `.properties` manifest, and checksum manifest. Evidence: - `tools/release/build-extension-ci-artifacts.mjs oliphaunt-extension-vector + `src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts oliphaunt-extension-vector --output-root target/extension-artifacts-test` staged `oliphaunt-extension-vector-0.1.0-manifest.properties` and `oliphaunt-extension-vector-0.1.0-release-assets.sha256`. - [x] SDK package checks prove wrapper packages do not ship runtime or extension payloads. Evidence: - `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --inspect-present` validates staged + `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --inspect-present` validates staged Swift, Kotlin, React Native, and TypeScript package artifacts, rejects runtime/share/static-registry payload leaks, and caught then removed a stale Kotlin debug AAR that embedded smoke runtime/vector assets. SDK staging now - runs `check-staged-artifacts.mjs --require-sdk-product "$product"` for every + runs `check-staged-artifacts.mts --require-sdk-product "$product"` for every SDK product and stages only the Kotlin release AAR. - [x] Mobile app artifact checks prove unselected extension files do not enter app artifacts. Evidence: - `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --require-mobile ios + `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-mobile ios --require-mobile-prebuilt-extensions` validates the fresh iOS `.app` built from staged React Native, Swift, liboliphaunt, and exact-extension artifacts; the checker binds the build report to the inspected app path, byte size, @@ -504,7 +504,7 @@ intentionally not maintained here. released. - [x] Node direct optional npm packages are built in the Builds workflow and published from staged tarballs. Evidence: - `tools/release/package-node-direct-runtime.sh` emits both + `src/runtimes/node-direct/tools/package-node-direct-runtime.sh` emits both `target/oliphaunt-node-direct/release-assets/*` and `target/oliphaunt-node-direct/npm-packages/*.tgz`; the release workflow downloads `oliphaunt-node-direct-npm-package-*`; `release.py` validates and @@ -517,7 +517,7 @@ intentionally not maintained here. narrowed WASIX workspace package set so Cargo sees the same-release internal asset/AOT crates, stages only `oliphaunt-wasix-0.5.1.crate` plus package-file metadata under `target/sdk-artifacts/oliphaunt-wasix-rust`, and - `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --require-sdk-product + `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-sdk-product oliphaunt-wasix-rust` validates that the SDK artifact does not carry runtime payloads. @@ -546,10 +546,10 @@ Run before claiming this architecture complete: - [x] `tools/dev/bun.sh tools/release/build-sdk-ci-artifacts.mjs --help` - [x] `python3 -m py_compile tools/release/release.py - tools/release/build-extension-ci-artifacts.mjs + src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts tools/release/check_artifact_targets.py tools/release/check_release_metadata.py` -- [x] `tools/dev/bun.sh tools/graph/ci_plan.mjs --help` +- [x] `tools/dev/bun.sh tools/graph/ci_plan.mts --help` - [x] `tools/dev/bun.sh tools/graph/graph.mjs check` - [x] `node tools/policy/check-moon-product-graph.mjs` - [x] `python3 tools/release/check_artifact_targets.py` @@ -574,22 +574,22 @@ Run before claiming this architecture complete: verifies local package shape only; publishable SDK artifact envelopes use explicit `package-artifacts` builder tasks, and runtime/extension/mobile artifacts stay in target-scoped builder jobs. -- [x] `tools/dev/bun.sh tools/graph/ci_plan.mjs` for a full run now selects only +- [x] `tools/dev/bun.sh tools/graph/ci_plan.mts` for a full run now selects only `affected` plus 21 artifact-producing builder jobs. WASIX AOT target fan-out is emitted by the affected plan as `liboliphaunt_wasix_aot_runtime_matrix`; there is no separate AOT planner job in the Builds workflow. - [x] `GITHUB_EVENT_NAME=workflow_dispatch NATIVE_TARGET=all WASM_TARGET=linux-x64-gnu MOBILE_TARGET=all - tools/dev/bun.sh tools/graph/ci_plan.mjs` now selects only + tools/dev/bun.sh tools/graph/ci_plan.mts` now selects only `affected`, `liboliphaunt-wasix-runtime`, and `liboliphaunt-wasix-aot`; it does not select `liboliphaunt-wasix-release-assets`, `wasix-rust-package`, SDK packages, extension packages, or mobile builders. The emitted AOT matrix contains the single friendly target id `linux-x64-gnu`. -- [x] `tools/dev/bun.sh tools/release/release_plan.mjs` -- [x] `tools/dev/bun.sh tools/release/release-check.mjs` -- [x] `tools/dev/bun.sh tools/release/release-publish.mjs publish-dry-run --products-json +- [x] `bash tools/release/release-plan.sh` +- [x] `bash tools/release/release-check.sh` +- [x] `bash tools/release/release-dry-run.sh --products-json '["oliphaunt-extension-vector"]' --head-ref HEAD` fails closed when the staged exact-extension package is incomplete or missing. - [x] `python3 tools/release/artifact_target_matrix.py @@ -610,46 +610,46 @@ Run before claiming this architecture complete: XCFramework zip has macOS, iOS device, and iOS simulator slices. This proves the Swift SDK package artifact path renders a checksum-pinned public `Package.swift.release`, stages `Oliphaunt-source.zip`, and passes - `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --require-sdk-product + `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-sdk-product oliphaunt-swift`. The CI `liboliphaunt-native-ios` builder still owns proof that the real native Apple XCFramework asset is produced. - [x] `GITHUB_EVENT_NAME=workflow_dispatch NATIVE_TARGET=all - WASM_TARGET=all MOBILE_TARGET=ios tools/dev/bun.sh tools/graph/ci_plan.mjs` + WASM_TARGET=all MOBILE_TARGET=ios tools/dev/bun.sh tools/graph/ci_plan.mts` - [x] `GITHUB_EVENT_NAME=workflow_dispatch NATIVE_TARGET=all - WASM_TARGET=all MOBILE_TARGET=android tools/dev/bun.sh tools/graph/ci_plan.mjs` -- [x] `tools/graph/ci_plan.mjs` direct probe for + WASM_TARGET=all MOBILE_TARGET=android tools/dev/bun.sh tools/graph/ci_plan.mts` +- [x] `tools/graph/ci_plan.mts` direct probe for `{"extension-artifacts-native:build-target"}` selects `extension-artifacts-native` without `liboliphaunt-native`, proving extension artifact-only work does not create a native-runtime waterfall. -- [x] `tools/graph/ci_plan.mjs` direct probes for +- [x] `tools/graph/ci_plan.mts` direct probes for `oliphaunt-react-native:mobile-build-android` and `oliphaunt-react-native:mobile-build-ios` select only Android or iOS native extension artifacts respectively. -- [x] `tools/graph/ci_plan.mjs` direct probe for +- [x] `tools/graph/ci_plan.mts` direct probe for `oliphaunt-react-native:package-artifacts` selects `react-native-sdk-package`, `mobile-build-android`, `mobile-build-ios`, `kotlin-sdk-package`, `swift-sdk-package`, Android/iOS native runtime builders, and `mobile-extension-packages`; native target selection is exactly `android-arm64-v8a`, `android-x86_64`, and `ios-xcframework`. -- [x] `tools/graph/ci_plan.mjs` direct probe for a single +- [x] `tools/graph/ci_plan.mts` direct probe for a single `oliphaunt-extension-postgis` change with aggregate artifact/package tasks selects only `oliphaunt-extension-postgis`, emits 6 native rows, and emits 1 WASIX row. -- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs +- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-sdk-product oliphaunt-rust` -- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs +- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-sdk-product oliphaunt-kotlin` -- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs +- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-sdk-product oliphaunt-swift` -- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs +- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-sdk-product oliphaunt-react-native` -- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs +- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-sdk-product oliphaunt-js` -- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs +- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-sdk-product oliphaunt-wasix-rust` -- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --require-mobile ios +- [x] `tools/dev/bun.sh tools/release/check-staged-artifacts.mts --require-mobile ios --require-mobile-prebuilt-extensions` passes after rebuilding - `pnpm --dir examples/react-native-expo run mobile-build:ios` with + `pnpm --dir src/examples/react-native-expo run mobile-build:ios` with staged SDK, native runtime, and exact-extension artifacts. The fresh app keeps generated static-registry C under compile-only `ios/generated/static-registry`, bundles runtime resources under @@ -672,10 +672,10 @@ Run before claiming this architecture complete: `_liboliphaunt_selected_static_extensions` plus vector registry symbols, and Maestro sees `liboliphaunt-smoke-status-passed`. - [x] `GITHUB_EVENT_NAME=workflow_dispatch NATIVE_TARGET=ios-xcframework - WASM_TARGET=all MOBILE_TARGET=all tools/dev/bun.sh tools/graph/ci_plan.mjs` + WASM_TARGET=all MOBILE_TARGET=all tools/dev/bun.sh tools/graph/ci_plan.mts` - [x] Focused mobile builder plans are target-consistent: `GITHUB_EVENT_NAME=workflow_dispatch NATIVE_TARGET=android-arm64-v8a - WASM_TARGET=all MOBILE_TARGET=android tools/dev/bun.sh tools/graph/ci_plan.mjs` + WASM_TARGET=all MOBILE_TARGET=android tools/dev/bun.sh tools/graph/ci_plan.mts` expands to both Android ABI receipt/extension producers and one representative `android-x86_64` emulator app; the matching iOS probe emits only `ios-xcframework`. Incompatible focused inputs such as @@ -688,15 +688,15 @@ Run before claiming this architecture complete: through `sdkmanager`, and passes idempotently on the local Android SDK with NDK `27.0.12077973`, CMake `3.22.1`, and compile SDK `36`. - [x] `moon run oliphaunt-kotlin:check` -- [x] `bash tools/release/package-node-direct-runtime.sh` -- [x] `tools/dev/bun.sh tools/release/build-extension-ci-artifacts.mjs +- [x] `bash src/runtimes/node-direct/tools/package-node-direct-runtime.sh` +- [x] `tools/dev/bun.sh src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts oliphaunt-extension-vector --output-root target/extension-artifacts-validate --require-native-target android-x86_64 --require-native-target ios-xcframework` - [x] `./gradlew :oliphaunt-android-gradle-plugin:compileJava :oliphaunt:tasks --no-daemon` - [x] `swift test --package-path src/sdks/swift --scratch-path target/swift-test-extension-resolver-2` -- [x] `tools/dev/bun.sh tools/release/release-publish.mjs publish-dry-run` +- [x] `bash tools/release/release-dry-run.sh` passes in public no-product policy/metadata mode. Product-scoped dry-runs still require staged builder artifacts from the same-SHA `Builds` workflow and remain covered by the @@ -710,7 +710,7 @@ Run before claiming this architecture complete: `python3 tools/policy/check-release-policy.py`. - [x] Local PR 38 CI hardening checks passed after fixing the observed builder failures: `cargo run -p xtask -- assets verify-committed`, `bash -n` for the - touched native scripts, `sh -n tools/release/package-node-direct-runtime.sh`, + touched native scripts, `sh -n src/runtimes/node-direct/tools/package-node-direct-runtime.sh`, `actionlint .github/workflows/ci.yml .github/workflows/mobile-e2e.yml .github/workflows/release.yml`, `python3 tools/release/check_artifact_targets.py`, `python3 tools/policy/check-release-policy.py`, @@ -781,7 +781,7 @@ Run before claiming this architecture complete: blockers: Android x86_64 and Linux arm64 native-runtime source fetches failed through `ftpmirror.gnu.org` libiconv 502s, Apple extension runtime builds passed the embedded `-bundle_loader` through `PG_LDFLAGS` so PostgreSQL's Darwin default - `BE_DLLLIBS=-bundle_loader ../../src/backend/postgres` won and failed when + `BE_DLLLIBS=-bundle_loader ../../backend/postgres` won and failed when the backend executable link was intentionally tolerated, and the Windows exact-extension row still selected `pgcrypto` even though the current Windows runtime disables SSL/OpenSSL and does not package that dependency. The @@ -796,7 +796,7 @@ Run before claiming this architecture complete: `build-postgres18-macos.sh`, `bash -n` for touched shell scripts, `cargo run -p xtask -- assets verify-committed`, `moon run source-inputs:unit --upstream none`, - `python3 src/extensions/tools/check-extension-model.py --check`, + `python3 src/extensions/tools/check-extension-model.sh --check`, `python3 tools/release/check_artifact_targets.py`, `python3 tools/policy/check-release-policy.py`, `moon run extensions:lint`, @@ -851,7 +851,7 @@ Run before claiming this architecture complete: `build-ios-extension-xcframeworks.sh` because Bash 3.2 plus `set -u` treats empty selected dependency arrays as unbound during XCFramework manifest and dependency packaging. The follow-up guards the empty-array expansions for - selected dependencies/extensions/stems and adds a mobile policy assertion for + selected dependencies/src/extensions/stems and adds a mobile policy assertion for the strict-mode guard. Local evidence after this patch passed: `bash -n` for the touched shell scripts, `moon run extensions:lint`, `git diff --check`, and a focused `dict_xsyn` iOS XCFramework packaging @@ -985,7 +985,7 @@ Run before claiming this architecture complete: WASIX runtime/AOT, exact-extension, SDK, mobile app, `artifact-builders`, and `required` jobs before the WASIX release version bump below. - [x] Local release version freshness no longer blocks the selected product - closure. `tools/dev/bun.sh tools/release/check_release_versions.mjs --products-json + closure. `tools/dev/bun.sh tools/release/check_release_versions.mts --products-json "$(cat target/release-dry-run-local/products.json)" --head-ref HEAD` first failed because `liboliphaunt-wasix` and `oliphaunt-wasix-rust` still used `0.5.1` while legacy tag `0.5.1` points at the old release commit. The @@ -993,10 +993,10 @@ Run before claiming this architecture complete: crates, pins `oliphaunt-wasix` runtime crate dependencies to `=0.6.0`, refreshes root and Tauri example lockfiles, and updates the optional perf-runner dependency. Local checks passed after the bump: `tools/dev/bun.sh - tools/release/release-check.mjs`, + tools/release/release-check.sh`, `tools/release/sync-example-lockfiles.mjs --check`, `cargo metadata --locked --format-version 1 --no-deps`, `tools/dev/bun.sh - tools/release/release-check-registries.mjs --products-json "$(cat + tools/release/release-check-registries.sh --products-json "$(cat target/release-dry-run-local/products.json)" --head-ref HEAD`, and `git diff --check`. - [x] The WASIX Rust publishing surface now uses the WASIX product name instead @@ -1006,8 +1006,8 @@ Run before claiming this architecture complete: artifact paths use `target/oliphaunt-wasix`. Local evidence: hidden-file-aware scan for the retired WASM package/import spellings returns no source matches, `cargo metadata --locked --format-version 1 --no-deps` resolves the renamed - packages, `tools/dev/bun.sh tools/release/release-check.mjs` passes, and - `tools/dev/bun.sh tools/release/release-check-registries.mjs --products-json "$(cat + packages, `bash tools/release/release-check.sh` passes, and + `bash tools/release/release-check-registries.sh --products-json "$(cat target/release-dry-run-local/products.json)" --head-ref HEAD` reports `crates:oliphaunt-wasix@0.6.0` plus the renamed internal WASIX crates. - [x] GitHub Builds run `27448574605` on `927457d3` proved the native @@ -1028,7 +1028,7 @@ Run before claiming this architecture complete: source template; the Windows path now mirrors the PostGIS Makefile by preprocessing `rtpostgis.sql` and generating `uninstall_rtpostgis.sql` through `utils/create_uninstall.pl`. The `1e88feb` retry got past that point and failed - later because `extensions/postgis_extension_helper.sql` was not generated; the + later because `src/extensions/postgis_extension_helper.sql` was not generated; the Windows path now preprocesses `postgis_extension_helper.sql.in` before composing extension upgrade SQL. The `d3cb9bd` replacement run `27451612217` got past the missing helper but failed because the handwritten SQL preprocessor treated @@ -1107,8 +1107,8 @@ Run before claiming this architecture complete: compatibility headers now define `PROJ_DLL` empty before `proj.h` is included, and the PostGIS compatibility header maps those case-insensitive string calls to MSVC's `_stricmp`/`_strnicmp`. Local evidence passed: - `bun src/sources/tools/fetch-sources.mjs native-runtime --force`, - `bun src/sources/tools/fetch-sources.mjs wasix-runtime --force`, + `bash src/sources/tools/fetch-sources.sh native-runtime --force`, + `bash src/sources/tools/fetch-sources.sh wasix-runtime --force`, `node tools/policy/check-moon-product-graph.mjs`, `bash tools/policy/check-tooling-stack.sh`, `bash tools/policy/check-repo-structure.sh`, Bash syntax checks for touched @@ -1122,7 +1122,7 @@ Run before claiming this architecture complete: both Android mobile build rows, `E2E / mobile-ios`, `E2E / mobile-android`, the aggregate `E2E` gate, the aggregate `Builds` gate, and `Required`. - [ ] Release workflow dry-run green for selected products. Historical note: - an earlier local check used `release-check-registries.mjs + an earlier local check used `release-check-registries.sh --require-identities` and therefore reported the not-yet-created first-release identities as a blocker. That is intentionally not the hosted first-release order. The current `publish-dry-run` is credential-free and @@ -1146,9 +1146,9 @@ Run before claiming this architecture complete: `proj/proj.db`. Target metadata now publishes those nine rows on `windows-x64-msvc`, so the native exact-extension matrix reports 39 Windows products. Local evidence after this patch passed: - `python3 src/extensions/tools/check-extension-model.py --write-evidence`, - `python3 src/extensions/tools/check-extension-model.py --check`, - `tools/dev/bun.sh tools/release/release-check.mjs`, + `python3 src/extensions/tools/check-extension-model.sh --write-evidence`, + `python3 src/extensions/tools/check-extension-model.sh --check`, + `bash tools/release/release-check.sh`, `python3 tools/release/artifact_target_matrix.py extension-artifacts-native`, and `git diff --check`. GitHub CI run `27744307637` then passed `Builds / extension-native (windows-x64-msvc)`, proving the expanded MSVC producers on @@ -1158,7 +1158,7 @@ Run before claiming this architecture complete: ## Tooling Cleanup Progress - [x] Native mobile CI target staging now uses the Bun - `build-ci-target.mjs` wrapper from Moon. The retired shell wrapper is blocked + `build-ci-target.mts` wrapper from Moon. The retired shell wrapper is blocked by `tools/policy/check-tooling-stack.sh`, while the product-owned native build scripts remain in their existing platform shell/PowerShell lanes. diff --git a/docs/internal/MONOREPO_SIMPLIFICATION_PLAN_2026-09-04.md b/src/docs/internal/MONOREPO_SIMPLIFICATION_PLAN_2026-09-04.md similarity index 98% rename from docs/internal/MONOREPO_SIMPLIFICATION_PLAN_2026-09-04.md rename to src/docs/internal/MONOREPO_SIMPLIFICATION_PLAN_2026-09-04.md index 60fd05035..618e9dfd3 100644 --- a/docs/internal/MONOREPO_SIMPLIFICATION_PLAN_2026-09-04.md +++ b/src/docs/internal/MONOREPO_SIMPLIFICATION_PLAN_2026-09-04.md @@ -51,7 +51,7 @@ uncached. Use `moon task-graph --json` for this inventory: `moon query tasks` omits internal tasks. Tracked-file footprint, including comments/tests/data: `tools/` has 517 files / -176,086 lines; `tools/release/` accounts for 353 / 114,614; `tools/xtask/` for +176,086 lines; `tools/release/` accounts for 353 / 114,614; `src/runtimes/liboliphaunt/wasix/tools/xtask/` for 14 / 13,469. The CI workflow alone is 3,290 lines. These identify review areas, not safe deletion totals. The open PR already reports 15,104 deleted versus 5,381 added lines across 314 files; deletion count has not translated into a @@ -64,7 +64,7 @@ comparable reduction in full-run cost. | 1 — native | Make real producer outputs explicit and reusable. Postmaster `runtime-build` / `postgres-build` and native `release-runtime` currently produce files without declaring Moon outputs. Cache their complete, target-specific deliverables; split portable production from host compiler/executor production so independent hosts can start concurrently. | Cold builds work; patch/toolchain/target changes invalidate; missing outputs hydrate or rebuild; restored binaries retain executable modes and provenance. | | 2 — shrink | Remove hidden qualification from builders. Postmaster `runtime/bin/build-runtime.sh` contains 86 `cargo test` invocations, including test-list probes, followed by release builds. Group tests by actual crate/feature/platform requirements and run explicit behavioral targets. Its `portable-inputs` depends on regression, and `release-assets` depends on stress/recovery. Put those proof edges on `qualify`; tests depend on prepared sources, not release binaries they do not consume. | All patched Wasmer behavior, memory isolation, concurrent connections, recovery and target-specific tests remain scheduled. Preserve distinct feature sets; do not combine compiler/headless profiles indiscriminately. | | 3 — delete/shrink | **Implemented:** hand-written product dependency implications are gone. Directly affected tasks and the resolved Moon DAG now select stable tagged jobs; GitHub retains runner/artifact transport only. | Every selected consumer has all producers, platform artifacts and required proof jobs; no missing-job success. GitHub still needs cross-runner transport and a static job skeleton. | -| 4 — shrink | Separate package-owned assembly from release control. `tools/release` mixes carrier creation, binary validation, licensing, registry publication and graph loading. `src/sources/tools/fetch-sources.mjs` imports a release-layer license auditor; product packagers import root release helpers. Preserve small pure shared libraries, but product code must not invoke the release planner. | Archive safety, licenses, ABI compatibility, integrity, exact candidate identity and publication recovery remain. Do not replace one large tool with a generic framework in every product. | +| 4 — shrink | Separate package-owned assembly from release control. `tools/release` mixes carrier creation, binary validation, licensing, registry publication and graph loading. `src/sources/tools/fetch-sources.mts` imports a release-layer license auditor; product packagers import root release helpers. Preserve small pure shared libraries, but product code must not invoke the release planner. | Archive safety, licenses, ABI compatibility, integrity, exact candidate identity and publication recovery remain. Do not replace one large tool with a generic framework in every product. | | 5 — native | Complete source-level sharing through existing [PR #166](https://github.com/f0rr0/oliphaunt/pull/166). `src/shared/js-core/moon.yml` still generates six checked-in mirrors into three consumers. Import a workspace module and bundle or publish it using normal package tooling. | Packed SDKs work outside the checkout; no unpublished workspace dependency leaks. Do not maintain a second implementation of that PR here. | | 6 — delete/shrink | Remove source-spelling tests after their intended invariant is either executable or explicitly retired. Postmaster's Python ownership verifiers parse Rust implementation text. The current task-model test accepts missing producer outputs as ordering edges and recognizes quality only through selected tags, so it misses real hidden work. | Keep parsed public-manifest checks, negative tamper tests, clean-consumer installation and runtime behavior. A string assertion on an emitted manifest/output is not automatically a bad test. | @@ -112,7 +112,7 @@ dispatch/orchestration as Moon/native commands assume it. Relocating its entire the same source-level contract while retaining distinct target outputs. - Postmaster now owns only per-target product assembly. Combining independently built target assets is a repository release operation named - `release-tools:postmaster-release-assets`; its workflow job remains fail-closed + `liboliphaunt-wasix-postmaster:finalize-release-assets`; its workflow job remains fail-closed unless the exact Linux ARM64, Linux x64, and macOS set is present. - Moon project discovery now uses one recursive `src` glob and one recursive `tools` glob instead of fourteen overlapping directory inventories. The @@ -175,7 +175,7 @@ There are three related models, with different responsibilities: 1. **Package/version dependencies:** native ecosystem manifests state what a published consumer requires. A new runtime release does not select SDK - releases automatically. Existing `release-graph.mjs:buildPlan` already stops + releases automatically. Existing `release-graph.mts:buildPlan` already stops at the first independently publishable boundary; preserve that behavior. 2. **Execution/data dependencies:** Moon task edges say which workspace outputs a command consumes. Project dependencies alone do not describe these files diff --git a/src/docs/internal/OLIPHAUNT_PATCH_STACK.md b/src/docs/internal/OLIPHAUNT_PATCH_STACK.md new file mode 100644 index 000000000..14607e5e5 --- /dev/null +++ b/src/docs/internal/OLIPHAUNT_PATCH_STACK.md @@ -0,0 +1,12 @@ +# Native PostgreSQL patch stack + +The ordered native recipe lives in +[`postgres/series`](../../runtimes/liboliphaunt/native/postgres/series), +and the shared source pin lives in +[`source.toml`](../../postgres/versions/18/source.toml). +Each patch header explains its change. Platform builders apply that series with +`git apply --whitespace=error-all` before compiling PostgreSQL. + +Run the native runtime build and its C ABI, SQL, lifecycle, and extension tests +for behavioral evidence. Source fragments, author headers, and a generated +review table do not prove those behaviors and no longer gate qualification. diff --git a/docs/internal/OLIPHAUNT_README.md b/src/docs/internal/OLIPHAUNT_README.md similarity index 93% rename from docs/internal/OLIPHAUNT_README.md rename to src/docs/internal/OLIPHAUNT_README.md index 0998bf933..5bf0251ab 100644 --- a/docs/internal/OLIPHAUNT_README.md +++ b/src/docs/internal/OLIPHAUNT_README.md @@ -1,7 +1,7 @@ # Oliphaunt Internal README > Archived product-copy draft; non-normative. The repository root `README.md`, -> `docs/maintainers/README.md`, and executable product metadata describe the +> `src/docs/maintainers/README.md`, and executable product metadata describe the > current product and release contract. This draft is retained only as implementation history. It predates the current @@ -40,7 +40,7 @@ keep Oliphaunt in Rust state behind narrow app-owned commands; a direct JavaScript/webview adapter is planned, not part of the first release. SDK features should have parity where the platform can support them honestly; platform support is summarized in the -[`Capability Matrix`](../../src/docs/content/reference/capabilities.mdx), +[`Capability Matrix`](../content/reference/capabilities.mdx), with the maintainer contract in [`SDK Parity`](../maintainers/sdk-parity-policy.md). @@ -55,14 +55,14 @@ with the maintainer contract in and `src/sdks/js/`: platform and runtime SDKs. - `tools/policy/sdk-manifest.toml`: SDK ownership registry used by parity checks. - `tools/`: repo automation, including `xtask` and validation scripts. -- `benchmarks/`: benchmark plans and future cross-engine harnesses. +- `src/benchmarks/`: benchmark plans and future cross-engine harnesses. - `src/docs/`: public Fumadocs/Next docs product, generated matrices, tested snippets, API-reference stubs, and LLM docs. - Public SDK docs live under `src/docs/content/sdk/`; product roots keep only package README/CHANGELOG files and source-adjacent API comments. -- `docs/`: architecture, release, development, maintainer, and internal source +- `src/docs/`: architecture, release, development, maintainer, and internal source material. -- `docs/internal/`: maintainer-only progress notes and generated patch-stack +- `src/docs/internal/`: maintainer-only progress notes and patch-stack audits. See [repo-structure.md](../maintainers/repo-structure.md) for the repository policy and the evidence behind @@ -86,7 +86,7 @@ release replacement: mode also exposes logical SQL backup through packaged `pg_dump`; - the gated native extension matrix creates or loads release-ready PostgreSQL 18 extensions by exact SQL name, then verifies restart and physical restore - through broker/direct-C-ABI and server paths; + through src/broker/direct-C-ABI and server paths; - Rust, Swift, Kotlin, React Native, and TypeScript SDK lanes track the same product concepts where platform constraints allow it, with platform status summarized in `src/docs/content/reference/capabilities.mdx`; @@ -139,7 +139,7 @@ tasks independently; CI lanes use `moon ci` through After building `liboliphaunt`, run: ```sh -tools/perf/matrix/run_native_oliphaunt_matrix.sh +src/benchmarks/perf/matrix/run_native_oliphaunt_matrix.sh ``` For fast local plumbing checks: @@ -159,7 +159,7 @@ Focused diagnostic runs can select one engine or suite without changing the release default: ```sh -tools/perf/matrix/run_native_oliphaunt_matrix.sh \ +src/benchmarks/perf/matrix/run_native_oliphaunt_matrix.sh \ --quick --engines broker --suites streaming ``` diff --git a/docs/internal/OLIPHAUNT_TRACK_REVIEW.md b/src/docs/internal/OLIPHAUNT_TRACK_REVIEW.md similarity index 98% rename from docs/internal/OLIPHAUNT_TRACK_REVIEW.md rename to src/docs/internal/OLIPHAUNT_TRACK_REVIEW.md index f61bd07af..3e4028ce4 100644 --- a/docs/internal/OLIPHAUNT_TRACK_REVIEW.md +++ b/src/docs/internal/OLIPHAUNT_TRACK_REVIEW.md @@ -7,11 +7,11 @@ Date: 2026-05-16 > and “not production-complete” below do not describe the present release > candidate and must not be used by maintainers or agents as release policy. > Determine current readiness from -> [`docs/maintainers/release.md`](../maintainers/release.md), -> [`docs/maintainers/release-setup.md`](../maintainers/release-setup.md), the +> [`src/docs/maintainers/release.md`](../maintainers/release.md), +> [`src/docs/maintainers/release-setup.md`](../maintainers/release-setup.md), the > generated target/catalog contracts, and the repository -> [`release-oliphaunt`](../../.codex/skills/release-oliphaunt/SKILL.md) and -> [`qualify-oliphaunt-change`](../../.codex/skills/qualify-oliphaunt-change/SKILL.md) +> [`release-oliphaunt`](../../../.codex/skills/release-oliphaunt/SKILL.md) and +> [`qualify-oliphaunt-change`](../../../.codex/skills/qualify-oliphaunt-change/SKILL.md) > skills. Verify any still-interesting observation against the current source > and exact-SHA evidence before acting on it. @@ -48,7 +48,7 @@ are: final platform artifacts and device distribution are not wired end to end; - extensions: extensions are opt-in in the Rust model, and the packaged PG18 extension matrix now passes install/load, restart, physical backup, and - physical restore checks across broker/direct-C-ABI and server paths; pgGraph + physical restore checks across src/broker/direct-C-ABI and server paths; pgGraph and ParadeDB external smokes now also cover core functional queries across direct, broker, and server; the C ABI static registry exists and is smoke tested, while generated platform registry sources/device packaging and signed @@ -144,7 +144,7 @@ This track pass addressed concrete gaps: sequential Bind/Execute/Sync traffic and a pipelined Bind/Execute batch inside one transaction. - The gated native extension matrix now creates or loads every currently - release-ready exact extension through broker/direct-C-ABI and server paths, reopens the + release-ready exact extension through src/broker/direct-C-ABI and server paths, reopens the root, takes a physical backup, restores it into a new root, and verifies the extension remains visible after restore. The manifest also distinguishes SQL-only extensions such as `pgtap` from extensions that require a native @@ -299,7 +299,7 @@ This track pass addressed concrete gaps: longer have to infer helper/server memory solely from `/usr/bin/time` on the parent benchmark process. - The xtask RSS/process-tree sampler has been extracted to - `tools/xtask/src/process_rss.rs` with focused unit coverage for descendant + `src/runtimes/liboliphaunt/wasix/tools/xtask/src/process_rss.rs` with focused unit coverage for descendant aggregation and cycle/double-count protection. This keeps benchmark resource accounting separate from command orchestration. - The Swift SDK now includes `OliphauntNativeDirectEngine`, backed by a small @@ -684,7 +684,7 @@ Required benchmark dimensions: The matrix script now measures the three native SDK modes separately: ```sh -tools/perf/matrix/run_native_oliphaunt_matrix.sh +src/benchmarks/perf/matrix/run_native_oliphaunt_matrix.sh ``` For fast local checks, run: @@ -701,7 +701,7 @@ the run directory and exact binary versions retained. The native matrix writes ```sh OLIPHAUNT_PERF_RUN_DIR="$PWD/target/perf/native-liboliphaunt-" \ -tools/perf/check-native-perf-report.sh +src/benchmarks/perf/check-native-perf-report.sh ``` ## Code Organization Review @@ -729,7 +729,7 @@ Files to split next: separated from tar mechanics. If the archive format grows beyond same-version physical tar, introduce a format dispatcher instead of adding branches to the tar module. -- `tools/xtask/src/main.rs`: extension cataloging, process RSS sampling, and +- `src/runtimes/liboliphaunt/wasix/tools/xtask/src/main.rs`: extension cataloging, process RSS sampling, and perf command orchestration now live in dedicated modules. The remaining split is asset/release orchestration; benchmark result/report models can move again if `perf.rs` keeps growing. diff --git a/docs/internal/PERFORMANCE.md b/src/docs/internal/PERFORMANCE.md similarity index 98% rename from docs/internal/PERFORMANCE.md rename to src/docs/internal/PERFORMANCE.md index 0be2e06be..fdf4fffe2 100644 --- a/docs/internal/PERFORMANCE.md +++ b/src/docs/internal/PERFORMANCE.md @@ -2,12 +2,12 @@ > **Historical implementation record — non-normative.** This page preserves > earlier performance practices, measurements, and API names. It is not current -> release evidence or API guidance. Use `docs/maintainers/performance-evidence.md` +> release evidence or API guidance. Use `src/docs/maintainers/performance-evidence.md` > and the retained benchmark reports for current qualification. This page is maintainer documentation for performance tuning, measurement harnesses, and release profiling. Public benchmark results now live in -[`src/docs/content/reference/performance.mdx`](../../src/docs/content/reference/performance.mdx). +[`src/docs/content/reference/performance.mdx`](../content/reference/performance.mdx). `oliphaunt-wasix` is optimized for test setup and local-app startup. The runtime avoids user-side compilation: supported targets load packaged Wasmer AOT diff --git a/docs/internal/PG18_WASIX_PERF_STATUS.md b/src/docs/internal/PG18_WASIX_PERF_STATUS.md similarity index 100% rename from docs/internal/PG18_WASIX_PERF_STATUS.md rename to src/docs/internal/PG18_WASIX_PERF_STATUS.md diff --git a/docs/internal/PG18_WASIX_POSTGRES.md b/src/docs/internal/PG18_WASIX_POSTGRES.md similarity index 92% rename from docs/internal/PG18_WASIX_POSTGRES.md rename to src/docs/internal/PG18_WASIX_POSTGRES.md index b8605ca0c..9d37e1301 100644 --- a/docs/internal/PG18_WASIX_POSTGRES.md +++ b/src/docs/internal/PG18_WASIX_POSTGRES.md @@ -29,7 +29,7 @@ performance constraint. ## Topology Decision The single-backend runtime and concurrent -[`liboliphaunt-wasix-postmaster`](../../src/runtimes/liboliphaunt/wasix-postmaster/README.md) +[`liboliphaunt-wasix-postmaster`](../../runtimes/liboliphaunt/wasix-postmaster/README.md) are peer release products. Neither replaces or silently falls back to the other. The single-backend product keeps one host lifecycle, direct FE/BE pumping, prebuilt PGDATA, and AOT reuse. The postmaster product owns sockets, @@ -51,13 +51,11 @@ The practical direction is therefore: - Defer broader planner/executor shortcuts, locale-sensitive LIKE shortcuts, and stack-allocation rewrites until they have focused regression coverage, because they can silently change SQL semantics or memory pressure. -- Preserve the concluded cross-topology patch review in - `src/runtimes/liboliphaunt/wasix/assets/build/postgres/experiment-patch-disposition.toml` - and require a fresh WASIX rationale before adopting any additional - postmaster-originated patch into the embedded runtime. +- Record the runtime rationale in each patch header when adopting a + postmaster-originated change into the embedded runtime. Current postmaster architecture and performance interpretation are maintained -in [`docs/maintainers/wasix-postmaster.md`](../maintainers/wasix-postmaster.md). +in [`src/docs/maintainers/wasix-postmaster.md`](../maintainers/wasix-postmaster.md). Historical carrier measurements are not current release evidence for either topology. @@ -133,7 +131,7 @@ simple-query execution, executor/storage, btree insertion, btree comparison, and heap update subphases. With a release-built host and the 37-patch O2 artifact, PG18 is faster than same-host PG17.5 and the documented PG17.5 release table on every speed-test head; see -`docs/internal/PG18_WASIX_PERF_STATUS.md`. +`src/docs/internal/PG18_WASIX_PERF_STATUS.md`. ## Upstream PG18 legacy lane Hints @@ -300,26 +298,19 @@ not by wholesale copying more upstream Oliphaunt code. The postmaster product's early patch stack was useful prior art, but its topology-specific patches are not the source of truth for this lane. The -reviewed historical disposition manifest is: - -```sh -src/runtimes/liboliphaunt/wasix/assets/build/postgres/experiment-patch-disposition.toml -``` - -The manifest records each reviewed patch by filename, whether it was applied, -adopted from current main, or rejected, and why that decision fits a -single-backend WASIX product. The five compatible optimizations—hash-load, +historical adoption decisions are recorded in Git history. Those decisions +reflect a single-backend WASIX product. The five compatible optimizations—hash-load, top-XID visibility, guarded btree int4 comparison, LIKE literal substring, and -first int4 leaf comparison—are owned by the main WASIX runtime. The postmaster -consumes those exact patches through -`postgres/main-optimizations.series` instead of maintaining copies. The +first int4 leaf comparison—are shared in `src/third-party/postgres/patches/wasix`. +Both products select those exact patches through their complete ordered +`postgres/series` recipes instead of maintaining copies. The single-user-only btree delete stack placement, bottom-up-delete runtime toggle, and full concurrent-postmaster runtime patches remain outside the default -single-backend lane. The postmaster keeps its narrow pg_dump LTO hygiene patch -locally because it belongs to that build topology. +single-backend lane. Both WASIX lanes also select the shared pg_dump LTO +hygiene and entropy-handling patches. -The source-spine guard keeps those concluded decisions explicit. New shared -optimizations must be adopted through the canonical single-backend patch stack; +New shared +optimizations must be explicitly selected by each compatible lane; postmaster lifecycle patches remain owned by the postmaster product. ## Current Slice @@ -334,29 +325,11 @@ It downloads or reuses the PostgreSQL 18.4 tarball, verifies the upstream checksum, extracts into `target/oliphaunt-wasix/wasix-build`, and applies the patch series in `src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/series`. -The source-spine guard also requires that file to match the duplicate -`[patches].series` list in `postgres/source.toml`, so build metadata -and the applied patch order cannot drift silently. It also rejects orphan -`.patch` files that are not listed in the series; source fingerprints and -applied patch contents must describe the same stack. The guard also checks -that the stack remains reviewable: sequentially numbered `oliphaunt-wasix` -patches, each with a matching subject/filename slug, an -Oliphaunt maintainer header, and a short rationale before the diff. When a -prepared PG18 source tree exists, xtask recomputes the source fingerprint from -the PostgreSQL tarball metadata, patch series file, and patch file hashes, then -compares both the source-tree marker and work-root marker against that value. -The same prepared-source verifier is used by PG18 source prep and build-output -discovery, so template/package/AOT commands do not accept a stale prepared -source tree. If source prep uses an overridden PG18 work root, xtask verifies -the marker in that actual work root rather than the default target directory. -The same guard scans the PG18 patch stack, PG18 build scripts, Rust host loader, -prepared source tree, and generated PG18 manifests/AOT metadata for legacy -Oliphaunt ABI tokens such as `__OLIPHAUNT__`, `OLIPHAUNT_*`, `PGL_*`, and `pgl_*`. PG17 -and upstream Oliphaunt remain valid references, but the PG18 release lane must use -only `oliphaunt_wasix_*` and `OLIPHAUNT_WASM_*` names in runtime/build -surfaces. - -The existing PG17.5 released build remains untouched. +That series is the only patch inventory. Source preparation and build-output +validation hash the same ordered patches and PostgreSQL source pin. A prepared +tree must carry matching source and work-root fingerprints before packaging or +AOT generation. The compiler and runtime tests verify behavior; patch authors, +source spellings, and generated review tables do not gate the build. ## Build Entry Points @@ -533,7 +506,7 @@ Promoted extension packaging is also fail-closed. PostgreSQL contrib and PGXS style extensions are lane-scoped through the selected build directory. The PG18 source-spine guard verifies that promoted PGXS source directories stay under shared `target/oliphaunt-sources/checkouts/*` pins instead of the released backend checkout, that -each source directory is represented in `src/sources/third-party/**`, and, when the +each source directory is represented in `src/sources/src/third-party/**`, and, when the checkout is present, that packaging-visible Makefile/control/SQL inputs exist. PG18 asset manifests derive extension `control-files` from the packaged extension archive contents, so contrib metadata cannot leak released diff --git a/src/docs/internal/README.md b/src/docs/internal/README.md new file mode 100644 index 000000000..b3a354c15 --- /dev/null +++ b/src/docs/internal/README.md @@ -0,0 +1,5 @@ +# Internal documents + +Status: archived implementation history and evidence. + +These files record earlier plans, completed work, investigations, and migration details. They are not current maintainer policy. Start with `src/docs/maintainers/README.md`, then inspect executable configuration and generated catalogs. A current maintainer document may link to a specific internal artifact as supporting evidence; that does not make the rest of the internal document normative. diff --git a/docs/internal/RELEASE_PIPELINE_READINESS_2026-09-03.md b/src/docs/internal/RELEASE_PIPELINE_READINESS_2026-09-03.md similarity index 99% rename from docs/internal/RELEASE_PIPELINE_READINESS_2026-09-03.md rename to src/docs/internal/RELEASE_PIPELINE_READINESS_2026-09-03.md index 02da03588..db9ca2c53 100644 --- a/docs/internal/RELEASE_PIPELINE_READINESS_2026-09-03.md +++ b/src/docs/internal/RELEASE_PIPELINE_READINESS_2026-09-03.md @@ -209,13 +209,13 @@ irreversible registry write. Passed on the final tree: -- full `tools/release/release-check.mjs`, including metadata and every +- full `tools/release/release-check.sh`, including metadata and every policy/release mutation unit file; - `tools/policy/check-workflows.sh`: actionlint, zizmor, workflow security, planner chaos tests, and fail-closed pinned toolchain bootstrap tests; - `release-metadata-check.mjs` after replacing the redundant workflow gates; - real PR #167 candidate normalization/synchronization and current - `verify-release-commit.mjs` for all 20 selected products; + `verify-release-commit.mts` for all 20 selected products; - focused pacer concurrency, deadline, malformed-journal, and test-isolation tests; - product task/edge invariants and 21 affected-selection chaos cases; diff --git a/docs/internal/REPOSITORY_ORGANIZATION_AUDIT_2026-09-03.md b/src/docs/internal/REPOSITORY_ORGANIZATION_AUDIT_2026-09-03.md similarity index 96% rename from docs/internal/REPOSITORY_ORGANIZATION_AUDIT_2026-09-03.md rename to src/docs/internal/REPOSITORY_ORGANIZATION_AUDIT_2026-09-03.md index 6a7842e21..af7a57071 100644 --- a/docs/internal/REPOSITORY_ORGANIZATION_AUDIT_2026-09-03.md +++ b/src/docs/internal/REPOSITORY_ORGANIZATION_AUDIT_2026-09-03.md @@ -55,7 +55,7 @@ ownership. | `tools/release` | Correct owner but too flat. Its 345 files coordinate multiple registries and products, so moving them under any product would be wrong. A short README now identifies entrypoints and the rule for future splits; mass renaming is deferred until a real independent task/import boundary exists. | | `.github` | Correct: workflow-only adapters/actions stay here; reusable release policy remains in `tools/release` and workflow security in `tools/policy`. Tests may live with the workflow module or in the policy/release suite that owns the contract. | | `examples` | Correct: paired native/WASIX examples intentionally remain standalone consumer projects. Their small repeated configs/styles preserve copyability and do not justify a shared package. | -| `docs/internal` | Correct: it is explicitly an archived, non-normative evidence area. Large completed checklists remain useful historical records and are not active policy. | +| `src/docs/internal` | Correct: it is explicitly an archived, non-normative evidence area. Large completed checklists remain useful historical records and are not active policy. | The Rust root is an idiomatic virtual workspace with one shared lockfile, as described by the [Cargo workspace documentation](https://doc.rust-lang.org/cargo/reference/workspaces.html). @@ -102,7 +102,7 @@ instead of imitating SwiftPM's `Tests` layout, consistent with Gradle's `Tests` tree. 2. Deleted the unused duplicate docs favicon under `static`; retained the standard Next.js `public/img/favicon.svg`. -3. Added `tools/native-extension-proof/**/*` to the existing release planner +3. Added `src/extensions/tests/native/**/*` to the existing release planner trigger and a chaos test. Editing the hosted proof executable now selects the native extension lifecycle that actually consumes it. 4. Renamed `native-tools-proof:check` and `native-packaging:test` to truthful @@ -110,7 +110,7 @@ instead of imitating SwiftPM's `Tests` layout, consistent with Gradle's compiles the crate, and the separate target directories previously repeated that work. 5. Replaced the stale fictional tree in - `docs/maintainers/repo-structure.md` with the current product hierarchy and + `src/docs/maintainers/repo-structure.md` with the current product hierarchy and documented why the root Swift manifest is valid. 6. Added `tools/release/README.md` as the minimal navigation/ownership index for the large cross-product release directory. @@ -168,7 +168,7 @@ instead of imitating SwiftPM's `Tests` layout, consistent with Gradle's - No mass rename of underscore-named release scripts was performed. Those paths are invoked by workflows and release tooling; naming consistency alone does not justify that failure surface. -- `tools/xtask` remains at the root because its surviving commands span WASIX +- `src/runtimes/liboliphaunt/wasix/tools/xtask` remains at the root because its surviving commands span WASIX source acquisition, runtime assets, extensions, AOT, and release staging. Earlier dead commands were removed; moving the remaining crate would only move complexity. diff --git a/docs/internal/TODO.md b/src/docs/internal/TODO.md similarity index 95% rename from docs/internal/TODO.md rename to src/docs/internal/TODO.md index ab2006f71..6a93f05d7 100644 --- a/docs/internal/TODO.md +++ b/src/docs/internal/TODO.md @@ -5,11 +5,11 @@ > “remaining work,” acceptance, device-evidence, and production-readiness > language reflects the track that created each entry; it is not an assertion > about the current release candidate. Maintainers and agents must use -> [`docs/maintainers/release.md`](../maintainers/release.md), -> [`docs/maintainers/release-setup.md`](../maintainers/release-setup.md), the +> [`src/docs/maintainers/release.md`](../maintainers/release.md), +> [`src/docs/maintainers/release-setup.md`](../maintainers/release-setup.md), the > generated target/catalog contracts, and the repository -> [`release-oliphaunt`](../../.codex/skills/release-oliphaunt/SKILL.md) and -> [`qualify-oliphaunt-change`](../../.codex/skills/qualify-oliphaunt-change/SKILL.md) +> [`release-oliphaunt`](../../../.codex/skills/release-oliphaunt/SKILL.md) and +> [`qualify-oliphaunt-change`](../../../.codex/skills/qualify-oliphaunt-change/SKILL.md) > skills for current policy and exact-SHA readiness. Re-verify an item against > the current tree before promoting it into normative maintainer documentation. @@ -74,7 +74,7 @@ Remaining work: Acceptance: -- `moon run liboliphaunt-native:host-smoke oliphaunt-rust:regression` proves C +- `moon run liboliphaunt-native:host-smoke oliphaunt-rust:test-integration` proves C smoke plus Rust SDK behavior against current artifacts. - Patch-stack review output is deterministic and checked into release evidence. - No patch grows product-specific branching that belongs above PostgreSQL. @@ -139,16 +139,16 @@ Acceptance: - Each affected SDK's `compile`, `unit`, `package`, and runtime smoke tasks pass against a current native runtime. -- `pnpm --dir src/sdks/react-native/examples/expo run smoke:android` passes on an Android +- `pnpm --dir src/sdks/react-native/src/examples/expo run smoke:android` passes on an Android emulator/device with current native Android artifacts. - `pnpm moon run oliphaunt-swift:smoke` passes on macOS with Xcode and stays warning-clean for the PostgreSQL embedded patch objects. - `pnpm moon run liboliphaunt-native:build-runtime-ios-xcframework` produces current iOS simulator/device `liboliphaunt.dylib` slices with the public C ABI symbols. -- `pnpm --dir src/sdks/react-native/examples/expo run smoke:ios` passes on an iOS +- `pnpm --dir src/sdks/react-native/src/examples/expo run smoke:ios` passes on an iOS simulator/device with current native iOS artifacts. -- Every row in `docs/maintainers/sdk-parity-policy.md` has SDK-specific tests or a documented +- Every row in `src/docs/maintainers/sdk-parity-policy.md` has SDK-specific tests or a documented product reason for non-parity. ### P0-04: Finish Extension Release Evidence @@ -173,7 +173,7 @@ Remaining work: Acceptance: -- `moon run extension-artifacts-native:build-target oliphaunt-rust:extension-regression` +- `moon run extension-artifacts-native:build-target oliphaunt-rust:test-extensions` passes with first-party extension artifacts. - `extension-packages:package` receives native extension artifacts for every published native runtime target and WASIX extension artifacts for every diff --git a/docs/internal/WASIX_NODE_BULK_PERF_REVIEW_20260814.md b/src/docs/internal/WASIX_NODE_BULK_PERF_REVIEW_20260814.md similarity index 91% rename from docs/internal/WASIX_NODE_BULK_PERF_REVIEW_20260814.md rename to src/docs/internal/WASIX_NODE_BULK_PERF_REVIEW_20260814.md index 788596705..5ff15ba8e 100644 --- a/docs/internal/WASIX_NODE_BULK_PERF_REVIEW_20260814.md +++ b/src/docs/internal/WASIX_NODE_BULK_PERF_REVIEW_20260814.md @@ -3,7 +3,7 @@ ## Scope - Re-ran WASIX asset release build with perf probe settings on core-only lane -- Ran Node benchmark plan `benchmarks/wasix/node-pglite-memory-v1.json` +- Ran Node benchmark plan `src/benchmarks/wasix/node-pglite-memory-v1.json` - Captured a paired candidate-vs-PGlite report in: - `target/perf/wasix-node-run-20260814/report.json` - `target/perf/wasix-node-run-20260814/report.md` @@ -12,7 +12,7 @@ ```bash OLIPHAUNT_WASM_SKIP_EXTENSIONS_FOR_PERF=1 cargo run -p xtask --features template-runner -- assets release-build --profile release --target-triple x86_64-unknown-linux-gnu --skip-aot --skip-package-size --fetch -node tools/perf/wasix-node/benchmark.mjs --run --config benchmarks/wasix/node-pglite-memory-v1.json --output target/perf/wasix-node-run-20260814 +node src/benchmarks/perf/wasix-node/benchmark.mts --run --config src/benchmarks/wasix/node-pglite-memory-v1.json --output target/perf/wasix-node-run-20260814 ``` ## Result summary diff --git a/src/docs/internal/WASIX_PATCH_STACK.md b/src/docs/internal/WASIX_PATCH_STACK.md new file mode 100644 index 000000000..22912d34e --- /dev/null +++ b/src/docs/internal/WASIX_PATCH_STACK.md @@ -0,0 +1,12 @@ +# WASIX PostgreSQL patch stack + +The ordered patches live in +[`patches/series`](../../runtimes/liboliphaunt/wasix/assets/build/postgres/patches/series); +the PostgreSQL source pin lives in +[`versions/18/source.toml`](../../postgres/versions/18/source.toml). +Each patch header explains its change. The WASIX builder applies that series +before compiling the runtime. + +Use the built runtime's protocol and extension tests for behavioral evidence. +Source fragments and generated review tables no longer gate qualification. +The concurrent Postmaster runtime has its own source, patches, and recovery tests. diff --git a/src/docs/maintainers/README.md b/src/docs/maintainers/README.md new file mode 100644 index 000000000..926f84e91 --- /dev/null +++ b/src/docs/maintainers/README.md @@ -0,0 +1,40 @@ +# Maintainer documentation + +Status: index. Last verified: 2026-08-15. Owner: repository maintainers. + +Executable configuration is authoritative. Documentation explains intent and operation; it must not invent workflow names, package identities, targets, or release state. When prose conflicts with the sources below, fix the prose in the same change. + +| Topic | Maintainer entry point | Executable source | +| --- | --- | --- | +| Release products, versions, tags, and recovery | `release.md` | `release-please-config.json`, `.release-please-manifest.json`, active-product `release.toml`, `tools/release/publication-catalog.mts`, `.github/scripts/manage-release-drafts.mts` | +| Registry and GitHub environment setup | `release-setup.md` | `.github/workflows/release.yml`, `tools/release/check_publish_environment.mts` | +| CI gates and test selection | `testing.md`, `tooling.md` | `.github/workflows/ci.yml`, `tools/ci/ci_plan.mts`, Moon project files | +| Binary artifacts and WASIX provenance | `assets.md`, `compiler-caching.md` | runtime target metadata, exact producer SHA, runtime/AOT manifests and checksums, `src/runtimes/liboliphaunt-wasix/tools/xtask` | +| WASIX host APIs and storage | `wasix-usage.md` | WASIX binding source, host pins/patches, and product Moon tasks | +| WASIX postmaster runtime and carrier | `wasix-postmaster.md` | `src/runtimes/liboliphaunt-wasix-postmaster`, its Moon project, sealed-carrier policy, and release metadata | +| Extension support and packaging | `extension-packaging-policy.md` | extension catalog, global target profiles, native-component contract, release catalog | +| SDK contracts | `sdk-products-policy.md`, `sdk-parity-policy.md`, `sdk-api-surface.md` | SDK manifests, package manifests, generated extension metadata, clean-consumer tests | +| Product, task, qualification, and release boundaries | `../architecture/final-product-source-architecture.md` | Moon graph, release metadata, and workflows | +| Repository layout | `repo-structure.md` | Moon projects and ecosystem manifests | + +The repository-local skills under `.codex/skills/` are the procedural entry +points for agents: + +- `release-oliphaunt` owns release preparation, bootstrap, publish, recovery, + and registry setup; +- `qualify-oliphaunt-change` owns affected local feedback and exact-SHA GitHub + qualification; +- `add-oliphaunt-extension` owns extension catalog, version, target, + carrier, and package changes. + +Those skills route to executable checks and the focused references above; they +do not replace the executable sources of truth. + +`consumer-dx-release-blueprint.md` is archived design history. Files under `src/docs/internal/` are implementation history, investigations, or evidence snapshots unless a current maintainer document links to a specific section. They are not policy and must not be used to override the executable sources above. + +When changing a workflow or contract: + +1. update the executable source and behavior tests; +2. update the relevant maintainer entry point and its verified date; +3. regenerate derived tables instead of hand-editing them; +4. avoid policy assertions that depend on YAML step order, display text, or helper filenames unless the string itself is an external API. diff --git a/docs/maintainers/assets.md b/src/docs/maintainers/assets.md similarity index 85% rename from docs/maintainers/assets.md rename to src/docs/maintainers/assets.md index 5e4d17fe6..500ef7afc 100644 --- a/docs/maintainers/assets.md +++ b/src/docs/maintainers/assets.md @@ -104,18 +104,18 @@ hardlinks, device nodes, and unsupported entry types. ## Provenance Asset provenance is recorded in runtime source pins under -`src/sources/third-party/**`, extension-owned source pins under +`src/third-party/**`, extension-owned source pins under `src/extensions/external/**/source.toml` and `src/extensions/external/**/dependencies/**/source.toml`, -`src/sources/toolchains/**`, the exact producer commit, and the generated +`tools/dev/*.toml`, the exact producer commit, and the generated runtime/AOT manifests produced by the `CI` workflow's WASIX runtime lane. Generated manifests record source pins, runtime hashes, `initdb` hashes, cluster-seed hashes, extension archive hashes, target information, and Wasmer engine identity. PostgreSQL ICU support uses the same provenance path: ICU code is source-pinned in -`src/sources/third-party/shared/icu.toml`, while the canonical official +`src/third-party/icu/source.toml`, while the canonical official little-endian data archive is independently pinned in -`src/sources/third-party/shared/icu-data.toml`. Native and WASIX builders compile +`src/database-resources/icu/source.toml`. Native and WASIX builders compile target-specific ICU code but expand that one data archive into the shared files-data identity. ICU data is packaged as a separate `oliphaunt-icu` payload; standard native and WASIX runtime artifacts do not carry `share/icu`. @@ -131,7 +131,7 @@ Maintainer source trees are fetched on demand into ignored `target/oliphaunt-sources/checkouts/**` directories: ```sh -cargo run -p xtask -- assets fetch +bash src/third-party/tools/fetch-sources.sh production-all --force ``` A Git source may declare one manually reviewed `mirror_url` when upstream @@ -146,20 +146,17 @@ validation, and a live exact-commit fetch from every newly declared endpoint. WASIX build and work trees are generated under `target/oliphaunt-wasix/wasix-build/**`. The source tree -`src/runtimes/liboliphaunt/wasix/assets/build/**` is reserved for scripts, patches, +`src/runtimes/liboliphaunt-wasix/assets/build/**` is reserved for scripts, patches, Docker inputs, and shims that define the build at the exact producer commit. -Normal development and source-free validation do not clone upstream repositories -or run Docker. The source-free gate is: +Local packaging tests do not clone upstream repositories or run Docker: ```sh -cargo run -p xtask -- assets verify-committed +moon run liboliphaunt-wasix:packaging-unit liboliphaunt-wasix:build-orchestration-test ``` -It verifies source pins, source and toolchain inputs, extension -metadata/constants when generated manifests are installed, AOT crate -templates, and the absence of committed cluster-seed, portable WASIX, or -native AOT blobs. +The runtime build verifies pinned source checkouts before compilation. Release +packaging validates the built manifests, artifact bytes, and runtime inventory. Release assets are built with the `release` profile by default: WASIX C code uses `-O2 -g0` with ThinLTO through the final guest link, and Binaryen runs the @@ -167,15 +164,15 @@ wasixcc default optimization plus `--converge`, `--strip-debug`, and `--strip-producers`. The `release-o3` profile remains available for explicit O3 comparison builds. -Generated runtime hashes in package metadata are refreshed in the release -staging workspace. CI-produced assets are selected by exact workflow run or +Release carrier hashes are derived from the packaged bytes. CI-produced +assets are selected by exact workflow run or exact commit, and their manifests and checksums bind the installed runtime and AOT bytes. Release versions, changelogs, package descriptions, and smoke expectations belong to the publication envelope/lock and do not alter those runtime bytes. The WASIX builder declares its immutable bootstrap inputs in -`src/sources/toolchains/wasix.toml`: the Ubuntu base image digest, Dockerfile +`src/runtimes/liboliphaunt-wasix/assets/build/docker/Dockerfile`: the Ubuntu base image digest, Dockerfile frontend digest, Ubuntu snapshot timestamp, and the committed TLS root used to reach `snapshot.ubuntu.com`. The APT helper writes one isolated deb822 source containing only `noble`, `noble-updates`, and `noble-security` with the `main` @@ -186,19 +183,16 @@ complete update/install transaction with a fixed bound; it never falls back to a live mirror or disables TLS verification. `ca-certificates` is installed in the same pinned transaction as the builder packages. -The committed `isrg-root-x1.pem` is independently SHA-256 pinned, and -`builder.snapshot_tls_root_not_after` records its certificate-derived expiry -boundary. Rotate it before the manifest-declared boundary, or sooner if the +The committed `isrg-root-x1.pem` is SHA-256 pinned in the Dockerfile and expires +on 2035-06-04. Rotate it before its certificate expires, or sooner if the snapshot service changes its certificate chain: 1. Obtain the replacement trust root from its authoritative CA distribution, verify its subject, issuer, fingerprint, and `notAfter` value independently, and replace only the committed PEM. -2. Update `snapshot_tls_root_sha256` and `snapshot_tls_root_not_after` in the - WASIX toolchain manifest, then update the Docker SHA-256 build argument to - match. If the Dockerfile frontend changes, pin its content digest in the - same change. -3. Run the pinned APT helper fault tests, source-spine verification, and a clean +2. Update the Dockerfile trust-root SHA-256 build argument and expiry comment. + If the Dockerfile frontend changes, pin its content digest in the same change. +3. Run the pinned APT helper fault tests and a clean Docker builder build. The build must reach the snapshot with normal peer verification and print the pinned wasixcc, Clang, and Binaryen versions. 4. Require the complete portable/AOT build and exact-SHA hosted qualification. @@ -211,7 +205,7 @@ authenticated archival mirror. The `CI` workflow's WASIX runtime/AOT build lane mirrors the release topology on trusted producer runs: one Linux/Docker job builds portable WASIX modules from -`src/runtimes/liboliphaunt/wasix/assets/build` into `target/oliphaunt-wasix/assets`, +`src/runtimes/liboliphaunt-wasix/assets/build` into `target/oliphaunt-wasix/assets`, then native matrix jobs generate and package target-specific Wasmer AOT crates into `target/oliphaunt-wasix/aot/`. Artifacts are uploaded with checksums and manifests. @@ -246,13 +240,13 @@ portable and AOT bundles, stages them into a clean release workspace, validates package contents, and only then publishes. Published releases also attach public `.tar.zst` mirrors of the validated -portable WASIX and target AOT bundles. `xtask assets download --release ` +portable WASIX and target AOT bundles. the product-local `download-assets.sh --release ` command installs those release assets directly and does not require the GitHub CLI. For workflow artifacts, select one exact run or full commit SHA; all three modes validate checksums and packaged manifests before installation: ```sh -cargo run -p xtask -- assets download --run-id --target-triple -cargo run -p xtask -- assets download --sha --target-triple -cargo run -p xtask -- assets download --release --target-triple +bash src/runtimes/liboliphaunt-wasix/tools/download-assets.sh --run-id --target-triple +bash src/runtimes/liboliphaunt-wasix/tools/download-assets.sh --sha --target-triple +bash src/runtimes/liboliphaunt-wasix/tools/download-assets.sh --release --target-triple ``` diff --git a/docs/maintainers/compiler-caching.md b/src/docs/maintainers/compiler-caching.md similarity index 94% rename from docs/maintainers/compiler-caching.md rename to src/docs/maintainers/compiler-caching.md index c849aadbb..ae9af4063 100644 --- a/docs/maintainers/compiler-caching.md +++ b/src/docs/maintainers/compiler-caching.md @@ -5,7 +5,7 @@ Status: normative cache policy. Last verified: 2026-07-21. Owner: repository mai Oliphaunt uses three separate cache layers. Keep them separate: - Moon caches deterministic task outputs. -- Cargo, Gradle, pnpm, SwiftPM, and Xcode cache their own dependency/build +- Cargo, Gradle, Bun, SwiftPM, and Xcode cache their own dependency/build state through their native tools. - Compiler caches reuse object-code compilation when a native lane has to run. @@ -24,7 +24,7 @@ Use Cargo cache actions for Rust dependencies and `target` reuse only in the bounded primary WASIX producer. Do not enable `sccache` by default yet. Gradle consumers may restore the one Kotlin package-producer cache; only that -producer may write it. Use normal local SwiftPM, pnpm, and Moon caches, but do +producer may write it. Use normal local SwiftPM, Bun, and Moon caches, but do not add repository-wide GitHub cache writers for them without measured evidence and an explicit storage budget. Do not put simulator state, device state, registry responses, PostgreSQL source checkouts, or release artifacts into @@ -41,15 +41,15 @@ The liboliphaunt build scripts automatically use `ccache` when it is on `PATH`. ```sh brew install ccache -src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh +src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh ccache --show-stats ``` -On Linux: +On Linux, provision GCC/G++ 12 and optional `ccache` before running the build. +The build itself does not install system packages or elevate privileges: ```sh -sudo apt-get install ccache gcc-12 g++-12 -src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh +src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh ccache --show-stats ``` @@ -67,8 +67,8 @@ contract because they are clang-based cross-builds launched from macOS. Override or disable it with: ```sh -OLIPHAUNT_CCACHE=/opt/homebrew/bin/ccache src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh -OLIPHAUNT_CCACHE=off src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh +OLIPHAUNT_CCACHE=/opt/homebrew/bin/ccache src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh +OLIPHAUNT_CCACHE=off src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh ``` The build scripts use prefix mode (`CC="ccache cc"` style). Keep cache @@ -86,7 +86,7 @@ ccache --set-config=compression=true Use a per-workstation cache directory only when you need to isolate experiments: ```sh -CCACHE_DIR="$HOME/.cache/oliphaunt-ccache" src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh +CCACHE_DIR="$HOME/.cache/oliphaunt-ccache" src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh ``` ## CI Cache Writer Budget diff --git a/docs/maintainers/consumer-dx-release-blueprint.md b/src/docs/maintainers/consumer-dx-release-blueprint.md similarity index 98% rename from docs/maintainers/consumer-dx-release-blueprint.md rename to src/docs/maintainers/consumer-dx-release-blueprint.md index e2c1cbf7a..0d235e375 100644 --- a/docs/maintainers/consumer-dx-release-blueprint.md +++ b/src/docs/maintainers/consumer-dx-release-blueprint.md @@ -2,8 +2,8 @@ Status: archived design plan; non-normative. Do not use package names, carrier counts, workflow steps, or release policy from this file. They are historical -snapshots and may intentionally be stale. See `docs/maintainers/README.md`, -`docs/maintainers/release.md`, and `docs/maintainers/extension-packaging-policy.md` +snapshots and may intentionally be stale. See `src/docs/maintainers/README.md`, +`src/docs/maintainers/release.md`, and `src/docs/maintainers/extension-packaging-policy.md` for the current operational contract. ## Decisions @@ -75,7 +75,7 @@ consumer configuration. Remove CLI-first consumer install guidance from: - `src/sdks/rust/README.md` -- `docs/maintainers/sdk-products-policy.md` +- `src/docs/maintainers/sdk-products-policy.md` - release metadata checks that treat `--resolve-release-assets` as the consumer path @@ -117,7 +117,7 @@ real local package artifacts installed by npm packages. Extend the generated SwiftPM release manifest in: -- `tools/release/render_swiftpm_release_package.mjs` +- `src/sdks/swift/tools/render_swiftpm_release_package.mts` Generate extension products and checksum-pinned binary targets. Do not use a plugin to add dependencies. diff --git a/src/docs/maintainers/development.md b/src/docs/maintainers/development.md new file mode 100644 index 000000000..828bd52ed --- /dev/null +++ b/src/docs/maintainers/development.md @@ -0,0 +1,384 @@ +# Maintainer Development Guide + +Status: normative local-development guide. Last verified: 2026-09-03. Owner: repository maintainers. + +This page is maintainer documentation for repository validation, generated +artifacts, and local release metadata checks. It is not end-user product +documentation. + +Bootstrap the pinned local toolchain once: + +```sh +tools/dev/bootstrap-tools.sh +``` + +This installs Prek, cargo-nextest, Actionlint, and Zizmor. Use +`tools/dev/bootstrap-tools.sh --workflows` when only the workflow validators are +needed. Optional tools such as cargo-deny, cargo-hack, and cargo-semver-checks can +be installed with Cargo when their checks are needed. + +For each change, follow `.codex/skills/qualify-oliphaunt-change/SKILL.md`: +inspect Moon affectedness, run focused checks first, and expand only when the +changed contract requires it. Inspect affectedness, then run explicit owner +checks. For example, for the native Rust SDK: + +```sh +moon query affected --upstream none --downstream deep +moon run oliphaunt-rust:format-check oliphaunt-rust:lint oliphaunt-rust:test +``` + +Run `moon run ci-workflows:check` for workflow changes and +`cargo deny check` for dependency or +supply-chain policy changes; neither is an unconditional pre-PR ceremony. + +Tool versions for Moon, Node, Bun, and Deno are pinned in `.prototools`. +Update tool versions there alongside their verified archive URLs and digests in +the corresponding `tools/dev/{moon-cli,node-runtime,bun,deno}.toml` manifest. +Renovate updates ecosystem dependencies; it does not propose partial changes to +these tool pins, which the verified installers would reject. +Bun is required for the TypeScript SDK checks because `@oliphaunt/ts` supports +Bun through the npm artifact; local checks use `tools/dev/bun.sh` when the shell +does not already provide the pinned Bun. Deno is optional for normal local checks +and uses `tools/dev/deno.sh` on demand for Deno npm-package validation. + +Windows native builds obtain WinFlexBison from the exact upstream archive pinned +in `tools/dev/winflexbison.toml`. The shared native setup verifies +the archive size and digest, safe ZIP layout, complete extracted-tree digest, +and both executable digests before adding the atomic cache payload to `PATH`. +Do not replace this path with a live Chocolatey lookup; Chocolatey is retained +only for Strawberry Perl when the hosted image does not already provide it, and +that fallback must prove the expected executable after every install attempt. + +Tool choices and rejected alternatives are recorded in +[tooling.md](tooling.md). Update that decision record before adding a new +repo-wide tool or hand-rolled release helper. + +Moon is the product graph and affected-task entrypoint. A fresh checkout should +install the pinned proto/Moon toolchain from `.prototools`, then call Moon +directly: + +```sh +moon query projects +moon query affected --upstream none --downstream deep +moon run oliphaunt-rust:coverage --affected --include-relations --downstream deep +``` + +Use `moon query affected` to inspect affectedness and `moon run ` for +explicit local targets. GitHub CI executes the exact planned target list with +Moon so jobs do not expand into unrelated downstream work. Normal commands use +Moon's own concurrency instead of a forced single-worker debug mode. + +The validation entrypoint is split by maintainer workflow: + +- `moon run liboliphaunt-native:host-smoke`: release-shaped, no-build host + C ABI/runtime smoke. It depends on the native release-runtime producer and + refuses any implicit rebuild inside the smoke; +- `cargo clippy -p --all-targets --locked -- -D warnings`: focused Rust lint; +- `moon run ci-workflows:check`: workflow syntax and security checks plus the + behavior tests for helpers invoked by Actions; +- `moon run liboliphaunt-wasix:smoke`: hard-requires portable assets plus host AOT, + installs them into ignored paths, and runs the real runtime tests; +- `moon run oliphaunt-wasix-ts:test-consumer`: installed Node/Bun/Deno/Electron + packages against the actual runtime, with producer prerequisites; +- `moon run oliphaunt-wasix-ts:test-browser`: Chrome package, storage and + extension behavior against the WASIX browser host; +- `moon run oliphaunt-wasix-ts:test-browser`: local browser proof, including its + declared runtime and seed prerequisites. It serves + COOP/COEP headers and requires Chrome/Chromium to exercise `pgtap`, recover two + PostgreSQL error paths, return `42`, and exit cleanly. Add `--pg-uuidv7` for the + private native-module canary; +- `moon run integration-examples:test`: mocked Tauri launcher and mobile proof-receipt tests; +- `moon run liboliphaunt-native:lint liboliphaunt-native:test`: cached native + Shell syntax and native unit tests without building a runtime; +- `moon run oliphaunt-rust:test-integration`: native direct, broker, and server + behavior against the current host runtime. Extension behavior remains the + separate `oliphaunt-rust:test-extensions` lane; +- `moon run perf-tools:native-measure`: optional native RTT measurement, using + the same benchmark runner available locally; +- `bun run --cwd src/benchmarks/perf/wasix-node bench:streaming`: quick local WASIX + TypeScript transport benchmark. It reuses staged packages and portable assets, + compares the root direct and explicit `/worker` contracts, exercises bounded COPY, + backpressure, event-loop delay, process RSS, the local server, `pg_dump`, and + `psql`, and prints a readable report (`-- --json` prints the complete JSON). + Process RSS deltas are descriptive because the quick run reuses one process. + If inputs are absent, first run + `moon run oliphaunt-wasix-tools-ts:package liboliphaunt-wasix:runtime-portable`; +- `moon run oliphaunt-rust:build`: Cargo compilation of `oliphaunt` and + `oliphaunt-build`. Artifact-relay build-script behavior is owned by `test`; + package and native runtime evidence remain separate `package` and `test-integration` + targets; +- `moon run oliphaunt-rust:test`: the hosted-equivalent Rust source-test lane. + It runs documentation tests, `oliphaunt-build` tests, and all `oliphaunt` + source tests. A focused command such as `cargo test -p oliphaunt --lib` + remains useful while iterating. Runtime-dependent tests have their own owner + tasks and artifact prerequisites; +- `moon run oliphaunt-rust:package`: creates the final `oliphaunt` and + `oliphaunt-build` crates and inspects their contents. The separate + `test-consumer` task compiles the extracted packages with their real packaged + dependencies. WASIX uses the same `package` / `test-consumer` distinction. + Source tests and runtime integration remain separate; +- Native package producers copy the canonical C header. Their consumers compile + it as part of normal builds; the shared seed and protocol fixtures exercise + behavior through the SDKs; +- `moon run oliphaunt-swift:build`: SwiftPM compilation of the SDK package; +- `moon run oliphaunt-swift:test-native`: Swift SDK tests against the current native + host runtime. Installed iOS app tests are a separate lane; +- `moon run oliphaunt-swift:package`: validates the Swift source package + shape without building platform release artifacts; +- `moon run liboliphaunt-native:build-runtime-ios-xcframework`: explicitly builds and + freshness-checks iOS simulator and device `liboliphaunt.dylib` slices from + the same PostgreSQL 18 patch stack, then packages them as + `liboliphaunt.xcframework`; +- `moon run oliphaunt-kotlin:format-check oliphaunt-kotlin:lint oliphaunt-kotlin:build`: Kotlin formatting, lint, and common/JVM and + Android compilation. Publication-shape checks run during `package`; isolated + tests remain in `oliphaunt-kotlin:test`; +- `moon run integration-examples:react-native-android-e2e`: Android React Native + installed-app harness over the Expo development-client sample; +- `moon run integration-examples:react-native-ios-e2e`: iOS React Native + installed-app harness over the Expo development-client sample; +- `moon run oliphaunt-react-native:build`: React Native TypeScript and packaging-helper compilation. + Run `oliphaunt-react-native:typecheck` and `oliphaunt-react-native:lint-codegen` + for source diagnostics. Package-shape work belongs to `oliphaunt-react-native:package`; +- `bun run --cwd src/examples/react-native-expo smoke:android`: real Android Expo + development-client smoke for the installed React Native package. It reuses + current native artifacts, generates the ignored Expo `android/` project only + when missing, packages `liboliphaunt.so` plus runtime/cluster-seed resources, starts + Metro when needed, installs the app, and waits for + `OLIPHAUNT_EXPO_SMOKE_PASS`; +- `bun run --cwd src/examples/react-native-expo smoke:ios`: real iOS Expo + development-client build/smoke harness for the installed React Native package. + For simulator builds it produces or reuses the current iOS simulator + `liboliphaunt.dylib` automatically when no explicit artifact override is set, + packages the same runtime/cluster-seed resources, patches only the ignored + generated `ios/` Podfile for local Swift pods, rejects macOS dylibs, and can + run in `OLIPHAUNT_EXPO_IOS_BUILD_ONLY=1` mode when CoreSimulator is + unavailable; +- `moon run :package`: stage and verify the selected product package; +- `cargo hack check -p --feature-powerset --no-dev-deps`: cargo-hack + feature combination checks; +- `cargo semver-checks check-release -p `: cargo-semver-checks public + API compatibility against the published version (use an explicit + `--baseline-rev ` before first publication); +- `cargo deny check`: cargo-deny dependency + policy checks; +- `moon run :test-integration`: the selected product's real runtime + behavior, when that task exists. Use `test-consumer` for installed artifacts + and `test-browser` for browser execution. Inspect the owner's tasks rather + than running every platform's packaging, coverage, or device tests globally; +- `moon run release-tools:check`: the canonical full local release-policy gate. + The direct equivalent is + `bash tools/release/release-check.sh`. This release-owned + metadata and mutation gate does not replace affected product source checks, `test`, + or `package` tasks; +- `bash tools/release/release-metadata-check.sh`: internal + protected-workflow replay after a generated release commit has passed its + structured verifier or after the exact hosted `Qualified` record has been + reverified against a clean checkout. It is not a replacement for the full + local gate. Candidate artifact dry-runs run only through the protected GitHub + `Release` workflow after exact-SHA qualification. + +Moon caches deterministic task results when their declared source inputs and +task dependencies have not changed. Local `:smoke` targets use `cache: local`, +so repeated `moon run :smoke` runs can return a cached result for the same source +graph. Use `moon run :smoke --cache off` when you need a live +device, simulator, or runtime probe regardless of the cache. Product tasks declare their own inputs and outputs; coverage remains an optional +product-local command. + +Kotlin and React Native Android SDK validation uses Gradle's configuration +cache by default so repeated local runs do not reconfigure the same Android/KMP +graphs. Set `OLIPHAUNT_GRADLE_CONFIGURATION_CACHE=0` only when diagnosing +Gradle configuration-cache behavior itself. + +The hook split is intentionally small: + +- pre-commit: file hygiene and formatting +- release readiness: the affected product source checks, unit, and package tasks +- CI/release: path-aware combinations of the same validation modes, workflow + linting, feature powerset, public API compatibility, crate packaging, + native AOT runtime tests, frozen Cargo publication dry-runs, and supply-chain + policy + +Install local hooks and pinned CLI tools when needed. Maintainer bootstrap +release assets are an explicit source contract in +`tools/dev/maintainer-tools.toml`: every supported Linux and macOS +host has an exact URL, archive SHA-256, extracted-binary SHA-256, archive +layout, and size bound. The installer accepts only bounded HTTPS downloads, +checks the complete archive before extraction, rejects unexpected or non-file +members, and promotes a staged binary and its identity marker atomically. A +matching version string alone is not a cache hit. + +`cargo-binstall` may fall back only after a transport failure or an unsupported +binary host. That fallback is an isolated, exact-version `cargo install +--locked` build and is promoted through the same rollback-safe path; it never +reuses a partial download. `actionlint` has no source fallback because the +repository does not pin a Go toolchain. Update the manifest and the fault tests +together when either maintainer tool is upgraded. + +```sh +tools/dev/bootstrap-tools.sh +bash tools/dev/install-hooks.sh +``` + +`src/sdks/rust-wasix/tests/runtime_smoke.rs` starts the real WASIX backend and +is intentionally slower than the protocol unit tests. + +## Maintenance Utilities + +The repository includes maintenance commands: + +- `oliphaunt-wasix-dump` is the logical dump CLI entry point. Its typed + `--database`, `--username`, and repeatable `--extension` options configure + the embedded server; arguments after `--` shape `pg_dump` output. +- `oliphaunt-pgwire-server` exposes a local PostgreSQL socket backed by the embedded + runtime. +- `database-resources` produces selectable standard/ICU seed profiles from the + runtime compiler output. WASIX seeds use the portable physical format; native + seeds have explicit desktop or mobile physical targets. Runtime packages do + not own these resource archives. + +Asset and source checks (source transport also requires GNU `timeout`; install +`coreutils` on macOS): + +```sh +bash src/third-party/tools/fetch-sources.sh production-all --force +bash src/third-party/tools/fetch-sources.sh wasix-runtime --verify-only +cargo run -p xtask -- assets check --strict-generated +moon run database-resources:package-wasix +bash src/runtimes/liboliphaunt-wasix/assets/build/prepare_postgres_source.sh +moon run oliphaunt-rust:package +``` + +## Local Runtime Development + +Local development has three supported modes. + +Fast contributor mode does not require Docker, upstream source checkouts, or +generated native AOT payloads. Use it for ordinary Rust, docs, tests, examples, +and workflow edits: + +```sh +moon query affected --upstream none --downstream deep +moon run oliphaunt-rust:format-check oliphaunt-rust:lint oliphaunt-rust:test +``` + +For native liboliphaunt work, run only the product boundary you changed: + +```sh +moon run liboliphaunt-native:host-smoke +moon run oliphaunt-rust:test-integration +moon run extension-artifacts-native:build-target oliphaunt-rust:test-extensions +``` + +`liboliphaunt-native:host-smoke` proves the C ABI. The Rust regression uses the basic native +runtime and runs SQL/protocol regression across direct, broker, and server mode. +`moon run oliphaunt-rust:test-extensions` is the separate +extension-artifact lane; it depends on `extension-artifacts-native:build-target` and is +intentionally not part of normal PR CI. The host artifact builder uses +the build script's no-build freshness probe before running the matrix, which avoids both +unnecessary rebuilds and the failure mode where a core-only runtime is +accidentally treated as extension ready. `sdks` validates SDK ownership/parity, +then runs the Rust, Swift, Kotlin, and React Native package checks. See +[`src/docs/maintainers/sdk-parity-policy.md`](./sdk-parity-policy.md) for the SDK ownership contract. `full` enables +native extension artifacts and the extension matrix in addition to the SDK +checks. Use +`OLIPHAUNT_TRACK_BUILD=never` when you want to prove the harness is not +rebuilding anything. + +Host-platform artifact mode is for runtime work on the current machine. It +builds or packages only the current host target, leaves all generated payloads +in ignored paths, and then runs the real runtime tests: + +```sh +host="$(rustc -vV | awk '/^host:/{print $2}')" +bash src/third-party/tools/fetch-sources.sh production-all --force +bash src/runtimes/liboliphaunt-wasix/tools/build-runtime-portable.sh +bash src/runtimes/liboliphaunt-wasix/tools/build-aot-target.sh +moon run liboliphaunt-wasix:smoke +``` + +Local AOT generation requires the Wasmer LLVM 22.1.x build for the +maintainer-only serializer. That build includes the LLVM target set Wasmer's +LLVM backend expects, including LoongArch and WebAssembly. Set +`LLVM_SYS_221_PREFIX` to an extracted +`wasmerio/llvm-custom-builds` 22.x archive, or use downloaded-artifact mode to +avoid local LLVM setup. + +When the portable WASIX assets are already current and only the host AOT crate +needs to be refreshed, skip the source/Docker build and generate host AOT from +the existing generated portable assets: + +```sh +host="$(rustc -vV | awk '/^host:/{print $2}')" +bash src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh --target-triple "$host" +cargo run -p xtask -- assets package-aot --target-triple "$host" +moon run liboliphaunt-wasix:smoke +``` + +Downloaded-artifact mode is the intended way to test a CI-produced runtime +locally without rebuilding Postgres/WASIX. Select either the exact successful +`CI` workflow run or the full 40-character commit SHA and install the host +target payloads into the same ignored generated locations used by the local +build path: + +```sh +host="$(rustc -vV | awk '/^host:/{print $2}')" +bash src/runtimes/liboliphaunt-wasix/tools/download-assets.sh --run-id --target-triple "$host" +# Or select the successful CI run for one exact commit: +bash src/runtimes/liboliphaunt-wasix/tools/download-assets.sh --sha --target-triple "$host" +moon run liboliphaunt-wasix:smoke +``` + +Workflow-run downloads require the authenticated GitHub CLI. The downloader +accepts only the requested run or exact SHA and validates the packaged runtime +and AOT manifests and checksums before installation. + +Released artifact bundles can be installed without the GitHub CLI because they +are public GitHub release assets: + +```sh +host="$(rustc -vV | awk '/^host:/{print $2}')" +bash src/runtimes/liboliphaunt-wasix/tools/download-assets.sh --release --target-triple "$host" +moon run liboliphaunt-wasix:smoke +``` + +Release downloads validate the published checksum manifest, archive checksums, +and packaged runtime/AOT manifests before installation. + +Release validation can download every supported target from the exact `CI` +workflow SHA: + +```sh +bash src/runtimes/liboliphaunt-wasix/tools/download-assets.sh --sha --all-targets +bash tools/release/release-check.sh +``` + +Developers should not be expected to build every target locally. Local runtime +work validates the host target; the `CI` workflow's WASIX runtime/AOT lane is +the authority for the full macOS, Linux, and Windows AOT matrix. + +Contributors do not need upstream source checkouts for normal Rust, docs, +examples, or package validation. Maintainers fetch sources only when rebuilding +the portable WASIX runtime, extensions, `initdb`, `pg_dump`, `psql`, or the generated +cluster seed. Portable WASIX artifacts, generated cluster seeds, and +native AOT artifacts are generated under `target/oliphaunt-wasix/**` locally or by +CI; they are not committed to git. + +The `CI` pull-request job uses Moon affectedness over `postgres18`, `third-party`, +`source-toolchains`, `extensions`, and the WASIX artifact inputs, plus a small producer path +allowlist, to decide whether the expensive asset build is required. Non-asset +PRs become an explicit no-op after source-controlled input checks. +Asset-producing PRs verify source pins, extension catalog metadata, generated +metadata policy, and then run the full portable/AOT producer workflow before +merge. `main` and explicit maintainer dispatches remain trusted producer lanes +for release artifacts. + +Release process details are tracked in [release.md](release.md). Historical +progress notes under `src/docs/internal/` are archived and non-normative; they are +not the current backlog or release checklist. + +Generated Cargo and npm carriers are assembled directly from private staging trees. Payload splitting uses the finished compressed archive size and reuses the fitted bytes. Maintained Rust SDK source packages use `tools/packaging/package-cargo-source.sh`, which lets Cargo select source files and describe compile targets. Product consumer checks compile the unpacked crates; carrier assembly does not rebuild each generated crate. + +Moon runs Shell tasks with Bash on Unix and Git Bash on Windows. CI machine setup +uses PowerShell only to initialize the MSVC environment. The task graph resolves +this configuration on Linux; actual Windows compiler and package execution still +requires Windows qualification. diff --git a/docs/maintainers/extension-packaging-policy.md b/src/docs/maintainers/extension-packaging-policy.md similarity index 79% rename from docs/maintainers/extension-packaging-policy.md rename to src/docs/maintainers/extension-packaging-policy.md index fee9fe88d..4c2ca0974 100644 --- a/docs/maintainers/extension-packaging-policy.md +++ b/src/docs/maintainers/extension-packaging-policy.md @@ -31,7 +31,7 @@ boundary, not general build metadata. Experimental extension work belongs on a branch; an extension merged into the public catalog has a complete package identity and only claims targets it supports. -`src/shared/extension-runtime-contract/extension-target-profiles.toml` is the single exact-extension +`src/extensions/contracts/extension-target-profiles.toml` is the single exact-extension target contract. Every extension merged to main ships on every target in that contract; incomplete target work stays on a branch. This keeps target coverage fail-closed without 39 identical member manifests or status fields. The @@ -212,42 +212,15 @@ cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources -- \ --output target/oliphaunt-resources \ --extension vector \ --prebuilt-extension vendor/acme_ext.tar.zst \ - --liboliphaunt-native-version 0.1.0 \ + --liboliphaunt-native-version "$(cat src/runtimes/liboliphaunt-native/VERSION)" \ --force ``` -Artifacts are produced from already-built PostgreSQL runtime files with the -unpublished native-packaging tool: - -```sh -cargo run -p oliphaunt-native-packaging --bin oliphaunt-extension-artifact -- \ - --runtime target/acme-pg18-runtime/files \ - --sql-name acme_ext \ - --native-module-stem acme_ext \ - --native-module-file acme_ext.so \ - --native-target linux-x64-gnu \ - --embedded-module-root target/acme-pg18-embedded/modules \ - --native-runtime-version 0.1.0 \ - --data-file data/acme_ext.rules \ - --license-profile external-native \ - --legal-files-root vendor/acme_ext-legal \ - --license-file share/licenses/acme_ext/LICENSE \ - --output vendor/acme_ext.tar.zst \ - --format tar-zst \ - --force -``` - -For desktop module extensions, `--runtime` supplies the standalone PostgreSQL -module under `lib/postgresql`, while `--embedded-module-root` supplies the -native-direct module. The artifact preserves both profile paths under -`files/lib/postgresql` and `files/lib/modules`; native server consumers select -the former, while native-direct and native-broker consumers select the latter. -Both paths are mandatory, even when their files are byte-identical. - -`--legal-files-root` is a source tree, not an output directory. For the command -above it contains `LICENSE`, `THIRD_PARTY_NOTICES.md`, and -`share/licenses/acme_ext/LICENSE`; the producer places the first two at the -carrier root and the declared upstream license below `files/`. +Extension products produce their own artifacts through +`src/extensions/artifacts/native/tools/extension-artifact-packager.mts` and their +owner package tasks. The private resource assembler only consumes explicit local +artifacts. Desktop module artifacts retain separate server and embedded module +paths under `files/lib/postgresql` and `files/lib/modules`. Binary qualification derives each profile's backend binding from the binary's actual import inventory, never from the extension name. On Windows, a @@ -258,93 +231,6 @@ must also have distinct bytes. A profile that imports neither backend provider is host-neutral; server and embedded copies may be byte-identical only when both are host-neutral. Omitting either desktop profile remains a packaging error. -The command does not build PostgreSQL or extension source. The producer and -consumer share the same schema validation, so the generated artifact is -immediately consumable by `oliphaunt-resources --prebuilt-extension`. - -For release distribution, publish an exact artifact index next to the binary -artifacts: - -```sh -cargo run -p oliphaunt-native-packaging --bin oliphaunt-extension-index -- \ - --output vendor/oliphaunt-extensions.toml \ - --target macos-arm64 \ - --artifact vendor/acme_ext-macos-arm64.tar.zst \ - --base-url https://cdn.example.com/oliphaunt/extensions/macos-arm64 \ - --signing-key-file acme-release-2026q2:keys/acme-extension-index.ed25519 \ - --force -``` - -The index producer validates each artifact manifest, rejects built-in extension -name overrides, computes byte counts and SHA-256 digests, and records relative -artifact paths plus catalog metadata such as dependencies, native module stem, -preload requirements, and mobile-prebuilt readiness. That metadata lets app -tooling list exact external extension names from the index without downloading -or building extension source. `--base-url` additionally records a URL for each -exact artifact row so release tooling can fetch missing artifacts into a cache -before verification. Release indexes should also publish a detached Ed25519 -sidecar signature at `.sig`; `--signing-key-file :` signs -the exact index bytes after writing the TOML. The signing key file contains a -hex-encoded 32-byte Ed25519 signing key. - -```toml -schema = "oliphaunt-extension-artifact-index-v1" -pg_major = 18 - -[[artifacts]] -sql_name = "acme_ext" -target = "macos-arm64" -creates_extension = true -native_module_stem = "acme_ext" -dependencies = [] -shared_preload_libraries = [] -mobile_prebuilt = true -mobile_static_archive_targets = ["ios-simulator", "ios-device", "arm64-v8a"] -path = "acme_ext-macos-arm64.tar.zst" -url = "https://cdn.example.com/oliphaunt/extensions/macos-arm64/acme_ext-macos-arm64.tar.zst" -sha256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" -bytes = 123456 -``` - -Developers can inspect built-in plus signed external availability without a -native build: - -```sh -cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources -- \ - --list-extensions \ - --extension-index vendor/oliphaunt-extensions.toml \ - --extension-target macos-arm64 \ - --trusted-extension-index-key-file acme-release-2026q2:keys/acme-extension-index.ed25519.pub -``` - -Then app/package tooling can select the external extension by exact SQL name: - -```sh -cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources -- \ - --output target/oliphaunt-resources \ - --extension acme_ext \ - --extension-index vendor/oliphaunt-extensions.toml \ - --extension-target macos-arm64 \ - --extension-cache ~/.cache/oliphaunt/extensions \ - --trusted-extension-index-key-file acme-release-2026q2:keys/acme-extension-index.ed25519.pub \ - --force -``` - -`oliphaunt-resources` verifies the artifact byte count, SHA-256 digest, PG major, -target, and artifact manifest before consuming it. It also follows exact -extension dependencies from the index. Built-in extension names -cannot be overridden by index entries. Local sidecar artifacts next to the index -are preferred. If a URL-backed artifact is missing locally, `--extension-cache` -downloads it to a target-scoped cache and verifies bytes, SHA-256, and manifest -before packaging. HTTPS artifact downloads are available only when maintainer -packaging tool builds enable the `extension-download` feature; the published SDK -does not expose or compile this HTTP/TLS implementation. Signed index verification -uses `--trusted-extension-index-key-file :`, which requires a -matching `.sig` sidecar before any indexed artifact can be used. The key -file contains a hex-encoded 32-byte Ed25519 public key. Signing and verification -are maintainer packaging-tool operations behind the `extension-signing` -feature. They are not application SDK capabilities. - `--prebuilt-extension` accepts an unpacked artifact directory, `.tar`, `.tar.gz`, or `.tar.zst`. The artifact root must contain `manifest.properties` plus a @@ -366,7 +252,7 @@ extensionSqlFileNames= extensionSqlFilePrefixes= sharedPreloadLibraries= mobilePrebuilt=yes -mobileStaticArchives=android-arm64-v8a:mobile-static/android-arm64-v8a/extensions/acme_ext/liboliphaunt_extension_acme_ext.a,ios-device:mobile-static/ios-device/extensions/acme_ext/liboliphaunt_extension_acme_ext.a,ios-simulator:mobile-static/ios-simulator/extensions/acme_ext/liboliphaunt_extension_acme_ext.a +mobileStaticArchives=android-arm64-v8a:mobile-static/android-arm64-v8a/src/extensions/acme_ext/liboliphaunt_extension_acme_ext.a,ios-device:mobile-static/ios-device/src/extensions/acme_ext/liboliphaunt_extension_acme_ext.a,ios-simulator:mobile-static/ios-simulator/src/extensions/acme_ext/liboliphaunt_extension_acme_ext.a mobileStaticDependencyArchives=android-arm64-v8a:openssl:mobile-static/android-arm64-v8a/dependencies/openssl/libcrypto.a,ios-device:openssl:mobile-static/ios-device/dependencies/openssl/libcrypto.a,ios-simulator:openssl:mobile-static/ios-simulator/dependencies/openssl/libcrypto.a staticSymbolPrefix=acme_static staticSymbolAliases= @@ -419,7 +305,7 @@ another provided prebuilt artifact. For mobile, `mobilePrebuilt=yes` on a native-module artifact means the artifact itself carries matching prebuilt static archives in `mobileStaticArchives`. The runtime-resource generator copies only selected archives into -`static-registry/archives//extensions//`. Dependency-backed +`static-registry/archives//src/extensions//`. Dependency-backed mobile artifacts can also carry `mobileStaticDependencyArchives` entries, which the runtime-resource generator copies into `static-registry/archives//dependencies//`. Android SDK builds @@ -523,7 +409,7 @@ cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources -- \ `--mobile-static-module` is an assertion that the platform build actually links the selected module. Unknown or unselected stems fail the package build. Mobile native build lanes emit one prebuilt archive per selected module at -`out/extensions//liboliphaunt_extension_.a`, so release packaging +`out/src/extensions//liboliphaunt_extension_.a`, so release packaging can link only the extensions the app selected. Android SDK builds first consume selected archives carried by the resource package under `static-registry/archives`; `-PoliphauntAndroidExtensionArchivesDir=` @@ -588,7 +474,7 @@ selected target can actually package and run. PostgreSQL 18.4 can build `uuid-ossp` only with `--with-uuid=bsd`, `--with-uuid=e2fs`, or `--with-uuid=ossp`. Oliphaunt carries a first-party portable UUID compatibility source for the e2fs API under -`src/runtimes/liboliphaunt/native/portable-uuid`; the WASIX, Linux/macOS native, +`src/runtimes/liboliphaunt-native/portable-uuid`; the WASIX, Linux/macOS native, iOS, Android, and Windows native build scripts compile and link it for `uuid-ossp`. `uuid-ossp` is stable in the generated WASIX plan; WASIX side-module builds and packages with matching archive and module hashes, has host AOT metadata, and has direct, server, restart, and diff --git a/docs/maintainers/mobile-stability-model.md b/src/docs/maintainers/mobile-stability-model.md similarity index 83% rename from docs/maintainers/mobile-stability-model.md rename to src/docs/maintainers/mobile-stability-model.md index 9a7394f65..06c793bee 100644 --- a/docs/maintainers/mobile-stability-model.md +++ b/src/docs/maintainers/mobile-stability-model.md @@ -22,10 +22,12 @@ isolation is required. ## Storage -Mobile SDKs hydrate a packaged cluster seed into app-private storage and publish +Mobile SDKs hydrate an explicitly selected seed carrier into app-private storage and publish the managed-root descriptor last. The C boundary validates complete PGDATA and never runs `initdb`. A failed initialization cannot leave a descriptor-only -root that later opens as valid. +root that later opens as valid. Existing databases do not need a seed to reopen. +ICU data is selected separately from the runtime; an ICU seed carrier declares +its canonical ICU dependency. Persistent roots survive close. Physical backup uses the native archive; restore accepts only a new or existing-empty destination. App migrations use @@ -46,8 +48,8 @@ mobile SDK moves them to an owned execution context: | SDK | Public shape | Runtime owner | Cancellation and close | | --- | --- | --- | --- | -| Swift | `async throws` | One dedicated serial dispatch queue owns root preparation, open, protocol work, backup, and close. | Transaction pinning and close are FIFO admission cutoffs: earlier permits drain and later incompatible calls fail. `cancel()` uses a separate control queue so it can interrupt the active owner call. | -| Kotlin | `suspend` | One single-thread coroutine dispatcher owns root preparation, JNI open, protocol work, backup, and close. | Transaction pinning and close are FIFO admission cutoffs. Admitted JNI work completes even if its caller is cancelled; close uses `NonCancellable`, while `cancel()` uses a separate control dispatcher. A phantom-reference fallback only enqueues forgotten-handle close on the owner. | +| Swift | `async throws` | Generated UniFFI `NativeDatabase` delegates execution to the shared Rust `EngineExecutor`; Swift owns resource preparation and facade admission. | Request-scoped task cancellation reaches the shared owner through `withTaskCancellationHandler`. Transaction pinning and close preserve admission order. | +| Kotlin | `suspend` | The same generated `NativeDatabase` and Rust executor own native execution; Kotlin owns resource preparation and facade admission. | Caller `Job` cancellation uses a scoped notification. Admitted work drains under `NonCancellable`; transaction pinning and close preserve admission order. | | React Native / Expo | JavaScript `Promise` | JSI copies binary arguments, then delegates to the same Swift or Kotlin SDK owner. | A thrown stream callback rejects its promise after native recovery confirms a known protocol boundary; an execution, transport, or recovery failure is authoritative instead. Invalidation stops callback delivery to the retiring runtime and schedules close without blocking the JavaScript, main, or UI thread. | The synchronous callback used for raw protocol streaming is backpressure, not a @@ -68,7 +70,7 @@ Cleaner/deinitializer paths are safety nets, not lifecycle APIs, and schedule best-effort close on the same owner rather than running PostgreSQL on a runtime finalizer thread. -The mobile bridges call `oliphaunt_copy_last_error` on the native operation's +The shared Rust native binding calls `oliphaunt_copy_last_error` on the native operation's calling thread and move its operation-local snapshot into language-owned memory. The size probe and copy remain stable if the separate cancellation owner updates the handle-wide fallback concurrently. The C boundary exposes no diff --git a/docs/maintainers/native-runtime-contract.md b/src/docs/maintainers/native-runtime-contract.md similarity index 96% rename from docs/maintainers/native-runtime-contract.md rename to src/docs/maintainers/native-runtime-contract.md index fc246b062..33ea10174 100644 --- a/docs/maintainers/native-runtime-contract.md +++ b/src/docs/maintainers/native-runtime-contract.md @@ -108,11 +108,11 @@ another mode. ## Qualification ```sh -moon run oliphaunt-rust:compile -moon run oliphaunt-js:compile -moon run oliphaunt-swift:compile -moon run oliphaunt-kotlin:check -moon run oliphaunt-react-native:compile +moon run oliphaunt-rust:build +moon run oliphaunt-js:build +moon run oliphaunt-swift:build +moon run oliphaunt-kotlin:format-check oliphaunt-kotlin:lint oliphaunt-kotlin:build +moon run oliphaunt-react-native:build moon run liboliphaunt-native:host-smoke ``` diff --git a/src/docs/maintainers/performance-evidence.md b/src/docs/maintainers/performance-evidence.md new file mode 100644 index 000000000..aa3848975 --- /dev/null +++ b/src/docs/maintainers/performance-evidence.md @@ -0,0 +1,50 @@ +# Performance measurements + +Benchmarks are optional measurements, not release qualification gates. The native +runner executes fixed workloads against direct, broker, and server modes, +ordinary PostgreSQL, and SQLite. Its JSON includes timings, sample counts, +percentiles, and the selected durability and memory settings. + +Build the runtime you intend to measure, then use an explicit library and matching +PostgreSQL tools. From the repository root: + +```sh +export LIBOLIPHAUNT_PATH=/absolute/path/to/liboliphaunt.so +export OLIPHAUNT_POSTGRES=/absolute/path/to/postgres +export OLIPHAUNT_INITDB=/absolute/path/to/initdb +src/benchmarks/perf/run-native.sh target/perf/direct-rtt native-liboliphaunt --engine direct --suite rtt --iterations 100 +src/benchmarks/perf/run-native.sh target/perf/postgres-rtt native-postgres --suite rtt --iterations 100 +src/benchmarks/perf/run-native.sh target/perf/sqlite-speed sqlite --suite speed +``` + +Use the platform's actual library filename. Native modes are `direct`, `broker`, +and `server`; suites are `rtt`, `speed`, `streaming`, `prepared-updates`, and +`backup-restore`. Native direct mode opens once per process, so run separate +commands for separate suites. The runner rejects unsupported mode/suite pairs. +SQLite supports `speed` and `backup-restore`. Narrow speed-case diagnostics remain +available through the `diagnose-speed-cases` subcommand. + +Each output directory is exclusive. It records the command, source and workload +hashes, runner and explicitly supplied runtime binary hashes, compiler/host +context, raw JSON, and diagnostics. A failed run leaves its JSON marked partial. +Source and recorded binary hashes must still match when a run completes. Preserve +any additional runtime assets and configuration used by the run alongside these +records. Use the environment variables above for runtime paths so they are hashed. + +Repeat the exact command in fresh output directories when comparing changes. +Keep hardware, engine, client transport, SQL, durability, dataset, and cache state +consistent. Report sample counts and variation; a quick plumbing run does not +establish a performance claim. Review the raw JSON rather than treating an +automatically generated parity verdict as evidence. + +WASIX Node and browser measurements retain their own specs and runners: + +```sh +moon run perf-tools:wasix-node-measure +moon run perf-tools:wasix-browser-measure +bun run --cwd src/benchmarks/perf/wasix-node bench:streaming +``` + +The browser runner uses an installed browser and the same isolated host headers +as the product smoke test. Committed historical baselines and reports under +`src/benchmarks/` remain historical evidence; they do not qualify current builds. diff --git a/docs/maintainers/physical-archive-format.md b/src/docs/maintainers/physical-archive-format.md similarity index 97% rename from docs/maintainers/physical-archive-format.md rename to src/docs/maintainers/physical-archive-format.md index ecc918562..f21a7a486 100644 --- a/docs/maintainers/physical-archive-format.md +++ b/src/docs/maintainers/physical-archive-format.md @@ -70,7 +70,7 @@ another backup mode. The filename arithmetic contract, including 16 MiB and 4 MiB segment sizes and the 4 GiB `XLogId` boundary, is fixed by -`src/shared/fixtures/storage/physical-backup-wal-range-v1.properties`. +`src/test-fixtures/storage/physical-backup-wal-range-v1.properties`. The bulk pass skips top-level backup/runtime temporaries, `.DS_Store` wherever encountered, `pg_internal.init*`, `pgsql_tmp*`, `global/pg_control`, `pg_wal` contents, and the contents of PostgreSQL's transient state directories. Those directories remain present as @@ -113,7 +113,7 @@ The required restored files are: ## Verification Native C tests and both WASIX binding suites consume the shared manifest and WAL -range fixtures under `src/shared/fixtures/storage`. Parser tests cover traversal, +range fixtures under `src/test-fixtures/storage`. Parser tests cover traversal, links, duplicate paths, invalid checksums, truncated terminators, trailing data, unknown metadata, and tree-shape conflicts. Backup tests cover same-segment and multi-segment WAL diff --git a/docs/maintainers/release-setup.md b/src/docs/maintainers/release-setup.md similarity index 87% rename from docs/maintainers/release-setup.md rename to src/docs/maintainers/release-setup.md index 7eadfe351..a55b03553 100644 --- a/docs/maintainers/release-setup.md +++ b/src/docs/maintainers/release-setup.md @@ -5,7 +5,7 @@ Status: normative external-setup guide. Last verified: 2026-07-30. Owner: reposi This document covers state that cannot live in the repository. The executable contract is the direct least-privilege workflow in `.github/workflows/release.yml` and -`tools/release/check_publish_environment.mjs`; update this guide when either +`tools/release/check_publish_environment.mts`; update this guide when either changes. ## GitHub controls @@ -48,7 +48,7 @@ GitHub can reject tags on an older candidate whose workflow files differ from the publishing commit, even with an existing transport ref. The normal `GITHUB_TOKEN` cannot request `workflows: write`. The pinned `actions/create-github-app-token` action requests only the two required -permissions for this repository, checks them before candidate download, and +permissions for this repository, checks them before publication, and mints fresh tokens immediately before product/transport tags and SwiftPM tags. It revokes each installation token during job cleanup. Ordinary publication, attestations, and registry authentication keep their existing credentials. @@ -134,7 +134,7 @@ mutation: ```sh lock=target/release/publication-lock.json -tools/dev/bun.sh tools/release/trusted-publisher-config.mjs --lock "$lock" +bash tools/release/trusted-publisher-config.sh --lock "$lock" ``` Authenticated `--audit` remains read-only. Mutation exists only behind the @@ -156,8 +156,8 @@ with the `release-publish` grants. Bootstrap's content write is solely to create the immutable release transport tag immediately before its first registry mutation; reruns do not create, move, or delete repository refs. -Dry-run and publish share one YAML-anchored step list but remain separate -permission and environment boundaries. +Candidate preparation, conditional bootstrap, and publication are dependent +jobs in one `publish` run with separate permissions and environments. The read-only dry-run validates every public release visible to its token and every selected product tag. `publish` uses its content-write token to require the complete live draft/public release set before mutation. A hidden draft is @@ -165,14 +165,15 @@ therefore never misclassified as absent proof, and dry-run does not gain write capability merely to list drafts. Bootstrap recovery uses GitHub's rerun of the original failed workflow run. -The rerun retains the original workflow SHA and explicit approved dry-run ID, +The rerun retains the original workflow SHA and explicit candidate identity, then verifies the exact `oliphaunt-release-transport/` tag instead of resolving moving `main`. -Audit the live controls without changing them: +Audit the live controls without changing them for release setup or an actual +public registry/tag/asset mutation: ```sh -tools/dev/bun.sh tools/release/audit-github-release-controls.mjs \ +tools/dev/bun.sh tools/release/audit-github-release-controls.mts \ --governance solo \ --bootstrap-state idle ``` @@ -181,12 +182,11 @@ Use `--governance team` only when an independent maintainer is actually available. Bootstrap state is an explicit credential lifecycle, not an authorization shortcut: -- `idle` is the default before first-identity bootstrap, including - qualification, release-PR preparation, and dry-run; it requires both - bootstrap tokens to be absent; +- `idle` is the default when bootstrap tokens are absent; it requires both + token names to be absent and does not describe whether source CI may run; - `ready` is valid only after every reviewed short-lived Cargo/npm token required by the approved lock has been installed for an imminent - `publish-bootstrap` dispatch; it accepts either registry token or both, and + `publish` dispatch that will bootstrap missing identities; it accepts either registry token or both, and requires at least one. Provision only the registries whose exact locked identities remain absent. A recovery in which every selected Cargo/npm version already matches stays `idle` and requires neither token; and @@ -194,7 +194,14 @@ authorization shortcut: configured, and both tokens were revoked and removed; it also requires the token names to be absent. -The `publish-bootstrap` workflow independently derives the registries required +This audit is not an ordinary branch-push, release-PR or source-qualification +gate. Those jobs do not select `release-bootstrap` and cannot receive its +environment secrets. A bootstrap lifecycle finding does not justify blocking +unrelated source work, changing credentials, or claiming a different lifecycle. +It remains a release setup finding to resolve before the affected public +mutation. No remote settings or secrets are changed by this diagnostic. + +The conditional bootstrap job independently derives the registries required by the approved lock and rejects each missing credential immediately before mutation, so an `idle` audit cannot authorize bootstrap publication. The auditor reads the canonical repository through `gh api`, prints deterministic @@ -213,7 +220,7 @@ The publication catalog defines stable carrier topology; the frozen publication 1. Create the maintainer account/team. 2. Inventory the exact first-release lock. Crates.io's documented per-user new-name limit is a burst of 5 followed by one new crate every 10 minutes. Do not copy a carrier count from this document: the publication catalog is the stable identity model, while oversized payloads add generated `*-part-NNN` carriers only when the candidate artifacts and publication lock are assembled. For `C` missing Cargo names, the untouched-default rate-limit floor is `max(0, C - 5) * 10 minutes`. Crates.io support may grant exceptional capacity, but no API exposes that account state, so the workflow never treats an operator-entered number as proof. A valid `429 Retry-After` response and the next read-only registry inventory are authoritative. -3. Use the protected `publish-bootstrap` operation for only the missing first versions. The operator supplies the run ID of the prior dry-run that emitted the approved lock and complete publication candidate. The slim bootstrap job verifies and atomically installs those exact bytes; it does not rebuild them. Before initializing its ledger or sending any npm/Cargo mutation, the workflow queries crates.io read-only and reports exact selected/existing/missing counts and the official-default duration floor. It admits only a dependency-closed batch that fits the bounded job window. Independent Cargo and npm mutations overlap; each registry remains strictly sequential, and dependencies within the absent-name scope remain barriers. An optional npm dependency on an existing package name stays on the normal trusted-publication graph; any other unavailable locked dependency stops bootstrap. +3. Dispatch `publish`; its conditional protected bootstrap job creates only missing first versions using the candidate prepared in the same run. The slim bootstrap job verifies and atomically installs those exact bytes; it does not rebuild them. Before initializing its ledger or sending any npm/Cargo mutation, the workflow queries crates.io read-only and reports exact selected/existing/missing counts and the official-default duration floor. It admits only a dependency-closed batch that fits the bounded job window. Independent Cargo and npm mutations overlap; each registry remains strictly sequential, and dependencies within the absent-name scope remain barriers. An optional npm dependency on an existing package name stays on the normal trusted-publication graph; any other unavailable locked dependency stops bootstrap. When the exact lock cannot finish in one six-hour hosted job, the job drains in-flight uploads, reconciles successful mutations, uploads its @@ -257,9 +264,9 @@ The publication catalog defines stable carrier topology; the frozen publication ```sh lock=target/release/publication-lock.json digest="$(jq -er .lockDigest "$lock")" - tools/dev/bun.sh tools/release/trusted-publisher-config.mjs \ + bash tools/release/trusted-publisher-config.sh \ --audit --ecosystem cargo --lock "$lock" - tools/dev/bun.sh tools/release/trusted-publisher-config.mjs \ + bash tools/release/trusted-publisher-config.sh \ --apply --confirm-lock-digest "$digest" --ecosystem cargo --lock "$lock" ``` @@ -329,10 +336,10 @@ publish before their aggregator, and are not independent release products. ```sh lock=target/release/publication-lock.json digest="$(jq -er .lockDigest "$lock")" - tools/dev/bun.sh tools/release/trusted-publisher-config.mjs \ + bash tools/release/trusted-publisher-config.sh \ --audit --ecosystem npm --batch 1 --lock "$lock" \ --output target/release/npm-trust-batch-1-pre-audit.json - tools/dev/bun.sh tools/release/trusted-publisher-config.mjs \ + bash tools/release/trusted-publisher-config.sh \ --apply --confirm-lock-digest "$digest" \ --ecosystem npm --batch 1 --lock "$lock" \ --output target/release/npm-trust-batch-1-apply.json @@ -435,33 +442,33 @@ promotion and remain covered by the exact GitHub asset/attestation receipt. head. A raw Release Please head is never mergeable merely because its direct versions and changelogs look complete. 4. Merge it and wait for that exact commit's non-cancelled `Qualified` CI run. -5. Run `publish-dry-run`. It must download that run's exact-SHA build artifacts, create/freeze the exhaustive publication lock and complete publication candidate, and perform clean package/install checks without credentials. Preserve the successful run ID containing both approval artifacts. -6. If npm/crates first identities are missing, run `publish-bootstrap` with that approved dry-run ID. Before any registry identity becomes public, it resolves the exact merged Release Please PR by the release SHA, requires pending or already-tagged lifecycle state, and proves the tagged label still exists. At the mutation boundary it uses the exact transport rule above; an absent tag is its first mutation and requires the immediately preceding current-main proof. It installs the complete candidate without rebuilding, writes a genesis checkpoint before the first registry mutation, and appends immutable byte receipts throughout the run. If the job reports incomplete, use its exact rerun command after the reported delay; the rerun restores the same lock-bound ledger and approval even if `main` advanced. After the chain seals, use the exact lock's `trusted-publisher-config.mjs` plan, audit, and explicit apply flow above; retain the final reports and revoke the bootstrap tokens. Bootstrap does not promote GitHub releases or publish unrelated registries. -7. Run normal `publish` on the same current `main` SHA. Before the first - mutation it repeats the exact Release Please markability assertion and pins - the immutable transport tag. One protected job stages GitHub releases, - attempts the complete dependency-ordered registry plan, runs public - Cargo/npm/Maven and Git/Swift probes from fresh anonymous caches, and - promotes drafts last. It has no normal checkpoint, continuation, or phase - handoff. If it stops, use GitHub's rerun on the original Release run; - matching immutable state is byte-verified and skipped. The final label updates add - `autorelease: tagged` and remove `autorelease: pending` without replacing - unrelated labels. -8. Preserve the publication lock, ledger, provenance, and workflow URL with the release. +5. Run `publish`. It prepares the frozen lock and complete candidate from + exact-SHA CI artifacts, then automatically bootstraps missing Cargo/npm + names, publishes the dependency-ordered registry plan, checks anonymous + public consumers, and promotes GitHub drafts last. Existing names use + trusted publishing. Provision short-lived bootstrap tokens only if names + are absent. No separate dry-run, bootstrap dispatch, or approval run ID is + needed on this path. +6. If a job stops, preserve its evidence and use + `gh run rerun --failed` after any reported not-before delay. + Bootstrap restores its checkpoint; publishers prove and skip matching + immutable bytes. Successful preparation is reused. +7. After first identities exist, configure their trusted publishers with the + exact lock's `trusted-publisher-config.sh` plan/audit/apply flow and revoke + bootstrap tokens before the next release. Preserve the lock, ledger, + provenance, and workflow URL. The first generated release PR consumes the one-time `bootstrap-sha` boundary. -`sync-release-pr.mjs` removes it on that PR once any manifest entry advances +`sync-release-pr.mts` removes it on that PR once any manifest entry advances from `0.0.0`; the release-bump commit must contain that removal. Never delete the boundary on the unreleased introduction tree. Never restore it on a publishable release-bump tree. -On every path, `release_commit` is only an equality assertion for the workflow -commit; it cannot select an older commit and the workflow ref must be `main`. -An incomplete bootstrap is resumed by rerunning the original workflow run, -which stays pinned to its release commit and approved candidate. Release -tooling fixes create a new candidate SHA and require new qualification. There -is no temporary Release Please target branch, and a later commit cannot finish -the release. +Normally `release_commit` asserts the current workflow SHA. For a narrowly +permitted publication-only fix, `publish` may supply an approved ancestor SHA +and its `approval_run_id`. The controller rejects product, packaging, build, +CI, and lockfile changes. The old candidate retains its exact qualification +and bytes; the current controller requires successful CI `Required`. ## Recovery @@ -476,10 +483,12 @@ qualification. Normal recovery reruns `publish` at the exact same release commit with the same qualified artifacts and approved lock. Use GitHub's rerun for the failed Release run rather than a fresh dispatch after `main` moves. The original run -and referenced CI/dry-run artifacts must still be available. The rerun +and referenced CI/candidate artifacts must still be available. The rerun byte-verifies public registry and GitHub state, skips exact matches, and writes -only missing state. A required fix creates a new candidate and requires normal -versioning and qualification. First-identity bootstrap alone restores its checkpoint chain. See +only missing state. Product changes require a new candidate and normal +versioning and qualification. Publication-only fixes may reuse a completed +Release run whose candidate preparation succeeded, through the explicit +source SHA and approval run inputs. First-identity bootstrap alone restores its checkpoint chain. See `.codex/skills/release-oliphaunt/references/recovery.md` for recovery. ## External readiness checklist diff --git a/docs/maintainers/release.md b/src/docs/maintainers/release.md similarity index 81% rename from docs/maintainers/release.md rename to src/docs/maintainers/release.md index 56279a75d..1b7b399be 100644 --- a/docs/maintainers/release.md +++ b/src/docs/maintainers/release.md @@ -8,6 +8,22 @@ Status: normative operation guide. Last verified: 2026-07-30. Owner: repository Oliphaunt releases independent products from one monorepo. There is no repository-wide product version. +CI can qualify selected products using the `release_products_json` dispatch +input, for example `["oliphaunt-js"]`. Leave all platform selectors at `all`. +Moon selects those owners' tasks, downstream compatibility checks and required +producer dependencies. An empty product array retains the exhaustive audit. +Publication accepts this record only for covered products at the exact candidate +SHA; it still verifies the immutable artifacts and any required WASIX evidence. +Generated release PRs and their main merge automatically select the products +whose Release Please manifest versions advance. Exact main pushes and eligible +main dispatches can produce publishable qualification; PR checks use the same +scope but cannot authorize publication. Publication reuses covering successful +CI, waits for active matching CI, or requests one missing run while main still +equals the candidate SHA. Failed causal runs require recovery; ambiguous +dispatches are not automatically repeated. Cross-commit producer reuse remains +an explicit acceptance item rather than permission to substitute arbitrary +older artifacts. + ## Model A product owns its SemVer, changelog, source identity, Release Please component, @@ -22,7 +38,7 @@ The canonical model is composed from: versions, changelogs, components, and tag naming; - the protected release workflow for exact-SHA tag and draft-release creation; - product `release.toml` and explicit target manifests for publish surfaces; -- `tools/release/publication-catalog.mjs` for the normalized Product → Carrier inventory; +- `tools/release/publication-catalog.mts` for the normalized Product → Carrier inventory; - the frozen publication lock for the actual files produced by one candidate. Do not maintain a second hand-written package matrix. Query the catalog and inspect the lock. Dynamic package identities are forbidden except crates.io payload `part-N` carriers whose parent is declared and whose size requires splitting. @@ -37,8 +53,8 @@ Legal material follows the bytes in each physical carrier, not merely the product name or source repository. Code-only and source-only facades carry the Oliphaunt MIT profile. A payload carrier carries its exact role profile plus the legal files for every component whose bytes it contains. The executable -authorities are the publication catalog, `release-notices.mjs`, -`extension-upstream-licenses.mjs`, and the broker dependency-license contract; +authorities are the publication catalog, `release-notices.mts`, +`extension-upstream-licenses.mts`, and the broker dependency-license contract; do not maintain a separate handwritten carrier matrix. Every direct carrier, payload part, aggregate, and final registry archive must @@ -92,21 +108,20 @@ and participates in the same carrier checks as other public products. do not remove it before Release Please has consumed it or retain it after the first bump. -`tools/dev/bun.sh tools/release/sync-release-pr.mjs` closes the generated -candidate metadata: shared-source candidates, compatibility values for selected +`bash tools/release/sync-release-pr.sh` closes the generated +candidate metadata: compatibility values for selected consumers, package pins, locks, and deterministic evidence. It never creates a consumer release merely because one of its dependencies changed. Its `--check` mode proves that the same state is already closed. Pure version/changelog changes alter package envelopes but do not alter committed runtime binaries. -PR CI runs `sync-release-pr.mjs --check-generated-release` only for the +PR CI runs `sync-release-pr.sh --check-generated-release` only for the same-repository `release-please--branches--main` head, before artifact planning. That cheap barrier checks the dependency/compatibility/lock fixed point and the exact structured release commit without compiling the asset -verifier. It prevents Release Please's transient raw PR commit from launching -the native and mobile matrices while the prepare job is still normalizing it. -It is an admission optimization, not a substitute for the full write/check, -metadata, asset, extension, and package gates on the normalized head. +verifier. The prepare workflow generates and validates the candidate locally +before its first push. This admission check verifies the already-closed pushed +head before expensive matrices begin. Release Please selects changes under each configured product path. Shared code that changes published bytes must therefore live in, or be represented by, the @@ -164,9 +179,10 @@ does not use GitHub Search or the Issues API's eventually consistent label Root publication admission accepts only a current-main candidate with one non-cancelled CI run whose `head_sha` is exact and whose `Qualified` gate succeeded. That record covers required checks, tests, builds, policy, selected E2E, and named build artifacts. A successful `Builds` job alone is insufficient. After the root job pins the immutable release transport tag, the rest of that run remains bound to the exact transaction without re-evaluating the moving main branch. -Publication has one identity: the qualified release commit owns the workflow, -artifacts, publication lock, product tags, and registry bytes. A retry must run -that exact commit; a later commit cannot control or finish its publication. +The qualified source commit owns the artifacts, lock, product tags, and +registry bytes. Ordinarily it also owns the publishing workflow. A narrowly +permitted publication-only controller fix may publish those same frozen bytes; +its workflow SHA is recorded separately and requires successful CI Required. The `macos-26` publication runner is ARM64, but its current runner-image contract exposes the installed Java 17 path as `JAVA_HOME_17_arm64` (including @@ -193,68 +209,57 @@ immediately before writes. Run local metadata gates before dispatching: ```sh -tools/dev/bun.sh tools/release/release-check.mjs -cargo run -p xtask -- assets verify-committed -tools/dev/bun.sh src/extensions/tools/check-extension-model.mjs --check +bash tools/release/release-check.sh +tools/dev/bun.sh src/extensions/tools/check-extension-model.mts --check ``` If the candidate changes a GitHub workflow or local action, also run -`bash tools/policy/check-workflows.sh`. That conditional gate runs the pinned +`bash tools/ci/check-workflows.sh`. That conditional gate runs the pinned `actionlint` and `zizmor` configuration, focused workflow security checks, and helper behavior tests; `actionlint` by itself is not equivalent. -The default `release-check.mjs` invocation includes publication metadata plus -the release-owned and policy-owned mutation unit suites. `check-release-metadata.mjs` +The default `release-check.sh` invocation includes publication metadata plus +the release-owned and policy-owned mutation unit suites. `check-release-metadata.mts` is the canonical product, version, registry ownership, and dependency graph -validator. The release-PR job runs `release-metadata-check.mjs` once after the +validator. The release-PR job runs `release-metadata-check.sh` once after the generated commit is synchronized, while hosted qualification owns candidate source-metadata evidence. Publishers verify the frozen candidate identity and live external state instead of replaying source-only metadata checks. -The `Release` workflow has four operations: - -1. `prepare-release-pr` — run from current `main`; creates/updates the single generated release PR and syncs derived files. -2. `publish-dry-run` — downloads exact-SHA CI artifacts, packages every public carrier, freezes/verifies the exhaustive lock, and uploads the complete lock-bound publication candidate without write credentials. -3. `publish-bootstrap` — creation of missing npm/crates identities only, from an explicitly approved candidate in a bounded Linux job. Its first registry inventory freezes only absent names into the checkpoint ledger; existing names awaiting a later version stay on the normal trusted-publication path. If bootstrap stops incomplete, rerun the failed job of that same workflow run; the checkpoint ledger resumes the exact SHA and approval. Provision only the registry token required by that frozen scope. npm requires a short-lived granular `@oliphaunt` read/write token with 2FA bypass only when an npm identity is absent. -4. `publish` — normal trusted release. It installs that same explicitly approved candidate, adds signing/upload envelopes, and uses short-lived Cargo/npm credentials plus Maven protected secrets. - -On the normal path, only a successful `publish-dry-run` uploads the canonical -`oliphaunt-publication-lock` and `oliphaunt-publication-candidate` approval -artifacts. Both mutating operations require the operator-supplied dry-run ID, -download both artifacts by immutable artifact identity, and verify the archive's -source SHA/tree, qualification run, approval run, products, lock, hashes, sizes, -dependencies, and complete file set. Missing, expired, extra, unsafe, or changed -contents stop publication. Neither operation rebuilds or silently selects a -newer dry-run. - -Because GitHub hides drafts from tokens without push access, this read-only -dry-run validates exact selected tags plus any visible public releases, then -replays the pinned GitHub-staging boundary. The mutating `publish` operation -repeats the preflight with its content-write token and requires every selected -draft or already-public release to have the exact frozen metadata before the -first write. The dry-run never receives write permission solely to observe -drafts. - -`.github/workflows/release.yml` is the one directly dispatched release -workflow. Its operation jobs declare their own least-privilege permissions and -protected environments: dry-run is repository-read-only, bootstrap adds -`contents: write`, preparation receives only release-PR writes, and normal -publication runs as one direct `release-publish` job. Bootstrap's -content write exists solely for the root generation to create the immutable -release transport tag immediately before its first registry mutation; -reruns never create, update, or delete that tag. Dry-run and -normal publish are separate jobs over one YAML-anchored step list, so this -separation does not create two release implementations that can drift. - -Credential-bearing steps execute only in direct jobs that select the -corresponding protected environment. The YAML anchor shared by dry-run and -normal publish contains Maven secret expressions, but every such step also requires -the literal `publish` operation and therefore cannot execute in dry-run. -`release-pr`, `release-bootstrap`, and `release-publish` remain the credential -boundaries; do not duplicate their secrets at repository level or route those -jobs through a reusable workflow that changes the environment-secret boundary. -GitHub automatically provides each job's scoped `GITHUB_TOKEN`. +The `Release` workflow has two operations: + +1. `prepare-release-pr` — run from current `main`; creates or updates the generated release PR and synchronizes derived files. +2. `publish` — waits for exact-SHA qualification, prepares and freezes the candidate, bootstraps missing Cargo/npm names when necessary, publishes verified bytes, checks public consumers, and promotes GitHub drafts last. + +Ordinary publication needs no approval run ID or separate dry-run/bootstrap +dispatch. Preparation uploads `oliphaunt-publication-lock` and +`oliphaunt-publication-candidate`; dependent jobs download their immutable +artifact IDs. They verify the source SHA/tree, qualification run, approval run, +products, lock, hashes, sizes, dependencies, and complete file set before use. +Missing, expired, extra, unsafe, or changed contents stop publication. Binary +producer outputs are reused from qualification, not rebuilt by publishers. + +An optional `approval_run_id` reuses a previous candidate during recovery. +The selected Release run must be completed and either successful (including a +legacy dry-run) or failed with a successful `Prepare frozen publication +candidate` job. Active and cancelled runs cannot authorize recovery. The +normal CI qualification gate still requires a successful complete workflow. + +Preparation is read-only and uses the existing `release-dry-run` environment. +It checks visible public releases; the publishing job repeats that preflight +with its content-write token so hidden drafts are checked before mutation. +The conditional bootstrap job uses `release-bootstrap` credentials only for +wholly absent names, preserves its resumable ledger, and hands its immutable +ledger artifact ID to publication. Provision only the registry tokens required +by missing names. After the initial release, configure trusted publishers for +those names and revoke bootstrap tokens before the next release. + +Credential-bearing jobs directly select `release-pr`, `release-bootstrap`, +or `release-publish`. Keep secrets in those protected environments. The +bootstrap job's content-write permission creates the immutable transport tag; +normal publication owns GitHub staging, attestations, and promotion. GitHub +provides each job's scoped `GITHUB_TOKEN`. Trusted publishers match `release.yml`: direct publication exposes that file through `workflow_ref`, together with the exact `workflow_sha` and the @@ -274,13 +279,13 @@ root-main ref and pinned approval run before any operation job. Malformed or contradictory manual inputs therefore fail before release work begins. After bootstrap, derive the complete configuration inventory from the exact -publication lock with `tools/release/trusted-publisher-config.mjs`. Its default +publication lock with `tools/release/trusted-publisher-config.sh`. Its default plan is offline/read-only; authenticated inspection requires `--audit`, and creation requires both `--apply` and confirmation of the exact lock digest. Wrong or extra configurations are blockers and are never automatically replaced. -Dry-run assembly installs the full workspace; normal publish and bootstrap +Candidate assembly installs the full workspace; normal publish and bootstrap install only the verified command-line tools required for signing, uploading, and public verification. Neither path relies on Corepack. When the selected carrier set includes npm, both normal and bootstrap jobs use @@ -296,16 +301,26 @@ the frozen registry mutation logic. Installer fault-injection suites are owned by the exact-SHA `ci-workflows:check` gate. Publication does not execute those download, cache, and rollback suites again. Release-PR preparation runs the live metadata checker -once after structured commit verification. The protected dry-run verifies the +once after structured commit verification. The candidate preparation job verifies the same-SHA `Qualified` record before freezing the candidate; slim publishers do not replay that source-only validation. -`--qualified-ci` is not a trusted Boolean bypass: the publisher rejects dirty -or non-hosted use, binds HEAD to `RELEASE_HEAD_SHA`, and reruns the fixed -candidate/plan/WASIX-evidence verifier before omitting mutation tests. Workflow -policy rejects extra full invocations or replay before candidate verification. - -Preparation and dry-run bind `release_commit` to the workflow commit. For -`publish-bootstrap` and `publish`, it may instead identify an approved ancestor +For local read-only validation, run `bash tools/release/release-check.sh` for +source metadata and release-tool tests. Check selected public version state with +`bash tools/release/release-check-registries.sh --products-json '["oliphaunt-js"]' --head-ref HEAD` +(replace the example selection with the actual products). Neither command +assembles release packages; the retired dry-run wrapper did not assemble them +either. Use the selected products' package and artifact/consumer test tasks for +local package rehearsal. + +Candidate preparation verifies its exact-SHA qualification record once and +performs registry preflight once. Immediately before assembly, +`qualified-release-replay.sh` still rejects source modifications, suppressed +index entries and a mismatched checkout SHA. This source check runs locally as +well as in GitHub Actions. Publication rechecks live registry state at its +mutation boundary, where a race can still change the result. + +Preparation binds `release_commit` to the workflow commit. For +`publish` with `approval_run_id`, it may instead identify an approved ancestor candidate after narrowly permitted publication-only fixes. The controller check requires a clean checkout and rejects changes to product source, packagers, build definitions, CI, and lockfiles. The publishing commit requires @@ -325,14 +340,14 @@ new dry-run, or bootstrap rerun. Incomplete bootstrap still resumes only through its original run; this does not add cross-run checkpoint migration. If a publication-only code fix makes that run unusable, retain its ledger and first verify every recorded public package against the approved lock. Then a -fresh bootstrap dispatch at the corrected current `main`, with the same source -SHA and approval run, inventories registry state and starts a new scope for +fresh `publish` dispatch at the corrected current `main`, with the same source +SHA and candidate run, inventories registry state and starts a new scope for only the still-absent names. Already-public versions are excluded from that new scope and remain subject to normal publication integrity verification. Use the new run for subsequent checkpoint retries. Normal publish discovers its completed ledger by the approved lock. Never edit or transplant the old checkpoint chain. At the mutation boundary, a root -`publish-bootstrap` or `publish` run first reads the lightweight +`publish` run first reads the lightweight `oliphaunt-release-transport/` tag and accepts only a direct commit ref at its exact release SHA. If the tag is absent, or this is the first run attempt, the helper proves that the publishing workflow is current `main` before creating or accepting it; @@ -342,7 +357,7 @@ original `refs/heads/main` workflow SHA may reuse an already exact tag after `main` advances. A missing tag still requires the proof on every attempt, while a wrong or annotated tag fails closed. The helper never updates or deletes the tag and never replays an ambiguous create. A manual -rerun retains the original workflow SHA and approved dry-run even after `main` +rerun retains the original workflow SHA and approved candidate even after `main` advances. Normal publication remains exact-SHA and lock-bound after the first mutation. @@ -371,9 +386,9 @@ lock-bound checkpoint, fails with an exact rerun command, and resumes only when the maintainer reruns the failed job of that same Release workflow run. The workflow does not encode a second product/ecosystem publish order. The -normal registry executor derives its in-memory plan directly from the approved +Shell registry executor derives its plan directly from the approved lock and rejects an omitted selected dependency, unknown carrier, cycle, or -non-contiguous operation order. It runs one sequential Cargo, npm, and Maven lane, +non-contiguous operation order. `bash tools/release/publish-registries.sh --products-json "$PRODUCTS_JSON" --head-ref "$RELEASE_HEAD_SHA" --publication-lock "$PUBLICATION_LOCK_PATH"` runs one sequential Cargo, npm, and Maven lane, overlaps independent lanes, and awaits every explicit cross-registry dependency barrier. Cargo (including dynamic payload parts) and npm consume their exact frozen carrier bytes. All selected Maven coordinates form one @@ -381,7 +396,12 @@ signed, atomic Central deployment because Maven Central validates and publishes that bundle as a unit. Before the first GitHub write, the workflow constructs the complete selected bundle without upload and verifies every coordinate, POM, primary artifact, sources JAR, javadoc JAR, signature, checksum, nonempty -file, and the strict sub-1-GB archive ceiling. A rerun skips an immutable carrier only after proving its +file, and the strict sub-1-GB archive ceiling. The Shell command +`bash tools/release/preflight-maven-central-bundle.sh --publication-lock "$PUBLICATION_LOCK_PATH" --products-json "$PRODUCTS_JSON" --release-commit "$RELEASE_HEAD_SHA"` +preserves the signed bundle in `target/release/maven-central/normal-registry-plan`. +Publication verifies its lock digest, exact carrier selection, size, and SHA-256 +and uploads those same bytes; it does not repeat signing or packaging. +A rerun skips an immutable carrier only after proving its public bytes match the lock; a partially published Maven product fails closed. npm is the deliberate exception to a separate moving-tag promotion phase. @@ -394,10 +414,12 @@ is documented by npm's [trusted-publishing limitations](https://docs.npmjs.com/t An existing immutable identity is skipped only when its version/integrity matches the lock. A conflict stops publication. Never replace a public artifact or reuse a version. -Identity bootstrap is checkpointed before and during publication. The genesis +Identity bootstrap runs through `bash .github/scripts/bootstrap-registry-identities.sh` +and is checkpointed before and during publication. Shell owns both registry +lanes and passes each publisher only its own registry credentials. The genesis checkpoint freezes the source SHA/tree, publication-lock and catalog digests, selected products, and complete expected registry envelope before the first -write. The slim bootstrap job consumes the canonical dry-run's complete +write. The slim bootstrap job consumes the preparation job's complete manifest-bound publication candidate; it neither reconstructs packages nor repeats the macOS build ceremony. Bootstrap preserves the lock's Cargo/npm dependency edges and executes one sequential lane per registry, overlapping only @@ -464,11 +486,14 @@ selected it also fetches the unscoped source tag, requires its synthetic commit to have the release SHA as its only parent, and evaluates that tagged `Package.swift` with `swift package dump-package`. -Known registry/CDN not-yet-visible and transient network responses are retried -only within one shared deadline. Every retry uses a new workspace and package -cache so a partial npm install or Gradle negative cache cannot authorize a -result. Exact-version, exact-source, closure, tag, and receipt mismatches are -terminal. The gate emits one deterministic immutable evidence file bound to +Run this gate locally with `bash tools/release/public-consumer-smoke.sh` and +the same lock and receipt arguments used by the workflow. It requires jq and +GNU timeout (`coreutils` on macOS). Shell owns the parallel command lanes, +private homes, deadlines, and descendant cleanup; TypeScript stages manifests +and validates the resulting resolution. Package managers retain their normal +network retries, and crates.io metadata reads have bounded retries. A failed +command or exact-version, source, closure, tag, or receipt mismatch stops the +gate; there is no second retry loop that discards and repeats entire installs. The gate emits one deterministic immutable evidence file bound to the registry receipt hash, GitHub receipt digest, lock digest, source SHA/tree, and selected products; that file is uploaded before draft promotion. The publish job runs on macOS, so npm's `installedCarrierIds` proves only the host @@ -650,18 +675,20 @@ Release run at the exact same commit; it reconciles matching immutable state and writes only what remains. Preserve the checkpoint chain only for first-identity bootstrap. Product changes require a new version and candidate. -Normal recovery never crosses commits. Re-run `publish` at the exact release +For ordinary recovery, rerun failed jobs in the original `publish` run at the release commit with the same qualified artifacts and approved lock. Use GitHub's rerun for the original failed Release run; do not create a fresh dispatch after -`main` moves. The original run and every referenced CI/dry-run artifact must +`main` moves. The original run and every referenced CI/candidate artifact must still be available. The rerun inventories every selected identity, proves existing registry bytes and GitHub state, skips exact matches, and writes only missing state. A conflict stops the release. -A newer workflow commit cannot finish an older release. If completion requires -a code or workflow fix, that fix is a new candidate and must follow normal -versioning and qualification. First-identity bootstrap keeps its separate -checkpointed recovery path. +If completion requires a publication-only fix allowed by the controller, +dispatch `publish` on current main with the original `release_commit` and +`approval_run_id`. The previous run must have completed with a successful +candidate preparation job, or be a successful legacy dry-run. Changes to +product source, packaging, builds, CI, or lockfiles require fresh qualification. +Bootstrap retains its lock-bound checkpointed recovery path. Ordinary clean-state control-plane workflow, policy, validator, registry-transport, test, or documentation changes do not use recovery and do diff --git a/src/docs/maintainers/repo-structure.md b/src/docs/maintainers/repo-structure.md new file mode 100644 index 000000000..7ad15abe5 --- /dev/null +++ b/src/docs/maintainers/repo-structure.md @@ -0,0 +1,104 @@ +# Repository structure + +Products own their source, native manifests, tests and packaging commands. Moon +orders cross-project tasks; Cargo, Bun, Gradle and SwiftPM retain their native +dependency and build semantics. + +## Current tree + +```text +/ + Cargo.toml, Cargo.lock + package.json, bun.lock, bunfig.toml + Package.swift + .moon/, .github/ + src/runtimes/ + liboliphaunt-native/ + liboliphaunt-wasix/ + liboliphaunt-wasix-postmaster/ + executor/ + wasmer/ + wasix-browser-host/ + src/sdks/ + ts/{sdk,node-addon}/ + ts-wasix/{sdk,node-addon}/ + rust/{sdk,liboliphaunt-native}/ + rust-wasix/ + ts-query/ + rust-query/ + swift/ + kotlin/ + react-native/ + src/broker/ + src/extensions/ + src/third-party/{postgres,icu,openssl,tools}/ + src/docs/{src,content,public,architecture,maintainers,internal}/ + src/examples/ + src/benchmarks/ + src/database-resources/{contracts,icu,seeds,tools}/ + src/postgres-tools/{native,wasix}/ + src/pgwire-server/ + src/test-fixtures/ + tools/{dev,graph,packaging,policy,release,test}/ +``` + +Release metadata readers live in `tools/release`; reusable archive and package +utilities live in `tools/packaging`. Runtime, Swift and extension packaging +contracts live with their producers. ICU data and four selectable seed profiles belong to +`database-resources`; PostgreSQL utilities and the pgwire server have independent +product owners. Shared source acquisition lives in `src/third-party/tools`, upstream +pins and notices beside each dependency, and installer pins in `tools/dev`. +Product-specific pins stay with their runtime. New package identities remain +unreleased until their first successful public release. +The [implementation plan](../architecture/repository-simplification-plan.md) +tracks those remaining boundaries. + +## Product boundaries + +- `src/runtimes/liboliphaunt-native` owns the native C ABI, embedded PostgreSQL + implementation, patches and platform runtime production. +- `src/runtimes/liboliphaunt-wasix` owns the single-backend WASIX runtime and its + portable/AOT carriers. `liboliphaunt-wasix-postmaster` owns the separate + concurrent postmaster product, executor and patched Wasmer host. +- `src/runtimes/wasix-browser-host` is a Rust/WASM execution-host build project + consumed by the WASIX TypeScript SDK; it is not another SDK. +- `src/sdks/rust/liboliphaunt-native` is the `liboliphaunt-native-bindings` Cargo + package. It owns Rust ABI loading, native sessions, runtime discovery and + database-root handling. The public Rust SDK and broker consume this package. +- `src/sdks/rust/sdk` is the `oliphaunt` public SDK. `broker` owns the process + helper, IPC service/client library and broker carriers. The broker does not + depend on the public SDK. +- `src/sdks/ts/sdk` and `src/sdks/ts-wasix/sdk` are the two TypeScript SDKs. + Their sibling `node-addon` projects own native Node-API artifacts. Browser + consumers use the WASIX SDK rather than a separate browser package. +- `src/sdks/rust-wasix` is the ordinary Cargo package for the WASIX SDK; its + former outer wrapper has been merged into the package. +- `src/sdks/ts-query` and `src/sdks/rust-query` are shared query packages with + explicit package dependencies. They are not copied private source trees. +- Swift, Kotlin and React Native keep their package-native APIs and mobile + integration. React Native's platform adapters consume the Swift/Kotlin SDKs. +- `extensions` owns contrib/external extension definitions, builds, carriers + and behavior tests. Contrib carriers follow their runtime release owners; + external extensions retain their own release identities. +- `docs` contains the public site and maintainer documentation. Public + guides describe latest behavior and use completed public release versions. + There are no documentation-version archives or SDK API-generation builds. + +Grouping directories such as `src/sdks/ts` and `src/sdks/rust` have no package +manifest. Root Cargo/Bun lockfiles belong to their workspaces. The root +`Package.swift` remains the public Swift tag entrypoint; the development +package lives in `src/sdks/swift`. + +## Working in a product + +Use the product README and native manifest for commands, and its `moon.yml` +for dependency ordering and affected-task selection. Tests live beside the +behavior they exercise. Cross-product fixture data remains shared only where +multiple real consumers need it. Generated output, fetched upstream trees, +registry staging and build caches belong in ignored output directories. + +See [tooling](tooling.md) for the task contract, +[development](development.md) for local commands and +[release](release.md) for publication. Historical investigation records remain +under `architecture` and `internal`; they describe their recorded source +state rather than acting as current path aliases. diff --git a/src/docs/maintainers/repository-docs.md b/src/docs/maintainers/repository-docs.md new file mode 100644 index 000000000..810c2c9d6 --- /dev/null +++ b/src/docs/maintainers/repository-docs.md @@ -0,0 +1,11 @@ +# Repository Docs + +The docs project contains both the public site and repository documentation. +Public SDK guides live under `src/docs/content/sdk`. Product roots keep +package README/CHANGELOG files and source-adjacent API comments. + +- [`../architecture/`](../architecture/): design rationale and product-boundary decisions. The status + banner in each investigation determines whether it is current or historical. +- [Maintainer index](README.md): repository, tooling, release, testing, and benchmark process. +- [`../internal/`](../internal/): archived progress notes, audits, and implementation history. + These files are non-normative; start with the maintainer index. diff --git a/docs/maintainers/rust-sdk-policy.md b/src/docs/maintainers/rust-sdk-policy.md similarity index 82% rename from docs/maintainers/rust-sdk-policy.md rename to src/docs/maintainers/rust-sdk-policy.md index 7ef9edb83..0df5f5f04 100644 --- a/docs/maintainers/rust-sdk-policy.md +++ b/src/docs/maintainers/rust-sdk-policy.md @@ -7,24 +7,20 @@ exact extension artifact selection, cluster-seed hydration, and language-native errors. `liboliphaunt` remains the compiled direct/broker boundary. -The public crate stays application focused. Native resource construction, -extension artifact/index creation and signing, package size reporting, and -release-policy generation belong to the unpublished workspace crate -`oliphaunt-native-packaging`, not to `oliphaunt`. - -That workspace tool enables `internal-native-packaging` and consumes the -version-locked `oliphaunt::__private::packaging` seam. The seam is absent from -default builds, is inventoried separately, and may change only together with -the unpublished tool; its symbols are not application API. - -The separately built, unpublished `oliphaunt-broker` executable consumes one -exact-version internal seam. It enables the non-default -`__internal-broker-helper` feature and accesses `oliphaunt::__private`; the -module is absent from default builds, is not application API, and may change -only in lockstep with that executable. Keeping the seam in-process avoids an -extra owner-thread hop inside the process whose sole job is to own PostgreSQL. -Its symbols are still listed separately in the generated API inventory so a -review cannot accidentally widen it. +The public crate stays application focused. Selectable seeds and ICU data are +produced by `database-resources`; extension products own extension carriers. +The remaining private `oliphaunt-native-packaging` tool composes mobile runtime +and static-extension resources. It depends directly on +`liboliphaunt-native-bindings` with `internal-native-packaging`, without exposing +a packaging feature or private packaging API through the public SDK. + +`src/broker/` now owns the independently versioned `oliphaunt-broker` library and +executable. Both the broker and the native SDK depend on +`liboliphaunt-native-bindings` in `src/sdks/rust/liboliphaunt-native`; the broker no +longer reaches back into a private SDK broker feature. SQL and cancellation use +PostgreSQL wire framing. Backup and shutdown use a separate authenticated +management connection. Swift and Kotlin reach the same native implementation +through the private `src/sdks/rust/mobile-bindings` UniFFI adapter. Current public concepts are: @@ -36,6 +32,8 @@ Current public concepts are: - a fluent `Sql` statement builder, typed query/command results, raw protocol, callback transactions without transaction-level raw protocol, root `CancelHandle` or async-handle cancellation, and close; +- explicit optional seed and ICU-data inputs; reopening an existing database + does not require an initialization seed; - one physical backup for direct and broker, plus static restore into a new or empty destination; and - dedicated synchronous and asynchronous server builders whose handles expose @@ -74,7 +72,8 @@ different execution owners: - blocking native `Oliphaunt` is `Send` but not `Sync`; blocking WASIX `Oliphaunt` is neither `Send` nor `Sync`; -- blocking `OliphauntServer` is `Send` but not `Sync` in both products; +- blocking `OliphauntServer` is `Send` but not `Sync`; the WASIX endpoint now + belongs to the separate `oliphaunt-pgwire-server` package; - `AsyncOliphaunt` and `AsyncOliphauntServer` are cloneable, `Send + Sync` owner handles; and - `AsyncTransaction` is `Send` but not `Sync`, and its operations require @@ -145,18 +144,15 @@ enums, tuning profiles, background lifecycle modes, or replacement switches. Unsupported operations return a direct mode-specific error. Fixed support is documented in the shared parity matrix. -Internal packaging commands use the workspace tool explicitly, for example: - -```sh -cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources -- ... -cargo run -p oliphaunt-native-packaging --bin oliphaunt-extension-artifact -- ... -cargo run -p oliphaunt-native-packaging --bin oliphaunt-extension-index -- ... -``` +The unpublished native packaging crate assembles local runtime and extension +resources for mobile producers through `oliphaunt-resources`. It depends on the +shared native bindings directly. Use `database-resources` tasks for selectable +seed/ICU assets and extension owner tasks for release artifacts. Validate the application crate with: ```sh -moon run oliphaunt-rust:compile -moon run oliphaunt-rust:unit +moon run oliphaunt-rust:build +moon run oliphaunt-rust:test moon run oliphaunt-rust:package ``` diff --git a/src/docs/maintainers/sdk-api-surface.md b/src/docs/maintainers/sdk-api-surface.md new file mode 100644 index 000000000..66f1ebd8d --- /dev/null +++ b/src/docs/maintainers/sdk-api-surface.md @@ -0,0 +1,23 @@ +# SDK API references + +Each SDK's source declarations and package documentation define its public API. +Compiler checks, protocol tests, and clean package consumers validate those APIs. +There is no separately maintained source parser or generated symbol-list gate. + +| Product | Reference | +| --- | --- | +| Native C ABI | [Canonical header](../../runtimes/liboliphaunt-native/include/oliphaunt.h) | +| Rust SDK | [SDK guide](../../sdks/rust/sdk/README.md); `cargo doc -p oliphaunt --no-deps --open` | +| Rust build support | [Build crate guide](../../sdks/rust/sdk/crates/oliphaunt-build/README.md) | +| TypeScript SDK | [SDK guide](../../sdks/ts/sdk/README.md) | +| Swift SDK | [SDK guide](../../sdks/swift/README.md) | +| Kotlin SDK and Gradle plugin | [SDK guide](../../sdks/kotlin/README.md) | +| React Native SDK and Expo plugin | [SDK guide](../../sdks/react-native/README.md) | +| WASIX Rust binding | [Binding guide](../../sdks/rust-wasix/README.md) | +| WASIX TypeScript binding | [Binding guide](../../sdks/ts-wasix/sdk/README.md) | +| WASIX logical tools | [Tools guide](../../postgres-tools/wasix/ts/README.md) | + +Run the affected project's `build`, `test`, and `package` tasks when changing +its API, plus the relevant installed-consumer or runtime test. Package producers +copy the canonical C header into distributables; consumer compilation and +package checks exercise that boundary. There is no separate header-layout gate. diff --git a/docs/maintainers/sdk-parity-policy.md b/src/docs/maintainers/sdk-parity-policy.md similarity index 96% rename from docs/maintainers/sdk-parity-policy.md rename to src/docs/maintainers/sdk-parity-policy.md index ed4c5645c..b2d9bb933 100644 --- a/docs/maintainers/sdk-parity-policy.md +++ b/src/docs/maintainers/sdk-parity-policy.md @@ -125,14 +125,14 @@ These are language-native deltas, not parity failures: support product directly. It may evolve only in lockstep with the carrier products that consume it. The public `COliphaunt` product is governed by the documented C ABI contract rather than the Swift application API. -- Native Rust's non-default `__internal-broker-helper` feature similarly exposes - `oliphaunt::__private` only to the exact-version, unpublished - `oliphaunt-broker` executable. It is absent from normal builds, is inventoried - separately, and is not part of the stable application contract. +- The native broker is an independent library and executable built on the + shared native binding. The SDK depends on it; the broker does not import a + private SDK feature. SQL uses PostgreSQL wire messages, with lifecycle and + physical-resource operations on the separate control boundary. - Native tools are endpoint-oriented optional products. `oliphaunt-tools` and `@oliphaunt/tools` accept a PostgreSQL connection string and do not become dependencies or methods of the embedded database SDKs. -- Server handles in native/WASIX Rust, desktop TypeScript, and WASIX TypeScript +- Server handles in native Rust, `pgwire-server`, desktop TypeScript, and WASIX TypeScript own only the process/listener, connection string, and lifecycle. Applications use an ordinary PostgreSQL ORM, driver, or tool for SQL, transactions, and connection lifecycle; a server handle never controls independent client @@ -266,18 +266,13 @@ rows below are likewise not hidden modes or partly supported capabilities. ## Review and release rule A public SDK change is complete when all affected language surfaces, C/header -copies, generated API inventory, docs route, package shape, and behavioral tests +copies, authored documentation, package shape, and behavioral tests agree. A deliberate delta must appear above with current behavior. A new idea needs a concrete cross-runtime contract and executable evidence; only the repository-enforced deferrals listed above require one of their existing exact IDs. -The lightweight contract checks are: - -```sh -moon run sdk-contracts:all -moon run extensions:lint -``` - -Product-owned compile, package, smoke, and release tasks remain the authority -for executable behavior. +Product-owned build, test, package, and consumer tasks are the authority for +executable behavior. The runtime owns the canonical C header; carrier producers +copy it and real consumers compile against it. There is no separate header +layout gate or generated documentation inventory to maintain. diff --git a/src/docs/maintainers/sdk-products-policy.md b/src/docs/maintainers/sdk-products-policy.md new file mode 100644 index 000000000..08a476420 --- /dev/null +++ b/src/docs/maintainers/sdk-products-policy.md @@ -0,0 +1,161 @@ +# SDK Products + +SDK source lives under `src/sdks/`, with language manifests and local build/test +entrypoints. This document describes the development checkout; newly introduced +carriers and bindings are not assumed to be publicly released. + +These are product SDKs, not auxiliary bindings. Native Rust, Rust WASIX, Swift, +Kotlin, React Native, native TypeScript, and WASIX TypeScript should expose the +same product concepts where the target platform can do so honestly: + +- Native Rust is the SDK for Tauri and Rust desktop apps using `liboliphaunt`. +- Rust WASIX is the portable/AOT SDK for Tauri and Rust desktop apps that embed + the WASIX runtime. +- Swift is the SDK for iOS and macOS apps. +- Kotlin is the SDK for Android apps. Only the Android AAR, Gradle plugin and + marker, and declared Android ABI carriers are public release surfaces. +- React Native is the TypeScript/TurboModule SDK over the Swift and Kotlin SDKs. +- TypeScript is the SDK for Node.js, Bun, and Deno. Tauri apps use the Rust SDK + behind narrow app-owned commands. +- WASIX TypeScript is the SDK for browser, Node.js, Bun, Deno, and Electron + applications. Browser root is caller-owned; the native-host root uses a Rust actor, + with explicit `/direct` and package-Worker placements. + +`tools/release/sdk-manifest.toml` records the SDK inventory. The documentation +site does not build SDK API references. Product dependencies and release identities live in each product's +Moon and package manifests. Product tests and package checks verify runtime +delegation and consumer behavior. + +- `src/sdks/rust/sdk/`: canonical native Rust SDK for Tauri and Rust desktop apps. +- `src/sdks/rust-wasix/`: Rust SDK over the portable + and host-AOT `liboliphaunt-wasix` runtime products. +- `src/sdks/ts-wasix/sdk/`: TypeScript SDK over the browser portable WASIX + carrier and the Node/Bun/Deno/Electron Rust Node-API carrier. Its native-host root + uses a Rust owner actor, `/direct` opts into caller-realm execution, and + `/worker` owns a JavaScript Worker on every runtime. Optional `pg_dump` and + `psql` belong to `src/postgres-tools/wasix`, including its TypeScript facade in + `src/postgres-tools/wasix/ts`. Portable and AOT tool inputs are supplied explicitly + to the adapter; the database addon does not embed the frontend tool payloads. +- `src/sdks/swift/`: Swift package with an actor-first `Oliphaunt` API, platform + resource composition, and generated UniFFI bindings to the shared Rust native + database implementation. +- `src/sdks/kotlin/`: Android SDK with a suspend-first common implementation, + JVM contract tests, and generated bindings to that same Rust implementation. Maven + publication is deliberately limited to the Android consumer surface. +- `src/sdks/react-native/`: React Native New Architecture package. Its product contract + is a typed TypeScript/TurboModule layer over the Swift and Kotlin SDKs, with + no independent database semantics. +- `src/sdks/ts/sdk/`: desktop JavaScript SDK for Node.js, Bun, and Deno. + Tauri apps expose narrow app-owned commands from the Rust SDK. Direct topology + is the default across supported JavaScript + runtimes; Node.js and Bun use the prebuilt Rust napi-rs addon. Deno retains its + nonblocking FFI adapter until the addon passes Worker teardown with queued + stream delivery; ordinary SQL success alone does not establish that parity. + TypeScript broker mode consumes the published `oliphaunt-broker` executable + and PostgreSQL wire protocol for SQL and cancellation. A separate authenticated + management connection owns backup and shutdown. App developers consume + verified release assets without building Rust locally. Runtime, addon, and + optional database resources have separate packages. + +`src/sdks/rust/liboliphaunt-native` owns native runtime loading and direct execution. +`src/sdks/rust/mobile-bindings` is the private UniFFI adapter consumed by Swift and +Kotlin. It does not own a second PostgreSQL runtime. `src/broker/` is an independent +process owner over the shared native implementation. `src/pgwire-server/` owns the +WASIX socket library and CLI. Browser host implementation and its Wasmer patches +live under `src/runtimes/wasix-browser-host`, outside the TypeScript SDK. + +The native Rust SDK is canonical for native mode and resource terminology; +Swift, Kotlin, React Native, and native TypeScript mirror it unless a platform +restriction is documented. Rust WASIX and WASIX TypeScript use the same raw +protocol, typed query, transaction, structured PostgreSQL error, backup, +restore, and exact-extension vocabulary where their runtime supports the +behavior honestly. PostgreSQL `CHECKPOINT` is explicit SQL through `execute`, +not a separate SDK method. Native-only process modes are not WASIX requirements. +React Native must not duplicate database runtime behavior: iOS calls flow +through `Oliphaunt`, and Android calls flow through the `oliphaunt` +`Oliphaunt` facade. +Unsupported product features are absent from an SDK unless +[`sdk-parity-policy.md`](sdk-parity-policy.md) explicitly documents a current +runtime error. Silent drift between SDKs is a release blocker. + +Validation is package-native: + +```sh +moon run oliphaunt-rust:build +moon run oliphaunt-wasix-rust:build +moon run oliphaunt-wasix-ts:typecheck +moon run oliphaunt-wasix-tools-ts:typecheck +moon run oliphaunt-swift:build +moon run oliphaunt-kotlin:format-check oliphaunt-kotlin:lint oliphaunt-kotlin:build +moon run oliphaunt-react-native:build +moon run oliphaunt-js:build +moon run extensions:lint +``` + +The Kotlin and React Native Android validation scripts opt into Gradle +configuration cache by default. Set `OLIPHAUNT_GRADLE_CONFIGURATION_CACHE=0` +when debugging Gradle task configuration itself. + +Source compilation and runtime integration are separate. Swift's +`test-native` and Kotlin's native binding tests require a real compatible native +library; the mobile packaging lanes additionally build the required Rust target +libraries. The canonical C header is copied by its consuming package producers +and compiled by those consumers, rather than checked by a separate header-copy +layout task. + +Initialization data belongs to the independently versioned `database-resources` +product. It provides native and WASIX seeds, each with standard and ICU profiles, +and one canonical ICU data family. Native seeds additionally bind their physical +target; Android and iOS use their explicitly produced datum64 variants. For +example, the owner commands are: + +```sh +moon run database-resources:package-icu +moon run database-resources:package-wasix +moon run database-resources:package-android +``` + +Extension selection is exact-name only. SDKs accept exact PostgreSQL extension +names; `vector` means only the SQL extension `vector`, and names like `core`, +`search`, or `geo` must not resolve to hidden extension sets. + +Select seed and ICU carriers explicitly. Browser creation of new storage needs +a seed; an existing database can reopen without one. Native desktop and native +WASIX hosts retain their supported `initdb` fallback. Writable PGDATA is separate +from immutable installed resources. Swift, Gradle, and the Expo plugin compose +the selected mobile carriers during the application build; ordinary applications +do not run the internal `oliphaunt-resources` maintainer CLI. + +For iOS and Android release artifacts, build runtime resources with +`--require-mobile-static-registry` once the selected extension modules have +platform static registry rows. Swift, Kotlin, and React Native reject requested +extensions whose packaged runtime advertises pending mobile registry work. +The platform resource build must also pass each linked registry module stem with +`--mobile-static-module `; the Rust runtime-resource CLI rejects stems +that are not selected by the runtime resources. Those stems are declarations for +validation; mobile-ready output includes +`oliphaunt/static-registry/oliphaunt_static_registry.c`, which exports +`liboliphaunt_selected_static_extensions`. Platform bridges discover that symbol +and register the returned rows through `oliphaunt_register_static_extensions` +before the first database open. +Every SDK consumes the resulting runtime resources through the same manifest +fields. Generated manifests record +`schema=oliphaunt-runtime-resources-v1`, per-package `layout`, +the full dependency-closed `selectedExtensions` domain, its exact +`creates-extension=true` subset in `extensions`, `runtimeFeatures`, and +`sharedPreloadLibraries`. Mobile manifests additionally bind the exact native +SQL-name domain in `mobileStaticRegistryRegistered` and its exact module stems +in `nativeModuleStems`; the static-registry manifest must agree. All domains +are sorted and duplicate-free. SDK resource-availability checks use +`selectedExtensions`, including for selected module-only extensions, so +SDK-bound artifacts can be audited independently of the local build path. +Swift and Kotlin reject unknown package layouts rather than silently accepting +stale app resources; React Native inherits those checks through the platform +SDKs. +The resource root also carries `package-size.tsv` for packaging and release +audits. It is maintainer evidence, not a database SDK API. + +Android packages the native C ABI library separately from runtime resources. +Pass a `jniLibs`-style directory with ABI subdirectories through +`-PoliphauntAndroidJniLibsDir=/path/to/jniLibs`; each packaged ABI must include +`liboliphaunt.so`. diff --git a/docs/maintainers/testing.md b/src/docs/maintainers/testing.md similarity index 77% rename from docs/maintainers/testing.md rename to src/docs/maintainers/testing.md index 24052cf42..953c81249 100644 --- a/docs/maintainers/testing.md +++ b/src/docs/maintainers/testing.md @@ -5,14 +5,14 @@ Status: normative testing policy. Last verified: 2026-07-28. Owner: repository m Oliphaunt is a polyglot product repo. Product-native tests stay in product-native test roots. Each SDK is validated with the same tools its consumers use: -- Rust SDK: `src/sdks/rust/tests/` -- Rust WASIX binding: `src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/` +- Rust SDK: `src/sdks/rust/sdk/tests/` +- Rust WASIX binding: `src/sdks/rust-wasix/tests/` - Swift SDK: `src/sdks/swift/Tests/` - Kotlin SDK: `src/sdks/kotlin/oliphaunt/src/commonTest/`, and `src/sdks/kotlin/oliphaunt/src/androidUnitTest/` - React Native package: `src/sdks/react-native/src/__tests__/` - Installed React Native app smoke and benchmark coverage: - `examples/react-native-expo/` + `src/examples/react-native-expo/` Use the tier model below when deciding whether a check belongs in PR fast feedback, affected integration, an explicit full manual run, release dry-run, or post-publish @@ -21,14 +21,16 @@ validation. - PR: Moon-affected `check` and `test` tasks, release intent, and the selected package, artifact, and E2E jobs. Measured `coverage` is an explicit local/manual lane; it is not part of the `Required` PR gate. -- Main: the PR gate plus selected runtime smokes and regressions for changed - products; a successful non-cancelled run emits the exact-SHA `Qualified` - release record. -- Full manual: full regressions, extension matrix, installed mobile app - smokes, lifecycle drills, and measured benchmark reports. +- Main: affected checks, builds, runtime tests, and selected E2E. This does not + currently emit a `Qualified` release record. +- Full manual: the complete selected source/runtime/package/E2E graph. Only + an exhaustive dispatch with all target selectors produces the exact-SHA + `Qualified` release record. Coverage and benchmarks remain optional. - Release: package-native dry-runs, artifact manifests, checksums, attestations, registry checks, exact-extension evidence, binary - compatibility-floor inspection, and selected regression/performance gates. + compatibility-floor inspection, and selected artifact behavior evidence. + Publication reuses qualified artifacts; it does not rebuild products or rerun + the release tooling's implementation tests. Merging a PR emits a `pull_request.closed` cancellation tombstone in the existing PR concurrency group. That event allocates no runners: the plan, @@ -59,7 +61,7 @@ result and therefore remain fail-closed for release evidence. Linux producer lanes prove compatibility twice. The format-independent ELF inspector rejects any `GLIBC` requirement above 2.38 or `GLIBCXX` requirement above 3.4.30, including objects inside static archives. The packaged dynamic -trees then run through `tools/release/check-linux-consumer-baseline.sh` in an +trees then run through `tools/packaging/check-linux-consumer-baseline.sh` in an immutable Fedora 39/glibc 2.38 container with no network, writable root, or Linux capabilities. The fixture is an ABI test appliance, not a supported-OS or security-lifecycle assertion. The broker is additionally built and started @@ -72,10 +74,10 @@ Cargo examples use crates.io dependencies pinned to the current Oliphaunt versio They do not commit nested lockfiles. Validate them with: ```sh -tools/dev/bun.sh tools/release/example-cargo-policy.mjs --check +tools/dev/bun.sh tools/release/example-cargo-policy.mts --check ``` -Cross-product behavior belongs in `docs/maintainers/sdk-parity-policy.md` and executable parity +Cross-product behavior belongs in `src/docs/maintainers/sdk-parity-policy.md` and executable parity checks. Do not centralize platform tests into a fake shared test harness when a native package manager, simulator, Gradle target, SwiftPM target, Cargo target, or React Native Codegen path is the actual consumer contract. @@ -90,26 +92,25 @@ fixtures are clearer and cheaper to maintain. Shared fixture domains are small, semantic contracts consumed by product-native tests or policy checks: -- `src/shared/fixtures/protocol/query-response-cases.json`: PostgreSQL backend-response +- `src/test-fixtures/protocol/query-response-cases.json`: PostgreSQL backend-response corpus consumed by Rust, Swift, Kotlin, React Native, TypeScript, and WASIX protocol tests. -- `src/shared/fixtures/postgres/behavior-contract.json`: common PostgreSQL +- `src/test-fixtures/postgres/behavior-contract.json`: common PostgreSQL behavior cases that are meaningful in more than one SDK. -- `src/shared/fixtures/storage/database-root.json`: the exact five-field +- `src/test-fixtures/storage/database-root.json`: the exact five-field managed-root descriptor cases consumed by native and WASIX validators. -- `src/shared/fixtures/storage/physical-archive-native-v1.properties` and +- `src/runtimes/liboliphaunt-native/smoke/fixtures/physical-archive-native-v1.properties` and `physical-archive-wasix-v1.properties`: exact physical archive identities consumed by the runtime-family backup and restore tests. -- `src/shared/fixtures/storage/physical-backup-wal-range-v1.properties`: exact +- `src/test-fixtures/storage/physical-backup-wal-range-v1.properties`: exact inclusive WAL segment-range vectors consumed by native and both WASIX online backup implementations, including non-default segment size arithmetic. -`bun tools/policy/check-shared-fixtures.mjs` validates the manifest and rejects -byte-for-byte source copies outside the canonical fixture root. Published -source packages receive any required standalone copies only in their generated -staging directories. +Product tests consume these shared fixtures through the actual protocol and +archive implementations. Published source packages receive required standalone +copies in their staging directories. Reusable benchmark datasets, benchmark plans, and published reports belong in -`benchmarks/`. Executable benchmark harnesses belong in `tools/perf/` unless +`src/benchmarks/`. Executable benchmark harnesses belong in `src/benchmarks/perf/` unless the harness is intentionally part of a product's public developer API. ## Moon Tasks @@ -124,7 +125,7 @@ Moon task names are intentionally narrow: regression suites. - `perf-tools:*-plan`: benchmark plan/report validation only. - `perf-tools:*-measure`: measured benchmark execution. -- `coverage-tools:`: runs product-native measured line coverage and writes +- `:coverage`: runs product-native measured line coverage and writes machine-readable reports under `target/coverage//`. `check` and `test` must not call the same command for SDK products. `test` @@ -144,9 +145,8 @@ artifacts cannot be built or located. React Native installed-app smoke is split by platform: ```sh -moon run oliphaunt-react-native:smoke-android -moon run oliphaunt-react-native:smoke-ios -moon run oliphaunt-react-native:smoke +moon run integration-examples:react-native-android-e2e +moon run integration-examples:react-native-ios-e2e ``` PR jobs run RN static, unit, Codegen, JSI, config-plugin, and package checks. @@ -165,23 +165,14 @@ files, app artifacts, runner behavior, and CI logs for the selected Maestro lanes; it does not revisit provider selection. `tools/dev/setup-maestro.sh` installs only the exact versioned release asset and -SHA-256 recorded in `src/sources/toolchains/maestro.toml`; that manifest is the +SHA-256 recorded in `tools/dev/maestro.toml`; that manifest is the single release pin. It does not execute the vendor's network installer. Version upgrades change the reviewed manifest metadata and must keep the staged archive/layout/version and atomic-promotion regression tests green; incomplete or inconsistent metadata fails before any download. -The Node direct addon likewise treats `src/sources/toolchains/node.toml` as the -single source for fallback header and Windows import-library release metadata. -`package-node-direct-runtime.sh` continues to prefer an explicit or installed local header -or `node.lib` candidate. Only a missing candidate activates the fallback, which -then requires the manifest's exact Node runtime, HTTPS-only bounded transfer, -SHA-256 verification, safe staged header extraction, and atomic cache promotion. -The fault suite covers invalid metadata, corrupt caches, unsafe or truncated -archives, transport interruption, checksum failure, and promotion rollback. -Node upgrades update that manifest's reviewed digests together with -`.prototools` and each CI `NODE_VERSION`; source-toolchain policy rejects any -runtime/manifest drift before a release build. +The native Node addon uses the Rust Node-API adapter. It no longer downloads +Node C headers or a separate Windows import library through a custom fallback. Prior provider research is historical context, not a standing checklist. Maestro pin upgrades are dependency maintenance; they do not reopen the runner decision @@ -201,11 +192,11 @@ the failure proves a concrete requirement this model cannot satisfy. Coverage is measured evidence, not a policy-only check. Product tasks run the native reporter for their ecosystem: `cargo-llvm-cov` for Rust and WASIX library coverage, `swift test --enable-code-coverage` for Swift, Kover for Kotlin, and -Vitest V8 coverage for TypeScript and React Native TypeScript code. Each product writes -`target/coverage//summary.json` plus its native report formats, and -The local-only `moon run repo:coverage` aggregate writes those summaries to -`target/coverage/summary.json` and `target/coverage/summary.md`; hosted CI owns -each product threshold directly and does not rerun the aggregate dependency tree. +Vitest V8 coverage for TypeScript and React Native TypeScript code. Run +`moon run :coverage` for that product's native reports under +`target/coverage//`. There is no repository coverage aggregate or +shared summary-file contract. Coverage is an explicit measurement, separate from +the required source-test and release gates. Rust and WASIX executable unit tests run through `cargo nextest` with the `ci` profile. Unit lanes still run doctests through `cargo test --doc` because @@ -226,21 +217,13 @@ Native native adapter compile checks, Codegen checks, Expo prebuild/app wiring, and installed-device smokes remain separate package or runtime lanes; Vitest coverage is only evidence for TypeScript API/config/JSI contract code. -`coverage/baseline.toml` records product-owned `source_globs`, precise -`exclude_globs`, explicit waivers, the blocking aggregate gate, and a visible -per-file warning threshold. Every owned source file must be measured or waived with a reason and -replacement evidence; every waiver also carries an owner and expiry/review -horizon. Generated code, vendored code, PostgreSQL sources, native build -outputs, package `lib/` output, Gradle build directories, Xcode DerivedData, -and Codegen output are excluded from SDK wrapper coverage gates. -The aggregate floor is 80 percent for SDK wrapper code. A file below 50 percent -emits a CI warning, including the current `storage.rs` result, without weakening -the aggregate gate or the requirement for complete, valid coverage evidence. -Actual measurements are published as CI artifacts rather than committed snapshots. -Use `moon run repo:coverage-policy` when you only need to validate the -coverage policy shape. - -The root coverage commands are: +Coverage is an optional product-owned diagnostic. Each SDK invokes its native +coverage tool directly; normal CI runs its unit tasks once. Reports remain under +`target/coverage//`. There is no cross-language percentage gate, source +scanner, waiver ledger, or second test execution layer. + +Run coverage for one product with `moon run :coverage`. To select all +product coverage tasks (requiring their respective toolchains): ```sh moon run :coverage @@ -249,6 +232,14 @@ moon run :coverage --affected ## WASIX Runtime Tests +Extension lifecycle qualification tests physical backup/restore, reopening the +restored database and verifying existing extension state without rerunning setup. +Logical `pg_dump`/`psql` tests are separate and prove only their tested fixtures. +In particular, pinned pg_ivm 1.13 does not preserve incremental-view maintenance +through a plain logical dump/restore: use physical backup/restore for those +databases. Upstream introduced metadata export and `restore_immv` in pg_ivm 1.15; +adopting that release requires the normal extension source and platform qualification. + `oliphaunt-wasix` is intended for tests that need real Postgres semantics without Docker. @@ -283,7 +274,7 @@ Use `OliphauntServer` when the application already talks to Postgres through a client library: ```rust,no_run -use oliphaunt_wasix::AsyncOliphauntServer; +use oliphaunt_pgwire_server::AsyncOliphauntServer; use sqlx::{Connection, Row}; #[tokio::test] @@ -367,10 +358,10 @@ Use logical dumps, not physical archives, when you need a portable export. ## Cross-Language Clients -Use `oliphaunt-wasix-proxy` when the test process lives outside Rust: +Use `oliphaunt-pgwire-server` when the test process lives outside Rust: ```sh -oliphaunt-wasix-proxy --memory --print-uri +oliphaunt-pgwire-server --memory --print-uri ``` Pass the printed URI to Python `psycopg`, Go `pgx`, Node `pg`, or another diff --git a/src/docs/maintainers/tooling.md b/src/docs/maintainers/tooling.md new file mode 100644 index 000000000..225de5bdc --- /dev/null +++ b/src/docs/maintainers/tooling.md @@ -0,0 +1,152 @@ +# Tooling + +Moon owns the project graph, affected task selection, task ordering, and output +caching. Cargo, Bun, Gradle, and SwiftPM own their package dependencies. +Product versions and compatibility requirements live in product manifests. +There is no second repository build scheduler. + +## Local commands and ownership + +Put build, lint, test, and package commands in the product's native manifest or +local Shell script. Its `moon.yml` orders and caches those commands; it should +not be the only place an ordinary compilation recipe exists. Shared runtime, +ABI, shared query, and fixture dependencies belong in the graph when the product +actually consumes them; unrelated platforms must not hold up one another's tests. + +Use Shell for external commands and TypeScript for data processing. Committed +JavaScript and Python implementations are not maintained. Generated JavaScript +inside npm packages remains part of those packages' supported interface. +Native Rust/C helpers remain where they execute WASM, serialize AOT artifacts, +or provide operating-system operations unavailable in the scripting runtime. + +Task names describe the result, not a compulsory sequence: + +| Task | Contract | Prerequisites | +| --- | --- | --- | +| `format-check` | Read-only formatting diagnostics | Source and formatter | +| `lint` | Source diagnostics | Source and language tools; compiler analysis is allowed | +| `typecheck` | Compiler/type diagnostics without a distributable artifact | Required dependency interfaces | +| `build` | Compile or generate usable product outputs | Builds of dependencies actually consumed | +| `test` | Source behavior and unit tests | The ecosystem's test runner may compile its test targets | +| `check` | An explicitly declared aggregate of source checks and isolated tests | Its listed source tasks; no platform release promise | +| `package` | Produce and inspect the distributable | Required build outputs; no implicit full source-test gate | +| `test-integration` | Behavior against a real runtime or dependency | The runtime and inputs actually exercised | +| `test-consumer` | Install or compile the produced package outside the source workspace | The actual package and dependency closure | +| `test-browser` / platform tests | Browser or device behavior | The named platform and required artifacts | +| `test-packaging` | Isolated packaging behavior | Artifact fixtures; an installed consumer remains a separate proof | +| `coverage` / benchmarks | Optional measurement | The suite or runtime being measured | + +Use a suffix when it identifies a real boundary, such as `smoke-android`, +`smoke-ios`, `lint-codegen`, or `rust-lint` in a mixed-language package. +Do not add empty tasks to make every ecosystem expose every name. In particular, +`cargo test`, `swift test`, and Gradle tests already compile what they need; +they should not depend on a second, standalone `build` merely to enforce a tier. +Native lifecycle names remain native: Gradle's `build` normally combines +assembly and checking; use its compilation/assembly tasks for the Moon `build` +phase. Do not override Gradle's lifecycle just to match the table. + +Optional prek hooks run cheap file checks and validate commit messages. Formatting +belongs to the owning project's `format` and `format-check` tasks; editing an +unrelated TOML file does not run formatting across the Rust workspace. + +The old product `qualify` aliases were removed: some meant source checks, +others included a native runtime or packaging, and none certified publication. +The hosted `Qualified` artifact is a separate release protocol, described below. + +Useful commands from the repository root: + +```sh +moon query tasks --project +moon query affected --upstream none --downstream deep +moon run :format-check :lint :test +moon run :package +moon run :test-consumer --cache off +bash tools/ci/check-workflows.sh +bash tools/dev/install-hooks.sh +``` + +Choose explicit owner targets from the affected graph and the product's task +list. CI selects source checks through task tags; local commands above name the +checks to run. Use a host with the required capabilities. Package and +installed-consumer checks must exercise their artifact; source-text assertions +cannot substitute for them. + +The ordinary package manager commands also remain available, such as +`cargo test -p `, `cargo clippy -p --all-targets`, and each +SDK's documented Bun, Gradle, or SwiftPM commands. For an unreleased crate, +`cargo semver-checks` needs an explicit `--baseline-rev `; a registry +baseline exists only after publication. + +For TypeScript, use `moon run oliphaunt-js:build` (or the corresponding WASIX/RN product) to build its declared query dependency first. A local `bun run build` runs the package's own recipe. Bun workspaces declare package dependencies; Moon orders cross-project tasks. An ordinary TypeScript edit does not require building PostgreSQL. + +Build dependencies and release propagation are different. A published dependency +can retain its existing compatible version. A private library copied or compiled +into several products must make every embedding product release-affected. A +shared test fixture must rerun its consumer tests without forcing a release. +The current release planner does not yet implement every one of these cases; +moving a directory or adding a Moon edge alone does not fix version propagation. + +## Toolchain and cache inputs + +Toolchain pins and platform archive checksums live under `tools/dev`. +GitHub setup actions use the local Shell installers. Use the pinned Moon and +Bun versions when reproducing CI; arbitrary globally installed versions can +behave differently. + +A cached task must declare every input that affects its output. Cache completed +build outputs as well as compiler objects where source, toolchain, flags, and ABI +identity establish safe reuse. A version label alone does not establish that +identity. Do not cache a live device, process-recovery, or benchmark measurement +as if it proved the current runner's state. + +Root Cargo package owners carry the `cargo-package` tag. Their internal +`cargo-sources` task runs no command: it hashes local source and the same node +in declared dependencies. Compiler tasks depend on this hash, so a transitive +library edit invalidates consumers without running a duplicate Cargo build. +Formatting stays local. Extend the owner's `cargo-sources` file group when its +crate compiles source outside `src`; do not repeat dependency directory lists +in each consumer. Cross-language consumers also depend on this source hash when +their required binary producer cannot be cached safely. Affected selection must +traverse task dependents deeply to preserve these transitive relationships. + +Postmaster binds prepared upstream checkouts to pinned commits, patches, and +executor source. Its build receipts additionally bind compiler and build +recipes. A build-script change must not force reapplying unchanged upstream +patches. Standalone tests are outside the executor source identity. + +## Release and qualification + +Ordinary execution delegates dependency ordering and parallelism to Moon. +Downloaded CI artifacts require a narrower path: Moon 2.5.4 with `--upstream none` +does not preserve edges even between explicitly selected tasks. A disposable +workspace probe on 2026-09-11 ran a consumer before its delayed producer wrote +its artifact; the consumer also ran when that producer was configured to fail. +Without the flag, Moon ordered them correctly, ran an independent task in +parallel, and withheld the consumer after producer failure. Consequently, CI +handoffs first run local prerequisites normally, then run selected roots in +dependency order with upstream traversal disabled. This fallback prevents +rebuilding downloaded producers; it is only used for transferred artifacts. + +Release Please prepares independently selected product versions and changelogs. +The protected Release workflow prepares or publishes a candidate. Its internal +steps freeze and qualify package bytes, perform necessary first-publication +setup, submit missing packages, and verify publication. Retries reconcile exact +bytes; they must not silently replace an existing version with different bytes. +See [the release guide](release.md) for the maintained commands and recovery flow. + +Currently, only an exhaustive manual CI dispatch can produce `Qualified`; an +affected PR or main push cannot. The record is bound to that exact SHA and +same-run artifacts. Publication consumes those artifacts without rebuilding +them. Product-scoped qualification requires changing the planner, evidence +record, verifier, and workflow together; deleting unrelated workflow jobs alone +would leave an invalid release contract. + +Run affected product checks before expensive platform builds. Checks of archive +safety, ABI compatibility, package installation, transaction recovery, and +immutable publication protect real boundaries. Source-spelling, repository +layout, fixture-content duplication, and generated symbol-list gates do not +replace those checks. + +Optional performance measurements use the native workloads described in +[performance evidence](performance-evidence.md). They retain raw results and +input identities and are separate from release qualification. diff --git a/docs/maintainers/wasix-postmaster.md b/src/docs/maintainers/wasix-postmaster.md similarity index 89% rename from docs/maintainers/wasix-postmaster.md rename to src/docs/maintainers/wasix-postmaster.md index 4a131177c..09029b55d 100644 --- a/docs/maintainers/wasix-postmaster.md +++ b/src/docs/maintainers/wasix-postmaster.md @@ -56,8 +56,9 @@ must not consume the single-backend-only patches that disable workers or guest process creation. Algorithmic optimizations can be shared when their guards and semantics are -topology-neutral. `postgres/main-optimizations.series` references those -canonical decisions. Postmaster-specific patches cover POSIX dynamic shared +topology-neutral. The complete ordered `postgres/series` references shared +patches in `src/third-party/postgres/patches/wasix` and product-owned patches. +Postmaster-specific patches cover POSIX dynamic shared memory, EXEC_BACKEND handoff, process join reliability, packed latch ordering, and other concurrency contracts. Every local patch must be explained by `postgres/product-patch-provenance.toml`; experiment disposition files are not @@ -92,7 +93,7 @@ build job and its output is tied to: - the exact installed guest closure. The complete loadable side-module closure is declared once in -`runtime/policies/sealed-side-modules.v1.tsv`. The builder, guest provenance, +`wasmer/policies/sealed-side-modules.v1.tsv`. The builder, guest provenance, linear-memory receipt, manifest, test fixture, and independent verifier all consume that policy. Do not reintroduce a hard-coded shortlist in any of those layers. Aliases are regular byte-identical carrier files because sealed path @@ -197,13 +198,19 @@ Windows x64 is present in the CI matrix as an explicit planned no-op. It does not build or publish an asset until its runtime, memory-mapping, packaging, and lifecycle contracts are implemented and qualified. -Linux admits direct carrier mappings only after immutable-inode deployment and -qualifies every server tree under finite cgroup-v2 memory controls. macOS has -neither primitive, so it copies verified AOT and preinitialized-memory bytes -into runtime-owned private backing. Its loader audit must account for the exact -copy, hash every mapped byte, perform no carrier-source writes or sync calls, -and retain no mutable carrier mapping. These are platform-specific mechanisms -for the same sealed-carrier integrity contract, not a weaker unqualified mode. +Ordinary build and recovery qualification runs without privilege escalation. +Linux uses verified private reflink or streamed snapshots when the carrier is +not already immutable; macOS uses streamed copies. The loader audit accounts +for the selected mechanism, hashes every mapped byte, and rejects carrier-source +writes or sync calls. No mutable carrier mapping is retained. + +Linux also supports direct mappings from immutable inodes or a supported read-only +filesystem. Testing immutable-inode deployment requires a separately provisioned +carrier: pass its `--immutable-carrier-receipt` and finite `--cgroup-memory-max`, +`--cgroup-memory-high`, and `--cgroup-swap-max` values to +`bin/qualify-release-carrier.sh`. That opt-in test verifies the immutable receipt, +direct activation, and cgroup membership. Product commands never acquire elevated +privileges themselves; ordinary release CI does not certify this deployment mode. Wasmer source portability alone does not make another target supported. @@ -234,14 +241,13 @@ The mandatory product boundary is: 4. build a carrier containing the full declared module closure; 5. independently verify the carrier; 6. run initdb, concurrent libpq sessions, regression subset, backend-wave - stress, and checkpoint/recovery on every target, plus immutable deployment - and cgroup checks on Linux; + stress, and checkpoint/recovery on every target using unprivileged activation; 7. package only the verified carrier from the exact release commit; 8. freeze it in the publication lock and verify the GitHub release assets. Generated checkouts, caches, reports, and measurement data remain under -`target/`. Benchmark harnesses belong under `tools/perf/` and durable benchmark -results under `benchmarks/`; neither belongs in the runtime product source. +`target/`. Benchmark harnesses belong under `src/benchmarks/perf/` and durable benchmark +results under `src/benchmarks/`; neither belongs in the runtime product source. ## Retired experimental machinery diff --git a/docs/maintainers/wasix-usage.md b/src/docs/maintainers/wasix-usage.md similarity index 91% rename from docs/maintainers/wasix-usage.md rename to src/docs/maintainers/wasix-usage.md index 83238ce13..4af42933f 100644 --- a/docs/maintainers/wasix-usage.md +++ b/src/docs/maintainers/wasix-usage.md @@ -36,13 +36,16 @@ The managed root contains `.oliphaunt.json` and `pgdata`. Runtime overlays and other mutable guest directories are SDK-owned state elsewhere. A host-directory owner prevents a second Rust open while the database is live. -Ordinary open initializes a new store from the packaged cluster seed. Tests or -tools that specifically need `initdb` invoke the packaged tool directly. +In the development checkout, ordinary Rust open initializes a new store with +initdb. Select `.seed(ClusterSeed::new(archive, manifest))` for a separately +produced seed, and `.icu_data(IcuData::new(data, manifest)?)` for canonical ICU. +Existing roots need no seed; ICU data remains necessary for ICU roots. Physical archives use the dedicated restore API. There is no legacy PGDATA-only restore path; nonempty descriptorless roots and incomplete stores fail without mutation. -`OliphauntServer::builder().start()` supplies a local PostgreSQL endpoint when +The separate `oliphaunt-pgwire-server` package +(`oliphaunt_pgwire_server::OliphauntServer::builder().start()`) supplies a local PostgreSQL endpoint when an existing Rust client needs one; the returned handle exposes only its connection string, closed state, and close. The parallel `AsyncOliphauntServer::builder().start().await` keeps lifecycle work off the @@ -70,6 +73,8 @@ and provide that runtime code again. ```ts import Oliphaunt from '@oliphaunt/wasix-ts'; +// Native hosts can initialize without a seed. New browser storage must pass +// seed: { archive, manifest } from the separate seed-wasix-standard carrier. await using database = await Oliphaunt.open(); const result = await database.query('select $1::int + 1 as answer', [41]); ``` @@ -188,10 +193,10 @@ already naturally portable. ```sh moon run oliphaunt-wasix-rust:package -moon run oliphaunt-wasix-rust:compile oliphaunt-wasix-rust:unit +moon run oliphaunt-wasix-rust:build oliphaunt-wasix-rust:test moon run oliphaunt-wasix-ts:package -moon run oliphaunt-wasix-ts:compile oliphaunt-wasix-ts:unit -moon run oliphaunt-wasix-tools-ts:qualify +moon run oliphaunt-wasix-ts:typecheck oliphaunt-wasix-ts:test +moon run oliphaunt-wasix-tools-ts:typecheck oliphaunt-wasix-tools-ts:test oliphaunt-wasix-tools-ts:package ``` Package tasks inspect carriers. Explicit artifact and smoke tasks own the diff --git a/docs/maintainers/windows-vc-runtime.md b/src/docs/maintainers/windows-vc-runtime.md similarity index 100% rename from docs/maintainers/windows-vc-runtime.md rename to src/docs/maintainers/windows-vc-runtime.md diff --git a/src/docs/moon.yml b/src/docs/moon.yml index f7b5a78f9..8e61e73b0 100644 --- a/src/docs/moon.yml +++ b/src/docs/moon.yml @@ -4,160 +4,62 @@ id: "docs" language: "typescript" layer: "application" stack: "frontend" -tags: ["docs", "fumadocs", "next", "public"] +tags: ["javascript-quality", "docs", "fumadocs", "next", "public"] dependsOn: - id: "extensions" scope: "build" project: title: "Oliphaunt Docs" - description: "Public documentation site, generated SDK matrices, tested snippets, and release-readiness docs gates." + description: "Latest public guides and completed product releases." owner: "oliphaunt" -owners: - defaultOwner: "@oliphaunt/docs" - paths: - "**/*.md": ["@oliphaunt/docs"] - "**/*.ts": ["@oliphaunt/docs"] - "**/*.tsx": ["@oliphaunt/docs"] - "docs-manifest.toml": ["@oliphaunt/docs"] - tasks: dev: - tags: ["dev"] - command: "pnpm --dir src/docs run dev" - inputs: - - "/docs/**/*" - - "/.release-please-manifest.json" - - "/release-please-config.json" - - "/src/**/release.toml" - - "**/*" - - project: "extensions" - group: "model" - - "/pnpm-lock.yaml" - - "/pnpm-workspace.yaml" + command: "bun run dev" options: cache: false - runFromWorkspaceRoot: true runInCI: false check: - tags: ["quality", "static"] - command: "pnpm --dir src/docs run check" + command: "bun run check" inputs: - - "/README.md" - - "/.release-please-manifest.json" - - "/docs/**/*" - - "/release-please-config.json" - - "/src/**/README.md" - - "/src/**/typedoc.json" - - "/src/sdks/**/package.json" - - "/src/bindings/**/package.json" - - "/src/sdks/**/Cargo.toml" - - "/src/bindings/**/Cargo.toml" - - "/src/sdks/**/Package.swift" - - "/src/sdks/**/build.gradle.kts" - - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h" - - "/src/sdks/rust/src/**/*" - - "/src/sdks/swift/Sources/**/*" - - "/src/sdks/kotlin/oliphaunt/src/commonMain/**/*" - - "/src/sdks/kotlin/oliphaunt/src/androidMain/**/*.kt" - - "/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/**/*" - - "/src/sdks/js/src/**/*" - - "/src/sdks/react-native/src/**/*" - - "/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/**/*" - - "/src/bindings/wasix-ts/src/**/*" - - "/src/**/release.toml" - "**/*" - - project: "extensions" - group: "model" - - "@group(pnpm-workspace)" + - "/src/extensions/generated/extensions.catalog.json" + - "/release-please-config.json" + - "/bun.lock" options: - cache: true - runFromWorkspaceRoot: true + cache: false + mutex: "docs-generated-files" + runInCI: false + test: + command: "bun run test" + inputs: + - "tools/published-products*" + - "tools/request-refresh*" + - "tools/verify-live*" + - "/bun.lock" build: - tags: ["build", "quality", "static"] - command: "pnpm --dir src/docs run build" + command: "bun run build" inputs: - - "/docs/**/*" - - "/.release-please-manifest.json" - - "/release-please-config.json" - - "/src/**/README.md" - - "/src/**/typedoc.json" - - "/src/sdks/**/package.json" - - "/src/bindings/**/package.json" - - "/src/sdks/**/Cargo.toml" - - "/src/bindings/**/Cargo.toml" - - "/src/sdks/**/Package.swift" - - "/src/sdks/**/build.gradle.kts" - - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h" - - "/src/sdks/rust/src/**/*" - - "/src/sdks/swift/Sources/**/*" - - "/src/sdks/kotlin/oliphaunt/src/commonMain/**/*" - - "/src/sdks/kotlin/oliphaunt/src/androidMain/**/*.kt" - - "/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/**/*" - - "/src/sdks/js/src/**/*" - - "/src/sdks/react-native/src/**/*" - - "/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/**/*" - - "/src/bindings/wasix-ts/src/**/*" - - "/src/**/release.toml" - "**/*" - - project: "extensions" - group: "model" - - "@group(pnpm-workspace)" + - "/src/extensions/generated/extensions.catalog.json" + - "/release-please-config.json" + - "/bun.lock" outputs: - "/target/docs/build/**/*" - "/target/docs/generated/routes.json" options: - cache: local - runFromWorkspaceRoot: true - smoke: - tags: ["quality", "runtime", "smoke"] - command: "pnpm --dir src/docs run smoke" + # Published release metadata must refresh even when source inputs are unchanged. + cache: false + mutex: "docs-generated-files" + test-package: + command: "bun run smoke" deps: - target: "docs:build" cacheStrategy: "outputs" inputs: - "/target/docs/build/**/*" - "/target/docs/generated/routes.json" - - "/src/docs/tools/smoke-built-site.mjs" - options: - cache: local - runFromWorkspaceRoot: true - qualify: - tags: ["release", "package"] - command: "pnpm --dir src/docs run release-check" - deps: - - target: "docs:build" - cacheStrategy: "outputs" - inputs: - - "/README.md" - - "/.release-please-manifest.json" - - "/docs/**/*" - - "/release-please-config.json" - - "/src/**/CHANGELOG.md" - - "/src/**/README.md" - - "/src/**/typedoc.json" - - "/src/sdks/**/package.json" - - "/src/bindings/**/package.json" - - "/src/sdks/**/Cargo.toml" - - "/src/bindings/**/Cargo.toml" - - "/src/sdks/**/Package.swift" - - "/src/sdks/**/build.gradle.kts" - - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h" - - "/src/sdks/rust/src/**/*" - - "/src/sdks/swift/Sources/**/*" - - "/src/sdks/kotlin/oliphaunt/src/commonMain/**/*" - - "/src/sdks/kotlin/oliphaunt/src/androidMain/**/*.kt" - - "/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/**/*" - - "/src/sdks/js/src/**/*" - - "/src/sdks/react-native/src/**/*" - - "/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/**/*" - - "/src/bindings/wasix-ts/src/**/*" - - "/src/**/release.toml" - - "**/*" - - project: "extensions" - group: "model" - - "@group(pnpm-workspace)" + - "tools/smoke-built-site.mts" options: - cache: local - runFromWorkspaceRoot: true + cache: false diff --git a/src/docs/next.config.mjs b/src/docs/next.config.mjs deleted file mode 100644 index 5b0acfd41..000000000 --- a/src/docs/next.config.mjs +++ /dev/null @@ -1,19 +0,0 @@ -import { createMDX } from 'fumadocs-mdx/next'; - -const withMDX = createMDX(); - -/** @type {import('next').NextConfig} */ -const config = { - output: 'export', - reactStrictMode: true, - trailingSlash: true, - images: { - unoptimized: true, - }, - experimental: { - optimizePackageImports: ['lucide-react', 'simple-icons'], - }, - basePath: process.env.OLIPHAUNT_DOCS_BASE_PATH || undefined, -}; - -export default withMDX(config); diff --git a/src/docs/next.config.ts b/src/docs/next.config.ts new file mode 100644 index 000000000..89273bcc4 --- /dev/null +++ b/src/docs/next.config.ts @@ -0,0 +1,19 @@ +import { createMDX } from 'fumadocs-mdx/next'; +import type { NextConfig } from 'next'; + +const withMDX = createMDX(); + +const config: NextConfig = { + output: 'export', + reactStrictMode: true, + trailingSlash: true, + images: { + unoptimized: true, + }, + experimental: { + optimizePackageImports: ['lucide-react', 'simple-icons'], + }, + basePath: process.env.OLIPHAUNT_DOCS_BASE_PATH || undefined, +}; + +export default withMDX(config); diff --git a/src/docs/package.json b/src/docs/package.json index 50454d032..4df0decda 100644 --- a/src/docs/package.json +++ b/src/docs/package.json @@ -3,24 +3,17 @@ "private": true, "version": "0.0.0", "scripts": { - "dev": "node tools/run-docs-task.mjs generate && next dev --hostname 127.0.0.1", - "generate": "node tools/run-docs-task.mjs generate", - "api-reference": "node tools/generate-api-reference.mjs --mode=release", - "api-reference:check": "pnpm run api-reference && node tools/check-docs-product.mjs --api-reference", - "check": "node tools/run-docs-task.mjs check", - "build": "node tools/run-docs-task.mjs build", - "smoke": "node tools/smoke-built-site.mjs", - "release-check": "node tools/run-docs-task.mjs release-check", - "start": "next start", - "types:check": "node tools/run-docs-task.mjs check", - "postinstall": "fumadocs-mdx", + "dev": "bun run generate && next dev --hostname 127.0.0.1", + "generate": "bun tools/generate-content.mts && fumadocs-mdx", + "check": "bun tools/check-docs-product.mts && next typegen && fumadocs-mdx && tsc --noEmit", + "build": "bun run generate && next build && bun tools/publish-next-export.mts", + "smoke": "bun tools/smoke-built-site.mts", "lint": "biome check", - "format": "biome format --write" + "format": "biome format --write", + "test": "bun test tools/published-products.test.mts tools/verify-live.test.mts && bash tools/request-refresh.test.sh" }, "dependencies": { "@mdx-js/react": "^3.1.0", - "@oliphaunt/react-native": "workspace:*", - "@oliphaunt/ts": "workspace:*", "clsx": "^2.1.1", "fumadocs-core": "16.9.3", "fumadocs-mdx": "15.0.10", @@ -31,11 +24,9 @@ "react": "19.2.7", "react-dom": "19.2.7", "simple-icons": "16.28.0", - "smol-toml": "^1.4.2", "tailwind-merge": "^3.6.0" }, "devDependencies": { - "@biomejs/biome": "^2.4.16", "@tailwindcss/postcss": "^4.3.0", "@types/mdx": "^2.0.13", "@types/node": "22.19.19", diff --git a/src/docs/postcss.config.json b/src/docs/postcss.config.json new file mode 100644 index 000000000..e092dc7c1 --- /dev/null +++ b/src/docs/postcss.config.json @@ -0,0 +1,5 @@ +{ + "plugins": { + "@tailwindcss/postcss": {} + } +} diff --git a/src/docs/postcss.config.mjs b/src/docs/postcss.config.mjs deleted file mode 100644 index 297374d80..000000000 --- a/src/docs/postcss.config.mjs +++ /dev/null @@ -1,7 +0,0 @@ -const config = { - plugins: { - '@tailwindcss/postcss': {}, - }, -}; - -export default config; diff --git a/src/docs/reference/doxygen/Doxyfile b/src/docs/reference/doxygen/Doxyfile deleted file mode 100644 index 54ba382a6..000000000 --- a/src/docs/reference/doxygen/Doxyfile +++ /dev/null @@ -1,15 +0,0 @@ -PROJECT_NAME = "Oliphaunt C ABI" -OUTPUT_DIRECTORY = target/docs/generated/api/c/doxygen -INPUT = src/runtimes/liboliphaunt/native/include/oliphaunt.h -FILE_PATTERNS = *.h -RECURSIVE = NO -GENERATE_HTML = NO -GENERATE_LATEX = NO -GENERATE_XML = YES -XML_OUTPUT = xml -QUIET = YES -WARN_IF_UNDOCUMENTED = NO -EXTRACT_ALL = YES -EXTRACT_STATIC = NO -MACRO_EXPANSION = YES -PREDEFINED = __cplusplus= diff --git a/src/docs/src/app/(home)/page.tsx b/src/docs/src/app/(home)/page.tsx index 8303927fc..48286d8ba 100644 --- a/src/docs/src/app/(home)/page.tsx +++ b/src/docs/src/app/(home)/page.tsx @@ -71,25 +71,25 @@ const examples = [ platform: 'Tauri / Native', proof: 'Rust owns the Oliphaunt handle in application state.', stack: 'Rust SDK · app-owned root', - href: `${githubRoot}/examples/tauri`, + href: `${githubRoot}/src/examples/tauri`, }, { platform: 'Tauri / WASIX', proof: 'OliphauntServer exposes a local PostgreSQL URL to SQLx.', stack: 'WASIX sidecar · SQLx', - href: `${githubRoot}/examples/tauri-wasix`, + href: `${githubRoot}/src/examples/tauri-wasix`, }, { platform: 'Electron / Native', proof: 'The TypeScript SDK runs native server mode in the main process.', stack: 'TypeScript SDK · native server', - href: `${githubRoot}/examples/electron`, + href: `${githubRoot}/src/examples/electron`, }, { platform: 'Electron / WASIX', proof: 'A Rust sidecar supplies a local PostgreSQL URL to the main process.', stack: 'WASIX sidecar · local endpoint', - href: `${githubRoot}/examples/electron-wasix`, + href: `${githubRoot}/src/examples/electron-wasix`, }, ] as const; diff --git a/src/docs/src/components/oliphaunt.tsx b/src/docs/src/components/oliphaunt.tsx index ba4378077..2a675559b 100644 --- a/src/docs/src/components/oliphaunt.tsx +++ b/src/docs/src/components/oliphaunt.tsx @@ -484,17 +484,16 @@ const referenceRows = [ }, { need: 'Update an installed app', - answer: - 'Match SDK versions, runtime artifacts, selected extensions, docs versions, and release notes.', + answer: 'Match SDK versions, runtime artifacts, selected extensions and release notes.', href: '/docs/reference/releases', label: 'Releases', icon: PackageCheck, }, { need: 'Match versions', - answer: 'Use the generated version matrix for product compatibility and release contents.', + answer: 'Use the published products page for completed releases.', href: '/docs/reference/version-matrix', - label: 'Version Matrix', + label: 'Published Products', icon: GitBranch, }, { @@ -555,7 +554,7 @@ const releaseLookupRows = [ question: 'Which package version fits my app?', answer: 'Start with the SDK package, then check the runtime dependency it carries.', href: '/docs/reference/version-matrix', - label: 'Version Matrix', + label: 'Published Products', icon: PackageCheck, }, { diff --git a/src/docs/src/lib/docs-data.ts b/src/docs/src/lib/docs-data.ts index 3d5ae1a55..9cea9819d 100644 --- a/src/docs/src/lib/docs-data.ts +++ b/src/docs/src/lib/docs-data.ts @@ -1,3 +1,5 @@ +import published from '../../../../target/docs/generated/published-products.json'; + import { Boxes, Braces, @@ -13,6 +15,11 @@ import { type LucideIcon, } from 'lucide-react'; +function publishedInstall(product: string, command: string) { + const release = (published as Record)[product]; + return release ? command.replaceAll('VERSION', release.version) : 'Not yet published'; +} + export type SdkSurface = { id: string; title: string; @@ -34,12 +41,13 @@ export const sdkSurfaces: SdkSurface[] = [ title: 'Rust', href: '/docs/sdk/rust', packageName: 'oliphaunt', - install: 'cargo add oliphaunt', + install: publishedInstall('oliphaunt-rust', 'cargo add oliphaunt@=VERSION'), target: 'Tauri and native Rust desktop apps', startWith: 'Direct, broker, and server modes', owns: 'Rust-native synchronous and explicit async APIs, helper processes, and desktop runtime selection.', modes: ['direct', 'broker', 'server'], - verifyFirst: 'Run a direct query, then use broker or server when the documented target support fits.', + verifyFirst: + 'Run a direct query, then use broker or server when the documented target support fits.', guideOutcomes: [ 'Open persistent or temporary storage from the synchronous root or explicit async owner handle.', 'Choose direct, broker, or server mode deliberately.', @@ -52,7 +60,7 @@ export const sdkSurfaces: SdkSurface[] = [ title: 'Swift', href: '/docs/sdk/swift', packageName: 'Oliphaunt', - install: 'Add package in Xcode or Package.swift', + install: publishedInstall('oliphaunt-swift', 'Add package VERSION in Xcode or Package.swift'), target: 'iOS and macOS apps', startWith: 'Swift concurrency and app storage', owns: 'Apple app storage, actors, and native runtime resources.', @@ -70,12 +78,16 @@ export const sdkSurfaces: SdkSurface[] = [ title: 'Kotlin', href: '/docs/sdk/kotlin', packageName: 'dev.oliphaunt:oliphaunt-android', - install: 'id("dev.oliphaunt.android") + implementation("dev.oliphaunt:oliphaunt-android:0.1.1")', + install: publishedInstall( + 'oliphaunt-kotlin', + 'implementation("dev.oliphaunt:oliphaunt-android:VERSION")', + ), target: 'Android apps', startWith: 'Coroutines, Android resources, and ABI artifacts', owns: 'Android resource hydration, ABI selection, coroutines, and native runtime ownership.', modes: ['direct'], - verifyFirst: 'Build the Android app, open from app-private storage, and confirm selected ABI assets.', + verifyFirst: + 'Build the Android app, open from app-private storage, and confirm selected ABI assets.', guideOutcomes: [ 'Add the Android package through Gradle.', 'Open from coroutine code using app-private storage.', @@ -88,12 +100,16 @@ export const sdkSurfaces: SdkSurface[] = [ title: 'React Native', href: '/docs/sdk/react-native', packageName: '@oliphaunt/react-native', - install: 'npx expo install @oliphaunt/react-native', + install: publishedInstall( + 'oliphaunt-react-native', + 'npx expo install @oliphaunt/react-native@VERSION', + ), target: 'Expo and React Native New Architecture apps', startWith: 'Config plugin, TurboModule, and JSI transport', owns: 'TypeScript DX, config plugin behavior, JSI bytes, and platform delegation.', modes: ['direct'], - verifyFirst: 'Build a development client, confirm native module loading, and move bytes through JSI.', + verifyFirst: + 'Build a development client, confirm native module loading, and move bytes through JSI.', guideOutcomes: [ 'Install the package and build a native app binary or development client.', 'Use the config plugin for exact extension artifacts.', @@ -106,7 +122,7 @@ export const sdkSurfaces: SdkSurface[] = [ title: 'TypeScript', href: '/docs/sdk/typescript', packageName: '@oliphaunt/ts', - install: 'npm install @oliphaunt/ts', + install: publishedInstall('oliphaunt-js', 'npm install @oliphaunt/ts@VERSION'), target: 'Node.js, Bun, and Deno', startWith: 'Desktop JavaScript over the native runtime family', owns: 'JavaScript API shape, native runtime asset resolution, and native engine modes.', @@ -124,7 +140,7 @@ export const sdkSurfaces: SdkSurface[] = [ title: 'Rust WASIX', href: '/docs/sdk/wasix-rust', packageName: 'oliphaunt-wasix', - install: 'cargo add oliphaunt-wasix', + install: publishedInstall('oliphaunt-wasix-rust', 'cargo add oliphaunt-wasix@=VERSION'), target: 'Rust applications hosting the portable WASIX runtime', startWith: 'Direct Rust calls or a local PostgreSQL-compatible endpoint', owns: 'Rust WASIX hosting, storage, server mode, and dump/restore tooling.', @@ -142,12 +158,14 @@ export const sdkSurfaces: SdkSurface[] = [ title: 'WASIX TypeScript', href: '/docs/sdk/wasix-typescript', packageName: '@oliphaunt/wasix-ts', - install: 'pnpm add @oliphaunt/wasix-ts', + install: publishedInstall('oliphaunt-wasix-ts', 'bun add @oliphaunt/wasix-ts@VERSION'), target: 'Cross-origin-isolated browser, Node.js, Bun, Deno, and Electron applications', - startWith: 'Browser caller-realm or native-host Rust-owner root; import /direct or /worker for explicit placement', + startWith: + 'Browser caller-realm or native-host Rust-owner root; import /direct or /worker for explicit placement', owns: 'Browser caller-realm, native-host actor/direct/Worker hosting, bounded pgwire streaming, optional tools, a host-only local server, selective extensions, and persistence.', modes: ['WASIX browser', 'WASIX actor', 'WASIX direct', 'WASIX Worker', 'WASIX local server'], - verifyFirst: 'Open memory storage on the chosen execution surface, recover from a SQL error, and close cleanly.', + verifyFirst: + 'Open memory storage on the chosen execution surface, recover from a SQL error, and close cleanly.', guideOutcomes: [ 'Install the same npm package on every host, including Deno.', 'Use the responsive native-host root, explicit /direct, or /worker without importing the native TypeScript SDK.', @@ -162,7 +180,10 @@ export const sdkSurfaces: SdkSurface[] = [ title: 'C ABI', href: '/docs/sdk/c-abi', packageName: 'liboliphaunt', - install: 'Use released headers, libraries, and runtime assets', + install: publishedInstall( + 'liboliphaunt-native', + 'Use released headers, libraries, and runtime assets from VERSION', + ), target: 'New language bindings', startWith: 'Native runtime ownership and ABI rules', owns: 'Opaque handles, raw protocol bytes, response ownership, and lifecycle.', @@ -223,8 +244,10 @@ export const runtimeModes: RuntimeMode[] = [ name: 'wasix-typescript', label: 'WASIX TypeScript', href: '/docs/sdk/wasix-typescript', - useWhen: 'A browser caller realm or Node, Bun, Deno, or Electron actor/direct/Worker owns one portable PostgreSQL instance.', - boundary: 'Memory by default, optional host persistence and tools, one Node/Bun/Deno/Electron-only local server subpath, and no native fallback.', + useWhen: + 'A browser caller realm or Node, Bun, Deno, or Electron actor/direct/Worker owns one portable PostgreSQL instance.', + boundary: + 'Memory by default, optional host persistence and tools, one Node/Bun/Deno/Electron-only local server subpath, and no native fallback.', icon: Boxes, }, ]; @@ -232,22 +255,26 @@ export const runtimeModes: RuntimeMode[] = [ export const productPillars = [ { title: 'PostgreSQL semantics', - description: 'Use PostgreSQL storage, WAL, SQL, protocol behavior, and selected extensions inside app-owned storage.', + description: + 'Use PostgreSQL storage, WAL, SQL, protocol behavior, and selected extensions inside app-owned storage.', icon: Database, }, { title: 'Runtime modes with clear boundaries', - description: 'Direct optimizes embedded latency, broker optimizes desktop isolation, and server optimizes independent client sessions.', + description: + 'Direct optimizes embedded latency, broker optimizes desktop isolation, and server optimizes independent client sessions.', icon: Server, }, { title: 'Exact extension packaging', - description: 'Apps select SQL extension names explicitly so release artifacts include only what the app uses.', + description: + 'Apps select SQL extension names explicitly so release artifacts include only what the app uses.', icon: ShieldCheck, }, { title: 'App-grade data movement', - description: 'SDK backup and restore APIs keep PostgreSQL directory mechanics out of application code.', + description: + 'SDK backup and restore APIs keep PostgreSQL directory mechanics out of application code.', icon: HardDrive, }, ]; diff --git a/src/docs/tools/check-docs-product.mjs b/src/docs/tools/check-docs-product.mjs deleted file mode 100644 index 9036624a0..000000000 --- a/src/docs/tools/check-docs-product.mjs +++ /dev/null @@ -1,1469 +0,0 @@ -#!/usr/bin/env node -import { execFileSync } from 'node:child_process'; -import fs from 'node:fs'; -import path from 'node:path'; - -import { generateDocs } from './generate-content.mjs'; - -const args = new Set(process.argv.slice(2)); -const apiReferenceRequested = args.has('--api-reference'); -const result = generateDocs({ - apiMode: apiReferenceRequested ? 'release' : 'fast', - publishApiArtifacts: apiReferenceRequested, -}); -const { manifest, sdkManifest, releaseGraph, routeRecords, paths } = result; -const { repoRoot, siteDocsRoot, staticRoot, generatedMetaRoot } = paths; -const { apiSummary } = result; - -function fail(message) { - console.error(message); - process.exit(1); -} - -function requireFile(relativePath) { - const fullPath = path.join(repoRoot, relativePath); - if (!fs.existsSync(fullPath)) { - fail(`required docs file missing: ${relativePath}`); - } - return fullPath; -} - -function readText(relativePath) { - return fs.readFileSync(requireFile(relativePath), 'utf8'); -} - -function readJsonFile(filePath) { - return JSON.parse(fs.readFileSync(filePath, 'utf8')); -} - -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&'); -} - -function escapeMarkdownCell(value) { - return String(value ?? '') - .replaceAll('\\', '\\\\') - .replaceAll('|', '\\|') - .replaceAll('\n', ' '); -} - -function routeSourcePagePath(route, page) { - const matches = ['.md', '.mdx'] - .map((extension) => path.join(route.source, `${page}${extension}`)) - .filter((relativePath) => fs.existsSync(path.join(repoRoot, relativePath))); - if (matches.length > 1) { - fail(`${route.id} docs contain duplicate source pages for ${page}: ${matches.join(', ')}`); - } - return matches[0] ?? null; -} - -function routePageSet(routeId) { - const route = manifest.routes.find((entry) => entry.id === routeId); - return new Set(route?.page_order ?? []); -} - -function sidebarPagesForRoute(route) { - return route.sidebar_pages ?? route.page_order ?? []; -} - -function gitTrackedFiles(pathspec) { - try { - return execFileSync('git', ['ls-files', pathspec], { - cwd: repoRoot, - encoding: 'utf8', - }) - .trim() - .split('\n') - .filter(Boolean); - } catch { - return []; - } -} - -function assertNoTrackedRootProductsDocs() { - const tracked = gitTrackedFiles('docs/products'); - if (tracked.length > 0) { - fail( - `public product docs must live under src/docs/content, found tracked docs/products files:\n${tracked.join('\n')}`, - ); - } -} - -function assertNoProductLocalPublicDocs() { - const tracked = gitTrackedFiles('src/*/docs/**').filter( - (file) => !file.startsWith('src/docs/') && /\.(md|mdx)$/u.test(file), - ); - if (tracked.length > 0) { - fail( - `public SDK docs must be centralized under src/docs/content; product-local docs require an explicit package-shipped exception:\n${tracked.join('\n')}`, - ); - } -} - -function assertNoTrackedRootPublicDocs() { - const tracked = gitTrackedFiles('docs').filter((file) => /^docs\/[^/]+\.md$/u.test(file)); - const unexpected = tracked.filter((file) => file !== 'docs/README.md'); - if (unexpected.length > 0) { - fail( - `top-level root docs are maintainer-only; move public docs into src/docs or docs subdirectories:\n${unexpected.join('\n')}`, - ); - } -} - -function assertRootDocsBuckets() { - for (const dir of ['docs/architecture', 'docs/maintainers', 'docs/internal']) { - if (!fs.existsSync(path.join(repoRoot, dir))) { - fail(`required root docs bucket missing: ${dir}`); - } - } -} - -function assertNoDocsMoonProject() { - if (fs.existsSync(path.join(repoRoot, 'docs/moon.yml'))) { - fail('docs/moon.yml must not exist; docs is the only docs project'); - } -} - -function assertDocsChromeDoesNotExposeSourcePaths() { - const pageShell = readText('src/docs/src/app/docs/[[...slug]]/page.tsx'); - if (/ViewOptionsPopover[\s\S]{0,240}\bgithubUrl\s*=/u.test(pageShell)) { - fail( - 'public docs page actions must not expose monorepo source-file links through ViewOptionsPopover', - ); - } - if (pageShell.includes('src/docs/content')) { - fail('public docs page actions must not construct GitHub links to source content paths'); - } -} - -function assertUniqueRoutes() { - const seen = new Set(); - for (const route of manifest.routes ?? []) { - if (!route.id || !route.route || !route.source) { - fail(`docs-manifest route is missing id, route, or source: ${JSON.stringify(route)}`); - } - if (route.route.startsWith('/') || route.route.includes('\\')) { - fail(`docs route must be relative and URL-safe: ${route.id}`); - } - if (seen.has(route.route)) { - fail(`duplicate docs route: ${route.route}`); - } - seen.add(route.route); - } -} - -function assertGeneratedFiles() { - const referencePages = routePageSet('reference'); - const generatedReferencePages = [ - 'sdk-matrix', - 'platforms', - 'extension-catalog', - 'api-reference', - 'tested-snippets', - 'artifact-provenance', - 'version-matrix', - ] - .filter((page) => referencePages.has(page)) - .map((page) => path.join(siteDocsRoot, 'reference', `${page}.md`)); - const required = [ - ...generatedReferencePages, - path.join(staticRoot, 'llms.txt'), - path.join(staticRoot, 'llms-full.txt'), - path.join(generatedMetaRoot, 'routes.json'), - path.join(generatedMetaRoot, 'navigation.json'), - path.join(repoRoot, 'target', 'docs', 'generated', 'api', 'summary.json'), - path.join(siteDocsRoot, 'meta.json'), - path.join(siteDocsRoot, 'sdk', 'meta.json'), - ]; - for (const file of required) { - if (!fs.existsSync(file)) { - fail(`generated docs artifact missing: ${path.relative(repoRoot, file)}`); - } - } -} - -function assertGeneratedFumadocsMetadata() { - const rootMeta = readJsonFile(path.join(siteDocsRoot, 'meta.json')); - const expectedRootPages = ['start', 'sdk', 'learn', 'reference']; - if (JSON.stringify(rootMeta.pages) !== JSON.stringify(expectedRootPages)) { - fail(`root Fumadocs metadata must keep compact public nav: ${expectedRootPages.join(', ')}`); - } - if (!rootMeta.description || rootMeta.description.length < 48) { - fail('root Fumadocs metadata must include a useful reader-facing description'); - } - - for (const route of manifest.routes ?? []) { - const metaPath = path.join(siteDocsRoot, route.route, 'meta.json'); - if (!fs.existsSync(metaPath)) { - fail(`generated Fumadocs metadata missing for route ${route.id}`); - } - const metadata = readJsonFile(metaPath); - if (!metadata.title) { - fail(`generated Fumadocs metadata missing title for route ${route.id}`); - } - if (!metadata.description || metadata.description === `${route.title} documentation`) { - fail(`generated Fumadocs metadata needs a real description for route ${route.id}`); - } - if (!metadata.icon) { - fail(`generated Fumadocs metadata needs an icon for route ${route.id}`); - } - if ((route.page_order ?? []).includes('index')) { - if (metadata.pagesIndex !== 'index') { - fail(`${route.id} metadata must expose index as the folder pagesIndex`); - } - if (metadata.pages?.includes('index')) { - fail(`${route.id} metadata must not duplicate index as a sidebar child page`); - } - } - if (route.kind === 'sdk') { - if (metadata.pagesIndex !== 'index') { - fail(`${route.id} SDK metadata must use the overview page as pagesIndex`); - } - if (!metadata.pages?.includes('guide')) { - fail(`${route.id} SDK metadata must expose guide in the SDK folder`); - } - if (metadata.pages?.includes('api-reference')) { - fail( - `${route.id} SDK metadata must keep API Reference out of the primary sidebar; link it from Reference and SDK page bodies`, - ); - } - for (const page of ['api-reference']) { - const routePath = page === 'index' ? `/${route.route}` : `/${route.route}/${page}`; - if (!routeRecords.some((record) => record.route === routePath)) { - fail(`${route.id} SDK metadata requires reachable ${page} route`); - } - } - } - } -} - -function assertSdkSidebarPages() { - const expectedOrder = [ - 'oliphaunt-rust', - 'oliphaunt-swift', - 'oliphaunt-kotlin', - 'oliphaunt-react-native', - 'oliphaunt-js', - 'oliphaunt-wasix-rust', - 'oliphaunt-wasix-typescript', - 'liboliphaunt-native', - ]; - const actualOrder = manifest.routes - .filter((entry) => entry.kind === 'sdk') - .map((entry) => entry.id); - if (JSON.stringify(actualOrder) !== JSON.stringify(expectedOrder)) { - fail(`SDK route order must stay app-developer first: ${expectedOrder.join(' -> ')}`); - } - - for (const route of manifest.routes.filter((entry) => entry.kind === 'sdk')) { - const expected = - route.id === 'oliphaunt-react-native' - ? ['index', 'guide', 'architecture'] - : route.id === 'oliphaunt-wasix-rust' - ? ['index', 'guide', 'runtime', 'dump-restore'] - : ['index', 'guide']; - const actual = route.sidebar_pages ?? []; - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - fail(`${route.id} sidebar_pages must be ${expected.join(', ')}`); - } - if (actual.includes('api-reference')) { - fail(`${route.id} sidebar_pages must not expose API Reference as a primary SDK page`); - } - } -} - -function assertReferenceSidebarPages() { - const route = manifest.routes.find((entry) => entry.id === 'reference'); - if (!route) { - fail('docs manifest is missing reference route'); - } - const expected = ['index', 'capabilities', 'extensions', 'performance']; - const actual = route.sidebar_pages ?? []; - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - fail(`reference sidebar_pages must stay focused: ${expected.join(', ')}`); - } - for (const reachable of [ - 'sdk-products', - 'releases', - 'version-matrix', - 'extension-catalog', - 'api-reference', - ]) { - if (!(route.page_order ?? []).includes(reachable)) { - fail(`reference page_order must keep ${reachable} reachable from lookup pages`); - } - if (actual.includes(reachable)) { - fail(`reference sidebar_pages must keep ${reachable} as a lookup page, not primary nav`); - } - } -} - -function assertNoStaleGeneratedNavigation() { - const stale = path.join(generatedMetaRoot, 'sidebars.json'); - if (fs.existsSync(stale)) { - fail( - 'stale generated sidebars.json must not exist; Fumadocs metadata is generated from meta.json and navigation.json', - ); - } -} - -function assertPublicContentIsMarkdownOnly() { - const contentRoot = path.join(repoRoot, 'src/docs/content'); - const unexpected = []; - function visit(dirPath) { - for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) { - const fullPath = path.join(dirPath, entry.name); - if (entry.isDirectory()) { - visit(fullPath); - continue; - } - if (entry.isFile() && !/\.mdx?$/u.test(entry.name)) { - unexpected.push(path.relative(repoRoot, fullPath)); - } - } - } - visit(contentRoot); - if (unexpected.length > 0) { - fail( - `public docs content may only contain Markdown/MDX pages; move data or policy files out of src/docs/content:\n${unexpected.join('\n')}`, - ); - } -} - -function collectPublicContentPages() { - const contentRoot = path.join(repoRoot, 'src/docs/content'); - const pages = []; - function visit(dirPath) { - for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) { - const fullPath = path.join(dirPath, entry.name); - if (entry.isDirectory()) { - visit(fullPath); - continue; - } - if (entry.isFile() && /\.mdx?$/u.test(entry.name)) { - pages.push(fullPath); - } - } - } - visit(contentRoot); - return pages.sort(); -} - -function frontmatterValue(markdown, key) { - const frontmatter = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/u); - if (!frontmatter) { - return ''; - } - const match = frontmatter[1].match(new RegExp(`^${key}\\s*:\\s*(.+)$`, 'mu')); - return match?.[1]?.trim().replace(/^["']|["']$/gu, '') ?? ''; -} - -function assertPublicContentMetadata() { - const missing = []; - for (const file of collectPublicContentPages()) { - const relative = path.relative(repoRoot, file); - const markdown = fs.readFileSync(file, 'utf8'); - const title = frontmatterValue(markdown, 'title'); - const description = frontmatterValue(markdown, 'description'); - if (!title) { - missing.push(`${relative}: missing title frontmatter`); - } - if (!description) { - missing.push(`${relative}: missing description frontmatter`); - } else if (description.length < 24) { - missing.push(`${relative}: description is too terse for a docs page`); - } - } - if (missing.length > 0) { - fail(`public docs pages must have explicit reader-facing metadata:\n${missing.join('\n')}`); - } -} - -function assertApplicabilityMetadata() { - const missing = []; - for (const record of routeRecords) { - const markdown = fs.readFileSync(record.file, 'utf8'); - if (!record.appliesTo || !/^applies_to\s*:/mu.test(markdown)) { - missing.push(record.source); - } - } - if (missing.length > 0) { - fail(`public docs pages must declare generated applies_to metadata:\n${missing.join('\n')}`); - } -} - -function assertLightweightVersioning() { - const releaseIndex = readText('src/docs/content/reference/releases.mdx'); - for (const required of [ - '`latest` channel', - 'package versions', - 'compatibility notes', - 'release notes', - 'Versioned docs remain available', - 'Documentation changes can update the docs site', - ]) { - if (!releaseIndex.includes(required)) { - fail(`release docs must describe lightweight docs versioning policy: missing ${required}`); - } - } - const versionMatrix = readText( - path.relative(repoRoot, path.join(siteDocsRoot, 'reference', 'version-matrix.md')), - ); - for (const required of [ - '| Product | Current source version | First public version | Version relationship | Publish targets | Tag prefix |', - 'unreleased sentinel', - 'Shared PostgreSQL contrib carrier inputs select both runtime owners', - 'upstream-bound', - 'Release Please selects changed product paths', - 'Native and WASIX are independent products', - 'liboliphaunt-native', - 'oliphaunt-react-native', - 'oliphaunt-wasix-rust', - ]) { - if (!versionMatrix.includes(required)) { - fail(`generated version matrix is missing compatibility/release data: ${required}`); - } - } - const products = Object.entries(releaseGraph.products ?? {}).sort(([left], [right]) => - left.localeCompare(right), - ); - if (products.length === 0) { - fail('generated version matrix has no canonical release products'); - } - for (const [productId, product] of products) { - const currentVersion = - product.current_version === '0.0.0' - ? `${product.current_version} (unreleased)` - : product.current_version; - const expectedRow = `| ${[ - productId, - currentVersion, - product.initial_version, - product.version_relationship, - (product.publish_targets ?? []).join(', ') || 'none', - product.tag_prefix, - ] - .map(escapeMarkdownCell) - .join(' | ')} |`; - if (!versionMatrix.includes(expectedRow)) { - fail( - `generated version matrix is missing the canonical row for ${productId}: ${expectedRow}`, - ); - } - } - if (releaseGraph.products?.['oliphaunt-swift']?.initial_version !== '0.6.0') { - fail('oliphaunt-swift must retain the collision-free first public version 0.6.0'); - } -} - -function assertRouteCoverage() { - const routes = new Set(routeRecords.map((record) => record.route)); - const requiredRoutes = []; - for (const route of manifest.routes ?? []) { - for (const page of route.page_order ?? ['index']) { - requiredRoutes.push(page === 'index' ? `/${route.route}` : `/${route.route}/${page}`); - } - for (const page of route.required_pages ?? []) { - requiredRoutes.push(page === 'index' ? `/${route.route}` : `/${route.route}/${page}`); - } - } - for (const route of requiredRoutes) { - if (!routes.has(route)) { - fail(`generated docs route missing: ${route}`); - } - } -} - -function assertPublicRootLandingPages() { - for (const route of manifest.routes.filter((entry) => entry.kind === 'public')) { - if (!(route.page_order ?? []).includes('index')) { - fail(`${route.id} public docs section must include an index landing page`); - } - const pagePath = routeSourcePagePath(route, 'index'); - if (!pagePath) { - fail(`${route.id} public docs section is missing index.md or index.mdx`); - } - } -} - -function assertLlmRouteCoverage() { - const llms = readText(path.relative(repoRoot, path.join(staticRoot, 'llms.txt'))); - const full = readText(path.relative(repoRoot, path.join(staticRoot, 'llms-full.txt'))); - for (const record of routeRecords) { - if (!llms.includes(record.route)) { - fail(`llms.txt is missing route ${record.route}`); - } - if (!full.includes(`Route: ${record.route}`)) { - fail(`llms-full.txt is missing route ${record.route}`); - } - } -} - -function stripMarkdownCodeBlocks(markdown) { - return markdown.replace(/```[\s\S]*?```/gu, ''); -} - -function extractHrefTargets(text) { - const hrefs = []; - const stripped = stripMarkdownCodeBlocks(text); - const markdownLinkPattern = /!?\[[^\]]*\]\(([^)\s]+)(?:\s+"[^"]*")?\)/gu; - const mdxHrefPattern = /\bhref=(?:"([^"]+)"|'([^']+)')/gu; - for (const match of stripped.matchAll(markdownLinkPattern)) { - hrefs.push(match[1]); - } - for (const match of stripped.matchAll(mdxHrefPattern)) { - hrefs.push(match[1] ?? match[2]); - } - return hrefs; -} - -function normalizedDocsPath(href) { - if (!href || href.startsWith('#')) { - return null; - } - if (/^(?:[a-z][a-z0-9+.-]*:)?\/\//iu.test(href) || /^[a-z][a-z0-9+.-]*:/iu.test(href)) { - return null; - } - if (!href.startsWith('/docs')) { - return null; - } - const [withoutHash] = href.split('#'); - const [withoutQuery] = withoutHash.split('?'); - return withoutQuery.replace(/\/+$/u, '') || '/docs'; -} - -function collectSourceTextFiles(dirPath, output = []) { - if (!fs.existsSync(dirPath)) { - return output; - } - for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) { - const fullPath = path.join(dirPath, entry.name); - if (entry.isDirectory()) { - if (!['node_modules', '.next', 'out'].includes(entry.name)) { - collectSourceTextFiles(fullPath, output); - } - continue; - } - if (entry.isFile() && /\.(?:md|mdx|ts|tsx|js|jsx)$/iu.test(entry.name)) { - output.push(fullPath); - } - } - return output; -} - -function assertDocsInternalLinksResolve() { - const validDocsPaths = new Set(['/docs']); - for (const record of routeRecords) { - validDocsPaths.add(`/docs${record.route}`); - } - - const failures = []; - const files = [ - ...routeRecords.map((record) => record.file), - ...collectSourceTextFiles(path.join(repoRoot, 'src/docs/src')), - ]; - for (const file of files) { - const relative = path.relative(repoRoot, file); - const text = fs.readFileSync(file, 'utf8'); - for (const href of extractHrefTargets(text)) { - const docsPath = normalizedDocsPath(href); - if (docsPath && !validDocsPaths.has(docsPath)) { - failures.push(`${relative}: unresolved docs link ${href}`); - } - } - } - if (failures.length > 0) { - fail(`public docs contain unresolved internal links:\n${failures.join('\n')}`); - } -} - -function assertSdkSectionCoverage() { - const guideSummaryIds = { - 'liboliphaunt-native': 'c-abi', - 'oliphaunt-rust': 'rust', - 'oliphaunt-swift': 'swift', - 'oliphaunt-kotlin': 'kotlin', - 'oliphaunt-react-native': 'react-native', - 'oliphaunt-js': 'typescript', - 'oliphaunt-wasix-rust': 'wasix-rust', - 'oliphaunt-wasix-typescript': 'wasix-typescript', - }; - const guideHeadingOrder = { - 'liboliphaunt-native': [ - 'Install', - 'Open and query', - 'Configure', - 'Choose a mode', - 'Handle lifecycle', - 'Select extensions', - 'Back up and restore', - ], - default: [ - 'Install', - 'Open and query', - 'Create app data', - 'Configure', - 'Choose a mode', - 'Handle lifecycle', - 'Select extensions', - 'Back up and restore', - ], - 'oliphaunt-wasix-rust': [ - 'Install', - 'Open and query', - 'Create app data', - 'Configure', - 'Choose execution placement', - 'Handle lifecycle', - 'Select extensions', - 'Back up, dump, and restore', - ], - 'oliphaunt-wasix-typescript': [ - 'Install', - 'Open and query', - 'Create app data', - 'Configure', - 'Choose execution placement', - 'Handle lifecycle', - 'Select extensions', - 'Back up and restore', - ], - }; - for (const route of manifest.routes.filter((entry) => entry.kind === 'sdk')) { - const requiredPages = route.required_pages ?? []; - for (const required of ['index', 'guide', 'api-reference']) { - if (!requiredPages.includes(required)) { - fail(`${route.id} docs must declare ${required} in docs-manifest.toml`); - } - } - if ((route.page_order ?? []).length > 6) { - fail( - `${route.id} docs sidebar is too granular; keep Overview, Guide, API Reference, and only justified deep pages`, - ); - } - for (const page of requiredPages) { - const pagePath = routeSourcePagePath(route, page); - if (!pagePath) { - fail(`${route.id} docs are missing required page ${page}.md or ${page}.mdx`); - } - } - const indexPath = routeSourcePagePath(route, 'index'); - const indexMarkdown = readText(indexPath); - const landingId = guideSummaryIds[route.id]; - if (!landingId || !indexMarkdown.includes(``)) { - fail(`${route.id} SDK overview is missing the SDK landing component`); - } - const requiredOverviewHeadings = [ - 'Install', - 'Open And Query', - 'Runtime Shape', - 'App Responsibilities', - 'First Query', - ]; - let previousHeadingIndex = -1; - for (const heading of requiredOverviewHeadings) { - const headingPattern = new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$`, 'mu'); - const headingIndex = indexMarkdown.search(headingPattern); - if (!headingPattern.test(indexMarkdown)) { - fail(`${route.id} SDK overview is missing required section: ${heading}`); - } - if (headingIndex < previousHeadingIndex) { - fail( - `${route.id} SDK overview sections must use this order: ${requiredOverviewHeadings.join(' -> ')}`, - ); - } - previousHeadingIndex = headingIndex; - } - const guidePath = routeSourcePagePath(route, 'guide'); - const guideMarkdown = readText(guidePath); - const guideSummaryId = guideSummaryIds[route.id]; - const hasGuideSummary = - guideSummaryId && guideMarkdown.includes(``); - const hasEquivalentGuideSummary = - route.id === 'oliphaunt-react-native' && - guideMarkdown.includes(''); - if (!hasGuideSummary && !hasEquivalentGuideSummary) { - fail(`${route.id} developer guide is missing the SDK guide summary component`); - } - if (!guideMarkdown.includes(``)) { - fail(`${route.id} developer guide is missing the SDK guide proof component`); - } - const expectedGuideHeadings = guideHeadingOrder[route.id] ?? guideHeadingOrder.default; - let previousGuideHeadingIndex = -1; - for (const heading of expectedGuideHeadings) { - const headingIndex = guideMarkdown.search( - new RegExp(`^###\\s+${escapeRegExp(heading)}\\s*$`, 'mu'), - ); - if (headingIndex < 0) { - fail(`${route.id} developer guide is missing required step heading: ${heading}`); - } - if (headingIndex < previousGuideHeadingIndex) { - fail( - `${route.id} developer guide steps must use this order: ${expectedGuideHeadings.join(' -> ')}`, - ); - } - previousGuideHeadingIndex = headingIndex; - } - if (!/^##\s+Troubleshooting\s*$/mu.test(guideMarkdown)) { - fail(`${route.id} developer guide is missing Troubleshooting`); - } - const sourceFiles = requiredPages.map((page) => - readText(routeSourcePagePath(route, page)).toLowerCase(), - ); - const combined = sourceFiles.join('\n'); - if (!combined.includes('exact') || !combined.includes('extension')) { - fail(`${route.id} docs must explain exact extension selection across its SDK section`); - } - if (!combined.includes('backup') || !combined.includes('restore')) { - fail(`${route.id} docs must include backup and restore guidance`); - } - if (route.id === 'oliphaunt-react-native') { - const architecturePath = routeSourcePagePath(route, 'architecture'); - if (!architecturePath) { - fail('React Native SDK docs are missing architecture.md or architecture.mdx'); - } - const architectureMarkdown = readText(architecturePath); - if (!architectureMarkdown.includes('')) { - fail('React Native architecture docs are missing ReactNativeBoundaryMap'); - } - for (const heading of [ - 'Ownership', - 'JavaScript surface', - 'Binary transport', - 'Storage and lifecycle', - 'Extensions and packaging', - ]) { - if (!new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$`, 'mu').test(architectureMarkdown)) { - fail(`React Native architecture docs are missing required section: ${heading}`); - } - } - } - if (route.id === 'oliphaunt-wasix-rust') { - const runtimePath = routeSourcePagePath(route, 'runtime'); - if (!runtimePath) { - fail('Rust WASIX docs are missing runtime.md or runtime.mdx'); - } - const runtimeMarkdown = readText(runtimePath); - if (!runtimeMarkdown.includes('')) { - fail('Rust WASIX runtime docs are missing WasmRuntimeMap'); - } - for (const heading of [ - 'Direct and server hosts', - 'Storage', - 'Startup and extensions', - 'Data movement and tools', - 'Lifecycle', - 'Supported hosts', - ]) { - if (!new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$`, 'mu').test(runtimeMarkdown)) { - fail(`Rust WASIX runtime docs are missing required section: ${heading}`); - } - } - - const dumpRestorePath = routeSourcePagePath(route, 'dump-restore'); - if (!dumpRestorePath) { - fail('Rust WASIX docs are missing dump-restore.md or dump-restore.mdx'); - } - const dumpRestoreMarkdown = readText(dumpRestorePath); - if (!dumpRestoreMarkdown.includes('')) { - fail('Rust WASIX dump/restore docs are missing WasmDataMovement'); - } - for (const heading of [ - 'Choose The Right Export Format', - 'Tool API', - '`PgDumpOptions`', - 'CLI', - 'Restore', - 'Upgrade Guidance', - ]) { - if (!new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$`, 'mu').test(dumpRestoreMarkdown)) { - fail(`Rust WASIX dump/restore docs are missing required section: ${heading}`); - } - } - } - } -} - -function assertStartPageCoverage() { - const startRoute = manifest.routes.find((entry) => entry.id === 'start'); - if (!startRoute) { - fail('docs manifest is missing the Start route'); - } - const startPath = routeSourcePagePath(startRoute, 'index'); - if (!startPath) { - fail('Start docs are missing index.md or index.mdx'); - } - const markdown = readText(startPath); - const requiredComponents = ['QuickstartPath', 'FirstQueryFlow', 'StartNextSteps']; - for (const component of requiredComponents) { - if (!markdown.includes(`<${component}`)) { - fail(`Start docs are missing ${component}`); - } - } - const requiredHeadings = [ - 'Start In One App Target', - 'First Query Shape', - 'After The First Query', - ]; - let previousHeadingIndex = -1; - for (const heading of requiredHeadings) { - const headingIndex = markdown.search(new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$`, 'mu')); - if (headingIndex < 0) { - fail(`Start docs are missing required section: ${heading}`); - } - if (headingIndex < previousHeadingIndex) { - fail(`Start docs sections must use this order: ${requiredHeadings.join(' -> ')}`); - } - previousHeadingIndex = headingIndex; - } -} - -function assertReferencePageCoverage() { - const referenceRoute = manifest.routes.find((entry) => entry.id === 'reference'); - if (!referenceRoute) { - fail('docs manifest is missing the Reference route'); - } - const requirements = [ - { - page: 'capabilities', - title: 'Runtime Support', - components: ['CapabilitySnapshot'], - headings: ['Products', 'Feature support', 'Selection guidance'], - }, - { - page: 'extensions', - title: 'Extensions', - components: ['ExactExtensionRule', 'ExtensionArtifactFlow'], - headings: [ - 'Native selection', - 'Rust WASIX selection', - 'WASIX TypeScript selection', - 'Platform Behavior', - 'Dependencies', - 'External Extensions', - 'Verifying App Artifacts', - ], - }, - { - page: 'performance', - title: 'Performance', - components: ['PerformanceResultsGrid'], - headings: [ - 'What to measure', - 'Compare modes honestly', - 'SQLite comparison', - 'Release Measurements', - ], - }, - { - page: 'releases', - title: 'Releases', - components: ['ReleaseLookup'], - headings: [ - 'First Release Boundary', - 'Version Relationships', - 'Target Availability', - 'What A Release Tells You', - 'Docs Versioning', - ], - }, - ]; - for (const requirement of requirements) { - const pagePath = routeSourcePagePath(referenceRoute, requirement.page); - if (!pagePath) { - fail(`Reference docs are missing ${requirement.page}.md or ${requirement.page}.mdx`); - } - const markdown = readText(pagePath); - if (!new RegExp(`^#\\s+${escapeRegExp(requirement.title)}\\s*$`, 'mu').test(markdown)) { - fail(`Reference page ${requirement.page} is missing title heading: ${requirement.title}`); - } - for (const component of requirement.components) { - if (!markdown.includes(`<${component}`)) { - fail(`Reference page ${requirement.page} is missing ${component}`); - } - } - let previousHeadingIndex = -1; - for (const heading of requirement.headings) { - const headingIndex = markdown.search( - new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$`, 'mu'), - ); - if (headingIndex < 0) { - fail(`Reference page ${requirement.page} is missing required section: ${heading}`); - } - if (headingIndex < previousHeadingIndex) { - fail( - `Reference page ${requirement.page} sections must use this order: ${requirement.headings.join(' -> ')}`, - ); - } - previousHeadingIndex = headingIndex; - } - } -} - -function assertLearnPageCoverage() { - const learnRoute = manifest.routes.find((entry) => entry.id === 'learn'); - if (!learnRoute) { - fail('docs manifest is missing the Learn route'); - } - const requirements = [ - { - page: 'embedded-postgres', - title: 'Embedded PostgreSQL', - components: ['EmbeddedPostgresModel'], - headings: [ - 'Database storage', - 'Lifecycle Contract', - 'Extension Selection', - 'What is different from SQLite?', - ], - }, - { - page: 'native-runtime', - title: 'Native Runtime', - components: ['ModeMatrix'], - headings: [ - 'Choose a mode', - 'Storage', - 'Startup configuration', - 'Backup and restore', - 'Extensions', - 'Fixed support', - ], - }, - { - page: 'mobile-stability', - title: 'Mobile Stability', - components: ['MobileStabilityContract'], - headings: [ - 'What developers can rely on', - 'Close and reopen', - 'Background and foreground', - 'Choosing the mode', - ], - }, - { - page: 'sqlite-upgrade', - title: 'Moving From SQLite', - components: ['SqliteMigrationMap'], - headings: [ - 'Concept Map', - 'Schema And SQL Differences', - 'Storage And Backup', - 'Migration Path', - 'When SQLite Is Still The Better Fit', - ], - }, - { - page: 'tauri', - title: 'Tauri Usage', - components: ['TauriAppPattern'], - headings: [ - 'App Shape', - 'Direct Topology In Async Rust State', - 'Existing Postgres Clients', - 'Extensions And Assets', - 'Backup And Restore', - 'Operational Guidance', - ], - }, - ]; - for (const requirement of requirements) { - const pagePath = routeSourcePagePath(learnRoute, requirement.page); - if (!pagePath) { - fail(`Learn docs are missing ${requirement.page}.md or ${requirement.page}.mdx`); - } - const markdown = readText(pagePath); - if (!new RegExp(`^#\\s+${escapeRegExp(requirement.title)}\\s*$`, 'mu').test(markdown)) { - fail(`Learn page ${requirement.page} is missing title heading: ${requirement.title}`); - } - for (const component of requirement.components) { - if (!markdown.includes(`<${component}`)) { - fail(`Learn page ${requirement.page} is missing ${component}`); - } - } - let previousHeadingIndex = -1; - for (const heading of requirement.headings) { - const headingIndex = markdown.search( - new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$`, 'mu'), - ); - if (headingIndex < 0) { - fail(`Learn page ${requirement.page} is missing required section: ${heading}`); - } - if (headingIndex < previousHeadingIndex) { - fail( - `Learn page ${requirement.page} sections must use this order: ${requirement.headings.join(' -> ')}`, - ); - } - previousHeadingIndex = headingIndex; - } - } -} - -function assertSnippetMarkers() { - for (const route of manifest.routes.filter((entry) => entry.kind === 'sdk')) { - const snippetPath = route.tested_snippet_path; - const marker = route.tested_snippet_marker; - if (!snippetPath || !marker) { - fail(`SDK route ${route.id} must declare tested snippet path and marker`); - } - const source = readText(snippetPath); - if (!source.includes(marker)) { - fail(`${route.id} snippet source is missing marker "${marker}" in ${snippetPath}`); - } - const guidePath = routeSourcePagePath(route, 'guide'); - if (!guidePath) { - fail(`${route.id} guide source is missing`); - } - const guide = readText(guidePath); - if (!guide.includes(`oliphaunt-snippet: ${route.id}`)) { - fail(`${route.id} guide must include the manifest-owned snippet directive`); - } - } -} - -function flattenNavigationItems(items, output = []) { - for (const item of items ?? []) { - if (typeof item === 'string') { - output.push(item); - } else if (item?.type === 'category') { - flattenNavigationItems(item.items, output); - } - } - return output; -} - -function assertFumadocsMetaCoverage() { - const rootMeta = JSON.parse(fs.readFileSync(path.join(siteDocsRoot, 'meta.json'), 'utf8')); - for (const section of ['start', 'sdk', 'learn', 'reference']) { - if (!(rootMeta.pages ?? []).includes(section)) { - fail(`Fumadocs root meta is missing section ${section}`); - } - } - for (const section of ['concepts', 'guides', 'releases']) { - if ((rootMeta.pages ?? []).includes(section)) { - fail(`Fumadocs root meta still exposes stale shallow section ${section}`); - } - } - - for (const route of manifest.routes ?? []) { - const metaPath = path.join(siteDocsRoot, route.route, 'meta.json'); - if (!fs.existsSync(metaPath)) { - fail(`Fumadocs meta missing for route ${route.route}`); - } - const meta = JSON.parse(fs.readFileSync(metaPath, 'utf8')); - const firstSegments = new Set(sidebarPagesForRoute(route).map((page) => page.split('/')[0])); - for (const segment of firstSegments) { - const present = (meta.pages ?? []).includes(segment) || meta.pagesIndex === segment; - if (!present) { - fail(`Fumadocs meta for ${route.route} is missing page or folder ${segment}`); - } - } - } -} - -function assertNavigationCoverage() { - const navigationPath = path.join(generatedMetaRoot, 'navigation.json'); - const navigation = JSON.parse(fs.readFileSync(navigationPath, 'utf8')); - const navigationItems = new Set(flattenNavigationItems(navigation.docs)); - const docIds = new Set(routeRecords.map((record) => record.docId)); - for (const item of navigationItems) { - if (!docIds.has(item)) { - fail(`generated navigation references missing doc id: ${item}`); - } - } - for (const route of manifest.routes ?? []) { - for (const page of sidebarPagesForRoute(route)) { - const item = `${route.route}/${page}`; - if (!navigationItems.has(item)) { - fail(`generated navigation missing sidebar page ${item}`); - } - } - } -} - -function assertApiReferenceSummary({ requireGenerated = false } = {}) { - const apiFileNames = { - 'liboliphaunt-native': 'c-abi', - 'oliphaunt-rust': 'rust', - 'oliphaunt-swift': 'swift', - 'oliphaunt-kotlin': 'kotlin', - 'oliphaunt-react-native': 'react-native', - 'oliphaunt-js': 'typescript', - 'oliphaunt-wasix-rust': 'wasix-rust', - 'oliphaunt-wasix-typescript': 'wasix-typescript', - }; - const expected = new Set( - manifest.routes.filter((entry) => entry.kind === 'sdk').map((entry) => entry.id), - ); - const records = new Map((apiSummary.records ?? []).map((record) => [record.id, record])); - for (const id of expected) { - const record = records.get(id); - if (!record) { - fail(`API reference summary missing ${id}`); - } - if (!record.status || record.status === 'stub' || record.status === 'failed') { - fail(`API reference status for ${id} is not truthful`); - } - if (!record.artifact) { - fail(`API reference summary for ${id} is missing an artifact path`); - } - if (requireGenerated && record.status !== 'generated') { - fail( - `API reference generation did not complete for ${id}: ${record.reason ?? record.status}`, - ); - } - } - for (const record of records.values()) { - const apiPage = apiFileNames[record.id] ?? record.id; - if (!routePageSet('reference').has(`api/${apiPage}`)) { - continue; - } - const siteApiPage = path.join(siteDocsRoot, 'reference', 'api', `${apiPage}.md`); - if (!fs.existsSync(siteApiPage)) { - fail(`generated API reference site page missing for ${record.id}`); - } - } -} - -function assertSdkManifestCoverage() { - const manifestSdkIds = new Set(Object.keys(sdkManifest.sdks ?? {})); - const required = ['rust', 'swift', 'kotlin', 'react-native', 'typescript']; - for (const sdk of required) { - if (!manifestSdkIds.has(sdk)) { - fail(`SDK manifest missing ${sdk}`); - } - } -} - -function assertReleaseGraphPolicy() { - if (releaseGraph.products?.docs) { - fail('docs must not be a release product'); - } -} - -function assertNoNodeModulesGenerated() { - const bad = routeRecords.filter((record) => - record.file.includes(`${path.sep}node_modules${path.sep}`), - ); - if (bad.length > 0) { - fail(`docs generator traversed node_modules:\n${bad.map((record) => record.file).join('\n')}`); - } -} - -function assertMdxComponentPagesStayMdx() { - const componentPattern = - /<(SdkChooser|SdkLanding|SdkGuideProof|StartOutcome|StartNextSteps|EmbeddedPostgresModel|MobileStabilityContract|SqliteMigrationMap|TauriAppPattern|ReactNativeBoundaryMap|WasmRuntimeMap|WasmDataMovement|CapabilitySnapshot|ExtensionArtifactFlow|PerformanceResultsGrid|ReleaseLookup|QuickstartPath|FirstQueryFlow|VerifyChecklist|ModeMatrix|ExactExtensionRule|Steps|Step|Callout|Tabs|Tab|Cards|Card|Files|File|Folder)\b/u; - const bad = routeRecords.filter( - (record) => record.file.endsWith('.md') && componentPattern.test(readText(record.source)), - ); - if (bad.length > 0) { - fail( - `docs pages with React components must be emitted as .mdx, not .md:\n${bad.map((record) => record.source).join('\n')}`, - ); - } -} - -function assertPublicDocsLanguageHygiene() { - const disallowed = [ - { label: 'stale sdk-parity route', pattern: /sdk-parity/u }, - { label: 'source checkout', pattern: /\bsource checkout\b/iu }, - { label: 'stale Expo Go wording', pattern: /\bExpo Go\b/u }, - { label: 'stale base64 transport wording', pattern: /\bbase64\b/iu }, - { label: 'advisory should wording', pattern: /\bshould\b/iu }, - { label: 'defensive should-not wording', pattern: /\bshould not\b/iu }, - { label: 'planning phrase "not pretend"', pattern: /\bnot pretend\b/iu }, - { label: 'runtime smoke evidence', pattern: /\bruntime smoke evidence\b/iu }, - { label: 'package evidence', pattern: /\bpackage evidence\b/iu }, - { label: 'real device evidence', pattern: /\breal device evidence\b/iu }, - { label: 'internal evidence wording', pattern: /\bevidence\b/iu }, - { - label: 'future or placeholder language', - pattern: /\b(?:TODO|placeholder|not yet|coming soon|eventually|can be added later)\b/iu, - }, - { label: 'release metadata internals', pattern: /\brelease metadata\b/iu }, - { label: 'maintainer-facing language', pattern: /\bmaintainer\b/iu }, - { label: 'internal-facing language', pattern: /\binternal\b/iu }, - { label: 'CI internals', pattern: /\bCI\b/u }, - { label: 'tooling path', pattern: /tools\//u }, - { label: 'source path', pattern: /src\//u }, - { label: 'target path', pattern: /target\//u }, - { label: 'fixture path', pattern: /fixtures\//u }, - { label: 'repo-structure language', pattern: /\bmonorepo\b/iu }, - { label: 'pre-release status language', pattern: /\bbefore the first stable\b/iu }, - { label: 'publication timing language', pattern: /\bonce release artifacts are published\b/iu }, - { label: 'defensive fallback wording', pattern: /\bfallback paths\b/iu }, - { - label: 'stale unavailable extension wording', - pattern: /\b(?:not available|not selected|not a pack)\b/iu, - }, - { label: 'stale WASM comparison wording', pattern: /\bOlder WASM examples\b/u }, - { label: 'defensive crash isolation wording', pattern: /\bCrash isolation belongs\b/u }, - { - label: 'defensive unsupported wording', - pattern: /\bunsupported (?:operation|extension|extensions)\b/iu, - }, - { label: 'internal lane wording', pattern: /\blane\b/iu }, - ]; - const failures = []; - for (const record of routeRecords) { - const markdown = readText(record.source); - const lines = markdown.split('\n'); - lines.forEach((line, index) => { - for (const rule of disallowed) { - if (rule.pattern.test(line)) { - failures.push(`${record.route}:${index + 1}: ${rule.label}: ${line.trim()}`); - } - } - }); - } - if (failures.length > 0) { - fail(`public generated docs include maintainer or planning language:\n${failures.join('\n')}`); - } -} - -function walkPublicTextFiles(dirPath, output = []) { - if (!fs.existsSync(dirPath)) { - return output; - } - for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) { - const fullPath = path.join(dirPath, entry.name); - if (entry.isDirectory()) { - walkPublicTextFiles(fullPath, output); - continue; - } - if (entry.isFile() && /\.(?:html|json|md|mdx|txt|xml)$/iu.test(entry.name)) { - output.push(fullPath); - } - } - return output; -} - -function assertPublicGeneratedOutputHygiene() { - const publicApiArtifacts = path.join(staticRoot, 'api-artifacts'); - if (!apiReferenceRequested && fs.existsSync(publicApiArtifacts)) { - fail( - 'default docs builds must not publish API reference artifacts; run the explicit api-reference task when those artifacts are needed', - ); - } - - const disallowed = [ - { label: 'stale sdk-parity route', pattern: /sdk-parity/iu }, - { label: 'source checkout', pattern: /\bsource checkout\b/iu }, - { label: 'stale Expo Go wording', pattern: /\bExpo Go\b/u }, - { label: 'stale base64 transport wording', pattern: /\bbase64\b/iu }, - { label: 'advisory should wording', pattern: /\bshould\b/iu }, - { label: 'defensive should-not wording', pattern: /\bshould not\b/iu }, - { label: 'planning phrase "not pretend"', pattern: /\bnot pretend\b/iu }, - { label: 'runtime smoke evidence', pattern: /\bruntime smoke evidence\b/iu }, - { label: 'package evidence', pattern: /\bpackage evidence\b/iu }, - { label: 'real device evidence', pattern: /\breal device evidence\b/iu }, - { label: 'internal evidence wording', pattern: /\bevidence\b/iu }, - { - label: 'future or placeholder language', - pattern: /\b(?:TODO|placeholder|not yet|coming soon|eventually|can be added later)\b/iu, - }, - { label: 'release metadata internals', pattern: /\brelease metadata\b/iu }, - { label: 'maintainer-facing language', pattern: /\bmaintainer\b/iu }, - { label: 'internal-facing language', pattern: /\binternal\b/iu }, - { label: 'CI internals', pattern: /\bCI\b/u }, - { label: 'tooling path', pattern: /tools\//u }, - { label: 'source path', pattern: /src\//u }, - { label: 'target path', pattern: /target\//u }, - { label: 'fixture path', pattern: /fixtures\//u }, - { label: 'repo-structure language', pattern: /\bmonorepo\b/iu }, - { label: 'pre-release status language', pattern: /\bbefore the first stable\b/iu }, - { label: 'publication timing language', pattern: /\bonce release artifacts are published\b/iu }, - { label: 'defensive fallback wording', pattern: /\bfallback paths\b/iu }, - { - label: 'stale unavailable extension wording', - pattern: /\b(?:not available|not selected|not a pack)\b/iu, - }, - { label: 'stale WASM comparison wording', pattern: /\bOlder WASM examples\b/u }, - { label: 'defensive crash isolation wording', pattern: /\bCrash isolation belongs\b/u }, - { - label: 'defensive unsupported wording', - pattern: /\bunsupported (?:operation|extension|extensions)\b/iu, - }, - { label: 'internal lane wording', pattern: /\blane\b/iu }, - { - label: 'generated API field', - pattern: /\b(?:implementation_path|documentation_path|tested_snippet|reference_artifact)\b/iu, - }, - { label: 'raw extension source kind', pattern: /\boliphaunt-other-extension\b/iu }, - { label: 'unrendered extension placeholder', pattern: /@EXTVERSION@|@MODULEPATH@/u }, - { label: 'generated reference wording', pattern: /\bgenerated language reference/iu }, - { - label: 'removed upstream reference', - pattern: new RegExp(`\\b${'pg'}${'lite'}\\b`, 'iu'), - }, - ]; - const failures = []; - for (const file of [...walkPublicTextFiles(siteDocsRoot), ...walkPublicTextFiles(staticRoot)]) { - const relative = path.relative(repoRoot, file); - const lines = fs.readFileSync(file, 'utf8').split('\n'); - lines.forEach((line, index) => { - for (const rule of disallowed) { - if (rule.pattern.test(line)) { - failures.push(`${relative}:${index + 1}: ${rule.label}: ${line.trim()}`); - } - } - }); - } - if (failures.length > 0) { - fail( - `public generated docs output includes maintainer or planning language:\n${failures.join('\n')}`, - ); - } -} - -function assertReleaseReadinessDocs() { - for (const route of manifest.routes.filter((entry) => entry.kind === 'sdk')) { - const productId = route.product_id; - const product = releaseGraph.products?.[productId]; - if (!product) { - fail(`release metadata missing docs product ${productId}`); - } - if (product.changelog_path) { - requireFile(product.changelog_path); - } - for (const page of ['index', 'guide', 'api-reference']) { - const pagePath = routeSourcePagePath(route, page); - if (!pagePath) { - fail(`${productId} release docs are missing ${page}.md or ${page}.mdx`); - } - const markdown = readText(pagePath); - if (!markdown.includes('# ')) { - fail(`${productId} release docs page ${page}.md is missing a title heading`); - } - } - } -} - -function assertSdkInstallReleaseContracts() { - const releasePlease = JSON.parse(readText('release-please-config.json')); - const packages = Object.values(releasePlease.packages ?? {}); - const packageConfig = (component) => { - const matches = packages.filter((entry) => entry?.component === component); - if (matches.length !== 1) { - fail(`release-please must define exactly one ${component} package`); - } - return matches[0]; - }; - const initialVersion = (component) => - packageConfig(component)['initial-version'] ?? releasePlease['initial-version']; - const swiftInitialVersion = initialVersion('oliphaunt-swift'); - if (swiftInitialVersion !== '0.6.0') { - fail( - `the first SwiftPM-compatible Oliphaunt version must remain 0.6.0; got ${swiftInitialVersion}`, - ); - } - const swiftVersion = releaseGraph.products?.['oliphaunt-swift']?.current_version; - const kotlinVersion = releaseGraph.products?.['oliphaunt-kotlin']?.current_version; - if (!swiftVersion || !kotlinVersion) { - fail('release graph must provide current Swift and Kotlin SDK versions'); - } - - const required = new Map([ - [ - 'src/docs/content/sdk/swift/index.mdx', - `.package(url: "https://github.com/f0rr0/oliphaunt.git", from: "${swiftVersion}")`, - ], - [ - 'src/docs/content/sdk/swift/guide.mdx', - `.package(url: "https://github.com/f0rr0/oliphaunt.git", from: "${swiftVersion}")`, - ], - [ - 'src/sdks/swift/README.md', - `.package(url: "https://github.com/f0rr0/oliphaunt.git", exact: "${swiftVersion}")`, - ], - [ - 'src/docs/content/sdk/kotlin/index.mdx', - `implementation("dev.oliphaunt:oliphaunt-android:${kotlinVersion}")`, - ], - [ - 'src/docs/content/sdk/kotlin/guide.mdx', - `implementation("dev.oliphaunt:oliphaunt-android:${kotlinVersion}")`, - ], - [ - 'src/sdks/kotlin/README.md', - `implementation("dev.oliphaunt:oliphaunt-android:${kotlinVersion}")`, - ], - ['src/docs/src/lib/docs-data.ts', `packageName: 'dev.oliphaunt:oliphaunt-android'`], - ]); - for (const [file, text] of required) { - if (!readText(file).includes(text)) { - fail(`${file} must use the release-owned SDK install contract ${JSON.stringify(text)}`); - } - } - - const publicKotlin = [ - 'src/docs/content/sdk/kotlin/index.mdx', - 'src/docs/content/sdk/kotlin/guide.mdx', - 'src/docs/src/lib/docs-data.ts', - ] - .map(readText) - .join('\n'); - if (publicKotlin.includes('dev.oliphaunt:oliphaunt:')) { - fail( - 'public Kotlin install docs must not advertise the unpublished dev.oliphaunt:oliphaunt coordinate', - ); - } - const wasixTypescriptDocs = readText('src/docs/content/sdk/wasix-typescript/guide.mdx'); - for (const contract of [ - "npm:@oliphaunt/wasix-ts';", - "npm:@oliphaunt/wasix-ts/storage/deno';", - 'same npm package as browsers, Node.js, Bun, and Electron', - '`--allow-ffi`, `--allow-read`, and', - '`app.asar.unpacked` beside', - ]) { - if (!wasixTypescriptDocs.includes(contract)) { - fail(`WASIX TypeScript public docs must include ${JSON.stringify(contract)}`); - } - } -} - -assertNoTrackedRootProductsDocs(); -assertNoProductLocalPublicDocs(); -assertNoTrackedRootPublicDocs(); -assertRootDocsBuckets(); -assertNoDocsMoonProject(); -assertDocsChromeDoesNotExposeSourcePaths(); -assertUniqueRoutes(); -assertGeneratedFiles(); -assertGeneratedFumadocsMetadata(); -assertSdkSidebarPages(); -assertReferenceSidebarPages(); -assertNoStaleGeneratedNavigation(); -assertPublicContentIsMarkdownOnly(); -assertPublicContentMetadata(); -assertApplicabilityMetadata(); -assertLightweightVersioning(); -assertRouteCoverage(); -assertPublicRootLandingPages(); -assertLlmRouteCoverage(); -assertDocsInternalLinksResolve(); -assertStartPageCoverage(); -assertLearnPageCoverage(); -assertReferencePageCoverage(); -assertSdkSectionCoverage(); -assertSnippetMarkers(); -assertSdkManifestCoverage(); -assertReleaseGraphPolicy(); -assertNoNodeModulesGenerated(); -assertMdxComponentPagesStayMdx(); -assertPublicDocsLanguageHygiene(); -assertPublicGeneratedOutputHygiene(); -assertFumadocsMetaCoverage(); -assertNavigationCoverage(); -assertApiReferenceSummary({ requireGenerated: apiReferenceRequested }); -assertSdkInstallReleaseContracts(); - -if (args.has('--release')) { - assertReleaseReadinessDocs(); -} - -if (args.has('--snippets')) { - assertSnippetMarkers(); -} - -console.log(`docs product checks passed (${routeRecords.length} routes)`); diff --git a/src/docs/tools/check-docs-product.mts b/src/docs/tools/check-docs-product.mts new file mode 100644 index 000000000..98fb2faaf --- /dev/null +++ b/src/docs/tools/check-docs-product.mts @@ -0,0 +1,95 @@ +#!/usr/bin/env bun +import fs from 'node:fs'; +import path from 'node:path'; + +import { generateDocs } from './generate-content.mts'; + +const result = await generateDocs(); +const { manifest, routeRecords, paths } = result; +const { repoRoot, siteDocsRoot, staticRoot, generatedMetaRoot } = paths; + +function fail(message) { + console.error(message); + process.exit(1); +} + +function stripMarkdownCodeBlocks(markdown) { + return markdown.replace(/```[\s\S]*?```/gu, ''); +} + +function extractHrefTargets(text) { + const hrefs = []; + const stripped = stripMarkdownCodeBlocks(text); + const markdownLinkPattern = /!?\[[^\]]*\]\(([^)\s]+)(?:\s+"[^"]*")?\)/gu; + const mdxHrefPattern = /\bhref=(?:"([^"]+)"|'([^']+)')/gu; + for (const match of stripped.matchAll(markdownLinkPattern)) { + hrefs.push(match[1]); + } + for (const match of stripped.matchAll(mdxHrefPattern)) { + hrefs.push(match[1] ?? match[2]); + } + return hrefs; +} + +function normalizedDocsPath(href) { + if (!href || href.startsWith('#')) { + return null; + } + if (/^(?:[a-z][a-z0-9+.-]*:)?\/\//iu.test(href) || /^[a-z][a-z0-9+.-]*:/iu.test(href)) { + return null; + } + if (!href.startsWith('/docs')) { + return null; + } + const [withoutHash] = href.split('#'); + const [withoutQuery] = withoutHash.split('?'); + return withoutQuery.replace(/\/+$/u, '') || '/docs'; +} + +function collectSourceTextFiles(dirPath, output = []) { + if (!fs.existsSync(dirPath)) { + return output; + } + for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) { + const fullPath = path.join(dirPath, entry.name); + if (entry.isDirectory()) { + if (!['node_modules', '.next', 'out'].includes(entry.name)) { + collectSourceTextFiles(fullPath, output); + } + continue; + } + if (entry.isFile() && /\.(?:md|mdx|ts|tsx|js|jsx)$/iu.test(entry.name)) { + output.push(fullPath); + } + } + return output; +} + +function assertDocsInternalLinksResolve() { + const validDocsPaths = new Set(['/docs']); + for (const record of routeRecords) { + validDocsPaths.add(`/docs${record.route}`); + } + + const failures = []; + const files = [ + ...routeRecords.map((record) => record.file), + ...collectSourceTextFiles(path.join(repoRoot, 'src/docs/src')), + ]; + for (const file of files) { + const relative = path.relative(repoRoot, file); + const text = fs.readFileSync(file, 'utf8'); + for (const href of extractHrefTargets(text)) { + const docsPath = normalizedDocsPath(href); + if (docsPath && !validDocsPaths.has(docsPath)) { + failures.push(`${relative}: unresolved docs link ${href}`); + } + } + } + if (failures.length > 0) { + fail(`public docs contain unresolved internal links:\n${failures.join('\n')}`); + } +} + +assertDocsInternalLinksResolve(); +console.log(`docs links passed (${routeRecords.length} routes)`); diff --git a/src/docs/tools/check-fumadocs-source.mjs b/src/docs/tools/check-fumadocs-source.mjs deleted file mode 100644 index a6f19fa15..000000000 --- a/src/docs/tools/check-fumadocs-source.mjs +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env node -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const scriptDir = path.dirname(fileURLToPath(import.meta.url)); -const docsRoot = path.resolve(scriptDir, '..'); -const sourceRoot = path.join(docsRoot, '.source'); - -const requiredFiles = [ - { - file: 'server.ts', - pattern: /\bexport\s+const\s+docs\b/u, - }, - { - file: 'browser.ts', - pattern: /\bexport\s+default\s+browserCollections\b/u, - }, - { - file: 'dynamic.ts', - pattern: /\bdynamic<.*\bConfig\b/su, - }, -]; - -for (const required of requiredFiles) { - const filePath = path.join(sourceRoot, required.file); - if (!fs.existsSync(filePath)) { - console.error(`Fumadocs generated source is missing: .source/${required.file}`); - process.exit(1); - } - const text = fs.readFileSync(filePath, 'utf8'); - if (text.trim().length === 0) { - console.error(`Fumadocs generated source is empty: .source/${required.file}`); - process.exit(1); - } - if (!required.pattern.test(text)) { - console.error(`Fumadocs generated source is malformed: .source/${required.file}`); - process.exit(1); - } -} diff --git a/src/docs/tools/generate-api-reference.mjs b/src/docs/tools/generate-api-reference.mjs deleted file mode 100644 index c0dd56cec..000000000 --- a/src/docs/tools/generate-api-reference.mjs +++ /dev/null @@ -1,473 +0,0 @@ -#!/usr/bin/env node -import { execFileSync } from 'node:child_process'; -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; - -import { parse as parseToml } from 'smol-toml'; - -const scriptDir = path.dirname(fileURLToPath(import.meta.url)); -const docsRoot = path.resolve(scriptDir, '..'); -const repoRoot = path.resolve(scriptDir, '../../..'); -const manifestPath = path.join(docsRoot, 'docs-manifest.toml'); -const apiRoot = path.join(repoRoot, 'target', 'docs', 'generated', 'api'); -const summaryPath = path.join(apiRoot, 'summary.json'); -const defaultCommandTimeoutMs = Number.parseInt( - process.env.OLIPHAUNT_DOCS_API_TIMEOUT_MS ?? '600000', - 10, -); - -function readText(filePath) { - return fs.readFileSync(filePath, 'utf8'); -} - -function parseTomlFile(filePath) { - return parseToml(readText(filePath)); -} - -function ensureDir(dirPath) { - fs.mkdirSync(dirPath, { recursive: true }); -} - -function relative(filePath) { - return path.relative(repoRoot, filePath).replaceAll(path.sep, '/'); -} - -function commandExists(command) { - try { - execFileSync('sh', ['-c', `command -v ${command}`], { - encoding: 'utf8', - stdio: ['ignore', 'pipe', 'ignore'], - }); - return true; - } catch { - return false; - } -} - -function run(command, args, options = {}) { - execFileSync(command, args, { - cwd: repoRoot, - encoding: 'utf8', - stdio: options.capture ? ['ignore', 'pipe', 'pipe'] : 'inherit', - timeout: options.timeout ?? defaultCommandTimeoutMs, - env: { - ...process.env, - ...options.env, - }, - }); -} - -function commandFailureStatus(error) { - if (error?.signal === 'SIGTERM' || error?.killed || error?.code === 'ETIMEDOUT') { - return 'skipped'; - } - return 'failed'; -} - -function commandFailureReason(error) { - if (error?.signal === 'SIGTERM' || error?.killed || error?.code === 'ETIMEDOUT') { - return `timed out after ${defaultCommandTimeoutMs}ms`; - } - return error?.message ?? 'command failed'; -} - -function statusRecord(route, status, details) { - return { - id: route.id, - productId: route.product_id, - title: route.title, - referenceKind: route.reference_kind, - status, - ...details, - }; -} - -function parseCHeader(headerPath) { - const header = readText(headerPath); - const withoutComments = header.replace(/\/\*[\s\S]*?\*\//g, ''); - const functions = [ - ...withoutComments.matchAll( - /\b(?:int32_t|uint64_t|void|const\s+char\s+\*)\s+(oliphaunt_[a-z0-9_]+)\s*\(([\s\S]*?)\);/g, - ), - ].map((match) => ({ - name: match[1], - args: match[2].replace(/\s+/g, ' ').trim(), - })); - const constants = [ - ...header.matchAll(/^#define[ \t]+(OLIPHAUNT_[A-Z0-9_]+)(?:[ \t]+([^\r\n]+))?$/gm), - ] - .map((match) => ({ - name: match[1], - value: (match[2] ?? '').trim(), - })) - .filter((constant) => constant.value.length > 0); - return { functions, constants }; -} - -function escapeXml(value) { - return String(value) - .replaceAll('&', '&') - .replaceAll('<', '<') - .replaceAll('>', '>') - .replaceAll('"', '"') - .replaceAll("'", '''); -} - -function writeCReference(manifest, route, fullMode) { - const config = manifest.api_reference?.c ?? {}; - const headerPath = path.join( - repoRoot, - config.header ?? 'src/runtimes/liboliphaunt/native/include/oliphaunt.h', - ); - const outputRoot = path.join(apiRoot, 'c'); - const xmlRoot = path.join(outputRoot, 'xml'); - ensureDir(xmlRoot); - - const parsed = parseCHeader(headerPath); - const xml = ` - - - ${escapeXml(relative(headerPath))} - -${parsed.constants - .map( - (constant) => - ` ${escapeXml(constant.name)}${escapeXml(constant.value)}`, - ) - .join('\n')} - - -${parsed.functions - .map( - (fn) => - ` ${escapeXml(fn.name)}(${escapeXml(fn.args)})`, - ) - .join('\n')} - - - -`; - const fallbackXmlPath = path.join(xmlRoot, 'oliphaunt-header.xml'); - fs.writeFileSync(fallbackXmlPath, xml); - - const markdownPath = path.join(outputRoot, 'reference.md'); - fs.writeFileSync( - markdownPath, - `# C ABI Reference - -Generated from \`${relative(headerPath)}\`. - -## Functions - -${parsed.functions.map((fn) => `- \`${fn.name}(${fn.args})\``).join('\n')} - -## Constants - -${parsed.constants.map((constant) => `- \`${constant.name}\` = \`${constant.value}\``).join('\n')} -`, - ); - - let doxygenStatus = 'not-run'; - let doxygenXmlPath = ''; - let doxygenFailureReason = ''; - const doxygenConfig = config.doxygen_config; - const expectedDoxygenXml = path.join(apiRoot, 'c', 'doxygen', 'xml', 'index.xml'); - if (fullMode && doxygenConfig) { - if (commandExists('doxygen')) { - try { - run('doxygen', [doxygenConfig]); - if (fs.existsSync(expectedDoxygenXml)) { - doxygenStatus = 'generated'; - doxygenXmlPath = relative(expectedDoxygenXml); - } else { - doxygenStatus = 'failed: expected Doxygen XML index missing'; - doxygenFailureReason = 'Doxygen completed but expected XML index is missing'; - } - } catch (error) { - doxygenStatus = `failed: ${error.message}`; - doxygenFailureReason = commandFailureReason(error); - } - } else { - doxygenStatus = 'failed: doxygen not installed'; - doxygenFailureReason = 'doxygen not installed'; - } - } else if (doxygenConfig && fs.existsSync(expectedDoxygenXml)) { - doxygenStatus = 'generated'; - doxygenXmlPath = relative(expectedDoxygenXml); - } - const fullModeRequiresDoxygen = fullMode && Boolean(doxygenConfig); - const generatedByDoxygen = doxygenStatus === 'generated'; - - return statusRecord( - route, - fullModeRequiresDoxygen && !generatedByDoxygen ? 'failed' : 'generated', - { - artifact: relative(markdownPath), - machineReadableArtifact: relative(fallbackXmlPath), - docsEntry: relative(markdownPath), - symbolCount: parsed.functions.length, - constantCount: parsed.constants.length, - generator: generatedByDoxygen ? 'doxygen+xml' : 'header-parser+xml', - doxygenStatus, - doxygenXmlPath, - reason: doxygenFailureReason, - }, - ); -} - -function runCargoDoc(route, packageName, outputKey, fullMode) { - const outputRoot = path.join(apiRoot, outputKey); - ensureDir(outputRoot); - const docsEntry = path.join(outputRoot, 'doc', packageName.replaceAll('-', '_'), 'index.html'); - if (!fullMode) { - return statusRecord(route, fs.existsSync(docsEntry) ? 'generated' : 'configured', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'cargo doc', - reason: fs.existsSync(docsEntry) - ? 'using existing generated rustdoc artifact' - : 'full rustdoc generation runs in release documentation checks', - }); - } - if (!commandExists('cargo')) { - return statusRecord(route, 'skipped', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'cargo doc', - reason: 'cargo not installed', - }); - } - try { - run('cargo', [ - 'doc', - '--no-deps', - '--package', - packageName, - '--target-dir', - relative(outputRoot), - ]); - run('cargo', ['test', '--doc', '--package', packageName], { env: { RUSTDOCFLAGS: '' } }); - return statusRecord(route, fs.existsSync(docsEntry) ? 'generated' : 'failed', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'cargo doc', - reason: fs.existsSync(docsEntry) - ? '' - : 'cargo doc completed but expected index.html is missing', - }); - } catch (error) { - return statusRecord(route, commandFailureStatus(error), { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'cargo doc', - reason: commandFailureReason(error), - }); - } -} - -function runSwiftDocC(manifest, route, fullMode) { - const config = manifest.api_reference?.swift ?? {}; - const outputRoot = path.join(apiRoot, 'swift'); - ensureDir(outputRoot); - const docsEntry = path.join(outputRoot, 'Oliphaunt.doccarchive'); - if (!fullMode) { - return statusRecord(route, fs.existsSync(docsEntry) ? 'generated' : 'configured', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'Swift-DocC', - reason: fs.existsSync(docsEntry) - ? 'using existing generated DocC archive' - : 'full DocC generation runs in release documentation checks', - }); - } - if (!commandExists('swift')) { - return statusRecord(route, 'skipped', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'Swift-DocC', - reason: 'swift not installed', - }); - } - try { - fs.rmSync(docsEntry, { force: true, recursive: true }); - run('swift', [ - 'package', - '--package-path', - config.package_path ?? 'src/sdks/swift', - '--allow-writing-to-directory', - relative(outputRoot), - 'generate-documentation', - '--target', - config.target ?? 'Oliphaunt', - '--output-path', - relative(docsEntry), - '--disable-indexing', - ]); - return statusRecord(route, fs.existsSync(docsEntry) ? 'generated' : 'failed', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'Swift-DocC', - reason: fs.existsSync(docsEntry) - ? '' - : 'Swift-DocC completed but expected archive is missing', - }); - } catch (error) { - return statusRecord(route, commandFailureStatus(error), { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'Swift-DocC', - reason: commandFailureReason(error), - }); - } -} - -function runKotlinDokka(manifest, route, fullMode) { - const config = manifest.api_reference?.kotlin ?? {}; - const projectPath = path.join(repoRoot, config.project_path ?? 'src/sdks/kotlin'); - const gradlew = path.join(projectPath, 'gradlew'); - const docsEntry = path.join(apiRoot, 'kotlin', 'html', 'index.html'); - if (!fullMode) { - return statusRecord(route, fs.existsSync(docsEntry) ? 'generated' : 'configured', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'Dokka v2', - reason: fs.existsSync(docsEntry) - ? 'using existing generated Dokka artifact' - : 'full Dokka generation runs in release documentation checks', - }); - } - if (!fs.existsSync(gradlew)) { - return statusRecord(route, 'skipped', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'Dokka v2', - reason: 'Gradle wrapper missing', - }); - } - try { - execFileSync( - gradlew, - ['--no-daemon', config.task ?? ':oliphaunt:dokkaGeneratePublicationHtml'], - { - cwd: projectPath, - stdio: 'inherit', - timeout: defaultCommandTimeoutMs, - env: { - ...process.env, - OLIPHAUNT_GRADLE_BUILD_ROOT: path.join(repoRoot, 'target', 'oliphaunt-gradle-build'), - }, - }, - ); - return statusRecord(route, fs.existsSync(docsEntry) ? 'generated' : 'failed', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'Dokka v2', - reason: fs.existsSync(docsEntry) ? '' : 'Dokka completed but expected index.html is missing', - }); - } catch (error) { - return statusRecord(route, commandFailureStatus(error), { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'Dokka v2', - reason: commandFailureReason(error), - }); - } -} - -function runTypeDoc(route, packagePath, outputKey, fullMode) { - const docsEntry = path.join(apiRoot, outputKey, 'html', 'index.html'); - if (!fullMode) { - return statusRecord(route, fs.existsSync(docsEntry) ? 'generated' : 'configured', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'TypeDoc', - reason: fs.existsSync(docsEntry) - ? 'using existing generated TypeDoc artifact' - : 'full TypeDoc generation runs in release documentation checks', - }); - } - try { - run('pnpm', ['--dir', packagePath, 'run', 'docs:api']); - return statusRecord(route, fs.existsSync(docsEntry) ? 'generated' : 'failed', { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'TypeDoc', - reason: fs.existsSync(docsEntry) - ? '' - : 'TypeDoc completed but expected index.html is missing', - }); - } catch (error) { - return statusRecord(route, commandFailureStatus(error), { - artifact: relative(docsEntry), - docsEntry: relative(docsEntry), - generator: 'TypeDoc', - reason: commandFailureReason(error), - }); - } -} - -function routeById(manifest, id) { - return manifest.routes.find((route) => route.id === id); -} - -export function generateApiReferenceArtifacts(options = {}) { - const manifest = options.manifest ?? parseTomlFile(manifestPath); - const fullMode = options.mode === 'release' || options.mode === 'full'; - ensureDir(apiRoot); - fs.rmSync(summaryPath, { force: true }); - - const records = [ - writeCReference(manifest, routeById(manifest, 'liboliphaunt-native'), fullMode), - runCargoDoc(routeById(manifest, 'oliphaunt-rust'), 'oliphaunt', 'rust', fullMode), - runSwiftDocC(manifest, routeById(manifest, 'oliphaunt-swift'), fullMode), - runKotlinDokka(manifest, routeById(manifest, 'oliphaunt-kotlin'), fullMode), - runTypeDoc( - routeById(manifest, 'oliphaunt-react-native'), - 'src/sdks/react-native', - 'react-native', - fullMode, - ), - runTypeDoc(routeById(manifest, 'oliphaunt-js'), 'src/sdks/js', 'typescript', fullMode), - runCargoDoc( - routeById(manifest, 'oliphaunt-wasix-rust'), - 'oliphaunt-wasix', - 'wasix-rust', - fullMode, - ), - runTypeDoc( - routeById(manifest, 'oliphaunt-wasix-typescript'), - 'src/bindings/wasix-ts', - 'wasix-typescript', - fullMode, - ), - ]; - - const summary = { - mode: fullMode ? 'release' : 'fast', - generatedAt: new Date().toISOString(), - records, - }; - fs.writeFileSync(summaryPath, `${JSON.stringify(summary, null, 2)}\n`); - return summary; -} - -if (import.meta.url === pathToFileURL(process.argv[1]).href) { - const modeArg = process.argv.find((arg) => arg.startsWith('--mode=')); - const mode = modeArg ? modeArg.split('=')[1] : 'fast'; - const summary = generateApiReferenceArtifacts({ mode }); - console.log( - `generated API reference status for ${summary.records.length} surfaces (${summary.mode})`, - ); - const requireGenerated = - mode === 'release' || process.env.OLIPHAUNT_DOCS_REQUIRE_NATIVE_API === '1'; - const failed = summary.records.filter((record) => - requireGenerated ? record.status !== 'generated' : record.status === 'failed', - ); - if (failed.length > 0) { - for (const record of failed) { - console.error(`${record.id}: ${record.status}: ${record.reason || record.doxygenStatus}`); - } - process.exit(1); - } -} diff --git a/src/docs/tools/generate-content.mjs b/src/docs/tools/generate-content.mjs deleted file mode 100644 index fa9109954..000000000 --- a/src/docs/tools/generate-content.mjs +++ /dev/null @@ -1,1258 +0,0 @@ -#!/usr/bin/env node -import { execFileSync } from 'node:child_process'; -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; - -import { parse as parseToml } from 'smol-toml'; - -import { generateApiReferenceArtifacts } from './generate-api-reference.mjs'; - -const scriptDir = path.dirname(fileURLToPath(import.meta.url)); -const docsRoot = path.resolve(scriptDir, '..'); -const repoRoot = path.resolve(scriptDir, '../../..'); -const manifestPath = path.join(docsRoot, 'docs-manifest.toml'); -const generatedRoot = path.join(repoRoot, 'target', 'docs'); -const siteDocsRoot = path.join(generatedRoot, 'site-docs'); -const staticRoot = path.join(generatedRoot, 'static'); -const staticApiArtifactsRoot = path.join(staticRoot, 'api-artifacts'); -const generatedMetaRoot = path.join(generatedRoot, 'generated'); -const generationLockDir = path.join(generatedRoot, '.generate.lock'); -const generationLockMetadata = path.join(generationLockDir, 'owner.json'); - -const SKIP_DIRS = new Set(['node_modules', '.git', '.moon', '.docusaurus', 'build', 'target']); - -function readText(filePath) { - return fs.readFileSync(filePath, 'utf8'); -} - -function parseTomlFile(filePath) { - return parseToml(readText(filePath)); -} - -function parseJsonFile(filePath) { - return JSON.parse(readText(filePath)); -} - -function releaseProductMetadata() { - const releasePlease = parseJsonFile(path.join(repoRoot, 'release-please-config.json')); - const releaseManifest = parseJsonFile(path.join(repoRoot, '.release-please-manifest.json')); - const packages = releasePlease.packages ?? {}; - const tagSeparator = releasePlease['tag-separator'] ?? '-'; - const tagVersionPrefix = releasePlease['include-v-in-tag'] === false ? '' : 'v'; - const defaultInitialVersion = releasePlease['initial-version']; - const products = {}; - for (const [packagePath, packageConfig] of Object.entries(packages)) { - const productId = packageConfig.component; - if (!productId) { - throw new Error(`release-please package ${packagePath} is missing component`); - } - const metadata = parseTomlFile(path.join(repoRoot, packagePath, 'release.toml')); - const currentVersion = releaseManifest[packagePath]; - const initialVersion = packageConfig['initial-version'] ?? defaultInitialVersion; - if (typeof currentVersion !== 'string' || typeof initialVersion !== 'string') { - throw new Error(`release version metadata is incomplete for ${productId}`); - } - const extensionVersioning = metadata.extension?.versioning; - products[productId] = { - ...metadata, - current_version: currentVersion, - initial_version: initialVersion, - version_relationship: extensionVersioning ?? 'independent', - tag_prefix: `${productId}${tagSeparator}${tagVersionPrefix}`, - }; - } - return { - policy: { - repository: 'f0rr0/oliphaunt', - default_branch: 'main', - versioning: 'independent', - extension_selection: 'exact-sql-extension', - }, - input_groups: {}, - products, - }; -} - -function ensureDir(dirPath) { - fs.mkdirSync(dirPath, { recursive: true }); -} - -function resetDir(dirPath) { - fs.rmSync(dirPath, { force: true, recursive: true }); - ensureDir(dirPath); -} - -function resetGeneratedMetadata() { - ensureDir(generatedMetaRoot); - for (const entry of fs.readdirSync(generatedMetaRoot, { withFileTypes: true })) { - if (entry.name === 'api') { - continue; - } - fs.rmSync(path.join(generatedMetaRoot, entry.name), { force: true, recursive: true }); - } -} - -function sleep(milliseconds) { - const buffer = new SharedArrayBuffer(4); - const view = new Int32Array(buffer); - Atomics.wait(view, 0, 0, milliseconds); -} - -function processIsAlive(pid) { - if (!Number.isInteger(pid) || pid <= 0) { - return false; - } - try { - process.kill(pid, 0); - return true; - } catch { - return false; - } -} - -function removeStaleGenerationLock() { - if (!fs.existsSync(generationLockDir)) { - return false; - } - try { - if (fs.existsSync(generationLockMetadata)) { - const metadata = JSON.parse(readText(generationLockMetadata)); - if (!processIsAlive(metadata.pid)) { - fs.rmSync(generationLockDir, { force: true, recursive: true }); - return true; - } - return false; - } - const stat = fs.statSync(generationLockDir); - if (Date.now() - stat.mtimeMs > 120_000) { - fs.rmSync(generationLockDir, { force: true, recursive: true }); - return true; - } - } catch { - fs.rmSync(generationLockDir, { force: true, recursive: true }); - return true; - } - return false; -} - -function withGenerationLock(callback) { - ensureDir(generatedRoot); - const started = Date.now(); - while (true) { - try { - fs.mkdirSync(generationLockDir); - fs.writeFileSync( - generationLockMetadata, - `${JSON.stringify({ pid: process.pid, createdAt: new Date().toISOString() }, null, 2)}\n`, - ); - break; - } catch (error) { - if (error?.code !== 'EEXIST') { - throw error; - } - if (removeStaleGenerationLock()) { - continue; - } - if (Date.now() - started > 120_000) { - throw new Error('timed out waiting for docs generation lock'); - } - sleep(100); - } - } - try { - return callback(); - } finally { - fs.rmSync(generationLockDir, { force: true, recursive: true }); - } -} - -function assertInsideRepo(relativePath, label) { - if (!relativePath || path.isAbsolute(relativePath) || relativePath.includes('\0')) { - throw new Error(`${label} must be a repository-relative path`); - } - const resolved = path.resolve(repoRoot, relativePath); - if (!resolved.startsWith(repoRoot + path.sep)) { - throw new Error(`${label} escapes the repository: ${relativePath}`); - } - return resolved; -} - -function replaceSnippetDirectives(markdown, context) { - return markdown.replace( - //giu, - (_match, routeId) => { - if (!context.sdkRoutesById.has(routeId)) { - throw new Error(`unknown docs snippet route id: ${routeId}`); - } - return ''; - }, - ); -} - -function normalizeMdxComments(markdown) { - return markdown.replace(//gu, (_match, comment) => `{/*${comment}*/}`); -} - -function yamlString(value) { - return JSON.stringify(String(value ?? '')); -} - -function ensureTitleFrontmatter(markdown, fallbackTitle) { - const title = firstHeading(markdown, fallbackTitle); - const frontmatterMatch = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/u); - if (!frontmatterMatch) { - return `---\ntitle: ${yamlString(title)}\n---\n\n${markdown}`; - } - if (/^title\s*:/mu.test(frontmatterMatch[1])) { - return markdown; - } - return markdown.replace(/^---\r?\n/u, `---\ntitle: ${yamlString(title)}\n`); -} - -function stripMatchingLeadingTitleHeading(markdown) { - const title = frontmatterValue(markdown, 'title'); - if (!title) { - return markdown; - } - const frontmatterMatch = markdown.match(/^(---\r?\n[\s\S]*?\r?\n---\r?\n?)([\s\S]*)$/u); - const prefix = frontmatterMatch ? frontmatterMatch[1] : ''; - const body = frontmatterMatch ? frontmatterMatch[2] : markdown; - const headingPattern = /^(\s*)#\s+(.+?)\s*#?\s*(?:\r?\n|$)/u; - const headingMatch = body.match(headingPattern); - if (!headingMatch || headingMatch[1].trim().length > 0) { - return markdown; - } - if (headingMatch[2].trim() !== title) { - return markdown; - } - const strippedBody = body.slice(headingMatch[0].length).replace(/^\r?\n/u, ''); - return `${prefix}${strippedBody}`; -} - -function normalizePageMarkdown(markdown, fallbackTitle) { - return stripMatchingLeadingTitleHeading(ensureTitleFrontmatter(markdown, fallbackTitle)); -} - -function normalizeCodeFenceInfoStrings(markdown) { - return markdown.replace( - /^(`{3,})([A-Za-z0-9_+-]+),([^\r\n]*)$/gmu, - (_match, fence, lang, meta) => { - return `${fence}${lang} ${meta.trim()}`; - }, - ); -} - -function copyDir(source, destination, context) { - if (!fs.existsSync(source)) { - throw new Error(`docs source does not exist: ${path.relative(repoRoot, source)}`); - } - ensureDir(destination); - for (const entry of fs.readdirSync(source, { withFileTypes: true })) { - if (SKIP_DIRS.has(entry.name)) { - continue; - } - const from = path.join(source, entry.name); - const to = path.join(destination, entry.name); - if (entry.isDirectory()) { - copyDir(from, to, context); - } else if (entry.isFile()) { - if (/\.mdx?$/u.test(entry.name)) { - const markdown = normalizeCodeFenceInfoStrings( - normalizeMdxComments(replaceSnippetDirectives(readText(from), context)), - ); - const fallbackTitle = path.basename(entry.name, path.extname(entry.name)); - fs.writeFileSync(to, normalizePageMarkdown(markdown, fallbackTitle)); - } else { - fs.copyFileSync(from, to); - } - } - } -} - -function routeSourcePagePath(source, page) { - for (const extension of ['.md', '.mdx']) { - const candidate = path.join(source, `${page}${extension}`); - if (fs.existsSync(candidate)) { - return candidate; - } - } - return null; -} - -function copyMarkdownPage(from, to, context) { - const markdown = normalizeCodeFenceInfoStrings( - normalizeMdxComments(replaceSnippetDirectives(readText(from), context)), - ); - const fallbackTitle = path.basename(from, path.extname(from)); - ensureDir(path.dirname(to)); - fs.writeFileSync(to, normalizePageMarkdown(markdown, fallbackTitle)); -} - -function copyRoutePages(route, context) { - const source = assertInsideRepo(route.source, `source for ${route.id}`); - const destination = path.join(siteDocsRoot, route.route); - ensureDir(destination); - for (const page of uniqueInOrder([ - ...(route.page_order ?? []), - ...(route.required_pages ?? []), - ])) { - const from = routeSourcePagePath(source, page); - if (!from) { - continue; - } - const to = path.join(destination, `${page}${path.extname(from)}`); - copyMarkdownPage(from, to, context); - } -} - -function copyStaticPath(source, destination) { - if (!fs.existsSync(source)) { - return false; - } - ensureDir(path.dirname(destination)); - const stat = fs.statSync(source); - if (stat.isDirectory()) { - fs.cpSync(source, destination, { force: true, recursive: true }); - } else if (stat.isFile()) { - fs.copyFileSync(source, destination); - } - return true; -} - -function escapeMarkdown(value) { - return String(value ?? '') - .replaceAll('\\', '\\\\') - .replaceAll('|', '\\|') - .replaceAll('\n', ' '); -} - -function firstHeading(markdown, fallback) { - const match = markdown.match(/^#\s+(.+)$/m); - return match ? match[1].trim() : fallback; -} - -function frontmatterValue(markdown, key) { - const frontmatterMatch = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/u); - if (!frontmatterMatch) { - return ''; - } - const match = frontmatterMatch[1].match(new RegExp(`^${key}\\s*:\\s*(.+)$`, 'mu')); - if (!match) { - return ''; - } - return match[1].trim().replace(/^["']|["']$/gu, ''); -} - -function collectMarkdownFiles(root) { - const files = []; - function visit(dir) { - for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { - if (SKIP_DIRS.has(entry.name)) { - continue; - } - const fullPath = path.join(dir, entry.name); - if (entry.isDirectory()) { - visit(fullPath); - } else if (entry.isFile() && /\.mdx?$/.test(entry.name)) { - files.push(fullPath); - } - } - } - if (fs.existsSync(root)) { - visit(root); - } - return files.sort(); -} - -function markdownRouteFor(filePath) { - const relative = path.relative(siteDocsRoot, filePath).replaceAll(path.sep, '/'); - const withoutExtension = relative.replace(/\.mdx?$/, ''); - const route = withoutExtension.replace(/\/index$/, ''); - return `/${route}`; -} - -function markdownDocIdFor(filePath) { - return path - .relative(siteDocsRoot, filePath) - .replaceAll(path.sep, '/') - .replace(/\.mdx?$/, ''); -} - -function releaseProducts(releaseGraph) { - return Object.entries(releaseGraph.products ?? {}).sort(([left], [right]) => - left.localeCompare(right), - ); -} - -function sdkRows(sdkManifest) { - return Object.entries(sdkManifest.sdks ?? {}).sort(([left], [right]) => - left.localeCompare(right), - ); -} - -function generateSdkMatrix(sdkManifest) { - const rows = sdkRows(sdkManifest).flatMap(([id, sdk]) => - (sdk.surfaces ?? []).map( - (surface) => - `| ${escapeMarkdown(id)} | ${escapeMarkdown(sdk.package_identity)} | ${escapeMarkdown(surface.entrypoint)} | ${escapeMarkdown(surface.calling_contract)} | ${escapeMarkdown(surface.execution_owner)} | ${surface.main_safe ? 'yes' : 'no'} | ${escapeMarkdown((surface.topologies ?? []).join(', '))} | ${escapeMarkdown((sdk.consumer_targets ?? []).join(', '))} | ${escapeMarkdown(sdk.runtime_boundary)} |`, - ), - ); - return `--- -title: SDK Matrix ---- - -# SDK Matrix - -Use this matrix to compare registry-qualified package identities, public -entrypoints, calling contracts, execution ownership, supported topologies, -consumer targets, and runtime boundaries. A topology such as direct or broker -does not imply caller-thread execution. - -| SDK | Package identity | Entrypoint | Calling contract | Execution owner | Main-safe | Topologies | Supported targets | Runtime boundary | -| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | -${rows.join('\n')} -`; -} - -function generatePlatformMatrix(sdkManifest) { - const rows = sdkRows(sdkManifest).flatMap(([id, sdk]) => - (sdk.consumer_targets ?? []).map( - (target) => - `| ${escapeMarkdown(target)} | ${escapeMarkdown(id)} | ${escapeMarkdown(sdk.package_identity)} |`, - ), - ); - return `--- -title: Platform And Package Matrix ---- - -# Platform And Package Matrix - -Use this matrix to pick the package for each app target. - -| Platform target | SDK | Package | -| --- | --- | --- | -${rows.join('\n')} -`; -} - -function generateExtensionCatalog() { - const catalogPath = path.join(repoRoot, 'src/extensions/generated/extensions.catalog.json'); - if (!fs.existsSync(catalogPath)) { - throw new Error('extension catalog source is required for public docs generation'); - } - const catalog = JSON.parse(readText(catalogPath)); - const rows = (catalog.extensions ?? []) - .sort((left, right) => - String(left['sql-name'] ?? left.id).localeCompare(String(right['sql-name'] ?? right.id)), - ) - .map((extension) => { - const control = extension.control ?? {}; - return `| ${escapeMarkdown(extension['sql-name'] ?? extension.id)} | ${escapeMarkdown(extension['display-name'] ?? extension.id)} | ${escapeMarkdown(extensionVersion(control['default-version']))} | ${escapeMarkdown(extensionFamily(extension['source-kind']))} | ${escapeMarkdown(extensionActivation(extension))} |`; - }); - return `--- -title: Extension Catalog ---- - -# Extension Catalog - -Use this table to find exact SQL extension names. SDK and app packaging -selection uses the SQL extension name. Every listed extension is supported -extensions only. - -| SQL extension | Display name | Version | Family | Activation | -| --- | --- | --- | --- | --- | -${rows.join('\n')} -`; -} - -function extensionVersion(version) { - if (!version || String(version).includes('@')) { - return 'Packaged with runtime'; - } - return version; -} - -function extensionFamily(sourceKind) { - const labels = { - 'postgres-contrib': 'PostgreSQL contrib', - 'oliphaunt-other-extension': 'External extension', - postgis: 'PostGIS', - }; - return labels[sourceKind] ?? 'Extension artifact'; -} - -function extensionActivation(extension) { - if (extension.lifecycle?.['create-extension'] === false) { - return 'Runtime module'; - } - return 'CREATE EXTENSION'; -} - -function statusLabel(status) { - if (status === 'generated') { - return 'generated'; - } - if (status === 'configured') { - return 'configured'; - } - if (status === 'skipped') { - return 'skipped'; - } - return status || 'unknown'; -} - -function referenceLabel(referenceKind) { - const labels = { - doxygen: 'Doxygen header reference', - rustdoc: 'Rustdoc', - 'swift-docc': 'Swift DocC', - dokka: 'Dokka', - typedoc: 'TypeDoc', - }; - return labels[referenceKind] ?? referenceKind ?? 'API reference'; -} - -function link(label, href) { - return href ? `[${label}](${href})` : ''; -} - -function apiArtifactHref(relativePath) { - return `/api-artifacts/${relativePath}`; -} - -function staticArtifactPlan(record) { - const plans = { - 'liboliphaunt-native': [ - { - source: record.artifact, - destination: 'c/reference.md', - href: apiArtifactHref('c/reference.md'), - label: 'Open C ABI Markdown', - }, - { - source: record.machineReadableArtifact, - destination: 'c/xml/oliphaunt-header.xml', - href: apiArtifactHref('c/xml/oliphaunt-header.xml'), - label: 'Open C ABI XML', - }, - { - source: record.doxygenXmlPath, - destination: 'c/doxygen/xml/index.xml', - href: apiArtifactHref('c/doxygen/xml/index.xml'), - label: 'Open Doxygen XML index', - }, - ], - 'oliphaunt-rust': [ - { - source: 'target/docs/generated/api/rust/doc', - destination: 'rust/doc', - href: apiArtifactHref('rust/doc/oliphaunt/index.html'), - label: 'Open rustdoc', - }, - ], - 'oliphaunt-swift': [ - { - source: record.artifact, - destination: 'swift/Oliphaunt.doccarchive', - href: apiArtifactHref('swift/Oliphaunt.doccarchive/index.html'), - label: 'Open Swift DocC archive', - }, - ], - 'oliphaunt-kotlin': [ - { - source: 'target/docs/generated/api/kotlin/html', - destination: 'kotlin/html', - href: apiArtifactHref('kotlin/html/index.html'), - label: 'Open Dokka reference', - }, - ], - 'oliphaunt-react-native': [ - { - source: 'target/docs/generated/api/react-native/html', - destination: 'react-native/html', - href: apiArtifactHref('react-native/html/index.html'), - label: 'Open TypeDoc reference', - }, - ], - 'oliphaunt-js': [ - { - source: 'target/docs/generated/api/typescript/html', - destination: 'typescript/html', - href: apiArtifactHref('typescript/html/index.html'), - label: 'Open TypeDoc reference', - }, - ], - 'oliphaunt-wasix-rust': [ - { - source: 'target/docs/generated/api/wasix-rust/doc', - destination: 'wasix-rust/doc', - href: apiArtifactHref('wasix-rust/doc/oliphaunt_wasix/index.html'), - label: 'Open Rust WASIX rustdoc', - }, - ], - 'oliphaunt-wasix-typescript': [ - { - source: 'target/docs/generated/api/wasix-typescript/html', - destination: 'wasix-typescript/html', - href: apiArtifactHref('wasix-typescript/html/index.html'), - label: 'Open WASIX TypeScript TypeDoc reference', - }, - ], - }; - return plans[record.id] ?? []; -} - -function copyApiArtifactsToStatic(apiSummary) { - const linksByRecordId = new Map(); - for (const record of apiSummary.records ?? []) { - const links = []; - for (const plan of staticArtifactPlan(record)) { - if (!plan.source) { - continue; - } - const source = assertInsideRepo(plan.source, `API artifact for ${record.id}`); - const destination = path.join(staticApiArtifactsRoot, plan.destination); - if (copyStaticPath(source, destination)) { - links.push({ - label: plan.label, - href: plan.href, - }); - } - } - linksByRecordId.set(record.id, links); - } - return linksByRecordId; -} - -function cReferenceBody(record) { - if (record.id !== 'liboliphaunt-native' || !record.artifact) { - return ''; - } - const artifactPath = path.join(repoRoot, record.artifact); - if (!fs.existsSync(artifactPath)) { - return ''; - } - return readText(artifactPath) - .replace(/^# C ABI Reference\s*/u, '') - .trim(); -} - -function generateApiReference(manifest) { - const rows = manifest.routes - .filter((route) => route.kind === 'sdk') - .map((route) => { - const reference = referenceLabel(route.reference_kind); - return `| ${escapeMarkdown(route.title)} | [Open](/docs/${route.route}/api-reference) | ${escapeMarkdown(reference)} |`; - }); - return `--- -title: API Reference ---- - -# API Reference - -Use this page when you know the SDK and need the API surface by task. SDK guides -show the first integration path. These maps point to the language reference for -configuration, query results, lifecycle, extension selection, data movement -where exposed, and error handling. Shared concepts do not imply API parity. - -## Choose By Task - -| Task | Look for | -| --- | --- | -| Open a database | builder or open configuration, storage, runtime host or mode, durability | -| Run SQL | query, execute, parameters, row access, result typing | -| Use raw protocol | owned buffered bytes and response ownership | -| Manage lifecycle | closed state, close, and cancellation where exposed | -| Run maintenance SQL | issue PostgreSQL statements such as \`CHECKPOINT\` through execute when required | -| Move data | backup, restore, dump, or archive APIs where exposed | -| Ship extensions | exact ecosystem-native selectors, dependency files, artifact reports | -| Handle errors | SDK errors, PostgreSQL SQLSTATE data, and runtime errors | - -## Language References - -| Surface | Reference page | Native reference format | -| --- | --- | --- | -${rows.join('\n')} -`; -} - -function generateSdkApiReferencePage(record, artifactLinks = []) { - const cBody = cReferenceBody(record); - const links = artifactLinks - .map((artifactLink) => `- ${link(artifactLink.label, artifactLink.href)}`) - .join('\n'); - const reference = referenceLabel(record.referenceKind); - return `--- -title: ${record.title} ---- - -# ${record.title} - -Use this page with the ${reference}. Product guides explain runtime behavior; -the API reference gives exact declarations for the released SDK. - -${statusLabel(record.status) === 'generated' && links ? `## Reference\n\n${links}\n` : ''} -${cBody ? `## Symbols\n\n${cBody}\n` : ''} -`; -} - -function apiReferenceFileName(record) { - const names = { - 'liboliphaunt-native': 'c-abi', - 'oliphaunt-rust': 'rust', - 'oliphaunt-swift': 'swift', - 'oliphaunt-kotlin': 'kotlin', - 'oliphaunt-react-native': 'react-native', - 'oliphaunt-js': 'typescript', - 'oliphaunt-wasix-rust': 'wasix-rust', - 'oliphaunt-wasix-typescript': 'wasix-typescript', - }; - return names[record.id] ?? record.id; -} - -function generateTestedSnippets(manifest) { - const rows = manifest.routes - .filter((route) => route.kind === 'sdk') - .map( - (route) => - `| ${escapeMarkdown(route.title)} | ${escapeMarkdown(route.tested_snippet_marker)} | ${escapeMarkdown(route.tested_snippet_path)} |`, - ); - return `--- -title: Tested Snippets ---- - -# Tested Snippets - -Public SDK snippets are tied to executable product tests or smoke files by -marker. The docs checker fails when a marker disappears. - -| Surface | Marker | Executable source | -| --- | --- | --- | -${rows.join('\n')} -`; -} - -function generateArtifactProvenance(releaseGraph) { - const rows = releaseProducts(releaseGraph).map(([id, product]) => { - return `| ${escapeMarkdown(id)} | ${escapeMarkdown((product.publish_targets ?? []).join(', '))} | ${escapeMarkdown((product.release_artifacts ?? []).join(', '))} | ${escapeMarkdown(product.tag_prefix)} |`; - }); - return `--- -title: Artifact And Provenance Matrix ---- - -# Artifact And Provenance Matrix - -Release verification checks asset checksums, attestations, and registry -publication for these surfaces. - -| Product | Publish targets | Release artifacts | Tag prefix | -| --- | --- | --- | --- | -${rows.join('\n')} -`; -} - -function generateVersionMatrix(releaseGraph) { - const rows = releaseProducts(releaseGraph).map(([id, product]) => { - const currentVersion = - product.current_version === '0.0.0' - ? `${product.current_version} (unreleased)` - : product.current_version; - return `| ${escapeMarkdown(id)} | ${escapeMarkdown(currentVersion)} | ${escapeMarkdown(product.initial_version)} | ${escapeMarkdown(product.version_relationship)} | ${escapeMarkdown((product.publish_targets ?? []).join(', ') || 'none')} | ${escapeMarkdown(product.tag_prefix)} |`; - }); - return `--- -title: Version Matrix ---- - -# Version Matrix - -Products are versioned independently. - -The source version \`0.0.0\` is the unreleased sentinel, not a public registry -version. The first-public-version column is derived from Release Please's -global or per-product initial version. - -Use this matrix before upgrading an app dependency. Start with the package your -app installs, then read the products it depends on for runtime artifact, -extension, and compatibility notes. A compatibility relationship does not turn -the repository into one version. - -Release Please selects changed product paths. Derived selection then follows -Moon production/peer edges and exact compatibility fields from dependency to -consumer. Shared PostgreSQL contrib carrier inputs select both runtime owners; -their native and WASIX carriers use the corresponding runtime version. -Native and WASIX are independent products; neither selects the other. - -| Product | Current source version | First public version | Version relationship | Publish targets | Tag prefix | -| --- | --- | --- | --- | --- | --- | -${rows.join('\n')} -`; -} - -function routePageSet(manifest, routeId) { - const route = (manifest.routes ?? []).find((entry) => entry.id === routeId); - return new Set(route?.page_order ?? []); -} - -function writeGeneratedReferencePages( - manifest, - sdkManifest, - releaseGraph, - apiSummary, - artifactLinksByRecordId, -) { - const referenceRoot = path.join(siteDocsRoot, 'reference'); - const apiRootForSite = path.join(referenceRoot, 'api'); - const referencePages = routePageSet(manifest, 'reference'); - ensureDir(referenceRoot); - if (referencePages.has('sdk-matrix')) { - fs.writeFileSync(path.join(referenceRoot, 'sdk-matrix.md'), generateSdkMatrix(sdkManifest)); - } - if (referencePages.has('platforms')) { - fs.writeFileSync(path.join(referenceRoot, 'platforms.md'), generatePlatformMatrix(sdkManifest)); - } - if (referencePages.has('extension-catalog')) { - fs.writeFileSync(path.join(referenceRoot, 'extension-catalog.md'), generateExtensionCatalog()); - } - if (referencePages.has('api-reference')) { - fs.writeFileSync(path.join(referenceRoot, 'api-reference.md'), generateApiReference(manifest)); - } - const apiPages = [...referencePages] - .filter((page) => page.startsWith('api/')) - .map((page) => page.slice('api/'.length)); - if (apiPages.length > 0) { - ensureDir(apiRootForSite); - for (const record of apiSummary.records ?? []) { - const fileName = apiReferenceFileName(record); - if (!apiPages.includes(fileName)) { - continue; - } - fs.writeFileSync( - path.join(apiRootForSite, `${fileName}.md`), - generateSdkApiReferencePage(record, artifactLinksByRecordId.get(record.id) ?? []), - ); - } - } - if (referencePages.has('tested-snippets')) { - fs.writeFileSync( - path.join(referenceRoot, 'tested-snippets.md'), - generateTestedSnippets(manifest), - ); - } - if (referencePages.has('artifact-provenance')) { - fs.writeFileSync( - path.join(referenceRoot, 'artifact-provenance.md'), - generateArtifactProvenance(releaseGraph), - ); - } - if (referencePages.has('version-matrix')) { - fs.writeFileSync( - path.join(referenceRoot, 'version-matrix.md'), - generateVersionMatrix(releaseGraph), - ); - } -} - -function writeMetadata(routeRecords) { - ensureDir(generatedMetaRoot); - fs.writeFileSync( - path.join(generatedMetaRoot, 'routes.json'), - `${JSON.stringify({ routes: routeRecords }, null, 2)}\n`, - ); -} - -function itemForPage(route, page) { - return `${route.route}/${page}`; -} - -const routePresentation = { - start: { - description: 'Install an SDK, open app-owned storage, and run the first PostgreSQL query.', - icon: 'Route', - defaultOpen: true, - collapsible: false, - }, - sdk: { - description: 'Choose a native SDK, Rust WASIX, WASIX TypeScript, or the C ABI.', - icon: 'PackageCheck', - defaultOpen: false, - }, - learn: { - description: - 'Understand embedded PostgreSQL storage, lifecycle, runtime modes, and migrations.', - icon: 'BookOpen', - defaultOpen: false, - }, - reference: { - description: 'Look up capabilities, extensions, releases, performance results, and API links.', - icon: 'SearchCheck', - defaultOpen: false, - }, - 'liboliphaunt-native': { - description: 'Stable C ABI, opaque handles, raw protocol bytes, and binding rules.', - icon: 'CodeXml', - }, - 'oliphaunt-rust': { - description: 'Rust and Tauri SDK with direct, broker, and server runtime modes.', - icon: 'Laptop', - }, - 'oliphaunt-swift': { - description: 'Apple SDK for iOS and macOS apps using Swift concurrency.', - icon: 'Smartphone', - }, - 'oliphaunt-kotlin': { - description: 'Android SDK with coroutine-first APIs and exact native resource packaging.', - icon: 'Smartphone', - }, - 'oliphaunt-react-native': { - description: 'New Architecture package with Expo config plugin, TurboModule, and JSI bytes.', - icon: 'Layers', - }, - 'oliphaunt-js': { - description: 'TypeScript SDK for Node.js, Bun, and Deno.', - icon: 'Braces', - }, - 'oliphaunt-wasix-rust': { - description: 'Rust SDK for the portable WASIX runtime.', - icon: 'Boxes', - }, - 'oliphaunt-wasix-typescript': { - description: 'Portable TypeScript SDK for browsers, Node.js, Bun, Deno, and Electron.', - icon: 'Boxes', - }, -}; - -function metadataForRoute(route) { - const presentation = routePresentation[route.id] ?? {}; - return Object.fromEntries( - Object.entries(presentation).filter(([, value]) => value !== undefined), - ); -} - -function category(label, items) { - return { - type: 'category', - label, - items, - }; -} - -function sidebarPagesForRoute(route) { - return route.sidebar_pages ?? route.page_order ?? []; -} - -function orderedItemsForRoute(route, routeRecords) { - const available = new Set( - routeRecords - .filter( - (record) => - record.route === `/${route.route}` || record.route.startsWith(`/${route.route}/`), - ) - .map((record) => record.docId), - ); - const declared = sidebarPagesForRoute(route); - const declaredItems = declared.map((page) => itemForPage(route, page)); - if (declared.length > 0) { - return declaredItems.filter((item) => available.has(item)); - } - return [...available].sort((left, right) => left.localeCompare(right)); -} - -function writeJson(filePath, value) { - ensureDir(path.dirname(filePath)); - fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`); -} - -function uniqueInOrder(values) { - const seen = new Set(); - const output = []; - for (const value of values) { - if (!seen.has(value)) { - seen.add(value); - output.push(value); - } - } - return output; -} - -function pageOrderForFumadocs(route) { - return uniqueInOrder( - sidebarPagesForRoute(route).map((page) => { - const [first] = page.split('/'); - return first; - }), - ); -} - -function titleForPathSegment(segment) { - return segment - .split('-') - .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) - .join(' '); -} - -function writeRouteMeta(route) { - const routeRoot = path.join(siteDocsRoot, route.route); - const metadata = { - title: route.title, - ...metadataForRoute(route), - pages: pageOrderForFumadocs(route), - }; - if (metadata.pages.includes('index')) { - metadata.pagesIndex = 'index'; - metadata.pages = metadata.pages.filter((page) => page !== 'index'); - } - if (route.kind === 'public') { - metadata.root = true; - metadata.description ??= `${route.title} documentation`; - } - writeJson(path.join(routeRoot, 'meta.json'), metadata); - - const nested = new Map(); - for (const page of sidebarPagesForRoute(route)) { - const parts = page.split('/'); - if (parts.length < 2) { - continue; - } - const [folder, child] = parts; - const children = nested.get(folder) ?? []; - children.push(child); - nested.set(folder, children); - } - - for (const [folder, pages] of nested) { - writeJson(path.join(routeRoot, folder, 'meta.json'), { - title: titleForPathSegment(folder), - pages: uniqueInOrder(pages), - }); - } -} - -function writeFumadocsMeta(manifest) { - const sdkRoutes = (manifest.routes ?? []).filter((route) => route.kind === 'sdk'); - writeJson(path.join(siteDocsRoot, 'meta.json'), { - title: 'Oliphaunt', - description: - 'Embedded PostgreSQL SDK documentation for native, Rust WASIX, and WASIX TypeScript apps.', - pages: ['start', 'sdk', 'learn', 'reference'], - }); - for (const route of manifest.routes ?? []) { - if (route.id !== 'sdk') { - writeRouteMeta(route); - } - } - writeJson(path.join(siteDocsRoot, 'sdk', 'meta.json'), { - title: 'SDKs', - description: routePresentation.sdk.description, - icon: routePresentation.sdk.icon, - root: true, - defaultOpen: routePresentation.sdk.defaultOpen, - pagesIndex: 'index', - pages: sdkRoutes.map((route) => route.route.replace(/^sdk\//u, '')), - }); -} - -function writeNavigationMetadata(manifest, routeRecords) { - const byId = new Map((manifest.routes ?? []).map((route) => [route.id, route])); - const sdkRoutes = (manifest.routes ?? []).filter((route) => route.kind === 'sdk'); - const navigation = { - docs: [ - 'start/index', - category('SDKs', [ - 'sdk/index', - ...sdkRoutes.map((route) => - category(route.title, orderedItemsForRoute(route, routeRecords)), - ), - ]), - category('Learn', orderedItemsForRoute(byId.get('learn'), routeRecords)), - category('Reference', orderedItemsForRoute(byId.get('reference'), routeRecords)), - ], - }; - writeJson(path.join(generatedMetaRoot, 'navigation.json'), navigation); - writeFumadocsMeta(manifest); -} - -function stripFrontmatter(markdown) { - return markdown.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/u, ''); -} - -function writeLlmFiles(routeRecords) { - ensureDir(staticRoot); - const summary = [ - '# Oliphaunt Docs', - '', - 'Oliphaunt is embedded PostgreSQL for native, Rust WASIX, and WASIX TypeScript apps.', - '', - '## Public routes', - ...routeRecords.map((record) => `- ${record.title}: ${record.route}`), - '', - ].join('\n'); - fs.writeFileSync(path.join(staticRoot, 'llms.txt'), summary); - - const full = routeRecords - .map((record) => { - const markdown = stripFrontmatter(readText(record.file)); - return `# ${record.title}\n\nRoute: ${record.route}\n\n${markdown}`; - }) - .join('\n\n---\n\n'); - fs.writeFileSync(path.join(staticRoot, 'llms-full.txt'), full); -} - -function appliesToForRoute(route) { - if (route.applies_to) { - return String(route.applies_to); - } - if (route.kind === 'sdk' && route.product_id) { - return `current ${route.product_id}`; - } - return 'current'; -} - -function routeForGeneratedPage(manifest, pageRoute) { - const candidates = (manifest.routes ?? []) - .filter((route) => { - const root = `/${route.route}`; - return pageRoute === root || pageRoute.startsWith(`${root}/`); - }) - .sort((left, right) => right.route.length - left.route.length); - return candidates[0]; -} - -function ensureApplicabilityFrontmatter(markdown, appliesTo) { - const escaped = yamlString(appliesTo); - const frontmatterMatch = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/u); - if (!frontmatterMatch) { - return `---\napplies_to: ${escaped}\n---\n\n${markdown}`; - } - if (/^applies_to\s*:/mu.test(frontmatterMatch[1])) { - return markdown; - } - return markdown.replace(/^---\r?\n/u, `---\napplies_to: ${escaped}\n`); -} - -function stampApplicabilityMetadata(manifest) { - for (const file of collectMarkdownFiles(siteDocsRoot)) { - const pageRoute = markdownRouteFor(file); - const route = routeForGeneratedPage(manifest, pageRoute); - if (!route) { - throw new Error(`no docs manifest route owns generated page ${pageRoute}`); - } - const markdown = readText(file); - fs.writeFileSync( - file, - stripMatchingLeadingTitleHeading( - ensureApplicabilityFrontmatter(markdown, appliesToForRoute(route)), - ), - ); - } -} - -function currentGitSha() { - try { - return execFileSync('git', ['rev-parse', '--short', 'HEAD'], { - cwd: repoRoot, - encoding: 'utf8', - }).trim(); - } catch { - return 'unknown'; - } -} - -function generateDocsUnlocked(options = {}) { - const manifest = parseTomlFile(manifestPath); - const sdkManifest = parseTomlFile(path.join(repoRoot, 'tools/policy/sdk-manifest.toml')); - const releaseGraph = releaseProductMetadata(); - const apiSummary = generateApiReferenceArtifacts({ - manifest, - mode: options.apiMode ?? 'fast', - }); - - resetDir(siteDocsRoot); - resetDir(staticRoot); - resetGeneratedMetadata(); - const artifactLinksByRecordId = options.publishApiArtifacts - ? copyApiArtifactsToStatic(apiSummary) - : new Map(); - - const context = { - sdkRoutesById: new Map( - (manifest.routes ?? []) - .filter((route) => route.kind === 'sdk') - .map((route) => [route.id, route]), - ), - }; - - for (const route of manifest.routes ?? []) { - copyRoutePages(route, context); - } - - writeGeneratedReferencePages( - manifest, - sdkManifest, - releaseGraph, - apiSummary, - artifactLinksByRecordId, - ); - stampApplicabilityMetadata(manifest); - - const routeRecords = collectMarkdownFiles(siteDocsRoot).map((file) => { - const markdown = readText(file); - return { - route: markdownRouteFor(file), - docId: markdownDocIdFor(file), - title: - frontmatterValue(markdown, 'title') || - firstHeading(markdown, path.basename(file, path.extname(file))), - appliesTo: frontmatterValue(markdown, 'applies_to'), - file, - source: path.relative(repoRoot, file), - }; - }); - - writeMetadata(routeRecords); - writeNavigationMetadata(manifest, routeRecords); - writeLlmFiles(routeRecords); - fs.writeFileSync( - path.join(generatedMetaRoot, 'build-metadata.json'), - `${JSON.stringify( - { - generatedAt: new Date().toISOString(), - gitSha: currentGitSha(), - routeCount: routeRecords.length, - apiReferenceMode: apiSummary.mode, - apiArtifactsPublished: Boolean(options.publishApiArtifacts), - }, - null, - 2, - )}\n`, - ); - - return { - manifest, - sdkManifest, - releaseGraph, - apiSummary, - routeRecords, - paths: { - repoRoot, - docsRoot, - siteDocsRoot, - staticRoot, - generatedMetaRoot, - }, - }; -} - -export function generateDocs(options = {}) { - return withGenerationLock(() => generateDocsUnlocked(options)); -} - -if (import.meta.url === pathToFileURL(process.argv[1]).href) { - const modeArg = process.argv.find((arg) => arg.startsWith('--api-mode=')); - const apiMode = modeArg ? modeArg.split('=')[1] : 'fast'; - const publishApiArtifacts = process.argv.includes('--publish-api-artifacts'); - const result = generateDocs({ apiMode, publishApiArtifacts }); - console.log( - `generated ${result.routeRecords.length} docs routes in target/docs (api artifacts published: ${publishApiArtifacts})`, - ); -} diff --git a/src/docs/tools/generate-content.mts b/src/docs/tools/generate-content.mts new file mode 100644 index 000000000..e64989ec9 --- /dev/null +++ b/src/docs/tools/generate-content.mts @@ -0,0 +1,589 @@ +#!/usr/bin/env bun +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +const parseToml = Bun.TOML.parse; + +import { publishedProducts } from './published-products.mts'; + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const docsRoot = path.resolve(scriptDir, '..'); +const repoRoot = path.resolve(scriptDir, '../../..'); +const manifestPath = path.join(docsRoot, 'docs-manifest.toml'); +const generatedRoot = path.join(repoRoot, 'target', 'docs'); +const siteDocsRoot = path.join(generatedRoot, 'site-docs'); +const staticRoot = path.join(generatedRoot, 'static'); + +const generatedMetaRoot = path.join(generatedRoot, 'generated'); + +const SKIP_DIRS = new Set(['node_modules', '.git', '.moon', '.docusaurus', 'build', 'target']); + +function readText(filePath) { + return fs.readFileSync(filePath, 'utf8'); +} + +function parseTomlFile(filePath) { + return parseToml(readText(filePath)); +} + +function ensureDir(dirPath) { + fs.mkdirSync(dirPath, { recursive: true }); +} + +function resetDir(dirPath) { + fs.rmSync(dirPath, { force: true, recursive: true }); + ensureDir(dirPath); +} + +function assertInsideRepo(relativePath, label) { + if (!relativePath || path.isAbsolute(relativePath) || relativePath.includes('\0')) { + throw new Error(`${label} must be a repository-relative path`); + } + const resolved = path.resolve(repoRoot, relativePath); + if (!resolved.startsWith(repoRoot + path.sep)) { + throw new Error(`${label} escapes the repository: ${relativePath}`); + } + return resolved; +} + +function substituteVersions(markdown, products) { + return markdown.replace(/\{\{release:([a-z0-9-]+)\}\}/gu, (_match, id) => { + if (!(id in products)) throw new Error(`Unknown release product: ${id}`); + return products[id]?.version ?? 'NOT-YET-PUBLISHED'; + }); +} + +function normalizeMdxComments(markdown) { + return markdown.replace(//gu, (_match, comment) => `{/*${comment}*/}`); +} + +function yamlString(value) { + return JSON.stringify(String(value ?? '')); +} + +function ensureTitleFrontmatter(markdown, fallbackTitle) { + const title = firstHeading(markdown, fallbackTitle); + const frontmatterMatch = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/u); + if (!frontmatterMatch) { + return `---\ntitle: ${yamlString(title)}\n---\n\n${markdown}`; + } + if (/^title\s*:/mu.test(frontmatterMatch[1])) { + return markdown; + } + return markdown.replace(/^---\r?\n/u, `---\ntitle: ${yamlString(title)}\n`); +} + +function stripMatchingLeadingTitleHeading(markdown) { + const title = frontmatterValue(markdown, 'title'); + if (!title) { + return markdown; + } + const frontmatterMatch = markdown.match(/^(---\r?\n[\s\S]*?\r?\n---\r?\n?)([\s\S]*)$/u); + const prefix = frontmatterMatch ? frontmatterMatch[1] : ''; + const body = frontmatterMatch ? frontmatterMatch[2] : markdown; + const headingPattern = /^(\s*)#\s+(.+?)\s*#?\s*(?:\r?\n|$)/u; + const headingMatch = body.match(headingPattern); + if (!headingMatch || headingMatch[1].trim().length > 0) { + return markdown; + } + if (headingMatch[2].trim() !== title) { + return markdown; + } + const strippedBody = body.slice(headingMatch[0].length).replace(/^\r?\n/u, ''); + return `${prefix}${strippedBody}`; +} + +function normalizePageMarkdown(markdown, fallbackTitle) { + return stripMatchingLeadingTitleHeading(ensureTitleFrontmatter(markdown, fallbackTitle)); +} + +function normalizeCodeFenceInfoStrings(markdown) { + return markdown.replace( + /^(`{3,})([A-Za-z0-9_+-]+),([^\r\n]*)$/gmu, + (_match, fence, lang, meta) => { + return `${fence}${lang} ${meta.trim()}`; + }, + ); +} + +function routeSourcePagePath(source, page) { + for (const extension of ['.md', '.mdx']) { + const candidate = path.join(source, `${page}${extension}`); + if (fs.existsSync(candidate)) { + return candidate; + } + } + return null; +} + +function copyMarkdownPage(from, to, context) { + const markdown = normalizeCodeFenceInfoStrings( + normalizeMdxComments(substituteVersions(readText(from), context)), + ); + const fallbackTitle = path.basename(from, path.extname(from)); + ensureDir(path.dirname(to)); + fs.writeFileSync(to, normalizePageMarkdown(markdown, fallbackTitle)); +} + +function copyRoutePages(route, context) { + const source = assertInsideRepo(route.source, `source for ${route.id}`); + const destination = path.join(siteDocsRoot, route.route); + ensureDir(destination); + for (const page of uniqueInOrder([ + ...(route.page_order ?? []), + ...(route.required_pages ?? []), + ])) { + const from = routeSourcePagePath(source, page); + if (!from) { + continue; + } + const to = path.join(destination, `${page}${path.extname(from)}`); + copyMarkdownPage(from, to, context); + if (route.product_id && !context[route.product_id]) { + const warning = + '\n> This product has no completed public release yet. Installation examples below are not available for use.\n'; + fs.writeFileSync( + to, + readText(to).replace(/^(---\r?\n[\s\S]*?\r?\n---\r?\n)/u, `$1${warning}`), + ); + } + } +} + +function escapeMarkdown(value) { + return String(value ?? '') + .replaceAll('\\', '\\\\') + .replaceAll('|', '\\|') + .replaceAll('\n', ' '); +} + +function firstHeading(markdown, fallback) { + const match = markdown.match(/^#\s+(.+)$/m); + return match ? match[1].trim() : fallback; +} + +function frontmatterValue(markdown, key) { + const frontmatterMatch = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/u); + if (!frontmatterMatch) { + return ''; + } + const match = frontmatterMatch[1].match(new RegExp(`^${key}\\s*:\\s*(.+)$`, 'mu')); + if (!match) { + return ''; + } + return match[1].trim().replace(/^["']|["']$/gu, ''); +} + +function collectMarkdownFiles(root) { + const files = []; + function visit(dir) { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + if (SKIP_DIRS.has(entry.name)) { + continue; + } + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + visit(fullPath); + } else if (entry.isFile() && /\.mdx?$/.test(entry.name)) { + files.push(fullPath); + } + } + } + if (fs.existsSync(root)) { + visit(root); + } + return files.sort(); +} + +function markdownRouteFor(filePath) { + const relative = path.relative(siteDocsRoot, filePath).replaceAll(path.sep, '/'); + const withoutExtension = relative.replace(/\.mdx?$/, ''); + const route = withoutExtension.replace(/\/index$/, ''); + return `/${route}`; +} + +function markdownDocIdFor(filePath) { + return path + .relative(siteDocsRoot, filePath) + .replaceAll(path.sep, '/') + .replace(/\.mdx?$/, ''); +} + +function generateExtensionCatalog() { + const catalogPath = path.join(repoRoot, 'src/extensions/generated/extensions.catalog.json'); + if (!fs.existsSync(catalogPath)) { + throw new Error('extension catalog source is required for public docs generation'); + } + const catalog = JSON.parse(readText(catalogPath)); + const rows = (catalog.extensions ?? []) + .sort((left, right) => + String(left['sql-name'] ?? left.id).localeCompare(String(right['sql-name'] ?? right.id)), + ) + .map((extension) => { + const control = extension.control ?? {}; + return `| ${escapeMarkdown(extension['sql-name'] ?? extension.id)} | ${escapeMarkdown(extension['display-name'] ?? extension.id)} | ${escapeMarkdown(extensionVersion(control['default-version']))} | ${escapeMarkdown(extensionFamily(extension['source-kind']))} | ${escapeMarkdown(extensionActivation(extension))} |`; + }); + return `--- +title: Extension Catalog +--- + +# Extension Catalog + +Use this table to find exact SQL extension names. SDK and app packaging +selection uses the SQL extension name. Every listed extension is supported +extensions only. + +| SQL extension | Display name | Version | Family | Activation | +| --- | --- | --- | --- | --- | +${rows.join('\n')} +`; +} + +function extensionVersion(version) { + if (!version || String(version).includes('@')) { + return 'Packaged with runtime'; + } + return version; +} + +function extensionFamily(sourceKind) { + const labels = { + 'postgres-contrib': 'PostgreSQL contrib', + 'oliphaunt-other-extension': 'External extension', + postgis: 'PostGIS', + }; + return labels[sourceKind] ?? 'Extension artifact'; +} + +function extensionActivation(extension) { + if (extension.lifecycle?.['create-extension'] === false) { + return 'Runtime module'; + } + return 'CREATE EXTENSION'; +} + +function writeMetadata(routeRecords) { + ensureDir(generatedMetaRoot); + fs.writeFileSync( + path.join(generatedMetaRoot, 'routes.json'), + `${JSON.stringify({ routes: routeRecords }, null, 2)}\n`, + ); +} + +function itemForPage(route, page) { + return `${route.route}/${page}`; +} + +const routePresentation = { + start: { + description: 'Install an SDK, open app-owned storage, and run the first PostgreSQL query.', + icon: 'Route', + defaultOpen: true, + collapsible: false, + }, + sdk: { + description: 'Choose a native SDK, Rust WASIX, WASIX TypeScript, or the C ABI.', + icon: 'PackageCheck', + defaultOpen: false, + }, + learn: { + description: + 'Understand embedded PostgreSQL storage, lifecycle, runtime modes, and migrations.', + icon: 'BookOpen', + defaultOpen: false, + }, + reference: { + description: 'Look up capabilities, extensions, releases, performance results, and API links.', + icon: 'SearchCheck', + defaultOpen: false, + }, + 'liboliphaunt-native': { + description: 'Stable C ABI, opaque handles, raw protocol bytes, and binding rules.', + icon: 'CodeXml', + }, + 'oliphaunt-rust': { + description: 'Rust and Tauri SDK with direct, broker, and server runtime modes.', + icon: 'Laptop', + }, + 'oliphaunt-swift': { + description: 'Apple SDK for iOS and macOS apps using Swift concurrency.', + icon: 'Smartphone', + }, + 'oliphaunt-kotlin': { + description: 'Android SDK with coroutine-first APIs and exact native resource packaging.', + icon: 'Smartphone', + }, + 'oliphaunt-react-native': { + description: 'New Architecture package with Expo config plugin, TurboModule, and JSI bytes.', + icon: 'Layers', + }, + 'oliphaunt-js': { + description: 'TypeScript SDK for Node.js, Bun, and Deno.', + icon: 'Braces', + }, + 'oliphaunt-wasix-rust': { + description: 'Rust SDK for the portable WASIX runtime.', + icon: 'Boxes', + }, + 'oliphaunt-wasix-typescript': { + description: 'Portable TypeScript SDK for browsers, Node.js, Bun, Deno, and Electron.', + icon: 'Boxes', + }, +}; + +function metadataForRoute(route) { + const presentation = routePresentation[route.id] ?? {}; + return Object.fromEntries( + Object.entries(presentation).filter(([, value]) => value !== undefined), + ); +} + +function category(label, items) { + return { + type: 'category', + label, + items, + }; +} + +function sidebarPagesForRoute(route) { + return route.sidebar_pages ?? route.page_order ?? []; +} + +function orderedItemsForRoute(route, routeRecords) { + const available = new Set( + routeRecords + .filter( + (record) => + record.route === `/${route.route}` || record.route.startsWith(`/${route.route}/`), + ) + .map((record) => record.docId), + ); + const declared = sidebarPagesForRoute(route); + const declaredItems = declared.map((page) => itemForPage(route, page)); + if (declared.length > 0) { + return declaredItems.filter((item) => available.has(item)); + } + return [...available].sort((left, right) => left.localeCompare(right)); +} + +function writeJson(filePath, value) { + ensureDir(path.dirname(filePath)); + fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`); +} + +function uniqueInOrder(values) { + const seen = new Set(); + const output = []; + for (const value of values) { + if (!seen.has(value)) { + seen.add(value); + output.push(value); + } + } + return output; +} + +function pageOrderForFumadocs(route) { + return uniqueInOrder( + sidebarPagesForRoute(route).map((page) => { + const [first] = page.split('/'); + return first; + }), + ); +} + +function titleForPathSegment(segment) { + return segment + .split('-') + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(' '); +} + +function writeRouteMeta(route) { + const routeRoot = path.join(siteDocsRoot, route.route); + const metadata = { + title: route.title, + ...metadataForRoute(route), + pages: pageOrderForFumadocs(route), + }; + if (metadata.pages.includes('index')) { + metadata.pagesIndex = 'index'; + metadata.pages = metadata.pages.filter((page) => page !== 'index'); + } + if (route.kind === 'public') { + metadata.root = true; + metadata.description ??= `${route.title} documentation`; + } + writeJson(path.join(routeRoot, 'meta.json'), metadata); + + const nested = new Map(); + for (const page of sidebarPagesForRoute(route)) { + const parts = page.split('/'); + if (parts.length < 2) { + continue; + } + const [folder, child] = parts; + const children = nested.get(folder) ?? []; + children.push(child); + nested.set(folder, children); + } + + for (const [folder, pages] of nested) { + writeJson(path.join(routeRoot, folder, 'meta.json'), { + title: titleForPathSegment(folder), + pages: uniqueInOrder(pages), + }); + } +} + +function writeFumadocsMeta(manifest) { + const sdkRoutes = (manifest.routes ?? []).filter((route) => route.kind === 'sdk'); + writeJson(path.join(siteDocsRoot, 'meta.json'), { + title: 'Oliphaunt', + description: + 'Embedded PostgreSQL SDK documentation for native, Rust WASIX, and WASIX TypeScript apps.', + pages: ['start', 'sdk', 'learn', 'reference'], + }); + for (const route of manifest.routes ?? []) { + if (route.id !== 'sdk') { + writeRouteMeta(route); + } + } + writeJson(path.join(siteDocsRoot, 'sdk', 'meta.json'), { + title: 'SDKs', + description: routePresentation.sdk.description, + icon: routePresentation.sdk.icon, + root: true, + defaultOpen: routePresentation.sdk.defaultOpen, + pagesIndex: 'index', + pages: sdkRoutes.map((route) => route.route.replace(/^sdk\//u, '')), + }); +} + +function writeNavigationMetadata(manifest, routeRecords) { + const byId = new Map((manifest.routes ?? []).map((route) => [route.id, route])); + const sdkRoutes = (manifest.routes ?? []).filter((route) => route.kind === 'sdk'); + const navigation = { + docs: [ + 'start/index', + category('SDKs', [ + 'sdk/index', + ...sdkRoutes.map((route) => + category(route.title, orderedItemsForRoute(route, routeRecords)), + ), + ]), + category('Learn', orderedItemsForRoute(byId.get('learn'), routeRecords)), + category('Reference', orderedItemsForRoute(byId.get('reference'), routeRecords)), + ], + }; + writeJson(path.join(generatedMetaRoot, 'navigation.json'), navigation); + writeFumadocsMeta(manifest); +} + +function stripFrontmatter(markdown) { + return markdown.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/u, ''); +} + +function writeLlmFiles(routeRecords) { + ensureDir(staticRoot); + const summary = [ + '# Oliphaunt Docs', + '', + 'Oliphaunt is embedded PostgreSQL for native, Rust WASIX, and WASIX TypeScript apps.', + '', + '## Public routes', + ...routeRecords.map((record) => `- ${record.title}: ${record.route}`), + '', + ].join('\n'); + fs.writeFileSync(path.join(staticRoot, 'llms.txt'), summary); + + const full = routeRecords + .map((record) => { + const markdown = stripFrontmatter(readText(record.file)); + return `# ${record.title}\n\nRoute: ${record.route}\n\n${markdown}`; + }) + .join('\n\n---\n\n'); + fs.writeFileSync(path.join(staticRoot, 'llms-full.txt'), full); +} + +function currentGitSha() { + return process.env.OLIPHAUNT_DOCS_GIT_SHA || 'unknown'; +} + +export async function generateDocs() { + const manifest = parseTomlFile(manifestPath); + const products = await publishedProducts(manifest.routes); + resetDir(siteDocsRoot); + resetDir(staticRoot); + resetDir(generatedMetaRoot); + fs.writeFileSync( + path.join(generatedMetaRoot, 'published-products.json'), + JSON.stringify(products, null, 2) + '\n', + ); + const context = products; + for (const route of manifest.routes ?? []) { + copyRoutePages(route, context); + } + + fs.writeFileSync( + path.join(siteDocsRoot, 'reference', 'extension-catalog.md'), + generateExtensionCatalog(), + ); + const rows = Object.entries(products).map(([id, product]) => + product ? `| ${id} | [${product.version}](${product.url}) |` : `| ${id} | Not yet published |`, + ); + fs.writeFileSync( + path.join(siteDocsRoot, 'reference', 'version-matrix.md'), + '---\ntitle: Published products\n---\n\nThese guides describe the latest available products. Versions below come from completed public releases.\n\n| Product | Latest release |\n| --- | --- |\n' + + rows.join('\n') + + '\n', + ); + + const routeRecords = collectMarkdownFiles(siteDocsRoot).map((file) => { + const markdown = readText(file); + return { + route: markdownRouteFor(file), + docId: markdownDocIdFor(file), + title: + frontmatterValue(markdown, 'title') || + firstHeading(markdown, path.basename(file, path.extname(file))), + file, + source: path.relative(repoRoot, file), + }; + }); + + writeMetadata(routeRecords); + writeNavigationMetadata(manifest, routeRecords); + writeLlmFiles(routeRecords); + fs.writeFileSync( + path.join(generatedMetaRoot, 'build-metadata.json'), + `${JSON.stringify( + { + generatedAt: new Date().toISOString(), + gitSha: currentGitSha(), + routeCount: routeRecords.length, + }, + null, + 2, + )}\n`, + ); + + return { + manifest, + routeRecords, + paths: { + repoRoot, + docsRoot, + siteDocsRoot, + staticRoot, + generatedMetaRoot, + }, + }; +} + +if (import.meta.url === pathToFileURL(process.argv[1]).href) { + const result = await generateDocs(); + console.log(`generated ${result.routeRecords.length} docs routes`); +} diff --git a/src/docs/tools/publish-next-export.mjs b/src/docs/tools/publish-next-export.mjs deleted file mode 100644 index 5f4f7589a..000000000 --- a/src/docs/tools/publish-next-export.mjs +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env node -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const scriptDir = path.dirname(fileURLToPath(import.meta.url)); -const docsRoot = path.resolve(scriptDir, '..'); -const repoRoot = path.resolve(scriptDir, '../../..'); -const nextExportRoot = path.join(docsRoot, 'out'); -const generatedStaticRoot = path.join(repoRoot, 'target', 'docs', 'static'); -const buildRoot = path.join(repoRoot, 'target', 'docs', 'build'); - -function fail(message) { - console.error(message); - process.exit(1); -} - -if (!fs.existsSync(nextExportRoot)) { - fail('Next static export is missing; run next build before publishing docs output'); -} - -fs.rmSync(buildRoot, { force: true, recursive: true }); -fs.mkdirSync(path.dirname(buildRoot), { recursive: true }); -fs.cpSync(nextExportRoot, buildRoot, { force: true, recursive: true }); - -if (fs.existsSync(generatedStaticRoot)) { - fs.cpSync(generatedStaticRoot, buildRoot, { force: true, recursive: true }); -} - -console.log(`published docs static export to ${path.relative(repoRoot, buildRoot)}`); diff --git a/src/docs/tools/publish-next-export.mts b/src/docs/tools/publish-next-export.mts new file mode 100644 index 000000000..8139ad457 --- /dev/null +++ b/src/docs/tools/publish-next-export.mts @@ -0,0 +1,30 @@ +#!/usr/bin/env bun +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const docsRoot = path.resolve(scriptDir, '..'); +const repoRoot = path.resolve(scriptDir, '../../..'); +const nextExportRoot = path.join(docsRoot, 'out'); +const generatedStaticRoot = path.join(repoRoot, 'target', 'docs', 'static'); +const buildRoot = path.join(repoRoot, 'target', 'docs', 'build'); + +function fail(message) { + console.error(message); + process.exit(1); +} + +if (!fs.existsSync(nextExportRoot)) { + fail('Next static export is missing; run next build before publishing docs output'); +} + +fs.rmSync(buildRoot, { force: true, recursive: true }); +fs.mkdirSync(path.dirname(buildRoot), { recursive: true }); +fs.cpSync(nextExportRoot, buildRoot, { force: true, recursive: true }); + +if (fs.existsSync(generatedStaticRoot)) { + fs.cpSync(generatedStaticRoot, buildRoot, { force: true, recursive: true }); +} + +console.log(`published docs static export to ${path.relative(repoRoot, buildRoot)}`); diff --git a/src/docs/tools/published-products.mts b/src/docs/tools/published-products.mts new file mode 100644 index 000000000..20452b3ac --- /dev/null +++ b/src/docs/tools/published-products.mts @@ -0,0 +1,76 @@ +import fs from 'node:fs/promises'; + +const cache = new URL('../../../target/docs/published-releases.json', import.meta.url); + +export function selectProducts(releases, ids) { + return Object.fromEntries( + [...new Set(ids)].map((id) => { + const prefix = `${id}-v`; + const release = releases + .filter( + (entry) => + !entry.draft && + !entry.prerelease && + entry.published_at && + entry.tag_name.startsWith(prefix) && + /^\d+\.\d+\.\d+$/.test(entry.tag_name.slice(prefix.length)) && + entry.tag_name !== `${prefix}0.0.0`, + ) + .sort((a, b) => + Bun.semver.order(b.tag_name.slice(prefix.length), a.tag_name.slice(prefix.length)), + )[0]; + return [ + id, + release + ? { + version: release.tag_name.slice(prefix.length), + tag: release.tag_name, + url: release.html_url, + } + : null, + ]; + }), + ); +} + +export async function publishedProducts(routes) { + // Release ownership supplies identities only; candidate versions are never read. + const releaseConfig = JSON.parse( + await fs.readFile(new URL('../../../release-please-config.json', import.meta.url), 'utf8'), + ); + const ids = Object.values(releaseConfig.packages).map((product) => product.component); + // Offline builds must explicitly select a previously resolved input or fixture. + const input = process.env.OLIPHAUNT_DOCS_RELEASES_FILE; + let releases = input ? JSON.parse(await fs.readFile(input, 'utf8')) : []; + if (!input) { + for (let page = 1; ; page++) { + const response = await fetch( + `https://api.github.com/repos/f0rr0/oliphaunt/releases?per_page=100&page=${page}`, + { + signal: AbortSignal.timeout(30_000), + headers: { + Accept: 'application/vnd.github+json', + ...(process.env.GITHUB_TOKEN + ? { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } + : {}), + }, + }, + ); + if (!response.ok) + throw new Error( + `Cannot resolve published product versions: GitHub HTTP ${response.status}`, + ); + const batch = await response.json(); + releases.push(...batch); + if (batch.length < 100) break; + } + await fs.mkdir(new URL('./', cache), { recursive: true }); + await fs.writeFile(cache, JSON.stringify(releases, null, 2) + '\n'); + } + if (!Array.isArray(releases)) + throw new Error('Docs release input must be a GitHub releases array'); + return selectProducts(releases, [ + ...ids, + ...routes.flatMap((route) => (route.product_id ? [route.product_id] : [])), + ]); +} diff --git a/src/docs/tools/published-products.test.mts b/src/docs/tools/published-products.test.mts new file mode 100644 index 000000000..60c56fa46 --- /dev/null +++ b/src/docs/tools/published-products.test.mts @@ -0,0 +1,27 @@ +import { expect, test } from 'bun:test'; +import { selectProducts } from './published-products.mts'; + +test('installation versions use completed stable releases of the requested product', () => { + const release = (tag_name: string, extra = {}) => ({ + tag_name, + published_at: '2026-09-11T00:00:00Z', + html_url: `https://github.com/f0rr0/oliphaunt/releases/tag/${tag_name}`, + draft: false, + prerelease: false, + ...extra, + }); + const products = selectProducts( + [ + release('oliphaunt-kotlin-v0.2.0'), + release('oliphaunt-kotlin-v0.10.0'), + release('oliphaunt-kotlin-v9.0.0', { prerelease: true }), + release('oliphaunt-kotlin-v8.0.0', { draft: true }), + release('oliphaunt-kotlin-v7.0.0', { published_at: null }), + release('oliphaunt-swift-v0.0.0'), + release('unrelated-v99.0.0'), + ], + ['oliphaunt-kotlin', 'oliphaunt-swift'], + ); + expect(products['oliphaunt-kotlin']?.version).toBe('0.10.0'); + expect(products['oliphaunt-swift']).toBeNull(); +}); diff --git a/src/docs/tools/request-refresh.sh b/src/docs/tools/request-refresh.sh new file mode 100644 index 000000000..7d8a958e6 --- /dev/null +++ b/src/docs/tools/request-refresh.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +: "${VERCEL_DOCS_DEPLOY_HOOK:?Set VERCEL_DOCS_DEPLOY_HOOK in the protected Production environment to the oliphaunt.dev main-branch deploy hook}" +receipt="${1:?usage: request-refresh.sh RECEIPT_JSON}" +response="$(mktemp)" +trap 'rm -f "$response"' EXIT + +# Do not retry a POST with an ambiguous outcome: it may already have queued a build. +curl --fail --silent --show-error --max-time 30 --request POST \ + "$VERCEL_DOCS_DEPLOY_HOOK" --output "$response" +mkdir -p "$(dirname "$receipt")" +jq -e '{job: {id: .job.id, state: .job.state, createdAt: .job.createdAt}} + | select((.job.id | type) == "string" and (.job.id | length) > 0)' \ + "$response" > "$receipt" +printf 'Vercel accepted the docs refresh request. Deployment success has not been verified.\n' diff --git a/src/docs/tools/request-refresh.test.sh b/src/docs/tools/request-refresh.test.sh new file mode 100644 index 000000000..c99452e31 --- /dev/null +++ b/src/docs/tools/request-refresh.test.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +script="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/request-refresh.sh" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +mkdir "$scratch/bin" +cat > "$scratch/bin/curl" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +while [ "$1" != --output ]; do shift; done +printf '%s\n' "$HOOK_RESPONSE" > "$2" +SH +chmod +x "$scratch/bin/curl" +export PATH="$scratch/bin:$PATH" +export VERCEL_DOCS_DEPLOY_HOOK=https://invalid.example/test-only +export HOOK_RESPONSE='{"job":{"id":"accepted-job","state":"PENDING","createdAt":123}}' +bash "$script" "$scratch/receipt.json" +jq -e '.job.id == "accepted-job" and .job.state == "PENDING"' "$scratch/receipt.json" >/dev/null +HOOK_RESPONSE='{}' +if bash "$script" "$scratch/invalid.json"; then + echo 'Malformed hook acceptance unexpectedly succeeded' >&2; exit 1 +fi +if VERCEL_DOCS_DEPLOY_HOOK= bash "$script" "$scratch/missing.json" 2>/dev/null; then + echo 'Missing hook configuration unexpectedly succeeded' >&2; exit 1 +fi +printf 'Docs hook acceptance and failure handling passed (no network requests)\n' diff --git a/src/docs/tools/run-docs-task.mjs b/src/docs/tools/run-docs-task.mjs deleted file mode 100644 index 8604a63c8..000000000 --- a/src/docs/tools/run-docs-task.mjs +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env node -import { spawnSync } from 'node:child_process'; -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const scriptDir = path.dirname(fileURLToPath(import.meta.url)); -const docsRoot = path.resolve(scriptDir, '..'); -const repoRoot = path.resolve(scriptDir, '../../..'); -const generatedRoot = path.join(repoRoot, 'target', 'docs'); -const lockDir = path.join(generatedRoot, '.docs-task.lock'); -const lockMetadata = path.join(lockDir, 'owner.json'); -const lockTimeoutMs = Number.parseInt(process.env.OLIPHAUNT_DOCS_LOCK_TIMEOUT_MS ?? '120000', 10); - -function fail(message) { - console.error(message); - process.exit(1); -} - -function sleep(milliseconds) { - const buffer = new SharedArrayBuffer(4); - const view = new Int32Array(buffer); - Atomics.wait(view, 0, 0, milliseconds); -} - -function processIsAlive(pid) { - if (!Number.isInteger(pid) || pid <= 0) { - return false; - } - try { - process.kill(pid, 0); - return true; - } catch { - return false; - } -} - -function removeStaleLock() { - if (!fs.existsSync(lockDir)) { - return false; - } - try { - if (fs.existsSync(lockMetadata)) { - const metadata = JSON.parse(fs.readFileSync(lockMetadata, 'utf8')); - if (!processIsAlive(metadata.pid)) { - fs.rmSync(lockDir, { force: true, recursive: true }); - return true; - } - return false; - } - const stat = fs.statSync(lockDir); - if (Date.now() - stat.mtimeMs > lockTimeoutMs) { - fs.rmSync(lockDir, { force: true, recursive: true }); - return true; - } - } catch { - fs.rmSync(lockDir, { force: true, recursive: true }); - return true; - } - return false; -} - -function acquireLock() { - fs.mkdirSync(generatedRoot, { recursive: true }); - const started = Date.now(); - while (Date.now() - started <= lockTimeoutMs) { - try { - fs.mkdirSync(lockDir); - fs.writeFileSync( - lockMetadata, - `${JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() }, null, 2)}\n`, - ); - return () => fs.rmSync(lockDir, { force: true, recursive: true }); - } catch (error) { - if (error?.code !== 'EEXIST') { - throw error; - } - removeStaleLock(); - sleep(100); - } - } - fail(`timed out waiting for docs generation lock: ${path.relative(repoRoot, lockDir)}`); -} - -function run(command, args) { - const result = spawnSync(command, args, { - cwd: docsRoot, - env: process.env, - stdio: 'inherit', - }); - if (result.error) { - fail(`could not run ${command}: ${result.error.message}`); - } - if (result.status !== 0) { - process.exit(result.status ?? 1); - } -} - -const task = process.argv[2]; -const fumadocsMdx = ['pnpm', ['exec', 'fumadocs-mdx']]; -const checkFumadocsSource = ['node', ['tools/check-fumadocs-source.mjs']]; -const tasks = { - generate: [['node', ['tools/generate-content.mjs']], fumadocsMdx, checkFumadocsSource], - check: [ - ['node', ['tools/check-docs-product.mjs']], - fumadocsMdx, - checkFumadocsSource, - ['pnpm', ['exec', 'next', 'typegen']], - fumadocsMdx, - checkFumadocsSource, - ['pnpm', ['exec', 'tsc', '--noEmit']], - ], - build: [ - ['node', ['tools/check-docs-product.mjs']], - fumadocsMdx, - checkFumadocsSource, - ['pnpm', ['exec', 'next', 'build']], - fumadocsMdx, - checkFumadocsSource, - ['node', ['tools/publish-next-export.mjs']], - ], - 'release-check': [['node', ['tools/check-docs-product.mjs', '--release']]], -}; - -if (!Object.hasOwn(tasks, task)) { - fail(`usage: node tools/run-docs-task.mjs ${Object.keys(tasks).join('|')}`); -} - -const releaseLock = acquireLock(); -try { - for (const [command, args] of tasks[task]) { - run(command, args); - } -} finally { - releaseLock(); -} diff --git a/src/docs/tools/smoke-built-site.mjs b/src/docs/tools/smoke-built-site.mjs deleted file mode 100644 index 862951d3d..000000000 --- a/src/docs/tools/smoke-built-site.mjs +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env node -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const scriptDir = path.dirname(fileURLToPath(import.meta.url)); -const repoRoot = path.resolve(scriptDir, '../../..'); -const buildRoot = path.join(repoRoot, 'target', 'docs', 'build'); -const routesPath = path.join(repoRoot, 'target', 'docs', 'generated', 'routes.json'); - -function fail(message) { - console.error(message); - process.exit(1); -} - -function findFiles(root, predicate) { - const files = []; - function visit(dir) { - for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { - const fullPath = path.join(dir, entry.name); - if (entry.isDirectory()) { - visit(fullPath); - } else if (entry.isFile() && predicate(fullPath)) { - files.push(fullPath); - } - } - } - if (fs.existsSync(root)) { - visit(root); - } - return files; -} - -if (!fs.existsSync(buildRoot)) { - fail('docs build output is missing; run pnpm docs:build first'); -} - -if (!fs.existsSync(routesPath)) { - fail('generated docs route metadata is missing; run docs generation before smoke'); -} - -const htmlFiles = findFiles(buildRoot, (file) => file.endsWith('.html')); -if (htmlFiles.length === 0) { - fail('docs build produced no HTML files'); -} - -function routeHtmlPath(route) { - const normalized = route === '/' ? 'index' : route.replace(/^\/+/u, '').replace(/\/$/u, ''); - return path.join(buildRoot, normalized, 'index.html'); -} - -const routeMetadata = JSON.parse(fs.readFileSync(routesPath, 'utf8')); -for (const record of routeMetadata.routes ?? []) { - const route = record.route === '/' ? '/' : `/docs${record.route}`; - const htmlPath = routeHtmlPath(route); - if (!fs.existsSync(htmlPath)) { - fail( - `docs build did not export generated route ${route}: ${path.relative(repoRoot, htmlPath)}`, - ); - } -} - -const combined = htmlFiles.map((file) => fs.readFileSync(file, 'utf8')).join('\n'); -for (const phrase of ['Oliphaunt', 'Rust SDK', 'Extension Catalog', 'SQLite']) { - if (!combined.includes(phrase)) { - fail(`docs build output missing phrase: ${phrase}`); - } -} - -const disallowedHtml = [ - { label: 'directory listing', pattern: /Directory listing for/iu }, - { - label: 'removed upstream reference', - pattern: new RegExp(`\\b${'pg'}${'lite'}\\b`, 'iu'), - }, - { label: 'internal lane wording', pattern: /\blane\b/iu }, - { label: 'internal evidence wording', pattern: /\bevidence\b/iu }, - { label: 'future planning language', pattern: /\b(?:TODO|coming soon)\b/iu }, -]; -for (const file of htmlFiles) { - const html = fs.readFileSync(file, 'utf8'); - for (const rule of disallowedHtml) { - if (rule.pattern.test(html)) { - fail(`${path.relative(repoRoot, file)} contains ${rule.label}`); - } - } -} - -for (const staticFile of ['llms.txt', 'llms-full.txt']) { - const fullPath = path.join(buildRoot, staticFile); - if (!fs.existsSync(fullPath)) { - fail(`docs build did not publish ${staticFile}`); - } -} - -const faviconPath = path.join(buildRoot, 'img', 'favicon.svg'); -if (!fs.existsSync(faviconPath)) { - fail('docs build did not publish img/favicon.svg'); -} - -const hasFaviconLink = htmlFiles.some((file) => { - const html = fs.readFileSync(file, 'utf8'); - return /]+rel="(?:shortcut icon|icon)"[^>]+href="\/img\/favicon\.svg"/u.test(html); -}); -if (!hasFaviconLink) { - fail('docs build output is missing a favicon link'); -} - -console.log(`docs smoke passed (${htmlFiles.length} HTML files)`); diff --git a/src/docs/tools/smoke-built-site.mts b/src/docs/tools/smoke-built-site.mts new file mode 100644 index 000000000..e30f78be8 --- /dev/null +++ b/src/docs/tools/smoke-built-site.mts @@ -0,0 +1,70 @@ +#!/usr/bin/env bun +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(scriptDir, '../../..'); +const buildRoot = path.join(repoRoot, 'target', 'docs', 'build'); +const routesPath = path.join(repoRoot, 'target', 'docs', 'generated', 'routes.json'); + +function fail(message) { + console.error(message); + process.exit(1); +} + +function findFiles(root, predicate) { + const files = []; + function visit(dir) { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + visit(fullPath); + } else if (entry.isFile() && predicate(fullPath)) { + files.push(fullPath); + } + } + } + if (fs.existsSync(root)) { + visit(root); + } + return files; +} + +if (!fs.existsSync(buildRoot)) { + fail('docs build output is missing; run bun run build first'); +} + +if (!fs.existsSync(routesPath)) { + fail('generated docs route metadata is missing; run docs generation before smoke'); +} + +const htmlFiles = findFiles(buildRoot, (file) => file.endsWith('.html')); +if (htmlFiles.length === 0) { + fail('docs build produced no HTML files'); +} + +function routeHtmlPath(route) { + const normalized = route === '/' ? 'index' : route.replace(/^\/+/u, '').replace(/\/$/u, ''); + return path.join(buildRoot, normalized, 'index.html'); +} + +const routeMetadata = JSON.parse(fs.readFileSync(routesPath, 'utf8')); +for (const record of routeMetadata.routes ?? []) { + const route = record.route === '/' ? '/' : `/docs${record.route}`; + const htmlPath = routeHtmlPath(route); + if (!fs.existsSync(htmlPath)) { + fail( + `docs build did not export generated route ${route}: ${path.relative(repoRoot, htmlPath)}`, + ); + } +} + +for (const staticFile of ['llms.txt', 'llms-full.txt']) { + const fullPath = path.join(buildRoot, staticFile); + if (!fs.existsSync(fullPath)) { + fail(`docs build did not publish ${staticFile}`); + } +} + +console.log(`docs smoke passed (${htmlFiles.length} HTML files)`); diff --git a/src/docs/tools/verify-live.mts b/src/docs/tools/verify-live.mts new file mode 100644 index 000000000..1e60d732b --- /dev/null +++ b/src/docs/tools/verify-live.mts @@ -0,0 +1,62 @@ +import { readFile, writeFile } from 'node:fs/promises'; +import { publishedProducts } from './published-products.mts'; + +const pageUrl = 'https://oliphaunt.dev/docs/reference/version-matrix/'; +type Products = Record; + +// Verify what users can read, independently of a deployment provider's job status. +export function missingPublishedProducts(html: string, products: Products) { + const links = new Set( + [...html.matchAll(/\bhref\s*=\s*["']([^"']+)["']/g)].map((match) => match[1]), + ); + return Object.entries(products) + .filter(([, product]) => { + if (!product) return false; + const prefix = product.url.slice(0, -product.version.length); + // A later completed release may deploy while this refresh is waiting. + return ![...links].some( + (link) => + link.startsWith(prefix) && + /^\d+\.\d+\.\d+$/.test(link.slice(prefix.length)) && + Bun.semver.order(link.slice(prefix.length), product.version) >= 0, + ); + }) + .map(([id, product]) => `${id}@${product?.version}`); +} + +export async function verifyLive( + products: Products, + { timeoutMs = 600_000, fetchPage = fetch } = {}, +) { + const deadline = Date.now() + timeoutMs; + let failure = 'No response from the live documentation'; + do { + try { + const response = await fetchPage(pageUrl, { + cache: 'no-store', + signal: AbortSignal.timeout(Math.max(1, Math.min(30_000, deadline - Date.now()))), + }); + if (!response.ok) throw new Error(`Docs returned HTTP ${response.status}`); + const missing = missingPublishedProducts(await response.text(), products); + if (missing.length === 0) return; + failure = `Live docs do not yet advertise: ${missing.join(', ')}`; + } catch (error) { + failure = String(error); + } + if (Date.now() >= deadline) break; + await Bun.sleep(Math.min(10_000, deadline - Date.now())); + } while (Date.now() < deadline); + throw new Error(failure); +} + +if (import.meta.main) { + const [mode, file] = process.argv.slice(2); + if (!file || !['snapshot', 'verify'].includes(mode)) + throw new Error('usage: verify-live.mts snapshot|verify EXPECTED_PRODUCTS_JSON'); + if (mode === 'snapshot') { + await writeFile(file, `${JSON.stringify(await publishedProducts([]), null, 2)}\n`); + } else { + await verifyLive(JSON.parse(await readFile(file, 'utf8'))); + console.log('Live documentation advertises the expected completed public releases.'); + } +} diff --git a/src/docs/tools/verify-live.test.mts b/src/docs/tools/verify-live.test.mts new file mode 100644 index 000000000..0f8f9c1c8 --- /dev/null +++ b/src/docs/tools/verify-live.test.mts @@ -0,0 +1,29 @@ +import { expect, test } from 'bun:test'; +import { missingPublishedProducts, verifyLive } from './verify-live.mts'; + +test('live docs must link the released version, not merely mention it or expose an old release', async () => { + const url = 'https://github.com/f0rr0/oliphaunt/releases/tag/sdk-v2.0.0'; + const products = { sdk: { version: '2.0.0', url }, unpublished: null }; + expect( + missingPublishedProducts( + `

${url}

old`, + products, + ), + ).toEqual(['sdk@2.0.0']); + await verifyLive(products, { + timeoutMs: 1, + fetchPage: async () => new Response(`2.0.0`), + }); + expect( + missingPublishedProducts(`newer`, products), + ).toEqual([]); + await expect( + verifyLive(products, { timeoutMs: 1, fetchPage: async () => new Response('stale') }), + ).rejects.toThrow('sdk@2.0.0'); + await expect( + verifyLive(products, { + timeoutMs: 1, + fetchPage: async () => new Response('unavailable', { status: 503 }), + }), + ).rejects.toThrow('HTTP 503'); +}); diff --git a/src/examples/README.md b/src/examples/README.md new file mode 100644 index 000000000..ec9ad5f2f --- /dev/null +++ b/src/examples/README.md @@ -0,0 +1,63 @@ +# Oliphaunt Examples + +The desktop examples keep the same todo schema across shells: + +- `tauri`: Tauri v2 with the native Rust SDK. +- `tauri-wasix`: Tauri v2 with `oliphaunt-wasix` and SQLx. +- `electron`: Electron with the TypeScript SDK and native server mode. +- `electron-wasix`: Electron with a Rust WASIX sidecar exposing a PostgreSQL URL. + +Additional platform examples live here as well: + +- `browser-wasix`: the caller-realm root and explicit `/worker` WASIX + TypeScript entrypoints with browser storage. +- `react-native-expo`: the React Native SDK in an Expo development build. + +Each app opts into `hstore`, `pg_trgm`, and `unaccent`, then uses `hstore` +tags plus trigram/accent-insensitive search for the todo list. Native examples +load `postgres`, `initdb`, and `pg_ctl` from `liboliphaunt-native-*`. Native +tool carriers separately package `pg_basebackup`, `pg_dump`, and `psql`. +WASIX examples load `postgres` and `initdb` from the runtime crates and enable the +`oliphaunt-wasix` `tools` feature, which resolves `pg_dump`/`psql` from +`oliphaunt-wasix-tools`; WASIX intentionally has no `pg_ctl`. + +Example dependencies resolve from npm and crates.io. Cargo manifests pin the +current Oliphaunt release versions and do not commit nested lockfiles. + +Run the static Cargo manifest checks with: + +```sh +tools/dev/bun.sh tools/release/example-cargo-policy.mts --check +``` +The native examples exercise their configured database path during startup; +native tool compatibility is qualified separately against the local server. +The WASIX examples exercise the optional `tools` namespace only in their +explicit Rust smoke tests; ordinary application startup does not run or load +`pg_dump` or `psql`. + +Run Tauri GUI smoke tests through WebDriver on Linux: + +```sh +src/examples/tools/run-tauri-webdriver-smoke.sh src/examples/tauri +src/examples/tools/run-tauri-webdriver-smoke.sh src/examples/tauri-wasix +``` + +The WebDriver smoke builds the selected Tauri app in debug mode, launches it +through `tauri-driver`, creates a todo through the real UI, toggles it done, and +asserts the done filter. It expects `WebKitWebDriver`; on Debian/Ubuntu install +`webkit2gtk-driver`. In headless environments it uses `xvfb-run` when present. + +Run Electron GUI smoke tests on Linux: + +```sh +src/examples/tools/run-electron-driver-smoke.sh src/examples/electron +src/examples/tools/run-electron-driver-smoke.sh src/examples/electron-wasix +``` + +The Electron smoke builds the selected app, launches the packaged Electron +binary with an isolated profile, creates a todo through the real renderer, +toggles it done, and asserts the done filter. GNU `timeout` bounds the run to +210 seconds. In headless environments it uses `xvfb-run` when present. + +On Linux, SwiftPM artifacts are staged for inspection and skipped for registry +publish when `swift` is not installed. diff --git a/examples/assets/tauri-icon.png b/src/examples/assets/tauri-icon.png similarity index 100% rename from examples/assets/tauri-icon.png rename to src/examples/assets/tauri-icon.png diff --git a/src/examples/browser-wasix/README.md b/src/examples/browser-wasix/README.md new file mode 100644 index 000000000..24c6dc55d --- /dev/null +++ b/src/examples/browser-wasix/README.md @@ -0,0 +1,20 @@ +# Browser WASIX + +This example exercises both public execution surfaces: the direct caller-realm +root entrypoint and the explicit package-owned `/worker` entrypoint. It also +demonstrates IndexedDB and OPFS persistence and verifies that the root +constructs no hidden Worker. + +Build the runtime and the independently selected standard seed, then start the example: + +```sh +moon run liboliphaunt-wasix:runtime-portable database-resources:build-wasix-standard +bun run --cwd src/sdks/ts-wasix/sdk dev +``` + +`resources.ts` selects the seed served by the local asset middleware. New browser +storage needs this seed; reopening IndexedDB or OPFS needs only the runtime. + +The browser smoke and benchmark commands in `src/sdks/ts-wasix/sdk/package.json` +use the same example so there is only one browser integration surface to keep +current. diff --git a/examples/browser-wasix/benchmark.html b/src/examples/browser-wasix/benchmark.html similarity index 100% rename from examples/browser-wasix/benchmark.html rename to src/examples/browser-wasix/benchmark.html diff --git a/examples/browser-wasix/benchmark.ts b/src/examples/browser-wasix/benchmark.ts similarity index 99% rename from examples/browser-wasix/benchmark.ts rename to src/examples/browser-wasix/benchmark.ts index 9d851927e..6ada38929 100644 --- a/examples/browser-wasix/benchmark.ts +++ b/src/examples/browser-wasix/benchmark.ts @@ -1,8 +1,9 @@ import { PGlite } from '@electric-sql/pglite'; import { PGliteWorker } from '@electric-sql/pglite/worker'; import Oliphaunt from '@oliphaunt/wasix-ts'; -import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker'; import { opfs } from '@oliphaunt/wasix-ts/storage/opfs'; +import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker'; +import { standardSeed } from './resources.js'; type QueryParameters = readonly (null | string | number | boolean)[]; @@ -599,6 +600,7 @@ async function openWasix(executionSurface: OliphauntExecutionSurface): PromiseOliphaunt WASIX in a browser

Loading the WASIX runtime and PostgreSQL template…

- +

       
     
diff --git a/src/examples/browser-wasix/main.ts b/src/examples/browser-wasix/main.ts
new file mode 100644
index 000000000..00f9af44a
--- /dev/null
+++ b/src/examples/browser-wasix/main.ts
@@ -0,0 +1,651 @@
+import pgtap from '@oliphaunt/extension-pgtap-wasix';
+import Oliphaunt, {
+  type OliphauntDatabase,
+  PostgresError,
+  type QueryParam,
+  type WasixExtensionDescriptor,
+  type WasixStorage,
+  WasixStorageError,
+} from '@oliphaunt/wasix-ts';
+import { indexedDB } from '@oliphaunt/wasix-ts/storage/indexed-db';
+import { opfs } from '@oliphaunt/wasix-ts/storage/opfs';
+import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker';
+import { standardSeed } from './resources.js';
+
+import { expectStructuredApi } from './structured-api-smoke.js';
+
+const status = requireElement('status');
+const sql = requireElement('sql');
+const run = requireElement('run');
+const output = requireElement('output');
+const searchParams = new URL(globalThis.location.href).searchParams;
+const smoke = searchParams.has('smoke');
+const pgUuidv7Canary = searchParams.has('pg_uuidv7');
+const postgisWorkerCanary = searchParams.has('postgis_worker');
+const directWorkerAudit = smoke ? auditDirectWorkerConstruction() : undefined;
+
+try {
+  const extensions: WasixExtensionDescriptor[] = [pgtap];
+  if (pgUuidv7Canary) {
+    const { default: pgUuidv7 } = await import('@oliphaunt/extension-pg-uuidv7-wasix');
+    extensions.push(pgUuidv7);
+  }
+  if (smoke) {
+    expectOwnedMemoryCopyAcrossGrowth();
+    await expectFailedDirectOpenRecovery();
+  }
+  const storage = indexedDB('browser-smoke');
+  let database = await (smoke ? Oliphaunt : WorkerOliphaunt).open({
+    seed: standardSeed,
+    extensions,
+    ...(smoke ? { storage } : {}),
+  });
+  status.textContent = `PostgreSQL 18 is running through the ${smoke ? 'direct root' : 'Worker-owned'} entrypoint.`;
+  if (smoke) {
+    await installSelectedExtensions(database, extensions);
+    await expectStructuredApi(database, 'browser direct');
+    await expectConcurrentDirectExecution(database);
+    await expectExclusiveOwnership(storage, extensions, 'IndexedDB');
+    const pgtapVersion = await exercisePgtap(database);
+    const firstUuid = pgUuidv7Canary ? await readPgUuidv7(database) : undefined;
+    await database.queryRaw('CREATE TABLE browser_reopen_probe (answer integer NOT NULL)');
+    await database.queryRaw('INSERT INTO browser_reopen_probe VALUES (42)');
+    await database.execute('CHECKPOINT');
+    // This row is intentionally newer than the explicit checkpoint. Its query
+    // Promise includes an operation storage boundary; clean close also drains
+    // the journal before releasing ownership.
+    await database.queryRaw('INSERT INTO browser_reopen_probe VALUES (43)');
+    await expectSqlstate(database, 'SELEC 1', '42601');
+    await expectAnswer(database);
+    await expectSqlstate(database, 'SELECT 1 / $1::int', '22012', [0]);
+    await expectAnswer(database);
+    await expectTransaction(database);
+    await expectClockConsistency(database);
+    const recoveredPgtapVersion = await readPgtapVersion(database);
+    if (recoveredPgtapVersion !== pgtapVersion) {
+      throw new Error('browser smoke observed a different pgtap version after recovery');
+    }
+    if (pgUuidv7Canary) {
+      await readPgUuidv7(database);
+    }
+    await database.close();
+
+    directWorkerAudit?.assertNoneAndRestore();
+    await expectDirectWithoutWorker();
+    await expectFailedWorkerOpenRecovery();
+
+    database = await WorkerOliphaunt.open({ storage, extensions });
+    await expectStructuredApi(database, 'browser Worker');
+    await expectSqlstate(database, 'SELEC 1', '42601');
+    await expectAnswer(database);
+    await expectSqlstate(database, 'SELECT 1 / $1::int', '22012', [0]);
+    await expectAnswer(database);
+    await expectOwnedRawProtocolResponse(database);
+    await expectClockConsistency(database);
+    const reopened = await database.queryRaw(
+      'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM browser_reopen_probe',
+      [','],
+    );
+    if (reopened.getText(0, 'answers') !== '42,43') {
+      throw new Error('browser smoke did not reopen operation-persisted PGDATA');
+    }
+    if ((await readPgtapVersion(database)) !== pgtapVersion) {
+      throw new Error('browser smoke did not reconstruct the selected pgtap carrier on reopen');
+    }
+    if (pgUuidv7Canary) {
+      await readPgUuidv7(database);
+    }
+    await database.close();
+    const opfsAnswers = await expectOpfsPersistence(extensions);
+    const opfsCrash = await expectOpfsCrashRecovery();
+    const postgisVersion = postgisWorkerCanary ? await expectLargePostgisWorkerModule() : undefined;
+    status.textContent = 'Browser smoke passed.';
+    output.textContent = JSON.stringify({
+      answers: [42, 43],
+      opfsAnswers,
+      pgtap: pgtapVersion,
+      startupSqlstate: '3D000',
+      directWorkers: 0,
+      opfsTransport: 'synchronous-access',
+      opfsCrashAnswer: opfsCrash.answer,
+      opfsCrashRelations: opfsCrash.relations,
+      ...(firstUuid === undefined ? {} : { pg_uuidv7: firstUuid }),
+      ...(postgisVersion === undefined ? {} : { postgis: postgisVersion }),
+    });
+    document.documentElement.dataset.oliphauntSmoke = 'passed';
+  } else {
+    run.disabled = false;
+    run.addEventListener('click', async () => {
+      run.disabled = true;
+      output.textContent = '';
+      try {
+        const result = await database.queryRaw(sql.value);
+        output.textContent = JSON.stringify(
+          result.rows.map((row) =>
+            Object.fromEntries(result.fields.map((field, index) => [field.name, row.text(index)])),
+          ),
+          null,
+          2,
+        );
+      } catch (error) {
+        output.textContent = describeError(error);
+      } finally {
+        run.disabled = false;
+      }
+    });
+  }
+} catch (error) {
+  status.textContent = 'Startup failed.';
+  output.textContent = describeError(error);
+  document.documentElement.dataset.oliphauntSmoke = 'failed';
+} finally {
+  directWorkerAudit?.restore();
+}
+
+function simpleQuery(sql: string): Uint8Array {
+  if (sql.includes('\0')) throw new Error('simple query SQL must not contain NUL bytes');
+  const body = new TextEncoder().encode(`${sql}\0`);
+  const message = new Uint8Array(body.length + 5);
+  message[0] = 0x51;
+  new DataView(message.buffer).setUint32(1, body.length + 4);
+  message.set(body, 5);
+  return message;
+}
+
+async function expectLargePostgisWorkerModule(): Promise {
+  const { default: postgis } = await import('@oliphaunt/extension-postgis-wasix');
+  const dependencyModule = postgis.carriers
+    .flatMap((carrier) => carrier.install.nativeModules)
+    .find((module) => module.name === 'postgis_deps');
+  if (dependencyModule === undefined || dependencyModule.size <= 8 * 1024 * 1024) {
+    throw new Error('browser worker canary requires a PostGIS side module larger than 8 MiB');
+  }
+
+  const database = await WorkerOliphaunt.open({ seed: standardSeed, extensions: [postgis] });
+  try {
+    await database.execute('CREATE EXTENSION postgis');
+    const version = await readPostgisVersion(database);
+    await database.queryRaw('CREATE TEMP TABLE postgis_nested_error_catch(value integer)');
+    await database.queryRaw(
+      `DO $$ BEGIN
+         BEGIN
+           PERFORM ST_GeomFromText('POINT(');
+         EXCEPTION WHEN OTHERS THEN
+           INSERT INTO postgis_nested_error_catch VALUES (1);
+         END;
+       END $$`,
+    );
+    const caught = await database.queryRaw(
+      'SELECT count(*)::int AS count FROM postgis_nested_error_catch',
+    );
+    if (caught.getText(0, 'count') !== '1') {
+      throw new Error('browser worker did not catch an error crossing PostGIS side modules');
+    }
+    try {
+      await database.queryRaw("SELECT ST_GeomFromText('POINT(')");
+      throw new Error('browser worker expected malformed PostGIS geometry to fail');
+    } catch (error) {
+      if (!(error instanceof PostgresError)) {
+        throw error;
+      }
+    }
+    if ((await readPostgisVersion(database)) !== version) {
+      throw new Error('browser worker did not recover its PostGIS session after an error');
+    }
+    return version;
+  } finally {
+    await database.close();
+  }
+}
+
+async function readPostgisVersion(database: OliphauntDatabase): Promise {
+  const result = await database.queryRaw('SELECT postgis_full_version()::text AS version');
+  const version = result.getText(0, 'version');
+  if (version === null || !version.includes('POSTGIS=')) {
+    throw new Error(
+      `browser worker returned an invalid PostGIS version: ${JSON.stringify(version)}`,
+    );
+  }
+  return version;
+}
+
+function expectOwnedMemoryCopyAcrossGrowth(): void {
+  const memory = new WebAssembly.Memory({ initial: 1, maximum: 2 });
+  const guest = new Uint8Array(memory.buffer, 0, 4);
+  guest.set([1, 2, 3, 4]);
+  const owned = guest.slice();
+  const previousBuffer = memory.buffer;
+  memory.grow(1);
+  if (memory.buffer === previousBuffer) {
+    throw new Error('WebAssembly memory growth did not replace its backing buffer');
+  }
+  new Uint8Array(memory.buffer, 0, 4).fill(9);
+  if (!owned.every((byte, index) => byte === index + 1)) {
+    throw new Error('owned protocol bytes changed after explicit WebAssembly memory growth');
+  }
+}
+
+async function expectConcurrentDirectExecution(first: OliphauntDatabase): Promise {
+  const attempts = await Promise.allSettled([
+    Oliphaunt.open({ seed: standardSeed }),
+    Oliphaunt.open({ seed: standardSeed }),
+  ]);
+  const opened = attempts.flatMap((attempt) =>
+    attempt.status === 'fulfilled' ? [attempt.value] : [],
+  );
+  const failed = attempts.find(
+    (attempt): attempt is PromiseRejectedResult => attempt.status === 'rejected',
+  );
+  if (failed !== undefined) {
+    await Promise.allSettled(opened.map((database) => database.close()));
+    throw failed.reason;
+  }
+  const [second, third] = opened;
+  if (second === undefined || third === undefined) {
+    throw new Error('direct concurrent-open smoke produced an incomplete result');
+  }
+  try {
+    await expectAnswer(first);
+    await expectAnswer(second);
+    await expectAnswer(third);
+  } finally {
+    await Promise.all([second.close(), third.close()]);
+  }
+}
+
+async function expectDirectWithoutWorker(): Promise {
+  const workerDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'Worker');
+  Object.defineProperty(globalThis, 'Worker', {
+    configurable: true,
+    writable: true,
+    value: undefined,
+  });
+  try {
+    const database = await Oliphaunt.open({ seed: standardSeed });
+    try {
+      await expectAnswer(database);
+      await expectOwnedRawProtocolResponse(database);
+    } finally {
+      await database.close();
+    }
+  } finally {
+    if (workerDescriptor === undefined) {
+      Reflect.deleteProperty(globalThis, 'Worker');
+    } else {
+      Object.defineProperty(globalThis, 'Worker', workerDescriptor);
+    }
+  }
+}
+
+async function expectTransaction(database: OliphauntDatabase): Promise {
+  const answer = await database.transaction(async (transaction) => {
+    const result = await transaction.queryRaw('SELECT $1::int + 1 AS answer', [41]);
+    return result.getText(0, 'answer');
+  });
+  if (answer !== '42') {
+    throw new Error(`browser smoke transaction expected 42, received ${JSON.stringify(answer)}`);
+  }
+}
+
+async function expectOwnedRawProtocolResponse(database: OliphauntDatabase): Promise {
+  const retained = await database.execProtocolRaw(
+    simpleQuery("SELECT repeat('a', 10240) AS retained_payload"),
+  );
+  const snapshot = retained.slice();
+  const large = await database.execProtocolRaw(
+    simpleQuery("SELECT repeat('z', 1048576) AS large_payload"),
+  );
+  if (large.byteLength < 1048576) {
+    throw new Error(
+      `browser worker returned a truncated large PGWire response: ${large.byteLength}`,
+    );
+  }
+  if (
+    retained.byteLength !== snapshot.byteLength ||
+    !retained.every((byte, index) => byte === snapshot[index])
+  ) {
+    throw new Error('browser worker response changed after the guest reused its output memory');
+  }
+}
+
+async function expectClockConsistency(database: OliphauntDatabase): Promise {
+  const wallClock = await database.queryRaw(
+    'SELECT (extract(epoch FROM clock_timestamp()) * 1000)::bigint AS millis',
+  );
+  const wallClockMillis = Number(wallClock.getText(0, 'millis'));
+  if (!Number.isFinite(wallClockMillis) || Math.abs(Date.now() - wallClockMillis) > 5_000) {
+    throw new Error(`browser WASI realtime clock drifted: ${wallClockMillis}`);
+  }
+  const plan = await database.queryRaw('EXPLAIN (ANALYZE, FORMAT JSON) SELECT pg_sleep(0.05)');
+  const explain = JSON.parse(plan.getText(0, 'QUERY PLAN') ?? 'null');
+  const elapsed = explain?.[0]?.['Execution Time'];
+  if (!Number.isFinite(elapsed) || elapsed < 25 || elapsed > 5_000) {
+    throw new Error(`browser WASI monotonic clock returned invalid elapsed time: ${elapsed}`);
+  }
+}
+
+async function expectStartupSqlstate(
+  database: string,
+  sqlstate: string,
+  client: typeof Oliphaunt,
+): Promise {
+  try {
+    const unexpected = await client.open({ seed: standardSeed, database });
+    await unexpected.close();
+    throw new Error(
+      `browser smoke unexpectedly opened missing database ${JSON.stringify(database)}`,
+    );
+  } catch (error) {
+    if (
+      !(error instanceof PostgresError) ||
+      error.sqlstate !== sqlstate ||
+      error.severity !== 'FATAL'
+    ) {
+      throw error;
+    }
+  }
+}
+
+async function expectFailedDirectOpenRecovery(): Promise {
+  await expectStartupSqlstate('oliphaunt_browser_smoke_missing_database', '3D000', Oliphaunt);
+  const reopened = await Oliphaunt.open({ seed: standardSeed });
+  try {
+    await expectAnswer(reopened);
+  } finally {
+    await reopened.close();
+  }
+}
+
+async function expectFailedWorkerOpenRecovery(): Promise {
+  await expectStartupSqlstate(
+    'oliphaunt_browser_worker_missing_database',
+    '3D000',
+    WorkerOliphaunt,
+  );
+  const reopened = await WorkerOliphaunt.open({ seed: standardSeed });
+  try {
+    await expectAnswer(reopened);
+  } finally {
+    await reopened.close();
+  }
+}
+
+async function expectExclusiveOwnership(
+  storage: WasixStorage,
+  extensions: readonly WasixExtensionDescriptor[],
+  provider: string,
+): Promise {
+  try {
+    const duplicate = await Oliphaunt.open({ seed: standardSeed, storage, extensions });
+    await duplicate.close();
+    throw new Error(`browser smoke opened one ${provider} database twice`);
+  } catch (error) {
+    if (!(error instanceof WasixStorageError) || error.code !== 'busy') {
+      throw error;
+    }
+  }
+}
+
+async function expectOpfsPersistence(
+  extensions: readonly WasixExtensionDescriptor[],
+): Promise {
+  const storage = opfs('browser-smoke');
+  let database = await Oliphaunt.open({ seed: standardSeed, storage, extensions });
+  await expectExclusiveOwnership(storage, extensions, 'OPFS');
+  await database.queryRaw('CREATE TABLE opfs_reopen_probe (answer integer NOT NULL)');
+  await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (1)');
+  // PostgreSQL normally retains the relation and WAL descriptors. This second
+  // operation proves that the host journal observes writes after initial open.
+  await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (2)');
+  await database.close();
+
+  database = await WorkerOliphaunt.open({ storage, extensions });
+  try {
+    await expectSynchronousOpfsTransport('browser-smoke');
+    const reopened = await database.queryRaw(
+      'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM opfs_reopen_probe',
+      [','],
+    );
+    const answers = reopened.getText(0, 'answers');
+    if (answers !== '1,2') {
+      throw new Error(`browser smoke did not reopen OPFS state: ${answers}`);
+    }
+    await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (3)');
+    await database.queryRaw('CREATE TABLE opfs_sync_create_probe (answer integer NOT NULL)');
+    await database.queryRaw('INSERT INTO opfs_sync_create_probe VALUES (99)');
+    await database.execute('CHECKPOINT');
+  } finally {
+    await database.close();
+  }
+
+  database = await Oliphaunt.open({ storage, extensions });
+  try {
+    const reopened = await database.queryRaw(
+      'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM opfs_reopen_probe',
+      [','],
+    );
+    const answers = reopened.getText(0, 'answers');
+    if (answers !== '1,2,3') {
+      throw new Error(`browser smoke did not reopen synchronous OPFS writes: ${answers}`);
+    }
+    const created = await database.queryRaw('SELECT answer FROM opfs_sync_create_probe');
+    if (created.getText(0, 'answer') !== '99') {
+      throw new Error('browser smoke did not reopen a relation created through synchronous OPFS');
+    }
+    return answers;
+  } finally {
+    await database.close();
+  }
+}
+
+async function expectSynchronousOpfsTransport(name: string): Promise {
+  const worker = new Worker(new URL('./opfs-transport-probe-worker.ts', import.meta.url), {
+    type: 'module',
+  });
+  try {
+    const response = await new Promise<
+      { ok: true; transport: 'synchronous-access' | 'portable' } | { ok: false; error: string }
+    >((resolve, reject) => {
+      const timeout = setTimeout(() => reject(new Error('OPFS transport probe timed out')), 10_000);
+      worker.addEventListener(
+        'error',
+        (event) => {
+          clearTimeout(timeout);
+          reject(event.error ?? new Error(event.message));
+        },
+        { once: true },
+      );
+      worker.addEventListener(
+        'message',
+        (event: MessageEvent) => {
+          clearTimeout(timeout);
+          resolve(
+            event.data as
+              | { ok: true; transport: 'synchronous-access' | 'portable' }
+              | { ok: false; error: string },
+          );
+        },
+        { once: true },
+      );
+      worker.postMessage({ name });
+    });
+    if (!response.ok) throw new Error(`OPFS transport probe failed: ${response.error}`);
+    if (response.transport !== 'synchronous-access') {
+      throw new Error(
+        'browser smoke selected portable OPFS instead of the synchronous-access Worker path',
+      );
+    }
+  } finally {
+    worker.terminate();
+  }
+}
+
+async function expectOpfsCrashRecovery(): Promise> {
+  const name = `browser-crash-${crypto.randomUUID()}`;
+  const worker = new Worker(new URL('./opfs-crash-probe-worker.ts', import.meta.url), {
+    type: 'module',
+  });
+  try {
+    const response = await new Promise<
+      Readonly<{ ok: true }> | Readonly<{ ok: false; error: string }>
+    >((resolve, reject) => {
+      const timeout = setTimeout(
+        () => reject(new Error('OPFS crash-recovery setup timed out')),
+        60_000,
+      );
+      worker.addEventListener(
+        'error',
+        (event) => {
+          clearTimeout(timeout);
+          reject(event.error ?? new Error(event.message));
+        },
+        { once: true },
+      );
+      worker.addEventListener(
+        'message',
+        (event: MessageEvent) => {
+          clearTimeout(timeout);
+          resolve(event.data as Readonly<{ ok: true }> | Readonly<{ ok: false; error: string }>);
+        },
+        { once: true },
+      );
+      worker.postMessage({ name });
+    });
+    if (!response.ok) throw new Error(`OPFS crash-recovery setup failed: ${response.error}`);
+  } finally {
+    worker.terminate();
+  }
+
+  const database = await Oliphaunt.open({ seed: standardSeed, storage: opfs(name) });
+  try {
+    const result = await database.queryRaw('SELECT answer FROM opfs_crash_probe');
+    const answer = result.getText(0, 'answer');
+    if (answer !== '73') {
+      throw new Error(`OPFS crash recovery returned an unexpected answer: ${answer}`);
+    }
+    const relationResult = await database.queryRaw(`
+      SELECT count(*)::text AS count
+      FROM pg_class
+      WHERE relname LIKE 'opfs_crash_burst_%'
+    `);
+    const relations = relationResult.getText(0, 'count');
+    if (relations !== '48') {
+      throw new Error(`OPFS crash recovery returned an unexpected relation count: ${relations}`);
+    }
+    return { answer, relations };
+  } finally {
+    await database.close();
+  }
+}
+
+async function exercisePgtap(database: OliphauntDatabase): Promise {
+  const version = await readPgtapVersion(database);
+  const plan = await database.queryRaw('SELECT plan(1)::text AS tap');
+  if (plan.getText(0, 'tap') !== '1..1') {
+    throw new Error('browser smoke expected pgtap plan(1) to return 1..1');
+  }
+  const assertion = await database.queryRaw("SELECT ok(true, 'browser pgtap')::text AS tap");
+  if (assertion.getText(0, 'tap') !== 'ok 1 - browser pgtap') {
+    throw new Error('browser smoke expected pgtap ok() to report a passing assertion');
+  }
+  await database.queryRaw('SELECT * FROM finish()');
+  return version;
+}
+
+async function installSelectedExtensions(
+  database: OliphauntDatabase,
+  extensions: readonly WasixExtensionDescriptor[],
+): Promise {
+  for (const extension of extensions) {
+    const sqlName = `"${extension.sqlName.replaceAll('"', '""')}"`;
+    await database.execute(`CREATE EXTENSION IF NOT EXISTS ${sqlName}`);
+  }
+}
+
+async function readPgtapVersion(database: OliphauntDatabase): Promise {
+  const pgtap = await database.queryRaw('SELECT pgtap_version()::text AS version');
+  const version = pgtap.getText(0, 'version');
+  if (version === null || version.length === 0) {
+    throw new Error('browser smoke expected pgtap_version() to return a version');
+  }
+  return version;
+}
+
+async function readPgUuidv7(database: OliphauntDatabase): Promise {
+  const result = await database.queryRaw('SELECT uuid_generate_v7()::text AS uuid');
+  const uuid = result.getText(0, 'uuid');
+  if (
+    uuid === null ||
+    !/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(uuid)
+  ) {
+    throw new Error(`browser smoke expected a version 7 UUID, received ${JSON.stringify(uuid)}`);
+  }
+  return uuid;
+}
+
+async function expectSqlstate(
+  database: OliphauntDatabase,
+  query: string,
+  sqlstate: string,
+  parameters: ReadonlyArray = [],
+): Promise {
+  try {
+    await database.queryRaw(query, parameters);
+    throw new Error(`browser smoke expected SQLSTATE ${sqlstate}`);
+  } catch (error) {
+    if (!(error instanceof PostgresError) || error.sqlstate !== sqlstate) {
+      throw error;
+    }
+  }
+}
+
+async function expectAnswer(database: OliphauntDatabase): Promise {
+  const result = await database.queryRaw('SELECT 40 + 2 AS answer');
+  const answer = result.getText(0, 'answer');
+  if (answer !== '42') {
+    throw new Error(`browser smoke expected 42, received ${JSON.stringify(answer)}`);
+  }
+}
+
+function requireElement(id: string): ElementType {
+  const element = document.getElementById(id);
+  if (element === null) {
+    throw new Error(`missing #${id}`);
+  }
+  return element as ElementType;
+}
+
+function describeError(error: unknown): string {
+  return error instanceof Error ? (error.stack ?? error.message) : String(error);
+}
+
+function auditDirectWorkerConstruction(): {
+  assertNoneAndRestore(): void;
+  restore(): void;
+} {
+  const NativeWorker = globalThis.Worker;
+  let constructed = 0;
+  let restored = false;
+  class AuditedWorker extends NativeWorker {
+    constructor(scriptURL: string | URL, options?: WorkerOptions) {
+      constructed += 1;
+      super(scriptURL, options);
+    }
+  }
+  globalThis.Worker = AuditedWorker;
+  const restore = () => {
+    if (!restored) {
+      globalThis.Worker = NativeWorker;
+      restored = true;
+    }
+  };
+  return {
+    assertNoneAndRestore() {
+      restore();
+      if (constructed !== 0) {
+        throw new Error(`root entrypoint constructed ${constructed} Web Worker(s)`);
+      }
+    },
+    restore,
+  };
+}
diff --git a/examples/browser-wasix/opfs-crash-probe-worker.ts b/src/examples/browser-wasix/opfs-crash-probe-worker.ts
similarity index 92%
rename from examples/browser-wasix/opfs-crash-probe-worker.ts
rename to src/examples/browser-wasix/opfs-crash-probe-worker.ts
index eea427fff..7b2e47ea6 100644
--- a/examples/browser-wasix/opfs-crash-probe-worker.ts
+++ b/src/examples/browser-wasix/opfs-crash-probe-worker.ts
@@ -1,5 +1,6 @@
 import Oliphaunt, { type OliphauntDatabase } from '@oliphaunt/wasix-ts';
 import { opfs } from '@oliphaunt/wasix-ts/storage/opfs';
+import { standardSeed } from './resources.js';
 
 type ProbeRequest = Readonly<{ name: string }>;
 type ProbeResponse = Readonly<{ ok: true }> | Readonly<{ ok: false; error: string }>;
@@ -14,7 +15,7 @@ scope.addEventListener('message', (event: MessageEvent) => {
 });
 
 async function prepareDurableState(name: string): Promise {
-  database = await Oliphaunt.open({ storage: opfs(name) });
+  database = await Oliphaunt.open({ seed: standardSeed, storage: opfs(name) });
   await database.queryRaw('CREATE TABLE opfs_crash_probe (answer integer NOT NULL)');
   await database.queryRaw('INSERT INTO opfs_crash_probe VALUES (73)');
   await database.queryRaw(`
diff --git a/examples/browser-wasix/opfs-transport-probe-worker.ts b/src/examples/browser-wasix/opfs-transport-probe-worker.ts
similarity index 100%
rename from examples/browser-wasix/opfs-transport-probe-worker.ts
rename to src/examples/browser-wasix/opfs-transport-probe-worker.ts
diff --git a/src/examples/browser-wasix/package-smoke.ts b/src/examples/browser-wasix/package-smoke.ts
new file mode 100644
index 000000000..08aaa5c83
--- /dev/null
+++ b/src/examples/browser-wasix/package-smoke.ts
@@ -0,0 +1,116 @@
+import seedArchive from '@oliphaunt/seed-wasix-standard/seed.tar.zst?url';
+import seedManifest from '@oliphaunt/seed-wasix-standard/manifest.json?url';
+import icuSeedArchive from '@oliphaunt/seed-wasix-icu/seed.tar.zst?url';
+import icuSeedManifest from '@oliphaunt/seed-wasix-icu/manifest.json?url';
+import icuData from '@oliphaunt/icu/data?url';
+import icuManifest from '@oliphaunt/icu/manifest?url';
+import pgtap from '@oliphaunt/extension-pgtap-wasix';
+import Oliphaunt, { type OliphauntDatabase } from '@oliphaunt/wasix-ts';
+import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker';
+import { indexedDB } from '@oliphaunt/wasix-ts/storage/indexed-db';
+
+import { expectStructuredApi } from './structured-api-smoke.js';
+
+const status = requireElement('status');
+const output = requireElement('output');
+
+try {
+  const storage = indexedDB('packed-browser-smoke');
+  let database = await Oliphaunt.open({
+    storage,
+    seed: { archive: seedArchive, manifest: seedManifest },
+    extensions: [pgtap],
+  });
+  let pgtapVersion: string;
+  try {
+    await database.execute('CREATE EXTENSION pgtap');
+    await expectAnswer(database);
+    await expectStructuredApi(database, 'packed browser direct');
+    pgtapVersion = await readPgtapVersion(database);
+    await database.transaction(async (transaction) => {
+      await transaction.execute('CREATE TABLE packed_reopen_probe (answer integer NOT NULL)');
+      await transaction.execute('INSERT INTO packed_reopen_probe VALUES ($1)', [42]);
+    });
+    await database.execute('CHECKPOINT');
+  } finally {
+    await database.close();
+  }
+
+  database = await WorkerOliphaunt.open({
+    storage,
+    extensions: [pgtap],
+  });
+  try {
+    await expectAnswer(database);
+    await expectStructuredApi(database, 'packed browser Worker');
+    const reopened = await database.queryRaw('SELECT answer FROM packed_reopen_probe');
+    const answer = reopened.getText(0, 'answer');
+    if (answer !== '42') {
+      throw new Error(`packed browser package did not reopen IndexedDB state: ${answer}`);
+    }
+    if ((await readPgtapVersion(database)) !== pgtapVersion) {
+      throw new Error('packed browser package changed its pgtap carrier on worker reopen');
+    }
+    await database.transaction(async (transaction) => {
+      await transaction.execute('INSERT INTO packed_reopen_probe VALUES ($1)', [43]);
+    });
+    const count = (
+      await database.queryRaw('SELECT count(*) AS count FROM packed_reopen_probe')
+    ).getText(0, 'count');
+    if (count !== '2') {
+      throw new Error(`packed browser worker transaction produced ${count} rows`);
+    }
+    await database.execute('CHECKPOINT');
+    const icuDatabase = await Oliphaunt.open({
+      seed: { archive: icuSeedArchive, manifest: icuSeedManifest },
+      icu: { data: icuData, manifest: icuManifest },
+    });
+    try {
+      const ordered = await icuDatabase.queryRaw(
+        `SELECT string_agg(value, ',' ORDER BY value COLLATE "en-x-icu") AS value FROM (VALUES ('z'), ('a'), (chr(228))) AS input(value)`,
+      );
+      if (ordered.getText(0, 'value') !== 'a,ä,z')
+        throw new Error('selected ICU resources did not provide ICU collation');
+    } finally {
+      await icuDatabase.close();
+    }
+    status.textContent = 'Packed browser package smoke passed.';
+    output.textContent = JSON.stringify({
+      direct: 42,
+      worker: 42,
+      indexedDB: answer,
+      transactionRows: count,
+      pgtap: pgtapVersion,
+    });
+    document.documentElement.dataset.oliphauntSmoke = 'passed';
+  } finally {
+    await database.close();
+  }
+} catch (error) {
+  status.textContent = 'Packed browser package smoke failed.';
+  output.textContent = error instanceof Error ? (error.stack ?? error.message) : String(error);
+  document.documentElement.dataset.oliphauntSmoke = 'failed';
+}
+
+async function expectAnswer(database: OliphauntDatabase): Promise {
+  const result = await database.queryRaw('SELECT 40 + 2 AS answer');
+  const answer = result.getText(0, 'answer');
+  if (answer !== '42') {
+    throw new Error(`packed browser package expected 42, received ${JSON.stringify(answer)}`);
+  }
+}
+
+async function readPgtapVersion(database: OliphauntDatabase): Promise {
+  const result = await database.queryRaw('SELECT pgtap_version()::text AS version');
+  const version = result.getText(0, 'version');
+  if (version === null || version.length === 0) {
+    throw new Error('packed browser package returned no pgtap version');
+  }
+  return version;
+}
+
+function requireElement(id: string): ElementType {
+  const element = document.getElementById(id);
+  if (element === null) throw new Error(`missing #${id}`);
+  return element as ElementType;
+}
diff --git a/examples/browser-wasix/package.json b/src/examples/browser-wasix/package.json
similarity index 100%
rename from examples/browser-wasix/package.json
rename to src/examples/browser-wasix/package.json
diff --git a/examples/browser-wasix/pglite-worker.ts b/src/examples/browser-wasix/pglite-worker.ts
similarity index 100%
rename from examples/browser-wasix/pglite-worker.ts
rename to src/examples/browser-wasix/pglite-worker.ts
diff --git a/src/examples/browser-wasix/resources.ts b/src/examples/browser-wasix/resources.ts
new file mode 100644
index 000000000..ec5425ab1
--- /dev/null
+++ b/src/examples/browser-wasix/resources.ts
@@ -0,0 +1,4 @@
+export const standardSeed = {
+  archive: '/wasix-assets/cluster-seed-standard',
+  manifest: '/wasix-assets/cluster-seed-standard-manifest',
+};
diff --git a/examples/browser-wasix/structured-api-smoke.ts b/src/examples/browser-wasix/structured-api-smoke.ts
similarity index 100%
rename from examples/browser-wasix/structured-api-smoke.ts
rename to src/examples/browser-wasix/structured-api-smoke.ts
diff --git a/src/examples/browser-wasix/tsconfig.json b/src/examples/browser-wasix/tsconfig.json
new file mode 100644
index 000000000..88165ceca
--- /dev/null
+++ b/src/examples/browser-wasix/tsconfig.json
@@ -0,0 +1,17 @@
+{
+  "extends": "../../sdks/ts-wasix/sdk/tsconfig.json",
+  "compilerOptions": {
+    "module": "ESNext",
+    "moduleResolution": "Bundler",
+    "noEmit": true,
+    "paths": {
+      "@oliphaunt/liboliphaunt-wasix": ["../../sdks/ts-wasix/sdk/src/runtime-carrier-shim.d.ts"],
+      "@oliphaunt/wasix-ts": ["../../sdks/ts-wasix/sdk/src/index.ts"],
+      "@oliphaunt/wasix-ts/worker": ["../../sdks/ts-wasix/sdk/src/worker-entry.ts"],
+      "@oliphaunt/wasix-ts/*": ["../../sdks/ts-wasix/sdk/src/*"]
+    },
+    "rootDir": "../../..",
+    "types": ["node", "vite/client"]
+  },
+  "include": ["./**/*.ts"]
+}
diff --git a/src/examples/browser-wasix/vite.config.ts b/src/examples/browser-wasix/vite.config.ts
new file mode 100644
index 000000000..053036cf4
--- /dev/null
+++ b/src/examples/browser-wasix/vite.config.ts
@@ -0,0 +1,421 @@
+import { createHash } from 'node:crypto';
+import { readFile } from 'node:fs/promises';
+import { createRequire } from 'node:module';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { defineConfig, type Plugin } from 'vite';
+
+const exampleRoot = dirname(fileURLToPath(import.meta.url));
+const repositoryRoot = resolve(exampleRoot, '../../..');
+const bindingRoot = resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk');
+const bindingLibRoot = resolve(bindingRoot, 'lib');
+const assetRoot = resolve(repositoryRoot, 'target/oliphaunt-wasix/assets');
+const extensionAssetRoot = resolve(repositoryRoot, 'target/extensions/wasix/assets');
+const resourceVersion = (
+  await readFile(resolve(repositoryRoot, 'src/database-resources/VERSION'), 'utf8')
+).trim();
+const seedBase = resolve(
+  repositoryRoot,
+  'target/database-resources/release-assets',
+  `database-resources-${resourceVersion}-seed-wasix-standard`,
+);
+const pgliteAssetRoot = resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist');
+const databaseRootContractFile = resolve(
+  repositoryRoot,
+  'src/test-fixtures/storage/database-root.json',
+);
+const packedConsumerRoot = process.env.OLIPHAUNT_WASIX_BROWSER_PACKAGE_ROOT;
+const packedConsumer = packedConsumerRoot === undefined ? undefined : resolve(packedConsumerRoot);
+export default defineConfig({
+  root: packedConsumer ?? exampleRoot,
+  resolve: {
+    ...(packedConsumer === undefined
+      ? {
+          alias: [
+            {
+              find: /^@oliphaunt\/wasix-ts$/,
+              replacement: resolve(bindingLibRoot, 'index.js'),
+            },
+            {
+              find: /^@oliphaunt\/wasix-ts\/worker$/,
+              replacement: resolve(bindingLibRoot, 'worker-entry.js'),
+            },
+            {
+              find: /^@oliphaunt\/wasix-ts\/(.+)$/,
+              replacement: `${bindingLibRoot}/$1.js`,
+            },
+          ],
+        }
+      : {
+          alias: [
+            {
+              find: /^fzstd$/,
+              replacement: createRequire(
+                resolve(packedConsumer, 'node_modules/@oliphaunt/wasix-ts/package.json'),
+              ).resolve('fzstd'),
+            },
+          ],
+          dedupe: [
+            '@oliphaunt/wasix-ts',
+            '@oliphaunt/liboliphaunt-wasix',
+            '@oliphaunt/wasix-tools',
+            '@oliphaunt/liboliphaunt-wasix-tools',
+            '@oliphaunt/extension-pgtap-wasix',
+            'fzstd',
+          ],
+        }),
+  },
+  optimizeDeps: {
+    ...(packedConsumer === undefined
+      ? {}
+      : {
+          exclude: [
+            '@oliphaunt/wasix-ts',
+            '@oliphaunt/liboliphaunt-wasix',
+            '@oliphaunt/wasix-tools',
+            '@oliphaunt/liboliphaunt-wasix-tools',
+            '@oliphaunt/extension-pgtap-wasix',
+          ],
+        }),
+    esbuildOptions: {
+      target: 'esnext',
+    },
+  },
+  build: {
+    target: 'esnext',
+  },
+  worker: {
+    format: 'es',
+  },
+  server: {
+    ...(process.env.OLIPHAUNT_WASIX_BROWSER_SMOKE === '1' ? { hmr: false, watch: null } : {}),
+    fs: {
+      allow: [repositoryRoot, ...(packedConsumer === undefined ? [] : [packedConsumer])],
+    },
+    headers: {
+      'Cross-Origin-Embedder-Policy': 'require-corp',
+      'Cross-Origin-Opener-Policy': 'same-origin',
+    },
+  },
+  plugins:
+    packedConsumer === undefined ? [wasixAssets()] : [packedBrowserPackageExports(packedConsumer)],
+});
+
+function packedBrowserPackageExports(consumerRoot: string): Plugin {
+  const expected = new Map([
+    ['@oliphaunt/wasix-ts', '/@oliphaunt/wasix-ts/lib/index.js'],
+    ['@oliphaunt/wasix-ts/worker', '/@oliphaunt/wasix-ts/lib/worker-entry.js'],
+    ['@oliphaunt/wasix-ts/storage/indexed-db', '/@oliphaunt/wasix-ts/lib/storage/indexed-db.js'],
+    ['@oliphaunt/liboliphaunt-wasix', '/@oliphaunt/liboliphaunt-wasix/index.js'],
+    ['@oliphaunt/wasix-tools', '/@oliphaunt/wasix-tools/lib/index.js'],
+    ['@oliphaunt/liboliphaunt-wasix-tools', '/@oliphaunt/liboliphaunt-wasix-tools/index.js'],
+    ['@oliphaunt/extension-pgtap-wasix', '/@oliphaunt/extension-pgtap-wasix/index.js'],
+  ]);
+  return {
+    name: 'oliphaunt-packed-browser-package-exports',
+    enforce: 'pre',
+    async resolveId(source, importer) {
+      const suffix = expected.get(source);
+      if (suffix === undefined) return undefined;
+      const resolved = await this.resolve(source, importer, { skipSelf: true });
+      if (resolved === null) {
+        throw new Error(`packed browser consumer could not resolve ${source}`);
+      }
+      const id = resolved.id.split('?')[0]?.split('\\').join('/');
+      if (id === undefined || !id.endsWith(suffix)) {
+        throw new Error(
+          `packed browser consumer resolved ${source} to ${resolved.id}, expected ${suffix}`,
+        );
+      }
+      if (!id.includes('/node_modules/')) {
+        throw new Error(`packed browser consumer did not load ${source} from its install`);
+      }
+      return resolved;
+    },
+    configResolved(config) {
+      if (resolve(config.root) !== consumerRoot) {
+        throw new Error('packed browser consumer did not become the Vite project root');
+      }
+    },
+  };
+}
+
+function wasixAssets(): Plugin {
+  const virtualModules = new Map([
+    ['@oliphaunt/liboliphaunt-wasix', '\0oliphaunt:liboliphaunt-wasix'],
+    ['@oliphaunt/extension-pgtap-wasix', '\0oliphaunt:extension-pgtap-wasix'],
+    ['@oliphaunt/extension-pg-uuidv7-wasix', '\0oliphaunt:extension-pg-uuidv7-wasix'],
+    ['@oliphaunt/extension-postgis-wasix', '\0oliphaunt:extension-postgis-wasix'],
+  ]);
+  const packageByVirtualModule = new Map(
+    [...virtualModules].map(([packageName, virtualModule]) => [virtualModule, packageName]),
+  );
+  const descriptorPromises = new Map>>();
+  let runtimeIdentityPromise:
+    | Promise<{ postgresMajor: number; physicalFormat: string }>
+    | undefined;
+  const routes = new Map([
+    ['/runtime', resolve(assetRoot, 'oliphaunt.wasix.tar.zst')],
+    ['/cluster-seed-standard', `${seedBase}.tar.zst`],
+    ['/cluster-seed-standard-manifest', `${seedBase}.json`],
+    ['/manifest', resolve(assetRoot, 'manifest.json')],
+    ['/extensions/pgtap', resolve(extensionAssetRoot, 'extensions/pgtap.tar.zst')],
+    ['/extensions/pg_uuidv7', resolve(extensionAssetRoot, 'extensions/pg_uuidv7.tar.zst')],
+    ['/extensions/postgis', resolve(extensionAssetRoot, 'extensions/postgis.tar.zst')],
+    ['/pglite.data', resolve(pgliteAssetRoot, 'pglite.data')],
+    ['/pglite.wasm', resolve(pgliteAssetRoot, 'pglite.wasm')],
+    ['/initdb.wasm', resolve(pgliteAssetRoot, 'initdb.wasm')],
+  ]);
+  return {
+    name: 'oliphaunt-wasix-assets',
+    enforce: 'pre',
+    resolveId(id) {
+      return virtualModules.get(id);
+    },
+    async load(id) {
+      const packageName = packageByVirtualModule.get(id);
+      if (packageName === undefined) {
+        return undefined;
+      }
+      let descriptorPromise = descriptorPromises.get(packageName);
+      if (descriptorPromise === undefined) {
+        descriptorPromise = developmentDescriptor(packageName);
+        descriptorPromises.set(packageName, descriptorPromise);
+      }
+      const descriptor = await descriptorPromise;
+      let namedRuntimeExports = '';
+      if (packageName === '@oliphaunt/liboliphaunt-wasix') {
+        runtimeIdentityPromise ??= developmentWasixIdentity();
+        const identity = await runtimeIdentityPromise;
+        namedRuntimeExports =
+          `export const POSTGRES_MAJOR = ${JSON.stringify(identity.postgresMajor)};\n` +
+          `export const PHYSICAL_FORMAT = ${JSON.stringify(identity.physicalFormat)};\n`;
+      }
+      return (
+        namedRuntimeExports +
+        `const descriptor = Object.freeze(${JSON.stringify(descriptor)});\n` +
+        'export { descriptor };\nexport default descriptor;\n'
+      );
+    },
+    configureServer(server) {
+      server.middlewares.use('/wasix-assets', async (request, response, next) => {
+        const path = routes.get(request.url ?? '');
+        if (path === undefined) {
+          next();
+          return;
+        }
+        try {
+          const source = await readFile(path);
+          const bytes = path.endsWith('manifest.json') ? coreManifest(source) : source;
+          response.statusCode = 200;
+          const contentType = path.endsWith('.json')
+            ? 'application/json'
+            : path.endsWith('.wasm')
+              ? 'application/wasm'
+              : path.endsWith('.data')
+                ? 'application/octet-stream'
+                : 'application/zstd';
+          response.setHeader('Content-Type', contentType);
+          response.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
+          response.end(bytes);
+        } catch (error) {
+          response.statusCode = 500;
+          response.end(
+            `Missing WASIX assets. Run liboliphaunt-wasix:runtime-portable and database-resources:build-wasix-standard first.\n${String(error)}`,
+          );
+        }
+      });
+    },
+  };
+}
+
+async function developmentWasixIdentity(): Promise<{
+  postgresMajor: number;
+  physicalFormat: string;
+}> {
+  const contract = JSON.parse(await readFile(databaseRootContractFile, 'utf8')) as Record<
+    string,
+    unknown
+  >;
+  const families = requireRecord(contract.families, 'database-root families');
+  const wasix = requireRecord(families.wasix, 'database-root WASIX family');
+  const postgresMajor = contract.postgresMajor;
+  const physicalFormat = wasix.physicalFormat;
+  if (!Number.isInteger(postgresMajor) || typeof physicalFormat !== 'string' || !physicalFormat) {
+    throw new Error('shared database-root fixture has no valid WASIX physical identity');
+  }
+  return { postgresMajor: postgresMajor as number, physicalFormat };
+}
+
+async function developmentDescriptor(packageName: string): Promise> {
+  const manifestBytes = await readFile(resolve(assetRoot, 'manifest.json'));
+  const manifest = JSON.parse(manifestBytes.toString('utf8')) as Record;
+  const versions = JSON.parse(
+    await readFile(resolve(repositoryRoot, '.release-please-manifest.json'), 'utf8'),
+  ) as Record;
+  const runtimeVersion = requireVersion(versions, 'src/runtimes/liboliphaunt-wasix');
+
+  if (packageName === '@oliphaunt/liboliphaunt-wasix') {
+    const runtime = requireRecord(manifest.runtime, 'runtime manifest entry');
+    const runtimeBytes = await readFile(resolve(assetRoot, String(runtime.archive)));
+    const projectedManifest = coreManifest(manifestBytes);
+    return {
+      schema: 'oliphaunt-wasix-runtime-v2',
+      runtime: 'wasix',
+      product: 'liboliphaunt-wasix',
+      version: runtimeVersion,
+      runtimeArchive: {
+        archive: runtime.archive,
+        sha256: sha256(runtimeBytes),
+        size: runtimeBytes.length,
+        source: '/wasix-assets/runtime',
+      },
+      manifest: {
+        sha256: sha256(projectedManifest),
+        size: projectedManifest.length,
+        source: '/wasix-assets/manifest',
+      },
+    };
+  }
+
+  const extension = extensionPackage(packageName);
+  const extensionManifest = JSON.parse(
+    await readFile(resolve(extensionAssetRoot, 'manifest.json'), 'utf8'),
+  );
+  const rows = extensionManifest.extensions;
+  if (!Array.isArray(rows)) {
+    throw new Error('canonical development manifest has no extension rows');
+  }
+  const row = rows.find(
+    (candidate) =>
+      candidate !== null &&
+      typeof candidate === 'object' &&
+      (candidate as Record)['sql-name'] === extension.sqlName,
+  );
+  const metadata = requireRecord(row, `${extension.sqlName} manifest entry`);
+  const lifecycle = requireRecord(metadata.lifecycle, `${extension.sqlName} lifecycle`);
+  const version = requireVersion(versions, extension.releasePath);
+  const carrier = {
+    product: extension.product,
+    version,
+    sqlName: extension.sqlName,
+    archive: metadata.archive,
+    sha256: metadata.sha256,
+    size: metadata.size,
+    source: `/wasix-assets/extensions/${extension.sqlName}`,
+    install: {
+      schema: 'oliphaunt-wasix-extension-install-v1',
+      name: metadata.name,
+      nativeModule: metadata['native-module'] ?? null,
+      nativeModules: requireArray(metadata['native-modules'], 'native modules').map((value) => {
+        const module = requireRecord(value, 'native module');
+        return {
+          name: module.name,
+          path: module.path,
+          sha256: module.sha256,
+          moduleSha256: module['module-sha256'],
+          size: module.size,
+        };
+      }),
+      dependencies: metadata.dependencies,
+      coreExportsRequired: metadata['core-exports-required'],
+      loadOrder: metadata['load-order'],
+      lifecycle: {
+        createExtension: lifecycle['create-extension'],
+        createSchema: lifecycle['create-schema'],
+        loadSql: lifecycle['load-sql'],
+        postCreateSql: lifecycle['post-create-sql'],
+        startupConfig: lifecycle['startup-config'],
+        preloadRequired: lifecycle['preload-required'],
+        restartRequired: lifecycle['restart-required'],
+        sharedMemoryRequired: lifecycle['shared-memory-required'],
+      },
+      installedFiles: metadata['installed-files'],
+      unresolvedImports: requireArray(metadata['unresolved-imports'], 'unresolved imports').map(
+        (value) => {
+          const entry = requireRecord(value, 'unresolved import');
+          return { module: entry.module, name: entry.name, kind: entry.kind };
+        },
+      ),
+    },
+  };
+  return {
+    schema: 'oliphaunt-wasix-extension-v1',
+    runtime: 'wasix',
+    product: extension.product,
+    version,
+    compatibility: {
+      extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1',
+      postgresMajor: '18',
+      wasixRuntimeProduct: 'liboliphaunt-wasix',
+      wasixRuntimeVersion: runtimeVersion,
+    },
+    sqlName: extension.sqlName,
+    carriers: [carrier],
+  };
+}
+
+function extensionPackage(packageName: string): {
+  product: string;
+  releasePath: string;
+  sqlName: string;
+} {
+  switch (packageName) {
+    case '@oliphaunt/extension-pgtap-wasix':
+      return {
+        product: 'oliphaunt-extension-pgtap',
+        releasePath: 'src/extensions/external/pgtap',
+        sqlName: 'pgtap',
+      };
+    case '@oliphaunt/extension-pg-uuidv7-wasix':
+      return {
+        product: 'oliphaunt-extension-pg-uuidv7',
+        releasePath: 'src/extensions/external/pg_uuidv7',
+        sqlName: 'pg_uuidv7',
+      };
+    case '@oliphaunt/extension-postgis-wasix':
+      return {
+        product: 'oliphaunt-extension-postgis',
+        releasePath: 'src/extensions/external/postgis',
+        sqlName: 'postgis',
+      };
+    default:
+      throw new Error(`unsupported development WASIX package ${packageName}`);
+  }
+}
+
+function requireRecord(value: unknown, label: string): Record {
+  if (value === null || typeof value !== 'object' || Array.isArray(value)) {
+    throw new Error(`${label} must be an object`);
+  }
+  return value as Record;
+}
+
+function requireArray(value: unknown, label: string): unknown[] {
+  if (!Array.isArray(value)) {
+    throw new Error(`${label} must be an array`);
+  }
+  return value;
+}
+
+function requireVersion(versions: Record, productPath: string): string {
+  const version = versions[productPath];
+  if (version === undefined) {
+    throw new Error(`missing release version for ${productPath}`);
+  }
+  return version;
+}
+
+function sha256(bytes: Uint8Array): string {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function coreManifest(bytes: Uint8Array): Uint8Array {
+  const manifest = JSON.parse(new TextDecoder().decode(bytes)) as Record;
+  manifest.extensions = [];
+  delete manifest['cluster-seeds'];
+  delete manifest['pg-dump'];
+  delete manifest.psql;
+  return new TextEncoder().encode(`${JSON.stringify(manifest, null, 2)}\n`);
+}
diff --git a/examples/electron-wasix/.gitignore b/src/examples/electron-wasix/.gitignore
similarity index 100%
rename from examples/electron-wasix/.gitignore
rename to src/examples/electron-wasix/.gitignore
diff --git a/src/examples/electron-wasix/README.md b/src/examples/electron-wasix/README.md
new file mode 100644
index 000000000..882de14d6
--- /dev/null
+++ b/src/examples/electron-wasix/README.md
@@ -0,0 +1,17 @@
+# Electron WASIX Todo
+
+Electron keeps WASIX in a Rust sidecar. The sidecar starts
+`oliphaunt-pgwire-server`’s `AsyncOliphauntServer`, prints a local PostgreSQL URL, and stays alive until
+Electron exits. The Electron main process uses `pg` with a single connection
+and exposes the same preload API as the native Electron example. Its explicit
+Rust smoke test covers `pg_dump` and `psql` through the direct
+`oliphaunt_wasix` API; normal sidecar startup does not run either
+tool.
+
+```sh
+bun install --cwd src/examples/electron-wasix
+bun run --cwd src/examples/electron-wasix start
+```
+
+For packaged apps, build the `src-wasix` binary and set
+`OLIPHAUNT_WASIX_TODO_SIDECAR` to its path before launching Electron.
diff --git a/examples/electron-wasix/index.html b/src/examples/electron-wasix/index.html
similarity index 100%
rename from examples/electron-wasix/index.html
rename to src/examples/electron-wasix/index.html
diff --git a/src/examples/electron-wasix/package.json b/src/examples/electron-wasix/package.json
new file mode 100644
index 000000000..763116cd6
--- /dev/null
+++ b/src/examples/electron-wasix/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "oliphaunt-example-electron-wasix",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "build": "tsc -p tsconfig.main.json && vite build",
+    "start": "bun run build && electron dist/main/main-process.js",
+    "dev:renderer": "vite"
+  },
+  "dependencies": {
+    "kysely": "^0.29.2",
+    "pg": "^8.16.3"
+  },
+  "devDependencies": {
+    "@types/node": "^24.10.1",
+    "@types/pg": "^8.15.6",
+    "electron": "^39.2.5",
+    "typescript": "^5.9.3",
+    "vite": "^6.0.3"
+  }
+}
diff --git a/examples/electron-wasix/pnpm-workspace.yaml b/src/examples/electron-wasix/pnpm-workspace.yaml
similarity index 100%
rename from examples/electron-wasix/pnpm-workspace.yaml
rename to src/examples/electron-wasix/pnpm-workspace.yaml
diff --git a/src/examples/electron-wasix/src-wasix/Cargo.toml b/src/examples/electron-wasix/src-wasix/Cargo.toml
new file mode 100644
index 000000000..d3bef09d7
--- /dev/null
+++ b/src/examples/electron-wasix/src-wasix/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "oliphaunt-electron-wasix-sidecar"
+version = "0.0.0"
+edition = "2021"
+publish = false
+
+[workspace]
+
+[dependencies]
+oliphaunt-pgwire-server = { version = "0.1.0", path = "../../../pgwire-server", features = ["extensions"] }
+anyhow = "1"
+oliphaunt-wasix = { version = "=0.2.0", path = "../../../sdks/rust-wasix", features = [
+  "extension-hstore",
+  "extension-pg-trgm",
+  "extension-unaccent",
+] }
+serde_json = "1"
+tokio = { version = "1", features = ["rt-multi-thread"] }
+
+[dev-dependencies]
+oliphaunt-wasix = { version = "=0.2.0", path = "../../../sdks/rust-wasix", features = ["tools"] }
+oliphaunt-wasix-tools = { version = "=0.2.1", path = "../../../postgres-tools/wasix/crates/tools" }
+
+[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dependencies]
+liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu = { version = "=0.2.0", path = "../../../runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu" }
+
+[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dev-dependencies]
+oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu = { version = "=0.2.1", path = "../../../postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu" }
diff --git a/src/examples/electron-wasix/src-wasix/src/main.rs b/src/examples/electron-wasix/src-wasix/src/main.rs
new file mode 100644
index 000000000..10e3c098e
--- /dev/null
+++ b/src/examples/electron-wasix/src-wasix/src/main.rs
@@ -0,0 +1,92 @@
+use std::env;
+use std::io::{self, Write};
+use std::path::PathBuf;
+use std::thread;
+
+use anyhow::{Context, Result, bail};
+use oliphaunt_pgwire_server::AsyncOliphauntServer;
+use oliphaunt_wasix::{DatabaseStorage, Extension};
+#[cfg(test)]
+use oliphaunt_wasix::{Oliphaunt, tools};
+use serde_json::json;
+
+fn main() -> Result<()> {
+    let directory = parse_directory()?;
+    let runtime = tokio::runtime::Builder::new_multi_thread()
+        .enable_all()
+        .build()
+        .context("build WASIX sidecar Tokio runtime")?;
+    let server = runtime.block_on(start_server(directory))?;
+    println!("{}", json!({ "databaseUrl": server.connection_string() }));
+    io::stdout().flush()?;
+    let _server = server;
+    loop {
+        thread::park();
+    }
+}
+
+async fn start_server(directory: PathBuf) -> Result {
+    let server = AsyncOliphauntServer::builder()
+        .storage(DatabaseStorage::Directory(directory))
+        .extensions([
+            Extension::HSTORE,
+            Extension::PG_TRGM,
+            Extension::UNACCENT,
+        ])
+        .start()
+        .await
+        .context("start oliphaunt-wasix server")?;
+    Ok(server)
+}
+
+#[cfg(test)]
+fn validate_wasix_tools() -> Result<()> {
+    let mut database = Oliphaunt::open()?;
+    let dump = database.pg_dump(tools::PgDumpOptions::new().arg("--schema-only"))?;
+    anyhow::ensure!(
+        dump.contains("PostgreSQL database dump"),
+        "pg_dump SQL backup smoke did not look like a PostgreSQL dump"
+    );
+    let psql = database.psql(tools::PsqlOptions::new().arg("-tA").command("SELECT 1"))?;
+    anyhow::ensure!(
+        psql.lines().any(|line| line.trim() == "1"),
+        "psql smoke did not return SELECT 1 output"
+    );
+    database.close()?;
+    Ok(())
+}
+
+fn parse_directory() -> Result {
+    let mut args = env::args().skip(1);
+    while let Some(arg) = args.next() {
+        if arg == "--directory" {
+            let value = args.next().context("--directory requires a path")?;
+            return Ok(PathBuf::from(value));
+        }
+    }
+    bail!("usage: oliphaunt-electron-wasix-sidecar --directory ")
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn startup_smoke_runs_split_wasix_tools() {
+        let directory = std::env::temp_dir().join(format!(
+            "oliphaunt-electron-wasix-sidecar-smoke-{}",
+            std::process::id()
+        ));
+        let _ = std::fs::remove_dir_all(&directory);
+        let runtime = tokio::runtime::Builder::new_multi_thread()
+            .enable_all()
+            .build()
+            .expect("build WASIX sidecar smoke runtime");
+        validate_wasix_tools().expect("run explicit split WASIX tools smoke");
+        let server = runtime
+            .block_on(start_server(directory.clone()))
+            .expect("start sidecar server after split WASIX tools smoke");
+        drop(server);
+        let _ = std::fs::remove_dir_all(directory);
+    }
+}
diff --git a/src/examples/electron-wasix/src/main-process.ts b/src/examples/electron-wasix/src/main-process.ts
new file mode 100644
index 000000000..f10498cb1
--- /dev/null
+++ b/src/examples/electron-wasix/src/main-process.ts
@@ -0,0 +1,77 @@
+import { dirname, join } from 'node:path';
+import { fileURLToPath, pathToFileURL } from 'node:url';
+import { app, BrowserWindow, ipcMain } from 'electron';
+
+import { closeStore, createTodo, deleteTodo, listTodos, toggleTodo } from './todos.js';
+import type { CreateTodoInput, StatusFilter } from './types.js';
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+function createWindow() {
+  const window = new BrowserWindow({
+    width: 1100,
+    height: 760,
+    title: 'Oliphaunt Electron WASIX Todo',
+    webPreferences: {
+      preload: join(__dirname, 'preload.cjs'),
+      contextIsolation: true,
+      nodeIntegration: false,
+    },
+  });
+
+  const devServer = process.env.VITE_DEV_SERVER_URL;
+  if (devServer) {
+    void window.loadURL(devServer);
+  } else {
+    void window.loadFile(join(__dirname, '../renderer/index.html'));
+  }
+  return window;
+}
+
+async function runTestDriver(window: BrowserWindow) {
+  if (!process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER) return;
+  const driver = await import(
+    pathToFileURL(join(process.cwd(), '../tools/electron-test-driver.mts')).href
+  );
+  try {
+    await driver.runElectronTodoSmoke(window);
+    console.log('electron todo smoke passed');
+  } finally {
+    await closeStore();
+  }
+  app.exit(0);
+}
+
+ipcMain.handle('todos:list', (_event, filter: { search: string; status: StatusFilter }) =>
+  listTodos(app.getPath('userData'), filter),
+);
+ipcMain.handle('todos:create', (_event, input: CreateTodoInput) =>
+  createTodo(app.getPath('userData'), input),
+);
+ipcMain.handle('todos:toggle', (_event, id: number) => toggleTodo(app.getPath('userData'), id));
+ipcMain.handle('todos:delete', (_event, id: number) => deleteTodo(app.getPath('userData'), id));
+
+void app
+  .whenReady()
+  .then(async () => {
+    await runTestDriver(createWindow());
+  })
+  .catch((error) => {
+    console.error(error);
+    app.exit(1);
+  });
+
+app.on('activate', () => {
+  if (BrowserWindow.getAllWindows().length === 0) createWindow();
+});
+
+app.on('window-all-closed', () => {
+  if (process.platform !== 'darwin') app.quit();
+});
+
+app.on('before-quit', (event) => {
+  event.preventDefault();
+  closeStore()
+    .catch((error) => console.error(error))
+    .finally(() => app.exit(0));
+});
diff --git a/src/examples/electron-wasix/src/preload.cts b/src/examples/electron-wasix/src/preload.cts
new file mode 100644
index 000000000..526ed621a
--- /dev/null
+++ b/src/examples/electron-wasix/src/preload.cts
@@ -0,0 +1,19 @@
+import { contextBridge, ipcRenderer } from 'electron';
+import type { CreateTodoInput, StatusFilter, TodoApi } from './types.js';
+
+const api: TodoApi = {
+  listTodos(filter: { search: string; status: StatusFilter }) {
+    return ipcRenderer.invoke('todos:list', filter);
+  },
+  createTodo(input: CreateTodoInput) {
+    return ipcRenderer.invoke('todos:create', input);
+  },
+  toggleTodo(id: number) {
+    return ipcRenderer.invoke('todos:toggle', id);
+  },
+  deleteTodo(id: number) {
+    return ipcRenderer.invoke('todos:delete', id);
+  },
+};
+
+contextBridge.exposeInMainWorld('todos', api);
diff --git a/src/examples/electron-wasix/src/renderer.ts b/src/examples/electron-wasix/src/renderer.ts
new file mode 100644
index 000000000..62f360801
--- /dev/null
+++ b/src/examples/electron-wasix/src/renderer.ts
@@ -0,0 +1 @@
+import '../../electron/src/renderer.ts';
diff --git a/src/examples/electron-wasix/src/sidecar.ts b/src/examples/electron-wasix/src/sidecar.ts
new file mode 100644
index 000000000..9c2501503
--- /dev/null
+++ b/src/examples/electron-wasix/src/sidecar.ts
@@ -0,0 +1,58 @@
+import { spawn, type ChildProcess } from 'node:child_process';
+import { existsSync } from 'node:fs';
+import { join } from 'node:path';
+import { createInterface } from 'node:readline';
+
+export type WasixSidecar = {
+  databaseUrl: string;
+  process: ChildProcess;
+};
+
+export async function startWasixSidecar(directory: string): Promise {
+  const configured = process.env.OLIPHAUNT_WASIX_TODO_SIDECAR;
+  const command = configured || 'cargo';
+  const args = configured
+    ? ['--directory', directory]
+    : [
+        'run',
+        '--quiet',
+        '--manifest-path',
+        join(process.cwd(), 'src-wasix/Cargo.toml'),
+        '--',
+        '--directory',
+        directory,
+      ];
+  if (configured && !existsSync(configured)) {
+    throw new Error(`OLIPHAUNT_WASIX_TODO_SIDECAR does not exist: ${configured}`);
+  }
+
+  const child = spawn(command, args, {
+    cwd: process.cwd(),
+    stdio: ['ignore', 'pipe', 'pipe'],
+  });
+  child.stderr.on('data', (chunk) => {
+    process.stderr.write(chunk);
+  });
+
+  const lines = createInterface({ input: child.stdout });
+  const firstLine = await new Promise((resolve, reject) => {
+    const timer = setTimeout(
+      () => reject(new Error('timed out waiting for WASIX sidecar')),
+      60_000,
+    );
+    child.once('exit', (code) => {
+      clearTimeout(timer);
+      reject(new Error(`WASIX sidecar exited before ready: ${code ?? 'signal'}`));
+    });
+    lines.once('line', (line) => {
+      clearTimeout(timer);
+      resolve(line);
+    });
+  });
+  const payload = JSON.parse(firstLine) as { databaseUrl?: string };
+  if (!payload.databaseUrl) throw new Error('WASIX sidecar did not print databaseUrl');
+  return {
+    databaseUrl: payload.databaseUrl,
+    process: child,
+  };
+}
diff --git a/examples/electron-wasix/src/styles.css b/src/examples/electron-wasix/src/styles.css
similarity index 100%
rename from examples/electron-wasix/src/styles.css
rename to src/examples/electron-wasix/src/styles.css
diff --git a/src/examples/electron-wasix/src/todos.ts b/src/examples/electron-wasix/src/todos.ts
new file mode 100644
index 000000000..b44f735b5
--- /dev/null
+++ b/src/examples/electron-wasix/src/todos.ts
@@ -0,0 +1,191 @@
+import { join } from 'node:path';
+
+import { Kysely, PostgresDialect, sql, type Generated } from 'kysely';
+import pg from 'pg';
+
+import { startWasixSidecar, type WasixSidecar } from './sidecar.js';
+import type { CreateTodoInput, StatusFilter, Todo } from './types.js';
+
+const { Pool } = pg;
+
+type TodoTable = {
+  id: Generated;
+  title: string;
+  notes: string;
+  tags: string;
+  done: Generated;
+  priority: number;
+  created_at: Generated;
+  updated_at: Generated;
+};
+
+type TodoDatabase = {
+  todos: TodoTable;
+};
+
+type TodoRecord = {
+  id: string;
+  title: string;
+  notes: string;
+  area: string;
+  context: string;
+  done: string;
+  priority: string;
+  created_at: string;
+  updated_at: string;
+};
+
+const schemaStatements = [
+  'CREATE EXTENSION IF NOT EXISTS hstore',
+  'CREATE EXTENSION IF NOT EXISTS pg_trgm',
+  'CREATE EXTENSION IF NOT EXISTS unaccent',
+  `CREATE TABLE IF NOT EXISTS todos (
+    id bigserial PRIMARY KEY,
+    title text NOT NULL,
+    notes text NOT NULL DEFAULT '',
+    tags hstore NOT NULL DEFAULT ''::hstore,
+    done boolean NOT NULL DEFAULT false,
+    priority integer NOT NULL DEFAULT 2 CHECK (priority BETWEEN 1 AND 3),
+    created_at timestamptz NOT NULL DEFAULT now(),
+    updated_at timestamptz NOT NULL DEFAULT now()
+  )`,
+  'CREATE INDEX IF NOT EXISTS todos_title_trgm ON todos USING gin (title gin_trgm_ops)',
+];
+
+type Store = {
+  db: Kysely;
+  sidecar: WasixSidecar;
+};
+
+let storePromise: Promise | undefined;
+
+async function getStore(userData: string) {
+  storePromise ??= openStore(userData);
+  return storePromise;
+}
+
+async function openStore(userData: string): Promise {
+  const sidecar = await startWasixSidecar(join(userData, 'oliphaunt-wasix-todos'));
+  const db = new Kysely({
+    dialect: new PostgresDialect({
+      pool: new Pool({
+        connectionString: sidecar.databaseUrl,
+        max: 1,
+      }),
+    }),
+  });
+  for (const statement of schemaStatements) {
+    await sql.raw(statement).execute(db);
+  }
+  return { db, sidecar };
+}
+
+export async function listTodos(
+  userData: string,
+  filter: { search: string; status: StatusFilter },
+) {
+  const { db } = await getStore(userData);
+  const rows = await db
+    .selectFrom('todos')
+    .select(todoColumns)
+    .where(searchPredicate(filter.search))
+    .where(statusPredicate(filter.status))
+    .orderBy('done', 'asc')
+    .orderBy('priority', 'asc')
+    .orderBy('updated_at', 'desc')
+    .orderBy('id', 'desc')
+    .execute();
+  return rows.map(todoFromRow);
+}
+
+export async function createTodo(userData: string, input: CreateTodoInput) {
+  const { db } = await getStore(userData);
+  const row = await db
+    .insertInto('todos')
+    .values({
+      title: input.title,
+      notes: input.notes,
+      tags: sql`hstore(ARRAY['area', ${input.area}, 'context', ${input.context}])`,
+      priority: clampPriority(input.priority),
+    })
+    .returning(todoColumns)
+    .executeTakeFirstOrThrow();
+  return todoFromRow(row);
+}
+
+export async function toggleTodo(userData: string, id: number) {
+  const { db } = await getStore(userData);
+  const row = await db
+    .updateTable('todos')
+    .set({
+      done: sql`NOT done`,
+      updated_at: sql`now()`,
+    })
+    .where('id', '=', String(id))
+    .returning(todoColumns)
+    .executeTakeFirstOrThrow();
+  return todoFromRow(row);
+}
+
+export async function deleteTodo(userData: string, id: number) {
+  const { db } = await getStore(userData);
+  await db.deleteFrom('todos').where('id', '=', String(id)).execute();
+}
+
+export async function closeStore() {
+  if (!storePromise) return;
+  const store = await storePromise;
+  await store.db.destroy();
+  store.sidecar.process.kill();
+  storePromise = undefined;
+}
+
+function todoColumns() {
+  return [
+    sql`id::text`.as('id'),
+    'title',
+    'notes',
+    sql`COALESCE(tags -> 'area', '')`.as('area'),
+    sql`COALESCE(tags -> 'context', '')`.as('context'),
+    sql`done::text`.as('done'),
+    sql`priority::text`.as('priority'),
+    sql`to_char(created_at, 'YYYY-MM-DD HH24:MI')`.as('created_at'),
+    sql`to_char(updated_at, 'YYYY-MM-DD HH24:MI')`.as('updated_at'),
+  ] as const;
+}
+
+function searchPredicate(search: string) {
+  return sql`(
+    ${search}::text = ''
+    OR unaccent(title || ' ' || notes) ILIKE '%' || unaccent(${search}::text) || '%'
+    OR COALESCE(tags -> 'area', '') ILIKE '%' || ${search}::text || '%'
+    OR COALESCE(tags -> 'context', '') ILIKE '%' || ${search}::text || '%'
+    OR tags ? ${search}::text
+  )`;
+}
+
+function statusPredicate(status: StatusFilter) {
+  return sql`(
+    ${status}::text = 'all'
+    OR (${status}::text = 'open' AND NOT done)
+    OR (${status}::text = 'done' AND done)
+  )`;
+}
+
+function todoFromRow(row: TodoRecord): Todo {
+  return {
+    id: Number(row.id),
+    title: row.title,
+    notes: row.notes,
+    area: row.area,
+    context: row.context,
+    priority: Number(row.priority),
+    done: row.done === 'true',
+    createdAt: row.created_at,
+    updatedAt: row.updated_at,
+  };
+}
+
+function clampPriority(value: number) {
+  return Math.min(Math.max(Math.trunc(value) || 2, 1), 3);
+}
diff --git a/src/examples/electron-wasix/src/types.ts b/src/examples/electron-wasix/src/types.ts
new file mode 100644
index 000000000..bf7f325c2
--- /dev/null
+++ b/src/examples/electron-wasix/src/types.ts
@@ -0,0 +1,28 @@
+export type Todo = {
+  id: number;
+  title: string;
+  notes: string;
+  area: string;
+  context: string;
+  priority: number;
+  done: boolean;
+  createdAt: string;
+  updatedAt: string;
+};
+
+export type CreateTodoInput = {
+  title: string;
+  notes: string;
+  area: string;
+  context: string;
+  priority: number;
+};
+
+export type StatusFilter = 'open' | 'all' | 'done';
+
+export type TodoApi = {
+  listTodos(filter: { search: string; status: StatusFilter }): Promise;
+  createTodo(input: CreateTodoInput): Promise;
+  toggleTodo(id: number): Promise;
+  deleteTodo(id: number): Promise;
+};
diff --git a/src/examples/electron-wasix/tsconfig.main.json b/src/examples/electron-wasix/tsconfig.main.json
new file mode 100644
index 000000000..7c4b4d868
--- /dev/null
+++ b/src/examples/electron-wasix/tsconfig.main.json
@@ -0,0 +1,20 @@
+{
+  "compilerOptions": {
+    "target": "ES2022",
+    "module": "NodeNext",
+    "moduleResolution": "NodeNext",
+    "lib": ["ES2022", "DOM"],
+    "outDir": "dist/main",
+    "rootDir": "src",
+    "strict": true,
+    "skipLibCheck": true,
+    "sourceMap": true
+  },
+  "include": [
+    "src/main-process.ts",
+    "src/preload.cts",
+    "src/sidecar.ts",
+    "src/todos.ts",
+    "src/types.ts"
+  ]
+}
diff --git a/examples/electron-wasix/tsconfig.renderer.json b/src/examples/electron-wasix/tsconfig.renderer.json
similarity index 100%
rename from examples/electron-wasix/tsconfig.renderer.json
rename to src/examples/electron-wasix/tsconfig.renderer.json
diff --git a/src/examples/electron-wasix/vite.config.ts b/src/examples/electron-wasix/vite.config.ts
new file mode 100644
index 000000000..9e9b6abd9
--- /dev/null
+++ b/src/examples/electron-wasix/vite.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+  root: '.',
+  base: './',
+  clearScreen: false,
+  server: {
+    port: 5175,
+    strictPort: true,
+  },
+  build: {
+    outDir: 'dist/renderer',
+    emptyOutDir: false,
+  },
+});
diff --git a/examples/electron/.gitignore b/src/examples/electron/.gitignore
similarity index 100%
rename from examples/electron/.gitignore
rename to src/examples/electron/.gitignore
diff --git a/src/examples/electron/README.md b/src/examples/electron/README.md
new file mode 100644
index 000000000..6190bf632
--- /dev/null
+++ b/src/examples/electron/README.md
@@ -0,0 +1,14 @@
+# Electron Native Todo
+
+Electron owns the Oliphaunt TypeScript SDK in the main process and exposes a
+small IPC surface to the renderer through preload. The app calls
+`Oliphaunt.openServer` with persistent storage under Electron's user data
+directory and owns the returned server handle. The explicit Electron E2E smoke
+also exercises the optional `@oliphaunt/tools` facade with a schema-only
+`pg_dump` and a non-interactive `psql` query; ordinary application startup does
+not run PostgreSQL client tools.
+
+```sh
+bun install --cwd src/examples/electron
+bun run --cwd src/examples/electron start
+```
diff --git a/examples/electron/index.html b/src/examples/electron/index.html
similarity index 100%
rename from examples/electron/index.html
rename to src/examples/electron/index.html
diff --git a/src/examples/electron/package.json b/src/examples/electron/package.json
new file mode 100644
index 000000000..e7a6cee37
--- /dev/null
+++ b/src/examples/electron/package.json
@@ -0,0 +1,25 @@
+{
+  "name": "oliphaunt-example-electron",
+  "private": true,
+  "version": "0.0.0",
+  "type": "module",
+  "scripts": {
+    "build": "tsc -p tsconfig.main.json && vite build",
+    "start": "bun run build && electron dist/main/main-process.js",
+    "dev:renderer": "vite"
+  },
+  "dependencies": {
+    "@oliphaunt/extension-contrib-pg18": "0.2.0",
+    "@oliphaunt/tools": "0.2.1",
+    "@oliphaunt/ts": "0.2.0",
+    "kysely": "^0.29.2",
+    "pg": "^8.16.3"
+  },
+  "devDependencies": {
+    "@types/node": "^24.10.1",
+    "@types/pg": "^8.15.6",
+    "electron": "^39.2.5",
+    "typescript": "^5.9.3",
+    "vite": "^6.0.3"
+  }
+}
diff --git a/examples/electron/pnpm-workspace.yaml b/src/examples/electron/pnpm-workspace.yaml
similarity index 100%
rename from examples/electron/pnpm-workspace.yaml
rename to src/examples/electron/pnpm-workspace.yaml
diff --git a/src/examples/electron/src/main-process.ts b/src/examples/electron/src/main-process.ts
new file mode 100644
index 000000000..f6e9b0ff4
--- /dev/null
+++ b/src/examples/electron/src/main-process.ts
@@ -0,0 +1,77 @@
+import { dirname, join } from 'node:path';
+import { fileURLToPath, pathToFileURL } from 'node:url';
+import { app, BrowserWindow, ipcMain } from 'electron';
+
+import { closeDatabase, createTodo, deleteTodo, listTodos, toggleTodo } from './todos.js';
+import type { CreateTodoInput, StatusFilter } from './types.js';
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+
+function createWindow() {
+  const window = new BrowserWindow({
+    width: 1100,
+    height: 760,
+    title: 'Oliphaunt Electron Todo',
+    webPreferences: {
+      preload: join(__dirname, 'preload.cjs'),
+      contextIsolation: true,
+      nodeIntegration: false,
+    },
+  });
+
+  const devServer = process.env.VITE_DEV_SERVER_URL;
+  if (devServer) {
+    void window.loadURL(devServer);
+  } else {
+    void window.loadFile(join(__dirname, '../renderer/index.html'));
+  }
+  return window;
+}
+
+async function runTestDriver(window: BrowserWindow) {
+  if (!process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER) return;
+  const driver = await import(
+    pathToFileURL(join(process.cwd(), '../tools/electron-test-driver.mts')).href
+  );
+  try {
+    await driver.runElectronTodoSmoke(window);
+    console.log('electron todo smoke passed');
+  } finally {
+    await closeDatabase();
+  }
+  app.exit(0);
+}
+
+ipcMain.handle('todos:list', (_event, filter: { search: string; status: StatusFilter }) =>
+  listTodos(app.getPath('userData'), filter),
+);
+ipcMain.handle('todos:create', (_event, input: CreateTodoInput) =>
+  createTodo(app.getPath('userData'), input),
+);
+ipcMain.handle('todos:toggle', (_event, id: number) => toggleTodo(app.getPath('userData'), id));
+ipcMain.handle('todos:delete', (_event, id: number) => deleteTodo(app.getPath('userData'), id));
+
+void app
+  .whenReady()
+  .then(async () => {
+    await runTestDriver(createWindow());
+  })
+  .catch((error) => {
+    console.error(error);
+    app.exit(1);
+  });
+
+app.on('activate', () => {
+  if (BrowserWindow.getAllWindows().length === 0) createWindow();
+});
+
+app.on('window-all-closed', () => {
+  if (process.platform !== 'darwin') app.quit();
+});
+
+app.on('before-quit', (event) => {
+  event.preventDefault();
+  closeDatabase()
+    .catch((error) => console.error(error))
+    .finally(() => app.exit(0));
+});
diff --git a/src/examples/electron/src/preload.cts b/src/examples/electron/src/preload.cts
new file mode 100644
index 000000000..526ed621a
--- /dev/null
+++ b/src/examples/electron/src/preload.cts
@@ -0,0 +1,19 @@
+import { contextBridge, ipcRenderer } from 'electron';
+import type { CreateTodoInput, StatusFilter, TodoApi } from './types.js';
+
+const api: TodoApi = {
+  listTodos(filter: { search: string; status: StatusFilter }) {
+    return ipcRenderer.invoke('todos:list', filter);
+  },
+  createTodo(input: CreateTodoInput) {
+    return ipcRenderer.invoke('todos:create', input);
+  },
+  toggleTodo(id: number) {
+    return ipcRenderer.invoke('todos:toggle', id);
+  },
+  deleteTodo(id: number) {
+    return ipcRenderer.invoke('todos:delete', id);
+  },
+};
+
+contextBridge.exposeInMainWorld('todos', api);
diff --git a/src/examples/electron/src/renderer.ts b/src/examples/electron/src/renderer.ts
new file mode 100644
index 000000000..4709a1ac9
--- /dev/null
+++ b/src/examples/electron/src/renderer.ts
@@ -0,0 +1,141 @@
+import type { CreateTodoInput, StatusFilter, Todo, TodoApi } from './types';
+
+declare global {
+  interface Window {
+    todos: TodoApi;
+  }
+}
+
+const form = document.querySelector('#todo-form');
+const list = document.querySelector('#todo-list');
+const status = document.querySelector('#status');
+const search = document.querySelector('#search');
+const openCount = document.querySelector('#open-count');
+const doneCount = document.querySelector('#done-count');
+const highCount = document.querySelector('#high-count');
+let activeStatus: StatusFilter = 'open';
+let todos: Todo[] = [];
+
+async function listTodos() {
+  todos = await window.todos.listTodos({
+    search: search?.value.trim() ?? '',
+    status: activeStatus,
+  });
+  render();
+}
+
+function setStatus(message: string) {
+  if (status) status.value = message;
+}
+
+function priorityLabel(priority: number) {
+  if (priority === 1) return 'High';
+  if (priority === 3) return 'Low';
+  return 'Normal';
+}
+
+function render() {
+  const open = todos.filter((todo) => !todo.done).length;
+  const done = todos.filter((todo) => todo.done).length;
+  const high = todos.filter((todo) => !todo.done && todo.priority === 1).length;
+  if (openCount) openCount.value = `${open} open`;
+  if (doneCount) doneCount.value = `${done} done`;
+  if (highCount) highCount.value = `${high} high priority`;
+  if (!list) return;
+  if (todos.length === 0) {
+    const empty = document.createElement('p');
+    empty.className = 'empty';
+    empty.textContent = 'No todos match the current filter.';
+    list.replaceChildren(empty);
+    return;
+  }
+  list.replaceChildren(...todos.map(renderTodo));
+}
+
+function renderTodo(todo: Todo) {
+  const row = document.createElement('article');
+  row.className = todo.done ? 'todo done' : 'todo';
+
+  const checkbox = document.createElement('input');
+  checkbox.type = 'checkbox';
+  checkbox.checked = todo.done;
+  checkbox.addEventListener('change', () => {
+    void window.todos
+      .toggleTodo(todo.id)
+      .then(listTodos)
+      .catch((error) => setStatus(String(error)));
+  });
+
+  const body = document.createElement('div');
+  const title = document.createElement('h2');
+  title.textContent = todo.title;
+  const notes = document.createElement('p');
+  notes.textContent = todo.notes || 'No notes';
+  const meta = document.createElement('div');
+  meta.className = 'meta';
+  for (const value of [
+    priorityLabel(todo.priority),
+    todo.area ? `area:${todo.area}` : '',
+    todo.context ? `context:${todo.context}` : '',
+    `updated ${todo.updatedAt}`,
+  ]) {
+    if (!value) continue;
+    const pill = document.createElement('span');
+    pill.className = 'pill';
+    pill.textContent = value;
+    meta.append(pill);
+  }
+  body.append(title, notes, meta);
+
+  const remove = document.createElement('button');
+  remove.className = 'secondary';
+  remove.type = 'button';
+  remove.textContent = 'Delete';
+  remove.addEventListener('click', () => {
+    void window.todos
+      .deleteTodo(todo.id)
+      .then(listTodos)
+      .catch((error) => setStatus(String(error)));
+  });
+
+  row.append(checkbox, body, remove);
+  return row;
+}
+
+form?.addEventListener('submit', (event) => {
+  event.preventDefault();
+  const data = new FormData(form);
+  const input: CreateTodoInput = {
+    title: String(data.get('title') ?? '').trim(),
+    notes: String(data.get('notes') ?? '').trim(),
+    area: String(data.get('area') ?? '').trim(),
+    context: String(data.get('context') ?? '').trim(),
+    priority: Number(data.get('priority') ?? 2),
+  };
+  if (!input.title) return;
+  setStatus('Saving');
+  window.todos
+    .createTodo(input)
+    .then(() => {
+      form.reset();
+      setStatus('Saved');
+      return listTodos();
+    })
+    .catch((error) => setStatus(String(error)));
+});
+
+search?.addEventListener('input', () => {
+  void listTodos().catch((error) => setStatus(String(error)));
+});
+
+document.querySelectorAll('[data-status]').forEach((button) => {
+  button.addEventListener('click', () => {
+    activeStatus = button.dataset.status as StatusFilter;
+    document.querySelectorAll('[data-status]').forEach((candidate) => {
+      candidate.classList.toggle('active', candidate === button);
+    });
+    void listTodos().catch((error) => setStatus(String(error)));
+  });
+});
+
+void listTodos().catch((error) => setStatus(String(error)));
diff --git a/examples/electron/src/styles.css b/src/examples/electron/src/styles.css
similarity index 100%
rename from examples/electron/src/styles.css
rename to src/examples/electron/src/styles.css
diff --git a/src/examples/electron/src/todos.ts b/src/examples/electron/src/todos.ts
new file mode 100644
index 000000000..9c12ae835
--- /dev/null
+++ b/src/examples/electron/src/todos.ts
@@ -0,0 +1,213 @@
+import { join } from 'node:path';
+
+import { Oliphaunt, type OliphauntServer } from '@oliphaunt/ts';
+import { pgDump, psql } from '@oliphaunt/tools';
+import { Kysely, PostgresDialect, sql, type Generated } from 'kysely';
+import pg from 'pg';
+
+import type { CreateTodoInput, StatusFilter, Todo } from './types.js';
+
+const { Pool } = pg;
+
+type TodoTable = {
+  id: Generated;
+  title: string;
+  notes: string;
+  tags: string;
+  done: Generated;
+  priority: number;
+  created_at: Generated;
+  updated_at: Generated;
+};
+
+type TodoDatabase = {
+  todos: TodoTable;
+};
+
+type TodoRecord = {
+  id: string;
+  title: string;
+  notes: string;
+  area: string;
+  context: string;
+  done: string;
+  priority: string;
+  created_at: string;
+  updated_at: string;
+};
+
+type Store = {
+  native: OliphauntServer;
+  db: Kysely;
+};
+
+const schemaStatements = [
+  'CREATE EXTENSION IF NOT EXISTS hstore',
+  'CREATE EXTENSION IF NOT EXISTS pg_trgm',
+  'CREATE EXTENSION IF NOT EXISTS unaccent',
+  `CREATE TABLE IF NOT EXISTS todos (
+    id bigserial PRIMARY KEY,
+    title text NOT NULL,
+    notes text NOT NULL DEFAULT '',
+    tags hstore NOT NULL DEFAULT ''::hstore,
+    done boolean NOT NULL DEFAULT false,
+    priority integer NOT NULL DEFAULT 2 CHECK (priority BETWEEN 1 AND 3),
+    created_at timestamptz NOT NULL DEFAULT now(),
+    updated_at timestamptz NOT NULL DEFAULT now()
+  )`,
+  'CREATE INDEX IF NOT EXISTS todos_title_trgm ON todos USING gin (title gin_trgm_ops)',
+];
+
+let storePromise: Promise | undefined;
+
+export function getDatabase(userData: string) {
+  storePromise ??= openDatabase(userData);
+  return storePromise;
+}
+
+async function openDatabase(userData: string): Promise {
+  const native = await Oliphaunt.openServer({
+    storage: { kind: 'directory', path: join(userData, 'oliphaunt-native-todos') },
+    extensions: ['hstore', 'pg_trgm', 'unaccent'],
+  });
+  const connectionString = native.connectionString;
+  const db = new Kysely({
+    dialect: new PostgresDialect({
+      pool: new Pool({
+        connectionString,
+        max: 2,
+      }),
+    }),
+  });
+  for (const statement of schemaStatements) {
+    await sql.raw(statement).execute(db);
+  }
+  if (process.env.OLIPHAUNT_ELECTRON_E2E_DRIVER) {
+    await validatePostgresTools(connectionString);
+  }
+  return { native, db };
+}
+
+async function validatePostgresTools(connectionString: string): Promise {
+  const dump = await pgDump(connectionString, { args: ['--schema-only'] });
+  if (!dump.includes('PostgreSQL database dump')) {
+    throw new Error('pg_dump schema smoke did not return a PostgreSQL dump');
+  }
+  const output = await psql(connectionString, {
+    args: ['-tA'],
+    command: 'SELECT 1',
+  });
+  if (!output.split('\n').some((line) => line.trim() === '1')) {
+    throw new Error('psql smoke did not return SELECT 1 output');
+  }
+}
+
+export async function listTodos(
+  userData: string,
+  filter: { search: string; status: StatusFilter },
+) {
+  const { db } = await getDatabase(userData);
+  const rows = await db
+    .selectFrom('todos')
+    .select(todoColumns)
+    .where(searchPredicate(filter.search))
+    .where(statusPredicate(filter.status))
+    .orderBy('done', 'asc')
+    .orderBy('priority', 'asc')
+    .orderBy('updated_at', 'desc')
+    .orderBy('id', 'desc')
+    .execute();
+  return rows.map(todoFromRow);
+}
+
+export async function createTodo(userData: string, input: CreateTodoInput) {
+  const { db } = await getDatabase(userData);
+  const row = await db
+    .insertInto('todos')
+    .values({
+      title: input.title,
+      notes: input.notes,
+      tags: sql`hstore(ARRAY['area', ${input.area}, 'context', ${input.context}])`,
+      priority: clampPriority(input.priority),
+    })
+    .returning(todoColumns)
+    .executeTakeFirstOrThrow();
+  return todoFromRow(row);
+}
+
+export async function toggleTodo(userData: string, id: number) {
+  const { db } = await getDatabase(userData);
+  const row = await db
+    .updateTable('todos')
+    .set({
+      done: sql`NOT done`,
+      updated_at: sql`now()`,
+    })
+    .where('id', '=', String(id))
+    .returning(todoColumns)
+    .executeTakeFirstOrThrow();
+  return todoFromRow(row);
+}
+
+export async function deleteTodo(userData: string, id: number) {
+  const { db } = await getDatabase(userData);
+  await db.deleteFrom('todos').where('id', '=', String(id)).execute();
+}
+
+export async function closeDatabase() {
+  if (!storePromise) return;
+  const store = await storePromise;
+  await store.db.destroy();
+  await store.native.close();
+  storePromise = undefined;
+}
+
+function todoColumns() {
+  return [
+    sql`id::text`.as('id'),
+    'title',
+    'notes',
+    sql`COALESCE(tags -> 'area', '')`.as('area'),
+    sql`COALESCE(tags -> 'context', '')`.as('context'),
+    sql`done::text`.as('done'),
+    sql`priority::text`.as('priority'),
+    sql`to_char(created_at, 'YYYY-MM-DD HH24:MI')`.as('created_at'),
+    sql`to_char(updated_at, 'YYYY-MM-DD HH24:MI')`.as('updated_at'),
+  ] as const;
+}
+
+function searchPredicate(search: string) {
+  return sql`(
+    ${search}::text = ''
+    OR unaccent(title || ' ' || notes) ILIKE '%' || unaccent(${search}::text) || '%'
+    OR COALESCE(tags -> 'area', '') ILIKE '%' || ${search}::text || '%'
+    OR COALESCE(tags -> 'context', '') ILIKE '%' || ${search}::text || '%'
+    OR tags ? ${search}::text
+  )`;
+}
+
+function statusPredicate(status: StatusFilter) {
+  return sql`(
+    ${status}::text = 'all'
+    OR (${status}::text = 'open' AND NOT done)
+    OR (${status}::text = 'done' AND done)
+  )`;
+}
+
+function todoFromRow(row: TodoRecord): Todo {
+  return {
+    id: Number(row.id),
+    title: row.title,
+    notes: row.notes,
+    area: row.area,
+    context: row.context,
+    priority: Number(row.priority),
+    done: row.done === 'true',
+    createdAt: row.created_at,
+    updatedAt: row.updated_at,
+  };
+}
+
+function clampPriority(value: number) {
+  return Math.min(Math.max(Math.trunc(value) || 2, 1), 3);
+}
diff --git a/src/examples/electron/src/types.ts b/src/examples/electron/src/types.ts
new file mode 100644
index 000000000..bf7f325c2
--- /dev/null
+++ b/src/examples/electron/src/types.ts
@@ -0,0 +1,28 @@
+export type Todo = {
+  id: number;
+  title: string;
+  notes: string;
+  area: string;
+  context: string;
+  priority: number;
+  done: boolean;
+  createdAt: string;
+  updatedAt: string;
+};
+
+export type CreateTodoInput = {
+  title: string;
+  notes: string;
+  area: string;
+  context: string;
+  priority: number;
+};
+
+export type StatusFilter = 'open' | 'all' | 'done';
+
+export type TodoApi = {
+  listTodos(filter: { search: string; status: StatusFilter }): Promise;
+  createTodo(input: CreateTodoInput): Promise;
+  toggleTodo(id: number): Promise;
+  deleteTodo(id: number): Promise;
+};
diff --git a/examples/electron/tsconfig.main.json b/src/examples/electron/tsconfig.main.json
similarity index 100%
rename from examples/electron/tsconfig.main.json
rename to src/examples/electron/tsconfig.main.json
diff --git a/examples/electron/tsconfig.renderer.json b/src/examples/electron/tsconfig.renderer.json
similarity index 100%
rename from examples/electron/tsconfig.renderer.json
rename to src/examples/electron/tsconfig.renderer.json
diff --git a/src/examples/electron/vite.config.ts b/src/examples/electron/vite.config.ts
new file mode 100644
index 000000000..10cdbf164
--- /dev/null
+++ b/src/examples/electron/vite.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+  root: '.',
+  base: './',
+  clearScreen: false,
+  server: {
+    port: 5174,
+    strictPort: true,
+  },
+  build: {
+    outDir: 'dist/renderer',
+    emptyOutDir: false,
+  },
+});
diff --git a/src/examples/moon.yml b/src/examples/moon.yml
new file mode 100644
index 000000000..f993b227d
--- /dev/null
+++ b/src/examples/moon.yml
@@ -0,0 +1,191 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "integration-examples"
+language: "typescript"
+layer: "application"
+stack: "frontend"
+tags: ["javascript-quality", "examples", "integration"]
+dependsOn:
+  - id: "extension-packages"
+    scope: "build"
+  - id: "extensions"
+    scope: "build"
+  - "liboliphaunt-native"
+  - "oliphaunt-broker"
+  - "oliphaunt-js"
+  - "oliphaunt-kotlin"
+  - "oliphaunt-node-direct"
+  - "oliphaunt-react-native"
+  - "oliphaunt-swift"
+  - "oliphaunt-wasix-ts"
+  - "release-tools"
+
+project:
+  title: "Integration Examples"
+  description: "Cross-product examples and installed-app validation entrypoints."
+  owner: "oliphaunt"
+
+owners:
+  defaultOwner: "@oliphaunt/core"
+  paths:
+    "**/*": ["@oliphaunt/core"]
+
+tasks:
+  browser-wasix-typecheck:
+    tags: ["quality", "static", "browser", "wasix"]
+    command: "bun run --cwd src/examples/browser-wasix typecheck"
+    deps:
+      - "oliphaunt-query-ts:build"
+    inputs:
+      - "browser-wasix/**/*"
+      - project: "oliphaunt-wasix-ts"
+        group: "code"
+      - "@group(bun-workspace)"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  test:
+    tags: ["quality", "unit"]
+    script: |
+      set -e
+      bash src/examples/tools/stage-tauri-webdriver-app.test.sh
+      bash src/examples/tools/run-tauri-webdriver-smoke.test.sh
+      bun test src/examples/react-native-expo/tools/smoke-pass-receipt.test.mts src/examples/react-native-expo/tools/mobile-extension-proof.test.mts
+    inputs:
+      - "**/*"
+      - "@group(bun-workspace)"
+      - "!/src/examples/**/node_modules"
+      - "!/src/examples/**/node_modules/**"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  react-native-android-build:
+    tags: ["mobile", "build", "android", "ci-mobile-build-android"]
+    script: |
+      export OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT="${OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT:-$PWD/target/mobile-extension-artifacts}"
+      exec bun run --cwd src/examples/react-native-expo mobile-build:android
+    deps:
+      - "oliphaunt-query-ts:package"
+      - "database-resources:build-native-android-icu"
+      - "database-resources:package-icu"
+      - "extension-packages:package-mobile"
+      - "liboliphaunt-native:package-runtime-android-x86_64"
+      - "liboliphaunt-native:finalize-runtime-android-abi"
+      - "oliphaunt-kotlin:package"
+      - "oliphaunt-react-native:package"
+    inputs:
+      - "react-native-expo/**/*"
+      - project: "oliphaunt-kotlin"
+        group: "code"
+      - project: "oliphaunt-react-native"
+        group: "code"
+      - project: "extensions"
+        group: "build"
+      - "/target/mobile-extension-artifacts/**/*"
+      - "/target/sdk-artifacts/oliphaunt-kotlin/**/*"
+      - "/target/sdk-artifacts/oliphaunt-react-native/**/*"
+      - "/src/runtimes/liboliphaunt-native/packaging/**/*"
+    outputs:
+      - "/target/mobile-build/react-native/android/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  react-native-android-e2e:
+    tags: ["mobile", "e2e", "android"]
+    command: "bun run --cwd src/examples/react-native-expo mobile-e2e:android"
+    deps:
+      - "integration-examples:react-native-android-build"
+    inputs:
+      - "react-native-expo/src/**/*"
+      - "react-native-expo/maestro/**/*"
+      - "react-native-expo/package.json"
+      - project: "oliphaunt-react-native"
+        group: "code"
+      - "/tools/dev/maestro.toml"
+      - "/tools/dev/setup-maestro.sh"
+      - "/target/mobile-build/react-native/android/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: skip
+  react-native-android-drill:
+    tags: ["mobile", "drill", "android"]
+    command: "bun run --cwd src/examples/react-native-expo mobile-drill:android"
+    inputs:
+      - "react-native-expo/**/*"
+      - project: "oliphaunt-kotlin"
+        group: "code"
+      - project: "oliphaunt-react-native"
+        group: "code"
+      - project: "extensions"
+        group: "build"
+      - "/src/runtimes/liboliphaunt-native/packaging/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: false
+  react-native-ios-build:
+    tags: ["mobile", "build", "ios", "ci-mobile-build-ios"]
+    script: |
+      export OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT="${OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT:-$PWD/target/mobile-extension-artifacts}"
+      exec bun run --cwd src/examples/react-native-expo mobile-build:ios
+    deps:
+      - "oliphaunt-query-ts:package"
+      - "database-resources:build-native-ios-icu"
+      - "database-resources:package-icu"
+      - "extension-packages:package-mobile"
+      - "liboliphaunt-native:package-runtime-ios-xcframework"
+      - "oliphaunt-react-native:package"
+      - "oliphaunt-swift:package"
+    inputs:
+      - "react-native-expo/**/*"
+      - project: "oliphaunt-react-native"
+        group: "code"
+      - project: "oliphaunt-swift"
+        group: "code"
+      - project: "extensions"
+        group: "build"
+      - "/target/mobile-extension-artifacts/**/*"
+      - "/target/sdk-artifacts/oliphaunt-react-native/**/*"
+      - "/target/sdk-artifacts/oliphaunt-swift/**/*"
+      - "/src/runtimes/liboliphaunt-native/packaging/**/*"
+    outputs:
+      - "/target/mobile-build/react-native/ios/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  react-native-ios-e2e:
+    tags: ["mobile", "e2e", "ios"]
+    command: "bun run --cwd src/examples/react-native-expo mobile-e2e:ios"
+    deps:
+      - "integration-examples:react-native-ios-build"
+    inputs:
+      - "react-native-expo/src/**/*"
+      - "react-native-expo/maestro/**/*"
+      - "react-native-expo/package.json"
+      - project: "oliphaunt-react-native"
+        group: "code"
+      - "/tools/dev/maestro.toml"
+      - "/tools/dev/setup-maestro.sh"
+      - "/target/mobile-build/react-native/ios/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: skip
+  react-native-ios-drill:
+    tags: ["mobile", "drill", "ios"]
+    command: "bun run --cwd src/examples/react-native-expo mobile-drill:ios"
+    inputs:
+      - "react-native-expo/**/*"
+      - project: "oliphaunt-react-native"
+        group: "code"
+      - project: "oliphaunt-swift"
+        group: "code"
+      - project: "extensions"
+        group: "build"
+      - "/src/runtimes/liboliphaunt-native/packaging/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: false
diff --git a/examples/react-native-expo/.gitignore b/src/examples/react-native-expo/.gitignore
similarity index 100%
rename from examples/react-native-expo/.gitignore
rename to src/examples/react-native-expo/.gitignore
diff --git a/examples/react-native-expo/.vscode/extensions.json b/src/examples/react-native-expo/.vscode/extensions.json
similarity index 100%
rename from examples/react-native-expo/.vscode/extensions.json
rename to src/examples/react-native-expo/.vscode/extensions.json
diff --git a/examples/react-native-expo/.vscode/settings.json b/src/examples/react-native-expo/.vscode/settings.json
similarity index 100%
rename from examples/react-native-expo/.vscode/settings.json
rename to src/examples/react-native-expo/.vscode/settings.json
diff --git a/examples/react-native-expo/LICENSE b/src/examples/react-native-expo/LICENSE
similarity index 100%
rename from examples/react-native-expo/LICENSE
rename to src/examples/react-native-expo/LICENSE
diff --git a/src/examples/react-native-expo/README.md b/src/examples/react-native-expo/README.md
new file mode 100644
index 000000000..0233048c5
--- /dev/null
+++ b/src/examples/react-native-expo/README.md
@@ -0,0 +1,212 @@
+# React Native Oliphaunt Expo Example
+
+This is a real Expo development-build app for validating
+`@oliphaunt/react-native` against the Kotlin Android SDK and the New
+Architecture JSI `ArrayBuffer` transport.
+
+The first screen is a small field-ops task board rather than a static smoke
+screen. On launch it opens one direct database, creates a
+project/task/event schema, seeds 240 tasks in a transaction, updates work items
+in a second transaction, runs parameterized aggregate/search queries, and logs
+latency percentiles through `OLIPHAUNT_EXPO_SMOKE_PASS`.
+
+The installed-app smoke activates the generated mobile extension set and runs
+the extension-specific runtime proofs, including the pgvector HNSW query.
+
+Fast Android smoke:
+
+```sh
+bun run smoke
+bun run smoke:android
+```
+
+`bun run smoke` is the default installed-app harness: it runs the Android and
+iOS Expo development-client smokes through the repository validation script.
+Use `smoke:android` or `smoke:ios` when only one simulator/device stack is
+available.
+
+The default local dev command is the Expo development-client harness with local
+Expo MCP capabilities enabled, not Expo Go:
+
+```sh
+bun run start
+bun run android:start
+bun run ios:start
+```
+
+The automated smoke, benchmark, and crash scripts start their own
+development-client Metro server with local MCP enabled by default so the native
+runner receives the same env on every machine. If port 8081 is busy, they choose
+a free port in 8082-8099 unless `OLIPHAUNT_EXPO_*_METRO_PORT` is set explicitly.
+Set `OLIPHAUNT_EXPO_*_REUSE_METRO=1` only when manually attaching to a Metro
+process that already has the desired `EXPO_PUBLIC_OLIPHAUNT_*` env.
+
+Device benchmark runs use the same native build/package path but launch the app
+with the benchmark runner. They emit `OLIPHAUNT_EXPO_BENCH_PASS` and write the
+parsed JSON report under `target/oliphaunt-expo--benchmark/reports/`.
+The report includes typed and parameterized RTT, set-based insert throughput,
+JS timer liveness, effective PostgreSQL settings, and checkpoint latency. The
+platform harness records process memory and built artifact sizes separately. A
+same-device Expo SQLite WAL baseline uses its own explicit SQLite durability
+profile so comparisons do not invent an Oliphaunt durability mode:
+
+```sh
+bun run bench:android
+bun run bench:ios
+```
+
+Process-death recovery runs use the same dev-client build but launch a
+two-phase crash harness. The write phase opens persistent app-private storage,
+writes committed data, and leaves the database open. The platform script then
+force-stops/terminates the app process and relaunches the verify phase against
+the same storage with a fresh phase-specific dev-client bundle, expecting
+PostgreSQL recovery to make the committed row visible. Before writing, the app
+verifies the effective PostgreSQL `fsync`, `full_page_writes`, and
+`synchronous_commit` settings are all `on`:
+
+```sh
+bun run crash:android
+bun run crash:ios
+```
+
+The runners choose isolated persistent storage by default. Set
+`OLIPHAUNT_EXPO_ANDROID_CRASH_STORAGE` or
+`OLIPHAUNT_EXPO_IOS_CRASH_STORAGE` to override it; the iOS runner accepts an
+`app-data:` selector for the public `applicationData` storage case.
+
+The smoke script:
+
+- packs the current React Native SDK when sources changed;
+- installs the packed SDK into this Expo app when needed;
+- runs Expo prebuild for Android when the ignored generated `android/` project
+  is missing;
+- builds clean Android `liboliphaunt` runtime resources with runtime files,
+  a standard cluster seed, package-size evidence, and `liboliphaunt.so`;
+- builds and installs the dev-client APK;
+- launches through Expo dev-client and waits for
+  `OLIPHAUNT_EXPO_SMOKE_PASS` from logcat.
+
+Useful overrides:
+
+```sh
+OLIPHAUNT_EXPO_MOBILE_STARTUP_GUCS=shared_buffers=8MB,wal_buffers=-1 bun run bench:android
+OLIPHAUNT_EXPO_MOBILE_BENCHMARK_PRESET=quick bun run bench:android
+OLIPHAUNT_EXPO_ANDROID_SKIP_BUILD=1 bun run smoke:android
+OLIPHAUNT_EXPO_ANDROID_KEEP_METRO=1 bun run smoke:android
+OLIPHAUNT_EXPO_ANDROID_REPACKAGE_ASSETS=1 bun run smoke:android
+OLIPHAUNT_EXPO_ANDROID_GRADLE_CONFIGURATION_CACHE=1 bun run smoke:android
+OLIPHAUNT_EXPO_ANDROID_RUNTIME_DIR=/path/to/runtime bun run smoke:android
+OLIPHAUNT_EXPO_ANDROID_SEED_CLOSURE_DIR=/path/to/android-datum64-runtime-closure bun run smoke:android
+OLIPHAUNT_EXPO_ANDROID_OLIPHAUNT_SO=/path/to/liboliphaunt.so bun run smoke:android
+```
+
+Benchmark and crash tuning uses explicit PostgreSQL startup GUCs:
+
+```sh
+export OLIPHAUNT_EXPO_MOBILE_STARTUP_GUCS=shared_buffers=32MB,wal_buffers=-1,min_wal_size=32MB,max_wal_size=64MB
+bun run bench:android
+bun run crash:android
+```
+
+Use `bench:ios` and `crash:ios` for iOS. Set
+`OLIPHAUNT_EXPO_MOBILE_BENCHMARK_PRESET=quick` for harness checks; keep the
+full default for reported performance. For multiple configurations, use a
+Shell loop and distinct `OLIPHAUNT_EXPO_ANDROID_SCRATCH` or
+`OLIPHAUNT_EXPO_IOS_SCRATCH` paths to retain each raw report.
+
+The harness defaults to `--no-configuration-cache` for the Expo app because the
+generated Expo Gradle files currently resolve React Native/Expo paths through
+Node during configuration. Keep configuration cache opt-in until that upstream
+behavior changes.
+
+Fast iOS build/smoke harness:
+
+```sh
+OLIPHAUNT_EXPO_IOS_OLIPHAUNT_XCFRAMEWORK=/path/to/liboliphaunt.xcframework \
+OLIPHAUNT_EXPO_IOS_RUNTIME_DIR=/path/to/postgres-runtime \
+OLIPHAUNT_EXPO_IOS_SEED_CLOSURE_DIR=/path/to/ios-datum64-runtime-closure \
+bun run smoke:ios
+```
+
+Use `OLIPHAUNT_EXPO_IOS_BUILD_ONLY=1` when you only want the generated Expo iOS
+project, CocoaPods integration, bundled resources, and Xcode build checked. The
+script rejects macOS `liboliphaunt.dylib` artifacts; iOS validation needs an iOS
+simulator/device build of `liboliphaunt`. For an unsigned generic iPhoneOS
+compile/package check, set `OLIPHAUNT_EXPO_IOS_SDK=iphoneos`,
+`OLIPHAUNT_EXPO_IOS_BUILD_ONLY=1`, and
+`OLIPHAUNT_EXPO_IOS_CODE_SIGNING_ALLOWED=NO`; install/launch benchmarks still
+require a runnable paired phone and valid signing.
+
+Physical iOS runs use Xcode's `devicectl` path:
+
+```sh
+OLIPHAUNT_EXPO_IOS_SDK=iphoneos \
+OLIPHAUNT_EXPO_IOS_OLIPHAUNT_XCFRAMEWORK=/path/to/liboliphaunt.xcframework \
+OLIPHAUNT_EXPO_IOS_RUNTIME_DIR=/path/to/postgres-runtime \
+OLIPHAUNT_EXPO_IOS_SEED_CLOSURE_DIR=/path/to/ios-datum64-runtime-closure \
+bun run bench:ios
+```
+
+Set `OLIPHAUNT_EXPO_IOS_DEVICE_ID` to pick a specific paired device, and
+`OLIPHAUNT_EXPO_IOS_METRO_URL` if the device cannot reach the host address that
+the harness auto-detects. Device crash-recovery runs default to the public
+`{ kind: 'applicationData', name }` storage case, which the platform SDK
+resolves inside the app sandbox and which survives process death.
+
+Physical-device runs require a working Apple Development signing setup. The
+harness first checks that the paired phone has Developer Mode and Developer Disk
+Image services available through `devicectl`, then uses
+`OLIPHAUNT_EXPO_IOS_DEVELOPMENT_TEAM` when set, otherwise it uses the single
+team configured in Xcode. If Xcode has multiple teams configured, set
+`OLIPHAUNT_EXPO_IOS_DEVELOPMENT_TEAM` explicitly. If no local signing identity
+is installed the harness fails before doing the expensive Expo/CocoaPods work; set
+`OLIPHAUNT_EXPO_IOS_ALLOW_PROVISIONING_UPDATES=1` to explicitly allow
+`xcodebuild -allowProvisioningUpdates` and device registration when the Xcode
+account session is valid. Override with `OLIPHAUNT_EXPO_IOS_CODE_SIGN_IDENTITY`,
+`OLIPHAUNT_EXPO_IOS_PROVISIONING_PROFILE_SPECIFIER`, or
+`OLIPHAUNT_EXPO_IOS_ALLOW_PROVISIONING_UPDATES=0` for locked-down local/CI
+signing.
+
+The iPhone must be unlocked and awake when `devicectl` launches the development
+client. If a physical run already built and installed the app but launch failed
+because the device was locked, retry without rebuilding:
+
+```sh
+OLIPHAUNT_EXPO_IOS_REUSE_INSTALLED_APP=1 \
+OLIPHAUNT_EXPO_IOS_SDK=iphoneos \
+OLIPHAUNT_EXPO_IOS_DEVICE_ID= \
+bun run crash:ios
+```
+
+The physical iOS smoke harness exercises background/foreground automatically:
+after the app reaches `lifecycle:ready`, it opens Safari, waits
+`OLIPHAUNT_EXPO_IOS_BACKGROUND_SECONDS` seconds, then foregrounds the same
+installed app and verifies SQL still works on the resumed database.
+
+Expo local MCP capabilities are installed through `expo-mcp`:
+
+```sh
+bun run mcp:version
+bun run mcp:start
+```
+
+`mcp:start` is an alias for the default `bun run start` dev-client/MCP harness,
+which is the local tool path for screenshots, app logs, DevTools, and automation
+from MCP-capable agents. Expo's remote MCP server requires Expo OAuth/EAS
+access, so the repo keeps local CLI/dev-client validation as the default
+reproducible path.
+
+EAS CLI is intentionally used through `npx eas-cli@latest` for build-service
+operations so the example does not pin a stale global CLI:
+
+```sh
+npx eas-cli@latest --version
+```
+
+Baseline local checks:
+
+```sh
+bun run typecheck
+bun run lint -- --max-warnings=0
+npx expo-doctor
+```
diff --git a/examples/react-native-expo/app.json b/src/examples/react-native-expo/app.json
similarity index 100%
rename from examples/react-native-expo/app.json
rename to src/examples/react-native-expo/app.json
diff --git a/examples/react-native-expo/assets/expo.icon/Assets/expo-symbol 2.svg b/src/examples/react-native-expo/assets/expo.icon/Assets/expo-symbol 2.svg
similarity index 100%
rename from examples/react-native-expo/assets/expo.icon/Assets/expo-symbol 2.svg
rename to src/examples/react-native-expo/assets/expo.icon/Assets/expo-symbol 2.svg
diff --git a/examples/react-native-expo/assets/expo.icon/Assets/grid.png b/src/examples/react-native-expo/assets/expo.icon/Assets/grid.png
similarity index 100%
rename from examples/react-native-expo/assets/expo.icon/Assets/grid.png
rename to src/examples/react-native-expo/assets/expo.icon/Assets/grid.png
diff --git a/src/examples/react-native-expo/assets/expo.icon/icon.json b/src/examples/react-native-expo/assets/expo.icon/icon.json
new file mode 100644
index 000000000..9a26f70e2
--- /dev/null
+++ b/src/examples/react-native-expo/assets/expo.icon/icon.json
@@ -0,0 +1,35 @@
+{
+  "fill": {
+    "automatic-gradient": "extended-srgb:0.00000,0.47843,1.00000,1.00000"
+  },
+  "groups": [
+    {
+      "layers": [
+        {
+          "image-name": "expo-symbol 2.svg",
+          "name": "expo-symbol 2",
+          "position": {
+            "scale": 1,
+            "translation-in-points": [1.1008400065293245e-5, -16.046875]
+          }
+        },
+        {
+          "image-name": "grid.png",
+          "name": "grid"
+        }
+      ],
+      "shadow": {
+        "kind": "neutral",
+        "opacity": 0.5
+      },
+      "translucency": {
+        "enabled": true,
+        "value": 0.5
+      }
+    }
+  ],
+  "supported-platforms": {
+    "circles": ["watchOS"],
+    "squares": "shared"
+  }
+}
diff --git a/examples/react-native-expo/assets/images/android-icon-background.png b/src/examples/react-native-expo/assets/images/android-icon-background.png
similarity index 100%
rename from examples/react-native-expo/assets/images/android-icon-background.png
rename to src/examples/react-native-expo/assets/images/android-icon-background.png
diff --git a/examples/react-native-expo/assets/images/android-icon-foreground.png b/src/examples/react-native-expo/assets/images/android-icon-foreground.png
similarity index 100%
rename from examples/react-native-expo/assets/images/android-icon-foreground.png
rename to src/examples/react-native-expo/assets/images/android-icon-foreground.png
diff --git a/examples/react-native-expo/assets/images/android-icon-monochrome.png b/src/examples/react-native-expo/assets/images/android-icon-monochrome.png
similarity index 100%
rename from examples/react-native-expo/assets/images/android-icon-monochrome.png
rename to src/examples/react-native-expo/assets/images/android-icon-monochrome.png
diff --git a/examples/react-native-expo/assets/images/favicon.png b/src/examples/react-native-expo/assets/images/favicon.png
similarity index 100%
rename from examples/react-native-expo/assets/images/favicon.png
rename to src/examples/react-native-expo/assets/images/favicon.png
diff --git a/examples/react-native-expo/assets/images/icon.png b/src/examples/react-native-expo/assets/images/icon.png
similarity index 100%
rename from examples/react-native-expo/assets/images/icon.png
rename to src/examples/react-native-expo/assets/images/icon.png
diff --git a/examples/react-native-expo/assets/images/splash-icon.png b/src/examples/react-native-expo/assets/images/splash-icon.png
similarity index 100%
rename from examples/react-native-expo/assets/images/splash-icon.png
rename to src/examples/react-native-expo/assets/images/splash-icon.png
diff --git a/examples/react-native-expo/eas.json b/src/examples/react-native-expo/eas.json
similarity index 100%
rename from examples/react-native-expo/eas.json
rename to src/examples/react-native-expo/eas.json
diff --git a/src/examples/react-native-expo/eslint.config.cts b/src/examples/react-native-expo/eslint.config.cts
new file mode 100644
index 000000000..5025da683
--- /dev/null
+++ b/src/examples/react-native-expo/eslint.config.cts
@@ -0,0 +1,10 @@
+// https://docs.expo.dev/guides/using-eslint/
+const { defineConfig } = require('eslint/config');
+const expoConfig = require('eslint-config-expo/flat');
+
+module.exports = defineConfig([
+  expoConfig,
+  {
+    ignores: ['dist/*'],
+  },
+]);
diff --git a/examples/react-native-expo/index.js b/src/examples/react-native-expo/index.ts
similarity index 100%
rename from examples/react-native-expo/index.js
rename to src/examples/react-native-expo/index.ts
diff --git a/examples/react-native-expo/maestro/installed-smoke.yaml b/src/examples/react-native-expo/maestro/installed-smoke.yaml
similarity index 100%
rename from examples/react-native-expo/maestro/installed-smoke.yaml
rename to src/examples/react-native-expo/maestro/installed-smoke.yaml
diff --git a/examples/react-native-expo/metro.config.js b/src/examples/react-native-expo/metro.config.cts
similarity index 100%
rename from examples/react-native-expo/metro.config.js
rename to src/examples/react-native-expo/metro.config.cts
diff --git a/src/examples/react-native-expo/package.json b/src/examples/react-native-expo/package.json
new file mode 100644
index 000000000..dc43be672
--- /dev/null
+++ b/src/examples/react-native-expo/package.json
@@ -0,0 +1,60 @@
+{
+  "name": "react-native-oliphaunt-expo",
+  "main": "index.ts",
+  "version": "0.0.0",
+  "dependencies": {
+    "@oliphaunt/react-native": "workspace:*",
+    "expo": "~56.0.15",
+    "expo-dev-client": "~56.0.22",
+    "expo-splash-screen": "~56.0.12",
+    "expo-sqlite": "~56.0.5",
+    "expo-system-ui": "~56.0.5",
+    "react": "19.2.3",
+    "react-dom": "19.2.3",
+    "react-native": "0.85.3",
+    "react-native-safe-area-context": "~5.7.0",
+    "react-native-web": "~0.21.0"
+  },
+  "devDependencies": {
+    "@react-native-community/cli": "20.2.0",
+    "@react-native-community/cli-platform-android": "20.2.0",
+    "@react-native-community/cli-platform-ios": "20.2.0",
+    "@react-native/metro-config": "0.85.3",
+    "@types/react": "19.2.16",
+    "eslint": "^9.0.0",
+    "eslint-config-expo": "~56.0.4",
+    "expo-doctor": "^1.19.7",
+    "expo-mcp": "~0.2.1",
+    "typescript": "~6.0.3"
+  },
+  "scripts": {
+    "start": "EXPO_UNSTABLE_MCP_SERVER=1 expo start --dev-client",
+    "android": "expo run:android",
+    "android:start": "EXPO_UNSTABLE_MCP_SERVER=1 expo start --dev-client --android",
+    "doctor": "expo-doctor",
+    "ios": "expo run:ios",
+    "ios:start": "EXPO_UNSTABLE_MCP_SERVER=1 expo start --dev-client --ios",
+    "mcp:version": "expo-mcp --version",
+    "mcp:start": "bun run start",
+    "prebuild:android": "expo prebuild --platform android",
+    "prebuild:ios": "expo prebuild --platform ios",
+    "smoke": "bun run smoke:android && bun run smoke:ios",
+    "mobile-build:android": "../../sdks/react-native/tools/mobile-build.sh android",
+    "mobile-build:ios": "../../sdks/react-native/tools/mobile-build.sh ios",
+    "mobile-e2e": "bun run mobile-e2e:android && bun run mobile-e2e:ios",
+    "mobile-e2e:android": "../../sdks/react-native/tools/mobile-e2e.sh android",
+    "mobile-e2e:ios": "../../sdks/react-native/tools/mobile-e2e.sh ios",
+    "mobile-drill:android": "../../sdks/react-native/tools/mobile-drill.sh android",
+    "mobile-drill:ios": "../../sdks/react-native/tools/mobile-drill.sh ios",
+    "bench:android": "../../sdks/react-native/tools/mobile-drill.sh android benchmark",
+    "bench:ios": "../../sdks/react-native/tools/mobile-drill.sh ios benchmark",
+    "crash:android": "../../sdks/react-native/tools/mobile-drill.sh android crash",
+    "crash:ios": "../../sdks/react-native/tools/mobile-drill.sh ios crash",
+    "smoke:android": "bun run mobile-build:android && bun run mobile-e2e:android",
+    "smoke:ios": "bun run mobile-build:ios && bun run mobile-e2e:ios",
+    "typecheck": "tsc --noEmit",
+    "web": "expo start --web",
+    "lint": "eslint --flag unstable_native_nodejs_ts_config ."
+  },
+  "private": true
+}
diff --git a/examples/react-native-expo/src/SmokeDashboard.tsx b/src/examples/react-native-expo/src/SmokeDashboard.tsx
similarity index 94%
rename from examples/react-native-expo/src/SmokeDashboard.tsx
rename to src/examples/react-native-expo/src/SmokeDashboard.tsx
index 3c663bf53..fb6de5bab 100644
--- a/examples/react-native-expo/src/SmokeDashboard.tsx
+++ b/src/examples/react-native-expo/src/SmokeDashboard.tsx
@@ -20,10 +20,7 @@ import {
   type ExpoSQLiteBenchmarkReport,
   type ReactNativeBenchmarkWorkload,
 } from './sqlite-benchmark';
-import {
-  EXPO_SMOKE_PASS_TAG,
-  serializeExpoSmokePassReceipt,
-} from './smoke-pass-receipt';
+import { EXPO_SMOKE_PASS_TAG, serializeExpoSmokePassReceipt } from './smoke-pass-receipt';
 import { useCallback, useEffect, useMemo, useState } from 'react';
 import {
   ActivityIndicator,
@@ -109,11 +106,9 @@ type NativeBenchmarkReport = {
 
 const smokeGlobalKey = '__OLIPHAUNT_EXPO_SMOKE_STATE__';
 const initialUrlTimeoutMs = 2_500;
-const defaultSmokeStorageName =
-  `installed-smoke-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
+const defaultSmokeStorageName = `installed-smoke-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
 const packagedCatalogProfile = process.env.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE;
-const packagedCatalogProfileProbeSql =
-  process.env.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_SQL;
+const packagedCatalogProfileProbeSql = process.env.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_SQL;
 const packagedCatalogProfileProbeExpected =
   process.env.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_EXPECTED;
 let initialLaunchUrlPromise: Promise | undefined;
@@ -156,7 +151,9 @@ export default function HomeScreen() {
         }
 
         if (Platform.OS !== 'android' && Platform.OS !== 'ios') {
-          throw new Error(`installed mobile release proof does not support platform ${Platform.OS}`);
+          throw new Error(
+            `installed mobile release proof does not support platform ${Platform.OS}`,
+          );
         }
         const extensionPlan = mobileReleaseExtensionProofPlan();
         const extensions = extensionPlan.map((extension) => extension.sqlName);
@@ -168,10 +165,11 @@ export default function HomeScreen() {
         const extensionProofResult = await runMobileReleaseExtensionProof(
           db,
           extensionPlan,
-          check =>
+          (check) =>
             stage(`extensions:${check.status}`, {
               name: check.name,
-              checkElapsedMs: check.elapsedMs === undefined ? undefined : Math.round(check.elapsedMs),
+              checkElapsedMs:
+                check.elapsedMs === undefined ? undefined : Math.round(check.elapsedMs),
             }),
         );
         const extensionProof = extensionProofResult.checks;
@@ -185,13 +183,11 @@ export default function HomeScreen() {
         const parameterized = await db.query('SELECT $1::text AS value', ['hello']);
         const parameterRoundTrip = requiredQueryText(parameterized, 'value');
         stage('query:parameter:done', { value: parameterRoundTrip });
-        const bindingProof = await runMobileBindingProof(
-          db,
-          check =>
-            stage(`binding:${check.status}`, {
-              name: check.name,
-              checkElapsedMs: check.elapsedMs === undefined ? undefined : Math.round(check.elapsedMs),
-            }),
+        const bindingProof = await runMobileBindingProof(db, (check) =>
+          stage(`binding:${check.status}`, {
+            name: check.name,
+            checkElapsedMs: check.elapsedMs === undefined ? undefined : Math.round(check.elapsedMs),
+          }),
         );
         const lifecycle = await runLifecycleResumeValidation(db, stage);
         const profileProof = await runCatalogProfileReopenProof(db, extensions, stage);
@@ -316,11 +312,16 @@ export default function HomeScreen() {
               label="SQLite p90"
               value={
                 report.sqliteBenchmark
-                  ? formatLatency(benchmarkWorkload(report.sqliteBenchmark, 'sqlite_parameterized_select_rtt'))
+                  ? formatLatency(
+                      benchmarkWorkload(report.sqliteBenchmark, 'sqlite_parameterized_select_rtt'),
+                    )
                   : 'pending'
               }
             />
-            
+            
           
 
           
@@ -375,11 +376,7 @@ export default function HomeScreen() {
 
 async function resolveRunnerMode(): Promise {
   const envRunner = process.env.EXPO_PUBLIC_OLIPHAUNT_RUNNER;
-  if (
-    envRunner === 'benchmark' ||
-    envRunner === 'crash-write' ||
-    envRunner === 'crash-verify'
-  ) {
+  if (envRunner === 'benchmark' || envRunner === 'crash-write' || envRunner === 'crash-verify') {
     return envRunner;
   }
   const url = await resolveInitialLaunchUrl();
@@ -387,11 +384,7 @@ async function resolveRunnerMode(): Promise {
     return 'smoke';
   }
   const urlRunner = extractQueryParam(url, 'liboliphauntRunner');
-  if (
-    urlRunner === 'benchmark' ||
-    urlRunner === 'crash-write' ||
-    urlRunner === 'crash-verify'
-  ) {
+  if (urlRunner === 'benchmark' || urlRunner === 'crash-write' || urlRunner === 'crash-verify') {
     return urlRunner;
   }
   if (url.includes('liboliphauntRunner=benchmark') || url.includes('benchmark=1')) {
@@ -477,7 +470,9 @@ async function runCatalogProfileReopenProof(
   );
   const reopenedMarker = requiredQueryText(persisted, 'value');
   if (reopenedMarker !== marker) {
-    throw new Error(`database reopen marker mismatch: expected '${marker}', got '${reopenedMarker}'`);
+    throw new Error(
+      `database reopen marker mismatch: expected '${marker}', got '${reopenedMarker}'`,
+    );
   }
   await assertCatalogProfileProbe(reopened, sql, expected, catalogProfile);
   const elapsedMs = now() - started;
@@ -498,7 +493,9 @@ async function assertCatalogProfileProbe(
   const result = await db.query(`SELECT (${sql})::text AS result`);
   const actual = requiredQueryText(result, 'result');
   if (actual !== expected) {
-    throw new Error(`${profile} packaged catalog probe failed: expected '${expected}', got '${actual}'`);
+    throw new Error(
+      `${profile} packaged catalog probe failed: expected '${expected}', got '${actual}'`,
+    );
   }
 }
 
@@ -673,8 +670,11 @@ async function runNativeBenchmark(
       await db.query('SELECT 1');
     }
     const workloads = [
-      await benchmarkLatency('typed_select_rtt', 'SELECT 1 query round trip', options.typedRttIterations, () =>
-        db.query('SELECT 1'),
+      await benchmarkLatency(
+        'typed_select_rtt',
+        'SELECT 1 query round trip',
+        options.typedRttIterations,
+        () => db.query('SELECT 1'),
       ),
       await benchmarkLatency(
         'parameterized_select_rtt',
@@ -685,7 +685,9 @@ async function runNativeBenchmark(
     ];
 
     await db.execute('DROP TABLE IF EXISTS oliphaunt_expo_benchmark');
-    await db.execute('CREATE TABLE oliphaunt_expo_benchmark(id integer PRIMARY KEY, value text NOT NULL)');
+    await db.execute(
+      'CREATE TABLE oliphaunt_expo_benchmark(id integer PRIMARY KEY, value text NOT NULL)',
+    );
     const insertStarted = now();
     await db.execute(
       'INSERT INTO oliphaunt_expo_benchmark SELECT value, md5(value::text) FROM generate_series(1, $1::integer) AS value',
@@ -698,7 +700,7 @@ async function runNativeBenchmark(
       throughput: {
         rows: options.insertRows,
         totalMs: insertMs,
-        rowsPerSecond: insertMs === 0 ? 0 : options.insertRows * 1_000 / insertMs,
+        rowsPerSecond: insertMs === 0 ? 0 : (options.insertRows * 1_000) / insertMs,
       },
       rows: options.insertRows,
     });
@@ -837,7 +839,9 @@ async function runCrashRecoveryPhase(
   if (!value.startsWith(`crash-${Platform.OS}-`)) {
     throw new Error(`crash recovery verification found unexpected value '${value}'`);
   }
-  await db.execute('INSERT INTO rn_crash_recovery (id, value) VALUES (2, \'verified\') ON CONFLICT (id) DO UPDATE SET value = excluded.value');
+  await db.execute(
+    "INSERT INTO rn_crash_recovery (id, value) VALUES (2, 'verified') ON CONFLICT (id) DO UPDATE SET value = excluded.value",
+  );
   await db.close();
   liveness.stop();
   const payload = {
@@ -935,7 +939,8 @@ async function openDatabase(
     } satisfies Parameters[0];
     smokeState.databasePromise = Oliphaunt.open(config).then((database) => {
       smokeState.databaseInstance = database;
-      (database as unknown as { __liboliphauntOpenMs?: number }).__liboliphauntOpenMs = now() - started;
+      (database as unknown as { __liboliphauntOpenMs?: number }).__liboliphauntOpenMs =
+        now() - started;
       stage?.('open:resolved', {
         openMs: (database as unknown as { __liboliphauntOpenMs?: number }).__liboliphauntOpenMs,
       });
@@ -955,8 +960,8 @@ async function resolveOpenTuning(): Promise {
   const url = await resolveInitialLaunchUrl();
   const rawStartupGUCs = String(
     process.env.EXPO_PUBLIC_OLIPHAUNT_STARTUP_GUCS ??
-    extractQueryParam(url, 'liboliphauntStartupGUCs') ??
-    '',
+      extractQueryParam(url, 'liboliphauntStartupGUCs') ??
+      '',
   );
   const startupGUCs = parseStartupGUCs(rawStartupGUCs);
   return {
@@ -967,7 +972,10 @@ async function resolveOpenTuning(): Promise {
 
 function parseStartupGUCs(value: string): Record {
   const gucs: Record = {};
-  for (const entry of value.split(',').map((part) => part.trim()).filter(Boolean)) {
+  for (const entry of value
+    .split(',')
+    .map((part) => part.trim())
+    .filter(Boolean)) {
     const separator = entry.indexOf('=');
     if (separator <= 0) {
       throw new Error(`startup GUC must use name=value syntax: ${entry}`);
@@ -1003,8 +1011,8 @@ async function resolveBenchmarkPreset(): Promise {
   const url = await resolveInitialLaunchUrl();
   const rawPreset = String(
     process.env.EXPO_PUBLIC_OLIPHAUNT_BENCHMARK_PRESET ??
-    extractQueryParam(url, 'liboliphauntBenchmarkPreset') ??
-    'full',
+      extractQueryParam(url, 'liboliphauntBenchmarkPreset') ??
+      'full',
   );
   return normalizeBenchmarkPreset(rawPreset);
 }
diff --git a/examples/react-native-expo/src/generated/extension-smoke.ts b/src/examples/react-native-expo/src/generated/extension-smoke.ts
similarity index 85%
rename from examples/react-native-expo/src/generated/extension-smoke.ts
rename to src/examples/react-native-expo/src/generated/extension-smoke.ts
index 7cc43c923..ae3ac7f05 100644
--- a/examples/react-native-expo/src/generated/extension-smoke.ts
+++ b/src/examples/react-native-expo/src/generated/extension-smoke.ts
@@ -1,4 +1,4 @@
-// This file is generated by src/extensions/tools/check-extension-model.mjs.
+// This file is generated by src/extensions/tools/check-extension-model.sh.
 // Do not edit by hand. It belongs only to installed mobile qualification.
 
 export type GeneratedMobileExtensionProof = {
@@ -257,7 +257,7 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = {
   "file_fdw": [
     "DROP SERVER IF EXISTS oliphaunt_file_server;",
     "CREATE SERVER oliphaunt_file_server FOREIGN DATA WRAPPER file_fdw;",
-    "DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_foreign_data_wrapper WHERE fdwname = 'file_fdw') THEN RAISE EXCEPTION 'file_fdw wrapper missing'; END IF; END $$;"
+    "-- oliphaunt-verify\nDO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname = 'oliphaunt_file_server') THEN RAISE EXCEPTION 'file_fdw server missing'; END IF; END $$;"
   ],
   "fuzzystrmatch": [
     "DO $$ BEGIN IF levenshtein('kitten', 'sitting') <> 3 THEN RAISE EXCEPTION 'levenshtein failed'; END IF; IF soundex('kitten') <> 'K350' THEN RAISE EXCEPTION 'soundex failed'; END IF; END $$;"
@@ -309,7 +309,7 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = {
     "CREATE TABLE oliphaunt_ivm_orders (id int, amount int);",
     "INSERT INTO oliphaunt_ivm_orders VALUES (1, 10), (2, 20);",
     "SELECT pgivm.create_immv('oliphaunt_ivm_summary', $$ SELECT id, amount FROM oliphaunt_ivm_orders $$);",
-    "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_ivm_summary; IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm initial count failed: %', n; END IF; END $$;"
+    "-- oliphaunt-verify\nDO $$\nDECLARE n int;\nBEGIN\n  SELECT count(*) INTO n FROM oliphaunt_ivm_summary;\n  IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF;\n  UPDATE oliphaunt_ivm_orders SET amount = 11 WHERE id = 1;\n  SELECT amount INTO n FROM oliphaunt_ivm_summary WHERE id = 1;\n  IF n IS DISTINCT FROM 11 THEN RAISE EXCEPTION 'pg_ivm maintenance failed: %', n; END IF;\n  UPDATE oliphaunt_ivm_orders SET amount = 10 WHERE id = 1;\nEND $$;"
   ],
   "pg_surgery": [
     "DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'heap_force_kill') THEN RAISE EXCEPTION 'pg_surgery function missing'; END IF; END $$;"
@@ -319,7 +319,7 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = {
     "CREATE TABLE oliphaunt_pg_textsearch_english (\n  id bigint PRIMARY KEY,\n  body text NOT NULL\n);",
     "INSERT INTO oliphaunt_pg_textsearch_english (id, body) VALUES\n  (1, 'PostgreSQL databases support reliable runners'),\n  (2, 'An unrelated document about walking');",
     "CREATE INDEX oliphaunt_pg_textsearch_english_bm25\n  ON oliphaunt_pg_textsearch_english\n  USING bm25 (body)\n  WITH (text_config = 'pg_catalog.english');",
-    "DO $oliphaunt$\nDECLARE\n  hit bigint;\nBEGIN\n  SELECT id\n  INTO hit\n  FROM oliphaunt_pg_textsearch_english\n  ORDER BY body <@> to_bm25query(\n    'running database',\n    'oliphaunt_pg_textsearch_english_bm25'\n  )\n  LIMIT 1;\n  IF hit IS DISTINCT FROM 1 THEN\n    RAISE EXCEPTION 'pg_textsearch English BM25 smoke returned id %, expected 1', hit;\n  END IF;\nEND\n$oliphaunt$;"
+    "-- oliphaunt-verify\nDO $oliphaunt$\nDECLARE\n  hit bigint;\nBEGIN\n  SELECT id\n  INTO hit\n  FROM oliphaunt_pg_textsearch_english\n  ORDER BY body <@> to_bm25query(\n    'running database',\n    'oliphaunt_pg_textsearch_english_bm25'\n  )\n  LIMIT 1;\n  IF hit IS DISTINCT FROM 1 THEN\n    RAISE EXCEPTION 'pg_textsearch English BM25 smoke returned id %, expected 1', hit;\n  END IF;\nEND\n$oliphaunt$;"
   ],
   "pg_trgm": [
     "DO $$ DECLARE score float8; BEGIN SELECT similarity('postgres', 'postgrex') INTO score; IF score <= 0 THEN RAISE EXCEPTION 'pg_trgm similarity failed: %', score; END IF; END $$;"
@@ -353,10 +353,10 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = {
   ],
   "postgis": [
     "DROP TABLE IF EXISTS oliphaunt_postgis_points;",
-    "CREATE TEMP TABLE oliphaunt_postgis_points(id int PRIMARY KEY, geom geometry(Point, 4326));",
+    "CREATE TABLE oliphaunt_postgis_points(id int PRIMARY KEY, geom geometry(Point, 4326));",
     "INSERT INTO oliphaunt_postgis_points VALUES\n  (1, ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)),\n  (2, ST_SetSRID(ST_MakePoint(-71.061, 48.433), 4326));",
     "CREATE INDEX oliphaunt_postgis_points_gix ON oliphaunt_postgis_points USING GIST (geom);",
-    "DO $$\nDECLARE\n  distance float8;\n  srid int;\n  area float8;\n  polygons int;\n  nearby int;\nBEGIN\n  SELECT ST_Distance(ST_GeomFromText('POINT(0 0)'), ST_GeomFromText('POINT(3 4)')) INTO distance;\n  IF distance <> 5 THEN\n    RAISE EXCEPTION 'postgis geometry distance failed: %', distance;\n  END IF;\n  IF ST_AsText(ST_Buffer(ST_GeomFromText('POINT(0 0)'), 1, 'quad_segs=1')) IS NULL THEN\n    RAISE EXCEPTION 'postgis buffer failed';\n  END IF;\n  IF NOT ST_Within(\n    ST_GeomFromText('POINT(0.5 0.5)'),\n    ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')\n  ) THEN\n    RAISE EXCEPTION 'postgis within failed';\n  END IF;\n  SELECT ST_SRID(ST_Transform(ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326), 3857)) INTO srid;\n  IF srid <> 3857 THEN\n    RAISE EXCEPTION 'postgis transform failed: %', srid;\n  END IF;\n  SELECT ST_Area(ST_Transform(ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-71.1776848522251 42.3902896512902,-71.1776843766797 42.3903701743239,-71.1775844305465 42.3903829478009,-71.1775825927231 42.3902893647987,-71.1776848522251 42.3902896512902)')), 4326), 26986)) INTO area;\n  IF area <= 0 THEN\n    RAISE EXCEPTION 'postgis projected area failed: %', area;\n  END IF;\n  SELECT ST_NumGeometries(ST_Polygonize(ARRAY[\n    ST_GeomFromText('LINESTRING(0 0, 1 0)'),\n    ST_GeomFromText('LINESTRING(1 0, 1 1)'),\n    ST_GeomFromText('LINESTRING(1 1, 0 1)'),\n    ST_GeomFromText('LINESTRING(0 1, 0 0)')\n  ])) INTO polygons;\n  IF polygons <> 1 THEN\n    RAISE EXCEPTION 'postgis polygonize failed: %', polygons;\n  END IF;\n  SELECT count(*) INTO nearby\n  FROM oliphaunt_postgis_points\n  WHERE ST_DWithin(\n    geom::geography,\n    ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)::geography,\n    200\n  );\n  IF nearby <> 2 THEN\n    RAISE EXCEPTION 'postgis dwithin failed: %', nearby;\n  END IF;\nEND $$;"
+    "-- oliphaunt-verify\nDO $$\nDECLARE\n  distance float8;\n  srid int;\n  area float8;\n  polygons int;\n  nearby int;\nBEGIN\n  SELECT ST_Distance(ST_GeomFromText('POINT(0 0)'), ST_GeomFromText('POINT(3 4)')) INTO distance;\n  IF distance <> 5 THEN\n    RAISE EXCEPTION 'postgis geometry distance failed: %', distance;\n  END IF;\n  IF ST_AsText(ST_Buffer(ST_GeomFromText('POINT(0 0)'), 1, 'quad_segs=1')) IS NULL THEN\n    RAISE EXCEPTION 'postgis buffer failed';\n  END IF;\n  IF NOT ST_Within(\n    ST_GeomFromText('POINT(0.5 0.5)'),\n    ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')\n  ) THEN\n    RAISE EXCEPTION 'postgis within failed';\n  END IF;\n  SELECT ST_SRID(ST_Transform(ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326), 3857)) INTO srid;\n  IF srid <> 3857 THEN\n    RAISE EXCEPTION 'postgis transform failed: %', srid;\n  END IF;\n  SELECT ST_Area(ST_Transform(ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-71.1776848522251 42.3902896512902,-71.1776843766797 42.3903701743239,-71.1775844305465 42.3903829478009,-71.1775825927231 42.3902893647987,-71.1776848522251 42.3902896512902)')), 4326), 26986)) INTO area;\n  IF area <= 0 THEN\n    RAISE EXCEPTION 'postgis projected area failed: %', area;\n  END IF;\n  SELECT ST_NumGeometries(ST_Polygonize(ARRAY[\n    ST_GeomFromText('LINESTRING(0 0, 1 0)'),\n    ST_GeomFromText('LINESTRING(1 0, 1 1)'),\n    ST_GeomFromText('LINESTRING(1 1, 0 1)'),\n    ST_GeomFromText('LINESTRING(0 1, 0 0)')\n  ])) INTO polygons;\n  IF polygons <> 1 THEN\n    RAISE EXCEPTION 'postgis polygonize failed: %', polygons;\n  END IF;\n  SELECT count(*) INTO nearby\n  FROM oliphaunt_postgis_points\n  WHERE ST_DWithin(\n    geom::geography,\n    ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)::geography,\n    200\n  );\n  IF nearby <> 2 THEN\n    RAISE EXCEPTION 'postgis dwithin failed: %', nearby;\n  END IF;\nEND $$;"
   ],
   "seg": [
     "DO $$ BEGIN IF '7(+-)1'::seg::text <> '6 .. 8' THEN RAISE EXCEPTION 'seg cast failed'; END IF; END $$;"
@@ -390,6 +390,6 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = {
     "DROP TABLE IF EXISTS oliphaunt_vector;",
     "CREATE TABLE oliphaunt_vector (id int PRIMARY KEY, embedding vector(3));",
     "INSERT INTO oliphaunt_vector VALUES (1, '[1,2,3]');",
-    "DO $$ DECLARE d float8; BEGIN SELECT embedding <-> '[1,2,4]'::vector INTO d FROM oliphaunt_vector WHERE id = 1; IF d <> 1 THEN RAISE EXCEPTION 'vector distance failed: %', d; END IF; END $$;"
+    "-- oliphaunt-verify\nDO $$ DECLARE d float8; BEGIN SELECT embedding <-> '[1,2,4]'::vector INTO d FROM oliphaunt_vector WHERE id = 1; IF d IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'vector distance failed: %', d; END IF; END $$;"
   ]
 } as const satisfies Readonly>;
diff --git a/examples/react-native-expo/src/mobile-smoke.ts b/src/examples/react-native-expo/src/mobile-smoke.ts
similarity index 89%
rename from examples/react-native-expo/src/mobile-smoke.ts
rename to src/examples/react-native-expo/src/mobile-smoke.ts
index e9b13c9e9..a2ecf15c7 100644
--- a/examples/react-native-expo/src/mobile-smoke.ts
+++ b/src/examples/react-native-expo/src/mobile-smoke.ts
@@ -1,8 +1,4 @@
-import {
-  PostgresError,
-  type OliphauntDatabase,
-  type QueryResult,
-} from '@oliphaunt/react-native';
+import { PostgresError, type OliphauntDatabase, type QueryResult } from '@oliphaunt/react-native';
 
 export type MobileReleaseExtensionProof = {
   readonly sqlName: string;
@@ -42,7 +38,9 @@ export async function runMobileBindingProof(
     checks,
     'raw protocol response',
     async () => {
-      const raw = await db.execProtocolRaw(simpleQuery('SELECT 1 AS raw_value; SELECT 2 AS raw_value'));
+      const raw = await db.execProtocolRaw(
+        simpleQuery('SELECT 1 AS raw_value; SELECT 2 AS raw_value'),
+      );
       assertPositiveInteger(raw.byteLength, 'raw protocol byte length');
       return `${raw.byteLength} raw bytes`;
     },
@@ -64,21 +62,18 @@ export async function runMobileBindingProof(
         let chunkCount = 0;
         let callbackActive = false;
         const chunks: Uint8Array[] = [];
-        await db.execProtocolRawStream(
-          request,
-          chunk => {
-            if (callbackActive) {
-              throw new Error('protocol stream callback was re-entered');
-            }
-            callbackActive = true;
-            try {
-              chunkCount += 1;
-              chunks.push(chunk.slice());
-            } finally {
-              callbackActive = false;
-            }
-          },
-        );
+        await db.execProtocolRawStream(request, (chunk) => {
+          if (callbackActive) {
+            throw new Error('protocol stream callback was re-entered');
+          }
+          callbackActive = true;
+          try {
+            chunkCount += 1;
+            chunks.push(chunk.slice());
+          } finally {
+            callbackActive = false;
+          }
+        });
         if (chunkCount < 2) {
           throw new Error(`protocol stream expected multiple chunks, got ${chunkCount}`);
         }
@@ -109,11 +104,7 @@ export async function runMobileBindingProof(
             );
           }
         }
-        assertEqual(
-          failureCallbackCount,
-          1,
-          'stream callback invocation count after failure',
-        );
+        assertEqual(failureCallbackCount, 1, 'stream callback invocation count after failure');
         assertEqual(
           await scalar(db, "SELECT 'after-stream-error'::text AS value"),
           'after-stream-error',
@@ -121,10 +112,9 @@ export async function runMobileBindingProof(
         );
         return `${chunkCount} acknowledged chunks, ${streamed.byteLength} complete raw bytes, callback exception preserved`;
       } finally {
-        await db.query(
-          "SELECT set_config('auto_explain.log_min_duration', $1, false) AS value",
-          [autoExplainLogMinDuration],
-        );
+        await db.query("SELECT set_config('auto_explain.log_min_duration', $1, false) AS value", [
+          autoExplainLogMinDuration,
+        ]);
       }
     },
     onCheckStage,
@@ -180,7 +170,9 @@ function assertBytesEqual(actual: Uint8Array, expected: Uint8Array, label: strin
       const start = Math.max(0, index - 8);
       const end = Math.min(actual.byteLength, index + 9);
       const hex = (bytes: Uint8Array) =>
-        Array.from(bytes.subarray(start, end), byte => byte.toString(16).padStart(2, '0')).join(' ');
+        Array.from(bytes.subarray(start, end), (byte) => byte.toString(16).padStart(2, '0')).join(
+          ' ',
+        );
       throw new Error(
         `${label}: byte ${index} differs (actual ${actual[index]}, expected ${expected[index]}; actual ${hex(actual)}; expected ${hex(expected)})`,
       );
@@ -266,7 +258,11 @@ export async function runMobileReleaseExtensionProof(
              WHERE extname = $1`,
             [extension.sqlName],
           );
-          assertEqual(requiredText(result, 0, 'name'), extension.sqlName, `${extension.sqlName} catalog identity`);
+          assertEqual(
+            requiredText(result, 0, 'name'),
+            extension.sqlName,
+            `${extension.sqlName} catalog identity`,
+          );
           const version = requiredText(result, 0, 'version');
           if (version.trim().length === 0) {
             throw new Error(`${extension.sqlName} catalog version is empty`);
@@ -300,8 +296,8 @@ export async function runMobileReleaseExtensionProof(
     'extension activation catalog completeness',
     async () => {
       const expected = plan
-        .filter(extension => extension.createsExtension)
-        .map(extension => extension.sqlName)
+        .filter((extension) => extension.createsExtension)
+        .map((extension) => extension.sqlName)
         .sort()
         .join(',');
       const actual = await scalar(
@@ -331,7 +327,9 @@ export async function runPostgresLifecycleResumeCheck(
   const select = await scalar(db, 'SELECT 1::text AS value');
   assertEqual(select, '1', 'resume SELECT 1');
   await db.execute('DROP TABLE IF EXISTS oliphaunt_mobile_resume_probe');
-  await db.execute('CREATE TABLE oliphaunt_mobile_resume_probe(id integer PRIMARY KEY, value text NOT NULL)');
+  await db.execute(
+    'CREATE TABLE oliphaunt_mobile_resume_probe(id integer PRIMARY KEY, value text NOT NULL)',
+  );
   await db.execute("INSERT INTO oliphaunt_mobile_resume_probe VALUES (1, 'resumed')");
   const value = await scalar(
     db,
@@ -374,10 +372,7 @@ async function record(
   checks.push({ name, detail, elapsedMs });
 }
 
-async function expectPostgresError(
-  promise: Promise,
-  sqlstate: string,
-): Promise {
+async function expectPostgresError(promise: Promise, sqlstate: string): Promise {
   try {
     await promise;
   } catch (error) {
@@ -411,7 +406,7 @@ function assertPositiveInteger(value: number, label: string): void {
 }
 
 function sleep(ms: number): Promise {
-  return new Promise(resolve => setTimeout(resolve, ms));
+  return new Promise((resolve) => setTimeout(resolve, ms));
 }
 
 function now(): number {
diff --git a/examples/react-native-expo/src/smoke-pass-receipt.ts b/src/examples/react-native-expo/src/smoke-pass-receipt.ts
similarity index 96%
rename from examples/react-native-expo/src/smoke-pass-receipt.ts
rename to src/examples/react-native-expo/src/smoke-pass-receipt.ts
index a1b99bfd1..34649b9b5 100644
--- a/examples/react-native-expo/src/smoke-pass-receipt.ts
+++ b/src/examples/react-native-expo/src/smoke-pass-receipt.ts
@@ -35,7 +35,9 @@ export function serializeExpoSmokePassReceipt(input: ExpoSmokePassReceiptInput):
     throw new Error('installed-app receipt requires an ICU runtime proof boolean');
   }
   if (input.catalogProfile !== 'standard' && input.catalogProfile !== 'icu') {
-    throw new Error(`installed-app receipt has unsupported catalog profile: ${String(input.catalogProfile)}`);
+    throw new Error(
+      `installed-app receipt has unsupported catalog profile: ${String(input.catalogProfile)}`,
+    );
   }
   if (input.icuRuntimeProof !== (input.catalogProfile === 'icu')) {
     throw new Error('installed-app receipt ICU proof must match its catalog profile');
diff --git a/examples/react-native-expo/src/sqlite-benchmark.ts b/src/examples/react-native-expo/src/sqlite-benchmark.ts
similarity index 95%
rename from examples/react-native-expo/src/sqlite-benchmark.ts
rename to src/examples/react-native-expo/src/sqlite-benchmark.ts
index 1d0b81015..b43a8fbdf 100644
--- a/examples/react-native-expo/src/sqlite-benchmark.ts
+++ b/src/examples/react-native-expo/src/sqlite-benchmark.ts
@@ -140,9 +140,7 @@ export async function runExpoSQLiteBenchmark(
   }
 }
 
-function resolveOptions(
-  options: ExpoSQLiteBenchmarkOptions,
-): ResolvedSQLiteBenchmarkOptions {
+function resolveOptions(options: ExpoSQLiteBenchmarkOptions): ResolvedSQLiteBenchmarkOptions {
   return {
     warmupIterations: positiveInteger(
       options.warmupIterations,
@@ -232,7 +230,7 @@ async function runSimpleSelectRtt(
   iterations: number,
 ): Promise {
   let checksum = 0;
-  const latency = await measureLatency(iterations, async index => {
+  const latency = await measureLatency(iterations, async (index) => {
     const row = await db.getFirstAsync<{ value: number }>('SELECT ? AS value', index % 17);
     checksum += row?.value ?? 0;
   });
@@ -249,11 +247,8 @@ async function runParameterizedSelectRtt(
   iterations: number,
 ): Promise {
   let checksum = 0;
-  const latency = await measureLatency(iterations, async index => {
-    const row = await db.getFirstAsync<{ value: string }>(
-      'SELECT ? AS value',
-      `value-${index}`,
-    );
+  const latency = await measureLatency(iterations, async (index) => {
+    const row = await db.getFirstAsync<{ value: string }>('SELECT ? AS value', `value-${index}`);
     checksum += row?.value.length ?? 0;
   });
   return {
@@ -283,7 +278,7 @@ async function prepareDataset(
   `);
 
   const started = monotonicNow();
-  await db.withExclusiveTransactionAsync(async tx => {
+  await db.withExclusiveTransactionAsync(async (tx) => {
     for (let index = 1; index <= rows; index += 1) {
       await tx.runAsync(
         `INSERT INTO rn_bench_events (id, bucket, label, amount, payload)
@@ -312,7 +307,7 @@ async function runIndexedLookup(
   rows: number,
 ): Promise {
   let checksum = 0;
-  const latency = await measureLatency(iterations, async index => {
+  const latency = await measureLatency(iterations, async (index) => {
     const id = (index % rows) + 1;
     const row = await db.getFirstAsync<{ payload: string }>(
       'SELECT payload FROM rn_bench_events WHERE id = ?',
@@ -333,7 +328,7 @@ async function runAggregateScan(
   iterations: number,
 ): Promise {
   let checksum = 0;
-  const latency = await measureLatency(iterations, async index => {
+  const latency = await measureLatency(iterations, async (index) => {
     const row = await db.getFirstAsync<{ rows: number; total: number }>(
       `SELECT count(*) AS rows, coalesce(sum(amount), 0) AS total
        FROM rn_bench_events
@@ -356,7 +351,7 @@ async function runIndexedUpdates(
   iterations: number,
   rows: number,
 ): Promise {
-  const latency = await measureLatency(iterations, async index => {
+  const latency = await measureLatency(iterations, async (index) => {
     const id = ((index * 17) % rows) + 1;
     await db.runAsync(
       `UPDATE rn_bench_events
diff --git a/src/examples/react-native-expo/tools/mobile-extension-proof.test.mts b/src/examples/react-native-expo/tools/mobile-extension-proof.test.mts
new file mode 100644
index 000000000..5a457d9e7
--- /dev/null
+++ b/src/examples/react-native-expo/tools/mobile-extension-proof.test.mts
@@ -0,0 +1,104 @@
+import assert from 'node:assert/strict';
+import { mock, test } from 'bun:test';
+
+class FixturePostgresError extends Error {}
+
+mock.module('@oliphaunt/react-native', () => ({
+  PostgresError: FixturePostgresError,
+  simpleQuery() {
+    throw new Error('simpleQuery is outside the extension-proof fixture');
+  },
+}));
+
+const { runMobileReleaseExtensionProof } = await import('../src/mobile-smoke.ts');
+const { serializeExpoSmokePassReceipt } = await import('../src/smoke-pass-receipt.ts');
+
+function queryResult(values) {
+  return {
+    getText(_row, column) {
+      return values[column] ?? null;
+    },
+    rowCount: 1,
+    rows: [values],
+  };
+}
+
+test('the successful pg_textsearch producer supplies every semantic PASS fact', async () => {
+  const executed = [];
+  const queried = [];
+  const db = {
+    async execute(sql) {
+      executed.push(sql);
+    },
+    async query(sql) {
+      queried.push(sql);
+      if (sql === 'SELECT 1') {
+        return queryResult({ '?column?': '1' });
+      }
+      if (sql.includes('WHERE extname = $1')) {
+        return queryResult({ name: 'pg_textsearch', version: '0.3.1' });
+      }
+      if (sql.includes('to_bm25query')) {
+        return queryResult({ id: '1' });
+      }
+      if (sql.includes('string_agg')) {
+        return queryResult({ value: 'pg_textsearch' });
+      }
+      throw new Error(`unexpected extension-proof query: ${sql}`);
+    },
+  };
+  const proof = await runMobileReleaseExtensionProof(db, [
+    {
+      sqlName: 'pg_textsearch',
+      createsExtension: true,
+      nativeModuleStem: 'pg_textsearch',
+      selectedExtensionDependencies: [],
+      activationSql: ['CREATE EXTENSION pg_textsearch'],
+      smokeStatements: ['SELECT 1'],
+    },
+  ]);
+
+  assert.deepEqual(proof.activatedExtensions, ['pg_textsearch']);
+  assert.equal(proof.extensionCatalogComplete, true);
+  assert.equal(proof.pgTextsearchEnglishBm25, true);
+  assert.deepEqual(executed, [
+    'CREATE EXTENSION pg_textsearch',
+    'DROP TABLE IF EXISTS oliphaunt_mobile_pg_textsearch_english',
+    'CREATE TABLE oliphaunt_mobile_pg_textsearch_english (id bigint PRIMARY KEY, body text NOT NULL)',
+    `INSERT INTO oliphaunt_mobile_pg_textsearch_english (id, body) VALUES
+        (1, 'PostgreSQL databases support reliable runners'),
+        (2, 'An unrelated document about walking')`,
+    `CREATE INDEX oliphaunt_mobile_pg_textsearch_english_bm25
+        ON oliphaunt_mobile_pg_textsearch_english
+        USING bm25 (body)
+        WITH (text_config = 'pg_catalog.english')`,
+    'DROP TABLE IF EXISTS oliphaunt_mobile_pg_textsearch_english',
+  ]);
+  assert.equal(queried[0], 'SELECT 1');
+  assert.deepEqual(
+    proof.checks.map((check) => check.name),
+    [
+      'extension activation: pg_textsearch',
+      'extension functional proof: pg_textsearch English BM25',
+      'extension activation catalog completeness',
+    ],
+  );
+
+  const receipt = JSON.parse(
+    serializeExpoSmokePassReceipt({
+      platform: 'ios',
+      extensions: ['pg_textsearch'],
+      activatedExtensions: proof.activatedExtensions,
+      extensionCatalogComplete: proof.extensionCatalogComplete,
+      pgTextsearchEnglishBm25: proof.pgTextsearchEnglishBm25,
+      extensionCatalogSha256: 'a'.repeat(64),
+      catalogProfile: 'icu',
+      icuRuntimeProof: true,
+    }),
+  );
+  assert.equal(receipt.schema, 'oliphaunt-expo-smoke-pass-v4');
+  assert.equal(receipt.catalogProfile, 'icu');
+  assert.equal(receipt.allExtensionsActivated, true);
+  assert.equal(receipt.extensionCatalogComplete, true);
+  assert.equal(receipt.pgTextsearchEnglishBm25, true);
+});
diff --git a/src/examples/react-native-expo/tools/smoke-pass-receipt.test.mts b/src/examples/react-native-expo/tools/smoke-pass-receipt.test.mts
new file mode 100644
index 000000000..3b480731f
--- /dev/null
+++ b/src/examples/react-native-expo/tools/smoke-pass-receipt.test.mts
@@ -0,0 +1,125 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+
+import {
+  EXPO_SMOKE_PASS_EVENT_MAX_BYTES,
+  EXPO_SMOKE_PASS_TAG,
+  serializeExpoSmokePassReceipt,
+} from '../src/smoke-pass-receipt.ts';
+import {
+  GENERATED_MOBILE_EXTENSION_METADATA_SHA256,
+  GENERATED_MOBILE_EXTENSION_PLAN,
+} from '../src/generated/extension-smoke.ts';
+
+function platformExtensions() {
+  return GENERATED_MOBILE_EXTENSION_PLAN.map((extension) => extension.sqlName).sort();
+}
+
+function receiptInput(platform, overrides = {}) {
+  const extensions = platformExtensions();
+  return {
+    platform,
+    extensions,
+    activatedExtensions: extensions,
+    extensionCatalogComplete: true,
+    pgTextsearchEnglishBm25: extensions.includes('pg_textsearch'),
+    extensionCatalogSha256: GENERATED_MOBILE_EXTENSION_METADATA_SHA256,
+    catalogProfile: 'icu',
+    icuRuntimeProof: true,
+    ...overrides,
+  };
+}
+
+test('the exact mobile catalog produces a bounded authoritative receipt', () => {
+  for (const platform of ['android', 'ios']) {
+    const extensions = platformExtensions();
+    const serialized = serializeExpoSmokePassReceipt(receiptInput(platform));
+    const event = `${EXPO_SMOKE_PASS_TAG} ${serialized}`;
+    assert(Buffer.byteLength(event) <= EXPO_SMOKE_PASS_EVENT_MAX_BYTES);
+    assert.deepEqual(Object.keys(JSON.parse(serialized)).sort(), [
+      'allExtensionsActivated',
+      'catalogProfile',
+      'extensionCatalogComplete',
+      'extensionCatalogSha256',
+      'extensionCount',
+      'icuRuntimeProof',
+      'pgTextsearchEnglishBm25',
+      'platform',
+      'runner',
+      'schema',
+    ]);
+  }
+});
+
+test('receipt serialization fails closed on proof drift and remains constant-size as catalogs grow', () => {
+  const extensions = platformExtensions();
+  assert.throws(
+    () =>
+      serializeExpoSmokePassReceipt(
+        receiptInput('ios', {
+          activatedExtensions: extensions.slice(1),
+        }),
+      ),
+    /activated extension mismatch/u,
+  );
+  assert.throws(
+    () =>
+      serializeExpoSmokePassReceipt(
+        receiptInput('ios', {
+          activatedExtensions: [...extensions, extensions[0]],
+        }),
+      ),
+    /activated extension mismatch/u,
+  );
+  assert.throws(
+    () =>
+      serializeExpoSmokePassReceipt(
+        receiptInput('ios', {
+          extensionCatalogComplete: false,
+        }),
+      ),
+    /catalog completeness/u,
+  );
+  assert.throws(
+    () =>
+      serializeExpoSmokePassReceipt(
+        receiptInput('ios', {
+          pgTextsearchEnglishBm25: false,
+        }),
+      ),
+    /pg_textsearch English BM25 proof mismatch/u,
+  );
+  assert.throws(
+    () =>
+      serializeExpoSmokePassReceipt(
+        receiptInput('ios', {
+          icuRuntimeProof: 'yes',
+        }),
+      ),
+    /ICU runtime proof boolean/u,
+  );
+  assert.throws(
+    () =>
+      serializeExpoSmokePassReceipt(
+        receiptInput('ios', {
+          catalogProfile: 'standard',
+        }),
+      ),
+    /ICU proof must match its catalog profile/u,
+  );
+  const largeCatalog = Array.from({ length: 500 }, (_, index) => `extension_${index}`);
+  const serialized = serializeExpoSmokePassReceipt({
+    platform: 'ios',
+    extensions: largeCatalog,
+    activatedExtensions: largeCatalog,
+    extensionCatalogComplete: true,
+    pgTextsearchEnglishBm25: false,
+    extensionCatalogSha256: GENERATED_MOBILE_EXTENSION_METADATA_SHA256,
+    catalogProfile: 'standard',
+    icuRuntimeProof: false,
+  });
+  assert(
+    Buffer.byteLength(`${EXPO_SMOKE_PASS_TAG} ${serialized}`) <= EXPO_SMOKE_PASS_EVENT_MAX_BYTES,
+  );
+  assert.equal(Object.hasOwn(JSON.parse(serialized), 'extensions'), false);
+});
diff --git a/src/examples/react-native-expo/tsconfig.json b/src/examples/react-native-expo/tsconfig.json
new file mode 100644
index 000000000..c933ecfe1
--- /dev/null
+++ b/src/examples/react-native-expo/tsconfig.json
@@ -0,0 +1,11 @@
+{
+  "extends": "expo/tsconfig.base",
+  "compilerOptions": {
+    "strict": true,
+    "paths": {
+      "@/*": ["./src/*"],
+      "@/assets/*": ["./assets/*"]
+    }
+  },
+  "include": ["**/*.ts", "**/*.tsx"]
+}
diff --git a/examples/tauri-wasix/.gitignore b/src/examples/tauri-wasix/.gitignore
similarity index 100%
rename from examples/tauri-wasix/.gitignore
rename to src/examples/tauri-wasix/.gitignore
diff --git a/src/examples/tauri-wasix/README.md b/src/examples/tauri-wasix/README.md
new file mode 100644
index 000000000..729d0d55c
--- /dev/null
+++ b/src/examples/tauri-wasix/README.md
@@ -0,0 +1,14 @@
+# Tauri WASIX Todo
+
+Tauri owns a Rust backend that asynchronously starts
+`AsyncOliphauntServer` from `oliphaunt-pgwire-server`, then uses a one-connection
+SQLx pool against the local
+PostgreSQL URL. The webview receives app-specific commands only. The explicit
+Rust smoke test covers `pg_dump` and `psql` through the direct
+`oliphaunt_wasix` API; ordinary application startup does not run
+PostgreSQL client tools.
+
+```sh
+bun install --cwd src/examples/tauri-wasix
+bun run --cwd src/examples/tauri-wasix tauri dev
+```
diff --git a/examples/tauri-wasix/index.html b/src/examples/tauri-wasix/index.html
similarity index 100%
rename from examples/tauri-wasix/index.html
rename to src/examples/tauri-wasix/index.html
diff --git a/examples/tauri-wasix/package.json b/src/examples/tauri-wasix/package.json
similarity index 100%
rename from examples/tauri-wasix/package.json
rename to src/examples/tauri-wasix/package.json
diff --git a/examples/tauri-wasix/pnpm-workspace.yaml b/src/examples/tauri-wasix/pnpm-workspace.yaml
similarity index 100%
rename from examples/tauri-wasix/pnpm-workspace.yaml
rename to src/examples/tauri-wasix/pnpm-workspace.yaml
diff --git a/src/examples/tauri-wasix/src-tauri/Cargo.toml b/src/examples/tauri-wasix/src-tauri/Cargo.toml
new file mode 100644
index 000000000..2f26808b0
--- /dev/null
+++ b/src/examples/tauri-wasix/src-tauri/Cargo.toml
@@ -0,0 +1,39 @@
+[package]
+name = "oliphaunt-example-tauri-wasix"
+version = "0.0.0"
+description = "Tauri todo app backed by oliphaunt-wasix and SQLx"
+edition = "2021"
+publish = false
+
+[workspace]
+
+[lib]
+name = "oliphaunt_example_tauri_wasix_lib"
+crate-type = ["staticlib", "cdylib", "rlib"]
+
+[build-dependencies]
+tauri-build = { version = "2", features = [] }
+
+[dependencies]
+oliphaunt-pgwire-server = { version = "0.1.0", path = "../../../pgwire-server", features = ["extensions"] }
+anyhow = "1"
+oliphaunt-wasix = { version = "=0.2.0", path = "../../../sdks/rust-wasix", features = [
+  "extension-hstore",
+  "extension-pg-trgm",
+  "extension-unaccent",
+] }
+serde = { version = "1", features = ["derive"] }
+sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio-rustls", "postgres"] }
+tauri = { version = "2", features = [] }
+thiserror = "2"
+tokio = { version = "1", features = ["rt-multi-thread", "sync"] }
+
+[dev-dependencies]
+oliphaunt-wasix = { version = "=0.2.0", path = "../../../sdks/rust-wasix", features = ["tools"] }
+oliphaunt-wasix-tools = { version = "=0.2.1", path = "../../../postgres-tools/wasix/crates/tools" }
+
+[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dependencies]
+liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu = { version = "=0.2.0", path = "../../../runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu" }
+
+[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dev-dependencies]
+oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu = { version = "=0.2.1", path = "../../../postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu" }
diff --git a/examples/tauri-wasix/src-tauri/build.rs b/src/examples/tauri-wasix/src-tauri/build.rs
similarity index 100%
rename from examples/tauri-wasix/src-tauri/build.rs
rename to src/examples/tauri-wasix/src-tauri/build.rs
diff --git a/examples/tauri-wasix/src-tauri/capabilities/default.json b/src/examples/tauri-wasix/src-tauri/capabilities/default.json
similarity index 100%
rename from examples/tauri-wasix/src-tauri/capabilities/default.json
rename to src/examples/tauri-wasix/src-tauri/capabilities/default.json
diff --git a/src/examples/tauri-wasix/src-tauri/src/lib.rs b/src/examples/tauri-wasix/src-tauri/src/lib.rs
new file mode 100644
index 000000000..a072f6d8c
--- /dev/null
+++ b/src/examples/tauri-wasix/src-tauri/src/lib.rs
@@ -0,0 +1,311 @@
+use std::path::PathBuf;
+use std::time::Duration;
+
+use anyhow::{Context, Result};
+#[cfg(test)]
+use oliphaunt_wasix::{tools, Oliphaunt};
+use oliphaunt_pgwire_server::AsyncOliphauntServer;
+use oliphaunt_wasix::{Extension};
+use serde::ser::Serializer;
+use serde::{Deserialize, Serialize};
+use sqlx::postgres::PgPoolOptions;
+use sqlx::{PgPool, Row};
+use tauri::Manager;
+use tokio::sync::Mutex;
+
+const CREATE_EXTENSIONS: &[&str] = &[
+    "CREATE EXTENSION IF NOT EXISTS hstore",
+    "CREATE EXTENSION IF NOT EXISTS pg_trgm",
+    "CREATE EXTENSION IF NOT EXISTS unaccent",
+];
+
+const CREATE_TABLE: &str = r#"
+CREATE TABLE IF NOT EXISTS todos (
+    id bigserial PRIMARY KEY,
+    title text NOT NULL,
+    notes text NOT NULL DEFAULT '',
+    tags hstore NOT NULL DEFAULT ''::hstore,
+    done boolean NOT NULL DEFAULT false,
+    priority integer NOT NULL DEFAULT 2 CHECK (priority BETWEEN 1 AND 3),
+    created_at timestamptz NOT NULL DEFAULT now(),
+    updated_at timestamptz NOT NULL DEFAULT now()
+)
+"#;
+
+const CREATE_INDEX: &str =
+    "CREATE INDEX IF NOT EXISTS todos_title_trgm ON todos USING gin (title gin_trgm_ops)";
+
+const SELECT_TODOS: &str = r#"
+SELECT
+    id,
+    title,
+    notes,
+    COALESCE(tags -> 'area', '') AS area,
+    COALESCE(tags -> 'context', '') AS context,
+    done,
+    priority,
+    to_char(created_at, 'YYYY-MM-DD HH24:MI') AS created_at,
+    to_char(updated_at, 'YYYY-MM-DD HH24:MI') AS updated_at
+FROM todos
+WHERE
+    (
+        $1::text = ''
+        OR unaccent(title || ' ' || notes) ILIKE '%' || unaccent($1::text) || '%'
+        OR COALESCE(tags -> 'area', '') ILIKE '%' || $1::text || '%'
+        OR COALESCE(tags -> 'context', '') ILIKE '%' || $1::text || '%'
+        OR tags ? $1::text
+    )
+    AND (
+        $2::text = 'all'
+        OR ($2::text = 'open' AND NOT done)
+        OR ($2::text = 'done' AND done)
+    )
+ORDER BY done ASC, priority ASC, updated_at DESC, id DESC
+"#;
+
+const RETURNING_TODO: &str = r#"
+RETURNING
+    id,
+    title,
+    notes,
+    COALESCE(tags -> 'area', '') AS area,
+    COALESCE(tags -> 'context', '') AS context,
+    done,
+    priority,
+    to_char(created_at, 'YYYY-MM-DD HH24:MI') AS created_at,
+    to_char(updated_at, 'YYYY-MM-DD HH24:MI') AS updated_at
+"#;
+
+struct TodoStore {
+    inner: Mutex,
+}
+
+struct TodoDatabase {
+    pool: PgPool,
+    _server: AsyncOliphauntServer,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct CreateTodo {
+    title: String,
+    notes: String,
+    area: String,
+    context: String,
+    priority: i32,
+}
+
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct Todo {
+    id: i64,
+    title: String,
+    notes: String,
+    area: String,
+    context: String,
+    priority: i32,
+    done: bool,
+    created_at: String,
+    updated_at: String,
+}
+
+#[derive(Debug, thiserror::Error)]
+enum CommandError {
+    #[error("{0}")]
+    Runtime(String),
+}
+
+impl serde::Serialize for CommandError {
+    fn serialize(&self, serializer: S) -> Result
+    where
+        S: Serializer,
+    {
+        serializer.serialize_str(&self.to_string())
+    }
+}
+
+impl From for CommandError {
+    fn from(value: anyhow::Error) -> Self {
+        Self::Runtime(format!("{value:#}"))
+    }
+}
+
+impl From for CommandError {
+    fn from(value: sqlx::Error) -> Self {
+        Self::Runtime(value.to_string())
+    }
+}
+
+fn open_database(directory: PathBuf) -> Result {
+    let runtime = tokio::runtime::Builder::new_multi_thread()
+        .enable_all()
+        .build()
+        .context("build WASIX example Tokio runtime")?;
+    runtime.block_on(async {
+        let server = start_database_server(directory).await?;
+        connect_database(server).await
+    })
+}
+
+async fn start_database_server(directory: PathBuf) -> Result {
+    let server = AsyncOliphauntServer::builder()
+        .storage(oliphaunt_wasix::DatabaseStorage::Directory(directory))
+        .extensions([Extension::HSTORE, Extension::PG_TRGM, Extension::UNACCENT])
+        .start()
+        .await
+        .context("start oliphaunt-wasix server")?;
+    Ok(server)
+}
+
+async fn connect_database(server: AsyncOliphauntServer) -> Result {
+    let pool = PgPoolOptions::new()
+        .max_connections(1)
+        .acquire_timeout(Duration::from_secs(30))
+        .connect(&server.connection_string())
+        .await
+        .context("connect SQLx pool to oliphaunt-wasix server")?;
+    init_schema(&pool).await?;
+    Ok(TodoDatabase {
+        pool,
+        _server: server,
+    })
+}
+
+async fn init_schema(pool: &PgPool) -> Result<()> {
+    for statement in CREATE_EXTENSIONS {
+        sqlx::query(statement).execute(pool).await?;
+    }
+    sqlx::query(CREATE_TABLE).execute(pool).await?;
+    sqlx::query(CREATE_INDEX).execute(pool).await?;
+    Ok(())
+}
+
+#[cfg(test)]
+fn validate_wasix_tools() -> Result<()> {
+    let mut database = Oliphaunt::open()?;
+    let dump = database.pg_dump(tools::PgDumpOptions::new().arg("--schema-only"))?;
+    anyhow::ensure!(
+        dump.contains("PostgreSQL database dump"),
+        "pg_dump SQL backup smoke did not look like a PostgreSQL dump"
+    );
+    let psql = database.psql(tools::PsqlOptions::new().arg("-tA").command("SELECT 1"))?;
+    anyhow::ensure!(
+        psql.lines().any(|line| line.trim() == "1"),
+        "psql smoke did not return SELECT 1 output"
+    );
+    database.close()?;
+    Ok(())
+}
+
+#[tauri::command]
+async fn list_todos(
+    state: tauri::State<'_, TodoStore>,
+    search: String,
+    status: String,
+) -> Result, CommandError> {
+    let db = state.inner.lock().await;
+    let rows = sqlx::query(SELECT_TODOS)
+        .bind(search)
+        .bind(status)
+        .fetch_all(&db.pool)
+        .await?;
+    rows.into_iter()
+        .map(|row| todo_from_row(&row).map_err(CommandError::from))
+        .collect()
+}
+
+#[tauri::command]
+async fn create_todo(
+    state: tauri::State<'_, TodoStore>,
+    input: CreateTodo,
+) -> Result {
+    let db = state.inner.lock().await;
+    let sql = format!(
+        "INSERT INTO todos (title, notes, tags, priority)
+         VALUES ($1, $2, hstore(ARRAY['area', $3, 'context', $4]), $5)
+         {RETURNING_TODO}"
+    );
+    let row = sqlx::query(&sql)
+        .bind(input.title)
+        .bind(input.notes)
+        .bind(input.area)
+        .bind(input.context)
+        .bind(input.priority.clamp(1, 3))
+        .fetch_one(&db.pool)
+        .await?;
+    todo_from_row(&row).map_err(CommandError::from)
+}
+
+#[tauri::command]
+async fn toggle_todo(state: tauri::State<'_, TodoStore>, id: i64) -> Result {
+    let db = state.inner.lock().await;
+    let sql = format!(
+        "UPDATE todos SET done = NOT done, updated_at = now() WHERE id = $1 {RETURNING_TODO}"
+    );
+    let row = sqlx::query(&sql).bind(id).fetch_one(&db.pool).await?;
+    todo_from_row(&row).map_err(CommandError::from)
+}
+
+#[tauri::command]
+async fn delete_todo(state: tauri::State<'_, TodoStore>, id: i64) -> Result<(), CommandError> {
+    let db = state.inner.lock().await;
+    sqlx::query("DELETE FROM todos WHERE id = $1")
+        .bind(id)
+        .execute(&db.pool)
+        .await?;
+    Ok(())
+}
+
+fn todo_from_row(row: &sqlx::postgres::PgRow) -> Result {
+    Ok(Todo {
+        id: row.try_get("id")?,
+        title: row.try_get("title")?,
+        notes: row.try_get("notes")?,
+        area: row.try_get("area")?,
+        context: row.try_get("context")?,
+        priority: row.try_get("priority")?,
+        done: row.try_get("done")?,
+        created_at: row.try_get("created_at")?,
+        updated_at: row.try_get("updated_at")?,
+    })
+}
+
+#[cfg_attr(mobile, tauri::mobile_entry_point)]
+pub fn run() {
+    tauri::Builder::default()
+        .setup(|app| {
+            let directory = app.path().app_data_dir()?.join("oliphaunt-wasix-todos");
+            let db = open_database(directory)?;
+            app.manage(TodoStore {
+                inner: Mutex::new(db),
+            });
+            Ok(())
+        })
+        .invoke_handler(tauri::generate_handler![
+            list_todos,
+            create_todo,
+            toggle_todo,
+            delete_todo
+        ])
+        .run(tauri::generate_context!())
+        .expect("error while running tauri application");
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn startup_smoke_runs_split_wasix_tools() {
+        let directory = std::env::temp_dir().join(format!(
+            "oliphaunt-example-tauri-wasix-smoke-{}",
+            std::process::id()
+        ));
+        let _ = std::fs::remove_dir_all(&directory);
+        validate_wasix_tools().expect("run explicit split WASIX tools smoke");
+        let db = open_database(directory.clone())
+            .expect("start oliphaunt-wasix example database after tools smoke");
+        drop(db);
+        let _ = std::fs::remove_dir_all(directory);
+    }
+}
diff --git a/examples/tauri-wasix/src-tauri/src/main.rs b/src/examples/tauri-wasix/src-tauri/src/main.rs
similarity index 100%
rename from examples/tauri-wasix/src-tauri/src/main.rs
rename to src/examples/tauri-wasix/src-tauri/src/main.rs
diff --git a/src/examples/tauri-wasix/src-tauri/tauri.conf.json b/src/examples/tauri-wasix/src-tauri/tauri.conf.json
new file mode 100644
index 000000000..d5924680a
--- /dev/null
+++ b/src/examples/tauri-wasix/src-tauri/tauri.conf.json
@@ -0,0 +1,28 @@
+{
+  "$schema": "https://schema.tauri.app/config/2",
+  "productName": "Oliphaunt Tauri WASIX Todo",
+  "version": "0.1.0",
+  "identifier": "dev.oliphaunt.examples.tauri.wasix.todo",
+  "build": {
+    "beforeDevCommand": "bun run dev",
+    "devUrl": "http://localhost:1422",
+    "beforeBuildCommand": "bun run build",
+    "frontendDist": "../dist"
+  },
+  "app": {
+    "windows": [
+      {
+        "title": "Oliphaunt Tauri WASIX Todo",
+        "width": 1100,
+        "height": 760
+      }
+    ],
+    "security": {
+      "csp": null
+    }
+  },
+  "bundle": {
+    "active": false,
+    "icon": ["../../assets/tauri-icon.png"]
+  }
+}
diff --git a/src/examples/tauri-wasix/src/main.ts b/src/examples/tauri-wasix/src/main.ts
new file mode 100644
index 000000000..9c72d46d3
--- /dev/null
+++ b/src/examples/tauri-wasix/src/main.ts
@@ -0,0 +1 @@
+import '../../tauri/src/main.ts';
diff --git a/examples/tauri-wasix/src/styles.css b/src/examples/tauri-wasix/src/styles.css
similarity index 100%
rename from examples/tauri-wasix/src/styles.css
rename to src/examples/tauri-wasix/src/styles.css
diff --git a/examples/tauri-wasix/tsconfig.json b/src/examples/tauri-wasix/tsconfig.json
similarity index 100%
rename from examples/tauri-wasix/tsconfig.json
rename to src/examples/tauri-wasix/tsconfig.json
diff --git a/src/examples/tauri-wasix/vite.config.ts b/src/examples/tauri-wasix/vite.config.ts
new file mode 100644
index 000000000..b4b718954
--- /dev/null
+++ b/src/examples/tauri-wasix/vite.config.ts
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+  clearScreen: false,
+  server: {
+    port: 1422,
+    strictPort: true,
+  },
+});
diff --git a/examples/tauri/.gitignore b/src/examples/tauri/.gitignore
similarity index 100%
rename from examples/tauri/.gitignore
rename to src/examples/tauri/.gitignore
diff --git a/src/examples/tauri/README.md b/src/examples/tauri/README.md
new file mode 100644
index 000000000..332a1bca3
--- /dev/null
+++ b/src/examples/tauri/README.md
@@ -0,0 +1,11 @@
+# Tauri Native Todo
+
+Tauri v2 owns an `oliphaunt` Rust SDK handle in backend state and exposes
+app-specific commands to the webview. The native runtime is selected in Rust,
+the persistent storage lives under the app data directory, and the exact extension
+set is declared in `src-tauri/Cargo.toml`.
+
+```sh
+bun install --cwd src/examples/tauri
+bun run --cwd src/examples/tauri tauri dev
+```
diff --git a/examples/tauri/index.html b/src/examples/tauri/index.html
similarity index 100%
rename from examples/tauri/index.html
rename to src/examples/tauri/index.html
diff --git a/examples/tauri/package.json b/src/examples/tauri/package.json
similarity index 100%
rename from examples/tauri/package.json
rename to src/examples/tauri/package.json
diff --git a/examples/tauri/pnpm-workspace.yaml b/src/examples/tauri/pnpm-workspace.yaml
similarity index 100%
rename from examples/tauri/pnpm-workspace.yaml
rename to src/examples/tauri/pnpm-workspace.yaml
diff --git a/examples/tauri/src-tauri/Cargo.toml b/src/examples/tauri/src-tauri/Cargo.toml
similarity index 100%
rename from examples/tauri/src-tauri/Cargo.toml
rename to src/examples/tauri/src-tauri/Cargo.toml
diff --git a/examples/tauri/src-tauri/build.rs b/src/examples/tauri/src-tauri/build.rs
similarity index 100%
rename from examples/tauri/src-tauri/build.rs
rename to src/examples/tauri/src-tauri/build.rs
diff --git a/examples/tauri/src-tauri/capabilities/default.json b/src/examples/tauri/src-tauri/capabilities/default.json
similarity index 100%
rename from examples/tauri/src-tauri/capabilities/default.json
rename to src/examples/tauri/src-tauri/capabilities/default.json
diff --git a/examples/tauri/src-tauri/src/lib.rs b/src/examples/tauri/src-tauri/src/lib.rs
similarity index 100%
rename from examples/tauri/src-tauri/src/lib.rs
rename to src/examples/tauri/src-tauri/src/lib.rs
diff --git a/examples/tauri/src-tauri/src/main.rs b/src/examples/tauri/src-tauri/src/main.rs
similarity index 100%
rename from examples/tauri/src-tauri/src/main.rs
rename to src/examples/tauri/src-tauri/src/main.rs
diff --git a/src/examples/tauri/src-tauri/tauri.conf.json b/src/examples/tauri/src-tauri/tauri.conf.json
new file mode 100644
index 000000000..05e8e2277
--- /dev/null
+++ b/src/examples/tauri/src-tauri/tauri.conf.json
@@ -0,0 +1,28 @@
+{
+  "$schema": "https://schema.tauri.app/config/2",
+  "productName": "Oliphaunt Tauri Todo",
+  "version": "0.1.0",
+  "identifier": "dev.oliphaunt.examples.tauri.todo",
+  "build": {
+    "beforeDevCommand": "bun run dev",
+    "devUrl": "http://localhost:1421",
+    "beforeBuildCommand": "bun run build",
+    "frontendDist": "../dist"
+  },
+  "app": {
+    "windows": [
+      {
+        "title": "Oliphaunt Tauri Todo",
+        "width": 1100,
+        "height": 760
+      }
+    ],
+    "security": {
+      "csp": null
+    }
+  },
+  "bundle": {
+    "active": false,
+    "icon": ["../../assets/tauri-icon.png"]
+  }
+}
diff --git a/src/examples/tauri/src/main.ts b/src/examples/tauri/src/main.ts
new file mode 100644
index 000000000..d76bedd1a
--- /dev/null
+++ b/src/examples/tauri/src/main.ts
@@ -0,0 +1,160 @@
+import { invoke } from '@tauri-apps/api/core';
+
+type Todo = {
+  id: number;
+  title: string;
+  notes: string;
+  area: string;
+  context: string;
+  priority: number;
+  done: boolean;
+  createdAt: string;
+  updatedAt: string;
+};
+
+type CreateTodoInput = {
+  title: string;
+  notes: string;
+  area: string;
+  context: string;
+  priority: number;
+};
+
+type StatusFilter = 'open' | 'all' | 'done';
+
+const form = document.querySelector('#todo-form');
+const list = document.querySelector('#todo-list');
+const status = document.querySelector('#status');
+const search = document.querySelector('#search');
+const openCount = document.querySelector('#open-count');
+const doneCount = document.querySelector('#done-count');
+const highCount = document.querySelector('#high-count');
+let activeStatus: StatusFilter = 'open';
+let todos: Todo[] = [];
+
+async function listTodos() {
+  todos = await invoke('list_todos', {
+    search: search?.value.trim() ?? '',
+    status: activeStatus,
+  });
+  render();
+}
+
+async function createTodo(input: CreateTodoInput) {
+  await invoke('create_todo', { input });
+  await listTodos();
+}
+
+async function toggleTodo(id: number) {
+  await invoke('toggle_todo', { id });
+  await listTodos();
+}
+
+async function deleteTodo(id: number) {
+  await invoke('delete_todo', { id });
+  await listTodos();
+}
+
+function setStatus(message: string) {
+  if (status) status.value = message;
+}
+
+function priorityLabel(priority: number) {
+  if (priority === 1) return 'High';
+  if (priority === 3) return 'Low';
+  return 'Normal';
+}
+
+function render() {
+  const open = todos.filter((todo) => !todo.done).length;
+  const done = todos.filter((todo) => todo.done).length;
+  const high = todos.filter((todo) => !todo.done && todo.priority === 1).length;
+  if (openCount) openCount.value = `${open} open`;
+  if (doneCount) doneCount.value = `${done} done`;
+  if (highCount) highCount.value = `${high} high priority`;
+  if (!list) return;
+  if (todos.length === 0) {
+    const empty = document.createElement('p');
+    empty.className = 'empty';
+    empty.textContent = 'No todos match the current filter.';
+    list.replaceChildren(empty);
+    return;
+  }
+  list.replaceChildren(...todos.map(renderTodo));
+}
+
+function renderTodo(todo: Todo) {
+  const row = document.createElement('article');
+  row.className = todo.done ? 'todo done' : 'todo';
+
+  const checkbox = document.createElement('input');
+  checkbox.type = 'checkbox';
+  checkbox.checked = todo.done;
+  checkbox.addEventListener('change', () => void toggleTodo(todo.id));
+
+  const body = document.createElement('div');
+  const title = document.createElement('h2');
+  title.textContent = todo.title;
+  const notes = document.createElement('p');
+  notes.textContent = todo.notes || 'No notes';
+  const meta = document.createElement('div');
+  meta.className = 'meta';
+  for (const value of [
+    priorityLabel(todo.priority),
+    todo.area ? `area:${todo.area}` : '',
+    todo.context ? `context:${todo.context}` : '',
+    `updated ${todo.updatedAt}`,
+  ]) {
+    if (!value) continue;
+    const pill = document.createElement('span');
+    pill.className = 'pill';
+    pill.textContent = value;
+    meta.append(pill);
+  }
+  body.append(title, notes, meta);
+
+  const remove = document.createElement('button');
+  remove.className = 'secondary';
+  remove.type = 'button';
+  remove.textContent = 'Delete';
+  remove.addEventListener('click', () => void deleteTodo(todo.id));
+
+  row.append(checkbox, body, remove);
+  return row;
+}
+
+form?.addEventListener('submit', (event) => {
+  event.preventDefault();
+  const data = new FormData(form);
+  const input: CreateTodoInput = {
+    title: String(data.get('title') ?? '').trim(),
+    notes: String(data.get('notes') ?? '').trim(),
+    area: String(data.get('area') ?? '').trim(),
+    context: String(data.get('context') ?? '').trim(),
+    priority: Number(data.get('priority') ?? 2),
+  };
+  if (!input.title) return;
+  setStatus('Saving');
+  createTodo(input)
+    .then(() => {
+      form.reset();
+      setStatus('Saved');
+    })
+    .catch((error) => setStatus(String(error)));
+});
+
+search?.addEventListener('input', () => {
+  void listTodos().catch((error) => setStatus(String(error)));
+});
+
+document.querySelectorAll('[data-status]').forEach((button) => {
+  button.addEventListener('click', () => {
+    activeStatus = button.dataset.status as StatusFilter;
+    document.querySelectorAll('[data-status]').forEach((candidate) => {
+      candidate.classList.toggle('active', candidate === button);
+    });
+    void listTodos().catch((error) => setStatus(String(error)));
+  });
+});
+
+void listTodos().catch((error) => setStatus(String(error)));
diff --git a/examples/tauri/src/styles.css b/src/examples/tauri/src/styles.css
similarity index 100%
rename from examples/tauri/src/styles.css
rename to src/examples/tauri/src/styles.css
diff --git a/examples/tauri/tsconfig.json b/src/examples/tauri/tsconfig.json
similarity index 100%
rename from examples/tauri/tsconfig.json
rename to src/examples/tauri/tsconfig.json
diff --git a/src/examples/tauri/vite.config.ts b/src/examples/tauri/vite.config.ts
new file mode 100644
index 000000000..8c799ba11
--- /dev/null
+++ b/src/examples/tauri/vite.config.ts
@@ -0,0 +1,9 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+  clearScreen: false,
+  server: {
+    port: 1421,
+    strictPort: true,
+  },
+});
diff --git a/src/examples/tools/assert-installed-package.mts b/src/examples/tools/assert-installed-package.mts
new file mode 100644
index 000000000..51119dc76
--- /dev/null
+++ b/src/examples/tools/assert-installed-package.mts
@@ -0,0 +1,24 @@
+import { createRequire } from 'node:module';
+const require = createRequire(import.meta.url);
+const fs = require('node:fs');
+const path = require('node:path');
+
+const [packageName, expectedVersion, resolverPackage] = process.argv.slice(2);
+const resolvePaths = [process.cwd()];
+if (resolverPackage) {
+  const resolverPackageJson = require.resolve(`${resolverPackage}/package.json`, {
+    paths: [process.cwd()],
+  });
+  resolvePaths.unshift(path.dirname(resolverPackageJson));
+}
+const packageJson = require.resolve(`${packageName}/package.json`, {
+  paths: resolvePaths,
+});
+const data = JSON.parse(fs.readFileSync(packageJson, 'utf8'));
+if (data.version !== expectedVersion) {
+  throw new Error(`${packageName} resolved version ${data.version}, expected ${expectedVersion}`);
+}
+const normalized = packageJson.split(path.sep).join('/');
+if (!normalized.includes('/node_modules/')) {
+  throw new Error(`${packageName} resolved outside node_modules: ${packageJson}`);
+}
diff --git a/src/examples/tools/electron-test-driver.mts b/src/examples/tools/electron-test-driver.mts
new file mode 100755
index 000000000..426bdbc0e
--- /dev/null
+++ b/src/examples/tools/electron-test-driver.mts
@@ -0,0 +1,75 @@
+const webdriverTimeoutMs = 90_000;
+
+async function waitForWindowLoad(window) {
+  if (!window.webContents.isLoading()) return;
+  await new Promise((resolve, reject) => {
+    const timer = setTimeout(() => reject(new Error('timed out waiting for window load')), 30_000);
+    window.webContents.once('did-finish-load', () => {
+      clearTimeout(timer);
+      resolve();
+    });
+    window.webContents.once('did-fail-load', (_event, _code, description) => {
+      clearTimeout(timer);
+      reject(new Error(`window failed to load: ${description}`));
+    });
+  });
+}
+
+export async function runElectronTodoSmoke(window) {
+  await waitForWindowLoad(window);
+  return window.webContents.executeJavaScript(
+    `(${rendererTodoSmoke.toString()})(${JSON.stringify(webdriverTimeoutMs)})`,
+    true,
+  );
+}
+
+async function rendererTodoSmoke(timeoutMs) {
+  const title = `Ship Electron e2e ${Date.now()}`;
+  const notes = 'created by Electron test driver';
+
+  const required = (selector) => {
+    const element = document.querySelector(selector);
+    if (!element) throw new Error(`missing selector: ${selector}`);
+    return element;
+  };
+  const setValue = (selector, value) => {
+    const element = required(selector);
+    element.value = value;
+    element.dispatchEvent(new Event('input', { bubbles: true }));
+    element.dispatchEvent(new Event('change', { bubbles: true }));
+  };
+  const waitFor = async (predicate, label) => {
+    const deadline = Date.now() + timeoutMs;
+    while (Date.now() < deadline) {
+      if (predicate()) return;
+      await new Promise((resolve) => setTimeout(resolve, 250));
+    }
+    throw new Error(`timed out waiting for ${label}; body was: ${document.body.innerText}`);
+  };
+
+  await waitFor(() => Boolean(window.todos), 'preload todo API');
+  await waitFor(
+    () => required('#todo-list').textContent?.includes('No todos match the current filter.'),
+    'initial todo list',
+  );
+
+  setValue('#title', title);
+  setValue('#notes', notes);
+  setValue('#area', 'examples');
+  setValue('#context', 'public packages');
+  setValue('#priority', '1');
+  required("button[type='submit']").click();
+
+  await waitFor(() => document.body.innerText.includes(title), 'created todo title');
+  await waitFor(() => document.body.innerText.includes(notes), 'created todo notes');
+
+  required("article.todo input[type='checkbox']").click();
+  await waitFor(() => required('#open-count').textContent?.includes('0 open'), 'todo toggle');
+  required("[data-status='done']").click();
+  await waitFor(
+    () => document.querySelector('article.todo.done')?.textContent?.includes(notes) === true,
+    'done todo filter',
+  );
+
+  return document.body.innerText;
+}
diff --git a/src/examples/tools/example-release-dependencies.mts b/src/examples/tools/example-release-dependencies.mts
new file mode 100644
index 000000000..f43700fa0
--- /dev/null
+++ b/src/examples/tools/example-release-dependencies.mts
@@ -0,0 +1,112 @@
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+import { pathToFileURL } from 'node:url';
+
+const ELECTRON_RELEASE_DEPENDENCIES = [
+  {
+    packageName: '@oliphaunt/ts',
+    versionSource: { type: 'json', path: 'src/sdks/ts/sdk/package.json', keys: ['version'] },
+  },
+  {
+    packageName: '@oliphaunt/tools',
+    versionSource: {
+      type: 'json',
+      path: 'src/postgres-tools/native/npm/package.json',
+      keys: ['version'],
+    },
+  },
+  {
+    packageName: '@oliphaunt/extension-contrib-pg18',
+    versionSource: { type: 'text', path: 'src/runtimes/liboliphaunt-native/VERSION' },
+  },
+];
+
+const ELECTRON_SMOKE_PACKAGES = [
+  {
+    packageName: '@oliphaunt/liboliphaunt-linux-x64-gnu',
+    versionSource: {
+      type: 'json',
+      path: 'src/runtimes/liboliphaunt-native/packages/linux-x64-gnu/package.json',
+      keys: ['version'],
+    },
+  },
+];
+
+function fail(message) {
+  console.error(`example-release-dependencies.mts: ${message}`);
+  process.exit(2);
+}
+
+function readJsonObject(root, relativePath) {
+  const file = path.join(root, relativePath);
+  const value = JSON.parse(readFileSync(file, 'utf8'));
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    throw new Error(`${relativePath} must contain a JSON object`);
+  }
+  return value;
+}
+
+function readVersion(root, source, context) {
+  if (source.type === 'text') {
+    const version = readFileSync(path.join(root, source.path), 'utf8').trim();
+    if (!version) {
+      throw new Error(`${source.path} does not define a version for ${context}`);
+    }
+    return version;
+  }
+  if (source.type === 'json') {
+    let current = readJsonObject(root, source.path);
+    for (const key of source.keys) {
+      if (current === null || Array.isArray(current) || typeof current !== 'object') {
+        throw new Error(
+          `${source.path} has no JSON object at ${source.keys.join('.')} for ${context}`,
+        );
+      }
+      current = current[key];
+    }
+    if (typeof current !== 'string' || !current) {
+      throw new Error(`${source.path} does not define a string version for ${context}`);
+    }
+    return current;
+  }
+  throw new Error(`${context} uses unsupported version source ${JSON.stringify(source.type)}`);
+}
+
+export function electronReleaseDependencies(root) {
+  return ELECTRON_RELEASE_DEPENDENCIES.map((entry) => ({
+    packageName: entry.packageName,
+    version: readVersion(root, entry.versionSource, entry.packageName),
+  }));
+}
+
+export function electronPackageVersion(root, packageName) {
+  const entry = [...ELECTRON_RELEASE_DEPENDENCIES, ...ELECTRON_SMOKE_PACKAGES].find(
+    (candidate) => candidate.packageName === packageName,
+  );
+  if (entry === undefined) {
+    throw new Error(`unknown Electron example package ${JSON.stringify(packageName)}`);
+  }
+  return readVersion(root, entry.versionSource, packageName);
+}
+
+function printElectronPackageVersion(argv) {
+  const packageName = argv[0];
+  if (typeof packageName !== 'string' || packageName.length === 0) {
+    fail('usage: example-release-dependencies.mts electron-package-version ');
+  }
+  try {
+    process.stdout.write(`${electronPackageVersion(process.cwd(), packageName)}\n`);
+  } catch (error) {
+    fail(error.message);
+  }
+}
+
+const mainUrl = process.argv[1] ? pathToFileURL(path.resolve(process.argv[1])).href : '';
+if (import.meta.url === mainUrl) {
+  const [command, ...args] = process.argv.slice(2);
+  if (command === 'electron-package-version') {
+    printElectronPackageVersion(args);
+  } else {
+    fail('usage: example-release-dependencies.mts electron-package-version ');
+  }
+}
diff --git a/src/examples/tools/run-electron-driver-smoke.sh b/src/examples/tools/run-electron-driver-smoke.sh
new file mode 100755
index 000000000..c2cdc7dd3
--- /dev/null
+++ b/src/examples/tools/run-electron-driver-smoke.sh
@@ -0,0 +1,168 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+
+fail() {
+  echo "run-electron-driver-smoke.sh: $*" >&2
+  exit 1
+}
+
+app_dir="${1:-}"
+if [ -z "$app_dir" ]; then
+  fail "usage: src/examples/tools/run-electron-driver-smoke.sh "
+fi
+if [ ! -f "$app_dir/package.json" ] || [ ! -f "$app_dir/src/main-process.ts" ]; then
+  fail "$app_dir does not look like an Electron example directory"
+fi
+
+command -v node >/dev/null 2>&1 || fail "missing node"
+command -v timeout >/dev/null 2>&1 || fail "missing GNU timeout"
+command -v bun >/dev/null 2>&1 || fail "missing bun"
+
+assert_npm_package() {
+  local package_name="$1"
+  local expected_version="$2"
+  local resolver_package="${3:-}"
+  (cd "$app_dir" && bun "$root/src/examples/tools/assert-installed-package.mts" "$package_name" "$expected_version" "$resolver_package")
+}
+
+example_package_version() {
+  local package_name="$1"
+  bun "$root/src/examples/tools/example-release-dependencies.mts" electron-package-version "$package_name"
+}
+
+electron_relative_path() {
+  local platform="$1"
+  local arch="$2"
+  case "$platform/$arch" in
+    linux/*)
+      printf '%s\n' "electron"
+      ;;
+    darwin/*)
+      printf '%s\n' "Electron.app/Contents/MacOS/Electron"
+      ;;
+    win32/*)
+      printf '%s\n' "electron.exe"
+      ;;
+    *)
+      fail "unsupported Electron e2e platform: $platform/$arch"
+      ;;
+  esac
+}
+
+repair_electron_install() {
+  local electron_pkg="$1"
+  local platform="$2"
+  local arch="$3"
+  local relative_path="$4"
+  local electron_path="$electron_pkg/dist/$relative_path"
+
+  if [ -x "$electron_path" ]; then
+    return
+  fi
+  command -v unzip >/dev/null 2>&1 || fail "missing unzip required to repair Electron binary install"
+
+  local version
+  version="$(node "$root/tools/dev/node-info.mts" package-version "$electron_pkg/package.json")"
+  local archive_name="electron-v$version-$platform-$arch.zip"
+  local archive=""
+  for cache_root in "${electron_config_cache:-}" "$HOME/.cache/electron"; do
+    if [ -n "$cache_root" ] && [ -d "$cache_root" ]; then
+      archive="$(find "$cache_root" -name "$archive_name" -type f | sort | tail -n 1)"
+      [ -n "$archive" ] && break
+    fi
+  done
+  if [ -z "$archive" ]; then
+    fail "Electron installed without $relative_path and cached $archive_name was not found"
+  fi
+
+  rm -rf "$electron_pkg/dist"
+  mkdir -p "$electron_pkg/dist"
+  unzip -q "$archive" -d "$electron_pkg/dist"
+  printf '%s' "$relative_path" >"$electron_pkg/path.txt"
+  if [ -f "$electron_pkg/dist/electron.d.ts" ]; then
+    mv "$electron_pkg/dist/electron.d.ts" "$electron_pkg/electron.d.ts"
+  fi
+}
+
+wasix_sidecar_env=()
+prepare_wasix_sidecar() {
+  if [ ! -f "$app_dir/src-wasix/Cargo.toml" ]; then
+    return
+  fi
+
+  local scratch="$root/target/e2e/electron-sidecars${app_dir//\//-}"
+  rm -rf "$scratch"
+  mkdir -p "$scratch"
+  cp -R "$root/$app_dir/src-wasix/." "$scratch/"
+  rm -f "$scratch/Cargo.lock"
+
+  cargo build \
+    --quiet \
+    --manifest-path "$scratch/Cargo.toml" \
+    --target-dir "$scratch/target"
+
+  local package_name
+  package_name="$(
+    awk -F'"' '
+      $0 ~ /^\[package\]/ { in_package = 1; next }
+      $0 ~ /^\[/ && $0 !~ /^\[package\]/ { in_package = 0 }
+      in_package && $1 ~ /^name = / { print $2; exit }
+    ' "$scratch/Cargo.toml"
+  )"
+  if [ -z "$package_name" ]; then
+    fail "could not read package name from $scratch/Cargo.toml"
+  fi
+  local sidecar="$scratch/target/debug/$package_name"
+  if [ ! -x "$sidecar" ]; then
+    fail "missing built WASIX sidecar: $sidecar"
+  fi
+  wasix_sidecar_env=("OLIPHAUNT_WASIX_TODO_SIDECAR=$sidecar")
+}
+
+bun install --cwd "$app_dir"
+electron_pkg="$root/$app_dir/node_modules/electron"
+electron_platform="$(node "$root/tools/dev/node-info.mts" platform)"
+electron_arch="$(node "$root/tools/dev/node-info.mts" arch)"
+electron_relative="$(electron_relative_path "$electron_platform" "$electron_arch")"
+repair_electron_install "$electron_pkg" "$electron_platform" "$electron_arch" "$electron_relative"
+electron="$electron_pkg/dist/$electron_relative"
+if [ ! -x "$electron" ]; then
+  fail "missing Electron executable at $electron after example install"
+fi
+if [ "$app_dir" = "src/examples/electron" ]; then
+  typescript_version="$(example_package_version "@oliphaunt/ts")"
+  liboliphaunt_linux_version="$(example_package_version "@oliphaunt/liboliphaunt-linux-x64-gnu")"
+  contrib_version="$(example_package_version "@oliphaunt/extension-contrib-pg18")"
+
+  assert_npm_package "@oliphaunt/ts" "$typescript_version"
+  assert_npm_package "@oliphaunt/liboliphaunt-linux-x64-gnu" "$liboliphaunt_linux_version" "@oliphaunt/ts"
+  assert_npm_package "@oliphaunt/extension-contrib-pg18" "$contrib_version"
+fi
+bun run --cwd "$app_dir" build
+prepare_wasix_sidecar
+
+user_data="$(mktemp -d)"
+trap 'rm -rf "$user_data"' EXIT
+cd "$root/$app_dir"
+run_smoke=(
+  timeout --kill-after=3s 210s
+  env
+  "OLIPHAUNT_ELECTRON_E2E_DRIVER=1"
+  "${wasix_sidecar_env[@]}"
+  "$electron"
+  --no-sandbox
+  "--user-data-dir=$user_data"
+  dist/main/main-process.js
+)
+
+if command -v xvfb-run >/dev/null 2>&1; then
+  xvfb-run -a "${run_smoke[@]}"
+else
+  "${run_smoke[@]}"
+fi
diff --git a/src/examples/tools/run-tauri-webdriver-smoke.sh b/src/examples/tools/run-tauri-webdriver-smoke.sh
new file mode 100755
index 000000000..ca1dc04a2
--- /dev/null
+++ b/src/examples/tools/run-tauri-webdriver-smoke.sh
@@ -0,0 +1,103 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+
+fail() {
+  echo "run-tauri-webdriver-smoke.sh: $*" >&2
+  exit 1
+}
+
+# The GUI session owns the driver process and its descendants.
+if [ "${1:-}" = --run-built ]; then
+  [ "$#" = 3 ] || fail 'internal GUI invocation requires DRIVER APPLICATION'
+  command -v setsid >/dev/null || fail 'missing setsid'
+  command -v timeout >/dev/null || fail 'missing GNU timeout'
+  app_data="$(mktemp -d)"
+  driver_pid=''
+  # This function is invoked only by the EXIT trap.
+  # shellcheck disable=SC2317
+  cleanup_driver() {
+    if [ -n "$driver_pid" ]; then
+      kill -TERM -- "-$driver_pid" 2>/dev/null || true
+      if kill -0 -- "-$driver_pid" 2>/dev/null; then
+        sleep 1
+        kill -KILL -- "-$driver_pid" 2>/dev/null || true
+      fi
+      wait "$driver_pid" 2>/dev/null || true
+    fi
+    rm -rf "$app_data"
+  }
+  trap 'cleanup_driver' EXIT
+  ports="$(bun "$root/src/examples/tools/tauri-webdriver-smoke.mts" --ports)"
+  read -r port native_port <<< "$ports"
+  XDG_DATA_HOME="$app_data" XDG_CONFIG_HOME="$app_data" XDG_CACHE_HOME="$app_data" \
+    setsid -- "$2" --port "$port" --native-port "$native_port" &
+  driver_pid=$!
+  timeout --kill-after=3s 210s bun "$root/src/examples/tools/tauri-webdriver-smoke.mts" "$port" "$3"
+  exit 0
+fi
+
+source_app_dir="${1:-}"
+if [ -z "$source_app_dir" ]; then
+  fail "usage: src/examples/tools/run-tauri-webdriver-smoke.sh "
+fi
+if [[ "$source_app_dir" = /* ]]; then
+  source_app_path="$(realpath -m "$source_app_dir")"
+else
+  source_app_path="$(realpath -m "$root/$source_app_dir")"
+fi
+case "$source_app_path" in
+  "$root"/*) ;;
+  *) fail "example path must remain inside the repository: $source_app_dir" ;;
+esac
+if [ ! -f "$source_app_path/src-tauri/Cargo.toml" ]; then
+  fail "$source_app_dir does not look like a Tauri example directory"
+fi
+
+command -v node >/dev/null 2>&1 || fail "missing node"
+command -v bun >/dev/null 2>&1 || fail "missing bun"
+command -v WebKitWebDriver >/dev/null 2>&1 ||
+  fail "missing WebKitWebDriver; install webkit2gtk-driver on Debian/Ubuntu"
+
+driver="$root/target/e2e-tools/bin/tauri-driver"
+if [ ! -x "$driver" ]; then
+  cargo install tauri-driver --locked --version 2.0.6 --root "$root/target/e2e-tools"
+fi
+
+source_app_relative="${source_app_path#"$root"/}"
+scratch="$root/target/e2e/tauri-apps${source_app_relative//\//-}/$$"
+trap 'rm -rf "$scratch"' EXIT
+rm -rf "$scratch"
+app_dir="$(src/examples/tools/stage-tauri-webdriver-app.sh "$source_app_path" "$scratch")"
+rm -f "$app_dir/src-tauri/Cargo.lock"
+
+bun install --cwd "$app_dir"
+bun run --cwd "$app_dir" tauri build --debug
+
+package_name="$(
+  awk -F'"' '
+    $0 ~ /^\[package\]/ { in_package = 1; next }
+    $0 ~ /^\[/ && $0 !~ /^\[package\]/ { in_package = 0 }
+    in_package && $1 ~ /^name = / { print $2; exit }
+  ' "$app_dir/src-tauri/Cargo.toml"
+)"
+if [ -z "$package_name" ]; then
+  fail "could not read package name from $app_dir/src-tauri/Cargo.toml"
+fi
+application="$app_dir/src-tauri/target/debug/$package_name"
+if [ ! -x "$application" ]; then
+  fail "missing built Tauri application: $application"
+fi
+
+run_smoke=(bash "$root/src/examples/tools/run-tauri-webdriver-smoke.sh" --run-built "$driver" "$application")
+
+if command -v xvfb-run >/dev/null 2>&1; then
+  xvfb-run -a "${run_smoke[@]}"
+else
+  "${run_smoke[@]}"
+fi
diff --git a/src/examples/tools/run-tauri-webdriver-smoke.test.sh b/src/examples/tools/run-tauri-webdriver-smoke.test.sh
new file mode 100644
index 000000000..5e5baa451
--- /dev/null
+++ b/src/examples/tools/run-tauri-webdriver-smoke.test.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+set -euo pipefail
+if [ "$(uname -s)" != Linux ]; then
+  echo 'Tauri WebDriver process cleanup check requires Linux'
+  exit 0
+fi
+root="$(git rev-parse --show-toplevel)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+export TAURI_DRIVER_PROOF="$scratch"
+
+cat > "$scratch/driver" <<'DRIVER'
+#!/usr/bin/env bash
+set -euo pipefail
+sleep 300 &
+echo "$!" > "$TAURI_DRIVER_PROOF/descendant"
+exec bun "$TAURI_DRIVER_PROOF/driver.mts" "$@"
+DRIVER
+chmod +x "$scratch/driver"
+cat > "$scratch/driver.mts" <<'DRIVER'
+import assert from 'node:assert/strict';
+import { writeFileSync } from 'node:fs';
+import { createServer } from 'node:http';
+const proof = process.env.TAURI_DRIVER_PROOF;
+writeFileSync(`${proof}/profile`, process.env.XDG_DATA_HOME);
+createServer(async (request, response) => {
+  const chunks = [];
+  for await (const chunk of request) chunks.push(chunk);
+  const body = JSON.parse(Buffer.concat(chunks).toString() || '{}');
+  let value = {};
+  if (request.method === 'POST' && request.url === '/session') {
+    assert.equal(body.capabilities.alwaysMatch['tauri:options'].application, '/test/application');
+    value = { sessionId: 'test' };
+  } else if (request.url.endsWith('/element')) {
+    value = process.env.FAIL_SMOKE === '1'
+      ? { error: 'no such element' }
+      : { 'element-6066-11e4-a52e-4f735466cecf': 'element' };
+  } else if (request.url.endsWith('/execute/sync')) {
+    value = 'created by raw WebDriver';
+  } else if (request.method === 'DELETE' && request.url === '/session/test') {
+    writeFileSync(`${proof}/deleted`, 'yes');
+  }
+  response.setHeader('content-type', 'application/json');
+  response.end(JSON.stringify({ value }));
+}).listen(Number(process.argv[3]), '127.0.0.1');
+DRIVER
+
+for failure in 0 1; do
+  rm -f "$scratch/deleted"
+  status=0
+  FAIL_SMOKE="$failure" bash "$root/src/examples/tools/run-tauri-webdriver-smoke.sh" \
+    --run-built "$scratch/driver" /test/application > "$scratch/output" 2>&1 || status=$?
+  if { [ "$failure" = 0 ] && [ "$status" != 0 ]; } ||
+     { [ "$failure" = 1 ] && [ "$status" = 0 ]; }; then
+    cat "$scratch/output" >&2
+    exit 1
+  fi
+  test -f "$scratch/deleted"
+  test ! -e "$(cat "$scratch/profile")"
+  descendant="$(cat "$scratch/descendant")"
+  # An orphan can briefly remain as a zombie until the host reaps it.
+  state="$(ps -o stat= -p "$descendant" || true)"
+  [[ -z "$state" || "$state" = Z* ]]
+done
+echo 'Tauri WebDriver session, profile and descendant cleanup passed on success and failure'
diff --git a/src/examples/tools/stage-tauri-webdriver-app.sh b/src/examples/tools/stage-tauri-webdriver-app.sh
new file mode 100755
index 000000000..15401ac1a
--- /dev/null
+++ b/src/examples/tools/stage-tauri-webdriver-app.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "stage-tauri-webdriver-app.sh: must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+
+fail() {
+  echo "stage-tauri-webdriver-app.sh: $*" >&2
+  exit 1
+}
+
+source_app_dir="${1:-}"
+destination_root="${2:-}"
+if [[ -z "$source_app_dir" || -z "$destination_root" ]]; then
+  fail "usage: src/examples/tools/stage-tauri-webdriver-app.sh  "
+fi
+for command_name in node realpath rsync; do
+  command -v "$command_name" >/dev/null 2>&1 || fail "missing required command: $command_name"
+done
+
+if [[ "$source_app_dir" = /* ]]; then
+  source_app_path="$(realpath -m "$source_app_dir")"
+else
+  source_app_path="$(realpath -m "$root/$source_app_dir")"
+fi
+case "$source_app_path" in
+  "$root/src/examples"*) ;;
+  *) fail "Tauri webdriver examples must live under $root/examples: $source_app_dir" ;;
+esac
+[[ -f "$source_app_path/package.json" && -f "$source_app_path/src-tauri/Cargo.toml" ]] ||
+  fail "$source_app_dir does not look like a Tauri example directory"
+source_app_relative="${source_app_path#"$root"/}"
+case "$source_app_relative" in
+  src/examples/tauri | src/examples/tauri-wasix) ;;
+  *) fail "unsupported Tauri webdriver example: $source_app_relative" ;;
+esac
+
+destination_root="$(realpath -m "$destination_root")"
+case "$destination_root" in
+  / | "$root" | "$root/src/examples" | "$root/src/examples"*)
+    fail "destination must not overlap the checkout or its example sources: $destination_root"
+    ;;
+esac
+worktree="$destination_root/worktree"
+rm -rf "$worktree"
+mkdir -p "$worktree/src/examples"
+
+# Keep the bounded example family at its repository-relative location. The
+# Tauri variants deliberately share frontend sources, and relocating only one
+# app silently breaks those relative imports.
+for example in tauri tauri-wasix; do
+  mkdir -p "$worktree/src/examples/$example"
+  rsync -a --delete \
+    --exclude node_modules \
+    --exclude dist \
+    --exclude src-tauri/gen \
+    --exclude src-tauri/target \
+    "$root/src/examples/$example/" "$worktree/src/examples/$example/"
+done
+
+# Tauri resolves bundle icons relative to src-tauri/tauri.conf.json. Copy each
+# selected app icon as a regular file at the same repository-relative path so
+# the scratch build has no symlink or live-checkout dependency.
+config="$source_app_path/src-tauri/tauri.conf.json"
+if [[ -f "$config" ]]; then
+  icons="$(bun "$root/src/examples/tools/tauri-icons.mts" "$config" "$root")"
+  while IFS= read -r asset_relative; do
+    [[ -n "$asset_relative" ]] || continue
+    mkdir -p "$worktree/$(dirname "$asset_relative")"
+    cp -p "$root/$asset_relative" "$worktree/$asset_relative"
+  done <<<"$icons"
+fi
+
+app_dir="$worktree/$source_app_relative"
+[[ -f "$app_dir/package.json" && -f "$app_dir/src-tauri/Cargo.toml" ]] ||
+  fail "staged Tauri example is incomplete: $app_dir"
+printf '%s\n' "$app_dir"
diff --git a/src/examples/tools/stage-tauri-webdriver-app.test.sh b/src/examples/tools/stage-tauri-webdriver-app.test.sh
new file mode 100755
index 000000000..bc19cc16d
--- /dev/null
+++ b/src/examples/tools/stage-tauri-webdriver-app.test.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "stage-tauri-webdriver-app.test.sh: must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+
+fail() {
+  echo "stage-tauri-webdriver-app.test.sh: $*" >&2
+  exit 1
+}
+
+scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-tauri-stage-test.XXXXXX")"
+trap 'rm -rf "$scratch"' EXIT
+
+stage_and_verify() {
+  example="$1"
+  destination="$scratch/$example"
+  actual="$(src/examples/tools/stage-tauri-webdriver-app.sh "src/examples/$example" "$destination")"
+  expected="$destination/worktree/src/examples/$example"
+  [[ "$actual" = "$expected" ]] ||
+    fail "$example staged at $actual, expected $expected"
+  cmp "$root/src/examples/$example/package.json" "$actual/package.json" >/dev/null ||
+    fail "$example package.json changed while staging"
+  cmp "$root/src/examples/$example/src-tauri/Cargo.toml" "$actual/src-tauri/Cargo.toml" >/dev/null ||
+    fail "$example Cargo.toml changed while staging"
+  [[ -z "$(find "$destination/worktree" -type l -print -quit)" ]] ||
+    fail "$example scratch closure contains a symlink into external state"
+  [[ -z "$(find "$destination/worktree/src/examples" -type d \
+    \( -name node_modules -o -name dist -o -path '*/src-tauri/gen' -o -path '*/src-tauri/target' \) \
+    -print -quit)" ]] || fail "$example scratch closure contains generated dependencies or build output"
+  printf '%s\n' "$actual"
+}
+
+tauri="$(stage_and_verify tauri)"
+tauri_wasix="$(stage_and_verify tauri-wasix)"
+
+shared_main="$tauri_wasix/src/../../tauri/src/main.ts"
+shared_styles="$tauri_wasix/src/../../tauri/src/styles.css"
+cmp "$root/src/examples/tauri/src/main.ts" "$shared_main" >/dev/null ||
+  fail "tauri-wasix scratch tree is missing its shared TypeScript source"
+cmp "$root/src/examples/tauri/src/styles.css" "$shared_styles" >/dev/null ||
+  fail "tauri-wasix scratch tree is missing its shared stylesheet"
+
+icon_relative='../../assets/tauri-icon.png'
+for app in "$tauri" "$tauri_wasix"; do
+  icon="$app/src-tauri/$icon_relative"
+  [[ -f "$icon" ]] || fail "$(basename "$app") scratch tree is missing its configured icon"
+  cmp "$root/src/examples/assets/tauri-icon.png" "$icon" >/dev/null ||
+    fail "$(basename "$app") scratch icon differs from its declared source"
+done
+
+if src/examples/tools/stage-tauri-webdriver-app.sh "$scratch" "$scratch/outside-source" >/dev/null 2>&1; then
+  fail "stager accepted a source outside src/examples/"
+fi
+
+echo "Tauri webdriver clean-scratch staging passed"
diff --git a/src/examples/tools/tauri-icons.mts b/src/examples/tools/tauri-icons.mts
new file mode 100644
index 000000000..672ed08bb
--- /dev/null
+++ b/src/examples/tools/tauri-icons.mts
@@ -0,0 +1,23 @@
+import * as fs from 'node:fs';
+import * as path from 'node:path';
+
+const [configFile, root] = process.argv.slice(2);
+const config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
+const icons = config?.bundle?.icon ?? [];
+if (!Array.isArray(icons) || !icons.every((value) => typeof value === 'string')) {
+  throw new Error(`${configFile}: bundle.icon must be an array of paths`);
+}
+for (const icon of icons) {
+  const source = path.resolve(path.dirname(configFile), icon);
+  const relative = path.relative(root, source);
+  if (relative === '' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
+    throw new Error(`${configFile}: bundle icon escapes the repository: ${icon}`);
+  }
+  if (/[\r\n\0]/u.test(relative)) {
+    throw new Error(`${configFile}: bundle icon has an unsafe path: ${icon}`);
+  }
+  if (!fs.statSync(source).isFile()) {
+    throw new Error(`${configFile}: bundle icon is not a regular file: ${icon}`);
+  }
+  process.stdout.write(`${relative.split(path.sep).join('/')}\n`);
+}
diff --git a/src/examples/tools/tauri-webdriver-smoke.mts b/src/examples/tools/tauri-webdriver-smoke.mts
new file mode 100755
index 000000000..d9b48106f
--- /dev/null
+++ b/src/examples/tools/tauri-webdriver-smoke.mts
@@ -0,0 +1,154 @@
+#!/usr/bin/env node
+import { createServer } from 'node:net';
+
+const webdriverElement = 'element-6066-11e4-a52e-4f735466cecf';
+
+if (process.argv[2] === '--ports') {
+  const servers = [createServer(), createServer()];
+  try {
+    await Promise.all(
+      servers.map(
+        (server) =>
+          new Promise((resolve, reject) => {
+            server.once('error', reject);
+            server.listen(0, '127.0.0.1', resolve);
+          }),
+      ),
+    );
+    console.log(
+      servers
+        .map((server) => {
+          const address = server.address();
+          if (!address || typeof address === 'string') throw new Error('missing TCP address');
+          return address.port;
+        })
+        .join(' '),
+    );
+  } finally {
+    for (const server of servers) server.close();
+  }
+} else {
+  await smoke();
+}
+
+async function smoke() {
+  const port = Number(process.argv[2]);
+  const application = process.argv[3];
+  if (!Number.isSafeInteger(port) || port < 1 || port > 65535 || !application)
+    throw new Error('usage: tauri-webdriver-smoke.mts PORT APPLICATION');
+  let sessionId;
+  try {
+    await waitForDriver(port);
+    const session = await request(port, 'POST', '/session', {
+      capabilities: {
+        alwaysMatch: {
+          'tauri:options': { application },
+        },
+      },
+    });
+    sessionId = session.sessionId ?? session.value?.sessionId;
+    if (!sessionId) {
+      throw new Error(`session response did not include sessionId: ${JSON.stringify(session)}`);
+    }
+
+    await setValue(port, sessionId, '#title', `Ship Tauri e2e ${Date.now()}`);
+    await setValue(port, sessionId, '#notes', 'created by raw WebDriver');
+    await setValue(port, sessionId, '#area', 'examples');
+    await setValue(port, sessionId, '#context', 'public packages');
+    await click(port, sessionId, "button[type='submit']");
+    await waitForText(port, sessionId, 'article.todo', 'created by raw WebDriver', 60_000);
+    await click(port, sessionId, "article.todo input[type='checkbox']");
+    await click(port, sessionId, "[data-status='done']");
+    await waitForText(port, sessionId, 'article.todo.done', 'created by raw WebDriver', 60_000);
+    console.log('tauri webdriver todo smoke passed');
+  } finally {
+    if (sessionId) {
+      await request(port, 'DELETE', `/session/${sessionId}`).catch(() => undefined);
+    }
+  }
+}
+
+async function setValue(port, sessionId, selector, value) {
+  const id = await element(port, sessionId, selector);
+  await request(port, 'POST', `/session/${sessionId}/element/${id}/clear`, {});
+  await request(port, 'POST', `/session/${sessionId}/element/${id}/value`, {
+    text: value,
+    value: [...value],
+  });
+}
+
+async function click(port, sessionId, selector) {
+  const id = await element(port, sessionId, selector);
+  await request(port, 'POST', `/session/${sessionId}/element/${id}/click`, {});
+}
+
+async function element(port, sessionId, selector) {
+  const response = await request(port, 'POST', `/session/${sessionId}/element`, {
+    using: 'css selector',
+    value: selector,
+  });
+  const value = response.value ?? response;
+  const id = value[webdriverElement] ?? value.ELEMENT;
+  if (!id) {
+    throw new Error(`element ${selector} response missing element id: ${JSON.stringify(response)}`);
+  }
+  return id;
+}
+
+async function waitForText(port, sessionId, selector, expected, timeoutMs) {
+  const deadline = Date.now() + timeoutMs;
+  while (Date.now() < deadline) {
+    const text = await execute(
+      port,
+      sessionId,
+      `return document.querySelector(${JSON.stringify(selector)})?.textContent ?? "";`,
+    );
+    if (String(text).includes(expected)) return;
+    await sleep(500);
+  }
+  const body = await execute(port, sessionId, "return document.body?.innerText ?? '';");
+  throw new Error(`timed out waiting for ${selector} to contain ${expected}; body was: ${body}`);
+}
+
+async function execute(port, sessionId, script) {
+  const response = await request(port, 'POST', `/session/${sessionId}/execute/sync`, {
+    script,
+    args: [],
+  });
+  return response.value;
+}
+
+async function request(port, method, path, body) {
+  const response = await fetch(`http://127.0.0.1:${port}${path}`, {
+    method,
+    signal: AbortSignal.timeout(30_000),
+    headers: { 'content-type': 'application/json' },
+    body: body === undefined ? undefined : JSON.stringify(body),
+  });
+  const text = await response.text();
+  const json = text ? JSON.parse(text) : {};
+  if (!response.ok) {
+    throw new Error(`${method} ${path} failed ${response.status}: ${text}`);
+  }
+  if (json.value?.error) {
+    throw new Error(`${method} ${path} failed: ${JSON.stringify(json.value)}`);
+  }
+  return json;
+}
+
+async function waitForDriver(port) {
+  const deadline = Date.now() + 30_000;
+  while (Date.now() < deadline) {
+    try {
+      await request(port, 'GET', '/status');
+      return;
+    } catch {
+      await sleep(250);
+    }
+  }
+  throw new Error('timed out waiting for tauri-driver');
+}
+
+function sleep(ms) {
+  return new Promise((resolve) => setTimeout(resolve, ms));
+}
diff --git a/src/extensions/artifacts/native/moon.yml b/src/extensions/artifacts/native/moon.yml
index 4ac3d5f35..ee7518fe7 100644
--- a/src/extensions/artifacts/native/moon.yml
+++ b/src/extensions/artifacts/native/moon.yml
@@ -1,83 +1,139 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "extension-artifacts-native"
-language: "unknown"
-layer: "tool"
-stack: "systems"
-tags: ["extensions", "artifacts", "native"]
+$schema: https://moonrepo.dev/schemas/project.json
+id: extension-artifacts-native
+language: unknown
+layer: tool
+stack: systems
+tags:
+  - javascript-quality
+  - extensions
+  - artifacts
+  - native
 dependsOn:
-  - id: "artifact-packaging"
-    scope: "build"
-  - id: "extension-runtime-contract"
-    scope: "build"
-  - id: "extensions"
-    scope: "build"
-  - id: "liboliphaunt-native"
-    scope: "build"
-  - id: "source-inputs"
-    scope: "build"
-  - id: "third-party-native"
-    scope: "build"
-  - id: "third-party-shared"
-    scope: "build"
-
+  - id: extension-runtime-contract
+    scope: build
+  - id: extensions
+    scope: build
+  - id: liboliphaunt-native
+    scope: build
+  - id: source-inputs
+    scope: build
+  - id: third-party-icu
+    scope: build
+  - id: third-party-openssl
+    scope: build
 project:
-  title: "Native Extension Artifacts"
-  description: "Publishable exact-extension artifact checks for native liboliphaunt targets."
-  owner: "oliphaunt"
-
+  title: Native Extension Artifacts
+  description: Publishable exact-extension artifact checks for native liboliphaunt targets.
+  owner: oliphaunt
 tasks:
-  unit:
-    tags: ["quality", "unit"]
-    command: "bash src/extensions/artifacts/native/tools/run-observed-phase.test.sh"
+  test:
+    tags:
+      - quality
+      - unit
+    command: bash src/extensions/artifacts/native/tools/test.sh
     inputs:
-      - "/src/extensions/artifacts/native/tools/run-observed-phase.sh"
-      - "/src/extensions/artifacts/native/tools/run-observed-phase.test.sh"
+      - /src/extensions/artifacts/native/tools/run-observed-phase.sh
+      - /src/extensions/artifacts/native/tools/run-observed-phase.test.sh
+      - /src/extensions/artifacts/native/tools/*.{mts,sh}
+      - /src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts
+      - /src/extensions/artifacts/native/tools/extension-artifact-packager.mts
+      - "@group(legal-files)"
+      - "@group(release-target-contract)"
+      - "@group(package-test-metadata)"
+      - /src/extensions/contracts/*.mts
+      - /src/extensions/tools/extension-artifact-archive-policy.mts
+      - /src/extensions/tools/extension-upstream-licenses.mts
+      - /src/extensions/external/**/upstream-license-data.json
+      - /src/extensions/external/**/upstream-licenses/**/*
+      - /tools/packaging/strip-native-binaries.sh
+      - /src/extensions/artifacts/native/tools/ios-extension-registration.sh
+      - /tools/packaging/*.mts
+      - /src/extensions/generated/**/*
+      - /tools/packaging/testdata/release-fixture-utils.mts
     options:
       cache: true
       runFromWorkspaceRoot: true
   build-target:
-    tags: ["release", "artifact-builder", "ci-extension-artifacts-native"]
-    command: "bash src/extensions/artifacts/native/tools/package-release-assets.sh"
+    tags:
+      - release
+      - artifact-builder
+      - ci-extension-artifacts-native
+    command: bash src/extensions/artifacts/native/tools/package-release-assets.sh
     env:
-      OLIPHAUNT_TRACK_BUILD: "missing"
+      OLIPHAUNT_TRACK_BUILD: missing
     deps:
-      - "source-inputs:source-fetch-native-runtime"
+      - source-inputs:source-fetch-native-runtime
+      - source-inputs:source-fetch-extensions
     inputs:
+      - /.github/actions/setup-apple/**
+      - /.github/actions/setup-android/**
+      - /.github/scripts/setup-native-build-tools.sh
+      - /.prototools
+      - /tools/dev/*.toml
       - "@group(legal-files)"
       - "@group(cargo-workspace)"
-      - project: "extensions"
-        group: "build"
-      - "/src/postgres/versions/18/**/*"
-      - "/src/runtimes/liboliphaunt/licenses/**/*"
-      - project: "liboliphaunt-native"
-        group: "runtime"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "third-party-native"
-        group: "sources"
-      - "/src/extensions/artifacts/native/tools/**/*"
-      - "/tools/release/check-linux-consumer-baseline.sh"
-      - "/src/sources/tools/source-fetch-core.mjs"
-      - "/tools/release/extension-upstream-licenses.mjs"
-      - "/tools/release/linux-abi-baseline.test.mjs"
-      - project: "artifact-packaging"
-        group: "source"
-      - "/tools/release/extension-artifact-archive-policy.mjs"
-      - "/tools/release/native-extension-asset-index-contract.mjs"
-      - "/tools/release/native-runtime-payload-policy.json"
-      - "/tools/release/platform-compatibility-policy.mjs"
-      - "/tools/release/platform-compatibility-policy.test.mjs"
-      - "/tools/release/platform-binary-contract.mjs"
-      - "/tools/release/platform-binary-contract.test.mjs"
-      - "/tools/release/release-notices.mjs"
-      - "/tools/release/release-directory-safety.mjs"
-      - "/tools/release/windows-vc-runtime-closure.mjs"
+      - project: extensions
+        group: build
+      - /src/third-party/postgres/**/*
+      - "@group(upstream-licenses)"
+      - project: liboliphaunt-native
+        group: runtime
+      - project: extension-runtime-contract
+        group: contract
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - /src/extensions/artifacts/native/tools/**/*
+      - /tools/packaging/check-linux-consumer-baseline.sh
+      - /src/third-party/tools/source-fetch-core.mts
+      - /src/extensions/tools/extension-upstream-licenses.mts
+      - /tools/packaging/linux-abi-baseline.test.sh
+      - "/tools/packaging/*.{mjs,mts}"
+      - /src/extensions/tools/extension-artifact-archive-policy.mts
+      - /src/extensions/artifacts/native/tools/native-extension-asset-index-contract.mts
+      - /src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json
+      - /tools/release/platform-compatibility-policy.mts
+      - /tools/release/platform-compatibility-policy.test.mts
+      - /tools/packaging/platform-binary-contract.mts
+      - /tools/packaging/strip-native-binaries.sh
+      - /tools/packaging/platform-binary-contract.test.mts
+      - /tools/packaging/release-notices.mts
+      - /tools/packaging/release-directory-safety.mts
+      - /tools/packaging/windows-vc-runtime-closure.mts
     outputs:
-      - "/target/extensions/native/release-assets/**/*"
+      - /target/extensions/native/release-assets/**/*
     options:
       cache: false
       runFromWorkspaceRoot: true
       runInCI: true
+  rust-format-check:
+    tags:
+      - quality
+      - static
+      - format
+      - requires-rust
+    command: cargo fmt -p oliphaunt-native-extension-proof --check
+    inputs:
+      - /src/extensions/tests/native/**/*.rs
+      - /src/extensions/tests/native/Cargo.toml
+      - /clippy.toml
+      - "@group(cargo-workspace)"
+    options:
+      runFromWorkspaceRoot: true
+  rust-lint:
+    tags:
+      - quality
+      - static
+      - requires-rust
+    command: cargo clippy -p oliphaunt-native-extension-proof --all-targets --locked -- -D warnings
+    env:
+      CARGO_TARGET_DIR: target
+    inputs:
+      - /src/extensions/tests/native/**/*.rs
+      - /src/extensions/tests/native/Cargo.toml
+      - /clippy.toml
+      - "@group(cargo-workspace)"
+    options:
+      runFromWorkspaceRoot: true
diff --git a/src/extensions/artifacts/native/tools/build-windows-extensions.sh b/src/extensions/artifacts/native/tools/build-windows-extensions.sh
new file mode 100644
index 000000000..eb17ffd30
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/build-windows-extensions.sh
@@ -0,0 +1,154 @@
+#!/usr/bin/env bash
+# Sourced by the native MSVC build; native commands and logging stay in Shell.
+# shellcheck disable=SC2154 # Paths and compiler callbacks belong to the sourcing build.
+
+windows_extension_cmake() {
+  local name="$1" source="$2" prefix="$3"
+  shift 3
+  local directory="$work_root/$name-windows-build"
+  rm -rf "$directory" "$prefix"
+  logged "$name-configure.log" cmake -S "$(native_path "$source")" -B "$(native_path "$directory")" -G Ninja \
+    -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$(native_path "$prefix")" \
+    -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe \
+    -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL "$@"
+  logged "$name-install.log" cmake --build "$(native_path "$directory")" --config Release --target install
+}
+
+windows_extension_copy() {
+  local source="$1" destination="$2"
+  [ -d "$source" ] || fail "missing extension source $source"
+  rm -rf "$destination"
+  mkdir -p "$destination"
+  cp -R "$source/." "$destination/"
+  rm -rf "$destination/.git"
+}
+
+windows_extension_openssl() {
+  local prefix="$work_root/windows-dependencies/openssl" directory="$work_root/openssl-windows-build"
+  [ ! -f "$prefix/lib/libcrypto.lib" ] || return 0
+  windows_extension_copy "$external_checkout_root/openssl" "$directory"
+  rm -rf "$prefix"
+  (
+    cd "$directory"
+    logged openssl-configure.log perl Configure VC-WIN64A no-shared no-tests no-apps no-module no-asm \
+      "--prefix=$(native_path "$prefix")" "--openssldir=$(native_path "$prefix/ssl")"
+    logged openssl-build.log native nmake.exe /nologo build_generated libcrypto.lib
+    logged openssl-install.log native nmake.exe /nologo install_sw
+  )
+  [ -d "$prefix/include/openssl" ] && [ -f "$prefix/lib/libcrypto.lib" ] || fail 'OpenSSL install is incomplete'
+}
+
+windows_extension_postgis_dependencies() {
+  local dependency_root="$work_root/windows-dependencies/postgis" prefix directory source
+  prefix="$dependency_root/sqlite"
+  if [ ! -f "$prefix/lib/sqlite3.lib" ] || [ ! -f "$prefix/bin/sqlite3.exe" ]; then
+    directory="$work_root/sqlite-windows-build"
+    windows_extension_copy "$external_checkout_root/sqlite" "$directory"
+    rm -rf "$prefix"
+    (
+      cd "$directory"
+      logged sqlite-build.log native nmake.exe /nologo /f Makefile.msc libsqlite3.lib sqlite3.exe \
+        USE_CRT_DLL=1 NO_TCL=1 LDFLAGS= 'OPTS=-DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION'
+    )
+    mkdir -p "$prefix"/{include,lib,bin}
+    cp "$directory/libsqlite3.lib" "$prefix/lib/sqlite3.lib"
+    cp "$directory/sqlite3.exe" "$prefix/bin/"
+    cp "$directory/"{sqlite3.h,sqlite3ext.h} "$prefix/include/"
+  fi
+  prefix="$dependency_root/json-c"
+  if ! (first_file "$prefix" json-c.lib json-c-static.lib) >/dev/null 2>&1; then
+    windows_extension_cmake json-c "$external_checkout_root/json-c" "$prefix" \
+      -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_LIBS=ON \
+      -DBUILD_APPS=OFF -DBUILD_TESTING=OFF -DDISABLE_WERROR=ON
+  fi
+  prefix="$dependency_root/geos"
+  if ! (first_file "$prefix" geos_c.lib) >/dev/null 2>&1; then
+    windows_extension_cmake geos "$external_checkout_root/geos" "$prefix" \
+      -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DBUILD_BENCHMARKS=OFF -DBUILD_GEOSOP=OFF -DGEOS_BUILD_DEVELOPER=OFF
+  fi
+  prefix="$dependency_root/libxml2"
+  if ! (first_file "$prefix" libxml2s.lib libxml2.lib xml2.lib) >/dev/null 2>&1; then
+    windows_extension_cmake libxml2 "$external_checkout_root/libxml2" "$prefix" \
+      -DBUILD_SHARED_LIBS=OFF -DLIBXML2_WITH_PROGRAMS=OFF -DLIBXML2_WITH_TESTS=OFF \
+      -DLIBXML2_WITH_PYTHON=OFF -DLIBXML2_WITH_THREADS=OFF -DLIBXML2_WITH_MODULES=OFF \
+      -DLIBXML2_WITH_ICONV=OFF -DLIBXML2_WITH_ZLIB=OFF -DLIBXML2_WITH_LZMA=OFF -DLIBXML2_WITH_HTTP=OFF
+  fi
+  prefix="$dependency_root/proj"
+  if ! (first_file "$prefix" proj.lib libproj.lib) >/dev/null 2>&1 || [ ! -f "$prefix/share/proj/proj.db" ]; then
+    windows_extension_cmake proj "$external_checkout_root/proj" "$prefix" \
+      -DBUILD_SHARED_LIBS=OFF "-DSQLite3_INCLUDE_DIR=$(native_path "$dependency_root/sqlite/include")" \
+      "-DSQLite3_LIBRARY=$(native_path "$dependency_root/sqlite/lib/sqlite3.lib")" \
+      "-DEXE_SQLITE3=$(native_path "$dependency_root/sqlite/bin/sqlite3.exe")" \
+      -DENABLE_TIFF=OFF -DENABLE_CURL=OFF -DENABLE_EMSCRIPTEN_FETCH=OFF -DHAVE_LIBDL=OFF \
+      -DBUILD_APPS=OFF -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF \
+      -DEMBED_RESOURCE_FILES=ON -DUSE_ONLY_EMBEDDED_RESOURCE_FILES=ON
+    if [ ! -f "$prefix/share/proj/proj.db" ]; then
+      mkdir -p "$prefix/share/proj"
+      cp "$work_root/proj-windows-build/data/proj.db" "$prefix/share/proj/proj.db"
+    fi
+  fi
+}
+
+windows_extension_generate() {
+  local phase="$1"
+  shift
+  bun "$repo_root/src/extensions/artifacts/native/tools/windows-extension-sources.mts" "$phase" \
+    --repo "$repo_root" --work "$work_root" --postgres "$build_dir" --install "$install_dir" "$@"
+}
+
+windows_extension_prepare() {
+  [ "$build_extensions" != 0 ] || return 0
+  local name
+  if selected pgcrypto; then
+    windows_extension_openssl
+    windows_extension_generate simple --extension pgcrypto
+  fi
+  for name in uuid-ossp pg_hashids pg_ivm pg_uuidv7 pg_textsearch vector; do
+    if selected "$name"; then windows_extension_generate simple --extension "$name"; fi
+  done
+  if selected postgis; then
+    (
+      export SOURCE_DATE_EPOCH
+      source "$repo_root/src/extensions/external/postgis/tools/reproducible-time.sh"
+      SOURCE_DATE_EPOCH="$(oliphaunt_postgis_source_date_epoch "$repo_root")"
+      windows_extension_postgis_dependencies
+      windows_extension_generate postgis-config
+      source "$repo_root/src/extensions/external/postgis/tools/windows/build-sql.sh"
+      windows_postgis_build_sql
+      windows_extension_postgis_flatgeobuf
+      windows_extension_generate postgis-meson
+    )
+  fi
+}
+
+windows_extension_postgis_flatgeobuf() {
+  local postgis="$build_dir/contrib/oliphaunt_external/postgis"
+  local prefix="$work_root/windows-dependencies/postgis/flatgeobuf"
+  [ ! -f "$prefix/lib/flatgeobuf.lib" ] || return 0
+  local directory="$work_root/postgis-flatgeobuf-windows-build" source object
+  local objects=()
+  rm -rf "$directory" "$prefix"
+  mkdir -p "$directory" "$prefix/lib"
+  for source in flatgeobuf_c geometrywriter geometryreader packedrtree; do
+    object="$directory/$source.obj"
+    logged "flatgeobuf-$source.log" native cl.exe /nologo /O2 /MD /EHsc /D_CRT_SECURE_NO_WARNINGS /Dflatbuffers=postgis_flatbuffers \
+      "/FI$(native_path "$postgis/oliphaunt_flatgeobuf_windows_compat.h")" \
+      "/I$(native_path "$postgis/liblwgeom")" "/I$(native_path "$postgis/deps/flatgeobuf")" \
+      "/I$(native_path "$postgis/deps/flatgeobuf/include")" "/I$(native_path "$work_root/windows-dependencies/postgis/proj/include")" \
+      /c "$(native_path "$postgis/deps/flatgeobuf/$source.cpp")" "/Fo$(native_path "$object")"
+    objects+=("$(native_path "$object")")
+  done
+  logged flatgeobuf-library.log native lib.exe /nologo "/OUT:$(native_path "$prefix/lib/flatgeobuf.lib")" "${objects[@]}"
+}
+
+windows_extension_install() {
+  selected pgtap || return 0
+  local directory="$work_root/pgtap-windows" destination="$install_dir/share/postgresql/extension"
+  windows_extension_generate pgtap
+  perl "$directory/compat/gencore" 0 "$directory/sql/pgtap-static.sql" >"$directory/sql/pgtap-core.sql"
+  perl "$directory/compat/gencore" 1 "$directory/sql/pgtap-static.sql" >"$directory/sql/pgtap-schema.sql"
+  perl -e 'for (grep { /^CREATE /} reverse <>) { chomp; s/CREATE (OR REPLACE )?/DROP /; s/DROP (FUNCTION|VIEW|TYPE) /DROP $1 IF EXISTS /; s/ (DEFAULT|=)[ ]+[a-zA-Z0-9]+//g; print "$_;\n" }' "$directory/sql/pgtap.sql" >"$directory/sql/uninstall_pgtap.sql"
+  windows_extension_generate pgtap-install
+  mkdir -p "$destination"
+  cp "$directory/pgtap.control" "$directory/sql/"pgtap*.sql "$directory/sql/uninstall_pgtap.sql" "$destination/"
+}
diff --git a/src/extensions/artifacts/native/tools/create-artifact.sh b/src/extensions/artifacts/native/tools/create-artifact.sh
new file mode 100755
index 000000000..f8b5c61ff
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/create-artifact.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../../.." && pwd)"
+cd "$root"
+packager=src/extensions/artifacts/native/tools/extension-artifact-packager.mts
+stage_root=target/extensions/native/release-stage/local
+args=("$@")
+for ((index=0; index<${#args[@]}; index++)); do
+  case "${args[index]}" in
+    --stage-root) stage_root="${args[index+1]:?--stage-root requires a value}" ;;
+    --stage-root=*) stage_root="${args[index]#*=}" ;;
+  esac
+done
+mkdir -p "$stage_root"
+stage="$(mktemp -d "$stage_root/.artifact.XXXXXXXX")"
+trap 'rm -rf "$stage"' EXIT
+bun "$packager" stage-artifact "$stage/artifact" "$@"
+target="$(awk -F= '$1 == "nativeTarget" {print $2}' "$stage/artifact/manifest.properties")"
+strip_args=()
+if [ -n "$target" ]; then strip_args=(--target "$target"); fi
+bash tools/packaging/strip-native-binaries.sh "${strip_args[@]}" "$stage/artifact"
+bun "$packager" finish-artifact "$stage/artifact" "$@"
diff --git a/src/extensions/artifacts/native/tools/create-artifact.test.mts b/src/extensions/artifacts/native/tools/create-artifact.test.mts
new file mode 100644
index 000000000..7fc1ace03
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/create-artifact.test.mts
@@ -0,0 +1,79 @@
+import assert from 'node:assert/strict';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import { elfFixture } from '../../../../../tools/packaging/testdata/release-fixture-utils.mts';
+import { validateExtensionArtifactArchive } from '../../packages/tools/extension-artifact-inventory.mts';
+
+const [phase, root, kind] = process.argv.slice(2);
+const metadata = {
+  sqlName: 'pgtap',
+  createsExtension: true,
+  nativeModuleStem: null,
+  dependencies: [],
+  dataFiles: [],
+  extensionSqlFileNames: ['uninstall_pgtap.sql'],
+  extensionSqlFilePrefixes: ['pgtap-core', 'pgtap-schema'],
+  sharedPreloadLibraries: [],
+};
+const dataFiles = [
+  'oliphaunt-streaming/a.bin',
+  'oliphaunt-streaming/b.bin',
+  'oliphaunt-streaming/c.bin',
+];
+if (phase === 'prepare-binaries') {
+  for (const [directory, requiredVersions] of [
+    ['runtime/lib/postgresql', []],
+    ['embedded', ['GLIBC_2.17']],
+  ]) {
+    await fs.mkdir(path.join(root, directory), { recursive: true });
+    await fs.writeFile(
+      path.join(root, directory, 'auto_explain.so'),
+      elfFixture({ machine: 62, requiredVersions }),
+      { mode: 0o755 },
+    );
+  }
+} else if (phase === 'prepare-stream') {
+  for (const [index, file] of dataFiles.entries()) {
+    const destination = path.join(root, 'runtime/share/postgresql', file);
+    await fs.mkdir(path.dirname(destination), { recursive: true });
+    await fs.writeFile(destination, Buffer.alloc(24 * 1024 * 1024, index + 1));
+  }
+} else if (phase === 'verify') {
+  const selected =
+    kind === 'module'
+      ? {
+          ...metadata,
+          sqlName: 'auto_explain',
+          createsExtension: false,
+          nativeModuleStem: 'auto_explain',
+          extensionSqlFileNames: [],
+          extensionSqlFilePrefixes: [],
+        }
+      : { ...metadata, dataFiles: kind === 'stream' ? dataFiles : [] };
+  const file = path.join(root, kind + '.tar.gz');
+  const result = validateExtensionArtifactArchive({
+    file,
+    metadata: selected,
+    target: 'linux-x64-gnu',
+    nativeRuntimeVersion: '1.2.3',
+    label: 'actual native producer',
+  });
+  if (kind === 'module') {
+    const normal = result.entries.get('files/lib/postgresql/auto_explain.so');
+    const embedded = result.entries.get('files/lib/modules/auto_explain.so');
+    assert.ok(normal);
+    assert.ok(embedded);
+    assert.notEqual(normal.sha256, embedded.sha256);
+  } else if (kind === 'stream') {
+    assert.ok(result.runtimeFiles.reduce((sum, row) => sum + row.bytes, 0) > 64 * 1024 * 1024);
+  } else if (kind === 'chain') {
+    for (const name of ['pgtap--1.3.3.sql', 'pgtap--1.3.3--1.3.4.sql', 'pgtap--1.3.4--1.3.5.sql'])
+      assert.ok(result.entries.has('files/share/postgresql/extension/' + name));
+  } else {
+    assert.equal((await fs.readFile(file)).subarray(0, 10).toString('hex'), '1f8b0800000000000003');
+    for (const name of ['pgtap-core-evil.control', 'foreign.control'])
+      assert.equal(result.entries.has('files/share/postgresql/extension/' + name), false);
+  }
+} else if (phase !== undefined) {
+  throw Error('Unknown native artifact fixture phase');
+}
diff --git a/src/extensions/artifacts/native/tools/create-artifact.test.sh b/src/extensions/artifacts/native/tools/create-artifact.test.sh
new file mode 100644
index 000000000..d215f99d6
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/create-artifact.test.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+fixture=src/extensions/artifacts/native/tools/create-artifact.test.mts
+producer=src/extensions/artifacts/native/tools/create-artifact.sh
+sql="$scratch/runtime/share/postgresql/extension"
+mkdir -p "$sql"
+printf "default_version = '1.3.5'\n" > "$sql/pgtap.control"
+for name in pgtap--1.3.5.sql uninstall_pgtap.sql pgtap-core--fixture.sql pgtap-core-evil.control foreign.control; do printf fixture > "$sql/$name"; done
+common=(--runtime "$scratch/runtime" --native-target linux-x64-gnu --native-runtime-product liboliphaunt-native --native-runtime-version 1.2.3 --format tar-gz --stage-root "$scratch/stage" --force)
+produce() { bash "$producer" "${common[@]}" --sql-name pgtap --output "$scratch/$1.tar.gz" "${@:2}"; }
+reject() {
+  local pattern="$1"; shift
+  if "$@" > "$scratch/rejected.log" 2>&1; then echo 'Invalid artifact was accepted' >&2; exit 1; fi
+  grep -Eq -- "$pattern" "$scratch/rejected.log"
+}
+produce base
+bun "$fixture" verify "$scratch" base
+printf "default_version = '1.3.4'\n" > "$sql/pgtap.control"
+reject 'does not match source-owned catalog version' produce skew
+printf "default_version = '1.3.5'\n" > "$sql/pgtap.control"
+rm "$sql/pgtap--1.3.5.sql"
+for name in pgtap--1.3.3.sql pgtap--1.3.3--1.3.4.sql pgtap--1.3.4--1.3.5.sql; do printf fixture > "$sql/$name"; done
+produce chain
+bun "$fixture" verify "$scratch" chain
+rm "$sql/pgtap--1.3.4--1.3.5.sql"
+reject 'has no canonical installation script or update path' produce disconnected
+rm "$sql/pgtap--1.3.3.sql" "$sql/pgtap--1.3.3--1.3.4.sql"
+printf fixture > "$sql/pgtap--1.3.4--1.3.5.sql"
+reject 'control file and canonical base install SQL' produce ancillary
+rm "$sql/pgtap--1.3.4--1.3.5.sql"
+printf fixture > "$sql/pgtap--release.sql"
+reject 'control file and canonical base install SQL' produce letter
+rm "$sql/pgtap--release.sql"
+printf fixture > "$sql/pgtap--1.3.5.sql"
+bun "$fixture" prepare-stream "$scratch"
+produce stream --data-files oliphaunt-streaming/a.bin,oliphaunt-streaming/b.bin,oliphaunt-streaming/c.bin
+bun "$fixture" verify "$scratch" stream
+bun "$fixture" prepare-binaries "$scratch"
+printf '#!/usr/bin/env sh\nexit 0\n' > "$scratch/strip"
+chmod +x "$scratch/strip"
+export OLIPHAUNT_ELF_STRIP="$scratch/strip"
+module=(--sql-name auto_explain --creates-extension false --native-module-stem auto_explain --native-module-file auto_explain.so)
+bash "$producer" "${common[@]}" "${module[@]}" --embedded-module-root "$scratch/embedded" --output "$scratch/module.tar.gz"
+bun "$fixture" verify "$scratch" module
+reject 'require --embedded-module-root' bash "$producer" "${common[@]}" "${module[@]}" --output "$scratch/missing.tar.gz"
+reject '--embedded-module-root is only valid' produce unexpected --embedded-module-root "$scratch/embedded"
+echo 'Actual producer SQL closure, source identity, module profiles and streaming checks passed'
diff --git a/src/extensions/artifacts/native/tools/extension-artifact-packager.mjs b/src/extensions/artifacts/native/tools/extension-artifact-packager.mjs
deleted file mode 100755
index b23977225..000000000
--- a/src/extensions/artifacts/native/tools/extension-artifact-packager.mjs
+++ /dev/null
@@ -1,1202 +0,0 @@
-#!/usr/bin/env bun
-import { spawnSync } from 'node:child_process';
-import { fileURLToPath } from 'node:url';
-import path from 'node:path';
-import { promises as fs } from 'node:fs';
-
-import { validateWindowsExtensionArtifactBinaryContract } from './stage-windows-binary-contract.mjs';
-import { inspectPlatformBinaryTree } from '../../../../../tools/release/platform-binary-contract.mjs';
-import {
-  validateExtensionArtifactArchivePlan,
-  validateExtensionArtifactCompressedBytes,
-} from '../../../../../tools/release/extension-artifact-archive-policy.mjs';
-import {
-  extensionControlDefaultVersion,
-  isCanonicalExtensionInstallSql,
-  validateExtensionInstallSqlReachability,
-} from '../../../../../tools/release/extension-artifact-inventory.mjs';
-import {
-  assertReleaseNoticesInArchive,
-  stageReleaseNotices,
-} from '../../../../../tools/release/release-notices.mjs';
-import { stageExtensionUpstreamLicenses } from '../../../../../tools/release/extension-upstream-licenses.mjs';
-import { canonicalGzipSync } from '../../../../../src/shared/artifact-packaging/portable-archive.mjs';
-import { extensionSqlNames } from '../../../../../tools/release/release-artifact-targets.mjs';
-import {
-  loadNativeComponentContract,
-  resolveNativeComponentClosure,
-} from '../../../tools/native-component-contract.mjs';
-
-const scriptDir = path.dirname(fileURLToPath(import.meta.url));
-const root = path.resolve(scriptDir, '../../../../..');
-
-const CATALOG_PATH = path.join(root, 'src/extensions/generated/extensions.catalog.json');
-const CONTRIB_RECIPE_PATH = path.join(root, 'src/extensions/contrib/postgres18.toml');
-const RELEASE_CONFIG_PATH = path.join(root, 'release-please-config.json');
-const DESKTOP_NATIVE_TARGETS = new Set([
-  'linux-x64-gnu',
-  'linux-arm64-gnu',
-  'macos-arm64',
-  'windows-x64-msvc',
-]);
-const MOBILE_NATIVE_TARGETS = new Set([
-  'ios-xcframework',
-  'android-arm64-v8a',
-  'android-x86_64',
-]);
-const nativeComponentContract = loadNativeComponentContract();
-
-function fail(message) {
-  throw new Error(message);
-}
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-async function readText(relativeOrAbsolute) {
-  return fs.readFile(path.isAbsolute(relativeOrAbsolute) ? relativeOrAbsolute : path.join(root, relativeOrAbsolute), 'utf8');
-}
-
-async function readJson(relativeOrAbsolute) {
-  return JSON.parse(await readText(relativeOrAbsolute));
-}
-
-async function readToml(relativeOrAbsolute) {
-  return Bun.TOML.parse(await readText(relativeOrAbsolute));
-}
-
-async function exists(file) {
-  try {
-    await fs.access(file);
-    return true;
-  } catch {
-    return false;
-  }
-}
-
-async function isFile(file) {
-  try {
-    return (await fs.stat(file)).isFile();
-  } catch {
-    return false;
-  }
-}
-
-async function isDirectory(file) {
-  try {
-    return (await fs.stat(file)).isDirectory();
-  } catch {
-    return false;
-  }
-}
-
-function stringList(value) {
-  if (!Array.isArray(value)) {
-    return [];
-  }
-  return value.filter((item) => typeof item === 'string' && item.length > 0).sort();
-}
-
-function splitCsv(value) {
-  if (value === undefined || value === null || value === '' || value === '-') {
-    return [];
-  }
-  return String(value)
-    .split(',')
-    .map((item) => item.trim())
-    .filter(Boolean);
-}
-
-function sortedDeduped(values) {
-  return [...new Set(values.filter((item) => item !== undefined && item !== null && String(item).length > 0).map(String))].sort();
-}
-
-function dashIfEmpty(value) {
-  if (Array.isArray(value)) {
-    return value.length === 0 ? '-' : value.join(',');
-  }
-  return value === undefined || value === null || value === '' ? '-' : String(value);
-}
-
-function yesNo(value) {
-  return value ? 'yes' : 'no';
-}
-
-function validatePortableId(value, label) {
-  if (!/^[A-Za-z0-9._-]{1,128}$/.test(value)) {
-    fail(`${label} '${value}' must contain 1 to 128 ASCII letters, digits, '.', '_' or '-'`);
-  }
-}
-
-function validateCIdentifier(value, label) {
-  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
-    fail(`${label} '${value}' must be a portable C identifier`);
-  }
-}
-
-function validateRelativeArtifactPath(value, label) {
-  if (!value || path.isAbsolute(value)) {
-    fail(`${label} '${value}' must be a relative path`);
-  }
-  const parts = value.split(/[\\/]+/);
-  if (parts.some((part) => part === '' || part === '.' || part === '..')) {
-    fail(`${label} '${value}' must not contain '.', '..', or empty path components`);
-  }
-  return parts.join('/');
-}
-
-function nativeModuleStem(extension) {
-  const moduleFile = extension['native-module-file'] ?? extension['module-file'];
-  if (typeof moduleFile !== 'string' || moduleFile.length === 0) {
-    return '';
-  }
-  for (const suffix of ['.so', '.dylib', '.dll']) {
-    if (moduleFile.endsWith(suffix)) {
-      return moduleFile.slice(0, -suffix.length);
-    }
-  }
-  return moduleFile;
-}
-
-function sharedPreloadLibraries(extension) {
-  const startupConfig = extension.lifecycle?.['startup-config'] ?? [];
-  const libraries = [];
-  for (const assignment of startupConfig) {
-    if (typeof assignment !== 'string') {
-      continue;
-    }
-    const separator = assignment.indexOf('=');
-    if (separator <= 0) {
-      continue;
-    }
-    if (assignment.slice(0, separator) === 'shared_preload_libraries') {
-      libraries.push(...splitCsv(assignment.slice(separator + 1)));
-    }
-  }
-  return sortedDeduped(libraries);
-}
-
-async function externalRecipe(sqlName) {
-  const recipePath = path.join(root, 'src/extensions/external', sqlName, 'recipe.toml');
-  if (!(await isFile(recipePath))) {
-    return null;
-  }
-  return readToml(recipePath);
-}
-
-async function extensionDataFiles(extension, contribRows) {
-  const sqlName = extension['sql-name'] ?? extension.id;
-  const recipe = await externalRecipe(sqlName);
-  if (recipe !== null) {
-    return stringList(recipe.artifacts?.data_files);
-  }
-  const row = contribRows.find((item) => item?.['sql-name'] === sqlName);
-  return stringList(row?.['data-files']);
-}
-
-function runtimeShareDataFiles(dataFiles) {
-  const prefix = 'share/postgresql/';
-  return dataFiles.map((item) => (item.startsWith(prefix) ? item.slice(prefix.length) : item)).sort();
-}
-
-async function extensionArtifactList(sqlName, field) {
-  const recipe = await externalRecipe(sqlName);
-  if (recipe === null) {
-    return [];
-  }
-  return stringList(recipe.artifacts?.[field]);
-}
-
-export function selectCatalogExtensions(extensions) {
-  if (!Array.isArray(extensions)) {
-    fail('generated extension catalog must define an extensions array');
-  }
-  const seen = new Set();
-  const normalized = [];
-  for (const extension of extensions) {
-    if (extension === null || Array.isArray(extension) || typeof extension !== 'object') {
-      fail('generated extension catalog rows must be objects');
-    }
-    const sqlName = extension['sql-name'] ?? extension.id;
-    if (typeof sqlName !== 'string') {
-      fail('generated extension catalog row must define a SQL name');
-    }
-    validatePortableId(sqlName, 'generated extension catalog SQL name');
-    if (seen.has(sqlName)) {
-      fail(`generated extension catalog repeats SQL name '${sqlName}'`);
-    }
-    seen.add(sqlName);
-    normalized.push({ extension, sqlName });
-  }
-  const supportedSqlNames = new Set(normalized.map(({ sqlName }) => sqlName));
-  return normalized.map(({ extension, sqlName }) => ({
-    dependencies: stringList(extension.dependencies).filter(dependency => supportedSqlNames.has(dependency)),
-    extension,
-    sqlName,
-  }));
-}
-
-export async function catalogRows() {
-  const catalog = await readJson(CATALOG_PATH);
-  const contrib = await readToml(CONTRIB_RECIPE_PATH);
-  const contribRows = Array.isArray(contrib.extensions) ? contrib.extensions : [];
-  const extensions = Array.isArray(catalog.extensions) ? catalog.extensions : [];
-  const rows = [];
-  for (const { dependencies, extension, sqlName } of selectCatalogExtensions(extensions)) {
-    const dataFiles = runtimeShareDataFiles(await extensionDataFiles(extension, contribRows));
-    const stem = nativeModuleStem(extension);
-    rows.push({
-      sqlName,
-      pgMajor: '18',
-      createsExtension: Boolean(extension.lifecycle?.['create-extension']),
-      stem,
-      dependencies,
-      sharedPreload: sharedPreloadLibraries(extension),
-      desktopPrebuilt: true,
-      mobilePrebuilt: true,
-      mobileStaticRequired: stem.length > 0,
-      mobileStaticTargets: [],
-      dataFiles,
-      artifact: 'first-party',
-    });
-  }
-  rows.sort((left, right) => compareText(left.sqlName, right.sqlName));
-  return rows;
-}
-
-async function catalogDefaultVersion(sqlName) {
-  const catalog = await readJson(CATALOG_PATH);
-  const matches = (Array.isArray(catalog.extensions) ? catalog.extensions : [])
-    .filter((extension) => (extension['sql-name'] ?? extension.id) === sqlName);
-  if (matches.length !== 1) {
-    fail(`generated extension catalog must contain exactly one row for '${sqlName}'`);
-  }
-  const version = matches[0].control?.['default-version'];
-  if (typeof version !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(version) || version.includes('--')) {
-    fail(`generated extension catalog has no literal control.default-version for '${sqlName}'`);
-  }
-  return version;
-}
-
-async function listCatalog(args = []) {
-  if (args.length > 0) fail('list-catalog does not accept arguments');
-  const header = [
-    'sql_name',
-    'pg_major',
-    'creates_extension',
-    'native_module_stem',
-    'dependencies',
-    'shared_preload',
-    'desktop_prebuilt',
-    'mobile_prebuilt',
-    'mobile_static_registry_required',
-    'mobile_static_archive_targets',
-    'data_files',
-    'artifact',
-  ];
-  console.log(header.join('\t'));
-  for (const row of await catalogRows()) {
-    console.log(
-      [
-        row.sqlName,
-        row.pgMajor,
-        yesNo(row.createsExtension),
-        dashIfEmpty(row.stem),
-        dashIfEmpty(row.dependencies),
-        dashIfEmpty(row.sharedPreload),
-        yesNo(row.desktopPrebuilt),
-        yesNo(row.mobilePrebuilt),
-        yesNo(row.mobileStaticRequired),
-        dashIfEmpty(row.mobileStaticTargets),
-        dashIfEmpty(row.dataFiles),
-        row.artifact,
-      ].join('\t'),
-    );
-  }
-}
-
-async function releasePackageByProduct(product) {
-  const releaseConfig = await readJson(RELEASE_CONFIG_PATH);
-  const packages = releaseConfig.packages ?? {};
-  for (const [packagePath, config] of Object.entries(packages)) {
-    if (config?.component === product) {
-      return { packagePath, config };
-    }
-  }
-  fail(`unknown release product '${product}'`);
-}
-
-async function selectedSqlNames(productsCsv) {
-  const products = sortedDeduped(splitCsv(productsCsv));
-  if (products.length === 0) {
-    fail('no exact-extension products were selected');
-  }
-  const sqlNames = [];
-  for (const product of products) {
-    sqlNames.push(...extensionSqlNames(product, 'extension-artifact-packager.mjs'));
-  }
-  console.log(sortedDeduped(sqlNames).join(','));
-}
-
-function parseCargoVersion(text) {
-  let inPackage = false;
-  for (const rawLine of text.split('\n')) {
-    const line = rawLine.trim();
-    if (line === '[package]') {
-      inPackage = true;
-      continue;
-    }
-    if (inPackage && line.startsWith('[')) {
-      break;
-    }
-    if (inPackage) {
-      const match = /^version\s*=\s*"([^"]+)"/.exec(line);
-      if (match) {
-        return match[1];
-      }
-    }
-  }
-  return '';
-}
-
-function parseJsonPath(text, dotted) {
-  let value = JSON.parse(text);
-  for (const key of dotted.split('.')) {
-    if (value === null || typeof value !== 'object' || !(key in value)) {
-      return '';
-    }
-    value = value[key];
-  }
-  return String(value);
-}
-
-async function productVersion(product) {
-  const { packagePath, config } = await releasePackageByProduct(product);
-  const releaseType = config['release-type'];
-  const relativeVersionFile =
-    typeof config['version-file'] === 'string' && config['version-file'].length > 0
-      ? config['version-file']
-      : releaseType === 'rust'
-        ? 'Cargo.toml'
-        : releaseType === 'node' || releaseType === 'expo'
-          ? 'package.json'
-          : null;
-  if (relativeVersionFile === null) {
-    fail(`${product} release-please config must declare version-file for release type '${releaseType}'`);
-  }
-  const versionFile = path.join(root, packagePath, relativeVersionFile);
-  const text = await readText(versionFile);
-  const parser =
-    path.basename(versionFile) === 'Cargo.toml'
-      ? 'cargo'
-      : path.basename(versionFile) === 'package.json'
-        ? 'json:version'
-        : 'raw';
-  const version = parser === 'cargo' ? parseCargoVersion(text) : parser.startsWith('json:') ? parseJsonPath(text, parser.slice(5)) : text.trim();
-  if (!/^[0-9]+[.][0-9]+[.][0-9]+(?:[-+][0-9A-Za-z][0-9A-Za-z.-]*)?$/.test(version)) {
-    fail(`${product} version is not semver-like: '${version}'`);
-  }
-  console.log(version);
-}
-
-function parseArgs(argv) {
-  const args = {
-    dependencies: [],
-    dataFiles: [],
-    sharedPreloadLibraries: [],
-    mobileStaticArchives: [],
-    mobileStaticDependencyArchives: [],
-    staticSymbolAliases: [],
-    createsExtension: true,
-    mobilePrebuilt: false,
-    format: 'directory',
-    force: false,
-  };
-  for (let index = 0; index < argv.length; index += 1) {
-    let arg = argv[index];
-    let value = null;
-    const equals = arg.indexOf('=');
-    if (arg.startsWith('--') && equals > 0) {
-      value = arg.slice(equals + 1);
-      arg = arg.slice(0, equals);
-    }
-    const nextValue = () => {
-      if (value !== null) {
-        return value;
-      }
-      index += 1;
-      if (index >= argv.length) {
-        fail(`${arg} requires a value`);
-      }
-      return argv[index];
-    };
-    switch (arg) {
-      case '--force':
-        args.force = true;
-        break;
-      case '--no-create-extension':
-        args.createsExtension = false;
-        break;
-      case '--mobile-prebuilt':
-        args.mobilePrebuilt = value === null ? true : parseBoolean(nextValue(), arg);
-        break;
-      case '--no-mobile-prebuilt':
-        args.mobilePrebuilt = false;
-        break;
-      case '--runtime':
-        args.runtime = nextValue();
-        break;
-      case '--embedded-module-root':
-        args.embeddedModuleRoot = nextValue();
-        break;
-      case '--sql-name':
-        args.sqlName = nextValue();
-        break;
-      case '--creates-extension':
-        args.createsExtension = parseBoolean(nextValue(), arg);
-        break;
-      case '--target':
-      case '--native-target':
-        args.nativeTarget = nextValue();
-        break;
-      case '--output':
-      case '-o':
-        args.output = nextValue();
-        break;
-      case '--stage-root':
-        args.stageRoot = nextValue();
-        break;
-      case '--format':
-        args.format = nextValue();
-        break;
-      case '--native-module-stem':
-        args.nativeModuleStem = nextValue();
-        break;
-      case '--native-module-file':
-        args.nativeModuleFile = nextValue();
-        break;
-      case '--native-runtime-product':
-        args.nativeRuntimeProduct = nextValue();
-        break;
-      case '--native-runtime-version':
-        args.nativeRuntimeVersion = nextValue();
-        break;
-      case '--dependency':
-      case '--dependencies':
-        args.dependencies.push(...splitCsv(nextValue()));
-        break;
-      case '--data-file':
-      case '--data-files':
-        args.dataFiles.push(...splitCsv(nextValue()).map((item) => validateRelativeArtifactPath(item, 'data file')));
-        break;
-      case '--shared-preload-library':
-      case '--shared-preload-libraries':
-        args.sharedPreloadLibraries.push(...splitCsv(nextValue()));
-        break;
-      case '--mobile-static-archive':
-      case '--mobile-static-archives':
-        args.mobileStaticArchives.push(...splitCsv(nextValue()).map(parseMobileStaticArchive));
-        break;
-      case '--mobile-static-dependency-archive':
-      case '--mobile-static-dependency-archives':
-        args.mobileStaticDependencyArchives.push(...splitCsv(nextValue()).map(parseMobileStaticDependencyArchive));
-        break;
-      case '--static-symbol-prefix':
-        args.staticSymbolPrefix = nextValue();
-        break;
-      case '--static-symbol-alias':
-      case '--static-symbol-aliases':
-        args.staticSymbolAliases.push(...splitCsv(nextValue()).map(parseStaticSymbolAlias));
-        break;
-      default:
-        fail(`unknown argument '${arg}'`);
-    }
-  }
-  return args;
-}
-
-function parseBoolean(value, label) {
-  if (['true', 'yes', '1'].includes(value)) {
-    return true;
-  }
-  if (['false', 'no', '0'].includes(value)) {
-    return false;
-  }
-  fail(`${label} expected true/false, got '${value}'`);
-}
-
-function parseMobileStaticArchive(value) {
-  const separator = value.includes('=') ? value.indexOf('=') : value.indexOf(':');
-  if (separator <= 0) {
-    fail('--mobile-static-archive values must use : or =');
-  }
-  const target = value.slice(0, separator).trim();
-  const archive = value.slice(separator + 1).trim();
-  if (target.length === 0 || archive.length === 0) {
-    fail('--mobile-static-archive values must include both target and archive path');
-  }
-  return { target, archive };
-}
-
-function parseMobileStaticDependencyArchive(value) {
-  if (value.includes('=')) {
-    const [left, archive] = value.split(/=(.*)/s);
-    const [target, name] = left.split(':');
-    if (!target || !name || !archive) {
-      fail('--mobile-static-dependency-archive values must use :: or :=');
-    }
-    return { target: target.trim(), name: name.trim(), archive: archive.trim() };
-  }
-  const parts = value.split(':');
-  if (parts.length < 3) {
-    fail('--mobile-static-dependency-archive values must use :: or :=');
-  }
-  const target = parts.shift().trim();
-  const name = parts.shift().trim();
-  const archive = parts.join(':').trim();
-  if (!target || !name || !archive) {
-    fail('--mobile-static-dependency-archive values must include target, name, and archive path');
-  }
-  return { target, name, archive };
-}
-
-function parseStaticSymbolAlias(value) {
-  const separator = value.includes('=') ? value.indexOf('=') : value.indexOf(':');
-  if (separator <= 0) {
-    fail('--static-symbol-alias values must use : or =');
-  }
-  const sqlSymbol = value.slice(0, separator).trim();
-  const linkedSymbol = value.slice(separator + 1).trim();
-  if (sqlSymbol.length === 0 || linkedSymbol.length === 0) {
-    fail('--static-symbol-alias values must include both SQL and linked C symbols');
-  }
-  return { sqlSymbol, linkedSymbol };
-}
-
-async function validateArtifactArgs(args) {
-  for (const [value, label] of [
-    [args.sqlName, 'prebuilt extension sqlName'],
-    [args.nativeModuleStem, 'prebuilt extension native module stem'],
-    [args.nativeModuleFile, 'prebuilt extension native module file'],
-    [args.nativeTarget, 'prebuilt extension native target'],
-  ]) {
-    if (value !== undefined) {
-      validatePortableId(value, label);
-    }
-  }
-  if (args.output === undefined) {
-    fail('missing required --output ');
-  }
-  if (args.runtime === undefined) {
-    fail('missing required --runtime ');
-  }
-  if (args.sqlName === undefined) {
-    fail('missing required --sql-name ');
-  }
-  if (args.nativeRuntimeProduct !== 'liboliphaunt-native') {
-    fail('prebuilt extension artifact --native-runtime-product must be liboliphaunt-native');
-  }
-  if (!/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/.test(args.nativeRuntimeVersion ?? '')) {
-    fail('prebuilt extension artifact --native-runtime-version must be stable SemVer X.Y.Z');
-  }
-  if (!(await isDirectory(args.runtime))) {
-    fail(`prebuilt extension artifact runtime root ${args.runtime} must be an existing directory`);
-  }
-  if (args.embeddedModuleRoot !== undefined && !(await isDirectory(args.embeddedModuleRoot))) {
-    fail(
-      `prebuilt extension artifact embedded module root ${args.embeddedModuleRoot} must be an existing directory`,
-    );
-  }
-  if (args.nativeModuleFile !== undefined && args.nativeModuleStem === undefined) {
-    fail('prebuilt extension nativeModuleFile requires nativeModuleStem');
-  }
-  if (args.nativeModuleStem !== undefined && args.nativeTarget === undefined) {
-    fail('prebuilt extension artifacts with nativeModuleStem must declare nativeTarget');
-  }
-  if (
-    args.nativeModuleStem !== undefined
-    && DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)
-    && args.embeddedModuleRoot === undefined
-  ) {
-    fail('desktop prebuilt extension artifacts with nativeModuleStem require --embedded-module-root');
-  }
-  if (
-    args.embeddedModuleRoot !== undefined
-    && (args.nativeModuleStem === undefined || !DESKTOP_NATIVE_TARGETS.has(args.nativeTarget))
-  ) {
-    fail('--embedded-module-root is only valid for desktop native-module extension artifacts');
-  }
-  if (args.staticSymbolPrefix !== undefined) {
-    validateCIdentifier(args.staticSymbolPrefix, 'prebuilt extension static symbol prefix');
-  }
-  const aliasSqlSymbols = new Set();
-  for (const alias of args.staticSymbolAliases) {
-    validateCIdentifier(alias.sqlSymbol, 'prebuilt extension static symbol alias');
-    validateCIdentifier(alias.linkedSymbol, 'prebuilt extension static symbol alias target');
-    if (aliasSqlSymbols.has(alias.sqlSymbol)) {
-      fail(`prebuilt extension repeats static symbol alias for '${alias.sqlSymbol}'`);
-    }
-    aliasSqlSymbols.add(alias.sqlSymbol);
-  }
-  if (args.mobileStaticArchives.length > 0 && args.nativeModuleStem === undefined) {
-    fail('prebuilt extension mobile static archives require nativeModuleStem');
-  }
-  const mobilePrebuilt = artifactMobilePrebuilt(args);
-  if (mobilePrebuilt && args.nativeModuleStem !== undefined && args.mobileStaticArchives.length === 0) {
-    fail('mobilePrebuilt native-module artifacts must carry at least one mobile static archive');
-  }
-  const mobileTargets = new Set();
-  for (const archive of args.mobileStaticArchives) {
-    validatePortableId(archive.target, 'prebuilt extension mobile static archive target');
-    if (mobileTargets.has(archive.target)) {
-      fail(`prebuilt extension mobile static archives repeat target '${archive.target}'`);
-    }
-    mobileTargets.add(archive.target);
-    if (!(await isFile(archive.archive))) {
-      fail(`prebuilt extension mobile static archive for target '${archive.target}' must be a file: ${archive.archive}`);
-    }
-  }
-  const mobileDependencyKeys = new Set();
-  for (const archive of args.mobileStaticDependencyArchives) {
-    validatePortableId(archive.target, 'prebuilt extension mobile static dependency archive target');
-    validatePortableId(archive.name, 'prebuilt extension mobile static dependency archive name');
-    if (!mobileTargets.has(archive.target)) {
-      fail(`prebuilt extension mobile static dependency archive '${archive.name}' for target '${archive.target}' requires a matching mobile static archive target`);
-    }
-    const key = `${archive.target}:${archive.name}`;
-    if (mobileDependencyKeys.has(key)) {
-      fail(`prebuilt extension mobile static dependency archives repeat '${archive.name}' for target '${archive.target}'`);
-    }
-    mobileDependencyKeys.add(key);
-    validatePortableId(path.basename(archive.archive), 'prebuilt extension mobile static dependency archive file');
-    if (!(await isFile(archive.archive))) {
-      fail(`prebuilt extension mobile static dependency archive '${archive.name}' for target '${archive.target}' must be a file: ${archive.archive}`);
-    }
-  }
-  for (const dataFile of args.dataFiles) {
-    validateRelativeArtifactPath(dataFile, 'data file');
-    if (dataFile.split('/')[0] === 'extension') {
-      fail(`prebuilt extension data file '${dataFile}' must not be under share/postgresql/extension; control and SQL files are selected from sqlName`);
-    }
-  }
-
-  const kind = DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)
-    ? 'native-dynamic'
-    : MOBILE_NATIVE_TARGETS.has(args.nativeTarget)
-      ? 'native-static-registry'
-      : null;
-  if (kind === null) {
-    fail(`prebuilt extension artifact has no native component profile for target '${args.nativeTarget}'`);
-  }
-  args.nativeComponentClosure = resolveNativeComponentClosure(nativeComponentContract, {
-    extension: args.sqlName,
-    family: 'native',
-    kind,
-    target: args.nativeTarget,
-  });
-  const missingRuntimeFiles = args.nativeComponentClosure.runtimeFiles
-    .filter((runtimeFile) => !args.dataFiles.includes(runtimeFile));
-  if (missingRuntimeFiles.length > 0) {
-    fail(
-      `prebuilt extension artifact ${args.sqlName}/${args.nativeTarget} is missing native component runtime files: `
-        + missingRuntimeFiles.join(', '),
-    );
-  }
-  if (kind === 'native-static-registry' && args.nativeModuleStem !== undefined) {
-    const expected = [...args.nativeComponentClosure.linkUnits].sort(compareText);
-    for (const target of mobileTargets) {
-      const actual = args.mobileStaticDependencyArchives
-        .filter((archive) => archive.target === target)
-        .map((archive) => archive.name)
-        .sort(compareText);
-      if (JSON.stringify(actual) !== JSON.stringify(expected)) {
-        fail(
-          `prebuilt extension artifact ${args.sqlName}/${target} native dependency archives do not match `
-            + `the ${args.nativeTarget} component closure: expected=${expected.join(',') || ''} `
-            + `actual=${actual.join(',') || ''}`,
-        );
-      }
-    }
-  }
-}
-
-function artifactMobilePrebuilt(args) {
-  return args.mobilePrebuilt || args.mobileStaticArchives.length > 0;
-}
-
-function extensionSqlFileBelongs(sqlName, fileName, extraSql, createsExtension) {
-  return (
-    (createsExtension && fileName === `${sqlName}.control`) ||
-    (createsExtension && fileName === `${sqlName}.sql`) ||
-    (createsExtension && fileName.startsWith(`${sqlName}--`) && fileName.endsWith('.sql')) ||
-    extraSql.names.includes(fileName) ||
-    (fileName.endsWith('.sql') && extraSql.prefixes.some((prefix) => fileName.startsWith(prefix)))
-  );
-}
-
-async function extensionSqlMetadata(sqlName) {
-  const prefixes = await extensionArtifactList(sqlName, 'extension_sql_file_prefixes');
-  const names = await extensionArtifactList(sqlName, 'extension_sql_file_names');
-  if (new Set(prefixes).size !== prefixes.length || new Set(names).size !== names.length) {
-    fail(`prebuilt extension '${sqlName}' SQL file names and prefixes must be sorted and unique`);
-  }
-  for (const name of names) {
-    if (path.basename(name) !== name || !name.endsWith('.sql')) {
-      fail(`prebuilt extension '${sqlName}' SQL file name '${name}' must be a .sql basename`);
-    }
-  }
-  for (const prefix of prefixes) {
-    validatePortableId(prefix, `prebuilt extension '${sqlName}' SQL file prefix`);
-    if (prefix.includes('.')) {
-      fail(`prebuilt extension '${sqlName}' SQL file prefix '${prefix}' must not contain '.'`);
-    }
-  }
-  return { names, prefixes };
-}
-
-async function ensureParent(file) {
-  await fs.mkdir(path.dirname(file), { recursive: true });
-}
-
-async function copyFileChecked(sourceRoot, source, destination) {
-  const sourceReal = await fs.realpath(source);
-  const rootReal = await fs.realpath(sourceRoot);
-  if (!sourceReal.startsWith(`${rootReal}${path.sep}`) && sourceReal !== rootReal) {
-    fail(`selected extension runtime symlink ${source} resolves outside runtime root ${sourceRoot}`);
-  }
-  const stat = await fs.stat(source);
-  if (!stat.isFile()) {
-    fail(`prebuilt extension artifact source runtime file ${source} must be a regular file`);
-  }
-  await ensureParent(destination);
-  await fs.copyFile(source, destination);
-  await fs.chmod(destination, stat.mode & 0o111 ? 0o755 : 0o644);
-}
-
-async function copyRuntimeRelativeFile(runtime, artifactFiles, relative) {
-  const normalized = validateRelativeArtifactPath(relative, 'runtime file');
-  const source = path.join(runtime, normalized);
-  if (!(await isFile(source))) {
-    fail(`prebuilt extension artifact source runtime is missing declared file ${source}`);
-  }
-  await copyFileChecked(runtime, source, path.join(artifactFiles, normalized));
-}
-
-async function copySqlFiles(args, artifactRoot, artifactFiles, extraSql) {
-  const sourceDir = path.join(args.runtime, 'share/postgresql/extension');
-  const targetDir = path.join(artifactFiles, 'share/postgresql/extension');
-  if (!(await isDirectory(sourceDir))) {
-    if (args.createsExtension) {
-      fail(`prebuilt extension artifact source runtime ${args.runtime} is missing share/postgresql/extension for '${args.sqlName}'`);
-    }
-    return;
-  }
-  let copied = 0;
-  let copiedControl = false;
-  let copiedSql = false;
-  const copiedFileNames = [];
-  const entries = (await fs.readdir(sourceDir)).sort();
-  for (const entry of entries) {
-    if (!extensionSqlFileBelongs(args.sqlName, entry, extraSql, args.createsExtension)) {
-      continue;
-    }
-    copied += 1;
-    copiedFileNames.push(entry);
-    if (entry === `${args.sqlName}.control`) {
-      copiedControl = true;
-    } else if (isCanonicalExtensionInstallSql(entry, args.sqlName)) {
-      copiedSql = true;
-    }
-    await copyFileChecked(args.runtime, path.join(sourceDir, entry), path.join(targetDir, entry));
-  }
-  if (args.createsExtension && (!copiedControl || !copiedSql)) {
-    fail(`prebuilt extension artifact ${artifactRoot} for '${args.sqlName}' must include a control file and canonical base install SQL`);
-  }
-  if (args.createsExtension) {
-    const control = await fs.readFile(path.join(targetDir, `${args.sqlName}.control`), 'utf8');
-    const actualDefaultVersion = extensionControlDefaultVersion(
-      control,
-      args.sqlName,
-      `prebuilt extension artifact ${artifactRoot}`,
-    );
-    const expectedDefaultVersion = await catalogDefaultVersion(args.sqlName);
-    if (actualDefaultVersion !== expectedDefaultVersion) {
-      fail(
-        `prebuilt extension artifact ${artifactRoot} ${args.sqlName}.control default_version `
-          + `'${actualDefaultVersion}' does not match source-owned catalog version '${expectedDefaultVersion}'`,
-      );
-    }
-    validateExtensionInstallSqlReachability({
-      sqlName: args.sqlName,
-      control,
-      fileNames: copiedFileNames,
-      label: `prebuilt extension artifact ${artifactRoot}`,
-    });
-  }
-  if (!args.createsExtension && copied === 0) {
-    return;
-  }
-}
-
-function mobileStaticArchiveRelativePath(target, stem) {
-  return `mobile-static/${target}/extensions/${stem}/liboliphaunt_extension_${stem}.a`;
-}
-
-function mobileStaticDependencyArchiveRelativePath(target, name, archivePath) {
-  return `mobile-static/${target}/dependencies/${name}/${path.basename(archivePath)}`;
-}
-
-async function copyStandaloneFile(source, destination) {
-  const stat = await fs.stat(source);
-  if (!stat.isFile()) {
-    fail(`prebuilt extension artifact source file ${source} must be a regular file`);
-  }
-  await ensureParent(destination);
-  await fs.copyFile(source, destination);
-  await fs.chmod(destination, stat.mode & 0o111 ? 0o755 : 0o644);
-}
-
-function extensionMetadata(args, extraSql) {
-  const dependencies = sortedDeduped(args.dependencies);
-  const dataFiles = sortedDeduped(args.dataFiles);
-  const sharedPreloadLibraries = sortedDeduped(args.sharedPreloadLibraries);
-  const mobileStaticArchives = args.nativeModuleStem === undefined
-    ? []
-    : args.mobileStaticArchives
-        .map((archive) => ({
-          target: archive.target,
-          source: archive.archive,
-          relativePath: mobileStaticArchiveRelativePath(archive.target, args.nativeModuleStem),
-        }))
-        .sort((left, right) => compareText(left.target, right.target));
-  const mobileStaticDependencyArchives = args.mobileStaticDependencyArchives
-    .map((archive) => ({
-      target: archive.target,
-      name: archive.name,
-      source: archive.archive,
-      relativePath: mobileStaticDependencyArchiveRelativePath(archive.target, archive.name, archive.archive),
-    }))
-    .sort((left, right) => compareText(left.target, right.target) || compareText(left.name, right.name));
-  const staticSymbolAliases = [...args.staticSymbolAliases].sort(
-    (left, right) => compareText(left.sqlSymbol, right.sqlSymbol) || compareText(left.linkedSymbol, right.linkedSymbol),
-  );
-  return {
-    dependencies,
-    dataFiles,
-    extensionSqlFileNames: extraSql.names,
-    extensionSqlFilePrefixes: extraSql.prefixes,
-    sharedPreloadLibraries,
-    mobileStaticArchives,
-    mobileStaticDependencyArchives,
-    staticSymbolAliases,
-    mobilePrebuilt: artifactMobilePrebuilt(args),
-    nativeModuleFile: args.nativeModuleStem === undefined ? '' : args.nativeModuleFile ?? args.nativeModuleStem,
-  };
-}
-
-async function writeArtifactDirectory(artifactRoot, args) {
-  const filesRoot = path.join(artifactRoot, 'files');
-  const extraSql = await extensionSqlMetadata(args.sqlName);
-  const metadata = extensionMetadata(args, extraSql);
-  await copySqlFiles(args, artifactRoot, filesRoot, extraSql);
-  for (const dataFile of metadata.dataFiles) {
-    await copyRuntimeRelativeFile(args.runtime, filesRoot, `share/postgresql/${dataFile}`);
-  }
-  if (metadata.nativeModuleFile.length > 0) {
-    await copyRuntimeRelativeFile(args.runtime, filesRoot, `lib/postgresql/${metadata.nativeModuleFile}`);
-    if (DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)) {
-      await copyFileChecked(
-        args.embeddedModuleRoot,
-        path.join(args.embeddedModuleRoot, metadata.nativeModuleFile),
-        path.join(filesRoot, 'lib/modules', metadata.nativeModuleFile),
-      );
-    }
-  }
-  for (const archive of metadata.mobileStaticArchives) {
-    await copyStandaloneFile(archive.source, path.join(artifactRoot, archive.relativePath));
-  }
-  for (const archive of metadata.mobileStaticDependencyArchives) {
-    await copyStandaloneFile(archive.source, path.join(artifactRoot, archive.relativePath));
-  }
-  const licenseFiles = stageExtensionUpstreamLicenses(args.sqlName, filesRoot);
-  const embedsOpenSsl = args.sqlName === 'pgcrypto'
-    && (
-      args.nativeTarget === 'windows-x64-msvc'
-      || args.nativeTarget === 'macos-arm64'
-      || metadata.mobileStaticDependencyArchives.some((archive) => archive.name === 'openssl')
-    );
-  const licenseProfile = licenseFiles.length > 0
-    ? 'external-native'
-    : embedsOpenSsl
-      ? 'contrib-native-openssl'
-      : 'contrib-native';
-  const manifest = [
-    'packageLayout=oliphaunt-extension-artifact-v1',
-    'pgMajor=18',
-    `sqlName=${args.sqlName}`,
-    `createsExtension=${yesNo(args.createsExtension)}`,
-    `nativeModuleStem=${args.nativeModuleStem ?? ''}`,
-    `nativeModuleFile=${metadata.nativeModuleFile}`,
-    `nativeTarget=${args.nativeTarget ?? ''}`,
-    `nativeRuntimeProduct=${args.nativeRuntimeProduct}`,
-    `nativeRuntimeVersion=${args.nativeRuntimeVersion}`,
-    `dependencies=${metadata.dependencies.join(',')}`,
-    `dataFiles=${metadata.dataFiles.join(',')}`,
-    `extensionSqlFileNames=${metadata.extensionSqlFileNames.join(',')}`,
-    `extensionSqlFilePrefixes=${metadata.extensionSqlFilePrefixes.join(',')}`,
-    `sharedPreloadLibraries=${metadata.sharedPreloadLibraries.join(',')}`,
-    `mobilePrebuilt=${yesNo(metadata.mobilePrebuilt)}`,
-    `mobileStaticArchives=${metadata.mobileStaticArchives.map((archive) => `${archive.target}:${archive.relativePath}`).join(',')}`,
-    `mobileStaticDependencyArchives=${metadata.mobileStaticDependencyArchives.map((archive) => `${archive.target}:${archive.name}:${archive.relativePath}`).join(',')}`,
-    `staticSymbolPrefix=${args.staticSymbolPrefix ?? ''}`,
-    `staticSymbolAliases=${metadata.staticSymbolAliases.map((alias) => `${alias.sqlSymbol}:${alias.linkedSymbol}`).join(',')}`,
-    `licenseFiles=${licenseFiles.join(',')}`,
-    `licenseProfile=${licenseProfile}`,
-    'files=files',
-    '',
-  ].join('\n');
-  await fs.mkdir(artifactRoot, { recursive: true });
-  await fs.writeFile(path.join(artifactRoot, 'manifest.properties'), manifest);
-  stageReleaseNotices(artifactRoot, { profile: licenseProfile });
-  return { licenseProfile };
-}
-
-function stripNativeReleaseBinaries(artifactRoot, nativeTarget) {
-  const stripArgs = ['tools/release/strip_native_release_binaries.mjs'];
-  if (nativeTarget) {
-    stripArgs.push('--target', nativeTarget);
-  }
-  stripArgs.push(artifactRoot);
-  const result = spawnSync(
-    process.execPath,
-    stripArgs,
-    { cwd: root, stdio: 'inherit' },
-  );
-  if (result.error !== undefined) {
-    fail(`failed to run native release binary stripper: ${result.error.message}`);
-  }
-  if (result.status !== 0) {
-    fail(`native release binary stripper failed for ${artifactRoot}`);
-  }
-}
-
-export async function validateExactArtifactBinaryContract(artifactRoot, args) {
-  if (
-    args.nativeModuleStem === undefined
-    || !DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)
-  ) {
-    return;
-  }
-  if (args.nativeTarget === 'windows-x64-msvc') {
-    return validateWindowsExtensionArtifactBinaryContract({
-      artifactRoot,
-      providerRuntimeRoot: args.runtime,
-    });
-  }
-  return inspectPlatformBinaryTree(artifactRoot, {
-    target: args.nativeTarget,
-  });
-}
-
-async function prepareOutputFile(output, force) {
-  if (await exists(output)) {
-    if (!force) {
-      fail(`prebuilt extension artifact output ${output} already exists; pass --force`);
-    }
-    const stat = await fs.lstat(output);
-    if (stat.isDirectory()) {
-      await fs.rm(output, { recursive: true, force: true });
-    } else {
-      await fs.unlink(output);
-    }
-  }
-  await ensureParent(output);
-}
-
-async function createArtifact(argv) {
-  const args = parseArgs(argv);
-  args.nativeRuntimeProduct ??= 'liboliphaunt-native';
-  args.nativeRuntimeVersion ??= (await readText('src/runtimes/liboliphaunt/native/VERSION')).trim();
-  await validateArtifactArgs(args);
-  if (!['directory', 'dir', 'tar', 'tar-gz', 'tar.gz', 'tgz', 'gz'].includes(args.format)) {
-    fail(`unknown extension artifact format '${args.format}'`);
-  }
-  const output = path.resolve(args.output);
-  if (args.format === 'directory' || args.format === 'dir') {
-    if (await exists(output)) {
-      if (!args.force) {
-        fail(`prebuilt extension artifact output ${output} already exists; pass --force`);
-      }
-      await fs.rm(output, { recursive: true, force: true });
-    }
-    await writeArtifactDirectory(output, args);
-    stripNativeReleaseBinaries(output, args.nativeTarget);
-    await validateExactArtifactBinaryContract(output, args);
-    console.log(`path=${output}`);
-    console.log(`sqlName=${args.sqlName}`);
-    console.log('format=directory');
-    console.log(`manifest=${path.join(output, 'manifest.properties')}`);
-    return;
-  }
-  await prepareOutputFile(output, args.force);
-  const stageRoot = path.resolve(args.stageRoot ?? path.join(root, 'target/extensions/native/release-stage/local'));
-  const artifactRoot = path.join(stageRoot, `.artifact-${args.sqlName}-${process.pid}-${Date.now()}`);
-  const formatLabel = args.format === 'tar' ? 'tar' : 'tar-gz';
-  await fs.rm(artifactRoot, { recursive: true, force: true });
-  await fs.mkdir(artifactRoot, { recursive: true });
-  try {
-    const { licenseProfile } = await writeArtifactDirectory(artifactRoot, args);
-    stripNativeReleaseBinaries(artifactRoot, args.nativeTarget);
-    await validateExactArtifactBinaryContract(artifactRoot, args);
-    if (args.format === 'tar') {
-      await fs.writeFile(output, await createTar(artifactRoot));
-    } else {
-      await fs.writeFile(output, canonicalGzip(await createTar(artifactRoot)));
-    }
-    assertReleaseNoticesInArchive(output, { profile: licenseProfile });
-  } finally {
-    await fs.rm(artifactRoot, { recursive: true, force: true });
-  }
-  console.log(`path=${output}`);
-  console.log(`sqlName=${args.sqlName}`);
-  console.log(`format=${formatLabel}`);
-  console.log('manifest=');
-}
-
-async function listFilesRecursive(base, current = base) {
-  const entries = (await fs.readdir(current, { withFileTypes: true })).sort((left, right) => compareText(left.name, right.name));
-  const files = [];
-  for (const entry of entries) {
-    const fullPath = path.join(current, entry.name);
-    if (entry.isSymbolicLink()) {
-      fail(`prebuilt extension artifact archives do not support symlinks: ${fullPath}`);
-    }
-    if (entry.isDirectory()) {
-      files.push(...(await listFilesRecursive(base, fullPath)));
-      continue;
-    }
-    if (!entry.isFile()) {
-      fail(`prebuilt extension artifact archives only support files and directories: ${fullPath}`);
-    }
-    files.push(fullPath);
-  }
-  return files;
-}
-
-function tarPathParts(relativePath) {
-  const normalized = relativePath.split(path.sep).join('/');
-  const bytes = Buffer.byteLength(normalized);
-  if (bytes <= 100) {
-    return { name: normalized, prefix: '' };
-  }
-  const parts = normalized.split('/');
-  for (let index = 1; index < parts.length; index += 1) {
-    const prefix = parts.slice(0, index).join('/');
-    const name = parts.slice(index).join('/');
-    if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) {
-      return { name, prefix };
-    }
-  }
-  fail(`prebuilt extension artifact archive path is too long for ustar: ${normalized}`);
-}
-
-function writeString(buffer, offset, length, value) {
-  const bytes = Buffer.from(value);
-  if (bytes.length > length) {
-    fail(`tar header field overflow for '${value}'`);
-  }
-  bytes.copy(buffer, offset);
-}
-
-function writeOctal(buffer, offset, length, value) {
-  const text = value.toString(8).padStart(length - 1, '0').slice(-(length - 1));
-  writeString(buffer, offset, length, `${text}\0`);
-}
-
-function tarHeader(relativePath, size, mode) {
-  const header = Buffer.alloc(512, 0);
-  const { name, prefix } = tarPathParts(relativePath);
-  writeString(header, 0, 100, name);
-  writeOctal(header, 100, 8, mode);
-  writeOctal(header, 108, 8, 0);
-  writeOctal(header, 116, 8, 0);
-  writeOctal(header, 124, 12, size);
-  writeOctal(header, 136, 12, 0);
-  header.fill(0x20, 148, 156);
-  writeString(header, 156, 1, '0');
-  writeString(header, 257, 6, 'ustar\0');
-  writeString(header, 263, 2, '00');
-  writeString(header, 265, 32, 'root');
-  writeString(header, 297, 32, 'root');
-  writeString(header, 345, 155, prefix);
-  let checksum = 0;
-  for (const byte of header) {
-    checksum += byte;
-  }
-  const checksumText = checksum.toString(8).padStart(6, '0');
-  writeString(header, 148, 8, `${checksumText}\0 `);
-  return header;
-}
-
-async function createTar(base) {
-  const chunks = [];
-  const files = await listFilesRecursive(base);
-  const members = [];
-  for (const file of files) {
-    const relative = validateRelativeArtifactPath(path.relative(base, file).split(path.sep).join('/'), 'archive file');
-    const stat = await fs.stat(file);
-    const mode = stat.mode & 0o111 ? 0o755 : 0o644;
-    const data = await fs.readFile(file);
-    members.push({ name: relative, bytes: data.length });
-    chunks.push(tarHeader(relative, data.length, mode));
-    chunks.push(data);
-    const remainder = data.length % 512;
-    if (remainder !== 0) {
-      chunks.push(Buffer.alloc(512 - remainder, 0));
-    }
-  }
-  const expectedBytes = validateExtensionArtifactArchivePlan(
-    members,
-    `prebuilt extension artifact ${base}`,
-  );
-  chunks.push(Buffer.alloc(1024, 0));
-  const archive = Buffer.concat(chunks);
-  if (archive.length !== expectedBytes) {
-    fail(`prebuilt extension artifact ${base} tar bytes ${archive.length} do not match bounded plan ${expectedBytes}`);
-  }
-  return archive;
-}
-
-function canonicalGzip(bytes) {
-  const compressed = canonicalGzipSync(bytes);
-  validateExtensionArtifactCompressedBytes(compressed.length, 'prebuilt extension artifact');
-  return compressed;
-}
-
-async function main() {
-  const [command, ...args] = process.argv.slice(2);
-  switch (command) {
-    case 'list-catalog':
-      await listCatalog(args);
-      break;
-    case 'selected-sql-names':
-      await selectedSqlNames(args[0] ?? '');
-      break;
-    case 'product-version':
-      await productVersion(args[0] ?? '');
-      break;
-    case 'create-artifact':
-      await createArtifact(args);
-      break;
-    default:
-      fail('usage: extension-artifact-packager.mjs  [options]');
-  }
-}
-
-if (import.meta.main) {
-  main().catch((error) => {
-    console.error(`extension-artifact-packager.mjs: ${error.message}`);
-    process.exit(2);
-  });
-}
diff --git a/src/extensions/artifacts/native/tools/extension-artifact-packager.mts b/src/extensions/artifacts/native/tools/extension-artifact-packager.mts
new file mode 100755
index 000000000..1ab585284
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/extension-artifact-packager.mts
@@ -0,0 +1,1203 @@
+#!/usr/bin/env bun
+import { fileURLToPath } from 'node:url';
+import path from 'node:path';
+import { tarHeader } from '../../../../../tools/packaging/archive-directory.mts';
+import { promises as fs } from 'node:fs';
+
+import { validateWindowsExtensionArtifactBinaryContract } from './stage-windows-binary-contract.mts';
+import { inspectPlatformBinaryTree } from '../../../../../tools/packaging/platform-binary-contract.mts';
+import {
+  validateExtensionArtifactArchivePlan,
+  validateExtensionArtifactCompressedBytes,
+} from '../../../tools/extension-artifact-archive-policy.mts';
+import {
+  extensionControlDefaultVersion,
+  isCanonicalExtensionInstallSql,
+  validateExtensionInstallSqlReachability,
+} from '../../packages/tools/extension-artifact-inventory.mts';
+import {
+  assertReleaseNoticesInArchive,
+  stageReleaseNotices,
+} from '../../../../../tools/packaging/release-notices.mts';
+import { stageExtensionUpstreamLicenses } from '../../../tools/extension-upstream-licenses.mts';
+import { canonicalGzipSync } from '../../../../../tools/packaging/portable-archive.mts';
+import { extensionSqlNames } from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  loadNativeComponentContract,
+  resolveNativeComponentClosure,
+} from '../../../tools/native-component-contract.mts';
+
+const scriptDir = path.dirname(fileURLToPath(import.meta.url));
+const root = path.resolve(scriptDir, '../../../../..');
+
+const CATALOG_PATH = path.join(root, 'src/extensions/generated/extensions.catalog.json');
+const CONTRIB_RECIPE_PATH = path.join(root, 'src/extensions/contrib/postgres18.toml');
+const RELEASE_CONFIG_PATH = path.join(root, 'release-please-config.json');
+const DESKTOP_NATIVE_TARGETS = new Set([
+  'linux-x64-gnu',
+  'linux-arm64-gnu',
+  'macos-arm64',
+  'windows-x64-msvc',
+]);
+const MOBILE_NATIVE_TARGETS = new Set(['ios-xcframework', 'android-arm64-v8a', 'android-x86_64']);
+const nativeComponentContract = loadNativeComponentContract();
+
+function fail(message) {
+  throw new Error(message);
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+async function readText(relativeOrAbsolute) {
+  return fs.readFile(
+    path.isAbsolute(relativeOrAbsolute) ? relativeOrAbsolute : path.join(root, relativeOrAbsolute),
+    'utf8',
+  );
+}
+
+async function readJson(relativeOrAbsolute) {
+  return JSON.parse(await readText(relativeOrAbsolute));
+}
+
+async function readToml(relativeOrAbsolute) {
+  return Bun.TOML.parse(await readText(relativeOrAbsolute));
+}
+
+async function exists(file) {
+  try {
+    await fs.access(file);
+    return true;
+  } catch {
+    return false;
+  }
+}
+
+async function isFile(file) {
+  try {
+    return (await fs.stat(file)).isFile();
+  } catch {
+    return false;
+  }
+}
+
+async function isDirectory(file) {
+  try {
+    return (await fs.stat(file)).isDirectory();
+  } catch {
+    return false;
+  }
+}
+
+function stringList(value) {
+  if (!Array.isArray(value)) {
+    return [];
+  }
+  return value.filter((item) => typeof item === 'string' && item.length > 0).sort();
+}
+
+function splitCsv(value) {
+  if (value === undefined || value === null || value === '' || value === '-') {
+    return [];
+  }
+  return String(value)
+    .split(',')
+    .map((item) => item.trim())
+    .filter(Boolean);
+}
+
+function sortedDeduped(values) {
+  return [
+    ...new Set(
+      values
+        .filter((item) => item !== undefined && item !== null && String(item).length > 0)
+        .map(String),
+    ),
+  ].sort();
+}
+
+function dashIfEmpty(value) {
+  if (Array.isArray(value)) {
+    return value.length === 0 ? '-' : value.join(',');
+  }
+  return value === undefined || value === null || value === '' ? '-' : String(value);
+}
+
+function yesNo(value) {
+  return value ? 'yes' : 'no';
+}
+
+function validatePortableId(value, label) {
+  if (!/^[A-Za-z0-9._-]{1,128}$/.test(value)) {
+    fail(`${label} '${value}' must contain 1 to 128 ASCII letters, digits, '.', '_' or '-'`);
+  }
+}
+
+function validateCIdentifier(value, label) {
+  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
+    fail(`${label} '${value}' must be a portable C identifier`);
+  }
+}
+
+function validateRelativeArtifactPath(value, label) {
+  if (!value || path.isAbsolute(value)) {
+    fail(`${label} '${value}' must be a relative path`);
+  }
+  const parts = value.split(/[\\/]+/);
+  if (parts.some((part) => part === '' || part === '.' || part === '..')) {
+    fail(`${label} '${value}' must not contain '.', '..', or empty path components`);
+  }
+  return parts.join('/');
+}
+
+function nativeModuleStem(extension) {
+  const moduleFile = extension['native-module-file'] ?? extension['module-file'];
+  if (typeof moduleFile !== 'string' || moduleFile.length === 0) {
+    return '';
+  }
+  for (const suffix of ['.so', '.dylib', '.dll']) {
+    if (moduleFile.endsWith(suffix)) {
+      return moduleFile.slice(0, -suffix.length);
+    }
+  }
+  return moduleFile;
+}
+
+function sharedPreloadLibraries(extension) {
+  const startupConfig = extension.lifecycle?.['startup-config'] ?? [];
+  const libraries = [];
+  for (const assignment of startupConfig) {
+    if (typeof assignment !== 'string') {
+      continue;
+    }
+    const separator = assignment.indexOf('=');
+    if (separator <= 0) {
+      continue;
+    }
+    if (assignment.slice(0, separator) === 'shared_preload_libraries') {
+      libraries.push(...splitCsv(assignment.slice(separator + 1)));
+    }
+  }
+  return sortedDeduped(libraries);
+}
+
+async function externalRecipe(sqlName) {
+  const recipePath = path.join(root, 'src/extensions/external', sqlName, 'recipe.toml');
+  if (!(await isFile(recipePath))) {
+    return null;
+  }
+  return readToml(recipePath);
+}
+
+async function extensionDataFiles(extension, contribRows) {
+  const sqlName = extension['sql-name'] ?? extension.id;
+  const recipe = await externalRecipe(sqlName);
+  if (recipe !== null) {
+    return stringList(recipe.artifacts?.data_files);
+  }
+  const row = contribRows.find((item) => item?.['sql-name'] === sqlName);
+  return stringList(row?.['data-files']);
+}
+
+function runtimeShareDataFiles(dataFiles) {
+  const prefix = 'share/postgresql/';
+  return dataFiles
+    .map((item) => (item.startsWith(prefix) ? item.slice(prefix.length) : item))
+    .sort();
+}
+
+async function extensionArtifactList(sqlName, field) {
+  const recipe = await externalRecipe(sqlName);
+  if (recipe === null) {
+    return [];
+  }
+  return stringList(recipe.artifacts?.[field]);
+}
+
+export function selectCatalogExtensions(extensions) {
+  if (!Array.isArray(extensions)) {
+    fail('generated extension catalog must define an extensions array');
+  }
+  const seen = new Set();
+  const normalized = [];
+  for (const extension of extensions) {
+    if (extension === null || Array.isArray(extension) || typeof extension !== 'object') {
+      fail('generated extension catalog rows must be objects');
+    }
+    const sqlName = extension['sql-name'] ?? extension.id;
+    if (typeof sqlName !== 'string') {
+      fail('generated extension catalog row must define a SQL name');
+    }
+    validatePortableId(sqlName, 'generated extension catalog SQL name');
+    if (seen.has(sqlName)) {
+      fail(`generated extension catalog repeats SQL name '${sqlName}'`);
+    }
+    seen.add(sqlName);
+    normalized.push({ extension, sqlName });
+  }
+  const supportedSqlNames = new Set(normalized.map(({ sqlName }) => sqlName));
+  return normalized.map(({ extension, sqlName }) => ({
+    dependencies: stringList(extension.dependencies).filter((dependency) =>
+      supportedSqlNames.has(dependency),
+    ),
+    extension,
+    sqlName,
+  }));
+}
+
+export async function catalogRows() {
+  const catalog = await readJson(CATALOG_PATH);
+  const contrib = await readToml(CONTRIB_RECIPE_PATH);
+  const contribRows = Array.isArray(contrib.extensions) ? contrib.extensions : [];
+  const extensions = Array.isArray(catalog.extensions) ? catalog.extensions : [];
+  const rows = [];
+  for (const { dependencies, extension, sqlName } of selectCatalogExtensions(extensions)) {
+    const dataFiles = runtimeShareDataFiles(await extensionDataFiles(extension, contribRows));
+    const stem = nativeModuleStem(extension);
+    rows.push({
+      sqlName,
+      pgMajor: '18',
+      createsExtension: Boolean(extension.lifecycle?.['create-extension']),
+      stem,
+      dependencies,
+      sharedPreload: sharedPreloadLibraries(extension),
+      desktopPrebuilt: true,
+      mobilePrebuilt: true,
+      mobileStaticRequired: stem.length > 0,
+      mobileStaticTargets: [],
+      dataFiles,
+      artifact: 'first-party',
+    });
+  }
+  rows.sort((left, right) => compareText(left.sqlName, right.sqlName));
+  return rows;
+}
+
+async function catalogDefaultVersion(sqlName) {
+  const catalog = await readJson(CATALOG_PATH);
+  const matches = (Array.isArray(catalog.extensions) ? catalog.extensions : []).filter(
+    (extension) => (extension['sql-name'] ?? extension.id) === sqlName,
+  );
+  if (matches.length !== 1) {
+    fail(`generated extension catalog must contain exactly one row for '${sqlName}'`);
+  }
+  const version = matches[0].control?.['default-version'];
+  if (
+    typeof version !== 'string' ||
+    !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(version) ||
+    version.includes('--')
+  ) {
+    fail(`generated extension catalog has no literal control.default-version for '${sqlName}'`);
+  }
+  return version;
+}
+
+async function listCatalog(args = []) {
+  if (args.length > 0) fail('list-catalog does not accept arguments');
+  const header = [
+    'sql_name',
+    'pg_major',
+    'creates_extension',
+    'native_module_stem',
+    'dependencies',
+    'shared_preload',
+    'desktop_prebuilt',
+    'mobile_prebuilt',
+    'mobile_static_registry_required',
+    'mobile_static_archive_targets',
+    'data_files',
+    'artifact',
+  ];
+  console.log(header.join('\t'));
+  for (const row of await catalogRows()) {
+    console.log(
+      [
+        row.sqlName,
+        row.pgMajor,
+        yesNo(row.createsExtension),
+        dashIfEmpty(row.stem),
+        dashIfEmpty(row.dependencies),
+        dashIfEmpty(row.sharedPreload),
+        yesNo(row.desktopPrebuilt),
+        yesNo(row.mobilePrebuilt),
+        yesNo(row.mobileStaticRequired),
+        dashIfEmpty(row.mobileStaticTargets),
+        dashIfEmpty(row.dataFiles),
+        row.artifact,
+      ].join('\t'),
+    );
+  }
+}
+
+async function releasePackageByProduct(product) {
+  const releaseConfig = await readJson(RELEASE_CONFIG_PATH);
+  const packages = releaseConfig.packages ?? {};
+  for (const [packagePath, config] of Object.entries(packages)) {
+    if (config?.component === product) {
+      return { packagePath, config };
+    }
+  }
+  fail(`unknown release product '${product}'`);
+}
+
+async function selectedSqlNames(productsCsv) {
+  const products = sortedDeduped(splitCsv(productsCsv));
+  if (products.length === 0) {
+    fail('no exact-extension products were selected');
+  }
+  const sqlNames = [];
+  for (const product of products) {
+    sqlNames.push(...extensionSqlNames(product, 'extension-artifact-packager.mts'));
+  }
+  console.log(sortedDeduped(sqlNames).join(','));
+}
+
+function parseCargoVersion(text) {
+  let inPackage = false;
+  for (const rawLine of text.split('\n')) {
+    const line = rawLine.trim();
+    if (line === '[package]') {
+      inPackage = true;
+      continue;
+    }
+    if (inPackage && line.startsWith('[')) {
+      break;
+    }
+    if (inPackage) {
+      const match = /^version\s*=\s*"([^"]+)"/.exec(line);
+      if (match) {
+        return match[1];
+      }
+    }
+  }
+  return '';
+}
+
+function parseJsonPath(text, dotted) {
+  let value = JSON.parse(text);
+  for (const key of dotted.split('.')) {
+    if (value === null || typeof value !== 'object' || !(key in value)) {
+      return '';
+    }
+    value = value[key];
+  }
+  return String(value);
+}
+
+async function productVersion(product) {
+  const { packagePath, config } = await releasePackageByProduct(product);
+  const releaseType = config['release-type'];
+  const relativeVersionFile =
+    typeof config['version-file'] === 'string' && config['version-file'].length > 0
+      ? config['version-file']
+      : releaseType === 'rust'
+        ? 'Cargo.toml'
+        : releaseType === 'node' || releaseType === 'expo'
+          ? 'package.json'
+          : null;
+  if (relativeVersionFile === null) {
+    fail(
+      `${product} release-please config must declare version-file for release type '${releaseType}'`,
+    );
+  }
+  const versionFile = path.join(root, packagePath, relativeVersionFile);
+  const text = await readText(versionFile);
+  const parser =
+    path.basename(versionFile) === 'Cargo.toml'
+      ? 'cargo'
+      : path.basename(versionFile) === 'package.json'
+        ? 'json:version'
+        : 'raw';
+  const version =
+    parser === 'cargo'
+      ? parseCargoVersion(text)
+      : parser.startsWith('json:')
+        ? parseJsonPath(text, parser.slice(5))
+        : text.trim();
+  if (!/^[0-9]+[.][0-9]+[.][0-9]+(?:[-+][0-9A-Za-z][0-9A-Za-z.-]*)?$/.test(version)) {
+    fail(`${product} version is not semver-like: '${version}'`);
+  }
+  console.log(version);
+}
+
+function parseArgs(argv) {
+  const args = {
+    dependencies: [],
+    dataFiles: [],
+    sharedPreloadLibraries: [],
+    mobileStaticArchives: [],
+    mobileStaticDependencyArchives: [],
+    staticSymbolAliases: [],
+    createsExtension: true,
+    mobilePrebuilt: false,
+    format: 'directory',
+    force: false,
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    let arg = argv[index];
+    let value = null;
+    const equals = arg.indexOf('=');
+    if (arg.startsWith('--') && equals > 0) {
+      value = arg.slice(equals + 1);
+      arg = arg.slice(0, equals);
+    }
+    const nextValue = () => {
+      if (value !== null) {
+        return value;
+      }
+      index += 1;
+      if (index >= argv.length) {
+        fail(`${arg} requires a value`);
+      }
+      return argv[index];
+    };
+    switch (arg) {
+      case '--force':
+        args.force = true;
+        break;
+      case '--no-create-extension':
+        args.createsExtension = false;
+        break;
+      case '--mobile-prebuilt':
+        args.mobilePrebuilt = value === null ? true : parseBoolean(nextValue(), arg);
+        break;
+      case '--no-mobile-prebuilt':
+        args.mobilePrebuilt = false;
+        break;
+      case '--runtime':
+        args.runtime = nextValue();
+        break;
+      case '--embedded-module-root':
+        args.embeddedModuleRoot = nextValue();
+        break;
+      case '--sql-name':
+        args.sqlName = nextValue();
+        break;
+      case '--creates-extension':
+        args.createsExtension = parseBoolean(nextValue(), arg);
+        break;
+      case '--target':
+      case '--native-target':
+        args.nativeTarget = nextValue();
+        break;
+      case '--output':
+      case '-o':
+        args.output = nextValue();
+        break;
+      case '--stage-root':
+        args.stageRoot = nextValue();
+        break;
+      case '--format':
+        args.format = nextValue();
+        break;
+      case '--native-module-stem':
+        args.nativeModuleStem = nextValue();
+        break;
+      case '--native-module-file':
+        args.nativeModuleFile = nextValue();
+        break;
+      case '--native-runtime-product':
+        args.nativeRuntimeProduct = nextValue();
+        break;
+      case '--native-runtime-version':
+        args.nativeRuntimeVersion = nextValue();
+        break;
+      case '--dependency':
+      case '--dependencies':
+        args.dependencies.push(...splitCsv(nextValue()));
+        break;
+      case '--data-file':
+      case '--data-files':
+        args.dataFiles.push(
+          ...splitCsv(nextValue()).map((item) => validateRelativeArtifactPath(item, 'data file')),
+        );
+        break;
+      case '--shared-preload-library':
+      case '--shared-preload-libraries':
+        args.sharedPreloadLibraries.push(...splitCsv(nextValue()));
+        break;
+      case '--mobile-static-archive':
+      case '--mobile-static-archives':
+        args.mobileStaticArchives.push(...splitCsv(nextValue()).map(parseMobileStaticArchive));
+        break;
+      case '--mobile-static-dependency-archive':
+      case '--mobile-static-dependency-archives':
+        args.mobileStaticDependencyArchives.push(
+          ...splitCsv(nextValue()).map(parseMobileStaticDependencyArchive),
+        );
+        break;
+      case '--static-symbol-prefix':
+        args.staticSymbolPrefix = nextValue();
+        break;
+      case '--static-symbol-alias':
+      case '--static-symbol-aliases':
+        args.staticSymbolAliases.push(...splitCsv(nextValue()).map(parseStaticSymbolAlias));
+        break;
+      default:
+        fail(`unknown argument '${arg}'`);
+    }
+  }
+  return args;
+}
+
+function parseBoolean(value, label) {
+  if (['true', 'yes', '1'].includes(value)) {
+    return true;
+  }
+  if (['false', 'no', '0'].includes(value)) {
+    return false;
+  }
+  fail(`${label} expected true/false, got '${value}'`);
+}
+
+function parseMobileStaticArchive(value) {
+  const separator = value.includes('=') ? value.indexOf('=') : value.indexOf(':');
+  if (separator <= 0) {
+    fail('--mobile-static-archive values must use : or =');
+  }
+  const target = value.slice(0, separator).trim();
+  const archive = value.slice(separator + 1).trim();
+  if (target.length === 0 || archive.length === 0) {
+    fail('--mobile-static-archive values must include both target and archive path');
+  }
+  return { target, archive };
+}
+
+function parseMobileStaticDependencyArchive(value) {
+  if (value.includes('=')) {
+    const [left, archive] = value.split(/=(.*)/s);
+    const [target, name] = left.split(':');
+    if (!target || !name || !archive) {
+      fail(
+        '--mobile-static-dependency-archive values must use :: or :=',
+      );
+    }
+    return { target: target.trim(), name: name.trim(), archive: archive.trim() };
+  }
+  const parts = value.split(':');
+  if (parts.length < 3) {
+    fail(
+      '--mobile-static-dependency-archive values must use :: or :=',
+    );
+  }
+  const target = parts.shift().trim();
+  const name = parts.shift().trim();
+  const archive = parts.join(':').trim();
+  if (!target || !name || !archive) {
+    fail('--mobile-static-dependency-archive values must include target, name, and archive path');
+  }
+  return { target, name, archive };
+}
+
+function parseStaticSymbolAlias(value) {
+  const separator = value.includes('=') ? value.indexOf('=') : value.indexOf(':');
+  if (separator <= 0) {
+    fail(
+      '--static-symbol-alias values must use : or =',
+    );
+  }
+  const sqlSymbol = value.slice(0, separator).trim();
+  const linkedSymbol = value.slice(separator + 1).trim();
+  if (sqlSymbol.length === 0 || linkedSymbol.length === 0) {
+    fail('--static-symbol-alias values must include both SQL and linked C symbols');
+  }
+  return { sqlSymbol, linkedSymbol };
+}
+
+async function validateArtifactArgs(args) {
+  for (const [value, label] of [
+    [args.sqlName, 'prebuilt extension sqlName'],
+    [args.nativeModuleStem, 'prebuilt extension native module stem'],
+    [args.nativeModuleFile, 'prebuilt extension native module file'],
+    [args.nativeTarget, 'prebuilt extension native target'],
+  ]) {
+    if (value !== undefined) {
+      validatePortableId(value, label);
+    }
+  }
+  if (args.output === undefined) {
+    fail('missing required --output ');
+  }
+  if (args.runtime === undefined) {
+    fail('missing required --runtime ');
+  }
+  if (args.sqlName === undefined) {
+    fail('missing required --sql-name ');
+  }
+  if (args.nativeRuntimeProduct !== 'liboliphaunt-native') {
+    fail('prebuilt extension artifact --native-runtime-product must be liboliphaunt-native');
+  }
+  if (
+    !/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/.test(args.nativeRuntimeVersion ?? '')
+  ) {
+    fail('prebuilt extension artifact --native-runtime-version must be stable SemVer X.Y.Z');
+  }
+  if (!(await isDirectory(args.runtime))) {
+    fail(`prebuilt extension artifact runtime root ${args.runtime} must be an existing directory`);
+  }
+  if (args.embeddedModuleRoot !== undefined && !(await isDirectory(args.embeddedModuleRoot))) {
+    fail(
+      `prebuilt extension artifact embedded module root ${args.embeddedModuleRoot} must be an existing directory`,
+    );
+  }
+  if (args.nativeModuleFile !== undefined && args.nativeModuleStem === undefined) {
+    fail('prebuilt extension nativeModuleFile requires nativeModuleStem');
+  }
+  if (args.nativeModuleStem !== undefined && args.nativeTarget === undefined) {
+    fail('prebuilt extension artifacts with nativeModuleStem must declare nativeTarget');
+  }
+  if (
+    args.nativeModuleStem !== undefined &&
+    DESKTOP_NATIVE_TARGETS.has(args.nativeTarget) &&
+    args.embeddedModuleRoot === undefined
+  ) {
+    fail(
+      'desktop prebuilt extension artifacts with nativeModuleStem require --embedded-module-root',
+    );
+  }
+  if (
+    args.embeddedModuleRoot !== undefined &&
+    (args.nativeModuleStem === undefined || !DESKTOP_NATIVE_TARGETS.has(args.nativeTarget))
+  ) {
+    fail('--embedded-module-root is only valid for desktop native-module extension artifacts');
+  }
+  if (args.staticSymbolPrefix !== undefined) {
+    validateCIdentifier(args.staticSymbolPrefix, 'prebuilt extension static symbol prefix');
+  }
+  const aliasSqlSymbols = new Set();
+  for (const alias of args.staticSymbolAliases) {
+    validateCIdentifier(alias.sqlSymbol, 'prebuilt extension static symbol alias');
+    validateCIdentifier(alias.linkedSymbol, 'prebuilt extension static symbol alias target');
+    if (aliasSqlSymbols.has(alias.sqlSymbol)) {
+      fail(`prebuilt extension repeats static symbol alias for '${alias.sqlSymbol}'`);
+    }
+    aliasSqlSymbols.add(alias.sqlSymbol);
+  }
+  if (args.mobileStaticArchives.length > 0 && args.nativeModuleStem === undefined) {
+    fail('prebuilt extension mobile static archives require nativeModuleStem');
+  }
+  const mobilePrebuilt = artifactMobilePrebuilt(args);
+  if (
+    mobilePrebuilt &&
+    args.nativeModuleStem !== undefined &&
+    args.mobileStaticArchives.length === 0
+  ) {
+    fail('mobilePrebuilt native-module artifacts must carry at least one mobile static archive');
+  }
+  const mobileTargets = new Set();
+  for (const archive of args.mobileStaticArchives) {
+    validatePortableId(archive.target, 'prebuilt extension mobile static archive target');
+    if (mobileTargets.has(archive.target)) {
+      fail(`prebuilt extension mobile static archives repeat target '${archive.target}'`);
+    }
+    mobileTargets.add(archive.target);
+    if (!(await isFile(archive.archive))) {
+      fail(
+        `prebuilt extension mobile static archive for target '${archive.target}' must be a file: ${archive.archive}`,
+      );
+    }
+  }
+  const mobileDependencyKeys = new Set();
+  for (const archive of args.mobileStaticDependencyArchives) {
+    validatePortableId(
+      archive.target,
+      'prebuilt extension mobile static dependency archive target',
+    );
+    validatePortableId(archive.name, 'prebuilt extension mobile static dependency archive name');
+    if (!mobileTargets.has(archive.target)) {
+      fail(
+        `prebuilt extension mobile static dependency archive '${archive.name}' for target '${archive.target}' requires a matching mobile static archive target`,
+      );
+    }
+    const key = `${archive.target}:${archive.name}`;
+    if (mobileDependencyKeys.has(key)) {
+      fail(
+        `prebuilt extension mobile static dependency archives repeat '${archive.name}' for target '${archive.target}'`,
+      );
+    }
+    mobileDependencyKeys.add(key);
+    validatePortableId(
+      path.basename(archive.archive),
+      'prebuilt extension mobile static dependency archive file',
+    );
+    if (!(await isFile(archive.archive))) {
+      fail(
+        `prebuilt extension mobile static dependency archive '${archive.name}' for target '${archive.target}' must be a file: ${archive.archive}`,
+      );
+    }
+  }
+  for (const dataFile of args.dataFiles) {
+    validateRelativeArtifactPath(dataFile, 'data file');
+    if (dataFile.split('/')[0] === 'extension') {
+      fail(
+        `prebuilt extension data file '${dataFile}' must not be under share/postgresql/extension; control and SQL files are selected from sqlName`,
+      );
+    }
+  }
+
+  const kind = DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)
+    ? 'native-dynamic'
+    : MOBILE_NATIVE_TARGETS.has(args.nativeTarget)
+      ? 'native-static-registry'
+      : null;
+  if (kind === null) {
+    fail(
+      `prebuilt extension artifact has no native component profile for target '${args.nativeTarget}'`,
+    );
+  }
+  args.nativeComponentClosure = resolveNativeComponentClosure(nativeComponentContract, {
+    extension: args.sqlName,
+    family: 'native',
+    kind,
+    target: args.nativeTarget,
+  });
+  const missingRuntimeFiles = args.nativeComponentClosure.runtimeFiles.filter(
+    (runtimeFile) => !args.dataFiles.includes(runtimeFile),
+  );
+  if (missingRuntimeFiles.length > 0) {
+    fail(
+      `prebuilt extension artifact ${args.sqlName}/${args.nativeTarget} is missing native component runtime files: ` +
+        missingRuntimeFiles.join(', '),
+    );
+  }
+  if (kind === 'native-static-registry' && args.nativeModuleStem !== undefined) {
+    const expected = [...args.nativeComponentClosure.linkUnits].sort(compareText);
+    for (const target of mobileTargets) {
+      const actual = args.mobileStaticDependencyArchives
+        .filter((archive) => archive.target === target)
+        .map((archive) => archive.name)
+        .sort(compareText);
+      if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+        fail(
+          `prebuilt extension artifact ${args.sqlName}/${target} native dependency archives do not match ` +
+            `the ${args.nativeTarget} component closure: expected=${expected.join(',') || ''} ` +
+            `actual=${actual.join(',') || ''}`,
+        );
+      }
+    }
+  }
+}
+
+function artifactMobilePrebuilt(args) {
+  return args.mobilePrebuilt || args.mobileStaticArchives.length > 0;
+}
+
+function extensionSqlFileBelongs(sqlName, fileName, extraSql, createsExtension) {
+  return (
+    (createsExtension && fileName === `${sqlName}.control`) ||
+    (createsExtension && fileName === `${sqlName}.sql`) ||
+    (createsExtension && fileName.startsWith(`${sqlName}--`) && fileName.endsWith('.sql')) ||
+    extraSql.names.includes(fileName) ||
+    (fileName.endsWith('.sql') && extraSql.prefixes.some((prefix) => fileName.startsWith(prefix)))
+  );
+}
+
+async function extensionSqlMetadata(sqlName) {
+  const prefixes = await extensionArtifactList(sqlName, 'extension_sql_file_prefixes');
+  const names = await extensionArtifactList(sqlName, 'extension_sql_file_names');
+  if (new Set(prefixes).size !== prefixes.length || new Set(names).size !== names.length) {
+    fail(`prebuilt extension '${sqlName}' SQL file names and prefixes must be sorted and unique`);
+  }
+  for (const name of names) {
+    if (path.basename(name) !== name || !name.endsWith('.sql')) {
+      fail(`prebuilt extension '${sqlName}' SQL file name '${name}' must be a .sql basename`);
+    }
+  }
+  for (const prefix of prefixes) {
+    validatePortableId(prefix, `prebuilt extension '${sqlName}' SQL file prefix`);
+    if (prefix.includes('.')) {
+      fail(`prebuilt extension '${sqlName}' SQL file prefix '${prefix}' must not contain '.'`);
+    }
+  }
+  return { names, prefixes };
+}
+
+async function ensureParent(file) {
+  await fs.mkdir(path.dirname(file), { recursive: true });
+}
+
+async function copyFileChecked(sourceRoot, source, destination) {
+  const sourceReal = await fs.realpath(source);
+  const rootReal = await fs.realpath(sourceRoot);
+  if (!sourceReal.startsWith(`${rootReal}${path.sep}`) && sourceReal !== rootReal) {
+    fail(
+      `selected extension runtime symlink ${source} resolves outside runtime root ${sourceRoot}`,
+    );
+  }
+  const stat = await fs.stat(source);
+  if (!stat.isFile()) {
+    fail(`prebuilt extension artifact source runtime file ${source} must be a regular file`);
+  }
+  await ensureParent(destination);
+  await fs.copyFile(source, destination);
+  await fs.chmod(destination, stat.mode & 0o111 ? 0o755 : 0o644);
+}
+
+async function copyRuntimeRelativeFile(runtime, artifactFiles, relative) {
+  const normalized = validateRelativeArtifactPath(relative, 'runtime file');
+  const source = path.join(runtime, normalized);
+  if (!(await isFile(source))) {
+    fail(`prebuilt extension artifact source runtime is missing declared file ${source}`);
+  }
+  await copyFileChecked(runtime, source, path.join(artifactFiles, normalized));
+}
+
+async function copySqlFiles(args, artifactRoot, artifactFiles, extraSql) {
+  const sourceDir = path.join(args.runtime, 'share/postgresql/extension');
+  const targetDir = path.join(artifactFiles, 'share/postgresql/extension');
+  if (!(await isDirectory(sourceDir))) {
+    if (args.createsExtension) {
+      fail(
+        `prebuilt extension artifact source runtime ${args.runtime} is missing share/postgresql/extension for '${args.sqlName}'`,
+      );
+    }
+    return;
+  }
+  let copied = 0;
+  let copiedControl = false;
+  let copiedSql = false;
+  const copiedFileNames = [];
+  const entries = (await fs.readdir(sourceDir)).sort();
+  for (const entry of entries) {
+    if (!extensionSqlFileBelongs(args.sqlName, entry, extraSql, args.createsExtension)) {
+      continue;
+    }
+    copied += 1;
+    copiedFileNames.push(entry);
+    if (entry === `${args.sqlName}.control`) {
+      copiedControl = true;
+    } else if (isCanonicalExtensionInstallSql(entry, args.sqlName)) {
+      copiedSql = true;
+    }
+    await copyFileChecked(args.runtime, path.join(sourceDir, entry), path.join(targetDir, entry));
+  }
+  if (args.createsExtension && (!copiedControl || !copiedSql)) {
+    fail(
+      `prebuilt extension artifact ${artifactRoot} for '${args.sqlName}' must include a control file and canonical base install SQL`,
+    );
+  }
+  if (args.createsExtension) {
+    const control = await fs.readFile(path.join(targetDir, `${args.sqlName}.control`), 'utf8');
+    const actualDefaultVersion = extensionControlDefaultVersion(
+      control,
+      args.sqlName,
+      `prebuilt extension artifact ${artifactRoot}`,
+    );
+    const expectedDefaultVersion = await catalogDefaultVersion(args.sqlName);
+    if (actualDefaultVersion !== expectedDefaultVersion) {
+      fail(
+        `prebuilt extension artifact ${artifactRoot} ${args.sqlName}.control default_version ` +
+          `'${actualDefaultVersion}' does not match source-owned catalog version '${expectedDefaultVersion}'`,
+      );
+    }
+    validateExtensionInstallSqlReachability({
+      sqlName: args.sqlName,
+      control,
+      fileNames: copiedFileNames,
+      label: `prebuilt extension artifact ${artifactRoot}`,
+    });
+  }
+  if (!args.createsExtension && copied === 0) {
+    return;
+  }
+}
+
+function mobileStaticArchiveRelativePath(target, stem) {
+  return `mobile-static/${target}/extensions/${stem}/liboliphaunt_extension_${stem}.a`;
+}
+
+function mobileStaticDependencyArchiveRelativePath(target, name, archivePath) {
+  return `mobile-static/${target}/dependencies/${name}/${path.basename(archivePath)}`;
+}
+
+async function copyStandaloneFile(source, destination) {
+  const stat = await fs.stat(source);
+  if (!stat.isFile()) {
+    fail(`prebuilt extension artifact source file ${source} must be a regular file`);
+  }
+  await ensureParent(destination);
+  await fs.copyFile(source, destination);
+  await fs.chmod(destination, stat.mode & 0o111 ? 0o755 : 0o644);
+}
+
+function extensionMetadata(args, extraSql) {
+  const dependencies = sortedDeduped(args.dependencies);
+  const dataFiles = sortedDeduped(args.dataFiles);
+  const sharedPreloadLibraries = sortedDeduped(args.sharedPreloadLibraries);
+  const mobileStaticArchives =
+    args.nativeModuleStem === undefined
+      ? []
+      : args.mobileStaticArchives
+          .map((archive) => ({
+            target: archive.target,
+            source: archive.archive,
+            relativePath: mobileStaticArchiveRelativePath(archive.target, args.nativeModuleStem),
+          }))
+          .sort((left, right) => compareText(left.target, right.target));
+  const mobileStaticDependencyArchives = args.mobileStaticDependencyArchives
+    .map((archive) => ({
+      target: archive.target,
+      name: archive.name,
+      source: archive.archive,
+      relativePath: mobileStaticDependencyArchiveRelativePath(
+        archive.target,
+        archive.name,
+        archive.archive,
+      ),
+    }))
+    .sort(
+      (left, right) => compareText(left.target, right.target) || compareText(left.name, right.name),
+    );
+  const staticSymbolAliases = [...args.staticSymbolAliases].sort(
+    (left, right) =>
+      compareText(left.sqlSymbol, right.sqlSymbol) ||
+      compareText(left.linkedSymbol, right.linkedSymbol),
+  );
+  return {
+    dependencies,
+    dataFiles,
+    extensionSqlFileNames: extraSql.names,
+    extensionSqlFilePrefixes: extraSql.prefixes,
+    sharedPreloadLibraries,
+    mobileStaticArchives,
+    mobileStaticDependencyArchives,
+    staticSymbolAliases,
+    mobilePrebuilt: artifactMobilePrebuilt(args),
+    nativeModuleFile:
+      args.nativeModuleStem === undefined ? '' : (args.nativeModuleFile ?? args.nativeModuleStem),
+  };
+}
+
+async function writeArtifactDirectory(artifactRoot, args) {
+  const filesRoot = path.join(artifactRoot, 'files');
+  const extraSql = await extensionSqlMetadata(args.sqlName);
+  const metadata = extensionMetadata(args, extraSql);
+  await copySqlFiles(args, artifactRoot, filesRoot, extraSql);
+  for (const dataFile of metadata.dataFiles) {
+    await copyRuntimeRelativeFile(args.runtime, filesRoot, `share/postgresql/${dataFile}`);
+  }
+  if (metadata.nativeModuleFile.length > 0) {
+    await copyRuntimeRelativeFile(
+      args.runtime,
+      filesRoot,
+      `lib/postgresql/${metadata.nativeModuleFile}`,
+    );
+    if (DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)) {
+      await copyFileChecked(
+        args.embeddedModuleRoot,
+        path.join(args.embeddedModuleRoot, metadata.nativeModuleFile),
+        path.join(filesRoot, 'lib/modules', metadata.nativeModuleFile),
+      );
+    }
+  }
+  for (const archive of metadata.mobileStaticArchives) {
+    await copyStandaloneFile(archive.source, path.join(artifactRoot, archive.relativePath));
+  }
+  for (const archive of metadata.mobileStaticDependencyArchives) {
+    await copyStandaloneFile(archive.source, path.join(artifactRoot, archive.relativePath));
+  }
+  const licenseFiles = stageExtensionUpstreamLicenses(args.sqlName, filesRoot);
+  const embedsOpenSsl =
+    args.sqlName === 'pgcrypto' &&
+    (args.nativeTarget === 'windows-x64-msvc' ||
+      args.nativeTarget === 'macos-arm64' ||
+      metadata.mobileStaticDependencyArchives.some((archive) => archive.name === 'openssl'));
+  const licenseProfile =
+    licenseFiles.length > 0
+      ? 'external-native'
+      : embedsOpenSsl
+        ? 'contrib-native-openssl'
+        : 'contrib-native';
+  const manifest = [
+    'packageLayout=oliphaunt-extension-artifact-v1',
+    'pgMajor=18',
+    `sqlName=${args.sqlName}`,
+    `createsExtension=${yesNo(args.createsExtension)}`,
+    `nativeModuleStem=${args.nativeModuleStem ?? ''}`,
+    `nativeModuleFile=${metadata.nativeModuleFile}`,
+    `nativeTarget=${args.nativeTarget ?? ''}`,
+    `nativeRuntimeProduct=${args.nativeRuntimeProduct}`,
+    `nativeRuntimeVersion=${args.nativeRuntimeVersion}`,
+    `dependencies=${metadata.dependencies.join(',')}`,
+    `dataFiles=${metadata.dataFiles.join(',')}`,
+    `extensionSqlFileNames=${metadata.extensionSqlFileNames.join(',')}`,
+    `extensionSqlFilePrefixes=${metadata.extensionSqlFilePrefixes.join(',')}`,
+    `sharedPreloadLibraries=${metadata.sharedPreloadLibraries.join(',')}`,
+    `mobilePrebuilt=${yesNo(metadata.mobilePrebuilt)}`,
+    `mobileStaticArchives=${metadata.mobileStaticArchives.map((archive) => `${archive.target}:${archive.relativePath}`).join(',')}`,
+    `mobileStaticDependencyArchives=${metadata.mobileStaticDependencyArchives.map((archive) => `${archive.target}:${archive.name}:${archive.relativePath}`).join(',')}`,
+    `staticSymbolPrefix=${args.staticSymbolPrefix ?? ''}`,
+    `staticSymbolAliases=${metadata.staticSymbolAliases.map((alias) => `${alias.sqlSymbol}:${alias.linkedSymbol}`).join(',')}`,
+    `licenseFiles=${licenseFiles.join(',')}`,
+    `licenseProfile=${licenseProfile}`,
+    'files=files',
+    '',
+  ].join('\n');
+  await fs.mkdir(artifactRoot, { recursive: true });
+  await fs.writeFile(path.join(artifactRoot, 'manifest.properties'), manifest);
+  stageReleaseNotices(artifactRoot, { profile: licenseProfile });
+  return { licenseProfile };
+}
+
+export async function validateExactArtifactBinaryContract(artifactRoot, args) {
+  if (args.nativeModuleStem === undefined || !DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)) {
+    return;
+  }
+  if (args.nativeTarget === 'windows-x64-msvc') {
+    return validateWindowsExtensionArtifactBinaryContract({
+      artifactRoot,
+      providerRuntimeRoot: args.runtime,
+    });
+  }
+  return inspectPlatformBinaryTree(artifactRoot, {
+    target: args.nativeTarget,
+  });
+}
+
+async function prepareOutputFile(output, force) {
+  if (await exists(output)) {
+    if (!force) {
+      fail(`prebuilt extension artifact output ${output} already exists; pass --force`);
+    }
+    const stat = await fs.lstat(output);
+    if (stat.isDirectory()) {
+      await fs.rm(output, { recursive: true, force: true });
+    } else {
+      await fs.unlink(output);
+    }
+  }
+  await ensureParent(output);
+}
+
+async function artifactPhase(phase, artifactRoot, argv) {
+  const args = parseArgs(argv);
+  args.nativeRuntimeProduct ??= 'liboliphaunt-native';
+  args.nativeRuntimeVersion ??= (await readText('src/runtimes/liboliphaunt-native/VERSION')).trim();
+  await validateArtifactArgs(args);
+  if (!['directory', 'dir', 'tar', 'tar-gz', 'tar.gz', 'tgz', 'gz'].includes(args.format)) {
+    fail('unknown extension artifact format: ' + args.format);
+  }
+  const output = path.resolve(args.output);
+  if (phase === 'stage-artifact') {
+    if ((await exists(output)) && !args.force) {
+      fail('prebuilt extension artifact output ' + output + ' already exists; pass --force');
+    }
+    await writeArtifactDirectory(artifactRoot, args);
+    return;
+  }
+  await validateExactArtifactBinaryContract(artifactRoot, args);
+  await prepareOutputFile(output, args.force);
+  const directory = args.format === 'directory' || args.format === 'dir';
+  if (directory) {
+    try {
+      await fs.rename(artifactRoot, output);
+    } catch (error) {
+      if (error.code !== 'EXDEV') throw error;
+      await fs.cp(artifactRoot, output, { recursive: true });
+    }
+  } else {
+    const manifest = await fs.readFile(path.join(artifactRoot, 'manifest.properties'), 'utf8');
+    const profile = manifest.match(/^licenseProfile=(.+)$/m)?.[1];
+    if (!profile) fail('staged extension artifact is missing its license profile');
+    const tar = await createTar(artifactRoot);
+    await fs.writeFile(output, args.format === 'tar' ? tar : canonicalGzip(tar));
+    assertReleaseNoticesInArchive(output, { profile });
+  }
+  console.log('path=' + output);
+  console.log('sqlName=' + args.sqlName);
+  console.log('format=' + (directory ? 'directory' : args.format === 'tar' ? 'tar' : 'tar-gz'));
+  console.log('manifest=' + (directory ? path.join(output, 'manifest.properties') : ''));
+}
+
+async function listFilesRecursive(base, current = base) {
+  const entries = (await fs.readdir(current, { withFileTypes: true })).sort((left, right) =>
+    compareText(left.name, right.name),
+  );
+  const files = [];
+  for (const entry of entries) {
+    const fullPath = path.join(current, entry.name);
+    if (entry.isSymbolicLink()) {
+      fail(`prebuilt extension artifact archives do not support symlinks: ${fullPath}`);
+    }
+    if (entry.isDirectory()) {
+      files.push(...(await listFilesRecursive(base, fullPath)));
+      continue;
+    }
+    if (!entry.isFile()) {
+      fail(`prebuilt extension artifact archives only support files and directories: ${fullPath}`);
+    }
+    files.push(fullPath);
+  }
+  return files;
+}
+
+async function createTar(base) {
+  const chunks = [];
+  const files = await listFilesRecursive(base);
+  const members = [];
+  for (const file of files) {
+    const relative = validateRelativeArtifactPath(
+      path.relative(base, file).split(path.sep).join('/'),
+      'archive file',
+    );
+    const stat = await fs.stat(file);
+    const mode = stat.mode & 0o111 ? 0o755 : 0o644;
+    const data = await fs.readFile(file);
+    members.push({ name: relative, bytes: data.length });
+    chunks.push(tarHeader({ name: relative, owner: 'root' }, data.length, mode));
+    chunks.push(data);
+    const remainder = data.length % 512;
+    if (remainder !== 0) {
+      chunks.push(Buffer.alloc(512 - remainder, 0));
+    }
+  }
+  const expectedBytes = validateExtensionArtifactArchivePlan(
+    members,
+    `prebuilt extension artifact ${base}`,
+  );
+  chunks.push(Buffer.alloc(1024, 0));
+  const archive = Buffer.concat(chunks);
+  if (archive.length !== expectedBytes) {
+    fail(
+      `prebuilt extension artifact ${base} tar bytes ${archive.length} do not match bounded plan ${expectedBytes}`,
+    );
+  }
+  return archive;
+}
+
+function canonicalGzip(bytes) {
+  const compressed = canonicalGzipSync(bytes);
+  validateExtensionArtifactCompressedBytes(compressed.length, 'prebuilt extension artifact');
+  return compressed;
+}
+
+async function main() {
+  const [command, ...args] = process.argv.slice(2);
+  switch (command) {
+    case 'list-catalog':
+      await listCatalog(args);
+      break;
+    case 'selected-sql-names':
+      await selectedSqlNames(args[0] ?? '');
+      break;
+    case 'product-version':
+      await productVersion(args[0] ?? '');
+      break;
+    case 'stage-artifact':
+    case 'finish-artifact':
+      await artifactPhase(command, args[0], args.slice(1));
+      break;
+    default:
+      fail(
+        'usage: extension-artifact-packager.mts  [options]',
+      );
+  }
+}
+
+if (import.meta.main) {
+  main().catch((error) => {
+    console.error(`extension-artifact-packager.mts: ${error.message}`);
+    process.exit(2);
+  });
+}
diff --git a/src/extensions/artifacts/native/tools/ios-extension-registration.mts b/src/extensions/artifacts/native/tools/ios-extension-registration.mts
new file mode 100755
index 000000000..2312b8113
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/ios-extension-registration.mts
@@ -0,0 +1,137 @@
+#!/usr/bin/env bun
+
+import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+import { compareText } from '../../../../../tools/release/release-artifact-targets.mts';
+
+const PREFIX = 'ios-extension-registration.mts';
+const SCHEMA = 'oliphaunt-ios-extension-registration-v1';
+const PORTABLE_RE = /^[A-Za-z0-9._-]{1,128}$/u;
+const C_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/u;
+
+function fail(message) {
+  console.error(`${PREFIX}: ${message}`);
+  process.exit(1);
+}
+
+function lines(file) {
+  return readFileSync(file, 'utf8')
+    .split(/\r?\n/u)
+    .map((line) => line.trim())
+    .filter(Boolean);
+}
+
+export function readRegistrationSymbols(out, stem) {
+  const root = path.join(out, 'extensions', stem);
+  const exported = lines(path.join(root, 'symbols.list')).map((name) => ({ name, address: name }));
+  const aliasFile = path.join(root, 'symbol-aliases.list');
+  const aliases = (existsSync(aliasFile) ? lines(aliasFile) : []).map((line) => {
+    const fields = line.split('\t');
+    if (fields.length !== 2) {
+      fail(`${aliasFile} contains an invalid alias row`);
+    }
+    return { name: fields[0], address: fields[1] };
+  });
+  const result = [...exported, ...aliases].sort((left, right) =>
+    compareText(`${left.name}\0${left.address}`, `${right.name}\0${right.address}`),
+  );
+  for (const row of result) {
+    if (!C_IDENTIFIER_RE.test(row.name) || !C_IDENTIFIER_RE.test(row.address)) {
+      fail(`${root} contains a non-C registration symbol`);
+    }
+  }
+  if (new Set(result.map(({ name }) => name)).size !== result.length) {
+    fail(`${root} repeats a SQL-visible registration symbol`);
+  }
+  return result;
+}
+
+export function assertDefinedRegistrationAddresses(symbols, defined, label) {
+  const missing = [
+    ...new Set(symbols.map(({ address }) => address).filter((address) => !defined.has(address))),
+  ].sort(compareText);
+  if (missing.length > 0) {
+    throw new Error(
+      `${label} registration address(es) are not defined by its extension objects: ${missing.join(',')}`,
+    );
+  }
+}
+
+function definedSymbols(file) {
+  const text = readFileSync(file, 'utf8');
+  if (Buffer.byteLength(text) > 64 * 1024 * 1024) fail('nm output exceeds 64 MiB');
+  const names = new Set();
+  for (const raw of text.split(/\r?\n/u)) {
+    const fields = raw.trim().split(/\s+/u);
+    if (fields.length < 2) continue;
+    const type = fields.at(-2);
+    const rawName = fields.at(-1);
+    if (!/^[A-Za-z]$/u.test(type) || type.toUpperCase() === 'U') continue;
+    names.add(rawName.startsWith('_') ? rawName.slice(1) : rawName);
+  }
+  return names;
+}
+
+function registration(out, sqlName, stem, inventory) {
+  const prefix = `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`;
+  const names = definedSymbols(inventory);
+  const magicSymbol = `${prefix}_Pg_magic_func`;
+  if (!names.has(magicSymbol)) {
+    fail(`${out} ${sqlName} archive does not export required ${magicSymbol}`);
+  }
+  const init = `${prefix}__PG_init`;
+  const symbols = readRegistrationSymbols(out, stem);
+  try {
+    assertDefinedRegistrationAddresses(symbols, names, `${out} ${sqlName}`);
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+  return {
+    initSymbol: names.has(init) ? init : null,
+    magicSymbol,
+    symbols,
+  };
+}
+
+function stable(value) {
+  if (Array.isArray(value)) return value.map(stable);
+  if (value !== null && typeof value === 'object') {
+    return Object.fromEntries(
+      Object.keys(value)
+        .sort()
+        .map((key) => [key, stable(value[key])]),
+    );
+  }
+  return value;
+}
+
+if (import.meta.main) {
+  const [sqlName, nativeModuleStem, simulatorOut, deviceOut, macosOut, outputFile, symbolsDir] =
+    process.argv.slice(2);
+  if (
+    process.argv.length !== 9 ||
+    !PORTABLE_RE.test(sqlName) ||
+    !PORTABLE_RE.test(nativeModuleStem)
+  )
+    fail(
+      'usage: ios-extension-registration.mts SQL STEM SIMULATOR DEVICE MACOS OUTPUT NM_DIRECTORY',
+    );
+  const [simulator, device, macos] = [simulatorOut, deviceOut, macosOut].map((out, index) =>
+    registration(out, sqlName, nativeModuleStem, path.join(symbolsDir, index + '.txt')),
+  );
+  if (
+    JSON.stringify(simulator) !== JSON.stringify(device) ||
+    JSON.stringify(simulator) !== JSON.stringify(macos)
+  ) {
+    fail(`${sqlName} macOS, iOS simulator, and iOS device registration metadata differ`);
+  }
+  const output = stable({
+    schema: SCHEMA,
+    sqlName: sqlName,
+    nativeModuleStem: nativeModuleStem,
+    ...simulator,
+  });
+  mkdirSync(path.dirname(outputFile), { recursive: true });
+  writeFileSync(outputFile, `${JSON.stringify(output, null, 2)}\n`, 'utf8');
+}
diff --git a/src/extensions/artifacts/native/tools/ios-extension-registration.sh b/src/extensions/artifacts/native/tools/ios-extension-registration.sh
new file mode 100644
index 000000000..1492383c3
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/ios-extension-registration.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+set -euo pipefail
+sql_name='' stem='' simulator='' device='' macos='' output=''
+while [ "$#" -gt 0 ]; do
+  if [ "$1" = --help ] || [ "$1" = -h ]; then
+    echo 'usage: ios-extension-registration.sh --sql-name NAME --native-module-stem STEM --simulator-out DIR --device-out DIR --macos-out DIR --output FILE'
+    exit 0
+  fi
+  [ "$#" -ge 2 ] || { echo "missing value for $1" >&2; exit 1; }
+  case "$1" in
+    --sql-name) sql_name=$2 ;; --native-module-stem) stem=$2 ;;
+    --simulator-out) simulator=$2 ;; --device-out) device=$2 ;; --macos-out) macos=$2 ;;
+    --output) output=$2 ;; *) echo "unknown argument $1" >&2; exit 1 ;;
+  esac
+  shift 2
+done
+for required in "$sql_name" "$stem" "$simulator" "$device" "$macos" "$output"; do
+  [ -n "$required" ] || { echo 'all registration arguments are required' >&2; exit 1; }
+done
+for identifier in "$sql_name" "$stem"; do
+  case "$identifier" in *[!A-Za-z0-9._-]*) echo 'invalid extension identifier' >&2; exit 1 ;; esac
+  [ "${#identifier}" -le 128 ] || exit 1
+done
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-ios-symbols-XXXXXX")
+trap 'rm -rf "$scratch"' EXIT
+index=0
+for slice in "$simulator" "$device" "$macos"; do
+  objects=()
+  while IFS= read -r object || [ -n "$object" ]; do
+    object=${object%$'\r'}
+    [ -n "$object" ] || continue
+    case "$object" in -*) object="./$object" ;; esac
+    objects+=("$object")
+  done < "$slice/extensions/$stem/objects.list"
+  [ "${#objects[@]}" -gt 0 ] || { echo "empty object list for $slice/$stem" >&2; exit 1; }
+  nm -g "${objects[@]}" | head -c 67108865 > "$scratch/$index.txt"
+  index=$((index + 1))
+done
+bun "$(dirname "${BASH_SOURCE[0]}")/ios-extension-registration.mts" "$sql_name" "$stem" "$simulator" "$device" "$macos" "$output" "$scratch"
diff --git a/src/extensions/artifacts/native/tools/ios-extension-registration.test.mts b/src/extensions/artifacts/native/tools/ios-extension-registration.test.mts
new file mode 100644
index 000000000..7ac8f0eda
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/ios-extension-registration.test.mts
@@ -0,0 +1,101 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import {
+  assertDefinedRegistrationAddresses,
+  readRegistrationSymbols,
+} from './ios-extension-registration.mts';
+
+test('iOS extension registration accepts an absent optional symbol alias list', () => {
+  const out = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-ios-registration-'));
+  try {
+    const extension = path.join(out, 'extensions', 'amcheck');
+    mkdirSync(extension, { recursive: true });
+    writeFileSync(path.join(extension, 'symbols.list'), 'verify_nbtree\n');
+
+    assert.deepEqual(readRegistrationSymbols(out, 'amcheck'), [
+      { name: 'verify_nbtree', address: 'verify_nbtree' },
+    ]);
+    assert.throws(
+      () => readRegistrationSymbols(out, 'missing'),
+      /symbols\.list/u,
+      'the required exported-symbol list must remain mandatory',
+    );
+  } finally {
+    rmSync(out, { recursive: true, force: true });
+  }
+});
+
+test('iOS extension registration merges and sorts explicit symbol aliases', () => {
+  const out = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-ios-registration-'));
+  try {
+    const extension = path.join(out, 'extensions', 'postgis-3');
+    mkdirSync(extension, { recursive: true });
+    writeFileSync(path.join(extension, 'symbols.list'), 'zeta\n');
+    writeFileSync(
+      path.join(extension, 'symbol-aliases.list'),
+      'difference\toliphaunt_static_postgis_3_difference\n',
+    );
+
+    assert.deepEqual(readRegistrationSymbols(out, 'postgis-3'), [
+      { name: 'difference', address: 'oliphaunt_static_postgis_3_difference' },
+      { name: 'zeta', address: 'zeta' },
+    ]);
+  } finally {
+    rmSync(out, { recursive: true, force: true });
+  }
+});
+
+test('iOS extension registration uses locale-independent ordinal ordering for mixed-case symbols', () => {
+  const out = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-ios-registration-'));
+  try {
+    const extension = path.join(out, 'extensions', 'bloom');
+    mkdirSync(extension, { recursive: true });
+    writeFileSync(
+      path.join(extension, 'symbols.list'),
+      'blbeginscan\nBloomFillMetapage\nblinsert\n',
+    );
+
+    assert.deepEqual(readRegistrationSymbols(out, 'bloom'), [
+      { name: 'BloomFillMetapage', address: 'BloomFillMetapage' },
+      { name: 'blbeginscan', address: 'blbeginscan' },
+      { name: 'blinsert', address: 'blinsert' },
+    ]);
+  } finally {
+    rmSync(out, { recursive: true, force: true });
+  }
+});
+
+test('iOS extension registration rejects an exported-symbol address absent from the built slice', () => {
+  assert.throws(
+    () =>
+      assertDefinedRegistrationAddresses(
+        [{ name: 'ellipsoid_in', address: 'ellipsoid_in' }],
+        new Set(['oliphaunt_static_postgis_3_Pg_magic_func']),
+        'ios-simulator postgis',
+      ),
+    /ios-simulator postgis registration address\(es\).*ellipsoid_in/u,
+  );
+});
+
+test('iOS extension registration rejects an alias whose linked address is absent from the built slice', () => {
+  assert.throws(
+    () =>
+      assertDefinedRegistrationAddresses(
+        [
+          {
+            name: 'difference',
+            address: 'oliphaunt_static_postgis_3_difference',
+          },
+        ],
+        new Set(['difference']),
+        'ios-device postgis',
+      ),
+    /ios-device postgis registration address\(es\).*oliphaunt_static_postgis_3_difference/u,
+  );
+});
diff --git a/src/extensions/artifacts/native/tools/ios-extension-registration.test.sh b/src/extensions/artifacts/native/tools/ios-extension-registration.test.sh
new file mode 100644
index 000000000..e7d5a3522
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/ios-extension-registration.test.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+bun test ./src/extensions/artifacts/native/tools/ios-extension-registration.test.mts
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+cat > "$scratch/extension.c" <<'C'
+void oliphaunt_static_sample_Pg_magic_func(void) {}
+void sample_sql(void) {}
+C
+cc -c "$scratch/extension.c" -o "$scratch/extension.o"
+for slice in simulator device macos; do
+  mkdir -p "$scratch/$slice/extensions/sample"
+  printf '%s\n' "$scratch/extension.o" > "$scratch/$slice/extensions/sample/objects.list"
+  printf 'sample_sql\n' > "$scratch/$slice/extensions/sample/symbols.list"
+done
+args=(--sql-name sample --native-module-stem sample --simulator-out "$scratch/simulator" --device-out "$scratch/device" --macos-out "$scratch/macos" --output "$scratch/registration.json")
+bash src/extensions/artifacts/native/tools/ios-extension-registration.sh "${args[@]}"
+bun -e 'import assert from "node:assert/strict"; const value=await Bun.file(process.argv[1]).json(); assert.deepEqual(value.symbols,[{name:"sample_sql",address:"sample_sql"}])' "$scratch/registration.json"
+cp "$scratch/registration.json" "$scratch/before.json"
+printf 'missing_sql\n' > "$scratch/device/extensions/sample/symbols.list"
+if bash src/extensions/artifacts/native/tools/ios-extension-registration.sh "${args[@]}" > "$scratch/invalid.log" 2>&1; then
+  echo 'Registration accepted an undefined symbol' >&2
+  exit 1
+fi
+grep -q 'not defined.*missing_sql' "$scratch/invalid.log"
+cmp "$scratch/before.json" "$scratch/registration.json"
+echo 'Compiled registration and failed-slice atomic output checks passed'
diff --git a/src/extensions/artifacts/native/tools/native-extension-asset-index-contract.mts b/src/extensions/artifacts/native/tools/native-extension-asset-index-contract.mts
new file mode 100644
index 000000000..7cd802994
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/native-extension-asset-index-contract.mts
@@ -0,0 +1,54 @@
+export const NATIVE_EXTENSION_ASSET_INDEX_HEADER = Object.freeze([
+  'sql_name',
+  'target',
+  'kind',
+  'identity',
+  'artifact',
+  'artifact_bytes',
+  'registration_artifact',
+]);
+
+export const NATIVE_EXTENSION_RUNTIME_KIND = 'runtime';
+
+export function nativeExtensionAssetIndexHeaderTsv() {
+  return NATIVE_EXTENSION_ASSET_INDEX_HEADER.join('\t');
+}
+
+export function nativeExtensionRuntimeKind() {
+  return NATIVE_EXTENSION_RUNTIME_KIND;
+}
+
+export function isCanonicalNativeExtensionRuntimeIndexRow(row, target) {
+  return (
+    row?.target === target &&
+    row.kind === NATIVE_EXTENSION_RUNTIME_KIND &&
+    row.identity === '-' &&
+    row.registration_artifact === '-'
+  );
+}
+
+function main(args) {
+  const [command, ...rest] = args;
+  if (rest.length !== 0) {
+    throw new Error(`${command ?? 'command'} does not accept arguments`);
+  }
+  switch (command) {
+    case 'header':
+      process.stdout.write(`${nativeExtensionAssetIndexHeaderTsv()}\n`);
+      return;
+    case 'runtime-kind':
+      process.stdout.write(`${nativeExtensionRuntimeKind()}\n`);
+      return;
+    default:
+      throw new Error('usage: native-extension-asset-index-contract.mts ');
+  }
+}
+
+if (import.meta.main) {
+  try {
+    main(process.argv.slice(2));
+  } catch (cause) {
+    console.error(cause instanceof Error ? cause.message : String(cause));
+    process.exitCode = 1;
+  }
+}
diff --git a/src/extensions/artifacts/native/tools/native-extension-asset-index-contract.test.mts b/src/extensions/artifacts/native/tools/native-extension-asset-index-contract.test.mts
new file mode 100644
index 000000000..7be89fbbe
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/native-extension-asset-index-contract.test.mts
@@ -0,0 +1,25 @@
+import { expect, test } from 'bun:test';
+
+import { isCanonicalNativeExtensionRuntimeIndexRow } from './native-extension-asset-index-contract.mts';
+
+test('the raw native extension index uses the canonical runtime carrier kind', () => {
+  const canonical = {
+    sql_name: 'amcheck',
+    target: 'linux-x64-gnu',
+    kind: 'runtime',
+    identity: '-',
+    artifact: 'amcheck.tar.gz',
+    artifact_bytes: '1',
+    registration_artifact: '-',
+  };
+  expect(isCanonicalNativeExtensionRuntimeIndexRow(canonical, 'linux-x64-gnu')).toBe(true);
+  expect(
+    isCanonicalNativeExtensionRuntimeIndexRow(
+      {
+        ...canonical,
+        kind: 'runtime-extension',
+      },
+      'linux-x64-gnu',
+    ),
+  ).toBe(false);
+});
diff --git a/src/extensions/artifacts/native/tools/package-release-assets.sh b/src/extensions/artifacts/native/tools/package-release-assets.sh
index 02d2dbc8a..d18acf4ce 100755
--- a/src/extensions/artifacts/native/tools/package-release-assets.sh
+++ b/src/extensions/artifacts/native/tools/package-release-assets.sh
@@ -17,14 +17,15 @@ require() {
   command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
 }
 
-source "$root/src/runtimes/liboliphaunt/native/bin/mobile-static-extensions.sh"
-packager="src/extensions/artifacts/native/tools/extension-artifact-packager.mjs"
+source "$root/src/runtimes/liboliphaunt-native/bin/mobile-static-extensions.sh"
+source "$root/src/runtimes/liboliphaunt-native/bin/build-output.bash"
+packager="src/extensions/artifacts/native/tools/extension-artifact-packager.mts"
 observed_phase="src/extensions/artifacts/native/tools/run-observed-phase.sh"
-native_asset_index_contract="tools/release/native-extension-asset-index-contract.mjs"
+native_asset_index_contract="src/extensions/artifacts/native/tools/native-extension-asset-index-contract.mts"
 
 target_id="${OLIPHAUNT_EXTENSION_TARGET:-${1:-}}"
 if [ -z "$target_id" ]; then
-  source "$root/src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh"
+  source "$root/src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh"
   target_id="$(oliphaunt_runtime_native_host_target_id)"
 fi
 case "$target_id" in
@@ -68,7 +69,7 @@ fi
 build_sql_names="$selected_sql_names"
 
 version="${OLIPHAUNT_EXTENSION_RELEASE_VERSION:-$(bun "$packager" product-version liboliphaunt-native)}"
-native_runtime_version="$(tr -d '[:space:]' < "$root/src/runtimes/liboliphaunt/native/VERSION")"
+native_runtime_version="$(tr -d '[:space:]' < "$root/src/runtimes/liboliphaunt-native/VERSION")"
 default_out_dir="$root/target/extensions/native/release-assets/$target_id"
 default_stage_root="$root/target/extensions/native/release-stage/$target_id"
 if [ -n "$extension_product" ] && [ -z "${OLIPHAUNT_EXTENSION_PRODUCTS:-}" ]; then
@@ -215,7 +216,11 @@ fetch_extension_source_assets() {
   "$observed_phase" \
     --label "fetch pinned native dependency sources" \
     --log /tmp/liboliphaunt-release-extension-assets-fetch.log \
-    -- bun src/sources/tools/fetch-sources.mjs native-runtime
+    -- bash src/third-party/tools/fetch-sources.sh native-runtime
+  "$observed_phase" \
+    --label "fetch pinned extension sources" \
+    --log /tmp/liboliphaunt-release-extension-assets-fetch.log \
+    -- bash src/third-party/tools/fetch-sources.sh extensions
 }
 
 archive_swiftpm_xcframework() {
@@ -223,7 +228,7 @@ archive_swiftpm_xcframework() {
   local output="$2"
   [ -d "$xcframework" ] || fail "missing SwiftPM XCFramework input at $xcframework"
   rm -f "$output"
-  tools/dev/bun.sh src/shared/artifact-packaging/archive-directory.mjs --keep-parent "$xcframework" "$output"
+  tools/dev/bun.sh tools/packaging/archive-directory.mts --keep-parent "$xcframework" "$output"
 }
 
 mobile_static_dependency_archive() {
@@ -321,7 +326,7 @@ prepare_extension_release_runtime() {
   rm -rf "$staged_runtime"
   mkdir -p "$staged_runtime"
   rsync -a --delete "$source_runtime/" "$staged_runtime/"
-  tools/dev/bun.sh src/shared/artifact-packaging/materialize-release-symlinks.mjs "$staged_runtime" >&2
+  tools/dev/bun.sh tools/packaging/materialize-release-symlinks.mts "$staged_runtime" >&2
   printf '%s\n' "$staged_runtime"
 }
 
@@ -329,7 +334,7 @@ prepare_windows_binary_contract_runtime() {
   local source_runtime="$1"
   local staged_runtime="$stage_root/windows-binary-contract-runtime"
   tools/dev/bun.sh \
-    src/extensions/artifacts/native/tools/stage-windows-binary-contract.mjs \
+    src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts \
     --runtime "$source_runtime" \
     --catalog "$catalog_file" \
     --selected-sql-names "$build_sql_names" \
@@ -348,7 +353,7 @@ build_desktop_extension_runtime() {
         OLIPHAUNT_WORK_ROOT="${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18-extension-release-$target_id}" \
         OLIPHAUNT_BUILD_EXTENSIONS=1 \
         OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES="$build_sql_names" \
-        src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh
+        src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh
       ;;
     linux-x64-gnu|linux-arm64-gnu)
       [ "$(uname -s)" = "Linux" ] || fail "$target_id extension artifacts must be built on Linux"
@@ -359,7 +364,7 @@ build_desktop_extension_runtime() {
         OLIPHAUNT_LINUX_WORK_ROOT="${OLIPHAUNT_LINUX_WORK_ROOT:-$root/target/liboliphaunt-pg18-$target_id-extension-release}" \
         OLIPHAUNT_BUILD_EXTENSIONS=1 \
         OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES="$build_sql_names" \
-        src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh
+        src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh
       ;;
     windows-x64-msvc)
       "$observed_phase" \
@@ -369,8 +374,7 @@ build_desktop_extension_runtime() {
         OLIPHAUNT_WINDOWS_WORK_ROOT="${OLIPHAUNT_WINDOWS_WORK_ROOT:-$root/target/liboliphaunt-pg18-$target_id-extension-release}" \
         OLIPHAUNT_BUILD_EXTENSIONS=1 \
         OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES="$build_sql_names" \
-        pwsh -NoLogo -NoProfile -ExecutionPolicy Bypass \
-          -File src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1
+        bash src/runtimes/liboliphaunt-native/bin/build-postgres18-windows.sh
       ;;
     *)
       fail "desktop extension runtime builder called for non-desktop target $target_id"
@@ -389,7 +393,7 @@ build_mobile_host_extension_runtime() {
         OLIPHAUNT_WORK_ROOT="${OLIPHAUNT_EXTENSION_MACOS_RUNTIME_ROOT:-$root/target/liboliphaunt-pg18-extension-release-$target_id}" \
         OLIPHAUNT_BUILD_EXTENSIONS=1 \
         OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES="$build_sql_names" \
-        src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh
+        src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh
       ;;
     android-*)
       [ "$(uname -s)" = "Linux" ] || fail "$target_id host extension runtime must be built on Linux"
@@ -400,7 +404,7 @@ build_mobile_host_extension_runtime() {
         OLIPHAUNT_LINUX_WORK_ROOT="${OLIPHAUNT_EXTENSION_LINUX_RUNTIME_ROOT:-$root/target/liboliphaunt-pg18-linux-x64-gnu-extension-release}" \
         OLIPHAUNT_BUILD_EXTENSIONS=1 \
         OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES="$build_sql_names" \
-        src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh
+        src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh
       ;;
     *)
       fail "mobile host extension runtime requested for non-mobile target $target_id"
@@ -411,26 +415,35 @@ build_mobile_host_extension_runtime() {
 build_mobile_static_artifacts() {
   local mobile_extensions="$1"
   local macos_runtime_root macos_archive_root
-  [ -n "$mobile_extensions" ] || return 0
+  if [ -z "$mobile_extensions" ]; then
+    [ "$target_id" != ios-xcframework ] || build_mobile_host_extension_runtime
+    return 0
+  fi
   case "$target_id" in
     ios-xcframework)
       [ "$(uname -s)" = "Darwin" ] || fail "$target_id extension artifacts must be built on macOS"
+      macos_runtime_root="${OLIPHAUNT_EXTENSION_MACOS_RUNTIME_ROOT:-$root/target/liboliphaunt-pg18-extension-release-$target_id}"
+      macos_archive_root="$mobile_extension_work_root/$target_id/macos-extension-archives"
+      simulator_lane() {
       "$observed_phase" \
         --label "build iOS simulator exact-extension archives" \
         --log /tmp/liboliphaunt-release-ios-simulator-extensions.log \
         -- env \
         OLIPHAUNT_IOS_SIMULATOR_ROOT="$mobile_extension_work_root/$target_id/ios-simulator" \
         OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$mobile_extensions" \
-        src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh
+        src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-simulator.sh
+      }
+      device_lane() {
       "$observed_phase" \
         --label "build iOS device exact-extension archives" \
         --log /tmp/liboliphaunt-release-ios-device-extensions.log \
         -- env \
         OLIPHAUNT_IOS_DEVICE_ROOT="$mobile_extension_work_root/$target_id/ios-device" \
         OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$mobile_extensions" \
-        src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-device.sh
-      macos_runtime_root="${OLIPHAUNT_EXTENSION_MACOS_RUNTIME_ROOT:-$root/target/liboliphaunt-pg18-extension-release-$target_id}"
-      macos_archive_root="$mobile_extension_work_root/$target_id/macos-extension-archives"
+        src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-device.sh
+      }
+      macos_lane() {
+        build_mobile_host_extension_runtime
       "$observed_phase" \
         --label "build macOS exact-extension static archives" \
         --log /tmp/liboliphaunt-release-macos-extension-archives.log \
@@ -438,7 +451,9 @@ build_mobile_static_artifacts() {
         OLIPHAUNT_MACOS_RUNTIME_ROOT="$macos_runtime_root" \
         OLIPHAUNT_MACOS_EXTENSION_ARCHIVE_ROOT="$macos_archive_root" \
         OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$mobile_extensions" \
-        src/runtimes/liboliphaunt/native/bin/build-macos-extension-archives.sh
+        src/runtimes/liboliphaunt-native/bin/build-macos-extension-archives.sh
+      }
+      oliphaunt_parallel_apple_builds macos_lane simulator_lane device_lane
       "$observed_phase" \
         --label "assemble iOS exact-extension XCFrameworks" \
         --log /tmp/liboliphaunt-release-ios-extension-xcframeworks.log \
@@ -448,7 +463,7 @@ build_mobile_static_artifacts() {
         OLIPHAUNT_MACOS_EXTENSION_OUT="$macos_archive_root/out" \
         OLIPHAUNT_IOS_EXTENSION_XCFRAMEWORK_ROOT="$mobile_extension_work_root/$target_id/ios-extension-xcframeworks" \
         OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$mobile_extensions" \
-        src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh
+        src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.sh
       ;;
     android-arm64-v8a)
       "$observed_phase" \
@@ -458,7 +473,7 @@ build_mobile_static_artifacts() {
         OLIPHAUNT_ANDROID_ARM64_ROOT="$mobile_extension_work_root/$target_id/android-arm64" \
         OLIPHAUNT_ANDROID_ABI=arm64-v8a \
         OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$mobile_extensions" \
-        src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh
+        src/runtimes/liboliphaunt-native/bin/build-postgres18-android-arm64.sh
       ;;
     android-x86_64)
       "$observed_phase" \
@@ -468,7 +483,7 @@ build_mobile_static_artifacts() {
         OLIPHAUNT_ANDROID_X86_64_ROOT="$mobile_extension_work_root/$target_id/android-x86_64" \
         OLIPHAUNT_ANDROID_ABI=x86_64 \
         OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$mobile_extensions" \
-        src/runtimes/liboliphaunt/native/bin/build-postgres18-android-x86_64.sh
+        src/runtimes/liboliphaunt-native/bin/build-postgres18-android-x86_64.sh
       ;;
   esac
 }
@@ -495,7 +510,6 @@ make_extension_artifact() {
   shift 8
 
   local -a artifact_args=(
-    "$packager" create-artifact
     --runtime "$runtime"
     --sql-name "$sql_name"
     --creates-extension "$creates_extension"
@@ -526,7 +540,7 @@ make_extension_artifact() {
   if [ "$#" -gt 0 ]; then
     artifact_args+=("$@")
   fi
-  bun "${artifact_args[@]}" >/tmp/liboliphaunt-release-extension-artifact-"$target_id"-"$sql_name".log
+  bash src/extensions/artifacts/native/tools/create-artifact.sh "${artifact_args[@]}" >/tmp/liboliphaunt-release-extension-artifact-"$target_id"-"$sql_name".log
 }
 
 package_desktop_target() {
@@ -538,20 +552,20 @@ package_desktop_target() {
   require_dir "$embedded_modules" "$target_id embedded extension modules"
   runtime="$(prepare_extension_release_runtime "$source_runtime")"
   if [ "$target_id" = "windows-x64-msvc" ]; then
-    tools/dev/bun.sh tools/release/windows-vc-runtime-closure.mjs verify \
+    tools/dev/bun.sh tools/packaging/windows-vc-runtime-closure.mts verify \
       --root "$runtime" \
       --profile provider \
       --search-root "$runtime/bin"
     binary_contract_runtime="$(prepare_windows_binary_contract_runtime "$runtime")"
-    tools/dev/bun.sh tools/release/platform-binary-contract.mjs \
+    tools/dev/bun.sh tools/packaging/platform-binary-contract.mts \
       --target "$target_id" \
       --root "$binary_contract_runtime" \
       --windows-vc-runtime-profile provider
   else
-    tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target_id" --root "$runtime"
+    tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target_id" --root "$runtime"
   fi
   if [[ "$target_id" == linux-*-gnu ]]; then
-    tools/release/check-linux-consumer-baseline.sh --target "$target_id" --root "$runtime"
+    tools/packaging/check-linux-consumer-baseline.sh --target "$target_id" --root "$runtime"
   fi
   local module_suffix
   module_suffix="$(module_suffix_for_target)"
@@ -585,19 +599,18 @@ package_desktop_target() {
 
 package_ios_target() {
   local source_runtime runtime mobile_extensions ios_sim_root ios_device_root macos_archive_root ios_xcframework_root
-  build_mobile_host_extension_runtime
   mobile_extensions="$(mobile_module_extensions_csv)"
   build_mobile_static_artifacts "$mobile_extensions"
   source_runtime="$(host_extension_runtime_root)"
   require_dir "$source_runtime" "mobile host extension runtime"
   runtime="$(prepare_extension_release_runtime "$source_runtime")"
-  tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target macos-arm64 --root "$runtime"
+  tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target macos-arm64 --root "$runtime"
   ios_sim_root="$mobile_extension_work_root/$target_id/ios-simulator"
   ios_device_root="$mobile_extension_work_root/$target_id/ios-device"
   macos_archive_root="$mobile_extension_work_root/$target_id/macos-extension-archives"
   ios_xcframework_root="$mobile_extension_work_root/$target_id/ios-extension-xcframeworks"
   require_dir "$ios_xcframework_root/out" "iOS extension XCFramework output"
-  tools/dev/bun.sh tools/release/platform-binary-contract.mjs \
+  tools/dev/bun.sh tools/packaging/platform-binary-contract.mts \
     --target "$target_id" \
     --root "$ios_xcframework_root/out" \
     --required-apple-platforms macos,ios,ios-simulator
@@ -645,7 +658,7 @@ package_ios_target() {
         mkdir -p "$stage_ios_extension/dependencies/$dependency"
         rsync -a --delete "$dependency_xcframework" "$stage_ios_extension/dependencies/$dependency/"
       done < <(oliphaunt_mobile_static_extension_dependencies_for_target "$sql_name" ios || true)
-      tools/dev/bun.sh tools/release/platform-binary-contract.mjs \
+      tools/dev/bun.sh tools/packaging/platform-binary-contract.mts \
         --target "$target_id" \
         --root "$stage_ios_extension" \
         --required-apple-platforms macos,ios,ios-simulator
@@ -654,7 +667,7 @@ package_ios_target() {
         "$out_dir/liboliphaunt-${version}-apple-spm-extension-$stem.zip"
       ios_artifact="liboliphaunt-${version}-apple-spm-extension-$stem.zip"
       registration_artifact="liboliphaunt-${version}-apple-spm-extension-$stem-registration.json"
-      bun tools/release/ios-extension-registration.mjs \
+      bash src/extensions/artifacts/native/tools/ios-extension-registration.sh \
         --sql-name "$sql_name" \
         --native-module-stem "$stem" \
         --simulator-out "$ios_sim_root/out" \
@@ -666,7 +679,7 @@ package_ios_target() {
         [ -n "$dependency" ] || continue
         dependency_xcframework="$ios_xcframework_root/out/dependencies/$dependency/liboliphaunt_dependency_$dependency.xcframework"
         require_dir "$dependency_xcframework" "iOS dependency XCFramework for $sql_name dependency $dependency"
-        tools/dev/bun.sh tools/release/platform-binary-contract.mjs \
+        tools/dev/bun.sh tools/packaging/platform-binary-contract.mts \
           --target "$target_id" \
           --root "$dependency_xcframework" \
           --required-apple-platforms macos,ios,ios-simulator
@@ -695,7 +708,7 @@ package_android_target() {
   source_runtime="$(host_extension_runtime_root)"
   require_dir "$source_runtime" "mobile host extension runtime"
   runtime="$(prepare_extension_release_runtime "$source_runtime")"
-  tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target linux-x64-gnu --root "$runtime"
+  tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target linux-x64-gnu --root "$runtime"
   case "$target_id" in
     android-arm64-v8a)
       android_root="$mobile_extension_work_root/$target_id/android-arm64"
@@ -707,7 +720,7 @@ package_android_target() {
       ;;
     *) fail "Android target packager called for $target_id" ;;
   esac
-  tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target_id" --root "$android_root/out"
+  tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target_id" --root "$android_root/out"
   local sql_name pg_major creates_extension stem dependencies shared_preload desktop_prebuilt mobile_prebuilt mobile_static_required mobile_static_targets data_files artifact_policy runtime_artifact android_archive static_prefix
   while IFS=$'\t' read -r sql_name pg_major creates_extension stem dependencies shared_preload desktop_prebuilt mobile_prebuilt mobile_static_required mobile_static_targets data_files artifact_policy; do
     [ -n "$sql_name" ] || continue
diff --git a/src/extensions/artifacts/native/tools/run-observed-phase.test.sh b/src/extensions/artifacts/native/tools/run-observed-phase.test.sh
index 1ed0c1d34..5336e4e73 100755
--- a/src/extensions/artifacts/native/tools/run-observed-phase.test.sh
+++ b/src/extensions/artifacts/native/tools/run-observed-phase.test.sh
@@ -2,8 +2,7 @@
 # shellcheck disable=SC2016
 set -euo pipefail
 
-root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd -P)"
-runner="$root/extensions/artifacts/native/tools/run-observed-phase.sh"
+runner="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)/run-observed-phase.sh"
 tmp="$(mktemp -d)"
 wrapper_pid=""
 child_pid=""
diff --git a/src/extensions/artifacts/native/tools/stage-windows-binary-contract.mjs b/src/extensions/artifacts/native/tools/stage-windows-binary-contract.mjs
deleted file mode 100644
index b49c8474e..000000000
--- a/src/extensions/artifacts/native/tools/stage-windows-binary-contract.mjs
+++ /dev/null
@@ -1,595 +0,0 @@
-#!/usr/bin/env bun
-
-import { createHash, randomUUID } from "node:crypto";
-import {
-  copyFile,
-  lstat,
-  mkdir,
-  readFile,
-  readdir,
-  realpath,
-  rename,
-  rm,
-  writeFile,
-} from "node:fs/promises";
-import path from "node:path";
-
-import { WINDOWS_VC_RUNTIME_DLLS } from "../../../../../tools/release/windows-vc-runtime-closure.mjs";
-import {
-  inspectPlatformBinaryBuffer,
-  inspectPlatformBinaryEntries,
-} from "../../../../../tools/release/platform-binary-contract.mjs";
-
-const TOOL = "stage-windows-binary-contract.mjs";
-const CATALOG_HEADER = Object.freeze([
-  "sql_name",
-  "pg_major",
-  "creates_extension",
-  "native_module_stem",
-  "dependencies",
-  "shared_preload",
-  "desktop_prebuilt",
-  "mobile_prebuilt",
-  "mobile_static_registry_required",
-  "mobile_static_archive_targets",
-  "data_files",
-  "artifact",
-]);
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function failure(message) {
-  return new Error(`${TOOL}: ${message}`);
-}
-
-export function validateWindowsEmbeddedModuleImports(data, label) {
-  const inspected = inspectPlatformBinaryBuffer(data, {
-    target: "windows-x64-msvc",
-    label,
-  });
-  const imports = new Set(
-    inspected.slices
-      .flatMap((slice) => slice.imports ?? [])
-      .map((name) => name.toLowerCase()),
-  );
-  if (imports.has("postgres.exe")) {
-    throw failure(
-      `${label} imports postgres.exe; embedded extension DLLs must not bind to the standalone server provider (they may bind to oliphaunt.dll or be host-neutral)`,
-    );
-  }
-  const providerBound = imports.has("oliphaunt.dll");
-  return {
-    imports: [...imports].sort(compareText),
-    backendProvider: providerBound ? "oliphaunt.dll" : "host-neutral",
-    hostNeutral: !providerBound,
-    providerBound,
-  };
-}
-
-export function validateWindowsServerModuleImports(data, label) {
-  const inspected = inspectPlatformBinaryBuffer(data, {
-    target: "windows-x64-msvc",
-    label,
-  });
-  const imports = new Set(
-    inspected.slices
-      .flatMap((slice) => slice.imports ?? [])
-      .map((name) => name.toLowerCase()),
-  );
-  if (imports.has("oliphaunt.dll")) {
-    throw failure(
-      `${label} imports oliphaunt.dll; standalone PostgreSQL extension DLLs must not bind to the embedded provider (they may bind to postgres.exe or be host-neutral)`,
-    );
-  }
-  const serverBound = imports.has("postgres.exe");
-  return {
-    imports: [...imports].sort(compareText),
-    backendProvider: serverBound ? "postgres.exe" : "host-neutral",
-    hostNeutral: !serverBound,
-    serverBound,
-  };
-}
-
-function sha256(data) {
-  return createHash("sha256").update(data).digest("hex");
-}
-
-function portableId(value, label) {
-  if (!/^[A-Za-z0-9._-]{1,128}$/u.test(value)) {
-    throw failure(
-      `${label} ${JSON.stringify(value)} is not a portable identifier`,
-    );
-  }
-  return value;
-}
-
-function parseSelection(value) {
-  if (value === undefined || value === null || value === "") return [];
-  const result = String(value)
-    .split(",")
-    .map((item) => portableId(item.trim(), "selected SQL name"));
-  if (result.some((item) => item.length === 0)) {
-    throw failure(
-      "selected SQL names must be a comma-separated list without empty entries",
-    );
-  }
-  if (new Set(result).size !== result.length) {
-    throw failure("selected SQL names contain duplicates");
-  }
-  return result;
-}
-
-export function parseExtensionCatalog(text, selectedSqlNames = "") {
-  const lines = String(text).replace(/\r\n/gu, "\n").split("\n");
-  if (lines.at(-1) === "") lines.pop();
-  if (lines.length === 0 || lines[0] !== CATALOG_HEADER.join("\t")) {
-    throw failure(
-      "extension catalog header does not match the exact native artifact schema",
-    );
-  }
-
-  const rows = new Map();
-  for (const [offset, line] of lines.slice(1).entries()) {
-    if (line.length === 0)
-      throw failure(`extension catalog row ${offset + 2} is empty`);
-    const columns = line.split("\t");
-    if (columns.length !== CATALOG_HEADER.length) {
-      throw failure(
-        `extension catalog row ${offset + 2} has ${columns.length} columns; expected ${CATALOG_HEADER.length}`,
-      );
-    }
-    const sqlName = portableId(
-      columns[0],
-      `extension catalog row ${offset + 2} SQL name`,
-    );
-    if (rows.has(sqlName))
-      throw failure(`extension catalog repeats SQL name ${sqlName}`);
-    if (columns[1] !== "18")
-      throw failure(
-        `extension catalog ${sqlName} targets PostgreSQL ${columns[1]}, not 18`,
-      );
-    if (!["yes", "no"].includes(columns[6])) {
-      throw failure(
-        `extension catalog ${sqlName} has invalid desktop_prebuilt value ${JSON.stringify(columns[6])}`,
-      );
-    }
-    const stem =
-      columns[3] === "-"
-        ? null
-        : portableId(columns[3], `extension catalog ${sqlName} module stem`);
-    rows.set(sqlName, { sqlName, stem, desktopPrebuilt: columns[6] === "yes" });
-  }
-
-  const requested = parseSelection(selectedSqlNames);
-  const selected =
-    requested.length === 0
-      ? [...rows.values()].filter(({ desktopPrebuilt }) => desktopPrebuilt)
-      : requested.map((sqlName) => {
-          const row = rows.get(sqlName);
-          if (row === undefined)
-            throw failure(
-              `selected SQL name ${sqlName} is absent from the extension catalog`,
-            );
-          if (!row.desktopPrebuilt)
-            throw failure(
-              `selected SQL name ${sqlName} is not a desktop prebuilt extension`,
-            );
-          return row;
-        });
-  return selected.sort((left, right) =>
-    compareText(left.sqlName, right.sqlName),
-  );
-}
-
-function containsPath(parent, candidate) {
-  const comparableParent =
-    process.platform === "win32" ? parent.toLowerCase() : parent;
-  const comparableCandidate =
-    process.platform === "win32" ? candidate.toLowerCase() : candidate;
-  const relative = path.relative(comparableParent, comparableCandidate);
-  return (
-    relative === "" ||
-    (!path.isAbsolute(relative) &&
-      relative !== ".." &&
-      !relative.startsWith(`..${path.sep}`))
-  );
-}
-
-async function canonicalProspectivePath(candidate) {
-  const suffix = [];
-  let current = path.resolve(candidate);
-  while (true) {
-    const stat = await lstat(current).catch((error) => {
-      if (error?.code === "ENOENT") return null;
-      throw failure(
-        `cannot inspect prospective binary-contract output ancestor ${current}: ${error.message}`,
-      );
-    });
-    if (stat !== null) {
-      const canonical = await realpath(current).catch((error) => {
-        throw failure(
-          `cannot resolve prospective binary-contract output ancestor ${current}: ${error.message}`,
-        );
-      });
-      if (suffix.length > 0 && !(await lstat(canonical)).isDirectory()) {
-        throw failure(
-          `prospective binary-contract output ancestor ${current} is not a directory`,
-        );
-      }
-      return path.resolve(canonical, ...suffix);
-    }
-    const parent = path.dirname(current);
-    if (parent === current) {
-      throw failure(
-        `cannot find an existing ancestor for binary-contract output ${candidate}`,
-      );
-    }
-    suffix.unshift(path.basename(current));
-    current = parent;
-  }
-}
-
-async function requireRealDirectory(directory, label) {
-  const stat = await lstat(directory).catch(() => null);
-  if (stat === null || !stat.isDirectory() || stat.isSymbolicLink()) {
-    throw failure(`${label} ${directory} must be a real directory`);
-  }
-  return realpath(directory);
-}
-
-async function copyContainedFile(
-  runtimeRoot,
-  runtimeReal,
-  relativePath,
-  stageRoot,
-) {
-  const source = path.join(runtimeRoot, ...relativePath.split("/"));
-  const stat = await lstat(source).catch(() => null);
-  if (stat === null || !stat.isFile() || stat.isSymbolicLink()) {
-    throw failure(
-      `required Windows carrier file ${relativePath} must be a real regular file under ${runtimeRoot}`,
-    );
-  }
-  const sourceReal = await realpath(source);
-  if (!containsPath(runtimeReal, sourceReal)) {
-    throw failure(
-      `required Windows carrier file ${relativePath} resolves outside ${runtimeRoot}`,
-    );
-  }
-  const destination = path.join(stageRoot, ...relativePath.split("/"));
-  await mkdir(path.dirname(destination), { recursive: true });
-  await copyFile(source, destination);
-  return relativePath;
-}
-
-async function collectArtifactEntries(
-  artifactRoot,
-  artifactReal,
-  relative = "",
-) {
-  const entries = [];
-  const directory = path.join(artifactRoot, relative);
-  const children = await readdir(directory, { withFileTypes: true });
-  children.sort((left, right) => compareText(left.name, right.name));
-  for (const child of children) {
-    const childRelative = relative ? `${relative}/${child.name}` : child.name;
-    const childPath = path.join(artifactRoot, ...childRelative.split("/"));
-    const stat = await lstat(childPath);
-    if (stat.isSymbolicLink()) {
-      throw failure(
-        `exact Windows extension artifact contains symbolic link ${childRelative}`,
-      );
-    }
-    if (stat.isDirectory()) {
-      entries.push(
-        ...(await collectArtifactEntries(
-          artifactRoot,
-          artifactReal,
-          childRelative,
-        )),
-      );
-      continue;
-    }
-    if (!stat.isFile()) {
-      throw failure(
-        `exact Windows extension artifact contains non-regular entry ${childRelative}`,
-      );
-    }
-    const childReal = await realpath(childPath);
-    if (!containsPath(artifactReal, childReal)) {
-      throw failure(
-        `exact Windows extension artifact file ${childRelative} resolves outside ${artifactRoot}`,
-      );
-    }
-    entries.push({
-      name: `artifact/${childRelative}`,
-      data: await readFile(childPath),
-      isFile: true,
-    });
-  }
-  return entries;
-}
-
-export async function validateWindowsExtensionArtifactBinaryContract({
-  artifactRoot,
-  providerRuntimeRoot,
-}) {
-  if (!artifactRoot) throw failure("artifactRoot is required");
-  if (!providerRuntimeRoot) throw failure("providerRuntimeRoot is required");
-  const artifact = path.resolve(artifactRoot);
-  const provider = path.resolve(providerRuntimeRoot);
-  const artifactReal = await requireRealDirectory(
-    artifact,
-    "exact Windows extension artifact root",
-  );
-  const providerReal = await requireRealDirectory(
-    provider,
-    "Windows provider runtime root",
-  );
-  const entries = await collectArtifactEntries(artifact, artifactReal);
-  const serverModules = new Map();
-  const embeddedModules = new Map();
-  for (const entry of entries) {
-    if (/^artifact\/files\/lib\/postgresql\/[^/]+\.dll$/iu.test(entry.name)) {
-      const moduleName = path.posix.basename(entry.name);
-      serverModules.set(moduleName, {
-        data: entry.data,
-        ...validateWindowsServerModuleImports(entry.data, entry.name),
-      });
-    } else if (/^artifact\/files\/lib\/modules\/[^/]+\.dll$/iu.test(entry.name)) {
-      const moduleName = path.posix.basename(entry.name);
-      embeddedModules.set(moduleName, {
-        data: entry.data,
-        ...validateWindowsEmbeddedModuleImports(entry.data, entry.name),
-      });
-    }
-  }
-  const moduleNames = [
-    ...new Set([...serverModules.keys(), ...embeddedModules.keys()]),
-  ].sort(compareText);
-  for (const moduleName of moduleNames) {
-    if (!serverModules.has(moduleName)) {
-      throw failure(
-        `exact Windows extension artifact is missing standalone server profile files/lib/postgresql/${moduleName}`,
-      );
-    }
-    if (!embeddedModules.has(moduleName)) {
-      throw failure(
-        `exact Windows extension artifact is missing embedded provider profile files/lib/modules/${moduleName}`,
-      );
-    }
-    const serverModule = serverModules.get(moduleName);
-    const embeddedModule = embeddedModules.get(moduleName);
-    const serverDigest = sha256(serverModule.data);
-    const embeddedDigest = sha256(embeddedModule.data);
-    if (
-      serverDigest === embeddedDigest &&
-      !(serverModule.hostNeutral && embeddedModule.hostNeutral)
-    ) {
-      throw failure(
-        `exact Windows extension artifact ${moduleName} host-bound server and embedded profiles have identical SHA-256 ${serverDigest}`,
-      );
-    }
-  }
-  for (const name of WINDOWS_VC_RUNTIME_DLLS) {
-    const relativePath = `bin/${name}`;
-    const source = path.join(provider, ...relativePath.split("/"));
-    const stat = await lstat(source).catch(() => null);
-    if (stat === null || !stat.isFile() || stat.isSymbolicLink()) {
-      throw failure(
-        `required Windows carrier file ${relativePath} must be a real regular file under ${provider}`,
-      );
-    }
-    const sourceReal = await realpath(source);
-    if (!containsPath(providerReal, sourceReal)) {
-      throw failure(
-        `required Windows carrier file ${relativePath} resolves outside ${provider}`,
-      );
-    }
-    entries.push({
-      name: `provider/${relativePath}`,
-      data: await readFile(source),
-      isFile: true,
-    });
-  }
-  const inspection = inspectPlatformBinaryEntries(entries, {
-    target: "windows-x64-msvc",
-    rootLabel: "exact Windows extension artifact with provider runtime",
-    windowsVcRuntimeProfile: "provider",
-  });
-  return {
-    ...inspection,
-    standaloneBackendProvider: "postgres.exe",
-    embeddedBackendProvider: "oliphaunt.dll",
-    serverBoundExtensionModules: moduleNames.filter(
-      (moduleName) => serverModules.get(moduleName).serverBound,
-    ),
-    hostNeutralServerModules: moduleNames.filter(
-      (moduleName) => serverModules.get(moduleName).hostNeutral,
-    ),
-    providerBoundEmbeddedModules: moduleNames.filter(
-      (moduleName) => embeddedModules.get(moduleName).providerBound,
-    ),
-    hostNeutralEmbeddedModules: moduleNames.filter(
-      (moduleName) => embeddedModules.get(moduleName).hostNeutral,
-    ),
-    byteIdenticalHostNeutralModules: moduleNames.filter((moduleName) => {
-      const serverModule = serverModules.get(moduleName);
-      const embeddedModule = embeddedModules.get(moduleName);
-      return (
-        serverModule.hostNeutral &&
-        embeddedModule.hostNeutral &&
-        sha256(serverModule.data) === sha256(embeddedModule.data)
-      );
-    }),
-    profileBindings: Object.fromEntries(
-      moduleNames.map((moduleName) => [
-        moduleName,
-        {
-          server: serverModules.get(moduleName).backendProvider,
-          embedded: embeddedModules.get(moduleName).backendProvider,
-        },
-      ]),
-    ),
-    profileSha256: Object.fromEntries(
-      moduleNames.map((moduleName) => [
-        moduleName,
-        {
-          server: sha256(serverModules.get(moduleName).data),
-          embedded: sha256(embeddedModules.get(moduleName).data),
-        },
-      ]),
-    ),
-  };
-}
-
-export async function stageWindowsExtensionBinaryContract({
-  runtimeRoot,
-  catalogText,
-  selectedSqlNames = "",
-  outputRoot,
-}) {
-  if (!runtimeRoot) throw failure("runtimeRoot is required");
-  if (catalogText === undefined) throw failure("catalogText is required");
-  if (!outputRoot) throw failure("outputRoot is required");
-
-  const runtime = path.resolve(runtimeRoot);
-  const output = path.resolve(outputRoot);
-  const runtimeReal = await requireRealDirectory(
-    runtime,
-    "Windows extension runtime root",
-  );
-  const outputStat = await lstat(output).catch((error) => {
-    if (error?.code === "ENOENT") return null;
-    throw failure(
-      `cannot inspect binary-contract output ${output}: ${error.message}`,
-    );
-  });
-  if (
-    outputStat !== null &&
-    (!outputStat.isDirectory() || outputStat.isSymbolicLink())
-  ) {
-    throw failure(
-      `existing binary-contract output ${output} must be a real directory`,
-    );
-  }
-  const outputCanonical = await canonicalProspectivePath(output);
-  if (
-    containsPath(runtimeReal, outputCanonical) ||
-    containsPath(outputCanonical, runtimeReal)
-  ) {
-    throw failure("binary-contract output must not overlap the source runtime");
-  }
-
-  const selected = parseExtensionCatalog(catalogText, selectedSqlNames);
-  const moduleNames = [
-    ...new Set(selected.map(({ stem }) => stem).filter(Boolean)),
-  ].sort();
-  const serverBoundExtensionModules = [];
-  const hostNeutralServerModules = [];
-  const partial = `${output}.partial-${process.pid}-${randomUUID()}`;
-  await rm(partial, { recursive: true, force: true });
-  try {
-    await mkdir(partial, { recursive: true });
-    const files = [];
-    for (const name of WINDOWS_VC_RUNTIME_DLLS) {
-      files.push(
-        await copyContainedFile(runtime, runtimeReal, `bin/${name}`, partial),
-      );
-    }
-    for (const stem of moduleNames) {
-      const relativePath = await copyContainedFile(
-        runtime,
-        runtimeReal,
-        `lib/postgresql/${stem}.dll`,
-        partial,
-      );
-      const binding = validateWindowsServerModuleImports(
-        await readFile(path.join(partial, ...relativePath.split("/"))),
-        relativePath,
-      );
-      if (binding.serverBound) {
-        serverBoundExtensionModules.push(`${stem}.dll`);
-      } else {
-        hostNeutralServerModules.push(`${stem}.dll`);
-      }
-      files.push(relativePath);
-    }
-    const manifest = {
-      schema: "oliphaunt-windows-extension-binary-contract-v4",
-      selectedSqlNames: selected.map(({ sqlName }) => sqlName),
-      standaloneBackendProvider: "postgres.exe",
-      forbiddenEmbeddedBackendProvider: "oliphaunt.dll",
-      providerRuntimeDlls: [...WINDOWS_VC_RUNTIME_DLLS],
-      extensionModules: moduleNames.map((stem) => `${stem}.dll`),
-      serverBoundExtensionModules,
-      hostNeutralServerModules,
-      files: [...files].sort(),
-    };
-    await writeFile(
-      path.join(partial, "binary-contract-manifest.json"),
-      `${JSON.stringify(manifest, null, 2)}\n`,
-      "utf8",
-    );
-    await rm(output, { recursive: true, force: true });
-    await mkdir(path.dirname(output), { recursive: true });
-    await rename(partial, output);
-    return manifest;
-  } catch (error) {
-    await rm(partial, { recursive: true, force: true });
-    throw error;
-  }
-}
-
-function usage() {
-  return `usage: ${TOOL} --runtime DIR --catalog FILE --output DIR [--selected-sql-names CSV]\n`;
-}
-
-function parseArgs(argv) {
-  const args = { runtime: "", catalog: "", output: "", selectedSqlNames: "" };
-  for (let index = 0; index < argv.length; index += 1) {
-    const flag = argv[index];
-    if (flag === "--help" || flag === "-h") return { help: true };
-    const value = argv[++index];
-    if (value === undefined) throw failure(`${flag} requires a value`);
-    if (flag === "--runtime") args.runtime = value;
-    else if (flag === "--catalog") args.catalog = value;
-    else if (flag === "--output") args.output = value;
-    else if (flag === "--selected-sql-names") args.selectedSqlNames = value;
-    else throw failure(`unknown argument ${flag}`);
-  }
-  return args;
-}
-
-async function main(argv) {
-  const args = parseArgs(argv);
-  if (args.help) {
-    process.stdout.write(usage());
-    return;
-  }
-  if (!args.runtime || !args.catalog || !args.output) {
-    process.stderr.write(usage());
-    process.exitCode = 2;
-    return;
-  }
-  const manifest = await stageWindowsExtensionBinaryContract({
-    runtimeRoot: args.runtime,
-    catalogText: await readFile(args.catalog, "utf8"),
-    selectedSqlNames: args.selectedSqlNames,
-    outputRoot: args.output,
-  });
-  console.log(
-    `Windows server extension binary-contract view staged: modules=${manifest.extensionModules.length} serverBound=${manifest.serverBoundExtensionModules.length} hostNeutral=${manifest.hostNeutralServerModules.length} providerDlls=${manifest.providerRuntimeDlls.length}`,
-  );
-}
-
-if (import.meta.main) {
-  try {
-    await main(Bun.argv.slice(2));
-  } catch (error) {
-    console.error(error instanceof Error ? error.message : String(error));
-    process.exit(1);
-  }
-}
diff --git a/src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts b/src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts
new file mode 100644
index 000000000..e8a66c57e
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts
@@ -0,0 +1,521 @@
+#!/usr/bin/env bun
+
+import { createHash, randomUUID } from 'node:crypto';
+import {
+  copyFile,
+  lstat,
+  mkdir,
+  readFile,
+  readdir,
+  realpath,
+  rename,
+  rm,
+  writeFile,
+} from 'node:fs/promises';
+import path from 'node:path';
+
+import { WINDOWS_VC_RUNTIME_DLLS } from '../../../../../tools/packaging/windows-vc-runtime-closure.mts';
+import {
+  inspectPlatformBinaryBuffer,
+  inspectPlatformBinaryEntries,
+} from '../../../../../tools/packaging/platform-binary-contract.mts';
+
+const TOOL = 'stage-windows-binary-contract.mts';
+const CATALOG_HEADER = Object.freeze([
+  'sql_name',
+  'pg_major',
+  'creates_extension',
+  'native_module_stem',
+  'dependencies',
+  'shared_preload',
+  'desktop_prebuilt',
+  'mobile_prebuilt',
+  'mobile_static_registry_required',
+  'mobile_static_archive_targets',
+  'data_files',
+  'artifact',
+]);
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function failure(message) {
+  return new Error(`${TOOL}: ${message}`);
+}
+
+export function validateWindowsEmbeddedModuleImports(data, label) {
+  const inspected = inspectPlatformBinaryBuffer(data, {
+    target: 'windows-x64-msvc',
+    label,
+  });
+  const imports = new Set(
+    inspected.slices.flatMap((slice) => slice.imports ?? []).map((name) => name.toLowerCase()),
+  );
+  if (imports.has('postgres.exe')) {
+    throw failure(
+      `${label} imports postgres.exe; embedded extension DLLs must not bind to the standalone server provider (they may bind to oliphaunt.dll or be host-neutral)`,
+    );
+  }
+  const providerBound = imports.has('oliphaunt.dll');
+  return {
+    imports: [...imports].sort(compareText),
+    backendProvider: providerBound ? 'oliphaunt.dll' : 'host-neutral',
+    hostNeutral: !providerBound,
+    providerBound,
+  };
+}
+
+export function validateWindowsServerModuleImports(data, label) {
+  const inspected = inspectPlatformBinaryBuffer(data, {
+    target: 'windows-x64-msvc',
+    label,
+  });
+  const imports = new Set(
+    inspected.slices.flatMap((slice) => slice.imports ?? []).map((name) => name.toLowerCase()),
+  );
+  if (imports.has('oliphaunt.dll')) {
+    throw failure(
+      `${label} imports oliphaunt.dll; standalone PostgreSQL extension DLLs must not bind to the embedded provider (they may bind to postgres.exe or be host-neutral)`,
+    );
+  }
+  const serverBound = imports.has('postgres.exe');
+  return {
+    imports: [...imports].sort(compareText),
+    backendProvider: serverBound ? 'postgres.exe' : 'host-neutral',
+    hostNeutral: !serverBound,
+    serverBound,
+  };
+}
+
+function sha256(data) {
+  return createHash('sha256').update(data).digest('hex');
+}
+
+function portableId(value, label) {
+  if (!/^[A-Za-z0-9._-]{1,128}$/u.test(value)) {
+    throw failure(`${label} ${JSON.stringify(value)} is not a portable identifier`);
+  }
+  return value;
+}
+
+function parseSelection(value) {
+  if (value === undefined || value === null || value === '') return [];
+  const result = String(value)
+    .split(',')
+    .map((item) => portableId(item.trim(), 'selected SQL name'));
+  if (result.some((item) => item.length === 0)) {
+    throw failure('selected SQL names must be a comma-separated list without empty entries');
+  }
+  if (new Set(result).size !== result.length) {
+    throw failure('selected SQL names contain duplicates');
+  }
+  return result;
+}
+
+export function parseExtensionCatalog(text, selectedSqlNames = '') {
+  const lines = String(text).replace(/\r\n/gu, '\n').split('\n');
+  if (lines.at(-1) === '') lines.pop();
+  if (lines.length === 0 || lines[0] !== CATALOG_HEADER.join('\t')) {
+    throw failure('extension catalog header does not match the exact native artifact schema');
+  }
+
+  const rows = new Map();
+  for (const [offset, line] of lines.slice(1).entries()) {
+    if (line.length === 0) throw failure(`extension catalog row ${offset + 2} is empty`);
+    const columns = line.split('\t');
+    if (columns.length !== CATALOG_HEADER.length) {
+      throw failure(
+        `extension catalog row ${offset + 2} has ${columns.length} columns; expected ${CATALOG_HEADER.length}`,
+      );
+    }
+    const sqlName = portableId(columns[0], `extension catalog row ${offset + 2} SQL name`);
+    if (rows.has(sqlName)) throw failure(`extension catalog repeats SQL name ${sqlName}`);
+    if (columns[1] !== '18')
+      throw failure(`extension catalog ${sqlName} targets PostgreSQL ${columns[1]}, not 18`);
+    if (!['yes', 'no'].includes(columns[6])) {
+      throw failure(
+        `extension catalog ${sqlName} has invalid desktop_prebuilt value ${JSON.stringify(columns[6])}`,
+      );
+    }
+    const stem =
+      columns[3] === '-'
+        ? null
+        : portableId(columns[3], `extension catalog ${sqlName} module stem`);
+    rows.set(sqlName, { sqlName, stem, desktopPrebuilt: columns[6] === 'yes' });
+  }
+
+  const requested = parseSelection(selectedSqlNames);
+  const selected =
+    requested.length === 0
+      ? [...rows.values()].filter(({ desktopPrebuilt }) => desktopPrebuilt)
+      : requested.map((sqlName) => {
+          const row = rows.get(sqlName);
+          if (row === undefined)
+            throw failure(`selected SQL name ${sqlName} is absent from the extension catalog`);
+          if (!row.desktopPrebuilt)
+            throw failure(`selected SQL name ${sqlName} is not a desktop prebuilt extension`);
+          return row;
+        });
+  return selected.sort((left, right) => compareText(left.sqlName, right.sqlName));
+}
+
+function containsPath(parent, candidate) {
+  const comparableParent = process.platform === 'win32' ? parent.toLowerCase() : parent;
+  const comparableCandidate = process.platform === 'win32' ? candidate.toLowerCase() : candidate;
+  const relative = path.relative(comparableParent, comparableCandidate);
+  return (
+    relative === '' ||
+    (!path.isAbsolute(relative) && relative !== '..' && !relative.startsWith(`..${path.sep}`))
+  );
+}
+
+async function canonicalProspectivePath(candidate) {
+  const suffix = [];
+  let current = path.resolve(candidate);
+  while (true) {
+    const stat = await lstat(current).catch((error) => {
+      if (error?.code === 'ENOENT') return null;
+      throw failure(
+        `cannot inspect prospective binary-contract output ancestor ${current}: ${error.message}`,
+      );
+    });
+    if (stat !== null) {
+      const canonical = await realpath(current).catch((error) => {
+        throw failure(
+          `cannot resolve prospective binary-contract output ancestor ${current}: ${error.message}`,
+        );
+      });
+      if (suffix.length > 0 && !(await lstat(canonical)).isDirectory()) {
+        throw failure(`prospective binary-contract output ancestor ${current} is not a directory`);
+      }
+      return path.resolve(canonical, ...suffix);
+    }
+    const parent = path.dirname(current);
+    if (parent === current) {
+      throw failure(`cannot find an existing ancestor for binary-contract output ${candidate}`);
+    }
+    suffix.unshift(path.basename(current));
+    current = parent;
+  }
+}
+
+async function requireRealDirectory(directory, label) {
+  const stat = await lstat(directory).catch(() => null);
+  if (stat === null || !stat.isDirectory() || stat.isSymbolicLink()) {
+    throw failure(`${label} ${directory} must be a real directory`);
+  }
+  return realpath(directory);
+}
+
+async function copyContainedFile(runtimeRoot, runtimeReal, relativePath, stageRoot) {
+  const source = path.join(runtimeRoot, ...relativePath.split('/'));
+  const stat = await lstat(source).catch(() => null);
+  if (stat === null || !stat.isFile() || stat.isSymbolicLink()) {
+    throw failure(
+      `required Windows carrier file ${relativePath} must be a real regular file under ${runtimeRoot}`,
+    );
+  }
+  const sourceReal = await realpath(source);
+  if (!containsPath(runtimeReal, sourceReal)) {
+    throw failure(`required Windows carrier file ${relativePath} resolves outside ${runtimeRoot}`);
+  }
+  const destination = path.join(stageRoot, ...relativePath.split('/'));
+  await mkdir(path.dirname(destination), { recursive: true });
+  await copyFile(source, destination);
+  return relativePath;
+}
+
+async function collectArtifactEntries(artifactRoot, artifactReal, relative = '') {
+  const entries = [];
+  const directory = path.join(artifactRoot, relative);
+  const children = await readdir(directory, { withFileTypes: true });
+  children.sort((left, right) => compareText(left.name, right.name));
+  for (const child of children) {
+    const childRelative = relative ? `${relative}/${child.name}` : child.name;
+    const childPath = path.join(artifactRoot, ...childRelative.split('/'));
+    const stat = await lstat(childPath);
+    if (stat.isSymbolicLink()) {
+      throw failure(`exact Windows extension artifact contains symbolic link ${childRelative}`);
+    }
+    if (stat.isDirectory()) {
+      entries.push(...(await collectArtifactEntries(artifactRoot, artifactReal, childRelative)));
+      continue;
+    }
+    if (!stat.isFile()) {
+      throw failure(`exact Windows extension artifact contains non-regular entry ${childRelative}`);
+    }
+    const childReal = await realpath(childPath);
+    if (!containsPath(artifactReal, childReal)) {
+      throw failure(
+        `exact Windows extension artifact file ${childRelative} resolves outside ${artifactRoot}`,
+      );
+    }
+    entries.push({
+      name: `artifact/${childRelative}`,
+      data: await readFile(childPath),
+      isFile: true,
+    });
+  }
+  return entries;
+}
+
+export async function validateWindowsExtensionArtifactBinaryContract({
+  artifactRoot,
+  providerRuntimeRoot,
+}) {
+  if (!artifactRoot) throw failure('artifactRoot is required');
+  if (!providerRuntimeRoot) throw failure('providerRuntimeRoot is required');
+  const artifact = path.resolve(artifactRoot);
+  const provider = path.resolve(providerRuntimeRoot);
+  const artifactReal = await requireRealDirectory(
+    artifact,
+    'exact Windows extension artifact root',
+  );
+  const providerReal = await requireRealDirectory(provider, 'Windows provider runtime root');
+  const entries = await collectArtifactEntries(artifact, artifactReal);
+  const serverModules = new Map();
+  const embeddedModules = new Map();
+  for (const entry of entries) {
+    if (/^artifact\/files\/lib\/postgresql\/[^/]+\.dll$/iu.test(entry.name)) {
+      const moduleName = path.posix.basename(entry.name);
+      serverModules.set(moduleName, {
+        data: entry.data,
+        ...validateWindowsServerModuleImports(entry.data, entry.name),
+      });
+    } else if (/^artifact\/files\/lib\/modules\/[^/]+\.dll$/iu.test(entry.name)) {
+      const moduleName = path.posix.basename(entry.name);
+      embeddedModules.set(moduleName, {
+        data: entry.data,
+        ...validateWindowsEmbeddedModuleImports(entry.data, entry.name),
+      });
+    }
+  }
+  const moduleNames = [...new Set([...serverModules.keys(), ...embeddedModules.keys()])].sort(
+    compareText,
+  );
+  for (const moduleName of moduleNames) {
+    if (!serverModules.has(moduleName)) {
+      throw failure(
+        `exact Windows extension artifact is missing standalone server profile files/lib/postgresql/${moduleName}`,
+      );
+    }
+    if (!embeddedModules.has(moduleName)) {
+      throw failure(
+        `exact Windows extension artifact is missing embedded provider profile files/lib/modules/${moduleName}`,
+      );
+    }
+    const serverModule = serverModules.get(moduleName);
+    const embeddedModule = embeddedModules.get(moduleName);
+    const serverDigest = sha256(serverModule.data);
+    const embeddedDigest = sha256(embeddedModule.data);
+    if (
+      serverDigest === embeddedDigest &&
+      !(serverModule.hostNeutral && embeddedModule.hostNeutral)
+    ) {
+      throw failure(
+        `exact Windows extension artifact ${moduleName} host-bound server and embedded profiles have identical SHA-256 ${serverDigest}`,
+      );
+    }
+  }
+  for (const name of WINDOWS_VC_RUNTIME_DLLS) {
+    const relativePath = `bin/${name}`;
+    const source = path.join(provider, ...relativePath.split('/'));
+    const stat = await lstat(source).catch(() => null);
+    if (stat === null || !stat.isFile() || stat.isSymbolicLink()) {
+      throw failure(
+        `required Windows carrier file ${relativePath} must be a real regular file under ${provider}`,
+      );
+    }
+    const sourceReal = await realpath(source);
+    if (!containsPath(providerReal, sourceReal)) {
+      throw failure(`required Windows carrier file ${relativePath} resolves outside ${provider}`);
+    }
+    entries.push({
+      name: `provider/${relativePath}`,
+      data: await readFile(source),
+      isFile: true,
+    });
+  }
+  const inspection = inspectPlatformBinaryEntries(entries, {
+    target: 'windows-x64-msvc',
+    rootLabel: 'exact Windows extension artifact with provider runtime',
+    windowsVcRuntimeProfile: 'provider',
+  });
+  return {
+    ...inspection,
+    standaloneBackendProvider: 'postgres.exe',
+    embeddedBackendProvider: 'oliphaunt.dll',
+    serverBoundExtensionModules: moduleNames.filter(
+      (moduleName) => serverModules.get(moduleName).serverBound,
+    ),
+    hostNeutralServerModules: moduleNames.filter(
+      (moduleName) => serverModules.get(moduleName).hostNeutral,
+    ),
+    providerBoundEmbeddedModules: moduleNames.filter(
+      (moduleName) => embeddedModules.get(moduleName).providerBound,
+    ),
+    hostNeutralEmbeddedModules: moduleNames.filter(
+      (moduleName) => embeddedModules.get(moduleName).hostNeutral,
+    ),
+    byteIdenticalHostNeutralModules: moduleNames.filter((moduleName) => {
+      const serverModule = serverModules.get(moduleName);
+      const embeddedModule = embeddedModules.get(moduleName);
+      return (
+        serverModule.hostNeutral &&
+        embeddedModule.hostNeutral &&
+        sha256(serverModule.data) === sha256(embeddedModule.data)
+      );
+    }),
+    profileBindings: Object.fromEntries(
+      moduleNames.map((moduleName) => [
+        moduleName,
+        {
+          server: serverModules.get(moduleName).backendProvider,
+          embedded: embeddedModules.get(moduleName).backendProvider,
+        },
+      ]),
+    ),
+    profileSha256: Object.fromEntries(
+      moduleNames.map((moduleName) => [
+        moduleName,
+        {
+          server: sha256(serverModules.get(moduleName).data),
+          embedded: sha256(embeddedModules.get(moduleName).data),
+        },
+      ]),
+    ),
+  };
+}
+
+export async function stageWindowsExtensionBinaryContract({
+  runtimeRoot,
+  catalogText,
+  selectedSqlNames = '',
+  outputRoot,
+}) {
+  if (!runtimeRoot) throw failure('runtimeRoot is required');
+  if (catalogText === undefined) throw failure('catalogText is required');
+  if (!outputRoot) throw failure('outputRoot is required');
+
+  const runtime = path.resolve(runtimeRoot);
+  const output = path.resolve(outputRoot);
+  const runtimeReal = await requireRealDirectory(runtime, 'Windows extension runtime root');
+  const outputStat = await lstat(output).catch((error) => {
+    if (error?.code === 'ENOENT') return null;
+    throw failure(`cannot inspect binary-contract output ${output}: ${error.message}`);
+  });
+  if (outputStat !== null && (!outputStat.isDirectory() || outputStat.isSymbolicLink())) {
+    throw failure(`existing binary-contract output ${output} must be a real directory`);
+  }
+  const outputCanonical = await canonicalProspectivePath(output);
+  if (containsPath(runtimeReal, outputCanonical) || containsPath(outputCanonical, runtimeReal)) {
+    throw failure('binary-contract output must not overlap the source runtime');
+  }
+
+  const selected = parseExtensionCatalog(catalogText, selectedSqlNames);
+  const moduleNames = [...new Set(selected.map(({ stem }) => stem).filter(Boolean))].sort();
+  const serverBoundExtensionModules = [];
+  const hostNeutralServerModules = [];
+  const partial = `${output}.partial-${process.pid}-${randomUUID()}`;
+  await rm(partial, { recursive: true, force: true });
+  try {
+    await mkdir(partial, { recursive: true });
+    const files = [];
+    for (const name of WINDOWS_VC_RUNTIME_DLLS) {
+      files.push(await copyContainedFile(runtime, runtimeReal, `bin/${name}`, partial));
+    }
+    for (const stem of moduleNames) {
+      const relativePath = await copyContainedFile(
+        runtime,
+        runtimeReal,
+        `lib/postgresql/${stem}.dll`,
+        partial,
+      );
+      const binding = validateWindowsServerModuleImports(
+        await readFile(path.join(partial, ...relativePath.split('/'))),
+        relativePath,
+      );
+      if (binding.serverBound) {
+        serverBoundExtensionModules.push(`${stem}.dll`);
+      } else {
+        hostNeutralServerModules.push(`${stem}.dll`);
+      }
+      files.push(relativePath);
+    }
+    const manifest = {
+      schema: 'oliphaunt-windows-extension-binary-contract-v4',
+      selectedSqlNames: selected.map(({ sqlName }) => sqlName),
+      standaloneBackendProvider: 'postgres.exe',
+      forbiddenEmbeddedBackendProvider: 'oliphaunt.dll',
+      providerRuntimeDlls: [...WINDOWS_VC_RUNTIME_DLLS],
+      extensionModules: moduleNames.map((stem) => `${stem}.dll`),
+      serverBoundExtensionModules,
+      hostNeutralServerModules,
+      files: [...files].sort(),
+    };
+    await writeFile(
+      path.join(partial, 'binary-contract-manifest.json'),
+      `${JSON.stringify(manifest, null, 2)}\n`,
+      'utf8',
+    );
+    await rm(output, { recursive: true, force: true });
+    await mkdir(path.dirname(output), { recursive: true });
+    await rename(partial, output);
+    return manifest;
+  } catch (error) {
+    await rm(partial, { recursive: true, force: true });
+    throw error;
+  }
+}
+
+function usage() {
+  return `usage: ${TOOL} --runtime DIR --catalog FILE --output DIR [--selected-sql-names CSV]\n`;
+}
+
+function parseArgs(argv) {
+  const args = { runtime: '', catalog: '', output: '', selectedSqlNames: '' };
+  for (let index = 0; index < argv.length; index += 1) {
+    const flag = argv[index];
+    if (flag === '--help' || flag === '-h') return { help: true };
+    const value = argv[++index];
+    if (value === undefined) throw failure(`${flag} requires a value`);
+    if (flag === '--runtime') args.runtime = value;
+    else if (flag === '--catalog') args.catalog = value;
+    else if (flag === '--output') args.output = value;
+    else if (flag === '--selected-sql-names') args.selectedSqlNames = value;
+    else throw failure(`unknown argument ${flag}`);
+  }
+  return args;
+}
+
+async function main(argv) {
+  const args = parseArgs(argv);
+  if (args.help) {
+    process.stdout.write(usage());
+    return;
+  }
+  if (!args.runtime || !args.catalog || !args.output) {
+    process.stderr.write(usage());
+    process.exitCode = 2;
+    return;
+  }
+  const manifest = await stageWindowsExtensionBinaryContract({
+    runtimeRoot: args.runtime,
+    catalogText: await readFile(args.catalog, 'utf8'),
+    selectedSqlNames: args.selectedSqlNames,
+    outputRoot: args.output,
+  });
+  console.log(
+    `Windows server extension binary-contract view staged: modules=${manifest.extensionModules.length} serverBound=${manifest.serverBoundExtensionModules.length} hostNeutral=${manifest.hostNeutralServerModules.length} providerDlls=${manifest.providerRuntimeDlls.length}`,
+  );
+}
+
+if (import.meta.main) {
+  try {
+    await main(Bun.argv.slice(2));
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(1);
+  }
+}
diff --git a/src/extensions/artifacts/native/tools/test.sh b/src/extensions/artifacts/native/tools/test.sh
new file mode 100644
index 000000000..af5ceffb2
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/test.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+for test_file in src/extensions/artifacts/native/tools/*.test.mts; do
+  [[ -f "${test_file%.mts}.sh" ]] || bun test --timeout=30000 "./$test_file"
+done
+for test_file in src/extensions/artifacts/native/tools/*.test.sh; do
+  bash "$test_file"
+done
diff --git a/src/extensions/artifacts/native/tools/windows-extension-binary-contract.test.mts b/src/extensions/artifacts/native/tools/windows-extension-binary-contract.test.mts
new file mode 100644
index 000000000..5e8914402
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/windows-extension-binary-contract.test.mts
@@ -0,0 +1,624 @@
+import { afterEach, describe, expect, test } from 'bun:test';
+import { mkdtemp, mkdir, readFile, readdir, rm, symlink, writeFile } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+
+import {
+  parseExtensionCatalog,
+  stageWindowsExtensionBinaryContract,
+  validateWindowsEmbeddedModuleImports,
+  validateWindowsExtensionArtifactBinaryContract,
+  validateWindowsServerModuleImports,
+} from './stage-windows-binary-contract.mts';
+import { validateExactArtifactBinaryContract } from './extension-artifact-packager.mts';
+import { inspectPlatformBinaryTree } from '../../../../../tools/packaging/platform-binary-contract.mts';
+import { WINDOWS_VC_RUNTIME_DLLS } from '../../../../../tools/packaging/windows-vc-runtime-closure.mts';
+import {
+  elfFixture,
+  machoFixture,
+} from '../../../../../tools/packaging/testdata/release-fixture-utils.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../../../../..');
+const temporaryRoots = [];
+const CATALOG_HEADER = [
+  'sql_name',
+  'pg_major',
+  'creates_extension',
+  'native_module_stem',
+  'dependencies',
+  'shared_preload',
+  'desktop_prebuilt',
+  'mobile_prebuilt',
+  'mobile_static_registry_required',
+  'mobile_static_archive_targets',
+  'data_files',
+  'artifact',
+].join('\t');
+
+afterEach(async () => {
+  await Promise.all(
+    temporaryRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
+  );
+});
+
+async function fixture(name) {
+  const root = await mkdtemp(path.join(tmpdir(), `oliphaunt-windows-extension-contract-${name}-`));
+  temporaryRoots.push(root);
+  return root;
+}
+
+function catalog(...rows) {
+  return `${[CATALOG_HEADER, ...rows.map((row) => row.join('\t'))].join('\n')}\n`;
+}
+
+const vectorRow = [
+  'vector',
+  '18',
+  'yes',
+  'vector',
+  '-',
+  '-',
+  'yes',
+  'yes',
+  'yes',
+  '-',
+  '-',
+  'first-party',
+];
+const postgisRow = [
+  'postgis',
+  '18',
+  'yes',
+  'postgis-3',
+  '-',
+  '-',
+  'yes',
+  'yes',
+  'yes',
+  '-',
+  '-',
+  'first-party',
+];
+const desktopOnlyRow = [
+  'desktop_extension',
+  '18',
+  'yes',
+  'desktop_extension',
+  '-',
+  '-',
+  'yes',
+  'no',
+  'yes',
+  '-',
+  '-',
+  'contrib',
+];
+const HOSTED_EARTHDISTANCE_IMPORTS = Object.freeze([
+  'VCRUNTIME140.dll',
+  'api-ms-win-crt-math-l1-1-0.dll',
+  'api-ms-win-crt-runtime-l1-1-0.dll',
+  'KERNEL32.dll',
+]);
+
+function pe({ machine = 0x8664, imports = ['KERNEL32.dll'], delayImports = [] } = {}) {
+  const peOffset = 0x80;
+  const optionalSize = 240;
+  const sectionTable = peOffset + 24 + optionalSize;
+  const rawOffset = 0x200;
+  const rawSize = 0x400;
+  const virtualAddress = 0x1000;
+  const buffer = Buffer.alloc(rawOffset + rawSize);
+  buffer.write('MZ', 0, 'ascii');
+  buffer.writeUInt32LE(peOffset, 0x3c);
+  buffer.write('PE\0\0', peOffset, 'ascii');
+  const coff = peOffset + 4;
+  buffer.writeUInt16LE(machine, coff);
+  buffer.writeUInt16LE(1, coff + 2);
+  buffer.writeUInt16LE(optionalSize, coff + 16);
+  buffer.writeUInt16LE(0x2022, coff + 18);
+  const optional = coff + 20;
+  buffer.writeUInt16LE(0x20b, optional);
+  buffer.writeBigUInt64LE(0x140000000n, optional + 24);
+  buffer.writeUInt32LE(rawOffset, optional + 60);
+  buffer.writeUInt32LE(16, optional + 108);
+  buffer.writeUInt32LE(virtualAddress, optional + 120);
+  buffer.writeUInt32LE((imports.length + 1) * 20, optional + 124);
+  if (delayImports.length > 0) {
+    const delayDescriptorOffset = rawOffset + 0x100;
+    buffer.writeUInt32LE(virtualAddress + (delayDescriptorOffset - rawOffset), optional + 216);
+    buffer.writeUInt32LE((delayImports.length + 1) * 32, optional + 220);
+  }
+  buffer.write('.rdata\0\0', sectionTable, 'ascii');
+  buffer.writeUInt32LE(rawSize, sectionTable + 8);
+  buffer.writeUInt32LE(virtualAddress, sectionTable + 12);
+  buffer.writeUInt32LE(rawSize, sectionTable + 16);
+  buffer.writeUInt32LE(rawOffset, sectionTable + 20);
+  let nameOffset = rawOffset + 0x200;
+  for (const [index, name] of imports.entries()) {
+    buffer.writeUInt32LE(virtualAddress + (nameOffset - rawOffset), rawOffset + index * 20 + 12);
+    buffer.write(`${name}\0`, nameOffset, 'ascii');
+    nameOffset += Buffer.byteLength(name) + 1;
+  }
+  for (const [index, name] of delayImports.entries()) {
+    const descriptor = rawOffset + 0x100 + index * 32;
+    buffer.writeUInt32LE(1, descriptor);
+    buffer.writeUInt32LE(virtualAddress + (nameOffset - rawOffset), descriptor + 4);
+    buffer.write(`${name}\0`, nameOffset, 'ascii');
+    nameOffset += Buffer.byteLength(name) + 1;
+  }
+  return buffer;
+}
+
+async function writeRuntimeFile(runtime, relative, data) {
+  const file = path.join(runtime, ...relative.split('/'));
+  await mkdir(path.dirname(file), { recursive: true });
+  await writeFile(file, data);
+}
+
+async function createProviderRuntime(runtime) {
+  for (const name of WINDOWS_VC_RUNTIME_DLLS) {
+    await writeRuntimeFile(runtime, `bin/${name}`, pe());
+  }
+}
+
+async function relativeFiles(root, relative = '') {
+  const files = [];
+  for (const entry of await readdir(path.join(root, relative), {
+    withFileTypes: true,
+  })) {
+    const child = relative ? `${relative}/${entry.name}` : entry.name;
+    if (entry.isDirectory()) files.push(...(await relativeFiles(root, child)));
+    else files.push(child);
+  }
+  return files.sort();
+}
+
+describe('desktop exact-extension post-strip binary qualification', () => {
+  test('validates both Linux profiles and rejects a corrupt or over-floor embedded module', async () => {
+    const root = await fixture('linux-exact-profiles');
+    const artifact = path.join(root, 'artifact');
+    const server = 'files/lib/postgresql/vector.so';
+    const embedded = 'files/lib/modules/vector.so';
+    await writeRuntimeFile(
+      artifact,
+      server,
+      elfFixture({ machine: 62, requiredVersions: ['GLIBC_2.17'] }),
+    );
+    await writeRuntimeFile(
+      artifact,
+      embedded,
+      elfFixture({ machine: 62, requiredVersions: ['GLIBC_2.27'] }),
+    );
+    await writeRuntimeFile(
+      artifact,
+      'files/share/licenses/libcharset/COPYING.LIB',
+      Buffer.from('GNU LIBRARY GENERAL PUBLIC LICENSE\n'),
+    );
+    const args = {
+      nativeModuleStem: 'vector',
+      nativeTarget: 'linux-x64-gnu',
+    };
+    await expect(validateExactArtifactBinaryContract(artifact, args)).resolves.toMatchObject({
+      target: 'linux-x64-gnu',
+      binaries: 2,
+    });
+
+    await writeRuntimeFile(
+      artifact,
+      embedded,
+      elfFixture({ machine: 62, requiredVersions: ['GLIBC_2.39'] }),
+    );
+    await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow(
+      /GLIBC_2\.39 exceeds/u,
+    );
+
+    await writeRuntimeFile(artifact, embedded, Buffer.from('truncated ELF'));
+    await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow(
+      /expected native binary is malformed or truncated/u,
+    );
+  });
+
+  test('validates both macOS profiles against the exact post-strip minimum-OS floor', async () => {
+    const root = await fixture('macos-exact-profiles');
+    const artifact = path.join(root, 'artifact');
+    const server = 'files/lib/postgresql/vector.dylib';
+    const embedded = 'files/lib/modules/vector.dylib';
+    await writeRuntimeFile(artifact, server, machoFixture({ minos: [11, 0, 0] }));
+    await writeRuntimeFile(artifact, embedded, machoFixture({ minos: [11, 0, 0] }));
+    const args = {
+      nativeModuleStem: 'vector',
+      nativeTarget: 'macos-arm64',
+    };
+    await expect(validateExactArtifactBinaryContract(artifact, args)).resolves.toMatchObject({
+      target: 'macos-arm64',
+      binaries: 2,
+    });
+
+    await writeRuntimeFile(artifact, embedded, machoFixture({ minos: [14, 0, 0] }));
+    await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow(
+      /minimum OS 14\.0 exceeds/u,
+    );
+  });
+});
+
+describe('Windows exact-extension binary-contract staging', () => {
+  test('validates an explicitly selected desktop extension set while excluding every development/archive class', async () => {
+    const root = await fixture('selected');
+    const runtime = path.join(root, 'install');
+    const output = path.join(root, 'contract-view');
+    await createProviderRuntime(runtime);
+    await writeRuntimeFile(
+      runtime,
+      'lib/postgresql/vector.dll',
+      pe({ imports: ['postgres.exe', 'VCRUNTIME140.dll'] }),
+    );
+    await writeRuntimeFile(
+      runtime,
+      'lib/postgresql/desktop_extension.dll',
+      pe({ imports: HOSTED_EARTHDISTANCE_IMPORTS }),
+    );
+    await writeRuntimeFile(runtime, 'lib/postgresql/postgis-3.dll', pe({ machine: 0xaa64 }));
+    const installedDevelopmentArchives = [
+      'lib/libpgport.a',
+      'lib/libpgport_shlib.a',
+      'lib/libpgcommon.a',
+      'lib/libpgcommon_shlib.a',
+      'lib/libpq.a',
+      'lib/libpgfeutils.a',
+      'lib/libpgtypes.a',
+      'lib/libecpg.a',
+      'lib/libecpg_compat.a',
+      'lib/libpq.lib',
+      'lib/postgres.lib',
+      'lib/postgresql/pgevent.lib',
+      'lib/libpgtypes.lib',
+      'lib/libecpg.lib',
+      'lib/libecpg_compat.lib',
+    ];
+    for (const relative of installedDevelopmentArchives) {
+      await writeRuntimeFile(runtime, relative, Buffer.from('!\n', 'ascii'));
+    }
+    await writeRuntimeFile(runtime, 'lib/libpgcommon.la', 'development metadata\n');
+    await writeRuntimeFile(
+      runtime,
+      'lib/postgresql/pgevent.lib',
+      Buffer.from('!\n', 'ascii'),
+    );
+    await writeRuntimeFile(runtime, 'bin/postgres.pdb', 'debug symbols\n');
+    await writeRuntimeFile(runtime, 'include/postgresql/server/postgres.h', 'development header\n');
+
+    const result = await stageWindowsExtensionBinaryContract({
+      runtimeRoot: runtime,
+      catalogText: catalog(vectorRow, postgisRow, desktopOnlyRow),
+      selectedSqlNames: 'vector,desktop_extension',
+      outputRoot: output,
+    });
+
+    expect(result.schema).toBe('oliphaunt-windows-extension-binary-contract-v4');
+    expect(result.standaloneBackendProvider).toBe('postgres.exe');
+    expect(result.forbiddenEmbeddedBackendProvider).toBe('oliphaunt.dll');
+    expect(result.extensionModules).toEqual(['desktop_extension.dll', 'vector.dll']);
+    expect(result.serverBoundExtensionModules).toEqual(['vector.dll']);
+    expect(result.hostNeutralServerModules).toEqual(['desktop_extension.dll']);
+    expect(result.providerRuntimeDlls).toEqual([...WINDOWS_VC_RUNTIME_DLLS]);
+    expect(await relativeFiles(output)).toEqual(
+      [
+        ...WINDOWS_VC_RUNTIME_DLLS.map((name) => `bin/${name}`),
+        'binary-contract-manifest.json',
+        'lib/postgresql/desktop_extension.dll',
+        'lib/postgresql/vector.dll',
+      ].sort(),
+    );
+    const inspected = await inspectPlatformBinaryTree(output, {
+      target: 'windows-x64-msvc',
+      windowsVcRuntimeProfile: 'provider',
+    });
+    expect(inspected.files).toContain('lib/postgresql/vector.dll');
+    expect(inspected.files).toContain('lib/postgresql/desktop_extension.dll');
+    expect(inspected.files).not.toContain('lib/postgresql/postgis-3.dll');
+    for (const relative of installedDevelopmentArchives) {
+      expect(inspected.files).not.toContain(relative);
+    }
+    expect(inspected.binaries).toBe(WINDOWS_VC_RUNTIME_DLLS.length + 2);
+  });
+
+  test('still rejects a selected wrong-architecture extension DLL', async () => {
+    const root = await fixture('wrong-architecture');
+    const runtime = path.join(root, 'install');
+    const output = path.join(root, 'contract-view');
+    await createProviderRuntime(runtime);
+    await writeRuntimeFile(runtime, 'lib/postgresql/vector.dll', pe({ machine: 0xaa64 }));
+    await expect(
+      stageWindowsExtensionBinaryContract({
+        runtimeRoot: runtime,
+        catalogText: catalog(vectorRow),
+        selectedSqlNames: 'vector',
+        outputRoot: output,
+      }),
+    ).rejects.toThrow(/PE machine 0xaa64 is not x64/u);
+  });
+
+  test('classifies backend bindings from direct and delay import inventories, independent of module name', () => {
+    expect(
+      validateWindowsServerModuleImports(
+        pe({ imports: HOSTED_EARTHDISTANCE_IMPORTS }),
+        'earthdistance.dll',
+      ),
+    ).toMatchObject({
+      backendProvider: 'host-neutral',
+      hostNeutral: true,
+      serverBound: false,
+    });
+    expect(
+      validateWindowsEmbeddedModuleImports(
+        pe({ imports: HOSTED_EARTHDISTANCE_IMPORTS }),
+        'earthdistance.dll',
+      ),
+    ).toMatchObject({
+      backendProvider: 'host-neutral',
+      hostNeutral: true,
+      providerBound: false,
+    });
+    expect(
+      validateWindowsServerModuleImports(
+        pe({ imports: ['VCRUNTIME140.dll'], delayImports: ['PoStGrEs.ExE'] }),
+        'earthdistance.dll',
+      ),
+    ).toMatchObject({
+      backendProvider: 'postgres.exe',
+      hostNeutral: false,
+      serverBound: true,
+    });
+    expect(() =>
+      validateWindowsEmbeddedModuleImports(
+        pe({ imports: ['VCRUNTIME140.dll'], delayImports: ['PoStGrEs.ExE'] }),
+        'earthdistance.dll',
+      ),
+    ).toThrow(/imports postgres\.exe/u);
+  });
+
+  test('validates exact post-strip artifact bytes and never ignores an archive that enters the carrier', async () => {
+    const root = await fixture('exact-artifact');
+    const runtime = path.join(root, 'install');
+    const artifact = path.join(root, 'artifact');
+    await createProviderRuntime(runtime);
+    await writeRuntimeFile(
+      artifact,
+      'files/lib/postgresql/vector.dll',
+      pe({ imports: ['postgres.exe', 'VCRUNTIME140.dll'] }),
+    );
+    await writeRuntimeFile(
+      artifact,
+      'files/lib/modules/vector.dll',
+      pe({ imports: ['oliphaunt.dll', 'VCRUNTIME140.dll'] }),
+    );
+    const neutralEarthdistance = pe({
+      imports: HOSTED_EARTHDISTANCE_IMPORTS,
+    });
+    await writeRuntimeFile(
+      artifact,
+      'files/lib/postgresql/earthdistance.dll',
+      neutralEarthdistance,
+    );
+    await writeRuntimeFile(artifact, 'files/lib/modules/earthdistance.dll', neutralEarthdistance);
+    await writeRuntimeFile(
+      artifact,
+      'files/share/postgresql/extension/vector.control',
+      "default_version = '0.8.2'\n",
+    );
+    await writeRuntimeFile(
+      artifact,
+      'files/share/licenses/libcharset/COPYING.LIB',
+      'GNU LIBRARY GENERAL PUBLIC LICENSE\n',
+    );
+    await writeRuntimeFile(
+      artifact,
+      'files/share/licenses/libiconv/COPYING.LIB',
+      'GNU LIBRARY GENERAL PUBLIC LICENSE\n',
+    );
+
+    const result = await validateWindowsExtensionArtifactBinaryContract({
+      artifactRoot: artifact,
+      providerRuntimeRoot: runtime,
+    });
+    expect(result.files).toContain('artifact/files/lib/postgresql/vector.dll');
+    expect(result.files).toContain('artifact/files/lib/modules/vector.dll');
+    expect(result.files).not.toContain('artifact/files/share/licenses/libcharset/COPYING.LIB');
+    expect(result.files).not.toContain('artifact/files/share/licenses/libiconv/COPYING.LIB');
+    expect(result.serverBoundExtensionModules).toEqual(['vector.dll']);
+    expect(result.providerBoundEmbeddedModules).toEqual(['vector.dll']);
+    expect(result.hostNeutralServerModules).toEqual(['earthdistance.dll']);
+    expect(result.hostNeutralEmbeddedModules).toEqual(['earthdistance.dll']);
+    expect(result.byteIdenticalHostNeutralModules).toEqual(['earthdistance.dll']);
+    expect(result.profileBindings).toEqual({
+      'earthdistance.dll': {
+        embedded: 'host-neutral',
+        server: 'host-neutral',
+      },
+      'vector.dll': {
+        embedded: 'oliphaunt.dll',
+        server: 'postgres.exe',
+      },
+    });
+    expect(result.profileSha256['earthdistance.dll'].server).toBe(
+      result.profileSha256['earthdistance.dll'].embedded,
+    );
+    expect(result.profileSha256['vector.dll'].server).not.toBe(
+      result.profileSha256['vector.dll'].embedded,
+    );
+
+    await writeRuntimeFile(
+      artifact,
+      'files/lib/accidental-development.a',
+      Buffer.from('!\n', 'ascii'),
+    );
+    await expect(
+      validateWindowsExtensionArtifactBinaryContract({
+        artifactRoot: artifact,
+        providerRuntimeRoot: runtime,
+      }),
+    ).rejects.toThrow(/static \.a archives are not permitted in a Windows release carrier/u);
+    await rm(path.join(artifact, 'files/lib/accidental-development.a'));
+
+    await writeRuntimeFile(artifact, 'files/lib/postgresql/vector.dll', pe({ machine: 0xaa64 }));
+    await expect(
+      validateWindowsExtensionArtifactBinaryContract({
+        artifactRoot: artifact,
+        providerRuntimeRoot: runtime,
+      }),
+    ).rejects.toThrow(/PE machine 0xaa64 is not x64/u);
+  });
+
+  test('fails closed for unknown selections, missing modules, malformed catalogs, and overlapping output', async () => {
+    const root = await fixture('fail-closed');
+    const runtime = path.join(root, 'install');
+    await createProviderRuntime(runtime);
+
+    expect(() => parseExtensionCatalog(catalog(vectorRow), 'missing')).toThrow(
+      /absent from the extension catalog/u,
+    );
+    expect(() => parseExtensionCatalog(`${CATALOG_HEADER}\nvector\t18\n`, 'vector')).toThrow(
+      /has 2 columns/u,
+    );
+    await expect(
+      stageWindowsExtensionBinaryContract({
+        runtimeRoot: runtime,
+        catalogText: catalog(vectorRow),
+        selectedSqlNames: 'vector',
+        outputRoot: path.join(root, 'contract-view'),
+      }),
+    ).rejects.toThrow(/lib\/postgresql\/vector\.dll must be a real regular file/u);
+    await expect(
+      stageWindowsExtensionBinaryContract({
+        runtimeRoot: runtime,
+        catalogText: catalog(vectorRow),
+        selectedSqlNames: 'vector',
+        outputRoot: path.join(runtime, 'contract-view'),
+      }),
+    ).rejects.toThrow(/must not overlap/u);
+
+    const runtimeAlias = path.join(root, 'runtime-alias');
+    await symlink(runtime, runtimeAlias, process.platform === 'win32' ? 'junction' : 'dir');
+    await expect(
+      stageWindowsExtensionBinaryContract({
+        runtimeRoot: runtime,
+        catalogText: catalog(vectorRow),
+        selectedSqlNames: 'vector',
+        outputRoot: path.join(runtimeAlias, 'missing-stage', 'contract-view'),
+      }),
+    ).rejects.toThrow(/must not overlap/u);
+    expect(await readdir(runtime)).not.toContain('missing-stage');
+
+    const protectedOutput = path.join(root, 'protected-output');
+    await writeFile(protectedOutput, 'do not replace\n');
+    await expect(
+      stageWindowsExtensionBinaryContract({
+        runtimeRoot: runtime,
+        catalogText: catalog(vectorRow),
+        selectedSqlNames: 'vector',
+        outputRoot: protectedOutput,
+      }),
+    ).rejects.toThrow(/must be a real directory/u);
+    expect(await readFile(protectedOutput, 'utf8')).toBe('do not replace\n');
+  });
+
+  test('rejects direct and delay-loaded embedded-provider imports in the standalone server profile', async () => {
+    const root = await fixture('server-provider-confusion');
+    const runtime = path.join(root, 'install');
+    const output = path.join(root, 'contract-view');
+    await createProviderRuntime(runtime);
+    await writeRuntimeFile(
+      runtime,
+      'lib/postgresql/vector.dll',
+      pe({ imports: ['oliphaunt.dll', 'VCRUNTIME140.dll'] }),
+    );
+
+    await expect(
+      stageWindowsExtensionBinaryContract({
+        runtimeRoot: runtime,
+        catalogText: catalog(vectorRow),
+        selectedSqlNames: 'vector',
+        outputRoot: output,
+      }),
+    ).rejects.toThrow(
+      /imports oliphaunt\.dll; standalone PostgreSQL extension DLLs must not bind to the embedded provider/u,
+    );
+
+    await writeRuntimeFile(
+      runtime,
+      'lib/postgresql/vector.dll',
+      pe({
+        imports: ['postgres.exe', 'VCRUNTIME140.dll'],
+        delayImports: ['OlIpHaUnT.DlL'],
+      }),
+    );
+    await expect(
+      stageWindowsExtensionBinaryContract({
+        runtimeRoot: runtime,
+        catalogText: catalog(vectorRow),
+        selectedSqlNames: 'vector',
+        outputRoot: output,
+      }),
+    ).rejects.toThrow(
+      /imports oliphaunt\.dll; standalone PostgreSQL extension DLLs must not bind to the embedded provider/u,
+    );
+  });
+
+  test('accepts byte-identical neutral profiles but rejects every crossed provider and a missing profile', async () => {
+    const root = await fixture('exact-profile-confusion');
+    const runtime = path.join(root, 'install');
+    const artifact = path.join(root, 'artifact');
+    await createProviderRuntime(runtime);
+    const neutral = pe({ imports: HOSTED_EARTHDISTANCE_IMPORTS });
+    await writeRuntimeFile(artifact, 'files/lib/postgresql/earthdistance.dll', neutral);
+    await writeRuntimeFile(artifact, 'files/lib/modules/earthdistance.dll', neutral);
+
+    await expect(
+      validateWindowsExtensionArtifactBinaryContract({
+        artifactRoot: artifact,
+        providerRuntimeRoot: runtime,
+      }),
+    ).resolves.toMatchObject({
+      byteIdenticalHostNeutralModules: ['earthdistance.dll'],
+      hostNeutralEmbeddedModules: ['earthdistance.dll'],
+      hostNeutralServerModules: ['earthdistance.dll'],
+      providerBoundEmbeddedModules: [],
+      serverBoundExtensionModules: [],
+    });
+
+    const crossed = pe({ imports: ['postgres.exe', 'VCRUNTIME140.dll'] });
+    await writeRuntimeFile(artifact, 'files/lib/modules/earthdistance.dll', crossed);
+    await expect(
+      validateWindowsExtensionArtifactBinaryContract({
+        artifactRoot: artifact,
+        providerRuntimeRoot: runtime,
+      }),
+    ).rejects.toThrow(
+      /imports postgres\.exe; embedded extension DLLs must not bind to the standalone server provider/u,
+    );
+
+    await writeRuntimeFile(artifact, 'files/lib/modules/earthdistance.dll', neutral);
+    await writeRuntimeFile(
+      artifact,
+      'files/lib/postgresql/earthdistance.dll',
+      pe({ imports: ['oliphaunt.dll', 'VCRUNTIME140.dll'] }),
+    );
+    await expect(
+      validateWindowsExtensionArtifactBinaryContract({
+        artifactRoot: artifact,
+        providerRuntimeRoot: runtime,
+      }),
+    ).rejects.toThrow(
+      /imports oliphaunt\.dll; standalone PostgreSQL extension DLLs must not bind to the embedded provider/u,
+    );
+
+    await writeRuntimeFile(artifact, 'files/lib/postgresql/earthdistance.dll', neutral);
+    await rm(path.join(artifact, 'files/lib/modules/earthdistance.dll'));
+    await expect(
+      validateWindowsExtensionArtifactBinaryContract({
+        artifactRoot: artifact,
+        providerRuntimeRoot: runtime,
+      }),
+    ).rejects.toThrow(/missing embedded provider profile/u);
+  });
+});
diff --git a/src/extensions/artifacts/native/tools/windows-extension-sources.mts b/src/extensions/artifacts/native/tools/windows-extension-sources.mts
new file mode 100644
index 000000000..b7433f83b
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/windows-extension-sources.mts
@@ -0,0 +1,678 @@
+import assert from 'node:assert/strict';
+import {
+  copyFileSync,
+  cpSync,
+  existsSync,
+  mkdirSync,
+  readFileSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { parseArgs } from 'node:util';
+import { preprocessSql } from '../../../external/postgis/tools/preprocess-sql.mts';
+
+const read = (file: string) => readFileSync(file, 'utf8');
+const write = (file: string, text: string) => {
+  mkdirSync(path.dirname(file), { recursive: true });
+  writeFileSync(file, text);
+};
+const quote = (value: string) => `'${value.replaceAll('\\', '/').replaceAll("'", "\\'")}'`;
+const list = (values: string[]) => values.map((value) => `  ${quote(value)}`).join(',\n');
+const glob = (root: string, pattern: string) =>
+  [...new Bun.Glob(pattern).scanSync({ cwd: root, onlyFiles: true })].sort();
+const version = (root: string, extension: string) => {
+  const matches = [
+    ...read(path.join(root, `${extension}.control`)).matchAll(
+      /^\s*default_version\s*=\s*'([^']+)'\s*$/gm,
+    ),
+  ];
+  assert.equal(matches.length, 1, `${extension} must declare a default_version`);
+  return matches[0][1];
+};
+function copy(source: string, destination: string) {
+  rmSync(destination, { recursive: true, force: true });
+  cpSync(source, destination, {
+    recursive: true,
+    filter: (file) => path.basename(file) !== '.git',
+  });
+}
+function replace(file: string, before: string | RegExp, after: string) {
+  const original = read(file);
+  const updated = original.replace(before, after);
+  assert.notEqual(updated, original, `missing Windows source patch anchor in ${file}`);
+  write(file, updated);
+}
+
+// Only the literal object list is needed from these pinned PGXS projects.
+// Reject expressions rather than attempting to implement GNU Make here.
+export function pgxsSources(root: string) {
+  const makefile = read(path.join(root, 'Makefile')).replace(/\\\r?\n/g, ' ');
+  const objects = makefile.match(/^OBJS\s*=\s*([^\n]*)/m)?.[1];
+  if (objects === undefined) {
+    const modules = makefile
+      .match(/^MODULES\s*=\s*([^\n]*)/m)?.[1]
+      ?.trim()
+      .split(/\s+/);
+    assert(
+      modules?.length && modules.every((value) => /^[\w-]+$/.test(value)),
+      'missing literal PGXS modules',
+    );
+    return modules.map((module) => `${module}.c`);
+  }
+  const values = objects.replaceAll('$(WIN32RES)', '').trim().split(/\s+/);
+  assert(
+    values.length && values.every((value) => /^[\w./-]+\.o$/.test(value)),
+    'unsupported PGXS object expression',
+  );
+  return values.map((value) => value.slice(0, -2) + '.c');
+}
+
+export function patchTextsearch(root: string) {
+  write(
+    path.join(root, 'src/oliphaunt_windows_compat.h'),
+    '#ifdef _MSC_VER\n#ifndef __attribute__\n#define __attribute__(x)\n#endif\n#endif\n',
+  );
+  write(
+    path.join(root, 'src/unistd.h'),
+    '#ifndef OLIPHAUNT_WINDOWS_UNISTD_H\n#define OLIPHAUNT_WINDOWS_UNISTD_H\n#endif\n',
+  );
+  for (const [file, name, attribute, pack, size, alignment] of [
+    ['segment/segment.h', 'TpDictEntryV3', 'aligned(4)', 4, 12, 4],
+    ['segment/segment.h', 'TpDictEntry', 'aligned(8)', 8, 16, 8],
+    ['segment/segment.h', 'TpSegmentPosting', 'packed', 1, 14, 1],
+    ['segment/segment.h', 'TpSkipEntryV3', 'packed', 1, 16, 1],
+    ['segment/segment.h', 'TpSkipEntry', 'packed', 1, 20, 1],
+    ['segment/segment.h', 'TpCtidMapEntry', 'packed', 1, 6, 1],
+    ['memtable/expull.h', 'TpExpullEntry', 'packed', 1, 7, 1],
+  ] as const) {
+    const target = path.join(root, 'src', file);
+    replace(
+      target,
+      new RegExp(`typedef struct ${name}\\b`),
+      `#ifdef _MSC_VER\n#pragma pack(push, ${pack})\n#endif\ntypedef struct ${name}`,
+    );
+    replace(
+      target,
+      `} __attribute__((${attribute})) ${name};`,
+      `} ${name};\n#ifdef _MSC_VER\n#pragma pack(pop)\nStaticAssertDecl(sizeof(${name}) == ${size}, "${name} size");\nStaticAssertDecl(__alignof(${name}) == ${alignment}, "${name} alignment");\n#endif`,
+    );
+  }
+  for (const file of ['src/am/am.h', 'src/types/vector.h', 'src/types/query.h']) {
+    replace(
+      path.join(root, file),
+      /^Datum (\w+)\(PG_FUNCTION_ARGS\);/gm,
+      'extern PGDLLEXPORT Datum $1(PG_FUNCTION_ARGS);',
+    );
+  }
+}
+
+type Config = { repo: string; work: string; postgres: string; install: string };
+function moduleRecipe(
+  config: Config,
+  subdir: string,
+  module: string,
+  sources: string[],
+  data: string[],
+  cArgs: string[] = [],
+  linkArgs: string[] = [],
+  includes: string[] = [],
+) {
+  const directory = path.join(config.postgres, 'contrib/oliphaunt_external', subdir);
+  const variable = subdir.replaceAll('-', '_');
+  write(
+    path.join(directory, 'meson.build'),
+    `${variable} = shared_module(\n  ${quote(module)},\n  files(\n${list(sources)}\n  ),\n  c_pch: pch_postgres_h,\n  include_directories: [${includes.map((value) => `include_directories(${quote(value)})`).join(', ')}],\n  kwargs: contrib_mod_args + { 'c_args': [\n${list(cArgs)}\n], 'link_args': [\n${list(linkArgs)}\n] },\n)\ncontrib_targets += ${variable}\ninstall_data(\n${list(data)},\n  kwargs: contrib_data_args,\n)\n`,
+  );
+  appendSubdir(config, subdir);
+}
+function appendSubdir(config: Config, subdir: string) {
+  const file = path.join(config.postgres, 'contrib/meson.build');
+  const line = `subdir('oliphaunt_external/${subdir}')`;
+  const text = read(file);
+  if (!text.includes(line)) write(file, text.trimEnd() + '\n' + line + '\n');
+}
+
+export function prepareSimple(config: Config, extension: string) {
+  const subdir = extension === 'uuid-ossp' ? 'uuid_ossp' : extension;
+  const destination = path.join(config.postgres, 'contrib/oliphaunt_external', subdir);
+  const cArgs: string[] = [],
+    linkArgs: string[] = [],
+    includes: string[] = [];
+  let sources: string[], data: string[];
+  if (extension === 'pgcrypto' || extension === 'uuid-ossp') {
+    mkdirSync(destination, { recursive: true });
+    const contrib = path.join(config.postgres, 'contrib', extension);
+    data = [...glob(contrib, `${extension}--*.sql`), `${extension}.control`].map(
+      (file) => `../../${extension}/${file}`,
+    );
+    if (extension === 'pgcrypto') {
+      sources = glob(contrib, '*.c').map((file) => `../../pgcrypto/${file}`);
+      cArgs.push(`/I${path.join(config.work, 'windows-dependencies/openssl/include')}`);
+      linkArgs.push(
+        path.join(config.work, 'windows-dependencies/openssl/lib/libcrypto.lib'),
+        'crypt32.lib',
+        'advapi32.lib',
+        'bcrypt.lib',
+        'ws2_32.lib',
+        'user32.lib',
+      );
+    } else {
+      copyFileSync(
+        path.join(config.repo, 'src/runtimes/liboliphaunt-native/portable-uuid/portable_uuid.c'),
+        path.join(destination, 'portable_uuid.c'),
+      );
+      sources = ['../../uuid-ossp/uuid-ossp.c', 'portable_uuid.c'];
+      cArgs.push(
+        `/I${path.join(config.repo, 'src/runtimes/liboliphaunt-native/portable-uuid/include')}`,
+        '/DHAVE_UUID_E2FS=1',
+        '/DHAVE_UUID_UUID_H=1',
+      );
+    }
+  } else {
+    const checkout = extension === 'vector' ? 'pgvector' : extension;
+    copy(path.join(config.repo, 'target/oliphaunt-sources/checkouts', checkout), destination);
+    sources = pgxsSources(destination);
+    if (extension === 'vector') {
+      copyFileSync(
+        path.join(destination, 'sql/vector.sql'),
+        path.join(destination, `sql/vector--${version(destination, extension)}.sql`),
+      );
+      cArgs.push('/fp:fast');
+    }
+    data = [
+      ...glob(destination, `${extension}--*.sql`),
+      ...glob(destination, `sql/${extension}--*.sql`),
+      `${extension}.control`,
+    ];
+    if (extension === 'pg_textsearch') {
+      patchTextsearch(destination);
+      cArgs.push(
+        '/D_CRT_SECURE_NO_WARNINGS',
+        `/DPG_TEXTSEARCH_VERSION="${version(destination, extension)}"`,
+        `/FI${path.join(destination, 'src/oliphaunt_windows_compat.h')}`,
+      );
+      includes.push('src');
+    }
+    if (extension === 'pg_uuidv7') {
+      replace(
+        path.join(destination, 'pg_uuidv7.c'),
+        '#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)',
+        `#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)\n#ifdef _WIN32\n#ifndef CLOCK_REALTIME\n#define CLOCK_REALTIME 0\n#endif\nstatic int oliphaunt_pg_uuidv7_clock_gettime(int clock_id, struct timespec *ts) {\n  TimestampTz unix_usecs;\n  if (clock_id != CLOCK_REALTIME || ts == NULL) return -1;\n  unix_usecs = GetCurrentTimestamp() + EPOCH_DIFF_USECS;\n  ts->tv_sec = (time_t) (unix_usecs / USECS_PER_SEC);\n  ts->tv_nsec = (long) ((unix_usecs % USECS_PER_SEC) * 1000);\n  return 0;\n}\n#define clock_gettime oliphaunt_pg_uuidv7_clock_gettime\n#endif`,
+      );
+    }
+  }
+  for (const file of [...sources, ...data])
+    assert(existsSync(path.join(destination, file)), `missing extension input ${file}`);
+  moduleRecipe(config, subdir, extension, sources, data, cArgs, linkArgs, includes);
+}
+
+function postgisVersion(root: string) {
+  const text = read(path.join(root, 'Version.config'));
+  const values = ['MAJOR', 'MINOR', 'MICRO'].map((key) => {
+    const value = text.match(new RegExp(`^POSTGIS_${key}_VERSION=(.+)$`, 'm'))?.[1].trim();
+    assert(value && /^[0-9]+$/.test(value), `invalid PostGIS ${key} version`);
+    return value;
+  });
+  return {
+    major: values[0],
+    minor: values[1],
+    micro: values[2],
+    version: values.join('.'),
+    majorMinor: values.slice(0, 2).join('.'),
+  };
+}
+function postgisDirectory(config: Config) {
+  return path.join(config.postgres, 'contrib/oliphaunt_external/postgis');
+}
+function postgisTemplates(config: Config) {
+  return path.join(config.repo, 'src/extensions/external/postgis/tools/windows');
+}
+function expand(input: string, output: string, values: Record) {
+  let text = read(input);
+  for (const [key, value] of Object.entries(values)) text = text.replaceAll(`@${key}@`, value);
+  write(output, text);
+}
+function sourceDate(config: Config) {
+  const pin = Bun.TOML.parse(
+    read(path.join(config.repo, 'src/extensions/external/postgis/source.toml')),
+  );
+  assert(
+    Number.isSafeInteger(pin.source_date_epoch) && pin.source_date_epoch > 0,
+    'invalid PostGIS source date',
+  );
+  assert.equal(
+    process.env.SOURCE_DATE_EPOCH,
+    String(pin.source_date_epoch),
+    'use the pinned PostGIS source date',
+  );
+  return new Date(pin.source_date_epoch * 1000).toISOString().slice(0, 19).replace('T', ' ');
+}
+export function preparePostgis(config: Config) {
+  const directory = postgisDirectory(config);
+  copy(path.join(config.repo, 'target/oliphaunt-sources/checkouts/postgis'), directory);
+  const pgis = postgisVersion(directory);
+  const source = Bun.TOML.parse(
+    read(path.join(config.repo, 'src/extensions/external/postgis/source.toml')),
+  );
+  const componentVersion = (component: string) => {
+    const pin = Bun.TOML.parse(
+      read(
+        path.join(
+          config.repo,
+          'src/extensions/external/postgis/dependencies',
+          component,
+          'source.toml',
+        ),
+      ),
+    );
+    const value = String(pin.branch).replace(/^v/, '');
+    assert(/^\d+\.\d+\.\d+$/.test(value), `invalid pinned ${component} version`);
+    return value;
+  };
+  const number = (value: string) =>
+    value
+      .split('.')
+      .map((part, index) => (index ? part.padStart(2, '0') : part))
+      .join('');
+  const pgMajor = String(
+    Bun.TOML.parse(read(path.join(config.repo, 'src/third-party/postgres/source.toml'))).postgresql
+      .version,
+  ).split('.')[0];
+  const values = {
+    LOCALE_DIR: path.join(config.install, 'share/locale').replaceAll('\\', '/'),
+    BUILD_DATE: sourceDate(config),
+    GEOS_VERSION: number(componentVersion('geos')),
+    LIBXML_VERSION: componentVersion('libxml2'),
+    PROJ_VERSION: number(componentVersion('proj')),
+    VERSION: pgis.version,
+    MAJOR: pgis.major,
+    MINOR: pgis.minor,
+    MICRO: pgis.micro,
+    POSTGIS_VERSION: `${pgis.majorMinor} USE_GEOS=1 USE_PROJ=1 USE_STATS=1`,
+  };
+  write(path.join(directory, 'postgis_revision.h'), `#define POSTGIS_REVISION ${source.commit}\n`);
+  expand(
+    path.join(postgisTemplates(config), 'postgis_config.h.in'),
+    path.join(directory, 'postgis_config.h'),
+    values,
+  );
+  const macros = {
+    POSTGIS_PGSQL_VERSION: `${pgMajor}0`,
+    POSTGIS_PGSQL_HR_VERSION: `${pgMajor}.0`,
+    POSTGIS_GEOS_VERSION: values.GEOS_VERSION,
+    POSTGIS_PROJ_VERSION: values.PROJ_VERSION,
+    POSTGIS_LIB_VERSION: pgis.version,
+    POSTGIS_LIBXML2_VERSION: values.LIBXML_VERSION,
+    POSTGIS_SFCGAL_VERSION: '0',
+    POSTGIS_VERSION: values.POSTGIS_VERSION,
+    POSTGIS_BUILD_DATE: values.BUILD_DATE,
+    POSTGIS_SCRIPTS_VERSION: pgis.version,
+    SRID_MAX: '999999',
+    SRID_USR_MAX: '998999',
+    POSTGIS_MAJOR_VERSION: pgis.major,
+    POSTGIS_MINOR_VERSION: pgis.minor,
+  };
+  for (const file of ['postgis/sqldefines.h', 'liblwgeom/liblwgeom.h'])
+    expand(path.join(directory, file + '.in'), path.join(directory, file), macros);
+  expand(
+    path.join(directory, 'extensions/postgis/postgis.control.in'),
+    path.join(directory, 'extensions/postgis/postgis.control'),
+    { EXTVERSION: pgis.version, EXTENSION: 'postgis', MODULEPATH: '$libdir/postgis-3' },
+  );
+  copyFileSync(
+    path.join(postgisTemplates(config), 'postgis-compat.h'),
+    path.join(directory, 'oliphaunt_postgis_windows_compat.h'),
+  );
+  copyFileSync(
+    path.join(postgisTemplates(config), 'flatgeobuf-compat.h'),
+    path.join(directory, 'oliphaunt_flatgeobuf_windows_compat.h'),
+  );
+  for (const folder of ['postgis', 'libpgcommon', 'liblwgeom']) {
+    for (const file of glob(path.join(directory, folder), '**/*.{c,h}')) {
+      const target = path.join(directory, folder, file),
+        text = read(target);
+      const updated = text.replace(
+        /^[ \t]*(?!(?:extern\s+)?PGDLLEXPORT\s+)(?:extern\s+)?Datum\s+(\w+)\s*\(PG_FUNCTION_ARGS\);\r?$/gm,
+        'extern PGDLLEXPORT Datum $1(PG_FUNCTION_ARGS);',
+      );
+      if (updated !== text) write(target, updated);
+    }
+  }
+  replace(
+    path.join(directory, 'postgis/postgis_legacy.c'),
+    /^([ \t]*)Datum[ \t]+funcname[ \t]*\(PG_FUNCTION_ARGS\);[ \t]*\\\r?$/gm,
+    '$1extern PGDLLEXPORT Datum funcname(PG_FUNCTION_ARGS); \\',
+  );
+  for (const variables of [
+    ['x', 'y', 'z', 'm'],
+    ['xv', 'yv', 'zv', 'mv'],
+  ]) {
+    replace(
+      path.join(directory, 'deps/flatgeobuf/geometryreader.cpp'),
+      `pt = (POINT4D) { ${variables.join(', ')} };`,
+      ['x', 'y', 'z', 'm'].map((field, index) => `pt.${field} = ${variables[index]};`).join('\n'),
+    );
+  }
+  const comments = path.join(directory, 'doc/postgis_comments.sql');
+  if (!existsSync(comments))
+    write(comments, '-- Optional SQL comments are not generated by the Windows producer.\n');
+}
+
+function firstLibrary(root: string, names: string[]) {
+  for (const name of names) {
+    const found = glob(root, `**/${name}`)[0];
+    if (found) return path.join(root, found);
+  }
+  throw new Error(`missing library ${names.join('/')} under ${root}`);
+}
+export function postgisMeson(config: Config) {
+  const directory = postgisDirectory(config),
+    pgis = postgisVersion(directory);
+  const dependencies = path.join(config.work, 'windows-dependencies/postgis');
+  const cArgs = [
+    '/D_CRT_SECURE_NO_WARNINGS',
+    '/D_USE_MATH_DEFINES',
+    '/DLIBXML_STATIC',
+    '/DRYU_NO_TRAILING_ZEROS',
+    `/FI${path.join(directory, 'oliphaunt_postgis_windows_compat.h')}`,
+  ];
+  // Keep liblwgeom before the similarly named PostgreSQL module headers.
+  cArgs.push(
+    ...[
+      '',
+      'liblwgeom',
+      'postgis',
+      'libpgcommon',
+      'deps',
+      'deps/flatgeobuf',
+      'deps/flatgeobuf/include',
+      'deps/ryu',
+    ].map((file) => `/I${path.join(directory, file)}`),
+  );
+  cArgs.push(
+    ...[
+      'geos/include',
+      'proj/include',
+      'json-c/include',
+      'json-c/include/json-c',
+      'libxml2/include/libxml2',
+    ].map((file) => `/I${path.join(dependencies, file)}`),
+  );
+  const linkArgs = [
+    firstLibrary(path.join(dependencies, 'flatgeobuf'), ['flatgeobuf.lib']),
+    firstLibrary(path.join(dependencies, 'geos'), ['geos_c.lib']),
+    firstLibrary(path.join(dependencies, 'geos'), ['geos.lib']),
+    firstLibrary(path.join(dependencies, 'proj'), ['proj.lib', 'libproj.lib']),
+    firstLibrary(path.join(dependencies, 'sqlite'), ['sqlite3.lib', 'libsqlite3.lib']),
+    firstLibrary(path.join(dependencies, 'json-c'), ['json-c.lib', 'json-c-static.lib']),
+    firstLibrary(path.join(dependencies, 'libxml2'), ['libxml2s.lib', 'libxml2.lib', 'xml2.lib']),
+    'ws2_32.lib',
+    'bcrypt.lib',
+    'advapi32.lib',
+    'shell32.lib',
+    'user32.lib',
+  ];
+  const data = [
+    'extensions/postgis/postgis.control',
+    ...glob(directory, 'extensions/postgis/sql/postgis--*.sql'),
+  ];
+  const contrib = [
+    'postgis/legacy.sql',
+    'postgis/legacy_gist.sql',
+    'postgis/legacy_minimal.sql',
+    'postgis/postgis.sql',
+    'postgis/postgis_upgrade.sql',
+    'spatial_ref_sys.sql',
+    'postgis/uninstall_legacy.sql',
+    'postgis/uninstall_postgis.sql',
+    'doc/postgis_comments.sql',
+  ];
+  expand(
+    path.join(postgisTemplates(config), 'meson.build.in'),
+    path.join(directory, 'meson.build'),
+    {
+      C_ARGS: list(cArgs),
+      LINK_ARGS: list(linkArgs),
+      EXTENSION_DATA: list(data),
+      CONTRIB_DATA: list(contrib),
+      MAJOR_MINOR: pgis.majorMinor,
+    },
+  );
+  mkdirSync(path.join(directory, 'share/proj'), { recursive: true });
+  copyFileSync(
+    path.join(dependencies, 'proj/share/proj/proj.db'),
+    path.join(directory, 'share/proj/proj.db'),
+  );
+  appendSubdir(config, 'postgis');
+}
+
+const withoutTransactions = (text: string) =>
+  text.replaceAll('BEGIN;', '').replaceAll('COMMIT;', '');
+const joined = (...texts: string[]) =>
+  texts.map((text) => (text.endsWith('\n') ? text : text + '\n')).join('');
+
+export function postgisSql(config: Config, phase: string) {
+  const directory = postgisDirectory(config),
+    pgis = postgisVersion(directory);
+  const pg = path.join(directory, 'postgis'),
+    sql = path.join(directory, 'extensions/postgis/sql');
+  const raster = path.join(directory, 'raster/rt_pg');
+  mkdirSync(sql, { recursive: true });
+  if (phase === 'postgis-sql-preprocess') {
+    const template = (
+      input: string,
+      output: string,
+      includes: string[],
+      module: string,
+      strip: boolean,
+      removeSchema: boolean,
+    ) => {
+      let text = preprocessSql(input, includes).replaceAll('MODULE_PATHNAME', module);
+      if (strip) text = withoutTransactions(text);
+      if (removeSchema) text = text.replaceAll('@extschema@.', '');
+      write(output, text);
+    };
+    template(
+      path.join(directory, 'extensions/postgis_extension_helper.sql.in'),
+      path.join(directory, 'extensions/postgis_extension_helper.sql'),
+      [directory, pg],
+      '',
+      false,
+      false,
+    );
+    for (const name of ['postgis', 'legacy_minimal', 'legacy', 'legacy_gist']) {
+      template(
+        path.join(pg, name + '.sql.in'),
+        path.join(pg, name + '.sql'),
+        [pg],
+        '$libdir/postgis-3',
+        false,
+        true,
+      );
+    }
+    template(
+      path.join(pg, 'postgis.sql.in'),
+      path.join(sql, 'postgis_for_extension.sql'),
+      [pg],
+      '$libdir/postgis-3',
+      true,
+      false,
+    );
+    write(
+      path.join(sql, 'spatial_ref_sys.sql'),
+      withoutTransactions(read(path.join(directory, 'spatial_ref_sys.sql'))),
+    );
+    for (const name of ['rtpostgis', 'rtpostgis_upgrade_cleanup', 'rtpostgis_drop']) {
+      template(
+        path.join(raster, name + '.sql.in'),
+        path.join(raster, name + '.sql'),
+        [pg, raster],
+        '$libdir/rtpostgis-3',
+        false,
+        true,
+      );
+    }
+  } else if (phase === 'postgis-sql-upgrade') {
+    const upgrade = (body: string) =>
+      joined(
+        ...[
+          path.join(pg, 'common_before_upgrade.sql'),
+          path.join(pg, 'postgis_before_upgrade.sql'),
+          body,
+          path.join(pg, 'postgis_after_upgrade.sql'),
+          path.join(pg, 'common_after_upgrade.sql'),
+        ].map(read),
+      );
+    write(
+      path.join(pg, 'postgis_upgrade.sql'),
+      joined('BEGIN;', upgrade(path.join(pg, 'postgis_upgrade.sql.in')), 'COMMIT;'),
+    );
+    const extensionUpgrade = withoutTransactions(
+      upgrade(path.join(sql, 'postgis_upgrade_for_extension.sql.in')),
+    );
+    write(path.join(sql, 'postgis_upgrade_for_extension.sql'), extensionUpgrade);
+    write(
+      path.join(sql, 'postgis_upgrade.sql'),
+      extensionUpgrade
+        .split(/\r?\n/)
+        .flatMap((line) => {
+          const drop = line.match(/^(DROP .*);/);
+          return drop
+            ? [
+                `SELECT @extschema@.postgis_extension_drop_if_exists('postgis', '${drop[1]}');`,
+                line,
+              ]
+            : [line];
+        })
+        .join('\n'),
+    );
+    write(
+      path.join(sql, 'raster_drop_all.sql'),
+      joined(
+        ...['rtpostgis_upgrade_cleanup.sql', 'rtpostgis_drop.sql', 'uninstall_rtpostgis.sql'].map(
+          (file) => read(path.join(raster, file)),
+        ),
+      ),
+    );
+  } else if (phase === 'postgis-sql-install') {
+    const template = read(
+      path.join(directory, 'extensions/postgis/unpackage_raster_if_needed.sql'),
+    );
+    const marker = template.indexOf('\n', template.indexOf('UNPACKAGE_CODE'));
+    assert(
+      template.includes('UNPACKAGE_CODE') && marker !== -1,
+      'missing raster unpackage insertion marker',
+    );
+    write(
+      path.join(sql, 'raster_unpackage.sql'),
+      template.slice(0, marker + 1) +
+        joined(read(path.join(sql, 'raster_unpackage_body.sql'))) +
+        template.slice(marker + 1),
+    );
+    const guard = '\\echo Use "CREATE EXTENSION postgis" to load this file. \\quit';
+    const joinFiles = (output: string, inputs: string[]) =>
+      write(path.join(sql, output), joined(guard, ...inputs.map(read)));
+    joinFiles(
+      `postgis--${pgis.version}.sql`,
+      ['postgis_for_extension.sql', 'spatial_ref_sys_config_dump.sql', 'spatial_ref_sys.sql'].map(
+        (file) => path.join(sql, file),
+      ),
+    );
+    joinFiles(`postgis--ANY--${pgis.version}.sql`, [
+      path.join(directory, 'extensions/postgis_extension_helper.sql'),
+      ...[
+        'raster_unpackage.sql',
+        'postgis_upgrade.sql',
+        'spatial_ref_sys.sql',
+        'spatial_ref_sys_config_dump.sql',
+      ].map((file) => path.join(sql, file)),
+      path.join(directory, 'extensions/postgis_extension_helper_uninstall.sql'),
+    ]);
+    const tag = `-- Just tag extension postgis version as "ANY"\n-- Installed by postgis ${pgis.version}\n-- Built on ${sourceDate(config)}\n`;
+    write(path.join(sql, 'postgis--TEMPLATED--TO--ANY.sql'), tag);
+    write(path.join(sql, `postgis--${pgis.version}--ANY.sql`), tag);
+    write(path.join(sql, 'postgis--unpackaged.sql'), '-- Nothing to do here\n');
+  } else if (phase === 'postgis-sql-unpackaged') {
+    const file = path.join(sql, `postgis--unpackaged--${pgis.version}.sql`);
+    write(file, joined(read(file), read(path.join(sql, `postgis--ANY--${pgis.version}.sql`))));
+  } else throw new Error(`unknown SQL phase ${phase}`);
+}
+
+export function pgtap(config: Config, install = false) {
+  const directory = path.join(config.work, 'pgtap-windows'),
+    sql = path.join(directory, 'sql');
+  if (!install) {
+    copy(path.join(config.repo, 'target/oliphaunt-sources/checkouts/pgtap'), directory);
+    const expandPgtap = (module: string) =>
+      read(path.join(sql, 'pgtap.sql.in'))
+        .replaceAll('MODULE_PATHNAME', module)
+        .replaceAll('__OS__', 'MSWin32')
+        .replaceAll('__VERSION__', version(directory, 'pgtap').split('.').slice(0, 2).join('.'));
+    write(path.join(sql, 'pgtap.sql'), expandPgtap('pgtap'));
+    for (const input of glob(sql, '*.sql.in')) {
+      const output = path.join(sql, input.slice(0, -3));
+      if (!existsSync(output)) copyFileSync(path.join(sql, input), output);
+    }
+    write(path.join(sql, 'pgtap-static.sql'), expandPgtap('$libdir/pgtap'));
+  } else {
+    const release = version(directory, 'pgtap');
+    for (const name of ['pgtap', 'pgtap-core', 'pgtap-schema'])
+      copyFileSync(path.join(sql, `${name}.sql`), path.join(sql, `${name}--${release}.sql`));
+  }
+}
+
+if (import.meta.main) {
+  const phase = process.argv[2];
+  const { values } = parseArgs({
+    args: process.argv.slice(3),
+    options: Object.fromEntries(
+      ['repo', 'work', 'postgres', 'install', 'extension'].map((key) => [key, { type: 'string' }]),
+    ),
+  });
+  for (const key of ['repo', 'work', 'postgres', 'install'])
+    assert(typeof values[key] === 'string' && values[key], `missing --${key}`);
+  const config = Object.fromEntries(
+    ['repo', 'work', 'postgres', 'install'].map((key) => [
+      key,
+      path.resolve(values[key] as string),
+    ]),
+  ) as Config;
+  switch (phase) {
+    case 'simple':
+      assert(typeof values.extension === 'string', 'missing --extension');
+      prepareSimple(config, values.extension);
+      break;
+    case 'postgis-config':
+      preparePostgis(config);
+      break;
+    case 'postgis-meson':
+      postgisMeson(config);
+      break;
+    case 'postgis-version':
+      console.log(postgisVersion(postgisDirectory(config)).version);
+      break;
+    case 'postgres-major':
+      console.log(
+        String(
+          Bun.TOML.parse(read(path.join(config.repo, 'src/third-party/postgres/source.toml')))
+            .postgresql.version,
+        ).split('.')[0] + '0',
+      );
+      break;
+    case 'postgis-sql-preprocess':
+    case 'postgis-sql-upgrade':
+    case 'postgis-sql-install':
+    case 'postgis-sql-unpackaged':
+      postgisSql(config, phase);
+      break;
+    case 'pgtap':
+      pgtap(config);
+      break;
+    case 'pgtap-install':
+      pgtap(config, true);
+      break;
+    default:
+      throw new Error(`unknown Windows extension phase ${phase}`);
+  }
+}
diff --git a/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts b/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts
new file mode 100644
index 000000000..fe2adb528
--- /dev/null
+++ b/src/extensions/artifacts/native/tools/windows-extension-sources.test.mts
@@ -0,0 +1,49 @@
+import { test } from 'bun:test';
+import assert from 'node:assert/strict';
+import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import { patchTextsearch } from './windows-extension-sources.mts';
+
+test('Windows packing applies to each exact textsearch struct, including V3 predecessors', () => {
+  const root = mkdtempSync(path.join(tmpdir(), 'textsearch-windows-'));
+  const structs = [
+    ['segment/segment.h', 'TpDictEntryV3', 'aligned(4)', 4],
+    ['segment/segment.h', 'TpDictEntry', 'aligned(8)', 8],
+    ['segment/segment.h', 'TpSegmentPosting', 'packed', 1],
+    ['segment/segment.h', 'TpSkipEntryV3', 'packed', 1],
+    ['segment/segment.h', 'TpSkipEntry', 'packed', 1],
+    ['segment/segment.h', 'TpCtidMapEntry', 'packed', 1],
+    ['memtable/expull.h', 'TpExpullEntry', 'packed', 1],
+  ] as const;
+  try {
+    for (const file of [
+      'segment/segment.h',
+      'memtable/expull.h',
+      'am/am.h',
+      'types/vector.h',
+      'types/query.h',
+    ]) {
+      const target = path.join(root, 'src', file);
+      mkdirSync(path.dirname(target), { recursive: true });
+      writeFileSync(
+        target,
+        structs
+          .filter(([header]) => header === file)
+          .map(
+            ([, name, attribute]) =>
+              `typedef struct ${name}\n{ int value; } __attribute__((${attribute})) ${name};\n`,
+          )
+          .join('') || 'Datum example(PG_FUNCTION_ARGS);\n',
+      );
+    }
+    patchTextsearch(root);
+    for (const [file, name, , pack] of structs) {
+      const text = readFileSync(path.join(root, 'src', file), 'utf8');
+      assert(text.includes(`#pragma pack(push, ${pack})\n#endif\ntypedef struct ${name}\n`), name);
+      assert(text.includes(`} ${name};\n#ifdef _MSC_VER\n#pragma pack(pop)\n`), name);
+    }
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
diff --git a/src/extensions/artifacts/packages/moon.yml b/src/extensions/artifacts/packages/moon.yml
index ab5af2224..7f75eabd5 100644
--- a/src/extensions/artifacts/packages/moon.yml
+++ b/src/extensions/artifacts/packages/moon.yml
@@ -1,138 +1,163 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "extension-packages"
-language: "javascript"
-layer: "tool"
-stack: "systems"
-tags: ["extensions", "artifacts", "release"]
+$schema: https://moonrepo.dev/schemas/project.json
+id: extension-packages
+language: typescript
+layer: tool
+stack: systems
+tags:
+  - javascript-quality
+  - extensions
+  - artifacts
+  - release
 dependsOn:
-  - id: "artifact-packaging"
-    scope: "build"
-  - id: "extension-artifacts-native"
-    scope: "build"
-  - id: "extension-artifacts-wasix"
-    scope: "build"
-  - id: "extension-runtime-contract"
-    scope: "build"
-  - id: "extensions"
-    scope: "build"
-  - id: "liboliphaunt-native"
-    scope: "build"
-  - id: "liboliphaunt-wasix"
-    scope: "build"
-
+  - id: extension-artifacts-native
+    scope: build
+  - id: extension-artifacts-wasix
+    scope: build
+  - id: extension-runtime-contract
+    scope: build
+  - id: extensions
+    scope: build
+  - id: liboliphaunt-native
+    scope: build
+  - id: liboliphaunt-wasix
+    scope: build
 project:
-  title: "Extension Packages"
-  description: "Publishable exact SQL extension artifacts staged per release product."
-  owner: "oliphaunt"
-
+  title: Extension Packages
+  description: Publishable exact SQL extension artifacts staged per release product.
+  owner: oliphaunt
 tasks:
   package-mobile:
-    tags: ["release", "artifact-package", "ci-mobile-extension-packages"]
-    command: "bash src/extensions/artifacts/packages/tools/package-mobile-release-assets.sh"
+    tags:
+      - release
+      - artifact-package
+      - ci-mobile-extension-packages
+    command: bash src/extensions/artifacts/packages/tools/package-mobile-release-assets.sh
     deps:
-      - "extension-artifacts-native:build-target"
+      - extension-artifacts-native:build-target
     inputs:
       - "@group(legal-files)"
-      - "/release-please-config.json"
-      - "tools/package-mobile-release-assets.sh"
-      - project: "extensions"
-        group: "package"
-      - "/src/runtimes/liboliphaunt/native/moon.yml"
-      - "/src/runtimes/liboliphaunt/native/release.toml"
-      - "/src/runtimes/liboliphaunt/native/VERSION"
-      - "/src/runtimes/liboliphaunt/licenses/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/moon.yml"
-      - "/src/runtimes/liboliphaunt/wasix/release.toml"
-      - "/src/runtimes/liboliphaunt/wasix/VERSION"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "/src/sdks/react-native/tools/validate-mobile-runtime-files.mjs"
-      - "/tools/dev/bun.sh"
-      - "/src/sources/tools/source-fetch-core.mjs"
-      - "/tools/release/build-extension-ci-artifacts.mjs"
-      - project: "artifact-packaging"
-        group: "source"
-      - "/tools/release/cargo-source-package.mjs"
-      - "/tools/release/check-staged-artifacts.mjs"
-      - "/tools/release/extension-runtime-asset-contract.mjs"
-      - "/tools/release/extension-upstream-licenses.mjs"
-      - "/tools/release/ios-carrier-manifest.mjs"
-      - "/tools/release/tar-command.mjs"
+      - /release-please-config.json
+      - tools/package-mobile-release-assets.sh
+      - project: extensions
+        group: package
+      - /src/runtimes/liboliphaunt-native/moon.yml
+      - /src/runtimes/liboliphaunt-native/release.toml
+      - /src/runtimes/liboliphaunt-native/VERSION
+      - "@group(upstream-licenses)"
+      - /src/runtimes/liboliphaunt-wasix/moon.yml
+      - /src/runtimes/liboliphaunt-wasix/release.toml
+      - /src/runtimes/liboliphaunt-wasix/VERSION
+      - project: extension-runtime-contract
+        group: contract
+      - /src/sdks/react-native/tools/validate-mobile-runtime-files.mts
+      - /tools/dev/bun.sh
+      - /src/third-party/tools/source-fetch-core.mts
+      - /src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts
+      - "/tools/packaging/*.{mjs,mts}"
+      - /tools/packaging/cargo-source-package.mts
+      - /src/extensions/artifacts/packages/tools/check-carriers.mts
+      - /src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts
+      - /src/extensions/tools/extension-upstream-licenses.mts
+      - /src/sdks/swift/tools/ios-carrier-manifest.mts
       - "@group(release-target-contract)"
-      - "/tools/release/prepare-swift-release-consumer.mjs"
-      - "/tools/release/release-graph.mjs"
+      - /src/sdks/swift/tools/prepare-swift-release-consumer.mts
+      - /tools/release/release-graph.mts
       - "@group(release-archive-contract)"
-      - "/tools/release/rust-native-targets.mjs"
-      - "/tools/release/source-only-sdk-package.mjs"
-      - "/tools/release/swift-source-carrier-contract.mjs"
-      - "/tools/release/wasix-aot-manifest.mjs"
-      - "/tools/release/wasix-cargo-toolchain-policy.mjs"
-      - "/tools/release/wasix-cargo-artifact-contract.mjs"
-      - "/tools/release/wasix-typescript-package.mjs"
-      - "/tools/dev/moon-command.mjs"
-      - "/src/postgres/versions/18/source.toml"
-      - "/target/extensions/native/release-assets/**/*"
+      - /tools/packaging/rust-native-targets.mts
+      - /tools/packaging/source-only-sdk-package.mts
+      - /src/sdks/swift/tools/swift-source-carrier-contract.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts
+      - /src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.mts
+      - /src/third-party/postgres/source.toml
+      - /target/extensions/native/release-assets/**/*
     outputs:
-      - "/target/mobile-extension-artifacts/**/*"
+      - /target/mobile-extension-artifacts/**/*
     options:
       cache: false
       runFromWorkspaceRoot: true
       runInCI: true
-
   package:
-    tags: ["release", "artifact-package", "ci-extension-packages"]
-    command: "bash src/extensions/artifacts/packages/tools/package-release-assets.sh"
+    tags:
+      - release
+      - artifact-package
+      - ci-extension-packages
+    command: bash src/extensions/artifacts/packages/tools/package-release-assets.sh
     deps:
-      - "extension-artifacts-native:build-target"
-      - "extension-artifacts-wasix:build-target"
-      - "liboliphaunt-wasix:runtime-aot"
+      - extension-artifacts-native:build-target
+      - extension-artifacts-wasix:build-target
+      - extension-artifacts-wasix:build-aot
     inputs:
       - "@group(legal-files)"
-      - "/release-please-config.json"
-      - "tools/package-release-assets.sh"
-      - project: "extensions"
-        group: "package"
-      - "/src/runtimes/liboliphaunt/native/moon.yml"
-      - "/src/runtimes/liboliphaunt/native/release.toml"
-      - "/src/runtimes/liboliphaunt/native/VERSION"
-      - "/src/runtimes/liboliphaunt/licenses/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/moon.yml"
-      - "/src/runtimes/liboliphaunt/wasix/release.toml"
-      - "/src/runtimes/liboliphaunt/wasix/VERSION"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "/src/sdks/react-native/tools/validate-mobile-runtime-files.mjs"
-      - "/tools/dev/bun.sh"
-      - "/src/sources/tools/source-fetch-core.mjs"
-      - "/tools/release/build-extension-ci-artifacts.mjs"
-      - project: "artifact-packaging"
-        group: "source"
-      - "/tools/release/cargo-source-package.mjs"
-      - "/tools/release/check-staged-artifacts.mjs"
-      - "/tools/release/extension-runtime-asset-contract.mjs"
-      - "/tools/release/extension-upstream-licenses.mjs"
-      - "/tools/release/ios-carrier-manifest.mjs"
-      - "/tools/release/tar-command.mjs"
+      - /release-please-config.json
+      - tools/package-release-assets.sh
+      - project: extensions
+        group: package
+      - /src/runtimes/liboliphaunt-native/moon.yml
+      - /src/runtimes/liboliphaunt-native/release.toml
+      - /src/runtimes/liboliphaunt-native/VERSION
+      - "@group(upstream-licenses)"
+      - /src/runtimes/liboliphaunt-wasix/moon.yml
+      - /src/runtimes/liboliphaunt-wasix/release.toml
+      - /src/runtimes/liboliphaunt-wasix/VERSION
+      - project: extension-runtime-contract
+        group: contract
+      - /src/sdks/react-native/tools/validate-mobile-runtime-files.mts
+      - /tools/dev/bun.sh
+      - /src/third-party/tools/source-fetch-core.mts
+      - /src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts
+      - "/tools/packaging/*.{mjs,mts}"
+      - /tools/packaging/cargo-source-package.mts
+      - /src/extensions/artifacts/packages/tools/check-carriers.mts
+      - /src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts
+      - /src/extensions/tools/extension-upstream-licenses.mts
+      - /src/sdks/swift/tools/ios-carrier-manifest.mts
       - "@group(release-target-contract)"
-      - "/tools/release/prepare-swift-release-consumer.mjs"
-      - "/tools/release/release-graph.mjs"
+      - /src/sdks/swift/tools/prepare-swift-release-consumer.mts
+      - /tools/release/release-graph.mts
       - "@group(release-archive-contract)"
-      - "/tools/release/rust-native-targets.mjs"
-      - "/tools/release/source-only-sdk-package.mjs"
-      - "/tools/release/swift-source-carrier-contract.mjs"
-      - "/tools/release/wasix-aot-manifest.mjs"
-      - "/tools/release/wasix-cargo-toolchain-policy.mjs"
-      - "/tools/release/wasix-cargo-artifact-contract.mjs"
-      - "/tools/release/wasix-typescript-package.mjs"
-      - "/tools/dev/moon-command.mjs"
-      - "/src/postgres/versions/18/source.toml"
-      - "/target/extensions/native/release-assets/**/*"
-      - "/target/extensions/wasix/release-assets/**/*"
-      - "/target/extensions/wasix/aot-artifacts/**/*"
+      - /tools/packaging/rust-native-targets.mts
+      - /tools/packaging/source-only-sdk-package.mts
+      - /src/sdks/swift/tools/swift-source-carrier-contract.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts
+      - /src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.mts
+      - /src/third-party/postgres/source.toml
+      - /target/extensions/native/release-assets/**/*
+      - /target/extensions/wasix/release-assets/**/*
+      - /target/extensions/wasix/aot-artifacts/**/*
     outputs:
-      - "/target/extension-artifacts/**/*"
+      - /target/extension-artifacts/**/*
     options:
       cache: false
       runFromWorkspaceRoot: true
       runInCI: true
+  packaging-unit:
+    tags:
+      - quality
+      - unit
+      - requires-rust
+    command: bash src/extensions/artifacts/packages/tools/test.sh
+    inputs:
+      - /src/sdks/rust/sdk/crates/oliphaunt-build/src/**/*.rs
+      - /src/sdks/rust/sdk/crates/oliphaunt-build/Cargo.toml
+      - "@group(cargo-workspace)"
+      - /src/extensions/tools/extension-upstream-licenses.mts
+      - /src/extensions/contracts/*.mts
+      - /src/sdks/ts/sdk/src/native/extension-contract.ts
+      - /src/extensions/generated/**/*
+      - /src/extensions/external/**/upstream-license-data.json
+      - "@group(upstream-licenses)"
+      - "@group(legal-files)"
+      - "@group(release-target-contract)"
+      - "@group(package-test-metadata)"
+      - "**/*.{mts,sh}"
+      - /tools/packaging/testdata/**/*
+      - /tools/dev/bun.sh
+      - "/tools/packaging/*.{mts,sh}"
+      - "/tools/release/*.{mjs,mts}"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts b/src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts
new file mode 100644
index 000000000..e75029499
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts
@@ -0,0 +1,1239 @@
+#!/usr/bin/env bun
+import { createHash } from 'node:crypto';
+import {
+  copyFileSync,
+  cpSync,
+  existsSync,
+  mkdirSync,
+  readdirSync,
+  readFileSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+  chmodSync,
+} from 'node:fs';
+import path from 'node:path';
+
+import {
+  assertReleaseNoticesInArchive,
+  stageReleaseNotices,
+} from '../../../../../tools/packaging/release-notices.mts';
+import {
+  assertExtensionUpstreamLicensesInArchive,
+  extensionCarrierLegalContract,
+  stageExtensionUpstreamLicenses,
+} from '../../../tools/extension-upstream-licenses.mts';
+
+import { createDeterministicTar } from '../../../../../tools/packaging/cargo-source-package.mts';
+import { extensionRuntimeAssetContract } from './extension-runtime-asset-contract.mts';
+import { canonicalGzipSync } from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  ROOT,
+  compareText,
+  currentProductVersionSync,
+  exactExtensionProducts,
+  extensionArtifactProductRoot,
+  extensionArtifactTargets,
+  extensionMetadata,
+  extensionReleaseProduct,
+  extensionReleaseVersion,
+  extensionSourceIdentity,
+  extensionSqlNames,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  swiftExtensionCarrierAssetName,
+  writeSwiftExtensionCarrierManifest,
+} from '../../../../sdks/swift/tools/ios-carrier-manifest.mts';
+import { AOT_TARGET_TRIPLES } from '../../../../runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts';
+import { assertCanonicalWasixAotManifest } from '../../../../runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts';
+import {
+  assertWasixExtensionArchiveInstall,
+  assertWasixExtensionInstallSidecar,
+  projectWasixExtensionInstallSidecar,
+} from '../../../contracts/wasix-extension-install.mts';
+
+const PREFIX = 'build-extension-ci-artifacts.mts';
+
+function fail(message) {
+  console.error(`${PREFIX}: ${message}`);
+  process.exit(1);
+}
+
+function rel(file) {
+  return path.relative(ROOT, file).split(path.sep).join('/');
+}
+
+function sha256(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function extensionProducts() {
+  return exactExtensionProducts(PREFIX);
+}
+
+function generatedExtensionRow(sqlName) {
+  const metadata = path.join(ROOT, 'src/extensions/generated/sdk/extensions.json');
+  const data = JSON.parse(readFileSync(metadata, 'utf8'));
+  const row = (data.extensions ?? []).find((item) => item && item['sql-name'] === sqlName);
+  if (!row) {
+    fail(`generated extension metadata has no row for ${sqlName}`);
+  }
+  return row;
+}
+
+function stringList(value, label) {
+  if (
+    !Array.isArray(value) ||
+    value.some((item) => typeof item !== 'string' || item.length === 0) ||
+    new Set(value).size !== value.length
+  ) {
+    fail(`generated extension metadata ${label} must be a unique non-empty string list`);
+  }
+  return [...value].sort(compareText);
+}
+
+function propertiesCsv(values) {
+  return values.join(',');
+}
+
+export function publicExtensionReleaseAsset(asset) {
+  return extensionRuntimeAssetContract(asset);
+}
+
+function resolveRepoPath(value, { label }) {
+  const resolved = path.resolve(ROOT, value);
+  const relative = path.relative(ROOT, resolved);
+  if (relative.startsWith('..') || path.isAbsolute(relative)) {
+    fail(`${label} must be inside the repository: ${resolved}`);
+  }
+  return resolved;
+}
+
+function nativeReleaseAssetRoot() {
+  return resolveRepoPath(
+    process.env.OLIPHAUNT_NATIVE_EXTENSION_RELEASE_ASSET_ROOT ??
+      'target/extensions/native/release-assets',
+    {
+      label: 'native extension release asset root',
+    },
+  );
+}
+
+function wasixReleaseAssetRoot() {
+  return resolveRepoPath(
+    process.env.OLIPHAUNT_WASIX_EXTENSION_RELEASE_ASSET_ROOT ??
+      'target/extensions/wasix/release-assets',
+    {
+      label: 'WASIX extension release asset root',
+    },
+  );
+}
+
+function wasixAotArtifactRoot() {
+  return resolveRepoPath(
+    process.env.OLIPHAUNT_WASIX_EXTENSION_AOT_ARTIFACT_ROOT ??
+      'target/extensions/wasix/aot-artifacts',
+    {
+      label: 'WASIX extension AOT artifact root',
+    },
+  );
+}
+
+function parseTsv(file) {
+  const lines = readFileSync(file, 'utf8')
+    .split(/\r?\n/u)
+    .filter((line) => line.length > 0);
+  if (lines.length === 0) {
+    return [];
+  }
+  const header = lines[0].split('\t');
+  return lines.slice(1).map((line) => {
+    const values = line.split('\t');
+    return Object.fromEntries(header.map((column, index) => [column, values[index] ?? '']));
+  });
+}
+
+function indexContainsSqlName(index, sqlName) {
+  return parseTsv(index).some((row) => row.sql_name === sqlName);
+}
+
+function publishedTargetIds(family) {
+  return [
+    ...new Set(extensionArtifactTargets({ family }, PREFIX).map((target) => target.target)),
+  ].sort(compareText);
+}
+
+function nativeExtensionAssetIndexes(sqlName, product = undefined) {
+  const version = currentProductVersionSync('liboliphaunt-native', PREFIX);
+  const root = nativeReleaseAssetRoot();
+  const indexes = [];
+  for (const target of publishedTargetIds('native')) {
+    const targetRoot = path.join(root, target);
+    if (product !== undefined) {
+      const productIndex = path.join(
+        targetRoot,
+        product,
+        `liboliphaunt-${version}-native-extension-assets.tsv`,
+      );
+      if (existsSync(productIndex) && indexContainsSqlName(productIndex, sqlName)) {
+        indexes.push(productIndex);
+        continue;
+      }
+    }
+    const directIndex = path.join(
+      targetRoot,
+      `liboliphaunt-${version}-native-extension-assets.tsv`,
+    );
+    if (existsSync(directIndex)) {
+      indexes.push(directIndex);
+    }
+  }
+  return indexes.sort(compareText);
+}
+
+function nativeAssetsFromTargetIndexes(sqlName, { product = undefined, required = false } = {}) {
+  const indexes = nativeExtensionAssetIndexes(sqlName, product);
+  if (indexes.length === 0) {
+    return [];
+  }
+  const assets = [];
+  const seen = new Set();
+  for (const index of indexes) {
+    for (const row of parseTsv(index)) {
+      if (row.sql_name !== sqlName) {
+        continue;
+      }
+      const { target, kind, artifact } = row;
+      if (!target || !kind || !artifact) {
+        fail(`${rel(index)} has an incomplete native asset row for ${sqlName}`);
+      }
+      const identity = row.identity && row.identity !== '-' ? row.identity : null;
+      const registrationArtifact =
+        row.registration_artifact && row.registration_artifact !== '-'
+          ? path.join(path.dirname(index), row.registration_artifact)
+          : null;
+      if (kind === 'ios-dependency-xcframework' && identity === null) {
+        fail(`${rel(index)} iOS dependency XCFramework row for ${sqlName} must declare identity`);
+      }
+      if (
+        kind !== 'ios-dependency-xcframework' &&
+        identity !== null &&
+        kind !== 'ios-xcframework'
+      ) {
+        fail(`${rel(index)} ${kind} row for ${sqlName} must not declare identity`);
+      }
+      const dedupeKey = `${target}\0${kind}\0${identity ?? ''}`;
+      if (seen.has(dedupeKey)) {
+        fail(
+          `duplicate native extension asset row for ${sqlName} target=${target} kind=${kind} identity=${identity ?? '-'}`,
+        );
+      }
+      seen.add(dedupeKey);
+      const asset = path.join(path.dirname(index), artifact);
+      if (!existsSync(asset) || !statSync(asset).isFile()) {
+        fail(`${rel(index)} references missing native asset ${rel(asset)}`);
+      }
+      if (
+        registrationArtifact !== null &&
+        (!existsSync(registrationArtifact) || !statSync(registrationArtifact).isFile())
+      ) {
+        fail(`${rel(index)} references missing registration metadata ${rel(registrationArtifact)}`);
+      }
+      assets.push({ asset, target, kind, identity, registrationArtifact });
+    }
+  }
+  if (required && assets.length === 0) {
+    fail(`${sqlName} has no native extension assets in native target asset indexes`);
+  }
+  return assets;
+}
+
+function nativeAssetsFor(sqlName, { product = undefined, required = false } = {}) {
+  const indexed = nativeAssetsFromTargetIndexes(sqlName, { product, required: false });
+  if (indexed.length > 0) {
+    return indexed;
+  }
+  if (required) {
+    fail(
+      `${sqlName}${product ? ` for ${product}` : ''} has no native extension assets in native target asset indexes`,
+    );
+  }
+  return [];
+}
+
+function wasixArchiveFor(sqlName, { product = undefined, required = false } = {}) {
+  const version = currentProductVersionSync('liboliphaunt-wasix', PREFIX);
+  const root = wasixReleaseAssetRoot();
+  const indexes = [];
+  for (const target of publishedTargetIds('wasix')) {
+    const targetRoot = path.join(root, target);
+    if (product !== undefined) {
+      const productIndex = path.join(
+        targetRoot,
+        product,
+        `liboliphaunt-wasix-${version}-wasix-extension-assets.tsv`,
+      );
+      if (existsSync(productIndex)) {
+        indexes.push(productIndex);
+        continue;
+      }
+    }
+    const directIndex = path.join(
+      targetRoot,
+      `liboliphaunt-wasix-${version}-wasix-extension-assets.tsv`,
+    );
+    if (existsSync(directIndex)) {
+      indexes.push(directIndex);
+    }
+  }
+  const assets = [];
+  for (const index of indexes) {
+    for (const row of parseTsv(index)) {
+      if (row.sql_name !== sqlName) {
+        continue;
+      }
+      const { target, kind, artifact, install_contract: installContractName } = row;
+      if (
+        target !== 'wasix-portable' ||
+        kind !== 'wasix-runtime' ||
+        !artifact ||
+        !/^[1-9][0-9]*$/u.test(row.artifact_bytes ?? '') ||
+        !installContractName
+      ) {
+        fail(`${rel(index)} has an invalid WASIX asset row for ${sqlName}`);
+      }
+      const asset = path.join(path.dirname(index), artifact);
+      if (!existsSync(asset) || !statSync(asset).isFile()) {
+        fail(`${rel(index)} references missing WASIX asset ${rel(asset)}`);
+      }
+      if (statSync(asset).size !== Number(row.artifact_bytes)) {
+        fail(`${rel(index)} references a WASIX asset with a drifted byte count for ${sqlName}`);
+      }
+      const installContractPath = path.join(path.dirname(index), installContractName);
+      if (!existsSync(installContractPath) || !statSync(installContractPath).isFile()) {
+        fail(`${rel(index)} references missing WASIX install contract ${rel(installContractPath)}`);
+      }
+      let sidecar;
+      try {
+        sidecar = assertWasixExtensionInstallSidecar(
+          JSON.parse(readFileSync(installContractPath, 'utf8')),
+          {
+            expectedArchive: `extensions/${sqlName}.tar.zst`,
+            expectedSha256: sha256(asset),
+            expectedSize: statSync(asset).size,
+            expectedSqlName: sqlName,
+            label: rel(installContractPath),
+          },
+        );
+        assertWasixExtensionArchiveInstall(readFileSync(asset), sidecar, {
+          label: rel(asset),
+        });
+      } catch (error) {
+        fail(error instanceof Error ? error.message : String(error));
+      }
+      assets.push({ archive: asset, install: sidecar.install });
+    }
+  }
+  if (assets.length > 1) {
+    fail(
+      `${sqlName} has duplicate WASIX extension assets: ${assets.map(({ archive }) => rel(archive)).join(', ')}`,
+    );
+  }
+  if (assets.length === 1) {
+    return assets[0];
+  }
+  const generatedRootValue = process.env.OLIPHAUNT_WASIX_GENERATED_ASSET_ROOT;
+  if (generatedRootValue) {
+    const generatedRoot = resolveRepoPath(generatedRootValue, {
+      label: 'generated WASIX asset root',
+    });
+    const manifestPath = path.join(generatedRoot, 'manifest.json');
+    if (!existsSync(manifestPath) || !statSync(manifestPath).isFile()) {
+      fail(`generated WASIX asset root is missing ${rel(manifestPath)}`);
+    }
+    let manifest;
+    try {
+      manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
+    } catch (error) {
+      fail(`${rel(manifestPath)} is not valid JSON: ${error.message}`);
+    }
+    const rows = Array.isArray(manifest.extensions)
+      ? manifest.extensions.filter((row) => row?.['sql-name'] === sqlName)
+      : [];
+    if (rows.length !== 1) {
+      fail(
+        `${rel(manifestPath)} must contain exactly one extension row for ${sqlName}, got ${rows.length}`,
+      );
+    }
+    const row = rows[0];
+    const expectedArchive = `extensions/${sqlName}.tar.zst`;
+    if (row.archive !== expectedArchive || !/^[0-9a-f]{64}$/u.test(row.sha256 ?? '')) {
+      fail(`${rel(manifestPath)} has a noncanonical archive identity for ${sqlName}`);
+    }
+    const archive = path.join(generatedRoot, expectedArchive);
+    if (!existsSync(archive) || !statSync(archive).isFile()) {
+      fail(`${rel(manifestPath)} references missing WASIX extension archive ${rel(archive)}`);
+    }
+    if (sha256(archive) !== row.sha256) {
+      fail(`${rel(archive)} does not match the digest in ${rel(manifestPath)}`);
+    }
+    const modelPath = path.join(ROOT, 'src/extensions/generated/wasix/extensions.json');
+    let model;
+    try {
+      model = JSON.parse(readFileSync(modelPath, 'utf8'));
+    } catch (error) {
+      fail(`${rel(modelPath)} is not valid JSON: ${error.message}`);
+    }
+    const modelRows = Array.isArray(model.extensions)
+      ? model.extensions.filter((candidate) => candidate?.['sql-name'] === sqlName)
+      : [];
+    if (modelRows.length !== 1) {
+      fail(
+        `${rel(modelPath)} must contain exactly one static extension row for ${sqlName}, got ${modelRows.length}`,
+      );
+    }
+    let sidecar;
+    try {
+      sidecar = projectWasixExtensionInstallSidecar(
+        {
+          modelRow: modelRows[0],
+          manifestRow: row,
+        },
+        {
+          archiveBytes: readFileSync(archive),
+          label: `${rel(manifestPath)} extension ${sqlName}`,
+        },
+      );
+    } catch (error) {
+      fail(error instanceof Error ? error.message : String(error));
+    }
+    return { archive, install: sidecar.install };
+  }
+  if (required) {
+    fail(
+      `${sqlName} has no WASIX extension assets in target/extensions/wasix/release-assets target indexes`,
+    );
+  }
+  return undefined;
+}
+
+function wasixAotDirsFor(sqlName) {
+  const root = wasixAotArtifactRoot();
+  if (!existsSync(root) || !statSync(root).isDirectory()) {
+    return [];
+  }
+  return readdirSync(root, { withFileTypes: true })
+    .filter((entry) => entry.isDirectory())
+    .map((entry) => [entry.name, path.join(root, entry.name, sqlName)])
+    .filter(([, candidate]) => existsSync(path.join(candidate, 'manifest.json')))
+    .sort(([left], [right]) => compareText(left, right));
+}
+
+function validateWasixAotDir(targetId, source) {
+  const expectedTarget = AOT_TARGET_TRIPLES[targetId];
+  if (expectedTarget === undefined) {
+    fail(`WASIX extension AOT artifact root contains unknown target id ${targetId}`);
+  }
+  const manifestPath = path.join(source, 'manifest.json');
+  let manifest;
+  try {
+    manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
+  } catch (error) {
+    fail(`${rel(manifestPath)} is not valid JSON: ${error.message}`);
+  }
+  try {
+    assertCanonicalWasixAotManifest(manifest, {
+      context: rel(manifestPath),
+      expectedTarget,
+    });
+  } catch (error) {
+    fail(error.message);
+  }
+}
+
+function copyAsset(source, destinationDir, { name }) {
+  mkdirSync(destinationDir, { recursive: true });
+  const destination = path.join(destinationDir, name);
+  copyFileSync(source, destination);
+  // Release payloads are data, not host executables.  A fixed mode keeps the
+  // aggregate archive independent of the producer's umask and checkout mode.
+  chmodSync(destination, 0o644);
+  return {
+    name: path.basename(destination),
+    path: rel(destination),
+    source: rel(source),
+    sha256: sha256(destination),
+    bytes: statSync(destination).size,
+  };
+}
+
+function nativeAssetName(product, version, target, kind, source) {
+  const suffix = archiveSuffix(source);
+  if (target === 'macos-arm64') {
+    return `${product}-${version}-native-macos-arm64-runtime${suffix}`;
+  }
+  if (target.startsWith('linux-')) {
+    return `${product}-${version}-native-${target}-runtime${suffix}`;
+  }
+  if (target.startsWith('windows-')) {
+    return `${product}-${version}-native-${target}-runtime${suffix}`;
+  }
+  if (target === 'ios-xcframework') {
+    if (kind === 'runtime') {
+      return `${product}-${version}-native-ios-runtime${suffix}`;
+    }
+    if (kind === 'ios-xcframework') {
+      return `${product}-${version}-native-ios-xcframework${suffix}`;
+    }
+    if (kind === 'ios-dependency-xcframework') {
+      fail(
+        `iOS dependency XCFramework ${path.basename(source)} requires its exact dependency identity`,
+      );
+    }
+    fail(`unsupported iOS extension artifact kind ${kind} for ${path.basename(source)}`);
+  }
+  if (target.startsWith('android-')) {
+    if (kind === 'runtime') {
+      return `${product}-${version}-native-${target}-runtime${suffix}`;
+    }
+    if (kind === 'android-static-archive') {
+      return `${product}-${version}-native-${target}-static${suffix}`;
+    }
+    fail(`unsupported Android extension artifact kind ${kind} for ${path.basename(source)}`);
+  }
+  fail(`unsupported native extension artifact target ${target} for ${path.basename(source)}`);
+}
+
+function nativeAssetNameForRow(product, version, row) {
+  if (row.kind === 'ios-dependency-xcframework') {
+    return `${product}-${version}-native-ios-dependency-${row.identity}-xcframework${archiveSuffix(row.asset)}`;
+  }
+  return nativeAssetName(product, version, row.target, row.kind, row.asset);
+}
+
+function readIosRegistration(file, { sqlName, nativeModuleStem }) {
+  if (file === null) return null;
+  let value;
+  try {
+    value = JSON.parse(readFileSync(file, 'utf8'));
+  } catch (error) {
+    fail(`${rel(file)} is not valid registration JSON: ${error.message}`);
+  }
+  if (
+    value?.schema !== 'oliphaunt-ios-extension-registration-v1' ||
+    value.sqlName !== sqlName ||
+    value.nativeModuleStem !== nativeModuleStem ||
+    typeof value.magicSymbol !== 'string' ||
+    !(value.initSymbol === null || typeof value.initSymbol === 'string') ||
+    !Array.isArray(value.symbols)
+  ) {
+    fail(`${rel(file)} does not describe ${sqlName}/${nativeModuleStem} iOS registration`);
+  }
+  return value;
+}
+
+function archiveSuffix(source) {
+  for (const suffix of ['.tar.gz', '.tar.zst', '.zip']) {
+    if (source.endsWith(suffix)) {
+      return suffix;
+    }
+  }
+  fail(`native extension asset ${path.basename(source)} must use .tar.gz, .tar.zst, or .zip`);
+}
+
+function validateStagedTargets(
+  product,
+  assets,
+  { requireNative, requireWasix, requireNativeTargets },
+) {
+  const declaredNativeTargets = new Set(
+    extensionArtifactTargets({ product, family: 'native' }, PREFIX).map((target) => target.target),
+  );
+  const declaredWasixTargets = new Set(
+    extensionArtifactTargets({ product, family: 'wasix' }, PREFIX).map((target) => target.target),
+  );
+  const stagedNativeTargets = new Set(
+    assets.filter((asset) => asset.family === 'native').map((asset) => String(asset.target)),
+  );
+  const stagedWasixTargets = new Set(
+    assets.filter((asset) => asset.family === 'wasix').map((asset) => String(asset.target)),
+  );
+  const extraNative = [...stagedNativeTargets]
+    .filter((target) => !declaredNativeTargets.has(target))
+    .sort(compareText);
+  const extraWasix = [...stagedWasixTargets]
+    .filter((target) => !declaredWasixTargets.has(target))
+    .sort(compareText);
+  if (extraNative.length > 0) {
+    fail(`${product} staged undeclared native extension targets: ${extraNative.join(', ')}`);
+  }
+  if (extraWasix.length > 0) {
+    fail(`${product} staged undeclared WASIX extension targets: ${extraWasix.join(', ')}`);
+  }
+  if (requireNativeTargets.size > 0) {
+    const unknownRequired = [...requireNativeTargets]
+      .filter((target) => !declaredNativeTargets.has(target))
+      .sort(compareText);
+    if (unknownRequired.length > 0) {
+      fail(
+        `${product} was asked to require undeclared native targets: ${unknownRequired.join(', ')}`,
+      );
+    }
+    const missingNative = [...requireNativeTargets]
+      .filter((target) => !stagedNativeTargets.has(target))
+      .sort(compareText);
+    if (missingNative.length > 0) {
+      fail(`${product} is missing native extension artifacts for: ${missingNative.join(', ')}`);
+    }
+  } else if (requireNative) {
+    const missingNative = [...declaredNativeTargets]
+      .filter((target) => !stagedNativeTargets.has(target))
+      .sort(compareText);
+    if (missingNative.length > 0) {
+      fail(`${product} is missing native extension artifacts for: ${missingNative.join(', ')}`);
+    }
+  }
+  if (requireWasix) {
+    const missingWasix = [...declaredWasixTargets]
+      .filter((target) => !stagedWasixTargets.has(target))
+      .sort(compareText);
+    if (missingWasix.length > 0) {
+      fail(`${product} is missing WASIX extension artifacts for: ${missingWasix.join(', ')}`);
+    }
+  }
+}
+
+function publicMemberAsset(asset) {
+  return publicExtensionReleaseAsset(asset);
+}
+
+function stageMember(
+  product,
+  sqlName,
+  version,
+  productRoot,
+  { destinationDir, bundle, families, requireNative, requireWasix, requireNativeTargets },
+) {
+  const extensionRow = generatedExtensionRow(sqlName);
+  const assets = [];
+  let wasixInstall = null;
+  let iosRegistration = null;
+  for (const row of families.has('native')
+    ? nativeAssetsFor(sqlName, { product, required: requireNative })
+    : []) {
+    const target = row.target;
+    if (requireNativeTargets.size > 0 && !requireNativeTargets.has(target)) {
+      continue;
+    }
+    const metadata = copyAsset(row.asset, destinationDir, {
+      name: nativeAssetNameForRow(product, version, row),
+    });
+    metadata.family = 'native';
+    metadata.kind = row.kind;
+    metadata.target = target;
+    metadata.identity = row.identity;
+    assets.push(metadata);
+    if (row.registrationArtifact !== null) {
+      const registration = readIosRegistration(row.registrationArtifact, {
+        sqlName,
+        nativeModuleStem: extensionRow['native-module-stem'],
+      });
+      if (
+        iosRegistration !== null &&
+        JSON.stringify(iosRegistration) !== JSON.stringify(registration)
+      ) {
+        fail(`${product} has conflicting iOS registration metadata`);
+      }
+      iosRegistration = registration;
+    }
+  }
+
+  const wasix = families.has('wasix')
+    ? wasixArchiveFor(sqlName, { product, required: requireWasix })
+    : undefined;
+  if (wasix !== undefined) {
+    const metadata = copyAsset(wasix.archive, destinationDir, {
+      name: `${product}-${version}-wasix-portable.tar.zst`,
+    });
+    metadata.family = 'wasix';
+    metadata.kind = 'wasix-runtime';
+    metadata.target = 'wasix-portable';
+    metadata.identity = null;
+    assets.push(metadata);
+    wasixInstall = wasix.install;
+  }
+
+  for (const [targetId, source] of families.has('wasix') ? wasixAotDirsFor(sqlName) : []) {
+    validateWasixAotDir(targetId, source);
+    const destination = bundle
+      ? path.join(productRoot, 'wasix-aot', targetId, sqlName)
+      : path.join(productRoot, 'wasix-aot', targetId);
+    rmSync(destination, { recursive: true, force: true });
+    cpSync(source, destination, { recursive: true });
+  }
+
+  validateStagedTargets(product, assets, {
+    requireNative,
+    requireWasix,
+    requireNativeTargets,
+  });
+  if (assets.length === 0) {
+    fail(`${product}/${sqlName} produced no extension artifacts`);
+  }
+  return {
+    sqlName,
+    createsExtension: extensionRow['creates-extension'] !== false,
+    dependencies: stringList(
+      extensionRow['selected-extension-dependencies'],
+      `${sqlName}.selected-extension-dependencies`,
+    ),
+    dataFiles: stringList(
+      extensionRow['runtime-share-data-files'],
+      `${sqlName}.runtime-share-data-files`,
+    ),
+    extensionSqlFileNames: stringList(
+      extensionRow['extension-sql-file-names'],
+      `${sqlName}.extension-sql-file-names`,
+    ),
+    extensionSqlFilePrefixes: stringList(
+      extensionRow['extension-sql-file-prefixes'],
+      `${sqlName}.extension-sql-file-prefixes`,
+    ),
+    nativeModuleStem: extensionRow['native-module-stem'],
+    iosNativeDependencies: assets
+      .filter((asset) => asset.kind === 'ios-dependency-xcframework')
+      .map((asset) => asset.identity)
+      .sort(compareText),
+    iosRegistration,
+    wasixInstall,
+    sharedPreloadLibraries: stringList(
+      extensionRow['shared-preload-libraries'],
+      `${sqlName}.shared-preload-libraries`,
+    ),
+    assets,
+  };
+}
+
+function bundleCarrierAssets(product, version, productRoot, members, compatibility) {
+  const assetDir = path.join(productRoot, 'release-assets');
+  const stageRoot = path.join(productRoot, '.bundle-stage');
+  const groups = new Map();
+  for (const member of members) {
+    for (const asset of member.assets) {
+      const key = `${asset.family}\0${asset.target}`;
+      const group = groups.get(key) ?? { family: asset.family, target: asset.target, rows: [] };
+      group.rows.push({ sqlName: member.sqlName, asset });
+      groups.set(key, group);
+    }
+  }
+  const carrierAssets = [];
+  for (const group of [...groups.values()].sort((left, right) =>
+    compareText(`${left.family}\0${left.target}`, `${right.family}\0${right.target}`),
+  )) {
+    const memberNames = [...new Set(group.rows.map((row) => row.sqlName))].sort(compareText);
+    const expectedNames = members.map((member) => member.sqlName).sort(compareText);
+    if (JSON.stringify(memberNames) !== JSON.stringify(expectedNames)) {
+      fail(
+        `${product} ${group.family}/${group.target} bundle is missing exact members: expected ${expectedNames.join(',')}, got ${memberNames.join(',')}`,
+      );
+    }
+    const archiveRoot = `${product}-${version}-${group.family}-${group.target}-bundle`;
+    const stageDir = path.join(stageRoot, archiveRoot);
+    rmSync(stageDir, { recursive: true, force: true });
+    mkdirSync(stageDir, { recursive: true });
+    const manifestMembers = [];
+    for (const row of group.rows.sort((left, right) =>
+      compareText(
+        `${left.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ''}`,
+        `${right.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ''}`,
+      ),
+    )) {
+      const memberPath = `extensions/${row.sqlName}/${row.asset.name}`;
+      const source = path.join(ROOT, row.asset.path);
+      const destination = path.join(stageDir, ...memberPath.split('/'));
+      mkdirSync(path.dirname(destination), { recursive: true });
+      copyFileSync(source, destination);
+      chmodSync(destination, 0o644);
+      const copiedSha256 = sha256(destination);
+      const copiedBytes = statSync(destination).size;
+      if (copiedSha256 !== row.asset.sha256 || copiedBytes !== row.asset.bytes) {
+        fail(
+          `${product} ${group.family}/${group.target} changed ${row.sqlName} member bytes while staging ${memberPath}`,
+        );
+      }
+      const member = {
+        sqlName: row.sqlName,
+        kind: row.asset.kind,
+        identity: row.asset.identity ?? null,
+        path: memberPath,
+        sha256: row.asset.sha256,
+        bytes: row.asset.bytes,
+      };
+      manifestMembers.push(member);
+      row.asset.carrierAsset = `${archiveRoot}.tar.gz`;
+      row.asset.carrierRoot = archiveRoot;
+      row.asset.memberPath = memberPath;
+    }
+    const externalLicenseFiles = [];
+    for (const sqlName of memberNames) {
+      externalLicenseFiles.push(...stageExtensionUpstreamLicenses(sqlName, stageDir));
+    }
+    const legal = extensionCarrierLegalContract(product, memberNames, {
+      family: group.family,
+      target: group.target,
+    });
+    const stagedLicenseFiles = [...new Set(externalLicenseFiles)].sort(compareText);
+    if (JSON.stringify(stagedLicenseFiles) !== JSON.stringify(legal.licenseFiles)) {
+      fail(
+        `${product} ${group.family}/${group.target} staged upstream licenses differ from its legal contract: ` +
+          `expected ${legal.licenseFiles.join(',')}, got ${stagedLicenseFiles.join(',')}`,
+      );
+    }
+    const bundleManifest = path.join(stageDir, 'bundle-manifest.json');
+    writeFileSync(
+      bundleManifest,
+      `${JSON.stringify(
+        sortValue({
+          schema: 'oliphaunt-extension-bundle-v1',
+          product,
+          version,
+          compatibility,
+          family: group.family,
+          target: group.target,
+          licenseProfile: legal.profile,
+          licenseFiles: legal.licenseFiles,
+          members: manifestMembers,
+        }),
+        null,
+        2,
+      )}\n`,
+      'utf8',
+    );
+    chmodSync(bundleManifest, 0o644);
+    stageReleaseNotices(stageDir, { profile: legal.profile });
+    const output = path.join(assetDir, `${archiveRoot}.tar.gz`);
+    writeFileSync(
+      output,
+      canonicalGzipSync(
+        createDeterministicTar(stageDir, archiveRoot, {
+          fail,
+          includeDirectories: false,
+          // Every bundle member is data. Windows filesystem modes are synthetic,
+          // so encode the portable carrier contract instead of copying stat bits.
+          fixedFileMode: 0o644,
+        }),
+      ),
+    );
+    assertReleaseNoticesInArchive(output, {
+      prefix: archiveRoot,
+      profile: legal.profile,
+    });
+    if (legal.upstreamMembers.length > 0) {
+      assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, output, {
+        prefix: archiveRoot,
+      });
+    }
+    carrierAssets.push({
+      name: path.basename(output),
+      path: rel(output),
+      sha256: sha256(output),
+      bytes: statSync(output).size,
+      family: group.family,
+      target: group.target,
+      kind: 'extension-bundle',
+      memberCount: memberNames.length,
+    });
+  }
+  rmSync(stageRoot, { recursive: true, force: true });
+  return carrierAssets;
+}
+
+export function extensionReleasePropertiesText({
+  product,
+  releaseProduct = product,
+  family = null,
+  version,
+  manifest,
+  releaseData,
+  directAssets,
+}) {
+  const sourceIdentity = releaseData.sourceIdentity;
+  const propertiesLines = [
+    `schema=${releaseData.schema}\n`,
+    `product=${product}\n`,
+    ...(releaseProduct === product
+      ? []
+      : [`releaseProduct=${releaseProduct}\n`, `carrierFamily=${family ?? 'combined'}\n`]),
+    `version=${version}\n`,
+    `extensionClass=${releaseData.extensionClass}\n`,
+    `versioning=${releaseData.versioning}\n`,
+    `sourceKind=${sourceIdentity.kind}\n`,
+  ];
+  if (manifest.schema === 'oliphaunt-extension-ci-artifacts-v1') {
+    propertiesLines.push(
+      `sqlName=${manifest.sqlName}\n`,
+      `createsExtension=${manifest.createsExtension ? 'true' : 'false'}\n`,
+      `dependencies=${propertiesCsv(manifest.dependencies)}\n`,
+      `dataFiles=${propertiesCsv(manifest.dataFiles)}\n`,
+      `extensionSqlFileNames=${propertiesCsv(manifest.extensionSqlFileNames)}\n`,
+      `extensionSqlFilePrefixes=${propertiesCsv(manifest.extensionSqlFilePrefixes)}\n`,
+      `nativeModuleStem=${manifest.nativeModuleStem || ''}\n`,
+      `iosNativeDependencies=${propertiesCsv(manifest.iosNativeDependencies)}\n`,
+      `sharedPreloadLibraries=${propertiesCsv(manifest.sharedPreloadLibraries)}\n`,
+    );
+    for (const asset of [...manifest.assets].sort((left, right) =>
+      compareText(
+        `${left.family}\0${left.target}\0${left.kind}\0${left.identity ?? ''}\0${left.name}`,
+        `${right.family}\0${right.target}\0${right.kind}\0${right.identity ?? ''}\0${right.name}`,
+      ),
+    )) {
+      const identity =
+        asset.identity === null || asset.identity === undefined ? '' : `.${asset.identity}`;
+      propertiesLines.push(
+        `asset.${asset.family}.${asset.target}.${asset.kind}${identity}=${asset.name}\n`,
+      );
+    }
+  } else {
+    propertiesLines.push(`extensions=${manifest.extensions.map((row) => row.sqlName).join(',')}\n`);
+    for (const member of manifest.extensions) {
+      const prefix = `extension.${member.sqlName}`;
+      propertiesLines.push(
+        `${prefix}.createsExtension=${member.createsExtension ? 'true' : 'false'}\n`,
+        `${prefix}.dependencies=${propertiesCsv(member.dependencies)}\n`,
+        `${prefix}.dataFiles=${propertiesCsv(member.dataFiles)}\n`,
+        `${prefix}.extensionSqlFileNames=${propertiesCsv(member.extensionSqlFileNames)}\n`,
+        `${prefix}.extensionSqlFilePrefixes=${propertiesCsv(member.extensionSqlFilePrefixes)}\n`,
+        `${prefix}.nativeModuleStem=${member.nativeModuleStem || ''}\n`,
+        `${prefix}.iosNativeDependencies=${propertiesCsv(member.iosNativeDependencies)}\n`,
+        `${prefix}.sharedPreloadLibraries=${propertiesCsv(member.sharedPreloadLibraries)}\n`,
+      );
+      for (const asset of member.assets) {
+        const identity =
+          asset.identity === null || asset.identity === undefined ? '' : `.${asset.identity}`;
+        propertiesLines.push(
+          `asset.${member.sqlName}.${asset.family}.${asset.target}.${asset.kind}${identity}=${asset.carrierAsset}:${asset.memberPath}:${asset.sha256}:${asset.bytes}\n`,
+        );
+      }
+    }
+    for (const asset of [...directAssets].sort((left, right) =>
+      compareText(
+        `${left.family}\0${left.target}\0${left.kind}`,
+        `${right.family}\0${right.target}\0${right.kind}`,
+      ),
+    )) {
+      propertiesLines.push(`carrier.${asset.family}.${asset.target}.${asset.kind}=${asset.name}\n`);
+    }
+  }
+  return propertiesLines.join('');
+}
+
+function writeReleaseControls({
+  product,
+  releaseProduct,
+  family,
+  version,
+  productRoot,
+  manifest,
+  releaseData,
+  releaseMetadata,
+  directAssets,
+}) {
+  const assetDir = path.join(productRoot, 'release-assets');
+  const extensionManifest = path.join(productRoot, 'extension-artifacts.json');
+  writeFileSync(extensionManifest, `${JSON.stringify(sortValue(manifest), null, 2)}\n`, 'utf8');
+  const swiftCarrier = directAssets.some(
+    (asset) => asset.family === 'native' && asset.target === 'ios-xcframework',
+  )
+    ? path.join(assetDir, swiftExtensionCarrierAssetName(product, version))
+    : null;
+  if (swiftCarrier !== null) {
+    writeSwiftExtensionCarrierManifest(swiftCarrier, {
+      extensionManifest,
+      nativeRuntimeVersion: releaseMetadata.compatibility.nativeRuntimeVersion,
+    });
+  }
+  const releaseManifest = path.join(assetDir, `${product}-${version}-manifest.json`);
+  writeFileSync(releaseManifest, `${JSON.stringify(sortValue(releaseData), null, 2)}\n`, 'utf8');
+
+  const propertiesManifest = path.join(assetDir, `${product}-${version}-manifest.properties`);
+  writeFileSync(
+    propertiesManifest,
+    extensionReleasePropertiesText({
+      product,
+      releaseProduct,
+      family,
+      version,
+      manifest,
+      releaseData,
+      directAssets,
+    }),
+    'utf8',
+  );
+
+  const checksumManifest = path.join(assetDir, `${product}-${version}-release-assets.sha256`);
+  const checksumLines = readdirSync(assetDir)
+    .map((name) => path.join(assetDir, name))
+    .filter((file) => statSync(file).isFile() && file !== checksumManifest)
+    .sort(compareText)
+    .map((file) => `${sha256(file)}  ./${path.basename(file)}\n`);
+  writeFileSync(checksumManifest, checksumLines.join(''), 'utf8');
+  const payloadPaths = Object.freeze(directAssets.map((asset) => asset.path));
+  const controlPaths = Object.freeze([
+    rel(releaseManifest),
+    rel(propertiesManifest),
+    ...(swiftCarrier === null ? [] : [rel(swiftCarrier)]),
+    rel(checksumManifest),
+  ]);
+  const artifactPaths = [...new Set([...payloadPaths, ...controlPaths])];
+  writeFileSync(
+    path.join(productRoot, 'artifacts.txt'),
+    artifactPaths.map((file) => `${file}\n`).join(''),
+    'utf8',
+  );
+  return { swiftCarrier, releaseManifest, propertiesManifest, checksumManifest };
+}
+
+function stageProductVariant(
+  product,
+  { outputRoot, family, requireNative, requireWasix, requireNativeTargets },
+) {
+  const known = new Set(extensionProducts());
+  if (!known.has(product)) {
+    fail(
+      `unknown exact-extension product ${product}; expected one of: ${[...known].sort(compareText).join(', ')}`,
+    );
+  }
+  const families = new Set(family === null ? ['native', 'wasix'] : [family]);
+  const releaseProduct = extensionReleaseProduct(product, family ?? 'native', PREFIX);
+  const ownership =
+    releaseProduct === product ? {} : { releaseProduct, family: family ?? 'combined' };
+  const sqlNames = extensionSqlNames(product, PREFIX);
+  const version = extensionReleaseVersion(product, family ?? 'native', PREFIX);
+  const productRoot = extensionArtifactProductRoot(product, family ?? 'native', outputRoot, PREFIX);
+  const assetDir = path.join(productRoot, 'release-assets');
+  rmSync(productRoot, { recursive: true, force: true });
+  mkdirSync(assetDir, { recursive: true });
+  const bundle = sqlNames.length > 1;
+  const members = sqlNames.map((sqlName) =>
+    stageMember(product, sqlName, version, productRoot, {
+      destinationDir: bundle ? path.join(productRoot, 'member-assets', sqlName) : assetDir,
+      bundle,
+      families,
+      requireNative: families.has('native') && requireNative,
+      requireWasix: families.has('wasix') && requireWasix,
+      requireNativeTargets: families.has('native') ? requireNativeTargets : new Set(),
+    }),
+  );
+  const releaseMetadata = extensionMetadata(product, PREFIX);
+  let manifest;
+  let releaseData;
+  let directAssets;
+  if (bundle) {
+    directAssets = bundleCarrierAssets(
+      product,
+      version,
+      productRoot,
+      members,
+      releaseMetadata.compatibility,
+    );
+    manifest = {
+      schema: 'oliphaunt-extension-ci-artifacts-v2',
+      product,
+      ...ownership,
+      version,
+      compatibility: releaseMetadata.compatibility,
+      extensions: members,
+      carrierAssets: directAssets,
+    };
+    releaseData = {
+      schema: 'oliphaunt-extension-release-manifest-v2',
+      product,
+      ...ownership,
+      version,
+      extensionClass: releaseMetadata.class,
+      versioning: releaseMetadata.versioning,
+      sourceIdentity: extensionSourceIdentity(product, PREFIX),
+      compatibility: releaseMetadata.compatibility,
+      extensions: members.map((member) => ({
+        ...member,
+        assets: member.assets.map(publicMemberAsset),
+      })),
+      assets: directAssets.map(publicExtensionReleaseAsset),
+    };
+  } else {
+    const member = members[0];
+    directAssets = member.assets;
+    manifest = {
+      schema: 'oliphaunt-extension-ci-artifacts-v1',
+      product,
+      ...ownership,
+      version,
+      compatibility: releaseMetadata.compatibility,
+      ...member,
+    };
+    releaseData = {
+      schema: 'oliphaunt-extension-release-manifest-v1',
+      product,
+      ...ownership,
+      version,
+      sqlName: member.sqlName,
+      extensionClass: releaseMetadata.class,
+      versioning: releaseMetadata.versioning,
+      sourceIdentity: extensionSourceIdentity(product, PREFIX),
+      compatibility: releaseMetadata.compatibility,
+      dependencies: member.dependencies,
+      dataFiles: member.dataFiles,
+      extensionSqlFileNames: member.extensionSqlFileNames,
+      extensionSqlFilePrefixes: member.extensionSqlFilePrefixes,
+      createsExtension: member.createsExtension,
+      nativeModuleStem: member.nativeModuleStem,
+      iosNativeDependencies: member.iosNativeDependencies,
+      iosRegistration: member.iosRegistration,
+      wasixInstall: member.wasixInstall,
+      sharedPreloadLibraries: member.sharedPreloadLibraries,
+      assets: member.assets.map(publicExtensionReleaseAsset),
+    };
+  }
+  writeReleaseControls({
+    product,
+    releaseProduct,
+    family,
+    version,
+    productRoot,
+    manifest,
+    releaseData,
+    releaseMetadata,
+    directAssets,
+  });
+  console.log(
+    `${product} (${family ?? 'combined'}, owned by ${releaseProduct}): staged ${members.length} exact member(s) in ${directAssets.length} direct carrier asset(s) under ${rel(productRoot)}`,
+  );
+}
+
+function stageProduct(product, options) {
+  const nativeOwner = extensionReleaseProduct(product, 'native', PREFIX);
+  const wasixOwner = extensionReleaseProduct(product, 'wasix', PREFIX);
+  const families =
+    options.family === null
+      ? nativeOwner === wasixOwner
+        ? [null]
+        : ['native', 'wasix']
+      : [options.family];
+  for (const family of families) {
+    stageProductVariant(product, { ...options, family });
+  }
+}
+
+function selectedProductsFromEnv() {
+  const raw = process.env.OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS ?? '';
+  const products = [
+    ...new Set(
+      raw
+        .split(',')
+        .map((item) => item.trim())
+        .filter(Boolean),
+    ),
+  ].sort(compareText);
+  if (products.length === 0) {
+    return [];
+  }
+  const known = new Set(extensionProducts());
+  const unknown = products.filter((product) => !known.has(product));
+  if (unknown.length > 0) {
+    fail(
+      `OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS contains unknown exact-extension product(s): ${unknown.join(', ')}`,
+    );
+  }
+  return products;
+}
+
+function parseArgs(argv) {
+  const args = {
+    products: [],
+    all: false,
+    outputRoot: 'target/extension-artifacts',
+    family: null,
+    requireNative: false,
+    requireWasix: false,
+    requireNativeTargets: new Set(),
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--all') {
+      args.all = true;
+    } else if (arg === '--output-root') {
+      const value = argv[index + 1];
+      if (!value) {
+        fail('--output-root requires a value');
+      }
+      args.outputRoot = value;
+      index += 1;
+    } else if (arg === '--require-native') {
+      args.requireNative = true;
+    } else if (arg === '--family') {
+      const value = argv[index + 1];
+      if (!value || !['native', 'wasix'].includes(value)) {
+        fail('--family requires native or wasix');
+      }
+      args.family = value;
+      index += 1;
+    } else if (arg === '--require-native-target') {
+      const value = argv[index + 1];
+      if (!value) {
+        fail('--require-native-target requires a value');
+      }
+      args.requireNativeTargets.add(value);
+      index += 1;
+    } else if (arg === '--require-wasix') {
+      args.requireWasix = true;
+    } else if (arg === '--help' || arg === '-h') {
+      console.log(
+        'usage: src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts [--all] [--output-root DIR] [--family native|wasix] [--require-native] [--require-native-target TARGET] [--require-wasix] [products...]',
+      );
+      process.exit(0);
+    } else if (arg.startsWith('--')) {
+      fail(`unknown argument ${arg}`);
+    } else {
+      args.products.push(arg);
+    }
+  }
+  return args;
+}
+
+function sortValue(value) {
+  if (Array.isArray(value)) {
+    return value.map(sortValue);
+  }
+  if (value !== null && typeof value === 'object') {
+    return Object.fromEntries(
+      Object.keys(value)
+        .sort(compareText)
+        .map((key) => [key, sortValue(value[key])]),
+    );
+  }
+  return value;
+}
+
+async function main(argv) {
+  const args = parseArgs(argv);
+  const envProducts = selectedProductsFromEnv();
+  const products =
+    envProducts.length > 0 ? envProducts : args.all ? extensionProducts() : args.products;
+  if (products.length === 0) {
+    fail('pass --all or at least one exact-extension product id');
+  }
+  const outputRoot = resolveRepoPath(args.outputRoot, { label: 'output root' });
+  for (const product of products) {
+    await stageProduct(product, {
+      outputRoot,
+      family: args.family,
+      requireNative: args.requireNative,
+      requireWasix: args.requireWasix,
+      requireNativeTargets: args.requireNativeTargets,
+    });
+  }
+}
+
+if (import.meta.main) {
+  await main(Bun.argv.slice(2));
+}
diff --git a/src/extensions/artifacts/packages/tools/check-carriers.mts b/src/extensions/artifacts/packages/tools/check-carriers.mts
new file mode 100644
index 000000000..0a5f50a96
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/check-carriers.mts
@@ -0,0 +1,1369 @@
+import { createHash } from 'node:crypto';
+import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
+import path from 'node:path';
+import {
+  buildSwiftExtensionCarrierManifest,
+  swiftExtensionCarrierAssetName,
+} from '../../../../sdks/swift/tools/ios-carrier-manifest.mts';
+import {
+  portableMemberName,
+  readFileOnlyTarGzipEntries,
+} from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  archiveTarNames,
+  archiveZipNames,
+  fail,
+  isFile,
+  PREFIX,
+  readJson,
+  readPropertiesText,
+  rel,
+  sha256File,
+} from '../../../../../tools/packaging/release-carrier.mts';
+import {
+  assertReleaseNoticesInArchive,
+  releaseNoticeRows,
+} from '../../../../../tools/packaging/release-notices.mts';
+import {
+  compareText,
+  exactExtensionProducts,
+  extensionArtifactProductRoot,
+  extensionArtifactTargets,
+  extensionMetadata,
+  extensionReleaseProduct,
+  extensionReleaseVersion,
+  extensionSourceIdentity,
+  extensionSqlNames,
+  ROOT,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import { assertWasixExtensionMemberInstall } from '../../../contracts/wasix-extension-install.mts';
+import {
+  assertExtensionUpstreamLicensesInArchive,
+  extensionCarrierLegalContract,
+} from '../../../tools/extension-upstream-licenses.mts';
+import { extensionRuntimeAssetContract } from './extension-runtime-asset-contract.mts';
+
+export const EXTENSION_ROOT = path.resolve(
+  ROOT,
+  process.env.OLIPHAUNT_EXTENSION_ARTIFACT_ROOT ?? 'target/extension-artifacts',
+);
+
+if (path.relative(ROOT, EXTENSION_ROOT).startsWith('..')) {
+  throw new Error('extension artifact root must stay inside the repository');
+}
+
+const PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS = new Set([
+  'schema',
+  'product',
+  'version',
+  'sqlName',
+  'extensionClass',
+  'versioning',
+  'sourceIdentity',
+  'compatibility',
+  'createsExtension',
+  'dependencies',
+  'dataFiles',
+  'extensionSqlFileNames',
+  'extensionSqlFilePrefixes',
+  'nativeModuleStem',
+  'iosNativeDependencies',
+  'iosRegistration',
+  'wasixInstall',
+  'sharedPreloadLibraries',
+  'assets',
+]);
+
+const PUBLIC_EXTENSION_BUNDLE_RELEASE_MANIFEST_KEYS = new Set([
+  'schema',
+  'product',
+  'version',
+  'extensionClass',
+  'versioning',
+  'sourceIdentity',
+  'compatibility',
+  'extensions',
+  'assets',
+]);
+
+const EXTENSION_BUNDLE_MEMBER_KEYS = new Set([
+  'sqlName',
+  'createsExtension',
+  'dependencies',
+  'dataFiles',
+  'extensionSqlFileNames',
+  'extensionSqlFilePrefixes',
+  'nativeModuleStem',
+  'iosNativeDependencies',
+  'iosRegistration',
+  'wasixInstall',
+  'sharedPreloadLibraries',
+  'assets',
+]);
+
+const PUBLIC_EXTENSION_RELEASE_ASSET_KEYS = new Set([
+  'name',
+  'family',
+  'target',
+  'kind',
+  'identity',
+  'sha256',
+  'bytes',
+]);
+
+const PUBLIC_EXTENSION_RELEASE_ASSET_KEY_ORDER = [
+  'name',
+  'family',
+  'target',
+  'kind',
+  'identity',
+  'sha256',
+  'bytes',
+];
+
+const PUBLIC_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS = new Set([
+  ...PUBLIC_EXTENSION_RELEASE_ASSET_KEY_ORDER,
+  'carrierAsset',
+  'carrierRoot',
+  'memberPath',
+]);
+
+const PUBLIC_EXTENSION_BUNDLE_CARRIER_ASSET_KEYS = new Set([
+  'name',
+  'family',
+  'target',
+  'kind',
+  'sha256',
+  'bytes',
+  'memberCount',
+]);
+
+const INTERNAL_EXTENSION_BUNDLE_ROOT_KEYS = new Set([
+  'schema',
+  'product',
+  'version',
+  'compatibility',
+  'extensions',
+  'carrierAssets',
+]);
+
+const INTERNAL_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS = new Set([
+  'name',
+  'path',
+  'source',
+  'sha256',
+  'bytes',
+  'family',
+  'kind',
+  'target',
+  'identity',
+  'carrierAsset',
+  'carrierRoot',
+  'memberPath',
+]);
+
+const INTERNAL_EXTENSION_BUNDLE_CARRIER_ASSET_KEYS = new Set([
+  'name',
+  'path',
+  'sha256',
+  'bytes',
+  'family',
+  'target',
+  'kind',
+  'memberCount',
+]);
+
+function bundleTarEntries(file) {
+  let archiveEntries;
+  try {
+    archiveEntries = readFileOnlyTarGzipEntries(file, { fileMode: 0o644 });
+  } catch (error) {
+    fail(`${rel(file)} is not a consumer-compatible bundle: ${error.message}`);
+  }
+  const entries = new Map();
+  for (const [name, entry] of archiveEntries) {
+    entries.set(name, Buffer.from(entry.data()));
+  }
+  if (entries.size === 0) {
+    fail(`${rel(file)} must contain at least one regular file and a canonical tar end marker`);
+  }
+  return entries;
+}
+
+function validateZstdArchiveMagic(file) {
+  if (
+    !readFileSync(file)
+      .subarray(0, 4)
+      .equals(Buffer.from([0x28, 0xb5, 0x2f, 0xfd]))
+  ) {
+    fail(`${rel(file)} is not a zstd archive`);
+  }
+}
+
+function validateReleaseArchivePayload(file) {
+  if (file.endsWith('.tar.gz') || file.endsWith('.tgz') || file.endsWith('.crate')) {
+    if (archiveTarNames(file).length === 0) {
+      fail(`${rel(file)} must contain at least one file`);
+    }
+    return;
+  }
+  if (file.endsWith('.zip') || file.endsWith('.aar') || file.endsWith('.jar')) {
+    if (archiveZipNames(file).length === 0) {
+      fail(`${rel(file)} must contain at least one file`);
+    }
+    return;
+  }
+  if (file.endsWith('.tar.zst')) {
+    validateZstdArchiveMagic(file);
+  }
+}
+
+function extensionArtifactKindAllowed(family, target, kind) {
+  if (family === 'wasix') {
+    return target === 'wasix-portable' && kind === 'wasix-runtime';
+  }
+  if (family !== 'native') {
+    return false;
+  }
+  if (target === 'ios-xcframework') {
+    return new Set(['runtime', 'ios-xcframework', 'ios-dependency-xcframework']).has(kind);
+  }
+  if (target.startsWith('android-')) {
+    return kind === 'runtime';
+  }
+  return kind === 'runtime';
+}
+
+function publicExtensionAsset(asset) {
+  return extensionRuntimeAssetContract(asset);
+}
+
+function requireExactKeys(value, expected, context) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(`${context} must be an object`);
+  }
+  const actual = new Set(Object.keys(value));
+  if (!setEquals(actual, expected)) {
+    fail(
+      `${context} keys must be ${JSON.stringify([...expected].sort(compareText))}, got ${JSON.stringify([...actual].sort(compareText))}`,
+    );
+  }
+}
+
+function requireSortedUniqueStrings(value, context) {
+  if (
+    !Array.isArray(value) ||
+    value.some((item) => typeof item !== 'string' || !item) ||
+    new Set(value).size !== value.length ||
+    JSON.stringify(value) !== JSON.stringify([...value].sort(compareText))
+  ) {
+    fail(`${context} must be a sorted unique string list`);
+  }
+}
+
+function validateMemberWasixInstall(member, context) {
+  try {
+    assertWasixExtensionMemberInstall(member, { label: context });
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+}
+
+function publicExtensionBundleMember(member) {
+  return {
+    ...Object.fromEntries(Object.entries(member).filter(([key]) => key !== 'assets')),
+    assets: member.assets.map(publicExtensionAsset),
+  };
+}
+
+function publicExtensionBundleCarrier(asset) {
+  return extensionRuntimeAssetContract(asset);
+}
+
+export function expectedExtensionBundleManifest({ product, version, data, carrier, rows }) {
+  const legal = extensionCarrierLegalContract(
+    product,
+    [...new Set(rows.map(({ member }) => member.sqlName))].sort(compareText),
+    { family: carrier.family, target: carrier.target },
+  );
+  return {
+    schema: 'oliphaunt-extension-bundle-v1',
+    product,
+    version,
+    compatibility: data.compatibility,
+    family: carrier.family,
+    target: carrier.target,
+    licenseProfile: legal.profile,
+    licenseFiles: legal.licenseFiles,
+    members: rows.map(({ member, asset }) => ({
+      sqlName: member.sqlName,
+      kind: asset.kind,
+      identity: asset.identity,
+      path: asset.memberPath,
+      sha256: asset.sha256,
+      bytes: asset.bytes,
+    })),
+  };
+}
+
+function expectedExtensionRoles(member, targets) {
+  const roles = [];
+  const nativeStem =
+    typeof member.nativeModuleStem === 'string' && member.nativeModuleStem
+      ? member.nativeModuleStem
+      : null;
+  for (const target of [...targets].sort(compareText)) {
+    if (target === 'wasix-portable') {
+      roles.push(`wasix:${target}:wasix-runtime:`);
+      continue;
+    }
+    roles.push(`native:${target}:runtime:`);
+    if (target === 'ios-xcframework' && nativeStem !== null) {
+      roles.push(`native:${target}:ios-xcframework:${nativeStem}`);
+      for (const dependency of member.iosNativeDependencies) {
+        roles.push(`native:${target}:ios-dependency-xcframework:${dependency}`);
+      }
+    }
+  }
+  return roles.sort(compareText);
+}
+
+function validateBundleMemberMetadata(member, manifest, stagedTargets) {
+  requireExactKeys(
+    member,
+    EXTENSION_BUNDLE_MEMBER_KEYS,
+    `${rel(manifest)} member ${JSON.stringify(member?.sqlName)}`,
+  );
+  if (typeof member.sqlName !== 'string' || !member.sqlName) {
+    fail(`${rel(manifest)} bundle member must declare sqlName`);
+  }
+  if (typeof member.createsExtension !== 'boolean') {
+    fail(`${rel(manifest)} member ${member.sqlName} createsExtension must be boolean`);
+  }
+  for (const field of [
+    'dependencies',
+    'dataFiles',
+    'extensionSqlFileNames',
+    'extensionSqlFilePrefixes',
+    'iosNativeDependencies',
+    'sharedPreloadLibraries',
+  ]) {
+    requireSortedUniqueStrings(member[field], `${rel(manifest)} member ${member.sqlName}.${field}`);
+  }
+  if (
+    !(
+      member.nativeModuleStem === null ||
+      (typeof member.nativeModuleStem === 'string' && member.nativeModuleStem)
+    )
+  ) {
+    fail(
+      `${rel(manifest)} member ${member.sqlName}.nativeModuleStem must be null or a non-empty string`,
+    );
+  }
+  validateMemberWasixInstall(member, `${rel(manifest)} member ${member.sqlName}`);
+  const stagesIos = stagedTargets.has('ios-xcframework');
+  if (member.nativeModuleStem === null) {
+    if (member.iosNativeDependencies.length > 0 || member.iosRegistration !== null) {
+      fail(
+        `${rel(manifest)} SQL-only member ${member.sqlName} must not declare iOS native metadata`,
+      );
+    }
+  } else if (stagesIos) {
+    if (
+      member.iosRegistration === null ||
+      Array.isArray(member.iosRegistration) ||
+      typeof member.iosRegistration !== 'object'
+    ) {
+      fail(
+        `${rel(manifest)} native member ${member.sqlName} must include build-derived iOS registration metadata`,
+      );
+    }
+    if (
+      member.iosRegistration.sqlName !== member.sqlName ||
+      member.iosRegistration.nativeModuleStem !== member.nativeModuleStem
+    ) {
+      fail(
+        `${rel(manifest)} iOS registration metadata does not match ${member.sqlName}/${member.nativeModuleStem}`,
+      );
+    }
+  } else if (member.iosNativeDependencies.length > 0 || member.iosRegistration !== null) {
+    fail(
+      `${rel(manifest)} member ${member.sqlName} must not claim iOS metadata without an iOS carrier`,
+    );
+  }
+}
+
+function checkExtensionArtifactInventory(root, expectedPaths) {
+  const inventory = path.join(root, 'artifacts.txt');
+  if (!isFile(inventory)) {
+    fail(`${rel(root)} must contain artifacts.txt`);
+  }
+  const actual = readFileSync(inventory, 'utf8').split(/\r?\n/u).filter(Boolean);
+  if (new Set(actual).size !== actual.length) {
+    fail(`${rel(inventory)} must not contain duplicate upload paths`);
+  }
+  const normalizedExpected = [...new Set(expectedPaths)];
+  if (JSON.stringify(actual) !== JSON.stringify(normalizedExpected)) {
+    fail(
+      `${rel(inventory)} must enumerate direct publish artifacts exactly: expected=${JSON.stringify(normalizedExpected)}, actual=${JSON.stringify(actual)}`,
+    );
+  }
+}
+
+async function checkExtensionBundleProduct(
+  product,
+  root,
+  manifest,
+  data,
+  { family, requireFullTargets },
+) {
+  const releaseProduct = extensionReleaseProduct(product, family ?? 'native', PREFIX);
+  const ownership = releaseProduct === product ? {} : { releaseProduct, family };
+  requireExactKeys(
+    data,
+    new Set([...INTERNAL_EXTENSION_BUNDLE_ROOT_KEYS, ...Object.keys(ownership)]),
+    rel(manifest),
+  );
+  const version = extensionReleaseVersion(product, family ?? 'native', PREFIX);
+  if (
+    data.product !== product ||
+    data.version !== version ||
+    Object.entries(ownership).some(([key, value]) => data[key] !== value)
+  ) {
+    fail(`${rel(manifest)} must describe ${product}@${version}`);
+  }
+  const releaseMetadata = extensionMetadata(product, PREFIX);
+  if (!deepEqual(data.compatibility, releaseMetadata.compatibility)) {
+    fail(`${rel(manifest)} has stale compatibility metadata`);
+  }
+  const expectedSqlNames = extensionSqlNames(product, PREFIX);
+  if (!Array.isArray(data.extensions)) {
+    fail(`${rel(manifest)} must declare extensions`);
+  }
+  const actualSqlNames = data.extensions.map((member) => member?.sqlName);
+  if (JSON.stringify(actualSqlNames) !== JSON.stringify(expectedSqlNames)) {
+    fail(
+      `${rel(manifest)} bundle members must exactly match release metadata: expected=${JSON.stringify(expectedSqlNames)}, actual=${JSON.stringify(actualSqlNames)}`,
+    );
+  }
+
+  const targetRows = extensionArtifactTargets({ product }, PREFIX).filter(
+    (row) => family === null || row.family === family,
+  );
+  const allowedTargetFamilies = new Map();
+  for (const row of targetRows) {
+    const current = allowedTargetFamilies.get(row.target);
+    if (current !== undefined && current !== row.family) {
+      fail(`${product} release metadata maps ${row.target} to multiple artifact families`);
+    }
+    allowedTargetFamilies.set(row.target, row.family);
+  }
+  const allowedTargets = new Set(allowedTargetFamilies.keys());
+  if (!Array.isArray(data.carrierAssets) || data.carrierAssets.length === 0) {
+    fail(`${rel(manifest)} must declare at least one aggregate carrier`);
+  }
+  const carriersByName = new Map();
+  const carrierEntries = new Map();
+  const carrierLegal = new Map();
+  const seenCarrierRoles = new Set();
+  const stagedTargets = new Set();
+  for (const carrier of data.carrierAssets) {
+    requireExactKeys(
+      carrier,
+      INTERNAL_EXTENSION_BUNDLE_CARRIER_ASSET_KEYS,
+      `${rel(manifest)} carrier ${JSON.stringify(carrier?.name)}`,
+    );
+    const { name, path: pathValue, family, target, kind, sha256, bytes, memberCount } = carrier;
+    if (
+      ![name, pathValue, family, target, kind, sha256].every(
+        (value) => typeof value === 'string' && value,
+      )
+    ) {
+      fail(`${rel(manifest)} contains an incomplete aggregate carrier: ${JSON.stringify(carrier)}`);
+    }
+    if (kind !== 'extension-bundle' || memberCount !== expectedSqlNames.length) {
+      fail(
+        `${rel(manifest)} carrier ${name} must be an exact ${expectedSqlNames.length}-member extension-bundle`,
+      );
+    }
+    if (!/^[0-9a-f]{64}$/u.test(sha256) || !Number.isInteger(bytes) || bytes <= 0) {
+      fail(`${rel(manifest)} carrier ${name} must declare a positive byte count and SHA-256`);
+    }
+    if (allowedTargetFamilies.get(target) !== family) {
+      fail(`${rel(manifest)} carrier ${name} uses undeclared family/target ${family}/${target}`);
+    }
+    const role = `${family}:${target}`;
+    if (seenCarrierRoles.has(role) || carriersByName.has(name)) {
+      fail(`${rel(manifest)} repeats aggregate carrier ${role} or name ${name}`);
+    }
+    seenCarrierRoles.add(role);
+    carriersByName.set(name, carrier);
+    stagedTargets.add(target);
+    const expectedName = `${product}-${version}-${family}-${target}-bundle.tar.gz`;
+    if (name !== expectedName) {
+      fail(`${rel(manifest)} carrier ${name} must use canonical name ${expectedName}`);
+    }
+    const carrierPath = path.join(ROOT, pathValue);
+    if (
+      path.dirname(carrierPath) !== path.join(root, 'release-assets') ||
+      path.basename(carrierPath) !== name
+    ) {
+      fail(
+        `${rel(manifest)} aggregate carrier ${name} must live directly under ${rel(path.join(root, 'release-assets'))}`,
+      );
+    }
+    if (
+      !isFile(carrierPath) ||
+      statSync(carrierPath).size !== bytes ||
+      sha256File(carrierPath) !== sha256
+    ) {
+      fail(
+        `${rel(manifest)} aggregate carrier ${name} is missing or does not match its outer size/digest`,
+      );
+    }
+    const legal = extensionCarrierLegalContract(product, expectedSqlNames, { family, target });
+    const carrierRoot = name.replace(/\.tar\.gz$/u, '');
+    assertReleaseNoticesInArchive(carrierPath, {
+      prefix: carrierRoot,
+      profile: legal.profile,
+    });
+    if (legal.upstreamMembers.length > 0) {
+      assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, carrierPath, {
+        prefix: carrierRoot,
+      });
+    }
+    carrierLegal.set(name, legal);
+    carrierEntries.set(name, bundleTarEntries(carrierPath));
+  }
+  if (requireFullTargets) {
+    const missing = [...allowedTargets]
+      .filter((target) => !stagedTargets.has(target))
+      .sort(compareText);
+    if (missing.length > 0) {
+      fail(`${product} is missing aggregate carriers for declared targets: ${missing.join(', ')}`);
+    }
+  }
+
+  const allMemberAssets = [];
+  for (const member of data.extensions) {
+    validateBundleMemberMetadata(member, manifest, stagedTargets);
+    if (!Array.isArray(member.assets) || member.assets.length === 0) {
+      fail(`${rel(manifest)} member ${member.sqlName} must declare assets`);
+    }
+    const roles = new Set();
+    const memberTargets = new Set();
+    for (const asset of member.assets) {
+      requireExactKeys(
+        asset,
+        INTERNAL_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS,
+        `${rel(manifest)} member ${member.sqlName} asset ${JSON.stringify(asset?.name)}`,
+      );
+      const {
+        name,
+        path: pathValue,
+        source,
+        family,
+        target,
+        kind,
+        identity,
+        sha256,
+        bytes,
+        carrierAsset,
+        carrierRoot,
+        memberPath,
+      } = asset;
+      if (
+        ![
+          name,
+          pathValue,
+          source,
+          family,
+          target,
+          kind,
+          sha256,
+          carrierAsset,
+          carrierRoot,
+          memberPath,
+        ].every((value) => typeof value === 'string' && value)
+      ) {
+        fail(`${rel(manifest)} member ${member.sqlName} contains an incomplete nested asset`);
+      }
+      if (!/^[0-9a-f]{64}$/u.test(sha256) || !Number.isInteger(bytes) || bytes <= 0) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} asset ${name} must declare a positive byte count and SHA-256`,
+        );
+      }
+      if (!(identity === null || (typeof identity === 'string' && identity))) {
+        fail(`${rel(manifest)} member ${member.sqlName} asset ${name} has invalid identity`);
+      }
+      if (kind === 'ios-dependency-xcframework' && identity === null) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} iOS dependency ${name} must declare identity`,
+        );
+      }
+      if (
+        kind !== 'ios-dependency-xcframework' &&
+        kind !== 'ios-xcframework' &&
+        identity !== null
+      ) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} asset ${name} must not declare identity for kind=${kind}`,
+        );
+      }
+      if (
+        allowedTargetFamilies.get(target) !== family ||
+        !extensionArtifactKindAllowed(family, target, kind)
+      ) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} asset ${name} uses invalid family/target/kind ${family}/${target}/${kind}`,
+        );
+      }
+      const role = `${family}:${target}:${kind}:${identity ?? ''}`;
+      if (roles.has(role)) {
+        fail(`${rel(manifest)} member ${member.sqlName} repeats artifact role ${role}`);
+      }
+      roles.add(role);
+      memberTargets.add(target);
+      const carrier = carriersByName.get(carrierAsset);
+      if (carrier === undefined || carrier.family !== family || carrier.target !== target) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} asset ${name} references the wrong aggregate carrier ${carrierAsset}`,
+        );
+      }
+      const expectedCarrierRoot = carrierAsset.replace(/\.tar\.gz$/u, '');
+      const expectedMemberPath = `extensions/${member.sqlName}/${name}`;
+      if (carrierRoot !== expectedCarrierRoot || memberPath !== expectedMemberPath) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} asset ${name} has a noncanonical nested locator`,
+        );
+      }
+      const composedPath = `${carrierRoot}/${memberPath}`;
+      if (
+        portableMemberName(
+          composedPath,
+          'file',
+          path.join(root, 'release-assets', carrierAsset),
+        ) !== composedPath
+      ) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} asset ${name} has an unsafe nested locator`,
+        );
+      }
+      const localPath = path.join(ROOT, pathValue);
+      const expectedLocalDir = path.join(root, 'member-assets', member.sqlName);
+      if (path.dirname(localPath) !== expectedLocalDir || path.basename(localPath) !== name) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} asset ${name} must be staged under ${rel(expectedLocalDir)}`,
+        );
+      }
+      if (
+        !isFile(localPath) ||
+        statSync(localPath).size !== bytes ||
+        sha256File(localPath) !== sha256
+      ) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} local asset ${name} is missing or does not match its size/digest`,
+        );
+      }
+      // bundleTarEntries also applies this contract to every key in
+      // the archive before any nested member is looked up.
+      const inner = carrierEntries.get(carrierAsset)?.get(composedPath);
+      if (
+        inner === undefined ||
+        inner.length !== bytes ||
+        createHash('sha256').update(inner).digest('hex') !== sha256
+      ) {
+        fail(
+          `${rel(manifest)} member ${member.sqlName} asset ${name} is missing or has wrong bytes inside ${carrierAsset}`,
+        );
+      }
+      allMemberAssets.push({ member, asset });
+    }
+    if (!setEquals(memberTargets, stagedTargets)) {
+      fail(
+        `${rel(manifest)} member ${member.sqlName} must be present in every staged aggregate target`,
+      );
+    }
+    const expectedRoles = expectedExtensionRoles(member, stagedTargets);
+    const actualRoles = [...roles].sort(compareText);
+    if (JSON.stringify(actualRoles) !== JSON.stringify(expectedRoles)) {
+      fail(
+        `${rel(manifest)} member ${member.sqlName} artifact roles are not dependency-closed: expected=${JSON.stringify(expectedRoles)}, actual=${JSON.stringify(actualRoles)}`,
+      );
+    }
+  }
+
+  for (const carrier of data.carrierAssets) {
+    const carrierRoot = carrier.name.replace(/\.tar\.gz$/u, '');
+    const rows = allMemberAssets
+      .filter(({ asset }) => asset.carrierAsset === carrier.name)
+      .sort((left, right) =>
+        compareText(
+          `${left.member.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ''}`,
+          `${right.member.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ''}`,
+        ),
+      );
+    const memberNames = [...new Set(rows.map(({ member }) => member.sqlName))].sort(compareText);
+    if (JSON.stringify(memberNames) !== JSON.stringify(expectedSqlNames)) {
+      fail(`${rel(manifest)} carrier ${carrier.name} does not contain every exact bundle member`);
+    }
+    const expectedBundleManifest = expectedExtensionBundleManifest({
+      product,
+      version,
+      data,
+      carrier,
+      rows,
+    });
+    const entries = carrierEntries.get(carrier.name);
+    const manifestName = `${carrierRoot}/bundle-manifest.json`;
+    const manifestBytes = entries.get(manifestName);
+    if (manifestBytes === undefined) {
+      fail(`${carrier.name} is missing ${manifestName}`);
+    }
+    const expectedManifestBytes = Buffer.from(
+      `${JSON.stringify(sortValue(expectedBundleManifest), null, 2)}\n`,
+    );
+    if (!manifestBytes.equals(expectedManifestBytes)) {
+      fail(
+        `${carrier.name} bundle-manifest.json must use its exact canonical nested member and legal bytes`,
+      );
+    }
+    let actualBundleManifest;
+    try {
+      actualBundleManifest = JSON.parse(manifestBytes.toString('utf8'));
+    } catch (error) {
+      fail(`${carrier.name} has invalid bundle-manifest.json: ${error.message}`);
+    }
+    if (!deepEqual(actualBundleManifest, expectedBundleManifest)) {
+      fail(
+        `${carrier.name} bundle-manifest.json does not exactly describe its nested member bytes`,
+      );
+    }
+    const expectedArchiveNames = [
+      manifestName,
+      ...rows.map(({ asset }) => `${carrierRoot}/${asset.memberPath}`),
+      ...releaseNoticeRows({ profile: carrierLegal.get(carrier.name).profile }).map(
+        ({ member }) => `${carrierRoot}/${member}`,
+      ),
+      ...carrierLegal.get(carrier.name).licenseFiles.map((member) => `${carrierRoot}/${member}`),
+    ].sort(compareText);
+    const actualArchiveNames = [...entries.keys()].sort(compareText);
+    if (JSON.stringify(actualArchiveNames) !== JSON.stringify(expectedArchiveNames)) {
+      fail(`${carrier.name} contents do not exactly match its declared members`);
+    }
+  }
+
+  const releaseManifest = path.join(root, 'release-assets', `${product}-${version}-manifest.json`);
+  const releaseData = readJson(releaseManifest);
+  requireExactKeys(
+    releaseData,
+    new Set([...PUBLIC_EXTENSION_BUNDLE_RELEASE_MANIFEST_KEYS, ...Object.keys(ownership)]),
+    rel(releaseManifest),
+  );
+  const expectedReleaseData = {
+    schema: 'oliphaunt-extension-release-manifest-v2',
+    product,
+    ...ownership,
+    version,
+    extensionClass: releaseMetadata.class,
+    versioning: releaseMetadata.versioning,
+    sourceIdentity: extensionSourceIdentity(product, PREFIX),
+    compatibility: releaseMetadata.compatibility,
+    extensions: data.extensions.map(publicExtensionBundleMember),
+    assets: data.carrierAssets.map(publicExtensionBundleCarrier),
+  };
+  if (!deepEqual(releaseData, expectedReleaseData)) {
+    fail(`${rel(releaseManifest)} must exactly match stable metadata and nested staged artifacts`);
+  }
+  for (const member of releaseData.extensions) {
+    requireExactKeys(
+      member,
+      EXTENSION_BUNDLE_MEMBER_KEYS,
+      `${rel(releaseManifest)} member ${member?.sqlName}`,
+    );
+    for (const asset of member.assets) {
+      requireExactKeys(
+        asset,
+        PUBLIC_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS,
+        `${rel(releaseManifest)} member ${member.sqlName} asset ${asset?.name}`,
+      );
+    }
+  }
+  for (const carrier of releaseData.assets) {
+    requireExactKeys(
+      carrier,
+      PUBLIC_EXTENSION_BUNDLE_CARRIER_ASSET_KEYS,
+      `${rel(releaseManifest)} carrier ${carrier?.name}`,
+    );
+  }
+
+  const stagesIos = stagedTargets.has('ios-xcframework');
+  const swiftCarrier = path.join(
+    root,
+    'release-assets',
+    swiftExtensionCarrierAssetName(product, version),
+  );
+  if (stagesIos) {
+    if (!isFile(swiftCarrier)) {
+      fail(`${product} must stage independently consumable Swift iOS carrier ${rel(swiftCarrier)}`);
+    }
+    let expectedCarrier;
+    try {
+      expectedCarrier = buildSwiftExtensionCarrierManifest({
+        extensionManifest: manifest,
+        nativeRuntimeVersion: releaseMetadata.compatibility.nativeRuntimeVersion,
+      });
+    } catch (error) {
+      fail(
+        `${rel(swiftCarrier)} cannot be derived from exact staged bundle artifacts: ${error.message}`,
+      );
+    }
+    if (!deepEqual(readJson(swiftCarrier), expectedCarrier)) {
+      fail(
+        `${rel(swiftCarrier)} must exactly describe every bundle member and its compatible native base`,
+      );
+    }
+  } else if (isFile(swiftCarrier)) {
+    fail(`${product} must not stage a Swift carrier without an iOS aggregate carrier`);
+  }
+
+  const propertiesManifest = path.join(
+    root,
+    'release-assets',
+    `${product}-${version}-manifest.properties`,
+  );
+  if (!isFile(propertiesManifest)) {
+    fail(`${product} must stage properties manifest ${rel(propertiesManifest)}`);
+  }
+  const expectedProperties = {
+    schema: 'oliphaunt-extension-release-manifest-v2',
+    product,
+    ...(releaseProduct === product ? {} : { releaseProduct, carrierFamily: family }),
+    version: String(version),
+    extensionClass: String(releaseData.extensionClass),
+    versioning: String(releaseData.versioning),
+    sourceKind: String(releaseData.sourceIdentity.kind),
+    extensions: expectedSqlNames.join(','),
+  };
+  for (const member of data.extensions) {
+    const prefix = `extension.${member.sqlName}`;
+    expectedProperties[`${prefix}.createsExtension`] = member.createsExtension ? 'true' : 'false';
+    expectedProperties[`${prefix}.dependencies`] = member.dependencies.join(',');
+    expectedProperties[`${prefix}.dataFiles`] = member.dataFiles.join(',');
+    expectedProperties[`${prefix}.extensionSqlFileNames`] = member.extensionSqlFileNames.join(',');
+    expectedProperties[`${prefix}.extensionSqlFilePrefixes`] =
+      member.extensionSqlFilePrefixes.join(',');
+    expectedProperties[`${prefix}.nativeModuleStem`] = member.nativeModuleStem ?? '';
+    expectedProperties[`${prefix}.iosNativeDependencies`] = member.iosNativeDependencies.join(',');
+    expectedProperties[`${prefix}.sharedPreloadLibraries`] =
+      member.sharedPreloadLibraries.join(',');
+    for (const asset of member.assets) {
+      const identity = asset.identity === null ? '' : `.${asset.identity}`;
+      expectedProperties[
+        `asset.${member.sqlName}.${asset.family}.${asset.target}.${asset.kind}${identity}`
+      ] = `${asset.carrierAsset}:${asset.memberPath}:${asset.sha256}:${asset.bytes}`;
+    }
+  }
+  for (const carrier of data.carrierAssets) {
+    expectedProperties[`carrier.${carrier.family}.${carrier.target}.${carrier.kind}`] =
+      carrier.name;
+  }
+  const actualProperties = readPropertiesText(readFileSync(propertiesManifest, 'utf8'));
+  if (!deepEqual(actualProperties, expectedProperties)) {
+    fail(
+      `${rel(propertiesManifest)} must exactly describe every aggregate carrier and nested member locator`,
+    );
+  }
+
+  const checksumManifest = path.join(
+    root,
+    'release-assets',
+    `${product}-${version}-release-assets.sha256`,
+  );
+  if (!isFile(checksumManifest)) {
+    fail(`${product} must stage checksum manifest ${rel(checksumManifest)}`);
+  }
+  validateChecksumManifest(checksumManifest, path.join(root, 'release-assets'));
+  checkExtensionArtifactInventory(root, [
+    ...data.carrierAssets.map((asset) => asset.path),
+    rel(releaseManifest),
+    rel(propertiesManifest),
+    ...(stagesIos ? [rel(swiftCarrier)] : []),
+    rel(checksumManifest),
+  ]);
+  console.log(
+    `validated exact-extension bundle artifacts: ${product} (${expectedSqlNames.length} members, ${data.carrierAssets.length} carriers)`,
+  );
+  return true;
+}
+
+async function checkExtensionProductVariant(
+  product,
+  root,
+  manifest,
+  data,
+  { family, requireFullTargets },
+) {
+  if (data.schema === 'oliphaunt-extension-ci-artifacts-v2') {
+    return checkExtensionBundleProduct(product, root, manifest, data, {
+      family,
+      requireFullTargets,
+    });
+  }
+  const releaseProduct = extensionReleaseProduct(product, family ?? 'native', PREFIX);
+  const ownership = releaseProduct === product ? {} : { releaseProduct, family };
+  const expected = {
+    schema: 'oliphaunt-extension-ci-artifacts-v1',
+    product,
+    ...ownership,
+    version: extensionReleaseVersion(product, family ?? 'native', PREFIX),
+  };
+  const metadata = extensionMetadata(product, PREFIX);
+  for (const [key, value] of Object.entries(expected)) {
+    if (data[key] !== value) {
+      fail(
+        `${rel(manifest)} has ${key}=${JSON.stringify(data[key])}, expected ${JSON.stringify(value)}`,
+      );
+    }
+  }
+  if (!deepEqual(data.compatibility, metadata.compatibility)) {
+    fail(`${rel(manifest)} has stale compatibility metadata`);
+  }
+  const sqlNames = extensionSqlNames(product, PREFIX);
+  if (sqlNames.length !== 1) {
+    fail(`${product} singleton artifact manifest requires exactly one SQL name`);
+  }
+  const [expectedSqlName] = sqlNames;
+  if (data.sqlName !== expectedSqlName) {
+    fail(
+      `${rel(manifest)} has sqlName=${JSON.stringify(data.sqlName)}, expected ${JSON.stringify(expectedSqlName)}`,
+    );
+  }
+  if (typeof data.createsExtension !== 'boolean') {
+    fail(`${rel(manifest)}.createsExtension must be boolean`);
+  }
+  for (const field of [
+    'dependencies',
+    'dataFiles',
+    'extensionSqlFileNames',
+    'extensionSqlFilePrefixes',
+    'sharedPreloadLibraries',
+  ]) {
+    requireSortedUniqueStrings(data[field], `${rel(manifest)}.${field}`);
+  }
+  const assets = data.assets;
+  if (!Array.isArray(assets) || assets.length === 0) {
+    fail(`${rel(manifest)} must declare at least one asset`);
+  }
+  const seenNames = new Set();
+  const seenRoles = new Set();
+  const stagedTargets = new Set();
+  const allowedTargets = new Set(
+    extensionArtifactTargets({ product }, PREFIX).map((target) => target.target),
+  );
+  for (const asset of assets) {
+    if (asset === null || Array.isArray(asset) || typeof asset !== 'object') {
+      fail(`${rel(manifest)} contains a non-object asset entry`);
+    }
+    const { family, target, kind, identity, name, path: pathValue, sha256, bytes } = asset;
+    if (
+      ![family, target, kind, name, pathValue, sha256].every(
+        (value) => typeof value === 'string' && value,
+      )
+    ) {
+      fail(`${rel(manifest)} contains an incomplete asset entry: ${JSON.stringify(asset)}`);
+    }
+    if (!Number.isInteger(bytes) || bytes <= 0) {
+      fail(`${rel(manifest)} asset ${name} must declare positive bytes`);
+    }
+    if (seenNames.has(name)) {
+      fail(`${rel(manifest)} declares duplicate asset name ${name}`);
+    }
+    seenNames.add(name);
+    if (!(identity === null || (typeof identity === 'string' && identity.length > 0))) {
+      fail(`${rel(manifest)} asset ${name} identity must be null or a non-empty string`);
+    }
+    if (kind === 'ios-dependency-xcframework' && identity === null) {
+      fail(`${rel(manifest)} iOS dependency XCFramework ${name} must declare its identity`);
+    }
+    if (kind !== 'ios-dependency-xcframework' && kind !== 'ios-xcframework' && identity !== null) {
+      fail(`${rel(manifest)} asset ${name} must not declare identity for kind=${kind}`);
+    }
+    const role = `${family}:${target}:${kind}:${identity ?? ''}`;
+    if (seenRoles.has(role)) {
+      fail(`${rel(manifest)} repeats artifact role ${role}`);
+    }
+    seenRoles.add(role);
+    stagedTargets.add(target);
+    if (!allowedTargets.has(target)) {
+      fail(`${rel(manifest)} stages undeclared target=${JSON.stringify(target)}`);
+    }
+    if (!extensionArtifactKindAllowed(family, target, kind)) {
+      fail(
+        `${rel(manifest)} stages invalid artifact kind=${JSON.stringify(kind)} for family=${JSON.stringify(family)} target=${JSON.stringify(target)}`,
+      );
+    }
+    const assetPath = path.join(ROOT, pathValue);
+    if (
+      path.dirname(assetPath) !== path.join(root, 'release-assets') ||
+      path.basename(assetPath) !== name
+    ) {
+      fail(
+        `${rel(manifest)} asset ${name} must live directly under ${rel(path.join(root, 'release-assets'))}`,
+      );
+    }
+    if (!isFile(assetPath)) {
+      fail(`${rel(manifest)} references missing asset ${rel(assetPath)}`);
+    }
+    if (statSync(assetPath).size !== bytes) {
+      fail(`${rel(assetPath)} size does not match ${rel(manifest)}`);
+    }
+    if (sha256File(assetPath) !== sha256) {
+      fail(`${rel(assetPath)} checksum does not match ${rel(manifest)}`);
+    }
+    validateReleaseArchivePayload(assetPath);
+  }
+  const nativeStem =
+    typeof data.nativeModuleStem === 'string' && data.nativeModuleStem.length > 0
+      ? data.nativeModuleStem
+      : null;
+  const iosDependencies = Array.isArray(data.iosNativeDependencies)
+    ? data.iosNativeDependencies
+    : fail(`${rel(manifest)} must declare iosNativeDependencies`);
+  if (
+    iosDependencies.some((value) => typeof value !== 'string' || value.length === 0) ||
+    new Set(iosDependencies).size !== iosDependencies.length ||
+    JSON.stringify([...iosDependencies].sort(compareText)) !== JSON.stringify(iosDependencies)
+  ) {
+    fail(`${rel(manifest)} iosNativeDependencies must be a sorted unique string list`);
+  }
+  const stagesIos = stagedTargets.has('ios-xcframework');
+  if (nativeStem === null && (iosDependencies.length > 0 || data.iosRegistration !== null)) {
+    fail(
+      `${rel(manifest)} SQL-only extension must not fabricate iOS native dependencies or registration`,
+    );
+  }
+  if (nativeStem !== null && stagesIos) {
+    if (
+      data.iosRegistration === null ||
+      typeof data.iosRegistration !== 'object' ||
+      Array.isArray(data.iosRegistration)
+    ) {
+      fail(
+        `${rel(manifest)} native extension must include build-derived iOS registration metadata`,
+      );
+    }
+    if (
+      data.iosRegistration.sqlName !== data.sqlName ||
+      data.iosRegistration.nativeModuleStem !== nativeStem
+    ) {
+      fail(
+        `${rel(manifest)} iOS registration metadata does not match ${data.sqlName}/${nativeStem}`,
+      );
+    }
+  }
+  if (!stagesIos && (iosDependencies.length > 0 || data.iosRegistration !== null)) {
+    fail(
+      `${rel(manifest)} must not claim iOS dependency/registration metadata without staging the iOS target`,
+    );
+  }
+  validateMemberWasixInstall(data, rel(manifest));
+  const expectedRoles = [];
+  const targetsToCheck = requireFullTargets ? allowedTargets : stagedTargets;
+  for (const target of [...targetsToCheck].sort(compareText)) {
+    if (target === 'wasix-portable') {
+      expectedRoles.push(`wasix:${target}:wasix-runtime:`);
+    } else {
+      expectedRoles.push(`native:${target}:runtime:`);
+      if (target === 'ios-xcframework' && nativeStem !== null) {
+        expectedRoles.push(`native:${target}:ios-xcframework:${nativeStem}`);
+        for (const dependency of iosDependencies) {
+          expectedRoles.push(`native:${target}:ios-dependency-xcframework:${dependency}`);
+        }
+      }
+    }
+  }
+  const actualRoles = [...seenRoles].sort(compareText);
+  expectedRoles.sort(compareText);
+  if (JSON.stringify(actualRoles) !== JSON.stringify(expectedRoles)) {
+    fail(
+      `${rel(manifest)} artifact roles are not dependency-closed: expected=${JSON.stringify(expectedRoles)}, actual=${JSON.stringify(actualRoles)}`,
+    );
+  }
+  const releaseManifest = path.join(
+    root,
+    'release-assets',
+    `${product}-${expected.version}-manifest.json`,
+  );
+  if (!existsSync(releaseManifest)) {
+    fail(`${product} must stage release manifest ${rel(releaseManifest)}`);
+  }
+  const releaseData = readJson(releaseManifest);
+  const expectedRelease = {
+    schema: 'oliphaunt-extension-release-manifest-v1',
+    product,
+    ...ownership,
+    version: String(expected.version),
+    sqlName: String(expectedSqlName),
+    extensionClass: metadata.class,
+    versioning: metadata.versioning,
+    sourceIdentity: extensionSourceIdentity(product, PREFIX),
+    compatibility: metadata.compatibility,
+    createsExtension: data.createsExtension,
+    dependencies: data.dependencies,
+    dataFiles: data.dataFiles,
+    extensionSqlFileNames: data.extensionSqlFileNames,
+    extensionSqlFilePrefixes: data.extensionSqlFilePrefixes,
+    nativeModuleStem: data.nativeModuleStem,
+    iosNativeDependencies: data.iosNativeDependencies,
+    iosRegistration: data.iosRegistration,
+    wasixInstall: data.wasixInstall,
+    sharedPreloadLibraries: data.sharedPreloadLibraries,
+    assets: assets.map(publicExtensionAsset),
+  };
+  requireExactKeys(
+    releaseData,
+    new Set([...PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS, ...Object.keys(ownership)]),
+    rel(releaseManifest),
+  );
+  if (!deepEqual(releaseData, expectedRelease)) {
+    fail(`${rel(releaseManifest)} must exactly match stable metadata and staged artifacts`);
+  }
+  if (stagesIos) {
+    const carrier = path.join(
+      root,
+      'release-assets',
+      swiftExtensionCarrierAssetName(product, expected.version),
+    );
+    if (!existsSync(carrier)) {
+      fail(`${product} must stage independently consumable Swift iOS carrier ${rel(carrier)}`);
+    }
+    let expectedCarrier;
+    try {
+      expectedCarrier = buildSwiftExtensionCarrierManifest({
+        extensionManifest: manifest,
+        nativeRuntimeVersion: metadata.compatibility.nativeRuntimeVersion,
+      });
+    } catch (error) {
+      fail(`${rel(carrier)} cannot be derived from exact staged artifacts: ${error.message}`);
+    }
+    if (!deepEqual(readJson(carrier), expectedCarrier)) {
+      fail(`${rel(carrier)} must exactly describe this extension and its compatible native base`);
+    }
+  }
+  const publicAssets = releaseData.assets;
+  for (const asset of publicAssets) {
+    if (asset === null || Array.isArray(asset) || typeof asset !== 'object') {
+      fail(`${rel(releaseManifest)} contains a non-object public asset row`);
+    }
+    if (!setEquals(new Set(Object.keys(asset)), PUBLIC_EXTENSION_RELEASE_ASSET_KEYS)) {
+      fail(
+        `${rel(releaseManifest)} public asset ${JSON.stringify(asset.name)} keys must be ${JSON.stringify([...PUBLIC_EXTENSION_RELEASE_ASSET_KEYS].sort(compareText))}, got ${JSON.stringify(Object.keys(asset).sort(compareText))}`,
+      );
+    }
+  }
+  const propertiesManifest = path.join(
+    root,
+    'release-assets',
+    `${product}-${expected.version}-manifest.properties`,
+  );
+  if (!existsSync(propertiesManifest)) {
+    fail(`${product} must stage properties manifest ${rel(propertiesManifest)}`);
+  }
+  const properties = readPropertiesText(readFileSync(propertiesManifest, 'utf8'));
+  const expectedProperties = {
+    schema: 'oliphaunt-extension-release-manifest-v1',
+    product,
+    ...(releaseProduct === product ? {} : { releaseProduct, carrierFamily: family }),
+    version: String(expected.version),
+    sqlName: String(expectedSqlName),
+    extensionClass: String(releaseData.extensionClass),
+    versioning: String(releaseData.versioning),
+    sourceKind: String(releaseData.sourceIdentity.kind),
+    createsExtension: data.createsExtension ? 'true' : 'false',
+    dependencies: data.dependencies.join(','),
+    dataFiles: data.dataFiles.join(','),
+    extensionSqlFileNames: data.extensionSqlFileNames.join(','),
+    extensionSqlFilePrefixes: data.extensionSqlFilePrefixes.join(','),
+    nativeModuleStem: data.nativeModuleStem ?? '',
+    iosNativeDependencies: data.iosNativeDependencies.join(','),
+    sharedPreloadLibraries: data.sharedPreloadLibraries.join(','),
+  };
+  for (const asset of assets) {
+    const identity = asset.identity === null ? '' : `.${asset.identity}`;
+    expectedProperties[`asset.${asset.family}.${asset.target}.${asset.kind}${identity}`] =
+      asset.name;
+  }
+  if (!deepEqual(properties, expectedProperties)) {
+    fail(
+      `${rel(propertiesManifest)} must exactly describe stable metadata and every staged asset identity`,
+    );
+  }
+  const checksumManifest = path.join(
+    root,
+    'release-assets',
+    `${product}-${expected.version}-release-assets.sha256`,
+  );
+  if (!existsSync(checksumManifest)) {
+    fail(`${product} must stage checksum manifest ${rel(checksumManifest)}`);
+  }
+  validateChecksumManifest(checksumManifest, path.join(root, 'release-assets'));
+  checkExtensionArtifactInventory(root, [
+    ...assets.map((asset) => asset.path),
+    rel(releaseManifest),
+    rel(propertiesManifest),
+    ...(stagesIos
+      ? [
+          rel(
+            path.join(
+              root,
+              'release-assets',
+              swiftExtensionCarrierAssetName(product, expected.version),
+            ),
+          ),
+        ]
+      : []),
+    rel(checksumManifest),
+  ]);
+  if (requireFullTargets) {
+    const missing = [...allowedTargets]
+      .filter((target) => !stagedTargets.has(target))
+      .sort(compareText);
+    if (missing.length > 0) {
+      fail(`${product} is missing published exact-extension targets: ${missing.join(', ')}`);
+    }
+  }
+  console.log(`validated exact-extension package artifacts: ${product}`);
+  return true;
+}
+
+export async function checkExtensionProduct(product, { family, require, requireFullTargets }) {
+  const variants =
+    family === null
+      ? (() => {
+          const nativeRoot = extensionArtifactProductRoot(
+            product,
+            'native',
+            EXTENSION_ROOT,
+            PREFIX,
+          );
+          const wasixRoot = extensionArtifactProductRoot(product, 'wasix', EXTENSION_ROOT, PREFIX);
+          return nativeRoot === wasixRoot
+            ? [{ family: null, root: nativeRoot }]
+            : [
+                { family: 'native', root: nativeRoot },
+                { family: 'wasix', root: wasixRoot },
+              ];
+        })()
+      : [
+          {
+            family,
+            root: extensionArtifactProductRoot(product, family, EXTENSION_ROOT, PREFIX),
+          },
+        ];
+  let checked = false;
+  for (const variant of variants) {
+    const manifest = path.join(variant.root, 'extension-artifacts.json');
+    if (!existsSync(manifest)) {
+      if (require) {
+        fail(
+          `missing staged exact-extension ${variant.family ?? 'combined'} package manifest for ${product} under ${rel(variant.root)}`,
+        );
+      }
+      continue;
+    }
+    checked =
+      (await checkExtensionProductVariant(product, variant.root, manifest, readJson(manifest), {
+        family: variant.family,
+        requireFullTargets,
+      })) || checked;
+  }
+  return checked;
+}
+
+function setEquals(left, right) {
+  return left.size === right.size && [...left].every((item) => right.has(item));
+}
+
+function sortValue(value) {
+  if (Array.isArray(value)) {
+    return value.map(sortValue);
+  }
+  if (value !== null && typeof value === 'object') {
+    return Object.fromEntries(
+      Object.keys(value)
+        .sort(compareText)
+        .map((key) => [key, sortValue(value[key])]),
+    );
+  }
+  return value;
+}
+
+function deepEqual(left, right) {
+  return JSON.stringify(sortValue(left)) === JSON.stringify(sortValue(right));
+}
+
+function validateChecksumManifest(file, assetDir) {
+  const declared = new Map();
+  const lines = readFileSync(file, 'utf8').split(/\r?\n/u);
+  for (let index = 0; index < lines.length; index += 1) {
+    const line = lines[index].trim();
+    if (!line) {
+      continue;
+    }
+    const parts = line.split(/\s+/u);
+    if (parts.length !== 2) {
+      fail(`${rel(file)}:${index + 1} must contain ' ./'`);
+    }
+    const [sha, name] = parts;
+    if (!/^[0-9a-f]{64}$/u.test(sha) || !name.startsWith('./') || name.slice(2).includes('/')) {
+      fail(`${rel(file)}:${index + 1} contains an invalid checksum entry`);
+    }
+    const assetName = name.slice(2);
+    if (declared.has(assetName)) {
+      fail(`${rel(file)} declares duplicate checksum entry for ${assetName}`);
+    }
+    declared.set(assetName, sha);
+  }
+  const expectedNames = readdirSync(assetDir)
+    .map((name) => path.join(assetDir, name))
+    .filter((candidate) => isFile(candidate) && candidate !== file)
+    .map((candidate) => path.basename(candidate))
+    .sort(compareText);
+  if (JSON.stringify([...declared.keys()].sort(compareText)) !== JSON.stringify(expectedNames)) {
+    fail(`${rel(file)} must cover release assets exactly`);
+  }
+  for (const [name, expectedSha] of declared) {
+    const actual = sha256File(path.join(assetDir, name));
+    if (actual !== expectedSha) {
+      fail(`${rel(file)} checksum mismatch for ${name}`);
+    }
+  }
+}
+
+if (import.meta.main) {
+  const args = process.argv.slice(2);
+  let family = null;
+  const familyIndex = args.indexOf('--family');
+  if (familyIndex >= 0) {
+    family = args[familyIndex + 1];
+    if (!['native', 'wasix'].includes(family)) fail('--family requires native or wasix');
+    args.splice(familyIndex, 2);
+  }
+  const requireFullTargets = args.includes('--require-full-extension-targets');
+  const products = args.filter((arg) => arg !== '--require-full-extension-targets');
+  const known = new Set(exactExtensionProducts(PREFIX));
+  if (
+    products.length === 0 ||
+    products.some((product) => product !== 'all' && !known.has(product))
+  ) {
+    fail(
+      'usage: check-carriers.mts PRODUCT...|all [--family native|wasix] [--require-full-extension-targets]',
+    );
+  }
+  for (const product of new Set(
+    products.flatMap((product) => (product === 'all' ? [...known] : [product])),
+  )) {
+    await checkExtensionProduct(product, { family, require: true, requireFullTargets });
+  }
+}
diff --git a/src/extensions/artifacts/packages/tools/check-carriers.test.mts b/src/extensions/artifacts/packages/tools/check-carriers.test.mts
new file mode 100644
index 000000000..b603d9117
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/check-carriers.test.mts
@@ -0,0 +1,169 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import { expectedExtensionBundleManifest } from './check-carriers.mts';
+import { extensionReleasePropertiesText } from './build-extension-ci-artifacts.mts';
+import { parseUniquePropertiesText } from '../../../../../tools/packaging/release-carrier.mts';
+
+test('derives nested bundle compatibility from the staged bundle data', () => {
+  const compatibility = {
+    nativeRuntimeProduct: 'liboliphaunt-native',
+    nativeRuntimeVersion: '1.2.3',
+    postgresMajor: '18',
+  };
+  const carrier = {
+    family: 'native',
+    target: 'android-arm64-v8a',
+  };
+  const rows = [
+    {
+      member: { sqlName: 'cube' },
+      asset: {
+        bytes: 123,
+        identity: null,
+        kind: 'runtime',
+        memberPath: 'extensions/cube/cube.tar.gz',
+        sha256: 'a'.repeat(64),
+      },
+    },
+  ];
+
+  assert.deepEqual(
+    expectedExtensionBundleManifest({
+      product: 'oliphaunt-extension-contrib-pg18',
+      version: '1.0.0',
+      data: { compatibility },
+      carrier,
+      rows,
+    }),
+    {
+      schema: 'oliphaunt-extension-bundle-v1',
+      product: 'oliphaunt-extension-contrib-pg18',
+      version: '1.0.0',
+      compatibility,
+      family: 'native',
+      target: 'android-arm64-v8a',
+      licenseProfile: 'contrib-native',
+      licenseFiles: [],
+      members: [
+        {
+          sqlName: 'cube',
+          kind: 'runtime',
+          identity: null,
+          path: 'extensions/cube/cube.tar.gz',
+          sha256: 'a'.repeat(64),
+          bytes: 123,
+        },
+      ],
+    },
+  );
+});
+
+test('renders every single-extension asset identity into the public properties manifest', () => {
+  const dependencyIdentities = ['geos', 'geos-c', 'json-c', 'libxml2', 'proj', 'sqlite'];
+  const assets = [
+    ...dependencyIdentities.map((identity) => ({
+      family: 'native',
+      target: 'ios-xcframework',
+      kind: 'ios-dependency-xcframework',
+      identity,
+      name: `postgis-${identity}.zip`,
+    })),
+    {
+      family: 'native',
+      target: 'ios-xcframework',
+      kind: 'ios-xcframework',
+      identity: 'postgis-3',
+      name: 'postgis.zip',
+    },
+    {
+      family: 'native',
+      target: 'ios-xcframework',
+      kind: 'runtime',
+      identity: null,
+      name: 'postgis-runtime.tar.gz',
+    },
+  ];
+  const text = extensionReleasePropertiesText({
+    product: 'oliphaunt-extension-postgis',
+    version: '1.0.0',
+    manifest: {
+      schema: 'oliphaunt-extension-ci-artifacts-v1',
+      sqlName: 'postgis',
+      createsExtension: true,
+      dependencies: [],
+      dataFiles: ['contrib/postgis-3.6/postgis.sql', 'proj/proj.db'],
+      extensionSqlFileNames: ['uninstall_postgis.sql'],
+      extensionSqlFilePrefixes: ['postgis_comments', 'rtpostgis'],
+      nativeModuleStem: 'postgis-3',
+      iosNativeDependencies: dependencyIdentities,
+      sharedPreloadLibraries: [],
+      assets,
+    },
+    releaseData: {
+      schema: 'oliphaunt-extension-release-manifest-v1',
+      extensionClass: 'external',
+      versioning: 'independent',
+      sourceIdentity: { kind: 'git' },
+    },
+    directAssets: assets,
+  });
+  const assetLines = text.split('\n').filter((line) => line.startsWith('asset.'));
+
+  assert.deepEqual(assetLines, [
+    'asset.native.ios-xcframework.ios-dependency-xcframework.geos=postgis-geos.zip',
+    'asset.native.ios-xcframework.ios-dependency-xcframework.geos-c=postgis-geos-c.zip',
+    'asset.native.ios-xcframework.ios-dependency-xcframework.json-c=postgis-json-c.zip',
+    'asset.native.ios-xcframework.ios-dependency-xcframework.libxml2=postgis-libxml2.zip',
+    'asset.native.ios-xcframework.ios-dependency-xcframework.proj=postgis-proj.zip',
+    'asset.native.ios-xcframework.ios-dependency-xcframework.sqlite=postgis-sqlite.zip',
+    'asset.native.ios-xcframework.ios-xcframework.postgis-3=postgis.zip',
+    'asset.native.ios-xcframework.runtime=postgis-runtime.tar.gz',
+  ]);
+  assert.equal(
+    Object.keys(parseUniquePropertiesText(text)).filter((key) => key.startsWith('asset.')).length,
+    8,
+  );
+  const properties = parseUniquePropertiesText(text);
+  assert.equal(properties.createsExtension, 'true');
+  assert.equal(properties.dataFiles, 'contrib/postgis-3.6/postgis.sql,proj/proj.db');
+  assert.equal(properties.extensionSqlFileNames, 'uninstall_postgis.sql');
+  assert.equal(properties.extensionSqlFilePrefixes, 'postgis_comments,rtpostgis');
+  assert.doesNotMatch(text, /^carrier\./mu);
+});
+
+test('freezes each bundle member desktop inventory in the public properties manifest', () => {
+  const text = extensionReleasePropertiesText({
+    product: 'oliphaunt-extension-contrib-pg18',
+    version: '1.0.0',
+    manifest: {
+      schema: 'oliphaunt-extension-ci-artifacts-v2',
+      extensions: [
+        {
+          sqlName: 'pgtap',
+          createsExtension: true,
+          dependencies: [],
+          dataFiles: [],
+          extensionSqlFileNames: ['uninstall_pgtap.sql'],
+          extensionSqlFilePrefixes: ['pgtap-core', 'pgtap-schema'],
+          nativeModuleStem: null,
+          iosNativeDependencies: [],
+          sharedPreloadLibraries: [],
+          assets: [],
+        },
+      ],
+    },
+    releaseData: {
+      schema: 'oliphaunt-extension-release-manifest-v2',
+      extensionClass: 'contrib',
+      versioning: 'coordinated',
+      sourceIdentity: { kind: 'repository' },
+    },
+    directAssets: [],
+  });
+  const properties = parseUniquePropertiesText(text);
+
+  assert.equal(properties['extension.pgtap.createsExtension'], 'true');
+  assert.equal(properties['extension.pgtap.dataFiles'], '');
+  assert.equal(properties['extension.pgtap.extensionSqlFileNames'], 'uninstall_pgtap.sql');
+  assert.equal(properties['extension.pgtap.extensionSqlFilePrefixes'], 'pgtap-core,pgtap-schema');
+});
diff --git a/src/extensions/artifacts/packages/tools/contrib-carriers.mts b/src/extensions/artifacts/packages/tools/contrib-carriers.mts
new file mode 100644
index 000000000..663559938
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/contrib-carriers.mts
@@ -0,0 +1,70 @@
+import { existsSync, readFileSync } from 'node:fs';
+import path from 'node:path';
+
+export const CONTRIB_CARRIERS_PATH = 'src/extensions/contrib/carriers.toml';
+
+function fail(prefix, message) {
+  throw new Error(`${prefix}: ${message}`);
+}
+
+function toml(root, relativePath, prefix) {
+  const file = path.join(root, relativePath);
+  if (!existsSync(file)) fail(prefix, `missing ${relativePath}`);
+  const value = Bun.TOML.parse(readFileSync(file, 'utf8'));
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(prefix, `${relativePath} must contain a TOML table`);
+  }
+  return value;
+}
+
+function string(value, context, prefix) {
+  if (typeof value !== 'string' || value.length === 0)
+    fail(prefix, `${context} must be a non-empty string`);
+  return value;
+}
+
+export function loadContribCarriers(root, prefix = 'contrib-carriers') {
+  const descriptor = toml(root, CONTRIB_CARRIERS_PATH, prefix);
+  const artifactProduct = string(descriptor.logical_product, 'logical_product', prefix);
+  const memberManifest = string(descriptor.member_manifest, 'member_manifest', prefix);
+  const source = string(descriptor.source, 'source', prefix);
+  const contract = string(descriptor.contract, 'contract', prefix);
+  const nativeOwner = string(descriptor.native_owner, 'native_owner', prefix);
+  const wasixOwner = string(descriptor.wasix_owner, 'wasix_owner', prefix);
+  const members = toml(root, memberManifest, prefix).extensions;
+  if (
+    !Array.isArray(members) ||
+    members.some(
+      (member) =>
+        member === null ||
+        Array.isArray(member) ||
+        typeof member !== 'object' ||
+        typeof member.id !== 'string',
+    )
+  ) {
+    fail(prefix, `${memberManifest}.extensions must name contrib member ids`);
+  }
+  const ids = members.map(({ id }) => id);
+  if (new Set(ids).size !== ids.length)
+    fail(prefix, `${memberManifest}.extensions ids must be unique`);
+  const inputFiles = [
+    CONTRIB_CARRIERS_PATH,
+    memberManifest,
+    'src/extensions/contracts/extension-target-profiles.toml',
+    source,
+    contract,
+  ];
+  for (const file of inputFiles) {
+    if (!existsSync(path.join(root, file))) fail(prefix, `missing contrib carrier input ${file}`);
+  }
+  return {
+    artifactProduct,
+    contract,
+    inputFiles,
+    memberManifest,
+    members,
+    nativeOwner,
+    source,
+    wasixOwner,
+  };
+}
diff --git a/src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts b/src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts
new file mode 100644
index 000000000..96f8ca457
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts
@@ -0,0 +1,894 @@
+import { createHash } from 'node:crypto';
+import {
+  closeSync,
+  constants,
+  fstatSync,
+  lstatSync,
+  openSync,
+  readFileSync,
+  readSync,
+} from 'node:fs';
+import path from 'node:path';
+import { TextDecoder } from 'node:util';
+import { strictGunzip } from '../../../../../tools/packaging/portable-archive.mts';
+
+import { EXTENSION_ARTIFACT_ARCHIVE_POLICY } from '../../../tools/extension-artifact-archive-policy.mts';
+import {
+  extensionCarrierLegalContract,
+  extensionUpstreamLicenseRow,
+} from '../../../tools/extension-upstream-licenses.mts';
+import { extensionProductForSqlName } from '../../../../../tools/release/release-artifact-targets.mts';
+import { releaseNoticeRows } from '../../../../../tools/packaging/release-notices.mts';
+
+export const EXTENSION_ARTIFACT_PROPERTY_KEYS = Object.freeze([
+  'packageLayout',
+  'pgMajor',
+  'sqlName',
+  'createsExtension',
+  'nativeModuleStem',
+  'nativeModuleFile',
+  'nativeTarget',
+  'nativeRuntimeProduct',
+  'nativeRuntimeVersion',
+  'dependencies',
+  'dataFiles',
+  'extensionSqlFileNames',
+  'extensionSqlFilePrefixes',
+  'sharedPreloadLibraries',
+  'mobilePrebuilt',
+  'mobileStaticArchives',
+  'mobileStaticDependencyArchives',
+  'staticSymbolPrefix',
+  'staticSymbolAliases',
+  'licenseFiles',
+  'licenseProfile',
+  'files',
+]);
+
+const PORTABLE_ID = /^[A-Za-z0-9._-]{1,128}$/u;
+const C_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u;
+const SHA256 = /^[0-9a-f]{64}$/u;
+const {
+  maxCompressedBytes: MAX_COMPRESSED_ARCHIVE_BYTES,
+  maxExpandedBytes: MAX_EXPANDED_ARCHIVE_BYTES,
+  maxMemberBytes: MAX_ARCHIVE_MEMBER_BYTES,
+  maxMembers: MAX_ARCHIVE_MEMBERS,
+} = EXTENSION_ARTIFACT_ARCHIVE_POLICY;
+const UTF8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
+const DESKTOP_NATIVE_TARGETS = new Set([
+  'linux-x64-gnu',
+  'linux-arm64-gnu',
+  'macos-arm64',
+  'windows-x64-msvc',
+]);
+
+function inventoryError(label, message) {
+  return new Error(`${label}: ${message}`);
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function safeRelativePath(value, label) {
+  if (typeof value !== 'string' || value.length === 0 || value.includes('\0')) {
+    throw inventoryError(label, 'must be a non-empty relative path');
+  }
+  if (
+    value.includes('\\') ||
+    value !== value.normalize('NFC') ||
+    /[\u0000-\u001f\u007f]/u.test(value)
+  ) {
+    throw inventoryError(
+      label,
+      'must use NFC UTF-8 text without backslashes or control characters',
+    );
+  }
+  const parts = value.split('/');
+  if (
+    value.startsWith('/') ||
+    /^[A-Za-z]:/u.test(value) ||
+    parts.some((part) => part.length === 0 || part === '.' || part === '..')
+  ) {
+    throw inventoryError(label, `must be a canonical relative path; got ${JSON.stringify(value)}`);
+  }
+  return parts.join('/');
+}
+
+function csv(value, label, { paths = false } = {}) {
+  if (typeof value !== 'string') throw inventoryError(label, 'must be a string');
+  if (value.length === 0) return [];
+  const rows = value.split(',').map((row, index) => {
+    if (row.length === 0 || row.trim() !== row) {
+      throw inventoryError(label, `contains a malformed item at index ${index}`);
+    }
+    return paths ? safeRelativePath(row, `${label}[${index}]`) : row;
+  });
+  if (new Set(rows).size !== rows.length)
+    throw inventoryError(label, 'must not contain duplicates');
+  const sorted = [...rows].sort(compareText);
+  if (JSON.stringify(rows) !== JSON.stringify(sorted)) {
+    throw inventoryError(label, 'must be sorted deterministically');
+  }
+  return rows;
+}
+
+export function parseExtensionArtifactProperties(text, label) {
+  if (
+    typeof text !== 'string' ||
+    text.startsWith('\uFEFF') ||
+    text.includes('\r') ||
+    text.includes('\\') ||
+    text !== text.normalize('NFC') ||
+    /[\u0000-\u0009\u000b-\u001f\u007f]/u.test(text) ||
+    !text.endsWith('\n') ||
+    text.endsWith('\n\n')
+  ) {
+    throw inventoryError(
+      label,
+      'must be canonical NFC UTF-8 key=value text with LF lines and exactly one final newline',
+    );
+  }
+  const properties = new Map();
+  const lines = text.slice(0, -1).split('\n');
+  for (const [index, rawLine] of lines.entries()) {
+    if (rawLine.length === 0) {
+      throw inventoryError(label, `has an internal blank line at ${index + 1}`);
+    }
+    const separator = rawLine.indexOf('=');
+    if (separator <= 0 || rawLine.trim() !== rawLine) {
+      throw inventoryError(label, `has malformed properties line ${index + 1}`);
+    }
+    const key = rawLine.slice(0, separator);
+    if (properties.has(key)) {
+      throw inventoryError(label, `repeats property ${key}`);
+    }
+    properties.set(key, rawLine.slice(separator + 1));
+  }
+  const actual = [...properties.keys()].sort(compareText);
+  const expected = [...EXTENSION_ARTIFACT_PROPERTY_KEYS].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+    throw inventoryError(
+      label,
+      `property fields must be exactly ${expected.join(',')}; got ${actual.join(',')}`,
+    );
+  }
+  if (JSON.stringify([...properties.keys()]) !== JSON.stringify(EXTENSION_ARTIFACT_PROPERTY_KEYS)) {
+    throw inventoryError(label, 'properties must use the canonical field order');
+  }
+  return properties;
+}
+
+function decodeUtf8(bytes, label) {
+  try {
+    return UTF8.decode(bytes);
+  } catch (error) {
+    throw inventoryError(label, `contains invalid UTF-8: ${error.message}`);
+  }
+}
+
+function tarString(buffer, offset, length, label, field) {
+  const bytes = buffer.subarray(offset, offset + length);
+  const end = bytes.indexOf(0);
+  if (end >= 0 && !bytes.subarray(end).every((byte) => byte === 0)) {
+    throw inventoryError(label, `tar ${field} has nonzero bytes after its terminator`);
+  }
+  return decodeUtf8(bytes.subarray(0, end < 0 ? bytes.length : end), `${label} tar ${field}`);
+}
+
+function canonicalTarOctal(length, value) {
+  return Buffer.from(`${value.toString(8).padStart(length - 1, '0')}\0`, 'ascii');
+}
+
+function tarOctal(buffer, offset, length, label, field) {
+  if (field === 'checksum') {
+    const bytes = buffer.subarray(offset, offset + length);
+    if (length !== 8 || bytes[6] !== 0 || bytes[7] !== 0x20) {
+      throw inventoryError(label, 'has noncanonical tar checksum encoding');
+    }
+    const digits = decodeUtf8(bytes.subarray(0, 6), `${label} tar checksum`);
+    if (!/^[0-7]{6}$/u.test(digits)) {
+      throw inventoryError(label, `has invalid tar checksum field ${JSON.stringify(digits)}`);
+    }
+    return Number.parseInt(digits, 8);
+  }
+  const value = tarString(buffer, offset, length, label, field).trim();
+  if (!/^[0-7]+$/u.test(value)) {
+    throw inventoryError(label, `has invalid tar ${field} field ${JSON.stringify(value)}`);
+  }
+  const parsed = Number.parseInt(value, 8);
+  if (!Number.isSafeInteger(parsed) || parsed < 0) {
+    throw inventoryError(label, `has out-of-range tar ${field}`);
+  }
+  return parsed;
+}
+
+function readExact(descriptor, position, length, label) {
+  const buffer = Buffer.alloc(length);
+  let offset = 0;
+  while (offset < length) {
+    const bytes = readSync(descriptor, buffer, offset, length - offset, position + offset);
+    if (bytes === 0) throw inventoryError(label, 'tar stream ended unexpectedly');
+    offset += bytes;
+  }
+  return buffer;
+}
+
+function canonicalTarPathParts(archiveName, label) {
+  if (Buffer.byteLength(archiveName) <= 100) {
+    return { name: archiveName, prefix: '' };
+  }
+  const parts = archiveName.split('/');
+  for (let index = 1; index < parts.length; index += 1) {
+    const prefix = parts.slice(0, index).join('/');
+    const name = parts.slice(index).join('/');
+    if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) {
+      return { name, prefix };
+    }
+  }
+  throw inventoryError(
+    label,
+    `member ${archiveName} cannot use the canonical producer ustar split`,
+  );
+}
+
+function validateCanonicalHeader(header, label, block, collisionNames, entries) {
+  const storedChecksum = tarOctal(header, 148, 8, label, 'checksum');
+  const checksumHeader = Buffer.from(header);
+  checksumHeader.fill(0x20, 148, 156);
+  const actualChecksum = checksumHeader.reduce((sum, byte) => sum + byte, 0);
+  if (storedChecksum !== actualChecksum) {
+    throw inventoryError(label, `has a tar header checksum mismatch at block ${block}`);
+  }
+  if (tarString(header, 257, 6, label, 'magic') !== 'ustar') {
+    throw inventoryError(label, 'must use canonical ustar headers');
+  }
+  const name = tarString(header, 0, 100, label, 'name');
+  const prefix = tarString(header, 345, 155, label, 'prefix');
+  const archiveName = safeRelativePath(prefix ? `${prefix}/${name}` : name, `${label} tar member`);
+  const canonicalPath = canonicalTarPathParts(archiveName, label);
+  if (name !== canonicalPath.name || prefix !== canonicalPath.prefix) {
+    throw inventoryError(
+      label,
+      `member ${archiveName} must use canonical ustar name/prefix split ${JSON.stringify(canonicalPath)}`,
+    );
+  }
+  const collisionKey = archiveName.normalize('NFC').toLowerCase();
+  const collision = collisionNames.get(collisionKey);
+  if (collision !== undefined && collision !== archiveName) {
+    throw inventoryError(
+      label,
+      `contains case/NFC-colliding members ${collision} and ${archiveName}`,
+    );
+  }
+  collisionNames.set(collisionKey, archiveName);
+  if (header[156] !== 0x30) {
+    throw inventoryError(label, `member ${archiveName} must be a regular file`);
+  }
+  const mode = tarOctal(header, 100, 8, label, 'mode');
+  const uid = tarOctal(header, 108, 8, label, 'uid');
+  const gid = tarOctal(header, 116, 8, label, 'gid');
+  const size = tarOctal(header, 124, 12, label, 'size');
+  const mtime = tarOctal(header, 136, 12, label, 'mtime');
+  if (size > MAX_ARCHIVE_MEMBER_BYTES) {
+    throw inventoryError(label, `member ${archiveName} exceeds ${MAX_ARCHIVE_MEMBER_BYTES} bytes`);
+  }
+  if (![0o644, 0o755].includes(mode) || uid !== 0 || gid !== 0 || mtime !== 0) {
+    throw inventoryError(
+      label,
+      `member ${archiveName} must use mode 0644/0755, uid=0, gid=0 and mtime=0`,
+    );
+  }
+  for (const [field, offset, length, value] of [
+    ['mode', 100, 8, mode],
+    ['uid', 108, 8, uid],
+    ['gid', 116, 8, gid],
+    ['size', 124, 12, size],
+    ['mtime', 136, 12, mtime],
+  ]) {
+    if (!header.subarray(offset, offset + length).equals(canonicalTarOctal(length, value))) {
+      throw inventoryError(label, `member ${archiveName} has noncanonical tar ${field} encoding`);
+    }
+  }
+  if (
+    !header
+      .subarray(148, 156)
+      .equals(Buffer.from(`${storedChecksum.toString(8).padStart(6, '0')}\0 `, 'ascii')) ||
+    !header.subarray(157, 257).every((byte) => byte === 0) ||
+    !header.subarray(257, 263).equals(Buffer.from('ustar\0', 'ascii')) ||
+    !header.subarray(263, 265).equals(Buffer.from('00', 'ascii')) ||
+    tarString(header, 265, 32, label, 'uname') !== 'root' ||
+    tarString(header, 297, 32, label, 'gname') !== 'root' ||
+    !header.subarray(329, 345).every((byte) => byte === 0) ||
+    !header.subarray(500, 512).every((byte) => byte === 0)
+  ) {
+    throw inventoryError(
+      label,
+      `member ${archiveName} does not use the canonical producer ustar header`,
+    );
+  }
+  if (entries.has(archiveName)) {
+    throw inventoryError(label, `contains duplicate member ${archiveName}`);
+  }
+  return { archiveName, mode, size };
+}
+
+/** Read exactly the bounded deterministic gzip+ustar emitted by extension-artifact-packager.mts. */
+export function readCanonicalExtensionArtifactArchive(file, label = file) {
+  const carrierMetadata = lstatSync(file, { bigint: true });
+  if (carrierMetadata.isSymbolicLink() || !carrierMetadata.isFile()) {
+    throw inventoryError(label, 'carrier input must be a regular non-symlink file');
+  }
+  let compressed;
+  const descriptor = openSync(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
+  try {
+    const opened = fstatSync(descriptor, { bigint: true });
+    if (
+      !opened.isFile() ||
+      opened.dev !== carrierMetadata.dev ||
+      opened.ino !== carrierMetadata.ino
+    ) {
+      throw inventoryError(label, 'carrier changed between path inspection and no-follow open');
+    }
+    const size = Number(opened.size);
+    if (!Number.isSafeInteger(size) || size < 18 || size > MAX_COMPRESSED_ARCHIVE_BYTES) {
+      throw inventoryError(
+        label,
+        'archive bytes must be between 18 and ' + MAX_COMPRESSED_ARCHIVE_BYTES,
+      );
+    }
+    compressed = readExact(descriptor, 0, size, label);
+    const after = fstatSync(descriptor, { bigint: true });
+    if (
+      after.size !== opened.size ||
+      after.mtimeNs !== opened.mtimeNs ||
+      after.ctimeNs !== opened.ctimeNs
+    ) {
+      throw inventoryError(label, 'carrier metadata changed while taking its private snapshot');
+    }
+  } finally {
+    closeSync(descriptor);
+  }
+  if (compressed.subarray(0, 10).toString('hex') !== '1f8b0800000000000003') {
+    throw inventoryError(label, 'must use the canonical cross-platform gzip header');
+  }
+  const tar = strictGunzip(compressed, label, MAX_EXPANDED_ARCHIVE_BYTES);
+  const expandedBytes = tar.length;
+  if (expandedBytes < 1024 || expandedBytes % 512 !== 0) {
+    throw inventoryError(label, 'must contain a bounded block-aligned ustar stream');
+  }
+  const entries = new Map();
+  const collisionNames = new Map();
+  let offset = 0;
+  let ended = false;
+  while (offset < expandedBytes) {
+    const header = tar.subarray(offset, offset + 512);
+    if (header.every((byte) => byte === 0)) {
+      if (expandedBytes - offset !== 1024 || !tar.subarray(offset).every((byte) => byte === 0)) {
+        throw inventoryError(label, 'tar end marker or trailing padding is not canonical');
+      }
+      ended = true;
+      break;
+    }
+    const { archiveName, mode, size } = validateCanonicalHeader(
+      header,
+      label,
+      offset / 512,
+      collisionNames,
+      entries,
+    );
+    const dataStart = offset + 512;
+    const dataEnd = dataStart + size;
+    const paddedEnd = dataStart + Math.ceil(size / 512) * 512;
+    if (dataEnd > expandedBytes || paddedEnd > expandedBytes) {
+      throw inventoryError(label, `member ${archiveName} exceeds the tar stream`);
+    }
+    const data = tar.subarray(dataStart, dataEnd);
+    if (!tar.subarray(dataEnd, paddedEnd).every((byte) => byte === 0)) {
+      throw inventoryError(label, `member ${archiveName} has nonzero tar padding`);
+    }
+    entries.set(archiveName, {
+      bytes: data.length,
+      data,
+      mode,
+      sha256: createHash('sha256').update(data).digest('hex'),
+    });
+    if (entries.size > MAX_ARCHIVE_MEMBERS) {
+      throw inventoryError(label, `contains more than ${MAX_ARCHIVE_MEMBERS} members`);
+    }
+    offset = paddedEnd;
+  }
+  if (!ended || entries.size === 0) {
+    throw inventoryError(label, 'must contain regular files and a canonical tar end marker');
+  }
+  const names = [...entries.keys()];
+  if (JSON.stringify(names) !== JSON.stringify([...names].sort(compareText))) {
+    throw inventoryError(label, 'tar members must be sorted deterministically');
+  }
+  return entries;
+}
+
+function normalizeMetadata(row, label) {
+  const sqlName = row?.sqlName ?? row?.['sql-name'];
+  if (typeof sqlName !== 'string' || !PORTABLE_ID.test(sqlName)) {
+    throw inventoryError(label, 'has an invalid sqlName');
+  }
+  const list = (camel, kebab, explicitValue = undefined) => {
+    const value = explicitValue ?? row?.[camel] ?? row?.[kebab];
+    if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
+      throw inventoryError(label, `${kebab} must be a string array`);
+    }
+    const sorted = [...value].sort(compareText);
+    if (new Set(sorted).size !== sorted.length) {
+      throw inventoryError(label, `${kebab} must not contain duplicates`);
+    }
+    return sorted;
+  };
+  const nativeModuleStem = row?.nativeModuleStem ?? row?.['native-module-stem'] ?? null;
+  if (
+    nativeModuleStem !== null &&
+    (typeof nativeModuleStem !== 'string' || !PORTABLE_ID.test(nativeModuleStem))
+  ) {
+    throw inventoryError(label, 'native-module-stem must be null or a portable identifier');
+  }
+  const createsExtension = row?.createsExtension ?? row?.['creates-extension'];
+  if (typeof createsExtension !== 'boolean') {
+    throw inventoryError(label, 'creates-extension must be boolean');
+  }
+  const metadata = {
+    sqlName,
+    createsExtension,
+    nativeModuleStem,
+    dependencies: (() => {
+      const selected =
+        row?.selectedExtensionDependencies ??
+        row?.['selected-extension-dependencies'] ??
+        row?.dependencies;
+      return list('selectedExtensionDependencies', 'selected-extension-dependencies', selected);
+    })(),
+    dataFiles: list(
+      'runtimeShareDataFiles',
+      'runtime-share-data-files',
+      row?.runtimeShareDataFiles ?? row?.['runtime-share-data-files'] ?? row?.dataFiles,
+    ).map((item, index) => safeRelativePath(item, `${label}.runtime-share-data-files[${index}]`)),
+    extensionSqlFileNames: list('extensionSqlFileNames', 'extension-sql-file-names'),
+    extensionSqlFilePrefixes: list('extensionSqlFilePrefixes', 'extension-sql-file-prefixes'),
+    sharedPreloadLibraries: list('sharedPreloadLibraries', 'shared-preload-libraries'),
+  };
+  for (const [field, values] of [
+    ['selected-extension-dependencies', metadata.dependencies],
+    ['shared-preload-libraries', metadata.sharedPreloadLibraries],
+  ]) {
+    if (values.some((item) => !PORTABLE_ID.test(item))) {
+      throw inventoryError(label, `${field} contains a non-portable identifier`);
+    }
+  }
+  if (
+    metadata.extensionSqlFileNames.some(
+      (item) => path.posix.basename(item) !== item || !item.endsWith('.sql'),
+    )
+  ) {
+    throw inventoryError(label, 'extension-sql-file-names must contain SQL basenames');
+  }
+  if (
+    metadata.extensionSqlFilePrefixes.some((item) => !PORTABLE_ID.test(item) || item.includes('.'))
+  ) {
+    throw inventoryError(
+      label,
+      'extension-sql-file-prefixes must contain portable basename prefixes',
+    );
+  }
+  return metadata;
+}
+
+function moduleSuffix(target) {
+  if (target === 'windows-x64-msvc') return '.dll';
+  if (target === 'macos-arm64' || target === 'ios-xcframework') return '.dylib';
+  return '.so';
+}
+
+function sqlFileOwned(fileName, metadata) {
+  return (
+    (metadata.createsExtension && fileName === `${metadata.sqlName}.control`) ||
+    (metadata.createsExtension && fileName === `${metadata.sqlName}.sql`) ||
+    (metadata.createsExtension &&
+      fileName.startsWith(`${metadata.sqlName}--`) &&
+      fileName.endsWith('.sql')) ||
+    metadata.extensionSqlFileNames.includes(fileName) ||
+    (fileName.endsWith('.sql') &&
+      metadata.extensionSqlFilePrefixes.some((prefix) => fileName.startsWith(prefix)))
+  );
+}
+
+export function isCanonicalExtensionInstallSql(fileName, sqlName) {
+  const prefix = `${sqlName}--`;
+  if (!fileName.startsWith(prefix) || !fileName.endsWith('.sql')) return false;
+  const version = fileName.slice(prefix.length, -'.sql'.length);
+  return /^[0-9][A-Za-z0-9._-]*$/u.test(version) && !version.includes('--');
+}
+
+function extensionSqlVersion(value) {
+  return /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value) && !value.includes('--');
+}
+
+export function extensionControlDefaultVersion(control, sqlName, label) {
+  const values = [];
+  for (const [index, raw] of control.split(/\r?\n/u).entries()) {
+    const line = raw.trim();
+    if (line.length === 0 || line.startsWith('#')) continue;
+    if (!/^default_version(?:\s|=)/u.test(line)) continue;
+    const match = line.match(/^default_version\s*=\s*'([^']+)'\s*(?:#.*)?$/u);
+    if (match === null || !extensionSqlVersion(match[1])) {
+      throw inventoryError(
+        label,
+        `${sqlName}.control has invalid default_version on line ${index + 1}`,
+      );
+    }
+    values.push(match[1]);
+  }
+  if (values.length !== 1) {
+    throw inventoryError(label, `${sqlName}.control must declare default_version exactly once`);
+  }
+  return values[0];
+}
+
+function canonicalInstallVersion(fileName, sqlName) {
+  if (!isCanonicalExtensionInstallSql(fileName, sqlName)) return null;
+  return fileName.slice(`${sqlName}--`.length, -'.sql'.length);
+}
+
+function canonicalUpdateEdge(fileName, sqlName) {
+  const prefix = `${sqlName}--`;
+  if (!fileName.startsWith(prefix) || !fileName.endsWith('.sql')) return null;
+  const versions = fileName.slice(prefix.length, -'.sql'.length).split('--');
+  if (versions.length !== 2 || !versions.every(extensionSqlVersion)) return null;
+  return versions;
+}
+
+/** Prove that PostgreSQL can install the control file's default version. */
+export function validateExtensionInstallSqlReachability({ sqlName, control, fileNames, label }) {
+  const defaultVersion = extensionControlDefaultVersion(control, sqlName, label);
+  const installVersions = new Set();
+  const updateTargets = new Map();
+  for (const fileName of [...new Set(fileNames)].sort(compareText)) {
+    const installVersion = canonicalInstallVersion(fileName, sqlName);
+    if (installVersion !== null) installVersions.add(installVersion);
+    const edge = canonicalUpdateEdge(fileName, sqlName);
+    if (edge !== null) {
+      const [from, to] = edge;
+      const targets = updateTargets.get(from) ?? new Set();
+      targets.add(to);
+      updateTargets.set(from, targets);
+    }
+  }
+  if (installVersions.has(defaultVersion)) return;
+
+  const reachable = new Set(installVersions);
+  const pending = [...installVersions].sort(compareText);
+  for (let index = 0; index < pending.length; index += 1) {
+    const current = pending[index];
+    for (const next of [...(updateTargets.get(current) ?? [])].sort(compareText)) {
+      if (reachable.has(next)) continue;
+      reachable.add(next);
+      pending.push(next);
+    }
+  }
+  if (reachable.has(defaultVersion)) return;
+
+  const updates = [...updateTargets]
+    .flatMap(([from, targets]) => [...targets].map((to) => `${from}->${to}`))
+    .sort(compareText);
+  throw inventoryError(
+    label,
+    `${sqlName} default_version '${defaultVersion}' has no canonical installation script or update path; ` +
+      `install versions=${[...installVersions].sort(compareText).join(',') || '-'}; updates=${updates.join(',') || '-'}`,
+  );
+}
+
+function declaredMobilePaths(properties, metadata, label) {
+  const paths = [];
+  const staticRows = csv(properties.get('mobileStaticArchives'), `${label} mobileStaticArchives`);
+  for (const [index, row] of staticRows.entries()) {
+    const separator = row.indexOf(':');
+    if (separator <= 0 || metadata.nativeModuleStem === null) {
+      throw inventoryError(label, `mobileStaticArchives[${index}] is malformed`);
+    }
+    const target = row.slice(0, separator);
+    const member = safeRelativePath(
+      row.slice(separator + 1),
+      `${label} mobileStaticArchives[${index}]`,
+    );
+    if (!PORTABLE_ID.test(target))
+      throw inventoryError(label, `mobile static target ${target} is invalid`);
+    const expected = `mobile-static/${target}/extensions/${metadata.nativeModuleStem}/liboliphaunt_extension_${metadata.nativeModuleStem}.a`;
+    if (member !== expected) {
+      throw inventoryError(label, `mobile static member ${member} must be ${expected}`);
+    }
+    paths.push(member);
+  }
+  const dependencyRows = csv(
+    properties.get('mobileStaticDependencyArchives'),
+    `${label} mobileStaticDependencyArchives`,
+  );
+  for (const [index, row] of dependencyRows.entries()) {
+    const first = row.indexOf(':');
+    const second = row.indexOf(':', first + 1);
+    if (first <= 0 || second <= first + 1) {
+      throw inventoryError(label, `mobileStaticDependencyArchives[${index}] is malformed`);
+    }
+    const target = row.slice(0, first);
+    const dependency = row.slice(first + 1, second);
+    const member = safeRelativePath(
+      row.slice(second + 1),
+      `${label} mobileStaticDependencyArchives[${index}]`,
+    );
+    if (!PORTABLE_ID.test(target) || !PORTABLE_ID.test(dependency)) {
+      throw inventoryError(
+        label,
+        `mobile static dependency identity ${target}:${dependency} is invalid`,
+      );
+    }
+    const prefix = `mobile-static/${target}/dependencies/${dependency}/`;
+    if (!member.startsWith(prefix) || path.posix.basename(member) !== member.slice(prefix.length)) {
+      throw inventoryError(label, `mobile static dependency member ${member} is not canonical`);
+    }
+    paths.push(member);
+  }
+  if (new Set(paths).size !== paths.length) {
+    throw inventoryError(label, 'mobile static archive paths must not repeat');
+  }
+  return paths;
+}
+
+function validateStaticLinkage(properties, metadata, target, label) {
+  const prefix = properties.get('staticSymbolPrefix');
+  if (prefix !== '' && !C_IDENTIFIER.test(prefix)) {
+    throw inventoryError(label, 'staticSymbolPrefix must be empty or a C identifier');
+  }
+  const aliases = csv(properties.get('staticSymbolAliases'), `${label} staticSymbolAliases`);
+  const sqlSymbols = new Set();
+  for (const [index, alias] of aliases.entries()) {
+    const fields = alias.split(':');
+    if (fields.length !== 2 || fields.some((field) => !C_IDENTIFIER.test(field))) {
+      throw inventoryError(label, `staticSymbolAliases[${index}] must be a C-identifier pair`);
+    }
+    if (sqlSymbols.has(fields[0])) {
+      throw inventoryError(label, `staticSymbolAliases repeats SQL-visible symbol ${fields[0]}`);
+    }
+    sqlSymbols.add(fields[0]);
+  }
+  if (DESKTOP_NATIVE_TARGETS.has(target) && (prefix !== '' || aliases.length !== 0)) {
+    throw inventoryError(label, 'desktop artifacts must not declare static symbol linkage');
+  }
+  if (metadata.nativeModuleStem === null && (prefix !== '' || aliases.length !== 0)) {
+    throw inventoryError(label, 'SQL-only artifacts must not declare static symbol linkage');
+  }
+}
+
+function canonicalLegalContract(metadata, target, label) {
+  let contract;
+  try {
+    const product = extensionProductForSqlName(
+      metadata.sqlName,
+      'extension-artifact-inventory.mts',
+    );
+    contract = extensionCarrierLegalContract(product, [metadata.sqlName], {
+      family: 'native',
+      target,
+    });
+  } catch (cause) {
+    throw inventoryError(label, `cannot resolve canonical legal contract: ${cause.message}`);
+  }
+  const members = new Map();
+  const add = (member, sha256, source) => {
+    const prior = members.get(member);
+    if (prior !== undefined && prior.sha256 !== sha256) {
+      throw inventoryError(label, `canonical legal member collision at ${member}`);
+    }
+    members.set(member, { sha256, source });
+  };
+  for (const row of releaseNoticeRows({ profile: contract.profile })) {
+    add(
+      row.member,
+      createHash('sha256').update(readFileSync(row.source)).digest('hex'),
+      row.source,
+    );
+  }
+  const upstreamFiles = contract.upstreamMembers.flatMap(
+    (sqlName) => extensionUpstreamLicenseRow(sqlName).files,
+  );
+  const destinations = upstreamFiles.map(({ destination }) => destination).sort(compareText);
+  if (JSON.stringify(destinations) !== JSON.stringify([...contract.licenseFiles])) {
+    throw inventoryError(
+      label,
+      'canonical upstream legal files disagree with the carrier contract',
+    );
+  }
+  for (const row of upstreamFiles) {
+    add(`files/${row.destination}`, row.sha256, `${metadata.sqlName}:${row.path}`);
+  }
+  return { contract, members };
+}
+
+/**
+ * Validate both manifest semantics and the exact leaf inventory of a native extension artifact.
+ * Returns the runtime `files/` rows used by npm staging.
+ */
+export function validateExtensionArtifactEntries({
+  entries,
+  metadata: rawMetadata,
+  target,
+  nativeRuntimeVersion,
+  label,
+}) {
+  if (!DESKTOP_NATIVE_TARGETS.has(target)) {
+    throw inventoryError(
+      label,
+      `native target ${JSON.stringify(target)} is not a canonical desktop target`,
+    );
+  }
+  if (
+    typeof nativeRuntimeVersion !== 'string' ||
+    !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(nativeRuntimeVersion)
+  ) {
+    throw inventoryError(label, 'native runtime version must be stable SemVer X.Y.Z');
+  }
+  const metadata = normalizeMetadata(rawMetadata, `${label} canonical metadata`);
+  const manifestEntry = entries.get('manifest.properties');
+  if (manifestEntry === undefined) throw inventoryError(label, 'is missing manifest.properties');
+  const properties = parseExtensionArtifactProperties(
+    decodeUtf8(manifestEntry.data, `${label} manifest.properties`),
+    `${label} manifest.properties`,
+  );
+  const legal = canonicalLegalContract(metadata, target, label);
+  const expectedProperties = new Map([
+    ['packageLayout', 'oliphaunt-extension-artifact-v1'],
+    ['pgMajor', '18'],
+    ['sqlName', metadata.sqlName],
+    ['createsExtension', metadata.createsExtension ? 'yes' : 'no'],
+    ['nativeModuleStem', metadata.nativeModuleStem ?? ''],
+    [
+      'nativeModuleFile',
+      metadata.nativeModuleStem === null
+        ? ''
+        : `${metadata.nativeModuleStem}${moduleSuffix(target)}`,
+    ],
+    ['nativeTarget', target],
+    ['nativeRuntimeProduct', 'liboliphaunt-native'],
+    ['nativeRuntimeVersion', nativeRuntimeVersion],
+    ['dependencies', metadata.dependencies.join(',')],
+    ['dataFiles', metadata.dataFiles.join(',')],
+    ['extensionSqlFileNames', metadata.extensionSqlFileNames.join(',')],
+    ['extensionSqlFilePrefixes', metadata.extensionSqlFilePrefixes.join(',')],
+    ['sharedPreloadLibraries', metadata.sharedPreloadLibraries.join(',')],
+    ['licenseFiles', legal.contract.licenseFiles.join(',')],
+    ['licenseProfile', legal.contract.profile],
+    ['files', 'files'],
+  ]);
+  for (const [key, expected] of expectedProperties) {
+    if (properties.get(key) !== expected) {
+      throw inventoryError(
+        label,
+        `manifest ${key} must be ${JSON.stringify(expected)}; got ${JSON.stringify(properties.get(key))}`,
+      );
+    }
+  }
+  if (!new Set(['yes', 'no']).has(properties.get('mobilePrebuilt'))) {
+    throw inventoryError(label, 'manifest mobilePrebuilt must be yes or no');
+  }
+  validateStaticLinkage(properties, metadata, target, label);
+
+  const allowed = new Set(['manifest.properties']);
+  for (const [member, expected] of legal.members) {
+    allowed.add(member);
+    const entry = entries.get(member);
+    if (entry !== undefined) {
+      if (entry.mode !== 0o644) {
+        throw inventoryError(label, `legal member ${member} must have mode 0644`);
+      }
+      if (entry.sha256 !== expected.sha256) {
+        throw inventoryError(
+          label,
+          `legal member ${member} does not match canonical bytes from ${expected.source}`,
+        );
+      }
+    }
+  }
+  const extensionPrefix = 'files/share/postgresql/extension/';
+  let hasControl = false;
+  let hasInstallSql = false;
+  const extensionFileNames = [];
+  for (const name of entries.keys()) {
+    if (!name.startsWith(extensionPrefix)) continue;
+    const fileName = name.slice(extensionPrefix.length);
+    if (fileName.includes('/') || !sqlFileOwned(fileName, metadata)) {
+      throw inventoryError(label, `contains undeclared extension SQL/control file ${name}`);
+    }
+    allowed.add(name);
+    extensionFileNames.push(fileName);
+    if (fileName === `${metadata.sqlName}.control`) hasControl = true;
+    if (isCanonicalExtensionInstallSql(fileName, metadata.sqlName)) hasInstallSql = true;
+  }
+  if (metadata.createsExtension && (!hasControl || !hasInstallSql)) {
+    throw inventoryError(
+      label,
+      `must contain ${metadata.sqlName}.control and canonical base installation SQL`,
+    );
+  }
+  if (metadata.createsExtension) {
+    const controlName = `${extensionPrefix}${metadata.sqlName}.control`;
+    validateExtensionInstallSqlReachability({
+      sqlName: metadata.sqlName,
+      control: decodeUtf8(entries.get(controlName).data, `${label} ${controlName}`),
+      fileNames: extensionFileNames,
+      label,
+    });
+  }
+  for (const dataFile of metadata.dataFiles) {
+    allowed.add(`files/share/postgresql/${dataFile}`);
+  }
+  if (metadata.nativeModuleStem !== null) {
+    allowed.add(`files/lib/postgresql/${properties.get('nativeModuleFile')}`);
+    if (DESKTOP_NATIVE_TARGETS.has(target)) {
+      allowed.add(`files/lib/modules/${properties.get('nativeModuleFile')}`);
+    }
+  }
+  const mobilePaths = declaredMobilePaths(properties, metadata, label);
+  if (
+    DESKTOP_NATIVE_TARGETS.has(target) &&
+    (properties.get('mobilePrebuilt') !== 'no' || mobilePaths.length !== 0)
+  ) {
+    throw inventoryError(label, 'desktop artifacts must not declare mobile prebuilt files');
+  }
+  for (const mobilePath of mobilePaths) {
+    allowed.add(mobilePath);
+  }
+  const actual = [...entries.keys()].sort(compareText);
+  const expected = [...allowed].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+    const undeclared = actual.filter((name) => !allowed.has(name));
+    const missing = expected.filter((name) => !entries.has(name));
+    throw inventoryError(
+      label,
+      `leaf inventory mismatch${undeclared.length ? `; undeclared: ${undeclared.join(',')}` : ''}` +
+        `${missing.length ? `; missing: ${missing.join(',')}` : ''}`,
+    );
+  }
+  const runtimeFiles = actual
+    .filter((name) => name.startsWith('files/'))
+    .map((name) => {
+      const entry = entries.get(name);
+      return {
+        path: name.slice('files/'.length),
+        bytes: entry.bytes,
+        sha256: entry.sha256,
+      };
+    });
+  if (runtimeFiles.some((row) => !SHA256.test(row.sha256))) {
+    throw inventoryError(label, 'computed an invalid runtime file digest');
+  }
+  const legalFiles = [...legal.members.keys()].sort(compareText).map((name) => {
+    const entry = entries.get(name);
+    return {
+      path: name,
+      bytes: entry.bytes,
+      sha256: entry.sha256,
+    };
+  });
+  return { metadata, properties, runtimeFiles, legalFiles };
+}
+
+export function validateExtensionArtifactArchive(options) {
+  const entries = readCanonicalExtensionArtifactArchive(
+    options.file,
+    options.label ?? options.file,
+  );
+  return {
+    entries,
+    ...validateExtensionArtifactEntries({
+      ...options,
+      entries,
+      label: options.label ?? options.file,
+    }),
+  };
+}
diff --git a/src/extensions/artifacts/packages/tools/extension-artifact-inventory.test.mts b/src/extensions/artifacts/packages/tools/extension-artifact-inventory.test.mts
new file mode 100644
index 000000000..2740113a5
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/extension-artifact-inventory.test.mts
@@ -0,0 +1,851 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import { createWriteStream } from 'node:fs';
+import fs from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
+import { Readable } from 'node:stream';
+import { pipeline } from 'node:stream/promises';
+import test from 'node:test';
+import { createGzip } from 'node:zlib';
+import { canonicalGzipSync } from '../../../../../tools/packaging/portable-archive.mts';
+import { stageReleaseNotices } from '../../../../../tools/packaging/release-notices.mts';
+import { extensionProductForSqlName } from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  EXTENSION_ARTIFACT_ARCHIVE_POLICY,
+  validateExtensionArtifactArchivePlan,
+} from '../../../tools/extension-artifact-archive-policy.mts';
+import {
+  extensionCarrierLegalContract,
+  stageExtensionUpstreamLicenses,
+} from '../../../tools/extension-upstream-licenses.mts';
+import {
+  EXTENSION_ARTIFACT_PROPERTY_KEYS,
+  parseExtensionArtifactProperties,
+  validateExtensionArtifactArchive,
+} from './extension-artifact-inventory.mts';
+
+function writeString(buffer, offset, length, value) {
+  const bytes = Buffer.from(value);
+  assert.ok(bytes.length <= length);
+  bytes.copy(buffer, offset);
+}
+
+function writeOctal(buffer, offset, length, value) {
+  writeString(buffer, offset, length, `${value.toString(8).padStart(length - 1, '0')}\0`);
+}
+
+function tarPathParts(archiveName) {
+  if (Buffer.byteLength(archiveName) <= 100) return { name: archiveName, prefix: '' };
+  const parts = archiveName.split('/');
+  for (let index = 1; index < parts.length; index += 1) {
+    const prefix = parts.slice(0, index).join('/');
+    const name = parts.slice(index).join('/');
+    if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) {
+      return { name, prefix };
+    }
+  }
+  throw new Error(`test archive path is too long for ustar: ${archiveName}`);
+}
+
+function tarHeader(archiveName, bytes, mode = 0o644) {
+  const header = Buffer.alloc(512);
+  const { name, prefix } = tarPathParts(archiveName);
+  writeString(header, 0, 100, name);
+  writeOctal(header, 100, 8, mode);
+  writeOctal(header, 108, 8, 0);
+  writeOctal(header, 116, 8, 0);
+  writeOctal(header, 124, 12, bytes);
+  writeOctal(header, 136, 12, 0);
+  header.fill(0x20, 148, 156);
+  writeString(header, 156, 1, '0');
+  writeString(header, 257, 6, 'ustar\0');
+  writeString(header, 263, 2, '00');
+  writeString(header, 265, 32, 'root');
+  writeString(header, 297, 32, 'root');
+  writeString(header, 345, 155, prefix);
+  const checksum = header.reduce((sum, byte) => sum + byte, 0);
+  writeString(header, 148, 8, `${checksum.toString(8).padStart(6, '0')}\0 `);
+  return header;
+}
+
+function refreshChecksum(header) {
+  header.fill(0x20, 148, 156);
+  const checksum = header.reduce((sum, byte) => sum + byte, 0);
+  writeString(header, 148, 8, `${checksum.toString(8).padStart(6, '0')}\0 `);
+}
+
+function rewriteTarPath(header, { name, prefix }) {
+  header.fill(0, 0, 100);
+  header.fill(0, 345, 500);
+  writeString(header, 0, 100, name);
+  writeString(header, 345, 155, prefix);
+}
+
+function canonicalArchive(entries, { mutateHeader = undefined, trailingZeroBlocks = 2 } = {}) {
+  const chunks = [];
+  for (const [index, [name, raw]] of [...entries]
+    .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
+    .entries()) {
+    const data = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
+    const header = tarHeader(name, data.length, name.includes('/lib/postgresql/') ? 0o755 : 0o644);
+    mutateHeader?.(header, name, index);
+    if (mutateHeader !== undefined) refreshChecksum(header);
+    chunks.push(header);
+    chunks.push(data);
+    if (data.length % 512 !== 0) chunks.push(Buffer.alloc(512 - (data.length % 512)));
+  }
+  chunks.push(Buffer.alloc(512 * trailingZeroBlocks));
+  return canonicalGzipSync(Buffer.concat(chunks));
+}
+
+function legalContract(sqlName, target) {
+  return extensionCarrierLegalContract(
+    extensionProductForSqlName(sqlName, 'extension-artifact-inventory.test.mts'),
+    [sqlName],
+    { family: 'native', target },
+  );
+}
+
+function manifest(overrides = {}) {
+  const sqlName = overrides.sqlName ?? 'pgtap';
+  const nativeTarget = overrides.nativeTarget ?? 'linux-x64-gnu';
+  const legal = legalContract(sqlName, nativeTarget);
+  const values = {
+    packageLayout: 'oliphaunt-extension-artifact-v1',
+    pgMajor: '18',
+    sqlName,
+    createsExtension: 'yes',
+    nativeModuleStem: '',
+    nativeModuleFile: '',
+    nativeTarget,
+    nativeRuntimeProduct: 'liboliphaunt-native',
+    nativeRuntimeVersion: '1.2.3',
+    dependencies: '',
+    dataFiles: '',
+    extensionSqlFileNames: 'uninstall_pgtap.sql',
+    extensionSqlFilePrefixes: 'pgtap-core,pgtap-schema',
+    sharedPreloadLibraries: '',
+    mobilePrebuilt: 'no',
+    mobileStaticArchives: '',
+    mobileStaticDependencyArchives: '',
+    staticSymbolPrefix: '',
+    staticSymbolAliases: '',
+    licenseFiles: legal.licenseFiles.join(','),
+    licenseProfile: legal.profile,
+    files: 'files',
+    ...overrides,
+  };
+  return `${EXTENSION_ARTIFACT_PROPERTY_KEYS.map((key) => `${key}=${values[key]}`).join('\n')}\n`;
+}
+
+async function canonicalLegalEntries(root, sqlName, target = 'linux-x64-gnu') {
+  const contract = legalContract(sqlName, target);
+  const stage = await fs.mkdtemp(path.join(root, `legal-${sqlName}-`));
+  try {
+    stageReleaseNotices(stage, { profile: contract.profile });
+    stageExtensionUpstreamLicenses(sqlName, path.join(stage, 'files'));
+    const rows = [];
+    const visit = async (directory) => {
+      const entries = await fs.readdir(directory, { withFileTypes: true });
+      entries.sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0));
+      for (const entry of entries) {
+        const file = path.join(directory, entry.name);
+        if (entry.isDirectory()) {
+          await visit(file);
+        } else {
+          assert.equal(entry.isFile(), true, `legal fixture contains a non-file entry: ${file}`);
+          rows.push([
+            path.relative(stage, file).split(path.sep).join('/'),
+            await fs.readFile(file),
+          ]);
+        }
+      }
+    };
+    await visit(stage);
+    return new Map(rows);
+  } finally {
+    await fs.rm(stage, { recursive: true, force: true });
+  }
+}
+
+const pgtapMetadata = {
+  sqlName: 'pgtap',
+  createsExtension: true,
+  nativeModuleStem: null,
+  dependencies: [],
+  dataFiles: [],
+  extensionSqlFileNames: ['uninstall_pgtap.sql'],
+  extensionSqlFilePrefixes: ['pgtap-core', 'pgtap-schema'],
+  sharedPreloadLibraries: [],
+};
+
+async function writeArchive(root, name, entries, options = undefined) {
+  const file = path.join(root, name);
+  await fs.writeFile(file, canonicalArchive(entries, options));
+  return file;
+}
+
+async function expectArchiveFailure(root, name, entries, metadata, pattern) {
+  const file = await writeArchive(root, name, entries);
+  assert.throws(
+    () =>
+      validateExtensionArtifactArchive({
+        file,
+        metadata,
+        target: 'linux-x64-gnu',
+        nativeRuntimeVersion: '1.2.3',
+        label: name,
+      }),
+    pattern,
+  );
+}
+
+async function main() {
+  assert.deepEqual(EXTENSION_ARTIFACT_ARCHIVE_POLICY, {
+    maxCompressedBytes: 128 * 1024 * 1024,
+    maxExpandedBytes: 512 * 1024 * 1024,
+    maxMemberBytes: 256 * 1024 * 1024,
+    maxMembers: 4096,
+  });
+  const observedAndroidPostgisMembers = [154_827_564, 110_259_522, 80_534_608];
+  observedAndroidPostgisMembers.length = 27;
+  observedAndroidPostgisMembers.fill(0, 3);
+  const observedAndroidPostgisExpanded = validateExtensionArtifactArchivePlan(
+    observedAndroidPostgisMembers.map((bytes, index) => ({ name: `member-${index}`, bytes })),
+    'observed Android ARM64 PostGIS artifact',
+  );
+  assert.ok(64_676_748 <= EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxCompressedBytes);
+  assert.ok(observedAndroidPostgisExpanded <= EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxExpandedBytes);
+
+  const root = await fs.realpath(
+    await fs.mkdtemp(path.join(os.tmpdir(), 'oliphaunt-extension-inventory-')),
+  );
+  try {
+    const pgtapLegal = await canonicalLegalEntries(root, 'pgtap');
+    const legitimate = new Map([
+      ['manifest.properties', manifest()],
+      ['files/share/postgresql/extension/pgtap--1.3.5.sql', 'install'],
+      ['files/share/postgresql/extension/pgtap-core--fixture.sql', 'owned prefix'],
+      ['files/share/postgresql/extension/pgtap.control', "default_version = '1.3.5'\n"],
+      ['files/share/postgresql/extension/uninstall_pgtap.sql', 'owned exact'],
+      ...pgtapLegal,
+    ]);
+    const validFile = await writeArchive(root, 'legitimate.tar.gz', legitimate);
+    assert.equal(
+      (await fs.readFile(validFile)).subarray(0, 10).toString('hex'),
+      '1f8b0800000000000003',
+    );
+    const validated = validateExtensionArtifactArchive({
+      file: validFile,
+      metadata: pgtapMetadata,
+      target: 'linux-x64-gnu',
+      nativeRuntimeVersion: '1.2.3',
+      label: 'legitimate',
+    });
+    assert.deepEqual(
+      validated.legalFiles.map(({ path: member }) => member),
+      [...pgtapLegal.keys()].sort(),
+    );
+    assert.equal(
+      validated.runtimeFiles.length,
+      4 + legalContract('pgtap', 'linux-x64-gnu').licenseFiles.length,
+    );
+
+    const pgtapUpstreamLegalMember = `files/${
+      legalContract('pgtap', 'linux-x64-gnu').licenseFiles[0]
+    }`;
+    assert.equal(pgtapLegal.has(pgtapUpstreamLegalMember), true);
+    for (const [caseName, member] of [
+      ['root', 'LICENSE'],
+      ['upstream', pgtapUpstreamLegalMember],
+    ]) {
+      const missingLegal = new Map(legitimate);
+      missingLegal.delete(member);
+      await expectArchiveFailure(
+        root,
+        `missing-${caseName}-legal.tar.gz`,
+        missingLegal,
+        pgtapMetadata,
+        new RegExp(`missing: ${member.replaceAll('/', '\\/').replaceAll('.', '\\.')}`, 'u'),
+      );
+
+      const mutatedLegal = new Map(legitimate);
+      mutatedLegal.set(member, `mutated ${caseName} legal bytes`);
+      await expectArchiveFailure(
+        root,
+        `mutated-${caseName}-legal.tar.gz`,
+        mutatedLegal,
+        pgtapMetadata,
+        /legal member .* does not match canonical bytes/u,
+      );
+
+      const executableLegalFile = await writeArchive(
+        root,
+        `executable-${caseName}-legal.tar.gz`,
+        legitimate,
+        {
+          mutateHeader(header, name) {
+            if (name === member) writeOctal(header, 100, 8, 0o755);
+          },
+        },
+      );
+      assert.throws(
+        () =>
+          validateExtensionArtifactArchive({
+            file: executableLegalFile,
+            metadata: pgtapMetadata,
+            target: 'linux-x64-gnu',
+            nativeRuntimeVersion: '1.2.3',
+            label: `executable ${caseName} legal member`,
+          }),
+        new RegExp(
+          `legal member ${member.replaceAll('/', '\\/').replaceAll('.', '\\.')} must have mode 0644`,
+          'u',
+        ),
+      );
+    }
+
+    const unexpectedLegal = new Map(legitimate);
+    unexpectedLegal.set('THIRD_PARTY_LICENSES/undeclared.txt', 'not contracted');
+    await expectArchiveFailure(
+      root,
+      'unexpected-legal.tar.gz',
+      unexpectedLegal,
+      pgtapMetadata,
+      /undeclared: THIRD_PARTY_LICENSES\/undeclared[.]txt/u,
+    );
+
+    for (const [name, overrides, pattern] of [
+      ['license-files', { licenseFiles: '' }, /manifest licenseFiles must be/u],
+      ['license-profile', { licenseProfile: 'contrib-native' }, /manifest licenseProfile must be/u],
+    ]) {
+      const driftedLegalProperty = new Map(legitimate);
+      driftedLegalProperty.set('manifest.properties', manifest(overrides));
+      await expectArchiveFailure(
+        root,
+        `drifted-${name}.tar.gz`,
+        driftedLegalProperty,
+        pgtapMetadata,
+        pattern,
+      );
+    }
+    assert.throws(
+      () =>
+        parseExtensionArtifactProperties(
+          manifest().replace(
+            /licenseFiles=([^\n]*)\nlicenseProfile=([^\n]*)\n/u,
+            'licenseProfile=$2\nlicenseFiles=$1\n',
+          ),
+          'reordered legal properties',
+        ),
+      /properties must use the canonical field order/u,
+    );
+
+    const carrierSymlink = path.join(root, 'carrier-symlink.tar.gz');
+    await fs.symlink(validFile, carrierSymlink);
+    assert.throws(
+      () =>
+        validateExtensionArtifactArchive({
+          file: carrierSymlink,
+          metadata: pgtapMetadata,
+          target: 'linux-x64-gnu',
+          nativeRuntimeVersion: '1.2.3',
+          label: 'carrier symlink',
+        }),
+      /regular non-symlink file/u,
+    );
+
+    const extraPaddingFile = await writeArchive(root, 'extra-zero-padding.tar.gz', legitimate, {
+      trailingZeroBlocks: 3,
+    });
+    assert.throws(
+      () =>
+        validateExtensionArtifactArchive({
+          file: extraPaddingFile,
+          metadata: pgtapMetadata,
+          target: 'linux-x64-gnu',
+          nativeRuntimeVersion: '1.2.3',
+          label: 'extra zero padding',
+        }),
+      /tar end marker or trailing padding is not canonical/u,
+    );
+
+    const shortAlternateSplit = await writeArchive(
+      root,
+      'short-alternate-ustar-split.tar.gz',
+      legitimate,
+      {
+        mutateHeader(header, name) {
+          if (name === 'files/share/postgresql/extension/pgtap.control') {
+            rewriteTarPath(header, {
+              prefix: 'files',
+              name: 'share/postgresql/extension/pgtap.control',
+            });
+          }
+        },
+      },
+    );
+    assert.throws(
+      () =>
+        validateExtensionArtifactArchive({
+          file: shortAlternateSplit,
+          metadata: pgtapMetadata,
+          target: 'linux-x64-gnu',
+          nativeRuntimeVersion: '1.2.3',
+          label: 'short alternate ustar split',
+        }),
+      /canonical ustar name\/prefix split/u,
+    );
+
+    const longMember = `files/share/postgresql/data/${'a'.repeat(40)}/${'b'.repeat(40)}/${'c'.repeat(40)}.bin`;
+    const longAlternateSplit = await writeArchive(
+      root,
+      'long-alternate-ustar-split.tar.gz',
+      new Map([...legitimate, [longMember, 'long path']]),
+      {
+        mutateHeader(header, name) {
+          if (name !== longMember) return;
+          const parts = name.split('/');
+          const validSplits = [];
+          for (let index = 1; index < parts.length; index += 1) {
+            const prefix = parts.slice(0, index).join('/');
+            const memberName = parts.slice(index).join('/');
+            if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(memberName) <= 100) {
+              validSplits.push({ prefix, name: memberName });
+            }
+          }
+          assert.ok(validSplits.length > 1);
+          rewriteTarPath(header, validSplits[1]);
+        },
+      },
+    );
+    assert.throws(
+      () =>
+        validateExtensionArtifactArchive({
+          file: longAlternateSplit,
+          metadata: pgtapMetadata,
+          target: 'linux-x64-gnu',
+          nativeRuntimeVersion: '1.2.3',
+          label: 'long alternate ustar split',
+        }),
+      /canonical ustar name\/prefix split/u,
+    );
+
+    const staleEighteenFieldManifest = manifest()
+      .replace('extensionSqlFileNames=uninstall_pgtap.sql\n', '')
+      .replace('extensionSqlFilePrefixes=pgtap-core,pgtap-schema\n', '');
+    assert.throws(
+      () => parseExtensionArtifactProperties(staleEighteenFieldManifest, 'stale leaf manifest'),
+      /property fields must be exactly/u,
+    );
+    for (const [field, value] of [
+      ['extensionSqlFileNames', 'foreign.sql'],
+      ['extensionSqlFilePrefixes', 'foreign-prefix'],
+    ]) {
+      const drifted = new Map(legitimate);
+      drifted.set('manifest.properties', manifest({ [field]: value }));
+      await expectArchiveFailure(
+        root,
+        `frozen-${field}-drift.tar.gz`,
+        drifted,
+        pgtapMetadata,
+        new RegExp(`manifest ${field} must be`, 'u'),
+      );
+    }
+
+    const contaminated = new Map(legitimate);
+    contaminated.set('files/share/postgresql/extension/foreign.control', 'undeclared');
+    await expectArchiveFailure(
+      root,
+      'recomputed-contaminated.tar.gz',
+      contaminated,
+      pgtapMetadata,
+      /undeclared extension SQL\/control file.*foreign\.control/u,
+    );
+
+    const prefixedControl = new Map(legitimate);
+    prefixedControl.set('files/share/postgresql/extension/pgtap-core-evil.control', 'undeclared');
+    await expectArchiveFailure(
+      root,
+      'prefixed-control.tar.gz',
+      prefixedControl,
+      pgtapMetadata,
+      /pgtap-core-evil\.control/u,
+    );
+
+    const ancillaryOnly = new Map(legitimate);
+    ancillaryOnly.delete('files/share/postgresql/extension/pgtap--1.3.5.sql');
+    ancillaryOnly.set(
+      'files/share/postgresql/extension/pgtap--1.3.4--1.3.5.sql',
+      'transition SQL is owned but is not a base install',
+    );
+    await expectArchiveFailure(
+      root,
+      'ancillary-only.tar.gz',
+      ancillaryOnly,
+      pgtapMetadata,
+      /control and canonical base installation SQL/u,
+    );
+
+    const disconnectedDefault = new Map(legitimate);
+    disconnectedDefault.delete('files/share/postgresql/extension/pgtap--1.3.5.sql');
+    disconnectedDefault.set('files/share/postgresql/extension/pgtap--1.3.3.sql', 'older install');
+    disconnectedDefault.set(
+      'files/share/postgresql/extension/pgtap--1.3.3--1.3.4.sql',
+      'incomplete update path',
+    );
+    await expectArchiveFailure(
+      root,
+      'disconnected-default.tar.gz',
+      disconnectedDefault,
+      pgtapMetadata,
+      /default_version '1[.]3[.]5' has no canonical installation script or update path/u,
+    );
+
+    const plainSqlOnly = new Map(legitimate);
+    plainSqlOnly.delete('files/share/postgresql/extension/pgtap--1.3.5.sql');
+    plainSqlOnly.set(
+      'files/share/postgresql/extension/pgtap.sql',
+      'PostgreSQL 18 does not discover this as a versioned install script',
+    );
+    await expectArchiveFailure(
+      root,
+      'plain-sql-only.tar.gz',
+      plainSqlOnly,
+      pgtapMetadata,
+      /control and canonical base installation SQL/u,
+    );
+
+    const letterLeadingOnly = new Map(legitimate);
+    letterLeadingOnly.delete('files/share/postgresql/extension/pgtap--1.3.5.sql');
+    letterLeadingOnly.set(
+      'files/share/postgresql/extension/pgtap--release.sql',
+      'letter-leading version is owned but is not a base install',
+    );
+    await expectArchiveFailure(
+      root,
+      'letter-leading-only.tar.gz',
+      letterLeadingOnly,
+      pgtapMetadata,
+      /control and canonical base installation SQL/u,
+    );
+
+    const autoExplainMetadata = {
+      ...pgtapMetadata,
+      sqlName: 'auto_explain',
+      createsExtension: false,
+      nativeModuleStem: 'auto_explain',
+      extensionSqlFileNames: [],
+      extensionSqlFilePrefixes: [],
+    };
+    const autoExplain = new Map([
+      [
+        'manifest.properties',
+        manifest({
+          sqlName: 'auto_explain',
+          createsExtension: 'no',
+          nativeModuleStem: 'auto_explain',
+          nativeModuleFile: 'auto_explain.so',
+          extensionSqlFileNames: '',
+          extensionSqlFilePrefixes: '',
+        }),
+      ],
+      ['files/lib/postgresql/auto_explain.so', 'module'],
+      ['files/share/postgresql/extension/auto_explain.control', 'undeclared'],
+    ]);
+    await expectArchiveFailure(
+      root,
+      'load-only-control.tar.gz',
+      autoExplain,
+      autoExplainMetadata,
+      /auto_explain\.control/u,
+    );
+
+    const postgisMetadata = {
+      sqlName: 'postgis',
+      createsExtension: true,
+      nativeModuleStem: 'postgis-3',
+      dependencies: [],
+      dataFiles: [
+        'contrib/postgis-3.6/legacy.sql',
+        'contrib/postgis-3.6/legacy_gist.sql',
+        'contrib/postgis-3.6/legacy_minimal.sql',
+        'contrib/postgis-3.6/postgis.sql',
+        'contrib/postgis-3.6/postgis_upgrade.sql',
+        'contrib/postgis-3.6/spatial_ref_sys.sql',
+        'contrib/postgis-3.6/uninstall_legacy.sql',
+        'contrib/postgis-3.6/uninstall_postgis.sql',
+        'proj/proj.db',
+      ],
+      extensionSqlFileNames: [],
+      extensionSqlFilePrefixes: ['postgis_comments'],
+      sharedPreloadLibraries: [],
+    };
+    const postgisLegal = await canonicalLegalEntries(root, 'postgis');
+    const postgis = new Map([
+      [
+        'manifest.properties',
+        manifest({
+          sqlName: 'postgis',
+          nativeModuleStem: 'postgis-3',
+          nativeModuleFile: 'postgis-3.so',
+          dataFiles: postgisMetadata.dataFiles.join(','),
+          extensionSqlFileNames: postgisMetadata.extensionSqlFileNames.join(','),
+          extensionSqlFilePrefixes: postgisMetadata.extensionSqlFilePrefixes.join(','),
+        }),
+      ],
+      ['files/lib/postgresql/postgis-3.so', 'module'],
+      ['files/lib/modules/postgis-3.so', 'embedded module'],
+      ['files/share/postgresql/extension/postgis--3.6.1--3.6.2.sql', 'upgrade'],
+      ['files/share/postgresql/extension/postgis--3.6.2--3.6.3.sql', 'upgrade'],
+      ['files/share/postgresql/extension/postgis--3.6.3.sql', 'install'],
+      ['files/share/postgresql/extension/postgis.control', "default_version = '3.6.3'\n"],
+      ...postgisMetadata.dataFiles.map((dataFile) => [
+        `files/share/postgresql/${dataFile}`,
+        `declared data ${dataFile}`,
+      ]),
+      ...postgisLegal,
+    ]);
+    const postgisFile = await writeArchive(root, 'postgis-legitimate.tar.gz', postgis);
+    const validatedPostgis = validateExtensionArtifactArchive({
+      file: postgisFile,
+      metadata: postgisMetadata,
+      target: 'linux-x64-gnu',
+      nativeRuntimeVersion: '1.2.3',
+      label: 'postgis legitimate',
+    });
+    assert.equal(
+      validatedPostgis.runtimeFiles.length,
+      [...postgis.keys()].filter((member) => member.startsWith('files/')).length,
+    );
+    assert.deepEqual(
+      validatedPostgis.legalFiles.map(({ path: member }) => member),
+      [...postgisLegal.keys()].sort(),
+    );
+
+    const missingEmbeddedPostgis = new Map(postgis);
+    missingEmbeddedPostgis.delete('files/lib/modules/postgis-3.so');
+    await expectArchiveFailure(
+      root,
+      'postgis-missing-embedded-module.tar.gz',
+      missingEmbeddedPostgis,
+      postgisMetadata,
+      /missing: files\/lib\/modules\/postgis-3[.]so/u,
+    );
+
+    for (const [name, text, pattern] of [
+      ['bom', `\uFEFF${manifest()}`, /canonical NFC UTF-8/u],
+      ['crlf', manifest().replaceAll('\n', '\r\n'), /canonical NFC UTF-8/u],
+      ['blank', manifest().replace('pgMajor=18\n', 'pgMajor=18\n\n'), /internal blank line/u],
+      [
+        'duplicate',
+        manifest().replace('pgMajor=18\n', 'pgMajor=18\npgMajor=18\n'),
+        /repeats property pgMajor/u,
+      ],
+    ]) {
+      assert.throws(() => parseExtensionArtifactProperties(text, name), pattern);
+    }
+
+    const invalidUtf8 = new Map(legitimate);
+    invalidUtf8.set(
+      'manifest.properties',
+      Buffer.concat([Buffer.from(manifest().slice(0, -1)), Buffer.from([0xff, 0x0a])]),
+    );
+    await expectArchiveFailure(
+      root,
+      'invalid-utf8.tar.gz',
+      invalidUtf8,
+      pgtapMetadata,
+      /invalid UTF-8/u,
+    );
+    const bomManifest = new Map(legitimate);
+    bomManifest.set(
+      'manifest.properties',
+      Buffer.concat([Buffer.from([0xef, 0xbb, 0xbf]), Buffer.from(manifest())]),
+    );
+    await expectArchiveFailure(
+      root,
+      'bom-manifest.tar.gz',
+      bomManifest,
+      pgtapMetadata,
+      /canonical NFC UTF-8/u,
+    );
+
+    const caseCollision = new Map(legitimate);
+    caseCollision.set('files/share/postgresql/extension/Pgtap.control', 'collision');
+    await expectArchiveFailure(
+      root,
+      'case-collision.tar.gz',
+      caseCollision,
+      pgtapMetadata,
+      /case\/NFC-colliding members/u,
+    );
+
+    for (const [name, memberPath, pattern] of [
+      ['backslash-path', 'files\\share/postgresql/extension/evil', /without backslashes/u],
+      ['traversal-path', '../evil', /canonical relative path/u],
+      ['non-nfc-path', 'files/share/postgresql/extension/pgta\u0065\u0301.sql', /NFC UTF-8/u],
+    ]) {
+      const entries = new Map(legitimate);
+      entries.set(memberPath, 'unsafe');
+      await expectArchiveFailure(root, `${name}.tar.gz`, entries, pgtapMetadata, pattern);
+    }
+
+    const duplicateMembers = [
+      ...legitimate,
+      ['files/share/postgresql/extension/pgtap.control', 'duplicate'],
+    ];
+    await expectArchiveFailure(
+      root,
+      'duplicate-member.tar.gz',
+      duplicateMembers,
+      pgtapMetadata,
+      /duplicate member.*pgtap\.control/u,
+    );
+
+    const symlinkFile = await writeArchive(root, 'symlink-type.tar.gz', legitimate, {
+      mutateHeader(header, _name, index) {
+        if (index === 0) header[156] = '2'.charCodeAt(0);
+      },
+    });
+    assert.throws(
+      () =>
+        validateExtensionArtifactArchive({
+          file: symlinkFile,
+          metadata: pgtapMetadata,
+          target: 'linux-x64-gnu',
+          nativeRuntimeVersion: '1.2.3',
+          label: 'symlink type',
+        }),
+      /must be a regular file/u,
+    );
+
+    const invalidHeader = Buffer.from(await fs.readFile(validFile));
+    invalidHeader[9] = 0x13;
+    const invalidHeaderFile = path.join(root, 'invalid-gzip-header.tar.gz');
+    await fs.writeFile(invalidHeaderFile, invalidHeader);
+    assert.throws(
+      () =>
+        validateExtensionArtifactArchive({
+          file: invalidHeaderFile,
+          metadata: pgtapMetadata,
+          target: 'linux-x64-gnu',
+          nativeRuntimeVersion: '1.2.3',
+          label: 'invalid gzip header',
+        }),
+      /canonical cross-platform gzip header/u,
+    );
+
+    const invalidAlias = new Map(legitimate);
+    invalidAlias.set('manifest.properties', manifest({ staticSymbolAliases: 'sql:not-valid!' }));
+    await expectArchiveFailure(
+      root,
+      'invalid-alias.tar.gz',
+      invalidAlias,
+      pgtapMetadata,
+      /C-identifier pair/u,
+    );
+    const duplicateAlias = new Map(legitimate);
+    duplicateAlias.set(
+      'manifest.properties',
+      manifest({ staticSymbolAliases: 'sql_symbol:linked_one,sql_symbol:linked_two' }),
+    );
+    await expectArchiveFailure(
+      root,
+      'duplicate-alias.tar.gz',
+      duplicateAlias,
+      pgtapMetadata,
+      /repeats SQL-visible symbol sql_symbol/u,
+    );
+
+    const oversizedMemberName = 'files/share/postgresql/extension/pgtap--oversized.sql';
+    const oversizedMember = new Map(legitimate);
+    oversizedMember.set(oversizedMemberName, 'declared-size-only');
+    const oversizedMemberFile = await writeArchive(
+      root,
+      'oversized-member.tar.gz',
+      oversizedMember,
+      {
+        mutateHeader(header, name) {
+          if (name === oversizedMemberName) {
+            writeOctal(header, 124, 12, EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes + 1);
+          }
+        },
+      },
+    );
+    assert.throws(
+      () =>
+        validateExtensionArtifactArchive({
+          file: oversizedMemberFile,
+          metadata: pgtapMetadata,
+          target: 'linux-x64-gnu',
+          nativeRuntimeVersion: '1.2.3',
+          label: 'oversized member',
+        }),
+      /member .* exceeds 268435456 bytes/u,
+    );
+
+    assert.throws(
+      () =>
+        validateExtensionArtifactArchivePlan([
+          { name: 'one', bytes: EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes },
+          { name: 'two', bytes: EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes },
+        ]),
+      /expands beyond 536870912 bytes/u,
+    );
+
+    const excessiveMembers = new Map([['manifest.properties', manifest()]]);
+    for (let index = 0; index < 4097; index += 1) {
+      excessiveMembers.set(
+        `files/share/postgresql/extension/pgtap--${String(index).padStart(4, '0')}.sql`,
+        'x',
+      );
+    }
+    await expectArchiveFailure(
+      root,
+      'excessive-members.tar.gz',
+      excessiveMembers,
+      pgtapMetadata,
+      /more than 4096 members/u,
+    );
+
+    const unbounded = path.join(root, 'expanded-bomb.tar.gz');
+    async function* oversizedZeros() {
+      const chunk = Buffer.alloc(1024 * 1024);
+      const chunks = EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxExpandedBytes / chunk.length + 1;
+      for (let index = 0; index < chunks; index += 1) yield chunk;
+    }
+    await pipeline(Readable.from(oversizedZeros()), createGzip(), createWriteStream(unbounded));
+    const unboundedDescriptor = await fs.open(unbounded, 'r+');
+    try {
+      await unboundedDescriptor.write(Buffer.from('1f8b0800000000000003', 'hex'), 0, 10, 0);
+    } finally {
+      await unboundedDescriptor.close();
+    }
+    assert.throws(
+      () =>
+        validateExtensionArtifactArchive({
+          file: unbounded,
+          metadata: pgtapMetadata,
+          target: 'linux-x64-gnu',
+          nativeRuntimeVersion: '1.2.3',
+          label: 'expanded bomb',
+        }),
+      /bounded readable gzip stream|expanded archive exceeds/u,
+    );
+
+    console.log(
+      'extension-artifact-inventory.test.mts: exact inventory and adversarial bounds checks passed',
+    );
+  } finally {
+    await fs.rm(root, { recursive: true, force: true });
+  }
+}
+
+test(
+  'extension artifact inventory enforces exact inventory and adversarial bounds',
+  { timeout: 120_000 },
+  main,
+);
diff --git a/src/extensions/artifacts/packages/tools/extension-registry-packages.mts b/src/extensions/artifacts/packages/tools/extension-registry-packages.mts
new file mode 100644
index 000000000..f39164bc4
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/extension-registry-packages.mts
@@ -0,0 +1,239 @@
+import {
+  expectedExtensionAotTargets,
+  wasixExtensionAotPackageName,
+  wasixExtensionPackageName,
+} from '../../../../runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts';
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+const REGISTRY_KIND_ORDER = new Map([
+  ['crates', 0],
+  ['npm', 1],
+  ['maven', 2],
+]);
+
+function stringTargetList(value, label) {
+  if (
+    !Array.isArray(value) ||
+    !value.every((item) => typeof item === 'string' && item.length > 0)
+  ) {
+    throw new TypeError(`${label} must be a string list`);
+  }
+  return [...value].sort(compareText);
+}
+
+export function extensionNpmPackage(sqlName) {
+  return `@oliphaunt/extension-${sqlName.replaceAll('_', '-')}`;
+}
+
+export function extensionNpmTargetPackage(sqlName, target) {
+  return `${extensionNpmPackage(sqlName)}-${target}`;
+}
+
+export function extensionNpmPackageForProduct(product) {
+  if (typeof product !== 'string' || !product.startsWith('oliphaunt-extension-')) {
+    throw new TypeError(
+      `extension product must start with oliphaunt-extension-: ${JSON.stringify(product)}`,
+    );
+  }
+  return `@oliphaunt/${product.slice('oliphaunt-'.length)}`;
+}
+
+/**
+ * Host-neutral npm carrier for one product's portable WASIX extension bytes.
+ *
+ * Keep the unsuffixed npm identity as the established native/default facade.
+ * Browser, Node, Bun, and Deno WASIX hosts intentionally share this one explicit carrier.
+ */
+export function extensionNpmWasixPackageForProduct(product) {
+  return `${extensionNpmPackageForProduct(product)}-wasix`;
+}
+
+export function extensionNpmTargetPackageForProduct(product, target) {
+  return `${extensionNpmPackageForProduct(product)}-${target}`;
+}
+
+export function nativeExtensionCargoPackageName(product, target) {
+  return `${product}-${target}`;
+}
+
+export function nativeExtensionCargoLinksName(product, target) {
+  const stem = `extension_${product.replace(/^oliphaunt-extension-/u, '')}_${target}`;
+  return `oliphaunt_artifact_${stem.replaceAll('-', '_')}`;
+}
+
+export function nativeExtensionCargoPartPackageName(product, target, index) {
+  if (!Number.isSafeInteger(index) || index < 1 || index > 999) {
+    throw new TypeError(
+      `native extension Cargo part number must be an integer from 1 through 999: ${JSON.stringify(index)}`,
+    );
+  }
+  return `${nativeExtensionCargoPackageName(product, target)}-part-${String(index).padStart(3, '0')}`;
+}
+
+export function assertCargoPackageName(
+  name,
+  { splittable = false, context = 'Cargo package' } = {},
+) {
+  if (typeof name !== 'string' || name.length === 0) {
+    throw new TypeError(`${context} name must be a non-empty string`);
+  }
+  if (name.length > 64) {
+    throw new TypeError(
+      `${context} ${JSON.stringify(name)} is ${name.length} characters; crates.io allows at most 64`,
+    );
+  }
+  if (splittable && `${name}-part-001`.length > 64) {
+    throw new TypeError(
+      `${context} ${JSON.stringify(name)} cannot be split: ${JSON.stringify(`${name}-part-001`)} exceeds crates.io's 64-character limit`,
+    );
+  }
+  return name;
+}
+
+export function extensionStableNpmPackageNames(sqlName, targets) {
+  const targetList = stringTargetList(targets, 'extension npm targets');
+  return [
+    extensionNpmPackage(sqlName),
+    ...targetList.map((target) => extensionNpmTargetPackage(sqlName, target)),
+  ].sort(compareText);
+}
+
+export function extensionStableNpmPackageNamesForProduct(product, targets) {
+  const targetList = stringTargetList(targets, 'extension npm targets');
+  return [
+    extensionNpmPackageForProduct(product),
+    ...targetList.map((target) => extensionNpmTargetPackageForProduct(product, target)),
+  ].sort(compareText);
+}
+
+export function extensionNativeCargoPackageNames(product, targets) {
+  return stringTargetList(targets, 'native extension Cargo targets')
+    .map((target) =>
+      assertCargoPackageName(nativeExtensionCargoPackageName(product, target), {
+        splittable: true,
+        context: `${product} native carrier`,
+      }),
+    )
+    .sort(compareText);
+}
+
+export function extensionWasixCargoPackageNames(
+  product,
+  { includeAot = true, aotTargets = expectedExtensionAotTargets() } = {},
+) {
+  return [
+    assertCargoPackageName(wasixExtensionPackageName(product), {
+      splittable: true,
+      context: `${product} portable WASIX carrier`,
+    }),
+    ...(includeAot
+      ? aotTargets.map((target) =>
+          assertCargoPackageName(wasixExtensionAotPackageName(product, target), {
+            splittable: true,
+            context: `${product} WASIX AOT carrier`,
+          }),
+        )
+      : []),
+  ].sort(compareText);
+}
+
+export function extensionMavenPackageNames(product, androidTargets) {
+  return stringTargetList(androidTargets, 'extension Android Maven targets')
+    .map((target) => `dev.oliphaunt.extensions:${product}-${target}`)
+    .sort(compareText);
+}
+
+export function extensionRegistryPackageEntries({
+  product,
+  androidTargets,
+  npmTargets,
+  nativeCargoTargets,
+  includeWasixAot = true,
+  includeWasixNpm = true,
+  wasixAotTargets = expectedExtensionAotTargets(),
+}) {
+  return [
+    ...extensionNativeRegistryPackageEntries({
+      product,
+      androidTargets,
+      npmTargets,
+      nativeCargoTargets,
+    }),
+    ...extensionWasixRegistryPackageEntries({
+      product,
+      includeAot: includeWasixAot,
+      includeNpm: includeWasixNpm,
+      aotTargets: wasixAotTargets,
+    }),
+  ].sort(
+    (left, right) =>
+      (REGISTRY_KIND_ORDER.get(left.kind) ?? 99) - (REGISTRY_KIND_ORDER.get(right.kind) ?? 99) ||
+      compareText(left.name, right.name),
+  );
+}
+
+export function extensionNativeRegistryPackageEntries({
+  product,
+  androidTargets,
+  npmTargets,
+  nativeCargoTargets,
+  includeFacade = true,
+}) {
+  return [
+    ...(includeFacade
+      ? [
+          {
+            kind: 'crates',
+            name: assertCargoPackageName(product, { context: `${product} facade` }),
+          },
+        ]
+      : []),
+    ...extensionNativeCargoPackageNames(product, nativeCargoTargets).map((name) => ({
+      kind: 'crates',
+      name,
+    })),
+    ...extensionStableNpmPackageNamesForProduct(product, npmTargets).map((name) => ({
+      kind: 'npm',
+      name,
+    })),
+    ...extensionMavenPackageNames(product, androidTargets).map((name) => ({ kind: 'maven', name })),
+  ].sort(
+    (left, right) =>
+      (REGISTRY_KIND_ORDER.get(left.kind) ?? 99) - (REGISTRY_KIND_ORDER.get(right.kind) ?? 99) ||
+      compareText(left.name, right.name),
+  );
+}
+
+export function extensionWasixRegistryPackageEntries({
+  product,
+  includeAot = true,
+  includeNpm = true,
+  aotTargets = expectedExtensionAotTargets(),
+}) {
+  return [
+    ...extensionWasixCargoPackageNames(product, { includeAot, aotTargets }).map((name) => ({
+      kind: 'crates',
+      name,
+    })),
+    ...(includeNpm ? [{ kind: 'npm', name: extensionNpmWasixPackageForProduct(product) }] : []),
+  ];
+}
+
+export function extensionRegistryPackageStrings(options) {
+  return extensionRegistryPackageEntries(options).map((entry) => `${entry.kind}:${entry.name}`);
+}
+
+export function extensionNativeRegistryPackageStrings(options) {
+  return extensionNativeRegistryPackageEntries(options).map(
+    (entry) => `${entry.kind}:${entry.name}`,
+  );
+}
+
+export function extensionWasixRegistryPackageStrings(options) {
+  return extensionWasixRegistryPackageEntries(options).map(
+    (entry) => `${entry.kind}:${entry.name}`,
+  );
+}
diff --git a/src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts b/src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts
new file mode 100644
index 000000000..b3c157b7c
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts
@@ -0,0 +1,21 @@
+const EXTENSION_RUNTIME_ASSET_CONTRACT_FIELDS = Object.freeze([
+  'name',
+  'family',
+  'target',
+  'kind',
+  'identity',
+  'sha256',
+  'bytes',
+  'carrierAsset',
+  'carrierRoot',
+  'memberPath',
+  'memberCount',
+]);
+
+export function extensionRuntimeAssetContract(asset) {
+  const result = {};
+  for (const key of EXTENSION_RUNTIME_ASSET_CONTRACT_FIELDS) {
+    if (Object.hasOwn(asset, key)) result[key] = asset[key];
+  }
+  return result;
+}
diff --git a/src/extensions/artifacts/packages/tools/extension-wasix-npm-packages.test.mts b/src/extensions/artifacts/packages/tools/extension-wasix-npm-packages.test.mts
new file mode 100644
index 000000000..56d87399c
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/extension-wasix-npm-packages.test.mts
@@ -0,0 +1,423 @@
+#!/usr/bin/env bun
+import { afterAll, expect, test } from 'bun:test';
+import { createHash } from 'node:crypto';
+import {
+  appendFileSync,
+  mkdirSync,
+  mkdtempSync,
+  readFileSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { zstdCompressSync } from 'node:zlib';
+
+import { createDeterministicTar } from '../../../../../tools/packaging/cargo-source-package.mts';
+import {
+  canonicalGzipSync,
+  extractPortableArchiveTree,
+} from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  currentProductVersionSync,
+  extensionRegistryPackageTargetSets,
+  extensionReleaseVersion,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  extensionNpmPackageForProduct,
+  extensionNpmWasixPackageForProduct,
+  extensionRegistryPackageEntries,
+} from './extension-registry-packages.mts';
+import {
+  stageExtensionNpmPackagesForTargets,
+  stageExtensionWasixNpmPackages,
+} from './package-extension-release-carriers.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../../../../..');
+const directories = [];
+const hostFixtures = process.env.OLIPHAUNT_EXTENSION_NODE_FIXTURES;
+
+import { inspectDescriptor } from './testdata/inspect-wasix-descriptor.mts';
+
+afterAll(() => {
+  if (hostFixtures) return;
+  for (const directory of directories) rmSync(directory, { recursive: true, force: true });
+});
+
+function temporaryRoot(name) {
+  const root = mkdtempSync(path.join(hostFixtures || os.tmpdir(), name));
+  directories.push(root);
+  return root;
+}
+
+function sha256Bytes(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function deterministicTar(stage, archiveRoot) {
+  return createDeterministicTar(stage, archiveRoot, {
+    fail(message) {
+      throw new Error(message);
+    },
+    fixedFileMode: 0o644,
+  });
+}
+
+function portableExtensionBytes(root, sqlName) {
+  const stage = path.join(root, 'portable-members', sqlName);
+  const control = path.join(stage, 'postgresql', 'extension', `${sqlName}.control`);
+  mkdirSync(path.dirname(control), { recursive: true });
+  writeFileSync(control, `comment = '${sqlName} fixture'\ndefault_version = '1.0'\n`);
+  return zstdCompressSync(deterministicTar(stage, 'share'));
+}
+
+function compatibility() {
+  return {
+    extensionRuntimeContract: 'src/extensions/contracts/contract.toml',
+    nativeRuntimeProduct: 'liboliphaunt-native',
+    nativeRuntimeVersion: currentProductVersionSync(
+      'liboliphaunt-native',
+      'extension-wasix-npm-packages.test',
+    ),
+    postgresMajor: '18',
+    wasixRuntimeProduct: 'liboliphaunt-wasix',
+    wasixRuntimeVersion: currentProductVersionSync(
+      'liboliphaunt-wasix',
+      'extension-wasix-npm-packages.test',
+    ),
+  };
+}
+
+function wasixInstall(sqlName, dependencies = []) {
+  return {
+    schema: 'oliphaunt-wasix-extension-install-v1',
+    name: sqlName,
+    nativeModule: null,
+    nativeModules: [],
+    coreExportsRequired: [],
+    dependencies,
+    loadOrder: [],
+    lifecycle: {
+      createExtension: true,
+      createSchema: 'pg_catalog',
+      loadSql: [],
+      postCreateSql: [],
+      startupConfig: [],
+      preloadRequired: false,
+      restartRequired: false,
+      sharedMemoryRequired: false,
+    },
+    installedFiles: [`share/postgresql/extension/${sqlName}.control`],
+    unresolvedImports: [],
+  };
+}
+
+function inventory(sqlName, dependencies = []) {
+  return {
+    sqlName,
+    createsExtension: true,
+    nativeModuleStem: null,
+    dependencies,
+    dataFiles: [],
+    extensionSqlFileNames: [`${sqlName}.control`],
+    extensionSqlFilePrefixes: [sqlName],
+    sharedPreloadLibraries: [],
+  };
+}
+
+function singletonFixture(root, { dependencies = ['plpgsql'] } = {}) {
+  const product = 'oliphaunt-extension-pgtap';
+  const version = '9.8.7';
+  const sqlName = 'pgtap';
+  const extensionRoot = path.join(root, product);
+  const releaseAssets = path.join(extensionRoot, 'release-assets');
+  const name = `${product}-${version}-wasix-portable.tar.zst`;
+  const archive = path.join(releaseAssets, name);
+  const bytes = portableExtensionBytes(root, sqlName);
+  mkdirSync(releaseAssets, { recursive: true });
+  writeFileSync(archive, bytes);
+  const member = inventory(sqlName, dependencies);
+  member.wasixInstall = wasixInstall(sqlName, dependencies);
+  const asset = {
+    name,
+    family: 'wasix',
+    target: 'wasix-portable',
+    kind: 'wasix-runtime',
+    identity: null,
+    path: archive,
+    sha256: sha256Bytes(bytes),
+    bytes: bytes.length,
+  };
+  const frozenCompatibility = compatibility();
+  writeFileSync(
+    path.join(extensionRoot, 'extension-artifacts.json'),
+    `${JSON.stringify(
+      {
+        schema: 'oliphaunt-extension-ci-artifacts-v1',
+        product,
+        version,
+        compatibility: frozenCompatibility,
+        ...member,
+        assets: [asset],
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  writeFileSync(
+    path.join(releaseAssets, `${product}-${version}-manifest.json`),
+    `${JSON.stringify(
+      {
+        schema: 'oliphaunt-extension-release-manifest-v1',
+        product,
+        version,
+        versioning: 'upstream-bound',
+        compatibility: frozenCompatibility,
+        ...member,
+        assets: [asset],
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  return { extensionRoot, product, sqlName, version };
+}
+
+function bundleFixture(root, { cycle = false } = {}) {
+  const product = 'oliphaunt-extension-contrib-pg18';
+  const version = extensionReleaseVersion(product, 'wasix', 'extension-wasix-npm-packages.test');
+  const extensionRoot = path.join(root, product);
+  const releaseAssets = path.join(extensionRoot, 'release-assets');
+  const archiveRoot = `${product}-${version}-wasix-wasix-portable-bundle`;
+  const carrierName = `${archiveRoot}.tar.gz`;
+  const aggregateStage = path.join(root, 'aggregate-stage');
+  const members = [
+    inventory('cube', cycle ? ['earthdistance'] : []),
+    inventory('earthdistance', ['cube']),
+  ].map((member) => {
+    const bytes = portableExtensionBytes(root, member.sqlName);
+    const name = `${product}-${version}-wasix-portable.tar.zst`;
+    const memberPath = `extensions/${member.sqlName}/${name}`;
+    const file = path.join(aggregateStage, ...memberPath.split('/'));
+    mkdirSync(path.dirname(file), { recursive: true });
+    writeFileSync(file, bytes);
+    return {
+      ...member,
+      wasixInstall: wasixInstall(member.sqlName, member.dependencies),
+      assets: [
+        {
+          name,
+          family: 'wasix',
+          target: 'wasix-portable',
+          kind: 'wasix-runtime',
+          identity: null,
+          path: file,
+          sha256: sha256Bytes(bytes),
+          bytes: bytes.length,
+          carrierAsset: carrierName,
+          carrierRoot: archiveRoot,
+          memberPath,
+        },
+      ],
+    };
+  });
+  mkdirSync(releaseAssets, { recursive: true });
+  const carrier = path.join(releaseAssets, carrierName);
+  const carrierBytes = canonicalGzipSync(deterministicTar(aggregateStage, archiveRoot));
+  writeFileSync(carrier, carrierBytes);
+  const carrierRow = {
+    name: carrierName,
+    family: 'wasix',
+    target: 'wasix-portable',
+    kind: 'extension-bundle',
+    sha256: sha256Bytes(carrierBytes),
+    bytes: carrierBytes.length,
+    memberCount: members.length,
+  };
+  const frozenCompatibility = compatibility();
+  writeFileSync(
+    path.join(extensionRoot, 'extension-artifacts.json'),
+    `${JSON.stringify(
+      {
+        schema: 'oliphaunt-extension-ci-artifacts-v2',
+        product,
+        version,
+        compatibility: frozenCompatibility,
+        extensions: members,
+        carrierAssets: [carrierRow],
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  writeFileSync(
+    path.join(releaseAssets, `${product}-${version}-manifest.json`),
+    `${JSON.stringify(
+      {
+        schema: 'oliphaunt-extension-release-manifest-v2',
+        product,
+        version,
+        versioning: 'runtime-bound',
+        compatibility: frozenCompatibility,
+        extensions: members,
+        assets: [carrierRow],
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  return { extensionRoot, product, version };
+}
+
+function packedTarball(result) {
+  const tarballs = result.staged.filter((file) => file.endsWith('.tgz'));
+  expect(tarballs).toHaveLength(1);
+  return path.isAbsolute(tarballs[0]) ? tarballs[0] : path.join(ROOT, tarballs[0]);
+}
+
+function extractPackage(tarball, root) {
+  extractPortableArchiveTree(tarball, root);
+  return path.join(root, 'package');
+}
+async function inspectPackedDescriptor(entrypoint) {
+  if (hostFixtures) appendFileSync(path.join(hostFixtures, 'entrypoints'), entrypoint + '\n');
+  return inspectDescriptor(entrypoint);
+}
+test('derives one explicit WASIX npm identity without renaming the native/default package', async () => {
+  const product = 'oliphaunt-extension-pgtap';
+  expect(extensionNpmPackageForProduct(product)).toBe('@oliphaunt/extension-pgtap');
+  expect(extensionNpmWasixPackageForProduct(product)).toBe('@oliphaunt/extension-pgtap-wasix');
+  const identities = extensionRegistryPackageEntries({
+    product,
+    ...extensionRegistryPackageTargetSets(product, 'extension-wasix-npm-packages.test'),
+  })
+    .filter(({ kind }) => kind === 'npm')
+    .map(({ name }) => name);
+  expect(identities).toContain('@oliphaunt/extension-pgtap');
+  expect(identities).toContain('@oliphaunt/extension-pgtap-wasix');
+  expect(identities).not.toContain('@oliphaunt/extension-pgtap-native');
+});
+
+test('packs a host-neutral singleton descriptor that Node imports and verifies byte-for-byte', async () => {
+  const root = temporaryRoot('oliphaunt-wasix-npm-singleton-');
+  const fixture = singletonFixture(root);
+  const staging = path.join(root, 'staging');
+  const result = { staged: [], skipped: [] };
+  expect(stageExtensionWasixNpmPackages([fixture.extensionRoot], staging, result)).not.toBeNull();
+  expect(result.skipped).toEqual([]);
+
+  const unpacked = extractPackage(packedTarball(result), path.join(root, 'unpacked'));
+  const inspected = await inspectPackedDescriptor(path.join(unpacked, 'index.js'));
+  expect(inspected.frozen).toBe(true);
+  expect(inspected.descriptor).toMatchObject({
+    schema: 'oliphaunt-wasix-extension-v1',
+    runtime: 'wasix',
+    product: fixture.product,
+    version: fixture.version,
+    sqlName: fixture.sqlName,
+    compatibility: {
+      extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1',
+      postgresMajor: '18',
+      wasixRuntimeProduct: 'liboliphaunt-wasix',
+    },
+  });
+  expect(inspected.descriptor.carriers.map(({ sqlName }) => sqlName)).toEqual(['pgtap']);
+  expect(inspected.descriptor.carriers[0].source).toMatch(
+    /\/extensions\/pgtap\/extension[.]tar[.]zst$/u,
+  );
+  expect(inspected.descriptor.carriers[0].actualSize).toBeGreaterThan(0);
+  expect(inspected.descriptor.carriers[0].install).toMatchObject({
+    schema: 'oliphaunt-wasix-extension-install-v1',
+    dependencies: ['plpgsql'],
+    installedFiles: ['share/postgresql/extension/pgtap.control'],
+  });
+
+  const packageJson = JSON.parse(readFileSync(path.join(unpacked, 'package.json'), 'utf8'));
+  expect(packageJson.name).toBe('@oliphaunt/extension-pgtap-wasix');
+  expect(packageJson.version).toBe(fixture.version);
+  expect(packageJson.exports['.'].types).toBe('./index.d.ts');
+
+  const repeated = { staged: [], skipped: [] };
+  stageExtensionWasixNpmPackages(
+    [fixture.extensionRoot],
+    path.join(root, 'staging-repeated'),
+    repeated,
+  );
+  expect(readFileSync(packedTarball(repeated))).toEqual(readFileSync(packedTarball(result)));
+});
+
+test('stages one physical WASIX leaf across the complete native target set', async () => {
+  const root = temporaryRoot('oliphaunt-wasix-npm-target-set-');
+  const fixture = singletonFixture(root);
+  const targets = ['linux-arm64-gnu', 'linux-x64-gnu', 'macos-arm64', 'windows-x64-msvc'];
+  const result = { staged: [], skipped: [] };
+  const staged = stageExtensionNpmPackagesForTargets(
+    [fixture.extensionRoot],
+    path.join(root, 'staging'),
+    targets,
+    result,
+  );
+  expect(Object.keys(staged.nativeRoots)).toEqual(targets);
+  expect(Object.values(staged.nativeRoots).every((value) => value === null)).toBe(true);
+  expect(staged.wasixRoot).not.toBeNull();
+  expect(result.staged.filter((file) => file.endsWith('.tgz'))).toHaveLength(1);
+
+  const unpacked = extractPackage(packedTarball(result), path.join(root, 'unpacked'));
+  const packageJson = JSON.parse(readFileSync(path.join(unpacked, 'package.json'), 'utf8'));
+  expect(packageJson.name).toBe('@oliphaunt/extension-pgtap-wasix');
+});
+
+test('contrib subpath imports carry their exact transitive dependency closure', async () => {
+  const root = temporaryRoot('oliphaunt-wasix-npm-bundle-');
+  const fixture = bundleFixture(root);
+  const staging = path.join(root, 'staging');
+  const result = { staged: [], skipped: [] };
+  stageExtensionWasixNpmPackages([fixture.extensionRoot], staging, result);
+  const unpacked = extractPackage(packedTarball(result), path.join(root, 'unpacked'));
+
+  const earthdistance = (
+    await inspectPackedDescriptor(path.join(unpacked, 'descriptors', 'earthdistance.js'))
+  ).descriptor;
+  expect(earthdistance.sqlName).toBe('earthdistance');
+  expect(earthdistance.carriers.map(({ sqlName }) => sqlName)).toEqual(['cube', 'earthdistance']);
+  expect(earthdistance.carriers.every(({ actualSha256, sha256 }) => actualSha256 === sha256)).toBe(
+    true,
+  );
+
+  const cube = (await inspectPackedDescriptor(path.join(unpacked, 'descriptors', 'cube.js')))
+    .descriptor;
+  expect(cube.carriers.map(({ sqlName }) => sqlName)).toEqual(['cube']);
+  const packageJson = JSON.parse(readFileSync(path.join(unpacked, 'package.json'), 'utf8'));
+  expect(packageJson.exports['.']).toBeUndefined();
+  expect(Object.keys(packageJson.exports).sort()).toEqual([
+    './cube',
+    './earthdistance',
+    './package.json',
+  ]);
+  expect(packageJson.oliphaunt.memberExports).toEqual({
+    cube: './cube',
+    earthdistance: './earthdistance',
+  });
+});
+
+test('rejects a cyclic descriptor dependency without recursing indefinitely', async () => {
+  const root = temporaryRoot('oliphaunt-wasix-npm-cycle-');
+  const fixture = bundleFixture(root, { cycle: true });
+  expect(() =>
+    stageExtensionWasixNpmPackages([fixture.extensionRoot], path.join(root, 'staging'), {
+      staged: [],
+      skipped: [],
+    }),
+  ).toThrow(/dependency cycle/u);
+});
+
+test('fails closed instead of publishing an incomplete cross-product descriptor', async () => {
+  const root = temporaryRoot('oliphaunt-wasix-npm-cross-product-');
+  const fixture = singletonFixture(root, { dependencies: ['vector'] });
+  expect(() =>
+    stageExtensionWasixNpmPackages([fixture.extensionRoot], path.join(root, 'staging'), {
+      staged: [],
+      skipped: [],
+    }),
+  ).toThrow(/unsupported cross-product or unavailable WASIX dependency "vector"/u);
+});
diff --git a/src/extensions/artifacts/packages/tools/extension-wasix-npm-packages.test.sh b/src/extensions/artifacts/packages/tools/extension-wasix-npm-packages.test.sh
new file mode 100644
index 000000000..a7944afd6
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/extension-wasix-npm-packages.test.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+OLIPHAUNT_EXTENSION_NODE_FIXTURES="$scratch" bun test ./src/extensions/artifacts/packages/tools/extension-wasix-npm-packages.test.mts
+while IFS= read -r entrypoint; do
+  node src/extensions/artifacts/packages/tools/testdata/inspect-wasix-descriptor.mts "$entrypoint"
+done < "$scratch/entrypoints"
+echo 'Actual Node imports verify frozen descriptors and carrier bytes'
diff --git a/src/extensions/artifacts/packages/tools/native-extension-cargo-parts.test.mts b/src/extensions/artifacts/packages/tools/native-extension-cargo-parts.test.mts
new file mode 100644
index 000000000..5e7354107
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/native-extension-cargo-parts.test.mts
@@ -0,0 +1,65 @@
+import assert from 'node:assert/strict';
+import { randomBytes } from 'node:crypto';
+import {
+  mkdirSync,
+  mkdtempSync,
+  readdirSync,
+  readFileSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import {
+  fitCargoPayloadParts,
+  packageGeneratedCargoSource,
+} from '../../../../../tools/packaging/cargo-source-package.mts';
+import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts';
+import { buildNativeExtensionPartCrates } from './package-extension-release-carriers.mts';
+
+test('smaller native extension parts replace prior payloads and reconstruct every byte', () => {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-extension-parts-'));
+  try {
+    const payload = path.join(root, 'payload');
+    mkdirSync(payload);
+    const original = randomBytes(12 * 1024 * 1024);
+    writeFileSync(path.join(payload, 'module.so'), original);
+    const parts = fitCargoPayloadParts(
+      (partBytes) =>
+        buildNativeExtensionPartCrates(payload, path.join(root, 'sources'), {
+          product: 'oliphaunt-extension-vector',
+          version: '0.2.0',
+          members: ['vector'],
+          target: 'linux-x64-gnu',
+          partBytes,
+        }),
+      (directory) =>
+        packageGeneratedCargoSource(
+          path.join(directory, 'Cargo.toml'),
+          path.join(root, 'archives'),
+          {
+            packageSizeLimitBytes: Number.MAX_SAFE_INTEGER,
+          },
+        ),
+      16 * 1024 * 1024,
+    );
+    assert.equal(parts.length, 2);
+    const chunks = [];
+    for (const directory of parts) {
+      const archive = path.join(root, 'archives', path.basename(directory) + '-0.2.0.crate');
+      assert(statSync(archive).size <= 9 * 1024 * 1024);
+      const entries = readPortableArchiveEntries(archive);
+      const payloadEntries = [...entries.values()].filter(
+        (entry) => entry.type !== 'directory' && entry.name.includes('/payload/'),
+      );
+      assert.equal(payloadEntries.length, 1);
+      assert(payloadEntries[0].name.includes('/payload/chunks/module.so.part'));
+      chunks.push(payloadEntries[0].data());
+    }
+    assert.deepEqual(Buffer.concat(chunks), original);
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
diff --git a/src/extensions/artifacts/packages/tools/package-assembly.test.mts b/src/extensions/artifacts/packages/tools/package-assembly.test.mts
new file mode 100644
index 000000000..d5cfd91bc
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/package-assembly.test.mts
@@ -0,0 +1,109 @@
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { zstdCompressSync } from 'node:zlib';
+import { test } from 'bun:test';
+import { createDeterministicTar } from '../../../../../tools/packaging/cargo-source-package.mts';
+import { extensionSqlNames } from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  loadNativeComponentContract,
+  resolveNativeComponentClosure,
+} from '../../../tools/native-component-contract.mts';
+
+const CONTRIB_PRODUCT = 'oliphaunt-extension-contrib-pg18';
+if (process.argv[2] === 'prepare') {
+  const fixture = process.argv[3];
+  const nativeComponentContract = loadNativeComponentContract();
+  const assetRoot = path.join(fixture, 'assets');
+  const extensionRoot = path.join(assetRoot, 'extensions');
+  const metadataPath = path.join(fixture, 'extensions.json');
+  const manifestPath = path.join(fixture, 'manifest.json');
+  const outDir = path.join(fixture, 'out');
+  mkdirSync(extensionRoot, { recursive: true });
+
+  const sqlNames = extensionSqlNames(CONTRIB_PRODUCT, 'extension-package-assembly.test');
+  const builtExtensions = [];
+  const extensions = sqlNames.map((sqlName) => {
+    const componentClosure = resolveNativeComponentClosure(nativeComponentContract, {
+      extension: sqlName,
+      family: 'wasix',
+      kind: 'wasix-runtime',
+      target: 'wasix-portable',
+    });
+    const archive = `extensions/${sqlName}.tar.zst`;
+    const archiveRoot = path.join(fixture, 'archive-input', sqlName);
+    const controlPath = `share/postgresql/extension/${sqlName}.control`;
+    const controlFile = path.join(archiveRoot, ...controlPath.split('/'));
+    mkdirSync(path.dirname(controlFile), { recursive: true });
+    writeFileSync(controlFile, `default_version = '1.0'\n`);
+    const archiveBytes = zstdCompressSync(
+      createDeterministicTar(archiveRoot, '.', {
+        fail(message) {
+          throw new Error(message);
+        },
+        fixedFileMode: 0o644,
+      }),
+    );
+    writeFileSync(path.join(assetRoot, archive), archiveBytes);
+    const lifecycle = {
+      'create-extension': true,
+      'create-schema': null,
+      'load-sql': [],
+      'post-create-sql': [],
+      'startup-config': [],
+      'preload-required': false,
+      'restart-required': false,
+      'shared-memory-required': false,
+    };
+    builtExtensions.push({
+      name: sqlName,
+      'sql-name': sqlName,
+      archive,
+      sha256: createHash('sha256').update(archiveBytes).digest('hex'),
+      size: archiveBytes.length,
+      'native-module': null,
+      'native-modules': [],
+      'core-exports-required': [],
+      dependencies: [],
+      'load-order': [],
+      lifecycle,
+      'installed-files': [controlPath],
+      'unresolved-imports': [],
+    });
+    return {
+      'sql-name': sqlName,
+      archive,
+      dependencies: [],
+      'load-order': [],
+      lifecycle,
+      'native-module-file': null,
+      'native-support-modules': [],
+      'native-components': componentClosure.components,
+      'native-link-units': componentClosure.linkUnits,
+      'native-runtime-files': componentClosure.runtimeFiles,
+    };
+  });
+  writeFileSync(metadataPath, `${JSON.stringify({ extensions }, null, 2)}\n`);
+  writeFileSync(manifestPath, `${JSON.stringify({ extensions: builtExtensions }, null, 2)}\n`);
+
+  process.exit(0);
+}
+test('WASIX staging packages every selected contrib member under its artifact owner', () => {
+  const fixture = process.env.OLIPHAUNT_EXTENSION_ASSEMBLY_TEST_ROOT;
+  if (!fixture)
+    throw new Error('Run bash src/extensions/artifacts/packages/tools/package-assembly.test.sh');
+  const outDir = path.join(fixture, 'out');
+  const sqlNames = extensionSqlNames(CONTRIB_PRODUCT, 'package-assembly.test');
+  const staged = readdirSync(outDir).sort();
+  assert.equal(staged.length, sqlNames.length * 2 + 1);
+  const index = staged.find((entry) => entry.endsWith('-wasix-extension-assets.tsv'));
+  assert.ok(index);
+  const indexedSqlNames = readFileSync(path.join(outDir, index), 'utf8')
+    .trimEnd()
+    .split('\n')
+    .slice(1)
+    .map((line) => line.split('\t', 1)[0])
+    .sort();
+  assert.deepEqual(indexedSqlNames, sqlNames);
+});
diff --git a/src/extensions/artifacts/packages/tools/package-assembly.test.sh b/src/extensions/artifacts/packages/tools/package-assembly.test.sh
new file mode 100644
index 000000000..18d935783
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/package-assembly.test.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "$0")/../../../../.."
+if [[ "${1:-}" != --context ]]; then
+  exec bash tools/ci/with-projects.sh --exec bash src/extensions/artifacts/packages/tools/package-assembly.test.sh --context
+fi
+root="$PWD"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+mkdir -p "$scratch/repo/tools/dev" "$scratch/wasix"
+git -C "$scratch/repo" init -q
+cat > "$scratch/repo/tools/dev/bun.sh" <<'SH'
+#!/usr/bin/env bash
+set -euo pipefail
+printf '%s\n' "$*" >> "$OLIPHAUNT_TEST_CALLS_FILE"
+[[ "${OLIPHAUNT_TEST_FAIL_TOOL:-}" != "$1" ]] || exit 73
+SH
+chmod +x "$scratch/repo/tools/dev/bun.sh"
+export OLIPHAUNT_TEST_CALLS_FILE="$scratch/calls"
+producer=src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts
+validator=src/extensions/artifacts/packages/tools/check-carriers.mts
+release_script="$root/src/extensions/artifacts/packages/tools/package-release-assets.sh"
+mobile_script="$root/src/extensions/artifacts/packages/tools/package-mobile-release-assets.sh"
+run() {
+  : > "$OLIPHAUNT_TEST_CALLS_FILE"
+  (cd "$scratch/repo" && bash "$@") > "$scratch/output" 2>&1
+}
+reject() {
+  local status=0
+  run "$@" || status=$?
+  [[ "$status" != 0 ]] || { echo 'Invalid assembly succeeded' >&2; exit 1; }
+}
+OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS='oliphaunt-extension-postgis, oliphaunt-extension-vector' run "$release_script"
+grep -Fxq "$validator --require-full-extension-targets oliphaunt-extension-postgis oliphaunt-extension-vector" "$OLIPHAUNT_TEST_CALLS_FILE"
+run "$release_script"
+grep -Fxq "$validator --require-full-extension-targets all" "$OLIPHAUNT_TEST_CALLS_FILE"
+OLIPHAUNT_TEST_FAIL_TOOL="$producer" reject "$release_script"
+[[ "$(wc -l < "$OLIPHAUNT_TEST_CALLS_FILE")" -eq 1 ]]
+if grep -Fq "$validator" "$OLIPHAUNT_TEST_CALLS_FILE"; then
+  echo 'Validator ran after producer failure' >&2; exit 1
+fi
+OLIPHAUNT_TEST_FAIL_TOOL="$validator" reject "$release_script"
+grep -Fq "$producer" "$OLIPHAUNT_TEST_CALLS_FILE"
+OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS=oliphaunt-extension-contrib-pg18 \
+  OLIPHAUNT_EXTENSION_PACKAGE_NATIVE_TARGETS=android-arm64-v8a,ios-xcframework run "$mobile_script"
+grep -Fxq "$producer --output-root target/mobile-extension-artifacts --family native oliphaunt-extension-contrib-pg18 --require-native-target android-arm64-v8a --require-native-target ios-xcframework" "$OLIPHAUNT_TEST_CALLS_FILE"
+grep -Fxq "$validator --family native oliphaunt-extension-contrib-pg18" "$OLIPHAUNT_TEST_CALLS_FILE"
+OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS=', ,' OLIPHAUNT_EXTENSION_PACKAGE_NATIVE_TARGETS=android-arm64-v8a reject "$mobile_script"
+grep -Fq 'did not contain any products' "$scratch/output"
+OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS=oliphaunt-extension-postgis OLIPHAUNT_EXTENSION_PACKAGE_NATIVE_TARGETS=', ,' reject "$mobile_script"
+grep -Fq 'did not contain any targets' "$scratch/output"
+if grep -Fq 'unbound variable' "$scratch/output"; then
+  echo 'Invalid selection triggered an unbound variable' >&2; exit 1
+fi
+
+test_file=src/extensions/artifacts/packages/tools/package-assembly.test.mts
+bun "$test_file" prepare "$scratch/wasix"
+bun src/extensions/artifacts/wasix/tools/package-release-assets.mts \
+  --root "$root" --asset-root "$scratch/wasix/assets" --metadata "$scratch/wasix/extensions.json" \
+  --manifest "$scratch/wasix/manifest.json" --out-dir "$scratch/wasix/out" \
+  --target wasix-portable --extension-products oliphaunt-extension-contrib-pg18
+OLIPHAUNT_EXTENSION_ASSEMBLY_TEST_ROOT="$scratch/wasix" bun test "./$test_file"
diff --git a/src/extensions/artifacts/packages/tools/package-carriers.mts b/src/extensions/artifacts/packages/tools/package-carriers.mts
new file mode 100644
index 000000000..fefbfc209
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/package-carriers.mts
@@ -0,0 +1,157 @@
+#!/usr/bin/env bun
+import {
+  ROOT,
+  contribCarrierDescriptor,
+  extensionArtifactProductRoot,
+  extensionRegistryPackageTargetSets,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import path from 'node:path';
+import { TOOL, fail, isFile, rel } from '../../../../../tools/packaging/release-carrier.mts';
+import { checkExtensionProduct } from './check-carriers.mts';
+import { buildMavenArtifactManifest } from '../../../../../tools/packaging/build-maven-artifact-manifest.mts';
+import { stageMavenArtifactManifest } from '../../../../../tools/packaging/maven-artifact-staging.mts';
+import {
+  packageNativeExtensionCargoCrates,
+  stageExtensionNpmPackagesForTargets,
+} from './package-extension-release-carriers.mts';
+import { packageWasixCargoArtifacts } from '../../../../runtimes/liboliphaunt-wasix/tools/package_liboliphaunt_wasix_cargo_artifacts.mts';
+import { readFileSync } from 'node:fs';
+import { WASIX_CARGO_ARTIFACT_SCHEMA } from '../../../../runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts';
+import {
+  expectedWasixExtensionPackageInventory,
+  validateWasixExtensionArtifactInventory,
+} from '../../../../runtimes/liboliphaunt-wasix/tools/wasix-extension-cargo-artifact-inventory.mts';
+import { packageExtensionCargoFacades } from './package-extension-cargo-facades.mts';
+
+export function extensionPackageDir(product, family = 'native') {
+  return extensionArtifactProductRoot(
+    product,
+    family,
+    path.join(ROOT, 'target/extension-artifacts'),
+    TOOL,
+  );
+}
+
+function releaseSurfaceResult(surface) {
+  return { surface, staged: [], skipped: [] };
+}
+
+async function requireExtensionAssets(product) {
+  await checkExtensionProduct(product, { family: null, require: true, requireFullTargets: true });
+}
+
+async function packageExtensionMavenCarriers(product) {
+  const manifest = await buildMavenArtifactManifest(
+    `target/release/maven-manifests/${product}.tsv`,
+    {
+      extensions: true,
+      extensionProducts: [product],
+    },
+  );
+  await stageMavenArtifactManifest(
+    manifest,
+    path.join(ROOT, 'target/release/maven-staging', product),
+  );
+}
+
+export function packageExtensionNpmCarriers(product, { family = null } = {}) {
+  const roots = [extensionPackageDir(product, family ?? 'native')];
+  const targetSets = extensionRegistryPackageTargetSets(product, TOOL);
+  const targets = targetSets.npmTargets;
+  const result = releaseSurfaceResult(`${product}-npm${family === null ? '' : `-${family}`}`);
+  const staged = stageExtensionNpmPackagesForTargets(
+    roots,
+    path.join(ROOT, 'target/release/extension-carriers/npm', product, family ?? 'all'),
+    targets,
+    result,
+    { metaTargets: targets },
+  );
+  const missingNativeTargets =
+    family === 'wasix' ? [] : targets.filter((target) => staged.nativeRoots[target] === null);
+  const missingWasix =
+    family === 'native' ? false : targetSets.includeWasixNpm && staged.wasixRoot === null;
+  if (missingNativeTargets.length > 0 || missingWasix || result.staged.length === 0) {
+    fail(
+      `${product} npm carrier packaging failed: missing native targets=${missingNativeTargets.join(',') || 'none'}; ` +
+        `missing portable WASIX=${missingWasix ? 'yes' : 'no'}; ` +
+        `details=${result.skipped.join('; ') || 'none'}`,
+    );
+  }
+}
+
+function packageExtensionNativeCargoCarriers(product) {
+  for (const target of extensionRegistryPackageTargetSets(product, TOOL).nativeCargoTargets) {
+    const result = releaseSurfaceResult(`${product}-cargo-${target}`);
+    const crates = packageNativeExtensionCargoCrates(
+      [extensionPackageDir(product, 'native')],
+      path.join(ROOT, 'target/release/extension-carriers/cargo', product, `native-${target}`),
+      target,
+      true,
+      result,
+    );
+    if (crates.length === 0) {
+      fail(
+        `${product} native Cargo carrier packaging failed for ${target}: ${result.skipped.join('; ')}`,
+      );
+    }
+  }
+}
+
+function packageExtensionWasixCargoCarriers(product) {
+  const outputDir = path.join(ROOT, 'target/release/extension-carriers/cargo', product, 'wasix');
+  packageWasixCargoArtifacts([
+    '--extensions-only',
+    '--output-dir',
+    rel(outputDir),
+    '--extension-artifact-root',
+    rel(extensionPackageDir(product, 'wasix')),
+  ]);
+  const manifestPath = path.join(outputDir, 'packages.json');
+  if (!isFile(manifestPath)) {
+    fail(`${product} WASIX Cargo packaging did not generate ${rel(manifestPath)}`);
+  }
+  const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
+  if (manifest?.schema !== WASIX_CARGO_ARTIFACT_SCHEMA || !Array.isArray(manifest.packages)) {
+    fail(`${product} WASIX Cargo packaging generated an invalid package manifest`);
+  }
+  try {
+    validateWasixExtensionArtifactInventory(
+      manifest.packages,
+      expectedWasixExtensionPackageInventory(TOOL, [product]),
+    );
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+}
+
+function packageExtensionFacade(product) {
+  const packages = packageExtensionCargoFacades(
+    [product],
+    path.join(ROOT, 'target/release/extension-carriers/cargo', product, 'facade'),
+  );
+  if (packages.length !== 1 || packages[0].name !== product) {
+    fail(`${product} Cargo facade packaging did not generate its canonical package`);
+  }
+}
+
+export async function packageExtensionCarriers(product) {
+  await requireExtensionAssets(product);
+  await packageExtensionMavenCarriers(product);
+  packageExtensionNpmCarriers(product);
+  packageExtensionNativeCargoCarriers(product);
+  packageExtensionWasixCargoCarriers(product);
+  packageExtensionFacade(product);
+}
+
+export async function packageContribNativeCarriers() {
+  const product = contribCarrierDescriptor(TOOL).artifactProduct;
+  const manifest = path.join(extensionPackageDir(product, 'native'), 'extension-artifacts.json');
+  if (!isFile(manifest)) {
+    fail(`liboliphaunt-native requires staged contrib native artifacts at ${rel(manifest)}`);
+  }
+  packageExtensionNpmCarriers(product, { family: 'native' });
+  packageExtensionNativeCargoCarriers(product);
+  packageExtensionFacade(product);
+}
+
+if (import.meta.main) await packageExtensionCarriers(process.argv[2]);
diff --git a/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts
new file mode 100644
index 000000000..c7d2ab44f
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts
@@ -0,0 +1,239 @@
+import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import {
+  expectedExtensionAotTargets,
+  wasixExtensionAotPackageName,
+  wasixExtensionPackageName,
+} from '../../../../runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts';
+import { packageGeneratedCargoSource } from '../../../../../tools/packaging/cargo-source-package.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  releaseNoticeRows,
+  releaseProfilePackageLicense,
+  stageReleaseNotices,
+} from '../../../../../tools/packaging/release-notices.mts';
+import {
+  renderUnsupportedNativeTargetGuard,
+  rustNativeTargetCfg,
+} from '../../../../../tools/packaging/rust-native-targets.mts';
+import {
+  exactExtensionProducts,
+  extensionRegistryPackageTargetSets,
+  extensionReleaseProduct,
+  extensionReleaseVersion,
+  extensionSqlNames,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import { compareText, ROOT } from '../../../../../tools/release/release-graph.mts';
+import { nativeExtensionCargoPackageName } from './extension-registry-packages.mts';
+
+const FACADE_NOTICE_OPTIONS = Object.freeze({ profile: 'code-facade' });
+
+function fail(message) {
+  throw new Error(`package-extension-cargo-facades: ${message}`);
+}
+
+function dependencyFeature(name) {
+  return `dep:${name}`;
+}
+
+function facadeLinksName(product) {
+  return `oliphaunt_artifact_relay_extension_${product
+    .replace(/^oliphaunt-extension-/u, '')
+    .replaceAll('-', '_')}`;
+}
+
+const FACADE_BUILD_RS = `use std::collections::BTreeMap;
+use std::env;
+
+const PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_";
+const RELAY_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_RELAY_";
+const SUFFIX: &str = "_MANIFEST";
+
+fn main() {
+    let mut manifests = BTreeMap::new();
+    for (key, value) in env::vars() {
+        if value.is_empty() || key.starts_with(RELAY_PREFIX) {
+            continue;
+        }
+        let Some(stem) = key.strip_prefix(PREFIX).and_then(|value| value.strip_suffix(SUFFIX)) else {
+            continue;
+        };
+        if stem.is_empty() {
+            panic!("empty Oliphaunt artifact metadata stem");
+        }
+        if let Some(previous) = manifests.insert(stem.to_ascii_lowercase(), value.clone()) {
+            if previous != value {
+                panic!("conflicting Oliphaunt extension leaf manifests for {stem}");
+            }
+        }
+        println!("cargo::rerun-if-changed={value}");
+    }
+    if manifests.is_empty() && env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("extension facade resolved no target-leaf artifact manifest");
+    }
+    for (stem, manifest) in manifests {
+        println!("cargo::metadata={stem}_manifest={manifest}");
+    }
+}
+`;
+
+export function renderUnsupportedNativeGuard(product, nativeTargets, nativeCfgs) {
+  return renderUnsupportedNativeTargetGuard({
+    product,
+    nativeTargets,
+    nativeCfgs,
+    feature: 'native',
+    featureLabel: 'default native feature',
+    guidance:
+      'use a declared native target leaf, or depend on the WASIX carrier directly for WASIX builds.',
+  });
+}
+
+export function writeFacadeSource(product, outputRoot, { dependencyPaths = {} } = {}) {
+  if (!exactExtensionProducts('package-extension-cargo-facades').includes(product)) {
+    fail(`${product} is not an exact extension product`);
+  }
+  const nativeOwner = extensionReleaseProduct(product, 'native', 'package-extension-cargo-facades');
+  const wasixOwner = extensionReleaseProduct(product, 'wasix', 'package-extension-cargo-facades');
+  const nativeOnly = nativeOwner !== wasixOwner;
+  const version = extensionReleaseVersion(product, 'native', 'package-extension-cargo-facades');
+  const sqlNames = extensionSqlNames(product, 'package-extension-cargo-facades');
+  const targets = extensionRegistryPackageTargetSets(product, 'package-extension-cargo-facades');
+  const wasixAotTargets =
+    !nativeOnly && targets.includeWasixAot ? expectedExtensionAotTargets() : [];
+  const sourceDir = path.join(outputRoot, 'sources', product);
+  mkdirSync(path.join(sourceDir, 'src'), { recursive: true });
+
+  const nativeNames = targets.nativeCargoTargets.map((target) =>
+    nativeExtensionCargoPackageName(product, target),
+  );
+  const wasixName = nativeOnly ? null : wasixExtensionPackageName(product);
+  const aotNames = wasixAotTargets.map((target) => wasixExtensionAotPackageName(product, target));
+  const features = [
+    `default = ["native"]`,
+    `native = [${nativeNames.map((name) => JSON.stringify(dependencyFeature(name))).join(', ')}]`,
+    ...(wasixName === null ? [] : [`wasix = [${JSON.stringify(dependencyFeature(wasixName))}]`]),
+    ...aotNames.map(
+      (name, index) =>
+        `${JSON.stringify(`wasix-aot-${wasixAotTargets[index]}`)} = [${JSON.stringify(dependencyFeature(wasixName))}, ${JSON.stringify(dependencyFeature(name))}]`,
+    ),
+  ];
+  const targetDependencies = [];
+  const nativeCfgs = [];
+  for (const target of targets.nativeCargoTargets) {
+    const cfg = rustNativeTargetCfg(target);
+    const name = nativeExtensionCargoPackageName(product, target);
+    nativeCfgs.push(cfg);
+    targetDependencies.push(
+      `[target.'cfg(${cfg})'.dependencies]\n${name} = { version = "=${version}", optional = true${dependencyPaths[name] ? `, path = ${JSON.stringify(dependencyPaths[name])}` : ''} }`,
+    );
+  }
+  const optionalDependencies = [...(wasixName === null ? [] : [wasixName]), ...aotNames]
+    .map(
+      (name) =>
+        `${name} = { version = "=${version}", optional = true${dependencyPaths[name] ? `, path = ${JSON.stringify(dependencyPaths[name])}` : ''} }`,
+    )
+    .join('\n');
+  const unsupportedNativeGuard = renderUnsupportedNativeGuard(
+    product,
+    targets.nativeCargoTargets,
+    nativeCfgs,
+  );
+  const legalMembers = releaseNoticeRows(FACADE_NOTICE_OPTIONS).map((row) => row.member);
+  writeFileSync(
+    path.join(sourceDir, 'Cargo.toml'),
+    `[package]
+name = ${JSON.stringify(product)}
+version = ${JSON.stringify(version)}
+edition = "2024"
+rust-version = "1.93"
+description = ${JSON.stringify(`Target-selecting Cargo facade for ${sqlNames.length} Oliphaunt PostgreSQL extension member${sqlNames.length === 1 ? '' : 's'}.`)}
+readme = "README.md"
+repository = "https://github.com/f0rr0/oliphaunt"
+homepage = "https://oliphaunt.dev"
+license = ${JSON.stringify(releaseProfilePackageLicense('code-facade').spdx)}
+links = ${JSON.stringify(facadeLinksName(product))}
+build = "build.rs"
+include = ${JSON.stringify(['Cargo.toml', 'README.md', 'build.rs', 'src/**', ...legalMembers])}
+
+[lib]
+path = "src/lib.rs"
+
+[features]
+${features.join('\n')}
+
+[dependencies]
+${optionalDependencies}
+
+${targetDependencies.join('\n\n')}
+
+[workspace]
+`,
+  );
+  writeFileSync(path.join(sourceDir, 'build.rs'), FACADE_BUILD_RS);
+  writeFileSync(
+    path.join(sourceDir, 'README.md'),
+    `# ${product}
+
+Target-selecting Cargo facade for ${sqlNames.length === 1 ? `the \`${sqlNames[0]}\` PostgreSQL extension` : `the PostgreSQL 18 contrib bundle (${sqlNames.length} exact SQL members)`}.
+
+The default \`native\` feature selects the matching native artifact leaf.${
+      nativeOnly
+        ? ''
+        : ` Use
+\`default-features = false, features = ["wasix"]\` (or a host-specific
+\`wasix-aot-*\` feature) for WASIX artifacts.`
+    }
+`,
+  );
+  writeFileSync(
+    path.join(sourceDir, 'src/lib.rs'),
+    `#![forbid(unsafe_code)]
+
+${unsupportedNativeGuard}
+
+pub const PRODUCT: &str = ${JSON.stringify(product)};
+pub const VERSION: &str = env!("CARGO_PKG_VERSION");
+pub const EXTENSION_SQL_NAMES: &[&str] = &[${sqlNames.map((sqlName) => JSON.stringify(sqlName)).join(', ')}];
+${sqlNames.length === 1 ? `pub const EXTENSION_SQL_NAME: &str = ${JSON.stringify(sqlNames[0])};` : ''}
+`,
+  );
+  stageReleaseNotices(sourceDir, FACADE_NOTICE_OPTIONS);
+  assertReleaseNoticesInDirectory(sourceDir, FACADE_NOTICE_OPTIONS);
+  return { product, releaseProduct: nativeOwner, version, sourceDir };
+}
+
+export function packageExtensionCargoFacades(products, outputRoot) {
+  const selected = [...new Set(products)].sort(compareText);
+  if (selected.length !== products.length || selected.length === 0) {
+    fail('products must be a non-empty duplicate-free list');
+  }
+  rmSync(outputRoot, { recursive: true, force: true });
+  mkdirSync(path.join(outputRoot, 'crates'), { recursive: true });
+  const packages = [];
+  for (const product of selected) {
+    const source = writeFacadeSource(product, outputRoot);
+    const cratePath = packageGeneratedCargoSource(
+      path.join(source.sourceDir, 'Cargo.toml'),
+      path.join(outputRoot, 'crates'),
+      {
+        fail,
+        rel: String,
+      },
+    );
+    assertReleaseNoticesInArchive(cratePath, {
+      ...FACADE_NOTICE_OPTIONS,
+      prefix: path.basename(cratePath, '.crate'),
+    });
+    packages.push({
+      product,
+      name: product,
+      version: source.version,
+      cratePath,
+      manifestPath: path.join(source.sourceDir, 'Cargo.toml'),
+      kind: 'extension-facade',
+    });
+  }
+  return packages;
+}
diff --git a/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.mts b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.mts
new file mode 100644
index 000000000..b4dc1000e
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.mts
@@ -0,0 +1,294 @@
+import { afterEach, describe, expect, test } from 'bun:test';
+import { createHash } from 'node:crypto';
+import {
+  mkdirSync,
+  mkdtempSync,
+  readdirSync,
+  readFileSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import {
+  expectedExtensionAotTargets,
+  wasixExtensionAotPackageName,
+  wasixExtensionPackageName,
+} from '../../../../runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts';
+import {
+  currentProductVersionSync,
+  extensionRegistryPackageTargetSets,
+  extensionReleaseVersion,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import { nativeExtensionCargoPackageName } from './extension-registry-packages.mts';
+import {
+  packageExtensionCargoFacades,
+  renderUnsupportedNativeGuard,
+  writeFacadeSource,
+} from './package-extension-cargo-facades.mts';
+
+const directories = [];
+
+if (['prepare-compiler', 'verify-compiler'].includes(process.argv[2])) {
+  if (process.argv[2] === 'prepare-compiler') {
+    const root = process.argv[3];
+    const leaves = path.join(root, 'leaves');
+    const generated = path.join(root, 'generated');
+    mkdirSync(leaves, { recursive: true });
+    const host = process.argv[4];
+    expect(host).toMatch(/^[A-Za-z0-9_+.]+(?:-[A-Za-z0-9_+.]+){2,3}$/u);
+    const targetTriples = {
+      'linux-arm64-gnu': 'aarch64-unknown-linux-gnu',
+      'linux-x64-gnu': 'x86_64-unknown-linux-gnu',
+      'macos-arm64': 'aarch64-apple-darwin',
+      'windows-x64-msvc': 'x86_64-pc-windows-msvc',
+    };
+    const nativeRuntimeVersion = currentProductVersionSync(
+      'liboliphaunt-native',
+      'package-extension-cargo-facades.test',
+    );
+    const products = ['oliphaunt-extension-contrib-pg18', 'oliphaunt-extension-vector'];
+    const dependencyPaths = {};
+    for (const product of products) {
+      const productVersion = extensionReleaseVersion(
+        product,
+        'native',
+        'package-extension-cargo-facades.test',
+      );
+      const targets = extensionRegistryPackageTargetSets(product, 'extension-facade-integration');
+      const nativeNames = targets.nativeCargoTargets.map((target) => [
+        nativeExtensionCargoPackageName(product, target),
+        targetTriples[target],
+      ]);
+      const wasixNames =
+        product === 'oliphaunt-extension-contrib-pg18'
+          ? []
+          : [
+              [wasixExtensionPackageName(product), 'portable'],
+              ...expectedExtensionAotTargets().map((target) => [
+                wasixExtensionAotPackageName(product, target),
+                target,
+              ]),
+            ];
+      for (const [name, target] of [...nativeNames, ...wasixNames]) {
+        const bundled = product === 'oliphaunt-extension-contrib-pg18';
+        const members = bundled
+          ? ['cube', 'hstore', 'pg_trgm'].map((extension) => ({
+              extension,
+              dependencies: [],
+              files: [
+                {
+                  relative: `share/postgresql/extension/${extension}.control`,
+                  contents: `${extension} fixture`,
+                },
+              ],
+            }))
+          : [
+              {
+                files: [
+                  {
+                    relative: 'share/postgresql/extension/vector.control',
+                    contents: 'vector fixture',
+                  },
+                ],
+              },
+            ];
+        const header = bundled
+          ? `schema = "oliphaunt-artifact-manifest-v2"\nproduct = ${JSON.stringify(product)}\nversion = ${JSON.stringify(productVersion)}\nkind = "extension"\ntarget = ${JSON.stringify(target)}\nruntime-product = "liboliphaunt-native"\nruntime-version = ${JSON.stringify(nativeRuntimeVersion)}`
+          : `schema = "oliphaunt-artifact-manifest-v1"\nproduct = ${JSON.stringify(product)}\nversion = ${JSON.stringify(productVersion)}\nkind = "extension"\ntarget = ${JSON.stringify(target)}\nruntime-product = "liboliphaunt-native"\nruntime-version = ${JSON.stringify(nativeRuntimeVersion)}\nextension = "vector"\ndependencies = []`;
+        dependencyPaths[name] = fakeCarrier(leaves, {
+          name,
+          version: productVersion,
+          header,
+          members,
+        });
+      }
+      writeFacadeSource(product, generated, { dependencyPaths });
+    }
+
+    const genericCarrier = (name, product, version, kind, files) =>
+      fakeCarrier(leaves, {
+        name,
+        version,
+        header: `schema = "oliphaunt-artifact-manifest-v1"\nproduct = ${JSON.stringify(product)}\nversion = ${JSON.stringify(version)}\nkind = ${JSON.stringify(kind)}\ntarget = ${JSON.stringify(host)}`,
+        members: [
+          { files: files.map((relative) => ({ relative, contents: `${name}:${relative}` })) },
+        ],
+      });
+    const runtime = genericCarrier(
+      'fixture-native-runtime',
+      'liboliphaunt-native',
+      nativeRuntimeVersion,
+      'native-runtime',
+      ['runtime/bin/postgres', 'runtime/bin/initdb', 'runtime/bin/pg_ctl'],
+    );
+    const tools = genericCarrier(
+      'fixture-native-tools',
+      'oliphaunt-tools',
+      currentProductVersionSync('postgres-tools-native', 'package-extension-cargo-facades.test'),
+      'native-tools',
+      ['runtime/bin/pg_basebackup', 'runtime/bin/pg_dump', 'runtime/bin/psql'],
+    );
+    const broker = genericCarrier(
+      'fixture-broker',
+      'oliphaunt-broker',
+      currentProductVersionSync('oliphaunt-broker', 'package-extension-cargo-facades.test'),
+      'broker-helper',
+      ['bin/oliphaunt-broker'],
+    );
+    const app = path.join(root, 'app');
+    mkdirSync(path.join(app, 'src'), { recursive: true });
+    writeFileSync(path.join(app, 'src/lib.rs'), '#![forbid(unsafe_code)]\n');
+    writeFileSync(path.join(app, 'build.rs'), 'fn main() { oliphaunt_build::configure(); }\n');
+    writeFileSync(
+      path.join(app, 'Cargo.toml'),
+      `[package]
+name = "facade-app"
+version = "0.0.0"
+edition = "2024"
+build = "build.rs"
+
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = ${JSON.stringify(nativeRuntimeVersion)}
+extensions = ["cube", "pg_trgm", "vector"]
+
+[dependencies]
+contrib = { package = "oliphaunt-extension-contrib-pg18", path = ${JSON.stringify(path.join(generated, 'sources/oliphaunt-extension-contrib-pg18'))} }
+vector = { package = "oliphaunt-extension-vector", path = ${JSON.stringify(path.join(generated, 'sources/oliphaunt-extension-vector'))} }
+fixture-native-runtime = { path = ${JSON.stringify(runtime)} }
+fixture-native-tools = { path = ${JSON.stringify(tools)} }
+fixture-broker = { path = ${JSON.stringify(broker)} }
+
+[build-dependencies]
+oliphaunt-build = { path = ${JSON.stringify(path.resolve(import.meta.dir, '../../../../sdks/rust/sdk/crates/oliphaunt-build'))} }
+
+[workspace]
+`,
+    );
+
+    const output = root;
+    const forcedUnsupportedSource = path.join(output, 'forced-unsupported.rs');
+    writeFileSync(
+      forcedUnsupportedSource,
+      `#![forbid(unsafe_code)]
+${renderUnsupportedNativeGuard('fixture-extension', ['fixture-unsupported'], ['any()'])}
+pub const FIXTURE: bool = true;
+`,
+    );
+  } else {
+    const root = process.argv[3];
+    const lock = findFile(path.join(root, 'cargo-target'), 'oliphaunt-assets.lock');
+    expect(lock).not.toBeNull();
+    const text = readFileSync(lock, 'utf8');
+    expect(text).toContain('extension = "cube"');
+    expect(text).toContain('extension = "pg_trgm"');
+    expect(text).toContain('extension = "vector"');
+    expect(text).not.toContain('extension = "hstore"');
+  }
+  process.exit(0);
+}
+afterEach(() => {
+  while (directories.length > 0) rmSync(directories.pop(), { recursive: true, force: true });
+});
+
+function sha256(value) {
+  return createHash('sha256').update(value).digest('hex');
+}
+
+function fakeCarrier(root, { name, version, header, members }) {
+  const directory = path.join(root, name);
+  mkdirSync(path.join(directory, 'src'), { recursive: true });
+  const links = `oliphaunt_artifact_fixture_${name.replaceAll('-', '_')}`;
+  writeFileSync(
+    path.join(directory, 'Cargo.toml'),
+    `[package]
+name = ${JSON.stringify(name)}
+version = ${JSON.stringify(version)}
+edition = "2024"
+links = ${JSON.stringify(links)}
+build = "build.rs"
+
+[lib]
+path = "src/lib.rs"
+
+[workspace]
+`,
+  );
+  writeFileSync(path.join(directory, 'src/lib.rs'), '#![forbid(unsafe_code)]\n');
+  const lines = [
+    'use std::env;',
+    'use std::fs;',
+    'use std::path::PathBuf;',
+    'fn main() {',
+    '  let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR"));',
+    `  let mut manifest = ${JSON.stringify(`${header}\n`)}.to_owned();`,
+  ];
+  for (const [memberIndex, member] of members.entries()) {
+    if (member.extension !== undefined) {
+      lines.push(
+        `  manifest.push_str(${JSON.stringify(`\n[[extensions]]\nextension = ${JSON.stringify(member.extension)}\ndependencies = ${JSON.stringify(member.dependencies ?? [])}\n`)});`,
+      );
+    }
+    for (const [fileIndex, file] of member.files.entries()) {
+      const variable = `file_${memberIndex}_${fileIndex}`;
+      lines.push(
+        `  let ${variable} = out.join(${JSON.stringify(`payload/${member.extension ?? 'root'}/${file.relative}`)});`,
+        `  fs::create_dir_all(${variable}.parent().expect("parent")).expect("mkdir");`,
+        `  fs::write(&${variable}, ${JSON.stringify(file.contents)}).expect("write payload");`,
+        `  manifest.push_str(&format!(${JSON.stringify(`\n${member.extension === undefined ? '[[files]]' : '[[extensions.files]]'}\nsource = {:?}\nrelative = ${JSON.stringify(file.relative)}\nsha256 = ${JSON.stringify(sha256(file.contents))}\nexecutable = false\n`)}, ${variable}.display().to_string()));`,
+      );
+    }
+  }
+  lines.push(
+    '  let path = out.join("oliphaunt-artifact.toml");',
+    '  fs::write(&path, manifest).expect("write manifest");',
+    '  println!("cargo::metadata=manifest={}", path.display());',
+    '}',
+  );
+  writeFileSync(path.join(directory, 'build.rs'), `${lines.join('\n')}\n`);
+  return directory;
+}
+
+function findFile(root, basename) {
+  for (const entry of readdirSync(root)) {
+    const candidate = path.join(root, entry);
+    if (statSync(candidate).isDirectory()) {
+      const found = findFile(candidate, basename);
+      if (found !== null) return found;
+    } else if (entry === basename) {
+      return candidate;
+    }
+  }
+  return null;
+}
+
+describe('exact extension Cargo facade', () => {
+  test('packages explicit native and WASIX feature selections', () => {
+    const output = mkdtempSync(path.join(tmpdir(), 'extension-facade-test-'));
+    directories.push(output);
+    const [pkg] = packageExtensionCargoFacades(['oliphaunt-extension-pgtap'], output);
+    const manifest = Bun.TOML.parse(readFileSync(pkg.manifestPath, 'utf8'));
+    expect(manifest.features.default).toEqual(['native']);
+    expect(manifest.features.wasix).toEqual([`dep:oliphaunt-extension-pgtap-wasix`]);
+    expect(pkg.cratePath.endsWith('.crate')).toBe(true);
+  });
+
+  test('the native-owned contrib facade has no WASIX carrier dependency', () => {
+    const output = mkdtempSync(path.join(tmpdir(), 'extension-facade-bundle-test-'));
+    directories.push(output);
+    const [pkg] = packageExtensionCargoFacades(['oliphaunt-extension-contrib-pg18'], output);
+    const manifest = Bun.TOML.parse(readFileSync(pkg.manifestPath, 'utf8'));
+    expect(manifest.package.version).toBe(
+      extensionReleaseVersion(
+        'oliphaunt-extension-contrib-pg18',
+        'native',
+        'package-extension-cargo-facades.test',
+      ),
+    );
+    expect(manifest.features.default).toEqual(['native']);
+    expect(manifest.features.wasix).toBeUndefined();
+    expect(Object.keys(manifest.dependencies ?? {})).toHaveLength(0);
+  });
+});
diff --git a/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.sh b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.sh
new file mode 100644
index 000000000..18404a332
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+bun test ./src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.mts
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+host="$(rustc -vV | sed -n 's/^host: //p')"
+fixture=src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.mts
+bun "$fixture" prepare-compiler "$scratch" "$host"
+if rustc --crate-name fixture_extension --crate-type lib --edition 2024 --cfg 'feature="native"' "$scratch/forced-unsupported.rs" --out-dir "$scratch" > "$scratch/unsupported.log" 2>&1; then
+  echo 'Unsupported native target unexpectedly compiled' >&2
+  exit 1
+fi
+grep -q 'default native feature supports only' "$scratch/unsupported.log"
+rustc --crate-name fixture_extension --crate-type lib --edition 2024 --cfg 'feature="wasix"' --emit metadata -o "$scratch/wasix.rmeta" "$scratch/forced-unsupported.rs"
+OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD=1 cargo check --manifest-path "$scratch/app/Cargo.toml" --target-dir "$scratch/cargo-target"
+bun "$fixture" verify-compiler "$scratch"
+echo 'Compiled facade target selection and exact selected Cargo payload propagation passed'
diff --git a/src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts b/src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts
new file mode 100644
index 000000000..a2d657274
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts
@@ -0,0 +1,2993 @@
+#!/usr/bin/env bun
+import { createHash } from 'node:crypto';
+import {
+  chmodSync,
+  closeSync,
+  copyFileSync,
+  cpSync,
+  existsSync,
+  lstatSync,
+  mkdirSync,
+  mkdtempSync,
+  openSync,
+  readdirSync,
+  readFileSync,
+  readSync,
+  realpathSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { extensionRuntimeAssetContract } from './extension-runtime-asset-contract.mts';
+import { RUST_BUILD_SCRIPT_SHA256 } from '../../../../../tools/packaging/rust-build-script-sha256.mts';
+import { CORE_RUNTIME_ARCHIVE_FILES } from '../../../../runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts';
+import { parseNpmExtensionLicenseFiles } from '../../../../sdks/ts/sdk/src/native/extension-contract.ts';
+import {
+  fitCargoPayloadParts,
+  packageGeneratedCargoSource,
+  readCargoPackageNameVersion,
+} from '../../../../../tools/packaging/cargo-source-package.mts';
+import {
+  buildIosCarrierManifest,
+  IOS_CARRIER_FILENAME,
+} from '../../../../sdks/swift/tools/ios-carrier-manifest.mts';
+import { packGeneratedNpmCarrier } from '../../../../../tools/packaging/npm-package.mts';
+import { NPM_TRUSTED_PUBLISHING_REPOSITORY } from '../../../../../tools/packaging/npm-trusted-publishing.mts';
+import {
+  readPortableArchiveEntries,
+  readPortableTarZstdBufferEntries,
+} from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  releaseNoticeRows,
+  stageReleaseNotices,
+} from '../../../../../tools/packaging/release-notices.mts';
+import {
+  assertWasixExtensionArchiveInstall,
+  assertWasixExtensionInstall,
+  assertWasixExtensionMemberInstall,
+  EXTENSION_RUNTIME_CONTRACT_PATH,
+  EXTENSION_RUNTIME_CONTRACT_SCHEMA,
+  WASIX_EXTENSION_INSTALL_SCHEMA,
+  WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA,
+} from '../../../contracts/wasix-extension-install.mts';
+import {
+  compareText,
+  extensionRegistryPackageTargetSets,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  assertExtensionUpstreamLicensesInArchive,
+  assertExtensionUpstreamLicensesInDirectory,
+  extensionCarrierLegalContract,
+  extensionUpstreamLicenseFileInventory,
+  stageExtensionUpstreamLicenses,
+} from '../../../tools/extension-upstream-licenses.mts';
+import { validateExtensionArtifactArchive } from './extension-artifact-inventory.mts';
+import {
+  extensionNpmPackageForProduct,
+  extensionNpmTargetPackageForProduct,
+  extensionNpmWasixPackageForProduct,
+  nativeExtensionCargoLinksName,
+  nativeExtensionCargoPackageName,
+  nativeExtensionCargoPartPackageName,
+} from './extension-registry-packages.mts';
+
+const ROOT = path.resolve(import.meta.dirname, '../../../../..');
+const TOOL = 'package-extension-release-carriers.mts';
+// npm does not impose crates.io's 10 MiB package limit. Keep one deliberately
+// generous guard against accidentally publishing an unbounded staging tree,
+// but never manufacture package identities merely to satisfy a repository-
+// local threshold.
+const NPM_PACKAGE_SAFETY_LIMIT_BYTES = 100 * 1024 * 1024;
+const CARGO_PACKAGE_SIZE_LIMIT_BYTES = 10 * 1024 * 1024;
+const CARGO_EXTENSION_SPLIT_THRESHOLD_BYTES = 9 * 1024 * 1024;
+const NPM_EXTENSION_CONTRACT_FILENAME = 'extension-contract.json';
+
+function fail(tool, message) {
+  throw new Error(`${tool}: ${message}`);
+}
+
+export function canonicalExtensionNpmTargets(product) {
+  return extensionRegistryPackageTargetSets(product, TOOL).npmTargets;
+}
+
+function rel(file) {
+  const relative = path.relative(ROOT, file);
+  return relative && !relative.startsWith('..') && !path.isAbsolute(relative)
+    ? relative.split(path.sep).join('/')
+    : file.split(path.sep).join('/');
+}
+
+function walkFiles(root) {
+  const files = [];
+  const visit = (current) => {
+    const entries = readdirSync(current, { withFileTypes: true }).sort((left, right) =>
+      compareText(left.name, right.name),
+    );
+    for (const entry of entries) {
+      const entryPath = path.join(current, entry.name);
+      if (entry.isDirectory()) {
+        visit(entryPath);
+      } else if (entry.isFile()) {
+        files.push(entryPath);
+      }
+    }
+  };
+  visit(root);
+  return files;
+}
+
+function isFile(file) {
+  try {
+    return statSync(file).isFile();
+  } catch {
+    return false;
+  }
+}
+
+function isDirectory(file) {
+  try {
+    return statSync(file).isDirectory();
+  } catch {
+    return false;
+  }
+}
+
+function safeNpmPackageFilenamePrefix(packageName) {
+  return packageName.replace(/^@/u, '').replaceAll('/', '-');
+}
+
+function readJsonFile(file) {
+  try {
+    return JSON.parse(readFileSync(file, 'utf8'));
+  } catch (error) {
+    fail(TOOL, `${rel(file)} is not valid JSON: ${error.message}`);
+  }
+}
+
+function extensionManifestIdentity(manifest) {
+  let data;
+  try {
+    data = JSON.parse(readFileSync(manifest, 'utf8'));
+  } catch {
+    return ['path', realpathSync(manifest)];
+  }
+  const { product, version, sqlName } = data;
+  if ([product, version, sqlName].every((value) => typeof value === 'string' && value.length > 0)) {
+    return ['extension', product, version, sqlName];
+  }
+  return ['path', realpathSync(manifest)];
+}
+
+function extensionManifestCandidates(root) {
+  if (!existsSync(root)) return [];
+  const metadata = lstatSync(root);
+  if (metadata.isSymbolicLink()) {
+    fail(TOOL, `extension manifest input must not be a symbolic link or junction: ${rel(root)}`);
+  }
+  if (metadata.isFile() && path.basename(root) === 'extension-artifacts.json') return [root];
+  if (metadata.isFile()) return [];
+  if (!metadata.isDirectory()) {
+    fail(TOOL, `extension manifest input has an unsupported filesystem type: ${rel(root)}`);
+  }
+  // Bun.Glob opens its cwd with a Windows access mask that is rejected by the
+  // deliberately read-only standard-user release token. The Node-compatible
+  // directory APIs use the narrower list/read contract already proven by the
+  // launcher. Keep this traversal explicit so a symlink, Windows junction, or
+  // special entry cannot be silently skipped while constructing release input.
+  const manifests = [];
+  const visit = (directory) => {
+    const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) =>
+      compareText(left.name, right.name),
+    );
+    for (const entry of entries) {
+      const candidate = path.join(directory, entry.name);
+      const candidateMetadata = lstatSync(candidate);
+      if (candidateMetadata.isSymbolicLink()) {
+        fail(
+          TOOL,
+          `extension manifest input must not contain a symbolic link or junction: ${rel(candidate)}`,
+        );
+      }
+      if (candidateMetadata.isDirectory()) {
+        visit(candidate);
+      } else if (candidateMetadata.isFile()) {
+        if (entry.name === 'extension-artifacts.json') manifests.push(candidate);
+      } else {
+        fail(
+          TOOL,
+          `extension manifest input contains an unsupported filesystem entry: ${rel(candidate)}`,
+        );
+      }
+    }
+  };
+  visit(root);
+  return manifests;
+}
+
+export function discoverExtensionManifests(roots) {
+  const manifests = new Map();
+  const seenPaths = new Set();
+  for (const root of roots) {
+    for (const manifest of extensionManifestCandidates(root)) {
+      const resolved = realpathSync(manifest);
+      if (seenPaths.has(resolved)) continue;
+      seenPaths.add(resolved);
+      const identity = JSON.stringify(extensionManifestIdentity(manifest));
+      if (!manifests.has(identity)) manifests.set(identity, manifest);
+    }
+  }
+  return [...manifests.values()];
+}
+
+function archiveTempDir() {
+  const root = path.join(ROOT, 'target', 'extension-carrier-archive-extract');
+  mkdirSync(root, { recursive: true });
+  return mkdtempSync(path.join(root, 'extract-'));
+}
+
+function cargoTargetTriple(targetId) {
+  if (targetId === 'linux-x64-gnu') return 'x86_64-unknown-linux-gnu';
+  if (targetId === 'linux-arm64-gnu') return 'aarch64-unknown-linux-gnu';
+  if (targetId === 'macos-arm64') return 'aarch64-apple-darwin';
+  if (targetId === 'windows-x64-msvc') return 'x86_64-pc-windows-msvc';
+  return null;
+}
+
+function rustCrateIdent(crateName) {
+  return crateName.replaceAll('-', '_');
+}
+
+function tomlString(value) {
+  return JSON.stringify(value);
+}
+
+function localFail(message) {
+  fail(TOOL, message);
+}
+
+export function nativeExtensionCarrierLegal(product, members, { target = null, carriesPayload }) {
+  if (
+    typeof product !== 'string' ||
+    !Array.isArray(members) ||
+    members.length === 0 ||
+    members.some((member) => typeof member !== 'string' || !member) ||
+    new Set(members).size !== members.length ||
+    typeof carriesPayload !== 'boolean'
+  ) {
+    throw new Error(
+      `${TOOL}: native extension carrier legal lookup requires a product, unique members, and carriesPayload`,
+    );
+  }
+  try {
+    return extensionCarrierLegalContract(product, members, {
+      family: 'native',
+      target,
+      carriesPayload,
+    });
+  } catch (cause) {
+    throw new Error(
+      `${TOOL}: cannot derive the canonical native extension carrier legal contract: ${cause.message}`,
+      { cause },
+    );
+  }
+}
+
+export function wasixExtensionCarrierLegal(product, members) {
+  if (
+    typeof product !== 'string' ||
+    !Array.isArray(members) ||
+    members.length === 0 ||
+    members.some((member) => typeof member !== 'string' || !member) ||
+    new Set(members).size !== members.length
+  ) {
+    throw new Error(
+      `${TOOL}: WASIX extension carrier legal lookup requires a product and unique members`,
+    );
+  }
+  try {
+    return extensionCarrierLegalContract(product, members, {
+      family: 'wasix',
+      target: WASIX_PORTABLE_TARGET,
+      carriesPayload: true,
+    });
+  } catch (cause) {
+    throw new Error(
+      `${TOOL}: cannot derive the canonical WASIX extension carrier legal contract: ${cause.message}`,
+      { cause },
+    );
+  }
+}
+
+function carrierLegalMembers(legal) {
+  return [
+    ...releaseNoticeRows({ profile: legal.profile }).map((row) => row.member),
+    ...(legal.upstreamMembers.length > 0 ? ['share/licenses/**'] : []),
+  ];
+}
+
+function stageExtensionCarrierLegal(directory, legal) {
+  stageReleaseNotices(directory, { profile: legal.profile });
+  const upstreamRoot = path.join(directory, 'share/licenses');
+  if (legal.upstreamMembers.length > 0) {
+    for (const sqlName of legal.upstreamMembers) {
+      stageExtensionUpstreamLicenses(sqlName, directory);
+    }
+    assertExtensionUpstreamLicensesInDirectory(legal.upstreamMembers, directory);
+  } else if (existsSync(upstreamRoot)) {
+    const stat = lstatSync(upstreamRoot);
+    if (!stat.isDirectory() || stat.isSymbolicLink()) {
+      fail(TOOL, `stale upstream license root must be a real directory: ${rel(upstreamRoot)}`);
+    }
+    rmSync(upstreamRoot, { recursive: true });
+  }
+  assertReleaseNoticesInDirectory(directory, { profile: legal.profile });
+}
+
+function assertExtensionCarrierArchive(archive, legal, prefix) {
+  assertReleaseNoticesInArchive(archive, { profile: legal.profile, prefix });
+  if (legal.upstreamMembers.length > 0) {
+    assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, archive, { prefix });
+  }
+}
+
+function assertNpmExtensionRuntimeLegalArchive(
+  archive,
+  { product, members, target, bundle, memberRuntimeRelativePaths },
+) {
+  for (const sqlName of members) {
+    const legal = nativeExtensionCarrierLegal(product, [sqlName], {
+      carriesPayload: true,
+      target,
+    });
+    if (legal.upstreamMembers.length === 0) continue;
+    const runtimeRelativePath = bundle ? memberRuntimeRelativePaths?.[sqlName] : 'runtime';
+    if (typeof runtimeRelativePath !== 'string' || runtimeRelativePath.length === 0) {
+      fail(TOOL, `${product} ${target} is missing the runtime path for legal member ${sqlName}`);
+    }
+    assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, archive, {
+      prefix: `package/${runtimeRelativePath}`,
+    });
+  }
+}
+
+function sha256File(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function npmPlatformConstraints(target) {
+  if (target === 'linux-x64-gnu') {
+    return { os: ['linux'], cpu: ['x64'], libc: ['glibc'] };
+  }
+  if (target === 'linux-arm64-gnu') {
+    return { os: ['linux'], cpu: ['arm64'], libc: ['glibc'] };
+  }
+  if (target === 'macos-arm64') {
+    return { os: ['darwin'], cpu: ['arm64'] };
+  }
+  if (target === 'windows-x64-msvc') {
+    return { os: ['win32'], cpu: ['x64'] };
+  }
+  return {};
+}
+
+function writeJsonFile(file, value) {
+  writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
+}
+
+export function renderNpmExtensionBundleManifest({ product, version, target, members }) {
+  return {
+    schema: 'oliphaunt-npm-extension-bundle-v1',
+    product,
+    version,
+    family: 'native',
+    target,
+    members,
+  };
+}
+
+export function npmExtensionMemberContract(product, version, target, member) {
+  const inventory = frozenExtensionMemberInventory(member, { product, version });
+  const legal = nativeExtensionCarrierLegal(product, [inventory.sqlName], {
+    target,
+    carriesPayload: true,
+  });
+  const licenseFiles = Object.freeze(
+    parseNpmExtensionLicenseFiles(
+      legal.upstreamMembers.length === 0
+        ? []
+        : extensionUpstreamLicenseFileInventory([inventory.sqlName]),
+      `${product}@${version}/${inventory.sqlName} npm extension licenseFiles`,
+    ).map((file) => Object.freeze(file)),
+  );
+  if (
+    JSON.stringify(licenseFiles.map(({ path: file }) => file)) !==
+    JSON.stringify([...legal.licenseFiles])
+  ) {
+    fail(
+      TOOL,
+      `${product}@${version}/${inventory.sqlName} license file integrity rows disagree with the canonical carrier legal contract`,
+    );
+  }
+  if (
+    Object.hasOwn(member, 'licenseFiles') &&
+    JSON.stringify(member.licenseFiles) !== JSON.stringify(licenseFiles)
+  ) {
+    fail(
+      TOOL,
+      `${product}@${version}/${inventory.sqlName} supplied licenseFiles disagree with the canonical carrier legal contract`,
+    );
+  }
+  return Object.freeze({ ...inventory, licenseFiles });
+}
+
+export function renderNpmExtensionContractManifest({ product, version, target, members }) {
+  return {
+    schema: 'oliphaunt-npm-extension-contract-v1',
+    product,
+    version,
+    family: 'native',
+    target,
+    members: members.map((member) => npmExtensionMemberContract(product, version, target, member)),
+  };
+}
+
+function extensionReleaseManifest(extensionDir, product, version) {
+  const manifestPath = path.join(
+    extensionDir,
+    'release-assets',
+    `${product}-${version}-manifest.json`,
+  );
+  return isFile(manifestPath) ? readJsonFile(manifestPath) : {};
+}
+
+export function extensionManifestMembers(manifest) {
+  if (manifest?.schema === 'oliphaunt-extension-ci-artifacts-v1') {
+    return typeof manifest.sqlName === 'string' && manifest.sqlName ? [manifest] : [];
+  }
+  if (manifest?.schema === 'oliphaunt-extension-ci-artifacts-v2') {
+    return Array.isArray(manifest.extensions) ? manifest.extensions : [];
+  }
+  return [];
+}
+
+const FROZEN_EXTENSION_INVENTORY_LIST_FIELDS = Object.freeze([
+  'dependencies',
+  'dataFiles',
+  'extensionSqlFileNames',
+  'extensionSqlFilePrefixes',
+  'sharedPreloadLibraries',
+]);
+
+/**
+ * Return the exact desktop inventory frozen into one product/member release row.
+ *
+ * Registry materialization deliberately does not consult the repository-wide
+ * generated SDK catalog: independently versioned external products must remain
+ * bound to the metadata that was qualified and versioned with that product.
+ */
+export function frozenExtensionMemberInventory(member, { product, version } = {}) {
+  const owner = [product, version].every((value) => typeof value === 'string' && value.length > 0)
+    ? `${product}@${version}`
+    : 'extension release';
+  const sqlName = member?.sqlName;
+  if (typeof sqlName !== 'string' || sqlName.length === 0) {
+    throw new Error(`${TOOL}: ${owner} has an invalid frozen extension sqlName`);
+  }
+  if (typeof member.createsExtension !== 'boolean') {
+    throw new Error(`${TOOL}: ${owner}/${sqlName} must freeze createsExtension as a boolean`);
+  }
+  if (
+    member.nativeModuleStem !== null &&
+    (typeof member.nativeModuleStem !== 'string' || member.nativeModuleStem.length === 0)
+  ) {
+    throw new Error(
+      `${TOOL}: ${owner}/${sqlName} must freeze nativeModuleStem as null or a non-empty string`,
+    );
+  }
+  const inventory = {
+    sqlName,
+    createsExtension: member.createsExtension,
+    nativeModuleStem: member.nativeModuleStem,
+  };
+  for (const field of FROZEN_EXTENSION_INVENTORY_LIST_FIELDS) {
+    const values = member[field];
+    if (
+      !Array.isArray(values) ||
+      values.some((value) => typeof value !== 'string' || value.length === 0)
+    ) {
+      throw new Error(`${TOOL}: ${owner}/${sqlName} must freeze ${field} as a string array`);
+    }
+    const canonical = [...new Set(values)].sort(compareText);
+    if (JSON.stringify(values) !== JSON.stringify(canonical)) {
+      throw new Error(`${TOOL}: ${owner}/${sqlName} frozen ${field} must be sorted and unique`);
+    }
+    inventory[field] = canonical;
+  }
+  if (inventory.dependencies.includes(sqlName)) {
+    throw new Error(`${TOOL}: ${owner}/${sqlName} frozen dependencies must exclude itself`);
+  }
+  return Object.freeze(inventory);
+}
+
+const FROZEN_EXTENSION_COMPATIBILITY_FIELDS = Object.freeze([
+  'extensionRuntimeContract',
+  'nativeRuntimeProduct',
+  'nativeRuntimeVersion',
+  'postgresMajor',
+  'wasixRuntimeProduct',
+  'wasixRuntimeVersion',
+]);
+
+function frozenExtensionCompatibility(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    throw new Error(`${TOOL}: ${label} must freeze extension compatibility as an object`);
+  }
+  const keys = Object.keys(value).sort(compareText);
+  if (
+    JSON.stringify(keys) !==
+    JSON.stringify([...FROZEN_EXTENSION_COMPATIBILITY_FIELDS].sort(compareText))
+  ) {
+    throw new Error(`${TOOL}: ${label} must freeze the exact extension compatibility fields`);
+  }
+  if (
+    value.postgresMajor !== '18' ||
+    value.nativeRuntimeProduct !== 'liboliphaunt-native' ||
+    value.wasixRuntimeProduct !== 'liboliphaunt-wasix' ||
+    value.extensionRuntimeContract !== EXTENSION_RUNTIME_CONTRACT_PATH ||
+    !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(
+      value.nativeRuntimeVersion ?? '',
+    ) ||
+    !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(
+      value.wasixRuntimeVersion ?? '',
+    )
+  ) {
+    throw new Error(`${TOOL}: ${label} contains invalid frozen extension compatibility values`);
+  }
+  return Object.freeze(
+    Object.fromEntries(FROZEN_EXTENSION_COMPATIBILITY_FIELDS.map((field) => [field, value[field]])),
+  );
+}
+
+function extensionReleaseManifestMembers(manifest) {
+  if (manifest?.schema === 'oliphaunt-extension-release-manifest-v1') {
+    return typeof manifest.sqlName === 'string' && manifest.sqlName.length > 0 ? [manifest] : [];
+  }
+  if (manifest?.schema === 'oliphaunt-extension-release-manifest-v2') {
+    return Array.isArray(manifest.extensions) ? manifest.extensions : [];
+  }
+  return [];
+}
+
+function sameFrozenValue(left, right) {
+  const normalize = (value) => {
+    if (Array.isArray(value)) return value.map(normalize);
+    if (value !== null && typeof value === 'object') {
+      return Object.fromEntries(
+        Object.keys(value)
+          .sort(compareText)
+          .map((key) => [key, normalize(value[key])]),
+      );
+    }
+    return value;
+  };
+  return JSON.stringify(normalize(left)) === JSON.stringify(normalize(right));
+}
+
+function frozenExtensionRelease(manifestPath, manifest, releaseManifest) {
+  const { product, version } = manifest;
+  const members = extensionManifestMembers(manifest);
+  const releaseMembers = extensionReleaseManifestMembers(releaseManifest);
+  const bundle = manifest?.schema === 'oliphaunt-extension-ci-artifacts-v2';
+  const expectedReleaseSchema = bundle
+    ? 'oliphaunt-extension-release-manifest-v2'
+    : 'oliphaunt-extension-release-manifest-v1';
+  if (
+    typeof product !== 'string' ||
+    !product ||
+    typeof version !== 'string' ||
+    !version ||
+    members.length === 0 ||
+    releaseManifest?.schema !== expectedReleaseSchema ||
+    releaseManifest.product !== product ||
+    releaseManifest.version !== version ||
+    releaseMembers.length !== members.length
+  ) {
+    return null;
+  }
+  const manifestCompatibility = frozenExtensionCompatibility(
+    manifest.compatibility,
+    `${product}@${version} CI manifest`,
+  );
+  const releaseCompatibility = frozenExtensionCompatibility(
+    releaseManifest.compatibility,
+    `${product}@${version} release manifest`,
+  );
+  if (!sameFrozenValue(manifestCompatibility, releaseCompatibility)) {
+    throw new Error(`${TOOL}: ${product}@${version} CI and release compatibility contracts differ`);
+  }
+  const memberNames = members.map((member) => member?.sqlName);
+  const releaseMemberNames = releaseMembers.map((member) => member?.sqlName);
+  const canonicalMemberNames = [...new Set(memberNames)].sort(compareText);
+  if (
+    JSON.stringify(memberNames) !== JSON.stringify(canonicalMemberNames) ||
+    JSON.stringify(releaseMemberNames) !== JSON.stringify(memberNames)
+  ) {
+    throw new Error(
+      `${TOOL}: ${rel(manifestPath)} and release manifest must freeze the same sorted unique members`,
+    );
+  }
+  const frozenMembers = members.map((member, index) => {
+    const metadata = frozenExtensionMemberInventory(member, { product, version });
+    const releaseMetadata = frozenExtensionMemberInventory(releaseMembers[index], {
+      product,
+      version,
+    });
+    if (!sameFrozenValue(metadata, releaseMetadata)) {
+      throw new Error(
+        `${TOOL}: ${product}@${version}/${member.sqlName} CI and release inventory contracts differ`,
+      );
+    }
+    return { sqlName: member.sqlName, metadata, member, releaseMember: releaseMembers[index] };
+  });
+  return {
+    bundle,
+    compatibility: manifestCompatibility,
+    members: frozenMembers,
+    product,
+    releaseManifest,
+    version,
+    versioning: releaseManifest.versioning,
+  };
+}
+
+function extensionRuntimeAssets(extensionDir, manifest, releaseManifest, target) {
+  const frozen = frozenExtensionRelease(
+    path.join(extensionDir, 'extension-artifacts.json'),
+    manifest,
+    releaseManifest,
+  );
+  if (frozen === null) return null;
+  const { product, version } = frozen;
+  const runtimeMembers = frozen.members.map(({ sqlName, metadata, member, releaseMember }) => {
+    const matches = Array.isArray(member.assets)
+      ? member.assets.filter(
+          (asset) =>
+            asset?.family === 'native' && asset?.kind === 'runtime' && asset?.target === target,
+        )
+      : [];
+    const releaseMatches = Array.isArray(releaseMember.assets)
+      ? releaseMember.assets.filter(
+          (asset) =>
+            asset?.family === 'native' && asset?.kind === 'runtime' && asset?.target === target,
+        )
+      : [];
+    if (matches.length !== 1) {
+      return null;
+    }
+    if (
+      releaseMatches.length !== 1 ||
+      !sameFrozenValue(
+        extensionRuntimeAssetContract(matches[0]),
+        extensionRuntimeAssetContract(releaseMatches[0]),
+      )
+    ) {
+      throw new Error(
+        `${TOOL}: ${product}@${version}/${member.sqlName} CI and release runtime asset contracts differ`,
+      );
+    }
+    return { sqlName, metadata, asset: matches[0] };
+  });
+  if (runtimeMembers.some((member) => member === null)) {
+    return null;
+  }
+  if (!frozen.bundle) {
+    const asset = runtimeMembers[0].asset;
+    const assetPath = path.join(extensionDir, 'release-assets', asset.name);
+    if (
+      !isFile(assetPath) ||
+      sha256File(assetPath) !== asset.sha256 ||
+      statSync(assetPath).size !== asset.bytes
+    ) {
+      fail(
+        TOOL,
+        `${product}@${version} ${target} runtime asset is missing or does not match its frozen digest`,
+      );
+    }
+    runtimeMembers[0].archive = assetPath;
+    return {
+      bundle: false,
+      members: runtimeMembers,
+      compatibility: frozen.compatibility,
+      versioning: frozen.versioning,
+    };
+  }
+
+  const carrierNames = new Set(runtimeMembers.map(({ asset }) => asset.carrierAsset));
+  if (carrierNames.size !== 1 || carrierNames.has(undefined)) {
+    fail(
+      TOOL,
+      `${product}@${version} ${target} bundle runtime members must share one aggregate carrier`,
+    );
+  }
+  const carrierName = [...carrierNames][0];
+  const carrierRows = Array.isArray(manifest.carrierAssets)
+    ? manifest.carrierAssets.filter(
+        (carrier) =>
+          carrier?.name === carrierName && carrier.family === 'native' && carrier.target === target,
+      )
+    : [];
+  if (carrierRows.length !== 1) {
+    fail(
+      TOOL,
+      `${product}@${version} ${target} bundle must declare exactly one aggregate carrier row`,
+    );
+  }
+  const carrier = carrierRows[0];
+  const releaseCarrierRows = Array.isArray(releaseManifest.assets)
+    ? releaseManifest.assets.filter(
+        (row) => row?.name === carrierName && row.family === 'native' && row.target === target,
+      )
+    : [];
+  if (
+    releaseCarrierRows.length !== 1 ||
+    !sameFrozenValue(
+      extensionRuntimeAssetContract(carrier),
+      extensionRuntimeAssetContract(releaseCarrierRows[0]),
+    )
+  ) {
+    throw new Error(
+      `${TOOL}: ${product}@${version} CI and release aggregate carrier contracts differ`,
+    );
+  }
+  const carrierPath = path.join(extensionDir, 'release-assets', carrierName);
+  if (
+    !isFile(carrierPath) ||
+    statSync(carrierPath).size !== carrier.bytes ||
+    sha256File(carrierPath) !== carrier.sha256
+  ) {
+    fail(
+      TOOL,
+      `${product}@${version} ${target} aggregate carrier is missing or does not match its frozen outer digest`,
+    );
+  }
+  return {
+    bundle: true,
+    members: runtimeMembers,
+    carrier,
+    carrierPath,
+    compatibility: frozen.compatibility,
+    versioning: frozen.versioning,
+  };
+}
+
+const WASIX_PORTABLE_TARGET = 'wasix-portable';
+const WASIX_EXTENSION_SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/u;
+const WASIX_RUNTIME_SUPPORT_SQL_NAMES = new Set(
+  CORE_RUNTIME_ARCHIVE_FILES.flatMap((member) => {
+    const match = member.match(/^oliphaunt\/share\/postgresql\/extension\/([^/]+)[.]control$/u);
+    return match === null ? [] : [match[1]];
+  }),
+);
+
+function portableWasixMemberBytes(bytes, label) {
+  try {
+    readPortableTarZstdBufferEntries(bytes, { label });
+  } catch (cause) {
+    throw new Error(`${TOOL}: ${cause.message}`, { cause });
+  }
+  return bytes;
+}
+
+function checkedPortableWasixMemberBytes(member, bytes, label) {
+  const portable = portableWasixMemberBytes(bytes, label);
+  try {
+    assertWasixExtensionArchiveInstall(
+      portable,
+      {
+        schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA,
+        sqlName: member.sqlName,
+        archive: `extensions/${member.sqlName}.tar.zst`,
+        sha256: member.asset.sha256,
+        size: member.asset.bytes,
+        install: member.install,
+      },
+      { label },
+    );
+  } catch (error) {
+    fail(TOOL, error instanceof Error ? error.message : String(error));
+  }
+  return portable;
+}
+
+function portableWasixExtensionAssets(extensionDir, manifest, releaseManifest) {
+  const manifestPath = path.join(extensionDir, 'extension-artifacts.json');
+  const frozen = frozenExtensionRelease(manifestPath, manifest, releaseManifest);
+  if (frozen === null) return null;
+  const { product, version } = frozen;
+  const members = frozen.members.map(({ sqlName, metadata, member, releaseMember }) => {
+    if (!WASIX_EXTENSION_SQL_NAME.test(sqlName)) {
+      fail(
+        TOOL,
+        `${product}@${version} has an invalid WASIX extension SQL name ${JSON.stringify(sqlName)}`,
+      );
+    }
+    const select = (row) =>
+      row?.family === 'wasix' &&
+      row?.kind === 'wasix-runtime' &&
+      row?.target === WASIX_PORTABLE_TARGET;
+    const matches = Array.isArray(member.assets) ? member.assets.filter(select) : [];
+    const releaseMatches = Array.isArray(releaseMember.assets)
+      ? releaseMember.assets.filter(select)
+      : [];
+    let install;
+    let releaseInstall;
+    try {
+      install = assertWasixExtensionMemberInstall(member, {
+        label: `${product}@${version}/${sqlName} CI member`,
+      });
+      releaseInstall = assertWasixExtensionMemberInstall(releaseMember, {
+        label: `${product}@${version}/${sqlName} release member`,
+      });
+    } catch (error) {
+      fail(TOOL, error instanceof Error ? error.message : String(error));
+    }
+    if (install === null && releaseInstall === null) return null;
+    if (
+      install === null ||
+      releaseInstall === null ||
+      matches.length !== 1 ||
+      releaseMatches.length !== 1 ||
+      !sameFrozenValue(
+        extensionRuntimeAssetContract(matches[0]),
+        extensionRuntimeAssetContract(releaseMatches[0]),
+      )
+    ) {
+      fail(
+        TOOL,
+        `${product}@${version}/${sqlName} CI and release portable WASIX asset contracts differ`,
+      );
+    }
+    const asset = matches[0];
+    if (asset.identity !== null) {
+      fail(
+        TOOL,
+        `${product}@${version}/${sqlName} portable WASIX runtime asset must declare identity=null`,
+      );
+    }
+    if (!sameFrozenValue(install, releaseInstall)) {
+      fail(TOOL, `${product}@${version}/${sqlName} CI and release WASIX install contracts differ`);
+    }
+    if (install.dependencies.some((dependency) => dependency === sqlName)) {
+      fail(TOOL, `${product}@${version}/${sqlName} WASIX install dependencies must exclude itself`);
+    }
+    return { sqlName, metadata, asset, install };
+  });
+  if (members.every((member) => member === null)) return null;
+  if (members.some((member) => member === null)) {
+    fail(TOOL, `${product}@${version} has an incomplete portable WASIX extension member set`);
+  }
+
+  const memberNames = new Set(members.map(({ sqlName }) => sqlName));
+  for (const { sqlName, install } of members) {
+    for (const dependency of install.dependencies) {
+      if (memberNames.has(dependency) || WASIX_RUNTIME_SUPPORT_SQL_NAMES.has(dependency)) continue;
+      fail(
+        TOOL,
+        `${product}@${version}/${sqlName} has unsupported cross-product or unavailable WASIX dependency ${JSON.stringify(dependency)}`,
+      );
+    }
+  }
+
+  if (!frozen.bundle) {
+    const [member] = members;
+    const archive = path.join(extensionDir, 'release-assets', member.asset.name);
+    if (
+      !isFile(archive) ||
+      statSync(archive).size !== member.asset.bytes ||
+      sha256File(archive) !== member.asset.sha256
+    ) {
+      fail(
+        TOOL,
+        `${product}@${version}/${member.sqlName} portable WASIX asset is missing or changed`,
+      );
+    }
+    const bytes = checkedPortableWasixMemberBytes(
+      member,
+      readFileSync(archive),
+      `${product}@${version}/${member.sqlName} portable WASIX archive`,
+    );
+    return {
+      bundle: false,
+      compatibility: frozen.compatibility,
+      members: [{ ...member, bytes }],
+      versioning: frozen.versioning,
+    };
+  }
+
+  const carrierNames = new Set(members.map(({ asset }) => asset.carrierAsset));
+  if (carrierNames.size !== 1 || carrierNames.has(undefined)) {
+    fail(TOOL, `${product}@${version} portable WASIX members must share one aggregate carrier`);
+  }
+  const carrierName = [...carrierNames][0];
+  const selectCarrier = (row) =>
+    row?.name === carrierName &&
+    row?.family === 'wasix' &&
+    row?.kind === 'extension-bundle' &&
+    row?.target === WASIX_PORTABLE_TARGET;
+  const carrierRows = Array.isArray(manifest.carrierAssets)
+    ? manifest.carrierAssets.filter(selectCarrier)
+    : [];
+  const releaseCarrierRows = Array.isArray(releaseManifest.assets)
+    ? releaseManifest.assets.filter(selectCarrier)
+    : [];
+  if (
+    carrierRows.length !== 1 ||
+    releaseCarrierRows.length !== 1 ||
+    !sameFrozenValue(
+      extensionRuntimeAssetContract(carrierRows[0]),
+      extensionRuntimeAssetContract(releaseCarrierRows[0]),
+    )
+  ) {
+    fail(
+      TOOL,
+      `${product}@${version} CI and release portable WASIX aggregate carrier contracts differ`,
+    );
+  }
+  const carrier = carrierRows[0];
+  const carrierPath = path.join(extensionDir, 'release-assets', carrierName);
+  if (
+    !isFile(carrierPath) ||
+    statSync(carrierPath).size !== carrier.bytes ||
+    sha256File(carrierPath) !== carrier.sha256
+  ) {
+    fail(TOOL, `${product}@${version} portable WASIX aggregate carrier is missing or changed`);
+  }
+  let entries;
+  try {
+    entries = readPortableArchiveEntries(carrierPath, { format: 'tar.gz' });
+  } catch (cause) {
+    throw new Error(`${TOOL}: ${cause.message}`, { cause });
+  }
+  return {
+    bundle: true,
+    compatibility: frozen.compatibility,
+    members: members.map((member) => {
+      const carrierRoot = carrierName.replace(/[.]tar[.]gz$/u, '');
+      const expectedMember = `${carrierRoot}/extensions/${member.sqlName}/${member.asset.name}`;
+      if (
+        member.asset.carrierRoot !== carrierRoot ||
+        member.asset.memberPath !== `extensions/${member.sqlName}/${member.asset.name}`
+      ) {
+        fail(
+          TOOL,
+          `${product}@${version}/${member.sqlName} has a noncanonical portable WASIX carrier locator`,
+        );
+      }
+      const entry = entries.get(expectedMember);
+      if (entry === undefined || !entry.isFile || entry.isSymbolicLink) {
+        fail(TOOL, `${rel(carrierPath)} must contain regular member ${expectedMember}`);
+      }
+      const bytes = entry.data();
+      if (
+        bytes.length !== member.asset.bytes ||
+        createHash('sha256').update(bytes).digest('hex') !== member.asset.sha256
+      ) {
+        fail(
+          TOOL,
+          `${product}@${version}/${member.sqlName} nested portable WASIX bytes do not match their frozen digest`,
+        );
+      }
+      return {
+        ...member,
+        bytes: checkedPortableWasixMemberBytes(
+          member,
+          bytes,
+          `${product}@${version}/${member.sqlName} nested portable WASIX archive`,
+        ),
+      };
+    }),
+    versioning: frozen.versioning,
+  };
+}
+
+function checkedArchiveMemberPath(name, archive) {
+  const normalized = String(name).replaceAll('\\', '/');
+  if (
+    !normalized ||
+    normalized === '.' ||
+    normalized === './' ||
+    normalized.startsWith('/') ||
+    normalized.includes('\0')
+  ) {
+    fail(TOOL, `${rel(archive)} contains unsafe archive member ${JSON.stringify(name)}`);
+  }
+  const parts = normalized.split('/').filter((part) => part && part !== '.');
+  if (parts.length === 0 || parts.includes('..')) {
+    fail(TOOL, `${rel(archive)} contains unsafe archive member ${JSON.stringify(name)}`);
+  }
+  return parts.join('/');
+}
+
+function extractExtensionRuntime(asset, runtimeDir, { metadata, target, nativeRuntimeVersion }) {
+  // Native release assets are stripped and platform-validated on their target
+  // builders. Carrier assembly preserves those qualified bytes; host-side
+  // binary rewriting would make output coordinator-dependent.
+  let validated;
+  try {
+    validated = validateExtensionArtifactArchive({
+      file: asset,
+      label: rel(asset),
+      metadata,
+      target,
+      nativeRuntimeVersion,
+    });
+  } catch (error) {
+    throw new Error(`${TOOL}: ${error instanceof Error ? error.message : String(error)}`, {
+      cause: error,
+    });
+  }
+  rmSync(runtimeDir, { recursive: true, force: true });
+  for (const row of validated.runtimeFiles) {
+    const archivePath = `files/${row.path}`;
+    const entry = validated.entries.get(archivePath);
+    if (entry === undefined) {
+      fail(TOOL, `${rel(asset)} validated runtime inventory lost ${archivePath}`);
+    }
+    const destination = path.join(runtimeDir, ...row.path.split('/'));
+    mkdirSync(path.dirname(destination), { recursive: true });
+    writeFileSync(destination, entry.data, { flag: 'wx', mode: entry.mode });
+    chmodSync(destination, entry.mode);
+  }
+  return validated.runtimeFiles;
+}
+
+function materializeBundleMemberArchive(runtimeSet, member, destination) {
+  const { asset, sqlName } = member;
+  const expectedRoot = runtimeSet.carrier.name.replace(/\.tar\.gz$/u, '');
+  const expectedMemberPath = `extensions/${sqlName}/${asset.name}`;
+  if (asset.carrierRoot !== expectedRoot || asset.memberPath !== expectedMemberPath) {
+    fail(TOOL, `${runtimeSet.carrier.name} has a noncanonical nested locator for ${sqlName}`);
+  }
+  const composed = checkedArchiveMemberPath(
+    `${asset.carrierRoot}/${asset.memberPath}`,
+    runtimeSet.carrierPath,
+  );
+  const entry = readPortableArchiveEntries(runtimeSet.carrierPath).get(composed);
+  if (!entry?.isFile || entry.isSymbolicLink) {
+    fail(TOOL, `${rel(runtimeSet.carrierPath)} must contain one regular nested member ${composed}`);
+  }
+  const bytes = entry.data();
+  if (
+    bytes.length !== asset.bytes ||
+    createHash('sha256').update(bytes).digest('hex') !== asset.sha256
+  ) {
+    fail(
+      TOOL,
+      `${rel(runtimeSet.carrierPath)} nested member ${composed} does not match its frozen size/digest`,
+    );
+  }
+  mkdirSync(path.dirname(destination), { recursive: true });
+  const descriptor = openSync(destination, 'wx', 0o600);
+  try {
+    try {
+      writeFileSync(descriptor, bytes);
+    } finally {
+      closeSync(descriptor);
+    }
+  } catch (error) {
+    rmSync(destination, { force: true });
+    throw error;
+  }
+  chmodSync(destination, 0o644);
+  return destination;
+}
+
+function wasixDescriptorClosure(runtimeSet, rootSqlName) {
+  const bySqlName = new Map(runtimeSet.members.map((member) => [member.sqlName, member]));
+  const visiting = new Set();
+  const visited = new Set();
+  const closure = [];
+  const visit = (sqlName) => {
+    if (visited.has(sqlName)) return;
+    if (visiting.has(sqlName)) {
+      fail(TOOL, `portable WASIX extension dependency cycle involving ${JSON.stringify(sqlName)}`);
+    }
+    visiting.add(sqlName);
+    const member = bySqlName.get(sqlName);
+    if (member === undefined) {
+      fail(
+        TOOL,
+        `portable WASIX extension descriptor has no carrier for ${JSON.stringify(sqlName)}`,
+      );
+    }
+    for (const dependency of member.install.dependencies) {
+      if (bySqlName.has(dependency)) visit(dependency);
+    }
+    visiting.delete(sqlName);
+    visited.add(sqlName);
+    closure.push(member);
+  };
+  visit(rootSqlName);
+  return closure;
+}
+
+function descriptorAssetSource(descriptorPath, sqlName) {
+  const asset = `extensions/${sqlName}/extension.tar.zst`;
+  const relative = path.posix.relative(path.posix.dirname(descriptorPath), asset);
+  return relative.startsWith('.') ? relative : `./${relative}`;
+}
+
+export function renderWasixExtensionDescriptorModule({
+  product,
+  version,
+  sqlName,
+  carriers,
+  compatibility,
+  descriptorPath = 'index.js',
+}) {
+  let frozenCompatibility;
+  try {
+    frozenCompatibility = frozenExtensionCompatibility(
+      compatibility,
+      `${product}@${version} portable WASIX descriptor`,
+    );
+  } catch {
+    throw new TypeError(`${TOOL}: invalid portable WASIX extension descriptor compatibility`);
+  }
+  if (
+    ![product, version, sqlName, descriptorPath].every(
+      (value) => typeof value === 'string' && value.length > 0,
+    ) ||
+    !Array.isArray(carriers) ||
+    carriers.length === 0 ||
+    carriers.some(
+      (carrier) =>
+        typeof carrier?.sqlName !== 'string' ||
+        !WASIX_EXTENSION_SQL_NAME.test(carrier.sqlName) ||
+        typeof carrier?.sha256 !== 'string' ||
+        !/^[0-9a-f]{64}$/u.test(carrier.sha256) ||
+        !Number.isSafeInteger(carrier?.size) ||
+        carrier.size <= 0 ||
+        carrier?.install === null ||
+        typeof carrier?.install !== 'object',
+    ) ||
+    new Set(carriers.map((carrier) => carrier.sqlName)).size !== carriers.length ||
+    !carriers.some((carrier) => carrier.sqlName === sqlName)
+  ) {
+    throw new TypeError(`${TOOL}: invalid portable WASIX extension descriptor input`);
+  }
+  const checkedCarriers = carriers.map((carrier, index) => ({
+    ...carrier,
+    install: assertWasixExtensionInstall(carrier.install, {
+      expectedSqlName: carrier.sqlName,
+      label: `${product}@${version} descriptor carrier ${index} install`,
+    }),
+  }));
+  const installRows = checkedCarriers.flatMap((carrier, index) => [
+    `const install${index} = deepFreeze(${JSON.stringify(carrier.install, null, 2)});`,
+  ]);
+  const carrierRows = checkedCarriers.map((carrier, index) =>
+    [
+      '  {',
+      `    product: ${JSON.stringify(product)},`,
+      `    version: ${JSON.stringify(version)},`,
+      `    sqlName: ${JSON.stringify(carrier.sqlName)},`,
+      `    archive: ${JSON.stringify(`extensions/${carrier.sqlName}.tar.zst`)},`,
+      `    sha256: ${JSON.stringify(carrier.sha256)},`,
+      `    size: ${carrier.size},`,
+      `    source: new URL(${JSON.stringify(descriptorAssetSource(descriptorPath, carrier.sqlName))}, import.meta.url),`,
+      `    install: install${index},`,
+      '  },',
+    ].join('\n'),
+  );
+  return [
+    'function deepFreeze(value) {',
+    '  if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {',
+    '    for (const child of Object.values(value)) deepFreeze(child);',
+    '    Object.freeze(value);',
+    '  }',
+    '  return value;',
+    '}',
+    '',
+    ...installRows,
+    ...(installRows.length === 0 ? [] : ['']),
+    'const compatibility = deepFreeze({',
+    `  extensionRuntimeContract: ${JSON.stringify(EXTENSION_RUNTIME_CONTRACT_SCHEMA)},`,
+    `  postgresMajor: ${JSON.stringify(frozenCompatibility.postgresMajor)},`,
+    `  wasixRuntimeProduct: ${JSON.stringify(frozenCompatibility.wasixRuntimeProduct)},`,
+    `  wasixRuntimeVersion: ${JSON.stringify(frozenCompatibility.wasixRuntimeVersion)},`,
+    '});',
+    '',
+    'const carriers = deepFreeze([',
+    ...carrierRows,
+    ']);',
+    '',
+    'const descriptor = deepFreeze({',
+    '  schema: "oliphaunt-wasix-extension-v1",',
+    '  runtime: "wasix",',
+    `  product: ${JSON.stringify(product)},`,
+    `  version: ${JSON.stringify(version)},`,
+    '  compatibility,',
+    `  sqlName: ${JSON.stringify(sqlName)},`,
+    '  carriers,',
+    '});',
+    '',
+    'export { descriptor };',
+    'export default descriptor;',
+    '',
+  ].join('\n');
+}
+
+export function renderWasixExtensionDescriptorTypes() {
+  return `export type OliphauntWasixExtensionNativeModule = Readonly<{
+  name: string;
+  path: string;
+  sha256: string;
+  moduleSha256: string;
+  size: number;
+}>;
+
+export type OliphauntWasixExtensionImport = Readonly<{
+  module: string;
+  name: string;
+  kind: string;
+}>;
+
+export type OliphauntWasixExtensionLifecycle = Readonly<{
+  createExtension: boolean;
+  createSchema: string | null;
+  loadSql: readonly string[];
+  postCreateSql: readonly string[];
+  startupConfig: readonly string[];
+  preloadRequired: boolean;
+  restartRequired: boolean;
+  sharedMemoryRequired: boolean;
+}>;
+
+export type OliphauntWasixExtensionInstall = Readonly<{
+  schema: "${WASIX_EXTENSION_INSTALL_SCHEMA}";
+  name: string;
+  nativeModule: string | null;
+  nativeModules: readonly OliphauntWasixExtensionNativeModule[];
+  coreExportsRequired: readonly string[];
+  dependencies: readonly string[];
+  loadOrder: readonly string[];
+  lifecycle: OliphauntWasixExtensionLifecycle;
+  installedFiles: readonly string[];
+  unresolvedImports: readonly OliphauntWasixExtensionImport[];
+}>;
+
+export type OliphauntWasixExtensionCarrier = Readonly<{
+  product: string;
+  version: string;
+  sqlName: string;
+  archive: string;
+  sha256: string;
+  size: number;
+  source: URL;
+  install: OliphauntWasixExtensionInstall;
+}>;
+
+export type OliphauntWasixExtensionCompatibility = Readonly<{
+  extensionRuntimeContract: "${EXTENSION_RUNTIME_CONTRACT_SCHEMA}";
+  postgresMajor: string;
+  wasixRuntimeProduct: "liboliphaunt-wasix";
+  wasixRuntimeVersion: string;
+}>;
+
+export type OliphauntWasixExtensionDescriptor = Readonly<{
+  schema: "oliphaunt-wasix-extension-v1";
+  runtime: "wasix";
+  product: string;
+  version: string;
+  compatibility: OliphauntWasixExtensionCompatibility;
+  sqlName: string;
+  carriers: readonly OliphauntWasixExtensionCarrier[];
+}>;
+
+declare const descriptor: OliphauntWasixExtensionDescriptor;
+export { descriptor };
+export default descriptor;
+`;
+}
+
+function writeWasixExtensionReadme(packageDir, packageName, members, bundle) {
+  const selectedMembers = bundle ? members.slice(0, 2) : members;
+  const imports = selectedMembers.map((sqlName) => {
+    const localName = sqlName.replaceAll('-', '_');
+    return `import ${localName} from '${packageName}${bundle ? `/${sqlName}` : ''}';`;
+  });
+  const selectedDescriptors = selectedMembers.map((sqlName) => sqlName.replaceAll('-', '_'));
+  writeFileSync(
+    path.join(packageDir, 'README.md'),
+    [
+      `# ${packageName}`,
+      '',
+      'Host-neutral portable WASIX carrier for exact Oliphaunt PostgreSQL extension bytes.',
+      'The carrier does not itself claim qualification for any particular browser or Node host.',
+      '',
+      'Consumer API:',
+      '',
+      '```ts',
+      "import Oliphaunt from '@oliphaunt/wasix-ts';",
+      ...imports,
+      '',
+      'const database = await Oliphaunt.open({',
+      `  extensions: [${selectedDescriptors.join(', ')}],`,
+      '});',
+      '```',
+      '',
+      'Import only the extension descriptors your application needs. The WASIX runtime',
+      'carrier and package-relative archives are resolved and verified by the binding.',
+      'This carrier is selected by the binding and is not a standalone database host.',
+      '',
+      'The package version, tag, and changelog belong to the unsuffixed extension release product.',
+      '',
+    ].join('\n'),
+  );
+}
+
+function writeWasixExtensionNpmPackage(packageDir, { product, version, runtimeSet }) {
+  const members = runtimeSet.members.map(({ sqlName }) => sqlName);
+  const bundle = members.length > 1;
+  const packageName = extensionNpmWasixPackageForProduct(product);
+  const legal = wasixExtensionCarrierLegal(product, members);
+  mkdirSync(packageDir, { recursive: true });
+  for (const member of runtimeSet.members) {
+    const output = path.join(packageDir, 'extensions', member.sqlName, 'extension.tar.zst');
+    mkdirSync(path.dirname(output), { recursive: true });
+    writeFileSync(output, member.bytes, { flag: 'wx', mode: 0o644 });
+    chmodSync(output, 0o644);
+  }
+
+  const exports = {};
+  const memberExports = {};
+  for (const member of runtimeSet.members) {
+    const descriptorPath = bundle ? `descriptors/${member.sqlName}.js` : 'index.js';
+    const typesPath = descriptorPath.replace(/[.]js$/u, '.d.ts');
+    const closure = wasixDescriptorClosure(runtimeSet, member.sqlName);
+    const module = renderWasixExtensionDescriptorModule({
+      product,
+      version,
+      sqlName: member.sqlName,
+      compatibility: runtimeSet.compatibility,
+      carriers: closure.map((carrier) => ({
+        sqlName: carrier.sqlName,
+        sha256: carrier.asset.sha256,
+        size: carrier.asset.bytes,
+        install: carrier.install,
+      })),
+      descriptorPath,
+    });
+    const modulePath = path.join(packageDir, ...descriptorPath.split('/'));
+    mkdirSync(path.dirname(modulePath), { recursive: true });
+    writeFileSync(modulePath, module);
+    writeFileSync(
+      path.join(packageDir, ...typesPath.split('/')),
+      renderWasixExtensionDescriptorTypes(),
+    );
+    const exportName = bundle ? `./${member.sqlName}` : '.';
+    memberExports[member.sqlName] = exportName;
+    exports[exportName] = {
+      types: `./${typesPath}`,
+      import: `./${descriptorPath}`,
+      default: `./${descriptorPath}`,
+    };
+  }
+  exports['./package.json'] = './package.json';
+
+  writeWasixExtensionReadme(packageDir, packageName, members, bundle);
+  writeJsonFile(path.join(packageDir, 'package.json'), {
+    name: packageName,
+    version,
+    description: bundle
+      ? `Portable Oliphaunt WASIX carrier for ${members.length} exact PostgreSQL contrib extensions.`
+      : `Portable Oliphaunt WASIX carrier for PostgreSQL ${members[0]}.`,
+    license: legal.packageSpdx,
+    type: 'module',
+    sideEffects: false,
+    repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY },
+    oliphaunt: {
+      product,
+      kind: bundle ? 'exact-extension-wasix-bundle' : 'exact-extension-wasix',
+      runtime: 'wasix',
+      descriptorSchema: 'oliphaunt-wasix-extension-v1',
+      members,
+      memberExports,
+      target: WASIX_PORTABLE_TARGET,
+      wasixRuntimeProduct: runtimeSet.compatibility.wasixRuntimeProduct,
+      wasixRuntimeVersion: runtimeSet.compatibility.wasixRuntimeVersion,
+      runtimeBound: runtimeSet.versioning === 'runtime-bound',
+    },
+    publishConfig: { access: 'public', provenance: true },
+    files: [
+      'README.md',
+      ...(bundle ? ['descriptors'] : ['index.js', 'index.d.ts']),
+      'extensions',
+      ...carrierLegalMembers(legal),
+    ],
+    exports,
+  });
+  stageExtensionCarrierLegal(packageDir, legal);
+  return { legal, packageName };
+}
+
+function extensionModuleDirectory(runtimeDir) {
+  for (const candidate of [
+    path.join(runtimeDir, 'lib', 'modules'),
+    path.join(runtimeDir, 'lib', 'postgresql'),
+  ]) {
+    if (!isDirectory(candidate)) continue;
+    for (const file of readdirSync(candidate).sort(compareText)) {
+      const fullPath = path.join(candidate, file);
+      if (
+        isFile(fullPath) &&
+        ['.so', '.dylib', '.dll'].includes(path.extname(file).toLowerCase())
+      ) {
+        return candidate;
+      }
+    }
+  }
+  return null;
+}
+
+function writeExtensionReadme(packageDir, packageName, members, target) {
+  const targetText = target === null ? '' : ` for \`${target}\``;
+  const memberText =
+    members.length === 1
+      ? `the \`${members[0]}\` PostgreSQL extension`
+      : `${members.length} PostgreSQL contrib extensions`;
+  const selectionExample = members.length === 1 ? members[0] : members.slice(0, 2).join("', '");
+  writeFileSync(
+    path.join(packageDir, 'README.md'),
+    [
+      `# ${packageName}`,
+      '',
+      `Oliphaunt registry package for ${memberText}${targetText}.`,
+      '',
+      'This package is consumed by `@oliphaunt/ts` when an application opens a database with',
+      `\`extensions: ['${selectionExample}']\`.`,
+      '',
+    ].join('\n'),
+  );
+}
+
+function writeExtensionMetaPackage(
+  packageDir,
+  {
+    product,
+    version,
+    members,
+    target,
+    targets = [target],
+    iosCarrier,
+    liboliphauntVersion,
+    runtimeBound,
+    legal,
+  },
+) {
+  const bundle = members.length > 1;
+  const packageName = extensionNpmPackageForProduct(product);
+  const targetPackageNames = Object.fromEntries(
+    targets
+      .filter((item) => typeof item === 'string' && item.length > 0)
+      .sort(compareText)
+      .map((item) => [item, extensionNpmTargetPackageForProduct(product, item)]),
+  );
+  mkdirSync(packageDir, { recursive: true });
+  writeExtensionReadme(packageDir, packageName, members, null);
+  writeJsonFile(path.join(packageDir, IOS_CARRIER_FILENAME), iosCarrier);
+  writeJsonFile(path.join(packageDir, 'package.json'), {
+    name: packageName,
+    version,
+    description: bundle
+      ? `Oliphaunt PostgreSQL contrib extension bundle (${members.length} exact members).`
+      : `Oliphaunt extension package for PostgreSQL ${members[0]}.`,
+    license: legal.packageSpdx,
+    type: 'module',
+    repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY },
+    optionalDependencies: Object.fromEntries(
+      Object.values(targetPackageNames).map((name) => [name, version]),
+    ),
+    oliphaunt: {
+      product,
+      kind: bundle ? 'exact-extension-bundle' : 'exact-extension',
+      ...(bundle ? {} : { sqlName: members[0] }),
+      members,
+      targetPackageNames,
+      iosCarrierManifest: `./${IOS_CARRIER_FILENAME}`,
+      liboliphauntVersion,
+      runtimeBound,
+    },
+    publishConfig: { access: 'public', provenance: true },
+    files: ['README.md', IOS_CARRIER_FILENAME, ...carrierLegalMembers(legal)],
+    exports: {
+      './ios-carriers': `./${IOS_CARRIER_FILENAME}`,
+      './package.json': './package.json',
+    },
+  });
+}
+
+function writeExtensionTargetPackage(
+  packageDir,
+  {
+    product,
+    version,
+    members,
+    memberContracts,
+    target,
+    liboliphauntVersion,
+    memberRuntimeRelativePaths = null,
+    memberModuleRelativePaths = null,
+    legal,
+  },
+) {
+  const bundle = members.length > 1;
+  if (
+    !Array.isArray(memberContracts) ||
+    JSON.stringify(memberContracts.map((contract) => contract?.sqlName)) !== JSON.stringify(members)
+  ) {
+    fail(
+      TOOL,
+      `${product}@${version} target package member contracts must exactly match its members`,
+    );
+  }
+  const packageName = extensionNpmTargetPackageForProduct(product, target);
+  const runtimeDir = bundle ? null : path.join(packageDir, 'runtime');
+  const moduleDir = runtimeDir === null ? null : extensionModuleDirectory(runtimeDir);
+  const metadata = {
+    product,
+    kind: bundle ? 'exact-extension-bundle-target' : 'exact-extension-target',
+    ...(bundle ? {} : { sqlName: members[0] }),
+    members,
+    extensionContract: NPM_EXTENSION_CONTRACT_FILENAME,
+    target,
+    ...(bundle
+      ? {
+          bundleManifest: 'bundle-manifest.json',
+          memberRuntimeRelativePaths,
+          ...(memberModuleRelativePaths !== null &&
+          Object.keys(memberModuleRelativePaths).length > 0
+            ? { memberModuleRelativePaths }
+            : {}),
+        }
+      : { runtimeRelativePath: 'runtime' }),
+    liboliphauntVersion,
+  };
+  if (moduleDir !== null) {
+    metadata.moduleRelativePath = path.relative(packageDir, moduleDir).split(path.sep).join('/');
+  }
+  mkdirSync(packageDir, { recursive: true });
+  writeExtensionReadme(packageDir, packageName, members, target);
+  writeJsonFile(
+    path.join(packageDir, NPM_EXTENSION_CONTRACT_FILENAME),
+    renderNpmExtensionContractManifest({ product, version, target, members: memberContracts }),
+  );
+  writeJsonFile(path.join(packageDir, 'package.json'), {
+    name: packageName,
+    version,
+    description: bundle
+      ? `${target} Oliphaunt runtime bundle for ${members.length} exact PostgreSQL contrib extensions.`
+      : `${target} Oliphaunt extension runtime package for PostgreSQL ${members[0]}.`,
+    license: legal.packageSpdx,
+    type: 'module',
+    repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY },
+    ...npmPlatformConstraints(target),
+    optional: true,
+    oliphaunt: metadata,
+    publishConfig: { access: 'public', provenance: true },
+    files: [
+      ...(bundle
+        ? ['extensions', 'bundle-manifest.json', NPM_EXTENSION_CONTRACT_FILENAME, 'README.md']
+        : ['runtime', NPM_EXTENSION_CONTRACT_FILENAME, 'README.md']),
+      ...carrierLegalMembers(legal),
+    ],
+    exports: {
+      ...(bundle ? { './bundle-manifest': './bundle-manifest.json' } : {}),
+      './extension-contract': `./${NPM_EXTENSION_CONTRACT_FILENAME}`,
+      './package.json': './package.json',
+    },
+  });
+}
+
+function npmPackageSizeSafe(tarball, result) {
+  const size = statSync(tarball).size;
+  if (size <= NPM_PACKAGE_SAFETY_LIMIT_BYTES) {
+    return true;
+  }
+  result.skipped.push(
+    `${rel(tarball)} is ${size} bytes, exceeding the 100 MiB release safety limit`,
+  );
+  rmSync(tarball, { force: true });
+  return false;
+}
+
+export function stageExtensionNativeNpmPackages(roots, stagingRoot, target, result, options = {}) {
+  const manifests = discoverExtensionManifests(roots);
+  if (manifests.length === 0) {
+    result.skipped.push('no extension-artifacts.json manifests found for npm extension packages');
+    return null;
+  }
+  if (target === null) {
+    result.skipped.push('current host does not map to a supported npm extension target');
+    return null;
+  }
+
+  rmSync(stagingRoot, { recursive: true, force: true });
+  const packageRoot = path.join(stagingRoot, 'packages');
+  const tarballRoot = path.join(stagingRoot, 'tarballs');
+  let stagedAny = false;
+  const stagedIdentities = new Map();
+
+  for (const manifestPath of manifests) {
+    const manifest = readJsonFile(manifestPath);
+    const extensionDir = path.dirname(manifestPath);
+    const { product, version } = manifest;
+    const members = extensionManifestMembers(manifest).map((member) => member.sqlName);
+    if (
+      ![product, version].every((value) => typeof value === 'string' && value.length > 0) ||
+      members.length === 0
+    ) {
+      result.skipped.push(`${rel(manifestPath)} is missing product, version, or exact member rows`);
+      continue;
+    }
+    const releaseManifest = extensionReleaseManifest(extensionDir, product, version);
+    const expectedReleaseSchema =
+      members.length > 1
+        ? 'oliphaunt-extension-release-manifest-v2'
+        : 'oliphaunt-extension-release-manifest-v1';
+    if (
+      releaseManifest.schema !== expectedReleaseSchema ||
+      releaseManifest.product !== product ||
+      releaseManifest.version !== version
+    ) {
+      result.skipped.push(
+        `${product}@${version} is missing its exact ${expectedReleaseSchema} release manifest`,
+      );
+      continue;
+    }
+    const runtimeSet = extensionRuntimeAssets(extensionDir, manifest, releaseManifest, target);
+    if (runtimeSet === null) {
+      result.skipped.push(
+        `${product}@${version} has no complete ${target} native runtime member set`,
+      );
+      continue;
+    }
+    const compatibility = runtimeSet.compatibility;
+    const liboliphauntVersion = compatibility.nativeRuntimeVersion;
+    const runtimeBound = runtimeSet.versioning === 'runtime-bound';
+    if (runtimeBound && version !== liboliphauntVersion) {
+      fail(
+        TOOL,
+        `${product}@${version} is runtime-bound but declares liboliphauntVersion=${liboliphauntVersion}`,
+      );
+    }
+    const identity = `${product}@${version}:${target}`;
+    const identityDigest = JSON.stringify({
+      release: createHash('sha256').update(JSON.stringify(releaseManifest)).digest('hex'),
+      members: runtimeSet.members.map(({ metadata, asset }) => ({
+        metadata,
+        sha256: asset.sha256,
+        bytes: asset.bytes,
+      })),
+      carrier:
+        runtimeSet.carrier === undefined
+          ? null
+          : { sha256: runtimeSet.carrier.sha256, bytes: runtimeSet.carrier.bytes },
+    });
+    const previousIdentityDigest = stagedIdentities.get(identity);
+    if (previousIdentityDigest !== undefined) {
+      if (previousIdentityDigest !== identityDigest) {
+        fail(TOOL, `conflicting extension packages discovered for ${identity}`);
+      }
+      result.skipped.push(
+        `deduplicated byte-identical extension package ${identity} from ${rel(manifestPath)}`,
+      );
+      continue;
+    }
+    stagedIdentities.set(identity, identityDigest);
+
+    const metaDir = path.join(
+      packageRoot,
+      safeNpmPackageFilenamePrefix(extensionNpmPackageForProduct(product)),
+    );
+    const targetDir = path.join(
+      packageRoot,
+      safeNpmPackageFilenamePrefix(extensionNpmTargetPackageForProduct(product, target)),
+    );
+    const memberRuntimeRelativePaths = {};
+    const memberModuleRelativePaths = {};
+    const bundleManifestMembers = [];
+    if (runtimeSet.bundle) {
+      for (const member of runtimeSet.members) {
+        const archiveRelativePath = `extensions/${member.sqlName}/${member.asset.name}`;
+        const archive = materializeBundleMemberArchive(
+          runtimeSet,
+          member,
+          path.join(targetDir, ...archiveRelativePath.split('/')),
+        );
+        const runtimeRelativePath = `extensions/${member.sqlName}/runtime`;
+        const runtimeDir = path.join(targetDir, ...runtimeRelativePath.split('/'));
+        extractExtensionRuntime(archive, runtimeDir, {
+          metadata: member.metadata,
+          target,
+          nativeRuntimeVersion: liboliphauntVersion,
+        });
+        if (walkFiles(runtimeDir).length === 0) {
+          fail(
+            TOOL,
+            `${product}@${version} produced an empty ${target} npm runtime payload for ${member.sqlName}`,
+          );
+        }
+        memberRuntimeRelativePaths[member.sqlName] = runtimeRelativePath;
+        const moduleDir = extensionModuleDirectory(runtimeDir);
+        const moduleRelativePath =
+          moduleDir === null ? null : path.relative(targetDir, moduleDir).split(path.sep).join('/');
+        if (moduleRelativePath !== null) {
+          memberModuleRelativePaths[member.sqlName] = moduleRelativePath;
+        }
+        if (!Object.hasOwn(member.asset, 'identity') || member.asset.identity !== null) {
+          fail(
+            TOOL,
+            `${product}@${version} ${target} runtime member ${member.sqlName} must declare identity=null`,
+          );
+        }
+        bundleManifestMembers.push({
+          sqlName: member.sqlName,
+          kind: member.asset.kind,
+          identity: null,
+          path: archiveRelativePath,
+          sha256: member.asset.sha256,
+          bytes: member.asset.bytes,
+          runtimeRelativePath,
+          ...(moduleRelativePath === null ? {} : { moduleRelativePath }),
+        });
+      }
+      writeJsonFile(
+        path.join(targetDir, 'bundle-manifest.json'),
+        renderNpmExtensionBundleManifest({
+          product,
+          version,
+          target,
+          members: bundleManifestMembers,
+        }),
+      );
+    } else {
+      const runtimeDir = path.join(targetDir, 'runtime');
+      extractExtensionRuntime(runtimeSet.members[0].archive, runtimeDir, {
+        metadata: runtimeSet.members[0].metadata,
+        target,
+        nativeRuntimeVersion: liboliphauntVersion,
+      });
+      if (walkFiles(runtimeDir).length === 0) {
+        result.skipped.push(
+          `${product}@${version} produced an empty ${target} npm runtime payload`,
+        );
+        continue;
+      }
+    }
+    const metaTargets =
+      typeof options.metaTargetsForProduct === 'function'
+        ? options.metaTargetsForProduct(product)
+        : options.metaTargets;
+    const metaLegal = nativeExtensionCarrierLegal(product, members, {
+      carriesPayload: false,
+    });
+    const targetLegal = nativeExtensionCarrierLegal(product, members, {
+      carriesPayload: true,
+      target,
+    });
+    writeExtensionTargetPackage(targetDir, {
+      product,
+      version,
+      members,
+      memberContracts: runtimeSet.members.map(({ metadata }) => metadata),
+      target,
+      liboliphauntVersion,
+      memberRuntimeRelativePaths: runtimeSet.bundle ? memberRuntimeRelativePaths : null,
+      memberModuleRelativePaths: runtimeSet.bundle ? memberModuleRelativePaths : null,
+      legal: targetLegal,
+    });
+    stageExtensionCarrierLegal(targetDir, targetLegal);
+    const targetTarball = packGeneratedNpmCarrier(targetDir, tarballRoot);
+    assertExtensionCarrierArchive(targetTarball, targetLegal, 'package');
+    assertNpmExtensionRuntimeLegalArchive(targetTarball, {
+      product,
+      members,
+      target,
+      bundle: runtimeSet.bundle,
+      memberRuntimeRelativePaths,
+    });
+    if (!npmPackageSizeSafe(targetTarball, result)) {
+      continue;
+    }
+    // An explicitly empty meta target set requests only the platform leaf.
+    // Full meta carriers retain their complete Apple resource contract.
+    if (metaTargets === undefined || metaTargets.length > 0) {
+      const iosCarrier = buildIosCarrierManifest({
+        baseAssetDir: options.baseAssetDir ?? path.join(ROOT, 'target/liboliphaunt/release-assets'),
+        baseCarrierManifest: options.baseCarrierManifest,
+        extensionManifests: [manifestPath],
+      });
+      writeExtensionMetaPackage(metaDir, {
+        product,
+        version,
+        members,
+        target,
+        targets: metaTargets ?? [target],
+        iosCarrier,
+        liboliphauntVersion,
+        runtimeBound,
+        legal: metaLegal,
+      });
+      stageExtensionCarrierLegal(metaDir, metaLegal);
+      const metaTarball = packGeneratedNpmCarrier(metaDir, tarballRoot);
+      assertExtensionCarrierArchive(metaTarball, metaLegal, 'package');
+      if (!npmPackageSizeSafe(metaTarball, result)) {
+        rmSync(targetTarball, { force: true });
+        continue;
+      }
+      result.staged.push(rel(metaTarball));
+    }
+    result.staged.push(rel(targetTarball));
+    stagedAny = true;
+  }
+
+  return stagedAny ? tarballRoot : null;
+}
+
+function assertWasixExtensionNpmArchive(
+  archive,
+  { legal, packageName, product, runtimeSet, version },
+) {
+  assertExtensionCarrierArchive(archive, legal, 'package');
+  let entries;
+  try {
+    entries = readPortableArchiveEntries(archive, { format: 'tar.gz' });
+  } catch (cause) {
+    throw new Error(`${TOOL}: ${cause.message}`, { cause });
+  }
+  const packageJsonEntry = entries.get('package/package.json');
+  if (
+    packageJsonEntry === undefined ||
+    !packageJsonEntry.isFile ||
+    packageJsonEntry.isSymbolicLink
+  ) {
+    fail(TOOL, `${rel(archive)} lacks a regular package/package.json`);
+  }
+  let packageJson;
+  try {
+    packageJson = JSON.parse(packageJsonEntry.data().toString('utf8'));
+  } catch (cause) {
+    fail(TOOL, `${rel(archive)} package/package.json is invalid JSON: ${cause.message}`);
+  }
+  if (
+    packageJson.name !== packageName ||
+    packageJson.version !== version ||
+    packageJson.oliphaunt?.product !== product ||
+    packageJson.oliphaunt?.runtime !== 'wasix'
+  ) {
+    fail(TOOL, `${rel(archive)} does not preserve its exact WASIX extension package identity`);
+  }
+  for (const member of runtimeSet.members) {
+    const memberPath = `package/extensions/${member.sqlName}/extension.tar.zst`;
+    const entry = entries.get(memberPath);
+    if (entry === undefined || !entry.isFile || entry.isSymbolicLink) {
+      fail(TOOL, `${rel(archive)} lacks regular WASIX carrier ${memberPath}`);
+    }
+    const bytes = entry.data();
+    if (
+      bytes.length !== member.asset.bytes ||
+      createHash('sha256').update(bytes).digest('hex') !== member.asset.sha256
+    ) {
+      fail(TOOL, `${rel(archive)} changed portable WASIX bytes for ${member.sqlName}`);
+    }
+  }
+}
+
+export function stageExtensionWasixNpmPackages(roots, stagingRoot, result) {
+  const manifests = discoverExtensionManifests(roots);
+  if (manifests.length === 0) return null;
+
+  rmSync(stagingRoot, { recursive: true, force: true });
+  const packageRoot = path.join(stagingRoot, 'packages');
+  const tarballRoot = path.join(stagingRoot, 'tarballs');
+  const stagedIdentities = new Map();
+  let stagedAny = false;
+  for (const manifestPath of manifests) {
+    const manifest = readJsonFile(manifestPath);
+    const extensionDir = path.dirname(manifestPath);
+    const { product, version } = manifest;
+    if (![product, version].every((value) => typeof value === 'string' && value.length > 0))
+      continue;
+    const releaseManifest = extensionReleaseManifest(extensionDir, product, version);
+    const runtimeSet = portableWasixExtensionAssets(extensionDir, manifest, releaseManifest);
+    if (runtimeSet === null) continue;
+    const runtimeVersion = runtimeSet.compatibility.wasixRuntimeVersion;
+    if (runtimeSet.versioning === 'runtime-bound' && version !== runtimeVersion) {
+      fail(
+        TOOL,
+        `${product}@${version} is runtime-bound but declares WASIX runtime version ${runtimeVersion}`,
+      );
+    }
+    const identity = `${extensionNpmWasixPackageForProduct(product)}@${version}`;
+    const digest = JSON.stringify({
+      compatibility: runtimeSet.compatibility,
+      members: runtimeSet.members.map(({ metadata, asset, install }) => ({
+        metadata,
+        sha256: asset.sha256,
+        bytes: asset.bytes,
+        install,
+      })),
+      versioning: runtimeSet.versioning,
+    });
+    const previous = stagedIdentities.get(identity);
+    if (previous !== undefined) {
+      if (previous !== digest) {
+        fail(TOOL, `conflicting portable WASIX npm candidates discovered for ${identity}`);
+      }
+      result.skipped.push(`deduplicated byte-identical portable WASIX npm candidate ${identity}`);
+      continue;
+    }
+    stagedIdentities.set(identity, digest);
+
+    const packageDir = path.join(
+      packageRoot,
+      safeNpmPackageFilenamePrefix(extensionNpmWasixPackageForProduct(product)),
+    );
+    const { legal, packageName } = writeWasixExtensionNpmPackage(packageDir, {
+      product,
+      version,
+      runtimeSet,
+    });
+    const tarball = packGeneratedNpmCarrier(packageDir, tarballRoot);
+    assertWasixExtensionNpmArchive(tarball, {
+      legal,
+      packageName,
+      product,
+      runtimeSet,
+      version,
+    });
+    if (!npmPackageSizeSafe(tarball, result)) continue;
+    result.staged.push(rel(tarball));
+    stagedAny = true;
+  }
+  return stagedAny ? tarballRoot : null;
+}
+
+export function stageExtensionNpmPackages(roots, stagingRoot, target, result, options = {}) {
+  rmSync(stagingRoot, { recursive: true, force: true });
+  const nativeRoot = stageExtensionNativeNpmPackages(
+    roots,
+    path.join(stagingRoot, 'native'),
+    target,
+    result,
+    options,
+  );
+  const wasixRoot = stageExtensionWasixNpmPackages(roots, path.join(stagingRoot, 'wasix'), result);
+  return nativeRoot === null && wasixRoot === null ? null : stagingRoot;
+}
+
+export function stageExtensionNpmPackagesForTargets(
+  roots,
+  stagingRoot,
+  targets,
+  result,
+  options = {},
+) {
+  if (
+    !Array.isArray(targets) ||
+    targets.length === 0 ||
+    targets.some((target) => typeof target !== 'string' || target.length === 0) ||
+    new Set(targets).size !== targets.length
+  ) {
+    throw new TypeError(
+      `${TOOL}: extension npm target-set staging requires a non-empty unique target list`,
+    );
+  }
+  const canonicalTargets = [...targets].sort(compareText);
+  rmSync(stagingRoot, { recursive: true, force: true });
+  const nativeRoots = Object.fromEntries(
+    canonicalTargets.map((target) => [
+      target,
+      stageExtensionNativeNpmPackages(roots, path.join(stagingRoot, target), target, result, {
+        ...options,
+        metaTargets: options.metaTargets ?? canonicalTargets,
+      }),
+    ]),
+  );
+  const wasixRoot = stageExtensionWasixNpmPackages(roots, path.join(stagingRoot, 'wasix'), result);
+  return Object.freeze({
+    nativeRoots: Object.freeze(nativeRoots),
+    wasixRoot,
+    root:
+      Object.values(nativeRoots).some((root) => root !== null) || wasixRoot !== null
+        ? stagingRoot
+        : null,
+  });
+}
+
+function writeNativeExtensionCargoPartCrate(
+  crateDir,
+  { product, version, members, target, index, legal },
+) {
+  rmSync(crateDir, { recursive: true, force: true });
+  const name = nativeExtensionCargoPartPackageName(product, target, index);
+  const subject = members.length === 1 ? members[0] : `${members.length}-member bundle`;
+  mkdirSync(path.join(crateDir, 'src'), { recursive: true });
+  writeFileSync(
+    path.join(crateDir, 'Cargo.toml'),
+    `[package]
+name = "${name}"
+version = "${version}"
+edition = "2024"
+rust-version = "1.93"
+description = "Cargo payload part ${String(index).padStart(3, '0')} for the ${subject} Oliphaunt native extension carrier on ${target}."
+readme = "README.md"
+repository = "https://github.com/f0rr0/oliphaunt"
+homepage = "https://oliphaunt.dev"
+license = ${tomlString(legal.packageSpdx)}
+include = ${tomlString(['Cargo.toml', 'README.md', 'src/**', 'payload/**', ...carrierLegalMembers(legal)])}
+
+[lib]
+path = "src/lib.rs"
+
+[workspace]
+`,
+  );
+  writeFileSync(
+    path.join(crateDir, 'README.md'),
+    `# ${name}
+
+Cargo payload part for the ${subject} Oliphaunt native extension carrier on \`${target}\`.
+Applications do not depend on this crate directly.
+`,
+  );
+  writeFileSync(
+    path.join(crateDir, 'src/lib.rs'),
+    `pub const PRODUCT: &str = "${product}";
+pub const KIND: &str = "extension-part";
+pub const MEMBERS: &[&str] = &[${members.map((member) => JSON.stringify(member)).join(', ')}];
+pub const RELEASE_TARGET: &str = "${target}";
+pub const PART_INDEX: usize = ${index};
+pub const PAYLOAD_ROOT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/payload");
+`,
+  );
+  stageExtensionCarrierLegal(crateDir, legal);
+}
+
+function writeChunk(file, data) {
+  mkdirSync(path.dirname(file), { recursive: true });
+  writeFileSync(file, data);
+}
+
+function copyPayloadFile(source, destination) {
+  mkdirSync(path.dirname(destination), { recursive: true });
+  copyFileSync(source, destination);
+}
+
+export function buildNativeExtensionPartCrates(
+  runtimeDir,
+  sourceRoot,
+  { product, version, members, target, partBytes },
+) {
+  const legal = nativeExtensionCarrierLegal(product, members, { target, carriesPayload: true });
+  const partDirs = [];
+  let currentDir = null;
+  let currentSize = 0;
+
+  const startPart = () => {
+    const index = partDirs.length + 1;
+    if (index > 999) {
+      throw new Error(
+        `${product}@${version} requires more than 999 Cargo payload parts for ${target}`,
+      );
+    }
+    const partDir = path.join(
+      sourceRoot,
+      nativeExtensionCargoPartPackageName(product, target, index),
+    );
+    writeNativeExtensionCargoPartCrate(partDir, {
+      product,
+      version,
+      members,
+      target,
+      index,
+      legal,
+    });
+    partDirs.push(partDir);
+    return partDir;
+  };
+
+  for (const source of walkFiles(runtimeDir)) {
+    const relative = path.relative(runtimeDir, source).split(path.sep).join('/');
+    const size = statSync(source).size;
+    if (size > partBytes) {
+      currentDir = null;
+      currentSize = 0;
+      const fd = openSync(source, 'r');
+      try {
+        let partIndex = 0;
+        let offset = 0;
+        while (offset < size) {
+          const length = Math.min(partBytes, size - offset);
+          const buffer = Buffer.allocUnsafe(length);
+          const bytesRead = readSync(fd, buffer, 0, length, offset);
+          if (bytesRead <= 0) {
+            break;
+          }
+          const partDir = startPart();
+          writeChunk(
+            path.join(
+              partDir,
+              'payload',
+              'chunks',
+              `${relative}.part${String(partIndex).padStart(3, '0')}`,
+            ),
+            buffer.subarray(0, bytesRead),
+          );
+          offset += bytesRead;
+          partIndex += 1;
+        }
+      } finally {
+        closeSync(fd);
+      }
+      continue;
+    }
+    if (currentDir === null || currentSize + size > partBytes) {
+      currentDir = startPart();
+      currentSize = 0;
+    }
+    copyPayloadFile(source, path.join(currentDir, 'payload', 'files', relative));
+    currentSize += size;
+  }
+
+  if (partDirs.length === 0) {
+    throw new Error(`${product}@${version} generated no native extension Cargo part crates`);
+  }
+  return partDirs;
+}
+
+const NATIVE_EXTENSION_AGGREGATOR_BUILD_RS = String.raw`use std::collections::BTreeMap;
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+const SCHEMA: &str = __SCHEMA__;
+const PRODUCT: &str = __PRODUCT__;
+const VERSION: &str = env!("CARGO_PKG_VERSION");
+const KIND: &str = "extension";
+const TARGET: &str = __TARGET__;
+const RUNTIME_PRODUCT: &str = __RUNTIME_PRODUCT__;
+const RUNTIME_VERSION: &str = __RUNTIME_VERSION__;
+const EXTENSIONS: &[&str] = &[
+__EXTENSIONS__
+];
+const EXTENSION_DEPENDENCIES: &[(&str, &[&str])] = &[
+__EXTENSION_DEPENDENCIES__
+];
+const PART_ROOTS: &[&str] = &[
+__PART_ROOTS__
+];
+
+fn main() {
+    emit_manifest();
+}
+
+fn emit_manifest() {
+    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set"));
+    let payload = out_dir.join("payload");
+    if payload.exists() {
+        fs::remove_dir_all(&payload).expect("remove stale Oliphaunt extension payload");
+    }
+    fs::create_dir_all(&payload).expect("create Oliphaunt extension payload directory");
+
+    let part_roots = part_roots();
+    if part_roots.is_empty() {
+        if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+            panic!("missing Oliphaunt extension payload part crates");
+        }
+        return;
+    }
+
+    let mut chunk_files: BTreeMap> = BTreeMap::new();
+    for root in part_roots {
+        println!("cargo::rerun-if-changed={}", root.display());
+        copy_complete_files(&root.join("files"), &payload).expect("copy complete extension payload files");
+        collect_chunks(&root.join("chunks"), &root.join("chunks"), &mut chunk_files)
+            .expect("collect extension payload chunks");
+    }
+
+    for (relative, mut chunks) in chunk_files {
+        chunks.sort_by_key(|(index, _)| *index);
+        for (expected, (actual, _)) in chunks.iter().enumerate() {
+            if *actual != expected {
+                panic!("non-contiguous Oliphaunt extension chunk indexes for {relative}");
+            }
+        }
+        let output = payload.join(&relative);
+        if let Some(parent) = output.parent() {
+            fs::create_dir_all(parent).expect("create reconstructed extension file parent");
+        }
+        let mut writer = fs::File::create(&output).expect("create reconstructed extension payload file");
+        for (_, path) in chunks {
+            let mut reader = fs::File::open(&path).expect("open extension payload chunk");
+            io::copy(&mut reader, &mut writer).expect("append extension payload chunk");
+        }
+    }
+
+    let files = collect_files(&payload).expect("collect reconstructed extension payload files");
+    if files.is_empty() {
+        panic!("Oliphaunt extension payload part crates produced no files");
+    }
+    let manifest = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {SCHEMA:?}\nproduct = {PRODUCT:?}\nversion = {VERSION:?}\nkind = {KIND:?}\ntarget = {TARGET:?}\nruntime-product = {RUNTIME_PRODUCT:?}\nruntime-version = {RUNTIME_VERSION:?}\n"
+    );
+    if SCHEMA == "oliphaunt-artifact-manifest-v1" {
+        if EXTENSIONS.len() != 1 {
+            panic!("v1 extension manifest requires exactly one member");
+        }
+        text.push_str(&format!("extension = {:?}\n", EXTENSIONS[0]));
+        append_dependencies(&mut text, EXTENSIONS[0]);
+        append_manifest_files(&mut text, &payload, "[[files]]");
+    } else if SCHEMA == "oliphaunt-artifact-manifest-v2" {
+        let extensions_root = payload.join("extensions");
+        let actual_members = directory_names(&extensions_root).expect("read reconstructed extension bundle members");
+        let expected_members: Vec = EXTENSIONS.iter().map(|value| (*value).to_owned()).collect();
+        if actual_members != expected_members {
+            panic!("reconstructed extension bundle member set mismatch: expected {expected_members:?}, got {actual_members:?}");
+        }
+        for extension in EXTENSIONS {
+            text.push_str(&format!("\n[[extensions]]\nextension = {extension:?}\n"));
+            append_dependencies(&mut text, extension);
+            append_manifest_files(&mut text, &extensions_root.join(extension), "[[extensions.files]]");
+        }
+    } else {
+        panic!("unsupported extension artifact manifest schema {SCHEMA}");
+    }
+    fs::write(&manifest, text).expect("write Oliphaunt extension artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest.display());
+}
+
+fn append_dependencies(text: &mut String, extension: &str) {
+    let dependencies = EXTENSION_DEPENDENCIES.iter()
+        .find(|(candidate, _)| *candidate == extension)
+        .map(|(_, dependencies)| *dependencies)
+        .unwrap_or_else(|| panic!("missing dependency metadata for extension {extension}"));
+    text.push_str(&format!("dependencies = {dependencies:?}\n"));
+}
+
+fn append_manifest_files(text: &mut String, root: &Path, table: &str) {
+    let files = collect_files(root).expect("collect extension member payload files");
+    if files.is_empty() {
+        panic!("Oliphaunt extension member payload produced no files under {}", root.display());
+    }
+    for file in files {
+        let relative = file.strip_prefix(root)
+            .expect("payload file stays under member root")
+            .to_string_lossy()
+            .replace(std::path::MAIN_SEPARATOR, "/");
+        let sha256 = sha256_file(&file).expect("hash extension payload file");
+        text.push_str(&format!(
+            "\n{table}\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(), relative, sha256,
+        ));
+    }
+}
+
+fn directory_names(root: &Path) -> io::Result> {
+    let mut names = Vec::new();
+    for entry in fs::read_dir(root)? {
+        let entry = entry?;
+        if entry.file_type()?.is_dir() {
+            names.push(entry.file_name().to_string_lossy().into_owned());
+        }
+    }
+    names.sort();
+    Ok(names)
+}
+
+fn part_roots() -> Vec {
+    PART_ROOTS.iter().map(PathBuf::from).collect()
+}
+
+fn copy_complete_files(source: &Path, destination: &Path) -> io::Result<()> {
+    if !source.is_dir() {
+        return Ok(());
+    }
+    for entry in fs::read_dir(source)? {
+        let entry = entry?;
+        let path = entry.path();
+        let output = destination.join(path.strip_prefix(source).unwrap_or(&path));
+        copy_tree_entry(&path, &output)?;
+    }
+    Ok(())
+}
+
+fn copy_tree_entry(source: &Path, destination: &Path) -> io::Result<()> {
+    let metadata = fs::metadata(source)?;
+    if metadata.is_dir() {
+        fs::create_dir_all(destination)?;
+        for entry in fs::read_dir(source)? {
+            let entry = entry?;
+            copy_tree_entry(&entry.path(), &destination.join(entry.file_name()))?;
+        }
+    } else if metadata.is_file() {
+        if let Some(parent) = destination.parent() {
+            fs::create_dir_all(parent)?;
+        }
+        fs::copy(source, destination)?;
+    }
+    Ok(())
+}
+
+fn collect_chunks(
+    root: &Path,
+    current: &Path,
+    chunks: &mut BTreeMap>,
+) -> io::Result<()> {
+    if !current.is_dir() {
+        return Ok(());
+    }
+    for entry in fs::read_dir(current)? {
+        let entry = entry?;
+        let path = entry.path();
+        let metadata = fs::metadata(&path)?;
+        if metadata.is_dir() {
+            collect_chunks(root, &path, chunks)?;
+            continue;
+        }
+        if !metadata.is_file() {
+            continue;
+        }
+        let relative = path.strip_prefix(root).unwrap_or(&path).to_string_lossy().replace(std::path::MAIN_SEPARATOR, "/");
+        let (file_relative, part_index) = split_part_relative(&relative)
+            .unwrap_or_else(|| panic!("invalid Oliphaunt extension chunk file name {relative}"));
+        chunks.entry(file_relative).or_default().push((part_index, path));
+    }
+    Ok(())
+}
+
+fn split_part_relative(relative: &str) -> Option<(String, usize)> {
+    let (file, index) = relative.rsplit_once(".part")?;
+    if file.is_empty() || index.len() != 3 || !index.bytes().all(|byte| byte.is_ascii_digit()) {
+        return None;
+    }
+    Some((file.to_owned(), index.parse().ok()?))
+}
+
+fn collect_files(root: &Path) -> io::Result> {
+    let mut files = Vec::new();
+    collect_files_inner(root, &mut files)?;
+    files.sort();
+    Ok(files)
+}
+
+fn collect_files_inner(path: &Path, files: &mut Vec) -> io::Result<()> {
+    if !path.is_dir() {
+        return Ok(());
+    }
+    for entry in fs::read_dir(path)? {
+        let entry = entry?;
+        let entry_path = entry.path();
+        let metadata = fs::metadata(&entry_path)?;
+        if metadata.is_dir() {
+            collect_files_inner(&entry_path, files)?;
+        } else if metadata.is_file() {
+            files.push(entry_path);
+        }
+    }
+    Ok(())
+}
+
+${RUST_BUILD_SCRIPT_SHA256}
+`;
+
+export function exactNativeExtensionMemberDependencies(members, memberDependencies) {
+  if (
+    !Array.isArray(members) ||
+    members.length === 0 ||
+    members.some((member) => typeof member !== 'string' || member.length === 0) ||
+    new Set(members).size !== members.length
+  ) {
+    throw new Error(`${TOOL}: native extension members must be a non-empty, unique string list`);
+  }
+  if (
+    memberDependencies === null ||
+    typeof memberDependencies !== 'object' ||
+    Array.isArray(memberDependencies)
+  ) {
+    throw new Error(
+      `${TOOL}: native extension member dependencies must be an object keyed by every exact member`,
+    );
+  }
+
+  const expectedMembers = [...members].sort(compareText);
+  const actualMembers = Object.keys(memberDependencies).sort(compareText);
+  const missing = expectedMembers.filter((member) => !Object.hasOwn(memberDependencies, member));
+  const extra = actualMembers.filter((member) => !expectedMembers.includes(member));
+  if (missing.length > 0 || extra.length > 0) {
+    throw new Error(
+      `${TOOL}: native extension member dependency keys must exactly match members; missing=${JSON.stringify(missing)}, extra=${JSON.stringify(extra)}`,
+    );
+  }
+
+  return members.map((member) => {
+    const dependencies = memberDependencies[member];
+    if (
+      !Array.isArray(dependencies) ||
+      dependencies.some((dependency) => typeof dependency !== 'string' || dependency.length === 0)
+    ) {
+      throw new Error(
+        `${TOOL}: native extension member ${member} dependencies must be a string list`,
+      );
+    }
+    const normalized = [...new Set(dependencies)].sort(compareText);
+    if (
+      JSON.stringify(normalized) !== JSON.stringify(dependencies) ||
+      dependencies.includes(member)
+    ) {
+      throw new Error(
+        `${TOOL}: native extension member ${member} dependencies must be sorted, unique, and exclude itself`,
+      );
+    }
+    return [member, normalized];
+  });
+}
+
+export function writeNativeExtensionSplitAggregatorCrate(
+  crateDir,
+  {
+    product,
+    version,
+    members,
+    memberDependencies,
+    target,
+    triple,
+    runtimeProduct,
+    runtimeVersion,
+    partDirs,
+  },
+) {
+  const legal = nativeExtensionCarrierLegal(product, members, { carriesPayload: false });
+  const name = nativeExtensionCargoPackageName(product, target);
+  const links = nativeExtensionCargoLinksName(product, target);
+  const subject = members.length === 1 ? members[0] : `${members.length}-member bundle`;
+  const dependencyRows = exactNativeExtensionMemberDependencies(members, memberDependencies);
+  rmSync(path.join(crateDir, 'payload'), { recursive: true, force: true });
+  const dependencyLines = [];
+  const partRoots = [];
+  for (let offset = 0; offset < partDirs.length; offset += 1) {
+    const dependencyName = nativeExtensionCargoPartPackageName(product, target, offset + 1);
+    const dependencyPath = path.relative(crateDir, partDirs[offset]).split(path.sep).join('/');
+    dependencyLines.push(
+      `${dependencyName} = { version = "=${version}", path = "${dependencyPath}" }`,
+    );
+    partRoots.push(`    ${rustCrateIdent(dependencyName)}::PAYLOAD_ROOT,`);
+  }
+  writeFileSync(
+    path.join(crateDir, 'Cargo.toml'),
+    `[package]
+name = "${name}"
+version = "${version}"
+edition = "2024"
+rust-version = "1.93"
+description = "Cargo artifact crate for the ${subject} Oliphaunt native extension carrier on ${target}."
+readme = "README.md"
+repository = "https://github.com/f0rr0/oliphaunt"
+homepage = "https://oliphaunt.dev"
+license = ${tomlString(legal.packageSpdx)}
+links = "${links}"
+build = "build.rs"
+include = ${tomlString(['Cargo.toml', 'README.md', 'build.rs', 'src/**', ...carrierLegalMembers(legal)])}
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+sha2 = "0.10"
+${dependencyLines.join('\n')}
+
+[workspace]
+`,
+  );
+  writeFileSync(
+    path.join(crateDir, 'build.rs'),
+    NATIVE_EXTENSION_AGGREGATOR_BUILD_RS.replace(
+      '__SCHEMA__',
+      tomlString(
+        members.length > 1 ? 'oliphaunt-artifact-manifest-v2' : 'oliphaunt-artifact-manifest-v1',
+      ),
+    )
+      .replace('__PRODUCT__', tomlString(product))
+      .replace('__TARGET__', tomlString(triple))
+      .replace('__RUNTIME_PRODUCT__', tomlString(runtimeProduct))
+      .replace('__RUNTIME_VERSION__', tomlString(runtimeVersion))
+      .replace('__EXTENSIONS__', members.map((member) => `    ${tomlString(member)},`).join('\n'))
+      .replace(
+        '__EXTENSION_DEPENDENCIES__',
+        dependencyRows
+          .map(
+            ([member, dependencies]) =>
+              `    (${tomlString(member)}, &[${dependencies.map((dependency) => tomlString(dependency)).join(', ')}]),`,
+          )
+          .join('\n'),
+      )
+      .replace('__PART_ROOTS__', partRoots.join('\n')),
+  );
+  stageExtensionCarrierLegal(crateDir, legal);
+  return legal;
+}
+
+function cargoPackage(crateDir, targetDir, legal) {
+  const manifest = path.join(crateDir, 'Cargo.toml');
+  const { name, version } = readCargoPackageNameVersion(manifest, { fail: localFail, rel });
+  const cratePath = packageGeneratedCargoSource(
+    manifest,
+    path.join(targetDir, 'strict-package', name),
+    {
+      fail: localFail,
+      rel,
+      // The caller splits using the finished archive's compressed size.
+      packageSizeLimitBytes: Number.MAX_SAFE_INTEGER,
+    },
+  );
+  assertExtensionCarrierArchive(cratePath, legal, `${name}-${version}`);
+  return cratePath;
+}
+
+function discardCargoPackageArtifact(cratePath) {
+  // packageGeneratedCargoSource gives each generated crate a dedicated output
+  // directory containing the archive and its verification stage.
+  rmSync(path.dirname(cratePath), { recursive: true, force: true });
+}
+
+function stageNativeExtensionCargoPayload(crateDir, runtimeSet, { target, nativeRuntimeVersion }) {
+  const payload = path.join(crateDir, 'payload');
+  rmSync(payload, { recursive: true, force: true });
+  if (!runtimeSet.bundle) {
+    extractExtensionRuntime(runtimeSet.members[0].archive, payload, {
+      metadata: runtimeSet.members[0].metadata,
+      target,
+      nativeRuntimeVersion,
+    });
+    return payload;
+  }
+  const temp = archiveTempDir();
+  try {
+    for (const member of runtimeSet.members) {
+      const archive = materializeBundleMemberArchive(
+        runtimeSet,
+        member,
+        path.join(temp, `${member.sqlName}.tar.gz`),
+      );
+      extractExtensionRuntime(archive, path.join(payload, 'extensions', member.sqlName), {
+        metadata: member.metadata,
+        target,
+        nativeRuntimeVersion,
+      });
+    }
+  } finally {
+    rmSync(temp, { recursive: true, force: true });
+  }
+  return payload;
+}
+
+function writeNativeExtensionCargoCrate(
+  crateDir,
+  {
+    product,
+    version,
+    members,
+    memberDependencies,
+    target,
+    triple,
+    runtimeProduct,
+    runtimeVersion,
+    runtimeSet,
+  },
+) {
+  const legal = nativeExtensionCarrierLegal(product, members, { target, carriesPayload: true });
+  const name = nativeExtensionCargoPackageName(product, target);
+  const links = nativeExtensionCargoLinksName(product, target);
+  const subject = members.length === 1 ? members[0] : `${members.length}-member bundle`;
+  const dependencyRows = exactNativeExtensionMemberDependencies(members, memberDependencies);
+  const runtimeDir = stageNativeExtensionCargoPayload(crateDir, runtimeSet, {
+    target,
+    nativeRuntimeVersion: runtimeVersion,
+  });
+  if (walkFiles(runtimeDir).length === 0) {
+    throw new Error(`${product}@${version} did not contain extension runtime files`);
+  }
+  mkdirSync(path.join(crateDir, 'src'), { recursive: true });
+  writeFileSync(
+    path.join(crateDir, 'README.md'),
+    `# ${name}
+
+Cargo artifact crate for the ${subject} Oliphaunt native extension carrier on \`${target}\`.
+`,
+  );
+  writeFileSync(
+    path.join(crateDir, 'Cargo.toml'),
+    `[package]
+name = "${name}"
+version = "${version}"
+edition = "2024"
+rust-version = "1.93"
+description = "Cargo artifact crate for the ${subject} Oliphaunt native extension carrier on ${target}."
+readme = "README.md"
+repository = "https://github.com/f0rr0/oliphaunt"
+homepage = "https://oliphaunt.dev"
+license = ${tomlString(legal.packageSpdx)}
+links = "${links}"
+build = "build.rs"
+include = ${tomlString(['Cargo.toml', 'README.md', 'build.rs', 'src/**', 'payload/**', ...carrierLegalMembers(legal)])}
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+sha2 = "0.10"
+
+[workspace]
+`,
+  );
+  writeFileSync(
+    path.join(crateDir, 'src/lib.rs'),
+    `pub const PRODUCT: &str = "${product}";
+pub const KIND: &str = "extension";
+pub const MEMBERS: &[&str] = &[${members.map((member) => JSON.stringify(member)).join(', ')}];
+pub const RELEASE_TARGET: &str = "${target}";
+pub const CARGO_TARGET: &str = "${triple}";
+`,
+  );
+  writeFileSync(
+    path.join(crateDir, 'build.rs'),
+    `use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+const SCHEMA: &str = ${JSON.stringify(members.length > 1 ? 'oliphaunt-artifact-manifest-v2' : 'oliphaunt-artifact-manifest-v1')};
+const PRODUCT: &str = ${JSON.stringify(product)};
+const VERSION: &str = env!("CARGO_PKG_VERSION");
+const KIND: &str = "extension";
+const TARGET: &str = ${JSON.stringify(triple)};
+const RUNTIME_PRODUCT: &str = ${JSON.stringify(runtimeProduct)};
+const RUNTIME_VERSION: &str = ${JSON.stringify(runtimeVersion)};
+const EXTENSIONS: &[&str] = &[${members.map((member) => JSON.stringify(member)).join(', ')}];
+const EXTENSION_DEPENDENCIES: &[(&str, &[&str])] = &[${dependencyRows.map(([member, dependencies]) => `(${JSON.stringify(member)}, &[${dependencies.map((dependency) => JSON.stringify(dependency)).join(', ')}])`).join(', ')}];
+
+fn main() {
+    let manifest_dir =
+        PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set"));
+    let payload = manifest_dir.join("payload");
+    println!("cargo::rerun-if-changed={}", payload.display());
+    if !payload.is_dir() {
+        if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+            panic!("missing packaged extension payload under {}", payload.display());
+        }
+        return;
+    }
+    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set"));
+    let manifest = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {SCHEMA:?}\\nproduct = {PRODUCT:?}\\nversion = {VERSION:?}\\nkind = {KIND:?}\\ntarget = {TARGET:?}\\nruntime-product = {RUNTIME_PRODUCT:?}\\nruntime-version = {RUNTIME_VERSION:?}\\n"
+    );
+    if SCHEMA == "oliphaunt-artifact-manifest-v1" {
+        if EXTENSIONS.len() != 1 { panic!("v1 extension manifest requires exactly one member"); }
+        text.push_str(&format!("extension = {:?}\\n", EXTENSIONS[0]));
+        append_dependencies(&mut text, EXTENSIONS[0]);
+        append_manifest_files(&mut text, &payload, "[[files]]");
+    } else {
+        let extensions_root = payload.join("extensions");
+        let mut actual_members: Vec = fs::read_dir(&extensions_root)
+            .expect("read extension bundle members")
+            .filter_map(|entry| entry.ok())
+            .filter(|entry| entry.file_type().map(|kind| kind.is_dir()).unwrap_or(false))
+            .map(|entry| entry.file_name().to_string_lossy().into_owned())
+            .collect();
+        actual_members.sort();
+        let expected_members: Vec = EXTENSIONS.iter().map(|value| (*value).to_owned()).collect();
+        if actual_members != expected_members {
+            panic!("extension bundle member set mismatch: expected {expected_members:?}, got {actual_members:?}");
+        }
+        for extension in EXTENSIONS {
+            text.push_str(&format!("\\n[[extensions]]\\nextension = {extension:?}\\n"));
+            append_dependencies(&mut text, extension);
+            append_manifest_files(&mut text, &extensions_root.join(extension), "[[extensions.files]]");
+        }
+    }
+    fs::write(&manifest, text).expect("write Oliphaunt extension artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest.display());
+}
+
+fn append_dependencies(text: &mut String, extension: &str) {
+    let dependencies = EXTENSION_DEPENDENCIES.iter()
+        .find(|(candidate, _)| *candidate == extension)
+        .map(|(_, dependencies)| *dependencies)
+        .unwrap_or_else(|| panic!("missing dependency metadata for extension {extension}"));
+    text.push_str(&format!("dependencies = {dependencies:?}\\n"));
+}
+
+fn append_manifest_files(text: &mut String, root: &Path, table: &str) {
+    let files = payload_files(root);
+    if files.is_empty() { panic!("empty extension payload under {}", root.display()); }
+    for file in files {
+        let relative = file
+            .strip_prefix(root)
+            .expect("payload file stays under member root")
+            .to_string_lossy()
+            .replace(std::path::MAIN_SEPARATOR, "/");
+        let sha256 = sha256_file(&file).expect("hash payload file");
+        text.push_str(&format!(
+            "\\n{table}\\nsource = {:?}\\nrelative = {:?}\\nsha256 = {sha256:?}\\nexecutable = false\\n",
+            file.display().to_string(),
+            relative,
+        ));
+    }
+}
+
+fn payload_files(root: &Path) -> Vec {
+    let mut files = Vec::new();
+    collect_payload_files(root, &mut files);
+    files.sort();
+    files
+}
+
+fn collect_payload_files(root: &Path, files: &mut Vec) {
+    for entry in fs::read_dir(root).expect("read payload directory") {
+        let path = entry.expect("read payload entry").path();
+        if path.is_dir() {
+            collect_payload_files(&path, files);
+        } else if path.is_file() {
+            files.push(path);
+        }
+    }
+}
+
+${RUST_BUILD_SCRIPT_SHA256}
+`,
+  );
+  stageExtensionCarrierLegal(crateDir, legal);
+  return legal;
+}
+
+export function packageNativeExtensionCargoCrates(roots, stagingRoot, target, strict, result) {
+  if (target === null) {
+    result.skipped.push('current host does not map to a supported native extension Cargo target');
+    return [];
+  }
+  const triple = cargoTargetTriple(target);
+  if (triple === null) {
+    result.skipped.push(`unsupported native extension Cargo target ${target}`);
+    return [];
+  }
+  const manifests = discoverExtensionManifests(roots);
+  if (manifests.length === 0) {
+    result.skipped.push(
+      'no extension-artifacts.json manifests found for native extension Cargo crates',
+    );
+    return [];
+  }
+
+  const sourceRoot = path.join(stagingRoot, 'native-extension-sources');
+  const outputDir = path.join(stagingRoot, 'native-extension-crates');
+  const cargoTargetDir = path.join(stagingRoot, 'native-extension-cargo-target');
+  rmSync(sourceRoot, { recursive: true, force: true });
+  rmSync(outputDir, { recursive: true, force: true });
+  rmSync(cargoTargetDir, { recursive: true, force: true });
+  mkdirSync(sourceRoot, { recursive: true });
+  mkdirSync(outputDir, { recursive: true });
+
+  const outputs = [];
+  const packageOptions = { root: ROOT, fail: localFail, rel };
+  const stagedIdentities = new Map();
+  try {
+    for (const manifestPath of manifests) {
+      const manifest = readJsonFile(manifestPath);
+      const extensionDir = path.dirname(manifestPath);
+      const { product, version } = manifest;
+      const memberRows = extensionManifestMembers(manifest);
+      const members = memberRows.map((member) => member.sqlName);
+      if (
+        ![product, version].every((value) => typeof value === 'string' && value.length > 0) ||
+        members.length === 0
+      ) {
+        result.skipped.push(
+          `${rel(manifestPath)} is missing product, version, or exact member rows`,
+        );
+        continue;
+      }
+      const memberDependencies = Object.fromEntries(
+        memberRows.map((member) => {
+          if (
+            !Array.isArray(member.dependencies) ||
+            member.dependencies.some((dependency) => typeof dependency !== 'string' || !dependency)
+          ) {
+            fail(
+              TOOL,
+              `${product}@${version} member ${member.sqlName} has invalid dependency metadata`,
+            );
+          }
+          const dependencies = [...new Set(member.dependencies)].sort(compareText);
+          if (
+            JSON.stringify(dependencies) !== JSON.stringify(member.dependencies) ||
+            dependencies.includes(member.sqlName)
+          ) {
+            fail(
+              TOOL,
+              `${product}@${version} member ${member.sqlName} dependencies must be sorted, unique, and exclude itself`,
+            );
+          }
+          return [member.sqlName, dependencies];
+        }),
+      );
+      const releaseManifest = extensionReleaseManifest(extensionDir, product, version);
+      const runtimeSet = extensionRuntimeAssets(extensionDir, manifest, releaseManifest, target);
+      if (runtimeSet === null) {
+        result.skipped.push(
+          `${product}@${version} has no complete ${target} native runtime member set`,
+        );
+        continue;
+      }
+      const runtimeProduct = runtimeSet.compatibility.nativeRuntimeProduct;
+      const runtimeVersion = runtimeSet.compatibility.nativeRuntimeVersion;
+      const identity = `${product}@${version}:${target}`;
+      const digest = JSON.stringify({
+        compatibility: runtimeSet.compatibility,
+        members: runtimeSet.members.map(({ metadata: inventory, asset }) => ({
+          inventory,
+          sha256: asset.sha256,
+          bytes: asset.bytes,
+        })),
+        carrier:
+          runtimeSet.carrier === undefined
+            ? null
+            : { sha256: runtimeSet.carrier.sha256, bytes: runtimeSet.carrier.bytes },
+      });
+      if (stagedIdentities.has(identity)) {
+        if (stagedIdentities.get(identity) !== digest) {
+          fail(TOOL, `conflicting native extension Cargo packages discovered for ${identity}`);
+        }
+        result.skipped.push(
+          `deduplicated byte-identical native extension Cargo package ${identity}`,
+        );
+        continue;
+      }
+      stagedIdentities.set(identity, digest);
+      const name = nativeExtensionCargoPackageName(product, target);
+      const crateDir = path.join(sourceRoot, name);
+      try {
+        const crateLegal = writeNativeExtensionCargoCrate(crateDir, {
+          product,
+          version,
+          members,
+          memberDependencies,
+          target,
+          triple,
+          runtimeProduct,
+          runtimeVersion,
+          runtimeSet,
+        });
+        let cratePath = cargoPackage(crateDir, cargoTargetDir, crateLegal);
+        let size = statSync(cratePath).size;
+        if (size > CARGO_EXTENSION_SPLIT_THRESHOLD_BYTES) {
+          discardCargoPackageArtifact(cratePath);
+          const partDirs = fitCargoPayloadParts(
+            (partBytes) =>
+              buildNativeExtensionPartCrates(path.join(crateDir, 'payload'), sourceRoot, {
+                product,
+                version,
+                members,
+                memberDependencies,
+                target,
+                partBytes,
+              }),
+            (partDir) =>
+              packageGeneratedCargoSource(
+                path.join(partDir, 'Cargo.toml'),
+                path.join(cargoTargetDir, 'size-probe'),
+                { ...packageOptions, packageSizeLimitBytes: Number.MAX_SAFE_INTEGER },
+              ),
+          );
+          const partLegal = nativeExtensionCarrierLegal(product, members, {
+            target,
+            carriesPayload: true,
+          });
+          const aggregatorLegal = writeNativeExtensionSplitAggregatorCrate(crateDir, {
+            product,
+            version,
+            members,
+            memberDependencies,
+            target,
+            triple,
+            runtimeProduct,
+            runtimeVersion,
+            partDirs,
+          });
+          let partFailed = false;
+          for (const partDir of partDirs) {
+            const partCratePath = path.join(
+              cargoTargetDir,
+              'size-probe',
+              path.basename(partDir) + '-' + version + '.crate',
+            );
+            assertExtensionCarrierArchive(
+              partCratePath,
+              partLegal,
+              path.basename(partCratePath, '.crate'),
+            );
+            const partSize = statSync(partCratePath).size;
+            if (partSize > CARGO_PACKAGE_SIZE_LIMIT_BYTES) {
+              const message = `${rel(partCratePath)} is ${partSize} bytes, above the crates.io 10 MiB package limit`;
+              result.skipped.push(message);
+              if (strict) {
+                fail(TOOL, message);
+              }
+              partFailed = true;
+              continue;
+            }
+            const output = path.join(outputDir, path.basename(partCratePath));
+            copyFileSync(partCratePath, output);
+            outputs.push(output);
+          }
+          if (partFailed) {
+            continue;
+          }
+          cratePath = packageGeneratedCargoSource(
+            path.join(crateDir, 'Cargo.toml'),
+            path.join(cargoTargetDir, 'manual-package'),
+            packageOptions,
+          );
+          assertExtensionCarrierArchive(
+            cratePath,
+            aggregatorLegal,
+            path.basename(cratePath, '.crate'),
+          );
+          size = statSync(cratePath).size;
+          if (size > CARGO_PACKAGE_SIZE_LIMIT_BYTES) {
+            const message = `${rel(cratePath)} is ${size} bytes after splitting, above the crates.io 10 MiB package limit`;
+            result.skipped.push(message);
+            if (strict) {
+              fail(TOOL, message);
+            }
+            continue;
+          }
+          if (partDirs.length === 0 || partDirs.length > 999) {
+            fail(
+              TOOL,
+              `${product}@${version} generated invalid Cargo payload part count ${partDirs.length}`,
+            );
+          }
+        }
+        if (size > CARGO_PACKAGE_SIZE_LIMIT_BYTES) {
+          fail(
+            TOOL,
+            `${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit`,
+          );
+        }
+        const output = path.join(outputDir, path.basename(cratePath));
+        copyFileSync(cratePath, output);
+        outputs.push(output);
+      } catch (error) {
+        const message = error instanceof Error ? error.message : String(error);
+        result.skipped.push(message);
+        if (strict) {
+          throw error;
+        }
+      }
+    }
+    result.staged.push(...outputs.map(rel));
+    return outputs;
+  } finally {
+    // Only final carriers belong in recursive publication inventory scans.
+    rmSync(sourceRoot, { recursive: true, force: true });
+    rmSync(cargoTargetDir, { recursive: true, force: true });
+  }
+}
diff --git a/src/extensions/artifacts/packages/tools/package-mobile-release-assets.sh b/src/extensions/artifacts/packages/tools/package-mobile-release-assets.sh
index 3f7906008..54ccdc0dc 100755
--- a/src/extensions/artifacts/packages/tools/package-mobile-release-assets.sh
+++ b/src/extensions/artifacts/packages/tools/package-mobile-release-assets.sh
@@ -27,7 +27,7 @@ if ((${#products[@]} > 0)); then
     product="$(printf '%s' "$product" | xargs)"
     [ -n "$product" ] || continue
     args+=("$product")
-    validation_args+=(--require-extension-product "$product")
+    validation_args+=("$product")
   done
 fi
 
@@ -66,7 +66,7 @@ case " ${args[*]} " in
 esac
 
 artifact_root=target/mobile-extension-artifacts
-tools/dev/bun.sh tools/release/build-extension-ci-artifacts.mjs \
+tools/dev/bun.sh src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts \
   --output-root "$artifact_root" --family native "${args[@]}"
 OLIPHAUNT_EXTENSION_ARTIFACT_ROOT="$artifact_root" \
-  tools/dev/bun.sh tools/release/check-staged-artifacts.mjs --family native "${validation_args[@]}"
+  tools/dev/bun.sh src/extensions/artifacts/packages/tools/check-carriers.mts --family native "${validation_args[@]}"
diff --git a/src/extensions/artifacts/packages/tools/package-release-assets.sh b/src/extensions/artifacts/packages/tools/package-release-assets.sh
index 7034021b4..2b0be297b 100755
--- a/src/extensions/artifacts/packages/tools/package-release-assets.sh
+++ b/src/extensions/artifacts/packages/tools/package-release-assets.sh
@@ -14,12 +14,12 @@ if ((${#products[@]} > 0)); then
   for product in "${products[@]}"; do
     product="$(printf '%s' "$product" | xargs)"
     [ -n "$product" ] || continue
-    validation_args+=(--require-extension-product "$product")
+    validation_args+=("$product")
   done
 fi
 if [ "${#validation_args[@]}" -eq 1 ]; then
-  validation_args+=(--require-extension-product all)
+  validation_args+=(all)
 fi
 
-tools/dev/bun.sh tools/release/build-extension-ci-artifacts.mjs --all --require-native --require-wasix
-tools/dev/bun.sh tools/release/check-staged-artifacts.mjs "${validation_args[@]}"
+tools/dev/bun.sh src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts --all --require-native --require-wasix
+tools/dev/bun.sh src/extensions/artifacts/packages/tools/check-carriers.mts "${validation_args[@]}"
diff --git a/src/extensions/artifacts/packages/tools/test.sh b/src/extensions/artifacts/packages/tools/test.sh
new file mode 100644
index 000000000..5cdde75b0
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/test.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+if [[ "${1:-}" != --context ]]; then
+  exec bash tools/ci/with-projects.sh --exec bash src/extensions/artifacts/packages/tools/test.sh --context
+fi
+for test_file in src/extensions/artifacts/packages/tools/*.test.mts; do
+  [[ -f "${test_file%.mts}.sh" ]] || bun test --timeout=120000 "./$test_file"
+done
+for test_file in src/extensions/artifacts/packages/tools/*.test.sh; do
+  bash "$test_file"
+done
diff --git a/src/extensions/artifacts/packages/tools/testdata/inspect-wasix-descriptor.mts b/src/extensions/artifacts/packages/tools/testdata/inspect-wasix-descriptor.mts
new file mode 100644
index 000000000..a32499c8d
--- /dev/null
+++ b/src/extensions/artifacts/packages/tools/testdata/inspect-wasix-descriptor.mts
@@ -0,0 +1,32 @@
+import { createHash } from 'node:crypto';
+import { readFileSync } from 'node:fs';
+import { pathToFileURL } from 'node:url';
+export async function inspectDescriptor(entrypoint) {
+  const descriptor = (await import(pathToFileURL(entrypoint).href)).default;
+  if (!Object.isFrozen(descriptor) || !Object.isFrozen(descriptor.carriers))
+    throw new Error('descriptor is mutable');
+  function assertDeepFrozen(value, label) {
+    if (value !== null && typeof value === 'object') {
+      if (!Object.isFrozen(value)) throw new Error(label + ' is mutable');
+      for (const [key, child] of Object.entries(value)) assertDeepFrozen(child, label + '.' + key);
+    }
+  }
+  assertDeepFrozen(descriptor.compatibility, 'compatibility');
+  const carriers = descriptor.carriers.map((carrier) => {
+    if (!Object.isFrozen(carrier)) throw new Error('carrier is mutable');
+    assertDeepFrozen(carrier.install, 'carrier.install');
+    const bytes = readFileSync(carrier.source);
+    const sha256 = createHash('sha256').update(bytes).digest('hex');
+    if (bytes.length !== carrier.size || sha256 !== carrier.sha256)
+      throw new Error('carrier integrity mismatch');
+    return {
+      ...carrier,
+      source: carrier.source.href,
+      actualSha256: sha256,
+      actualSize: bytes.length,
+    };
+  });
+  return { descriptor: { ...descriptor, carriers }, frozen: true };
+}
+if (process.argv[1]?.endsWith('/inspect-wasix-descriptor.mts'))
+  await inspectDescriptor(process.argv[2]);
diff --git a/src/extensions/artifacts/wasix/moon.yml b/src/extensions/artifacts/wasix/moon.yml
index b5478a345..02b966fb3 100644
--- a/src/extensions/artifacts/wasix/moon.yml
+++ b/src/extensions/artifacts/wasix/moon.yml
@@ -4,10 +4,8 @@ id: "extension-artifacts-wasix"
 language: "unknown"
 layer: "tool"
 stack: "systems"
-tags: ["extensions", "artifacts", "wasix"]
+tags: ["javascript-quality", "extensions", "artifacts", "wasix"]
 dependsOn:
-  - id: "artifact-packaging"
-    scope: "build"
   - id: "extension-runtime-contract"
     scope: "build"
   - id: "extensions"
@@ -23,20 +21,33 @@ project:
   owner: "oliphaunt"
 
 tasks:
+  compiler-output:
+    tags: ["artifact", "ci-liboliphaunt-wasix-runtime"]
+    command: "bash src/extensions/artifacts/wasix/tools/build-portable.sh"
+    deps: ["liboliphaunt-wasix:runtime-portable"]
+    inputs: ["tools/build-portable.sh", "/src/runtimes/liboliphaunt-wasix/assets/build/**/*", "/src/runtimes/liboliphaunt-wasix/tools/extension-build-scripts.mts", "/src/runtimes/liboliphaunt-wasix/tools/xtask/**/*", {project: "extensions", group: "build"}]
+    outputs: ["/target/extensions/wasix/assets/**/*"]
+    options: {runFromWorkspaceRoot: true, cache: local}
+  build-aot:
+    command: "bash src/extensions/artifacts/wasix/tools/build-aot.sh"
+    deps: ["compiler-output"]
+    tags: ["artifact", "ci-liboliphaunt-wasix-aot"]
+    inputs: ["tools/build-aot.sh", "/src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh", "/src/runtimes/liboliphaunt-wasix/tools/xtask/**/*", "$AOT_TARGET"]
+    outputs: ["/target/extensions/wasix/aot-artifacts/**/*"]
+    options: {runFromWorkspaceRoot: true, cache: local}
   build-target:
     tags: ["release", "artifact-builder", "ci-extension-artifacts-wasix"]
     command: "bash src/extensions/artifacts/wasix/tools/package-release-assets.sh"
     deps:
-      - "liboliphaunt-wasix:runtime-portable"
+      - "compiler-output"
     inputs:
       - project: "extensions"
         group: "build"
       - project: "liboliphaunt-wasix"
         group: "version"
-      - "tools/package-release-assets.mjs"
+      - "tools/package-release-assets.mts"
       - "tools/package-release-assets.sh"
-      - project: "artifact-packaging"
-        group: "source"
+      - "/tools/packaging/*.{mjs,mts}"
       - project: "extension-runtime-contract"
         group: "contract"
     outputs:
diff --git a/src/extensions/artifacts/wasix/tools/build-aot.sh b/src/extensions/artifacts/wasix/tools/build-aot.sh
new file mode 100644
index 000000000..584bb5679
--- /dev/null
+++ b/src/extensions/artifacts/wasix/tools/build-aot.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+export OLIPHAUNT_WASM_BUILD_PROFILE="${ASSET_PROFILE:-release}"
+target="${AOT_TARGET:-$(rustc -vV | awk '/^host:/{print $2}')}"
+host="$(rustc -vV | awk '/^host:/{print $2}')"
+[ "$target" = "$host" ] || { echo "AOT target $target requires its matching builder host, got $host" >&2; exit 1; }
+bash src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh --target-triple "$target" --product extensions
+cargo run -p xtask --locked -- assets package-extension-aot --target-triple "$target"
diff --git a/src/extensions/artifacts/wasix/tools/build-portable.sh b/src/extensions/artifacts/wasix/tools/build-portable.sh
new file mode 100644
index 000000000..af058cbfc
--- /dev/null
+++ b/src/extensions/artifacts/wasix/tools/build-portable.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+export OLIPHAUNT_WASM_BUILD_PROFILE="${ASSET_PROFILE:-release}"
+build=src/runtimes/liboliphaunt-wasix/assets/build
+bash "$build/docker_pgxs_extensions.sh"
+bash "$build/docker_contrib_extensions.sh"
+extension_scripts="$(bun src/runtimes/liboliphaunt-wasix/tools/extension-build-scripts.mts)"
+while IFS= read -r script; do
+  [ -z "$script" ] || bash "$script"
+done <<<"$extension_scripts"
+cargo run -p xtask --locked -- assets package-extensions
diff --git a/src/extensions/artifacts/wasix/tools/package-release-assets.mjs b/src/extensions/artifacts/wasix/tools/package-release-assets.mjs
deleted file mode 100644
index d9f5762e1..000000000
--- a/src/extensions/artifacts/wasix/tools/package-release-assets.mjs
+++ /dev/null
@@ -1,281 +0,0 @@
-#!/usr/bin/env bun
-import { copyFile, mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
-import path from "node:path";
-import process from "node:process";
-
-import {
-  projectWasixExtensionInstallSidecar,
-} from "../../../../shared/extension-runtime-contract/wasix-extension-install.mjs";
-import {
-  loadNativeComponentContract,
-  resolveNativeComponentClosure,
-} from "../../../tools/native-component-contract.mjs";
-const PREFIX = "package-wasix-extension-assets.sh";
-const WASIX_PRODUCT_PATH = "src/runtimes/liboliphaunt/wasix";
-const WASIX_VERSION_PATH = `${WASIX_PRODUCT_PATH}/VERSION`;
-const PRODUCT_METADATA_PATH = "src/extensions/generated/sdk/extensions.json";
-const nativeComponentContract = loadNativeComponentContract();
-
-function fail(message) {
-  console.error(`${PREFIX}: ${message}`);
-  process.exit(2);
-}
-
-function usage() {
-  fail(
-    "usage: package-release-assets.mjs --root PATH --asset-root PATH --metadata PATH --manifest PATH --out-dir PATH --target TARGET --extension-products CSV",
-  );
-}
-
-function optionValue(args, name) {
-  const index = args.indexOf(name);
-  if (index === -1) {
-    usage();
-  }
-  const value = args[index + 1];
-  if (value === undefined || value.startsWith("--")) {
-    usage();
-  }
-  return value;
-}
-
-function parseCsv(value) {
-  return [...new Set(value.split(",").map((item) => item.trim()).filter(Boolean))].sort();
-}
-
-function isObject(value) {
-  return value !== null && typeof value === "object" && !Array.isArray(value);
-}
-
-async function readJson(file) {
-  let value;
-  try {
-    value = JSON.parse(await readFile(file, "utf8"));
-  } catch (error) {
-    fail(`could not read JSON file ${file}: ${error.message}`);
-  }
-  if (!isObject(value)) {
-    fail(`${file} must contain a JSON object`);
-  }
-  return value;
-}
-
-function relativeToRoot(root, file) {
-  return path.relative(root, file).split(path.sep).join("/");
-}
-
-async function releaseVersion(root) {
-  let version;
-  try {
-    version = (await readFile(path.join(root, WASIX_VERSION_PATH), "utf8")).trim();
-  } catch (error) {
-    fail(`could not read ${WASIX_VERSION_PATH}: ${error.message}`);
-  }
-  if (!/^\d+\.\d+\.\d+$/u.test(version)) {
-    fail(`${WASIX_VERSION_PATH} must contain one semantic version`);
-  }
-  return version;
-}
-
-async function selectedSqlNames(root, extensionProductsCsv) {
-  const products = parseCsv(extensionProductsCsv);
-  if (products.length === 0) {
-    return new Set();
-  }
-
-  const metadataPath = path.join(root, PRODUCT_METADATA_PATH);
-  const metadata = await readJson(metadataPath);
-  if (!Array.isArray(metadata.extensions)) {
-    fail(`${PRODUCT_METADATA_PATH} must contain an extensions array`);
-  }
-  const sqlNames = new Set();
-  for (const product of products) {
-    const matches = metadata.extensions.filter((row) => row?.["artifact-product"] === product);
-    if (matches.length === 0) {
-      fail(`${PRODUCT_METADATA_PATH} has no extension rows for product ${product}`);
-    }
-    for (const row of matches) {
-      const sqlName = row["sql-name"];
-      if (typeof sqlName !== "string" || sqlName.length === 0) {
-        fail(`${PRODUCT_METADATA_PATH} has an invalid sql-name for product ${product}`);
-      }
-      sqlNames.add(sqlName);
-    }
-  }
-  return sqlNames;
-}
-
-async function fileSize(file) {
-  try {
-    return (await stat(file)).size;
-  } catch {
-    return undefined;
-  }
-}
-
-function tsvCell(value) {
-  const text = String(value);
-  if (text.includes("\t") || text.includes("\n") || text.includes("\r")) {
-    fail(`TSV field contains unsupported whitespace: ${JSON.stringify(text)}`);
-  }
-  return text;
-}
-
-const args = process.argv.slice(2);
-const root = path.resolve(optionValue(args, "--root"));
-const assetRoot = path.resolve(optionValue(args, "--asset-root"));
-const metadataPath = path.resolve(optionValue(args, "--metadata"));
-const manifestPath = path.resolve(optionValue(args, "--manifest"));
-const outDir = path.resolve(optionValue(args, "--out-dir"));
-const targetId = optionValue(args, "--target");
-const extensionProductsCsv = optionValue(args, "--extension-products");
-
-const [version, selected] = await Promise.all([
-  releaseVersion(root),
-  selectedSqlNames(root, extensionProductsCsv),
-]);
-
-const data = await readJson(metadataPath);
-const extensions = data.extensions;
-if (!Array.isArray(extensions) || extensions.length === 0) {
-  fail(`${relativeToRoot(root, metadataPath)} must contain a non-empty extensions array`);
-}
-const builtManifest = await readJson(manifestPath);
-const builtExtensions = builtManifest.extensions;
-if (!Array.isArray(builtExtensions) || builtExtensions.length === 0) {
-  fail(`${relativeToRoot(root, manifestPath)} must contain a non-empty extensions array`);
-}
-const builtBySqlName = new Map();
-for (const row of builtExtensions) {
-  const sqlName = isObject(row) ? row["sql-name"] : undefined;
-  if (typeof sqlName !== "string" || sqlName.length === 0 || builtBySqlName.has(sqlName)) {
-    fail(`${relativeToRoot(root, manifestPath)} must contain unique extension sql-name rows`);
-  }
-  builtBySqlName.set(sqlName, row);
-}
-
-await rm(outDir, { recursive: true, force: true });
-await mkdir(outDir, { recursive: true });
-
-const rows = [];
-for (const item of extensions) {
-  if (!isObject(item)) {
-    fail(`${relativeToRoot(root, metadataPath)} contains a non-object extension row`);
-  }
-  const sqlName = item["sql-name"];
-  const archive = item.archive;
-  if (typeof sqlName !== "string" || sqlName.length === 0) {
-    fail(`${relativeToRoot(root, metadataPath)} contains an extension row without sql-name`);
-  }
-  if (selected.size > 0 && !selected.has(sqlName)) {
-    continue;
-  }
-  if (typeof archive !== "string" || archive.length === 0) {
-    fail(`${relativeToRoot(root, metadataPath)} row for ${sqlName} is missing archive`);
-  }
-  const componentClosure = resolveNativeComponentClosure(nativeComponentContract, {
-    extension: sqlName,
-    family: "wasix",
-    kind: "wasix-runtime",
-    target: targetId,
-  });
-  for (const [field, expected] of [
-    ["native-components", componentClosure.components],
-    ["native-link-units", componentClosure.linkUnits],
-    ["native-runtime-files", componentClosure.runtimeFiles],
-  ]) {
-    if (JSON.stringify(item[field]) !== JSON.stringify(expected)) {
-      fail(`${relativeToRoot(root, metadataPath)} row for ${sqlName} has stale ${field}`);
-    }
-  }
-
-  const source = path.join(assetRoot, archive);
-  const sourceSize = await fileSize(source);
-  if (sourceSize === undefined) {
-    fail(`missing WASIX extension archive for ${sqlName}: ${relativeToRoot(root, source)}`);
-  }
-  if (sourceSize === 0) {
-    fail(`WASIX extension archive for ${sqlName} is empty: ${relativeToRoot(root, source)}`);
-  }
-  const builtRow = builtBySqlName.get(sqlName);
-  if (builtRow === undefined) {
-    fail(`${relativeToRoot(root, manifestPath)} has no built extension row for ${sqlName}`);
-  }
-  const installedFiles = Array.isArray(builtRow["installed-files"])
-    ? builtRow["installed-files"]
-    : [];
-  const missingComponentRuntimeFiles = componentClosure.runtimeFiles
-    .map((file) => `share/${file}`)
-    .filter((file) => !installedFiles.includes(file));
-  if (missingComponentRuntimeFiles.length > 0) {
-    fail(
-      `${relativeToRoot(root, manifestPath)} extension ${sqlName} is missing native component runtime files: `
-        + missingComponentRuntimeFiles.join(", "),
-    );
-  }
-  const archiveBytes = await readFile(source);
-  let installContract;
-  try {
-    installContract = projectWasixExtensionInstallSidecar({
-      modelRow: item,
-      manifestRow: builtRow,
-    }, {
-      archiveBytes,
-      label: `${relativeToRoot(root, manifestPath)} extension ${sqlName}`,
-    });
-  } catch (error) {
-    fail(error instanceof Error ? error.message : String(error));
-  }
-
-  const artifact = `liboliphaunt-wasix-${version}-extension-${sqlName}-${targetId}.tar.zst`;
-  const destination = path.join(outDir, artifact);
-  await copyFile(source, destination);
-  const artifactBytes = await fileSize(destination);
-  if (artifactBytes !== installContract.size) {
-    fail(`WASIX extension archive for ${sqlName} changed while being staged`);
-  }
-  const installContractName =
-    `liboliphaunt-wasix-${version}-extension-${sqlName}-${targetId}.install-contract.json`;
-  await writeFile(
-    path.join(outDir, installContractName),
-    `${JSON.stringify(installContract, null, 2)}\n`,
-    "utf8",
-  );
-  rows.push({
-    sqlName,
-    target: targetId,
-    kind: "wasix-runtime",
-    artifact,
-    artifactBytes,
-    installContract: installContractName,
-  });
-}
-
-if (rows.length === 0) {
-  fail("no WASIX extension artifacts were staged");
-}
-
-const indexPath = path.join(outDir, `liboliphaunt-wasix-${version}-wasix-extension-assets.tsv`);
-const lines = [[
-  "sql_name",
-  "target",
-  "kind",
-  "artifact",
-  "artifact_bytes",
-  "install_contract",
-].join("\t")];
-for (const row of rows) {
-  lines.push(
-    [
-      tsvCell(row.sqlName),
-      tsvCell(row.target),
-      tsvCell(row.kind),
-      tsvCell(row.artifact),
-      tsvCell(row.artifactBytes),
-      tsvCell(row.installContract),
-    ].join("\t"),
-  );
-}
-await writeFile(indexPath, `${lines.join("\n")}\n`, "utf8");
-
-console.log(`staged ${rows.length} WASIX exact-extension artifact(s) in ${relativeToRoot(root, outDir)}`);
diff --git a/src/extensions/artifacts/wasix/tools/package-release-assets.mts b/src/extensions/artifacts/wasix/tools/package-release-assets.mts
new file mode 100644
index 000000000..6a709e5f2
--- /dev/null
+++ b/src/extensions/artifacts/wasix/tools/package-release-assets.mts
@@ -0,0 +1,285 @@
+#!/usr/bin/env bun
+import { copyFile, mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises';
+import path from 'node:path';
+import process from 'node:process';
+
+import { projectWasixExtensionInstallSidecar } from '../../../contracts/wasix-extension-install.mts';
+import {
+  loadNativeComponentContract,
+  resolveNativeComponentClosure,
+} from '../../../tools/native-component-contract.mts';
+const PREFIX = 'package-wasix-extension-assets.sh';
+const WASIX_PRODUCT_PATH = 'src/runtimes/liboliphaunt-wasix';
+const WASIX_VERSION_PATH = `${WASIX_PRODUCT_PATH}/VERSION`;
+const PRODUCT_METADATA_PATH = 'src/extensions/generated/sdk/extensions.json';
+const nativeComponentContract = loadNativeComponentContract();
+
+function fail(message) {
+  console.error(`${PREFIX}: ${message}`);
+  process.exit(2);
+}
+
+function usage() {
+  fail(
+    'usage: package-release-assets.mts --root PATH --asset-root PATH --metadata PATH --manifest PATH --out-dir PATH --target TARGET --extension-products CSV',
+  );
+}
+
+function optionValue(args, name) {
+  const index = args.indexOf(name);
+  if (index === -1) {
+    usage();
+  }
+  const value = args[index + 1];
+  if (value === undefined || value.startsWith('--')) {
+    usage();
+  }
+  return value;
+}
+
+function parseCsv(value) {
+  return [
+    ...new Set(
+      value
+        .split(',')
+        .map((item) => item.trim())
+        .filter(Boolean),
+    ),
+  ].sort();
+}
+
+function isObject(value) {
+  return value !== null && typeof value === 'object' && !Array.isArray(value);
+}
+
+async function readJson(file) {
+  let value;
+  try {
+    value = JSON.parse(await readFile(file, 'utf8'));
+  } catch (error) {
+    fail(`could not read JSON file ${file}: ${error.message}`);
+  }
+  if (!isObject(value)) {
+    fail(`${file} must contain a JSON object`);
+  }
+  return value;
+}
+
+function relativeToRoot(root, file) {
+  return path.relative(root, file).split(path.sep).join('/');
+}
+
+async function releaseVersion(root) {
+  let version;
+  try {
+    version = (await readFile(path.join(root, WASIX_VERSION_PATH), 'utf8')).trim();
+  } catch (error) {
+    fail(`could not read ${WASIX_VERSION_PATH}: ${error.message}`);
+  }
+  if (!/^\d+\.\d+\.\d+$/u.test(version)) {
+    fail(`${WASIX_VERSION_PATH} must contain one semantic version`);
+  }
+  return version;
+}
+
+async function selectedSqlNames(root, extensionProductsCsv) {
+  const products = parseCsv(extensionProductsCsv);
+  if (products.length === 0) {
+    return new Set();
+  }
+
+  const metadataPath = path.join(root, PRODUCT_METADATA_PATH);
+  const metadata = await readJson(metadataPath);
+  if (!Array.isArray(metadata.extensions)) {
+    fail(`${PRODUCT_METADATA_PATH} must contain an extensions array`);
+  }
+  const sqlNames = new Set();
+  for (const product of products) {
+    const matches = metadata.extensions.filter((row) => row?.['artifact-product'] === product);
+    if (matches.length === 0) {
+      fail(`${PRODUCT_METADATA_PATH} has no extension rows for product ${product}`);
+    }
+    for (const row of matches) {
+      const sqlName = row['sql-name'];
+      if (typeof sqlName !== 'string' || sqlName.length === 0) {
+        fail(`${PRODUCT_METADATA_PATH} has an invalid sql-name for product ${product}`);
+      }
+      sqlNames.add(sqlName);
+    }
+  }
+  return sqlNames;
+}
+
+async function fileSize(file) {
+  try {
+    return (await stat(file)).size;
+  } catch {
+    return undefined;
+  }
+}
+
+function tsvCell(value) {
+  const text = String(value);
+  if (text.includes('\t') || text.includes('\n') || text.includes('\r')) {
+    fail(`TSV field contains unsupported whitespace: ${JSON.stringify(text)}`);
+  }
+  return text;
+}
+
+const args = process.argv.slice(2);
+const root = path.resolve(optionValue(args, '--root'));
+const assetRoot = path.resolve(optionValue(args, '--asset-root'));
+const metadataPath = path.resolve(optionValue(args, '--metadata'));
+const manifestPath = path.resolve(optionValue(args, '--manifest'));
+const outDir = path.resolve(optionValue(args, '--out-dir'));
+const targetId = optionValue(args, '--target');
+const extensionProductsCsv = optionValue(args, '--extension-products');
+
+const [version, selected] = await Promise.all([
+  releaseVersion(root),
+  selectedSqlNames(root, extensionProductsCsv),
+]);
+
+const data = await readJson(metadataPath);
+const extensions = data.extensions;
+if (!Array.isArray(extensions) || extensions.length === 0) {
+  fail(`${relativeToRoot(root, metadataPath)} must contain a non-empty extensions array`);
+}
+const builtManifest = await readJson(manifestPath);
+const builtExtensions = builtManifest.extensions;
+if (!Array.isArray(builtExtensions) || builtExtensions.length === 0) {
+  fail(`${relativeToRoot(root, manifestPath)} must contain a non-empty extensions array`);
+}
+const builtBySqlName = new Map();
+for (const row of builtExtensions) {
+  const sqlName = isObject(row) ? row['sql-name'] : undefined;
+  if (typeof sqlName !== 'string' || sqlName.length === 0 || builtBySqlName.has(sqlName)) {
+    fail(`${relativeToRoot(root, manifestPath)} must contain unique extension sql-name rows`);
+  }
+  builtBySqlName.set(sqlName, row);
+}
+
+await rm(outDir, { recursive: true, force: true });
+await mkdir(outDir, { recursive: true });
+
+const rows = [];
+for (const item of extensions) {
+  if (!isObject(item)) {
+    fail(`${relativeToRoot(root, metadataPath)} contains a non-object extension row`);
+  }
+  const sqlName = item['sql-name'];
+  const archive = item.archive;
+  if (typeof sqlName !== 'string' || sqlName.length === 0) {
+    fail(`${relativeToRoot(root, metadataPath)} contains an extension row without sql-name`);
+  }
+  if (selected.size > 0 && !selected.has(sqlName)) {
+    continue;
+  }
+  if (typeof archive !== 'string' || archive.length === 0) {
+    fail(`${relativeToRoot(root, metadataPath)} row for ${sqlName} is missing archive`);
+  }
+  const componentClosure = resolveNativeComponentClosure(nativeComponentContract, {
+    extension: sqlName,
+    family: 'wasix',
+    kind: 'wasix-runtime',
+    target: targetId,
+  });
+  for (const [field, expected] of [
+    ['native-components', componentClosure.components],
+    ['native-link-units', componentClosure.linkUnits],
+    ['native-runtime-files', componentClosure.runtimeFiles],
+  ]) {
+    if (JSON.stringify(item[field]) !== JSON.stringify(expected)) {
+      fail(`${relativeToRoot(root, metadataPath)} row for ${sqlName} has stale ${field}`);
+    }
+  }
+
+  const source = path.join(assetRoot, archive);
+  const sourceSize = await fileSize(source);
+  if (sourceSize === undefined) {
+    fail(`missing WASIX extension archive for ${sqlName}: ${relativeToRoot(root, source)}`);
+  }
+  if (sourceSize === 0) {
+    fail(`WASIX extension archive for ${sqlName} is empty: ${relativeToRoot(root, source)}`);
+  }
+  const builtRow = builtBySqlName.get(sqlName);
+  if (builtRow === undefined) {
+    fail(`${relativeToRoot(root, manifestPath)} has no built extension row for ${sqlName}`);
+  }
+  const installedFiles = Array.isArray(builtRow['installed-files'])
+    ? builtRow['installed-files']
+    : [];
+  const missingComponentRuntimeFiles = componentClosure.runtimeFiles
+    .map((file) => `share/${file}`)
+    .filter((file) => !installedFiles.includes(file));
+  if (missingComponentRuntimeFiles.length > 0) {
+    fail(
+      `${relativeToRoot(root, manifestPath)} extension ${sqlName} is missing native component runtime files: ` +
+        missingComponentRuntimeFiles.join(', '),
+    );
+  }
+  const archiveBytes = await readFile(source);
+  let installContract;
+  try {
+    installContract = projectWasixExtensionInstallSidecar(
+      {
+        modelRow: item,
+        manifestRow: builtRow,
+      },
+      {
+        archiveBytes,
+        label: `${relativeToRoot(root, manifestPath)} extension ${sqlName}`,
+      },
+    );
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+
+  const artifact = `liboliphaunt-wasix-${version}-extension-${sqlName}-${targetId}.tar.zst`;
+  const destination = path.join(outDir, artifact);
+  await copyFile(source, destination);
+  const artifactBytes = await fileSize(destination);
+  if (artifactBytes !== installContract.size) {
+    fail(`WASIX extension archive for ${sqlName} changed while being staged`);
+  }
+  const installContractName = `liboliphaunt-wasix-${version}-extension-${sqlName}-${targetId}.install-contract.json`;
+  await writeFile(
+    path.join(outDir, installContractName),
+    `${JSON.stringify(installContract, null, 2)}\n`,
+    'utf8',
+  );
+  rows.push({
+    sqlName,
+    target: targetId,
+    kind: 'wasix-runtime',
+    artifact,
+    artifactBytes,
+    installContract: installContractName,
+  });
+}
+
+if (rows.length === 0) {
+  fail('no WASIX extension artifacts were staged');
+}
+
+const indexPath = path.join(outDir, `liboliphaunt-wasix-${version}-wasix-extension-assets.tsv`);
+const lines = [
+  ['sql_name', 'target', 'kind', 'artifact', 'artifact_bytes', 'install_contract'].join('\t'),
+];
+for (const row of rows) {
+  lines.push(
+    [
+      tsvCell(row.sqlName),
+      tsvCell(row.target),
+      tsvCell(row.kind),
+      tsvCell(row.artifact),
+      tsvCell(row.artifactBytes),
+      tsvCell(row.installContract),
+    ].join('\t'),
+  );
+}
+await writeFile(indexPath, `${lines.join('\n')}\n`, 'utf8');
+
+console.log(
+  `staged ${rows.length} WASIX exact-extension artifact(s) in ${relativeToRoot(root, outDir)}`,
+);
diff --git a/src/extensions/artifacts/wasix/tools/package-release-assets.sh b/src/extensions/artifacts/wasix/tools/package-release-assets.sh
index 714573cfa..dd69be33a 100755
--- a/src/extensions/artifacts/wasix/tools/package-release-assets.sh
+++ b/src/extensions/artifacts/wasix/tools/package-release-assets.sh
@@ -32,7 +32,7 @@ if [ -n "$extension_product" ]; then
     extension_products="$extension_product"
   fi
 fi
-asset_root="$root/target/oliphaunt-wasix/assets"
+asset_root="$root/target/extensions/wasix/assets"
 generated_metadata="$root/src/extensions/generated/wasix/extensions.json"
 built_manifest="$asset_root/manifest.json"
 default_out_dir="$root/target/extensions/wasix/release-assets/$target_id"
@@ -46,7 +46,7 @@ out_dir="${OLIPHAUNT_WASIX_EXTENSION_RELEASE_ASSET_DIR:-$default_out_dir}"
 [ -d "$asset_root/extensions" ] || fail "missing WASIX extension asset directory: ${asset_root#$root/}/extensions"
 
 bun \
-  "$root/src/extensions/artifacts/wasix/tools/package-release-assets.mjs" \
+  "$root/src/extensions/artifacts/wasix/tools/package-release-assets.mts" \
   --root "$root" \
   --asset-root "$asset_root" \
   --metadata "$generated_metadata" \
diff --git a/src/extensions/catalog/extensions.source.json b/src/extensions/catalog/extensions.source.json
index 85ad94e0f..6afb49f57 100644
--- a/src/extensions/catalog/extensions.source.json
+++ b/src/extensions/catalog/extensions.source.json
@@ -9,12 +9,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "amcheck",
       "package-export": "./contrib/amcheck",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 18815,
-      "control-file": "src/postgres/versions/18/contrib/amcheck/amcheck.control",
+      "control-file": "src/third-party/postgres/contrib/amcheck/amcheck.control",
       "control": {
         "module-pathname": "$libdir/amcheck",
         "requires": [],
@@ -32,9 +29,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/amcheck.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/amcheck.test.js"],
       "native-module-file": "amcheck.so",
       "notes": []
     },
@@ -46,10 +41,7 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "auto_explain",
       "package-export": "./contrib/auto_explain",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 3125,
       "dependencies": [],
       "load-order": [],
@@ -81,12 +73,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "bloom",
       "package-export": "./contrib/bloom",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 6197,
-      "control-file": "src/postgres/versions/18/contrib/bloom/bloom.control",
+      "control-file": "src/third-party/postgres/contrib/bloom/bloom.control",
       "control": {
         "module-pathname": "$libdir/bloom",
         "requires": [],
@@ -104,9 +93,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/bloom.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/bloom.test.js"],
       "native-module-file": "bloom.so",
       "notes": []
     },
@@ -118,12 +105,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "btree_gin",
       "package-export": "./contrib/btree_gin",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 6347,
-      "control-file": "src/postgres/versions/18/contrib/btree_gin/btree_gin.control",
+      "control-file": "src/third-party/postgres/contrib/btree_gin/btree_gin.control",
       "control": {
         "module-pathname": "$libdir/btree_gin",
         "requires": [],
@@ -155,12 +139,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "btree_gist",
       "package-export": "./contrib/btree_gist",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 24181,
-      "control-file": "src/postgres/versions/18/contrib/btree_gist/btree_gist.control",
+      "control-file": "src/third-party/postgres/contrib/btree_gist/btree_gist.control",
       "control": {
         "module-pathname": "$libdir/btree_gist",
         "requires": [],
@@ -192,12 +173,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "citext",
       "package-export": "./contrib/citext",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 4983,
-      "control-file": "src/postgres/versions/18/contrib/citext/citext.control",
+      "control-file": "src/third-party/postgres/contrib/citext/citext.control",
       "control": {
         "module-pathname": "$libdir/citext",
         "requires": [],
@@ -215,9 +193,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/citext.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/citext.test.js"],
       "native-module-file": "citext.so",
       "notes": []
     },
@@ -229,12 +205,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "cube",
       "package-export": "./contrib/cube",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 15104,
-      "control-file": "src/postgres/versions/18/contrib/cube/cube.control",
+      "control-file": "src/third-party/postgres/contrib/cube/cube.control",
       "control": {
         "module-pathname": "$libdir/cube",
         "requires": [],
@@ -252,9 +225,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/cube.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/cube.test.js"],
       "native-module-file": "cube.so",
       "notes": []
     },
@@ -266,12 +237,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "dict_int",
       "package-export": "./contrib/dict_int",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 1361,
-      "control-file": "src/postgres/versions/18/contrib/dict_int/dict_int.control",
+      "control-file": "src/third-party/postgres/contrib/dict_int/dict_int.control",
       "control": {
         "module-pathname": "$libdir/dict_int",
         "requires": [],
@@ -289,9 +257,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/dict_int.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/dict_int.test.js"],
       "native-module-file": "dict_int.so",
       "notes": []
     },
@@ -303,12 +269,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "dict_xsyn",
       "package-export": "./contrib/dict_xsyn",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 1948,
-      "control-file": "src/postgres/versions/18/contrib/dict_xsyn/dict_xsyn.control",
+      "control-file": "src/third-party/postgres/contrib/dict_xsyn/dict_xsyn.control",
       "control": {
         "module-pathname": "$libdir/dict_xsyn",
         "requires": [],
@@ -340,22 +303,15 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "earthdistance",
       "package-export": "./contrib/earthdistance",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 2220,
-      "control-file": "src/postgres/versions/18/contrib/earthdistance/earthdistance.control",
+      "control-file": "src/third-party/postgres/contrib/earthdistance/earthdistance.control",
       "control": {
         "module-pathname": "$libdir/earthdistance",
-        "requires": [
-          "cube"
-        ],
+        "requires": ["cube"],
         "relocatable": "true"
       },
-      "dependencies": [
-        "cube"
-      ],
+      "dependencies": ["cube"],
       "load-order": [],
       "lifecycle": {
         "create-extension": true,
@@ -381,12 +337,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "file_fdw",
       "package-export": "./contrib/file_fdw",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 4467,
-      "control-file": "src/postgres/versions/18/contrib/file_fdw/file_fdw.control",
+      "control-file": "src/third-party/postgres/contrib/file_fdw/file_fdw.control",
       "control": {
         "module-pathname": "$libdir/file_fdw",
         "requires": [],
@@ -404,9 +357,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/file_fdw.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/file_fdw.test.js"],
       "native-module-file": "file_fdw.so",
       "notes": []
     },
@@ -418,12 +369,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "fuzzystrmatch",
       "package-export": "./contrib/fuzzystrmatch",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 12026,
-      "control-file": "src/postgres/versions/18/contrib/fuzzystrmatch/fuzzystrmatch.control",
+      "control-file": "src/third-party/postgres/contrib/fuzzystrmatch/fuzzystrmatch.control",
       "control": {
         "module-pathname": "$libdir/fuzzystrmatch",
         "requires": [],
@@ -455,12 +403,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "hstore",
       "package-export": "./contrib/hstore",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 21380,
-      "control-file": "src/postgres/versions/18/contrib/hstore/hstore.control",
+      "control-file": "src/third-party/postgres/contrib/hstore/hstore.control",
       "control": {
         "module-pathname": "$libdir/hstore",
         "requires": [],
@@ -478,9 +423,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/hstore.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/hstore.test.js"],
       "native-module-file": "hstore.so",
       "notes": []
     },
@@ -492,12 +435,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "intarray",
       "package-export": "./contrib/intarray",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 14712,
-      "control-file": "src/postgres/versions/18/contrib/intarray/intarray.control",
+      "control-file": "src/third-party/postgres/contrib/intarray/intarray.control",
       "control": {
         "module-pathname": "$libdir/_int",
         "requires": [],
@@ -515,9 +455,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/intarray.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/intarray.test.js"],
       "native-module-file": "_int.so",
       "notes": []
     },
@@ -529,12 +467,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "isn",
       "package-export": "./contrib/isn",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 31417,
-      "control-file": "src/postgres/versions/18/contrib/isn/isn.control",
+      "control-file": "src/third-party/postgres/contrib/isn/isn.control",
       "control": {
         "module-pathname": "$libdir/isn",
         "requires": [],
@@ -552,9 +487,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/isn.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/isn.test.js"],
       "native-module-file": "isn.so",
       "notes": []
     },
@@ -566,12 +499,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "lo",
       "package-export": "./contrib/lo",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 1822,
-      "control-file": "src/postgres/versions/18/contrib/lo/lo.control",
+      "control-file": "src/third-party/postgres/contrib/lo/lo.control",
       "control": {
         "module-pathname": "$libdir/lo",
         "requires": [],
@@ -589,9 +519,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/lo.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/lo.test.js"],
       "native-module-file": "lo.so",
       "notes": []
     },
@@ -603,12 +531,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "ltree",
       "package-export": "./contrib/ltree",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 19553,
-      "control-file": "src/postgres/versions/18/contrib/ltree/ltree.control",
+      "control-file": "src/third-party/postgres/contrib/ltree/ltree.control",
       "control": {
         "module-pathname": "$libdir/ltree",
         "requires": [],
@@ -626,9 +551,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/ltree.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/ltree.test.js"],
       "native-module-file": "ltree.so",
       "notes": []
     },
@@ -640,12 +563,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "pageinspect",
       "package-export": "./contrib/pageinspect",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 15923,
-      "control-file": "src/postgres/versions/18/contrib/pageinspect/pageinspect.control",
+      "control-file": "src/third-party/postgres/contrib/pageinspect/pageinspect.control",
       "control": {
         "module-pathname": "$libdir/pageinspect",
         "requires": [],
@@ -677,12 +597,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "pg_buffercache",
       "package-export": "./contrib/pg_buffercache",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 3133,
-      "control-file": "src/postgres/versions/18/contrib/pg_buffercache/pg_buffercache.control",
+      "control-file": "src/third-party/postgres/contrib/pg_buffercache/pg_buffercache.control",
       "control": {
         "module-pathname": "$libdir/pg_buffercache",
         "requires": [],
@@ -714,12 +631,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "pg_freespacemap",
       "package-export": "./contrib/pg_freespacemap",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 1485,
-      "control-file": "src/postgres/versions/18/contrib/pg_freespacemap/pg_freespacemap.control",
+      "control-file": "src/third-party/postgres/contrib/pg_freespacemap/pg_freespacemap.control",
       "control": {
         "module-pathname": "$libdir/pg_freespacemap",
         "requires": [],
@@ -751,9 +665,7 @@
       "source-kind": "oliphaunt-other-extension",
       "upstream-import-name": "pg_hashids",
       "package-export": "./pg_hashids",
-      "tags": [
-        "postgres extension"
-      ],
+      "tags": ["postgres extension"],
       "bundle-size": 4212,
       "control-file": "target/oliphaunt-sources/checkouts/pg_hashids/pg_hashids.control",
       "control": {
@@ -773,9 +685,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/pg_hashids.test.ts"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/pg_hashids.test.ts"],
       "native-module-file": "pg_hashids.so",
       "notes": []
     },
@@ -787,9 +697,7 @@
       "source-kind": "oliphaunt-other-extension",
       "upstream-import-name": "pg_ivm",
       "package-export": "./pg_ivm",
-      "tags": [
-        "postgres extension"
-      ],
+      "tags": ["postgres extension"],
       "bundle-size": 24865,
       "control-file": "target/oliphaunt-sources/checkouts/pg_ivm/pg_ivm.control",
       "control": {
@@ -810,9 +718,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/pg_ivm.test.ts"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/pg_ivm.test.ts"],
       "native-module-file": "pg_ivm.so",
       "notes": []
     },
@@ -824,12 +730,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "pg_surgery",
       "package-export": "./contrib/pg_surgery",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 2635,
-      "control-file": "src/postgres/versions/18/contrib/pg_surgery/pg_surgery.control",
+      "control-file": "src/third-party/postgres/contrib/pg_surgery/pg_surgery.control",
       "control": {
         "module-pathname": "$libdir/pg_surgery",
         "requires": [],
@@ -861,9 +764,7 @@
       "source-kind": "oliphaunt-other-extension",
       "upstream-import-name": "pg_textsearch",
       "package-export": "./pg_textsearch",
-      "tags": [
-        "postgres extension"
-      ],
+      "tags": ["postgres extension"],
       "bundle-size": 55062,
       "control-file": "target/oliphaunt-sources/checkouts/pg_textsearch/pg_textsearch.control",
       "control": {
@@ -878,16 +779,12 @@
         "create-schema": "pg_catalog",
         "load-sql": [],
         "post-create-sql": [],
-        "startup-config": [
-          "shared_preload_libraries=pg_textsearch"
-        ],
+        "startup-config": ["shared_preload_libraries=pg_textsearch"],
         "preload-required": true,
         "restart-required": true,
         "shared-memory-required": true
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/pg_textsearch.test.ts"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/pg_textsearch.test.ts"],
       "native-module-file": "pg_textsearch.so",
       "notes": []
     },
@@ -899,12 +796,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "pg_trgm",
       "package-export": "./contrib/pg_trgm",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 16208,
-      "control-file": "src/postgres/versions/18/contrib/pg_trgm/pg_trgm.control",
+      "control-file": "src/third-party/postgres/contrib/pg_trgm/pg_trgm.control",
       "control": {
         "module-pathname": "$libdir/pg_trgm",
         "requires": [],
@@ -922,9 +816,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/pg_trgm.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/pg_trgm.test.js"],
       "native-module-file": "pg_trgm.so",
       "notes": []
     },
@@ -936,9 +828,7 @@
       "source-kind": "oliphaunt-other-extension",
       "upstream-import-name": "pg_uuidv7",
       "package-export": "./pg_uuidv7",
-      "tags": [
-        "postgres extension"
-      ],
+      "tags": ["postgres extension"],
       "bundle-size": 1522,
       "control-file": "target/oliphaunt-sources/checkouts/pg_uuidv7/pg_uuidv7.control",
       "control": {
@@ -958,9 +848,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/pg_uuidv7.test.ts"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/pg_uuidv7.test.ts"],
       "native-module-file": "pg_uuidv7.so",
       "notes": []
     },
@@ -972,12 +860,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "pg_visibility",
       "package-export": "./contrib/pg_visibility",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 4159,
-      "control-file": "src/postgres/versions/18/contrib/pg_visibility/pg_visibility.control",
+      "control-file": "src/third-party/postgres/contrib/pg_visibility/pg_visibility.control",
       "control": {
         "module-pathname": "$libdir/pg_visibility",
         "requires": [],
@@ -1009,12 +894,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "pg_walinspect",
       "package-export": "./contrib/pg_walinspect",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 4689,
-      "control-file": "src/postgres/versions/18/contrib/pg_walinspect/pg_walinspect.control",
+      "control-file": "src/third-party/postgres/contrib/pg_walinspect/pg_walinspect.control",
       "control": {
         "module-pathname": "$libdir/pg_walinspect",
         "requires": [],
@@ -1046,12 +928,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "pgcrypto",
       "package-export": "./contrib/pgcrypto",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 1148162,
-      "control-file": "src/postgres/versions/18/contrib/pgcrypto/pgcrypto.control",
+      "control-file": "src/third-party/postgres/contrib/pgcrypto/pgcrypto.control",
       "control": {
         "module-pathname": "$libdir/pgcrypto",
         "requires": [],
@@ -1068,9 +947,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/pgcrypto.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/pgcrypto.test.js"],
       "native-module-file": "pgcrypto.so",
       "notes": []
     },
@@ -1082,20 +959,14 @@
       "source-kind": "oliphaunt-other-extension",
       "upstream-import-name": "pgtap",
       "package-export": "./pgtap",
-      "tags": [
-        "postgres extension"
-      ],
+      "tags": ["postgres extension"],
       "bundle-size": 239428,
       "control-file": "target/oliphaunt-sources/checkouts/pgtap/pgtap.control",
       "control": {
-        "requires": [
-          "plpgsql"
-        ],
+        "requires": ["plpgsql"],
         "relocatable": "true"
       },
-      "dependencies": [
-        "plpgsql"
-      ],
+      "dependencies": ["plpgsql"],
       "load-order": [],
       "lifecycle": {
         "create-extension": true,
@@ -1107,9 +978,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/pgtap.test.ts"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/pgtap.test.ts"],
       "notes": []
     },
     {
@@ -1119,9 +988,7 @@
       "display-name": "PostGIS",
       "source-kind": "postgis",
       "upstream-import-name": "postgis",
-      "tags": [
-        "postgres extension"
-      ],
+      "tags": ["postgres extension"],
       "bundle-size": 8551161,
       "control-file": "target/oliphaunt-sources/checkouts/postgis/extensions/postgis/postgis.control.in",
       "control": {
@@ -1130,9 +997,7 @@
         "relocatable": "false"
       },
       "dependencies": [],
-      "load-order": [
-        "lib/postgresql/postgis-3.so"
-      ],
+      "load-order": ["lib/postgresql/postgis-3.so"],
       "lifecycle": {
         "create-extension": true,
         "load-sql": [],
@@ -1142,9 +1007,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/postgis/postgis.test.ts"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/postgis/postgis.test.ts"],
       "native-module-file": "postgis-3.so",
       "notes": []
     },
@@ -1156,12 +1019,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "seg",
       "package-export": "./contrib/seg",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 10426,
-      "control-file": "src/postgres/versions/18/contrib/seg/seg.control",
+      "control-file": "src/third-party/postgres/contrib/seg/seg.control",
       "control": {
         "module-pathname": "$libdir/seg",
         "requires": [],
@@ -1179,9 +1039,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/seg.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/seg.test.js"],
       "native-module-file": "seg.so",
       "notes": []
     },
@@ -1193,12 +1051,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "tablefunc",
       "package-export": "./contrib/tablefunc",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 5824,
-      "control-file": "src/postgres/versions/18/contrib/tablefunc/tablefunc.control",
+      "control-file": "src/third-party/postgres/contrib/tablefunc/tablefunc.control",
       "control": {
         "module-pathname": "$libdir/tablefunc",
         "requires": [],
@@ -1230,12 +1085,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "tcn",
       "package-export": "./contrib/tcn",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 1914,
-      "control-file": "src/postgres/versions/18/contrib/tcn/tcn.control",
+      "control-file": "src/third-party/postgres/contrib/tcn/tcn.control",
       "control": {
         "module-pathname": "$libdir/tcn",
         "requires": [],
@@ -1253,9 +1105,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/tcn.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/tcn.test.js"],
       "native-module-file": "tcn.so",
       "notes": []
     },
@@ -1267,12 +1117,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "tsm_system_rows",
       "package-export": "./contrib/tsm_system_rows",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 2048,
-      "control-file": "src/postgres/versions/18/contrib/tsm_system_rows/tsm_system_rows.control",
+      "control-file": "src/third-party/postgres/contrib/tsm_system_rows/tsm_system_rows.control",
       "control": {
         "module-pathname": "$libdir/tsm_system_rows",
         "requires": [],
@@ -1304,12 +1151,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "tsm_system_time",
       "package-export": "./contrib/tsm_system_time",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 2099,
-      "control-file": "src/postgres/versions/18/contrib/tsm_system_time/tsm_system_time.control",
+      "control-file": "src/third-party/postgres/contrib/tsm_system_time/tsm_system_time.control",
       "control": {
         "module-pathname": "$libdir/tsm_system_time",
         "requires": [],
@@ -1341,12 +1185,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "unaccent",
       "package-export": "./contrib/unaccent",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 9323,
-      "control-file": "src/postgres/versions/18/contrib/unaccent/unaccent.control",
+      "control-file": "src/third-party/postgres/contrib/unaccent/unaccent.control",
       "control": {
         "module-pathname": "$libdir/unaccent",
         "requires": [],
@@ -1364,9 +1205,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/unaccent.test.js"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/contrib/unaccent.test.js"],
       "native-module-file": "unaccent.so",
       "notes": []
     },
@@ -1378,12 +1217,9 @@
       "source-kind": "postgres-contrib",
       "upstream-import-name": "uuid_ossp",
       "package-export": "./contrib/uuid_ossp",
-      "tags": [
-        "postgres extension",
-        "postgres/contrib"
-      ],
+      "tags": ["postgres extension", "postgres/contrib"],
       "bundle-size": 17936,
-      "control-file": "src/postgres/versions/18/contrib/uuid-ossp/uuid-ossp.control",
+      "control-file": "src/third-party/postgres/contrib/uuid-ossp/uuid-ossp.control",
       "control": {
         "module-pathname": "$libdir/uuid-ossp",
         "requires": [],
@@ -1415,9 +1251,7 @@
       "source-kind": "oliphaunt-other-extension",
       "upstream-import-name": "vector",
       "package-export": "./vector",
-      "tags": [
-        "postgres extension"
-      ],
+      "tags": ["postgres extension"],
       "bundle-size": 43953,
       "control-file": "target/oliphaunt-sources/checkouts/pgvector/vector.control",
       "control": {
@@ -1437,9 +1271,7 @@
         "restart-required": false,
         "shared-memory-required": false
       },
-      "tests": [
-        "target/oliphaunt-sources/checkouts/src/extensions/tests/pgvector.test.ts"
-      ],
+      "tests": ["target/oliphaunt-sources/checkouts/src/extensions/tests/pgvector.test.ts"],
       "native-module-file": "vector.so",
       "notes": []
     }
diff --git a/src/extensions/catalog/native-components.toml b/src/extensions/catalog/native-components.toml
index 08107cb3c..842fdcb7b 100644
--- a/src/extensions/catalog/native-components.toml
+++ b/src/extensions/catalog/native-components.toml
@@ -80,7 +80,7 @@ archive-candidates = ["openssl/libcrypto.a", "openssl/lib/libcrypto.a"]
 
 [[components]]
 id = "portable-uuid"
-source-path = "src/runtimes/liboliphaunt/native/portable-uuid"
+source-path = "src/runtimes/liboliphaunt-native/portable-uuid"
 depends-on = []
 runtime-files = []
 
diff --git a/src/shared/extension-runtime-contract/contract.toml b/src/extensions/contracts/contract.toml
similarity index 100%
rename from src/shared/extension-runtime-contract/contract.toml
rename to src/extensions/contracts/contract.toml
diff --git a/src/shared/extension-runtime-contract/extension-artifact-archive-policy.properties b/src/extensions/contracts/extension-artifact-archive-policy.properties
similarity index 100%
rename from src/shared/extension-runtime-contract/extension-artifact-archive-policy.properties
rename to src/extensions/contracts/extension-artifact-archive-policy.properties
diff --git a/src/extensions/contracts/extension-target-profiles.mts b/src/extensions/contracts/extension-target-profiles.mts
new file mode 100644
index 000000000..03504b7ed
--- /dev/null
+++ b/src/extensions/contracts/extension-target-profiles.mts
@@ -0,0 +1,93 @@
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+
+export const EXTENSION_TARGET_PROFILES_RELATIVE_PATH =
+  'src/extensions/contracts/extension-target-profiles.toml';
+const ROOT = path.resolve(import.meta.dir, '../../..');
+const ID = /^[a-z][a-z0-9_-]*$/u;
+
+function fail(message) {
+  throw new Error(`extension target profiles: ${message}`);
+}
+
+function table(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(`${label} must be a table`);
+  }
+  return value;
+}
+
+function exactKeys(value, expected, label) {
+  const actual = Object.keys(value).sort();
+  const wanted = [...expected].sort();
+  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
+    fail(`${label} fields must be exactly ${wanted.join(', ')}; got ${actual.join(', ')}`);
+  }
+}
+
+function id(value, label) {
+  if (typeof value !== 'string' || !ID.test(value)) {
+    fail(`${label} must match ${ID}`);
+  }
+  return value;
+}
+
+export function validateExtensionTargetProfiles(raw) {
+  table(raw, 'root');
+  exactKeys(raw, ['profiles', 'schema'], 'root');
+  if (raw.schema !== 'oliphaunt-extension-artifact-target-profiles-v1') {
+    fail('schema must be oliphaunt-extension-artifact-target-profiles-v1');
+  }
+  if (!Array.isArray(raw.profiles) || raw.profiles.length === 0) {
+    fail('profiles must be a non-empty array');
+  }
+
+  const profileIds = new Set();
+  const targets = new Set();
+  const profiles = raw.profiles.map((rawProfile, profileIndex) => {
+    const profile = table(rawProfile, `profiles[${profileIndex}]`);
+    exactKeys(profile, ['id', 'targets'], `profiles[${profileIndex}]`);
+    const profileId = id(profile.id, `profiles[${profileIndex}].id`);
+    if (profileIds.has(profileId)) fail(`duplicate profile ${profileId}`);
+    profileIds.add(profileId);
+    if (!Array.isArray(profile.targets) || profile.targets.length === 0) {
+      fail(`profile ${profileId} must define a non-empty targets array`);
+    }
+    const rows = profile.targets.map((rawTarget, targetIndex) => {
+      const target = table(rawTarget, `profile ${profileId} targets[${targetIndex}]`);
+      exactKeys(
+        target,
+        ['family', 'kind', 'target'],
+        `profile ${profileId} targets[${targetIndex}]`,
+      );
+      const targetId = id(target.target, `profile ${profileId} targets[${targetIndex}].target`);
+      if (targets.has(targetId)) fail(`duplicate target ${targetId}`);
+      targets.add(targetId);
+      return Object.freeze({
+        profileId,
+        target: targetId,
+        family: id(target.family, `target ${targetId}.family`),
+        kind: id(target.kind, `target ${targetId}.kind`),
+      });
+    });
+    return Object.freeze({ id: profileId, targets: Object.freeze(rows) });
+  });
+
+  return Object.freeze({
+    schema: raw.schema,
+    profiles: Object.freeze(profiles),
+    targets: Object.freeze(profiles.flatMap((profile) => profile.targets)),
+  });
+}
+
+export function loadExtensionTargetProfiles({
+  file = path.join(ROOT, EXTENSION_TARGET_PROFILES_RELATIVE_PATH),
+} = {}) {
+  try {
+    return validateExtensionTargetProfiles(Bun.TOML.parse(readFileSync(file, 'utf8')));
+  } catch (error) {
+    if (error instanceof Error && error.message.startsWith('extension target profiles:'))
+      throw error;
+    fail(`cannot read ${file}: ${error instanceof Error ? error.message : String(error)}`);
+  }
+}
diff --git a/src/extensions/contracts/extension-target-profiles.test.mts b/src/extensions/contracts/extension-target-profiles.test.mts
new file mode 100644
index 000000000..b304564e2
--- /dev/null
+++ b/src/extensions/contracts/extension-target-profiles.test.mts
@@ -0,0 +1,40 @@
+import { expect, test } from 'bun:test';
+
+import { validateExtensionTargetProfiles } from './extension-target-profiles.mts';
+
+function fixture() {
+  return {
+    schema: 'oliphaunt-extension-artifact-target-profiles-v1',
+    profiles: [
+      {
+        id: 'native-v1',
+        targets: [{ target: 'linux-x64-gnu', family: 'native', kind: 'native-dynamic' }],
+      },
+    ],
+  };
+}
+
+test('normalizes the minimal target identity contract', () => {
+  expect(validateExtensionTargetProfiles(fixture()).targets).toEqual([
+    {
+      profileId: 'native-v1',
+      target: 'linux-x64-gnu',
+      family: 'native',
+      kind: 'native-dynamic',
+    },
+  ]);
+});
+
+test('rejects intermediate state fields', () => {
+  const raw = fixture();
+  raw.profiles[0].targets[0].status = 'supported';
+  expect(() => validateExtensionTargetProfiles(raw)).toThrow(
+    /fields must be exactly family, kind, target/u,
+  );
+});
+
+test('rejects a target declared by more than one profile', () => {
+  const raw = fixture();
+  raw.profiles.push({ ...raw.profiles[0], id: 'duplicate-v1' });
+  expect(() => validateExtensionTargetProfiles(raw)).toThrow(/duplicate target linux-x64-gnu/u);
+});
diff --git a/src/shared/extension-runtime-contract/extension-target-profiles.toml b/src/extensions/contracts/extension-target-profiles.toml
similarity index 100%
rename from src/shared/extension-runtime-contract/extension-target-profiles.toml
rename to src/extensions/contracts/extension-target-profiles.toml
diff --git a/src/extensions/contracts/moon.yml b/src/extensions/contracts/moon.yml
new file mode 100644
index 000000000..ee2f60bf5
--- /dev/null
+++ b/src/extensions/contracts/moon.yml
@@ -0,0 +1,38 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "extension-runtime-contract"
+language: "typescript"
+layer: "configuration"
+stack: "systems"
+tags: ["javascript-quality", "extensions", "contract", "runtime"]
+dependsOn:
+
+project:
+  title: "Extension Runtime Contract"
+  description: "Shared contract between base runtimes and exact extension artifacts."
+  owner: "oliphaunt"
+
+owners:
+  defaultOwner: "@oliphaunt/core"
+  paths:
+    "**/*": ["@oliphaunt/core"]
+
+fileGroups:
+  contract:
+    - "contract.toml"
+    - "extension-artifact-archive-policy.properties"
+    - "extension-target-profiles.mts"
+    - "extension-target-profiles.toml"
+    - "wasix-extension-install.mts"
+
+tasks:
+  test:
+    tags: ["quality", "unit"]
+    command: "bun test ./src/extensions/contracts"
+    inputs:
+      - "@group(contract)"
+      - "*.test.mts"
+      - "/tools/packaging/*.{mjs,mts}"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/extensions/contracts/wasix-extension-install.mts b/src/extensions/contracts/wasix-extension-install.mts
new file mode 100644
index 000000000..d4b6f16c3
--- /dev/null
+++ b/src/extensions/contracts/wasix-extension-install.mts
@@ -0,0 +1,464 @@
+import { createHash } from 'node:crypto';
+
+import { readPortableTarZstdBufferEntries } from '../../../tools/packaging/portable-archive.mts';
+
+export const WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA =
+  'oliphaunt-wasix-extension-install-sidecar-v1';
+export const WASIX_EXTENSION_INSTALL_SCHEMA = 'oliphaunt-wasix-extension-install-v1';
+export const EXTENSION_RUNTIME_CONTRACT_PATH = 'src/extensions/contracts/contract.toml';
+export const EXTENSION_RUNTIME_CONTRACT_SCHEMA = 'oliphaunt-extension-runtime-contract-v1';
+
+const LOWER_SHA256 = /^[0-9a-f]{64}$/u;
+const SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/u;
+const SIDECAR_FIELDS = Object.freeze(['archive', 'install', 'schema', 'sha256', 'size', 'sqlName']);
+const INSTALL_FIELDS = Object.freeze([
+  'coreExportsRequired',
+  'dependencies',
+  'installedFiles',
+  'lifecycle',
+  'loadOrder',
+  'name',
+  'nativeModule',
+  'nativeModules',
+  'schema',
+  'unresolvedImports',
+]);
+const LIFECYCLE_FIELDS = Object.freeze([
+  'createExtension',
+  'createSchema',
+  'loadSql',
+  'postCreateSql',
+  'preloadRequired',
+  'restartRequired',
+  'sharedMemoryRequired',
+  'startupConfig',
+]);
+const NATIVE_MODULE_FIELDS = Object.freeze(['moduleSha256', 'name', 'path', 'sha256', 'size']);
+const UNRESOLVED_IMPORT_FIELDS = Object.freeze(['kind', 'module', 'name']);
+
+function error(label, message) {
+  return new Error(`wasix-extension-install-contract: ${label} ${message}`);
+}
+
+function object(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    throw error(label, 'must be an object');
+  }
+  return value;
+}
+
+function exactObject(value, fields, label) {
+  const result = object(value, label);
+  const actual = Object.keys(result).sort();
+  const expected = [...fields].sort();
+  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+    throw error(label, `must contain exactly ${expected.join(', ')}`);
+  }
+  return result;
+}
+
+function nonEmptyString(value, label) {
+  if (typeof value !== 'string' || value.length === 0) {
+    throw error(label, 'must be a non-empty string');
+  }
+  return value;
+}
+
+function safeRelativePath(value, label) {
+  const result = nonEmptyString(value, label);
+  const normalized = result.replaceAll('\\', '/');
+  const segments = normalized.split('/');
+  if (
+    result !== normalized ||
+    result.startsWith('/') ||
+    segments.some((segment) => segment.length === 0 || segment === '.' || segment === '..')
+  ) {
+    throw error(label, 'must be a canonical safe relative path');
+  }
+  return result;
+}
+
+function sha256(value, label) {
+  if (typeof value !== 'string' || !LOWER_SHA256.test(value)) {
+    throw error(label, 'must be a lowercase SHA-256 digest');
+  }
+  return value;
+}
+
+function positiveSize(value, label) {
+  if (!Number.isSafeInteger(value) || value <= 0) {
+    throw error(label, 'must be a positive safe integer');
+  }
+  return value;
+}
+
+function stringList(value, label, { paths = false } = {}) {
+  if (!Array.isArray(value)) throw error(label, 'must be an array');
+  const result = value.map((entry, index) => {
+    const entryLabel = `${label}[${index}]`;
+    return paths ? safeRelativePath(entry, entryLabel) : nonEmptyString(entry, entryLabel);
+  });
+  if (new Set(result).size !== result.length) {
+    throw error(label, 'must not contain duplicates');
+  }
+  return result;
+}
+
+function uniqueValues(values, label) {
+  if (new Set(values).size !== values.length) {
+    throw error(label, 'must not contain duplicates');
+  }
+}
+
+function sqlName(value, label) {
+  const result = nonEmptyString(value, label);
+  if (!SQL_NAME.test(result)) throw error(label, 'must be a portable PostgreSQL extension name');
+  return result;
+}
+
+function sameValue(left, right) {
+  return JSON.stringify(left) === JSON.stringify(right);
+}
+
+function lifecycleFromManifest(value, label) {
+  const row = object(value, label);
+  const result = {
+    createExtension: row['create-extension'],
+    createSchema: row['create-schema'] ?? null,
+    loadSql: row['load-sql'],
+    postCreateSql: row['post-create-sql'],
+    startupConfig: row['startup-config'],
+    preloadRequired: row['preload-required'],
+    restartRequired: row['restart-required'],
+    sharedMemoryRequired: row['shared-memory-required'],
+  };
+  return checkedLifecycle(result, label);
+}
+
+function checkedLifecycle(value, label) {
+  const row = exactObject(value, LIFECYCLE_FIELDS, label);
+  for (const field of [
+    'createExtension',
+    'preloadRequired',
+    'restartRequired',
+    'sharedMemoryRequired',
+  ]) {
+    if (typeof row[field] !== 'boolean') throw error(`${label}.${field}`, 'must be a boolean');
+  }
+  if (row.createSchema !== null) nonEmptyString(row.createSchema, `${label}.createSchema`);
+  return {
+    createExtension: row.createExtension,
+    createSchema: row.createSchema,
+    loadSql: stringList(row.loadSql, `${label}.loadSql`),
+    postCreateSql: stringList(row.postCreateSql, `${label}.postCreateSql`),
+    startupConfig: stringList(row.startupConfig, `${label}.startupConfig`),
+    preloadRequired: row.preloadRequired,
+    restartRequired: row.restartRequired,
+    sharedMemoryRequired: row.sharedMemoryRequired,
+  };
+}
+
+function compactNativeModule(value, label) {
+  const row = object(value, label);
+  return checkedNativeModule(
+    {
+      name: row.name,
+      path: row.path,
+      sha256: row.sha256,
+      moduleSha256: row['module-sha256'],
+      size: row.size,
+    },
+    label,
+  );
+}
+
+function checkedNativeModule(value, label) {
+  const row = exactObject(value, NATIVE_MODULE_FIELDS, label);
+  return {
+    name: nonEmptyString(row.name, `${label}.name`),
+    path: safeRelativePath(row.path, `${label}.path`),
+    sha256: sha256(row.sha256, `${label}.sha256`),
+    moduleSha256: sha256(row.moduleSha256, `${label}.moduleSha256`),
+    size: positiveSize(row.size, `${label}.size`),
+  };
+}
+
+function checkedUnresolvedImport(value, label) {
+  const row = exactObject(value, UNRESOLVED_IMPORT_FIELDS, label);
+  return {
+    module: nonEmptyString(row.module, `${label}.module`),
+    name: nonEmptyString(row.name, `${label}.name`),
+    kind: nonEmptyString(row.kind, `${label}.kind`),
+  };
+}
+
+function checkedInstall(value, label, { expectedSqlName } = {}) {
+  const row = exactObject(value, INSTALL_FIELDS, label);
+  if (row.schema !== WASIX_EXTENSION_INSTALL_SCHEMA) {
+    throw error(`${label}.schema`, `must be ${WASIX_EXTENSION_INSTALL_SCHEMA}`);
+  }
+  const nativeModule =
+    row.nativeModule === null ? null : safeRelativePath(row.nativeModule, `${label}.nativeModule`);
+  if (!Array.isArray(row.nativeModules)) throw error(`${label}.nativeModules`, 'must be an array');
+  if (!Array.isArray(row.unresolvedImports)) {
+    throw error(`${label}.unresolvedImports`, 'must be an array');
+  }
+  const nativeModules = row.nativeModules.map((entry, index) =>
+    checkedNativeModule(entry, `${label}.nativeModules[${index}]`),
+  );
+  uniqueValues(
+    nativeModules.map((entry) => entry.name),
+    `${label}.nativeModules names`,
+  );
+  uniqueValues(
+    nativeModules.map((entry) => entry.path),
+    `${label}.nativeModules paths`,
+  );
+  if ((nativeModule === null) !== (nativeModules.length === 0)) {
+    throw error(`${label}.nativeModule`, 'must be null exactly when nativeModules is empty');
+  }
+  const dependencies = stringList(row.dependencies, `${label}.dependencies`).map(
+    (dependency, index) => sqlName(dependency, `${label}.dependencies[${index}]`),
+  );
+  if (expectedSqlName !== undefined) {
+    const rootSqlName = sqlName(expectedSqlName, `${label} expected SQL name`);
+    if (dependencies.includes(rootSqlName)) {
+      throw error(`${label}.dependencies`, `must not include its own SQL name ${rootSqlName}`);
+    }
+  }
+  const installedFiles = stringList(row.installedFiles, `${label}.installedFiles`, { paths: true });
+  for (const module of nativeModules) {
+    if (!installedFiles.includes(module.path)) {
+      throw error(`${label}.nativeModules`, `path ${module.path} must appear in installedFiles`);
+    }
+  }
+  return {
+    schema: WASIX_EXTENSION_INSTALL_SCHEMA,
+    name: nonEmptyString(row.name, `${label}.name`),
+    nativeModule,
+    nativeModules,
+    coreExportsRequired: stringList(row.coreExportsRequired, `${label}.coreExportsRequired`),
+    dependencies,
+    loadOrder: stringList(row.loadOrder, `${label}.loadOrder`, { paths: true }),
+    lifecycle: checkedLifecycle(row.lifecycle, `${label}.lifecycle`),
+    installedFiles,
+    unresolvedImports: row.unresolvedImports.map((entry, index) =>
+      checkedUnresolvedImport(entry, `${label}.unresolvedImports[${index}]`),
+    ),
+  };
+}
+
+export function assertWasixExtensionInstall(
+  value,
+  { expectedSqlName, label = 'WASIX extension install' } = {},
+) {
+  return deepFreeze(checkedInstall(value, label, { expectedSqlName }));
+}
+
+export function assertWasixExtensionMemberInstall(value, { label = 'extension member' } = {}) {
+  const member = object(value, label);
+  if (!Array.isArray(member.assets)) throw error(`${label}.assets`, 'must be an array');
+  const portableAssets = member.assets.filter(
+    (asset) =>
+      asset?.family === 'wasix' &&
+      asset?.target === 'wasix-portable' &&
+      asset?.kind === 'wasix-runtime',
+  );
+  if (portableAssets.length === 0) {
+    if (member.wasixInstall !== null) {
+      throw error(`${label}.wasixInstall`, 'must be null without a portable WASIX asset');
+    }
+    return null;
+  }
+  if (portableAssets.length !== 1) {
+    throw error(label, 'must declare exactly one portable WASIX asset');
+  }
+  return assertWasixExtensionInstall(member.wasixInstall, {
+    expectedSqlName: member.sqlName,
+    label: `${label}.wasixInstall`,
+  });
+}
+
+export function assertWasixExtensionInstallSidecar(
+  value,
+  {
+    expectedArchive,
+    expectedSha256,
+    expectedSize,
+    expectedSqlName,
+    label = 'install sidecar',
+  } = {},
+) {
+  const row = exactObject(value, SIDECAR_FIELDS, label);
+  if (row.schema !== WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA) {
+    throw error(`${label}.schema`, `must be ${WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA}`);
+  }
+  const sqlName = nonEmptyString(row.sqlName, `${label}.sqlName`);
+  if (!SQL_NAME.test(sqlName)) throw error(`${label}.sqlName`, 'is not portable');
+  const archive = safeRelativePath(row.archive, `${label}.archive`);
+  const digest = sha256(row.sha256, `${label}.sha256`);
+  const size = positiveSize(row.size, `${label}.size`);
+  if (expectedSqlName !== undefined && sqlName !== expectedSqlName) {
+    throw error(`${label}.sqlName`, `must be ${expectedSqlName}`);
+  }
+  if (archive !== `extensions/${sqlName}.tar.zst`) {
+    throw error(`${label}.archive`, `must be extensions/${sqlName}.tar.zst`);
+  }
+  if (expectedArchive !== undefined && archive !== expectedArchive) {
+    throw error(`${label}.archive`, `must be ${expectedArchive}`);
+  }
+  if (expectedSha256 !== undefined && digest !== expectedSha256) {
+    throw error(`${label}.sha256`, 'does not match the frozen archive digest');
+  }
+  if (expectedSize !== undefined && size !== expectedSize) {
+    throw error(`${label}.size`, 'does not match the frozen archive size');
+  }
+  return deepFreeze({
+    schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA,
+    sqlName,
+    archive,
+    sha256: digest,
+    size,
+    install: checkedInstall(row.install, `${label}.install`, { expectedSqlName: sqlName }),
+  });
+}
+
+function assertStaticModelMatchesBuilt(model, built, label) {
+  const modelSqlName = nonEmptyString(model['sql-name'], `${label} model.sql-name`);
+  const builtSqlName = nonEmptyString(built['sql-name'], `${label} manifest.sql-name`);
+  if (modelSqlName !== builtSqlName) throw error(label, 'static and built SQL names differ');
+  for (const [modelField, builtField] of [
+    ['archive', 'archive'],
+    ['dependencies', 'dependencies'],
+    ['load-order', 'load-order'],
+  ]) {
+    if (!sameValue(model[modelField], built[builtField])) {
+      throw error(label, `static ${modelField} differs from the built manifest`);
+    }
+  }
+  const modelNativeModule = model['native-module-file'] ?? null;
+  const builtNativeModule = built['native-module'] ?? null;
+  if (modelNativeModule !== builtNativeModule) {
+    throw error(label, 'static native-module-file differs from the built manifest');
+  }
+  if (
+    !sameValue(
+      lifecycleFromManifest(model.lifecycle, `${label} model.lifecycle`),
+      lifecycleFromManifest(built.lifecycle, `${label} manifest.lifecycle`),
+    )
+  ) {
+    throw error(label, 'static lifecycle differs from the built manifest');
+  }
+
+  const nativeModules = Array.isArray(built['native-modules'])
+    ? built['native-modules'].map((entry, index) =>
+        compactNativeModule(entry, `${label} manifest.native-modules[${index}]`),
+      )
+    : null;
+  if (nativeModules === null) throw error(label, 'built native-modules must be an array');
+  if (!Array.isArray(model['native-support-modules'])) {
+    throw error(label, 'static native-support-modules must be an array');
+  }
+  const expectedModulePaths = [
+    ...model['native-support-modules'].map((entry, index) =>
+      safeRelativePath(entry?.['runtime-path'], `${label} model.native-support-modules[${index}]`),
+    ),
+    ...(modelNativeModule === null ? [] : [`lib/postgresql/${modelNativeModule}`]),
+  ];
+  const actualModulePaths = nativeModules.map((entry) => entry.path);
+  if (
+    expectedModulePaths.length !== actualModulePaths.length ||
+    expectedModulePaths.some((modulePath) => !actualModulePaths.includes(modulePath))
+  ) {
+    throw error(label, 'static native module inventory differs from the built manifest');
+  }
+}
+
+export function projectWasixExtensionInstallSidecar(
+  { modelRow, manifestRow },
+  { archiveBytes, label = 'WASIX extension' } = {},
+) {
+  const model = object(modelRow, `${label} static model row`);
+  const built = object(manifestRow, `${label} built manifest row`);
+  assertStaticModelMatchesBuilt(model, built, label);
+  const sidecar = assertWasixExtensionInstallSidecar(
+    {
+      schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA,
+      sqlName: built['sql-name'],
+      archive: built.archive,
+      sha256: built.sha256,
+      size: built.size,
+      install: {
+        schema: WASIX_EXTENSION_INSTALL_SCHEMA,
+        name: built.name,
+        nativeModule: built['native-module'] ?? null,
+        nativeModules: built['native-modules'].map((entry, index) =>
+          compactNativeModule(entry, `${label} manifest.native-modules[${index}]`),
+        ),
+        coreExportsRequired: built['core-exports-required'],
+        dependencies: built.dependencies,
+        loadOrder: built['load-order'],
+        lifecycle: lifecycleFromManifest(built.lifecycle, `${label} manifest.lifecycle`),
+        installedFiles: built['installed-files'],
+        unresolvedImports: built['unresolved-imports'],
+      },
+    },
+    { label },
+  );
+  if (archiveBytes !== undefined)
+    assertWasixExtensionArchiveInstall(archiveBytes, sidecar, { label });
+  return sidecar;
+}
+
+export function assertWasixExtensionArchiveInstall(
+  archiveBytes,
+  sidecarValue,
+  { label = 'WASIX extension archive' } = {},
+) {
+  if (!Buffer.isBuffer(archiveBytes) && !(archiveBytes instanceof Uint8Array)) {
+    throw error(label, 'bytes must be a Buffer or Uint8Array');
+  }
+  const bytes = Buffer.from(archiveBytes);
+  const sidecar = assertWasixExtensionInstallSidecar(sidecarValue, { label: `${label} sidecar` });
+  if (bytes.length !== sidecar.size) throw error(label, 'size differs from its install sidecar');
+  if (createHash('sha256').update(bytes).digest('hex') !== sidecar.sha256) {
+    throw error(label, 'digest differs from its install sidecar');
+  }
+  let entries;
+  try {
+    entries = readPortableTarZstdBufferEntries(bytes, { label });
+  } catch (cause) {
+    throw error(label, cause.message);
+  }
+  const files = [...entries].filter(([, entry]) => entry.isFile).map(([member]) => member);
+  if (!sameValue(files, sidecar.install.installedFiles)) {
+    throw error(label, 'regular file inventory differs from install.installedFiles');
+  }
+  for (const [member, entry] of entries) {
+    if (entry.isSymbolicLink) throw error(label, `must not contain symbolic link ${member}`);
+  }
+  for (const module of sidecar.install.nativeModules) {
+    const entry = entries.get(module.path);
+    if (entry === undefined || !entry.isFile || entry.isSymbolicLink) {
+      throw error(label, `must contain native module ${module.path} as a regular file`);
+    }
+    const moduleBytes = Buffer.from(entry.data());
+    const digest = createHash('sha256').update(moduleBytes).digest('hex');
+    if (
+      moduleBytes.length !== module.size ||
+      digest !== module.sha256 ||
+      digest !== module.moduleSha256
+    ) {
+      throw error(label, `native module ${module.path} differs from its compact identity`);
+    }
+  }
+  return sidecar;
+}
+
+export function deepFreeze(value) {
+  if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
+    for (const child of Object.values(value)) deepFreeze(child);
+    Object.freeze(value);
+  }
+  return value;
+}
diff --git a/src/extensions/contracts/wasix-extension-install.test.mts b/src/extensions/contracts/wasix-extension-install.test.mts
new file mode 100644
index 000000000..9cf3288cf
--- /dev/null
+++ b/src/extensions/contracts/wasix-extension-install.test.mts
@@ -0,0 +1,218 @@
+#!/usr/bin/env bun
+import { createHash } from 'node:crypto';
+import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { zstdCompressSync } from 'node:zlib';
+import { afterAll, expect, test } from 'bun:test';
+
+import { createDeterministicTar } from '../../../tools/packaging/archive-directory.mts';
+import {
+  assertWasixExtensionInstall,
+  assertWasixExtensionMemberInstall,
+  projectWasixExtensionInstallSidecar,
+} from './wasix-extension-install.mts';
+
+const directories = [];
+
+afterAll(() => {
+  for (const directory of directories) rmSync(directory, { recursive: true, force: true });
+});
+
+function sha256(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+async function fixture() {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-wasix-install-contract-'));
+  directories.push(root);
+  const moduleBytes = Buffer.from('wasix-side-module');
+  const modulePath = 'lib/postgresql/example.so';
+  const controlPath = 'share/postgresql/extension/example.control';
+  for (const [member, bytes] of [
+    [modulePath, moduleBytes],
+    [controlPath, Buffer.from("default_version = '1.0'\n")],
+  ]) {
+    const output = path.join(root, ...member.split('/'));
+    mkdirSync(path.dirname(output), { recursive: true });
+    writeFileSync(output, bytes);
+  }
+  const archiveBytes = zstdCompressSync(await createDeterministicTar(root));
+  const lifecycle = {
+    'create-extension': true,
+    'create-schema': 'pg_catalog',
+    'load-sql': [],
+    'post-create-sql': [],
+    'startup-config': [],
+    'preload-required': false,
+    'restart-required': false,
+    'shared-memory-required': false,
+  };
+  const modelRow = {
+    id: 'example',
+    'sql-name': 'example',
+    archive: 'extensions/example.tar.zst',
+    dependencies: ['plpgsql'],
+    'load-order': [modulePath],
+    lifecycle,
+    'native-module-file': 'example.so',
+    'native-support-modules': [],
+  };
+  const manifestRow = {
+    name: 'Example',
+    'sql-name': 'example',
+    archive: 'extensions/example.tar.zst',
+    sha256: sha256(archiveBytes),
+    size: archiveBytes.length,
+    'native-module': 'example.so',
+    'native-modules': [
+      {
+        name: 'example',
+        path: modulePath,
+        sha256: sha256(moduleBytes),
+        'module-sha256': sha256(moduleBytes),
+        size: moduleBytes.length,
+        link: { deliberately: 'not public' },
+      },
+    ],
+    'core-exports-required': ['palloc'],
+    dependencies: ['plpgsql'],
+    'load-order': [modulePath],
+    lifecycle,
+    'installed-files': [modulePath, controlPath],
+    'unresolved-imports': [],
+  };
+  return { archiveBytes, manifestRow, modelRow };
+}
+
+test('projects and deeply freezes only the compact extension-owned install authority', async () => {
+  const value = await fixture();
+  const sidecar = projectWasixExtensionInstallSidecar(value, {
+    archiveBytes: value.archiveBytes,
+    label: 'example fixture',
+  });
+  expect(sidecar).toMatchObject({
+    schema: 'oliphaunt-wasix-extension-install-sidecar-v1',
+    sqlName: 'example',
+    archive: 'extensions/example.tar.zst',
+    install: {
+      schema: 'oliphaunt-wasix-extension-install-v1',
+      dependencies: ['plpgsql'],
+      coreExportsRequired: ['palloc'],
+    },
+  });
+  expect(sidecar.install.nativeModules[0]).toEqual({
+    name: 'example',
+    path: 'lib/postgresql/example.so',
+    sha256: value.manifestRow['native-modules'][0].sha256,
+    moduleSha256: value.manifestRow['native-modules'][0]['module-sha256'],
+    size: value.manifestRow['native-modules'][0].size,
+  });
+  expect(Object.isFrozen(sidecar.install.nativeModules[0])).toBe(true);
+  expect(Object.isFrozen(sidecar.install.lifecycle.loadSql)).toBe(true);
+});
+
+test('rejects installed-file and compact module hash drift against the archive', async () => {
+  const missingFile = await fixture();
+  missingFile.manifestRow['installed-files'] = ['lib/postgresql/example.so'];
+  expect(() =>
+    projectWasixExtensionInstallSidecar(missingFile, {
+      archiveBytes: missingFile.archiveBytes,
+      label: 'missing file fixture',
+    }),
+  ).toThrow(/regular file inventory differs from install[.]installedFiles/u);
+
+  const badModule = await fixture();
+  badModule.manifestRow['native-modules'][0]['module-sha256'] = 'a'.repeat(64);
+  expect(() =>
+    projectWasixExtensionInstallSidecar(badModule, {
+      archiveBytes: badModule.archiveBytes,
+      label: 'bad module fixture',
+    }),
+  ).toThrow(/differs from its compact identity/u);
+});
+
+test('rejects install contracts that the consumer descriptor cannot accept', async () => {
+  const value = await fixture();
+  const install = structuredClone(
+    projectWasixExtensionInstallSidecar(value, {
+      archiveBytes: value.archiveBytes,
+      label: 'consumer parity fixture',
+    }).install,
+  );
+
+  const duplicateModule = structuredClone(install);
+  duplicateModule.nativeModules.push({ ...duplicateModule.nativeModules[0] });
+  expect(() =>
+    assertWasixExtensionInstall(duplicateModule, {
+      expectedSqlName: 'example',
+    }),
+  ).toThrow(/nativeModules names must not contain duplicates/u);
+
+  const missingModuleIdentity = structuredClone(install);
+  missingModuleIdentity.nativeModule = null;
+  expect(() =>
+    assertWasixExtensionInstall(missingModuleIdentity, {
+      expectedSqlName: 'example',
+    }),
+  ).toThrow(/must be null exactly when nativeModules is empty/u);
+
+  const selfDependency = structuredClone(install);
+  selfDependency.dependencies = ['example'];
+  expect(() =>
+    assertWasixExtensionInstall(selfDependency, {
+      expectedSqlName: 'example',
+    }),
+  ).toThrow(/must not include its own SQL name example/u);
+
+  const missingInstalledModule = structuredClone(install);
+  missingInstalledModule.installedFiles = missingInstalledModule.installedFiles.filter(
+    (file) => file !== missingInstalledModule.nativeModules[0].path,
+  );
+  expect(() =>
+    assertWasixExtensionInstall(missingInstalledModule, {
+      expectedSqlName: 'example',
+    }),
+  ).toThrow(/must appear in installedFiles/u);
+});
+
+test('binds one install contract to exactly one portable member asset', async () => {
+  const value = await fixture();
+  const install = projectWasixExtensionInstallSidecar(value, {
+    archiveBytes: value.archiveBytes,
+    label: 'member fixture',
+  }).install;
+  const portableAsset = {
+    family: 'wasix',
+    kind: 'wasix-runtime',
+    target: 'wasix-portable',
+  };
+  expect(
+    assertWasixExtensionMemberInstall({
+      sqlName: 'example',
+      assets: [portableAsset],
+      wasixInstall: install,
+    }),
+  ).toEqual(install);
+  expect(
+    assertWasixExtensionMemberInstall({
+      sqlName: 'example',
+      assets: [{ family: 'native', kind: 'runtime', target: 'linux-x64-gnu' }],
+      wasixInstall: null,
+    }),
+  ).toBeNull();
+  expect(() =>
+    assertWasixExtensionMemberInstall({
+      sqlName: 'example',
+      assets: [],
+      wasixInstall: install,
+    }),
+  ).toThrow(/must be null without a portable WASIX asset/u);
+  expect(() =>
+    assertWasixExtensionMemberInstall({
+      sqlName: 'example',
+      assets: [portableAsset, portableAsset],
+      wasixInstall: install,
+    }),
+  ).toThrow(/must declare exactly one portable WASIX asset/u);
+});
diff --git a/src/extensions/contrib/carriers.toml b/src/extensions/contrib/carriers.toml
index 8a3dc14a9..95dfb1d7f 100644
--- a/src/extensions/contrib/carriers.toml
+++ b/src/extensions/contrib/carriers.toml
@@ -1,6 +1,6 @@
 logical_product = "oliphaunt-extension-contrib-pg18"
 member_manifest = "src/extensions/contrib/postgres18.toml"
-source = "src/postgres/versions/18/source.toml"
-contract = "src/shared/extension-runtime-contract/contract.toml"
+source = "src/third-party/postgres/source.toml"
+contract = "src/extensions/contracts/contract.toml"
 native_owner = "liboliphaunt-native"
 wasix_owner = "liboliphaunt-wasix"
diff --git a/src/extensions/contrib/postgres18.toml b/src/extensions/contrib/postgres18.toml
index 28e583bbc..ec2dcd9c4 100644
--- a/src/extensions/contrib/postgres18.toml
+++ b/src/extensions/contrib/postgres18.toml
@@ -1,7 +1,7 @@
 format-version = 1
 postgres-version = "18.4"
 source-kind = "postgres-contrib"
-source-root = "src/postgres/versions/18/contrib"
+source-root = "src/third-party/postgres/contrib"
 
 [[extensions]]
 id = "amcheck"
@@ -227,6 +227,6 @@ sql-name = "uuid-ossp"
 contrib-dir = "uuid-ossp"
 module-file = "uuid-ossp.so"
 default-version = "1.1"
-mobile-static-include-dirs = ["src/runtimes/liboliphaunt/native/portable-uuid/include"]
+mobile-static-include-dirs = ["src/runtimes/liboliphaunt-native/portable-uuid/include"]
 mobile-static-cflags = ["-DHAVE_UUID_E2FS=1", "-DHAVE_UUID_UUID_H=1"]
-mobile-static-hash-dirs = ["src/runtimes/liboliphaunt/native/portable-uuid"]
+mobile-static-hash-dirs = ["src/runtimes/liboliphaunt-native/portable-uuid"]
diff --git a/src/extensions/evidence/matrix.toml b/src/extensions/evidence/matrix.toml
index 95873ef46..f74fcdc5d 100644
--- a/src/extensions/evidence/matrix.toml
+++ b/src/extensions/evidence/matrix.toml
@@ -1,12 +1,13 @@
 format-version = 1
 source-digest-inputs = [
-  "src/postgres/versions/18/source.toml",
+  "src/third-party/postgres/source.toml",
   "src/extensions/catalog/extensions.source.json",
   "src/extensions/catalog/native-components.toml",
   "src/extensions/contrib/postgres18.toml",
   "src/extensions/generated/extensions.catalog.json",
   "src/extensions/generated/contrib-build.tsv",
   "src/extensions/generated/pgxs-build.tsv",
+  "src/database-resources/icu/source.toml",
   "src/extensions/external/pg_hashids/source.toml",
   "src/extensions/external/pg_ivm/source.toml",
   "src/extensions/external/pg_textsearch/source.toml",
@@ -20,10 +21,9 @@ source-digest-inputs = [
   "src/extensions/external/postgis/dependencies/sqlite/source.toml",
   "src/extensions/external/postgis/source.toml",
   "src/extensions/external/vector/source.toml",
-  "src/sources/third-party/native/icu-windows.toml",
-  "src/sources/third-party/shared/icu-data.toml",
-  "src/sources/third-party/shared/icu.toml",
-  "src/sources/third-party/shared/openssl.toml",
+  "src/runtimes/liboliphaunt-native/sources/icu-windows.toml",
+  "src/third-party/icu/source.toml",
+  "src/third-party/openssl/source.toml",
   "src/extensions/external/README.md",
   "src/extensions/external/pg_hashids/upstream-license-data.json",
   "src/extensions/external/pg_ivm/targets/native-static-registry.toml",
@@ -42,52 +42,57 @@ source-digest-inputs = [
   "src/extensions/external/postgis/targets/native-static-registry.toml",
   "src/extensions/external/postgis/targets/native.toml",
   "src/extensions/external/postgis/targets/wasix.toml",
-  "src/extensions/external/postgis/tests/regression.sql",
   "src/extensions/external/postgis/tools/build_wasix.sh",
+  "src/extensions/external/postgis/tools/preprocess-sql.mts",
   "src/extensions/external/postgis/tools/reproducible-bin/date",
   "src/extensions/external/postgis/tools/reproducible-time.sh",
+  "src/extensions/external/postgis/tools/windows/build-sql.sh",
+  "src/extensions/external/postgis/tools/windows/flatgeobuf-compat.h",
+  "src/extensions/external/postgis/tools/windows/meson.build.in",
+  "src/extensions/external/postgis/tools/windows/postgis-compat.h",
+  "src/extensions/external/postgis/tools/windows/postgis_config.h.in",
   "src/extensions/external/postgis/upstream-license-data.json",
   "src/extensions/external/vector/upstream-license-data.json",
-  "src/shared/fixtures/extensions/manifest.json",
-  "src/shared/fixtures/extensions/amcheck.sql",
-  "src/shared/fixtures/extensions/auto_explain.sql",
-  "src/shared/fixtures/extensions/bloom.sql",
-  "src/shared/fixtures/extensions/btree_gin.sql",
-  "src/shared/fixtures/extensions/btree_gist.sql",
-  "src/shared/fixtures/extensions/citext.sql",
-  "src/shared/fixtures/extensions/cube.sql",
-  "src/shared/fixtures/extensions/dict_int.sql",
-  "src/shared/fixtures/extensions/dict_xsyn.sql",
-  "src/shared/fixtures/extensions/earthdistance.sql",
-  "src/shared/fixtures/extensions/file_fdw.sql",
-  "src/shared/fixtures/extensions/fuzzystrmatch.sql",
-  "src/shared/fixtures/extensions/hstore.sql",
-  "src/shared/fixtures/extensions/intarray.sql",
-  "src/shared/fixtures/extensions/isn.sql",
-  "src/shared/fixtures/extensions/lo.sql",
-  "src/shared/fixtures/extensions/ltree.sql",
-  "src/shared/fixtures/extensions/pageinspect.sql",
-  "src/shared/fixtures/extensions/pg_buffercache.sql",
-  "src/shared/fixtures/extensions/pg_freespacemap.sql",
-  "src/shared/fixtures/extensions/pg_hashids.sql",
-  "src/shared/fixtures/extensions/pg_ivm.sql",
-  "src/shared/fixtures/extensions/pg_surgery.sql",
-  "src/shared/fixtures/extensions/pg_textsearch.sql",
-  "src/shared/fixtures/extensions/pg_trgm.sql",
-  "src/shared/fixtures/extensions/pg_uuidv7.sql",
-  "src/shared/fixtures/extensions/pg_visibility.sql",
-  "src/shared/fixtures/extensions/pg_walinspect.sql",
-  "src/shared/fixtures/extensions/pgcrypto.sql",
-  "src/shared/fixtures/extensions/pgtap.sql",
-  "src/shared/fixtures/extensions/postgis.sql",
-  "src/shared/fixtures/extensions/seg.sql",
-  "src/shared/fixtures/extensions/tablefunc.sql",
-  "src/shared/fixtures/extensions/tcn.sql",
-  "src/shared/fixtures/extensions/tsm_system_rows.sql",
-  "src/shared/fixtures/extensions/tsm_system_time.sql",
-  "src/shared/fixtures/extensions/unaccent.sql",
-  "src/shared/fixtures/extensions/uuid-ossp.sql",
-  "src/shared/fixtures/extensions/vector.sql",
+  "src/test-fixtures/extensions/manifest.json",
+  "src/test-fixtures/extensions/amcheck.sql",
+  "src/test-fixtures/extensions/auto_explain.sql",
+  "src/test-fixtures/extensions/bloom.sql",
+  "src/test-fixtures/extensions/btree_gin.sql",
+  "src/test-fixtures/extensions/btree_gist.sql",
+  "src/test-fixtures/extensions/citext.sql",
+  "src/test-fixtures/extensions/cube.sql",
+  "src/test-fixtures/extensions/dict_int.sql",
+  "src/test-fixtures/extensions/dict_xsyn.sql",
+  "src/test-fixtures/extensions/earthdistance.sql",
+  "src/test-fixtures/extensions/file_fdw.sql",
+  "src/test-fixtures/extensions/fuzzystrmatch.sql",
+  "src/test-fixtures/extensions/hstore.sql",
+  "src/test-fixtures/extensions/intarray.sql",
+  "src/test-fixtures/extensions/isn.sql",
+  "src/test-fixtures/extensions/lo.sql",
+  "src/test-fixtures/extensions/ltree.sql",
+  "src/test-fixtures/extensions/pageinspect.sql",
+  "src/test-fixtures/extensions/pg_buffercache.sql",
+  "src/test-fixtures/extensions/pg_freespacemap.sql",
+  "src/test-fixtures/extensions/pg_hashids.sql",
+  "src/test-fixtures/extensions/pg_ivm.sql",
+  "src/test-fixtures/extensions/pg_surgery.sql",
+  "src/test-fixtures/extensions/pg_textsearch.sql",
+  "src/test-fixtures/extensions/pg_trgm.sql",
+  "src/test-fixtures/extensions/pg_uuidv7.sql",
+  "src/test-fixtures/extensions/pg_visibility.sql",
+  "src/test-fixtures/extensions/pg_walinspect.sql",
+  "src/test-fixtures/extensions/pgcrypto.sql",
+  "src/test-fixtures/extensions/pgtap.sql",
+  "src/test-fixtures/extensions/postgis.sql",
+  "src/test-fixtures/extensions/seg.sql",
+  "src/test-fixtures/extensions/tablefunc.sql",
+  "src/test-fixtures/extensions/tcn.sql",
+  "src/test-fixtures/extensions/tsm_system_rows.sql",
+  "src/test-fixtures/extensions/tsm_system_time.sql",
+  "src/test-fixtures/extensions/unaccent.sql",
+  "src/test-fixtures/extensions/uuid-ossp.sql",
+  "src/test-fixtures/extensions/vector.sql",
 ]
 
 [[claims]]
@@ -95,7 +100,7 @@ extension = "amcheck"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -103,7 +108,7 @@ extension = "auto_explain"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -111,7 +116,7 @@ extension = "bloom"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -119,7 +124,7 @@ extension = "btree_gin"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -127,7 +132,7 @@ extension = "btree_gist"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -135,7 +140,7 @@ extension = "citext"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -143,7 +148,7 @@ extension = "cube"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -151,7 +156,7 @@ extension = "dict_int"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -159,7 +164,7 @@ extension = "dict_xsyn"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -167,7 +172,7 @@ extension = "earthdistance"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -175,7 +180,7 @@ extension = "file_fdw"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -183,7 +188,7 @@ extension = "fuzzystrmatch"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -191,7 +196,7 @@ extension = "hstore"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -199,7 +204,7 @@ extension = "intarray"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -207,7 +212,7 @@ extension = "isn"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -215,7 +220,7 @@ extension = "lo"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -223,7 +228,7 @@ extension = "ltree"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -231,7 +236,7 @@ extension = "pageinspect"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -239,7 +244,7 @@ extension = "pg_buffercache"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -247,7 +252,7 @@ extension = "pg_freespacemap"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -255,7 +260,7 @@ extension = "pg_hashids"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -263,7 +268,7 @@ extension = "pg_ivm"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -271,7 +276,7 @@ extension = "pg_surgery"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -279,7 +284,7 @@ extension = "pg_textsearch"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -287,7 +292,7 @@ extension = "pg_trgm"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -295,7 +300,7 @@ extension = "pg_uuidv7"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -303,7 +308,7 @@ extension = "pg_visibility"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -311,7 +316,7 @@ extension = "pg_walinspect"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -319,7 +324,7 @@ extension = "pgcrypto"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -327,7 +332,7 @@ extension = "pgtap"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -335,7 +340,7 @@ extension = "postgis"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -343,7 +348,7 @@ extension = "seg"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -351,7 +356,7 @@ extension = "tablefunc"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -359,7 +364,7 @@ extension = "tcn"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -367,7 +372,7 @@ extension = "tsm_system_rows"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -375,7 +380,7 @@ extension = "tsm_system_time"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -383,7 +388,7 @@ extension = "unaccent"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -391,7 +396,7 @@ extension = "uuid_ossp"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
 
 [[claims]]
@@ -399,5 +404,5 @@ extension = "vector"
 postgres-major = 18
 artifact-family = "wasix-runtime"
 platform-targets = ["portable"]
-runtime-modes = ["direct", "server", "restart", "dump-restore"]
+runtime-modes = ["direct", "server", "restart", "backup-restore"]
 evidence-required = ["wasix-full-lifecycle-v1"]
diff --git a/src/extensions/evidence/runs/2026-06-07-transitional-catalog-smoke.json b/src/extensions/evidence/runs/2026-06-07-transitional-catalog-smoke.json
index ebdf80408..c43c34303 100644
--- a/src/extensions/evidence/runs/2026-06-07-transitional-catalog-smoke.json
+++ b/src/extensions/evidence/runs/2026-06-07-transitional-catalog-smoke.json
@@ -1,5 +1,5 @@
 {
-  "collector": "tools/dev/bun.sh src/extensions/tools/check-extension-model.mjs --write-evidence",
+  "collector": "tools/dev/bun.sh extensions/tools/check-extension-model.mjs --write-evidence",
   "evidenceTier": "transitional-catalog-smoke",
   "id": "2026-06-07-transitional-catalog-smoke",
   "notes": "Transitional evidence imported from extensions.smoke.toml while per-recipe evidence runs are introduced.",
@@ -516,62 +516,62 @@
   "schema": "oliphaunt-extension-evidence-v1",
   "sourceDigest": "sha256:de166adedb39eb3a867e42290903ea34c5a08810df9bc2e7e225f8c17cab5dfe",
   "sourceDigestInputs": [
-    "src/postgres/versions/18/source.toml",
-    "src/extensions/catalog/extensions.promoted.toml",
-    "src/extensions/catalog/extensions.smoke.toml",
-    "src/extensions/contrib/postgres18.toml",
-    "src/extensions/generated/extensions.catalog.json",
-    "src/extensions/generated/extensions.build-plan.json",
-    "src/extensions/generated/contrib-build.tsv",
-    "src/extensions/generated/pgxs-build.tsv",
-    "src/runtimes/liboliphaunt/wasix/assets/generated/asset-inputs.sha256",
-    "src/extensions/external/age/source.toml",
-    "src/extensions/external/pg_hashids/source.toml",
-    "src/extensions/external/pg_ivm/source.toml",
-    "src/extensions/external/pg_textsearch/source.toml",
-    "src/extensions/external/pg_uuidv7/source.toml",
-    "src/extensions/external/pgtap/source.toml",
-    "src/extensions/external/postgis/dependencies/geos/source.toml",
-    "src/extensions/external/postgis/dependencies/json-c/source.toml",
-    "src/extensions/external/postgis/dependencies/libiconv/source.toml",
-    "src/extensions/external/postgis/dependencies/libxml2/source.toml",
-    "src/extensions/external/postgis/dependencies/proj/source.toml",
-    "src/extensions/external/postgis/dependencies/sqlite/source.toml",
-    "src/extensions/external/postgis/source.toml",
-    "src/extensions/external/vector/source.toml",
+    "third-party/postgres/source.toml",
+    "extensions/catalog/extensions.promoted.toml",
+    "extensions/catalog/extensions.smoke.toml",
+    "extensions/contrib/postgres18.toml",
+    "extensions/generated/extensions.catalog.json",
+    "extensions/generated/extensions.build-plan.json",
+    "extensions/generated/contrib-build.tsv",
+    "extensions/generated/pgxs-build.tsv",
+    "runtimes/liboliphaunt-wasix/assets/generated/asset-inputs.sha256",
+    "extensions/external/age/source.toml",
+    "extensions/external/pg_hashids/source.toml",
+    "extensions/external/pg_ivm/source.toml",
+    "extensions/external/pg_textsearch/source.toml",
+    "extensions/external/pg_uuidv7/source.toml",
+    "extensions/external/pgtap/source.toml",
+    "extensions/external/postgis/dependencies/geos/source.toml",
+    "extensions/external/postgis/dependencies/json-c/source.toml",
+    "extensions/external/postgis/dependencies/libiconv/source.toml",
+    "extensions/external/postgis/dependencies/libxml2/source.toml",
+    "extensions/external/postgis/dependencies/proj/source.toml",
+    "extensions/external/postgis/dependencies/sqlite/source.toml",
+    "extensions/external/postgis/source.toml",
+    "extensions/external/vector/source.toml",
     "src/sources/third-party/shared/icu.toml",
     "src/sources/third-party/shared/openssl.toml",
-    "src/extensions/external/README.md",
-    "src/extensions/external/age/moon.yml",
-    "src/extensions/external/pg_hashids/moon.yml",
-    "src/extensions/external/pg_ivm/moon.yml",
-    "src/extensions/external/pg_ivm/targets/native-static-registry.toml",
-    "src/extensions/external/pg_textsearch/moon.yml",
-    "src/extensions/external/pg_textsearch/recipe.toml",
-    "src/extensions/external/pg_textsearch/targets/native-static-registry.toml",
-    "src/extensions/external/pg_textsearch/tests/smoke.sql",
-    "src/extensions/external/pg_textsearch/tests/upstream.toml",
-    "src/extensions/external/pg_uuidv7/moon.yml",
-    "src/extensions/external/pgtap/moon.yml",
-    "src/extensions/external/pgtap/recipe.toml",
-    "src/extensions/external/pgtap/targets/native-static-registry.toml",
-    "src/extensions/external/pgtap/targets/native.toml",
-    "src/extensions/external/pgtap/targets/wasix.toml",
-    "src/extensions/external/pgtap/tests/smoke.sql",
-    "src/extensions/external/pgtap/tests/upstream.toml",
-    "src/extensions/external/postgis/blockers.toml",
-    "src/extensions/external/postgis/deps.toml",
-    "src/extensions/external/postgis/moon.yml",
-    "src/extensions/external/postgis/patches/README.md",
-    "src/extensions/external/postgis/recipe.toml",
-    "src/extensions/external/postgis/targets/native-static-registry.toml",
-    "src/extensions/external/postgis/targets/native.toml",
-    "src/extensions/external/postgis/targets/wasix.toml",
-    "src/extensions/external/postgis/tests/regression.sql",
-    "src/extensions/external/postgis/tests/smoke.sql",
-    "src/extensions/external/postgis/tests/upstream.toml",
-    "src/extensions/external/postgis/tools/build_wasix.sh",
-    "src/extensions/external/vector/moon.yml"
+    "extensions/external/README.md",
+    "extensions/external/age/moon.yml",
+    "extensions/external/pg_hashids/moon.yml",
+    "extensions/external/pg_ivm/moon.yml",
+    "extensions/external/pg_ivm/targets/native-static-registry.toml",
+    "extensions/external/pg_textsearch/moon.yml",
+    "extensions/external/pg_textsearch/recipe.toml",
+    "extensions/external/pg_textsearch/targets/native-static-registry.toml",
+    "extensions/external/pg_textsearch/tests/smoke.sql",
+    "extensions/external/pg_textsearch/tests/upstream.toml",
+    "extensions/external/pg_uuidv7/moon.yml",
+    "extensions/external/pgtap/moon.yml",
+    "extensions/external/pgtap/recipe.toml",
+    "extensions/external/pgtap/targets/native-static-registry.toml",
+    "extensions/external/pgtap/targets/native.toml",
+    "extensions/external/pgtap/targets/wasix.toml",
+    "extensions/external/pgtap/tests/smoke.sql",
+    "extensions/external/pgtap/tests/upstream.toml",
+    "extensions/external/postgis/blockers.toml",
+    "extensions/external/postgis/deps.toml",
+    "extensions/external/postgis/moon.yml",
+    "extensions/external/postgis/patches/README.md",
+    "extensions/external/postgis/recipe.toml",
+    "extensions/external/postgis/targets/native-static-registry.toml",
+    "extensions/external/postgis/targets/native.toml",
+    "extensions/external/postgis/targets/wasix.toml",
+    "extensions/external/postgis/tests/regression.sql",
+    "extensions/external/postgis/tests/smoke.sql",
+    "extensions/external/postgis/tests/upstream.toml",
+    "extensions/external/postgis/tools/build_wasix.sh",
+    "extensions/external/vector/moon.yml"
   ],
   "status": "passed"
 }
diff --git a/src/extensions/external/pg_hashids/CHANGELOG.md b/src/extensions/external/pg_hashids/CHANGELOG.md
index 562cdd1da..6db257f7e 100644
--- a/src/extensions/external/pg_hashids/CHANGELOG.md
+++ b/src/extensions/external/pg_hashids/CHANGELOG.md
@@ -5,7 +5,6 @@
 
 ### ⚠ BREAKING CHANGES
 
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/extensions/external/pg_hashids/release.toml b/src/extensions/external/pg_hashids/release.toml
index 9343649a9..ab7c82b5e 100644
--- a/src/extensions/external/pg_hashids/release.toml
+++ b/src/extensions/external/pg_hashids/release.toml
@@ -40,7 +40,7 @@ path = "src/extensions/external/pg_hashids/source.toml"
 
 [extension.compatibility]
 postgres_major = "18"
-extension_runtime_contract = "src/shared/extension-runtime-contract/contract.toml"
+extension_runtime_contract = "src/extensions/contracts/contract.toml"
 native_runtime_product = "liboliphaunt-native"
 native_runtime_version = "0.2.0"
 wasix_runtime_product = "liboliphaunt-wasix"
diff --git a/src/extensions/external/pg_ivm/CHANGELOG.md b/src/extensions/external/pg_ivm/CHANGELOG.md
index 01f8db6b9..0ffb7648c 100644
--- a/src/extensions/external/pg_ivm/CHANGELOG.md
+++ b/src/extensions/external/pg_ivm/CHANGELOG.md
@@ -5,7 +5,6 @@
 
 ### ⚠ BREAKING CHANGES
 
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/extensions/external/pg_ivm/release.toml b/src/extensions/external/pg_ivm/release.toml
index f2bf46f0c..da8f4980c 100644
--- a/src/extensions/external/pg_ivm/release.toml
+++ b/src/extensions/external/pg_ivm/release.toml
@@ -40,7 +40,7 @@ path = "src/extensions/external/pg_ivm/source.toml"
 
 [extension.compatibility]
 postgres_major = "18"
-extension_runtime_contract = "src/shared/extension-runtime-contract/contract.toml"
+extension_runtime_contract = "src/extensions/contracts/contract.toml"
 native_runtime_product = "liboliphaunt-native"
 native_runtime_version = "0.2.0"
 wasix_runtime_product = "liboliphaunt-wasix"
diff --git a/src/extensions/external/pg_textsearch/CHANGELOG.md b/src/extensions/external/pg_textsearch/CHANGELOG.md
index cbda0c5b9..8b52edbfe 100644
--- a/src/extensions/external/pg_textsearch/CHANGELOG.md
+++ b/src/extensions/external/pg_textsearch/CHANGELOG.md
@@ -5,7 +5,6 @@
 
 ### ⚠ BREAKING CHANGES
 
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/extensions/external/pg_textsearch/release.toml b/src/extensions/external/pg_textsearch/release.toml
index 53ebc0370..cbbee270f 100644
--- a/src/extensions/external/pg_textsearch/release.toml
+++ b/src/extensions/external/pg_textsearch/release.toml
@@ -40,7 +40,7 @@ path = "src/extensions/external/pg_textsearch/source.toml"
 
 [extension.compatibility]
 postgres_major = "18"
-extension_runtime_contract = "src/shared/extension-runtime-contract/contract.toml"
+extension_runtime_contract = "src/extensions/contracts/contract.toml"
 native_runtime_product = "liboliphaunt-native"
 native_runtime_version = "0.2.0"
 wasix_runtime_product = "liboliphaunt-wasix"
diff --git a/src/extensions/external/pg_textsearch/targets/native-static-registry.toml b/src/extensions/external/pg_textsearch/targets/native-static-registry.toml
index 8b11a32bf..24ebabcfb 100644
--- a/src/extensions/external/pg_textsearch/targets/native-static-registry.toml
+++ b/src/extensions/external/pg_textsearch/targets/native-static-registry.toml
@@ -3,4 +3,4 @@ artifact_family = "native-static-registry"
 build_kind = "pgxs-static-registry"
 source_recursive_dirs = ["src"]
 include_dirs = ["source:src"]
-cflags = ['-DPG_TEXTSEARCH_VERSION="0.6.1"']
+cflags = ['-DPG_TEXTSEARCH_VERSION="@EXTVERSION@"']
diff --git a/src/extensions/external/pg_uuidv7/CHANGELOG.md b/src/extensions/external/pg_uuidv7/CHANGELOG.md
index ef3888b46..19690145b 100644
--- a/src/extensions/external/pg_uuidv7/CHANGELOG.md
+++ b/src/extensions/external/pg_uuidv7/CHANGELOG.md
@@ -5,7 +5,6 @@
 
 ### ⚠ BREAKING CHANGES
 
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/extensions/external/pg_uuidv7/release.toml b/src/extensions/external/pg_uuidv7/release.toml
index 019f090ad..76dc9df4f 100644
--- a/src/extensions/external/pg_uuidv7/release.toml
+++ b/src/extensions/external/pg_uuidv7/release.toml
@@ -40,7 +40,7 @@ path = "src/extensions/external/pg_uuidv7/source.toml"
 
 [extension.compatibility]
 postgres_major = "18"
-extension_runtime_contract = "src/shared/extension-runtime-contract/contract.toml"
+extension_runtime_contract = "src/extensions/contracts/contract.toml"
 native_runtime_product = "liboliphaunt-native"
 native_runtime_version = "0.2.0"
 wasix_runtime_product = "liboliphaunt-wasix"
diff --git a/src/extensions/external/pgtap/CHANGELOG.md b/src/extensions/external/pgtap/CHANGELOG.md
index f1434c6d2..5546a303a 100644
--- a/src/extensions/external/pgtap/CHANGELOG.md
+++ b/src/extensions/external/pgtap/CHANGELOG.md
@@ -5,7 +5,6 @@
 
 ### ⚠ BREAKING CHANGES
 
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/extensions/external/pgtap/release.toml b/src/extensions/external/pgtap/release.toml
index a8254531c..e37eb1975 100644
--- a/src/extensions/external/pgtap/release.toml
+++ b/src/extensions/external/pgtap/release.toml
@@ -36,7 +36,7 @@ path = "src/extensions/external/pgtap/source.toml"
 
 [extension.compatibility]
 postgres_major = "18"
-extension_runtime_contract = "src/shared/extension-runtime-contract/contract.toml"
+extension_runtime_contract = "src/extensions/contracts/contract.toml"
 native_runtime_product = "liboliphaunt-native"
 native_runtime_version = "0.2.0"
 wasix_runtime_product = "liboliphaunt-wasix"
diff --git a/src/extensions/external/postgis/CHANGELOG.md b/src/extensions/external/postgis/CHANGELOG.md
index 54713f723..dcf0797ec 100644
--- a/src/extensions/external/postgis/CHANGELOG.md
+++ b/src/extensions/external/postgis/CHANGELOG.md
@@ -5,7 +5,6 @@
 
 ### ⚠ BREAKING CHANGES
 
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/extensions/external/postgis/dependencies/libiconv/source.toml b/src/extensions/external/postgis/dependencies/libiconv/source.toml
index 6e1a3fb09..f47e04a1e 100644
--- a/src/extensions/external/postgis/dependencies/libiconv/source.toml
+++ b/src/extensions/external/postgis/dependencies/libiconv/source.toml
@@ -1,6 +1,8 @@
 name = "libiconv"
 kind = "archive"
 url = "https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz"
+# GNU-listed HTTPS mirror: https://www.gnu.org/prep/ftp.en.html
+mirror_url = "https://mirrors.ocf.berkeley.edu/gnu/libiconv/libiconv-1.19.tar.gz"
 branch = "1.19"
 commit = "88dd96a8c0464eca144fc791ae60cd31cd8ee78321e67397e25fc095c4a19aa6"
 sha256 = "88dd96a8c0464eca144fc791ae60cd31cd8ee78321e67397e25fc095c4a19aa6"
diff --git a/src/extensions/external/postgis/moon.yml b/src/extensions/external/postgis/moon.yml
index ede724137..a1a57a4ed 100644
--- a/src/extensions/external/postgis/moon.yml
+++ b/src/extensions/external/postgis/moon.yml
@@ -4,7 +4,7 @@ id: "oliphaunt-extension-postgis"
 language: "unknown"
 layer: "library"
 stack: "systems"
-tags: ["extensions", "external", "postgis", "release-product"]
+tags: ["javascript-quality", "extensions", "external", "postgis", "release-product"]
 dependsOn:
   - id: "extension-runtime-contract"
     scope: "build"
@@ -17,3 +17,14 @@ project:
   release:
     component: "oliphaunt-extension-postgis"
     packagePath: "src/extensions/external/postgis"
+
+tasks:
+  test:
+    tags: ["quality", "unit"]
+    command: "bun test ./src/extensions/external/postgis/tools/preprocess-sql.test.mts"
+    inputs:
+      - "tools/preprocess-sql.mts"
+      - "tools/preprocess-sql.test.mts"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/extensions/external/postgis/release.toml b/src/extensions/external/postgis/release.toml
index 8096c464a..a75c92f7a 100644
--- a/src/extensions/external/postgis/release.toml
+++ b/src/extensions/external/postgis/release.toml
@@ -40,7 +40,7 @@ path = "src/extensions/external/postgis/source.toml"
 
 [extension.compatibility]
 postgres_major = "18"
-extension_runtime_contract = "src/shared/extension-runtime-contract/contract.toml"
+extension_runtime_contract = "src/extensions/contracts/contract.toml"
 native_runtime_product = "liboliphaunt-native"
 native_runtime_version = "0.2.0"
 wasix_runtime_product = "liboliphaunt-wasix"
diff --git a/src/extensions/external/postgis/tests/regression.sql b/src/extensions/external/postgis/tests/regression.sql
deleted file mode 100644
index 243a42b54..000000000
--- a/src/extensions/external/postgis/tests/regression.sql
+++ /dev/null
@@ -1,3 +0,0 @@
--- Full upstream PostGIS regression coverage is declared in upstream.toml.
--- This file reserves the Oliphaunt-owned regression slot for runtime-specific
--- additions that are not covered by the smoke path.
diff --git a/src/extensions/external/postgis/tools/build_wasix.sh b/src/extensions/external/postgis/tools/build_wasix.sh
index 44ddf8e57..6df953098 100755
--- a/src/extensions/external/postgis/tools/build_wasix.sh
+++ b/src/extensions/external/postgis/tools/build_wasix.sh
@@ -13,7 +13,7 @@ oliphaunt_postgis_bootstrap_repo_root() {
   repo_root="$SCRIPT_DIR"
   while [ "$repo_root" != "/" ]; do
     if [ -f "$repo_root/package.json" ] &&
-       [ -d "$repo_root/src/runtimes/liboliphaunt/wasix/assets/build" ]; then
+       [ -d "$repo_root/src/runtimes/liboliphaunt-wasix/assets/build" ]; then
       printf '%s\n' "$repo_root"
       return 0
     fi
@@ -25,7 +25,7 @@ oliphaunt_postgis_bootstrap_repo_root() {
 }
 
 BOOTSTRAP_REPO_ROOT="$(oliphaunt_postgis_bootstrap_repo_root)"
-ROOT="${OLIPHAUNT_WASIX_BUILD_ROOT:-$BOOTSTRAP_REPO_ROOT/src/runtimes/liboliphaunt/wasix/assets/build}"
+ROOT="${OLIPHAUNT_WASIX_BUILD_ROOT:-$BOOTSTRAP_REPO_ROOT/src/runtimes/liboliphaunt-wasix/assets/build}"
 . "$ROOT/wasix_third_party.sh"
 . "$ROOT/source_lane.sh"
 
@@ -51,7 +51,7 @@ while IFS= read -r flag; do
 done < <(oliphaunt_wasix_extension_wasix_configure_flags "$REPO_ROOT" postgis)
 
 if [ ! -f "$POSTGIS_SOURCE_DIR/configure.ac" ]; then
-  echo "missing PostGIS source checkout at $POSTGIS_SOURCE_DIR; run assets fetch/source-spine first" >&2
+  echo "missing PostGIS source checkout at $POSTGIS_SOURCE_DIR; run bash src/third-party/tools/fetch-sources.sh wasix-runtime --force first" >&2
   exit 1
 fi
 if [ ! -f "$BUILD_DIR/config.status" ]; then
diff --git a/src/extensions/external/postgis/tools/preprocess-sql.mts b/src/extensions/external/postgis/tools/preprocess-sql.mts
new file mode 100644
index 000000000..605b02764
--- /dev/null
+++ b/src/extensions/external/postgis/tools/preprocess-sql.mts
@@ -0,0 +1,116 @@
+import assert from 'node:assert/strict';
+import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import { dirname, resolve } from 'node:path';
+
+// ponytail: Windows has no GNU traditional-cpp. Pinned SQL uses object macros
+// and integer comparisons only; reject new syntax until its pin has a fixture.
+export function preprocessSql(input: string, includeDirs: string[] = []) {
+  const macros = new Map(),
+    includes = new Set(),
+    result: string[] = [];
+  const expand = (text: string) => {
+    for (let depth = 0; depth < 16; depth++) {
+      const expanded = text.replace(
+        /\b[A-Za-z_][A-Za-z0-9_]*\b/g,
+        (name) => macros.get(name) ?? name,
+      );
+      if (expanded === text) return text;
+      text = expanded;
+    }
+    throw new Error('recursive SQL macro expansion');
+  };
+  const condition = (expression: string) => {
+    const match = expand(expression)
+      .replace(/\b[A-Za-z_][A-Za-z0-9_]*\b/g, '0')
+      .trim()
+      .match(/^(-?\d+)(?:\s*(==|!=|>=|<=|>|<)\s*(-?\d+))?$/);
+    assert(match, `unsupported SQL condition: ${expression}`);
+    const left = BigInt(match[1]),
+      right = BigInt(match[3] ?? '0');
+    switch (match[2]) {
+      case '==':
+        return left === right;
+      case '!=':
+        return left !== right;
+      case '>=':
+        return left >= right;
+      case '<=':
+        return left <= right;
+      case '>':
+        return left > right;
+      case '<':
+        return left < right;
+      default:
+        return left !== 0n;
+    }
+  };
+  const processFile = (file: string) => {
+    file = resolve(file);
+    assert(!includes.has(file), `recursive SQL include: ${file}`);
+    includes.add(file);
+    const stack: { parent: boolean; taken: boolean }[] = [];
+    let active = true,
+      comment = false;
+    for (const raw of readFileSync(file, 'utf8')
+      .replaceAll('\r\n', '\n')
+      .match(/[^\n]*\n|[^\n]+$/g) ?? []) {
+      const directive = !comment && raw.match(/^\s*#\s*(\w+)\b(.*)/);
+      if (!directive) {
+        if (active) result.push(expand(raw));
+        for (let offset = 0; offset < raw.length; ) {
+          const found = raw.indexOf(comment ? '*/' : '/*', offset);
+          if (found < 0) break;
+          comment = !comment;
+          offset = found + 2;
+        }
+        continue;
+      }
+      const [, command, value] = directive,
+        argument = value.trim();
+      if (['if', 'ifdef', 'ifndef'].includes(command)) {
+        const accepted =
+          active &&
+          (command === 'if' ? condition(argument) : macros.has(argument) === (command === 'ifdef'));
+        stack.push({ parent: active, taken: accepted });
+        active = accepted;
+      } else if (['else', 'elif', 'endif'].includes(command)) {
+        const frame = stack.at(-1);
+        assert(frame, `orphan #${command} in ${file}`);
+        if (command === 'endif') {
+          active = frame.parent;
+          stack.pop();
+        } else {
+          active = frame.parent && !frame.taken && (command === 'else' || condition(argument));
+          frame.taken ||= active;
+        }
+      } else if (active) {
+        if (command === 'include') {
+          const name = argument.match(/^"([^"]+)"$/)?.[1];
+          assert(name, `unsupported SQL include: ${argument}`);
+          const target = [dirname(file), ...includeDirs]
+            .map((dir) => resolve(dir, name))
+            .find(existsSync);
+          assert(target, `could not resolve SQL include ${name} from ${file}`);
+          processFile(target);
+        } else if (command === 'define') {
+          const match = argument.match(/^([A-Za-z_][A-Za-z0-9_]*)(?:\s+(.*))?$/);
+          assert(match, `unsupported SQL macro: ${argument}`);
+          macros.set(match[1], match[2] ?? '1');
+        } else if (command === 'undef') macros.delete(argument);
+        else result.push(raw);
+      }
+    }
+    assert(!stack.length, `unterminated SQL conditional in ${file}`);
+    includes.delete(file);
+  };
+  processFile(input);
+  return result.join('');
+}
+
+if (import.meta.main) {
+  const [input, output, ...includeDirs] = process.argv.slice(2);
+  assert(input && output, 'usage: preprocess-sql.mts INPUT OUTPUT [INCLUDE_DIRECTORY...]');
+  const sql = preprocessSql(input, includeDirs);
+  mkdirSync(dirname(output), { recursive: true });
+  writeFileSync(output, sql);
+}
diff --git a/src/extensions/external/postgis/tools/preprocess-sql.test.mts b/src/extensions/external/postgis/tools/preprocess-sql.test.mts
new file mode 100644
index 000000000..325e64138
--- /dev/null
+++ b/src/extensions/external/postgis/tools/preprocess-sql.test.mts
@@ -0,0 +1,31 @@
+import assert from 'node:assert/strict';
+import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import test from 'node:test';
+import { preprocessSql } from './preprocess-sql.mts';
+
+test('Windows PostGIS SQL preserves comments, expands included versions, and selects supported SQL', (t) => {
+  const root = mkdtempSync(join(tmpdir(), 'postgis-sql-'));
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+  const source = join(root, 'input.sql');
+  writeFileSync(
+    join(root, 'defines.h'),
+    "#ifndef GUARD\n#define GUARD\n#define PG 180\n#define VERSION '3.6.3'\n#endif\n",
+  );
+  writeFileSync(
+    source,
+    '#include "defines.h"\n#include "defines.h"\n/*\n#define IGNORED 1\n*/\n#if PG >= 180\nSELECT VERSION;\n#elif PG < 180\nwrong\n#else\nwrong\n#endif\n#ifdef IGNORED\nwrong\n#endif\n#undef PG\n#ifndef PG\nSELECT 1;\n#endif\n',
+  );
+  assert.equal(preprocessSql(source), "/*\n#define IGNORED 1\n*/\nSELECT '3.6.3';\nSELECT 1;\n");
+  for (const [text, diagnostic] of [
+    ['#include "input.sql"\n', /recursive SQL include/],
+    ['#include "absent"\n', /could not resolve/],
+    ['#if 1\n', /unterminated/],
+    ['#else\n', /orphan/],
+    ['#if function()\n', /unsupported SQL condition/],
+  ] as const) {
+    writeFileSync(source, text);
+    assert.throws(() => preprocessSql(source), diagnostic);
+  }
+});
diff --git a/src/extensions/external/postgis/tools/windows/build-sql.sh b/src/extensions/external/postgis/tools/windows/build-sql.sh
new file mode 100644
index 000000000..873e9569b
--- /dev/null
+++ b/src/extensions/external/postgis/tools/windows/build-sql.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+# Sourced by the Windows extension builder after source/configuration generation.
+# shellcheck disable=SC2154 # The sourcing build supplies build_dir and the generator callback.
+windows_postgis_build_sql() {
+  local directory="$build_dir/contrib/oliphaunt_external/postgis"
+  local pg="$directory/postgis" sql="$directory/extensions/postgis/sql" raster="$directory/raster/rt_pg"
+  local version pg_version
+  version="$(windows_extension_generate postgis-version)"
+  pg_version="$(windows_extension_generate postgres-major)"
+  windows_extension_generate postgis-sql-preprocess
+  perl "$directory/utils/create_upgrade.pl" "$pg/postgis.sql" >"$pg/postgis_upgrade.sql.in"
+  perl "$directory/utils/create_uninstall.pl" "$pg/postgis.sql" "$pg_version" >"$pg/uninstall_postgis.sql"
+  perl "$directory/utils/create_uninstall.pl" "$pg/legacy.sql" "$pg_version" >"$pg/uninstall_legacy.sql"
+  perl "$directory/utils/create_spatial_ref_sys_config_dump.pl" "$directory/spatial_ref_sys.sql" >"$sql/spatial_ref_sys_config_dump.sql"
+  perl "$directory/utils/create_upgrade.pl" "$sql/postgis_for_extension.sql" >"$sql/postgis_upgrade_for_extension.sql.in"
+  perl "$directory/utils/create_uninstall.pl" "$raster/rtpostgis.sql" "$pg_version" >"$raster/uninstall_rtpostgis.sql"
+  windows_extension_generate postgis-sql-upgrade
+  perl "$directory/utils/create_extension_unpackage.pl" postgis <"$sql/raster_drop_all.sql" >"$sql/raster_unpackage_body.sql"
+  windows_extension_generate postgis-sql-install
+  perl "$directory/utils/create_unpackaged.pl" postgis <"$sql/postgis--$version.sql" >"$sql/postgis--unpackaged--$version.sql"
+  windows_extension_generate postgis-sql-unpackaged
+}
diff --git a/src/extensions/external/postgis/tools/windows/flatgeobuf-compat.h b/src/extensions/external/postgis/tools/windows/flatgeobuf-compat.h
new file mode 100644
index 000000000..69b867537
--- /dev/null
+++ b/src/extensions/external/postgis/tools/windows/flatgeobuf-compat.h
@@ -0,0 +1,8 @@
+#ifdef _MSC_VER
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#ifndef PROJ_DLL
+#define PROJ_DLL
+#endif
+#endif
diff --git a/src/extensions/external/postgis/tools/windows/meson.build.in b/src/extensions/external/postgis/tools/windows/meson.build.in
new file mode 100644
index 000000000..f4ca28225
--- /dev/null
+++ b/src/extensions/external/postgis/tools/windows/meson.build.in
@@ -0,0 +1,181 @@
+postgis = shared_module(
+  'postgis-3',
+  files(
+    'postgis/postgis_module.c',
+    'postgis/lwgeom_accum.c',
+    'postgis/lwgeom_union.c',
+    'postgis/lwgeom_spheroid.c',
+    'postgis/lwgeom_ogc.c',
+    'postgis/lwgeom_functions_analytic.c',
+    'postgis/lwgeom_functions_basic.c',
+    'postgis/lwgeom_inout.c',
+    'postgis/lwgeom_btree.c',
+    'postgis/lwgeom_box.c',
+    'postgis/lwgeom_box3d.c',
+    'postgis/lwgeom_geos.c',
+    'postgis/lwgeom_geos_predicates.c',
+    'postgis/lwgeom_geos_prepared.c',
+    'postgis/lwgeom_geos_clean.c',
+    'postgis/lwgeom_geos_relatematch.c',
+    'postgis/lwgeom_generate_grid.c',
+    'postgis/lwgeom_export.c',
+    'postgis/lwgeom_in_gml.c',
+    'postgis/lwgeom_in_kml.c',
+    'postgis/lwgeom_in_marc21.c',
+    'postgis/lwgeom_out_marc21.c',
+    'postgis/lwgeom_in_geohash.c',
+    'postgis/lwgeom_in_geojson.c',
+    'postgis/lwgeom_in_encoded_polyline.c',
+    'postgis/lwgeom_triggers.c',
+    'postgis/lwgeom_dump.c',
+    'postgis/lwgeom_dumppoints.c',
+    'postgis/lwgeom_functions_lrs.c',
+    'postgis/lwgeom_functions_temporal.c',
+    'postgis/lwgeom_rectree.c',
+    'postgis/lwgeom_itree.c',
+    'postgis/lwgeom_sqlmm.c',
+    'postgis/lwgeom_transform.c',
+    'postgis/lwgeom_window.c',
+    'postgis/gserialized_typmod.c',
+    'postgis/gserialized_gist_2d.c',
+    'postgis/gserialized_gist_nd.c',
+    'postgis/gserialized_supportfn.c',
+    'postgis/gserialized_spgist_2d.c',
+    'postgis/gserialized_spgist_3d.c',
+    'postgis/gserialized_spgist_nd.c',
+    'postgis/brin_2d.c',
+    'postgis/brin_nd.c',
+    'postgis/brin_common.c',
+    'postgis/gserialized_estimate.c',
+    'postgis/geography_inout.c',
+    'postgis/geography_btree.c',
+    'postgis/geography_centroid.c',
+    'postgis/geography_measurement.c',
+    'postgis/geography_measurement_trees.c',
+    'postgis/geometry_inout.c',
+    'postgis/postgis_libprotobuf.c',
+    'postgis/mvt.c',
+    'postgis/lwgeom_out_mvt.c',
+    'postgis/geobuf.c',
+    'postgis/lwgeom_out_geobuf.c',
+    'postgis/lwgeom_out_geojson.c',
+    'postgis/flatgeobuf.c',
+    'postgis/lwgeom_in_flatgeobuf.c',
+    'postgis/lwgeom_out_flatgeobuf.c',
+    'postgis/lwgeom_remove_irrelevant_points_for_view.c',
+    'postgis/lwgeom_remove_small_parts.c',
+    'postgis/postgis_legacy.c',
+    'libpgcommon/gserialized_gist.c',
+    'libpgcommon/lwgeom_transform.c',
+    'libpgcommon/lwgeom_cache.c',
+    'libpgcommon/lwgeom_pg.c',
+    'libpgcommon/shared_gserialized.c',
+    'liblwgeom/stringbuffer.c',
+    'liblwgeom/optionlist.c',
+    'liblwgeom/stringlist.c',
+    'liblwgeom/bytebuffer.c',
+    'liblwgeom/measures.c',
+    'liblwgeom/measures3d.c',
+    'liblwgeom/ptarray.c',
+    'liblwgeom/lookup3.c',
+    'liblwgeom/lwgeom_api.c',
+    'liblwgeom/lwgeom.c',
+    'liblwgeom/lwpoint.c',
+    'liblwgeom/lwline.c',
+    'liblwgeom/lwpoly.c',
+    'liblwgeom/lwtriangle.c',
+    'liblwgeom/lwmpoint.c',
+    'liblwgeom/lwmline.c',
+    'liblwgeom/lwmpoly.c',
+    'liblwgeom/lwboundingcircle.c',
+    'liblwgeom/lwcollection.c',
+    'liblwgeom/lwcircstring.c',
+    'liblwgeom/lwcompound.c',
+    'liblwgeom/lwcurvepoly.c',
+    'liblwgeom/lwmcurve.c',
+    'liblwgeom/lwmsurface.c',
+    'liblwgeom/lwpsurface.c',
+    'liblwgeom/lwtin.c',
+    'liblwgeom/lwout_wkb.c',
+    'liblwgeom/lwin_geojson.c',
+    'liblwgeom/lwin_wkb.c',
+    'liblwgeom/lwin_twkb.c',
+    'liblwgeom/lwiterator.c',
+    'liblwgeom/lwgeom_median.c',
+    'liblwgeom/lwout_wkt.c',
+    'liblwgeom/lwout_twkb.c',
+    'liblwgeom/lwin_wkt_parse.c',
+    'liblwgeom/lwin_wkt_lex.c',
+    'liblwgeom/lwin_wkt.c',
+    'liblwgeom/lwin_encoded_polyline.c',
+    'liblwgeom/lwutil.c',
+    'liblwgeom/lwhomogenize.c',
+    'liblwgeom/intervaltree.c',
+    'liblwgeom/lwalgorithm.c',
+    'liblwgeom/lwstroke.c',
+    'liblwgeom/lwlinearreferencing.c',
+    'liblwgeom/lwprint.c',
+    'liblwgeom/gbox.c',
+    'liblwgeom/gserialized.c',
+    'liblwgeom/gserialized1.c',
+    'liblwgeom/gserialized2.c',
+    'liblwgeom/lwgeodetic.c',
+    'liblwgeom/lwgeodetic_measures.c',
+    'liblwgeom/lwgeodetic_tree.c',
+    'liblwgeom/lwrandom.c',
+    'liblwgeom/lwtree.c',
+    'liblwgeom/lwout_gml.c',
+    'liblwgeom/lwout_kml.c',
+    'liblwgeom/lwout_geojson.c',
+    'liblwgeom/lwout_svg.c',
+    'liblwgeom/lwout_x3d.c',
+    'liblwgeom/lwout_encoded_polyline.c',
+    'liblwgeom/lwgeom_debug.c',
+    'liblwgeom/lwgeom_geos.c',
+    'liblwgeom/lwgeom_geos_clean.c',
+    'liblwgeom/lwgeom_geos_cluster.c',
+    'liblwgeom/lwgeom_geos_node.c',
+    'liblwgeom/lwgeom_geos_split.c',
+    'liblwgeom/topo/lwgeom_topo.c',
+    'liblwgeom/topo/lwgeom_topo_polygonizer.c',
+    'liblwgeom/topo/lwt_edgeend.c',
+    'liblwgeom/topo/lwt_edgeend_star.c',
+    'liblwgeom/topo/lwt_node_edges.c',
+    'liblwgeom/lwgeom_transform.c',
+    'liblwgeom/lwgeom_wrapx.c',
+    'liblwgeom/lwunionfind.c',
+    'liblwgeom/effectivearea.c',
+    'liblwgeom/lwchaikins.c',
+    'liblwgeom/lwmval.c',
+    'liblwgeom/lwkmeans.c',
+    'liblwgeom/varint.c',
+    'liblwgeom/lwgeom_remove_irrelevant_points_for_view.c',
+    'liblwgeom/lwspheroid.c',
+    'deps/ryu/d2s.c',
+  ),
+  c_pch: pch_postgres_h,
+  kwargs: contrib_mod_args + {
+    'c_args': [
+@C_ARGS@
+    ],
+    'link_args': [
+@LINK_ARGS@
+    ],
+  },
+)
+contrib_targets += postgis
+
+install_data(
+@EXTENSION_DATA@,
+  kwargs: contrib_data_args,
+)
+
+install_data(
+@CONTRIB_DATA@,
+  install_dir: dir_data / 'contrib' / 'postgis-@MAJOR_MINOR@',
+)
+
+install_data(
+  'share/proj/proj.db',
+  install_dir: dir_data / 'proj',
+)
diff --git a/src/extensions/external/postgis/tools/windows/postgis-compat.h b/src/extensions/external/postgis/tools/windows/postgis-compat.h
new file mode 100644
index 000000000..b151e2b2d
--- /dev/null
+++ b/src/extensions/external/postgis/tools/windows/postgis-compat.h
@@ -0,0 +1,25 @@
+#ifndef OLIPHAUNT_POSTGIS_WINDOWS_COMPAT_H
+#define OLIPHAUNT_POSTGIS_WINDOWS_COMPAT_H
+
+#ifdef _MSC_VER
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#ifndef __attribute
+#define __attribute(x)
+#endif
+#ifndef FALLTHROUGH
+#define FALLTHROUGH ((void)0)
+#endif
+#ifndef PROJ_DLL
+#define PROJ_DLL
+#endif
+#ifndef strcasecmp
+#define strcasecmp _stricmp
+#endif
+#ifndef strncasecmp
+#define strncasecmp _strnicmp
+#endif
+#endif
+
+#endif
diff --git a/src/extensions/external/postgis/tools/windows/postgis_config.h.in b/src/extensions/external/postgis/tools/windows/postgis_config.h.in
new file mode 100644
index 000000000..9686dff80
--- /dev/null
+++ b/src/extensions/external/postgis/tools/windows/postgis_config.h.in
@@ -0,0 +1,47 @@
+/* postgis_config.h. Generated by Oliphaunt's Windows native producer. */
+#ifndef POSTGIS_CONFIG_H
+#define POSTGIS_CONFIG_H 1
+
+#include "postgis_revision.h"
+
+#define POSTGIS_DEBUG_LEVEL 0
+/* #undef ENABLE_NLS */
+/* #undef HAVE_GETTEXT */
+/* #undef WORDS_BIGENDIAN */
+/* #undef HAVE_ICONV */
+/* #undef HAVE_ICONVCTL */
+#define HAVE_IEEEFP_H 0
+#define HAVE_LIBGEOS_C 1
+/* #undef HAVE_LIBICONVCTL */
+/* #undef HAVE_LIBPROTOBUF */
+/* #undef LIBPROTOBUF_VERSION */
+#define HAVE_LIBJSON 1
+#define HAVE_LIBPQ 1
+#define HAVE_LIBPROJ 1
+#define HAVE_LIBXML2 1
+#define HAVE_LIBXML_PARSER_H 1
+#define HAVE_LIBXML_TREE_H 1
+#define HAVE_LIBXML_XPATHINTERNALS_H 1
+#define HAVE_LIBXML_XPATH_H 1
+/* #undef HAVE_UNISTD_H */
+/* #undef HAVE_SFCGAL */
+#define LT_OBJDIR ".libs/"
+#define PGSQL_LOCALEDIR "@LOCALE_DIR@"
+#define POSTGIS_BUILD_DATE "@BUILD_DATE@"
+/* #undef POSTGIS_SFCGAL_VERSION */
+/* #undef POSTGIS_GDAL_VERSION */
+#define POSTGIS_GEOS_VERSION @GEOS_VERSION@
+#define POSTGIS_LIBXML2_VERSION "@LIBXML_VERSION@"
+#define POSTGIS_LIB_VERSION "@VERSION@"
+#define POSTGIS_MAJOR_VERSION "@MAJOR@"
+#define POSTGIS_MINOR_VERSION "@MINOR@"
+#define POSTGIS_MICRO_VERSION "@MICRO@"
+#define POSTGIS_PGSQL_VERSION 180
+#define POSTGIS_PROJ_VERSION @PROJ_VERSION@
+/* #undef POSTGIS_RASTER_WARN_ON_TRUNCATION */
+#define POSTGIS_SCRIPTS_VERSION "@VERSION@"
+#define POSTGIS_VERSION "@POSTGIS_VERSION@"
+#define STDC_HEADERS 1
+#define YYTEXT_POINTER 1
+
+#endif /* POSTGIS_CONFIG_H */
diff --git a/src/extensions/external/vector/CHANGELOG.md b/src/extensions/external/vector/CHANGELOG.md
index 8755ecce4..dcb481d74 100644
--- a/src/extensions/external/vector/CHANGELOG.md
+++ b/src/extensions/external/vector/CHANGELOG.md
@@ -5,7 +5,6 @@
 
 ### ⚠ BREAKING CHANGES
 
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/extensions/external/vector/release.toml b/src/extensions/external/vector/release.toml
index 7c25de556..5bca196c2 100644
--- a/src/extensions/external/vector/release.toml
+++ b/src/extensions/external/vector/release.toml
@@ -40,7 +40,7 @@ path = "src/extensions/external/vector/source.toml"
 
 [extension.compatibility]
 postgres_major = "18"
-extension_runtime_contract = "src/shared/extension-runtime-contract/contract.toml"
+extension_runtime_contract = "src/extensions/contracts/contract.toml"
 native_runtime_product = "liboliphaunt-native"
 native_runtime_version = "0.2.0"
 wasix_runtime_product = "liboliphaunt-wasix"
diff --git a/src/extensions/generated/docs/extension-evidence.json b/src/extensions/generated/docs/extension-evidence.json
index 68b8ee601..c1dd3e3d2 100644
--- a/src/extensions/generated/docs/extension-evidence.json
+++ b/src/extensions/generated/docs/extension-evidence.json
@@ -16,7 +16,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -28,7 +28,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "amcheck"
     },
@@ -48,7 +48,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -60,7 +60,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "auto_explain"
     },
@@ -80,7 +80,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -92,7 +92,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "bloom"
     },
@@ -112,7 +112,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -124,7 +124,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "btree_gin"
     },
@@ -144,7 +144,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -156,7 +156,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "btree_gist"
     },
@@ -176,7 +176,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -188,7 +188,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "citext"
     },
@@ -208,7 +208,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -220,7 +220,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "cube"
     },
@@ -240,7 +240,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -252,7 +252,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "dict_int"
     },
@@ -272,7 +272,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -284,7 +284,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "dict_xsyn"
     },
@@ -304,7 +304,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -316,7 +316,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "earthdistance"
     },
@@ -336,7 +336,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -348,7 +348,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "file_fdw"
     },
@@ -368,7 +368,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -380,7 +380,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "fuzzystrmatch"
     },
@@ -400,7 +400,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -412,7 +412,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "hstore"
     },
@@ -432,7 +432,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -444,7 +444,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "intarray"
     },
@@ -464,7 +464,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -476,7 +476,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "isn"
     },
@@ -496,7 +496,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -508,7 +508,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "lo"
     },
@@ -528,7 +528,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -540,7 +540,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "ltree"
     },
@@ -560,7 +560,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -572,7 +572,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pageinspect"
     },
@@ -592,7 +592,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -604,7 +604,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_buffercache"
     },
@@ -624,7 +624,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -636,7 +636,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_freespacemap"
     },
@@ -656,7 +656,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -668,7 +668,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_hashids"
     },
@@ -688,7 +688,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -700,7 +700,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_ivm"
     },
@@ -720,7 +720,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -732,7 +732,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_surgery"
     },
@@ -752,7 +752,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -764,7 +764,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_textsearch"
     },
@@ -784,7 +784,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -796,7 +796,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_trgm"
     },
@@ -816,7 +816,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -828,7 +828,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_uuidv7"
     },
@@ -848,7 +848,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -860,7 +860,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_visibility"
     },
@@ -880,7 +880,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -892,7 +892,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pg_walinspect"
     },
@@ -912,7 +912,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -924,7 +924,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pgcrypto"
     },
@@ -944,7 +944,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -956,7 +956,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "pgtap"
     },
@@ -976,7 +976,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -988,7 +988,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "postgis"
     },
@@ -1008,7 +1008,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -1020,7 +1020,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "seg"
     },
@@ -1040,7 +1040,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -1052,7 +1052,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "tablefunc"
     },
@@ -1072,7 +1072,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -1084,7 +1084,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "tcn"
     },
@@ -1104,7 +1104,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -1116,7 +1116,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "tsm_system_rows"
     },
@@ -1136,7 +1136,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -1148,7 +1148,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "tsm_system_time"
     },
@@ -1168,7 +1168,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -1180,7 +1180,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "unaccent"
     },
@@ -1200,7 +1200,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -1212,7 +1212,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "uuid-ossp"
     },
@@ -1232,7 +1232,7 @@
             "direct",
             "server",
             "restart",
-            "dump-restore"
+            "backup-restore"
           ]
         }
       ],
@@ -1244,7 +1244,7 @@
         "direct",
         "server",
         "restart",
-        "dump-restore"
+        "backup-restore"
       ],
       "sql-name": "vector"
     }
@@ -1268,15 +1268,16 @@
     "collector": "src/extensions/tools/collect-wasix-evidence.sh",
     "kind": "exact-sha-ci"
   },
-  "source-digest": "sha256:47bc7c405ac17e5ca1d29bff8f4455cf105a457d5c6de300a6392ded5f5891b4",
+  "source-digest": "sha256:3a8f82a57c35a3200bd33f0c57e46ec430acff7a402222c907fbee927e10ed2d",
   "source-digest-inputs": [
-    "src/postgres/versions/18/source.toml",
+    "src/third-party/postgres/source.toml",
     "src/extensions/catalog/extensions.source.json",
     "src/extensions/catalog/native-components.toml",
     "src/extensions/contrib/postgres18.toml",
     "src/extensions/generated/extensions.catalog.json",
     "src/extensions/generated/contrib-build.tsv",
     "src/extensions/generated/pgxs-build.tsv",
+    "src/database-resources/icu/source.toml",
     "src/extensions/external/pg_hashids/source.toml",
     "src/extensions/external/pg_ivm/source.toml",
     "src/extensions/external/pg_textsearch/source.toml",
@@ -1290,10 +1291,9 @@
     "src/extensions/external/postgis/dependencies/sqlite/source.toml",
     "src/extensions/external/postgis/source.toml",
     "src/extensions/external/vector/source.toml",
-    "src/sources/third-party/native/icu-windows.toml",
-    "src/sources/third-party/shared/icu-data.toml",
-    "src/sources/third-party/shared/icu.toml",
-    "src/sources/third-party/shared/openssl.toml",
+    "src/runtimes/liboliphaunt-native/sources/icu-windows.toml",
+    "src/third-party/icu/source.toml",
+    "src/third-party/openssl/source.toml",
     "src/extensions/external/README.md",
     "src/extensions/external/pg_hashids/upstream-license-data.json",
     "src/extensions/external/pg_ivm/targets/native-static-registry.toml",
@@ -1312,51 +1312,56 @@
     "src/extensions/external/postgis/targets/native-static-registry.toml",
     "src/extensions/external/postgis/targets/native.toml",
     "src/extensions/external/postgis/targets/wasix.toml",
-    "src/extensions/external/postgis/tests/regression.sql",
     "src/extensions/external/postgis/tools/build_wasix.sh",
+    "src/extensions/external/postgis/tools/preprocess-sql.mts",
     "src/extensions/external/postgis/tools/reproducible-bin/date",
     "src/extensions/external/postgis/tools/reproducible-time.sh",
+    "src/extensions/external/postgis/tools/windows/build-sql.sh",
+    "src/extensions/external/postgis/tools/windows/flatgeobuf-compat.h",
+    "src/extensions/external/postgis/tools/windows/meson.build.in",
+    "src/extensions/external/postgis/tools/windows/postgis-compat.h",
+    "src/extensions/external/postgis/tools/windows/postgis_config.h.in",
     "src/extensions/external/postgis/upstream-license-data.json",
     "src/extensions/external/vector/upstream-license-data.json",
-    "src/shared/fixtures/extensions/manifest.json",
-    "src/shared/fixtures/extensions/amcheck.sql",
-    "src/shared/fixtures/extensions/auto_explain.sql",
-    "src/shared/fixtures/extensions/bloom.sql",
-    "src/shared/fixtures/extensions/btree_gin.sql",
-    "src/shared/fixtures/extensions/btree_gist.sql",
-    "src/shared/fixtures/extensions/citext.sql",
-    "src/shared/fixtures/extensions/cube.sql",
-    "src/shared/fixtures/extensions/dict_int.sql",
-    "src/shared/fixtures/extensions/dict_xsyn.sql",
-    "src/shared/fixtures/extensions/earthdistance.sql",
-    "src/shared/fixtures/extensions/file_fdw.sql",
-    "src/shared/fixtures/extensions/fuzzystrmatch.sql",
-    "src/shared/fixtures/extensions/hstore.sql",
-    "src/shared/fixtures/extensions/intarray.sql",
-    "src/shared/fixtures/extensions/isn.sql",
-    "src/shared/fixtures/extensions/lo.sql",
-    "src/shared/fixtures/extensions/ltree.sql",
-    "src/shared/fixtures/extensions/pageinspect.sql",
-    "src/shared/fixtures/extensions/pg_buffercache.sql",
-    "src/shared/fixtures/extensions/pg_freespacemap.sql",
-    "src/shared/fixtures/extensions/pg_hashids.sql",
-    "src/shared/fixtures/extensions/pg_ivm.sql",
-    "src/shared/fixtures/extensions/pg_surgery.sql",
-    "src/shared/fixtures/extensions/pg_textsearch.sql",
-    "src/shared/fixtures/extensions/pg_trgm.sql",
-    "src/shared/fixtures/extensions/pg_uuidv7.sql",
-    "src/shared/fixtures/extensions/pg_visibility.sql",
-    "src/shared/fixtures/extensions/pg_walinspect.sql",
-    "src/shared/fixtures/extensions/pgcrypto.sql",
-    "src/shared/fixtures/extensions/pgtap.sql",
-    "src/shared/fixtures/extensions/postgis.sql",
-    "src/shared/fixtures/extensions/seg.sql",
-    "src/shared/fixtures/extensions/tablefunc.sql",
-    "src/shared/fixtures/extensions/tcn.sql",
-    "src/shared/fixtures/extensions/tsm_system_rows.sql",
-    "src/shared/fixtures/extensions/tsm_system_time.sql",
-    "src/shared/fixtures/extensions/unaccent.sql",
-    "src/shared/fixtures/extensions/uuid-ossp.sql",
-    "src/shared/fixtures/extensions/vector.sql"
+    "src/test-fixtures/extensions/manifest.json",
+    "src/test-fixtures/extensions/amcheck.sql",
+    "src/test-fixtures/extensions/auto_explain.sql",
+    "src/test-fixtures/extensions/bloom.sql",
+    "src/test-fixtures/extensions/btree_gin.sql",
+    "src/test-fixtures/extensions/btree_gist.sql",
+    "src/test-fixtures/extensions/citext.sql",
+    "src/test-fixtures/extensions/cube.sql",
+    "src/test-fixtures/extensions/dict_int.sql",
+    "src/test-fixtures/extensions/dict_xsyn.sql",
+    "src/test-fixtures/extensions/earthdistance.sql",
+    "src/test-fixtures/extensions/file_fdw.sql",
+    "src/test-fixtures/extensions/fuzzystrmatch.sql",
+    "src/test-fixtures/extensions/hstore.sql",
+    "src/test-fixtures/extensions/intarray.sql",
+    "src/test-fixtures/extensions/isn.sql",
+    "src/test-fixtures/extensions/lo.sql",
+    "src/test-fixtures/extensions/ltree.sql",
+    "src/test-fixtures/extensions/pageinspect.sql",
+    "src/test-fixtures/extensions/pg_buffercache.sql",
+    "src/test-fixtures/extensions/pg_freespacemap.sql",
+    "src/test-fixtures/extensions/pg_hashids.sql",
+    "src/test-fixtures/extensions/pg_ivm.sql",
+    "src/test-fixtures/extensions/pg_surgery.sql",
+    "src/test-fixtures/extensions/pg_textsearch.sql",
+    "src/test-fixtures/extensions/pg_trgm.sql",
+    "src/test-fixtures/extensions/pg_uuidv7.sql",
+    "src/test-fixtures/extensions/pg_visibility.sql",
+    "src/test-fixtures/extensions/pg_walinspect.sql",
+    "src/test-fixtures/extensions/pgcrypto.sql",
+    "src/test-fixtures/extensions/pgtap.sql",
+    "src/test-fixtures/extensions/postgis.sql",
+    "src/test-fixtures/extensions/seg.sql",
+    "src/test-fixtures/extensions/tablefunc.sql",
+    "src/test-fixtures/extensions/tcn.sql",
+    "src/test-fixtures/extensions/tsm_system_rows.sql",
+    "src/test-fixtures/extensions/tsm_system_time.sql",
+    "src/test-fixtures/extensions/unaccent.sql",
+    "src/test-fixtures/extensions/uuid-ossp.sql",
+    "src/test-fixtures/extensions/vector.sql"
   ]
 }
diff --git a/src/extensions/generated/extensions.catalog.json b/src/extensions/generated/extensions.catalog.json
index dc588103e..7ee933e81 100644
--- a/src/extensions/generated/extensions.catalog.json
+++ b/src/extensions/generated/extensions.catalog.json
@@ -3,7 +3,7 @@
   "generated-from": [
     {
       "name": "postgres18-source",
-      "path": "src/postgres/versions/18/source.toml"
+      "path": "src/third-party/postgres/source.toml"
     },
     {
       "name": "extension-catalog",
@@ -32,7 +32,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 18815,
-      "control-file": "src/postgres/versions/18/contrib/amcheck/amcheck.control",
+      "control-file": "src/third-party/postgres/contrib/amcheck/amcheck.control",
       "control": {
         "default-version": "1.5",
         "module-pathname": "$libdir/amcheck",
@@ -105,7 +105,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 6197,
-      "control-file": "src/postgres/versions/18/contrib/bloom/bloom.control",
+      "control-file": "src/third-party/postgres/contrib/bloom/bloom.control",
       "control": {
         "default-version": "1.0",
         "module-pathname": "$libdir/bloom",
@@ -143,7 +143,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 6347,
-      "control-file": "src/postgres/versions/18/contrib/btree_gin/btree_gin.control",
+      "control-file": "src/third-party/postgres/contrib/btree_gin/btree_gin.control",
       "control": {
         "default-version": "1.3",
         "module-pathname": "$libdir/btree_gin",
@@ -181,7 +181,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 24181,
-      "control-file": "src/postgres/versions/18/contrib/btree_gist/btree_gist.control",
+      "control-file": "src/third-party/postgres/contrib/btree_gist/btree_gist.control",
       "control": {
         "default-version": "1.8",
         "module-pathname": "$libdir/btree_gist",
@@ -219,7 +219,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 4983,
-      "control-file": "src/postgres/versions/18/contrib/citext/citext.control",
+      "control-file": "src/third-party/postgres/contrib/citext/citext.control",
       "control": {
         "default-version": "1.8",
         "module-pathname": "$libdir/citext",
@@ -257,7 +257,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 15104,
-      "control-file": "src/postgres/versions/18/contrib/cube/cube.control",
+      "control-file": "src/third-party/postgres/contrib/cube/cube.control",
       "control": {
         "default-version": "1.5",
         "module-pathname": "$libdir/cube",
@@ -295,7 +295,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 1361,
-      "control-file": "src/postgres/versions/18/contrib/dict_int/dict_int.control",
+      "control-file": "src/third-party/postgres/contrib/dict_int/dict_int.control",
       "control": {
         "default-version": "1.0",
         "module-pathname": "$libdir/dict_int",
@@ -333,7 +333,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 1948,
-      "control-file": "src/postgres/versions/18/contrib/dict_xsyn/dict_xsyn.control",
+      "control-file": "src/third-party/postgres/contrib/dict_xsyn/dict_xsyn.control",
       "control": {
         "default-version": "1.0",
         "module-pathname": "$libdir/dict_xsyn",
@@ -371,7 +371,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 2220,
-      "control-file": "src/postgres/versions/18/contrib/earthdistance/earthdistance.control",
+      "control-file": "src/third-party/postgres/contrib/earthdistance/earthdistance.control",
       "control": {
         "default-version": "1.2",
         "module-pathname": "$libdir/earthdistance",
@@ -413,7 +413,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 4467,
-      "control-file": "src/postgres/versions/18/contrib/file_fdw/file_fdw.control",
+      "control-file": "src/third-party/postgres/contrib/file_fdw/file_fdw.control",
       "control": {
         "default-version": "1.0",
         "module-pathname": "$libdir/file_fdw",
@@ -451,7 +451,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 12026,
-      "control-file": "src/postgres/versions/18/contrib/fuzzystrmatch/fuzzystrmatch.control",
+      "control-file": "src/third-party/postgres/contrib/fuzzystrmatch/fuzzystrmatch.control",
       "control": {
         "default-version": "1.2",
         "module-pathname": "$libdir/fuzzystrmatch",
@@ -489,7 +489,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 21380,
-      "control-file": "src/postgres/versions/18/contrib/hstore/hstore.control",
+      "control-file": "src/third-party/postgres/contrib/hstore/hstore.control",
       "control": {
         "default-version": "1.8",
         "module-pathname": "$libdir/hstore",
@@ -527,7 +527,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 14712,
-      "control-file": "src/postgres/versions/18/contrib/intarray/intarray.control",
+      "control-file": "src/third-party/postgres/contrib/intarray/intarray.control",
       "control": {
         "default-version": "1.5",
         "module-pathname": "$libdir/_int",
@@ -565,7 +565,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 31417,
-      "control-file": "src/postgres/versions/18/contrib/isn/isn.control",
+      "control-file": "src/third-party/postgres/contrib/isn/isn.control",
       "control": {
         "default-version": "1.3",
         "module-pathname": "$libdir/isn",
@@ -603,7 +603,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 1822,
-      "control-file": "src/postgres/versions/18/contrib/lo/lo.control",
+      "control-file": "src/third-party/postgres/contrib/lo/lo.control",
       "control": {
         "default-version": "1.2",
         "module-pathname": "$libdir/lo",
@@ -641,7 +641,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 19553,
-      "control-file": "src/postgres/versions/18/contrib/ltree/ltree.control",
+      "control-file": "src/third-party/postgres/contrib/ltree/ltree.control",
       "control": {
         "default-version": "1.3",
         "module-pathname": "$libdir/ltree",
@@ -679,7 +679,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 15923,
-      "control-file": "src/postgres/versions/18/contrib/pageinspect/pageinspect.control",
+      "control-file": "src/third-party/postgres/contrib/pageinspect/pageinspect.control",
       "control": {
         "default-version": "1.13",
         "module-pathname": "$libdir/pageinspect",
@@ -717,7 +717,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 3133,
-      "control-file": "src/postgres/versions/18/contrib/pg_buffercache/pg_buffercache.control",
+      "control-file": "src/third-party/postgres/contrib/pg_buffercache/pg_buffercache.control",
       "control": {
         "default-version": "1.6",
         "module-pathname": "$libdir/pg_buffercache",
@@ -755,7 +755,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 1485,
-      "control-file": "src/postgres/versions/18/contrib/pg_freespacemap/pg_freespacemap.control",
+      "control-file": "src/third-party/postgres/contrib/pg_freespacemap/pg_freespacemap.control",
       "control": {
         "default-version": "1.3",
         "module-pathname": "$libdir/pg_freespacemap",
@@ -868,7 +868,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 2635,
-      "control-file": "src/postgres/versions/18/contrib/pg_surgery/pg_surgery.control",
+      "control-file": "src/third-party/postgres/contrib/pg_surgery/pg_surgery.control",
       "control": {
         "default-version": "1.0",
         "module-pathname": "$libdir/pg_surgery",
@@ -945,7 +945,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 16208,
-      "control-file": "src/postgres/versions/18/contrib/pg_trgm/pg_trgm.control",
+      "control-file": "src/third-party/postgres/contrib/pg_trgm/pg_trgm.control",
       "control": {
         "default-version": "1.6",
         "module-pathname": "$libdir/pg_trgm",
@@ -1020,7 +1020,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 4159,
-      "control-file": "src/postgres/versions/18/contrib/pg_visibility/pg_visibility.control",
+      "control-file": "src/third-party/postgres/contrib/pg_visibility/pg_visibility.control",
       "control": {
         "default-version": "1.2",
         "module-pathname": "$libdir/pg_visibility",
@@ -1058,7 +1058,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 4689,
-      "control-file": "src/postgres/versions/18/contrib/pg_walinspect/pg_walinspect.control",
+      "control-file": "src/third-party/postgres/contrib/pg_walinspect/pg_walinspect.control",
       "control": {
         "default-version": "1.1",
         "module-pathname": "$libdir/pg_walinspect",
@@ -1096,7 +1096,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 1148162,
-      "control-file": "src/postgres/versions/18/contrib/pgcrypto/pgcrypto.control",
+      "control-file": "src/third-party/postgres/contrib/pgcrypto/pgcrypto.control",
       "control": {
         "default-version": "1.4",
         "module-pathname": "$libdir/pgcrypto",
@@ -1209,7 +1209,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 10426,
-      "control-file": "src/postgres/versions/18/contrib/seg/seg.control",
+      "control-file": "src/third-party/postgres/contrib/seg/seg.control",
       "control": {
         "default-version": "1.4",
         "module-pathname": "$libdir/seg",
@@ -1247,7 +1247,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 5824,
-      "control-file": "src/postgres/versions/18/contrib/tablefunc/tablefunc.control",
+      "control-file": "src/third-party/postgres/contrib/tablefunc/tablefunc.control",
       "control": {
         "default-version": "1.0",
         "module-pathname": "$libdir/tablefunc",
@@ -1285,7 +1285,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 1914,
-      "control-file": "src/postgres/versions/18/contrib/tcn/tcn.control",
+      "control-file": "src/third-party/postgres/contrib/tcn/tcn.control",
       "control": {
         "default-version": "1.0",
         "module-pathname": "$libdir/tcn",
@@ -1323,7 +1323,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 2048,
-      "control-file": "src/postgres/versions/18/contrib/tsm_system_rows/tsm_system_rows.control",
+      "control-file": "src/third-party/postgres/contrib/tsm_system_rows/tsm_system_rows.control",
       "control": {
         "default-version": "1.0",
         "module-pathname": "$libdir/tsm_system_rows",
@@ -1361,7 +1361,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 2099,
-      "control-file": "src/postgres/versions/18/contrib/tsm_system_time/tsm_system_time.control",
+      "control-file": "src/third-party/postgres/contrib/tsm_system_time/tsm_system_time.control",
       "control": {
         "default-version": "1.0",
         "module-pathname": "$libdir/tsm_system_time",
@@ -1399,7 +1399,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 9323,
-      "control-file": "src/postgres/versions/18/contrib/unaccent/unaccent.control",
+      "control-file": "src/third-party/postgres/contrib/unaccent/unaccent.control",
       "control": {
         "default-version": "1.1",
         "module-pathname": "$libdir/unaccent",
@@ -1437,7 +1437,7 @@
         "postgres/contrib"
       ],
       "bundle-size": 17936,
-      "control-file": "src/postgres/versions/18/contrib/uuid-ossp/uuid-ossp.control",
+      "control-file": "src/third-party/postgres/contrib/uuid-ossp/uuid-ossp.control",
       "control": {
         "default-version": "1.1",
         "module-pathname": "$libdir/uuid-ossp",
diff --git a/src/extensions/generated/mobile/static-extensions.tsv b/src/extensions/generated/mobile/static-extensions.tsv
index c4ed97e42..31ff98f29 100644
--- a/src/extensions/generated/mobile/static-extensions.tsv
+++ b/src/extensions/generated/mobile/static-extensions.tsv
@@ -1,4 +1,4 @@
-# @generated by src/extensions/tools/check-extension-model.mjs --write
+# @generated by src/extensions/tools/check-extension-model.sh --write
 sql-name	native-module-stem	source-kind	source-rel	mobile-static-dependencies	ios-static-dependencies	android-static-dependencies	include-dependencies	include-dirs	cflags	hash-source-dependencies	ios-hash-source-dependencies	android-hash-source-dependencies	hash-dirs	source-files	source-recursive-dirs
 amcheck	amcheck	contrib	contrib/amcheck
 auto_explain	auto_explain	contrib	contrib/auto_explain
@@ -36,5 +36,5 @@ tcn	tcn	contrib	contrib/tcn
 tsm_system_rows	tsm_system_rows	contrib	contrib/tsm_system_rows
 tsm_system_time	tsm_system_time	contrib	contrib/tsm_system_time
 unaccent	unaccent	contrib	contrib/unaccent
-uuid-ossp	uuid-ossp	contrib	contrib/uuid-ossp	uuid	uuid	uuid		src/runtimes/liboliphaunt/native/portable-uuid/include	-DHAVE_UUID_E2FS=1,-DHAVE_UUID_UUID_H=1				src/runtimes/liboliphaunt/native/portable-uuid
+uuid-ossp	uuid-ossp	contrib	contrib/uuid-ossp	uuid	uuid	uuid		src/runtimes/liboliphaunt-native/portable-uuid/include	-DHAVE_UUID_E2FS=1,-DHAVE_UUID_UUID_H=1				src/runtimes/liboliphaunt-native/portable-uuid
 vector	vector	external	target/oliphaunt-sources/checkouts/pgvector
diff --git a/src/extensions/generated/sdk/extensions.json b/src/extensions/generated/sdk/extensions.json
index 5cc769a99..c8a047409 100644
--- a/src/extensions/generated/sdk/extensions.json
+++ b/src/extensions/generated/sdk/extensions.json
@@ -1480,7 +1480,7 @@
     },
     {
       "name": "extension-recipes",
-      "path": "src/extensions"
+      "path": "extensions"
     },
     {
       "name": "release-products",
diff --git a/src/extensions/moon.yml b/src/extensions/moon.yml
index f0a7eeaa3..8cfc7bae0 100644
--- a/src/extensions/moon.yml
+++ b/src/extensions/moon.yml
@@ -1,112 +1,151 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "extensions"
-language: "unknown"
-layer: "configuration"
-stack: "systems"
-tags: ["extensions", "catalog", "assets"]
+$schema: https://moonrepo.dev/schemas/project.json
+id: extensions
+language: unknown
+layer: configuration
+stack: systems
+tags:
+  - javascript-quality
+  - extensions
+  - catalog
+  - assets
 dependsOn:
-  - id: "postgres18"
-    scope: "build"
-  - id: "extension-runtime-contract"
-    scope: "build"
-  - id: "third-party-native"
-    scope: "build"
-  - id: "third-party-shared"
-    scope: "build"
-
+  - id: postgres18
+    scope: build
+  - id: extension-runtime-contract
+    scope: build
+  - id: third-party-icu
+    scope: build
+  - id: third-party-openssl
+    scope: build
 project:
-  title: "Extension Catalog"
+  title: Extension Catalog
   description: "Exact SQL extension catalog, build plans, and generated tables."
-  owner: "oliphaunt"
-
+  owner: oliphaunt
 owners:
   defaultOwner: "@oliphaunt/core"
   paths:
-    "**/*": ["@oliphaunt/core"]
-
+    "**/*":
+      - "@oliphaunt/core"
 fileGroups:
+  mobile-metadata:
+    - generated/mobile/**/*
   sdk-metadata:
-    - "generated/sdk/**/*"
+    - generated/sdk/**/*
   model:
-    - "catalog/**/*"
-    - "contrib/**/*"
-    - "evidence/**/*"
-    - "external/**/*"
-    - "generated/**/*"
-    - "schemas/**/*"
-    - "tools/**/*"
+    - catalog/**/*
+    - contrib/**/*
+    - evidence/**/*
+    - external/**/*
+    - generated/**/*
+    - schemas/**/*
+    - tools/**/*
   build:
-    - "catalog/**/*"
-    - "contrib/**/*"
-    - "external/**/*"
-    - "generated/**/*"
-    - "schemas/**/*"
-    - "tools/**/*"
+    - catalog/**/*
+    - contrib/**/*
+    - external/**/*
+    - generated/**/*
+    - schemas/**/*
+    - tools/**/*
     - "!**/*.md"
     - "!external/**/VERSION"
     - "!external/**/release.toml"
     - "!generated/docs"
     - "!generated/docs/**"
   package:
-    - "catalog/**/*"
-    - "contrib/**/*"
-    - "external/**/*"
-    - "generated/**/*"
-    - "schemas/**/*"
-    - "tools/**/*"
+    - catalog/**/*
+    - contrib/**/*
+    - external/**/*
+    - generated/**/*
+    - schemas/**/*
+    - tools/**/*
     - "!generated/docs"
     - "!generated/docs/**"
-
 tasks:
   lint:
-    tags: ["quality", "static"]
-    command: "bash tools/dev/bun.sh src/extensions/tools/check-extension-model.mjs --check"
+    toolchains: [bun]
+    tags:
+      - quality
+      - static
+    command: bash src/extensions/tools/check-extension-model.sh --check
     inputs:
       - "@group(legal-files)"
-      - project: "postgres18"
-        group: "source"
+      - project: postgres18
+        group: source
       - "@group(model)"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "/src/shared/fixtures/extensions/**/*"
-      - project: "third-party-native"
-        group: "sources"
-      - project: "third-party-shared"
-        group: "sources"
-      - "/src/sdks/rust/src/generated/extensions.rs"
-      - "/src/sdks/js/src/generated/extensions.ts"
-      - "/src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt"
-      - "/src/sdks/react-native/src/generated/extensions.ts"
-      - "/examples/react-native-expo/src/generated/extension-smoke.ts"
-      - "/src/runtimes/liboliphaunt/licenses/openssl-3.5.6-LICENSE.txt"
-      - "/src/runtimes/liboliphaunt/licenses/postgresql-18.4-COPYRIGHT"
-      - "/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json"
-      - "/tools/dev/capture-command-output.mjs"
-      - "/src/sources/tools/source-fetch-core.mjs"
-      - "/tools/release/extension-upstream-licenses.mjs"
+      - project: extension-runtime-contract
+        group: contract
+      - /src/test-fixtures/extensions/**/*
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - /src/sdks/rust/liboliphaunt-native/src/generated/extensions.rs
+      - /src/sdks/ts/sdk/src/generated/extensions.ts
+      - /src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt
+      - /src/sdks/react-native/src/generated/extensions.ts
+      - /src/examples/react-native-expo/src/generated/extension-smoke.ts
+      - /src/third-party/openssl/LICENSE.txt
+      - /src/third-party/postgres/COPYRIGHT
+      - /src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json
+      - /src/third-party/tools/source-fetch-core.mts
+      - /src/extensions/tools/extension-upstream-licenses.mts
       - "@group(release-archive-contract)"
-      - "/tools/release/release_graph_query.mjs"
+      - /tools/release/query.mts
       - "@group(release-target-contract)"
-      - "/tools/release/platform-compatibility-policy.test.mjs"
-      - "/tools/release/release-graph.mjs"
-      - "/tools/xtask/**/*"
-      - "/Cargo.lock"
-      - "/Cargo.toml"
+      - /tools/release/platform-compatibility-policy.test.mts
+      - /tools/release/release-graph.mts
     options:
       cache: true
       runFromWorkspaceRoot: true
-  unit:
-    tags: ["quality", "unit"]
-    command: "bash tools/dev/bun.sh test '--path-ignore-patterns=target/**' src/extensions/tools/native-component-contract.test.mjs"
+  test:
+    tags:
+      - quality
+      - unit
+    command: bash tools/dev/bun.sh test ./src/extensions/tools/native-component-contract.test.mts ./src/extensions/tools/extension-model.test.mts
     inputs:
-      - "catalog/native-components.toml"
-      - "catalog/extensions.source.json"
-      - "tools/native-component-contract.mjs"
-      - "tools/native-component-contract.test.mjs"
-      - "/src/runtimes/liboliphaunt/native/portable-uuid/**/*"
-      - project: "extension-runtime-contract"
-        group: "contract"
+      - catalog/native-components.toml
+      - catalog/extensions.source.json
+      - tools/native-component-contract.mts
+      - tools/native-component-contract.test.mts
+      - tools/extension-model.test.mts
+      - tools/extension-evidence.mts
+      - tools/extension-projections.mts
+      - "@group(model)"
+      - /src/test-fixtures/extensions/**/*
+      - "/src/third-party/{icu,openssl}/source.toml"
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - /src/runtimes/liboliphaunt-native/portable-uuid/**/*
+      - project: extension-runtime-contract
+        group: contract
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  packaging-unit:
+    tags:
+      - quality
+      - unit
+    command: bash src/extensions/tools/extension-upstream-licenses.test.sh
+    inputs:
+      - external/**/upstream-license-data.json
+      - external/**/upstream-licenses/**/*
+      - generated/sdk/extensions.json
+      - /src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json
+      - "@group(upstream-licenses)"
+      - "@group(legal-files)"
+      - "@group(release-target-contract)"
+      - "@group(package-test-metadata)"
+      - "**/*.{mjs,mts}"
+      - tools/extension-upstream-licenses.test.sh
+      - /tools/packaging/testdata/**/*
+      - /tools/dev/bun.sh
+      - "/tools/packaging/*.{mts,sh}"
+      - "/tools/release/*.{mjs,mts}"
     options:
       cache: true
       runFromWorkspaceRoot: true
+  audit-license-sources:
+    command: bun tools/extension-upstream-licenses.mts audit-sources
+    options:
+      cache: false
+      runInCI: false
diff --git a/src/extensions/tests/native/Cargo.toml b/src/extensions/tests/native/Cargo.toml
new file mode 100644
index 000000000..8e2acf9cd
--- /dev/null
+++ b/src/extensions/tests/native/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "oliphaunt-native-extension-proof"
+version = "0.0.0"
+edition.workspace = true
+rust-version.workspace = true
+license.workspace = true
+publish = false
+
+[features]
+default = []
+
+[dependencies]
+oliphaunt = { path = "../../../sdks/rust/sdk" }
+tar = "0.4"
diff --git a/src/extensions/tests/native/moon.yml b/src/extensions/tests/native/moon.yml
new file mode 100644
index 000000000..d7b8533d2
--- /dev/null
+++ b/src/extensions/tests/native/moon.yml
@@ -0,0 +1,52 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+id: "native-extension-lifecycle"
+language: "rust"
+layer: "tool"
+tags: ["javascript-quality"]
+dependsOn:
+  - id: "oliphaunt-rust"
+    scope: "development"
+  - id: "shared-test-fixtures"
+    scope: "development"
+tasks:
+  test:
+    tags: ["quality", "unit", "requires-rust"]
+    script: |
+      set -e
+      bun test ./src/extensions/tests/native/tools
+      cargo test --locked -p oliphaunt-native-extension-proof
+    inputs:
+      - "Cargo.toml"
+      - "src/**/*.rs"
+      - "@group(cargo-workspace)"
+      - "/src/sdks/rust-query/src/lib.rs"
+      - project: "oliphaunt-rust"
+        group: "code"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - "tools/**/*.mts"
+      - "/tools/release/**/*.mts"
+      - "/src/extensions/artifacts/native/tools/**/*.mts"
+      - "/src/extensions/artifacts/packages/tools/**/*.mts"
+      - "/src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  lifecycle:
+    tags: ["release", "integration", "ci-native-extension-lifecycle"]
+    command: "src/extensions/tests/native/tools/run-native-extension-lifecycle-proof.sh"
+    deps:
+      - "extension-artifacts-native:build-target"
+      - "liboliphaunt-native:build-runtime-desktop-target"
+      - "postgres-tools-native:package-assets"
+      - "oliphaunt-broker:build-release-assets"
+      - "oliphaunt-rust:package"
+    inputs:
+      - "/src/runtimes/liboliphaunt-wasix-postmaster/lib/process-supervision.sh"
+      - "/src/extensions/tests/native/**/*"
+      - "/src/extensions/tests/native/tools/run-native-extension-lifecycle-proof.sh"
+      - "/src/postgres-tools/native/tools/smoke-packed-tools-npm.sh"
+      - "/src/postgres-tools/native/tools/smoke-packed-tools-npm.mts"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
diff --git a/src/extensions/tests/native/src/main.rs b/src/extensions/tests/native/src/main.rs
new file mode 100644
index 000000000..fb3b886df
--- /dev/null
+++ b/src/extensions/tests/native/src/main.rs
@@ -0,0 +1,77 @@
+#![allow(dead_code)]
+
+include!("../../../../sdks/rust/sdk/tests/native_extensions.rs");
+
+fn parse_usize_flag(arguments: &[String], name: &str, default: usize) -> usize {
+    let flag = format!("--{name}");
+    for (index, argument) in arguments.iter().enumerate() {
+        if argument == &flag {
+            return arguments
+                .get(index + 1)
+                .unwrap_or_else(|| panic!("{flag} requires a value"))
+                .parse::()
+                .unwrap_or_else(|_| panic!("{flag} must be an unsigned integer"));
+        }
+        if let Some(value) = argument.strip_prefix(&format!("{flag}=")) {
+            return value
+                .parse::()
+                .unwrap_or_else(|_| panic!("{flag} must be an unsigned integer"));
+        }
+    }
+    default
+}
+
+fn main() {
+    if let Some(result) = run_direct_extension_child_from_env() {
+        result.expect("native extension proof direct child failed");
+        return;
+    }
+    unsafe {
+        std::env::set_var(RELEASE_PROOF_RUNNER_ENV, "1");
+    }
+    let arguments = std::env::args().skip(1).collect::>();
+    if arguments.first().map(String::as_str) == Some("--native-tools-npm-smoke") {
+        let command = arguments
+            .get(1..)
+            .filter(|arguments| arguments.first().map(String::as_str) == Some("--"))
+            .and_then(|arguments| arguments.get(1..))
+            .filter(|command| !command.is_empty())
+            .expect("usage: oliphaunt-native-extension-proof --native-tools-npm-smoke -- COMMAND [ARG ...]");
+        run_native_tools_npm_smoke(command).expect("packed native npm tools smoke failed");
+        return;
+    }
+    let shard_index = parse_usize_flag(&arguments, "shard-index", 0);
+    let shard_count = parse_usize_flag(&arguments, "shard-count", 1);
+    run_native_extension_release_proof(shard_index, shard_count);
+}
+
+fn run_native_tools_npm_smoke(
+    command: &[String],
+) -> std::result::Result<(), Box> {
+    let root = unique_temp_root("native-tools-npm-smoke");
+    let server = block_on(
+        OliphauntServer::builder()
+            .storage(DatabaseStorage::Directory(root.clone()))
+            .extension(Extension::PGTAP)
+            .start(),
+    )?;
+    let child = Command::new(&command[0])
+        .args(&command[1..])
+        .env(
+            "OLIPHAUNT_NATIVE_TOOLS_CONNECTION_STRING",
+            server.connection_string(),
+        )
+        .status();
+    let close = block_on(server.close());
+    let _ = fs::remove_dir_all(&root);
+    let status = child?;
+    close?;
+    if !status.success() {
+        return Err(std::io::Error::other(format!(
+            "packed native npm tools smoke command exited with {status}"
+        ))
+        .into());
+    }
+    println!("OLIPHAUNT_NATIVE_TOOLS_NPM_SMOKE_PASS engines=node,bun,deno");
+    Ok(())
+}
diff --git a/src/extensions/tests/native/tools/native-extension-lifecycle-receipts.test.mts b/src/extensions/tests/native/tools/native-extension-lifecycle-receipts.test.mts
new file mode 100644
index 000000000..9a6bdb596
--- /dev/null
+++ b/src/extensions/tests/native/tools/native-extension-lifecycle-receipts.test.mts
@@ -0,0 +1,370 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import {
+  compareText,
+  exactExtensionProducts,
+  extensionSqlNames,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  assertExactFiles,
+  selectedExtensionDependencies,
+  stageExtensionCarrier,
+} from './stage-native-extension-lifecycle.mts';
+import { verifyReceipts } from './verify-native-extension-lifecycle-receipts.mts';
+import { writeReceipt } from './write-native-extension-lifecycle-receipt.mts';
+
+const TEST_SHARD_COUNT = 3;
+const CANDIDATE_SHA = 'a'.repeat(40);
+const CANDIDATE_TREE = 'b'.repeat(40);
+
+function sha256(value) {
+  return createHash('sha256').update(value).digest('hex');
+}
+
+function canonicalExtensions() {
+  return exactExtensionProducts('native-extension-lifecycle-receipts.test')
+    .flatMap((product) => extensionSqlNames(product, 'native-extension-lifecycle-receipts.test'))
+    .sort(compareText);
+}
+
+function inputEnvelope(extensions = canonicalExtensions()) {
+  const identities = [
+    'broker',
+    'broker-checksum',
+    'native-extension-index',
+    'native-extension-legacy-index',
+    'native-extension-proof-runner',
+    'native-runtime',
+    'native-tools',
+    ...extensions.map((name) => `native-extension:${name}`),
+  ].sort(compareText);
+  const core = {
+    schema: 'oliphaunt-native-extension-lifecycle-inputs-v1',
+    candidateSha: CANDIDATE_SHA,
+    candidateTree: CANDIDATE_TREE,
+    target: 'linux-x64-gnu',
+    extensionCount: extensions.length,
+    extensions,
+    modes: ['direct', 'broker', 'server'],
+    lifecycle: ['install', 'load', 'restart', 'backup', 'restore'],
+    consumedArtifacts: identities.map((identity, index) => ({
+      identity,
+      file: `artifact-${index}.tar.gz`,
+      bytes: index + 1,
+      sha256: sha256(identity),
+    })),
+  };
+  return { ...core, inputEnvelopeSha256: sha256(JSON.stringify(core)) };
+}
+
+function proofLog(inputs, shardIndex, shardCount) {
+  const selected = inputs.extensions.filter((_, index) => index % shardCount === shardIndex);
+  const lines = [
+    `OLIPHAUNT_NATIVE_EXTENSION_PROOF_START shard=${shardIndex}/${shardCount} selected=${selected.length} planned=${inputs.extensions.length} modes=direct,broker,server`,
+  ];
+  for (const extension of selected) {
+    lines.push(
+      `OLIPHAUNT_NATIVE_EXTENSION_PROOF_EXTENSION_PASS shard=${shardIndex}/${shardCount} extension=${extension} modes=direct,broker,server lifecycle=install-load-restart-backup-restore`,
+    );
+  }
+  lines.push(
+    `OLIPHAUNT_NATIVE_EXTENSION_PROOF_PASS shard=${shardIndex}/${shardCount} planned=${inputs.extensions.length} modes=direct,broker,server`,
+  );
+  return `${lines.join('\n')}\n`;
+}
+
+function fixture(extensions) {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-extension-receipts-'));
+  const input = path.join(root, 'inputs.json');
+  const inputs = inputEnvelope(extensions);
+  writeFileSync(input, `${JSON.stringify(inputs, null, 2)}\n`);
+  return { input, inputs, root };
+}
+
+function carrierEntries(files) {
+  return new Map([
+    [
+      'manifest.properties',
+      {
+        data: Buffer.from('packageLayout=oliphaunt-extension-artifact-v1\n'),
+        isDirectory: false,
+        mode: 0o644,
+      },
+    ],
+    ...files.map(([name, data, mode = 0o644]) => [
+      `files/${name}`,
+      { data: Buffer.from(data), isDirectory: false, mode },
+    ]),
+  ]);
+}
+
+function writeShard(value, shardIndex, { shardCount = TEST_SHARD_COUNT, logOverride } = {}) {
+  const log = path.join(value.root, `proof-shard-${shardIndex}.log`);
+  const output = path.join(value.root, `receipt-shard-${shardIndex}.json`);
+  writeFileSync(log, logOverride ?? proofLog(value.inputs, shardIndex, shardCount));
+  writeReceipt({
+    inputs: value.input,
+    log,
+    output,
+    'shard-index': String(shardIndex),
+    'shard-count': String(shardCount),
+  });
+  return output;
+}
+
+test('native staging excludes built-in dependencies from packaged extension dependency edges', () => {
+  assert.equal(
+    selectedExtensionDependencies({
+      dependencies: ['plpgsql'],
+      'selected-extension-dependencies': [],
+    }),
+    '',
+  );
+  assert.equal(
+    selectedExtensionDependencies({
+      dependencies: ['plpgsql', 'postgis'],
+      'selected-extension-dependencies': ['postgis'],
+    }),
+    'postgis',
+  );
+});
+
+test('exact lifecycle input diagnostics report basenames without masking inventory drift', () => {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-extension-inputs-'));
+  try {
+    writeFileSync(path.join(root, 'unexpected.tar.gz'), 'unexpected');
+    assert.throws(
+      () => assertExactFiles(root, [path.join(root, 'expected.tar.gz')], 'lifecycle input'),
+      /expected=expected\.tar\.gz; actual=unexpected\.tar\.gz/u,
+    );
+  } finally {
+    rmSync(root, { force: true, recursive: true });
+  }
+});
+
+test('native lifecycle staging flattens carrier envelopes and merges members by artifact product', () => {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-extension-staging-'));
+  try {
+    const contrib = {
+      'artifact-product': 'oliphaunt-extension-contrib-pg18',
+      'release-product': 'liboliphaunt-native',
+    };
+    stageExtensionCarrier(
+      carrierEntries([
+        ['share/postgresql/extension/amcheck.control', "default_version = '1.5'\n"],
+        ['share/postgresql/extension/amcheck--1.4.sql', 'SELECT 1;\n'],
+        ['share/postgresql/extension/amcheck--1.4--1.5.sql', 'SELECT 2;\n'],
+        ['lib/postgresql/amcheck.so', 'amcheck-module', 0o755],
+      ]),
+      root,
+      contrib,
+      'amcheck carrier',
+    );
+    stageExtensionCarrier(
+      carrierEntries([['lib/postgresql/auto_explain.so', 'auto-explain-module', 0o755]]),
+      root,
+      contrib,
+      'auto_explain carrier',
+    );
+    stageExtensionCarrier(
+      carrierEntries([
+        ['share/postgresql/extension/vector.control', "default_version = '0.8.0'\n"],
+        ['lib/postgresql/vector.so', 'vector-module', 0o755],
+      ]),
+      root,
+      {
+        'artifact-product': 'oliphaunt-extension-vector',
+        'release-product': 'oliphaunt-extension-vector',
+      },
+      'vector carrier',
+    );
+
+    const extensionRoot = path.join(root, 'resources/extension');
+    const contribRoot = path.join(extensionRoot, 'oliphaunt-extension-contrib-pg18');
+    assert.equal(
+      readFileSync(path.join(contribRoot, 'share/postgresql/extension/amcheck.control'), 'utf8'),
+      "default_version = '1.5'\n",
+    );
+    assert.equal(
+      readFileSync(
+        path.join(contribRoot, 'share/postgresql/extension/amcheck--1.4--1.5.sql'),
+        'utf8',
+      ),
+      'SELECT 2;\n',
+    );
+    assert.equal(
+      readFileSync(path.join(contribRoot, 'lib/postgresql/auto_explain.so'), 'utf8'),
+      'auto-explain-module',
+    );
+    assert.ok(
+      (statSync(path.join(contribRoot, 'lib/postgresql/auto_explain.so')).mode & 0o111) !== 0,
+    );
+    assert.equal(
+      readFileSync(
+        path.join(extensionRoot, 'oliphaunt-extension-vector/lib/postgresql/vector.so'),
+        'utf8',
+      ),
+      'vector-module',
+    );
+    assert.equal(existsSync(path.join(contribRoot, 'manifest.properties')), false);
+    assert.equal(existsSync(path.join(contribRoot, 'files')), false);
+    assert.equal(existsSync(path.join(extensionRoot, 'amcheck')), false);
+    assert.equal(existsSync(path.join(extensionRoot, 'auto_explain')), false);
+  } finally {
+    rmSync(root, { force: true, recursive: true });
+  }
+});
+
+test('native lifecycle product merges accept identical files and reject differing bytes', () => {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-extension-merge-'));
+  const product = {
+    'artifact-product': 'oliphaunt-extension-contrib-pg18',
+    'release-product': 'liboliphaunt-native',
+  };
+  const relative = 'share/postgresql/extension/shared--1.0.sql';
+  try {
+    stageExtensionCarrier(carrierEntries([[relative, 'same\n']]), root, product, 'first carrier');
+    stageExtensionCarrier(
+      carrierEntries([[relative, 'same\n']]),
+      root,
+      product,
+      'identical carrier',
+    );
+    assert.throws(
+      () =>
+        stageExtensionCarrier(
+          carrierEntries([[relative, 'different\n']]),
+          root,
+          product,
+          'conflicting carrier',
+        ),
+      /payload conflicts .* with different bytes/u,
+    );
+  } finally {
+    rmSync(root, { force: true, recursive: true });
+  }
+});
+
+test('three machine shard receipts aggregate to the exact artifact-bound public catalog', () => {
+  const value = fixture();
+  try {
+    for (let shardIndex = 0; shardIndex < TEST_SHARD_COUNT; shardIndex += 1)
+      writeShard(value, shardIndex);
+    const output = path.join(value.root, 'aggregate-receipt.json');
+    verifyReceipts({
+      receipts: value.root,
+      'candidate-sha': CANDIDATE_SHA,
+      'candidate-tree': CANDIDATE_TREE,
+      'expected-extensions-csv': value.inputs.extensions.join(','),
+      'expected-shard-count': String(TEST_SHARD_COUNT),
+      output,
+    });
+    const aggregate = JSON.parse(readFileSync(output, 'utf8'));
+    assert.equal(aggregate.extensionCount, value.inputs.extensions.length);
+    assert.deepEqual(aggregate.extensions, value.inputs.extensions);
+    assert.deepEqual(
+      aggregate.shardReceipts.map((receipt) => receipt.shardIndex),
+      Array.from({ length: TEST_SHARD_COUNT }, (_, shardIndex) => shardIndex),
+    );
+    assert.match(aggregate.aggregateSha256, /^[0-9a-f]{64}$/u);
+  } finally {
+    rmSync(value.root, { force: true, recursive: true });
+  }
+});
+
+test('focused dependency-closure proof uses one nonempty shard and aggregates exactly the selected subset', () => {
+  const value = fixture(['cube', 'earthdistance']);
+  try {
+    writeShard(value, 0, { shardCount: 1 });
+    const output = path.join(value.root, 'aggregate-receipt.json');
+    verifyReceipts({
+      receipts: value.root,
+      'candidate-sha': CANDIDATE_SHA,
+      'candidate-tree': CANDIDATE_TREE,
+      'expected-extensions-csv': value.inputs.extensions.join(','),
+      'expected-shard-count': '1',
+      output,
+    });
+    const aggregate = JSON.parse(readFileSync(output, 'utf8'));
+    assert.deepEqual(aggregate.extensions, ['cube', 'earthdistance']);
+    assert.equal(aggregate.extensionCount, 2);
+    assert.equal(aggregate.shardCount, 1);
+    assert.deepEqual(
+      aggregate.shardReceipts.map((receipt) => receipt.shardIndex),
+      [0],
+    );
+  } finally {
+    rmSync(value.root, { force: true, recursive: true });
+  }
+});
+
+test('shard receipt generation rejects omitted extension PASS records and incomplete artifact evidence', () => {
+  const value = fixture();
+  try {
+    const incompleteLog = proofLog(value.inputs, 0, TEST_SHARD_COUNT)
+      .split('\n')
+      .filter((line) => !line.includes(`extension=${value.inputs.extensions[0]} `))
+      .join('\n');
+    assert.throws(
+      () => writeShard(value, 0, { logOverride: incompleteLog }),
+      /unique extension PASS records/u,
+    );
+
+    const { inputEnvelopeSha256: ignored, ...core } = value.inputs;
+    core.consumedArtifacts = core.consumedArtifacts.slice(1);
+    const incomplete = { ...core, inputEnvelopeSha256: sha256(JSON.stringify(core)) };
+    writeFileSync(value.input, `${JSON.stringify(incomplete, null, 2)}\n`);
+    assert.throws(() => writeShard(value, 0), /enumerate all \d+ consumed artifacts/u);
+  } finally {
+    rmSync(value.root, { force: true, recursive: true });
+  }
+});
+
+test('aggregate verification rejects candidate, shard, and PASS-record drift even with recomputed receipts', () => {
+  const mutations = [
+    (receipt) => {
+      receipt.candidateSha = 'c'.repeat(40);
+    },
+    (receipt) => {
+      receipt.extensions = receipt.extensions.slice(1);
+      receipt.extensionCount -= 1;
+    },
+    (receipt) => {
+      receipt.passRecords[0].modes = ['direct', 'broker'];
+    },
+  ];
+  for (const mutate of mutations) {
+    const value = fixture();
+    try {
+      const files = Array.from({ length: TEST_SHARD_COUNT }, (_, shardIndex) =>
+        writeShard(value, shardIndex),
+      );
+      const receipt = JSON.parse(readFileSync(files[0], 'utf8'));
+      mutate(receipt);
+      const { receiptSha256: ignored, ...core } = receipt;
+      receipt.receiptSha256 = sha256(JSON.stringify(core));
+      writeFileSync(files[0], `${JSON.stringify(receipt, null, 2)}\n`);
+      assert.throws(
+        () =>
+          verifyReceipts({
+            receipts: value.root,
+            'candidate-sha': CANDIDATE_SHA,
+            'candidate-tree': CANDIDATE_TREE,
+            'expected-extensions-csv': value.inputs.extensions.join(','),
+            'expected-shard-count': String(TEST_SHARD_COUNT),
+            output: path.join(value.root, 'aggregate-receipt.json'),
+          }),
+        /candidate identity mismatch|PASS record count drift|malformed or misordered/u,
+      );
+    } finally {
+      rmSync(value.root, { force: true, recursive: true });
+    }
+  }
+});
diff --git a/tools/release/run-native-extension-lifecycle-proof.sh b/src/extensions/tests/native/tools/run-native-extension-lifecycle-proof.sh
similarity index 88%
rename from tools/release/run-native-extension-lifecycle-proof.sh
rename to src/extensions/tests/native/tools/run-native-extension-lifecycle-proof.sh
index cde3e7b25..3f3355164 100755
--- a/tools/release/run-native-extension-lifecycle-proof.sh
+++ b/src/extensions/tests/native/tools/run-native-extension-lifecycle-proof.sh
@@ -6,7 +6,7 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
   exit 1
 }
 cd "$root"
-source "$root/src/runtimes/liboliphaunt/wasix-postmaster/lib/process-supervision.sh"
+source "$root/src/runtimes/liboliphaunt-wasix-postmaster/lib/process-supervision.sh"
 
 shard_index="${SHARD_INDEX:-${1:-}}"
 shard_count="${SHARD_COUNT:-${2:-}}"
@@ -31,8 +31,9 @@ actual_sha="$(git rev-parse HEAD)"
 }
 candidate_tree="$(git rev-parse 'HEAD^{tree}')"
 
-"$root/tools/dev/bun.sh" "$root/tools/release/stage-native-extension-lifecycle.mjs" \
+"$root/tools/dev/bun.sh" "$root/src/extensions/tests/native/tools/stage-native-extension-lifecycle.mts" \
   --runtime-assets "$input_root/runtime" \
+  --tools-assets "$input_root/tools" \
   --extension-assets "$input_root/extensions" \
   --broker-assets "$input_root/broker" \
   --proof-runner "$runner" \
@@ -68,12 +69,12 @@ fresh_run_process_group_timeout_ms "$proof_timeout_ms" -- \
 if [ "$shard_index" = "0" ]; then
   fresh_run_process_group_timeout_ms "$proof_timeout_ms" -- \
     "$runner" --native-tools-npm-smoke -- \
-      "$root/tools/dev/bun.sh" \
-      "$root/src/runtimes/liboliphaunt/native/tools/smoke-packed-tools-npm.mjs" \
-      --asset-dir "$input_root/runtime" 2>&1 \
+      bash \
+      "$root/src/postgres-tools/native/tools/smoke-packed-tools-npm.sh" \
+      --asset-dir "$input_root/tools" 2>&1 \
     | tee "$evidence_root/native-tools-npm-shard-$shard_index.log"
 fi
-"$root/tools/dev/bun.sh" "$root/tools/release/write-native-extension-lifecycle-receipt.mjs" \
+"$root/tools/dev/bun.sh" "$root/src/extensions/tests/native/tools/write-native-extension-lifecycle-receipt.mts" \
   --inputs "$stage_root/inputs.json" \
   --log "$evidence_root/proof-shard-$shard_index.log" \
   --shard-index "$shard_index" \
diff --git a/src/extensions/tests/native/tools/stage-native-extension-lifecycle.mts b/src/extensions/tests/native/tools/stage-native-extension-lifecycle.mts
new file mode 100755
index 000000000..b4dbe6021
--- /dev/null
+++ b/src/extensions/tests/native/tools/stage-native-extension-lifecycle.mts
@@ -0,0 +1,620 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import {
+  chmodSync,
+  lstatSync,
+  mkdirSync,
+  readdirSync,
+  readFileSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { gunzipSync } from 'node:zlib';
+import {
+  requiredRuntimeMemberPaths,
+  requiredToolsMemberPaths,
+} from '../../../../runtimes/liboliphaunt-native/tools/native-runtime-payload.mts';
+import {
+  compareText,
+  currentProductVersionSync,
+  exactExtensionProducts,
+  extensionReleaseProduct,
+  extensionSqlNames,
+  ROOT,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  isCanonicalNativeExtensionRuntimeIndexRow,
+  NATIVE_EXTENSION_ASSET_INDEX_HEADER,
+} from '../../../artifacts/native/tools/native-extension-asset-index-contract.mts';
+import {
+  isCanonicalExtensionInstallSql,
+  validateExtensionArtifactArchive,
+  validateExtensionInstallSqlReachability,
+} from '../../../artifacts/packages/tools/extension-artifact-inventory.mts';
+
+const PREFIX = 'stage-native-extension-lifecycle.mts';
+const TARGET = 'linux-x64-gnu';
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+
+function parseArgs(argv) {
+  const values = new Map();
+  const pathArguments = new Set([
+    'runtime-assets',
+    'tools-assets',
+    'extension-assets',
+    'broker-assets',
+    'proof-runner',
+    'output',
+  ]);
+  for (let index = 0; index < argv.length; index += 1) {
+    const name = argv[index];
+    if (!name?.startsWith('--')) fail(`unknown argument ${name}`);
+    const value = argv[index + 1];
+    if (!value || value.startsWith('--')) fail(`${name} requires a value`);
+    const key = name.slice(2);
+    values.set(key, pathArguments.has(key) ? path.resolve(value) : value);
+    index += 1;
+  }
+  for (const required of [
+    'runtime-assets',
+    'tools-assets',
+    'extension-assets',
+    'broker-assets',
+    'proof-runner',
+    'candidate-sha',
+    'candidate-tree',
+    'extensions-csv',
+    'output',
+  ]) {
+    if (!values.has(required)) fail(`--${required} is required`);
+  }
+  return Object.fromEntries(values);
+}
+
+function sha256Bytes(data) {
+  return createHash('sha256').update(data).digest('hex');
+}
+
+function artifactRecord(identity, file) {
+  const data = readFileSync(file);
+  return {
+    identity,
+    file: path.basename(file),
+    bytes: data.length,
+    sha256: sha256Bytes(data),
+  };
+}
+
+export function assertExactFiles(root, expected, label) {
+  const actual = regularFiles(root)
+    .map((file) => path.resolve(file))
+    .sort(compareText);
+  const wanted = [...expected].map((file) => path.resolve(file)).sort(compareText);
+  if (actual.join('\0') !== wanted.join('\0')) {
+    fail(
+      `${label} has unindexed files: expected=${wanted.map((file) => path.basename(file)).join(',')}; ` +
+        `actual=${actual.map((file) => path.basename(file)).join(',')}`,
+    );
+  }
+}
+
+function regularFiles(root) {
+  const files = [];
+  const visit = (directory) => {
+    for (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) =>
+      compareText(a.name, b.name),
+    )) {
+      const file = path.join(directory, entry.name);
+      const stat = lstatSync(file);
+      if (stat.isSymbolicLink()) fail(`artifact input contains symbolic link: ${file}`);
+      if (stat.isDirectory()) visit(file);
+      else if (stat.isFile()) files.push(file);
+      else fail(`artifact input contains unsupported filesystem entry: ${file}`);
+    }
+  };
+  if (!statSync(root).isDirectory()) fail(`artifact input is not a directory: ${root}`);
+  visit(root);
+  return files;
+}
+
+function oneFile(root, basename) {
+  const matches = regularFiles(root).filter((file) => path.basename(file) === basename);
+  if (matches.length !== 1) {
+    fail(`${root} must contain exactly one ${basename}, found ${matches.length}`);
+  }
+  return matches[0];
+}
+
+function tarString(buffer, start, length) {
+  const end = buffer.indexOf(0, start);
+  return buffer
+    .subarray(start, end >= start && end < start + length ? end : start + length)
+    .toString('utf8')
+    .trim();
+}
+
+function tarOctal(buffer, start, length, label) {
+  const value = tarString(buffer, start, length).replaceAll('\0', '').trim();
+  if (!value) return 0;
+  if (!/^[0-7]+$/u.test(value)) fail(`archive has malformed ${label}: ${JSON.stringify(value)}`);
+  return Number.parseInt(value, 8);
+}
+
+function safeArchivePath(raw, archive) {
+  const normalized = raw.replaceAll('\\', '/').replace(/\/$/u, '');
+  if (normalized === '.') return null;
+  const parts = normalized.split('/');
+  if (
+    !normalized ||
+    normalized.startsWith('/') ||
+    parts.some((part) => !part || part === '.' || part === '..')
+  ) {
+    fail(`${archive} contains unsafe member ${JSON.stringify(raw)}`);
+  }
+  return parts.join('/');
+}
+
+export function readCanonicalTarGz(file) {
+  let buffer;
+  try {
+    buffer = gunzipSync(readFileSync(file));
+  } catch (error) {
+    fail(`${file} is not a readable gzip tar archive: ${error.message}`);
+  }
+  const entries = new Map();
+  let sawTerminator = false;
+  for (let offset = 0; offset + 512 <= buffer.length; ) {
+    const header = buffer.subarray(offset, offset + 512);
+    if (header.every((byte) => byte === 0)) {
+      sawTerminator = true;
+      break;
+    }
+    const rawName = tarString(header, 0, 100);
+    const prefix = tarString(header, 345, 155);
+    const fullName = prefix ? `${prefix}/${rawName}` : rawName;
+    const name = safeArchivePath(fullName, file);
+    const mode = tarOctal(header, 100, 8, 'mode');
+    const size = tarOctal(header, 124, 12, 'size');
+    const type = header.subarray(156, 157).toString('utf8');
+    if (type !== '0' && type !== '5' && type !== '') {
+      fail(
+        `${file} contains unsupported non-file member ${JSON.stringify(fullName)} type=${JSON.stringify(type)}`,
+      );
+    }
+    const isDirectory = type === '5';
+    if (isDirectory !== fullName.endsWith('/') && name !== null) {
+      fail(`${file} contains non-canonical member marker ${JSON.stringify(fullName)}`);
+    }
+    const dataOffset = offset + 512;
+    if (dataOffset + size > buffer.length) fail(`${file} truncates member ${fullName}`);
+    if (name !== null) {
+      if (entries.has(name)) fail(`${file} contains duplicate member ${name}`);
+      entries.set(name, {
+        data: Buffer.from(buffer.subarray(dataOffset, dataOffset + size)),
+        isDirectory,
+        mode,
+      });
+    }
+    offset = dataOffset + Math.ceil(size / 512) * 512;
+  }
+  if (!sawTerminator) fail(`${file} is missing the tar terminator`);
+  return entries;
+}
+
+function extract(entries, destination) {
+  mkdirSync(destination, { recursive: true });
+  for (const [name, entry] of [...entries].sort(([left], [right]) => compareText(left, right))) {
+    const output = path.join(destination, ...name.split('/'));
+    const relative = path.relative(destination, output);
+    if (relative.startsWith('..') || path.isAbsolute(relative))
+      fail(`unsafe extraction path ${name}`);
+    if (entry.isDirectory) {
+      mkdirSync(output, { recursive: true });
+      chmodSync(output, 0o755);
+    } else {
+      mkdirSync(path.dirname(output), { recursive: true });
+      writeFileSync(output, entry.data, { mode: entry.mode & 0o111 ? 0o755 : 0o644 });
+    }
+  }
+}
+
+function optionalLstat(file) {
+  try {
+    return lstatSync(file);
+  } catch (error) {
+    if (error?.code === 'ENOENT') return null;
+    throw error;
+  }
+}
+
+/**
+ * Stage one validated extension carrier into the product-owned resource layout
+ * emitted by oliphaunt-build. Carrier-only manifest.properties and files/
+ * envelope paths are deliberately not exposed to the runtime locator.
+ */
+export function stageExtensionCarrier(
+  entries,
+  output,
+  metadata,
+  archive = 'native extension carrier',
+) {
+  const artifactProduct = metadata?.['artifact-product'];
+  const releaseProduct = metadata?.['release-product'];
+  if (
+    typeof artifactProduct !== 'string' ||
+    !/^oliphaunt-extension-[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(artifactProduct)
+  ) {
+    fail(`${archive} has invalid generated artifact-product ${JSON.stringify(artifactProduct)}`);
+  }
+  const expectedReleaseProduct = extensionReleaseProduct(artifactProduct, 'native', PREFIX);
+  if (releaseProduct !== expectedReleaseProduct) {
+    fail(`${archive} has invalid generated release-product ${JSON.stringify(releaseProduct)}`);
+  }
+  requireArchiveFile(entries, 'manifest.properties', archive);
+  const destination = path.join(output, 'resources/extension', artifactProduct);
+  mkdirSync(destination, { recursive: true });
+  let stagedFiles = 0;
+  for (const [name, entry] of [...entries].sort(([left], [right]) => compareText(left, right))) {
+    if (name === 'manifest.properties') continue;
+    if (name === 'files') {
+      if (!entry.isDirectory) fail(`${archive} files carrier root must be a directory`);
+      continue;
+    }
+    if (!name.startsWith('files/')) {
+      fail(`${archive} contains unexpected carrier-root member ${name}`);
+    }
+    const relativeName = name.slice('files/'.length);
+    if (!relativeName) fail(`${archive} contains an empty carrier payload path`);
+    const target = path.join(destination, ...relativeName.split('/'));
+    const relative = path.relative(destination, target);
+    if (relative.startsWith('..') || path.isAbsolute(relative)) {
+      fail(`${archive} contains unsafe carrier payload path ${name}`);
+    }
+    const existing = optionalLstat(target);
+    if (entry.isDirectory) {
+      if (existing !== null && !existing.isDirectory()) {
+        fail(`${archive} payload directory conflicts at ${target}`);
+      }
+      mkdirSync(target, { recursive: true });
+      chmodSync(target, 0o755);
+      continue;
+    }
+    if (existing !== null) {
+      if (!existing.isFile() || existing.isSymbolicLink()) {
+        fail(`${archive} payload file conflicts at ${target}`);
+      }
+      const existingData = readFileSync(target);
+      if (!existingData.equals(entry.data)) {
+        fail(
+          `${archive} payload conflicts at ${target} with different bytes: ` +
+            `existing=${sha256Bytes(existingData)} incoming=${sha256Bytes(entry.data)}`,
+        );
+      }
+      const executable = (existing.mode & 0o111) !== 0 || (entry.mode & 0o111) !== 0;
+      chmodSync(target, executable ? 0o755 : 0o644);
+    } else {
+      try {
+        mkdirSync(path.dirname(target), { recursive: true });
+      } catch (error) {
+        fail(`${archive} cannot create payload parent for ${target}: ${error.message}`);
+      }
+      writeFileSync(target, entry.data, { mode: entry.mode & 0o111 ? 0o755 : 0o644 });
+    }
+    stagedFiles += 1;
+  }
+  if (stagedFiles === 0) fail(`${archive} has no files/ payload files`);
+  return destination;
+}
+
+function parseProperties(data, label) {
+  const properties = new Map();
+  for (const [index, raw] of data.toString('utf8').split(/\r?\n/u).entries()) {
+    if (!raw) continue;
+    const separator = raw.indexOf('=');
+    if (separator <= 0) fail(`${label} has malformed properties line ${index + 1}`);
+    const key = raw.slice(0, separator);
+    if (properties.has(key)) fail(`${label} repeats property ${key}`);
+    properties.set(key, raw.slice(separator + 1));
+  }
+  return properties;
+}
+
+function parseTsv(file) {
+  const lines = readFileSync(file, 'utf8').split(/\r?\n/u).filter(Boolean);
+  if (lines.length < 2) fail(`${file} has no artifact rows`);
+  const header = lines[0].split('\t');
+  const expectedHeader = NATIVE_EXTENSION_ASSET_INDEX_HEADER;
+  if (header.join('\t') !== expectedHeader.join('\t')) fail(`${file} has a non-canonical header`);
+  return lines.slice(1).map((line, index) => {
+    const fields = line.split('\t');
+    if (fields.length !== header.length)
+      fail(`${file} row ${index + 2} has ${fields.length} fields`);
+    return Object.fromEntries(header.map((column, fieldIndex) => [column, fields[fieldIndex]]));
+  });
+}
+
+function canonicalExtensions(selectionCsv) {
+  const metadataFile = path.join(ROOT, 'src/extensions/generated/sdk/extensions.json');
+  const metadata = JSON.parse(readFileSync(metadataFile, 'utf8'));
+  const byName = new Map((metadata.extensions ?? []).map((row) => [row['sql-name'], row]));
+  const canonicalNames = exactExtensionProducts(PREFIX)
+    .flatMap((product) => extensionSqlNames(product, PREFIX))
+    .sort(compareText);
+  if (canonicalNames.length === 0 || new Set(canonicalNames).size !== canonicalNames.length) {
+    fail('canonical exact-extension products must resolve to a nonempty unique SQL-name set');
+  }
+  const names = selectionCsv.split(',').filter(Boolean).sort(compareText);
+  if (names.length === 0 || new Set(names).size !== names.length) {
+    fail('planned native lifecycle extension selection must be nonempty and unique');
+  }
+  const canonicalSet = new Set(canonicalNames);
+  const unknown = names.filter((name) => !canonicalSet.has(name));
+  if (unknown.length > 0)
+    fail(`planned native lifecycle selection contains unknown extensions: ${unknown.join(',')}`);
+  const rows = names.map((name) => {
+    const row = byName.get(name);
+    if (!row) fail(`generated extension metadata has no row for ${name}`);
+    return row;
+  });
+  const selectedSet = new Set(names);
+  for (const row of rows) {
+    const missing = (row['selected-extension-dependencies'] ?? []).filter(
+      (dependency) => !selectedSet.has(dependency),
+    );
+    if (missing.length > 0) {
+      fail(
+        `${row['sql-name']} planned native lifecycle selection omits dependencies: ${missing.join(',')}`,
+      );
+    }
+  }
+  return rows;
+}
+
+function requireArchiveFile(entries, name, archive) {
+  const entry = entries.get(name);
+  if (!entry || entry.isDirectory || entry.data.length === 0)
+    fail(`${archive} is missing non-empty ${name}`);
+  return entry;
+}
+
+export function selectedExtensionDependencies(metadata) {
+  const selected = metadata?.['selected-extension-dependencies'];
+  if (
+    !Array.isArray(selected) ||
+    selected.some((name) => typeof name !== 'string' || name.length === 0)
+  ) {
+    fail('generated extension metadata has invalid selected-extension-dependencies');
+  }
+  const sorted = [...selected].sort(compareText);
+  if (new Set(sorted).size !== sorted.length) {
+    fail('generated extension metadata repeats a selected extension dependency');
+  }
+  return sorted.join(',');
+}
+
+function stageBaseRuntime(runtimeAssets, toolsAssets, output, extensionRows) {
+  const version = currentProductVersionSync('liboliphaunt-native', PREFIX);
+  const runtimeArchive = oneFile(runtimeAssets, `liboliphaunt-${version}-${TARGET}.tar.gz`);
+  const toolsVersion = currentProductVersionSync('postgres-tools-native', PREFIX);
+  const toolsArchive = oneFile(toolsAssets, `oliphaunt-tools-${toolsVersion}-${TARGET}.tar.gz`);
+  const runtimeEntries = readCanonicalTarGz(runtimeArchive);
+  const toolsEntries = readCanonicalTarGz(toolsArchive);
+  for (const required of [
+    'lib/liboliphaunt.so',
+    'lib/modules/dict_snowball.so',
+    'lib/modules/plpgsql.so',
+    ...requiredRuntimeMemberPaths(TARGET, 'runtime/bin'),
+  ])
+    requireArchiveFile(runtimeEntries, required, runtimeArchive);
+  for (const required of requiredToolsMemberPaths(TARGET, 'runtime/bin')) {
+    requireArchiveFile(toolsEntries, required, toolsArchive);
+  }
+  for (const row of extensionRows) {
+    const sqlName = row['sql-name'];
+    if (runtimeEntries.has(`runtime/share/postgresql/extension/${sqlName}.control`)) {
+      fail(`base runtime artifact leaks optional extension ${sqlName}`);
+    }
+  }
+  extract(runtimeEntries, path.join(output, 'resources/native-runtime/liboliphaunt-native'));
+  extract(toolsEntries, path.join(output, 'resources/native-tools/oliphaunt-tools'));
+  assertExactFiles(runtimeAssets, [runtimeArchive], 'Linux runtime artifact download');
+  assertExactFiles(toolsAssets, [toolsArchive], 'Linux tools artifact download');
+  return [
+    artifactRecord('native-runtime', runtimeArchive),
+    artifactRecord('native-tools', toolsArchive),
+  ];
+}
+
+function stageBroker(brokerAssets, output) {
+  const version = currentProductVersionSync('oliphaunt-broker', PREFIX);
+  const archive = oneFile(brokerAssets, `oliphaunt-broker-${version}-${TARGET}.tar.gz`);
+  const checksum = oneFile(brokerAssets, `oliphaunt-broker-${version}-release-assets.sha256`);
+  const checksumLines = readFileSync(checksum, 'utf8').split(/\r?\n/u).filter(Boolean);
+  if (checksumLines.length !== 1)
+    fail(`${checksum} must cover exactly the one partial Linux broker artifact`);
+  const checksumMatch = checksumLines[0].match(/^([0-9a-f]{64})\s+\.\/(.+)$/u);
+  if (!checksumMatch || checksumMatch[2] !== path.basename(archive)) {
+    fail(`${checksum} does not bind the exact Linux broker artifact`);
+  }
+  const actualBrokerSha = artifactRecord('broker', archive).sha256;
+  if (checksumMatch[1] !== actualBrokerSha) fail(`${checksum} digest does not match ${archive}`);
+  const entries = readCanonicalTarGz(archive);
+  const binary = requireArchiveFile(entries, 'bin/oliphaunt-broker', archive);
+  if ((binary.mode & 0o111) === 0) fail(`${archive} broker is not executable`);
+  const manifest = parseProperties(
+    requireArchiveFile(entries, 'manifest.properties', archive).data,
+    archive,
+  );
+  for (const [key, expected] of [
+    ['schema', 'oliphaunt-broker-release-assets-v1'],
+    ['product', 'oliphaunt-broker'],
+    ['version', version],
+    ['target', TARGET],
+    ['binary', 'bin/oliphaunt-broker'],
+  ]) {
+    if (manifest.get(key) !== expected) fail(`${archive} ${key} must be ${expected}`);
+  }
+  extract(entries, path.join(output, 'broker'));
+  assertExactFiles(brokerAssets, [archive, checksum], 'Linux broker artifact download');
+  return [artifactRecord('broker', archive), artifactRecord('broker-checksum', checksum)];
+}
+
+function stageExtensions(extensionAssets, output, extensionRows) {
+  const version = currentProductVersionSync('liboliphaunt-native', PREFIX);
+  const index = oneFile(extensionAssets, `liboliphaunt-${version}-native-extension-assets.tsv`);
+  const rows = parseTsv(index);
+  const expectedNames = extensionRows.map((row) => row['sql-name']).sort(compareText);
+  const actualNames = rows.map((row) => row.sql_name).sort(compareText);
+  if (rows.length !== expectedNames.length || new Set(actualNames).size !== rows.length) {
+    fail(
+      `native extension artifact index must contain ${expectedNames.length} unique rows, got ${rows.length}`,
+    );
+  }
+  if (actualNames.join('\0') !== expectedNames.join('\0')) {
+    fail(
+      `native extension artifact index drift: expected=${expectedNames.join(',')}; actual=${actualNames.join(',')}`,
+    );
+  }
+  const metadataByName = new Map(extensionRows.map((row) => [row['sql-name'], row]));
+  const referenced = new Set();
+  const consumed = [artifactRecord('native-extension-index', index)];
+  for (const row of rows) {
+    if (!isCanonicalNativeExtensionRuntimeIndexRow(row, TARGET)) {
+      fail(`native extension artifact index has invalid carrier row for ${row.sql_name}`);
+    }
+    if (!/^[1-9][0-9]*$/u.test(row.artifact_bytes))
+      fail(`invalid artifact byte count for ${row.sql_name}`);
+    const archive = path.resolve(path.dirname(index), row.artifact);
+    const relative = path.relative(path.dirname(index), archive);
+    if (relative.startsWith('..') || path.isAbsolute(relative))
+      fail(`artifact path escapes index for ${row.sql_name}`);
+    if (statSync(archive).size !== Number(row.artifact_bytes))
+      fail(`artifact byte count drift for ${row.sql_name}`);
+    referenced.add(archive);
+    consumed.push(artifactRecord(`native-extension:${row.sql_name}`, archive));
+    const metadata = metadataByName.get(row.sql_name);
+    const validated = validateExtensionArtifactArchive({
+      file: archive,
+      metadata,
+      target: TARGET,
+      nativeRuntimeVersion: version,
+      label: archive,
+    });
+    const { entries, properties: manifest } = validated;
+    const expectedDependencies = selectedExtensionDependencies(metadata);
+    for (const [key, expected] of [
+      ['packageLayout', 'oliphaunt-extension-artifact-v1'],
+      ['pgMajor', '18'],
+      ['sqlName', row.sql_name],
+      ['createsExtension', metadata['creates-extension'] === true ? 'yes' : 'no'],
+      ['nativeModuleStem', metadata['native-module-stem'] ?? ''],
+      ['nativeTarget', TARGET],
+      ['nativeRuntimeProduct', 'liboliphaunt-native'],
+      ['nativeRuntimeVersion', version],
+      ['dependencies', expectedDependencies],
+      ['dataFiles', (metadata['runtime-share-data-files'] ?? []).join(',')],
+      ['extensionSqlFileNames', (metadata['extension-sql-file-names'] ?? []).join(',')],
+      ['extensionSqlFilePrefixes', (metadata['extension-sql-file-prefixes'] ?? []).join(',')],
+      ['sharedPreloadLibraries', (metadata['shared-preload-libraries'] ?? []).join(',')],
+      ['files', 'files'],
+    ]) {
+      if (manifest.get(key) !== expected) fail(`${archive} ${key} must be ${expected}`);
+    }
+    if (!new Set(['yes', 'no']).has(manifest.get('mobilePrebuilt'))) {
+      fail(`${archive} mobilePrebuilt must be yes or no`);
+    }
+    if (metadata['creates-extension'] === true) {
+      const controlName = `files/share/postgresql/extension/${row.sql_name}.control`;
+      const control = requireArchiveFile(entries, controlName, archive);
+      const sqlPrefix = 'files/share/postgresql/extension/';
+      const sqlFileNames = [...entries.keys()]
+        .filter((name) => name.startsWith(sqlPrefix) && !entries.get(name).isDirectory)
+        .map((name) => name.slice(sqlPrefix.length));
+      if (!sqlFileNames.some((name) => isCanonicalExtensionInstallSql(name, row.sql_name))) {
+        fail(`${archive} has no canonical base install SQL for ${row.sql_name}`);
+      }
+      validateExtensionInstallSqlReachability({
+        sqlName: row.sql_name,
+        control: control.data.toString('utf8'),
+        fileNames: sqlFileNames,
+        label: archive,
+      });
+    }
+    const stem = metadata['native-module-stem'];
+    const expectedModuleFile = stem === null ? '' : `${stem}.so`;
+    if (manifest.get('nativeModuleFile') !== expectedModuleFile) {
+      fail(`${archive} nativeModuleFile must be ${expectedModuleFile}`);
+    }
+    if (expectedModuleFile !== '') {
+      requireArchiveFile(entries, `files/lib/postgresql/${expectedModuleFile}`, archive);
+    }
+    // Legal-envelope members are validated above but are not runtime resources.
+    // Flatten only manifest.properties + files/** into the lifecycle layout.
+    const runtimeEntries = new Map(
+      [...entries].filter(([name]) => name === 'manifest.properties' || name.startsWith('files/')),
+    );
+    stageExtensionCarrier(runtimeEntries, output, metadata, archive);
+  }
+  const unreferenced = regularFiles(path.dirname(index))
+    .filter((file) => file.endsWith('.tar.gz') && !referenced.has(file))
+    .map((file) => path.basename(file));
+  if (unreferenced.length > 0)
+    fail(`unindexed native extension artifacts: ${unreferenced.join(',')}`);
+  const legacyIndex = oneFile(extensionAssets, `liboliphaunt-${version}-extension-assets.tsv`);
+  consumed.push(artifactRecord('native-extension-legacy-index', legacyIndex));
+  assertExactFiles(
+    extensionAssets,
+    [index, legacyIndex, ...referenced],
+    'Linux exact-extension artifact download',
+  );
+  return consumed;
+}
+
+export function stageNativeExtensionLifecycle(args) {
+  if (!/^[0-9a-f]{40}$/u.test(args['candidate-sha']))
+    fail('--candidate-sha must be a full 40-character Git object ID');
+  if (!/^[0-9a-f]{40}$/u.test(args['candidate-tree']))
+    fail('--candidate-tree must be a full 40-character Git tree ID');
+  const extensionRows = canonicalExtensions(args['extensions-csv']);
+  rmSync(args.output, { force: true, recursive: true });
+  mkdirSync(args.output, { recursive: true });
+  const consumedArtifacts = [
+    ...stageBaseRuntime(args['runtime-assets'], args['tools-assets'], args.output, extensionRows),
+    ...stageBroker(args['broker-assets'], args.output),
+    ...stageExtensions(args['extension-assets'], args.output, extensionRows),
+    artifactRecord('native-extension-proof-runner', args['proof-runner']),
+  ].sort((left, right) => compareText(left.identity, right.identity));
+  const evidenceCore = {
+    schema: 'oliphaunt-native-extension-lifecycle-inputs-v1',
+    candidateSha: args['candidate-sha'],
+    candidateTree: args['candidate-tree'],
+    target: TARGET,
+    extensionCount: extensionRows.length,
+    extensions: extensionRows.map((row) => row['sql-name']).sort(compareText),
+    modes: ['direct', 'broker', 'server'],
+    lifecycle: ['install', 'load', 'restart', 'backup', 'restore'],
+    consumedArtifacts,
+  };
+  const evidence = {
+    ...evidenceCore,
+    inputEnvelopeSha256: sha256Bytes(Buffer.from(JSON.stringify(evidenceCore))),
+  };
+  writeFileSync(path.join(args.output, 'inputs.json'), `${JSON.stringify(evidence, null, 2)}\n`);
+  console.log(
+    `native extension lifecycle inputs staged: ${args.output} (${extensionRows.length} extensions)`,
+  );
+}
+
+if (import.meta.main) {
+  try {
+    stageNativeExtensionLifecycle(parseArgs(Bun.argv.slice(2)));
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(1);
+  }
+}
diff --git a/src/extensions/tests/native/tools/verify-native-extension-lifecycle-receipts.mts b/src/extensions/tests/native/tools/verify-native-extension-lifecycle-receipts.mts
new file mode 100644
index 000000000..0724efe44
--- /dev/null
+++ b/src/extensions/tests/native/tools/verify-native-extension-lifecycle-receipts.mts
@@ -0,0 +1,245 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { lstatSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+import {
+  compareText,
+  exactExtensionProducts,
+  extensionSqlNames,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+
+function fail(message) {
+  throw new Error(`verify-native-extension-lifecycle-receipts.mts: ${message}`);
+}
+
+function flags(argv) {
+  const values = {};
+  for (let index = 0; index < argv.length; index += 2) {
+    const name = argv[index];
+    const value = argv[index + 1];
+    if (!name?.startsWith('--') || value === undefined) fail(`invalid argument ${name ?? ''}`);
+    values[name.slice(2)] = value;
+  }
+  for (const name of [
+    'receipts',
+    'candidate-sha',
+    'candidate-tree',
+    'expected-extensions-csv',
+    'expected-shard-count',
+    'output',
+  ]) {
+    if (values[name] === undefined) fail(`--${name} is required`);
+  }
+  return values;
+}
+
+function sha256(value) {
+  return createHash('sha256').update(value).digest('hex');
+}
+
+function assertConsumedArtifacts(artifacts, extensions, shardIndex) {
+  const expectedIdentities = [
+    'broker',
+    'broker-checksum',
+    'native-extension-index',
+    'native-extension-legacy-index',
+    'native-extension-proof-runner',
+    'native-runtime',
+    'native-tools',
+    ...extensions.map((name) => `native-extension:${name}`),
+  ].sort(compareText);
+  if (!Array.isArray(artifacts) || artifacts.length !== expectedIdentities.length) {
+    fail(`shard ${shardIndex} consumed artifact count drift`);
+  }
+  if (
+    artifacts.map((artifact) => artifact?.identity).join('\0') !== expectedIdentities.join('\0')
+  ) {
+    fail(`shard ${shardIndex} consumed artifact identities are incomplete or unsorted`);
+  }
+  for (const artifact of artifacts) {
+    if (
+      typeof artifact.file !== 'string' ||
+      artifact.file.length === 0 ||
+      artifact.file.includes('/') ||
+      artifact.file.includes('\\') ||
+      !Number.isSafeInteger(artifact.bytes) ||
+      artifact.bytes <= 0 ||
+      !/^[0-9a-f]{64}$/u.test(artifact.sha256)
+    )
+      fail(
+        `shard ${shardIndex} consumed artifact ${String(artifact.identity)} lacks SHA-256 and byte evidence`,
+      );
+  }
+}
+
+function receiptFiles(root) {
+  const files = [];
+  const visit = (directory) => {
+    for (const entry of readdirSync(directory, { withFileTypes: true })) {
+      const file = path.join(directory, entry.name);
+      if (lstatSync(file).isSymbolicLink()) fail(`receipt input contains symbolic link ${file}`);
+      if (entry.isDirectory()) visit(file);
+      else if (entry.isFile() && /^receipt-shard-\d+\.json$/u.test(entry.name)) files.push(file);
+    }
+  };
+  visit(root);
+  return files.sort(compareText);
+}
+
+export function verifyReceipts(options) {
+  if (
+    !/^[0-9a-f]{40}$/u.test(options['candidate-sha']) ||
+    !/^[0-9a-f]{40}$/u.test(options['candidate-tree'])
+  ) {
+    fail('candidate SHA and tree must be full 40-character Git object IDs');
+  }
+  const canonical = exactExtensionProducts('native-extension-lifecycle-receipts')
+    .flatMap((product) => extensionSqlNames(product, 'native-extension-lifecycle-receipts'))
+    .sort(compareText);
+  if (canonical.length === 0 || new Set(canonical).size !== canonical.length) {
+    fail('canonical release graph must resolve to a nonempty unique extension set');
+  }
+  const expected = options['expected-extensions-csv'].split(',').filter(Boolean).sort(compareText);
+  const canonicalSet = new Set(canonical);
+  if (
+    expected.length === 0 ||
+    new Set(expected).size !== expected.length ||
+    expected.some((name) => !canonicalSet.has(name))
+  )
+    fail('expected extension set must be a nonempty unique canonical release-graph subset');
+  const expectedShardCount = Number(options['expected-shard-count']);
+  if (
+    !Number.isInteger(expectedShardCount) ||
+    expectedShardCount < 1 ||
+    expectedShardCount > expected.length
+  ) {
+    fail(
+      'expected shard count must be a positive integer no greater than the planned extension count',
+    );
+  }
+  const files = receiptFiles(options.receipts);
+  if (files.length !== expectedShardCount) {
+    fail(`expected exactly ${expectedShardCount} shard receipts, found ${files.length}`);
+  }
+  const receipts = files.map((file) => ({ file, receipt: JSON.parse(readFileSync(file, 'utf8')) }));
+
+  const seenShards = new Set();
+  const seenExtensions = new Set();
+  const inputDigests = new Set();
+  let consumedArtifacts;
+  for (const { file, receipt } of receipts) {
+    const { receiptSha256, ...core } = receipt;
+    if (receiptSha256 !== sha256(JSON.stringify(core)))
+      fail(`shard ${receipt.shardIndex} receipt digest mismatch`);
+    if (receipt.schema !== 'oliphaunt-native-extension-lifecycle-shard-receipt-v1')
+      fail('unknown shard receipt schema');
+    if (
+      receipt.candidateSha !== options['candidate-sha'] ||
+      receipt.candidateTree !== options['candidate-tree']
+    ) {
+      fail(`shard ${receipt.shardIndex} candidate identity mismatch`);
+    }
+    if (
+      receipt.target !== 'linux-x64-gnu' ||
+      receipt.shardCount !== expectedShardCount ||
+      !Number.isInteger(receipt.shardIndex) ||
+      receipt.shardIndex < 0 ||
+      receipt.shardIndex >= expectedShardCount
+    ) {
+      fail('receipt has non-canonical target or shard identity');
+    }
+    if (path.basename(file) !== `receipt-shard-${receipt.shardIndex}.json`) {
+      fail(`receipt filename does not match shard identity ${receipt.shardIndex}`);
+    }
+    if (seenShards.has(receipt.shardIndex)) fail(`duplicate shard receipt ${receipt.shardIndex}`);
+    seenShards.add(receipt.shardIndex);
+    if (
+      !/^[0-9a-f]{64}$/u.test(receipt.inputEnvelopeSha256) ||
+      !/^[0-9a-f]{64}$/u.test(receipt.proofLogSha256)
+    ) {
+      fail(`shard ${receipt.shardIndex} lacks input-envelope or proof-log SHA-256 evidence`);
+    }
+    inputDigests.add(receipt.inputEnvelopeSha256);
+    assertConsumedArtifacts(receipt.consumedArtifacts, expected, receipt.shardIndex);
+    const artifactJson = JSON.stringify(receipt.consumedArtifacts);
+    if (consumedArtifacts === undefined) consumedArtifacts = artifactJson;
+    else if (consumedArtifacts !== artifactJson)
+      fail('shard receipts consumed different artifact envelopes');
+    if (
+      receipt.modes.join(',') !== 'direct,broker,server' ||
+      receipt.lifecycle.join(',') !== 'install,load,restart,backup,restore'
+    ) {
+      fail(`shard ${receipt.shardIndex} has incomplete modes or lifecycle`);
+    }
+    const expectedShardExtensions = expected.filter(
+      (_, index) => index % expectedShardCount === receipt.shardIndex,
+    );
+    if (
+      receipt.plannedExtensionCount !== expected.length ||
+      receipt.extensionCount !== expectedShardExtensions.length ||
+      !Array.isArray(receipt.extensions) ||
+      receipt.extensions.join('\0') !== expectedShardExtensions.join('\0') ||
+      !Array.isArray(receipt.passRecords) ||
+      receipt.passRecords.length !== expectedShardExtensions.length
+    ) {
+      fail(`shard ${receipt.shardIndex} PASS record count drift`);
+    }
+    for (const [index, record] of receipt.passRecords.entries()) {
+      if (
+        record.shardIndex !== receipt.shardIndex ||
+        record.shardCount !== expectedShardCount ||
+        record.extension !== expectedShardExtensions[index] ||
+        record.modes?.join(',') !== 'direct,broker,server' ||
+        record.lifecycle?.join(',') !== 'install,load,restart,backup,restore'
+      )
+        fail(`shard ${receipt.shardIndex} has a malformed or misordered extension PASS record`);
+    }
+    for (const extension of receipt.extensions) {
+      if (seenExtensions.has(extension))
+        fail(`extension ${extension} appears in multiple shard receipts`);
+      seenExtensions.add(extension);
+    }
+  }
+  if (seenShards.size !== expectedShardCount || inputDigests.size !== 1) {
+    fail('shard receipts do not form one complete artifact-bound run');
+  }
+  const actual = [...seenExtensions].sort(compareText);
+  if (actual.length !== expected.length || actual.join('\0') !== expected.join('\0')) {
+    fail(
+      `aggregate extension coverage drift: expected=${expected.join(',')}; actual=${actual.join(',')}`,
+    );
+  }
+  const aggregateCore = {
+    schema: 'oliphaunt-native-extension-lifecycle-aggregate-v1',
+    candidateSha: options['candidate-sha'],
+    candidateTree: options['candidate-tree'],
+    target: 'linux-x64-gnu',
+    shardCount: expectedShardCount,
+    extensionCount: expected.length,
+    extensions: expected,
+    modes: ['direct', 'broker', 'server'],
+    lifecycle: ['install', 'load', 'restart', 'backup', 'restore'],
+    inputEnvelopeSha256: [...inputDigests][0],
+    consumedArtifacts: JSON.parse(consumedArtifacts),
+    shardReceipts: receipts
+      .map(({ receipt }) => ({
+        shardIndex: receipt.shardIndex,
+        receiptSha256: receipt.receiptSha256,
+      }))
+      .sort((left, right) => left.shardIndex - right.shardIndex),
+  };
+  const aggregate = { ...aggregateCore, aggregateSha256: sha256(JSON.stringify(aggregateCore)) };
+  writeFileSync(options.output, `${JSON.stringify(aggregate, null, 2)}\n`);
+  console.log(`native extension lifecycle aggregate verified: ${options.output}`);
+}
+
+if (import.meta.main) {
+  try {
+    verifyReceipts(flags(Bun.argv.slice(2)));
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(1);
+  }
+}
diff --git a/src/extensions/tests/native/tools/write-native-extension-lifecycle-receipt.mts b/src/extensions/tests/native/tools/write-native-extension-lifecycle-receipt.mts
new file mode 100644
index 000000000..50c108c14
--- /dev/null
+++ b/src/extensions/tests/native/tools/write-native-extension-lifecycle-receipt.mts
@@ -0,0 +1,194 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { readFileSync, writeFileSync } from 'node:fs';
+
+import {
+  compareText,
+  exactExtensionProducts,
+  extensionSqlNames,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+
+function fail(message) {
+  throw new Error(`write-native-extension-lifecycle-receipt.mts: ${message}`);
+}
+
+function flags(argv) {
+  const values = {};
+  for (let index = 0; index < argv.length; index += 2) {
+    const name = argv[index];
+    const value = argv[index + 1];
+    if (!name?.startsWith('--') || value === undefined) fail(`invalid argument ${name ?? ''}`);
+    values[name.slice(2)] = value;
+  }
+  for (const name of ['inputs', 'log', 'output', 'shard-index', 'shard-count']) {
+    if (values[name] === undefined) fail(`--${name} is required`);
+  }
+  return values;
+}
+
+function sha256(value) {
+  return createHash('sha256').update(value).digest('hex');
+}
+
+function canonicalExtensions() {
+  const names = exactExtensionProducts('write-native-extension-lifecycle-receipt.mts')
+    .flatMap((product) =>
+      extensionSqlNames(product, 'write-native-extension-lifecycle-receipt.mts'),
+    )
+    .sort(compareText);
+  if (names.length === 0 || new Set(names).size !== names.length) {
+    fail('canonical release graph must resolve to a nonempty unique extension set');
+  }
+  return names;
+}
+
+function verifyInputEnvelope(inputs) {
+  const { inputEnvelopeSha256, ...core } = inputs;
+  if (inputEnvelopeSha256 !== sha256(JSON.stringify(core))) fail('input envelope digest mismatch');
+  if (inputs.schema !== 'oliphaunt-native-extension-lifecycle-inputs-v1')
+    fail('unknown input envelope schema');
+  if (
+    !/^[0-9a-f]{40}$/u.test(inputs.candidateSha) ||
+    !/^[0-9a-f]{40}$/u.test(inputs.candidateTree)
+  ) {
+    fail('input candidate SHA and tree must be full Git object IDs');
+  }
+  if (inputs.target !== 'linux-x64-gnu') fail('input envelope must target canonical linux-x64-gnu');
+  const canonical = canonicalExtensions();
+  const selected = Array.isArray(inputs.extensions) ? inputs.extensions : [];
+  const canonicalSet = new Set(canonical);
+  if (
+    selected.length === 0 ||
+    inputs.extensionCount !== selected.length ||
+    new Set(selected).size !== selected.length ||
+    selected.some((name) => !canonicalSet.has(name)) ||
+    selected.join('\0') !== [...selected].sort(compareText).join('\0')
+  )
+    fail(
+      'input envelope extensions must be a nonempty unique sorted subset of the canonical release graph set',
+    );
+  if (inputs.modes?.join(',') !== 'direct,broker,server')
+    fail('input envelope has incomplete modes');
+  if (inputs.lifecycle?.join(',') !== 'install,load,restart,backup,restore') {
+    fail('input envelope has incomplete lifecycle');
+  }
+  const expectedIdentities = [
+    'broker',
+    'broker-checksum',
+    'native-extension-index',
+    'native-extension-legacy-index',
+    'native-extension-proof-runner',
+    'native-runtime',
+    'native-tools',
+    ...inputs.extensions.map((name) => `native-extension:${name}`),
+  ].sort();
+  if (
+    !Array.isArray(inputs.consumedArtifacts) ||
+    inputs.consumedArtifacts.length !== expectedIdentities.length
+  ) {
+    fail(`input envelope must enumerate all ${expectedIdentities.length} consumed artifacts`);
+  }
+  const actualIdentities = inputs.consumedArtifacts.map((artifact) => artifact?.identity);
+  if (actualIdentities.join('\0') !== expectedIdentities.join('\0')) {
+    fail('input envelope consumed artifact identities are incomplete or unsorted');
+  }
+  for (const artifact of inputs.consumedArtifacts) {
+    if (
+      typeof artifact.file !== 'string' ||
+      artifact.file.length === 0 ||
+      artifact.file.includes('/') ||
+      artifact.file.includes('\\') ||
+      !Number.isSafeInteger(artifact.bytes) ||
+      artifact.bytes <= 0 ||
+      !/^[0-9a-f]{64}$/u.test(artifact.sha256)
+    )
+      fail(
+        `consumed artifact ${String(artifact.identity)} lacks canonical file, byte, or SHA-256 evidence`,
+      );
+  }
+}
+
+export function writeReceipt(options) {
+  const inputs = JSON.parse(readFileSync(options.inputs, 'utf8'));
+  verifyInputEnvelope(inputs);
+  const plannedCount = inputs.extensions.length;
+  const log = readFileSync(options.log, 'utf8');
+  const shardIndex = Number(options['shard-index']);
+  const shardCount = Number(options['shard-count']);
+  if (
+    !Number.isInteger(shardIndex) ||
+    !Number.isInteger(shardCount) ||
+    shardCount < 1 ||
+    shardCount > plannedCount ||
+    shardIndex < 0 ||
+    shardIndex >= shardCount
+  ) {
+    fail(
+      `receipt requires a shard index in [0, ${Math.max(0, shardCount - 1)}] and no more shards than planned extensions`,
+    );
+  }
+  const expected = inputs.extensions.filter((_, index) => index % shardCount === shardIndex);
+  const passPattern =
+    /OLIPHAUNT_NATIVE_EXTENSION_PROOF_EXTENSION_PASS shard=(\d+)\/(\d+) extension=([^ ]+) modes=([^ ]+) lifecycle=([^\s]+)/gu;
+  const passRecords = [...log.matchAll(passPattern)].map((match) => ({
+    shardIndex: Number(match[1]),
+    shardCount: Number(match[2]),
+    extension: match[3],
+    modes: match[4].split(','),
+    lifecycle: match[5].split('-'),
+  }));
+  if (
+    passRecords.length !== expected.length ||
+    new Set(passRecords.map((row) => row.extension)).size !== passRecords.length
+  ) {
+    fail(`shard ${shardIndex} must contain ${expected.length} unique extension PASS records`);
+  }
+  for (const record of passRecords) {
+    if (record.shardIndex !== shardIndex || record.shardCount !== shardCount)
+      fail('extension PASS record has wrong shard identity');
+    if (record.modes.join(',') !== 'direct,broker,server')
+      fail(`${record.extension} PASS record has incomplete modes`);
+    if (record.lifecycle.join(',') !== 'install,load,restart,backup,restore')
+      fail(`${record.extension} PASS record has incomplete lifecycle`);
+  }
+  const actual = passRecords.map((row) => row.extension).sort();
+  if (actual.join('\0') !== [...expected].sort().join('\0')) {
+    fail(
+      `shard ${shardIndex} extension set drift: expected=${expected.join(',')}; actual=${actual.join(',')}`,
+    );
+  }
+  const finalMarker = `OLIPHAUNT_NATIVE_EXTENSION_PROOF_PASS shard=${shardIndex}/${shardCount} planned=${plannedCount} modes=direct,broker,server`;
+  if (log.split(finalMarker).length !== 2)
+    fail(`shard ${shardIndex} must contain exactly one final PASS marker`);
+
+  const receiptCore = {
+    schema: 'oliphaunt-native-extension-lifecycle-shard-receipt-v1',
+    candidateSha: inputs.candidateSha,
+    candidateTree: inputs.candidateTree,
+    target: inputs.target,
+    shardIndex,
+    shardCount,
+    plannedExtensionCount: plannedCount,
+    extensionCount: expected.length,
+    extensions: expected,
+    modes: inputs.modes,
+    lifecycle: inputs.lifecycle,
+    inputEnvelopeSha256: inputs.inputEnvelopeSha256,
+    consumedArtifacts: inputs.consumedArtifacts,
+    proofLogSha256: sha256(log),
+    passRecords,
+  };
+  const receipt = { ...receiptCore, receiptSha256: sha256(JSON.stringify(receiptCore)) };
+  writeFileSync(options.output, `${JSON.stringify(receipt, null, 2)}\n`);
+  console.log(`native extension lifecycle shard receipt written: ${options.output}`);
+}
+
+if (import.meta.main) {
+  try {
+    writeReceipt(flags(Bun.argv.slice(2)));
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(1);
+  }
+}
diff --git a/src/extensions/tools/android-extension-legal-catalog.mjs b/src/extensions/tools/android-extension-legal-catalog.mjs
deleted file mode 100644
index 1b036a872..000000000
--- a/src/extensions/tools/android-extension-legal-catalog.mjs
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/usr/bin/env node
-
-import { createHash } from "node:crypto";
-import {
-  readFileSync,
-  renameSync,
-  rmSync,
-  writeFileSync,
-} from "node:fs";
-import path from "node:path";
-import { fileURLToPath } from "node:url";
-
-import {
-  extensionCarrierLegalContract,
-  extensionCarrierLegalFileInventory,
-} from "../../../tools/release/extension-upstream-licenses.mjs";
-
-const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
-const INPUT = path.join(ROOT, "src/extensions/generated/sdk/extensions.json");
-const OUTPUT = path.join(
-  ROOT,
-  "src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json",
-);
-const SCHEMA = "oliphaunt-android-extension-legal-catalog-v1";
-const TARGETS = Object.freeze(["android-arm64-v8a", "android-x86_64"]);
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function fail(message) {
-  throw new Error(`android-extension-legal-catalog: ${message}`);
-}
-
-function canonicalMetadata(metadata) {
-  if (
-    metadata === null
-    || typeof metadata !== "object"
-    || Array.isArray(metadata)
-    || metadata["format-version"] !== 1
-    || typeof metadata["extension-catalog-sha256"] !== "string"
-    || !/^[0-9a-f]{64}$/u.test(metadata["extension-catalog-sha256"])
-    || !Array.isArray(metadata.extensions)
-    || metadata.extensions.length === 0
-  ) {
-    fail("generated Kotlin metadata is malformed");
-  }
-  const rows = metadata.extensions.map((row, index) => {
-    const sqlName = row?.["sql-name"];
-    const product = row?.["artifact-product"];
-    if (
-      typeof sqlName !== "string"
-      || !/^[A-Za-z0-9._-]{1,128}$/u.test(sqlName)
-      || typeof product !== "string"
-      || !/^oliphaunt-extension-[A-Za-z0-9._-]+$/u.test(product)
-    ) {
-      fail(`generated extension row ${index} is not a supported package contract`);
-    }
-    return Object.freeze({ sqlName, product });
-  });
-  const sorted = [...rows].sort((left, right) => compareText(left.sqlName, right.sqlName));
-  if (
-    JSON.stringify(rows) !== JSON.stringify(sorted)
-    || new Set(rows.map(({ sqlName }) => sqlName)).size !== rows.length
-  ) {
-    fail("generated Kotlin extension rows must be sorted and unique by SQL name");
-  }
-  return Object.freeze({
-    sourceCatalogSha256: metadata["extension-catalog-sha256"],
-    rows: Object.freeze(rows),
-  });
-}
-
-function legalMembers(product, sqlNames, target, scope) {
-  const files = extensionCarrierLegalFileInventory(product, sqlNames, {
-    family: "native",
-    target,
-  });
-  return files.map((file) => Object.freeze({
-    path: scope === "leaf" && file.path.startsWith("share/licenses/")
-      ? `files/${file.path}`
-      : file.path,
-    bytes: file.bytes,
-    sha256: file.sha256,
-    mode: file.mode,
-  })).sort((left, right) => compareText(left.path, right.path));
-}
-
-function contract(scope, identity, product, sqlNames, target) {
-  const legal = extensionCarrierLegalContract(product, sqlNames, {
-    family: "native",
-    target,
-  });
-  return Object.freeze({
-    scope,
-    identity,
-    product,
-    target,
-    profile: legal.profile,
-    licenseFiles: [...legal.licenseFiles],
-    members: legalMembers(product, sqlNames, target, scope),
-  });
-}
-
-export function androidExtensionLegalCatalog(metadata) {
-  const checked = canonicalMetadata(metadata);
-  const products = new Map();
-  for (const row of checked.rows) {
-    const members = products.get(row.product) ?? [];
-    members.push(row.sqlName);
-    products.set(row.product, members);
-  }
-
-  const contracts = [];
-  for (const [product, sqlNames] of [...products].sort(([left], [right]) => compareText(left, right))) {
-    for (const target of TARGETS) {
-      contracts.push(contract("aggregate", product, product, sqlNames, target));
-    }
-  }
-  for (const { sqlName, product } of checked.rows) {
-    for (const target of TARGETS) {
-      contracts.push(contract("leaf", sqlName, product, [sqlName], target));
-    }
-  }
-  contracts.sort((left, right) => compareText(
-    `${left.scope}\0${left.identity}\0${left.target}`,
-    `${right.scope}\0${right.identity}\0${right.target}`,
-  ));
-  return Object.freeze({
-    schema: SCHEMA,
-    sourceCatalogSha256: checked.sourceCatalogSha256,
-    contracts: Object.freeze(contracts),
-  });
-}
-
-export function androidExtensionLegalCatalogText(metadata) {
-  return `${JSON.stringify(androidExtensionLegalCatalog(metadata), null, 2)}\n`;
-}
-
-export function readAndroidExtensionLegalCatalogMetadata() {
-  let metadata;
-  try {
-    metadata = JSON.parse(readFileSync(INPUT, "utf8"));
-  } catch (cause) {
-    fail(`cannot read ${path.relative(ROOT, INPUT)}: ${cause.message}`);
-  }
-  return metadata;
-}
-
-export function checkAndroidExtensionLegalCatalog({ write = false } = {}) {
-  const expected = androidExtensionLegalCatalogText(readAndroidExtensionLegalCatalogMetadata());
-  if (write) {
-    const temporary = `${OUTPUT}.tmp-${process.pid}`;
-    try {
-      writeFileSync(temporary, expected, { encoding: "utf8", mode: 0o644 });
-      renameSync(temporary, OUTPUT);
-    } finally {
-      rmSync(temporary, { force: true });
-    }
-    return;
-  }
-  let actual;
-  try {
-    actual = readFileSync(OUTPUT, "utf8");
-  } catch (cause) {
-    fail(`${path.relative(ROOT, OUTPUT)} is missing: ${cause.message}`);
-  }
-  if (actual !== expected) {
-    const expectedDigest = createHash("sha256").update(expected).digest("hex");
-    const actualDigest = createHash("sha256").update(actual).digest("hex");
-    fail(
-      `${path.relative(ROOT, OUTPUT)} is stale (expected ${expectedDigest}, got ${actualDigest}); `
-      + "run tools/dev/bun.sh src/extensions/tools/check-extension-model.mjs --write",
-    );
-  }
-}
-
-function parseArgs(argv) {
-  if (argv.length > 1 || (argv.length === 1 && !["--check", "--write"].includes(argv[0]))) {
-    fail("usage: android-extension-legal-catalog.mjs [--check|--write]");
-  }
-  return { write: argv[0] === "--write" };
-}
-
-if (import.meta.main) {
-  try {
-    checkAndroidExtensionLegalCatalog(parseArgs(Bun.argv.slice(2)));
-    console.log("Android extension legal catalog is current");
-  } catch (cause) {
-    console.error(cause.message);
-    process.exitCode = 1;
-  }
-}
diff --git a/src/extensions/tools/android-extension-legal-catalog.mts b/src/extensions/tools/android-extension-legal-catalog.mts
new file mode 100644
index 000000000..e08db234f
--- /dev/null
+++ b/src/extensions/tools/android-extension-legal-catalog.mts
@@ -0,0 +1,197 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import {
+  extensionCarrierLegalContract,
+  extensionCarrierLegalFileInventory,
+} from './extension-upstream-licenses.mts';
+
+const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
+const INPUT = path.join(ROOT, 'src/extensions/generated/sdk/extensions.json');
+const OUTPUT = path.join(
+  ROOT,
+  'src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json',
+);
+const SCHEMA = 'oliphaunt-android-extension-legal-catalog-v1';
+const TARGETS = Object.freeze(['android-arm64-v8a', 'android-x86_64']);
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function fail(message) {
+  throw new Error(`android-extension-legal-catalog: ${message}`);
+}
+
+function canonicalMetadata(metadata) {
+  if (
+    metadata === null ||
+    typeof metadata !== 'object' ||
+    Array.isArray(metadata) ||
+    metadata['format-version'] !== 1 ||
+    typeof metadata['extension-catalog-sha256'] !== 'string' ||
+    !/^[0-9a-f]{64}$/u.test(metadata['extension-catalog-sha256']) ||
+    !Array.isArray(metadata.extensions) ||
+    metadata.extensions.length === 0
+  ) {
+    fail('generated Kotlin metadata is malformed');
+  }
+  const rows = metadata.extensions.map((row, index) => {
+    const sqlName = row?.['sql-name'];
+    const product = row?.['artifact-product'];
+    if (
+      typeof sqlName !== 'string' ||
+      !/^[A-Za-z0-9._-]{1,128}$/u.test(sqlName) ||
+      typeof product !== 'string' ||
+      !/^oliphaunt-extension-[A-Za-z0-9._-]+$/u.test(product)
+    ) {
+      fail(`generated extension row ${index} is not a supported package contract`);
+    }
+    return Object.freeze({ sqlName, product });
+  });
+  const sorted = [...rows].sort((left, right) => compareText(left.sqlName, right.sqlName));
+  if (
+    JSON.stringify(rows) !== JSON.stringify(sorted) ||
+    new Set(rows.map(({ sqlName }) => sqlName)).size !== rows.length
+  ) {
+    fail('generated Kotlin extension rows must be sorted and unique by SQL name');
+  }
+  return Object.freeze({
+    sourceCatalogSha256: metadata['extension-catalog-sha256'],
+    rows: Object.freeze(rows),
+  });
+}
+
+function legalMembers(product, sqlNames, target, scope) {
+  const files = extensionCarrierLegalFileInventory(product, sqlNames, {
+    family: 'native',
+    target,
+  });
+  return files
+    .map((file) =>
+      Object.freeze({
+        path:
+          scope === 'leaf' && file.path.startsWith('share/licenses/')
+            ? `files/${file.path}`
+            : file.path,
+        bytes: file.bytes,
+        sha256: file.sha256,
+        mode: file.mode,
+      }),
+    )
+    .sort((left, right) => compareText(left.path, right.path));
+}
+
+function contract(scope, identity, product, sqlNames, target) {
+  const legal = extensionCarrierLegalContract(product, sqlNames, {
+    family: 'native',
+    target,
+  });
+  return Object.freeze({
+    scope,
+    identity,
+    product,
+    target,
+    profile: legal.profile,
+    licenseFiles: [...legal.licenseFiles],
+    members: legalMembers(product, sqlNames, target, scope),
+  });
+}
+
+export function androidExtensionLegalCatalog(metadata) {
+  const checked = canonicalMetadata(metadata);
+  const products = new Map();
+  for (const row of checked.rows) {
+    const members = products.get(row.product) ?? [];
+    members.push(row.sqlName);
+    products.set(row.product, members);
+  }
+
+  const contracts = [];
+  for (const [product, sqlNames] of [...products].sort(([left], [right]) =>
+    compareText(left, right),
+  )) {
+    for (const target of TARGETS) {
+      contracts.push(contract('aggregate', product, product, sqlNames, target));
+    }
+  }
+  for (const { sqlName, product } of checked.rows) {
+    for (const target of TARGETS) {
+      contracts.push(contract('leaf', sqlName, product, [sqlName], target));
+    }
+  }
+  contracts.sort((left, right) =>
+    compareText(
+      `${left.scope}\0${left.identity}\0${left.target}`,
+      `${right.scope}\0${right.identity}\0${right.target}`,
+    ),
+  );
+  return Object.freeze({
+    schema: SCHEMA,
+    sourceCatalogSha256: checked.sourceCatalogSha256,
+    contracts: Object.freeze(contracts),
+  });
+}
+
+export function androidExtensionLegalCatalogText(metadata) {
+  return `${JSON.stringify(androidExtensionLegalCatalog(metadata), null, 2)}\n`;
+}
+
+export function readAndroidExtensionLegalCatalogMetadata() {
+  let metadata;
+  try {
+    metadata = JSON.parse(readFileSync(INPUT, 'utf8'));
+  } catch (cause) {
+    fail(`cannot read ${path.relative(ROOT, INPUT)}: ${cause.message}`);
+  }
+  return metadata;
+}
+
+export function checkAndroidExtensionLegalCatalog({ write = false } = {}) {
+  const expected = androidExtensionLegalCatalogText(readAndroidExtensionLegalCatalogMetadata());
+  if (write) {
+    const temporary = `${OUTPUT}.tmp-${process.pid}`;
+    try {
+      writeFileSync(temporary, expected, { encoding: 'utf8', mode: 0o644 });
+      renameSync(temporary, OUTPUT);
+    } finally {
+      rmSync(temporary, { force: true });
+    }
+    return;
+  }
+  let actual;
+  try {
+    actual = readFileSync(OUTPUT, 'utf8');
+  } catch (cause) {
+    fail(`${path.relative(ROOT, OUTPUT)} is missing: ${cause.message}`);
+  }
+  if (actual !== expected) {
+    const expectedDigest = createHash('sha256').update(expected).digest('hex');
+    const actualDigest = createHash('sha256').update(actual).digest('hex');
+    fail(
+      `${path.relative(ROOT, OUTPUT)} is stale (expected ${expectedDigest}, got ${actualDigest}); ` +
+        'run bash src/extensions/tools/check-extension-model.sh --write',
+    );
+  }
+}
+
+function parseArgs(argv) {
+  if (argv.length > 1 || (argv.length === 1 && !['--check', '--write'].includes(argv[0]))) {
+    fail('usage: android-extension-legal-catalog.mts [--check|--write]');
+  }
+  return { write: argv[0] === '--write' };
+}
+
+if (import.meta.main) {
+  try {
+    checkAndroidExtensionLegalCatalog(parseArgs(Bun.argv.slice(2)));
+    console.log('Android extension legal catalog is current');
+  } catch (cause) {
+    console.error(cause.message);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/extensions/tools/android-extension-legal-catalog.test.mjs b/src/extensions/tools/android-extension-legal-catalog.test.mjs
deleted file mode 100644
index 4457e2743..000000000
--- a/src/extensions/tools/android-extension-legal-catalog.test.mjs
+++ /dev/null
@@ -1,139 +0,0 @@
-import assert from "node:assert/strict";
-import test from "node:test";
-
-import {
-  androidExtensionLegalCatalog,
-  androidExtensionLegalCatalogText,
-  checkAndroidExtensionLegalCatalog,
-  readAndroidExtensionLegalCatalogMetadata,
-} from "./android-extension-legal-catalog.mjs";
-
-function clone(value) {
-  return structuredClone(value);
-}
-
-function findContract(catalog, scope, identity, target = "android-arm64-v8a") {
-  const contract = catalog.contracts.find((candidate) => (
-    candidate.scope === scope
-    && candidate.identity === identity
-    && candidate.target === target
-  ));
-  assert.ok(contract, `missing ${scope} ${identity} ${target}`);
-  return contract;
-}
-
-function withoutTarget(contract) {
-  const { target: _target, ...rest } = contract;
-  return rest;
-}
-
-test("Android legal catalog is deterministic, complete, and current", () => {
-  const metadata = readAndroidExtensionLegalCatalogMetadata();
-  const first = androidExtensionLegalCatalog(metadata);
-  const second = androidExtensionLegalCatalog(clone(metadata));
-
-  assert.deepEqual(second, first);
-  assert.equal(androidExtensionLegalCatalogText(metadata), androidExtensionLegalCatalogText(metadata));
-  assert.equal(first.schema, "oliphaunt-android-extension-legal-catalog-v1");
-  assert.equal(first.sourceCatalogSha256, metadata["extension-catalog-sha256"]);
-
-  const products = new Set(metadata.extensions.map((row) => row["release-product"]));
-  assert.equal(metadata.extensions.length, 39);
-  assert.equal(products.size, 8);
-  assert.equal(first.contracts.length, (metadata.extensions.length + products.size) * 2);
-  assert.equal(first.contracts.filter(({ scope }) => scope === "leaf").length, 78);
-  assert.equal(first.contracts.filter(({ scope }) => scope === "aggregate").length, 16);
-
-  const keys = first.contracts.map(({ scope, identity, target }) => `${scope}\0${identity}\0${target}`);
-  assert.deepEqual(keys, [...keys].sort());
-  assert.equal(new Set(keys).size, keys.length);
-  checkAndroidExtensionLegalCatalog();
-});
-
-test("Android legal contracts retain contrib, OpenSSL, and external closures", () => {
-  const catalog = androidExtensionLegalCatalog(readAndroidExtensionLegalCatalogMetadata());
-  const cube = findContract(catalog, "leaf", "cube");
-  assert.equal(cube.profile, "contrib-native");
-  assert.deepEqual(cube.licenseFiles, []);
-  assert.deepEqual(cube.members.map(({ path }) => path), [
-    "LICENSE",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "THIRD_PARTY_NOTICES.md",
-  ]);
-
-  const pgcrypto = findContract(catalog, "leaf", "pgcrypto");
-  assert.equal(pgcrypto.profile, "contrib-native-openssl");
-  assert.deepEqual(pgcrypto.licenseFiles, []);
-  assert.deepEqual(pgcrypto.members.map(({ path }) => path), [
-    "LICENSE",
-    "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "THIRD_PARTY_NOTICES.md",
-  ]);
-
-  const contrib = findContract(catalog, "aggregate", "oliphaunt-extension-contrib-pg18");
-  assert.equal(contrib.profile, "contrib-native-openssl");
-  assert.deepEqual(contrib.members.map(({ path }) => path), [
-    "LICENSE",
-    "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "THIRD_PARTY_NOTICES.md",
-  ]);
-
-  const postgis = findContract(catalog, "leaf", "postgis");
-  assert.equal(postgis.profile, "external-native");
-  assert.equal(postgis.licenseFiles.length, 16);
-  assert.equal(postgis.members.length, 18);
-  assert.equal(
-    postgis.members.filter(({ path }) => path.startsWith("files/share/licenses/")).length,
-    16,
-  );
-  assert.deepEqual(
-    findContract(catalog, "aggregate", "oliphaunt-extension-postgis").licenseFiles,
-    postgis.licenseFiles,
-  );
-});
-
-test("every Android legal member is canonical and both ABIs are identical", () => {
-  const catalog = androidExtensionLegalCatalog(readAndroidExtensionLegalCatalogMetadata());
-  for (const contract of catalog.contracts) {
-    assert.ok(["contrib-native", "contrib-native-openssl", "external-native"].includes(contract.profile));
-    assert.deepEqual(contract.licenseFiles, [...contract.licenseFiles].sort());
-    assert.equal(new Set(contract.licenseFiles).size, contract.licenseFiles.length);
-    assert.deepEqual(contract.members.map(({ path }) => path), contract.members.map(({ path }) => path).sort());
-    assert.equal(new Set(contract.members.map(({ path }) => path)).size, contract.members.length);
-    for (const member of contract.members) {
-      assert.deepEqual(Object.keys(member), ["path", "bytes", "sha256", "mode"]);
-      assert.equal(Number.isSafeInteger(member.bytes) && member.bytes > 0, true);
-      assert.match(member.sha256, /^[0-9a-f]{64}$/u);
-      assert.equal(member.mode, "0644");
-      assert.equal(member.path.startsWith("/") || member.path.includes("..") || member.path.includes("\\"), false);
-    }
-  }
-
-  const armContracts = catalog.contracts.filter(({ target }) => target === "android-arm64-v8a");
-  for (const arm of armContracts) {
-    const x86 = findContract(catalog, arm.scope, arm.identity, "android-x86_64");
-    assert.deepEqual(withoutTarget(x86), withoutTarget(arm));
-  }
-});
-
-test("malformed generated Kotlin metadata cannot produce an Android legal catalog", () => {
-  const metadata = readAndroidExtensionLegalCatalogMetadata();
-
-  const reversed = clone(metadata);
-  reversed.extensions.reverse();
-  assert.throws(() => androidExtensionLegalCatalog(reversed), /sorted and unique/u);
-
-  const duplicate = clone(metadata);
-  duplicate.extensions = [duplicate.extensions[0], clone(duplicate.extensions[0])];
-  assert.throws(() => androidExtensionLegalCatalog(duplicate), /sorted and unique/u);
-
-  const invalidProduct = clone(metadata);
-  invalidProduct.extensions[0]["artifact-product"] = "invalid";
-  assert.throws(() => androidExtensionLegalCatalog(invalidProduct), /not a supported package contract/u);
-
-  const invalidDigest = clone(metadata);
-  invalidDigest["extension-catalog-sha256"] = "not-a-digest";
-  assert.throws(() => androidExtensionLegalCatalog(invalidDigest), /metadata is malformed/u);
-});
diff --git a/src/extensions/tools/android-extension-legal-catalog.test.mts b/src/extensions/tools/android-extension-legal-catalog.test.mts
new file mode 100644
index 000000000..5d55c6b29
--- /dev/null
+++ b/src/extensions/tools/android-extension-legal-catalog.test.mts
@@ -0,0 +1,152 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+
+import {
+  androidExtensionLegalCatalog,
+  checkAndroidExtensionLegalCatalog,
+  readAndroidExtensionLegalCatalogMetadata,
+} from './android-extension-legal-catalog.mts';
+
+function clone(value) {
+  return structuredClone(value);
+}
+
+function findContract(catalog, scope, identity, target = 'android-arm64-v8a') {
+  const contract = catalog.contracts.find(
+    (candidate) =>
+      candidate.scope === scope && candidate.identity === identity && candidate.target === target,
+  );
+  assert.ok(contract, `missing ${scope} ${identity} ${target}`);
+  return contract;
+}
+
+function withoutTarget(contract) {
+  const { target: _target, ...rest } = contract;
+  return rest;
+}
+
+test('Android legal catalog is deterministic, complete, and current', () => {
+  const metadata = readAndroidExtensionLegalCatalogMetadata();
+  const first = androidExtensionLegalCatalog(metadata);
+  const second = androidExtensionLegalCatalog(clone(metadata));
+
+  assert.deepEqual(second, first);
+  assert.equal(first.schema, 'oliphaunt-android-extension-legal-catalog-v1');
+  assert.equal(first.sourceCatalogSha256, metadata['extension-catalog-sha256']);
+
+  const keys = first.contracts.map(
+    ({ scope, identity, target }) => `${scope}\0${identity}\0${target}`,
+  );
+  const products = new Set(metadata.extensions.map((row) => row['artifact-product']));
+  const expected = ['android-arm64-v8a', 'android-x86_64'].flatMap((target) => [
+    ...metadata.extensions.map((row) => `leaf\0${row['sql-name']}\0${target}`),
+    ...[...products].map((product) => `aggregate\0${product}\0${target}`),
+  ]);
+  assert.deepEqual(keys, expected.sort());
+  checkAndroidExtensionLegalCatalog();
+});
+
+test('Android legal contracts retain contrib, OpenSSL, and external closures', () => {
+  const catalog = androidExtensionLegalCatalog(readAndroidExtensionLegalCatalogMetadata());
+  const cube = findContract(catalog, 'leaf', 'cube');
+  assert.equal(cube.profile, 'contrib-native');
+  assert.deepEqual(cube.licenseFiles, []);
+  assert.deepEqual(
+    cube.members.map(({ path }) => path),
+    ['LICENSE', 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', 'THIRD_PARTY_NOTICES.md'],
+  );
+
+  const pgcrypto = findContract(catalog, 'leaf', 'pgcrypto');
+  assert.equal(pgcrypto.profile, 'contrib-native-openssl');
+  assert.deepEqual(pgcrypto.licenseFiles, []);
+  assert.deepEqual(
+    pgcrypto.members.map(({ path }) => path),
+    [
+      'LICENSE',
+      'THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt',
+      'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT',
+      'THIRD_PARTY_NOTICES.md',
+    ],
+  );
+
+  const contrib = findContract(catalog, 'aggregate', 'oliphaunt-extension-contrib-pg18');
+  assert.equal(contrib.profile, 'contrib-native-openssl');
+  assert.deepEqual(
+    contrib.members.map(({ path }) => path),
+    [
+      'LICENSE',
+      'THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt',
+      'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT',
+      'THIRD_PARTY_NOTICES.md',
+    ],
+  );
+
+  const postgis = findContract(catalog, 'leaf', 'postgis');
+  assert.equal(postgis.profile, 'external-native');
+  assert.ok(postgis.licenseFiles.length > 0);
+  assert.deepEqual(
+    postgis.members
+      .filter(({ path }) => path.startsWith('files/share/licenses/'))
+      .map(({ path }) => path.slice('files/'.length)),
+    postgis.licenseFiles,
+  );
+  assert.deepEqual(
+    findContract(catalog, 'aggregate', 'oliphaunt-extension-postgis').licenseFiles,
+    postgis.licenseFiles,
+  );
+});
+
+test('every Android legal member is canonical and both ABIs are identical', () => {
+  const catalog = androidExtensionLegalCatalog(readAndroidExtensionLegalCatalogMetadata());
+  for (const contract of catalog.contracts) {
+    assert.ok(
+      ['contrib-native', 'contrib-native-openssl', 'external-native'].includes(contract.profile),
+    );
+    assert.deepEqual(contract.licenseFiles, [...contract.licenseFiles].sort());
+    assert.equal(new Set(contract.licenseFiles).size, contract.licenseFiles.length);
+    assert.deepEqual(
+      contract.members.map(({ path }) => path),
+      contract.members.map(({ path }) => path).sort(),
+    );
+    assert.equal(new Set(contract.members.map(({ path }) => path)).size, contract.members.length);
+    for (const member of contract.members) {
+      assert.deepEqual(Object.keys(member), ['path', 'bytes', 'sha256', 'mode']);
+      assert.equal(Number.isSafeInteger(member.bytes) && member.bytes > 0, true);
+      assert.match(member.sha256, /^[0-9a-f]{64}$/u);
+      assert.equal(member.mode, '0644');
+      assert.equal(
+        member.path.startsWith('/') || member.path.includes('..') || member.path.includes('\\'),
+        false,
+      );
+    }
+  }
+
+  const armContracts = catalog.contracts.filter(({ target }) => target === 'android-arm64-v8a');
+  for (const arm of armContracts) {
+    const x86 = findContract(catalog, arm.scope, arm.identity, 'android-x86_64');
+    assert.deepEqual(withoutTarget(x86), withoutTarget(arm));
+  }
+});
+
+test('malformed generated Kotlin metadata cannot produce an Android legal catalog', () => {
+  const metadata = readAndroidExtensionLegalCatalogMetadata();
+
+  const reversed = clone(metadata);
+  reversed.extensions.reverse();
+  assert.throws(() => androidExtensionLegalCatalog(reversed), /sorted and unique/u);
+
+  const duplicate = clone(metadata);
+  duplicate.extensions = [duplicate.extensions[0], clone(duplicate.extensions[0])];
+  assert.throws(() => androidExtensionLegalCatalog(duplicate), /sorted and unique/u);
+
+  const invalidProduct = clone(metadata);
+  invalidProduct.extensions[0]['artifact-product'] = 'invalid';
+  assert.throws(
+    () => androidExtensionLegalCatalog(invalidProduct),
+    /not a supported package contract/u,
+  );
+
+  const invalidDigest = clone(metadata);
+  invalidDigest['extension-catalog-sha256'] = 'not-a-digest';
+  assert.throws(() => androidExtensionLegalCatalog(invalidDigest), /metadata is malformed/u);
+});
diff --git a/src/extensions/tools/check-extension-model.mjs b/src/extensions/tools/check-extension-model.mjs
deleted file mode 100755
index f96179f09..000000000
--- a/src/extensions/tools/check-extension-model.mjs
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env bun
-import { spawnSync } from "node:child_process";
-import { fileURLToPath } from "node:url";
-
-import { checkAndroidExtensionLegalCatalog } from "./android-extension-legal-catalog.mjs";
-
-const TOOL = "check-extension-model.mjs";
-const ROOT = fileURLToPath(new URL("../../..", import.meta.url));
-
-const result = spawnSync("python3", [
-  "src/extensions/tools/check-extension-model.py",
-  ...Bun.argv.slice(2),
-], {
-  cwd: ROOT,
-  stdio: "inherit",
-});
-
-if (result.error !== undefined) {
-  console.error(`${TOOL}: ${result.error.message}`);
-  process.exit(1);
-}
-
-if (result.status !== 0) {
-  process.exit(result.status ?? 1);
-}
-
-try {
-  checkAndroidExtensionLegalCatalog({ write: Bun.argv.slice(2).includes("--write") });
-} catch (cause) {
-  console.error(`${TOOL}: ${cause.message}`);
-  process.exit(1);
-}
diff --git a/src/extensions/tools/check-extension-model.mts b/src/extensions/tools/check-extension-model.mts
new file mode 100755
index 000000000..1b05328b0
--- /dev/null
+++ b/src/extensions/tools/check-extension-model.mts
@@ -0,0 +1,104 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { mkdirSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { parseArgs } from 'node:util';
+import {
+  catalogProjections,
+  discoverCatalog,
+  extensionProjections,
+  jsonText,
+  readJson,
+} from './extension-projections.mts';
+import {
+  currentEvidenceTable,
+  evidenceMatrix,
+  evidenceMatrixPath,
+  evidenceRunsPath,
+  evidenceTablePath,
+  recordedEvidence,
+  sourceDigestInputs,
+} from './extension-evidence.mts';
+
+const { values } = parseArgs({
+  args: Bun.argv.slice(2),
+  options: {
+    stage: { type: 'string' },
+    'release-metadata': { type: 'string' },
+    'source-inputs': { type: 'boolean' },
+    'source-commit': { type: 'string' },
+    'source-tree': { type: 'string' },
+    'clean-inputs': { type: 'boolean' },
+    write: { type: 'boolean' },
+    check: { type: 'boolean' },
+    'write-evidence': { type: 'boolean' },
+    'write-evidence-summary': { type: 'boolean' },
+    'require-current-evidence': { type: 'boolean' },
+    'record-wasix-evidence-run': { type: 'string' },
+    'observed-at': { type: 'string' },
+  },
+  strict: true,
+});
+if (values['source-inputs']) {
+  console.log(sourceDigestInputs().join('\n'));
+} else {
+  assert(
+    values.stage && values['release-metadata'],
+    'run bash src/extensions/tools/check-extension-model.sh',
+  );
+  assert(
+    [
+      values.write,
+      values['write-evidence'],
+      values['write-evidence-summary'],
+      values['record-wasix-evidence-run'],
+    ].filter(Boolean).length <= 1,
+    'mutation modes are mutually exclusive',
+  );
+  const identity = { commit: values['source-commit'] ?? '', tree: values['source-tree'] ?? '' };
+  assert(
+    /^[0-9a-f]{40}$/.test(identity.commit) && /^[0-9a-f]{40}$/.test(identity.tree),
+    'missing checkout commit/tree',
+  );
+  const catalog = discoverCatalog();
+  const outputs = new Map([
+    ...catalogProjections(catalog),
+    ...extensionProjections(catalog, readJson(values['release-metadata']) as any),
+  ]);
+  if (values.write || values['write-evidence'] || values['record-wasix-evidence-run'])
+    outputs.set(evidenceMatrixPath, evidenceMatrix(catalog));
+  const matrix = outputs.has(evidenceMatrixPath)
+    ? Bun.TOML.parse(outputs.get(evidenceMatrixPath)!)
+    : undefined;
+  const extraRuns = [];
+  if (values['record-wasix-evidence-run']) {
+    assert(values['observed-at'], 'recording requires --observed-at');
+    const file = `${evidenceRunsPath}/${values['record-wasix-evidence-run']}.json`;
+    const run = recordedEvidence(
+      catalog,
+      values['record-wasix-evidence-run'],
+      values['observed-at'],
+      identity,
+      values['clean-inputs'] ?? false,
+    );
+    outputs.set(file, jsonText(run));
+    extraRuns.push({ path: file, run });
+  } else assert(!values['observed-at'], '--observed-at requires recording');
+  outputs.set(
+    evidenceTablePath,
+    currentEvidenceTable(
+      catalog,
+      identity,
+      values['require-current-evidence'],
+      matrix,
+      outputs,
+      extraRuns,
+    ),
+  );
+  for (const [file, text] of outputs) {
+    const destination = path.join(values.stage, file);
+    mkdirSync(path.dirname(destination), { recursive: true });
+    writeFileSync(destination, text);
+    console.log(file);
+  }
+}
diff --git a/src/extensions/tools/check-extension-model.py b/src/extensions/tools/check-extension-model.py
deleted file mode 100755
index 856edfb3d..000000000
--- a/src/extensions/tools/check-extension-model.py
+++ /dev/null
@@ -1,2659 +0,0 @@
-#!/usr/bin/env python3
-from __future__ import annotations
-
-import argparse
-import hashlib
-import json
-import os
-import re
-import shutil
-import subprocess
-import tomllib
-from functools import lru_cache
-from pathlib import Path
-from tempfile import TemporaryDirectory
-
-ROOT = Path(__file__).resolve().parents[3]
-
-SOURCE_CATALOG = ROOT / "src/extensions/catalog/extensions.source.json"
-CATALOG = ROOT / "src/extensions/generated/extensions.catalog.json"
-NATIVE_COMPONENT_CONTRACT = ROOT / "src/extensions/catalog/native-components.toml"
-NATIVE_COMPONENT_TOOL = ROOT / "src/extensions/tools/native-component-contract.mjs"
-CONTRIB_RECIPE = ROOT / "src/extensions/contrib/postgres18.toml"
-RECIPE_SCHEMA = ROOT / "src/extensions/schemas/recipe.schema.json"
-EVIDENCE_MATRIX = ROOT / "src/extensions/evidence/matrix.toml"
-EVIDENCE_RUN_SCHEMA = ROOT / "src/extensions/evidence/schemas/run.schema.json"
-EVIDENCE_MATRIX_SCHEMA = ROOT / "src/extensions/evidence/schemas/matrix.schema.json"
-EVIDENCE_RUNS = ROOT / "src/extensions/evidence/runs"
-EVIDENCE_TABLE = ROOT / "src/extensions/generated/docs/extension-evidence.json"
-THIRD_PARTY_ROOT = ROOT / "src/sources/third-party"
-PRODUCTION_THIRD_PARTY_DOMAINS = ("shared", "native")
-EXTENSIONS_ROOT = ROOT / "src/extensions"
-EXTERNAL_ROOT = EXTENSIONS_ROOT / "external"
-SMOKE_RECIPE_ROOT = ROOT / "src/shared/fixtures/extensions"
-SMOKE_RECIPE_MANIFEST = SMOKE_RECIPE_ROOT / "manifest.json"
-EXTENSION_ENVELOPE_FILENAMES = {
-    "CHANGELOG.md",
-    "VERSION",
-    "moon.yml",
-    "release.toml",
-}
-OBSOLETE_EXTENSION_FILENAMES = {
-    "artifacts.toml",
-    "blockers.toml",
-    "publication-blocker.toml",
-}
-GENERATED_SDK_METADATA = ROOT / "src/extensions/generated/sdk/extensions.json"
-GENERATED_IOS_STATIC_DEPENDENCIES = (
-    ROOT / "src/extensions/generated/sdk/ios-static-dependencies.json"
-)
-OBSOLETE_GENERATED_FILES = (
-    ROOT / "src/extensions/generated/extensions.build-plan.json",
-    ROOT / "src/extensions/generated/sdk/js.json",
-    ROOT / "src/extensions/generated/sdk/kotlin.json",
-    ROOT / "src/extensions/generated/sdk/react-native.json",
-    ROOT / "src/extensions/generated/sdk/rust.json",
-    ROOT / "src/extensions/generated/sdk/swift.json",
-    ROOT / "src/sdks/kotlin/oliphaunt/src/generated/extensions.json",
-    ROOT / "src/sdks/react-native/src/generated/extensions.json",
-)
-GENERATED_RUST_SDK_MODULE = ROOT / "src/sdks/rust/src/generated/extensions.rs"
-GENERATED_TS_SDK_MODULE = ROOT / "src/sdks/js/src/generated/extensions.ts"
-GENERATED_KOTLIN_SDK_MODULE = ROOT / "src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt"
-GENERATED_KOTLIN_GRADLE_PLUGIN_CATALOG = (
-    ROOT
-    / "src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties"
-)
-GENERATED_RN_SDK_MODULE = ROOT / "src/sdks/react-native/src/generated/extensions.ts"
-GENERATED_MOBILE_SMOKE_MODULE = (
-    ROOT / "examples/react-native-expo/src/generated/extension-smoke.ts"
-)
-GENERATED_MOBILE_REGISTRY = ROOT / "src/extensions/generated/mobile/static-registry.json"
-GENERATED_MOBILE_STATIC_SPECS = ROOT / "src/extensions/generated/mobile/static-extensions.tsv"
-GENERATED_WASIX_METADATA = ROOT / "src/extensions/generated/wasix/extensions.json"
-BIOME_VERSION = "2.4.16"
-CHECK_EXTENSION_MODEL_PATH = "src/extensions/tools/check-extension-model.mjs"
-CHECK_EXTENSION_MODEL_COMMAND = f"tools/dev/bun.sh {CHECK_EXTENSION_MODEL_PATH}"
-CHECK_EXTENSION_MODEL_WRITE_COMMAND = f"{CHECK_EXTENSION_MODEL_COMMAND} --write"
-CHECK_EXTENSION_MODEL_WRITE_EVIDENCE_COMMAND = f"{CHECK_EXTENSION_MODEL_COMMAND} --write-evidence"
-CHECK_EXTENSION_MODEL_WRITE_EVIDENCE_SUMMARY_COMMAND = (
-    f"{CHECK_EXTENSION_MODEL_COMMAND} --write-evidence-summary"
-)
-WASIX_EVIDENCE_TIER = "wasix-full-lifecycle-v1"
-
-BASE_SOURCE_DIGEST_INPUTS = [
-    "src/postgres/versions/18/source.toml",
-    "src/extensions/catalog/extensions.source.json",
-    "src/extensions/catalog/native-components.toml",
-    "src/extensions/contrib/postgres18.toml",
-    "src/extensions/generated/extensions.catalog.json",
-    "src/extensions/generated/contrib-build.tsv",
-    "src/extensions/generated/pgxs-build.tsv",
-]
-
-ID_RE = re.compile(r"^[a-z][a-z0-9_]*$")
-SQL_NAME_RE = re.compile(r"^[a-z][a-z0-9_-]*$")
-EVIDENCE_STATUSES = {"passed", "failed", "blocked", "not-run"}
-
-
-def fail(message: str) -> None:
-    raise SystemExit(message)
-
-
-def ensure_trailing_newline(text: str) -> str:
-    return text if text.endswith("\n") else f"{text}\n"
-
-
-def format_rust_source(source: str) -> str:
-    try:
-        return ensure_trailing_newline(
-            subprocess.check_output(
-                ["rustfmt", "--emit", "stdout"],
-                cwd=ROOT,
-                input=source,
-                text=True,
-            )
-        )
-    except (FileNotFoundError, subprocess.CalledProcessError) as error:
-        fail(f"failed to format generated Rust extension metadata with rustfmt: {error}")
-
-
-def format_typescript_source(source: str, path: Path) -> str:
-    pnpm = shutil.which("pnpm") or shutil.which("pnpm.cmd")
-    if pnpm is None:
-        fail(f"failed to format generated TypeScript extension metadata with Biome {BIOME_VERSION}: pnpm was not found")
-    try:
-        return ensure_trailing_newline(
-            subprocess.check_output(
-                [
-                    pnpm,
-                    f"--package=@biomejs/biome@{BIOME_VERSION}",
-                    "dlx",
-                    "biome",
-                    "format",
-                    "--stdin-file-path",
-                    rel(path),
-                ],
-                cwd=ROOT,
-                input=source,
-                text=True,
-            )
-        )
-    except (FileNotFoundError, subprocess.CalledProcessError) as error:
-        fail(f"failed to format generated TypeScript extension metadata with Biome {BIOME_VERSION}: {error}")
-
-
-@lru_cache(maxsize=1)
-def pinned_bun_version() -> str:
-    for raw_line in (ROOT / ".prototools").read_text(encoding="utf-8").splitlines():
-        key, separator, value = raw_line.partition("=")
-        if separator and key.strip() == "bun":
-            return value.strip().strip('"')
-    fail(".prototools must pin a bun version")
-
-
-def pinned_bun_executable() -> str | None:
-    for name in ["bun.exe", "bun"]:
-        candidate = shutil.which(name)
-        if candidate is None:
-            continue
-        try:
-            version = subprocess.check_output(
-                [candidate, "--version"],
-                cwd=ROOT,
-                stderr=subprocess.DEVNULL,
-                text=True,
-            ).strip()
-        except (FileNotFoundError, subprocess.CalledProcessError):
-            continue
-        if version == pinned_bun_version():
-            return candidate
-    return None
-
-
-def git_bash_executable() -> str:
-    candidates: list[Path] = []
-    for root in [os.environ.get("ProgramFiles"), os.environ.get("ProgramFiles(x86)")]:
-        if root:
-            candidates.extend([Path(root) / "Git/bin/bash.exe", Path(root) / "Git/usr/bin/bash.exe"])
-    for name in ["git.exe", "git"]:
-        git = shutil.which(name)
-        if git is None:
-            continue
-        for parent in Path(git).parents:
-            if parent.name.lower() == "git":
-                candidates.extend([parent / "bin/bash.exe", parent / "usr/bin/bash.exe"])
-                break
-    for name in ["bash.exe", "bash"]:
-        bash = shutil.which(name)
-        if bash is None:
-            continue
-        candidate = Path(bash)
-        if "system32" not in {part.lower() for part in candidate.parts}:
-            candidates.append(candidate)
-    for candidate in candidates:
-        if candidate.is_file():
-            return str(candidate)
-    fail("failed to find Git for Windows bash.exe; install Git Bash or put it on PATH")
-
-
-def bun_command(*args: str) -> list[str]:
-    if os.name == "nt":
-        bun = pinned_bun_executable()
-        if bun is not None:
-            return [bun, *args]
-        return [git_bash_executable(), "tools/dev/bun.sh", *args]
-    return ["tools/dev/bun.sh", *args]
-
-
-@lru_cache(maxsize=None)
-def release_graph_rows(command: str) -> tuple[dict, ...]:
-    try:
-        output = subprocess.check_output(
-            bun_command("tools/release/release_graph_query.mjs", command),
-            cwd=ROOT,
-            text=True,
-            stderr=subprocess.PIPE,
-        )
-    except (FileNotFoundError, subprocess.CalledProcessError) as error:
-        stderr = getattr(error, "stderr", "") or ""
-        stdout = getattr(error, "output", "") or ""
-        detail = "\n".join(part for part in [stderr.strip(), stdout.strip()] if part) or str(error)
-        fail(f"failed to query release graph {command}: {detail.strip()}")
-    try:
-        rows = json.loads(output)
-    except json.JSONDecodeError as error:
-        fail(f"release graph {command} query did not return valid JSON: {error}")
-    if not isinstance(rows, list) or not all(isinstance(row, dict) for row in rows):
-        fail(f"release graph {command} query must return a JSON object list")
-    return tuple(rows)
-
-
-def validate_extension_metadata_row(row: dict) -> None:
-    product = row.get("product")
-    if not isinstance(product, str) or not product.startswith("oliphaunt-extension-"):
-        fail(f"release graph extension-metadata row must declare an exact-extension product: {product!r}")
-    artifact_product = row.get("artifactProduct", product)
-    if artifact_product != product:
-        fail(
-            "release graph extension-metadata row must keep product and artifactProduct equal: "
-            f"{product!r} != {artifact_product!r}"
-        )
-    for key in [
-        "sqlName",
-        "memberPath",
-        "class",
-        "versioning",
-        "sourcePath",
-        "cargoPackage",
-        "npmPackage",
-        "mavenGroup",
-        "mavenArtifact",
-    ]:
-        value = row.get(key)
-        if not isinstance(value, str) or not value:
-            fail(f"release graph extension-metadata {product}.{key} must be a non-empty string")
-    compatibility = row.get("compatibility")
-    if not isinstance(compatibility, dict):
-        fail(f"release graph extension-metadata {product}.compatibility must be an object")
-    for key in [
-        "postgresMajor",
-        "extensionRuntimeContract",
-        "nativeRuntimeProduct",
-        "nativeRuntimeVersion",
-        "wasixRuntimeProduct",
-        "wasixRuntimeVersion",
-    ]:
-        value = compatibility.get(key)
-        if not isinstance(value, str) or not value:
-            fail(f"release graph extension-metadata {product}.compatibility.{key} must be a non-empty string")
-    source_identity = row.get("sourceIdentity")
-    if not isinstance(source_identity, dict) or not source_identity:
-        fail(f"release graph extension-metadata {product}.sourceIdentity must be an object")
-
-
-@lru_cache(maxsize=1)
-def extension_metadata_rows() -> tuple[dict, ...]:
-    rows = release_graph_rows("extension-metadata")
-    seen: set[str] = set()
-    for row in rows:
-        validate_extension_metadata_row(row)
-        sql_name = str(row["sqlName"])
-        if sql_name in seen:
-            fail(f"release graph extension-metadata query returned duplicate SQL member {sql_name}")
-        seen.add(sql_name)
-    if not rows:
-        fail("release graph extension-metadata query returned no products")
-    return rows
-
-
-@lru_cache(maxsize=1)
-def extension_metadata_by_sql_name() -> dict[str, dict]:
-    rows = {}
-    for source in extension_metadata_rows():
-        row = dict(source)
-        row["artifactProduct"] = row.get("artifactProduct", row["product"])
-        compatibility = row["compatibility"]
-        row["releaseProduct"] = (
-            compatibility["nativeRuntimeProduct"]
-            if row["versioning"] == "runtime-bound"
-            else row["artifactProduct"]
-        )
-        rows[str(row["sqlName"])] = row
-    return rows
-
-
-def rel(path: Path) -> str:
-    try:
-        return path.relative_to(ROOT).as_posix()
-    except ValueError:
-        return path.as_posix()
-
-
-def read_toml(path: Path) -> dict:
-    try:
-        with path.open("rb") as handle:
-            return tomllib.load(handle)
-    except tomllib.TOMLDecodeError as error:
-        fail(f"{rel(path)} is invalid TOML: {error}")
-
-
-def read_json(path: Path) -> dict:
-    try:
-        return json.loads(path.read_text(encoding="utf-8"))
-    except json.JSONDecodeError as error:
-        fail(f"{rel(path)} is invalid JSON: {error}")
-
-
-def source_pin_paths() -> list[Path]:
-    if not THIRD_PARTY_ROOT.is_dir():
-        fail(f"{rel(THIRD_PARTY_ROOT)} must exist")
-    if not EXTERNAL_ROOT.is_dir():
-        fail(f"{rel(EXTERNAL_ROOT)} must exist")
-    paths = [
-        path
-        for domain in PRODUCTION_THIRD_PARTY_DOMAINS
-        for path in (THIRD_PARTY_ROOT / domain).glob("**/*.toml")
-        if path.is_file()
-    ]
-    paths.extend(
-        path
-        for path in EXTERNAL_ROOT.glob("**/source.toml")
-        if path.is_file()
-    )
-    return sorted(paths, key=rel)
-
-
-def normalized_rel_list(values: object, label: str) -> list[str]:
-    if not isinstance(values, list) or not all(isinstance(value, str) for value in values):
-        fail(f"{label} must be a list of repository-relative paths")
-    return [value.replace("\\", "/") for value in values]
-
-
-def load_source_names() -> set[str]:
-    source_names: set[str] = set()
-    for path in source_pin_paths():
-        data = read_toml(path)
-        name = data.get("name")
-        if not isinstance(name, str) or not name:
-            fail(f"{rel(path)} must declare a source name")
-        if name in source_names:
-            fail(f"duplicate source pin {name} across source metadata")
-        source_names.add(name)
-    if not source_names:
-        fail("source metadata must contain at least one source pin")
-    return source_names
-
-
-@lru_cache(maxsize=1)
-def native_component_inventory() -> dict:
-    result = subprocess.run(
-        bun_command(rel(NATIVE_COMPONENT_TOOL), "inventory"),
-        cwd=ROOT,
-        check=False,
-        capture_output=True,
-        text=True,
-    )
-    if result.returncode != 0:
-        detail = result.stderr.strip() or result.stdout.strip() or f"exit {result.returncode}"
-        fail(f"failed to load {rel(NATIVE_COMPONENT_CONTRACT)}: {detail}")
-    try:
-        inventory = json.loads(result.stdout)
-    except json.JSONDecodeError as error:
-        fail(f"native component resolver returned invalid JSON: {error}")
-    if inventory.get("schema") != "oliphaunt-native-components-v1":
-        fail(f"{rel(NATIVE_COMPONENT_CONTRACT)} has an unsupported schema")
-    if not isinstance(inventory.get("components"), list) or not isinstance(
-        inventory.get("resolutions"), list
-    ):
-        fail(f"{rel(NATIVE_COMPONENT_CONTRACT)} inventory is malformed")
-    return inventory
-
-
-def native_component_resolutions(sql_name: str) -> list[dict]:
-    return [
-        row
-        for row in native_component_inventory()["resolutions"]
-        if row.get("extension") == sql_name
-    ]
-
-
-def native_component_resolution(
-    sql_name: str,
-    family: str,
-    kind: str,
-    target: str,
-) -> dict:
-    matches = [
-        row
-        for row in native_component_resolutions(sql_name)
-        if row.get("family") == family
-        and row.get("kind") == kind
-        and row.get("target") == target
-    ]
-    if len(matches) > 1:
-        fail(f"native component contract is ambiguous for {sql_name}/{family}/{kind}/{target}")
-    return matches[0] if matches else {
-        "components": [],
-        "sources": [],
-        "sourcePaths": [],
-        "linkUnits": [],
-        "runtimeFiles": [],
-    }
-
-
-def native_component_union(sql_name: str, field: str) -> list[str]:
-    return sorted(
-        {
-            value
-            for row in native_component_resolutions(sql_name)
-            for value in row.get(field, [])
-            if isinstance(value, str) and value
-        }
-    )
-
-
-def validate_native_component_inventory(catalog: dict) -> None:
-    inventory = native_component_inventory()
-    source_names = load_source_names()
-    public_sql_names = {
-        row.get("sql-name", row.get("id"))
-        for row in catalog.get("extensions", [])
-        if isinstance(row, dict)
-    }
-    contract_sources = {
-        row.get("source")
-        for row in inventory["components"]
-        if isinstance(row, dict) and row.get("source") is not None
-    }
-    unknown_sources = sorted(contract_sources - source_names)
-    if unknown_sources:
-        fail(
-            f"{rel(NATIVE_COMPONENT_CONTRACT)} references missing source metadata: "
-            f"{unknown_sources}"
-        )
-    requirement_extensions = {
-        row.get("extension")
-        for row in inventory["resolutions"]
-        if isinstance(row, dict)
-    }
-    unknown_extensions = sorted(requirement_extensions - public_sql_names)
-    if unknown_extensions:
-        fail(
-            f"{rel(NATIVE_COMPONENT_CONTRACT)} references unknown catalog extensions: "
-            f"{unknown_extensions}"
-        )
-
-
-def source_digest_inputs() -> list[str]:
-    source_files = [rel(path) for path in source_pin_paths()]
-    recipe_files = sorted(
-        rel(path)
-        for path in EXTERNAL_ROOT.glob("**/*")
-        if path.is_file()
-        and path.name != "source.toml"
-        and path.name not in EXTENSION_ENVELOPE_FILENAMES
-    )
-    smoke_recipe_files = [
-        rel(SMOKE_RECIPE_MANIFEST),
-        *sorted(rel(path) for path in SMOKE_RECIPE_ROOT.glob("*.sql") if path.is_file()),
-    ]
-    return [*BASE_SOURCE_DIGEST_INPUTS, *source_files, *recipe_files, *smoke_recipe_files]
-
-
-def validate_no_obsolete_extension_files(root: Path = EXTERNAL_ROOT) -> None:
-    obsolete = sorted(
-        rel(path)
-        for path in root.glob("**/*")
-        if path.is_file() and path.name in OBSOLETE_EXTENSION_FILENAMES
-    )
-    if obsolete:
-        fail(
-            "obsolete per-extension artifact or lifecycle state must stay off main: "
-            + ", ".join(obsolete)
-        )
-
-
-def source_digest(paths: list[str] | None = None) -> str:
-    paths = source_digest_inputs() if paths is None else paths
-    digest = hashlib.sha256()
-    for relative in paths:
-        path = ROOT / relative
-        if not path.exists():
-            fail(f"source digest input is missing: {relative}")
-        contents = path.read_bytes().replace(b"\r\n", b"\n").replace(b"\r", b"\n")
-        digest.update(relative.encode("utf-8"))
-        digest.update(b"\0")
-        digest.update(contents)
-        digest.update(b"\0")
-    return f"sha256:{digest.hexdigest()}"
-
-
-@lru_cache(maxsize=1)
-def current_git_identity() -> tuple[str, str]:
-    try:
-        commit = subprocess.check_output(
-            ["git", "rev-parse", "HEAD^{commit}"],
-            cwd=ROOT,
-            text=True,
-            stderr=subprocess.PIPE,
-        ).strip()
-        tree = subprocess.check_output(
-            ["git", "rev-parse", f"{commit}^{{tree}}"],
-            cwd=ROOT,
-            text=True,
-            stderr=subprocess.PIPE,
-        ).strip()
-    except (FileNotFoundError, subprocess.CalledProcessError) as error:
-        stderr = getattr(error, "stderr", "") or ""
-        fail(f"failed to resolve exact evidence source commit/tree: {stderr.strip() or error}")
-    if re.fullmatch(r"[0-9a-f]{40}", commit) is None or re.fullmatch(r"[0-9a-f]{40}", tree) is None:
-        fail("git returned an invalid exact evidence source commit/tree")
-    return commit, tree
-
-
-def require_clean_evidence_inputs() -> None:
-    try:
-        status = subprocess.check_output(
-            ["git", "status", "--porcelain=v1", "--", *source_digest_inputs()],
-            cwd=ROOT,
-            text=True,
-            stderr=subprocess.PIPE,
-        ).strip()
-    except (FileNotFoundError, subprocess.CalledProcessError) as error:
-        stderr = getattr(error, "stderr", "") or ""
-        fail(f"failed to verify exact evidence source inputs: {stderr.strip() or error}")
-    if status:
-        fail(
-            "full WASIX evidence source inputs differ from the recorded commit; "
-            f"refusing dirty exact-SHA evidence:\n{status}"
-        )
-
-
-def validate_id(value: object, label: str) -> str:
-    if not isinstance(value, str) or ID_RE.fullmatch(value) is None:
-        fail(f"{label} must be a lower snake-case extension id, got {value!r}")
-    return value
-
-
-def validate_sql_name(value: object, label: str) -> str:
-    if not isinstance(value, str) or SQL_NAME_RE.fullmatch(value) is None:
-        fail(f"{label} must be an exact SQL extension name, got {value!r}")
-    return value
-
-
-def extension_rows(path: Path) -> list[dict]:
-    data = read_toml(path)
-    if data.get("format-version") != 1:
-        fail(f"{rel(path)} must use format-version = 1")
-    rows = data.get("extensions")
-    if not isinstance(rows, list) or not rows:
-        fail(f"{rel(path)} must define [[extensions]] rows")
-    return rows
-
-
-def validate_contrib_recipe(catalog: dict) -> None:
-    data = read_toml(CONTRIB_RECIPE)
-    if data.get("format-version") != 1:
-        fail(f"{rel(CONTRIB_RECIPE)} must use format-version = 1")
-    if data.get("postgres-version") != "18.4":
-        fail(f"{rel(CONTRIB_RECIPE)} must target PostgreSQL 18.4")
-    if data.get("source-kind") != "postgres-contrib":
-        fail(f"{rel(CONTRIB_RECIPE)} must declare source-kind = postgres-contrib")
-    if data.get("source-root") != "src/postgres/versions/18/contrib":
-        fail(f"{rel(CONTRIB_RECIPE)} must point at src/postgres/versions/18/contrib")
-    rows = data.get("extensions")
-    if not isinstance(rows, list) or not rows:
-        fail(f"{rel(CONTRIB_RECIPE)} must declare contrib extension rows")
-    recipe_by_id: dict[str, dict] = {}
-    for row in rows:
-        extension_id = validate_id(row.get("id"), f"{rel(CONTRIB_RECIPE)} row id")
-        validate_sql_name(row.get("sql-name"), f"{rel(CONTRIB_RECIPE)} row {extension_id} sql-name")
-        for field in ("contrib-dir", "module-file"):
-            if not isinstance(row.get(field), str) or not row[field]:
-                fail(f"{rel(CONTRIB_RECIPE)} row {extension_id} must define {field}")
-        data_files = row.get("data-files", [])
-        if not isinstance(data_files, list) or not all(isinstance(value, str) for value in data_files):
-            fail(f"{rel(CONTRIB_RECIPE)} row {extension_id} data-files must be an array of strings when present")
-        duplicate_fields = sorted(
-            field
-            for field in (
-                "mobile-static-dependencies",
-                "mobile-static-include-dependencies",
-                "mobile-static-hash-source-dependencies",
-            )
-            if field in row
-        )
-        if duplicate_fields:
-            fail(
-                f"{rel(CONTRIB_RECIPE)} row {extension_id} duplicates native component "
-                f"requirements in {rel(NATIVE_COMPONENT_CONTRACT)}: {duplicate_fields}"
-            )
-        for recipe_field in (
-            "mobile-static-include-dirs",
-            "mobile-static-cflags",
-            "mobile-static-hash-dirs",
-        ):
-            values = row.get(recipe_field, [])
-            if not isinstance(values, list) or not all(isinstance(value, str) and value for value in values):
-                fail(
-                    f"{rel(CONTRIB_RECIPE)} row {extension_id} {recipe_field} "
-                    "must be an array of strings when present"
-                )
-        if extension_id in recipe_by_id:
-            fail(f"{rel(CONTRIB_RECIPE)} has duplicate extension id {extension_id}")
-        recipe_by_id[extension_id] = row
-
-    catalog_rows = [
-        row
-        for row in catalog.get("extensions", [])
-        if row.get("source-kind") == "postgres-contrib"
-    ]
-    catalog_by_id = {
-        validate_id(row.get("id"), f"{rel(CATALOG)} row id"): row for row in catalog_rows
-    }
-    if sorted(recipe_by_id) != sorted(catalog_by_id):
-        fail(
-            f"{rel(CONTRIB_RECIPE)} ids must match the generated contrib catalog; "
-            f"recipe-only={sorted(set(recipe_by_id) - set(catalog_by_id))}, "
-            f"catalog-only={sorted(set(catalog_by_id) - set(recipe_by_id))}"
-        )
-    for extension_id, catalog_row in catalog_by_id.items():
-        recipe = recipe_by_id[extension_id]
-        expected = {
-            "sql-name": catalog_row.get("sql-name"),
-            "module-file": catalog_row.get("native-module-file"),
-        }
-        for field, value in expected.items():
-            if recipe.get(field) != value:
-                fail(
-                    f"{rel(CONTRIB_RECIPE)} row {extension_id} {field}={recipe.get(field)!r} "
-                    f"does not match generated catalog {value!r}"
-                )
-
-
-def validate_external_recipes(catalog: dict) -> None:
-    source_names = load_source_names()
-    catalog_by_sql_name = {
-        row.get("sql-name", row.get("id")): row
-        for row in catalog.get("extensions", [])
-        if isinstance(row, dict)
-    }
-    validate_external_source_pins(catalog_by_sql_name, source_names)
-    validate_pg_textsearch_mobile_version_flag()
-    for recipe in sorted(EXTERNAL_ROOT.glob("*/recipe.toml")):
-        data = read_toml(recipe)
-        if data.get("schema") != "oliphaunt-extension-recipe-v1":
-            fail(f"{rel(recipe)} must use schema = oliphaunt-extension-recipe-v1")
-        sql_name = validate_sql_name(data.get("sql_name"), f"{rel(recipe)} sql_name")
-        if recipe.parent.name != sql_name:
-            fail(f"{rel(recipe)} directory name must match sql_name {sql_name}")
-        kind = data.get("kind")
-        if kind not in {"external-simple-pgxs", "external-complex"}:
-            fail(f"{rel(recipe)} kind must be external-simple-pgxs or external-complex")
-        source = data.get("source")
-        if source not in source_names:
-            fail(f"{rel(recipe)} source {source!r} must reference source metadata")
-        majors = data.get("postgres_majors")
-        if not isinstance(majors, list) or 18 not in majors:
-            fail(f"{rel(recipe)} must explicitly support postgres_majors including 18")
-        if not isinstance(data.get("license"), str) or not data["license"]:
-            fail(f"{rel(recipe)} must declare license metadata")
-        lifecycle = data.get("lifecycle")
-        artifacts = data.get("artifacts")
-        if not isinstance(lifecycle, dict) or not isinstance(artifacts, dict):
-            fail(f"{rel(recipe)} must declare lifecycle and artifacts tables")
-        if "support" in data:
-            fail(f"{rel(recipe)} must not carry an intermediate support-status table")
-        runtime_environment = data.get("runtime_environment") or []
-        if not isinstance(runtime_environment, list):
-            fail(f"{rel(recipe)} runtime_environment must be an array when present")
-        for index, entry in enumerate(runtime_environment):
-            if not isinstance(entry, dict):
-                fail(f"{rel(recipe)} runtime_environment[{index}] must be a table")
-            for field in ("name", "path", "required_file"):
-                if not isinstance(entry.get(field), str) or not entry[field]:
-                    fail(f"{rel(recipe)} runtime_environment[{index}].{field} must be a non-empty string")
-        for field in (
-            "requires",
-            "implicit_sql_dependencies",
-            "load_sql",
-            "post_create_sql",
-            "shared_preload_libraries",
-        ):
-            if not isinstance(lifecycle.get(field), list):
-                fail(f"{rel(recipe)} lifecycle.{field} must be an array")
-        for field in (
-            "creates_extension",
-            "restart_required",
-            "background_workers",
-            "shared_memory",
-            "session_load_required",
-            "needs_superuser",
-            "trusted",
-        ):
-            if not isinstance(lifecycle.get(field), bool):
-                fail(f"{rel(recipe)} lifecycle.{field} must be boolean")
-        for field in (
-            "control_files",
-            "sql_globs",
-            "native_modules",
-            "native_dependency_modules",
-            "data_files",
-            "headers",
-            "licenses",
-        ):
-            if not isinstance(artifacts.get(field), list):
-                fail(f"{rel(recipe)} artifacts.{field} must be an array")
-        for field in ("extension_sql_file_prefixes", "extension_sql_file_names"):
-            if field in artifacts and not isinstance(artifacts.get(field), list):
-                fail(f"{rel(recipe)} artifacts.{field} must be an array when present")
-        if kind == "external-complex":
-            for path in (
-                recipe.parent / "targets/native.toml",
-                recipe.parent / "targets/wasix.toml",
-                recipe.parent / "targets/native-static-registry.toml",
-                recipe.parent / "patches/README.md",
-            ):
-                if not path.exists():
-                    fail(f"{rel(recipe)} complex recipe is missing {rel(path)}")
-
-        for target_path in sorted((recipe.parent / "targets").glob("*.toml")):
-            target = read_toml(target_path)
-            duplicate_fields = sorted(
-                field
-                for field in (
-                    "dependencies",
-                    "ios_dependencies",
-                    "android_dependencies",
-                    "include_dependencies",
-                    "status",
-                )
-                if field in target
-            )
-            if duplicate_fields:
-                fail(
-                    f"{rel(target_path)} duplicates native component requirements in "
-                    f"{rel(NATIVE_COMPONENT_CONTRACT)}: {duplicate_fields}"
-                )
-
-        generated = catalog_by_sql_name.get(sql_name)
-        if generated is None:
-            fail(f"{rel(recipe)} has no matching generated catalog row")
-        if generated.get("source-kind") != "postgis" and kind == "external-complex":
-            fail(f"{rel(recipe)} complex recipe must match generated source-kind postgis")
-        generated_modules = set(generated.get("load-order") or [])
-        for module in artifacts.get("native_modules", []):
-            if module not in generated_modules:
-                fail(f"{rel(recipe)} native module {module!r} must match generated load-order")
-
-
-def split_smoke_statements(sql: str) -> list[str]:
-    return [
-        statement.strip()
-        for statement in sql.split("-- oliphaunt-statement")
-        if statement.strip()
-    ]
-
-
-def validate_extension_smoke_recipes(catalog: dict) -> None:
-    expected = sorted(
-        validate_sql_name(
-            row.get("sql-name", row.get("id")),
-            f"{rel(CATALOG)} extension smoke SQL name",
-        )
-        for row in catalog.get("extensions", [])
-        if isinstance(row, dict)
-    )
-    manifest = read_json(SMOKE_RECIPE_MANIFEST)
-    if set(manifest) != {"format-version", "recipes"} or manifest.get("format-version") != 1:
-        fail(f"{rel(SMOKE_RECIPE_MANIFEST)} must contain only format-version 1 and recipes")
-    recipes = manifest.get("recipes")
-    if not isinstance(recipes, dict):
-        fail(f"{rel(SMOKE_RECIPE_MANIFEST)} recipes must be an object")
-    if sorted(recipes) != expected:
-        fail(
-            f"{rel(SMOKE_RECIPE_MANIFEST)} must exactly map the public extension catalog; "
-            f"recipe-only={sorted(set(recipes) - set(expected))}, "
-            f"catalog-only={sorted(set(expected) - set(recipes))}"
-        )
-    expected_files = [f"{sql_name}.sql" for sql_name in expected]
-    mapped_files = list(recipes.values())
-    if mapped_files != expected_files or len(set(mapped_files)) != len(mapped_files):
-        fail(
-            f"{rel(SMOKE_RECIPE_MANIFEST)} must map each SQL name to its unique .sql recipe"
-        )
-    files = sorted(path for path in SMOKE_RECIPE_ROOT.iterdir() if path.is_file())
-    invalid = [
-        rel(path)
-        for path in files
-        if path != SMOKE_RECIPE_MANIFEST and path.suffix != ".sql"
-    ]
-    if invalid:
-        fail(f"{rel(SMOKE_RECIPE_ROOT)} contains non-SQL recipe files: {invalid}")
-    sql_files = [path for path in files if path.suffix == ".sql"]
-    actual = [path.name for path in sql_files]
-    if actual != expected_files:
-        fail(
-            f"{rel(SMOKE_RECIPE_ROOT)} must exactly match the public extension catalog; "
-            f"recipe-only={sorted(set(actual) - set(expected_files))}, "
-            f"catalog-only={sorted(set(expected_files) - set(actual))}"
-        )
-    for path in sql_files:
-        text = path.read_text(encoding="utf-8")
-        if "-- oliphaunt-statement" not in text:
-            fail(f"{rel(path)} must include explicit statement delimiters")
-        if not split_smoke_statements(text):
-            fail(f"{rel(path)} must contain at least one SQL statement")
-
-
-def validate_pg_textsearch_mobile_version_flag() -> None:
-    extension_dir = EXTERNAL_ROOT / "pg_textsearch"
-    source_path = extension_dir / "source.toml"
-    target_path = extension_dir / "targets/native-static-registry.toml"
-    source = read_toml(source_path)
-    control = source.get("extension-control")
-    if not isinstance(control, dict):
-        fail(f"{rel(source_path)} must declare extension-control metadata")
-    version = control.get("default-version")
-    if not isinstance(version, str) or not re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+", version):
-        fail(f"{rel(source_path)} extension-control.default-version must be a semantic version")
-
-    target = read_toml(target_path)
-    cflags = validate_string_list(target.get("cflags"), f"{rel(target_path)} cflags")
-    expected = f'-DPG_TEXTSEARCH_VERSION="{version}"'
-    if cflags.count(expected) != 1:
-        fail(
-            f"{rel(target_path)} cflags must contain exactly {expected!r} so Android and iOS "
-            "static builds match the pinned pg_textsearch control version"
-        )
-
-
-def validate_external_source_pins(catalog_by_sql_name: dict[str, dict], source_names: set[str]) -> None:
-    for source_path in sorted(EXTERNAL_ROOT.glob("*/source.toml")):
-        extension_dir = source_path.parent
-        sql_name = validate_sql_name(extension_dir.name, f"{rel(source_path)} directory")
-        source = read_toml(source_path)
-        name = source.get("name")
-        if not isinstance(name, str) or name not in source_names:
-            fail(f"{rel(source_path)} must declare a valid source name")
-        if sql_name not in catalog_by_sql_name:
-            continue
-        generated = catalog_by_sql_name[sql_name]
-        generated_control_file = generated.get("control-file")
-        if isinstance(generated_control_file, str) and generated_control_file:
-            expected_checkout = f"target/oliphaunt-sources/checkouts/{name}/"
-            if not generated_control_file.startswith(expected_checkout):
-                fail(
-                    f"{rel(source_path)} source name {name!r} implies checkout "
-                    f"{expected_checkout}, but generated catalog uses {generated_control_file}"
-                )
-
-
-def validate_extension_release_metadata() -> None:
-    extension_metadata_rows()
-
-
-def extension_family(source_kind: object) -> str:
-    return {
-        "postgres-contrib": "PostgreSQL contrib",
-        "oliphaunt-other-extension": "External PGXS",
-        "postgis": "Complex external",
-    }.get(str(source_kind), "Other")
-
-
-def extension_activation(extension: dict) -> str:
-    lifecycle = extension.get("lifecycle", {})
-    create_extension = bool(lifecycle.get("create-extension"))
-    load_sql = lifecycle.get("load-sql") or []
-    if create_extension and load_sql:
-        return "CREATE EXTENSION + LOAD"
-    if create_extension:
-        return "CREATE EXTENSION"
-    if load_sql:
-        return "LOAD"
-    return "manual"
-
-
-def extension_version(extension: dict) -> str:
-    control = extension.get("control")
-    if isinstance(control, dict):
-        version = control.get("default-version")
-        if isinstance(version, str) and "@" not in version:
-            return version
-    return ""
-
-
-def native_module_stem(extension: dict) -> str | None:
-    module_file = extension.get("native-module-file") or extension.get("module-file")
-    if not isinstance(module_file, str) or not module_file:
-        return None
-    for suffix in (".so", ".dylib", ".dll"):
-        if module_file.endswith(suffix):
-            return module_file[: -len(suffix)]
-    return module_file
-
-
-def shared_preload_libraries(extension: dict) -> list[str]:
-    lifecycle = extension.get("lifecycle") or {}
-    values = []
-    for assignment in lifecycle.get("startup-config") or []:
-        if not isinstance(assignment, str):
-            continue
-        key, separator, value = assignment.partition("=")
-        if separator and key == "shared_preload_libraries":
-            values.extend(part.strip() for part in value.split(",") if part.strip())
-    return sorted(set(values))
-
-
-def extension_data_files_from_recipe(extension: dict) -> list[str]:
-    sql_name = extension.get("sql-name", extension.get("id"))
-    if not isinstance(sql_name, str):
-        return []
-    recipe = ROOT / "src/extensions/external" / sql_name / "recipe.toml"
-    if not recipe.exists():
-        contrib_rows = read_toml(CONTRIB_RECIPE).get("extensions") or []
-        for row in contrib_rows:
-            if isinstance(row, dict) and row.get("sql-name") == sql_name:
-                data_files = row.get("data-files") or []
-                return sorted(value for value in data_files if isinstance(value, str))
-        return []
-    artifacts = read_toml(recipe).get("artifacts") or {}
-    data_files = artifacts.get("data_files") or []
-    return sorted(value for value in data_files if isinstance(value, str))
-
-
-def extension_artifact_list_from_recipe(extension: dict, field: str) -> list[str]:
-    sql_name = extension.get("sql-name", extension.get("id"))
-    if not isinstance(sql_name, str):
-        return []
-    recipe = ROOT / "src/extensions/external" / sql_name / "recipe.toml"
-    if not recipe.exists():
-        return []
-    artifacts = read_toml(recipe).get("artifacts") or {}
-    values = artifacts.get(field) or []
-    return sorted(value for value in values if isinstance(value, str))
-
-
-def extension_runtime_environment_from_recipe(extension: dict) -> list[dict[str, str]]:
-    sql_name = extension.get("sql-name", extension.get("id"))
-    if not isinstance(sql_name, str):
-        return []
-    recipe = ROOT / "src/extensions/external" / sql_name / "recipe.toml"
-    if not recipe.exists():
-        return []
-    rows = read_toml(recipe).get("runtime_environment") or []
-    env = []
-    for row in rows:
-        if not isinstance(row, dict):
-            continue
-        name = row.get("name")
-        path = row.get("path")
-        required_file = row.get("required_file")
-        if all(isinstance(value, str) and value for value in (name, path, required_file)):
-            env.append({"name": name, "path": path, "required_file": required_file})
-    return sorted(env, key=lambda row: (row["name"], row["path"], row["required_file"]))
-
-
-def runtime_share_data_files(data_files: list[str]) -> list[str]:
-    prefix = "share/postgresql/"
-    return sorted(value[len(prefix) :] if value.startswith(prefix) else value for value in data_files)
-
-
-def contrib_recipe_row(sql_name: str) -> dict | None:
-    for row in read_toml(CONTRIB_RECIPE).get("extensions") or []:
-        if isinstance(row, dict) and row.get("sql-name") == sql_name:
-            return row
-    return None
-
-
-def validate_string_list(values: object, label: str) -> list[str]:
-    if values is None:
-        return []
-    if not isinstance(values, list) or not all(isinstance(value, str) and value for value in values):
-        fail(f"{label} must be an array of non-empty strings")
-    return values
-
-
-def mobile_static_dependencies(sql_name: str, field: str = "dependencies") -> list[str]:
-    targets = {
-        "dependencies": ["ios-xcframework", "android-arm64-v8a", "android-x86_64"],
-        "ios_dependencies": ["ios-xcframework"],
-        "android_dependencies": ["android-arm64-v8a", "android-x86_64"],
-    }.get(field)
-    if targets is None:
-        fail(f"unknown mobile static dependency field {field!r}")
-    return sorted(
-        {
-            dependency
-            for target in targets
-            for dependency in native_component_resolution(
-                sql_name,
-                "native",
-                "native-static-registry",
-                target,
-            ).get("linkUnits", [])
-        }
-    )
-
-
-def contrib_mobile_static_list(sql_name: str, recipe_field: str) -> list[str]:
-    row = contrib_recipe_row(sql_name)
-    if row is None:
-        return []
-    return sorted(
-        dict.fromkeys(
-            validate_string_list(
-                row.get(recipe_field),
-                f"{rel(CONTRIB_RECIPE)} row {sql_name} {recipe_field}",
-            )
-        )
-    )
-
-
-def external_mobile_target_list(sql_name: str, field: str) -> list[str]:
-    target_path = ROOT / "src/extensions/external" / sql_name / "targets/native-static-registry.toml"
-    if not target_path.exists():
-        return []
-    target = read_toml(target_path)
-    return sorted(
-        dict.fromkeys(
-            validate_string_list(target.get(field), f"{rel(target_path)} {field}")
-        )
-    )
-
-
-def mobile_static_include_dependencies(sql_name: str) -> list[str]:
-    return sorted(
-        {
-            source
-            for target in ("ios-xcframework", "android-arm64-v8a", "android-x86_64")
-            for source in native_component_resolution(
-                sql_name,
-                "native",
-                "native-static-registry",
-                target,
-            ).get("sources", [])
-        }
-    )
-
-
-def mobile_static_include_dirs(sql_name: str) -> list[str]:
-    external = external_mobile_target_list(sql_name, "include_dirs")
-    if external:
-        return external
-    return contrib_mobile_static_list(sql_name, "mobile-static-include-dirs")
-
-
-def mobile_static_cflags(sql_name: str) -> list[str]:
-    external = external_mobile_target_list(sql_name, "cflags")
-    if external:
-        return external
-    return contrib_mobile_static_list(sql_name, "mobile-static-cflags")
-
-
-def mobile_static_hash_source_dependencies(sql_name: str, field: str = "dependencies") -> list[str]:
-    targets = {
-        "dependencies": ["ios-xcframework", "android-arm64-v8a", "android-x86_64"],
-        "ios_dependencies": ["ios-xcframework"],
-        "android_dependencies": ["android-arm64-v8a", "android-x86_64"],
-    }.get(field)
-    if targets is None:
-        fail(f"unknown mobile static hash dependency field {field!r}")
-    return sorted(
-        {
-            dependency
-            for target in targets
-            for dependency in native_component_resolution(
-                sql_name,
-                "native",
-                "native-static-registry",
-                target,
-            ).get("sources", [])
-        }
-    )
-
-
-def mobile_static_hash_dirs(sql_name: str) -> list[str]:
-    external = external_mobile_target_list(sql_name, "hash_dirs")
-    if external:
-        return external
-    return contrib_mobile_static_list(sql_name, "mobile-static-hash-dirs")
-
-
-def mobile_static_source_files(sql_name: str) -> list[str]:
-    return external_mobile_target_list(sql_name, "source_files")
-
-
-def mobile_static_source_recursive_dirs(sql_name: str) -> list[str]:
-    return external_mobile_target_list(sql_name, "source_recursive_dirs")
-
-
-def target_native_support_modules(sql_name: str, target: str) -> list[dict]:
-    path = ROOT / "src/extensions/external" / sql_name / "targets" / f"{target}.toml"
-    if not path.exists():
-        return []
-    rows = read_toml(path).get("native_support_modules") or []
-    modules = []
-    for index, row in enumerate(rows):
-        if not isinstance(row, dict):
-            fail(f"{rel(path)} native_support_modules[{index}] must be a table")
-        module = {}
-        for field in ("name", "runtime_path", "build_path", "aot_file"):
-            value = row.get(field)
-            if not isinstance(value, str) or not value:
-                fail(f"{rel(path)} native_support_modules[{index}] must define {field}")
-            module[field.replace("_", "-")] = value
-        modules.append(module)
-    modules.sort(key=lambda module: module["name"])
-    return modules
-
-
-def generated_sdk_metadata(catalog: dict) -> dict:
-    rows = []
-    release_metadata = extension_metadata_by_sql_name()
-    public_sql_names = {
-        extension.get("sql-name", extension.get("id"))
-        for extension in catalog.get("extensions", [])
-        if isinstance(extension, dict)
-    }
-    for extension in catalog.get("extensions", []):
-        data_files = extension_data_files_from_recipe(extension)
-        dependencies = extension.get("dependencies") or []
-        sql_name = str(extension.get("sql-name", extension.get("id")))
-        release = release_metadata.get(sql_name)
-        if release is None:
-            fail(f"release graph has no exact release owner for catalog extension {sql_name}")
-        native_requirements = [
-            {
-                "family": requirement["family"],
-                "kind": requirement["kind"],
-                "target": requirement["target"],
-                "components": requirement["components"],
-                "link-units": requirement["linkUnits"],
-                "runtime-files": requirement["runtimeFiles"],
-            }
-            for requirement in native_component_resolutions(sql_name)
-        ]
-        row = {
-            "id": extension.get("id"),
-            "sql-name": sql_name,
-            "display-name": extension.get("display-name", extension.get("id")),
-            "postgres-major": 18,
-            "artifact-product": release["artifactProduct"],
-            "release-product": release["releaseProduct"],
-            "cargo-package": release["cargoPackage"],
-            "npm-package": release["npmPackage"],
-            "maven-group": release["mavenGroup"],
-            "maven-artifact": release["mavenArtifact"],
-            "runtime-bound": release["versioning"] == "runtime-bound",
-            "creates-extension": bool((extension.get("lifecycle") or {}).get("create-extension")),
-            "native-module-stem": native_module_stem(extension),
-            "dependencies": dependencies,
-            "selected-extension-dependencies": sorted(
-                dependency for dependency in dependencies if dependency in public_sql_names
-            ),
-            "native-components": native_component_union(sql_name, "components"),
-            "native-component-requirements": native_requirements,
-            "shared-preload-libraries": shared_preload_libraries(extension),
-            "data-files": data_files,
-            "runtime-share-data-files": runtime_share_data_files(data_files),
-            "extension-sql-file-prefixes": extension_artifact_list_from_recipe(
-                extension, "extension_sql_file_prefixes"
-            ),
-            "extension-sql-file-names": extension_artifact_list_from_recipe(
-                extension, "extension_sql_file_names"
-            ),
-            "runtime-environment": extension_runtime_environment_from_recipe(extension),
-            "source-kind": extension.get("source-kind"),
-        }
-        rows.append(row)
-    rows.sort(key=lambda row: (str(row["sql-name"]), str(row["id"])))
-    catalog_sha256 = hashlib.sha256(
-        json.dumps(rows, sort_keys=True, separators=(",", ":")).encode("utf-8")
-    ).hexdigest()
-    return {
-        "format-version": 1,
-        "extension-catalog-sha256": catalog_sha256,
-        "generated-from": [
-            {"name": "extension-catalog", "path": rel(CATALOG)},
-            {"name": "native-components", "path": rel(NATIVE_COMPONENT_CONTRACT)},
-            {"name": "extension-recipes", "path": "src/extensions"},
-            {"name": "release-products", "path": "src"},
-        ],
-        "extensions": rows,
-    }
-
-
-def generated_ios_static_dependencies(catalog: dict) -> dict:
-    rows = []
-    for extension in catalog.get("extensions", []):
-        sql_name = str(extension.get("sql-name", extension.get("id")))
-        dependencies = mobile_static_dependencies(sql_name, "ios_dependencies")
-        if dependencies:
-            rows.append(
-                {
-                    "sql-name": sql_name,
-                    "static-dependencies": dependencies,
-                }
-            )
-    rows.sort(key=lambda row: str(row["sql-name"]))
-    return {
-        "format-version": 1,
-        "generated-from": [
-            {"name": "extension-catalog", "path": rel(CATALOG)},
-            {"name": "native-components", "path": rel(NATIVE_COMPONENT_CONTRACT)},
-            {"name": "contrib-recipe", "path": rel(CONTRIB_RECIPE)},
-            {"name": "external-static-targets", "path": "src/extensions/external"},
-        ],
-        "extensions": rows,
-    }
-
-
-def generated_typescript_extension_module(
-    metadata: dict,
-    ios_static_dependencies: dict | None = None,
-) -> str:
-    ios_dependencies_by_sql_name = {
-        row["sql-name"]: row["static-dependencies"]
-        for row in (ios_static_dependencies or {}).get("extensions", [])
-    }
-    include_ios_static_dependencies = ios_static_dependencies is not None
-
-    def camel(row: dict) -> dict:
-        result = {
-            "id": row["id"],
-            "sqlName": row["sql-name"],
-            "displayName": row["display-name"],
-            "postgresMajor": row["postgres-major"],
-            "artifactProduct": row["artifact-product"],
-            "releaseProduct": row["release-product"],
-            "cargoPackage": row["cargo-package"],
-            "npmPackage": row["npm-package"],
-            "mavenGroup": row["maven-group"],
-            "mavenArtifact": row["maven-artifact"],
-            "runtimeBound": row["runtime-bound"],
-            "createsExtension": row["creates-extension"],
-            "nativeModuleStem": row["native-module-stem"],
-            "dependencies": row["dependencies"],
-            "selectedExtensionDependencies": row["selected-extension-dependencies"],
-            "sharedPreloadLibraries": row["shared-preload-libraries"],
-            "dataFiles": row["data-files"],
-            "runtimeShareDataFiles": row["runtime-share-data-files"],
-            "extensionSqlFilePrefixes": row["extension-sql-file-prefixes"],
-            "extensionSqlFileNames": row["extension-sql-file-names"],
-            "sourceKind": row["source-kind"],
-        }
-        if include_ios_static_dependencies:
-            result["iosStaticDependencies"] = ios_dependencies_by_sql_name.get(
-                row["sql-name"], []
-            )
-        return result
-
-    rows = [camel(row) for row in metadata.get("extensions", [])]
-    ios_static_dependency_type = (
-        "  readonly iosStaticDependencies: readonly string[];\n"
-        if include_ios_static_dependencies
-        else ""
-    )
-    source = (
-        f"// This file is generated by {CHECK_EXTENSION_MODEL_PATH}.\n"
-        "// Do not edit by hand.\n\n"
-        "export type GeneratedExtensionMetadata = {\n"
-        "  readonly id: string;\n"
-        "  readonly sqlName: string;\n"
-        "  readonly displayName: string;\n"
-        "  readonly postgresMajor: number;\n"
-        "  readonly artifactProduct: string;\n"
-        "  readonly releaseProduct: string;\n"
-        "  readonly cargoPackage: string;\n"
-        "  readonly npmPackage: string;\n"
-        "  readonly mavenGroup: string;\n"
-        "  readonly mavenArtifact: string;\n"
-        "  readonly runtimeBound: boolean;\n"
-        "  readonly createsExtension: boolean;\n"
-        "  readonly nativeModuleStem: string | null;\n"
-        "  readonly dependencies: readonly string[];\n"
-        "  readonly selectedExtensionDependencies: readonly string[];\n"
-        f"{ios_static_dependency_type}"
-        "  readonly sharedPreloadLibraries: readonly string[];\n"
-        "  readonly dataFiles: readonly string[];\n"
-        "  readonly runtimeShareDataFiles: readonly string[];\n"
-        "  readonly extensionSqlFilePrefixes: readonly string[];\n"
-        "  readonly extensionSqlFileNames: readonly string[];\n"
-        "  readonly sourceKind: string;\n"
-        "};\n\n"
-        f"export const GENERATED_EXTENSION_METADATA_SHA256 = {json.dumps(metadata['extension-catalog-sha256'])} as const;\n\n"
-        f"export const GENERATED_EXTENSION_METADATA = {json.dumps(rows, indent=2, sort_keys=True)} as const satisfies readonly GeneratedExtensionMetadata[];\n\n"
-        "export function generatedExtensionBySqlName(sqlName: string): GeneratedExtensionMetadata | undefined {\n"
-        "  return GENERATED_EXTENSION_METADATA.find((extension) => extension.sqlName === sqlName);\n"
-        "}\n\n"
-        "export function generatedSharedPreloadLibraries(extensionSqlNames: readonly string[]): string[] {\n"
-        "  const libraries = new Set();\n"
-        "  for (const sqlName of extensionSqlNames) {\n"
-        "    const extension = generatedExtensionBySqlName(sqlName);\n"
-        "    for (const library of extension?.sharedPreloadLibraries ?? []) {\n"
-        "      libraries.add(library);\n"
-        "    }\n"
-        "  }\n"
-        "  return [...libraries].sort();\n"
-        "}\n"
-    )
-    return format_typescript_source(source, GENERATED_TS_SDK_MODULE)
-
-
-def generated_mobile_extension_smoke_module(metadata: dict) -> str:
-    extension_plan = [
-        {
-            "sqlName": row["sql-name"],
-            "createsExtension": row["creates-extension"],
-            "selectedExtensionDependencies": row["selected-extension-dependencies"],
-        }
-        for row in metadata.get("extensions", [])
-    ]
-    recipes = {
-        row["sql-name"]: split_smoke_statements(
-            (SMOKE_RECIPE_ROOT / f"{row['sql-name']}.sql").read_text(
-                encoding="utf-8"
-            )
-        )
-        for row in metadata.get("extensions", [])
-    }
-    source = (
-        f"// This file is generated by {CHECK_EXTENSION_MODEL_PATH}.\n"
-        "// Do not edit by hand. It belongs only to installed mobile qualification.\n\n"
-        "export type GeneratedMobileExtensionProof = {\n"
-        "  readonly sqlName: string;\n"
-        "  readonly createsExtension: boolean;\n"
-        "  readonly selectedExtensionDependencies: readonly string[];\n"
-        "};\n\n"
-        f"export const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = {json.dumps(metadata['extension-catalog-sha256'])} as const;\n\n"
-        f"export const GENERATED_MOBILE_EXTENSION_PLAN = {json.dumps(extension_plan, indent=2)} as const satisfies readonly GeneratedMobileExtensionProof[];\n\n"
-        f"export const GENERATED_MOBILE_EXTENSION_SMOKE = {json.dumps(recipes, indent=2, sort_keys=True)} as const satisfies Readonly>;\n"
-    )
-    return format_typescript_source(source, GENERATED_MOBILE_SMOKE_MODULE)
-
-
-def generated_kotlin_extension_module(metadata: dict) -> str:
-    rows = sorted(metadata.get("extensions", []), key=lambda row: str(row["sql-name"]))
-    body = "\n".join(
-        "    "
-        + json.dumps(str(row["sql-name"]))
-        + " to GeneratedExtensionRuntimeContract("
-        + f"createsExtension = {'true' if row['creates-extension'] else 'false'}, "
-        + "nativeModuleStem = "
-        + (json.dumps(str(row["native-module-stem"])) if row["native-module-stem"] is not None else "null")
-        + "),"
-        for row in rows
-    )
-    return (
-        f"// This file is generated by {CHECK_EXTENSION_MODEL_PATH}.\n"
-        "// Do not edit by hand.\n\n"
-        "package dev.oliphaunt\n\n"
-        "internal data class GeneratedExtensionRuntimeContract(\n"
-        "    val createsExtension: Boolean,\n"
-        "    val nativeModuleStem: String?,\n"
-        ")\n\n"
-        "internal val generatedExtensionRuntimeContracts: Map = mapOf(\n"
-        f"{body}\n"
-        ")\n\n"
-        "internal val generatedExtensionSqlNames: Set = generatedExtensionRuntimeContracts.keys\n\n"
-        "internal fun generatedExtensionSqlNameExists(sqlName: String): Boolean = generatedExtensionSqlNames.contains(sqlName)\n"
-        "\n"
-        "internal fun generatedExtensionRuntimeContract(sqlName: String): GeneratedExtensionRuntimeContract? = generatedExtensionRuntimeContracts[sqlName]\n"
-    )
-
-
-def generated_kotlin_gradle_plugin_catalog(metadata: dict) -> str:
-    lines = [
-        f"# This file is generated by {CHECK_EXTENSION_MODEL_PATH}.",
-        "# Do not edit by hand.",
-        "schema=oliphaunt-android-extension-catalog-v2",
-        f"catalogSha256={metadata['extension-catalog-sha256']}",
-    ]
-    for row in sorted(metadata.get("extensions", []), key=lambda item: str(item["sql-name"])):
-        sql_name = str(row["sql-name"])
-        prefix = f"extension.{sql_name}"
-        lines.extend(
-            [
-                f"{prefix}.artifactProduct={row['artifact-product']}",
-                f"{prefix}.releaseProduct={row['release-product']}",
-                f"{prefix}.mavenGroup={row['maven-group']}",
-                f"{prefix}.mavenArtifact={row['maven-artifact']}",
-                f"{prefix}.runtimeBound={'true' if row['runtime-bound'] else 'false'}",
-                f"{prefix}.dependencies={','.join(row['selected-extension-dependencies'])}",
-            ]
-        )
-    return "\n".join(lines) + "\n"
-
-
-def rust_string_literal(value: str) -> str:
-    return json.dumps(value)
-
-
-def rust_variant_from_constant(value: str) -> str:
-    parts = [part for part in value.split("_") if part]
-    if not parts:
-        fail(f"invalid rust extension constant {value!r}")
-    return "".join(part.lower().capitalize() for part in parts)
-
-
-def rust_extension_expr(row: dict) -> str:
-    return f"Extension::{str(row['rust-constant'])}"
-
-
-def rust_extension_id_expr(row: dict) -> str:
-    return f"ExtensionId::{rust_variant_from_constant(str(row['rust-constant']))}"
-
-
-def rust_doc_comment(text: str, *, indent: str = "") -> str:
-    escaped = text.replace("*/", "* /")
-    return "\n".join(f"{indent}/// {line}" if line else f"{indent}///" for line in escaped.splitlines())
-
-
-def rust_array(
-    values: list[str],
-    *,
-    item_indent: str = "    ",
-    closing_indent: str = "",
-) -> str:
-    if not values:
-        return "&[]"
-    if len(values) <= 2 and all(len(value) <= 72 for value in values):
-        return f"&[{', '.join(values)}]"
-    rendered = "".join(f"{item_indent}{value},\n" for value in values)
-    return "&[\n" + rendered + closing_indent + "]"
-
-
-def rust_extension_slice(
-    rows: list[dict],
-    *,
-    item_indent: str = "    ",
-    closing_indent: str = "",
-) -> str:
-    return rust_array(
-        [rust_extension_expr(row) for row in rows],
-        item_indent=item_indent,
-        closing_indent=closing_indent,
-    )
-
-
-def rust_option_string(value: object) -> str:
-    if value is None or value == "":
-        return "None"
-    if not isinstance(value, str):
-        fail(f"Rust string option must be a string or null, got {value!r}")
-    return f"Some({rust_string_literal(value)})"
-
-
-def rust_string_slice(
-    values: list[str],
-    *,
-    item_indent: str = "    ",
-    closing_indent: str = "",
-) -> str:
-    return rust_array(
-        [rust_string_literal(value) for value in values],
-        item_indent=item_indent,
-        closing_indent=closing_indent,
-    )
-
-
-def rust_runtime_environment_slice(
-    values: list[dict],
-    *,
-    item_indent: str = "    ",
-    closing_indent: str = "",
-) -> str:
-    if len(values) == 1:
-        value = values[0]
-        field_indent = item_indent
-        return (
-            "&[ExtensionRuntimeEnvironment {\n"
-            f"{field_indent}name: {rust_string_literal(value['name'])},\n"
-            f"{field_indent}relative_path: {rust_string_literal(value['path'])},\n"
-            f"{field_indent}required_file: {rust_string_literal(value['required_file'])},\n"
-            f"{closing_indent}}}]"
-        )
-    return rust_array(
-        [
-            "ExtensionRuntimeEnvironment { "
-            f"name: {rust_string_literal(value['name'])}, "
-            f"relative_path: {rust_string_literal(value['path'])}, "
-            f"required_file: {rust_string_literal(value['required_file'])} "
-            "}"
-            for value in values
-        ],
-        item_indent=item_indent,
-        closing_indent=closing_indent,
-    )
-
-
-def rust_extension_dependency_slice(
-    values: list[str],
-    rows_by_sql_name: dict[str, dict],
-    *,
-    item_indent: str = "    ",
-    closing_indent: str = "",
-) -> str:
-    if not values:
-        return "&[]"
-    dependencies = []
-    for value in values:
-        dependency = rows_by_sql_name.get(value)
-        if dependency is None:
-            fail(f"generated Rust dependency {value!r} is not a known Rust extension row")
-        dependencies.append(rust_extension_expr(dependency))
-    return rust_array(
-        dependencies,
-        item_indent=item_indent,
-        closing_indent=closing_indent,
-    )
-
-
-def generated_rust_extension_rows(catalog: dict) -> list[dict]:
-    rows = []
-    release_metadata = extension_metadata_by_sql_name()
-    public_sql_names = {
-        extension.get("sql-name", extension.get("id"))
-        for extension in catalog.get("extensions", [])
-        if isinstance(extension, dict)
-    }
-    for extension in catalog.get("extensions", []):
-        sql_name = str(extension.get("sql-name", extension.get("id")))
-        release = release_metadata.get(sql_name)
-        if release is None:
-            fail(f"release graph has no exact release owner for catalogued Rust extension {sql_name}")
-        rows.append(
-            {
-                "id": extension.get("id"),
-                "sql-name": sql_name,
-                "artifact-product": release["artifactProduct"],
-                "release-product": release["releaseProduct"],
-                "rust-constant": extension.get("rust-constant"),
-                "creates-extension": bool((extension.get("lifecycle") or {}).get("create-extension")),
-                "native-module-stem": native_module_stem(extension),
-                "selected-extension-dependencies": sorted(
-                    dependency
-                    for dependency in (extension.get("dependencies") or [])
-                    if dependency in public_sql_names
-                ),
-                "runtime-share-data-files": runtime_share_data_files(
-                    extension_data_files_from_recipe(extension)
-                ),
-                "shared-preload-libraries": shared_preload_libraries(extension),
-                "first-party": True,
-                "extension-sql-file-prefixes": extension_artifact_list_from_recipe(
-                    extension, "extension_sql_file_prefixes"
-                ),
-                "extension-sql-file-names": extension_artifact_list_from_recipe(
-                    extension, "extension_sql_file_names"
-                ),
-                "runtime-environment": extension_runtime_environment_from_recipe(extension),
-                "external-policy": None,
-            }
-        )
-    rows.sort(key=lambda row: str(row["sql-name"]))
-    for row in rows:
-        if not isinstance(row.get("rust-constant"), str) or not row["rust-constant"]:
-            fail(f"Rust generated extension row {row.get('id')} must define rust-constant")
-    return rows
-
-
-def rust_match(
-    function_name: str,
-    return_type: str,
-    rows: list[dict],
-    value_for_row,
-) -> str:
-    arms = [
-        f"        {rust_extension_id_expr(row)} => {value_for_row(row)},"
-        for row in rows
-    ]
-    signature = f"pub(super) const fn {function_name}(extension: Extension) -> {return_type} {{"
-    if len(signature) > 100:
-        signature = (
-            f"pub(super) const fn {function_name}(\n"
-            "    extension: Extension,\n"
-            f") -> {return_type} {{"
-        )
-    return (
-        "/// Generated extension metadata accessor.\n"
-        f"{signature}\n"
-        "    match extension.id {\n"
-        + "\n".join(arms)
-        + "\n    }\n"
-        "}\n"
-    )
-
-
-def generated_rust_extension_module(catalog: dict) -> str:
-    rows = generated_rust_extension_rows(catalog)
-    rows_by_sql_name = {str(row["sql-name"]): row for row in rows}
-
-    for row in rows:
-        if len(row["shared-preload-libraries"]) > 1:
-            fail(
-                f"Rust Extension::required_shared_preload_library supports one library; "
-                f"{row['sql-name']} declared {row['shared-preload-libraries']}"
-            )
-
-    text = [
-        f"// @generated by {CHECK_EXTENSION_MODEL_PATH} --write",
-        "// Do not edit by hand.",
-        "",
-        "use super::ExtensionRuntimeEnvironment;",
-        "",
-        "/// Native PostgreSQL 18 extension artifact that can be selected by an app.",
-        "#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]",
-        "pub struct Extension {",
-        "    id: ExtensionId,",
-        "}",
-        "",
-        "#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]",
-        "enum ExtensionId {",
-    ]
-
-    for row in rows:
-        doc_prefix = "PostgreSQL"
-        policy = row.get("external-policy")
-        if isinstance(policy, dict):
-            upstream = str(policy.get("upstream", ""))
-            if "pggraph" in upstream:
-                doc_prefix = "pgGraph"
-            elif "paradedb" in upstream:
-                doc_prefix = "ParadeDB"
-        text.extend(
-            [
-                rust_doc_comment(f"{doc_prefix} `{row['sql-name']}`.", indent="    "),
-                f"    {rust_variant_from_constant(str(row['rust-constant']))},",
-            ]
-        )
-
-    text.extend(
-        [
-            "}",
-            "",
-            "impl Extension {",
-        ]
-    )
-    for row in rows:
-        text.extend(
-            [
-                rust_doc_comment(
-                    f"Select the `{row['sql-name']}` artifact.", indent="    "
-                ),
-                f"    pub const {row['rust-constant']}: Self = Self {{",
-                f"        id: {rust_extension_id_expr(row)},",
-                "    };",
-            ]
-        )
-    text.extend(
-        [
-            "",
-            "    /// All PostgreSQL 18 extension artifacts known to the native SDK.",
-            f"    pub const ALL: &'static [Self] = {rust_extension_slice(rows, item_indent='        ', closing_indent='    ')};",
-            "}",
-            "",
-        rust_match("sql_name", "&'static str", rows, lambda row: rust_string_literal(row["sql-name"])),
-        rust_match(
-            "native_module_stem",
-            "Option<&'static str>",
-            rows,
-            lambda row: rust_option_string(row["native-module-stem"]),
-        ),
-        rust_match(
-            "creates_extension",
-            "bool",
-            rows,
-            lambda row: "true" if row["creates-extension"] else "false",
-        ),
-        rust_match(
-            "dependencies",
-            "&'static [Extension]",
-            rows,
-            lambda row: rust_extension_dependency_slice(
-                row["selected-extension-dependencies"],
-                rows_by_sql_name,
-                item_indent="            ",
-                closing_indent="        ",
-            ),
-        ),
-        rust_match(
-            "required_shared_preload_library",
-            "Option<&'static str>",
-            rows,
-            lambda row: rust_option_string(
-                row["shared-preload-libraries"][0]
-                if row["shared-preload-libraries"]
-                else None
-            ),
-        ),
-        rust_match(
-            "extension_data_files",
-            "&'static [&'static str]",
-            rows,
-            lambda row: rust_string_slice(
-                row["runtime-share-data-files"],
-                item_indent="            ",
-                closing_indent="        ",
-            ),
-        ),
-        rust_match(
-            "extension_sql_file_prefixes",
-            "&'static [&'static str]",
-            rows,
-            lambda row: rust_string_slice(
-                row.get("extension-sql-file-prefixes") or [],
-                item_indent="            ",
-                closing_indent="        ",
-            ),
-        ),
-        rust_match(
-            "extension_sql_file_names",
-            "&'static [&'static str]",
-            rows,
-            lambda row: rust_string_slice(
-                row.get("extension-sql-file-names") or [],
-                item_indent="            ",
-                closing_indent="        ",
-            ),
-        ),
-        rust_match(
-            "runtime_environment",
-            "&'static [ExtensionRuntimeEnvironment]",
-            rows,
-            lambda row: rust_runtime_environment_slice(
-                row.get("runtime-environment") or [],
-                item_indent="            ",
-                closing_indent="        ",
-            ),
-        ),
-    ]
-    )
-
-    return format_rust_source("\n".join(text))
-
-
-def validate_generated_text_file(path: Path, expected: str, write: bool) -> None:
-    if write:
-        path.parent.mkdir(parents=True, exist_ok=True)
-        path.write_text(expected, encoding="utf-8")
-        return
-    if not path.exists():
-        fail(f"{rel(path)} is missing; run {CHECK_EXTENSION_MODEL_WRITE_COMMAND}")
-    if path.read_text(encoding="utf-8") != expected:
-        fail(f"{rel(path)} is stale; run {CHECK_EXTENSION_MODEL_WRITE_COMMAND}")
-
-
-def generated_mobile_registry(catalog: dict) -> dict:
-    rows = []
-    for extension in catalog.get("extensions", []):
-        stem = native_module_stem(extension)
-        if stem is None:
-            continue
-        rows.append(
-            {
-                "id": extension.get("id"),
-                "sql-name": extension.get("sql-name", extension.get("id")),
-                "native-module-stem": stem,
-                "data-files": extension_data_files_from_recipe(extension),
-                "static-registry-required": True,
-            }
-        )
-    rows.sort(key=lambda row: (str(row["sql-name"]), str(row["id"])))
-    return {
-        "format-version": 1,
-        "generated-from": [
-            {"name": "extension-catalog", "path": rel(CATALOG)},
-            {"name": "extension-definitions", "path": "src/extensions/external"},
-        ],
-        "modules": rows,
-    }
-
-
-def generated_mobile_static_specs(
-    catalog: dict,
-    *,
-    modules: list[dict] | None = None,
-) -> str:
-    catalog_by_sql_name = {
-        row.get("sql-name", row.get("id")): row
-        for row in catalog.get("extensions", [])
-        if isinstance(row, dict)
-    }
-    contrib_by_sql_name = {
-        row.get("sql-name"): row
-        for row in read_toml(CONTRIB_RECIPE).get("extensions", [])
-        if isinstance(row, dict)
-    }
-    rows = []
-    selected_modules = generated_mobile_registry(catalog)["modules"] if modules is None else modules
-    for module in selected_modules:
-        sql_name = module["sql-name"]
-        extension = catalog_by_sql_name.get(sql_name)
-        if extension is None:
-            fail(f"mobile static module {sql_name} has no generated catalog row")
-        if extension.get("source-kind") == "postgres-contrib":
-            contrib_dir = contrib_by_sql_name.get(sql_name, {}).get("contrib-dir")
-            if not isinstance(contrib_dir, str) or not contrib_dir:
-                fail(f"mobile static contrib module {sql_name} is missing contrib-dir")
-            source_kind = "contrib"
-            source_rel = f"contrib/{contrib_dir}"
-        else:
-            control_file = extension.get("control-file")
-            match = (
-                re.match(r"^(target/oliphaunt-sources/checkouts/[^/]+)/", control_file)
-                if isinstance(control_file, str)
-                else None
-            )
-            if match is None:
-                fail(
-                    f"mobile static external module {sql_name} cannot derive its source checkout "
-                    "from control-file"
-                )
-            source_kind = "external"
-            source_rel = match.group(1)
-        static_dependencies = ",".join(mobile_static_dependencies(sql_name))
-        ios_static_dependencies = ",".join(mobile_static_dependencies(sql_name, "ios_dependencies"))
-        android_static_dependencies = ",".join(mobile_static_dependencies(sql_name, "android_dependencies"))
-        include_dependencies = ",".join(mobile_static_include_dependencies(sql_name))
-        include_dirs = ",".join(mobile_static_include_dirs(sql_name))
-        cflags = ",".join(mobile_static_cflags(sql_name))
-        hash_source_dependencies = ",".join(mobile_static_hash_source_dependencies(sql_name))
-        ios_hash_source_dependencies = ",".join(
-            mobile_static_hash_source_dependencies(sql_name, "ios_dependencies")
-        )
-        android_hash_source_dependencies = ",".join(
-            mobile_static_hash_source_dependencies(sql_name, "android_dependencies")
-        )
-        hash_dirs = ",".join(mobile_static_hash_dirs(sql_name))
-        source_files = ",".join(mobile_static_source_files(sql_name))
-        source_recursive_dirs = ",".join(mobile_static_source_recursive_dirs(sql_name))
-        rows.append(
-            [
-                sql_name,
-                module["native-module-stem"],
-                source_kind,
-                source_rel,
-                static_dependencies,
-                ios_static_dependencies,
-                android_static_dependencies,
-                include_dependencies,
-                include_dirs,
-                cflags,
-                hash_source_dependencies,
-                ios_hash_source_dependencies,
-                android_hash_source_dependencies,
-                hash_dirs,
-                source_files,
-                source_recursive_dirs,
-            ]
-        )
-    rows.sort(key=lambda row: row[0])
-    lines = [
-        f"# @generated by {CHECK_EXTENSION_MODEL_PATH} --write",
-        (
-            "sql-name\tnative-module-stem\tsource-kind\tsource-rel"
-            "\tmobile-static-dependencies\tios-static-dependencies\tandroid-static-dependencies"
-                "\tinclude-dependencies\tinclude-dirs\tcflags"
-                "\thash-source-dependencies\tios-hash-source-dependencies"
-                "\tandroid-hash-source-dependencies\thash-dirs"
-                "\tsource-files\tsource-recursive-dirs"
-            ),
-        *["\t".join(row).rstrip("\t") for row in rows],
-        "",
-    ]
-    return "\n".join(lines)
-
-
-def generated_wasix_metadata(catalog: dict) -> dict:
-    rows = []
-    for extension in catalog.get("extensions", []):
-        sql_name = str(extension.get("sql-name", extension.get("id")))
-        component_closure = native_component_resolution(
-            sql_name,
-            "wasix",
-            "wasix-runtime",
-            "wasix-portable",
-        )
-        rows.append(
-            {
-                "id": extension.get("id"),
-                "sql-name": sql_name,
-                "archive": extension.get("archive") or f"extensions/{extension.get('sql-name', extension.get('id'))}.tar.zst",
-                "native-module-file": extension.get("native-module-file") or extension.get("module-file"),
-                "native-support-modules": target_native_support_modules(
-                    sql_name,
-                    "wasix",
-                ),
-                "native-components": component_closure["components"],
-                "native-link-units": component_closure["linkUnits"],
-                "native-runtime-files": component_closure["runtimeFiles"],
-                "dependencies": extension.get("dependencies") or [],
-                "load-order": extension.get("load-order") or [],
-                "lifecycle": extension.get("lifecycle") or {},
-            }
-        )
-    rows.sort(key=lambda row: (str(row["sql-name"]), str(row["id"])))
-    return {
-        "format-version": 1,
-        "generated-from": [
-            {"name": "extension-catalog", "path": rel(CATALOG)},
-            {"name": "native-components", "path": rel(NATIVE_COMPONENT_CONTRACT)},
-            {"name": "extension-definitions", "path": "src/extensions/external"},
-        ],
-        "extensions": rows,
-    }
-
-
-def validate_generated_file(path: Path, expected: dict, write: bool) -> None:
-    text = json_text(expected)
-    if write:
-        path.parent.mkdir(parents=True, exist_ok=True)
-        path.write_text(text, encoding="utf-8")
-        return
-    if not path.exists():
-        fail(f"{rel(path)} is missing; run {CHECK_EXTENSION_MODEL_WRITE_COMMAND}")
-    if path.read_text(encoding="utf-8") != text:
-        fail(f"{rel(path)} is stale; run {CHECK_EXTENSION_MODEL_WRITE_COMMAND}")
-    parsed = read_json(path)
-    if parsed.get("format-version") != 1:
-        fail(f"{rel(path)} must use format-version 1")
-
-
-def validate_generated_sdk_metadata(catalog: dict, write: bool) -> None:
-    metadata = generated_sdk_metadata(catalog)
-    ios_static_dependencies = generated_ios_static_dependencies(catalog)
-    validate_generated_file(GENERATED_SDK_METADATA, metadata, write)
-    validate_generated_file(
-        GENERATED_IOS_STATIC_DEPENDENCIES,
-        ios_static_dependencies,
-        write,
-    )
-    for obsolete in OBSOLETE_GENERATED_FILES:
-        if write:
-            obsolete.unlink(missing_ok=True)
-        elif obsolete.exists():
-            fail(f"obsolete generated file must be removed: {rel(obsolete)}")
-    validate_generated_text_file(
-        GENERATED_RUST_SDK_MODULE,
-        generated_rust_extension_module(catalog),
-        write,
-    )
-    validate_generated_text_file(
-        GENERATED_TS_SDK_MODULE,
-        generated_typescript_extension_module(metadata),
-        write,
-    )
-    validate_generated_text_file(
-        GENERATED_RN_SDK_MODULE,
-        generated_typescript_extension_module(metadata, ios_static_dependencies),
-        write,
-    )
-    validate_generated_text_file(
-        GENERATED_MOBILE_SMOKE_MODULE,
-        generated_mobile_extension_smoke_module(metadata),
-        write,
-    )
-    validate_generated_text_file(
-        GENERATED_KOTLIN_SDK_MODULE,
-        generated_kotlin_extension_module(metadata),
-        write,
-    )
-    validate_generated_text_file(
-        GENERATED_KOTLIN_GRADLE_PLUGIN_CATALOG,
-        generated_kotlin_gradle_plugin_catalog(metadata),
-        write,
-    )
-    validate_generated_file(GENERATED_MOBILE_REGISTRY, generated_mobile_registry(catalog), write)
-    validate_generated_text_file(
-        GENERATED_MOBILE_STATIC_SPECS,
-        generated_mobile_static_specs(catalog),
-        write,
-    )
-    validate_generated_file(GENERATED_WASIX_METADATA, generated_wasix_metadata(catalog), write)
-
-
-def json_text(value: dict) -> str:
-    return json.dumps(value, indent=2, sort_keys=True) + "\n"
-
-
-def catalog_extensions(catalog: dict) -> list[dict]:
-    rows = [extension for extension in catalog.get("extensions", []) if isinstance(extension, dict)]
-    rows.sort(key=lambda row: (str(row.get("sql-name", row.get("id"))), str(row.get("id"))))
-    return rows
-
-
-def write_evidence_files(catalog: dict) -> None:
-    """Regenerate the claim matrix without mutating observed evidence runs.
-
-    Evidence run JSON is an immutable observation.  A source change that makes
-    an existing run stale must stay red until a runtime harness records a new
-    run; deriving a fresh `passed` run from catalog metadata would counterfeit
-    provenance.
-    """
-    catalog_rows = catalog_extensions(catalog)
-    matrix_lines = [
-        "format-version = 1",
-        "source-digest-inputs = [",
-        *[f'  "{path}",' for path in source_digest_inputs()],
-        "]",
-        "",
-    ]
-    for extension in catalog_rows:
-        extension_id = validate_id(extension.get("id"), "catalog extension id")
-        matrix_lines.extend(
-            [
-                "[[claims]]",
-                f'extension = "{extension_id}"',
-                "postgres-major = 18",
-                'artifact-family = "wasix-runtime"',
-                'platform-targets = ["portable"]',
-                'runtime-modes = ["direct", "server", "restart", "dump-restore"]',
-                f'evidence-required = ["{WASIX_EVIDENCE_TIER}"]',
-                "",
-            ]
-        )
-    EVIDENCE_MATRIX.parent.mkdir(parents=True, exist_ok=True)
-    EVIDENCE_MATRIX.write_text("\n".join(matrix_lines).rstrip() + "\n", encoding="utf-8")
-
-
-def validate_evidence(catalog: dict, require_current: bool = False) -> dict:
-    for path in (EVIDENCE_MATRIX, EVIDENCE_RUN_SCHEMA, EVIDENCE_MATRIX_SCHEMA):
-        if not path.exists():
-            fail(f"missing required extension evidence file: {rel(path)}")
-    matrix = read_toml(EVIDENCE_MATRIX)
-    if matrix.get("format-version") != 1:
-        fail(f"{rel(EVIDENCE_MATRIX)} must use format-version = 1")
-    digest_inputs = normalized_rel_list(
-        matrix.get("source-digest-inputs"),
-        f"{rel(EVIDENCE_MATRIX)} source-digest-inputs",
-    )
-    if digest_inputs != source_digest_inputs():
-        fail(f"{rel(EVIDENCE_MATRIX)} source-digest-inputs must match the checker contract")
-    catalog_ids = {
-        validate_id(row.get("id"), "catalog extension")
-        for row in catalog_extensions(catalog)
-    }
-    claims = matrix.get("claims")
-    if not isinstance(claims, list) or not claims:
-        fail(f"{rel(EVIDENCE_MATRIX)} must declare [[claims]]")
-    claim_ids: set[str] = set()
-    for claim in claims:
-        extension_id = validate_id(claim.get("extension"), f"{rel(EVIDENCE_MATRIX)} claim extension")
-        if extension_id in claim_ids:
-            fail(f"{rel(EVIDENCE_MATRIX)} has duplicate claim for {extension_id}")
-        claim_ids.add(extension_id)
-        if claim.get("postgres-major") != 18:
-            fail(f"{rel(EVIDENCE_MATRIX)} claim {extension_id} must target postgres-major = 18")
-        for field in ("artifact-family", "platform-targets", "runtime-modes", "evidence-required"):
-            if field not in claim:
-                fail(f"{rel(EVIDENCE_MATRIX)} claim {extension_id} is missing {field}")
-    missing_claims = sorted(catalog_ids - claim_ids)
-    extra_claims = sorted(claim_ids - catalog_ids)
-    if missing_claims:
-        fail(f"{rel(EVIDENCE_MATRIX)} is missing claims for {missing_claims}")
-    if extra_claims:
-        fail(f"{rel(EVIDENCE_MATRIX)} claims support for unknown extensions {extra_claims}")
-
-    current_digest = source_digest(digest_inputs)
-    evidence: dict[tuple[str, str, str, str], dict[str, str]] = {}
-    latest: dict[tuple[str, str, str, str], dict] = {}
-    latest_order: dict[tuple[str, str, str, str], tuple[str, str, str]] = {}
-    run_files = sorted(EVIDENCE_RUNS.glob("*.json"))
-    if not run_files:
-        fail(f"{rel(EVIDENCE_RUNS)} must contain evidence run JSON files")
-    for run_file in run_files:
-        run = read_json(run_file)
-        if run.get("schema") != "oliphaunt-extension-evidence-v1":
-            fail(f"{rel(run_file)} has unsupported evidence schema")
-        run_digest = run.get("sourceDigest")
-        if not isinstance(run_digest, str) or re.fullmatch(r"sha256:[0-9a-f]{64}", run_digest) is None:
-            fail(f"{rel(run_file)} must define a valid sourceDigest")
-        run_digest_inputs = normalized_rel_list(
-            run.get("sourceDigestInputs"),
-            f"{rel(run_file)} sourceDigestInputs",
-        )
-        run_id = run.get("id")
-        if not isinstance(run_id, str) or not run_id:
-            fail(f"{rel(run_file)} must define a non-empty id")
-        observed_at = run.get("observedAt")
-        if not isinstance(observed_at, str) or not observed_at:
-            fail(f"{rel(run_file)} must define a non-empty observedAt")
-        collector = run.get("collector")
-        if not isinstance(collector, str) or not collector:
-            fail(f"{rel(run_file)} must define a non-empty collector")
-        run_status = run.get("status")
-        if run_status not in {"passed", "failed", "blocked"}:
-            fail(f"{rel(run_file)} has unsupported status {run_status!r}")
-        tier = run.get("evidenceTier")
-        if not isinstance(tier, str) or not tier:
-            fail(f"{rel(run_file)} must define evidenceTier")
-        source_commit = run.get("sourceCommit")
-        source_tree = run.get("sourceTree")
-        github = run.get("github")
-        if tier == WASIX_EVIDENCE_TIER:
-            if not isinstance(source_commit, str) or re.fullmatch(r"[0-9a-f]{40}", source_commit) is None:
-                fail(f"{rel(run_file)} {tier} evidence must define a full sourceCommit")
-            if not isinstance(source_tree, str) or re.fullmatch(r"[0-9a-f]{40}", source_tree) is None:
-                fail(f"{rel(run_file)} {tier} evidence must define a full sourceTree")
-            if not isinstance(github, dict):
-                fail(f"{rel(run_file)} {tier} evidence must define GitHub run provenance")
-            for field in ("repository", "workflow", "job"):
-                if not isinstance(github.get(field), str) or not github[field]:
-                    fail(f"{rel(run_file)} github.{field} must be a non-empty string")
-            for field in ("runId", "runAttempt"):
-                if not isinstance(github.get(field), int) or isinstance(github[field], bool) or github[field] < 1:
-                    fail(f"{rel(run_file)} github.{field} must be a positive integer")
-        results = run.get("results")
-        if not isinstance(results, list) or not results:
-            fail(f"{rel(run_file)} must define evidence results")
-        run_results: dict[tuple[str, str, str], dict[str, str]] = {}
-        for result in results:
-            extension_id = validate_id(result.get("extension"), f"{rel(run_file)} result extension")
-            sql_name = result.get("sqlName")
-            if not isinstance(sql_name, str) or not sql_name:
-                fail(f"{rel(run_file)} result {extension_id} must define sqlName")
-            if result.get("postgresMajor") != 18:
-                continue
-            family = result.get("artifactFamily")
-            target = result.get("platformTarget")
-            statuses = result.get("runtimeModeStatuses")
-            if not isinstance(family, str) or not isinstance(target, str) or not isinstance(statuses, dict):
-                fail(f"{rel(run_file)} result {extension_id} must define family, target, and runtimeModeStatuses")
-            if not statuses or any(
-                not isinstance(mode, str)
-                or not mode
-                or status not in EVIDENCE_STATUSES
-                for mode, status in statuses.items()
-            ):
-                fail(f"{rel(run_file)} result {extension_id} has invalid runtimeModeStatuses")
-            run_key = (extension_id, family, target)
-            if run_key in run_results:
-                fail(
-                    f"{rel(run_file)} has duplicate result for "
-                    f"{extension_id} {family}/{target}"
-                )
-            run_results[run_key] = statuses
-
-        # Evidence observations are immutable history. A run for an older
-        # semantic input set remains valid history, but it cannot satisfy a
-        # current CI support claim.
-        if (
-            run_digest != current_digest
-            or run_digest_inputs != digest_inputs
-            or run_status != "passed"
-        ):
-            continue
-        if tier == WASIX_EVIDENCE_TIER:
-            current_commit, current_tree = current_git_identity()
-            if source_commit != current_commit or source_tree != current_tree:
-                continue
-        for (extension_id, family, target), statuses in run_results.items():
-            key = (extension_id, tier, family, target)
-            order = (observed_at, run_id, rel(run_file))
-            if order <= latest_order.get(key, ("", "", "")):
-                continue
-            evidence[key] = statuses
-            latest_order[key] = order
-            latest[key] = {
-                "run-id": run_id,
-                "run-path": rel(run_file),
-                "evidence-tier": tier,
-                "artifact-family": family,
-                "platform-target": target,
-                "source-digest": current_digest,
-                "source-commit": source_commit,
-                "source-tree": source_tree,
-                "github": github,
-                "observed-at": observed_at,
-                "runtime-mode-statuses": statuses,
-            }
-
-    claim_rows = []
-    for claim in claims:
-        extension_id = claim["extension"]
-        tiers = claim["evidence-required"]
-        targets = claim["platform-targets"]
-        modes = claim["runtime-modes"]
-        family = claim["artifact-family"]
-        if not isinstance(tiers, list) or not isinstance(targets, list) or not isinstance(modes, list):
-            fail(f"{rel(EVIDENCE_MATRIX)} claim {extension_id} has invalid evidence target arrays")
-        accepted = []
-        missing = []
-        for tier in tiers:
-            for target in targets:
-                statuses = evidence.get((extension_id, tier, family, target))
-                missing_modes = [mode for mode in modes if statuses is None or statuses.get(mode) != "passed"]
-                if missing_modes:
-                    missing.append(
-                        {
-                            "evidence-tier": tier,
-                            "artifact-family": family,
-                            "platform-target": target,
-                            "runtime-modes": missing_modes,
-                        }
-                    )
-                    continue
-                accepted.append(latest[(extension_id, tier, family, target)])
-        if require_current and missing:
-            first = missing[0]
-            fail(
-                f"extension claim {extension_id} lacks current CI "
-                f"{first['evidence-tier']} evidence for "
-                f"{first['artifact-family']}/{first['platform-target']} modes "
-                f"{first['runtime-modes']}"
-            )
-        catalog_row = next((row for row in catalog.get("extensions", []) if row.get("id") == extension_id), {})
-        claim_rows.append(
-            {
-                "extension": extension_id,
-                "sql-name": catalog_row.get("sql-name", extension_id),
-                "postgres-major": claim.get("postgres-major"),
-                "artifact-family": family,
-                "platform-targets": targets,
-                "runtime-modes": modes,
-                "evidence-required": tiers,
-                "latest-accepted-evidence": accepted,
-                "missing-current-evidence": missing,
-            }
-        )
-
-    claim_rows.sort(key=lambda row: (str(row["sql-name"]), str(row["extension"])))
-    return {
-        "format-version": 1,
-        "qualification-authority": {
-            "kind": "exact-sha-ci",
-            "collector": "src/extensions/tools/collect-wasix-evidence.sh",
-        },
-        "generated-from": [
-            {"name": "extension-catalog", "path": rel(CATALOG)},
-            {"name": "evidence-matrix", "path": rel(EVIDENCE_MATRIX)},
-            {"name": "evidence-runs", "path": rel(EVIDENCE_RUNS)},
-        ],
-        "source-digest": current_digest,
-        "source-digest-inputs": digest_inputs,
-        "claims": claim_rows,
-    }
-
-
-def record_wasix_evidence_run(catalog: dict, run_id: str, observed_at: str) -> None:
-    if re.fullmatch(r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{6}Z-[a-z0-9-]+", run_id) is None:
-        fail(
-            "--record-wasix-evidence-run must use "
-            "YYYY-MM-DDTHHMMSSZ-lower-kebab-case"
-        )
-    if re.fullmatch(r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z", observed_at) is None:
-        fail("--observed-at must use UTC YYYY-MM-DDTHH:MM:SSZ")
-    output = EVIDENCE_RUNS / f"{run_id}.json"
-    if output.exists():
-        fail(f"refusing to overwrite immutable evidence run {rel(output)}")
-
-    required_github = {
-        "repository": os.environ.get("GITHUB_REPOSITORY", ""),
-        "workflow": os.environ.get("GITHUB_WORKFLOW", ""),
-        "job": os.environ.get("GITHUB_JOB", ""),
-        "runId": os.environ.get("GITHUB_RUN_ID", ""),
-        "runAttempt": os.environ.get("GITHUB_RUN_ATTEMPT", ""),
-    }
-    if os.environ.get("GITHUB_ACTIONS") != "true":
-        fail("full WASIX release evidence may only be recorded by the GitHub Actions collector")
-    for field in ("repository", "workflow", "job"):
-        if not required_github[field]:
-            fail(f"GitHub Actions evidence is missing {field}")
-    for field in ("runId", "runAttempt"):
-        if not str(required_github[field]).isdigit() or int(str(required_github[field])) < 1:
-            fail(f"GitHub Actions evidence has invalid {field}")
-    source_commit, source_tree = current_git_identity()
-    candidate_sha = os.environ.get("CI_HEAD_SHA", "")
-    if candidate_sha != source_commit:
-        fail(f"GitHub Actions CI_HEAD_SHA {candidate_sha!r} does not match checkout HEAD {source_commit}")
-    require_clean_evidence_inputs()
-
-    results = []
-    for extension in catalog_extensions(catalog):
-        results.append(
-            {
-                "extension": extension.get("id"),
-                "sqlName": extension.get("sql-name", extension.get("id")),
-                "postgresMajor": 18,
-                "artifactFamily": "wasix-runtime",
-                "platformTarget": "portable",
-                "runtimeModeStatuses": {
-                    "direct": "passed",
-                    "server": "passed",
-                    "restart": "passed",
-                    "dump-restore": "passed",
-                },
-            }
-        )
-    run = {
-        "schema": "oliphaunt-extension-evidence-v1",
-        "id": run_id,
-        "evidenceTier": WASIX_EVIDENCE_TIER,
-        "status": "passed",
-        "sourceDigest": source_digest(),
-        "sourceDigestInputs": source_digest_inputs(),
-        "sourceCommit": source_commit,
-        "sourceTree": source_tree,
-        "observedAt": observed_at,
-        "collector": "src/extensions/tools/collect-wasix-evidence.sh",
-        "github": {
-            "repository": required_github["repository"],
-            "workflow": required_github["workflow"],
-            "runId": int(str(required_github["runId"])),
-            "runAttempt": int(str(required_github["runAttempt"])),
-            "job": required_github["job"],
-        },
-        "notes": (
-            "Recorded only after the full WASIX catalog-extension direct, server, "
-            "restart, materialization, and dump/restore suites succeeded."
-        ),
-        "results": results,
-    }
-    EVIDENCE_RUNS.mkdir(parents=True, exist_ok=True)
-    output.write_text(json_text(run), encoding="utf-8")
-
-
-def evidence_table_text(catalog: dict, require_current: bool = False) -> str:
-    table = validate_evidence(catalog, require_current=require_current)
-    if table.get("format-version") != 1:
-        fail(f"generated {rel(EVIDENCE_TABLE)} must use format-version 1")
-    if not table.get("claims"):
-        fail(f"generated {rel(EVIDENCE_TABLE)} must define evidence claims")
-    return json_text(table)
-
-
-def write_evidence_summary(catalog: dict, require_current: bool = False) -> None:
-    """Rewrite only the deterministic evidence summary.
-
-    The claim matrix and observed evidence run records are inputs to this
-    projection. They are never created, updated, or removed here. A stale run
-    remains immutable history and cannot become current by regenerating this
-    summary.
-    """
-    expected = evidence_table_text(catalog, require_current=require_current)
-    EVIDENCE_TABLE.parent.mkdir(parents=True, exist_ok=True)
-    EVIDENCE_TABLE.write_text(expected, encoding="utf-8")
-
-
-def validate_evidence_table(catalog: dict, write: bool, require_current: bool = False) -> None:
-    expected = evidence_table_text(catalog, require_current=require_current)
-    if write:
-        EVIDENCE_TABLE.parent.mkdir(parents=True, exist_ok=True)
-        EVIDENCE_TABLE.write_text(expected, encoding="utf-8")
-        return
-    if not EVIDENCE_TABLE.exists():
-        fail(
-            f"{rel(EVIDENCE_TABLE)} is missing; run "
-            f"{CHECK_EXTENSION_MODEL_WRITE_EVIDENCE_SUMMARY_COMMAND}"
-        )
-    actual = EVIDENCE_TABLE.read_text(encoding="utf-8")
-    if actual != expected:
-        fail(
-            f"{rel(EVIDENCE_TABLE)} is stale; run "
-            f"{CHECK_EXTENSION_MODEL_WRITE_EVIDENCE_SUMMARY_COMMAND}"
-        )
-    table = read_json(EVIDENCE_TABLE)
-    if table.get("format-version") != 1:
-        fail(f"{rel(EVIDENCE_TABLE)} must use format-version 1")
-    if not table.get("claims"):
-        fail(f"{rel(EVIDENCE_TABLE)} must define evidence claims")
-
-
-def run_xtask_check() -> None:
-    result = subprocess.run(
-        ["cargo", "run", "-p", "xtask", "--", "extensions", "check"],
-        cwd=ROOT,
-        check=False,
-    )
-    if result.returncode != 0:
-        raise SystemExit(result.returncode)
-
-
-def self_test() -> None:
-    digest_inputs = set(source_digest_inputs())
-    for domain in PRODUCTION_THIRD_PARTY_DOMAINS:
-        for path in (THIRD_PARTY_ROOT / domain).glob("**/*.toml"):
-            if path.is_file() and rel(path) not in digest_inputs:
-                fail(
-                    "self-test expected production third-party source pin in extension "
-                    f"digest inputs: {rel(path)}"
-                )
-    nonproduction_third_party_inputs = sorted(
-        path
-        for path in digest_inputs
-        if path.startswith("src/sources/third-party/")
-        and path.split("/", 4)[3] not in PRODUCTION_THIRD_PARTY_DOMAINS
-    )
-    if nonproduction_third_party_inputs:
-        fail(
-            "self-test expected nonproduction source pins to stay outside extension digest "
-            "inputs: " + ", ".join(nonproduction_third_party_inputs)
-        )
-    for path in [
-        "src/extensions/external/vector/VERSION",
-        "src/extensions/external/vector/CHANGELOG.md",
-        "src/extensions/external/vector/release.toml",
-    ]:
-        if path in digest_inputs:
-            fail(f"self-test expected release/package envelope metadata to be excluded from source digest inputs: {path}")
-    for path in [
-        "src/extensions/external/postgis/recipe.toml",
-        "src/extensions/catalog/native-components.toml",
-        "src/shared/fixtures/extensions/postgis.sql",
-    ]:
-        if path not in digest_inputs:
-            fail(f"self-test expected source recipe input to stay in source digest inputs: {path}")
-
-    with TemporaryDirectory() as tmp:
-        obsolete_root = Path(tmp)
-        obsolete = obsolete_root / "external/vector/targets/artifacts.toml"
-        obsolete.parent.mkdir(parents=True)
-        obsolete.write_text("obsolete = true\n", encoding="utf-8")
-        try:
-            validate_no_obsolete_extension_files(obsolete_root)
-        except SystemExit:
-            pass
-        else:
-            fail("self-test expected an obsolete per-extension artifact manifest to fail")
-
-    originals = {
-        "EVIDENCE_MATRIX": globals()["EVIDENCE_MATRIX"],
-        "EVIDENCE_RUN_SCHEMA": globals()["EVIDENCE_RUN_SCHEMA"],
-        "EVIDENCE_MATRIX_SCHEMA": globals()["EVIDENCE_MATRIX_SCHEMA"],
-        "EVIDENCE_RUNS": globals()["EVIDENCE_RUNS"],
-        "EVIDENCE_TABLE": globals()["EVIDENCE_TABLE"],
-    }
-    catalog = {"extensions": [{"id": "vector", "sql-name": "vector"}]}
-    try:
-        with TemporaryDirectory() as tmp:
-            root = Path(tmp)
-            globals()["EVIDENCE_MATRIX"] = root / "missing.toml"
-            globals()["EVIDENCE_RUN_SCHEMA"] = root / "run.schema.json"
-            globals()["EVIDENCE_MATRIX_SCHEMA"] = root / "matrix.schema.json"
-            globals()["EVIDENCE_RUNS"] = root / "runs"
-            globals()["EVIDENCE_RUN_SCHEMA"].write_text("{}\n", encoding="utf-8")
-            globals()["EVIDENCE_MATRIX_SCHEMA"].write_text("{}\n", encoding="utf-8")
-            globals()["EVIDENCE_RUNS"].mkdir()
-            try:
-                validate_evidence(catalog)
-            except SystemExit:
-                pass
-            else:
-                fail("self-test expected missing evidence matrix to fail")
-
-        with TemporaryDirectory() as tmp:
-            root = Path(tmp)
-            globals()["EVIDENCE_MATRIX"] = root / "matrix.toml"
-            globals()["EVIDENCE_RUN_SCHEMA"] = root / "run.schema.json"
-            globals()["EVIDENCE_MATRIX_SCHEMA"] = root / "matrix.schema.json"
-            globals()["EVIDENCE_RUNS"] = root / "runs"
-            globals()["EVIDENCE_TABLE"] = root / "generated" / "extension-evidence.json"
-            globals()["EVIDENCE_RUNS"].mkdir()
-            globals()["EVIDENCE_RUN_SCHEMA"].write_text("{}\n", encoding="utf-8")
-            globals()["EVIDENCE_MATRIX_SCHEMA"].write_text("{}\n", encoding="utf-8")
-            globals()["EVIDENCE_MATRIX"].write_text(
-                "\n".join(
-                    [
-                        "format-version = 1",
-                        "source-digest-inputs = [",
-                        *[f'  "{path}",' for path in source_digest_inputs()],
-                        "]",
-                        "",
-                        "[[claims]]",
-                        'extension = "vector"',
-                        "postgres-major = 18",
-                        'artifact-family = "wasix-runtime"',
-                        'platform-targets = ["portable"]',
-                        'runtime-modes = ["direct"]',
-                        'evidence-required = ["self-test"]',
-                        "",
-                    ]
-                ),
-                encoding="utf-8",
-            )
-            stale_run = globals()["EVIDENCE_RUNS"] / "stale.json"
-            stale_run.write_text(
-                json_text(
-                    {
-                        "schema": "oliphaunt-extension-evidence-v1",
-                        "id": "stale",
-                        "evidenceTier": "self-test",
-                        "status": "passed",
-                        "sourceDigest": f"sha256:{'0' * 64}",
-                        "sourceDigestInputs": source_digest_inputs(),
-                        "observedAt": "2026-01-01T00:00:00Z",
-                        "collector": "self-test",
-                        "results": [
-                            {
-                                "extension": "vector",
-                                "sqlName": "vector",
-                                "postgresMajor": 18,
-                                "artifactFamily": "wasix-runtime",
-                                "platformTarget": "portable",
-                                "runtimeModeStatuses": {"direct": "passed"},
-                            }
-                        ],
-                    }
-                ),
-                encoding="utf-8",
-            )
-            table = validate_evidence(catalog)
-            if not table["claims"][0]["missing-current-evidence"]:
-                fail("self-test expected stale evidence to remain history without qualifying current source")
-            try:
-                validate_evidence(catalog, require_current=True)
-            except SystemExit:
-                pass
-            else:
-                fail("self-test expected current-CI qualification to reject stale evidence")
-
-            matrix_before = globals()["EVIDENCE_MATRIX"].read_bytes()
-            run_before = stale_run.read_bytes()
-            write_evidence_summary(catalog)
-            if globals()["EVIDENCE_MATRIX"].read_bytes() != matrix_before:
-                fail("self-test evidence-summary write mutated the claim matrix")
-            if stale_run.read_bytes() != run_before:
-                fail("self-test evidence-summary write mutated an observed run")
-            written = read_json(globals()["EVIDENCE_TABLE"])
-            if written != table:
-                fail("self-test evidence-summary write did not persist the validated projection")
-            actual_files = {
-                path.relative_to(root).as_posix()
-                for path in root.rglob("*")
-                if path.is_file()
-            }
-            expected_files = {
-                "generated/extension-evidence.json",
-                "matrix.schema.json",
-                "matrix.toml",
-                "run.schema.json",
-                "runs/stale.json",
-            }
-            if actual_files != expected_files:
-                fail(
-                    "self-test evidence-summary write changed the evidence file inventory: "
-                    f"missing={sorted(expected_files - actual_files)}, "
-                    f"extra={sorted(actual_files - expected_files)}"
-                )
-    finally:
-        for name, value in originals.items():
-            globals()[name] = value
-
-
-def main() -> None:
-    parser = argparse.ArgumentParser()
-    mutation = parser.add_mutually_exclusive_group()
-    mutation.add_argument(
-        "--write",
-        action="store_true",
-        help="regenerate all derived extension metadata",
-    )
-    mutation.add_argument(
-        "--write-evidence",
-        action="store_true",
-        help=(
-            "regenerate the evidence claim matrix and deterministic summary; observed run files "
-            "are immutable"
-        ),
-    )
-    mutation.add_argument(
-        "--write-evidence-summary",
-        action="store_true",
-        help=(
-            "rewrite only generated extension-evidence.json from the claim matrix and immutable "
-            "observed runs; never mutate either input"
-        ),
-    )
-    mutation.add_argument(
-        "--record-wasix-evidence-run",
-        metavar="RUN_ID",
-        help="record an immutable full WASIX lifecycle run after the collector succeeds",
-    )
-    parser.add_argument("--observed-at", help="UTC timestamp for --record-wasix-evidence-run")
-    parser.add_argument(
-        "--require-current-evidence",
-        action="store_true",
-        help="fail unless every claim has passing evidence for the current semantic source digest",
-    )
-    parser.add_argument("--check", action="store_true", help="validate generated files without writing")
-    parser.add_argument("--self-test", action="store_true", help="run negative validation tests")
-    args = parser.parse_args()
-
-    if args.self_test:
-        self_test()
-        print("extension model self-tests passed")
-        return
-
-    for path in (
-        RECIPE_SCHEMA,
-        SOURCE_CATALOG,
-        CATALOG,
-        CONTRIB_RECIPE,
-        SMOKE_RECIPE_ROOT,
-    ):
-        if not path.exists():
-            fail(f"missing required extension model file: {rel(path)}")
-
-    validate_no_obsolete_extension_files()
-    catalog = read_json(CATALOG)
-    if args.record_wasix_evidence_run:
-        if not args.observed_at:
-            fail("--record-wasix-evidence-run requires --observed-at")
-        record_wasix_evidence_run(catalog, args.record_wasix_evidence_run, args.observed_at)
-        write_evidence_files(catalog)
-    elif args.observed_at:
-        fail("--observed-at requires --record-wasix-evidence-run")
-    # A catalog transition changes the evidence claim matrix and every
-    # SDK projection together. Keep --write a one-command
-    # fixed point while preserving immutable observed evidence run JSON.
-    if args.write or args.write_evidence:
-        write_evidence_files(catalog)
-    validate_extension_release_metadata()
-    validate_contrib_recipe(catalog)
-    validate_native_component_inventory(catalog)
-    validate_external_recipes(catalog)
-    validate_extension_smoke_recipes(catalog)
-    evidence_summary_pending = args.write_evidence_summary
-    if evidence_summary_pending:
-        # Validate the complete projection now, but defer the only write until
-        # every other model and xtask check has passed.
-        evidence_table_text(catalog, require_current=args.require_current_evidence)
-    else:
-        validate_evidence_table(
-            catalog,
-            write=args.write or args.write_evidence or bool(args.record_wasix_evidence_run),
-            require_current=args.require_current_evidence,
-        )
-    validate_generated_sdk_metadata(catalog, write=args.write)
-    if not args.write:
-        run_xtask_check()
-    if evidence_summary_pending:
-        write_evidence_summary(catalog, require_current=args.require_current_evidence)
-    print("extension model checks passed")
-
-
-if __name__ == "__main__":
-    main()
diff --git a/src/extensions/tools/check-extension-model.sh b/src/extensions/tools/check-extension-model.sh
new file mode 100755
index 000000000..316c9e8f8
--- /dev/null
+++ b/src/extensions/tools/check-extension-model.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+cd "$root"
+mkdir -p target
+stage="$(mktemp -d "$root/target/extension-model.XXXXXX")"
+trap 'rm -rf "$stage"' EXIT
+mode=check
+for arg in "$@"; do
+  case "$arg" in
+    --write) mode=write ;;
+    --write-evidence) mode=evidence ;;
+    --write-evidence-summary) mode=summary ;;
+    --record-wasix-evidence-run) mode=record ;;
+  esac
+done
+identity=(--source-commit "$(git rev-parse 'HEAD^{commit}')" --source-tree "$(git rev-parse 'HEAD^{tree}')")
+if [ "$mode" = record ]; then
+  bash tools/dev/bun.sh src/extensions/tools/check-extension-model.mts --source-inputs > "$stage/inputs"
+  inputs=()
+  while IFS= read -r file; do inputs+=("$file"); done < "$stage/inputs"
+  if [ -z "$(git status --porcelain=v1 -- "${inputs[@]}")" ]; then identity+=(--clean-inputs); fi
+fi
+bash tools/dev/bun.sh tools/release/query.mts extension-metadata > "$stage/releases.json"
+bash tools/dev/bun.sh src/extensions/tools/check-extension-model.mts --stage "$stage" --release-metadata "$stage/releases.json" "${identity[@]}" "$@" > "$stage/outputs"
+# Format staged source before comparing or installing any generated file.
+while IFS= read -r file; do
+  case "$file" in
+    *.rs) rustfmt "$stage/$file" ;;
+    *.ts)
+      bun x --no-install biome format --stdin-file-path "$file" < "$stage/$file" > "$stage/formatted" || {
+        cat "$stage/formatted" >&2
+        exit 1
+      }
+      mv "$stage/formatted" "$stage/$file"
+      ;;
+  esac
+done < "$stage/outputs"
+while IFS= read -r file; do
+  case "$mode:$file" in
+    write:*|evidence:src/extensions/evidence/matrix.toml|evidence:src/extensions/generated/docs/extension-evidence.json|summary:src/extensions/generated/docs/extension-evidence.json|record:src/extensions/evidence/*|record:src/extensions/generated/docs/extension-evidence.json) ;;
+    *) cmp "$file" "$stage/$file" || { echo "$file is stale; run bash src/extensions/tools/check-extension-model.sh --write" >&2; exit 1; } ;;
+  esac
+done < "$stage/outputs"
+while IFS= read -r file; do
+  case "$mode:$file" in
+    record:src/extensions/evidence/runs/*)
+      # Same-filesystem link publishes a complete record and cannot overwrite history.
+      ln "$stage/$file" "$file"
+      ;;
+    write:*|evidence:src/extensions/evidence/matrix.toml|evidence:src/extensions/generated/docs/extension-evidence.json|summary:src/extensions/generated/docs/extension-evidence.json|record:src/extensions/evidence/matrix.toml|record:src/extensions/generated/docs/extension-evidence.json)
+      cp "$stage/$file" "$file"
+      ;;
+  esac
+done < "$stage/outputs"
+legal_mode=--check
+[ "$mode" != write ] || legal_mode=--write
+bash tools/dev/bun.sh src/extensions/tools/android-extension-legal-catalog.mts "$legal_mode"
+echo 'extension model checks passed'
diff --git a/src/extensions/tools/collect-wasix-evidence.sh b/src/extensions/tools/collect-wasix-evidence.sh
index ba4f3efc0..c18df1ce0 100755
--- a/src/extensions/tools/collect-wasix-evidence.sh
+++ b/src/extensions/tools/collect-wasix-evidence.sh
@@ -5,12 +5,13 @@ script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
 root="$(git -C "$script_dir" rev-parse --show-toplevel)"
 cd "$root"
 
-for command in pnpm python3 rustfmt; do
+for command in bun rustfmt; do
   if ! command -v "$command" >/dev/null 2>&1; then
     echo "missing required evidence command: $command" >&2
     exit 1
   fi
 done
+bun x --no-install biome --version
 
 for name in GITHUB_ACTIONS GITHUB_REPOSITORY GITHUB_WORKFLOW GITHUB_RUN_ID GITHUB_RUN_ATTEMPT GITHUB_JOB CI_HEAD_SHA; do
   if [ -z "${!name:-}" ]; then
@@ -25,14 +26,17 @@ fi
 
 run_id="${1:-$(date -u +%Y-%m-%dT%H%M%SZ)-wasix-full-lifecycle}"
 observed_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
+OLIPHAUNT_EXTENSION_EVIDENCE_DIR="$(mktemp -d)"
+export OLIPHAUNT_EXTENSION_EVIDENCE_DIR
+trap 'rm -rf "$OLIPHAUNT_EXTENSION_EVIDENCE_DIR"' EXIT
 
 # This command exercises every catalogued extension in direct, server, restart,
-# materialization, and dump/restore modes.  The record command is deliberately
+# materialization, and physical backup/restore modes. The record command is deliberately
 # after it so a failing or interrupted run cannot produce passed evidence.
-bash src/runtimes/liboliphaunt/wasix/tools/runtime-smoke.sh regression
-tools/dev/bun.sh src/extensions/tools/check-extension-model.mjs \
+bash src/runtimes/liboliphaunt-wasix/tools/runtime-smoke.sh regression
+bash src/extensions/tools/check-extension-model.sh \
   --record-wasix-evidence-run "$run_id" \
   --observed-at "$observed_at"
-tools/dev/bun.sh src/extensions/tools/check-extension-model.mjs --check --require-current-evidence
+bash src/extensions/tools/check-extension-model.sh --check --require-current-evidence
 
 echo "recorded immutable WASIX extension evidence run: $run_id"
diff --git a/src/extensions/tools/extension-artifact-archive-policy.mts b/src/extensions/tools/extension-artifact-archive-policy.mts
new file mode 100644
index 000000000..016861ee8
--- /dev/null
+++ b/src/extensions/tools/extension-artifact-archive-policy.mts
@@ -0,0 +1,113 @@
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+
+const ROOT = path.resolve(import.meta.dirname, '../../..');
+export const EXTENSION_ARTIFACT_ARCHIVE_POLICY_PATH =
+  'src/extensions/contracts/extension-artifact-archive-policy.properties';
+
+const EXPECTED_SCHEMA = 'oliphaunt-extension-artifact-archive-policy-v1';
+const EXPECTED_KEYS = Object.freeze([
+  'schema',
+  'maxCompressedBytes',
+  'maxExpandedBytes',
+  'maxMemberBytes',
+  'maxMembers',
+]);
+
+function fail(message) {
+  throw new Error(`extension artifact archive policy: ${message}`);
+}
+
+function parseCanonicalProperties(text) {
+  if (
+    text.includes('\r') ||
+    !text.endsWith('\n') ||
+    text.endsWith('\n\n') ||
+    text !== text.normalize('NFC')
+  ) {
+    fail('must use canonical NFC UTF-8 key=value text with LF lines and one final newline');
+  }
+  const values = new Map();
+  for (const [index, line] of text.slice(0, -1).split('\n').entries()) {
+    const separator = line.indexOf('=');
+    if (separator <= 0 || separator === line.length - 1) {
+      fail(`line ${index + 1} must be a non-empty key=value pair`);
+    }
+    const key = line.slice(0, separator);
+    const value = line.slice(separator + 1);
+    if (values.has(key)) fail(`repeats property ${key}`);
+    values.set(key, value);
+  }
+  if (JSON.stringify([...values.keys()]) !== JSON.stringify(EXPECTED_KEYS)) {
+    fail(`property keys must be exactly ${EXPECTED_KEYS.join(',')}`);
+  }
+  if (values.get('schema') !== EXPECTED_SCHEMA) {
+    fail(`schema must be ${EXPECTED_SCHEMA}`);
+  }
+  const positiveInteger = (key) => {
+    const value = Number(values.get(key));
+    if (!Number.isSafeInteger(value) || value <= 0 || String(value) !== values.get(key)) {
+      fail(`${key} must be a canonical positive safe integer`);
+    }
+    return value;
+  };
+  const policy = {
+    maxCompressedBytes: positiveInteger('maxCompressedBytes'),
+    maxExpandedBytes: positiveInteger('maxExpandedBytes'),
+    maxMemberBytes: positiveInteger('maxMemberBytes'),
+    maxMembers: positiveInteger('maxMembers'),
+  };
+  if (policy.maxMemberBytes > policy.maxExpandedBytes) {
+    fail('maxMemberBytes must not exceed maxExpandedBytes');
+  }
+  return Object.freeze(policy);
+}
+
+export const EXTENSION_ARTIFACT_ARCHIVE_POLICY = parseCanonicalProperties(
+  readFileSync(path.join(ROOT, EXTENSION_ARTIFACT_ARCHIVE_POLICY_PATH), 'utf8'),
+);
+
+export function validateExtensionArtifactArchivePlan(members, label = 'extension artifact') {
+  if (!Array.isArray(members) || members.length === 0) {
+    fail(`${label} must contain at least one regular member`);
+  }
+  if (members.length > EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMembers) {
+    fail(`${label} contains more than ${EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMembers} members`);
+  }
+  let expandedBytes = 1024;
+  for (const [index, member] of members.entries()) {
+    const bytes = member?.bytes;
+    const name =
+      typeof member?.name === 'string' && member.name.length > 0 ? member.name : `member ${index}`;
+    if (!Number.isSafeInteger(bytes) || bytes < 0) {
+      fail(`${label} ${name} has an invalid byte count`);
+    }
+    if (bytes > EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes) {
+      fail(
+        `${label} member ${name} exceeds ${EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes} bytes`,
+      );
+    }
+    const padded = Math.ceil(bytes / 512) * 512;
+    expandedBytes += 512 + padded;
+    if (!Number.isSafeInteger(expandedBytes)) {
+      fail(`${label} expanded size overflows a safe integer`);
+    }
+    if (expandedBytes > EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxExpandedBytes) {
+      fail(`${label} expands beyond ${EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxExpandedBytes} bytes`);
+    }
+  }
+  return expandedBytes;
+}
+
+export function validateExtensionArtifactCompressedBytes(bytes, label = 'extension artifact') {
+  if (
+    !Number.isSafeInteger(bytes) ||
+    bytes <= 0 ||
+    bytes > EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxCompressedBytes
+  ) {
+    fail(
+      `${label} compressed bytes must be between 1 and ${EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxCompressedBytes}`,
+    );
+  }
+  return bytes;
+}
diff --git a/src/extensions/tools/extension-evidence.mts b/src/extensions/tools/extension-evidence.mts
new file mode 100644
index 000000000..472bf021e
--- /dev/null
+++ b/src/extensions/tools/extension-evidence.mts
@@ -0,0 +1,367 @@
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { readFileSync } from 'node:fs';
+import {
+  catalogPath,
+  contribPath,
+  jsonText,
+  readJson,
+  readToml,
+} from './extension-projections.mts';
+
+type Row = Record;
+export const evidenceMatrixPath = 'src/extensions/evidence/matrix.toml';
+export const evidenceRunsPath = 'src/extensions/evidence/runs';
+export const evidenceTablePath = 'src/extensions/generated/docs/extension-evidence.json';
+const tier = 'wasix-full-lifecycle-v1';
+const collector = 'src/extensions/tools/collect-wasix-evidence.sh';
+const modes = ['direct', 'server', 'restart', 'backup-restore', 'materialization'];
+const statuses = new Set(['passed', 'failed', 'blocked', 'not-run']);
+const fullSha = (value: unknown) => typeof value === 'string' && /^[0-9a-f]{40}$/.test(value);
+const string = (value: unknown): value is string => typeof value === 'string' && value.length > 0;
+const list = (value: unknown): value is string[] => Array.isArray(value) && value.every(string);
+const id = (value: unknown): value is string =>
+  typeof value === 'string' && /^[a-z][a-z0-9_]*$/.test(value);
+const files = (pattern: string) =>
+  [...new Bun.Glob(pattern).scanSync({ cwd: '.', onlyFiles: true })].sort();
+
+export function sourceDigestInputs(): string[] {
+  const envelope = new Set(['CHANGELOG.md', 'VERSION', 'moon.yml', 'release.toml']);
+  return [
+    'src/third-party/postgres/source.toml',
+    'src/extensions/catalog/extensions.source.json',
+    'src/extensions/catalog/native-components.toml',
+    contribPath,
+    catalogPath,
+    'src/extensions/generated/contrib-build.tsv',
+    'src/extensions/generated/pgxs-build.tsv',
+    ...files('src/third-party/{icu,openssl}/source.toml')
+      .concat(files('src/runtimes/liboliphaunt-native/sources/*.toml'))
+      .concat(files('src/extensions/external/**/source.toml'))
+      .concat('src/database-resources/icu/source.toml')
+      .sort(),
+    ...files('src/extensions/external/**/*').filter(
+      (file) =>
+        !envelope.has(file.split('/').at(-1)!) &&
+        !file.endsWith('/source.toml') &&
+        !/\.test\.[cm]?ts$/.test(file),
+    ),
+    'src/test-fixtures/extensions/manifest.json',
+    ...files('src/test-fixtures/extensions/*.sql'),
+  ];
+}
+
+export function sourceDigest(
+  paths = sourceDigestInputs(),
+  overrides = new Map(),
+): string {
+  const digest = createHash('sha256');
+  for (const file of paths)
+    digest
+      .update(file)
+      .update('\0')
+      .update((overrides.get(file) ?? readFileSync(file, 'utf8')).replace(/\r\n?/g, '\n'))
+      .update('\0');
+  return `sha256:${digest.digest('hex')}`;
+}
+
+export function evidenceMatrix(catalog: Row): string {
+  return (
+    [
+      'format-version = 1',
+      'source-digest-inputs = [',
+      ...sourceDigestInputs().map((file) => `  ${JSON.stringify(file)},`),
+      ']',
+      '',
+      ...[...catalog.extensions]
+        .sort((a, b) => (a['sql-name'] < b['sql-name'] ? -1 : 1))
+        .flatMap((extension) => {
+          assert(id(extension.id), 'invalid extension evidence id');
+          return [
+            '[[claims]]',
+            `extension = "${extension.id}"`,
+            'postgres-major = 18',
+            'artifact-family = "wasix-runtime"',
+            'platform-targets = ["portable"]',
+            'runtime-modes = ["direct", "server", "restart", "backup-restore"]',
+            `evidence-required = ["${tier}"]`,
+            '',
+          ];
+        }),
+    ]
+      .join('\n')
+      .trimEnd() + '\n'
+  );
+}
+
+export function validateEvidenceRun(run: Row): void {
+  assert.equal(run.schema, 'oliphaunt-extension-evidence-v1', 'unsupported evidence schema');
+  assert(
+    typeof run.sourceDigest === 'string' && /^sha256:[0-9a-f]{64}$/.test(run.sourceDigest),
+    'invalid evidence digest',
+  );
+  assert(list(run.sourceDigestInputs), 'invalid evidence source inputs');
+  for (const field of ['id', 'observedAt', 'collector', 'evidenceTier'])
+    assert(string(run[field]), `missing evidence ${field}`);
+  assert(['passed', 'failed', 'blocked'].includes(run.status), 'invalid evidence status');
+  if (run.evidenceTier === tier) {
+    assert(
+      fullSha(run.sourceCommit) && fullSha(run.sourceTree),
+      'full lifecycle evidence needs exact commit and tree',
+    );
+    for (const field of ['repository', 'workflow', 'job'])
+      assert(string(run.github?.[field]), `missing GitHub ${field}`);
+    for (const field of ['runId', 'runAttempt'])
+      assert(
+        Number.isSafeInteger(run.github?.[field]) && run.github[field] > 0,
+        `invalid GitHub ${field}`,
+      );
+  }
+  assert(Array.isArray(run.results) && run.results.length, 'missing evidence results');
+  const seen = new Set();
+  for (const result of run.results) {
+    assert(id(result.extension) && string(result.sqlName), 'invalid evidence extension');
+    if (result.postgresMajor !== 18) continue;
+    assert(
+      string(result.artifactFamily) && string(result.platformTarget),
+      'invalid evidence target',
+    );
+    assert(
+      result.runtimeModeStatuses &&
+        typeof result.runtimeModeStatuses === 'object' &&
+        !Array.isArray(result.runtimeModeStatuses),
+      'missing runtime statuses',
+    );
+    const entries = Object.entries(result.runtimeModeStatuses);
+    assert(
+      entries.length &&
+        entries.every(([mode, status]) => string(mode) && statuses.has(status as string)),
+      'invalid runtime statuses',
+    );
+    const key = JSON.stringify([result.extension, result.artifactFamily, result.platformTarget]);
+    assert(!seen.has(key), `duplicate evidence result ${key}`);
+    seen.add(key);
+  }
+}
+
+export function evidenceTable(
+  catalog: Row,
+  matrix: Row,
+  runs: { path: string; run: Row }[],
+  identity: { commit: string; tree: string },
+  requireCurrent = false,
+  overrides = new Map(),
+): Row {
+  const inputs = sourceDigestInputs();
+  assert.equal(matrix['format-version'], 1, 'unsupported evidence matrix');
+  assert(list(matrix['source-digest-inputs']), 'missing evidence source inputs');
+  assert.deepEqual(
+    matrix['source-digest-inputs'].map((file: string) => file.replaceAll('\\', '/')),
+    inputs,
+    'stale evidence source inputs',
+  );
+  const catalogById = new Map(catalog.extensions.map((row: Row) => [row.id, row]));
+  const claims: Row[] = matrix.claims;
+  assert(Array.isArray(claims) && claims.length, 'missing evidence claims');
+  const claimIds = claims.map((claim) => claim.extension);
+  assert.equal(new Set(claimIds).size, claims.length, 'duplicate evidence claims');
+  assert.deepEqual(
+    [...claimIds].sort(),
+    [...catalogById.keys()].sort(),
+    'evidence claims must cover the extension catalog',
+  );
+  const digest = sourceDigest(inputs, overrides);
+  assert(runs.length, 'missing immutable evidence runs');
+  const accepted = new Map();
+  const order = new Map();
+  for (const { path, run } of runs) {
+    validateEvidenceRun(run);
+    if (
+      run.sourceDigest !== digest ||
+      JSON.stringify(run.sourceDigestInputs.map((file: string) => file.replaceAll('\\', '/'))) !==
+        JSON.stringify(inputs) ||
+      run.status !== 'passed'
+    )
+      continue;
+    if (
+      run.evidenceTier === tier &&
+      (run.sourceCommit !== identity.commit || run.sourceTree !== identity.tree)
+    )
+      continue;
+    for (const result of run.results) {
+      if (result.postgresMajor !== 18) continue;
+      assert.equal(
+        catalogById.get(result.extension)?.['sql-name'],
+        result.sqlName,
+        'current evidence SQL name differs from catalog',
+      );
+      const key = JSON.stringify([
+        result.extension,
+        run.evidenceTier,
+        result.artifactFamily,
+        result.platformTarget,
+      ]);
+      const nextOrder = [run.observedAt, run.id, path].join('\0');
+      if (nextOrder <= (order.get(key) ?? '')) continue;
+      order.set(key, nextOrder);
+      accepted.set(key, {
+        'run-id': run.id,
+        'run-path': path,
+        'evidence-tier': run.evidenceTier,
+        'artifact-family': result.artifactFamily,
+        'platform-target': result.platformTarget,
+        'source-digest': digest,
+        'source-commit': run.sourceCommit ?? null,
+        'source-tree': run.sourceTree ?? null,
+        github: run.github ?? null,
+        'observed-at': run.observedAt,
+        'runtime-mode-statuses': result.runtimeModeStatuses,
+      });
+    }
+  }
+  const rows = claims
+    .map((claim) => {
+      assert(id(claim.extension) && claim['postgres-major'] === 18, 'invalid evidence claim');
+      for (const field of ['evidence-required', 'platform-targets', 'runtime-modes'])
+        assert(list(claim[field]) && claim[field].length, `invalid claim ${field}`);
+      assert(string(claim['artifact-family']), 'missing claim artifact family');
+      const latest: Row[] = [],
+        missing: Row[] = [];
+      for (const required of claim['evidence-required'])
+        for (const target of claim['platform-targets']) {
+          const result = accepted.get(
+            JSON.stringify([claim.extension, required, claim['artifact-family'], target]),
+          );
+          const missingModes = claim['runtime-modes'].filter(
+            (mode: string) => result?.['runtime-mode-statuses'][mode] !== 'passed',
+          );
+          if (missingModes.length)
+            missing.push({
+              'evidence-tier': required,
+              'artifact-family': claim['artifact-family'],
+              'platform-target': target,
+              'runtime-modes': missingModes,
+            });
+          else latest.push(result!);
+        }
+      assert(
+        !requireCurrent || !missing.length,
+        `extension ${claim.extension} lacks current CI evidence: ${JSON.stringify(missing)}`,
+      );
+      return {
+        ...claim,
+        'sql-name': catalogById.get(claim.extension)!['sql-name'],
+        'latest-accepted-evidence': latest,
+        'missing-current-evidence': missing,
+      };
+    })
+    .sort((a, b) => (a['sql-name'] < b['sql-name'] ? -1 : 1));
+  return {
+    'format-version': 1,
+    'qualification-authority': { kind: 'exact-sha-ci', collector },
+    'generated-from': [
+      { name: 'extension-catalog', path: catalogPath },
+      { name: 'evidence-matrix', path: evidenceMatrixPath },
+      { name: 'evidence-runs', path: evidenceRunsPath },
+    ],
+    'source-digest': digest,
+    'source-digest-inputs': inputs,
+    claims: rows,
+  };
+}
+
+export function observedWasixModes(directory: string, sql: string): Record {
+  return Object.fromEntries(
+    modes.map((mode) => {
+      assert.equal(
+        readFileSync(`${directory}/${sql}.${mode}`, 'utf8'),
+        'passed\n',
+        `missing successful observation for ${sql}/${mode}`,
+      );
+      return [mode, 'passed'];
+    }),
+  );
+}
+
+export function recordedEvidence(
+  catalog: Row,
+  runId: string,
+  observedAt: string,
+  identity: { commit: string; tree: string },
+  cleanInputs: boolean,
+): Row {
+  assert(
+    /^\d{4}-\d{2}-\d{2}T\d{6}Z-[a-z0-9-]+$/.test(runId),
+    'run id must use YYYY-MM-DDTHHMMSSZ-lower-kebab-case',
+  );
+  assert(
+    /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(observedAt),
+    'observed-at must use UTC YYYY-MM-DDTHH:MM:SSZ',
+  );
+  assert.equal(
+    process.env.GITHUB_ACTIONS,
+    'true',
+    'full release evidence requires the GitHub Actions collector',
+  );
+  assert(fullSha(identity.commit) && fullSha(identity.tree), 'invalid checkout identity');
+  assert.equal(process.env.CI_HEAD_SHA, identity.commit, 'CI_HEAD_SHA differs from checkout');
+  assert(cleanInputs, 'refusing dirty exact-SHA evidence');
+  const directory = process.env.OLIPHAUNT_EXTENSION_EVIDENCE_DIR;
+  assert(directory, 'missing current run observations');
+  const run = {
+    schema: 'oliphaunt-extension-evidence-v1',
+    id: runId,
+    evidenceTier: tier,
+    status: 'passed',
+    sourceDigest: sourceDigest(),
+    sourceDigestInputs: sourceDigestInputs(),
+    sourceCommit: identity.commit,
+    sourceTree: identity.tree,
+    observedAt,
+    collector,
+    github: {
+      repository: process.env.GITHUB_REPOSITORY,
+      workflow: process.env.GITHUB_WORKFLOW,
+      runId: Number(process.env.GITHUB_RUN_ID),
+      runAttempt: Number(process.env.GITHUB_RUN_ATTEMPT),
+      job: process.env.GITHUB_JOB,
+    },
+    notes:
+      'Recorded only after the full WASIX catalog-extension direct, server, restart, materialization, and physical backup/restore suites succeeded.',
+    results: [...catalog.extensions]
+      .sort((a, b) => (a['sql-name'] < b['sql-name'] ? -1 : 1))
+      .map((extension) => ({
+        extension: extension.id,
+        sqlName: extension['sql-name'],
+        postgresMajor: 18,
+        artifactFamily: 'wasix-runtime',
+        platformTarget: 'portable',
+        runtimeModeStatuses: observedWasixModes(directory, extension['sql-name']),
+      })),
+  };
+  validateEvidenceRun(run);
+  return run;
+}
+
+export function currentEvidenceTable(
+  catalog: Row,
+  identity: { commit: string; tree: string },
+  requireCurrent = false,
+  matrix = readToml(evidenceMatrixPath),
+  overrides = new Map(),
+  extraRuns: { path: string; run: Row }[] = [],
+): string {
+  return jsonText(
+    evidenceTable(
+      catalog,
+      matrix,
+      [
+        ...files(`${evidenceRunsPath}/*.json`).map((path) => ({ path, run: readJson(path) })),
+        ...extraRuns,
+      ],
+      identity,
+      requireCurrent,
+      overrides,
+    ),
+  );
+}
diff --git a/src/extensions/tools/extension-model.test.mts b/src/extensions/tools/extension-model.test.mts
new file mode 100644
index 000000000..f9946df5a
--- /dev/null
+++ b/src/extensions/tools/extension-model.test.mts
@@ -0,0 +1,147 @@
+import assert from 'node:assert/strict';
+import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import {
+  evidenceMatrix,
+  evidenceTable,
+  observedWasixModes,
+  sourceDigest,
+  sourceDigestInputs,
+} from './extension-evidence.mts';
+import { discoverCatalog, extensionProjections, readJson } from './extension-projections.mts';
+
+const identity = { commit: '1'.repeat(40), tree: '2'.repeat(40) };
+const catalog = { extensions: [{ id: 'vector', 'sql-name': 'vector' }] };
+const matrix = () => Bun.TOML.parse(evidenceMatrix(catalog));
+function run() {
+  return {
+    path: 'src/extensions/evidence/runs/current.json',
+    run: {
+      schema: 'oliphaunt-extension-evidence-v1',
+      id: 'current',
+      evidenceTier: 'wasix-full-lifecycle-v1',
+      status: 'passed',
+      sourceDigest: sourceDigest(),
+      sourceDigestInputs: sourceDigestInputs(),
+      sourceCommit: identity.commit,
+      sourceTree: identity.tree,
+      observedAt: '2026-09-08T00:00:00Z',
+      collector: 'test',
+      github: {
+        repository: 'test/repo',
+        workflow: 'CI',
+        job: 'extensions',
+        runId: 1,
+        runAttempt: 1,
+      },
+      results: [
+        {
+          extension: 'vector',
+          sqlName: 'vector',
+          postgresMajor: 18,
+          artifactFamily: 'wasix-runtime',
+          platformTarget: 'portable',
+          runtimeModeStatuses: {
+            direct: 'passed',
+            server: 'passed',
+            restart: 'passed',
+            'backup-restore': 'passed',
+          },
+        },
+      ],
+    },
+  };
+}
+
+test('only observed passing results for the current source commit qualify', () => {
+  const passing = run();
+  const original = JSON.stringify(passing);
+  assert.equal(
+    evidenceTable(catalog, matrix(), [passing], identity, true).claims[0][
+      'latest-accepted-evidence'
+    ].length,
+    1,
+  );
+  assert.equal(JSON.stringify(passing), original);
+  for (const mutate of [
+    (run: any) => {
+      run.sourceDigest = `sha256:${'0'.repeat(64)}`;
+    },
+    (run: any) => {
+      run.sourceCommit = '3'.repeat(40);
+    },
+    (run: any) => {
+      run.sourceTree = '4'.repeat(40);
+    },
+    (run: any) => {
+      run.results[0].runtimeModeStatuses['backup-restore'] = 'failed';
+    },
+    (run: any) => {
+      run.status = 'failed';
+    },
+  ]) {
+    const stale = structuredClone(passing);
+    mutate(stale.run);
+    assert(
+      evidenceTable(catalog, matrix(), [stale], identity).claims[0]['missing-current-evidence']
+        .length,
+    );
+    assert.throws(
+      () => evidenceTable(catalog, matrix(), [stale], identity, true),
+      /lacks current CI evidence/,
+    );
+  }
+  const duplicate = structuredClone(passing);
+  duplicate.run.results.push(duplicate.run.results[0]);
+  assert.throws(
+    () => evidenceTable(catalog, matrix(), [duplicate], identity),
+    /duplicate evidence result/,
+  );
+  const mismatched = structuredClone(passing);
+  mismatched.run.results[0].sqlName = 'postgis';
+  assert.throws(() => evidenceTable(catalog, matrix(), [mismatched], identity), /SQL name differs/);
+});
+
+test('recording needs all five successful runtime observations', () => {
+  const directory = mkdtempSync(path.join(tmpdir(), 'oliphaunt-evidence-'));
+  try {
+    for (const mode of ['direct', 'server', 'restart', 'materialization'])
+      writeFileSync(`${directory}/vector.${mode}`, 'passed\n');
+    assert.throws(() => observedWasixModes(directory, 'vector'));
+    writeFileSync(`${directory}/vector.backup-restore`, 'failed\n');
+    assert.throws(() => observedWasixModes(directory, 'vector'), /successful observation/);
+    writeFileSync(`${directory}/vector.backup-restore`, 'passed\n');
+    assert.equal(Object.keys(observedWasixModes(directory, 'vector')).length, 5);
+  } finally {
+    rmSync(directory, { recursive: true, force: true });
+  }
+});
+
+test('extension projections retain dependency and runtime data while deriving mobile versions', () => {
+  const source = discoverCatalog();
+  const metadata = readJson('src/extensions/generated/sdk/extensions.json');
+  const releases = metadata.extensions.map((row: any) => ({
+    sqlName: row['sql-name'],
+    product: row['artifact-product'],
+    versioning: row['runtime-bound'] ? 'runtime-bound' : 'independent',
+    compatibility: { nativeRuntimeProduct: row['release-product'] },
+    cargoPackage: row['cargo-package'],
+    npmPackage: row['npm-package'],
+    mavenGroup: row['maven-group'],
+    mavenArtifact: row['maven-artifact'],
+  }));
+  const outputs = extensionProjections(source, releases);
+  assert.deepEqual(
+    JSON.parse(outputs.get('src/extensions/generated/sdk/extensions.json')!),
+    metadata,
+  );
+  const extension = source.extensions.find((row: any) => row.id === 'pg_textsearch');
+  extension.control['default-version'] = '9.8.7';
+  const updated = extensionProjections(source, releases).get(
+    'src/extensions/generated/mobile/static-extensions.tsv',
+  )!;
+  assert(updated.includes('-DPG_TEXTSEARCH_VERSION="9.8.7"'));
+  assert(!updated.includes('@EXTVERSION@'));
+});
diff --git a/src/extensions/tools/extension-projections.mts b/src/extensions/tools/extension-projections.mts
new file mode 100644
index 000000000..04de4435c
--- /dev/null
+++ b/src/extensions/tools/extension-projections.mts
@@ -0,0 +1,638 @@
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { existsSync, readFileSync } from 'node:fs';
+import { nativeComponentInventory } from './native-component-contract.mts';
+
+type Row = Record;
+export const modelPath = 'src/extensions/tools/check-extension-model.sh';
+export const catalogPath = 'src/extensions/generated/extensions.catalog.json';
+export const contribPath = 'src/extensions/contrib/postgres18.toml';
+const componentsPath = 'src/extensions/catalog/native-components.toml';
+const externalRoot = 'src/extensions/external';
+const smokeRoot = 'src/test-fixtures/extensions';
+export const readJson = (file: string): Row => JSON.parse(readFileSync(file, 'utf8'));
+export const readToml = (file: string): Row => Bun.TOML.parse(readFileSync(file, 'utf8'));
+export function sorted(value: any): any {
+  if (Array.isArray(value)) return value.map(sorted);
+  if (value !== null && typeof value === 'object')
+    return Object.fromEntries(
+      Object.keys(value)
+        .sort()
+        .map((key) => [key, sorted(value[key])]),
+    );
+  return value;
+}
+export const jsonText = (value: any) => `${JSON.stringify(sorted(value), null, 2)}\n`;
+const unique = (values: string[]) => [...new Set(values)].sort();
+const literal = (value: any) => JSON.stringify(value);
+const camel = (value: string) => value.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
+const moduleStem = (row: Row): string | null =>
+  (row['native-module-file'] || row['module-file'])?.replace(/\.(so|dylib|dll)$/, '') ?? null;
+const generated = `// This file is generated by ${modelPath}.\n// Do not edit by hand.\n\n`;
+
+export function extensionProjections(catalog: Row, releases: Row[]): Map {
+  const inventory = nativeComponentInventory();
+  const contrib = readToml(contribPath).extensions;
+  const extensions: Row[] = [...catalog.extensions].sort((a, b) =>
+    a['sql-name'] < b['sql-name'] ? -1 : 1,
+  );
+  const names = new Set(extensions.map((row) => row['sql-name']));
+  assert.equal(names.size, extensions.length, 'duplicate SQL extension name');
+  const releaseByName = new Map(releases.map((row) => [row.sqlName, row]));
+  assert.equal(releaseByName.size, releases.length, 'duplicate release owner');
+  for (const row of inventory.resolutions)
+    assert(names.has(row.extension), `unknown native component extension ${row.extension}`);
+  const recipes = new Map(
+    extensions.map((row) => {
+      const file = `${externalRoot}/${row['sql-name']}/recipe.toml`;
+      return [row['sql-name'], existsSync(file) ? readToml(file) : {}];
+    }),
+  );
+  const resolutions = (sql: string) => inventory.resolutions.filter((row) => row.extension === sql);
+  const mobile = (
+    sql: string,
+    field: string,
+    targets = ['ios-xcframework', 'android-arm64-v8a', 'android-x86_64'],
+  ) =>
+    unique(
+      resolutions(sql)
+        .filter(
+          (row) =>
+            row.family === 'native' &&
+            row.kind === 'native-static-registry' &&
+            targets.includes(row.target),
+        )
+        .flatMap((row) => row[field]),
+    );
+  const source = (name: string, path: string) => ({ name, path });
+  const metadataRows = extensions.map((extension) => {
+    const sql = extension['sql-name'];
+    const release = releaseByName.get(sql);
+    assert(release, `no release owner for ${sql}`);
+    const recipe = recipes.get(sql)!;
+    const contribRow = contrib.find((row: Row) => row['sql-name'] === sql);
+    const files = [...(recipe.artifacts?.data_files ?? contribRow?.['data-files'] ?? [])].sort();
+    const requirements = resolutions(sql);
+    const preload = unique(
+      (extension.lifecycle?.['startup-config'] ?? []).flatMap((assignment: string) =>
+        assignment.startsWith('shared_preload_libraries=')
+          ? assignment
+              .slice('shared_preload_libraries='.length)
+              .split(',')
+              .map((value) => value.trim())
+              .filter(Boolean)
+          : [],
+      ),
+    );
+    const environment = [...(recipe.runtime_environment ?? [])]
+      .map((row) => {
+        for (const key of ['name', 'path', 'required_file'])
+          assert(
+            typeof row[key] === 'string' && row[key],
+            `${sql} runtime environment requires ${key}`,
+          );
+        return { name: row.name, path: row.path, required_file: row.required_file };
+      })
+      .sort((a, b) =>
+        a.name < b.name
+          ? -1
+          : a.name > b.name
+            ? 1
+            : a.path < b.path
+              ? -1
+              : a.path > b.path
+                ? 1
+                : a.required_file < b.required_file
+                  ? -1
+                  : 1,
+      );
+    return {
+      id: extension.id,
+      'sql-name': sql,
+      'display-name': extension['display-name'] ?? extension.id,
+      'postgres-major': 18,
+      'artifact-product': release.artifactProduct ?? release.product,
+      'release-product':
+        release.versioning === 'runtime-bound'
+          ? release.compatibility.nativeRuntimeProduct
+          : release.product,
+      'cargo-package': release.cargoPackage,
+      'npm-package': release.npmPackage,
+      'maven-group': release.mavenGroup,
+      'maven-artifact': release.mavenArtifact,
+      'runtime-bound': release.versioning === 'runtime-bound',
+      'creates-extension': Boolean(extension.lifecycle?.['create-extension']),
+      'native-module-stem': moduleStem(extension),
+      dependencies: extension.dependencies ?? [],
+      'selected-extension-dependencies': (extension.dependencies ?? [])
+        .filter((name: string) => names.has(name))
+        .sort(),
+      'native-components': unique(requirements.flatMap((row) => row.components)),
+      'native-component-requirements': requirements.map((row) => ({
+        family: row.family,
+        kind: row.kind,
+        target: row.target,
+        components: row.components,
+        'link-units': row.linkUnits,
+        'runtime-files': row.runtimeFiles,
+      })),
+      'shared-preload-libraries': preload,
+      'data-files': files,
+      'runtime-share-data-files': files
+        .map((file: string) => file.replace(/^share\/postgresql\//, ''))
+        .sort(),
+      'extension-sql-file-prefixes': [
+        ...(recipe.artifacts?.extension_sql_file_prefixes ?? []),
+      ].sort(),
+      'extension-sql-file-names': [...(recipe.artifacts?.extension_sql_file_names ?? [])].sort(),
+      'runtime-environment': environment,
+      'source-kind': extension['source-kind'],
+    };
+  });
+  const hash = createHash('sha256')
+    .update(JSON.stringify(sorted(metadataRows)))
+    .digest('hex');
+  const outputs = new Map();
+  const putJson = (file: string, value: any) => outputs.set(file, jsonText(value));
+  const base = 'src/extensions/generated';
+  putJson(`${base}/sdk/extensions.json`, {
+    'format-version': 1,
+    'extension-catalog-sha256': hash,
+    'generated-from': [
+      source('extension-catalog', catalogPath),
+      source('native-components', componentsPath),
+      source('extension-recipes', 'extensions'),
+      source('release-products', 'src'),
+    ],
+    extensions: metadataRows,
+  });
+  const ios = new Map(
+    extensions.map((row) => [
+      row['sql-name'],
+      mobile(row['sql-name'], 'linkUnits', ['ios-xcframework']),
+    ]),
+  );
+  putJson(`${base}/sdk/ios-static-dependencies.json`, {
+    'format-version': 1,
+    'generated-from': [
+      source('extension-catalog', catalogPath),
+      source('native-components', componentsPath),
+      source('contrib-recipe', contribPath),
+      source('external-static-targets', externalRoot),
+    ],
+    extensions: [...ios]
+      .filter(([, deps]) => deps.length)
+      .map(([sql, deps]) => ({ 'sql-name': sql, 'static-dependencies': deps })),
+  });
+  const tsFields = [
+    'id',
+    'sql-name',
+    'display-name',
+    'postgres-major',
+    'artifact-product',
+    'release-product',
+    'cargo-package',
+    'npm-package',
+    'maven-group',
+    'maven-artifact',
+    'runtime-bound',
+    'creates-extension',
+    'native-module-stem',
+    'dependencies',
+    'selected-extension-dependencies',
+    'shared-preload-libraries',
+    'data-files',
+    'runtime-share-data-files',
+    'extension-sql-file-prefixes',
+    'extension-sql-file-names',
+    'source-kind',
+  ];
+  for (const [sdk, includeIos] of [
+    ['ts/sdk', false],
+    ['react-native', true],
+  ] as const) {
+    const fields = [...tsFields];
+    if (includeIos) fields.splice(15, 0, 'ios-static-dependencies');
+    const rows = metadataRows.map((row) =>
+      Object.fromEntries(
+        fields.map((field) => [
+          camel(field),
+          field === 'ios-static-dependencies' ? ios.get(row['sql-name']) : row[field],
+        ]),
+      ),
+    );
+    const type = fields
+      .map((field) => {
+        const value = rows[0][camel(field)];
+        return `  readonly ${camel(field)}: ${field === 'native-module-stem' ? 'string | null' : Array.isArray(value) ? 'readonly string[]' : typeof value};`;
+      })
+      .join('\n');
+    outputs.set(
+      `src/sdks/${sdk}/src/generated/extensions.ts`,
+      `${generated}export type GeneratedExtensionMetadata = {\n${type}\n};\n\nexport const GENERATED_EXTENSION_METADATA_SHA256 = ${literal(hash)} as const;\n\nexport const GENERATED_EXTENSION_METADATA = ${JSON.stringify(sorted(rows), null, 2)} as const satisfies readonly GeneratedExtensionMetadata[];\n\nexport function generatedExtensionBySqlName(sqlName: string): GeneratedExtensionMetadata | undefined {\n  return GENERATED_EXTENSION_METADATA.find((extension) => extension.sqlName === sqlName);\n}\n\nexport function generatedSharedPreloadLibraries(extensionSqlNames: readonly string[]): string[] {\n  const libraries = new Set();\n  for (const sqlName of extensionSqlNames) {\n    const extension = generatedExtensionBySqlName(sqlName);\n    for (const library of extension?.sharedPreloadLibraries ?? []) {\n      libraries.add(library);\n    }\n  }\n  return [...libraries].sort();\n}\n`,
+    );
+  }
+  const smokePlan = metadataRows.map((row) => ({
+    sqlName: row['sql-name'],
+    createsExtension: row['creates-extension'],
+    selectedExtensionDependencies: row['selected-extension-dependencies'],
+  }));
+  const smoke = Object.fromEntries(
+    metadataRows.map((row) => [
+      row['sql-name'],
+      readFileSync(`${smokeRoot}/${row['sql-name']}.sql`, 'utf8')
+        .split('-- oliphaunt-statement')
+        .map((sql) => sql.trim())
+        .filter(Boolean),
+    ]),
+  );
+  for (const [name, statements] of Object.entries(smoke))
+    assert(statements.length, `empty smoke recipe for ${name}`);
+  outputs.set(
+    'src/examples/react-native-expo/src/generated/extension-smoke.ts',
+    `// This file is generated by ${modelPath}.\n// Do not edit by hand. It belongs only to installed mobile qualification.\n\nexport type GeneratedMobileExtensionProof = {\n  readonly sqlName: string;\n  readonly createsExtension: boolean;\n  readonly selectedExtensionDependencies: readonly string[];\n};\n\nexport const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = ${literal(hash)} as const;\n\nexport const GENERATED_MOBILE_EXTENSION_PLAN = ${JSON.stringify(smokePlan, null, 2)} as const satisfies readonly GeneratedMobileExtensionProof[];\n\nexport const GENERATED_MOBILE_EXTENSION_SMOKE = ${JSON.stringify(sorted(smoke), null, 2).replace(/[\u007f-\uffff]/g, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`)} as const satisfies Readonly>;\n`,
+  );
+  outputs.set(
+    'src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt',
+    `${generated}package dev.oliphaunt\n\ninternal data class GeneratedExtensionRuntimeContract(\n    val createsExtension: Boolean,\n    val nativeModuleStem: String?,\n)\n\ninternal val generatedExtensionRuntimeContracts: Map = mapOf(\n${metadataRows.map((row) => `    ${literal(row['sql-name'])} to GeneratedExtensionRuntimeContract(createsExtension = ${row['creates-extension']}, nativeModuleStem = ${literal(row['native-module-stem'])}),`).join('\n')}\n)\n\ninternal val generatedExtensionSqlNames: Set = generatedExtensionRuntimeContracts.keys\n\ninternal fun generatedExtensionSqlNameExists(sqlName: String): Boolean = generatedExtensionSqlNames.contains(sqlName)\n\ninternal fun generatedExtensionRuntimeContract(sqlName: String): GeneratedExtensionRuntimeContract? = generatedExtensionRuntimeContracts[sqlName]\n`,
+  );
+  outputs.set(
+    'src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties',
+    [
+      `# This file is generated by ${modelPath}.`,
+      '# Do not edit by hand.',
+      'schema=oliphaunt-android-extension-catalog-v2',
+      `catalogSha256=${hash}`,
+      ...metadataRows.flatMap((row) =>
+        Object.entries({
+          artifactProduct: row['artifact-product'],
+          releaseProduct: row['release-product'],
+          mavenGroup: row['maven-group'],
+          mavenArtifact: row['maven-artifact'],
+          runtimeBound: row['runtime-bound'],
+          dependencies: row['selected-extension-dependencies'].join(','),
+        }).map(([key, value]) => `extension.${row['sql-name']}.${key}=${value}`),
+      ),
+      '',
+    ].join('\n'),
+  );
+  outputs.set(
+    'src/sdks/rust/liboliphaunt-native/src/generated/extensions.rs',
+    rustModule(
+      metadataRows.map((row) => ({
+        ...row,
+        'rust-constant': extensions.find((extension) => extension.id === row.id)!['rust-constant'],
+      })),
+    ),
+  );
+  const modules = metadataRows
+    .filter((row) => row['native-module-stem'] !== null)
+    .map((row) => ({
+      id: row.id,
+      'sql-name': row['sql-name'],
+      'native-module-stem': row['native-module-stem'],
+      'data-files': row['data-files'],
+      'static-registry-required': true,
+    }));
+  putJson(`${base}/mobile/static-registry.json`, {
+    'format-version': 1,
+    'generated-from': [
+      source('extension-catalog', catalogPath),
+      source('extension-definitions', externalRoot),
+    ],
+    modules,
+  });
+  const mobileRows = modules.map((module) => {
+    const sql = module['sql-name'];
+    const extension = extensions.find((row) => row['sql-name'] === sql)!;
+    const contribRow = contrib.find((row: Row) => row['sql-name'] === sql);
+    const targetFile = `${externalRoot}/${sql}/targets/native-static-registry.toml`;
+    const target = existsSync(targetFile) ? readToml(targetFile) : {};
+    const list = (field: string, contribField?: string) =>
+      unique(target[field]?.length ? target[field] : (contribRow?.[contribField!] ?? []));
+    const sourceRel =
+      extension['source-kind'] === 'postgres-contrib'
+        ? `contrib/${contribRow?.['contrib-dir']}`
+        : extension['control-file']?.match(/^(target\/oliphaunt-sources\/checkouts\/[^/]+)\//)?.[1];
+    assert(sourceRel && !sourceRel.endsWith('undefined'), `${sql} has no mobile source path`);
+    const dependencies = (field: string, targets?: string[]) => mobile(sql, field, targets);
+    return [
+      sql,
+      module['native-module-stem'],
+      contribRow ? 'contrib' : 'external',
+      sourceRel,
+      dependencies('linkUnits'),
+      dependencies('linkUnits', ['ios-xcframework']),
+      dependencies('linkUnits', ['android-arm64-v8a', 'android-x86_64']),
+      dependencies('sources'),
+      list('include_dirs', 'mobile-static-include-dirs'),
+      list('cflags', 'mobile-static-cflags').map((flag) =>
+        flag.replaceAll('@EXTVERSION@', extension.control?.['default-version'] ?? ''),
+      ),
+      dependencies('sources'),
+      dependencies('sources', ['ios-xcframework']),
+      dependencies('sources', ['android-arm64-v8a', 'android-x86_64']),
+      list('hash_dirs', 'mobile-static-hash-dirs'),
+      list('source_files'),
+      list('source_recursive_dirs'),
+    ]
+      .map((value) => (Array.isArray(value) ? value.join(',') : value))
+      .join('\t')
+      .replace(/\t+$/, '');
+  });
+  outputs.set(
+    `${base}/mobile/static-extensions.tsv`,
+    [
+      `# @generated by ${modelPath} --write`,
+      'sql-name\tnative-module-stem\tsource-kind\tsource-rel\tmobile-static-dependencies\tios-static-dependencies\tandroid-static-dependencies\tinclude-dependencies\tinclude-dirs\tcflags\thash-source-dependencies\tios-hash-source-dependencies\tandroid-hash-source-dependencies\thash-dirs\tsource-files\tsource-recursive-dirs',
+      ...mobileRows,
+      '',
+    ].join('\n'),
+  );
+  putJson(`${base}/wasix/extensions.json`, {
+    'format-version': 1,
+    'generated-from': [
+      source('extension-catalog', catalogPath),
+      source('native-components', componentsPath),
+      source('extension-definitions', externalRoot),
+    ],
+    extensions: extensions.map((row) => {
+      const sql = row['sql-name'];
+      const closure = resolutions(sql).find(
+        (row) =>
+          row.family === 'wasix' && row.kind === 'wasix-runtime' && row.target === 'wasix-portable',
+      );
+      const targetFile = `${externalRoot}/${sql}/targets/wasix.toml`;
+      const support = existsSync(targetFile)
+        ? (readToml(targetFile).native_support_modules ?? [])
+        : [];
+      return {
+        id: row.id,
+        'sql-name': sql,
+        archive: row.archive || `extensions/${sql}.tar.zst`,
+        'native-module-file': row['native-module-file'] || row['module-file'] || null,
+        'native-support-modules': support
+          .map((module: Row) =>
+            Object.fromEntries(
+              ['name', 'runtime_path', 'build_path', 'aot_file'].map((field) => {
+                assert(
+                  typeof module[field] === 'string' && module[field],
+                  `${sql} support module needs ${field}`,
+                );
+                return [field.replaceAll('_', '-'), module[field]];
+              }),
+            ),
+          )
+          .sort((a: Row, b: Row) => (a.name < b.name ? -1 : 1)),
+        'native-components': closure?.components ?? [],
+        'native-link-units': closure?.linkUnits ?? [],
+        'native-runtime-files': closure?.runtimeFiles ?? [],
+        dependencies: row.dependencies ?? [],
+        'load-order': row['load-order'] ?? [],
+        lifecycle: row.lifecycle ?? {},
+      };
+    }),
+  });
+  return outputs;
+}
+
+function rustModule(rows: Row[]): string {
+  const variant = (row: Row) =>
+    row['rust-constant']
+      .split('_')
+      .map((part: string) => part[0] + part.slice(1).toLowerCase())
+      .join('');
+  const id = (row: Row) => `ExtensionId::${variant(row)}`;
+  const selected = (row: Row) => `Extension::${row['rust-constant']}`;
+  const option = (value: string | null) => (value === null ? 'None' : `Some(${literal(value)})`);
+  const array = (values: string[]) => `&[${values.join(', ')}]`;
+  const match = (name: string, type: string, value: (row: Row) => string) =>
+    `/// Generated extension metadata accessor.\npub(super) const fn ${name}(extension: Extension) -> ${type} {\n    match extension.id {\n${rows.map((row) => `        ${id(row)} => ${value(row)},`).join('\n')}\n    }\n}\n`;
+  for (const row of rows) {
+    assert(
+      /^[A-Z][A-Z0-9_]*$/.test(row['rust-constant']),
+      `invalid Rust extension constant ${row.id}`,
+    );
+    assert(
+      row['shared-preload-libraries'].length <= 1,
+      `Rust Extension supports one preload library: ${row.id}`,
+    );
+  }
+  return [
+    `// @generated by ${modelPath} --write`,
+    '// Do not edit by hand.',
+    '',
+    'use super::ExtensionRuntimeEnvironment;',
+    '',
+    '/// Native PostgreSQL 18 extension artifact that can be selected by an app.',
+    '#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]',
+    'pub struct Extension {',
+    '    id: ExtensionId,',
+    '}',
+    '',
+    '#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]',
+    'enum ExtensionId {',
+    ...rows.map((row) => `    /// PostgreSQL \`${row['sql-name']}\`.\n    ${variant(row)},`),
+    '}',
+    '',
+    'impl Extension {',
+    ...rows.map(
+      (row) =>
+        `    /// Select the \`${row['sql-name']}\` artifact.\n    pub const ${row['rust-constant']}: Self = Self { id: ${id(row)} };`,
+    ),
+    '',
+    '    /// All PostgreSQL 18 extension artifacts known to the native SDK.',
+    `    pub const ALL: &'static [Self] = ${array(rows.map(selected))};`,
+    '}',
+    '',
+    match('sql_name', "&'static str", (row) => literal(row['sql-name'])),
+    match('native_module_stem', "Option<&'static str>", (row) => option(row['native-module-stem'])),
+    match('creates_extension', 'bool', (row) => String(row['creates-extension'])),
+    match('dependencies', "&'static [Extension]", (row) =>
+      array(
+        row['selected-extension-dependencies'].map((sql: string) =>
+          selected(rows.find((row) => row['sql-name'] === sql)!),
+        ),
+      ),
+    ),
+    match('required_shared_preload_library', "Option<&'static str>", (row) =>
+      option(row['shared-preload-libraries'][0] ?? null),
+    ),
+    ...[
+      ['extension_data_files', 'runtime-share-data-files'],
+      ['extension_sql_file_prefixes', 'extension-sql-file-prefixes'],
+      ['extension_sql_file_names', 'extension-sql-file-names'],
+    ].map(([name, field]) =>
+      match(name, "&'static [&'static str]", (row) => array(row[field].map(literal))),
+    ),
+    match('runtime_environment', "&'static [ExtensionRuntimeEnvironment]", (row) =>
+      array(
+        row['runtime-environment'].map(
+          (env: Row) =>
+            `ExtensionRuntimeEnvironment { name: ${literal(env.name)}, relative_path: ${literal(env.path)}, required_file: ${literal(env.required_file)} }`,
+        ),
+      ),
+    ),
+  ].join('\n');
+}
+
+export function discoverCatalog(): Row {
+  const catalog = readJson('src/extensions/catalog/extensions.source.json');
+  assert.equal(catalog['format-version'], 1);
+  const versions = new Map();
+  const addVersion = (sql: string, version: unknown) => {
+    assert(
+      typeof version === 'string' &&
+        /^[a-zA-Z0-9._-]{1,128}$/.test(version) &&
+        !version.includes('--'),
+      `invalid default version for ${sql}`,
+    );
+    assert(!versions.has(sql), `duplicate default version for ${sql}`);
+    versions.set(sql, version);
+  };
+  const contrib = readToml(contribPath).extensions;
+  for (const row of contrib)
+    if (row['default-version'] !== undefined) addVersion(row['sql-name'], row['default-version']);
+  for (const file of new Bun.Glob(`${externalRoot}/*/source.toml`).scanSync({ onlyFiles: true })) {
+    const source = readToml(file),
+      control = source['extension-control'];
+    if (!control) continue;
+    addVersion(control['sql-name'], control['default-version']);
+    assert.equal(
+      catalog.extensions.find((row: Row) => row['sql-name'] === control['sql-name'])?.[
+        'control-file'
+      ],
+      `target/oliphaunt-sources/checkouts/${source.name}/${control['source-path']}`,
+      `source control provenance differs: ${file}`,
+    );
+  }
+  const ids = new Set(),
+    sqlNames = new Set();
+  for (const row of catalog.extensions) {
+    assert(
+      /^[a-z][a-z0-9_]*$/.test(row.id) && /^[a-z][a-z0-9_-]*$/.test(row['sql-name']),
+      'invalid extension name',
+    );
+    assert(!ids.has(row.id) && !sqlNames.has(row['sql-name']), `duplicate extension ${row.id}`);
+    ids.add(row.id);
+    sqlNames.add(row['sql-name']);
+    const version = versions.get(row['sql-name']);
+    if (row.lifecycle['create-extension']) {
+      assert(row.control && version, `missing control version for ${row.id}`);
+      // Preserve the catalog's public field order while replacing source-owned versions.
+      delete row.control['default-version'];
+      row.control = { 'default-version': version, ...row.control };
+    } else assert(!version, `module-only extension ${row.id} declares a SQL version`);
+    assert(
+      row.lifecycle['create-extension'] || row.lifecycle['load-sql'].length,
+      `missing activation for ${row.id}`,
+    );
+    const recipe = contrib.find((contrib: Row) => contrib.id === row.id);
+    if (recipe) {
+      assert.equal(recipe['sql-name'], row['sql-name']);
+      assert.equal(recipe['module-file'], row['native-module-file']);
+    }
+  }
+  for (const sql of versions.keys())
+    assert(sqlNames.has(sql), `version declared for unknown extension ${sql}`);
+  for (const row of catalog.extensions)
+    for (const dependency of row.dependencies)
+      assert(
+        dependency === 'plpgsql' || sqlNames.has(dependency) || ids.has(dependency),
+        `unknown extension dependency ${dependency}`,
+      );
+  return {
+    'format-version': 1,
+    'generated-from': [
+      { name: 'postgres18-source', path: 'src/third-party/postgres/source.toml' },
+      { name: 'extension-catalog', path: 'src/extensions/catalog/extensions.source.json' },
+      { name: 'postgres-contrib', path: contribPath },
+      { name: 'external-extension-recipes', path: externalRoot },
+    ],
+    extensions: catalog.extensions.sort((a: Row, b: Row) => (a.id < b.id ? -1 : 1)),
+  };
+}
+
+export function catalogProjections(catalog: Row): Map {
+  const outputs = new Map([[catalogPath, `${JSON.stringify(catalog, null, 2)}\n`]]);
+  const contrib = ['# id\tsql_name\tcontrib_dir\tmodule_file\tarchive'];
+  const pgxs = ['# id\tsql_name\tsource_dir\tmodule_file\tarchive\tmake_args'];
+  const recipes = readToml(contribPath).extensions;
+  for (const row of [...catalog.extensions].sort((a, b) =>
+    a['sql-name'] < b['sql-name'] ? -1 : 1,
+  )) {
+    const archive = `extensions/${row['sql-name']}.tar.zst`;
+    if (row['source-kind'] === 'postgres-contrib') {
+      const recipe = recipes.find((recipe: Row) => recipe.id === row.id);
+      assert(recipe?.['contrib-dir'], `missing contrib directory ${row.id}`);
+      contrib.push(
+        [
+          row.id,
+          row['sql-name'],
+          recipe['contrib-dir'],
+          row['native-module-file'] ?? '-',
+          archive,
+        ].join('\t'),
+      );
+    } else if (row['source-kind'] === 'oliphaunt-other-extension') {
+      const source = readToml(`${externalRoot}/${row['sql-name']}/source.toml`);
+      pgxs.push(
+        [
+          row.id,
+          row['sql-name'],
+          `target/oliphaunt-sources/checkouts/${source.name}`,
+          row['native-module-file'] ?? '-',
+          archive,
+          row.id === 'age' ? 'SIZEOF_DATUM=4' : '-',
+        ].join('\t'),
+      );
+    } else assert.equal(row['source-kind'], 'postgis', 'unsupported extension build kind');
+  }
+  outputs.set('src/extensions/generated/contrib-build.tsv', `${contrib.join('\n')}\n`);
+  outputs.set('src/extensions/generated/pgxs-build.tsv', `${pgxs.join('\n')}\n`);
+  outputs.set(
+    'src/sdks/rust-wasix/src/oliphaunt/generated_extensions.rs',
+    wasixRustModule(catalog.extensions),
+  );
+  return outputs;
+}
+
+function wasixRustModule(rows: Row[]): string {
+  const feature = (row: Row) => `extension-${row['sql-name'].replaceAll('_', '-')}`;
+  const cfg = (row: Row) => `#[cfg(feature = ${literal(feature(row))})]`;
+  const array = (values: string[]) => `&[${values.map(literal).join(', ')}]`;
+  const option = (value: string | undefined) =>
+    value === undefined ? 'None' : `Some(${literal(value)})`;
+  const quoteSql = (value: string) => `"${value.replaceAll('"', '""')}"`;
+  let text = `// @generated by ${modelPath} --write\n\nuse super::Extension;\n\n`;
+  for (const row of rows) {
+    const file = `${externalRoot}/${row['sql-name']}/targets/wasix.toml`;
+    const target = existsSync(file) ? readToml(file) : {};
+    const modules = [...(target.native_support_modules ?? [])]
+      .sort((a, b) => (a.name < b.name ? -1 : 1))
+      .map(
+        (module) =>
+          `super::ExtensionNativeModule { runtime_path: ${literal(module.runtime_path)}, aot_name: Some(${literal(`extension:${row['sql-name']}:${module.name}`)}) }`,
+      );
+    text += `${cfg(row)}\nconst DEFINITION_${row['rust-constant']}: Extension = Extension {\n    sql_name: ${literal(row['sql-name'])},\n    native_support_modules: &[${modules.join(', ')}],\n    native_module_file: ${option(row['native-module-file'])},\n    aot_name: ${option(row['native-module-file'] ? `extension:${row['sql-name']}` : undefined)},\n    dependencies: ${array(row.dependencies.filter((sql: string) => sql !== 'plpgsql'))},\n    startup_config: ${array(row.lifecycle['startup-config'])},\n};\n\n`;
+  }
+  text += `impl Extension {\n${rows.map((row) => `    /// Select the \`${row['sql-name']}\` artifact.\n    ${cfg(row)}\n    pub const ${row['rust-constant']}: Self = DEFINITION_${row['rust-constant']};`).join('\n')}\n\n    /// Extension artifacts enabled in this Cargo build.\n    pub const ALL: &'static [Self] = &[\n${rows.map((row) => `        ${cfg(row)}\n        Self::${row['rust-constant']},`).join('\n')}\n    ];\n}\n`;
+  text += `\n#[cfg(test)]\npub(super) fn creates_database_object_for_test(extension: Extension) -> bool {\n    match extension.sql_name() {\n${rows.map((row) => `        ${cfg(row)}\n        ${literal(row['sql-name'])} => ${row.lifecycle['create-extension']},`).join('\n')}\n        _ => false,\n    }\n}\n`;
+  const activation = (row: Row) => {
+    const sql: string[] = [],
+      lifecycle = row.lifecycle,
+      schema = lifecycle['create-schema'];
+    if (lifecycle['create-extension']) {
+      if (schema && schema !== 'pg_catalog')
+        sql.push(`CREATE SCHEMA IF NOT EXISTS ${quoteSql(schema)};`);
+      sql.push(
+        `CREATE EXTENSION IF NOT EXISTS ${quoteSql(row['sql-name'])}${schema ? ` WITH SCHEMA ${quoteSql(schema)}` : ''};`,
+      );
+    }
+    return [...sql, ...lifecycle['load-sql'], ...lifecycle['post-create-sql']];
+  };
+  return (
+    text +
+    `\n#[cfg(test)]\npub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'static str] {\n    match extension.sql_name() {\n${rows.map((row) => `        ${cfg(row)}\n        ${literal(row['sql-name'])} => ${array(activation(row))},`).join('\n')}\n        _ => &[],\n    }\n}\n`
+  );
+}
diff --git a/src/extensions/tools/extension-upstream-licenses.mts b/src/extensions/tools/extension-upstream-licenses.mts
new file mode 100644
index 000000000..29e2f6039
--- /dev/null
+++ b/src/extensions/tools/extension-upstream-licenses.mts
@@ -0,0 +1,976 @@
+import { createHash } from 'node:crypto';
+import {
+  chmodSync,
+  existsSync,
+  lstatSync,
+  mkdirSync,
+  readFileSync,
+  readdirSync,
+  realpathSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { requireSafeDirectoryChain as requireReleaseDirectoryChain } from '../../../tools/packaging/release-directory-safety.mts';
+import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts';
+import {
+  hasCanonicalReleaseStagingMode,
+  releaseNoticeRows,
+  releaseMavenLicenses,
+  releaseProfilePackageLicense,
+} from '../../../tools/packaging/release-notices.mts';
+
+const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
+const EXTERNAL_ROOT = path.join(ROOT, 'src/extensions/external');
+const PRODUCT_DATA_FILE = 'upstream-license-data.json';
+const CHECKOUT_ROOT = path.resolve(
+  process.env.OLIPHAUNT_EXTENSION_SOURCE_CHECKOUT_ROOT ??
+    path.join(ROOT, 'target/oliphaunt-sources/checkouts'),
+);
+const SCHEMA = 'oliphaunt-extension-upstream-license-data-v1';
+const SHA256 = /^[0-9a-f]{64}$/u;
+const GIT_COMMIT = /^[0-9a-f]{40}$/u;
+const SAFE_ID = /^[A-Za-z0-9._-]+$/u;
+const FILE_ROLES = new Set(['license', 'notice']);
+const SPDX_ORDER = Object.freeze([
+  'MIT',
+  'Apache-2.0',
+  'PostgreSQL',
+  'Unicode-3.0',
+  'MPL-2.0',
+  'GPL-2.0-or-later',
+  'LGPL-2.1-or-later',
+  'blessing',
+]);
+const SUPPORTED_SPDX_IDS = new Set(SPDX_ORDER);
+const CONTRIB_LICENSE = Object.freeze({
+  product: 'oliphaunt-extension-contrib-pg18',
+  upstreamSpdx: 'PostgreSQL',
+  packageSpdx: 'MIT AND PostgreSQL',
+});
+const OPENSSL_EMBEDDED_NATIVE_TARGETS = new Set([
+  'android-arm64-v8a',
+  'android-x86_64',
+  'ios-xcframework',
+  'macos-arm64',
+  'macos-x64',
+  'windows-x64-msvc',
+]);
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function fail(message) {
+  throw new Error(`extension-upstream-licenses: ${message}`);
+}
+
+function simpleRelative(value, label) {
+  if (typeof value !== 'string' || !value || path.isAbsolute(value) || value.includes('\\')) {
+    fail(`${label} must be a non-empty portable relative path`);
+  }
+  const parts = value.split('/');
+  if (parts.some((part) => !part || part === '.' || part === '..')) {
+    fail(`${label} must not contain empty, '.' or '..' components`);
+  }
+  return parts.join('/');
+}
+
+function httpsUrl(value, label) {
+  let url;
+  try {
+    url = new URL(value);
+  } catch (cause) {
+    fail(`${label} must be an absolute URL: ${cause.message}`);
+  }
+  if (
+    typeof value !== 'string' ||
+    value.trim() !== value ||
+    value.includes('\\') ||
+    url.protocol !== 'https:' ||
+    url.username ||
+    url.password ||
+    url.hash
+  ) {
+    fail(`${label} must be one canonical credential-free HTTPS URL without a fragment`);
+  }
+  return value;
+}
+
+function spdxExpression(ids) {
+  const selected = new Set(ids);
+  const known = SPDX_ORDER.filter((id) => selected.delete(id));
+  return [...known, ...[...selected].sort(compareText)].join(' AND ');
+}
+
+export function assertSupportedExtensionUpstreamSpdxId(
+  value,
+  label = 'extension upstream license',
+) {
+  if (typeof value !== 'string' || !SUPPORTED_SPDX_IDS.has(value)) {
+    fail(
+      `${label} must declare one supported SPDX identifier (${SPDX_ORDER.join(', ')}); got ${JSON.stringify(value)}`,
+    );
+  }
+  return value;
+}
+
+function parseSource(raw) {
+  const id = raw?.id;
+  if (typeof id !== 'string' || !SAFE_ID.test(id)) fail(`invalid source id ${JSON.stringify(id)}`);
+  const manifest = simpleRelative(raw.manifest, `${id} source manifest`);
+  if (!manifest.startsWith('src/extensions/external/')) {
+    fail(`${id} source manifest must be under src/extensions/external/`);
+  }
+  const kind = raw.kind;
+  if (!new Set(['git', 'archive']).has(kind)) fail(`${id} source kind must be git or archive`);
+  const url = httpsUrl(raw.url, `${id} source URL`);
+  const branch = raw.branch;
+  const commit = raw.commit;
+  if (typeof branch !== 'string' || !branch || /[\u0000-\u001f\u007f]/u.test(branch)) {
+    fail(`${id} source branch must be a non-empty printable string`);
+  }
+  if (kind === 'git' ? !GIT_COMMIT.test(commit) : !SHA256.test(commit)) {
+    fail(`${id} source commit is not an exact ${kind} identity`);
+  }
+  const manifestFile = path.join(ROOT, ...manifest.split('/'));
+  let manifestData;
+  let stat;
+  try {
+    stat = lstatSync(manifestFile);
+    manifestData = Bun.TOML.parse(readFileSync(manifestFile, 'utf8'));
+  } catch (cause) {
+    fail(`${manifest} cannot be inspected and parsed: ${cause.message}`);
+  }
+  if (!stat.isFile() || stat.isSymbolicLink())
+    fail(`${manifest} must be a regular non-symlink file`);
+  const manifestKind = manifestData.kind ?? 'git';
+  if (
+    manifestData.name !== id ||
+    manifestKind !== kind ||
+    manifestData.url !== url ||
+    manifestData.branch !== branch ||
+    manifestData.commit !== commit ||
+    (kind === 'archive' && manifestData.sha256 !== commit)
+  ) {
+    fail(`${id} source identity does not match ${manifest}`);
+  }
+  return Object.freeze({ id, manifest, kind, url, branch, commit });
+}
+
+function canonicalSource(source) {
+  return {
+    id: source.id,
+    manifest: source.manifest,
+    kind: source.kind,
+    url: source.url,
+    branch: source.branch,
+    commit: source.commit,
+  };
+}
+
+function canonicalFile(file) {
+  return {
+    source: file.source.id,
+    path: file.path,
+    destination: file.destination,
+    role: file.role,
+    spdx: file.spdx,
+    license_url: file.licenseUrl,
+    sha256: file.sha256,
+  };
+}
+
+function decodeProductBlobs(rawBlobs, expectedDigests, label) {
+  if (rawBlobs === null || typeof rawBlobs !== 'object' || Array.isArray(rawBlobs)) {
+    fail(`${label} must declare a blobs object`);
+  }
+  const digests = Object.keys(rawBlobs);
+  if (JSON.stringify(digests) !== JSON.stringify([...digests].sort(compareText))) {
+    fail(`${label} blob digests must be sorted`);
+  }
+  const expected = [...new Set(expectedDigests)].sort(compareText);
+  if (JSON.stringify(digests) !== JSON.stringify(expected)) {
+    fail(`${label} blob set differs: expected ${expected.join(', ')}, got ${digests.join(', ')}`);
+  }
+  const decoded = new Map();
+  for (const digest of digests) {
+    const encoded = rawBlobs[digest];
+    if (
+      !SHA256.test(digest) ||
+      typeof encoded !== 'string' ||
+      !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u.test(encoded)
+    ) {
+      fail(`${label} contains a malformed digest or base64 payload`);
+    }
+    const payload = Buffer.from(encoded, 'base64');
+    if (
+      payload.toString('base64') !== encoded ||
+      createHash('sha256').update(payload).digest('hex') !== digest
+    ) {
+      fail(`${label} payload does not match digest ${digest}`);
+    }
+    decoded.set(digest, payload);
+  }
+  return decoded;
+}
+
+function parseProductContract(contractFile) {
+  const label = path.relative(ROOT, contractFile);
+  let bytes;
+  let data;
+  let stat;
+  try {
+    stat = lstatSync(contractFile);
+    bytes = readFileSync(contractFile, 'utf8');
+    data = JSON.parse(bytes);
+  } catch (cause) {
+    fail(`${label} cannot be inspected and parsed: ${cause.message}`);
+  }
+  if (!stat.isFile() || stat.isSymbolicLink()) fail(`${label} must be a regular non-symlink file`);
+  if (
+    data?.schema !== SCHEMA ||
+    !Array.isArray(data.sources) ||
+    data.extension === null ||
+    typeof data.extension !== 'object' ||
+    Array.isArray(data.extension) ||
+    data.blobs === null ||
+    typeof data.blobs !== 'object' ||
+    Array.isArray(data.blobs) ||
+    Object.keys(data).join('\0') !== 'schema\0sources\0extension\0blobs'
+  ) {
+    fail(`${label} must declare only schema ${SCHEMA}, sources, extension, and blobs`);
+  }
+
+  const sources = data.sources.map(parseSource);
+  if (new Set(sources.map((source) => source.id)).size !== sources.length) {
+    fail(`${label} source ids must be unique`);
+  }
+  const sortedSources = [...sources].sort((left, right) => compareText(left.id, right.id));
+  if (JSON.stringify(sources) !== JSON.stringify(sortedSources))
+    fail(`${label} source rows must be sorted by id`);
+  const sourceById = new Map(sources.map((source) => [source.id, source]));
+
+  const sqlName = data.extension.sql_name;
+  const owner = path.basename(path.dirname(contractFile));
+  if (typeof sqlName !== 'string' || !SAFE_ID.test(sqlName) || sqlName !== owner) {
+    fail(`${label} must be owned by its exact extension_sql_name directory`);
+  }
+  if (!Array.isArray(data.extension.files) || data.extension.files.length === 0) {
+    fail(`${sqlName} must declare at least one upstream license or notice file`);
+  }
+  const files = [];
+  const destinations = new Set();
+  const usedSources = new Set();
+  for (const rawFile of data.extension.files) {
+    const source = sourceById.get(rawFile?.source);
+    if (!source)
+      fail(`${sqlName} file references unknown source ${JSON.stringify(rawFile?.source)}`);
+    usedSources.add(source.id);
+    const sourcePath = simpleRelative(rawFile.path, `${sqlName} license path`);
+    const destination = simpleRelative(rawFile.destination, `${sqlName} license destination`);
+    if (!destination.startsWith('share/licenses/')) {
+      fail(`${sqlName} license destination must be under share/licenses/: ${destination}`);
+    }
+    if (destinations.has(destination))
+      fail(`${sqlName} repeats license destination ${destination}`);
+    destinations.add(destination);
+    if (!FILE_ROLES.has(rawFile.role))
+      fail(`${sqlName} ${destination} must have role license or notice`);
+    const spdx = assertSupportedExtensionUpstreamSpdxId(rawFile.spdx, `${sqlName} ${destination}`);
+    if (typeof rawFile.sha256 !== 'string' || !SHA256.test(rawFile.sha256)) {
+      fail(`${sqlName} ${destination} must declare a lowercase SHA-256 digest`);
+    }
+    files.push(
+      Object.freeze({
+        checkout: source.id,
+        source,
+        path: sourcePath,
+        destination,
+        role: rawFile.role,
+        spdx,
+        licenseUrl: httpsUrl(rawFile.license_url, `${sqlName} ${destination} license URL`),
+        sha256: rawFile.sha256,
+      }),
+    );
+  }
+  const sortedFiles = [...files].sort((left, right) =>
+    compareText(left.destination, right.destination),
+  );
+  if (JSON.stringify(files) !== JSON.stringify(sortedFiles)) {
+    fail(`${sqlName} license files must be sorted by destination`);
+  }
+  const unusedSources = sources.map((source) => source.id).filter((id) => !usedSources.has(id));
+  if (unusedSources.length > 0)
+    fail(`${label} has unused source identities: ${unusedSources.join(', ')}`);
+  const blobs = decodeProductBlobs(
+    data.blobs,
+    files.map((file) => file.sha256),
+    label,
+  );
+  const canonical = `${JSON.stringify(
+    {
+      schema: SCHEMA,
+      sources: sources.map(canonicalSource),
+      extension: {
+        sql_name: sqlName,
+        files: files.map(canonicalFile),
+      },
+      blobs: Object.fromEntries([...blobs.keys()].map((digest) => [digest, data.blobs[digest]])),
+    },
+    null,
+    2,
+  )}\n`;
+  if (bytes !== canonical)
+    fail(`${label} must be canonical two-space JSON with one trailing newline`);
+  return Object.freeze({
+    row: Object.freeze({
+      sqlName,
+      upstreamSpdx: spdxExpression(files.map((file) => file.spdx)),
+      packageSpdx: spdxExpression(['MIT', ...files.map((file) => file.spdx)]),
+      files: Object.freeze(files),
+    }),
+    sources: Object.freeze(sources),
+    blobs,
+  });
+}
+
+const cachedProductContracts = new Map();
+
+function productContractFile(sqlName) {
+  if (typeof sqlName !== 'string' || !SAFE_ID.test(sqlName)) {
+    fail(`invalid extension SQL name ${JSON.stringify(sqlName)}`);
+  }
+  return path.join(EXTERNAL_ROOT, sqlName, PRODUCT_DATA_FILE);
+}
+
+function productContract(sqlName) {
+  let parsed = cachedProductContracts.get(sqlName);
+  if (parsed === undefined) {
+    parsed = parseProductContract(productContractFile(sqlName));
+    cachedProductContracts.set(sqlName, parsed);
+  }
+  return parsed;
+}
+
+function productContractSqlNames() {
+  return readdirSync(EXTERNAL_ROOT, { withFileTypes: true })
+    .filter(
+      (entry) =>
+        entry.isDirectory() && existsSync(path.join(EXTERNAL_ROOT, entry.name, PRODUCT_DATA_FILE)),
+    )
+    .map((entry) => entry.name)
+    .sort(compareText);
+}
+
+function parseContract() {
+  const productContracts = productContractSqlNames().map(productContract);
+  const rows = productContracts.map((entry) => entry.row);
+  const sortedRows = [...rows].sort((left, right) => compareText(left.sqlName, right.sqlName));
+  if (JSON.stringify(rows) !== JSON.stringify(sortedRows))
+    fail('extension license rows must be sorted by sql_name');
+  const sourceById = new Map();
+  for (const source of productContracts.flatMap((entry) => entry.sources)) {
+    const prior = sourceById.get(source.id);
+    if (
+      prior !== undefined &&
+      JSON.stringify(canonicalSource(prior)) !== JSON.stringify(canonicalSource(source))
+    ) {
+      fail(
+        `source id ${source.id} has conflicting identities across product-owned upstream license data`,
+      );
+    }
+    sourceById.set(source.id, source);
+  }
+  const sortedSources = [...sourceById.values()].sort((left, right) =>
+    compareText(left.id, right.id),
+  );
+  const blobs = new Map();
+  for (const productContract of productContracts) {
+    for (const [digest, payload] of productContract.blobs) {
+      const prior = blobs.get(digest);
+      if (prior !== undefined && !prior.equals(payload))
+        fail(`committed upstream license blob conflicts at ${digest}`);
+      blobs.set(digest, payload);
+    }
+  }
+  return Object.freeze({
+    rows: Object.freeze(rows),
+    sources: Object.freeze(sortedSources),
+    blobs,
+  });
+}
+
+let cachedContract;
+
+function contract() {
+  cachedContract ??= parseContract();
+  return cachedContract;
+}
+
+export function extensionUpstreamLicenseRows() {
+  return contract().rows;
+}
+
+export function extensionUpstreamLicenseSources() {
+  return contract().sources;
+}
+
+export function extensionUpstreamLicenseRow(sqlName) {
+  return productContract(sqlName).row;
+}
+
+export function externalReleaseExtensionSqlNames() {
+  const sqlNames = [];
+  for (const entry of readdirSync(path.join(ROOT, 'src/extensions/external'), {
+    withFileTypes: true,
+  })) {
+    if (!entry.isDirectory()) continue;
+    const releaseFile = path.join(ROOT, 'src/extensions/external', entry.name, 'release.toml');
+    if (existsSync(releaseFile)) {
+      let release;
+      try {
+        release = Bun.TOML.parse(readFileSync(releaseFile, 'utf8'));
+      } catch (cause) {
+        fail(`${path.relative(ROOT, releaseFile)} cannot be read: ${cause.message}`);
+      }
+      if (
+        typeof release?.extension_sql_name !== 'string' ||
+        !SAFE_ID.test(release.extension_sql_name)
+      ) {
+        fail(`${path.relative(ROOT, releaseFile)} must declare a safe extension_sql_name`);
+      }
+      sqlNames.push(release.extension_sql_name);
+      continue;
+    }
+  }
+  const canonical = [...new Set(sqlNames)].sort(compareText);
+  if (canonical.length !== sqlNames.length) fail('external release SQL names must be unique');
+  return Object.freeze(canonical);
+}
+
+export function validateExtensionUpstreamLicenseContract() {
+  const rows = extensionUpstreamLicenseRows();
+  const expected = externalReleaseExtensionSqlNames();
+  const actual = rows.map((row) => row.sqlName);
+  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+    fail(
+      `contract extension set mismatch: expected ${expected.join(', ')}, got ${actual.join(', ')}`,
+    );
+  }
+  committedLicenseBlobs(rows.flatMap((row) => row.files.map((file) => file.sha256)));
+  return rows;
+}
+
+function externalLicenseRow(product, members) {
+  if (members.length !== 1) {
+    fail(
+      `${product} is not the explicit contrib bundle and must have exactly one external extension member`,
+    );
+  }
+  const row = extensionUpstreamLicenseRow(members[0]);
+  const releaseToml = path.join(ROOT, 'src/extensions/external', row.sqlName, 'release.toml');
+  let release;
+  try {
+    release = Bun.TOML.parse(readFileSync(releaseToml, 'utf8'));
+  } catch (cause) {
+    fail(`${path.relative(ROOT, releaseToml)} cannot be read: ${cause.message}`);
+  }
+  if (release?.id !== product || release?.extension_sql_name !== row.sqlName) {
+    fail(`${product} does not match ${row.sqlName}'s release identity`);
+  }
+  return row;
+}
+
+export function extensionRegistryLicense(product, members) {
+  if (
+    typeof product !== 'string' ||
+    !Array.isArray(members) ||
+    members.length === 0 ||
+    members.some((member) => typeof member !== 'string' || !member)
+  ) {
+    fail('registry license lookup requires a product and non-empty member list');
+  }
+  if (product === CONTRIB_LICENSE.product) return CONTRIB_LICENSE;
+  const row = externalLicenseRow(product, members);
+  return Object.freeze({
+    product,
+    upstreamSpdx: row.upstreamSpdx,
+    packageSpdx: row.packageSpdx,
+  });
+}
+
+export function extensionMavenLicenses(product, members, { version } = {}) {
+  if (product === CONTRIB_LICENSE.product) {
+    return releaseMavenLicenses({ product, version, components: ['postgresql'] });
+  }
+  const row = externalLicenseRow(product, members);
+  const entries = [...releaseMavenLicenses({ product, version })];
+  const seen = new Set(entries.map((entry) => JSON.stringify(entry)));
+  for (const file of row.files.filter((candidate) => candidate.role === 'license')) {
+    const entry = Object.freeze({
+      name: `${file.spdx} (${file.source.id})`,
+      url: file.licenseUrl,
+      distribution: 'repo',
+    });
+    const key = JSON.stringify(entry);
+    if (!seen.has(key)) {
+      entries.push(entry);
+      seen.add(key);
+    }
+  }
+  return Object.freeze(entries);
+}
+
+function hashFile(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function committedLicenseBlobs(expectedDigests) {
+  const blobs = contract().blobs;
+  const actual = [...blobs.keys()].sort(compareText);
+  const expected = [...new Set(expectedDigests)].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+    fail(
+      `committed upstream license blob set differs: expected ${expected.join(', ')}, got ${actual.join(', ')}`,
+    );
+  }
+  return blobs;
+}
+
+function productLicenseBlobs(sqlName, expectedDigests) {
+  const blobs = productContract(sqlName).blobs;
+  const actual = [...blobs.keys()].sort(compareText);
+  const expected = [...new Set(expectedDigests)].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+    fail(
+      `${sqlName} committed upstream license blob set differs: expected ${expected.join(', ')}, got ${actual.join(', ')}`,
+    );
+  }
+  return blobs;
+}
+
+function requireRealDirectory(directory, label, { create = false } = {}) {
+  let stat;
+  try {
+    stat = lstatSync(directory);
+  } catch (cause) {
+    if (cause?.code !== 'ENOENT' || !create) fail(`${label} cannot be inspected: ${cause.message}`);
+    mkdirSync(directory, { mode: 0o755 });
+    stat = lstatSync(directory);
+  }
+  if (!stat.isDirectory() || stat.isSymbolicLink())
+    fail(`${label} must be a real directory: ${directory}`);
+}
+
+function requireSafeDirectoryChain(directory, { create = true, label = 'license staging' } = {}) {
+  try {
+    return requireReleaseDirectoryChain(directory, { create, label });
+  } catch (cause) {
+    fail(cause.message);
+  }
+}
+
+function safeDestination(root, relative) {
+  const destination = path.join(root, ...relative.split('/'));
+  let cursor = root;
+  for (const part of relative.split('/').slice(0, -1)) {
+    cursor = path.join(cursor, part);
+    requireRealDirectory(cursor, 'license staging parent', { create: true });
+  }
+  let stat;
+  try {
+    stat = lstatSync(destination);
+  } catch (cause) {
+    if (cause?.code !== 'ENOENT')
+      fail(`license destination cannot be inspected: ${destination} (${cause.message})`);
+  }
+  if (stat && (!stat.isFile() || stat.isSymbolicLink())) {
+    fail(`license destination must be absent or a regular non-symlink file: ${destination}`);
+  }
+  return destination;
+}
+
+export function stageExtensionUpstreamLicenses(sqlName, filesRoot) {
+  const externalRoot = path.join(ROOT, 'src/extensions/external', sqlName);
+  if (!existsSync(path.join(externalRoot, 'release.toml'))) return Object.freeze([]);
+  const row = extensionUpstreamLicenseRow(sqlName);
+  const blobs = productLicenseBlobs(
+    sqlName,
+    row.files.map((file) => file.sha256),
+  );
+  const stagingRoot = requireSafeDirectoryChain(filesRoot);
+  const staged = [];
+  for (const file of row.files) {
+    const source = blobs.get(file.sha256);
+    if (source === undefined)
+      fail(`${sqlName} has no committed legal bytes for ${file.destination}`);
+    const destination = safeDestination(stagingRoot, file.destination);
+    writeFileSync(destination, source);
+    chmodSync(destination, 0o644);
+    const destinationStat = lstatSync(destination);
+    if (
+      !destinationStat.isFile() ||
+      destinationStat.isSymbolicLink() ||
+      !hasCanonicalReleaseStagingMode(destinationStat.mode)
+    ) {
+      fail(`${sqlName} staged license is not a regular mode-0644 file: ${file.destination}`);
+    }
+    if (hashFile(destination) !== file.sha256)
+      fail(`${sqlName} staged license bytes changed for ${file.destination}`);
+    staged.push(file.destination);
+  }
+  return Object.freeze(staged);
+}
+
+export function auditExtensionUpstreamLicenseSources() {
+  const blobs = committedLicenseBlobs(
+    extensionUpstreamLicenseRows().flatMap((row) => row.files.map((file) => file.sha256)),
+  );
+  let checked = 0;
+  for (const row of extensionUpstreamLicenseRows()) {
+    for (const file of row.files) {
+      // Source acquisition verifies the checkout identity before this byte audit.
+      const sourceRoot = path.join(CHECKOUT_ROOT, file.source.id);
+      requireRealDirectory(sourceRoot, `${file.source.id} checkout`);
+      const source = path.join(sourceRoot, ...file.path.split('/'));
+      let sourceStat;
+      try {
+        sourceStat = lstatSync(source);
+      } catch (cause) {
+        fail(
+          `${row.sqlName} license source is missing: ${path.relative(ROOT, source)} (${cause.message})`,
+        );
+      }
+      if (!sourceStat.isFile() || sourceStat.isSymbolicLink()) {
+        fail(
+          `${row.sqlName} license source must be a regular non-symlink file: ${path.relative(ROOT, source)}`,
+        );
+      }
+      const realRoot = realpathSync(sourceRoot);
+      const realSource = realpathSync(source);
+      if (!realSource.startsWith(`${realRoot}${path.sep}`)) {
+        fail(`${row.sqlName} license source escapes checkout ${file.source.id}: ${file.path}`);
+      }
+      const sourceBytes = readFileSync(source);
+      const actualSha256 = createHash('sha256').update(sourceBytes).digest('hex');
+      if (actualSha256 !== file.sha256 || !sourceBytes.equals(blobs.get(file.sha256))) {
+        fail(
+          `${row.sqlName} legal bytes changed for ${file.source.id}/${file.path}: expected committed digest ${file.sha256}, got ${actualSha256}`,
+        );
+      }
+      checked += 1;
+    }
+  }
+  return checked;
+}
+
+function checkedLicenseRows(sqlNames) {
+  if (
+    !Array.isArray(sqlNames) ||
+    sqlNames.length === 0 ||
+    sqlNames.some((sqlName) => typeof sqlName !== 'string' || !SAFE_ID.test(sqlName)) ||
+    new Set(sqlNames).size !== sqlNames.length
+  ) {
+    fail('upstream license assertion requires a non-empty unique extension member list');
+  }
+  return sqlNames.map(extensionUpstreamLicenseRow);
+}
+
+function expectedLicenseFiles(sqlNames) {
+  const expected = new Map();
+  for (const row of checkedLicenseRows(sqlNames)) {
+    for (const file of row.files) {
+      const prior = expected.get(file.destination);
+      if (prior && prior.sha256 !== file.sha256) {
+        fail(`upstream license destination collision at ${file.destination}`);
+      }
+      expected.set(file.destination, file);
+    }
+  }
+  return expected;
+}
+
+export function extensionUpstreamLicenseFileInventory(sqlNames) {
+  return Object.freeze(
+    [...expectedLicenseFiles(sqlNames).values()]
+      .sort((left, right) => compareText(left.destination, right.destination))
+      .map((file) =>
+        Object.freeze({
+          path: file.destination,
+          sha256: file.sha256,
+          mode: '0644',
+        }),
+      ),
+  );
+}
+
+export function extensionCarrierLegalContract(
+  product,
+  sqlNames,
+  { family, target, carriesPayload = true } = {},
+) {
+  if (
+    typeof product !== 'string' ||
+    !product ||
+    !Array.isArray(sqlNames) ||
+    sqlNames.length === 0 ||
+    sqlNames.some((sqlName) => typeof sqlName !== 'string' || !SAFE_ID.test(sqlName)) ||
+    new Set(sqlNames).size !== sqlNames.length ||
+    typeof carriesPayload !== 'boolean'
+  ) {
+    fail(
+      'carrier legal lookup requires a product, a unique non-empty extension member list, and carriesPayload',
+    );
+  }
+  if (!carriesPayload) {
+    return Object.freeze({
+      profile: 'code-facade',
+      packageSpdx: releaseProfilePackageLicense('code-facade').spdx,
+      upstreamMembers: Object.freeze([]),
+      licenseFiles: Object.freeze([]),
+    });
+  }
+  if (!new Set(['native', 'wasix']).has(family) || typeof target !== 'string' || !target) {
+    fail('payload-bearing carrier legal lookup requires family=native|wasix and an exact target');
+  }
+  if (product === CONTRIB_LICENSE.product) {
+    const embedsOpenSsl =
+      sqlNames.includes('pgcrypto') &&
+      (family === 'wasix' || OPENSSL_EMBEDDED_NATIVE_TARGETS.has(target));
+    const profile = `${family === 'native' ? 'contrib-native' : 'contrib-wasix'}${embedsOpenSsl ? '-openssl' : ''}`;
+    return Object.freeze({
+      profile,
+      packageSpdx: releaseProfilePackageLicense(profile).spdx,
+      upstreamMembers: Object.freeze([]),
+      licenseFiles: Object.freeze([]),
+    });
+  }
+  const registry = extensionRegistryLicense(product, sqlNames);
+  const licenseFiles = [...expectedLicenseFiles(sqlNames).keys()].sort(compareText);
+  return Object.freeze({
+    profile: `external-${family}`,
+    packageSpdx: registry.packageSpdx,
+    upstreamMembers: Object.freeze([...sqlNames]),
+    licenseFiles: Object.freeze(licenseFiles),
+  });
+}
+
+export function extensionCarrierLegalFileInventory(
+  product,
+  sqlNames,
+  { family, target, carriesPayload = true } = {},
+) {
+  const legal = extensionCarrierLegalContract(product, sqlNames, {
+    family,
+    target,
+    carriesPayload,
+  });
+  const files = new Map();
+  const add = (file, bytes, expectedSha256 = undefined) => {
+    const payload = Buffer.from(bytes);
+    const sha256 = createHash('sha256').update(payload).digest('hex');
+    if (expectedSha256 !== undefined && sha256 !== expectedSha256) {
+      fail(`canonical legal bytes changed for ${file}: expected ${expectedSha256}, got ${sha256}`);
+    }
+    const row = Object.freeze({
+      path: simpleRelative(file, 'carrier legal member'),
+      sha256,
+      bytes: payload.length,
+      mode: '0644',
+    });
+    const prior = files.get(row.path);
+    if (
+      prior !== undefined &&
+      (prior.sha256 !== row.sha256 || prior.bytes !== row.bytes || prior.mode !== row.mode)
+    ) {
+      fail(`carrier legal member collision at ${row.path}`);
+    }
+    files.set(row.path, prior ?? row);
+  };
+
+  for (const row of releaseNoticeRows({ profile: legal.profile })) {
+    add(row.member, readFileSync(row.source), row.sha256);
+  }
+
+  const upstreamPaths = [];
+  for (const sqlName of legal.upstreamMembers) {
+    const row = extensionUpstreamLicenseRow(sqlName);
+    const blobs = productLicenseBlobs(
+      sqlName,
+      row.files.map((file) => file.sha256),
+    );
+    for (const file of row.files) {
+      const bytes = blobs.get(file.sha256);
+      if (bytes === undefined)
+        fail(`${sqlName} has no committed legal bytes for ${file.destination}`);
+      upstreamPaths.push(file.destination);
+      add(file.destination, bytes, file.sha256);
+    }
+  }
+  const actualUpstreamPaths = [...new Set(upstreamPaths)].sort(compareText);
+  if (JSON.stringify(actualUpstreamPaths) !== JSON.stringify([...legal.licenseFiles])) {
+    fail(
+      `carrier legal file inventory differs from its contract: expected ${legal.licenseFiles.join(', ')}, ` +
+        `got ${actualUpstreamPaths.join(', ')}`,
+    );
+  }
+
+  return Object.freeze(
+    [...files.values()].sort((left, right) => compareText(left.path, right.path)),
+  );
+}
+
+function checkedArchivePrefix(value = '') {
+  if (value === '') return '';
+  return simpleRelative(String(value).replace(/\/$/u, ''), 'upstream license archive prefix');
+}
+
+function prefixed(prefix, member) {
+  return prefix ? `${prefix}/${member}` : member;
+}
+
+export function assertExtensionUpstreamLicensesInDirectory(sqlNames, filesRoot) {
+  const root = requireSafeDirectoryChain(filesRoot, {
+    create: false,
+    label: 'upstream license assertion',
+  });
+  const expected = expectedLicenseFiles(sqlNames);
+  const actualFiles = [];
+  const actualDirectories = [];
+  const licensesRoot = path.join(root, 'share/licenses');
+  const visit = (directory) => {
+    for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) =>
+      compareText(left.name, right.name),
+    )) {
+      const candidate = path.join(directory, entry.name);
+      const stat = lstatSync(candidate);
+      if (stat.isSymbolicLink())
+        fail(`staged upstream license must not be a symlink: ${candidate}`);
+      if (stat.isDirectory()) {
+        actualDirectories.push(path.relative(root, candidate).split(path.sep).join('/'));
+        visit(candidate);
+      } else if (stat.isFile()) {
+        actualFiles.push(path.relative(root, candidate).split(path.sep).join('/'));
+      } else {
+        fail(`staged upstream license tree contains a special entry: ${candidate}`);
+      }
+    }
+  };
+  if (!existsSync(licensesRoot))
+    fail(`staged upstream license directory is missing: ${licensesRoot}`);
+  const licensesRootStat = lstatSync(licensesRoot);
+  if (!licensesRootStat.isDirectory() || licensesRootStat.isSymbolicLink()) {
+    fail(`staged upstream license root must be a real directory: ${licensesRoot}`);
+  }
+  visit(licensesRoot);
+  const expectedNames = [...expected.keys()].sort(compareText);
+  const expectedDirectories = expectedLicenseDirectories(expectedNames);
+  if (JSON.stringify(actualFiles.sort(compareText)) !== JSON.stringify(expectedNames)) {
+    fail(
+      `staged upstream license members differ: expected ${expectedNames.join(', ')}, got ${actualFiles.sort(compareText).join(', ')}`,
+    );
+  }
+  if (JSON.stringify(actualDirectories.sort(compareText)) !== JSON.stringify(expectedDirectories)) {
+    fail(
+      `staged upstream license directories differ: expected ${expectedDirectories.join(', ')}, ` +
+        `got ${actualDirectories.sort(compareText).join(', ')}`,
+    );
+  }
+  for (const [destination, file] of expected) {
+    const staged = path.join(root, ...destination.split('/'));
+    const stat = lstatSync(staged);
+    if (!stat.isFile() || stat.isSymbolicLink() || !hasCanonicalReleaseStagingMode(stat.mode)) {
+      fail(`staged upstream license must be a regular mode-0644 file: ${destination}`);
+    }
+    if (hashFile(staged) !== file.sha256)
+      fail(`staged upstream license bytes changed for ${destination}`);
+  }
+  return Object.freeze(expectedNames);
+}
+
+function expectedLicenseDirectories(expectedNames, prefix = '') {
+  const namespaceRoot = prefixed(prefix, 'share/licenses');
+  const directories = new Set();
+  for (const member of expectedNames) {
+    let directory = path.posix.dirname(member);
+    while (directory !== namespaceRoot) {
+      if (!directory.startsWith(`${namespaceRoot}/`)) {
+        fail(`upstream license member escapes its namespace: ${member}`);
+      }
+      directories.add(directory);
+      directory = path.posix.dirname(directory);
+    }
+  }
+  return [...directories].sort(compareText);
+}
+
+function archiveEntryKind(entry) {
+  if (entry?.isSymbolicLink) return 'symlink';
+  if (entry?.isFile && !entry?.isDirectory) return 'file';
+  if (entry?.isDirectory && !entry?.isFile) return 'directory';
+  return 'special';
+}
+
+export function assertExtensionUpstreamLicensesInEntries(sqlNames, entries, { prefix = '' } = {}) {
+  if (!(entries instanceof Map)) fail('upstream license archive entries must be a Map');
+  const normalizedPrefix = checkedArchivePrefix(prefix);
+  const expected = expectedLicenseFiles(sqlNames);
+  const expectedNames = [...expected.keys()]
+    .map((member) => prefixed(normalizedPrefix, member))
+    .sort(compareText);
+  const namespaceRoot = prefixed(normalizedPrefix, 'share/licenses');
+  const expectedDirectories = new Set(expectedLicenseDirectories(expectedNames, normalizedPrefix));
+  expectedDirectories.add(namespaceRoot);
+  const actualNames = [];
+  for (const [member, entry] of entries) {
+    if (member !== namespaceRoot && !member.startsWith(`${namespaceRoot}/`)) continue;
+    const kind = archiveEntryKind(entry);
+    if (expectedNames.includes(member)) {
+      if (kind !== 'file' || (entry.mode & 0o7777) !== 0o644) {
+        fail(`packed upstream license must be a regular non-symlink mode-0644 file: ${member}`);
+      }
+      actualNames.push(member);
+      continue;
+    }
+    if (expectedDirectories.has(member)) {
+      if (kind !== 'directory' || (entry.mode & 0o7777) !== 0o755) {
+        fail(`packed upstream license directory must be a real mode-0755 directory: ${member}`);
+      }
+      continue;
+    }
+    fail(`packed upstream license namespace contains unexpected ${kind} member: ${member}`);
+  }
+  actualNames.sort(compareText);
+  if (JSON.stringify(actualNames) !== JSON.stringify(expectedNames)) {
+    fail(
+      `packed upstream license members differ: expected ${expectedNames.join(', ')}, got ${actualNames.join(', ')}`,
+    );
+  }
+  for (const [destination, file] of expected) {
+    const member = prefixed(normalizedPrefix, destination);
+    const entry = entries.get(member);
+    if (archiveEntryKind(entry) !== 'file' || (entry.mode & 0o7777) !== 0o644) {
+      fail(`packed upstream license must be a regular non-symlink mode-0644 file: ${member}`);
+    }
+    const actual = createHash('sha256').update(entry.data()).digest('hex');
+    if (actual !== file.sha256) fail(`packed upstream license bytes changed for ${member}`);
+  }
+  return Object.freeze(expectedNames);
+}
+
+export function assertExtensionUpstreamLicensesInArchive(sqlNames, archive, options = {}) {
+  return assertExtensionUpstreamLicensesInEntries(
+    sqlNames,
+    readPortableArchiveEntries(archive),
+    options,
+  );
+}
+
+if (import.meta.main) {
+  if (process.argv.length !== 3 || process.argv[2] !== 'audit-sources') {
+    throw new Error('usage: extension-upstream-licenses.mts audit-sources');
+  }
+  console.log(`Verified ${auditExtensionUpstreamLicenseSources()} pinned source license files`);
+}
diff --git a/src/extensions/tools/extension-upstream-licenses.test.mts b/src/extensions/tools/extension-upstream-licenses.test.mts
new file mode 100644
index 000000000..e412a37a2
--- /dev/null
+++ b/src/extensions/tools/extension-upstream-licenses.test.mts
@@ -0,0 +1,425 @@
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import {
+  existsSync,
+  lstatSync,
+  mkdirSync,
+  mkdtempSync,
+  readFileSync,
+  rmSync,
+  symlinkSync,
+  writeFileSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import { createDeterministicTar } from '../../../tools/packaging/cargo-source-package.mts';
+import {
+  canonicalGzipSync,
+  readPortableArchiveEntries,
+} from '../../../tools/packaging/portable-archive.mts';
+import { hasCanonicalReleaseStagingMode } from '../../../tools/packaging/release-notices.mts';
+import {
+  assertExtensionUpstreamLicensesInEntries,
+  assertExtensionUpstreamLicensesInArchive,
+  assertExtensionUpstreamLicensesInDirectory,
+  assertSupportedExtensionUpstreamSpdxId,
+  externalReleaseExtensionSqlNames,
+  extensionCarrierLegalContract,
+  extensionCarrierLegalFileInventory,
+  extensionMavenLicenses,
+  extensionRegistryLicense,
+  stageExtensionUpstreamLicenses,
+  extensionUpstreamLicenseFileInventory,
+  extensionUpstreamLicenseRows,
+  validateExtensionUpstreamLicenseContract,
+} from './extension-upstream-licenses.mts';
+
+const ROOT = path.resolve(import.meta.dirname, '../../..');
+
+test('every active external release has an exact upstream license contract', () => {
+  const rows = validateExtensionUpstreamLicenseContract();
+  assert.deepEqual(
+    rows.map((row) => row.sqlName),
+    externalReleaseExtensionSqlNames(),
+  );
+  for (const row of rows) {
+    assert.ok(row.files.length > 0, `${row.sqlName} must ship at least one license file`);
+    assert.equal(new Set(row.files.map((file) => file.destination)).size, row.files.length);
+  }
+});
+
+test('npm extension legal inventory binds canonical paths, bytes, and modes', () => {
+  const row = extensionUpstreamLicenseRows().find(({ sqlName }) => sqlName === 'pg_uuidv7');
+  assert.ok(row, 'pg_uuidv7 must have canonical upstream legal metadata');
+  assert.deepEqual(
+    extensionUpstreamLicenseFileInventory(['pg_uuidv7']),
+    row.files.map((file) => ({
+      path: file.destination,
+      sha256: file.sha256,
+      mode: '0644',
+    })),
+  );
+  const postgis = extensionUpstreamLicenseFileInventory(['postgis']);
+  assert.deepEqual(
+    postgis.map(({ path: member }) => member),
+    [...postgis].map(({ path: member }) => member).sort(),
+  );
+  assert.equal(Object.isFrozen(postgis), true);
+  assert.equal(postgis.every(Object.isFrozen), true);
+  assert.throws(
+    () => extensionUpstreamLicenseFileInventory([]),
+    /requires a non-empty unique extension member list/u,
+  );
+});
+
+test('carrier legal inventory binds release notices and PostGIS upstream bytes', () => {
+  const legal = extensionCarrierLegalContract('oliphaunt-extension-postgis', ['postgis'], {
+    family: 'native',
+    target: 'android-arm64-v8a',
+  });
+  const files = extensionCarrierLegalFileInventory('oliphaunt-extension-postgis', ['postgis'], {
+    family: 'native',
+    target: 'android-arm64-v8a',
+  });
+  assert.deepEqual(
+    files
+      .filter(({ path: file }) => file.startsWith('share/licenses/'))
+      .map(({ path: file }) => file),
+    [...legal.licenseFiles],
+  );
+  assert.deepEqual(
+    files.slice(0, 2).map(({ path: file }) => file),
+    ['LICENSE', 'THIRD_PARTY_NOTICES.md'],
+  );
+  assert.equal(
+    files.every(({ bytes }) => Number.isSafeInteger(bytes) && bytes > 0),
+    true,
+  );
+  assert.equal(
+    files.every(({ sha256 }) => /^[0-9a-f]{64}$/u.test(sha256)),
+    true,
+  );
+  assert.equal(
+    files.every(({ mode }) => mode === '0644'),
+    true,
+  );
+  assert.equal(Object.isFrozen(files), true);
+  assert.equal(files.every(Object.isFrozen), true);
+});
+
+test('committed legal bytes stage every active external release without source checkouts', (t) => {
+  const root = mkdtempSync(path.join(tmpdir(), 'external-license-clean-stage-'));
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+  const missingCheckouts = process.env.OLIPHAUNT_EXTENSION_SOURCE_CHECKOUT_ROOT;
+  assert.ok(missingCheckouts, 'run bash src/extensions/tools/extension-upstream-licenses.test.sh');
+  assert.equal(existsSync(missingCheckouts), false);
+  for (const sqlName of externalReleaseExtensionSqlNames()) {
+    const stage = path.join(root, sqlName);
+    mkdirSync(stage, { recursive: true });
+    const staged = stageExtensionUpstreamLicenses(sqlName, stage);
+    assert.deepEqual(assertExtensionUpstreamLicensesInDirectory([sqlName], stage), staged);
+    const archive = path.join(root, `${sqlName}.tar.gz`);
+    writeFileSync(archive, canonicalGzipSync(createDeterministicTar(stage, sqlName, {})));
+    assert.deepEqual(
+      assertExtensionUpstreamLicensesInArchive([sqlName], archive, { prefix: sqlName }),
+      staged.map((member) => `${sqlName}/${member}`),
+    );
+  }
+  assert.equal(existsSync(missingCheckouts), false);
+});
+
+test("the contract retains dependency licenses and pgtap's complete upstream grant", () => {
+  const rows = extensionUpstreamLicenseRows();
+  const postgis = rows.find((row) => row.sqlName === 'postgis');
+  assert.deepEqual(
+    [...new Set(postgis.files.map((file) => file.checkout))],
+    ['geos', 'json-c', 'libiconv', 'libxml2', 'postgis', 'proj', 'sqlite'],
+  );
+  assert.deepEqual(
+    postgis.files.filter((file) => file.checkout === 'libiconv').map((file) => file.path),
+    ['libcharset/COPYING.LIB', 'COPYING.LIB'],
+  );
+  assert.deepEqual(
+    postgis.files
+      .filter((file) => file.checkout === 'geos' && file.path.startsWith('src/deps/ryu/'))
+      .map((file) => file.path),
+    ['src/deps/ryu/LICENSE', 'src/deps/ryu/LICENSE-Apache2', 'src/deps/ryu/LICENSE-Boost'],
+  );
+  assert.deepEqual(
+    postgis.files.filter((file) => file.checkout === 'postgis').map((file) => file.path),
+    [
+      'COPYING',
+      'LICENSE.TXT',
+      'deps/flatgeobuf/include/flatbuffers/LICENSE',
+      'deps/ryu/LICENSE',
+      'deps/ryu/LICENSE-Apache2',
+      'deps/ryu/LICENSE-Boost',
+    ],
+  );
+  const pgtap = rows.find((row) => row.sqlName === 'pgtap');
+  assert.equal(pgtap.files.length, 1);
+  assert.equal(pgtap.files[0].path, 'README.md');
+  const source = path.join(ROOT, 'target/oliphaunt-sources/checkouts/pgtap/README.md');
+  try {
+    const text = readFileSync(source, 'utf8');
+    assert.match(text, /Permission to use, copy, modify, and distribute/u);
+  } catch (error) {
+    if (error?.code !== 'ENOENT') throw error;
+  }
+});
+
+test('registry metadata derives external and contrib SPDX expressions from the same contract', () => {
+  assert.deepEqual(extensionRegistryLicense('oliphaunt-extension-pg-uuidv7', ['pg_uuidv7']), {
+    product: 'oliphaunt-extension-pg-uuidv7',
+    upstreamSpdx: 'MPL-2.0',
+    packageSpdx: 'MIT AND MPL-2.0',
+  });
+  assert.deepEqual(extensionRegistryLicense('oliphaunt-extension-postgis', ['postgis']), {
+    product: 'oliphaunt-extension-postgis',
+    upstreamSpdx: 'MIT AND Apache-2.0 AND GPL-2.0-or-later AND LGPL-2.1-or-later AND blessing',
+    packageSpdx: 'MIT AND Apache-2.0 AND GPL-2.0-or-later AND LGPL-2.1-or-later AND blessing',
+  });
+  assert.deepEqual(
+    extensionRegistryLicense('oliphaunt-extension-contrib-pg18', ['hstore', 'pgcrypto']),
+    {
+      product: 'oliphaunt-extension-contrib-pg18',
+      upstreamSpdx: 'PostgreSQL',
+      packageSpdx: 'MIT AND PostgreSQL',
+    },
+  );
+  assert.deepEqual(
+    extensionRegistryLicense('oliphaunt-extension-pg-hashids', ['pg_hashids']).packageSpdx,
+    'MIT',
+  );
+  const maven = extensionMavenLicenses('oliphaunt-extension-pg-uuidv7', ['pg_uuidv7'], {
+    version: '0.1.0',
+  });
+  assert.deepEqual(
+    maven.map((entry) => entry.name),
+    ['MIT License (Oliphaunt)', 'MPL-2.0 (pg_uuidv7)'],
+  );
+  assert.match(maven[0].url, /\/blob\/oliphaunt-extension-pg-uuidv7-v0\.1\.0\/LICENSE$/u);
+  assert.match(maven[1].url, /c707aae2411181be4802f5fa565b44d9c0bcbc29\/LICENSE$/u);
+});
+
+test('carrier legal roles derive exact contrib and external payload closure', () => {
+  assert.deepEqual(
+    extensionCarrierLegalContract('oliphaunt-extension-contrib-pg18', ['hstore', 'pgcrypto'], {
+      family: 'native',
+      target: 'linux-x64-gnu',
+    }),
+    {
+      profile: 'contrib-native',
+      packageSpdx: 'MIT AND PostgreSQL',
+      upstreamMembers: [],
+      licenseFiles: [],
+    },
+  );
+  assert.equal(
+    extensionCarrierLegalContract('oliphaunt-extension-contrib-pg18', ['hstore', 'pgcrypto'], {
+      family: 'wasix',
+      target: 'wasix',
+    }).profile,
+    'contrib-wasix-openssl',
+  );
+  const postgis = extensionCarrierLegalContract('oliphaunt-extension-postgis', ['postgis'], {
+    family: 'native',
+    target: 'android-arm64-v8a',
+  });
+  assert.equal(postgis.profile, 'external-native');
+  assert.deepEqual(postgis.upstreamMembers, ['postgis']);
+  assert.deepEqual(postgis.licenseFiles, [
+    'share/licenses/geos/COPYING',
+    'share/licenses/geos/src/deps/ryu/LICENSE',
+    'share/licenses/geos/src/deps/ryu/LICENSE-Apache2',
+    'share/licenses/geos/src/deps/ryu/LICENSE-Boost',
+    'share/licenses/json-c/COPYING',
+    'share/licenses/libcharset/COPYING.LIB',
+    'share/licenses/libiconv/COPYING.LIB',
+    'share/licenses/libxml2/Copyright',
+    'share/licenses/postgis/COPYING',
+    'share/licenses/postgis/LICENSE.TXT',
+    'share/licenses/postgis/deps/flatgeobuf/flatbuffers/LICENSE',
+    'share/licenses/postgis/deps/ryu/LICENSE',
+    'share/licenses/postgis/deps/ryu/LICENSE-Apache2',
+    'share/licenses/postgis/deps/ryu/LICENSE-Boost',
+    'share/licenses/proj/COPYING',
+    'share/licenses/sqlite/LICENSE.md',
+  ]);
+  assert.deepEqual(
+    extensionCarrierLegalContract('oliphaunt-extension-vector', ['vector'], {
+      carriesPayload: false,
+    }),
+    {
+      profile: 'code-facade',
+      packageSpdx: 'MIT',
+      upstreamMembers: [],
+      licenseFiles: [],
+    },
+  );
+});
+
+test('SPDX metadata fails closed to the identifiers supported by the carrier contract', () => {
+  assert.equal(assertSupportedExtensionUpstreamSpdxId('MPL-2.0'), 'MPL-2.0');
+  assert.throws(
+    () => assertSupportedExtensionUpstreamSpdxId('Unknown-License-1.0'),
+    /must declare one supported SPDX identifier/u,
+  );
+});
+
+test('staging verifies committed bytes, mode, and directory safety', (t) => {
+  const root = mkdtempSync(path.join(tmpdir(), 'extension-license-stage-'));
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+  const stage = path.join(root, 'stage');
+  const staged = stageExtensionUpstreamLicenses('pg_hashids', stage);
+  assert.deepEqual(staged, ['share/licenses/pg_hashids/LICENSE']);
+  const output = path.join(stage, staged[0]);
+  assert.equal(hasCanonicalReleaseStagingMode(lstatSync(output).mode), true);
+  assert.equal(
+    createHash('sha256').update(readFileSync(output)).digest('hex'),
+    extensionUpstreamLicenseRows().find(({ sqlName }) => sqlName === 'pg_hashids').files[0].sha256,
+  );
+  assert.deepEqual(assertExtensionUpstreamLicensesInDirectory(['pg_hashids'], stage), staged);
+
+  const archive = path.join(root, 'pg-hashids.crate');
+  writeFileSync(
+    archive,
+    canonicalGzipSync(
+      createDeterministicTar(stage, 'pg-hashids-0.1.0', {
+        fail(message) {
+          throw new Error(message);
+        },
+      }),
+    ),
+  );
+  assert.deepEqual(
+    assertExtensionUpstreamLicensesInArchive(['pg_hashids'], archive, {
+      prefix: 'pg-hashids-0.1.0',
+    }),
+    ['pg-hashids-0.1.0/share/licenses/pg_hashids/LICENSE'],
+  );
+
+  const entries = readPortableArchiveEntries(archive);
+  const assertion = (mutated) =>
+    assertExtensionUpstreamLicensesInEntries(['pg_hashids'], mutated, {
+      prefix: 'pg-hashids-0.1.0',
+    });
+  const inject = (member, entry) => new Map([...entries, [member, entry]]);
+  const fakeEntry = (overrides = {}) => ({
+    data: () => Buffer.from('unexpected'),
+    isDirectory: false,
+    isFile: true,
+    isSymbolicLink: false,
+    mode: 0o644,
+    ...overrides,
+  });
+  assert.throws(
+    () => assertion(inject('pg-hashids-0.1.0/share/licenses/unknown/LICENSE', fakeEntry())),
+    /unexpected file member/u,
+  );
+  assert.throws(
+    () =>
+      assertion(
+        inject(
+          'pg-hashids-0.1.0/share/licenses/unknown',
+          fakeEntry({ isDirectory: true, isFile: false, mode: 0o755 }),
+        ),
+      ),
+    /unexpected directory member/u,
+  );
+  assert.throws(
+    () =>
+      assertion(
+        inject(
+          'pg-hashids-0.1.0/share/licenses/unknown-link',
+          fakeEntry({ isFile: false, isSymbolicLink: true, mode: 0o777 }),
+        ),
+      ),
+    /unexpected symlink member/u,
+  );
+  assert.throws(
+    () =>
+      assertion(
+        inject(
+          'pg-hashids-0.1.0/share/licenses/unknown-special',
+          fakeEntry({ isFile: false, mode: 0o600 }),
+        ),
+      ),
+    /unexpected special member/u,
+  );
+  const wrongDirectoryMode = new Map(entries);
+  const directoryMember = 'pg-hashids-0.1.0/share/licenses/pg_hashids';
+  wrongDirectoryMode.set(directoryMember, {
+    ...wrongDirectoryMode.get(directoryMember),
+    mode: 0o700,
+  });
+  assert.throws(() => assertion(wrongDirectoryMode), /directory must be a real mode-0755/u);
+
+  const privilegedFileMode = new Map(entries);
+  const licenseMember = 'pg-hashids-0.1.0/share/licenses/pg_hashids/LICENSE';
+  privilegedFileMode.set(licenseMember, {
+    ...privilegedFileMode.get(licenseMember),
+    mode: 0o4644,
+  });
+  assert.throws(
+    () => assertion(privilegedFileMode),
+    /must be a regular non-symlink mode-0644 file/u,
+  );
+
+  const missingAssertionRoot = path.join(root, 'missing-parent', 'missing-stage');
+  assert.throws(
+    () => assertExtensionUpstreamLicensesInDirectory(['pg_hashids'], missingAssertionRoot),
+    /upstream license assertion cannot be inspected/u,
+  );
+  assert.equal(existsSync(path.join(root, 'missing-parent')), false);
+
+  const unsafe = path.join(root, 'unsafe');
+  const outside = path.join(root, 'outside');
+  mkdirSync(unsafe);
+  mkdirSync(outside);
+  symlinkSync(outside, path.join(unsafe, 'share'));
+  assert.throws(
+    () => stageExtensionUpstreamLicenses('pg_hashids', unsafe),
+    /staging parent must be a real directory/u,
+  );
+
+  const realAncestor = path.join(root, 'real-ancestor');
+  const existingStage = path.join(realAncestor, 'existing-stage');
+  mkdirSync(existingStage, { recursive: true });
+  const linkedAncestor = path.join(root, 'linked-ancestor');
+  symlinkSync(realAncestor, linkedAncestor);
+  assert.throws(
+    () => stageExtensionUpstreamLicenses('pg_hashids', path.join(linkedAncestor, 'existing-stage')),
+    /symlink or non-directory ancestor/u,
+  );
+});
+
+test("the public PostGIS carrier's compiled-component legal atoms are pinned, staged, and exact in archives", (t) => {
+  const root = mkdtempSync(path.join(tmpdir(), 'postgis-license-stage-'));
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+  const stage = path.join(root, 'stage');
+  const expected = extensionCarrierLegalContract('oliphaunt-extension-postgis', ['postgis'], {
+    family: 'wasix',
+    target: 'wasix-portable',
+  }).licenseFiles;
+  assert.deepEqual(stageExtensionUpstreamLicenses('postgis', stage), expected);
+  assert.deepEqual(assertExtensionUpstreamLicensesInDirectory(['postgis'], stage), expected);
+
+  const archive = path.join(root, 'postgis.tar.gz');
+  writeFileSync(
+    archive,
+    canonicalGzipSync(
+      createDeterministicTar(stage, 'postgis', {
+        fail(message) {
+          throw new Error(message);
+        },
+      }),
+    ),
+  );
+  assert.deepEqual(
+    assertExtensionUpstreamLicensesInArchive(['postgis'], archive, { prefix: 'postgis' }),
+    expected.map((member) => `postgis/${member}`),
+  );
+});
diff --git a/src/extensions/tools/extension-upstream-licenses.test.sh b/src/extensions/tools/extension-upstream-licenses.test.sh
new file mode 100644
index 000000000..bcc38ed92
--- /dev/null
+++ b/src/extensions/tools/extension-upstream-licenses.test.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../../.."
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+OLIPHAUNT_EXTENSION_SOURCE_CHECKOUT_ROOT="$scratch/missing-checkouts" \
+  bun test --timeout=30000 ./src/extensions/tools/extension-upstream-licenses.test.mts \
+    ./src/extensions/tools/android-extension-legal-catalog.test.mts
diff --git a/src/extensions/tools/native-component-contract.mjs b/src/extensions/tools/native-component-contract.mjs
deleted file mode 100644
index 2c2bfc06c..000000000
--- a/src/extensions/tools/native-component-contract.mjs
+++ /dev/null
@@ -1,408 +0,0 @@
-#!/usr/bin/env bun
-
-import { readFileSync, statSync } from 'node:fs';
-import { fileURLToPath } from 'node:url';
-import path from 'node:path';
-
-import { loadExtensionTargetProfiles } from '../../shared/extension-runtime-contract/extension-target-profiles.mjs';
-
-const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
-export const NATIVE_COMPONENT_CONTRACT_PATH = path.join(
-  ROOT,
-  'src/extensions/catalog/native-components.toml',
-);
-const EXTENSION_CATALOG_PATH = path.join(ROOT, 'src/extensions/catalog/extensions.source.json');
-const ID = /^[a-z][a-z0-9_-]*$/u;
-const ALLOWED_COMPONENT_KEYS = new Set([
-  'id',
-  'source',
-  'source-path',
-  'depends-on',
-  'runtime-files',
-  'link-units',
-]);
-const ALLOWED_LINK_UNIT_KEYS = new Set(['id', 'archive-candidates']);
-const ALLOWED_REQUIREMENT_KEYS = new Set(['extension', 'family', 'kind', 'targets', 'roots']);
-
-function fail(message) {
-  throw new Error(`native component contract: ${message}`);
-}
-
-function object(value, label) {
-  if (value === null || Array.isArray(value) || typeof value !== 'object') {
-    fail(`${label} must be a table`);
-  }
-  return value;
-}
-
-function exactKeys(value, allowed, label) {
-  const unknown = Object.keys(value).filter((key) => !allowed.has(key)).sort();
-  if (unknown.length > 0) {
-    fail(`${label} has unknown fields: ${unknown.join(', ')}`);
-  }
-}
-
-function portableId(value, label) {
-  if (typeof value !== 'string' || !ID.test(value)) {
-    fail(`${label} must match ${ID}`);
-  }
-  return value;
-}
-
-function relativePath(value, label) {
-  if (
-    typeof value !== 'string'
-    || value.length === 0
-    || value.includes('\\')
-    || path.posix.isAbsolute(value)
-    || value.split('/').some((part) => part === '' || part === '.' || part === '..')
-  ) {
-    fail(`${label} must be a canonical repository-relative path`);
-  }
-  return value;
-}
-
-function uniqueList(value, label, itemValidator = portableId) {
-  if (!Array.isArray(value)) {
-    fail(`${label} must be an array`);
-  }
-  const result = value.map((item, index) => itemValidator(item, `${label}[${index}]`));
-  if (new Set(result).size !== result.length) {
-    fail(`${label} must not contain duplicates`);
-  }
-  return result;
-}
-
-function targetProfiles() {
-  try {
-    const rows = loadExtensionTargetProfiles().targets;
-    return new Map(rows.map((row) => [row.target, `${row.family}\0${row.kind}`]));
-  } catch (error) {
-    fail(`cannot read target profiles: ${error.message}`);
-  }
-}
-
-function publicExtensionNames() {
-  let parsed;
-  try {
-    parsed = JSON.parse(readFileSync(EXTENSION_CATALOG_PATH, 'utf8'));
-  } catch (error) {
-    fail(`cannot read canonical extension catalog: ${error.message}`);
-  }
-  object(parsed, 'canonical extension catalog');
-  if (parsed['format-version'] !== 1 || !Array.isArray(parsed.extensions)) {
-    fail('canonical extension catalog must use format-version 1 and define extensions');
-  }
-  const names = new Set();
-  for (const [index, row] of parsed.extensions.entries()) {
-    object(row, `canonical extension catalog extensions[${index}]`);
-    const name = portableId(row['sql-name'], `canonical extension catalog extensions[${index}].sql-name`);
-    if (names.has(name)) fail(`canonical extension catalog repeats ${name}`);
-    names.add(name);
-  }
-  return names;
-}
-
-function normalizeComponent(row, index, linkUnitOwners) {
-  object(row, `components[${index}]`);
-  exactKeys(row, ALLOWED_COMPONENT_KEYS, `components[${index}]`);
-  const id = portableId(row.id, `components[${index}].id`);
-  const source = row.source === undefined ? null : portableId(row.source, `component ${id} source`);
-  const sourcePath = row['source-path'] === undefined
-    ? null
-    : relativePath(row['source-path'], `component ${id} source-path`);
-  if ((source === null) === (sourcePath === null)) {
-    fail(`component ${id} must define exactly one of source or source-path`);
-  }
-  const linkUnits = (row['link-units'] ?? []).map((unit, unitIndex) => {
-    object(unit, `component ${id} link-units[${unitIndex}]`);
-    exactKeys(unit, ALLOWED_LINK_UNIT_KEYS, `component ${id} link-units[${unitIndex}]`);
-    const unitId = portableId(unit.id, `component ${id} link-units[${unitIndex}].id`);
-    const owner = linkUnitOwners.get(unitId);
-    if (owner !== undefined) {
-      fail(`link unit ${unitId} is owned by both ${owner} and ${id}`);
-    }
-    linkUnitOwners.set(unitId, id);
-    return {
-      id: unitId,
-      archiveCandidates: uniqueList(
-        unit['archive-candidates'],
-        `component ${id} link unit ${unitId} archive-candidates`,
-        relativePath,
-      ),
-    };
-  });
-  if (linkUnits.length === 0) {
-    fail(`component ${id} must declare at least one link unit`);
-  }
-  return {
-    id,
-    source,
-    sourcePath,
-    dependsOn: uniqueList(row['depends-on'], `component ${id} depends-on`),
-    runtimeFiles: uniqueList(row['runtime-files'], `component ${id} runtime-files`, relativePath),
-    linkUnits,
-  };
-}
-
-function validateAcyclic(componentsById) {
-  const visiting = new Set();
-  const visited = new Set();
-  const visit = (id, trail) => {
-    if (visiting.has(id)) {
-      fail(`component dependency cycle: ${[...trail, id].join(' -> ')}`);
-    }
-    if (visited.has(id)) return;
-    visiting.add(id);
-    const component = componentsById.get(id);
-    for (const dependency of component.dependsOn) {
-      if (!componentsById.has(dependency)) {
-        fail(`component ${id} depends on unknown component ${dependency}`);
-      }
-      visit(dependency, [...trail, id]);
-    }
-    visiting.delete(id);
-    visited.add(id);
-  };
-  for (const id of componentsById.keys()) visit(id, []);
-}
-
-export function validateNativeComponentContract(raw, options = {}) {
-  object(raw, 'root');
-  const allowedRootKeys = new Set(['schema', 'components', 'requirements']);
-  exactKeys(raw, allowedRootKeys, 'root');
-  if (raw.schema !== 'oliphaunt-native-components-v1') {
-    fail('schema must be oliphaunt-native-components-v1');
-  }
-  if (!Array.isArray(raw.components) || raw.components.length === 0) {
-    fail('components must be a non-empty array');
-  }
-  if (!Array.isArray(raw.requirements)) {
-    fail('requirements must be an array');
-  }
-
-  const linkUnitOwners = new Map();
-  const archiveCandidateOwners = new Map();
-  const components = raw.components.map((row, index) => normalizeComponent(row, index, linkUnitOwners));
-  const componentsById = new Map();
-  for (const component of components) {
-    if (componentsById.has(component.id)) fail(`duplicate component ${component.id}`);
-    componentsById.set(component.id, component);
-    if (component.sourcePath !== null && options.checkSourcePaths !== false) {
-      const absolute = path.join(options.root ?? ROOT, component.sourcePath);
-      try {
-        if (!statSync(absolute).isDirectory()) {
-          fail(`component ${component.id} source-path must be a directory: ${component.sourcePath}`);
-        }
-      } catch (error) {
-        if (error.message.startsWith('native component contract:')) throw error;
-        fail(`component ${component.id} source-path does not exist: ${component.sourcePath}`);
-      }
-    }
-    for (const linkUnit of component.linkUnits) {
-      for (const candidate of linkUnit.archiveCandidates) {
-        const owner = archiveCandidateOwners.get(candidate);
-        if (owner !== undefined) {
-          fail(`archive candidate ${candidate} is owned by both ${owner} and ${linkUnit.id}`);
-        }
-        archiveCandidateOwners.set(candidate, linkUnit.id);
-      }
-    }
-  }
-  validateAcyclic(componentsById);
-
-  const profiles = options.targetProfiles ?? targetProfiles();
-  const knownExtensions = options.knownExtensions ?? publicExtensionNames();
-  const requirementKeys = new Set();
-  const requirements = raw.requirements.map((row, index) => {
-    object(row, `requirements[${index}]`);
-    exactKeys(row, ALLOWED_REQUIREMENT_KEYS, `requirements[${index}]`);
-    const extension = portableId(row.extension, `requirements[${index}].extension`);
-    if (!knownExtensions.has(extension)) {
-      fail(`requirements[${index}] references unknown catalog extension ${extension}`);
-    }
-    const family = portableId(row.family, `requirement ${extension} family`);
-    const kind = portableId(row.kind, `requirement ${extension} kind`);
-    const targets = uniqueList(row.targets, `requirement ${extension} targets`);
-    const roots = uniqueList(row.roots, `requirement ${extension} roots`);
-    if (targets.length === 0 || roots.length === 0) {
-      fail(`requirement ${extension}/${family}/${kind} must declare targets and roots`);
-    }
-    for (const root of roots) {
-      if (!componentsById.has(root)) {
-        fail(`requirement ${extension}/${family}/${kind} references unknown root ${root}`);
-      }
-    }
-    for (const target of targets) {
-      const expectedIdentity = profiles.get(target);
-      if (expectedIdentity === undefined) {
-        fail(`requirement ${extension}/${family}/${kind} uses unknown target ${target}`);
-      }
-      if (expectedIdentity !== `${family}\0${kind}`) {
-        fail(`requirement ${extension}/${family}/${kind} conflicts with target profile ${target}`);
-      }
-      const key = `${extension}\0${family}\0${kind}\0${target}`;
-      if (requirementKeys.has(key)) {
-        fail(`duplicate requirement for ${extension}/${family}/${kind}/${target}`);
-      }
-      requirementKeys.add(key);
-    }
-    return { extension, family, kind, targets, roots };
-  });
-  return {
-    schema: raw.schema,
-    components,
-    requirements,
-    componentsById,
-    linkUnitOwners,
-    targetProfiles: profiles,
-    knownExtensions,
-  };
-}
-
-export function loadNativeComponentContract(file = NATIVE_COMPONENT_CONTRACT_PATH) {
-  let raw;
-  try {
-    raw = Bun.TOML.parse(readFileSync(file, 'utf8'));
-  } catch (error) {
-    fail(`cannot read ${path.relative(ROOT, file)}: ${error.message}`);
-  }
-  return validateNativeComponentContract(raw);
-}
-
-export function resolveNativeComponentClosure(contract, query) {
-  const extension = portableId(query.extension, 'query extension');
-  if (!contract.knownExtensions.has(extension)) fail(`query uses unknown catalog extension ${extension}`);
-  const family = portableId(query.family, 'query family');
-  const kind = portableId(query.kind, 'query kind');
-  const target = portableId(query.target, 'query target');
-  const targetIdentity = contract.targetProfiles.get(target);
-  if (targetIdentity === undefined) fail(`query uses unknown target ${target}`);
-  if (targetIdentity !== `${family}\0${kind}`) {
-    fail(`query ${family}/${kind} conflicts with target profile ${target}`);
-  }
-  const matches = contract.requirements.filter(
-    (row) => row.extension === extension
-      && row.family === family
-      && row.kind === kind
-      && row.targets.includes(target),
-  );
-  if (matches.length > 1) fail(`ambiguous requirement for ${extension}/${family}/${kind}/${target}`);
-  const roots = matches[0]?.roots ?? [];
-  const buildOrder = [];
-  const built = new Set();
-  const addBuild = (id) => {
-    if (built.has(id)) return;
-    const component = contract.componentsById.get(id);
-    for (const dependency of component.dependsOn) addBuild(dependency);
-    built.add(id);
-    buildOrder.push(id);
-  };
-  for (const root of roots) addBuild(root);
-
-  const linkOrder = [];
-  const linkedComponents = new Set();
-  const addLink = (id) => {
-    if (linkedComponents.has(id)) return;
-    linkedComponents.add(id);
-    const component = contract.componentsById.get(id);
-    linkOrder.push(...component.linkUnits.map((unit) => unit.id));
-    for (const dependency of component.dependsOn) addLink(dependency);
-  };
-  for (const root of roots) addLink(root);
-
-  const closure = buildOrder.map((id) => contract.componentsById.get(id));
-  return {
-    extension,
-    family,
-    kind,
-    target,
-    roots: [...roots],
-    components: buildOrder,
-    sources: [...new Set(closure.map((component) => component.source).filter(Boolean))].sort(),
-    sourcePaths: [...new Set(closure.map((component) => component.sourcePath).filter(Boolean))].sort(),
-    linkUnits: linkOrder,
-    runtimeFiles: [...new Set(closure.flatMap((component) => component.runtimeFiles))].sort(),
-  };
-}
-
-export function nativeComponentInventory(contract = loadNativeComponentContract()) {
-  const resolutions = contract.requirements.flatMap((requirement) =>
-    requirement.targets.map((target) => resolveNativeComponentClosure(contract, { ...requirement, target }))
-  );
-  resolutions.sort((left, right) =>
-    left.extension.localeCompare(right.extension)
-      || left.family.localeCompare(right.family)
-      || left.kind.localeCompare(right.kind)
-      || left.target.localeCompare(right.target)
-  );
-  return {
-    schema: contract.schema,
-    components: contract.components.map(({ id, source, sourcePath, dependsOn, runtimeFiles, linkUnits }) => ({
-      id,
-      source,
-      sourcePath,
-      dependsOn,
-      runtimeFiles,
-      linkUnits,
-    })),
-    resolutions,
-  };
-}
-
-function printLines(values) {
-  if (values.length > 0) process.stdout.write(`${values.join('\n')}\n`);
-}
-
-function usage() {
-  fail(
-    'usage: native-component-contract.mjs '
-      + '   |'
-      + 'field     |'
-      + 'archive-candidates >',
-  );
-}
-
-async function main(argv) {
-  const [command, ...args] = argv;
-  const contract = loadNativeComponentContract();
-  if (command === 'check' && args.length === 0) {
-    console.log('native component contract checks passed');
-    return;
-  }
-  if (command === 'inventory' && args.length === 0) {
-    console.log(JSON.stringify(nativeComponentInventory(contract), null, 2));
-    return;
-  }
-  if ((command === 'resolve' || command === 'field') && args.length >= 4) {
-    const closure = resolveNativeComponentClosure(contract, {
-      extension: args[0],
-      family: args[1],
-      kind: args[2],
-      target: args[3],
-    });
-    if (command === 'resolve' && args.length === 4) {
-      console.log(JSON.stringify(closure, null, 2));
-      return;
-    }
-    if (command === 'field' && args.length === 5 && Array.isArray(closure[args[4]])) {
-      printLines(closure[args[4]]);
-      return;
-    }
-  }
-  if (command === 'archive-candidates' && args.length === 1) {
-    const owner = contract.linkUnitOwners.get(args[0]);
-    if (owner === undefined) fail(`unknown link unit ${args[0]}`);
-    const component = contract.componentsById.get(owner);
-    printLines(component.linkUnits.find((unit) => unit.id === args[0]).archiveCandidates);
-    return;
-  }
-  usage();
-}
-
-if (import.meta.main) {
-  main(process.argv.slice(2)).catch((error) => {
-    console.error(error.message);
-    process.exit(2);
-  });
-}
diff --git a/src/extensions/tools/native-component-contract.mts b/src/extensions/tools/native-component-contract.mts
new file mode 100644
index 000000000..ea4272364
--- /dev/null
+++ b/src/extensions/tools/native-component-contract.mts
@@ -0,0 +1,428 @@
+#!/usr/bin/env bun
+
+import { readFileSync, statSync } from 'node:fs';
+import { fileURLToPath } from 'node:url';
+import path from 'node:path';
+
+import { loadExtensionTargetProfiles } from '../contracts/extension-target-profiles.mts';
+
+const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..');
+export const NATIVE_COMPONENT_CONTRACT_PATH = path.join(
+  ROOT,
+  'src/extensions/catalog/native-components.toml',
+);
+const EXTENSION_CATALOG_PATH = path.join(ROOT, 'src/extensions/catalog/extensions.source.json');
+const ID = /^[a-z][a-z0-9_-]*$/u;
+const ALLOWED_COMPONENT_KEYS = new Set([
+  'id',
+  'source',
+  'source-path',
+  'depends-on',
+  'runtime-files',
+  'link-units',
+]);
+const ALLOWED_LINK_UNIT_KEYS = new Set(['id', 'archive-candidates']);
+const ALLOWED_REQUIREMENT_KEYS = new Set(['extension', 'family', 'kind', 'targets', 'roots']);
+
+function fail(message) {
+  throw new Error(`native component contract: ${message}`);
+}
+
+function object(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(`${label} must be a table`);
+  }
+  return value;
+}
+
+function exactKeys(value, allowed, label) {
+  const unknown = Object.keys(value)
+    .filter((key) => !allowed.has(key))
+    .sort();
+  if (unknown.length > 0) {
+    fail(`${label} has unknown fields: ${unknown.join(', ')}`);
+  }
+}
+
+function portableId(value, label) {
+  if (typeof value !== 'string' || !ID.test(value)) {
+    fail(`${label} must match ${ID}`);
+  }
+  return value;
+}
+
+function relativePath(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    path.posix.isAbsolute(value) ||
+    value.split('/').some((part) => part === '' || part === '.' || part === '..')
+  ) {
+    fail(`${label} must be a canonical repository-relative path`);
+  }
+  return value;
+}
+
+function uniqueList(value, label, itemValidator = portableId) {
+  if (!Array.isArray(value)) {
+    fail(`${label} must be an array`);
+  }
+  const result = value.map((item, index) => itemValidator(item, `${label}[${index}]`));
+  if (new Set(result).size !== result.length) {
+    fail(`${label} must not contain duplicates`);
+  }
+  return result;
+}
+
+function targetProfiles() {
+  try {
+    const rows = loadExtensionTargetProfiles().targets;
+    return new Map(rows.map((row) => [row.target, `${row.family}\0${row.kind}`]));
+  } catch (error) {
+    fail(`cannot read target profiles: ${error.message}`);
+  }
+}
+
+function publicExtensionNames() {
+  let parsed;
+  try {
+    parsed = JSON.parse(readFileSync(EXTENSION_CATALOG_PATH, 'utf8'));
+  } catch (error) {
+    fail(`cannot read canonical extension catalog: ${error.message}`);
+  }
+  object(parsed, 'canonical extension catalog');
+  if (parsed['format-version'] !== 1 || !Array.isArray(parsed.extensions)) {
+    fail('canonical extension catalog must use format-version 1 and define extensions');
+  }
+  const names = new Set();
+  for (const [index, row] of parsed.extensions.entries()) {
+    object(row, `canonical extension catalog extensions[${index}]`);
+    const name = portableId(
+      row['sql-name'],
+      `canonical extension catalog extensions[${index}].sql-name`,
+    );
+    if (names.has(name)) fail(`canonical extension catalog repeats ${name}`);
+    names.add(name);
+  }
+  return names;
+}
+
+function normalizeComponent(row, index, linkUnitOwners) {
+  object(row, `components[${index}]`);
+  exactKeys(row, ALLOWED_COMPONENT_KEYS, `components[${index}]`);
+  const id = portableId(row.id, `components[${index}].id`);
+  const source = row.source === undefined ? null : portableId(row.source, `component ${id} source`);
+  const sourcePath =
+    row['source-path'] === undefined
+      ? null
+      : relativePath(row['source-path'], `component ${id} source-path`);
+  if ((source === null) === (sourcePath === null)) {
+    fail(`component ${id} must define exactly one of source or source-path`);
+  }
+  const linkUnits = (row['link-units'] ?? []).map((unit, unitIndex) => {
+    object(unit, `component ${id} link-units[${unitIndex}]`);
+    exactKeys(unit, ALLOWED_LINK_UNIT_KEYS, `component ${id} link-units[${unitIndex}]`);
+    const unitId = portableId(unit.id, `component ${id} link-units[${unitIndex}].id`);
+    const owner = linkUnitOwners.get(unitId);
+    if (owner !== undefined) {
+      fail(`link unit ${unitId} is owned by both ${owner} and ${id}`);
+    }
+    linkUnitOwners.set(unitId, id);
+    return {
+      id: unitId,
+      archiveCandidates: uniqueList(
+        unit['archive-candidates'],
+        `component ${id} link unit ${unitId} archive-candidates`,
+        relativePath,
+      ),
+    };
+  });
+  if (linkUnits.length === 0) {
+    fail(`component ${id} must declare at least one link unit`);
+  }
+  return {
+    id,
+    source,
+    sourcePath,
+    dependsOn: uniqueList(row['depends-on'], `component ${id} depends-on`),
+    runtimeFiles: uniqueList(row['runtime-files'], `component ${id} runtime-files`, relativePath),
+    linkUnits,
+  };
+}
+
+function validateAcyclic(componentsById) {
+  const visiting = new Set();
+  const visited = new Set();
+  const visit = (id, trail) => {
+    if (visiting.has(id)) {
+      fail(`component dependency cycle: ${[...trail, id].join(' -> ')}`);
+    }
+    if (visited.has(id)) return;
+    visiting.add(id);
+    const component = componentsById.get(id);
+    for (const dependency of component.dependsOn) {
+      if (!componentsById.has(dependency)) {
+        fail(`component ${id} depends on unknown component ${dependency}`);
+      }
+      visit(dependency, [...trail, id]);
+    }
+    visiting.delete(id);
+    visited.add(id);
+  };
+  for (const id of componentsById.keys()) visit(id, []);
+}
+
+export function validateNativeComponentContract(raw, options = {}) {
+  object(raw, 'root');
+  const allowedRootKeys = new Set(['schema', 'components', 'requirements']);
+  exactKeys(raw, allowedRootKeys, 'root');
+  if (raw.schema !== 'oliphaunt-native-components-v1') {
+    fail('schema must be oliphaunt-native-components-v1');
+  }
+  if (!Array.isArray(raw.components) || raw.components.length === 0) {
+    fail('components must be a non-empty array');
+  }
+  if (!Array.isArray(raw.requirements)) {
+    fail('requirements must be an array');
+  }
+
+  const linkUnitOwners = new Map();
+  const archiveCandidateOwners = new Map();
+  const components = raw.components.map((row, index) =>
+    normalizeComponent(row, index, linkUnitOwners),
+  );
+  const componentsById = new Map();
+  for (const component of components) {
+    if (componentsById.has(component.id)) fail(`duplicate component ${component.id}`);
+    componentsById.set(component.id, component);
+    if (component.sourcePath !== null && options.checkSourcePaths !== false) {
+      const absolute = path.join(options.root ?? ROOT, component.sourcePath);
+      try {
+        if (!statSync(absolute).isDirectory()) {
+          fail(
+            `component ${component.id} source-path must be a directory: ${component.sourcePath}`,
+          );
+        }
+      } catch (error) {
+        if (error.message.startsWith('native component contract:')) throw error;
+        fail(`component ${component.id} source-path does not exist: ${component.sourcePath}`);
+      }
+    }
+    for (const linkUnit of component.linkUnits) {
+      for (const candidate of linkUnit.archiveCandidates) {
+        const owner = archiveCandidateOwners.get(candidate);
+        if (owner !== undefined) {
+          fail(`archive candidate ${candidate} is owned by both ${owner} and ${linkUnit.id}`);
+        }
+        archiveCandidateOwners.set(candidate, linkUnit.id);
+      }
+    }
+  }
+  validateAcyclic(componentsById);
+
+  const profiles = options.targetProfiles ?? targetProfiles();
+  const knownExtensions = options.knownExtensions ?? publicExtensionNames();
+  const requirementKeys = new Set();
+  const requirements = raw.requirements.map((row, index) => {
+    object(row, `requirements[${index}]`);
+    exactKeys(row, ALLOWED_REQUIREMENT_KEYS, `requirements[${index}]`);
+    const extension = portableId(row.extension, `requirements[${index}].extension`);
+    if (!knownExtensions.has(extension)) {
+      fail(`requirements[${index}] references unknown catalog extension ${extension}`);
+    }
+    const family = portableId(row.family, `requirement ${extension} family`);
+    const kind = portableId(row.kind, `requirement ${extension} kind`);
+    const targets = uniqueList(row.targets, `requirement ${extension} targets`);
+    const roots = uniqueList(row.roots, `requirement ${extension} roots`);
+    if (targets.length === 0 || roots.length === 0) {
+      fail(`requirement ${extension}/${family}/${kind} must declare targets and roots`);
+    }
+    for (const root of roots) {
+      if (!componentsById.has(root)) {
+        fail(`requirement ${extension}/${family}/${kind} references unknown root ${root}`);
+      }
+    }
+    for (const target of targets) {
+      const expectedIdentity = profiles.get(target);
+      if (expectedIdentity === undefined) {
+        fail(`requirement ${extension}/${family}/${kind} uses unknown target ${target}`);
+      }
+      if (expectedIdentity !== `${family}\0${kind}`) {
+        fail(`requirement ${extension}/${family}/${kind} conflicts with target profile ${target}`);
+      }
+      const key = `${extension}\0${family}\0${kind}\0${target}`;
+      if (requirementKeys.has(key)) {
+        fail(`duplicate requirement for ${extension}/${family}/${kind}/${target}`);
+      }
+      requirementKeys.add(key);
+    }
+    return { extension, family, kind, targets, roots };
+  });
+  return {
+    schema: raw.schema,
+    components,
+    requirements,
+    componentsById,
+    linkUnitOwners,
+    targetProfiles: profiles,
+    knownExtensions,
+  };
+}
+
+export function loadNativeComponentContract(file = NATIVE_COMPONENT_CONTRACT_PATH) {
+  let raw;
+  try {
+    raw = Bun.TOML.parse(readFileSync(file, 'utf8'));
+  } catch (error) {
+    fail(`cannot read ${path.relative(ROOT, file)}: ${error.message}`);
+  }
+  return validateNativeComponentContract(raw);
+}
+
+export function resolveNativeComponentClosure(contract, query) {
+  const extension = portableId(query.extension, 'query extension');
+  if (!contract.knownExtensions.has(extension))
+    fail(`query uses unknown catalog extension ${extension}`);
+  const family = portableId(query.family, 'query family');
+  const kind = portableId(query.kind, 'query kind');
+  const target = portableId(query.target, 'query target');
+  const targetIdentity = contract.targetProfiles.get(target);
+  if (targetIdentity === undefined) fail(`query uses unknown target ${target}`);
+  if (targetIdentity !== `${family}\0${kind}`) {
+    fail(`query ${family}/${kind} conflicts with target profile ${target}`);
+  }
+  const matches = contract.requirements.filter(
+    (row) =>
+      row.extension === extension &&
+      row.family === family &&
+      row.kind === kind &&
+      row.targets.includes(target),
+  );
+  if (matches.length > 1)
+    fail(`ambiguous requirement for ${extension}/${family}/${kind}/${target}`);
+  const roots = matches[0]?.roots ?? [];
+  const buildOrder = [];
+  const built = new Set();
+  const addBuild = (id) => {
+    if (built.has(id)) return;
+    const component = contract.componentsById.get(id);
+    for (const dependency of component.dependsOn) addBuild(dependency);
+    built.add(id);
+    buildOrder.push(id);
+  };
+  for (const root of roots) addBuild(root);
+
+  const linkOrder = [];
+  const linkedComponents = new Set();
+  const addLink = (id) => {
+    if (linkedComponents.has(id)) return;
+    linkedComponents.add(id);
+    const component = contract.componentsById.get(id);
+    linkOrder.push(...component.linkUnits.map((unit) => unit.id));
+    for (const dependency of component.dependsOn) addLink(dependency);
+  };
+  for (const root of roots) addLink(root);
+
+  const closure = buildOrder.map((id) => contract.componentsById.get(id));
+  return {
+    extension,
+    family,
+    kind,
+    target,
+    roots: [...roots],
+    components: buildOrder,
+    sources: [...new Set(closure.map((component) => component.source).filter(Boolean))].sort(),
+    sourcePaths: [
+      ...new Set(closure.map((component) => component.sourcePath).filter(Boolean)),
+    ].sort(),
+    linkUnits: linkOrder,
+    runtimeFiles: [...new Set(closure.flatMap((component) => component.runtimeFiles))].sort(),
+  };
+}
+
+export function nativeComponentInventory(contract = loadNativeComponentContract()) {
+  const resolutions = contract.requirements.flatMap((requirement) =>
+    requirement.targets.map((target) =>
+      resolveNativeComponentClosure(contract, { ...requirement, target }),
+    ),
+  );
+  resolutions.sort(
+    (left, right) =>
+      left.extension.localeCompare(right.extension) ||
+      left.family.localeCompare(right.family) ||
+      left.kind.localeCompare(right.kind) ||
+      left.target.localeCompare(right.target),
+  );
+  return {
+    schema: contract.schema,
+    components: contract.components.map(
+      ({ id, source, sourcePath, dependsOn, runtimeFiles, linkUnits }) => ({
+        id,
+        source,
+        sourcePath,
+        dependsOn,
+        runtimeFiles,
+        linkUnits,
+      }),
+    ),
+    resolutions,
+  };
+}
+
+function printLines(values) {
+  if (values.length > 0) process.stdout.write(`${values.join('\n')}\n`);
+}
+
+function usage() {
+  fail(
+    'usage: native-component-contract.mts ' +
+      '   |' +
+      'field     |' +
+      'archive-candidates >',
+  );
+}
+
+async function main(argv) {
+  const [command, ...args] = argv;
+  const contract = loadNativeComponentContract();
+  if (command === 'check' && args.length === 0) {
+    console.log('native component contract checks passed');
+    return;
+  }
+  if (command === 'inventory' && args.length === 0) {
+    console.log(JSON.stringify(nativeComponentInventory(contract), null, 2));
+    return;
+  }
+  if ((command === 'resolve' || command === 'field') && args.length >= 4) {
+    const closure = resolveNativeComponentClosure(contract, {
+      extension: args[0],
+      family: args[1],
+      kind: args[2],
+      target: args[3],
+    });
+    if (command === 'resolve' && args.length === 4) {
+      console.log(JSON.stringify(closure, null, 2));
+      return;
+    }
+    if (command === 'field' && args.length === 5 && Array.isArray(closure[args[4]])) {
+      printLines(closure[args[4]]);
+      return;
+    }
+  }
+  if (command === 'archive-candidates' && args.length === 1) {
+    const owner = contract.linkUnitOwners.get(args[0]);
+    if (owner === undefined) fail(`unknown link unit ${args[0]}`);
+    const component = contract.componentsById.get(owner);
+    printLines(component.linkUnits.find((unit) => unit.id === args[0]).archiveCandidates);
+    return;
+  }
+  usage();
+}
+
+if (import.meta.main) {
+  main(process.argv.slice(2)).catch((error) => {
+    console.error(error.message);
+    process.exit(2);
+  });
+}
diff --git a/src/extensions/tools/native-component-contract.test.mjs b/src/extensions/tools/native-component-contract.test.mjs
deleted file mode 100644
index c7798aef2..000000000
--- a/src/extensions/tools/native-component-contract.test.mjs
+++ /dev/null
@@ -1,144 +0,0 @@
-import assert from 'node:assert/strict';
-import test from 'node:test';
-
-import {
-  loadNativeComponentContract,
-  resolveNativeComponentClosure,
-  validateNativeComponentContract,
-} from './native-component-contract.mjs';
-
-const contract = loadNativeComponentContract();
-
-function resolve(extension, family, kind, target) {
-  return resolveNativeComponentClosure(contract, { extension, family, kind, target });
-}
-
-test('PROJ brings SQLite and its runtime database into every PostGIS closure', () => {
-  const ios = resolve('postgis', 'native', 'native-static-registry', 'ios-xcframework');
-  assert.deepEqual(ios.components, ['geos', 'sqlite', 'proj', 'libxml2', 'json-c']);
-  assert.deepEqual(ios.runtimeFiles, ['proj/proj.db']);
-  assert.deepEqual(ios.linkUnits, ['geos-c', 'geos', 'proj', 'sqlite', 'libxml2', 'json-c']);
-});
-
-test('PostGIS target differences are explicit', () => {
-  const ios = resolve('postgis', 'native', 'native-static-registry', 'ios-xcframework');
-  const android = resolve('postgis', 'native', 'native-static-registry', 'android-arm64-v8a');
-  const wasix = resolve('postgis', 'wasix', 'wasix-runtime', 'wasix-portable');
-  assert.equal(ios.components.includes('libiconv'), false);
-  assert.deepEqual(android.components.slice(-1), ['libiconv']);
-  assert.deepEqual(wasix.components, android.components);
-  assert.deepEqual(android.linkUnits.slice(-2), ['libiconv', 'libcharset']);
-});
-
-test('contrib native dependencies share the same cross-platform contract', () => {
-  assert.deepEqual(
-    resolve('pgcrypto', 'native', 'native-static-registry', 'android-x86_64').components,
-    ['openssl'],
-  );
-  assert.deepEqual(
-    resolve('uuid-ossp', 'wasix', 'wasix-runtime', 'wasix-portable').linkUnits,
-    ['uuid'],
-  );
-});
-
-test('extensions without native components resolve to an empty closure', () => {
-  assert.deepEqual(
-    resolve('pgtap', 'wasix', 'wasix-runtime', 'wasix-portable').components,
-    [],
-  );
-});
-
-test('queries must use a real target with its declared family and kind', () => {
-  assert.throws(
-    () => resolve('pgtapp', 'wasix', 'wasix-runtime', 'wasix-portable'),
-    /query uses unknown catalog extension/u,
-  );
-  assert.throws(
-    () => resolve('postgis', 'native', 'native-dynamic', 'linux-x65-gnu'),
-    /query uses unknown target/u,
-  );
-  assert.throws(
-    () => resolve('postgis', 'wasix', 'wasix-runtime', 'linux-x64-gnu'),
-    /conflicts with target profile/u,
-  );
-});
-
-function fixture(overrides = {}) {
-  return {
-    schema: 'oliphaunt-native-components-v1',
-    components: [
-      {
-        id: 'alpha',
-        source: 'alpha',
-        'depends-on': [],
-        'runtime-files': [],
-        'link-units': [{ id: 'alpha', 'archive-candidates': ['alpha/lib/libalpha.a'] }],
-      },
-    ],
-    requirements: [
-      {
-        extension: 'demo',
-        family: 'native',
-        kind: 'native-dynamic',
-        targets: ['demo-target'],
-        roots: ['alpha'],
-      },
-    ],
-    ...overrides,
-  };
-}
-
-const fixtureOptions = {
-  checkSourcePaths: false,
-  knownExtensions: new Set(['demo']),
-  targetProfiles: new Map([['demo-target', 'native\0native-dynamic']]),
-};
-
-test('cycles fail closed', () => {
-  const raw = fixture();
-  raw.components.push({
-    id: 'beta',
-    source: 'beta',
-    'depends-on': ['alpha'],
-    'runtime-files': [],
-    'link-units': [{ id: 'beta', 'archive-candidates': ['beta/lib/libbeta.a'] }],
-  });
-  raw.components[0]['depends-on'] = ['beta'];
-  assert.throws(
-    () => validateNativeComponentContract(raw, fixtureOptions),
-    /component dependency cycle/u,
-  );
-});
-
-test('overlapping target requirements fail closed', () => {
-  const raw = fixture();
-  raw.requirements.push({ ...raw.requirements[0] });
-  assert.throws(
-    () => validateNativeComponentContract(raw, fixtureOptions),
-    /duplicate requirement/u,
-  );
-});
-
-test('typos in schema fields fail closed', () => {
-  const raw = fixture();
-  raw.components[0].dependz = [];
-  assert.throws(
-    () => validateNativeComponentContract(raw, fixtureOptions),
-    /unknown fields: dependz/u,
-  );
-});
-
-test('archive candidates have one canonical link-unit owner', () => {
-  const raw = fixture();
-  raw.components.push({
-    id: 'beta',
-    source: 'beta',
-    'depends-on': [],
-    'runtime-files': [],
-    'link-units': [{ id: 'beta', 'archive-candidates': ['alpha/lib/libalpha.a'] }],
-  });
-  assert.throws(
-    () => validateNativeComponentContract(raw, fixtureOptions),
-    /archive candidate .* is owned by both/u,
-  );
-});
diff --git a/src/extensions/tools/native-component-contract.test.mts b/src/extensions/tools/native-component-contract.test.mts
new file mode 100644
index 000000000..4fd4beda5
--- /dev/null
+++ b/src/extensions/tools/native-component-contract.test.mts
@@ -0,0 +1,140 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+
+import {
+  loadNativeComponentContract,
+  resolveNativeComponentClosure,
+  validateNativeComponentContract,
+} from './native-component-contract.mts';
+
+const contract = loadNativeComponentContract();
+
+function resolve(extension, family, kind, target) {
+  return resolveNativeComponentClosure(contract, { extension, family, kind, target });
+}
+
+test('PROJ brings SQLite and its runtime database into every PostGIS closure', () => {
+  const ios = resolve('postgis', 'native', 'native-static-registry', 'ios-xcframework');
+  assert.deepEqual(ios.components, ['geos', 'sqlite', 'proj', 'libxml2', 'json-c']);
+  assert.deepEqual(ios.runtimeFiles, ['proj/proj.db']);
+  assert.deepEqual(ios.linkUnits, ['geos-c', 'geos', 'proj', 'sqlite', 'libxml2', 'json-c']);
+});
+
+test('PostGIS target differences are explicit', () => {
+  const ios = resolve('postgis', 'native', 'native-static-registry', 'ios-xcframework');
+  const android = resolve('postgis', 'native', 'native-static-registry', 'android-arm64-v8a');
+  const wasix = resolve('postgis', 'wasix', 'wasix-runtime', 'wasix-portable');
+  assert.equal(ios.components.includes('libiconv'), false);
+  assert.deepEqual(android.components.slice(-1), ['libiconv']);
+  assert.deepEqual(wasix.components, android.components);
+  assert.deepEqual(android.linkUnits.slice(-2), ['libiconv', 'libcharset']);
+});
+
+test('contrib native dependencies share the same cross-platform contract', () => {
+  assert.deepEqual(
+    resolve('pgcrypto', 'native', 'native-static-registry', 'android-x86_64').components,
+    ['openssl'],
+  );
+  assert.deepEqual(resolve('uuid-ossp', 'wasix', 'wasix-runtime', 'wasix-portable').linkUnits, [
+    'uuid',
+  ]);
+});
+
+test('extensions without native components resolve to an empty closure', () => {
+  assert.deepEqual(resolve('pgtap', 'wasix', 'wasix-runtime', 'wasix-portable').components, []);
+});
+
+test('queries must use a real target with its declared family and kind', () => {
+  assert.throws(
+    () => resolve('pgtapp', 'wasix', 'wasix-runtime', 'wasix-portable'),
+    /query uses unknown catalog extension/u,
+  );
+  assert.throws(
+    () => resolve('postgis', 'native', 'native-dynamic', 'linux-x65-gnu'),
+    /query uses unknown target/u,
+  );
+  assert.throws(
+    () => resolve('postgis', 'wasix', 'wasix-runtime', 'linux-x64-gnu'),
+    /conflicts with target profile/u,
+  );
+});
+
+function fixture(overrides = {}) {
+  return {
+    schema: 'oliphaunt-native-components-v1',
+    components: [
+      {
+        id: 'alpha',
+        source: 'alpha',
+        'depends-on': [],
+        'runtime-files': [],
+        'link-units': [{ id: 'alpha', 'archive-candidates': ['alpha/lib/libalpha.a'] }],
+      },
+    ],
+    requirements: [
+      {
+        extension: 'demo',
+        family: 'native',
+        kind: 'native-dynamic',
+        targets: ['demo-target'],
+        roots: ['alpha'],
+      },
+    ],
+    ...overrides,
+  };
+}
+
+const fixtureOptions = {
+  checkSourcePaths: false,
+  knownExtensions: new Set(['demo']),
+  targetProfiles: new Map([['demo-target', 'native\0native-dynamic']]),
+};
+
+test('cycles fail closed', () => {
+  const raw = fixture();
+  raw.components.push({
+    id: 'beta',
+    source: 'beta',
+    'depends-on': ['alpha'],
+    'runtime-files': [],
+    'link-units': [{ id: 'beta', 'archive-candidates': ['beta/lib/libbeta.a'] }],
+  });
+  raw.components[0]['depends-on'] = ['beta'];
+  assert.throws(
+    () => validateNativeComponentContract(raw, fixtureOptions),
+    /component dependency cycle/u,
+  );
+});
+
+test('overlapping target requirements fail closed', () => {
+  const raw = fixture();
+  raw.requirements.push({ ...raw.requirements[0] });
+  assert.throws(
+    () => validateNativeComponentContract(raw, fixtureOptions),
+    /duplicate requirement/u,
+  );
+});
+
+test('typos in schema fields fail closed', () => {
+  const raw = fixture();
+  raw.components[0].dependz = [];
+  assert.throws(
+    () => validateNativeComponentContract(raw, fixtureOptions),
+    /unknown fields: dependz/u,
+  );
+});
+
+test('archive candidates have one canonical link-unit owner', () => {
+  const raw = fixture();
+  raw.components.push({
+    id: 'beta',
+    source: 'beta',
+    'depends-on': [],
+    'runtime-files': [],
+    'link-units': [{ id: 'beta', 'archive-candidates': ['alpha/lib/libalpha.a'] }],
+  });
+  assert.throws(
+    () => validateNativeComponentContract(raw, fixtureOptions),
+    /archive candidate .* is owned by both/u,
+  );
+});
diff --git a/src/extensions/tools/native-extension-files.mts b/src/extensions/tools/native-extension-files.mts
new file mode 100644
index 000000000..71082797d
--- /dev/null
+++ b/src/extensions/tools/native-extension-files.mts
@@ -0,0 +1,25 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { readFileSync } from 'node:fs';
+
+// Shell builders need only the installed file identities, not a compiled SDK.
+const { extensions } = JSON.parse(
+  readFileSync(new URL('../generated/sdk/extensions.json', import.meta.url), 'utf8'),
+);
+const rows = extensions.map((extension) => {
+  const name = extension['sql-name'];
+  const stem = extension['native-module-stem'];
+  const data = extension['runtime-share-data-files'];
+  assert(typeof name === 'string' && /^[a-z0-9_-]+$/.test(name));
+  assert(stem === null || (typeof stem === 'string' && /^[a-z0-9_-]+$/.test(stem)));
+  assert(Array.isArray(data));
+  for (const member of data)
+    assert(
+      typeof member === 'string' &&
+        member
+          .split('/')
+          .every((part) => /^[a-zA-Z0-9_.-]+$/.test(part) && part !== '.' && part !== '..'),
+    );
+  return [name, stem ?? '-', data.join(',') || '-'].join('\t');
+});
+console.log(['sql_name\tnative_module_stem\tdata_files', ...rows].join('\n'));
diff --git a/src/pgwire-server/CHANGELOG.md b/src/pgwire-server/CHANGELOG.md
new file mode 100644
index 000000000..1350f4c4c
--- /dev/null
+++ b/src/pgwire-server/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## Unreleased
+
+Extract the existing WASIX socket server and command-line interface into its own product.
diff --git a/src/pgwire-server/Cargo.toml b/src/pgwire-server/Cargo.toml
new file mode 100644
index 000000000..57eb4ad4c
--- /dev/null
+++ b/src/pgwire-server/Cargo.toml
@@ -0,0 +1,76 @@
+[package]
+name = "oliphaunt-pgwire-server"
+version = "0.1.0"
+edition = "2024"
+rust-version = "1.93"
+license = "MIT"
+repository.workspace = true
+homepage.workspace = true
+description = "PostgreSQL socket server and CLI for embedded Oliphaunt databases."
+readme = "README.md"
+exclude = ["moon.yml", "release.toml", "tools"]
+
+[features]
+default = ["wasix"]
+wasix = ["dep:oliphaunt-wasix", "dep:tokio", "dep:tracing", "dep:tempfile"]
+extensions = ["wasix", "oliphaunt-wasix/extensions"]
+icu = ["wasix", "oliphaunt-wasix/icu"]
+
+extension-amcheck = ["extensions", "oliphaunt-wasix/extension-amcheck"]
+extension-auto-explain = ["extensions", "oliphaunt-wasix/extension-auto-explain"]
+extension-bloom = ["extensions", "oliphaunt-wasix/extension-bloom"]
+extension-btree-gin = ["extensions", "oliphaunt-wasix/extension-btree-gin"]
+extension-btree-gist = ["extensions", "oliphaunt-wasix/extension-btree-gist"]
+extension-citext = ["extensions", "oliphaunt-wasix/extension-citext"]
+extension-cube = ["extensions", "oliphaunt-wasix/extension-cube"]
+extension-dict-int = ["extensions", "oliphaunt-wasix/extension-dict-int"]
+extension-dict-xsyn = ["extensions", "oliphaunt-wasix/extension-dict-xsyn"]
+extension-earthdistance = ["extensions", "oliphaunt-wasix/extension-earthdistance"]
+extension-file-fdw = ["extensions", "oliphaunt-wasix/extension-file-fdw"]
+extension-fuzzystrmatch = ["extensions", "oliphaunt-wasix/extension-fuzzystrmatch"]
+extension-hstore = ["extensions", "oliphaunt-wasix/extension-hstore"]
+extension-intarray = ["extensions", "oliphaunt-wasix/extension-intarray"]
+extension-isn = ["extensions", "oliphaunt-wasix/extension-isn"]
+extension-lo = ["extensions", "oliphaunt-wasix/extension-lo"]
+extension-ltree = ["extensions", "oliphaunt-wasix/extension-ltree"]
+extension-pageinspect = ["extensions", "oliphaunt-wasix/extension-pageinspect"]
+extension-pg-buffercache = ["extensions", "oliphaunt-wasix/extension-pg-buffercache"]
+extension-pg-freespacemap = ["extensions", "oliphaunt-wasix/extension-pg-freespacemap"]
+extension-pg-hashids = ["extensions", "oliphaunt-wasix/extension-pg-hashids"]
+extension-pg-ivm = ["extensions", "oliphaunt-wasix/extension-pg-ivm"]
+extension-pg-surgery = ["extensions", "oliphaunt-wasix/extension-pg-surgery"]
+extension-pg-textsearch = ["extensions", "oliphaunt-wasix/extension-pg-textsearch"]
+extension-pg-trgm = ["extensions", "oliphaunt-wasix/extension-pg-trgm"]
+extension-pg-uuidv7 = ["extensions", "oliphaunt-wasix/extension-pg-uuidv7"]
+extension-pg-visibility = ["extensions", "oliphaunt-wasix/extension-pg-visibility"]
+extension-pg-walinspect = ["extensions", "oliphaunt-wasix/extension-pg-walinspect"]
+extension-pgcrypto = ["extensions", "oliphaunt-wasix/extension-pgcrypto"]
+extension-pgtap = ["extensions", "oliphaunt-wasix/extension-pgtap"]
+extension-postgis = ["extensions", "oliphaunt-wasix/extension-postgis"]
+extension-seg = ["extensions", "oliphaunt-wasix/extension-seg"]
+extension-tablefunc = ["extensions", "oliphaunt-wasix/extension-tablefunc"]
+extension-tcn = ["extensions", "oliphaunt-wasix/extension-tcn"]
+extension-tsm-system-rows = ["extensions", "oliphaunt-wasix/extension-tsm-system-rows"]
+extension-tsm-system-time = ["extensions", "oliphaunt-wasix/extension-tsm-system-time"]
+extension-unaccent = ["extensions", "oliphaunt-wasix/extension-unaccent"]
+extension-uuid-ossp = ["extensions", "oliphaunt-wasix/extension-uuid-ossp"]
+extension-vector = ["extensions", "oliphaunt-wasix/extension-vector"]
+
+[dependencies]
+anyhow = "1"
+oliphaunt-query = { path = "../sdks/rust-query", version = "0.1.0" }
+oliphaunt-wasix = { path = "../sdks/rust-wasix", version = "0.2.0", optional = true }
+tempfile = { version = "3", optional = true }
+tokio = { version = "1", features = ["sync"], optional = true }
+tracing = { version = "0.1", optional = true }
+
+[dev-dependencies]
+serde_json = "1"
+sqlx = { version = "0.8", default-features = false, features = ["postgres", "runtime-tokio"] }
+tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }
+tokio-postgres = "0.7"
+
+[[bin]]
+name = "oliphaunt-pgwire-server"
+path = "src/main.rs"
+required-features = ["wasix"]
diff --git a/src/pgwire-server/LICENSE b/src/pgwire-server/LICENSE
new file mode 100644
index 000000000..ac7484ea4
--- /dev/null
+++ b/src/pgwire-server/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 oliphaunt-wasix Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/pgwire-server/README.md b/src/pgwire-server/README.md
new file mode 100644
index 000000000..6434f9c7f
--- /dev/null
+++ b/src/pgwire-server/README.md
@@ -0,0 +1,47 @@
+# Oliphaunt PostgreSQL wire server
+
+This library and CLI expose the embedded WASIX database through a PostgreSQL socket. Connect with an ordinary PostgreSQL driver. The adapter serves one client at a time; configure connection pools with one connection.
+
+The default `wasix` feature includes the WASIX adapter. Build without default features to use the runtime-independent PostgreSQL connection framing without Wasmer.
+
+From this directory, `cargo build` builds the library and CLI plus its Rust
+dependencies. `cargo test` runs source tests; runtime tests are explicitly ignored
+until their assets are prepared. `cargo fmt --check` checks formatting and
+`cargo clippy --all-targets -- -D warnings` lints the owner.
+
+From the checkout root, `moon run oliphaunt-pgwire-server:test-integration`
+prepares the runtime and runs the socket, driver, CLI and release-of-ownership
+tests. `test-aot` exercises the host's AOT runtime with a real extension.
+`package` creates the publishable Cargo archive, while `test-consumer` compiles
+the extracted archive with the actual packaged SDK and query dependencies.
+
+Install the CLI locally with `cargo install --path . --locked`, then run
+`oliphaunt-pgwire-server --memory --print-uri`. It prints a PostgreSQL connection
+URL and runs until the process is stopped. Use `--help` for persistent storage and
+listener options.
+
+The endpoint uses loopback TCP on every supported host; Unix hosts may instead
+select a Unix-domain socket. It uses PostgreSQL trust authentication, refuses
+TLS and GSS negotiation, and owns one connected client at a time. Its current
+`CancelRequest` path does not authenticate or interrupt the guest backend, so
+client cancellation is unsupported. Treat the example below as the covered
+SQLx connection shape, not proof of pool, COPY, cancellation, or
+arbitrary-driver conformance.
+
+```rust,no_run
+use oliphaunt_pgwire_server::OliphauntServer;
+use sqlx::{Connection, Row};
+
+#[tokio::main]
+async fn main() -> anyhow::Result<()> {
+    let mut server = OliphauntServer::builder().start()?;
+    let mut connection = sqlx::PgConnection::connect(&server.connection_string()).await?;
+    let row = sqlx::query("SELECT 42::int AS answer")
+        .fetch_one(&mut connection)
+        .await?;
+    assert_eq!(row.try_get::("answer")?, 42);
+    connection.close().await?;
+    server.close()?;
+    Ok(())
+}
+```
diff --git a/src/pgwire-server/moon.yml b/src/pgwire-server/moon.yml
new file mode 100644
index 000000000..26a7b2682
--- /dev/null
+++ b/src/pgwire-server/moon.yml
@@ -0,0 +1,82 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+id: "oliphaunt-pgwire-server"
+language: "rust"
+layer: "library"
+stack: "systems"
+tags: ["cargo-package", "rust", "wasix", "release-product"]
+dependsOn: ["oliphaunt-wasix-rust", "oliphaunt-query"]
+project:
+  title: "PostgreSQL socket server"
+  description: "Sequential PostgreSQL socket server and CLI over the WASIX SDK."
+  owner: "oliphaunt"
+  release:
+    component: "oliphaunt-pgwire-server"
+    packagePath: "src/pgwire-server"
+fileGroups:
+  sources: ["src/**/*", "tests/**/*", "Cargo.toml"]
+tasks:
+  format:
+    command: "cargo fmt"
+    options:
+      cache: false
+      runInCI: false
+  format-check:
+    command: "cargo fmt --check"
+    tags: ["quality", "static", "format", "requires-rust"]
+    inputs: ["@group(sources)"]
+  lint:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    command: "cargo clippy --all-targets --locked -- -D warnings"
+    tags: ["quality", "static", "requires-rust"]
+    inputs: ["@group(sources)", "/Cargo.toml", "/Cargo.lock"]
+  build:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    command: "cargo build --locked"
+    tags: ["build", "requires-rust"]
+    inputs: ["@group(sources)", "/Cargo.toml", "/Cargo.lock"]
+    outputs: ["/target/debug/oliphaunt-pgwire-server*", "/target/debug/liboliphaunt_pgwire_server.rlib"]
+  test:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    command: "cargo test --locked"
+    tags: ["quality", "unit", "requires-rust"]
+    inputs: ["@group(sources)", "/Cargo.toml", "/Cargo.lock"]
+  test-integration:
+    command: "cargo test --locked -- --ignored --test-threads=1"
+    tags: ["runtime", "integration", "requires-rust", "ci-liboliphaunt-wasix-aot"]
+    deps: [{target: "cargo-sources", cacheStrategy: hash}, "liboliphaunt-wasix:runtime-aot"]
+    inputs: ["@group(sources)", "/Cargo.toml", "/Cargo.lock", "/src/extensions/catalog/extensions.source.json", "/src/test-fixtures/extensions/**/*"]
+    options:
+      cache: false
+  test-aot:
+    command: "bash src/pgwire-server/tools/test-aot.sh"
+    tags: ["runtime", "integration", "requires-rust", "ci-liboliphaunt-wasix-aot"]
+    deps: [{target: "cargo-sources", cacheStrategy: hash}, "liboliphaunt-wasix:runtime-aot", "extension-artifacts-wasix:build-aot"]
+    inputs: ["@group(sources)", "tools/test-aot.sh", "/Cargo.toml", "/Cargo.lock"]
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  package:
+    command: "bash src/pgwire-server/tools/package.sh"
+    tags: ["release", "artifact-package", "ci-wasix-rust-package"]
+    inputs: ["**/*", "@group(legal-files)", "/Cargo.toml", "/Cargo.lock", "/tools/packaging/*.{mts,sh}"]
+    outputs: ["/target/sdk-artifacts/oliphaunt-pgwire-server/**/*"]
+    options:
+      runFromWorkspaceRoot: true
+  test-consumer:
+    tags: ["release", "consumer", "ci-wasix-rust-package"]
+    deps: ["oliphaunt-pgwire-server:package", "oliphaunt-wasix-rust:package", "oliphaunt-query:package"]
+    script: |
+      set -eu
+      version="$(bun tools/release/product-version.mts version oliphaunt-pgwire-server)"
+      sdk_version="$(bun tools/release/product-version.mts version oliphaunt-wasix-rust)"
+      query_version="$(bun tools/release/product-version.mts version oliphaunt-query)"
+      bash tools/packaging/check-cargo-package-tests.sh --crate "target/sdk-artifacts/oliphaunt-pgwire-server/oliphaunt-pgwire-server-$version.crate" --dependency-crate "target/sdk-artifacts/oliphaunt-wasix-rust/oliphaunt-wasix-$sdk_version.crate" --dependency-crate "target/sdk-artifacts/oliphaunt-query/oliphaunt-query-$query_version.crate" --path-dependencies-from src/sdks/rust-wasix/Cargo.toml
+    inputs: ["@group(sources)", "/Cargo.toml", "/Cargo.lock", "/tools/packaging/*.{mts,sh}"]
+    options:
+      runFromWorkspaceRoot: true
diff --git a/src/pgwire-server/release.toml b/src/pgwire-server/release.toml
new file mode 100644
index 000000000..ab6fcfc15
--- /dev/null
+++ b/src/pgwire-server/release.toml
@@ -0,0 +1,16 @@
+id = "oliphaunt-pgwire-server"
+owner = "@oliphaunt/core"
+kind = "sdk"
+publish_targets = ["crates-io"]
+registry_packages = ["crates:oliphaunt-pgwire-server"]
+release_artifacts = ["cargo-crate"]
+
+[compatibility_versions.pgwire_server_query]
+source_product = "oliphaunt-query"
+path = "src/pgwire-server/Cargo.toml"
+parser = "toml:dependencies.oliphaunt-query.version"
+
+[compatibility_versions.pgwire_server_wasix]
+source_product = "oliphaunt-wasix-rust"
+path = "src/pgwire-server/Cargo.toml"
+parser = "toml:dependencies.oliphaunt-wasix.version"
diff --git a/src/pgwire-server/src/async_server.rs b/src/pgwire-server/src/async_server.rs
new file mode 100644
index 000000000..06ac79832
--- /dev/null
+++ b/src/pgwire-server/src/async_server.rs
@@ -0,0 +1,371 @@
+use std::sync::{Arc, Mutex, mpsc};
+use std::thread;
+
+use tokio::sync::oneshot;
+
+use crate::{Error, ErrorKind, OliphauntServer, OliphauntServerBuilder, Result};
+
+type Completion = Box) + Send>;
+enum State {
+    Open,
+    Closing(Vec),
+    Closed(Result<()>),
+}
+enum Control {
+    Close,
+}
+struct OwnerStopped(Arc>);
+impl Drop for OwnerStopped {
+    fn drop(&mut self) {
+        complete(&self.0, Err(stopped()));
+    }
+}
+struct Owner {
+    sender: mpsc::Sender,
+    state: Arc>,
+}
+impl Drop for Owner {
+    fn drop(&mut self) {
+        let _ = self.sender.send(Control::Close);
+    }
+}
+
+/// Cloneable, asynchronous owner of a sequential PostgreSQL socket server.
+#[derive(Clone)]
+pub struct AsyncOliphauntServer {
+    owner: Arc,
+    connection_string: Arc,
+}
+
+impl AsyncOliphauntServer {
+    pub fn builder() -> AsyncOliphauntServerBuilder {
+        AsyncOliphauntServerBuilder::new()
+    }
+    pub fn connection_string(&self) -> &str {
+        &self.connection_string
+    }
+    pub fn is_closed(&self) -> bool {
+        matches!(
+            *self
+                .owner
+                .state
+                .lock()
+                .unwrap_or_else(|error| error.into_inner()),
+            State::Closed(_)
+        )
+    }
+    /// Join the one terminal shutdown attempt. Dropping this future does not
+    /// cancel accepted teardown; later calls observe the same result.
+    pub async fn close(&self) -> Result<()> {
+        let (reply, receiver) = oneshot::channel();
+        self.close_with_completion(move |result| {
+            let _ = reply.send(result);
+        });
+        receiver.await.map_err(|_| stopped())?
+    }
+    pub fn close_with_completion(&self, completion: impl FnOnce(Result<()>) + Send + 'static) {
+        let mut completion: Option = Some(Box::new(completion));
+        let mut start = false;
+        let settled = {
+            let mut state = self
+                .owner
+                .state
+                .lock()
+                .unwrap_or_else(|error| error.into_inner());
+            match &mut *state {
+                State::Open => {
+                    *state = State::Closing(vec![completion.take().unwrap()]);
+                    start = true;
+                    None
+                }
+                State::Closing(waiters) => {
+                    waiters.push(completion.take().unwrap());
+                    None
+                }
+                State::Closed(result) => Some(result.clone()),
+            }
+        };
+        if let Some(result) = settled {
+            dispatch(completion.take().unwrap(), result);
+        }
+        if start && self.owner.sender.send(Control::Close).is_err() {
+            complete(&self.owner.state, Err(stopped()));
+        }
+    }
+}
+
+fn stopped() -> Error {
+    Error::classified(ErrorKind::Lifecycle, "WASIX server owner has stopped")
+}
+fn dispatch(completion: Completion, result: Result<()>) {
+    let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| completion(result)));
+}
+fn complete(state: &Mutex, result: Result<()>) {
+    let waiters = {
+        let mut state = state.lock().unwrap_or_else(|error| error.into_inner());
+        if matches!(*state, State::Closed(_)) {
+            return;
+        }
+        match std::mem::replace(&mut *state, State::Closed(result.clone())) {
+            State::Closing(waiters) => waiters,
+            _ => Vec::new(),
+        }
+    };
+    for waiter in waiters {
+        dispatch(waiter, result.clone());
+    }
+}
+
+/// Builder for the asynchronous socket owner.
+#[derive(Debug, Clone, Default)]
+pub struct AsyncOliphauntServerBuilder {
+    inner: OliphauntServerBuilder,
+}
+impl AsyncOliphauntServerBuilder {
+    pub fn new() -> Self {
+        Self::default()
+    }
+    pub fn storage(mut self, storage: crate::DatabaseStorage) -> Self {
+        self.inner = self.inner.storage(storage);
+        self
+    }
+    pub fn seed(mut self, seed: oliphaunt_wasix::ClusterSeed) -> Self {
+        self.inner = self.inner.seed(seed);
+        self
+    }
+
+    /// Select independently packaged ICU data and its catalog profile.
+    pub fn icu_data(mut self, data: oliphaunt_wasix::IcuData) -> Self {
+        self.inner = self.inner.icu_data(data);
+        self
+    }
+    pub fn catalog_profile(mut self, profile: oliphaunt_wasix::session::CatalogProfile) -> Self {
+        self.inner = self.inner.catalog_profile(profile);
+        self
+    }
+    pub fn listen(mut self, listen: crate::ServerListen) -> Self {
+        self.inner = self.inner.listen(listen);
+        self
+    }
+    pub fn username(mut self, user: impl Into) -> Self {
+        self.inner = self.inner.username(user);
+        self
+    }
+    pub fn database(mut self, database: impl Into) -> Self {
+        self.inner = self.inner.database(database);
+        self
+    }
+    pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self {
+        self.inner = self.inner.startup_guc(name, value);
+        self
+    }
+    pub fn startup_gucs, V: Into>(
+        mut self,
+        settings: impl IntoIterator,
+    ) -> Self {
+        self.inner = self.inner.startup_gucs(settings);
+        self
+    }
+    #[cfg(feature = "extensions")]
+    pub fn extension(mut self, extension: oliphaunt_wasix::Extension) -> Self {
+        self.inner = self.inner.extension(extension);
+        self
+    }
+    #[cfg(feature = "extensions")]
+    pub fn extensions(
+        mut self,
+        extensions: impl IntoIterator,
+    ) -> Self {
+        self.inner = self.inner.extensions(extensions);
+        self
+    }
+    pub async fn start(self) -> Result {
+        let (reply, receiver) = oneshot::channel();
+        self.start_with_completion(move |result| {
+            let _ = reply.send(result);
+        });
+        receiver.await.map_err(|_| stopped())?
+    }
+    pub fn start_with_completion(
+        self,
+        completion: impl FnOnce(Result) + Send + 'static,
+    ) {
+        Self::start_configured_with_completion(move || Ok(self), completion);
+    }
+    /// Prepare resources and start on the permanent server owner thread.
+    #[doc(hidden)]
+    pub fn start_configured_with_completion(
+        configure: impl FnOnce() -> std::result::Result + Send + 'static,
+        completion: impl FnOnce(Result) + Send + 'static,
+    ) {
+        let completion = Arc::new(Mutex::new(Some(completion)));
+        let callback = completion.clone();
+        let spawned = thread::Builder::new()
+            .name("oliphaunt-pgwire-owner".into())
+            .spawn(move || {
+                let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
+                    configure()
+                        .map_err(|error| Error::classified(ErrorKind::InvalidConfiguration, error))?
+                        .inner
+                        .start()
+                }))
+                .unwrap_or_else(|_| {
+                    Err(Error::classified(
+                        ErrorKind::Lifecycle,
+                        "WASIX server startup panicked",
+                    ))
+                });
+                let callback = callback
+                    .lock()
+                    .unwrap_or_else(|error| error.into_inner())
+                    .take()
+                    .unwrap();
+                let mut server: OliphauntServer = match result {
+                    Ok(server) => server,
+                    Err(error) => {
+                        let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
+                            callback(Err(error))
+                        }));
+                        return;
+                    }
+                };
+                let (sender, receiver) = mpsc::channel();
+                let state = Arc::new(Mutex::new(State::Open));
+                let _stopped = OwnerStopped(state.clone());
+                let handle = AsyncOliphauntServer {
+                    owner: Arc::new(Owner {
+                        sender,
+                        state: state.clone(),
+                    }),
+                    connection_string: Arc::from(server.connection_string()),
+                };
+                // A cancelled start future drops this handle and queues shutdown.
+                let _ =
+                    std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| callback(Ok(handle))));
+                let _ = receiver.recv();
+                let result = server.owner_close();
+                drop(server);
+                complete(&state, result);
+            });
+        if let Err(error) = spawned
+            && let Some(callback) = completion
+                .lock()
+                .unwrap_or_else(|error| error.into_inner())
+                .take()
+        {
+            let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
+                callback(Err(Error::from_anyhow(anyhow::anyhow!(
+                    "spawn WASIX server owner: {error}"
+                ))))
+            }));
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn preparation_runs_on_owner_and_failure_completes_once() {
+        let caller = std::thread::current().id();
+        let (sent, received) = std::sync::mpsc::channel();
+        super::AsyncOliphauntServerBuilder::start_configured_with_completion(
+            move || {
+                assert_ne!(std::thread::current().id(), caller);
+                Err("invalid server resources".to_owned())
+            },
+            move |result| {
+                sent.send(result.err().unwrap()).unwrap();
+            },
+        );
+        let error = received
+            .recv_timeout(std::time::Duration::from_secs(5))
+            .unwrap();
+        assert_eq!(error.kind(), crate::ErrorKind::InvalidConfiguration);
+        assert!(error.to_string().contains("invalid server resources"));
+        assert!(
+            received
+                .recv_timeout(std::time::Duration::from_secs(5))
+                .is_err()
+        );
+    }
+    use super::*;
+    use std::future::Future;
+    use std::task::{Context, Poll, Waker};
+
+    fn pending_server() -> (AsyncOliphauntServer, mpsc::Receiver) {
+        let (sender, receiver) = mpsc::channel();
+        let server = AsyncOliphauntServer {
+            owner: Arc::new(Owner {
+                sender,
+                state: Arc::new(Mutex::new(State::Open)),
+            }),
+            connection_string: Arc::from("postgres://localhost/test"),
+        };
+        (server, receiver)
+    }
+
+    #[tokio::test]
+    async fn cancelled_waiter_and_clones_join_one_shutdown_and_replay_failure() {
+        let (server, receiver) = pending_server();
+        let mut first = Box::pin(server.close());
+        let mut context = Context::from_waker(Waker::noop());
+        assert!(matches!(first.as_mut().poll(&mut context), Poll::Pending));
+        receiver.try_recv().expect("accepted close queued");
+        drop(first);
+        let clone = server.clone();
+        let mut second = Box::pin(clone.close());
+        assert!(matches!(second.as_mut().poll(&mut context), Poll::Pending));
+        assert!(
+            receiver.try_recv().is_err(),
+            "must not queue a second teardown"
+        );
+        let failure = Error::classified(ErrorKind::Lifecycle, "worker did not stop");
+        complete(&server.owner.state, Err(failure));
+        assert_eq!(second.await.unwrap_err().to_string(), "worker did not stop");
+        assert!(server.is_closed());
+        assert_eq!(
+            server.close().await.unwrap_err().to_string(),
+            "worker did not stop"
+        );
+        // Worker-drop notification cannot overwrite the actual terminal error.
+        drop(OwnerStopped(server.owner.state.clone()));
+        assert_eq!(
+            server.close().await.unwrap_err().to_string(),
+            "worker did not stop"
+        );
+    }
+
+    #[test]
+    fn panicking_and_reentrant_callbacks_do_not_block_other_waiters() {
+        let (server, _receiver) = pending_server();
+        server.close_with_completion(|_| panic!("caller panic"));
+        let clone = server.clone();
+        let (reply, received) = mpsc::channel();
+        server.close_with_completion(move |result| {
+            result.unwrap();
+            assert!(clone.is_closed());
+            clone.close_with_completion(move |result| {
+                reply.send(result).unwrap();
+            });
+        });
+        complete(&server.owner.state, Ok(()));
+        received
+            .recv_timeout(std::time::Duration::from_secs(1))
+            .unwrap()
+            .unwrap();
+    }
+
+    #[tokio::test]
+    async fn stopped_owner_settles_accepted_waiters() {
+        let (server, receiver) = pending_server();
+        let mut close = Box::pin(server.close());
+        assert!(matches!(
+            close.as_mut().poll(&mut Context::from_waker(Waker::noop())),
+            Poll::Pending
+        ));
+        receiver.try_recv().unwrap();
+        drop(OwnerStopped(server.owner.state.clone()));
+        assert_eq!(close.await.unwrap_err().kind(), ErrorKind::Lifecycle);
+        assert!(server.is_closed());
+    }
+}
diff --git a/src/pgwire-server/src/error.rs b/src/pgwire-server/src/error.rs
new file mode 100644
index 000000000..1fda62579
--- /dev/null
+++ b/src/pgwire-server/src/error.rs
@@ -0,0 +1,12 @@
+pub(crate) fn public_result(result: anyhow::Result) -> crate::Result {
+    result.map_err(crate::Error::from_anyhow)
+}
+
+pub(crate) fn invalid_configuration(
+    message: impl std::fmt::Display + Send + Sync + 'static,
+) -> anyhow::Error {
+    anyhow::Error::new(crate::Error::classified(
+        crate::ErrorKind::InvalidConfiguration,
+        message,
+    ))
+}
diff --git a/src/pgwire-server/src/lib.rs b/src/pgwire-server/src/lib.rs
new file mode 100644
index 000000000..39ea7be5d
--- /dev/null
+++ b/src/pgwire-server/src/lib.rs
@@ -0,0 +1,21 @@
+//! PostgreSQL wire server with a separately selectable WASIX backend.
+
+/// Runtime-independent PostgreSQL connection framing.
+pub use oliphaunt_query::wire;
+
+#[cfg(feature = "wasix")]
+mod async_server;
+#[cfg(feature = "wasix")]
+mod error;
+#[cfg(feature = "wasix")]
+mod lifecycle;
+#[cfg(feature = "wasix")]
+mod proxy;
+#[cfg(feature = "wasix")]
+mod server;
+#[cfg(feature = "wasix")]
+pub use async_server::{AsyncOliphauntServer, AsyncOliphauntServerBuilder};
+#[cfg(feature = "wasix")]
+pub use oliphaunt_wasix::{DatabaseStorage, Error, ErrorKind, Result};
+#[cfg(feature = "wasix")]
+pub use server::{OliphauntServer, OliphauntServerBuilder, ServerListen};
diff --git a/src/pgwire-server/src/lifecycle.rs b/src/pgwire-server/src/lifecycle.rs
new file mode 100644
index 000000000..86add73f7
--- /dev/null
+++ b/src/pgwire-server/src/lifecycle.rs
@@ -0,0 +1,20 @@
+pub(crate) type TerminalCloseResult = crate::Result<()>;
+
+pub(crate) fn teardown_result(
+    owner: &'static str,
+    close: impl FnOnce() -> anyhow::Result<()>,
+) -> TerminalCloseResult {
+    match std::panic::catch_unwind(std::panic::AssertUnwindSafe(close)) {
+        Ok(result) => result.map_err(crate::Error::from_anyhow),
+        Err(panic) => {
+            let message = panic
+                .downcast_ref::()
+                .map(String::as_str)
+                .or_else(|| panic.downcast_ref::<&'static str>().copied())
+                .unwrap_or("unknown panic payload");
+            Err(crate::Error::from_anyhow(anyhow::anyhow!(
+                "{owner} panicked during teardown: {message}"
+            )))
+        }
+    }
+}
diff --git a/src/pgwire-server/src/main.rs b/src/pgwire-server/src/main.rs
new file mode 100644
index 000000000..529202f0f
--- /dev/null
+++ b/src/pgwire-server/src/main.rs
@@ -0,0 +1,153 @@
+use anyhow::{Result, bail};
+use oliphaunt_pgwire_server::{DatabaseStorage, OliphauntServer, ServerListen};
+#[cfg(feature = "extensions")]
+use oliphaunt_wasix::Extension;
+use std::env;
+use std::path::PathBuf;
+
+#[derive(Debug)]
+enum Bind {
+    Tcp(u16),
+    #[cfg(unix)]
+    Unix {
+        directory: PathBuf,
+        port: u16,
+    },
+}
+
+#[derive(Debug)]
+struct Args {
+    storage: DatabaseStorage,
+    bind: Bind,
+    print_uri: bool,
+    postgres_config: Vec<(String, String)>,
+    extensions: Vec,
+}
+
+fn main() -> Result<()> {
+    let args = parse_args()?;
+    let mut builder = OliphauntServer::builder().storage(args.storage);
+
+    builder = match args.bind {
+        Bind::Tcp(0) => builder.listen(ServerListen::tcp()),
+        Bind::Tcp(port) => builder.listen(ServerListen::tcp_port(port)),
+        #[cfg(unix)]
+        Bind::Unix { directory, port } => builder.listen(ServerListen::unix_port(directory, port)),
+    };
+    builder = builder.startup_gucs(args.postgres_config);
+
+    #[cfg(feature = "extensions")]
+    {
+        for name in &args.extensions {
+            let extension = Extension::by_sql_name(name)
+                .ok_or_else(|| anyhow::anyhow!("unknown extension: {name}"))?;
+            builder = builder.extension(extension);
+        }
+    }
+    #[cfg(not(feature = "extensions"))]
+    if !args.extensions.is_empty() {
+        bail!("this oliphaunt-pgwire-server build was compiled without extension support");
+    }
+
+    let server = builder.start()?;
+    if args.print_uri {
+        println!("{}", server.connection_string());
+    } else {
+        eprintln!("listening: {}", server.connection_string());
+    }
+
+    loop {
+        std::thread::park();
+    }
+}
+
+fn parse_args() -> Result {
+    let mut storage = DatabaseStorage::Memory;
+    let mut print_uri = false;
+    let mut postgres_config = Vec::new();
+    let mut extensions = Vec::new();
+    let mut bind = Bind::Tcp(0);
+
+    let mut args = env::args().skip(1);
+    while let Some(arg) = args.next() {
+        match arg.as_str() {
+            "--memory" => storage = DatabaseStorage::Memory,
+            "--directory" => {
+                let value = args
+                    .next()
+                    .ok_or_else(|| anyhow::anyhow!("--directory requires a path"))?;
+                storage = DatabaseStorage::Directory(PathBuf::from(value));
+            }
+            "--tcp" => {
+                let value = args
+                    .next()
+                    .ok_or_else(|| anyhow::anyhow!("--tcp requires a port"))?;
+                bind = Bind::Tcp(parse_port("--tcp", &value)?);
+            }
+            #[cfg(unix)]
+            "--unix" | "--uds" => {
+                let directory = args
+                    .next()
+                    .ok_or_else(|| anyhow::anyhow!("--unix requires a directory"))?;
+                bind = Bind::Unix {
+                    directory: PathBuf::from(directory),
+                    port: 5432,
+                };
+            }
+            "--print-uri" => print_uri = true,
+            "--startup-guc" => {
+                let value = args
+                    .next()
+                    .ok_or_else(|| anyhow::anyhow!("--startup-guc requires name=value"))?;
+                let (name, value) = value
+                    .split_once('=')
+                    .ok_or_else(|| anyhow::anyhow!("--startup-guc requires name=value"))?;
+                postgres_config.push((name.to_owned(), value.to_owned()));
+            }
+            "--extension" => {
+                let value = args
+                    .next()
+                    .ok_or_else(|| anyhow::anyhow!("--extension requires a name"))?;
+                extensions.push(value);
+            }
+            "--help" | "-h" => {
+                print_usage();
+                std::process::exit(0);
+            }
+            other => bail!("unknown argument: {other}"),
+        }
+    }
+
+    Ok(Args {
+        storage,
+        bind,
+        print_uri,
+        postgres_config,
+        extensions,
+    })
+}
+
+fn parse_port(flag: &str, value: &str) -> Result {
+    let port = value
+        .parse::()
+        .map_err(|_| anyhow::anyhow!("{flag} requires a port in the range 1..=65535"))?;
+    if port == 0 {
+        bail!("{flag} requires a port in the range 1..=65535");
+    }
+    Ok(port)
+}
+
+fn print_usage() {
+    eprintln!(
+        "Usage: oliphaunt-pgwire-server [--memory | --directory PATH] [--tcp PORT | --unix DIRECTORY] [--print-uri] [--startup-guc NAME=VALUE] [--extension NAME]"
+    );
+    eprintln!("  --memory          Store PGDATA in memory. This is the default");
+    eprintln!("  --directory PATH  Store PGDATA in a retained host directory");
+    eprintln!("  --tcp PORT        Listen on IPv4 loopback using PORT");
+    #[cfg(unix)]
+    eprintln!("  --unix DIRECTORY  Listen on DIRECTORY/.s.PGSQL.5432");
+    eprintln!("  --print-uri       Print the PostgreSQL connection URI to stdout");
+    eprintln!("  --startup-guc NAME=VALUE");
+    eprintln!("                    Set a PostgreSQL startup GUC on the embedded backend");
+    eprintln!("  --extension NAME  Select an extension artifact by SQL name");
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/proxy.rs b/src/pgwire-server/src/proxy.rs
similarity index 86%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/proxy.rs
rename to src/pgwire-server/src/proxy.rs
index fb18e592d..484e003e4 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/proxy.rs
+++ b/src/pgwire-server/src/proxy.rs
@@ -8,23 +8,21 @@ use std::sync::{
     atomic::{AtomicBool, Ordering},
     mpsc::SyncSender,
 };
+use std::time::Duration;
 
-use crate::oliphaunt::backend::BackendSession;
-use crate::oliphaunt::base::InstallOutcome;
-#[cfg(feature = "extensions")]
-use crate::oliphaunt::base::install_missing_extension_archives;
-use crate::oliphaunt::config::{PostgresConfig, StartupConfig};
+use crate::lifecycle::teardown_result;
+use crate::wire::{
+    FrontendFrameKind, FrontendFrameReader, classify_frontend_message, error_response,
+    response_contains_error, startup_parameter,
+};
+use oliphaunt_query::simple_query;
 #[cfg(feature = "extensions")]
-use crate::oliphaunt::extensions::Extension;
-use crate::oliphaunt::lifecycle::{TeardownOwnership, teardown_result};
-use crate::oliphaunt::postgres_mod::{
+use oliphaunt_wasix::Extension;
+use oliphaunt_wasix::session::{PostgresConfig, StartupConfig};
+use oliphaunt_wasix::session::{PreparedRuntime, ProtocolSession};
+use oliphaunt_wasix::session::{
     ProtocolPumpOutcome, ProtocolStream, StartupProtocolResponse, startup_error_response_output,
 };
-use crate::oliphaunt::query::simple_query;
-use crate::oliphaunt::wire::{
-    FrontendFrameKind, FrontendFrameReader, classify_frontend_message, error_response,
-    response_contains_error, startup_config_for_message, startup_parameter,
-};
 
 const PROXY_READ_BUFFER_BYTES: usize = 64 * 1024;
 
@@ -35,7 +33,7 @@ const PROXY_READ_BUFFER_BYTES: usize = 64 * 1024;
 /// nested runtime panics when an async wrapper blocks inside the embedded engine.
 #[derive(Debug, Clone)]
 pub(crate) struct OliphauntProxy {
-    prepared_database: Arc,
+    prepared_database: Arc,
     postgres_config: Arc,
     startup_config: Arc,
     backend_teardown_failure: Arc>>,
@@ -122,7 +120,7 @@ impl Drop for ActiveConnectionGuard {
 }
 
 impl OliphauntProxy {
-    pub(crate) fn from_prepared_database(outcome: InstallOutcome) -> Self {
+    pub(crate) fn from_prepared_database(outcome: PreparedRuntime) -> Self {
         Self {
             prepared_database: Arc::new(outcome),
             postgres_config: Arc::new(PostgresConfig::default()),
@@ -170,12 +168,17 @@ impl OliphauntProxy {
                 stream
                     .set_nonblocking(false)
                     .context("configure TCP proxy stream as blocking")?;
+                // Bound reads so shutdown does not depend on the OS interrupting
+                // an in-flight recv on a cloned socket handle.
+                stream
+                    .set_read_timeout(Some(Duration::from_millis(100)))
+                    .context("configure TCP proxy shutdown polling")?;
                 let _active = active_connection.register_tcp(&stream)?;
                 if shutdown.load(Ordering::SeqCst) {
                     active_connection.shutdown();
                     return Ok(());
                 }
-                self.handle_stream(stream)
+                self.handle_stream(stream, &shutdown)
             })();
             if let Some(error) = self.connection_teardown_failure(&result) {
                 return Err(error);
@@ -213,7 +216,7 @@ impl OliphauntProxy {
                     active_connection.shutdown();
                     return Ok(());
                 }
-                self.handle_stream(stream)
+                self.handle_stream(stream, &shutdown)
             })();
             if let Some(error) = self.connection_teardown_failure(&result) {
                 return Err(error);
@@ -226,7 +229,7 @@ impl OliphauntProxy {
         Ok(())
     }
 
-    fn handle_stream(&self, mut stream: S) -> Result<()>
+    fn handle_stream(&self, mut stream: S, shutdown: &Arc) -> Result<()>
     where
         S: CloneProtocolStream,
     {
@@ -236,7 +239,8 @@ impl OliphauntProxy {
         let mut protocol_batch = Vec::new();
 
         loop {
-            let read = stream.read(&mut buffer).context("read frontend socket")?;
+            let read = read_frontend(&mut stream, &mut buffer, shutdown)
+                .context("read frontend socket")?;
             if read == 0 {
                 flush_protocol_batch_if_started(
                     &mut protocol_batch,
@@ -346,11 +350,12 @@ impl OliphauntProxy {
                         }
                         if response_accepted {
                             if opened.supports_protocol_pump() {
-                                opened.attach_protocol_stream(
+                                opened.attach_protocol_stream(ProtocolIo(
                                     stream
                                         .try_clone_for_protocol()
                                         .context("clone frontend socket for protocol pump")?,
-                                )?;
+                                    Arc::clone(shutdown),
+                                ))?;
                             }
                             backend = Some(opened);
                         } else {
@@ -464,13 +469,7 @@ impl ProtocolReadiness for UnixStream {
     }
 }
 
-impl ProtocolStream for TcpStream {
-    fn read_ready(&mut self) -> io::Result {
-        ProtocolReadiness::read_ready(self)
-    }
-}
-
-trait CloneProtocolStream: Read + Write + Send + ProtocolStream + Sized + 'static {
+trait CloneProtocolStream: Read + Write + Send + ProtocolReadiness + Sized + 'static {
     fn try_clone_for_protocol(&self) -> io::Result;
 }
 
@@ -519,13 +518,6 @@ impl SetNonblocking for UnixStream {
     }
 }
 
-#[cfg(unix)]
-impl ProtocolStream for UnixStream {
-    fn read_ready(&mut self) -> io::Result {
-        ProtocolReadiness::read_ready(self)
-    }
-}
-
 #[cfg(unix)]
 impl CloneProtocolStream for UnixStream {
     fn try_clone_for_protocol(&self) -> io::Result {
@@ -581,70 +573,27 @@ impl<'a> ContinuationPrefix<'a> {
 }
 
 struct WireBackend {
-    session: TeardownOwnership,
+    session: ProtocolSession,
     teardown_failure: Arc>>,
     connection_started: bool,
     closed: bool,
 }
 
 impl WireBackend {
-    #[cfg(feature = "extensions")]
     fn open(
-        prepared_database: &InstallOutcome,
-        postgres_config: &PostgresConfig,
-        startup_config: &StartupConfig,
-        extensions: &[Extension],
+        prepared: &PreparedRuntime,
+        config: &PostgresConfig,
+        startup: &StartupConfig,
+        #[cfg(feature = "extensions")] extensions: &[Extension],
+        #[cfg(not(feature = "extensions"))] _extensions: &[()],
         teardown_failure: Arc>>,
     ) -> Result {
-        {
-            install_missing_extension_archives(prepared_database, extensions)?;
-        }
-        Self::open_prepared(
-            prepared_database,
-            postgres_config,
-            startup_config,
-            extensions,
-            teardown_failure,
-        )
-    }
-
-    #[cfg(feature = "extensions")]
-    fn open_prepared(
-        outcome: &InstallOutcome,
-        postgres_config: &PostgresConfig,
-        startup_config: &StartupConfig,
-        extensions: &[Extension],
-        teardown_failure: Arc>>,
-    ) -> Result {
-        let session = BackendSession::open_with_extension_preload(
-            outcome.clone(),
-            postgres_config.clone(),
-            startup_config.clone(),
-            extensions,
-        )?;
+        #[cfg(feature = "extensions")]
+        let session = prepared.open_with_extensions(config.clone(), startup.clone(), extensions)?;
+        #[cfg(not(feature = "extensions"))]
+        let session = prepared.open(config.clone(), startup.clone())?;
         Ok(Self {
-            session: TeardownOwnership::new(session),
-            teardown_failure,
-            connection_started: false,
-            closed: false,
-        })
-    }
-
-    #[cfg(not(feature = "extensions"))]
-    fn open(
-        prepared_database: &InstallOutcome,
-        postgres_config: &PostgresConfig,
-        startup_config: &StartupConfig,
-        _extensions: &[()],
-        teardown_failure: Arc>>,
-    ) -> Result {
-        let session = BackendSession::open(
-            prepared_database.clone(),
-            postgres_config.clone(),
-            startup_config.clone(),
-        )?;
-        Ok(Self {
-            session: TeardownOwnership::new(session),
+            session,
             teardown_failure,
             connection_started: false,
             closed: false,
@@ -682,7 +631,7 @@ impl WireBackend {
     }
 
     fn set_role(&mut self, user: &str) -> Result> {
-        let sql = format!("SET ROLE {}", crate::oliphaunt::sql::quote_identifier(user));
+        let sql = format!("SET ROLE \"{}\"", user.replace('"', "\"\""));
         self.send(&simple_query(&sql)?)
     }
 
@@ -708,7 +657,6 @@ impl WireBackend {
         };
         let shutdown = teardown_result("WASIX proxy backend", || {
             self.session.shutdown()?;
-            self.session.release();
             Ok(())
         });
         if let Err(shutdown) = shutdown {
@@ -850,10 +798,95 @@ where
     Ok(())
 }
 
+fn startup_config_for_message(base: &StartupConfig, message: &[u8]) -> Result {
+    let mut config = base.clone();
+    if let Some(user) = startup_parameter(message, "user")? {
+        config.username = user.to_owned();
+    }
+    if let Some(database) = startup_parameter(message, "database")? {
+        config.database = database.to_owned();
+    }
+    config.validate()?;
+    Ok(config)
+}
+
+fn read_frontend(
+    stream: &mut impl Read,
+    bytes: &mut [u8],
+    shutdown: &AtomicBool,
+) -> io::Result {
+    loop {
+        if shutdown.load(Ordering::SeqCst) {
+            return Ok(0);
+        }
+        match stream.read(bytes) {
+            Err(error)
+                if matches!(
+                    error.kind(),
+                    io::ErrorKind::WouldBlock | io::ErrorKind::TimedOut
+                ) => {}
+            result => return result,
+        }
+    }
+}
+
+struct ProtocolIo(S, Arc);
+impl Read for ProtocolIo {
+    fn read(&mut self, bytes: &mut [u8]) -> io::Result {
+        read_frontend(&mut self.0, bytes, &self.1)
+    }
+}
+impl Write for ProtocolIo {
+    fn write(&mut self, bytes: &[u8]) -> io::Result {
+        self.0.write(bytes)
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        self.0.flush()
+    }
+}
+impl ProtocolStream for ProtocolIo {
+    fn read_ready(&mut self) -> io::Result {
+        if self.1.load(Ordering::SeqCst) {
+            return Ok(true);
+        }
+        self.0.read_ready()
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
 
+    #[test]
+    fn protocol_reader_retries_idle_timeouts_and_observes_shutdown() -> Result<()> {
+        let listener = TcpListener::bind("127.0.0.1:0")?;
+        let mut client = TcpStream::connect(listener.local_addr()?)?;
+        let (stream, _) = listener.accept()?;
+        stream.set_read_timeout(Some(Duration::from_millis(10)))?;
+        let shutdown = Arc::new(AtomicBool::new(false));
+        let mut protocol = ProtocolIo(stream, Arc::clone(&shutdown));
+        let (tx, rx) = std::sync::mpsc::sync_channel(1);
+        let worker = std::thread::spawn(move || -> io::Result<()> {
+            let mut byte = [0];
+            assert_eq!(protocol.read(&mut byte)?, 1);
+            assert_eq!(byte, [42]);
+            tx.send(()).unwrap();
+            assert_eq!(protocol.read(&mut byte)?, 0);
+            assert!(protocol.read_ready()?);
+            tx.send(()).unwrap();
+            Ok(())
+        });
+        std::thread::sleep(Duration::from_millis(50));
+        client.write_all(&[42])?;
+        rx.recv_timeout(Duration::from_secs(2))?;
+        // Deliberately leave the socket open: cancellation must work even if
+        // the OS does not interrupt the pending read on the cloned handle.
+        shutdown.store(true, Ordering::SeqCst);
+        rx.recv_timeout(Duration::from_secs(2))?;
+        worker.join().unwrap()?;
+        Ok(())
+    }
+
     #[test]
     fn protocol_batch_flushes_on_client_boundaries() {
         assert!(should_flush_protocol_batch(b"Q\0\0\0\rSELECT 1\0", false));
diff --git a/src/pgwire-server/src/server.rs b/src/pgwire-server/src/server.rs
new file mode 100644
index 000000000..8e1a12bcf
--- /dev/null
+++ b/src/pgwire-server/src/server.rs
@@ -0,0 +1,1130 @@
+use std::cell::Cell;
+use std::marker::PhantomData;
+use std::net::{SocketAddr, TcpListener, TcpStream};
+#[cfg(unix)]
+use std::os::unix::ffi::OsStrExt;
+#[cfg(unix)]
+use std::os::unix::fs::{FileTypeExt, MetadataExt};
+#[cfg(unix)]
+use std::os::unix::net::{UnixListener, UnixStream};
+use std::path::{Path, PathBuf};
+use std::sync::{
+    Arc,
+    atomic::{AtomicBool, Ordering},
+    mpsc::{Receiver, sync_channel},
+};
+use std::thread::{self, JoinHandle};
+
+use anyhow::{Context, Result, anyhow};
+
+use crate::lifecycle::{TerminalCloseResult, teardown_result};
+use crate::proxy::{ActiveConnection, OliphauntProxy};
+use oliphaunt_wasix::DatabaseStorage;
+#[cfg(feature = "extensions")]
+use oliphaunt_wasix::Extension;
+use oliphaunt_wasix::session::PreparedDatabase;
+use oliphaunt_wasix::session::{CatalogProfile, default_catalog_profile};
+use oliphaunt_wasix::session::{PostgresConfig, StartupConfig};
+#[cfg(feature = "extensions")]
+use oliphaunt_wasix::session::{postgres_config_with_extension_startup, resolve_extension_set};
+
+/// A supervised local PostgreSQL socket backed by one embedded Oliphaunt runtime.
+///
+/// Use this entry point for code that expects a PostgreSQL URI, such as
+/// `tokio-postgres`, SQLx, or tools that speak the wire protocol. The
+/// server owns one embedded backend, so downstream pools should use a single
+/// connection.
+#[derive(Debug)]
+pub struct OliphauntServer {
+    // The listener is owned and stopped by one blocking caller. Moving that
+    // ownership to another thread is safe; sharing references concurrently is
+    // deliberately unsupported. AsyncOliphauntServer provides a Sync handle.
+    _not_sync: PhantomData>,
+    prepared_database: Option,
+    endpoint: ServerEndpoint,
+    connection_string: String,
+    shutdown: Arc,
+    active_connection: Arc,
+    handle: Option>>,
+    close_result: Option,
+    #[cfg(all(test, feature = "icu"))]
+    catalog_profile: CatalogProfile,
+    #[cfg(all(test, feature = "icu"))]
+    runtime_root: PathBuf,
+    #[cfg(unix)]
+    owned_unix_socket: Option,
+}
+
+#[derive(Debug, Clone)]
+enum ServerEndpoint {
+    Tcp(SocketAddr),
+    #[cfg(unix)]
+    Unix(UnixSocketEndpoint),
+}
+
+#[cfg(unix)]
+#[derive(Debug, Clone)]
+struct UnixSocketEndpoint {
+    path: PathBuf,
+    port: u16,
+}
+
+#[cfg(unix)]
+#[derive(Debug)]
+struct OwnedUnixSocket {
+    path: PathBuf,
+    identity: Option<(u64, u64)>,
+}
+
+impl OliphauntServer {
+    /// Build a local Oliphaunt server. The default is an in-memory database
+    /// served on IPv4 loopback with an automatically assigned port.
+    pub fn builder() -> OliphauntServerBuilder {
+        OliphauntServerBuilder::new()
+    }
+
+    /// Return a PostgreSQL connection URI for the local server.
+    pub fn connection_string(&self) -> &str {
+        &self.connection_string
+    }
+
+    /// Whether this direct server is permanently retired.
+    ///
+    /// The value becomes true when shutdown begins, including when terminal
+    /// cleanup later reports an error. Repeated [`Self::close`] calls replay
+    /// that first terminal result.
+    ///
+    /// This is lifecycle state, not a health check. `false` does not poll the
+    /// proxy listener or prove that the published endpoint is reachable.
+    pub fn is_closed(&self) -> bool {
+        self.shutdown.load(Ordering::SeqCst) || self.close_result.is_some()
+    }
+
+    /// Request shutdown and wait for the listener thread to exit.
+    ///
+    /// Any active client connection is closed before the listener thread is
+    /// joined. Once stop begins, the server is terminal even when cleanup
+    /// reports an error. Successful teardown releases managed-root ownership;
+    /// failed teardown retains it until process exit.
+    pub fn close(&mut self) -> crate::Result<()> {
+        self.owner_close()
+    }
+
+    /// Terminal close boundary used by the asynchronous owner thread.
+    ///
+    /// Once stop begins, later calls replay its exact success or failure.
+    pub(crate) fn owner_close(&mut self) -> crate::Result<()> {
+        if let Some(result) = &self.close_result {
+            return result.clone();
+        }
+        let result = teardown_result("WASIX server", || self.stop());
+        self.close_result = Some(result.clone());
+        result
+    }
+
+    fn stop(&mut self) -> Result<()> {
+        self.shutdown.store(true, Ordering::SeqCst);
+        self.active_connection.shutdown();
+        {
+            wake_listener(&self.endpoint);
+        }
+        let worker_result = if let Some(handle) = self.handle.take() {
+            match handle.join() {
+                Ok(result) => result,
+                Err(_) => Err(anyhow!("oliphaunt server thread panicked")),
+            }
+        } else {
+            Ok(())
+        };
+        #[cfg(unix)]
+        let socket_result = if let Some(mut socket) = self.owned_unix_socket.take() {
+            socket.cleanup()
+        } else {
+            Ok(())
+        };
+        #[cfg(not(unix))]
+        let socket_result = Ok::<(), anyhow::Error>(());
+
+        let result = match (worker_result, socket_result) {
+            (Ok(()), Ok(())) => Ok(()),
+            (Err(error), Ok(())) | (Ok(()), Err(error)) => Err(error),
+            (Err(worker), Err(socket)) => Err(anyhow!(
+                "Oliphaunt server worker failed: {worker:#}; Unix socket cleanup also failed: {socket:#}"
+            )),
+        };
+        if result.is_ok() {
+            // Keep the managed-root lock until every other owned resource has
+            // been destroyed. `owner_close` contains a destructor panic and
+            // caches it as a terminal failure without a second cleanup.
+            if let Some(prepared) = self.prepared_database.as_mut() {
+                prepared.release()?;
+            }
+            self.prepared_database.take();
+        }
+        result
+    }
+}
+
+impl Drop for OliphauntServer {
+    fn drop(&mut self) {
+        if self.close_result.is_none()
+            && let Err(err) = self.owner_close()
+        {
+            tracing::warn!("oliphaunt server shutdown during drop failed: {err:#}");
+        }
+    }
+}
+
+#[cfg(test)]
+pub(crate) fn server_with_worker_result_for_test(
+    result: Result<()>,
+    prepared_database: Option,
+) -> OliphauntServer {
+    OliphauntServer {
+        _not_sync: PhantomData,
+        prepared_database,
+        endpoint: ServerEndpoint::Tcp(SocketAddr::from(([127, 0, 0, 1], 0))),
+        connection_string: tcp_connection_string(
+            SocketAddr::from(([127, 0, 0, 1], 0)),
+            &StartupConfig::default(),
+        ),
+        shutdown: Arc::new(AtomicBool::new(false)),
+        active_connection: Arc::new(ActiveConnection::default()),
+        handle: Some(thread::spawn(move || result)),
+        close_result: None,
+        #[cfg(feature = "icu")]
+        catalog_profile: CatalogProfile::default(),
+        #[cfg(feature = "icu")]
+        runtime_root: PathBuf::new(),
+        #[cfg(unix)]
+        owned_unix_socket: None,
+    }
+}
+
+/// Builder for [`OliphauntServer`].
+#[derive(Debug, Clone)]
+pub struct OliphauntServerBuilder {
+    storage: DatabaseStorage,
+    seed: Option,
+    icu_data: Option,
+    catalog_profile: CatalogProfile,
+    listen: ServerListen,
+    postgres_config: PostgresConfig,
+    startup_config: StartupConfig,
+    #[cfg(feature = "extensions")]
+    extensions: Vec,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum ServerListen {
+    /// Listen on IPv4 loopback on any supported host. An omitted port asks the
+    /// operating system for one.
+    Tcp { port: Option },
+    #[cfg(unix)]
+    /// Listen on a Unix host in a directory using PostgreSQL's
+    /// `.s.PGSQL.` filename. The directory path must be nonempty and
+    /// valid UTF-8, and contain no NUL bytes. UTF-8 keeps the published
+    /// connection string lossless across Rust drivers and ORMs.
+    Unix { directory: PathBuf, port: u16 },
+}
+
+impl ServerListen {
+    /// Listen on IPv4 loopback on any supported host and let the operating
+    /// system choose the port.
+    pub const fn tcp() -> Self {
+        Self::Tcp { port: None }
+    }
+
+    /// Listen on IPv4 loopback on any supported host at an explicit port.
+    pub const fn tcp_port(port: u16) -> Self {
+        Self::Tcp { port: Some(port) }
+    }
+
+    /// Listen on a Unix host in a UTF-8 Unix-domain socket directory using
+    /// PostgreSQL port 5432.
+    #[cfg(unix)]
+    pub fn unix(directory: impl Into) -> Self {
+        Self::Unix {
+            directory: directory.into(),
+            port: 5432,
+        }
+    }
+
+    /// Listen on a Unix host in a UTF-8 Unix-domain socket directory using an
+    /// explicit PostgreSQL port.
+    #[cfg(unix)]
+    pub fn unix_port(directory: impl Into, port: u16) -> Self {
+        Self::Unix {
+            directory: directory.into(),
+            port,
+        }
+    }
+}
+
+impl Default for ServerListen {
+    fn default() -> Self {
+        Self::tcp()
+    }
+}
+
+impl Default for OliphauntServerBuilder {
+    fn default() -> Self {
+        Self {
+            storage: DatabaseStorage::Memory,
+            seed: None,
+            icu_data: None,
+            catalog_profile: default_catalog_profile(),
+            listen: ServerListen::tcp(),
+            postgres_config: PostgresConfig::default(),
+            startup_config: StartupConfig::default(),
+            #[cfg(feature = "extensions")]
+            extensions: Vec::new(),
+        }
+    }
+}
+
+impl OliphauntServerBuilder {
+    /// Select an independently packaged cluster seed; absent seeds use initdb.
+    pub fn seed(mut self, seed: oliphaunt_wasix::ClusterSeed) -> Self {
+        self.seed = Some(seed);
+        self
+    }
+
+    /// Select independently packaged ICU data and its catalog profile.
+    pub fn icu_data(mut self, data: oliphaunt_wasix::IcuData) -> Self {
+        self.icu_data = Some(data);
+        self.catalog_profile = CatalogProfile::Icu;
+        self
+    }
+    /// Create a builder. Defaults to a memory database on IPv4 loopback with
+    /// an automatically assigned port.
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Select where PostgreSQL stores its mutable database files.
+    pub fn storage(mut self, storage: DatabaseStorage) -> Self {
+        self.storage = storage;
+        self
+    }
+
+    /// Select the packaged standard or ICU catalog and matching runtime data.
+    pub fn catalog_profile(mut self, profile: CatalogProfile) -> Self {
+        self.catalog_profile = profile;
+        self
+    }
+
+    /// Select a loopback TCP listener on any supported host or a PostgreSQL
+    /// Unix-domain listener on a Unix host.
+    pub fn listen(mut self, listen: ServerListen) -> Self {
+        self.listen = listen;
+        self
+    }
+
+    /// Set a PostgreSQL startup GUC for the embedded backend used by this
+    /// server.
+    pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self {
+        self.postgres_config.insert(name, value);
+        self
+    }
+
+    /// Set multiple PostgreSQL startup GUCs for the embedded backend used by
+    /// this server.
+    pub fn startup_gucs(mut self, settings: impl IntoIterator) -> Self
+    where
+        K: Into,
+        V: Into,
+    {
+        for (name, value) in settings {
+            self.postgres_config.insert(name, value);
+        }
+        self
+    }
+
+    /// Default user encoded in [`OliphauntServer::connection_string`].
+    pub fn username(mut self, username: impl Into) -> Self {
+        self.startup_config.username = username.into();
+        self
+    }
+
+    /// Default database encoded in [`OliphauntServer::connection_string`].
+    pub fn database(mut self, database: impl Into) -> Self {
+        self.startup_config.database = database.into();
+        self
+    }
+
+    /// Make one bundled PostgreSQL extension artifact available to clients.
+    /// Database-local installation remains the application's migration concern.
+    #[cfg(feature = "extensions")]
+    pub fn extension(mut self, extension: Extension) -> Self {
+        self.extensions.push(extension);
+        self
+    }
+
+    /// Make bundled PostgreSQL extension artifacts available to clients.
+    /// Database-local installation remains the application's migration concern.
+    #[cfg(feature = "extensions")]
+    pub fn extensions(mut self, extensions: impl IntoIterator) -> Self {
+        self.extensions.extend(extensions);
+        self
+    }
+
+    /// Install the runtime if needed, initialize the cluster, and start serving.
+    pub fn start(self) -> crate::Result {
+        crate::error::public_result(self.start_inner())
+    }
+
+    fn start_inner(self) -> Result {
+        if matches!(self.listen, ServerListen::Tcp { port: Some(0) }) {
+            return Err(crate::error::invalid_configuration(
+                "TCP port must be in the range 1..=65535; omit it to allocate one",
+            ));
+        }
+        #[cfg(unix)]
+        let unix_endpoint = match &self.listen {
+            ServerListen::Unix { directory, port } => {
+                Some(resolve_unix_socket_endpoint(directory, *port)?)
+            }
+            ServerListen::Tcp { .. } => None,
+        };
+
+        #[cfg(feature = "extensions")]
+        let (extensions, postgres_config) = self.resolved_extension_startup()?;
+        #[cfg(not(feature = "extensions"))]
+        let postgres_config = self.postgres_config.clone();
+        postgres_config.validate()?;
+        self.startup_config.validate()?;
+        let startup_config = self.startup_config.clone();
+
+        let mut prepared_database = PreparedDatabase::prepare_with_resources(
+            self.storage.clone(),
+            self.catalog_profile,
+            &startup_config.username,
+            self.seed,
+            self.icu_data,
+        )?;
+        let outcome = prepared_database.runtime()?;
+        #[cfg(all(test, feature = "icu"))]
+        let catalog_profile = outcome.catalog_profile();
+        #[cfg(all(test, feature = "icu"))]
+        let runtime_root = outcome.runtime_root();
+
+        let shutdown = Arc::new(AtomicBool::new(false));
+        let active_connection = Arc::new(ActiveConnection::default());
+        let proxy = { OliphauntProxy::from_prepared_database(outcome) };
+        let proxy = proxy
+            .with_postgres_config(postgres_config)
+            .with_startup_config(startup_config.clone());
+        #[cfg(feature = "extensions")]
+        let proxy = proxy.with_extensions(extensions);
+
+        #[cfg(unix)]
+        let (endpoint, handle, owned_unix_socket) = match self.listen {
+            ServerListen::Tcp { port } => {
+                let addr = SocketAddr::from(([127, 0, 0, 1], port.unwrap_or(0)));
+                let (endpoint, handle) =
+                    start_tcp(proxy, addr, shutdown.clone(), active_connection.clone())
+                        .inspect_err(|_| {
+                            let _ = prepared_database.release();
+                        })?;
+                (endpoint, handle, None)
+            }
+            ServerListen::Unix { .. } => {
+                let (endpoint, handle, socket) = start_unix(
+                    proxy,
+                    unix_endpoint.expect("Unix endpoint was resolved before database preparation"),
+                    shutdown.clone(),
+                    active_connection.clone(),
+                )
+                .inspect_err(|_| {
+                    let _ = prepared_database.release();
+                })?;
+                (endpoint, handle, Some(socket))
+            }
+        };
+        #[cfg(not(unix))]
+        let (endpoint, handle) = match self.listen {
+            ServerListen::Tcp { port } => {
+                let addr = SocketAddr::from(([127, 0, 0, 1], port.unwrap_or(0)));
+                start_tcp(proxy, addr, shutdown.clone(), active_connection.clone()).map_err(
+                    |error| {
+                        let _ = prepared_database.release();
+                        error
+                    },
+                )?
+            }
+        };
+        let connection_string = match &endpoint {
+            ServerEndpoint::Tcp(addr) => tcp_connection_string(*addr, &startup_config),
+            #[cfg(unix)]
+            ServerEndpoint::Unix(endpoint) => unix_connection_string(endpoint, &startup_config),
+        };
+
+        Ok(OliphauntServer {
+            _not_sync: PhantomData,
+            prepared_database: Some(prepared_database),
+            endpoint,
+            connection_string,
+            shutdown,
+            active_connection,
+            handle: Some(handle),
+            close_result: None,
+            #[cfg(all(test, feature = "icu"))]
+            catalog_profile,
+            #[cfg(all(test, feature = "icu"))]
+            runtime_root,
+            #[cfg(unix)]
+            owned_unix_socket,
+        })
+    }
+
+    #[cfg(feature = "extensions")]
+    fn resolved_extension_startup(&self) -> Result<(Vec, PostgresConfig)> {
+        let extensions = resolve_extension_set(&self.extensions)?;
+        let postgres_config =
+            postgres_config_with_extension_startup(self.postgres_config.clone(), &extensions)?;
+        Ok((extensions, postgres_config))
+    }
+}
+
+fn start_tcp(
+    proxy: OliphauntProxy,
+    addr: SocketAddr,
+    shutdown: Arc,
+    active_connection: Arc,
+) -> Result<(ServerEndpoint, JoinHandle>)> {
+    let listener = TcpListener::bind(addr).context("bind Oliphaunt TCP server")?;
+    let addr = {
+        listener
+            .local_addr()
+            .context("read Oliphaunt TCP address")?
+    };
+    let (ready_tx, ready_rx) = sync_channel(1);
+    let handle = thread::spawn(move || {
+        proxy.serve_tcp_listener_until_ready(listener, shutdown, active_connection, Some(ready_tx))
+    });
+    {
+        wait_until_ready(&ready_rx)?;
+    }
+    Ok((ServerEndpoint::Tcp(addr), handle))
+}
+
+fn tcp_connection_string(addr: SocketAddr, startup: &StartupConfig) -> String {
+    let username = percent_encode_uri_component(&startup.username);
+    let database = percent_encode_uri_component(&startup.database);
+    match addr {
+        SocketAddr::V4(addr) => {
+            format!(
+                "postgresql://{}@{}:{}/{}?sslmode=disable",
+                username,
+                addr.ip(),
+                addr.port(),
+                database
+            )
+        }
+        SocketAddr::V6(addr) => {
+            format!(
+                "postgresql://{}@[{}]:{}/{}?sslmode=disable",
+                username,
+                addr.ip(),
+                addr.port(),
+                database
+            )
+        }
+    }
+}
+
+#[cfg(unix)]
+fn unix_connection_string(endpoint: &UnixSocketEndpoint, startup: &StartupConfig) -> String {
+    let host = endpoint
+        .path
+        .parent()
+        .expect("resolved Unix socket path is absolute");
+    let host = host
+        .to_str()
+        .expect("resolved Unix socket directory was validated as UTF-8");
+    format!(
+        "postgresql:///{database}?host={host}&port={port}&user={user}&sslmode=disable",
+        database = percent_encode_uri_component(&startup.database),
+        host = percent_encode_uri_component(host),
+        port = endpoint.port,
+        user = percent_encode_uri_component(&startup.username),
+    )
+}
+
+#[cfg(unix)]
+fn start_unix(
+    proxy: OliphauntProxy,
+    endpoint: UnixSocketEndpoint,
+    shutdown: Arc,
+    active_connection: Arc,
+) -> Result<(ServerEndpoint, JoinHandle>, OwnedUnixSocket)> {
+    let path = endpoint.path.clone();
+    prepare_unix_socket_directory(&path)?;
+    ensure_unix_socket_path_available(&path)?;
+
+    let listener = {
+        UnixListener::bind(&path)
+            .with_context(|| format!("bind Oliphaunt Unix socket {}", path.display()))?
+    };
+    let mut owned_socket = match OwnedUnixSocket::capture(&path) {
+        Ok(socket) => socket,
+        Err(error) => {
+            cleanup_new_unix_socket(&path);
+            return Err(error);
+        }
+    };
+    let server_endpoint = ServerEndpoint::Unix(endpoint);
+    let (ready_tx, ready_rx) = sync_channel(1);
+    let worker_shutdown = shutdown.clone();
+    let handle = thread::spawn(move || {
+        proxy.serve_unix_listener_until_ready(
+            listener,
+            worker_shutdown,
+            active_connection,
+            Some(ready_tx),
+        )
+    });
+    let ready_result = { wait_until_ready(&ready_rx) };
+    if let Err(error) = ready_result {
+        shutdown.store(true, Ordering::SeqCst);
+        let _ = UnixStream::connect(&path);
+        let worker_result = handle
+            .join()
+            .map_err(|_| anyhow!("oliphaunt Unix server thread panicked during startup"))?;
+        owned_socket.cleanup()?;
+        worker_result?;
+        return Err(error);
+    }
+    Ok((server_endpoint, handle, owned_socket))
+}
+
+#[cfg(unix)]
+impl OwnedUnixSocket {
+    fn capture(path: &Path) -> Result {
+        let metadata = std::fs::symlink_metadata(path)
+            .with_context(|| format!("inspect bound Unix socket {}", path.display()))?;
+        if !metadata.file_type().is_socket() {
+            return Err(anyhow!(
+                "bound Unix endpoint {} is not a socket",
+                path.display()
+            ));
+        }
+        Ok(Self {
+            path: path.to_path_buf(),
+            identity: Some((metadata.dev(), metadata.ino())),
+        })
+    }
+
+    fn cleanup(&mut self) -> Result<()> {
+        let Some(expected) = self.identity else {
+            return Ok(());
+        };
+        let metadata = match std::fs::symlink_metadata(&self.path) {
+            Ok(metadata) => metadata,
+            Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
+                self.identity = None;
+                return Ok(());
+            }
+            Err(error) => {
+                return Err(error)
+                    .with_context(|| format!("inspect owned Unix socket {}", self.path.display()));
+            }
+        };
+        let actual = (metadata.dev(), metadata.ino());
+        if !metadata.file_type().is_socket() || actual != expected {
+            self.identity = None;
+            return Err(anyhow!(
+                "refusing to remove replaced Unix endpoint {}",
+                self.path.display()
+            ));
+        }
+        std::fs::remove_file(&self.path)
+            .with_context(|| format!("remove owned Unix socket {}", self.path.display()))?;
+        self.identity = None;
+        Ok(())
+    }
+}
+
+#[cfg(unix)]
+impl Drop for OwnedUnixSocket {
+    fn drop(&mut self) {
+        if let Err(error) = self.cleanup() {
+            tracing::warn!("Oliphaunt Unix socket cleanup during drop failed: {error:#}");
+        }
+    }
+}
+
+#[cfg(unix)]
+fn cleanup_new_unix_socket(path: &Path) {
+    match std::fs::remove_file(path) {
+        Ok(()) => {}
+        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
+        Err(error) => tracing::warn!(
+            "Oliphaunt Unix socket cleanup after startup failure failed for {}: {error:#}",
+            path.display()
+        ),
+    }
+}
+
+#[cfg(unix)]
+fn ensure_unix_socket_path_available(path: &Path) -> Result<()> {
+    let metadata = match std::fs::symlink_metadata(path) {
+        Ok(metadata) => metadata,
+        Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(()),
+        Err(error) => {
+            return Err(error).with_context(|| format!("inspect Unix socket {}", path.display()));
+        }
+    };
+    let kind = if metadata.file_type().is_socket() {
+        "socket"
+    } else {
+        "non-socket endpoint"
+    };
+    Err(anyhow!(
+        "refusing to replace existing Unix {kind} {}; remove it explicitly if it is stale",
+        path.display()
+    ))
+}
+
+#[cfg(unix)]
+fn prepare_unix_socket_directory(path: &Path) -> Result<()> {
+    let parent = path.parent().ok_or_else(|| {
+        crate::error::invalid_configuration(format!(
+            "Unix socket path has no parent: {}",
+            path.display()
+        ))
+    })?;
+    std::fs::create_dir_all(parent)
+        .with_context(|| format!("create socket directory {}", parent.display()))?;
+    let metadata = std::fs::symlink_metadata(parent)
+        .with_context(|| format!("inspect socket directory {}", parent.display()))?;
+    if metadata.file_type().is_symlink() || !metadata.is_dir() {
+        return Err(crate::error::invalid_configuration(format!(
+            "Unix socket directory must be a real directory, not a symlink: {}",
+            parent.display()
+        )));
+    }
+    if path.as_os_str().as_bytes().len() >= 100 {
+        return Err(crate::error::invalid_configuration(format!(
+            "Unix socket path is too long: {}",
+            path.display()
+        )));
+    }
+    Ok(())
+}
+
+fn wait_until_ready(ready_rx: &Receiver>) -> Result<()> {
+    ready_rx
+        .recv()
+        .context("Oliphaunt server thread exited before reporting readiness")?
+}
+
+fn wake_listener(endpoint: &ServerEndpoint) {
+    match endpoint {
+        ServerEndpoint::Tcp(addr) => {
+            let _ = TcpStream::connect(addr);
+        }
+        #[cfg(unix)]
+        ServerEndpoint::Unix(endpoint) => {
+            let _ = UnixStream::connect(&endpoint.path);
+        }
+    }
+}
+
+#[cfg(unix)]
+fn resolve_unix_socket_endpoint(directory: &Path, port: u16) -> Result {
+    let current_directory = if directory.is_absolute() {
+        None
+    } else {
+        Some(
+            std::env::current_dir()
+                .context("resolve current directory for Unix socket directory")?,
+        )
+    };
+    resolve_unix_socket_endpoint_at(directory, port, current_directory.as_deref())
+}
+
+#[cfg(unix)]
+fn resolve_unix_socket_endpoint_at(
+    directory: &Path,
+    port: u16,
+    current_directory: Option<&Path>,
+) -> Result {
+    if directory.as_os_str().is_empty() {
+        return Err(crate::error::invalid_configuration(
+            "Unix socket directory must not be empty",
+        ));
+    }
+    if directory.as_os_str().as_bytes().contains(&0) {
+        return Err(crate::error::invalid_configuration(
+            "Unix socket directory must not contain NUL bytes",
+        ));
+    }
+    if port == 0 {
+        return Err(crate::error::invalid_configuration(
+            "Unix socket port must be in the range 1..=65535",
+        ));
+    }
+    let directory = if directory.is_absolute() {
+        directory.to_path_buf()
+    } else {
+        current_directory
+            .expect("relative Unix socket directory resolution provides a current directory")
+            .join(directory)
+    };
+    if directory.to_str().is_none() {
+        return Err(crate::error::invalid_configuration(
+            "Unix socket directory must be valid UTF-8 so the published PostgreSQL connection string preserves the exact path",
+        ));
+    }
+    let path = directory.join(format!(".s.PGSQL.{port}"));
+    if path.as_os_str().as_bytes().len() >= 100 {
+        return Err(crate::error::invalid_configuration(format!(
+            "Unix socket path is too long: {}",
+            path.display()
+        )));
+    }
+    Ok(UnixSocketEndpoint { path, port })
+}
+
+fn percent_encode_uri_component(value: &str) -> String {
+    percent_encode_bytes(value.as_bytes())
+}
+
+fn percent_encode_bytes(value: &[u8]) -> String {
+    const HEX: &[u8; 16] = b"0123456789ABCDEF";
+    let mut encoded = String::with_capacity(value.len());
+    for &byte in value {
+        if matches!(
+            byte,
+            b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'.' | b'_' | b'~'
+        ) {
+            encoded.push(byte as char);
+        } else {
+            encoded.push('%');
+            encoded.push(HEX[usize::from(byte >> 4)] as char);
+            encoded.push(HEX[usize::from(byte & 0x0f)] as char);
+        }
+    }
+    encoded
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[cfg(feature = "extension-pg-textsearch")]
+    use oliphaunt_wasix::Extension;
+
+    #[cfg(feature = "icu")]
+    fn assert_server_profile(server: &OliphauntServer, expected: CatalogProfile) {
+        assert_eq!(server.catalog_profile, expected);
+        assert_eq!(
+            server.runtime_root.join("share/icu").is_dir(),
+            expected == CatalogProfile::Icu
+        );
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_socket_uri_host_is_query_encoded() {
+        assert_eq!(
+            percent_encode_bytes(b"/tmp/Application Support/oliphaunt"),
+            "%2Ftmp%2FApplication%20Support%2Foliphaunt"
+        );
+    }
+
+    #[test]
+    fn tcp_connection_string_encodes_username_and_database_components() {
+        let startup = StartupConfig {
+            username: "role@example:admin".to_string(),
+            database: "tenant/a?mode=#100%".to_string(),
+        };
+
+        assert_eq!(
+            tcp_connection_string(SocketAddr::from(([127, 0, 0, 1], 6543)), &startup),
+            "postgresql://role%40example%3Aadmin@127.0.0.1:6543/tenant%2Fa%3Fmode%3D%23100%25?sslmode=disable"
+        );
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_connection_string_encodes_every_caller_controlled_component() {
+        use std::str::FromStr;
+
+        let startup = StartupConfig {
+            username: "role name".to_string(),
+            database: "tenant/db#1".to_string(),
+        };
+
+        let endpoint =
+            resolve_unix_socket_endpoint(Path::new("/tmp/Application Support/db?slot"), 6543)
+                .unwrap();
+        let connection_string = unix_connection_string(&endpoint, &startup);
+        assert_eq!(
+            connection_string,
+            "postgresql:///tenant%2Fdb%231?host=%2Ftmp%2FApplication%20Support%2Fdb%3Fslot&port=6543&user=role%20name&sslmode=disable"
+        );
+
+        let options = tokio_postgres::Config::from_str(&connection_string)
+            .expect("the published URI must retain its exact PostgreSQL connection shape");
+        assert_eq!(
+            options.get_hosts(),
+            &[tokio_postgres::config::Host::Unix(PathBuf::from(
+                "/tmp/Application Support/db?slot"
+            ))]
+        );
+        assert_eq!(options.get_ports(), &[6543]);
+        assert_eq!(options.get_user(), Some("role name"));
+        assert_eq!(options.get_dbname(), Some("tenant/db#1"));
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_socket_endpoint_rejects_non_utf8_directory_without_mutation() {
+        use std::ffi::OsStr;
+        use std::os::unix::ffi::OsStrExt;
+
+        let temp = tempfile::TempDir::new().unwrap();
+        let directory = temp.path().join(OsStr::from_bytes(b"db-\xFF"));
+        assert!(!directory.exists());
+
+        let error = resolve_unix_socket_endpoint(&directory, 6543)
+            .expect_err("a String connection URI cannot preserve a non-UTF-8 socket path");
+
+        assert!(error.to_string().contains("must be valid UTF-8"));
+        assert!(!directory.exists());
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_socket_endpoint_rejects_zero_port() {
+        let error = resolve_unix_socket_endpoint(Path::new("/tmp"), 0).unwrap_err();
+        assert!(error.to_string().contains("range 1..=65535"));
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_socket_endpoint_rejects_too_long_path_without_mutation() {
+        let directory = std::env::temp_dir().join(format!(
+            "oliphaunt-wasix-socket-{}-{}",
+            std::process::id(),
+            "x".repeat(120)
+        ));
+        assert!(!directory.exists());
+
+        let error = resolve_unix_socket_endpoint(&directory, 6543).expect_err(
+            "Unix socket sockaddr length must be validated before database preparation",
+        );
+
+        assert!(error.to_string().contains("socket path is too long"));
+        assert!(!directory.exists());
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_socket_endpoint_resolves_relative_paths() -> Result<()> {
+        let current_directory = Path::new("/tmp/oliphaunt-relative-base");
+        let endpoint =
+            resolve_unix_socket_endpoint_at(Path::new("run"), 6543, Some(current_directory))?;
+        assert_eq!(endpoint.path, current_directory.join("run/.s.PGSQL.6543"));
+        assert_eq!(endpoint.port, 6543);
+        Ok(())
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_socket_preparation_rejects_regular_files_and_symlinks() -> Result<()> {
+        use std::os::unix::fs::symlink;
+
+        let temp = tempfile::TempDir::new()?;
+        let regular = temp.path().join("regular");
+        std::fs::write(®ular, b"keep")?;
+        let error = ensure_unix_socket_path_available(®ular).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("refusing to replace existing Unix non-socket")
+        );
+        assert_eq!(std::fs::read(®ular)?, b"keep");
+
+        let link = temp.path().join("link");
+        symlink(®ular, &link)?;
+        let error = ensure_unix_socket_path_available(&link).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("refusing to replace existing Unix non-socket")
+        );
+        assert!(link.symlink_metadata()?.file_type().is_symlink());
+        Ok(())
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_socket_preparation_rejects_active_and_stale_sockets() -> Result<()> {
+        let temp = tempfile::TempDir::new()?;
+        let socket = temp.path().join(".s.PGSQL.6543");
+        let listener = UnixListener::bind(&socket)?;
+
+        let error = ensure_unix_socket_path_available(&socket).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("refusing to replace existing Unix socket")
+        );
+        assert!(socket.exists());
+
+        drop(listener);
+        let error = ensure_unix_socket_path_available(&socket).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("remove it explicitly if it is stale")
+        );
+        assert!(socket.exists());
+        Ok(())
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_socket_cleanup_removes_only_the_owned_inode() -> Result<()> {
+        let temp = tempfile::TempDir::new()?;
+        let socket = temp.path().join(".s.PGSQL.6543");
+        let listener = UnixListener::bind(&socket)?;
+        let mut owned = OwnedUnixSocket::capture(&socket)?;
+
+        std::fs::remove_file(&socket)?;
+        std::fs::write(&socket, b"replacement")?;
+        let error = owned.cleanup().unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("refusing to remove replaced Unix endpoint")
+        );
+        assert_eq!(std::fs::read(&socket)?, b"replacement");
+        drop(listener);
+        Ok(())
+    }
+
+    #[test]
+    fn default_server_builder_selects_memory() {
+        let builder = OliphauntServerBuilder::default();
+        assert_eq!(builder.storage, DatabaseStorage::Memory);
+        assert_eq!(builder.catalog_profile, CatalogProfile::default());
+    }
+
+    #[cfg(feature = "icu")]
+    #[test]
+    #[ignore = "requires prepared standard and ICU WASIX runtime profiles"]
+    fn server_profiles_remain_isolated_in_both_construction_orders() -> Result<()> {
+        for profiles in [
+            [CatalogProfile::Standard, CatalogProfile::Icu],
+            [CatalogProfile::Icu, CatalogProfile::Standard],
+        ] {
+            let mut first = OliphauntServerBuilder::new()
+                .catalog_profile(profiles[0])
+                .start()
+                .map_err(|error| anyhow!(error.to_string()))?;
+            let mut second = OliphauntServerBuilder::new()
+                .catalog_profile(profiles[1])
+                .start()
+                .map_err(|error| anyhow!(error.to_string()))?;
+
+            assert_server_profile(&first, profiles[0]);
+            assert_server_profile(&second, profiles[1]);
+            assert_ne!(first.runtime_root, second.runtime_root);
+
+            second.close().map_err(|error| anyhow!(error.to_string()))?;
+            first.close().map_err(|error| anyhow!(error.to_string()))?;
+        }
+        Ok(())
+    }
+
+    #[cfg(feature = "icu")]
+    #[test]
+    #[ignore = "requires prepared standard and ICU WASIX runtime profiles"]
+    fn server_profiles_start_concurrently_without_contamination() -> Result<()> {
+        let barrier = Arc::new(std::sync::Barrier::new(2));
+        let start = |profile| {
+            let barrier = Arc::clone(&barrier);
+            std::thread::spawn(move || -> Result<(CatalogProfile, PathBuf, bool)> {
+                let mut server = OliphauntServerBuilder::new()
+                    .catalog_profile(profile)
+                    .start()
+                    .map_err(|error| anyhow!(error.to_string()))?;
+                barrier.wait();
+                let snapshot = (
+                    server.catalog_profile,
+                    server.runtime_root.clone(),
+                    server.runtime_root.join("share/icu").is_dir(),
+                );
+                server.close().map_err(|error| anyhow!(error.to_string()))?;
+                Ok(snapshot)
+            })
+        };
+        let standard = start(CatalogProfile::Standard);
+        let icu = start(CatalogProfile::Icu);
+        let standard = standard
+            .join()
+            .map_err(|_| anyhow!("standard server startup panicked"))??;
+        let icu = icu
+            .join()
+            .map_err(|_| anyhow!("ICU server startup panicked"))??;
+
+        assert_eq!(standard.0, CatalogProfile::Standard);
+        assert!(!standard.2);
+        assert_eq!(icu.0, CatalogProfile::Icu);
+        assert!(icu.2);
+        assert_ne!(standard.1, icu.1);
+        Ok(())
+    }
+
+    #[test]
+    fn direct_server_close_keeps_observable_terminal_state_and_replays_failure() {
+        let mut server =
+            server_with_worker_result_for_test(Err(anyhow!("injected server stop failure")), None);
+        assert!(!server.is_closed());
+
+        let first = server.close().unwrap_err().to_string();
+        assert!(server.is_closed());
+        let second = server.close().unwrap_err().to_string();
+
+        assert_eq!(first, second);
+        assert!(first.contains("injected server stop failure"));
+    }
+
+    #[test]
+    fn explicit_zero_tcp_port_is_rejected_before_runtime_work() {
+        let error = OliphauntServer::builder()
+            .listen(ServerListen::tcp_port(0))
+            .start()
+            .unwrap_err();
+        assert_eq!(error.kind(), crate::ErrorKind::InvalidConfiguration);
+        assert!(error.to_string().contains("omit it to allocate one"));
+    }
+
+    #[cfg(feature = "extension-pg-textsearch")]
+    #[test]
+    fn server_path_merges_pg_textsearch_preload_once_before_start() {
+        let builder = OliphauntServerBuilder::new()
+            .startup_guc("shared_preload_libraries", "auto_explain,pg_textsearch")
+            .extensions([Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH]);
+
+        let (_, postgres_config) = builder.resolved_extension_startup().unwrap();
+
+        assert_eq!(
+            postgres_config.get("shared_preload_libraries"),
+            Some("auto_explain,pg_textsearch")
+        );
+        assert_eq!(
+            postgres_config
+                .get("shared_preload_libraries")
+                .unwrap()
+                .split(',')
+                .filter(|library| *library == "pg_textsearch")
+                .count(),
+            1
+        );
+    }
+}
diff --git a/src/pgwire-server/tests/cli_smoke.rs b/src/pgwire-server/tests/cli_smoke.rs
new file mode 100644
index 000000000..85b737923
--- /dev/null
+++ b/src/pgwire-server/tests/cli_smoke.rs
@@ -0,0 +1,94 @@
+#![cfg(feature = "wasix")]
+
+use anyhow::{Context, Result};
+use oliphaunt_wasix::Oliphaunt;
+use sqlx::{Connection, Row};
+use std::io::{BufRead, BufReader};
+use std::process::{Command, Stdio};
+use tokio::time::{Duration, timeout};
+
+mod support;
+use support::{ChildGuard, TestTrace, trace_step};
+
+fn direct_open_diagnostic() -> String {
+    match Oliphaunt::builder().open() {
+        Ok(mut pg) => match pg.close() {
+            Ok(()) => "direct memory Oliphaunt open succeeded".to_owned(),
+            Err(err) => format!("direct memory Oliphaunt open succeeded, close failed: {err:#}"),
+        },
+        Err(err) => format!("direct memory Oliphaunt open failed: {err:#}"),
+    }
+}
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+#[ignore = "requires prepared WASIX runtime"]
+async fn oliphaunt_proxy_print_uri_accepts_sqlx_connection() -> Result<()> {
+    let _trace = TestTrace::new("oliphaunt_proxy_print_uri_accepts_sqlx_connection");
+    let executable = std::env::var_os("OLIPHAUNT_PGWIRE_SERVER_BINARY")
+        .unwrap_or_else(|| env!("CARGO_BIN_EXE_oliphaunt-pgwire-server").into());
+    let process = Command::new(executable)
+        .args(["--memory", "--print-uri"])
+        .stdout(Stdio::piped())
+        .stderr(Stdio::piped())
+        .spawn()
+        .context("spawn oliphaunt-pgwire-server")?;
+    let mut child = ChildGuard::new(process, "oliphaunt-pgwire-server")?;
+
+    let stdout = child
+        .child_mut()
+        .stdout
+        .take()
+        .context("oliphaunt-pgwire-server stdout pipe")?;
+    let read_uri = tokio::task::spawn_blocking(move || {
+        let mut reader = BufReader::new(stdout);
+        let mut uri = String::new();
+        let bytes = reader
+            .read_line(&mut uri)
+            .context("read oliphaunt-pgwire-server printed URI")?;
+        Ok::<_, anyhow::Error>((bytes, uri))
+    });
+    let (bytes, uri) = match timeout(Duration::from_secs(30), read_uri).await {
+        Ok(Ok(Ok(result))) => result,
+        Ok(Ok(Err(err))) => return Err(err),
+        Ok(Err(err)) => return Err(err).context("join URI reader task"),
+        Err(err) => {
+            let stderr = child.collect_stderr();
+            anyhow::bail!(
+                "timed out waiting for oliphaunt-pgwire-server URI: {err}\n\nstderr:\n{stderr}"
+            );
+        }
+    };
+    if bytes == 0 {
+        let stderr = child.collect_stderr();
+        anyhow::bail!("oliphaunt-pgwire-server exited before printing URI\n\nstderr:\n{stderr}");
+    }
+    let uri = uri.trim();
+    assert!(uri.starts_with("postgresql://"), "unexpected URI: {uri}");
+    trace_step("oliphaunt_proxy printed URI");
+
+    let mut conn = match timeout(Duration::from_secs(30), sqlx::PgConnection::connect(uri)).await {
+        Ok(Ok(conn)) => conn,
+        Ok(Err(err)) => {
+            let stderr = child.collect_stderr();
+            let direct = direct_open_diagnostic();
+            anyhow::bail!(
+                "connect to oliphaunt-pgwire-server failed: {err:#}\n\nstderr:\n{stderr}\n\ndirect backend diagnostic:\n{direct}"
+            );
+        }
+        Err(err) => {
+            let stderr = child.collect_stderr();
+            let direct = direct_open_diagnostic();
+            anyhow::bail!(
+                "timed out connecting to oliphaunt-pgwire-server: {err}\n\nstderr:\n{stderr}\n\ndirect backend diagnostic:\n{direct}"
+            );
+        }
+    };
+    let row = sqlx::query("SELECT $1::int4 + 1 AS answer")
+        .bind(41_i32)
+        .fetch_one(&mut conn)
+        .await?;
+    assert_eq!(row.try_get::("answer")?, 42);
+
+    conn.close().await?;
+    Ok(())
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/client_compat.rs b/src/pgwire-server/tests/client_compat.rs
similarity index 87%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/client_compat.rs
rename to src/pgwire-server/tests/client_compat.rs
index b06f51790..f64349e23 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/client_compat.rs
+++ b/src/pgwire-server/tests/client_compat.rs
@@ -1,11 +1,12 @@
-#![cfg(feature = "extensions")]
+#![cfg(feature = "wasix")]
 
 use anyhow::{Context, Result};
-use oliphaunt_wasix::{AsyncOliphauntServer, OliphauntServer as DirectOliphauntServer};
+use oliphaunt_pgwire_server::AsyncOliphauntServer;
 use sqlx::{Connection, Row};
 use tokio_postgres::NoTls;
 
 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+#[ignore = "requires prepared WASIX runtime"]
 async fn tokio_postgres_parameters_and_error_recovery_work() -> Result<()> {
     let server = AsyncOliphauntServer::builder().start().await?;
     let (client, connection) = tokio_postgres::connect(server.connection_string(), NoTls)
@@ -40,12 +41,14 @@ async fn tokio_postgres_parameters_and_error_recovery_work() -> Result<()> {
 }
 
 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+#[ignore = "requires prepared WASIX runtime"]
 async fn sqlx_uses_the_standard_postgres_connection_string() -> Result<()> {
-    let mut server = DirectOliphauntServer::builder()
+    let server = AsyncOliphauntServer::builder()
         .username("postgres")
         .database("postgres")
         .startup_guc("work_mem", "8MB")
-        .start()?;
+        .start()
+        .await?;
     let connection_string = server.connection_string();
     let mut connection = sqlx::PgConnection::connect(connection_string).await?;
     let row = sqlx::query("SELECT current_setting('work_mem') AS work_mem, $1::text AS value")
@@ -55,6 +58,6 @@ async fn sqlx_uses_the_standard_postgres_connection_string() -> Result<()> {
     assert_eq!(row.try_get::<&str, _>("work_mem")?, "8MB");
     assert_eq!(row.try_get::<&str, _>("value")?, "ok");
     connection.close().await?;
-    server.close()?;
+    server.close().await?;
     Ok(())
 }
diff --git a/src/pgwire-server/tests/extensions.rs b/src/pgwire-server/tests/extensions.rs
new file mode 100644
index 000000000..cdc28e7ff
--- /dev/null
+++ b/src/pgwire-server/tests/extensions.rs
@@ -0,0 +1,180 @@
+#![cfg(feature = "extensions")]
+use anyhow::{Context, Result, ensure};
+use oliphaunt_pgwire_server::AsyncOliphauntServer;
+use oliphaunt_wasix::Extension;
+use sqlx::Connection;
+#[cfg(feature = "extension-vector")]
+use sqlx::Row;
+use std::path::Path;
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+#[ignore = "requires prepared WASIX runtime and every catalogued extension"]
+async fn public_extensions_pass_server_smoke() -> Result<()> {
+    let root = Path::new(env!("CARGO_MANIFEST_DIR"))
+        .parent()
+        .unwrap()
+        .parent()
+        .unwrap();
+    let catalog: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(
+        root.join("src/extensions/catalog/extensions.source.json"),
+    )?)?;
+    let rows = catalog["extensions"]
+        .as_array()
+        .context("extension catalog rows")?;
+    ensure!(
+        Extension::ALL.len() == rows.len(),
+        "enable every catalogued extension for server evidence"
+    );
+    for extension in Extension::ALL {
+        let name = extension.sql_name();
+        eprintln!("server extension smoke: {name}");
+        let server = AsyncOliphauntServer::builder()
+            .extension(*extension)
+            .start()
+            .await
+            .with_context(|| format!("start server with extension {name}"))?;
+        let mut connection = sqlx::PgConnection::connect(server.connection_string()).await?;
+        let installed: i64 =
+            sqlx::query_scalar("SELECT count(*)::int8 FROM pg_extension WHERE extname = $1")
+                .bind(name)
+                .fetch_one(&mut connection)
+                .await?;
+        ensure!(
+            installed == 0,
+            "selecting server extension {name} must not install it"
+        );
+        let mut activation = Vec::new();
+        extension_activation(rows, name, &mut activation)?;
+        for statement in activation {
+            sqlx::raw_sql(&statement)
+                .execute(&mut connection)
+                .await
+                .with_context(|| format!("activate server extension {name}: {statement}"))?;
+        }
+        let recipe =
+            std::fs::read_to_string(root.join(format!("src/test-fixtures/extensions/{name}.sql")))?;
+        for statement in recipe
+            .split("-- oliphaunt-statement")
+            .map(str::trim)
+            .filter(|sql| !sql.is_empty())
+        {
+            sqlx::raw_sql(statement)
+                .fetch_all(&mut connection)
+                .await
+                .with_context(|| format!("server extension {name}: {statement}"))?;
+        }
+        connection.close().await?;
+        server.close().await?;
+        if let Some(evidence) = std::env::var_os("OLIPHAUNT_EXTENSION_EVIDENCE_DIR") {
+            std::fs::write(
+                Path::new(&evidence).join(format!("{name}.server")),
+                "passed\n",
+            )?;
+        }
+    }
+    Ok(())
+}
+
+fn extension_activation(
+    rows: &[serde_json::Value],
+    name: &str,
+    sql: &mut Vec,
+) -> Result<()> {
+    let row = rows
+        .iter()
+        .find(|row| row["sql-name"] == name)
+        .context("catalogued extension")?;
+    for dependency in row["dependencies"]
+        .as_array()
+        .context("extension dependencies")?
+    {
+        let dependency = dependency.as_str().context("extension dependency name")?;
+        if dependency != "plpgsql" {
+            extension_activation(rows, dependency, sql)?;
+        }
+    }
+    let lifecycle = &row["lifecycle"];
+    let quote = |name: &str| format!("\"{}\"", name.replace('"', "\"\""));
+    if lifecycle["create-extension"] == true {
+        let schema = lifecycle["create-schema"]
+            .as_str()
+            .filter(|schema| !schema.is_empty());
+        if let Some(schema) = schema.filter(|schema| *schema != "pg_catalog") {
+            sql.push(format!("CREATE SCHEMA IF NOT EXISTS {}", quote(schema)));
+        }
+        sql.push(format!(
+            "CREATE EXTENSION IF NOT EXISTS {}{}",
+            quote(name),
+            schema
+                .map(|schema| format!(" WITH SCHEMA {}", quote(schema)))
+                .unwrap_or_default()
+        ));
+    }
+    for key in ["load-sql", "post-create-sql"] {
+        for statement in lifecycle[key]
+            .as_array()
+            .context("extension activation SQL")?
+        {
+            sql.push(
+                statement
+                    .as_str()
+                    .context("activation SQL string")?
+                    .to_owned(),
+            );
+        }
+    }
+    Ok(())
+}
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+#[ignore = "requires prepared WASIX runtime and vector extension"]
+#[cfg(feature = "extension-vector")]
+async fn vector_extension_works_through_server() -> Result<()> {
+    let server = AsyncOliphauntServer::builder()
+        .extension(Extension::VECTOR)
+        .start()
+        .await?;
+    let mut connection = sqlx::PgConnection::connect(server.connection_string()).await?;
+    let installed: i64 =
+        sqlx::query_scalar("SELECT count(*)::int8 FROM pg_extension WHERE extname = 'vector'")
+            .fetch_one(&mut connection)
+            .await?;
+    assert_eq!(installed, 0);
+    sqlx::query("CREATE EXTENSION vector")
+        .execute(&mut connection)
+        .await?;
+    let row = sqlx::query("SELECT '[1,2,3]'::vector <-> '[1,2,4]'::vector AS distance")
+        .fetch_one(&mut connection)
+        .await?;
+    assert_eq!(row.try_get::("distance")?, 1.0);
+    connection.close().await?;
+    server.close().await?;
+    Ok(())
+}
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+#[ignore = "requires prepared WASIX AOT runtime and uuid-ossp extension"]
+#[cfg(feature = "extension-uuid-ossp")]
+async fn uuid_ossp_aot_server_smoke() -> Result<()> {
+    let server = AsyncOliphauntServer::builder()
+        .extension(Extension::UUID_OSSP)
+        .start()
+        .await?;
+    let mut connection = sqlx::PgConnection::connect(server.connection_string()).await?;
+    let installed: i64 =
+        sqlx::query_scalar("SELECT count(*)::int8 FROM pg_extension WHERE extname = 'uuid-ossp'")
+            .fetch_one(&mut connection)
+            .await?;
+    assert_eq!(installed, 0);
+    sqlx::query("CREATE EXTENSION \"uuid-ossp\"")
+        .execute(&mut connection)
+        .await?;
+    let generated: String = sqlx::query_scalar("SELECT uuid_generate_v4()::text")
+        .fetch_one(&mut connection)
+        .await?;
+    assert_eq!(generated.len(), 36);
+    assert_eq!(&generated[14..15], "4");
+    connection.close().await?;
+    server.close().await?;
+    Ok(())
+}
diff --git a/src/pgwire-server/tests/lifecycle.rs b/src/pgwire-server/tests/lifecycle.rs
new file mode 100644
index 000000000..a62f80ebb
--- /dev/null
+++ b/src/pgwire-server/tests/lifecycle.rs
@@ -0,0 +1,43 @@
+#![cfg(feature = "wasix")]
+use anyhow::Result;
+use oliphaunt_pgwire_server::{AsyncOliphauntServer, DatabaseStorage, OliphauntServer};
+use oliphaunt_wasix::Oliphaunt;
+
+#[test]
+#[ignore = "requires prepared WASIX runtime"]
+fn direct_server_close_releases_directory_ownership_before_returning() -> Result<()> {
+    let workspace = tempfile::tempdir()?;
+    let root = workspace.path().join("server-root");
+    let mut server = OliphauntServer::builder()
+        .storage(DatabaseStorage::Directory(root.clone()))
+        .start()?;
+    server.close()?;
+    let mut database = Oliphaunt::builder()
+        .storage(DatabaseStorage::Directory(root))
+        .open()?;
+    database.close()?;
+    assert!(server.is_closed());
+    Ok(())
+}
+
+#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+#[ignore = "requires prepared WASIX runtime"]
+async fn async_server_close_releases_directory_ownership_before_completion() -> Result<()> {
+    let workspace = tempfile::tempdir()?;
+    let root = workspace.path().join("async-server-root");
+    let server = AsyncOliphauntServer::builder()
+        .storage(DatabaseStorage::Directory(root.clone()))
+        .start()
+        .await?;
+    server.close().await?;
+    tokio::task::spawn_blocking(move || -> Result<()> {
+        let mut database = Oliphaunt::builder()
+            .storage(DatabaseStorage::Directory(root))
+            .open()?;
+        database.close()?;
+        Ok(())
+    })
+    .await??;
+    assert!(server.is_closed());
+    Ok(())
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/proxy_smoke.rs b/src/pgwire-server/tests/proxy_smoke.rs
similarity index 89%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/proxy_smoke.rs
rename to src/pgwire-server/tests/proxy_smoke.rs
index dfda1fe88..0eae820c7 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/proxy_smoke.rs
+++ b/src/pgwire-server/tests/proxy_smoke.rs
@@ -1,7 +1,7 @@
-#![cfg(feature = "extensions")]
+#![cfg(feature = "wasix")]
 
 use anyhow::{Context, Result, bail, ensure};
-use oliphaunt_wasix::{OliphauntServer, ServerListen};
+use oliphaunt_pgwire_server::{OliphauntServer, ServerListen};
 use std::io::{Read, Write};
 use std::net::{SocketAddr, TcpStream};
 #[cfg(unix)]
@@ -30,6 +30,7 @@ fn tcp_addr(server: &OliphauntServer) -> Result {
 }
 
 #[test]
+#[ignore = "requires prepared WASIX runtime"]
 fn tcp_proxy_handles_psql_style_and_fragmented_connections() -> Result<()> {
     let mut server = OliphauntServer::builder().start()?;
     assert!(!server.is_closed());
@@ -51,6 +52,7 @@ fn tcp_proxy_handles_psql_style_and_fragmented_connections() -> Result<()> {
 }
 
 #[test]
+#[ignore = "requires prepared WASIX runtime"]
 fn tcp_proxy_survives_a_malformed_client() -> Result<()> {
     let mut server = OliphauntServer::builder().start()?;
     let addr = tcp_addr(&server)?;
@@ -80,6 +82,7 @@ fn tcp_proxy_survives_a_malformed_client() -> Result<()> {
 }
 
 #[test]
+#[ignore = "requires prepared WASIX runtime"]
 fn tcp_proxy_contains_each_startup_and_control_failure() -> Result<()> {
     let mut server = OliphauntServer::builder().start()?;
     let addr = tcp_addr(&server)?;
@@ -126,6 +129,7 @@ fn tcp_proxy_contains_each_startup_and_control_failure() -> Result<()> {
 }
 
 #[test]
+#[ignore = "requires prepared WASIX runtime"]
 fn tcp_proxy_accepts_a_fragmented_message_larger_than_64_kib() -> Result<()> {
     let mut server = OliphauntServer::builder().start()?;
     let addr = tcp_addr(&server)?;
@@ -143,26 +147,41 @@ fn tcp_proxy_accepts_a_fragmented_message_larger_than_64_kib() -> Result<()> {
 }
 
 #[test]
+#[ignore = "requires prepared WASIX runtime"]
 fn tcp_server_close_interrupts_an_active_client() -> Result<()> {
-    let mut server = OliphauntServer::builder().start()?;
-    let addr = tcp_addr(&server)?;
-    let mut client = TcpStream::connect(addr)?;
-    client.set_read_timeout(Some(Duration::from_secs(30)))?;
-    client.write_all(&startup_message())?;
-    read_until_ready(&mut client)?;
-
-    let (closed_tx, closed_rx) = std::sync::mpsc::sync_channel(1);
-    thread::spawn(move || {
-        let _ = closed_tx.send(server.close());
-    });
-    closed_rx
-        .recv_timeout(Duration::from_secs(10))
-        .map_err(|_| anyhow::anyhow!("server close remained blocked on its active client"))??;
+    for stage in ["before startup", "after startup", "COPY input"] {
+        let mut server = OliphauntServer::builder().start()?;
+        let addr = tcp_addr(&server)?;
+        let mut client = TcpStream::connect(addr)?;
+        client.set_read_timeout(Some(Duration::from_secs(30)))?;
+        if stage != "before startup" {
+            client.write_all(&startup_message())?;
+            read_until_ready(&mut client)?;
+        }
+        if stage == "COPY input" {
+            client.write_all(&simple_query_message(
+                "CREATE TEMP TABLE shutdown_copy(value integer)",
+            ))?;
+            read_query_values(&mut client)?;
+            client.write_all(&simple_query_message("COPY shutdown_copy FROM STDIN"))?;
+            let (tag, _) = read_backend_message(&mut client)?;
+            ensure!(tag == b'G', "expected CopyInResponse before shutdown");
+        }
+
+        let (closed_tx, closed_rx) = std::sync::mpsc::sync_channel(1);
+        thread::spawn(move || {
+            let _ = closed_tx.send(server.close());
+        });
+        closed_rx
+            .recv_timeout(Duration::from_secs(10))
+            .map_err(|_| anyhow::anyhow!("server close blocked on active client: {stage}"))??;
+    }
     Ok(())
 }
 
 #[cfg(unix)]
 #[test]
+#[ignore = "requires prepared WASIX runtime"]
 fn unix_proxy_survives_a_malformed_client() -> Result<()> {
     let directory = tempfile::tempdir()?;
     let socket = directory.path().join(".s.PGSQL.5432");
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/support/mod.rs b/src/pgwire-server/tests/support/mod.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/support/mod.rs
rename to src/pgwire-server/tests/support/mod.rs
diff --git a/src/pgwire-server/tests/validation.rs b/src/pgwire-server/tests/validation.rs
new file mode 100644
index 000000000..ec9dfba50
--- /dev/null
+++ b/src/pgwire-server/tests/validation.rs
@@ -0,0 +1,149 @@
+#![cfg(feature = "wasix")]
+#[cfg(unix)]
+use oliphaunt_pgwire_server::ServerListen;
+use oliphaunt_pgwire_server::{
+    AsyncOliphauntServer, DatabaseStorage, Error, ErrorKind, OliphauntServer, Result,
+};
+use std::path::PathBuf;
+#[cfg(unix)]
+fn non_utf8_unix_socket_directory() -> PathBuf {
+    use std::ffi::OsString;
+    use std::os::unix::ffi::OsStringExt;
+
+    let mut leaf = format!("oliphaunt-wasix-socket-{}-", std::process::id()).into_bytes();
+    leaf.push(0xff);
+    std::env::temp_dir().join(OsString::from_vec(leaf))
+}
+
+fn assert_invalid_startup_identity(error: Error, name: &str) {
+    assert_invalid_configuration(error, &format!("{name} must not be empty"));
+}
+
+fn assert_invalid_configuration(error: Error, expected_message: &str) {
+    assert_eq!(error.kind(), ErrorKind::InvalidConfiguration);
+    assert_eq!(error.to_string(), expected_message);
+}
+
+fn expect_sdk_error(result: Result, message: &str) -> Error {
+    match result {
+        Ok(_) => panic!("{message}"),
+        Err(error) => error,
+    }
+}
+
+#[test]
+fn direct_builders_reject_empty_startup_identities_before_runtime_work() {
+    for value in ["", " \t\n"] {
+        let error = expect_sdk_error(
+            OliphauntServer::builder().username(value).start(),
+            "empty server username must fail before runtime setup",
+        );
+        assert_invalid_startup_identity(error, "username");
+
+        let error = expect_sdk_error(
+            OliphauntServer::builder().database(value).start(),
+            "empty server database must fail before runtime setup",
+        );
+        assert_invalid_startup_identity(error, "database");
+    }
+}
+
+#[tokio::test]
+async fn async_builders_preserve_startup_identity_validation() {
+    let error = expect_sdk_error(
+        AsyncOliphauntServer::builder().database("").start().await,
+        "async server must preserve direct database validation",
+    );
+    assert_invalid_startup_identity(error, "database");
+}
+
+#[test]
+fn sync_builders_reject_invalid_host_paths_before_filesystem_work() {
+    for (path, reason) in [
+        (PathBuf::new(), "must not be empty"),
+        (PathBuf::from("invalid\0path"), "must not contain NUL bytes"),
+    ] {
+        let error = expect_sdk_error(
+            OliphauntServer::builder()
+                .storage(DatabaseStorage::Directory(path.clone()))
+                .start(),
+            "invalid server storage path must fail before runtime setup",
+        );
+        assert_invalid_configuration(error, &format!("database storage directory {reason}"));
+
+        #[cfg(unix)]
+        {
+            let error = expect_sdk_error(
+                OliphauntServer::builder()
+                    .listen(ServerListen::unix(path))
+                    .start(),
+                "invalid Unix listener path must fail before runtime setup",
+            );
+            assert_invalid_configuration(error, &format!("Unix socket directory {reason}"));
+        }
+    }
+
+    #[cfg(unix)]
+    {
+        let path = non_utf8_unix_socket_directory();
+        assert!(!path.exists());
+        let error = expect_sdk_error(
+            OliphauntServer::builder()
+                .listen(ServerListen::unix(path.clone()))
+                .start(),
+            "non-UTF-8 Unix listener path must fail before runtime setup",
+        );
+        assert_invalid_configuration(
+            error,
+            "Unix socket directory must be valid UTF-8 so the published PostgreSQL connection string preserves the exact path",
+        );
+        assert!(!path.exists());
+    }
+}
+
+#[tokio::test]
+async fn async_builders_preserve_host_path_validation() {
+    for (path, reason) in [
+        (PathBuf::new(), "must not be empty"),
+        (PathBuf::from("invalid\0path"), "must not contain NUL bytes"),
+    ] {
+        let error = expect_sdk_error(
+            AsyncOliphauntServer::builder()
+                .storage(DatabaseStorage::Directory(path.clone()))
+                .start()
+                .await,
+            "async server must preserve storage path validation",
+        );
+        assert_invalid_configuration(error, &format!("database storage directory {reason}"));
+
+        #[cfg(unix)]
+        {
+            let error = expect_sdk_error(
+                AsyncOliphauntServer::builder()
+                    .listen(ServerListen::unix(path))
+                    .start()
+                    .await,
+                "async server must preserve Unix listener path validation",
+            );
+            assert_invalid_configuration(error, &format!("Unix socket directory {reason}"));
+        }
+    }
+
+    #[cfg(unix)]
+    {
+        let path = non_utf8_unix_socket_directory();
+        assert!(!path.exists());
+        let error = expect_sdk_error(
+            AsyncOliphauntServer::builder()
+                .listen(ServerListen::unix(path.clone()))
+                .start()
+                .await,
+            "async non-UTF-8 Unix listener path must fail before runtime setup",
+        );
+        assert_invalid_configuration(
+            error,
+            "Unix socket directory must be valid UTF-8 so the published PostgreSQL connection string preserves the exact path",
+        );
+        assert!(!path.exists());
+    }
+}
diff --git a/src/pgwire-server/tools/package.sh b/src/pgwire-server/tools/package.sh
new file mode 100644
index 000000000..54f9f0fad
--- /dev/null
+++ b/src/pgwire-server/tools/package.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+artifact_root="$PWD/target/sdk-artifacts/oliphaunt-pgwire-server"
+rm -rf "$artifact_root"
+mkdir -p "$artifact_root"
+crate=$(OLIPHAUNT_CARGO_NOTICE_PROFILE=source-sdk bash tools/packaging/package-cargo-source.sh src/pgwire-server/Cargo.toml "$PWD/target/sdk-artifacts-work/oliphaunt-pgwire-server")
+prefix=$(basename "$crate" .crate)
+bun tools/packaging/release-notices.mts check-archive "$crate" --profile source-sdk --prefix "$prefix"
+cp "$crate" "$artifact_root/"
+bun tools/packaging/staging.mts "$artifact_root"
diff --git a/src/pgwire-server/tools/test-aot.sh b/src/pgwire-server/tools/test-aot.sh
new file mode 100644
index 000000000..c192fb77a
--- /dev/null
+++ b/src/pgwire-server/tools/test-aot.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+host="$(rustc -vV | awk '/^host:/{print $2}')"
+target="${AOT_TARGET:-$host}"
+if [ "$host" != "$target" ]; then
+  echo "AOT server execution requires host $host to match target $target" >&2
+  exit 1
+fi
+proof_root="$PWD/target/pgwire-server-aot-smoke"
+OLIPHAUNT_WASIX_GENERATED_ASSET_ROOT="$PWD/target/extensions/wasix/assets" \
+OLIPHAUNT_WASIX_EXTENSION_AOT_ARTIFACT_ROOT="$PWD/target/extensions/wasix/aot-artifacts" \
+  bash tools/dev/bun.sh src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts \
+    --output-root "$proof_root/extension-artifacts" --family wasix --require-wasix \
+    oliphaunt-extension-contrib-pg18
+OLIPHAUNT_WASM_AOT_VERIFY=full \
+OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="$proof_root/extension-artifacts" \
+  cargo test -p oliphaunt-pgwire-server --locked --features extension-uuid-ossp \
+    --test extensions uuid_ossp_aot_server_smoke -- --ignored --exact --nocapture
diff --git a/src/postgres-tools/native/CHANGELOG.md b/src/postgres-tools/native/CHANGELOG.md
new file mode 100644
index 000000000..c60f12b1d
--- /dev/null
+++ b/src/postgres-tools/native/CHANGELOG.md
@@ -0,0 +1,3 @@
+# Changelog
+
+This product carries forward the PostgreSQL utility packages previously released with liboliphaunt-native. Existing published versions remain in their original release history.
diff --git a/src/postgres-tools/native/README.md b/src/postgres-tools/native/README.md
new file mode 100644
index 000000000..914d7e5d7
--- /dev/null
+++ b/src/postgres-tools/native/README.md
@@ -0,0 +1,18 @@
+# Native PostgreSQL tools
+
+This product owns the `oliphaunt-tools` Rust facade, `@oliphaunt/tools` npm facade, and their platform-specific tool carriers. Its versions are independent of the native database runtime.
+
+`moon run postgres-tools-native:test` runs Rust tools source tests, including the shared argument contract. `moon run postgres-tools-native:build` builds both Rust and npm facades without compiling PostgreSQL. `moon run postgres-tools-native:package-assets` builds the native PostgreSQL prerequisite and assembles the current platform's executables and their own shared libraries; `test-assets` checks that archive's platform compatibility. Native Windows and macOS producers require those hosts and their compiler toolchains.
+
+The separate Rust integration proof starts native SDK servers and uses the public Rust `psql` and `pg_dump` APIs to seed, dump, restore and verify a database. It is ignored by ordinary Cargo test runs because it requires prepared runtime and extension resources. Invoke it explicitly from this directory:
+
+```sh
+export LIBOLIPHAUNT_PATH=/absolute/path/to/liboliphaunt.so
+export OLIPHAUNT_INSTALL_DIR=/absolute/path/to/native-runtime
+export OLIPHAUNT_TOOLS_DIR=/absolute/path/to/tools/runtime
+export OLIPHAUNT_RESOURCES_DIR=/absolute/path/to/prepared-sdk-resources
+export OLIPHAUNT_ICU_DATA_DIR=/absolute/path/to/verified-icu-data
+cargo test -p oliphaunt-native-tools-proof --locked --lib -- --ignored native_server_pg_dump_psql_round_trip
+```
+
+Use the host's library suffix. The native install must contain the server/initdb programs and their supporting files. The SDK resources must include the packaged `pgtap` extension and native runtime resources; ICU must match that runtime. Missing resources fail the explicit test through the actual SDK/resource loaders. There is no best-effort availability probe. The proof manages and removes its temporary database directories.
diff --git a/src/postgres-tools/native/VERSION b/src/postgres-tools/native/VERSION
new file mode 100644
index 000000000..0c62199f1
--- /dev/null
+++ b/src/postgres-tools/native/VERSION
@@ -0,0 +1 @@
+0.2.1
diff --git a/src/postgres-tools/native/crates/tools/Cargo.toml b/src/postgres-tools/native/crates/tools/Cargo.toml
new file mode 100644
index 000000000..049469f72
--- /dev/null
+++ b/src/postgres-tools/native/crates/tools/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "oliphaunt-tools"
+version = "0.2.1"
+edition = "2024"
+rust-version = "1.93"
+description = "Target-selecting Cargo facade for Oliphaunt native PostgreSQL client tool artifacts."
+readme = "README.md"
+repository.workspace = true
+homepage.workspace = true
+license = "MIT"
+links = "oliphaunt_artifact_oliphaunt_tools_relay"
+build = "build.rs"
+include = [
+  "Cargo.toml",
+  "README.md",
+  "build.rs",
+  "build_support.rs",
+  "src/**",
+  "testdata/**",
+  "LICENSE",
+  "THIRD_PARTY_NOTICES.md",
+]
+
+[lib]
+path = "src/lib.rs"
+
+[dev-dependencies]
+serde_json = "1"
diff --git a/src/runtimes/liboliphaunt/native/crates/tools/README.md b/src/postgres-tools/native/crates/tools/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/crates/tools/README.md
rename to src/postgres-tools/native/crates/tools/README.md
diff --git a/src/runtimes/liboliphaunt/native/crates/tools/build.rs b/src/postgres-tools/native/crates/tools/build.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/native/crates/tools/build.rs
rename to src/postgres-tools/native/crates/tools/build.rs
diff --git a/src/runtimes/liboliphaunt/native/crates/tools/build_support.rs b/src/postgres-tools/native/crates/tools/build_support.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/native/crates/tools/build_support.rs
rename to src/postgres-tools/native/crates/tools/build_support.rs
diff --git a/src/runtimes/liboliphaunt/native/crates/tools/src/arguments.rs b/src/postgres-tools/native/crates/tools/src/arguments.rs
similarity index 77%
rename from src/runtimes/liboliphaunt/native/crates/tools/src/arguments.rs
rename to src/postgres-tools/native/crates/tools/src/arguments.rs
index d18c0a0bd..95e560d5d 100644
--- a/src/runtimes/liboliphaunt/native/crates/tools/src/arguments.rs
+++ b/src/postgres-tools/native/crates/tools/src/arguments.rs
@@ -210,3 +210,52 @@ fn disallowed_flag(
     }
     None
 }
+
+#[cfg(test)]
+mod tests {
+    use super::{validate_pg_dump_arguments, validate_psql_arguments};
+
+    #[test]
+    fn arguments_match_the_canonical_contract() {
+        let owner = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
+        let source = owner.join("../../../../test-fixtures/postgres/logical-tools.json");
+        let fixture = if source.is_file() {
+            source
+        } else {
+            owner.join("testdata/logical-tools.json")
+        };
+        let contract: serde_json::Value = serde_json::from_slice(
+            &std::fs::read(fixture).expect("read canonical logical tools contract"),
+        )
+        .expect("parse canonical logical tools contract");
+        type Validator = fn(&[String]) -> Result<(), String>;
+        for (section, validate) in [
+            ("pgDump", validate_pg_dump_arguments as Validator),
+            ("psql", validate_psql_arguments as Validator),
+        ] {
+            for (field, accepted, scalar) in [
+                ("acceptedArgs", true, true),
+                ("acceptedArgv", true, false),
+                ("rejectedArgs", false, true),
+                ("rejectedArgv", false, false),
+            ] {
+                for case in contract[section][field].as_array().expect("contract cases") {
+                    let arguments = if scalar {
+                        vec![case.as_str().expect("argument").to_owned()]
+                    } else {
+                        case.as_array()
+                            .expect("argument list")
+                            .iter()
+                            .map(|argument| argument.as_str().expect("argument").to_owned())
+                            .collect()
+                    };
+                    assert_eq!(
+                        validate(&arguments).is_ok(),
+                        accepted,
+                        "{section}: {arguments:?}"
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/src/runtimes/liboliphaunt/native/crates/tools/src/lib.rs b/src/postgres-tools/native/crates/tools/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/native/crates/tools/src/lib.rs
rename to src/postgres-tools/native/crates/tools/src/lib.rs
diff --git a/src/runtimes/liboliphaunt/native/crates/tools/tests/build_support.rs b/src/postgres-tools/native/crates/tools/tests/build_support.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/native/crates/tools/tests/build_support.rs
rename to src/postgres-tools/native/crates/tools/tests/build_support.rs
diff --git a/src/postgres-tools/native/moon.yml b/src/postgres-tools/native/moon.yml
new file mode 100644
index 000000000..d7b8ed92a
--- /dev/null
+++ b/src/postgres-tools/native/moon.yml
@@ -0,0 +1,84 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+id: "postgres-tools-native"
+language: "unknown"
+layer: "tool"
+stack: "systems"
+tags: ["postgres", "tools", "release-product"]
+dependsOn:
+  - id: "shared-test-fixtures"
+    scope: "development"
+  - id: "liboliphaunt-native"
+    scope: "build"
+project:
+  title: "PostgreSQL native tools"
+  owner: "oliphaunt"
+  release:
+    component: "postgres-tools-native"
+    packagePath: "src/postgres-tools/native"
+    artifactTargets:
+      preset: "postgres-tools-native"
+      targets: ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"]
+fileGroups:
+  sources: ["**/*", "!**/node_modules/**/*", "!**/target/**/*"]
+tasks:
+  format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt -p oliphaunt-tools --check"
+    inputs: ["crates/tools/**/*.rs", "crates/tools/Cargo.toml", "@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+  lint:
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy -p oliphaunt-tools --all-targets --locked -- -D warnings"
+    inputs: ["crates/tools/**/*", "/clippy.toml", "@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+  build:
+    tags: ["build", "requires-rust"]
+    script: |
+      set -e
+      cargo build -p oliphaunt-tools --locked
+      bun run --cwd src/postgres-tools/native/npm build
+    inputs: ["crates/tools/**/*", "@group(cargo-workspace)", "npm/index.mts", "/tools/packaging/emit-javascript.mts"]
+    outputs: ["npm/index.js", "/target/debug/liboliphaunt_tools.rlib"]
+    options:
+      runFromWorkspaceRoot: true
+  test:
+    tags: ["quality", "unit", "requires-rust"]
+    command: "cargo test -p oliphaunt-tools --locked"
+    inputs:
+      - "crates/tools/**/*"
+      - "@group(cargo-workspace)"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+    options:
+      runFromWorkspaceRoot: true
+  package-assets:
+    tags: ["artifact-package", "ci-liboliphaunt-native-desktop"]
+    command: "bash src/postgres-tools/native/tools/package-assets.sh"
+    deps: ["liboliphaunt-native:build-runtime-desktop-target"]
+    inputs:
+      - "$OLIPHAUNT_CI_TARGET"
+      - "VERSION"
+      - "tools/package-assets.sh"
+      - "/src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh"
+      - "/src/runtimes/liboliphaunt-native/tools/native-runtime-payload*"
+      - "/tools/packaging/*.{mts,sh}"
+      - "@group(legal-files)"
+    outputs: ["/target/postgres-tools/native/release-assets/**/*"]
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  test-assets:
+    tags: ["integration", "ci-liboliphaunt-native-desktop"]
+    command: "bash src/postgres-tools/native/tools/test-assets.sh"
+    deps: ["postgres-tools-native:package-assets"]
+    inputs:
+      - "$OLIPHAUNT_CI_TARGET"
+      - "VERSION"
+      - "tools/test-assets.sh"
+      - "/src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh"
+      - "/tools/packaging/{portable-archive.mts,check-linux-consumer-baseline.sh}"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
diff --git a/src/runtimes/liboliphaunt/native/tools-packages/darwin-arm64/README.md b/src/postgres-tools/native/npm-platforms/darwin-arm64/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools-packages/darwin-arm64/README.md
rename to src/postgres-tools/native/npm-platforms/darwin-arm64/README.md
diff --git a/src/postgres-tools/native/npm-platforms/darwin-arm64/package.json b/src/postgres-tools/native/npm-platforms/darwin-arm64/package.json
new file mode 100644
index 000000000..1bf1e7093
--- /dev/null
+++ b/src/postgres-tools/native/npm-platforms/darwin-arm64/package.json
@@ -0,0 +1,45 @@
+{
+  "name": "@oliphaunt/tools-darwin-arm64",
+  "version": "0.2.1",
+  "description": "macOS arm64 PostgreSQL client tools for Oliphaunt.",
+  "license": "MIT AND PostgreSQL",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/postgres-tools/native/npm-platforms/darwin-arm64"
+  },
+  "os": [
+    "darwin"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "product": "oliphaunt-tools",
+    "kind": "native-tools",
+    "target": "macos-arm64",
+    "runtimeRelativePath": "runtime"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true,
+    "executableFiles": [
+      "./runtime/bin/pg_basebackup",
+      "./runtime/bin/pg_dump",
+      "./runtime/bin/psql"
+    ]
+  },
+  "files": [
+    "runtime",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
+    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/liboliphaunt/native/tools-packages/linux-arm64-gnu/README.md b/src/postgres-tools/native/npm-platforms/linux-arm64-gnu/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools-packages/linux-arm64-gnu/README.md
rename to src/postgres-tools/native/npm-platforms/linux-arm64-gnu/README.md
diff --git a/src/postgres-tools/native/npm-platforms/linux-arm64-gnu/package.json b/src/postgres-tools/native/npm-platforms/linux-arm64-gnu/package.json
new file mode 100644
index 000000000..a9fb88476
--- /dev/null
+++ b/src/postgres-tools/native/npm-platforms/linux-arm64-gnu/package.json
@@ -0,0 +1,48 @@
+{
+  "name": "@oliphaunt/tools-linux-arm64-gnu",
+  "version": "0.2.1",
+  "description": "Linux arm64 glibc PostgreSQL client tools for Oliphaunt.",
+  "license": "MIT AND PostgreSQL",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/postgres-tools/native/npm-platforms/linux-arm64-gnu"
+  },
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "product": "oliphaunt-tools",
+    "kind": "native-tools",
+    "target": "linux-arm64-gnu",
+    "runtimeRelativePath": "runtime"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true,
+    "executableFiles": [
+      "./runtime/bin/pg_basebackup",
+      "./runtime/bin/pg_dump",
+      "./runtime/bin/psql"
+    ]
+  },
+  "files": [
+    "runtime",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
+    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/liboliphaunt/native/tools-packages/linux-x64-gnu/README.md b/src/postgres-tools/native/npm-platforms/linux-x64-gnu/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools-packages/linux-x64-gnu/README.md
rename to src/postgres-tools/native/npm-platforms/linux-x64-gnu/README.md
diff --git a/src/postgres-tools/native/npm-platforms/linux-x64-gnu/package.json b/src/postgres-tools/native/npm-platforms/linux-x64-gnu/package.json
new file mode 100644
index 000000000..c43848f83
--- /dev/null
+++ b/src/postgres-tools/native/npm-platforms/linux-x64-gnu/package.json
@@ -0,0 +1,48 @@
+{
+  "name": "@oliphaunt/tools-linux-x64-gnu",
+  "version": "0.2.1",
+  "description": "Linux x64 glibc PostgreSQL client tools for Oliphaunt.",
+  "license": "MIT AND PostgreSQL",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/postgres-tools/native/npm-platforms/linux-x64-gnu"
+  },
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "product": "oliphaunt-tools",
+    "kind": "native-tools",
+    "target": "linux-x64-gnu",
+    "runtimeRelativePath": "runtime"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true,
+    "executableFiles": [
+      "./runtime/bin/pg_basebackup",
+      "./runtime/bin/pg_dump",
+      "./runtime/bin/psql"
+    ]
+  },
+  "files": [
+    "runtime",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
+    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/liboliphaunt/native/tools-packages/win32-x64-msvc/README.md b/src/postgres-tools/native/npm-platforms/win32-x64-msvc/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools-packages/win32-x64-msvc/README.md
rename to src/postgres-tools/native/npm-platforms/win32-x64-msvc/README.md
diff --git a/src/postgres-tools/native/npm-platforms/win32-x64-msvc/package.json b/src/postgres-tools/native/npm-platforms/win32-x64-msvc/package.json
new file mode 100644
index 000000000..52c413652
--- /dev/null
+++ b/src/postgres-tools/native/npm-platforms/win32-x64-msvc/package.json
@@ -0,0 +1,45 @@
+{
+  "name": "@oliphaunt/tools-win32-x64-msvc",
+  "version": "0.2.1",
+  "description": "Windows x64 MSVC PostgreSQL client tools for Oliphaunt.",
+  "license": "MIT AND PostgreSQL",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/postgres-tools/native/npm-platforms/win32-x64-msvc"
+  },
+  "os": [
+    "win32"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "product": "oliphaunt-tools",
+    "kind": "native-tools",
+    "target": "windows-x64-msvc",
+    "runtimeRelativePath": "runtime"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true,
+    "executableFiles": [
+      "./runtime/bin/pg_basebackup.exe",
+      "./runtime/bin/pg_dump.exe",
+      "./runtime/bin/psql.exe"
+    ]
+  },
+  "files": [
+    "runtime",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
+    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/liboliphaunt/native/tools-npm/README.md b/src/postgres-tools/native/npm/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools-npm/README.md
rename to src/postgres-tools/native/npm/README.md
diff --git a/src/runtimes/liboliphaunt/native/tools-npm/index.d.ts b/src/postgres-tools/native/npm/index.d.ts
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools-npm/index.d.ts
rename to src/postgres-tools/native/npm/index.d.ts
diff --git a/src/runtimes/liboliphaunt/native/tools-npm/index.js b/src/postgres-tools/native/npm/index.mts
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools-npm/index.js
rename to src/postgres-tools/native/npm/index.mts
diff --git a/src/postgres-tools/native/npm/package.json b/src/postgres-tools/native/npm/package.json
new file mode 100644
index 000000000..737e25ed6
--- /dev/null
+++ b/src/postgres-tools/native/npm/package.json
@@ -0,0 +1,50 @@
+{
+  "name": "@oliphaunt/tools",
+  "version": "0.2.1",
+  "description": "Optional PostgreSQL pg_dump and psql runners for Oliphaunt native endpoints.",
+  "license": "MIT",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/postgres-tools/native/npm"
+  },
+  "bugs": {
+    "url": "https://github.com/f0rr0/oliphaunt/issues"
+  },
+  "homepage": "https://oliphaunt.dev",
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "exports": {
+    ".": {
+      "types": "./index.d.ts",
+      "default": "./index.js"
+    },
+    "./package.json": "./package.json"
+  },
+  "main": "index.js",
+  "scripts": {
+    "build": "bun ../../../../tools/packaging/emit-javascript.mts index.mts index.js"
+  },
+  "types": "index.d.ts",
+  "files": [
+    "index.d.ts",
+    "index.js",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md"
+  ],
+  "optionalDependencies": {
+    "@oliphaunt/tools-darwin-arm64": "workspace:0.2.1",
+    "@oliphaunt/tools-linux-arm64-gnu": "workspace:0.2.1",
+    "@oliphaunt/tools-linux-x64-gnu": "workspace:0.2.1",
+    "@oliphaunt/tools-win32-x64-msvc": "workspace:0.2.1"
+  },
+  "engines": {
+    "node": ">=22.13 <25",
+    "bun": ">=1.3.14",
+    "deno": ">=2.8.1"
+  }
+}
diff --git a/src/postgres-tools/native/release.toml b/src/postgres-tools/native/release.toml
new file mode 100644
index 000000000..299d18cd7
--- /dev/null
+++ b/src/postgres-tools/native/release.toml
@@ -0,0 +1,17 @@
+id = "postgres-tools-native"
+owner = "@oliphaunt/core"
+kind = "postgres-tools"
+publish_targets = ["github-release-assets", "crates-io", "npm"]
+registry_packages = [
+  "crates:oliphaunt-tools",
+  "crates:oliphaunt-tools-linux-arm64-gnu",
+  "crates:oliphaunt-tools-linux-x64-gnu",
+  "crates:oliphaunt-tools-macos-arm64",
+  "crates:oliphaunt-tools-windows-x64-msvc",
+  "npm:@oliphaunt/tools-darwin-arm64",
+  "npm:@oliphaunt/tools-linux-x64-gnu",
+  "npm:@oliphaunt/tools-linux-arm64-gnu",
+  "npm:@oliphaunt/tools-win32-x64-msvc",
+  "npm:@oliphaunt/tools",
+]
+release_artifacts = ["postgres-tools"]
diff --git a/src/postgres-tools/native/tests/Cargo.toml b/src/postgres-tools/native/tests/Cargo.toml
new file mode 100644
index 000000000..4d0c3e25b
--- /dev/null
+++ b/src/postgres-tools/native/tests/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "oliphaunt-native-tools-proof"
+version = "0.0.0"
+edition.workspace = true
+rust-version.workspace = true
+license.workspace = true
+publish = false
+
+[dev-dependencies]
+oliphaunt = { path = "../../../sdks/rust/sdk" }
+oliphaunt-tools = { path = "../crates/tools" }
+serde_json = "1"
diff --git a/src/postgres-tools/native/tests/moon.yml b/src/postgres-tools/native/tests/moon.yml
new file mode 100644
index 000000000..8b4a7dadd
--- /dev/null
+++ b/src/postgres-tools/native/tests/moon.yml
@@ -0,0 +1,56 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "native-tools-proof"
+language: "rust"
+layer: "tool"
+stack: "systems"
+tags: ["maintainer-tool", "native", "rust", "tools"]
+dependsOn:
+  - id: "oliphaunt-rust"
+    scope: "build"
+  - id: "liboliphaunt-native"
+    scope: "development"
+  - id: "shared-test-fixtures"
+    scope: "development"
+
+project:
+  title: "Native tools proof"
+  description: "Unpublished cross-product conformance for native SDK servers and PostgreSQL tool facades."
+  owner: "oliphaunt"
+
+owners:
+  defaultOwner: "@oliphaunt/sdk-rust"
+
+tasks:
+  test:
+    tags: ["quality", "unit", "requires-rust"]
+    command: "cargo test -p oliphaunt-native-tools-proof --locked"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - project: "liboliphaunt-native"
+        group: "runtime"
+      - project: "oliphaunt-rust"
+        group: "code"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - "**/*"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt -p oliphaunt-native-tools-proof --check"
+    inputs: ["/src/postgres-tools/native/tests/**/*.rs","/src/postgres-tools/native/tests/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+  lint:
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy -p oliphaunt-native-tools-proof --all-targets --locked -- -D warnings"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs: ["/src/postgres-tools/native/tests/**/*.rs","/src/postgres-tools/native/tests/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
diff --git a/src/postgres-tools/native/tests/src/lib.rs b/src/postgres-tools/native/tests/src/lib.rs
new file mode 100644
index 000000000..cfdde14a9
--- /dev/null
+++ b/src/postgres-tools/native/tests/src/lib.rs
@@ -0,0 +1,116 @@
+#[cfg(test)]
+mod tests {
+    use std::path::{Path, PathBuf};
+    use std::time::{SystemTime, UNIX_EPOCH};
+
+    use oliphaunt::{DatabaseStorage, Extension, OliphauntServer};
+    use oliphaunt_tools::{PgDumpOptions, PsqlOptions};
+    use serde_json::Value;
+
+    #[test]
+    #[ignore = "requires prepared native runtime, PostgreSQL tools and pgtap"]
+    fn native_server_pg_dump_psql_round_trip() {
+        let library = std::env::var_os("LIBOLIPHAUNT_PATH")
+            .expect("LIBOLIPHAUNT_PATH must point to the prepared native runtime library");
+        assert!(
+            Path::new(&library).is_file(),
+            "LIBOLIPHAUNT_PATH must name an existing file"
+        );
+
+        let source_root = unique_root("native-logical-source");
+        let restored_root = unique_root("native-logical-restored");
+        let seed = fixture("logical-tools-seed.sql");
+        let verify = fixture("logical-tools-verify.sql");
+        let result = std::panic::catch_unwind(|| {
+            let mut source = OliphauntServer::builder()
+                .storage(DatabaseStorage::Directory(source_root.clone()))
+                .extension(Extension::PGTAP)
+                .start()
+                .expect("open native logical source server");
+            oliphaunt_tools::psql(
+                source.connection_string(),
+                PsqlOptions::new().script(seed.as_str()),
+            )
+            .expect("seed native server through public psql facade");
+            let dump_sql =
+                oliphaunt_tools::pg_dump(source.connection_string(), PgDumpOptions::new())
+                    .expect("dump native server through public pg_dump facade");
+            assert!(dump_sql.contains("COPY public.logical_items"));
+            assert!(!dump_sql.contains("INSERT INTO public.logical_items"));
+            source.close().expect("close native logical source server");
+
+            let mut restored = OliphauntServer::builder()
+                .storage(DatabaseStorage::Directory(restored_root.clone()))
+                .extension(Extension::PGTAP)
+                .start()
+                .expect("open native logical restore server");
+            oliphaunt_tools::psql(
+                restored.connection_string(),
+                PsqlOptions::new().script(dump_sql),
+            )
+            .expect("restore native server through public psql facade");
+            let verify_output = oliphaunt_tools::psql(
+                restored.connection_string(),
+                PsqlOptions::new().arg("-tA").script(verify.as_str()),
+            )
+            .expect("verify native logical restore through public psql facade");
+            assert_eq!(verify_output.trim(), expected_logical_tools_row());
+            restored
+                .close()
+                .expect("close native logical restore server");
+        });
+        let _ = std::fs::remove_dir_all(source_root);
+        let _ = std::fs::remove_dir_all(restored_root);
+        if let Err(payload) = result {
+            std::panic::resume_unwind(payload);
+        }
+    }
+
+    fn fixture(name: &str) -> String {
+        std::fs::read_to_string(
+            Path::new(env!("CARGO_MANIFEST_DIR"))
+                .join("../../../test-fixtures/postgres")
+                .join(name),
+        )
+        .unwrap_or_else(|error| panic!("read canonical logical tools fixture {name}: {error}"))
+    }
+
+    fn expected_logical_tools_row() -> String {
+        let fixture: Value = serde_json::from_str(&fixture("logical-tools.json"))
+            .expect("canonical logical tools fixture must be valid JSON");
+        let expected = &fixture["expected"];
+        format!(
+            "{}|{}|{}|{}|{}|{}",
+            expected["rows"].as_i64().expect("fixture rows"),
+            expected["sum"].as_i64().expect("fixture sum"),
+            expected["sequenceLastValue"]
+                .as_i64()
+                .expect("fixture sequence last value"),
+            expected["quotedValue"]
+                .as_str()
+                .expect("fixture quoted value"),
+            expected["normalizedMatches"]
+                .as_i64()
+                .expect("fixture normalized matches"),
+            if expected["extensionLoaded"]
+                .as_bool()
+                .expect("fixture extension loaded")
+            {
+                "t"
+            } else {
+                "f"
+            }
+        )
+    }
+
+    fn unique_root(label: &str) -> PathBuf {
+        std::env::temp_dir().join(format!(
+            "oliphaunt-{label}-{}-{}",
+            std::process::id(),
+            SystemTime::now()
+                .duration_since(UNIX_EPOCH)
+                .expect("system clock is before Unix epoch")
+                .as_nanos()
+        ))
+    }
+}
diff --git a/src/postgres-tools/native/tools/package-assets.sh b/src/postgres-tools/native/tools/package-assets.sh
new file mode 100644
index 000000000..ddba1012b
--- /dev/null
+++ b/src/postgres-tools/native/tools/package-assets.sh
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+cd "$root"
+. src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+target="${OLIPHAUNT_CI_TARGET:-}"
+runtime=""
+output="$root/target/postgres-tools/native/release-assets"
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --target) target="${2:?missing target}"; shift 2 ;;
+    --runtime) runtime="${2:?missing runtime install directory}"; shift 2 ;;
+    --output-dir) output="${2:?missing output directory}"; shift 2 ;;
+    *) echo 'usage: package-assets.sh --target TARGET [--runtime INSTALL] [--output-dir DIR]' >&2; exit 2 ;;
+  esac
+done
+target="${target:-$(oliphaunt_runtime_native_host_target_id)}"
+case "$target" in
+  linux-x64-gnu|linux-arm64-gnu)
+    runtime="${runtime:-${OLIPHAUNT_LINUX_WORK_ROOT:-$root/target/liboliphaunt-pg18-$target}/install}"
+    suffix=""; archive_suffix=tar.gz ;;
+  macos-arm64)
+    runtime="${runtime:-${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18}/install}"
+    suffix=""; archive_suffix=tar.gz ;;
+  windows-x64-msvc)
+    runtime="${runtime:-${OLIPHAUNT_WINDOWS_WORK_ROOT:-${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18-$target}}/install}"
+    suffix=.exe; archive_suffix=zip ;;
+  *) echo "unsupported native tools target: $target" >&2; exit 2 ;;
+esac
+[ -d "$runtime" ] || { echo "missing PostgreSQL installation: $runtime" >&2; exit 1; }
+version="$(tools/dev/bun.sh tools/release/product-version.mts version postgres-tools-native)"
+mkdir -p "$output"
+stage="$(mktemp -d "$output/.stage-$target.XXXXXX")"
+trap 'rm -rf "$stage"' EXIT
+mkdir -p "$stage/runtime/bin" "$stage/runtime/lib"
+queue=()
+for tool in pg_basebackup pg_dump psql; do
+  cp -Lp "$runtime/bin/$tool$suffix" "$stage/runtime/bin/"
+  queue+=("$stage/runtime/bin/$tool$suffix")
+done
+
+# Copy only dependencies present in the producer installation. OS libraries
+# remain supplied by the supported host, never borrowed from another package.
+imports() {
+  case "$target" in
+    linux-*) readelf -d "$1" | sed -n 's/.*(NEEDED).*\[\([^]]*\)\].*/\1/p' ;;
+    macos-*) otool -L "$1" | sed '1d;s/^[[:space:]]*//;s/ (compatibility version.*//' ;;
+    windows-*) tools/dev/bun.sh - "$1" <<'TS'
+import { readFileSync } from 'node:fs';
+import { inspectPortableExecutable } from './tools/packaging/windows-vc-runtime-closure.mts';
+console.log(inspectPortableExecutable(readFileSync(process.argv[2]), process.argv[2]).imports.join('\n'));
+TS
+      ;;
+  esac
+}
+for ((index=0; index<${#queue[@]}; index++)); do
+  imports "${queue[index]}" > "$stage/imports"
+  while IFS= read -r dependency; do
+    name="${dependency##*/}"
+    [ -n "$name" ] || continue
+    directory=lib
+    [ "$target" != windows-x64-msvc ] || directory=bin
+    source="$runtime/$directory/$name"
+    destination="$stage/runtime/$directory/$name"
+    [ -f "$source" ] && [ ! -e "$destination" ] || continue
+    cp -Lp "$source" "$destination"
+    queue+=("$destination")
+  done < "$stage/imports"
+done
+rm "$stage/imports"
+if [ "$target" = windows-x64-msvc ]; then
+  tools/dev/bun.sh tools/packaging/windows-vc-runtime-closure.mts stage \
+    --root "$stage" --source-dir "$runtime/bin" --destination "$stage/runtime/bin"
+fi
+tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts "$stage" --target "$target" --tool-set tools
+bash tools/packaging/strip-native-binaries.sh --target "$target" "$stage"
+tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target" --root "$stage"
+tools/dev/bun.sh tools/packaging/release-notices.mts stage "$stage" --profile native-tools
+archive="$output/oliphaunt-tools-$version-$target.$archive_suffix"
+tools/dev/bun.sh tools/packaging/archive-directory.mts "$stage" "$archive"
+tools/dev/bun.sh tools/packaging/release-notices.mts check-archive "$archive" --profile native-tools
+printf 'nativeToolsReleaseAsset=%s\n' "$archive"
diff --git a/src/postgres-tools/native/tools/package-cargo-artifacts.mts b/src/postgres-tools/native/tools/package-cargo-artifacts.mts
new file mode 100644
index 000000000..a73f3ff82
--- /dev/null
+++ b/src/postgres-tools/native/tools/package-cargo-artifacts.mts
@@ -0,0 +1,149 @@
+#!/usr/bin/env bun
+import path from 'node:path';
+import { existsSync, cpSync, mkdirSync, copyFileSync, readFileSync, writeFileSync } from 'node:fs';
+import { ROOT, compareText } from '../../../../tools/release/release-artifact-targets.mts';
+import { inspectPlatformBinaryTree } from '../../../../tools/packaging/platform-binary-contract.mts';
+import { extractPortableArchiveTree } from '../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  stageReleaseNotices,
+} from '../../../../tools/packaging/release-notices.mts';
+import {
+  renderUnsupportedNativeTargetGuard,
+  rustNativeTargetCfg,
+} from '../../../../tools/packaging/rust-native-targets.mts';
+import { validatePayload } from '../../../runtimes/liboliphaunt-native/tools/native-runtime-payload.mts';
+import {
+  fail,
+  rel,
+  cargoPackageName,
+  freezeSourceCrate,
+  packagePayload,
+  parseCargoArtifactArgs,
+  prepareCargoArtifactWorkspace,
+  selectCargoArtifactTargets,
+  writePackagesManifest,
+} from '../../../../tools/packaging/native-cargo-payload.mts';
+const PRODUCT = 'postgres-tools-native';
+const TOOLS_PRODUCT = 'oliphaunt-tools';
+const TOOLS_KIND = 'native-tools';
+const TOOLS_FACADE_TEMPLATE = path.join(ROOT, 'src/postgres-tools/native/crates/tools');
+export function renderUnsupportedToolsTargetGuard(nativeTargets, nativeCfgs) {
+  return renderUnsupportedNativeTargetGuard({
+    product: TOOLS_PRODUCT,
+    nativeTargets,
+    nativeCfgs,
+    guidance: 'use one of these declared native targets; this package has no portable fallback.',
+  });
+}
+
+function writeToolsFacadeCrate(sourceRoot, { version, toolsTargets }) {
+  const crateDir = path.join(sourceRoot, TOOLS_PRODUCT);
+  if (existsSync(crateDir)) {
+    fail(`duplicate generated ${TOOLS_PRODUCT} source crate: ${rel(crateDir)}`);
+  }
+  cpSync(TOOLS_FACADE_TEMPLATE, crateDir, {
+    recursive: true,
+    filter: (source) =>
+      path.basename(source) !== 'target' && source !== path.join(TOOLS_FACADE_TEMPLATE, 'tests'),
+  });
+  mkdirSync(path.join(crateDir, 'testdata'), { recursive: true });
+  copyFileSync(
+    path.join(ROOT, 'src/test-fixtures/postgres/logical-tools.json'),
+    path.join(crateDir, 'testdata/logical-tools.json'),
+  );
+  const cargoToml = path.join(crateDir, 'Cargo.toml');
+  let text = readFileSync(cargoToml, 'utf8');
+  text = text
+    .replace('repository.workspace = true', 'repository = "https://github.com/f0rr0/oliphaunt"')
+    .replace('homepage.workspace = true', 'homepage = "https://oliphaunt.dev"');
+  const versionMatches = text.match(/^version = "[^"]+"$/gm) ?? [];
+  if (versionMatches.length !== 1) {
+    fail(`${rel(cargoToml)} must declare exactly one package version`);
+  }
+  text = text.replace(/^version = "[^"]+"$/m, `version = "${version}"`);
+  const dependencyBlocks = [];
+  const sortedToolsTargets = [...toolsTargets].sort((left, right) =>
+    compareText(left.target, right.target),
+  );
+  const nativeTargets = sortedToolsTargets.map((target) => target.target);
+  const nativeCfgs = sortedToolsTargets.map((target) => rustNativeTargetCfg(target));
+  for (let index = 0; index < sortedToolsTargets.length; index += 1) {
+    const target = sortedToolsTargets[index];
+    const packageName = cargoPackageName(target.target, { packageBase: TOOLS_PRODUCT });
+    dependencyBlocks.push(
+      [
+        '',
+        `[target.'cfg(${nativeCfgs[index]})'.dependencies]`,
+        `${packageName} = { version = "=${version}", path = "../${packageName}" }`,
+      ].join('\n'),
+    );
+  }
+  if (!text.includes('\n[workspace]')) {
+    text = `${text.trimEnd()}\n\n[workspace]\n`;
+  }
+  writeFileSync(cargoToml, `${text.trimEnd()}\n${dependencyBlocks.join('\n')}\n`);
+  const libRs = path.join(crateDir, 'src/lib.rs');
+  const releaseOnlyGuard = renderUnsupportedToolsTargetGuard(nativeTargets, nativeCfgs);
+  writeFileSync(
+    libRs,
+    `${readFileSync(libRs, 'utf8').trimEnd()}\n\n// Generated release-only native target guard.\n${releaseOnlyGuard}\n`,
+  );
+  stageReleaseNotices(crateDir, { profile: 'code-facade' });
+  assertReleaseNoticesInDirectory(crateDir, { profile: 'code-facade' });
+  return {
+    name: TOOLS_PRODUCT,
+    version,
+    manifestPath: cargoToml,
+    cratePath: null,
+    target: 'portable',
+    product: TOOLS_PRODUCT,
+    kind: TOOLS_KIND,
+    role: 'facade',
+    noticeProfile: 'code-facade',
+    index: null,
+  };
+}
+
+export async function packageNativeToolsCargoArtifacts(argv) {
+  const args = await parseCargoArtifactArgs(argv, {
+    product: PRODUCT,
+    assetDir: 'target/postgres-tools/native/release-assets',
+    outputDir: 'target/postgres-tools/native/cargo-artifacts',
+    workDir: 'target/postgres-tools/native',
+  });
+  const { sourceRoot, cargoTargetDir } = prepareCargoArtifactWorkspace(args);
+  const targets = selectCargoArtifactTargets(PRODUCT, TOOLS_KIND, args.targets);
+  const packages = [];
+  for (const target of targets) {
+    const archive = path.join(args.assetDir, target.asset.replaceAll('{version}', args.version));
+    assertReleaseNoticesInArchive(archive, { profile: 'native-tools' });
+    const root = path.join(sourceRoot, target.target + '-extracted');
+    extractPortableArchiveTree(archive, root);
+    await inspectPlatformBinaryTree(root, { target: target.target });
+    validatePayload(root, target.target, { toolSet: 'tools' });
+    packages.push(
+      ...packagePayload(root, sourceRoot, args.outputDir, cargoTargetDir, {
+        target,
+        version: args.version,
+        partBytes: args.partBytes,
+        packageBase: TOOLS_PRODUCT,
+        artifactProduct: TOOLS_PRODUCT,
+        artifactKind: TOOLS_KIND,
+        artifactLabel: 'Oliphaunt native tools',
+        noticeProfile: 'native-tools',
+      }),
+    );
+  }
+  packages.push(
+    freezeSourceCrate(
+      writeToolsFacadeCrate(sourceRoot, { version: args.version, toolsTargets: targets }),
+      args.outputDir,
+      cargoTargetDir,
+    ),
+  );
+  writePackagesManifest(packages, args.outputDir, PRODUCT);
+  return packages;
+}
+if (import.meta.main) await packageNativeToolsCargoArtifacts(Bun.argv.slice(2));
diff --git a/src/postgres-tools/native/tools/package-carriers.mts b/src/postgres-tools/native/tools/package-carriers.mts
new file mode 100644
index 000000000..26ffd9e6b
--- /dev/null
+++ b/src/postgres-tools/native/tools/package-carriers.mts
@@ -0,0 +1,203 @@
+#!/usr/bin/env bun
+import { copyFileSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { emitJavaScript } from '../../../../tools/packaging/emit-javascript.mts';
+import {
+  extractPortableArchiveTree,
+  readPortableArchiveEntries,
+} from '../../../../tools/packaging/portable-archive.mts';
+import {
+  artifactNpmPackageTargets,
+  fail,
+  packStagedNpmCarrier,
+  stageNpmPackageDescriptor,
+  stageWindowsVcRuntimeMembers,
+  TOOL,
+  validatePackedNpmPackage,
+} from '../../../../tools/packaging/release-carrier.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  releaseNoticeRows,
+  stageReleaseNotices,
+} from '../../../../tools/packaging/release-notices.mts';
+import {
+  compareText,
+  currentProductVersionSync,
+  ROOT,
+  artifactTargets,
+  registryPackageRows,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  requiredToolsMemberPaths,
+  validatePayload,
+} from '../../../runtimes/liboliphaunt-native/tools/native-runtime-payload.mts';
+import { validateCargoArtifactPackages } from '../../../../tools/packaging/native-cargo-payload.mts';
+import { packageNativeToolsCargoArtifacts } from './package-cargo-artifacts.mts';
+const LIBOLIPHAUNT_NATIVE_PRODUCT = 'postgres-tools-native';
+const LIBOLIPHAUNT_NATIVE_TOOLS_KIND = 'native-tools';
+const LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_PACKAGE = '@oliphaunt/tools';
+const LIBOLIPHAUNT_NATIVE_TOOLS_PACKAGE_ROOT = path.join(
+  ROOT,
+  'src/postgres-tools/native/npm-platforms',
+);
+const LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_ROOT = path.join(ROOT, 'src/postgres-tools/native/npm');
+function liboliphauntToolsNpmPackageTargets(version) {
+  return artifactNpmPackageTargets({
+    product: LIBOLIPHAUNT_NATIVE_PRODUCT,
+    kind: LIBOLIPHAUNT_NATIVE_TOOLS_KIND,
+    surface: 'typescript-native-direct',
+    packageRoot: LIBOLIPHAUNT_NATIVE_TOOLS_PACKAGE_ROOT,
+    version,
+  });
+}
+
+function selectedLiboliphauntToolsNpmPackageTargets(version, targetIds) {
+  const targets = liboliphauntToolsNpmPackageTargets(version);
+  if (targetIds === undefined) return targets;
+  const selected = new Set(targetIds);
+  const filtered = targets.filter(([, , target]) => selected.has(target.target));
+  const actual = new Set(filtered.map(([, , target]) => target.target));
+  const missing = [...selected].filter((target) => !actual.has(target)).sort(compareText);
+  if (missing.length > 0) {
+    fail(`unknown native tools npm target(s): ${missing.join(', ')}`);
+  }
+  return filtered;
+}
+
+function stageLiboliphauntToolsNpmPayloads(
+  version,
+  { assetDir = path.join(ROOT, 'target/postgres-tools/native/release-assets'), targetIds } = {},
+) {
+  const stages = new Map();
+  for (const [packageName, packageDir, target] of selectedLiboliphauntToolsNpmPackageTargets(
+    version,
+    targetIds,
+  )) {
+    const stage = stageNpmPackageDescriptor(packageName, packageDir, version, {
+      target: target.target,
+    });
+    stageReleaseNotices(stage, { profile: 'native-tools' });
+    const archive = path.join(assetDir, target.asset.replaceAll('{version}', version));
+    extractPortableArchiveTree(archive, path.join(stage, 'runtime'), 'runtime');
+    const payloadMembers = [...readPortableArchiveEntries(archive).values()]
+      .filter((entry) => !entry.isDirectory && entry.name.startsWith('runtime/'))
+      .map((entry) => entry.name);
+    const vcRuntimeMembers = stageWindowsVcRuntimeMembers(
+      archive,
+      stage,
+      target.target,
+      'runtime/bin',
+      { alreadyExtracted: true },
+    );
+    validatePayload(stage, target.target, { toolSet: 'tools' });
+    assertReleaseNoticesInDirectory(stage, { profile: 'native-tools' });
+    stages.set(packageName, { stage, vcRuntimeMembers, payloadMembers });
+  }
+  return stages;
+}
+
+function stageLiboliphauntToolsNpmFacade(version) {
+  const stage = stageNpmPackageDescriptor(
+    LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_PACKAGE,
+    LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_ROOT,
+    version,
+  );
+  emitJavaScript(
+    path.join(LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_ROOT, 'index.mts'),
+    path.join(stage, 'index.js'),
+  );
+  for (const descriptor of ['index.d.ts']) {
+    copyFileSync(
+      path.join(LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_ROOT, descriptor),
+      path.join(stage, descriptor),
+    );
+  }
+  const manifestFile = path.join(stage, 'package.json');
+  const manifest = JSON.parse(readFileSync(manifestFile, 'utf8'));
+  delete manifest.scripts;
+  manifest.optionalDependencies = Object.fromEntries(
+    Object.keys(manifest.optionalDependencies ?? {})
+      .sort(compareText)
+      .map((name) => [name, version]),
+  );
+  writeFileSync(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`);
+  stageReleaseNotices(stage, { profile: 'source-sdk' });
+  assertReleaseNoticesInDirectory(stage, { profile: 'source-sdk' });
+  return stage;
+}
+
+export function liboliphauntToolsNpmTarballs(
+  version = currentProductVersionSync(LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL),
+  options = {},
+) {
+  const packages = [];
+  const toolsStages = stageLiboliphauntToolsNpmPayloads(version, options);
+  for (const [packageName, , target] of selectedLiboliphauntToolsNpmPackageTargets(
+    version,
+    options.targetIds,
+  )) {
+    const payload = toolsStages.get(packageName);
+    const runtimeMembers = requiredToolsMemberPaths(target.target, 'package/runtime/bin');
+    const tarball = packStagedNpmCarrier(payload.stage);
+    validatePackedNpmPackage({
+      packageName,
+      version,
+      tarball,
+      requiredMembers: [
+        ...payload.payloadMembers.map((member) => `package/${member}`),
+        ...payload.vcRuntimeMembers.map((member) => `package/${member}`),
+        ...releaseNoticeRows({ profile: 'native-tools' }).map((row) => `package/${row.member}`),
+      ],
+      executableMembers: runtimeMembers,
+    });
+    assertReleaseNoticesInArchive(tarball, { profile: 'native-tools', prefix: 'package' });
+    packages.push([packageName, tarball]);
+  }
+  const toolsFacadeStage = stageLiboliphauntToolsNpmFacade(version);
+  const toolsFacadeTarball = packStagedNpmCarrier(toolsFacadeStage);
+  validatePackedNpmPackage({
+    packageName: LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_PACKAGE,
+    version,
+    tarball: toolsFacadeTarball,
+    requiredMembers: [
+      'package/index.js',
+      'package/index.d.ts',
+      ...releaseNoticeRows({ profile: 'source-sdk' }).map((row) => `package/${row.member}`),
+    ],
+  });
+  assertReleaseNoticesInArchive(toolsFacadeTarball, {
+    profile: 'source-sdk',
+    prefix: 'package',
+  });
+  packages.push([LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_PACKAGE, toolsFacadeTarball]);
+  return packages;
+}
+
+export async function nativeToolsCargoArtifactPackages(
+  version = currentProductVersionSync(LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL),
+) {
+  const outputDir = path.join(ROOT, 'target/postgres-tools/native/cargo-artifacts');
+  await packageNativeToolsCargoArtifacts(['--version', version]);
+  return validateCargoArtifactPackages(outputDir, {
+    product: LIBOLIPHAUNT_NATIVE_PRODUCT,
+    expectedAggregators: new Set(
+      artifactTargets(LIBOLIPHAUNT_NATIVE_PRODUCT, LIBOLIPHAUNT_NATIVE_TOOLS_KIND, TOOL)
+        .filter((t) => t.surfaces.includes('rust-native-direct'))
+        .map((t) => 'oliphaunt-tools-' + t.target),
+    ),
+    expectedFacade: 'oliphaunt-tools',
+    configuredCrates: new Set(
+      registryPackageRows(
+        { product: LIBOLIPHAUNT_NATIVE_PRODUCT, packageKind: 'crates' },
+        TOOL,
+      ).map((row) => row.packageName),
+    ),
+  });
+}
+export async function packageNativeToolsCarriers() {
+  const version = currentProductVersionSync(LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL);
+  await nativeToolsCargoArtifactPackages(version);
+  return liboliphauntToolsNpmTarballs(version);
+}
+if (import.meta.main) await packageNativeToolsCarriers();
diff --git a/src/postgres-tools/native/tools/smoke-packed-tools-npm.mts b/src/postgres-tools/native/tools/smoke-packed-tools-npm.mts
new file mode 100644
index 000000000..cae2bfd29
--- /dev/null
+++ b/src/postgres-tools/native/tools/smoke-packed-tools-npm.mts
@@ -0,0 +1,156 @@
+#!/usr/bin/env node
+
+import { copyFile, readFile, writeFile } from 'node:fs/promises';
+import path from 'node:path';
+import process from 'node:process';
+import { fileURLToPath, pathToFileURL } from 'node:url';
+
+const TOOL = 'smoke-packed-tools-npm.mts';
+const ENGINE_FLAG = '--engine';
+
+if (process.argv.includes(ENGINE_FLAG)) {
+  await runConsumer(readEngine(process.argv.slice(2)));
+} else {
+  if (process.argv.length !== 4)
+    throw new Error('usage: smoke-packed-tools-npm.mts ASSET_DIR STAGE_DIR');
+  await prepareConsumer(path.resolve(process.argv[2]), path.resolve(process.argv[3]));
+}
+
+async function prepareConsumer(assetDir, scratch) {
+  const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
+  const { currentProductVersionSync } = await import(
+    pathToFileURL(path.join(repositoryRoot, 'tools/release/release-artifact-targets.mts')).href
+  );
+  const { liboliphauntToolsNpmTarballs } = await import(
+    pathToFileURL(path.join(repositoryRoot, 'src/postgres-tools/native/tools/package-carriers.mts'))
+      .href
+  );
+  const version = currentProductVersionSync('postgres-tools-native', TOOL);
+  const packages = liboliphauntToolsNpmTarballs(version, {
+    assetDir,
+    targetIds: ['linux-x64-gnu'],
+  });
+  const packageFiles = new Map(packages);
+  const facade = requiredPackage(packageFiles, '@oliphaunt/tools');
+  const carrier = requiredPackage(packageFiles, '@oliphaunt/tools-linux-x64-gnu');
+  if (packages.length !== 2 || packageFiles.size !== 2) {
+    throw new Error(`${TOOL}: expected exactly the facade and Linux x64 carrier`);
+  }
+
+  await writeFile(
+    path.join(scratch, 'package.json'),
+    `${JSON.stringify(
+      {
+        name: 'oliphaunt-native-tools-smoke-consumer',
+        version: '0.0.0',
+        private: true,
+        type: 'module',
+        dependencies: {
+          '@oliphaunt/tools': version,
+          '@oliphaunt/tools-linux-x64-gnu': version,
+        },
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  await copyFile(fileURLToPath(import.meta.url), path.join(scratch, 'smoke.mts'));
+  await writeFile(path.join(scratch, 'tarballs'), facade + '\0' + carrier + '\0');
+}
+
+async function runConsumer(engine) {
+  const connectionString = requiredEnvironment('OLIPHAUNT_NATIVE_TOOLS_CONNECTION_STRING');
+  const contract = JSON.parse(
+    await readFile(requiredEnvironment('OLIPHAUNT_LOGICAL_TOOLS_CONTRACT'), 'utf8'),
+  );
+  const seed = await readFile(requiredEnvironment('OLIPHAUNT_LOGICAL_TOOLS_SEED'), 'utf8');
+  const verify = await readFile(requiredEnvironment('OLIPHAUNT_LOGICAL_TOOLS_VERIFY'), 'utf8');
+  const { pgDump, psql } = await import('@oliphaunt/tools');
+  const suffix = `${engine}_${process.pid}`.replaceAll(/[^a-z0-9_]/gu, '_');
+  const sourceDatabase = `oliphaunt_tools_${suffix}_source`;
+  const restoredDatabase = `oliphaunt_tools_${suffix}_restored`;
+  const sourceConnection = databaseConnectionString(connectionString, sourceDatabase);
+  const restoredConnection = databaseConnectionString(connectionString, restoredDatabase);
+  try {
+    await psql(connectionString, { command: `CREATE DATABASE ${quoteIdentifier(sourceDatabase)}` });
+    await psql(connectionString, {
+      command: `CREATE DATABASE ${quoteIdentifier(restoredDatabase)}`,
+    });
+    await psql(sourceConnection, { script: seed });
+    const dump = await pgDump(sourceConnection);
+    if (
+      !dump.includes('COPY public.logical_items') ||
+      dump.includes('INSERT INTO public.logical_items')
+    ) {
+      throw new Error(`${engine}: pg_dump did not preserve PostgreSQL's ordinary COPY output`);
+    }
+    await psql(restoredConnection, { script: dump });
+    const actual = (await psql(restoredConnection, { args: ['-tA'], script: verify })).trim();
+    const expected = expectedLogicalToolsRow(contract);
+    if (actual !== expected) {
+      throw new Error(
+        `${engine}: logical tools round trip returned ${JSON.stringify(actual)}, ` +
+          `expected ${JSON.stringify(expected)}`,
+      );
+    }
+    console.log(`OLIPHAUNT_NATIVE_TOOLS_NPM_SMOKE_PASS engine=${engine}`);
+  } finally {
+    for (const database of [restoredDatabase, sourceDatabase]) {
+      try {
+        await psql(connectionString, {
+          command: `DROP DATABASE IF EXISTS ${quoteIdentifier(database)} WITH (FORCE)`,
+        });
+      } catch (error) {
+        console.error(`${TOOL}: failed to drop ${database}: ${error?.stack ?? error}`);
+      }
+    }
+  }
+}
+
+function readEngine(arguments_) {
+  if (arguments_.length !== 2 || arguments_[0] !== ENGINE_FLAG) {
+    throw new Error(`usage: ${TOOL} ${ENGINE_FLAG} node|bun|deno`);
+  }
+  if (!new Set(['node', 'bun', 'deno']).has(arguments_[1])) {
+    throw new Error(`${TOOL}: unsupported engine ${JSON.stringify(arguments_[1])}`);
+  }
+  return arguments_[1];
+}
+
+function requiredPackage(packages, name) {
+  const file = packages.get(name);
+  if (typeof file !== 'string' || file.length === 0) {
+    throw new Error(`${TOOL}: packed package ${name} is missing`);
+  }
+  return file;
+}
+
+function requiredEnvironment(name) {
+  const value = process.env[name];
+  if (typeof value !== 'string' || value.length === 0) {
+    throw new Error(`${TOOL}: ${name} is required`);
+  }
+  return value;
+}
+
+function databaseConnectionString(connectionString, database) {
+  const url = new URL(connectionString);
+  url.pathname = `/${database}`;
+  return url.href;
+}
+
+function quoteIdentifier(identifier) {
+  return `"${identifier.replaceAll('"', '""')}"`;
+}
+
+function expectedLogicalToolsRow(contract) {
+  const expected = contract.expected;
+  return [
+    expected.rows,
+    expected.sum,
+    expected.sequenceLastValue,
+    expected.quotedValue,
+    expected.normalizedMatches,
+    expected.extensionLoaded ? 't' : 'f',
+  ].join('|');
+}
diff --git a/src/postgres-tools/native/tools/smoke-packed-tools-npm.sh b/src/postgres-tools/native/tools/smoke-packed-tools-npm.sh
new file mode 100644
index 000000000..3f7ba1582
--- /dev/null
+++ b/src/postgres-tools/native/tools/smoke-packed-tools-npm.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+set -euo pipefail
+[[ $# == 2 && $1 == --asset-dir ]] || { echo 'usage: smoke-packed-tools-npm.sh --asset-dir DIRECTORY' >&2; exit 2; }
+: "${OLIPHAUNT_NATIVE_TOOLS_CONNECTION_STRING:?a running native server is required}"
+asset_dir=$(cd "$2" && pwd)
+root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-native-tools-npm-XXXXXX")
+trap 'rm -rf "$scratch"' EXIT
+scratch=$(cd "$scratch" && pwd -P)
+bash "$root/tools/dev/bun.sh" "$root/src/postgres-tools/native/tools/smoke-packed-tools-npm.mts" "$asset_dir" "$scratch"
+{ IFS= read -r -d '' facade; IFS= read -r -d '' carrier; } < "$scratch/tarballs"
+# These are the two freshly validated release packages. Extracting only this
+# host's payload keeps the smoke offline without fake optional dependencies.
+mkdir -p "$scratch/node_modules/@oliphaunt/tools" "$scratch/node_modules/@oliphaunt/tools-linux-x64-gnu"
+tar -xzf "$facade" --strip-components=1 -C "$scratch/node_modules/@oliphaunt/tools"
+tar -xzf "$carrier" --strip-components=1 -C "$scratch/node_modules/@oliphaunt/tools-linux-x64-gnu"
+export OLIPHAUNT_LOGICAL_TOOLS_CONTRACT="$root/src/test-fixtures/postgres/logical-tools.json"
+export OLIPHAUNT_LOGICAL_TOOLS_SEED="$root/src/test-fixtures/postgres/logical-tools-seed.sql"
+export OLIPHAUNT_LOGICAL_TOOLS_VERIFY="$root/src/test-fixtures/postgres/logical-tools-verify.sql"
+cd "$scratch"
+timeout --kill-after=5 300 node "$scratch/smoke.mts" --engine node
+timeout --kill-after=5 300 bash "$root/tools/dev/bun.sh" "$scratch/smoke.mts" --engine bun
+timeout --kill-after=5 300 bash "$root/tools/dev/deno.sh" run --allow-all "$scratch/smoke.mts" --engine deno
diff --git a/src/postgres-tools/native/tools/test-assets.sh b/src/postgres-tools/native/tools/test-assets.sh
new file mode 100644
index 000000000..c3554d74e
--- /dev/null
+++ b/src/postgres-tools/native/tools/test-assets.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+cd "$root"
+. src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+target="${OLIPHAUNT_CI_TARGET:-$(oliphaunt_runtime_native_host_target_id)}"
+version="$(tools/dev/bun.sh tools/release/product-version.mts version postgres-tools-native)"
+case "$target" in
+  linux-*|macos-*) extension=tar.gz; suffix="" ;;
+  windows-x64-msvc) extension=zip; suffix=.exe ;;
+  *) echo "unsupported native tools target: $target" >&2; exit 2 ;;
+esac
+archive="$root/target/postgres-tools/native/release-assets/oliphaunt-tools-$version-$target.$extension"
+scratch="$(mktemp -d "$root/target/native-tools-consumer.XXXXXX")"
+trap 'rm -rf "$scratch"' EXIT
+tools/dev/bun.sh - "$archive" "$scratch" <<'TS'
+import { extractPortableArchiveTree } from './tools/packaging/portable-archive.mts';
+extractPortableArchiveTree(process.argv[2], process.argv[3]);
+TS
+case "$target" in
+  linux-*)
+    # No runtime package mount: missing libpq must fail in the consumer image.
+    bash tools/packaging/check-linux-consumer-baseline.sh --target "$target" --root "$scratch"
+    ;;
+  *)
+    for tool in pg_basebackup pg_dump psql; do
+      DYLD_LIBRARY_PATH="$scratch/runtime/lib" "$scratch/runtime/bin/$tool$suffix" --version
+    done
+    ;;
+esac
diff --git a/src/postgres-tools/wasix/CHANGELOG.md b/src/postgres-tools/wasix/CHANGELOG.md
new file mode 100644
index 000000000..bb67d71ca
--- /dev/null
+++ b/src/postgres-tools/wasix/CHANGELOG.md
@@ -0,0 +1,3 @@
+# Changelog
+
+This product carries forward the PostgreSQL utility packages previously released with liboliphaunt-wasix. Existing published versions remain in their original release history.
diff --git a/src/postgres-tools/wasix/README.md b/src/postgres-tools/wasix/README.md
new file mode 100644
index 000000000..da0721600
--- /dev/null
+++ b/src/postgres-tools/wasix/README.md
@@ -0,0 +1,27 @@
+# PostgreSQL WASIX tools
+
+This product packages `pg_dump` and `psql` for the WASIX executor. Its release version is independent of the runtime; each portable archive records the runtime version and PostgreSQL source fingerprint that produced its modules. AOT archives retain the compiler identity and module digests from their producer.
+
+From this directory:
+
+```sh
+moon run postgres-tools-wasix:package-portable
+moon run postgres-tools-wasix:package-aot
+moon run postgres-tools-wasix:build
+```
+
+These tasks build the core runtime first, then compile only `pg_dump` and `psql`. Their portable modules live in `target/postgres-tools/wasix/assets`; their AOT task serializes only those two modules into `target/postgres-tools/wasix/aot`. Building the runtime alone does not build these tools or extensions. To package already prepared outputs without rebuilding them:
+
+```sh
+bun tools/package-assets.mts --target portable
+bun tools/package-assets.mts --target aot
+bun tools/package-cargo-artifacts.mts --target portable
+```
+
+The AOT command uses the current host, or `AOT_TARGET`. Packaging rejects stale source fingerprints and modified binaries. Release aggregation collects portable and all four platform archives before calling `tools/package-carriers.mts`; a local Cargo packaging check can select only the targets available locally with repeated `--target` arguments.
+
+Archives and Cargo packages go to `target/postgres-tools/wasix` at the repository root. They contain tools and their notices; runtime, extensions, seeds and ICU are separate inputs to applications.
+
+Checkout Cargo carriers use those owner directories automatically. Custom inputs use
+`OLIPHAUNT_WASIX_TOOLS_ASSETS_DIR` and `OLIPHAUNT_WASIX_TOOLS_AOT_DIR`; the runtime
+SDK asset variables do not redirect tools.
diff --git a/src/postgres-tools/wasix/VERSION b/src/postgres-tools/wasix/VERSION
new file mode 100644
index 000000000..0c62199f1
--- /dev/null
+++ b/src/postgres-tools/wasix/VERSION
@@ -0,0 +1 @@
+0.2.1
diff --git a/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/Cargo.toml b/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/Cargo.toml
new file mode 100644
index 000000000..c1360acd5
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "oliphaunt-wasix-tools-aot-aarch64-apple-darwin"
+version = "0.2.1"
+edition = "2024"
+rust-version = "1.93"
+description = "Wasmer AOT pg_dump and psql artifacts for oliphaunt-wasix on aarch64-apple-darwin"
+repository = "https://github.com/f0rr0/oliphaunt"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_oliphaunt_wasix_tools_aot_macos_arm64"
+include = ["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+serde_json = "1"
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/README.md b/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/README.md
rename to src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/README.md
diff --git a/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/build-support.rs b/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/build-support.rs
new file mode 100644
index 000000000..1627cd212
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/build-support.rs
@@ -0,0 +1,303 @@
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
+const ARTIFACT_KIND: &str = "wasix-tools-aot";
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_TOOLS_AOT_DIR");
+
+    let target = env::var("CARGO_PKG_NAME")
+        .expect("CARGO_PKG_NAME is set by Cargo")
+        .strip_prefix("oliphaunt-wasix-tools-aot-")
+        .expect("AOT crate name starts with oliphaunt-wasix-tools-aot-")
+        .to_owned();
+    emit_expected_artifact_inputs(&target);
+
+    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
+        .join("generated_aot.rs");
+    if let Some(artifact_dir) = find_artifact_dir(&target) {
+        emit_rerun_directives(&artifact_dir);
+        write_generated_aot(&out, &target, &artifact_dir);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX tools AOT artifacts for {target}");
+    } else {
+        write_source_only_aot(&out, &target);
+    }
+}
+
+fn emit_expected_artifact_inputs(target: &str) {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        emit_manifest_probe(&candidate);
+    }
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_manifest_probe(
+            &repo_root
+                .join("target/postgres-tools/wasix/aot")
+                .join(target),
+        );
+    }
+    emit_manifest_probe(&manifest_dir.join("artifacts"));
+}
+
+fn emit_manifest_probe(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("manifest.json").display()
+    );
+}
+
+fn find_artifact_dir(target: &str) -> Option {
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let package_artifacts = manifest_dir.join("artifacts");
+    if package_artifacts.join("manifest.json").is_file() {
+        return Some(package_artifacts);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local artifacts");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        if candidate.join("manifest.json").is_file() {
+            return Some(candidate);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_artifacts = repo_root
+            .join("target/postgres-tools/wasix/aot")
+            .join(target);
+        if target_artifacts.join("manifest.json").is_file() {
+            return Some(target_artifacts);
+        }
+    }
+
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
+    manifest_dir.ancestors().find(|candidate| {
+        candidate.join("Cargo.toml").is_file()
+            && candidate.join("src/sdks/rust-wasix/Cargo.toml").is_file()
+    })
+}
+
+fn emit_rerun_directives(artifact_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", artifact_dir.display());
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        for entry in entries.flatten() {
+            let path = entry.path();
+            if path.is_file() {
+                println!("cargo:rerun-if-changed={}", path.display());
+            }
+        }
+    }
+}
+
+fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
+    let manifest = artifact_dir.join("manifest.json");
+    let generated_manifest = out
+        .parent()
+        .expect("generated AOT output has parent")
+        .join("manifest.json");
+    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
+    for relative in &retained_paths {
+        assert!(
+            artifact_dir.join(relative).is_file(),
+            "missing declared WASIX AOT artifact: {relative}"
+        );
+    }
+    let mut cases = String::new();
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        let mut files = entries
+            .flatten()
+            .map(|entry| entry.path())
+            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
+            .collect::>();
+        files.sort();
+        for file in files {
+            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
+                continue;
+            };
+            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
+                continue;
+            };
+            let artifact_name = artifact_name_from_file_stem(stem);
+            if !artifact_belongs_to_crate(&artifact_name) {
+                continue;
+            }
+            cases.push_str(&format!(
+                "        {:?} => Some(include_bytes!({})),\n",
+                artifact_name,
+                rust_string_literal(&file)
+            ));
+        }
+    }
+    cases.push_str("        _ => None,\n");
+
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = true;\n\
+         pub const MANIFEST_JSON: &str = include_str!({});\n\
+         #[rustfmt::skip]\n\
+         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
+             match name {{\n\
+         {cases}    }}\n\
+         }}\n",
+        target,
+        rust_string_literal(&generated_manifest)
+    );
+    fs::write(out, text).expect("write generated AOT include module");
+    let mut manifest_files = vec![generated_manifest];
+    for relative in retained_paths {
+        manifest_files.push(artifact_dir.join(relative));
+    }
+    emit_artifact_manifest(
+        out.parent().expect("generated AOT output has parent"),
+        target,
+        artifact_dir,
+        &manifest_files,
+    );
+}
+
+fn write_source_only_aot(out: &Path, target: &str) {
+    let manifest = format!(
+        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
+    );
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {target:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = false;\n\
+         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
+         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
+    );
+    fs::write(out, text).expect("write source-only AOT include module");
+}
+
+fn artifact_name_from_file_stem(stem: &str) -> String {
+    match stem {
+        "oliphaunt" => "runtime:oliphaunt".to_owned(),
+        "pg_dump" => "tool:pg_dump".to_owned(),
+        "psql" => "tool:psql".to_owned(),
+        "initdb" => "tool:initdb".to_owned(),
+        "plpgsql" => "runtime-support:plpgsql".to_owned(),
+        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
+        extension_support if extension_support.ends_with("_deps") => {
+            let sql_name = extension_support.trim_end_matches("_deps");
+            format!("extension:{sql_name}:{extension_support}")
+        }
+        extension => format!("extension:{extension}"),
+    }
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn artifact_belongs_to_crate(name: &str) -> bool {
+    match ARTIFACT_KIND {
+        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
+        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
+    }
+}
+
+fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
+    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
+    let mut manifest: serde_json::Value =
+        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
+    let artifacts = manifest
+        .get_mut("artifacts")
+        .and_then(|value| value.as_array_mut())
+        .expect("generated WASIX AOT manifest has artifacts array");
+    let mut retained = Vec::new();
+    let mut paths = Vec::new();
+    for artifact in artifacts.drain(..) {
+        let name = artifact
+            .get("name")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has name")
+            .to_owned();
+        if !artifact_belongs_to_crate(&name) {
+            continue;
+        }
+        let path = artifact
+            .get("path")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has path")
+            .to_owned();
+        paths.push(path);
+        retained.push(artifact);
+    }
+    *artifacts = retained;
+    let rendered =
+        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
+    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
+    paths
+}
+
+fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
+    );
+    for file in files {
+        if !file.is_file() {
+            continue;
+        }
+        let relative = file
+            .strip_prefix(artifact_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| "manifest.json".to_owned());
+        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/build.rs b/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/src/lib.rs b/src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/src/lib.rs
rename to src/postgres-tools/wasix/crates/aot/aarch64-apple-darwin/src/lib.rs
diff --git a/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/Cargo.toml b/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/Cargo.toml
new file mode 100644
index 000000000..de7274dd1
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu"
+version = "0.2.1"
+edition = "2024"
+rust-version = "1.93"
+description = "Wasmer AOT pg_dump and psql artifacts for oliphaunt-wasix on aarch64-unknown-linux-gnu"
+repository = "https://github.com/f0rr0/oliphaunt"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_oliphaunt_wasix_tools_aot_linux_arm64_gnu"
+include = ["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+serde_json = "1"
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/README.md b/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/README.md
rename to src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/README.md
diff --git a/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/build-support.rs b/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/build-support.rs
new file mode 100644
index 000000000..1627cd212
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/build-support.rs
@@ -0,0 +1,303 @@
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
+const ARTIFACT_KIND: &str = "wasix-tools-aot";
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_TOOLS_AOT_DIR");
+
+    let target = env::var("CARGO_PKG_NAME")
+        .expect("CARGO_PKG_NAME is set by Cargo")
+        .strip_prefix("oliphaunt-wasix-tools-aot-")
+        .expect("AOT crate name starts with oliphaunt-wasix-tools-aot-")
+        .to_owned();
+    emit_expected_artifact_inputs(&target);
+
+    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
+        .join("generated_aot.rs");
+    if let Some(artifact_dir) = find_artifact_dir(&target) {
+        emit_rerun_directives(&artifact_dir);
+        write_generated_aot(&out, &target, &artifact_dir);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX tools AOT artifacts for {target}");
+    } else {
+        write_source_only_aot(&out, &target);
+    }
+}
+
+fn emit_expected_artifact_inputs(target: &str) {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        emit_manifest_probe(&candidate);
+    }
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_manifest_probe(
+            &repo_root
+                .join("target/postgres-tools/wasix/aot")
+                .join(target),
+        );
+    }
+    emit_manifest_probe(&manifest_dir.join("artifacts"));
+}
+
+fn emit_manifest_probe(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("manifest.json").display()
+    );
+}
+
+fn find_artifact_dir(target: &str) -> Option {
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let package_artifacts = manifest_dir.join("artifacts");
+    if package_artifacts.join("manifest.json").is_file() {
+        return Some(package_artifacts);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local artifacts");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        if candidate.join("manifest.json").is_file() {
+            return Some(candidate);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_artifacts = repo_root
+            .join("target/postgres-tools/wasix/aot")
+            .join(target);
+        if target_artifacts.join("manifest.json").is_file() {
+            return Some(target_artifacts);
+        }
+    }
+
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
+    manifest_dir.ancestors().find(|candidate| {
+        candidate.join("Cargo.toml").is_file()
+            && candidate.join("src/sdks/rust-wasix/Cargo.toml").is_file()
+    })
+}
+
+fn emit_rerun_directives(artifact_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", artifact_dir.display());
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        for entry in entries.flatten() {
+            let path = entry.path();
+            if path.is_file() {
+                println!("cargo:rerun-if-changed={}", path.display());
+            }
+        }
+    }
+}
+
+fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
+    let manifest = artifact_dir.join("manifest.json");
+    let generated_manifest = out
+        .parent()
+        .expect("generated AOT output has parent")
+        .join("manifest.json");
+    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
+    for relative in &retained_paths {
+        assert!(
+            artifact_dir.join(relative).is_file(),
+            "missing declared WASIX AOT artifact: {relative}"
+        );
+    }
+    let mut cases = String::new();
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        let mut files = entries
+            .flatten()
+            .map(|entry| entry.path())
+            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
+            .collect::>();
+        files.sort();
+        for file in files {
+            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
+                continue;
+            };
+            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
+                continue;
+            };
+            let artifact_name = artifact_name_from_file_stem(stem);
+            if !artifact_belongs_to_crate(&artifact_name) {
+                continue;
+            }
+            cases.push_str(&format!(
+                "        {:?} => Some(include_bytes!({})),\n",
+                artifact_name,
+                rust_string_literal(&file)
+            ));
+        }
+    }
+    cases.push_str("        _ => None,\n");
+
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = true;\n\
+         pub const MANIFEST_JSON: &str = include_str!({});\n\
+         #[rustfmt::skip]\n\
+         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
+             match name {{\n\
+         {cases}    }}\n\
+         }}\n",
+        target,
+        rust_string_literal(&generated_manifest)
+    );
+    fs::write(out, text).expect("write generated AOT include module");
+    let mut manifest_files = vec![generated_manifest];
+    for relative in retained_paths {
+        manifest_files.push(artifact_dir.join(relative));
+    }
+    emit_artifact_manifest(
+        out.parent().expect("generated AOT output has parent"),
+        target,
+        artifact_dir,
+        &manifest_files,
+    );
+}
+
+fn write_source_only_aot(out: &Path, target: &str) {
+    let manifest = format!(
+        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
+    );
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {target:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = false;\n\
+         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
+         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
+    );
+    fs::write(out, text).expect("write source-only AOT include module");
+}
+
+fn artifact_name_from_file_stem(stem: &str) -> String {
+    match stem {
+        "oliphaunt" => "runtime:oliphaunt".to_owned(),
+        "pg_dump" => "tool:pg_dump".to_owned(),
+        "psql" => "tool:psql".to_owned(),
+        "initdb" => "tool:initdb".to_owned(),
+        "plpgsql" => "runtime-support:plpgsql".to_owned(),
+        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
+        extension_support if extension_support.ends_with("_deps") => {
+            let sql_name = extension_support.trim_end_matches("_deps");
+            format!("extension:{sql_name}:{extension_support}")
+        }
+        extension => format!("extension:{extension}"),
+    }
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn artifact_belongs_to_crate(name: &str) -> bool {
+    match ARTIFACT_KIND {
+        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
+        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
+    }
+}
+
+fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
+    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
+    let mut manifest: serde_json::Value =
+        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
+    let artifacts = manifest
+        .get_mut("artifacts")
+        .and_then(|value| value.as_array_mut())
+        .expect("generated WASIX AOT manifest has artifacts array");
+    let mut retained = Vec::new();
+    let mut paths = Vec::new();
+    for artifact in artifacts.drain(..) {
+        let name = artifact
+            .get("name")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has name")
+            .to_owned();
+        if !artifact_belongs_to_crate(&name) {
+            continue;
+        }
+        let path = artifact
+            .get("path")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has path")
+            .to_owned();
+        paths.push(path);
+        retained.push(artifact);
+    }
+    *artifacts = retained;
+    let rendered =
+        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
+    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
+    paths
+}
+
+fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
+    );
+    for file in files {
+        if !file.is_file() {
+            continue;
+        }
+        let relative = file
+            .strip_prefix(artifact_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| "manifest.json".to_owned());
+        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/build.rs b/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/src/lib.rs b/src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/src/lib.rs
rename to src/postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu/src/lib.rs
diff --git a/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/Cargo.toml b/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/Cargo.toml
new file mode 100644
index 000000000..1295730cf
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc"
+version = "0.2.1"
+edition = "2024"
+rust-version = "1.93"
+description = "Wasmer AOT pg_dump and psql artifacts for oliphaunt-wasix on x86_64-pc-windows-msvc"
+repository = "https://github.com/f0rr0/oliphaunt"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_oliphaunt_wasix_tools_aot_windows_x64_msvc"
+include = ["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+serde_json = "1"
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/README.md b/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/README.md
rename to src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/README.md
diff --git a/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/build-support.rs b/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/build-support.rs
new file mode 100644
index 000000000..1627cd212
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/build-support.rs
@@ -0,0 +1,303 @@
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
+const ARTIFACT_KIND: &str = "wasix-tools-aot";
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_TOOLS_AOT_DIR");
+
+    let target = env::var("CARGO_PKG_NAME")
+        .expect("CARGO_PKG_NAME is set by Cargo")
+        .strip_prefix("oliphaunt-wasix-tools-aot-")
+        .expect("AOT crate name starts with oliphaunt-wasix-tools-aot-")
+        .to_owned();
+    emit_expected_artifact_inputs(&target);
+
+    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
+        .join("generated_aot.rs");
+    if let Some(artifact_dir) = find_artifact_dir(&target) {
+        emit_rerun_directives(&artifact_dir);
+        write_generated_aot(&out, &target, &artifact_dir);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX tools AOT artifacts for {target}");
+    } else {
+        write_source_only_aot(&out, &target);
+    }
+}
+
+fn emit_expected_artifact_inputs(target: &str) {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        emit_manifest_probe(&candidate);
+    }
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_manifest_probe(
+            &repo_root
+                .join("target/postgres-tools/wasix/aot")
+                .join(target),
+        );
+    }
+    emit_manifest_probe(&manifest_dir.join("artifacts"));
+}
+
+fn emit_manifest_probe(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("manifest.json").display()
+    );
+}
+
+fn find_artifact_dir(target: &str) -> Option {
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let package_artifacts = manifest_dir.join("artifacts");
+    if package_artifacts.join("manifest.json").is_file() {
+        return Some(package_artifacts);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local artifacts");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        if candidate.join("manifest.json").is_file() {
+            return Some(candidate);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_artifacts = repo_root
+            .join("target/postgres-tools/wasix/aot")
+            .join(target);
+        if target_artifacts.join("manifest.json").is_file() {
+            return Some(target_artifacts);
+        }
+    }
+
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
+    manifest_dir.ancestors().find(|candidate| {
+        candidate.join("Cargo.toml").is_file()
+            && candidate.join("src/sdks/rust-wasix/Cargo.toml").is_file()
+    })
+}
+
+fn emit_rerun_directives(artifact_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", artifact_dir.display());
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        for entry in entries.flatten() {
+            let path = entry.path();
+            if path.is_file() {
+                println!("cargo:rerun-if-changed={}", path.display());
+            }
+        }
+    }
+}
+
+fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
+    let manifest = artifact_dir.join("manifest.json");
+    let generated_manifest = out
+        .parent()
+        .expect("generated AOT output has parent")
+        .join("manifest.json");
+    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
+    for relative in &retained_paths {
+        assert!(
+            artifact_dir.join(relative).is_file(),
+            "missing declared WASIX AOT artifact: {relative}"
+        );
+    }
+    let mut cases = String::new();
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        let mut files = entries
+            .flatten()
+            .map(|entry| entry.path())
+            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
+            .collect::>();
+        files.sort();
+        for file in files {
+            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
+                continue;
+            };
+            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
+                continue;
+            };
+            let artifact_name = artifact_name_from_file_stem(stem);
+            if !artifact_belongs_to_crate(&artifact_name) {
+                continue;
+            }
+            cases.push_str(&format!(
+                "        {:?} => Some(include_bytes!({})),\n",
+                artifact_name,
+                rust_string_literal(&file)
+            ));
+        }
+    }
+    cases.push_str("        _ => None,\n");
+
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = true;\n\
+         pub const MANIFEST_JSON: &str = include_str!({});\n\
+         #[rustfmt::skip]\n\
+         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
+             match name {{\n\
+         {cases}    }}\n\
+         }}\n",
+        target,
+        rust_string_literal(&generated_manifest)
+    );
+    fs::write(out, text).expect("write generated AOT include module");
+    let mut manifest_files = vec![generated_manifest];
+    for relative in retained_paths {
+        manifest_files.push(artifact_dir.join(relative));
+    }
+    emit_artifact_manifest(
+        out.parent().expect("generated AOT output has parent"),
+        target,
+        artifact_dir,
+        &manifest_files,
+    );
+}
+
+fn write_source_only_aot(out: &Path, target: &str) {
+    let manifest = format!(
+        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
+    );
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {target:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = false;\n\
+         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
+         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
+    );
+    fs::write(out, text).expect("write source-only AOT include module");
+}
+
+fn artifact_name_from_file_stem(stem: &str) -> String {
+    match stem {
+        "oliphaunt" => "runtime:oliphaunt".to_owned(),
+        "pg_dump" => "tool:pg_dump".to_owned(),
+        "psql" => "tool:psql".to_owned(),
+        "initdb" => "tool:initdb".to_owned(),
+        "plpgsql" => "runtime-support:plpgsql".to_owned(),
+        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
+        extension_support if extension_support.ends_with("_deps") => {
+            let sql_name = extension_support.trim_end_matches("_deps");
+            format!("extension:{sql_name}:{extension_support}")
+        }
+        extension => format!("extension:{extension}"),
+    }
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn artifact_belongs_to_crate(name: &str) -> bool {
+    match ARTIFACT_KIND {
+        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
+        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
+    }
+}
+
+fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
+    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
+    let mut manifest: serde_json::Value =
+        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
+    let artifacts = manifest
+        .get_mut("artifacts")
+        .and_then(|value| value.as_array_mut())
+        .expect("generated WASIX AOT manifest has artifacts array");
+    let mut retained = Vec::new();
+    let mut paths = Vec::new();
+    for artifact in artifacts.drain(..) {
+        let name = artifact
+            .get("name")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has name")
+            .to_owned();
+        if !artifact_belongs_to_crate(&name) {
+            continue;
+        }
+        let path = artifact
+            .get("path")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has path")
+            .to_owned();
+        paths.push(path);
+        retained.push(artifact);
+    }
+    *artifacts = retained;
+    let rendered =
+        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
+    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
+    paths
+}
+
+fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
+    );
+    for file in files {
+        if !file.is_file() {
+            continue;
+        }
+        let relative = file
+            .strip_prefix(artifact_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| "manifest.json".to_owned());
+        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/build.rs b/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/src/lib.rs b/src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/src/lib.rs
rename to src/postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc/src/lib.rs
diff --git a/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/Cargo.toml b/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/Cargo.toml
new file mode 100644
index 000000000..ff69cd56b
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu"
+version = "0.2.1"
+edition = "2024"
+rust-version = "1.93"
+description = "Wasmer AOT pg_dump and psql artifacts for oliphaunt-wasix on x86_64-unknown-linux-gnu"
+repository = "https://github.com/f0rr0/oliphaunt"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_oliphaunt_wasix_tools_aot_linux_x64_gnu"
+include = ["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+serde_json = "1"
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/README.md b/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/README.md
rename to src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/README.md
diff --git a/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/build-support.rs b/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/build-support.rs
new file mode 100644
index 000000000..1627cd212
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/build-support.rs
@@ -0,0 +1,303 @@
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
+const ARTIFACT_KIND: &str = "wasix-tools-aot";
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_TOOLS_AOT_DIR");
+
+    let target = env::var("CARGO_PKG_NAME")
+        .expect("CARGO_PKG_NAME is set by Cargo")
+        .strip_prefix("oliphaunt-wasix-tools-aot-")
+        .expect("AOT crate name starts with oliphaunt-wasix-tools-aot-")
+        .to_owned();
+    emit_expected_artifact_inputs(&target);
+
+    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
+        .join("generated_aot.rs");
+    if let Some(artifact_dir) = find_artifact_dir(&target) {
+        emit_rerun_directives(&artifact_dir);
+        write_generated_aot(&out, &target, &artifact_dir);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX tools AOT artifacts for {target}");
+    } else {
+        write_source_only_aot(&out, &target);
+    }
+}
+
+fn emit_expected_artifact_inputs(target: &str) {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        emit_manifest_probe(&candidate);
+    }
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_manifest_probe(
+            &repo_root
+                .join("target/postgres-tools/wasix/aot")
+                .join(target),
+        );
+    }
+    emit_manifest_probe(&manifest_dir.join("artifacts"));
+}
+
+fn emit_manifest_probe(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("manifest.json").display()
+    );
+}
+
+fn find_artifact_dir(target: &str) -> Option {
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let package_artifacts = manifest_dir.join("artifacts");
+    if package_artifacts.join("manifest.json").is_file() {
+        return Some(package_artifacts);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local artifacts");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        if candidate.join("manifest.json").is_file() {
+            return Some(candidate);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_artifacts = repo_root
+            .join("target/postgres-tools/wasix/aot")
+            .join(target);
+        if target_artifacts.join("manifest.json").is_file() {
+            return Some(target_artifacts);
+        }
+    }
+
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
+    manifest_dir.ancestors().find(|candidate| {
+        candidate.join("Cargo.toml").is_file()
+            && candidate.join("src/sdks/rust-wasix/Cargo.toml").is_file()
+    })
+}
+
+fn emit_rerun_directives(artifact_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", artifact_dir.display());
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        for entry in entries.flatten() {
+            let path = entry.path();
+            if path.is_file() {
+                println!("cargo:rerun-if-changed={}", path.display());
+            }
+        }
+    }
+}
+
+fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
+    let manifest = artifact_dir.join("manifest.json");
+    let generated_manifest = out
+        .parent()
+        .expect("generated AOT output has parent")
+        .join("manifest.json");
+    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
+    for relative in &retained_paths {
+        assert!(
+            artifact_dir.join(relative).is_file(),
+            "missing declared WASIX AOT artifact: {relative}"
+        );
+    }
+    let mut cases = String::new();
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        let mut files = entries
+            .flatten()
+            .map(|entry| entry.path())
+            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
+            .collect::>();
+        files.sort();
+        for file in files {
+            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
+                continue;
+            };
+            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
+                continue;
+            };
+            let artifact_name = artifact_name_from_file_stem(stem);
+            if !artifact_belongs_to_crate(&artifact_name) {
+                continue;
+            }
+            cases.push_str(&format!(
+                "        {:?} => Some(include_bytes!({})),\n",
+                artifact_name,
+                rust_string_literal(&file)
+            ));
+        }
+    }
+    cases.push_str("        _ => None,\n");
+
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = true;\n\
+         pub const MANIFEST_JSON: &str = include_str!({});\n\
+         #[rustfmt::skip]\n\
+         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
+             match name {{\n\
+         {cases}    }}\n\
+         }}\n",
+        target,
+        rust_string_literal(&generated_manifest)
+    );
+    fs::write(out, text).expect("write generated AOT include module");
+    let mut manifest_files = vec![generated_manifest];
+    for relative in retained_paths {
+        manifest_files.push(artifact_dir.join(relative));
+    }
+    emit_artifact_manifest(
+        out.parent().expect("generated AOT output has parent"),
+        target,
+        artifact_dir,
+        &manifest_files,
+    );
+}
+
+fn write_source_only_aot(out: &Path, target: &str) {
+    let manifest = format!(
+        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
+    );
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {target:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = false;\n\
+         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
+         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
+    );
+    fs::write(out, text).expect("write source-only AOT include module");
+}
+
+fn artifact_name_from_file_stem(stem: &str) -> String {
+    match stem {
+        "oliphaunt" => "runtime:oliphaunt".to_owned(),
+        "pg_dump" => "tool:pg_dump".to_owned(),
+        "psql" => "tool:psql".to_owned(),
+        "initdb" => "tool:initdb".to_owned(),
+        "plpgsql" => "runtime-support:plpgsql".to_owned(),
+        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
+        extension_support if extension_support.ends_with("_deps") => {
+            let sql_name = extension_support.trim_end_matches("_deps");
+            format!("extension:{sql_name}:{extension_support}")
+        }
+        extension => format!("extension:{extension}"),
+    }
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn artifact_belongs_to_crate(name: &str) -> bool {
+    match ARTIFACT_KIND {
+        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
+        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
+    }
+}
+
+fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
+    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
+    let mut manifest: serde_json::Value =
+        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
+    let artifacts = manifest
+        .get_mut("artifacts")
+        .and_then(|value| value.as_array_mut())
+        .expect("generated WASIX AOT manifest has artifacts array");
+    let mut retained = Vec::new();
+    let mut paths = Vec::new();
+    for artifact in artifacts.drain(..) {
+        let name = artifact
+            .get("name")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has name")
+            .to_owned();
+        if !artifact_belongs_to_crate(&name) {
+            continue;
+        }
+        let path = artifact
+            .get("path")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has path")
+            .to_owned();
+        paths.push(path);
+        retained.push(artifact);
+    }
+    *artifacts = retained;
+    let rendered =
+        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
+    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
+    paths
+}
+
+fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
+    );
+    for file in files {
+        if !file.is_file() {
+            continue;
+        }
+        let relative = file
+            .strip_prefix(artifact_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| "manifest.json".to_owned());
+        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/build.rs b/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/src/lib.rs b/src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/src/lib.rs
rename to src/postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu/src/lib.rs
diff --git a/src/postgres-tools/wasix/crates/tools/Cargo.toml b/src/postgres-tools/wasix/crates/tools/Cargo.toml
new file mode 100644
index 000000000..2b28b52d7
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/tools/Cargo.toml
@@ -0,0 +1,30 @@
+[package]
+name = "oliphaunt-wasix-tools"
+version = "0.2.1"
+edition = "2024"
+rust-version = "1.93"
+description = "WASIX pg_dump and psql assets for oliphaunt-wasix"
+repository = "https://github.com/f0rr0/oliphaunt"
+homepage = "https://oliphaunt.dev"
+documentation = "https://docs.rs/oliphaunt-wasix-tools"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_oliphaunt_wasix_tools"
+include = [
+  "Cargo.toml",
+  "build.rs", "build-support.rs",
+  "README.md",
+  "src/**",
+  "payload/**",
+  "LICENSE",
+  "THIRD_PARTY_NOTICES.md",
+  "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
+  "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
+  "THIRD_PARTY_LICENSES/ICU-LICENSE",
+]
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools/README.md b/src/postgres-tools/wasix/crates/tools/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools/README.md
rename to src/postgres-tools/wasix/crates/tools/README.md
diff --git a/src/postgres-tools/wasix/crates/tools/build-support.rs b/src/postgres-tools/wasix/crates/tools/build-support.rs
new file mode 100644
index 000000000..40e2a351a
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/tools/build-support.rs
@@ -0,0 +1,199 @@
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
+const ARTIFACT_KIND: &str = "wasix-tools";
+const ARTIFACT_TARGET: &str = "portable";
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_TOOLS_ASSETS_DIR");
+    emit_expected_asset_inputs();
+
+    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"));
+    let out = out_dir.join("generated_tools.rs");
+    if let Some(asset_dir) = find_asset_dir() {
+        emit_rerun_directives(&asset_dir);
+        write_generated_tools(&out, &asset_dir);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX tools payload");
+    } else {
+        write_source_only_tools(&out);
+    }
+}
+
+fn emit_expected_asset_inputs() {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_ASSETS_DIR") {
+        emit_tool_probes(&PathBuf::from(path));
+    }
+
+    let manifest_dir =
+        PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set"));
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_tool_probes(&repo_root.join("target/postgres-tools/wasix/assets"));
+    }
+    emit_tool_probes(&manifest_dir.join("payload"));
+}
+
+fn emit_tool_probes(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("bin/pg_dump.wasix.wasm").display()
+    );
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("bin/psql.wasix.wasm").display()
+    );
+}
+
+fn find_asset_dir() -> Option {
+    let manifest_dir =
+        PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set"));
+    let package_payload = manifest_dir.join("payload");
+    if package_payload.join("bin/pg_dump.wasix.wasm").is_file()
+        && package_payload.join("bin/psql.wasix.wasm").is_file()
+    {
+        return Some(package_payload);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local payload");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_TOOLS_ASSETS_DIR") {
+        let path = PathBuf::from(path);
+        if path.join("bin/pg_dump.wasix.wasm").is_file()
+            && path.join("bin/psql.wasix.wasm").is_file()
+        {
+            return Some(path);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_assets = repo_root.join("target/postgres-tools/wasix/assets");
+        if target_assets.join("bin/pg_dump.wasix.wasm").is_file()
+            && target_assets.join("bin/psql.wasix.wasm").is_file()
+        {
+            return Some(target_assets);
+        }
+    }
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option {
+    for ancestor in manifest_dir.ancestors() {
+        if ancestor.join(".git").exists() && ancestor.join("Cargo.toml").is_file() {
+            return Some(ancestor.to_path_buf());
+        }
+    }
+    None
+}
+
+fn emit_rerun_directives(asset_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", asset_dir.display());
+    visit_files(asset_dir, &mut |path| {
+        println!("cargo:rerun-if-changed={}", path.display());
+    });
+}
+
+fn visit_files(path: &Path, f: &mut impl FnMut(&Path)) {
+    let Ok(entries) = fs::read_dir(path) else {
+        return;
+    };
+    for entry in entries.flatten() {
+        let path = entry.path();
+        if path.is_dir() {
+            visit_files(&path, f);
+        } else if path.is_file() {
+            f(&path);
+        }
+    }
+}
+
+fn write_generated_tools(out: &Path, asset_dir: &Path) {
+    let pg_dump = asset_dir.join("bin/pg_dump.wasix.wasm");
+    let psql = asset_dir.join("bin/psql.wasix.wasm");
+    for required in [&pg_dump, &psql] {
+        assert!(
+            required.is_file(),
+            "generated WASIX tools directory {} is missing required file {}",
+            asset_dir.display(),
+            required.display()
+        );
+    }
+    let text = format!(
+        "pub const HAS_EMBEDDED_TOOLS: bool = true;\n\
+         pub fn pg_dump_wasm() -> Option<&'static [u8]> {{ Some(include_bytes!({pg_dump})) }}\n\
+         pub fn psql_wasm() -> Option<&'static [u8]> {{ Some(include_bytes!({psql})) }}\n",
+        pg_dump = rust_string_literal(&pg_dump),
+        psql = rust_string_literal(&psql),
+    );
+    fs::write(out, text).expect("write generated WASIX tool include module");
+    emit_artifact_manifest(
+        out.parent().expect("generated tool output has parent"),
+        asset_dir,
+        &[&pg_dump, &psql],
+    );
+}
+
+fn write_source_only_tools(out: &Path) {
+    fs::write(
+        out,
+        "pub const HAS_EMBEDDED_TOOLS: bool = false;\n\
+         pub fn pg_dump_wasm() -> Option<&'static [u8]> { None }\n\
+         pub fn psql_wasm() -> Option<&'static [u8]> { None }\n",
+    )
+    .expect("write source-only WASIX tool include module");
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn emit_artifact_manifest(out_dir: &Path, asset_dir: &Path, files: &[&Path]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {ARTIFACT_TARGET:?}\n"
+    );
+    for file in files {
+        let relative = file
+            .strip_prefix(asset_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| {
+                file.file_name()
+                    .unwrap_or_default()
+                    .to_string_lossy()
+                    .into_owned()
+            });
+        let sha256 = sha256_file(file).expect("hash WASIX tools artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX tools Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/postgres-tools/wasix/crates/tools/build.rs b/src/postgres-tools/wasix/crates/tools/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/postgres-tools/wasix/crates/tools/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools/src/lib.rs b/src/postgres-tools/wasix/crates/tools/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools/src/lib.rs
rename to src/postgres-tools/wasix/crates/tools/src/lib.rs
diff --git a/src/postgres-tools/wasix/moon.yml b/src/postgres-tools/wasix/moon.yml
new file mode 100644
index 000000000..5b4ead7cd
--- /dev/null
+++ b/src/postgres-tools/wasix/moon.yml
@@ -0,0 +1,103 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+id: "postgres-tools-wasix"
+language: "unknown"
+layer: "tool"
+stack: "systems"
+tags: ["postgres", "tools", "release-product"]
+dependsOn:
+  - id: "liboliphaunt-wasix"
+    scope: "build"
+project:
+  title: "PostgreSQL WASIX tools"
+  owner: "oliphaunt"
+  release:
+    component: "postgres-tools-wasix"
+    packagePath: "src/postgres-tools/wasix"
+    artifactTargets:
+      preset: "postgres-tools-wasix"
+      targets: ["portable", "linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"]
+fileGroups:
+  sources: ["**/*", "!**/node_modules/**/*", "!**/target/**/*"]
+  cargo-carrier-sources: ["crates/**/*.rs", "crates/**/Cargo.toml"]
+tasks:
+  test:
+    command: "bash src/postgres-tools/wasix/tools/test-packaging.sh"
+    tags: ["quality", "unit"]
+    inputs: ["tools/**/*", "npm/**/*", "cargo/**/*", "/src/runtimes/liboliphaunt-wasix/tools/*.mts", "/tools/packaging/**/*", "@group(release-target-contract)", "@group(legal-files)"]
+    options: {runFromWorkspaceRoot: true}
+  compiler-output:
+    tags: ["artifact", "ci-liboliphaunt-wasix-runtime"]
+    command: "bash src/postgres-tools/wasix/tools/build-portable.sh"
+    deps: ["liboliphaunt-wasix:runtime-portable"]
+    inputs: ["tools/build-portable.sh", "/src/runtimes/liboliphaunt-wasix/assets/build/docker_{pgdump,psql}.sh", "/src/runtimes/liboliphaunt-wasix/tools/xtask/**/*"]
+    outputs: ["/target/postgres-tools/wasix/assets/**/*"]
+    options: {runFromWorkspaceRoot: true, cache: local}
+  build-aot:
+    command: "bash src/postgres-tools/wasix/tools/build-aot.sh"
+    deps: ["compiler-output"]
+    tags: ["artifact", "ci-liboliphaunt-wasix-aot"]
+    inputs: ["tools/build-aot.sh", "/src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh", "/src/runtimes/liboliphaunt-wasix/tools/xtask/**/*", "$AOT_TARGET"]
+    outputs: ["/target/postgres-tools/wasix/aot/**/*"]
+    options: {runFromWorkspaceRoot: true, cache: local}
+  package-portable:
+    command: "bash tools/ci/with-projects.sh src/postgres-tools/wasix/tools/package-assets.mts --target portable"
+    deps: ["compiler-output"]
+    tags: ["artifact", "ci-liboliphaunt-wasix-runtime"]
+    inputs: ["VERSION", "tools/package-assets.mts", "/tools/packaging/**/*", "/src/runtimes/liboliphaunt-wasix/tools/{check-release-assets.mts,package-release-assets.mts,wasix-aot-manifest.mts,wasix-cargo-artifact-contract.mts}"]
+    outputs: ["/target/postgres-tools/wasix/release-assets/*-portable.tar.gz"]
+    options:
+      runInCI: true
+      runFromWorkspaceRoot: true
+  package-aot:
+    command: "bash tools/ci/with-projects.sh src/postgres-tools/wasix/tools/package-assets.mts --target aot"
+    deps: ["build-aot"]
+    tags: ["artifact", "ci-liboliphaunt-wasix-aot"]
+    inputs: ["VERSION", "tools/package-assets.mts", "/tools/packaging/**/*", "/src/runtimes/liboliphaunt-wasix/tools/{check-release-assets.mts,package-release-assets.mts,wasix-aot-manifest.mts,wasix-cargo-artifact-contract.mts}", "$AOT_TARGET"]
+    outputs: ["/target/postgres-tools/wasix/release-assets/*-aot-*.tar.gz"]
+    options:
+      runInCI: true
+      runFromWorkspaceRoot: true
+  build:
+    command: "bash tools/ci/with-projects.sh src/postgres-tools/wasix/tools/build-npm.mts"
+    deps: ["package-portable"]
+    inputs: ["npm/**/*", "tools/build-npm.mts", "tools/wasix-tools-npm-carrier.mts"]
+    outputs: ["/target/postgres-tools/wasix/npm/**/*"]
+    options: {runFromWorkspaceRoot: true}
+  test-consumer:
+    tags: ["integration", "consumer", "ci-wasix-ts-sdk-package"]
+    command: "bash tools/ci/with-projects.sh --exec bash src/postgres-tools/wasix/ts/tests/consumer.sh"
+    deps: ["oliphaunt-wasix-tools-ts:package", "oliphaunt-wasix-ts:package", "oliphaunt-wasix-napi:build-release-assets", "postgres-tools-wasix:package-portable", "postgres-tools-wasix:package-aot"]
+    inputs: ["ts/tests/**/*", "/src/sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts", "/src/sdks/ts-wasix/sdk/tools/pgwire-client.mts", "/src/test-fixtures/postgres/**/*", "tools/*.mts"]
+    options: {cache: false, runFromWorkspaceRoot: true}
+  test-browser:
+    tags: ["integration", "browser", "ci-wasix-ts-sdk-package"]
+    command: "bash tools/ci/with-projects.sh --exec bash src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh --package-only --tools"
+    deps: ["oliphaunt-wasix-tools-ts:package", "oliphaunt-wasix-ts:package", "postgres-tools-wasix:package-portable"]
+    inputs: ["ts/tests/**/*", "/src/sdks/ts-wasix/sdk/tools/integration/{packed-node-fixture.mts,smoke-browser.*}", "/src/test-fixtures/postgres/**/*", "tools/*.mts"]
+    options: {cache: false, runFromWorkspaceRoot: true}
+  format-check:
+    tags:
+      - quality
+      - static
+      - format
+      - requires-rust
+    command: cargo fmt -p oliphaunt-wasix-tools -p oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu -p oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu -p oliphaunt-wasix-tools-aot-aarch64-apple-darwin -p oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc --check
+    inputs:
+      - "@group(cargo-carrier-sources)"
+      - "@group(cargo-workspace)"
+    options:
+      runFromWorkspaceRoot: true
+  lint:
+    tags:
+      - quality
+      - static
+      - requires-rust
+    command: cargo clippy -p oliphaunt-wasix-tools -p oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu -p oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu -p oliphaunt-wasix-tools-aot-aarch64-apple-darwin -p oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc --all-targets --locked -- -D warnings
+    env:
+      CARGO_TARGET_DIR: target
+    inputs:
+      - "@group(cargo-carrier-sources)"
+      - "@group(cargo-workspace)"
+      - /clippy.toml
+    options:
+      runFromWorkspaceRoot: true
diff --git a/src/postgres-tools/wasix/npm-platforms/darwin-arm64/package.json b/src/postgres-tools/wasix/npm-platforms/darwin-arm64/package.json
new file mode 100644
index 000000000..0eb95c34a
--- /dev/null
+++ b/src/postgres-tools/wasix/npm-platforms/darwin-arm64/package.json
@@ -0,0 +1,16 @@
+{
+  "name": "@oliphaunt/liboliphaunt-wasix-tools-darwin-arm64",
+  "version": "0.2.1",
+  "private": true,
+  "type": "module",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0",
+  "os": [
+    "darwin"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/postgres-tools/wasix/npm-platforms/linux-arm64-gnu/package.json b/src/postgres-tools/wasix/npm-platforms/linux-arm64-gnu/package.json
new file mode 100644
index 000000000..5c6447d5c
--- /dev/null
+++ b/src/postgres-tools/wasix/npm-platforms/linux-arm64-gnu/package.json
@@ -0,0 +1,19 @@
+{
+  "name": "@oliphaunt/liboliphaunt-wasix-tools-linux-arm64-gnu",
+  "version": "0.2.1",
+  "private": true,
+  "type": "module",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0",
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/postgres-tools/wasix/npm-platforms/linux-x64-gnu/package.json b/src/postgres-tools/wasix/npm-platforms/linux-x64-gnu/package.json
new file mode 100644
index 000000000..240379149
--- /dev/null
+++ b/src/postgres-tools/wasix/npm-platforms/linux-x64-gnu/package.json
@@ -0,0 +1,19 @@
+{
+  "name": "@oliphaunt/liboliphaunt-wasix-tools-linux-x64-gnu",
+  "version": "0.2.1",
+  "private": true,
+  "type": "module",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0",
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/postgres-tools/wasix/npm-platforms/win32-x64-msvc/package.json b/src/postgres-tools/wasix/npm-platforms/win32-x64-msvc/package.json
new file mode 100644
index 000000000..46aa9ed12
--- /dev/null
+++ b/src/postgres-tools/wasix/npm-platforms/win32-x64-msvc/package.json
@@ -0,0 +1,16 @@
+{
+  "name": "@oliphaunt/liboliphaunt-wasix-tools-win32-x64-msvc",
+  "version": "0.2.1",
+  "private": true,
+  "type": "module",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0",
+  "os": [
+    "win32"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/liboliphaunt/wasix/tools-npm/README.md b/src/postgres-tools/wasix/npm/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/tools-npm/README.md
rename to src/postgres-tools/wasix/npm/README.md
diff --git a/src/runtimes/liboliphaunt/wasix/tools-npm/index.d.ts b/src/postgres-tools/wasix/npm/index.d.ts
similarity index 89%
rename from src/runtimes/liboliphaunt/wasix/tools-npm/index.d.ts
rename to src/postgres-tools/wasix/npm/index.d.ts
index 85e965a1c..e0e34411f 100644
--- a/src/runtimes/liboliphaunt/wasix/tools-npm/index.d.ts
+++ b/src/postgres-tools/wasix/npm/index.d.ts
@@ -3,6 +3,7 @@ export type WasixToolModule = Readonly<{
   sha256: string;
   size: number;
   source: string;
+  aot?: Readonly<{ source: string; manifest: string }>;
 }>;
 
 export type WasixToolsDescriptor = Readonly<{
diff --git a/src/postgres-tools/wasix/npm/index.mts b/src/postgres-tools/wasix/npm/index.mts
new file mode 100644
index 000000000..02c8da622
--- /dev/null
+++ b/src/postgres-tools/wasix/npm/index.mts
@@ -0,0 +1,2 @@
+// Produced from the tools owner archive by postgres-tools-wasix:build.
+export { default } from '../../../../../target/postgres-tools/wasix/npm/portable/index.js';
diff --git a/src/postgres-tools/wasix/npm/native.mts b/src/postgres-tools/wasix/npm/native.mts
new file mode 100644
index 000000000..90bc794fc
--- /dev/null
+++ b/src/postgres-tools/wasix/npm/native.mts
@@ -0,0 +1,46 @@
+import { readFileSync } from 'node:fs';
+import { createRequire } from 'node:module';
+import { dirname, join } from 'node:path';
+import { pathToFileURL } from 'node:url';
+import portable from './index.js';
+
+const require = createRequire(import.meta.url);
+const targets = {
+  'linux-arm64': 'linux-arm64-gnu',
+  'linux-x64': 'linux-x64-gnu',
+  'darwin-arm64': 'darwin-arm64',
+  'win32-x64': 'win32-x64-msvc',
+};
+const target = targets[`${process.platform}-${process.arch}`];
+if (!target)
+  throw new Error(`WASIX PostgreSQL tools do not support ${process.platform}/${process.arch}`);
+const root = dirname(require.resolve(`@oliphaunt/liboliphaunt-wasix-tools-${target}/package.json`));
+const carrier = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
+if (carrier.version !== portable.version)
+  throw new Error('WASIX tools AOT carrier version differs from the portable tools package');
+const manifestFile = join(root, 'assets/manifest.json');
+const manifest = JSON.parse(readFileSync(manifestFile, 'utf8'));
+const tool = (descriptor) => {
+  const artifact = manifest.artifacts.find(({ name }) => name === `tool:${descriptor.name}`);
+  if (
+    !artifact ||
+    typeof artifact.path !== 'string' ||
+    artifact.path.includes('..') ||
+    artifact.path.includes('/') ||
+    artifact.path.includes('\\')
+  ) {
+    throw new Error(`WASIX tools AOT carrier is missing ${descriptor.name}`);
+  }
+  return Object.freeze({
+    ...descriptor,
+    aot: Object.freeze({
+      source: pathToFileURL(join(root, 'assets', artifact.path)).href,
+      manifest: pathToFileURL(manifestFile).href,
+    }),
+  });
+};
+export default Object.freeze({
+  ...portable,
+  pgDump: tool(portable.pgDump),
+  psql: tool(portable.psql),
+});
diff --git a/src/postgres-tools/wasix/npm/package.json b/src/postgres-tools/wasix/npm/package.json
new file mode 100644
index 000000000..723fdd862
--- /dev/null
+++ b/src/postgres-tools/wasix/npm/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "@oliphaunt/liboliphaunt-wasix-tools",
+  "version": "0.2.1",
+  "description": "Portable WASIX pg_dump and psql modules for Oliphaunt hosts.",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0",
+  "type": "module",
+  "sideEffects": false,
+  "private": true,
+  "exports": {
+    ".": {
+      "types": "./index.d.ts",
+      "browser": "./index.mts",
+      "node": "./native.mts",
+      "bun": "./native.mts",
+      "deno": "./native.mts",
+      "default": "./index.mts"
+    },
+    "./package.json": "./package.json"
+  },
+  "optionalDependencies": {
+    "@oliphaunt/liboliphaunt-wasix-tools-linux-arm64-gnu": "workspace:*",
+    "@oliphaunt/liboliphaunt-wasix-tools-linux-x64-gnu": "workspace:*",
+    "@oliphaunt/liboliphaunt-wasix-tools-darwin-arm64": "workspace:*",
+    "@oliphaunt/liboliphaunt-wasix-tools-win32-x64-msvc": "workspace:*"
+  },
+  "oliphaunt": {
+    "runtimeVersion": "0.2.0"
+  }
+}
diff --git a/src/postgres-tools/wasix/release.toml b/src/postgres-tools/wasix/release.toml
new file mode 100644
index 000000000..cf4746f05
--- /dev/null
+++ b/src/postgres-tools/wasix/release.toml
@@ -0,0 +1,28 @@
+id = "postgres-tools-wasix"
+owner = "@oliphaunt/core"
+kind = "postgres-tools"
+publish_targets = ["github-release-assets", "crates-io", "npm"]
+registry_packages = [
+  "npm:@oliphaunt/liboliphaunt-wasix-tools-win32-x64-msvc",
+  "npm:@oliphaunt/liboliphaunt-wasix-tools-darwin-arm64",
+  "npm:@oliphaunt/liboliphaunt-wasix-tools-linux-x64-gnu",
+  "npm:@oliphaunt/liboliphaunt-wasix-tools-linux-arm64-gnu",
+  "crates:oliphaunt-wasix-tools",
+  "crates:oliphaunt-wasix-tools-aot-aarch64-apple-darwin",
+  "crates:oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu",
+  "crates:oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc",
+  "crates:oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu",
+  "npm:@oliphaunt/liboliphaunt-wasix-tools",
+  "npm:@oliphaunt/wasix-tools",
+]
+release_artifacts = ["postgres-tools", "npm-package"]
+
+[compatibility_versions.oliphaunt-wasix-tools-runtime]
+source_product = "liboliphaunt-wasix"
+path = "src/postgres-tools/wasix/ts/package.json"
+parser = "json:oliphaunt.runtimeVersion"
+
+[compatibility_versions.oliphaunt-wasix-tools-carrier-runtime]
+source_product = "liboliphaunt-wasix"
+path = "src/postgres-tools/wasix/npm/package.json"
+parser = "json:oliphaunt.runtimeVersion"
diff --git a/src/postgres-tools/wasix/tools/build-aot.sh b/src/postgres-tools/wasix/tools/build-aot.sh
new file mode 100644
index 000000000..d521dde5b
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/build-aot.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+export OLIPHAUNT_WASM_BUILD_PROFILE="${ASSET_PROFILE:-release}"
+target="${AOT_TARGET:-$(rustc -vV | awk '/^host:/{print $2}')}"
+host="$(rustc -vV | awk '/^host:/{print $2}')"
+[ "$target" = "$host" ] || { echo "AOT target $target requires its matching builder host, got $host" >&2; exit 1; }
+bash src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh --target-triple "$target" --product tools
+cargo run -p xtask --locked -- assets package-aot --target-triple "$target" --product tools
diff --git a/src/postgres-tools/wasix/tools/build-npm.mts b/src/postgres-tools/wasix/tools/build-npm.mts
new file mode 100644
index 000000000..ad68a8e0b
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/build-npm.mts
@@ -0,0 +1,15 @@
+import path from 'node:path';
+import {
+  currentProductVersionSync,
+  ROOT,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { stageWasixToolsNpmCarrier } from './wasix-tools-npm-carrier.mts';
+const version = currentProductVersionSync('postgres-tools-wasix', 'build-npm.mts');
+stageWasixToolsNpmCarrier({
+  version,
+  portableReleaseArchive: path.join(
+    ROOT,
+    `target/postgres-tools/wasix/release-assets/postgres-tools-wasix-${version}-portable.tar.gz`,
+  ),
+  packageDir: path.join(ROOT, 'target/postgres-tools/wasix/npm/portable'),
+});
diff --git a/src/postgres-tools/wasix/tools/build-portable.sh b/src/postgres-tools/wasix/tools/build-portable.sh
new file mode 100644
index 000000000..717cd9594
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/build-portable.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+export OLIPHAUNT_WASM_BUILD_PROFILE="${ASSET_PROFILE:-release}"
+for tool in pgdump psql; do
+  bash "src/runtimes/liboliphaunt-wasix/assets/build/docker_$tool.sh"
+done
+cargo run -p xtask --locked -- assets package-tools
diff --git a/src/postgres-tools/wasix/tools/package-assets.mts b/src/postgres-tools/wasix/tools/package-assets.mts
new file mode 100644
index 000000000..09736c458
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/package-assets.mts
@@ -0,0 +1,185 @@
+#!/usr/bin/env bun
+import { createHash } from 'node:crypto';
+import { copyFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { parseArgs } from 'node:util';
+import { assertWasixAotArtifactPayloads } from '../../../runtimes/liboliphaunt-wasix/tools/check-release-assets.mts';
+import { validateAotPayload } from '../../../runtimes/liboliphaunt-wasix/tools/package_liboliphaunt_wasix_cargo_artifacts.mts';
+import { postgresSourceFingerprint } from '../../../runtimes/liboliphaunt-wasix/tools/package-release-assets.mts';
+import { assertCanonicalWasixAotManifest } from '../../../runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts';
+import { AOT_TARGET_TRIPLES } from '../../../runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts';
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import { canonicalGzipSync } from '../../../../tools/packaging/portable-archive.mts';
+import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts';
+import { currentProductVersionSync } from '../../../../tools/release/release-artifact-targets.mts';
+
+export const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
+export const PORTABLE_SCHEMA = 'postgres-tools-wasix-portable-v1';
+export function fail(message) {
+  throw new Error(message);
+}
+export function sha256(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+export function readJson(file) {
+  return JSON.parse(readFileSync(file, 'utf8'));
+}
+
+export function validateToolsAotPayload(root, triple) {
+  const manifest = readJson(path.join(root, 'manifest.json'));
+  assertSource(manifest);
+  const names = manifest.artifacts?.map((row) => row.name).sort();
+  if (JSON.stringify(names) !== JSON.stringify(['tool:pg_dump', 'tool:psql']))
+    fail('WASIX tools AOT archive must contain exactly pg_dump and psql');
+  validateAotPayload(root, triple);
+  return manifest;
+}
+
+export function validatePortableToolsPayload(root, version) {
+  const manifest = readJson(path.join(root, 'manifest.json'));
+  if (
+    manifest.schema !== PORTABLE_SCHEMA ||
+    manifest.version !== version ||
+    manifest.runtimeVersion !== currentProductVersionSync('liboliphaunt-wasix') ||
+    manifest.sourceFingerprint !== postgresSourceFingerprint()
+  )
+    fail('WASIX tools portable archive has incompatible producer identity');
+  for (const [key, name] of [
+    ['pgDump', 'pg_dump'],
+    ['psql', 'psql'],
+  ]) {
+    const row = manifest[key];
+    const relative = `bin/${name}.wasix.wasm`;
+    const bytes = readFileSync(path.join(root, relative));
+    if (
+      row?.path !== relative ||
+      row.name !== name ||
+      row.sha256 !== sha256(bytes) ||
+      row.size !== bytes.length
+    )
+      fail(`WASIX ${name} archive bytes do not match its manifest`);
+  }
+  return manifest;
+}
+
+function assertSource(manifest) {
+  if (
+    manifest['source-lane'] !== 'stable' ||
+    manifest['source-fingerprint'] !== postgresSourceFingerprint()
+  ) {
+    fail(
+      'WASIX tools inputs do not match the current PostgreSQL source fingerprint; rebuild the producer',
+    );
+  }
+}
+
+export function stagePortableTools(source, destination, version) {
+  const input = readJson(path.join(source, 'manifest.json'));
+  assertSource(input);
+  const manifest = {
+    schema: PORTABLE_SCHEMA,
+    version,
+    runtimeVersion: currentProductVersionSync('liboliphaunt-wasix'),
+    sourceFingerprint: input['source-fingerprint'],
+  };
+  mkdirSync(path.join(destination, 'bin'), { recursive: true });
+  for (const [key, sourceKey, name] of [
+    ['pgDump', 'pg-dump', 'pg_dump'],
+    ['psql', 'psql', 'psql'],
+  ]) {
+    const relative = `bin/${name}.wasix.wasm`;
+    const bytes = readFileSync(path.join(source, relative));
+    const row = input[sourceKey];
+    if (row?.path !== relative || row.sha256 !== sha256(bytes) || row.size !== bytes.length) {
+      fail(`WASIX ${name} bytes do not match the producing manifest`);
+    }
+    writeFileSync(path.join(destination, relative), bytes);
+    manifest[key] = { name, path: relative, sha256: row.sha256, size: bytes.length };
+  }
+  writeFileSync(path.join(destination, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
+  stageReleaseNotices(destination, { profile: 'wasix-tools' });
+  return manifest;
+}
+
+export function stageAotTools(source, destination, triple) {
+  const manifest = readJson(path.join(source, 'manifest.json'));
+  assertSource(manifest);
+  assertCanonicalWasixAotManifest(manifest, { context: source, expectedTarget: triple });
+  const selected = {
+    ...manifest,
+    artifacts: manifest.artifacts.filter((row) => ['tool:pg_dump', 'tool:psql'].includes(row.name)),
+  };
+  if (
+    selected.artifacts.length !== 2 ||
+    new Set(selected.artifacts.map((row) => row.name)).size !== 2
+  )
+    fail('WASIX AOT tools require pg_dump and psql');
+  const rows = assertWasixAotArtifactPayloads(selected, {
+    context: source,
+    readArtifact: (relative) => readFileSync(path.join(source, relative)),
+  });
+  mkdirSync(destination, { recursive: true });
+  for (const row of rows) {
+    const file = path.join(destination, row.path);
+    mkdirSync(path.dirname(file), { recursive: true });
+    copyFileSync(path.join(source, row.path), file);
+  }
+  writeFileSync(path.join(destination, 'manifest.json'), `${JSON.stringify(selected, null, 2)}\n`);
+  stageReleaseNotices(destination, { profile: 'wasix-aot' });
+}
+
+export function packageWasixToolsAssets(argv) {
+  const { values } = parseArgs({
+    args: argv,
+    options: {
+      target: { type: 'string', default: 'portable' },
+      source: { type: 'string' },
+      version: { type: 'string', default: currentProductVersionSync('postgres-tools-wasix') },
+      'output-dir': { type: 'string', default: 'target/postgres-tools/wasix/release-assets' },
+    },
+  });
+  if (values.target === 'aot') {
+    const requested = process.env.AOT_TARGET;
+    values.target = requested
+      ? (Object.keys(AOT_TARGET_TRIPLES).find((key) => AOT_TARGET_TRIPLES[key] === requested) ??
+        requested)
+      : {
+          linux: `linux-${process.arch}-gnu`,
+          darwin: `macos-${process.arch}`,
+          win32: `windows-${process.arch}-msvc`,
+        }[process.platform];
+  }
+  const triple = AOT_TARGET_TRIPLES[values.target];
+  if (values.target !== 'portable' && !triple)
+    fail(`unsupported WASIX tools target ${values.target}`);
+  const output = path.resolve(ROOT, values['output-dir']);
+  const stage = path.join(output, `.stage-${values.target}`);
+  rmSync(stage, { recursive: true, force: true });
+  mkdirSync(stage, { recursive: true });
+  try {
+    const source = path.resolve(
+      ROOT,
+      values.source ??
+        (triple
+          ? `target/postgres-tools/wasix/aot/${triple}`
+          : 'target/postgres-tools/wasix/assets'),
+    );
+    if (triple) stageAotTools(source, stage, triple);
+    else stagePortableTools(source, stage, values.version);
+    const archive = path.join(
+      output,
+      `postgres-tools-wasix-${values.version}-${triple ? `aot-${values.target}` : 'portable'}.tar.gz`,
+    );
+    writeFileSync(
+      archive,
+      canonicalGzipSync(createDeterministicTar(stage, '.', { fail, fixedFileMode: 0o644 })),
+    );
+    console.log(archive);
+    return archive;
+  } finally {
+    rmSync(stage, { recursive: true, force: true });
+  }
+}
+
+if (import.meta.main) packageWasixToolsAssets(Bun.argv.slice(2));
diff --git a/src/postgres-tools/wasix/tools/package-assets.test.mts b/src/postgres-tools/wasix/tools/package-assets.test.mts
new file mode 100644
index 000000000..826d0d2cc
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/package-assets.test.mts
@@ -0,0 +1,56 @@
+import { afterAll, expect, test } from 'bun:test';
+import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import { postgresSourceFingerprint } from '../../../runtimes/liboliphaunt-wasix/tools/package-release-assets.mts';
+import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts';
+import { packageWasixToolsAssets, sha256 } from './package-assets.mts';
+import { packageWasixToolsCargoArtifacts } from './package-cargo-artifacts.mts';
+
+const scratch = mkdtempSync(path.join(tmpdir(), 'wasix-tools-package-'));
+afterAll(() => rmSync(scratch, { recursive: true, force: true }));
+
+test('independent tools archive freezes real Cargo payload and rejects stale or modified inputs', () => {
+  const source = path.join(scratch, 'source');
+  mkdirSync(path.join(source, 'bin'), { recursive: true });
+  const manifest = { 'source-lane': 'stable', 'source-fingerprint': postgresSourceFingerprint() };
+  for (const [key, name] of [
+    ['pg-dump', 'pg_dump'],
+    ['psql', 'psql'],
+  ]) {
+    const bytes = Buffer.from('\0asm\x01\0\0\0');
+    const relative = `bin/${name}.wasix.wasm`;
+    writeFileSync(path.join(source, relative), bytes);
+    manifest[key] = { name, path: relative, sha256: sha256(bytes), size: bytes.length };
+  }
+  const manifestPath = path.join(source, 'manifest.json');
+  writeFileSync(manifestPath, JSON.stringify(manifest));
+  const output = path.join(scratch, 'release-assets');
+  const argv = ['--source', source, '--version', '0.2.1', '--output-dir', output];
+  const archive = packageWasixToolsAssets(argv);
+  const before = readFileSync(archive);
+  packageWasixToolsAssets(argv);
+  expect(readFileSync(archive)).toEqual(before);
+  const packages = packageWasixToolsCargoArtifacts([
+    '--target',
+    'portable',
+    '--version',
+    '0.2.1',
+    '--asset-dir',
+    output,
+    '--output-dir',
+    path.join(scratch, 'cargo'),
+    '--work-dir',
+    path.join(scratch, 'work'),
+  ]);
+  expect(packages.map((row) => row.name)).toEqual(['oliphaunt-wasix-tools']);
+  const entries = readPortableArchiveEntries(packages[0].cratePath);
+  expect(entries.get('oliphaunt-wasix-tools-0.2.1/payload/bin/pg_dump.wasix.wasm')?.data()).toEqual(
+    Buffer.from('\0asm\x01\0\0\0'),
+  );
+  writeFileSync(path.join(source, 'bin/psql.wasix.wasm'), 'corrupted');
+  expect(() => packageWasixToolsAssets(argv)).toThrow('bytes do not match');
+  manifest['source-fingerprint'] = 'stale';
+  writeFileSync(manifestPath, JSON.stringify(manifest));
+  expect(() => packageWasixToolsAssets(argv)).toThrow('source fingerprint');
+});
diff --git a/src/postgres-tools/wasix/tools/package-cargo-artifacts.mts b/src/postgres-tools/wasix/tools/package-cargo-artifacts.mts
new file mode 100644
index 000000000..f74f18bd2
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/package-cargo-artifacts.mts
@@ -0,0 +1,95 @@
+#!/usr/bin/env bun
+import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { parseArgs } from 'node:util';
+import {
+  AOT_TARGET_TRIPLES,
+  TOOLS_AOT_PACKAGES,
+  TOOLS_PACKAGE,
+  WASIX_CARGO_ARTIFACT_SCHEMA,
+} from '../../../runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts';
+import { extractPortableArchiveTree } from '../../../../tools/packaging/portable-archive.mts';
+import { packageSpec } from '../../../../tools/packaging/wasix-cargo-payload.mts';
+import { currentProductVersionSync } from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  fail,
+  ROOT,
+  validatePortableToolsPayload,
+  validateToolsAotPayload,
+} from './package-assets.mts';
+
+export function packageWasixToolsCargoArtifacts(argv) {
+  const { values } = parseArgs({
+    args: argv,
+    options: {
+      target: { type: 'string', multiple: true },
+      version: { type: 'string', default: currentProductVersionSync('postgres-tools-wasix') },
+      'asset-dir': { type: 'string', default: 'target/postgres-tools/wasix/release-assets' },
+      'output-dir': { type: 'string', default: 'target/postgres-tools/wasix/cargo-artifacts' },
+      'work-dir': { type: 'string', default: 'target/postgres-tools/wasix' },
+    },
+  });
+  const outputDir = path.resolve(ROOT, values['output-dir']);
+  const work = path.resolve(ROOT, values['work-dir']);
+  const sourceRoot = path.join(work, 'cargo-package-sources');
+  const extracted = path.join(work, 'cargo-package-extracted');
+  for (const directory of [outputDir, sourceRoot, extracted]) {
+    rmSync(directory, { recursive: true, force: true });
+    mkdirSync(directory, { recursive: true });
+  }
+  const targets = values.target ?? ['portable', ...Object.keys(AOT_TARGET_TRIPLES)];
+  const packages = targets.map((target) => {
+    const triple = AOT_TARGET_TRIPLES[target];
+    if (target !== 'portable' && !triple) fail(`unsupported WASIX tools target ${target}`);
+    const payloadRoot = path.join(extracted, target);
+    const archive = path.resolve(
+      ROOT,
+      values['asset-dir'],
+      `postgres-tools-wasix-${values.version}-${triple ? `aot-${target}` : 'portable'}.tar.gz`,
+    );
+    extractPortableArchiveTree(archive, payloadRoot);
+    if (triple) validateToolsAotPayload(payloadRoot, triple);
+    else validatePortableToolsPayload(payloadRoot, values.version);
+    return packageSpec(
+      {
+        name: triple ? TOOLS_AOT_PACKAGES[target] : TOOLS_PACKAGE,
+        target: triple ?? 'portable',
+        kind: triple ? 'wasix-tools-aot' : 'wasix-tools',
+        templateDir: path.join(
+          ROOT,
+          'src/postgres-tools/wasix/crates',
+          triple ? `aot/${triple}` : 'tools',
+        ),
+        payloadRoot,
+        payloadDirName: triple ? 'artifacts' : 'payload',
+      },
+      {
+        version: values.version,
+        sourceRoot,
+        outputDir,
+        cargoTargetDir: path.join(work, 'cargo-package-target'),
+      },
+    );
+  });
+  const relative = (value) => path.relative(ROOT, value).split(path.sep).join('/');
+  writeFileSync(
+    path.join(outputDir, 'packages.json'),
+    `${JSON.stringify(
+      {
+        schema: WASIX_CARGO_ARTIFACT_SCHEMA,
+        product: 'postgres-tools-wasix',
+        packages: packages.map((row) => ({
+          ...row,
+          role: 'artifact',
+          manifestPath: relative(row.manifestPath),
+          cratePath: relative(row.cratePath),
+        })),
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  return packages;
+}
+
+if (import.meta.main) packageWasixToolsCargoArtifacts(Bun.argv.slice(2));
diff --git a/src/postgres-tools/wasix/tools/package-carriers.mts b/src/postgres-tools/wasix/tools/package-carriers.mts
new file mode 100644
index 000000000..d10eca3a3
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/package-carriers.mts
@@ -0,0 +1,21 @@
+#!/usr/bin/env bun
+import path from 'node:path';
+import {
+  currentProductVersionSync,
+  ROOT,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { packageWasixToolsCargoArtifacts } from './package-cargo-artifacts.mts';
+import { packWasixToolsNpmCarrier } from './wasix-tools-npm-carrier.mts';
+import { packWasixToolsAotNpmCarriers } from './wasix-tools-aot-npm.mts';
+
+export function packageWasixToolsCarriers() {
+  const version = currentProductVersionSync('postgres-tools-wasix', 'package-carriers.mts');
+  const assetDir = path.join(ROOT, 'target/postgres-tools/wasix/release-assets');
+  packageWasixToolsCargoArtifacts([]);
+  const portable = packWasixToolsNpmCarrier({
+    version,
+    portableReleaseArchive: path.join(assetDir, `postgres-tools-wasix-${version}-portable.tar.gz`),
+  });
+  return [portable.tarball, ...packWasixToolsAotNpmCarriers(version, assetDir)];
+}
+if (import.meta.main) packageWasixToolsCarriers();
diff --git a/src/postgres-tools/wasix/tools/test-packaging.sh b/src/postgres-tools/wasix/tools/test-packaging.sh
new file mode 100644
index 000000000..833a6dd63
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/test-packaging.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+export OLIPHAUNT_WASIX_TOOLS_TEST_ROOT
+OLIPHAUNT_WASIX_TOOLS_TEST_ROOT="$(mktemp -d)"
+trap 'rm -rf "$OLIPHAUNT_WASIX_TOOLS_TEST_ROOT"' EXIT
+bun test --timeout=30000 ./src/postgres-tools/wasix/tools
+node src/postgres-tools/wasix/tools/wasix-tools-npm.test-consumer.mts
diff --git a/src/postgres-tools/wasix/tools/wasix-tools-aot-npm.mts b/src/postgres-tools/wasix/tools/wasix-tools-aot-npm.mts
new file mode 100644
index 000000000..d15496038
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/wasix-tools-aot-npm.mts
@@ -0,0 +1,78 @@
+import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { artifactTargets, ROOT } from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  extractPortableArchiveTree,
+  canonicalGzipSync,
+} from '../../../../tools/packaging/portable-archive.mts';
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import {
+  stageReleaseNotices,
+  assertReleaseNoticesInArchive,
+  releaseProfilePackageLicense,
+} from '../../../../tools/packaging/release-notices.mts';
+import {
+  NPM_TRUSTED_PUBLISHING_REPOSITORY,
+  validateNpmTrustedPublishingManifest,
+} from '../../../../tools/packaging/npm-trusted-publishing.mts';
+import { validateToolsAotPayload } from './package-assets.mts';
+
+export function packWasixToolsAotNpmCarriers(
+  version,
+  assetDir,
+  { targetIds, workRoot = path.join(ROOT, 'target/release') } = {},
+) {
+  return artifactTargets('postgres-tools-wasix', 'wasix-tools-aot', 'wasix-tools-aot-npm.mts')
+    .filter((target) => targetIds === undefined || targetIds.includes(target.target))
+    .map((target) => {
+      const packageName = target.npmPackage;
+      const stage = path.join(
+        workRoot,
+        'npm-package-sources',
+        packageName.replace('@oliphaunt/', ''),
+      );
+      rmSync(stage, { recursive: true, force: true });
+      mkdirSync(stage, { recursive: true });
+      extractPortableArchiveTree(
+        path.join(assetDir, target.asset.replaceAll('{version}', version)),
+        path.join(stage, 'assets'),
+      );
+      validateToolsAotPayload(path.join(stage, 'assets'), target.triple);
+      const manifest = {
+        name: packageName,
+        version,
+        type: 'module',
+        description: 'Target AOT PostgreSQL tools for the Oliphaunt WASIX tools package.',
+        license: releaseProfilePackageLicense('wasix-runtime').spdx,
+        os: [target.npmOs],
+        cpu: [target.npmCpu],
+        ...(target.npmLibc ? { libc: [target.npmLibc] } : {}),
+        repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY },
+        publishConfig: { access: 'public', provenance: true },
+        exports: { './package.json': './package.json' },
+        files: ['assets', 'LICENSE', 'THIRD_PARTY_NOTICES.md', 'third-party-licenses'],
+      };
+      validateNpmTrustedPublishingManifest(manifest, packageName);
+      writeFileSync(path.join(stage, 'package.json'), JSON.stringify(manifest, null, 2) + '\n');
+      stageReleaseNotices(stage, { profile: 'wasix-runtime' });
+      const output = path.join(workRoot, 'npm-packages', packageName.replace('@oliphaunt/', ''));
+      mkdirSync(output, { recursive: true });
+      const tarball = path.join(
+        output,
+        `${packageName.replace('@', '').replace('/', '-')}-${version}.tgz`,
+      );
+      writeFileSync(
+        tarball,
+        canonicalGzipSync(
+          createDeterministicTar(stage, 'package', {
+            fail: (message) => {
+              throw new Error(message);
+            },
+            fixedFileMode: 0o644,
+          }),
+        ),
+      );
+      assertReleaseNoticesInArchive(tarball, { profile: 'wasix-runtime', prefix: 'package' });
+      return tarball;
+    });
+}
diff --git a/src/postgres-tools/wasix/tools/wasix-tools-npm-carrier.mts b/src/postgres-tools/wasix/tools/wasix-tools-npm-carrier.mts
new file mode 100644
index 000000000..c49348f9d
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/wasix-tools-npm-carrier.mts
@@ -0,0 +1,241 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { lstatSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
+import { isDeepStrictEqual } from 'node:util';
+import path from 'node:path';
+
+import {
+  NPM_TRUSTED_PUBLISHING_REPOSITORY,
+  validateNpmTrustedPublishingManifest,
+} from '../../../../tools/packaging/npm-trusted-publishing.mts';
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import {
+  canonicalGzipSync,
+  readPortableArchiveEntries,
+} from '../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  releaseNoticeRows,
+  releaseProfilePackageLicense,
+  stageReleaseNotices,
+} from '../../../../tools/packaging/release-notices.mts';
+
+const TOOL = 'wasix-tools-npm-carrier.mts';
+const ROOT = path.resolve(import.meta.dirname, '../../../..');
+const PACKAGE_NAME = '@oliphaunt/liboliphaunt-wasix-tools';
+const DESCRIPTOR_SCHEMA = 'oliphaunt-wasix-tools-v1';
+const RELEASE_TOOLS = Object.freeze({
+  pgDump: Object.freeze({
+    name: 'pg_dump',
+    member: 'bin/pg_dump.wasix.wasm',
+  }),
+  psql: Object.freeze({
+    name: 'psql',
+    member: 'bin/psql.wasix.wasm',
+  }),
+});
+const NOTICE_OPTIONS = Object.freeze({ profile: 'wasix-runtime' });
+
+function fail(message) {
+  throw new Error(`${TOOL}: ${message}`);
+}
+
+function sha256(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function requiredEntry(entries, member, label) {
+  const entry = entries.get(member);
+  if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) {
+    fail(`${label} must contain ${member} as a non-empty regular file`);
+  }
+  return Buffer.from(entry.data());
+}
+
+function regularArchive(file) {
+  try {
+    const metadata = lstatSync(file);
+    if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) {
+      fail(`${file} must be a non-empty regular non-symlink archive`);
+    }
+  } catch (cause) {
+    fail(`${file} cannot be inspected: ${cause.message}`);
+  }
+}
+
+export function wasixToolsNpmInputs({ portableReleaseArchive }) {
+  const archive = path.resolve(portableReleaseArchive);
+  regularArchive(archive);
+  const entries = readPortableArchiveEntries(archive);
+  const manifest = JSON.parse(requiredEntry(entries, 'manifest.json', archive).toString('utf8'));
+  if (
+    manifest.schema !== 'postgres-tools-wasix-portable-v1' ||
+    !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(manifest.runtimeVersion)
+  )
+    fail('incompatible PostgreSQL tools manifest');
+  const tools = {};
+  for (const [descriptorName, spec] of Object.entries(RELEASE_TOOLS)) {
+    const bytes = requiredEntry(entries, spec.member, archive);
+    const identity = manifest[descriptorName];
+    if (
+      identity?.name !== spec.name ||
+      identity.path !== spec.member ||
+      identity.sha256 !== sha256(bytes) ||
+      identity.size !== bytes.length
+    )
+      fail(`${spec.name} differs from its manifest`);
+    tools[descriptorName] = Object.freeze({
+      name: spec.name,
+      sha256: sha256(bytes),
+      size: bytes.length,
+      bytes,
+    });
+  }
+  return Object.freeze({ tools: Object.freeze(tools), manifest });
+}
+
+export function stageWasixToolsNpmCarrier({ version, portableReleaseArchive, packageDir }) {
+  if (typeof version !== 'string' || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.test(version)) {
+    throw new TypeError(`${TOOL}: version must be an exact semantic version`);
+  }
+  const output = path.resolve(packageDir);
+  const { tools, manifest: inputManifest } = wasixToolsNpmInputs({ portableReleaseArchive });
+  if (inputManifest.version !== version)
+    fail('tools archive version differs from the package version');
+  const runtimeVersion = inputManifest.runtimeVersion;
+  rmSync(output, { recursive: true, force: true });
+  mkdirSync(path.join(output, 'assets'), { recursive: true });
+  for (const [name, tool] of Object.entries(tools)) {
+    const filename = name === 'pgDump' ? 'pg_dump.wasix.wasm' : 'psql.wasix.wasm';
+    writeFileSync(path.join(output, 'assets', filename), tool.bytes, { mode: 0o644 });
+  }
+  const descriptor = Object.freeze({ version, runtimeVersion, ...tools });
+  writeFileSync(path.join(output, 'index.js'), renderDescriptor(descriptor), { mode: 0o644 });
+  writeFileSync(path.join(output, 'index.d.ts'), renderTypes(), { mode: 0o644 });
+  writeFileSync(
+    path.join(output, 'native.js'),
+    readFileSync(path.join(ROOT, 'src/postgres-tools/wasix/npm/native.mts')),
+    { mode: 0o644 },
+  );
+  writeFileSync(
+    path.join(output, 'README.md'),
+    `# ${PACKAGE_NAME}\n\nPortable PostgreSQL \`pg_dump\` and \`psql\` modules used by \`@oliphaunt/wasix-tools\`. Application code should depend on the facade rather than this asset carrier.\n`,
+    { mode: 0o644 },
+  );
+  stageReleaseNotices(output, NOTICE_OPTIONS);
+  const notices = releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => member);
+  const manifest = {
+    name: PACKAGE_NAME,
+    version,
+    description: 'Portable WASIX pg_dump and psql modules for Oliphaunt hosts.',
+    license: releaseProfilePackageLicense('wasix-runtime').spdx,
+    type: 'module',
+    sideEffects: false,
+    repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY },
+    oliphaunt: {
+      product: 'postgres-tools-wasix',
+      kind: 'wasix-tools',
+      runtime: 'wasix',
+      target: 'portable',
+      runtimeVersion,
+      descriptorSchema: DESCRIPTOR_SCHEMA,
+    },
+    publishConfig: { access: 'public', provenance: true },
+    files: ['README.md', 'index.js', 'native.js', 'index.d.ts', 'assets', ...notices],
+    optionalDependencies: Object.fromEntries(
+      ['linux-arm64-gnu', 'linux-x64-gnu', 'darwin-arm64', 'win32-x64-msvc'].map((target) => [
+        `@oliphaunt/liboliphaunt-wasix-tools-${target}`,
+        version,
+      ]),
+    ),
+    exports: {
+      '.': {
+        types: './index.d.ts',
+        browser: './index.js',
+        node: './native.js',
+        bun: './native.js',
+        deno: './native.js',
+        default: './index.js',
+      },
+      './package.json': './package.json',
+    },
+  };
+  validateNpmTrustedPublishingManifest(manifest, `${PACKAGE_NAME} generated package`);
+  writeFileSync(path.join(output, 'package.json'), `${JSON.stringify(manifest, null, 2)}\n`, {
+    mode: 0o644,
+  });
+  assertReleaseNoticesInDirectory(output, NOTICE_OPTIONS);
+  return Object.freeze({ packageDir: output, descriptor });
+}
+
+export function packWasixToolsNpmCarrier({
+  version,
+  portableReleaseArchive,
+  packageDir = path.join(ROOT, 'target/release/npm-package-sources/liboliphaunt-wasix-tools'),
+  tarballRoot = path.join(ROOT, 'target/release/npm-packages/liboliphaunt-wasix-tools'),
+}) {
+  const staged = stageWasixToolsNpmCarrier({ version, portableReleaseArchive, packageDir });
+  const output = path.resolve(tarballRoot);
+  rmSync(output, { recursive: true, force: true });
+  mkdirSync(output, { recursive: true });
+  const tarball = path.join(output, `oliphaunt-liboliphaunt-wasix-tools-${version}.tgz`);
+  writeFileSync(
+    tarball,
+    canonicalGzipSync(
+      createDeterministicTar(staged.packageDir, 'package', { fail, fixedFileMode: 0o644 }),
+    ),
+  );
+  assertWasixToolsNpmArchive(tarball, staged.descriptor);
+  return Object.freeze({ ...staged, tarball });
+}
+
+export function assertWasixToolsNpmArchive(archive, descriptor) {
+  if (statSync(archive).size > 20 * 1024 * 1024) fail(`${archive} exceeds the package size limit`);
+  assertReleaseNoticesInArchive(archive, { ...NOTICE_OPTIONS, prefix: 'package' });
+  const entries = readPortableArchiveEntries(archive);
+  const expected = [
+    'package/package.json',
+    'package/README.md',
+    'package/index.js',
+    'package/native.js',
+    'package/index.d.ts',
+    'package/assets/pg_dump.wasix.wasm',
+    'package/assets/psql.wasix.wasm',
+    ...releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => `package/${member}`),
+  ].sort();
+  const actual = [...entries]
+    .filter(([, entry]) => entry.isFile)
+    .map(([member]) => member)
+    .sort();
+  if (!isDeepStrictEqual(actual, expected))
+    fail(`${archive} file inventory differs from its allowlist`);
+  const manifest = JSON.parse(
+    requiredEntry(entries, 'package/package.json', archive).toString('utf8'),
+  );
+  validateNpmTrustedPublishingManifest(manifest, `${archive} package.json`);
+  if (manifest.name !== PACKAGE_NAME || manifest.version !== descriptor.version) {
+    fail(`${archive} has the wrong package identity`);
+  }
+  for (const [name, tool] of Object.entries({
+    'pg_dump.wasix.wasm': descriptor.pgDump,
+    'psql.wasix.wasm': descriptor.psql,
+  })) {
+    const bytes = requiredEntry(entries, `package/assets/${name}`, archive);
+    if (bytes.length !== tool.size || sha256(bytes) !== tool.sha256) {
+      fail(`${archive} contains unexpected ${name} bytes`);
+    }
+  }
+  return manifest;
+}
+
+function renderDescriptor(descriptor) {
+  const tool = (name, value) =>
+    `Object.freeze({ name: ${JSON.stringify(value.name)}, sha256: ${JSON.stringify(value.sha256)}, size: ${value.size}, source: new URL('./assets/${name}.wasix.wasm', import.meta.url).href })`;
+  return `export default Object.freeze({\n  schema: '${DESCRIPTOR_SCHEMA}',\n  product: 'oliphaunt-wasix-tools',\n  version: ${JSON.stringify(descriptor.version)},\n  runtimeProduct: 'liboliphaunt-wasix',\n  runtimeVersion: ${JSON.stringify(descriptor.runtimeVersion)},\n  pgDump: ${tool('pg_dump', descriptor.pgDump)},\n  psql: ${tool('psql', descriptor.psql)},\n});\n`;
+}
+
+function renderTypes() {
+  return `export type WasixToolModule = Readonly<{ name: 'pg_dump' | 'psql'; sha256: string; size: number; source: string; aot?: Readonly<{source: string; manifest: string}> }>;\nexport type WasixToolsDescriptor = Readonly<{ schema: '${DESCRIPTOR_SCHEMA}'; product: 'oliphaunt-wasix-tools'; version: string; runtimeProduct: 'liboliphaunt-wasix'; runtimeVersion: string; pgDump: WasixToolModule; psql: WasixToolModule }>;\ndeclare const descriptor: WasixToolsDescriptor;\nexport default descriptor;\n`;
+}
diff --git a/src/postgres-tools/wasix/tools/wasix-tools-npm-carrier.test.mts b/src/postgres-tools/wasix/tools/wasix-tools-npm-carrier.test.mts
new file mode 100644
index 000000000..b39929fdf
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/wasix-tools-npm-carrier.test.mts
@@ -0,0 +1,104 @@
+import { expect, test } from 'bun:test';
+import { createHash } from 'node:crypto';
+import { cpSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { pathToFileURL } from 'node:url';
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import { canonicalGzipSync } from '../../../../tools/packaging/portable-archive.mts';
+import { packWasixToolsNpmCarrier } from './wasix-tools-npm-carrier.mts';
+
+test('packages tool bytes with an independent version and preserves runtime compatibility', async () => {
+  const root = process.env.OLIPHAUNT_WASIX_TOOLS_TEST_ROOT;
+  if (!root) throw new Error('Run bash src/postgres-tools/wasix/tools/test-packaging.sh');
+  const payload = path.join(root, 'payload');
+  mkdirSync(path.join(payload, 'bin'), { recursive: true });
+  const manifest = {
+    schema: 'postgres-tools-wasix-portable-v1',
+    version: '7.8.9',
+    runtimeVersion: '1.2.3',
+    sourceFingerprint: 'fixture',
+    pgDump: null,
+    psql: null,
+  };
+  for (const [key, name] of [
+    ['pgDump', 'pg_dump'],
+    ['psql', 'psql'],
+  ]) {
+    const bytes = Buffer.from(name);
+    const member = `bin/${name}.wasix.wasm`;
+    writeFileSync(path.join(payload, member), bytes);
+    manifest[key] = {
+      name,
+      path: member,
+      sha256: createHash('sha256').update(bytes).digest('hex'),
+      size: bytes.length,
+    };
+  }
+  writeFileSync(path.join(payload, 'manifest.json'), JSON.stringify(manifest));
+  const archive = path.join(root, 'tools.tar.gz');
+  const writeArchive = () =>
+    writeFileSync(
+      archive,
+      canonicalGzipSync(
+        createDeterministicTar(payload, '.', {
+          fail: (message) => {
+            throw new Error(message);
+          },
+        }),
+      ),
+    );
+  writeArchive();
+  const args = {
+    version: '7.8.9',
+    portableReleaseArchive: archive,
+    packageDir: path.join(root, 'package'),
+    tarballRoot: path.join(root, 'tarballs'),
+  };
+  const packed = packWasixToolsNpmCarrier(args);
+  const metadata = JSON.parse(readFileSync(path.join(packed.packageDir, 'package.json'), 'utf8'));
+  expect(metadata.version).toBe('7.8.9');
+  expect(metadata.oliphaunt.runtimeVersion).toBe('1.2.3');
+  expect(Object.values(metadata.optionalDependencies)).toEqual(Array(4).fill('7.8.9'));
+  const descriptor = (await import(pathToFileURL(path.join(packed.packageDir, 'index.js')).href))
+    .default;
+  expect(readFileSync(new URL(descriptor.pgDump.source), 'utf8')).toBe('pg_dump');
+  expect(descriptor.runtimeVersion).toBe('1.2.3');
+  expect(descriptor.pgDump.aot).toBeUndefined();
+  const target =
+    process.platform === 'linux'
+      ? `linux-${process.arch}-gnu`
+      : process.platform === 'darwin'
+        ? `darwin-${process.arch}`
+        : `win32-${process.arch}-msvc`;
+  const aotPackage = path.join(
+    packed.packageDir,
+    'node_modules/@oliphaunt',
+    `liboliphaunt-wasix-tools-${target}`,
+  );
+  mkdirSync(path.join(aotPackage, 'assets'), { recursive: true });
+  writeFileSync(
+    path.join(aotPackage, 'package.json'),
+    JSON.stringify({
+      name: `@oliphaunt/liboliphaunt-wasix-tools-${target}`,
+      version: '7.8.9',
+      exports: { './package.json': './package.json' },
+    }),
+  );
+  writeFileSync(
+    path.join(aotPackage, 'assets/manifest.json'),
+    JSON.stringify({
+      artifacts: [
+        { name: 'tool:pg_dump', path: 'pg_dump.bin.zst' },
+        { name: 'tool:psql', path: 'psql.bin.zst' },
+      ],
+    }),
+  );
+  writeFileSync(path.join(aotPackage, 'assets/pg_dump.bin.zst'), 'target-code');
+  cpSync(packed.packageDir, path.join(root, 'consumer'), { recursive: true });
+  writeFileSync(path.join(payload, 'bin/pg_dump.wasix.wasm'), 'altered');
+  writeArchive();
+  expect(() => packWasixToolsNpmCarrier(args)).toThrow('differs from its manifest');
+  expect(() => packWasixToolsNpmCarrier({ ...args, version: '../escape' })).toThrow(
+    'semantic version',
+  );
+});
diff --git a/src/postgres-tools/wasix/tools/wasix-tools-npm.test-consumer.mts b/src/postgres-tools/wasix/tools/wasix-tools-npm.test-consumer.mts
new file mode 100644
index 000000000..fb9240c4b
--- /dev/null
+++ b/src/postgres-tools/wasix/tools/wasix-tools-npm.test-consumer.mts
@@ -0,0 +1,12 @@
+import assert from 'node:assert/strict';
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+import { pathToFileURL } from 'node:url';
+
+const root = process.env.OLIPHAUNT_WASIX_TOOLS_TEST_ROOT;
+if (!root) throw new Error('Run bash src/postgres-tools/wasix/tools/test-packaging.sh');
+const portable = (await import(pathToFileURL(path.join(root, 'consumer/index.js')).href)).default;
+const native = (await import(pathToFileURL(path.join(root, 'consumer/native.js')).href)).default;
+assert.equal(readFileSync(new URL(native.pgDump.aot.source), 'utf8'), 'target-code');
+assert.equal(native.pgDump.sha256, portable.pgDump.sha256);
+assert.equal(native.runtimeVersion, '1.2.3');
diff --git a/src/bindings/wasix-ts/.gitignore b/src/postgres-tools/wasix/ts/.gitignore
similarity index 100%
rename from src/bindings/wasix-ts/.gitignore
rename to src/postgres-tools/wasix/ts/.gitignore
diff --git a/src/postgres-tools/wasix/ts/README.md b/src/postgres-tools/wasix/ts/README.md
new file mode 100644
index 000000000..66b98a037
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/README.md
@@ -0,0 +1,62 @@
+# @oliphaunt/wasix-tools
+
+Optional standard PostgreSQL `pg_dump` and non-interactive `psql` runners for
+an open `@oliphaunt/wasix-ts` database. This package remains the public opt-in
+facade on every host. Browsers load separately carried portable tool binaries;
+Node.js, Bun, Deno, and Electron call the copies compiled into the matching Node-API
+platform carrier.
+
+`pgDump()` returns PostgreSQL's ordinary plain SQL dump, including normal
+`COPY` data. `psql()` accepts a command or script and can restore that output.
+Both operations exclusively own the database session until they finish.
+They reset PostgreSQL session state before and after running, so raw-protocol
+callers must not expect prepared statements or session settings to survive.
+
+```sh
+bun add @oliphaunt/wasix-ts @oliphaunt/wasix-tools
+```
+
+```ts
+import Oliphaunt from '@oliphaunt/wasix-ts';
+import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker';
+import { pgDump, psql } from '@oliphaunt/wasix-tools';
+
+await using source = await Oliphaunt.open();
+const sql = await pgDump(source, { args: ['--schema-only'] });
+await using target = await WorkerOliphaunt.open();
+await psql(target, { script: sql });
+```
+
+`pgDump()` supports databases from the root, `/direct`, and `/worker` entrypoints.
+In browsers, `psql()` requires `/worker` because COPY restore is full duplex.
+On Node.js, Bun, Deno, and Electron the Rust tool bridge supports `psql()` on
+all three entrypoints.
+Ordinary PostgreSQL
+arguments are passed through, except connection, input/output, encoding, dump
+format, compression, and parallel-job arguments owned by the runner.
+`pgDump()` always uses plain UTF-8 output and rejects custom formats; it does
+not force `--inserts` or rewrite valid dump SQL. `psql()` accepts `command` or
+`script`, uses no user psqlrc, and stops on the first SQL error. Interactive
+input and `pg_restore` are not part of this package.
+
+Tool failures throw `PostgresToolError` with `tool`, `exitCode`, `stdout`, and
+`stderr` fields.
+
+## Maintainer commands
+
+After installing the pinned workspace tools and dependencies, run these from
+this directory:
+
+```sh
+moon run oliphaunt-wasix-tools-ts:build
+moon run oliphaunt-wasix-tools-ts:typecheck
+moon run oliphaunt-wasix-tools-ts:test
+moon run oliphaunt-wasix-tools-ts:package
+```
+
+Build and typecheck first build the SDK's actual declarations; they do not
+compile PostgreSQL, Wasmer or the Node addon. Packaging depends on this build
+and stages only the facade. `bun run build` and `bun run typecheck` consume an
+already built SDK. The separate `postgres-tools-wasix:test-consumer` and
+`postgres-tools-wasix:test-browser` tasks produce the runtime/tool dependencies
+and exercise the installed packages on their respective hosts.
diff --git a/src/postgres-tools/wasix/ts/bunfig.toml b/src/postgres-tools/wasix/ts/bunfig.toml
new file mode 100644
index 000000000..37ff1f948
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/bunfig.toml
@@ -0,0 +1,2 @@
+[test]
+preload = ["./src/__tests__/setup.ts"]
diff --git a/src/postgres-tools/wasix/ts/moon.yml b/src/postgres-tools/wasix/ts/moon.yml
new file mode 100644
index 000000000..55ad2326a
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/moon.yml
@@ -0,0 +1,73 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "oliphaunt-wasix-tools-ts"
+language: "typescript"
+layer: "library"
+stack: "frontend"
+tags: ["javascript-quality", "binding", "wasix", "typescript", "tools", "package"]
+dependsOn:
+  - id: "oliphaunt-wasix-ts"
+    scope: "production"
+  - id: "shared-test-fixtures"
+    scope: "development"
+
+project:
+  title: "Oliphaunt WASIX TypeScript tools"
+  description: "TypeScript pg_dump and psql facade for the WASIX runtime."
+  owner: "oliphaunt"
+
+owners:
+  defaultOwner: "@oliphaunt/sdk-js"
+
+fileGroups:
+  code:
+    - "**/*"
+    - "!**/*.md"
+    - "!moon.yml"
+
+tasks:
+  build:
+    tags: ["build"]
+    command: "bun run build"
+    deps: ["oliphaunt-wasix-ts:build"]
+    inputs: ["@group(bun-workspace)", "@group(code)"]
+    outputs: ["lib/**/*"]
+
+  typecheck:
+    tags: ["quality", "static"]
+    command: "bun run --cwd src/postgres-tools/wasix/ts typecheck"
+    deps: ["oliphaunt-wasix-ts:build"]
+    inputs:
+      - "@group(bun-workspace)"
+      - "@group(code)"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  test:
+    tags: ["quality", "unit"]
+    command: "bun run --cwd src/postgres-tools/wasix/ts test"
+    inputs:
+      - "@group(bun-workspace)"
+      - "@group(code)"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  package:
+    tags: ["package", "artifact-package", "ci-js-sdk-package"]
+    command: "bash src/postgres-tools/wasix/ts/tools/package.sh"
+    deps: ["build"]
+    inputs:
+      - "@group(legal-files)"
+      - "@group(bun-workspace)"
+      - "**/*"
+      - "/src/sdks/ts-wasix/sdk/package.json"
+    outputs:
+      - "/target/oliphaunt-wasix-tools-ts/package/**/*"
+      - "/target/sdk-artifacts/postgres-tools-wasix/**/*"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/postgres-tools/wasix/ts/package.json b/src/postgres-tools/wasix/ts/package.json
new file mode 100644
index 000000000..2b93de70e
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/package.json
@@ -0,0 +1,64 @@
+{
+  "name": "@oliphaunt/wasix-tools",
+  "version": "0.2.1",
+  "description": "Optional in-process PostgreSQL pg_dump and psql runners for Oliphaunt WASIX.",
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": false,
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/postgres-tools/wasix/ts"
+  },
+  "bugs": {
+    "url": "https://github.com/f0rr0/oliphaunt/issues"
+  },
+  "homepage": "https://oliphaunt.dev",
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "oliphaunt": {
+    "runtimeProduct": "liboliphaunt-wasix",
+    "runtimeVersion": "0.2.0"
+  },
+  "exports": {
+    ".": {
+      "types": "./lib/index.d.ts",
+      "default": "./lib/index.js"
+    },
+    "./package.json": "./package.json"
+  },
+  "main": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "files": [
+    "lib",
+    "README.md",
+    "CHANGELOG.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md"
+  ],
+  "scripts": {
+    "build": "bash -c \"rm -rf lib\" && tsc -p tsconfig.build.json",
+    "typecheck": "tsc --noEmit",
+    "test": "bun test --isolate --timeout=30000 ./src/__tests__ ./tools/wasix-tools-typescript-package.test.mts",
+    "clean": "bash -c \"rm -rf lib\""
+  },
+  "dependencies": {
+    "@oliphaunt/liboliphaunt-wasix-tools": "workspace:*"
+  },
+  "peerDependencies": {
+    "@oliphaunt/wasix-ts": "workspace:*"
+  },
+  "devDependencies": {
+    "@oliphaunt/wasix-ts": "workspace:*",
+    "@types/node": "^24.10.1",
+    "typescript": "catalog:",
+    "@types/bun": "catalog:"
+  },
+  "engines": {
+    "node": ">=22.13 <25",
+    "bun": ">=1.3.14",
+    "deno": ">=2.8.1"
+  }
+}
diff --git a/src/bindings/wasix-ts/tools-package/src/__tests__/api.test.ts b/src/postgres-tools/wasix/ts/src/__tests__/api.test.ts
similarity index 81%
rename from src/bindings/wasix-ts/tools-package/src/__tests__/api.test.ts
rename to src/postgres-tools/wasix/ts/src/__tests__/api.test.ts
index b80b8f1dd..0f0b4b9b6 100644
--- a/src/bindings/wasix-ts/tools-package/src/__tests__/api.test.ts
+++ b/src/postgres-tools/wasix/ts/src/__tests__/api.test.ts
@@ -1,7 +1,6 @@
+import { describe, expect, it } from 'bun:test';
 import { readFileSync } from 'node:fs';
-
-import { describe, expect, it } from 'vitest';
-import { pgDump, PostgresToolError, psql } from '../index.js';
+import { PostgresToolError, pgDump, psql } from '../index.js';
 import { toolRuntimeCalls, toolRuntimeResponses } from './wasix-ts-runtime.js';
 
 type LogicalToolsFixture = Readonly<{
@@ -21,7 +20,7 @@ type LogicalToolsFixture = Readonly<{
 
 const fixture = JSON.parse(
   readFileSync(
-    new URL('../../../../../shared/fixtures/postgres/logical-tools.json', import.meta.url),
+    new URL('../../../../../test-fixtures/postgres/logical-tools.json', import.meta.url),
     'utf8',
   ),
 ) as LogicalToolsFixture;
@@ -97,28 +96,16 @@ describe('WASIX tools public validation', () => {
     }
   });
 
-  it('passes the database startup identity through unambiguous managed long options', async () => {
-    toolRuntimeCalls.length = 0;
-    await pgDump(database).catch(() => undefined);
-    await psql(database, { command: 'select 1' }).catch(() => undefined);
-
-    expect(toolRuntimeCalls).toHaveLength(2);
-    for (const call of toolRuntimeCalls) {
-      expect(call.args).toContain('--username=-application user');
-      expect(call.args).toContain('--dbname=-application database');
-      expect(call.args).not.toContain('-application database');
-    }
-  });
-
-  it('marks stdin scripts as non-interactive psql files', async () => {
+  it('passes user arguments and input without manufacturing native connection arguments', async () => {
     toolRuntimeCalls.length = 0;
-    await psql(database, { script: 'select 1' }).catch(() => undefined);
+    await pgDump(database, { args: ['--schema-only'] }).catch(() => undefined);
     await psql(database, { command: 'select 1' }).catch(() => undefined);
-
-    expect(toolRuntimeCalls[0]?.args).toContain('--file=-');
-    expect(toolRuntimeCalls[0]?.args).not.toContain('--command');
-    expect(toolRuntimeCalls[1]?.args).not.toContain('--file=-');
-    expect(toolRuntimeCalls[1]?.args).toContain('--command');
+    await psql(database, { script: 'select 2' }).catch(() => undefined);
+    expect(toolRuntimeCalls[0]?.args).toEqual(['--schema-only']);
+    expect(toolRuntimeCalls[1]?.args).toEqual([]);
+    expect(toolRuntimeCalls[1]?.command).toBe('select 1');
+    expect(toolRuntimeCalls[2]?.args).toEqual([]);
+    expect(new TextDecoder().decode(toolRuntimeCalls[2]?.stdin)).toBe('select 2');
   });
 
   it('strictly decodes successful output once at the public boundary', async () => {
diff --git a/src/postgres-tools/wasix/ts/src/__tests__/setup.ts b/src/postgres-tools/wasix/ts/src/__tests__/setup.ts
new file mode 100644
index 000000000..b64d753a7
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/src/__tests__/setup.ts
@@ -0,0 +1,14 @@
+import { mock } from 'bun:test';
+import * as runtime from './wasix-ts-runtime.js';
+
+mock.module('@oliphaunt/wasix-ts/internal/tools', () => runtime);
+mock.module('@oliphaunt/liboliphaunt-wasix-tools', () => ({
+  default: {
+    schema: 'oliphaunt-wasix-tools-v1',
+    product: 'oliphaunt-wasix-tools',
+    runtimeProduct: 'liboliphaunt-wasix',
+    runtimeVersion: '1.2.3',
+    pgDump: { name: 'pg_dump' },
+    psql: { name: 'psql' },
+  },
+}));
diff --git a/src/postgres-tools/wasix/ts/src/__tests__/wasix-ts-runtime.ts b/src/postgres-tools/wasix/ts/src/__tests__/wasix-ts-runtime.ts
new file mode 100644
index 000000000..f8dabacdc
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/src/__tests__/wasix-ts-runtime.ts
@@ -0,0 +1,16 @@
+export const toolRuntimeCalls: Array<
+  Readonly<{ args: readonly string[]; command?: string; stdin?: Uint8Array }>
+> = [];
+export const toolRuntimeResponses: Array<
+  Readonly<{ exitCode: number; stdout: Uint8Array; stderr: Uint8Array }>
+> = [];
+
+export async function runWasixToolProcess(
+  _database: unknown,
+  options: Readonly<{ args: readonly string[]; command?: string; stdin?: Uint8Array }>,
+): Promise> {
+  toolRuntimeCalls.push(options);
+  const response = toolRuntimeResponses.shift();
+  if (response !== undefined) return response;
+  throw new Error('unexpected WASIX tool runtime call in validation test');
+}
diff --git a/src/postgres-tools/wasix/ts/src/index.ts b/src/postgres-tools/wasix/ts/src/index.ts
new file mode 100644
index 000000000..0c42a3866
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/src/index.ts
@@ -0,0 +1,325 @@
+import tools from '@oliphaunt/liboliphaunt-wasix-tools';
+import type { OliphauntDatabase } from '@oliphaunt/wasix-ts';
+import { runWasixToolProcess } from '@oliphaunt/wasix-ts/internal/tools';
+
+assertToolsCarrier();
+
+// PostgreSQL 18 getopt_long optstrings. A value-taking option owns the rest
+// of its token, so a managed-looking character inside that value stays data.
+const PG_DUMP_SHORT_OPTIONS = 'abBcCd:e:E:f:F:h:j:n:N:Op:RsS:t:T:U:vwWxXZ:';
+const PSQL_SHORT_OPTIONS = 'aAbc:d:eEf:F:h:HlL:no:p:P:qR:sStT:U:v:VwWxXz?01';
+const PG_DUMP_VALUE_OPTIONS = [
+  '--extension',
+  '--schema',
+  '--exclude-schema',
+  '--superuser',
+  '--table',
+  '--exclude-table',
+  '--exclude-table-data',
+  '--extra-float-digits',
+  '--lock-wait-timeout',
+  '--role',
+  '--section',
+  '--snapshot',
+  '--rows-per-insert',
+  '--include-foreign-data',
+  '--table-and-children',
+  '--exclude-table-and-children',
+  '--exclude-table-data-and-children',
+  '--sync-method',
+  '--exclude-extension',
+  '--restrict-key',
+] as const;
+const PSQL_VALUE_OPTIONS = [
+  '--field-separator',
+  '--pset',
+  '--record-separator',
+  '--table-attr',
+  '--set',
+  '--variable',
+] as const;
+
+export type PgDumpOptions = Readonly<{
+  /** Ordinary PostgreSQL pg_dump arguments. Connection, file input/output, format, compression, encoding, and job flags are managed. */
+  args?: readonly string[];
+}>;
+
+export type PsqlOptions = Readonly<{
+  /** Ordinary PostgreSQL psql arguments. Connection, input, and output are managed. */
+  args?: readonly string[];
+  command?: string;
+  script?: string;
+}>;
+
+export class PostgresToolError extends Error {
+  readonly tool: 'pg_dump' | 'psql';
+  readonly exitCode: number | null;
+  readonly stdout: string;
+  readonly stderr: string;
+
+  constructor(
+    tool: 'pg_dump' | 'psql',
+    message: string,
+    options: {
+      exitCode?: number | null;
+      stdout?: string;
+      stderr?: string;
+      cause?: unknown;
+    } = {},
+  ) {
+    super(message, { cause: options.cause });
+    this.name = 'PostgresToolError';
+    this.tool = tool;
+    this.exitCode = options.exitCode ?? null;
+    this.stdout = options.stdout ?? '';
+    this.stderr = options.stderr ?? '';
+  }
+}
+
+/** Run standard PostgreSQL plain pg_dump against an open WASIX database. */
+export async function pgDump(
+  database: OliphauntDatabase,
+  options: PgDumpOptions = {},
+): Promise {
+  const args = validatedArguments(
+    'pg_dump',
+    options.args,
+    pgDumpManagedArgument,
+    PG_DUMP_SHORT_OPTIONS,
+    PG_DUMP_VALUE_OPTIONS,
+  );
+  return runTool('pg_dump', database, args);
+}
+
+/**
+ * Run standard non-interactive psql. Browsers require a `/worker` database;
+ * Node.js, Bun, Deno, and Electron support root, `/direct`, and `/worker` databases.
+ */
+export async function psql(
+  database: OliphauntDatabase,
+  options: PsqlOptions = {},
+): Promise {
+  const args = validatedArguments(
+    'psql',
+    options.args,
+    psqlManagedArgument,
+    PSQL_SHORT_OPTIONS,
+    PSQL_VALUE_OPTIONS,
+  );
+  if (options.command !== undefined && options.script !== undefined) {
+    throw new TypeError('psql accepts command or script, not both');
+  }
+  const command = validatedInput(options.command, 'psql command');
+  const script = validatedInput(options.script, 'psql script');
+  if (command === undefined && script === undefined && args.length === 0) {
+    throw new TypeError('psql requires non-interactive input through command, script, or args');
+  }
+  return runTool(
+    'psql',
+    database,
+    args,
+    script === undefined ? undefined : new TextEncoder().encode(script),
+    command,
+  );
+}
+
+async function runTool(
+  name: 'pg_dump' | 'psql',
+  database: OliphauntDatabase,
+  args: string[],
+  stdin?: Uint8Array,
+  command?: string,
+): Promise {
+  const descriptor = name === 'pg_dump' ? tools.pgDump : tools.psql;
+  let result: Awaited>;
+  try {
+    result = await runWasixToolProcess(database, {
+      runtimeVersion: tools.runtimeVersion,
+      tool: descriptor,
+      args,
+      stdin,
+      command,
+    });
+  } catch (cause) {
+    const detail = cause instanceof Error ? cause.message : String(cause);
+    throw new PostgresToolError(name, `could not run ${name}: ${detail}`, { cause });
+  }
+  if (result.exitCode !== 0) {
+    // Diagnostics are best-effort text just like native process output. Keep
+    // the structured failure even if either stream contains invalid UTF-8.
+    const stdout = decodeDiagnostics(result.stdout);
+    const stderr = decodeDiagnostics(result.stderr);
+    throw new PostgresToolError(
+      name,
+      `${name} exited with status ${result.exitCode}${stderr.trim() === '' ? '' : `: ${stderr.trim()}`}`,
+      { exitCode: result.exitCode, stdout, stderr },
+    );
+  }
+  try {
+    return decode(result.stdout, `${name} output`);
+  } catch (cause) {
+    throw new PostgresToolError(name, `${name} output is not valid UTF-8`, {
+      exitCode: result.exitCode,
+      stdout: decodeDiagnostics(result.stdout),
+      stderr: decodeDiagnostics(result.stderr),
+      cause,
+    });
+  }
+}
+
+function validatedInput(value: string | undefined, label: string): string | undefined {
+  if (value === undefined) return undefined;
+  if (typeof value !== 'string') throw new TypeError(`${label} must be a string`);
+  if (value.includes('\0')) throw new TypeError(`${label} must not contain NUL bytes`);
+  return value;
+}
+
+function validatedArguments(
+  tool: 'pg_dump' | 'psql',
+  value: readonly string[] | undefined,
+  managed: (argument: string) => string | undefined,
+  shortOptions: string,
+  valueOptions: readonly string[],
+): string[] {
+  if (value === undefined) return [];
+  if (!Array.isArray(value)) throw new TypeError(`${tool} args must be an array of strings`);
+  let expectsValue = false;
+  const validated = value.map((argument) => {
+    if (typeof argument !== 'string') throw new TypeError(`${tool} argument must be a string`);
+    if (argument.includes('\0')) throw new TypeError(`${tool} argument must not contain NUL bytes`);
+    if (expectsValue) {
+      expectsValue = false;
+      return argument;
+    }
+    const label = managed(argument);
+    if (label !== undefined) {
+      throw new TypeError(
+        `${tool} argument ${JSON.stringify(argument)} conflicts with Oliphaunt's managed ${label}`,
+      );
+    }
+    if (argument === '-' || !argument.startsWith('-')) {
+      throw new TypeError(
+        `${tool} argument ${JSON.stringify(argument)} conflicts with Oliphaunt's managed database or username`,
+      );
+    }
+    expectsValue = optionConsumesNext(argument, shortOptions, valueOptions);
+    return argument;
+  });
+  if (expectsValue) {
+    throw new TypeError(`${tool} argument ${JSON.stringify(validated.at(-1))} requires a value`);
+  }
+  return validated;
+}
+
+function pgDumpManagedArgument(argument: string): string | undefined {
+  if (argument === '--') return 'option terminator';
+  return managedArgument(
+    argument,
+    [
+      ['--password', '-W', 'password prompting'],
+      ['--filter', '', 'input file'],
+      ['--file', '-f', 'output file'],
+      ['--format', '-F', 'output format'],
+      ['--compress', '-Z', 'output compression'],
+      ['--encoding', '-E', 'output encoding'],
+      ['--host', '-h', 'host'],
+      ['--port', '-p', 'port'],
+      ['--username', '-U', 'username'],
+      ['--dbname', '-d', 'database'],
+      ['--jobs', '-j', 'job count'],
+    ],
+    PG_DUMP_SHORT_OPTIONS,
+  );
+}
+
+function optionConsumesNext(
+  argument: string,
+  shortOptions: string,
+  valueOptions: readonly string[],
+): boolean {
+  if (argument.startsWith('--')) {
+    if (argument.includes('=')) return false;
+    return valueOptions.some((option) => option.startsWith(argument));
+  }
+  for (let index = 1; index < argument.length; index += 1) {
+    const option = argument[index];
+    if (option === undefined) return false;
+    const position = shortOptions.indexOf(option);
+    if (position < 0) return false;
+    if (shortOptions[position + 1] === ':') return index === argument.length - 1;
+  }
+  return false;
+}
+
+function psqlManagedArgument(argument: string): string | undefined {
+  if (argument === '--') return 'option terminator';
+  return managedArgument(
+    argument,
+    [
+      ['--password', '-W', 'password prompting'],
+      ['--single-step', '-s', 'interactive prompting'],
+      ['--host', '-h', 'host'],
+      ['--port', '-p', 'port'],
+      ['--username', '-U', 'username'],
+      ['--dbname', '-d', 'database'],
+      ['--output', '-o', 'stdout capture'],
+      ['--log-file', '-L', 'stderr capture'],
+      ['--command', '-c', 'input'],
+      ['--file', '-f', 'input'],
+    ],
+    PSQL_SHORT_OPTIONS,
+  );
+}
+
+function managedArgument(
+  argument: string,
+  flags: readonly (readonly [long: string, short: string, label: string])[],
+  shortOptions: string,
+): string | undefined {
+  const longName = argument.split('=', 1)[0];
+  if (longName !== undefined && longName.length > 2 && longName.startsWith('--')) {
+    for (const [long, , label] of flags) {
+      // Native getopt_long accepts unique prefixes while PostgreSQL's bundled
+      // fallback requires exact names. Reject either spelling consistently so
+      // a managed option cannot become host-dependent.
+      if (long.startsWith(longName)) return label;
+    }
+  }
+  if (argument.length < 2 || argument[0] !== '-' || argument[1] === '-') {
+    return undefined;
+  }
+  for (let index = 1; index < argument.length; index += 1) {
+    const option = argument[index];
+    if (option === undefined) return undefined;
+    const position = shortOptions.indexOf(option);
+    if (position < 0) return undefined;
+    const managed = flags.find(([, short]) => short === `-${option}`);
+    if (managed !== undefined) return managed[2];
+    if (shortOptions[position + 1] === ':') return undefined;
+  }
+  return undefined;
+}
+
+function decode(bytes: Uint8Array, label: string): string {
+  try {
+    return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
+  } catch (cause) {
+    throw new Error(`${label} is not valid UTF-8`, { cause });
+  }
+}
+
+function decodeDiagnostics(bytes: Uint8Array): string {
+  return new TextDecoder().decode(bytes);
+}
+
+function assertToolsCarrier(): void {
+  if (
+    tools.schema !== 'oliphaunt-wasix-tools-v1' ||
+    tools.product !== 'oliphaunt-wasix-tools' ||
+    tools.runtimeProduct !== 'liboliphaunt-wasix' ||
+    typeof tools.runtimeVersion !== 'string' ||
+    tools.runtimeVersion.length === 0
+  ) {
+    throw new Error('@oliphaunt/liboliphaunt-wasix-tools has an invalid descriptor');
+  }
+}
diff --git a/src/postgres-tools/wasix/ts/tests/browser.ts b/src/postgres-tools/wasix/ts/tests/browser.ts
new file mode 100644
index 000000000..5b0c497a3
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tests/browser.ts
@@ -0,0 +1,65 @@
+import seedArchive from '@oliphaunt/seed-wasix-standard/seed.tar.zst?url';
+import seedManifest from '@oliphaunt/seed-wasix-standard/manifest.json?url';
+const seed = { archive: seedArchive, manifest: seedManifest };
+import pgtap from '@oliphaunt/extension-pgtap-wasix';
+import Oliphaunt from '@oliphaunt/wasix-ts';
+import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker';
+import { pgDump, psql } from '@oliphaunt/wasix-tools';
+import logicalToolsFixtureJson from './logical-tools.json?raw';
+import logicalToolsSeed from './logical-tools-seed.sql?raw';
+import logicalToolsVerify from './logical-tools-verify.sql?raw';
+import { expectDirectPgDump } from './direct-pg-dump-smoke.js';
+const logicalToolsFixture = JSON.parse(logicalToolsFixtureJson);
+const status = document.getElementById('status')!;
+const output = document.getElementById('output')!;
+try {
+  const direct = await Oliphaunt.open({ seed, extensions: [pgtap] });
+  try {
+    await expectDirectPgDump(direct);
+  } finally {
+    await direct.close();
+  }
+  const logicalTools = await expectLogicalTools();
+  status.textContent = 'PostgreSQL tools browser smoke passed.';
+  output.textContent = JSON.stringify({ directPgDump: true, logicalTools });
+  document.documentElement.dataset.oliphauntSmoke = 'passed';
+} catch (error) {
+  status.textContent = 'PostgreSQL tools browser smoke failed.';
+  output.textContent = error instanceof Error ? (error.stack ?? error.message) : String(error);
+  document.documentElement.dataset.oliphauntSmoke = 'failed';
+}
+async function expectLogicalTools(): Promise {
+  const source = await WorkerOliphaunt.open({ seed, extensions: [pgtap] });
+  let sql: string;
+  try {
+    await psql(source, { script: logicalToolsSeed });
+    sql = await pgDump(source);
+    if (!sql.includes('COPY public.logical_items') || sql.includes('--inserts')) {
+      throw new Error('packed browser pg_dump did not preserve standard plain COPY output');
+    }
+  } finally {
+    await source.close();
+  }
+
+  const target = await WorkerOliphaunt.open({ seed, extensions: [pgtap] });
+  try {
+    await psql(target, { script: sql });
+    const result = await target.queryRaw(logicalToolsVerify);
+    const actual = {
+      rows: Number(result.getText(0, 'rows')),
+      sum: Number(result.getText(0, 'sum')),
+      sequenceLastValue: Number(result.getText(0, 'sequence_last_value')),
+      quotedValue: result.getText(0, 'quoted_value'),
+      normalizedMatches: Number(result.getText(0, 'normalized_matches')),
+      extensionLoaded: result.getText(0, 'extension_loaded') === 't',
+    };
+    if (JSON.stringify(actual) !== JSON.stringify(logicalToolsFixture.expected)) {
+      throw new Error(
+        `packed browser logical tool round trip differed from the shared fixture: ${JSON.stringify(actual)}`,
+      );
+    }
+    return `${actual.rows}:${actual.sum}:${actual.sequenceLastValue}`;
+  } finally {
+    await target.close();
+  }
+}
diff --git a/src/postgres-tools/wasix/ts/tests/consumer.sh b/src/postgres-tools/wasix/ts/tests/consumer.sh
new file mode 100644
index 000000000..f4d901364
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tests/consumer.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")"
+for runtime in node bun deno; do
+  bash smoke-host.sh --runtime "$runtime"
+done
diff --git a/examples/browser-wasix/direct-pg-dump-smoke.ts b/src/postgres-tools/wasix/ts/tests/direct-pg-dump-smoke.ts
similarity index 100%
rename from examples/browser-wasix/direct-pg-dump-smoke.ts
rename to src/postgres-tools/wasix/ts/tests/direct-pg-dump-smoke.ts
diff --git a/src/postgres-tools/wasix/ts/tests/smoke-host.mts b/src/postgres-tools/wasix/ts/tests/smoke-host.mts
new file mode 100644
index 000000000..c880095ec
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tests/smoke-host.mts
@@ -0,0 +1,289 @@
+import { mkdtemp, readFile, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { dirname, join, resolve } from 'node:path';
+import { fileURLToPath, pathToFileURL } from 'node:url';
+
+import {
+  connect,
+  controlPacket,
+  onceClosed,
+  onceConnected,
+  readExchange,
+  readSingleByte,
+  simpleQuery,
+  startupPacket,
+} from '../../../../sdks/ts-wasix/sdk/tools/pgwire-client.mts';
+
+const root = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../..');
+const runtimeName = readRuntime(process.argv.slice(3));
+const seed = await readFile(
+  resolve(root, 'src/test-fixtures/postgres/logical-tools-seed.sql'),
+  'utf8',
+);
+const verify = await readFile(
+  resolve(root, 'src/test-fixtures/postgres/logical-tools-verify.sql'),
+  'utf8',
+);
+const fixture = JSON.parse(
+  await readFile(resolve(root, 'src/test-fixtures/postgres/logical-tools.json'), 'utf8'),
+);
+const socketOperationTimeoutMs = 30_000;
+const queuedClientObservationMs = 100;
+const packed = JSON.parse(await readFile(process.argv[2], 'utf8'));
+const packageRoot = (name) => resolve(packed.consumer, 'node_modules', ...name.split('/'));
+const runtime = (
+  await import(pathToFileURL(resolve(packageRoot(packed.packages.runtime.name), 'index.js')).href)
+).default;
+const { default: Oliphaunt } = await import(
+  pathToFileURL(resolve(packageRoot(packed.packages.binding.name), `lib/index.${runtimeName}.js`))
+    .href
+);
+const { default: WorkerOliphaunt } = await import(
+  pathToFileURL(
+    resolve(packageRoot(packed.packages.binding.name), `lib/worker-entry.${runtimeName}.js`),
+  ).href
+);
+const { PostgresToolError, pgDump, psql } = await import(
+  pathToFileURL(resolve(packageRoot(packed.packages.toolsFacade.name), 'lib/index.js')).href
+);
+const { openServer } = await import(
+  pathToFileURL(resolve(packageRoot(packed.packages.binding.name), 'lib/server.node.js')).href
+);
+const { default: extension } = await import(
+  pathToFileURL(resolve(packageRoot(packed.packages.extension.name), 'index.js')).href
+);
+
+console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: logical tools`);
+await verifyLogicalTools({
+  Oliphaunt,
+  WorkerOliphaunt,
+  PostgresToolError,
+  pgDump,
+  psql,
+  extension,
+});
+console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: TCP server`);
+await verifyServer(openServer, { transport: 'tcp' });
+if (process.platform !== 'win32') {
+  const directory = await mkdtemp(join(tmpdir(), `oliphaunt-wasix-${runtimeName}-socket-`));
+  try {
+    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: Unix server`);
+    await verifyServer(openServer, { transport: 'unix', directory, port: 6543 });
+  } finally {
+    await rm(directory, { force: true, recursive: true });
+  }
+}
+
+console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: PASS`);
+
+async function verifyLogicalTools({
+  Oliphaunt,
+  WorkerOliphaunt,
+  PostgresToolError,
+  pgDump,
+  psql,
+  extension,
+}) {
+  const source = await WorkerOliphaunt.open({ extensions: [extension] });
+  let sql;
+  try {
+    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: psql seed`);
+    await psql(source, { script: seed });
+    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: pg_dump`);
+    sql = await pgDump(source);
+    if (!sql.includes('COPY public.logical_items') || sql.includes('--inserts')) {
+      throw new Error('pg_dump did not preserve standard plain COPY output');
+    }
+    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: pg_dump schema`);
+    const schema = await pgDump(source, { args: ['--schema-only'] });
+    if (!schema.includes('CREATE TABLE') || schema.includes('COPY public.logical_items')) {
+      throw new Error('pg_dump --schema-only returned an invalid logical dump');
+    }
+    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: psql error`);
+    try {
+      await psql(source, { command: 'SELEC 1' });
+      throw new Error('invalid psql command unexpectedly succeeded');
+    } catch (error) {
+      if (!(error instanceof PostgresToolError) || error.exitCode === null || error.stderr === '') {
+        throw error;
+      }
+    }
+  } finally {
+    await source.close();
+  }
+
+  if (runtimeName === 'node') {
+    await verifyDirectPgDump(Oliphaunt, pgDump);
+  }
+
+  const target = await WorkerOliphaunt.open({ extensions: [extension] });
+  try {
+    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: psql restore`);
+    await psql(target, { script: sql });
+    const result = await target.queryRaw(verify);
+    const expected = fixture.expected;
+    const actual = {
+      rows: Number(result.getText(0, 'rows')),
+      sum: Number(result.getText(0, 'sum')),
+      sequenceLastValue: Number(result.getText(0, 'sequence_last_value')),
+      quotedValue: result.getText(0, 'quoted_value'),
+      normalizedMatches: Number(result.getText(0, 'normalized_matches')),
+      extensionLoaded: result.getText(0, 'extension_loaded') === 't',
+    };
+    if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+      throw new Error(
+        `logical tool round trip differed from the shared fixture: ${JSON.stringify(actual)}`,
+      );
+    }
+  } finally {
+    await target.close();
+  }
+}
+
+async function verifyDirectPgDump(Oliphaunt, pgDump) {
+  console.log('WASIX TypeScript node tools/server smoke: direct pg_dump');
+  const database = await Oliphaunt.open();
+  try {
+    await database.execute(
+      'CREATE TABLE direct_dump_probe (id integer PRIMARY KEY, value text NOT NULL)',
+    );
+    await database.execute("INSERT INTO direct_dump_probe VALUES (1, 'same-realm')");
+    const sql = await pgDump(database);
+    if (!sql.includes('COPY public.direct_dump_probe') || !sql.includes('same-realm')) {
+      throw new Error('direct pg_dump did not preserve standard plain COPY output');
+    }
+    const result = await database.queryRaw('SELECT count(*)::int AS rows FROM direct_dump_probe');
+    if (result.getText(0, 'rows') !== '1') {
+      throw new Error('direct database was not usable after pg_dump');
+    }
+  } finally {
+    await database.close();
+  }
+}
+
+async function verifyServer(openServer, listen) {
+  const server = await openServer({ listen });
+  try {
+    const socket = connect(server.connectionString);
+    let queued;
+    let queuedStartup;
+    try {
+      await withSocketDeadline(socket, onceConnected(socket), 'first client connect');
+      for (const code of [80_877_103, 80_877_104]) {
+        const negotiation = withSocketDeadline(
+          socket,
+          readSingleByte(socket),
+          `PostgreSQL negotiation ${code}`,
+        );
+        socket.write(controlPacket(code));
+        const response = await negotiation;
+        if (response !== 'N'.charCodeAt(0)) {
+          throw new Error(
+            `local server returned ${response} for PostgreSQL negotiation request ${code}`,
+          );
+        }
+      }
+      const firstStartup = withSocketDeadline(socket, readExchange(socket), 'first client startup');
+      socket.write(startupPacket('postgres', 'postgres'));
+      await firstStartup;
+      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: first startup`);
+
+      // The Rust listener deliberately owns one complete client at a time. A
+      // second TCP/Unix connection can finish its host handshake in the OS
+      // backlog, but its PostgreSQL startup must wait for the active backend.
+      queued = connect(server.connectionString);
+      await withSocketDeadline(queued, onceConnected(queued), 'queued client connect');
+      queuedStartup = readExchange(queued);
+      queued.write(startupPacket('postgres', 'postgres'));
+      await expectStillPending(queuedStartup, queuedClientObservationMs, 'queued client startup');
+      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: second client queued`);
+
+      const copy = withSocketDeadline(socket, readExchange(socket), 'first client COPY');
+      socket.write(simpleQuery('COPY (SELECT generate_series(1, 100000)) TO STDOUT'));
+      const copied = await copy;
+      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: first COPY`);
+      if (copied.copyBytes < 500_000) {
+        throw new Error(`local server truncated COPY output at ${copied.copyBytes} bytes`);
+      }
+      const begin = withSocketDeadline(socket, readExchange(socket), 'first client BEGIN');
+      socket.write(simpleQuery('BEGIN'));
+      await begin;
+      const create = withSocketDeadline(
+        socket,
+        readExchange(socket),
+        'first client transaction query',
+      );
+      socket.write(simpleQuery('CREATE TABLE disconnect_must_rollback(value integer)'));
+      await create;
+      const firstClosed = withSocketDeadline(socket, onceClosed(socket), 'first client disconnect');
+      socket.destroy();
+      await firstClosed;
+      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: disconnect recovered`);
+
+      await withSocketDeadline(queued, queuedStartup, 'queued client startup after handoff');
+      const queuedQuery = withSocketDeadline(queued, readExchange(queued), 'queued client query');
+      queued.write(simpleQuery('CREATE TABLE disconnect_must_rollback(value integer)'));
+      await queuedQuery;
+      const queuedClosed = withSocketDeadline(queued, onceClosed(queued), 'queued client close');
+      queued.end(Uint8Array.of('X'.charCodeAt(0), 0, 0, 0, 4));
+      await queuedClosed;
+      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: queued client accepted`);
+    } finally {
+      socket.destroy();
+      queued?.destroy();
+      await queuedStartup?.catch(() => undefined);
+    }
+  } finally {
+    await server.close();
+  }
+}
+
+function withSocketDeadline(socket, operation, label) {
+  return new Promise((resolveOperation, rejectOperation) => {
+    let settled = false;
+    const finish = (settle, value) => {
+      if (settled) return;
+      settled = true;
+      clearTimeout(timeout);
+      settle(value);
+    };
+    const timeout = setTimeout(() => {
+      if (settled) return;
+      settled = true;
+      socket.destroy();
+      rejectOperation(new Error(`${label} timed out after ${socketOperationTimeoutMs}ms`));
+    }, socketOperationTimeoutMs);
+    operation.then(
+      (value) => finish(resolveOperation, value),
+      (error) => finish(rejectOperation, error),
+    );
+  });
+}
+
+async function expectStillPending(operation, observationMs, label) {
+  let timeout;
+  const observed = await Promise.race([
+    operation.then(
+      () => ({ status: 'resolved' }),
+      (error) => ({ status: 'rejected', error }),
+    ),
+    new Promise((resolveObservation) => {
+      timeout = setTimeout(() => resolveObservation({ status: 'pending' }), observationMs);
+    }),
+  ]);
+  clearTimeout(timeout);
+  if (observed.status === 'pending') return;
+  if (observed.status === 'rejected') {
+    throw new Error(`${label} was rejected instead of waiting behind the active client`, {
+      cause: observed.error,
+    });
+  }
+  throw new Error(`${label} completed while the first client still owned the embedded backend`);
+}
+
+function readRuntime(args) {
+  if (args.length !== 2 || args[0] !== '--runtime' || !['node', 'bun', 'deno'].includes(args[1])) {
+    throw new Error('usage: smoke-host.mjs --runtime node|bun|deno');
+  }
+  return args[1];
+}
diff --git a/src/postgres-tools/wasix/ts/tests/smoke-host.sh b/src/postgres-tools/wasix/ts/tests/smoke-host.sh
new file mode 100644
index 000000000..d2cdeb077
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tests/smoke-host.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../../.." && pwd)"
+if [ "$#" != 2 ] || [ "$1" != --runtime ]; then
+  echo 'usage: smoke-host.sh --runtime node|bun|deno' >&2
+  exit 1
+fi
+case "$2" in
+  node) host=(node) ;;
+  bun) host=(bash "$root/tools/dev/bun.sh") ;;
+  deno) host=(bash "$root/tools/dev/deno.sh" run --allow-all) ;;
+  *) echo "unsupported tools smoke runtime: $2" >&2; exit 1 ;;
+esac
+deadline="$(command -v gtimeout || command -v timeout)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+bun run --cwd "$root/src/sdks/ts-query" build
+bun pm --cwd "$root/src/sdks/ts-query" pack --filename "$scratch/query.tgz" --quiet
+bun "$root/src/sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts" "$scratch" --pgtap --tools
+cd "$scratch/consumer"
+if [ "$2" = deno ]; then
+  printf '%s\n' '{"nodeModulesDir":"manual"}' > deno.json
+  host+=(--config "$scratch/consumer/deno.json")
+fi
+export NPM_CONFIG_IGNORE_SCRIPTS=true
+"$deadline" --kill-after=3s 120s bun install --ignore-scripts
+"$deadline" --kill-after=3s 300s "${host[@]}" \
+  "$root/src/postgres-tools/wasix/ts/tests/smoke-host.mts" "$scratch/packed-consumer.json" "$@"
diff --git a/src/postgres-tools/wasix/ts/tools/package.mts b/src/postgres-tools/wasix/ts/tools/package.mts
new file mode 100755
index 000000000..a3d4b8e27
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tools/package.mts
@@ -0,0 +1,61 @@
+#!/usr/bin/env bun
+import {
+  copyFileSync,
+  cpSync,
+  existsSync,
+  mkdirSync,
+  readFileSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { stageReleaseNotices } from '../../../../../tools/packaging/release-notices.mts';
+
+export const ROOT = path.resolve(import.meta.dirname, '../../../../..');
+const SOURCE = path.join(ROOT, 'src/postgres-tools/wasix/ts');
+const CARRIER = '@oliphaunt/liboliphaunt-wasix-tools';
+const BINDING = '@oliphaunt/wasix-ts';
+
+export function prepareWasixToolsTypescriptPackage(packageDir, bindingVersion) {
+  if (!/^\d+\.\d+\.\d+$/u.test(bindingVersion)) throw new Error('binding version must be exact');
+  const manifestFile = path.join(packageDir, 'package.json');
+  const manifest = JSON.parse(readFileSync(manifestFile, 'utf8'));
+  const runtimeVersion = manifest.oliphaunt?.runtimeVersion;
+  if (!/^\d+\.\d+\.\d+$/u.test(runtimeVersion)) throw new Error('runtime version must be exact');
+  manifest.dependencies = { [CARRIER]: manifest.version };
+  manifest.peerDependencies = { [BINDING]: bindingVersion };
+  delete manifest.scripts;
+  delete manifest.devDependencies;
+  writeFileSync(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`);
+  stageReleaseNotices(packageDir, { profile: 'source-sdk' });
+  return manifest;
+}
+
+export function stageWasixToolsTypescriptPackage(outputDir, bindingVersion) {
+  const destination = path.resolve(ROOT, outputDir);
+  const relative = path.relative(ROOT, destination);
+  if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
+    throw new Error(`WASIX tools package stage must stay inside the repository: ${outputDir}`);
+  }
+  rmSync(destination, { recursive: true, force: true });
+  mkdirSync(destination, { recursive: true });
+  const manifest = JSON.parse(readFileSync(path.join(SOURCE, 'package.json'), 'utf8'));
+  copyFileSync(path.join(SOURCE, 'package.json'), path.join(destination, 'package.json'));
+  for (const name of manifest.files ?? []) {
+    const source = path.join(SOURCE, name);
+    if (existsSync(source)) cpSync(source, path.join(destination, name), { recursive: true });
+  }
+  copyFileSync(
+    path.join(ROOT, 'src/postgres-tools/wasix/CHANGELOG.md'),
+    path.join(destination, 'CHANGELOG.md'),
+  );
+  return prepareWasixToolsTypescriptPackage(destination, bindingVersion);
+}
+
+if (import.meta.main) {
+  const output = process.argv[2] ?? 'target/oliphaunt-wasix-tools-ts/package';
+  const binding = JSON.parse(
+    readFileSync(path.join(ROOT, 'src/sdks/ts-wasix/sdk/package.json'), 'utf8'),
+  );
+  stageWasixToolsTypescriptPackage(output, binding.version);
+}
diff --git a/src/postgres-tools/wasix/ts/tools/package.sh b/src/postgres-tools/wasix/ts/tools/package.sh
new file mode 100644
index 000000000..88cf5a86b
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tools/package.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../../../../.."
+bun src/postgres-tools/wasix/ts/tools/package.mts target/oliphaunt-wasix-tools-ts/package
+mkdir -p target/oliphaunt-wasix-tools-ts/package/packages
+bun pm pack --cwd target/oliphaunt-wasix-tools-ts/package --quiet --destination packages
+bun src/postgres-tools/wasix/ts/tools/stage-release-artifacts.mts
diff --git a/src/postgres-tools/wasix/ts/tools/stage-release-artifacts.mts b/src/postgres-tools/wasix/ts/tools/stage-release-artifacts.mts
new file mode 100644
index 000000000..805f9aa27
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tools/stage-release-artifacts.mts
@@ -0,0 +1,13 @@
+import { copyFileSync } from 'node:fs';
+import path from 'node:path';
+import { ROOT, filesUnder, stageSdkArtifacts } from '../../../../../tools/packaging/staging.mts';
+import { assertWasixToolsTypescriptNpmArchive } from './wasix-tools-typescript-package.mts';
+await stageSdkArtifacts('postgres-tools-wasix', (artifactRoot) => {
+  const archives = filesUnder(
+    path.join(ROOT, 'target/oliphaunt-wasix-tools-ts/package/packages'),
+  ).filter((file) => file.endsWith('.tgz'));
+  if (archives.length !== 1)
+    throw new Error(`Expected one PostgreSQL tools facade archive, found ${archives.length}`);
+  assertWasixToolsTypescriptNpmArchive(archives[0]);
+  copyFileSync(archives[0], path.join(artifactRoot, path.basename(archives[0])));
+});
diff --git a/src/postgres-tools/wasix/ts/tools/wasix-tools-typescript-package.mts b/src/postgres-tools/wasix/ts/tools/wasix-tools-typescript-package.mts
new file mode 100644
index 000000000..d436e0654
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tools/wasix-tools-typescript-package.mts
@@ -0,0 +1,112 @@
+import path from 'node:path';
+
+import { prepareWasixToolsTypescriptPackage as prepareProductPackage } from './package.mts';
+
+import { validateNpmTrustedPublishingManifest } from '../../../../../tools/packaging/npm-trusted-publishing.mts';
+import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  releasePackageLicense,
+} from '../../../../../tools/packaging/release-notices.mts';
+
+const TOOL = 'wasix-tools-typescript-package.mts';
+const PACKAGE_NAME = '@oliphaunt/wasix-tools';
+const TOOLS_CARRIER = '@oliphaunt/liboliphaunt-wasix-tools';
+const WASIX_BINDING = '@oliphaunt/wasix-ts';
+const NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' });
+const EXACT_VERSION = /^\d+\.\d+\.\d+$/u;
+
+function fail(message) {
+  throw new Error(`${TOOL}: ${message}`);
+}
+
+export function prepareWasixToolsTypescriptPackage(packageDir, bindingVersion) {
+  const root = path.resolve(packageDir);
+  const manifest = prepareProductPackage(root, bindingVersion);
+  assertReleaseNoticesInDirectory(root, NOTICE_OPTIONS);
+  assertWasixToolsTypescriptManifest(manifest, `${PACKAGE_NAME} staged package`);
+  return manifest;
+}
+
+export function assertWasixToolsTypescriptManifest(manifest, label = PACKAGE_NAME) {
+  validateNpmTrustedPublishingManifest(manifest, label);
+  if (
+    manifest.name !== PACKAGE_NAME ||
+    !EXACT_VERSION.test(manifest.version) ||
+    manifest.private === true ||
+    manifest.license !== releasePackageLicense().spdx ||
+    manifest.type !== 'module' ||
+    manifest.scripts !== undefined ||
+    manifest.devDependencies !== undefined
+  ) {
+    fail(`${label} is not the exact public source-only tools package`);
+  }
+  const dependencies = manifest.dependencies ?? {};
+  const peerDependencies = manifest.peerDependencies ?? {};
+  if (
+    JSON.stringify(Object.keys(dependencies)) !== JSON.stringify([TOOLS_CARRIER]) ||
+    dependencies[TOOLS_CARRIER] !== manifest.version ||
+    JSON.stringify(Object.keys(peerDependencies)) !== JSON.stringify([WASIX_BINDING]) ||
+    !EXACT_VERSION.test(peerDependencies[WASIX_BINDING]) ||
+    manifest.oliphaunt?.runtimeProduct !== 'liboliphaunt-wasix' ||
+    !EXACT_VERSION.test(manifest.oliphaunt?.runtimeVersion) ||
+    Object.keys(manifest.optionalDependencies ?? {}).length > 0
+  ) {
+    fail(`${label} must depend on the exact tools carrier and peer with its exact WASIX binding`);
+  }
+  if (
+    manifest.exports?.['.']?.types !== './lib/index.d.ts' ||
+    manifest.exports?.['.']?.default !== './lib/index.js' ||
+    manifest.exports?.['./package.json'] !== './package.json'
+  ) {
+    fail(`${label} exports differ from the two-function public package surface`);
+  }
+  return manifest;
+}
+
+export function assertWasixToolsTypescriptNpmArchive(archive) {
+  const file = path.resolve(archive);
+  assertReleaseNoticesInArchive(file, { ...NOTICE_OPTIONS, prefix: 'package' });
+  const entries = readPortableArchiveEntries(file);
+  const manifest = assertWasixToolsTypescriptManifest(
+    JSON.parse(required(entries, 'package/package.json').toString('utf8')),
+    `${path.basename(file)} package.json`,
+  );
+  if (
+    JSON.stringify([...(manifest.files ?? [])].sort()) !==
+    JSON.stringify(['CHANGELOG.md', 'LICENSE', 'README.md', 'THIRD_PARTY_NOTICES.md', 'lib'])
+  ) {
+    fail(`${file} package.json files differ from the owned package roots`);
+  }
+  const allowed = new Set(['package.json', ...manifest.files.filter((name) => name !== 'lib')]);
+  for (const [name, entry] of entries) {
+    if (entry.isSymbolicLink) fail(`${file} contains symbolic link ${name}`);
+    const relative = name.replace(/^package\//u, '');
+    if (entry.isFile && !allowed.has(relative) && !relative.startsWith('lib/')) {
+      fail(`${file} contains file outside package.json files: ${name}`);
+    }
+  }
+  for (const name of [
+    'README.md',
+    'LICENSE',
+    'THIRD_PARTY_NOTICES.md',
+    'lib/index.d.ts',
+    'lib/index.js',
+  ]) {
+    required(entries, `package/${name}`);
+  }
+  for (const name of ['CHANGELOG.md']) {
+    if (name === 'CHANGELOG.md' && manifest.version === '0.0.0') continue;
+    required(entries, `package/${name}`);
+  }
+  return manifest;
+}
+
+function required(entries, member) {
+  const entry = entries.get(member);
+  if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) {
+    fail(`package is missing non-empty regular ${member}`);
+  }
+  return Buffer.from(entry.data());
+}
diff --git a/src/postgres-tools/wasix/ts/tools/wasix-tools-typescript-package.test.mts b/src/postgres-tools/wasix/ts/tools/wasix-tools-typescript-package.test.mts
new file mode 100644
index 000000000..e9aa5eefb
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tools/wasix-tools-typescript-package.test.mts
@@ -0,0 +1,47 @@
+import { describe, expect, test } from 'bun:test';
+
+import { assertWasixToolsTypescriptManifest } from './wasix-tools-typescript-package.mts';
+
+function manifest() {
+  return {
+    name: '@oliphaunt/wasix-tools',
+    version: '1.2.3',
+    license: 'MIT',
+    type: 'module',
+    repository: {
+      type: 'git',
+      url: 'git+https://github.com/f0rr0/oliphaunt.git',
+      directory: 'src/postgres-tools/wasix/ts',
+    },
+    publishConfig: { access: 'public', provenance: true },
+    oliphaunt: {
+      runtimeProduct: 'liboliphaunt-wasix',
+      runtimeVersion: '4.5.6',
+    },
+    dependencies: {
+      '@oliphaunt/liboliphaunt-wasix-tools': '1.2.3',
+    },
+    peerDependencies: {
+      '@oliphaunt/wasix-ts': '7.8.9',
+    },
+    exports: {
+      '.': { types: './lib/index.d.ts', default: './lib/index.js' },
+      './package.json': './package.json',
+    },
+  };
+}
+
+describe('WASIX TypeScript tools package contract', () => {
+  test('accepts only the exact binding and carrier closure', () => {
+    expect(() => assertWasixToolsTypescriptManifest(manifest())).not.toThrow();
+  });
+
+  test('rejects semver ranges and extra dependencies', () => {
+    const range = manifest();
+    range.peerDependencies['@oliphaunt/wasix-ts'] = '^1.2.3';
+    expect(() => assertWasixToolsTypescriptManifest(range)).toThrow(/exact WASIX binding/);
+    const extra = manifest();
+    extra.dependencies.other = '1.0.0';
+    expect(() => assertWasixToolsTypescriptManifest(extra)).toThrow(/exact WASIX binding/);
+  });
+});
diff --git a/src/bindings/wasix-ts/tools-package/tsconfig.build.json b/src/postgres-tools/wasix/ts/tsconfig.build.json
similarity index 100%
rename from src/bindings/wasix-ts/tools-package/tsconfig.build.json
rename to src/postgres-tools/wasix/ts/tsconfig.build.json
diff --git a/src/postgres-tools/wasix/ts/tsconfig.json b/src/postgres-tools/wasix/ts/tsconfig.json
new file mode 100644
index 000000000..16b519c48
--- /dev/null
+++ b/src/postgres-tools/wasix/ts/tsconfig.json
@@ -0,0 +1,22 @@
+{
+  "compilerOptions": {
+    "declaration": true,
+    "declarationMap": false,
+    "lib": ["ES2023", "DOM", "WebWorker"],
+    "module": "NodeNext",
+    "moduleResolution": "NodeNext",
+    "noEmit": true,
+    "noUncheckedIndexedAccess": true,
+    "outDir": "lib",
+    "paths": {
+      "@oliphaunt/liboliphaunt-wasix-tools": ["../npm/index.d.ts"]
+    },
+    "rootDir": "src",
+    "skipLibCheck": true,
+    "strict": true,
+    "target": "ES2022",
+    "types": ["node", "bun"]
+  },
+  "include": ["src/**/*"],
+  "exclude": ["lib", "node_modules"]
+}
diff --git a/src/runtimes/broker/CHANGELOG.md b/src/runtimes/broker/CHANGELOG.md
deleted file mode 100644
index 82205c70b..000000000
--- a/src/runtimes/broker/CHANGELOG.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# Changelog
-
-## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-broker-v0.1.1...oliphaunt-broker-v0.2.0) (2026-09-05)
-
-
-### ⚠ BREAKING CHANGES
-
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
-
-### Features
-
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))
-* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
-
-
-### Code Refactoring
-
-* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
-* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
-
-## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-broker-v0.1.0...oliphaunt-broker-v0.1.1) (2026-08-08)
-
-
-### Bug Fixes
-
-* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))
-
-## 0.1.0 (2026-07-28)
-
-
-### Features
-
-* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/runtimes/broker/Cargo.toml b/src/runtimes/broker/Cargo.toml
deleted file mode 100644
index c046c156d..000000000
--- a/src/runtimes/broker/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "oliphaunt-broker"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Oliphaunt broker helper process for process-isolated embedded PostgreSQL."
-readme = "README.md"
-repository.workspace = true
-homepage.workspace = true
-license = "MIT"
-publish = false
-
-[[bin]]
-name = "oliphaunt-broker"
-path = "src/main.rs"
-
-[dependencies]
-oliphaunt = { path = "../../sdks/rust", version = "*", features = ["__internal-broker-helper"] }
diff --git a/src/runtimes/broker/README.md b/src/runtimes/broker/README.md
deleted file mode 100644
index 73e23c77b..000000000
--- a/src/runtimes/broker/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# oliphaunt-broker
-
-`oliphaunt-broker` is the helper process used by broker mode. It owns one
-native database root per process, serves the Oliphaunt broker IPC protocol, and
-is packaged as platform-specific release assets for SDKs that need process
-isolation.
-
-Application developers should use their SDK's broker mode instead of invoking
-this binary directly.
-
-## Release licensing
-
-The source-only `oliphaunt-broker` crate is Oliphaunt code under MIT and is not
-published. The four compiled target carriers also contain the exact normal
-Rust dependency graph selected for their OS target. Those binary carriers
-therefore declare the complete payload expression and carry a target-specific
-`THIRD_PARTY_LICENSES/rust/DEPENDENCIES.json` plus its byte-pinned license
-texts.
-
-`dependency-licenses.json` binds every registry dependency to its Cargo.lock
-name, version, checksum, declared license, selected redistribution branch,
-target set, and complete LICENSE/UNLICENSE/COPYING/NOTICE/COPYRIGHT plus
-author, credit, patent, and third-party attribution inventory.
-`tools/release/broker-dependency-license-contract.mjs check-contract` verifies
-the self-contained contract and committed canonical blobs without consulting
-Cargo or a registry cache. The connected production audit runs
-`tools/release/broker-dependency-license-contract.mjs audit-contract`: it
-creates an empty Cargo home, fetches the exact locked workspace closure for all
-targets, then verifies every target graph and canonical source byte offline in
-that same home. A dependency update is incomplete until that audit passes and
-all four packed target carriers reopen the exact updated closure.
diff --git a/src/runtimes/broker/crates/linux-arm64-gnu/Cargo.toml b/src/runtimes/broker/crates/linux-arm64-gnu/Cargo.toml
deleted file mode 100644
index 01e3a9460..000000000
--- a/src/runtimes/broker/crates/linux-arm64-gnu/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "oliphaunt-broker-linux-arm64-gnu"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Cargo artifact crate for the linux-arm64-gnu oliphaunt-broker helper binary."
-readme = "README.md"
-repository = "https://github.com/f0rr0/oliphaunt"
-homepage = "https://oliphaunt.dev"
-license = "MIT AND ISC AND Unicode-3.0"
-links = "oliphaunt_artifact_broker_linux_arm64_gnu"
-build = "build.rs"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_LICENSES/**"]
-
-[lib]
-path = "src/lib.rs"
-
-[workspace]
diff --git a/src/runtimes/broker/crates/linux-x64-gnu/Cargo.toml b/src/runtimes/broker/crates/linux-x64-gnu/Cargo.toml
deleted file mode 100644
index 4be8eab30..000000000
--- a/src/runtimes/broker/crates/linux-x64-gnu/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "oliphaunt-broker-linux-x64-gnu"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Cargo artifact crate for the linux-x64-gnu oliphaunt-broker helper binary."
-readme = "README.md"
-repository = "https://github.com/f0rr0/oliphaunt"
-homepage = "https://oliphaunt.dev"
-license = "MIT AND ISC AND Unicode-3.0"
-links = "oliphaunt_artifact_broker_linux_x64_gnu"
-build = "build.rs"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_LICENSES/**"]
-
-[lib]
-path = "src/lib.rs"
-
-[workspace]
diff --git a/src/runtimes/broker/crates/macos-arm64/Cargo.toml b/src/runtimes/broker/crates/macos-arm64/Cargo.toml
deleted file mode 100644
index 99f9d5c34..000000000
--- a/src/runtimes/broker/crates/macos-arm64/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "oliphaunt-broker-macos-arm64"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Cargo artifact crate for the macos-arm64 oliphaunt-broker helper binary."
-readme = "README.md"
-repository = "https://github.com/f0rr0/oliphaunt"
-homepage = "https://oliphaunt.dev"
-license = "MIT AND ISC AND Unicode-3.0"
-links = "oliphaunt_artifact_broker_macos_arm64"
-build = "build.rs"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_LICENSES/**"]
-
-[lib]
-path = "src/lib.rs"
-
-[workspace]
diff --git a/src/runtimes/broker/crates/windows-x64-msvc/Cargo.toml b/src/runtimes/broker/crates/windows-x64-msvc/Cargo.toml
deleted file mode 100644
index 187a1603f..000000000
--- a/src/runtimes/broker/crates/windows-x64-msvc/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "oliphaunt-broker-windows-x64-msvc"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Cargo artifact crate for the windows-x64-msvc oliphaunt-broker helper binary."
-readme = "README.md"
-repository = "https://github.com/f0rr0/oliphaunt"
-homepage = "https://oliphaunt.dev"
-license = "MIT AND ISC AND Unicode-3.0"
-links = "oliphaunt_artifact_broker_windows_x64_msvc"
-build = "build.rs"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_LICENSES/**"]
-
-[lib]
-path = "src/lib.rs"
-
-[workspace]
diff --git a/src/runtimes/broker/dependency-licenses.json b/src/runtimes/broker/dependency-licenses.json
deleted file mode 100644
index 4e7bd635c..000000000
--- a/src/runtimes/broker/dependency-licenses.json
+++ /dev/null
@@ -1,741 +0,0 @@
-{
-  "schema": "oliphaunt-broker-dependency-license-contract-v1",
-  "product": "oliphaunt-broker",
-  "cargoSource": "registry+https://github.com/rust-lang/crates.io-index",
-  "payloadLicense": "MIT AND ISC AND Unicode-3.0",
-  "targets": {
-    "linux-x64-gnu": {
-      "cargoTarget": "x86_64-unknown-linux-gnu",
-      "packages": [
-        "block-buffer@0.10.4",
-        "cfg-if@1.0.4",
-        "cpufeatures@0.2.17",
-        "crypto-common@0.1.7",
-        "digest@0.10.7",
-        "fs2@0.4.3",
-        "generic-array@0.14.7",
-        "getrandom@0.3.4",
-        "itoa@1.0.18",
-        "libc@0.2.186",
-        "libloading@0.8.9",
-        "memchr@2.8.1",
-        "proc-macro2@1.0.106",
-        "quote@1.0.45",
-        "serde@1.0.228",
-        "serde_core@1.0.228",
-        "serde_derive@1.0.228",
-        "serde_json@1.0.150",
-        "sha2@0.10.9",
-        "syn@2.0.117",
-        "typenum@1.20.1",
-        "unicode-ident@1.0.24",
-        "zmij@1.0.21"
-      ]
-    },
-    "linux-arm64-gnu": {
-      "cargoTarget": "aarch64-unknown-linux-gnu",
-      "packages": [
-        "block-buffer@0.10.4",
-        "cfg-if@1.0.4",
-        "cpufeatures@0.2.17",
-        "crypto-common@0.1.7",
-        "digest@0.10.7",
-        "fs2@0.4.3",
-        "generic-array@0.14.7",
-        "getrandom@0.3.4",
-        "itoa@1.0.18",
-        "libc@0.2.186",
-        "libloading@0.8.9",
-        "memchr@2.8.1",
-        "proc-macro2@1.0.106",
-        "quote@1.0.45",
-        "serde@1.0.228",
-        "serde_core@1.0.228",
-        "serde_derive@1.0.228",
-        "serde_json@1.0.150",
-        "sha2@0.10.9",
-        "syn@2.0.117",
-        "typenum@1.20.1",
-        "unicode-ident@1.0.24",
-        "zmij@1.0.21"
-      ]
-    },
-    "macos-arm64": {
-      "cargoTarget": "aarch64-apple-darwin",
-      "packages": [
-        "block-buffer@0.10.4",
-        "cfg-if@1.0.4",
-        "cpufeatures@0.2.17",
-        "crypto-common@0.1.7",
-        "digest@0.10.7",
-        "fs2@0.4.3",
-        "generic-array@0.14.7",
-        "getrandom@0.3.4",
-        "itoa@1.0.18",
-        "libc@0.2.186",
-        "libloading@0.8.9",
-        "memchr@2.8.1",
-        "proc-macro2@1.0.106",
-        "quote@1.0.45",
-        "serde@1.0.228",
-        "serde_core@1.0.228",
-        "serde_derive@1.0.228",
-        "serde_json@1.0.150",
-        "sha2@0.10.9",
-        "syn@2.0.117",
-        "typenum@1.20.1",
-        "unicode-ident@1.0.24",
-        "zmij@1.0.21"
-      ]
-    },
-    "windows-x64-msvc": {
-      "cargoTarget": "x86_64-pc-windows-msvc",
-      "packages": [
-        "block-buffer@0.10.4",
-        "cfg-if@1.0.4",
-        "cpufeatures@0.2.17",
-        "crypto-common@0.1.7",
-        "digest@0.10.7",
-        "fs2@0.4.3",
-        "generic-array@0.14.7",
-        "getrandom@0.3.4",
-        "itoa@1.0.18",
-        "libloading@0.8.9",
-        "memchr@2.8.1",
-        "proc-macro2@1.0.106",
-        "quote@1.0.45",
-        "serde@1.0.228",
-        "serde_core@1.0.228",
-        "serde_derive@1.0.228",
-        "serde_json@1.0.150",
-        "sha2@0.10.9",
-        "syn@2.0.117",
-        "typenum@1.20.1",
-        "unicode-ident@1.0.24",
-        "winapi@0.3.9",
-        "windows-link@0.2.1",
-        "zmij@1.0.21"
-      ]
-    }
-  },
-  "packages": [
-    {
-      "name": "block-buffer",
-      "version": "0.10.4",
-      "checksum": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
-          "bytes": 10849
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef",
-          "bytes": 1082
-        }
-      ]
-    },
-    {
-      "name": "cfg-if",
-      "version": "1.0.4",
-      "checksum": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
-          "bytes": 10847
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
-          "bytes": 1057
-        }
-      ]
-    },
-    {
-      "name": "cpufeatures",
-      "version": "0.2.17",
-      "checksum": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
-          "bytes": 10849
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985",
-          "bytes": 1082
-        }
-      ]
-    },
-    {
-      "name": "crypto-common",
-      "version": "0.1.7",
-      "checksum": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
-          "bytes": 10849
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897",
-          "bytes": 1065
-        }
-      ]
-    },
-    {
-      "name": "digest",
-      "version": "0.10.7",
-      "checksum": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
-          "bytes": 10849
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba",
-          "bytes": 1057
-        }
-      ]
-    },
-    {
-      "name": "fs2",
-      "version": "0.4.3",
-      "checksum": "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213",
-      "declaredLicense": "MIT/Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
-          "bytes": 10847
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
-          "bytes": 1071
-        }
-      ]
-    },
-    {
-      "name": "generic-array",
-      "version": "0.14.7",
-      "checksum": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a",
-      "declaredLicense": "MIT",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE",
-          "sha256": "c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583",
-          "bytes": 1107
-        }
-      ]
-    },
-    {
-      "name": "getrandom",
-      "version": "0.3.4",
-      "checksum": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
-          "bytes": 10849
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4",
-          "bytes": 1130
-        }
-      ]
-    },
-    {
-      "name": "itoa",
-      "version": "1.0.18",
-      "checksum": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        }
-      ]
-    },
-    {
-      "name": "libc",
-      "version": "0.2.186",
-      "checksum": "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e",
-          "bytes": 1066
-        }
-      ]
-    },
-    {
-      "name": "libloading",
-      "version": "0.8.9",
-      "checksum": "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55",
-      "declaredLicense": "ISC",
-      "selectedLicense": "ISC",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE",
-          "sha256": "b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f",
-          "bytes": 736
-        }
-      ]
-    },
-    {
-      "name": "memchr",
-      "version": "2.8.1",
-      "checksum": "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8",
-      "declaredLicense": "Unlicense OR MIT",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "COPYING",
-          "sha256": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
-          "bytes": 126
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f",
-          "bytes": 1081
-        },
-        {
-          "name": "UNLICENSE",
-          "sha256": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
-          "bytes": 1211
-        }
-      ]
-    },
-    {
-      "name": "proc-macro2",
-      "version": "1.0.106",
-      "checksum": "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        }
-      ]
-    },
-    {
-      "name": "quote",
-      "version": "1.0.45",
-      "checksum": "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        }
-      ]
-    },
-    {
-      "name": "serde",
-      "version": "1.0.228",
-      "checksum": "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        }
-      ]
-    },
-    {
-      "name": "serde_core",
-      "version": "1.0.228",
-      "checksum": "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        }
-      ]
-    },
-    {
-      "name": "serde_derive",
-      "version": "1.0.228",
-      "checksum": "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        }
-      ]
-    },
-    {
-      "name": "serde_json",
-      "version": "1.0.150",
-      "checksum": "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        }
-      ]
-    },
-    {
-      "name": "sha2",
-      "version": "0.10.9",
-      "checksum": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
-          "bytes": 10849
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1",
-          "bytes": 1138
-        }
-      ]
-    },
-    {
-      "name": "syn",
-      "version": "2.0.117",
-      "checksum": "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        }
-      ]
-    },
-    {
-      "name": "typenum",
-      "version": "1.20.1",
-      "checksum": "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE",
-          "sha256": "db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a",
-          "bytes": 17
-        },
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406",
-          "bytes": 10835
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f",
-          "bytes": 1083
-        }
-      ]
-    },
-    {
-      "name": "unicode-ident",
-      "version": "1.0.24",
-      "checksum": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75",
-      "declaredLicense": "(MIT OR Apache-2.0) AND Unicode-3.0",
-      "selectedLicense": "MIT AND Unicode-3.0",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
-          "bytes": 9723
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        },
-        {
-          "name": "LICENSE-UNICODE",
-          "sha256": "f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1",
-          "bytes": 1995
-        }
-      ]
-    },
-    {
-      "name": "winapi",
-      "version": "0.3.9",
-      "checksum": "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419",
-      "declaredLicense": "MIT/Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-APACHE",
-          "sha256": "b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1",
-          "bytes": 11357
-        },
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b",
-          "bytes": 1073
-        }
-      ]
-    },
-    {
-      "name": "windows-link",
-      "version": "0.2.1",
-      "checksum": "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5",
-      "declaredLicense": "MIT OR Apache-2.0",
-      "selectedLicense": "MIT",
-      "targets": [
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "license-apache-2.0",
-          "sha256": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
-          "bytes": 11351
-        },
-        {
-          "name": "license-mit",
-          "sha256": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
-          "bytes": 1141
-        }
-      ]
-    },
-    {
-      "name": "zmij",
-      "version": "1.0.21",
-      "checksum": "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa",
-      "declaredLicense": "MIT",
-      "selectedLicense": "MIT",
-      "targets": [
-        "linux-arm64-gnu",
-        "linux-x64-gnu",
-        "macos-arm64",
-        "windows-x64-msvc"
-      ],
-      "licenseFiles": [
-        {
-          "name": "LICENSE-MIT",
-          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
-          "bytes": 1023
-        }
-      ]
-    }
-  ]
-}
diff --git a/src/runtimes/broker/moon.yml b/src/runtimes/broker/moon.yml
deleted file mode 100644
index 34afe87ad..000000000
--- a/src/runtimes/broker/moon.yml
+++ /dev/null
@@ -1,90 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "oliphaunt-broker"
-language: "rust"
-layer: "library"
-stack: "systems"
-tags: ["runtime", "broker", "native", "postgres", "release-product"]
-dependsOn:
-  - "liboliphaunt-native"
-
-project:
-  title: "Oliphaunt Broker"
-  description: "Process-isolated broker helper runtime used by Rust and TypeScript SDKs."
-  owner: "oliphaunt"
-  release:
-    component: "oliphaunt-broker"
-    packagePath: "src/runtimes/broker"
-    artifactTargets:
-      preset: "broker-helper"
-      targets:
-        - "linux-arm64-gnu"
-        - "linux-x64-gnu"
-        - "macos-arm64"
-        - "windows-x64-msvc"
-
-owners:
-  defaultOwner: "@oliphaunt/broker"
-
-fileGroups:
-  code:
-    - "**/*"
-    - "!**/*.md"
-    - "!moon.yml"
-    - "!release.toml"
-
-tasks:
-  build:
-    tags: ["build", "requires-rust"]
-    command: "cargo build -p oliphaunt-broker --locked"
-    env:
-      CARGO_TARGET_DIR: "target/moon/oliphaunt-broker/build"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "@group(code)"
-      - project: "oliphaunt-rust"
-        group: "code"
-    outputs:
-      - "/target/moon/oliphaunt-broker/build/debug/oliphaunt-broker*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-
-  compile:
-    tags: ["quality", "static", "requires-rust"]
-    command: "cargo check -p oliphaunt-broker --locked"
-    env:
-      CARGO_TARGET_DIR: "target/moon/oliphaunt-broker/check"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "@group(code)"
-      - project: "oliphaunt-rust"
-        group: "code"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-
-  unit:
-    tags: ["quality", "unit", "requires-rust"]
-    command: "cargo test -p oliphaunt-broker --locked"
-    env:
-      CARGO_TARGET_DIR: "target/moon/oliphaunt-broker/unit"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "@group(code)"
-      - project: "oliphaunt-rust"
-        group: "code"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-
-  qualify:
-    tags: ["release"]
-    command: "true"
-    deps:
-      - "oliphaunt-broker:compile"
-      - "oliphaunt-broker:unit"
-    inputs: []
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
diff --git a/src/runtimes/broker/packages/darwin-arm64/package.json b/src/runtimes/broker/packages/darwin-arm64/package.json
deleted file mode 100644
index b14d0a127..000000000
--- a/src/runtimes/broker/packages/darwin-arm64/package.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "name": "@oliphaunt/broker-darwin-arm64",
-  "version": "0.2.0",
-  "description": "macOS arm64 oliphaunt-broker helper binary.",
-  "license": "MIT AND ISC AND Unicode-3.0",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/broker/packages/darwin-arm64"
-  },
-  "os": [
-    "darwin"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "brokerHelper": "oliphaunt-broker",
-    "target": "macos-arm64",
-    "executableRelativePath": "bin/oliphaunt-broker"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./bin/oliphaunt-broker"
-    ]
-  },
-  "files": [
-    "bin",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_LICENSES"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/broker/packages/linux-arm64-gnu/package.json b/src/runtimes/broker/packages/linux-arm64-gnu/package.json
deleted file mode 100644
index cfbd1194b..000000000
--- a/src/runtimes/broker/packages/linux-arm64-gnu/package.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-  "name": "@oliphaunt/broker-linux-arm64-gnu",
-  "version": "0.2.0",
-  "description": "Linux arm64 glibc oliphaunt-broker helper binary.",
-  "license": "MIT AND ISC AND Unicode-3.0",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/broker/packages/linux-arm64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "brokerHelper": "oliphaunt-broker",
-    "target": "linux-arm64-gnu",
-    "executableRelativePath": "bin/oliphaunt-broker"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./bin/oliphaunt-broker"
-    ]
-  },
-  "files": [
-    "bin",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_LICENSES"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/broker/packages/linux-x64-gnu/package.json b/src/runtimes/broker/packages/linux-x64-gnu/package.json
deleted file mode 100644
index 6aee4a2dc..000000000
--- a/src/runtimes/broker/packages/linux-x64-gnu/package.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-  "name": "@oliphaunt/broker-linux-x64-gnu",
-  "version": "0.2.0",
-  "description": "Linux x64 glibc oliphaunt-broker helper binary.",
-  "license": "MIT AND ISC AND Unicode-3.0",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/broker/packages/linux-x64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "brokerHelper": "oliphaunt-broker",
-    "target": "linux-x64-gnu",
-    "executableRelativePath": "bin/oliphaunt-broker"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./bin/oliphaunt-broker"
-    ]
-  },
-  "files": [
-    "bin",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_LICENSES"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/broker/packages/win32-x64-msvc/package.json b/src/runtimes/broker/packages/win32-x64-msvc/package.json
deleted file mode 100644
index 1e5b26eb6..000000000
--- a/src/runtimes/broker/packages/win32-x64-msvc/package.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "name": "@oliphaunt/broker-win32-x64-msvc",
-  "version": "0.2.0",
-  "description": "Windows x64 MSVC oliphaunt-broker helper binary.",
-  "license": "MIT AND ISC AND Unicode-3.0",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/broker/packages/win32-x64-msvc"
-  },
-  "os": [
-    "win32"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "brokerHelper": "oliphaunt-broker",
-    "target": "windows-x64-msvc",
-    "executableRelativePath": "bin/oliphaunt-broker.exe"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./bin/oliphaunt-broker.exe"
-    ]
-  },
-  "files": [
-    "bin",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_LICENSES"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/broker/release.toml b/src/runtimes/broker/release.toml
deleted file mode 100644
index f3e857f36..000000000
--- a/src/runtimes/broker/release.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-id = "oliphaunt-broker"
-owner = "@oliphaunt/broker"
-kind = "runtime"
-publish_targets = ["github-release-assets", "npm", "crates-io"]
-registry_packages = [
-  "crates:oliphaunt-broker-linux-arm64-gnu",
-  "crates:oliphaunt-broker-linux-x64-gnu",
-  "crates:oliphaunt-broker-macos-arm64",
-  "crates:oliphaunt-broker-windows-x64-msvc",
-  "npm:@oliphaunt/broker-darwin-arm64",
-  "npm:@oliphaunt/broker-linux-x64-gnu",
-  "npm:@oliphaunt/broker-linux-arm64-gnu",
-  "npm:@oliphaunt/broker-win32-x64-msvc",
-]
-release_artifacts = ["broker-helper-binary"]
diff --git a/src/runtimes/broker/src/main.rs b/src/runtimes/broker/src/main.rs
deleted file mode 100644
index a954b38f0..000000000
--- a/src/runtimes/broker/src/main.rs
+++ /dev/null
@@ -1,480 +0,0 @@
-use std::env;
-use std::error::Error as StdError;
-use std::ffi::OsString;
-use std::fmt;
-use std::io::{self, Read, Write};
-use std::net::TcpListener;
-#[cfg(unix)]
-use std::os::unix::net::UnixListener;
-use std::process;
-use std::thread;
-
-use oliphaunt::{__private as broker_support, Extension};
-
-const ENV_BROKER_AUTH_TOKEN: &str = "OLIPHAUNT_BROKER_AUTH_TOKEN";
-const DEFAULT_USERNAME: &str = "postgres";
-const DEFAULT_DATABASE: &str = "postgres";
-
-type BrokerResult = std::result::Result;
-
-#[derive(Debug)]
-enum BrokerError {
-    Configuration(String),
-    Runtime(String),
-    Oliphaunt(oliphaunt::Error),
-}
-
-impl BrokerError {
-    fn configuration(message: impl Into) -> Self {
-        Self::Configuration(message.into())
-    }
-
-    fn runtime(message: impl Into) -> Self {
-        Self::Runtime(message.into())
-    }
-}
-
-impl fmt::Display for BrokerError {
-    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Configuration(message) | Self::Runtime(message) => formatter.write_str(message),
-            Self::Oliphaunt(error) => error.fmt(formatter),
-        }
-    }
-}
-
-impl StdError for BrokerError {
-    fn source(&self) -> Option<&(dyn StdError + 'static)> {
-        match self {
-            Self::Oliphaunt(error) => Some(error),
-            Self::Configuration(_) | Self::Runtime(_) => None,
-        }
-    }
-}
-
-impl From for BrokerError {
-    fn from(error: oliphaunt::Error) -> Self {
-        Self::Oliphaunt(error)
-    }
-}
-
-fn main() {
-    if let Err(error) = run() {
-        println!("OLIPHAUNT_BROKER_ERROR {error}");
-        process::exit(2);
-    }
-}
-
-fn run() -> BrokerResult<()> {
-    let args: Vec = env::args_os().skip(1).collect();
-    let args = BrokerArgs::parse(args)?;
-    let mut session = broker_support::open(
-        args.root,
-        args.startup_gucs,
-        Some(args.username),
-        Some(args.database),
-        args.extensions,
-    )?;
-    let cancel = session.cancel_handle()?;
-    let listener = BrokerListener::bind(args.endpoint)?;
-    let cancel_listener = BrokerListener::bind(args.cancel_endpoint)?;
-    let cancel_ready_endpoint = cancel_listener.ready_endpoint();
-    start_cancel_listener(cancel_listener, cancel, args.auth_token.clone());
-    println!(
-        "OLIPHAUNT_BROKER_READY {} cancel={}",
-        listener.ready_endpoint(),
-        cancel_ready_endpoint
-    );
-    io::stdout()
-        .flush()
-        .map_err(|err| BrokerError::runtime(format!("flush broker ready line: {err}")))?;
-
-    let mut stream = listener.accept()?;
-    authenticate_client(&mut stream, &args.auth_token)?;
-    loop {
-        let request = broker_support::broker_ipc_read_request(&mut stream)?;
-        match request {
-            broker_support::BrokerIpcRequest::Authenticate(_) => {
-                broker_support::broker_ipc_write_error(
-                    &mut stream,
-                    "broker client is already authenticated".to_owned(),
-                )?;
-                break;
-            }
-            broker_support::BrokerIpcRequest::ExecProtocol(bytes) => {
-                write_broker_response(&mut stream, session.exec_protocol_raw(bytes))?;
-            }
-            broker_support::BrokerIpcRequest::ExecProtocolStream(bytes) => {
-                let result = session.exec_protocol_raw_stream(bytes, &mut |chunk| {
-                    broker_support::broker_ipc_write_chunk(&mut stream, chunk)
-                });
-                match result {
-                    broker_support::BrokerStreamOutcome::ReadyForQuery(Ok(())) => {
-                        broker_support::broker_ipc_write_ok(&mut stream, Vec::new())?
-                    }
-                    broker_support::BrokerStreamOutcome::ReadyForQuery(Err(error)) => {
-                        broker_support::broker_ipc_write_stream_callback_aborted(
-                            &mut stream,
-                            error.to_string(),
-                        )?
-                    }
-                    broker_support::BrokerStreamOutcome::SessionStateUnknown(error) => {
-                        broker_support::broker_ipc_write_error(&mut stream, error.to_string())?
-                    }
-                }
-            }
-            broker_support::BrokerIpcRequest::ExecSimpleQuery(sql) => {
-                write_broker_response(&mut stream, session.execute(&sql))?;
-            }
-            broker_support::BrokerIpcRequest::Backup => {
-                write_broker_response(&mut stream, session.backup())?;
-            }
-            broker_support::BrokerIpcRequest::Cancel => {
-                broker_support::broker_ipc_write_error(
-                    &mut stream,
-                    "broker cancellation must use the cancel endpoint".to_owned(),
-                )?;
-            }
-            broker_support::BrokerIpcRequest::Close => {
-                let result = session.close().map(|()| Vec::new());
-                write_broker_response(&mut stream, result)?;
-                break;
-            }
-        }
-    }
-    Ok(())
-}
-
-fn start_cancel_listener(
-    listener: BrokerListener,
-    cancel: broker_support::BrokerCancel,
-    expected_token: String,
-) {
-    thread::Builder::new()
-        .name("oliphaunt-broker-cancel".to_owned())
-        .spawn(move || {
-            loop {
-                match listener.accept() {
-                    Ok(mut stream) => {
-                        if let Err(error) =
-                            handle_cancel_client(&mut stream, &cancel, &expected_token)
-                        {
-                            eprintln!("OLIPHAUNT_BROKER_CANCEL_ERROR {error}");
-                        }
-                    }
-                    Err(error) => {
-                        eprintln!("OLIPHAUNT_BROKER_CANCEL_ERROR {error}");
-                        break;
-                    }
-                }
-            }
-        })
-        .expect("spawn native broker cancel listener");
-}
-
-fn handle_cancel_client(
-    stream: &mut Box,
-    cancel: &broker_support::BrokerCancel,
-    expected_token: &str,
-) -> BrokerResult<()> {
-    authenticate_client(stream, expected_token)?;
-    match broker_support::broker_ipc_read_request(stream)? {
-        broker_support::BrokerIpcRequest::Cancel => {
-            write_broker_response(stream, cancel.cancel().map(|()| Vec::new()))?
-        }
-        broker_support::BrokerIpcRequest::Authenticate(_) => {
-            broker_support::broker_ipc_write_error(
-                stream,
-                "broker cancel client is already authenticated".to_owned(),
-            )?
-        }
-        _ => broker_support::broker_ipc_write_error(
-            stream,
-            "broker cancel endpoint only accepts cancellation requests".to_owned(),
-        )?,
-    }
-    Ok(())
-}
-
-fn authenticate_client(
-    stream: &mut Box,
-    expected_token: &str,
-) -> BrokerResult<()> {
-    match broker_support::broker_ipc_read_request(stream)? {
-        broker_support::BrokerIpcRequest::Authenticate(token) if token == expected_token => {
-            broker_support::broker_ipc_write_ok(stream, Vec::new())?;
-            Ok(())
-        }
-        broker_support::BrokerIpcRequest::Authenticate(_) => {
-            broker_support::broker_ipc_write_error(
-                stream,
-                "invalid broker authentication token".to_owned(),
-            )?;
-            Err(BrokerError::runtime("invalid broker authentication token"))
-        }
-        _ => {
-            broker_support::broker_ipc_write_error(
-                stream,
-                "broker client must authenticate before sending requests".to_owned(),
-            )?;
-            Err(BrokerError::runtime("broker client did not authenticate"))
-        }
-    }
-}
-
-fn write_broker_response(
-    stream: &mut impl Write,
-    result: oliphaunt::Result>,
-) -> BrokerResult<()> {
-    match result {
-        Ok(bytes) => broker_support::broker_ipc_write_ok(stream, bytes)?,
-        Err(error) => broker_support::broker_ipc_write_error(stream, error.to_string())?,
-    }
-    Ok(())
-}
-
-struct BrokerArgs {
-    root: std::path::PathBuf,
-    endpoint: BrokerListenEndpoint,
-    cancel_endpoint: BrokerListenEndpoint,
-    startup_gucs: Vec<(String, String)>,
-    username: String,
-    database: String,
-    extensions: Vec,
-    auth_token: String,
-}
-
-impl BrokerArgs {
-    fn parse(args: Vec) -> BrokerResult {
-        let auth_token = env::var(ENV_BROKER_AUTH_TOKEN).map_err(|_| {
-            BrokerError::configuration(format!("{ENV_BROKER_AUTH_TOKEN} is required"))
-        })?;
-        Self::parse_with_auth_token(args, auth_token)
-    }
-
-    fn parse_with_auth_token(args: Vec, auth_token: String) -> BrokerResult {
-        let mut root = None;
-        let mut endpoint = BrokerListenEndpoint::Tcp("127.0.0.1:0".to_owned());
-        let mut cancel_endpoint = BrokerListenEndpoint::Tcp("127.0.0.1:0".to_owned());
-        let mut startup_gucs = Vec::new();
-        let mut username = DEFAULT_USERNAME.to_owned();
-        let mut database = DEFAULT_DATABASE.to_owned();
-        let mut extensions = Vec::new();
-        let mut iter = args.into_iter();
-        while let Some(arg) = iter.next() {
-            let arg = arg.into_string().map_err(|_| {
-                BrokerError::configuration("broker argument names must be valid UTF-8")
-            })?;
-            match arg.as_str() {
-                "--root" => {
-                    root = Some(next_broker_arg(&mut iter, "--root", "a filesystem path")?.into())
-                }
-                "--listen" => {
-                    let listen = next_utf8_broker_arg(&mut iter, "--listen", "an address")?;
-                    endpoint = BrokerListenEndpoint::Tcp(listen);
-                }
-                "--cancel-listen" => {
-                    let listen = next_utf8_broker_arg(&mut iter, "--cancel-listen", "an address")?;
-                    cancel_endpoint = BrokerListenEndpoint::Tcp(listen);
-                }
-                "--socket" => {
-                    let socket = next_broker_arg(&mut iter, "--socket", "a filesystem path")?;
-                    endpoint = BrokerListenEndpoint::unix(socket)?;
-                }
-                "--cancel-socket" => {
-                    let socket =
-                        next_broker_arg(&mut iter, "--cancel-socket", "a filesystem path")?;
-                    cancel_endpoint = BrokerListenEndpoint::unix(socket)?;
-                }
-                "--startup-guc" => {
-                    let assignment =
-                        next_utf8_broker_arg(&mut iter, "--startup-guc", "name=value")?;
-                    startup_gucs.push(parse_startup_guc(&assignment)?);
-                }
-                "--username" => {
-                    username = next_utf8_broker_arg(&mut iter, "--username", "a PostgreSQL role")?;
-                }
-                "--database" => {
-                    database = next_utf8_broker_arg(
-                        &mut iter,
-                        "--database",
-                        "a PostgreSQL database name",
-                    )?;
-                }
-                "--extension" => {
-                    let sql_name =
-                        next_utf8_broker_arg(&mut iter, "--extension", "a SQL extension name")?;
-                    let extension = Extension::by_sql_name(&sql_name).ok_or_else(|| {
-                        BrokerError::configuration(format!(
-                            "unsupported native extension '{sql_name}'"
-                        ))
-                    })?;
-                    extensions.push(extension);
-                }
-                _ => {
-                    return Err(BrokerError::configuration(format!(
-                        "unknown broker argument '{arg}'"
-                    )));
-                }
-            }
-        }
-        if auth_token.is_empty() {
-            return Err(BrokerError::configuration(format!(
-                "{ENV_BROKER_AUTH_TOKEN} must not be empty"
-            )));
-        }
-
-        Ok(Self {
-            root: root.ok_or_else(|| BrokerError::configuration("--root is required"))?,
-            endpoint,
-            cancel_endpoint,
-            startup_gucs,
-            username,
-            database,
-            extensions,
-            auth_token,
-        })
-    }
-}
-
-fn next_broker_arg(
-    iter: &mut impl Iterator,
-    option: &str,
-    expected: &str,
-) -> BrokerResult {
-    iter.next()
-        .ok_or_else(|| BrokerError::configuration(format!("{option} requires {expected}")))
-}
-
-fn next_utf8_broker_arg(
-    iter: &mut impl Iterator,
-    option: &str,
-    expected: &str,
-) -> BrokerResult {
-    next_broker_arg(iter, option, expected)?
-        .into_string()
-        .map_err(|_| {
-            BrokerError::configuration(format!(
-                "{option} requires {expected} encoded as valid UTF-8"
-            ))
-        })
-}
-
-fn parse_startup_guc(value: &str) -> BrokerResult<(String, String)> {
-    let Some((name, guc_value)) = value.split_once('=') else {
-        return Err(BrokerError::configuration(
-            "--startup-guc requires name=value",
-        ));
-    };
-    Ok((name.to_owned(), guc_value.to_owned()))
-}
-
-enum BrokerListenEndpoint {
-    Tcp(String),
-    #[cfg(unix)]
-    Unix(std::path::PathBuf),
-}
-
-impl BrokerListenEndpoint {
-    #[cfg(unix)]
-    fn unix(path: impl Into) -> BrokerResult {
-        Ok(Self::Unix(path.into()))
-    }
-
-    #[cfg(not(unix))]
-    fn unix(_path: impl Into) -> BrokerResult {
-        Err(BrokerError::configuration(
-            "Unix-domain broker sockets are not supported on this platform",
-        ))
-    }
-}
-
-trait BrokerTransport: Read + Write {}
-
-impl BrokerTransport for T where T: Read + Write {}
-
-enum BrokerListener {
-    Tcp(TcpListener),
-    #[cfg(unix)]
-    Unix {
-        listener: UnixListener,
-        path: std::path::PathBuf,
-    },
-}
-
-impl BrokerListener {
-    fn bind(endpoint: BrokerListenEndpoint) -> BrokerResult {
-        match endpoint {
-            BrokerListenEndpoint::Tcp(listen) => {
-                TcpListener::bind(&listen).map(Self::Tcp).map_err(|err| {
-                    BrokerError::runtime(format!("bind broker TCP listener {listen}: {err}"))
-                })
-            }
-            #[cfg(unix)]
-            BrokerListenEndpoint::Unix(path) => {
-                if path.exists() {
-                    std::fs::remove_file(&path).map_err(|err| {
-                        BrokerError::runtime(format!(
-                            "remove stale broker socket {}: {err}",
-                            path.display()
-                        ))
-                    })?;
-                }
-                UnixListener::bind(&path)
-                    .map(|listener| Self::Unix { listener, path })
-                    .map_err(|err| BrokerError::runtime(format!("bind broker Unix socket: {err}")))
-            }
-        }
-    }
-
-    fn ready_endpoint(&self) -> String {
-        match self {
-            Self::Tcp(listener) => listener
-                .local_addr()
-                .map(|addr| format!("tcp:{addr}"))
-                .unwrap_or_else(|_| "tcp:".to_owned()),
-            #[cfg(unix)]
-            Self::Unix { path, .. } => format!("unix:{}", path.display()),
-        }
-    }
-
-    fn accept(&self) -> BrokerResult> {
-        match self {
-            Self::Tcp(listener) => listener
-                .accept()
-                .map(|(stream, _)| Box::new(stream) as Box)
-                .map_err(|err| BrokerError::runtime(format!("accept broker TCP client: {err}"))),
-            #[cfg(unix)]
-            Self::Unix { listener, path } => listener
-                .accept()
-                .map(|(stream, _)| Box::new(stream) as Box)
-                .map_err(|err| {
-                    BrokerError::runtime(format!(
-                        "accept broker Unix client on {}: {err}",
-                        path.display()
-                    ))
-                }),
-        }
-    }
-}
-
-#[cfg(all(test, unix))]
-mod tests {
-    use std::os::unix::ffi::OsStringExt;
-    use std::path::PathBuf;
-
-    use super::*;
-
-    #[test]
-    fn broker_arguments_preserve_non_utf8_database_roots() {
-        let root = PathBuf::from(OsString::from_vec(
-            b"/tmp/oliphaunt-broker-root-\xff".to_vec(),
-        ));
-        let args = vec![OsString::from("--root"), root.clone().into_os_string()];
-
-        let parsed = BrokerArgs::parse_with_auth_token(args, "test-token".to_owned())
-            .expect("non-UTF-8 filesystem paths remain valid broker roots");
-
-        assert_eq!(parsed.root, root);
-    }
-}
diff --git a/src/runtimes/liboliphaunt-native/CHANGELOG.md b/src/runtimes/liboliphaunt-native/CHANGELOG.md
new file mode 100644
index 000000000..8f3725736
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/CHANGELOG.md
@@ -0,0 +1,38 @@
+# Changelog
+
+## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-native-v0.1.1...liboliphaunt-native-v0.2.0) (2026-09-05)
+
+
+### ⚠ BREAKING CHANGES
+
+* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
+
+### Features
+
+* **contrib:** shared contrib carrier source: simplify releases and make contrib runtime-owned (#127) (c45082dc)
+* **contrib:** shared contrib carrier source: unify native and WASIX runtimes and SDKs (#129) (fae2bd7b)
+* **contrib:** shared contrib carrier source: model independent product dependencies (#173) (2d5f90c8)
+* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))
+* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
+
+
+### Code Refactoring
+
+* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
+* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
+
+## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-native-v0.1.0...liboliphaunt-native-v0.1.1) (2026-08-08)
+
+
+### Bug Fixes
+
+* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))
+
+## 0.1.0 (2026-07-28)
+
+
+### Features
+
+* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/runtimes/liboliphaunt-native/README.md b/src/runtimes/liboliphaunt-native/README.md
new file mode 100644
index 000000000..d87a2d5be
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/README.md
@@ -0,0 +1,189 @@
+# liboliphaunt
+
+`liboliphaunt` is the native C boundary for embedded PostgreSQL. It owns the
+PostgreSQL 18 source pin, upstreamable patch stack, C ABI header, native shim,
+and local smoke/build scripts.
+
+This directory is intentionally not an app SDK. Rust, Swift, Kotlin, desktop
+TypeScript, and React Native bind to this C ABI instead of reaching into
+PostgreSQL internals.
+
+## Layout
+
+- `include/oliphaunt.h`: public C ABI.
+- `src/liboliphaunt_native.c`: direct-mode lifecycle, backend thread ownership,
+  and non-query public ABI entrypoints.
+- `src/liboliphaunt_error.c`: synchronized shared errors plus nested,
+  operation-local error attribution for binding-safe copies.
+- `src/liboliphaunt_runtime.c`: embedded backend argv/default-GUC construction
+  and backend thread stack sizing policy.
+- `src/liboliphaunt_protocol.c`: raw protocol execution, streaming backpressure,
+  readiness scanning, and embedded backend read/write callbacks.
+- `src/liboliphaunt_config.c`: configuration copying, PostgreSQL executable
+  resolution, and startup argument copying.
+- `src/liboliphaunt_process.c`: process-wide direct-mode instance guard and
+  desktop dynamic-extension symbol-scope promotion.
+- `src/liboliphaunt_static_extensions.c`: process-wide static extension registry
+  used by mobile-style builds that link extension modules into the app binary.
+- `src/liboliphaunt_trace.c`: low-overhead protocol timing counters.
+- `src/liboliphaunt_backup_state.c`: physical-backup phase validation and
+  one-attempt failure cleanup.
+- `src/liboliphaunt_archive.c`: backup/restore lifecycle over the C ABI.
+- `src/liboliphaunt_archive_tar.c`: private ustar read/write implementation for
+  same-version physical archives.
+- `src/liboliphaunt_fs.c`: private filesystem/path helpers shared by archive and
+  restore code.
+- `src/liboliphaunt_internal.h`: private helpers shared between C translation
+  units; not part of the public ABI.
+- `patches/postgresql-18.4/`: minimal PostgreSQL patch stack.
+- `postgres/series`: ordered native patch recipe, including shared patches from `src/third-party/postgres/patches/`.
+- `src/third-party/postgres/source.toml`: shared pinned PostgreSQL source manifest.
+- `bin/build-postgres18-macos.sh`: macOS build harness.
+- `tools/run-host-c-smoke.sh --abi-only`: consumer-style C ABI check that
+  includes only `oliphaunt.h`, links the public dylib, and verifies stable
+  constants, structs, exported symbols, and safe global calls.
+- `bin/smoke-host-happy-path.sh`: host C ABI smoke harness for macOS, Linux,
+  and Windows.
+
+## Build
+
+```sh
+src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh
+```
+
+The default output root is `target/liboliphaunt-pg18`. Use `OLIPHAUNT_*` for runtime and build controls. `LIBOLIPHAUNT_PATH` is reserved
+for the literal C library artifact path.
+
+The direct build produces PostgreSQL runtime artifacts without optional
+extension artifacts by default. Set `OLIPHAUNT_BUILD_EXTENSIONS=1` only when
+refreshing or validating exact extension artifacts; the
+`extension-artifacts-native:build-target` sets that flag when building extension artifacts.
+
+Released extensions use the catalog and recipes under `extensions`.
+
+`OLIPHAUNT_STARTUP_TIMEOUT_MS` bounds only initial backend startup readiness.
+Normal `oliphaunt_exec_protocol`, `oliphaunt_exec_simple_query`, and streaming
+execution do not impose a synthetic query timeout; callers should use
+`oliphaunt_cancel` to interrupt long-running SQL. Ordinary SDK close is a
+lifecycle detach/wait boundary, not an implicit query cancellation primitive.
+
+Hosts serialize ordinary non-cancel calls on one logical C handle;
+`oliphaunt_cancel` is the cross-thread exception. Streaming callbacks borrow
+each byte chunk only for the callback invocation. They may copy it, inspect an
+error, or cancel, but same-handle query, backup, detach, close, and nested stream
+calls fail busy until streaming drains to `ReadyForQuery`. This guard applies
+while the callback lock is released as well, preventing callback reentrancy or a
+concurrent close from corrupting protocol state or freeing the active handle.
+
+FFI schedulers that resume on a different thread use the ABI 10 `_with_error`
+variants with one caller-owned `OliphauntErrorCapture` per invocation. The
+worker fills that fixed-layout capture before its handle lease ends; synchronous
+callers may continue copying the operation-local error immediately with
+`oliphaunt_copy_last_error`.
+
+The C runtime keeps throughput-oriented PostgreSQL defaults for direct callers:
+`shared_buffers=128MB`, `wal_buffers=4MB`, and `min_wal_size=80MB`. SDKs that
+need different PostgreSQL settings do not need a new C ABI; they pass validated
+`-c name=value` startup arguments through `OliphauntConfig.startup_args`. Later
+arguments win, so SDKs and benchmark harnesses can apply concrete PostgreSQL
+GUC overrides above the stable C boundary without inventing tuning profiles.
+
+SDKs must hydrate PGDATA from a packaged cluster seed before calling
+`oliphaunt_init`; the C boundary never runs `initdb` or initializes an empty
+root. `tools/run-host-c-smoke.sh` performs that preparation explicitly before
+running the C consumer and includes a fast iOS simulator syntax
+check over the liboliphaunt C shim files. `bin/check-postgres18-ios-simulator.sh`
+then validates the upstream PostgreSQL patch touchpoints that matter for the
+embedded path: host I/O callbacks, the embedded backend entrypoint, lifecycle
+cleanup, static extension lookup, and shell-command exclusion on Apple mobile
+SDKs.
+`bin/build-postgres18-ios-simulator.sh` is the fast simulator artifact lane for
+Expo/RN and Swift validation. `bin/build-postgres18-ios-device.sh` builds the
+matching `IOS` device slice, and `bin/build-ios-xcframework.sh` packages both
+validated dylibs with public headers as
+`target/liboliphaunt-ios-xcframework/out/liboliphaunt.xcframework`. Each lane
+cross-builds the patched PostgreSQL backend object graph, tolerates the final
+PostgreSQL executable/tool link failure after the embedded objects exist,
+links target-specific static ICU code for PostgreSQL collation support, stages
+ICU data into the optional ICU package sidecar instead of the base runtime
+install, validates the exported C ABI symbols, and reuses the result through
+stamped ccache-friendly paths.
+
+## Static Extension Registry
+
+Mobile-style packages cannot rely on PostgreSQL dynamically loading every
+extension module from the app bundle. `oliphaunt_register_static_extensions`
+registers statically linked modules before `oliphaunt_init`, and the PostgreSQL
+`dfmgr` patch resolves those entries through the same normal `CREATE
+EXTENSION`/`LOAD` path that dynamic modules use. The registry is process-wide,
+validates extension names, magic functions, symbol names, duplicate symbols,
+and ABI versions, and becomes immutable at backend startup.
+
+The runtime-resource `--mobile-static-module ` flag is only release
+metadata. It must match modules that the platform package actually links and
+registers through this C ABI before opening the database.
+
+The macOS arm64, iOS simulator, iOS device, and Android build lanes also emit
+per-extension static archives beside the generated object lists:
+`out/extensions//liboliphaunt_extension_.a`. Those archives are the
+release artifact boundary for exact mobile extension selection; SDK packaging
+can link only the archives for the extensions an app requested instead of
+shipping one bundled extension set or rebuilding extension source in the app.
+`bin/build-ios-extension-xcframeworks.sh` packages selected macOS arm64, iOS
+simulator arm64, and iOS device arm64 archives into per-extension and
+per-dependency XCFrameworks for Apple SDK and Xcode consumers without rebuilding
+extension sources. Packaging rejects any such XCFramework that lacks one of
+those three claimed slices.
+
+## Root Ownership
+
+Direct init and restore each take one non-blocking sibling lease for the target
+root by default. The Rust SDK acquires the byte-identical sibling lease while
+preparing direct, broker, and server roots, then passes
+`OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK` for direct init so the C runtime does not
+try to acquire the same lease twice. Other C ABI consumers leave the flag clear
+and rely on the C runtime. The flag is only an ownership handoff; callers must
+already hold the stable lease for the full native handle lifetime.
+Detached reopens of a resident runtime must repeat the same root-lock ownership
+mode; changing the flag is rejected rather than silently changing who protects
+the live root.
+
+`oliphaunt_init` only validates an existing managed root. It requires the exact
+five-field `/.oliphaunt.json`, a real `/pgdata` directory,
+PostgreSQL 18 `PG_VERSION`, nonempty `global/pg_control`, and a real `pg_wal`
+directory. Exact native and WASIX descriptor tuples are accepted; unknown,
+missing, duplicated, or mismatched fields and other PGDATA leaf names are
+rejected without changing the root. SDK initialization creates PGDATA first and
+publishes the descriptor last.
+
+## Physical Archive Contract
+
+`oliphaunt_backup` emits one PostgreSQL 18 physical archive format with no
+format switch or generated-file hook. Every archive contains the exact
+five-key `.oliphaunt/backup-manifest.properties`; restore requires and consumes
+that manifest. The destination-owned `.oliphaunt.json` is not archive content,
+and restore publishes only to a new or existing-empty destination. The C ABI
+accepts only regular
+files and directories under `pgdata`; symlinks, hardlinks, device nodes, FIFOs,
+sockets, sparse/special tar records, external tablespaces, and linked WAL
+directories are rejected. `oliphaunt_restore` enforces the same rule before
+consuming archive metadata and publishing a restored root, so Swift, Kotlin,
+React Native, and Rust SDK callers inherit one portable archive contract instead
+of platform-specific tar behavior.
+
+## Fast Native Iteration
+
+Run the narrow product boundary instead of a workspace-wide track wrapper:
+
+```sh
+moon run liboliphaunt-native:host-smoke
+moon run oliphaunt-rust:test-integration
+moon run extension-artifacts-native:build-target oliphaunt-rust:test-extensions
+```
+
+`liboliphaunt-native:host-smoke` is the no-build host C ABI smoke for the current platform.
+It reuses the release-runtime artifact produced for macOS, Linux, or Windows
+and fails if that artifact is missing or stale. The Rust regression checks direct,
+broker, and server behavior; the separate extension pair checks packaged extension behavior.
+See [`src/docs/maintainers/sdk-parity-policy.md`](../../docs/maintainers/sdk-parity-policy.md)
+for the SDK ownership contract.
diff --git a/src/runtimes/liboliphaunt-native/THIRD_PARTY_NOTICES.md b/src/runtimes/liboliphaunt-native/THIRD_PARTY_NOTICES.md
new file mode 100644
index 000000000..4db1a8144
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/THIRD_PARTY_NOTICES.md
@@ -0,0 +1,23 @@
+# liboliphaunt Third-Party Notices
+
+`liboliphaunt` ships native embedded PostgreSQL runtime artifacts, selected SQL
+extensions, and supporting runtime resources.
+
+The PostgreSQL runtime is derived from PostgreSQL 18 source pinned under
+`src/third-party/postgres/` and built with the native patch stack owned by
+`src/runtimes/liboliphaunt-native/`. Selected runtime and extension carriers
+also embed ICU 76.1 and OpenSSL 3.5.6.
+
+Every carrier that embeds these components includes their exact pinned license
+bytes under `THIRD_PARTY_LICENSES/`:
+
+- `PostgreSQL-COPYRIGHT` — PostgreSQL 18.4, source SHA-256
+  `81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094`.
+- `ICU-LICENSE` — ICU commit `8eca245c7484ac6cc179e3e5f7c1ea7680810f39`.
+- `OpenSSL-LICENSE.txt` — OpenSSL commit
+  `286ddeaac037533bbdce65b3c689e3f7ffebf0f6`.
+
+Third-party source pins for optional external extensions and supporting native
+libraries are maintained in `src/third-party/`. Exact SQL extension selection is
+modeled in `extensions/`; release artifacts must include only the extension
+artifacts explicitly selected by the application developer.
diff --git a/src/runtimes/liboliphaunt/native/VERSION b/src/runtimes/liboliphaunt-native/VERSION
similarity index 100%
rename from src/runtimes/liboliphaunt/native/VERSION
rename to src/runtimes/liboliphaunt-native/VERSION
diff --git a/src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh b/src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.sh
similarity index 98%
rename from src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh
rename to src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.sh
index b8f29cade..8136b027a 100755
--- a/src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh
+++ b/src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.sh
@@ -11,27 +11,27 @@ device_out="${OLIPHAUNT_IOS_DEVICE_OUT:-$repo_root/target/liboliphaunt-ios-devic
 macos_out="${OLIPHAUNT_MACOS_EXTENSION_OUT:-$repo_root/target/liboliphaunt-pg18/macos-extension-archives/out}"
 work_root="${OLIPHAUNT_IOS_EXTENSION_XCFRAMEWORK_ROOT:-$repo_root/target/liboliphaunt-ios-extension-xcframeworks}"
 out_dir="$work_root/out"
-headers_dir="$repo_root/src/runtimes/liboliphaunt/native/include"
+headers_dir="$repo_root/src/runtimes/liboliphaunt-native/include"
 runtime_resources_dir="${OLIPHAUNT_IOS_RUNTIME_RESOURCES_DIR:-${OLIPHAUNT_RUNTIME_RESOURCES_DIR:-}}"
 manifest_file="$out_dir/manifest.properties"
 
 usage() {
   cat >&2 <]
+usage: src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.sh [--check-current] [--runtime-resources ]
 
 Packages selected prebuilt Apple extension archives into per-extension
 XCFrameworks with macOS arm64, iOS device arm64, and iOS simulator arm64
 slices. Prefer passing the Rust runtime-resource output so the selected
 native modules are derived from runtime/manifest.properties:
 
-  src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh \\
+  src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.sh \\
     --runtime-resources target/oliphaunt-resources
 
 For release automation, OLIPHAUNT_MOBILE_STATIC_EXTENSIONS may still provide a
 comma-separated exact extension or module-stem list:
 
   OLIPHAUNT_MOBILE_STATIC_EXTENSIONS=vector,pg_trgm \\
-    src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh
+    src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.sh
 
 Inputs:
   OLIPHAUNT_IOS_SIMULATOR_OUT   default target/liboliphaunt-ios-simulator/out
diff --git a/src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.test.sh b/src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.test.sh
similarity index 97%
rename from src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.test.sh
rename to src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.test.sh
index 347d11642..92871c6d3 100755
--- a/src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.test.sh
+++ b/src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.test.sh
@@ -5,7 +5,7 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
   echo "must run inside the Oliphaunt git checkout" >&2
   exit 1
 }
-builder="$root/src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh"
+builder="$root/src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.sh"
 test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-ios-extension-packager-test.XXXXXX")"
 trap 'rm -rf "$test_root"' EXIT HUP INT TERM
 
diff --git a/src/runtimes/liboliphaunt/native/bin/build-ios-xcframework.sh b/src/runtimes/liboliphaunt-native/bin/build-ios-xcframework.sh
similarity index 92%
rename from src/runtimes/liboliphaunt/native/bin/build-ios-xcframework.sh
rename to src/runtimes/liboliphaunt-native/bin/build-ios-xcframework.sh
index 9c3afa390..aa793ea9c 100755
--- a/src/runtimes/liboliphaunt/native/bin/build-ios-xcframework.sh
+++ b/src/runtimes/liboliphaunt-native/bin/build-ios-xcframework.sh
@@ -14,7 +14,7 @@ stamp="$work_root/.liboliphaunt-ios-xcframework.sha256"
 script_mode="${1:-build}"
 macos_runtime_resources_root="${OLIPHAUNT_MACOS_RUNTIME_RESOURCES_ROOT:-}"
 ios_runtime_resources_root="${OLIPHAUNT_IOS_RUNTIME_RESOURCES_ROOT:-}"
-runtime_version_file="$repo_root/src/runtimes/liboliphaunt/native/VERSION"
+runtime_version_file="$repo_root/src/runtimes/liboliphaunt-native/VERSION"
 macos_work_root="${OLIPHAUNT_WORK_ROOT:-$repo_root/target/liboliphaunt-pg18}"
 
 if [ "$(uname -s)" != "Darwin" ]; then
@@ -39,10 +39,10 @@ if ! oliphaunt_text_matches_ere "$runtime_version" '^(0|[1-9][0-9]*)[.](0|[1-9][
   exit 1
 fi
 
-simulator_script="$repo_root/src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh"
-device_script="$repo_root/src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-device.sh"
-macos_script="$repo_root/src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh"
-public_header="$repo_root/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
+simulator_script="$repo_root/src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-simulator.sh"
+device_script="$repo_root/src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-device.sh"
+macos_script="$repo_root/src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh"
+public_header="$repo_root/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
 default_macos_library="$macos_work_root/out/liboliphaunt.dylib"
 default_simulator_library="$repo_root/target/liboliphaunt-ios-simulator/out/liboliphaunt.dylib"
 default_device_library="$repo_root/target/liboliphaunt-ios-device/out/liboliphaunt.dylib"
@@ -56,7 +56,7 @@ device_framework="$framework_root/ios-arm64/liboliphaunt.framework"
 
 usage() {
   cat >&2 <<'MSG'
-usage: src/runtimes/liboliphaunt/native/bin/build-ios-xcframework.sh [--check-current]
+usage: src/runtimes/liboliphaunt-native/bin/build-ios-xcframework.sh [--check-current]
 MSG
 }
 
@@ -128,6 +128,8 @@ assert_library_slice() {
     _oliphaunt_exec_protocol \
     _oliphaunt_exec_simple_query \
     _oliphaunt_exec_protocol_raw_stream \
+    _oliphaunt_protocol_stream_token \
+    _oliphaunt_feed_protocol_stream \
     _oliphaunt_backup \
     _oliphaunt_restore \
     _oliphaunt_init_with_error \
@@ -338,9 +340,13 @@ MODULEMAP
 
 build_xcframework() {
   mkdir -p "$out_dir" "$headers_dir"
-  rsync -a --delete "$repo_root/src/runtimes/liboliphaunt/native/include/" "$headers_dir/"
+  rsync -a --delete "$repo_root/src/runtimes/liboliphaunt-native/include/" "$headers_dir/"
 
+  mkdir -p "$work_root/logs"
   local macos_library="$default_macos_library"
+  local simulator_library="$default_simulator_library"
+  local device_library="$default_device_library"
+  macos_slice() {
   if ! "$macos_script" --check-oliphaunt-current >/dev/null 2>&1 ||
     ! assert_library_slice "$macos_library" MACOS >/dev/null 2>&1; then
     macos_library="$(oliphaunt_capture_build_artifact_path \
@@ -349,8 +355,9 @@ build_xcframework() {
       "$macos_script")"
   fi
 
-  local simulator_library="$default_simulator_library"
-  local device_library="$default_device_library"
+    printf '%s\n' "$macos_library" > "$work_root/logs/macos-artifact.path"
+  }
+  simulator_slice() {
   if ! OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="${OLIPHAUNT_MOBILE_STATIC_EXTENSIONS:-}" \
        "$simulator_script" --check-current >/dev/null 2>&1 ||
      ! assert_library_slice "$simulator_library" IOSSIMULATOR >/dev/null 2>&1; then
@@ -359,6 +366,9 @@ build_xcframework() {
       "$work_root/logs/build-ios-simulator.log" \
       env OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="${OLIPHAUNT_MOBILE_STATIC_EXTENSIONS:-}" "$simulator_script")"
   fi
+    printf '%s\n' "$simulator_library" > "$work_root/logs/simulator-artifact.path"
+  }
+  device_slice() {
   if ! OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="${OLIPHAUNT_MOBILE_STATIC_EXTENSIONS:-}" \
        "$device_script" --check-current >/dev/null 2>&1 ||
      ! assert_library_slice "$device_library" IOS >/dev/null 2>&1; then
@@ -367,6 +377,12 @@ build_xcframework() {
       "$work_root/logs/build-ios-device.log" \
       env OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="${OLIPHAUNT_MOBILE_STATIC_EXTENSIONS:-}" "$device_script")"
   fi
+    printf '%s\n' "$device_library" > "$work_root/logs/device-artifact.path"
+  }
+  oliphaunt_parallel_apple_builds macos_slice simulator_slice device_slice
+  macos_library="$(cat "$work_root/logs/macos-artifact.path")"
+  simulator_library="$(cat "$work_root/logs/simulator-artifact.path")"
+  device_library="$(cat "$work_root/logs/device-artifact.path")"
   assert_library_slice "$macos_library" MACOS
   assert_library_slice "$simulator_library" IOSSIMULATOR
   assert_library_slice "$device_library" IOS
diff --git a/src/runtimes/liboliphaunt/native/bin/build-macos-extension-archives.sh b/src/runtimes/liboliphaunt-native/bin/build-macos-extension-archives.sh
similarity index 99%
rename from src/runtimes/liboliphaunt/native/bin/build-macos-extension-archives.sh
rename to src/runtimes/liboliphaunt-native/bin/build-macos-extension-archives.sh
index 0289f06f3..1ad7f94a0 100755
--- a/src/runtimes/liboliphaunt/native/bin/build-macos-extension-archives.sh
+++ b/src/runtimes/liboliphaunt-native/bin/build-macos-extension-archives.sh
@@ -4,7 +4,7 @@ set -euo pipefail
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 script_path="$script_dir/$(basename "${BASH_SOURCE[0]}")"
 . "$script_dir/common.sh"
-. "$script_dir/icu.sh"
+. "$script_dir/../../../third-party/icu/tools/build.sh"
 . "$script_dir/mobile-static-extensions.sh"
 . "$script_dir/mobile-postgis-extensions.sh"
 repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
@@ -32,7 +32,7 @@ fail() {
 
 usage() {
   cat >&2 <<'MSG'
-usage: src/runtimes/liboliphaunt/native/bin/build-macos-extension-archives.sh [--check-current]
+usage: src/runtimes/liboliphaunt-native/bin/build-macos-extension-archives.sh [--check-current]
 
 Builds arm64 macOS static extension and dependency archives from the same
 canonical source inventory and symbol-prefix contract used by the iOS lanes.
@@ -235,7 +235,7 @@ build_openssl_dependency() {
 
 build_uuid_dependency() {
   mobile_static_dependency_selected uuid || return 0
-  local source_dir="$repo_root/src/runtimes/liboliphaunt/native/portable-uuid"
+  local source_dir="$repo_root/src/runtimes/liboliphaunt-native/portable-uuid"
   local dependency_dir="$mobile_static_dependency_root/uuid"
   local archive="$dependency_dir/lib/libuuid.a"
   local object="$dependency_dir/portable_uuid.o"
diff --git a/src/runtimes/liboliphaunt-native/bin/build-output.bash b/src/runtimes/liboliphaunt-native/bin/build-output.bash
new file mode 100644
index 000000000..eb2cdb5f5
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/bin/build-output.bash
@@ -0,0 +1,98 @@
+#!/usr/bin/env bash
+
+# Run the independent Apple slices within one CPU budget. Each lane owns a
+# process group; cancellation reaches build shells as well as their compilers.
+oliphaunt_parallel_apple_builds() (
+  set -euo pipefail
+  local jobs="${OLIPHAUNT_JOBS:-$(sysctl -n hw.ncpu 2>/dev/null || echo 4)}"
+  local command pid running status attempt alive
+  local pids=() remaining=()
+  case "$jobs" in ''|0*|*[!0-9]*) echo 'OLIPHAUNT_JOBS must be positive' >&2; return 2 ;; esac
+  [ "$#" -gt 0 ] || return 2
+  if [ "$jobs" -lt "$#" ]; then
+    for command in "$@"; do "$command"; done
+    return
+  fi
+  export OLIPHAUNT_JOBS="$((jobs / $#))"
+  stop_lanes() {
+    status="$?"
+    trap - EXIT HUP INT TERM
+    for pid in ${pids[@]+"${pids[@]}"}; do kill -TERM -- "-$pid" 2>/dev/null || true; done
+    for attempt in 1 2 3 4 5; do
+      alive=0
+      for pid in ${pids[@]+"${pids[@]}"}; do
+        if kill -0 -- "-$pid" 2>/dev/null; then alive=1; fi
+      done
+      [ "$alive" = 1 ] || break
+      sleep 1
+    done
+    for pid in ${pids[@]+"${pids[@]}"}; do
+      kill -KILL -- "-$pid" 2>/dev/null || true
+      wait "$pid" 2>/dev/null || true
+    done
+    exit "$status"
+  }
+  trap stop_lanes EXIT
+  trap 'exit 129' HUP
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
+  set -m
+  for command in "$@"; do
+    "$command" &
+    pids+=("$!")
+  done
+  set +m
+  while [ -n "${pids[*]-}" ]; do
+    running=" $(jobs -pr | tr '\n' ' ') "
+    remaining=()
+    for pid in "${pids[@]}"; do
+      case "$running" in
+        *" $pid "*) remaining+=("$pid") ;;
+        *) if wait "$pid"; then :; else return "$?"; fi ;;
+      esac
+    done
+    pids=(${remaining[@]+"${remaining[@]}"})
+    [ -z "${pids[*]-}" ] || sleep 1
+  done
+)
+
+oliphaunt_capture_build_artifact_path() {
+  local description="${1:?oliphaunt_capture_build_artifact_path requires a description}"
+  shift
+  local log_file="${1:?oliphaunt_capture_build_artifact_path requires a log file}"
+  shift
+  local log_dir tmp status artifact
+
+  log_dir="$(dirname "$log_file")"
+  mkdir -p "$log_dir"
+  tmp="$(mktemp "${TMPDIR:-/tmp}/oliphaunt-build-output.XXXXXX")"
+
+  set +e
+  "$@" 2>&1 | tee "$tmp" | tee "$log_file" >&2
+  status="${PIPESTATUS[0]}"
+  set -e
+
+  if [ "$status" -ne 0 ]; then
+    rm -f "$tmp"
+    echo "error: $description failed; see $log_file" >&2
+    return "$status"
+  fi
+
+  artifact=""
+  while IFS= read -r line; do
+    [ -n "$line" ] || continue
+    if [ -e "$line" ]; then
+      artifact="$line"
+    fi
+  done < "$tmp"
+  if [ -z "$artifact" ]; then
+    artifact="$(awk 'NF { line = $0 } END { if (line != "") print line }' "$tmp")"
+  fi
+  rm -f "$tmp"
+  if [ -z "$artifact" ]; then
+    echo "error: $description did not print an artifact path; see $log_file" >&2
+    return 1
+  fi
+
+  printf '%s\n' "$artifact"
+}
diff --git a/src/runtimes/liboliphaunt-native/bin/build-output.test.sh b/src/runtimes/liboliphaunt-native/bin/build-output.test.sh
new file mode 100644
index 000000000..01796eafa
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/bin/build-output.test.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+set -euo pipefail
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+. "$script_dir/build-output.bash"
+root="$(git -C "$script_dir" rev-parse --show-toplevel)"
+observer="$root/src/extensions/artifacts/native/tools/run-observed-phase.sh"
+
+if [ "${1:-}" = worker ]; then
+  work="$2"
+  mode="$3"
+  export OLIPHAUNT_JOBS=6
+  lane() {
+    [ "$OLIPHAUNT_JOBS" = 2 ]
+    touch "$work/$1"
+    for attempt in 1 2 3 4 5; do
+      if [ -f "$work/one" ] && [ -f "$work/two" ] && [ -f "$work/three" ]; then return; fi
+      sleep 1
+    done
+    return 9
+  }
+  one() { lane one; }
+  two() { lane two; }
+  three() { lane three; }
+  slow() {
+    "$observer" --label 'cancelled peer' --log "$work/slow.log" -- \
+      bash -c 'trap "" TERM; echo "$$" > "$1"; sleep 60' bash "$work/slow.pid"
+  }
+  fail_peer() {
+    for attempt in 1 2 3 4 5; do
+      [ ! -s "$work/slow.pid" ] || return 7
+      sleep 1
+    done
+    return 8
+  }
+  case "$mode" in
+    success) oliphaunt_parallel_apple_builds one two three ;;
+    failure) oliphaunt_parallel_apple_builds slow fail_peer ;;
+    cancellation) oliphaunt_parallel_apple_builds slow ;;
+  esac
+  exit
+fi
+
+work="$(mktemp -d)"
+trap 'rm -rf "$work"' EXIT
+bash "$0" worker "$work" success
+set +e
+bash "$0" worker "$work" failure >"$work/failure.log" 2>&1
+status="$?"
+set -e
+[ "$status" = 7 ]
+! kill -0 "$(cat "$work/slow.pid")" 2>/dev/null
+rm "$work/slow.pid"
+bash "$0" worker "$work" cancellation >"$work/cancellation.log" 2>&1 &
+worker="$!"
+for attempt in 1 2 3 4 5; do
+  [ ! -s "$work/slow.pid" ] || break
+  sleep 1
+done
+[ -s "$work/slow.pid" ]
+kill -TERM "$worker"
+set +e
+wait "$worker"
+status="$?"
+set -e
+[ "$status" = 143 ]
+! kill -0 "$(cat "$work/slow.pid")" 2>/dev/null
+echo 'parallel Apple build, failure, and cancellation checks passed'
diff --git a/src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh b/src/runtimes/liboliphaunt-native/bin/build-postgres18-android-arm64.sh
similarity index 94%
rename from src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh
rename to src/runtimes/liboliphaunt-native/bin/build-postgres18-android-arm64.sh
index 434a3a434..aaf665938 100755
--- a/src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh
+++ b/src/runtimes/liboliphaunt-native/bin/build-postgres18-android-arm64.sh
@@ -3,17 +3,18 @@ set -euo pipefail
 
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 . "$script_dir/common.sh"
-. "$script_dir/icu.sh"
+. "$script_dir/../../../third-party/icu/tools/build.sh"
 . "$script_dir/mobile-static-extensions.sh"
 . "$script_dir/mobile-postgis-extensions.sh"
 script_path="$script_dir/$(basename "$0")"
 repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
-. "$repo_root/src/postgres/versions/18/fetch-source.sh"
+. "$repo_root/src/third-party/postgres/fetch-source.sh"
 pg_version="18.4"
 pg_sha256="81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094"
 pg_url="https://ftp.postgresql.org/pub/source/v${pg_version}/postgresql-${pg_version}.tar.bz2"
-source_manifest="$repo_root/src/runtimes/liboliphaunt/native/postgres18/source.toml"
-patch_dir="$repo_root/src/runtimes/liboliphaunt/native/patches/postgresql-${pg_version}"
+source_manifest="$repo_root/src/third-party/postgres/source.toml"
+patch_dir="$repo_root"
+patch_series_file="$repo_root/src/runtimes/liboliphaunt-native/postgres/series"
 android_abi="${OLIPHAUNT_ANDROID_ABI:-arm64-v8a}"
 case "$android_abi" in
   arm64-v8a)
@@ -57,19 +58,19 @@ icu_cpp_libs="-lc++_static -lc++abi"
 icu_libs="$icu_static_libs $icu_cpp_libs"
 
 liboliphaunt_sources=(
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_native.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_error.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_runtime.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_protocol.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_config.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_trace.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_backup_state.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive_tar.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_static_extensions.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_builtin_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_native.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_error.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_runtime.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_protocol.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_config.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_trace.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_fs.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_backup_state.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive_tar.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_static_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_builtin_extensions.c"
 )
 
 plpgsql_objects=(
@@ -230,8 +231,7 @@ hash_mobile_static_extension_sources() {
 }
 
 patch_series() {
-  sed -n '/series = \[/,/\]/p' "$source_manifest" |
-    sed -n 's/.*"\([^"]*\.patch\)".*/\1/p'
+  sed '/^#/d; /^[[:space:]]*$/d' "$patch_series_file"
 }
 
 patch_series_hash() {
@@ -255,7 +255,7 @@ desired_hash() {
     printf 'ar=%s\n' "$llvm_ar"
     printf 'ranlib=%s\n' "$llvm_ranlib"
     printf 'icu_source=%s\n' "$(oliphaunt_icu_source_commit "$icu_source_dir")"
-    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256 "$script_dir")"
+    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256)"
     printf 'native_cflags=%s\n' "$native_cflags"
     printf 'liboliphaunt_cflags=%s\n' "$liboliphaunt_cflags"
     printf 'pg_extension_cflags=%s\n' "$pg_extension_cflags"
@@ -279,11 +279,7 @@ desired_hash() {
 }
 
 apply_patch_series() {
-  local patch_name
-  while IFS= read -r patch_name; do
-    [ -n "$patch_name" ] || continue
-    GIT_CEILING_DIRECTORIES="$work_root" git apply --whitespace=error-all "$patch_dir/$patch_name" >/dev/null
-  done < <(patch_series)
+  bash "$repo_root/src/third-party/postgres/apply-series.sh" "$build_dir" "$patch_series_file"
 }
 
 
@@ -310,6 +306,8 @@ artifact_ready() {
     oliphaunt_exec_protocol \
     oliphaunt_exec_simple_query \
     oliphaunt_exec_protocol_raw_stream \
+    oliphaunt_protocol_stream_token \
+    oliphaunt_feed_protocol_stream \
     oliphaunt_backup \
     oliphaunt_restore \
     oliphaunt_init_with_error \
@@ -476,7 +474,6 @@ configure_source() {
 build_icu() {
   oliphaunt_icu_build_target \
     "$icu_source_dir" \
-    "$script_dir" \
     "$icu_native_build_dir" \
     "$icu_build_dir" \
     "$icu_prefix" \
@@ -597,8 +594,8 @@ build_liboliphaunt_objects() {
     object="$out_dir/$(basename "${source%.c}").o"
     liboliphaunt_objects+=("$object")
     "${cc[@]}" $liboliphaunt_cflags \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/include" \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/src" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/include" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/src" \
       -c "$source" \
       -o "$object"
   done
@@ -655,7 +652,7 @@ build_openssl_dependency() {
 
 build_uuid_dependency() {
   mobile_static_dependency_selected uuid || return 0
-  local source_dir="$repo_root/src/runtimes/liboliphaunt/native/portable-uuid"
+  local source_dir="$repo_root/src/runtimes/liboliphaunt-native/portable-uuid"
   local dependency_dir="$mobile_static_dependency_root/uuid"
   local archive="$dependency_dir/lib/libuuid.a"
   local object="$dependency_dir/portable_uuid.o"
@@ -906,7 +903,7 @@ FOOTER
 build_mobile_static_registry_object() {
   [ "${#mobile_static_extensions[@]}" -gt 0 ] || return 0
   "${cc[@]}" $native_cflags \
-    -I"$repo_root/src/runtimes/liboliphaunt/native/include" \
+    -I"$repo_root/src/runtimes/liboliphaunt-native/include" \
     -c "$mobile_static_registry_source" \
     -o "$mobile_static_registry_object"
   mobile_static_objects+=("$mobile_static_registry_object")
@@ -955,7 +952,7 @@ link_liboliphaunt() {
 
 usage() {
   cat >&2 <<'MSG'
-usage: src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh [--check-current]
+usage: src/runtimes/liboliphaunt-native/bin/build-postgres18-android-arm64.sh [--check-current]
 
 Environment:
   OLIPHAUNT_ANDROID_ABI=arm64-v8a|x86_64
diff --git a/src/runtimes/liboliphaunt/native/bin/build-postgres18-android-x86_64.sh b/src/runtimes/liboliphaunt-native/bin/build-postgres18-android-x86_64.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/native/bin/build-postgres18-android-x86_64.sh
rename to src/runtimes/liboliphaunt-native/bin/build-postgres18-android-x86_64.sh
diff --git a/src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-device.sh b/src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-device.sh
similarity index 94%
rename from src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-device.sh
rename to src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-device.sh
index 854f54410..f351e1753 100755
--- a/src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-device.sh
+++ b/src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-device.sh
@@ -3,18 +3,19 @@ set -euo pipefail
 
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 . "$script_dir/common.sh"
-. "$script_dir/icu.sh"
+. "$script_dir/../../../third-party/icu/tools/build.sh"
 . "$script_dir/mobile-static-extensions.sh"
 . "$script_dir/mobile-postgis-extensions.sh"
 script_path="$script_dir/$(basename "$0")"
 repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
-. "$repo_root/src/postgres/versions/18/fetch-source.sh"
+. "$repo_root/src/third-party/postgres/fetch-source.sh"
 oliphaunt_mobile_target="ios-device"
 pg_version="18.4"
 pg_sha256="81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094"
 pg_url="https://ftp.postgresql.org/pub/source/v${pg_version}/postgresql-${pg_version}.tar.bz2"
-source_manifest="$repo_root/src/runtimes/liboliphaunt/native/postgres18/source.toml"
-patch_dir="$repo_root/src/runtimes/liboliphaunt/native/patches/postgresql-${pg_version}"
+source_manifest="$repo_root/src/third-party/postgres/source.toml"
+patch_dir="$repo_root"
+patch_series_file="$repo_root/src/runtimes/liboliphaunt-native/postgres/series"
 work_root="${OLIPHAUNT_IOS_DEVICE_ROOT:-$repo_root/target/liboliphaunt-ios-device}"
 source_cache="$work_root/source"
 tarball="$source_cache/postgresql-${pg_version}.tar.bz2"
@@ -59,19 +60,19 @@ report_failure() {
 }
 
 liboliphaunt_sources=(
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_native.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_error.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_runtime.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_protocol.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_config.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_trace.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_backup_state.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive_tar.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_static_extensions.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_builtin_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_native.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_error.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_runtime.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_protocol.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_config.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_trace.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_fs.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_backup_state.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive_tar.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_static_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_builtin_extensions.c"
 )
 
 plpgsql_objects=(
@@ -213,8 +214,7 @@ hash_mobile_static_extension_sources() {
 }
 
 patch_series() {
-  sed -n '/series = \[/,/\]/p' "$source_manifest" |
-    sed -n 's/.*"\([^"]*\.patch\)".*/\1/p'
+  sed '/^#/d; /^[[:space:]]*$/d' "$patch_series_file"
 }
 
 patch_series_hash() {
@@ -229,6 +229,9 @@ desired_hash() {
     printf 'pg_version=%s\n' "$pg_version"
     printf 'pg_sha256=%s\n' "$pg_sha256"
     printf 'sdk_path=%s\n' "$sdk_path"
+    xcodebuild -version
+    xcrun --sdk iphoneos --show-sdk-version
+    shasum -a 256 "$clang_path" "$clangxx_path" "$ar_path" "$ranlib_path" "$libtool_path"
     printf 'clang_path=%s\n' "$clang_path"
     printf 'clangxx_path=%s\n' "$clangxx_path"
     printf 'min_ios=%s\n' "$min_ios"
@@ -237,7 +240,7 @@ desired_hash() {
     printf 'ar=%s\n' "$ar_path"
     printf 'ranlib=%s\n' "$ranlib_path"
     printf 'icu_source=%s\n' "$(oliphaunt_icu_source_commit "$icu_source_dir")"
-    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256 "$script_dir")"
+    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256)"
     printf 'native_cflags=%s\n' "$native_cflags"
     printf 'liboliphaunt_cflags=%s\n' "$liboliphaunt_cflags"
     printf 'pg_extension_cflags=%s\n' "$pg_extension_cflags"
@@ -261,11 +264,7 @@ desired_hash() {
 }
 
 apply_patch_series() {
-  local patch_name
-  while IFS= read -r patch_name; do
-    [ -n "$patch_name" ] || continue
-    GIT_CEILING_DIRECTORIES="$work_root" git apply --whitespace=error-all "$patch_dir/$patch_name" >/dev/null
-  done < <(patch_series)
+  bash "$repo_root/src/third-party/postgres/apply-series.sh" "$build_dir" "$patch_series_file"
 }
 
 
@@ -292,6 +291,8 @@ artifact_ready() {
     _oliphaunt_exec_protocol \
     _oliphaunt_exec_simple_query \
     _oliphaunt_exec_protocol_raw_stream \
+    _oliphaunt_protocol_stream_token \
+    _oliphaunt_feed_protocol_stream \
     _oliphaunt_backup \
     _oliphaunt_restore \
     _oliphaunt_init_with_error \
@@ -459,7 +460,6 @@ configure_source() {
 build_icu() {
   oliphaunt_icu_build_target \
     "$icu_source_dir" \
-    "$script_dir" \
     "$icu_native_build_dir" \
     "$icu_build_dir" \
     "$icu_prefix" \
@@ -635,8 +635,8 @@ build_liboliphaunt_objects() {
     object="$out_dir/$(basename "${source%.c}").o"
     liboliphaunt_objects+=("$object")
     "${cc[@]}" $liboliphaunt_cflags \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/include" \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/src" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/include" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/src" \
       -c "$source" \
       -o "$object"
   done
@@ -691,7 +691,7 @@ build_openssl_dependency() {
 
 build_uuid_dependency() {
   mobile_static_dependency_selected uuid || return 0
-  local source_dir="$repo_root/src/runtimes/liboliphaunt/native/portable-uuid"
+  local source_dir="$repo_root/src/runtimes/liboliphaunt-native/portable-uuid"
   local dependency_dir="$mobile_static_dependency_root/uuid"
   local archive="$dependency_dir/lib/libuuid.a"
   local object="$dependency_dir/portable_uuid.o"
@@ -948,7 +948,7 @@ FOOTER
 build_mobile_static_registry_object() {
   [ "${#mobile_static_extensions[@]}" -gt 0 ] || return 0
   "${cc[@]}" $native_cflags \
-    -I"$repo_root/src/runtimes/liboliphaunt/native/include" \
+    -I"$repo_root/src/runtimes/liboliphaunt-native/include" \
     -c "$mobile_static_registry_source" \
     -o "$mobile_static_registry_object"
   mobile_static_objects+=("$mobile_static_registry_object")
@@ -994,7 +994,7 @@ link_liboliphaunt() {
 
 usage() {
   cat >&2 <<'MSG'
-usage: src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-device.sh [--check-current]
+usage: src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-device.sh [--check-current]
 MSG
 }
 
@@ -1007,6 +1007,10 @@ fi
 
 case "$script_mode" in
   build)
+    if artifact_ready && (cd "$build_dir" && generated_headers_ready && backend_objects_ready && support_libraries_ready && plpgsql_objects_ready && oliphaunt_mobile_builtin_snowball_objects_ready && jit_objects_ready) && [ -f "$stamp" ] && [ "$(cat "$stamp")" = "$(desired_hash)" ]; then
+      echo "$lib_out"
+      exit 0
+    fi
     failure_phase="prepare source"
     # EXIT is observed by this outer shell even when errexit originates inside
     # a build function or subshell. The handler clears the trap before
@@ -1017,10 +1021,6 @@ case "$script_mode" in
     build_icu
     failure_phase="configure PostgreSQL"
     configure_source
-    if artifact_ready && (cd "$build_dir" && generated_headers_ready && backend_objects_ready && support_libraries_ready && plpgsql_objects_ready && oliphaunt_mobile_builtin_snowball_objects_ready && jit_objects_ready) && [ -f "$stamp" ] && [ "$(cat "$stamp")" = "$(desired_hash)" ]; then
-      echo "$lib_out"
-      exit 0
-    fi
     : > "$make_log"
     failure_phase="generate PostgreSQL headers"
     build_generated_headers
diff --git a/src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh b/src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-simulator.sh
similarity index 94%
rename from src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh
rename to src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-simulator.sh
index d8fc54f4c..a6d2ee35d 100755
--- a/src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh
+++ b/src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-simulator.sh
@@ -3,18 +3,19 @@ set -euo pipefail
 
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 . "$script_dir/common.sh"
-. "$script_dir/icu.sh"
+. "$script_dir/../../../third-party/icu/tools/build.sh"
 . "$script_dir/mobile-static-extensions.sh"
 . "$script_dir/mobile-postgis-extensions.sh"
 script_path="$script_dir/$(basename "$0")"
 repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
-. "$repo_root/src/postgres/versions/18/fetch-source.sh"
+. "$repo_root/src/third-party/postgres/fetch-source.sh"
 oliphaunt_mobile_target="ios-simulator"
 pg_version="18.4"
 pg_sha256="81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094"
 pg_url="https://ftp.postgresql.org/pub/source/v${pg_version}/postgresql-${pg_version}.tar.bz2"
-source_manifest="$repo_root/src/runtimes/liboliphaunt/native/postgres18/source.toml"
-patch_dir="$repo_root/src/runtimes/liboliphaunt/native/patches/postgresql-${pg_version}"
+source_manifest="$repo_root/src/third-party/postgres/source.toml"
+patch_dir="$repo_root"
+patch_series_file="$repo_root/src/runtimes/liboliphaunt-native/postgres/series"
 work_root="${OLIPHAUNT_IOS_SIMULATOR_ROOT:-$repo_root/target/liboliphaunt-ios-simulator}"
 source_cache="$work_root/source"
 tarball="$source_cache/postgresql-${pg_version}.tar.bz2"
@@ -59,19 +60,19 @@ report_failure() {
 }
 
 liboliphaunt_sources=(
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_native.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_error.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_runtime.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_protocol.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_config.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_trace.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_backup_state.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive_tar.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_static_extensions.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_builtin_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_native.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_error.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_runtime.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_protocol.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_config.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_trace.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_fs.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_backup_state.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive_tar.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_static_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_builtin_extensions.c"
 )
 
 plpgsql_objects=(
@@ -213,8 +214,7 @@ hash_mobile_static_extension_sources() {
 }
 
 patch_series() {
-  sed -n '/series = \[/,/\]/p' "$source_manifest" |
-    sed -n 's/.*"\([^"]*\.patch\)".*/\1/p'
+  sed '/^#/d; /^[[:space:]]*$/d' "$patch_series_file"
 }
 
 patch_series_hash() {
@@ -229,6 +229,9 @@ desired_hash() {
     printf 'pg_version=%s\n' "$pg_version"
     printf 'pg_sha256=%s\n' "$pg_sha256"
     printf 'sdk_path=%s\n' "$sdk_path"
+    xcodebuild -version
+    xcrun --sdk iphonesimulator --show-sdk-version
+    shasum -a 256 "$clang_path" "$clangxx_path" "$ar_path" "$ranlib_path" "$libtool_path"
     printf 'clang_path=%s\n' "$clang_path"
     printf 'clangxx_path=%s\n' "$clangxx_path"
     printf 'min_ios=%s\n' "$min_ios"
@@ -237,7 +240,7 @@ desired_hash() {
     printf 'ar=%s\n' "$ar_path"
     printf 'ranlib=%s\n' "$ranlib_path"
     printf 'icu_source=%s\n' "$(oliphaunt_icu_source_commit "$icu_source_dir")"
-    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256 "$script_dir")"
+    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256)"
     printf 'native_cflags=%s\n' "$native_cflags"
     printf 'liboliphaunt_cflags=%s\n' "$liboliphaunt_cflags"
     printf 'pg_extension_cflags=%s\n' "$pg_extension_cflags"
@@ -261,11 +264,7 @@ desired_hash() {
 }
 
 apply_patch_series() {
-  local patch_name
-  while IFS= read -r patch_name; do
-    [ -n "$patch_name" ] || continue
-    GIT_CEILING_DIRECTORIES="$work_root" git apply --whitespace=error-all "$patch_dir/$patch_name" >/dev/null
-  done < <(patch_series)
+  bash "$repo_root/src/third-party/postgres/apply-series.sh" "$build_dir" "$patch_series_file"
 }
 
 
@@ -292,6 +291,8 @@ artifact_ready() {
     _oliphaunt_exec_protocol \
     _oliphaunt_exec_simple_query \
     _oliphaunt_exec_protocol_raw_stream \
+    _oliphaunt_protocol_stream_token \
+    _oliphaunt_feed_protocol_stream \
     _oliphaunt_backup \
     _oliphaunt_restore \
     _oliphaunt_init_with_error \
@@ -459,7 +460,6 @@ configure_source() {
 build_icu() {
   oliphaunt_icu_build_target \
     "$icu_source_dir" \
-    "$script_dir" \
     "$icu_native_build_dir" \
     "$icu_build_dir" \
     "$icu_prefix" \
@@ -635,8 +635,8 @@ build_liboliphaunt_objects() {
     object="$out_dir/$(basename "${source%.c}").o"
     liboliphaunt_objects+=("$object")
     "${cc[@]}" $liboliphaunt_cflags \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/include" \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/src" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/include" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/src" \
       -c "$source" \
       -o "$object"
   done
@@ -691,7 +691,7 @@ build_openssl_dependency() {
 
 build_uuid_dependency() {
   mobile_static_dependency_selected uuid || return 0
-  local source_dir="$repo_root/src/runtimes/liboliphaunt/native/portable-uuid"
+  local source_dir="$repo_root/src/runtimes/liboliphaunt-native/portable-uuid"
   local dependency_dir="$mobile_static_dependency_root/uuid"
   local archive="$dependency_dir/lib/libuuid.a"
   local object="$dependency_dir/portable_uuid.o"
@@ -948,7 +948,7 @@ FOOTER
 build_mobile_static_registry_object() {
   [ "${#mobile_static_extensions[@]}" -gt 0 ] || return 0
   "${cc[@]}" $native_cflags \
-    -I"$repo_root/src/runtimes/liboliphaunt/native/include" \
+    -I"$repo_root/src/runtimes/liboliphaunt-native/include" \
     -c "$mobile_static_registry_source" \
     -o "$mobile_static_registry_object"
   mobile_static_objects+=("$mobile_static_registry_object")
@@ -994,7 +994,7 @@ link_liboliphaunt() {
 
 usage() {
   cat >&2 <<'MSG'
-usage: src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh [--check-current]
+usage: src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-simulator.sh [--check-current]
 MSG
 }
 
@@ -1007,6 +1007,10 @@ fi
 
 case "$script_mode" in
   build)
+    if artifact_ready && (cd "$build_dir" && generated_headers_ready && backend_objects_ready && support_libraries_ready && plpgsql_objects_ready && oliphaunt_mobile_builtin_snowball_objects_ready && jit_objects_ready) && [ -f "$stamp" ] && [ "$(cat "$stamp")" = "$(desired_hash)" ]; then
+      echo "$lib_out"
+      exit 0
+    fi
     failure_phase="prepare source"
     # EXIT is observed by this outer shell even when errexit originates inside
     # a build function or subshell. The handler clears the trap before
@@ -1017,10 +1021,6 @@ case "$script_mode" in
     build_icu
     failure_phase="configure PostgreSQL"
     configure_source
-    if artifact_ready && (cd "$build_dir" && generated_headers_ready && backend_objects_ready && support_libraries_ready && plpgsql_objects_ready && oliphaunt_mobile_builtin_snowball_objects_ready && jit_objects_ready) && [ -f "$stamp" ] && [ "$(cat "$stamp")" = "$(desired_hash)" ]; then
-      echo "$lib_out"
-      exit 0
-    fi
     : > "$make_log"
     failure_phase="generate PostgreSQL headers"
     build_generated_headers
diff --git a/src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh b/src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh
similarity index 96%
rename from src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh
rename to src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh
index 54ee401a9..da71477ce 100755
--- a/src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh
+++ b/src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh
@@ -3,16 +3,17 @@ set -euo pipefail
 
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 . "$script_dir/common.sh"
-. "$script_dir/icu.sh"
+. "$script_dir/../../../third-party/icu/tools/build.sh"
 . "$script_dir/postgis-dependency-cache.sh"
 
 repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
-. "$repo_root/src/postgres/versions/18/fetch-source.sh"
+. "$repo_root/src/third-party/postgres/fetch-source.sh"
 pg_version="18.4"
 pg_sha256="81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094"
 pg_url="https://ftp.postgresql.org/pub/source/v${pg_version}/postgresql-${pg_version}.tar.bz2"
-source_manifest="$repo_root/src/runtimes/liboliphaunt/native/postgres18/source.toml"
-patch_dir="$repo_root/src/runtimes/liboliphaunt/native/patches/postgresql-${pg_version}"
+source_manifest="$repo_root/src/third-party/postgres/source.toml"
+patch_dir="$repo_root"
+patch_series_file="$repo_root/src/runtimes/liboliphaunt-native/postgres/series"
 
 case "$(uname -s):$(uname -m)" in
   Linux:x86_64|Linux:amd64)
@@ -57,19 +58,19 @@ icu_cpp_libs="-lstdc++"
 icu_libs="$icu_static_libs $icu_cpp_libs"
 
 liboliphaunt_sources=(
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_native.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_error.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_runtime.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_protocol.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_config.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_trace.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_backup_state.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive_tar.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_static_extensions.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_builtin_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_native.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_error.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_runtime.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_protocol.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_config.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_trace.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_fs.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_backup_state.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive_tar.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_static_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_builtin_extensions.c"
 )
 
 plpgsql_objects=(
@@ -375,13 +376,12 @@ liboliphaunt_cflags="$native_cflags -DOLIPHAUNT_BUILTIN_PLPGSQL"
 embedded_module_be_dllibs="-Wl,--no-as-needed -Wl,-z,defs -L$out_dir -Wl,-rpath,$out_dir -loliphaunt"
 normal_module_be_dllibs=""
 jobs="${OLIPHAUNT_JOBS:-$(nproc 2>/dev/null || echo 4)}"
-portable_uuid_dir="$repo_root/src/runtimes/liboliphaunt/native/portable-uuid"
+portable_uuid_dir="$repo_root/src/runtimes/liboliphaunt-native/portable-uuid"
 native_uuid_dependency_dir="$work_root/portable-uuid-native"
 native_uuid_archive="$native_uuid_dependency_dir/lib/libuuid.a"
 
 patch_series() {
-  sed -n '/series = \[/,/\]/p' "$source_manifest" |
-    sed -n 's/.*"\([^"]*\.patch\)".*/\1/p'
+  sed '/^#/d; /^[[:space:]]*$/d' "$patch_series_file"
 }
 
 patch_series_hash() {
@@ -400,7 +400,7 @@ desired_hash() {
     printf 'cc=%s\n' "$cc_string"
     printf 'cxx=%s\n' "$cxx_string"
     printf 'icu_source=%s\n' "$(oliphaunt_icu_source_commit "$icu_source_dir")"
-    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256 "$script_dir")"
+    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256)"
     printf 'native_cflags=%s\n' "$native_cflags"
     printf 'postgres_embedded_copt=%s\n' "$postgres_embedded_copt"
     printf 'liboliphaunt_cflags=%s\n' "$liboliphaunt_cflags"
@@ -492,8 +492,8 @@ extension_build_fingerprint() {
     printf 'embedded_be_dllibs=%s\n' "$embedded_module_be_dllibs"
     printf 'base_hash=%s\n' "$(desired_hash)"
     shasum -a 256 "$script_dir/$(basename "$0")"
-    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h"
+    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
+    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h"
     printf 'contrib_extensions=%s\n' "${contrib_extensions[*]}"
     printf 'external_extensions=%s\n' "${external_extensions[*]}"
     local extension dependency source_rel extension_checkout
@@ -536,11 +536,7 @@ extension_build_fingerprint() {
 }
 
 apply_patch_series() {
-  local patch_name
-  while IFS= read -r patch_name; do
-    [ -n "$patch_name" ] || continue
-    GIT_CEILING_DIRECTORIES="$work_root" git apply --whitespace=error-all "$patch_dir/$patch_name" >/dev/null
-  done < <(patch_series)
+  bash "$repo_root/src/third-party/postgres/apply-series.sh" "$build_dir" "$patch_series_file"
 }
 
 
@@ -570,7 +566,6 @@ prepare_source() {
 build_icu() {
   oliphaunt_icu_build_target \
     "$icu_source_dir" \
-    "$script_dir" \
     "$icu_native_build_dir" \
     "$icu_build_dir" \
     "$icu_prefix" \
@@ -1047,7 +1042,7 @@ native_extension_component_field() {
   local extension="${1:?missing extension}"
   local field="${2:?missing native component field}"
   "$repo_root/tools/dev/bun.sh" \
-    "$repo_root/src/extensions/tools/native-component-contract.mjs" \
+    "$repo_root/src/extensions/tools/native-component-contract.mts" \
     field "$extension" native native-dynamic "$target_id" "$field"
 }
 
@@ -1622,8 +1617,8 @@ build_liboliphaunt_objects() {
     object="$out_dir/$(basename "${source%.c}").o"
     liboliphaunt_objects+=("$object")
     "${cc[@]}" $liboliphaunt_cflags \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/include" \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/src" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/include" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/src" \
       -c "$source" \
       -o "$object"
   done
@@ -1675,6 +1670,8 @@ artifact_ready() {
     oliphaunt_exec_protocol \
     oliphaunt_exec_simple_query \
     oliphaunt_exec_protocol_raw_stream \
+    oliphaunt_protocol_stream_token \
+    oliphaunt_feed_protocol_stream \
     oliphaunt_backup \
     oliphaunt_restore \
     oliphaunt_init_with_error \
@@ -1702,7 +1699,7 @@ artifact_ready() {
 
 usage() {
   cat >&2 <<'MSG'
-usage: src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh [--runtime-only|--print-required-extension-artifacts|--check-current|--check-extension-artifacts-current]
+usage: src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh [--runtime-only|--print-required-extension-artifacts|--check-current|--check-extension-artifacts-current]
 MSG
 }
 
diff --git a/src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh b/src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh
similarity index 96%
rename from src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh
rename to src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh
index da64388b7..82d45c06c 100755
--- a/src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh
+++ b/src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh
@@ -4,10 +4,10 @@ set -euo pipefail
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 script_path="$script_dir/$(basename "${BASH_SOURCE[0]}")"
 . "$script_dir/common.sh"
-. "$script_dir/icu.sh"
+. "$script_dir/../../../third-party/icu/tools/build.sh"
 . "$script_dir/postgis-dependency-cache.sh"
 repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
-. "$repo_root/src/postgres/versions/18/fetch-source.sh"
+. "$repo_root/src/third-party/postgres/fetch-source.sh"
 macos_deployment_target="${MACOSX_DEPLOYMENT_TARGET:-11.0}"
 case "$macos_deployment_target" in
   ""|*[!0-9.]*)
@@ -19,8 +19,9 @@ export MACOSX_DEPLOYMENT_TARGET="$macos_deployment_target"
 pg_version="18.4"
 pg_sha256="81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094"
 pg_url="https://ftp.postgresql.org/pub/source/v${pg_version}/postgresql-${pg_version}.tar.bz2"
-source_manifest="$repo_root/src/runtimes/liboliphaunt/native/postgres18/source.toml"
-patch_dir="$repo_root/src/runtimes/liboliphaunt/native/patches/postgresql-${pg_version}"
+source_manifest="$repo_root/src/third-party/postgres/source.toml"
+patch_dir="$repo_root"
+patch_series_file="$repo_root/src/runtimes/liboliphaunt-native/postgres/series"
 work_root="${OLIPHAUNT_WORK_ROOT:-$repo_root/target/liboliphaunt-pg18}"
 source_cache="$work_root/source"
 tarball="$source_cache/postgresql-${pg_version}.tar.bz2"
@@ -35,22 +36,22 @@ extension_build_stamp="$out_dir/native-extension-artifacts.sha256"
 embedded_dict_snowball_build_stamp="$out_dir/dict_snowball.dylib.inputs.sha256"
 embedded_plpgsql_build_stamp="$out_dir/plpgsql.dylib.inputs.sha256"
 postgres_runtime_stamp="$install_dir/.oliphaunt-postgres-runtime.sha256"
-macos_module_nm_audit="$repo_root/src/runtimes/liboliphaunt/native/tools/audit-macos-module-nm.awk"
-macos_provider_collision_audit="$repo_root/src/runtimes/liboliphaunt/native/tools/audit-macos-provider-collisions.awk"
+macos_module_nm_audit="$repo_root/src/runtimes/liboliphaunt-native/tools/audit-macos-module-nm.awk"
+macos_provider_collision_audit="$repo_root/src/runtimes/liboliphaunt-native/tools/audit-macos-provider-collisions.awk"
 liboliphaunt_sources=(
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_native.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_error.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_runtime.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_protocol.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_config.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_trace.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_backup_state.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive_tar.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_static_extensions.c"
-  "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_builtin_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_native.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_error.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_runtime.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_protocol.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_config.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_trace.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_fs.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_backup_state.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive_tar.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_static_extensions.c"
+  "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_builtin_extensions.c"
 )
 liboliphaunt_objects=()
 lib_out="$out_dir/liboliphaunt.dylib"
@@ -297,13 +298,18 @@ verify_source_manifest() {
     grep -q "sha256 = \"$pg_sha256\"" "$source_manifest"
 }
 
+patch_series() {
+  sed '/^#/d; /^[[:space:]]*$/d' "$patch_series_file"
+}
+
 patch_series_hash() {
   (
     export LC_ALL=C
     local patch
-    for patch in "$patch_dir"/*.patch; do
+    while IFS= read -r patch_name; do
+      patch="$patch_dir/$patch_name"
       printf '%s %s\n' "$(basename "$patch")" "$(shasum -a 256 "$patch" | awk '{print $1}')"
-    done
+    done < <(patch_series)
   ) | shasum -a 256 | awk '{print $1}'
 }
 
@@ -661,6 +667,8 @@ liboliphaunt_artifact_ready() {
     _oliphaunt_exec_protocol \
     _oliphaunt_exec_simple_query \
     _oliphaunt_exec_protocol_raw_stream \
+    _oliphaunt_protocol_stream_token \
+    _oliphaunt_feed_protocol_stream \
     _oliphaunt_backup \
     _oliphaunt_restore \
     _oliphaunt_init_with_error \
@@ -732,8 +740,8 @@ liboliphaunt_build_fingerprint() {
     printf 'build_hash=%s\n' "$desired_build_hash"
     printf 'install_name=%s\n' '@rpath/liboliphaunt.dylib'
     printf 'liboliphaunt_sources=%s\n' "${liboliphaunt_sources[*]}"
-    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h"
+    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
+    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h"
     local source
     for source in "${liboliphaunt_sources[@]}"; do
       shasum -a 256 "$source"
@@ -844,7 +852,7 @@ native_extension_component_field() {
   local extension="${1:?missing extension}"
   local field="${2:?missing native component field}"
   "$repo_root/tools/dev/bun.sh" \
-    "$repo_root/src/extensions/tools/native-component-contract.mjs" \
+    "$repo_root/src/extensions/tools/native-component-contract.mts" \
     field "$extension" native native-dynamic macos-arm64 "$field"
 }
 
@@ -898,8 +906,8 @@ extension_build_fingerprint() {
     printf 'normal_be_dllibs=%s\n' "$normal_module_be_dllibs"
     printf 'embedded_be_dllibs=%s\n' "$embedded_module_be_dllibs"
     stat -f '%m %z %N' "$install_dir/bin/postgres"
-    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h"
+    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
+    shasum -a 256 "$repo_root/src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h"
     local source
     for source in "${liboliphaunt_sources[@]}"; do
       shasum -a 256 "$source"
@@ -955,7 +963,7 @@ extension_build_fingerprint() {
       done < <(native_extension_component_sources postgis)
       postgis_host_dependency_identity || return 1
     fi
-    hash_extension_source_tree "$repo_root/src/runtimes/liboliphaunt/native/portable-uuid"
+    hash_extension_source_tree "$repo_root/src/runtimes/liboliphaunt-native/portable-uuid"
   } | shasum -a 256 | awk '{print $1}'
 }
 
@@ -1211,12 +1219,12 @@ desired_build_hash="$(
     printf 'native_cflags=%s\n' "$native_cflags"
     printf 'apple_toolchain=%s\n' "$apple_toolchain_hash"
     printf 'icu_source=%s\n' "$(oliphaunt_icu_source_commit "$icu_source_dir")"
-    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256 "$script_dir")"
+    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256)"
     printf 'postgres_configure=with-icu\n'
     printf 'build_script=%s\n' "$(shasum -a 256 "$script_path" | awk '{print $1}')"
     printf 'backend_objects_makefile=%s\n' "$(shasum -a 256 "$script_dir/postgres-backend-objects.mk" | awk '{print $1}')"
     printf 'common_script=%s\n' "$(shasum -a 256 "$script_dir/common.sh" | awk '{print $1}')"
-    printf 'fetch_script=%s\n' "$(shasum -a 256 "$repo_root/src/postgres/versions/18/fetch-source.sh" | awk '{print $1}')"
+    printf 'fetch_script=%s\n' "$(shasum -a 256 "$repo_root/src/third-party/postgres/fetch-source.sh" | awk '{print $1}')"
     printf 'source_manifest=%s\n' "$(shasum -a 256 "$source_manifest" | awk '{print $1}')"
     printf 'module_audit=%s\n' "$(shasum -a 256 "$macos_module_nm_audit" | awk '{print $1}')"
     printf 'provider_audit=%s\n' "$(shasum -a 256 "$macos_provider_collision_audit" | awk '{print $1}')"
@@ -1240,7 +1248,7 @@ fi
 normal_module_be_dllibs="-undefined dynamic_lookup"
 embedded_module_be_dllibs="-L$out_dir -loliphaunt -Wl,-rpath,$out_dir"
 postgis_cc="${OLIPHAUNT_POSTGIS_CC:-$native_cc}"
-portable_uuid_dir="$repo_root/src/runtimes/liboliphaunt/native/portable-uuid"
+portable_uuid_dir="$repo_root/src/runtimes/liboliphaunt-native/portable-uuid"
 native_uuid_dependency_dir="$work_root/portable-uuid-native"
 native_uuid_archive="$native_uuid_dependency_dir/lib/libuuid.a"
 
@@ -1264,124 +1272,11 @@ fi
 
 if [ "$script_mode" != "build" ] && [ "$script_mode" != "--runtime-only" ]; then
   cat >&2 <<'MSG'
-usage: src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh [--runtime-only|--print-required-extension-artifacts|--check-oliphaunt-current|--check-extension-artifacts-current]
+usage: src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh [--runtime-only|--print-required-extension-artifacts|--check-oliphaunt-current|--check-extension-artifacts-current]
 MSG
   exit 2
 fi
 
-jobs="${OLIPHAUNT_JOBS:-$(sysctl -n hw.ncpu 2>/dev/null || echo 4)}"
-mkdir -p "$source_cache"
-
-macos_generation_roots_coherent() {
-  local root
-  local present=0
-  for root in "$build_dir" "$install_dir" "$out_dir"; do
-    if [ -L "$root" ] || { [ -e "$root" ] && [ ! -d "$root" ]; }; then
-      return 1
-    fi
-    if [ -d "$root" ]; then
-      present=$((present + 1))
-    fi
-  done
-  [ "$present" -eq 0 ] || [ "$present" -eq 3 ]
-}
-
-if [ "$current_generation_hash" != "$desired_build_hash" ] || ! macos_generation_roots_coherent; then
-  echo "invalidating stale macOS native build generation"
-  rm -rf \
-    "$build_dir" \
-    "$install_dir" \
-    "$out_dir" \
-    "$icu_native_build_dir" \
-    "$icu_build_dir" \
-    "$icu_prefix" \
-    "$work_root/icu"
-  generation_stamp_stage="$generation_stamp.tmp.$$"
-  rm -rf "$generation_stamp_stage"
-  printf '%s\n' "$desired_build_hash" > "$generation_stamp_stage"
-  mv -f "$generation_stamp_stage" "$generation_stamp"
-fi
-mkdir -p "$out_dir"
-
-icu_host="$(sh "$icu_source_dir/config.guess")"
-oliphaunt_icu_build_target \
-  "$icu_source_dir" \
-  "$script_dir" \
-  "$icu_native_build_dir" \
-  "$icu_build_dir" \
-  "$icu_prefix" \
-  "$jobs" \
-  "macos" \
-  "$icu_host" \
-  "$CC" \
-  "$CXX" \
-  "ar" \
-  "ranlib" \
-  "$native_cflags" \
-  "$native_cflags -std=c++17" \
-  ""
-
-oliphaunt_fetch_postgresql_source_archive "$tarball" "$pg_version" "$pg_sha256" "$pg_url"
-
-(
-  cd "$source_cache"
-  printf '%s  %s\n' "$pg_sha256" "postgresql-${pg_version}.tar.bz2" | shasum -a 256 -c -
-)
-
-postgres_source_configure_complete() {
-  [ -f "$build_dir/config.status" ] &&
-    [ -f "$build_dir/src/include/pg_config.h" ]
-}
-
-postgres_source_configure_reusable() {
-  if postgres_source_configure_complete; then
-    return 0
-  fi
-  [ ! -f "$build_dir/config.status" ] &&
-    [ ! -f "$build_dir/config.log" ]
-}
-
-if [ -d "$build_dir" ] && ! postgres_source_configure_reusable; then
-  echo "discarding incomplete PostgreSQL configure tree at $build_dir" >&2
-  rm -rf "$build_dir"
-fi
-
-if [ ! -d "$build_dir" ]; then
-  tar -xjf "$tarball" -C "$work_root"
-fi
-
-cd "$build_dir"
-
-if [ ! -f "$build_stamp" ]; then
-  git init -q
-  for patch_file in "$patch_dir"/*.patch; do
-    GIT_CEILING_DIRECTORIES="$work_root" git apply --whitespace=error-all "$patch_file"
-  done
-  printf '%s\n' "$desired_build_hash" > "$build_stamp"
-fi
-
-if [ ! -f config.status ]; then
-  echo "Using CC=$CC"
-  CPPFLAGS="$icu_cflags" \
-  LDFLAGS="-L$icu_prefix/lib" \
-  ICU_CFLAGS="$icu_cflags" \
-  ICU_LIBS="$icu_libs" \
-    ./configure \
-    --prefix="$install_dir" \
-    --without-readline \
-    --with-icu \
-    --without-llvm \
-    --without-pam \
-    --with-openssl=no \
-    --without-zlib \
-    --disable-nls
-fi
-
-if ! postgres_source_configure_complete; then
-  echo "PostgreSQL configure did not produce config.status and src/include/pg_config.h" >&2
-  exit 1
-fi
-
 runtime_installed() {
   [ -x "$install_dir/bin/initdb" ] &&
     [ -x "$install_dir/bin/postgres" ] &&
@@ -1436,8 +1331,8 @@ compile_liboliphaunt_objects() {
   local index
   for index in "${!liboliphaunt_sources[@]}"; do
     $CC $(oliphaunt_native_release_cflags -fPIC) \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/include" \
-      -I"$repo_root/src/runtimes/liboliphaunt/native/src" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/include" \
+      -I"$repo_root/src/runtimes/liboliphaunt-native/src" \
       -c "${liboliphaunt_sources[$index]}" \
       -o "${liboliphaunt_objects[$index]}"
   done
@@ -2386,6 +2281,141 @@ build_native_extension_artifacts() {
   printf '%s\n' "$desired_extension_hash" > "$extension_build_stamp"
 }
 
+# A finished generation needs no configure, ICU make walk, or object rebuild.
+if [ "$script_mode" = build ] &&
+  [ "$current_generation_hash" = "$desired_build_hash" ] &&
+  [ "${OLIPHAUNT_FORCE_RELINK:-0}" != 1 ] &&
+  [ "${OLIPHAUNT_FORCE_EXTENSION_REBUILD:-0}" != 1 ] &&
+  [ -d "$build_dir" ] && [ ! -L "$build_dir" ] &&
+  [ -d "$install_dir" ] && [ ! -L "$install_dir" ] &&
+  [ -d "$out_dir" ] && [ ! -L "$out_dir" ] &&
+  (cd "$build_dir" && runtime_installed && liboliphaunt_artifacts_current) &&
+  { if [ "${OLIPHAUNT_BUILD_EXTENSIONS:-0}" = 0 ]; then
+      base_embedded_module_closure_ready
+    else
+      native_extension_artifacts_current
+    fi; }; then
+  embedded_dict_snowball_avoids_provider_collisions
+  embedded_plpgsql_avoids_provider_collisions
+  if [ "${OLIPHAUNT_BUILD_EXTENSIONS:-0}" != 0 ]; then
+    audit_packaged_extension_modules
+    audit_embedded_extension_modules
+  fi
+  echo "reusing finished macOS native build" >&2
+  echo "$lib_out"
+  exit 0
+fi
+
+jobs="${OLIPHAUNT_JOBS:-$(sysctl -n hw.ncpu 2>/dev/null || echo 4)}"
+mkdir -p "$source_cache"
+
+macos_generation_roots_coherent() {
+  local root
+  local present=0
+  for root in "$build_dir" "$install_dir" "$out_dir"; do
+    if [ -L "$root" ] || { [ -e "$root" ] && [ ! -d "$root" ]; }; then
+      return 1
+    fi
+    if [ -d "$root" ]; then
+      present=$((present + 1))
+    fi
+  done
+  [ "$present" -eq 0 ] || [ "$present" -eq 3 ]
+}
+
+if [ "$current_generation_hash" != "$desired_build_hash" ] || ! macos_generation_roots_coherent; then
+  echo "invalidating stale macOS native build generation"
+  rm -rf \
+    "$build_dir" \
+    "$install_dir" \
+    "$out_dir" \
+    "$icu_native_build_dir" \
+    "$icu_build_dir" \
+    "$icu_prefix" \
+    "$work_root/icu"
+  generation_stamp_stage="$generation_stamp.tmp.$$"
+  rm -rf "$generation_stamp_stage"
+  printf '%s\n' "$desired_build_hash" > "$generation_stamp_stage"
+  mv -f "$generation_stamp_stage" "$generation_stamp"
+fi
+mkdir -p "$out_dir"
+
+icu_host="$(sh "$icu_source_dir/config.guess")"
+oliphaunt_icu_build_target \
+  "$icu_source_dir" \
+  "$icu_native_build_dir" \
+  "$icu_build_dir" \
+  "$icu_prefix" \
+  "$jobs" \
+  "macos" \
+  "$icu_host" \
+  "$CC" \
+  "$CXX" \
+  "ar" \
+  "ranlib" \
+  "$native_cflags" \
+  "$native_cflags -std=c++17" \
+  ""
+
+oliphaunt_fetch_postgresql_source_archive "$tarball" "$pg_version" "$pg_sha256" "$pg_url"
+
+(
+  cd "$source_cache"
+  printf '%s  %s\n' "$pg_sha256" "postgresql-${pg_version}.tar.bz2" | shasum -a 256 -c -
+)
+
+postgres_source_configure_complete() {
+  [ -f "$build_dir/config.status" ] &&
+    [ -f "$build_dir/src/include/pg_config.h" ]
+}
+
+postgres_source_configure_reusable() {
+  if postgres_source_configure_complete; then
+    return 0
+  fi
+  [ ! -f "$build_dir/config.status" ] &&
+    [ ! -f "$build_dir/config.log" ]
+}
+
+if [ -d "$build_dir" ] && ! postgres_source_configure_reusable; then
+  echo "discarding incomplete PostgreSQL configure tree at $build_dir" >&2
+  rm -rf "$build_dir"
+fi
+
+if [ ! -d "$build_dir" ]; then
+  tar -xjf "$tarball" -C "$work_root"
+fi
+
+cd "$build_dir"
+
+if [ ! -f "$build_stamp" ]; then
+  git init -q
+  bash "$repo_root/src/third-party/postgres/apply-series.sh" "$build_dir" "$patch_series_file"
+  printf '%s\n' "$desired_build_hash" > "$build_stamp"
+fi
+
+if [ ! -f config.status ]; then
+  echo "Using CC=$CC"
+  CPPFLAGS="$icu_cflags" \
+  LDFLAGS="-L$icu_prefix/lib" \
+  ICU_CFLAGS="$icu_cflags" \
+  ICU_LIBS="$icu_libs" \
+    ./configure \
+    --prefix="$install_dir" \
+    --without-readline \
+    --with-icu \
+    --without-llvm \
+    --without-pam \
+    --with-openssl=no \
+    --without-zlib \
+    --disable-nls
+fi
+
+if ! postgres_source_configure_complete; then
+  echo "PostgreSQL configure did not produce config.status and src/include/pg_config.h" >&2
+  exit 1
+fi
+
 # Build and install a normal PostgreSQL tree first. initdb needs the matching
 # sibling postgres binary and the installed share/lib tree needs core modules
 # such as dict_snowball and plpgsql. Keep this separate from the embedded/PIC
diff --git a/src/runtimes/liboliphaunt-native/bin/build-postgres18-windows.sh b/src/runtimes/liboliphaunt-native/bin/build-postgres18-windows.sh
new file mode 100755
index 000000000..b101cb582
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/bin/build-postgres18-windows.sh
@@ -0,0 +1,343 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+source "$script_dir/common.sh"
+repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
+cd "$repo_root"
+source src/third-party/postgres/fetch-source.sh
+source src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
+
+fail() {
+  echo "build-postgres18-windows.sh: $*" >&2
+  exit 1
+}
+case "$(uname -s)" in MINGW* | MSYS*) ;; *) fail 'run on Windows in Git Bash with an MSVC developer environment' ;; esac
+[ "$#" -le 1 ] || fail 'usage: build-postgres18-windows.sh [--check-current]'
+case "${1:-}" in '' | --check-current) ;; *) fail 'usage: build-postgres18-windows.sh [--check-current]' ;; esac
+native_path() { cygpath -m "$1"; }
+native() { MSYS2_ARG_CONV_EXCL='*' "$@"; }
+sha256() { oliphaunt_postgresql_sha256_file "$1"; }
+logged() {
+  local name="$1"
+  shift
+  if "$@" >"$work_root/$name" 2>&1; then return; else
+    local status=$?
+    oliphaunt_tail_log_excerpt "$work_root/$name" 160 >&2
+    echo "Windows build failed; see $work_root/$name" >&2
+    return "$status"
+  fi
+}
+first_file() {
+  local root="$1" pattern result
+  shift
+  for pattern in "$@"; do
+    result="$(find "$root" -type f -name "$pattern" -print | LC_ALL=C sort | sed -n '1p')"
+    if [ -n "$result" ]; then
+      printf '%s\n' "$result"
+      return
+    fi
+  done
+  fail "missing $* under $root"
+}
+
+target_id=windows-x64-msvc
+work_root="$(cygpath -u "${OLIPHAUNT_WINDOWS_WORK_ROOT:-${OLIPHAUNT_WORK_ROOT:-$repo_root/target/liboliphaunt-pg18-$target_id}}")"
+postgres_source="$(bun src/third-party/postgres/source.mts)"
+IFS=$'\t' read -r pg_version pg_sha256 pg_url <<<"$postgres_source"
+build_dir="$work_root/postgresql-$pg_version"
+runtime_build_dir="$work_root/meson-runtime"
+embedded_build_dir="$work_root/meson-embedded"
+install_dir="$work_root/install"
+out_dir="$work_root/out"
+obj_dir="$out_dir/obj"
+dll_out="$out_dir/bin/oliphaunt.dll"
+import_lib_out="$out_dir/lib/oliphaunt.lib"
+embedded_modules_dir="$out_dir/modules"
+stamp="$out_dir/oliphaunt-windows.inputs.sha256"
+external_checkout_root="$repo_root/target/oliphaunt-sources/checkouts"
+icu_windows_root="$external_checkout_root/icu-windows"
+build_extensions="${OLIPHAUNT_BUILD_EXTENSIONS:-0}"
+native_extension_sql_names="${OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES:-${OLIPHAUNT_EXTENSION_SQL_NAMES:-}}"
+vc_runtime_tool="$repo_root/tools/packaging/windows-vc-runtime-closure.mts"
+core_modules=(dict_snowball plpgsql)
+icu_dlls=(icudt76.dll icuin76.dll icuuc76.dll)
+sources=("$repo_root"/src/runtimes/liboliphaunt-native/src/*.c)
+
+selected() {
+  [ "$build_extensions" != 0 ] || return 1
+  [ -n "$native_extension_sql_names" ] || return 0
+  local name
+  local -a names
+  IFS=',' read -r -a names <<<"$native_extension_sql_names"
+  for name in "${names[@]}"; do
+    name="${name//[[:space:]]/}"
+    [ "$name" != "$1" ] || return 0
+  done
+  return 1
+}
+
+configure_tools() {
+  : "${VCToolsInstallDir:?Run Git Bash with the Visual Studio x64 developer environment; CI uses setup-msvc}"
+  local msvc_bin tool perl_dir
+  msvc_bin="$(cygpath -u "$VCToolsInstallDir")/bin/Hostx64/x64"
+  for tool in cl.exe link.exe lib.exe dumpbin.exe; do
+    [ -f "$msvc_bin/$tool" ] || fail "missing MSVC tool $msvc_bin/$tool"
+  done
+  # MSVC must precede Git's unrelated link.exe; native Perl must precede MSYS Perl.
+  for perl_dir in /c/Strawberry/perl/bin /c/Perl64/bin; do
+    if [ -x "$perl_dir/perl.exe" ]; then
+      export PATH="$perl_dir:$PATH"
+      break
+    fi
+  done
+  export PATH="$msvc_bin:$PATH"
+  hash -r
+  for tool in cl.exe link.exe lib.exe dumpbin.exe; do
+    [ "$(native_path "$(command -v "$tool")")" = "$(native_path "$msvc_bin/$tool")" ] || fail "$tool is not from MSVC"
+  done
+  case "$(command -v perl.exe)" in */Git/usr/bin/* | /usr/bin/*) fail 'PostgreSQL requires native Windows Perl, not MSYS Perl' ;; esac
+  export CC=cl.exe CXX=cl.exe AR=lib.exe CCACHE_DISABLE=1
+  for tool in git bun perl.exe meson ninja; do command -v "$tool" >/dev/null || fail "missing build tool: $tool"; done
+  [ "$(meson --version | tr -d '\r')" = 1.10.0 ] || fail 'expected Meson 1.10.0'
+  local ninja_version
+  ninja_version="$(ninja --version | tr -d '\r')"
+  case "$ninja_version" in
+    1.13.0 | 1.13.0.gd74ef.kitware.jobserver-pipe-1 | 1.13.0.git.kitware.jobserver-pipe-1) ;;
+    *) fail "expected Ninja from the pinned 1.13.0 distribution, got $ninja_version" ;;
+  esac
+  export ICU_ROOT
+  ICU_ROOT="$(native_path "$icu_windows_root")"
+}
+
+extension_catalog() {
+  bun src/extensions/tools/native-extension-files.mts
+}
+windows_extension_modules() {
+  [ "$build_extensions" != 0 ] || return 0
+  local sql_name stem
+  while IFS=$'\t' read -r sql_name stem; do
+    if selected "$sql_name" && [ "$stem" != - ]; then printf '%s\t%s\n' "$sql_name" "$stem"; fi
+  done < <(awk -F '\t' 'NR>1 { print $1 "\t" $2 }' "$catalog")
+}
+windows_extension_prune() {
+  [ "$build_extensions" = 0 ] || return 0
+  local sql_name stem data_files item suffix
+  while IFS=$'\t' read -r sql_name stem data_files; do
+    rm -f "$install_dir/share/postgresql/extension/$sql_name.control" "$install_dir/share/postgresql/extension/$sql_name"--*.sql
+    if [ "$stem" != - ]; then
+      for suffix in dll so dylib; do rm -f "$install_dir/lib/postgresql/$stem.$suffix"; done
+    fi
+    if [ "$data_files" != - ]; then
+      local -a data
+      IFS=',' read -r -a data <<<"$data_files"
+      for item in "${data[@]}"; do [ -z "$item" ] || rm -rf "$install_dir/share/postgresql/$item"; done
+    fi
+  done < <(awk -F '\t' 'NR>1 { print $1 "\t" $2 "\t" $3 }' "$catalog")
+  rm -f "$install_dir"/share/postgresql/extension/{postgis*,rtpostgis*,pgtap-*,uninstall_postgis,uninstall_legacy,uninstall_pgtap}.sql
+  rm -rf "$install_dir/share/postgresql/contrib" "$install_dir/share/postgresql/proj"
+}
+windows_extension_base_absent() {
+  [ "$build_extensions" = 0 ] || return 0
+  oliphaunt_assert_base_runtime_has_no_optional_extensions "$catalog" "$install_dir" || return
+  local sql_name
+  while IFS= read -r sql_name; do
+    if compgen -G "$install_dir/share/postgresql/extension/$sql_name--*.sql" >/dev/null; then return 1; fi
+  done < <(awk -F '\t' 'NR>1 { print $1 }' "$catalog")
+  [ ! -d "$install_dir/share/postgresql/contrib" ] && [ ! -d "$install_dir/share/postgresql/proj" ]
+}
+
+module_binding() {
+  [ -f "$1" ] || return 1
+  local imports
+  imports="$(native dumpbin.exe /dependents "$(native_path "$1")")" || return
+  local server=0 embedded=0
+  if oliphaunt_text_matches_ere "$imports" '^[[:space:]]*postgres\.exe[[:space:]]*$'; then server=1; fi
+  if oliphaunt_text_matches_ere "$imports" '^[[:space:]]*oliphaunt\.dll[[:space:]]*$'; then embedded=1; fi
+  case "$server:$embedded" in 0:0) echo neutral ;; 1:0) echo server ;; 0:1) echo embedded ;; *) echo crossed ;; esac
+}
+module_profiles_ready() {
+  local stem="$1" required="$2" server embedded
+  server="$(module_binding "$install_dir/lib/postgresql/$stem.dll")" || return
+  embedded="$(module_binding "$embedded_modules_dir/$stem.dll")" || return
+  case "$server" in server | neutral) ;; *) return 1 ;; esac
+  case "$embedded:$required" in embedded:* | neutral:0) ;; *) return 1 ;; esac
+  if [ "$(sha256 "$install_dir/lib/postgresql/$stem.dll")" = "$(sha256 "$embedded_modules_dir/$stem.dll")" ]; then
+    [ "$server:$embedded" = neutral:neutral ] || return 1
+  fi
+}
+public_exports() {
+  sed -nE 's/^OLIPHAUNT_API[[:space:]]+.*[[:space:]*](oliphaunt_[a-z0-9_]+)\(.*/\1/p' src/runtimes/liboliphaunt-native/include/oliphaunt.h
+}
+artifact_ready() {
+  [ -s "$dll_out" ] && [ -s "$import_lib_out" ] || return 1
+  local stem sql_name name exports symbol
+  for stem in "${core_modules[@]}"; do module_profiles_ready "$stem" 1 || return; done
+  while IFS=$'\t' read -r sql_name stem; do module_profiles_ready "$stem" 0 || return; done < <(windows_extension_modules)
+  for name in "${icu_dlls[@]}"; do [ -s "$out_dir/bin/$name" ] || return 1; done
+  bun "$vc_runtime_tool" verify --root "$install_dir" --profile provider --search-root "$install_dir/bin" || return
+  bun "$vc_runtime_tool" verify --root "$out_dir" --profile provider --search-root "$out_dir/bin" || return
+  exports="$(native dumpbin.exe /exports "$(native_path "$dll_out")")" || return
+  while IFS= read -r symbol; do
+    oliphaunt_text_matches_ere "$exports" "(^|[^A-Za-z0-9_])$symbol([^A-Za-z0-9_]|$)" || return
+  done < <(public_exports)
+}
+runtime_ready() {
+  local file
+  for file in bin/{initdb,postgres,pg_config}.exe include/pg_config.h share/postgresql/{postgresql.conf.sample,snowball_create.sql,timezone/UTC} lib/postgresql/dict_snowball.dll; do
+    [ -s "$install_dir/$file" ] && [ ! -L "$install_dir/$file" ] || return 1
+  done
+  grep -F '#define USE_ICU 1' "$install_dir/include/pg_config.h" >/dev/null || return
+  for file in "$build_dir"/src/backend/snowball/stopwords/*.stop; do
+    [ -s "$install_dir/share/postgresql/tsearch_data/${file##*/}" ] || return 1
+  done
+  for file in "${icu_dlls[@]}"; do [ -s "$install_dir/bin/$file" ] || return 1; done
+  [ -f "$install_dir/.oliphaunt-postgres-runtime.sha256" ] && [ "$(cat "$install_dir/.oliphaunt-postgres-runtime.sha256")" = "$desired_hash" ] || return 1
+  windows_extension_base_absent
+}
+
+write_native_file() {
+  printf "[binaries]\nc = 'cl.exe'\ncpp = 'cl.exe'\nar = 'lib.exe'\n" >"$1"
+  if [ "$2" = embedded ]; then printf "\n[built-in options]\nc_args = ['/D_CRT_SECURE_NO_WARNINGS']\n" >>"$1"; fi
+}
+meson_setup() {
+  local directory="$1" profile="$2" native_file="$work_root/meson-$2-native.ini"
+  write_native_file "$native_file" "$profile"
+  local -a options=(--native-file "$(native_path "$native_file")" --prefix "$(native_path "$install_dir")" --buildtype=release -Db_pch=false -Dreadline=disabled -Dicu=enabled -Dldap=disabled -Dllvm=disabled -Dzlib=disabled -Dzstd=disabled -Dlz4=disabled -Dnls=disabled -Dssl=none -Ddocs=disabled -Dtap_tests=disabled -Dplperl=disabled -Dplpython=disabled -Dpltcl=disabled)
+  if [ "$profile" = embedded ]; then options+=(-Doliphaunt_embedded=true -Doliphaunt_embedded_module_provider=); fi
+  [ -d "$directory" ] || logged "meson-$profile-setup.log" meson setup "$(native_path "$directory")" "$(native_path "$build_dir")" "${options[@]}"
+}
+stage_icu_runtime() {
+  local name
+  mkdir -p "$1"
+  for name in "${icu_dlls[@]}"; do cp "$icu_windows_root/bin64/$name" "$1/"; done
+}
+assert_symbol() {
+  local symbols
+  symbols="$(native dumpbin.exe /symbols "$(native_path "$1")")"
+  oliphaunt_text_matches_ere "$symbols" "(^|[^A-Za-z0-9_])_?$2([^A-Za-z0-9_]|$)" || fail "$1 lacks embedded symbol $2"
+}
+link_embedded() {
+  local postgres_lib postgres_def source object stem
+  postgres_lib="$(first_file "$embedded_build_dir" postgres_lib.lib postgres_lib.a)"
+  postgres_def="$(first_file "$embedded_build_dir" postgres.def)"
+  assert_symbol "$postgres_lib" oliphaunt_embedded_main
+  mkdir -p "$out_dir/bin" "$out_dir/lib"
+  rm -rf "$obj_dir"
+  mkdir -p "$obj_dir"
+  # Public C functions use the header's dllexport declarations. These two hooks
+  # come from PostgreSQL's archive and need explicit exports for embedded modules.
+  local -a arguments=(/nologo /DLL /INCREMENTAL:NO "/OUT:$(native_path "$dll_out")" "/IMPLIB:$(native_path "$import_lib_out")" "/PDB:$(native_path "$out_dir/bin/oliphaunt.pdb")" "/DEF:$(native_path "$postgres_def")" "/WHOLEARCHIVE:$(native_path "$postgres_lib")" /EXPORT:oliphaunt_embedded_kill /EXPORT:oliphaunt_embedded_raise)
+  for source in "${sources[@]}"; do
+    stem="${source##*/}"
+    stem="${stem%.c}"
+    object="$obj_dir/$stem.obj"
+    logged "compile-$stem.log" native cl.exe /nologo /std:c11 /O2 /Zi /MD /DOLIPHAUNT_EMBEDDED /DOLIPHAUNT_BUILTIN_PLPGSQL /DOLIPHAUNT_BUILDING_DLL /D_CRT_SECURE_NO_WARNINGS "/I$(native_path "$repo_root/src/runtimes/liboliphaunt-native/include")" "/I$(native_path "$repo_root/src/runtimes/liboliphaunt-native/src")" /c "$(native_path "$source")" "/Fo$(native_path "$object")"
+    arguments+=("$(native_path "$object")")
+  done
+  for stem in pl_comp pl_exec pl_funcs pl_gram pl_handler pl_scanner; do
+    local -a matches=()
+    while IFS= read -r -d '' object; do matches+=("$object"); done < <(find "$embedded_build_dir/src/pl/plpgsql/src" -type f -name "*$stem.c.obj" -print0)
+    [ "${#matches[@]}" = 1 ] || fail "expected one PL/pgSQL object for $stem, found ${#matches[@]}"
+    case "$stem" in pl_gram) assert_symbol "${matches[0]}" plpgsql_yyparse ;; pl_handler) assert_symbol "${matches[0]}" plpgsql_call_handler ;; esac
+    arguments+=("$(native_path "${matches[0]}")")
+  done
+  for stem in icuin icuuc icudt; do arguments+=("$(native_path "$icu_windows_root/lib64/$stem.lib")"); done
+  arguments+=(ws2_32.lib secur32.lib advapi32.lib shell32.lib user32.lib bcrypt.lib)
+  printf '"%s"\r\n' "${arguments[@]}" >"$out_dir/link-oliphaunt.rsp"
+  logged link-oliphaunt.log native link.exe "@$(native_path "$out_dir/link-oliphaunt.rsp")"
+}
+build_modules() {
+  local -a stems=("${core_modules[@]}") matches
+  local sql_name stem source
+  while IFS=$'\t' read -r sql_name stem; do stems+=("$stem"); done < <(windows_extension_modules)
+  logged meson-embedded-module-provider.log meson configure "$(native_path "$embedded_build_dir")" "-Doliphaunt_embedded_module_provider=$(native_path "$import_lib_out")"
+  logged meson-embedded-modules.log meson compile -C "$(native_path "$embedded_build_dir")" "${stems[@]}"
+  rm -rf "$embedded_modules_dir"
+  mkdir -p "$embedded_modules_dir"
+  for stem in "${stems[@]}"; do
+    matches=()
+    while IFS= read -r -d '' source; do matches+=("$source"); done < <(find "$embedded_build_dir" -type f -name "$stem.dll" -print0)
+    [ "${#matches[@]}" = 1 ] || fail "expected one embedded $stem.dll, found ${#matches[@]}"
+    cp "${matches[0]}" "$embedded_modules_dir/$stem.dll"
+  done
+}
+
+# The extension owner supplies source/Meson generation and optional SQL installation.
+source "$repo_root/src/extensions/artifacts/native/tools/build-windows-extensions.sh"
+configure_tools
+for required in include/unicode/ucol.h lib64/{icudt,icuin,icuuc}.lib bin64/{icudt76,icuin76,icuuc76}.dll; do
+  [ -s "$icu_windows_root/$required" ] || fail "missing pinned Windows ICU dependency $required"
+done
+catalog="$(mktemp)"
+trap 'rm -f "$catalog"' EXIT
+extension_catalog >"$catalog"
+desired_hash="$(
+  set -e
+  {
+    printf '%s\n' "postgres=$pg_version/$pg_sha256" "target=$target_id" "extensions=$build_extensions/$native_extension_sql_names" "msvc=${VCToolsVersion:-}" "windows_sdk=${WindowsSDKVersion:-}"
+    sha256 "$(command -v cl.exe)"
+    sha256 "$(command -v link.exe)"
+    for input in src/third-party/postgres/{source.toml,source.mts,fetch-source.sh} src/runtimes/liboliphaunt-native/postgres/series src/runtimes/liboliphaunt-native/sources/icu-windows.toml src/extensions/generated/pgxs-build.tsv src/extensions/catalog/native-components.toml src/extensions/tools/native-component-contract.mts src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh "$vc_runtime_tool" src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json "$catalog"; do sha256 "$input"; done
+    while IFS= read -r patch; do
+      case "$patch" in '' | '#'*) continue ;; esac
+      sha256 "$patch"
+    done "$install_dir/.oliphaunt-postgres-runtime.sha256"
+  runtime_ready || fail 'PostgreSQL Windows runtime install is incomplete'
+fi
+(
+  export CFLAGS=''
+  meson_setup "$embedded_build_dir" embedded
+  logged meson-embedded-bootstrap-provider.log meson configure "$(native_path "$embedded_build_dir")" -Doliphaunt_embedded_module_provider=
+  for target in postgres_lib postgres.def plpgsql; do logged "meson-embedded-$target.log" meson compile -C "$(native_path "$embedded_build_dir")" "$target"; done
+)
+link_embedded
+stage_icu_runtime "$out_dir/bin"
+build_modules
+for directory in "$install_dir" "$out_dir"; do bun "$vc_runtime_tool" stage --root "$directory" --profile provider --destination "$directory/bin"; done
+artifact_ready || fail 'Windows DLL or module/VC runtime closure is incomplete'
+printf '%s' "$desired_hash" >"$stamp"
+echo "$dll_out"
diff --git a/src/runtimes/liboliphaunt/native/bin/check-postgres18-ios-simulator.sh b/src/runtimes/liboliphaunt-native/bin/check-postgres18-ios-simulator.sh
similarity index 91%
rename from src/runtimes/liboliphaunt/native/bin/check-postgres18-ios-simulator.sh
rename to src/runtimes/liboliphaunt-native/bin/check-postgres18-ios-simulator.sh
index 4ab4c2762..c37ab8c3e 100755
--- a/src/runtimes/liboliphaunt/native/bin/check-postgres18-ios-simulator.sh
+++ b/src/runtimes/liboliphaunt-native/bin/check-postgres18-ios-simulator.sh
@@ -3,14 +3,15 @@ set -euo pipefail
 
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 . "$script_dir/common.sh"
-. "$script_dir/icu.sh"
+. "$script_dir/../../../third-party/icu/tools/build.sh"
 repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
-. "$repo_root/src/postgres/versions/18/fetch-source.sh"
+. "$repo_root/src/third-party/postgres/fetch-source.sh"
 pg_version="18.4"
 pg_sha256="81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094"
 pg_url="https://ftp.postgresql.org/pub/source/v${pg_version}/postgresql-${pg_version}.tar.bz2"
-source_manifest="$repo_root/src/runtimes/liboliphaunt/native/postgres18/source.toml"
-patch_dir="$repo_root/src/runtimes/liboliphaunt/native/patches/postgresql-${pg_version}"
+source_manifest="$repo_root/src/third-party/postgres/source.toml"
+patch_dir="$repo_root"
+patch_series_file="$repo_root/src/runtimes/liboliphaunt-native/postgres/series"
 work_root="${OLIPHAUNT_IOS_SIMULATOR_CHECK_ROOT:-$repo_root/target/liboliphaunt-ios-simulator-check}"
 source_cache="$work_root/source"
 tarball="$source_cache/postgresql-${pg_version}.tar.bz2"
@@ -74,8 +75,7 @@ cc_string="${cc[*]}"
 cxx_string="${cxx[*]}"
 
 patch_series() {
-  sed -n '/series = \[/,/\]/p' "$source_manifest" |
-    sed -n 's/.*"\([^"]*\.patch\)".*/\1/p'
+  sed '/^#/d; /^[[:space:]]*$/d' "$patch_series_file"
 }
 
 patch_series_hash() {
@@ -98,7 +98,7 @@ desired_hash() {
     printf 'ar=%s\n' "$ar_path"
     printf 'ranlib=%s\n' "$ranlib_path"
     printf 'icu_source=%s\n' "$(oliphaunt_icu_source_commit "$icu_source_dir")"
-    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256 "$script_dir")"
+    printf 'icu_script=%s\n' "$(oliphaunt_icu_script_sha256)"
     printf 'patch_series_hash=%s\n' "$(patch_series_hash)"
     shasum -a 256 "$0"
     shasum -a 256 "$source_manifest"
@@ -106,11 +106,7 @@ desired_hash() {
 }
 
 apply_patch_series() {
-  local patch_name
-  while IFS= read -r patch_name; do
-    [ -n "$patch_name" ] || continue
-    GIT_CEILING_DIRECTORIES="$work_root" git apply --whitespace=error-all "$patch_dir/$patch_name" >/dev/null
-  done < <(patch_series)
+  bash "$repo_root/src/third-party/postgres/apply-series.sh" "$build_dir" "$patch_series_file"
 }
 
 prepare_source() {
@@ -167,7 +163,6 @@ configure_source() {
 build_icu() {
   oliphaunt_icu_build_target \
     "$icu_source_dir" \
-    "$script_dir" \
     "$icu_native_build_dir" \
     "$icu_build_dir" \
     "$icu_prefix" \
diff --git a/src/runtimes/liboliphaunt-native/bin/common.sh b/src/runtimes/liboliphaunt-native/bin/common.sh
new file mode 100755
index 000000000..c7b699aa1
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/bin/common.sh
@@ -0,0 +1,87 @@
+#!/usr/bin/env sh
+
+oliphaunt_resolve_repo_root() {
+  script_dir="${1:?oliphaunt_resolve_repo_root requires a script directory}"
+  if repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)"; then
+    printf '%s\n' "$repo_root"
+    return 0
+  fi
+  cd "$script_dir/../../../.." && pwd
+}
+
+oliphaunt_native_release_cflags() {
+  printf '%s' '-O2'
+  case "${OLIPHAUNT_NATIVE_DEBUG_SYMBOLS:-0}" in
+    1|true|TRUE|yes|YES|on|ON)
+      printf ' %s' '-g'
+      ;;
+  esac
+  while [ "$#" -gt 0 ]; do
+    printf ' %s' "$1"
+    shift
+  done
+}
+
+# Read the complete diagnostic payload before deciding whether it matches.
+# A producer piped into `grep -q`/`rg -q` can receive SIGPIPE after the matcher
+# exits on its first hit. Under `set -o pipefail`, that turns a successful
+# readiness probe into a false failure. These helpers deliberately consume the
+# complete payload so callers remain deterministic for large symbol tables.
+oliphaunt_text_matches_ere() {
+  [ "$#" -eq 2 ] || {
+    echo "oliphaunt_text_matches_ere requires text and an extended regular expression" >&2
+    return 2
+  }
+  printf '%s\n' "$1" | awk -v oliphaunt_pattern="$2" '
+    $0 ~ oliphaunt_pattern { oliphaunt_found = 1 }
+    END { exit oliphaunt_found ? 0 : 1 }
+  '
+}
+
+oliphaunt_text_has_nm_symbol() {
+  [ "$#" -eq 2 ] || {
+    echo "oliphaunt_text_has_nm_symbol requires nm output and a symbol" >&2
+    return 2
+  }
+  printf '%s\n' "$1" | awk -v oliphaunt_symbol="$2" '
+    $NF == oliphaunt_symbol || $NF == "_" oliphaunt_symbol { oliphaunt_found = 1 }
+    END { exit oliphaunt_found ? 0 : 1 }
+  '
+}
+
+oliphaunt_tail_log_excerpt() {
+  [ "$#" -ge 1 ] && [ "$#" -le 3 ] || {
+    echo "oliphaunt_tail_log_excerpt requires a path and optional line/column limits" >&2
+    return 2
+  }
+  [ -f "$1" ] || return 0
+  tail -n "${2:-40}" "$1" | awk -v oliphaunt_columns="${3:-2000}" '
+    length($0) > oliphaunt_columns {
+      print substr($0, 1, oliphaunt_columns) " ... [line truncated]"
+      next
+    }
+    { print }
+  '
+}
+
+oliphaunt_native_external_extension_source_rel() {
+  [ "$#" -eq 2 ] || {
+    echo "oliphaunt_native_external_extension_source_rel requires a repository root and extension id" >&2
+    return 2
+  }
+  case "$2" in
+    postgis)
+      printf '%s\n' 'target/oliphaunt-sources/checkouts/postgis'
+      ;;
+    *)
+      awk -F '\t' -v extension="$2" '
+        NR > 1 && ($1 == extension || $3 == "target/oliphaunt-sources/checkouts/" extension) {
+          print $3
+          found = 1
+          exit
+        }
+        END { exit found ? 0 : 1 }
+      ' "$1/src/extensions/generated/pgxs-build.tsv"
+      ;;
+  esac
+}
diff --git a/src/runtimes/liboliphaunt-native/bin/extension-source.test.sh b/src/runtimes/liboliphaunt-native/bin/extension-source.test.sh
new file mode 100644
index 000000000..29468469c
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/bin/extension-source.test.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+set -euo pipefail
+. "$(dirname "${BASH_SOURCE[0]}")/common.sh"
+fixture="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-extension-source.XXXXXX")"
+trap 'rm -rf "$fixture"' EXIT
+mkdir -p "$fixture/src/extensions/generated"
+printf 'name\tmodule\tsource\nfixture_sql\tfixture_module\ttarget/oliphaunt-sources/checkouts/fixture_upstream\n' > "$fixture/src/extensions/generated/pgxs-build.tsv"
+# Both SQL identity and upstream alias locate the same checkout from another cwd.
+cd "$fixture"
+sql="$(oliphaunt_native_external_extension_source_rel "$fixture" fixture_sql)"
+alias="$(oliphaunt_native_external_extension_source_rel "$fixture" fixture_upstream)"
+test -n "$sql"
+test "$sql" = "$alias"
+if oliphaunt_native_external_extension_source_rel "$fixture" missing > "$fixture/result"; then exit 1; fi
+test ! -s "$fixture/result"
+printf 'Extension source lookup checks passed\n'
diff --git a/src/runtimes/liboliphaunt/native/bin/fetch-pinned-git-checkout.sh b/src/runtimes/liboliphaunt-native/bin/fetch-pinned-git-checkout.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/native/bin/fetch-pinned-git-checkout.sh
rename to src/runtimes/liboliphaunt-native/bin/fetch-pinned-git-checkout.sh
diff --git a/src/runtimes/liboliphaunt/native/bin/fetch-pinned-git-checkout.test.sh b/src/runtimes/liboliphaunt-native/bin/fetch-pinned-git-checkout.test.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/native/bin/fetch-pinned-git-checkout.test.sh
rename to src/runtimes/liboliphaunt-native/bin/fetch-pinned-git-checkout.test.sh
diff --git a/src/runtimes/liboliphaunt/native/bin/mobile-postgis-extensions.sh b/src/runtimes/liboliphaunt-native/bin/mobile-postgis-extensions.sh
similarity index 99%
rename from src/runtimes/liboliphaunt/native/bin/mobile-postgis-extensions.sh
rename to src/runtimes/liboliphaunt-native/bin/mobile-postgis-extensions.sh
index 492aa6461..89ae449b2 100644
--- a/src/runtimes/liboliphaunt/native/bin/mobile-postgis-extensions.sh
+++ b/src/runtimes/liboliphaunt-native/bin/mobile-postgis-extensions.sh
@@ -312,10 +312,10 @@ build_postgis_libiconv_dependency() {
   fi
   if [ ! -f "$source_dir/configure" ] || [ ! -f "$source_dir/.oliphaunt-source-pin" ]; then
     oliphaunt_postgis_fail \
-      "pinned libiconv source checkout is missing; run tools/dev/bun.sh src/sources/tools/fetch-sources.mjs native-runtime --force"
+      "pinned libiconv source checkout is missing; run bash src/third-party/tools/fetch-sources.sh extensions --force"
   fi
-  "$repo_root/tools/dev/bun.sh" \
-    "$repo_root/src/sources/tools/fetch-sources.mjs" extensions --verify-only >/dev/null
+  bash \
+    "$repo_root/src/third-party/tools/fetch-sources.sh" extensions --verify-only >/dev/null
   rm -rf "$build_root" "$dependency_dir"
   mkdir -p "$build_root" "$dependency_dir"
   rsync -a --delete --exclude .git "$source_dir/" "$build_root/"
diff --git a/src/runtimes/liboliphaunt/native/bin/mobile-static-extensions.sh b/src/runtimes/liboliphaunt-native/bin/mobile-static-extensions.sh
similarity index 98%
rename from src/runtimes/liboliphaunt/native/bin/mobile-static-extensions.sh
rename to src/runtimes/liboliphaunt-native/bin/mobile-static-extensions.sh
index c709a1685..a8ab848d9 100644
--- a/src/runtimes/liboliphaunt/native/bin/mobile-static-extensions.sh
+++ b/src/runtimes/liboliphaunt-native/bin/mobile-static-extensions.sh
@@ -7,7 +7,7 @@ oliphaunt_mobile_static_specs_tsv() {
   fi
   local script_dir
   script_dir="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
-  printf '%s\n' "$script_dir/../../../../../src/extensions/generated/mobile/static-extensions.tsv"
+  printf '%s\n' "$script_dir/../../../extensions/generated/mobile/static-extensions.tsv"
 }
 
 oliphaunt_mobile_static_extension_spec() {
@@ -50,9 +50,9 @@ oliphaunt_native_component_contract_field() {
   local field="${5:?missing component closure field}"
   local script_dir repo_root
   script_dir="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
-  repo_root="$(CDPATH= cd -- "$script_dir/../../../../.." && pwd)"
+  repo_root="$(CDPATH= cd -- "$script_dir/../../../.." && pwd)"
   "$repo_root/tools/dev/bun.sh" \
-    "$repo_root/src/extensions/tools/native-component-contract.mjs" \
+    "$repo_root/src/extensions/tools/native-component-contract.mts" \
     field "$extension" "$family" "$kind" "$target" "$field"
 }
 
@@ -132,13 +132,13 @@ oliphaunt_mobile_static_dependency_archive_candidates() {
   local dependency="${2:?missing mobile static dependency name}"
   local script_dir repo_root candidate
   script_dir="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
-  repo_root="$(CDPATH= cd -- "$script_dir/../../../../.." && pwd)"
+  repo_root="$(CDPATH= cd -- "$script_dir/../../../.." && pwd)"
   while IFS= read -r candidate; do
     [ -n "$candidate" ] || continue
     printf '%s/%s\n' "$dependency_root" "$candidate"
   done < <(
     "$repo_root/tools/dev/bun.sh" \
-      "$repo_root/src/extensions/tools/native-component-contract.mjs" \
+      "$repo_root/src/extensions/tools/native-component-contract.mts" \
       archive-candidates "$dependency"
   )
 }
diff --git a/src/runtimes/liboliphaunt/native/bin/postgis-dependency-cache.sh b/src/runtimes/liboliphaunt-native/bin/postgis-dependency-cache.sh
similarity index 89%
rename from src/runtimes/liboliphaunt/native/bin/postgis-dependency-cache.sh
rename to src/runtimes/liboliphaunt-native/bin/postgis-dependency-cache.sh
index 933a49231..14c072ba9 100644
--- a/src/runtimes/liboliphaunt/native/bin/postgis-dependency-cache.sh
+++ b/src/runtimes/liboliphaunt-native/bin/postgis-dependency-cache.sh
@@ -66,21 +66,17 @@ oliphaunt_postgis_dependency_cache_prepare() {
   local dependency_root="$1"
   local fingerprint="$2"
   shift 2
-  local stamp="$dependency_root/.oliphaunt-postgis-native-dependencies.sha256"
 
   oliphaunt_postgis_dependency_cache_validate_inputs \
     "$dependency_root" \
     "$fingerprint" \
     "$@" || return
 
-  if ! oliphaunt_postgis_dependency_cache_is_complete "$dependency_root" "$fingerprint"; then
-    rm -rf -- "$dependency_root" "$@"
+  if oliphaunt_postgis_dependency_cache_is_complete "$dependency_root" "$fingerprint"; then
+    return 0
   fi
+  rm -rf -- "$dependency_root" "$@"
   mkdir -p "$dependency_root"
-  # A completion stamp is a lease for exactly one verified reuse attempt. Drop
-  # it before builders inspect the cache so an interrupted repair/reuse cannot
-  # be mistaken for a committed cache by the next process.
-  rm -f -- "$stamp"
 }
 
 oliphaunt_postgis_dependency_cache_commit() {
diff --git a/src/runtimes/liboliphaunt-native/bin/postgis-dependency-cache.test.sh b/src/runtimes/liboliphaunt-native/bin/postgis-dependency-cache.test.sh
new file mode 100644
index 000000000..fa5df5507
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/bin/postgis-dependency-cache.test.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+set -euo pipefail
+. "$(dirname "${BASH_SOURCE[0]}")/postgis-dependency-cache.sh"
+fixture="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-postgis-cache.XXXXXX")"
+trap 'rm -rf "$fixture"' EXIT
+deps="$fixture/dependencies"
+build="$fixture/build"
+fingerprint="$(printf 'a%.0s' {1..64})"
+new_fingerprint="$(printf 'b%.0s' {1..64})"
+archive="$deps/archive.a"
+
+populate() {
+  mkdir -p "$deps" "$build"
+  printf library > "$archive"
+  printf object > "$build/object.o"
+}
+
+# Reusing a complete cache does not revoke it. A caller interrupted after
+# preparation must leave the same verified libraries available to the next run.
+populate
+oliphaunt_postgis_dependency_cache_commit "$deps" "$fingerprint" "$archive"
+oliphaunt_postgis_dependency_cache_prepare "$deps" "$fingerprint" "$build"
+test "$(cat "$archive")" = library
+test "$(cat "$build/object.o")" = object
+oliphaunt_postgis_dependency_cache_prepare "$deps" "$fingerprint" "$build"
+test "$(cat "$archive")" = library
+test "$(cat "$build/object.o")" = object
+oliphaunt_postgis_dependency_cache_is_complete "$deps" "$fingerprint"
+
+# Toolchain changes and changed output bytes both invalidate installed and build trees.
+for change in fingerprint bytes; do
+  populate
+  oliphaunt_postgis_dependency_cache_commit "$deps" "$fingerprint" "$archive"
+  wanted="$fingerprint"
+  if [ "$change" = fingerprint ]; then wanted="$new_fingerprint"; else printf corrupt > "$archive"; fi
+  oliphaunt_postgis_dependency_cache_prepare "$deps" "$wanted" "$build"
+  test ! -e "$archive"
+  test ! -e "$build"
+done
+
+# Empty outputs cannot commit a repair; an interrupted repair cannot be reused.
+populate
+: > "$archive"
+if oliphaunt_postgis_dependency_cache_commit "$deps" "$fingerprint" "$archive"; then exit 1; fi
+printf partial > "$archive"
+oliphaunt_postgis_dependency_cache_prepare "$deps" "$fingerprint" "$build"
+test ! -e "$archive"
+
+# Invalid inputs must fail without deleting existing output.
+populate
+if oliphaunt_postgis_dependency_cache_prepare "$deps" invalid "$build"; then exit 1; fi
+if oliphaunt_postgis_dependency_cache_prepare / "$fingerprint" "$build"; then exit 1; fi
+test "$(cat "$archive")" = library
+test "$(cat "$build/object.o")" = object
+printf 'PostGIS dependency cache checks passed\n'
diff --git a/src/runtimes/liboliphaunt/native/bin/postgis-reproducible-time.test.sh b/src/runtimes/liboliphaunt-native/bin/postgis-reproducible-time.test.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/native/bin/postgis-reproducible-time.test.sh
rename to src/runtimes/liboliphaunt-native/bin/postgis-reproducible-time.test.sh
diff --git a/src/runtimes/liboliphaunt/native/bin/postgres-backend-objects.mk b/src/runtimes/liboliphaunt-native/bin/postgres-backend-objects.mk
similarity index 100%
rename from src/runtimes/liboliphaunt/native/bin/postgres-backend-objects.mk
rename to src/runtimes/liboliphaunt-native/bin/postgres-backend-objects.mk
diff --git a/src/runtimes/liboliphaunt-native/bin/smoke-host-happy-path.sh b/src/runtimes/liboliphaunt-native/bin/smoke-host-happy-path.sh
new file mode 100755
index 000000000..602afd722
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/bin/smoke-host-happy-path.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env sh
+set -eu
+
+script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
+. "$script_dir/common.sh"
+repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
+cd "$repo_root"
+
+if [ "${1:-}" != "" ]; then
+  bash src/runtimes/liboliphaunt-native/tools/run-host-c-smoke.sh --smoke-only --root "$1"
+else
+  bash src/runtimes/liboliphaunt-native/tools/run-host-c-smoke.sh --smoke-only
+fi
diff --git a/src/runtimes/liboliphaunt-native/include/oliphaunt.h b/src/runtimes/liboliphaunt-native/include/oliphaunt.h
new file mode 100644
index 000000000..60d077564
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/include/oliphaunt.h
@@ -0,0 +1,283 @@
+#ifndef OLIPHAUNT_H
+#define OLIPHAUNT_H
+
+#include 
+#include 
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OLIPHAUNT_ABI_VERSION 11u
+#define OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION 1u
+#define OLIPHAUNT_ERROR_CAPTURE_CAPACITY 1024u
+#define OLIPHAUNT_STREAM_CALLBACK_ABORTED 1
+#define OLIPHAUNT_STREAM_INPUT_BUSY 1
+#define OLIPHAUNT_STREAM_INPUT_MAX_BYTES (128u * 1024u * 1024u)
+/* The caller already owns liboliphaunt's stable sibling root lease. */
+#define OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK (1ull << 0)
+
+#if defined(_WIN32) && defined(OLIPHAUNT_BUILDING_DLL)
+#define OLIPHAUNT_API __declspec(dllexport)
+#elif defined(_WIN32)
+#define OLIPHAUNT_API __declspec(dllimport)
+#else
+#define OLIPHAUNT_API
+#endif
+
+typedef struct OliphauntHandle OliphauntHandle;
+
+typedef struct OliphauntStaticExtensionSymbol {
+    const char *name;
+    void *address;
+} OliphauntStaticExtensionSymbol;
+
+typedef struct OliphauntStaticExtension {
+    uint32_t abi_version;
+    const char *name;
+    const void *(*magic)(void);
+    void (*init)(void);
+    const OliphauntStaticExtensionSymbol *symbols;
+    size_t symbol_count;
+    uint64_t reserved_flags;
+} OliphauntStaticExtension;
+
+/*
+ * Direct-mode extension compatibility contract:
+ *
+ * oliphaunt_init sets the process PGDATA environment variable to this config's
+ * pgdata path while the embedded backend is active, because PostgreSQL
+ * extensions may read PGDATA through standard process APIs. oliphaunt_detach
+ * releases a logical direct-mode lease but keeps the resident backend alive;
+ * oliphaunt_close is terminal for the process lifetime and restores the caller's
+ * previous PGDATA value, or unsets it if it was unset.
+ *
+ * Every successful oliphaunt_init establishes a current
+ * logical lease generation. Hosts with independent cleanup owners must capture
+ * its non-zero value immediately with oliphaunt_logical_generation and use
+ * oliphaunt_close_if_generation: a stale owner then cannot terminate a newer
+ * logical lease on the same resident handle.
+ *
+ * Callers that require process environment isolation should use src/broker/server
+ * mode through the Rust SDK instead of keeping multiple direct-mode backends in
+ * one process.
+ */
+typedef struct OliphauntConfig {
+    uint32_t abi_version;
+    /* The pgdata child of an already-prepared managed root. Init does not create it. */
+    const char *pgdata;
+    const char *runtime_dir;
+    /*
+     * Exact PostgreSQL $libdir for the embedded handle. It must name an
+     * existing directory. Pass NULL to use OLIPHAUNT_EMBEDDED_MODULE_DIR and
+     * release-layout discovery.
+     */
+    const char *module_dir;
+    const char *username;
+    const char *database;
+    /* OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK or zero. */
+    uint64_t flags;
+    /* Zero or more `-c`, `name=value` pairs. Storage-routing GUCs are rejected. */
+    const char *const *startup_args;
+    size_t startup_arg_count;
+    /* Optional existing ICU data directory. NULL preserves runtime/env discovery. */
+    const char *icu_data_dir;
+} OliphauntConfig;
+
+typedef struct OliphauntResponse {
+    uint8_t *data;
+    size_t len;
+} OliphauntResponse;
+
+/*
+ * Operation-owned error storage for hosts whose FFI scheduler resumes the
+ * caller on a different thread. The `_with_error` entry points below execute
+ * the operation and capture its thread-local failure before that native
+ * invocation returns. `length` excludes the trailing NUL and is at most
+ * OLIPHAUNT_ERROR_CAPTURE_CAPACITY - 1; `message` is always NUL-terminated
+ * and is empty on success. The entire capture is zeroed on success. Native
+ * error sources use the same bound, so a valid runtime error is not
+ * additionally truncated during capture.
+ */
+typedef struct OliphauntErrorCapture {
+    uint32_t length;
+    char message[OLIPHAUNT_ERROR_CAPTURE_CAPACITY];
+} OliphauntErrorCapture;
+
+typedef struct OliphauntRestoreOptions {
+    uint32_t abi_version;
+    /* New or existing-empty managed-root path; this is not a PGDATA path. */
+    const char *destination;
+    /* Bytes in the single native physical archive format returned by oliphaunt_backup. */
+    const uint8_t *data;
+    size_t len;
+} OliphauntRestoreOptions;
+
+/*
+ * Same-handle ownership and streaming contract:
+ *
+ * Hosts serialize ordinary operations on one logical handle. Cancellation and
+ * token-bound stream input are the deliberate cross-thread exceptions.
+ * oliphaunt_cancel may interrupt the active PostgreSQL operation. A successful
+ * detach ends that logical lease; a successful close invalidates the handle, which
+ * must never be dereferenced again.
+ *
+ * A raw-stream callback borrows data only for that callback invocation. It may
+ * copy bytes, inspect errors, cancel, or feed its stream token. It must not call
+ * query, backup, detach, close, or another raw-stream operation on the same
+ * handle. Those calls fail with a busy error while streaming is active,
+ * including from another thread, so the callback cannot corrupt protocol
+ * ordering or free its own handle. A non-zero callback result stops later
+ * callback delivery and drains the backend to ReadyForQuery. The stream then
+ * returns OLIPHAUNT_STREAM_CALLBACK_ABORTED; negative results identify
+ * validation, transport, backend, or recovery failures for which reuse may be
+ * unsafe.
+ */
+typedef int32_t (*OliphauntStreamCallback)(void *context, const uint8_t *data, size_t len);
+
+/*
+ * Incremental extended-query or COPY input for an active raw stream. The token is zero
+ * unless the stream can accept more input; a nonzero token identifies exactly
+ * one stream, including across detach/reopen. Capture it for that stream only.
+ * Feed may run on another thread or from its output callback. It copies complete
+ * frontend frames, up to INPUT_MAX_BYTES per call, without blocking. BUSY means
+ * no bytes were accepted: retry after the backend consumes its current input.
+ * Sync (or simple Query) must be the final frame and closes further input for
+ * this stream. Output continues through the existing callback to ReadyForQuery.
+ * A backend CopyInResponse temporarily permits CopyData and a final CopyDone
+ * or CopyFail even after Query/Sync closed ordinary input. Other frontend
+ * commands remain excluded until that stream reaches ReadyForQuery.
+ * Terminate also closes input, ends the backend and fails the stream instead
+ * of producing ReadyForQuery; terminal close then releases the owned handle.
+ * Stop the producer when its stream finishes; stale tokens return an error.
+ * Error capture is optional. Existing query/backup/detach/close exclusions remain.
+ */
+OLIPHAUNT_API uint64_t oliphaunt_protocol_stream_token(OliphauntHandle *handle);
+OLIPHAUNT_API int32_t oliphaunt_feed_protocol_stream(
+    OliphauntHandle *handle, uint64_t token, const uint8_t *request,
+    size_t request_len, OliphauntErrorCapture *error);
+
+OLIPHAUNT_API int32_t oliphaunt_init(const OliphauntConfig *config, OliphauntHandle **out);
+OLIPHAUNT_API int32_t oliphaunt_exec_protocol(
+    OliphauntHandle *handle,
+    const uint8_t *request,
+    size_t request_len,
+    OliphauntResponse *out);
+OLIPHAUNT_API int32_t oliphaunt_exec_simple_query(
+    OliphauntHandle *handle,
+    const char *sql,
+    size_t sql_len,
+    OliphauntResponse *out);
+OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream(
+    OliphauntHandle *handle,
+    const uint8_t *request,
+    size_t request_len,
+    OliphauntStreamCallback callback,
+    void *callback_context);
+/*
+ * Creates a session-preserving online physical archive. If an error says that
+ * backup-mode exit is unconfirmed, no later query is safe: detach/close the
+ * handle and restart the process before reopening PostgreSQL.
+ */
+OLIPHAUNT_API int32_t oliphaunt_backup(
+    OliphauntHandle *handle,
+    OliphauntResponse *out);
+OLIPHAUNT_API int32_t oliphaunt_restore(const OliphauntRestoreOptions *options);
+/*
+ * Scheduler-safe variants for asynchronous FFI hosts. These preserve the
+ * return code and response ownership of their corresponding operation while
+ * filling a required caller-owned capture before returning.
+ */
+OLIPHAUNT_API int32_t oliphaunt_init_with_error(
+    const OliphauntConfig *config,
+    OliphauntHandle **out,
+    OliphauntErrorCapture *error);
+OLIPHAUNT_API int32_t oliphaunt_exec_protocol_with_error(
+    OliphauntHandle *handle,
+    const uint8_t *request,
+    size_t request_len,
+    OliphauntResponse *out,
+    OliphauntErrorCapture *error);
+OLIPHAUNT_API int32_t oliphaunt_exec_simple_query_with_error(
+    OliphauntHandle *handle,
+    const char *sql,
+    size_t sql_len,
+    OliphauntResponse *out,
+    OliphauntErrorCapture *error);
+OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream_with_error(
+    OliphauntHandle *handle,
+    const uint8_t *request,
+    size_t request_len,
+    OliphauntStreamCallback callback,
+    void *callback_context,
+    OliphauntErrorCapture *error);
+OLIPHAUNT_API int32_t oliphaunt_backup_with_error(
+    OliphauntHandle *handle,
+    OliphauntResponse *out,
+    OliphauntErrorCapture *error);
+OLIPHAUNT_API int32_t oliphaunt_restore_with_error(
+    const OliphauntRestoreOptions *options,
+    OliphauntErrorCapture *error);
+OLIPHAUNT_API int32_t oliphaunt_detach_with_error(
+    OliphauntHandle *handle,
+    OliphauntErrorCapture *error);
+OLIPHAUNT_API int32_t oliphaunt_cancel(OliphauntHandle *handle);
+/* A poisoned backup session is terminally closed instead of retained. */
+OLIPHAUNT_API int32_t oliphaunt_detach(OliphauntHandle *handle);
+/*
+ * Returns the non-zero generation of the currently published logical lease.
+ * Returns zero for NULL, stale, terminally closed, or otherwise non-current
+ * handles. The registry is validated before the opaque handle is dereferenced.
+ */
+OLIPHAUNT_API uint64_t oliphaunt_logical_generation(OliphauntHandle *handle);
+/*
+ * Terminally closes the process-wide resident handle only when generation
+ * still owns its current logical lease. Returns 0 when terminal close completes
+ * or had already completed, 1 for an active stale/non-owner generation no-op,
+ * and -1 for generation zero or an internal failure.
+ */
+OLIPHAUNT_API int32_t oliphaunt_close_if_generation(
+    uint64_t generation);
+/*
+ * Unconditionally performs process-terminal close for the current published
+ * resident handle. Hosts with multiple cleanup owners should use
+ * oliphaunt_close_if_generation and retain only its generation token.
+ */
+OLIPHAUNT_API int32_t oliphaunt_close(OliphauntHandle *handle);
+/*
+ * Registers statically linked PostgreSQL extension modules for the embedded
+ * backend's normal LOAD path.
+ *
+ * Call this before oliphaunt_init in processes that link extension code directly
+ * into the application or SDK library. The registry is process-wide and becomes
+ * immutable once backend startup begins. Each extension name is the module stem
+ * used by SQL, for example AS 'vector', and each symbol row exposes the C
+ * symbols PostgreSQL would otherwise resolve with dlsym().
+ */
+OLIPHAUNT_API int32_t oliphaunt_register_static_extensions(const OliphauntStaticExtension *extensions, size_t count);
+/*
+ * Copies an error into caller-owned storage. Immediately after a fallible C
+ * operation returns failure, calls on that same thread read the operation's
+ * owned snapshot. It takes precedence over the shared handle/global error and
+ * remains stable across a size probe and repeated copies until the thread
+ * begins another fallible C operation, even if another thread updates the
+ * shared error. With no operation snapshot, this atomically reads the latest
+ * handle error, or the process-global error when handle is NULL.
+ *
+ * The return value is the full UTF-8 byte length excluding the trailing NUL.
+ * When capacity is non-zero, out must be non-NULL and is always
+ * NUL-terminated; content is truncated when capacity is smaller than length +
+ * 1.
+ */
+OLIPHAUNT_API size_t oliphaunt_copy_last_error(
+    OliphauntHandle *handle,
+    char *out,
+    size_t capacity);
+OLIPHAUNT_API const char *oliphaunt_version(void);
+OLIPHAUNT_API void oliphaunt_free_response(OliphauntResponse *response);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/runtimes/liboliphaunt-native/moon.yml b/src/runtimes/liboliphaunt-native/moon.yml
new file mode 100644
index 000000000..3af91d92d
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/moon.yml
@@ -0,0 +1,620 @@
+$schema: https://moonrepo.dev/schemas/project.json
+id: liboliphaunt-native
+language: c
+layer: library
+stack: systems
+tags:
+  - javascript-quality
+  - native
+  - postgres
+  - c-abi
+  - pg18
+  - release-product
+dependsOn:
+  - id: extensions
+    scope: build
+  - id: shared-test-fixtures
+    scope: development
+  - id: postgres18
+    scope: build
+  - id: third-party-icu
+    scope: build
+  - id: third-party-openssl
+    scope: build
+  - id: extension-runtime-contract
+    scope: build
+  - id: oliphaunt-extension-contrib-pg18
+    scope: build
+project:
+  title: liboliphaunt Native
+  description: C ABI and PostgreSQL 18 patch stack for native embedded Oliphaunt.
+  owner: oliphaunt
+  release:
+    component: liboliphaunt-native
+    packagePath: src/runtimes/liboliphaunt-native
+    artifactTargets:
+      preset: liboliphaunt-native
+      targets:
+        - android-arm64-v8a
+        - android-x86_64
+        - ios-xcframework
+        - linux-arm64-gnu
+        - linux-x64-gnu
+        - macos-arm64
+        - windows-x64-msvc
+owners:
+  defaultOwner: "@oliphaunt/core"
+  paths:
+    "**/*":
+      - "@oliphaunt/core"
+fileGroups:
+  runtime:
+    - bin/**/*
+    - include/**/*
+    - src/**/*
+    - patches/**/*
+    - postgres/**/*
+    - /src/third-party/postgres/**/*
+    - "!/src/third-party/postgres/**/*.test.*"
+    - "!/src/third-party/postgres/testdata/**/*"
+    - portable-uuid/**/*
+    - postgres18/**/*
+    - "tools/build-*.{mts,sh}"
+    - tools/release-runtime.sh
+    - /src/extensions/artifacts/native/tools/build-windows-extensions.sh
+    - /src/extensions/artifacts/native/tools/windows-extension-sources.mts
+    - /src/extensions/external/postgis/tools/windows/**/*
+    - VERSION
+    - "!**/*.md"
+    - "!moon.yml"
+    - "!bin/**/*.test.sh"
+    - "!tools/**/*.test.sh"
+tasks:
+  build-orchestration-test:
+    tags:
+      - quality
+      - unit
+    script: "set -e\nbash src/runtimes/liboliphaunt-native/bin/build-output.test.sh\nbash src/runtimes/liboliphaunt-native/tools/build-dispatch.test.sh\nbash src/runtimes/liboliphaunt-native/bin/postgis-dependency-cache.test.sh\n"
+    inputs:
+      - bin/build-output.bash
+      - bin/build-output.test.sh
+      - bin/postgis-dependency-cache.sh
+      - bin/postgis-dependency-cache.test.sh
+      - tools/build-dispatch.test.sh
+      - tools/build-ci-target.sh
+      - tools/release-runtime.sh
+      - tools/runtime-preflight.sh
+      - /src/third-party/postgres/source.toml
+      - /src/extensions/artifacts/native/tools/run-observed-phase.sh
+    options:
+      runFromWorkspaceRoot: true
+  lint:
+    tags:
+      - quality
+      - static
+    script: "set -e\nwhile IFS= read -r -d '' script; do bash -n \"$script\"; done < <(find src/runtimes/liboliphaunt-native -type f \\( -name '*.sh' -o -name '*.bash' \\) -print0)\n"
+    inputs:
+      - "**/*.sh"
+      - "**/*.bash"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  test:
+    tags:
+      - quality
+      - unit
+    command: "true"
+    deps:
+      - liboliphaunt-native:build-orchestration-test
+      - liboliphaunt-native:external-source-fetch-test
+      - liboliphaunt-native:error-attribution-test
+      - liboliphaunt-native:generation-lifecycle-test
+      - liboliphaunt-native:ios-extension-packager-test
+      - liboliphaunt-native:module-dir-resolver-test
+      - liboliphaunt-native:postgis-reproducible-time-test
+      - liboliphaunt-native:static-extension-registry-test
+      - liboliphaunt-native:symbol-scope-test
+    inputs:
+      []
+  external-source-fetch-test:
+    script: "set -e\nbash src/runtimes/liboliphaunt-native/bin/fetch-pinned-git-checkout.test.sh\nbash src/runtimes/liboliphaunt-native/bin/extension-source.test.sh\n"
+    inputs:
+      - bin/common.sh
+      - bin/extension-source.test.sh
+      - /src/runtimes/liboliphaunt-native/bin/fetch-pinned-git-checkout.sh
+      - /src/runtimes/liboliphaunt-native/bin/fetch-pinned-git-checkout.test.sh
+    options:
+      cache: true
+      internal: true
+      runFromWorkspaceRoot: true
+  error-attribution-test:
+    command: bash src/runtimes/liboliphaunt-native/tools/test-error-attribution.sh
+    inputs:
+      - /src/runtimes/liboliphaunt-native/include/oliphaunt.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_error.c
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_platform.h
+      - /src/runtimes/liboliphaunt-native/smoke/liboliphaunt_error_attribution.c
+      - /src/runtimes/liboliphaunt-native/tools/test-error-attribution.sh
+    options:
+      cache: true
+      internal: true
+      runFromWorkspaceRoot: true
+  generation-lifecycle-test:
+    command: bash src/runtimes/liboliphaunt-native/tools/test-generation-lifecycle.sh
+    inputs:
+      - /src/runtimes/liboliphaunt-native/include/oliphaunt.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_platform.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_backup_state.c
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c
+      - /src/runtimes/liboliphaunt-native/smoke/liboliphaunt_generation_lifecycle.c
+      - /src/runtimes/liboliphaunt-native/tools/test-generation-lifecycle.sh
+    options:
+      cache: true
+      internal: true
+      runFromWorkspaceRoot: true
+  ios-extension-packager-test:
+    command: bash src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.test.sh
+    inputs:
+      - /src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.sh
+      - /src/runtimes/liboliphaunt-native/bin/build-ios-extension-xcframeworks.test.sh
+      - /src/runtimes/liboliphaunt-native/bin/common.sh
+      - /src/runtimes/liboliphaunt-native/bin/mobile-static-extensions.sh
+      - /src/runtimes/liboliphaunt-native/include/oliphaunt.h
+    options:
+      cache: true
+      internal: true
+      runFromWorkspaceRoot: true
+  postgis-reproducible-time-test:
+    script: "set -e\nbash src/runtimes/liboliphaunt-native/bin/postgis-reproducible-time.test.sh\n"
+    inputs:
+      - /src/extensions/external/postgis/source.toml
+      - /src/extensions/external/postgis/tools/build_wasix.sh
+      - /src/extensions/external/postgis/tools/reproducible-bin/date
+      - /src/extensions/external/postgis/tools/reproducible-time.sh
+      - /src/runtimes/liboliphaunt-native/bin/build-macos-extension-archives.sh
+      - /src/runtimes/liboliphaunt-native/bin/build-postgres18-android-arm64.sh
+      - /src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-device.sh
+      - /src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-simulator.sh
+      - /src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh
+      - /src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh
+      - /src/extensions/artifacts/native/tools/build-windows-extensions.sh
+      - /src/extensions/artifacts/native/tools/windows-extension-sources.mts
+      - /src/extensions/external/postgis/tools/windows/**/*
+      - /src/runtimes/liboliphaunt-native/bin/mobile-postgis-extensions.sh
+      - /src/runtimes/liboliphaunt-native/bin/postgis-reproducible-time.test.sh
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_checks.rs
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_manifest.rs
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_pipeline.rs
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/src/source_spine.rs
+    options:
+      cache: true
+      internal: true
+      runFromWorkspaceRoot: true
+  module-dir-resolver-test:
+    command: bash src/runtimes/liboliphaunt-native/tools/test-module-dir-resolver.sh
+    inputs:
+      - /src/runtimes/liboliphaunt-native/include/oliphaunt.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_fs.c
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_platform.h
+      - /src/runtimes/liboliphaunt-native/smoke/liboliphaunt_module_dir_resolver.c
+      - /src/runtimes/liboliphaunt-native/tools/test-module-dir-resolver.sh
+    options:
+      cache: true
+      internal: true
+      runFromWorkspaceRoot: true
+  static-extension-registry-test:
+    command: bash src/runtimes/liboliphaunt-native/tools/test-static-extension-registry.sh
+    inputs:
+      - /src/runtimes/liboliphaunt-native/include/oliphaunt.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_platform.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_static_extensions.c
+      - /src/runtimes/liboliphaunt-native/smoke/liboliphaunt_static_extension_registry.c
+      - /src/runtimes/liboliphaunt-native/tools/test-static-extension-registry.sh
+    options:
+      cache: true
+      internal: true
+      runFromWorkspaceRoot: true
+  symbol-scope-test:
+    script: "set -e\nbash src/runtimes/liboliphaunt-native/tools/test-symbol-scope.sh\nbash src/runtimes/liboliphaunt-native/tools/native-readiness-probes.test.sh\n"
+    inputs:
+      - /src/runtimes/liboliphaunt-native/tools/native-readiness-probes.test.sh
+      - /src/runtimes/liboliphaunt-native/bin/common.sh
+      - /src/runtimes/liboliphaunt-native/bin/mobile-static-extensions.sh
+      - /src/runtimes/liboliphaunt-native/include/oliphaunt.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_platform.h
+      - /src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c
+      - /src/runtimes/liboliphaunt-native/smoke/liboliphaunt_symbol_scope_consumer.c
+      - /src/runtimes/liboliphaunt-native/smoke/liboliphaunt_symbol_scope_host.c
+      - /src/runtimes/liboliphaunt-native/smoke/liboliphaunt_symbol_scope_provider.c
+      - /src/runtimes/liboliphaunt-native/tools/audit-macos-module-nm.awk
+      - /src/runtimes/liboliphaunt-native/tools/audit-macos-provider-collisions.awk
+      - /src/runtimes/liboliphaunt-native/tools/test-symbol-scope.sh
+    options:
+      cache: true
+      internal: true
+      runFromWorkspaceRoot: true
+  test-integration:
+    tags:
+      - runtime
+      - smoke
+    script: "set -e\n. src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh\noliphaunt_runtime_native_host_require basic\nbash src/runtimes/liboliphaunt-native/tools/run-host-c-smoke.sh\n"
+    deps:
+      - liboliphaunt-native:build-runtime-desktop-target
+    inputs:
+      - "**/*"
+      - project: postgres18
+        group: source
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - project: extension-runtime-contract
+        group: contract
+      - project: shared-test-fixtures
+        group: fixtures
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: skip
+  build-runtime-desktop-target:
+    tags:
+      - runtime
+      - build
+    deps:
+      - source-inputs:source-fetch-native-runtime
+    command: bash src/runtimes/liboliphaunt-native/tools/release-runtime.sh build
+    inputs:
+      - $OLIPHAUNT_CI_TARGET
+      - project: postgres18
+        group: source
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - project: extension-runtime-contract
+        group: contract
+      - "@group(runtime)"
+      - /src/extensions/tools/native-extension-files.mts
+      - /src/extensions/generated/sdk/extensions.json
+    outputs:
+      - /target/liboliphaunt-pg18/**/*
+      - /target/liboliphaunt-pg18-linux-*/**/*
+      - /target/liboliphaunt-pg18-windows-*/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  package-runtime-desktop-target:
+    tags:
+      - runtime
+      - release
+      - artifact-package
+      - ci-liboliphaunt-native-desktop
+    command: bash src/runtimes/liboliphaunt-native/tools/release-runtime.sh package
+    deps:
+      - liboliphaunt-native:build-runtime-desktop-target
+    inputs:
+      - $OLIPHAUNT_CI_TARGET
+      - "@group(legal-files)"
+      - /src/runtimes/liboliphaunt-native/include/**/*
+      - /src/runtimes/liboliphaunt-native/tools/release-runtime.sh
+      - /src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+      - /src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-linux-assets.sh
+      - /src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-macos-assets.sh
+      - /src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-windows-assets.sh
+      - /src/extensions/tools/native-extension-files.mts
+      - /src/extensions/generated/sdk/extensions.json
+      - /src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
+      - /tools/packaging/release-notices.mts
+      - /tools/packaging/strip-native-binaries.sh
+      - /tools/packaging/platform-binary-contract.mts
+      - "/tools/packaging/*.{mjs,mts}"
+    outputs:
+      - /target/liboliphaunt/desktop-release-assets/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  test-artifacts-desktop-target:
+    tags:
+      - runtime
+      - integration
+      - ci-liboliphaunt-native-desktop
+    command: bash src/runtimes/liboliphaunt-native/tools/test-desktop-artifact.sh
+    deps:
+      - liboliphaunt-native:package-runtime-desktop-target
+    inputs:
+      - $OLIPHAUNT_CI_TARGET
+      - tools/test-desktop-artifact.sh
+      - tools/run-host-c-smoke.sh
+      - tools/native-smoke-data.mts
+      - smoke/**/*
+      - include/**/*
+      - src/**/*.h
+      - /src/runtimes/liboliphaunt-native/smoke/fixtures/physical-archive-native-v1.properties
+      - /tools/packaging/check-linux-consumer-baseline.sh
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  build-runtime-android-arm64-v8a:
+    tags:
+      - runtime
+      - build
+      - ci-liboliphaunt-native-android
+    deps:
+      - source-inputs:source-fetch-native-runtime
+    command: bash src/runtimes/liboliphaunt-native/tools/build-ci-target.sh android-arm64-v8a
+    inputs:
+      - "@group(legal-files)"
+      - project: postgres18
+        group: source
+      - "@group(upstream-licenses)"
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - project: extension-runtime-contract
+        group: contract
+      - "@group(runtime)"
+      - /src/runtimes/liboliphaunt-native/packaging/**/*
+      - /src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/**/*
+      - "@group(cargo-workspace)"
+    outputs:
+      - /target/liboliphaunt-native-ci/android-arm64-v8a/**/*
+      - /target/liboliphaunt-pg18-android-arm64/**/*
+      - /target/liboliphaunt-mobile-host/android-arm64-v8a/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  package-runtime-android-arm64-v8a:
+    tags:
+      - runtime
+      - release
+      - artifact-package
+      - ci-liboliphaunt-native-android
+    command: "env OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS=\"target/liboliphaunt/mobile-release-assets/android-arm64-v8a\" OLIPHAUNT_LINUX_X64_ROOT=\"$PWD/target/liboliphaunt-mobile-host/android-arm64-v8a\" bash src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh android-arm64-v8a"
+    deps:
+      - liboliphaunt-native:build-runtime-android-arm64-v8a
+    inputs:
+      - "@group(legal-files)"
+      - /src/runtimes/liboliphaunt-native/include/**/*
+      - /src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh
+      - /src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
+      - /src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
+      - /src/runtimes/liboliphaunt-native/tools/finalize-native-runtime-carrier.mts
+      - /tools/packaging/strip-native-binaries.sh
+      - /tools/packaging/platform-binary-contract.mts
+      - "@group(release-archive-contract)"
+    outputs:
+      - /target/liboliphaunt/mobile-release-assets/android-arm64-v8a/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  build-runtime-android-x86_64:
+    tags:
+      - runtime
+      - build
+      - ci-liboliphaunt-native-android
+    deps:
+      - source-inputs:source-fetch-native-runtime
+    command: bash src/runtimes/liboliphaunt-native/tools/build-ci-target.sh android-x86_64
+    inputs:
+      - "@group(legal-files)"
+      - project: postgres18
+        group: source
+      - "@group(upstream-licenses)"
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - project: extension-runtime-contract
+        group: contract
+      - "@group(runtime)"
+      - /src/runtimes/liboliphaunt-native/packaging/**/*
+      - /src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/**/*
+      - "@group(cargo-workspace)"
+    outputs:
+      - /target/liboliphaunt-native-ci/android-x86_64/**/*
+      - /target/liboliphaunt-pg18-android-x86_64/**/*
+      - /target/liboliphaunt-mobile-host/android-x86_64/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  package-runtime-android-x86_64:
+    tags:
+      - runtime
+      - release
+      - artifact-package
+      - ci-liboliphaunt-native-android
+    command: "env OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS=\"target/liboliphaunt/mobile-release-assets/android-x86_64\" OLIPHAUNT_LINUX_X64_ROOT=\"$PWD/target/liboliphaunt-mobile-host/android-x86_64\" bash src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh android-x86_64"
+    deps:
+      - liboliphaunt-native:build-runtime-android-x86_64
+    inputs:
+      - "@group(legal-files)"
+      - /src/runtimes/liboliphaunt-native/include/**/*
+      - /src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh
+      - /src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
+      - /src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
+      - /src/runtimes/liboliphaunt-native/tools/finalize-native-runtime-carrier.mts
+      - /tools/packaging/strip-native-binaries.sh
+      - /tools/packaging/platform-binary-contract.mts
+      - "@group(release-archive-contract)"
+    outputs:
+      - /target/liboliphaunt/mobile-release-assets/android-x86_64/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  build-runtime-ios-xcframework:
+    tags:
+      - runtime
+      - build
+      - ci-liboliphaunt-native-ios
+    deps:
+      - source-inputs:source-fetch-native-runtime
+    command: bash src/runtimes/liboliphaunt-native/tools/build-ci-target.sh ios-xcframework
+    inputs:
+      - "@group(legal-files)"
+      - project: postgres18
+        group: source
+      - "@group(upstream-licenses)"
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - project: extension-runtime-contract
+        group: contract
+      - "@group(runtime)"
+      - /src/runtimes/liboliphaunt-native/packaging/**/*
+      - /src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/**/*
+      - "@group(cargo-workspace)"
+    outputs:
+      - /target/liboliphaunt-native-ci/ios-xcframework/**/*
+      - /target/liboliphaunt-ios-device/**/*
+      - /target/liboliphaunt-ios-simulator/**/*
+      - /target/liboliphaunt-ios-xcframework/**/*
+      - /target/liboliphaunt-mobile-host/ios-xcframework/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  package-runtime-ios-xcframework:
+    tags:
+      - runtime
+      - release
+      - artifact-package
+      - ci-liboliphaunt-native-ios
+    script: |
+      set -e
+      export OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS="target/liboliphaunt/mobile-release-assets/ios-xcframework"
+      export OLIPHAUNT_WORK_ROOT="$PWD/target/liboliphaunt-mobile-host/ios-xcframework"
+      src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh ios-xcframework
+      bun src/runtimes/liboliphaunt-native/tools/validate-ios-carrier-zips.mts --root "$OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS"
+    deps:
+      - liboliphaunt-native:build-runtime-ios-xcframework
+    inputs:
+      - "@group(legal-files)"
+      - /src/runtimes/liboliphaunt-native/include/**/*
+      - /src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh
+      - /src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
+      - /src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
+      - /src/runtimes/liboliphaunt-native/tools/finalize-native-runtime-carrier.mts
+      - /tools/packaging/strip-native-binaries.sh
+      - /tools/packaging/platform-binary-contract.mts
+      - /src/runtimes/liboliphaunt-native/tools/validate-ios-carrier-zips.mts
+      - /src/runtimes/liboliphaunt-native/bin/build-ios-xcframework.sh
+      - "@group(release-archive-contract)"
+    outputs:
+      - /target/liboliphaunt/mobile-release-assets/ios-xcframework/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  finalize-runtime-android-abi:
+    tags:
+      - runtime
+      - artifact-package
+      - ci-liboliphaunt-native-android-abi
+    command: tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.mts --domain android-datum64 --asset-dir target/liboliphaunt/mobile-release-assets/android-x86_64 --receipt-root target/liboliphaunt-native-ci --output-dir target/liboliphaunt/abi-compatible-release-assets/android-datum64
+    deps:
+      - liboliphaunt-native:package-runtime-android-arm64-v8a
+      - liboliphaunt-native:package-runtime-android-x86_64
+    inputs:
+      - /src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.mts
+      - /src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
+      - /target/liboliphaunt/mobile-release-assets/android-x86_64/**/*
+      - /target/liboliphaunt-native-ci/android-*/**/*
+    outputs:
+      - /target/liboliphaunt/abi-compatible-release-assets/android-datum64/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  finalize-runtime-ios-abi:
+    tags:
+      - runtime
+      - artifact-package
+      - ci-liboliphaunt-native-ios-abi
+    command: tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.mts --domain ios-datum64 --asset-dir target/liboliphaunt/mobile-release-assets/ios-xcframework --receipt-root target/liboliphaunt-native-ci/ios-xcframework --output-dir target/liboliphaunt/abi-compatible-release-assets/ios-datum64
+    deps:
+      - liboliphaunt-native:package-runtime-ios-xcframework
+    inputs:
+      - /src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.mts
+      - /src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
+      - /target/liboliphaunt/mobile-release-assets/ios-xcframework/**/*
+      - /target/liboliphaunt-native-ci/ios-xcframework/**/*
+    outputs:
+      - /target/liboliphaunt/abi-compatible-release-assets/ios-datum64/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  release-assets:
+    tags:
+      - runtime
+      - release
+      - artifact-package
+      - ci-liboliphaunt-native-release-assets
+    command: bash src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-aggregate-assets.sh
+    deps:
+      - liboliphaunt-native:package-runtime-desktop-target
+      - liboliphaunt-native:package-runtime-android-arm64-v8a
+      - liboliphaunt-native:package-runtime-android-x86_64
+      - liboliphaunt-native:package-runtime-ios-xcframework
+      - liboliphaunt-native:finalize-runtime-android-abi
+      - liboliphaunt-native:finalize-runtime-ios-abi
+    inputs:
+      - /release-please-config.json
+      - project: extensions
+        group: sdk-metadata
+      - /src/runtimes/liboliphaunt-native/moon.yml
+      - "/tools/packaging/*.{mjs,mts}"
+      - /src/runtimes/liboliphaunt-native/tools/check-release-assets.mts
+      - /src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-aggregate-assets.sh
+      - "@group(release-target-contract)"
+      - /tools/packaging/platform-binary-contract.mts
+      - /tools/release/release-graph.mts
+      - /tools/release/query.mts
+      - /target/liboliphaunt/release-assets/**/*
+    outputs:
+      - /target/liboliphaunt/release-assets/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  packaging-unit:
+    tags:
+      - quality
+      - unit
+      - requires-rust
+    command: "bash src/runtimes/liboliphaunt-native/tools/test-packaging.sh"
+    inputs:
+      - /src/extensions/tools/extension-upstream-licenses.mts
+      - /src/extensions/contracts/*.mts
+      - /src/sdks/swift/tools/prepare-swift-release-consumer.mts
+      - /src/sdks/swift/tools/swift-source-carrier-contract.mts
+      - /src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts
+      - /src/runtimes/liboliphaunt-wasix/tools/wasix-*-npm-contract.mts
+      - "@group(release-target-contract)"
+      - "@group(package-test-metadata)"
+      - "**/*.{mts,cts,sh,podspec,json}"
+      - /tools/packaging/testdata/**/*
+      - /tools/dev/bun.sh
+      - /src/database-resources/contracts/*.mts
+      - /LICENSE
+      - /THIRD_PARTY_NOTICES.md
+      - THIRD_PARTY_NOTICES.md
+      - "@group(upstream-licenses)"
+      - /src/third-party/postgres/source.toml
+      - /src/third-party/icu/source.toml
+      - "/tools/packaging/*.{mts,sh}"
+      - "/tools/release/*.{mjs,mts}"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/runtimes/liboliphaunt/native/packages/darwin-arm64/README.md b/src/runtimes/liboliphaunt-native/packages/darwin-arm64/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/packages/darwin-arm64/README.md
rename to src/runtimes/liboliphaunt-native/packages/darwin-arm64/README.md
diff --git a/src/runtimes/liboliphaunt-native/packages/darwin-arm64/package.json b/src/runtimes/liboliphaunt-native/packages/darwin-arm64/package.json
new file mode 100644
index 000000000..455c87585
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packages/darwin-arm64/package.json
@@ -0,0 +1,46 @@
+{
+  "name": "@oliphaunt/liboliphaunt-darwin-arm64",
+  "version": "0.2.0",
+  "description": "macOS arm64 liboliphaunt native library for Oliphaunt.",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/runtimes/liboliphaunt-native/packages/darwin-arm64"
+  },
+  "os": [
+    "darwin"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "macos-arm64",
+    "libraryRelativePath": "lib/liboliphaunt.dylib",
+    "runtimeRelativePath": "runtime"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true,
+    "executableFiles": [
+      "./runtime/bin/initdb",
+      "./runtime/bin/pg_ctl",
+      "./runtime/bin/postgres"
+    ]
+  },
+  "files": [
+    "lib",
+    "runtime",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
+    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
+    "THIRD_PARTY_LICENSES/ICU-LICENSE"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/liboliphaunt/native/packages/linux-arm64-gnu/README.md b/src/runtimes/liboliphaunt-native/packages/linux-arm64-gnu/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/packages/linux-arm64-gnu/README.md
rename to src/runtimes/liboliphaunt-native/packages/linux-arm64-gnu/README.md
diff --git a/src/runtimes/liboliphaunt-native/packages/linux-arm64-gnu/package.json b/src/runtimes/liboliphaunt-native/packages/linux-arm64-gnu/package.json
new file mode 100644
index 000000000..d4bd3ee85
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packages/linux-arm64-gnu/package.json
@@ -0,0 +1,49 @@
+{
+  "name": "@oliphaunt/liboliphaunt-linux-arm64-gnu",
+  "version": "0.2.0",
+  "description": "Linux arm64 glibc liboliphaunt native library for Oliphaunt.",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/runtimes/liboliphaunt-native/packages/linux-arm64-gnu"
+  },
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "linux-arm64-gnu",
+    "libraryRelativePath": "lib/liboliphaunt.so",
+    "runtimeRelativePath": "runtime"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true,
+    "executableFiles": [
+      "./runtime/bin/initdb",
+      "./runtime/bin/pg_ctl",
+      "./runtime/bin/postgres"
+    ]
+  },
+  "files": [
+    "lib",
+    "runtime",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
+    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
+    "THIRD_PARTY_LICENSES/ICU-LICENSE"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/liboliphaunt/native/packages/linux-x64-gnu/README.md b/src/runtimes/liboliphaunt-native/packages/linux-x64-gnu/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/packages/linux-x64-gnu/README.md
rename to src/runtimes/liboliphaunt-native/packages/linux-x64-gnu/README.md
diff --git a/src/runtimes/liboliphaunt-native/packages/linux-x64-gnu/package.json b/src/runtimes/liboliphaunt-native/packages/linux-x64-gnu/package.json
new file mode 100644
index 000000000..2e625c462
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packages/linux-x64-gnu/package.json
@@ -0,0 +1,49 @@
+{
+  "name": "@oliphaunt/liboliphaunt-linux-x64-gnu",
+  "version": "0.2.0",
+  "description": "Linux x64 glibc liboliphaunt native library for Oliphaunt.",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/runtimes/liboliphaunt-native/packages/linux-x64-gnu"
+  },
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "linux-x64-gnu",
+    "libraryRelativePath": "lib/liboliphaunt.so",
+    "runtimeRelativePath": "runtime"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true,
+    "executableFiles": [
+      "./runtime/bin/initdb",
+      "./runtime/bin/pg_ctl",
+      "./runtime/bin/postgres"
+    ]
+  },
+  "files": [
+    "lib",
+    "runtime",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
+    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
+    "THIRD_PARTY_LICENSES/ICU-LICENSE"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/liboliphaunt/native/packages/win32-x64-msvc/README.md b/src/runtimes/liboliphaunt-native/packages/win32-x64-msvc/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/native/packages/win32-x64-msvc/README.md
rename to src/runtimes/liboliphaunt-native/packages/win32-x64-msvc/README.md
diff --git a/src/runtimes/liboliphaunt-native/packages/win32-x64-msvc/package.json b/src/runtimes/liboliphaunt-native/packages/win32-x64-msvc/package.json
new file mode 100644
index 000000000..a0bc17ea6
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packages/win32-x64-msvc/package.json
@@ -0,0 +1,47 @@
+{
+  "name": "@oliphaunt/liboliphaunt-win32-x64-msvc",
+  "version": "0.2.0",
+  "description": "Windows x64 MSVC liboliphaunt native library for Oliphaunt.",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/runtimes/liboliphaunt-native/packages/win32-x64-msvc"
+  },
+  "os": [
+    "win32"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "windows-x64-msvc",
+    "libraryRelativePath": "bin/oliphaunt.dll",
+    "runtimeRelativePath": "runtime"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true,
+    "executableFiles": [
+      "./runtime/bin/initdb.exe",
+      "./runtime/bin/pg_ctl.exe",
+      "./runtime/bin/postgres.exe"
+    ]
+  },
+  "files": [
+    "bin",
+    "lib",
+    "runtime",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
+    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
+    "THIRD_PARTY_LICENSES/ICU-LICENSE"
+  ],
+  "exports": {
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/liboliphaunt-native/packaging/Cargo.toml b/src/runtimes/liboliphaunt-native/packaging/Cargo.toml
new file mode 100644
index 000000000..659dfec00
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packaging/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "oliphaunt-native-packaging"
+version = "0.0.0"
+edition.workspace = true
+rust-version.workspace = true
+license.workspace = true
+publish = false
+
+[dependencies]
+flate2 = "1"
+liboliphaunt-native-bindings = { path = "../../../sdks/rust/liboliphaunt-native", features = ["internal-native-packaging"] }
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+sha2 = "0.10"
+tar = "0.4"
+toml = "0.9"
+zstd = { version = "0.13", default-features = false }
+
+[dev-dependencies]
+tempfile = "3"
+
+[[bin]]
+name = "oliphaunt-resources"
+path = "./src/bin/package_resources.rs"
diff --git a/src/runtimes/liboliphaunt-native/packaging/README.md b/src/runtimes/liboliphaunt-native/packaging/README.md
new file mode 100644
index 000000000..9c1f5ba5b
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packaging/README.md
@@ -0,0 +1,12 @@
+# Native mobile resource assembly
+
+This unpublished crate assembles already-built native runtime files and selected
+extension artifacts for mobile packages. Its only command is
+`cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources -- --help`.
+The native mobile archive producer and React Native mobile fixture use it.
+
+Extension products own artifact creation and release downloads. This consumer
+validates explicit local artifacts, runtime compatibility, archive limits and
+legal inventories before assembling resources and a static extension registry.
+ICU is included only when explicitly selected. The extension catalog comes from
+the canonical generated inventory.
diff --git a/src/runtimes/liboliphaunt-native/packaging/moon.yml b/src/runtimes/liboliphaunt-native/packaging/moon.yml
new file mode 100644
index 000000000..6c2ea9a41
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packaging/moon.yml
@@ -0,0 +1,71 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "native-packaging"
+language: "rust"
+layer: "tool"
+stack: "systems"
+tags: ["maintainer-tool", "native", "rust"]
+dependsOn:
+  - id: "extensions"
+    scope: "build"
+  - id: "extension-runtime-contract"
+    scope: "build"
+
+project:
+  title: "Native packaging tools"
+  description: "Unpublished maintainer tooling for native runtime and extension packages."
+  owner: "oliphaunt"
+
+owners:
+  defaultOwner: "@oliphaunt/sdk-rust"
+
+tasks:
+  typecheck:
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo check -p oliphaunt-native-packaging --locked --all-targets"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - project: "extensions"
+        group: "sdk-metadata"
+      - project: "extension-runtime-contract"
+        group: "contract"
+      - project: "liboliphaunt-native-bindings"
+        group: "code"
+      - "**/*"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  test:
+    tags: ["quality", "unit", "requires-rust"]
+    command: "cargo test -p oliphaunt-native-packaging --locked"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - project: "extensions"
+        group: "sdk-metadata"
+      - project: "extension-runtime-contract"
+        group: "contract"
+      - project: "liboliphaunt-native-bindings"
+        group: "code"
+      - "**/*"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  rust-format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt -p oliphaunt-native-packaging --check"
+    inputs: ["/src/runtimes/liboliphaunt-native/packaging/**/*.rs","/src/runtimes/liboliphaunt-native/packaging/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+  rust-lint:
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy -p oliphaunt-native-packaging --all-targets --locked -- -D warnings"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs: ["/src/runtimes/liboliphaunt-native/packaging/**/*.rs","/src/runtimes/liboliphaunt-native/packaging/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
diff --git a/src/runtimes/liboliphaunt-native/packaging/src/bin/package_resources.rs b/src/runtimes/liboliphaunt-native/packaging/src/bin/package_resources.rs
new file mode 100644
index 000000000..18e940d6f
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packaging/src/bin/package_resources.rs
@@ -0,0 +1,574 @@
+use std::env;
+use std::path::PathBuf;
+use std::process;
+
+use liboliphaunt_native_bindings::Extension;
+use oliphaunt_native_packaging::{
+    Error, MobileStaticRegistryState, NativePrebuiltExtensionArtifact, NativeRuntimeFeature,
+    NativeRuntimeResourceOptions, Result, build_native_runtime_resources,
+};
+
+fn main() {
+    match run() {
+        Ok(()) => {}
+        Err(error) => {
+            eprintln!("oliphaunt-resources: {error}");
+            process::exit(2);
+        }
+    }
+}
+
+fn run() -> Result<()> {
+    let args = PackageArgs::parse(env::args().skip(1))?;
+    run_with_package_args(args)
+}
+
+fn run_with_package_args(args: PackageArgs) -> Result<()> {
+    if args.help {
+        print_help();
+        return Ok(());
+    }
+    let output_dir = args
+        .output_dir
+        .ok_or_else(|| Error::InvalidConfig("missing required --output ".to_owned()))?;
+    let extension_target = args
+        .extension_target
+        .clone()
+        .unwrap_or_else(default_extension_artifact_target);
+
+    let mut options = NativeRuntimeResourceOptions::new(output_dir)
+        .runtime_features(args.runtime_features)
+        .replace_existing(args.force)
+        .require_mobile_static_registry(args.require_mobile_static_registry)
+        .mobile_static_module_stems(args.mobile_static_module_stems)
+        .extension_target(extension_target);
+    if let Some(version) = args.liboliphaunt_version {
+        options = options.native_runtime_version(version);
+    }
+    for name in args.extensions {
+        let extension = Extension::by_sql_name(&name).ok_or_else(|| Error::InvalidConfig(format!("unknown built-in extension {name}; supply external artifacts with --prebuilt-extension")))?;
+        options = options.extension(extension);
+    }
+    for artifact in args.prebuilt_extensions {
+        options = options.prebuilt_extension(artifact.root);
+    }
+
+    let package = build_native_runtime_resources(options)?;
+    println!("root={}", package.root.display());
+    println!("runtimeFiles={}", package.runtime_files.display());
+    println!("runtimeCacheKey={}", package.runtime_cache_key);
+    println!("extensions={}", package.extension_names.join(","));
+    println!(
+        "runtimeFeatures={}",
+        package
+            .runtime_features
+            .iter()
+            .map(|feature| feature.as_str())
+            .collect::>()
+            .join(",")
+    );
+    println!(
+        "mobileStaticRegistryState={}",
+        match package.mobile_static_registry.state {
+            MobileStaticRegistryState::NotRequired => "not-required",
+            MobileStaticRegistryState::Complete => "complete",
+            MobileStaticRegistryState::Pending => "pending",
+        }
+    );
+    println!(
+        "mobileStaticRegistryPending={}",
+        package.mobile_static_registry.pending_extensions.join(",")
+    );
+    println!(
+        "mobileStaticRegistryRegistered={}",
+        package
+            .mobile_static_registry
+            .registered_extensions
+            .join(",")
+    );
+    println!(
+        "sharedPreloadLibraries={}",
+        package.shared_preload_libraries.join(",")
+    );
+    println!(
+        "nativeModuleStems={}",
+        package.mobile_static_registry.native_module_stems.join(",")
+    );
+    println!(
+        "staticRegistryManifest={}",
+        package.static_registry_manifest.display()
+    );
+    println!(
+        "staticRegistrySource={}",
+        package
+            .static_registry_source
+            .as_ref()
+            .map(|path| path.display().to_string())
+            .unwrap_or_default()
+    );
+    println!("packageSizeReport={}", package.size_report.path.display());
+    println!("packageBytes={}", package.size_report.package_bytes);
+    println!("runtimeBytes={}", package.size_report.runtime_bytes);
+    println!(
+        "staticRegistryBytes={}",
+        package.size_report.static_registry_bytes
+    );
+    println!(
+        "selectedExtensionBytes={}",
+        package.size_report.selected_extension_bytes
+    );
+    println!(
+        "extensionBytes={}",
+        package
+            .size_report
+            .extensions
+            .iter()
+            .map(|extension| format!("{}:{}", extension.name, extension.bytes))
+            .collect::>()
+            .join(",")
+    );
+    Ok(())
+}
+
+struct PackageArgs {
+    output_dir: Option,
+    extensions: Vec,
+    runtime_features: Vec,
+    extension_target: Option,
+    prebuilt_extensions: Vec,
+    mobile_static_module_stems: Vec,
+    force: bool,
+    require_mobile_static_registry: bool,
+    liboliphaunt_version: Option,
+    help: bool,
+}
+impl PackageArgs {
+    fn parse(args: impl IntoIterator) -> Result {
+        Self::parse_with_native_runtime_version(
+            args,
+            env::var("OLIPHAUNT_LIBOLIPHAUNT_VERSION")
+                .ok()
+                .filter(|value| !value.trim().is_empty()),
+        )
+    }
+    fn parse_with_native_runtime_version(
+        args: impl IntoIterator,
+        native_runtime_version: Option,
+    ) -> Result {
+        let mut parsed = Self {
+            output_dir: None,
+            extensions: Vec::new(),
+            runtime_features: Vec::new(),
+            extension_target: None,
+            prebuilt_extensions: Vec::new(),
+            mobile_static_module_stems: Vec::new(),
+            force: false,
+            require_mobile_static_registry: false,
+            liboliphaunt_version: native_runtime_version,
+            help: false,
+        };
+        let mut args = args.into_iter();
+        while let Some(arg) = args.next() {
+            let (flag, inline) = arg
+                .split_once('=')
+                .filter(|(flag, _)| flag.starts_with("--"))
+                .map_or((arg.as_str(), None), |(flag, value)| (flag, Some(value)));
+            if inline.is_some()
+                && matches!(
+                    flag,
+                    "--help" | "--force" | "--require-mobile-static-registry"
+                )
+            {
+                return Err(Error::InvalidConfig(format!("unknown argument '{arg}'")));
+            }
+            let mut value = || {
+                inline
+                    .map(str::to_owned)
+                    .map(Ok)
+                    .unwrap_or_else(|| next_value(&mut args, &arg))
+            };
+            match flag {
+                "-h" | "--help" => parsed.help = true,
+                "--force" => parsed.force = true,
+                "--require-mobile-static-registry" => parsed.require_mobile_static_registry = true,
+                "--output" | "-o" => parsed.output_dir = Some(PathBuf::from(value()?)),
+                "--liboliphaunt-native-version" => parsed.liboliphaunt_version = Some(value()?),
+                "--extension" => push_extension_names(&mut parsed.extensions, &value()?),
+                "--runtime-feature" | "--runtime-features" => {
+                    push_runtime_feature_names(&mut parsed.runtime_features, &value()?)?
+                }
+                "--extension-target" | "--artifact-target" => {
+                    parsed.extension_target = Some(value()?)
+                }
+                "--prebuilt-extension" | "--prebuilt-extension-artifact" => parsed
+                    .prebuilt_extensions
+                    .push(NativePrebuiltExtensionArtifact::new(
+                        PathBuf::from(value()?),
+                    )),
+                "--mobile-static-module" | "--mobile-static-registry-module" => {
+                    push_mobile_static_module_stems(
+                        &mut parsed.mobile_static_module_stems,
+                        &value()?,
+                    )
+                }
+                _ => return Err(Error::InvalidConfig(format!("unknown argument '{arg}'"))),
+            }
+        }
+        Ok(parsed)
+    }
+}
+
+fn next_value(args: &mut impl Iterator, flag: &str) -> Result {
+    args.next()
+        .ok_or_else(|| Error::InvalidConfig(format!("{flag} requires a value")))
+}
+
+fn push_extension_names(target: &mut Vec, value: &str) {
+    for extension in split_csv(value) {
+        target.push(extension.to_owned());
+    }
+}
+
+fn push_runtime_feature_names(target: &mut Vec, value: &str) -> Result<()> {
+    for feature in split_csv(value) {
+        target.push(parse_runtime_feature(feature)?);
+    }
+    Ok(())
+}
+
+fn parse_runtime_feature(value: &str) -> Result {
+    match value {
+        "icu" => Ok(NativeRuntimeFeature::Icu),
+        _ => Err(Error::InvalidConfig(format!(
+            "unknown native runtime feature '{value}'; supported values: icu"
+        ))),
+    }
+}
+
+fn push_mobile_static_module_stems(target: &mut Vec, value: &str) {
+    for stem in split_csv(value) {
+        target.push(stem.to_owned());
+    }
+}
+
+fn split_csv(value: &str) -> impl Iterator {
+    value
+        .split(',')
+        .map(str::trim)
+        .filter(|value| !value.is_empty())
+}
+
+fn default_extension_artifact_target() -> String {
+    if let Ok(target) = env::var("OLIPHAUNT_EXTENSION_TARGET")
+        && !target.trim().is_empty()
+    {
+        return target;
+    }
+    match (env::consts::ARCH, env::consts::OS) {
+        ("aarch64", "macos") => "macos-arm64",
+        ("x86_64", "macos") => "macos-x64",
+        ("aarch64", "linux") => "linux-arm64-gnu",
+        ("x86_64", "linux") => "linux-x64-gnu",
+        ("x86_64", "windows") => "windows-x64-msvc",
+        _ => "host",
+    }
+    .to_owned()
+}
+
+fn print_help() {
+    println!(
+        "oliphaunt-resources --output  [--runtime-feature icu] [--extension name] [--prebuilt-extension artifact] [--liboliphaunt-native-version version] [--extension-target target] [--mobile-static-module module] [--require-mobile-static-registry] [--force]"
+    );
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::fs;
+    #[cfg(unix)]
+    use std::os::unix::fs::PermissionsExt;
+    use std::path::Path;
+    #[cfg(unix)]
+    use std::sync::{Mutex, OnceLock};
+    use std::time::{SystemTime, UNIX_EPOCH};
+
+    #[cfg(unix)]
+    static ENV_LOCK: OnceLock> = OnceLock::new();
+
+    #[test]
+    fn value_options_preserve_equals_and_flags_reject_values() {
+        for args in [
+            vec![
+                "--output",
+                "resources=with spaces",
+                "--extension",
+                "hstore,vector",
+            ],
+            vec![
+                "--output=resources=with spaces",
+                "--extension=hstore,vector",
+            ],
+        ] {
+            let parsed = PackageArgs::parse_with_native_runtime_version(
+                args.into_iter().map(str::to_owned),
+                None,
+            )
+            .unwrap();
+            assert_eq!(parsed.output_dir, Some("resources=with spaces".into()));
+            assert_eq!(parsed.extensions, ["hstore", "vector"]);
+        }
+        assert!(PackageArgs::parse(["--force=false".to_owned()]).is_err());
+        assert!(PackageArgs::parse(["--output".to_owned()]).is_err());
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn direct_prebuilt_cli_packages_matching_native_runtime_version() {
+        let _lock = ENV_LOCK.get_or_init(|| Mutex::new(())).lock().unwrap();
+        let temp = test_temp_root("direct-positive-version-binding");
+        let install = temp.join("install");
+        let artifact = temp.join("acme_ext");
+        let output = temp.join("output");
+        write_test_native_install(&install);
+        write_test_extension_artifact(&artifact, "1.2.3");
+        let _env = TestEnvironment::replace([
+            ("OLIPHAUNT_INSTALL_DIR", Some(install.as_os_str())),
+            (
+                "OLIPHAUNT_RUNTIME_CACHE_DIR",
+                Some(temp.join("runtime-cache").as_os_str()),
+            ),
+            ("OLIPHAUNT_RESOURCES_DIR", None),
+            ("OLIPHAUNT_POSTGRES", None),
+            ("OLIPHAUNT_INITDB", None),
+        ]);
+
+        let args = PackageArgs::parse_with_native_runtime_version(
+            strings([
+                "--output",
+                output.to_str().unwrap(),
+                "--prebuilt-extension",
+                artifact.to_str().unwrap(),
+                "--extension-target",
+                "test-target",
+                "--liboliphaunt-native-version",
+                "1.2.3",
+            ]),
+            None,
+        )
+        .unwrap();
+        run_with_package_args(args).unwrap();
+
+        let manifest =
+            fs::read_to_string(output.join("oliphaunt/runtime/manifest.properties")).unwrap();
+        assert!(
+            manifest
+                .lines()
+                .any(|line| line == "selectedExtensions=acme_ext"),
+            "selected prebuilt extension missing from selectedExtensions domain:\n{manifest}"
+        );
+        assert!(
+            manifest.lines().any(|line| line == "extensions="),
+            "non-createable prebuilt extension leaked into createable extensions domain:\n{manifest}"
+        );
+        assert!(!output.join("oliphaunt/cluster-seed").exists());
+        for executable in ["postgres", "pg_ctl"] {
+            assert!(
+                output
+                    .join("oliphaunt/runtime/files/bin")
+                    .join(executable)
+                    .is_file(),
+                "packaged native server runtime is missing {executable}"
+            );
+        }
+        for tool in ["pg_basebackup", "pg_dump", "psql"] {
+            assert!(
+                !output
+                    .join("oliphaunt/runtime/files/bin")
+                    .join(tool)
+                    .exists(),
+                "optional PostgreSQL tool leaked into the core runtime: {tool}"
+            );
+        }
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn direct_prebuilt_cli_requires_and_binds_selected_native_runtime_version() {
+        let temp = test_temp_root("direct-version-binding");
+        let artifact = temp.join("acme_ext");
+        let output = temp.join("missing-version-output");
+        write_test_extension_artifact(&artifact, "1.2.3");
+
+        let args = PackageArgs::parse_with_native_runtime_version(
+            strings([
+                "--output",
+                output.to_str().unwrap(),
+                "--prebuilt-extension",
+                artifact.to_str().unwrap(),
+                "--extension-target",
+                "test-target",
+            ]),
+            None,
+        )
+        .unwrap();
+        let error = run_with_package_args(args).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("requires an exact stable liboliphaunt-native version"),
+            "unexpected missing-version error: {error}"
+        );
+        assert!(!output.exists(), "validation must precede materialization");
+
+        let output = temp.join("wrong-version-output");
+        let args = PackageArgs::parse_with_native_runtime_version(
+            strings([
+                "--output",
+                output.to_str().unwrap(),
+                "--prebuilt-extension",
+                artifact.to_str().unwrap(),
+                "--extension-target",
+                "test-target",
+                "--liboliphaunt-native-version",
+                "1.2.4",
+            ]),
+            None,
+        )
+        .unwrap();
+        let error = run_with_package_args(args).unwrap_err();
+        assert!(
+            error.to_string().contains(
+                "requires liboliphaunt-native version '1.2.3', but runtime packaging selected '1.2.4'"
+            ),
+            "unexpected bound-version error: {error}"
+        );
+        assert!(!output.exists(), "validation must precede materialization");
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    fn write_test_extension_artifact(root: &Path, native_runtime_version: &str) {
+        fs::create_dir_all(root.join("files/share/licenses/acme_ext")).unwrap();
+        fs::write(
+            root.join("manifest.properties"),
+            format!(
+                "packageLayout=oliphaunt-extension-artifact-v1\npgMajor=18\nsqlName=acme_ext\ncreatesExtension=no\nnativeModuleStem=\nnativeModuleFile=\nnativeTarget=\nnativeRuntimeProduct=liboliphaunt-native\nnativeRuntimeVersion={native_runtime_version}\ndependencies=\ndataFiles=\nextensionSqlFileNames=\nextensionSqlFilePrefixes=\nsharedPreloadLibraries=\nmobilePrebuilt=no\nmobileStaticArchives=\nmobileStaticDependencyArchives=\nstaticSymbolPrefix=\nstaticSymbolAliases=\nlicenseFiles=share/licenses/acme_ext/LICENSE\nlicenseProfile=external-native\nfiles=files\n"
+            ),
+        )
+        .unwrap();
+        fs::write(root.join("LICENSE"), "fixture license\n").unwrap();
+        fs::write(
+            root.join("THIRD_PARTY_NOTICES.md"),
+            "fixture third-party notices\n",
+        )
+        .unwrap();
+        fs::write(
+            root.join("files/share/licenses/acme_ext/LICENSE"),
+            "fixture upstream license\n",
+        )
+        .unwrap();
+        #[cfg(unix)]
+        for legal in [
+            root.join("LICENSE"),
+            root.join("THIRD_PARTY_NOTICES.md"),
+            root.join("files/share/licenses/acme_ext/LICENSE"),
+        ] {
+            fs::set_permissions(legal, fs::Permissions::from_mode(0o644)).unwrap();
+        }
+    }
+
+    #[cfg(unix)]
+    fn write_test_native_install(root: &Path) {
+        for tool in ["postgres", "pg_ctl", "pg_basebackup", "pg_dump", "psql"] {
+            write_test_file(&root.join("bin").join(tool), tool.as_bytes());
+        }
+        let initdb = root.join("bin/initdb");
+        write_test_file(&initdb, b"#!/bin/sh\nexit 99\n");
+        fs::set_permissions(&initdb, fs::Permissions::from_mode(0o755)).unwrap();
+        write_test_file(
+            &root.join("share/postgresql/postgresql.conf.sample"),
+            b"# sample\n",
+        );
+        write_test_file(
+            &root.join("share/postgresql/extension/plpgsql.control"),
+            b"comment = 'PL/pgSQL'\n",
+        );
+        write_test_file(
+            &root.join("share/postgresql/extension/plpgsql--1.0.sql"),
+            b"select 'plpgsql install';\n",
+        );
+        fs::create_dir_all(root.join("lib/postgresql")).unwrap();
+        for module in ["dict_snowball", "plpgsql"] {
+            write_test_file(
+                &root
+                    .parent()
+                    .unwrap()
+                    .join("out/modules")
+                    .join(format!("{module}{}", std::env::consts::DLL_SUFFIX)),
+                b"embedded module fixture",
+            );
+        }
+    }
+
+    #[cfg(unix)]
+    fn write_test_file(path: &Path, contents: &[u8]) {
+        if let Some(parent) = path.parent() {
+            fs::create_dir_all(parent).unwrap();
+        }
+        fs::write(path, contents).unwrap();
+    }
+
+    #[cfg(unix)]
+    struct TestEnvironment {
+        previous: Vec<(&'static str, Option)>,
+    }
+
+    #[cfg(unix)]
+    impl TestEnvironment {
+        fn replace(values: [(&'static str, Option<&std::ffi::OsStr>); N]) -> Self {
+            let previous = values
+                .iter()
+                .map(|(name, _)| (*name, env::var_os(name)))
+                .collect();
+            for (name, value) in values {
+                unsafe {
+                    match value {
+                        Some(value) => env::set_var(name, value),
+                        None => env::remove_var(name),
+                    }
+                }
+            }
+            Self { previous }
+        }
+    }
+
+    #[cfg(unix)]
+    impl Drop for TestEnvironment {
+        fn drop(&mut self) {
+            for (name, value) in self.previous.drain(..).rev() {
+                unsafe {
+                    match value {
+                        Some(value) => env::set_var(name, value),
+                        None => env::remove_var(name),
+                    }
+                }
+            }
+        }
+    }
+
+    fn strings(values: [&str; N]) -> Vec {
+        values.into_iter().map(str::to_owned).collect()
+    }
+
+    fn test_temp_root(label: &str) -> PathBuf {
+        let nanos = SystemTime::now()
+            .duration_since(UNIX_EPOCH)
+            .map(|duration| duration.as_nanos())
+            .unwrap_or(0);
+        env::temp_dir().join(format!(
+            "oliphaunt-package-resources-{label}-{}-{nanos}",
+            process::id()
+        ))
+    }
+}
diff --git a/src/runtimes/liboliphaunt-native/packaging/src/catalog.rs b/src/runtimes/liboliphaunt-native/packaging/src/catalog.rs
new file mode 100644
index 000000000..fe5a5a979
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packaging/src/catalog.rs
@@ -0,0 +1,50 @@
+use std::collections::BTreeMap;
+use std::sync::OnceLock;
+
+use serde::Deserialize;
+
+use liboliphaunt_native_bindings::Extension;
+
+const GENERATED_EXTENSION_CATALOG: &str =
+    include_str!("../../../../extensions/generated/sdk/extensions.json");
+
+#[derive(Debug, Deserialize)]
+struct CatalogDocument {
+    extensions: Vec,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub(crate) struct CatalogExtension {
+    pub(crate) sql_name: String,
+    pub(crate) creates_extension: bool,
+    pub(crate) native_module_stem: Option,
+    pub(crate) dependencies: Vec,
+    pub(crate) runtime_share_data_files: Vec,
+    pub(crate) extension_sql_file_names: Vec,
+    pub(crate) extension_sql_file_prefixes: Vec,
+    pub(crate) shared_preload_libraries: Vec,
+    pub(crate) artifact_product: Option,
+}
+
+fn catalog() -> &'static BTreeMap {
+    static CATALOG: OnceLock> = OnceLock::new();
+    CATALOG.get_or_init(|| {
+        let document: CatalogDocument = serde_json::from_str(GENERATED_EXTENSION_CATALOG)
+            .expect("generated extension catalog must remain valid JSON");
+        document
+            .extensions
+            .into_iter()
+            .map(|entry| (entry.sql_name.clone(), entry))
+            .collect()
+    })
+}
+
+pub(crate) fn by_sql_name(sql_name: &str) -> Option<&'static CatalogExtension> {
+    catalog().get(sql_name)
+}
+
+pub(crate) fn for_extension(extension: Extension) -> &'static CatalogExtension {
+    by_sql_name(extension.sql_name())
+        .expect("every generated Rust extension must exist in the generated extension catalog")
+}
diff --git a/src/runtimes/liboliphaunt-native/packaging/src/extension_artifact.rs b/src/runtimes/liboliphaunt-native/packaging/src/extension_artifact.rs
new file mode 100644
index 000000000..a2440fe81
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packaging/src/extension_artifact.rs
@@ -0,0 +1,804 @@
+pub(super) fn mobile_static_dependency_archive_artifact_relative_path(
+    target: &str,
+    name: &str,
+    file_name: &str,
+) -> PathBuf {
+    PathBuf::from("mobile-static")
+        .join(target)
+        .join("dependencies")
+        .join(name)
+        .join(file_name)
+}
+
+pub(super) fn mobile_static_archive_artifact_relative_path(target: &str, stem: &str) -> PathBuf {
+    PathBuf::from("mobile-static")
+        .join(target)
+        .join("extensions")
+        .join(stem)
+        .join(format!("liboliphaunt_extension_{stem}.a"))
+}
+
+use super::*;
+use std::path::Component;
+
+const EXTENSION_ARTIFACT_ARCHIVE_POLICY: &str =
+    include_str!("../../../../extensions/contracts/extension-artifact-archive-policy.properties");
+const EXTENSION_ARTIFACT_ARCHIVE_POLICY_SCHEMA: &str =
+    "oliphaunt-extension-artifact-archive-policy-v1";
+const DESKTOP_NATIVE_TARGETS: [&str; 4] = [
+    "linux-x64-gnu",
+    "linux-arm64-gnu",
+    "macos-arm64",
+    "windows-x64-msvc",
+];
+const EXTENSION_ARTIFACT_BASE_LEGAL_MEMBERS: [&str; 2] = ["LICENSE", "THIRD_PARTY_NOTICES.md"];
+pub(super) const EXTENSION_ARTIFACT_POSTGRESQL_LICENSE: &str =
+    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT";
+pub(super) const EXTENSION_ARTIFACT_OPENSSL_LICENSE: &str =
+    "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt";
+
+fn extension_artifact_legal_members(
+    profile: NativeExtensionArtifactLicenseProfile,
+) -> Vec {
+    let mut members = EXTENSION_ARTIFACT_BASE_LEGAL_MEMBERS
+        .iter()
+        .map(PathBuf::from)
+        .collect::>();
+    match profile {
+        NativeExtensionArtifactLicenseProfile::ContribNative => {
+            members.push(PathBuf::from(EXTENSION_ARTIFACT_POSTGRESQL_LICENSE));
+        }
+        NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl => {
+            members.push(PathBuf::from(EXTENSION_ARTIFACT_POSTGRESQL_LICENSE));
+            members.push(PathBuf::from(EXTENSION_ARTIFACT_OPENSSL_LICENSE));
+        }
+        NativeExtensionArtifactLicenseProfile::ExternalNative => {}
+    }
+    members.sort();
+    members
+}
+
+pub(super) fn validate_extension_artifact_license_paths(
+    manifest_path: &Path,
+    license_files: &[PathBuf],
+) -> Result<()> {
+    for relative in license_files {
+        let mut components = relative.components();
+        let in_license_namespace = matches!(components.next(), Some(Component::Normal(value)) if value == "share")
+            && matches!(components.next(), Some(Component::Normal(value)) if value == "licenses")
+            && components.next().is_some();
+        if !in_license_namespace {
+            return Err(Error::InvalidConfig(format!(
+                "manifest {} licenseFiles entry '{}' must be an exact leaf below share/licenses/",
+                manifest_path.display(),
+                relative.display()
+            )));
+        }
+    }
+    Ok(())
+}
+
+pub(super) fn validate_extension_artifact_license_profile(
+    manifest_path: &Path,
+    sql_name: &str,
+    native_target: Option<&str>,
+    mobile_static_dependency_archives: &[MobileStaticDependencyArchive],
+    profile: NativeExtensionArtifactLicenseProfile,
+    license_files: &[PathBuf],
+) -> Result<()> {
+    let external = catalog::by_sql_name(sql_name)
+        .and_then(|extension| extension.artifact_product.as_deref())
+        .is_none_or(|product| product != "oliphaunt-extension-contrib-pg18");
+    let embeds_openssl = !external
+        && sql_name == "pgcrypto"
+        && (matches!(native_target, Some("macos-arm64" | "windows-x64-msvc"))
+            || mobile_static_dependency_archives
+                .iter()
+                .any(|archive| archive.name == "openssl"));
+    let expected = if external {
+        NativeExtensionArtifactLicenseProfile::ExternalNative
+    } else if embeds_openssl {
+        NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl
+    } else {
+        NativeExtensionArtifactLicenseProfile::ContribNative
+    };
+    if profile != expected {
+        return Err(Error::InvalidConfig(format!(
+            "manifest {} has licenseProfile='{}' for extension '{}' and target '{}', expected '{}'",
+            manifest_path.display(),
+            profile.as_str(),
+            sql_name,
+            native_target.unwrap_or(""),
+            expected.as_str()
+        )));
+    }
+    if external && license_files.is_empty() {
+        return Err(Error::InvalidConfig(format!(
+            "manifest {} external-native profile must declare at least one exact licenseFiles leaf",
+            manifest_path.display()
+        )));
+    }
+    if !external && !license_files.is_empty() {
+        return Err(Error::InvalidConfig(format!(
+            "manifest {} contrib profile must not declare upstream licenseFiles leaves",
+            manifest_path.display()
+        )));
+    }
+    Ok(())
+}
+
+pub(super) fn validate_prebuilt_extension_leaf_inventory(
+    root: &Path,
+    manifest_path: &Path,
+    extension: &RuntimeResourceExtension,
+) -> Result<()> {
+    let profile = extension.license_profile.ok_or_else(|| {
+        Error::Engine(format!(
+            "internal error: prebuilt extension {} has no legal profile",
+            manifest_path.display()
+        ))
+    })?;
+    let actual = extension_artifact_leaf_inventory(root)?;
+    let mut expected = BTreeSet::from([PathBuf::from("manifest.properties")]);
+    let mut legal_members = BTreeSet::new();
+    for member in extension_artifact_legal_members(profile) {
+        legal_members.insert(member.clone());
+        expected.insert(member);
+    }
+    for relative in &extension.license_files {
+        let member = PathBuf::from("files").join(relative);
+        legal_members.insert(member.clone());
+        expected.insert(member);
+    }
+
+    let extension_prefix = Path::new("files/share/postgresql/extension");
+    let mut has_control = false;
+    let mut has_install_sql = false;
+    for relative in &actual {
+        let Ok(file_name) = relative.strip_prefix(extension_prefix) else {
+            continue;
+        };
+        if file_name.components().count() != 1 {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact {} contains undeclared extension SQL/control file {}",
+                root.display(),
+                relative.display()
+            )));
+        }
+        let file_name = file_name.to_str().ok_or_else(|| {
+            Error::InvalidConfig(format!(
+                "prebuilt extension artifact {} has a non-UTF-8 extension SQL/control file {}",
+                root.display(),
+                relative.display()
+            ))
+        })?;
+        if !runtime_extension_sql_file_belongs(extension, file_name) {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact {} contains undeclared extension SQL/control file {}",
+                root.display(),
+                relative.display()
+            )));
+        }
+        expected.insert(relative.clone());
+        has_control |= file_name == format!("{}.control", extension.sql_name);
+        has_install_sql |= extension_install_sql_file_belongs(&extension.sql_name, file_name);
+    }
+    if extension.creates_extension && (!has_control || !has_install_sql) {
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact {} for '{}' must include its control file and at least one canonical base install SQL file",
+            root.display(),
+            extension.sql_name
+        )));
+    }
+    for relative in &extension.data_files {
+        expected.insert(PathBuf::from("files/share/postgresql").join(relative));
+    }
+    if let Some(module) = &extension.native_module_file {
+        expected.insert(PathBuf::from("files/lib/postgresql").join(module));
+        let embedded = PathBuf::from("files/lib/modules").join(module);
+        if extension
+            .native_target
+            .as_deref()
+            .is_some_and(|target| DESKTOP_NATIVE_TARGETS.contains(&target))
+            || actual.contains(&embedded)
+        {
+            expected.insert(embedded);
+        }
+    }
+    for archive in &extension.mobile_static_archives {
+        expected.insert(archive.relative_path.clone());
+    }
+    for archive in &extension.mobile_static_dependency_archives {
+        expected.insert(archive.relative_path.clone());
+    }
+
+    if actual != expected {
+        let undeclared = actual
+            .difference(&expected)
+            .map(|path| path.display().to_string());
+        let missing = expected
+            .difference(&actual)
+            .map(|path| path.display().to_string());
+        let undeclared = undeclared.collect::>();
+        let missing = missing.collect::>();
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact {} leaf inventory mismatch{}{}",
+            root.display(),
+            if undeclared.is_empty() {
+                String::new()
+            } else {
+                format!("; undeclared: {}", undeclared.join(","))
+            },
+            if missing.is_empty() {
+                String::new()
+            } else {
+                format!("; missing: {}", missing.join(","))
+            }
+        )));
+    }
+    for relative in legal_members {
+        validate_extension_artifact_legal_leaf(root, &relative)?;
+    }
+    Ok(())
+}
+
+fn extension_artifact_leaf_inventory(root: &Path) -> Result> {
+    fn walk(root: &Path, current: &Path, out: &mut BTreeSet) -> Result<()> {
+        let mut entries = fs::read_dir(current)
+            .map_err(|err| Error::InvalidConfig(format!("read {}: {err}", current.display())))?
+            .collect::, _>>()
+            .map_err(|err| {
+                Error::InvalidConfig(format!("read entry in {}: {err}", current.display()))
+            })?;
+        entries.sort_by_key(|entry| entry.file_name());
+        for entry in entries {
+            let path = entry.path();
+            let metadata = fs::symlink_metadata(&path).map_err(|err| {
+                Error::InvalidConfig(format!("inspect artifact member {}: {err}", path.display()))
+            })?;
+            if metadata.file_type().is_symlink() {
+                return Err(Error::InvalidConfig(format!(
+                    "prebuilt extension artifact {} contains unsafe symlink {}",
+                    root.display(),
+                    path.display()
+                )));
+            }
+            if metadata.is_dir() {
+                walk(root, &path, out)?;
+                continue;
+            }
+            if !metadata.is_file() {
+                return Err(Error::InvalidConfig(format!(
+                    "prebuilt extension artifact {} contains non-file member {}",
+                    root.display(),
+                    path.display()
+                )));
+            }
+            let relative = path.strip_prefix(root).map_err(|err| {
+                Error::Engine(format!(
+                    "derive artifact member path {}: {err}",
+                    path.display()
+                ))
+            })?;
+            validate_relative_artifact_path(root, "artifact member", relative)?;
+            for component in relative.components() {
+                let Component::Normal(component) = component else {
+                    continue;
+                };
+                let component = component.to_str().ok_or_else(|| {
+                    Error::InvalidConfig(format!(
+                        "prebuilt extension artifact {} member {} must use UTF-8 path text",
+                        root.display(),
+                        relative.display()
+                    ))
+                })?;
+                if component.contains('\\') {
+                    return Err(Error::InvalidConfig(format!(
+                        "prebuilt extension artifact {} member {} contains a literal backslash",
+                        root.display(),
+                        relative.display()
+                    )));
+                }
+            }
+            if !out.insert(relative.to_path_buf()) {
+                return Err(Error::InvalidConfig(format!(
+                    "prebuilt extension artifact {} repeats leaf {}",
+                    root.display(),
+                    relative.display()
+                )));
+            }
+        }
+        Ok(())
+    }
+
+    let metadata = fs::symlink_metadata(root).map_err(|err| {
+        Error::InvalidConfig(format!(
+            "inspect prebuilt extension artifact {}: {err}",
+            root.display()
+        ))
+    })?;
+    if metadata.file_type().is_symlink() || !metadata.is_dir() {
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact {} must be a real directory after extraction",
+            root.display()
+        )));
+    }
+    let mut out = BTreeSet::new();
+    walk(root, root, &mut out)?;
+    Ok(out)
+}
+
+fn validate_extension_artifact_legal_leaf(root: &Path, relative: &Path) -> Result<()> {
+    let path = root.join(relative);
+    let metadata = fs::symlink_metadata(&path).map_err(|err| {
+        Error::InvalidConfig(format!("inspect legal member {}: {err}", path.display()))
+    })?;
+    if metadata.file_type().is_symlink() || !metadata.is_file() || metadata.len() == 0 {
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact legal member {} must be a non-empty regular non-symlink file",
+            relative.display()
+        )));
+    }
+    #[cfg(unix)]
+    {
+        use std::os::unix::fs::PermissionsExt;
+        if metadata.permissions().mode() & 0o777 != 0o644 {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact legal member {} must have mode 0644",
+                relative.display()
+            )));
+        }
+    }
+    Ok(())
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub(super) struct ExtensionArtifactArchivePolicy {
+    pub(super) max_compressed_bytes: u64,
+    pub(super) max_expanded_bytes: u64,
+    pub(super) max_member_bytes: u64,
+    pub(super) max_members: usize,
+}
+
+pub(super) fn extension_artifact_archive_policy() -> Result {
+    if EXTENSION_ARTIFACT_ARCHIVE_POLICY.contains('\r')
+        || !EXTENSION_ARTIFACT_ARCHIVE_POLICY.ends_with('\n')
+        || EXTENSION_ARTIFACT_ARCHIVE_POLICY.ends_with("\n\n")
+    {
+        return Err(Error::Engine(
+            "embedded extension artifact archive policy must use LF lines and one final newline"
+                .to_owned(),
+        ));
+    }
+    let expected_keys = [
+        "schema",
+        "maxCompressedBytes",
+        "maxExpandedBytes",
+        "maxMemberBytes",
+        "maxMembers",
+    ];
+    let lines = EXTENSION_ARTIFACT_ARCHIVE_POLICY
+        .trim_end_matches('\n')
+        .lines()
+        .collect::>();
+    if lines.len() != expected_keys.len() {
+        return Err(Error::Engine(
+            "embedded extension artifact archive policy has the wrong property count".to_owned(),
+        ));
+    }
+    let mut values = BTreeMap::new();
+    for (index, line) in lines.iter().enumerate() {
+        let (key, value) = line.split_once('=').ok_or_else(|| {
+            Error::Engine(format!(
+                "embedded extension artifact archive policy line {} is not key=value",
+                index + 1
+            ))
+        })?;
+        if key != expected_keys[index] || value.is_empty() || values.insert(key, value).is_some() {
+            return Err(Error::Engine(format!(
+                "embedded extension artifact archive policy property {} must be {}",
+                index + 1,
+                expected_keys[index]
+            )));
+        }
+    }
+    if values.get("schema").copied() != Some(EXTENSION_ARTIFACT_ARCHIVE_POLICY_SCHEMA) {
+        return Err(Error::Engine(format!(
+            "embedded extension artifact archive policy schema must be {EXTENSION_ARTIFACT_ARCHIVE_POLICY_SCHEMA}"
+        )));
+    }
+    let positive_u64 = |key: &str| -> Result {
+        let raw = values.get(key).copied().unwrap_or_default();
+        let value = raw.parse::().map_err(|err| {
+            Error::Engine(format!(
+                "embedded extension artifact archive policy {key} is invalid: {err}"
+            ))
+        })?;
+        if value == 0 || value.to_string() != raw {
+            return Err(Error::Engine(format!(
+                "embedded extension artifact archive policy {key} must be a canonical positive integer"
+            )));
+        }
+        Ok(value)
+    };
+    let max_members_u64 = positive_u64("maxMembers")?;
+    let max_members = usize::try_from(max_members_u64).map_err(|err| {
+        Error::Engine(format!(
+            "embedded extension artifact archive policy maxMembers does not fit usize: {err}"
+        ))
+    })?;
+    let policy = ExtensionArtifactArchivePolicy {
+        max_compressed_bytes: positive_u64("maxCompressedBytes")?,
+        max_expanded_bytes: positive_u64("maxExpandedBytes")?,
+        max_member_bytes: positive_u64("maxMemberBytes")?,
+        max_members,
+    };
+    if policy.max_member_bytes > policy.max_expanded_bytes {
+        return Err(Error::Engine(
+            "embedded extension artifact archive policy maxMemberBytes must not exceed maxExpandedBytes"
+                .to_owned(),
+        ));
+    }
+    Ok(policy)
+}
+
+pub(super) fn unique_extension_extraction_root() -> PathBuf {
+    let nanos = SystemTime::now()
+        .duration_since(UNIX_EPOCH)
+        .map(|duration| duration.as_nanos())
+        .unwrap_or(0);
+    std::env::temp_dir().join(format!(
+        "oliphaunt-extension-artifacts-{}-{nanos}",
+        std::process::id()
+    ))
+}
+
+pub(super) fn extract_prebuilt_extension_archive(
+    archive_path: &Path,
+    destination: &Path,
+) -> Result {
+    let policy = extension_artifact_archive_policy()?;
+    let archive_metadata = fs::symlink_metadata(archive_path).map_err(|err| {
+        Error::InvalidConfig(format!(
+            "inspect prebuilt extension artifact archive {}: {err}",
+            archive_path.display()
+        ))
+    })?;
+    if archive_metadata.file_type().is_symlink() || !archive_metadata.is_file() {
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact archive {} must be a regular non-symlink file",
+            archive_path.display()
+        )));
+    }
+    let compressed = archive_is_tar_zst(archive_path) || archive_is_tar_gz(archive_path);
+    let archive_limit = if compressed {
+        policy.max_compressed_bytes
+    } else {
+        policy.max_expanded_bytes
+    };
+    if archive_metadata.len() == 0 || archive_metadata.len() > archive_limit {
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact archive {} must contain between 1 and {archive_limit} bytes",
+            archive_path.display()
+        )));
+    }
+    fs::create_dir_all(destination).map_err(|err| {
+        Error::Engine(format!(
+            "create prebuilt extension artifact extraction dir {}: {err}",
+            destination.display()
+        ))
+    })?;
+    let file = File::open(archive_path).map_err(|err| {
+        Error::InvalidConfig(format!(
+            "open prebuilt extension artifact archive {}: {err}",
+            archive_path.display()
+        ))
+    })?;
+    let file_modes = if archive_is_tar_zst(archive_path) {
+        let decoder = zstd::stream::read::Decoder::new(file).map_err(|err| {
+            Error::InvalidConfig(format!(
+                "open zstd prebuilt extension artifact archive {}: {err}",
+                archive_path.display()
+            ))
+        })?;
+        extract_prebuilt_extension_tar(archive_path, decoder, destination, policy)?
+    } else if archive_is_tar_gz(archive_path) {
+        let decoder = flate2::read::GzDecoder::new(file);
+        extract_prebuilt_extension_tar(archive_path, decoder, destination, policy)?
+    } else if archive_is_tar(archive_path) {
+        extract_prebuilt_extension_tar(archive_path, file, destination, policy)?
+    } else {
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact archive {} must end in .tar, .tar.gz, or .tar.zst",
+            archive_path.display()
+        )));
+    };
+    let root = extracted_extension_artifact_root(destination)?;
+    validate_extension_artifact_archive_legal_modes(archive_path, destination, &root, &file_modes)?;
+    Ok(root)
+}
+
+fn archive_is_tar(path: &Path) -> bool {
+    path.file_name()
+        .and_then(|name| name.to_str())
+        .is_some_and(|name| name.ends_with(".tar"))
+}
+
+fn archive_is_tar_zst(path: &Path) -> bool {
+    path.file_name()
+        .and_then(|name| name.to_str())
+        .is_some_and(|name| name.ends_with(".tar.zst"))
+}
+
+fn archive_is_tar_gz(path: &Path) -> bool {
+    path.file_name()
+        .and_then(|name| name.to_str())
+        .is_some_and(|name| name.ends_with(".tar.gz") || name.ends_with(".tgz"))
+}
+
+fn extract_prebuilt_extension_tar(
+    archive_path: &Path,
+    reader: impl io::Read,
+    destination: &Path,
+    policy: ExtensionArtifactArchivePolicy,
+) -> Result> {
+    let mut archive = tar::Archive::new(reader);
+    let entries = archive.entries().map_err(|err| {
+        Error::InvalidConfig(format!(
+            "read prebuilt extension artifact archive {}: {err}",
+            archive_path.display()
+        ))
+    })?;
+    let mut seen_files = BTreeSet::new();
+    let mut seen_dirs = BTreeSet::new();
+    let mut file_modes = BTreeMap::new();
+    let mut member_count = 0usize;
+    // The canonical archive policy includes the two 512-byte tar end-marker
+    // blocks in the expanded byte budget. `tar::Archive::entries` stops before
+    // those blocks, so account for them up front just as the JS producer,
+    // release inventory, and Android consumer do.
+    let mut expanded_bytes = 1024u64;
+    for entry in entries {
+        let mut entry = entry.map_err(|err| {
+            Error::InvalidConfig(format!(
+                "read prebuilt extension artifact archive entry in {}: {err}",
+                archive_path.display()
+            ))
+        })?;
+        member_count += 1;
+        if member_count > policy.max_members {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive {} contains more than {} members",
+                archive_path.display(),
+                policy.max_members
+            )));
+        }
+        let member_bytes = entry.size();
+        if member_bytes > policy.max_member_bytes {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive {} contains a member larger than {} bytes",
+                archive_path.display(),
+                policy.max_member_bytes
+            )));
+        }
+        let padded_member_bytes = member_bytes
+            .checked_add(511)
+            .map(|value| value / 512 * 512)
+            .ok_or_else(|| {
+                Error::InvalidConfig(format!(
+                    "prebuilt extension artifact archive {} has an overflowing member size",
+                    archive_path.display()
+                ))
+            })?;
+        expanded_bytes = expanded_bytes
+            .checked_add(512)
+            .and_then(|value| value.checked_add(padded_member_bytes))
+            .ok_or_else(|| {
+                Error::InvalidConfig(format!(
+                    "prebuilt extension artifact archive {} has an overflowing expanded size",
+                    archive_path.display()
+                ))
+            })?;
+        if expanded_bytes > policy.max_expanded_bytes {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive {} expands beyond {} bytes",
+                archive_path.display(),
+                policy.max_expanded_bytes
+            )));
+        }
+        let entry_type = entry.header().entry_type();
+        let raw_relative = entry.path_bytes();
+        let raw_relative = std::str::from_utf8(raw_relative.as_ref()).map_err(|err| {
+            Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive {} contains a non-UTF-8 path: {err}",
+                archive_path.display()
+            ))
+        })?;
+        let raw_relative = if entry_type.is_dir() {
+            raw_relative.strip_suffix('/').unwrap_or(raw_relative)
+        } else {
+            raw_relative
+        };
+        let relative =
+            parse_portable_artifact_path_text(archive_path, "archive entry", raw_relative)?;
+        if entry_type.is_dir() {
+            if member_bytes != 0 {
+                return Err(Error::InvalidConfig(format!(
+                    "prebuilt extension artifact archive {} directory {} must have size zero",
+                    archive_path.display(),
+                    relative.display()
+                )));
+            }
+            validate_archive_entry_plan(&relative, true, &mut seen_files, &mut seen_dirs)?;
+            fs::create_dir_all(destination.join(&relative)).map_err(|err| {
+                Error::Engine(format!(
+                    "create prebuilt extension artifact archive dir {}: {err}",
+                    destination.join(&relative).display()
+                ))
+            })?;
+        } else if entry_type.is_file() {
+            validate_archive_entry_plan(&relative, false, &mut seen_files, &mut seen_dirs)?;
+            let mode = entry.header().mode().map_err(|err| {
+                Error::InvalidConfig(format!(
+                    "read prebuilt extension artifact archive mode for {} in {}: {err}",
+                    relative.display(),
+                    archive_path.display()
+                ))
+            })?;
+            file_modes.insert(relative.clone(), mode);
+            if let Some(parent) = destination.join(&relative).parent() {
+                fs::create_dir_all(parent).map_err(|err| {
+                    Error::Engine(format!(
+                        "create prebuilt extension artifact archive parent {}: {err}",
+                        parent.display()
+                    ))
+                })?;
+            }
+            entry.unpack(destination.join(&relative)).map_err(|err| {
+                Error::Engine(format!(
+                    "extract prebuilt extension artifact archive entry {} from {}: {err}",
+                    relative.display(),
+                    archive_path.display()
+                ))
+            })?;
+        } else {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive {} entry {} must be a regular file or directory, not {:?}",
+                archive_path.display(),
+                relative.display(),
+                entry_type
+            )));
+        }
+    }
+    Ok(file_modes)
+}
+
+fn validate_extension_artifact_archive_legal_modes(
+    archive_path: &Path,
+    destination: &Path,
+    artifact_root: &Path,
+    file_modes: &BTreeMap,
+) -> Result<()> {
+    let wrapper = artifact_root.strip_prefix(destination).map_err(|err| {
+        Error::Engine(format!(
+            "derive prebuilt extension artifact wrapper path for {}: {err}",
+            artifact_root.display()
+        ))
+    })?;
+    for (archive_member, mode) in file_modes {
+        let relative = if wrapper.as_os_str().is_empty() {
+            archive_member.as_path()
+        } else {
+            archive_member.strip_prefix(wrapper).map_err(|_| {
+                Error::InvalidConfig(format!(
+                    "prebuilt extension artifact archive {} contains top-level member {} outside wrapper {}",
+                    archive_path.display(),
+                    archive_member.display(),
+                    wrapper.display()
+                ))
+            })?
+        };
+        if extension_artifact_archive_member_is_legal(relative) && *mode != 0o644 {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive {} legal member {} must have exact tar header mode 0644, got {:04o}",
+                archive_path.display(),
+                archive_member.display(),
+                mode
+            )));
+        }
+    }
+    Ok(())
+}
+
+fn extension_artifact_archive_member_is_legal(relative: &Path) -> bool {
+    relative == Path::new("LICENSE")
+        || relative == Path::new("THIRD_PARTY_NOTICES.md")
+        || relative.starts_with("THIRD_PARTY_LICENSES")
+        || relative.starts_with("files/share/licenses")
+}
+
+fn validate_archive_entry_plan(
+    relative: &Path,
+    is_dir: bool,
+    seen_files: &mut BTreeSet,
+    seen_dirs: &mut BTreeSet,
+) -> Result<()> {
+    let mut ancestors = relative.ancestors();
+    let _ = ancestors.next();
+    for ancestor in ancestors {
+        if ancestor.as_os_str().is_empty() {
+            continue;
+        }
+        if seen_files.contains(ancestor) {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive entry {} is nested under file entry {}",
+                relative.display(),
+                ancestor.display()
+            )));
+        }
+    }
+    if is_dir {
+        if seen_files.contains(relative) {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive has both file and directory entries for {}",
+                relative.display()
+            )));
+        }
+        if !seen_dirs.insert(relative.to_path_buf()) {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive repeats directory entry {}",
+                relative.display()
+            )));
+        }
+    } else {
+        if seen_dirs.contains(relative) {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive has both directory and file entries for {}",
+                relative.display()
+            )));
+        }
+        if !seen_files.insert(relative.to_path_buf()) {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact archive repeats file entry {}",
+                relative.display()
+            )));
+        }
+    }
+    Ok(())
+}
+
+fn extracted_extension_artifact_root(destination: &Path) -> Result {
+    if destination.join("manifest.properties").is_file() {
+        return Ok(destination.to_path_buf());
+    }
+    let mut children = fs::read_dir(destination)
+        .map_err(|err| {
+            Error::Engine(format!(
+                "read prebuilt extension artifact extraction dir {}: {err}",
+                destination.display()
+            ))
+        })?
+        .collect::, _>>()
+        .map_err(|err| {
+            Error::Engine(format!(
+                "read entry in prebuilt extension artifact extraction dir {}: {err}",
+                destination.display()
+            ))
+        })?;
+    children.sort_by_key(|entry| entry.file_name());
+    if let [nested] = children.as_slice() {
+        let file_type = nested.file_type().map_err(|err| {
+            Error::Engine(format!(
+                "inspect top-level prebuilt extension artifact archive entry {}: {err}",
+                nested.path().display()
+            ))
+        })?;
+        if file_type.is_dir() && nested.path().join("manifest.properties").is_file() {
+            return Ok(nested.path());
+        }
+    }
+    Err(Error::InvalidConfig(format!(
+        "prebuilt extension artifact archive extracted to {} but did not contain manifest.properties at archive root or under exactly one top-level directory with no sibling entries",
+        destination.display()
+    )))
+}
diff --git a/src/runtimes/liboliphaunt-native/packaging/src/lib.rs b/src/runtimes/liboliphaunt-native/packaging/src/lib.rs
new file mode 100644
index 000000000..6e82905ef
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/packaging/src/lib.rs
@@ -0,0 +1,3119 @@
+use std::collections::{BTreeMap, BTreeSet};
+use std::fs::{self, File};
+use std::io;
+use std::path::{Path, PathBuf};
+use std::time::{SystemTime, UNIX_EPOCH};
+
+use sha2::{Digest, Sha256};
+
+use liboliphaunt_native_bindings::Extension;
+use liboliphaunt_native_bindings::{
+    NativePackagingCatalogProfile, NativePackagingResources as MaterializedNativeResources,
+    materialize_native_packaging_resources,
+};
+
+/// Error returned by native packaging tooling.
+///
+/// Packaging validation and filesystem failures are intentionally owned by
+/// this unpublished tooling crate. Native binding failures retain their source.
+#[derive(Debug)]
+pub enum Error {
+    /// A packaging option, manifest, artifact, or command-line value is invalid.
+    InvalidConfig(String),
+    /// A packaging filesystem, archive, or subprocess operation failed.
+    Engine(String),
+    /// Native bindings failed while materializing runtime resources.
+    Oliphaunt(liboliphaunt_native_bindings::Error),
+}
+
+impl std::fmt::Display for Error {
+    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::InvalidConfig(message) | Self::Engine(message) => formatter.write_str(message),
+            Self::Oliphaunt(error) => error.fmt(formatter),
+        }
+    }
+}
+
+impl std::error::Error for Error {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            Self::Oliphaunt(error) => Some(error),
+            Self::InvalidConfig(_) | Self::Engine(_) => None,
+        }
+    }
+}
+
+impl From for Error {
+    fn from(error: liboliphaunt_native_bindings::Error) -> Self {
+        Self::Oliphaunt(error)
+    }
+}
+
+/// Result returned by native packaging tooling.
+pub type Result = std::result::Result;
+
+mod catalog;
+mod extension_artifact;
+mod manifest;
+mod package;
+mod static_registry;
+
+use extension_artifact::*;
+use manifest::*;
+use package::*;
+use static_registry::*;
+
+const RUNTIME_RESOURCES_SCHEMA: &str = "oliphaunt-runtime-resources-v1";
+const EXTENSION_ARTIFACT_LAYOUT: &str = "oliphaunt-extension-artifact-v1";
+const EXTENSION_ARTIFACT_NATIVE_RUNTIME_PRODUCT: &str = "liboliphaunt-native";
+const EXTENSION_ARTIFACT_MANIFEST_KEYS: [&str; 22] = [
+    "packageLayout",
+    "pgMajor",
+    "sqlName",
+    "createsExtension",
+    "nativeModuleStem",
+    "nativeModuleFile",
+    "nativeTarget",
+    "nativeRuntimeProduct",
+    "nativeRuntimeVersion",
+    "dependencies",
+    "dataFiles",
+    "extensionSqlFileNames",
+    "extensionSqlFilePrefixes",
+    "sharedPreloadLibraries",
+    "mobilePrebuilt",
+    "mobileStaticArchives",
+    "mobileStaticDependencyArchives",
+    "staticSymbolPrefix",
+    "staticSymbolAliases",
+    "licenseFiles",
+    "licenseProfile",
+    "files",
+];
+const RUNTIME_FILES_LAYOUT: &str = "postgres-runtime-files-v1";
+const STATIC_REGISTRY_PACKAGE_LAYOUT: &str = "oliphaunt-static-registry-v1";
+const STATIC_REGISTRY_SOURCE_FILE: &str = "oliphaunt_static_registry.c";
+const STATIC_REGISTRY_SOURCE_MANIFEST_VALUE: &str = "static-registry/oliphaunt_static_registry.c";
+// Resource-relative directory under the runtime path `static-registry/archives`.
+const STATIC_REGISTRY_ARCHIVES_DIR: &str = "archives";
+
+fn extension_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
+    file_name == format!("{sql_name}.control")
+        || file_name == format!("{sql_name}.sql")
+        || extension_install_sql_file_belongs(sql_name, file_name)
+        || extension_versioned_sql_file_belongs(sql_name, file_name)
+        || catalog::by_sql_name(sql_name).is_some_and(|extension| {
+            extension
+                .extension_sql_file_names
+                .iter()
+                .any(|name| name == file_name)
+                || (file_name.ends_with(".sql")
+                    && extension
+                        .extension_sql_file_prefixes
+                        .iter()
+                        .any(|prefix| file_name.starts_with(prefix)))
+        })
+}
+
+fn extension_versioned_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
+    file_name
+        .strip_prefix(&format!("{sql_name}--"))
+        .and_then(|value| value.strip_suffix(".sql"))
+        .is_some_and(|version_path| {
+            !version_path.is_empty()
+                && version_path
+                    .bytes()
+                    .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
+        })
+}
+
+fn extension_install_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
+    let Some(version) = file_name
+        .strip_prefix(&format!("{sql_name}--"))
+        .and_then(|value| value.strip_suffix(".sql"))
+    else {
+        return false;
+    };
+    !version.is_empty()
+        && !version.contains("--")
+        && version.as_bytes()[0].is_ascii_digit()
+        && version
+            .bytes()
+            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
+}
+
+/// Options for building platform SDK runtime resources.
+#[derive(Debug, Clone)]
+pub struct NativeRuntimeResourceOptions {
+    /// Directory that receives the generated `oliphaunt/...` resource tree.
+    pub output_dir: PathBuf,
+    /// Exact PostgreSQL extensions made available by these runtime resources.
+    pub extensions: Vec,
+    /// Optional runtime data/features made available by these resources.
+    pub runtime_features: Vec,
+    /// Replace an existing `liboliphaunt` resource tree under `output_dir`.
+    pub replace_existing: bool,
+    /// Fail packaging when selected native-module extensions do not have a
+    /// mobile static-registry entry.
+    pub require_mobile_static_registry: bool,
+    /// Native module stems that the platform build has registered for static
+    /// mobile loading.
+    pub mobile_static_module_stems: Vec,
+    /// Exact third-party extension artifacts that are already built for the
+    /// target PostgreSQL runtime.
+    pub prebuilt_extensions: Vec,
+    /// Exact stable `liboliphaunt-native` version selected by the package.
+    ///
+    /// This is required whenever `prebuilt_extensions` is non-empty. Every
+    /// artifact must declare the same version in `nativeRuntimeVersion`.
+    pub native_runtime_version: Option,
+    /// Public artifact target the runtime resources are being packaged for.
+    ///
+    /// This is required for every prebuilt artifact that declares a native
+    /// module, including iOS and Android artifacts whose modules are linked
+    /// through `mobile-static` archives instead of copied as dynamic modules.
+    pub extension_target: Option,
+}
+
+impl NativeRuntimeResourceOptions {
+    /// Create options for native-direct runtime resources.
+    pub fn new(output_dir: impl Into) -> Self {
+        Self {
+            output_dir: output_dir.into(),
+            extensions: Vec::new(),
+            runtime_features: Vec::new(),
+            replace_existing: false,
+            require_mobile_static_registry: false,
+            mobile_static_module_stems: Vec::new(),
+            prebuilt_extensions: Vec::new(),
+            native_runtime_version: None,
+            extension_target: None,
+        }
+    }
+
+    /// Add one exact PostgreSQL extension to the runtime resources.
+    pub fn extension(mut self, extension: Extension) -> Self {
+        self.extensions.push(extension);
+        self
+    }
+
+    /// Add optional runtime features to the resource bundle.
+    pub fn runtime_features(
+        mut self,
+        features: impl IntoIterator,
+    ) -> Self {
+        self.runtime_features.extend(features);
+        self
+    }
+
+    /// Allow replacement of an existing generated `liboliphaunt` resource tree.
+    pub fn replace_existing(mut self, replace_existing: bool) -> Self {
+        self.replace_existing = replace_existing;
+        self
+    }
+
+    /// Require every selected native-module extension to be mobile static-ready.
+    pub fn require_mobile_static_registry(mut self, required: bool) -> Self {
+        self.require_mobile_static_registry = required;
+        self
+    }
+
+    /// Declare native module stems as present in the platform static registry.
+    pub fn mobile_static_module_stems(mut self, stems: Vec) -> Self {
+        self.mobile_static_module_stems.extend(stems);
+        self
+    }
+
+    /// Add one exact prebuilt extension artifact directory.
+    pub fn prebuilt_extension(mut self, root: impl Into) -> Self {
+        self.prebuilt_extensions
+            .push(NativePrebuiltExtensionArtifact::new(root));
+        self
+    }
+
+    /// Select the exact stable `liboliphaunt-native` version for prebuilt
+    /// extension compatibility checks.
+    pub fn native_runtime_version(mut self, version: impl Into) -> Self {
+        self.native_runtime_version = Some(version.into());
+        self
+    }
+
+    /// Set the public artifact target these runtime resources are packaged for.
+    pub fn extension_target(mut self, target: impl Into) -> Self {
+        self.extension_target = Some(target.into());
+        self
+    }
+}
+
+/// Optional runtime data/features selected independently from PostgreSQL
+/// extensions.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum NativeRuntimeFeature {
+    /// ICU locale/collation data under `share/icu`.
+    Icu,
+}
+
+impl NativeRuntimeFeature {
+    /// Stable manifest/CLI spelling for this runtime feature.
+    pub fn as_str(self) -> &'static str {
+        match self {
+            Self::Icu => "icu",
+        }
+    }
+}
+
+/// One exact third-party extension artifact that has already been built.
+///
+/// The artifact may be an unpacked directory, `.tar`, `.tar.gz` (or `.tgz`),
+/// or `.tar.zst`. Its root must contain `manifest.properties` with
+/// `packageLayout=oliphaunt-extension-artifact-v1` and a `files/` tree whose
+/// paths mirror PostgreSQL runtime paths, such as
+/// `files/share/postgresql/extension/.control`.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NativePrebuiltExtensionArtifact {
+    /// Artifact root directory or archive file.
+    pub root: PathBuf,
+}
+
+impl NativePrebuiltExtensionArtifact {
+    /// Create a prebuilt extension artifact reference.
+    pub fn new(root: impl Into) -> Self {
+        Self { root: root.into() }
+    }
+}
+
+/// One mobile static-registry symbol alias for an exact prebuilt extension.
+///
+/// `sql_symbol` is the C symbol name referenced by extension SQL. `linked_symbol`
+/// is the actual C identifier exported by the carried mobile static archive.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NativeExtensionStaticSymbolAlias {
+    /// SQL-visible C symbol name.
+    pub sql_symbol: String,
+    /// Link-time C identifier in the mobile static archive.
+    pub linked_symbol: String,
+}
+
+impl NativeExtensionStaticSymbolAlias {
+    /// Create a static-registry symbol alias.
+    pub fn new(sql_symbol: impl Into, linked_symbol: impl Into) -> Self {
+        Self {
+            sql_symbol: sql_symbol.into(),
+            linked_symbol: linked_symbol.into(),
+        }
+    }
+}
+
+/// Legal payload profile carried by one native prebuilt extension artifact.
+///
+/// The profile determines the exact release-notice leaves at the artifact
+/// root. External artifacts additionally declare their exact PostgreSQL-
+/// relative upstream license paths in their manifest.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum NativeExtensionArtifactLicenseProfile {
+    /// Contrib payload carrying PostgreSQL notices.
+    ContribNative,
+    /// Contrib payload carrying PostgreSQL and embedded OpenSSL notices.
+    ContribNativeOpenSsl,
+    /// Independently versioned external-extension payload.
+    ExternalNative,
+}
+
+impl NativeExtensionArtifactLicenseProfile {
+    /// Stable `manifest.properties` spelling.
+    pub fn as_str(self) -> &'static str {
+        match self {
+            Self::ContribNative => "contrib-native",
+            Self::ContribNativeOpenSsl => "contrib-native-openssl",
+            Self::ExternalNative => "external-native",
+        }
+    }
+
+    /// Parse the stable `manifest.properties` spelling.
+    pub fn parse(value: &str) -> Result {
+        match value {
+            "contrib-native" => Ok(Self::ContribNative),
+            "contrib-native-openssl" => Ok(Self::ContribNativeOpenSsl),
+            "external-native" => Ok(Self::ExternalNative),
+            _ => Err(Error::InvalidConfig(format!(
+                "unsupported native extension artifact license profile '{value}'; expected contrib-native, contrib-native-openssl, or external-native"
+            ))),
+        }
+    }
+}
+
+/// Mobile static-registry readiness of generated runtime resources.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum MobileStaticRegistryState {
+    /// The selected extensions do not require native modules.
+    NotRequired,
+    /// Every selected native-module extension has a mobile static-registry row.
+    Complete,
+    /// At least one selected native-module extension still needs registry work.
+    Pending,
+}
+
+impl MobileStaticRegistryState {
+    fn as_manifest_value(self) -> &'static str {
+        match self {
+            Self::NotRequired => "not-required",
+            Self::Complete => "complete",
+            Self::Pending => "pending",
+        }
+    }
+}
+
+/// Mobile static-registry metadata recorded in generated runtime resources.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct MobileStaticRegistryMetadata {
+    /// Runtime-resource readiness state.
+    pub state: MobileStaticRegistryState,
+    /// Selected SQL extension names that are registered for mobile static use.
+    pub registered_extensions: Vec,
+    /// Selected SQL extension names that still need mobile static registry rows.
+    pub pending_extensions: Vec,
+    /// Native module stems required by the selected extensions.
+    pub native_module_stems: Vec,
+}
+
+/// Size report for generated runtime resources.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NativeRuntimeResourceSizeReport {
+    /// Stable TSV report path under the resource root.
+    pub path: PathBuf,
+    /// Bytes in runtime and static-registry resource trees. This
+    /// intentionally excludes the report file itself to avoid circular output.
+    pub package_bytes: u64,
+    /// Bytes in `runtime/files`.
+    pub runtime_bytes: u64,
+    /// Bytes in `static-registry`.
+    pub static_registry_bytes: u64,
+    /// De-duplicated bytes for all selected extension assets present in the
+    /// runtime tree.
+    pub selected_extension_bytes: u64,
+    /// Per-extension asset footprints.
+    pub extensions: Vec,
+}
+
+/// Size report row for one selected extension.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ExtensionSizeReport {
+    /// SQL extension name.
+    pub name: String,
+    /// Number of runtime files counted for this extension.
+    pub file_count: usize,
+    /// Runtime bytes counted for this extension.
+    pub bytes: u64,
+}
+
+/// Runtime resources generated by the Rust SDK and consumed by Swift, Kotlin,
+/// and React Native SDKs.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NativeRuntimeResources {
+    /// Root directory containing runtime and static-registry resources.
+    pub root: PathBuf,
+    /// Runtime files directory copied into app storage before opening.
+    pub runtime_files: PathBuf,
+    /// Content key of the source runtime cache.
+    pub runtime_cache_key: String,
+    /// Built-in extensions materialized into the runtime resources.
+    pub extensions: Vec,
+    /// Optional runtime features materialized into the runtime resources.
+    pub runtime_features: Vec,
+    /// Exact extension names materialized into the runtime resources, including
+    /// built-in and concrete prebuilt extension artifacts.
+    pub extension_names: Vec,
+    /// Mobile static-registry metadata for the materialized runtime resources.
+    pub mobile_static_registry: MobileStaticRegistryMetadata,
+    /// PostgreSQL shared-preload libraries required by the selected extensions.
+    pub shared_preload_libraries: Vec,
+    /// Static registry manifest generated for platform SDK resources.
+    pub static_registry_manifest: PathBuf,
+    /// Generated static registry source when the runtime resources are
+    /// mobile-ready.
+    pub static_registry_source: Option,
+    /// Package and extension size report.
+    pub size_report: NativeRuntimeResourceSizeReport,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+struct RuntimeResourceExtension {
+    sql_name: String,
+    native_runtime_version: Option,
+    creates_extension: bool,
+    native_module_stem: Option,
+    native_module_file: Option,
+    native_target: Option,
+    dependencies: Vec,
+    data_files: Vec,
+    extension_sql_file_names: Vec,
+    extension_sql_file_prefixes: Vec,
+    shared_preload_libraries: Vec,
+    mobile_prebuilt: bool,
+    mobile_static_archives: Vec,
+    mobile_static_dependency_archives: Vec,
+    static_symbol_prefix: Option,
+    static_symbol_aliases: Vec,
+    license_profile: Option,
+    license_files: Vec,
+    source: RuntimeResourceExtensionSource,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum RuntimeResourceExtensionSource {
+    BuiltIn(Extension),
+    Prebuilt { root: PathBuf, files_root: PathBuf },
+}
+
+#[derive(Debug)]
+struct PreparedPrebuiltExtensionArtifacts {
+    artifacts: Vec,
+    extraction_root: Option,
+}
+
+impl PreparedPrebuiltExtensionArtifacts {
+    fn prepare(artifacts: &[NativePrebuiltExtensionArtifact]) -> Result {
+        let mut prepared = Vec::new();
+        let mut extraction_root = None;
+        for (index, artifact) in artifacts.iter().enumerate() {
+            if artifact.root.is_dir() {
+                prepared.push(artifact.clone());
+            } else if artifact.root.is_file() {
+                let root = extraction_root.get_or_insert_with(unique_extension_extraction_root);
+                fs::create_dir_all(&root).map_err(|err| {
+                    Error::Engine(format!(
+                        "create prebuilt extension artifact extraction root {}: {err}",
+                        root.display()
+                    ))
+                })?;
+                let destination = root.join(format!("artifact-{index}"));
+                let extracted_root =
+                    extract_prebuilt_extension_archive(&artifact.root, &destination)?;
+                prepared.push(NativePrebuiltExtensionArtifact::new(extracted_root));
+            } else {
+                return Err(Error::InvalidConfig(format!(
+                    "prebuilt extension artifact {} must be an unpacked directory, .tar archive, .tar.gz/.tgz archive, or .tar.zst archive",
+                    artifact.root.display()
+                )));
+            }
+        }
+        Ok(Self {
+            artifacts: prepared,
+            extraction_root,
+        })
+    }
+
+    fn artifacts(&self) -> &[NativePrebuiltExtensionArtifact] {
+        &self.artifacts
+    }
+}
+
+impl Drop for PreparedPrebuiltExtensionArtifacts {
+    fn drop(&mut self) {
+        if let Some(root) = &self.extraction_root {
+            let _ = fs::remove_dir_all(root);
+        }
+    }
+}
+
+/// Build the portable runtime-resource layout consumed by platform SDK
+/// packaging.
+pub fn build_native_runtime_resources(
+    options: NativeRuntimeResourceOptions,
+) -> Result {
+    if options.output_dir.as_os_str().is_empty() {
+        return Err(Error::InvalidConfig(
+            "native runtime-resource output directory must not be empty".to_owned(),
+        ));
+    }
+
+    let expected_native_runtime_version = expected_prebuilt_native_runtime_version(&options)?;
+    let prebuilt_artifacts =
+        PreparedPrebuiltExtensionArtifacts::prepare(&options.prebuilt_extensions)?;
+    let selected_extensions =
+        resolve_runtime_resource_extensions(&options.extensions, prebuilt_artifacts.artifacts())?;
+    validate_prebuilt_native_runtime_versions(
+        &selected_extensions,
+        expected_native_runtime_version,
+    )?;
+    validate_prebuilt_extension_targets(&selected_extensions, options.extension_target.as_deref())?;
+    let runtime_features = normalize_runtime_features(&options.runtime_features);
+    let extensions = built_in_extensions(&selected_extensions);
+    let extension_names = selected_extension_names(&selected_extensions);
+    let shared_preload_libraries = shared_preload_libraries(&selected_extensions);
+    let mobile_static_registry =
+        mobile_static_registry_metadata(&selected_extensions, &options.mobile_static_module_stems)?;
+    if options.require_mobile_static_registry {
+        require_mobile_static_registry_ready(&mobile_static_registry)?;
+    }
+    let catalog_profile = if runtime_features.contains(&NativeRuntimeFeature::Icu) {
+        NativePackagingCatalogProfile::Icu
+    } else {
+        NativePackagingCatalogProfile::Standard
+    };
+    let materialized = materialize_native_packaging_resources(&extensions, catalog_profile)?;
+    let root = options.output_dir.join("oliphaunt");
+    prepare_output_root(&root, options.replace_existing)?;
+
+    write_runtime_resource_tree(
+        &root,
+        &materialized,
+        &selected_extensions,
+        &runtime_features,
+        &shared_preload_libraries,
+        &mobile_static_registry,
+        options.extension_target.as_deref(),
+    )?;
+    let size_report = runtime_resource_size_report(
+        &root,
+        &selected_extensions,
+        options.extension_target.as_deref(),
+        &mobile_static_registry,
+    )?;
+    write_runtime_resource_size_report(&size_report)?;
+
+    Ok(NativeRuntimeResources {
+        runtime_files: root.join("runtime/files"),
+        static_registry_manifest: root.join("static-registry/manifest.properties"),
+        static_registry_source: (mobile_static_registry.state
+            == MobileStaticRegistryState::Complete)
+            .then(|| root.join(format!("static-registry/{STATIC_REGISTRY_SOURCE_FILE}"))),
+        root,
+        runtime_cache_key: materialized.runtime_cache_key,
+        extensions,
+        runtime_features,
+        extension_names,
+        mobile_static_registry,
+        shared_preload_libraries,
+        size_report,
+    })
+}
+
+fn expected_prebuilt_native_runtime_version(
+    options: &NativeRuntimeResourceOptions,
+) -> Result> {
+    let version = options.native_runtime_version.as_deref();
+    if let Some(version) = version {
+        validate_stable_semver(
+            version,
+            "selected liboliphaunt-native version for prebuilt extension packaging",
+        )?;
+    }
+    if !options.prebuilt_extensions.is_empty() && version.is_none() {
+        return Err(Error::InvalidConfig(
+            "prebuilt extension packaging requires an exact stable liboliphaunt-native version; set NativeRuntimeResourceOptions::native_runtime_version(...) or pass --liboliphaunt-native-version "
+                .to_owned(),
+        ));
+    }
+    Ok(version)
+}
+
+fn validate_prebuilt_native_runtime_versions(
+    extensions: &[RuntimeResourceExtension],
+    expected: Option<&str>,
+) -> Result<()> {
+    for extension in extensions {
+        if !matches!(
+            extension.source,
+            RuntimeResourceExtensionSource::Prebuilt { .. }
+        ) {
+            continue;
+        }
+        let expected = expected.ok_or_else(|| {
+            Error::InvalidConfig(
+                "prebuilt extension packaging requires an exact stable liboliphaunt-native version"
+                    .to_owned(),
+            )
+        })?;
+        let actual = extension
+            .native_runtime_version
+            .as_deref()
+            .expect("validated v1 prebuilt extension manifests carry nativeRuntimeVersion");
+        if actual != expected {
+            return Err(Error::InvalidConfig(format!(
+                "prebuilt extension artifact for '{}' requires liboliphaunt-native version '{}', but runtime packaging selected '{}'",
+                extension.sql_name, actual, expected
+            )));
+        }
+    }
+    Ok(())
+}
+
+fn validate_prebuilt_extension_targets(
+    extensions: &[RuntimeResourceExtension],
+    extension_target: Option<&str>,
+) -> Result<()> {
+    for extension in extensions {
+        if !matches!(
+            extension.source,
+            RuntimeResourceExtensionSource::Prebuilt { .. }
+        ) || extension.native_module_stem.is_none()
+        {
+            continue;
+        }
+        validate_prebuilt_extension_target(extension, extension_target)?;
+    }
+    Ok(())
+}
+
+fn normalize_runtime_features(features: &[NativeRuntimeFeature]) -> Vec {
+    let normalized = features.iter().copied().collect::>();
+    normalized.into_iter().collect()
+}
+
+fn runtime_feature_names(features: &[NativeRuntimeFeature]) -> Vec<&'static str> {
+    features.iter().map(|feature| feature.as_str()).collect()
+}
+
+fn resolve_runtime_resource_extensions(
+    built_in: &[Extension],
+    prebuilt_artifacts: &[NativePrebuiltExtensionArtifact],
+) -> Result> {
+    let mut prebuilt = BTreeMap::new();
+    for artifact in prebuilt_artifacts {
+        let extension = load_prebuilt_extension_artifact(&artifact.root)?;
+        if prebuilt
+            .insert(extension.sql_name.clone(), extension)
+            .is_some()
+        {
+            return Err(Error::InvalidConfig(
+                "prebuilt extension artifacts must not repeat the same SQL extension name"
+                    .to_owned(),
+            ));
+        }
+    }
+
+    let mut requested = built_in
+        .iter()
+        .map(|extension| extension.sql_name().to_owned())
+        .collect::>();
+    requested.extend(prebuilt.keys().cloned());
+
+    let mut resolved = Vec::new();
+    let mut visiting = BTreeSet::new();
+    let mut visited = BTreeSet::new();
+    for sql_name in requested {
+        visit_runtime_resource_extension(
+            &sql_name,
+            &prebuilt,
+            &mut visiting,
+            &mut visited,
+            &mut resolved,
+        )?;
+    }
+    Ok(resolved)
+}
+
+fn visit_runtime_resource_extension(
+    sql_name: &str,
+    prebuilt: &BTreeMap,
+    visiting: &mut BTreeSet,
+    visited: &mut BTreeSet,
+    resolved: &mut Vec,
+) -> Result<()> {
+    if visited.contains(sql_name) {
+        return Ok(());
+    }
+    if !visiting.insert(sql_name.to_owned()) {
+        return Err(Error::InvalidConfig(format!(
+            "cyclic native extension dependency involving '{sql_name}'"
+        )));
+    }
+
+    let (extension, dependencies) = if let Some(extension) = prebuilt.get(sql_name) {
+        (
+            extension.clone(),
+            extension
+                .dependencies()
+                .into_iter()
+                .map(str::to_owned)
+                .collect::>(),
+        )
+    } else {
+        let Some(extension) = Extension::by_sql_name(sql_name) else {
+            return Err(Error::InvalidConfig(format!(
+                "selected extension '{sql_name}' is neither built into this Oliphaunt release nor provided as a prebuilt extension artifact"
+            )));
+        };
+        let selected_extension = built_in_runtime_resource_extension(extension);
+        (
+            selected_extension,
+            catalog::for_extension(extension).dependencies.clone(),
+        )
+    };
+
+    for dependency in dependencies {
+        visit_runtime_resource_extension(&dependency, prebuilt, visiting, visited, resolved)?;
+    }
+    visiting.remove(sql_name);
+    visited.insert(sql_name.to_owned());
+    resolved.push(extension);
+    Ok(())
+}
+
+fn built_in_runtime_resource_extension(extension: Extension) -> RuntimeResourceExtension {
+    let catalog = catalog::for_extension(extension);
+    RuntimeResourceExtension {
+        sql_name: catalog.sql_name.clone(),
+        native_runtime_version: None,
+        creates_extension: catalog.creates_extension,
+        native_module_stem: catalog.native_module_stem.clone(),
+        native_module_file: catalog
+            .native_module_stem
+            .as_deref()
+            .map(|stem| format!("{stem}{}", std::env::consts::DLL_SUFFIX)),
+        native_target: None,
+        dependencies: catalog.dependencies.clone(),
+        data_files: catalog
+            .runtime_share_data_files
+            .iter()
+            .map(PathBuf::from)
+            .collect(),
+        extension_sql_file_names: catalog.extension_sql_file_names.clone(),
+        extension_sql_file_prefixes: catalog.extension_sql_file_prefixes.clone(),
+        shared_preload_libraries: catalog.shared_preload_libraries.clone(),
+        mobile_prebuilt: true,
+        mobile_static_archives: Vec::new(),
+        mobile_static_dependency_archives: Vec::new(),
+        static_symbol_prefix: None,
+        static_symbol_aliases: Vec::new(),
+        license_profile: None,
+        license_files: Vec::new(),
+        source: RuntimeResourceExtensionSource::BuiltIn(extension),
+    }
+}
+
+fn built_in_extensions(extensions: &[RuntimeResourceExtension]) -> Vec {
+    extensions
+        .iter()
+        .filter_map(|extension| match extension.source {
+            RuntimeResourceExtensionSource::BuiltIn(extension) => Some(extension),
+            RuntimeResourceExtensionSource::Prebuilt { .. } => None,
+        })
+        .collect()
+}
+
+fn selected_extension_names(extensions: &[RuntimeResourceExtension]) -> Vec {
+    let mut names = extensions
+        .iter()
+        .map(|extension| extension.sql_name.clone())
+        .collect::>();
+    names.sort();
+    names.dedup();
+    names
+}
+
+fn createable_extension_names(extensions: &[RuntimeResourceExtension]) -> Vec {
+    let mut names = extensions
+        .iter()
+        .filter(|extension| extension.creates_extension)
+        .map(|extension| extension.sql_name.clone())
+        .collect::>();
+    names.sort();
+    names.dedup();
+    names
+}
+
+fn load_prebuilt_extension_artifact(root: &Path) -> Result {
+    let manifest_path = root.join("manifest.properties");
+    let manifest_text = fs::read_to_string(&manifest_path).map_err(|err| {
+        Error::InvalidConfig(format!(
+            "read prebuilt extension artifact manifest {}: {err}",
+            manifest_path.display()
+        ))
+    })?;
+    let manifest = parse_canonical_properties_manifest(
+        &manifest_path,
+        &manifest_text,
+        &EXTENSION_ARTIFACT_MANIFEST_KEYS,
+    )?;
+    require_property(
+        &manifest_path,
+        &manifest,
+        "packageLayout",
+        EXTENSION_ARTIFACT_LAYOUT,
+    )?;
+    require_exact_manifest_keys(&manifest_path, &manifest, &EXTENSION_ARTIFACT_MANIFEST_KEYS)?;
+    let pg_major = required_manifest_value(&manifest_path, &manifest, "pgMajor")?;
+    if pg_major != "18" {
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact {} targets PostgreSQL {pg_major}; Oliphaunt native packages require PostgreSQL 18",
+            manifest_path.display()
+        )));
+    }
+    let files_value = manifest
+        .get("files")
+        .map(String::as_str)
+        .unwrap_or("files")
+        .trim();
+    if files_value != "files" {
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact {} must use files=files",
+            manifest_path.display()
+        )));
+    }
+    let files_root = root.join("files");
+    if !files_root.is_dir() {
+        return Err(Error::InvalidConfig(format!(
+            "prebuilt extension artifact {} is missing files/ runtime tree",
+            root.display()
+        )));
+    }
+
+    let sql_name = required_manifest_value(&manifest_path, &manifest, "sqlName")?.to_owned();
+    validate_portable_id(&sql_name, "prebuilt extension sqlName")?;
+    require_property(
+        &manifest_path,
+        &manifest,
+        "nativeRuntimeProduct",
+        EXTENSION_ARTIFACT_NATIVE_RUNTIME_PRODUCT,
+    )?;
+    let native_runtime_version =
+        required_manifest_value(&manifest_path, &manifest, "nativeRuntimeVersion")?.to_owned();
+    validate_stable_semver(
+        &native_runtime_version,
+        "prebuilt extension nativeRuntimeVersion",
+    )?;
+    let creates_extension = parse_manifest_yes_no(&manifest_path, &manifest, "createsExtension")?;
+    let native_module_stem = optional_manifest_id(&manifest_path, &manifest, "nativeModuleStem")?;
+    let native_module_file = optional_manifest_id(&manifest_path, &manifest, "nativeModuleFile")?;
+    if native_module_file.is_some() && native_module_stem.is_none() {
+        return Err(Error::InvalidConfig(format!(
+            "manifest {} uses nativeModuleFile without nativeModuleStem",
+            manifest_path.display()
+        )));
+    }
+    let native_module_file = native_module_stem.as_ref().map(|stem| {
+        native_module_file
+            .clone()
+            .unwrap_or_else(|| format!("{}{}", stem, std::env::consts::DLL_SUFFIX))
+    });
+    let native_target = optional_manifest_id(&manifest_path, &manifest, "nativeTarget")?;
+    if native_module_stem.is_some() && native_target.is_none() {
+        return Err(Error::InvalidConfig(format!(
+            "manifest {} declares nativeModuleStem but is missing nativeTarget",
+            manifest_path.display()
+        )));
+    }
+    let dependencies = parse_manifest_id_list(&manifest_path, &manifest, "dependencies")?;
+    let data_files = parse_manifest_relative_path_list(&manifest_path, &manifest, "dataFiles")?;
+    let extension_sql_file_names =
+        parse_manifest_id_list(&manifest_path, &manifest, "extensionSqlFileNames")?;
+    for file_name in &extension_sql_file_names {
+        if !file_name.ends_with(".sql") {
+            return Err(Error::InvalidConfig(format!(
+                "manifest {} extensionSqlFileNames entry '{}' must be a SQL basename",
+                manifest_path.display(),
+                file_name
+            )));
+        }
+    }
+    let extension_sql_file_prefixes =
+        parse_manifest_id_list(&manifest_path, &manifest, "extensionSqlFilePrefixes")?;
+    for prefix in &extension_sql_file_prefixes {
+        if prefix.contains('.') {
+            return Err(Error::InvalidConfig(format!(
+                "manifest {} extensionSqlFilePrefixes entry '{}' must be a basename prefix without '.'",
+                manifest_path.display(),
+                prefix
+            )));
+        }
+    }
+    let shared_preload_libraries =
+        parse_manifest_id_list(&manifest_path, &manifest, "sharedPreloadLibraries")?;
+    let mobile_prebuilt = parse_manifest_yes_no(&manifest_path, &manifest, "mobilePrebuilt")?;
+    let mobile_static_archives =
+        parse_manifest_mobile_static_archives(&manifest_path, &manifest, "mobileStaticArchives")?;
+    let mobile_static_dependency_archives = parse_manifest_mobile_static_dependency_archives(
+        &manifest_path,
+        &manifest,
+        "mobileStaticDependencyArchives",
+    )?;
+    let static_symbol_prefix =
+        optional_manifest_c_identifier(&manifest_path, &manifest, "staticSymbolPrefix")?;
+    let static_symbol_aliases =
+        parse_manifest_static_symbol_aliases(&manifest_path, &manifest, "staticSymbolAliases")?;
+    let license_files =
+        parse_manifest_relative_path_list(&manifest_path, &manifest, "licenseFiles")?;
+    validate_extension_artifact_license_paths(&manifest_path, &license_files)?;
+    let license_profile = NativeExtensionArtifactLicenseProfile::parse(required_manifest_value(
+        &manifest_path,
+        &manifest,
+        "licenseProfile",
+    )?)?;
+    validate_extension_artifact_license_profile(
+        &manifest_path,
+        &sql_name,
+        native_target.as_deref(),
+        &mobile_static_dependency_archives,
+        license_profile,
+        &license_files,
+    )?;
+    validate_prebuilt_extension_mobile_static_archives(
+        root,
+        &manifest_path,
+        native_module_stem.as_deref(),
+        mobile_prebuilt,
+        &mobile_static_archives,
+    )?;
+    validate_prebuilt_extension_mobile_static_dependency_archives(
+        root,
+        &manifest_path,
+        &mobile_static_archives,
+        &mobile_static_dependency_archives,
+    )?;
+
+    let extension = RuntimeResourceExtension {
+        sql_name,
+        native_runtime_version: Some(native_runtime_version),
+        creates_extension,
+        native_module_stem,
+        native_module_file,
+        native_target,
+        dependencies,
+        data_files,
+        extension_sql_file_names,
+        extension_sql_file_prefixes,
+        shared_preload_libraries,
+        mobile_prebuilt,
+        mobile_static_archives,
+        mobile_static_dependency_archives,
+        static_symbol_prefix,
+        static_symbol_aliases,
+        license_profile: Some(license_profile),
+        license_files,
+        source: RuntimeResourceExtensionSource::Prebuilt {
+            root: root.to_path_buf(),
+            files_root,
+        },
+    };
+    validate_prebuilt_extension_leaf_inventory(root, &manifest_path, &extension)?;
+    Ok(extension)
+}
+
+impl RuntimeResourceExtension {
+    fn dependencies(&self) -> Vec<&str> {
+        self.dependencies.iter().map(String::as_str).collect()
+    }
+}
+
+fn runtime_extension_sql_file_belongs(
+    extension: &RuntimeResourceExtension,
+    file_name: &str,
+) -> bool {
+    (extension.creates_extension
+        && (file_name == format!("{}.control", extension.sql_name)
+            || file_name == format!("{}.sql", extension.sql_name)
+            || (file_name.starts_with(&format!("{}--", extension.sql_name))
+                && file_name.ends_with(".sql"))))
+        || extension
+            .extension_sql_file_names
+            .iter()
+            .any(|name| name == file_name)
+        || (file_name.ends_with(".sql")
+            && extension
+                .extension_sql_file_prefixes
+                .iter()
+                .any(|prefix| file_name.starts_with(prefix)))
+}
+
+fn require_mobile_static_registry_ready(metadata: &MobileStaticRegistryMetadata) -> Result<()> {
+    if metadata.state != MobileStaticRegistryState::Pending {
+        return Ok(());
+    }
+    Err(Error::InvalidConfig(format!(
+        "selected extension(s) require mobile static registry entries before iOS/Android packaging: {}",
+        metadata.pending_extensions.join(",")
+    )))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::time::{SystemTime, UNIX_EPOCH};
+    use tar::EntryType;
+
+    #[test]
+    fn logical_tree_digest_uses_portable_path_order() {
+        let root = tempfile::tempdir().unwrap();
+        fs::create_dir(root.path().join("a")).unwrap();
+        write_file(&root.path().join("a/b"), b"nested");
+        write_file(&root.path().join("a0"), b"flat");
+
+        let windows_native_order = vec![
+            ("a0".to_string(), root.path().join("a0")),
+            ("a/b".to_string(), root.path().join("a/b")),
+        ];
+        let expected = "33fcdf990b4a606acc4d5cdda3ab275513c3a2fa87ae72bafc5f4e1278a2faa3";
+        assert_eq!(
+            logical_tree_sha256_files(windows_native_order).unwrap(),
+            expected
+        );
+        assert_eq!(logical_tree_sha256(root.path()).unwrap(), expected);
+    }
+
+    #[test]
+    fn mobile_static_registry_metadata_marks_sql_only_packages_not_required() {
+        let extensions = runtime_resource_extensions(&[Extension::PGTAP]);
+        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
+        assert_eq!(metadata.state, MobileStaticRegistryState::NotRequired);
+        assert!(metadata.registered_extensions.is_empty());
+        assert!(metadata.pending_extensions.is_empty());
+        assert!(metadata.native_module_stems.is_empty());
+    }
+
+    #[test]
+    fn mobile_static_registry_metadata_marks_module_extensions_pending() {
+        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
+        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
+        assert_eq!(metadata.state, MobileStaticRegistryState::Pending);
+        assert_eq!(metadata.pending_extensions, vec!["vector"]);
+        assert_eq!(metadata.native_module_stems, vec!["vector"]);
+        assert!(metadata.registered_extensions.is_empty());
+    }
+
+    #[test]
+    fn mobile_static_registry_requirement_rejects_pending_modules() {
+        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
+        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
+        let error = require_mobile_static_registry_ready(&metadata).unwrap_err();
+        assert!(matches!(
+            error,
+            Error::InvalidConfig(message)
+                if message
+                    == "selected extension(s) require mobile static registry entries before iOS/Android packaging: vector"
+        ));
+    }
+
+    #[test]
+    fn mobile_static_registry_metadata_marks_declared_modules_complete() {
+        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
+        let metadata =
+            mobile_static_registry_metadata(&extensions, &["vector".to_owned()]).unwrap();
+        assert_eq!(metadata.state, MobileStaticRegistryState::Complete);
+        assert_eq!(metadata.registered_extensions, vec!["vector"]);
+        assert!(metadata.pending_extensions.is_empty());
+        assert_eq!(metadata.native_module_stems, vec!["vector"]);
+        require_mobile_static_registry_ready(&metadata).unwrap();
+    }
+
+    #[test]
+    fn mobile_static_registry_metadata_marks_hstore_complete_after_prebuilt_artifact_support() {
+        let extensions = runtime_resource_extensions(&[Extension::HSTORE]);
+        let metadata =
+            mobile_static_registry_metadata(&extensions, &["hstore".to_owned()]).unwrap();
+        assert_eq!(metadata.state, MobileStaticRegistryState::Complete);
+        assert_eq!(metadata.registered_extensions, vec!["hstore"]);
+        assert!(metadata.pending_extensions.is_empty());
+        assert_eq!(metadata.native_module_stems, vec!["hstore"]);
+        require_mobile_static_registry_ready(&metadata).unwrap();
+    }
+
+    #[test]
+    fn mobile_static_registry_metadata_rejects_unknown_registered_modules() {
+        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
+        let error =
+            mobile_static_registry_metadata(&extensions, &["hstore".to_owned()]).unwrap_err();
+        assert!(matches!(
+            error,
+            Error::InvalidConfig(message)
+                if message
+                    == "mobile static registry module stem(s) were not selected by these runtime resources: hstore"
+        ));
+    }
+
+    #[test]
+    fn manifest_records_mobile_static_registry_metadata() {
+        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
+        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
+        let manifest = RuntimeResourceManifest {
+            cache_key: "runtime-smoke",
+            layout: RUNTIME_FILES_LAYOUT,
+            artifact_role: "runtime",
+            catalog_profile: "",
+            icu_data_tree_sha256: "",
+            extensions: &extensions,
+            runtime_features: &[],
+            shared_preload_libraries: &[],
+            mobile_static_registry: &metadata,
+        };
+        let text = manifest_text(&manifest);
+        assert!(text.contains("selectedExtensions=vector\n"));
+        assert!(text.contains("extensions=vector\n"));
+        assert!(text.contains("sharedPreloadLibraries=\n"));
+        assert!(text.contains("mobileStaticRegistryState=pending\n"));
+        assert!(text.contains("mobileStaticRegistryPending=vector\n"));
+        assert!(text.contains("nativeModuleStems=vector\n"));
+        assert!(text.contains("mobileStaticRegistrySource=\n"));
+        assert_eq!(
+            text.lines()
+                .map(|line| line.split_once('=').unwrap().0)
+                .collect::>(),
+            vec![
+                "schema",
+                "layout",
+                "artifactRole",
+                "catalogProfile",
+                "clusterSeedTarget",
+                "icuDataTreeSha256",
+                "mode",
+                "cacheKey",
+                "selectedExtensions",
+                "extensions",
+                "runtimeFeatures",
+                "sharedPreloadLibraries",
+                "mobileStaticRegistryState",
+                "mobileStaticRegistryRegistered",
+                "mobileStaticRegistryPending",
+                "nativeModuleStems",
+                "mobileStaticRegistrySource",
+            ]
+        );
+    }
+
+    #[test]
+    fn manifest_records_required_shared_preload_libraries() {
+        let extensions =
+            runtime_resource_extensions(&[Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH]);
+        let preload = shared_preload_libraries(&extensions);
+        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
+        let manifest = RuntimeResourceManifest {
+            cache_key: "runtime-smoke",
+            layout: RUNTIME_FILES_LAYOUT,
+            artifact_role: "runtime",
+            catalog_profile: "",
+            icu_data_tree_sha256: "",
+            extensions: &extensions,
+            runtime_features: &[],
+            shared_preload_libraries: &preload,
+            mobile_static_registry: &metadata,
+        };
+        let text = manifest_text(&manifest);
+        assert!(text.contains("selectedExtensions=pg_textsearch\n"));
+        assert!(text.contains("extensions=pg_textsearch\n"));
+        assert!(text.contains("sharedPreloadLibraries=pg_textsearch\n"));
+    }
+
+    #[test]
+    fn manifest_separates_selected_and_createable_extension_domains() {
+        let extensions = runtime_resource_extensions(&[Extension::HSTORE, Extension::AUTO_EXPLAIN]);
+        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
+        let manifest = RuntimeResourceManifest {
+            cache_key: "runtime-domain-smoke",
+            layout: RUNTIME_FILES_LAYOUT,
+            artifact_role: "runtime",
+            catalog_profile: "",
+            icu_data_tree_sha256: "",
+            extensions: &extensions,
+            runtime_features: &[],
+            shared_preload_libraries: &[],
+            mobile_static_registry: &metadata,
+        };
+        let text = manifest_text(&manifest);
+        assert!(text.contains("selectedExtensions=auto_explain,hstore\n"));
+        assert!(text.contains("extensions=hstore\n"));
+        assert!(!text.contains("extensions=auto_explain"));
+    }
+
+    #[test]
+    fn runtime_resource_package_omits_native_icu_files_data() {
+        let temp = unique_temp_root("oliphaunt-runtime-resources-icu-data");
+        let root = temp.join("oliphaunt");
+        let materialized = MaterializedNativeResources {
+            runtime_dir: temp.join("materialized/runtime"),
+            runtime_cache_key: "runtime-icu".to_owned(),
+        };
+        write_file(
+            &materialized
+                .runtime_dir
+                .join("share/postgresql/postgresql.conf.sample"),
+            b"core-runtime",
+        );
+        write_file(
+            &materialized.runtime_dir.join("share/icu/icudt76l.dat"),
+            b"icu-data",
+        );
+        fs::create_dir_all(&root).unwrap();
+
+        let metadata = mobile_static_registry_metadata(&[], &[]).unwrap();
+        write_runtime_resource_tree(&root, &materialized, &[], &[], &[], &metadata, None).unwrap();
+
+        assert!(
+            !root.join("runtime/files/share/icu").exists(),
+            "base runtime-resource packages must not carry ICU data; apps opt in through the ICU package"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn runtime_resource_package_copies_native_icu_data_when_feature_selected() {
+        let temp = unique_temp_root("oliphaunt-runtime-resources-selected-icu-data");
+        let root = temp.join("oliphaunt");
+        let materialized = MaterializedNativeResources {
+            runtime_dir: temp.join("materialized/runtime"),
+            runtime_cache_key: "runtime-icu".to_owned(),
+        };
+        write_file(
+            &materialized
+                .runtime_dir
+                .join("share/postgresql/postgresql.conf.sample"),
+            b"core-runtime",
+        );
+        write_file(
+            &materialized.runtime_dir.join("share/icu/icudt76l.dat"),
+            b"icu-data",
+        );
+        fs::create_dir_all(&root).unwrap();
+
+        let metadata = mobile_static_registry_metadata(&[], &[]).unwrap();
+        write_runtime_resource_tree(
+            &root,
+            &materialized,
+            &[],
+            &[NativeRuntimeFeature::Icu],
+            &[],
+            &metadata,
+            None,
+        )
+        .unwrap();
+
+        assert!(root.join("runtime/files/share/icu/icudt76l.dat").is_file());
+        let manifest = fs::read_to_string(root.join("runtime/manifest.properties")).unwrap();
+        assert!(manifest.contains("runtimeFeatures=icu\n"));
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn package_size_report_counts_selected_extension_assets() {
+        let temp = unique_temp_root("oliphaunt-runtime-resources-size-report");
+        let root = temp.join("oliphaunt");
+        write_file(
+            &root.join("runtime/files/share/postgresql/extension/vector.control"),
+            b"vector-control",
+        );
+        write_file(
+            &root.join("runtime/files/share/postgresql/extension/vector--1.0.sql"),
+            b"vector-sql",
+        );
+        write_file(
+            &root
+                .join("runtime/files/lib/postgresql")
+                .join(format!("vector{}", std::env::consts::DLL_SUFFIX)),
+            b"vector-module",
+        );
+        write_file(
+            &root.join("runtime/files/share/postgresql/postgresql.conf.sample"),
+            b"core-runtime",
+        );
+
+        write_file(
+            &root.join("static-registry/manifest.properties"),
+            b"state=pending\n",
+        );
+
+        let selected_extensions = runtime_resource_extensions(&[Extension::VECTOR]);
+        let metadata = mobile_static_registry_metadata(&selected_extensions, &[]).unwrap();
+        let report = runtime_resource_size_report(
+            &root,
+            &selected_extensions,
+            Some("test-target"),
+            &metadata,
+        )
+        .unwrap();
+        write_runtime_resource_size_report(&report).unwrap();
+
+        let vector_bytes = b"vector-control".len() as u64
+            + b"vector-sql".len() as u64
+            + b"vector-module".len() as u64;
+        assert_eq!(report.selected_extension_bytes, vector_bytes);
+        assert_eq!(report.extensions.len(), 1);
+        assert_eq!(report.extensions[0].name, "vector");
+        assert_eq!(report.extensions[0].file_count, 3);
+        assert_eq!(report.extensions[0].bytes, vector_bytes);
+
+        let text = fs::read_to_string(root.join("package-size.tsv")).unwrap();
+        assert!(text.contains("kind\tid\textensions\tfiles\tbytes\n"));
+        assert!(text.contains(&format!("extensions\tselected\t-\t-\t{vector_bytes}\n")));
+        assert!(text.contains(&format!("extension\tvector\t-\t3\t{vector_bytes}\n")));
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn package_size_report_counts_selected_extension_data_files_under_share() {
+        let temp = unique_temp_root("oliphaunt-runtime-resources-data-file-report");
+        let root = temp.join("oliphaunt");
+        write_file(
+            &root.join("runtime/files/share/postgresql/extension/unaccent.control"),
+            b"unaccent-control",
+        );
+        write_file(
+            &root.join("runtime/files/share/postgresql/extension/unaccent--1.1.sql"),
+            b"unaccent-sql",
+        );
+        write_file(
+            &root.join("runtime/files/share/postgresql/tsearch_data/unaccent.rules"),
+            b"unaccent-rules",
+        );
+        write_file(
+            &root
+                .join("runtime/files/lib/postgresql")
+                .join(format!("unaccent{}", std::env::consts::DLL_SUFFIX)),
+            b"unaccent-module",
+        );
+        write_file(
+            &root.join("runtime/files/share/postgresql/postgresql.conf.sample"),
+            b"core-runtime",
+        );
+
+        write_file(
+            &root.join("static-registry/manifest.properties"),
+            b"state=pending\n",
+        );
+
+        let selected_extensions = runtime_resource_extensions(&[Extension::UNACCENT]);
+        let metadata = mobile_static_registry_metadata(&selected_extensions, &[]).unwrap();
+        let report = runtime_resource_size_report(
+            &root,
+            &selected_extensions,
+            Some("test-target"),
+            &metadata,
+        )
+        .unwrap();
+
+        let unaccent_bytes = b"unaccent-control".len() as u64
+            + b"unaccent-sql".len() as u64
+            + b"unaccent-rules".len() as u64
+            + b"unaccent-module".len() as u64;
+        assert_eq!(report.selected_extension_bytes, unaccent_bytes);
+        assert_eq!(report.extensions.len(), 1);
+        assert_eq!(report.extensions[0].name, "unaccent");
+        assert_eq!(report.extensions[0].file_count, 4);
+        assert_eq!(report.extensions[0].bytes, unaccent_bytes);
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn module_symbol_parser_finds_module_pathname_and_exact_libdir_symbols() {
+        let symbols = module_c_symbols(
+            r#"
+-- Commented AS 'MODULE_PATHNAME', 'ignored_symbol' LANGUAGE C;
+CREATE FUNCTION public.implicit_symbol(integer) RETURNS integer
+  AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
+CREATE OR REPLACE FUNCTION public.explicit_sql_name(integer) RETURNS integer
+  AS 'MODULE_PATHNAME', 'explicit_c_symbol'
+  LANGUAGE C STRICT;
+CREATE OR REPLACE FUNCTION public.spheroid_in(cstring) RETURNS spheroid
+  AS '$libdir/postgis-3', 'ellipsoid_in'
+  LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE;
+CREATE FUNCTION public.default_literal_decoy(text DEFAULT '$libdir/postgis-3') RETURNS integer
+  AS '$libdir/not-postgis-3', 'default_literal_must_not_be_registered' LANGUAGE C;
+CREATE FUNCTION public.as_keyword_decoy(text DEFAULT 'AS ''$libdir/postgis-3'', ''also_not_registered''') RETURNS integer
+  AS '$libdir/not-postgis-3', 'as_literal_must_not_be_registered' LANGUAGE C;
+CREATE FUNCTION public.foreign_module(integer) RETURNS integer
+  AS '$libdir/not-postgis-3', 'must_not_be_registered' LANGUAGE C;
+CREATE FUNCTION sql_only(integer) RETURNS integer
+  LANGUAGE sql AS 'SELECT $1';
+"#,
+            "postgis-3",
+        )
+        .unwrap();
+        assert_eq!(
+            symbols,
+            vec!["ellipsoid_in", "explicit_c_symbol", "implicit_symbol"]
+        );
+    }
+
+    #[test]
+    fn static_registry_source_declares_magic_init_and_sql_symbols() {
+        let modules = vec![StaticRegistryModule {
+            extension_sql_name: "vector".to_owned(),
+            module_stem: "vector".to_owned(),
+            symbol_prefix: "oliphaunt_static_vector".to_owned(),
+            sql_symbols: vec!["vector_in".to_owned(), "vector_out".to_owned()],
+            symbol_aliases: BTreeMap::new(),
+        }];
+        let source = static_registry_source_text(&modules);
+        assert!(source.contains("liboliphaunt_selected_static_extensions"));
+        assert!(source.contains("oliphaunt_static_vector_Pg_magic_func"));
+        assert!(source.contains("oliphaunt_static_vector__PG_init"));
+        assert!(source.contains("OLIPHAUNT_STATIC_OPTIONAL"));
+        assert!(source.contains("extern const void *oliphaunt_static_vector_Pg_magic_func(void);"));
+        assert!(source.contains(
+            "extern void oliphaunt_static_vector__PG_init(void) OLIPHAUNT_STATIC_OPTIONAL;"
+        ));
+        assert!(source.contains("extern void vector_in(void);"));
+        assert!(!source.contains(&format!("OLIPHAUNT_STATIC_{}", "WEAK")));
+        assert!(!source.contains("extern void vector_in(void) OLIPHAUNT_STATIC_OPTIONAL"));
+        assert!(source.contains("{ .name = \"vector_in\", .address = (void *)vector_in }"));
+        assert!(
+            source.contains(
+                "{ .name = \"pg_finfo_vector_in\", .address = (void *)pg_finfo_vector_in }"
+            )
+        );
+        let manifest = static_registry_manifest_text(
+            &MobileStaticRegistryMetadata {
+                state: MobileStaticRegistryState::Complete,
+                registered_extensions: vec!["vector".to_owned()],
+                pending_extensions: vec![],
+                native_module_stems: vec!["vector".to_owned()],
+            },
+            &modules,
+            &[],
+            &[],
+        );
+        assert!(manifest.contains("packageLayout=oliphaunt-static-registry-v1\n"));
+        assert!(manifest.contains("source=oliphaunt_static_registry.c\n"));
+        assert!(manifest.contains("module.vector.sqlSymbols=vector_in,vector_out\n"));
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_is_exact_and_mobile_registry_ready() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-artifact");
+        let artifact = temp.join("acme_ext");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            true,
+        );
+        write_file(
+            &artifact.join("files/share/postgresql/extension/hstore.control"),
+            b"comment = 'should not leak'\n",
+        );
+
+        let error = resolve_runtime_resource_extensions(
+            &[],
+            &[NativePrebuiltExtensionArtifact::new(&artifact)],
+        )
+        .unwrap_err();
+        assert!(
+            error.to_string().contains("contains undeclared extension SQL/control file files/share/postgresql/extension/hstore.control"),
+            "unexpected extra-leaf error: {error}"
+        );
+        fs::remove_file(artifact.join("files/share/postgresql/extension/hstore.control")).unwrap();
+
+        let extensions = resolve_runtime_resource_extensions(
+            &[],
+            &[NativePrebuiltExtensionArtifact::new(&artifact)],
+        )
+        .unwrap();
+        assert_eq!(selected_extension_names(&extensions), vec!["acme_ext"]);
+
+        let runtime_files = temp.join("runtime/files");
+        write_file(
+            &runtime_files.join("share/postgresql/postgresql.conf.sample"),
+            b"core-runtime",
+        );
+
+        let pending_metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
+        copy_prebuilt_extension_artifacts(
+            &runtime_files,
+            &extensions,
+            Some("test-target"),
+            &pending_metadata,
+        )
+        .unwrap();
+
+        assert!(
+            runtime_files
+                .join("share/postgresql/extension/acme_ext.control")
+                .is_file()
+        );
+        assert!(
+            runtime_files
+                .join("share/postgresql/extension/acme_ext--1.0.sql")
+                .is_file()
+        );
+        assert!(
+            runtime_files
+                .join("share/postgresql/data/acme_ext.rules")
+                .is_file()
+        );
+        assert!(
+            runtime_files
+                .join("lib/postgresql")
+                .join(format!("acme_ext{}", std::env::consts::DLL_SUFFIX))
+                .is_file()
+        );
+        assert!(
+            !runtime_files
+                .join("share/postgresql/extension/hstore.control")
+                .exists(),
+            "unselected files inside a prebuilt extension artifact must not leak"
+        );
+
+        let metadata =
+            mobile_static_registry_metadata(&extensions, &["acme_ext".to_owned()]).unwrap();
+        assert_eq!(metadata.state, MobileStaticRegistryState::Complete);
+        assert_eq!(metadata.registered_extensions, vec!["acme_ext"]);
+        assert_eq!(metadata.native_module_stems, vec!["acme_ext"]);
+
+        let modules = static_registry_modules(&runtime_files, &extensions, &metadata).unwrap();
+        assert_eq!(modules.len(), 1);
+        assert_eq!(modules[0].extension_sql_name, "acme_ext");
+        assert_eq!(modules[0].symbol_prefix, "acme_static");
+        assert_eq!(modules[0].sql_symbols, vec!["acme_ext_echo"]);
+        let static_registry_dir = temp.join("oliphaunt/static-registry");
+        let archives = copy_prebuilt_mobile_static_archives(&static_registry_dir, &extensions)
+            .expect("copy selected mobile static archives");
+        assert_eq!(archives.len(), 1);
+        assert_eq!(archives[0].target, "ios-simulator");
+        assert!(
+            static_registry_dir
+                .join(
+                    "archives/ios-simulator/extensions/acme_ext/liboliphaunt_extension_acme_ext.a"
+                )
+                .is_file(),
+            "selected external mobile static archive must be copied into runtime resources"
+        );
+        let dependency_archives =
+            copy_prebuilt_mobile_static_dependency_archives(&static_registry_dir, &extensions)
+                .expect("copy selected mobile static dependency archives");
+        assert_eq!(dependency_archives.len(), 1);
+        assert_eq!(dependency_archives[0].target, "ios-simulator");
+        assert_eq!(dependency_archives[0].name, "openssl");
+        assert!(
+            static_registry_dir
+                .join("archives/ios-simulator/dependencies/openssl/libcrypto.a")
+                .is_file(),
+            "selected external mobile static dependency archive must be copied into runtime resources"
+        );
+        let static_manifest =
+            static_registry_manifest_text(&metadata, &modules, &archives, &dependency_archives);
+        assert!(static_manifest.contains("archiveTargets=ios-simulator\n"));
+        assert!(static_manifest.contains("dependencyArchiveTargets=ios-simulator\n"));
+        assert!(static_manifest.contains("dependencyArchives=openssl\n"));
+        assert!(static_manifest.contains("module.acme_ext.archiveTargets=ios-simulator\n"));
+        assert!(static_manifest.contains(
+            "module.acme_ext.archive.ios-simulator=archives/ios-simulator/extensions/acme_ext/liboliphaunt_extension_acme_ext.a\n"
+        ));
+        assert!(static_manifest.contains("dependency.openssl.archiveTargets=ios-simulator\n"));
+        assert!(static_manifest.contains(
+            "dependency.openssl.archive.ios-simulator=archives/ios-simulator/dependencies/openssl/libcrypto.a\n"
+        ));
+
+        write_file(
+            &temp.join("oliphaunt/static-registry/manifest.properties"),
+            b"state=complete\n",
+        );
+        copy_portable_tree(&runtime_files, &temp.join("oliphaunt/runtime/files")).unwrap();
+        let report = runtime_resource_size_report(
+            &temp.join("oliphaunt"),
+            &extensions,
+            Some("test-target"),
+            &pending_metadata,
+        )
+        .unwrap();
+        assert_eq!(report.extensions.len(), 1);
+        assert_eq!(report.extensions[0].name, "acme_ext");
+        assert_eq!(report.extensions[0].file_count, 5);
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn runtime_resource_packaging_selects_the_engine_module_profile() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-engine-profiles");
+        let artifact = temp.join("acme_ext");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let extensions = resolve_runtime_resource_extensions(
+            &[],
+            &[NativePrebuiltExtensionArtifact::new(&artifact)],
+        )
+        .unwrap();
+        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
+        let module = format!("acme_ext{}", std::env::consts::DLL_SUFFIX);
+        let direct_runtime = temp.join("direct-runtime");
+
+        copy_prebuilt_extension_artifacts(
+            &direct_runtime,
+            &extensions,
+            Some("test-target"),
+            &metadata,
+        )
+        .unwrap();
+        assert_eq!(
+            fs::read(direct_runtime.join("lib/postgresql").join(&module)).unwrap(),
+            b"acme-embedded-module\n"
+        );
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_mobile_static_registry_skips_desktop_dynamic_module() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-mobile-static");
+        let artifact = temp.join("acme_ext");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            true,
+        );
+        let extensions = resolve_runtime_resource_extensions(
+            &[],
+            &[NativePrebuiltExtensionArtifact::new(&artifact)],
+        )
+        .unwrap();
+        let metadata =
+            mobile_static_registry_metadata(&extensions, &["acme_ext".to_owned()]).unwrap();
+        let runtime_files = temp.join("runtime/files");
+        copy_prebuilt_extension_artifacts(
+            &runtime_files,
+            &extensions,
+            Some("ios-xcframework"),
+            &metadata,
+        )
+        .unwrap();
+
+        assert!(
+            runtime_files
+                .join("share/postgresql/extension/acme_ext.control")
+                .is_file()
+        );
+        assert!(
+            !runtime_files
+                .join("lib/postgresql")
+                .join(format!("acme_ext{}", std::env::consts::DLL_SUFFIX))
+                .exists(),
+            "mobile-static extension packaging must not copy a desktop dynamic module"
+        );
+        let root = temp.join("oliphaunt");
+        write_file(
+            &root.join("static-registry/manifest.properties"),
+            b"state=complete\n",
+        );
+        copy_portable_tree(&runtime_files, &root.join("runtime/files")).unwrap();
+
+        let report =
+            runtime_resource_size_report(&root, &extensions, Some("ios-xcframework"), &metadata)
+                .unwrap();
+        assert_eq!(report.extensions[0].file_count, 4);
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn runtime_resource_tree_generates_static_registry_from_packaged_prebuilt_sql() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-packaged-static-registry");
+        let base_runtime = temp.join("base-runtime");
+        write_file(
+            &base_runtime.join("share/postgresql/postgresql.conf.sample"),
+            b"core-runtime\n",
+        );
+        write_file(
+            &base_runtime.join("share/postgresql/extension/plpgsql.control"),
+            b"comment = 'must not leak'\n",
+        );
+        write_file(
+            &base_runtime.join("share/postgresql/extension/plpgsql--1.0.sql"),
+            b"select 'must not leak';\n",
+        );
+        write_file(
+            &base_runtime.join("share/postgresql/extension/acme_ext--base.sql"),
+            b"select 'base acme must not shadow prebuilt';\n",
+        );
+        write_file(
+            &base_runtime
+                .join("lib/postgresql")
+                .join(format!("acme_ext{}", std::env::consts::DLL_SUFFIX)),
+            b"base-acme-module\n",
+        );
+
+        let artifact = temp.join("acme_ext");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            true,
+        );
+        let manifest = artifact.join("manifest.properties");
+        let alias_line = "staticSymbolAliases=acme_ext_echo:acme_static_acme_ext_echo,pg_finfo_acme_ext_echo:acme_static_pg_finfo_acme_ext_echo,helper_symbol:acme_static_helper_symbol\n";
+        let mut manifest_text = fs::read_to_string(&manifest).unwrap();
+        if manifest_text.contains("staticSymbolAliases=\n") {
+            manifest_text = manifest_text.replace("staticSymbolAliases=\n", alias_line);
+        } else {
+            manifest_text.push_str(alias_line);
+        }
+        write_file(&manifest, manifest_text.as_bytes());
+        let extensions = resolve_runtime_resource_extensions(
+            &[],
+            &[NativePrebuiltExtensionArtifact::new(&artifact)],
+        )
+        .unwrap();
+        let metadata =
+            mobile_static_registry_metadata(&extensions, &["acme_ext".to_owned()]).unwrap();
+
+        let root = temp.join("oliphaunt");
+        write_runtime_resource_tree(
+            &root,
+            &MaterializedNativeResources {
+                runtime_dir: base_runtime,
+                runtime_cache_key: "runtime-cache".to_owned(),
+            },
+            &extensions,
+            &[],
+            &[],
+            &metadata,
+            Some("test-target"),
+        )
+        .unwrap();
+
+        let registry_source =
+            fs::read_to_string(root.join("static-registry/oliphaunt_static_registry.c")).unwrap();
+        assert!(registry_source.contains("liboliphaunt_selected_static_extensions"));
+        assert!(
+            registry_source.contains("acme_ext_echo"),
+            "static registry must parse SQL copied from the prebuilt extension artifact"
+        );
+        assert!(
+            registry_source.contains("extern void acme_static_acme_ext_echo(void);"),
+            "static registry must reference aliased link-time symbols"
+        );
+        assert!(
+            registry_source.contains(
+                "{ .name = \"acme_ext_echo\", .address = (void *)acme_static_acme_ext_echo }"
+            ),
+            "static registry must keep SQL symbol names while pointing at aliased symbols"
+        );
+        assert!(
+            registry_source.contains(
+                "{ .name = \"helper_symbol\", .address = (void *)acme_static_helper_symbol }"
+            ),
+            "static registry must include explicit aliases outside main extension SQL"
+        );
+        assert!(
+            root.join("runtime/files/share/postgresql/extension/acme_ext--1.0.sql")
+                .is_file(),
+            "prebuilt SQL must be part of the final runtime package"
+        );
+        assert!(
+            root.join("runtime/files/share/postgresql/extension/plpgsql.control")
+                .is_file(),
+            "PL/pgSQL control metadata is mandatory baseline runtime metadata"
+        );
+        assert!(
+            root.join("runtime/files/share/postgresql/extension/plpgsql--1.0.sql")
+                .is_file(),
+            "PL/pgSQL SQL metadata is mandatory baseline runtime metadata"
+        );
+        assert!(
+            !root
+                .join("runtime/files/share/postgresql/extension/acme_ext--base.sql")
+                .exists(),
+            "base runtime files for a prebuilt-selected extension must not shadow the exact artifact"
+        );
+        assert!(
+            !root
+                .join("runtime/files/lib/postgresql")
+                .join(format!("acme_ext{}", std::env::consts::DLL_SUFFIX))
+                .exists(),
+            "mobile-static prebuilt extensions must not retain base dynamic modules"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_rejects_missing_native_target() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-missing-target");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let manifest = artifact.join("manifest.properties");
+        let text = fs::read_to_string(&manifest).unwrap();
+        fs::write(
+            &manifest,
+            text.replace("nativeTarget=test-target\n", "nativeTarget=\n"),
+        )
+        .unwrap();
+
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error.to_string().contains("missing nativeTarget"),
+            "unexpected missing-target error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_requires_canonical_native_runtime_product() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-native-product");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let manifest = artifact.join("manifest.properties");
+        let canonical = fs::read_to_string(&manifest).unwrap();
+
+        fs::write(
+            &manifest,
+            canonical.replace(
+                "nativeRuntimeProduct=liboliphaunt-native\n",
+                "nativeRuntimeProduct=another-runtime\n",
+            ),
+        )
+        .unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("nativeRuntimeProduct='another-runtime', expected 'liboliphaunt-native'"),
+            "unexpected wrong-product error: {error}"
+        );
+
+        fs::write(
+            &manifest,
+            canonical.replace("nativeRuntimeProduct=liboliphaunt-native\n", ""),
+        )
+        .unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error.to_string().contains("missing=[nativeRuntimeProduct]"),
+            "unexpected missing-product error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_requires_stable_native_runtime_version() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-native-version");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let manifest = artifact.join("manifest.properties");
+        let canonical = fs::read_to_string(&manifest).unwrap();
+
+        fs::write(
+            &manifest,
+            canonical.replace(
+                "nativeRuntimeVersion=1.2.3\n",
+                "nativeRuntimeVersion=1.2.3-rc.1\n",
+            ),
+        )
+        .unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error.to_string().contains("stable semantic version"),
+            "unexpected prerelease-version error: {error}"
+        );
+
+        fs::write(
+            &manifest,
+            canonical.replace("nativeRuntimeVersion=1.2.3\n", ""),
+        )
+        .unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error.to_string().contains("missing=[nativeRuntimeVersion]"),
+            "unexpected missing-version error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_rejects_unknown_manifest_key() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-unknown-key");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let manifest = artifact.join("manifest.properties");
+        let mut text = fs::read_to_string(&manifest).unwrap();
+        text.push_str("futureCompatibilityGuess=yes\n");
+        fs::write(&manifest, text).unwrap();
+
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("unknown=[futureCompatibilityGuess]"),
+            "unexpected unknown-key error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_requires_canonical_ancillary_sql_fields() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-ancillary-sql-fields");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let manifest = artifact.join("manifest.properties");
+        let canonical = fs::read_to_string(&manifest).unwrap();
+
+        fs::write(
+            &manifest,
+            canonical.replace(
+                "extensionSqlFileNames=\n",
+                "extensionSqlFileNames=z.sql,a.sql\n",
+            ),
+        )
+        .unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("extensionSqlFileNames must be sorted and unique"),
+            "unexpected unsorted ancillary-SQL error: {error}"
+        );
+
+        fs::write(
+            &manifest,
+            canonical.replace(
+                "extensionSqlFilePrefixes=\n",
+                "extensionSqlFilePrefixes=acme_,acme_\n",
+            ),
+        )
+        .unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("extensionSqlFilePrefixes must be sorted and unique"),
+            "unexpected duplicate ancillary-SQL-prefix error: {error}"
+        );
+
+        let reordered = canonical.replace(
+            "extensionSqlFileNames=\nextensionSqlFilePrefixes=\n",
+            "extensionSqlFilePrefixes=\nextensionSqlFileNames=\n",
+        );
+        fs::write(&manifest, reordered).unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("line 12 must be canonical field extensionSqlFileNames"),
+            "unexpected reordered-field error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_rejects_noncanonical_boolean_values() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-noncanonical-bool");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let manifest = artifact.join("manifest.properties");
+        let canonical = fs::read_to_string(&manifest).unwrap();
+
+        fs::write(
+            &manifest,
+            canonical.replace("createsExtension=yes\n", "createsExtension=true\n"),
+        )
+        .unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("createsExtension='true', expected canonical yes/no"),
+            "unexpected createsExtension boolean error: {error}"
+        );
+
+        fs::write(
+            &manifest,
+            canonical.replace("mobilePrebuilt=no\n", "mobilePrebuilt=false\n"),
+        )
+        .unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("mobilePrebuilt='false', expected canonical yes/no"),
+            "unexpected mobilePrebuilt boolean error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_packaging_requires_selected_native_runtime_version() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-selected-version-required");
+        let artifact = temp.join("artifact-root");
+        let output = temp.join("output");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+
+        let error = build_native_runtime_resources(
+            NativeRuntimeResourceOptions::new(&output).prebuilt_extension(&artifact),
+        )
+        .unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("requires an exact stable liboliphaunt-native version"),
+            "unexpected missing selected-version error: {error}"
+        );
+        assert!(!output.exists(), "validation must precede materialization");
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_packaging_rejects_wrong_native_runtime_version_before_materialization() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-wrong-native-version");
+        let artifact = temp.join("artifact-root");
+        let output = temp.join("output");
+        write_prebuilt_extension_artifact_for_runtime(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+            "1.2.4",
+        );
+
+        let error = build_native_runtime_resources(
+            NativeRuntimeResourceOptions::new(&output)
+                .prebuilt_extension(&artifact)
+                .native_runtime_version("1.2.3"),
+        )
+        .unwrap_err();
+        assert!(
+            error.to_string().contains(
+                "requires liboliphaunt-native version '1.2.4', but runtime packaging selected '1.2.3'"
+            ),
+            "unexpected mismatched-version error: {error}"
+        );
+        assert!(!output.exists(), "validation must precede materialization");
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_packaging_rejects_mixed_native_runtime_versions() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-mixed-native-versions");
+        let first = temp.join("first");
+        let second = temp.join("second");
+        let output = temp.join("output");
+        write_prebuilt_extension_artifact_for_runtime(
+            &first,
+            "acme_a",
+            "acme_a",
+            "acme_static_a",
+            "data/acme_a.rules",
+            false,
+            "1.2.3",
+        );
+        write_prebuilt_extension_artifact_for_runtime(
+            &second,
+            "acme_b",
+            "acme_b",
+            "acme_static_b",
+            "data/acme_b.rules",
+            false,
+            "1.2.4",
+        );
+
+        let error = build_native_runtime_resources(
+            NativeRuntimeResourceOptions::new(&output)
+                .prebuilt_extension(first)
+                .prebuilt_extension(second)
+                .native_runtime_version("1.2.3"),
+        )
+        .unwrap_err();
+        assert!(
+            error.to_string().contains("artifact for 'acme_b'")
+                && error.to_string().contains("version '1.2.4'")
+                && error.to_string().contains("selected '1.2.3'"),
+            "unexpected mixed-version error: {error}"
+        );
+        assert!(!output.exists(), "validation must precede materialization");
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_rejects_wrong_runtime_target() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-wrong-target");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let extensions = resolve_runtime_resource_extensions(
+            &[],
+            &[NativePrebuiltExtensionArtifact::new(&artifact)],
+        )
+        .unwrap();
+        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
+        let error = copy_prebuilt_extension_artifacts(
+            &temp.join("runtime/files"),
+            &extensions,
+            Some("linux-x64-gnu"),
+            &metadata,
+        )
+        .unwrap_err();
+        assert!(
+            error.to_string().contains(
+                "prebuilt extension artifact for 'acme_ext' targets 'test-target', but runtime packaging target is 'linux-x64-gnu'"
+            ),
+            "unexpected wrong-target error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn mobile_static_prebuilt_extension_rejects_wrong_runtime_target_before_materialization() {
+        let temp = unique_temp_root("oliphaunt-mobile-static-prebuilt-wrong-target");
+        let artifact = temp.join("artifact-root");
+        let output = temp.join("output");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            true,
+        );
+
+        let error = build_native_runtime_resources(
+            NativeRuntimeResourceOptions::new(&output)
+                .prebuilt_extension(&artifact)
+                .native_runtime_version("1.2.3")
+                .extension_target("ios-simulator")
+                .mobile_static_module_stems(vec!["acme_ext".to_owned()]),
+        )
+        .unwrap_err();
+        assert!(
+            error.to_string().contains(
+                "prebuilt extension artifact for 'acme_ext' targets 'test-target', but runtime packaging target is 'ios-simulator'"
+            ),
+            "unexpected mobile-static wrong-target error: {error}"
+        );
+        assert!(!output.exists(), "validation must precede materialization");
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_tar_archive_is_validated_and_consumed() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let archive = temp.join("acme_ext.tar");
+        write_tar_archive_from_dir(&archive, &artifact, "acme_ext");
+
+        let prepared =
+            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
+                &archive,
+            )])
+            .unwrap();
+        let extensions = resolve_runtime_resource_extensions(&[], prepared.artifacts()).unwrap();
+        assert_eq!(selected_extension_names(&extensions), vec!["acme_ext"]);
+        assert_eq!(
+            extensions[0].native_module_stem.as_deref(),
+            Some("acme_ext")
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_nested_archive_rejects_top_level_file_sibling() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-file-sibling");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let archive = temp.join("acme_ext-with-file-sibling.tar");
+        write_tar_archive_from_dir_with_top_level_sibling(
+            &archive,
+            &artifact,
+            "acme_ext",
+            "undeclared.txt",
+            false,
+        );
+
+        let error =
+            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
+                &archive,
+            )])
+            .unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("exactly one top-level directory with no sibling entries"),
+            "unexpected top-level file sibling error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_nested_archive_rejects_top_level_directory_sibling() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-directory-sibling");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let archive = temp.join("acme_ext-with-directory-sibling.tar");
+        write_tar_archive_from_dir_with_top_level_sibling(
+            &archive,
+            &artifact,
+            "acme_ext",
+            "undeclared",
+            true,
+        );
+
+        let error =
+            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
+                &archive,
+            )])
+            .unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("exactly one top-level directory with no sibling entries"),
+            "unexpected top-level directory sibling error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_archive_rejects_noncanonical_legal_header_modes() {
+        for (case, member) in [
+            ("root-license", "acme_ext/LICENSE"),
+            (
+                "declared-upstream-license",
+                "acme_ext/files/share/licenses/acme_ext/LICENSE",
+            ),
+        ] {
+            let temp = unique_temp_root(&format!(
+                "oliphaunt-prebuilt-extension-tar-legal-mode-{case}"
+            ));
+            let artifact = temp.join("artifact-root");
+            write_prebuilt_extension_artifact(
+                &artifact,
+                "acme_ext",
+                "acme_ext",
+                "acme_static",
+                "data/acme_ext.rules",
+                false,
+            );
+            let archive = temp.join(format!("acme_ext-{case}.tar"));
+            write_tar_archive_from_dir(&archive, &artifact, "acme_ext");
+            rewrite_tar_archive_member_mode(&archive, Path::new(member), 0o600);
+
+            let error = PreparedPrebuiltExtensionArtifacts::prepare(&[
+                NativePrebuiltExtensionArtifact::new(&archive),
+            ])
+            .unwrap_err();
+            assert!(
+                error.to_string().contains(&format!(
+                    "legal member {member} must have exact tar header mode 0644, got 0600"
+                )),
+                "unexpected {case} legal header-mode error: {error}"
+            );
+
+            let _ = fs::remove_dir_all(temp);
+        }
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_rejects_mobile_archive_path_escape() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-mobile-path");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            true,
+        );
+        let wrong_relative = "files/lib/postgresql/liboliphaunt_extension_acme_ext.a";
+        write_file(&artifact.join(wrong_relative), b"wrong-place-static\n");
+        let manifest = artifact.join("manifest.properties");
+        let text = fs::read_to_string(&manifest).unwrap();
+        fs::write(
+            &manifest,
+            text.replace(
+                "mobileStaticArchives=ios-simulator:mobile-static/ios-simulator/extensions/acme_ext/liboliphaunt_extension_acme_ext.a\n",
+                &format!("mobileStaticArchives=ios-simulator:{wrong_relative}\n"),
+            ),
+        )
+        .unwrap();
+
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error.to_string().contains("must use mobile-static"),
+            "unexpected mobile archive path error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_compressed_archives_are_validated_and_consumed() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-zst");
+        let artifact = temp.join("artifact-root");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            false,
+        );
+        let tar = temp.join("source.tar");
+        write_tar_archive_from_dir(&tar, &artifact, "acme_ext");
+        let bytes = fs::read(&tar).unwrap();
+        let mut gzip = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::default());
+        std::io::Write::write_all(&mut gzip, &bytes).unwrap();
+        let gz = temp.join("acme_ext.tar.gz");
+        fs::write(&gz, gzip.finish().unwrap()).unwrap();
+        let zst = temp.join("acme_ext.tar.zst");
+        write_tar_zst_archive_from_dir(&zst, &artifact, "acme_ext");
+        for archive in [gz, zst] {
+            let prepared = PreparedPrebuiltExtensionArtifacts::prepare(&[
+                NativePrebuiltExtensionArtifact::new(&archive),
+            ])
+            .unwrap();
+            let extensions =
+                resolve_runtime_resource_extensions(&[], prepared.artifacts()).unwrap();
+            assert_eq!(selected_extension_names(&extensions), vec!["acme_ext"]);
+        }
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_archive_rejects_non_file_entries() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-symlink");
+        let archive_path = temp.join("malicious.tar");
+        let mut bytes = Vec::new();
+        {
+            let mut archive = tar::Builder::new(&mut bytes);
+            let mut header = tar::Header::new_gnu();
+            header.set_entry_type(EntryType::symlink());
+            header.set_path("manifest.properties").unwrap();
+            header.set_link_name("/tmp/not-allowed").unwrap();
+            header.set_mode(0o777);
+            header.set_size(0);
+            header.set_cksum();
+            archive.append(&header, std::io::empty()).unwrap();
+            archive.finish().unwrap();
+        }
+        write_file(&archive_path, &bytes);
+
+        let error =
+            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
+                &archive_path,
+            )])
+            .unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("must be a regular file or directory"),
+            "unexpected symlink-entry error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_archive_rejects_oversized_members_before_extraction() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-oversized-member");
+        let archive_path = temp.join("oversized.tar");
+        fs::create_dir_all(&temp).unwrap();
+        let policy = extension_artifact_archive_policy().unwrap();
+        let mut header = tar::Header::new_ustar();
+        header.set_entry_type(EntryType::Regular);
+        header.set_path("files/oversized.bin").unwrap();
+        header.set_mode(0o644);
+        header.set_size(policy.max_member_bytes + 1);
+        header.set_cksum();
+        let mut bytes = header.as_bytes().to_vec();
+        bytes.extend_from_slice(&[0u8; 1024]);
+        write_file(&archive_path, &bytes);
+
+        let error =
+            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
+                &archive_path,
+            )])
+            .unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("member larger than 268435456 bytes"),
+            "unexpected oversized-member error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_archive_rejects_oversized_compressed_carriers_before_decoding() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-oversized-compressed");
+        let archive_path = temp.join("oversized.tar.gz");
+        fs::create_dir_all(&temp).unwrap();
+        let file = File::create(&archive_path).unwrap();
+        let policy = extension_artifact_archive_policy().unwrap();
+        file.set_len(policy.max_compressed_bytes + 1).unwrap();
+
+        let error =
+            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
+                &archive_path,
+            )])
+            .unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("must contain between 1 and 134217728 bytes"),
+            "unexpected oversized-carrier error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn production_extension_legal_profiles_load_with_exact_leaf_inventories() {
+        let temp = unique_temp_root("oliphaunt-extension-legal-profiles");
+        let cube = temp.join("cube");
+        write_profiled_extension_artifact(
+            &cube,
+            "cube",
+            "cube",
+            "linux-x64-gnu",
+            NativeExtensionArtifactLicenseProfile::ContribNative,
+            &[],
+        );
+        let loaded = load_prebuilt_extension_artifact(&cube).unwrap();
+        assert_eq!(
+            loaded.license_profile,
+            Some(NativeExtensionArtifactLicenseProfile::ContribNative)
+        );
+        assert!(loaded.license_files.is_empty());
+
+        let pgcrypto = temp.join("pgcrypto");
+        write_profiled_extension_artifact(
+            &pgcrypto,
+            "pgcrypto",
+            "pgcrypto",
+            "macos-arm64",
+            NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl,
+            &[],
+        );
+        let loaded = load_prebuilt_extension_artifact(&pgcrypto).unwrap();
+        assert_eq!(
+            loaded.license_profile,
+            Some(NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl)
+        );
+
+        let postgis = temp.join("postgis");
+        let postgis_licenses = [
+            "share/licenses/geos/COPYING",
+            "share/licenses/postgis/COPYING",
+        ];
+        write_profiled_extension_artifact(
+            &postgis,
+            "postgis",
+            "postgis-3",
+            "linux-x64-gnu",
+            NativeExtensionArtifactLicenseProfile::ExternalNative,
+            &postgis_licenses,
+        );
+        let loaded = load_prebuilt_extension_artifact(&postgis).unwrap();
+        assert_eq!(
+            loaded.license_profile,
+            Some(NativeExtensionArtifactLicenseProfile::ExternalNative)
+        );
+        assert_eq!(
+            loaded.license_files,
+            postgis_licenses.map(PathBuf::from).to_vec()
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_rejects_missing_extra_unsafe_and_wrong_profile_legal_files() {
+        let temp = unique_temp_root("oliphaunt-extension-legal-adversarial");
+
+        let missing = temp.join("missing");
+        write_profiled_extension_artifact(
+            &missing,
+            "postgis",
+            "postgis-3",
+            "linux-x64-gnu",
+            NativeExtensionArtifactLicenseProfile::ExternalNative,
+            &["share/licenses/postgis/COPYING"],
+        );
+        fs::remove_file(missing.join("files/share/licenses/postgis/COPYING")).unwrap();
+        let error = load_prebuilt_extension_artifact(&missing).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("leaf inventory mismatch; missing: files/share/licenses/postgis/COPYING"),
+            "unexpected missing legal leaf error: {error}"
+        );
+
+        let extra = temp.join("extra");
+        write_profiled_extension_artifact(
+            &extra,
+            "cube",
+            "cube",
+            "linux-x64-gnu",
+            NativeExtensionArtifactLicenseProfile::ContribNative,
+            &[],
+        );
+        write_file(
+            &extra.join("THIRD_PARTY_LICENSES/undeclared.txt"),
+            b"undeclared\n",
+        );
+        let error = load_prebuilt_extension_artifact(&extra).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("undeclared: THIRD_PARTY_LICENSES/undeclared.txt"),
+            "unexpected extra legal leaf error: {error}"
+        );
+
+        let unsafe_path = temp.join("unsafe");
+        write_profiled_extension_artifact(
+            &unsafe_path,
+            "postgis",
+            "postgis-3",
+            "linux-x64-gnu",
+            NativeExtensionArtifactLicenseProfile::ExternalNative,
+            &["share/licenses/postgis/COPYING"],
+        );
+        let manifest = unsafe_path.join("manifest.properties");
+        let text = fs::read_to_string(&manifest).unwrap().replace(
+            "licenseFiles=share/licenses/postgis/COPYING\n",
+            "licenseFiles=../outside-license\n",
+        );
+        fs::write(&manifest, text).unwrap();
+        let error = load_prebuilt_extension_artifact(&unsafe_path).unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("contains path component \"..\" that is unsafe on supported build hosts"),
+            "unexpected unsafe legal path error: {error}"
+        );
+
+        let wrong_profile = temp.join("wrong-profile");
+        write_profiled_extension_artifact(
+            &wrong_profile,
+            "cube",
+            "cube",
+            "linux-x64-gnu",
+            NativeExtensionArtifactLicenseProfile::ContribNative,
+            &[],
+        );
+        let manifest = wrong_profile.join("manifest.properties");
+        let text = fs::read_to_string(&manifest).unwrap().replace(
+            "licenseProfile=contrib-native\n",
+            "licenseProfile=external-native\n",
+        );
+        fs::write(&manifest, text).unwrap();
+        let error = load_prebuilt_extension_artifact(&wrong_profile).unwrap_err();
+        assert!(
+            error.to_string().contains("expected 'contrib-native'"),
+            "unexpected wrong legal profile error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn prebuilt_extension_rejects_noncanonical_legal_file_mode() {
+        use std::os::unix::fs::PermissionsExt;
+
+        let temp = unique_temp_root("oliphaunt-extension-legal-mode");
+        let artifact = temp.join("cube");
+        write_profiled_extension_artifact(
+            &artifact,
+            "cube",
+            "cube",
+            "linux-x64-gnu",
+            NativeExtensionArtifactLicenseProfile::ContribNative,
+            &[],
+        );
+        fs::set_permissions(artifact.join("LICENSE"), fs::Permissions::from_mode(0o600)).unwrap();
+        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
+        assert!(
+            error.to_string().contains("LICENSE must have mode 0644"),
+            "unexpected legal mode error: {error}"
+        );
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_can_override_builtin_artifact_payload() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-override");
+        let artifact = temp.join("vector");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "vector",
+            "vector",
+            "oliphaunt_static_vector",
+            "data/vector.rules",
+            true,
+        );
+
+        let resolved = resolve_runtime_resource_extensions(
+            &[],
+            &[NativePrebuiltExtensionArtifact::new(&artifact)],
+        )
+        .unwrap();
+        assert_eq!(resolved.len(), 1);
+        assert_eq!(resolved[0].sql_name, "vector");
+        assert!(matches!(
+            resolved[0].source,
+            RuntimeResourceExtensionSource::Prebuilt { .. }
+        ));
+        assert_eq!(resolved[0].mobile_static_archives.len(), 1);
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    #[test]
+    fn prebuilt_extension_artifact_dependencies_must_be_available() {
+        let temp = unique_temp_root("oliphaunt-prebuilt-extension-missing-dependency");
+        let artifact = temp.join("acme_ext");
+        write_prebuilt_extension_artifact(
+            &artifact,
+            "acme_ext",
+            "acme_ext",
+            "acme_static",
+            "data/acme_ext.rules",
+            true,
+        );
+        let manifest = artifact.join("manifest.properties");
+        let text = fs::read_to_string(&manifest).unwrap();
+        fs::write(
+            &manifest,
+            text.replace("dependencies=\n", "dependencies=missing_ext\n"),
+        )
+        .unwrap();
+
+        let error = resolve_runtime_resource_extensions(
+            &[],
+            &[NativePrebuiltExtensionArtifact::new(&artifact)],
+        )
+        .unwrap_err();
+        assert!(
+            error.to_string().contains(
+                "selected extension 'missing_ext' is neither built into this Oliphaunt release nor provided as a prebuilt extension artifact"
+            ),
+            "unexpected missing-dependency error: {error}"
+        );
+
+        let _ = fs::remove_dir_all(temp);
+    }
+
+    fn write_file(path: &Path, contents: &[u8]) {
+        if let Some(parent) = path.parent() {
+            fs::create_dir_all(parent).expect("create parent directory");
+        }
+        fs::write(path, contents).expect("write fixture file");
+    }
+
+    fn write_legal_fixture_file(path: &Path, contents: &[u8]) {
+        write_file(path, contents);
+        #[cfg(unix)]
+        {
+            use std::os::unix::fs::PermissionsExt;
+            fs::set_permissions(path, fs::Permissions::from_mode(0o644))
+                .expect("set canonical fixture legal mode");
+        }
+    }
+
+    fn write_prebuilt_extension_artifact(
+        root: &Path,
+        sql_name: &str,
+        module_stem: &str,
+        static_symbol_prefix: &str,
+        data_file: &str,
+        mobile_prebuilt: bool,
+    ) {
+        write_prebuilt_extension_artifact_for_runtime(
+            root,
+            sql_name,
+            module_stem,
+            static_symbol_prefix,
+            data_file,
+            mobile_prebuilt,
+            "1.2.3",
+        );
+    }
+
+    fn write_prebuilt_extension_artifact_for_runtime(
+        root: &Path,
+        sql_name: &str,
+        module_stem: &str,
+        static_symbol_prefix: &str,
+        data_file: &str,
+        mobile_prebuilt: bool,
+        native_runtime_version: &str,
+    ) {
+        let mobile_static_archives = if mobile_prebuilt {
+            format!(
+                "ios-simulator:mobile-static/ios-simulator/extensions/{module_stem}/liboliphaunt_extension_{module_stem}.a"
+            )
+        } else {
+            String::new()
+        };
+        let mobile_static_dependency_archives = if mobile_prebuilt {
+            "ios-simulator:openssl:mobile-static/ios-simulator/dependencies/openssl/libcrypto.a"
+                .to_owned()
+        } else {
+            String::new()
+        };
+        write_file(
+            &root.join("manifest.properties"),
+            format!(
+                "\
+packageLayout=oliphaunt-extension-artifact-v1
+pgMajor=18
+sqlName={sql_name}
+createsExtension=yes
+nativeModuleStem={module_stem}
+nativeModuleFile=
+nativeTarget=test-target
+nativeRuntimeProduct=liboliphaunt-native
+nativeRuntimeVersion={native_runtime_version}
+dependencies=
+dataFiles={data_file}
+extensionSqlFileNames=
+extensionSqlFilePrefixes=
+sharedPreloadLibraries=
+mobilePrebuilt={}
+mobileStaticArchives={mobile_static_archives}
+mobileStaticDependencyArchives={mobile_static_dependency_archives}
+staticSymbolPrefix={static_symbol_prefix}
+staticSymbolAliases=
+licenseFiles=share/licenses/{sql_name}/LICENSE
+licenseProfile=external-native
+files=files
+",
+                if mobile_prebuilt { "yes" } else { "no" }
+            )
+            .as_bytes(),
+        );
+        write_file(
+            &root
+                .join("files/share/postgresql/extension")
+                .join(format!("{sql_name}.control")),
+            b"comment = 'acme extension'\n",
+        );
+        write_file(
+            &root
+                .join("files/share/postgresql/extension")
+                .join(format!("{sql_name}--1.0.sql")),
+            b"CREATE FUNCTION acme_ext_echo(integer) RETURNS integer AS 'MODULE_PATHNAME' LANGUAGE C STRICT;\n",
+        );
+        write_file(
+            &root.join("files/share/postgresql").join(data_file),
+            b"acme-data\n",
+        );
+        write_legal_fixture_file(&root.join("LICENSE"), b"fixture Oliphaunt license\n");
+        write_legal_fixture_file(
+            &root.join("THIRD_PARTY_NOTICES.md"),
+            b"fixture third-party notices\n",
+        );
+        write_legal_fixture_file(
+            &root
+                .join("files/share/licenses")
+                .join(sql_name)
+                .join("LICENSE"),
+            b"fixture upstream license\n",
+        );
+        write_file(
+            &root
+                .join("files/lib/postgresql")
+                .join(format!("{module_stem}{}", std::env::consts::DLL_SUFFIX)),
+            b"acme-module\n",
+        );
+        write_file(
+            &root
+                .join("files/lib/modules")
+                .join(format!("{module_stem}{}", std::env::consts::DLL_SUFFIX)),
+            b"acme-embedded-module\n",
+        );
+        if mobile_prebuilt {
+            write_file(
+                &root
+                    .join("mobile-static/ios-simulator/extensions")
+                    .join(module_stem)
+                    .join(format!("liboliphaunt_extension_{module_stem}.a")),
+                b"acme-ios-simulator-static\n",
+            );
+            write_file(
+                &root.join("mobile-static/ios-simulator/dependencies/openssl/libcrypto.a"),
+                b"acme-ios-simulator-libcrypto\n",
+            );
+        }
+    }
+
+    fn write_profiled_extension_artifact(
+        root: &Path,
+        sql_name: &str,
+        module_stem: &str,
+        target: &str,
+        profile: NativeExtensionArtifactLicenseProfile,
+        license_files: &[&str],
+    ) {
+        let module_file = format!("{module_stem}.so");
+        let license_value = license_files.join(",");
+        write_file(
+            &root.join("manifest.properties"),
+            format!(
+                "\
+packageLayout=oliphaunt-extension-artifact-v1
+pgMajor=18
+sqlName={sql_name}
+createsExtension=yes
+nativeModuleStem={module_stem}
+nativeModuleFile={module_file}
+nativeTarget={target}
+nativeRuntimeProduct=liboliphaunt-native
+nativeRuntimeVersion=1.2.3
+dependencies=
+dataFiles=
+extensionSqlFileNames=
+extensionSqlFilePrefixes=
+sharedPreloadLibraries=
+mobilePrebuilt=no
+mobileStaticArchives=
+mobileStaticDependencyArchives=
+staticSymbolPrefix=
+staticSymbolAliases=
+licenseFiles={license_value}
+licenseProfile={}
+files=files
+",
+                profile.as_str()
+            )
+            .as_bytes(),
+        );
+        write_legal_fixture_file(&root.join("LICENSE"), b"fixture Oliphaunt license\n");
+        write_legal_fixture_file(
+            &root.join("THIRD_PARTY_NOTICES.md"),
+            b"fixture third-party notices\n",
+        );
+        if matches!(
+            profile,
+            NativeExtensionArtifactLicenseProfile::ContribNative
+                | NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl
+        ) {
+            write_legal_fixture_file(
+                &root.join(EXTENSION_ARTIFACT_POSTGRESQL_LICENSE),
+                b"fixture PostgreSQL license\n",
+            );
+        }
+        if profile == NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl {
+            write_legal_fixture_file(
+                &root.join(EXTENSION_ARTIFACT_OPENSSL_LICENSE),
+                b"fixture OpenSSL license\n",
+            );
+        }
+        for license in license_files {
+            write_legal_fixture_file(
+                &root.join("files").join(license),
+                format!("fixture upstream license {license}\n").as_bytes(),
+            );
+        }
+        write_file(
+            &root
+                .join("files/share/postgresql/extension")
+                .join(format!("{sql_name}.control")),
+            b"comment = 'profile fixture'\n",
+        );
+        write_file(
+            &root
+                .join("files/share/postgresql/extension")
+                .join(format!("{sql_name}--1.0.sql")),
+            b"SELECT 1;\n",
+        );
+        write_file(
+            &root.join("files/lib/postgresql").join(&module_file),
+            b"fixture server module\n",
+        );
+        write_file(
+            &root.join("files/lib/modules").join(module_file),
+            b"fixture embedded module\n",
+        );
+    }
+
+    fn write_tar_archive_from_dir(archive_path: &Path, source: &Path, prefix: &str) {
+        if let Some(parent) = archive_path.parent() {
+            fs::create_dir_all(parent).unwrap();
+        }
+        let file = File::create(archive_path).unwrap();
+        let mut archive = tar::Builder::new(file);
+        archive.mode(tar::HeaderMode::Deterministic);
+        archive.append_dir_all(prefix, source).unwrap();
+        archive.finish().unwrap();
+    }
+
+    fn write_tar_archive_from_dir_with_top_level_sibling(
+        archive_path: &Path,
+        source: &Path,
+        prefix: &str,
+        sibling: &str,
+        sibling_is_directory: bool,
+    ) {
+        if let Some(parent) = archive_path.parent() {
+            fs::create_dir_all(parent).unwrap();
+        }
+        let file = File::create(archive_path).unwrap();
+        let mut archive = tar::Builder::new(file);
+        archive.append_dir_all(prefix, source).unwrap();
+        let mut header = tar::Header::new_ustar();
+        header.set_path(sibling).unwrap();
+        header.set_mode(if sibling_is_directory { 0o755 } else { 0o644 });
+        header.set_size(0);
+        header.set_entry_type(if sibling_is_directory {
+            EntryType::Directory
+        } else {
+            EntryType::Regular
+        });
+        header.set_cksum();
+        archive.append(&header, io::empty()).unwrap();
+        archive.finish().unwrap();
+    }
+
+    fn rewrite_tar_archive_member_mode(archive_path: &Path, member: &Path, mode: u32) {
+        let source_path = archive_path.with_extension("original.tar");
+        fs::rename(archive_path, &source_path).unwrap();
+        let source_file = File::open(&source_path).unwrap();
+        let mut source_archive = tar::Archive::new(source_file);
+        let output_file = File::create(archive_path).unwrap();
+        let mut output_archive = tar::Builder::new(output_file);
+        let mut found = false;
+        for entry in source_archive.entries().unwrap() {
+            let mut entry = entry.unwrap();
+            let path = entry.path().unwrap().into_owned();
+            let mut header = entry.header().clone();
+            if header.entry_type().is_file() {
+                header.set_mode(if path == member { mode } else { 0o644 });
+                header.set_cksum();
+                found |= path == member;
+            }
+            output_archive.append(&header, &mut entry).unwrap();
+        }
+        output_archive.finish().unwrap();
+        assert!(
+            found,
+            "tar fixture is missing mode override member {}",
+            member.display()
+        );
+        fs::remove_file(source_path).unwrap();
+    }
+
+    fn write_tar_zst_archive_from_dir(archive_path: &Path, source: &Path, prefix: &str) {
+        let tar_path = archive_path.with_extension("tar");
+        write_tar_archive_from_dir(&tar_path, source, prefix);
+        let tar_bytes = fs::read(&tar_path).unwrap();
+        let compressed = zstd::stream::encode_all(tar_bytes.as_slice(), 0).unwrap();
+        write_file(archive_path, &compressed);
+        let _ = fs::remove_file(tar_path);
+    }
+
+    fn runtime_resource_extensions(extensions: &[Extension]) -> Vec {
+        extensions
+            .iter()
+            .copied()
+            .map(built_in_runtime_resource_extension)
+            .collect()
+    }
+
+    fn unique_temp_root(prefix: &str) -> PathBuf {
+        let nanos = SystemTime::now()
+            .duration_since(UNIX_EPOCH)
+            .unwrap()
+            .as_nanos();
+        std::env::temp_dir().join(format!("{prefix}-{}-{nanos}", std::process::id()))
+    }
+}
diff --git a/tools/native-packaging/src/manifest.rs b/src/runtimes/liboliphaunt-native/packaging/src/manifest.rs
similarity index 95%
rename from tools/native-packaging/src/manifest.rs
rename to src/runtimes/liboliphaunt-native/packaging/src/manifest.rs
index d1cff28f4..ce1b9d4e1 100644
--- a/tools/native-packaging/src/manifest.rs
+++ b/src/runtimes/liboliphaunt-native/packaging/src/manifest.rs
@@ -640,36 +640,6 @@ pub(super) fn parse_portable_artifact_path_text(
     Ok(relative)
 }
 
-pub(super) fn render_portable_artifact_path(path: &Path, label: &str) -> Result {
-    let mut components = Vec::new();
-    for component in path.components() {
-        let Component::Normal(component) = component else {
-            return Err(Error::InvalidConfig(format!(
-                "{label} '{}' must be a canonical relative path",
-                path.display()
-            )));
-        };
-        let component = component.to_str().ok_or_else(|| {
-            Error::InvalidConfig(format!(
-                "{label} '{}' must use UTF-8 path text",
-                path.display()
-            ))
-        })?;
-        validate_portable_artifact_path_component(
-            component,
-            &format!("{label} '{}'", path.display()),
-        )?;
-        components.push(component);
-    }
-    if components.is_empty() {
-        return Err(Error::InvalidConfig(format!(
-            "{label} '{}' must not be empty",
-            path.display()
-        )));
-    }
-    Ok(components.join("/"))
-}
-
 pub(super) fn validate_portable_artifact_path_component(
     component: &str,
     context: &str,
@@ -794,10 +764,7 @@ mod tests {
                 path,
             )
             .unwrap_or_else(|error| panic!("portable path {path:?} was rejected: {error}"));
-            assert_eq!(
-                render_portable_artifact_path(&parsed, "contract test").unwrap(),
-                path
-            );
+            assert_eq!(parsed, path.split('/').collect::());
         }
     }
 }
diff --git a/tools/native-packaging/src/package.rs b/src/runtimes/liboliphaunt-native/packaging/src/package.rs
similarity index 89%
rename from tools/native-packaging/src/package.rs
rename to src/runtimes/liboliphaunt-native/packaging/src/package.rs
index e09bbc8bd..806580f94 100644
--- a/tools/native-packaging/src/package.rs
+++ b/src/runtimes/liboliphaunt-native/packaging/src/package.rs
@@ -18,7 +18,7 @@ pub(super) fn prepare_output_root(root: &Path, replace_existing: bool) -> Result
 #[allow(clippy::too_many_arguments)] // Inputs are distinct frozen runtime-package contract fields.
 pub(super) fn write_runtime_resource_tree(
     root: &Path,
-    mode: NativePackagingMode,
+
     materialized: &MaterializedNativeResources,
     extensions: &[RuntimeResourceExtension],
     runtime_features: &[NativeRuntimeFeature],
@@ -46,7 +46,6 @@ pub(super) fn write_runtime_resource_tree(
     copy_prebuilt_extension_artifacts(
         &runtime_files,
         extensions,
-        mode,
         extension_target,
         mobile_static_registry,
     )?;
@@ -58,7 +57,7 @@ pub(super) fn write_runtime_resource_tree(
             artifact_role: "runtime",
             catalog_profile: "",
             icu_data_tree_sha256: &icu_data_tree_sha256,
-            mode,
+
             extensions,
             runtime_features,
             shared_preload_libraries,
@@ -66,33 +65,6 @@ pub(super) fn write_runtime_resource_tree(
         },
     )?;
 
-    let template_mobile_static_registry = mobile_static_registry_metadata(&[], &[])?;
-    let template_package = root.join("cluster-seed");
-    let template_files = template_package.join("files");
-    copy_portable_tree(&materialized.cluster_seed, &template_files)?;
-    write_manifest(
-        &template_package,
-        &RuntimeResourceManifest {
-            cache_key: &materialized.cluster_seed_cache_key,
-            layout: CLUSTER_SEED_LAYOUT,
-            artifact_role: if runtime_features.contains(&NativeRuntimeFeature::Icu) {
-                "cluster-seed-icu"
-            } else {
-                "cluster-seed-standard"
-            },
-            catalog_profile: if runtime_features.contains(&NativeRuntimeFeature::Icu) {
-                "icu"
-            } else {
-                "standard"
-            },
-            icu_data_tree_sha256: &icu_data_tree_sha256,
-            mode,
-            extensions: &[],
-            runtime_features,
-            shared_preload_libraries: &[],
-            mobile_static_registry: &template_mobile_static_registry,
-        },
-    )?;
     write_static_registry_package(root, &runtime_files, extensions, mobile_static_registry)?;
     Ok(())
 }
@@ -262,7 +234,7 @@ fn prune_prebuilt_extension_base_artifact_paths(
 pub(super) fn copy_prebuilt_extension_artifacts(
     runtime_files: &Path,
     extensions: &[RuntimeResourceExtension],
-    mode: NativePackagingMode,
+
     extension_target: Option<&str>,
     mobile_static_registry: &MobileStaticRegistryMetadata,
 ) -> Result<()> {
@@ -290,16 +262,10 @@ pub(super) fn copy_prebuilt_extension_artifacts(
             let Some(module) = &extension.native_module_file else {
                 continue;
             };
-            let source_relative = match mode {
-                NativePackagingMode::NativeDirect | NativePackagingMode::NativeBroker => {
-                    PathBuf::from("lib/modules").join(module)
-                }
-                NativePackagingMode::NativeServer => PathBuf::from("lib/postgresql").join(module),
-            };
             copy_artifact_runtime_file_to(
                 files_root,
                 runtime_files,
-                &source_relative,
+                &PathBuf::from("lib/modules").join(module),
                 &PathBuf::from("lib/postgresql").join(module),
             )?;
         }
@@ -394,7 +360,6 @@ pub(super) fn runtime_resource_size_report(
     mobile_static_registry: &MobileStaticRegistryMetadata,
 ) -> Result {
     let runtime_files = root.join("runtime/files");
-    let cluster_seed_files = root.join("cluster-seed/files");
     let static_registry = root.join("static-registry");
     let selected_extension_paths = extension_asset_paths(
         &runtime_files,
@@ -420,13 +385,11 @@ pub(super) fn runtime_resource_size_report(
     extension_reports.sort_by(|left, right| left.name.cmp(&right.name));
 
     let runtime_bytes = tree_size(&runtime_files)?;
-    let cluster_seed_bytes = tree_size(&cluster_seed_files)?;
     let static_registry_bytes = tree_size(&static_registry)?;
     Ok(NativeRuntimeResourceSizeReport {
         path: root.join("package-size.tsv"),
-        package_bytes: runtime_bytes + cluster_seed_bytes + static_registry_bytes,
+        package_bytes: runtime_bytes + static_registry_bytes,
         runtime_bytes,
-        cluster_seed_bytes,
         static_registry_bytes,
         selected_extension_bytes: byte_sum(&runtime_files, &selected_extension_paths)?,
         extensions: extension_reports,
@@ -440,7 +403,6 @@ pub(super) fn write_runtime_resource_size_report(
         "kind\tid\textensions\tfiles\tbytes".to_owned(),
         format!("package\ttotal\t-\t-\t{}", report.package_bytes),
         format!("package\truntime\t-\t-\t{}", report.runtime_bytes),
-        format!("package\tcluster-seed\t-\t-\t{}", report.cluster_seed_bytes),
         format!(
             "package\tstatic-registry\t-\t-\t{}",
             report.static_registry_bytes
@@ -654,7 +616,7 @@ pub(super) struct RuntimeResourceManifest<'a> {
     pub(super) artifact_role: &'a str,
     pub(super) catalog_profile: &'a str,
     pub(super) icu_data_tree_sha256: &'a str,
-    pub(super) mode: NativePackagingMode,
+
     pub(super) extensions: &'a [RuntimeResourceExtension],
     pub(super) runtime_features: &'a [NativeRuntimeFeature],
     pub(super) shared_preload_libraries: &'a [String],
@@ -677,38 +639,14 @@ fn write_manifest(package_dir: &Path, manifest: &RuntimeResourceManifest<'_>) ->
 }
 
 pub(super) fn manifest_text(manifest: &RuntimeResourceManifest<'_>) -> String {
-    let is_cluster_seed = manifest.artifact_role.starts_with("cluster-seed-");
-    if is_cluster_seed {
-        let icu_data_version = if manifest.catalog_profile == "icu" {
-            "76.1"
-        } else {
-            ""
-        };
-        let icu_data_form = if manifest.catalog_profile == "icu" {
-            "files-le"
-        } else {
-            ""
-        };
-        return format!(
-            "schema={RUNTIME_RESOURCES_SCHEMA}\nlayout={}\nartifactRole={}\ncatalogProfile={}\npostgresMajor=18\nphysicalFormat=native-pg18-v1\ninitialSuperuser=postgres\nicuDataVersion={icu_data_version}\nicuDataForm={icu_data_form}\nicuDataTreeSha256={}\nruntimeFeatures={}\ncacheKey={}\n",
-            manifest.layout,
-            manifest.artifact_role,
-            manifest.catalog_profile,
-            manifest.icu_data_tree_sha256,
-            runtime_feature_names(manifest.runtime_features).join(","),
-            manifest.cache_key,
-        );
-    }
-
     // Generic materialization is an unbound producer intermediate. Release
     // staging fills clusterSeedTarget before the carrier reaches an SDK.
     format!(
-        "schema={RUNTIME_RESOURCES_SCHEMA}\nlayout={}\nartifactRole={}\ncatalogProfile={}\nclusterSeedTarget=\nicuDataTreeSha256={}\nmode={}\ncacheKey={}\nselectedExtensions={}\nextensions={}\nruntimeFeatures={}\nsharedPreloadLibraries={}\nmobileStaticRegistryState={}\nmobileStaticRegistryRegistered={}\nmobileStaticRegistryPending={}\nnativeModuleStems={}\nmobileStaticRegistrySource={}\n",
+        "schema={RUNTIME_RESOURCES_SCHEMA}\nlayout={}\nartifactRole={}\ncatalogProfile={}\nclusterSeedTarget=\nicuDataTreeSha256={}\nmode=native-direct\ncacheKey={}\nselectedExtensions={}\nextensions={}\nruntimeFeatures={}\nsharedPreloadLibraries={}\nmobileStaticRegistryState={}\nmobileStaticRegistryRegistered={}\nmobileStaticRegistryPending={}\nnativeModuleStems={}\nmobileStaticRegistrySource={}\n",
         manifest.layout,
         manifest.artifact_role,
         manifest.catalog_profile,
         manifest.icu_data_tree_sha256,
-        manifest.mode.as_manifest_value(),
         manifest.cache_key,
         selected_extension_names(manifest.extensions).join(","),
         createable_extension_names(manifest.extensions).join(","),
diff --git a/tools/native-packaging/src/static_registry.rs b/src/runtimes/liboliphaunt-native/packaging/src/static_registry.rs
similarity index 100%
rename from tools/native-packaging/src/static_registry.rs
rename to src/runtimes/liboliphaunt-native/packaging/src/static_registry.rs
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0001-liboliphaunt-add-backend-host-io.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0001-liboliphaunt-add-backend-host-io.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0001-liboliphaunt-add-backend-host-io.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0001-liboliphaunt-add-backend-host-io.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0002-liboliphaunt-add-embedded-entrypoint.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0002-liboliphaunt-add-embedded-entrypoint.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0002-liboliphaunt-add-embedded-entrypoint.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0002-liboliphaunt-add-embedded-entrypoint.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0003-liboliphaunt-return-from-embedded-frontend-terminate.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0003-liboliphaunt-return-from-embedded-frontend-terminate.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0003-liboliphaunt-return-from-embedded-frontend-terminate.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0003-liboliphaunt-return-from-embedded-frontend-terminate.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0004-liboliphaunt-run-embedded-exit-cleanup.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0004-liboliphaunt-run-embedded-exit-cleanup.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0004-liboliphaunt-run-embedded-exit-cleanup.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0004-liboliphaunt-run-embedded-exit-cleanup.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0005-liboliphaunt-restore-host-cwd.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0005-liboliphaunt-restore-host-cwd.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0005-liboliphaunt-restore-host-cwd.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0005-liboliphaunt-restore-host-cwd.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0006-liboliphaunt-add-static-extension-loader.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0006-liboliphaunt-add-static-extension-loader.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0006-liboliphaunt-add-static-extension-loader.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0006-liboliphaunt-add-static-extension-loader.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0008-liboliphaunt-clean-embedded-symbols.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0008-liboliphaunt-clean-embedded-symbols.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0008-liboliphaunt-clean-embedded-symbols.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0008-liboliphaunt-clean-embedded-symbols.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0009-liboliphaunt-guard-embedded-proc-exit.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0009-liboliphaunt-guard-embedded-proc-exit.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0009-liboliphaunt-guard-embedded-proc-exit.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0009-liboliphaunt-guard-embedded-proc-exit.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0010-liboliphaunt-use-host-runtime-paths.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0010-liboliphaunt-use-host-runtime-paths.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0010-liboliphaunt-use-host-runtime-paths.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0010-liboliphaunt-use-host-runtime-paths.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0011-liboliphaunt-add-android-embedded-shared-memory.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0011-liboliphaunt-add-android-embedded-shared-memory.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0011-liboliphaunt-add-android-embedded-shared-memory.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0011-liboliphaunt-add-android-embedded-shared-memory.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0014-liboliphaunt-use-portable-embedded-socketpair.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0014-liboliphaunt-use-portable-embedded-socketpair.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0014-liboliphaunt-use-portable-embedded-socketpair.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0014-liboliphaunt-use-portable-embedded-socketpair.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0015-liboliphaunt-add-embedded-meson-option.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0015-liboliphaunt-add-embedded-meson-option.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0015-liboliphaunt-add-embedded-meson-option.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0015-liboliphaunt-add-embedded-meson-option.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0017-liboliphaunt-namespace-dynahash-host-collisions.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0017-liboliphaunt-namespace-dynahash-host-collisions.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0017-liboliphaunt-namespace-dynahash-host-collisions.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0017-liboliphaunt-namespace-dynahash-host-collisions.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0018-liboliphaunt-contain-embedded-proc-signals.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0018-liboliphaunt-contain-embedded-proc-signals.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0018-liboliphaunt-contain-embedded-proc-signals.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0018-liboliphaunt-contain-embedded-proc-signals.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0019-liboliphaunt-link-windows-embedded-modules-to-host.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0019-liboliphaunt-link-windows-embedded-modules-to-host.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0019-liboliphaunt-link-windows-embedded-modules-to-host.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0019-liboliphaunt-link-windows-embedded-modules-to-host.patch
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0020-liboliphaunt-enforce-embedded-signal-boundary.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0020-liboliphaunt-enforce-embedded-signal-boundary.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0020-liboliphaunt-enforce-embedded-signal-boundary.patch
rename to src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0020-liboliphaunt-enforce-embedded-signal-boundary.patch
diff --git a/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0021-liboliphaunt-wake-embedded-epoll-through-self-pipe.patch b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0021-liboliphaunt-wake-embedded-epoll-through-self-pipe.patch
new file mode 100644
index 000000000..e81da2d4b
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0021-liboliphaunt-wake-embedded-epoll-through-self-pipe.patch
@@ -0,0 +1,49 @@
+--- a/src/backend/storage/ipc/waiteventset.c
++++ b/src/backend/storage/ipc/waiteventset.c
+@@ -103,6 +103,10 @@
+  * By default, we use a self-pipe with poll() and a signalfd with epoll(), if
+  * available.  For testing the choice can also be manually specified.
+  */
++#if defined(OLIPHAUNT_EMBEDDED) && defined(WAIT_USE_EPOLL)
++/* The embedded host cancels from another thread, without PostgreSQL signals. */
++#define WAIT_USE_SELF_PIPE
++#endif
+ #if defined(WAIT_USE_POLL) || defined(WAIT_USE_EPOLL)
+ #if defined(WAIT_USE_SELF_PIPE) || defined(WAIT_USE_SIGNALFD)
+ /* don't overwrite manual choice */
+@@ -185,7 +189,9 @@
+ static int	selfpipe_owner_pid = 0;
+ 
+ /* Private function prototypes */
++#if !defined(OLIPHAUNT_EMBEDDED) || !defined(WAIT_USE_EPOLL)
+ static void latch_sigurg_handler(SIGNAL_ARGS);
++#endif
+ static void sendSelfPipeByte(void);
+ #endif
+ 
+@@ -311,8 +317,10 @@
+ 	ReserveExternalFD();
+ 	ReserveExternalFD();
+ 
++#if !defined(OLIPHAUNT_EMBEDDED) || !defined(WAIT_USE_EPOLL)
+ 	pqsignal(SIGURG, latch_sigurg_handler);
+ #endif
++#endif
+ 
+ #ifdef WAIT_USE_SIGNALFD
+ 	sigset_t	signalfd_mask;
+@@ -1892,12 +1900,14 @@
+  *
+  * Wake up WaitLatch, if we're waiting.
+  */
++#if !defined(OLIPHAUNT_EMBEDDED) || !defined(WAIT_USE_EPOLL)
+ static void
+ latch_sigurg_handler(SIGNAL_ARGS)
+ {
+ 	if (waiting)
+ 		sendSelfPipeByte();
+ }
++#endif
+ 
+ /* Send one byte to the self-pipe, to wake up WaitLatch */
+ static void
diff --git a/src/runtimes/liboliphaunt/native/portable-uuid/include/uuid/uuid.h b/src/runtimes/liboliphaunt-native/portable-uuid/include/uuid/uuid.h
similarity index 100%
rename from src/runtimes/liboliphaunt/native/portable-uuid/include/uuid/uuid.h
rename to src/runtimes/liboliphaunt-native/portable-uuid/include/uuid/uuid.h
diff --git a/src/runtimes/liboliphaunt/native/portable-uuid/portable_uuid.c b/src/runtimes/liboliphaunt-native/portable-uuid/portable_uuid.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/portable-uuid/portable_uuid.c
rename to src/runtimes/liboliphaunt-native/portable-uuid/portable_uuid.c
diff --git a/src/runtimes/liboliphaunt-native/postgres/series b/src/runtimes/liboliphaunt-native/postgres/series
new file mode 100644
index 000000000..d93c3e3ab
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/postgres/series
@@ -0,0 +1,22 @@
+# PostgreSQL 18.4. Ordered repository-relative patch paths.
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0001-liboliphaunt-add-backend-host-io.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0002-liboliphaunt-add-embedded-entrypoint.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0003-liboliphaunt-return-from-embedded-frontend-terminate.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0004-liboliphaunt-run-embedded-exit-cleanup.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0005-liboliphaunt-restore-host-cwd.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0006-liboliphaunt-add-static-extension-loader.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0008-liboliphaunt-clean-embedded-symbols.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0009-liboliphaunt-guard-embedded-proc-exit.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0010-liboliphaunt-use-host-runtime-paths.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0011-liboliphaunt-add-android-embedded-shared-memory.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0014-liboliphaunt-use-portable-embedded-socketpair.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0015-liboliphaunt-add-embedded-meson-option.patch
+src/third-party/postgres/patches/common/control-initdb-collation-discovery.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0017-liboliphaunt-namespace-dynahash-host-collisions.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0018-liboliphaunt-contain-embedded-proc-signals.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0019-liboliphaunt-link-windows-embedded-modules-to-host.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0020-liboliphaunt-enforce-embedded-signal-boundary.patch
+src/runtimes/liboliphaunt-native/patches/postgresql-18.4/0021-liboliphaunt-wake-embedded-epoll-through-self-pipe.patch
diff --git a/src/runtimes/liboliphaunt-native/release.toml b/src/runtimes/liboliphaunt-native/release.toml
new file mode 100644
index 000000000..b80408efb
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/release.toml
@@ -0,0 +1,28 @@
+id = "liboliphaunt-native"
+owner = "@oliphaunt/core"
+kind = "native-core"
+publish_targets = ["github-release-assets", "npm", "maven-central", "crates-io"]
+registry_packages = [
+  "crates:liboliphaunt-native-linux-arm64-gnu",
+  "crates:liboliphaunt-native-linux-x64-gnu",
+  "crates:liboliphaunt-native-macos-arm64",
+  "crates:liboliphaunt-native-windows-x64-msvc",
+  "npm:@oliphaunt/liboliphaunt-darwin-arm64",
+  "npm:@oliphaunt/liboliphaunt-linux-x64-gnu",
+  "npm:@oliphaunt/liboliphaunt-linux-arm64-gnu",
+  "npm:@oliphaunt/liboliphaunt-win32-x64-msvc",
+  "maven:dev.oliphaunt.runtime:liboliphaunt-runtime-resources-android-datum64",
+  "maven:dev.oliphaunt.runtime:liboliphaunt-android-arm64-v8a",
+  "maven:dev.oliphaunt.runtime:liboliphaunt-android-x86_64",
+]
+release_artifacts = [
+  "c-headers",
+  "macos-dylib",
+  "linux-shared-library",
+  "windows-dll",
+  "ios-xcframework",
+  "android-shared-library",
+  "runtime-resources-ios-datum64",
+  "runtime-resources-android-datum64",
+  "icu-data",
+]
diff --git a/src/shared/fixtures/storage/physical-archive-native-v1.properties b/src/runtimes/liboliphaunt-native/smoke/fixtures/physical-archive-native-v1.properties
similarity index 100%
rename from src/shared/fixtures/storage/physical-archive-native-v1.properties
rename to src/runtimes/liboliphaunt-native/smoke/fixtures/physical-archive-native-v1.properties
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_abi_conformance.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_abi_conformance.c
similarity index 99%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_abi_conformance.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_abi_conformance.c
index e0ad9743f..ff1c3807b 100644
--- a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_abi_conformance.c
+++ b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_abi_conformance.c
@@ -26,7 +26,6 @@
             operation " must publish its null-capture validation error"); \
     } while (0)
 
-_Static_assert(OLIPHAUNT_ABI_VERSION == 10u, "unexpected liboliphaunt ABI version");
 _Static_assert(OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION == 1u, "unexpected static extension ABI version");
 _Static_assert(OLIPHAUNT_ERROR_CAPTURE_CAPACITY == 1024u, "unexpected error capture capacity");
 _Static_assert(OLIPHAUNT_STREAM_CALLBACK_ABORTED == 1, "unexpected callback-aborted status");
@@ -42,9 +41,10 @@ _Static_assert(offsetof(OliphauntErrorCapture, message) == 4, "unexpected error
 _Static_assert(sizeof(OliphauntErrorCapture) == 1028, "unexpected error capture size");
 
 #if UINTPTR_MAX == UINT64_MAX
-_Static_assert(sizeof(OliphauntConfig) == 72, "unexpected 64-bit OliphauntConfig size");
+_Static_assert(sizeof(OliphauntConfig) == 80, "unexpected 64-bit OliphauntConfig size");
 _Static_assert(offsetof(OliphauntConfig, module_dir) == 24, "unexpected 64-bit module_dir offset");
 _Static_assert(offsetof(OliphauntConfig, startup_arg_count) == 64, "unexpected 64-bit startup_arg_count offset");
+_Static_assert(offsetof(OliphauntConfig, icu_data_dir) == 72, "unexpected 64-bit icu_data_dir offset");
 _Static_assert(sizeof(OliphauntRestoreOptions) == 32, "unexpected 64-bit OliphauntRestoreOptions size");
 _Static_assert(offsetof(OliphauntRestoreOptions, destination) == 8, "unexpected 64-bit restore destination offset");
 _Static_assert(offsetof(OliphauntRestoreOptions, data) == 16, "unexpected 64-bit restore data offset");
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_cluster_seed_smoke.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_cluster_seed_smoke.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_cluster_seed_smoke.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_cluster_seed_smoke.c
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_error_attribution.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_error_attribution.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_error_attribution.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_error_attribution.c
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_generation_lifecycle.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_generation_lifecycle.c
similarity index 97%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_generation_lifecycle.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_generation_lifecycle.c
index 606b9f066..14e43b97d 100644
--- a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_generation_lifecycle.c
+++ b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_generation_lifecycle.c
@@ -127,6 +127,12 @@ int main(void) {
     };
     CHECK(oliphaunt_config_matches_resident_runtime(&resident_config, &reopen_config),
           "an internally locked resident runtime must accept the same reopen mode");
+    reopen_config.icu_data_dir = "/selected-icu";
+    CHECK(!oliphaunt_config_matches_resident_runtime(&resident_config, &reopen_config),
+          "a resident runtime must reject changing its selected ICU data");
+    resident_config.icu_data_dir = "/selected-icu";
+    CHECK(oliphaunt_config_matches_resident_runtime(&resident_config, &reopen_config),
+          "a resident runtime must accept the same selected ICU data");
     reopen_config.flags = OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK;
     CHECK(!oliphaunt_config_matches_resident_runtime(&resident_config, &reopen_config),
           "an internally locked resident runtime must reject external-lock reopen");
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_module_dir_resolver.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_module_dir_resolver.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_module_dir_resolver.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_module_dir_resolver.c
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_smoke.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_smoke.c
similarity index 94%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_smoke.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_smoke.c
index 5e4e61af9..076f087fd 100644
--- a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_smoke.c
+++ b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_smoke.c
@@ -493,7 +493,7 @@ static WalRangeFixtureCase *wal_fixture_case(
 }
 
 static int verify_shared_wal_range_fixture(void) {
-    const char *path = "src/shared/fixtures/storage/physical-backup-wal-range-v1.properties";
+    const char *path = "src/test-fixtures/storage/physical-backup-wal-range-v1.properties";
     FILE *file = fopen(path, "rb");
     if (file == NULL) {
         fprintf(stderr, "failed to open shared WAL range fixture %s\n", path);
@@ -704,6 +704,7 @@ typedef struct StreamReentrancyProbe {
 
 typedef struct CancelQueryThread {
     OliphauntHandle *db;
+    const char *sql;
     int status;
 } CancelQueryThread;
 
@@ -1086,6 +1087,112 @@ static int exec_stream_expect_tags(
     return 0;
 }
 
+typedef struct IncrementalInputProbe {
+    OliphauntHandle *db;
+    StreamAccumulator response;
+    uint64_t previous_token;
+    uint64_t token;
+    int failed;
+} IncrementalInputProbe;
+
+static int32_t finish_incremental_input(void *context, const uint8_t *data, size_t len) {
+    IncrementalInputProbe *probe = context;
+    if (probe->token == 0) {
+        static const uint8_t sync[] = {'S', 0, 0, 0, 4};
+        static const uint8_t extra_sync[] = {'S', 0, 0, 0, 4, 'S', 0, 0, 0, 4};
+        OliphauntErrorCapture error;
+        probe->token = oliphaunt_protocol_stream_token(probe->db);
+        if (probe->token == 0 || probe->token == probe->previous_token ||
+            oliphaunt_feed_protocol_stream(probe->db, probe->previous_token,
+                sync, sizeof(sync), &error) != -1 || error.length == 0 ||
+            oliphaunt_feed_protocol_stream(probe->db, probe->token,
+                sync, OLIPHAUNT_STREAM_INPUT_MAX_BYTES + 1u, &error) != -1 ||
+            oliphaunt_feed_protocol_stream(probe->db, probe->token,
+                sync, sizeof(sync) - 1, &error) != -1 ||
+            oliphaunt_feed_protocol_stream(probe->db, probe->token,
+                extra_sync, sizeof(extra_sync), &error) != -1) {
+            probe->failed = 1;
+        }
+        if (oliphaunt_feed_protocol_stream(probe->db, probe->token,
+                sync, sizeof(sync), &error) != 0 || error.length != 0 ||
+            oliphaunt_protocol_stream_token(probe->db) != 0 ||
+            oliphaunt_feed_protocol_stream(probe->db, probe->token,
+                sync, sizeof(sync), &error) != -1) {
+            probe->failed = 1;
+        }
+    }
+    return append_stream_chunk(&probe->response, data, len);
+}
+
+static int exec_incremental_input(OliphauntHandle *db) {
+    static const uint8_t parse_flush[] = {
+        'P', 0, 0, 0, 17, 0, 'S', 'E', 'L', 'E', 'C', 'T', ' ', '4', '2', 0, 0, 0,
+        'H', 0, 0, 0, 4,
+    };
+    static uint64_t previous_token = 0;
+    for (int pass = 0; pass < 2; pass++) {
+        IncrementalInputProbe probe = {.db = db, .previous_token = previous_token};
+        int rc = oliphaunt_exec_protocol_raw_stream(db, parse_flush, sizeof(parse_flush),
+            finish_incremental_input, &probe);
+        OliphauntResponse response = {.data = probe.response.data, .len = probe.response.len};
+        int failed = rc != 0 || probe.failed || probe.token == 0 ||
+            oliphaunt_protocol_stream_token(db) != 0 ||
+            !contains_tag(&response, '1') || !contains_tag(&response, 'Z');
+        free(probe.response.data);
+        if (failed) {
+            fprintf(stderr, "incremental Parse/Flush then Sync failed\n");
+            return 1;
+        }
+        previous_token = probe.token;
+    }
+    return 0;
+}
+
+static int32_t feed_copy_input(void *context, const uint8_t *data, size_t len) {
+    IncrementalInputProbe *probe = context;
+    int rc = append_stream_chunk(&probe->response, data, len);
+    OliphauntResponse response = {.data = probe->response.data, .len = probe->response.len};
+    if (probe->token == 0 && contains_tag(&response, 'G')) {
+        static const uint8_t sync[] = {'S', 0, 0, 0, 4};
+        static const uint8_t copy[] = {'d', 0, 0, 0, 7, '4', '2', '\n', 'c', 0, 0, 0, 4};
+        static const uint8_t fail[] = {'f', 0, 0, 0, 12, 'a', 'b', 'o', 'r', 't', 'e', 'd', 0};
+        const uint8_t *input = probe->previous_token ? fail : copy;
+        size_t input_len = probe->previous_token ? sizeof(fail) : sizeof(copy);
+        OliphauntErrorCapture error;
+        probe->token = oliphaunt_protocol_stream_token(probe->db);
+        if (probe->token == 0 ||
+            oliphaunt_feed_protocol_stream(probe->db, probe->token, sync, sizeof(sync), &error) != -1 ||
+            oliphaunt_feed_protocol_stream(probe->db, probe->token, input, input_len, &error) != 0 ||
+            oliphaunt_protocol_stream_token(probe->db) != 0) probe->failed = 1;
+    }
+    return rc;
+}
+
+static int exec_incremental_copy(OliphauntHandle *db) {
+    unsigned char *query = NULL;
+    size_t query_len = 0;
+    push_query(&query, &query_len, "CREATE TEMP TABLE incremental_copy(value int); COPY incremental_copy FROM STDIN");
+    IncrementalInputProbe probe = {.db = db};
+    int rc = oliphaunt_exec_protocol_raw_stream(db, query, query_len, feed_copy_input, &probe);
+    OliphauntResponse response = {.data = probe.response.data, .len = probe.response.len};
+    int failed = rc != 0 || probe.failed || probe.token == 0 ||
+        !contains_tag(&response, 'G') || !contains_tag(&response, 'Z');
+    free(query);
+    free(probe.response.data);
+    if (failed) return 1;
+    if (exec_simple_query_expect_bytes(db, "SELECT value FROM incremental_copy", "42")) return 1;
+    query = NULL;
+    query_len = 0;
+    push_query(&query, &query_len, "COPY incremental_copy FROM STDIN");
+    probe = (IncrementalInputProbe){.db = db, .previous_token = 1};
+    rc = oliphaunt_exec_protocol_raw_stream(db, query, query_len, feed_copy_input, &probe);
+    response = (OliphauntResponse){.data = probe.response.data, .len = probe.response.len};
+    failed = rc != 0 || probe.failed || !contains_tag(&response, 'E') || !contains_tag(&response, 'Z');
+    free(query);
+    free(probe.response.data);
+    return failed || exec_simple_query_expect_bytes(db, "SELECT count(*) FROM incremental_copy", "1");
+}
+
 static int exec_stream_callback_failure_recovers(OliphauntHandle *db) {
     unsigned char *query = NULL;
     size_t query_len = 0;
@@ -1163,7 +1270,7 @@ static void *cancel_query_thread_main(void *context) {
     CancelQueryThread *state = (CancelQueryThread *)context;
     unsigned char *query = NULL;
     size_t query_len = 0;
-    push_query(&query, &query_len, "SELECT pg_sleep(5) AS should_cancel");
+    push_query(&query, &query_len, state->sql);
 
     OliphauntResponse response = {0};
     fprintf(stderr, "executing cancellable raw protocol query\n");
@@ -1193,9 +1300,22 @@ static void *cancel_query_thread_main(void *context) {
     return NULL;
 }
 
-static int exec_cancel_recovers(OliphauntHandle *db) {
+static uint64_t smoke_monotonic_millis(void) {
+#ifdef _WIN32
+    return GetTickCount64();
+#else
+    struct timespec now;
+    if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
+        abort();
+    }
+    return (uint64_t)now.tv_sec * 1000u + (uint64_t)now.tv_nsec / 1000000u;
+#endif
+}
+
+static int exec_cancel_recovers(OliphauntHandle *db, const char *sql) {
     CancelQueryThread state = {
         .db = db,
+        .sql = sql,
         .status = 1,
     };
     pthread_t thread;
@@ -1206,12 +1326,17 @@ static int exec_cancel_recovers(OliphauntHandle *db) {
 
     smoke_sleep_millis(100);
     fprintf(stderr, "cancelling active raw protocol query\n");
+    uint64_t cancel_started = smoke_monotonic_millis();
     if (oliphaunt_cancel(db) != 0) {
         fprintf(stderr, "oliphaunt_cancel failed: %s\n", last_error_message(db));
         pthread_join(thread, NULL);
         return 1;
     }
     pthread_join(thread, NULL);
+    if (smoke_monotonic_millis() - cancel_started >= 3000u) {
+        fprintf(stderr, "cancellation did not wake the sleeping backend within three seconds\n");
+        return 1;
+    }
     if (state.status != 0) {
         return 1;
     }
@@ -2670,7 +2795,7 @@ static int run_cycle(const char *pgdata, const char *runtime_dir) {
         return 1;
     }
 
-    if (exec_stream_callback_failure_recovers(db) != 0) {
+    if (exec_incremental_input(db) != 0 || exec_incremental_copy(db) != 0 || exec_stream_callback_failure_recovers(db) != 0) {
         oliphaunt_close(db);
         return 1;
     }
@@ -2680,7 +2805,9 @@ static int run_cycle(const char *pgdata, const char *runtime_dir) {
         return 1;
     }
 
-    if (exec_cancel_recovers(db) != 0) {
+    if (exec_cancel_recovers(db, "SELECT pg_sleep(5)") != 0 ||
+        exec_cancel_recovers(db, "DO $$ BEGIN PERFORM pg_sleep(5); END $$") != 0 ||
+        exec_cancel_recovers(db, "SELECT pg_sleep(5)") != 0) {
         oliphaunt_close(db);
         return 1;
     }
@@ -2770,7 +2897,8 @@ static int run_cycle(const char *pgdata, const char *runtime_dir) {
         oliphaunt_close(reopened);
         return 1;
     }
-    if (exec_query_expect_tags(reopened, "SELECT 42 AS reopened_after_stale_close", select_tags, sizeof(select_tags)) != 0) {
+    if (exec_incremental_input(reopened) != 0 ||
+        exec_query_expect_tags(reopened, "SELECT 42 AS reopened_after_stale_close", select_tags, sizeof(select_tags)) != 0) {
         oliphaunt_close(reopened);
         return 1;
     }
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_static_extension_registry.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_static_extension_registry.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_static_extension_registry.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_static_extension_registry.c
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_symbol_scope_consumer.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_symbol_scope_consumer.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_symbol_scope_consumer.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_symbol_scope_consumer.c
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_symbol_scope_host.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_symbol_scope_host.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_symbol_scope_host.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_symbol_scope_host.c
diff --git a/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_symbol_scope_provider.c b/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_symbol_scope_provider.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/smoke/liboliphaunt_symbol_scope_provider.c
rename to src/runtimes/liboliphaunt-native/smoke/liboliphaunt_symbol_scope_provider.c
diff --git a/src/sources/third-party/native/icu-windows.toml b/src/runtimes/liboliphaunt-native/sources/icu-windows.toml
similarity index 100%
rename from src/sources/third-party/native/icu-windows.toml
rename to src/runtimes/liboliphaunt-native/sources/icu-windows.toml
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_archive.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_archive.c
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_archive_tar.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_archive_tar.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_archive_tar.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_archive_tar.c
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_backup_state.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_backup_state.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_backup_state.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_backup_state.c
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_builtin_extensions.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_builtin_extensions.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_builtin_extensions.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_builtin_extensions.c
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_config.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_config.c
similarity index 99%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_config.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_config.c
index d481c63d3..4bc32298f 100644
--- a/src/runtimes/liboliphaunt/native/src/liboliphaunt_config.c
+++ b/src/runtimes/liboliphaunt-native/src/liboliphaunt_config.c
@@ -54,6 +54,7 @@ bool oliphaunt_config_matches_resident_runtime(
            config_string_matches(handle->pgdata, config->pgdata, "") &&
            config_string_matches(handle->runtime_dir, config->runtime_dir, "") &&
            config_string_matches(handle->module_dir, config->module_dir, "") &&
+           config_string_matches(handle->icu_data_dir, config->icu_data_dir, "") &&
            config_string_matches(handle->username, config->username, "postgres") &&
            config_string_matches(handle->database, config->database, "postgres") &&
            startup_args_match(handle, config);
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_error.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_error.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_error.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_error.c
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_fs.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_fs.c
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h b/src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h
similarity index 99%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h
index 9fe6d3e24..cccf4b478 100644
--- a/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h
+++ b/src/runtimes/liboliphaunt-native/src/liboliphaunt_internal.h
@@ -131,6 +131,7 @@ struct OliphauntHandle {
     char *pgdata;
     char *runtime_dir;
     char *module_dir;
+    char *icu_data_dir;
     char *username;
     char *database;
     char *postgres_path;
@@ -187,6 +188,9 @@ struct OliphauntHandle {
     bool backup_mode_exit_unconfirmed;
 
     bool streaming;
+    uint64_t stream_token;
+    bool stream_input_closed;
+    bool stream_copy_input;
     bool stream_failed;
     OliphauntOutputChunk *stream_head;
     OliphauntOutputChunk *stream_tail;
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_native.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_native.c
similarity index 97%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_native.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_native.c
index 8147cf7c4..8a996cacf 100644
--- a/src/runtimes/liboliphaunt/native/src/liboliphaunt_native.c
+++ b/src/runtimes/liboliphaunt-native/src/liboliphaunt_native.c
@@ -216,7 +216,12 @@ static int clear_backend_internal_collation_env(OliphauntHandle *handle) {
 }
 
 static int set_backend_icu_data_env(OliphauntHandle *handle) {
-    char *icu_data_dir = oliphaunt_runtime_icu_data_dir(handle->runtime_dir);
+    char *discovered = NULL;
+    const char *icu_data_dir = handle->icu_data_dir;
+    if (icu_data_dir == NULL || icu_data_dir[0] == '\0') {
+        discovered = oliphaunt_runtime_icu_data_dir(handle->runtime_dir);
+        icu_data_dir = discovered;
+    }
     if (icu_data_dir == NULL) {
         return unset_backend_env_var(
             handle,
@@ -234,7 +239,7 @@ static int set_backend_icu_data_env(OliphauntHandle *handle) {
         &handle->had_previous_icu_data_env,
         &handle->icu_data_env_overridden,
         "ICU data");
-    free(icu_data_dir);
+    free(discovered);
     return rc;
 }
 
@@ -471,6 +476,11 @@ static int32_t oliphaunt_init_impl(const OliphauntConfig *config, OliphauntHandl
         set_error(NULL, "invalid oliphaunt_init module_dir");
         return -1;
     }
+    if (config->icu_data_dir != NULL &&
+        (config->icu_data_dir[0] == '\0' || !oliphaunt_path_is_directory(config->icu_data_dir))) {
+        set_error(NULL, "invalid oliphaunt_init icu_data_dir");
+        return -1;
+    }
     if ((config->flags & ~OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK) != 0) {
         set_error(NULL, "invalid oliphaunt_init config flags");
         return -1;
@@ -516,9 +526,10 @@ static int32_t oliphaunt_init_impl(const OliphauntConfig *config, OliphauntHandl
     handle->pgdata = oliphaunt_dup_config_string(config->pgdata, "");
     handle->runtime_dir = oliphaunt_dup_config_string(config->runtime_dir, "");
     handle->module_dir = oliphaunt_dup_config_string(config->module_dir, "");
+    handle->icu_data_dir = oliphaunt_dup_config_string(config->icu_data_dir, "");
     handle->username = oliphaunt_dup_config_string(config->username, "postgres");
     handle->database = oliphaunt_dup_config_string(config->database, "postgres");
-    if (handle->pgdata == NULL || handle->runtime_dir == NULL || handle->module_dir == NULL ||
+    if (handle->pgdata == NULL || handle->runtime_dir == NULL || handle->module_dir == NULL || handle->icu_data_dir == NULL ||
         handle->username == NULL || handle->database == NULL) {
         close_unpublished_handle(handle);
         set_error(NULL, "out of memory copying oliphaunt config");
@@ -761,6 +772,7 @@ int32_t oliphaunt_close_claimed_global_instance(OliphauntHandle *handle) {
     free(handle->pgdata);
     free(handle->runtime_dir);
     free(handle->module_dir);
+    free(handle->icu_data_dir);
     free(handle->username);
     free(handle->database);
     free(handle->postgres_path);
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_platform.h b/src/runtimes/liboliphaunt-native/src/liboliphaunt_platform.h
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_platform.h
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_platform.h
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_protocol.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_protocol.c
similarity index 87%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_protocol.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_protocol.c
index 70b6b1c9d..0d5fc45f5 100644
--- a/src/runtimes/liboliphaunt/native/src/liboliphaunt_protocol.c
+++ b/src/runtimes/liboliphaunt-native/src/liboliphaunt_protocol.c
@@ -107,6 +107,8 @@ static bool scan_stream_ready_locked(OliphauntHandle *handle, const unsigned cha
             scanner->payload_remaining = (size_t)msg_len - 4;
             if (scanner->payload_remaining == 0) {
                 bool ready = scanner->tag == 'Z';
+                if (scanner->tag == 'G') handle->stream_copy_input = true;
+                if (scanner->tag == 'E' || ready) handle->stream_copy_input = false;
                 if (ready) {
                     handle->transaction_status = 'I';
                 }
@@ -128,6 +130,8 @@ static bool scan_stream_ready_locked(OliphauntHandle *handle, const unsigned cha
             scanner->payload_remaining -= take;
             if (scanner->payload_remaining == 0) {
                 bool ready = scanner->tag == 'Z';
+                if (scanner->tag == 'G') handle->stream_copy_input = true;
+                if (scanner->tag == 'E' || ready) handle->stream_copy_input = false;
                 if (ready) {
                     handle->transaction_status = scanner->ready_status_set ? scanner->ready_status : 'I';
                 }
@@ -761,6 +765,100 @@ int32_t oliphaunt_exec_simple_query_with_error(
         handle, sql, sql_len, out, error, true);
 }
 
+/* The caller has already validated complete frame lengths. */
+static bool request_closes_stream_input(const uint8_t *request, size_t len) {
+    for (size_t off = 0; off < len; off += (size_t)read_be32(request + off + 1) + 1) {
+        if (request[off] == 'Q' || request[off] == 'S' || request[off] == 'X') {
+            return true;
+        }
+    }
+    return false;
+}
+
+uint64_t oliphaunt_protocol_stream_token(OliphauntHandle *handle) {
+    if (oliphaunt_begin_handle_call(handle) != 0) {
+        return 0;
+    }
+    pthread_mutex_lock(&handle->mutex);
+    uint64_t token = handle->streaming && handle->logical_active &&
+        !handle->closing && !handle->backend_exited && !handle->output_ready &&
+        !handle->stream_failed && (!handle->stream_input_closed || handle->stream_copy_input)
+            ? handle->stream_token : 0;
+    pthread_mutex_unlock(&handle->mutex);
+    oliphaunt_end_handle_call();
+    return token;
+}
+
+int32_t oliphaunt_feed_protocol_stream(
+    OliphauntHandle *handle, uint64_t token, const uint8_t *request,
+    size_t request_len, OliphauntErrorCapture *capture) {
+    OliphauntErrorScope scope;
+    oliphaunt_error_scope_begin(&scope, NULL, "oliphaunt_feed_protocol_stream");
+    int32_t rc = -1;
+    bool leased = oliphaunt_begin_handle_call(handle) == 0;
+    if (!leased) {
+        goto done;
+    }
+    scope.fallback_handle = handle;
+    if (token == 0 || request == NULL || request_len == 0 ||
+        request_len > OLIPHAUNT_STREAM_INPUT_MAX_BYTES) {
+        set_error(handle, "invalid or oversized protocol stream input");
+        goto done;
+    }
+    if (validate_frontend_protocol_frames(handle, request, request_len) != 0) {
+        goto done;
+    }
+    for (size_t off = 0; off < request_len;) {
+        size_t end = off + (size_t)read_be32(request + off + 1) + 1;
+        if ((request[off] == 'Q' || request[off] == 'S' || request[off] == 'X') &&
+            end != request_len) {
+            set_error(handle, "protocol stream input continues beyond its completion frame");
+            goto done;
+        }
+        off = end;
+    }
+    pthread_mutex_lock(&handle->mutex);
+    if (!handle->streaming || handle->stream_token != token || !handle->logical_active ||
+        handle->closing || handle->backend_exited || handle->stream_failed ||
+        handle->output_ready || (handle->stream_input_closed && !handle->stream_copy_input)) {
+        set_error(handle, "protocol stream input token is no longer active");
+    } else if (handle->input_len != 0) {
+        rc = OLIPHAUNT_STREAM_INPUT_BUSY;
+    } else {
+        bool copy_finished = false;
+        if (handle->stream_copy_input) {
+            for (size_t off = 0; off < request_len;) {
+                uint8_t tag = request[off];
+                size_t end = off + (size_t)read_be32(request + off + 1) + 1;
+                if ((tag != 'd' && tag != 'c' && tag != 'f' && tag != 'X') ||
+                    ((tag == 'c' || tag == 'f' || tag == 'X') && end != request_len)) {
+                    set_error(handle, "COPY input accepts only CopyData followed by CopyDone, CopyFail, or Terminate");
+                    pthread_mutex_unlock(&handle->mutex);
+                    goto done;
+                }
+                copy_finished = tag != 'd';
+                off = end;
+            }
+        }
+        rc = oliphaunt_set_input_locked(handle, request, request_len);
+        if (rc == 0) {
+            if (handle->stream_copy_input) {
+                if (copy_finished) handle->stream_copy_input = false;
+            } else {
+                handle->stream_input_closed = request_closes_stream_input(request, request_len);
+            }
+        }
+    }
+    pthread_mutex_unlock(&handle->mutex);
+done:
+    oliphaunt_error_scope_end(&scope, rc < 0);
+    oliphaunt_error_capture_current(capture, leased ? handle : NULL, rc < 0);
+    if (leased) {
+        oliphaunt_end_handle_call();
+    }
+    return rc;
+}
+
 static int32_t oliphaunt_exec_protocol_raw_stream_impl(
     OliphauntHandle *handle,
     const uint8_t *request,
@@ -797,6 +895,15 @@ static int32_t oliphaunt_exec_protocol_raw_stream_impl(
         return -1;
     }
 
+    if (handle->stream_token == UINT64_MAX) {
+        set_error(handle, "protocol stream token space is exhausted");
+        pthread_mutex_unlock(&handle->mutex);
+        return -1;
+    }
+    handle->stream_token++;
+    handle->stream_input_closed = request_closes_stream_input(request, request_len);
+    handle->stream_copy_input = false;
+
     handle->output_len = 0;
     handle->output_scan_off = 0;
     handle->output_ready = false;
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_runtime.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_runtime.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_runtime.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_runtime.c
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_static_extensions.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_static_extensions.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_static_extensions.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_static_extensions.c
diff --git a/src/runtimes/liboliphaunt/native/src/liboliphaunt_trace.c b/src/runtimes/liboliphaunt-native/src/liboliphaunt_trace.c
similarity index 100%
rename from src/runtimes/liboliphaunt/native/src/liboliphaunt_trace.c
rename to src/runtimes/liboliphaunt-native/src/liboliphaunt_trace.c
diff --git a/src/runtimes/liboliphaunt/native/tools/audit-macos-module-nm.awk b/src/runtimes/liboliphaunt-native/tools/audit-macos-module-nm.awk
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools/audit-macos-module-nm.awk
rename to src/runtimes/liboliphaunt-native/tools/audit-macos-module-nm.awk
diff --git a/src/runtimes/liboliphaunt/native/tools/audit-macos-provider-collisions.awk b/src/runtimes/liboliphaunt-native/tools/audit-macos-provider-collisions.awk
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools/audit-macos-provider-collisions.awk
rename to src/runtimes/liboliphaunt-native/tools/audit-macos-provider-collisions.awk
diff --git a/src/runtimes/liboliphaunt-native/tools/build-ci-target.sh b/src/runtimes/liboliphaunt-native/tools/build-ci-target.sh
new file mode 100755
index 000000000..54daacf44
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/build-ci-target.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+cd "$root"
+target="${1:-}"
+case "$target" in android-arm64-v8a|android-x86_64|ios-xcframework) ;; *) echo 'usage: build-ci-target.sh android-arm64-v8a|android-x86_64|ios-xcframework' >&2; exit 2 ;; esac
+[ -z "${OLIPHAUNT_CI_MOBILE_EXTENSIONS-${OLIPHAUNT_MOBILE_STATIC_EXTENSIONS-}}" ] || { echo 'build exact extension artifacts through the extension artifact lane' >&2; exit 2; }
+stage_root="$root/target/liboliphaunt-native-ci/$target"
+host_root="target/liboliphaunt-mobile-host/$target"
+pg_version="$(awk -F '"' '/^version = / { print $2; exit }' src/third-party/postgres/source.toml)"
+[ -n "$pg_version" ] || { echo 'PostgreSQL version is missing' >&2; exit 1; }
+rm -rf "$stage_root"
+mkdir -p "$stage_root"
+stage() {
+  [ -d "$root/$1" ] || { echo "missing CI artifact: $1" >&2; exit 1; }
+  mkdir -p "$stage_root/$1"
+  rsync -a --delete "$root/$1/" "$stage_root/$1/"
+}
+receipt() {
+  bun src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts write --build-root "$root/$1/postgresql-$pg_version" --target "$2" --output "$root/$3"
+}
+case "$target" in
+  android-*)
+    if [ "$target" = android-arm64-v8a ]; then
+      mobile_root=target/liboliphaunt-pg18-android-arm64
+      OLIPHAUNT_ANDROID_ABI=arm64-v8a OLIPHAUNT_ANDROID_ARM64_ROOT="$root/$mobile_root" bash src/runtimes/liboliphaunt-native/bin/build-postgres18-android-arm64.sh
+      host_args=(--runtime-only)
+    else
+      mobile_root=target/liboliphaunt-pg18-android-x86_64
+      OLIPHAUNT_ANDROID_ABI=x86_64 OLIPHAUNT_ANDROID_X86_64_ROOT="$root/$mobile_root" bash src/runtimes/liboliphaunt-native/bin/build-postgres18-android-x86_64.sh
+      host_args=()
+    fi
+    OLIPHAUNT_LINUX_WORK_ROOT="$root/$host_root" bash src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh "${host_args[@]}"
+    receipt "$host_root" linux-x64-gnu "$mobile_root/out/native-mobile-abi-producer.properties"
+    receipt "$mobile_root" "$target" "$mobile_root/out/native-mobile-abi.properties"
+    stage "$mobile_root/out"
+    stage "$host_root/install"
+    stage "$host_root/icu/share/icu"
+    [ "$target" != android-x86_64 ] || stage "$host_root/out/modules"
+    ;;
+  ios-xcframework)
+    OLIPHAUNT_WORK_ROOT="$root/$host_root" bash src/runtimes/liboliphaunt-native/bin/build-ios-xcframework.sh
+    OLIPHAUNT_BUILD_EXTENSIONS="${OLIPHAUNT_BUILD_EXTENSIONS-0}" OLIPHAUNT_WORK_ROOT="$root/$host_root" bash src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh --runtime-only
+    device=target/liboliphaunt-ios-device
+    simulator=target/liboliphaunt-ios-simulator
+    framework=target/liboliphaunt-ios-xcframework
+    receipt "$host_root" macos-arm64 "$framework/out/native-mobile-abi-producer.properties"
+    receipt "$device" ios-arm64 "$device/out/native-mobile-abi.properties"
+    receipt "$simulator" ios-arm64-simulator "$simulator/out/native-mobile-abi.properties"
+    bun src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts compare --domain ios-datum64 --receipt "$root/$device/out/native-mobile-abi.properties" --receipt "$root/$simulator/out/native-mobile-abi.properties" --receipt "$root/$framework/out/native-mobile-abi-producer.properties"
+    stage "$framework/out"
+    stage "$simulator/out"
+    stage "$device/out"
+    stage "$host_root/install"
+    stage "$host_root/icu/share/icu"
+    ;;
+esac
+printf 'Staged native CI artifact: %s\n' "$stage_root"
diff --git a/src/runtimes/liboliphaunt-native/tools/build-dispatch.test.sh b/src/runtimes/liboliphaunt-native/tools/build-dispatch.test.sh
new file mode 100755
index 000000000..0494ab8c5
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/build-dispatch.test.sh
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+fixture="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-build-dispatch.XXXXXX")"
+trap 'rm -rf "$fixture"' EXIT
+cd "$fixture"
+git init -q
+owner=src/runtimes/liboliphaunt-native
+mkdir -p "$owner/tools" "$owner/bin" src/third-party/postgres bin
+cp "$root/$owner/tools/release-runtime.sh" "$root/$owner/tools/build-ci-target.sh" "$root/$owner/tools/runtime-preflight.sh" "$owner/tools/"
+cp "$root/src/third-party/postgres/source.toml" src/third-party/postgres/
+export PATH="$fixture/bin:$PATH" CAPTURE="$fixture/calls" TEST_HOST=Linux TEST_ARCH=x86_64
+cat > bin/uname <<'STUB'
+#!/usr/bin/env bash
+case "$1" in
+  -s) printf '%s\n' "$TEST_HOST" ;;
+  -m) printf '%s\n' "$TEST_ARCH" ;;
+  *) exit 1 ;;
+esac
+STUB
+cat > bin/bun <<'STUB'
+#!/usr/bin/env bash
+printf '%s\n' "$*" >>"$CAPTURE"
+STUB
+cat > bin/product-build <<'STUB'
+#!/usr/bin/env bash
+set -euo pipefail
+printf '%s %s\n' "$(basename "$0")" "$*" >>"$CAPTURE"
+if [ -n "${FAIL_BUILD:-}" ]; then exit 19; fi
+if [ -n "${OLIPHAUNT_ANDROID_ARM64_ROOT:-}" ]; then mkdir -p "$OLIPHAUNT_ANDROID_ARM64_ROOT/out"; fi
+if [ -n "${OLIPHAUNT_ANDROID_X86_64_ROOT:-}" ]; then mkdir -p "$OLIPHAUNT_ANDROID_X86_64_ROOT/out"; fi
+host="${OLIPHAUNT_LINUX_WORK_ROOT:-${OLIPHAUNT_WORK_ROOT:-}}"
+if [ -n "$host" ]; then mkdir -p "$host/install" "$host/icu/share/icu" "$host/out/modules"; printf library >"$host/install/library"; printf data >"$host/icu/share/icu/icudt76l.dat"; fi
+case "$0" in *build-ios-xcframework.sh) mkdir -p target/liboliphaunt-ios-{device,simulator,xcframework}/out ;; esac
+case "$0" in *package-*) printf '%s %s %s\n' "$OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS" "$OLIPHAUNT_RELEASE_BUILD_RUNTIME" "$OLIPHAUNT_RELEASE_FETCH_ASSETS" >>"$CAPTURE" ;; esac
+STUB
+chmod +x bin/*
+for name in build-postgres18-linux build-postgres18-macos build-postgres18-windows build-postgres18-android-arm64 build-postgres18-android-x86_64 build-ios-xcframework; do cp bin/product-build "$owner/bin/$name.sh"; done
+for platform in linux macos windows; do cp bin/product-build "$owner/tools/package-liboliphaunt-$platform-assets.sh"; done
+for target in android-arm64-v8a android-x86_64 ios-xcframework; do
+  : >"$CAPTURE"
+  bash "$owner/tools/build-ci-target.sh" "$target"
+  test -f "target/liboliphaunt-native-ci/$target/target/liboliphaunt-mobile-host/$target/install/library"
+  test "$(cat "target/liboliphaunt-native-ci/$target/target/liboliphaunt-mobile-host/$target/icu/share/icu/icudt76l.dat")" = data
+  if [ "$target" = android-x86_64 ]; then
+    ! grep -q -- '--runtime-only' "$CAPTURE"
+    test -d "target/liboliphaunt-native-ci/$target/target/liboliphaunt-mobile-host/$target/out/modules"
+  else grep -q -- '--runtime-only' "$CAPTURE"; fi
+  if [ "$target" = ios-xcframework ]; then grep -q 'compare --domain ios-datum64' "$CAPTURE"; fi
+done
+for pair in Linux:linux-x64-gnu Darwin:macos-arm64 MINGW64_NT:windows-x64-msvc; do
+  export TEST_HOST="${pair%%:*}" OLIPHAUNT_CI_TARGET="${pair#*:}"
+  case "$TEST_HOST" in Darwin) export TEST_ARCH=arm64 ;; *) export TEST_ARCH=x86_64 ;; esac
+  : >"$CAPTURE"
+  bash "$owner/tools/release-runtime.sh" build
+  bash "$owner/tools/release-runtime.sh" package
+  if [ "$TEST_HOST" = MINGW64_NT ]; then
+    grep -q 'build-postgres18-windows.sh' "$CAPTURE"
+  fi
+  grep -q "desktop-release-assets/$OLIPHAUNT_CI_TARGET 0 0" "$CAPTURE"
+  expected="$(cat "$CAPTURE")"
+  : >"$CAPTURE"
+  env -u OLIPHAUNT_CI_TARGET bash "$owner/tools/release-runtime.sh" build
+  env -u OLIPHAUNT_CI_TARGET bash "$owner/tools/release-runtime.sh" package
+  test "$(cat "$CAPTURE")" = "$expected"
+  if [ "$TEST_HOST" = MINGW64_NT ]; then
+    if FAIL_BUILD=1 bash "$owner/tools/release-runtime.sh" build; then exit 1; else test "$?" = 19; fi
+  fi
+done
+: >"$CAPTURE"
+if TEST_HOST=Linux OLIPHAUNT_CI_TARGET=macos-arm64 bash "$owner/tools/release-runtime.sh" build; then exit 1; fi
+test ! -s "$CAPTURE"
+if FAIL_BUILD=1 TEST_HOST=Linux OLIPHAUNT_CI_TARGET=linux-x64-gnu bash "$owner/tools/release-runtime.sh" build; then exit 1; else test "$?" = 19; fi
+printf 'Native build and package dispatch passed.\n'
diff --git a/src/runtimes/liboliphaunt-native/tools/check-release-assets.mts b/src/runtimes/liboliphaunt-native/tools/check-release-assets.mts
new file mode 100644
index 000000000..998780cb6
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/check-release-assets.mts
@@ -0,0 +1,511 @@
+#!/usr/bin/env bun
+import { createHash } from 'node:crypto';
+import {
+  chmodSync,
+  existsSync,
+  mkdirSync,
+  mkdtempSync,
+  readdirSync,
+  readFileSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import { parseProperties } from '../../../database-resources/contracts/native-manifest.mts';
+import { inspectPlatformBinaryTree } from '../../../../tools/packaging/platform-binary-contract.mts';
+import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts';
+import { assertReleaseNoticesInArchive } from '../../../../tools/packaging/release-notices.mts';
+import {
+  allArtifactTargets,
+  compareText,
+  currentProductVersion,
+  ROOT,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  compareNativeMobileAbiReceipts,
+  NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN,
+} from './native-mobile-abi-contract.mts';
+import { SNOWBALL_STOPWORD_LANGUAGES, validatePayload } from './native-runtime-payload.mts';
+
+const PREFIX = 'check-liboliphaunt-release-assets.mts';
+const PRODUCT = 'liboliphaunt-native';
+
+function fail(message) {
+  console.error(`${PREFIX}: ${message}`);
+  process.exit(1);
+}
+
+function rel(file) {
+  const relative = path.relative(ROOT, file);
+  if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
+    return file;
+  }
+  return relative.split(path.sep).join('/');
+}
+
+function sha256(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function requireFile(file, description) {
+  let stat;
+  try {
+    stat = statSync(file);
+  } catch {
+    fail(`missing ${description}: ${file}`);
+  }
+  if (!stat.isFile()) {
+    fail(`${description} is not a file: ${file}`);
+  }
+  if (stat.size <= 0) {
+    fail(`${description} is empty: ${file}`);
+  }
+}
+
+function parseChecksumFile(file) {
+  const checksums = new Map();
+  for (const rawLine of readFileSync(file, 'utf8').split(/\r?\n/u)) {
+    if (!rawLine.trim()) {
+      continue;
+    }
+    const parts = rawLine.trim().split(/\s+/u);
+    if (parts.length !== 2) {
+      fail(`malformed checksum line in ${file}: ${JSON.stringify(rawLine)}`);
+    }
+    const [digest, filename] = parts;
+    if (!filename.startsWith('./')) {
+      fail(`checksum path must be relative './name': ${filename}`);
+    }
+    checksums.set(filename.slice(2), digest);
+  }
+  return checksums;
+}
+
+function validateChecksums(assetDir, checksumFile) {
+  const checksums = parseChecksumFile(checksumFile);
+  const expectedAssets = readdirSync(assetDir)
+    .map((name) => path.join(assetDir, name))
+    .filter((file) => statSync(file).isFile() && path.extname(file) !== '.sha256')
+    .sort(compareText);
+  if (expectedAssets.length === 0) {
+    fail(`no release assets found in ${assetDir}`);
+  }
+  const assetNames = new Set(expectedAssets.map((file) => path.basename(file)));
+  for (const asset of expectedAssets) {
+    const recorded = checksums.get(path.basename(asset));
+    if (!recorded) {
+      fail(`checksum file does not cover release asset: ${path.basename(asset)}`);
+    }
+    const actual = sha256(asset);
+    if (recorded !== actual) {
+      fail(`checksum mismatch for ${path.basename(asset)}: expected ${recorded}, got ${actual}`);
+    }
+  }
+  const extra = [...checksums.keys()].filter((name) => !assetNames.has(name)).sort(compareText);
+  if (extra.length > 0) {
+    fail(`checksum file contains entries for missing assets: ${extra.join(', ')}`);
+  }
+}
+
+function generatedExtensionMetadata() {
+  const metadataPath = path.join(ROOT, 'src/extensions/generated/sdk/extensions.json');
+  let metadata;
+  try {
+    metadata = JSON.parse(readFileSync(metadataPath, 'utf8'));
+  } catch (error) {
+    fail(`read generated Rust SDK extension metadata ${metadataPath}: ${error.message}`);
+  }
+  if (!Array.isArray(metadata.extensions)) {
+    fail(`${metadataPath} must define an extensions array`);
+  }
+  const expected = new Map();
+  for (const [index, row] of metadata.extensions.entries()) {
+    if (row === null || Array.isArray(row) || typeof row !== 'object') {
+      fail(`${metadataPath} extensions[${index}] must be an object`);
+    }
+    const sqlName = row['sql-name'];
+    if (typeof sqlName !== 'string' || !sqlName) {
+      fail(`${metadataPath} extensions[${index}] must define sql-name`);
+    }
+    const dataFiles = row['runtime-share-data-files'];
+    if (!Array.isArray(dataFiles) || !dataFiles.every((value) => typeof value === 'string')) {
+      fail(`${metadataPath} extension ${sqlName} must define runtime-share-data-files`);
+    }
+    const nativeModuleStem = row['native-module-stem'];
+    if (
+      nativeModuleStem !== null &&
+      nativeModuleStem !== undefined &&
+      typeof nativeModuleStem !== 'string'
+    ) {
+      fail(`${metadataPath} extension ${sqlName} native-module-stem must be a string or null`);
+    }
+    expected.set(sqlName, {
+      createsExtension: row['creates-extension'] === true,
+      dataFiles,
+      dataFilesTsv: dataFiles.length > 0 ? dataFiles.join(',') : '-',
+      nativeModuleStem,
+    });
+  }
+  return expected;
+}
+
+function readArchiveEntries(file) {
+  try {
+    return readPortableArchiveEntries(file);
+  } catch (error) {
+    fail(`${file} is not a strict portable release archive: ${error.message}`);
+  }
+}
+
+function archiveText(entries, file, memberName) {
+  const entry = entries.get(memberName);
+  if (!entry) {
+    fail(`${file} is missing ${memberName}`);
+  }
+  if (!entry.isFile) {
+    fail(`${file} member ${memberName} is not a regular file`);
+  }
+  try {
+    const data = typeof entry.data === 'function' ? entry.data() : entry.data;
+    return Buffer.from(data).toString('utf8');
+  } catch (error) {
+    fail(`${file} member ${memberName} is not readable UTF-8: ${error.message}`);
+  }
+}
+
+function validateMobileAbiProofEntries(entries, file, domain, prefix = 'oliphaunt/') {
+  const targets = NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[domain];
+  if (targets === undefined) fail(`${file} uses unsupported mobile ABI domain ${domain}`);
+  const proofPrefix = `${prefix}provenance/native-mobile-abi/`;
+  try {
+    compareNativeMobileAbiReceipts(
+      domain,
+      targets.map((target) => {
+        const member = `${proofPrefix}${target}.properties`;
+        return { label: `${file} ${member}`, text: archiveText(entries, file, member) };
+      }),
+    );
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+}
+
+function extractArchive(file, destination) {
+  rmSync(destination, { recursive: true, force: true });
+  mkdirSync(destination, { recursive: true });
+  for (const [name, entry] of readArchiveEntries(file)) {
+    if (entry.isDirectory) {
+      continue;
+    }
+    if (!entry.isFile) {
+      fail(`${file} member ${name} must be a regular file`);
+    }
+    const output = path.join(destination, ...name.split('/'));
+    mkdirSync(path.dirname(output), { recursive: true });
+    const data = typeof entry.data === 'function' ? entry.data() : entry.data;
+    writeFileSync(output, data);
+    if (entry.mode) {
+      chmodSync(output, entry.mode & 0o777);
+    }
+  }
+}
+
+async function validateNativeTargetArtifact(file, target, { requireRuntime, toolSet }) {
+  if (requireRuntime && toolSet === 'runtime') {
+    const entries = readPortableArchiveEntries(file);
+    if (target === 'windows-x64-msvc') {
+      for (const directory of ['bin', 'runtime/bin']) {
+        for (const name of ['icudt76.dll', 'icuin76.dll', 'icuuc76.dll']) {
+          const member = `${directory}/${name}`;
+          const entry = entries.get(member);
+          if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) {
+            fail(`${file} ICU-enabled Windows runtime is missing ${member}`);
+          }
+        }
+      }
+    }
+  }
+  const temp = mkdtempSync(path.join(tmpdir(), `oliphaunt-native-${target}-`));
+  try {
+    const extracted = path.join(temp, 'payload');
+    extractArchive(file, extracted);
+    await inspectPlatformBinaryTree(extracted, {
+      target,
+      requireWindowsRuntimeImportLibrary: target === 'windows-x64-msvc' && toolSet === 'runtime',
+      windowsVcRuntimeProfile:
+        target === 'windows-x64-msvc' && toolSet === 'runtime' ? 'provider' : undefined,
+    });
+    validatePayload(extracted, target, { requireRuntime, toolSet });
+  } finally {
+    rmSync(temp, { recursive: true, force: true });
+  }
+}
+
+function assetName(target, version) {
+  return target.asset.replaceAll('{version}', version);
+}
+
+async function validateNativeTargetArtifacts(assetDir, version) {
+  const runtimeTargets = new Set(
+    allArtifactTargets({
+      product: PRODUCT,
+      kind: 'native-runtime',
+      surface: 'rust-native-direct',
+    }).map((target) => target.target),
+  );
+  for (const target of allArtifactTargets({
+    product: PRODUCT,
+    kind: 'native-runtime',
+    surface: 'github-release',
+  })) {
+    await validateNativeTargetArtifact(
+      path.join(assetDir, assetName(target, version)),
+      target.target,
+      {
+        requireRuntime: runtimeTargets.has(target.target),
+        toolSet: 'runtime',
+      },
+    );
+  }
+  for (const target of allArtifactTargets({
+    product: PRODUCT,
+    kind: 'native-tools',
+    surface: 'github-release',
+  })) {
+    await validateNativeTargetArtifact(
+      path.join(assetDir, assetName(target, version)),
+      target.target,
+      {
+        requireRuntime: true,
+        toolSet: 'tools',
+      },
+    );
+  }
+}
+
+function validateRuntimeResourceArtifactContents(file, { target, extensionMetadata }) {
+  const entries = readArchiveEntries(file);
+  const names = new Set(entries.keys());
+  const runtimePrefix = 'oliphaunt/runtime/files/';
+  for (const requiredMember of [
+    'oliphaunt/runtime/manifest.properties',
+    'oliphaunt/static-registry/manifest.properties',
+  ]) {
+    if (!names.has(requiredMember)) {
+      fail(`${file} must contain ${requiredMember}`);
+    }
+  }
+  if (
+    !names.has(`${runtimePrefix}share/postgresql/README.release-fixture`) &&
+    ![...names].some((name) => name.startsWith(runtimePrefix))
+  ) {
+    fail(`${file} must contain an oliphaunt/runtime/files tree`);
+  }
+  if ([...names].some((name) => name.startsWith(`${runtimePrefix}share/icu/`))) {
+    fail(`${file} standard runtime must not contain ICU data under ${runtimePrefix}share/icu`);
+  }
+  for (const required of [
+    `${runtimePrefix}share/postgresql/extension/plpgsql--1.0.sql`,
+    `${runtimePrefix}share/postgresql/extension/plpgsql.control`,
+    `${runtimePrefix}share/postgresql/snowball_create.sql`,
+    ...SNOWBALL_STOPWORD_LANGUAGES.map(
+      (language) => `${runtimePrefix}share/postgresql/tsearch_data/${language}.stop`,
+    ),
+  ]) {
+    const entry = entries.get(required);
+    if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) {
+      fail(`${file} standard runtime is missing required core PostgreSQL resource ${required}`);
+    }
+  }
+  for (const [sqlName, metadata] of extensionMetadata) {
+    const control = `${runtimePrefix}share/postgresql/extension/${sqlName}.control`;
+    if (names.has(control)) {
+      fail(`${file} standard runtime must not contain optional extension control file ${control}`);
+    }
+    for (const dataFile of metadata.dataFiles) {
+      const dataPath = `${runtimePrefix}share/postgresql/${dataFile}`;
+      if (names.has(dataPath)) {
+        fail(`${file} standard runtime must not contain optional extension data file ${dataPath}`);
+      }
+    }
+    if (typeof metadata.nativeModuleStem === 'string' && metadata.nativeModuleStem) {
+      for (const suffix of ['.dylib', '.so', '.dll']) {
+        const module = `${runtimePrefix}lib/postgresql/${metadata.nativeModuleStem}${suffix}`;
+        if (names.has(module)) {
+          fail(`${file} standard runtime must not contain optional extension module ${module}`);
+        }
+      }
+    }
+  }
+
+  validateMobileAbiProofEntries(entries, file, target);
+  const runtime = parseProperties(
+    Buffer.from(archiveText(entries, file, 'oliphaunt/runtime/manifest.properties')),
+    `${file} runtime manifest`,
+  );
+  if (
+    runtime.get('schema') !== 'oliphaunt-runtime-resources-v1' ||
+    runtime.get('layout') !== 'postgres-runtime-files-v1' ||
+    runtime.get('artifactRole') !== 'runtime' ||
+    runtime.get('mode') !== 'native-direct' ||
+    runtime.get('clusterSeedTarget') !== target ||
+    runtime.get('mobileStaticRegistryState') !== 'not-required' ||
+    [
+      'selectedExtensions',
+      'extensions',
+      'runtimeFeatures',
+      'sharedPreloadLibraries',
+      'mobileStaticRegistryRegistered',
+      'mobileStaticRegistryPending',
+      'nativeModuleStems',
+      'mobileStaticRegistrySource',
+    ].some((key) => runtime.get(key))
+  ) {
+    fail(`${file} base runtime metadata is incompatible with ${target}`);
+  }
+  const registry = parseProperties(
+    Buffer.from(archiveText(entries, file, 'oliphaunt/static-registry/manifest.properties')),
+    `${file} static registry`,
+  );
+  if (
+    registry.get('state') !== 'not-required' ||
+    registry.get('registeredExtensions') ||
+    registry.get('pendingExtensions')
+  ) {
+    fail(`${file} base runtime must not contain a static extension registry`);
+  }
+}
+
+const RELEASE_NOTICE_OPTIONS_BY_KIND = new Map([
+  ['native-runtime', Object.freeze({ profile: 'native-runtime' })],
+  ['native-tools', Object.freeze({ profile: 'native-tools' })],
+  [
+    'apple-swiftpm-binary',
+    Object.freeze({
+      profile: 'native-runtime',
+      prefix: 'liboliphaunt.xcframework',
+    }),
+  ],
+  ['runtime-resources', Object.freeze({ profile: 'native-runtime-resources' })],
+]);
+
+export function assertLiboliphauntArtifactReleaseNotices(file, kind) {
+  const options = RELEASE_NOTICE_OPTIONS_BY_KIND.get(kind);
+  if (options === undefined) {
+    return false;
+  }
+  assertReleaseNoticesInArchive(file, options);
+  return true;
+}
+
+function validateReleaseNoticeClosure(assetDir, version) {
+  for (const target of allArtifactTargets({
+    product: PRODUCT,
+    surface: 'github-release',
+  })) {
+    assertLiboliphauntArtifactReleaseNotices(
+      path.join(assetDir, assetName(target, version)),
+      target.kind,
+    );
+  }
+}
+
+function expectedGithubAssets(version) {
+  return allArtifactTargets({
+    product: PRODUCT,
+    surface: 'github-release',
+  })
+    .map((target) => assetName(target, version))
+    .sort(compareText);
+}
+
+async function validate(assetDir) {
+  const version = await currentProductVersion(PRODUCT, PREFIX);
+  const metadata = generatedExtensionMetadata();
+  const required = expectedGithubAssets(version);
+  const expected = new Set(required);
+  const actual = new Set(
+    readdirSync(assetDir).filter((name) => statSync(path.join(assetDir, name)).isFile()),
+  );
+  const missing = [...expected].filter((name) => !actual.has(name)).sort(compareText);
+  if (missing.length > 0) {
+    fail(
+      `liboliphaunt-native release asset directory is missing expected assets: ${missing.join(', ')}`,
+    );
+  }
+  const unexpected = [...actual].filter((name) => !expected.has(name)).sort(compareText);
+  if (unexpected.length > 0) {
+    fail(
+      `liboliphaunt-native release asset directory contains unexpected assets: ${unexpected.join(', ')}`,
+    );
+  }
+  for (const filename of required) {
+    requireFile(path.join(assetDir, filename), `liboliphaunt release artifact ${filename}`);
+  }
+  validateReleaseNoticeClosure(assetDir, version);
+  const leakedExtensionAssets = [...actual]
+    .filter((name) => name.includes('extension') && !name.endsWith('-release-assets.sha256'))
+    .sort(compareText);
+  if (leakedExtensionAssets.length > 0) {
+    fail(
+      'liboliphaunt-native release assets must not include exact-extension artifacts; ' +
+        `publish them through oliphaunt-extension-* products instead: ${leakedExtensionAssets.join(', ')}`,
+    );
+  }
+  for (const target of ['ios-datum64', 'android-datum64']) {
+    validateRuntimeResourceArtifactContents(
+      path.join(assetDir, `liboliphaunt-${version}-runtime-resources-${target}.tar.gz`),
+      { target, extensionMetadata: metadata },
+    );
+  }
+  for (const filename of [
+    `liboliphaunt-${version}-ios-xcframework.tar.gz`,
+    `liboliphaunt-${version}-apple-spm-xcframework.zip`,
+  ]) {
+    const file = path.join(assetDir, filename);
+    const entries = readArchiveEntries(file);
+    for (const slice of ['ios-arm64', 'ios-arm64-simulator']) {
+      validateMobileAbiProofEntries(
+        entries,
+        file,
+        'ios-datum64',
+        `liboliphaunt.xcframework/${slice}/liboliphaunt.framework/Resources/oliphaunt/`,
+      );
+    }
+  }
+  await validateNativeTargetArtifacts(assetDir, version);
+  validateChecksums(assetDir, path.join(assetDir, `liboliphaunt-${version}-release-assets.sha256`));
+}
+
+function parseArgs(argv) {
+  const args = {
+    assetDir: path.join(ROOT, 'target/liboliphaunt/release-assets'),
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--asset-dir') {
+      const value = argv[index + 1];
+      if (!value) {
+        fail('--asset-dir requires a value');
+      }
+      args.assetDir = path.resolve(ROOT, value);
+      index += 1;
+    } else {
+      fail(`unknown argument ${arg}`);
+    }
+  }
+  return args;
+}
+
+export async function checkLiboliphauntReleaseAssets(argv = Bun.argv.slice(2)) {
+  const args = parseArgs(argv);
+  if (!existsSync(args.assetDir) || !statSync(args.assetDir).isDirectory()) {
+    fail(`release asset directory does not exist: ${args.assetDir}`);
+  }
+  await validate(args.assetDir);
+  console.log(`liboliphaunt release assets validated: ${rel(args.assetDir)}`);
+}
+
+if (import.meta.main) await checkLiboliphauntReleaseAssets();
diff --git a/src/runtimes/liboliphaunt-native/tools/check-release-assets.test.mts b/src/runtimes/liboliphaunt-native/tools/check-release-assets.test.mts
new file mode 100644
index 000000000..7f2e53cd9
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/check-release-assets.test.mts
@@ -0,0 +1,30 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts';
+import { archiveDirectory } from '../../../../tools/packaging/archive-directory.mts';
+import { assertLiboliphauntArtifactReleaseNotices } from './check-release-assets.mts';
+
+test('aggregate validation reads Apple notices from the canonical XCFramework member root', async (t) => {
+  const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-apple-notice-'));
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+  const framework = path.join(root, 'liboliphaunt.xcframework');
+  mkdirSync(framework);
+  writeFileSync(path.join(framework, 'Info.plist'), 'fixture\n');
+  stageReleaseNotices(framework, { profile: 'native-runtime' });
+  const archive = path.join(root, 'liboliphaunt-0.0.0-apple-spm-xcframework.zip');
+  await archiveDirectory(framework, archive, { keepParent: true });
+  assert.equal(assertLiboliphauntArtifactReleaseNotices(archive, 'apple-swiftpm-binary'), true);
+
+  rmSync(path.join(framework, 'LICENSE'));
+  const missingNoticeArchive = path.join(root, 'missing-notice.zip');
+  await archiveDirectory(framework, missingNoticeArchive, { keepParent: true });
+  assert.throws(
+    () => assertLiboliphauntArtifactReleaseNotices(missingNoticeArchive, 'apple-swiftpm-binary'),
+    /liboliphaunt[.]xcframework\/LICENSE/u,
+  );
+});
diff --git a/src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.mts b/src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.mts
new file mode 100644
index 000000000..0979bd182
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.mts
@@ -0,0 +1,170 @@
+#!/usr/bin/env bun
+
+import {
+  chmodSync,
+  cpSync,
+  lstatSync,
+  mkdirSync,
+  mkdtempSync,
+  readdirSync,
+  readFileSync,
+  renameSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import { archiveDirectory } from '../../../../tools/packaging/archive-directory.mts';
+
+import {
+  compareNativeMobileAbiReceipts,
+  NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN,
+  parseNativeMobileAbiReceipt,
+} from './native-mobile-abi-contract.mts';
+import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts';
+
+function fail(message) {
+  throw new Error(`finalize-native-mobile-abi-proofs.mts: ${message}`);
+}
+
+function receiptFiles(root) {
+  const files = [];
+  const visit = (directory) => {
+    for (const name of readdirSync(directory).sort()) {
+      const file = path.join(directory, name);
+      const metadata = lstatSync(file);
+      if (metadata.isDirectory()) visit(file);
+      else if (/^native-mobile-abi(?:-producer)?\.properties$/u.test(name)) {
+        if (!metadata.isFile()) fail(`receipt input is not a regular file: ${file}`);
+        files.push(file);
+      }
+    }
+  };
+  visit(root);
+  return files;
+}
+
+function loadDomainReceipts(domain, root) {
+  const required = NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[domain];
+  if (required === undefined) fail(`unsupported compatibility domain ${domain}`);
+  const byTarget = new Map();
+  for (const file of receiptFiles(root)) {
+    const text = readFileSync(file, 'utf8');
+    const target = parseNativeMobileAbiReceipt(text, file).get('target');
+    if (!required.includes(target)) continue;
+    const existing = byTarget.get(target);
+    if (existing !== undefined && existing.text !== text) {
+      fail(`${domain} has divergent duplicate receipts for ${target}: ${existing.file}, ${file}`);
+    }
+    if (existing === undefined) byTarget.set(target, { file, text });
+  }
+  const missing = required.filter((target) => !byTarget.has(target));
+  if (missing.length > 0) fail(`${domain} is missing receipts for ${missing.join(', ')}`);
+  const receipts = required.map((target) => ({
+    label: byTarget.get(target).file,
+    text: byTarget.get(target).text,
+  }));
+  compareNativeMobileAbiReceipts(domain, receipts);
+  return new Map(required.map((target) => [target, byTarget.get(target).text]));
+}
+
+function materializeArchive(archive, destination) {
+  for (const [rawName, entry] of readPortableArchiveEntries(archive)) {
+    const name = rawName.replace(/\/$/u, '');
+    if (name === '.' || name.length === 0) continue;
+    const output = path.join(destination, ...name.split('/'));
+    if (entry.isDirectory) {
+      mkdirSync(output, { recursive: true });
+      continue;
+    }
+    if (!entry.isFile || entry.isSymbolicLink) {
+      fail(`${archive} contains unsupported member ${rawName}`);
+    }
+    mkdirSync(path.dirname(output), { recursive: true });
+    writeFileSync(output, entry.data());
+    chmodSync(output, (entry.mode ?? 0o644) & 0o777);
+  }
+}
+
+async function finalizeArchive(archive, receipts) {
+  const work = mkdtempSync(path.join(tmpdir(), 'oliphaunt-mobile-abi-proof-'));
+  const staging = path.join(work, 'carrier');
+  const output = `${archive}.tmp-${process.pid}.tar.gz`;
+  try {
+    mkdirSync(staging);
+    materializeArchive(archive, staging);
+    const proof = path.join(staging, 'oliphaunt/provenance/native-mobile-abi');
+    rmSync(proof, { recursive: true, force: true });
+    mkdirSync(proof, { recursive: true });
+    for (const [target, text] of receipts) {
+      writeFileSync(path.join(proof, `${target}.properties`), text);
+    }
+    await archiveDirectory(staging, output);
+    renameSync(output, archive);
+  } finally {
+    rmSync(output, { force: true });
+    rmSync(work, { recursive: true, force: true });
+  }
+}
+
+export async function finalizeNativeMobileAbiProofs({
+  domain,
+  assetDir,
+  receiptRoot,
+  outputDir = assetDir,
+}) {
+  const receipts = loadDomainReceipts(domain, receiptRoot);
+  const suffix = `-runtime-resources-${domain}.tar.gz`;
+  const archives = readdirSync(assetDir)
+    .filter((name) => name.endsWith(suffix))
+    .map((name) => path.join(assetDir, name));
+  if (archives.length !== 1) {
+    fail(`${assetDir} must contain exactly one *${suffix}; found ${archives.length}`);
+  }
+  const sourceArchive = archives[0];
+  let outputArchive = sourceArchive;
+  if (path.resolve(outputDir) !== path.resolve(assetDir)) {
+    rmSync(outputDir, { recursive: true, force: true });
+    cpSync(assetDir, outputDir, { recursive: true });
+    outputArchive = path.join(outputDir, path.basename(sourceArchive));
+  }
+  await finalizeArchive(outputArchive, receipts);
+  return { archive: outputArchive, targets: [...receipts.keys()] };
+}
+
+function parseArgs(argv) {
+  const values = new Map();
+  for (let index = 0; index < argv.length; index += 2) {
+    const key = argv[index];
+    const value = argv[index + 1];
+    if (!key?.startsWith('--') || value === undefined || values.has(key)) {
+      fail('usage: --domain DOMAIN --asset-dir DIR --receipt-root DIR [--output-dir DIR]');
+    }
+    values.set(key, value);
+  }
+  if (
+    (values.size !== 3 && values.size !== 4) ||
+    !values.has('--domain') ||
+    !values.has('--asset-dir') ||
+    !values.has('--receipt-root')
+  ) {
+    fail('usage: --domain DOMAIN --asset-dir DIR --receipt-root DIR');
+  }
+  return {
+    domain: values.get('--domain'),
+    assetDir: path.resolve(values.get('--asset-dir')),
+    receiptRoot: path.resolve(values.get('--receipt-root')),
+    outputDir: values.has('--output-dir') ? path.resolve(values.get('--output-dir')) : undefined,
+  };
+}
+
+if (import.meta.main) {
+  try {
+    const result = await finalizeNativeMobileAbiProofs(parseArgs(process.argv.slice(2)));
+    console.log(`nativeMobileAbiProofArchive=${result.archive}`);
+    console.log(`nativeMobileAbiProofTargets=${result.targets.join(',')}`);
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(2);
+  }
+}
diff --git a/src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.test.mts b/src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.test.mts
new file mode 100644
index 000000000..494a09e6c
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/finalize-native-mobile-abi-proofs.test.mts
@@ -0,0 +1,148 @@
+import { expect, test } from 'bun:test';
+import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+
+import { writeEntriesArchive } from '../../../../tools/packaging/testdata/release-fixture-utils.mts';
+import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts';
+import { finalizeNativeMobileAbiProofs } from './finalize-native-mobile-abi-proofs.mts';
+
+function receipt(target, blockSize = 8192) {
+  return [
+    'schema=oliphaunt-native-mobile-abi-v1',
+    `target=${target}`,
+    'byteOrder=little',
+    'datumBytes=8',
+    'maximumAlignof=8',
+    'float8ByVal=1',
+    `blockSize=${blockSize}`,
+    'walBlockSize=8192',
+    'relationSegmentSize=131072',
+    'nameDataLength=64',
+    'indexMaxKeys=32',
+    'catalogVersion=202506291',
+    'pgControlVersion=1800',
+    '',
+  ].join('\n');
+}
+
+function writeReceipt(root, directory, name, text) {
+  const target = path.join(root, directory);
+  mkdirSync(target, { recursive: true });
+  writeFileSync(path.join(target, name), text);
+}
+
+async function fixture() {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-mobile-proof-test-'));
+  const assetDir = path.join(root, 'assets');
+  const receiptRoot = path.join(root, 'receipts');
+  mkdirSync(assetDir);
+  mkdirSync(receiptRoot);
+  const archive = path.join(
+    assetDir,
+    'liboliphaunt-1.2.3-runtime-resources-android-datum64.tar.gz',
+  );
+  await writeEntriesArchive(archive, { 'oliphaunt/runtime/files/value': 'value\n' });
+  writeReceipt(receiptRoot, 'arm', 'native-mobile-abi.properties', receipt('android-arm64-v8a'));
+  writeReceipt(receiptRoot, 'x86', 'native-mobile-abi.properties', receipt('android-x86_64'));
+  const producer = receipt('linux-x64-gnu');
+  writeReceipt(receiptRoot, 'arm', 'native-mobile-abi-producer.properties', producer);
+  writeReceipt(receiptRoot, 'x86', 'native-mobile-abi-producer.properties', producer);
+  return { root, assetDir, receiptRoot, archive };
+}
+
+test('finalizes one domain with exact deterministic proof members', async () => {
+  const current = await fixture();
+  try {
+    symlinkSync('libecpg.so.6', path.join(current.receiptRoot, 'arm/libecpg.so'));
+    symlinkSync(current.receiptRoot, path.join(current.receiptRoot, 'cycle'));
+    await finalizeNativeMobileAbiProofs({
+      domain: 'android-datum64',
+      assetDir: current.assetDir,
+      receiptRoot: current.receiptRoot,
+    });
+    const first = readFileSync(current.archive);
+    const proofPrefix = 'oliphaunt/provenance/native-mobile-abi/';
+    const proofMembers = [...readPortableArchiveEntries(current.archive).keys()]
+      .filter((name) => name.startsWith(proofPrefix) && name.endsWith('.properties'))
+      .sort();
+    expect(proofMembers).toEqual([
+      `${proofPrefix}android-arm64-v8a.properties`,
+      `${proofPrefix}android-x86_64.properties`,
+      `${proofPrefix}linux-x64-gnu.properties`,
+    ]);
+
+    await finalizeNativeMobileAbiProofs({
+      domain: 'android-datum64',
+      assetDir: current.assetDir,
+      receiptRoot: current.receiptRoot,
+    });
+    expect(readFileSync(current.archive)).toEqual(first);
+  } finally {
+    rmSync(current.root, { recursive: true, force: true });
+  }
+});
+
+test('rejects symbolic links used as ABI receipts', async () => {
+  const current = await fixture();
+  try {
+    const file = path.join(current.receiptRoot, 'arm/native-mobile-abi.properties');
+    writeFileSync(path.join(current.root, 'linked-receipt'), readFileSync(file));
+    rmSync(file);
+    symlinkSync(path.join(current.root, 'linked-receipt'), file);
+    await expect(
+      finalizeNativeMobileAbiProofs({
+        domain: 'android-datum64',
+        assetDir: current.assetDir,
+        receiptRoot: current.receiptRoot,
+      }),
+    ).rejects.toThrow(/receipt input is not a regular file/u);
+  } finally {
+    rmSync(current.root, { recursive: true, force: true });
+  }
+});
+
+test('rejects divergent duplicate producer receipts', async () => {
+  const current = await fixture();
+  try {
+    writeReceipt(
+      current.receiptRoot,
+      'x86',
+      'native-mobile-abi-producer.properties',
+      receipt('linux-x64-gnu', 4096),
+    );
+    await expect(
+      finalizeNativeMobileAbiProofs({
+        domain: 'android-datum64',
+        assetDir: current.assetDir,
+        receiptRoot: current.receiptRoot,
+      }),
+    ).rejects.toThrow(/divergent duplicate receipts/u);
+  } finally {
+    rmSync(current.root, { recursive: true, force: true });
+  }
+});
+
+test('can finalize an immutable input archive into a separately owned output', async () => {
+  const current = await fixture();
+  try {
+    const baseArchive = path.join(current.assetDir, 'liboliphaunt-1.2.3-android-x86_64.tar.gz');
+    writeFileSync(baseArchive, 'base carrier');
+    const before = readFileSync(current.archive);
+    const outputDir = path.join(current.root, 'final');
+    const result = await finalizeNativeMobileAbiProofs({
+      domain: 'android-datum64',
+      assetDir: current.assetDir,
+      receiptRoot: current.receiptRoot,
+      outputDir,
+    });
+    expect(readFileSync(current.archive)).toEqual(before);
+    expect(result.archive).toBe(path.join(outputDir, path.basename(current.archive)));
+    expect(readFileSync(result.archive)).not.toEqual(before);
+    expect(readFileSync(path.join(outputDir, path.basename(baseArchive)), 'utf8')).toBe(
+      'base carrier',
+    );
+  } finally {
+    rmSync(current.root, { recursive: true, force: true });
+  }
+});
diff --git a/src/runtimes/liboliphaunt-native/tools/finalize-native-runtime-carrier.mts b/src/runtimes/liboliphaunt-native/tools/finalize-native-runtime-carrier.mts
new file mode 100644
index 000000000..a350b410a
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/finalize-native-runtime-carrier.mts
@@ -0,0 +1,94 @@
+#!/usr/bin/env bun
+
+import { existsSync, lstatSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+import {
+  bindNativeRuntimeResourceManifest,
+  validateNativeRuntimeCarrier,
+} from './native-runtime-carrier-contract.mts';
+
+function fail(message) {
+  throw new Error(`finalize-native-runtime-carrier.mts: ${message}`);
+}
+
+function treeBytes(root) {
+  if (!existsSync(root)) return 0;
+  const metadata = lstatSync(root);
+  if (metadata.isSymbolicLink()) fail(`carrier tree must not contain symlinks: ${root}`);
+  if (metadata.isFile()) return metadata.size;
+  if (!metadata.isDirectory()) fail(`carrier tree contains a special file: ${root}`);
+  return readdirSync(root).reduce((total, name) => total + treeBytes(path.join(root, name)), 0);
+}
+
+function rewritePackageSizeReport(root) {
+  const report = path.join(root, 'package-size.tsv');
+  const rows = readFileSync(report, 'utf8').split(/\r?\n/u).filter(Boolean);
+  if (rows.shift() !== 'kind\tid\textensions\tfiles\tbytes') {
+    fail(`${report} has an unsupported header`);
+  }
+  const retained = rows.filter((row) => !row.startsWith('package\t'));
+  const runtime = treeBytes(path.join(root, 'runtime/files'));
+  const staticRegistry = treeBytes(path.join(root, 'static-registry'));
+  const total = runtime + staticRegistry;
+  writeFileSync(
+    report,
+    [
+      'kind\tid\textensions\tfiles\tbytes',
+      `package\ttotal\t-\t-\t${total}`,
+      `package\truntime\t-\t-\t${runtime}`,
+      `package\tstatic-registry\t-\t-\t${staticRegistry}`,
+      ...retained,
+      '',
+    ].join('\n'),
+  );
+}
+
+export function finalizeNativeRuntimeCarrier(root, target) {
+  const runtimeManifest = path.join(root, 'runtime/manifest.properties');
+  if (existsSync(runtimeManifest)) {
+    writeFileSync(
+      runtimeManifest,
+      bindNativeRuntimeResourceManifest(readFileSync(runtimeManifest), target),
+    );
+  } else {
+    fail(`${runtimeManifest} is missing`);
+  }
+  if (existsSync(path.join(root, 'package-size.tsv'))) rewritePackageSizeReport(root);
+  return validateNativeRuntimeCarrier(root, { target });
+}
+
+function parseArgs(argv) {
+  const values = new Map();
+  for (let index = 0; index < argv.length; index += 2) {
+    const key = argv[index];
+    const value = argv[index + 1];
+    if (!key?.startsWith('--') || value === undefined || values.has(key)) {
+      fail('usage: --root DIR --target TARGET');
+    }
+    values.set(key, value);
+  }
+  const allowed = new Set(['--root', '--target']);
+  if (
+    [...values.keys()].some((key) => !allowed.has(key)) ||
+    !values.has('--root') ||
+    !values.has('--target')
+  ) {
+    fail('usage: --root DIR --target TARGET');
+  }
+  return {
+    root: path.resolve(values.get('--root')),
+    target: values.get('--target'),
+  };
+}
+
+if (import.meta.main) {
+  try {
+    const args = parseArgs(process.argv.slice(2));
+    const result = finalizeNativeRuntimeCarrier(args.root, args.target);
+    console.log(`clusterSeedTarget=${result.target}`);
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(2);
+  }
+}
diff --git a/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.fixture.mts b/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.fixture.mts
new file mode 100644
index 000000000..b8f1edc8e
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.fixture.mts
@@ -0,0 +1,17 @@
+import { chmodSync, mkdirSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { requiredCoreRuntimePaths, requiredRuntimeTools } from './native-runtime-payload.mts';
+
+const runtime = path.join(process.argv[2], 'runtime');
+const target = 'linux-x64-gnu';
+for (const tool of requiredRuntimeTools(target)) {
+  const file = path.join(runtime, 'bin', tool);
+  mkdirSync(path.dirname(file), { recursive: true });
+  writeFileSync(file, '#!/bin/sh\nexit 0\n');
+  chmodSync(file, 0o755);
+}
+for (const relativePath of requiredCoreRuntimePaths(target, runtime)) {
+  const file = path.join(runtime, relativePath);
+  mkdirSync(path.dirname(file), { recursive: true });
+  writeFileSync(file, `${relativePath}\n`);
+}
diff --git a/tools/release/liboliphaunt-extension-guard.sh b/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
similarity index 86%
rename from tools/release/liboliphaunt-extension-guard.sh
rename to src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
index 43c72e6a8..453a31c52 100644
--- a/tools/release/liboliphaunt-extension-guard.sh
+++ b/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
@@ -6,9 +6,9 @@ oliphaunt_assert_base_runtime_has_no_optional_extensions() {
   local extension_dir="$runtime/share/postgresql/extension"
   local module_dir="$runtime/lib/postgresql"
   local failures=()
-  local sql_name pg_major creates_extension stem dependencies shared_preload desktop_prebuilt mobile_prebuilt mobile_static_required mobile_static_targets data_files artifact_policy
+  local sql_name stem data_files
 
-  while IFS=$'\t' read -r sql_name pg_major creates_extension stem dependencies shared_preload desktop_prebuilt mobile_prebuilt mobile_static_required mobile_static_targets data_files artifact_policy; do
+  while IFS=$'\t' read -r sql_name stem data_files; do
     [ -n "$sql_name" ] || continue
     if [ -f "$extension_dir/$sql_name.control" ]; then
       failures+=("control:$sql_name")
diff --git a/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.test.sh b/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.test.sh
new file mode 100644
index 000000000..37ef5d8a3
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.test.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "$0")/../../../.."
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+guard() (
+  source src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
+  oliphaunt_assert_base_embedded_modules_exact "$scratch/modules" so
+)
+reject() {
+  if guard > "$scratch/rejected.log" 2>&1; then
+    echo 'Invalid embedded module inventory was accepted' >&2; exit 1
+  fi
+}
+reject
+mkdir "$scratch/modules"
+printf snowball > "$scratch/modules/dict_snowball.so"
+reject
+printf plpgsql > "$scratch/modules/plpgsql.so"
+guard
+printf stale > "$scratch/modules/.stale-extension.so"
+reject
+rm "$scratch/modules/.stale-extension.so"
+printf linked > "$scratch/outside.so"
+for module in plpgsql dict_snowball; do
+  rm "$scratch/modules/$module.so"
+  ln -s "$scratch/outside.so" "$scratch/modules/$module.so"
+  reject
+  rm "$scratch/modules/$module.so"
+  printf regular > "$scratch/modules/$module.so"
+done
+
+bun src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.fixture.mts "$scratch/payload"
+bun src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts "$scratch/payload" --target linux-x64-gnu --tool-set runtime
+rm "$scratch/payload/runtime/share/postgresql/tsearch_data/english.stop"
+if bun src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts "$scratch/payload" \
+  --target linux-x64-gnu --tool-set runtime --check > "$scratch/payload.log" 2>&1; then
+  echo 'Incomplete Snowball runtime data was accepted' >&2; exit 1
+fi
+grep -Eq 'missing required core runtime file .*english[.]stop' "$scratch/payload.log"
+echo 'Embedded module inventory and Snowball resource validation passed'
diff --git a/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts b/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
new file mode 100644
index 000000000..60ec4c163
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts
@@ -0,0 +1,215 @@
+#!/usr/bin/env bun
+
+import { readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+const SCHEMA = 'oliphaunt-native-mobile-abi-v1';
+export const NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN = Object.freeze({
+  'android-datum64': Object.freeze(['android-arm64-v8a', 'android-x86_64', 'linux-x64-gnu']),
+  'ios-datum64': Object.freeze(['ios-arm64', 'ios-arm64-simulator', 'macos-arm64']),
+});
+export const NATIVE_MOBILE_ABI_RECEIPT_KEYS = Object.freeze([
+  'schema',
+  'target',
+  'byteOrder',
+  'datumBytes',
+  'maximumAlignof',
+  'float8ByVal',
+  'blockSize',
+  'walBlockSize',
+  'relationSegmentSize',
+  'nameDataLength',
+  'indexMaxKeys',
+  'catalogVersion',
+  'pgControlVersion',
+]);
+
+function fail(message) {
+  throw new Error(`native-mobile-abi-contract.mts: ${message}`);
+}
+
+function parseProperties(text, label) {
+  const values = new Map();
+  for (const [index, line] of text.split(/\r?\n/u).entries()) {
+    if (line.length === 0) continue;
+    const separator = line.indexOf('=');
+    if (separator <= 0) fail(`${label}:${index + 1} is not key=value`);
+    const key = line.slice(0, separator);
+    if (values.has(key)) fail(`${label}:${index + 1} repeats ${key}`);
+    values.set(key, line.slice(separator + 1));
+  }
+  return values;
+}
+
+function defineValue(text, name, label) {
+  const match = text.match(new RegExp(`^\\s*#define\\s+${name}\\s+([^\\s/]+)`, 'mu'));
+  if (match === null) fail(`${label} does not define ${name}`);
+  return match[1].replace(/^\((.*)\)$/u, '$1');
+}
+
+function integerDefine(text, name, label) {
+  const raw = defineValue(text, name, label).replace(/[uUlL]+$/u, '');
+  if (!/^(?:0[xX][0-9a-fA-F]+|[0-9]+)$/u.test(raw)) {
+    fail(`${label} has invalid ${name}=${raw}`);
+  }
+  const value = Number.parseInt(raw, /^0[xX]/u.test(raw) ? 16 : 10);
+  if (!Number.isSafeInteger(value) || value <= 0) fail(`${label} has invalid ${name}=${raw}`);
+  return String(value);
+}
+
+function header(buildRoot, relative) {
+  const file = path.join(buildRoot, ...relative.split('/'));
+  try {
+    return { file, text: readFileSync(file, 'utf8') };
+  } catch (error) {
+    fail(`cannot read ${file}: ${error instanceof Error ? error.message : String(error)}`);
+  }
+}
+
+export function nativeMobileAbiReceipt(buildRoot, target) {
+  const pgConfig = header(buildRoot, 'src/include/pg_config.h');
+  const pgConfigManual = header(buildRoot, 'src/include/pg_config_manual.h');
+  const catversion = header(buildRoot, 'src/include/catalog/catversion.h');
+  const pgControl = header(buildRoot, 'src/include/catalog/pg_control.h');
+  const datumBytes = integerDefine(pgConfig.text, 'SIZEOF_VOID_P', pgConfig.file);
+  if (datumBytes !== '8') fail(`${target} is not a Datum64 target`);
+  const maximumAlignof = integerDefine(pgConfig.text, 'MAXIMUM_ALIGNOF', pgConfig.file);
+  const byteOrder = /^\s*#define\s+WORDS_BIGENDIAN\s+1\b/mu.test(pgConfig.text) ? 'big' : 'little';
+  const float8ByVal = /^\s*#define\s+USE_FLOAT8_BYVAL(?:\s+1)?\s*$/mu.test(pgConfigManual.text)
+    ? '1'
+    : '0';
+  const values = new Map([
+    ['schema', SCHEMA],
+    ['target', target],
+    ['byteOrder', byteOrder],
+    ['datumBytes', datumBytes],
+    ['maximumAlignof', maximumAlignof],
+    ['float8ByVal', float8ByVal],
+    ['blockSize', integerDefine(pgConfig.text, 'BLCKSZ', pgConfig.file)],
+    ['walBlockSize', integerDefine(pgConfig.text, 'XLOG_BLCKSZ', pgConfig.file)],
+    ['relationSegmentSize', integerDefine(pgConfig.text, 'RELSEG_SIZE', pgConfig.file)],
+    ['nameDataLength', integerDefine(pgConfigManual.text, 'NAMEDATALEN', pgConfigManual.file)],
+    ['indexMaxKeys', integerDefine(pgConfigManual.text, 'INDEX_MAX_KEYS', pgConfigManual.file)],
+    ['catalogVersion', integerDefine(catversion.text, 'CATALOG_VERSION_NO', catversion.file)],
+    ['pgControlVersion', integerDefine(pgControl.text, 'PG_CONTROL_VERSION', pgControl.file)],
+  ]);
+  return `${NATIVE_MOBILE_ABI_RECEIPT_KEYS.map((key) => `${key}=${values.get(key)}`).join('\n')}\n`;
+}
+
+export function parseNativeMobileAbiReceipt(text, label = 'native mobile ABI receipt') {
+  const values = parseProperties(text, label);
+  if (
+    values.size !== NATIVE_MOBILE_ABI_RECEIPT_KEYS.length ||
+    NATIVE_MOBILE_ABI_RECEIPT_KEYS.some((key) => !values.has(key))
+  ) {
+    fail(`${label} fields must be exactly ${NATIVE_MOBILE_ABI_RECEIPT_KEYS.join(',')}`);
+  }
+  if (values.get('schema') !== SCHEMA) fail(`${label} has unsupported schema`);
+  if (!/^[a-z0-9][a-z0-9_-]*$/u.test(values.get('target'))) {
+    fail(`${label} has invalid target`);
+  }
+  if (!new Set(['little', 'big']).has(values.get('byteOrder'))) {
+    fail(`${label} has invalid byteOrder`);
+  }
+  for (const key of [
+    'datumBytes',
+    'maximumAlignof',
+    'blockSize',
+    'walBlockSize',
+    'relationSegmentSize',
+    'nameDataLength',
+    'indexMaxKeys',
+    'catalogVersion',
+    'pgControlVersion',
+  ]) {
+    if (!/^[1-9][0-9]*$/u.test(values.get(key))) fail(`${label} has invalid ${key}`);
+  }
+  if (!new Set(['0', '1']).has(values.get('float8ByVal'))) {
+    fail(`${label} has invalid float8ByVal`);
+  }
+  if (values.get('datumBytes') !== '8') fail(`${label} is not a Datum64 receipt`);
+  return values;
+}
+
+export function compareNativeMobileAbiReceipts(domain, receipts) {
+  const expectedTargets = NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[domain];
+  if (expectedTargets === undefined) fail(`unsupported compatibility domain ${domain}`);
+  if (receipts.length !== expectedTargets.length) {
+    fail(`${domain} requires receipts for ${expectedTargets.join(', ')}`);
+  }
+  const rows = receipts.map(({ text, label }) => ({
+    values: parseNativeMobileAbiReceipt(text, label),
+    label,
+  }));
+  const actualTargets = rows.map(({ values }) => values.get('target')).sort();
+  if (JSON.stringify(actualTargets) !== JSON.stringify([...expectedTargets].sort())) {
+    fail(`${domain} receipts must target exactly ${expectedTargets.join(', ')}`);
+  }
+  const baseline = rows[0];
+  for (const row of rows.slice(1)) {
+    for (const key of NATIVE_MOBILE_ABI_RECEIPT_KEYS) {
+      if (key === 'target') continue;
+      if (row.values.get(key) !== baseline.values.get(key)) {
+        fail(
+          `${domain} ABI mismatch for ${key}: ${baseline.label}=${baseline.values.get(key)}, ${row.label}=${row.values.get(key)}`,
+        );
+      }
+    }
+  }
+  return Object.freeze({ domain, targets: Object.freeze([...expectedTargets]) });
+}
+
+function parseArgs(argv) {
+  const command = argv[0];
+  if (
+    command === 'write' &&
+    argv.length === 7 &&
+    argv[1] === '--build-root' &&
+    argv[3] === '--target' &&
+    argv[5] === '--output'
+  ) {
+    return {
+      command,
+      buildRoot: path.resolve(argv[2]),
+      target: argv[4],
+      output: path.resolve(argv[6]),
+    };
+  }
+  if (
+    command === 'compare' &&
+    argv.length >= 6 &&
+    argv[1] === '--domain' &&
+    argv[3] === '--receipt'
+  ) {
+    const receiptFiles = [];
+    for (let index = 3; index < argv.length; index += 2) {
+      if (argv[index] !== '--receipt' || argv[index + 1] === undefined)
+        fail('compare accepts repeated --receipt FILE');
+      receiptFiles.push(path.resolve(argv[index + 1]));
+    }
+    return { command, domain: argv[2], receiptFiles };
+  }
+  fail(
+    'usage: write --build-root DIR --target TARGET --output FILE | compare --domain DOMAIN --receipt FILE --receipt FILE',
+  );
+}
+
+if (import.meta.main) {
+  try {
+    const args = parseArgs(process.argv.slice(2));
+    if (args.command === 'write') {
+      writeFileSync(args.output, nativeMobileAbiReceipt(args.buildRoot, args.target));
+      console.log(`nativeMobileAbiReceipt=${args.output}`);
+    } else {
+      const receipts = args.receiptFiles.map((file) => ({
+        text: readFileSync(file, 'utf8'),
+        label: file,
+      }));
+      const result = compareNativeMobileAbiReceipts(args.domain, receipts);
+      console.log(`nativeMobileAbiDomain=${result.domain}`);
+    }
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(2);
+  }
+}
diff --git a/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.test.mts b/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.test.mts
new file mode 100644
index 000000000..690e1b195
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.test.mts
@@ -0,0 +1,94 @@
+import { expect, test } from 'bun:test';
+import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+
+import {
+  compareNativeMobileAbiReceipts,
+  nativeMobileAbiReceipt,
+  parseNativeMobileAbiReceipt,
+} from './native-mobile-abi-contract.mts';
+
+function fixture(target, overrides = {}) {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-mobile-abi-'));
+  const include = path.join(root, 'src/include');
+  mkdirSync(path.join(include, 'catalog'), { recursive: true });
+  writeFileSync(
+    path.join(include, 'pg_config.h'),
+    [
+      `#define SIZEOF_VOID_P ${overrides.pointerBytes ?? 8}`,
+      `#define MAXIMUM_ALIGNOF ${overrides.alignment ?? 8}`,
+      '#define BLCKSZ 8192',
+      '#define XLOG_BLCKSZ 8192',
+      '#define RELSEG_SIZE 131072',
+      overrides.bigEndian ? '#define WORDS_BIGENDIAN 1' : '/* #undef WORDS_BIGENDIAN */',
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(
+    path.join(include, 'pg_config_manual.h'),
+    [
+      '#define USE_FLOAT8_BYVAL 1',
+      `#define NAMEDATALEN ${overrides.nameDataLength ?? 64}`,
+      '#define INDEX_MAX_KEYS 32',
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(
+    path.join(include, 'catalog/catversion.h'),
+    '#define CATALOG_VERSION_NO 202506291\n',
+  );
+  writeFileSync(path.join(include, 'catalog/pg_control.h'), '#define PG_CONTROL_VERSION 1800\n');
+  return { text: nativeMobileAbiReceipt(root, target), label: target };
+}
+
+test('qualifies matching Android Datum64 ABI receipts', () => {
+  expect(
+    compareNativeMobileAbiReceipts('android-datum64', [
+      fixture('android-arm64-v8a'),
+      fixture('android-x86_64'),
+      fixture('linux-x64-gnu'),
+    ]).domain,
+  ).toBe('android-datum64');
+});
+
+test('rejects ABI differences and incorrect domain membership', () => {
+  expect(() =>
+    compareNativeMobileAbiReceipts('ios-datum64', [
+      fixture('ios-arm64'),
+      fixture('ios-arm64-simulator', { alignment: 16 }),
+      fixture('macos-arm64'),
+    ]),
+  ).toThrow(/ABI mismatch for maximumAlignof/u);
+  expect(() =>
+    compareNativeMobileAbiReceipts('android-datum64', [
+      fixture('android-arm64-v8a'),
+      fixture('ios-arm64'),
+      fixture('linux-x64-gnu'),
+    ]),
+  ).toThrow(/target exactly/u);
+  expect(() =>
+    compareNativeMobileAbiReceipts('android-datum64', [
+      fixture('android-arm64-v8a'),
+      fixture('android-x86_64', { nameDataLength: 128 }),
+      fixture('linux-x64-gnu'),
+    ]),
+  ).toThrow(/ABI mismatch for nameDataLength/u);
+});
+
+test('rejects non-Datum64 producer headers', () => {
+  expect(() => fixture('android-x86_64', { pointerBytes: 4 })).toThrow(/not a Datum64/u);
+  expect(() => fixture('android-x86_64', { pointerBytes: '8garbage' })).toThrow(
+    /invalid SIZEOF_VOID_P/u,
+  );
+});
+
+test('rejects malformed or internally inconsistent receipts', () => {
+  const valid = fixture('android-x86_64').text;
+  expect(() =>
+    parseNativeMobileAbiReceipt(valid.replace('byteOrder=little', 'byteOrder=sideways')),
+  ).toThrow(/invalid byteOrder/u);
+  expect(() => parseNativeMobileAbiReceipt(valid.replace('datumBytes=8', 'datumBytes=4'))).toThrow(
+    /not a Datum64 receipt/u,
+  );
+});
diff --git a/src/runtimes/liboliphaunt-native/tools/native-readiness-probes.test.sh b/src/runtimes/liboliphaunt-native/tools/native-readiness-probes.test.sh
new file mode 100644
index 000000000..a77a6f823
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/native-readiness-probes.test.sh
@@ -0,0 +1,66 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+. "$root/src/runtimes/liboliphaunt-native/bin/common.sh"
+. "$root/src/runtimes/liboliphaunt-native/bin/mobile-static-extensions.sh"
+
+
+required_symbols='oliphaunt_builtin_dict_snowball_Pg_magic_func
+dsnowball_init
+pg_finfo_dsnowball_init
+dsnowball_lexize
+pg_finfo_dsnowball_lexize'
+
+for symbol_prefix in '' '_'; do
+  symbols="$({
+    while IFS= read -r symbol; do
+      printf '0000000000000000 T %s%s\n' "$symbol_prefix" "$symbol"
+    done <&2
+    exit 1
+  fi
+done <&2
+  exit 1
+fi
+device_metadata='      platform IOS'
+simulator_metadata='      platform IOSSIMULATOR'
+ios_device_pattern='(^|[[:space:]])platform[[:space:]]+IOS([[:space:]]|$)'
+ios_simulator_pattern='(^|[[:space:]])platform[[:space:]]+IOSSIMULATOR([[:space:]]|$)'
+oliphaunt_text_matches_ere "$device_metadata" "$ios_device_pattern"
+oliphaunt_text_matches_ere "$simulator_metadata" "$ios_simulator_pattern"
+if oliphaunt_text_matches_ere "$simulator_metadata" "$ios_device_pattern"; then
+  echo "iOS device probe accepted an iOS simulator slice" >&2
+  exit 1
+fi
+
+log="$(mktemp)"
+trap 'rm -f "$log"' EXIT
+awk 'BEGIN { for (i = 1; i <= 100; i++) { printf "%03d ", i; for (j = 0; j < 5000; j++) printf "x"; printf "\n" } }' > "$log"
+excerpt="$(oliphaunt_tail_log_excerpt "$log" 10 200)"
+[ "$(printf '%s\n' "$excerpt" | awk 'END { print NR }')" -eq 10 ]
+printf '%s\n' "$excerpt" | awk 'length($0) > 221 { exit 1 }'
+
+printf "native symbol, target, and bounded-log probes passed\n"
diff --git a/src/runtimes/liboliphaunt-native/tools/native-runtime-carrier-contract.mts b/src/runtimes/liboliphaunt-native/tools/native-runtime-carrier-contract.mts
new file mode 100644
index 000000000..810e4c501
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/native-runtime-carrier-contract.mts
@@ -0,0 +1,123 @@
+#!/usr/bin/env bun
+
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+
+import {
+  parseProperties,
+  validNativeCacheKey,
+} from '../../../database-resources/contracts/native-manifest.mts';
+
+export const NATIVE_RUNTIME_RESOURCE_MANIFEST_KEYS = Object.freeze([
+  'schema',
+  'layout',
+  'artifactRole',
+  'catalogProfile',
+  'clusterSeedTarget',
+  'icuDataTreeSha256',
+  'mode',
+  'cacheKey',
+  'selectedExtensions',
+  'extensions',
+  'runtimeFeatures',
+  'sharedPreloadLibraries',
+  'mobileStaticRegistryState',
+  'mobileStaticRegistryRegistered',
+  'mobileStaticRegistryPending',
+  'nativeModuleStems',
+  'mobileStaticRegistrySource',
+]);
+
+function requireTarget(target) {
+  if (!['android-datum64', 'ios-datum64', 'macos-arm64'].includes(target)) {
+    throw new Error(`unsupported native cluster-seed target ${JSON.stringify(target)}`);
+  }
+  return target;
+}
+
+export function bindNativeRuntimeResourceManifest(bytes, target) {
+  requireTarget(target);
+  const fields = parseProperties(bytes, 'native runtime resource manifest');
+  const expectedKeys = new Set(NATIVE_RUNTIME_RESOURCE_MANIFEST_KEYS);
+  if (
+    fields.size !== expectedKeys.size ||
+    [...fields.keys()].some((key) => !expectedKeys.has(key))
+  ) {
+    throw new Error('native runtime resource manifest must contain its exact canonical field set');
+  }
+  if (
+    fields.get('schema') !== 'oliphaunt-runtime-resources-v1' ||
+    fields.get('layout') !== 'postgres-runtime-files-v1' ||
+    fields.get('artifactRole') !== 'runtime' ||
+    fields.get('catalogProfile') !== '' ||
+    !['', target].includes(fields.get('clusterSeedTarget')) ||
+    fields.get('mode') !== 'native-direct' ||
+    !validNativeCacheKey(fields.get('cacheKey') ?? '')
+  ) {
+    throw new Error('native runtime resource manifest has an incompatible native-direct contract');
+  }
+  const registryState = fields.get('mobileStaticRegistryState');
+  const expectedSource =
+    registryState === 'complete' ? 'static-registry/oliphaunt_static_registry.c' : '';
+  if (fields.get('mobileStaticRegistrySource') !== expectedSource) {
+    throw new Error('native runtime resource manifest has inconsistent mobileStaticRegistrySource');
+  }
+  fields.set('clusterSeedTarget', target);
+  return Buffer.from(
+    `${NATIVE_RUNTIME_RESOURCE_MANIFEST_KEYS.map((key) => `${key}=${fields.get(key)}`).join('\n')}\n`,
+  );
+}
+
+export function validateNativeRuntimeCarrier(root, { target }) {
+  const runtimeManifestPath = path.join(root, 'runtime/manifest.properties');
+  const runtimeManifest = readFileSync(runtimeManifestPath);
+  const canonicalRuntimeManifest = bindNativeRuntimeResourceManifest(runtimeManifest, target);
+  if (!runtimeManifest.equals(canonicalRuntimeManifest)) {
+    throw new Error(
+      `${runtimeManifestPath}: runtime resource manifest is not canonical for ${target}`,
+    );
+  }
+  return Object.freeze({ target });
+}
+
+function parseArgs(argv) {
+  const values = new Map();
+  for (let index = 0; index < argv.length; index += 2) {
+    const key = argv[index];
+    const value = argv[index + 1];
+    if (
+      !key?.startsWith('--') ||
+      value === undefined ||
+      value.startsWith('--') ||
+      values.has(key)
+    ) {
+      throw new Error(
+        'usage: native-runtime-carrier-contract.mts check --root DIR --target TARGET',
+      );
+    }
+    values.set(key, value);
+  }
+  const root = values.get('--root');
+  const target = values.get('--target');
+  if (!root || !target || values.size !== 2) {
+    throw new Error('usage: native-runtime-carrier-contract.mts check --root DIR --target TARGET');
+  }
+  return { root: path.resolve(root), target };
+}
+
+if (import.meta.main) {
+  try {
+    const check = process.argv[2] === 'check';
+    const args = parseArgs(process.argv.slice(check ? 3 : 2));
+    const result = validateNativeRuntimeCarrier(args.root, { target: args.target });
+    if (result.target !== args.target) {
+      throw new Error(`expected ${args.target}, got ${result.target}`);
+    }
+    console.log(`clusterSeedTarget=${result.target}`);
+  } catch (error) {
+    console.error(
+      `native-runtime-carrier-contract.mts: ${error instanceof Error ? error.message : String(error)}`,
+    );
+    process.exit(2);
+  }
+}
diff --git a/src/runtimes/liboliphaunt-native/tools/native-runtime-carrier-contract.test.mts b/src/runtimes/liboliphaunt-native/tools/native-runtime-carrier-contract.test.mts
new file mode 100644
index 000000000..08fb516ed
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/native-runtime-carrier-contract.test.mts
@@ -0,0 +1,30 @@
+import { expect, test } from 'bun:test';
+
+import { bindNativeRuntimeResourceManifest } from './native-runtime-carrier-contract.mts';
+import { nativeRuntimeResourceManifestFixture } from './testdata/native-runtime-fixture.mts';
+
+test('binds only the exact native-direct runtime resource contract', () => {
+  const bound = bindNativeRuntimeResourceManifest(
+    nativeRuntimeResourceManifestFixture(),
+    'android-datum64',
+  );
+  expect(bound.toString('utf8')).toContain('clusterSeedTarget=android-datum64\n');
+  expect(() =>
+    bindNativeRuntimeResourceManifest(
+      nativeRuntimeResourceManifestFixture({ extra: { legacy: 'value' } }),
+      'android-datum64',
+    ),
+  ).toThrow(/exact canonical field set/u);
+  expect(() =>
+    bindNativeRuntimeResourceManifest(
+      nativeRuntimeResourceManifestFixture({ overrides: { cacheKey: '..' } }),
+      'android-datum64',
+    ),
+  ).toThrow(/native-direct contract/u);
+  expect(() =>
+    bindNativeRuntimeResourceManifest(
+      nativeRuntimeResourceManifestFixture({ overrides: { mode: 'native-server' } }),
+      'android-datum64',
+    ),
+  ).toThrow(/native-direct contract/u);
+});
diff --git a/tools/release/native-runtime-payload-policy.json b/src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json
similarity index 100%
rename from tools/release/native-runtime-payload-policy.json
rename to src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json
diff --git a/src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts b/src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts
new file mode 100644
index 000000000..069cd48d8
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts
@@ -0,0 +1,530 @@
+#!/usr/bin/env bun
+import {
+  accessSync,
+  constants,
+  existsSync,
+  lstatSync,
+  readFileSync,
+  readdirSync,
+  rmSync,
+  rmdirSync,
+} from 'node:fs';
+import { dirname, join, relative, resolve, sep } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import {
+  WINDOWS_VC_RUNTIME_RECEIPT,
+  verifyWindowsVcRuntimeClosure,
+} from '../../../../tools/packaging/windows-vc-runtime-closure.mts';
+
+const TOOL = 'native-runtime-payload.mts';
+const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../../../..');
+const POLICY_PATH = join(
+  ROOT,
+  'src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json',
+);
+const POLICY = JSON.parse(readFileSync(POLICY_PATH, 'utf8'));
+
+export const NATIVE_RUNTIME_TOOL_STEMS = Object.freeze([...POLICY.nativeRuntimeToolStems]);
+export const NATIVE_TOOLS_TOOL_STEMS = Object.freeze([...POLICY.nativeToolsToolStems]);
+export const WINDOWS_VC_RUNTIME_DLLS = Object.freeze([...POLICY.windowsVcRuntimeDlls]);
+export const NATIVE_PACKAGED_TOOL_STEMS = Object.freeze([
+  ...NATIVE_RUNTIME_TOOL_STEMS,
+  ...NATIVE_TOOLS_TOOL_STEMS,
+]);
+export const SNOWBALL_STOPWORD_LANGUAGES = Object.freeze([
+  'danish',
+  'dutch',
+  'english',
+  'finnish',
+  'french',
+  'german',
+  'hungarian',
+  'italian',
+  'nepali',
+  'norwegian',
+  'portuguese',
+  'russian',
+  'spanish',
+  'swedish',
+  'turkish',
+]);
+
+const DEV_RUNTIME_DIRS = Object.freeze([...POLICY.devRuntimeDirs]);
+const DEV_RUNTIME_SUFFIXES = Object.freeze([...POLICY.devRuntimeSuffixes]);
+const WINDOWS_DEV_RUNTIME_SUFFIXES = Object.freeze([...POLICY.windowsDevRuntimeSuffixes]);
+function fail(message) {
+  console.error(`${TOOL}: ${message}`);
+  process.exit(1);
+}
+
+function rel(path) {
+  const resolved = resolve(String(path));
+  const relativePath = relative(ROOT, resolved);
+  if (!relativePath || relativePath.startsWith('..') || relativePath === resolved) {
+    return resolved.split(sep).join('/');
+  }
+  return relativePath.split(sep).join('/');
+}
+
+function exists(path) {
+  return existsSync(path);
+}
+
+function isDirectory(path) {
+  try {
+    return lstatSync(path).isDirectory();
+  } catch {
+    return false;
+  }
+}
+
+function isFile(path) {
+  try {
+    return lstatSync(path).isFile();
+  } catch {
+    return false;
+  }
+}
+
+export function isWindowsTarget(target, runtimeDir = null) {
+  if (target && target.startsWith('windows-')) {
+    return true;
+  }
+  if (!runtimeDir) {
+    return false;
+  }
+  const binDir = join(runtimeDir, 'bin');
+  return NATIVE_PACKAGED_TOOL_STEMS.some((stem) => isFile(join(binDir, `${stem}.exe`)));
+}
+
+export function requiredRuntimeTools(target, runtimeDir = null) {
+  if (isWindowsTarget(target, runtimeDir)) {
+    return NATIVE_RUNTIME_TOOL_STEMS.map((stem) => `${stem}.exe`);
+  }
+  return [...NATIVE_RUNTIME_TOOL_STEMS];
+}
+
+export function requiredToolsPackageTools(target, runtimeDir = null) {
+  if (isWindowsTarget(target, runtimeDir)) {
+    return NATIVE_TOOLS_TOOL_STEMS.map((stem) => `${stem}.exe`);
+  }
+  return [...NATIVE_TOOLS_TOOL_STEMS];
+}
+
+export function packagedRuntimeTools(target, runtimeDir = null) {
+  if (isWindowsTarget(target, runtimeDir)) {
+    return NATIVE_PACKAGED_TOOL_STEMS.map((stem) => `${stem}.exe`);
+  }
+  return [...NATIVE_PACKAGED_TOOL_STEMS];
+}
+
+export function runtimeToolsForSet(target, runtimeDir = null, toolSet = 'packaged') {
+  if (toolSet === 'runtime') {
+    return requiredRuntimeTools(target, runtimeDir);
+  }
+  if (toolSet === 'tools') {
+    return requiredToolsPackageTools(target, runtimeDir);
+  }
+  return packagedRuntimeTools(target, runtimeDir);
+}
+
+export function requiredRuntimeMemberPaths(target, prefix) {
+  return requiredRuntimeTools(target).map((tool) => `${prefix.replace(/\/+$/, '')}/${tool}`);
+}
+
+export function requiredToolsMemberPaths(target, prefix) {
+  return requiredToolsPackageTools(target).map((tool) => `${prefix.replace(/\/+$/, '')}/${tool}`);
+}
+
+export function requiredCoreRuntimePaths(target, runtimeDir = null) {
+  const moduleSuffix = isWindowsTarget(target, runtimeDir)
+    ? '.dll'
+    : target?.startsWith('macos-')
+      ? '.dylib'
+      : '.so';
+  return [
+    `lib/postgresql/dict_snowball${moduleSuffix}`,
+    `lib/postgresql/plpgsql${moduleSuffix}`,
+    'share/postgresql/extension/plpgsql--1.0.sql',
+    'share/postgresql/extension/plpgsql.control',
+    'share/postgresql/snowball_create.sql',
+    ...SNOWBALL_STOPWORD_LANGUAGES.map(
+      (language) => `share/postgresql/tsearch_data/${language}.stop`,
+    ),
+  ];
+}
+
+function runtimeDirFor(root) {
+  for (const candidate of [join(root, 'runtime'), join(root, 'oliphaunt', 'runtime', 'files')]) {
+    if (isDirectory(candidate)) {
+      return candidate;
+    }
+  }
+  if (
+    isDirectory(join(root, 'bin')) &&
+    (isDirectory(join(root, 'share')) || isDirectory(join(root, 'lib')))
+  ) {
+    return root;
+  }
+  return null;
+}
+
+function removePath(path) {
+  rmSync(path, { recursive: true, force: true });
+}
+
+function walk(root, { includeDirs = false } = {}) {
+  if (!isDirectory(root)) {
+    return [];
+  }
+  const results = [];
+  const visit = (current) => {
+    for (const name of readdirSync(current).sort()) {
+      const path = join(current, name);
+      let stat;
+      try {
+        stat = lstatSync(path);
+      } catch {
+        continue;
+      }
+      if (stat.isDirectory()) {
+        if (includeDirs) {
+          results.push(path);
+        }
+        visit(path);
+      } else if (stat.isFile()) {
+        results.push(path);
+      }
+    }
+  };
+  visit(root);
+  return results.sort();
+}
+
+function pruneEmptyDirs(root) {
+  for (const path of walk(root, { includeDirs: true }).filter(isDirectory).sort().reverse()) {
+    try {
+      rmdirSync(path);
+    } catch {
+      // Directory is not empty or disappeared while pruning.
+    }
+  }
+}
+
+function posixRelative(from, to) {
+  return relative(from, to).split(sep).join('/');
+}
+
+function isDevRuntimeFile(relativePath, { windows }) {
+  const name = relativePath.split('/').pop().toLowerCase();
+  if (DEV_RUNTIME_SUFFIXES.some((suffix) => name.endsWith(suffix))) {
+    return true;
+  }
+  return windows && WINDOWS_DEV_RUNTIME_SUFFIXES.some((suffix) => name.endsWith(suffix));
+}
+
+function pruneTopLevelModuleDevFiles(root, { windows }) {
+  const moduleDir = join(root, 'lib', 'modules');
+  if (!isDirectory(moduleDir)) {
+    return;
+  }
+  for (const path of walk(moduleDir)) {
+    const relativePath = posixRelative(moduleDir, path);
+    if (isDevRuntimeFile(relativePath, { windows })) {
+      removePath(path);
+    }
+  }
+  pruneEmptyDirs(moduleDir);
+}
+
+export function pruneRuntimePayload(root, target = null, { toolSet = 'packaged' } = {}) {
+  const runtimeDir = runtimeDirFor(root);
+  if (!runtimeDir) {
+    return;
+  }
+
+  const windows = isWindowsTarget(target, runtimeDir);
+  const requiredTools = new Set(runtimeToolsForSet(target, runtimeDir, toolSet));
+  const binDir = join(runtimeDir, 'bin');
+  if (isDirectory(binDir)) {
+    for (const name of readdirSync(binDir).sort()) {
+      const path = join(binDir, name);
+      if (windows) {
+        if (name.toLowerCase().endsWith('.exe') && !requiredTools.has(name)) {
+          removePath(path);
+        }
+      } else if (!requiredTools.has(name)) {
+        removePath(path);
+      }
+    }
+  }
+
+  if (toolSet === 'tools' && isDirectory(runtimeDir)) {
+    for (const name of readdirSync(runtimeDir).sort()) {
+      if (name !== 'bin' && name !== 'lib') {
+        removePath(join(runtimeDir, name));
+      }
+    }
+  }
+
+  for (const relativePath of DEV_RUNTIME_DIRS) {
+    removePath(join(runtimeDir, ...relativePath.split('/')));
+  }
+
+  for (const path of walk(runtimeDir, { includeDirs: true }).sort().reverse()) {
+    if (isDirectory(path) && path.endsWith('.dSYM')) {
+      removePath(path);
+      continue;
+    }
+    if (!isFile(path)) {
+      continue;
+    }
+    const relativePath = posixRelative(runtimeDir, path);
+    if (isDevRuntimeFile(relativePath, { windows })) {
+      removePath(path);
+    }
+  }
+
+  pruneEmptyDirs(runtimeDir);
+  pruneTopLevelModuleDevFiles(root, { windows });
+}
+
+function validateTopLevelModuleDevFiles(root, { windows }) {
+  const errors = [];
+  const moduleDir = join(root, 'lib', 'modules');
+  if (!isDirectory(moduleDir)) {
+    return errors;
+  }
+  for (const path of walk(moduleDir)) {
+    const relativePath = posixRelative(moduleDir, path);
+    if (isDevRuntimeFile(relativePath, { windows })) {
+      errors.push(`${rel(path)} is a development-only native module file`);
+    }
+  }
+  return errors;
+}
+
+function validateRuntimeTree(root, target, requireRuntime, { toolSet = 'packaged' } = {}) {
+  const errors = [];
+  const runtimeDir = runtimeDirFor(root);
+  if (!runtimeDir) {
+    if (requireRuntime) {
+      errors.push(`${rel(root)} is missing a runtime tree`);
+    }
+    return errors;
+  }
+
+  const windows = isWindowsTarget(target, runtimeDir);
+  const requiredTools = new Set(runtimeToolsForSet(target, runtimeDir, toolSet));
+  const binDir = join(runtimeDir, 'bin');
+  if (requireRuntime && !isDirectory(binDir)) {
+    errors.push(`${rel(runtimeDir)} is missing bin`);
+  }
+  if (isDirectory(binDir)) {
+    for (const tool of [...requiredTools].sort()) {
+      const path = join(binDir, tool);
+      if (!isFile(path)) {
+        errors.push(`${rel(runtimeDir)} is missing required runtime tool bin/${tool}`);
+        continue;
+      }
+      if (!windows) {
+        try {
+          accessSync(path, constants.X_OK);
+        } catch {
+          errors.push(`${rel(path)} must be executable`);
+        }
+      }
+    }
+    for (const name of readdirSync(binDir).sort()) {
+      const path = join(binDir, name);
+      if (windows) {
+        if (name.toLowerCase().endsWith('.exe') && !requiredTools.has(name)) {
+          errors.push(`${rel(path)} is an extra Windows runtime executable`);
+        }
+      } else if (!requiredTools.has(name)) {
+        errors.push(`${rel(path)} is an extra runtime tool`);
+      }
+    }
+  }
+
+  if (requireRuntime && toolSet !== 'tools') {
+    for (const relativePath of requiredCoreRuntimePaths(target, runtimeDir)) {
+      if (!isFile(join(runtimeDir, ...relativePath.split('/')))) {
+        errors.push(`${rel(runtimeDir)} is missing required core runtime file ${relativePath}`);
+      }
+    }
+  }
+
+  if (toolSet === 'tools' && isDirectory(runtimeDir)) {
+    const allowed = new Set([
+      ...[...requiredTools].map((tool) => `bin/${tool}`),
+      ...(windows ? WINDOWS_VC_RUNTIME_DLLS.map((name) => `bin/${name}`) : []),
+      ...(windows ? [`bin/${WINDOWS_VC_RUNTIME_RECEIPT}`] : []),
+    ]);
+    for (const path of walk(runtimeDir)) {
+      const relativePath = posixRelative(runtimeDir, path);
+      const dependencyLibrary = windows
+        ? /^bin\/[^/]+\.dll$/iu.test(relativePath)
+        : /^lib\/[^/]+(?:\.so(?:\.[0-9]+)*|\.dylib)$/u.test(relativePath);
+      if (!allowed.has(relativePath) && !dependencyLibrary) {
+        errors.push(`${rel(path)} is not part of the native tools payload`);
+      }
+    }
+  }
+
+  for (const relativePath of DEV_RUNTIME_DIRS) {
+    const path = join(runtimeDir, ...relativePath.split('/'));
+    if (exists(path)) {
+      errors.push(`${rel(path)} is a development-only runtime path`);
+    }
+  }
+
+  for (const path of walk(runtimeDir, { includeDirs: true })) {
+    if (isDirectory(path) && path.endsWith('.dSYM')) {
+      errors.push(`${rel(path)} is a development-only debug symbol bundle`);
+      continue;
+    }
+    if (!isFile(path)) {
+      continue;
+    }
+    const relativePath = posixRelative(runtimeDir, path);
+    if (isDevRuntimeFile(relativePath, { windows })) {
+      errors.push(`${rel(path)} is a development-only runtime file`);
+    }
+  }
+
+  return errors;
+}
+
+export function validatePayload(
+  root,
+  target = null,
+  { requireRuntime = true, toolSet = 'packaged' } = {},
+) {
+  const runtimeDir = runtimeDirFor(root);
+  const windows = isWindowsTarget(target, runtimeDir);
+  const errors = [
+    ...validateRuntimeTree(root, target, requireRuntime, { toolSet }),
+    ...validateTopLevelModuleDevFiles(root, { windows }),
+  ];
+  if (windows && runtimeDir !== null && isDirectory(join(runtimeDir, 'bin'))) {
+    const searchRoots = [join(runtimeDir, 'bin')];
+    if (isFile(join(root, 'bin', 'oliphaunt.dll'))) {
+      searchRoots.push(join(root, 'bin'));
+    }
+    try {
+      verifyWindowsVcRuntimeClosure({
+        root,
+        searchRoots,
+        profile: toolSet === 'tools' ? undefined : 'provider',
+      });
+    } catch (error) {
+      errors.push(error instanceof Error ? error.message : String(error));
+    }
+  }
+  if (errors.length > 0) {
+    for (const error of errors) {
+      console.error(error);
+    }
+    fail(`${rel(root)} is not an optimized native runtime payload`);
+  }
+}
+
+export function optimizePayload(
+  root,
+  target = null,
+  { requireRuntime = true, toolSet = 'packaged' } = {},
+) {
+  pruneRuntimePayload(root, target, { toolSet });
+  validatePayload(root, target, { requireRuntime, toolSet });
+}
+
+function usage() {
+  return `Usage: src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts  [options]
+
+Prune and validate liboliphaunt native runtime payloads.
+The product packaging scripts strip binaries after pruning.
+
+Options:
+  --target            Release target id.
+  --check                     Validate without mutating the payload.
+  --allow-missing-runtime     Validate native files when the archive is library-only.
+  --tool-set             packaged, runtime, or tools. Default: packaged.
+  --help                      Show this help.
+`;
+}
+
+function parseArgs(argv) {
+  const args = {
+    root: null,
+    target: null,
+    check: false,
+    allowMissingRuntime: false,
+    toolSet: 'packaged',
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--help' || arg === '-h') {
+      console.log(usage());
+      process.exit(0);
+    }
+    if (arg === '--target') {
+      args.target = argv[++index];
+      if (!args.target) {
+        fail('--target requires a value');
+      }
+      continue;
+    }
+    if (arg === '--check') {
+      args.check = true;
+      continue;
+    }
+    if (arg === '--allow-missing-runtime') {
+      args.allowMissingRuntime = true;
+      continue;
+    }
+    if (arg === '--tool-set') {
+      args.toolSet = argv[++index];
+      if (!['packaged', 'runtime', 'tools'].includes(args.toolSet)) {
+        fail('--tool-set must be one of: packaged, runtime, tools');
+      }
+      continue;
+    }
+    if (arg.startsWith('-')) {
+      fail(`unknown option: ${arg}`);
+    }
+    if (args.root) {
+      fail(`unexpected positional argument: ${arg}`);
+    }
+    args.root = arg;
+  }
+  if (!args.root) {
+    console.error(usage());
+    process.exit(2);
+  }
+  return args;
+}
+
+export function main(argv = process.argv.slice(2)) {
+  const args = parseArgs(argv);
+  const root = resolve(args.root);
+  if (!exists(root)) {
+    fail(`payload root does not exist: ${root}`);
+  }
+  if (args.check) {
+    validatePayload(root, args.target, {
+      requireRuntime: !args.allowMissingRuntime,
+      toolSet: args.toolSet,
+    });
+    return;
+  }
+  optimizePayload(root, args.target, {
+    requireRuntime: !args.allowMissingRuntime,
+    toolSet: args.toolSet,
+  });
+}
+
+if (import.meta.main) {
+  main();
+}
diff --git a/src/runtimes/liboliphaunt-native/tools/native-smoke-data.mts b/src/runtimes/liboliphaunt-native/tools/native-smoke-data.mts
new file mode 100644
index 000000000..d9867a27c
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/native-smoke-data.mts
@@ -0,0 +1,38 @@
+import { readFileSync, renameSync, writeFileSync } from 'node:fs';
+import { join } from 'node:path';
+
+const [operation, value] = process.argv.slice(2);
+switch (operation) {
+  case 'postgres-version':
+    console.log(
+      Bun.TOML.parse(readFileSync('src/third-party/postgres/source.toml', 'utf8')).postgresql
+        .version,
+    );
+    break;
+  case 'profile': {
+    const fixture = JSON.parse(
+      readFileSync('src/database-resources/contracts/profile-probe.json', 'utf8'),
+    );
+    const probe = fixture.profiles?.[value];
+    if (fixture.schema !== 'oliphaunt-cluster-seed-profile-probe-v1' || !probe)
+      throw new Error(`missing cluster-seed profile ${value}`);
+    for (const field of ['sql', 'expected']) {
+      if (typeof probe[field] !== 'string' || /[\r\n\0]/u.test(probe[field]))
+        throw new Error(`invalid ${value}.${field}`);
+      console.log(probe[field]);
+    }
+    break;
+  }
+  case 'managed-root': {
+    const descriptor = join(value, '.oliphaunt.json');
+    writeFileSync(
+      `${descriptor}.tmp`,
+      '{"schema":"oliphaunt-database-root-v1","engineFamily":"native","pgdata":"pgdata","postgresMajor":18,"physicalFormat":"native-pg18-v1"}\n',
+      { flag: 'wx', mode: 0o600 },
+    );
+    renameSync(`${descriptor}.tmp`, descriptor);
+    break;
+  }
+  default:
+    throw new Error(`unknown native smoke data operation ${operation}`);
+}
diff --git a/src/runtimes/liboliphaunt-native/tools/package-carriers.mts b/src/runtimes/liboliphaunt-native/tools/package-carriers.mts
new file mode 100644
index 000000000..9496ad928
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/package-carriers.mts
@@ -0,0 +1,264 @@
+#!/usr/bin/env bun
+import { existsSync, readdirSync } from 'node:fs';
+import path from 'node:path';
+import { packageContribNativeCarriers } from '../../../extensions/artifacts/packages/tools/package-carriers.mts';
+import { buildMavenArtifactManifest } from '../../../../tools/packaging/build-maven-artifact-manifest.mts';
+import { stageMavenArtifactManifest } from '../../../../tools/packaging/maven-artifact-staging.mts';
+import { validateCargoArtifactPackages } from '../../../../tools/packaging/native-cargo-payload.mts';
+import { extractPortableArchiveTree } from '../../../../tools/packaging/portable-archive.mts';
+import {
+  artifactNpmPackageTargets,
+  copyStagedRuntimeAssets,
+  extractReleaseArchiveFile,
+  fail,
+  isDirectory,
+  packStagedNpmCarrier,
+  rel,
+  stageNpmPackageDescriptor,
+  stageWindowsVcRuntimeMembers,
+  TOOL,
+  validatePackedNpmPackage,
+} from '../../../../tools/packaging/release-carrier.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  releaseNoticeRows,
+  stageReleaseNotices,
+} from '../../../../tools/packaging/release-notices.mts';
+import { writeChecksumManifest } from '../../../../tools/packaging/write-checksum-manifest.mts';
+import {
+  artifactTargets,
+  compareText,
+  contribCarrierDescriptor,
+  currentProductVersionSync,
+  ROOT,
+  registryPackageRows,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { checkLiboliphauntReleaseAssets } from './check-release-assets.mts';
+import {
+  requiredCoreRuntimePaths,
+  requiredRuntimeMemberPaths,
+  requiredToolsPackageTools,
+  validatePayload,
+} from './native-runtime-payload.mts';
+import { packageNativeCargoArtifacts } from './package-liboliphaunt-cargo-artifacts.mts';
+
+export const LIBOLIPHAUNT_NATIVE_PRODUCT = 'liboliphaunt-native';
+
+const LIBOLIPHAUNT_NATIVE_KIND = 'native-runtime';
+
+const LIBOLIPHAUNT_NATIVE_PACKAGE_ROOT = path.join(
+  ROOT,
+  'src/runtimes/liboliphaunt-native/packages',
+);
+
+function hasLiboliphauntReleaseArchive(assetDir) {
+  if (!isDirectory(assetDir)) {
+    return false;
+  }
+  return readdirSync(assetDir).some(
+    (name) =>
+      name.startsWith('liboliphaunt-') &&
+      (name.endsWith('.tar.gz') || name.endsWith('.zip') || name.endsWith('.tsv')),
+  );
+}
+
+async function ensureLiboliphauntReleaseAssets() {
+  const assetDir = path.join(ROOT, 'target/liboliphaunt/release-assets');
+  if (!hasLiboliphauntReleaseArchive(assetDir)) {
+    copyStagedRuntimeAssets({
+      product: LIBOLIPHAUNT_NATIVE_PRODUCT,
+      destination: assetDir,
+      envName: 'OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSET_INPUT_DIRS',
+      patterns: [
+        'liboliphaunt-*.tar.gz',
+        'liboliphaunt-*.zip',
+        'liboliphaunt-*.tsv',
+        'liboliphaunt-*.sha256',
+      ],
+    });
+  }
+  const version = currentProductVersionSync(LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL);
+  await writeChecksumManifest([
+    '--asset-dir',
+    rel(assetDir),
+    '--output',
+    `liboliphaunt-${version}-release-assets.sha256`,
+    '--pattern',
+    'liboliphaunt-*.tar.gz',
+    '--pattern',
+    'liboliphaunt-*.zip',
+    '--pattern',
+    'liboliphaunt-*.tsv',
+  ]);
+  await checkLiboliphauntReleaseAssets(['--asset-dir', rel(assetDir)]);
+}
+
+function ensureNativeToolsAbsentFromRuntime(stage, target) {
+  const runtimeDir = path.join(stage, 'runtime');
+  const leaked = [];
+  for (const tool of requiredToolsPackageTools(target, runtimeDir)) {
+    if (existsSync(path.join(runtimeDir, 'bin', tool))) {
+      leaked.push(`runtime/bin/${tool}`);
+    }
+  }
+  if (leaked.length > 0) {
+    fail(
+      `${rel(stage)} root runtime package must not contain split native tools: ${leaked.join(', ')}`,
+    );
+  }
+}
+
+function liboliphauntRuntimeNpmPackageTargets(version, targets) {
+  const available = artifactNpmPackageTargets({
+    product: LIBOLIPHAUNT_NATIVE_PRODUCT,
+    kind: LIBOLIPHAUNT_NATIVE_KIND,
+    surface: 'typescript-native-direct',
+    packageRoot: LIBOLIPHAUNT_NATIVE_PACKAGE_ROOT,
+    version,
+  });
+  if (!targets) return available;
+  for (const target of targets) {
+    if (!available.some((row) => row[2].target === target))
+      fail(`unsupported native npm carrier target: ${target}`);
+  }
+  return available.filter((row) => targets.includes(row[2].target));
+}
+
+function embeddedCoreModuleMembers(target, prefix) {
+  const suffix =
+    target === 'windows-x64-msvc' ? '.dll' : target === 'macos-arm64' ? '.dylib' : '.so';
+  const normalizedPrefix = prefix.replace(/\/+$/u, '');
+  return ['dict_snowball', 'plpgsql'].map((stem) => `${normalizedPrefix}/${stem}${suffix}`);
+}
+
+function stageLiboliphauntNpmPayloads(
+  version,
+  { assetDir = path.join(ROOT, 'target/liboliphaunt/release-assets'), targets } = {},
+) {
+  const stages = new Map();
+  for (const [packageName, packageDir, target] of liboliphauntRuntimeNpmPackageTargets(
+    version,
+    targets,
+  )) {
+    const libraryRelativePath = target.libraryRelativePath ?? target.library_relative_path;
+    if (typeof libraryRelativePath !== 'string' || libraryRelativePath.length === 0) {
+      fail(`${target.id} must declare library_relative_path for npm artifact package publication`);
+    }
+    const stage = stageNpmPackageDescriptor(packageName, packageDir, version, {
+      target: target.target,
+    });
+    stageReleaseNotices(stage, { profile: 'native-runtime' });
+    const archive = path.join(assetDir, target.asset.replaceAll('{version}', version));
+    extractReleaseArchiveFile(archive, libraryRelativePath, path.join(stage, libraryRelativePath));
+    extractPortableArchiveTree(archive, path.join(stage, 'lib/modules'), 'lib/modules');
+    extractPortableArchiveTree(archive, path.join(stage, 'runtime'), 'runtime');
+    const vcRuntimeMembers = [
+      ...stageWindowsVcRuntimeMembers(archive, stage, target.target, 'bin', {
+        profile: 'provider',
+      }),
+      ...stageWindowsVcRuntimeMembers(archive, stage, target.target, 'runtime/bin', {
+        alreadyExtracted: true,
+        profile: 'provider',
+      }),
+    ];
+    ensureNativeToolsAbsentFromRuntime(stage, target.target);
+    validatePayload(stage, target.target, { toolSet: 'runtime' });
+    assertReleaseNoticesInDirectory(stage, { profile: 'native-runtime' });
+    stages.set(packageName, { stage, vcRuntimeMembers });
+  }
+  return stages;
+}
+
+export function liboliphauntNpmTarballs(version, options = {}) {
+  const packages = [];
+  const runtimeStages = stageLiboliphauntNpmPayloads(version, options);
+  for (const [packageName, , target] of liboliphauntRuntimeNpmPackageTargets(
+    version,
+    options.targets,
+  )) {
+    const payload = runtimeStages.get(packageName);
+    const libraryRelativePath = target.libraryRelativePath ?? target.library_relative_path;
+    const runtimeMembers = requiredRuntimeMemberPaths(target.target, 'package/runtime/bin');
+    const coreRuntimeMembers = requiredCoreRuntimePaths(target.target).map(
+      (member) => `package/runtime/${member}`,
+    );
+    const requiredMembers = [
+      `package/${libraryRelativePath}`,
+      ...embeddedCoreModuleMembers(target.target, 'package/lib/modules'),
+      ...runtimeMembers,
+      ...coreRuntimeMembers,
+      ...payload.vcRuntimeMembers.map((member) => `package/${member}`),
+      ...releaseNoticeRows({ profile: 'native-runtime' }).map((row) => `package/${row.member}`),
+    ];
+    const tarball = packStagedNpmCarrier(payload.stage);
+    validatePackedNpmPackage({
+      packageName,
+      version,
+      tarball,
+      requiredMembers,
+      executableMembers: runtimeMembers,
+    });
+    assertReleaseNoticesInArchive(tarball, { profile: 'native-runtime', prefix: 'package' });
+    packages.push([packageName, tarball]);
+  }
+  return packages;
+}
+
+function nativeCargoArtifactTargets(kind) {
+  return artifactTargets(LIBOLIPHAUNT_NATIVE_PRODUCT, kind, TOOL)
+    .filter((target) => target.surfaces.includes('rust-native-direct'))
+    .sort((left, right) => compareText(left.target, right.target));
+}
+
+function validateNativeCargoArtifacts(outputDir) {
+  const expectedAggregators = new Set(
+    nativeCargoArtifactTargets(LIBOLIPHAUNT_NATIVE_KIND).map(
+      (target) => `${LIBOLIPHAUNT_NATIVE_PRODUCT}-${target.target}`,
+    ),
+  );
+  const contribArtifactProduct = contribCarrierDescriptor(TOOL).artifactProduct;
+  const configuredCrates = new Set(
+    registryPackageRows({ product: LIBOLIPHAUNT_NATIVE_PRODUCT, packageKind: 'crates' }, TOOL)
+      .map((row) => row.packageName)
+      .filter(
+        (name) => name !== contribArtifactProduct && !name.startsWith(`${contribArtifactProduct}-`),
+      ),
+  );
+  return validateCargoArtifactPackages(outputDir, {
+    product: LIBOLIPHAUNT_NATIVE_PRODUCT,
+    expectedAggregators,
+    configuredCrates,
+  });
+}
+
+export async function liboliphauntNativeCargoArtifactPackages(
+  version = currentProductVersionSync(LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL),
+) {
+  const outputDir = path.join(ROOT, 'target/liboliphaunt/cargo-artifacts');
+  await ensureLiboliphauntReleaseAssets();
+  await packageNativeCargoArtifacts(['--version', version, '--output-dir', rel(outputDir)]);
+  return validateNativeCargoArtifacts(outputDir);
+}
+
+export async function packageLiboliphauntNativeCarriers() {
+  const version = currentProductVersionSync(LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL);
+  await liboliphauntNativeCargoArtifactPackages(version);
+  liboliphauntNpmTarballs(version);
+  const contribProduct = contribCarrierDescriptor(TOOL).artifactProduct;
+  const manifest = await buildMavenArtifactManifest(
+    'target/release/maven-manifests/liboliphaunt-native.tsv',
+    {
+      runtime: true,
+      extensions: true,
+      extensionProducts: [contribProduct],
+    },
+  );
+  await stageMavenArtifactManifest(
+    manifest,
+    path.join(ROOT, 'target/release/maven-staging/liboliphaunt-native'),
+  );
+  await packageContribNativeCarriers();
+}
+
+if (import.meta.main) await packageLiboliphauntNativeCarriers();
diff --git a/tools/release/package-liboliphaunt-aggregate-assets.sh b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-aggregate-assets.sh
similarity index 77%
rename from tools/release/package-liboliphaunt-aggregate-assets.sh
rename to src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-aggregate-assets.sh
index 08c490db1..78bc00eb9 100755
--- a/tools/release/package-liboliphaunt-aggregate-assets.sh
+++ b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-aggregate-assets.sh
@@ -15,10 +15,10 @@ fail() {
 asset_dir="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS:-target/liboliphaunt/release-assets}"
 [ -d "$asset_dir" ] || fail "missing liboliphaunt release asset directory: $asset_dir"
 
-version="$(tools/dev/bun.sh tools/release/product-version.mjs version liboliphaunt-native)"
+version="$(tools/dev/bun.sh tools/release/product-version.mts version liboliphaunt-native)"
 checksum_file="$asset_dir/liboliphaunt-${version}-release-assets.sha256"
 
-tools/release/write_checksum_manifest.mjs \
+tools/packaging/write-checksum-manifest.mts \
   --asset-dir "$asset_dir" \
   --output "$(basename "$checksum_file")" \
   --pattern '*.tar.gz' \
@@ -26,4 +26,4 @@ tools/release/write_checksum_manifest.mjs \
   --pattern '*.zip' \
   --pattern '*.tsv'
 
-tools/dev/bun.sh tools/release/check-liboliphaunt-release-assets.mjs --asset-dir "$asset_dir"
+tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/check-release-assets.mts --asset-dir "$asset_dir"
diff --git a/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.mts b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.mts
new file mode 100644
index 000000000..7b223f5c9
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.mts
@@ -0,0 +1,59 @@
+#!/usr/bin/env bun
+import path from 'node:path';
+import {
+  packagePayload,
+  parseCargoArtifactArgs,
+  prepareCargoArtifactWorkspace,
+  selectCargoArtifactTargets,
+  writePackagesManifest,
+} from '../../../../tools/packaging/native-cargo-payload.mts';
+import { inspectPlatformBinaryTree } from '../../../../tools/packaging/platform-binary-contract.mts';
+import { extractPortableArchiveTree } from '../../../../tools/packaging/portable-archive.mts';
+import { assertReleaseNoticesInArchive } from '../../../../tools/packaging/release-notices.mts';
+import { validatePayload } from './native-runtime-payload.mts';
+
+const PRODUCT = 'liboliphaunt-native';
+const KIND = 'native-runtime';
+async function validateNativePayload(payloadRoot, target, { toolSet }) {
+  const windowsRuntime = target === 'windows-x64-msvc' && toolSet === 'runtime';
+  await inspectPlatformBinaryTree(payloadRoot, {
+    target,
+    requireWindowsRuntimeImportLibrary: windowsRuntime,
+    windowsVcRuntimeProfile: windowsRuntime ? 'provider' : undefined,
+  });
+  validatePayload(payloadRoot, target, { toolSet });
+}
+
+export async function packageNativeCargoArtifacts(argv) {
+  const args = await parseCargoArtifactArgs(argv, {
+    product: PRODUCT,
+    assetDir: 'target/liboliphaunt/release-assets',
+    outputDir: 'target/liboliphaunt/cargo-artifacts',
+    workDir: 'target/liboliphaunt',
+  });
+  const { sourceRoot, cargoTargetDir } = prepareCargoArtifactWorkspace(args);
+  const targets = selectCargoArtifactTargets(PRODUCT, KIND, args.targets);
+  const packages = [];
+  for (const target of targets) {
+    const archive = path.join(args.assetDir, target.asset.replaceAll('{version}', args.version));
+    assertReleaseNoticesInArchive(archive, { profile: 'native-runtime' });
+    const root = path.join(sourceRoot, target.target + '-extracted');
+    extractPortableArchiveTree(archive, root);
+    await validateNativePayload(root, target.target, { toolSet: 'runtime' });
+    packages.push(
+      ...packagePayload(root, sourceRoot, args.outputDir, cargoTargetDir, {
+        target,
+        version: args.version,
+        partBytes: args.partBytes,
+        packageBase: PRODUCT,
+        artifactProduct: PRODUCT,
+        artifactKind: KIND,
+        artifactLabel: 'liboliphaunt native runtime',
+        noticeProfile: 'native-runtime',
+      }),
+    );
+  }
+  writePackagesManifest(packages, args.outputDir, PRODUCT);
+  return packages;
+}
+if (import.meta.main) await packageNativeCargoArtifacts(Bun.argv.slice(2));
diff --git a/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.test.mts b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.test.mts
new file mode 100644
index 000000000..a46ff87b5
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.test.mts
@@ -0,0 +1,231 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { chmodSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import test from 'node:test';
+import {
+  packageNativeToolsCargoArtifacts,
+  renderUnsupportedToolsTargetGuard,
+} from '../../../postgres-tools/native/tools/package-cargo-artifacts.mts';
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import { NATIVE_CARGO_CARRIER_LICENSES } from '../../../../tools/packaging/native-cargo-payload.mts';
+import {
+  canonicalGzipSync,
+  extractPortableArchiveTree,
+  readPortableArchiveEntries,
+} from '../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInArchive,
+  stageReleaseNotices,
+} from '../../../../tools/packaging/release-notices.mts';
+import { elfFixture } from '../../../../tools/packaging/testdata/release-fixture-utils.mts';
+import { requiredCoreRuntimePaths } from './native-runtime-payload.mts';
+import { packageNativeCargoArtifacts } from './package-liboliphaunt-cargo-artifacts.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../../../..');
+
+function archiveMember(file, member) {
+  return readPortableArchiveEntries(file).get(member).data().toString('utf8');
+}
+
+function writeExecutable(file, contents) {
+  mkdirSync(path.dirname(file), { recursive: true });
+  writeFileSync(file, contents);
+  chmodSync(file, 0o755);
+}
+
+function archiveFixture(source, archive) {
+  writeFileSync(archive, canonicalGzipSync(createDeterministicTar(source, '.', {})));
+}
+
+function sha256(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+test('freezes deterministic .crate bytes and prepares an extracted native consumer', async () => {
+  const root = process.env.OLIPHAUNT_NATIVE_CARGO_TEST_ROOT;
+  if (!root)
+    throw new Error(
+      'Run bash src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.test.sh',
+    );
+  const assets = path.join(root, 'assets');
+  const runtime = path.join(root, 'runtime-fixture');
+  const tools = path.join(root, 'tools-fixture');
+  const output = path.join(root, 'output');
+  const work = path.join(root, 'work');
+  const fixtureElf = elfFixture({ machine: 62, requiredVersions: ['GLIBC_2.17'] });
+  mkdirSync(path.join(runtime, 'runtime/lib'), { recursive: true });
+  writeFileSync(path.join(runtime, 'runtime/lib/liboliphaunt.so'), fixtureElf);
+  for (const name of ['initdb', 'pg_ctl', 'postgres']) {
+    writeExecutable(path.join(runtime, 'runtime/bin', name), fixtureElf);
+  }
+  for (const relativePath of requiredCoreRuntimePaths(
+    'linux-x64-gnu',
+    path.join(runtime, 'runtime'),
+  )) {
+    const file = path.join(runtime, 'runtime', ...relativePath.split('/'));
+    mkdirSync(path.dirname(file), { recursive: true });
+    writeFileSync(
+      file,
+      relativePath.startsWith('lib/postgresql/') ? fixtureElf : `${relativePath}\n`,
+    );
+  }
+  for (const name of ['pg_basebackup', 'pg_dump', 'psql']) {
+    writeExecutable(path.join(tools, 'runtime/bin', name), fixtureElf);
+  }
+  stageReleaseNotices(runtime, { profile: 'native-runtime' });
+  stageReleaseNotices(tools, { profile: 'native-tools' });
+  mkdirSync(assets, { recursive: true });
+  archiveFixture(runtime, path.join(assets, 'liboliphaunt-9.8.7-linux-x64-gnu.tar.gz'));
+  const toolsAssets = path.join(root, 'tools-assets');
+  mkdirSync(toolsAssets, { recursive: true });
+  mkdirSync(path.join(tools, 'runtime/lib'), { recursive: true });
+  writeFileSync(path.join(tools, 'runtime/lib/libpq.so.5'), fixtureElf);
+  archiveFixture(tools, path.join(toolsAssets, 'oliphaunt-tools-9.8.7-linux-x64-gnu.tar.gz'));
+
+  const packageArgs = [
+    '--asset-dir',
+    assets,
+    '--output-dir',
+    output,
+    '--work-dir',
+    work,
+    '--version',
+    '9.8.7',
+    '--target',
+    'linux-x64-gnu',
+    '--part-bytes',
+    '65536',
+  ];
+  await packageNativeCargoArtifacts(packageArgs);
+
+  const toolsOutput = path.join(root, 'tools-output');
+  const toolsArgs = [...packageArgs];
+  toolsArgs[toolsArgs.indexOf('--asset-dir') + 1] = toolsAssets;
+  toolsArgs[toolsArgs.indexOf('--output-dir') + 1] = toolsOutput;
+  toolsArgs[toolsArgs.indexOf('--work-dir') + 1] = path.join(root, 'tools-work');
+  await packageNativeToolsCargoArtifacts(toolsArgs);
+  const manifest = JSON.parse(readFileSync(path.join(output, 'packages.json'), 'utf8'));
+  const toolsManifest = JSON.parse(readFileSync(path.join(toolsOutput, 'packages.json'), 'utf8'));
+  manifest.packages.push(...toolsManifest.packages);
+  assert(
+    toolsManifest.packages.some(
+      ({ role, cratePath, name }) =>
+        role === 'part' &&
+        readPortableArchiveEntries(path.resolve(ROOT, cratePath)).has(
+          name + '-9.8.7/payload/files/runtime/lib/libpq.so.5',
+        ),
+    ),
+  );
+  assert.ok(manifest.packages.length >= 5);
+  assert.deepEqual(
+    new Set(manifest.packages.map(({ role }) => role)),
+    new Set(['part', 'aggregator', 'facade']),
+  );
+  assert.ok(
+    manifest.packages.every(
+      ({ cratePath }) => typeof cratePath === 'string' && cratePath.endsWith('.crate'),
+    ),
+  );
+  assert.equal(
+    readdirSync(output).filter((name) => name.endsWith('.crate')).length +
+      readdirSync(toolsOutput).filter((name) => name.endsWith('.crate')).length,
+    manifest.packages.length,
+  );
+  for (const item of manifest.packages) {
+    const expectedProfile = item.role === 'part' ? item.kind : 'code-facade';
+    assert.equal(
+      item.noticeProfile,
+      expectedProfile,
+      `${item.name} must freeze its carrier notice profile`,
+    );
+    const packedManifest = archiveMember(
+      path.resolve(ROOT, item.cratePath),
+      `${item.name}-9.8.7/Cargo.toml`,
+    );
+    assert.equal(
+      Bun.TOML.parse(packedManifest).package.license,
+      NATIVE_CARGO_CARRIER_LICENSES[expectedProfile],
+      `${item.name} must declare its exact role license closure`,
+    );
+    assertReleaseNoticesInArchive(path.resolve(ROOT, item.cratePath), {
+      prefix: `${item.name}-9.8.7`,
+      profile: expectedProfile,
+    });
+  }
+
+  const consumer = path.join(root, 'installed-consumer');
+  mkdirSync(path.join(consumer, 'src'), { recursive: true });
+  const patches = [];
+  for (const item of manifest.packages) {
+    const extracted = path.join(consumer, 'packages', item.name);
+    extractPortableArchiveTree(path.resolve(ROOT, item.cratePath), extracted);
+    patches.push(
+      `${item.name} = { path = ${JSON.stringify(path.join(extracted, item.name + '-9.8.7'))} }`,
+    );
+  }
+  writeFileSync(
+    path.join(consumer, 'Cargo.toml'),
+    [
+      '[package]',
+      'name = "installed-native-consumer"',
+      'version = "0.0.0"',
+      'edition = "2024"',
+      '[workspace]',
+      '[dependencies]',
+      'oliphaunt-tools = "=9.8.7"',
+      'liboliphaunt-native-linux-x64-gnu = "=9.8.7"',
+      '[patch.crates-io]',
+      ...patches,
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(path.join(consumer, 'src/lib.rs'), 'pub fn installed() {}\n');
+  const packedAggregator = manifest.packages.find(({ role }) => role === 'aggregator');
+  const packedManifest = archiveMember(
+    path.resolve(ROOT, packedAggregator.cratePath),
+    `${packedAggregator.name}-9.8.7/Cargo.toml`,
+  );
+  assert.doesNotMatch(packedManifest, /oliphaunt-package-deps|registry\s*=/u);
+  assert.doesNotMatch(
+    packedManifest,
+    /\[build-dependencies[.]liboliphaunt-native-linux-x64-gnu-part-001\][\s\S]*?path\s*=/u,
+  );
+  assert.match(packedManifest, /version\s*=\s*"=9[.]8[.]7"/u);
+
+  const facade = manifest.packages.find(({ role }) => role === 'facade');
+  assert.ok(facade);
+  const facadeRoot = path.dirname(path.resolve(ROOT, facade.manifestPath));
+  const facadeSource = path.join(facadeRoot, 'src/lib.rs');
+  const facadeText = readFileSync(facadeSource, 'utf8');
+  const packedFacadeSource = archiveMember(
+    path.resolve(ROOT, facade.cratePath),
+    `${facade.name}-9.8.7/src/lib.rs`,
+  );
+  assert.equal(packedFacadeSource, facadeText);
+  const forcedUnsupported = path.join(root, 'forced-unsupported-tools.rs');
+  writeFileSync(
+    forcedUnsupported,
+    `#![forbid(unsafe_code)]
+${renderUnsupportedToolsTargetGuard(['fixture-unsupported'], ['any()'])}
+pub const FIXTURE: bool = true;
+`,
+  );
+  const forcedSupported = path.join(root, 'forced-supported-tools.rs');
+  writeFileSync(
+    forcedSupported,
+    `#![forbid(unsafe_code)]
+${renderUnsupportedToolsTargetGuard(['fixture-supported'], ['all()'])}
+pub const FIXTURE: bool = true;
+`,
+  );
+  const digests = () =>
+    new Map(
+      manifest.packages.map((item) => [item.name, sha256(path.resolve(ROOT, item.cratePath))]),
+    );
+  const firstDigests = digests();
+  await packageNativeCargoArtifacts(packageArgs);
+  await packageNativeToolsCargoArtifacts(toolsArgs);
+  assert.deepEqual(digests(), firstDigests);
+});
diff --git a/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.test.sh b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.test.sh
new file mode 100644
index 000000000..c49aefdcb
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.test.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+export OLIPHAUNT_NATIVE_CARGO_TEST_ROOT OLIPHAUNT_ELF_STRIP OLIPHAUNT_STRIP
+OLIPHAUNT_NATIVE_CARGO_TEST_ROOT="$(mktemp -d)"
+trap 'rm -rf "$OLIPHAUNT_NATIVE_CARGO_TEST_ROOT"' EXIT
+root="$OLIPHAUNT_NATIVE_CARGO_TEST_ROOT"
+OLIPHAUNT_ELF_STRIP="$root/forbidden-strip"
+OLIPHAUNT_STRIP="$OLIPHAUNT_ELF_STRIP"
+cat > "$OLIPHAUNT_STRIP" <<'STRIP'
+#!/bin/sh
+echo 'Carrier assembly must not strip frozen release assets' >&2
+exit 99
+STRIP
+chmod +x "$OLIPHAUNT_STRIP"
+bun test --timeout=30000 ./src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-cargo-artifacts.test.mts
+CARGO_HOME="$root/installed-consumer/cargo-home" \
+  CARGO_TARGET_DIR="$root/installed-consumer/target" \
+  cargo check --offline --manifest-path "$root/installed-consumer/Cargo.toml"
+if rustc --crate-name oliphaunt_tools --crate-type lib --edition 2024 \
+  --emit metadata -o "$root/unsupported.rmeta" "$root/forced-unsupported-tools.rs" \
+  > "$root/unsupported.log" 2>&1; then
+  echo 'Unsupported tools target unexpectedly compiled' >&2
+  exit 1
+fi
+grep -Fq 'has no portable fallback' "$root/unsupported.log"
+rustc --crate-name oliphaunt_tools --crate-type lib --edition 2024 \
+  --emit metadata -o "$root/supported.rmeta" "$root/forced-supported-tools.rs"
diff --git a/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-linux-assets.sh b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-linux-assets.sh
new file mode 100755
index 000000000..ba9401cd0
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-linux-assets.sh
@@ -0,0 +1,105 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+
+fail() {
+  echo "package-liboliphaunt-linux-assets.sh: $*" >&2
+  exit 1
+}
+
+require() {
+  command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
+}
+
+source "$root/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh"
+
+fetch_release_source_assets() {
+  if [ "${OLIPHAUNT_RELEASE_FETCH_ASSETS:-1}" = "0" ]; then
+    return 0
+  fi
+  echo "==> Fetching pinned source assets"
+  bash src/third-party/tools/fetch-sources.sh native-runtime >/tmp/liboliphaunt-release-linux-assets-fetch.log
+  if [ "${OLIPHAUNT_BUILD_EXTENSIONS:-0}" != 0 ]; then
+    bash src/third-party/tools/fetch-sources.sh extensions >>/tmp/liboliphaunt-release-linux-assets-fetch.log
+  fi
+}
+
+if [ "$(uname -s)" != "Linux" ]; then
+  fail "Linux liboliphaunt release assets must be built on Linux"
+fi
+
+case "$(uname -m)" in
+  x86_64|amd64) target_id="linux-x64-gnu" ;;
+  aarch64|arm64) target_id="linux-arm64-gnu" ;;
+  *) fail "unsupported Linux architecture $(uname -m)" ;;
+esac
+
+require bun
+
+version="$(tools/dev/bun.sh tools/release/product-version.mts version liboliphaunt-native)"
+out_dir="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS:-$root/target/liboliphaunt/release-assets}"
+stage_root="$root/target/liboliphaunt/release-stage-$target_id"
+work_root="${OLIPHAUNT_LINUX_WORK_ROOT:-$root/target/liboliphaunt-pg18-$target_id}"
+headers_dir="$root/src/runtimes/liboliphaunt-native/include"
+lib="$work_root/out/liboliphaunt.so"
+embedded_modules="$work_root/out/modules"
+runtime="$work_root/install"
+stage="$stage_root/liboliphaunt-${version}-${target_id}"
+asset="liboliphaunt-${version}-${target_id}.tar.gz"
+catalog_file="$stage_root/extension-catalog.tsv"
+
+rm -rf "$stage_root"
+mkdir -p "$out_dir" "$stage/include" "$stage/lib" "$stage/runtime"
+
+fetch_release_source_assets
+
+if [ "${OLIPHAUNT_RELEASE_BUILD_RUNTIME:-1}" = "1" ]; then
+  echo "==> Building liboliphaunt $target_id"
+  src/runtimes/liboliphaunt-native/bin/build-postgres18-linux.sh >/tmp/liboliphaunt-release-"$target_id".log
+fi
+
+[ -f "$lib" ] || fail "missing Linux liboliphaunt shared library at $lib"
+oliphaunt_assert_base_embedded_modules_exact "$embedded_modules" so ||
+  fail "base $target_id embedded module inventory must contain only regular dict_snowball.so and plpgsql.so modules"
+for tool in initdb pg_ctl postgres; do
+  [ -x "$runtime/bin/$tool" ] || fail "missing Linux $tool at $runtime/bin/$tool"
+done
+
+echo "==> Verifying base liboliphaunt $target_id runtime is extension-clean"
+bun src/extensions/tools/native-extension-files.mts >"$catalog_file"
+oliphaunt_assert_base_runtime_has_no_optional_extensions "$catalog_file" "$runtime" ||
+  fail "base $target_id runtime must not ship optional extension assets"
+
+rsync -a --delete "$headers_dir/" "$stage/include/"
+cp "$lib" "$stage/lib/"
+rsync -a --delete "$embedded_modules/" "$stage/lib/modules/"
+rsync -a --delete \
+  --exclude '/bin/pg_dump' \
+  --exclude '/bin/pg_basebackup' \
+  --exclude '/bin/psql' \
+  --exclude 'share/icu/***' \
+  "$runtime/" "$stage/runtime/"
+# PostgreSQL installs versioned shared-library aliases as symlinks. Release
+# archives are link-free consumer inputs, so materialize only validated,
+# relative aliases that remain inside the staged tree.
+tools/dev/bun.sh tools/packaging/materialize-release-symlinks.mts "$stage"
+
+echo "==> Optimizing staged liboliphaunt $target_id release payload"
+tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts "$stage" --target "$target_id" --tool-set runtime
+
+
+bash tools/packaging/strip-native-binaries.sh --target "$target_id" "$stage"
+
+echo "==> Verifying staged $target_id binary compatibility"
+tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target_id" --root "$stage"
+
+tools/dev/bun.sh tools/packaging/release-notices.mts stage "$stage" --profile native-runtime
+
+tools/packaging/archive-directory.mts "$stage" "$out_dir/$asset"
+tools/dev/bun.sh tools/packaging/release-notices.mts check-archive "$out_dir/$asset" --profile native-runtime
+echo "liboliphauntLinuxReleaseAsset=$out_dir/$asset"
diff --git a/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-macos-assets.sh b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-macos-assets.sh
new file mode 100755
index 000000000..30faf2f52
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-macos-assets.sh
@@ -0,0 +1,99 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+source "$root/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh"
+
+fail() {
+  echo "package-liboliphaunt-macos-assets.sh: $*" >&2
+  exit 1
+}
+
+fetch_release_source_assets() {
+  if [ "${OLIPHAUNT_RELEASE_FETCH_ASSETS:-1}" = "0" ]; then
+    return 0
+  fi
+  echo "==> Fetching pinned source assets"
+  bash src/third-party/tools/fetch-sources.sh native-runtime >/tmp/liboliphaunt-release-macos-assets-fetch.log
+  if [ "${OLIPHAUNT_BUILD_EXTENSIONS:-0}" != 0 ]; then
+    bash src/third-party/tools/fetch-sources.sh extensions >>/tmp/liboliphaunt-release-macos-assets-fetch.log
+  fi
+}
+
+if [ "$(uname -s)" != "Darwin" ]; then
+  fail "macOS liboliphaunt release assets must be built on macOS"
+fi
+
+case "$(uname -m)" in
+  arm64|aarch64) target_id="macos-arm64" ;;
+  *) fail "unsupported macOS architecture $(uname -m)" ;;
+esac
+
+version="$(tools/dev/bun.sh tools/release/product-version.mts version liboliphaunt-native)"
+command -v bun >/dev/null 2>&1 || fail "missing required command: bun"
+out_dir="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS:-$root/target/liboliphaunt/release-assets}"
+stage_root="$root/target/liboliphaunt/release-stage-$target_id"
+work_root="${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18}"
+headers_dir="$root/src/runtimes/liboliphaunt-native/include"
+lib="$work_root/out/liboliphaunt.dylib"
+embedded_modules="$work_root/out/modules"
+runtime="$work_root/install"
+stage="$stage_root/liboliphaunt-${version}-${target_id}"
+asset="liboliphaunt-${version}-${target_id}.tar.gz"
+catalog_file="$stage_root/extension-catalog.tsv"
+
+rm -rf "$stage_root"
+mkdir -p "$out_dir" "$stage/include" "$stage/lib" "$stage/runtime"
+
+fetch_release_source_assets
+
+if [ "${OLIPHAUNT_RELEASE_BUILD_RUNTIME:-1}" = "1" ]; then
+  echo "==> Building liboliphaunt $target_id"
+  OLIPHAUNT_BUILD_EXTENSIONS="${OLIPHAUNT_BUILD_EXTENSIONS:-0}" \
+    src/runtimes/liboliphaunt-native/bin/build-postgres18-macos.sh >/tmp/liboliphaunt-release-"$target_id".log
+fi
+
+[ -f "$lib" ] || fail "missing macOS liboliphaunt dylib at $lib"
+oliphaunt_assert_base_embedded_modules_exact "$embedded_modules" dylib ||
+  fail "base $target_id embedded module inventory must contain only regular dict_snowball.dylib and plpgsql.dylib modules"
+for tool in initdb pg_ctl postgres; do
+  [ -x "$runtime/bin/$tool" ] || fail "missing macOS $tool at $runtime/bin/$tool"
+done
+
+echo "==> Verifying base liboliphaunt $target_id runtime is extension-clean"
+bun src/extensions/tools/native-extension-files.mts >"$catalog_file"
+oliphaunt_assert_base_runtime_has_no_optional_extensions "$catalog_file" "$runtime" ||
+  fail "base $target_id runtime must not ship optional extension assets"
+
+rsync -a --delete "$headers_dir/" "$stage/include/"
+cp "$lib" "$stage/lib/"
+rsync -a --delete "$embedded_modules/" "$stage/lib/modules/"
+rsync -a --delete \
+  --exclude '/bin/pg_dump' \
+  --exclude '/bin/pg_basebackup' \
+  --exclude '/bin/psql' \
+  --exclude 'share/icu/***' \
+  "$runtime/" "$stage/runtime/"
+# PostgreSQL installs versioned shared-library aliases as symlinks. Release
+# archives are link-free consumer inputs, so materialize only validated,
+# relative aliases that remain inside the staged tree.
+tools/dev/bun.sh tools/packaging/materialize-release-symlinks.mts "$stage"
+
+echo "==> Optimizing staged liboliphaunt $target_id release payload"
+tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts "$stage" --target "$target_id" --tool-set runtime
+
+
+bash tools/packaging/strip-native-binaries.sh --target "$target_id" "$stage"
+
+echo "==> Verifying staged $target_id binary compatibility"
+tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target_id" --root "$stage"
+
+tools/dev/bun.sh tools/packaging/release-notices.mts stage "$stage" --profile native-runtime
+
+tools/packaging/archive-directory.mts "$stage" "$out_dir/$asset"
+tools/dev/bun.sh tools/packaging/release-notices.mts check-archive "$out_dir/$asset" --profile native-runtime
+echo "liboliphauntMacosReleaseAsset=$out_dir/$asset"
diff --git a/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh
new file mode 100755
index 000000000..96b83f7fe
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh
@@ -0,0 +1,215 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+
+fail() {
+  echo "package-liboliphaunt-mobile-assets.sh: $*" >&2
+  exit 1
+}
+
+require() {
+  command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
+}
+
+source "$root/src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh"
+
+require cargo
+require bun
+require rsync
+
+target_id="${1:-}"
+case "$target_id" in
+  android-arm64-v8a|android-x86_64|ios-xcframework)
+    ;;
+  *)
+    fail "usage: src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh [android-arm64-v8a|android-x86_64|ios-xcframework]"
+    ;;
+esac
+
+version="$(tools/dev/bun.sh tools/release/product-version.mts version liboliphaunt-native)"
+out_dir="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS:-$root/target/liboliphaunt/release-assets}"
+stage_root="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_STAGE_ROOT:-$root/target/liboliphaunt/release-stage-$target_id}"
+headers_dir="$root/src/runtimes/liboliphaunt-native/include"
+
+rm -rf "$stage_root"
+mkdir -p "$out_dir" "$stage_root"
+
+archive_staged_dir() {
+  local staged="$1"
+  local profile="$2"
+  local name
+  name="$(basename "$staged")"
+  tools/packaging/archive-directory.mts "$staged" "$out_dir/${name}.tar.gz"
+  tools/dev/bun.sh tools/packaging/release-notices.mts check-archive \
+    "$out_dir/${name}.tar.gz" \
+    --profile "$profile"
+}
+
+archive_swiftpm_xcframework() {
+  local xcframework="$1"
+  local output="$2"
+  [ -d "$xcframework" ] || fail "missing SwiftPM XCFramework input at $xcframework"
+  rm -f "$output"
+  tools/dev/bun.sh tools/packaging/archive-directory.mts --keep-parent "$xcframework" "$output"
+}
+
+stage_runtime_resource_closure() {
+  local runtime="$1"
+  local seed_target="$2"
+  local stage="$3"
+
+  env \
+    OLIPHAUNT_INSTALL_DIR="$runtime" \
+    cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked -- \
+      --output "$stage" \
+      --force >/tmp/liboliphaunt-release-mobile-runtime-resources.log
+  local closure="$stage/oliphaunt"
+  [ -d "$closure/runtime/files" ] || fail "runtime-resource package did not create $closure/runtime/files"
+  tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/finalize-native-runtime-carrier.mts \
+    --root "$closure" \
+    --target "$seed_target"
+}
+
+package_android() {
+  local abi="$1"
+  local work_root="$2"
+  local lib="$work_root/out/liboliphaunt.so"
+  local static_registry="$work_root/out/liboliphaunt_mobile_static_registry.c"
+  local stage="$stage_root/liboliphaunt-${version}-android-${abi}"
+  local host_work_root="${OLIPHAUNT_LINUX_X64_ROOT:-$root/target/liboliphaunt-pg18-linux-x64-gnu}"
+  local host_runtime="$host_work_root/install"
+  local runtime_stage="$stage_root/liboliphaunt-${version}-runtime-resources-android-datum64"
+
+  [ -f "$lib" ] || fail "missing Android $abi liboliphaunt shared library at $lib"
+  [ ! -f "$static_registry" ] ||
+    fail "base Android $abi release asset must not include mobile static extension registry $static_registry"
+  [ -d "$host_runtime" ] || fail "missing native host runtime at $host_runtime"
+
+  tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts write \
+    --build-root "$work_root/postgresql-18.4" \
+    --target "$target_id" \
+    --output "$work_root/out/native-mobile-abi.properties"
+
+  mkdir -p "$stage/include" "$stage/jni/$abi"
+  rsync -a --delete "$headers_dir/" "$stage/include/"
+  cp "$lib" "$stage/jni/$abi/"
+  echo "==> Stripping staged liboliphaunt Android $abi release binaries"
+  bash tools/packaging/strip-native-binaries.sh --target "$target_id" "$stage"
+  echo "==> Verifying staged liboliphaunt Android $abi binary compatibility"
+  tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target_id" --root "$stage"
+  tools/dev/bun.sh tools/packaging/release-notices.mts stage \
+    "$stage" \
+    --profile native-runtime
+  archive_staged_dir "$stage" native-runtime
+  if [ "$target_id" = "android-x86_64" ]; then
+    stage_runtime_resource_closure \
+      "$host_runtime" \
+      android-datum64 \
+      "$runtime_stage"
+    tools/dev/bun.sh tools/packaging/release-notices.mts stage \
+      "$runtime_stage" \
+      --profile native-runtime-resources
+    archive_staged_dir "$runtime_stage" native-runtime-resources
+  fi
+}
+
+package_ios() {
+  local ios_work_root="${OLIPHAUNT_IOS_XCFRAMEWORK_ROOT:-$root/target/liboliphaunt-ios-xcframework}"
+  local macos_work_root="${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18}"
+  local ios_xcframework="$ios_work_root/out/liboliphaunt.xcframework"
+  local packaged_ios_work_root="$stage_root/packaged-ios-xcframework"
+  local packaged_ios_xcframework="$packaged_ios_work_root/out/liboliphaunt.xcframework"
+  local macos_runtime="$macos_work_root/install"
+  local catalog_file="$stage_root/extension-catalog.tsv"
+  local macos_runtime_stage="$stage_root/liboliphaunt-${version}-runtime-resources-macos-arm64"
+  local ios_runtime_stage="$stage_root/liboliphaunt-${version}-runtime-resources-ios-datum64"
+  local stage_ios="$stage_root/liboliphaunt-${version}-ios-xcframework"
+  local static_registry="$ios_work_root/out/liboliphaunt_mobile_static_registry.c"
+  local ios_device_receipt="${OLIPHAUNT_IOS_DEVICE_ROOT:-$root/target/liboliphaunt-ios-device}/out/native-mobile-abi.properties"
+  local ios_simulator_receipt="${OLIPHAUNT_IOS_SIMULATOR_ROOT:-$root/target/liboliphaunt-ios-simulator}/out/native-mobile-abi.properties"
+  local macos_producer_receipt="$ios_work_root/out/native-mobile-abi-producer.properties"
+
+  [ -d "$ios_xcframework" ] || fail "missing iOS XCFramework at $ios_xcframework"
+  [ -d "$macos_runtime" ] || fail "missing macOS PostgreSQL runtime at $macos_runtime"
+  [ ! -f "$static_registry" ] ||
+    fail "base iOS release asset must not include mobile static extension registry $static_registry"
+
+  bun src/extensions/tools/native-extension-files.mts >"$catalog_file"
+  oliphaunt_assert_base_runtime_has_no_optional_extensions "$catalog_file" "$macos_runtime" ||
+    fail "base iOS release runtime must not ship optional extension assets; selected extensions belong in exact extension artifacts"
+
+  tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts write \
+    --build-root "${OLIPHAUNT_IOS_DEVICE_ROOT:-$root/target/liboliphaunt-ios-device}/postgresql-18.4" \
+    --target ios-arm64 \
+    --output "$ios_device_receipt"
+  tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts write \
+    --build-root "${OLIPHAUNT_IOS_SIMULATOR_ROOT:-$root/target/liboliphaunt-ios-simulator}/postgresql-18.4" \
+    --target ios-arm64-simulator \
+    --output "$ios_simulator_receipt"
+  tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts write \
+    --build-root "$macos_work_root/postgresql-18.4" \
+    --target macos-arm64 \
+    --output "$macos_producer_receipt"
+  tools/dev/bun.sh src/runtimes/liboliphaunt-native/tools/native-mobile-abi-contract.mts compare \
+    --domain ios-datum64 \
+    --receipt "$ios_device_receipt" \
+    --receipt "$ios_simulator_receipt" \
+    --receipt "$macos_producer_receipt"
+
+  stage_runtime_resource_closure "$macos_runtime" macos-arm64 "$macos_runtime_stage"
+  stage_runtime_resource_closure "$macos_runtime" ios-datum64 "$ios_runtime_stage"
+  local ios_proof="$ios_runtime_stage/oliphaunt/provenance/native-mobile-abi"
+  mkdir -p "$ios_proof"
+  cp "$ios_device_receipt" "$ios_proof/ios-arm64.properties"
+  cp "$ios_simulator_receipt" "$ios_proof/ios-arm64-simulator.properties"
+  cp "$macos_producer_receipt" "$ios_proof/macos-arm64.properties"
+  OLIPHAUNT_MACOS_RUNTIME_RESOURCES_ROOT="$macos_runtime_stage/oliphaunt" \
+    OLIPHAUNT_IOS_RUNTIME_RESOURCES_ROOT="$ios_runtime_stage/oliphaunt" \
+    OLIPHAUNT_IOS_XCFRAMEWORK_ROOT="$packaged_ios_work_root" \
+    src/runtimes/liboliphaunt-native/bin/build-ios-xcframework.sh >/tmp/liboliphaunt-release-ios-xcframework-resources.log
+  mkdir -p "$stage_ios"
+  rsync -a --delete "$packaged_ios_xcframework" "$stage_ios/"
+  echo "==> Stripping staged liboliphaunt iOS release binaries"
+  bash tools/packaging/strip-native-binaries.sh --target "$target_id" "$stage_ios"
+  echo "==> Verifying staged liboliphaunt iOS binary compatibility"
+  tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target_id" --root "$stage_ios"
+
+  tools/dev/bun.sh tools/packaging/release-notices.mts stage \
+    "$stage_ios" \
+    --profile native-runtime
+  tools/dev/bun.sh tools/packaging/release-notices.mts stage \
+    "$stage_ios/liboliphaunt.xcframework" \
+    --profile native-runtime
+
+  archive_staged_dir "$stage_ios" native-runtime
+  archive_swiftpm_xcframework \
+    "$stage_ios/liboliphaunt.xcframework" \
+    "$out_dir/liboliphaunt-${version}-apple-spm-xcframework.zip"
+  tools/dev/bun.sh tools/packaging/release-notices.mts check-archive \
+    "$out_dir/liboliphaunt-${version}-apple-spm-xcframework.zip" \
+    --prefix liboliphaunt.xcframework \
+    --profile native-runtime
+  tools/dev/bun.sh tools/packaging/release-notices.mts stage \
+    "$ios_runtime_stage" \
+    --profile native-runtime-resources
+  archive_staged_dir "$ios_runtime_stage" native-runtime-resources
+}
+
+case "$target_id" in
+  android-arm64-v8a)
+    package_android arm64-v8a "${OLIPHAUNT_ANDROID_ARM64_ROOT:-$root/target/liboliphaunt-pg18-android-arm64}"
+    ;;
+  android-x86_64)
+    package_android x86_64 "${OLIPHAUNT_ANDROID_X86_64_ROOT:-$root/target/liboliphaunt-pg18-android-x86_64}"
+    ;;
+  ios-xcframework)
+    package_ios
+    ;;
+esac
+
+echo "liboliphauntMobileReleaseAssetDir=$out_dir"
diff --git a/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.test.sh b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.test.sh
new file mode 100644
index 000000000..b878f35c2
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.test.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+fixture="$(mktemp -d)"
+trap 'rm -rf "$fixture"' EXIT
+cd "$fixture"
+git init -q
+owner=src/runtimes/liboliphaunt-native
+mkdir -p "$owner/tools" "$owner/include" "$owner/bin" tools/dev tools/packaging bin
+cp "$root/$owner/tools/package-liboliphaunt-mobile-assets.sh" "$owner/tools/"
+printf 'oliphaunt_assert_base_runtime_has_no_optional_extensions() { return 0; }\n' >"$owner/tools/liboliphaunt-extension-guard.sh"
+export PATH="$fixture/bin:$PATH" CAPTURE="$fixture/calls"
+cat >bin/bun <<'STUB'
+#!/usr/bin/env bash
+set -euo pipefail
+case "$1" in
+  *product-version.mts) echo 1.2.3 ;;
+  *native-mobile-abi-contract.mts)
+    while [ "$#" -gt 0 ]; do
+      if [ "$1" = --output ]; then mkdir -p "$(dirname "$2")"; echo receipt >"$2"; break; fi
+      shift
+    done ;;
+  *finalize-native-runtime-carrier.mts) printf '%s\n' "$*" >>"$CAPTURE" ;;
+esac
+STUB
+cat >bin/cargo <<'STUB'
+#!/usr/bin/env bash
+set -euo pipefail
+while [ "$#" -gt 0 ]; do
+  if [ "$1" = --output ]; then mkdir -p "$2/oliphaunt/runtime/files"; break; fi
+  shift
+done
+STUB
+cat >bin/rsync <<'STUB'
+#!/usr/bin/env bash
+cp -R "$3" "$4"
+STUB
+printf '#!/usr/bin/env bash\nbun "$@"\n' >tools/dev/bun.sh
+printf '#!/usr/bin/env bash\nexit 0\n' >tools/packaging/archive-directory.mts
+cp tools/packaging/archive-directory.mts tools/packaging/strip-native-binaries.sh
+cat >"$owner/bin/build-ios-xcframework.sh" <<'STUB'
+#!/usr/bin/env bash
+set -euo pipefail
+test -d "$OLIPHAUNT_MACOS_RUNTIME_RESOURCES_ROOT/runtime/files"
+test -f "$OLIPHAUNT_IOS_RUNTIME_RESOURCES_ROOT/provenance/native-mobile-abi/ios-arm64.properties"
+mkdir -p "$OLIPHAUNT_IOS_XCFRAMEWORK_ROOT/out/liboliphaunt.xcframework"
+STUB
+chmod +x bin/* tools/dev/* tools/packaging/* "$owner/bin/"*
+mkdir -p target/liboliphaunt-ios-xcframework/out/liboliphaunt.xcframework target/liboliphaunt-pg18/install
+bash "$owner/tools/package-liboliphaunt-mobile-assets.sh" ios-xcframework
+grep -F -- '--target macos-arm64' "$CAPTURE"
+grep -F -- '--target ios-datum64' "$CAPTURE"
+echo 'iOS runtime resource packaging dispatch verified.'
diff --git a/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-windows-assets.sh b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-windows-assets.sh
new file mode 100644
index 000000000..a51fee485
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-windows-assets.sh
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+root="$PWD"
+fail() { echo "package-liboliphaunt-windows-assets.sh: $*" >&2; exit 1; }
+case "$(uname -s)" in MINGW*|MSYS*) ;; *) fail 'Windows release assets require Windows' ;; esac
+source src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.sh
+
+version="$(bun tools/release/product-version.mts version liboliphaunt-native)"
+target_id=windows-x64-msvc
+out_dir="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS:-$root/target/liboliphaunt/release-assets}"
+work_root="${OLIPHAUNT_WINDOWS_WORK_ROOT:-${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18-$target_id}}"
+# Native callers may supply drive-letter paths; normalize once for Git Bash tools.
+out_dir="$(cygpath -u "$out_dir")"
+work_root="$(cygpath -u "$work_root")"
+stage_root="$root/target/liboliphaunt/release-stage-$target_id"
+stage="$stage_root/liboliphaunt-$version-$target_id"
+runtime="$work_root/install"
+modules="$work_root/out/modules"
+asset="$out_dir/liboliphaunt-$version-$target_id.zip"
+
+if [ "${OLIPHAUNT_RELEASE_FETCH_ASSETS:-1}" != 0 ]; then
+  bash src/third-party/tools/fetch-sources.sh native-runtime
+fi
+if [ "${OLIPHAUNT_RELEASE_BUILD_RUNTIME:-1}" != 0 ]; then
+  OLIPHAUNT_CI_TARGET="$target_id" bash src/runtimes/liboliphaunt-native/tools/release-runtime.sh build
+fi
+for file in out/bin/oliphaunt.dll out/lib/oliphaunt.lib out/bin/icudt76.dll out/bin/icuin76.dll out/bin/icuuc76.dll install/bin/initdb.exe install/bin/pg_ctl.exe install/bin/postgres.exe; do
+  [ -f "$work_root/$file" ] || fail "missing Windows build output $work_root/$file"
+done
+oliphaunt_assert_base_embedded_modules_exact "$modules" dll
+rm -rf "$stage_root"
+mkdir -p "$out_dir" "$stage"/{include,bin,lib/modules,runtime}
+bun src/extensions/tools/native-extension-files.mts >"$stage_root/extension-catalog.tsv"
+oliphaunt_assert_base_runtime_has_no_optional_extensions "$stage_root/extension-catalog.tsv" "$runtime"
+
+cp -R src/runtimes/liboliphaunt-native/include/. "$stage/include/"
+cp "$work_root/out/bin/oliphaunt.dll" "$work_root/out/bin/"{icudt76,icuin76,icuuc76}.dll "$stage/bin/"
+cp "$work_root/out/lib/oliphaunt.lib" "$stage/lib/"
+cp -R "$modules/." "$stage/lib/modules/"
+cp -R "$runtime/." "$stage/runtime/"
+bun tools/packaging/windows-vc-runtime-closure.mts stage \
+  --root "$stage" --source-dir "$work_root/out/bin" --profile provider \
+  --destination "$stage/bin" --destination "$stage/runtime/bin"
+rm -f "$stage/runtime/bin/"{pg_basebackup,pg_dump,psql}.exe
+rm -rf "$stage/runtime/share/icu"
+bun src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts "$stage" --target "$target_id" --tool-set runtime
+bash tools/packaging/strip-native-binaries.sh --target "$target_id" "$stage"
+bun tools/packaging/platform-binary-contract.mts --target "$target_id" --root "$stage" \
+  --require-windows-runtime-import-library --windows-vc-runtime-profile provider
+bun tools/packaging/release-notices.mts stage "$stage" --profile native-runtime
+bun tools/packaging/archive-directory.mts "$stage" "$asset"
+bun tools/packaging/release-notices.mts check-archive "$asset" --profile native-runtime
+echo "liboliphauntWindowsReleaseAsset=$asset"
diff --git a/src/runtimes/liboliphaunt-native/tools/release-runtime.sh b/src/runtimes/liboliphaunt-native/tools/release-runtime.sh
new file mode 100755
index 000000000..0c8f780ab
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/release-runtime.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+mode="${1:-}"
+target="${OLIPHAUNT_CI_TARGET:-}"
+case "$(uname -s):$target" in
+  Darwin:macos-arm64|Darwin:) platform=macos ;;
+  Linux:linux-arm64-gnu|Linux:linux-x64-gnu|Linux:) platform=linux ;;
+  MINGW*:windows-x64-msvc|MSYS*:windows-x64-msvc|MINGW*:|MSYS*:) platform=windows ;;
+  *) echo "unsupported native runtime host/target: $(uname -s)/$target" >&2; exit 2 ;;
+esac
+case "$mode" in
+  build)
+    [ "$platform" != macos ] || export OLIPHAUNT_BUILD_EXTENSIONS="${OLIPHAUNT_BUILD_EXTENSIONS-0}"
+    script="src/runtimes/liboliphaunt-native/bin/build-postgres18-$platform"
+    ;;
+  package)
+    . src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+    target="${target:-$(oliphaunt_runtime_native_host_target_id)}"
+    export OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS="target/liboliphaunt/desktop-release-assets/$target"
+    export OLIPHAUNT_RELEASE_BUILD_RUNTIME=0 OLIPHAUNT_RELEASE_FETCH_ASSETS=0
+    script="src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-$platform-assets"
+    ;;
+  *) echo 'usage: release-runtime.sh build|package' >&2; exit 2 ;;
+esac
+exec bash "$script.sh"
diff --git a/src/runtimes/liboliphaunt-native/tools/run-host-c-smoke.sh b/src/runtimes/liboliphaunt-native/tools/run-host-c-smoke.sh
new file mode 100755
index 000000000..dda450447
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/run-host-c-smoke.sh
@@ -0,0 +1,247 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+cd "$root"
+abi_only=0
+smoke_only=0
+cluster_seeds=0
+root_arg=''
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --abi-only) abi_only=1 ;;
+    --smoke-only) smoke_only=1 ;;
+    --cluster-seeds) cluster_seeds=1 ;;
+    --root)
+      root_arg="${2:?--root requires a directory}"
+      shift
+      ;;
+    -h | --help)
+      echo 'usage: run-host-c-smoke.sh [--abi-only|--smoke-only] [--cluster-seeds] [--root DIR]'
+      exit 0
+      ;;
+    -*)
+      echo "unknown argument: $1" >&2
+      exit 2
+      ;;
+    *)
+      [ -z "$root_arg" ] || exit 2
+      root_arg="$1"
+      ;;
+  esac
+  shift
+done
+if [ "$abi_only" = 1 ] && { [ "$smoke_only" = 1 ] || [ "$cluster_seeds" = 1 ]; }; then
+  echo '--abi-only cannot be combined with --smoke-only or --cluster-seeds' >&2
+  exit 2
+fi
+case "$(uname -s):$(uname -m)" in
+  Darwin:arm64 | Darwin:aarch64)
+    platform=macos
+    target=macos-arm64
+    ;;
+  Darwin:x86_64)
+    platform=macos
+    target=macos-x64
+    ;;
+  Linux:x86_64 | Linux:amd64)
+    platform=linux
+    target=linux-x64-gnu
+    ;;
+  Linux:aarch64 | Linux:arm64)
+    platform=linux
+    target=linux-arm64-gnu
+    ;;
+  MINGW*:x86_64 | MSYS*:x86_64 | CYGWIN*:x86_64)
+    platform=windows
+    target=windows-x64-msvc
+    ;;
+  *)
+    echo 'unsupported native smoke host' >&2
+    exit 2
+    ;;
+esac
+absolute() {
+  if [ "$platform" = windows ]; then
+    cygpath -au "$1"
+  else case "$1" in /*) printf '%s\n' "$1" ;; *) printf '%s/%s\n' "$root" "$1" ;; esac fi
+}
+native_path() {
+  if [ "$platform" = windows ]; then cygpath -am "$1"; else printf '%s\n' "$1"; fi
+}
+require_file() { [ -f "$1" ] || {
+  echo "missing required file: $1" >&2
+  exit 1
+}; }
+work_root="$root/target/liboliphaunt-pg18-$target"
+[ "$platform" != macos ] || work_root="$root/target/liboliphaunt-pg18"
+work_root="$(absolute "${OLIPHAUNT_WORK_ROOT:-$work_root}")"
+install_dir="$(absolute "${OLIPHAUNT_INSTALL_DIR:-$work_root/install}")"
+exe_suffix=''
+case "$platform" in
+  windows)
+    library="$work_root/out/bin/oliphaunt.dll"
+    exe_suffix=.exe
+    ;;
+  macos) library="$work_root/out/liboliphaunt.dylib" ;;
+  linux) library="$work_root/out/liboliphaunt.so" ;;
+esac
+library="$(absolute "${LIBOLIPHAUNT_PATH:-$library}")"
+library_dir="$(dirname "$library")"
+out_dir="$library_dir"
+[ "$platform" != windows ] || out_dir="$(dirname "$library_dir")"
+bin_dir="$(absolute "${OLIPHAUNT_SMOKE_BIN_DIR:-$library_dir}")"
+initdb="$(absolute "${OLIPHAUNT_INITDB:-$install_dir/bin/initdb$exe_suffix}")"
+postgres="$(absolute "${OLIPHAUNT_POSTGRES:-$install_dir/bin/postgres$exe_suffix}")"
+pg_version="$(bun src/runtimes/liboliphaunt-native/tools/native-smoke-data.mts postgres-version)"
+build_dir="$work_root/postgresql-$pg_version"
+include_dir="$root/src/runtimes/liboliphaunt-native/include"
+source_dir="$root/src/runtimes/liboliphaunt-native/src"
+smoke_dir="$root/src/runtimes/liboliphaunt-native/smoke"
+require_file "$library"
+mkdir -p "$bin_dir"
+printf 'liboliphaunt host target: %s\nliboliphaunt work root: %s\n' "$target" "$work_root" >&2
+
+msvc_env_file=''
+cluster_root=''
+remove_icu=0
+smoke_failure_root=''
+cleanup() {
+  [ -z "$msvc_env_file" ] || rm -f "$msvc_env_file"
+  [ -z "$cluster_root" ] || rm -rf "$cluster_root"
+  [ "$remove_icu" = 0 ] || rm -rf "$install_dir/share/icu"
+  [ -z "$smoke_failure_root" ] || printf 'native smoke root: %s\n' "$smoke_failure_root" >&2
+  return 0
+}
+trap cleanup EXIT
+if [ "$platform" = windows ] && ! command -v cl.exe >/dev/null; then
+  program_files="$(printenv 'ProgramFiles(x86)')"
+  vswhere="$(cygpath -u "$program_files")/Microsoft Visual Studio/Installer/vswhere.exe"
+  require_file "$vswhere"
+  vs_root="$("$vswhere" -latest -products '*' -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath)"
+  vs_root="${vs_root%$'\r'}"
+  [ -n "$vs_root" ] || {
+    echo 'Visual Studio Build Tools were not found' >&2
+    exit 1
+  }
+  vs_command="$(cygpath -aw "$vs_root/Common7/Tools/VsDevCmd.bat")"
+  msvc_env_file="$(mktemp)"
+  MSYS2_ARG_CONV_EXCL='*' cmd.exe /d /s /c "call \"$vs_command\" -arch=x64 -host_arch=x64 >nul && set" >"$msvc_env_file"
+  while IFS='=' read -r name value; do
+    value="${value%$'\r'}"
+    case "$name" in
+      PATH | Path)
+        PATH="$(cygpath -up "$value")"
+        export PATH
+        ;;
+      INCLUDE | LIB | LIBPATH) export "$name=$value" ;;
+    esac
+  done <"$msvc_env_file"
+  command -v cl.exe >/dev/null
+fi
+case "$platform" in
+  windows) export PATH="$library_dir:$install_dir/bin:$PATH" ;;
+  macos) export DYLD_LIBRARY_PATH="$library_dir:$install_dir/lib:${DYLD_LIBRARY_PATH:-}" ;;
+  linux) export LD_LIBRARY_PATH="$library_dir:$install_dir/lib:${LD_LIBRARY_PATH:-}" ;;
+esac
+LIBOLIPHAUNT_PATH="$(native_path "$library")"
+OLIPHAUNT_INSTALL_DIR="$(native_path "$install_dir")"
+OLIPHAUNT_POSTGRES="$(native_path "$postgres")"
+export LIBOLIPHAUNT_PATH OLIPHAUNT_INSTALL_DIR OLIPHAUNT_POSTGRES
+export OLIPHAUNT_STREAM_QUEUE_MAX_BYTES="${OLIPHAUNT_STREAM_QUEUE_MAX_BYTES:-4096}"
+compile() {
+  local kind="$1" name="$2" output="$bin_dir/$2$exe_suffix"
+  local source="$smoke_dir/$name.c" include
+  local includes=() flags=() compiler=() prefix=()
+  if [ "$name" = liboliphaunt_smoke ]; then
+    includes=("$source_dir" "$build_dir/src/include" "$work_root/meson-embedded/src/include" "$install_dir/include")
+    [ "$platform" != windows ] || includes+=("$build_dir/src/include/port/win32")
+  fi
+  if [ "$platform" = windows ]; then
+    require_file "$out_dir/lib/oliphaunt.lib"
+    flags=("/I$(native_path "$include_dir")")
+    for include in ${includes[@]+"${includes[@]}"}; do flags+=("/I$(native_path "$include")"); done
+    MSYS2_ARG_CONV_EXCL='*' cl.exe /nologo /std:c11 /Zi /MD /D_CRT_SECURE_NO_WARNINGS /DWIN32_LEAN_AND_MEAN \
+      "${flags[@]}" "$(native_path "$source")" /link "/LIBPATH:$(native_path "$out_dir/lib")" oliphaunt.lib "/OUT:$(native_path "$output")"
+  else
+    if [ "$kind" = abi ]; then
+      read -r -a compiler <<<"${OLIPHAUNT_ABI_CC:-cc}"
+      flags+=(-pedantic)
+    else read -r -a compiler <<<"${OLIPHAUNT_SMOKE_CC:-cc}"; fi
+    case "${OLIPHAUNT_CCACHE:-auto}" in
+      0 | off) ;;
+      auto) if command -v ccache >/dev/null; then prefix=(ccache); fi ;;
+      *) prefix=("$OLIPHAUNT_CCACHE") ;;
+    esac
+    for include in ${includes[@]+"${includes[@]}"}; do flags+=(-I "$include"); done
+    ${prefix[@]+"${prefix[@]}"} "${compiler[@]}" -std=c11 -Wall -Wextra -Werror -O0 -g -I "$include_dir" \
+      ${flags[@]+"${flags[@]}"} "$source" -L "$library_dir" "-Wl,-rpath,$library_dir" -pthread -loliphaunt -o "$output"
+  fi
+}
+if [ "$smoke_only" = 0 ]; then
+  compile abi liboliphaunt_abi_conformance
+  "$bin_dir/liboliphaunt_abi_conformance$exe_suffix"
+fi
+[ "$abi_only" = 0 ] || exit 0
+require_file "$initdb"
+require_file "$postgres"
+compile smoke liboliphaunt_smoke
+if [ -n "$root_arg" ]; then
+  smoke_root="$(absolute "$root_arg")"
+else
+  scratch="$(absolute "${OLIPHAUNT_SMOKE_ROOT:-$work_root}")"
+  mkdir -p "$scratch"
+  smoke_root="$(mktemp -d "$scratch/smoke.XXXXXX")"
+fi
+smoke_failure_root="$smoke_root"
+if [ ! -e "$smoke_root/.oliphaunt.json" ]; then
+  if [ ! -d "$smoke_root" ] || [ -n "$(ls -A "$smoke_root")" ]; then
+    echo "native smoke root is nonempty or missing: $smoke_root" >&2
+    exit 1
+  fi
+  OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY=1 OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY=1 \
+    "$initdb" -D "$(native_path "$smoke_root/pgdata")" -U postgres --auth=trust --no-sync --locale-provider=libc --locale=C --encoding=UTF8
+  bun src/runtimes/liboliphaunt-native/tools/native-smoke-data.mts managed-root "$smoke_root"
+fi
+archive_fixture="$root/src/runtimes/liboliphaunt-native/smoke/fixtures/physical-archive-native-v1.properties"
+require_file "$archive_fixture"
+for _attempt in 1 2; do
+  "$bin_dir/liboliphaunt_smoke$exe_suffix" "$(native_path "$smoke_root/pgdata")" "$(native_path "$install_dir")" "$(native_path "$archive_fixture")"
+done
+smoke_failure_root=''
+[ -n "$root_arg" ] || rm -rf "$smoke_root"
+[ "$cluster_seeds" = 1 ] || exit 0
+standard_seed="$(absolute "${OLIPHAUNT_STANDARD_CLUSTER_SEED:?standard cluster seed is required}")"
+icu_seed="$(absolute "${OLIPHAUNT_ICU_CLUSTER_SEED:?ICU cluster seed is required}")"
+icu_data="$(absolute "${OLIPHAUNT_ICU_DATA_DIR:?ICU data is required}")"
+compile smoke liboliphaunt_cluster_seed_smoke
+cluster_root="$(mktemp -d)"
+if [ ! -e "$install_dir/share/icu" ]; then
+  mkdir -p "$install_dir/share"
+  remove_icu=1
+  cp -R "$icu_data" "$install_dir/share/icu"
+fi
+for profile in standard icu; do
+  seed="$standard_seed"
+  [ "$profile" != icu ] || seed="$icu_seed"
+  mkdir "$cluster_root/$profile"
+  cp -R "$seed/files" "$cluster_root/$profile/pgdata"
+  chmod 700 "$cluster_root/$profile/pgdata"
+  bun src/runtimes/liboliphaunt-native/tools/native-smoke-data.mts managed-root "$cluster_root/$profile"
+  probe="$(bun src/runtimes/liboliphaunt-native/tools/native-smoke-data.mts profile "$profile")"
+  sql="${probe%$'\n'*}"
+  expected="${probe##*$'\n'}"
+  for _attempt in 1 2; do
+    env -u OLIPHAUNT_ICU_DATA_DIR ICU_DATA=/ambient/unverified-icu \
+      "$bin_dir/liboliphaunt_cluster_seed_smoke$exe_suffix" "$(native_path "$cluster_root/$profile/pgdata")" "$(native_path "$install_dir")" "$sql" "$expected"
+  done
+done
+mkdir "$cluster_root/standard-icu-import"
+cp -R "$standard_seed/files" "$cluster_root/standard-icu-import/pgdata"
+chmod 700 "$cluster_root/standard-icu-import/pgdata"
+bun src/runtimes/liboliphaunt-native/tools/native-smoke-data.mts managed-root "$cluster_root/standard-icu-import"
+for _attempt in 1 2; do
+  ICU_DATA=/ambient/unverified-icu OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY=1 \
+    "$bin_dir/liboliphaunt_cluster_seed_smoke$exe_suffix" "$(native_path "$cluster_root/standard-icu-import/pgdata")" "$(native_path "$install_dir")" \
+    "SELECT pg_import_system_collations('pg_catalog'); SELECT CASE WHEN EXISTS (SELECT 1 FROM pg_collation WHERE collname LIKE '%-x-icu') THEN 'OLIPHAUNT_ICU_IMPORT_OK' ELSE 'OLIPHAUNT_ICU_IMPORT_MISSING' END" OLIPHAUNT_ICU_IMPORT_OK
+done
+printf 'native standard and ICU cluster seeds passed open, catalog, close, and reopen qualification\n' >&2
diff --git a/src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh b/src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh
rename to src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
diff --git a/src/runtimes/liboliphaunt-native/tools/test-desktop-artifact.sh b/src/runtimes/liboliphaunt-native/tools/test-desktop-artifact.sh
new file mode 100755
index 000000000..c0ed56fae
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/test-desktop-artifact.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+cd "$root"
+case "$(uname -s):$(uname -m)" in
+  Linux:x86_64 | Linux:amd64)
+    target=linux-x64-gnu
+    library=lib/liboliphaunt.so
+    ;;
+  Linux:aarch64 | Linux:arm64)
+    target=linux-arm64-gnu
+    library=lib/liboliphaunt.so
+    ;;
+  Darwin:arm64 | Darwin:aarch64)
+    target=macos-arm64
+    library=lib/liboliphaunt.dylib
+    ;;
+  MINGW*:x86_64 | MSYS*:x86_64)
+    target=windows-x64-msvc
+    library=bin/oliphaunt.dll
+    ;;
+  *)
+    echo 'Unsupported native artifact test host' >&2
+    exit 2
+    ;;
+esac
+if [ -n "${OLIPHAUNT_CI_TARGET:-}" ] && [ "$OLIPHAUNT_CI_TARGET" != "$target" ]; then
+  echo "Cannot execute $OLIPHAUNT_CI_TARGET artifacts on $target" >&2
+  exit 2
+fi
+version="$(bun tools/release/product-version.mts version liboliphaunt-native)"
+asset_dir="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS:-$root/target/liboliphaunt/desktop-release-assets/$target}"
+work_root="${OLIPHAUNT_WORK_ROOT:-}"
+case "$target" in
+  linux-*) work_root="${OLIPHAUNT_LINUX_WORK_ROOT:-$work_root}" ;;
+  windows-*)
+    work_root="${OLIPHAUNT_WINDOWS_WORK_ROOT:-$work_root}"
+    asset_dir="$(cygpath -u "$asset_dir")"
+    ;;
+esac
+extension=tar.gz
+[ "$target" != windows-x64-msvc ] || extension=zip
+archive="$asset_dir/liboliphaunt-$version-$target.$extension"
+test_root="$root/target/liboliphaunt/artifact-test-$target"
+stage="$test_root/package"
+rm -rf "$test_root"
+mkdir -p "$stage"
+if [ "$extension" = zip ]; then
+  unzip -q "$archive" -d "$stage"
+else
+  tar -xzf "$archive" -C "$stage"
+fi
+case "$target" in
+  linux-*) bash tools/packaging/check-linux-consumer-baseline.sh --target "$target" --root "$stage" ;;
+esac
+env OLIPHAUNT_WORK_ROOT="$work_root" LIBOLIPHAUNT_PATH="$stage/$library" OLIPHAUNT_INSTALL_DIR="$stage/runtime" \
+  OLIPHAUNT_SMOKE_BIN_DIR="$test_root/bin" OLIPHAUNT_SMOKE_ROOT="$test_root/databases" \
+  bash src/runtimes/liboliphaunt-native/tools/run-host-c-smoke.sh
diff --git a/src/runtimes/liboliphaunt/native/tools/test-error-attribution.sh b/src/runtimes/liboliphaunt-native/tools/test-error-attribution.sh
similarity index 92%
rename from src/runtimes/liboliphaunt/native/tools/test-error-attribution.sh
rename to src/runtimes/liboliphaunt-native/tools/test-error-attribution.sh
index 90e9dcbd3..0c73ed4ea 100644
--- a/src/runtimes/liboliphaunt/native/tools/test-error-attribution.sh
+++ b/src/runtimes/liboliphaunt-native/tools/test-error-attribution.sh
@@ -9,7 +9,7 @@ case "$(uname -s)" in
     ;;
 esac
 
-source_root="$repo_root/src/runtimes/liboliphaunt/native"
+source_root="$repo_root/src/runtimes/liboliphaunt-native"
 scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-error-attribution.XXXXXX")
 trap 'rm -rf "$scratch"' EXIT
 
diff --git a/src/runtimes/liboliphaunt/native/tools/test-generation-lifecycle.sh b/src/runtimes/liboliphaunt-native/tools/test-generation-lifecycle.sh
similarity index 94%
rename from src/runtimes/liboliphaunt/native/tools/test-generation-lifecycle.sh
rename to src/runtimes/liboliphaunt-native/tools/test-generation-lifecycle.sh
index 7d735e6aa..422964135 100755
--- a/src/runtimes/liboliphaunt/native/tools/test-generation-lifecycle.sh
+++ b/src/runtimes/liboliphaunt-native/tools/test-generation-lifecycle.sh
@@ -2,7 +2,7 @@
 set -euo pipefail
 
 root="$(git rev-parse --show-toplevel)"
-source_root="$root/src/runtimes/liboliphaunt/native"
+source_root="$root/src/runtimes/liboliphaunt-native"
 work_root="$root/target/liboliphaunt-generation-lifecycle-test"
 
 platform_lib=
diff --git a/src/runtimes/liboliphaunt-native/tools/test-module-dir-resolver.sh b/src/runtimes/liboliphaunt-native/tools/test-module-dir-resolver.sh
new file mode 100644
index 000000000..4ec130831
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/test-module-dir-resolver.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root=$(git rev-parse --show-toplevel)
+case "$(uname -s)" in
+  MINGW*|MSYS*|CYGWIN*)
+    echo "liboliphaunt module-dir resolver test is covered by the Linux/macOS C lanes"
+    exit 0
+    ;;
+esac
+
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-module-dir-test.XXXXXX")
+trap 'rm -rf "$scratch"' EXIT
+
+compiler=${CC:-cc}
+linker_arg=
+if [[ "$(uname -s)" == Linux ]]; then
+  linker_arg=-ldl
+fi
+
+"$compiler" \
+  -std=c11 \
+  -Wall \
+  -Wextra \
+  -Werror \
+  -I "$root/src/runtimes/liboliphaunt-native/include" \
+  -I "$root/src/runtimes/liboliphaunt-native/src" \
+  "$root/src/runtimes/liboliphaunt-native/smoke/liboliphaunt_module_dir_resolver.c" \
+  "$root/src/runtimes/liboliphaunt-native/src/liboliphaunt_fs.c" \
+  ${linker_arg:+"$linker_arg"} \
+  -o "$scratch/liboliphaunt_module_dir_resolver"
+
+mkdir "$scratch/fixture"
+"$scratch/liboliphaunt_module_dir_resolver" "$scratch/fixture"
diff --git a/src/runtimes/liboliphaunt-native/tools/test-packaging.sh b/src/runtimes/liboliphaunt-native/tools/test-packaging.sh
new file mode 100644
index 000000000..bd0f276e1
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/test-packaging.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "$0")/../../../.."
+tests=()
+shell_tests=(src/runtimes/liboliphaunt-native/tools/liboliphaunt-extension-guard.test.sh src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.test.sh)
+for file in src/runtimes/liboliphaunt-native/tools/*.test.mts; do
+  if [[ -f "${file%.mts}.sh" ]]; then
+    shell_tests+=("${file%.mts}.sh")
+  else
+    tests+=("./$file")
+  fi
+done
+bun test --timeout=30000 "${tests[@]}"
+for file in "${shell_tests[@]}"; do bash "$file"; done
diff --git a/src/runtimes/liboliphaunt/native/tools/test-static-extension-registry.sh b/src/runtimes/liboliphaunt-native/tools/test-static-extension-registry.sh
similarity index 93%
rename from src/runtimes/liboliphaunt/native/tools/test-static-extension-registry.sh
rename to src/runtimes/liboliphaunt-native/tools/test-static-extension-registry.sh
index 1f2bc8b65..1fd5895f6 100755
--- a/src/runtimes/liboliphaunt/native/tools/test-static-extension-registry.sh
+++ b/src/runtimes/liboliphaunt-native/tools/test-static-extension-registry.sh
@@ -9,7 +9,7 @@ case "$(uname -s)" in
     ;;
 esac
 
-source_root="$root/src/runtimes/liboliphaunt/native"
+source_root="$root/src/runtimes/liboliphaunt-native"
 scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-static-extension-registry.XXXXXX")
 trap 'rm -rf "$scratch"' EXIT
 
diff --git a/src/runtimes/liboliphaunt/native/tools/test-symbol-scope.sh b/src/runtimes/liboliphaunt-native/tools/test-symbol-scope.sh
similarity index 99%
rename from src/runtimes/liboliphaunt/native/tools/test-symbol-scope.sh
rename to src/runtimes/liboliphaunt-native/tools/test-symbol-scope.sh
index fba7b205b..391f92986 100755
--- a/src/runtimes/liboliphaunt/native/tools/test-symbol-scope.sh
+++ b/src/runtimes/liboliphaunt-native/tools/test-symbol-scope.sh
@@ -2,7 +2,7 @@
 set -euo pipefail
 
 root="$(git rev-parse --show-toplevel)"
-source_root="$root/src/runtimes/liboliphaunt/native"
+source_root="$root/src/runtimes/liboliphaunt-native"
 work_root="$root/target/liboliphaunt-symbol-scope-test"
 macos_module_nm_audit="$source_root/tools/audit-macos-module-nm.awk"
 macos_provider_collision_audit="$source_root/tools/audit-macos-provider-collisions.awk"
diff --git a/tools/test/native-runtime-fixture.mjs b/src/runtimes/liboliphaunt-native/tools/testdata/native-runtime-fixture.mts
similarity index 100%
rename from tools/test/native-runtime-fixture.mjs
rename to src/runtimes/liboliphaunt-native/tools/testdata/native-runtime-fixture.mts
diff --git a/src/runtimes/liboliphaunt-native/tools/validate-ios-carrier-zips.mts b/src/runtimes/liboliphaunt-native/tools/validate-ios-carrier-zips.mts
new file mode 100644
index 000000000..69dc47771
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/validate-ios-carrier-zips.mts
@@ -0,0 +1,137 @@
+#!/usr/bin/env bun
+
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import {
+  DEFAULT_PORTABLE_ARCHIVE_LIMITS,
+  readPortableArchiveEntries,
+} from '../../../../tools/packaging/portable-archive.mts';
+
+const PREFIX = 'validate-ios-carrier-zips.mts';
+const XCFRAMEWORK_ROOT = /^[A-Za-z0-9][A-Za-z0-9._-]*[.]xcframework$/u;
+// Match the shipped Apple carrier envelope. The shared verifier processes one
+// expanded ZIP member at a time, so the logical aggregate bound does not become
+// a same-sized in-memory allocation.
+const IOS_ZIP_LIMITS = Object.freeze({
+  format: 'zip',
+  maxArchiveBytes: 512 * 1024 * 1024,
+  maxEntries: DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntries,
+  maxEntryBytes: 1024 * 1024 * 1024,
+  maxExpandedBytes: 4 * 1024 * 1024 * 1024,
+});
+
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+async function regularDirectory(directory, label) {
+  let stat;
+  try {
+    stat = await fs.lstat(directory);
+  } catch (error) {
+    if (error?.code === 'ENOENT') fail(`${label} does not exist: ${directory}`);
+    throw error;
+  }
+  if (!stat.isDirectory() || stat.isSymbolicLink()) {
+    fail(`${label} must be a real directory: ${directory}`);
+  }
+}
+
+async function zipFiles(root) {
+  const files = [];
+  const pending = [root];
+  while (pending.length > 0) {
+    const directory = pending.pop();
+    const entries = await fs.readdir(directory, { withFileTypes: true });
+    entries.sort((left, right) => compareText(left.name, right.name));
+    for (const entry of entries) {
+      const file = path.join(directory, entry.name);
+      if (entry.isSymbolicLink()) {
+        fail(`carrier root contains a symbolic link: ${path.relative(root, file)}`);
+      }
+      if (entry.isDirectory()) {
+        pending.push(file);
+      } else if (entry.isFile()) {
+        if (entry.name.endsWith('.zip')) files.push(file);
+        else if (entry.name.toLowerCase().endsWith('.zip')) {
+          fail(
+            `ZIP carrier names must use the canonical lowercase suffix: ${path.relative(root, file)}`,
+          );
+        }
+      } else {
+        fail(`carrier root contains an unsupported filesystem entry: ${path.relative(root, file)}`);
+      }
+    }
+  }
+  files.sort((left, right) => compareText(path.relative(root, left), path.relative(root, right)));
+  if (files.length === 0) fail(`found no ZIP carriers under ${root}`);
+  return files;
+}
+
+function validateCarrierEntries(entries, archive) {
+  const roots = new Set([...entries.keys()].map((name) => name.split('/', 1)[0]));
+  if (roots.size !== 1) {
+    fail(
+      `${archive} must contain exactly one top-level XCFramework root; found ${[...roots].sort(compareText).join(',')}`,
+    );
+  }
+  const [root] = roots;
+  if (!XCFRAMEWORK_ROOT.test(root) || root === '.' || root === '..') {
+    fail(`${archive} has unsafe or non-XCFramework top-level root ${JSON.stringify(root)}`);
+  }
+  if (entries.get(root)?.isDirectory !== true) {
+    fail(`${archive} does not materialize ${root} as a directory`);
+  }
+  if (entries.get(`${root}/Info.plist`)?.isFile !== true) {
+    fail(`${archive} XCFramework root lacks a regular Info.plist`);
+  }
+  return root;
+}
+
+export async function validateIosCarrierZipRoot(root) {
+  const carrierRoot = path.resolve(root);
+  await regularDirectory(carrierRoot, 'carrier root');
+  const archives = await zipFiles(carrierRoot);
+  const validated = [];
+  for (const archive of archives) {
+    const entries = readPortableArchiveEntries(archive, IOS_ZIP_LIMITS);
+    validated.push({
+      archive,
+      framework: validateCarrierEntries(entries, archive),
+    });
+  }
+  return validated;
+}
+
+function parseArgs(argv) {
+  if (argv.includes('--help') || argv.includes('-h')) {
+    console.log('usage: validate-ios-carrier-zips.mts --root DIRECTORY');
+    return null;
+  }
+  if (argv.length !== 2 || argv[0] !== '--root' || argv[1].length === 0) {
+    fail('usage: validate-ios-carrier-zips.mts --root DIRECTORY');
+  }
+  return { root: argv[1] };
+}
+
+async function main() {
+  const args = parseArgs(process.argv.slice(2));
+  if (args === null) return;
+  const rows = await validateIosCarrierZipRoot(args.root);
+  console.log(
+    `${PREFIX}: validated ${rows.length} iOS XCFramework ZIP carrier(s) under ${path.resolve(args.root)}`,
+  );
+}
+
+if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
+  main().catch((error) => {
+    console.error(error instanceof Error ? error.stack : String(error));
+    process.exit(1);
+  });
+}
diff --git a/src/runtimes/liboliphaunt-native/tools/validate-ios-carrier-zips.test.mts b/src/runtimes/liboliphaunt-native/tools/validate-ios-carrier-zips.test.mts
new file mode 100644
index 000000000..24dc31302
--- /dev/null
+++ b/src/runtimes/liboliphaunt-native/tools/validate-ios-carrier-zips.test.mts
@@ -0,0 +1,67 @@
+import { afterEach, test } from 'bun:test';
+import assert from 'node:assert/strict';
+import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { archiveDirectory } from '../../../../tools/packaging/archive-directory.mts';
+import { validateIosCarrierZipRoot } from './validate-ios-carrier-zips.mts';
+
+const roots = [];
+afterEach(() => {
+  for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true });
+});
+function fixture() {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-ios-carriers-'));
+  roots.push(root);
+  mkdirSync(path.join(root, 'carriers'));
+  return root;
+}
+async function makeCarrier(root, relativeArchive, frameworkName) {
+  const framework = path.join(root, 'source', relativeArchive.replaceAll('/', '-'), frameworkName);
+  mkdirSync(path.join(framework, 'ios-arm64', 'libFixture.framework'), { recursive: true });
+  writeFileSync(path.join(framework, 'Info.plist'), '\n');
+  writeFileSync(
+    path.join(framework, 'ios-arm64', 'libFixture.framework', 'libFixture'),
+    'fixture-binary\n',
+  );
+  const archive = path.join(root, 'carriers', relativeArchive);
+  mkdirSync(path.dirname(archive), { recursive: true });
+  await archiveDirectory(framework, archive, { keepParent: true });
+}
+
+test('validates recursively produced XCFramework ZIP carriers', async () => {
+  const root = fixture();
+  await makeCarrier(root, 'nested/base.zip', 'liboliphaunt.xcframework');
+  await makeCarrier(root, 'extensions/vector.zip', 'liboliphaunt_extension_vector.xcframework');
+  const rows = await validateIosCarrierZipRoot(path.join(root, 'carriers'));
+  assert.deepEqual(rows.map(({ framework }) => framework).sort(), [
+    'liboliphaunt.xcframework',
+    'liboliphaunt_extension_vector.xcframework',
+  ]);
+});
+test('rejects an empty producer output', async () => {
+  await assert.rejects(
+    validateIosCarrierZipRoot(path.join(fixture(), 'carriers')),
+    /found no ZIP carriers/u,
+  );
+});
+test('rejects a non-XCFramework member in an otherwise valid producer set', async () => {
+  const root = fixture();
+  await makeCarrier(root, 'a-valid.zip', 'liboliphaunt.xcframework');
+  await makeCarrier(root, 'z-invalid.zip', 'not-a-framework');
+  await assert.rejects(
+    validateIosCarrierZipRoot(path.join(root, 'carriers')),
+    /z-invalid[.]zip has unsafe or non-XCFramework top-level root/u,
+  );
+});
+test('rejects carrier-root symlinks', async () => {
+  const root = fixture();
+  await makeCarrier(root, 'valid.zip', 'liboliphaunt.xcframework');
+  const outside = path.join(root, 'outside.zip');
+  writeFileSync(outside, 'not a carrier\n');
+  symlinkSync(outside, path.join(root, 'carriers', 'linked.zip'));
+  await assert.rejects(
+    validateIosCarrierZipRoot(path.join(root, 'carriers')),
+    /carrier root contains a symbolic link: linked[.]zip/u,
+  );
+});
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/.gitattributes b/src/runtimes/liboliphaunt-wasix-postmaster/.gitattributes
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/.gitattributes
rename to src/runtimes/liboliphaunt-wasix-postmaster/.gitattributes
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/.gitignore b/src/runtimes/liboliphaunt-wasix-postmaster/.gitignore
new file mode 100644
index 000000000..cda3f0bfb
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/.gitignore
@@ -0,0 +1,13 @@
+/build/
+/builds/
+/install/
+/reports/
+/run/
+/tools/sealed-export-closure/target/
+/work/
+*.a
+*.dylib
+*.log
+*.o
+*.so
+*.wasm
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/CHANGELOG.md b/src/runtimes/liboliphaunt-wasix-postmaster/CHANGELOG.md
new file mode 100644
index 000000000..415aca04b
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/CHANGELOG.md
@@ -0,0 +1,17 @@
+# Changelog
+
+## 0.1.0 (2026-09-05)
+
+
+### ⚠ BREAKING CHANGES
+
+
+### Features
+
+* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
+
+
+### Code Refactoring
+
+* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
+* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/README.md b/src/runtimes/liboliphaunt-wasix-postmaster/README.md
new file mode 100644
index 000000000..98d3012d0
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/README.md
@@ -0,0 +1,150 @@
+# liboliphaunt WASIX Postmaster
+
+The [executor](executor/README.md) has its own Cargo manifest and lockfile.
+After `moon run liboliphaunt-wasix-postmaster:prepare-runtime`, it builds and
+tests directly from that directory without copying source into Wasmer.
+
+`liboliphaunt-wasix-postmaster` is the concurrent PostgreSQL 18 runtime for
+WASIX. One PostgreSQL postmaster accepts connections and starts isolated WASIX
+backend processes that coordinate through PostgreSQL shared memory.
+
+This is a release product. Its release identity, version, source pins, build,
+sealed carrier, verification, and qualification tasks are owned by this
+directory. The existing `liboliphaunt-wasix` runtime remains the lightweight
+single-backend product; applications select the topology that fits their
+workload without changing PostgreSQL protocol semantics.
+
+## Release targets
+
+Release carriers are published as level-19 Zstandard `.tar.zst` archives for
+`linux-arm64-gnu`, `linux-x64-gnu`, and `macos-arm64`, matching the normal
+WASIX carrier format. Each published carrier contains:
+
+- the compiler-free postmaster executor;
+- `initdb`, `postgres`, and every side module declared by
+  `wasmer/policies/sealed-side-modules.v1.tsv`;
+- receipt-bound AOT artifacts for every admitted executable module;
+- PostgreSQL support files, build receipts, a complete payload inventory, and
+  the sealed manifest.
+
+Each carrier is fail-closed: the verifier rejects missing, unexpected, renamed,
+symlinked, special, or modified payloads, an incompatible runtime ABI, a
+mismatched producer recipe, and undeclared modules. Platform support is a
+release target claim, not an inference from Wasmer portability. Additional
+targets are added only with an artifact target, CI builder, and consumer smoke.
+
+## Run the release carrier
+
+Download and extract the release archive matching the host, then start a local
+cluster through its supported launcher:
+
+```sh
+./bin/oliphaunt-wasix-postmaster start --data-dir "$PWD/pgdata"
+```
+
+The launcher initializes an empty directory with the `postgres` superuser,
+prints `postgresql://postgres@127.0.0.1:5432/postgres`, and keeps PostgreSQL in
+the foreground. It binds only to loopback unless `--allow-remote` is explicit.
+Use `--port`, repeated `--guc name=value`, and `--username` to configure the
+cluster without depending on the repository's build scripts. Send SIGTERM for
+a clean shutdown. The archive is self-contained; it does not compile or fetch
+code when it starts.
+
+## Build and verify
+
+Run the focused source and product checks:
+
+```sh
+moon run liboliphaunt-wasix-postmaster:lint
+```
+
+Build the pinned runtime and PostgreSQL guest, then construct the sealed
+carrier:
+
+```sh
+moon run liboliphaunt-wasix-postmaster:runtime-build
+moon run liboliphaunt-wasix-postmaster:postgres-build
+moon run liboliphaunt-wasix-postmaster:carrier
+```
+
+Verify an existing carrier independently:
+
+```sh
+src/runtimes/liboliphaunt-wasix-postmaster/bin/verify-sealed-headless-carrier.sh \
+  target/oliphaunt-wasix-postmaster/carriers/
+```
+
+Build outputs, fetched sources, caches, and qualification results stay under
+`target/oliphaunt-wasix-postmaster/`. Nothing generated is admitted as a
+release asset unless it was built from the exact release commit and passes the
+product verifier and lifecycle qualification.
+
+PostgreSQL builds and sealing passes use a private install directory. Only
+after the complete generation, including its build and ABI receipts, is ready
+does the producer publish it and atomically update the profile's `.current`
+selection file. Readers resolve that selection once; an interrupted rebuild
+cannot change the directory they are using. Existing generations are retained.
+The separate portable-input archive preserves its fixed internal install path;
+an explicit `WASIX_INSTALL_DIR` with portable-input mode selects those exact
+imported bytes without rebuilding or rewriting them.
+
+After extracting the portable-input archive into the work root, select its
+install directory explicitly, including when that checkout already has a local
+`.current` selection:
+
+```sh
+OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS=1 \
+WASIX_INSTALL_DIR="$PWD/target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3" \
+  src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.sh
+```
+
+Linux release qualification additionally requires immutable-inode activation
+and cgroup-v2 memory controls. macOS uses runtime-owned private AOT and memory
+image copies because Linux immutable-inode and cgroup primitives do not exist
+there; qualification proves the copy/hash byte accounting, forbids carrier
+source writes and sync calls, and runs the same backend-wave and crash-recovery
+campaign.
+
+## Architecture boundary
+
+The launcher's `--data-dir` is a raw PostgreSQL PGDATA directory. It is not an
+Oliphaunt SDK managed root and does not participate in the single-backend
+WASIX root or physical-backup contracts.
+
+PostgreSQL is built with `EXEC_BACKEND`. The postmaster uses the WASIX process
+and exec syscalls to create a fresh Wasmer instance for each backend. The child
+restores PostgreSQL's serialized backend parameters and reattaches the
+postmaster's shared-memory segment at the original guest address.
+
+```text
+native supervisor and compiler-free WASIX executor
+  PostgreSQL postmaster.wasm
+    TCP listener + PostgreSQL shared memory
+      |
+      +-- vfork + execv --> isolated backend.wasm instance
+      +-- vfork + execv --> isolated backend.wasm instance
+```
+
+The postmaster guest deliberately does not consume the single-backend patches
+that remove concurrent observers, workers, process creation, or PostgreSQL's
+normal spinlock/atomic behavior. Compatible PostgreSQL optimizations are
+referenced from the canonical WASIX product where possible; postmaster-only
+concurrency patches remain local and are justified in
+`postgres/product-patch-provenance.toml`.
+
+Maintainer architecture, failure semantics, performance interpretation, and
+the durable conclusions from product development are documented in
+`src/docs/maintainers/wasix-postmaster.md`. Product source contains only build,
+runtime, packaging, verification, and qualification machinery.
+
+## Release contract
+
+- Product id and tag prefix: `liboliphaunt-wasix-postmaster` and
+  `liboliphaunt-wasix-postmaster-v`.
+- The source version remains `0.0.0` until the first generated release PR.
+- `release.toml`, Moon release metadata, Release Please, and the release asset
+  task describe the same product.
+- A release is valid only when the exact release commit produced and verified
+  the carrier later attached to its GitHub release.
+- The checksum manifest uses the same canonical release-asset contract as the
+  single-backend WASIX product and covers every published carrier exactly.
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/VERSION b/src/runtimes/liboliphaunt-wasix-postmaster/VERSION
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/VERSION
rename to src/runtimes/liboliphaunt-wasix-postmaster/VERSION
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/apply-wasix-core-overlay.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/apply-wasix-core-overlay.sh
similarity index 80%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/apply-wasix-core-overlay.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/apply-wasix-core-overlay.sh
index 1c0f701db..b244fd1e2 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/apply-wasix-core-overlay.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/apply-wasix-core-overlay.sh
@@ -57,38 +57,8 @@ fresh_unlock_postgres_baseline
 
 cp -R "$FRESH_ROOT/postgres/overlays/wasix-core/." "$WASIX_SRC_DIR/"
 
-apply_patch_series() {
-  local patches_dir="$1"
-  local series_file="$2"
-  local patch
-  local patch_name
-
-  [ -f "$series_file" ] && [ ! -L "$series_file" ] || {
-    echo "missing regular PostgreSQL patch series: $series_file" >&2
-    exit 2
-  }
-  while IFS= read -r patch_name || [ -n "$patch_name" ]; do
-    case "$patch_name" in
-      ''|'#'*) continue ;;
-      */*)
-        echo "unsafe PostgreSQL patch entry: $patch_name" >&2
-        exit 2
-        ;;
-    esac
-    patch="$patches_dir/$patch_name"
-    [ -f "$patch" ] && [ ! -L "$patch" ] || {
-      echo "missing regular PostgreSQL patch from series: $patch" >&2
-      exit 2
-    }
-    git -C "$WASIX_SRC_DIR" apply --whitespace=nowarn "$patch"
-  done <"$series_file"
-}
-
-apply_patch_series "$FRESH_ROOT/postgres/patches" \
-  "$FRESH_ROOT/postgres/patches/series"
-apply_patch_series \
-  "$REPO_ROOT/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches" \
-  "$FRESH_ROOT/postgres/main-optimizations.series"
+bash "$REPO_ROOT/src/third-party/postgres/apply-series.sh" \
+  "$WASIX_SRC_DIR" "$FRESH_ROOT/postgres/series"
 
 worktree_state="$(
   fresh_git_worktree_state_sha256 "$WASIX_SRC_DIR" ".fresh-wasix-core-signature"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-native-client-tools.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-native-client-tools.sh
similarity index 87%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/build-native-client-tools.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/build-native-client-tools.sh
index 113379496..6fab3c03f 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-native-client-tools.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-native-client-tools.sh
@@ -27,6 +27,10 @@ until mkdir "$lock_dir" 2>/dev/null; do
   sleep 0.2
 done
 cleanup() {
+  local status=$?
+  if [ "$status" -ne 0 ] && [ -f "${log:-}" ]; then
+    tail -n 80 "$log" >&2
+  fi
   fresh_unlock_postgres_baseline || true
   rmdir "$lock_dir" 2>/dev/null || true
 }
@@ -63,7 +67,8 @@ configure_args=(
 
 source_signature="$(
   {
-    printf 'build_signature_version=3\n'
+    printf 'build_signature_version=4\n'
+    shasum -a 256 "$0"
     printf 'baseline_fingerprint=%s\n' "$baseline_fingerprint"
     printf 'baseline=%s\n' "$baseline_head"
     printf 'baseline_tree=%s\n' "$baseline_tree"
@@ -105,8 +110,14 @@ fresh_require_managed_generated_path "$CLIENT_TOOLS_INSTALL_DIR" CLIENT_TOOLS_IN
   if [ ! -f config.status ]; then
     "$BASELINE_DIR/configure" "${configure_args[@]}"
   fi
-  make -j "$jobs"
-  make install
+  # Only psql and pg_regress are consumed by Postmaster qualification.
+  make -C src/backend generated-headers
+  # psql's recursive dependencies otherwise race to generate pg_config_paths.h.
+  make -C src/bin/psql -j "$jobs" submake-libpgfeutils
+  make -C src/bin/psql -j "$jobs"
+  make -C src/interfaces/libpq install
+  make -C src/bin/psql install
+  make -C src/test/regress -j "$jobs" pg_regress
 ) >"$log" 2>&1
 
 {
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-sealed-headless-carrier.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-sealed-headless-carrier.sh
new file mode 100755
index 000000000..ef4313cad
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-sealed-headless-carrier.sh
@@ -0,0 +1,596 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+wasix_core_profile_explicit=0
+if [ "${WASIX_CORE_PROFILE+x}" = x ] && [ -n "$WASIX_CORE_PROFILE" ]; then
+  wasix_core_profile_explicit=1
+fi
+source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/common.sh"
+source "$FRESH_ROOT/lib/sealed-carrier.sh"
+
+usage() {
+  cat <<'EOF'
+Usage: build-sealed-headless-carrier.sh [options]
+
+Build an atomic, compiler-free WASIX PostgreSQL carrier from an already
+validated runtime receipt and precompiled AOT cache.
+
+Options:
+  --output DIR              Final carrier directory (must not already exist).
+                            By default, publish below the work-root carriers
+                            directory under the exact payload-inventory digest.
+  --install-dir DIR         WASIX PostgreSQL prefix (default: WASIX_INSTALL_DIR)
+  --postmaster-compiler FILE
+                            Receipt-bound bounded-memory LLVM producer
+  --postmaster-executor FILE
+                            Product-specific sealed-postmaster executor
+  --postmaster-executor-receipt FILE
+                            Exact product executor build receipt
+  --cache-bucket DIR        Exact precompiled AOT bucket
+  --receipt FILE            Canonical Wasmer build receipt
+  -h, --help                Show this help
+
+The builder never compiles implicitly and never accepts host-native CPU AOT.
+EOF
+}
+
+fail() {
+  printf 'sealed carrier build: %s\n' "$*" >&2
+  exit 2
+}
+
+output=""
+install_dir="$WASIX_INSTALL_DIR"
+postmaster_compiler="$FRESH_POSTMASTER_COMPILER_BIN"
+postmaster_executor="$FRESH_POSTMASTER_EXECUTOR_BIN"
+postmaster_executor_receipt="$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
+receipt="${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}"
+cache_bucket=""
+
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --output|--install-dir|--postmaster-compiler|--postmaster-executor|--postmaster-executor-receipt|--cache-bucket|--receipt)
+      option="$1"
+      shift
+      [ "$#" -gt 0 ] || fail "$option requires a value"
+      case "$option" in
+        --output) output="$1" ;;
+        --install-dir) install_dir="$1" ;;
+        --postmaster-compiler) postmaster_compiler="$1" ;;
+        --postmaster-executor) postmaster_executor="$1" ;;
+        --postmaster-executor-receipt) postmaster_executor_receipt="$1" ;;
+        --cache-bucket) cache_bucket="$1" ;;
+        --receipt) receipt="$1" ;;
+      esac
+      ;;
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    *)
+      fail "unknown argument: $1"
+      ;;
+  esac
+  shift
+done
+
+selected_executor="$postmaster_executor"
+
+fresh_require_command bun
+carrier_data="$FRESH_ROOT/lib/build-sealed-carrier.mts"
+fresh_require_command cp
+fresh_require_command find
+fresh_require_command sort
+
+[ "$wasix_core_profile_explicit" -eq 1 ] || {
+  fail 'WASIX_CORE_PROFILE must be explicit for a sealed qualification carrier'
+}
+core_profile="$(fresh_normalize_wasix_core_profile "$WASIX_CORE_PROFILE")" || exit
+case "$core_profile" in
+  release-o3) ;;
+  *)
+    fail "sealed qualification carriers require a release-o3 guest with a qualified final fence inventory, got: $core_profile"
+    ;;
+esac
+
+fresh_require_patched_postmaster_compiler \
+  "$postmaster_compiler" \
+  "$postmaster_executor_receipt" \
+  "$receipt" \
+  "$postmaster_executor"
+fresh_require_patched_postmaster_executor \
+  "$selected_executor" "$postmaster_executor_receipt" "$receipt"
+
+runtime_abi_id="$(fresh_manifest_value "$receipt" runtime_abi_id)"
+output_is_explicit=1
+if [ -n "$output" ]; then
+  case "$output" in
+    */.|*/..|.|..|/) fail "unsafe output directory: $output" ;;
+  esac
+  output_parent_input="$(dirname "$output")"
+  output_name="$(basename "$output")"
+  [ -n "$output_name" ] || fail "output directory has no basename: $output"
+  case "$output_name" in
+    *$'\n'*|*$'\r'*|*$'\t'*) fail "output directory basename contains a control delimiter" ;;
+  esac
+else
+  # The complete payload identity is unavailable until manifest.json and the
+  # exact inventory have been generated.  Keep unpublished construction in a
+  # generic, private staging name and resolve the public path immediately
+  # before the atomic rename.  This prevents two PostgreSQL build profiles
+  # with the same runtime ABI from colliding at the old default path.
+  output_is_explicit=0
+  output_parent_input="$FRESH_WORK_ROOT/carriers"
+  output_name="wasix-postmaster-$POSTGRES_VERSION-${runtime_abi_id:0:16}-unpublished"
+fi
+mkdir -p "$output_parent_input"
+output_parent="$(cd "$output_parent_input" && pwd -P)"
+if [ "$output_is_explicit" -eq 1 ]; then
+  output="$output_parent/$output_name"
+  [ ! -e "$output" ] && [ ! -L "$output" ] || fail "output already exists: $output"
+fi
+
+[ -d "$install_dir" ] && [ ! -L "$install_dir" ] || fail "missing regular WASIX install prefix: $install_dir"
+install_dir="$(cd "$install_dir" && pwd -P)"
+guest_build_receipt_source="$install_dir/guest-build.receipt"
+[ -f "$guest_build_receipt_source" ] && [ ! -L "$guest_build_receipt_source" ] || {
+  fail "missing regular guest build receipt: $guest_build_receipt_source"
+}
+bun "$carrier_data" guest-receipt "$install_dir" "$core_profile" "$POSTGRES_TAG" \
+  "$POSTGRES_VERSION" "$WASIXCC_SYSROOT_VARIANT"
+final_wasm_concurrency_receipt_source="$install_dir/share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt"
+[ -f "$final_wasm_concurrency_receipt_source" ] && \
+  [ ! -L "$final_wasm_concurrency_receipt_source" ] || {
+  fail "missing regular final Wasm concurrency receipt: $final_wasm_concurrency_receipt_source"
+}
+expected_final_wasm_concurrency_receipt_sha256="$(
+  fresh_manifest_value "$guest_build_receipt_source" \
+    final_wasm_concurrency_receipt_sha256
+)"
+actual_final_wasm_concurrency_receipt_sha256="$(
+  fresh_wasmer_bin_hash "$final_wasm_concurrency_receipt_source"
+)"
+[ "$actual_final_wasm_concurrency_receipt_sha256" = \
+  "$expected_final_wasm_concurrency_receipt_sha256" ] || {
+  fail 'final Wasm concurrency receipt differs from guest build receipt'
+}
+linear_memory_receipt_relative="share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
+linear_memory_receipt_source="$install_dir/$linear_memory_receipt_relative"
+[ -f "$linear_memory_receipt_source" ] && [ ! -L "$linear_memory_receipt_source" ] || {
+  fail "missing regular linear-memory install receipt: $linear_memory_receipt_source"
+}
+linear_memory_install_receipt_sha256="$(fresh_wasmer_bin_hash "$linear_memory_receipt_source")"
+fresh_is_sha256 "$linear_memory_install_receipt_sha256" ||
+  fail 'linear-memory install receipt identity is invalid'
+[ "$(fresh_manifest_value "$guest_build_receipt_source" linear_memory_profile_id)" = \
+  "$FRESH_LINEAR_MEMORY_PROFILE_ID" ] || {
+  fail 'guest build receipt linear-memory profile differs'
+}
+[ "$(fresh_manifest_value "$guest_build_receipt_source" linear_memory_install_receipt_sha256)" = \
+  "$linear_memory_install_receipt_sha256" ] || {
+  fail 'linear-memory install receipt differs from guest build receipt'
+}
+expected_atomic_fence_total="$(
+  fresh_manifest_value "$guest_build_receipt_source" atomic_fence_total
+)"
+bun "$FRESH_ROOT/wasmer/bin/verify-postmaster-concurrency-contract.mts" \
+  --expected-total "$expected_atomic_fence_total" \
+  --latch-state-contract packed-atomic-v1 \
+  --verified-receipt "$final_wasm_concurrency_receipt_source" \
+  --receipt-only \
+  "$install_dir/bin/postgres" >/dev/null || {
+  fail 'final Wasm concurrency receipt contract validation failed'
+}
+guest_build_recipe_sha256="$(fresh_wasmer_bin_hash "$guest_build_receipt_source")"
+fresh_is_sha256 "$guest_build_recipe_sha256" || fail 'invalid guest build recipe identity'
+guest_installed_closure_sha256="$(
+  fresh_manifest_value "$guest_build_receipt_source" installed_closure_sha256
+)"
+fresh_is_sha256 "$guest_installed_closure_sha256" || {
+  fail 'invalid guest installed closure identity'
+}
+actual_guest_installed_closure_sha256="$(
+  bun "$FRESH_ROOT/lib/guest-build-provenance.mts" identity "$install_dir"
+)" || exit
+[ "$actual_guest_installed_closure_sha256" = \
+  "$guest_installed_closure_sha256" ] || {
+  fail 'guest install bytes differ from their build receipt'
+}
+share_source="$install_dir/share/postgresql"
+[ -d "$share_source" ] && [ ! -L "$share_source" ] || fail "missing PostgreSQL support tree: $share_source"
+
+compiler="$(fresh_wasmer_compiler)"
+llvm_opt_level=aggressive
+runtime_stack_size="${WASMER_STACK_SIZE:-33554432}"
+case "$runtime_stack_size" in
+  ''|*[!0-9]*) fail "WASMER_STACK_SIZE must be a positive integer" ;;
+esac
+[ "$runtime_stack_size" -gt 0 ] || fail "WASMER_STACK_SIZE must be greater than zero"
+compiler_config="$(fresh_wasmer_compiler_cache_bucket \
+  "$compiler" "$llvm_opt_level" "$FRESH_WASMER_ARTIFACT_ABI_VERSION")"
+[ -z "${FRESH_PINNED_WASMER_CACHE_DIR:-}" ] || {
+  fail "sealed product carriers refuse pinned or foreign AOT cache roots: $FRESH_PINNED_WASMER_CACHE_DIR"
+}
+expected_cache_bucket="$(fresh_wasmer_cache_dir "$postmaster_compiler")/compiled/$compiler_config"
+if [ -z "$cache_bucket" ]; then
+  cache_bucket="$expected_cache_bucket"
+fi
+[ -d "$cache_bucket" ] && [ ! -L "$cache_bucket" ] || fail "missing regular AOT cache bucket: $cache_bucket"
+cache_bucket="$(cd "$cache_bucket" && pwd -P)"
+[ -d "$expected_cache_bucket" ] && [ ! -L "$expected_cache_bucket" ] || {
+  fail "missing receipt-bound AOT cache bucket: $expected_cache_bucket"
+}
+expected_cache_bucket="$(cd "$expected_cache_bucket" && pwd -P)"
+[ "$cache_bucket" = "$expected_cache_bucket" ] || {
+  fail "AOT cache bucket is not bound to the selected producer: expected $expected_cache_bucket, got $cache_bucket"
+}
+
+side_module_policy="$FRESH_ROOT/wasmer/policies/sealed-side-modules.v1.tsv"
+[ -f "$side_module_policy" ] && [ ! -L "$side_module_policy" ] || {
+  fail "missing regular sealed side-module policy: $side_module_policy"
+}
+
+required_modules=(
+  bin/initdb
+  bin/postgres
+)
+while IFS=$'\t' read -r relative aliases abi_policy extra; do
+  case "$relative" in
+    ""|'#'*) continue ;;
+  esac
+  [ -z "${extra:-}" ] && [ -n "${aliases:-}" ] && [ -n "${abi_policy:-}" ] || {
+    fail "invalid sealed side-module policy row: $relative"
+  }
+  case "$relative" in
+    lib/*.so|lib/*.so.*|lib/postgresql/*.so) ;;
+    *) fail "invalid sealed side-module path: $relative" ;;
+  esac
+  required_modules+=("$relative")
+done <"$side_module_policy"
+[ "${#required_modules[@]}" -gt 2 ] || fail "sealed side-module policy is empty"
+for relative in "${required_modules[@]}"; do
+  source_path="$install_dir/$relative"
+  [ -f "$source_path" ] && [ ! -L "$source_path" ] || fail "missing regular runtime-closure module: $source_path"
+done
+if find "$share_source" -type l -print -quit | grep -q .; then
+  fail "PostgreSQL support tree contains a symbolic link: $share_source"
+fi
+if find "$share_source" ! -type d ! -type f -print -quit | grep -q .; then
+  fail "PostgreSQL support tree contains a special file: $share_source"
+fi
+
+staging="$(mktemp -d "$output_parent/.${output_name}.tmp.XXXXXX")"
+validation_root=""
+chmod 0755 "$staging"
+cleanup_validation_root() {
+  if [ -n "${validation_root:-}" ] && [ -d "$validation_root" ]; then
+    chmod -R u+w "$validation_root" 2>/dev/null || true
+    rm -rf -- "$validation_root"
+  fi
+  validation_root=""
+}
+cleanup() {
+  cleanup_validation_root
+  if [ -n "${staging:-}" ] && [ -d "$staging" ]; then
+    chmod -R u+w "$staging" 2>/dev/null || true
+    rm -rf -- "$staging"
+  fi
+}
+handle_signal() {
+  local status="$1"
+  trap - EXIT HUP INT TERM
+  cleanup
+  exit "$status"
+}
+trap cleanup EXIT
+trap 'handle_signal 129' HUP
+trap 'handle_signal 130' INT
+trap 'handle_signal 143' TERM
+
+mkdir -p \
+  "$staging/bin" \
+  "$staging/lib/postgresql" \
+  "$staging/share/postgresql" \
+  "$staging/aot"
+cp -p "$selected_executor" "$staging/bin/wasmer-headless"
+chmod 0555 "$staging/bin/wasmer-headless"
+cp -pR "$share_source/." "$staging/share/postgresql/"
+
+artifact_rows="$staging/.artifact-rows.tsv"
+: >"$artifact_rows"
+
+copy_artifact() {
+  local name="$1"
+  local kind="$2"
+  local relative="$3"
+  local alias="$4"
+  local module_source="$install_dir/$relative"
+  local module_sha256
+  local module_hash
+  local artifact_source
+  local artifact_relative
+  local artifact_sha256
+  local module_size
+  local artifact_size
+
+  module_sha256="$(fresh_wasmer_bin_hash "$module_source")"
+  fresh_is_sha256 "$module_sha256" || fail "invalid module digest: $module_source"
+  module_hash="$(printf '%s' "$module_sha256" | tr '[:lower:]' '[:upper:]')"
+  artifact_source="$cache_bucket/$module_hash.bin"
+  [ -f "$artifact_source" ] && [ ! -L "$artifact_source" ] && [ -s "$artifact_source" ] || {
+    fail "missing regular precompiled AOT artifact for $relative: $artifact_source"
+  }
+
+  mkdir -p "$staging/$(dirname "$relative")"
+  cp -p "$module_source" "$staging/$relative"
+  artifact_relative="aot/$module_hash.bin"
+  cp -p "$artifact_source" "$staging/$artifact_relative"
+  chmod 0444 "$staging/$artifact_relative"
+  "$postmaster_compiler" verify-aot \
+    "$staging/$relative" "$staging/$artifact_relative" >/dev/null || {
+    fail "AOT artifact failed product compiler admission: $relative"
+  }
+
+  artifact_sha256="$(fresh_wasmer_bin_hash "$staging/$artifact_relative")"
+  module_size="$(wc -c <"$staging/$relative" | tr -d '[:space:]')"
+  artifact_size="$(wc -c <"$staging/$artifact_relative" | tr -d '[:space:]')"
+  [ "$module_sha256" = "$(fresh_wasmer_bin_hash "$staging/$relative")" ] || {
+    fail "module changed while copying: $module_source"
+  }
+  [ "$artifact_sha256" = "$(fresh_wasmer_bin_hash "$artifact_source")" ] || {
+    fail "AOT artifact changed while copying: $artifact_source"
+  }
+
+  printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
+    "$name" "$kind" "$artifact_relative" "$relative" "$artifact_sha256" \
+    "$artifact_size" "$module_sha256" "$module_size" "$alias" >>"$artifact_rows"
+}
+
+copy_artifact runtime:initdb executable bin/initdb /bin/initdb
+copy_artifact runtime:postgres executable bin/postgres /bin/postgres
+while IFS=$'\t' read -r relative aliases abi_policy extra; do
+  case "$relative" in
+    ""|'#'*) continue ;;
+  esac
+  artifact_name="runtime:${relative##*/}"
+  copy_artifact "$artifact_name" side-module "$relative" ""
+
+  # Dynamic-loader aliases are policy, not ad-hoc carrier knowledge. Keep each
+  # alias as a regular byte-identical file because sealed paths reject symlinks.
+  if [ "$aliases" != - ]; then
+    old_ifs="$IFS"
+    IFS=','
+    for alias_relative in $aliases; do
+      IFS="$old_ifs"
+      case "$alias_relative" in
+        lib/*.so|lib/*.so.*|lib/postgresql/*.so) ;;
+        *) fail "invalid sealed side-module alias: $alias_relative" ;;
+      esac
+      [ ! -e "$staging/$alias_relative" ] || {
+        fail "duplicate sealed side-module alias: $alias_relative"
+      }
+      mkdir -p "$staging/$(dirname "$alias_relative")"
+      cp -p "$staging/$relative" "$staging/$alias_relative"
+      IFS=','
+    done
+    IFS="$old_ifs"
+  fi
+done <"$side_module_policy"
+
+if find "$staging" -type l -print -quit | grep -q .; then
+  fail "staged carrier contains a symbolic link"
+fi
+if find "$staging" ! -type d ! -type f -print -quit | grep -q .; then
+  fail "staged carrier contains a special file"
+fi
+
+sealed_receipt="$staging/wasmer-build.receipt"
+cp -p "$receipt" "$sealed_receipt"
+chmod 0444 "$sealed_receipt"
+sealed_postmaster_executor_receipt="$staging/postmaster-executor.receipt"
+cp -p "$postmaster_executor_receipt" "$sealed_postmaster_executor_receipt"
+chmod 0444 "$sealed_postmaster_executor_receipt"
+sealed_product_build_receipt="$sealed_postmaster_executor_receipt"
+guest_build_receipt="$staging/guest-build.receipt"
+cp -p "$guest_build_receipt_source" "$guest_build_receipt"
+chmod 0444 "$guest_build_receipt"
+[ "$(fresh_wasmer_bin_hash "$guest_build_receipt")" = \
+  "$guest_build_recipe_sha256" ] || {
+  fail 'guest build receipt changed while packaging the carrier'
+}
+staged_guest_installed_closure_sha256="$(
+  bun "$FRESH_ROOT/lib/guest-build-provenance.mts" identity "$staging"
+)" || exit
+[ "$staged_guest_installed_closure_sha256" = \
+  "$guest_installed_closure_sha256" ] || {
+  fail 'staged guest bytes differ from their build receipt'
+}
+actual_guest_installed_closure_sha256="$(
+  bun "$FRESH_ROOT/lib/guest-build-provenance.mts" identity "$install_dir"
+)" || exit
+[ "$actual_guest_installed_closure_sha256" = \
+  "$guest_installed_closure_sha256" ] || {
+  fail 'guest install changed while the carrier was staged'
+}
+
+# From this point onward, derive every manifest identity from the immutable
+# carrier snapshot, not from a mutable external pathname. Revalidating both
+# binaries against that snapshot also closes the receipt/executor copy window.
+fresh_require_patched_postmaster_compiler \
+  "$postmaster_compiler" \
+  "$sealed_product_build_receipt" \
+  "$sealed_receipt" \
+  "$postmaster_executor"
+fresh_require_patched_postmaster_executor \
+  "$staging/bin/wasmer-headless" \
+  "$sealed_postmaster_executor_receipt" \
+  "$sealed_receipt"
+snapshot_runtime_abi_id="$(fresh_manifest_value "$sealed_receipt" runtime_abi_id)"
+[ "$snapshot_runtime_abi_id" = "$runtime_abi_id" ] || {
+  fail "runtime ABI changed while snapshotting the build receipt"
+}
+receipt="$sealed_receipt"
+
+source_fingerprint="$(bun "$carrier_data" source-fingerprint "$staging")"
+fresh_is_sha256 "$source_fingerprint" || fail "failed to compute PostgreSQL carrier fingerprint"
+
+executor_sha256="$(fresh_wasmer_bin_hash "$staging/bin/wasmer-headless")"
+executor_size="$(wc -c <"$staging/bin/wasmer-headless" | tr -d '[:space:]')"
+target_triple="$(fresh_manifest_value "$receipt" rustc_host)"
+host_abi="$(fresh_manifest_value "$receipt" host_abi)"
+wasmer_source_commit="$(fresh_manifest_value "$receipt" wasmer_source_commit)"
+wasmer_patch_sha256="$(fresh_manifest_value "$receipt" wasmer_patch_sha256)"
+wasmer_cargo_lock_sha256="$(fresh_manifest_value "$receipt" wasmer_cargo_lock_sha256)"
+producer_recipe_sha256="$(fresh_aot_producer_recipe_sha256 \
+  "$receipt" "$sealed_product_build_receipt" "$compiler_config" \
+  "$target_triple" "$source_fingerprint")"
+fresh_is_sha256 "$producer_recipe_sha256" || fail "failed to compute AOT producer recipe identity"
+
+write_sealed_manifest() {
+  local output_path="$1"
+
+  bun "$carrier_data" manifest \
+    "$artifact_rows" \
+    "$staging" \
+    "$output_path" \
+    "$source_fingerprint" \
+    "$core_profile" \
+    "$guest_build_recipe_sha256" \
+    "$target_triple" \
+    "$host_abi" \
+    "$compiler_config" \
+    "$wasmer_source_commit" \
+    "$wasmer_patch_sha256" \
+    "$wasmer_cargo_lock_sha256" \
+    "$runtime_abi_id" \
+    "$producer_recipe_sha256" \
+    "$executor_sha256" \
+    "$executor_size" \
+    "$POSTGRES_VERSION" \
+    "$FRESH_WASMER_VERSION" \
+    "$FRESH_WASMER_WASIX_VERSION" \
+    "$FRESH_WASMER_ARTIFACT_ABI_VERSION" \
+    "$linear_memory_receipt_relative" \
+    "$linear_memory_install_receipt_sha256"
+}
+
+write_sealed_manifest "$staging/manifest.json"
+rm "$artifact_rows"
+chmod 0444 "$staging/manifest.json"
+
+# Exercise the final sealed carrier before publication. A
+# version probe is sufficient for the postgres entrypoint, but initdb must run
+# its real bootstrap lifecycle: it reads the packaged share tree, loads libpq,
+# creates writable relation files, and EXEC_BACKEND-spawns the sealed postgres
+# alias.  Keep every writable path outside staging and remove it through the
+# same signal-safe cleanup path as the unpublished carrier.
+validation_root="$(mktemp -d "$output_parent/.${output_name}.validate.XXXXXX")"
+mkdir -p \
+  "$validation_root/home" \
+  "$validation_root/cache" \
+  "$validation_root/pgdata" \
+  "$validation_root/dev-shm"
+chmod 0700 "$validation_root/pgdata"
+chmod 1777 "$validation_root/dev-shm"
+
+# Seal before guest execution. Keep all writable paths in the disposable validation root.
+bun "$carrier_data" seal "$staging"
+validation_inventory_sha256="$(fresh_wasmer_bin_hash "$staging/payload.files")"
+
+validation_common_args=(
+  run
+  --disable-cache
+  --stack-size "$runtime_stack_size"
+  --sealed-module-manifest "$staging/manifest.json"
+  --enable-exceptions
+  --enable-threads
+  --net
+  --volume "$staging:$staging"
+  --volume "$staging/share:/share"
+  --volume "$staging/lib:/lib"
+  --volume "$validation_root/pgdata:/pgdata"
+  --volume "$validation_root/dev-shm:/dev/shm"
+)
+
+postgres_validation_log="$validation_root/postgres.log"
+set +e
+env \
+  WASMER_DIR="$validation_root/home" \
+  WASMER_CACHE_DIR="$validation_root/cache" \
+  "$staging/bin/wasmer-headless" "${validation_common_args[@]}" \
+    "$staging/bin/postgres" -- --version >"$postgres_validation_log" 2>&1
+postgres_validation_status=$?
+set -e
+if [ "$postgres_validation_status" -ne 0 ]; then
+  sed 's/^/sealed postgres load check: /' "$postgres_validation_log" >&2
+  fail "headless executor rejected sealed postgres"
+fi
+
+initdb_validation_log="$validation_root/initdb.log"
+set +e
+env \
+  WASMER_DIR="$validation_root/home" \
+  WASMER_CACHE_DIR="$validation_root/cache" \
+  "$staging/bin/wasmer-headless" "${validation_common_args[@]}" \
+    "$staging/bin/initdb" -- \
+      -D /pgdata \
+      -A trust \
+      --no-locale \
+      --encoding=UTF8 \
+      --no-instructions >"$initdb_validation_log" 2>&1
+initdb_validation_status=$?
+set -e
+if [ "$initdb_validation_status" -ne 0 ]; then
+  sed 's/^/sealed initdb lifecycle check: /' "$initdb_validation_log" >&2
+  fail "headless executor failed the sealed initdb lifecycle"
+fi
+for initialized_path in PG_VERSION global/pg_control; do
+  if ! { [ -f "$validation_root/pgdata/$initialized_path" ] \
+    && [ ! -L "$validation_root/pgdata/$initialized_path" ] \
+    && [ -s "$validation_root/pgdata/$initialized_path" ]; }
+  then
+    fail "sealed initdb lifecycle did not create regular non-empty $initialized_path"
+  fi
+done
+
+[ "$(fresh_wasmer_bin_hash "$staging/payload.files")" = "$validation_inventory_sha256" ] ||
+  fail "sealed validation changed the payload inventory"
+cleanup_validation_root
+
+# Reconsume the finished staging tree through the same verifier used by every
+# sealed runtime entrypoint. This proves that the inventory is exact and that
+# its manifest, receipt, executor, modules, and AOT artifacts form one
+# internally consistent closure before any path is published.
+fresh_verify_sealed_headless_carrier "$staging" || {
+  fail "finished sealed carrier failed complete payload verification"
+}
+
+payload_inventory_sha256="$(fresh_wasmer_bin_hash "$staging/payload.files")"
+fresh_is_sha256 "$payload_inventory_sha256" || {
+  fail "failed to compute sealed carrier payload identity"
+}
+if [ "$output_is_explicit" -eq 0 ]; then
+  output_name="wasix-postmaster-$POSTGRES_VERSION-${runtime_abi_id:0:16}-$payload_inventory_sha256"
+  output="$output_parent/$output_name"
+  [ ! -e "$output" ] && [ ! -L "$output" ] || {
+    fail "content-addressed output already exists: $output"
+  }
+fi
+
+# Durability is scoped to the carrier: flush each regular file, then each
+# directory bottom-up.  This avoids a global sync while ensuring rename never
+# publishes a directory whose verified bytes only lived in page cache.
+bun "$carrier_data" sync-tree "$staging"
+
+fresh_atomic_publish_directory_noreplace "$staging" "$output" ||
+  fail "could not atomically publish sealed carrier: $output"
+staging=""
+trap - EXIT HUP INT TERM
+
+printf 'built sealed headless WASIX PostgreSQL carrier: %s\n' "$output"
+printf 'executor role: postmaster-product\n'
+printf 'runtime ABI ID: %s\n' "$runtime_abi_id"
+printf 'source fingerprint: %s\n' "$source_fingerprint"
+printf 'payload inventory SHA-256: %s\n' "$payload_inventory_sha256"
+printf 'payload inventory: %s\n' "$output/payload.files"
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-sealed-headless-carrier.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-sealed-headless-carrier.test.sh
new file mode 100755
index 000000000..afe922eaa
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-sealed-headless-carrier.test.sh
@@ -0,0 +1,682 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-sealed-carrier.XXXXXX")"
+test_root="$(cd "$test_root" && pwd -P)"
+cleanup_test_root() {
+  chmod -R u+w "$test_root" 2>/dev/null || true
+  rm -rf -- "$test_root"
+}
+trap cleanup_test_root EXIT
+
+export FRESH_WORK_ROOT="$test_root/work"
+export FRESH_UPSTREAM_WASMER_BIN="$test_root/wasmer"
+export FRESH_UPSTREAM_WASMER_HEADLESS_BIN="$test_root/wasmer-headless"
+export FRESH_POSTMASTER_EXECUTOR_BIN="$test_root/postmaster-executor"
+export FRESH_START_PROOF_BIN="$test_root/start-proof"
+export FRESH_POSTMASTER_COMPILER_BIN="$test_root/postmaster-compiler"
+export FRESH_WASMER_BUILD_RECEIPT="$test_root/wasmer-build.receipt"
+export FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT="$test_root/postmaster-executor-build.receipt"
+export WASIX_INSTALL_DIR="$test_root/install"
+export WASIX_CORE_PROFILE=release-o3
+export FAKE_WASMER_VALIDATION_LOG="$test_root/final-validations.log"
+unset FRESH_PINNED_WASMER_CACHE_DIR FRESH_ALLOW_PINNED_CACHE_WRITE
+
+source "$project_root/lib/common.sh"
+source "$project_root/lib/sealed-carrier.sh"
+
+atomic_parent="$test_root/atomic-publication"
+mkdir -p "$atomic_parent/source" "$atomic_parent/competitor"
+printf 'owned-by-competitor\n' >"$atomic_parent/competitor/sentinel"
+if fresh_atomic_publish_directory_noreplace \
+  "$atomic_parent/source" "$atomic_parent/competitor" >/dev/null 2>&1; then
+  printf 'atomic carrier publication replaced a competitor unexpectedly\n' >&2
+  exit 1
+fi
+[ -d "$atomic_parent/source" ] && \
+  [ "$(cat "$atomic_parent/competitor/sentinel")" = owned-by-competitor ] || {
+  printf 'failed atomic publication mutated source or competitor output\n' >&2
+  exit 1
+}
+mkdir "$atomic_parent/publishable"
+printf 'published\n' >"$atomic_parent/publishable/payload"
+fresh_atomic_publish_directory_noreplace \
+  "$atomic_parent/publishable" "$atomic_parent/published"
+[ ! -e "$atomic_parent/publishable" ] && \
+  [ "$(cat "$atomic_parent/published/payload")" = published ] || {
+  printf 'atomic carrier publication did not rename the exact source directory\n' >&2
+  exit 1
+}
+mkdir "$atomic_parent/empty-competitor"
+touch "$atomic_parent/file-competitor"
+ln -s published "$atomic_parent/link-competitor"
+for competitor in empty-competitor file-competitor link-competitor; do
+  if fresh_atomic_publish_directory_noreplace \
+    "$atomic_parent/source" "$atomic_parent/$competitor" >/dev/null 2>&1; then
+    printf 'atomic publication replaced %s\n' "$competitor" >&2
+    exit 1
+  fi
+  [ -d "$atomic_parent/source" ] || exit 1
+done
+
+mkdir -p \
+  "$WASIX_INSTALL_DIR/bin" \
+  "$WASIX_INSTALL_DIR/lib/postgresql" \
+  "$WASIX_INSTALL_DIR/share/postgresql"
+bun build --target=bun "$project_root/testdata/fake-sealed-wasmer.mts" --outfile "$FRESH_UPSTREAM_WASMER_BIN" >/dev/null
+cp "$FRESH_UPSTREAM_WASMER_BIN" "$FRESH_UPSTREAM_WASMER_HEADLESS_BIN"
+cp "$FRESH_UPSTREAM_WASMER_BIN" "$FRESH_POSTMASTER_EXECUTOR_BIN"
+printf '// product-executor-fixture\n' >>"$FRESH_POSTMASTER_EXECUTOR_BIN"
+bun build --target=bun "$project_root/testdata/fake-start-proof.mts" --outfile "$FRESH_START_PROOF_BIN" >/dev/null
+bun build --target=bun "$project_root/testdata/fake-postmaster-compiler.mts" --outfile "$FRESH_POSTMASTER_COMPILER_BIN" >/dev/null
+chmod +x "$FRESH_UPSTREAM_WASMER_BIN" "$FRESH_UPSTREAM_WASMER_HEADLESS_BIN" \
+  "$FRESH_POSTMASTER_EXECUTOR_BIN" "$FRESH_START_PROOF_BIN" \
+  "$FRESH_POSTMASTER_COMPILER_BIN"
+printf 'initdb-wasm\n' >"$WASIX_INSTALL_DIR/bin/initdb"
+printf 'postgres-wasm\n' >"$WASIX_INSTALL_DIR/bin/postgres"
+printf 'libpq-wasm\n' >"$WASIX_INSTALL_DIR/lib/libpq.so.5.18"
+printf 'snowball-wasm\n' >"$WASIX_INSTALL_DIR/lib/postgresql/dict_snowball.so"
+printf 'plpgsql-wasm\n' >"$WASIX_INSTALL_DIR/lib/postgresql/plpgsql.so"
+printf 'sample-config\n' >"$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample"
+bun "$project_root/testdata/make-sealed-export-fixture.mts" \
+  --install-root "$WASIX_INSTALL_DIR" \
+  --project-root "$project_root"
+chmod 0644 "$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample"
+postgres_sha256="$(fresh_wasmer_bin_hash "$WASIX_INSTALL_DIR/bin/postgres")"
+final_wasm_concurrency_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt"
+{
+  printf 'schema=oliphaunt.wasix-postmaster.final-wasm-concurrency.v1\n'
+  printf 'postgres_sha256=%s\n' "$postgres_sha256"
+  printf 'wasm_dis_sha256=%064d\n' 2
+  printf 'wasm_dis_version=fake-wasm-dis version 130\n'
+  printf 'latch_state_contract=packed-atomic-v1\n'
+  printf 'atomic_fence_total=995\n'
+  printf 'atomic_fence_set_latch=2\n'
+  printf 'atomic_fence_reset_latch=1\n'
+  printf 'atomic_fence_wait_event_set_wait=1\n'
+  printf 'i32_atomic_load_total=2\n'
+  printf 'i32_atomic_load_wait_event_set_wait=2\n'
+  printf 'i32_atomic_rmw_and_total=7\n'
+  printf 'i32_atomic_rmw_and_reset_latch=1\n'
+  printf 'i32_atomic_rmw_and_wait_event_set_wait=2\n'
+  printf 'i32_atomic_rmw_or_total=117\n'
+  printf 'i32_atomic_rmw_or_set_latch=1\n'
+  printf 'i32_atomic_rmw_or_wait_event_set_wait=1\n'
+} >"$final_wasm_concurrency_receipt"
+chmod 0444 "$final_wasm_concurrency_receipt"
+final_wasm_concurrency_receipt_sha256="$(
+  fresh_wasmer_bin_hash "$final_wasm_concurrency_receipt"
+)"
+
+sealed_export_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
+linear_memory_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
+bun "$project_root/testdata/make-sealed-export-fixture.mts" --linear-memory --install-root "$WASIX_INSTALL_DIR" --project-root "$project_root"
+chmod 0444 "$sealed_export_receipt" "$linear_memory_receipt"
+linear_memory_install_receipt_sha256="$(fresh_wasmer_bin_hash "$linear_memory_receipt")"
+
+installed_closure_sha256="$(
+  bun "$project_root/lib/guest-build-provenance.mts" \
+    identity "$WASIX_INSTALL_DIR"
+)"
+{
+  printf 'schema=oliphaunt.wasix-postmaster.guest-build.v5\n'
+  printf 'core_profile=release-o3\n'
+  printf 'guest_source_signature_sha256=%064d\n' 1
+  printf 'docker_image_id=sha256:%064d\n' 2
+  printf 'installed_closure_sha256=%s\n' "$installed_closure_sha256"
+  printf 'child_backend=exec\n'
+  printf 'effective_cflags=-O3 -g0 -flto=thin\n'
+  printf 'effective_ldflags=-flto=thin\n'
+  printf 'effective_wasm_opt=yes\n'
+  printf 'effective_wasm_opt_flags=--converge:--strip-debug:--strip-producers\n'
+  printf 'effective_wasm_opt_suppress_default=yes\n'
+  printf 'atomic_fence_total=995\n'
+  printf 'atomic_fence_set_latch=2\n'
+  printf 'atomic_fence_reset_latch=1\n'
+  printf 'atomic_fence_wait_event_set_wait=1\n'
+  printf 'latch_state_contract=packed-atomic-v1\n'
+  printf 'final_wasm_concurrency_receipt_sha256=%s\n' \
+    "$final_wasm_concurrency_receipt_sha256"
+  printf 'linear_memory_profile_id=%s\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
+  printf 'linear_memory_install_receipt_sha256=%s\n' \
+    "$linear_memory_install_receipt_sha256"
+  printf 'postgres_tag=%s\n' "$POSTGRES_TAG"
+  printf 'postgres_version=%s\n' "$POSTGRES_VERSION"
+  printf 'sysroot_variant=%s\n' "$WASIXCC_SYSROOT_VARIANT"
+} >"$WASIX_INSTALL_DIR/guest-build.receipt"
+
+cargo_lock_sha256="$(printf test-cargo-lock | fresh_sha256_stream)"
+runtime_abi_id="$(fresh_runtime_abi_id \
+  "$cargo_lock_sha256" "$(fresh_host_arch | sed 's/linux-amd64/x86_64-unknown-linux-gnu/; s/linux-arm64/aarch64-unknown-linux-gnu/; s/darwin-amd64/x86_64-apple-darwin/; s/darwin-arm64/aarch64-apple-darwin/')" \
+  "$(fresh_host_arch)" "$(fresh_host_abi)")"
+target_triple="$(fresh_host_arch | sed 's/linux-amd64/x86_64-unknown-linux-gnu/; s/linux-arm64/aarch64-unknown-linux-gnu/; s/darwin-amd64/x86_64-apple-darwin/; s/darwin-arm64/aarch64-apple-darwin/')"
+
+{
+  printf 'schema=oliphaunt.wasix-postmaster.wasmer-build.v2\n'
+  printf 'build_recipe_sha256=%s\n' "$(fresh_runtime_build_recipe_sha256)"
+  printf 'wasmer_source_commit=%s\n' "$FRESH_WASMER_SOURCE_COMMIT"
+  printf 'wasmer_napi_commit=%s\n' "$FRESH_WASMER_NAPI_COMMIT"
+  printf 'wasmer_test_files_commit=%s\n' "$FRESH_WASMER_TEST_FILES_COMMIT"
+  printf 'wasmer_spec_commit=%s\n' "$FRESH_WASMER_SPEC_COMMIT"
+  printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch")"
+  printf 'wasmer_prepared_signature_sha256=%064d\n' 0
+  printf 'wasmer_cargo_lock_sha256=%s\n' "$cargo_lock_sha256"
+  printf 'wasmer_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_UPSTREAM_WASMER_BIN")"
+  printf 'wasmer_features=%s\n' "$FRESH_WASMER_COMPILER_FEATURES"
+  printf 'wasmer_headless_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_UPSTREAM_WASMER_HEADLESS_BIN")"
+  printf 'wasmer_headless_features=%s\n' "$FRESH_WASMER_HEADLESS_FEATURES"
+  printf 'runtime_abi_id=%s\n' "$runtime_abi_id"
+  printf 'artifact_abi_version=%s\n' "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
+  printf 'wasix_libc_source_commit=%s\n' "$FRESH_WASIX_LIBC_SOURCE_COMMIT"
+  printf 'wasix_libc_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch")"
+  printf 'wasix_libc_prepared_signature_sha256=%064d\n' 0
+  printf 'sysroot_carrier_manifest_sha256=%064d\n' 0
+  printf 'sysroot_variant=%s\n' "$WASIXCC_SYSROOT_VARIANT"
+  printf 'sysroot_variant_manifest_sha256=%064d\n' 0
+  printf 'host_platform=%s\n' "$(fresh_host_arch)"
+  printf 'host_abi=%s\n' "$(fresh_host_abi)"
+  printf 'rustc_host=%s\n' "$target_triple"
+  printf 'rustc_version=test-rustc\n'
+  printf 'llvm_version=22.1.0\n'
+} >"$FRESH_WASMER_BUILD_RECEIPT"
+
+{
+  printf 'schema=oliphaunt.wasix-postmaster.postmaster-executor-build.v3\n'
+  printf 'build_recipe_sha256=%s\n' "$(fresh_runtime_build_recipe_sha256)"
+  printf 'wasmer_build_receipt_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_WASMER_BUILD_RECEIPT")"
+  printf 'wasmer_source_commit=%s\n' "$FRESH_WASMER_SOURCE_COMMIT"
+  printf 'wasmer_patch_sha256=%s\n' "$(fresh_manifest_value "$FRESH_WASMER_BUILD_RECEIPT" wasmer_patch_sha256)"
+  printf 'wasmer_prepared_signature_sha256=%s\n' "$(fresh_manifest_value "$FRESH_WASMER_BUILD_RECEIPT" wasmer_prepared_signature_sha256)"
+  printf 'wasmer_cargo_lock_sha256=%s\n' "$cargo_lock_sha256"
+  printf 'runtime_abi_id=%s\n' "$runtime_abi_id"
+  printf 'artifact_abi_version=%s\n' "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
+  printf 'executor_package=%s\n' "$FRESH_POSTMASTER_EXECUTOR_PACKAGE"
+  printf 'executor_binary=%s\n' "$FRESH_POSTMASTER_EXECUTOR_BINARY"
+  printf 'executor_features=%s\n' "$FRESH_POSTMASTER_EXECUTOR_FEATURES"
+  printf 'executor_role=%s\n' "$FRESH_POSTMASTER_EXECUTOR_ROLE"
+  printf 'runtime_policy_id=%s\n' "$FRESH_POSTMASTER_EXECUTOR_RUNTIME_POLICY_ID"
+  printf 'cli_contract=%s\n' "$FRESH_POSTMASTER_EXECUTOR_CLI_CONTRACT"
+  printf 'executor_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_POSTMASTER_EXECUTOR_BIN")"
+  printf 'start_proof_binary=%s\n' "$FRESH_START_PROOF_BINARY"
+  printf 'start_proof_features=%s\n' "$FRESH_START_PROOF_FEATURES"
+  printf 'start_proof_policy=%s\n' "$FRESH_START_PROOF_POLICY"
+  printf 'start_proof_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_START_PROOF_BIN")"
+  printf 'memory_profile_binary=%s\n' "$FRESH_MEMORY_PROFILE_BINARY"
+  printf 'memory_profile_features=%s\n' "$FRESH_MEMORY_PROFILE_FEATURES"
+  printf 'linear_memory_profile_id=%s\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
+  printf 'memory_profile_binary_sha256=%064d\n' 9
+  printf 'postmaster_compiler_binary=%s\n' "$FRESH_POSTMASTER_COMPILER_BINARY"
+  printf 'postmaster_compiler_features=%s\n' "$FRESH_POSTMASTER_COMPILER_FEATURES"
+  printf 'compiler_cpu_policy=generic-baseline\n'
+  printf 'compiler_cpu_features=none\n'
+  printf 'postmaster_compiler_binary_sha256=%s\n' \
+    "$(fresh_wasmer_bin_hash "$FRESH_POSTMASTER_COMPILER_BIN")"
+  printf 'host_platform=%s\n' "$(fresh_host_arch)"
+  printf 'host_abi=%s\n' "$(fresh_host_abi)"
+  printf 'rustc_host=%s\n' "$target_triple"
+  printf 'rustc_version=test-rustc\n'
+} >"$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
+
+cache_bucket="$(fresh_wasmer_cache_dir "$FRESH_POSTMASTER_COMPILER_BIN")/compiled/$(fresh_wasmer_compiler_cache_bucket llvm aggressive "$FRESH_WASMER_ARTIFACT_ABI_VERSION")"
+mkdir -p "$cache_bucket"
+required_modules=(bin/initdb bin/postgres)
+while IFS=$'\t' read -r relative _aliases _abi_policy; do
+  case "$relative" in
+    ""|'#'*) continue ;;
+  esac
+  required_modules+=("$relative")
+done <"$project_root/wasmer/policies/sealed-side-modules.v1.tsv"
+for relative in "${required_modules[@]}"; do
+  module="$WASIX_INSTALL_DIR/$relative"
+  module_hash="$(fresh_wasmer_module_hash "$module")"
+  "$FRESH_POSTMASTER_COMPILER_BIN" \
+    --llvm --llvm-opt-level aggressive --compiler-threads 1 \
+    --enable-exceptions --enable-threads \
+    -o "$cache_bucket/$module_hash.bin" "$module"
+done
+
+cp "$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample" \
+  "$test_root/postgresql.conf.sample.saved"
+printf 'stale-install-mutation\n' \
+  >>"$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample"
+if "$project_root/bin/build-sealed-headless-carrier.sh" \
+  --output "$test_root/stale-guest-receipt-carrier" \
+  --cache-bucket "$cache_bucket" >/dev/null 2>&1
+then
+  printf 'carrier builder accepted guest bytes differing from their build receipt\n' >&2
+  exit 1
+fi
+mv "$test_root/postgresql.conf.sample.saved" \
+  "$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample"
+
+postgres_hash="$(fresh_wasmer_module_hash "$WASIX_INSTALL_DIR/bin/postgres")"
+mv "$cache_bucket/$postgres_hash.bin" "$test_root/postgres-aot.saved"
+if "$project_root/bin/build-sealed-headless-carrier.sh" \
+  --output "$test_root/missing-artifact-carrier" \
+  --cache-bucket "$cache_bucket" >/dev/null 2>&1
+then
+  printf 'carrier builder compiled or ignored a missing AOT artifact\n' >&2
+  exit 1
+fi
+mv "$test_root/postgres-aot.saved" "$cache_bucket/$postgres_hash.bin"
+
+plpgsql_hash="$(fresh_wasmer_module_hash "$WASIX_INSTALL_DIR/lib/postgresql/plpgsql.so")"
+mv "$cache_bucket/$plpgsql_hash.bin" "$test_root/plpgsql-aot.saved"
+printf 'wrong-plan-or-module-fixture\n' >"$cache_bucket/$plpgsql_hash.bin"
+if "$project_root/bin/build-sealed-headless-carrier.sh" \
+  --output "$test_root/invalid-inactive-aot-carrier" \
+  --cache-bucket "$cache_bucket" >/dev/null 2>&1
+then
+  printf 'carrier builder accepted an invalid inactive side-module AOT artifact\n' >&2
+  exit 1
+fi
+mv "$test_root/plpgsql-aot.saved" "$cache_bucket/$plpgsql_hash.bin"
+
+: >"$FAKE_WASMER_VALIDATION_LOG"
+failed_validation_output="$test_root/failed-initdb-carrier"
+if FAKE_WASMER_FAIL_FINAL_INITDB=1 \
+  "$project_root/bin/build-sealed-headless-carrier.sh" \
+    --output "$failed_validation_output" \
+    --cache-bucket "$cache_bucket" >/dev/null 2>&1
+then
+  printf 'carrier builder published after the final initdb lifecycle failed\n' >&2
+  exit 1
+fi
+[ ! -e "$failed_validation_output" ]
+if find "$test_root" -maxdepth 1 -type d \
+  \( -name '.failed-initdb-carrier.tmp.*' -o -name '.failed-initdb-carrier.validate.*' \) \
+  -print -quit | grep -q .
+then
+  printf 'carrier builder left staging or validation state after initdb failure\n' >&2
+  exit 1
+fi
+bun "$project_root/testdata/check-carrier-receipts.mts" --validation-log "$FAKE_WASMER_VALIDATION_LOG"
+
+: >"$FAKE_WASMER_VALIDATION_LOG"
+
+if FRESH_PINNED_WASMER_CACHE_DIR="$test_root/foreign-pinned-cache" \
+  "$project_root/bin/build-sealed-headless-carrier.sh" \
+    --output "$test_root/pinned-cache-carrier" \
+    --cache-bucket "$cache_bucket" >/dev/null 2>&1
+then
+  printf 'carrier builder admitted a pinned or foreign AOT cache root\n' >&2
+  exit 1
+fi
+[ ! -e "$test_root/pinned-cache-carrier" ]
+
+output="$test_root/carrier"
+"$project_root/bin/build-sealed-headless-carrier.sh" \
+  --output "$output" \
+  --cache-bucket "$cache_bucket"
+
+for required in \
+  bin/wasmer-headless \
+  bin/initdb \
+  bin/postgres \
+  lib/libpq.so \
+  lib/libpq.so.5 \
+  lib/libpq.so.5.18 \
+  lib/postgresql/dict_snowball.so \
+  lib/postgresql/plpgsql.so \
+  share/postgresql/postgresql.conf.sample \
+  share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json \
+  share/postgresql/wasix-postmaster.sealed-export.structure.receipt \
+  guest-build.receipt \
+  manifest.json \
+  payload.files \
+  postmaster-executor.receipt \
+  wasmer-build.receipt
+do
+  [ -f "$output/$required" ] && [ ! -L "$output/$required" ] || {
+    printf 'missing regular carrier test output: %s\n' "$required" >&2
+    exit 1
+  }
+done
+while IFS=$'\t' read -r relative aliases _abi_policy; do
+  case "$relative" in
+    ""|'#'*) continue ;;
+  esac
+  [ -f "$output/$relative" ] && [ ! -L "$output/$relative" ] || {
+    printf 'missing regular carrier side module: %s\n' "$relative" >&2
+    exit 1
+  }
+  if [ "$aliases" != - ]; then
+    old_ifs="$IFS"
+    IFS=','
+    for alias_relative in $aliases; do
+      IFS="$old_ifs"
+      cmp -s "$output/$relative" "$output/$alias_relative" || {
+        printf 'carrier side-module alias differs from canonical module: %s\n' \
+          "$alias_relative" >&2
+        exit 1
+      }
+      IFS=','
+    done
+    IFS="$old_ifs"
+  fi
+done <"$project_root/wasmer/policies/sealed-side-modules.v1.tsv"
+side_module_count="$(awk -F '\t' '!/^#/ && NF { count += 1 } END { print count + 0 }' \
+  "$project_root/wasmer/policies/sealed-side-modules.v1.tsv")"
+[ "$(find "$output/aot" -type f -name '*.bin' | wc -l | tr -d '[:space:]')" -eq "$((side_module_count + 2))" ]
+[ "$(wc -l <"$FAKE_WASMER_VALIDATION_LOG" | tr -d '[:space:]')" -eq 2 ]
+[ "$(stat -c %a "$output" 2>/dev/null || stat -f %Lp "$output")" = 555 ]
+[ "$(stat -c %a "$output/share/postgresql/postgresql.conf.sample" 2>/dev/null || stat -f %Lp "$output/share/postgresql/postgresql.conf.sample")" = 444 ]
+
+
+
+bun "$project_root/testdata/check-carrier-receipts.mts" --validation-log "$FAKE_WASMER_VALIDATION_LOG"
+
+if find "$test_root" -maxdepth 1 -type d \
+  \( -name '.carrier.tmp.*' -o -name '.carrier.validate.*' \) \
+  -print -quit | grep -q .
+then
+  printf 'carrier builder left staging or validation state after success\n' >&2
+  exit 1
+fi
+
+manifest_source_fingerprint="$(bun "$project_root/testdata/check-carrier-receipts.mts" --field "$output/manifest.json" source-fingerprint
+)"
+manifest_producer_recipe="$(bun "$project_root/testdata/check-carrier-receipts.mts" --field "$output/manifest.json" producer-recipe-sha256
+)"
+compiler_config="$(fresh_wasmer_compiler_cache_bucket \
+  llvm aggressive "$FRESH_WASMER_ARTIFACT_ABI_VERSION")"
+expected_producer_recipe="$(fresh_aot_producer_recipe_sha256 \
+  "$output/wasmer-build.receipt" \
+  "$output/postmaster-executor.receipt" \
+  "$compiler_config" \
+  "$target_triple" \
+  "$manifest_source_fingerprint")"
+[ "$manifest_producer_recipe" = "$expected_producer_recipe" ] || {
+  printf 'manifest AOT producer recipe is not reproducible from packaged inputs\n' >&2
+  exit 1
+}
+bun "$project_root/testdata/check-carrier-receipts.mts" "$output"
+recipe_fixture="$test_root/producer-recipe-fixture"
+mkdir -p "$recipe_fixture/bin" "$recipe_fixture/lib"
+cp "$project_root/bin/precompile-wasix-core.sh" "$recipe_fixture/bin/"
+cp "$project_root/bin/build-sealed-headless-carrier.sh" "$recipe_fixture/bin/"
+cp "$project_root/lib/sealed-carrier.sh" "$recipe_fixture/lib/"
+cp "$project_root/lib/verify-sealed-carrier.mts" "$recipe_fixture/lib/"
+cp "$project_root/lib/sealed-export-chain.mts" "$recipe_fixture/lib/"
+cp "$project_root/lib/publish-directory.c" "$project_root/lib/guest-build-provenance.mts" "$project_root/lib/build-sealed-carrier.mts" "$recipe_fixture/lib/"
+cp "$project_root/lib/linear-memory-profile.mts" "$project_root/lib/receipt-files.mts" "$recipe_fixture/lib/"
+mkdir -p "$recipe_fixture/wasmer/bin"
+cp "$project_root/wasmer/bin/verify-postmaster-concurrency-contract.mts" "$project_root/wasmer/bin/verify-postmaster-wasm-import.mts" "$recipe_fixture/wasmer/bin/"
+fixture_producer_recipe="$(FRESH_ROOT="$recipe_fixture" \
+  fresh_aot_producer_recipe_sha256 \
+    "$output/wasmer-build.receipt" \
+    "$output/postmaster-executor.receipt" \
+    "$compiler_config" \
+    "$target_triple" \
+    "$manifest_source_fingerprint")"
+[ "$manifest_producer_recipe" = "$fixture_producer_recipe" ] || {
+  printf 'AOT producer recipe depends on paths outside its declared inputs\n' >&2
+  exit 1
+}
+printf '// verifier policy mutation\n' >>"$recipe_fixture/lib/verify-sealed-carrier.mts"
+[ "$manifest_producer_recipe" != "$(FRESH_ROOT="$recipe_fixture" \
+  fresh_aot_producer_recipe_sha256 \
+    "$output/wasmer-build.receipt" \
+    "$output/postmaster-executor.receipt" \
+    "$compiler_config" \
+    "$target_triple" \
+    "$manifest_source_fingerprint")" ] || {
+  printf 'AOT producer recipe does not bind the carrier verifier policy\n' >&2
+  exit 1
+}
+cp "$project_root/lib/verify-sealed-carrier.mts" "$recipe_fixture/lib/"
+printf '// export chain policy mutation\n' >>"$recipe_fixture/lib/sealed-export-chain.mts"
+[ "$manifest_producer_recipe" != "$(FRESH_ROOT="$recipe_fixture" \
+  fresh_aot_producer_recipe_sha256 \
+    "$output/wasmer-build.receipt" \
+    "$output/postmaster-executor.receipt" \
+    "$compiler_config" \
+    "$target_triple" \
+    "$manifest_source_fingerprint")" ] || {
+  printf 'AOT producer recipe does not bind sealed export lineage policy\n' >&2
+  exit 1
+}
+[ "$manifest_producer_recipe" != "$(fresh_manifest_value "$output/wasmer-build.receipt" build_recipe_sha256)" ] || {
+  printf 'AOT producer recipe collapsed to the runtime build recipe\n' >&2
+  exit 1
+}
+different_source_fingerprint="$(printf different-source | fresh_sha256_stream)"
+[ "$manifest_producer_recipe" != "$(fresh_aot_producer_recipe_sha256 \
+  "$output/wasmer-build.receipt" \
+  "$output/postmaster-executor.receipt" \
+  "$compiler_config" \
+  "$target_triple" \
+  "$different_source_fingerprint")" ] || {
+  printf 'AOT producer recipe does not bind the guest source fingerprint\n' >&2
+  exit 1
+}
+sed 's/^rustc_version=.*/rustc_version=alternate-test-rustc/' \
+  "$output/wasmer-build.receipt" >"$test_root/alternate-wasmer-build.receipt"
+if fresh_aot_producer_recipe_sha256 \
+  "$test_root/alternate-wasmer-build.receipt" \
+  "$output/postmaster-executor.receipt" \
+  "$compiler_config" \
+  "$target_triple" \
+  "$manifest_source_fingerprint" >"$test_root/alternate-receipt.log" 2>&1; then
+  printf 'AOT producer accepted mismatched Wasmer and executor receipts\n' >&2
+  exit 1
+fi
+[ "$manifest_producer_recipe" != "$(fresh_aot_producer_recipe_sha256 \
+  "$output/wasmer-build.receipt" \
+  "$output/postmaster-executor.receipt" \
+  "${compiler_config}-different" \
+  "$target_triple" \
+  "$manifest_source_fingerprint")" ] || {
+  printf 'AOT producer recipe does not bind the compiler configuration\n' >&2
+  exit 1
+}
+[ "$manifest_producer_recipe" != "$(WASMER_STACK_SIZE=16777216 \
+  fresh_aot_producer_recipe_sha256 \
+    "$output/wasmer-build.receipt" \
+    "$output/postmaster-executor.receipt" \
+    "$compiler_config" \
+    "$target_triple" \
+    "$manifest_source_fingerprint")" ] || {
+  printf 'AOT producer recipe does not bind the runtime stack size\n' >&2
+  exit 1
+}
+if fresh_aot_producer_recipe_sha256 \
+  "$output/wasmer-build.receipt" \
+  "$output/postmaster-executor.receipt" \
+  "$compiler_config" \
+  different-target \
+  "$manifest_source_fingerprint" >/dev/null 2>&1
+then
+  printf 'AOT producer recipe accepted a target inconsistent with its receipt\n' >&2
+  exit 1
+fi
+
+if "$project_root/bin/build-sealed-headless-carrier.sh" \
+  --output "$output" \
+  --cache-bucket "$cache_bucket" >/dev/null 2>&1
+then
+  printf 'carrier builder replaced an existing output unexpectedly\n' >&2
+  exit 1
+fi
+
+"$project_root/bin/verify-sealed-headless-carrier.sh" "$output" >/dev/null
+[ "$(bun "$project_root/lib/verify-sealed-carrier.mts" executor-selection "$output")" = \
+  $'postmaster-product\tpostmaster-executor.receipt\t'"$(fresh_wasmer_bin_hash "$output/postmaster-executor.receipt")"$'\t'"$(fresh_wasmer_bin_hash "$output/bin/wasmer-headless")" ]
+
+# The implicit publication path is derived from the finished exact payload
+# inventory, not merely from the runtime ABI.  This keeps distinct PostgreSQL
+# build profiles from racing for or aliasing one default directory.
+default_build_log="$test_root/default-build.log"
+"$project_root/bin/build-sealed-headless-carrier.sh" \
+  --cache-bucket "$cache_bucket" >"$default_build_log"
+default_output="$(sed -n 's/^built sealed headless WASIX PostgreSQL carrier: //p' "$default_build_log")"
+[ -n "$default_output" ] && [ -d "$default_output" ] || {
+  printf 'default carrier output was not published\n' >&2
+  exit 1
+}
+default_payload_sha256="$(fresh_wasmer_bin_hash "$default_output/payload.files")"
+expected_default_output="$FRESH_WORK_ROOT/carriers/wasix-postmaster-$POSTGRES_VERSION-${runtime_abi_id:0:16}-$default_payload_sha256"
+[ "$default_output" = "$expected_default_output" ] || {
+  printf 'default carrier output is not content-addressed: expected %s, got %s\n' \
+    "$expected_default_output" "$default_output" >&2
+  exit 1
+}
+grep -Fx "payload inventory SHA-256: $default_payload_sha256" "$default_build_log" >/dev/null
+"$project_root/bin/verify-sealed-headless-carrier.sh" "$default_output" >/dev/null
+[ "$(fresh_select_current_sealed_carrier)" = "$default_output" ] || {
+  printf 'current carrier selection did not resolve the receipt-bound output\n' >&2
+  exit 1
+}
+if "$project_root/bin/build-sealed-headless-carrier.sh" \
+  --cache-bucket "$cache_bucket" >/dev/null 2>&1
+then
+  printf 'default carrier builder replaced an existing content identity\n' >&2
+  exit 1
+fi
+
+expect_verifier_failure() {
+  local label="$1"
+  local carrier="$2"
+
+  if "$project_root/bin/verify-sealed-headless-carrier.sh" "$carrier" \
+    >"$test_root/$label.stdout" 2>"$test_root/$label.stderr"
+  then
+    printf 'sealed carrier verifier accepted %s\n' "$label" >&2
+    exit 1
+  fi
+}
+
+reindex_carrier() {
+  local carrier="$1"
+
+  chmod u+w "$carrier/payload.files"
+  bun "$project_root/testdata/check-carrier-receipts.mts" --reindex "$carrier"
+  chmod 0444 "$carrier/payload.files"
+}
+
+legacy_manifest="$test_root/verifier-legacy-manifest-v4"
+cp -a "$output" "$legacy_manifest"
+chmod u+w "$legacy_manifest/manifest.json"
+printf '%s\n' '{"schema":"oliphaunt.wasix-postmaster.sealed-aot.v4","format-version":5}' | bun "$project_root/testdata/check-carrier-receipts.mts" --patch-manifest "$legacy_manifest/manifest.json"
+chmod 0444 "$legacy_manifest/manifest.json"
+reindex_carrier "$legacy_manifest"
+expect_verifier_failure legacy-manifest-v4 "$legacy_manifest"
+
+legacy_guest="$test_root/verifier-legacy-guest-v4"
+cp -a "$output" "$legacy_guest"
+chmod u+w "$legacy_guest/guest-build.receipt" "$legacy_guest/manifest.json"
+sed 's/^schema=oliphaunt.wasix-postmaster.guest-build.v5$/schema=oliphaunt.wasix-postmaster.guest-build.v4/' \
+  "$output/guest-build.receipt" >"$legacy_guest/guest-build.receipt"
+printf '{"guest-build-recipe-sha256":"%s"}\n' "$(fresh_wasmer_bin_hash "$legacy_guest/guest-build.receipt")" | bun "$project_root/testdata/check-carrier-receipts.mts" --patch-manifest "$legacy_guest/manifest.json"
+chmod 0444 "$legacy_guest/guest-build.receipt" "$legacy_guest/manifest.json"
+reindex_carrier "$legacy_guest"
+expect_verifier_failure legacy-guest-v4 "$legacy_guest"
+
+tampered="$test_root/verifier-tampered"
+cp -a "$output" "$tampered"
+chmod u+w "$tampered/bin/postgres"
+printf 'tampered\n' >>"$tampered/bin/postgres"
+chmod 0555 "$tampered/bin/postgres"
+expect_verifier_failure tampered-payload "$tampered"
+
+missing="$test_root/verifier-missing"
+cp -a "$output" "$missing"
+chmod u+w "$missing/share/postgresql"
+mv "$missing/share/postgresql/postgresql.conf.sample" \
+  "$test_root/missing-postgresql.conf.sample"
+chmod 0555 "$missing/share/postgresql"
+expect_verifier_failure missing-payload "$missing"
+
+unexpected="$test_root/verifier-unexpected"
+cp -a "$output" "$unexpected"
+chmod u+w "$unexpected"
+printf 'unexpected\n' >"$unexpected/unexpected.txt"
+chmod 0444 "$unexpected/unexpected.txt"
+chmod 0555 "$unexpected"
+expect_verifier_failure unexpected-payload "$unexpected"
+
+symlinked="$test_root/verifier-symlink"
+cp -a "$output" "$symlinked"
+chmod u+w "$symlinked"
+ln -s bin/postgres "$symlinked/postgres-link"
+chmod 0555 "$symlinked"
+expect_verifier_failure symlink-entry "$symlinked"
+
+special="$test_root/verifier-special"
+cp -a "$output" "$special"
+chmod u+w "$special"
+mkfifo "$special/unexpected.fifo"
+chmod 0555 "$special"
+expect_verifier_failure special-entry "$special"
+
+empty_directory="$test_root/verifier-empty-directory"
+cp -a "$output" "$empty_directory"
+chmod u+w "$empty_directory"
+mkdir "$empty_directory/unrepresented-directory"
+chmod 0555 "$empty_directory/unrepresented-directory" "$empty_directory"
+expect_verifier_failure unrepresented-directory "$empty_directory"
+
+writable_file="$test_root/verifier-writable-file"
+cp -a "$output" "$writable_file"
+chmod u+w "$writable_file/bin/postgres"
+expect_verifier_failure writable-file "$writable_file"
+
+writable_directory="$test_root/verifier-writable-directory"
+cp -a "$output" "$writable_directory"
+chmod u+w "$writable_directory/aot"
+expect_verifier_failure writable-directory "$writable_directory"
+
+unsafe_inventory="$test_root/verifier-unsafe-inventory"
+cp -a "$output" "$unsafe_inventory"
+chmod u+w "$unsafe_inventory/payload.files"
+printf '%064d\t0\t../outside\n' 0 >>"$unsafe_inventory/payload.files"
+chmod 0444 "$unsafe_inventory/payload.files"
+expect_verifier_failure unsafe-inventory-path "$unsafe_inventory"
+
+wrong_executor="$test_root/verifier-wrong-executor"
+cp -a "$output" "$wrong_executor"
+chmod u+w "$wrong_executor/bin/wasmer-headless"
+printf 'different executor\n' >>"$wrong_executor/bin/wasmer-headless"
+chmod 0555 "$wrong_executor/bin/wasmer-headless"
+reindex_carrier "$wrong_executor"
+expect_verifier_failure headless-receipt-identity "$wrong_executor"
+
+wrong_manifest="$test_root/verifier-wrong-manifest"
+cp -a "$output" "$wrong_manifest"
+chmod u+w "$wrong_manifest/manifest.json"
+printf '{"executor-sha256":"%064d"}\n' 0 | bun "$project_root/testdata/check-carrier-receipts.mts" --patch-manifest "$wrong_manifest/manifest.json"
+chmod 0444 "$wrong_manifest/manifest.json"
+reindex_carrier "$wrong_manifest"
+expect_verifier_failure manifest-executor-identity "$wrong_manifest"
+
+wrong_receipt="$test_root/verifier-wrong-receipt"
+cp -a "$output" "$wrong_receipt"
+chmod u+w "$wrong_receipt/wasmer-build.receipt"
+sed 's/^wasmer_headless_binary_sha256=.*/wasmer_headless_binary_sha256=0000000000000000000000000000000000000000000000000000000000000000/' \
+  "$output/wasmer-build.receipt" >"$wrong_receipt/wasmer-build.receipt"
+chmod 0444 "$wrong_receipt/wasmer-build.receipt"
+reindex_carrier "$wrong_receipt"
+expect_verifier_failure receipt-headless-identity "$wrong_receipt"
+
+wrong_product_receipt="$test_root/verifier-wrong-product-receipt"
+cp -a "$output" "$wrong_product_receipt"
+chmod u+w "$wrong_product_receipt/postmaster-executor.receipt"
+sed 's/^executor_binary_sha256=.*/executor_binary_sha256=0000000000000000000000000000000000000000000000000000000000000000/' \
+  "$output/postmaster-executor.receipt" \
+  >"$wrong_product_receipt/postmaster-executor.receipt"
+chmod 0444 "$wrong_product_receipt/postmaster-executor.receipt"
+reindex_carrier "$wrong_product_receipt"
+expect_verifier_failure product-receipt-executor-identity "$wrong_product_receipt"
+
+missing_product_receipt="$test_root/verifier-missing-product-receipt"
+cp -a "$output" "$missing_product_receipt"
+chmod u+w "$missing_product_receipt"
+mv "$missing_product_receipt/postmaster-executor.receipt" \
+  "$test_root/missing-postmaster-executor.receipt"
+chmod 0555 "$missing_product_receipt"
+reindex_carrier "$missing_product_receipt"
+expect_verifier_failure missing-product-role-sidecar "$missing_product_receipt"
+
+printf 'sealed headless carrier packaging tests passed\n'
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.backend.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.backend.test.sh
new file mode 100755
index 000000000..ab40d9b05
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.backend.test.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+builder="$project_root/bin/build-wasix-core.sh"
+
+for unsupported in copied-fork fork typo; do
+  set +e
+  output="$(WASIX_CORE_CHILD_BACKEND="$unsupported" "$builder" --configure-only 2>&1)"
+  status=$?
+  set -e
+
+  [ "$status" -eq 2 ] || {
+    printf 'unsupported backend %s exited %s instead of 2\n' \
+      "$unsupported" "$status" >&2
+    exit 1
+  }
+  [ "$output" = "unsupported WASIX_CORE_CHILD_BACKEND=$unsupported; expected exec" ] || {
+    printf 'unexpected unsupported-backend diagnostic for %s: %s\n' \
+      "$unsupported" "$output" >&2
+    exit 1
+  }
+done
+
+printf 'WASIX core backend validation tests passed\n'
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.sh
new file mode 100755
index 000000000..5a4c977ff
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.sh
@@ -0,0 +1,654 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/common.sh"
+source "$FRESH_ROOT/lib/wasix-build-lock.sh"
+source "$FRESH_ROOT/lib/sealed-carrier.sh"
+
+configure_only=0
+force_clean=0
+portable_inputs="${OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS:-0}"
+case "$portable_inputs" in
+  0|1) ;;
+  *)
+    echo 'OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS must be 0 or 1' >&2
+    exit 2
+    ;;
+esac
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --configure-only)
+      configure_only=1
+      ;;
+    --clean)
+      force_clean=1
+      ;;
+    *)
+      printf 'unknown argument: %s\n' "$1" >&2
+      exit 2
+      ;;
+  esac
+  shift
+done
+
+case "${WASIX_CORE_CHILD_BACKEND:-exec}" in
+  exec|exec-backend)
+    wasix_core_child_backend="exec"
+    ;;
+  *)
+    printf 'unsupported WASIX_CORE_CHILD_BACKEND=%s; expected exec\n' \
+      "$WASIX_CORE_CHILD_BACKEND" >&2
+    exit 2
+    ;;
+esac
+
+if [ "$portable_inputs" -eq 1 ]; then
+  [ "$force_clean" -eq 0 ] || {
+    echo '--clean is incompatible with portable PostgreSQL build inputs' >&2
+    exit 2
+  }
+  guest_receipt="$WASIX_INSTALL_DIR/guest-build.receipt"
+  [ -f "$guest_receipt" ] && [ ! -L "$guest_receipt" ] || {
+    printf 'missing portable PostgreSQL guest receipt: %s\n' "$guest_receipt" >&2
+    exit 2
+  }
+  expected_guest_identity="$(
+    fresh_manifest_value "$guest_receipt" installed_closure_sha256
+  )"
+  actual_guest_identity="$(
+    bun "$FRESH_ROOT/lib/guest-build-provenance.mts" identity \
+      "$WASIX_INSTALL_DIR"
+  )"
+  [ "$actual_guest_identity" = "$expected_guest_identity" ] || {
+    echo 'portable PostgreSQL guest differs from its build receipt' >&2
+    exit 2
+  }
+  [ "$(fresh_manifest_value "$guest_receipt" core_profile)" = \
+    "$WASIX_CORE_PROFILE" ] || {
+    echo 'portable PostgreSQL guest profile differs from the selected product profile' >&2
+    exit 2
+  }
+  printf 'validated portable PostgreSQL guest: %s\n' "$WASIX_INSTALL_DIR"
+  exit 0
+fi
+
+managed_work_probe="$FRESH_WORK_ROOT/.managed-path-boundary"
+fresh_require_managed_generated_path "$managed_work_probe" FRESH_WORK_ROOT
+fresh_require_managed_generated_path "$WASIX_BUILD_DIR" WASIX_BUILD_DIR
+fresh_require_managed_generated_path "$WASIX_INSTALL_DIR" WASIX_INSTALL_DIR
+fresh_require_managed_generated_path "$REPORT_DIR" REPORT_DIR
+fresh_require_managed_generated_path "$RUN_DIR" RUN_DIR
+
+fresh_ensure_dirs
+fresh_require_command git
+fresh_require_command bun
+
+# Serialize the complete producer, including configuration, sealing, and
+# receipt publication.  Every profile and wasix-make.sh acquires this same
+# product-wide lock because the default profiles share one mutable source tree.
+fresh_lock_wasix_core_build "$WASIX_INSTALL_DIR"
+
+# Every rewrite happens in a private complete prefix, never the selected one.
+generation_base="$(fresh_wasix_core_install_base_for "$WASIX_CORE_PROFILE")"
+{
+  case "$WASIX_INSTALL_DIR" in
+    "$generation_base"|"$generation_base.generations/"*) ;;
+    *)
+      echo 'custom WASIX_INSTALL_DIR is a read-only imported generation; use portable-input mode' >&2
+      exit 2 ;;
+  esac
+  mkdir -p "$generation_base.generations"
+  [ -d "$generation_base.generations" ] && [ ! -L "$generation_base.generations" ] || exit 2
+  WASIX_INSTALL_DIR="$(mktemp -d "$generation_base.generations/.pending.XXXXXXXX")"
+  export WASIX_INSTALL_DIR FRESH_WASIX_PRIVATE_INSTALL_DIR="$WASIX_INSTALL_DIR"
+  export FRESH_WASIX_CORE_BUILD_LOCK_INSTALL="$WASIX_INSTALL_DIR"
+  cleanup_guest_generation() {
+    local status=$?
+    trap - EXIT
+    if [ -n "${FRESH_WASIX_PRIVATE_INSTALL_DIR:-}" ]; then
+      rm -rf -- "$FRESH_WASIX_PRIVATE_INSTALL_DIR"
+    fi
+    exit "$status"
+  }
+  trap cleanup_guest_generation EXIT
+  trap 'exit 129' HUP
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
+}
+
+jobs="${JOBS:-$(fresh_jobs)}"
+docker_bin="$(fresh_docker_bin)"
+fresh_resolve_wasix_core_profile
+wasix_core_cflags="$FRESH_WASIX_CORE_EFFECTIVE_CFLAGS"
+wasix_core_ldflags="$FRESH_WASIX_CORE_EFFECTIVE_LDFLAGS"
+wasix_core_latch_state_contract="packed-atomic-v1"
+wasixcc_run_wasm_opt="$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT"
+wasixcc_wasm_opt_flags="$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_FLAGS"
+wasixcc_wasm_opt_suppress_default="$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT"
+expected_atomic_fence_total="$FRESH_WASIX_CORE_EXPECTED_ATOMIC_FENCE_TOTAL"
+expected_final_atomic_fence_total="$FRESH_WASIX_CORE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL"
+
+wasix_core_cflags="$wasix_core_cflags -DPG_WASIX_ATOMIC_LATCH_STATE=1"
+
+"$FRESH_ROOT/bin/apply-wasix-core-overlay.sh" >/dev/null
+postgres_worktree_signature="$WASIX_SRC_DIR/.fresh-wasix-core-signature"
+postgres_worktree_state="$(
+  fresh_git_worktree_state_sha256 "$WASIX_SRC_DIR" ".fresh-wasix-core-signature"
+)" || exit
+fresh_require_manifest_value "$postgres_worktree_signature" \
+  worktree_state_sha256 "$postgres_worktree_state" || exit
+
+compute_source_signature() {
+  local worktree_state="$1"
+  local builder_image_id="$2"
+
+  {
+    cat "$postgres_worktree_signature"
+    shasum -a 256 "$0"
+    shasum -a 256 \
+      "$FRESH_ROOT/bin/apply-wasix-core-overlay.sh" \
+      "$FRESH_ROOT/lib/common.sh" \
+      "$FRESH_ROOT/lib/wasix-build-lock.sh" \
+      "$FRESH_ROOT/wasmer/bin/verify-postmaster-wasm-import.mts" \
+      "$FRESH_ROOT/wasmer/bin/verify-postmaster-concurrency-contract.mts" \
+      "$FRESH_ROOT/wasmer/bin/analyze-wasm-concurrency.sh" \
+      "$FRESH_ROOT/bin/seal-wasix-core-exports.sh" \
+      "$FRESH_ROOT/bin/seal-wasix-linear-memory.sh" \
+      "$FRESH_ROOT/lib/guest-build-provenance.mts" \
+      "$FRESH_ROOT/lib/receipt-files.mts" \
+      "$FRESH_ROOT/lib/guest-generation.sh" \
+      "$FRESH_ROOT/lib/select-guest-generation.mts" \
+      "$FRESH_ROOT/lib/publish-directory.c" \
+      "$FRESH_ROOT/lib/linear-memory-profile.mts" \
+      "$REPO_ROOT/tools/packaging/strict-json.mts" \
+      "$FRESH_ROOT/lib/sealed-export-chain.mts" \
+      "$FRESH_ROOT/wasmer/policies/sealed-main-runtime-exports.v1.txt" \
+      "$FRESH_ROOT/wasmer/policies/sealed-main-dlsym-exports.v1.txt" \
+      "$FRESH_ROOT/wasmer/policies/sealed-side-modules.v1.tsv" \
+      "$FRESH_ROOT/tools/sealed-export-closure/Cargo.toml" \
+      "$FRESH_ROOT/tools/sealed-export-closure/Cargo.lock" \
+      "$FRESH_ROOT/tools/sealed-export-closure/src/main.rs"
+    printf 'WASIXCC_SYSROOT_PREFIX=%s\n' "${WASIXCC_SYSROOT_PREFIX:-}"
+    printf 'WASIXCC_SYSROOT=%s\n' "${WASIXCC_SYSROOT:-}"
+    if [ -n "${WASIXCC_SYSROOT_PREFIX:-}" ] && [ -f "$WASIXCC_SYSROOT_PREFIX/.fresh-sysroot-signature" ]; then
+      printf 'WASIXCC_SYSROOT_PREFIX_SIGNATURE='
+      cat "$WASIXCC_SYSROOT_PREFIX/.fresh-sysroot-signature"
+    fi
+    if [ -n "${WASIXCC_SYSROOT:-}" ] && [ -f "$WASIXCC_SYSROOT/.fresh-sysroot-signature" ]; then
+      printf 'WASIXCC_SYSROOT_SIGNATURE='
+      cat "$WASIXCC_SYSROOT/.fresh-sysroot-signature"
+    fi
+    printf 'WASIX_CORE_PROFILE=%s\n' "$WASIX_CORE_PROFILE"
+    printf 'WASIX_CORE_CHILD_BACKEND=%s\n' "$wasix_core_child_backend"
+    printf 'WASIX_CORE_LATCH_STATE_CONTRACT=%s\n' "$wasix_core_latch_state_contract"
+    printf 'WASIX_CORE_CFLAGS=%s\n' "$wasix_core_cflags"
+    printf 'WASIX_CORE_LDFLAGS=%s\n' "$wasix_core_ldflags"
+    printf 'WASIXCC_RUN_WASM_OPT=%s\n' "$wasixcc_run_wasm_opt"
+    printf 'WASIXCC_WASM_OPT_FLAGS=%s\n' "$wasixcc_wasm_opt_flags"
+    printf 'WASIXCC_WASM_OPT_SUPPRESS_DEFAULT=%s\n' "$wasixcc_wasm_opt_suppress_default"
+    printf 'EXPECTED_ATOMIC_FENCE_TOTAL=%s\n' "${expected_atomic_fence_total:-profile-unlocked}"
+    printf 'EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=%s\n' \
+      "${expected_final_atomic_fence_total:-profile-unlocked}"
+    printf 'LINEAR_MEMORY_PROFILE_ID=%s\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
+    printf 'LINEAR_MEMORY_MAXIMUM_PAGES=%s\n' "$FRESH_LINEAR_MEMORY_MAXIMUM_PAGES"
+    printf 'LINEAR_MEMORY_STATIC_BOUND_PAGES=%s\n' "$FRESH_LINEAR_MEMORY_STATIC_BOUND_PAGES"
+    printf 'LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES=%s\n' \
+      "$FRESH_LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES"
+    printf 'DOCKER_IMAGE_ID=%s\n' "$builder_image_id"
+    printf 'POSTGRES_WORKTREE_STATE=%s\n' "$worktree_state"
+  } | shasum -a 256 | awk '{print $1}'
+}
+
+build_signature_file="$WASIX_BUILD_DIR/.fresh-wasix-core-build-signature"
+fresh_require_managed_generated_path "$build_signature_file" wasix-core-build-signature
+
+require_build_inputs_unchanged() {
+  local context="$1"
+  local current_source_signature
+  local current_postgres_worktree_state
+
+  [ -f "$build_signature_file" ] && [ ! -L "$build_signature_file" ] &&
+    [ "$(cat "$build_signature_file")" = "$source_signature" ] || {
+    printf 'WASIX core build signature changed %s\n' "$context" >&2
+    return 125
+  }
+  current_postgres_worktree_state="$(
+    fresh_git_worktree_state_sha256 \
+      "$WASIX_SRC_DIR" ".fresh-wasix-core-signature"
+  )" || return 125
+  [ "$current_postgres_worktree_state" = "$postgres_worktree_state" ] || {
+    printf 'WASIX core PostgreSQL source changed %s\n' "$context" >&2
+    return 125
+  }
+  current_source_signature="$(
+    compute_source_signature "$current_postgres_worktree_state" "$docker_image_id"
+  )" || return 125
+  fresh_is_sha256 "$current_source_signature" || return 125
+  [ "$current_source_signature" = "$source_signature" ] || {
+    printf 'WASIX core build input changed %s\n' "$context" >&2
+    return 125
+  }
+}
+
+report="$REPORT_DIR/wasix-core-build.md"
+log="$REPORT_DIR/wasix-core-build.log"
+fresh_require_managed_generated_path "$report" wasix-core-build-report
+fresh_require_managed_generated_path "$log" wasix-core-build-log
+fresh_write_report_header "$report" "WASIX Core PostgreSQL Build"
+
+{
+  printf '## Scope\n\n'
+  printf -- '- Source: clean PostgreSQL `%s` plus `postgres/overlays/wasix-core` and the explicit patch series.\n' "$POSTGRES_TAG"
+  printf -- '- Template: `--with-template=wasix-core`.\n'
+  printf -- '- Build profile: `%s`.\n' "$WASIX_CORE_PROFILE"
+  printf -- '- Profile description: `%s`.\n' "$FRESH_WASIX_CORE_PROFILE_DESCRIPTION"
+  printf -- '- Child backend: `%s`.\n' "$wasix_core_child_backend"
+  printf -- '- Shared latch state contract: `%s`.\n' "$wasix_core_latch_state_contract"
+  printf -- '- Build lane: optimized core server/tools, PL/pgSQL, snowball dictionary, and core encoding conversion modules; no contrib or regression test binaries.\n'
+  printf -- '- wasixcc sysroot prefix: `%s`.\n' "${WASIXCC_SYSROOT_PREFIX:-}"
+  printf -- '- wasixcc sysroot: `%s`.\n' "${WASIXCC_SYSROOT:-}"
+  printf -- '- Build directory: `%s`.\n' "$WASIX_BUILD_DIR"
+  printf -- '- Install directory: `%s`.\n' "$WASIX_INSTALL_DIR"
+  printf -- '- CFLAGS: `%s`.\n' "$wasix_core_cflags"
+  printf -- '- LDFLAGS: `%s`.\n' "$wasix_core_ldflags"
+  printf -- '- wasixcc wasm-opt: `%s`.\n' "$wasixcc_run_wasm_opt"
+  printf -- '- wasixcc wasm-opt flags: `%s`.\n' "$wasixcc_wasm_opt_flags"
+  printf -- '- wasixcc suppress implicit wasm-opt defaults: `%s`.\n' "$wasixcc_wasm_opt_suppress_default"
+  printf -- '- Final-module critical fence contract: `SetLatch=2`, `ResetLatch=1`, and `WaitEventSetWait=1`.\n'
+  printf -- '- Main export policy: exact typed packaged-side closure, followed only by Binaryen module-element reachability DCE and final proof replay.\n'
+  printf -- '- Linear-memory ABI: `%s` (bounded 256 MiB guest maximum; 64-bit-host static lowering only).\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
+  printf -- '- Profile-locked pre-seal fence inventory: `%s`.\n' "${expected_atomic_fence_total:-critical-functions-only}"
+  printf -- '- Profile-locked final sealed-module fence inventory: `%s`.\n' \
+    "${expected_final_atomic_fence_total:-critical-functions-only}"
+  printf -- '- Configure wasm-opt: `no`.\n'
+  printf -- '- Largefile support: not disabled.\n'
+  printf -- '- Spinlocks: not disabled.\n'
+  printf -- '- Single-user compatibility macros: not used.\n\n'
+  printf '## Build Log\n\n'
+  printf 'See `%s`.\n' "$log"
+} >>"$report"
+
+mode="build"
+if [ "$configure_only" -eq 1 ]; then
+  mode="configure-only"
+fi
+
+: >"$log"
+if ! "$docker_bin" info >>"$log" 2>&1; then
+  {
+    printf '\n## Result\n\n'
+    printf -- '- Status: `blocked`\n'
+    printf -- '- Mode: `%s`\n' "$mode"
+    printf -- '- Blocker: Docker daemon is not reachable.\n\n'
+    printf 'Start Docker or run this script inside an environment with the pinned WASIX toolchain already available.\n'
+  } >>"$report"
+  printf 'blocked: Docker daemon is not reachable; see %s\n' "$log" >&2
+  exit 2
+fi
+
+set +e
+fresh_ensure_docker_image >>"$log" 2>&1
+image_status=$?
+set -e
+if [ "$image_status" -ne 0 ]; then
+  {
+    printf '\n## Result\n\n'
+    printf -- '- Status: `fail`\n'
+    printf -- '- Mode: `%s`\n' "$mode"
+    printf -- '- Exit code: `%s`\n' "$image_status"
+    printf -- '- Failure: could not prepare Docker image `%s`.\n' "$FRESH_WASIX_DOCKER_IMAGE"
+  } >>"$report"
+  printf 'WASIX Docker image preparation failed; see %s\n' "$log" >&2
+  exit "$image_status"
+fi
+docker_image_id="$(fresh_wasix_builder_image_id)" || {
+  printf 'WASIX Docker image identity lookup failed; see %s\n' "$log" >&2
+  exit 2
+}
+{
+  printf '\n## Immutable Builder\n\n'
+  printf -- '- Image reference: `%s`\n' "$FRESH_WASIX_DOCKER_IMAGE"
+  printf -- '- Image ID: `%s`\n' "$docker_image_id"
+} >>"$report"
+
+# The immutable builder is an input, not merely the transport used to execute
+# the build. Resolve it before deciding whether an existing build directory is
+# reusable, and bind that exact identity into every later provenance record.
+source_signature="$(
+  compute_source_signature "$postgres_worktree_state" "$docker_image_id"
+)"
+fresh_is_sha256 "$source_signature" || {
+  printf 'could not derive WASIX core source signature\n' >&2
+  exit 125
+}
+if [ "$force_clean" -eq 0 ] && [ -f "$build_signature_file" ] && \
+  [ "$(cat "$build_signature_file")" = "$source_signature" ]; then
+  mkdir -p "$WASIX_BUILD_DIR" "$WASIX_INSTALL_DIR"
+else
+  fresh_require_managed_generated_path "$WASIX_BUILD_DIR" WASIX_BUILD_DIR
+  fresh_require_managed_generated_path "$WASIX_INSTALL_DIR" WASIX_INSTALL_DIR
+  rm -rf "$WASIX_BUILD_DIR" "$WASIX_INSTALL_DIR"
+  mkdir -p "$WASIX_BUILD_DIR" "$WASIX_INSTALL_DIR"
+  printf '%s' "$source_signature" >"$build_signature_file"
+fi
+
+if ! DOCKER_IMAGE="$FRESH_WASIX_DOCKER_IMAGE" \
+  "$FRESH_ROOT/wasmer/bin/validate-runtime-capabilities.sh" --validate-sysroot-only >>"$log" 2>&1; then
+  {
+    printf '\n## Result\n\n'
+    printf -- '- Status: `fail`\n'
+    printf -- '- Mode: `%s`\n' "$mode"
+    printf -- '- Failure: exact patched WASIX libc carrier validation failed.\n'
+  } >>"$report"
+  printf 'WASIX libc carrier validation failed; see %s\n' "$log" >&2
+  exit 2
+fi
+
+fresh_require_managed_generated_path "$WASIX_BUILD_DIR" WASIX_BUILD_DIR
+fresh_require_managed_generated_path "$WASIX_INSTALL_DIR" WASIX_INSTALL_DIR
+set +e
+printf '\n## docker run\n\n' >>"$log"
+docker_env=()
+if [ -n "${WASIXCC_SYSROOT_PREFIX:-}" ]; then
+  docker_env+=(-e "WASIXCC_SYSROOT_PREFIX=$(fresh_docker_path_for "$WASIXCC_SYSROOT_PREFIX")")
+fi
+if [ -n "${WASIXCC_SYSROOT:-}" ]; then
+  docker_env+=(-e "WASIXCC_SYSROOT=$(fresh_docker_path_for "$WASIXCC_SYSROOT")")
+fi
+"$docker_bin" run --rm \
+  -v "$REPO_ROOT:/work" \
+  -w /work \
+  -e JOBS="$jobs" \
+  -e PGSRC="${WASIX_SRC_DIR#$REPO_ROOT/}" \
+  -e BUILD_DIR="${WASIX_BUILD_DIR#$REPO_ROOT/}" \
+  -e INSTALL_DIR="${WASIX_INSTALL_DIR#$REPO_ROOT/}" \
+  -e MODE="$mode" \
+  -e WASIX_CORE_CFLAGS="$wasix_core_cflags" \
+  -e WASIX_CORE_LDFLAGS="$wasix_core_ldflags" \
+  -e WASIXCC_RUN_WASM_OPT="$wasixcc_run_wasm_opt" \
+  -e WASIXCC_WASM_OPT_FLAGS="$wasixcc_wasm_opt_flags" \
+  -e WASIXCC_WASM_OPT_SUPPRESS_DEFAULT="$wasixcc_wasm_opt_suppress_default" \
+  -e EXPECTED_ATOMIC_FENCE_TOTAL="$expected_atomic_fence_total" \
+  -e WASIX_CORE_LATCH_STATE_CONTRACT="$wasix_core_latch_state_contract" \
+  -e "HOST_UID=$(id -u)" \
+  -e "HOST_GID=$(id -g)" \
+  "${docker_env[@]}" \
+  "$docker_image_id" \
+  bash -lc '
+    set -euo pipefail
+    source ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+    cd /work
+
+    restore_host_ownership() {
+      local command_status="$?"
+      local ownership_failed=0
+      local output_path
+
+      trap - EXIT
+      for output_path in "/work/$BUILD_DIR" "/work/$INSTALL_DIR"; do
+        if [ -e "$output_path" ] && ! chown -R "$HOST_UID:$HOST_GID" "$output_path"; then
+          printf "failed to restore host ownership for %s\n" "$output_path" >&2
+          ownership_failed=1
+        fi
+      done
+      if [ "$command_status" -eq 0 ] && [ "$ownership_failed" -ne 0 ]; then
+        command_status="$ownership_failed"
+      fi
+      exit "$command_status"
+    }
+    trap restore_host_ownership EXIT
+
+    mkdir -p "$BUILD_DIR" "$INSTALL_DIR"
+    cd "$BUILD_DIR"
+    configure_args=(
+      "--prefix=/"
+      "--bindir=/bin"
+      "--libdir=/lib"
+      "--datadir=/share/postgresql"
+      "--host=wasm32-wasix"
+      "--with-template=wasix-core"
+      "--without-readline"
+      "--without-icu"
+      "--without-zlib"
+      "--without-llvm"
+      "--without-pam"
+      "--with-openssl=no"
+    )
+    if [ ! -f config.status ]; then
+      WASIXCC_RUN_WASM_OPT=no \
+      CC=wasixcc \
+      AR=wasixar \
+      RANLIB=wasixranlib \
+      NM=wasixnm \
+      CPPFLAGS="-D_GNU_SOURCE" \
+      CFLAGS="$WASIX_CORE_CFLAGS" \
+      LDFLAGS="$WASIX_CORE_LDFLAGS" \
+      "/work/$PGSRC/configure" "${configure_args[@]}"
+    fi
+    if ! grep -Fxq "#define HAVE_SYNC_FILE_RANGE 1" src/include/pg_config.h; then
+      printf "configured PostgreSQL does not define HAVE_SYNC_FILE_RANGE=1; refuse the fallback build\n" >&2
+      exit 2
+    fi
+    if [ "$MODE" = "configure-only" ]; then
+      exit 0
+    fi
+    core_dirs=(
+      src/port
+      src/common
+      src/include
+      src/interfaces/libpq
+      src/backend
+      src/backend/snowball
+      src/backend/utils/mb/conversion_procs
+      src/pl/plpgsql/src
+      src/bin/initdb
+      src/bin/pg_ctl
+      src/bin/psql
+      src/bin/pg_dump
+      src/bin/pg_config
+      src/timezone
+    )
+    make -C src/backend -j "$JOBS" generated-headers
+    rm -f \
+      src/backend/postgres \
+      src/bin/initdb/initdb \
+      src/bin/pg_ctl/pg_ctl \
+      src/bin/psql/psql \
+      src/bin/pg_dump/pg_dump \
+      src/bin/pg_dump/pg_restore \
+      src/bin/pg_dump/pg_dumpall \
+      src/bin/pg_config/pg_config
+    for dir in "${core_dirs[@]}"; do
+      make -C "$dir" -j "$JOBS" all
+    done
+    rm -rf "/work/$INSTALL_DIR"
+    mkdir -p "/work/$INSTALL_DIR"
+    for dir in "${core_dirs[@]}"; do
+      make -C "$dir" -j "$JOBS" install DESTDIR="/work/$INSTALL_DIR"
+    done
+  ' >>"$log" 2>&1
+status=$?
+set -e
+
+if [ "$status" -eq 0 ] && [ "$mode" = build ]; then
+  bun "$FRESH_ROOT/wasmer/bin/verify-postmaster-wasm-import.mts" \
+    "$WASIX_INSTALL_DIR/bin/postgres" >>"$log" 2>&1 || status=$?
+fi
+
+if [ "$status" -eq 0 ] && [ "$mode" = build ]; then
+  concurrency_args=(--latch-state-contract "$wasix_core_latch_state_contract")
+  if [ -n "$expected_atomic_fence_total" ]; then
+    concurrency_args+=(--expected-total "$expected_atomic_fence_total")
+  fi
+  bash "$FRESH_ROOT/wasmer/bin/analyze-wasm-concurrency.sh" "$docker_bin" "$docker_image_id" \
+    "$WASIX_INSTALL_DIR/bin/postgres" "${concurrency_args[@]}" >>"$log" 2>&1 || status=$?
+fi
+
+if [ "$status" -eq 0 ] && [ "$mode" = build ] && \
+  [ "$wasix_core_latch_state_contract" = packed-atomic-v1 ]
+then
+  if [ -z "$expected_atomic_fence_total" ] || \
+    [ -z "$expected_final_atomic_fence_total" ]; then
+    printf 'sealed export closure requires profile-locked pre-seal and final atomic fence totals\n' >>"$log"
+    status=2
+  else
+    set +e
+    (
+      set -euo pipefail
+
+      "$FRESH_ROOT/bin/seal-wasix-core-exports.sh" \
+        --install-dir "$WASIX_INSTALL_DIR" \
+        --expected-total "$expected_final_atomic_fence_total"
+
+      sealed_export_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
+      "$FRESH_ROOT/bin/seal-wasix-linear-memory.sh" \
+        --install-dir "$WASIX_INSTALL_DIR" \
+        --predecessor-receipt "$sealed_export_receipt"
+
+      bun "$FRESH_ROOT/wasmer/bin/verify-postmaster-wasm-import.mts" \
+        "$WASIX_INSTALL_DIR/bin/postgres"
+      fresh_require_start_proof_tool \
+        "$FRESH_START_PROOF_BIN" \
+        "$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
+
+      proof_dir="$WASIX_INSTALL_DIR/share/postgresql"
+      final_start_proof="$proof_dir/wasix-postmaster.start-proof.json"
+      final_concurrency_receipt="$proof_dir/wasix-postmaster.final-wasm-concurrency.receipt"
+      "$FRESH_START_PROOF_BIN" "$WASIX_INSTALL_DIR/bin/postgres" >"$final_start_proof"
+      [ -s "$final_start_proof" ] && [ ! -L "$final_start_proof" ]
+      bash "$FRESH_ROOT/wasmer/bin/analyze-wasm-concurrency.sh" "$docker_bin" "$docker_image_id" \
+        "$WASIX_INSTALL_DIR/bin/postgres" \
+        --expected-total "$expected_final_atomic_fence_total" \
+        --latch-state-contract packed-atomic-v1 \
+        --receipt "$final_concurrency_receipt"
+      bun "$FRESH_ROOT/wasmer/bin/verify-postmaster-concurrency-contract.mts" \
+        --expected-total "$expected_final_atomic_fence_total" \
+        --latch-state-contract packed-atomic-v1 \
+        --verified-receipt "$final_concurrency_receipt" --receipt-only \
+        "$WASIX_INSTALL_DIR/bin/postgres"
+    ) >>"$log" 2>&1
+    status=$?
+    set -e
+  fi
+fi
+
+if [ "$status" -eq 0 ]; then
+  if [ "$mode" = build ]; then
+    guest_build_receipt="$WASIX_INSTALL_DIR/guest-build.receipt"
+    concurrency_args=()
+    if [ -n "$expected_final_atomic_fence_total" ]; then
+      concurrency_args+=(--expected-total "$expected_final_atomic_fence_total")
+    fi
+    final_wasm_concurrency_receipt_sha256="none"
+    if [ "$wasix_core_latch_state_contract" = packed-atomic-v1 ]; then
+      final_wasm_concurrency_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt"
+      [ -f "$final_wasm_concurrency_receipt" ] && [ ! -L "$final_wasm_concurrency_receipt" ] || {
+        echo 'missing final Wasm concurrency receipt' >&2
+        exit 125
+      }
+      concurrency_args+=(
+        --latch-state-contract packed-atomic-v1
+        --verified-receipt "$final_wasm_concurrency_receipt"
+      )
+      final_wasm_concurrency_receipt_sha256="$(
+        fresh_wasmer_bin_hash "$final_wasm_concurrency_receipt"
+      )" || exit
+      fresh_is_sha256 "$final_wasm_concurrency_receipt_sha256" || {
+        echo 'final Wasm concurrency receipt identity is not a SHA-256' >&2
+        exit 125
+      }
+    fi
+    concurrency_contract_output="$(
+      bun "$FRESH_ROOT/wasmer/bin/verify-postmaster-concurrency-contract.mts" \
+        "${concurrency_args[@]}" "$WASIX_INSTALL_DIR/bin/postgres"
+    )" || exit
+    atomic_fence_total="$(
+      printf '%s\n' "$concurrency_contract_output" |
+        sed -n 's/^verified PostgreSQL Wasm concurrency contract: total=\([0-9][0-9]*\) .*/\1/p'
+    )"
+    case "$atomic_fence_total" in
+      ''|*[!0-9]*) echo 'could not parse verified atomic fence total' >&2; exit 125 ;;
+    esac
+    linear_memory_profile_id="$FRESH_LINEAR_MEMORY_PROFILE_ID"
+    linear_memory_install_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
+    [ -f "$linear_memory_install_receipt" ] && \
+      [ ! -L "$linear_memory_install_receipt" ] || {
+      echo 'missing regular linear-memory install receipt' >&2
+      exit 125
+    }
+    linear_memory_install_receipt_sha256="$(
+      fresh_wasmer_bin_hash "$linear_memory_install_receipt"
+    )" || exit
+    fresh_is_sha256 "$linear_memory_install_receipt_sha256" || {
+      echo 'linear-memory install receipt identity is not a SHA-256' >&2
+      exit 125
+    }
+    require_build_inputs_unchanged 'before guest receipt publication' || exit
+    installed_closure_sha256="$(
+      bun "$FRESH_ROOT/lib/guest-build-provenance.mts" \
+        seal-identity "$WASIX_INSTALL_DIR"
+    )" || exit
+    fresh_is_sha256 "$installed_closure_sha256" || {
+      echo 'WASIX core installed closure identity is not a SHA-256' >&2
+      exit 125
+    }
+    require_build_inputs_unchanged 'while installed outputs were hashed' || exit
+    case "$wasix_core_cflags$wasix_core_ldflags$wasixcc_run_wasm_opt$wasixcc_wasm_opt_flags$wasixcc_wasm_opt_suppress_default" in
+      *$'\n'*|*$'\r'*)
+        echo 'WASIX core effective build flags contain a line break' >&2
+        exit 2
+        ;;
+    esac
+    {
+      printf 'schema=oliphaunt.wasix-postmaster.guest-build.v5\n'
+      printf 'core_profile=%s\n' "$WASIX_CORE_PROFILE"
+      printf 'guest_source_signature_sha256=%s\n' "$source_signature"
+      printf 'docker_image_id=%s\n' "$docker_image_id"
+      printf 'installed_closure_sha256=%s\n' "$installed_closure_sha256"
+      printf 'child_backend=%s\n' "$wasix_core_child_backend"
+      printf 'effective_cflags=%s\n' "$wasix_core_cflags"
+      printf 'effective_ldflags=%s\n' "$wasix_core_ldflags"
+      printf 'effective_wasm_opt=%s\n' "$wasixcc_run_wasm_opt"
+      printf 'effective_wasm_opt_flags=%s\n' "${wasixcc_wasm_opt_flags:-none}"
+      printf 'effective_wasm_opt_suppress_default=%s\n' "$wasixcc_wasm_opt_suppress_default"
+      printf 'atomic_fence_total=%s\n' "$atomic_fence_total"
+      printf 'atomic_fence_set_latch=2\n'
+      printf 'atomic_fence_reset_latch=1\n'
+      printf 'atomic_fence_wait_event_set_wait=1\n'
+      printf 'latch_state_contract=%s\n' "$wasix_core_latch_state_contract"
+      printf 'final_wasm_concurrency_receipt_sha256=%s\n' \
+        "$final_wasm_concurrency_receipt_sha256"
+      printf 'linear_memory_profile_id=%s\n' "$linear_memory_profile_id"
+      printf 'linear_memory_install_receipt_sha256=%s\n' \
+        "$linear_memory_install_receipt_sha256"
+      printf 'postgres_tag=%s\n' "$POSTGRES_TAG"
+      printf 'postgres_version=%s\n' "$POSTGRES_VERSION"
+      printf 'sysroot_variant=%s\n' "$WASIXCC_SYSROOT_VARIANT"
+    } >"$guest_build_receipt"
+    require_build_inputs_unchanged 'before completed guest generation publication' || exit
+    WASIX_INSTALL_DIR="$(fresh_publish_guest_generation "$WASIX_INSTALL_DIR" "$generation_base")" || exit
+    unset FRESH_WASIX_PRIVATE_INSTALL_DIR
+    export WASIX_INSTALL_DIR
+
+  fi
+  {
+    printf '\n## Result\n\n'
+    printf -- '- Status: `pass`\n'
+    printf -- '- Mode: `%s`\n' "$mode"
+    printf -- '- Build directory: `%s`\n' "$WASIX_BUILD_DIR"
+    printf -- '- Install directory: `%s`\n' "$WASIX_INSTALL_DIR"
+  } >>"$report"
+  printf 'built WASIX core PostgreSQL lane at %s\n' "$WASIX_INSTALL_DIR"
+else
+  {
+    printf '\n## Result\n\n'
+    printf -- '- Status: `fail`\n'
+    printf -- '- Mode: `%s`\n' "$mode"
+    printf -- '- Exit code: `%s`\n\n' "$status"
+    printf '## Blocker Policy\n\n'
+    printf 'Treat this as a PostgreSQL/WASIX/toolchain compatibility blocker. Do not add fake PostgreSQL success shims to make this pass.\n'
+  } >>"$report"
+  printf 'WASIX core build failed; see %s\n' "$log" >&2
+  exit "$status"
+fi
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/deploy-immutable-sealed-carrier.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/deploy-immutable-sealed-carrier.sh
similarity index 92%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/deploy-immutable-sealed-carrier.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/deploy-immutable-sealed-carrier.sh
index e94751d0c..e03c94594 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/deploy-immutable-sealed-carrier.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/deploy-immutable-sealed-carrier.sh
@@ -5,6 +5,7 @@ set -euo pipefail
 project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
 source "$project_root/lib/common.sh"
 source "$project_root/lib/sealed-carrier.sh"
+source "$project_root/lib/immutable-carrier.sh"
 source "$project_root/lib/qualification-identities.sh"
 
 usage() {
@@ -74,18 +75,18 @@ arguments=(
   --headless-sha256 "$FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256"
 )
 if [ "$remove" -eq 1 ]; then
-  python3 "$project_root/lib/immutable-carrier.py" --remove "${arguments[@]}"
+  fresh_immutable_carrier --remove "${arguments[@]}"
   fresh_verify_sealed_headless_carrier "$carrier" || {
     echo 'carrier verification failed after immutable deployment removal' >&2
     exit 1
   }
 else
-  python3 "$project_root/lib/immutable-carrier.py" --deploy "${arguments[@]}"
+  fresh_immutable_carrier --deploy "${arguments[@]}"
   # The complete payload is verified again after +i, then the read-only
   # deployment verifier proves the receipt and every live immutable inode.
   fresh_capture_qualification_carrier_identity "$carrier" || {
     echo 'carrier verification failed after immutable deployment' >&2
     exit 1
   }
-  python3 "$project_root/lib/immutable-carrier.py" --verify "${arguments[@]}"
+  fresh_immutable_carrier --verify "${arguments[@]}"
 fi
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/package-portable-build-inputs.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/package-portable-build-inputs.sh
similarity index 90%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/package-portable-build-inputs.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/package-portable-build-inputs.sh
index 6c13d21ad..2ee480a05 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/package-portable-build-inputs.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/package-portable-build-inputs.sh
@@ -36,7 +36,7 @@ done < <(find "$probes_dir" -maxdepth 1 -type f \
   exit 2
 }
 
-actual_guest_identity="$(python3 "$project_root/lib/guest_build_provenance.py" identity "$guest_dir")"
+actual_guest_identity="$(bun "$project_root/lib/guest-build-provenance.mts" identity "$guest_dir")"
 expected_guest_identity="$(fresh_manifest_value "$guest_dir/guest-build.receipt" installed_closure_sha256)"
 [ "$actual_guest_identity" = "$expected_guest_identity" ] || {
   echo 'portable guest bytes differ from their build receipt' >&2
@@ -55,10 +55,10 @@ mkdir -p "$stage/portable-inputs/install" "$stage/portable-inputs/runtime/build"
 cp -a "$guest_dir" "$stage/portable-inputs/install/wasix-core-release-o3"
 cp -a "$sysroot_dir" "$stage/portable-inputs/runtime/build/patched-wasixcc-sysroot"
 cp -a "$probes_dir" "$stage/portable-inputs/runtime/build/probes"
-node "$repo_root/src/shared/artifact-packaging/materialize-release-symlinks.mjs" \
+bun "$repo_root/tools/packaging/materialize-release-symlinks.mts" \
   "$stage/portable-inputs"
 
-node "$repo_root/src/shared/artifact-packaging/archive-directory.mjs" \
+bun "$repo_root/tools/packaging/archive-directory.mts" \
   --keep-parent "$stage/portable-inputs" "$archive"
 chmod 0444 "$archive"
 printf 'packaged portable WASIX postmaster build inputs: %s\n' "$archive"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/package-release-assets.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/package-release-assets.sh
similarity index 87%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/package-release-assets.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/package-release-assets.sh
index 860caff4f..de2b57484 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/package-release-assets.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/package-release-assets.sh
@@ -58,18 +58,10 @@ fi
 }
 carrier_dir="$(cd "$carrier_dir" && pwd -P)"
 "$project_root/bin/verify-sealed-headless-carrier.sh" "$carrier_dir"
-python3 - "$carrier_dir/manifest.json" "$expected_target_triple" <<'PY'
-import json
-import pathlib
-import sys
-
-manifest = json.loads(pathlib.Path(sys.argv[1]).read_text(encoding="utf-8"))
-if manifest.get("target-triple") != sys.argv[2]:
-    raise SystemExit(
-        "sealed carrier target differs from release target: "
-        f"expected {sys.argv[2]}, got {manifest.get('target-triple')!r}"
-    )
-PY
+[ "$(fresh_manifest_value "$carrier_dir/wasmer-build.receipt" rustc_host)" = "$expected_target_triple" ] || {
+  echo 'sealed carrier target differs from release target' >&2
+  exit 2
+}
 
 version="$(tr -d '\r\n' <"$project_root/VERSION")"
 [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
@@ -99,7 +91,7 @@ cp -p "$repo_root/LICENSE" "$package_root/LICENSE"
 cp -p "$repo_root/THIRD_PARTY_NOTICES.md" "$package_root/THIRD_PARTY_NOTICES.md"
 cp -p "$project_root/README.md" "$package_root/README.md"
 
-node "$repo_root/src/shared/artifact-packaging/archive-directory.mjs" \
+bun "$repo_root/tools/packaging/archive-directory.mts" \
   --keep-parent "$package_root" "$asset_dir/$asset_name"
 asset_sha256="$(fresh_wasmer_bin_hash "$asset_dir/$asset_name")"
 asset_size="$(wc -c <"$asset_dir/$asset_name" | tr -d '[:space:]')"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/precompile-wasix-core.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/precompile-wasix-core.sh
similarity index 97%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/precompile-wasix-core.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/precompile-wasix-core.sh
index 1635732c1..ec09fe3e3 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/precompile-wasix-core.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/precompile-wasix-core.sh
@@ -26,7 +26,7 @@ fresh_require_patched_postmaster_compiler \
 compiler_hash="$(fresh_wasmer_bin_hash "$compiler_bin")"
 compiler_cache_dir="$(fresh_wasmer_cache_dir "$compiler_bin")"
 cache_bucket="$compiler_cache_dir/compiled/$(fresh_wasmer_compiler_cache_bucket llvm aggressive "$FRESH_WASMER_ARTIFACT_ABI_VERSION")"
-side_policy="$FRESH_ROOT/runtime/policies/sealed-side-modules.v1.tsv"
+side_policy="$FRESH_ROOT/wasmer/policies/sealed-side-modules.v1.tsv"
 compiler_threads="${WASMER_COMPILER_THREADS:-$(fresh_jobs)}"
 wasmer_dir="$FRESH_WORK_ROOT/tools/wasmer-home"
 log="$REPORT_DIR/wasix-core-precompile.log"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/prepare-baseline.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/prepare-baseline.sh
similarity index 94%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/prepare-baseline.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/prepare-baseline.sh
index 1f3b99bb7..286db4319 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/prepare-baseline.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/prepare-baseline.sh
@@ -3,7 +3,7 @@
 set -euo pipefail
 
 source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/common.sh"
-source "$REPO_ROOT/src/postgres/versions/18/fetch-source.sh"
+source "$REPO_ROOT/src/third-party/postgres/fetch-source.sh"
 
 print_path=0
 refresh=0
@@ -16,18 +16,6 @@ while [ "$#" -gt 0 ]; do
   shift
 done
 
-read_toml_value() {
-  local key="$1"
-  awk -F'=' -v key="$key" '
-    $1 ~ "^[[:space:]]*" key "[[:space:]]*$" {
-      gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2)
-      gsub(/^"|"$/, "", $2)
-      print $2
-      exit
-    }
-  ' "$POSTGRES_SOURCE_TOML"
-}
-
 sha256_file() {
   if command -v shasum >/dev/null 2>&1; then
     shasum -a 256 "$1" | awk '{print $1}'
@@ -48,9 +36,9 @@ fresh_require_managed_generated_path "$BASELINE_DIR" BASELINE_DIR
 # baseline, so no process can observe a partially replaced checkout.
 fresh_lock_postgres_baseline exclusive
 
-manifest_version="$(read_toml_value version)"
-manifest_url="$(read_toml_value url)"
-manifest_sha256="$(read_toml_value sha256)"
+manifest_version="$(fresh_source_scalar "$POSTGRES_SOURCE_TOML" version)"
+manifest_url="$(fresh_source_scalar "$POSTGRES_SOURCE_TOML" url)"
+manifest_sha256="$(fresh_source_scalar "$POSTGRES_SOURCE_TOML" sha256)"
 [ "$manifest_version" = "$POSTGRES_VERSION" ] || {
   echo "PostgreSQL version mismatch: common=$POSTGRES_VERSION manifest=$manifest_version" >&2
   exit 1
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-release-carrier.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-release-carrier.sh
new file mode 100755
index 000000000..1674bef3a
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-release-carrier.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
+source "$project_root/lib/common.sh"
+source "$project_root/lib/sealed-carrier.sh"
+
+carrier="$(fresh_select_current_sealed_carrier)"
+target="$(fresh_release_target)"
+
+bash "$project_root/bin/build-native-client-tools.sh"
+exec bash "$project_root/bin/qualify-wasix-immediate-recovery.sh" \
+  --target "$target" \
+  --sealed-carrier "$carrier" "$@"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-wasix-immediate-recovery.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-wasix-immediate-recovery.sh
similarity index 93%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-wasix-immediate-recovery.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-wasix-immediate-recovery.sh
index 81ae87755..13a900c40 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-wasix-immediate-recovery.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-wasix-immediate-recovery.sh
@@ -28,8 +28,8 @@ Options:
                              macos-arm64.
   --immutable-carrier-receipt FILE
                              External receipt created by
-                             deploy-immutable-sealed-carrier.sh. Required on
-                             Linux; unsupported on macOS.
+                             deploy-immutable-sealed-carrier.sh. Opts into
+                             Linux immutable-deployment qualification.
   --cgroup-memory-max SIZE   Finite MemoryMax for each postmaster server tree.
   --cgroup-memory-high SIZE  Finite MemoryHigh for each postmaster server tree.
   --cgroup-swap-max SIZE     Finite MemorySwapMax for each postmaster server
@@ -57,7 +57,8 @@ Both release targets require full cryptographic carrier verification at both
 campaign boundaries, continuity checks before every execution, an exact
 population of one outer initdb and three outer postgres executor invocations,
 and loader evidence for every activated module (including initdb's bootstrap
-postgres and dynamic modules). Linux additionally requires immutable-inode
+postgres and dynamic modules). Ordinary qualification uses unprivileged sealed
+activation. An immutable receipt additionally requires Linux immutable-inode
 activation and proven MemoryMax/MemoryHigh/MemorySwapMax membership. macOS
 requires private streamed-copy activation with no source writes or sync calls.
 USAGE
@@ -192,21 +193,7 @@ validate_cgroup_size() {
 }
 
 cgroup_size_to_bytes() {
-  python3 - "$1" <<'PY'
-import re
-import sys
-
-match = re.fullmatch(r"([0-9]+)([KMGTPE])?(?:i?B)?", sys.argv[1])
-if match is None:
-    raise SystemExit(2)
-value = int(match.group(1))
-suffix = match.group(2)
-if suffix is not None:
-    value *= 1024 ** ("KMGTPE".index(suffix) + 1)
-if value > 2**63 - 1:
-    raise SystemExit(2)
-print(value)
-PY
+  bun "$FRESH_ROOT/lib/server-lifecycle.mts" size "$1"
 }
 
 [ -n "$sealed_carrier" ] || { echo "--sealed-carrier is required" >&2; exit 2; }
@@ -221,9 +208,14 @@ release_target="${release_target:-$host_target}"
 }
 case "$release_target" in
   linux-arm64-gnu|linux-x64-gnu)
-    hardened_qualification=1
-    boundary_verification_scope=full-cryptographic-plus-immutable-receipt
-    required_snapshot_policy=direct-immutable
+    hardened_qualification=0
+    boundary_verification_scope=full-cryptographic
+    required_snapshot_policy=compatible
+    if [ -n "$immutable_carrier_receipt" ]; then
+      hardened_qualification=1
+      boundary_verification_scope=full-cryptographic-plus-immutable-receipt
+      required_snapshot_policy=direct-immutable
+    fi
     ;;
   macos-arm64)
     hardened_qualification=0
@@ -266,11 +258,11 @@ if [ "$hardened_qualification" -eq 1 ]; then
     echo "--immutable-carrier-receipt is required on Linux" >&2
     exit 2
   }
-elif [ "$cgroup_enabled" -eq 1 ] || [ -n "$immutable_carrier_receipt" ]; then
+elif [ "$release_target" = macos-arm64 ] && { [ "$cgroup_enabled" -eq 1 ] || [ -n "$immutable_carrier_receipt" ]; }; then
   echo "immutable-carrier receipts and Linux cgroup controls are unsupported on macOS" >&2
   exit 2
 fi
-fresh_require_command python3
+fresh_require_command bun
 if [ "$cgroup_enabled" -eq 1 ]; then
   cgroup_memory_max_bytes="$(cgroup_size_to_bytes "$cgroup_memory_max")" || {
     echo "--cgroup-memory-max exceeds the supported finite range" >&2
@@ -392,7 +384,7 @@ mkdir -p "$pgdata" "$dev_shm"
 profile_inputs="$report_dir/postgres-profile-inputs.tsv"
 profile_resolution="$report_dir/postgres-profile-resolution.tsv"
 fresh_write_postgres_profile_evidence "$profile_inputs" "$profile_resolution"
-loader_validator="$FRESH_ROOT/bin/validate-sealed-loader-audit.py"
+loader_validator="$FRESH_ROOT/bin/validate-sealed-loader-audit.mts"
 loader_validator_sha256="$(fresh_wasmer_bin_hash "$loader_validator")"
 sealed_loader_audit="$report_dir/sealed-loader-audit.jsonl"
 sealed_loader_validation="$report_dir/sealed-loader-audit-validation.tsv"
@@ -940,63 +932,7 @@ signal_active_server() {
   fresh_signal_owned_pid "$signal" "$active_pid" "$active_identity"
 }
 
-wait_for_unassisted_exit() {
-  local exit_evidence="$1"
-  local deadline wait_status group_deadline cgroup_empty=not-requested
 
-  deadline=$(( $(fresh_supervision_now_ms) + timeout_seconds * 1000 ))
-  while fresh_supervision_pid_running "$active_pid"; do
-    if ! fresh_pid_matches_birth_identity "$active_pid" "$active_identity"; then
-      # The leader can exit between the liveness check above and reading its
-      # immutable birth identity.  Only classify an identity mismatch as PID
-      # reuse when the numeric PID is still live after that failed read.
-      fresh_supervision_pid_running "$active_pid" && return 125
-      break
-    fi
-    [ "$(fresh_supervision_now_ms)" -lt "$deadline" ] || {
-      printf 'server did not exit after bridged signal without escalation\n' >&2
-      return 124
-    }
-    sleep 0.05
-  done
-  fresh_reap_process_group_leader "$active_pid"
-  wait_status="$FRESH_PROCESS_GROUP_WAIT_STATUS"
-  group_deadline=$(( $(fresh_supervision_now_ms) + timeout_seconds * 1000 ))
-  while fresh_process_group_exists "$active_pgid"; do
-    [ "$(fresh_supervision_now_ms)" -lt "$group_deadline" ] || {
-      printf 'server process group remained after leader exit: %s\n' "$active_pgid" >&2
-      return 124
-    }
-    sleep 0.05
-  done
-  if [ -n "$active_cgroup_dir" ] && [ -n "$active_cgroup_identity" ]; then
-    fresh_wait_cgroup_empty "$active_cgroup_dir" "$active_cgroup_identity" \
-      "$((timeout_seconds * 1000))"
-    cgroup_empty=true
-  fi
-  fresh_wait_tcp_port_closed 127.0.0.1 "$port" "$((timeout_seconds * 1000))"
-  [ -z "$(find "$dev_shm" -mindepth 1 -print -quit)" ] || {
-    printf 'shared objects survived normal guest shutdown: %s\n' "$dev_shm" >&2
-    return 1
-  }
-  [ "$wait_status" -eq 0 ] || {
-    printf 'server leader exited nonzero after unassisted guest shutdown: phase=%s status=%s\n' \
-      "$active_phase" "$wait_status" >&2
-    return 1
-  }
-  {
-    printf 'phase\twait_status\tprocess_group_empty\tcgroup_empty\tport_closed\tshared_objects_empty\tescalation_used\n'
-    printf '%s\t%s\ttrue\t%s\ttrue\ttrue\tfalse\n' \
-      "$active_phase" "$wait_status" "$cgroup_empty"
-  } >"$exit_evidence"
-  active_pid=""
-  active_pgid=""
-  active_identity=""
-  active_phase=""
-  active_cgroup_unit=""
-  active_cgroup_dir=""
-  active_cgroup_identity=""
-}
 
 snapshot_carrier before-initdb
 current_stage="initdb"
@@ -1146,13 +1082,25 @@ grep -Fq 'received smart shutdown request' "$report_dir/clean-reopen.server.log"
 snapshot_carrier final
 
 current_stage="sealed-loader-validation"
-python3 "$loader_validator" \
+loader_validation_payload="$(bun "$loader_validator" \
   --audit "$sealed_loader_audit" \
   --manifest "$sealed_manifest" \
-  --output "$sealed_loader_validation" \
   --snapshot-policy "$required_snapshot_policy" \
   --expected-initdb-executions 1 \
-  --expected-postgres-executions 3
+  --expected-postgres-executions 3)"
+loader_validation_pending="$report_dir/.loader-validation.pending.$$"
+publication_tool="$FRESH_ROOT/lib/durable-publication.mts"
+loader_validation_identity="$(printf '%s\n' "$loader_validation_payload" |
+  bun "$publication_tool" write-stdin-identified "$loader_validation_pending")"
+read -r validation_dev validation_ino validation_size validation_sha <<<"$loader_validation_identity"
+if ! bun "$publication_tool" publish-identified "$loader_validation_pending" "$sealed_loader_validation" \
+  "$validation_dev" "$validation_ino" "$validation_size" "$validation_sha"; then
+  bun "$publication_tool" remove-private-identified "$loader_validation_pending" \
+    "$validation_dev" "$validation_ino" "$validation_size" "$validation_sha"
+  exit 1
+fi
+bun "$publication_tool" remove-private-identified "$loader_validation_pending" \
+  "$validation_dev" "$validation_ino" "$validation_size" "$validation_sha"
 chmod 0444 "$sealed_loader_audit" "$sealed_loader_validation"
 
 current_stage="campaign-end-verification"
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-wasix-immediate-recovery.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-wasix-immediate-recovery.test.sh
new file mode 100755
index 000000000..564161409
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-wasix-immediate-recovery.test.sh
@@ -0,0 +1,110 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+qualifier="$root/bin/qualify-wasix-immediate-recovery.sh"
+test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-immediate-recovery-test.XXXXXX")"
+trap 'rm -rf -- "$test_root"' EXIT HUP INT TERM
+
+"$qualifier" --help >/dev/null
+source "$root/lib/server-lifecycle.sh"
+
+fresh_supervision_now_ms() {
+  printf '1000\n'
+}
+
+fresh_supervision_pid_running() {
+  return 1
+}
+
+fresh_pid_matches_birth_identity() {
+  return 0
+}
+
+fresh_reap_process_group_leader() {
+  FRESH_PROCESS_GROUP_WAIT_STATUS="$fixture_wait_status"
+}
+
+fresh_process_group_exists() {
+  return 1
+}
+
+fresh_wait_tcp_port_closed() {
+  return 0
+}
+
+reset_fixture() {
+  fixture_wait_status="$1"
+  active_pid=4242
+  active_pgid=4242
+  active_identity=linux-starttime:303
+  active_phase=fixture-shutdown
+}
+
+timeout_seconds=1
+port=15432
+dev_shm="$test_root/dev-shm"
+active_cgroup_unit=""
+active_cgroup_dir=""
+active_cgroup_identity=""
+mkdir -p "$dev_shm"
+
+reset_fixture 17
+set +e
+wait_for_unassisted_exit "$test_root/nonzero-exit.tsv" \
+  >"$test_root/nonzero.out" 2>"$test_root/nonzero.err"
+status=$?
+set -e
+[ "$status" -eq 1 ] || {
+  printf 'expected nonzero leader status to reject recovery evidence, got %s\n' \
+    "$status" >&2
+  exit 1
+}
+[ ! -e "$test_root/nonzero-exit.tsv" ] || {
+  printf 'nonzero leader status produced successful recovery evidence\n' >&2
+  exit 1
+}
+[ "$active_pid" = 4242 ]
+[ "$active_pgid" = 4242 ]
+[ "$active_identity" = linux-starttime:303 ]
+[ "$active_phase" = fixture-shutdown ]
+
+reset_fixture 0
+wait_for_unassisted_exit "$test_root/zero-exit.tsv"
+awk -F '\t' '
+  NR == 1 {
+    valid = ($1 == "phase" && $2 == "wait_status" &&
+      $3 == "process_group_empty" && $4 == "cgroup_empty" &&
+      $5 == "port_closed" && $6 == "shared_objects_empty" &&
+      $7 == "escalation_used")
+  }
+  NR == 2 {
+    valid = valid && ($1 == "fixture-shutdown" && $2 == "0" &&
+      $3 == "true" && $4 == "not-requested" && $5 == "true" &&
+      $6 == "true" && $7 == "false")
+  }
+  END { exit !(valid && NR == 2) }
+' "$test_root/zero-exit.tsv"
+[ -z "$active_pid" ]
+[ -z "$active_pgid" ]
+[ -z "$active_identity" ]
+[ -z "$active_phase" ]
+
+fresh_wait_cgroup_empty() {
+  [ "$1" = "$test_root/fake-cgroup" ]
+  [ "$2" = 42:99 ]
+  [ "$3" = 1000 ]
+  cgroup_wait_called=1
+}
+reset_fixture 0
+active_cgroup_unit=oliphaunt-recovery-fixture
+active_cgroup_dir="$test_root/fake-cgroup"
+active_cgroup_identity=42:99
+cgroup_wait_called=0
+wait_for_unassisted_exit "$test_root/cgroup-exit.tsv"
+[ "$cgroup_wait_called" -eq 1 ]
+awk -F '\t' 'NR == 2 { exit !($4 == "true") }' \
+  "$test_root/cgroup-exit.tsv"
+
+printf 'immediate recovery exit tests passed\n'
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/regress-suite-name.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/regress-suite-name.test.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/regress-suite-name.test.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/regress-suite-name.test.sh
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/run-release-carrier.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/run-release-carrier.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/run-release-carrier.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/run-release-carrier.sh
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/run-release-carrier.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/run-release-carrier.test.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/run-release-carrier.test.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/run-release-carrier.test.sh
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/run-wasix-regress-subset.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/run-wasix-regress-subset.sh
similarity index 98%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/run-wasix-regress-subset.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/run-wasix-regress-subset.sh
index 6f45d4b1d..39f295b0f 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/run-wasix-regress-subset.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/run-wasix-regress-subset.sh
@@ -39,6 +39,7 @@ pg_regress_bin="$CLIENT_TOOLS_BUILD_DIR/src/test/regress/pg_regress"
 "$FRESH_ROOT/bin/build-native-client-tools.sh" >/dev/null
 if [ ! -x "$WASIX_INSTALL_DIR/bin/postgres" ]; then
   "$FRESH_ROOT/bin/build-wasix-core.sh"
+  WASIX_INSTALL_DIR="$(fresh_wasix_core_install_dir_for "$WASIX_CORE_PROFILE")"
 fi
 fresh_lock_postgres_baseline shared
 baseline_fingerprint="$(fresh_postgres_baseline_fingerprint)"
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-core-exports.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-core-exports.sh
new file mode 100755
index 000000000..908f3751c
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-core-exports.sh
@@ -0,0 +1,234 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/common.sh"
+
+usage() {
+  cat <<'EOF'
+Usage: seal-wasix-core-exports.sh [options]
+
+Derive the exact typed PostgreSQL main-module export closure from the packaged
+side modules, remove unreachable definitions with one pinned Binaryen pass,
+re-run the start/import/fence proofs, and publish the module plus receipts.
+
+Options:
+  --install-dir DIR       WASIX PostgreSQL prefix (default: WASIX_INSTALL_DIR)
+  --expected-total COUNT  Exact final atomic.fence count for the packed latch proof
+  -h, --help              Show this help
+EOF
+}
+
+fail() {
+  printf 'sealed export closure: %s\n' "$*" >&2
+  exit 2
+}
+
+install_dir="$WASIX_INSTALL_DIR"
+expected_total=""
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --install-dir|--expected-total)
+      option="$1"
+      shift
+      [ "$#" -gt 0 ] || fail "$option requires a value"
+      case "$option" in
+        --install-dir) install_dir="$1" ;;
+        --expected-total) expected_total="$1" ;;
+      esac
+      ;;
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    *) fail "unknown argument: $1" ;;
+  esac
+  shift
+done
+
+case "$expected_total" in
+  ''|*[!0-9]*) fail '--expected-total must be a nonnegative integer' ;;
+esac
+
+fresh_require_command cargo
+fresh_require_command cmp
+fresh_require_command cp
+fresh_require_command find
+fresh_require_command grep
+fresh_require_command bun
+fresh_require_command sha256sum
+fresh_require_command sort
+
+[ -d "$install_dir" ] && [ ! -L "$install_dir" ] || fail "missing regular install prefix: $install_dir"
+install_dir="$(cd "$install_dir" && pwd -P)"
+postgres="$install_dir/bin/postgres"
+[ -f "$postgres" ] && [ ! -L "$postgres" ] || fail "missing regular PostgreSQL module: $postgres"
+fresh_require_managed_generated_path "$postgres" sealed-postgres-module
+
+[ "${FRESH_WASIX_PRIVATE_INSTALL_DIR:-}" = "$install_dir" ] && [ ! -e "$install_dir/guest-build.receipt" ] ||
+  fail "export sealing requires the producer private install directory"
+stage="$install_dir/.oliphaunt-sealed-export-closure.pending"
+[ ! -e "$stage" ] && [ ! -L "$stage" ] || fail "private export stage already exists"
+mkdir -p "$stage/bin" "$stage/share/postgresql"
+trap 'rm -rf -- "$stage"' EXIT
+
+readonly tool_manifest="$FRESH_ROOT/tools/sealed-export-closure/Cargo.toml"
+readonly mandatory_policy="$FRESH_ROOT/wasmer/policies/sealed-main-runtime-exports.v1.txt"
+readonly dlsym_policy="$FRESH_ROOT/wasmer/policies/sealed-main-dlsym-exports.v1.txt"
+readonly side_manifest="$FRESH_ROOT/wasmer/policies/sealed-side-modules.v1.tsv"
+for required in "$tool_manifest" "$mandatory_policy" "$dlsym_policy" "$side_manifest"; do
+  [ -f "$required" ] && [ ! -L "$required" ] || fail "missing regular closure input: $required"
+done
+grep -Fxq '# schema=oliphaunt.wasix-postmaster.sealed-side-modules.v1' "$side_manifest" ||
+  fail 'side-module manifest schema differs'
+
+declare -a side_modules=()
+declare -A admitted_side_paths=()
+manifest_records=0
+while IFS=$'\t' read -r canonical aliases abi_policy extra; do
+  case "$canonical" in
+    ''|'#'*) continue ;;
+  esac
+  [ -z "${extra:-}" ] || fail "side-module manifest has extra columns: $canonical"
+  [ -n "$aliases" ] && [ -n "$abi_policy" ] || fail "incomplete side-module record: $canonical"
+  case "$canonical" in
+    /*|*/../*|../*|*/./*|./*|*//*|*[$'\n\r']*) fail "unsafe canonical side path: $canonical" ;;
+  esac
+  [ -z "${admitted_side_paths[$canonical]+x}" ] || fail "duplicate side path: $canonical"
+  canonical_file="$install_dir/$canonical"
+  [ -f "$canonical_file" ] && [ ! -L "$canonical_file" ] ||
+    fail "missing regular canonical side module: $canonical"
+  admitted_side_paths[$canonical]=1
+  side_modules+=("$canonical")
+  manifest_records=$((manifest_records + 1))
+  if [ "$aliases" != - ]; then
+    IFS=',' read -r -a alias_paths <<<"$aliases"
+    [ "${#alias_paths[@]}" -gt 0 ] || fail "empty alias set: $canonical"
+    for alias_path in "${alias_paths[@]}"; do
+      case "$alias_path" in
+        ''|/*|*/../*|../*|*/./*|./*|*//*|*[$'\n\r']*) fail "unsafe side alias: $alias_path" ;;
+      esac
+      [ -z "${admitted_side_paths[$alias_path]+x}" ] || fail "duplicate side alias: $alias_path"
+      alias_file="$install_dir/$alias_path"
+      [ -f "$alias_file" ] || fail "missing side alias: $alias_path"
+      cmp -s "$canonical_file" "$alias_file" ||
+        fail "side alias bytes differ from $canonical: $alias_path"
+      admitted_side_paths[$alias_path]=1
+    done
+  fi
+done <"$side_manifest"
+[ "$manifest_records" -gt 0 ] || fail 'side-module manifest has no records'
+
+find "$install_dir/lib" \( -type f -o -type l \) \
+  \( -name '*.so' -o -name '*.so.*' \) -printf '%P\0' >"$stage/discovered-side-modules.unsorted"
+LC_ALL=C sort -z "$stage/discovered-side-modules.unsorted" >"$stage/discovered-side-modules.sorted"
+while IFS= read -r -d '' discovered; do
+  relative="lib/$discovered"
+  [ -n "${admitted_side_paths[$relative]+x}" ] ||
+    fail "installed side module is absent from the sealed graph: $relative"
+done <"$stage/discovered-side-modules.sorted"
+
+tool_target="$FRESH_WORK_ROOT/runtime/sealed-export-closure-target"
+fresh_require_managed_generated_path "$tool_target" sealed-export-closure-tool-target
+CARGO_TARGET_DIR="$tool_target" cargo build --locked --release --manifest-path "$tool_manifest"
+closure_tool="$tool_target/release/oliphaunt-wasix-sealed-export-closure"
+[ -x "$closure_tool" ] && [ ! -L "$closure_tool" ] || fail "missing built closure analyzer: $closure_tool"
+
+docker_bin="$(fresh_docker_bin)"
+fresh_ensure_docker_image
+docker_image_id="$(fresh_wasix_builder_image_id)" ||
+  fail 'could not resolve pinned WASIX builder image identity'
+readonly container_wasm_opt=/opt/wasixcc-home/.wasixcc/binaryen/bin/wasm-opt
+dce_identity="$($docker_bin run --rm "$docker_image_id" sha256sum "$container_wasm_opt")" ||
+  fail 'could not hash pinned wasm-opt'
+dce_sha256="${dce_identity%% *}"
+fresh_is_sha256 "$dce_sha256" || fail "invalid wasm-opt SHA-256: $dce_sha256"
+dce_version="$($docker_bin run --rm "$docker_image_id" "$container_wasm_opt" --version)" ||
+  fail 'could not read pinned wasm-opt version'
+[ "$(printf '%s\n' "$dce_version" | wc -l | tr -d ' ')" -eq 1 ] || fail 'wasm-opt version is multiline'
+
+cp -p "$postgres" "$stage/bin/postgres.seed"
+seed_proof="$stage/share/postgresql/wasix-postmaster.sealed-export.seed-proof.json"
+final_proof="$stage/share/postgresql/wasix-postmaster.sealed-export.final-proof.json"
+allowlist="$stage/share/postgresql/wasix-postmaster.sealed-export.allowlist"
+structure_receipt="$stage/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
+start_proof="$stage/share/postgresql/wasix-postmaster.sealed-export.start-proof.intermediate.json"
+concurrency_receipt="$stage/share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt"
+
+side_manifest_sha256="$(sha256sum "$side_manifest" | awk '{print $1}')"
+
+(
+  cd "$install_dir"
+  "$closure_tool" seal \
+    bin/postgres \
+    "$mandatory_policy" \
+    "$dlsym_policy" \
+    "$seed_proof" \
+    "$allowlist" \
+    "${side_modules[@]}"
+  "$closure_tool" rewrite \
+    bin/postgres \
+    "$allowlist" \
+    .oliphaunt-sealed-export-closure.pending/bin/postgres.stripped
+)
+
+docker_stage="$(fresh_docker_path_for "$stage")"
+"$docker_bin" run --rm \
+  --user "$(id -u):$(id -g)" \
+  -v "$REPO_ROOT:/work" \
+  -w /work \
+  "$docker_image_id" \
+  "$container_wasm_opt" \
+  "$docker_stage/bin/postgres.stripped" \
+  --remove-unused-module-elements \
+  --enable-bulk-memory \
+  --enable-threads \
+  --enable-mutable-globals \
+  --enable-exception-handling \
+  --enable-extended-const \
+  -o "$docker_stage/bin/postgres"
+chmod --reference="$postgres" "$stage/bin/postgres"
+
+(
+  cd "$install_dir"
+  "$closure_tool" attest-final \
+    bin/postgres \
+    .oliphaunt-sealed-export-closure.pending/bin/postgres \
+    "$mandatory_policy" \
+    "$dlsym_policy" \
+    "$allowlist" \
+    "$seed_proof" \
+    "$final_proof" \
+    "$structure_receipt" \
+    "$dce_sha256" \
+    "$dce_version" \
+    "$side_manifest_sha256" \
+    "${side_modules[@]}"
+)
+
+bun "$FRESH_ROOT/wasmer/bin/verify-postmaster-wasm-import.mts" "$stage/bin/postgres"
+fresh_require_start_proof_tool "$FRESH_START_PROOF_BIN" "$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
+"$FRESH_START_PROOF_BIN" "$stage/bin/postgres" >"$start_proof"
+
+bash "$FRESH_ROOT/wasmer/bin/analyze-wasm-concurrency.sh" "$docker_bin" "$docker_image_id" \
+  "$stage/bin/postgres" \
+  --expected-total "$expected_total" \
+  --latch-state-contract packed-atomic-v1 \
+  --receipt "$stage/share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt"
+
+for artifact in \
+  "$seed_proof" \
+  "$final_proof" \
+  "$allowlist" \
+  "$structure_receipt" \
+  "$start_proof" \
+  "$concurrency_receipt"
+do
+  [ -f "$artifact" ] && [ ! -L "$artifact" ] || fail "missing staged receipt: $artifact"
+done
+
+# Only the complete install generation is published by build-wasix-core.sh.
+# A failure here discards that private generation; no live files need rollback.
+mv "$stage/bin/postgres" "$postgres"
+cp -p "$stage/share/postgresql/"* "$install_dir/share/postgresql/"
+printf 'sealed exact main-module export closure: module=%s\n' "$postgres"
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-linear-memory.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-linear-memory.sh
new file mode 100755
index 000000000..bddd47a27
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-linear-memory.sh
@@ -0,0 +1,157 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/common.sh"
+
+usage() {
+  cat <<'EOF'
+Usage: seal-wasix-linear-memory.sh [options]
+
+Seal every installed WASIX WebAssembly module to the versioned product memory
+ABI after all code-rewriting passes have completed.
+
+Options:
+  --install-dir DIR          WASIX PostgreSQL prefix (default: WASIX_INSTALL_DIR)
+  --predecessor-receipt FILE Exact sealed-export structural receipt
+  -h, --help                 Show this help
+EOF
+}
+
+fail() {
+  printf 'WASIX linear-memory sealer: %s\n' "$*" >&2
+  exit 2
+}
+
+install_dir="$WASIX_INSTALL_DIR"
+predecessor_receipt=""
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --install-dir|--predecessor-receipt)
+      option="$1"
+      shift
+      [ "$#" -gt 0 ] || fail "$option requires a value"
+      case "$option" in
+        --install-dir) install_dir="$1" ;;
+        --predecessor-receipt) predecessor_receipt="$1" ;;
+      esac
+      ;;
+    -h|--help)
+      usage
+      exit 0
+      ;;
+    *) fail "unknown argument: $1" ;;
+  esac
+  shift
+done
+
+[ -n "$predecessor_receipt" ] || fail '--predecessor-receipt is required'
+for command in bun find od sha256sum sort; do
+  fresh_require_command "$command"
+done
+[ -d "$install_dir" ] && [ ! -L "$install_dir" ] ||
+  fail "missing non-symlink install prefix: $install_dir"
+install_dir="$(cd "$install_dir" && pwd -P)"
+fresh_require_managed_generated_path "$install_dir" WASIX_INSTALL_DIR
+
+[ "${FRESH_WASIX_PRIVATE_INSTALL_DIR:-}" = "$install_dir" ] && [ ! -e "$install_dir/guest-build.receipt" ] ||
+  fail "memory sealing requires the producer private install directory"
+stage="$install_dir/.oliphaunt-linear-memory.pending"
+[ ! -e "$stage" ] && [ ! -L "$stage" ] || fail "private memory stage already exists"
+mkdir -p "$stage/modules" "$stage/receipts"
+trap 'rm -rf -- "$stage"' EXIT
+
+[ -f "$predecessor_receipt" ] && [ ! -L "$predecessor_receipt" ] ||
+  fail "missing regular predecessor receipt: $predecessor_receipt"
+predecessor_receipt="$(cd "$(dirname "$predecessor_receipt")" && pwd -P)/$(basename "$predecessor_receipt")"
+expected_predecessor="$install_dir/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
+[ "$predecessor_receipt" = "$expected_predecessor" ] ||
+  fail "predecessor receipt must be the canonical sealed-export receipt: $expected_predecessor"
+
+memory_tool="$FRESH_MEMORY_PROFILE_BIN"
+fresh_require_memory_profile_tool "$memory_tool" "$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
+aggregate_destination="$install_dir/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
+if [ -e "$aggregate_destination" ] || [ -L "$aggregate_destination" ]; then
+  [ -f "$aggregate_destination" ] && [ ! -L "$aggregate_destination" ] ||
+    fail "existing linear-memory receipt is not a regular file: $aggregate_destination"
+  bun "$FRESH_ROOT/lib/sealed-export-chain.mts" \
+    --install-root "$install_dir" \
+    --project-root "$FRESH_ROOT" \
+    --allow-linear-memory-descendant ||
+    fail 'existing linear-memory descendant proof chain is invalid'
+  module_list="$(bun "$FRESH_ROOT/lib/linear-memory-profile.mts" modules "$aggregate_destination")" ||
+    fail 'could not read existing module list'
+  while IFS= read -r relative; do
+    "$memory_tool" verify "$install_dir/$relative" >/dev/null
+  done <<< "$module_list"
+  printf 'WASIX linear-memory profile already sealed: receipt=%s\n' \
+    "$aggregate_destination"
+  exit 0
+fi
+
+bun "$FRESH_ROOT/lib/sealed-export-chain.mts" \
+  --install-root "$install_dir" \
+  --project-root "$FRESH_ROOT" ||
+  fail 'sealed-export predecessor proof chain is invalid'
+profile_json="$($memory_tool --profile-json)" || fail 'could not read memory-tool profile'
+predecessor_sha256="$(sha256sum "$predecessor_receipt" | awk '{print $1}')"
+fresh_is_sha256 "$predecessor_sha256" || fail 'predecessor receipt hash is invalid'
+predecessor_relative="${predecessor_receipt#"$install_dir"/}"
+
+index="$stage/modules.tsv"
+: >"$index"
+
+module_count=0
+module_paths="$stage/module-paths.nul"
+find "$install_dir/bin" "$install_dir/lib" -type f -print0 | \
+  LC_ALL=C sort -z >"$module_paths" ||
+  fail 'could not enumerate the installed WebAssembly module closure'
+while IFS= read -r -d '' module; do
+  magic="$(od -An -tx1 -N4 "$module" | tr -d ' \n')"
+  [ "$magic" = 0061736d ] || continue
+  relative="${module#"$install_dir"/}"
+  case "$relative" in
+    ''|/*|*/../*|../*|*/./*|./*|*//*|*$'\t'*|*$'\n'*|*$'\r'*)
+      fail "unsafe installed module path: $relative"
+      ;;
+  esac
+  output="$stage/modules/$relative"
+  receipt="$stage/receipts/$relative.json"
+  mkdir -p "$(dirname "$output")" "$(dirname "$receipt")"
+  "$memory_tool" seal --output "$output" --receipt "$receipt" "$module"
+  chmod --reference="$module" "$output"
+  printf '%s\t%s\n' "$relative" "${receipt#"$stage"/}" >>"$index"
+  module_count=$((module_count + 1))
+done <"$module_paths"
+[ "$module_count" -gt 0 ] || fail 'no installed WebAssembly modules were found'
+
+for required in \
+  bin/initdb \
+  bin/postgres \
+  lib/libpq.so.5.18 \
+  lib/postgresql/dict_snowball.so \
+  lib/postgresql/plpgsql.so
+do
+  awk -F '\t' -v expected="$required" '$1 == expected { count += 1 } END { exit count == 1 ? 0 : 1 }' "$index" ||
+    fail "required carrier module was not sealed exactly once: $required"
+done
+
+aggregate="$stage/wasix-postmaster.linear-memory-profile.receipt.json"
+PROFILE_JSON="$profile_json" bun "$FRESH_ROOT/lib/linear-memory-profile.mts" aggregate \
+  "$stage" "$index" "$predecessor_relative" "$predecessor_sha256" "$aggregate"
+
+[ "$(sha256sum "$predecessor_receipt" | awk '{print $1}')" = "$predecessor_sha256" ] ||
+  fail 'predecessor export receipt changed while modules were sealed'
+while IFS=$'\t' read -r relative receipt_relative; do
+  "$memory_tool" verify "$stage/modules/$relative" >/dev/null
+done <"$index"
+
+[ "$(sha256sum "$predecessor_receipt" | awk '{print $1}')" = "$predecessor_sha256" ] ||
+  fail 'predecessor export receipt changed before transaction preparation'
+
+while IFS=$'\t' read -r relative receipt_relative; do
+  mv "$stage/modules/$relative" "$install_dir/$relative"
+done <"$index"
+mv "$aggregate" "$aggregate_destination"
+printf 'sealed WASIX linear-memory profile: modules=%s receipt=%s\n' \
+  "$module_count" "$aggregate_destination"
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-linear-memory.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-linear-memory.test.sh
new file mode 100755
index 000000000..bb91c75dd
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-linear-memory.test.sh
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
+source "$project_root/lib/common.sh"
+memory_tool="$FRESH_MEMORY_PROFILE_BIN"
+[ -f "$memory_tool" ] && [ -x "$memory_tool" ] || {
+  printf 'missing executable memory-profile tool: %s\n' "$memory_tool" >&2
+  exit 2
+}
+repo_root="$(cd "$project_root/../../.." && pwd -P)"
+mkdir -p "$repo_root/target/oliphaunt-wasix-postmaster"
+test_root="$(mktemp -d "$repo_root/target/oliphaunt-wasix-postmaster/linear-memory-test.XXXXXX")"
+cleanup() {
+  chmod -R u+w "$test_root" 2>/dev/null || true
+  rm -rf -- "$test_root"
+}
+trap cleanup EXIT
+
+make_fixture() {
+  local name="$1"
+  local root="$test_root/$name"
+  local receipt="$root/executor.receipt"
+  mkdir -p \
+    "$root/install/bin" \
+    "$root/install/lib/postgresql" \
+    "$root/install/share/postgresql"
+  for relative in bin/initdb bin/postgres lib/libpq.so.5.18 lib/postgresql/dict_snowball.so lib/postgresql/plpgsql.so; do
+    printf '\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x12\x01\x03\x65\x6e\x76\x06\x6d\x65\x6d\x6f\x72\x79\x02\x03\x01\x80\x80\x04' >"$root/install/$relative"
+    chmod 0755 "$root/install/$relative"
+  done
+  bun "$project_root/testdata/make-sealed-export-fixture.mts" \
+    --install-root "$root/install" \
+    --project-root "$project_root"
+  cp "$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT" "$receipt"
+  printf '%s\n' "$root"
+}
+
+invoke() {
+  local root="$1"
+  FRESH_WORK_ROOT="$test_root/work" \
+  WASIX_INSTALL_DIR="$root/install" \
+  FRESH_WASIX_PRIVATE_INSTALL_DIR="$root/install" \
+  FRESH_MEMORY_PROFILE_BIN="$memory_tool" \
+  FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT="$root/executor.receipt" \
+    "$project_root/bin/seal-wasix-linear-memory.sh" \
+      --install-dir "$root/install" \
+      --predecessor-receipt \
+        "$root/install/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
+}
+
+success_root="$(make_fixture success)"
+invoke "$success_root"
+module_paths="$(bun "$project_root/lib/linear-memory-profile.mts" modules "$success_root/install/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json")"
+[ "$(printf '%s\n' "$module_paths" | wc -l | tr -d '[:space:]')" = 29 ]
+printf '%s\n' "$module_paths" | LC_ALL=C sort -c
+while IFS= read -r relative; do
+  "$memory_tool" verify "$success_root/install/$relative" >/dev/null
+done <<<"$module_paths"
+receipt_before="$(sha256sum "$success_root/install/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json" | awk '{print $1}')"
+invoke "$success_root" >/dev/null
+receipt_after="$(sha256sum "$success_root/install/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json" | awk '{print $1}')"
+[ "$receipt_before" = "$receipt_after" ] || {
+  echo 'idempotent linear-memory sealing changed the aggregate receipt' >&2
+  exit 1
+}
+
+
+# Completed generations must never be rewritten by standalone sealers.
+printf 'admitted guest\n' >"$success_root/install/guest-build.receipt"
+if invoke "$success_root" >/dev/null 2>&1; then
+  echo 'memory sealer accepted a published generation' >&2
+  exit 1
+fi
+[ "$(sha256sum "$success_root/install/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json" | awk '{print $1}')" = "$receipt_before" ]
+
+invalid_root="$(make_fixture invalid)"
+printf 'invalid module\n' >"$invalid_root/install/bin/initdb"
+if invoke "$invalid_root" >/dev/null 2>&1; then
+  echo 'memory sealer accepted a broken predecessor chain' >&2
+  exit 1
+fi
+[ ! -e "$invalid_root/install/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json" ]
+printf 'WASIX private linear-memory sealer tests passed\n'
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-concurrent-connections.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-concurrent-connections.sh
similarity index 95%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-concurrent-connections.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-concurrent-connections.sh
index dcd449232..35cd67950 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-concurrent-connections.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-concurrent-connections.sh
@@ -186,6 +186,8 @@ elif [ ! -x "$WASIX_INSTALL_DIR/bin/postgres" ] || [ ! -x "$WASIX_INSTALL_DIR/bi
     exit 2
   fi
   "$FRESH_ROOT/bin/build-wasix-core.sh" >/dev/null
+  WASIX_INSTALL_DIR="$(fresh_wasix_core_install_dir_for "$WASIX_CORE_PROFILE")"
+  runtime_root="$WASIX_INSTALL_DIR"
 fi
 
 if [ -n "$sealed_carrier" ]; then
@@ -262,40 +264,6 @@ fresh_write_report_header "$summary" "WASIX Concurrent Connections Smoke"
 } >>"$summary"
 printf 'client\tstatus\tlog\n' >"$summary_tsv"
 
-run_logged_timeout() {
-  local timeout_seconds="$1"
-  shift
-  local log="$1"
-  shift
-  local pid started elapsed status
-
-  "$@" >"$log" 2>&1 &
-  pid=$!
-  started="$(date +%s)"
-  while kill -0 "$pid" 2>/dev/null; do
-    elapsed=$(( $(date +%s) - started ))
-    if [ "$elapsed" -ge "$timeout_seconds" ]; then
-      {
-        printf '\ncommand timed out after %s seconds\n' "$timeout_seconds"
-        printf 'command:'
-        printf ' %q' "$@"
-        printf '\n'
-      } >>"$log"
-      kill "$pid" 2>/dev/null || true
-      sleep 0.5
-      kill -9 "$pid" 2>/dev/null || true
-      wait "$pid" 2>/dev/null || true
-      return 124
-    fi
-    sleep 0.1
-  done
-  if wait "$pid"; then
-    return 0
-  fi
-  status=$?
-  return "$status"
-}
-
 readiness_blocker_reason() {
   local log="$1"
 
@@ -343,6 +311,14 @@ where client_id = :client_id
 SQL
 
 cat >"$verify_sql" <<'SQL'
+-- Exercise the packaged PL/pgSQL and Snowball side modules after sealing.
+do $$
+begin
+  if not (to_tsvector('english', 'running') @@ to_tsquery('english', 'run')) then
+    raise exception 'packaged Snowball stemming failed';
+  end if;
+end;
+$$ language plpgsql;
 select
   count(*)::int as rows_written,
   count(distinct client_id)::int as clients_seen,
@@ -392,7 +368,11 @@ env "${wasmer_env[@]}" \
     --no-locale \
     --encoding=UTF8 \
     --no-instructions \
-    >"$initdb_log" 2>&1
+    >"$initdb_log" 2>&1 || {
+      status=$?
+      cat "$initdb_log" >&2
+      exit "$status"
+    }
 
 server_pid=""
 server_pgid=""
@@ -585,7 +565,7 @@ for index in "${!client_pids[@]}"; do
 done
 
 if [ "$timed_out" -eq 1 ]; then
-  run_logged_timeout "$verify_timeout" "$timeout_activity_log" \
+  fresh_run_process_group_timeout "$verify_timeout" -- \
     "$CLIENT_TOOLS_INSTALL_DIR/bin/psql" "$conn" \
       -X -q -A -t -F $'\t' \
       -v ON_ERROR_STOP=1 \
@@ -595,15 +575,15 @@ if [ "$timed_out" -eq 1 ]; then
                left(regexp_replace(query, '[[:space:]]+', ' ', 'g'), 240)
         FROM pg_stat_activity
         ORDER BY pid
-      " || true
+      " >"$timeout_activity_log" 2>&1 || true
 fi
 
 set +e
-run_logged_timeout "$verify_timeout" "$verify_log" \
+fresh_run_process_group_timeout "$verify_timeout" -- \
   "$CLIENT_TOOLS_INSTALL_DIR/bin/psql" "$conn" \
     -X -q -A -t -F $'\t' \
     -v ON_ERROR_STOP=1 \
-    -f "$verify_sql"
+    -f "$verify_sql" >"$verify_log" 2>&1
 verify_status=$?
 set -e
 verify_line=""
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-concurrent-options.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-concurrent-options.test.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-concurrent-options.test.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-concurrent-options.test.sh
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-core.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-core.sh
similarity index 96%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-core.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-core.sh
index c915eaaeb..b3c2328ab 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-core.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-core.sh
@@ -20,7 +20,7 @@ if [ "$wasmer_status" -ne 0 ]; then
     printf '## Result\n\n'
     printf -- '- Status: `blocked`\n'
     printf -- '- Blocker: Wasmer CLI is missing or failed pinned-build validation.\n\n'
-    printf 'Run `%s/runtime/bin/build-runtime.sh`, or set `WASMER_BIN` and `WASMER_BUILD_RECEIPT` to a matching pinned build.\n' "$FRESH_ROOT"
+    printf 'Run `%s/wasmer/bin/build-runtime.sh`, or set `WASMER_BIN` and `WASMER_BUILD_RECEIPT` to a matching pinned build.\n' "$FRESH_ROOT"
   } >>"$report"
   echo "blocked: Wasmer CLI is missing or failed pinned-build validation; see $report" >&2
   exit 2
@@ -28,6 +28,7 @@ fi
 
 if [ ! -x "$WASIX_INSTALL_DIR/bin/initdb" ]; then
   "$FRESH_ROOT/bin/build-wasix-core.sh"
+  WASIX_INSTALL_DIR="$(fresh_wasix_core_install_dir_for "$WASIX_CORE_PROFILE")"
 fi
 
 wasmer_bin_hash="$(fresh_wasmer_bin_hash "$wasmer_bin")"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/stress-wasix-backend-waves.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/stress-wasix-backend-waves.sh
similarity index 89%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/stress-wasix-backend-waves.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/stress-wasix-backend-waves.sh
index 978a8c2b7..5b8e61d68 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/stress-wasix-backend-waves.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/stress-wasix-backend-waves.sh
@@ -83,21 +83,7 @@ sealed_carrier="$(cd "$sealed_carrier" && pwd -P)"
 select_available_port() {
   local candidate="$1"
 
-  python3 - "$candidate" <<'PY'
-import socket
-import sys
-
-candidate = int(sys.argv[1])
-for port in range(candidate, 65536):
-    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as listener:
-        try:
-            listener.bind(("127.0.0.1", port))
-        except OSError:
-            continue
-        print(port)
-        raise SystemExit(0)
-raise SystemExit("no available backend-wave TCP port remains")
-PY
+  bun "$FRESH_ROOT/lib/server-lifecycle.mts" available-port "$candidate"
 }
 
 next_port="$start_port"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/stress-wasix-initdb.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/stress-wasix-initdb.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/stress-wasix-initdb.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/stress-wasix-initdb.sh
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/validate-sealed-loader-audit.mts b/src/runtimes/liboliphaunt-wasix-postmaster/bin/validate-sealed-loader-audit.mts
new file mode 100644
index 000000000..ff4bb5332
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/validate-sealed-loader-audit.mts
@@ -0,0 +1,355 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { parseArgs } from 'node:util';
+import { parseStrictJson } from '../../../../tools/packaging/strict-json.mts';
+import { stableRead } from '../lib/receipt-files.mts';
+
+export const schema = 'oliphaunt.wasix-postmaster.sealed-loader-receipt.v2';
+const advice = [
+  'read_advice',
+  'source_cache_eviction',
+  'snapshot_cache_eviction',
+  'mapping_cache_eviction',
+];
+const checkpoints = [
+  'residency_after_hash_inspect',
+  'residency_after_archive_release',
+  'source_residency_before_eviction',
+  'source_residency_after_eviction',
+  'residency_after_eviction',
+];
+const residencyFields = [
+  'state',
+  'page_size',
+  'total_pages',
+  'resident_pages',
+  'resident_bytes',
+  'errno',
+];
+const fields = [
+  'schema',
+  'pid',
+  'artifact_kind',
+  'module_sha256',
+  'snapshot_mode',
+  'logical_bytes',
+  'source_bytes_read',
+  'source_bytes_written',
+  'snapshot_bytes_written',
+  'mapping_bytes_hashed',
+  'sync_calls',
+  ...advice.flatMap((prefix) =>
+    [
+      'applicable',
+      'supported',
+      'calls',
+      'successes',
+      prefix === 'read_advice' ? 'first_errno' : 'errno',
+    ].map((suffix) => `${prefix}_${suffix}`),
+  ),
+  ...checkpoints,
+  'write_policy',
+];
+// Preserve the v4 evidence columns for existing reports; memory-image summaries
+// are no longer emitted by this AOT-only executor.
+const retiredCounters = [
+  'ordinary_start_completed_instances',
+  'fresh_zeroed_instances',
+  'nonfresh_instances',
+  'validation_attempts',
+  'full_compare_attempts',
+  'full_compare_successes',
+  'full_compare_failures',
+  'compared_bytes',
+  'reuse_successes',
+  'reuse_failures',
+  'skipped_bytes',
+  'remap_successes',
+  'remap_failures',
+];
+const hash = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex');
+const object = (value: unknown): value is Record =>
+  value !== null && typeof value === 'object' && !Array.isArray(value);
+function exactFields(
+  value: unknown,
+  expected: string[],
+  label: string,
+): asserts value is Record {
+  assert(object(value), `${label} must be an object`);
+  assert.deepEqual(Object.keys(value).sort(), [...expected].sort(), `${label} fields differ`);
+}
+function digest(value: unknown): asserts value is string {
+  assert(typeof value === 'string' && /^[0-9a-f]{64}$/u.test(value), 'invalid module SHA-256');
+}
+function integer(value: unknown, label: string): bigint {
+  assert(typeof value === 'bigint' && value >= 0n, `${label} must be a nonnegative integer`);
+  return value;
+}
+function json(bytes: Uint8Array) {
+  return parseStrictJson(
+    new TextDecoder('utf-8', { fatal: true }).decode(bytes),
+    (_key, value, context?: { source: string }) => {
+      if (typeof value !== 'number') return value;
+      // Use the original token: JSON.parse's Number would round large Rust counters.
+      assert(
+        context && /^-?(0|[1-9][0-9]*)$/u.test(context.source),
+        'audit numbers must be integers',
+      );
+      return BigInt(context.source);
+    },
+  );
+}
+export function readRegular(file: string) {
+  const chunks: Buffer[] = [];
+  stableRead(
+    file,
+    (chunk) => {
+      chunks.push(Buffer.from(chunk));
+    },
+    16 * 1024 * 1024,
+  );
+  return Buffer.concat(chunks);
+}
+function residency(value: unknown, logical: bigint, portable: boolean, label: string) {
+  exactFields(value, residencyFields, label);
+  assert.equal(
+    value.state,
+    portable ? 'unsupported-platform' : 'measured',
+    `${label} state differs`,
+  );
+  assert.equal(value.errno, null, `${label} carries errno`);
+  if (portable) {
+    for (const field of residencyFields.filter((field) => field !== 'state'))
+      assert.equal(value[field], null, `${label} ${field} must be null`);
+    return;
+  }
+  const page = integer(value.page_size, label);
+  const total = integer(value.total_pages, label);
+  const resident = integer(value.resident_pages, label);
+  const bytes = integer(value.resident_bytes, label);
+  assert(page >= 512n && (page & (page - 1n)) === 0n, `${label} page size is invalid`);
+  assert.equal(total, (logical + page - 1n) / page, `${label} total pages differs`);
+  assert(resident <= total, `${label} resident pages exceed total`);
+  const whole = resident * page;
+  const tail = logical - (total - 1n) * page;
+  assert(
+    resident === 0n
+      ? bytes === 0n
+      : bytes === (whole < logical ? whole : logical) || bytes === (resident - 1n) * page + tail,
+    `${label} resident byte/page accounting differs`,
+  );
+}
+export function validate(
+  audit: Uint8Array,
+  manifest: Uint8Array,
+  validator: Uint8Array,
+  policy = 'direct',
+  initdbCount = 1n,
+  postgresCount = 1n,
+): string {
+  assert(
+    ['direct', 'direct-immutable', 'portable-copy', 'compatible'].includes(policy),
+    'unknown snapshot policy',
+  );
+  assert(initdbCount > 0n && postgresCount > 0n, 'expected executions must be positive');
+  const portable = policy === 'portable-copy';
+  const manifestValue = json(manifest);
+  assert(
+    object(manifestValue) &&
+      Array.isArray(manifestValue.artifacts) &&
+      manifestValue.artifacts.length >= 2,
+    'manifest artifact closure is incomplete',
+  );
+  const modules = new Map();
+  const hashes = new Set();
+  for (const artifact of manifestValue.artifacts) {
+    assert(
+      object(artifact) &&
+        typeof artifact.name === 'string' &&
+        artifact.name.startsWith('runtime:') &&
+        artifact.name.length > 8,
+      'invalid manifest artifact',
+    );
+    const sha = artifact['module-sha256'];
+    digest(sha);
+    assert(
+      !modules.has(artifact.name) && !hashes.has(sha),
+      'duplicate manifest artifact or module hash',
+    );
+    modules.set(artifact.name, sha);
+    hashes.add(sha);
+  }
+  assert(
+    modules.has('runtime:initdb') && modules.has('runtime:postgres'),
+    'manifest executable closure differs',
+  );
+  const text = new TextDecoder('utf-8', { fatal: true }).decode(audit);
+  assert(
+    text.endsWith('\n') && !text.includes('\r'),
+    'audit must be newline-terminated without carriage returns',
+  );
+  const records = text
+    .slice(0, -1)
+    .split('\n')
+    .map((line, index) => {
+      const label = `loader audit line ${index + 1}`;
+      const record = json(Buffer.from(line));
+      exactFields(record, fields, label);
+      assert.equal(record.schema, schema, `${label} schema differs`);
+      assert(integer(record.pid, 'pid') > 0n, 'invalid audit pid');
+      assert.equal(record.artifact_kind, 'aot', 'invalid artifact kind');
+      digest(record.module_sha256);
+      assert(hashes.has(record.module_sha256), 'audit module SHA-256 is not in sealed manifest');
+      assert(
+        policy === 'compatible'
+          ? [
+              'direct-immutable-inode',
+              'direct-read-only-filesystem',
+              'reflink',
+              'streamed-copy',
+            ].includes(record.snapshot_mode)
+          : portable
+            ? record.snapshot_mode === 'streamed-copy'
+            : policy === 'direct-immutable'
+              ? record.snapshot_mode === 'direct-immutable-inode'
+              : ['direct-immutable-inode', 'direct-read-only-filesystem'].includes(
+                  record.snapshot_mode,
+                ),
+        'snapshot mode differs from policy',
+      );
+      const streamed = record.snapshot_mode === 'streamed-copy';
+      const reflink = record.snapshot_mode === 'reflink';
+      const privateCopy = streamed || reflink;
+      const logical = integer(record.logical_bytes, 'logical_bytes');
+      const read = integer(record.source_bytes_read, 'source_bytes_read');
+      assert(
+        logical > 0n &&
+          (streamed ? read === logical : reflink ? read === 0n : read === 0n || read === logical),
+        'source byte accounting differs',
+      );
+      for (const [field, expected] of Object.entries({
+        source_bytes_written: 0n,
+        snapshot_bytes_written: streamed ? logical : 0n,
+        mapping_bytes_hashed: logical,
+        sync_calls: 0n,
+      })) {
+        assert.equal(integer(record[field], field), expected, `${field} differs`);
+      }
+      for (const [index, prefix] of advice.entries()) {
+        const applicable = record[`${prefix}_applicable`];
+        const supported = record[`${prefix}_supported`];
+        const calls = integer(record[`${prefix}_calls`], prefix);
+        const successes = integer(record[`${prefix}_successes`], prefix);
+        const errno = record[`${prefix}_${index === 0 ? 'first_errno' : 'errno'}`];
+        assert.equal(
+          applicable,
+          index < 2 || (index === 2 && privateCopy),
+          `${prefix} applicability differs`,
+        );
+        assert.equal(typeof supported, 'boolean', `${prefix} supported must be boolean`);
+        assert(successes <= calls, `${prefix} successes exceed calls`);
+        assert.equal(errno, null, `${prefix} carries errno`);
+        if (!applicable || !supported) {
+          assert(!applicable || portable, `${prefix} is unsupported`);
+          assert(
+            calls === 0n && successes === 0n,
+            `${prefix} issued an inapplicable/unsupported call`,
+          );
+        } else
+          assert(
+            calls === (index === 0 ? 2n : 1n) && successes === calls,
+            `${prefix} advisory call failed`,
+          );
+      }
+      for (const checkpoint of checkpoints)
+        residency(record[checkpoint], logical, portable, checkpoint);
+      assert.equal(
+        record.write_policy,
+        streamed
+          ? 'private-streamed-copy-no-sync'
+          : reflink
+            ? 'private-reflink-no-userspace-payload-write'
+            : 'none-immutable-source',
+        'write policy differs',
+      );
+      return record;
+    });
+  const pids = (name: string) => {
+    const values = records
+      .filter((record) => record.module_sha256 === modules.get(name))
+      .map((record) => record.pid as bigint);
+    assert.equal(new Set(values).size, values.length, `${name} AOT audit pids are not unique`);
+    return new Set(values);
+  };
+  const initdb = pids('runtime:initdb'),
+    postgres = pids('runtime:postgres');
+  assert.equal(BigInt(initdb.size), initdbCount, 'initdb outer execution count differs');
+  assert(
+    [...initdb].every((pid) => postgres.has(pid)),
+    'every initdb execution must activate bootstrap postgres on the same pid',
+  );
+  const outerPostgres = [...postgres].filter((pid) => !initdb.has(pid));
+  assert.equal(
+    BigInt(outerPostgres.length),
+    postgresCount,
+    'postgres outer execution count differs',
+  );
+  const renderPids = (values: Iterable) =>
+    [...values].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)).join(',');
+  const output: Record = {
+    schema_version: 'oliphaunt.wasix-postmaster.sealed-loader-audit-validation.v4',
+    status: 'passed',
+    records: records.length,
+    aot_records: records.length,
+    memory_records: 0,
+    initdb_executions: initdbCount,
+    postgres_executions: postgresCount,
+    initdb_pids: renderPids(initdb),
+    postgres_pids: renderPids(outerPostgres),
+    snapshot_policy: policy,
+    audit_sha256: hash(audit),
+    manifest_sha256: hash(manifest),
+    validator_sha256: hash(validator),
+  };
+  for (const prefix of advice)
+    for (const suffix of ['calls', 'successes']) {
+      const key = `${prefix}_${suffix}`;
+      output[key] = records.reduce((total, record) => total + record[key], 0n);
+    }
+  for (const checkpoint of checkpoints)
+    output[`${checkpoint}_bytes`] = records.reduce(
+      (total, record) => total + (record[checkpoint].resident_bytes ?? 0n),
+      0n,
+    );
+  for (const key of ['attested_summary_records', ...retiredCounters, 'counter_overflow_records'])
+    output[key] = 0;
+  return `${Object.keys(output).join('\t')}\n${Object.values(output).join('\t')}\n`;
+}
+if (import.meta.main) {
+  try {
+    const { values } = parseArgs({
+      options: {
+        audit: { type: 'string' },
+        manifest: { type: 'string' },
+        'snapshot-policy': { type: 'string', default: 'direct' },
+        'expected-initdb-executions': { type: 'string', default: '1' },
+        'expected-postgres-executions': { type: 'string', default: '1' },
+      },
+    });
+    assert(values.audit && values.manifest, '--audit and --manifest are required');
+    process.stdout.write(
+      validate(
+        readRegular(values.audit),
+        readRegular(values.manifest),
+        readRegular(import.meta.path),
+        values['snapshot-policy'],
+        BigInt(values['expected-initdb-executions']!),
+        BigInt(values['expected-postgres-executions']!),
+      ),
+    );
+  } catch (error) {
+    console.error(`sealed loader audit validation failed: ${(error as Error).message}`);
+    process.exitCode = 2;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/bin/validate-sealed-loader-audit.test.mts b/src/runtimes/liboliphaunt-wasix-postmaster/bin/validate-sealed-loader-audit.test.mts
new file mode 100644
index 000000000..ec837b9fe
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/validate-sealed-loader-audit.test.mts
@@ -0,0 +1,187 @@
+import assert from 'node:assert/strict';
+import { mkdtempSync, writeFileSync, symlinkSync, rmSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import test from 'node:test';
+import { schema, validate, readRegular } from './validate-sealed-loader-audit.mts';
+
+const initdb = '1'.repeat(64),
+  postgres = '2'.repeat(64);
+const manifest = Buffer.from(
+  JSON.stringify({
+    artifacts: [
+      { name: 'runtime:initdb', 'module-sha256': initdb },
+      { name: 'runtime:postgres', 'module-sha256': postgres },
+    ],
+  }),
+);
+function record(module: string, pid: number, portable = false): Record {
+  const value: Record = {
+    schema,
+    pid,
+    artifact_kind: 'aot',
+    module_sha256: module,
+    snapshot_mode: portable ? 'streamed-copy' : 'direct-immutable-inode',
+    logical_bytes: 4096,
+    source_bytes_read: portable ? 4096 : 0,
+    source_bytes_written: 0,
+    snapshot_bytes_written: portable ? 4096 : 0,
+    mapping_bytes_hashed: 4096,
+    sync_calls: 0,
+    write_policy: portable ? 'private-streamed-copy-no-sync' : 'none-immutable-source',
+  };
+  for (const [index, prefix] of [
+    'read_advice',
+    'source_cache_eviction',
+    'snapshot_cache_eviction',
+    'mapping_cache_eviction',
+  ].entries()) {
+    value[`${prefix}_applicable`] = index < 2 || (index === 2 && portable);
+    value[`${prefix}_supported`] = !portable;
+    value[`${prefix}_calls`] = value[`${prefix}_successes`] =
+      !portable && index < 2 ? (index === 0 ? 2 : 1) : 0;
+    value[`${prefix}_${index === 0 ? 'first_errno' : 'errno'}`] = null;
+  }
+  for (const key of [
+    'residency_after_hash_inspect',
+    'residency_after_archive_release',
+    'source_residency_before_eviction',
+    'source_residency_after_eviction',
+    'residency_after_eviction',
+  ]) {
+    value[key] = portable
+      ? {
+          state: 'unsupported-platform',
+          page_size: null,
+          total_pages: null,
+          resident_pages: null,
+          resident_bytes: null,
+          errno: null,
+        }
+      : {
+          state: 'measured',
+          page_size: 4096,
+          total_pages: 1,
+          resident_pages: 1,
+          resident_bytes: 4096,
+          errno: null,
+        };
+  }
+  return value;
+}
+const lifecycle = (portable = false) => [
+  record(initdb, 101, portable),
+  record(postgres, 101, portable),
+  record(postgres, 202, portable),
+];
+const encode = (records: unknown[]) =>
+  Buffer.from(`${records.map((record) => JSON.stringify(record)).join('\n')}\n`);
+const run = (records = lifecycle(), policy = 'direct-immutable') =>
+  validate(encode(records), manifest, Buffer.from('validator'), policy);
+
+test('counts bootstrap and outer activations, validates portable copies and rejects broken evidence', () => {
+  const [header, values] = run()
+    .trimEnd()
+    .split('\n')
+    .map((line) => line.split('\t'));
+  const result = Object.fromEntries(header!.map((key, i) => [key, values![i]]));
+  assert.equal(result.status, 'passed');
+  assert.equal(result.records, '3');
+  assert.equal(result.initdb_pids, '101');
+  assert.equal(result.postgres_pids, '202');
+  assert.equal(result.read_advice_calls, '6');
+  assert.doesNotThrow(() => run(lifecycle(true), 'portable-copy'));
+  assert.doesNotThrow(() => run(lifecycle(), 'compatible'));
+  for (const mode of ['streamed-copy', 'reflink']) {
+    const records = lifecycle().map((value) => ({
+      ...value,
+      snapshot_mode: mode,
+      source_bytes_read: mode === 'streamed-copy' ? 4096 : 0,
+      snapshot_bytes_written: mode === 'streamed-copy' ? 4096 : 0,
+      snapshot_cache_eviction_applicable: true,
+      snapshot_cache_eviction_calls: 1,
+      snapshot_cache_eviction_successes: 1,
+      write_policy:
+        mode === 'streamed-copy'
+          ? 'private-streamed-copy-no-sync'
+          : 'private-reflink-no-userspace-payload-write',
+    }));
+    assert.doesNotThrow(() => run(records, 'compatible'));
+    assert.throws(() => run(records, 'direct-immutable'), /snapshot mode/);
+    for (const change of [
+      { source_bytes_written: 1 },
+      { mapping_bytes_hashed: 4095 },
+      { snapshot_bytes_written: 1 },
+      { write_policy: 'none-immutable-source' },
+    ]) {
+      assert.throws(() => run([{ ...records[0], ...change }, ...records.slice(1)], 'compatible'));
+    }
+  }
+  assert.throws(() => run([record(initdb, 101), record(postgres, 202)]), /bootstrap postgres/);
+  assert.throws(() => run([...lifecycle(), record(postgres, 202)]), /not unique/);
+  assert.throws(() => run([...lifecycle(), record('f'.repeat(64), 303)]), /not in sealed manifest/);
+  for (const change of [
+    { artifact_kind: 'preinitialized-memory' },
+    { unknown: true },
+    { snapshot_mode: 'reflink' },
+    { pid: true },
+    { logical_bytes: -1 },
+    { source_bytes_written: 1 },
+    { mapping_bytes_hashed: 4095 },
+    { read_advice_successes: 1 },
+    { source_cache_eviction_errno: 5 },
+    { sync_calls: 1 },
+    {
+      residency_after_eviction: {
+        state: 'measured',
+        page_size: 4096,
+        total_pages: 1,
+        resident_pages: 1,
+        resident_bytes: 4095,
+        errno: null,
+      },
+    },
+  ]) {
+    const records = lifecycle();
+    Object.assign(records[0]!, change);
+    assert.throws(() => run(records), `accepted ${JSON.stringify(change)}`);
+  }
+  const audit = encode(lifecycle()).toString();
+  assert.throws(
+    () =>
+      validate(
+        Buffer.from(audit.replace('"pid":101', '"pid":101,"pid":101')),
+        manifest,
+        Buffer.alloc(0),
+      ),
+    /duplicate/,
+  );
+  // Adjacent integers above 2^53 must remain distinct process identities.
+  const precise = audit
+    .replaceAll('"pid":101', '"pid":9007199254740992')
+    .replace('"pid":202', '"pid":9007199254740993');
+  assert.match(
+    validate(Buffer.from(precise), manifest, Buffer.alloc(0)),
+    /9007199254740992\t9007199254740993/,
+  );
+  assert.throws(
+    () =>
+      validate(Buffer.from(audit.replace('"pid":101', '"pid":101.0')), manifest, Buffer.alloc(0)),
+    /integers/,
+  );
+});
+
+test('bounded audit reads reject symlinks and oversized inputs', () => {
+  const root = mkdtempSync(join(tmpdir(), 'loader-audit-'));
+  try {
+    const file = join(root, 'audit');
+    writeFileSync(file, 'audit');
+    symlinkSync(file, join(root, 'link'));
+    assert.equal(readRegular(file).toString(), 'audit');
+    assert.throws(() => readRegular(join(root, 'link')));
+    writeFileSync(file, Buffer.alloc(16 * 1024 * 1024 + 1));
+    assert.throws(() => readRegular(file), /bounded regular/);
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/verify-immutable-sealed-carrier.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/verify-immutable-sealed-carrier.sh
similarity index 95%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/verify-immutable-sealed-carrier.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/verify-immutable-sealed-carrier.sh
index 4109a8352..e0874a4d7 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/verify-immutable-sealed-carrier.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/verify-immutable-sealed-carrier.sh
@@ -5,6 +5,7 @@ set -euo pipefail
 project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
 source "$project_root/lib/common.sh"
 source "$project_root/lib/sealed-carrier.sh"
+source "$project_root/lib/immutable-carrier.sh"
 source "$project_root/lib/qualification-identities.sh"
 
 usage() {
@@ -65,4 +66,4 @@ if [ "$fast" -eq 0 ]; then
     --headless-sha256 "$FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256"
   )
 fi
-python3 "$project_root/lib/immutable-carrier.py" "${arguments[@]}"
+fresh_immutable_carrier "${arguments[@]}"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/verify-sealed-headless-carrier.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/verify-sealed-headless-carrier.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/verify-sealed-headless-carrier.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/verify-sealed-headless-carrier.sh
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/wasix-make.sh b/src/runtimes/liboliphaunt-wasix-postmaster/bin/wasix-make.sh
similarity index 96%
rename from src/runtimes/liboliphaunt/wasix-postmaster/bin/wasix-make.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/bin/wasix-make.sh
index 666f9d16c..57ff81ca5 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/wasix-make.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/bin/wasix-make.sh
@@ -61,7 +61,7 @@ fi
   "$docker_image_id" \
   bash -lc "
     set -euo pipefail
-    source ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
+    source ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
     if [ ! -e \"\$BUILD_DIR/src/include/utils/errcodes.h\" ]; then
       make -C \"\$BUILD_DIR/src/backend\" generated-headers
     fi
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/.gitignore b/src/runtimes/liboliphaunt-wasix-postmaster/executor/.gitignore
new file mode 100644
index 000000000..9573e2221
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/.gitignore
@@ -0,0 +1,2 @@
+/.cargo/config.toml
+/target/
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/Cargo.lock b/src/runtimes/liboliphaunt-wasix-postmaster/executor/Cargo.lock
new file mode 100644
index 000000000..c598d29f5
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/Cargo.lock
@@ -0,0 +1,4279 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "addr2line"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
+dependencies = [
+ "gimli 0.32.3",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "any_ascii"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e"
+
+[[package]]
+name = "anyhow"
+version = "1.0.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
+
+[[package]]
+name = "arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
+
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "backtrace"
+version = "0.3.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object 0.37.3",
+ "rustc-demangle",
+ "windows-link",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bincode"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
+dependencies = [
+ "bincode_derive",
+ "serde",
+ "unty",
+]
+
+[[package]]
+name = "bincode_derive"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
+dependencies = [
+ "virtue",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.72.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
+dependencies = [
+ "bitflags 2.11.1",
+ "cexpr",
+ "clang-sys",
+ "itertools 0.13.0",
+ "log",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
+
+[[package]]
+name = "blake3"
+version = "1.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "cc",
+ "cfg-if",
+ "constant_time_eq",
+ "cpufeatures 0.3.0",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be"
+dependencies = [
+ "hybrid-array",
+]
+
+[[package]]
+name = "bstr"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
+dependencies = [
+ "allocator-api2",
+]
+
+[[package]]
+name = "bytecheck"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b"
+dependencies = [
+ "bytecheck_derive",
+ "ptr_meta",
+ "rancor",
+ "simdutf8",
+]
+
+[[package]]
+name = "bytecheck_derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bytesize"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom 7.1.3",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "chacha20"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.3.0",
+ "rand_core 0.10.1",
+]
+
+[[package]]
+name = "chrono"
+version = "0.4.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "ciborium"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "console"
+version = "0.16.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87"
+dependencies = [
+ "encode_unicode",
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "const-oid"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"
+
+[[package]]
+name = "constant_time_eq"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
+
+[[package]]
+name = "convert_case"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "cooked-waker"
+version = "5.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f"
+
+[[package]]
+name = "corosensei"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c54787b605c7df106ceccf798df23da4f2e09918defad66705d1cedf3bb914f"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "libc",
+ "scopeguard",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "cpp_demangle"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cranelift-assembler-x64"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6edb5bdd1af46714e3224a017fabbbd57f70df4e840eb5ad6a7429dc456119d6"
+dependencies = [
+ "cranelift-assembler-x64-meta",
+]
+
+[[package]]
+name = "cranelift-assembler-x64-meta"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a819599186e1b1a1f88d464e06045696afc7aa3e0cc018aa0b2999cb63d1d088"
+dependencies = [
+ "cranelift-srcgen",
+]
+
+[[package]]
+name = "cranelift-bforest"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36e2c152d488e03c87b913bc2ed3414416eb1e0d66d61b49af60bf456a9665c7"
+dependencies = [
+ "cranelift-entity",
+ "wasmtime-internal-core",
+]
+
+[[package]]
+name = "cranelift-bitset"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6559d4fbc253d1396e1f6beeae57fa88a244f02aaf0cde2a735afd3492d9b2e"
+dependencies = [
+ "wasmtime-internal-core",
+]
+
+[[package]]
+name = "cranelift-codegen"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96d9315d98d6e0a64454d4c83be2ee0e8055c3f80c3b2d7bcad7079f281a06ff"
+dependencies = [
+ "bumpalo",
+ "cranelift-assembler-x64",
+ "cranelift-bforest",
+ "cranelift-bitset",
+ "cranelift-codegen-meta",
+ "cranelift-codegen-shared",
+ "cranelift-control",
+ "cranelift-entity",
+ "cranelift-isle",
+ "gimli 0.33.0",
+ "hashbrown 0.16.1",
+ "libm",
+ "log",
+ "regalloc2",
+ "rustc-hash",
+ "serde",
+ "smallvec",
+ "target-lexicon",
+ "wasmtime-internal-core",
+]
+
+[[package]]
+name = "cranelift-codegen-meta"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d89c00a88081c55e3087c45bebc77e0cc973de2d7b44ef6a943c7122647b89f5"
+dependencies = [
+ "cranelift-assembler-x64-meta",
+ "cranelift-codegen-shared",
+ "cranelift-srcgen",
+ "heck 0.5.0",
+]
+
+[[package]]
+name = "cranelift-codegen-shared"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879f77c497a1eb6273482aa1ac3b23cb8563ff04edb39ed5dfcfd28c8deff8f5"
+
+[[package]]
+name = "cranelift-control"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "498dc1f17a6910c88316d49c7176d8fa97cf10c30859c32a266040449317f963"
+dependencies = [
+ "arbitrary",
+]
+
+[[package]]
+name = "cranelift-entity"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2acba797f6a46042ce82aaf7680d0c3567fe2001e238db9df649fd104a2727f"
+dependencies = [
+ "cranelift-bitset",
+ "wasmtime-internal-core",
+]
+
+[[package]]
+name = "cranelift-frontend"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dca3df1d107d98d88f159ad1d5eaa2d5cdb678b3d5bcfadc6fc83d8ebb448ea"
+dependencies = [
+ "cranelift-codegen",
+ "log",
+ "smallvec",
+ "target-lexicon",
+]
+
+[[package]]
+name = "cranelift-isle"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f62dd18116d88bed649871feceda79dad7b59cc685ea8998c2b3e64d0e689602"
+
+[[package]]
+name = "cranelift-srcgen"
+version = "0.131.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "090ee5de58c6f17eb5e3a5ae8cf1695c7efea04ec4dd0ecba6a5b996c9bad7dc"
+
+[[package]]
+name = "crc32fast"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
+dependencies = [
+ "hybrid-array",
+]
+
+[[package]]
+name = "darling"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
+dependencies = [
+ "darling_core 0.20.11",
+ "darling_macro 0.20.11",
+]
+
+[[package]]
+name = "darling"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
+dependencies = [
+ "darling_core 0.21.3",
+ "darling_macro 0.21.3",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
+dependencies = [
+ "darling_core 0.20.11",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
+dependencies = [
+ "darling_core 0.21.3",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "dashmap"
+version = "6.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "hashbrown 0.14.5",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "debugid"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
+dependencies = [
+ "uuid",
+]
+
+[[package]]
+name = "defmt"
+version = "0.3.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad"
+dependencies = [
+ "defmt 1.0.1",
+]
+
+[[package]]
+name = "defmt"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78"
+dependencies = [
+ "bitflags 1.3.2",
+ "defmt-macros",
+]
+
+[[package]]
+name = "defmt-macros"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e"
+dependencies = [
+ "defmt-parser",
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "defmt-parser"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
+dependencies = [
+ "thiserror",
+]
+
+[[package]]
+name = "deranged"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "derive_builder"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
+dependencies = [
+ "derive_builder_macro",
+]
+
+[[package]]
+name = "derive_builder_core"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
+dependencies = [
+ "darling 0.20.11",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "derive_builder_macro"
+version = "0.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
+dependencies = [
+ "derive_builder_core",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "derive_more"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn 2.0.117",
+ "unicode-xid",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer 0.10.4",
+ "crypto-common 0.1.7",
+]
+
+[[package]]
+name = "digest"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c"
+dependencies = [
+ "block-buffer 0.12.0",
+ "const-oid",
+ "crypto-common 0.2.1",
+]
+
+[[package]]
+name = "dirs"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "document-features"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
+dependencies = [
+ "litrs",
+]
+
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
+name = "dyn-clone"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "encode_unicode"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
+
+[[package]]
+name = "enum-iterator"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016"
+dependencies = [
+ "enum-iterator-derive",
+]
+
+[[package]]
+name = "enum-iterator-derive"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "enumset"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634"
+dependencies = [
+ "enumset_derive",
+]
+
+[[package]]
+name = "enumset_derive"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce"
+dependencies = [
+ "darling 0.21.3",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
+
+[[package]]
+name = "filetime"
+version = "0.2.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "libredox",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "fixedbitset"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
+
+[[package]]
+name = "flate2"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
+name = "foldhash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
+name = "futures"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi 5.3.0",
+ "wasip2",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi 6.0.0",
+ "rand_core 0.10.1",
+ "wasip2",
+ "wasip3",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "gimli"
+version = "0.32.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
+
+[[package]]
+name = "gimli"
+version = "0.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c"
+dependencies = [
+ "fnv",
+ "hashbrown 0.16.1",
+ "indexmap",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+
+[[package]]
+name = "globset"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "log",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "half"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+ "zerocopy",
+]
+
+[[package]]
+name = "hash32"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+dependencies = [
+ "foldhash 0.1.5",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+dependencies = [
+ "foldhash 0.2.0",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
+dependencies = [
+ "foldhash 0.2.0",
+]
+
+[[package]]
+name = "heapless"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed"
+dependencies = [
+ "hash32",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "http"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
+dependencies = [
+ "bytes",
+ "itoa",
+]
+
+[[package]]
+name = "hybrid-array"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214"
+dependencies = [
+ "typenum",
+]
+
+[[package]]
+name = "icu_collections"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "utf8_iter",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
+
+[[package]]
+name = "icu_properties"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
+dependencies = [
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
+
+[[package]]
+name = "icu_provider"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "id-arena"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "idna"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "ignore"
+version = "0.4.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a"
+dependencies = [
+ "crossbeam-deque",
+ "globset",
+ "log",
+ "memchr",
+ "regex-automata",
+ "same-file",
+ "walkdir",
+ "winapi-util",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.17.0",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "inkwell"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7decbc9dfa45a4a827a6ff7b822c113b1285678a937e84213417d4ca8a095782"
+dependencies = [
+ "bitflags 2.11.1",
+ "inkwell_internals",
+ "libc",
+ "llvm-sys",
+ "thiserror",
+]
+
+[[package]]
+name = "inkwell_internals"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6cfe97ee860815a90ed17e09639513269e39420a7440f3f4c996f238c514cf8d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "insta"
+version = "1.47.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e"
+dependencies = [
+ "console",
+ "once_cell",
+ "regex",
+ "serde",
+ "similar",
+ "tempfile",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
+
+[[package]]
+name = "iprange"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00"
+dependencies = [
+ "ipnet",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.4",
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "leb128"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545"
+
+[[package]]
+name = "leb128fmt"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
+
+[[package]]
+name = "lexical-sort"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a"
+dependencies = [
+ "any_ascii",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link",
+]
+
+[[package]]
+name = "libm"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
+
+[[package]]
+name = "libredox"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
+dependencies = [
+ "bitflags 2.11.1",
+ "libc",
+ "plain",
+ "redox_syscall 0.7.4",
+]
+
+[[package]]
+name = "libunwind"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac"
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
+[[package]]
+name = "linked_hash_set"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8"
+dependencies = [
+ "linked-hash-map",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
+
+[[package]]
+name = "litemap"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
+
+[[package]]
+name = "litrs"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
+
+[[package]]
+name = "llvm-sys"
+version = "221.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2abcc34a3b190f03c2a61b555f218f529589ff13657bdd2ff8ac3e85f2abe6bb"
+dependencies = [
+ "anyhow",
+ "cc",
+ "lazy_static",
+ "libc",
+ "regex-lite",
+ "semver",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+
+[[package]]
+name = "lz4_flex"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a"
+dependencies = [
+ "twox-hash",
+]
+
+[[package]]
+name = "mach2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "mach2"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b"
+
+[[package]]
+name = "macho-unwind-info"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149"
+dependencies = [
+ "thiserror",
+ "zerocopy",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "managed"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+
+[[package]]
+name = "memmap2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memmap2"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+ "simd-adler32",
+]
+
+[[package]]
+name = "mio"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "more-asserts"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e"
+
+[[package]]
+name = "msvc-demangler"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbeff6bd154a309b2ada5639b2661ca6ae4599b34e8487dc276d2cd637da2d76"
+dependencies = [
+ "bitflags 2.11.1",
+ "itoa",
+]
+
+[[package]]
+name = "munge"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c"
+dependencies = [
+ "munge_macro",
+]
+
+[[package]]
+name = "munge_macro"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "nom"
+version = "5.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b"
+dependencies = [
+ "memchr",
+ "version_check",
+]
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26"
+dependencies = [
+ "num_enum_derive",
+ "rustversion",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "object"
+version = "0.37.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "object"
+version = "0.39.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b"
+dependencies = [
+ "crc32fast",
+ "flate2",
+ "hashbrown 0.17.0",
+ "indexmap",
+ "memchr",
+ "ruzstd",
+]
+
+[[package]]
+name = "oliphaunt-wasix-postmaster-executor"
+version = "7.2.0-alpha.2"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "dirs",
+ "futures",
+ "hex",
+ "libc",
+ "serde",
+ "serde_json",
+ "sha2 0.11.0",
+ "tempfile",
+ "tokio",
+ "tracing",
+ "wasmer",
+ "wasmer-compiler-cranelift",
+ "wasmer-compiler-llvm",
+ "wasmer-types",
+ "wasmer-vm",
+ "wasmer-wasix",
+ "wasmparser 0.247.0",
+ "wat",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "parking"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall 0.5.18",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "path-clean"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "petgraph"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
+dependencies = [
+ "fixedbitset",
+ "hashbrown 0.15.5",
+ "indexmap",
+ "serde",
+]
+
+[[package]]
+name = "phf"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
+dependencies = [
+ "phf_macros",
+ "phf_shared",
+ "serde",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
+dependencies = [
+ "fastrand",
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_macros"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "pin-project"
+version = "1.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
+
+[[package]]
+name = "plain"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
+
+[[package]]
+name = "potential_utf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "prettyplease"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "ptr_meta"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79"
+dependencies = [
+ "ptr_meta_derive",
+]
+
+[[package]]
+name = "ptr_meta_derive"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "pulldown-cmark"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
+dependencies = [
+ "bitflags 1.3.2",
+ "memchr",
+ "unicase",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "rancor"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee"
+dependencies = [
+ "ptr_meta",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
+dependencies = [
+ "rand_chacha",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
+dependencies = [
+ "chacha20",
+ "getrandom 0.4.2",
+ "rand_core 0.10.1",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom 0.3.4",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+
+[[package]]
+name = "rangemap"
+version = "1.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68"
+
+[[package]]
+name = "rayon"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags 2.11.1",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a"
+dependencies = [
+ "bitflags 2.11.1",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
+dependencies = [
+ "getrandom 0.2.17",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
+name = "ref-cast"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "regalloc2"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de2c52737737f8609e94f975dee22854a2d5c125772d4b1cf292120f4d45c186"
+dependencies = [
+ "allocator-api2",
+ "bumpalo",
+ "hashbrown 0.17.0",
+ "log",
+ "rustc-hash",
+ "smallvec",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-lite"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973"
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+
+[[package]]
+name = "region"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+ "mach2 0.4.3",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rend"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6"
+dependencies = [
+ "bytecheck",
+]
+
+[[package]]
+name = "replace_with"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884"
+
+[[package]]
+name = "rkyv"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3"
+dependencies = [
+ "bytecheck",
+ "bytes",
+ "hashbrown 0.17.0",
+ "indexmap",
+ "munge",
+ "ptr_meta",
+ "rancor",
+ "rend",
+ "rkyv_derive",
+ "tinyvec",
+ "uuid",
+]
+
+[[package]]
+name = "rkyv_derive"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
+dependencies = [
+ "bitflags 2.11.1",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "rusty_pool"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff"
+dependencies = [
+ "crossbeam-channel",
+ "futures",
+ "futures-channel",
+ "futures-executor",
+ "num_cpus",
+]
+
+[[package]]
+name = "ruzstd"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01"
+dependencies = [
+ "twox-hash",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
+
+[[package]]
+name = "saffron"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9"
+dependencies = [
+ "chrono",
+ "nom 5.1.3",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "schemars"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc"
+dependencies = [
+ "dyn-clone",
+ "indexmap",
+ "ref-cast",
+ "schemars_derive",
+ "serde",
+ "serde_json",
+ "url",
+]
+
+[[package]]
+name = "schemars_derive"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "serde_derive_internals",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "self_cell"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89"
+
+[[package]]
+name = "semver"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+dependencies = [
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde-wasm-bindgen"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
+dependencies = [
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "serde_derive_internals"
+version = "0.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.149"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "serde_yaml"
+version = "0.9.34+deprecated"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
+dependencies = [
+ "indexmap",
+ "itoa",
+ "ryu",
+ "serde",
+ "unsafe-libyaml",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "sha2"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.3.0",
+ "digest 0.11.2",
+]
+
+[[package]]
+name = "shared-buffer"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16"
+dependencies = [
+ "bytes",
+ "memmap2 0.6.2",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
+
+[[package]]
+name = "simdutf8"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
+
+[[package]]
+name = "similar"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
+
+[[package]]
+name = "siphasher"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
+
+[[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "smoltcp"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac729b0a77bd092a3f06ddaddc59fe0d67f48ba0de45a9abe707c2842c7f8767"
+dependencies = [
+ "bitflags 1.3.2",
+ "byteorder",
+ "cfg-if",
+ "defmt 0.3.100",
+ "heapless",
+ "managed",
+]
+
+[[package]]
+name = "socket2"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "symbolic-common"
+version = "12.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "332615d90111d8eeaf86a84dc9bbe9f65d0d8c5cf11b4caccedc37754eb0dcfd"
+dependencies = [
+ "debugid",
+ "memmap2 0.9.10",
+ "stable_deref_trait",
+ "uuid",
+]
+
+[[package]]
+name = "symbolic-demangle"
+version = "12.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "912017718eb4d21930546245af9a3475c9dccf15675a5c215664e76621afc471"
+dependencies = [
+ "cpp_demangle",
+ "msvc-demangler",
+ "rustc-demangle",
+ "symbolic-common",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "tar"
+version = "0.4.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
+dependencies = [
+ "filetime",
+ "libc",
+ "xattr",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.13.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
+
+[[package]]
+name = "tempfile"
+version = "3.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
+dependencies = [
+ "fastrand",
+ "getrandom 0.4.2",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "terminal_size"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874"
+dependencies = [
+ "rustix",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "termios"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "time"
+version = "0.3.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde_core",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
+
+[[package]]
+name = "time-macros"
+version = "0.2.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.52.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+ "tokio-util",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "toml"
+version = "1.1.2+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
+dependencies = [
+ "indexmap",
+ "serde_core",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "1.1.1+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.25.11+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "toml_parser",
+ "winnow",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.1.2+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "toml_writer"
+version = "1.1.1+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "log",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "twox-hash"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c"
+
+[[package]]
+name = "typenum"
+version = "1.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
+
+[[package]]
+name = "unicase"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
+
+[[package]]
+name = "unicode-width"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "unsafe-libyaml"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
+
+[[package]]
+name = "unty"
+version = "0.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
+
+[[package]]
+name = "url"
+version = "2.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+ "serde_derive",
+]
+
+[[package]]
+name = "urlencoding"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "uuid"
+version = "1.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "virtual-fs"
+version = "0.702.0-alpha.2"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "bytes",
+ "dashmap",
+ "derive_more",
+ "dunce",
+ "filetime",
+ "fs_extra",
+ "futures",
+ "getrandom 0.4.2",
+ "indexmap",
+ "libc",
+ "pin-project-lite",
+ "replace_with",
+ "shared-buffer",
+ "slab",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "virtual-mio",
+ "wasmer-package",
+ "webc",
+]
+
+[[package]]
+name = "virtual-mio"
+version = "0.702.0-alpha.2"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "futures",
+ "mio",
+ "parking",
+ "serde",
+ "socket2",
+ "thiserror",
+ "tracing",
+]
+
+[[package]]
+name = "virtual-net"
+version = "0.702.0-alpha.2"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "base64",
+ "bincode",
+ "bytecheck",
+ "bytes",
+ "derive_more",
+ "futures-util",
+ "ipnet",
+ "iprange",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "rkyv",
+ "serde",
+ "smoltcp",
+ "socket2",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "virtual-mio",
+]
+
+[[package]]
+name = "virtue"
+version = "0.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
+
+[[package]]
+name = "wai-bindgen-gen-core"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c"
+dependencies = [
+ "anyhow",
+ "wai-parser",
+]
+
+[[package]]
+name = "wai-bindgen-gen-rust"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe"
+dependencies = [
+ "heck 0.3.3",
+ "wai-bindgen-gen-core",
+]
+
+[[package]]
+name = "wai-bindgen-gen-rust-wasm"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199"
+dependencies = [
+ "heck 0.3.3",
+ "wai-bindgen-gen-core",
+ "wai-bindgen-gen-rust",
+]
+
+[[package]]
+name = "wai-bindgen-rust"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741"
+dependencies = [
+ "bitflags 1.3.2",
+ "wai-bindgen-rust-impl",
+]
+
+[[package]]
+name = "wai-bindgen-rust-impl"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4"
+dependencies = [
+ "proc-macro2",
+ "syn 1.0.109",
+ "wai-bindgen-gen-core",
+ "wai-bindgen-gen-rust-wasm",
+]
+
+[[package]]
+name = "wai-parser"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "pulldown-cmark",
+ "unicode-normalization",
+ "unicode-xid",
+]
+
+[[package]]
+name = "waker-fn"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.3+wasi-0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
+dependencies = [
+ "wit-bindgen 0.57.1",
+]
+
+[[package]]
+name = "wasip3"
+version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
+dependencies = [
+ "wit-bindgen 0.51.0",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.118"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.118"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.118"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.118"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasm-encoder"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
+dependencies = [
+ "leb128fmt",
+ "wasmparser 0.244.0",
+]
+
+[[package]]
+name = "wasm-encoder"
+version = "0.247.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204"
+dependencies = [
+ "leb128fmt",
+ "wasmparser 0.247.0",
+]
+
+[[package]]
+name = "wasm-metadata"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
+dependencies = [
+ "anyhow",
+ "indexmap",
+ "wasm-encoder 0.244.0",
+ "wasmparser 0.244.0",
+]
+
+[[package]]
+name = "wasmer"
+version = "7.2.0-alpha.2"
+dependencies = [
+ "bindgen",
+ "bytes",
+ "cfg-if",
+ "cmake",
+ "corosensei",
+ "dashmap",
+ "derive_more",
+ "futures",
+ "indexmap",
+ "js-sys",
+ "more-asserts",
+ "paste",
+ "serde",
+ "serde-wasm-bindgen",
+ "shared-buffer",
+ "symbolic-demangle",
+ "tar",
+ "target-lexicon",
+ "thiserror",
+ "tracing",
+ "wasm-bindgen",
+ "wasmer-compiler",
+ "wasmer-compiler-cranelift",
+ "wasmer-compiler-llvm",
+ "wasmer-derive",
+ "wasmer-types",
+ "wasmer-vm",
+ "wasmparser 0.247.0",
+ "wat",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "wasmer-compiler"
+version = "7.2.0-alpha.2"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "cfg-if",
+ "crossbeam-channel",
+ "enum-iterator",
+ "enumset",
+ "itertools 0.14.0",
+ "leb128",
+ "libc",
+ "macho-unwind-info",
+ "memmap2 0.9.10",
+ "more-asserts",
+ "object 0.39.1",
+ "rangemap",
+ "rayon",
+ "region",
+ "rkyv",
+ "self_cell",
+ "shared-buffer",
+ "smallvec",
+ "target-lexicon",
+ "tempfile",
+ "thiserror",
+ "wasmer-types",
+ "wasmer-vm",
+ "wasmparser 0.247.0",
+ "which",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "wasmer-compiler-cranelift"
+version = "7.2.0-alpha.2"
+dependencies = [
+ "cranelift-codegen",
+ "cranelift-entity",
+ "cranelift-frontend",
+ "gimli 0.33.0",
+ "indexmap",
+ "itertools 0.14.0",
+ "leb128",
+ "more-asserts",
+ "rayon",
+ "smallvec",
+ "target-lexicon",
+ "tracing",
+ "wasmer-compiler",
+ "wasmer-types",
+]
+
+[[package]]
+name = "wasmer-compiler-llvm"
+version = "7.2.0-alpha.2"
+dependencies = [
+ "byteorder",
+ "cc",
+ "crossbeam-channel",
+ "enum-iterator",
+ "enumset",
+ "inkwell",
+ "itertools 0.14.0",
+ "libc",
+ "object 0.39.1",
+ "phf",
+ "rayon",
+ "regex",
+ "rustc_version",
+ "semver",
+ "smallvec",
+ "target-lexicon",
+ "tracing",
+ "wasmer-compiler",
+ "wasmer-types",
+ "wasmer-vm",
+]
+
+[[package]]
+name = "wasmer-config"
+version = "0.702.0-alpha.2"
+dependencies = [
+ "anyhow",
+ "bytesize",
+ "ciborium",
+ "derive_builder",
+ "hex",
+ "indexmap",
+ "saffron",
+ "schemars",
+ "semver",
+ "serde",
+ "serde_json",
+ "serde_yaml",
+ "thiserror",
+ "toml",
+ "url",
+]
+
+[[package]]
+name = "wasmer-derive"
+version = "7.2.0-alpha.2"
+dependencies = [
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "wasmer-journal"
+version = "0.702.0-alpha.2"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "base64",
+ "bincode",
+ "bytecheck",
+ "bytes",
+ "derive_more",
+ "lz4_flex",
+ "num_enum",
+ "rkyv",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tracing",
+ "virtual-fs",
+ "virtual-net",
+ "wasmer",
+ "wasmer-config",
+ "wasmer-wasix-types",
+]
+
+[[package]]
+name = "wasmer-package"
+version = "0.702.0-alpha.2"
+dependencies = [
+ "anyhow",
+ "bytes",
+ "cfg-if",
+ "ciborium",
+ "flate2",
+ "ignore",
+ "insta",
+ "libc",
+ "semver",
+ "serde",
+ "serde_json",
+ "sha2 0.11.0",
+ "shared-buffer",
+ "tar",
+ "tempfile",
+ "thiserror",
+ "toml",
+ "url",
+ "wasmer-config",
+ "wasmer-types",
+ "webc",
+]
+
+[[package]]
+name = "wasmer-types"
+version = "7.2.0-alpha.2"
+dependencies = [
+ "bytecheck",
+ "crc32fast",
+ "enum-iterator",
+ "enumset",
+ "getrandom 0.4.2",
+ "hex",
+ "indexmap",
+ "itertools 0.14.0",
+ "more-asserts",
+ "rkyv",
+ "serde",
+ "sha2 0.11.0",
+ "target-lexicon",
+ "thiserror",
+ "wasmparser 0.247.0",
+]
+
+[[package]]
+name = "wasmer-vm"
+version = "7.2.0-alpha.2"
+dependencies = [
+ "backtrace",
+ "bytesize",
+ "cc",
+ "cfg-if",
+ "corosensei",
+ "crossbeam-queue",
+ "dashmap",
+ "enum-iterator",
+ "fnv",
+ "gimli 0.33.0",
+ "indexmap",
+ "itertools 0.14.0",
+ "libc",
+ "libunwind",
+ "mach2 0.6.0",
+ "memoffset",
+ "more-asserts",
+ "parking_lot",
+ "region",
+ "rustversion",
+ "scopeguard",
+ "thiserror",
+ "wasmer-types",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "wasmer-wasix"
+version = "0.702.0-alpha.2"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "base64",
+ "bincode",
+ "blake3",
+ "bytecheck",
+ "bytes",
+ "cfg-if",
+ "cooked-waker",
+ "crossbeam-channel",
+ "dashmap",
+ "derive_more",
+ "flate2",
+ "fnv",
+ "futures",
+ "getrandom 0.3.4",
+ "getrandom 0.4.2",
+ "heapless",
+ "hex",
+ "http",
+ "libc",
+ "linked_hash_set",
+ "lz4_flex",
+ "num_enum",
+ "once_cell",
+ "petgraph",
+ "pin-project",
+ "pin-utils",
+ "rand 0.10.1",
+ "rkyv",
+ "rusty_pool",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "serde_yaml",
+ "sha2 0.11.0",
+ "shared-buffer",
+ "tempfile",
+ "terminal_size",
+ "termios",
+ "thiserror",
+ "tokio",
+ "tokio-stream",
+ "toml",
+ "tracing",
+ "url",
+ "urlencoding",
+ "virtual-fs",
+ "virtual-mio",
+ "virtual-net",
+ "waker-fn",
+ "wasm-encoder 0.247.0",
+ "wasmer",
+ "wasmer-config",
+ "wasmer-journal",
+ "wasmer-package",
+ "wasmer-types",
+ "wasmer-wasix-types",
+ "wasmparser 0.247.0",
+ "webc",
+ "weezl",
+ "windows-sys 0.61.2",
+ "xxhash-rust",
+ "zstd",
+]
+
+[[package]]
+name = "wasmer-wasix-types"
+version = "0.702.0-alpha.2"
+dependencies = [
+ "anyhow",
+ "bitflags 2.11.1",
+ "byteorder",
+ "cfg-if",
+ "num_enum",
+ "serde",
+ "time",
+ "tracing",
+ "wai-bindgen-gen-core",
+ "wai-bindgen-gen-rust",
+ "wai-bindgen-gen-rust-wasm",
+ "wai-bindgen-rust",
+ "wai-parser",
+ "wasmer",
+ "wasmer-derive",
+ "wasmer-types",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
+dependencies = [
+ "bitflags 2.11.1",
+ "hashbrown 0.15.5",
+ "indexmap",
+ "semver",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.247.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80"
+dependencies = [
+ "bitflags 2.11.1",
+ "indexmap",
+ "semver",
+]
+
+[[package]]
+name = "wasmtime-internal-core"
+version = "44.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "816a61a75275c6be435131fc625a4f5956daf24d9f9f59443e81cbef228929b3"
+dependencies = [
+ "hashbrown 0.16.1",
+ "libm",
+]
+
+[[package]]
+name = "wast"
+version = "247.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "579d2d47eb33b0cdf9b14723cb115f1e1b7d6e77aac6f0816e5b7c7aeaa418ff"
+dependencies = [
+ "bumpalo",
+ "leb128fmt",
+ "memchr",
+ "unicode-width",
+ "wasm-encoder 0.247.0",
+]
+
+[[package]]
+name = "wat"
+version = "1.247.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3f4091c56437e86f2b57fa2fac72c4f528957a605b3f44f7c0b3b19a17ac5ee"
+dependencies = [
+ "wast",
+]
+
+[[package]]
+name = "webc"
+version = "11.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20b8b523112384e8c1caf77cffdd371ca7e0013779f081e6beafc537f5b5325d"
+dependencies = [
+ "anyhow",
+ "base64",
+ "bytes",
+ "cfg-if",
+ "ciborium",
+ "document-features",
+ "ignore",
+ "indexmap",
+ "leb128",
+ "lexical-sort",
+ "libc",
+ "once_cell",
+ "path-clean",
+ "rand 0.9.4",
+ "serde",
+ "serde_json",
+ "sha2 0.10.9",
+ "shared-buffer",
+ "thiserror",
+ "url",
+]
+
+[[package]]
+name = "weezl"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
+
+[[package]]
+name = "which"
+version = "8.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+dependencies = [
+ "wit-bindgen-rust-macro",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.57.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
+
+[[package]]
+name = "wit-bindgen-core"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
+dependencies = [
+ "anyhow",
+ "heck 0.5.0",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-bindgen-rust"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
+dependencies = [
+ "anyhow",
+ "heck 0.5.0",
+ "indexmap",
+ "prettyplease",
+ "syn 2.0.117",
+ "wasm-metadata",
+ "wit-bindgen-core",
+ "wit-component",
+]
+
+[[package]]
+name = "wit-bindgen-rust-macro"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
+dependencies = [
+ "anyhow",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "wit-bindgen-core",
+ "wit-bindgen-rust",
+]
+
+[[package]]
+name = "wit-component"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
+dependencies = [
+ "anyhow",
+ "bitflags 2.11.1",
+ "indexmap",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-encoder 0.244.0",
+ "wasm-metadata",
+ "wasmparser 0.244.0",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-parser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+ "wasmparser 0.244.0",
+]
+
+[[package]]
+name = "writeable"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
+
+[[package]]
+name = "xattr"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
+dependencies = [
+ "libc",
+ "rustix",
+]
+
+[[package]]
+name = "xxhash-rust"
+version = "0.8.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3"
+
+[[package]]
+name = "yoke"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
+name = "zerotrie"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+
+[[package]]
+name = "zstd"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "7.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
+dependencies = [
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.16+zstd.1.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/Cargo.toml b/src/runtimes/liboliphaunt-wasix-postmaster/executor/Cargo.toml
new file mode 100644
index 000000000..2862a6a1c
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/Cargo.toml
@@ -0,0 +1,115 @@
+[package]
+name = "oliphaunt-wasix-postmaster-executor"
+description = "Compiler-free sealed executor for the Oliphaunt WASIX PostgreSQL postmaster product"
+publish = false
+authors = ["Oliphaunt contributors"]
+edition = "2024"
+homepage = "https://oliphaunt.dev"
+license = "MIT"
+repository = "https://github.com/f0rr0/oliphaunt"
+rust-version = "1.93"
+version = "7.2.0-alpha.2"
+
+[[bin]]
+name = "oliphaunt-wasix-postmaster-executor"
+path = "src/bin/executor.rs"
+doc = false
+required-features = ["product-executor"]
+
+[[bin]]
+name = "oliphaunt-wasix-start-proof"
+path = "src/bin/start-proof.rs"
+doc = false
+required-features = ["start-proof-tool"]
+
+[[bin]]
+name = "oliphaunt-wasix-memory-profile"
+path = "src/bin/memory-profile.rs"
+doc = false
+required-features = ["memory-profile-tool"]
+
+[[bin]]
+name = "oliphaunt-wasix-postmaster-compiler"
+path = "src/bin/compiler.rs"
+doc = false
+required-features = ["product-compiler"]
+
+[features]
+default = []
+product-executor = [
+	"memory-profile-core",
+	"dep:tokio",
+	"wasmer-wasix/ctrlc",
+	"wasmer-wasix/disable-all-logging",
+	"wasmer-wasix/host-fs",
+	"wasmer-wasix/host-threads",
+	"wasmer-wasix/host-vnet",
+	"wasmer-wasix/sys-poll",
+]
+# Build-time-only analyzer for the exact raw executable's WebAssembly start
+# closure. This binary is never copied into the compiler-free carrier.
+start-proof-tool = ["dep:wasmparser"]
+# Build-time-only exact WebAssembly memory-contract sealer. This binary is
+# never copied into the compiler-free carrier.
+memory-profile-core = ["dep:wasmer-vm"]
+memory-profile-tool = ["memory-profile-core", "dep:wasmparser"]
+# Build-time-only LLVM AOT producer with the product's explicit static-memory
+# tunables. Build it in a target directory separate from product-executor so
+# the shipped executor remains compiler-free.
+product-compiler = [
+	"memory-profile-tool",
+	"dep:wasmer-compiler-llvm",
+	"wasmer/llvm",
+]
+# Preserve the generic CLI's historical writable-snapshot search path without
+# making a user cache-directory resolver part of the product executor closure.
+compat-cache-dir = ["dep:dirs"]
+# These features exist only for the sealed artifact loader's positive-path
+# tests. Production builds must use --no-default-features and never enable
+# either compiler-bearing test feature.
+cranelift = ["memory-profile-core", "dep:wasmer-compiler-cranelift", "wasmer/cranelift"]
+wat = ["wasmer/wat"]
+
+[dependencies]
+anyhow = "1.0"
+async-trait = "0.1.68"
+dirs = { version = "6.0.0", optional = true }
+hex = "0.4"
+libc = { version = "0.2.178", default-features = false }
+serde = { version = "1", default-features = false, features = ["derive"] }
+serde_json = "1"
+sha2 = "0.11.0"
+tempfile = "3.6.0"
+tokio = { version = "1.39.0", default-features = false, optional = true, features = [
+	"rt-multi-thread",
+	"time",
+] }
+tracing = { version = "0.1", default-features = false }
+wasmer = { version = "=7.2.0-alpha.2", default-features = false, features = [
+	"headless",
+	"sys",
+] }
+wasmer-compiler-cranelift = { version = "=7.2.0-alpha.2", optional = true }
+wasmer-compiler-llvm = { version = "=7.2.0-alpha.2", optional = true }
+wasmer-types = { version = "=7.2.0-alpha.2", default-features = false, features = [
+	"std",
+] }
+wasmer-vm = { version = "=7.2.0-alpha.2", default-features = false, optional = true }
+wasmparser = { version = "0.247.0", default-features = false, features = ["validate", "features", "simd"], optional = true }
+wasmer-wasix = { version = "=0.702.0-alpha.2", default-features = false, features = [
+	"sys-minimal",
+] }
+
+[dev-dependencies]
+futures = "0.3.30"
+wat = "1.247.0"
+
+[package.metadata.oliphaunt-executor-policy]
+compiler-free = true
+exact-module-count = 29
+network = "host-only"
+package-resolution = false
+runtime-compilation = false
+
+# This product consumes a separately prepared, patched Wasmer workspace.
+[workspace]
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/README.md b/src/runtimes/liboliphaunt-wasix-postmaster/executor/README.md
new file mode 100644
index 000000000..15c724c10
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/README.md
@@ -0,0 +1,25 @@
+# Postmaster executor
+
+This crate owns the sealed WASIX PostgreSQL executor and its build-time analysis tools. It is an internal part of the postmaster runtime, not an independently published SDK. Its version matches the Wasmer artifact ABI family because sealed manifests compare that exact version.
+
+Prepare the pinned, patched Wasmer checkout from this directory:
+
+```sh
+moon run liboliphaunt-wasix-postmaster:prepare-runtime
+```
+
+Then ordinary Cargo commands work here:
+
+```sh
+cargo fmt --check
+cargo build --locked --release --no-default-features --features product-executor --bin oliphaunt-wasix-postmaster-executor
+cargo test --locked --release --no-default-features --features product-executor --lib
+```
+
+The preparation step writes only `.cargo/config.toml` with paths to the six patched Wasmer dependencies. The committed manifest declares their versions, features and ownership; the committed lockfile pins the remaining dependency closure. No executor source is copied into Wasmer. The patched generic Wasmer CLI depends directly on this crate for its sealed-loader functionality. To reconnect an already prepared checkout at a different location, run `bun prepare-paths.mts /absolute/path/to/wasmer`.
+
+The equivalent `moon run liboliphaunt-wasix-postmaster:executor-build` and `executor-test` tasks prepare dependencies first and share the product executor build directory. A source build without `OLIPHAUNT_WASIX_RUNTIME_ABI_ID` can run source tests and print its version, but intentionally cannot load a sealed release carrier. The complete `runtime-build` task computes that identity from the prepared inputs and creates the release receipts.
+
+The `product-executor` feature has no LLVM or Cranelift backend. Build-time tools are explicit features: `start-proof-tool`, `memory-profile-tool`, and `product-compiler`. The compiler requires LLVM 22 and must use its separate compiler target directory; `wasmer/bin/build-runtime.sh` maintains that separation and packaging copies only the executor into the carrier. The `cranelift,wat` feature pair exists solely for behavioral tests of sealed artifact loading.
+
+Run Cargo from this directory so its generated dependency-path configuration is loaded. All preparation is unprivileged; compilation requires the matching native host toolchain. Runtime concurrency and host-capability tests remain in the postmaster product’s `runtime-patch-tests` and capability qualification tasks.
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/prepare-paths.mts b/src/runtimes/liboliphaunt-wasix-postmaster/executor/prepare-paths.mts
new file mode 100644
index 000000000..2130793ae
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/prepare-paths.mts
@@ -0,0 +1,41 @@
+import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+const owner = import.meta.dir;
+const prepared = path.resolve(
+  process.argv[2] ??
+    path.join(owner, '../../../../target/oliphaunt-wasix-postmaster/runtime/wasmer'),
+);
+const crates = {
+  wasmer: 'api',
+  'wasmer-compiler-cranelift': 'compiler-cranelift',
+  'wasmer-compiler-llvm': 'compiler-llvm',
+  'wasmer-types': 'types',
+  'wasmer-vm': 'vm',
+  'wasmer-wasix': 'wasix',
+};
+let config =
+  '# Generated by executor/prepare-paths.mts; prepared dependency locations only.\n[patch.crates-io]\n';
+for (const [name, directory] of Object.entries(crates)) {
+  const location = path.join(prepared, 'lib', directory);
+  if (!existsSync(path.join(location, 'Cargo.toml'))) {
+    throw new Error(
+      `Missing prepared ${name}: ${location}; run the postmaster Wasmer preparation first`,
+    );
+  }
+  config += `${JSON.stringify(name)} = { path = ${JSON.stringify(location)} }\n`;
+}
+const cliManifest = path.join(prepared, 'lib/cli/Cargo.toml');
+const cli = readFileSync(cliManifest, 'utf8');
+const dependency = /^(oliphaunt-wasix-postmaster-executor = \{[^\n]*path = )"(?:[^"\\]|\\.)*"/m;
+if (!dependency.test(cli))
+  throw new Error(`Prepared CLI lacks the executor dependency: ${cliManifest}`);
+// The patched generic CLI shares the sealed loader. Point it at its actual owner.
+const ownerFromCli = path.relative(path.dirname(cliManifest), owner).split(path.sep).join('/');
+writeFileSync(
+  cliManifest,
+  cli.replace(dependency, (_, prefix) => prefix + JSON.stringify(ownerFromCli)),
+);
+mkdirSync(path.join(owner, '.cargo'), { recursive: true });
+writeFileSync(path.join(owner, '.cargo/config.toml'), config);
+console.log(`Prepared Cargo dependency paths for ${owner}`);
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/args.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/args.rs
new file mode 100644
index 000000000..0a9b33b9f
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/args.rs
@@ -0,0 +1,436 @@
+//! Strict command-line contract for the sealed PostgreSQL executor.
+
+use std::{collections::HashSet, ffi::OsString, path::PathBuf};
+
+use anyhow::{Context, Error, bail, ensure};
+
+/// Parsed top-level product command.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Command {
+    /// Print the executor version without initializing a runtime.
+    Version,
+    /// Execute one member of an exact sealed PostgreSQL carrier.
+    Run(RunOptions),
+}
+
+/// One explicit host-to-guest directory mapping.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct VolumeSpec {
+    /// Host directory, canonicalized immediately before execution.
+    pub host: PathBuf,
+    /// Absolute normalized Unix-style guest path.
+    pub guest: String,
+}
+
+/// Complete, closed execution request.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct RunOptions {
+    /// Suppress executor-owned informational output.
+    pub quiet: bool,
+    /// Exact sealed carrier manifest.
+    pub manifest: PathBuf,
+    /// Wasmer host stack allocation requested by the carrier recipe.
+    pub stack_size: usize,
+    /// Explicit host filesystem mappings.
+    pub volumes: Vec,
+    /// Selected `bin/initdb` or `bin/postgres` carrier member.
+    pub input: PathBuf,
+    /// Arguments passed to the selected PostgreSQL executable.
+    pub guest_args: Vec,
+}
+
+#[derive(Default)]
+struct SeenOptions {
+    quiet: bool,
+    disable_cache: bool,
+    manifest: bool,
+    stack_size: bool,
+    exceptions: bool,
+    threads: bool,
+    networking: bool,
+}
+
+impl SeenOptions {
+    fn once(slot: &mut bool, option: &str) -> Result<(), Error> {
+        ensure!(!*slot, "duplicate product executor option '{option}'");
+        *slot = true;
+        Ok(())
+    }
+}
+
+/// Parse the exact product command from an argv sequence, including argv[0].
+pub fn parse_from(arguments: I) -> Result
+where
+    I: IntoIterator,
+    S: Into,
+{
+    let arguments = arguments.into_iter().map(Into::into).collect::>();
+    ensure!(!arguments.is_empty(), "product executor argv is empty");
+    let tail = &arguments[1..];
+
+    if tail == [OsString::from("--version")] {
+        return Ok(Command::Version);
+    }
+    ensure!(
+        tail.first().is_some_and(|value| value == "run"),
+        "expected exactly 'run' or '--version'"
+    );
+
+    parse_run(&tail[1..]).map(Command::Run)
+}
+
+fn parse_run(arguments: &[OsString]) -> Result {
+    let mut seen = SeenOptions::default();
+    let mut manifest = None;
+    let mut stack_size = None;
+    let mut volumes = Vec::new();
+    let mut input = None;
+    let mut index = 0;
+
+    while index < arguments.len() {
+        let argument = &arguments[index];
+        if argument == "--" {
+            bail!("guest argument separator '--' appeared before the carrier executable");
+        }
+
+        let Some(text) = argument.to_str() else {
+            input = Some(PathBuf::from(argument));
+            index += 1;
+            break;
+        };
+        if !text.starts_with("--") {
+            input = Some(PathBuf::from(argument));
+            index += 1;
+            break;
+        }
+
+        let (name, inline_value) = text
+            .split_once('=')
+            .map_or((text, None), |(name, value)| (name, Some(value)));
+        match name {
+            "--quiet" => {
+                reject_inline_value(name, inline_value)?;
+                SeenOptions::once(&mut seen.quiet, name)?;
+            }
+            "--disable-cache" => {
+                reject_inline_value(name, inline_value)?;
+                SeenOptions::once(&mut seen.disable_cache, name)?;
+            }
+            "--enable-exceptions" => {
+                reject_inline_value(name, inline_value)?;
+                SeenOptions::once(&mut seen.exceptions, name)?;
+            }
+            "--enable-threads" => {
+                reject_inline_value(name, inline_value)?;
+                SeenOptions::once(&mut seen.threads, name)?;
+            }
+            "--net" => {
+                reject_inline_value(name, inline_value)?;
+                SeenOptions::once(&mut seen.networking, name)?;
+            }
+            "--sealed-module-manifest" => {
+                SeenOptions::once(&mut seen.manifest, name)?;
+                manifest = Some(PathBuf::from(take_os_value(
+                    arguments,
+                    &mut index,
+                    name,
+                    inline_value,
+                )?));
+            }
+            "--stack-size" => {
+                SeenOptions::once(&mut seen.stack_size, name)?;
+                let value = take_utf8_value(arguments, &mut index, name, inline_value)?;
+                let parsed = value
+                    .parse::()
+                    .with_context(|| format!("invalid value for {name}: '{value}'"))?;
+                ensure!(parsed > 0, "{name} must be greater than zero");
+                stack_size = Some(parsed);
+            }
+            "--volume" => {
+                let value = take_utf8_value(arguments, &mut index, name, inline_value)?;
+                volumes.push(parse_volume(&value)?);
+            }
+            _ => bail!("unsupported product executor option '{name}'"),
+        }
+        index += 1;
+    }
+
+    let input = input.context("sealed carrier executable is required")?;
+    let guest_args = if index == arguments.len() {
+        Vec::new()
+    } else {
+        ensure!(
+            arguments[index] == "--",
+            "arguments after the carrier executable require the '--' separator"
+        );
+        arguments[index + 1..]
+            .iter()
+            .map(|argument| {
+                argument
+                    .to_str()
+                    .map(ToOwned::to_owned)
+                    .context("PostgreSQL guest arguments must be valid UTF-8")
+            })
+            .collect::, _>>()?
+    };
+
+    ensure!(
+        seen.disable_cache,
+        "--disable-cache is required by the sealed executor contract"
+    );
+    ensure!(
+        seen.exceptions,
+        "--enable-exceptions is required by the sealed carrier ABI"
+    );
+    ensure!(
+        seen.threads,
+        "--enable-threads is required by the sealed carrier ABI"
+    );
+    ensure!(
+        seen.networking,
+        "--net is required by the PostgreSQL postmaster contract"
+    );
+    ensure!(
+        !volumes.is_empty(),
+        "at least one explicit --volume is required"
+    );
+
+    let manifest = manifest.context("--sealed-module-manifest is required")?;
+    let stack_size = stack_size.context("--stack-size is required")?;
+    let mut guest_mounts = HashSet::new();
+    for volume in &volumes {
+        ensure!(
+            guest_mounts.insert(volume.guest.as_str()),
+            "duplicate guest volume mount '{}'",
+            volume.guest
+        );
+    }
+
+    Ok(RunOptions {
+        quiet: seen.quiet,
+        manifest,
+        stack_size,
+        volumes,
+        input,
+        guest_args,
+    })
+}
+
+fn reject_inline_value(option: &str, value: Option<&str>) -> Result<(), Error> {
+    ensure!(value.is_none(), "flag '{option}' does not accept a value");
+    Ok(())
+}
+
+fn take_os_value(
+    arguments: &[OsString],
+    index: &mut usize,
+    option: &str,
+    inline_value: Option<&str>,
+) -> Result {
+    if let Some(value) = inline_value {
+        ensure!(!value.is_empty(), "{option} requires a non-empty value");
+        return Ok(OsString::from(value));
+    }
+    *index = index.checked_add(1).context("argument index overflow")?;
+    let value = arguments
+        .get(*index)
+        .with_context(|| format!("{option} requires a value"))?;
+    ensure!(!value.is_empty(), "{option} requires a non-empty value");
+    Ok(value.clone())
+}
+
+fn take_utf8_value(
+    arguments: &[OsString],
+    index: &mut usize,
+    option: &str,
+    inline_value: Option<&str>,
+) -> Result {
+    let value = take_os_value(arguments, index, option, inline_value)?;
+    value
+        .into_string()
+        .map_err(|_| anyhow::anyhow!("{option} requires a valid UTF-8 value"))
+}
+
+fn parse_volume(value: &str) -> Result {
+    let (host, guest) = value
+        .rsplit_once(':')
+        .context("--volume requires an explicit HOST_DIR:GUEST_DIR mapping")?;
+    ensure!(
+        !host.is_empty(),
+        "--volume host directory must not be empty"
+    );
+    validate_guest_path(guest)?;
+    Ok(VolumeSpec {
+        host: PathBuf::from(host),
+        guest: guest.to_owned(),
+    })
+}
+
+pub(crate) fn validate_guest_path(path: &str) -> Result<(), Error> {
+    ensure!(
+        path.starts_with('/'),
+        "--volume guest path must be absolute"
+    );
+    ensure!(
+        path == "/" || !path.ends_with('/'),
+        "--volume guest path must be normalized"
+    );
+    ensure!(
+        !path.contains("//"),
+        "--volume guest path must be normalized"
+    );
+    ensure!(
+        path.split('/')
+            .all(|component| component != "." && component != ".."),
+        "--volume guest path must not contain '.' or '..' components"
+    );
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn valid_args() -> Vec {
+        [
+            "executor",
+            "run",
+            "--quiet",
+            "--disable-cache",
+            "--stack-size",
+            "33554432",
+            "--sealed-module-manifest",
+            "/carrier/manifest.json",
+            "--enable-exceptions",
+            "--enable-threads",
+            "--net",
+            "--volume",
+            "/carrier:/carrier",
+            "--volume=/runtime/lib:/lib",
+            "/carrier/bin/postgres",
+            "--",
+            "-D",
+            "/pgdata",
+        ]
+        .into_iter()
+        .map(OsString::from)
+        .collect()
+    }
+
+    #[test]
+    fn parses_the_complete_closed_product_contract() {
+        let command = parse_from(valid_args()).unwrap();
+        let Command::Run(run) = command else {
+            panic!("expected run command");
+        };
+        assert!(run.quiet);
+        assert_eq!(run.stack_size, 33_554_432);
+        assert_eq!(run.manifest, PathBuf::from("/carrier/manifest.json"));
+        assert_eq!(run.input, PathBuf::from("/carrier/bin/postgres"));
+        assert_eq!(run.guest_args, ["-D", "/pgdata"]);
+        assert_eq!(run.volumes.len(), 2);
+    }
+
+    #[test]
+    fn version_is_the_only_non_run_surface() {
+        assert_eq!(
+            parse_from(["executor", "--version"]).unwrap(),
+            Command::Version
+        );
+        assert!(parse_from(["executor", "--help"]).is_err());
+        assert!(parse_from(["executor", "package", "list"]).is_err());
+        assert!(parse_from(["executor", "--version", "extra"]).is_err());
+    }
+
+    #[test]
+    fn denies_unknown_generic_wasmer_options() {
+        for denied in [
+            "--llvm",
+            "--cranelift",
+            "--singlepass",
+            "--use",
+            "--include-webc",
+            "--map-command",
+            "--env",
+            "--http-client",
+            "--invoke",
+            "--entrypoint",
+            "--enable-simd",
+            "--net=ipv4:allow=127.0.0.1:*",
+        ] {
+            let mut args = valid_args();
+            args.insert(2, OsString::from(denied));
+            assert!(parse_from(args).is_err(), "accepted denied option {denied}");
+        }
+    }
+
+    #[test]
+    fn required_abi_and_cache_assertions_fail_closed() {
+        for required in [
+            "--disable-cache",
+            "--enable-exceptions",
+            "--enable-threads",
+            "--net",
+            "--stack-size",
+            "--sealed-module-manifest",
+        ] {
+            let mut args = valid_args();
+            let index = args.iter().position(|arg| arg == required).unwrap();
+            args.remove(index);
+            if matches!(required, "--stack-size" | "--sealed-module-manifest") {
+                args.remove(index);
+            }
+            assert!(
+                parse_from(args).is_err(),
+                "accepted request without {required}"
+            );
+        }
+    }
+
+    #[test]
+    fn duplicate_scalar_options_and_guest_mounts_are_rejected() {
+        let mut duplicate_flag = valid_args();
+        duplicate_flag.insert(2, OsString::from("--enable-threads"));
+        assert!(parse_from(duplicate_flag).is_err());
+
+        let mut duplicate_mount = valid_args();
+        duplicate_mount.splice(
+            2..2,
+            [OsString::from("--volume"), OsString::from("/other:/lib")],
+        );
+        assert!(parse_from(duplicate_mount).is_err());
+    }
+
+    #[test]
+    fn executable_and_guest_arguments_have_an_unambiguous_boundary() {
+        let mut missing_separator = valid_args();
+        let separator = missing_separator
+            .iter()
+            .position(|arg| arg == "--")
+            .unwrap();
+        missing_separator.remove(separator);
+        assert!(parse_from(missing_separator).is_err());
+
+        let mut separator_before_input = valid_args();
+        let input = separator_before_input
+            .iter()
+            .position(|arg| arg == "/carrier/bin/postgres")
+            .unwrap();
+        separator_before_input.insert(input, OsString::from("--"));
+        assert!(parse_from(separator_before_input).is_err());
+    }
+
+    #[test]
+    fn volumes_require_normalized_absolute_guest_paths() {
+        for invalid in [
+            "/host:relative",
+            "/host:/a/../b",
+            "/host:/a//b",
+            "/host:/a/",
+            ":/guest",
+        ] {
+            assert!(parse_volume(invalid).is_err(), "accepted {invalid}");
+        }
+        assert_eq!(parse_volume("C:\\data:/data").unwrap().guest, "/data");
+    }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/compiler.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/compiler.rs
new file mode 100644
index 000000000..c323d4db5
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/compiler.rs
@@ -0,0 +1,211 @@
+use std::{env, ffi::OsString, fs, num::NonZeroUsize, path::PathBuf};
+
+use anyhow::{Context, Result, bail, ensure};
+use oliphaunt_wasix_postmaster_executor::memory_profile::{
+    LinearMemoryProfile, compiler_tunables_for_target, derived_static_style,
+    validate_serialized_memory_plans, verify_module_bytes,
+};
+use wasmer::{
+    Engine, Module,
+    sys::{CompilerConfig, NativeEngineExt},
+};
+use wasmer_compiler_llvm::{LLVM, LLVMOptLevel};
+use wasmer_types::{
+    Features, ModuleHash,
+    target::{CpuFeature, Target, Triple},
+};
+
+const USAGE: &str = "usage: oliphaunt-wasix-postmaster-compiler --llvm --llvm-opt-level aggressive [--compiler-threads N] --enable-exceptions --enable-threads -o OUTPUT MODULE\n       oliphaunt-wasix-postmaster-compiler verify-aot MODULE ARTIFACT";
+
+#[derive(Debug)]
+struct Options {
+    input: PathBuf,
+    output: PathBuf,
+    compiler_threads: Option,
+}
+
+fn take_value(arguments: &[OsString], index: &mut usize, option: &str) -> Result {
+    *index += 1;
+    arguments
+        .get(*index)
+        .cloned()
+        .with_context(|| format!("{option} requires a value; {USAGE}"))
+}
+
+fn parse() -> Result> {
+    let arguments: Vec<_> = env::args_os().skip(1).collect();
+    if arguments.len() == 1 && arguments[0] == "--version" {
+        println!(
+            "oliphaunt-wasix-postmaster-compiler {} {}",
+            oliphaunt_wasix_postmaster_executor::VERSION,
+            LinearMemoryProfile::embedded().id()
+        );
+        return Ok(None);
+    }
+
+    let mut llvm = false;
+    let mut exceptions = false;
+    let mut threads = false;
+    let mut output = None;
+    let mut input = None;
+    let mut compiler_threads = None;
+    let mut index = 0;
+    while index < arguments.len() {
+        let argument = &arguments[index];
+        match argument.to_str() {
+            Some("--llvm") => llvm = true,
+            Some("--enable-exceptions") => exceptions = true,
+            Some("--enable-threads") => threads = true,
+            Some("--llvm-opt-level") => {
+                let value =
+                    take_value(&arguments, &mut index, argument.to_string_lossy().as_ref())?;
+                ensure!(
+                    value == "aggressive",
+                    "the product compiler requires --llvm-opt-level aggressive"
+                );
+            }
+            Some("--compiler-threads") => {
+                let value =
+                    take_value(&arguments, &mut index, argument.to_string_lossy().as_ref())?;
+                let parsed = value
+                    .to_str()
+                    .context("compiler thread count is not UTF-8")?
+                    .parse::()
+                    .context("compiler thread count is not an integer")?;
+                compiler_threads = Some(
+                    NonZeroUsize::new(parsed).context("compiler thread count must be positive")?,
+                );
+            }
+            Some("-o") => {
+                ensure!(output.is_none(), "output path was supplied more than once");
+                output = Some(PathBuf::from(take_value(&arguments, &mut index, "-o")?));
+            }
+            Some(value) if value.starts_with('-') => {
+                bail!("unsupported option '{value}'; {USAGE}")
+            }
+            _ => {
+                ensure!(
+                    input.is_none(),
+                    "more than one input module was supplied; {USAGE}"
+                );
+                input = Some(PathBuf::from(argument));
+            }
+        }
+        index += 1;
+    }
+    ensure!(llvm, "the product compiler requires --llvm");
+    ensure!(
+        exceptions,
+        "the product compiler requires --enable-exceptions"
+    );
+    ensure!(threads, "the product compiler requires --enable-threads");
+    Ok(Some(Options {
+        input: input.with_context(|| USAGE.to_owned())?,
+        output: output.with_context(|| USAGE.to_owned())?,
+        compiler_threads,
+    }))
+}
+
+fn main() -> Result<()> {
+    let arguments: Vec<_> = env::args_os().skip(1).collect();
+    if arguments.first().and_then(|value| value.to_str()) == Some("verify-aot") {
+        ensure!(arguments.len() == 3, "verify-aot requires MODULE ARTIFACT");
+        return verify_aot(PathBuf::from(&arguments[1]), PathBuf::from(&arguments[2]));
+    }
+    let Some(options) = parse()? else {
+        return Ok(());
+    };
+    let module_bytes = fs::read(&options.input)
+        .with_context(|| format!("read sealed module {}", options.input.display()))?;
+    verify_module_bytes(&module_bytes)
+        .with_context(|| format!("admit sealed module {}", options.input.display()))?;
+
+    let mut compiler = LLVM::new();
+    compiler
+        .opt_level(LLVMOptLevel::Aggressive)
+        .non_volatile_memops(true)
+        .readonly_funcref_table(true);
+    if let Some(threads) = options.compiler_threads {
+        compiler.num_threads(threads);
+    }
+
+    // The carrier promises a relocatable architecture baseline. Never inherit
+    // host features here: doing so would make an otherwise receipt-identical
+    // artifact capable of trapping with SIGILL on an older embedded host.
+    let target = Target::new(Triple::host(), CpuFeature::set());
+    let tunables = compiler_tunables_for_target(&target)
+        .context("derive product compiler linear-memory profile")?;
+    let (static_bound_pages, static_offset_guard_bytes) = derived_static_style(&tunables, 0)
+        .context("prove product compiler linear-memory allocation style")?;
+    let mut features = Features::default();
+    features.threads(true).exceptions(true);
+    let mut engine = Engine::new(
+        Box::new(compiler) as Box,
+        target,
+        features,
+    );
+    engine.set_tunables(tunables);
+
+    eprintln!(
+        "Compiler: llvm; profile: {}; guest-max-pages: {}; static-bound-pages: {}; static-offset-guard-bytes: {}",
+        LinearMemoryProfile::embedded().id(),
+        LinearMemoryProfile::embedded().maximum_pages(),
+        static_bound_pages,
+        static_offset_guard_bytes
+    );
+    let module = Module::new(&engine, &module_bytes)
+        .with_context(|| format!("compile sealed module {}", options.input.display()))?;
+    module
+        .serialize_to_file(&options.output)
+        .with_context(|| format!("write AOT artifact {}", options.output.display()))?;
+    Ok(())
+}
+
+fn verify_aot(module_path: PathBuf, artifact_path: PathBuf) -> Result<()> {
+    let module_bytes = fs::read(&module_path)
+        .with_context(|| format!("read sealed module {}", module_path.display()))?;
+    verify_module_bytes(&module_bytes)
+        .with_context(|| format!("admit sealed module {}", module_path.display()))?;
+    let target = Target::new(Triple::host(), CpuFeature::set());
+    let tunables = compiler_tunables_for_target(&target)
+        .context("derive product verifier linear-memory profile")?;
+    let mut features = Features::default();
+    features.threads(true).exceptions(true);
+    let mut compiler = LLVM::new();
+    compiler
+        .opt_level(LLVMOptLevel::Aggressive)
+        .non_volatile_memops(true)
+        .readonly_funcref_table(true);
+    let mut engine = Engine::new(
+        Box::new(compiler) as Box,
+        target,
+        features,
+    );
+    engine.set_tunables(tunables);
+
+    let file = fs::File::open(&artifact_path)
+        .with_context(|| format!("open AOT artifact {}", artifact_path.display()))?;
+    let mapping = wasmer::sys::OwnedBuffer::from_file(&file)
+        .with_context(|| format!("map AOT artifact {}", artifact_path.display()))?;
+    let expected_hash = ModuleHash::new(&module_bytes);
+    let inspected = engine
+        .inspect_serialized_artifact(&mapping)
+        .with_context(|| format!("inspect AOT artifact {}", artifact_path.display()))?;
+    ensure!(
+        inspected == expected_hash,
+        "AOT embedded module hash differs"
+    );
+    // SAFETY: the exact opened artifact was structurally inspected above and
+    // remains owned by this process. Dropping the pending activation rolls all
+    // code registrations back after the allocation plan is attested.
+    let pending = unsafe { engine.deserialize_from_mmapped_buffer_detached_pending(mapping) }
+        .with_context(|| format!("admit AOT artifact {}", artifact_path.display()))?;
+    ensure!(
+        pending.module_hash() == Some(expected_hash),
+        "activated AOT embedded module hash differs"
+    );
+    validate_serialized_memory_plans(&pending.linear_memory_plans())
+        .context("AOT linear-memory allocation plan differs")?;
+    println!("{}", expected_hash);
+    Ok(())
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/executor.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/executor.rs
new file mode 100644
index 000000000..f7c24a43b
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/executor.rs
@@ -0,0 +1,3 @@
+fn main() {
+    std::process::exit(oliphaunt_wasix_postmaster_executor::run_from_env());
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/memory-profile.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/memory-profile.rs
new file mode 100644
index 000000000..a6eb79319
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/memory-profile.rs
@@ -0,0 +1,48 @@
+use std::{env, ffi::OsString, path::PathBuf};
+
+use anyhow::{Context, Result, bail, ensure};
+use oliphaunt_wasix_postmaster_executor::memory_profile::{
+    profile_json, seal_module, verify_module,
+};
+
+const USAGE: &str = "usage: oliphaunt-wasix-memory-profile --profile-json\n       oliphaunt-wasix-memory-profile verify MODULE\n       oliphaunt-wasix-memory-profile seal --output SEALED --receipt RECEIPT MODULE";
+
+fn take_path(arguments: &mut impl Iterator, name: &str) -> Result {
+    arguments
+        .next()
+        .map(PathBuf::from)
+        .with_context(|| format!("missing {name}; {USAGE}"))
+}
+
+fn main() -> Result<()> {
+    let mut arguments = env::args_os().skip(1);
+    let command = arguments.next().with_context(|| USAGE.to_owned())?;
+    if command == "--profile-json" {
+        ensure!(arguments.next().is_none(), "{USAGE}");
+        println!("{}", profile_json()?);
+        return Ok(());
+    }
+    if command == "verify" {
+        let module = take_path(&mut arguments, "MODULE")?;
+        ensure!(arguments.next().is_none(), "{USAGE}");
+        println!("{}", verify_module(&module)?);
+        return Ok(());
+    }
+    if command == "seal" {
+        ensure!(
+            arguments.next().as_deref() == Some("--output".as_ref()),
+            "{USAGE}"
+        );
+        let output = take_path(&mut arguments, "SEALED")?;
+        ensure!(
+            arguments.next().as_deref() == Some("--receipt".as_ref()),
+            "{USAGE}"
+        );
+        let receipt = take_path(&mut arguments, "RECEIPT")?;
+        let module = take_path(&mut arguments, "MODULE")?;
+        ensure!(arguments.next().is_none(), "{USAGE}");
+        seal_module(&module, &output, &receipt)?;
+        return Ok(());
+    }
+    bail!("unknown command '{}'; {USAGE}", command.to_string_lossy())
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/start-proof.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/start-proof.rs
new file mode 100644
index 000000000..558aa5cc0
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/bin/start-proof.rs
@@ -0,0 +1,561 @@
+use std::{
+    collections::{BTreeMap, BTreeSet, VecDeque},
+    env, fs,
+    ops::Range,
+};
+
+use anyhow::{Context, Result, bail, ensure};
+use serde::Serialize;
+use sha2::{Digest, Sha256};
+use wasmparser::{ExternalKind, Operator, Parser, Payload, TypeRef, Validator, WasmFeatures};
+
+const PROOF_SCHEMA: &str = "oliphaunt.wasix-postmaster.deterministic-start-proof.v1";
+const POLICY: &str = "llvm-shared-memory-init-restricted-effects.v1";
+const START_EXPORT: &str = "__wasm_init_memory";
+
+#[derive(Debug, Default)]
+struct Effects {
+    allowed: bool,
+    rejection: Option,
+    calls: BTreeMap,
+    global_gets: BTreeSet,
+    global_sets: BTreeSet,
+    memory_init: Vec,
+    data_drop: Vec,
+    block_count: u32,
+    br_count: u32,
+    br_table_count: u32,
+    memory_fill_count: u32,
+    cmpxchg_count: u32,
+    atomic_store_count: u32,
+    atomic_notify_count: u32,
+    atomic_wait_count: u32,
+}
+
+#[derive(Debug)]
+struct BodySummary {
+    range: Range,
+    effects: Effects,
+}
+
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "kebab-case")]
+struct Proof {
+    schema: &'static str,
+    analyzer_policy: &'static str,
+    module_sha256: String,
+    proof_sha256: String,
+    start_function_index: u32,
+    start_function_export: &'static str,
+    transitive_function_indices: Vec,
+    imported_function_calls: u32,
+    memory_reads: &'static str,
+    memory_effects: &'static str,
+    global_effects: &'static str,
+    table_effects: &'static str,
+    requires_fresh_zeroed_memory: bool,
+    ordinary_start_execution_per_instance: bool,
+    first_instance_full_byte_validation: bool,
+}
+
+fn main() -> Result<()> {
+    let mut arguments = env::args().skip(1);
+    let path = arguments
+        .next()
+        .context("usage: oliphaunt-wasix-start-proof MODULE | --policy-id")?;
+    if path == "--policy-id" {
+        ensure!(
+            arguments.next().is_none(),
+            "--policy-id accepts no arguments"
+        );
+        println!("{POLICY}");
+        return Ok(());
+    }
+    ensure!(
+        arguments.next().is_none(),
+        "analyzer accepts exactly one module"
+    );
+    let bytes = fs::read(&path).with_context(|| format!("read {path}"))?;
+    Validator::new_with_features(WasmFeatures::default() | WasmFeatures::THREADS)
+        .validate_all(&bytes)
+        .context("validate input WebAssembly")?;
+
+    let module_sha256 = hex::encode(Sha256::digest(&bytes));
+    let mut imported_functions = 0_u32;
+    let mut imported_globals = Vec::new();
+    let mut shared_memory_imports = 0_u32;
+    let mut start = None;
+    let mut function_exports = BTreeMap::new();
+    let mut bodies = BTreeMap::new();
+    let mut local_body = 0_u32;
+    let mut passive_data = BTreeMap::new();
+
+    for payload in Parser::new(0).parse_all(&bytes) {
+        match payload? {
+            Payload::ImportSection(section) => {
+                for import in section.into_imports() {
+                    let import = import?;
+                    match import.ty {
+                        TypeRef::Func(_) | TypeRef::FuncExact(_) => imported_functions += 1,
+                        TypeRef::Global(ty) => {
+                            imported_globals.push((
+                                import.module.to_owned(),
+                                import.name.to_owned(),
+                                ty,
+                            ));
+                        }
+                        TypeRef::Memory(ty)
+                            if import.module == "env" && import.name == "memory" && ty.shared =>
+                        {
+                            shared_memory_imports += 1;
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            Payload::ExportSection(section) => {
+                for export in section {
+                    let export = export?;
+                    if export.kind == ExternalKind::Func {
+                        function_exports.insert(export.name.to_owned(), export.index);
+                    }
+                }
+            }
+            Payload::StartSection { func, .. } => start = Some(func),
+            Payload::CodeSectionEntry(body) => {
+                let index = imported_functions + local_body;
+                local_body += 1;
+                bodies.insert(
+                    index,
+                    BodySummary {
+                        range: body.range(),
+                        effects: analyze_body(body)?,
+                    },
+                );
+            }
+            Payload::DataSection(section) => {
+                for (index, data) in section.into_iter().enumerate() {
+                    let data = data?;
+                    ensure!(
+                        matches!(data.kind, wasmparser::DataKind::Passive),
+                        "deterministic-start policy rejects active data segment {index}"
+                    );
+                    passive_data.insert(index as u32, data.data.len());
+                }
+            }
+            _ => {}
+        }
+    }
+
+    ensure!(
+        shared_memory_imports == 1,
+        "policy requires one shared env.memory import"
+    );
+    let start = start.context("module has no start section")?;
+    ensure!(
+        function_exports.get(START_EXPORT) == Some(&start),
+        "module start is not exported as {START_EXPORT}"
+    );
+    ensure!(start >= imported_functions, "module start is imported");
+
+    let mut closure = BTreeSet::new();
+    let mut queue = VecDeque::from([start]);
+    while let Some(index) = queue.pop_front() {
+        if !closure.insert(index) {
+            continue;
+        }
+        ensure!(
+            index >= imported_functions,
+            "start closure calls imported function {index}"
+        );
+        let body = bodies
+            .get(&index)
+            .with_context(|| format!("missing body for local function {index}"))?;
+        ensure!(
+            body.effects.allowed,
+            "function {index} is outside restricted-effects policy: {}",
+            body.effects
+                .rejection
+                .as_deref()
+                .unwrap_or("unknown operator")
+        );
+        for called in body.effects.calls.keys() {
+            if *called < imported_functions {
+                bail!("start closure calls imported function {called}");
+            }
+            queue.push_back(*called);
+        }
+    }
+
+    validate_call_shape(start, &closure, &bodies)?;
+    let start_effects = &bodies.get(&start).unwrap().effects;
+    ensure!(
+        start_effects.block_count == 3,
+        "unexpected LLVM init guard block shape"
+    );
+    ensure!(
+        start_effects.br_table_count == 1 && start_effects.br_count == 1,
+        "unexpected LLVM init guard branches"
+    );
+    ensure!(
+        start_effects.cmpxchg_count == 1,
+        "policy requires one initialization-guard cmpxchg"
+    );
+    ensure!(
+        start_effects.atomic_store_count == 1,
+        "policy requires one initialization-guard store"
+    );
+    ensure!(
+        start_effects.atomic_notify_count == 1,
+        "policy requires one initialization-guard notify"
+    );
+    ensure!(
+        start_effects.atomic_wait_count == 1,
+        "policy requires one initialization-guard wait"
+    );
+    ensure!(
+        start_effects.memory_fill_count == 1,
+        "policy requires one deterministic BSS fill"
+    );
+    ensure!(
+        start_effects.memory_init.len() == passive_data.len(),
+        "every passive data segment must be initialized exactly once"
+    );
+    ensure!(
+        start_effects
+            .memory_init
+            .iter()
+            .copied()
+            .collect::>()
+            == passive_data.keys().copied().collect::>(),
+        "memory.init coverage differs from passive data segments"
+    );
+    ensure!(
+        start_effects.data_drop == vec![1, 2],
+        "policy requires LLVM TLS segment 0 retained and segments 1/2 dropped"
+    );
+    ensure!(
+        passive_data.len() == 3,
+        "policy expects LLVM TLS/data/BSS passive segment layout"
+    );
+
+    let memory_base_import = imported_globals
+        .iter()
+        .enumerate()
+        .find(|(_, (module, name, ty))| {
+            module == "env"
+                && name == "__memory_base"
+                && !ty.mutable
+                && ty.content_type == wasmparser::ValType::I32
+        })
+        .map(|(index, _)| index as u32)
+        .context("missing immutable i32 env.__memory_base import")?;
+    let all_gets = closure
+        .iter()
+        .flat_map(|index| bodies[index].effects.global_gets.iter().copied())
+        .collect::>();
+    let all_sets = closure
+        .iter()
+        .flat_map(|index| bodies[index].effects.global_sets.iter().copied())
+        .collect::>();
+    ensure!(
+        all_gets
+            .iter()
+            .all(|index| { *index == memory_base_import || all_sets.contains(index) }),
+        "start closure reads a global not derived from __memory_base"
+    );
+    ensure!(
+        all_sets
+            .iter()
+            .all(|index| *index >= imported_globals.len() as u32),
+        "start closure mutates an imported global"
+    );
+    ensure!(
+        !all_sets.is_empty(),
+        "policy requires local numeric relocation globals"
+    );
+
+    let mut proof_hasher = Sha256::new();
+    proof_hasher.update(POLICY.as_bytes());
+    proof_hasher.update([0]);
+    proof_hasher.update(module_sha256.as_bytes());
+    for index in &closure {
+        let body = &bodies[index];
+        proof_hasher.update(index.to_le_bytes());
+        proof_hasher.update((body.range.len() as u64).to_le_bytes());
+        proof_hasher.update(&bytes[body.range.clone()]);
+    }
+
+    let proof = Proof {
+        schema: PROOF_SCHEMA,
+        analyzer_policy: POLICY,
+        module_sha256,
+        proof_sha256: hex::encode(proof_hasher.finalize()),
+        start_function_index: start,
+        start_function_export: START_EXPORT,
+        transitive_function_indices: closure.into_iter().collect(),
+        imported_function_calls: 0,
+        memory_reads: "fresh-zero-atomic-guard-only",
+        memory_effects: "passive-data-init-zero-fill-atomic-guard-only",
+        global_effects: "local-numeric-relocations-only",
+        table_effects: "none",
+        requires_fresh_zeroed_memory: true,
+        ordinary_start_execution_per_instance: true,
+        first_instance_full_byte_validation: true,
+    };
+    serde_json::to_writer_pretty(std::io::stdout().lock(), &proof)?;
+    println!();
+    Ok(())
+}
+
+fn analyze_body(body: wasmparser::FunctionBody<'_>) -> Result {
+    let mut effects = Effects {
+        allowed: true,
+        ..Effects::default()
+    };
+    for operator in body.get_operators_reader()? {
+        let operator = operator?;
+        match operator {
+            Operator::GlobalGet { global_index } => {
+                effects.global_gets.insert(global_index);
+            }
+            Operator::GlobalSet { global_index } => {
+                effects.global_sets.insert(global_index);
+            }
+            Operator::Call { function_index } => {
+                let count = effects.calls.entry(function_index).or_default();
+                *count = count.checked_add(1).context("direct call count overflow")?;
+            }
+            Operator::MemoryInit { data_index, mem: 0 } => effects.memory_init.push(data_index),
+            Operator::DataDrop { data_index } => effects.data_drop.push(data_index),
+            Operator::MemoryFill { mem: 0 } => effects.memory_fill_count += 1,
+            Operator::I32AtomicRmwCmpxchg { memarg }
+                if memarg.memory == 0 && memarg.offset == 0 && memarg.align == 2 =>
+            {
+                effects.cmpxchg_count += 1;
+            }
+            Operator::I32AtomicStore { memarg }
+                if memarg.memory == 0 && memarg.offset == 0 && memarg.align == 2 =>
+            {
+                effects.atomic_store_count += 1;
+            }
+            Operator::MemoryAtomicNotify { memarg }
+                if memarg.memory == 0 && memarg.offset == 0 && memarg.align == 2 =>
+            {
+                effects.atomic_notify_count += 1;
+            }
+            Operator::MemoryAtomicWait32 { memarg }
+                if memarg.memory == 0 && memarg.offset == 0 && memarg.align == 2 =>
+            {
+                effects.atomic_wait_count += 1;
+            }
+            Operator::Block { .. } => effects.block_count += 1,
+            Operator::Br { .. } => effects.br_count += 1,
+            Operator::BrTable { .. } => effects.br_table_count += 1,
+            Operator::I32Const { .. }
+            | Operator::I64Const { .. }
+            | Operator::I32Add
+            | Operator::LocalGet { .. }
+            | Operator::LocalSet { .. }
+            | Operator::LocalTee { .. }
+            | Operator::Drop
+            | Operator::End => {}
+            rejected => {
+                effects.allowed = false;
+                effects.rejection = Some(format!("{rejected:?}"));
+                break;
+            }
+        }
+    }
+    Ok(effects)
+}
+
+fn has_call_cycle(
+    start: u32,
+    closure: &BTreeSet,
+    bodies: &BTreeMap,
+) -> Result {
+    fn visit(
+        index: u32,
+        closure: &BTreeSet,
+        bodies: &BTreeMap,
+        visiting: &mut BTreeSet,
+        visited: &mut BTreeSet,
+    ) -> Result {
+        if visiting.contains(&index) {
+            return Ok(true);
+        }
+        if !visited.insert(index) {
+            return Ok(false);
+        }
+        visiting.insert(index);
+        for called in bodies
+            .get(&index)
+            .context("missing call-graph body")?
+            .effects
+            .calls
+            .keys()
+        {
+            ensure!(
+                closure.contains(called),
+                "call graph escaped analyzed closure"
+            );
+            if visit(*called, closure, bodies, visiting, visited)? {
+                return Ok(true);
+            }
+        }
+        visiting.remove(&index);
+        Ok(false)
+    }
+
+    visit(
+        start,
+        closure,
+        bodies,
+        &mut BTreeSet::new(),
+        &mut BTreeSet::new(),
+    )
+}
+
+fn validate_call_shape(
+    start: u32,
+    closure: &BTreeSet,
+    bodies: &BTreeMap,
+) -> Result<()> {
+    ensure!(
+        closure.len() == 2,
+        "LLVM init policy expects start plus one relocation helper"
+    );
+    ensure!(
+        !has_call_cycle(start, closure, bodies)?,
+        "start call graph is cyclic"
+    );
+    let helper = *closure
+        .iter()
+        .find(|index| **index != start)
+        .context("relocation helper is missing")?;
+    let start_effects = &bodies
+        .get(&start)
+        .context("start function body is missing")?
+        .effects;
+    let helper_effects = &bodies
+        .get(&helper)
+        .context("relocation helper body is missing")?
+        .effects;
+    ensure!(
+        start_effects.calls == BTreeMap::from([(helper, 1)]),
+        "start must call only its relocation helper exactly once"
+    );
+    ensure!(
+        helper_effects.calls.is_empty(),
+        "relocation helper must be a leaf"
+    );
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn first_body_effects(wat_source: &str) -> Effects {
+        let bytes = wat::parse_str(wat_source).unwrap();
+        for payload in Parser::new(0).parse_all(&bytes) {
+            if let Payload::CodeSectionEntry(body) = payload.unwrap() {
+                return analyze_body(body).unwrap();
+            }
+        }
+        panic!("fixture has no function body");
+    }
+
+    #[test]
+    fn policy_rejects_memory_reads() {
+        let effects =
+            first_body_effects("(module (memory 1) (func (drop (i32.load (i32.const 0)))))");
+        assert!(!effects.allowed);
+        assert!(effects.rejection.unwrap().starts_with("I32Load"));
+    }
+
+    #[test]
+    fn policy_rejects_indirect_calls_and_table_effects() {
+        let indirect = first_body_effects(
+            "(module (type (func)) (table 1 funcref) (func (call_indirect (type 0) (i32.const 0))))",
+        );
+        assert!(!indirect.allowed);
+        assert!(indirect.rejection.unwrap().starts_with("CallIndirect"));
+
+        let table = first_body_effects("(module (table 1 funcref) (func (drop (table.size 0))))");
+        assert!(!table.allowed);
+        assert!(table.rejection.unwrap().starts_with("TableSize"));
+    }
+
+    #[test]
+    fn policy_rejects_unrecognized_atomic_reads() {
+        let effects = first_body_effects(
+            "(module (memory 1 1 shared) (func (drop (i32.atomic.load (i32.const 0)))))",
+        );
+        assert!(!effects.allowed);
+        assert!(effects.rejection.unwrap().starts_with("I32AtomicLoad"));
+    }
+
+    #[test]
+    fn call_graph_cycle_is_rejected() {
+        let mut bodies = BTreeMap::new();
+        let mut first = Effects {
+            allowed: true,
+            ..Effects::default()
+        };
+        first.calls.insert(11, 1);
+        let mut second = Effects {
+            allowed: true,
+            ..Effects::default()
+        };
+        second.calls.insert(10, 1);
+        bodies.insert(
+            10,
+            BodySummary {
+                range: 0..0,
+                effects: first,
+            },
+        );
+        bodies.insert(
+            11,
+            BodySummary {
+                range: 0..0,
+                effects: second,
+            },
+        );
+        assert!(has_call_cycle(10, &BTreeSet::from([10, 11]), &bodies).unwrap());
+    }
+
+    #[test]
+    fn duplicate_relocation_helper_call_is_rejected() {
+        let mut bodies = BTreeMap::new();
+        let mut start = Effects {
+            allowed: true,
+            ..Effects::default()
+        };
+        start.calls.insert(11, 2);
+        bodies.insert(
+            10,
+            BodySummary {
+                range: 0..0,
+                effects: start,
+            },
+        );
+        bodies.insert(
+            11,
+            BodySummary {
+                range: 0..0,
+                effects: Effects {
+                    allowed: true,
+                    ..Effects::default()
+                },
+            },
+        );
+
+        let error = validate_call_shape(10, &BTreeSet::from([10, 11]), &bodies)
+            .unwrap_err()
+            .to_string();
+        assert!(error.contains("exactly once"), "unexpected error: {error}");
+    }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/execute.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/execute.rs
new file mode 100644
index 000000000..dc3eaad7d
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/execute.rs
@@ -0,0 +1,246 @@
+use std::{collections::HashSet, io::Write as _, sync::Arc};
+
+use anyhow::{Context, Error, ensure};
+use wasmer_wasix::{
+    Runtime, WasiError, WasiRuntimeError,
+    runners::{
+        MappedDirectory,
+        wasi::{RuntimeOrEngine, WasiRunner},
+    },
+};
+
+#[cfg(any(unix, windows))]
+use wasmer_wasix::os::task::HostLifecycleSupervisor;
+
+use crate::{
+    VERSION,
+    args::{Command, RunOptions, VolumeSpec},
+    runtime::{
+        HOST_TASK_BUDGET, SealedPostmasterRuntime, build_tokio_runtime, configure_stack,
+        headless_engine, prepare_system_tty,
+    },
+    sealed,
+};
+
+/// Parse process arguments and execute the requested product command.
+pub fn run_from_env() -> i32 {
+    let command = match crate::args::parse_from(std::env::args_os()) {
+        Ok(command) => command,
+        Err(error) => {
+            eprintln!("error: {error:#}");
+            return 2;
+        }
+    };
+
+    match command {
+        Command::Version => {
+            println!("oliphaunt-wasix-postmaster-executor {VERSION}");
+            0
+        }
+        Command::Run(options) => exit_code_for_result(execute(options)),
+    }
+}
+
+/// Execute one strictly parsed sealed PostgreSQL request.
+pub fn execute(options: RunOptions) -> Result<(), Error> {
+    ensure!(
+        options.stack_size > 0,
+        "stack size must be greater than zero"
+    );
+    ensure!(
+        !options.volumes.is_empty(),
+        "at least one explicit host volume is required"
+    );
+    let resource_limits = configure_stack(options.stack_size);
+    // This owner must remain in this stack frame until `run_wasm` has joined
+    // the root and all fresh EXEC_BACKEND tasks. The task manager intentionally
+    // receives only a Handle; dropping this owner earlier would stop its reactor.
+    let tokio_runtime = build_tokio_runtime()?;
+    let handle = tokio_runtime.handle().clone();
+    let _runtime_guard = handle.enter();
+
+    let prepared = sealed::prepare(&options.manifest, &options.input)?;
+    prepared
+        .runtime_identity()
+        .context("sealed manifest selected no product runtime identity")?;
+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+    let (code_memory_directory, code_memory_device, code_memory_inode) =
+        prepared.strict_code_memory_directory()?;
+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+    let engine = headless_engine(Some((
+        &code_memory_directory,
+        code_memory_device,
+        code_memory_inode,
+    )))?;
+    #[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
+    let engine = headless_engine(None)?;
+    let loaded = sealed::load(prepared, &engine)?;
+
+    // This scope-owned guard restores host terminal state after every normal
+    // return, error propagation, or unwind, independent of runtime Arc clones.
+    let (tty, _tty_restore_guard) = prepare_system_tty();
+    let runtime = Arc::new(SealedPostmasterRuntime::new(
+        handle,
+        engine,
+        loaded.module_cache.clone(),
+        resource_limits,
+        tty,
+    ));
+    let runtime: Arc = runtime;
+
+    let mapped_directories = resolve_volumes(&options.volumes)?;
+    let mut runner = WasiRunner::new();
+    apply_host_task_budget(&mut runner);
+    runner
+        .with_args(options.guest_args)
+        .with_mapped_directories(mapped_directories);
+    attach_host_lifecycle(&mut runner)?;
+    for (guest_path, module_hash) in loaded.executables {
+        runner.with_sealed_module(guest_path, module_hash, None);
+    }
+
+    ensure!(
+        wasmer_wasix::is_wasix_module(&loaded.module),
+        "sealed PostgreSQL entrypoint is not a WASIX module"
+    );
+    let program_name = loaded.path.display().to_string();
+    runner.run_wasm(
+        RuntimeOrEngine::Runtime(runtime),
+        &program_name,
+        loaded.module,
+        loaded.module_hash,
+    )
+}
+
+fn apply_host_task_budget(runner: &mut WasiRunner) {
+    // WasiEnvBuilder creates the one process-tree control plane from these
+    // capabilities. Its exact CAS admission guard therefore shares the same
+    // receipt-bound ceiling as the host blocking-worker pool.
+    runner.capabilities_mut().threading.max_threads = Some(HOST_TASK_BUDGET);
+}
+
+fn resolve_volumes(volumes: &[VolumeSpec]) -> Result, Error> {
+    let mut canonical_hosts = HashSet::new();
+    let mut guest_mounts = HashSet::new();
+    volumes
+        .iter()
+        .map(|volume| {
+            crate::args::validate_guest_path(&volume.guest)?;
+            ensure!(
+                guest_mounts.insert(volume.guest.clone()),
+                "duplicate guest volume mount '{}'",
+                volume.guest
+            );
+            let host = volume.host.canonicalize().with_context(|| {
+                format!(
+                    "canonicalize host directory for --volume {}:{}",
+                    volume.host.display(),
+                    volume.guest
+                )
+            })?;
+            ensure!(
+                host.is_dir(),
+                "--volume host path '{}' is not a directory",
+                host.display()
+            );
+            ensure!(
+                canonical_hosts.insert((host.clone(), volume.guest.clone())),
+                "duplicate canonical --volume mapping '{}:{}'",
+                host.display(),
+                volume.guest
+            );
+            Ok(MappedDirectory {
+                host,
+                guest: volume.guest.clone(),
+            })
+        })
+        .collect()
+}
+
+#[cfg(any(unix, windows))]
+fn attach_host_lifecycle(runner: &mut WasiRunner) -> Result<(), Error> {
+    let supervisor = HostLifecycleSupervisor::install()
+        .context("install exclusive product executor host lifecycle supervision")?;
+    runner.with_host_lifecycle_supervisor(Arc::new(supervisor));
+    Ok(())
+}
+
+#[cfg(not(any(unix, windows)))]
+fn attach_host_lifecycle(_runner: &mut WasiRunner) -> Result<(), Error> {
+    Ok(())
+}
+
+/// Convert an execution result to the process status used by the full CLI.
+pub fn exit_code_for_result(result: Result<(), Error>) -> i32 {
+    let exit_code = match result {
+        Ok(()) => 0,
+        Err(error) => {
+            if let Some(exit_code) = error.chain().find_map(wasi_exit_code) {
+                exit_code.raw()
+            } else {
+                eprintln!("error: {error:#}");
+                1
+            }
+        }
+    };
+
+    std::io::stdout().flush().ok();
+    std::io::stderr().flush().ok();
+    exit_code
+}
+
+fn wasi_exit_code(
+    error: &(dyn std::error::Error + 'static),
+) -> Option {
+    if let Some(WasiError::Exit(exit_code)) = error.downcast_ref() {
+        return Some(*exit_code);
+    }
+    error
+        .downcast_ref::()
+        .and_then(WasiRuntimeError::as_exit_code)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn product_runtime_policy_is_declared_at_the_execution_boundary() {
+        assert_eq!(
+            crate::runtime::POLICY_ID,
+            "oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2"
+        );
+    }
+
+    #[test]
+    fn product_runner_applies_the_same_guest_and_host_task_budget() {
+        let mut runner = WasiRunner::new();
+        apply_host_task_budget(&mut runner);
+
+        assert_eq!(
+            runner.capabilities_mut().threading.max_threads,
+            Some(crate::runtime::HOST_TASK_BUDGET)
+        );
+        assert_eq!(crate::runtime::HOST_TASK_BUDGET, 96);
+    }
+
+    #[test]
+    fn success_maps_to_zero() {
+        assert_eq!(exit_code_for_result(Ok(())), 0);
+    }
+
+    #[test]
+    fn wasi_exit_status_is_preserved() {
+        let error = Error::new(WasiError::Exit(7_u16.into()));
+        assert_eq!(exit_code_for_result(Err(error)), 7);
+    }
+
+    #[test]
+    fn volume_resolution_requires_existing_directories() {
+        let missing = VolumeSpec {
+            host: std::path::Path::new("/path/that/must/not/exist").to_path_buf(),
+            guest: "/data".to_owned(),
+        };
+        assert!(resolve_volumes(&[missing]).is_err());
+    }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/lib.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/lib.rs
new file mode 100644
index 000000000..724f31e17
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/lib.rs
@@ -0,0 +1,26 @@
+//! Closed, compiler-free executor for Oliphaunt's WASIX PostgreSQL product.
+//!
+//! This crate deliberately does not depend on `wasmer-cli`. Its public API is
+//! the complete product boundary: an exact sealed carrier, host filesystem
+//! mappings, required host networking, and PostgreSQL guest arguments.
+
+#![deny(missing_docs, unsafe_op_in_unsafe_fn)]
+
+pub mod args;
+#[cfg(feature = "product-executor")]
+mod execute;
+#[cfg(feature = "memory-profile-core")]
+pub mod memory_profile;
+#[cfg(feature = "product-executor")]
+mod runtime;
+pub mod sealed;
+
+#[cfg(feature = "product-executor")]
+pub use execute::{execute, exit_code_for_result, run_from_env};
+
+/// Exact receipt identity for the reversible bounded memory-maximum rewrite.
+pub(crate) const SEALED_MODULE_TRANSFORMATION_ID: &str =
+    "pinned-wasixcc-65536-to-embedded-4096-reversible-v1";
+
+/// Exact product executor version.
+pub const VERSION: &str = env!("CARGO_PKG_VERSION");
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/memory_profile.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/memory_profile.rs
new file mode 100644
index 000000000..e439e32dd
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/memory_profile.rs
@@ -0,0 +1,812 @@
+//! Versioned, fail-closed linear-memory policy for the embedded postmaster.
+//!
+//! This is intentionally a product profile rather than a change to Wasmer's
+//! generic defaults. The AOT producer and compiler-free executor select the
+//! same profile without an environment or CLI override, while carrier
+//! admission checks the resulting serialized allocation plan.
+
+use anyhow::{Error, Result, bail, ensure};
+use wasmer::sys::{
+    BaseTunables, SerializedLinearMemoryPlan, SerializedLinearMemoryStyle, Tunables,
+};
+use wasmer_types::{MemoryType, Pages, target::PointerWidth, target::Target};
+use wasmer_vm::MemoryStyle;
+
+/// Identifier of the first bounded embedded-postmaster linear-memory profile.
+pub const EMBEDDED_256M_V1_ID: &str =
+    "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1";
+
+/// WebAssembly page size used by the profile.
+pub const WASM_PAGE_BYTES: u64 = 65_536;
+
+/// Exact guest-visible maximum, in WebAssembly pages.
+pub const EMBEDDED_256M_V1_MAXIMUM_PAGES: u32 = 4_096;
+
+/// Exact maximum and static reservation bound, in bytes.
+pub const EMBEDDED_256M_V1_MAXIMUM_BYTES: u64 =
+    (EMBEDDED_256M_V1_MAXIMUM_PAGES as u64) * WASM_PAGE_BYTES;
+
+/// Exact U64 static reservation required by Wasmer's unchecked LLVM accesses.
+pub const EMBEDDED_256M_V1_STATIC_BOUND_PAGES: u32 = 65_536;
+
+/// Exact U64 offset guard required by Wasmer's unchecked LLVM accesses.
+pub const EMBEDDED_256M_V1_OFFSET_GUARD_BYTES: u64 = 0x8000_0000;
+
+/// Maximum injected by the pinned WASIX compiler wrapper before sealing.
+pub const PINNED_WASIXCC_MAXIMUM_PAGES: u32 = 65_536;
+
+/// A closed set of product linear-memory profiles.
+///
+/// Adding a profile requires a new enum variant, carrier schema identity, and
+/// qualification evidence. Runtime strings never construct arbitrary bounds.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum LinearMemoryProfile {
+    /// 256 MiB guest maximum with Wasmer's U64 4 GiB + 2 GiB trap reservation.
+    Embedded256MiBV1,
+}
+
+impl LinearMemoryProfile {
+    /// Return the only profile selected by the current embedded product.
+    pub const fn embedded() -> Self {
+        Self::Embedded256MiBV1
+    }
+
+    /// Return the stable profile identifier.
+    pub const fn id(self) -> &'static str {
+        match self {
+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_ID,
+        }
+    }
+
+    /// Return the maximum number of WebAssembly pages.
+    pub const fn maximum_pages(self) -> u32 {
+        match self {
+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_MAXIMUM_PAGES,
+        }
+    }
+
+    /// Return the maximum number of linear-memory bytes.
+    pub const fn maximum_bytes(self) -> u64 {
+        match self {
+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_MAXIMUM_BYTES,
+        }
+    }
+
+    /// Return the static reservation bound in WebAssembly pages.
+    pub const fn static_bound_pages(self) -> u32 {
+        match self {
+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_STATIC_BOUND_PAGES,
+        }
+    }
+
+    /// Return the static offset guard in bytes.
+    pub const fn offset_guard_bytes(self) -> u64 {
+        match self {
+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_OFFSET_GUARD_BYTES,
+        }
+    }
+
+    fn tunables(self, target: &Target, boundary: &str) -> Result {
+        let pointer_width = target.triple().pointer_width().map_err(|error| {
+            Error::msg(format!("derive {boundary} host pointer width: {error:?}"))
+        })?;
+        ensure!(
+            pointer_width == PointerWidth::U64,
+            "{boundary} profile '{}' requires a U64 host because Wasmer's LLVM static-memory access lowering relies on the 4 GiB reservation and 2 GiB guard; got {pointer_width:?}",
+            self.id()
+        );
+        ensure!(
+            self.maximum_pages() < PINNED_WASIXCC_MAXIMUM_PAGES,
+            "bounded profile must exclude the Wasm32 65536th-page end-wrap boundary"
+        );
+        let tunables = BaseTunables::for_target(target);
+        ensure!(
+            tunables.static_memory_bound.0 == self.static_bound_pages()
+                && tunables.static_memory_offset_guard_size == self.offset_guard_bytes(),
+            "{boundary} Wasmer U64 defaults drifted from profile '{}': bound={} guard={}",
+            self.id(),
+            tunables.static_memory_bound.0,
+            tunables.static_memory_offset_guard_size
+        );
+        Ok(tunables)
+    }
+}
+
+/// Derive compiler tunables for the explicit embedded profile.
+pub fn compiler_tunables_for_target(target: &Target) -> Result {
+    LinearMemoryProfile::embedded().tunables(target, "AOT compiler")
+}
+
+/// Derive compiler-free executor tunables for the explicit embedded profile.
+pub fn executor_tunables_for_target(target: &Target) -> Result {
+    LinearMemoryProfile::embedded().tunables(target, "headless executor")
+}
+
+/// Return the expected module memory type used to prove the selected tunables.
+pub fn admitted_memory_type(minimum_pages: u32) -> Result {
+    let profile = LinearMemoryProfile::embedded();
+    ensure!(
+        minimum_pages <= profile.maximum_pages(),
+        "initial memory exceeds profile maximum"
+    );
+    Ok(MemoryType::new(
+        Pages(minimum_pages),
+        Some(Pages(profile.maximum_pages())),
+        true,
+    ))
+}
+
+/// Describe and validate the style derived by one tunables boundary.
+pub fn derived_static_style(tunables: &BaseTunables, minimum_pages: u32) -> Result<(u32, u64)> {
+    let profile = LinearMemoryProfile::embedded();
+    match tunables.memory_style(&admitted_memory_type(minimum_pages)?) {
+        MemoryStyle::Static {
+            bound,
+            offset_guard_size,
+        } => {
+            ensure!(
+                bound.0 == profile.static_bound_pages()
+                    && offset_guard_size == profile.offset_guard_bytes(),
+                "derived static style differs from profile '{}'",
+                profile.id()
+            );
+            Ok((bound.0, offset_guard_size))
+        }
+        MemoryStyle::Dynamic { .. } => {
+            bail!("bounded profile unexpectedly derived a moving dynamic memory style")
+        }
+    }
+}
+
+/// Reject an AOT artifact unless its module type and compiled allocation plan
+/// exactly match the selected U64 trap-preserving embedded profile.
+pub fn validate_serialized_memory_plans(plans: &[SerializedLinearMemoryPlan]) -> Result<()> {
+    let profile = LinearMemoryProfile::embedded();
+    ensure!(
+        plans.len() == 1,
+        "profile '{}' requires exactly one linear memory, found {}",
+        profile.id(),
+        plans.len()
+    );
+    let plan = plans[0];
+    ensure!(
+        plan.minimum_pages <= profile.maximum_pages(),
+        "artifact initial memory exceeds profile maximum"
+    );
+    ensure!(
+        plan.maximum_pages == Some(profile.maximum_pages()),
+        "artifact maximum memory differs from profile '{}': {:?}",
+        profile.id(),
+        plan.maximum_pages
+    );
+    ensure!(plan.shared, "artifact linear memory is not shared");
+    ensure!(
+        plan.maximum_pages.unwrap() < PINNED_WASIXCC_MAXIMUM_PAGES,
+        "artifact admits the Wasm32 65536th-page end-wrap boundary"
+    );
+    ensure!(
+        plan.style
+            == SerializedLinearMemoryStyle::Static {
+                bound_pages: profile.static_bound_pages(),
+                offset_guard_bytes: profile.offset_guard_bytes(),
+            },
+        "artifact linear-memory style is not the exact nonmoving profile: {:?}",
+        plan.style
+    );
+    Ok(())
+}
+
+#[cfg(feature = "memory-profile-tool")]
+mod wasm_tool {
+    use std::{
+        fs::{self, OpenOptions},
+        io::Write,
+        ops::Range,
+        path::Path,
+    };
+
+    use anyhow::{Context, Result, bail, ensure};
+    use serde::Serialize;
+    use sha2::{Digest, Sha256};
+    use wasmparser::{BinaryReader, Imports, Parser, Payload, TypeRef, Validator, WasmFeatures};
+
+    use super::{LinearMemoryProfile, PINNED_WASIXCC_MAXIMUM_PAGES};
+    use crate::SEALED_MODULE_TRANSFORMATION_ID;
+
+    /// Schema emitted by the exact module memory-contract sealer.
+    pub const RECEIPT_SCHEMA: &str = "oliphaunt.wasix-postmaster.linear-memory-module.v1";
+
+    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+    struct RawMemoryContract {
+        initial_pages: u64,
+        maximum_pages: Option,
+        shared: bool,
+        memory64: bool,
+        page_size_log2: Option,
+    }
+
+    #[derive(Debug, Serialize)]
+    #[serde(rename_all = "kebab-case")]
+    struct ModuleReceipt<'a> {
+        schema: &'static str,
+        profile_id: &'static str,
+        module_sha256: String,
+        source_module_sha256: Option,
+        import_module: &'static str,
+        import_name: &'static str,
+        address_width: &'static str,
+        initial_pages: u64,
+        maximum_pages: u64,
+        maximum_bytes: u64,
+        shared: bool,
+        static_bound_pages: u32,
+        static_offset_guard_bytes: u64,
+        excludes_wasm32_end_wrap: bool,
+        transformation: &'a str,
+    }
+
+    fn validate_wasm(bytes: &[u8]) -> Result<()> {
+        Validator::new_with_features(WasmFeatures::default() | WasmFeatures::THREADS)
+            .validate_all(bytes)
+            .context("validate WebAssembly module")?;
+        Ok(())
+    }
+
+    fn raw_memory_contract(bytes: &[u8]) -> Result {
+        validate_wasm(bytes)?;
+        let mut memory_imports = Vec::new();
+        let mut defined_memories = 0_u32;
+        for payload in Parser::new(0).parse_all(bytes) {
+            match payload? {
+                Payload::ImportSection(section) => {
+                    for import in section.into_imports() {
+                        let import = import?;
+                        if let TypeRef::Memory(memory) = import.ty {
+                            memory_imports.push((
+                                import.module.to_owned(),
+                                import.name.to_owned(),
+                                RawMemoryContract {
+                                    initial_pages: memory.initial,
+                                    maximum_pages: memory.maximum,
+                                    shared: memory.shared,
+                                    memory64: memory.memory64,
+                                    page_size_log2: memory.page_size_log2,
+                                },
+                            ));
+                        }
+                    }
+                }
+                Payload::MemorySection(section) => {
+                    defined_memories += section.count();
+                }
+                _ => {}
+            }
+        }
+        ensure!(
+            defined_memories == 0,
+            "profile requires imported linear memory; found {defined_memories} defined memories"
+        );
+        ensure!(
+            memory_imports.len() == 1,
+            "profile requires exactly one memory import, found {}",
+            memory_imports.len()
+        );
+        let (module, name, memory) = memory_imports.pop().unwrap();
+        ensure!(
+            module == "env" && name == "memory",
+            "profile requires the exact env.memory import, found {module}.{name}"
+        );
+        ensure!(!memory.memory64, "profile requires Wasm32 linear memory");
+        ensure!(memory.shared, "profile requires shared linear memory");
+        ensure!(
+            matches!(memory.page_size_log2, None | Some(16)),
+            "profile requires the standard 64 KiB WebAssembly page"
+        );
+        let maximum = memory
+            .maximum_pages
+            .context("shared memory has no explicit maximum")?;
+        ensure!(
+            maximum <= u64::from(PINNED_WASIXCC_MAXIMUM_PAGES),
+            "memory maximum exceeds Wasm32"
+        );
+        ensure!(
+            memory.initial_pages <= maximum,
+            "memory minimum exceeds maximum"
+        );
+        Ok(memory)
+    }
+
+    fn imported_memory_maximum_span(
+        bytes: &[u8],
+        expected: RawMemoryContract,
+    ) -> Result> {
+        let mut maximum_span = None;
+        for payload in Parser::new(0).parse_all(bytes) {
+            let Payload::ImportSection(section) = payload? else {
+                continue;
+            };
+            let section_end = section.range().end;
+            for imports in section {
+                let Imports::Single(offset, import) = imports? else {
+                    bail!("compact import encodings are not supported by the memory sealer");
+                };
+                let TypeRef::Memory(memory) = import.ty else {
+                    continue;
+                };
+                ensure!(
+                    maximum_span.is_none(),
+                    "profile requires exactly one memory import"
+                );
+                ensure!(
+                    import.module == "env" && import.name == "memory",
+                    "profile requires the exact env.memory import"
+                );
+
+                // Parse only the validated import entry to locate its encoded
+                // maximum. Re-encoding the module would also canonicalize
+                // wasm-ld's relocation-width LEBs and invalidate raw custom
+                // sections such as DWARF.
+                let mut reader = BinaryReader::new(&bytes[offset..section_end], offset);
+                ensure!(
+                    reader.read_string()? == import.module,
+                    "import module drifted"
+                );
+                ensure!(reader.read_string()? == import.name, "import name drifted");
+                ensure!(reader.read_u8()? == 0x02, "memory import kind drifted");
+                let flags = reader.read_u8()?;
+                ensure!(flags & !0b1111 == 0, "invalid memory limits flags");
+                let has_maximum = flags & 0b0001 != 0;
+                let shared = flags & 0b0010 != 0;
+                let memory64 = flags & 0b0100 != 0;
+                let has_page_size = flags & 0b1000 != 0;
+                ensure!(!memory64, "profile requires Wasm32 linear memory");
+                ensure!(shared, "profile requires shared linear memory");
+                ensure!(has_maximum, "shared memory has no explicit maximum");
+
+                let initial = u64::from(reader.read_var_u32()?);
+                let start = reader.original_position();
+                let maximum = u64::from(reader.read_var_u32()?);
+                let end = reader.original_position();
+                let page_size_log2 = has_page_size.then(|| reader.read_var_u32()).transpose()?;
+                ensure!(
+                    initial == memory.initial
+                        && maximum == memory.maximum.context("memory maximum disappeared")?
+                        && memory64 == memory.memory64
+                        && shared == memory.shared
+                        && page_size_log2 == memory.page_size_log2,
+                    "raw memory import differs from its parsed contract"
+                );
+                ensure!(
+                    expected
+                        == (RawMemoryContract {
+                            initial_pages: initial,
+                            maximum_pages: Some(maximum),
+                            shared,
+                            memory64,
+                            page_size_log2,
+                        }),
+                    "located memory import differs from the validated module contract"
+                );
+                maximum_span = Some(start..end);
+            }
+        }
+        maximum_span.context("validated env.memory import was not located")
+    }
+
+    fn encode_u32_leb_exact_width(value: u32, width: usize) -> Result> {
+        ensure!((1..=5).contains(&width), "invalid u32 LEB width {width}");
+        let mut remaining = u64::from(value);
+        let mut encoded = Vec::with_capacity(width);
+        for index in 0..width {
+            let last = index + 1 == width;
+            let byte = (remaining & 0x7f) as u8;
+            remaining >>= 7;
+            if last {
+                ensure!(
+                    remaining == 0,
+                    "value {value} does not fit LEB width {width}"
+                );
+                encoded.push(byte);
+            } else {
+                encoded.push(byte | 0x80);
+            }
+        }
+        Ok(encoded)
+    }
+
+    fn rewrite_memory_maximum(
+        bytes: &[u8],
+        contract: RawMemoryContract,
+        maximum_pages: u32,
+    ) -> Result<(Vec, Range)> {
+        let span = imported_memory_maximum_span(bytes, contract)?;
+        let replacement = encode_u32_leb_exact_width(maximum_pages, span.len())?;
+        let mut rewritten = bytes.to_vec();
+        rewritten[span.clone()].copy_from_slice(&replacement);
+        ensure!(
+            rewritten.len() == bytes.len(),
+            "memory rewrite changed module length"
+        );
+        ensure!(
+            rewritten[..span.start] == bytes[..span.start]
+                && rewritten[span.end..] == bytes[span.end..],
+            "memory rewrite changed bytes outside the maximum field"
+        );
+        Ok((rewritten, span))
+    }
+
+    fn receipt<'a>(
+        bytes: &[u8],
+        source_bytes: Option<&[u8]>,
+        contract: RawMemoryContract,
+        transformation: &'a str,
+    ) -> Result> {
+        let profile = LinearMemoryProfile::embedded();
+        ensure!(
+            contract.maximum_pages == Some(u64::from(profile.maximum_pages())),
+            "module maximum does not match profile '{}'",
+            profile.id()
+        );
+        ensure!(
+            contract.initial_pages <= u64::from(profile.maximum_pages()),
+            "module minimum exceeds profile maximum"
+        );
+        ensure!(
+            profile.maximum_pages() < PINNED_WASIXCC_MAXIMUM_PAGES,
+            "profile does not exclude the Wasm32 65536th-page boundary"
+        );
+        Ok(ModuleReceipt {
+            schema: RECEIPT_SCHEMA,
+            profile_id: profile.id(),
+            module_sha256: hex::encode(Sha256::digest(bytes)),
+            source_module_sha256: source_bytes.map(|source| hex::encode(Sha256::digest(source))),
+            import_module: "env",
+            import_name: "memory",
+            address_width: "wasm32",
+            initial_pages: contract.initial_pages,
+            maximum_pages: profile.maximum_pages().into(),
+            maximum_bytes: profile.maximum_bytes(),
+            shared: contract.shared,
+            static_bound_pages: profile.static_bound_pages(),
+            static_offset_guard_bytes: profile.offset_guard_bytes(),
+            excludes_wasm32_end_wrap: true,
+            transformation,
+        })
+    }
+
+    fn write_new(path: &Path, bytes: &[u8]) -> Result<()> {
+        let mut output = OpenOptions::new()
+            .write(true)
+            .create_new(true)
+            .open(path)
+            .with_context(|| format!("create {}", path.display()))?;
+        output
+            .write_all(bytes)
+            .with_context(|| format!("write {}", path.display()))?;
+        output
+            .sync_all()
+            .with_context(|| format!("sync {}", path.display()))?;
+        Ok(())
+    }
+
+    /// Verify a module already sealed to the selected profile and emit its
+    /// canonical receipt JSON.
+    pub fn verify_module_bytes(bytes: &[u8]) -> Result {
+        let contract = raw_memory_contract(bytes)?;
+        let receipt = receipt(bytes, None, contract, "verified-existing-v1")?;
+        serde_json::to_string_pretty(&receipt).context("serialize module memory receipt")
+    }
+
+    /// Verify a module file already sealed to the selected profile and emit
+    /// its canonical receipt JSON.
+    pub fn verify_module(path: &Path) -> Result {
+        let bytes = fs::read(path).with_context(|| format!("read {}", path.display()))?;
+        verify_module_bytes(&bytes)
+    }
+
+    /// Rewrite only a pinned-toolchain module's encoded memory maximum into
+    /// the selected profile, prove the same-width edit is byte-reversible, and
+    /// write new module/receipt files.
+    pub fn seal_module(input: &Path, output: &Path, receipt_path: &Path) -> Result<()> {
+        let source = fs::read(input).with_context(|| format!("read {}", input.display()))?;
+        let source_contract = raw_memory_contract(&source)?;
+        ensure!(
+            source_contract.maximum_pages == Some(u64::from(PINNED_WASIXCC_MAXIMUM_PAGES)),
+            "sealer input must carry the pinned wasixcc {}-page maximum, found {:?}",
+            PINNED_WASIXCC_MAXIMUM_PAGES,
+            source_contract.maximum_pages
+        );
+        let profile = LinearMemoryProfile::embedded();
+        ensure!(
+            source_contract.initial_pages <= u64::from(profile.maximum_pages()),
+            "module minimum cannot fit the selected profile"
+        );
+        let (sealed, maximum_span) =
+            rewrite_memory_maximum(&source, source_contract, profile.maximum_pages())?;
+        let sealed_contract = raw_memory_contract(&sealed)?;
+        ensure!(
+            sealed_contract.maximum_pages == Some(u64::from(profile.maximum_pages())),
+            "sealed module maximum differs"
+        );
+        let sealed_span = imported_memory_maximum_span(&sealed, sealed_contract)?;
+        ensure!(
+            sealed_span == maximum_span,
+            "memory-maximum field moved during the same-width rewrite"
+        );
+        let (reversed, reversed_span) =
+            rewrite_memory_maximum(&sealed, sealed_contract, PINNED_WASIXCC_MAXIMUM_PAGES)?;
+        ensure!(
+            reversed_span == maximum_span && reversed == source,
+            "memory-maximum transformation changed bytes outside its reversible field"
+        );
+        let receipt = receipt(
+            &sealed,
+            Some(&source),
+            sealed_contract,
+            SEALED_MODULE_TRANSFORMATION_ID,
+        )?;
+        let mut receipt_bytes =
+            serde_json::to_vec_pretty(&receipt).context("serialize module memory receipt")?;
+        receipt_bytes.push(b'\n');
+        write_new(output, &sealed)?;
+        if let Err(error) = write_new(receipt_path, &receipt_bytes) {
+            let _ = fs::remove_file(output);
+            return Err(error);
+        }
+        Ok(())
+    }
+
+    /// Return a canonical JSON object describing the selected profile.
+    pub fn profile_json() -> Result {
+        let profile = LinearMemoryProfile::embedded();
+        #[derive(Serialize)]
+        #[serde(rename_all = "kebab-case")]
+        struct Profile {
+            id: &'static str,
+            address_width: &'static str,
+            supported_host_pointer_width: &'static str,
+            maximum_pages: u32,
+            maximum_bytes: u64,
+            static_bound_pages: u32,
+            static_offset_guard_bytes: u64,
+            static_access_lowering: &'static str,
+            requires_shared: bool,
+            requires_import: &'static str,
+            excludes_wasm32_end_wrap: bool,
+        }
+        serde_json::to_string_pretty(&Profile {
+            id: profile.id(),
+            address_width: "wasm32",
+            supported_host_pointer_width: "u64",
+            maximum_pages: profile.maximum_pages(),
+            maximum_bytes: profile.maximum_bytes(),
+            static_bound_pages: profile.static_bound_pages(),
+            static_offset_guard_bytes: profile.offset_guard_bytes(),
+            static_access_lowering: "wasmer-llvm-unchecked-reservation-and-guard-v1",
+            requires_shared: true,
+            requires_import: "env.memory",
+            excludes_wasm32_end_wrap: true,
+        })
+        .context("serialize linear-memory profile")
+    }
+
+    #[cfg(test)]
+    mod tests {
+        use super::*;
+
+        #[test]
+        fn selected_profile_is_strictly_below_wasm32_end_wrap() {
+            let profile = LinearMemoryProfile::embedded();
+            assert_eq!(profile.maximum_pages(), 4_096);
+            assert_eq!(profile.maximum_bytes(), 256 * 1024 * 1024);
+            assert!(profile.maximum_pages() < PINNED_WASIXCC_MAXIMUM_PAGES);
+            assert_eq!(super::super::WASM_PAGE_BYTES, 65_536);
+        }
+
+        #[test]
+        fn sealer_changes_only_the_explicit_memory_maximum() {
+            let source = wat::parse_str(
+                r#"(module $named_module
+                    (import "env" "memory" (memory 2 65536 shared))
+                    (func $read (export "read") (result i32)
+                        i32.const 0
+                        i32.load))"#,
+            )
+            .unwrap();
+            let directory = tempfile::tempdir().unwrap();
+            let input = directory.path().join("input.wasm");
+            let output = directory.path().join("sealed.wasm");
+            let receipt_path = directory.path().join("receipt.json");
+            fs::write(&input, &source).unwrap();
+
+            seal_module(&input, &output, &receipt_path).unwrap();
+            let sealed = fs::read(&output).unwrap();
+            let contract = raw_memory_contract(&sealed).unwrap();
+            assert_eq!(contract.maximum_pages, Some(4_096));
+            assert_eq!(contract.initial_pages, 2);
+            assert!(contract.shared);
+            let receipt: serde_json::Value =
+                serde_json::from_slice(&fs::read(receipt_path).unwrap()).unwrap();
+            assert_eq!(
+                receipt["source-module-sha256"],
+                hex::encode(Sha256::digest(&source))
+            );
+            assert_eq!(
+                receipt["module-sha256"],
+                hex::encode(Sha256::digest(&sealed))
+            );
+            assert_eq!(receipt["transformation"], SEALED_MODULE_TRANSFORMATION_ID);
+            verify_module_bytes(&sealed).unwrap();
+        }
+
+        #[test]
+        fn sealer_preserves_relocation_width_immediates() {
+            // wasm-ld emits padded relocation-width LEBs. The function body
+            // contains global.get 0 as `23 80 80 80 80 00`; canonicalizing it
+            // would shift code offsets without updating raw DWARF sections.
+            let source = hex::decode(concat!(
+                "0061736d01000000010401600000021b0203656e76066d656d6f7279",
+                "02030280800403656e760167037f00030201000a0b0109002380808080001a0b"
+            ))
+            .unwrap();
+            validate_wasm(&source).unwrap();
+            let source_contract = raw_memory_contract(&source).unwrap();
+            let maximum_span = imported_memory_maximum_span(&source, source_contract).unwrap();
+            assert_eq!(maximum_span, 31..34);
+            assert_eq!(&source[maximum_span.clone()], &[0x80, 0x80, 0x04]);
+
+            let directory = tempfile::tempdir().unwrap();
+            let input = directory.path().join("input.wasm");
+            let output = directory.path().join("sealed.wasm");
+            let receipt = directory.path().join("receipt.json");
+            fs::write(&input, &source).unwrap();
+            seal_module(&input, &output, &receipt).unwrap();
+
+            let sealed = fs::read(output).unwrap();
+            assert_eq!(sealed.len(), source.len());
+            assert_eq!(&sealed[maximum_span.clone()], &[0x80, 0xa0, 0x00]);
+            assert_eq!(&sealed[..maximum_span.start], &source[..maximum_span.start]);
+            assert_eq!(&sealed[maximum_span.end..], &source[maximum_span.end..]);
+            assert!(
+                sealed
+                    .windows(6)
+                    .any(|bytes| bytes == [0x23, 0x80, 0x80, 0x80, 0x80, 0x00])
+            );
+            let changed: Vec<_> = source
+                .iter()
+                .zip(&sealed)
+                .enumerate()
+                .filter_map(|(index, (before, after))| (before != after).then_some(index))
+                .collect();
+            assert_eq!(changed, [32, 33]);
+
+            let sealed_contract = raw_memory_contract(&sealed).unwrap();
+            assert_eq!(sealed_contract.maximum_pages, Some(4_096));
+            let (restored, restored_span) =
+                rewrite_memory_maximum(&sealed, sealed_contract, PINNED_WASIXCC_MAXIMUM_PAGES)
+                    .unwrap();
+            assert_eq!(restored_span, maximum_span);
+            assert_eq!(restored, source);
+            verify_module_bytes(&sealed).unwrap();
+        }
+
+        #[test]
+        fn exact_width_u32_leb_encoding_fails_closed() {
+            assert_eq!(
+                encode_u32_leb_exact_width(4_096, 3).unwrap(),
+                [0x80, 0xa0, 0x00]
+            );
+            assert_eq!(
+                encode_u32_leb_exact_width(65_536, 3).unwrap(),
+                [0x80, 0x80, 0x04]
+            );
+            assert_eq!(
+                encode_u32_leb_exact_width(u32::MAX, 5).unwrap(),
+                [0xff, 0xff, 0xff, 0xff, 0x0f]
+            );
+            assert!(encode_u32_leb_exact_width(128, 1).is_err());
+            assert!(encode_u32_leb_exact_width(0, 0).is_err());
+            assert!(encode_u32_leb_exact_width(0, 6).is_err());
+        }
+
+        #[test]
+        fn invalid_memory_import_shapes_fail_closed() {
+            for wat in [
+                r#"(module (import "other" "memory" (memory 2 65536 shared)))"#,
+                r#"(module (memory 2 4 shared))"#,
+                r#"(module
+                    (import "env" "memory" (memory 2 65536 shared))
+                    (memory 2 4 shared))"#,
+                r#"(module
+                    (import "env" "memory" (memory 2 65536 shared))
+                    (import "env" "memory2" (memory 2 65536 shared)))"#,
+            ] {
+                assert!(raw_memory_contract(&wat::parse_str(wat).unwrap()).is_err());
+            }
+
+            let compact = hex::decode(concat!(
+                "0061736d0100000002150103656e76007f01066d656d6f7279",
+                "020302808004"
+            ))
+            .unwrap();
+            let expected = RawMemoryContract {
+                initial_pages: 2,
+                maximum_pages: Some(65_536),
+                shared: true,
+                memory64: false,
+                page_size_log2: None,
+            };
+            assert!(imported_memory_maximum_span(&compact, expected).is_err());
+        }
+    }
+}
+
+#[cfg(feature = "memory-profile-tool")]
+pub use wasm_tool::{profile_json, seal_module, verify_module, verify_module_bytes};
+
+#[cfg(test)]
+mod tests {
+    use std::str::FromStr;
+
+    use wasmer_types::target::{CpuFeature, Target, Triple};
+
+    use super::*;
+
+    fn target(triple: &str) -> Target {
+        Target::new(Triple::from_str(triple).unwrap(), CpuFeature::set())
+    }
+
+    #[test]
+    fn compiler_and_executor_independently_derive_exact_u64_trap_style() {
+        let target = target("x86_64-unknown-linux-gnu");
+        let compiler = compiler_tunables_for_target(&target).unwrap();
+        let executor = executor_tunables_for_target(&target).unwrap();
+        assert_eq!(
+            derived_static_style(&compiler, 41).unwrap(),
+            (65_536, 2_147_483_648)
+        );
+        assert_eq!(
+            derived_static_style(&executor, 41).unwrap(),
+            (65_536, 2_147_483_648)
+        );
+    }
+
+    #[test]
+    fn u32_host_fails_closed_instead_of_using_unchecked_compact_static_memory() {
+        let target = target("i686-unknown-linux-gnu");
+        assert!(compiler_tunables_for_target(&target).is_err());
+        assert!(executor_tunables_for_target(&target).is_err());
+    }
+
+    #[test]
+    fn serialized_plan_rejects_dynamic_or_wasm32_end_wrap_profiles() {
+        let valid = SerializedLinearMemoryPlan {
+            minimum_pages: 41,
+            maximum_pages: Some(4_096),
+            shared: true,
+            style: SerializedLinearMemoryStyle::Static {
+                bound_pages: 65_536,
+                offset_guard_bytes: 2_147_483_648,
+            },
+        };
+        validate_serialized_memory_plans(&[valid]).unwrap();
+
+        let dynamic = SerializedLinearMemoryPlan {
+            style: SerializedLinearMemoryStyle::Dynamic {
+                offset_guard_bytes: 2_147_483_648,
+            },
+            ..valid
+        };
+        assert!(validate_serialized_memory_plans(&[dynamic]).is_err());
+
+        let wrap = SerializedLinearMemoryPlan {
+            maximum_pages: Some(65_536),
+            style: SerializedLinearMemoryStyle::Static {
+                bound_pages: 65_536,
+                offset_guard_bytes: 2_147_483_648,
+            },
+            ..valid
+        };
+        assert!(validate_serialized_memory_plans(&[wrap]).is_err());
+    }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/runtime.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/runtime.rs
new file mode 100644
index 000000000..267665b8c
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/runtime.rs
@@ -0,0 +1,359 @@
+use std::{path::Path, sync::Arc, time::Duration};
+
+use anyhow::{Context, Error};
+#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+use wasmer::sys::CodeMemoryPolicy;
+use wasmer::{Engine, Store, sys::NativeEngineExt};
+use wasmer_wasix::{
+    LocalNetworking, ResourceLimits, Runtime, VirtualTaskManager,
+    os::{TtyBridge, tty_sys::SysTty},
+    runtime::{
+        module_cache::ModuleCache,
+        resolver::{MultiSource, Source},
+        task_manager::tokio::{TokioTaskManager, TokioTaskManagerConfig},
+    },
+    virtual_net::DynVirtualNetworking,
+};
+
+use crate::{
+    memory_profile::{LinearMemoryProfile, derived_static_style, executor_tunables_for_target},
+    sealed::SealedModuleCache,
+};
+
+pub(crate) const POLICY_ID: &str =
+    "oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2";
+pub(crate) const CODE_MEMORY_POLICY_ID: &str =
+    "wasmer.code-memory.relocated-regular-file.linux-x86_64.v1";
+const TOKIO_WORKER_THREADS: usize = 2;
+pub(crate) const HOST_TASK_BUDGET: usize = 96;
+const BLOCKING_CORE_THREADS: usize = 1;
+const BLOCKING_WORKER_IDLE_TIMEOUT: Duration = Duration::from_millis(1_000);
+const WASIX_STACK_RLIMIT_DIVISOR: u64 = 8;
+
+fn task_manager_config() -> TokioTaskManagerConfig {
+    TokioTaskManagerConfig {
+        core_threads: BLOCKING_CORE_THREADS,
+        max_threads: HOST_TASK_BUDGET,
+        idle_timeout: BLOCKING_WORKER_IDLE_TIMEOUT,
+    }
+}
+
+pub(crate) fn build_tokio_runtime() -> Result {
+    tokio::runtime::Builder::new_multi_thread()
+        .worker_threads(TOKIO_WORKER_THREADS)
+        .enable_all()
+        .build()
+        .context("build sealed WASIX-postmaster Tokio runtime")
+}
+
+pub(crate) fn headless_engine(
+    strict_directory: Option<(&Path, u64, u64)>,
+) -> Result {
+    // In a compiler-free build EngineBuilder cannot apply a new Features set;
+    // the serialized artifact carries its compiled feature contract. The CLI
+    // flags are compatibility assertions and sealed manifest admission checks
+    // the exact {threads, exceptions} set before this engine activates bytes.
+    let mut engine = Engine::headless();
+    let memory_tunables = executor_tunables_for_target(engine.target())
+        .context("derive sealed executor linear-memory profile")?;
+    let (static_bound_pages, static_offset_guard_bytes) = derived_static_style(&memory_tunables, 0)
+        .context("prove sealed executor linear-memory allocation style")?;
+    tracing::debug!(
+        linear_memory_profile_id = LinearMemoryProfile::embedded().id(),
+        guest_maximum_pages = LinearMemoryProfile::embedded().maximum_pages(),
+        static_bound_pages,
+        static_offset_guard_bytes,
+        "configure trap-preserving sealed linear-memory profile"
+    );
+    engine.set_tunables(memory_tunables);
+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+    {
+        let (directory, expected_device, expected_inode) = strict_directory.context(
+            "Linux x86-64 sealed execution requires an explicit strict code-memory directory",
+        )?;
+        let policy = CodeMemoryPolicy::strict_linux_x86_64_file_backed(directory)
+            .map_err(Error::msg)
+            .with_context(|| {
+                format!(
+                    "configure strict file-backed code memory in {}",
+                    directory.display()
+                )
+            })?;
+        anyhow::ensure!(
+            policy.id() == CODE_MEMORY_POLICY_ID,
+            "strict code-memory policy identity drifted: {}",
+            policy.id()
+        );
+        anyhow::ensure!(
+            policy.pinned_directory_device() == Some(expected_device),
+            "strict code-memory directory is not on the admitted carrier-state device"
+        );
+        anyhow::ensure!(
+            policy.pinned_directory_inode() == Some(expected_inode),
+            "strict code-memory directory changed identity before its descriptor was pinned"
+        );
+        tracing::debug!(
+            code_memory_policy_id = policy.id(),
+            code_memory_directory = %policy
+                .pinned_directory()
+                .expect("strict policy has a pinned directory")
+                .display(),
+            code_memory_directory_device = expected_device,
+            code_memory_directory_inode = expected_inode,
+            "configure sealed WASIX-postmaster code-memory ownership"
+        );
+        engine
+            .set_code_memory_policy(policy)
+            .map_err(Error::msg)
+            .context("install strict code-memory policy before AOT deserialization")?;
+    }
+    #[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
+    {
+        anyhow::ensure!(
+            strict_directory.is_none(),
+            "strict Linux x86-64 code-memory directory was supplied on an unsupported platform"
+        );
+        tracing::debug!(
+            code_memory_policy_id = "wasmer.code-memory.anonymous.v1",
+            "configure portable sealed WASIX-postmaster code-memory ownership"
+        );
+    }
+    Ok(engine)
+}
+
+pub(crate) fn configure_stack(stack_size: usize) -> ResourceLimits {
+    wasmer_vm::set_stack_size(stack_size);
+    ResourceLimits {
+        stack: Some(((wasmer_vm::get_stack_size() as u64) / WASIX_STACK_RLIMIT_DIVISOR).max(1)),
+    }
+}
+
+pub(crate) struct TtyRestoreGuard {
+    tty: Arc,
+    original: wasmer_wasix::WasiTtyState,
+}
+
+impl TtyRestoreGuard {
+    fn new(tty: Arc) -> Self {
+        Self {
+            original: tty.tty_get(),
+            tty,
+        }
+    }
+}
+
+impl Drop for TtyRestoreGuard {
+    fn drop(&mut self) {
+        self.tty.tty_set(self.original.clone());
+    }
+}
+
+pub(crate) fn prepare_system_tty() -> (Arc, TtyRestoreGuard) {
+    let tty = Arc::new(SysTty);
+    let guard = TtyRestoreGuard::new(tty.clone());
+    tty.reset();
+    (tty, guard)
+}
+
+/// Runtime with no compiler, package resolver, registry, or HTTP client.
+#[derive(Debug)]
+pub(crate) struct SealedPostmasterRuntime {
+    tasks: Arc,
+    networking: DynVirtualNetworking,
+    engine: Engine,
+    module_cache: Arc,
+    resource_limits: ResourceLimits,
+    source: Arc,
+    tty: Arc,
+}
+
+impl SealedPostmasterRuntime {
+    pub(crate) fn new(
+        handle: tokio::runtime::Handle,
+        engine: Engine,
+        module_cache: Arc,
+        resource_limits: ResourceLimits,
+        tty: Arc,
+    ) -> Self {
+        tracing::debug!(
+            runtime_policy_id = POLICY_ID,
+            async_worker_threads = TOKIO_WORKER_THREADS,
+            host_task_budget = HOST_TASK_BUDGET,
+            blocking_core_threads = BLOCKING_CORE_THREADS,
+            blocking_worker_idle_timeout_ms = BLOCKING_WORKER_IDLE_TIMEOUT.as_millis(),
+            "construct sealed WASIX-postmaster runtime"
+        );
+        let tasks: Arc = Arc::new(TokioTaskManager::new_with_config(
+            handle,
+            task_manager_config(),
+        ));
+        let networking: DynVirtualNetworking = Arc::new(LocalNetworking::default());
+        Self {
+            tasks,
+            networking,
+            engine,
+            module_cache,
+            resource_limits,
+            source: Arc::new(MultiSource::default()),
+            tty,
+        }
+    }
+}
+
+impl Runtime for SealedPostmasterRuntime {
+    fn networking(&self) -> &DynVirtualNetworking {
+        &self.networking
+    }
+
+    fn task_manager(&self) -> &Arc {
+        &self.tasks
+    }
+
+    fn resource_limits(&self) -> ResourceLimits {
+        self.resource_limits
+    }
+
+    fn module_cache(&self) -> Arc {
+        self.module_cache.clone()
+    }
+
+    fn source(&self) -> Arc {
+        self.source.clone()
+    }
+
+    fn engine(&self) -> Engine {
+        self.engine.clone()
+    }
+
+    fn new_store(&self) -> Store {
+        // `wasmer-wasix/sys-minimal` does not enable its broad `sys` cfg, so
+        // relying on Runtime's default would construct a default store rather
+        // than one tied to this exact admitted headless engine.
+        Store::new(self.engine.clone())
+    }
+
+    fn tty(&self) -> Option<&(dyn TtyBridge + Send + Sync)> {
+        Some(self.tty.as_ref())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn runtime_policy_identity_is_stable() {
+        assert_eq!(
+            POLICY_ID,
+            "oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2"
+        );
+        assert_eq!(TOKIO_WORKER_THREADS, 2);
+        assert_eq!(HOST_TASK_BUDGET, 96);
+        assert_eq!(
+            CODE_MEMORY_POLICY_ID,
+            "wasmer.code-memory.relocated-regular-file.linux-x86_64.v1"
+        );
+    }
+
+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+    #[test]
+    fn headless_product_engine_requires_the_exact_admitted_state_identity() {
+        use std::os::unix::fs::{MetadataExt, PermissionsExt};
+
+        let directory = tempfile::Builder::new()
+            .prefix("oliphaunt-code-memory-engine-test-")
+            .tempdir_in("/var/tmp")
+            .unwrap();
+        std::fs::set_permissions(directory.path(), std::fs::Permissions::from_mode(0o700)).unwrap();
+        let device = directory.path().metadata().unwrap().dev();
+        let inode = directory.path().metadata().unwrap().ino();
+        headless_engine(Some((directory.path(), device, inode))).unwrap();
+
+        let error = headless_engine(Some((directory.path(), device.wrapping_add(1), inode)))
+            .err()
+            .expect("mismatched device must be rejected");
+        assert!(error.to_string().contains("admitted carrier-state device"));
+
+        let error = headless_engine(Some((directory.path(), device, inode.wrapping_add(1))))
+            .err()
+            .expect("mismatched inode must be rejected");
+        assert!(error.to_string().contains("changed identity"));
+    }
+
+    #[test]
+    fn runtime_has_exactly_two_tokio_workers() {
+        let runtime = build_tokio_runtime().unwrap();
+        assert_eq!(runtime.metrics().num_workers(), 2);
+    }
+
+    #[test]
+    fn blocking_worker_growth_is_bounded_by_the_host_task_budget() {
+        let owner = build_tokio_runtime().unwrap();
+        let manager =
+            TokioTaskManager::new_with_config(owner.handle().clone(), task_manager_config());
+
+        assert_eq!(
+            manager.config(),
+            TokioTaskManagerConfig {
+                core_threads: 1,
+                max_threads: HOST_TASK_BUDGET,
+                idle_timeout: Duration::from_millis(1_000),
+            }
+        );
+    }
+
+    #[test]
+    fn owned_tokio_runtime_keeps_handle_consumers_live() {
+        use wasmer_wasix::runtime::task_manager::VirtualTaskManagerExt as _;
+
+        let owner = build_tokio_runtime().unwrap();
+        let tasks = Arc::new(TokioTaskManager::new_with_config(
+            owner.handle().clone(),
+            task_manager_config(),
+        ));
+        let answer = tasks
+            .spawn_and_block_on(async {
+                tokio::time::sleep(std::time::Duration::from_millis(1)).await;
+                42_u8
+            })
+            .unwrap();
+        assert_eq!(answer, 42);
+        drop(tasks);
+        drop(owner);
+    }
+
+    #[test]
+    fn tty_guard_restores_state_during_unwind() {
+        use std::sync::Mutex;
+
+        #[derive(Debug)]
+        struct FakeTty(Mutex);
+
+        impl TtyBridge for FakeTty {
+            fn reset(&self) {}
+
+            fn tty_get(&self) -> wasmer_wasix::WasiTtyState {
+                self.0.lock().unwrap().clone()
+            }
+
+            fn tty_set(&self, state: wasmer_wasix::WasiTtyState) {
+                *self.0.lock().unwrap() = state;
+            }
+        }
+
+        let original = wasmer_wasix::WasiTtyState::default();
+        let tty = Arc::new(FakeTty(Mutex::new(original.clone())));
+        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe({
+            let tty = tty.clone();
+            move || {
+                let _guard = TtyRestoreGuard::new(tty.clone());
+                let mut changed = tty.tty_get();
+                changed.echo = !changed.echo;
+                tty.tty_set(changed);
+                panic!("exercise unwind restoration");
+            }
+        }));
+        assert!(result.is_err());
+        assert_eq!(tty.tty_get(), original);
+    }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/sealed.rs b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/sealed.rs
new file mode 100644
index 000000000..d92c985c9
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/executor/src/sealed.rs
@@ -0,0 +1,3382 @@
+//! Exact-five sealed carrier admission and immutable lazy AOT activation.
+
+use std::{
+    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
+    fmt,
+    fs::{self, File, OpenOptions},
+    io::{Read, Write},
+    path::{Component, Path, PathBuf},
+    sync::{Arc, Mutex, OnceLock},
+};
+
+use anyhow::{Context, Error, bail, ensure};
+use serde::{Deserialize, Serialize};
+use sha2::{Digest, Sha256};
+use wasmer::{
+    Engine, Module,
+    sys::{NativeEngineExt, PendingModuleActivation},
+};
+use wasmer_types::{ModuleHash, target::Target};
+use wasmer_wasix::{
+    IntrinsicFileImmutability, intrinsic_file_immutability,
+    runtime::{
+        module_cache::{CacheError, ModuleCache},
+        sealed_loader_audit::{
+            FileAdviceAudit, FileResidencyAudit, advise_file_away, advise_file_for_one_shot_read,
+            file_residency,
+        },
+    },
+};
+
+use crate::SEALED_MODULE_TRANSFORMATION_ID;
+#[cfg(feature = "memory-profile-core")]
+use crate::memory_profile::validate_serialized_memory_plans;
+
+const MANIFEST_SCHEMA: &str = "oliphaunt.wasix-postmaster.sealed-aot.v5";
+const MANIFEST_FORMAT_VERSION: u32 = 6;
+const ARTIFACT_ABI_VERSION: u32 = 21;
+const LINEAR_MEMORY_INSTALL_RECEIPT_SCHEMA: &str =
+    "oliphaunt.wasix-postmaster.linear-memory-install.v1";
+const SEALED_EXPORT_RECEIPT_PATH: &str =
+    "share/postgresql/wasix-postmaster.sealed-export.structure.receipt";
+const SEALED_EXPORT_SEED_PROOF_PATH: &str =
+    "share/postgresql/wasix-postmaster.sealed-export.seed-proof.json";
+const SEALED_EXPORT_FINAL_PROOF_PATH: &str =
+    "share/postgresql/wasix-postmaster.sealed-export.final-proof.json";
+const SEALED_EXPORT_ALLOWLIST_PATH: &str =
+    "share/postgresql/wasix-postmaster.sealed-export.allowlist";
+const SEALED_EXPORT_RECEIPT_SCHEMA: &str = "oliphaunt.wasix-postmaster.sealed-export-structure.v1";
+const SEALED_EXPORT_PROOF_SCHEMA: &str =
+    "oliphaunt.wasix-postmaster.sealed-export-closure-proof.v2";
+const SEALED_EXPORT_POLICY_ID: &str = "oliphaunt.wasix-postmaster.sealed-export-closure.v1";
+const SEALED_EXPORT_MANDATORY_POLICY_SHA256: &str =
+    "a129bd8c380dfd148bfcd96ca4f008ac1db7976b2565bae43fea382b249f4575";
+const SEALED_EXPORT_DLSYM_POLICY_SHA256: &str =
+    "b695f84830efdf23cb0cc2b025dc6d0e59645139272063f4e717303c201b1637";
+const SEALED_EXPORT_SIDE_MANIFEST_SHA256: &str =
+    "d2759bb82f0b17f6d6314fd72b500d92a7b7c2fc5f3755fffa277038ed515b55";
+const LINEAR_MEMORY_PROFILE_ID: &str =
+    "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1";
+const LINEAR_MEMORY_MAXIMUM_PAGES: u32 = 4_096;
+const LINEAR_MEMORY_MAXIMUM_BYTES: u64 = 268_435_456;
+const LINEAR_MEMORY_STATIC_BOUND_PAGES: u32 = 65_536;
+const LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES: u64 = 2_147_483_648;
+const MAX_LINEAR_MEMORY_RECEIPT_BYTES: u64 = 4 * 1024 * 1024;
+const MAX_SEALED_EXPORT_PROOF_BYTES: u64 = 16 * 1024 * 1024;
+const MAX_MANIFEST_BYTES: u64 = 1024 * 1024;
+const SEALED_EXPORT_SIDE_PATHS: [&str; 27] = [
+    "lib/libpq.so.5.18",
+    "lib/postgresql/cyrillic_and_mic.so",
+    "lib/postgresql/dict_snowball.so",
+    "lib/postgresql/euc2004_sjis2004.so",
+    "lib/postgresql/euc_cn_and_mic.so",
+    "lib/postgresql/euc_jp_and_sjis.so",
+    "lib/postgresql/euc_kr_and_mic.so",
+    "lib/postgresql/euc_tw_and_big5.so",
+    "lib/postgresql/latin2_and_win1250.so",
+    "lib/postgresql/latin_and_mic.so",
+    "lib/postgresql/plpgsql.so",
+    "lib/postgresql/utf8_and_big5.so",
+    "lib/postgresql/utf8_and_cyrillic.so",
+    "lib/postgresql/utf8_and_euc2004.so",
+    "lib/postgresql/utf8_and_euc_cn.so",
+    "lib/postgresql/utf8_and_euc_jp.so",
+    "lib/postgresql/utf8_and_euc_kr.so",
+    "lib/postgresql/utf8_and_euc_tw.so",
+    "lib/postgresql/utf8_and_gb18030.so",
+    "lib/postgresql/utf8_and_gbk.so",
+    "lib/postgresql/utf8_and_iso8859.so",
+    "lib/postgresql/utf8_and_iso8859_1.so",
+    "lib/postgresql/utf8_and_johab.so",
+    "lib/postgresql/utf8_and_sjis.so",
+    "lib/postgresql/utf8_and_sjis2004.so",
+    "lib/postgresql/utf8_and_uhc.so",
+    "lib/postgresql/utf8_and_win.so",
+];
+const EXPECTED_WASM_FEATURES: [&str; 2] = ["exceptions", "threads"];
+const WASIX_POSTMASTER_SOURCE_LANE: &str = "wasix-postmaster";
+const WASIX_POSTMASTER_ENTRYPOINT: &str = "runtime:postgres";
+const REQUIRE_ZERO_WRITE_AOT_ENV: &str = "OLIPHAUNT_WASIX_REQUIRE_ZERO_WRITE_AOT";
+const SEALED_LOADER_AUDIT_FILE_ENV: &str = "OLIPHAUNT_WASIX_SEALED_LOADER_AUDIT_FILE";
+#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+const CODE_MEMORY_STATE_DIRECTORY: &str = ".oliphaunt-wasix-postmaster-code-memory-v1";
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum SealedActivationPolicy {
+    Compatibility,
+    RequireDirectImmutable,
+}
+
+impl SealedActivationPolicy {
+    fn from_environment() -> Result {
+        match std::env::var_os(REQUIRE_ZERO_WRITE_AOT_ENV) {
+            None => Ok(Self::Compatibility),
+            Some(value) if value == "0" => Ok(Self::Compatibility),
+            Some(value) if value == "1" => Ok(Self::RequireDirectImmutable),
+            Some(value) => bail!(
+                "{REQUIRE_ZERO_WRITE_AOT_ENV} must be exactly 0 or 1, got {:?}",
+                value
+            ),
+        }
+    }
+
+    const fn requires_direct_immutable(self) -> bool {
+        matches!(self, Self::RequireDirectImmutable)
+    }
+}
+
+/// Product executable selected from the exact sealed closure.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum SealedRuntimeIdentity {
+    /// The carrier's `bin/initdb` executable.
+    WasixPostmasterInitdb,
+    /// The carrier's `bin/postgres` executable.
+    WasixPostmasterPostgres,
+}
+
+impl SealedRuntimeIdentity {
+    /// Stable workload identity used by product-owned runtime policy.
+    pub const fn workload_id(self) -> &'static str {
+        match self {
+            Self::WasixPostmasterInitdb => "runtime:initdb",
+            Self::WasixPostmasterPostgres => "runtime:postgres",
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy)]
+struct ExpectedWasixPostmasterArtifact {
+    kind: &'static str,
+    module_path: &'static str,
+    exec_aliases: &'static [&'static str],
+    executable: Option,
+}
+
+const EXPECTED_WASIX_POSTMASTER_EXECUTABLES: [ExpectedWasixPostmasterArtifact; 2] = [
+    ExpectedWasixPostmasterArtifact {
+        kind: "executable",
+        module_path: "bin/initdb",
+        exec_aliases: &["/bin/initdb"],
+        executable: Some(SealedRuntimeIdentity::WasixPostmasterInitdb),
+    },
+    ExpectedWasixPostmasterArtifact {
+        kind: "executable",
+        module_path: "bin/postgres",
+        exec_aliases: &["/bin/postgres"],
+        executable: Some(SealedRuntimeIdentity::WasixPostmasterPostgres),
+    },
+];
+
+/// Activated entrypoint plus the still-lazy authoritative carrier closure.
+#[derive(Debug)]
+pub struct LoadedSealedModules {
+    /// Selected compiler-free entrypoint module.
+    pub module: Module,
+    /// Hash of the selected entrypoint's raw Wasm module.
+    pub module_hash: ModuleHash,
+    /// Exact host spelling of the selected carrier executable.
+    pub path: PathBuf,
+    /// Closed executable alias registry shared by all fresh EXEC_BACKEND environments.
+    pub executables: Vec<(String, ModuleHash)>,
+    /// Authoritative, immutable full-closure AOT cache.
+    pub module_cache: Arc,
+}
+
+/// The manifest and path identities captured by the single authoritative read.
+#[derive(Debug)]
+pub struct PreparedSealedManifest {
+    manifest: SealedManifest,
+    carrier_root: PathBuf,
+    input_path: PathBuf,
+    input_canonical: PathBuf,
+    runtime_identity: Option,
+}
+
+impl PreparedSealedManifest {
+    /// Return the exact initdb/postgres identity selected by the input path.
+    pub const fn runtime_identity(&self) -> Option {
+        self.runtime_identity
+    }
+
+    /// Create or validate the product-owned strict code-memory state directory.
+    ///
+    /// The exact admitted carrier root is already canonical. The state directory
+    /// is one deterministic sibling beneath its owned carrier parent;
+    /// there is no environment lookup, temporary-directory search, or fallback.
+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+    pub fn strict_code_memory_directory(&self) -> Result<(PathBuf, u64, u64), Error> {
+        strict_code_memory_directory_for_carrier(&self.carrier_root)
+    }
+}
+
+#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+fn strict_code_memory_directory_for_carrier(
+    carrier_root: &Path,
+) -> Result<(PathBuf, u64, u64), Error> {
+    use std::os::unix::{fs::DirBuilderExt, fs::MetadataExt};
+
+    let carrier_parent = carrier_root
+        .parent()
+        .context("sealed carrier root must have a parent directory")?;
+    let parent_metadata = fs::metadata(carrier_parent).with_context(|| {
+        format!(
+            "inspect strict code-memory parent {}",
+            carrier_parent.display()
+        )
+    })?;
+    ensure!(
+        parent_metadata.is_dir(),
+        "strict code-memory parent is not a directory: {}",
+        carrier_parent.display()
+    );
+    ensure!(
+        parent_metadata.uid() == unsafe { libc::geteuid() },
+        "strict code-memory parent is not owned by the effective user: {}",
+        carrier_parent.display()
+    );
+
+    let directory = carrier_parent.join(CODE_MEMORY_STATE_DIRECTORY);
+    let mut builder = fs::DirBuilder::new();
+    builder.mode(0o700);
+    match builder.create(&directory) {
+        Ok(()) => {}
+        Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {}
+        Err(error) => {
+            return Err(error).with_context(|| {
+                format!(
+                    "create strict code-memory directory {}",
+                    directory.display()
+                )
+            });
+        }
+    }
+
+    // lstat rejects a path substitution before the engine independently opens
+    // and pins its O_DIRECTORY descriptor. The engine repeats the owner/mode
+    // checks on that descriptor to close the validation/open race rather than
+    // trusting these path-based observations alone.
+    let metadata = fs::symlink_metadata(&directory).with_context(|| {
+        format!(
+            "inspect strict code-memory directory {}",
+            directory.display()
+        )
+    })?;
+    ensure!(
+        !metadata.file_type().is_symlink() && metadata.is_dir(),
+        "strict code-memory path must be a non-symlink directory: {}",
+        directory.display()
+    );
+    ensure!(
+        metadata.uid() == unsafe { libc::geteuid() },
+        "strict code-memory directory is not owned by the effective user: {}",
+        directory.display()
+    );
+    ensure!(
+        metadata.mode() & 0o7777 == 0o700,
+        "strict code-memory directory must have exact mode 0700: {}",
+        directory.display()
+    );
+    ensure!(
+        metadata.dev() == parent_metadata.dev(),
+        "strict code-memory directory changed filesystem device: {}",
+        directory.display()
+    );
+    Ok((directory, parent_metadata.dev(), metadata.ino()))
+}
+
+/// The exact, immutable AOT closure admitted by a sealed carrier.
+#[derive(Debug)]
+pub struct SealedModuleCache {
+    engine_id: wasmer::EngineId,
+    engine_kind: String,
+    artifacts: HashMap>,
+}
+
+impl SealedModuleCache {
+    fn new(engine: &Engine, artifacts: HashMap>) -> Self {
+        Self {
+            engine_id: engine.id(),
+            engine_kind: engine.deterministic_id(),
+            artifacts,
+        }
+    }
+
+    fn load_exact(&self, key: ModuleHash, engine: &Engine) -> Result {
+        if engine.id() != self.engine_id {
+            return Err(sealed_cache_error(format!(
+                "sealed module cache engine mismatch: cache={:?}/{} requested={:?}/{}",
+                self.engine_id,
+                self.engine_kind,
+                engine.id(),
+                engine.deterministic_id(),
+            )));
+        }
+        self.artifacts
+            .get(&key)
+            .ok_or(CacheError::NotFound)?
+            .activate(engine)
+    }
+}
+
+#[async_trait::async_trait]
+impl ModuleCache for SealedModuleCache {
+    fn is_authoritative(&self) -> bool {
+        true
+    }
+
+    async fn load(&self, key: ModuleHash, engine: &Engine) -> Result {
+        self.load_exact(key, engine)
+    }
+
+    async fn contains(&self, key: ModuleHash, engine: &Engine) -> Result {
+        if engine.id() != self.engine_id {
+            return Err(sealed_cache_error(format!(
+                "sealed module cache engine mismatch: cache={:?}/{} requested={:?}/{}",
+                self.engine_id,
+                self.engine_kind,
+                engine.id(),
+                engine.deterministic_id(),
+            )));
+        }
+        Ok(self.artifacts.contains_key(&key))
+    }
+
+    async fn save(
+        &self,
+        key: ModuleHash,
+        _engine: &Engine,
+        _module: &Module,
+    ) -> Result<(), CacheError> {
+        Err(sealed_cache_error(format!(
+            "sealed module cache is immutable; refusing save for {key}"
+        )))
+    }
+}
+
+fn sealed_cache_error(message: impl Into) -> CacheError {
+    CacheError::other(std::io::Error::new(
+        std::io::ErrorKind::PermissionDenied,
+        message.into(),
+    ))
+}
+
+struct LazySealedArtifact {
+    module_hash: ModuleHash,
+    expected_digest: [u8; 32],
+    policy: SealedActivationPolicy,
+    source: Mutex>,
+    activation: OnceLock>>,
+    #[cfg(test)]
+    activation_attempts: std::sync::atomic::AtomicUsize,
+}
+
+impl fmt::Debug for LazySealedArtifact {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        formatter
+            .debug_struct("LazySealedArtifact")
+            .field("module_hash", &self.module_hash)
+            .field("activated", &self.activation.get().is_some())
+            .finish_non_exhaustive()
+    }
+}
+
+impl LazySealedArtifact {
+    fn new(
+        module_hash: ModuleHash,
+        expected_digest: [u8; 32],
+        source: SealedArtifactSource,
+        policy: SealedActivationPolicy,
+    ) -> Self {
+        Self {
+            module_hash,
+            expected_digest,
+            policy,
+            source: Mutex::new(Some(source)),
+            activation: OnceLock::new(),
+            #[cfg(test)]
+            activation_attempts: std::sync::atomic::AtomicUsize::new(0),
+        }
+    }
+
+    fn activate(&self, engine: &Engine) -> Result {
+        self.activate_with_audit(engine, emit_loader_audit)
+    }
+
+    fn activate_with_audit(
+        &self,
+        engine: &Engine,
+        emit_audit: impl FnOnce(LoaderAuditRecord) -> Result<(), Error>,
+    ) -> Result {
+        self.activation
+            .get_or_init(|| {
+                #[cfg(test)]
+                self.activation_attempts
+                    .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
+
+                let source = self
+                    .source
+                    .lock()
+                    .map_err(|_| Arc::::from("sealed artifact source lock poisoned"))?
+                    .take()
+                    .ok_or_else(|| Arc::::from("sealed artifact source already consumed"))?;
+                let snapshot = immutable_artifact_snapshot(source, self.policy).map_err(|error| {
+                    Arc::::from(format!("snapshot sealed AOT artifact: {error:#}"))
+                })?;
+                let read_advice = snapshot.advise_for_one_shot_read();
+                let audit = snapshot.audit;
+                let activation = (|| -> Result<
+                    (
+                        PendingModuleActivation,
+                        FileResidencyAudit,
+                        FileResidencyAudit,
+                    ),
+                    Arc,
+                > {
+                    let mapping = snapshot.mapping().map_err(|error| {
+                        Arc::::from(format!(
+                            "map immutable sealed artifact snapshot: {error:#}"
+                        ))
+                    })?;
+
+                    let actual_digest: [u8; 32] = Sha256::digest(mapping.as_slice()).into();
+                    if actual_digest != self.expected_digest {
+                        return Err(Arc::::from(format!(
+                            "sealed AOT artifact SHA-256 mismatch: expected={} actual={}",
+                            hex::encode(self.expected_digest),
+                            hex::encode(actual_digest)
+                        )));
+                    }
+                    let inspected_hash = engine
+                        .inspect_serialized_artifact(&mapping)
+                        .map_err(|error| {
+                            Arc::::from(format!("inspect sealed AOT artifact: {error}"))
+                        })?;
+                    if inspected_hash != self.module_hash {
+                        return Err(Arc::::from(format!(
+                            "sealed AOT artifact embedded hash mismatch: expected={} actual={inspected_hash}",
+                            self.module_hash
+                        )));
+                    }
+                    let residency_after_hash_inspect =
+                        snapshot.residency();
+
+                    // SAFETY: this exact immutable mapping was just hashed and
+                    // inspected. The checked deserializer consumes that same
+                    // mapping; no path is reopened between verification/use.
+                    let pending = unsafe {
+                        engine.deserialize_from_mmapped_buffer_detached_pending(mapping)
+                    }
+                    .map_err(|error| {
+                        Arc::::from(format!("activate sealed AOT artifact: {error}"))
+                    })?;
+                    // The detached deserializer consumed and released the
+                    // archive mapping before returning. This descriptor-only
+                    // mincore probe cannot touch executable or payload bytes.
+                    let residency_after_archive_release = snapshot.residency();
+                    let embedded_hash = pending.module_hash().ok_or_else(|| {
+                        Arc::::from("activated sealed artifact has no embedded module hash")
+                    })?;
+                    if embedded_hash != self.module_hash {
+                        return Err(Arc::::from(format!(
+                            "activated sealed artifact hash mismatch: expected={} actual={embedded_hash}",
+                            self.module_hash
+                        )));
+                    }
+                    #[cfg(feature = "memory-profile-core")]
+                    validate_serialized_memory_plans(&pending.linear_memory_plans()).map_err(
+                        |error| {
+                            Arc::::from(format!(
+                                "activated sealed artifact linear-memory profile mismatch: {error:#}"
+                            ))
+                        },
+                    )?;
+                    Ok((
+                        pending,
+                        residency_after_hash_inspect,
+                        residency_after_archive_release,
+                    ))
+                })();
+                let source_residency_before_eviction = snapshot.source_residency();
+                let source_cache_eviction = snapshot.advise_source_away();
+                let source_residency_after_eviction = snapshot.source_residency();
+                let snapshot_cache_eviction = snapshot.advise_snapshot_away();
+                let residency_after_eviction = snapshot.residency();
+                let (pending, residency_after_hash_inspect, residency_after_archive_release) =
+                    activation?;
+                tracing::debug!(
+                    target: "wasmer_cli::sealed_loader_audit",
+                    audit_schema = "oliphaunt.wasix-postmaster.sealed-loader-audit.v2",
+                    artifact_kind = "aot",
+                    module_sha256 = %self.module_hash,
+                    activation_state = "active",
+                    snapshot_mode = audit.mode.as_str(),
+                    logical_bytes = audit.logical_bytes,
+                    source_bytes_read = audit.source_bytes_read,
+                    snapshot_bytes_written = audit.snapshot_bytes_written,
+                    source_bytes_written = 0_u64,
+                    mapping_bytes_hashed = audit.mapping_bytes_hashed,
+                    sync_calls = audit.sync_calls,
+                    read_advice_calls = read_advice.calls,
+                    read_advice_successes = read_advice.successes,
+                    read_advice_first_errno = read_advice.first_errno,
+                    source_cache_eviction_supported = source_cache_eviction.supported,
+                    source_cache_eviction_calls = source_cache_eviction.calls,
+                    source_cache_eviction_successes = source_cache_eviction.successes,
+                    source_cache_eviction_errno = source_cache_eviction.first_errno,
+                    snapshot_cache_eviction_applicable = snapshot.has_distinct_source(),
+                    snapshot_cache_eviction_supported = snapshot_cache_eviction.supported,
+                    snapshot_cache_eviction_calls = snapshot_cache_eviction.calls,
+                    snapshot_cache_eviction_successes = snapshot_cache_eviction.successes,
+                    snapshot_cache_eviction_errno = snapshot_cache_eviction.first_errno,
+                    residency_after_hash_inspect_state = residency_after_hash_inspect.state.as_str(),
+                    residency_after_hash_inspect_pages = residency_after_hash_inspect.resident_pages,
+                    residency_after_archive_release_state = residency_after_archive_release.state.as_str(),
+                    residency_after_archive_release_pages = residency_after_archive_release.resident_pages,
+                    residency_after_eviction_state = residency_after_eviction.state.as_str(),
+                    residency_after_eviction_pages = residency_after_eviction.resident_pages,
+                    write_policy = audit.mode.write_policy(),
+                    "activated sealed artifact"
+                );
+                emit_audit(LoaderAuditRecord {
+                    artifact_kind: "aot",
+                    module_sha256: canonical_module_sha256(self.module_hash),
+                    snapshot_mode: audit.mode.as_str(),
+                    logical_bytes: audit.logical_bytes,
+                    source_bytes_read: audit.source_bytes_read,
+                    source_bytes_written: 0,
+                    snapshot_bytes_written: audit.snapshot_bytes_written,
+                    mapping_bytes_hashed: audit.mapping_bytes_hashed,
+                    sync_calls: audit.sync_calls,
+                    read_advice_applicable: true,
+                    read_advice_supported: read_advice.supported,
+                    read_advice_calls: read_advice.calls,
+                    read_advice_successes: read_advice.successes,
+                    read_advice_first_errno: read_advice.first_errno,
+                    source_cache_eviction_applicable: true,
+                    source_cache_eviction_supported: source_cache_eviction.supported,
+                    source_cache_eviction_calls: source_cache_eviction.calls,
+                    source_cache_eviction_successes: source_cache_eviction.successes,
+                    source_cache_eviction_errno: source_cache_eviction.first_errno,
+                    snapshot_cache_eviction_applicable: snapshot.has_distinct_source(),
+                    snapshot_cache_eviction_supported: snapshot_cache_eviction.supported,
+                    snapshot_cache_eviction_calls: snapshot_cache_eviction.calls,
+                    snapshot_cache_eviction_successes: snapshot_cache_eviction.successes,
+                    snapshot_cache_eviction_errno: snapshot_cache_eviction.first_errno,
+                    mapping_cache_eviction_applicable: false,
+                    mapping_cache_eviction_supported: true,
+                    mapping_cache_eviction_calls: 0,
+                    mapping_cache_eviction_successes: 0,
+                    mapping_cache_eviction_errno: None,
+                    residency_after_hash_inspect: residency_after_hash_inspect.into(),
+                    residency_after_archive_release: residency_after_archive_release.into(),
+                    source_residency_before_eviction: source_residency_before_eviction.into(),
+                    source_residency_after_eviction: source_residency_after_eviction.into(),
+                    residency_after_eviction: residency_after_eviction.into(),
+                    write_policy: audit.mode.write_policy(),
+                })
+                .map_err(|error| {
+                    Arc::::from(format!("write sealed loader audit receipt: {error:#}"))
+                })?;
+                Ok(pending.commit())
+            })
+            .clone()
+            .map_err(|message| sealed_cache_error(message.to_string()))
+    }
+}
+
+struct SealedArtifactSource {
+    file: File,
+    path: PathBuf,
+    carrier_root: PathBuf,
+    expected_size: u64,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum ArtifactSnapshotMode {
+    DirectIntrinsic(IntrinsicFileImmutability),
+    Reflink,
+    StreamedCopy,
+}
+
+impl ArtifactSnapshotMode {
+    const fn as_str(self) -> &'static str {
+        match self {
+            Self::DirectIntrinsic(IntrinsicFileImmutability::ReadOnlyFilesystem) => {
+                "direct-read-only-filesystem"
+            }
+            Self::DirectIntrinsic(IntrinsicFileImmutability::ImmutableInode) => {
+                "direct-immutable-inode"
+            }
+            Self::Reflink => "reflink",
+            Self::StreamedCopy => "streamed-copy",
+        }
+    }
+
+    const fn write_policy(self) -> &'static str {
+        match self {
+            Self::DirectIntrinsic(_) => "none-immutable-source",
+            Self::Reflink => "private-reflink-no-userspace-payload-write",
+            Self::StreamedCopy => "private-streamed-copy-no-sync",
+        }
+    }
+}
+
+#[derive(Debug, Serialize)]
+struct LoaderAuditRecord {
+    artifact_kind: &'static str,
+    module_sha256: String,
+    snapshot_mode: &'static str,
+    logical_bytes: u64,
+    source_bytes_read: u64,
+    source_bytes_written: u64,
+    snapshot_bytes_written: u64,
+    mapping_bytes_hashed: u64,
+    sync_calls: u64,
+    read_advice_applicable: bool,
+    read_advice_supported: bool,
+    read_advice_calls: u64,
+    read_advice_successes: u64,
+    read_advice_first_errno: Option,
+    source_cache_eviction_applicable: bool,
+    source_cache_eviction_supported: bool,
+    source_cache_eviction_calls: u64,
+    source_cache_eviction_successes: u64,
+    source_cache_eviction_errno: Option,
+    snapshot_cache_eviction_applicable: bool,
+    snapshot_cache_eviction_supported: bool,
+    snapshot_cache_eviction_calls: u64,
+    snapshot_cache_eviction_successes: u64,
+    snapshot_cache_eviction_errno: Option,
+    mapping_cache_eviction_applicable: bool,
+    mapping_cache_eviction_supported: bool,
+    mapping_cache_eviction_calls: u64,
+    mapping_cache_eviction_successes: u64,
+    mapping_cache_eviction_errno: Option,
+    residency_after_hash_inspect: LoaderResidencyRecord,
+    residency_after_archive_release: LoaderResidencyRecord,
+    source_residency_before_eviction: LoaderResidencyRecord,
+    source_residency_after_eviction: LoaderResidencyRecord,
+    residency_after_eviction: LoaderResidencyRecord,
+    write_policy: &'static str,
+}
+
+fn canonical_module_sha256(module_hash: ModuleHash) -> String {
+    hex::encode(module_hash.as_bytes())
+}
+
+#[derive(Debug, Serialize)]
+struct LoaderResidencyRecord {
+    state: &'static str,
+    page_size: Option,
+    total_pages: Option,
+    resident_pages: Option,
+    resident_bytes: Option,
+    errno: Option,
+}
+
+impl From for LoaderResidencyRecord {
+    fn from(audit: FileResidencyAudit) -> Self {
+        Self {
+            state: audit.state.as_str(),
+            page_size: audit.page_size,
+            total_pages: audit.total_pages,
+            resident_pages: audit.resident_pages,
+            resident_bytes: audit.resident_bytes,
+            errno: audit.errno,
+        }
+    }
+}
+
+#[derive(Serialize)]
+struct LoaderAuditEnvelope<'a> {
+    schema: &'static str,
+    pid: u32,
+    #[serde(flatten)]
+    record: &'a LoaderAuditRecord,
+}
+
+fn emit_loader_audit(record: LoaderAuditRecord) -> Result<(), Error> {
+    let Some(path) = std::env::var_os(SEALED_LOADER_AUDIT_FILE_ENV) else {
+        return Ok(());
+    };
+    let path = PathBuf::from(path);
+    ensure!(
+        !path.as_os_str().is_empty(),
+        "{SEALED_LOADER_AUDIT_FILE_ENV} must not be empty"
+    );
+    emit_loader_audit_to_path(&path, &record)
+}
+
+#[cfg(unix)]
+fn emit_loader_audit_to_path(path: &Path, record: &LoaderAuditRecord) -> Result<(), Error> {
+    let envelope = LoaderAuditEnvelope {
+        schema: "oliphaunt.wasix-postmaster.sealed-loader-receipt.v2",
+        pid: std::process::id(),
+        record,
+    };
+    append_sealed_loader_audit_record(path, &envelope)
+}
+
+#[cfg(unix)]
+fn append_sealed_loader_audit_record(path: &Path, record: &impl Serialize) -> Result<(), Error> {
+    use std::os::{
+        fd::AsRawFd,
+        unix::fs::{MetadataExt, OpenOptionsExt},
+    };
+
+    let mut options = OpenOptions::new();
+    options
+        .create(true)
+        .append(true)
+        .mode(0o600)
+        .custom_flags(libc::O_CLOEXEC | libc::O_NOFOLLOW);
+    let file = options
+        .open(path)
+        .with_context(|| format!("open sealed loader audit receipt {}", path.display()))?;
+    let metadata = file.metadata()?;
+    ensure!(
+        metadata.is_file(),
+        "sealed loader audit receipt is not a regular file"
+    );
+    ensure!(
+        metadata.uid() == unsafe { libc::geteuid() },
+        "sealed loader audit receipt is not owned by the runtime uid"
+    );
+    ensure!(
+        metadata.nlink() == 1,
+        "sealed loader audit receipt must have exactly one link"
+    );
+    ensure!(
+        metadata.mode() & 0o077 == 0,
+        "sealed loader audit receipt exposes group/other permissions"
+    );
+
+    let mut line = serde_json::to_vec(record).context("encode sealed loader audit record")?;
+    line.push(b'\n');
+    ensure!(
+        line.len() <= 4096,
+        "sealed loader audit record exceeds atomic-write bound"
+    );
+    // SAFETY: the buffer remains live for this single O_APPEND write. One
+    // syscall keeps concurrent process records contiguous; short writes fail
+    // activation so qualification cannot accept a partial receipt.
+    let written = unsafe { libc::write(file.as_raw_fd(), line.as_ptr().cast(), line.len()) };
+    if written < 0 {
+        return Err(std::io::Error::last_os_error()).context("append sealed loader audit record");
+    }
+    ensure!(
+        usize::try_from(written).ok() == Some(line.len()),
+        "short sealed loader audit write: expected={} actual={written}",
+        line.len()
+    );
+    Ok(())
+}
+
+#[cfg(not(unix))]
+fn emit_loader_audit_to_path(_path: &Path, _record: &LoaderAuditRecord) -> Result<(), Error> {
+    bail!("sealed loader audit receipts require Unix O_APPEND/O_NOFOLLOW semantics")
+}
+
+#[cfg(not(unix))]
+fn append_sealed_loader_audit_record(_path: &Path, _record: &impl Serialize) -> Result<(), Error> {
+    bail!("sealed loader audit receipts require Unix O_APPEND/O_NOFOLLOW semantics")
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+struct ArtifactSnapshotAudit {
+    mode: ArtifactSnapshotMode,
+    logical_bytes: u64,
+    source_bytes_read: u64,
+    snapshot_bytes_written: u64,
+    mapping_bytes_hashed: u64,
+    sync_calls: u64,
+}
+
+struct ImmutableArtifactSnapshot {
+    file: File,
+    /// Retained only when activation uses a private reflink/streamed snapshot.
+    /// This is the exact already-open carrier source, never a reopened path.
+    source_file: Option,
+    len: u64,
+    audit: ArtifactSnapshotAudit,
+}
+
+impl fmt::Debug for ImmutableArtifactSnapshot {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        formatter
+            .debug_struct("ImmutableArtifactSnapshot")
+            .field("len", &self.len)
+            .field("has_distinct_source", &self.source_file.is_some())
+            .finish_non_exhaustive()
+    }
+}
+
+impl ImmutableArtifactSnapshot {
+    fn mapping(&self) -> Result {
+        let mapping = wasmer::sys::OwnedBuffer::from_file(&self.file)
+            .context("memory-map immutable sealed artifact snapshot")?;
+        ensure!(
+            u64::try_from(mapping.len()).ok() == Some(self.len),
+            "immutable sealed artifact snapshot changed size"
+        );
+        Ok(mapping)
+    }
+
+    fn advise_for_one_shot_read(&self) -> FileAdviceAudit {
+        advise_file_for_one_shot_read(&self.file)
+    }
+
+    fn advise_source_away(&self) -> FileAdviceAudit {
+        advise_file_away(self.source_file.as_ref().unwrap_or(&self.file))
+    }
+
+    fn advise_snapshot_away(&self) -> FileAdviceAudit {
+        self.source_file
+            .as_ref()
+            .map_or_else(FileAdviceAudit::not_applicable, |_| {
+                advise_file_away(&self.file)
+            })
+    }
+
+    fn residency(&self) -> FileResidencyAudit {
+        file_residency(&self.file, self.len)
+    }
+
+    fn source_residency(&self) -> FileResidencyAudit {
+        file_residency(self.source_file.as_ref().unwrap_or(&self.file), self.len)
+    }
+
+    fn has_distinct_source(&self) -> bool {
+        self.source_file.is_some()
+    }
+}
+
+enum WritableArtifactSnapshot {
+    #[cfg(target_os = "linux")]
+    Anonymous(File),
+    Named {
+        temp_dir: tempfile::TempDir,
+        file: tempfile::NamedTempFile,
+    },
+}
+
+impl WritableArtifactSnapshot {
+    fn file_mut(&mut self) -> &mut File {
+        match self {
+            #[cfg(target_os = "linux")]
+            Self::Anonymous(file) => file,
+            Self::Named { file, .. } => file.as_file_mut(),
+        }
+    }
+
+    fn finalize(
+        self,
+        expected_size: u64,
+        audit: ArtifactSnapshotAudit,
+    ) -> Result {
+        match self {
+            #[cfg(target_os = "linux")]
+            Self::Anonymous(file) => finalize_anonymous_snapshot(file, expected_size, audit),
+            Self::Named { temp_dir, file } => {
+                finalize_named_snapshot(temp_dir, file, expected_size, audit)
+            }
+        }
+    }
+}
+
+#[derive(Debug, Deserialize)]
+#[cfg_attr(test, derive(serde::Serialize))]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+struct SealedManifest {
+    format_version: u32,
+    schema: String,
+    source_lane: String,
+    source_fingerprint: String,
+    core_profile: String,
+    guest_build_recipe_sha256: String,
+    postgres_version: String,
+    target_triple: String,
+    host_abi: String,
+    engine: String,
+    compiler_config: String,
+    cpu_policy: String,
+    cpu_features: Vec,
+    wasmer_version: String,
+    wasmer_wasix_version: String,
+    wasmer_source_commit: String,
+    wasmer_patch_sha256: String,
+    wasmer_cargo_lock_sha256: String,
+    artifact_abi_version: u32,
+    runtime_abi_id: String,
+    producer_recipe_sha256: String,
+    executor_engine: String,
+    executor_sha256: String,
+    executor_size: u64,
+    linear_memory_profile: SealedLinearMemoryProfile,
+    wasm_features: Vec,
+    entrypoint: String,
+    artifacts: Vec,
+}
+
+#[derive(Debug, Deserialize)]
+#[cfg_attr(test, derive(serde::Serialize))]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+struct SealedLinearMemoryProfile {
+    id: String,
+    address_width: String,
+    supported_host_pointer_width: String,
+    maximum_pages: u32,
+    maximum_bytes: u64,
+    static_bound_pages: u32,
+    static_offset_guard_bytes: u64,
+    static_access_lowering: String,
+    install_receipt_path: String,
+    install_receipt_sha256: String,
+}
+
+#[derive(Debug, Deserialize)]
+#[cfg_attr(test, derive(serde::Serialize))]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+struct SealedArtifact {
+    name: String,
+    kind: String,
+    path: String,
+    module_path: String,
+    sha256: String,
+    raw_sha256: String,
+    raw_size: u64,
+    module_sha256: String,
+    module_size: u64,
+    linear_memory: SealedArtifactLinearMemory,
+    compressed: bool,
+    exec_aliases: Vec,
+}
+
+#[derive(Debug, Deserialize)]
+#[cfg_attr(test, derive(serde::Serialize))]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+struct SealedArtifactLinearMemory {
+    profile_id: String,
+    source_module_sha256: String,
+    install_receipt_sha256: String,
+}
+
+/// Read and structurally admit an exact sealed manifest for one local executable.
+pub fn prepare(manifest_path: &Path, input_path: &Path) -> Result {
+    let manifest = read_manifest(manifest_path)?;
+    ensure!(
+        has_exact_wasix_postmaster_identity(&manifest),
+        "sealed manifest is not the exact WASIX-postmaster artifact closure"
+    );
+    let carrier_root = manifest_path
+        .parent()
+        .context("sealed manifest must have a parent directory")?
+        .canonicalize()
+        .with_context(|| format!("resolve carrier root for {}", manifest_path.display()))?;
+    validate_linear_memory_install_receipt(&manifest, &carrier_root)?;
+    let input_canonical = input_path
+        .canonicalize()
+        .with_context(|| format!("resolve sealed executable input {}", input_path.display()))?;
+    let runtime_identity = EXPECTED_WASIX_POSTMASTER_EXECUTABLES
+        .iter()
+        .filter_map(|artifact| artifact.executable.map(|identity| (artifact, identity)))
+        .find_map(|(artifact, identity)| {
+            let expected_path = carrier_root
+                .join(artifact.module_path)
+                .canonicalize()
+                .ok()?;
+            (expected_path == input_canonical).then_some(identity)
+        });
+    ensure!(
+        runtime_identity.is_some(),
+        "input '{}' is not an executable in the exact WASIX-postmaster closure",
+        input_path.display()
+    );
+    Ok(PreparedSealedManifest {
+        manifest,
+        carrier_root,
+        input_path: input_path.to_path_buf(),
+        input_canonical,
+        runtime_identity,
+    })
+}
+
+fn validate_linear_memory_profile(profile: &SealedLinearMemoryProfile) -> Result<(), Error> {
+    ensure!(
+        profile.id == LINEAR_MEMORY_PROFILE_ID
+            && profile.address_width == "wasm32"
+            && profile.supported_host_pointer_width == "u64"
+            && profile.maximum_pages == LINEAR_MEMORY_MAXIMUM_PAGES
+            && profile.maximum_bytes == LINEAR_MEMORY_MAXIMUM_BYTES
+            && profile.static_bound_pages == LINEAR_MEMORY_STATIC_BOUND_PAGES
+            && profile.static_offset_guard_bytes == LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES
+            && profile.static_access_lowering == "wasmer-llvm-unchecked-reservation-and-guard-v1",
+        "sealed manifest linear-memory profile does not match the exact trap-preserving product profile"
+    );
+    ensure_nonempty(
+        "linear-memory-profile.install-receipt-path",
+        &profile.install_receipt_path,
+    )?;
+    parse_sha256(
+        "linear-memory-profile.install-receipt-sha256",
+        &profile.install_receipt_sha256,
+    )?;
+    Ok(())
+}
+
+#[derive(Debug, Deserialize)]
+#[cfg_attr(test, derive(serde::Serialize))]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+struct LinearMemoryInstallReceipt {
+    schema: String,
+    profile_id: String,
+    address_width: String,
+    supported_host_pointer_width: String,
+    maximum_pages: u32,
+    maximum_bytes: u64,
+    static_bound_pages: u32,
+    static_offset_guard_bytes: u64,
+    static_access_lowering: String,
+    requires_shared: bool,
+    requires_import: String,
+    excludes_wasm32_end_wrap: bool,
+    predecessor_export_closure_receipt: String,
+    predecessor_export_closure_receipt_sha256: String,
+    source_module_closure_sha256: String,
+    module_closure_sha256: String,
+    module_count: usize,
+    modules: Vec,
+}
+
+#[derive(Debug, Deserialize)]
+#[cfg_attr(test, derive(serde::Serialize))]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+struct LinearMemoryInstallModule {
+    path: String,
+    source_module_sha256: String,
+    module_sha256: String,
+    initial_pages: u64,
+    maximum_pages: u64,
+    maximum_bytes: u64,
+    shared: bool,
+    import_module: String,
+    import_name: String,
+    transformation: String,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+#[allow(dead_code)] // Receipt schema fields are authenticated even when not consumed at runtime.
+struct SealedExportSnapshot {
+    sha256: String,
+    bytes: usize,
+    exports: usize,
+    local_functions: u32,
+    local_globals: u32,
+    element_function_entries: u32,
+    element_unique_function_indices: u32,
+    start_function_index: u32,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+struct SealedExportSideIdentity {
+    path: String,
+    sha256: String,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+#[allow(dead_code)] // Receipt schema fields are authenticated even when not consumed at runtime.
+struct SealedExportStructureReceipt {
+    schema: String,
+    policy_id: String,
+    analyzer_version: String,
+    analyzer_binary_sha256: String,
+    dce_tool_sha256: String,
+    dce_tool_version: String,
+    dce_passes: Vec,
+    mandatory_policy_sha256: String,
+    declared_main_dlsym_policy_sha256: String,
+    side_manifest_sha256: String,
+    allowlist_sha256: String,
+    seed_proof_sha256: String,
+    final_proof_sha256: String,
+    seed: SealedExportSnapshot,
+    final_module: SealedExportSnapshot,
+    sides: Vec,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+#[allow(dead_code)] // Proof schema fields are authenticated even when not consumed at runtime.
+struct SealedExportProofModule {
+    path: String,
+    sha256: String,
+    bytes: usize,
+    non_export_sections_sha256: String,
+    dylink_needed: Vec,
+    imported_functions: u32,
+    local_functions: u32,
+    imported_globals: u32,
+    local_globals: u32,
+    imported_tables: u32,
+    local_tables: u32,
+    element_function_entries: u32,
+    element_unique_function_indices: u32,
+    element_max_function_index: Option,
+    start_function_index: Option,
+    imports: Vec,
+    export_counts: BTreeMap,
+    exported_global_type_counts: BTreeMap,
+    exported_immutable_i32_globals: u32,
+    exported_local_functions: u32,
+    exported_imported_functions: u32,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+#[allow(dead_code)] // Proof schema fields are authenticated even when not consumed at runtime.
+struct SealedExportClosureProof {
+    schema: String,
+    policy_id: String,
+    analyzer_version: String,
+    mandatory_policy_sha256: String,
+    declared_main_dlsym_policy_sha256: String,
+    main: SealedExportProofModule,
+    sides: Vec,
+    mandatory_runtime_exports: Vec,
+    declared_main_dlsym_exports: Vec,
+    side_dynamic_imports: Vec,
+    retained_main_exports: Vec,
+    retained_main_export_descriptors: Vec,
+    removed_main_export_count: usize,
+    removed_main_export_names_sha256: String,
+    unresolved_main_requirements: Vec,
+    mismatched_main_requirements: Vec,
+    unresolved_side_dependencies: Vec,
+    retained_counts: BTreeMap,
+    removed_counts: BTreeMap,
+}
+
+fn update_framed(digest: &mut Sha256, value: &str) {
+    digest.update((value.len() as u64).to_be_bytes());
+    digest.update(value.as_bytes());
+}
+
+fn linear_memory_closure_sha256(modules: &[LinearMemoryInstallModule], hash_field: &str) -> String {
+    let mut digest = Sha256::new();
+    update_framed(
+        &mut digest,
+        "oliphaunt.wasix-postmaster.linear-memory-install-closure.v1",
+    );
+    update_framed(&mut digest, hash_field);
+    for module in modules {
+        update_framed(&mut digest, &module.path);
+        update_framed(
+            &mut digest,
+            if hash_field == "source-module-sha256" {
+                &module.source_module_sha256
+            } else {
+                &module.module_sha256
+            },
+        );
+    }
+    hex::encode(digest.finalize())
+}
+
+fn validate_sealed_export_proof(
+    proof: &SealedExportClosureProof,
+    label: &str,
+    receipt: &SealedExportStructureReceipt,
+    expected_main_sha256: &str,
+) -> Result<(), Error> {
+    ensure!(
+        proof.schema == SEALED_EXPORT_PROOF_SCHEMA
+            && proof.policy_id == SEALED_EXPORT_POLICY_ID
+            && proof.analyzer_version == receipt.analyzer_version
+            && proof.mandatory_policy_sha256 == receipt.mandatory_policy_sha256
+            && proof.declared_main_dlsym_policy_sha256 == receipt.declared_main_dlsym_policy_sha256,
+        "{label} schema/policy identity differs"
+    );
+    ensure!(
+        proof.main.path == "bin/postgres" && proof.main.sha256 == expected_main_sha256,
+        "{label} main module identity differs"
+    );
+    ensure!(
+        proof.sides.len() == receipt.sides.len(),
+        "{label} side-module count differs"
+    );
+    for (module, expected) in proof.sides.iter().zip(&receipt.sides) {
+        ensure!(
+            module.path == expected.path && module.sha256 == expected.sha256,
+            "{label} side-module identity differs for '{}'",
+            expected.path
+        );
+    }
+    ensure!(
+        proof.unresolved_main_requirements.is_empty()
+            && proof.mismatched_main_requirements.is_empty()
+            && proof.unresolved_side_dependencies.is_empty(),
+        "{label} does not prove a closed export graph"
+    );
+    parse_sha256(
+        &format!("{label} removed export names"),
+        &proof.removed_main_export_names_sha256,
+    )?;
+    ensure_nonempty(
+        &format!("{label} analyzer version"),
+        &proof.analyzer_version,
+    )?;
+    Ok(())
+}
+
+fn validate_sealed_export_predecessor(
+    carrier_root: &Path,
+    linear_receipt: &LinearMemoryInstallReceipt,
+) -> Result<(), Error> {
+    ensure!(
+        linear_receipt.predecessor_export_closure_receipt == SEALED_EXPORT_RECEIPT_PATH,
+        "linear-memory predecessor must be the canonical sealed-export receipt"
+    );
+    let source_modules = linear_receipt
+        .modules
+        .iter()
+        .map(|module| (module.path.as_str(), module.source_module_sha256.as_str()))
+        .collect::>();
+    let receipt_path = carrier_file_path(carrier_root, SEALED_EXPORT_RECEIPT_PATH)?;
+    let receipt_bytes = read_small_regular_file(&receipt_path, MAX_SEALED_EXPORT_PROOF_BYTES)?;
+    ensure!(
+        hex::encode(Sha256::digest(&receipt_bytes))
+            == linear_receipt.predecessor_export_closure_receipt_sha256,
+        "linear-memory predecessor sealed-export receipt SHA-256 differs"
+    );
+    let receipt: SealedExportStructureReceipt =
+        serde_json::from_slice(&receipt_bytes).context("parse sealed-export structural receipt")?;
+    ensure!(
+        receipt.schema == SEALED_EXPORT_RECEIPT_SCHEMA
+            && receipt.policy_id == SEALED_EXPORT_POLICY_ID
+            && receipt.dce_passes == ["--remove-unused-module-elements"]
+            && receipt.mandatory_policy_sha256 == SEALED_EXPORT_MANDATORY_POLICY_SHA256
+            && receipt.declared_main_dlsym_policy_sha256 == SEALED_EXPORT_DLSYM_POLICY_SHA256
+            && receipt.side_manifest_sha256 == SEALED_EXPORT_SIDE_MANIFEST_SHA256,
+        "sealed-export structural receipt policy differs"
+    );
+    for (label, value) in [
+        ("analyzer binary", receipt.analyzer_binary_sha256.as_str()),
+        ("DCE tool", receipt.dce_tool_sha256.as_str()),
+        ("allowlist", receipt.allowlist_sha256.as_str()),
+        ("seed proof", receipt.seed_proof_sha256.as_str()),
+        ("final proof", receipt.final_proof_sha256.as_str()),
+        ("seed module", receipt.seed.sha256.as_str()),
+        ("final module", receipt.final_module.sha256.as_str()),
+    ] {
+        parse_sha256(&format!("sealed-export {label}"), value)?;
+    }
+    ensure_nonempty("sealed-export analyzer version", &receipt.analyzer_version)?;
+    ensure_nonempty("sealed-export DCE tool version", &receipt.dce_tool_version)?;
+    ensure!(
+        source_modules.get("bin/postgres").copied() == Some(receipt.final_module.sha256.as_str()),
+        "sealed-export final module is not bin/postgres's linear-memory predecessor"
+    );
+    ensure!(
+        receipt.sides.len() == SEALED_EXPORT_SIDE_PATHS.len(),
+        "sealed-export structural receipt side count differs"
+    );
+    for (side, expected_path) in receipt.sides.iter().zip(SEALED_EXPORT_SIDE_PATHS) {
+        parse_sha256("sealed-export side module", &side.sha256)?;
+        ensure!(
+            side.path == expected_path
+                && source_modules.get(expected_path).copied() == Some(side.sha256.as_str()),
+            "sealed-export side is not the linear-memory predecessor for '{expected_path}'"
+        );
+    }
+
+    let read_bound = |relative: &str, expected: &str| -> Result, Error> {
+        let path = carrier_file_path(carrier_root, relative)?;
+        let bytes = read_small_regular_file(&path, MAX_SEALED_EXPORT_PROOF_BYTES)?;
+        ensure!(
+            hex::encode(Sha256::digest(&bytes)) == expected,
+            "sealed-export installed proof differs: {relative}"
+        );
+        Ok(bytes)
+    };
+    let _allowlist = read_bound(SEALED_EXPORT_ALLOWLIST_PATH, &receipt.allowlist_sha256)?;
+    let seed_bytes = read_bound(SEALED_EXPORT_SEED_PROOF_PATH, &receipt.seed_proof_sha256)?;
+    let final_bytes = read_bound(SEALED_EXPORT_FINAL_PROOF_PATH, &receipt.final_proof_sha256)?;
+    let seed: SealedExportClosureProof =
+        serde_json::from_slice(&seed_bytes).context("parse sealed-export seed proof")?;
+    let final_proof: SealedExportClosureProof =
+        serde_json::from_slice(&final_bytes).context("parse sealed-export final proof")?;
+    validate_sealed_export_proof(
+        &seed,
+        "sealed-export seed proof",
+        &receipt,
+        &receipt.seed.sha256,
+    )?;
+    validate_sealed_export_proof(
+        &final_proof,
+        "sealed-export final proof",
+        &receipt,
+        &receipt.final_module.sha256,
+    )?;
+    Ok(())
+}
+
+fn validate_linear_memory_install_receipt(
+    manifest: &SealedManifest,
+    carrier_root: &Path,
+) -> Result<(), Error> {
+    let profile = &manifest.linear_memory_profile;
+    validate_linear_memory_profile(profile)?;
+    let receipt_path = carrier_file_path(carrier_root, &profile.install_receipt_path)?;
+    let bytes = read_small_regular_file(&receipt_path, MAX_LINEAR_MEMORY_RECEIPT_BYTES)
+        .with_context(|| {
+            format!(
+                "read linear-memory install receipt {}",
+                receipt_path.display()
+            )
+        })?;
+    let actual_sha256 = hex::encode(Sha256::digest(&bytes));
+    ensure!(
+        actual_sha256.eq_ignore_ascii_case(&profile.install_receipt_sha256),
+        "linear-memory install receipt SHA-256 mismatch"
+    );
+    let receipt: LinearMemoryInstallReceipt =
+        serde_json::from_slice(&bytes).context("parse linear-memory install receipt")?;
+    ensure!(
+        receipt.schema == LINEAR_MEMORY_INSTALL_RECEIPT_SCHEMA
+            && receipt.profile_id == profile.id
+            && receipt.address_width == profile.address_width
+            && receipt.supported_host_pointer_width == profile.supported_host_pointer_width
+            && receipt.maximum_pages == profile.maximum_pages
+            && receipt.maximum_bytes == profile.maximum_bytes
+            && receipt.static_bound_pages == profile.static_bound_pages
+            && receipt.static_offset_guard_bytes == profile.static_offset_guard_bytes
+            && receipt.static_access_lowering == profile.static_access_lowering
+            && receipt.requires_shared
+            && receipt.requires_import == "env.memory"
+            && receipt.excludes_wasm32_end_wrap,
+        "linear-memory install receipt profile differs from sealed manifest"
+    );
+    ensure!(
+        receipt.module_count == receipt.modules.len() && receipt.module_count > 0,
+        "linear-memory install receipt module count is invalid"
+    );
+    parse_sha256(
+        "linear-memory predecessor export receipt",
+        &receipt.predecessor_export_closure_receipt_sha256,
+    )?;
+    ensure_nonempty(
+        "linear-memory predecessor export receipt path",
+        &receipt.predecessor_export_closure_receipt,
+    )?;
+    parse_sha256(
+        "linear-memory source closure",
+        &receipt.source_module_closure_sha256,
+    )?;
+    parse_sha256(
+        "linear-memory sealed closure",
+        &receipt.module_closure_sha256,
+    )?;
+
+    let mut paths = BTreeSet::new();
+    let mut previous = None;
+    for module in &receipt.modules {
+        ensure!(
+            previous.is_none_or(|path: &str| path < module.path.as_str()),
+            "linear-memory install receipt modules are not strictly path-sorted"
+        );
+        previous = Some(module.path.as_str());
+        ensure!(
+            paths.insert(module.path.as_str()),
+            "duplicate linear-memory module path"
+        );
+        parse_sha256("linear-memory source module", &module.source_module_sha256)?;
+        parse_sha256("linear-memory sealed module", &module.module_sha256)?;
+        ensure!(
+            module.initial_pages <= u64::from(LINEAR_MEMORY_MAXIMUM_PAGES)
+                && module.maximum_pages == u64::from(LINEAR_MEMORY_MAXIMUM_PAGES)
+                && module.maximum_bytes == LINEAR_MEMORY_MAXIMUM_BYTES
+                && module.shared
+                && module.import_module == "env"
+                && module.import_name == "memory"
+                && module.transformation == SEALED_MODULE_TRANSFORMATION_ID,
+            "linear-memory install module '{}' has a noncanonical contract",
+            module.path
+        );
+    }
+    ensure!(
+        linear_memory_closure_sha256(&receipt.modules, "source-module-sha256")
+            == receipt.source_module_closure_sha256
+            && linear_memory_closure_sha256(&receipt.modules, "module-sha256")
+                == receipt.module_closure_sha256,
+        "linear-memory install receipt closure hash mismatch"
+    );
+    validate_sealed_export_predecessor(carrier_root, &receipt)?;
+
+    for artifact in &manifest.artifacts {
+        let module = receipt
+            .modules
+            .iter()
+            .find(|module| module.path == artifact.module_path)
+            .with_context(|| {
+                format!(
+                    "linear-memory install receipt has no record for '{}'",
+                    artifact.module_path
+                )
+            })?;
+        ensure!(
+            artifact.linear_memory.profile_id == profile.id
+                && artifact.linear_memory.install_receipt_sha256 == profile.install_receipt_sha256
+                && artifact.linear_memory.source_module_sha256 == module.source_module_sha256
+                && artifact
+                    .module_sha256
+                    .eq_ignore_ascii_case(&module.module_sha256),
+            "sealed artifact '{}' linear-memory binding differs from install receipt",
+            artifact.name
+        );
+    }
+    Ok(())
+}
+
+fn read_manifest(manifest_path: &Path) -> Result {
+    let manifest_bytes = read_small_regular_file(manifest_path, MAX_MANIFEST_BYTES)
+        .with_context(|| format!("read sealed manifest {}", manifest_path.display()))?;
+    serde_json::from_slice(&manifest_bytes)
+        .with_context(|| format!("parse sealed manifest {}", manifest_path.display()))
+}
+
+fn has_exact_wasix_postmaster_identity(manifest: &SealedManifest) -> bool {
+    if manifest.format_version != MANIFEST_FORMAT_VERSION
+        || manifest.schema != MANIFEST_SCHEMA
+        || manifest.source_lane != WASIX_POSTMASTER_SOURCE_LANE
+        || !matches!(manifest.core_profile.as_str(), "release-o3" | "safe-o2")
+        || parse_sha256(
+            "guest-build-recipe-sha256",
+            &manifest.guest_build_recipe_sha256,
+        )
+        .is_err()
+        || validate_linear_memory_profile(&manifest.linear_memory_profile).is_err()
+        || manifest.entrypoint != WASIX_POSTMASTER_ENTRYPOINT
+        || manifest.wasm_features.len() != EXPECTED_WASM_FEATURES.len()
+        || EXPECTED_WASM_FEATURES.iter().any(|expected| {
+            !manifest
+                .wasm_features
+                .iter()
+                .any(|actual| actual == expected)
+        })
+        || manifest.artifacts.len()
+            != EXPECTED_WASIX_POSTMASTER_EXECUTABLES.len() + SEALED_EXPORT_SIDE_PATHS.len()
+    {
+        return false;
+    }
+
+    let mut names = HashSet::new();
+    let mut module_paths = HashSet::new();
+    let mut artifact_paths = HashSet::new();
+    for (index, artifact) in manifest.artifacts.iter().enumerate() {
+        let (kind, module_path, exec_aliases, _executable) =
+            if let Some(expected) = EXPECTED_WASIX_POSTMASTER_EXECUTABLES.get(index) {
+                (
+                    expected.kind,
+                    expected.module_path,
+                    expected.exec_aliases,
+                    expected.executable,
+                )
+            } else {
+                let side_index = index - EXPECTED_WASIX_POSTMASTER_EXECUTABLES.len();
+                (
+                    "side-module",
+                    SEALED_EXPORT_SIDE_PATHS[side_index],
+                    &[] as &[&str],
+                    None,
+                )
+            };
+        let expected_name = format!(
+            "runtime:{}",
+            module_path
+                .rsplit_once('/')
+                .map_or(module_path, |(_, basename)| basename)
+        );
+        let expected_aliases = exec_aliases.iter().copied();
+        let module_digest_is_valid = parse_sha256("module-sha256", &artifact.module_sha256).is_ok();
+        let expected_artifact_path =
+            format!("aot/{}.bin", artifact.module_sha256.to_ascii_uppercase());
+        if artifact.name != expected_name
+            || artifact.kind != kind
+            || artifact.module_path != module_path
+            || artifact
+                .exec_aliases
+                .iter()
+                .map(String::as_str)
+                .ne(expected_aliases)
+            || artifact.compressed
+            || artifact.linear_memory.profile_id != manifest.linear_memory_profile.id
+            || artifact.linear_memory.install_receipt_sha256
+                != manifest.linear_memory_profile.install_receipt_sha256
+            || parse_sha256(
+                "linear-memory-source-module-sha256",
+                &artifact.linear_memory.source_module_sha256,
+            )
+            .is_err()
+            || !module_digest_is_valid
+            || artifact.path != expected_artifact_path
+            || !names.insert(artifact.name.as_str())
+            || !module_paths.insert(artifact.module_path.as_str())
+            || !artifact_paths.insert(artifact.path.as_str())
+        {
+            return false;
+        }
+    }
+    true
+}
+
+/// Activate only the selected AOT entrypoint and retain the remaining exact closure lazily.
+pub fn load(
+    prepared: PreparedSealedManifest,
+    engine: &Engine,
+) -> Result {
+    let PreparedSealedManifest {
+        manifest,
+        carrier_root,
+        input_path,
+        input_canonical,
+        runtime_identity: _,
+    } = prepared;
+    validate_manifest_identity(&manifest, engine)?;
+    let activation_policy = SealedActivationPolicy::from_environment()?;
+    audit_executor_trust_boundary(&manifest);
+
+    ensure!(
+        !manifest.artifacts.is_empty(),
+        "sealed manifest has no artifacts"
+    );
+    let mut names = HashSet::new();
+    let mut aliases = HashMap::::new();
+    let mut artifact_paths = HashSet::new();
+    let mut module_paths = HashSet::new();
+    let mut executables = Vec::new();
+    let mut artifacts = HashMap::new();
+    let mut declared_entrypoint = false;
+    let mut selected: Option = None;
+    let input_name = input_path.to_string_lossy();
+
+    for artifact in &manifest.artifacts {
+        ensure!(
+            names.insert(artifact.name.as_str()),
+            "sealed manifest contains duplicate artifact name '{}'",
+            artifact.name
+        );
+        ensure!(
+            matches!(artifact.kind.as_str(), "executable" | "side-module"),
+            "sealed artifact '{}' has unsupported kind '{}'",
+            artifact.name,
+            artifact.kind
+        );
+        ensure!(
+            !artifact.compressed,
+            "sealed artifact '{}' must be an uncompressed, directly mappable AOT file",
+            artifact.name
+        );
+        ensure!(
+            artifact.sha256.eq_ignore_ascii_case(&artifact.raw_sha256),
+            "sealed artifact '{}' must use the same packaged and raw digest when uncompressed",
+            artifact.name
+        );
+        if artifact.kind == "executable" {
+            ensure!(
+                !artifact.exec_aliases.is_empty(),
+                "sealed executable '{}' has no aliases",
+                artifact.name
+            );
+        } else {
+            ensure!(
+                artifact.exec_aliases.is_empty(),
+                "sealed side module '{}' must not declare executable aliases",
+                artifact.name
+            );
+        }
+
+        let module_path = carrier_file_path(&carrier_root, &artifact.module_path)?;
+        ensure!(
+            module_paths.insert(module_path.clone()),
+            "sealed manifest contains duplicate module path '{}'",
+            artifact.module_path
+        );
+        // Raw module bytes do not authorize execution. Executables resolve
+        // directly to the manifest hash, and guest-loaded side modules are
+        // hashed by the loader before the authoritative cache lookup. A
+        // changed raw module therefore resolves to NotFound. Avoid faulting
+        // every inactive raw module into the cold-start cgroup here; validate
+        // only its path/type/size and derive the admitted key from the strict
+        // manifest. The AOT activation independently hashes its immutable
+        // snapshot and checks the archive's embedded module hash.
+        let raw_module = open_regular(&module_path)?;
+        let raw_module_size = raw_module.metadata()?.len();
+        ensure!(
+            raw_module_size == artifact.module_size,
+            "size mismatch for {}: manifest={} actual={}",
+            module_path.display(),
+            artifact.module_size,
+            raw_module_size
+        );
+        let module_digest = parse_sha256("module-sha256", &artifact.module_sha256)?;
+        let module_hash = ModuleHash::from_bytes(module_digest);
+        tracing::debug!(
+            target: "wasmer_cli::sealed_loader_audit",
+            audit_schema = "oliphaunt.wasix-postmaster.sealed-loader-audit.v1",
+            artifact_name = artifact.name.as_str(),
+            artifact_kind = "raw-module",
+            module_sha256 = %module_hash,
+            activation_state = "inactive",
+            snapshot_mode = "metadata-only-authoritative-on-use",
+            logical_bytes = artifact.module_size,
+            source_bytes_read = 0_u64,
+            snapshot_bytes_written = 0_u64,
+            mapping_bytes_hashed = 0_u64,
+            sync_calls = 0_u64,
+            write_policy = "none",
+            "prepared sealed raw module identity"
+        );
+        drop(raw_module);
+
+        let artifact_path = carrier_file_path(&carrier_root, &artifact.path)?;
+        ensure!(
+            artifact_paths.insert(artifact_path.clone()),
+            "sealed manifest contains duplicate AOT artifact path '{}'",
+            artifact.path
+        );
+        ensure!(
+            !artifacts.contains_key(&module_hash),
+            "sealed manifest contains duplicate module hash {module_hash} for '{}'",
+            artifact.name
+        );
+        ensure!(
+            usize::try_from(artifact.raw_size).is_ok(),
+            "AOT artifact '{}' is too large to map on this host",
+            artifact.name
+        );
+        let artifact_source = open_regular(&artifact_path)?;
+        ensure!(
+            artifact_source.metadata()?.len() == artifact.raw_size,
+            "size mismatch for {}: manifest={} actual={}",
+            artifact_path.display(),
+            artifact.raw_size,
+            artifact_source.metadata()?.len()
+        );
+        let expected_artifact_digest = parse_sha256("raw-sha256", &artifact.raw_sha256)?;
+        tracing::debug!(
+            target: "wasmer_cli::sealed_loader_audit",
+            audit_schema = "oliphaunt.wasix-postmaster.sealed-loader-audit.v1",
+            artifact_name = artifact.name.as_str(),
+            artifact_kind = "aot",
+            module_sha256 = %module_hash,
+            activation_state = "inactive",
+            snapshot_mode = "deferred-open-fd",
+            logical_bytes = artifact.raw_size,
+            source_bytes_read = 0_u64,
+            snapshot_bytes_written = 0_u64,
+            mapping_bytes_hashed = 0_u64,
+            sync_calls = 0_u64,
+            write_policy = "none",
+            "prepared sealed artifact descriptor"
+        );
+
+        let input_matches = artifact.kind == "executable" && module_path == input_canonical;
+        if artifact.kind == "executable" {
+            let carrier_exec_path = module_path.to_string_lossy().into_owned();
+            ensure!(
+                aliases
+                    .insert(carrier_exec_path.clone(), module_hash)
+                    .is_none(),
+                "sealed manifest contains duplicate executable alias '{carrier_exec_path}'"
+            );
+            executables.push((carrier_exec_path, module_hash));
+        }
+        for alias in &artifact.exec_aliases {
+            validate_guest_alias(alias)?;
+            ensure!(
+                aliases.insert(alias.clone(), module_hash).is_none(),
+                "sealed manifest contains duplicate executable alias '{alias}'"
+            );
+            executables.push((alias.clone(), module_hash));
+        }
+
+        // The host input path selects an executable by its carrier-relative
+        // module-path. Guest aliases remain Unix-style WASIX paths and are not
+        // overloaded with host path syntax, which keeps the manifest portable
+        // across Linux, macOS, and Windows hosts. Register the exact argv[0]
+        // spelling as well so an EXEC_BACKEND using that path remains sealed.
+        if input_matches {
+            match aliases.get(input_name.as_ref()) {
+                Some(existing_hash) => ensure!(
+                    *existing_hash == module_hash,
+                    "selected executable spelling '{}' belongs to a different sealed artifact",
+                    input_name
+                ),
+                None => {
+                    aliases.insert(input_name.to_string(), module_hash);
+                    executables.push((input_name.to_string(), module_hash));
+                }
+            }
+        }
+
+        artifacts.insert(
+            module_hash,
+            Arc::new(LazySealedArtifact::new(
+                module_hash,
+                expected_artifact_digest,
+                SealedArtifactSource {
+                    file: artifact_source,
+                    path: artifact_path,
+                    carrier_root: carrier_root.clone(),
+                    expected_size: artifact.raw_size,
+                },
+                activation_policy,
+            )),
+        );
+
+        if artifact.name == manifest.entrypoint {
+            ensure!(
+                artifact.kind == "executable",
+                "sealed manifest entrypoint '{}' is not executable",
+                manifest.entrypoint
+            );
+            declared_entrypoint = true;
+        }
+
+        if input_matches {
+            ensure!(
+                selected.is_none(),
+                "input '{}' matches more than one sealed executable",
+                input_path.display()
+            );
+            selected = Some(module_hash);
+        }
+    }
+
+    ensure!(
+        declared_entrypoint,
+        "sealed manifest entrypoint '{}' is not present in artifacts",
+        manifest.entrypoint
+    );
+    let module_hash = selected.with_context(|| {
+        format!(
+            "input '{}' is not an alias of any sealed executable",
+            input_path.display()
+        )
+    })?;
+    let module_cache = Arc::new(SealedModuleCache::new(engine, artifacts));
+    // The selected executable is the only artifact activated at startup. All
+    // remaining executable and side-module descriptors stay file-backed and
+    // cold until an exact alias/hash lookup reaches the authoritative cache.
+    let module = module_cache
+        .load_exact(module_hash, engine)
+        .with_context(|| format!("activate selected sealed executable {module_hash}"))?;
+
+    Ok(LoadedSealedModules {
+        module,
+        module_hash,
+        path: input_path.clone(),
+        executables,
+        module_cache,
+    })
+}
+
+fn validate_manifest_identity(manifest: &SealedManifest, engine: &Engine) -> Result<(), Error> {
+    ensure!(
+        manifest.format_version == MANIFEST_FORMAT_VERSION,
+        "sealed manifest format mismatch: manifest={} runtime={MANIFEST_FORMAT_VERSION}",
+        manifest.format_version
+    );
+    ensure!(
+        manifest.schema == MANIFEST_SCHEMA,
+        "sealed manifest schema mismatch: manifest={} runtime={MANIFEST_SCHEMA}",
+        manifest.schema
+    );
+    ensure!(
+        manifest.source_lane == "wasix-postmaster",
+        "sealed manifest source lane must be 'wasix-postmaster'"
+    );
+    ensure_nonempty("source-fingerprint", &manifest.source_fingerprint)?;
+    ensure!(
+        matches!(manifest.core_profile.as_str(), "release-o3" | "safe-o2"),
+        "sealed manifest core-profile must be release-o3 candidate or safe-o2 control"
+    );
+    ensure_nonempty("postgres-version", &manifest.postgres_version)?;
+    ensure_nonempty("host-abi", &manifest.host_abi)?;
+    ensure!(
+        manifest.target_triple == Target::default().triple().to_string(),
+        "sealed manifest target mismatch: manifest={} runtime={}",
+        manifest.target_triple,
+        Target::default().triple()
+    );
+    ensure!(
+        manifest.engine == "llvm-opta",
+        "sealed manifest producer engine must be 'llvm-opta'"
+    );
+    ensure_nonempty("compiler-config", &manifest.compiler_config)?;
+    ensure!(
+        manifest.cpu_policy == "generic-baseline" && manifest.cpu_features.is_empty(),
+        "sealed manifest currently requires generic-baseline CPU policy with no host-specific features"
+    );
+    ensure!(
+        manifest.wasmer_version == env!("CARGO_PKG_VERSION"),
+        "sealed manifest Wasmer version mismatch: manifest={} runtime={}",
+        manifest.wasmer_version,
+        env!("CARGO_PKG_VERSION")
+    );
+    ensure!(
+        manifest.wasmer_wasix_version == wasmer_wasix::VERSION,
+        "sealed manifest wasmer-wasix version mismatch: manifest={} runtime={}",
+        manifest.wasmer_wasix_version,
+        wasmer_wasix::VERSION
+    );
+    ensure!(
+        manifest.artifact_abi_version == ARTIFACT_ABI_VERSION,
+        "sealed manifest artifact ABI mismatch: manifest={} runtime={ARTIFACT_ABI_VERSION}",
+        manifest.artifact_abi_version
+    );
+    let runtime_abi_id = option_env!("OLIPHAUNT_WASIX_RUNTIME_ABI_ID").context(
+        "this headless executor was not built with OLIPHAUNT_WASIX_RUNTIME_ABI_ID and cannot load sealed carriers",
+    )?;
+    ensure!(
+        manifest.runtime_abi_id.eq_ignore_ascii_case(runtime_abi_id),
+        "sealed manifest runtime ABI mismatch: manifest={} runtime={runtime_abi_id}",
+        manifest.runtime_abi_id
+    );
+    ensure!(
+        engine.deterministic_id() == manifest.executor_engine,
+        "sealed manifest executor mismatch: manifest={} runtime={}",
+        manifest.executor_engine,
+        engine.deterministic_id()
+    );
+    ensure!(
+        manifest.executor_engine == "engine-headless",
+        "sealed modules require the compiler-free headless executor"
+    );
+    validate_linear_memory_profile(&manifest.linear_memory_profile)?;
+
+    validate_git_sha1("wasmer-source-commit", &manifest.wasmer_source_commit)?;
+    for (field, value) in [
+        ("wasmer-patch-sha256", manifest.wasmer_patch_sha256.as_str()),
+        (
+            "wasmer-cargo-lock-sha256",
+            manifest.wasmer_cargo_lock_sha256.as_str(),
+        ),
+        (
+            "producer-recipe-sha256",
+            manifest.producer_recipe_sha256.as_str(),
+        ),
+        (
+            "guest-build-recipe-sha256",
+            manifest.guest_build_recipe_sha256.as_str(),
+        ),
+        ("runtime-abi-id", manifest.runtime_abi_id.as_str()),
+        ("executor-sha256", manifest.executor_sha256.as_str()),
+    ] {
+        parse_sha256(field, value)?;
+    }
+    ensure!(
+        manifest.executor_size > 0,
+        "sealed manifest executor-size must be positive"
+    );
+    let mut features = BTreeSet::new();
+    for feature in &manifest.wasm_features {
+        ensure!(
+            features.insert(feature.as_str()),
+            "sealed manifest contains duplicate Wasm feature '{feature}'"
+        );
+    }
+    for expected in EXPECTED_WASM_FEATURES {
+        ensure!(
+            features.contains(expected),
+            "sealed manifest is missing required Wasm feature '{expected}'"
+        );
+    }
+    ensure!(
+        features.len() == EXPECTED_WASM_FEATURES.len(),
+        "sealed manifest Wasm feature set must be exact: expected={:?} actual={:?}",
+        EXPECTED_WASM_FEATURES,
+        features
+    );
+    Ok(())
+}
+
+fn audit_executor_trust_boundary(manifest: &SealedManifest) {
+    // The executor digest comes from the same manifest and therefore cannot
+    // authenticate that manifest or the running executable. The carrier's
+    // external verifier/install boundary binds these bytes; compile-time ABI
+    // and deterministic engine checks above enforce runtime compatibility.
+    // Re-reading /proc/self/exe here would fault the whole executor into the
+    // embedded cgroup without adding a cryptographic trust anchor.
+    tracing::debug!(
+        target: "wasmer_cli::sealed_loader_audit",
+        audit_schema = "oliphaunt.wasix-postmaster.sealed-loader-audit.v1",
+        artifact_kind = "headless-executor",
+        activation_state = "external-verifier-trust-boundary",
+        snapshot_mode = "metadata-only-no-runtime-read",
+        logical_bytes = manifest.executor_size,
+        source_bytes_read = 0_u64,
+        source_bytes_written = 0_u64,
+        snapshot_bytes_written = 0_u64,
+        mapping_bytes_hashed = 0_u64,
+        sync_calls = 0_u64,
+        write_policy = "none",
+        trust_binding = "external-carrier-verifier-plus-compile-time-runtime-abi",
+        "accepted externally verified headless executor identity"
+    );
+}
+
+fn read_small_regular_file(path: &Path, max_size: u64) -> Result, Error> {
+    let file = open_regular(path)?;
+    let len = file.metadata()?.len();
+    ensure!(len <= max_size, "file exceeds {max_size} byte limit");
+    let read_limit = max_size
+        .checked_add(1)
+        .context("small regular file limit overflow")?;
+    let capacity = usize::try_from(len.min(read_limit))
+        .context("small regular file exceeds host address width")?;
+    let mut bytes = Vec::with_capacity(capacity);
+    file.take(read_limit).read_to_end(&mut bytes)?;
+    ensure!(
+        u64::try_from(bytes.len())
+            .ok()
+            .is_some_and(|len| len <= max_size),
+        "file grew beyond {max_size} byte limit while being read"
+    );
+    Ok(bytes)
+}
+
+fn immutable_artifact_snapshot(
+    source: SealedArtifactSource,
+    policy: SealedActivationPolicy,
+) -> Result {
+    let expected_size = source.expected_size;
+    ensure!(
+        usize::try_from(expected_size).is_ok(),
+        "AOT artifact is too large to map on this host"
+    );
+    let metadata = source.file.metadata()?;
+    ensure!(
+        metadata.len() == expected_size,
+        "size mismatch for {}: manifest={} actual={}",
+        source.path.display(),
+        expected_size,
+        metadata.len()
+    );
+
+    #[cfg(windows)]
+    bail!(
+        "sealed AOT activation is disabled on Windows until a pathless, deny-write snapshot lifecycle is implemented"
+    );
+
+    #[cfg(target_os = "linux")]
+    if let Ok(snapshot) = direct_immutable_artifact_snapshot(&source) {
+        return Ok(snapshot);
+    }
+
+    if policy.requires_direct_immutable() {
+        bail!(
+            "{REQUIRE_ZERO_WRITE_AOT_ENV}=1 requires direct activation from a SquashFS/EROFS or immutable-inode AOT source; refusing reflink and streamed-copy compatibility modes for {}",
+            source.path.display()
+        );
+    }
+
+    #[cfg(target_os = "linux")]
+    if let Ok(snapshot) = reflink_artifact_snapshot(&source) {
+        return Ok(snapshot);
+    }
+
+    streamed_artifact_snapshot(source)
+}
+
+#[cfg(target_os = "linux")]
+fn direct_immutable_artifact_snapshot(
+    source: &SealedArtifactSource,
+) -> Result {
+    let immutable = intrinsic_file_immutability(&source.file).map_err(Error::msg)?;
+    direct_artifact_snapshot_from_proof(source, immutable)
+}
+
+#[cfg(target_os = "linux")]
+fn direct_artifact_snapshot_from_proof(
+    source: &SealedArtifactSource,
+    immutable: IntrinsicFileImmutability,
+) -> Result {
+    let file = source
+        .file
+        .try_clone()
+        .context("duplicate direct immutable AOT descriptor")?;
+    ensure!(
+        file.metadata()?.len() == source.expected_size,
+        "direct immutable AOT artifact changed size"
+    );
+    Ok(ImmutableArtifactSnapshot {
+        file,
+        source_file: None,
+        len: source.expected_size,
+        audit: ArtifactSnapshotAudit {
+            mode: ArtifactSnapshotMode::DirectIntrinsic(immutable),
+            logical_bytes: source.expected_size,
+            // The digest walks the source-backed mapping exactly once.
+            source_bytes_read: source.expected_size,
+            snapshot_bytes_written: 0,
+            mapping_bytes_hashed: source.expected_size,
+            sync_calls: 0,
+        },
+    })
+}
+
+fn streamed_artifact_snapshot(
+    mut source: SealedArtifactSource,
+) -> Result {
+    let expected_size = source.expected_size;
+    let mut snapshot = create_disk_backed_snapshot_file(&source.carrier_root)?;
+    let mut copied = 0_u64;
+    let mut buffer = [0_u8; 128 * 1024];
+    loop {
+        let count = source.file.read(&mut buffer)?;
+        if count == 0 {
+            break;
+        }
+        copied = copied
+            .checked_add(count as u64)
+            .context("AOT artifact size overflow while creating immutable snapshot")?;
+        ensure!(
+            copied <= expected_size,
+            "size mismatch for {}: manifest={} actual exceeds manifest size",
+            source.path.display(),
+            expected_size
+        );
+        snapshot.file_mut().write_all(&buffer[..count])?;
+    }
+    ensure!(
+        copied == expected_size,
+        "size mismatch for {}: manifest={} copied={copied}",
+        source.path.display(),
+        expected_size
+    );
+    let mut finalized = snapshot.finalize(
+        expected_size,
+        ArtifactSnapshotAudit {
+            mode: ArtifactSnapshotMode::StreamedCopy,
+            logical_bytes: expected_size,
+            source_bytes_read: copied,
+            snapshot_bytes_written: copied,
+            mapping_bytes_hashed: expected_size,
+            sync_calls: 0,
+        },
+    )?;
+    finalized.source_file = Some(source.file);
+    Ok(finalized)
+}
+
+#[cfg(target_os = "linux")]
+fn reflink_artifact_snapshot(
+    source: &SealedArtifactSource,
+) -> Result {
+    use std::os::fd::AsRawFd;
+
+    let mut candidates = vec![
+        source
+            .path
+            .parent()
+            .context("sealed AOT artifact must have a parent directory")?
+            .to_path_buf(),
+    ];
+    candidates.extend(artifact_snapshot_directories(&source.carrier_root));
+    let mut seen = HashSet::new();
+    let mut failures = Vec::new();
+    for directory in candidates {
+        if !seen.insert(directory.clone()) || !directory.is_dir() {
+            continue;
+        }
+        let attempt = (|| -> Result<_, Error> {
+            let destination = create_anonymous_snapshot_file(&directory)?;
+            // SAFETY: both descriptors remain live for the ioctl. FICLONE
+            // creates a copy-on-write clone and does not share later writes.
+            // The kernel also rejects a destination on a different filesystem.
+            let result = unsafe {
+                libc::ioctl(
+                    destination.as_raw_fd(),
+                    libc::FICLONE,
+                    source.file.as_raw_fd(),
+                )
+            };
+            if result != 0 {
+                return Err(std::io::Error::last_os_error()).context("reflink sealed AOT artifact");
+            }
+            ensure!(
+                destination.metadata()?.len() == source.expected_size,
+                "reflinked AOT artifact size mismatch"
+            );
+            let mut snapshot = WritableArtifactSnapshot::Anonymous(destination).finalize(
+                source.expected_size,
+                ArtifactSnapshotAudit {
+                    mode: ArtifactSnapshotMode::Reflink,
+                    logical_bytes: source.expected_size,
+                    source_bytes_read: 0,
+                    snapshot_bytes_written: 0,
+                    mapping_bytes_hashed: source.expected_size,
+                    sync_calls: 0,
+                },
+            )?;
+            snapshot.source_file = Some(
+                source
+                    .file
+                    .try_clone()
+                    .context("duplicate reflink AOT source descriptor")?,
+            );
+            Ok(snapshot)
+        })();
+        match attempt {
+            Ok(snapshot) => return Ok(snapshot),
+            Err(error) => failures.push(format!("{}: {error:#}", directory.display())),
+        }
+    }
+    bail!(
+        "no writable same-filesystem O_TMPFILE destination accepted FICLONE{}",
+        if failures.is_empty() {
+            String::new()
+        } else {
+            format!(": {}", failures.join("; "))
+        }
+    )
+}
+
+fn artifact_snapshot_directories(carrier_root: &Path) -> Vec {
+    let mut candidates = Vec::new();
+    if let Some(explicit) = std::env::var_os("OLIPHAUNT_WASIX_ARTIFACT_SNAPSHOT_DIR") {
+        candidates.push(PathBuf::from(explicit));
+    }
+    candidates.push(carrier_root.to_path_buf());
+    #[cfg(unix)]
+    candidates.push(PathBuf::from("/var/tmp"));
+    candidates.push(std::env::temp_dir());
+    #[cfg(feature = "compat-cache-dir")]
+    {
+        if let Some(cache_dir) = dirs::cache_dir() {
+            candidates.push(cache_dir);
+        }
+    }
+    candidates
+}
+
+fn create_disk_backed_snapshot_file(
+    carrier_root: &Path,
+) -> Result {
+    let mut seen = HashSet::new();
+    let mut failures = Vec::new();
+    for candidate in artifact_snapshot_directories(carrier_root) {
+        if !seen.insert(candidate.clone()) || !candidate.is_dir() {
+            continue;
+        }
+        #[cfg(target_os = "linux")]
+        match create_anonymous_snapshot_file(&candidate) {
+            Ok(file) => return Ok(WritableArtifactSnapshot::Anonymous(file)),
+            Err(error) => failures.push(format!("{} (O_TMPFILE): {error:#}", candidate.display())),
+        }
+        let attempt = (|| -> Result<_, Error> {
+            let temp_dir = tempfile::Builder::new()
+                .prefix(".wasmer-sealed-aot-")
+                .tempdir_in(&candidate)
+                .with_context(|| {
+                    format!(
+                        "create private snapshot directory in {}",
+                        candidate.display()
+                    )
+                })?;
+            #[cfg(unix)]
+            {
+                use std::os::unix::fs::PermissionsExt;
+                fs::set_permissions(temp_dir.path(), fs::Permissions::from_mode(0o700))?;
+            }
+            let snapshot = tempfile::Builder::new()
+                .prefix("artifact-")
+                .tempfile_in(temp_dir.path())
+                .context("create private snapshot file")?;
+            ensure_disk_backed(snapshot.as_file())?;
+            Ok(WritableArtifactSnapshot::Named {
+                temp_dir,
+                file: snapshot,
+            })
+        })();
+        match attempt {
+            Ok(snapshot) => return Ok(snapshot),
+            Err(error) => failures.push(format!("{}: {error:#}", candidate.display())),
+        }
+    }
+
+    bail!(
+        "unable to create a private disk-backed AOT snapshot{}",
+        if failures.is_empty() {
+            String::new()
+        } else {
+            format!(": {}", failures.join("; "))
+        }
+    )
+}
+
+#[cfg(target_os = "linux")]
+fn create_anonymous_snapshot_file(directory: &Path) -> Result {
+    use std::os::unix::fs::OpenOptionsExt;
+
+    let mut options = OpenOptions::new();
+    options
+        .read(true)
+        .write(true)
+        .mode(0o600)
+        .custom_flags(libc::O_TMPFILE | libc::O_CLOEXEC);
+    let file = options
+        .open(directory)
+        .with_context(|| format!("create anonymous snapshot in {}", directory.display()))?;
+    ensure_disk_backed(&file)?;
+
+    // Verify up front that this host exposes a safe way to downgrade the
+    // anonymous inode to a read-only descriptor after the copy. If /proc is
+    // unavailable, the caller will use the private named/unlink fallback.
+    let probe = reopen_anonymous_snapshot_read_only(&file)?;
+    verify_same_unix_file(&file, &probe)?;
+    Ok(file)
+}
+
+#[cfg(target_os = "linux")]
+fn reopen_anonymous_snapshot_read_only(file: &File) -> Result {
+    use std::os::{fd::AsRawFd, unix::fs::OpenOptionsExt};
+
+    let descriptor_path = PathBuf::from(format!("/proc/self/fd/{}", file.as_raw_fd()));
+    let mut options = OpenOptions::new();
+    options.read(true).custom_flags(libc::O_CLOEXEC);
+    options.open(&descriptor_path).with_context(|| {
+        format!(
+            "reopen anonymous snapshot via {}",
+            descriptor_path.display()
+        )
+    })
+}
+
+#[cfg(target_os = "linux")]
+fn verify_same_unix_file(first: &File, second: &File) -> Result<(), Error> {
+    use std::os::unix::fs::MetadataExt;
+
+    let first = first.metadata()?;
+    let second = second.metadata()?;
+    ensure!(
+        first.dev() == second.dev() && first.ino() == second.ino(),
+        "private snapshot changed identity while being sealed"
+    );
+    Ok(())
+}
+
+#[cfg(target_os = "linux")]
+fn ensure_disk_backed(file: &File) -> Result<(), Error> {
+    use std::os::fd::AsRawFd;
+
+    let mut stat = std::mem::MaybeUninit::::uninit();
+    // SAFETY: `stat` points to writable storage and the file descriptor remains
+    // open for the duration of the call.
+    let result = unsafe { libc::fstatfs(file.as_raw_fd(), stat.as_mut_ptr()) };
+    if result != 0 {
+        return Err(std::io::Error::last_os_error()).context("identify snapshot filesystem");
+    }
+    // SAFETY: a successful fstatfs initialized the structure.
+    let filesystem_type = unsafe { stat.assume_init() }.f_type as u64;
+    const TMPFS_MAGIC: u64 = 0x0102_1994;
+    const RAMFS_MAGIC: u64 = 0x8584_58f6;
+    const HUGETLBFS_MAGIC: u64 = 0x9584_58f6;
+    ensure!(
+        !matches!(filesystem_type, TMPFS_MAGIC | RAMFS_MAGIC | HUGETLBFS_MAGIC),
+        "snapshot filesystem is memory-backed (type 0x{filesystem_type:x})"
+    );
+    Ok(())
+}
+
+#[cfg(not(target_os = "linux"))]
+fn ensure_disk_backed(_file: &File) -> Result<(), Error> {
+    Ok(())
+}
+
+#[cfg(target_os = "linux")]
+fn finalize_anonymous_snapshot(
+    snapshot: File,
+    expected_size: u64,
+    audit: ArtifactSnapshotAudit,
+) -> Result {
+    use std::os::unix::fs::{MetadataExt, PermissionsExt};
+
+    snapshot.set_permissions(fs::Permissions::from_mode(0o400))?;
+    let read_only = reopen_anonymous_snapshot_read_only(&snapshot)?;
+    verify_same_unix_file(&snapshot, &read_only)?;
+    ensure!(
+        read_only.metadata()?.len() == expected_size,
+        "anonymous snapshot changed size while being sealed"
+    );
+    ensure!(
+        read_only.metadata()?.nlink() == 0,
+        "anonymous snapshot unexpectedly acquired a filesystem path"
+    );
+    drop(snapshot);
+    advise_file_away(&read_only);
+    Ok(ImmutableArtifactSnapshot {
+        file: read_only,
+        source_file: None,
+        len: expected_size,
+        audit,
+    })
+}
+
+#[cfg(unix)]
+fn finalize_named_snapshot(
+    temp_dir: tempfile::TempDir,
+    snapshot: tempfile::NamedTempFile,
+    expected_size: u64,
+    audit: ArtifactSnapshotAudit,
+) -> Result {
+    use std::os::unix::fs::{MetadataExt, OpenOptionsExt, PermissionsExt};
+
+    snapshot
+        .as_file()
+        .set_permissions(fs::Permissions::from_mode(0o400))?;
+    let writer_metadata = snapshot.as_file().metadata()?;
+    let path = snapshot.path().to_path_buf();
+    let mut options = OpenOptions::new();
+    options
+        .read(true)
+        .custom_flags(libc::O_CLOEXEC | libc::O_NOFOLLOW);
+    let read_only = options
+        .open(&path)
+        .with_context(|| format!("reopen immutable snapshot {} read-only", path.display()))?;
+    let reader_metadata = read_only.metadata()?;
+    ensure!(
+        writer_metadata.dev() == reader_metadata.dev()
+            && writer_metadata.ino() == reader_metadata.ino(),
+        "private snapshot changed identity while being sealed"
+    );
+    ensure!(
+        reader_metadata.len() == expected_size,
+        "private snapshot changed size while being sealed"
+    );
+
+    fs::remove_file(&path)
+        .with_context(|| format!("unlink immutable snapshot {}", path.display()))?;
+    drop(snapshot);
+    drop(temp_dir);
+
+    #[cfg(target_os = "linux")]
+    ensure!(
+        read_only.metadata()?.nlink() == 0,
+        "immutable snapshot remained reachable by a filesystem path"
+    );
+    advise_file_away(&read_only);
+    Ok(ImmutableArtifactSnapshot {
+        file: read_only,
+        source_file: None,
+        len: expected_size,
+        audit,
+    })
+}
+
+#[cfg(windows)]
+fn finalize_named_snapshot(
+    _temp_dir: tempfile::TempDir,
+    _snapshot: tempfile::NamedTempFile,
+    _expected_size: u64,
+    _audit: ArtifactSnapshotAudit,
+) -> Result {
+    bail!(
+        "Windows named-temp AOT snapshots are disabled: the prior close/reopen lifecycle could delete the path before establishing the final deny-write handle"
+    )
+}
+
+#[cfg(not(any(unix, windows)))]
+fn finalize_named_snapshot(
+    _temp_dir: tempfile::TempDir,
+    _snapshot: tempfile::NamedTempFile,
+    _expected_size: u64,
+    _audit: ArtifactSnapshotAudit,
+) -> Result {
+    bail!("immutable sealed AOT snapshots are not implemented on this host")
+}
+
+fn open_regular(path: &Path) -> Result {
+    let mut options = OpenOptions::new();
+    options.read(true);
+    #[cfg(unix)]
+    {
+        use std::os::unix::fs::OpenOptionsExt;
+        options.custom_flags(libc::O_CLOEXEC | libc::O_NOFOLLOW);
+    }
+    #[cfg(windows)]
+    {
+        use std::os::windows::fs::OpenOptionsExt;
+        use windows_sys::Win32::Storage::FileSystem::FILE_SHARE_READ;
+        // Keep the exact carrier inode stable for the duration of validation:
+        // other handles may read it, but cannot obtain write/delete sharing.
+        options.share_mode(FILE_SHARE_READ);
+    }
+    let file = options
+        .open(path)
+        .with_context(|| format!("open regular file {}", path.display()))?;
+    ensure!(
+        file.metadata()?.is_file(),
+        "carrier path is not a regular file: {}",
+        path.display()
+    );
+    Ok(file)
+}
+
+fn carrier_file_path(root: &Path, relative: &str) -> Result {
+    ensure_nonempty("carrier file path", relative)?;
+    let relative_path = Path::new(relative);
+    ensure!(
+        relative_path
+            .components()
+            .all(|component| matches!(component, Component::Normal(_))),
+        "carrier file path must be a normalized relative path: {relative}"
+    );
+    let canonical_root = root
+        .canonicalize()
+        .with_context(|| format!("resolve carrier root {}", root.display()))?;
+    let path = canonical_root.join(relative_path);
+    let canonical = path
+        .canonicalize()
+        .with_context(|| format!("resolve carrier file {}", path.display()))?;
+    ensure!(
+        canonical.starts_with(&canonical_root),
+        "carrier file escapes carrier root: {relative}"
+    );
+    Ok(canonical)
+}
+
+fn validate_guest_alias(alias: &str) -> Result<(), Error> {
+    ensure!(
+        alias.starts_with('/'),
+        "guest executable alias must be absolute: {alias}"
+    );
+    ensure!(
+        !alias.contains('\\')
+            && alias
+                .split('/')
+                .skip(1)
+                .all(|component| !component.is_empty() && component != "." && component != ".."),
+        "guest executable alias must be normalized: {alias}"
+    );
+    Ok(())
+}
+
+fn ensure_nonempty(field: &str, value: &str) -> Result<(), Error> {
+    ensure!(
+        !value.trim().is_empty(),
+        "sealed manifest field '{field}' is empty"
+    );
+    Ok(())
+}
+
+fn parse_sha256(field: &str, value: &str) -> Result<[u8; 32], Error> {
+    ensure!(
+        value.len() == 64,
+        "sealed manifest field '{field}' is not a SHA-256 digest"
+    );
+    let mut digest = [0_u8; 32];
+    hex::decode_to_slice(value, &mut digest)
+        .with_context(|| format!("sealed manifest field '{field}' is not hexadecimal"))?;
+    Ok(digest)
+}
+
+fn validate_git_sha1(field: &str, value: &str) -> Result<(), Error> {
+    ensure!(
+        value.len() == 40,
+        "sealed manifest field '{field}' is not a Git SHA-1"
+    );
+    ensure!(
+        value.bytes().all(|byte| byte.is_ascii_hexdigit()),
+        "sealed manifest field '{field}' is not hexadecimal"
+    );
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn test_artifact(expected: ExpectedWasixPostmasterArtifact, digest_byte: u8) -> SealedArtifact {
+        let module_sha256 = format!("{digest_byte:02x}").repeat(32);
+        let artifact_sha256 = format!("{:02x}", digest_byte.wrapping_add(32)).repeat(32);
+        SealedArtifact {
+            name: format!(
+                "runtime:{}",
+                expected
+                    .module_path
+                    .rsplit_once('/')
+                    .map_or(expected.module_path, |(_, basename)| basename)
+            ),
+            kind: expected.kind.to_string(),
+            path: format!("aot/{}.bin", module_sha256.to_ascii_uppercase()),
+            module_path: expected.module_path.to_string(),
+            sha256: artifact_sha256.clone(),
+            raw_sha256: artifact_sha256,
+            raw_size: 1,
+            module_sha256,
+            module_size: 1,
+            linear_memory: SealedArtifactLinearMemory {
+                profile_id: LINEAR_MEMORY_PROFILE_ID.to_string(),
+                source_module_sha256: format!("{:02x}", digest_byte.wrapping_add(96)).repeat(32),
+                install_receipt_sha256: "8".repeat(64),
+            },
+            compressed: false,
+            exec_aliases: expected
+                .exec_aliases
+                .iter()
+                .map(|alias| (*alias).to_string())
+                .collect(),
+        }
+    }
+
+    fn test_wasix_postmaster_manifest() -> SealedManifest {
+        SealedManifest {
+            format_version: MANIFEST_FORMAT_VERSION,
+            schema: MANIFEST_SCHEMA.to_string(),
+            source_lane: WASIX_POSTMASTER_SOURCE_LANE.to_string(),
+            source_fingerprint: "source-fingerprint".to_string(),
+            core_profile: "release-o3".to_string(),
+            guest_build_recipe_sha256: "7".repeat(64),
+            postgres_version: "18.4".to_string(),
+            target_triple: "test-target".to_string(),
+            host_abi: "test-abi".to_string(),
+            engine: "llvm-opta".to_string(),
+            compiler_config: "test-compiler".to_string(),
+            cpu_policy: "generic-baseline".to_string(),
+            cpu_features: Vec::new(),
+            wasmer_version: "test-wasmer".to_string(),
+            wasmer_wasix_version: "test-wasmer-wasix".to_string(),
+            wasmer_source_commit: "1".repeat(40),
+            wasmer_patch_sha256: "2".repeat(64),
+            wasmer_cargo_lock_sha256: "3".repeat(64),
+            artifact_abi_version: ARTIFACT_ABI_VERSION,
+            runtime_abi_id: "4".repeat(64),
+            producer_recipe_sha256: "5".repeat(64),
+            executor_engine: "engine-headless".to_string(),
+            executor_sha256: "6".repeat(64),
+            executor_size: 1,
+            linear_memory_profile: SealedLinearMemoryProfile {
+                id: LINEAR_MEMORY_PROFILE_ID.to_string(),
+                address_width: "wasm32".to_string(),
+                supported_host_pointer_width: "u64".to_string(),
+                maximum_pages: LINEAR_MEMORY_MAXIMUM_PAGES,
+                maximum_bytes: LINEAR_MEMORY_MAXIMUM_BYTES,
+                static_bound_pages: LINEAR_MEMORY_STATIC_BOUND_PAGES,
+                static_offset_guard_bytes: LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES,
+                static_access_lowering: "wasmer-llvm-unchecked-reservation-and-guard-v1"
+                    .to_string(),
+                install_receipt_path: "receipts/linear-memory-profile.json".to_string(),
+                install_receipt_sha256: "8".repeat(64),
+            },
+            wasm_features: EXPECTED_WASM_FEATURES
+                .iter()
+                .map(|feature| (*feature).to_string())
+                .collect(),
+            entrypoint: WASIX_POSTMASTER_ENTRYPOINT.to_string(),
+            artifacts: EXPECTED_WASIX_POSTMASTER_EXECUTABLES
+                .iter()
+                .copied()
+                .enumerate()
+                .map(|(index, expected)| test_artifact(expected, index as u8 + 1))
+                .chain(
+                    SEALED_EXPORT_SIDE_PATHS
+                        .iter()
+                        .enumerate()
+                        .map(|(index, module_path)| {
+                            test_artifact(
+                                ExpectedWasixPostmasterArtifact {
+                                    kind: "side-module",
+                                    module_path,
+                                    exec_aliases: &[],
+                                    executable: None,
+                                },
+                                index as u8 + 3,
+                            )
+                        }),
+                )
+                .collect(),
+        }
+    }
+
+    fn write_test_manifest(root: &Path) -> PathBuf {
+        let mut manifest = test_wasix_postmaster_manifest();
+        let mut modules: Vec<_> = manifest
+            .artifacts
+            .iter()
+            .map(|artifact| LinearMemoryInstallModule {
+                path: artifact.module_path.clone(),
+                source_module_sha256: artifact.linear_memory.source_module_sha256.clone(),
+                module_sha256: artifact.module_sha256.clone(),
+                initial_pages: 1,
+                maximum_pages: u64::from(LINEAR_MEMORY_MAXIMUM_PAGES),
+                maximum_bytes: LINEAR_MEMORY_MAXIMUM_BYTES,
+                shared: true,
+                import_module: "env".to_string(),
+                import_name: "memory".to_string(),
+                transformation: SEALED_MODULE_TRANSFORMATION_ID.to_string(),
+            })
+            .collect();
+        for (index, path) in SEALED_EXPORT_SIDE_PATHS.iter().enumerate() {
+            if modules.iter().any(|module| module.path == *path) {
+                continue;
+            }
+            modules.push(LinearMemoryInstallModule {
+                path: (*path).to_string(),
+                source_module_sha256: format!("{:02x}", 0x80 + index as u8).repeat(32),
+                module_sha256: format!("{:02x}", 0xa0 + index as u8).repeat(32),
+                initial_pages: 1,
+                maximum_pages: u64::from(LINEAR_MEMORY_MAXIMUM_PAGES),
+                maximum_bytes: LINEAR_MEMORY_MAXIMUM_BYTES,
+                shared: true,
+                import_module: "env".to_string(),
+                import_name: "memory".to_string(),
+                transformation: SEALED_MODULE_TRANSFORMATION_ID.to_string(),
+            });
+        }
+        modules.sort_by(|left, right| left.path.cmp(&right.path));
+        let source_sha256 = |path: &str| {
+            modules
+                .iter()
+                .find(|module| module.path == path)
+                .unwrap()
+                .source_module_sha256
+                .clone()
+        };
+        let side_identities = SEALED_EXPORT_SIDE_PATHS
+            .iter()
+            .map(|path| serde_json::json!({"path": path, "sha256": source_sha256(path)}))
+            .collect::>();
+        let proof_module = |path: &str, sha256: String| {
+            serde_json::json!({
+                "path": path,
+                "sha256": sha256,
+                "bytes": 1,
+                "non-export-sections-sha256": "b".repeat(64),
+                "dylink-needed": [],
+                "imported-functions": 0,
+                "local-functions": 1,
+                "imported-globals": 0,
+                "local-globals": 0,
+                "imported-tables": 0,
+                "local-tables": 1,
+                "element-function-entries": 1,
+                "element-unique-function-indices": 1,
+                "element-max-function-index": 0,
+                "start-function-index": 0,
+                "imports": [],
+                "export-counts": {},
+                "exported-global-type-counts": {},
+                "exported-immutable-i32-globals": 0,
+                "exported-local-functions": 0,
+                "exported-imported-functions": 0
+            })
+        };
+        let proof = |main_sha256: String| {
+            serde_json::json!({
+                "schema": SEALED_EXPORT_PROOF_SCHEMA,
+                "policy-id": SEALED_EXPORT_POLICY_ID,
+                "analyzer-version": "fixture",
+                "mandatory-policy-sha256": SEALED_EXPORT_MANDATORY_POLICY_SHA256,
+                "declared-main-dlsym-policy-sha256": SEALED_EXPORT_DLSYM_POLICY_SHA256,
+                "main": proof_module("bin/postgres", main_sha256),
+                "sides": SEALED_EXPORT_SIDE_PATHS.iter().map(|path| {
+                    proof_module(path, source_sha256(path))
+                }).collect::>(),
+                "mandatory-runtime-exports": [],
+                "declared-main-dlsym-exports": [],
+                "side-dynamic-imports": [],
+                "retained-main-exports": [],
+                "retained-main-export-descriptors": [],
+                "removed-main-export-count": 1,
+                "removed-main-export-names-sha256": "c".repeat(64),
+                "unresolved-main-requirements": [],
+                "mismatched-main-requirements": [],
+                "unresolved-side-dependencies": [],
+                "retained-counts": {},
+                "removed-counts": {"function": 1}
+            })
+        };
+        let seed_sha256 = "d".repeat(64);
+        let final_sha256 = source_sha256("bin/postgres");
+        let seed_proof_bytes = serde_json::to_vec(&proof(seed_sha256.clone())).unwrap();
+        let final_proof_bytes = serde_json::to_vec(&proof(final_sha256.clone())).unwrap();
+        let allowlist_bytes = b"fixture-export\n";
+        let share = root.join("share/postgresql");
+        fs::create_dir_all(&share).unwrap();
+        fs::write(root.join(SEALED_EXPORT_SEED_PROOF_PATH), &seed_proof_bytes).unwrap();
+        fs::write(
+            root.join(SEALED_EXPORT_FINAL_PROOF_PATH),
+            &final_proof_bytes,
+        )
+        .unwrap();
+        fs::write(root.join(SEALED_EXPORT_ALLOWLIST_PATH), allowlist_bytes).unwrap();
+        let snapshot = |sha256: String| {
+            serde_json::json!({
+                "sha256": sha256,
+                "bytes": 1,
+                "exports": 0,
+                "local-functions": 1,
+                "local-globals": 0,
+                "element-function-entries": 1,
+                "element-unique-function-indices": 1,
+                "start-function-index": 0
+            })
+        };
+        let export_receipt = serde_json::json!({
+            "schema": SEALED_EXPORT_RECEIPT_SCHEMA,
+            "policy-id": SEALED_EXPORT_POLICY_ID,
+            "analyzer-version": "fixture",
+            "analyzer-binary-sha256": "e".repeat(64),
+            "dce-tool-sha256": "f".repeat(64),
+            "dce-tool-version": "fixture-wasm-opt",
+            "dce-passes": ["--remove-unused-module-elements"],
+            "mandatory-policy-sha256": SEALED_EXPORT_MANDATORY_POLICY_SHA256,
+            "declared-main-dlsym-policy-sha256": SEALED_EXPORT_DLSYM_POLICY_SHA256,
+            "side-manifest-sha256": SEALED_EXPORT_SIDE_MANIFEST_SHA256,
+            "allowlist-sha256": hex::encode(Sha256::digest(allowlist_bytes)),
+            "seed-proof-sha256": hex::encode(Sha256::digest(&seed_proof_bytes)),
+            "final-proof-sha256": hex::encode(Sha256::digest(&final_proof_bytes)),
+            "seed": snapshot(seed_sha256),
+            "final-module": snapshot(final_sha256),
+            "sides": side_identities
+        });
+        let export_receipt_bytes = serde_json::to_vec(&export_receipt).unwrap();
+        fs::write(root.join(SEALED_EXPORT_RECEIPT_PATH), &export_receipt_bytes).unwrap();
+        let receipt = LinearMemoryInstallReceipt {
+            schema: LINEAR_MEMORY_INSTALL_RECEIPT_SCHEMA.to_string(),
+            profile_id: LINEAR_MEMORY_PROFILE_ID.to_string(),
+            address_width: "wasm32".to_string(),
+            supported_host_pointer_width: "u64".to_string(),
+            maximum_pages: LINEAR_MEMORY_MAXIMUM_PAGES,
+            maximum_bytes: LINEAR_MEMORY_MAXIMUM_BYTES,
+            static_bound_pages: LINEAR_MEMORY_STATIC_BOUND_PAGES,
+            static_offset_guard_bytes: LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES,
+            static_access_lowering: "wasmer-llvm-unchecked-reservation-and-guard-v1".to_string(),
+            requires_shared: true,
+            requires_import: "env.memory".to_string(),
+            excludes_wasm32_end_wrap: true,
+            predecessor_export_closure_receipt: SEALED_EXPORT_RECEIPT_PATH.to_string(),
+            predecessor_export_closure_receipt_sha256: hex::encode(Sha256::digest(
+                &export_receipt_bytes,
+            )),
+            source_module_closure_sha256: linear_memory_closure_sha256(
+                &modules,
+                "source-module-sha256",
+            ),
+            module_closure_sha256: linear_memory_closure_sha256(&modules, "module-sha256"),
+            module_count: modules.len(),
+            modules,
+        };
+        let receipt_bytes = serde_json::to_vec(&receipt).unwrap();
+        let receipt_sha256 = hex::encode(Sha256::digest(&receipt_bytes));
+        manifest.linear_memory_profile.install_receipt_sha256 = receipt_sha256.clone();
+        for artifact in &mut manifest.artifacts {
+            artifact.linear_memory.install_receipt_sha256 = receipt_sha256.clone();
+        }
+        let receipt_path = root.join(&manifest.linear_memory_profile.install_receipt_path);
+        fs::create_dir_all(receipt_path.parent().unwrap()).unwrap();
+        fs::write(receipt_path, receipt_bytes).unwrap();
+        let manifest_path = root.join("manifest.json");
+        fs::write(&manifest_path, serde_json::to_vec(&manifest).unwrap()).unwrap();
+        manifest_path
+    }
+
+    fn source_from_bytes(carrier_root: &Path, name: &str, bytes: &[u8]) -> SealedArtifactSource {
+        let path = carrier_root.join(name);
+        fs::write(&path, bytes).unwrap();
+        SealedArtifactSource {
+            file: open_regular(&path).unwrap(),
+            path,
+            carrier_root: carrier_root.to_path_buf(),
+            expected_size: bytes.len() as u64,
+        }
+    }
+
+    fn snapshot_from_bytes(
+        carrier_root: &Path,
+        name: &str,
+        bytes: &[u8],
+    ) -> ImmutableArtifactSnapshot {
+        immutable_artifact_snapshot(
+            source_from_bytes(carrier_root, name, bytes),
+            SealedActivationPolicy::Compatibility,
+        )
+        .unwrap()
+    }
+
+    fn lazy_artifact_from_bytes(
+        carrier_root: &Path,
+        name: &str,
+        bytes: &[u8],
+        module_hash: ModuleHash,
+    ) -> LazySealedArtifact {
+        LazySealedArtifact::new(
+            module_hash,
+            Sha256::digest(bytes).into(),
+            source_from_bytes(carrier_root, name, bytes),
+            SealedActivationPolicy::Compatibility,
+        )
+    }
+
+    #[test]
+    fn runtime_policy_identity_requires_the_exact_postmaster_closure() {
+        assert!(has_exact_wasix_postmaster_identity(
+            &test_wasix_postmaster_manifest()
+        ));
+
+        let mut missing = test_wasix_postmaster_manifest();
+        missing.artifacts.pop();
+        assert!(!has_exact_wasix_postmaster_identity(&missing));
+
+        let mut duplicate_path = test_wasix_postmaster_manifest();
+        duplicate_path.artifacts[1].module_path = duplicate_path.artifacts[0].module_path.clone();
+        assert!(!has_exact_wasix_postmaster_identity(&duplicate_path));
+
+        let mut reordered = test_wasix_postmaster_manifest();
+        reordered.artifacts.swap(0, 1);
+        assert!(!has_exact_wasix_postmaster_identity(&reordered));
+
+        let mut extra_feature = test_wasix_postmaster_manifest();
+        extra_feature.wasm_features.push("simd".to_string());
+        assert!(!has_exact_wasix_postmaster_identity(&extra_feature));
+
+        let mut unsupported_profile = test_wasix_postmaster_manifest();
+        unsupported_profile.core_profile = "o3".to_string();
+        assert!(!has_exact_wasix_postmaster_identity(&unsupported_profile));
+
+        let mut invalid_guest_recipe = test_wasix_postmaster_manifest();
+        invalid_guest_recipe.guest_build_recipe_sha256 = "not-a-digest".to_string();
+        assert!(!has_exact_wasix_postmaster_identity(&invalid_guest_recipe));
+
+        let mut superseded_schema = test_wasix_postmaster_manifest();
+        superseded_schema.format_version = 5;
+        superseded_schema.schema = "oliphaunt.wasix-postmaster.sealed-aot.v4".to_string();
+        assert!(!has_exact_wasix_postmaster_identity(&superseded_schema));
+    }
+
+    #[test]
+    fn runtime_policy_identity_parser_rejects_unknown_manifest_fields() {
+        let mut manifest = serde_json::to_value(test_wasix_postmaster_manifest()).unwrap();
+        manifest
+            .as_object_mut()
+            .unwrap()
+            .insert("runtime-policy".to_string(), serde_json::json!("unknown"));
+        assert!(serde_json::from_value::(manifest).is_err());
+
+        let mut artifact_manifest = serde_json::to_value(test_wasix_postmaster_manifest()).unwrap();
+        artifact_manifest["artifacts"][0]
+            .as_object_mut()
+            .unwrap()
+            .insert("identity-extension".to_string(), serde_json::json!(true));
+        assert!(serde_json::from_value::(artifact_manifest).is_err());
+    }
+
+    #[test]
+    fn small_regular_file_read_enforces_a_hard_stream_limit() {
+        let root = tempfile::tempdir().unwrap();
+        let path = root.path().join("bounded");
+        fs::write(&path, b"12345678").unwrap();
+        assert_eq!(read_small_regular_file(&path, 8).unwrap(), b"12345678");
+
+        fs::write(&path, b"123456789").unwrap();
+        assert!(read_small_regular_file(&path, 8).is_err());
+    }
+
+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+    #[test]
+    fn strict_code_memory_state_directory_is_deterministic_private_and_deny_symlink() {
+        use std::os::unix::{fs::MetadataExt, fs::PermissionsExt, fs::symlink};
+
+        let parent = tempfile::Builder::new()
+            .prefix("oliphaunt-code-memory-state-test-")
+            .tempdir_in("/var/tmp")
+            .unwrap();
+        let carrier = parent.path().join("immutable-carrier");
+        fs::create_dir(&carrier).unwrap();
+
+        let (directory, device, inode) =
+            strict_code_memory_directory_for_carrier(&carrier).unwrap();
+        assert_eq!(directory, parent.path().join(CODE_MEMORY_STATE_DIRECTORY));
+        let metadata = fs::symlink_metadata(&directory).unwrap();
+        assert!(metadata.is_dir());
+        assert!(!metadata.file_type().is_symlink());
+        assert_eq!(metadata.uid(), unsafe { libc::geteuid() });
+        assert_eq!(metadata.mode() & 0o7777, 0o700);
+        assert_eq!(metadata.dev(), device);
+        assert_eq!(metadata.ino(), inode);
+        assert_eq!(
+            strict_code_memory_directory_for_carrier(&carrier)
+                .unwrap()
+                .0,
+            directory
+        );
+
+        fs::remove_dir(&directory).unwrap();
+        let redirect = parent.path().join("redirect");
+        fs::create_dir(&redirect).unwrap();
+        fs::set_permissions(&redirect, fs::Permissions::from_mode(0o700)).unwrap();
+        symlink(&redirect, &directory).unwrap();
+        let error = strict_code_memory_directory_for_carrier(&carrier).unwrap_err();
+        assert!(error.to_string().contains("non-symlink"));
+    }
+
+    #[test]
+    fn runtime_policy_identity_selects_only_product_executables() {
+        let root = tempfile::tempdir().unwrap();
+        fs::create_dir_all(root.path().join("bin")).unwrap();
+        let initdb = root.path().join("bin/initdb");
+        let postgres = root.path().join("bin/postgres");
+        let unrelated = root.path().join("bin/unrelated");
+        fs::write(&initdb, b"initdb").unwrap();
+        fs::write(&postgres, b"postgres").unwrap();
+        fs::write(&unrelated, b"unrelated").unwrap();
+        let manifest_path = write_test_manifest(root.path());
+
+        let prepared_initdb = prepare(&manifest_path, &initdb).unwrap();
+        assert_eq!(
+            prepared_initdb.runtime_identity(),
+            Some(SealedRuntimeIdentity::WasixPostmasterInitdb)
+        );
+        let prepared_postgres = prepare(&manifest_path, &postgres).unwrap();
+        assert_eq!(
+            prepared_postgres.runtime_identity(),
+            Some(SealedRuntimeIdentity::WasixPostmasterPostgres)
+        );
+        assert!(prepare(&manifest_path, &unrelated).is_err());
+
+        fs::write(&manifest_path, b"{").unwrap();
+        assert!(prepare(&manifest_path, &root.path().join("bin/postgres")).is_err());
+    }
+
+    #[test]
+    fn carrier_paths_are_relative_and_normalized() {
+        let root = tempfile::tempdir().unwrap();
+        fs::write(root.path().join("artifact.bin"), b"artifact").unwrap();
+        assert!(carrier_file_path(root.path(), "artifact.bin").is_ok());
+        assert!(carrier_file_path(root.path(), "../artifact.bin").is_err());
+        assert!(carrier_file_path(root.path(), "/artifact.bin").is_err());
+        assert!(carrier_file_path(root.path(), "a/../artifact.bin").is_err());
+    }
+
+    #[test]
+    fn guest_aliases_are_absolute_and_normalized() {
+        assert!(validate_guest_alias("/bin/postgres").is_ok());
+        assert!(validate_guest_alias("bin/postgres").is_err());
+        assert!(validate_guest_alias("/bin/../postgres").is_err());
+        assert!(validate_guest_alias("/bin//postgres").is_err());
+    }
+
+    #[test]
+    fn sha256_fields_are_exact() {
+        assert!(parse_sha256("digest", &"ab".repeat(32)).is_ok());
+        assert!(parse_sha256("digest", &"ab".repeat(31)).is_err());
+        assert!(parse_sha256("digest", &"zz".repeat(32)).is_err());
+    }
+
+    #[test]
+    fn artifact_snapshot_is_pathless_read_only_and_stable() {
+        let root = tempfile::tempdir().unwrap();
+        let original = b"verified artifact bytes";
+        let snapshot = snapshot_from_bytes(root.path(), "artifact.bin", original);
+
+        assert_eq!(snapshot.audit.logical_bytes, original.len() as u64);
+        assert_eq!(snapshot.audit.mapping_bytes_hashed, original.len() as u64);
+        assert_eq!(snapshot.audit.sync_calls, 0);
+        match snapshot.audit.mode {
+            ArtifactSnapshotMode::DirectIntrinsic(_) => {
+                assert_eq!(snapshot.audit.source_bytes_read, original.len() as u64);
+                assert_eq!(snapshot.audit.snapshot_bytes_written, 0);
+            }
+            ArtifactSnapshotMode::Reflink => {
+                assert_eq!(snapshot.audit.source_bytes_read, 0);
+                assert_eq!(snapshot.audit.snapshot_bytes_written, 0);
+            }
+            ArtifactSnapshotMode::StreamedCopy => {
+                assert_eq!(snapshot.audit.source_bytes_read, original.len() as u64);
+                assert_eq!(snapshot.audit.snapshot_bytes_written, original.len() as u64);
+            }
+        }
+
+        fs::write(root.path().join("artifact.bin"), b"mutated artifact bytes!").unwrap();
+        assert_eq!(snapshot.mapping().unwrap().as_slice(), original);
+
+        #[cfg(target_os = "linux")]
+        {
+            use std::os::{fd::AsRawFd, unix::fs::MetadataExt};
+            assert_eq!(snapshot.file.metadata().unwrap().nlink(), 0);
+            let flags = unsafe { libc::fcntl(snapshot.file.as_raw_fd(), libc::F_GETFL) };
+            assert_ne!(flags, -1);
+            assert_eq!(flags & libc::O_ACCMODE, libc::O_RDONLY);
+        }
+    }
+
+    #[test]
+    fn streamed_snapshot_fallback_accounts_copy_without_sync() {
+        let root = tempfile::tempdir().unwrap();
+        let bytes = b"forced streamed snapshot bytes";
+        let snapshot =
+            streamed_artifact_snapshot(source_from_bytes(root.path(), "streamed.aot", bytes))
+                .unwrap();
+
+        assert_eq!(snapshot.audit.mode, ArtifactSnapshotMode::StreamedCopy);
+        assert_eq!(snapshot.audit.logical_bytes, bytes.len() as u64);
+        assert_eq!(snapshot.audit.source_bytes_read, bytes.len() as u64);
+        assert_eq!(snapshot.audit.snapshot_bytes_written, bytes.len() as u64);
+        assert_eq!(snapshot.audit.mapping_bytes_hashed, bytes.len() as u64);
+        assert_eq!(snapshot.audit.sync_calls, 0);
+        assert_eq!(snapshot.mapping().unwrap().as_slice(), bytes);
+        assert!(snapshot.has_distinct_source());
+
+        #[cfg(target_os = "linux")]
+        {
+            use std::os::unix::fs::MetadataExt;
+
+            let source = snapshot.source_file.as_ref().unwrap().metadata().unwrap();
+            let private = snapshot.file.metadata().unwrap();
+            assert_ne!((source.dev(), source.ino()), (private.dev(), private.ino()));
+            let source_advice = snapshot.advise_source_away();
+            let snapshot_advice = snapshot.advise_snapshot_away();
+            assert_eq!(source_advice.calls, 1);
+            assert_eq!(source_advice.successes, 1);
+            assert_eq!(snapshot_advice.calls, 1);
+            assert_eq!(snapshot_advice.successes, 1);
+        }
+    }
+
+    #[cfg(target_os = "linux")]
+    #[test]
+    fn direct_snapshot_accounts_no_payload_writes() {
+        let root = tempfile::tempdir().unwrap();
+        let bytes = b"direct immutable snapshot bytes";
+        let source = source_from_bytes(root.path(), "direct.aot", bytes);
+        // The kernel-proof classifier is covered in wasmer-wasix. Supplying a
+        // proof here isolates accounting and live-FD mapping behavior.
+        let snapshot =
+            direct_artifact_snapshot_from_proof(&source, IntrinsicFileImmutability::ImmutableInode)
+                .unwrap();
+
+        assert_eq!(
+            snapshot.audit.mode,
+            ArtifactSnapshotMode::DirectIntrinsic(IntrinsicFileImmutability::ImmutableInode)
+        );
+        assert_eq!(snapshot.audit.source_bytes_read, bytes.len() as u64);
+        assert_eq!(snapshot.audit.snapshot_bytes_written, 0);
+        assert_eq!(snapshot.audit.sync_calls, 0);
+        assert_eq!(snapshot.mapping().unwrap().as_slice(), bytes);
+        assert!(!snapshot.has_distinct_source());
+        assert_eq!(
+            snapshot.advise_snapshot_away(),
+            FileAdviceAudit::not_applicable()
+        );
+    }
+
+    #[cfg(target_os = "linux")]
+    #[test]
+    fn required_zero_write_rejects_mutable_source_before_compatibility_copy() {
+        let root = tempfile::tempdir().unwrap();
+        let bytes = b"mutable AOT bytes";
+        let source = source_from_bytes(root.path(), "mutable.aot", bytes);
+        let error =
+            immutable_artifact_snapshot(source, SealedActivationPolicy::RequireDirectImmutable)
+                .unwrap_err();
+
+        assert!(error.to_string().contains("requires direct activation"));
+        assert_eq!(fs::read(root.path().join("mutable.aot")).unwrap(), bytes);
+        assert_eq!(fs::read_dir(root.path()).unwrap().count(), 1);
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn loader_audit_receipt_is_owned_compact_jsonl() {
+        use std::os::unix::fs::PermissionsExt;
+
+        let root = tempfile::tempdir().unwrap();
+        let path = root.path().join("loader.jsonl");
+        let record = LoaderAuditRecord {
+            artifact_kind: "aot",
+            module_sha256: "ab".repeat(32),
+            snapshot_mode: "direct-immutable-inode",
+            logical_bytes: 17,
+            source_bytes_read: 0,
+            source_bytes_written: 0,
+            snapshot_bytes_written: 0,
+            mapping_bytes_hashed: 17,
+            sync_calls: 0,
+            read_advice_applicable: true,
+            read_advice_supported: true,
+            read_advice_calls: 2,
+            read_advice_successes: 2,
+            read_advice_first_errno: None,
+            source_cache_eviction_applicable: true,
+            source_cache_eviction_supported: true,
+            source_cache_eviction_calls: 1,
+            source_cache_eviction_successes: 1,
+            source_cache_eviction_errno: None,
+            snapshot_cache_eviction_applicable: false,
+            snapshot_cache_eviction_supported: true,
+            snapshot_cache_eviction_calls: 0,
+            snapshot_cache_eviction_successes: 0,
+            snapshot_cache_eviction_errno: None,
+            mapping_cache_eviction_applicable: false,
+            mapping_cache_eviction_supported: true,
+            mapping_cache_eviction_calls: 0,
+            mapping_cache_eviction_successes: 0,
+            mapping_cache_eviction_errno: None,
+            residency_after_hash_inspect: LoaderResidencyRecord {
+                state: "measured",
+                page_size: Some(4096),
+                total_pages: Some(1),
+                resident_pages: Some(1),
+                resident_bytes: Some(17),
+                errno: None,
+            },
+            residency_after_archive_release: LoaderResidencyRecord {
+                state: "measured",
+                page_size: Some(4096),
+                total_pages: Some(1),
+                resident_pages: Some(1),
+                resident_bytes: Some(17),
+                errno: None,
+            },
+            source_residency_before_eviction: LoaderResidencyRecord {
+                state: "measured",
+                page_size: Some(4096),
+                total_pages: Some(1),
+                resident_pages: Some(1),
+                resident_bytes: Some(17),
+                errno: None,
+            },
+            source_residency_after_eviction: LoaderResidencyRecord {
+                state: "measured",
+                page_size: Some(4096),
+                total_pages: Some(1),
+                resident_pages: Some(0),
+                resident_bytes: Some(0),
+                errno: None,
+            },
+            residency_after_eviction: LoaderResidencyRecord {
+                state: "measured",
+                page_size: Some(4096),
+                total_pages: Some(1),
+                resident_pages: Some(0),
+                resident_bytes: Some(0),
+                errno: None,
+            },
+            write_policy: "none-immutable-source",
+        };
+        emit_loader_audit_to_path(&path, &record).unwrap();
+
+        let text = fs::read_to_string(&path).unwrap();
+        assert_eq!(text.lines().count(), 1);
+        let parsed: serde_json::Value = serde_json::from_str(text.trim()).unwrap();
+        assert_eq!(
+            parsed["schema"],
+            "oliphaunt.wasix-postmaster.sealed-loader-receipt.v2"
+        );
+        assert_eq!(parsed["snapshot_mode"], "direct-immutable-inode");
+        assert_eq!(parsed["source_bytes_written"], 0);
+        assert_eq!(parsed["snapshot_bytes_written"], 0);
+        assert_eq!(parsed["sync_calls"], 0);
+        assert_eq!(parsed["read_advice_calls"], 2);
+        assert_eq!(parsed["source_cache_eviction_successes"], 1);
+        assert_eq!(parsed["snapshot_cache_eviction_applicable"], false);
+        assert_eq!(parsed["mapping_cache_eviction_applicable"], false);
+        assert_eq!(parsed["residency_after_eviction"]["resident_pages"], 0);
+        assert_eq!(
+            fs::metadata(path).unwrap().permissions().mode() & 0o777,
+            0o600
+        );
+    }
+
+    #[test]
+    fn loader_audit_module_hash_is_canonical_lowercase_sha256() {
+        let module_hash = ModuleHash::from_bytes([0xab; 32]);
+        assert_eq!(canonical_module_sha256(module_hash), "ab".repeat(32));
+    }
+
+    #[test]
+    fn failed_activation_is_single_flight_and_stable() {
+        use std::sync::{Barrier, atomic::Ordering};
+
+        let root = tempfile::tempdir().unwrap();
+        let module_hash = ModuleHash::from_bytes([0x11; 32]);
+        let artifact = Arc::new(lazy_artifact_from_bytes(
+            root.path(),
+            "invalid.aot",
+            b"not a Wasmer artifact",
+            module_hash,
+        ));
+        let engine = Engine::headless();
+        let cache = Arc::new(SealedModuleCache::new(
+            &engine,
+            HashMap::from([(module_hash, artifact.clone())]),
+        ));
+        let barrier = Arc::new(Barrier::new(8));
+        let threads = (0..8)
+            .map(|_| {
+                let barrier = barrier.clone();
+                let cache = cache.clone();
+                let engine = engine.clone();
+                std::thread::spawn(move || {
+                    barrier.wait();
+                    cache
+                        .load_exact(module_hash, &engine)
+                        .unwrap_err()
+                        .to_string()
+                })
+            })
+            .collect::>();
+        let errors = threads
+            .into_iter()
+            .map(|thread| thread.join().unwrap())
+            .collect::>();
+
+        assert!(errors.iter().all(|error| error == &errors[0]));
+        assert_eq!(artifact.activation_attempts.load(Ordering::Relaxed), 1);
+        assert!(matches!(
+            cache.load_exact(ModuleHash::from_bytes([0x22; 32]), &engine),
+            Err(CacheError::NotFound)
+        ));
+        let different_engine = Engine::headless();
+        let engine_mismatch = cache
+            .load_exact(module_hash, &different_engine)
+            .unwrap_err();
+        assert!(engine_mismatch.to_string().contains("engine mismatch"));
+
+        let fallback_error = futures::executor::block_on(wasmer_wasix::runtime::load_module(
+            &engine,
+            cache.as_ref(),
+            wasmer_wasix::runtime::ModuleInput::Bytes(std::borrow::Cow::Borrowed(
+                b"\0asm\x01\0\0\0",
+            )),
+            None,
+        ))
+        .unwrap_err();
+        assert!(matches!(
+            fallback_error,
+            wasmer_wasix::SpawnError::CacheError(CacheError::NotFound)
+        ));
+    }
+
+    #[cfg(all(feature = "cranelift", feature = "wat"))]
+    fn serialized_artifact(wat: &str) -> (Vec, ModuleHash) {
+        let compiler_engine = Engine::new(
+            Box::new(wasmer_compiler_cranelift::Cranelift::default()),
+            Target::default(),
+            wasmer_types::Features::default(),
+        );
+        let wasm = wasmer::wat2wasm(wat.as_bytes()).unwrap();
+        let module_hash = ModuleHash::new(wasm.as_ref());
+        let module = Module::new(&compiler_engine, wasm.as_ref()).unwrap();
+        (module.serialize().unwrap().to_vec(), module_hash)
+    }
+
+    #[cfg(all(
+        feature = "cranelift",
+        feature = "wat",
+        target_os = "linux",
+        target_arch = "x86_64"
+    ))]
+    #[test]
+    fn post_publication_audit_failure_rolls_back_strict_code_memory() {
+        use std::os::unix::fs::PermissionsExt;
+
+        let carrier_root = tempfile::tempdir().unwrap();
+        let (bytes, module_hash) =
+            serialized_artifact("(module (memory 1 4096 shared) (func (export \"selected\")))");
+        let artifact =
+            lazy_artifact_from_bytes(carrier_root.path(), "selected.aot", &bytes, module_hash);
+
+        let code_root = tempfile::Builder::new()
+            .prefix("wasmer-sealed-pending-code-memory-test-")
+            .tempdir_in("/var/tmp")
+            .unwrap();
+        fs::set_permissions(code_root.path(), fs::Permissions::from_mode(0o700)).unwrap();
+        let policy =
+            wasmer::sys::CodeMemoryPolicy::strict_linux_x86_64_file_backed(code_root.path())
+                .unwrap();
+        let mut engine = Engine::headless();
+        engine.set_code_memory_policy(policy).unwrap();
+        let baseline = engine.as_sys().code_memory_allocation_count();
+
+        let error = artifact
+            .activate_with_audit(&engine, |_| {
+                assert_eq!(
+                    engine.as_sys().code_memory_allocation_count(),
+                    baseline + 1,
+                    "published code must remain transaction-owned during audit"
+                );
+                Err(anyhow::anyhow!("injected post-publication audit failure"))
+            })
+            .unwrap_err();
+        assert!(
+            error.to_string().contains("post-publication audit failure"),
+            "unexpected activation failure: {error}"
+        );
+        assert_eq!(
+            engine.as_sys().code_memory_allocation_count(),
+            baseline,
+            "failed admission must deregister and unmap its exact allocation"
+        );
+    }
+
+    #[cfg(all(feature = "cranelift", feature = "wat"))]
+    #[test]
+    fn selected_only_activation_and_success_are_single_flight() {
+        use std::sync::{Barrier, atomic::Ordering};
+
+        let root = tempfile::tempdir().unwrap();
+        let (selected_bytes, selected_hash) =
+            serialized_artifact("(module (memory 1 4096 shared) (func (export \"selected\")))");
+        let (cold_bytes, cold_hash) =
+            serialized_artifact("(module (memory 1 4096 shared) (func (export \"cold\")))");
+        let selected = Arc::new(lazy_artifact_from_bytes(
+            root.path(),
+            "selected.aot",
+            &selected_bytes,
+            selected_hash,
+        ));
+        let cold = Arc::new(lazy_artifact_from_bytes(
+            root.path(),
+            "cold.aot",
+            &cold_bytes,
+            cold_hash,
+        ));
+        let engine = Engine::headless();
+        let cache = Arc::new(SealedModuleCache::new(
+            &engine,
+            HashMap::from([(selected_hash, selected.clone()), (cold_hash, cold.clone())]),
+        ));
+
+        let selected_module = cache.load_exact(selected_hash, &engine).unwrap();
+        assert_eq!(selected.activation_attempts.load(Ordering::Relaxed), 1);
+        assert_eq!(cold.activation_attempts.load(Ordering::Relaxed), 0);
+
+        let barrier = Arc::new(Barrier::new(8));
+        let threads = (0..8)
+            .map(|_| {
+                let barrier = barrier.clone();
+                let cache = cache.clone();
+                let engine = engine.clone();
+                std::thread::spawn(move || {
+                    barrier.wait();
+                    cache.load_exact(selected_hash, &engine).unwrap();
+                })
+            })
+            .collect::>();
+        for thread in threads {
+            thread.join().unwrap();
+        }
+        assert_eq!(selected.activation_attempts.load(Ordering::Relaxed), 1);
+        assert_eq!(cold.activation_attempts.load(Ordering::Relaxed), 0);
+
+        cache.load_exact(cold_hash, &engine).unwrap();
+        assert_eq!(cold.activation_attempts.load(Ordering::Relaxed), 1);
+        drop(selected_module);
+    }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/build-sealed-carrier.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/build-sealed-carrier.mts
new file mode 100644
index 000000000..f8bc91e53
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/build-sealed-carrier.mts
@@ -0,0 +1,204 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import {
+  fchmodSync,
+  openSync,
+  closeSync,
+  fsyncSync,
+  fstatSync,
+  writeFileSync,
+  constants,
+} from 'node:fs';
+import { member } from './receipt-files.mts';
+import { dirname, basename } from 'node:path';
+import { profile, profileId } from './linear-memory-profile.mts';
+import { readRegular, parseJson, requireSha } from './sealed-export-chain.mts';
+import {
+  guestReceipt,
+  sourceFingerprint,
+  carrierTree,
+  hashRegular,
+} from './verify-sealed-carrier.mts';
+
+function manifest(args: string[]) {
+  assert.equal(args.length, 22, 'manifest requires exact builder inputs');
+  const [
+    rows,
+    root,
+    output,
+    fingerprint,
+    coreProfile,
+    guestHash,
+    target,
+    abi,
+    config,
+    commit,
+    patch,
+    lock,
+    runtime,
+    producer,
+    executorHash,
+    executorSize,
+    pg,
+    wasmer,
+    wasix,
+    artifactAbi,
+    linearPath,
+    linearHash,
+  ] = args;
+  const linear = parseJson(readRegular(root, linearPath));
+  assert.equal(linear.schema, 'oliphaunt.wasix-postmaster.linear-memory-install.v1');
+  assert.equal(linear['profile-id'], profileId);
+  for (const [key, value] of Object.entries(profile))
+    assert.equal(linear[key], value, `linear profile differs: ${key}`);
+  const modules = new Map();
+  assert(Array.isArray(linear.modules), 'memory receipt lacks modules');
+  for (const row of linear.modules) {
+    assert(typeof row.path === 'string' && !modules.has(row.path), 'duplicate/invalid module path');
+    modules.set(row.path, row);
+  }
+  const text = new TextDecoder('utf8', { fatal: true }).decode(
+    readRegular(dirname(rows), basename(rows)),
+  );
+  assert(text.endsWith('\n') && !/[\r\0]/.test(text), 'non-canonical artifact rows');
+  const unsigned = (value: string) => {
+    assert(
+      /^(0|[1-9][0-9]*)$/.test(value) && Number.isSafeInteger(Number(value)),
+      'invalid artifact size/ABI',
+    );
+    return Number(value);
+  };
+  const artifacts = text
+    .slice(0, -1)
+    .split('\n')
+    .map((line) => {
+      const fields = line.split('\t');
+      assert.equal(fields.length, 9, 'invalid artifact row');
+      const [name, kind, path, modulePath, hash, size, moduleHash, moduleSize, alias] = fields;
+      const record = modules.get(modulePath);
+      assert(record, 'memory receipt lacks module');
+      requireSha(hash);
+      requireSha(moduleHash);
+      assert.equal(record['module-sha256'], moduleHash);
+      return {
+        name,
+        kind,
+        path,
+        'module-path': modulePath,
+        sha256: hash,
+        'raw-sha256': hash,
+        'raw-size': unsigned(size),
+        'module-sha256': moduleHash,
+        'module-size': unsigned(moduleSize),
+        'linear-memory': {
+          'profile-id': profileId,
+          'source-module-sha256': record['source-module-sha256'],
+          'install-receipt-sha256': linearHash,
+        },
+        compressed: false,
+        'exec-aliases': alias ? [alias] : [],
+      };
+    });
+  const result = {
+    'format-version': 6,
+    schema: 'oliphaunt.wasix-postmaster.sealed-aot.v5',
+    'source-lane': 'wasix-postmaster',
+    'source-fingerprint': fingerprint,
+    'core-profile': coreProfile,
+    'guest-build-recipe-sha256': guestHash,
+    'postgres-version': pg,
+    'target-triple': target,
+    'host-abi': abi,
+    engine: 'llvm-opta',
+    'compiler-config': config,
+    'cpu-policy': 'generic-baseline',
+    'cpu-features': [],
+    'wasmer-version': wasmer,
+    'wasmer-wasix-version': wasix,
+    'wasmer-source-commit': commit,
+    'wasmer-patch-sha256': patch,
+    'wasmer-cargo-lock-sha256': lock,
+    'artifact-abi-version': unsigned(artifactAbi),
+    'runtime-abi-id': runtime,
+    'producer-recipe-sha256': producer,
+    'executor-engine': 'engine-headless',
+    'executor-sha256': executorHash,
+    'executor-size': unsigned(executorSize),
+    'linear-memory-profile': {
+      id: profileId,
+      ...Object.fromEntries(
+        Object.entries(profile).filter(
+          ([key]) =>
+            !['requires-shared', 'requires-import', 'excludes-wasm32-end-wrap'].includes(key),
+        ),
+      ),
+      'install-receipt-path': linearPath,
+      'install-receipt-sha256': linearHash,
+    },
+    'wasm-features': ['exceptions', 'threads'],
+    entrypoint: 'runtime:postgres',
+    artifacts,
+  };
+  writeFileSync(output, `${JSON.stringify(result, null, 2)}\n`, { flag: 'wx' });
+}
+function synchronize(path: string, directory: boolean, mode?: number) {
+  const fd = openSync(
+    path,
+    constants.O_RDONLY | constants.O_NOFOLLOW | (directory ? constants.O_DIRECTORY : 0),
+  );
+  try {
+    const info = fstatSync(fd);
+    assert(directory ? info.isDirectory() : info.isFile(), 'non-regular sync input');
+    if (mode === undefined) fsyncSync(fd);
+    else fchmodSync(fd, mode);
+  } finally {
+    closeSync(fd);
+  }
+}
+if (import.meta.main) {
+  try {
+    const [command, ...args] = process.argv.slice(2),
+      [root] = args;
+    assert(root, 'builder input is required');
+    if (command === 'guest-receipt' && args.length === 5) {
+      const receipt = guestReceipt(root);
+      for (const [index, key] of [
+        'core_profile',
+        'postgres_tag',
+        'postgres_version',
+        'sysroot_variant',
+      ].entries())
+        assert.equal(receipt[key], args[index + 1], `guest ${key} differs`);
+    } else if (command === 'source-fingerprint' && args.length === 1)
+      console.log(sourceFingerprint(root));
+    else if (command === 'manifest') manifest(args);
+    else if (command === 'seal' && args.length === 1) {
+      const tree = carrierTree(root),
+        lines = [];
+      for (const [relative, info] of [...tree].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
+        assert(relative !== 'payload.files', 'payload inventory already exists');
+        if (!info.isFile()) continue;
+        const { size, sha256 } = hashRegular(member(root, relative));
+        lines.push(`${sha256}\t${size}\t${relative}`);
+        synchronize(member(root, relative), false, info.mode & 0o111 ? 0o555 : 0o444);
+      }
+      writeFileSync(
+        member(root, 'payload.files'),
+        `schema=oliphaunt.wasix-postmaster.payload-files.v1\n${lines.join('\n')}\n`,
+        { flag: 'wx', mode: 0o444 },
+      );
+      for (const [relative, info] of [...tree].reverse())
+        if (info.isDirectory())
+          synchronize(relative === '.' ? root : member(root, relative), true, 0o555);
+    } else if (command === 'sync-tree' && args.length === 1) {
+      const tree = carrierTree(root);
+      for (const [relative, info] of tree)
+        if (info.isFile()) synchronize(member(root, relative), false);
+      for (const [relative, info] of [...tree].reverse())
+        if (info.isDirectory()) synchronize(relative === '.' ? root : member(root, relative), true);
+    } else assert.fail('unknown sealed-carrier builder command or arguments');
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : error);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
new file mode 100644
index 000000000..15f8106c1
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
@@ -0,0 +1,1765 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+_fresh_common_source="${BASH_SOURCE[0]}"
+_fresh_source_root="$(cd -P "$(dirname "$_fresh_common_source")/.." && pwd -P)"
+_fresh_source_repo_root="$(cd -P "$_fresh_source_root/../../.." && pwd -P)"
+export FRESH_ROOT="${FRESH_ROOT:-$_fresh_source_root}"
+export REPO_ROOT="${REPO_ROOT:-$_fresh_source_repo_root}"
+_fresh_project_source_id_prefix="src/runtimes/liboliphaunt-wasix-postmaster"
+if [ "${FRESH_PROJECT_SOURCE_ID_PREFIX+x}" = x ]; then
+  if [ "$FRESH_PROJECT_SOURCE_ID_PREFIX" != "$_fresh_project_source_id_prefix" ]; then
+    printf 'FRESH_PROJECT_SOURCE_ID_PREFIX must be %s\n' \
+      "$_fresh_project_source_id_prefix" >&2
+    return 2 2>/dev/null || exit 2
+  fi
+else
+  FRESH_PROJECT_SOURCE_ID_PREFIX="$_fresh_project_source_id_prefix"
+fi
+readonly FRESH_PROJECT_SOURCE_ID_PREFIX
+export FRESH_PROJECT_SOURCE_ID_PREFIX
+export WASIX_TOOLCHAIN_ROOT="${WASIX_TOOLCHAIN_ROOT:-$REPO_ROOT/src/runtimes/liboliphaunt-wasix/assets/build}"
+export FRESH_WORK_ROOT="${FRESH_WORK_ROOT:-$REPO_ROOT/target/oliphaunt-wasix-postmaster}"
+
+# Source manifests contain only plain quoted scalars for these fields. Read the
+# authoritative pin directly; checkout verification below binds the actual tree.
+fresh_source_scalar() {
+  [ -f "$1" ] && [ ! -L "$1" ] || return 2
+  awk -F= -v key="$2" '
+    $1 ~ "^[[:space:]]*" key "[[:space:]]*$" {
+      count++
+      value = $2
+      gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
+      if (NF != 2 || (key == "url" ? value !~ /^"https:\/\/[A-Za-z0-9_.+\/-]+"$/ : value !~ /^"[A-Za-z0-9_.+-]+"$/)) exit 2
+      value = substr(value, 2, length(value) - 2)
+    }
+    END { if (count != 1 || value == "") exit 2; print value }
+  ' "$1"
+}
+
+export POSTGRES_SOURCE_TOML="${POSTGRES_SOURCE_TOML:-$REPO_ROOT/src/third-party/postgres/source.toml}"
+POSTGRES_VERSION="${POSTGRES_VERSION:-$(fresh_source_scalar "$POSTGRES_SOURCE_TOML" version)}" || return 2
+export POSTGRES_VERSION
+export POSTGRES_TAG="${POSTGRES_TAG:-REL_${POSTGRES_VERSION//./_}}"
+export BASELINE_DIR="${BASELINE_DIR:-$FRESH_WORK_ROOT/sources/postgresql-$POSTGRES_VERSION}"
+export WASIX_SRC_DIR="${WASIX_SRC_DIR:-$FRESH_WORK_ROOT/work/postgres-wasix-core-src}"
+export CLIENT_TOOLS_BUILD_DIR="${CLIENT_TOOLS_BUILD_DIR:-$FRESH_WORK_ROOT/builds/native-client-tools}"
+export CLIENT_TOOLS_INSTALL_DIR="${CLIENT_TOOLS_INSTALL_DIR:-$FRESH_WORK_ROOT/install/native-client-tools}"
+export FRESH_WASIX_DOCKER_IMAGE="${FRESH_WASIX_DOCKER_IMAGE:-oliphaunt-wasix-wasix-build:local}"
+_fresh_wasmer_tag="$(fresh_source_scalar "$REPO_ROOT/src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer.toml" branch)" || return 2
+export FRESH_WASMER_VERSION="${FRESH_WASMER_VERSION:-${_fresh_wasmer_tag#v}}"
+export FRESH_WASMER_WASIX_VERSION="${FRESH_WASMER_WASIX_VERSION:-0.702.0-alpha.2}"
+export FRESH_WASMER_COMPILER_FEATURES="${FRESH_WASMER_COMPILER_FEATURES:-llvm,wat}"
+export FRESH_WASMER_HEADLESS_FEATURES="${FRESH_WASMER_HEADLESS_FEATURES:-headless-minimal}"
+export FRESH_POSTMASTER_EXECUTOR_PACKAGE="oliphaunt-wasix-postmaster-executor"
+export FRESH_POSTMASTER_EXECUTOR_BINARY="oliphaunt-wasix-postmaster-executor"
+export FRESH_POSTMASTER_EXECUTOR_FEATURES="product-executor"
+export FRESH_START_PROOF_BINARY="oliphaunt-wasix-start-proof"
+export FRESH_START_PROOF_FEATURES="start-proof-tool"
+export FRESH_START_PROOF_POLICY="llvm-shared-memory-init-restricted-effects.v1"
+export FRESH_MEMORY_PROFILE_BINARY="oliphaunt-wasix-memory-profile"
+export FRESH_MEMORY_PROFILE_FEATURES="memory-profile-tool"
+export FRESH_LINEAR_MEMORY_PROFILE_ID="oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1"
+export FRESH_LINEAR_MEMORY_MAXIMUM_PAGES="4096"
+export FRESH_LINEAR_MEMORY_STATIC_BOUND_PAGES="65536"
+export FRESH_LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES="2147483648"
+export FRESH_POSTMASTER_COMPILER_BINARY="oliphaunt-wasix-postmaster-compiler"
+export FRESH_POSTMASTER_COMPILER_FEATURES="product-compiler"
+export FRESH_POSTMASTER_EXECUTOR_ROLE="postmaster-product"
+export FRESH_POSTMASTER_TASK_BUDGET_PROFILE="$FRESH_ROOT/profiles/runtime-task-budgets/embedded-postmaster-v1.tsv"
+export FRESH_POSTMASTER_RUNTIME_FOOTPRINT_PROFILE="$FRESH_ROOT/profiles/runtime-footprints/embedded-concurrent-v1.gucs"
+export FRESH_POSTMASTER_TASK_BUDGET_PROFILE_ID="embedded-postmaster-v1"
+export FRESH_POSTMASTER_HOST_TASK_BUDGET="96"
+export FRESH_POSTMASTER_BLOCKING_CORE_THREADS="1"
+export FRESH_POSTMASTER_BLOCKING_WORKER_IDLE_TIMEOUT_MS="1000"
+export FRESH_POSTMASTER_EXECUTOR_RUNTIME_POLICY_ID="oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2"
+export FRESH_POSTMASTER_EXECUTOR_CLI_CONTRACT="sealed-postmaster-run-v1"
+export FRESH_WASMER_ARTIFACT_ABI_VERSION="${FRESH_WASMER_ARTIFACT_ABI_VERSION:-21}"
+FRESH_WASMER_SOURCE_COMMIT="${FRESH_WASMER_SOURCE_COMMIT:-$(fresh_source_scalar "$REPO_ROOT/src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer.toml" commit)}" || return 2
+export FRESH_WASMER_SOURCE_COMMIT
+FRESH_WASMER_NAPI_COMMIT="${FRESH_WASMER_NAPI_COMMIT:-$(fresh_source_scalar "$REPO_ROOT/src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer-napi.toml" commit)}" || return 2
+export FRESH_WASMER_NAPI_COMMIT
+FRESH_WASMER_TEST_FILES_COMMIT="${FRESH_WASMER_TEST_FILES_COMMIT:-$(fresh_source_scalar "$REPO_ROOT/src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer-test-files.toml" commit)}" || return 2
+export FRESH_WASMER_TEST_FILES_COMMIT
+FRESH_WASMER_SPEC_COMMIT="${FRESH_WASMER_SPEC_COMMIT:-$(fresh_source_scalar "$REPO_ROOT/src/runtimes/liboliphaunt-wasix-postmaster/sources/webassembly-testsuite.toml" commit)}" || return 2
+export FRESH_WASMER_SPEC_COMMIT
+FRESH_WASIX_LIBC_SOURCE_COMMIT="${FRESH_WASIX_LIBC_SOURCE_COMMIT:-$(fresh_source_scalar "$REPO_ROOT/src/runtimes/liboliphaunt-wasix-postmaster/sources/wasix-libc.toml" commit)}" || return 2
+export FRESH_WASIX_LIBC_SOURCE_COMMIT
+export FRESH_UPSTREAM_WASMER_BIN="${FRESH_UPSTREAM_WASMER_BIN:-$FRESH_WORK_ROOT/runtime/wasmer/target/release/wasmer}"
+export FRESH_UPSTREAM_WASMER_HEADLESS_BIN="${FRESH_UPSTREAM_WASMER_HEADLESS_BIN:-$FRESH_WORK_ROOT/runtime/wasmer/target/release/wasmer-headless}"
+export FRESH_WASMER_BUILD_RECEIPT="${FRESH_WASMER_BUILD_RECEIPT:-$FRESH_WORK_ROOT/runtime/build/wasmer-build.receipt}"
+export FRESH_POSTMASTER_EXECUTOR_TARGET_DIR="${FRESH_POSTMASTER_EXECUTOR_TARGET_DIR:-$FRESH_WORK_ROOT/runtime/postmaster-executor-target}"
+export FRESH_POSTMASTER_EXECUTOR_BIN="${FRESH_POSTMASTER_EXECUTOR_BIN:-$FRESH_POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_POSTMASTER_EXECUTOR_BINARY}"
+export FRESH_START_PROOF_BIN="${FRESH_START_PROOF_BIN:-$FRESH_POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_START_PROOF_BINARY}"
+export FRESH_MEMORY_PROFILE_BIN="${FRESH_MEMORY_PROFILE_BIN:-$FRESH_POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_MEMORY_PROFILE_BINARY}"
+export FRESH_POSTMASTER_COMPILER_TARGET_DIR="${FRESH_POSTMASTER_COMPILER_TARGET_DIR:-$FRESH_WORK_ROOT/runtime/postmaster-compiler-target}"
+export FRESH_POSTMASTER_COMPILER_BIN="${FRESH_POSTMASTER_COMPILER_BIN:-$FRESH_POSTMASTER_COMPILER_TARGET_DIR/release/$FRESH_POSTMASTER_COMPILER_BINARY}"
+export FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT="${FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT:-$FRESH_WORK_ROOT/runtime/build/postmaster-executor-build.receipt}"
+export FRESH_PATCHED_WASIXCC_SYSROOT_PREFIX="${FRESH_PATCHED_WASIXCC_SYSROOT_PREFIX:-$FRESH_WORK_ROOT/runtime/build/patched-wasixcc-sysroot}"
+export WASIXCC_SYSROOT_VARIANT="${WASIXCC_SYSROOT_VARIANT:-sysroot-exnref-ehpic}"
+export WASIXCC_SYSROOT_PREFIX="${WASIXCC_SYSROOT_PREFIX:-$FRESH_PATCHED_WASIXCC_SYSROOT_PREFIX}"
+export WASIXCC_SYSROOT="${WASIXCC_SYSROOT:-$WASIXCC_SYSROOT_PREFIX/$WASIXCC_SYSROOT_VARIANT}"
+
+fresh_validate_postmaster_task_budget_profile() {
+  local profile="${1:-$FRESH_POSTMASTER_TASK_BUDGET_PROFILE}"
+  local footprint="${2:-$FRESH_POSTMASTER_RUNTIME_FOOTPRINT_PROFILE}"
+  local max_connections
+  local max_wal_senders
+  local autovacuum_worker_slots
+  local max_worker_processes
+  local io_method
+  local profile_key
+  local profile_value
+
+  [ -f "$profile" ] && [ ! -L "$profile" ] || {
+    printf 'missing regular postmaster task-budget profile: %s\n' "$profile" >&2
+    return 2
+  }
+  [ -f "$footprint" ] && [ ! -L "$footprint" ] || {
+    printf 'missing regular postmaster runtime-footprint profile: %s\n' "$footprint" >&2
+    return 2
+  }
+  for profile_key in \
+    max_connections max_wal_senders autovacuum_worker_slots max_worker_processes io_method
+  do
+    profile_value="$(awk -F= -v expected="$profile_key" '
+      $1 == expected { count += 1; value = substr($0, index($0, "=") + 1) }
+      END { if (count != 1 || value == "") exit 2; print value }
+    ' "$footprint")" || {
+      printf 'runtime-footprint profile must contain one %s: %s\n' \
+        "$profile_key" "$footprint" >&2
+      return 2
+    }
+    case "$profile_key" in
+      max_connections) max_connections="$profile_value" ;;
+      max_wal_senders) max_wal_senders="$profile_value" ;;
+      autovacuum_worker_slots) autovacuum_worker_slots="$profile_value" ;;
+      max_worker_processes) max_worker_processes="$profile_value" ;;
+      io_method) io_method="$profile_value" ;;
+    esac
+  done
+  [ "$max_connections" = 8 ] && [ "$max_wal_senders" = 10 ] && \
+    [ "$autovacuum_worker_slots" = 4 ] && [ "$max_worker_processes" = 8 ] && \
+    [ "$io_method" = sync ] || {
+    printf 'postmaster task budget does not match runtime-footprint GUC capacity: %s\n' \
+      "$footprint" >&2
+    return 2
+  }
+  awk -F '\t' \
+    -v expected_id="$FRESH_POSTMASTER_TASK_BUDGET_PROFILE_ID" \
+    -v expected_budget="$FRESH_POSTMASTER_HOST_TASK_BUDGET" \
+    -v expected_core="$FRESH_POSTMASTER_BLOCKING_CORE_THREADS" \
+    -v expected_idle_ms="$FRESH_POSTMASTER_BLOCKING_WORKER_IDLE_TIMEOUT_MS" '
+    BEGIN {
+      header = "schema_version\tprofile_id\tstatus\tpostgres_major\truntime_footprint\tmax_backends\tbackend_authentication_overlap\tmax_io_worker_slots\tfixed_non_max_backends_pmchild_roles\ttracked_child_capacity\tpostmaster_tasks\treserve_tasks\thost_task_budget\tblocking_core_threads\tblocking_worker_idle_timeout_ms"
+    }
+    NR == 1 {
+      if ($0 != header) exit 2
+      next
+    }
+    NR == 2 {
+      if (NF != 15 ||
+          $1 != "oliphaunt.wasix-postmaster.runtime-task-budget.v1" ||
+          $2 != expected_id ||
+          $3 != "supported" ||
+          $4 != "18" ||
+          $5 != "embedded-concurrent") exit 2
+      for (i = 6; i <= 15; i++)
+        if ($i !~ /^(0|[1-9][0-9]*)$/) exit 2
+      if ($6 != 32 || $7 != 18 || $8 != 32 || $9 != 8) exit 2
+      if ($10 != $6 + $7 + $8 + $9) exit 2
+      if ($13 != $10 + $11 + $12) exit 2
+      if ($13 != expected_budget || $14 != expected_core ||
+          $15 != expected_idle_ms || $14 < 1 || $14 > $13 || $15 < 1) exit 2
+      next
+    }
+    { exit 2 }
+    END { if (NR != 2) exit 2 }
+  ' "$profile" || {
+    printf 'invalid or non-canonical postmaster task-budget profile: %s\n' "$profile" >&2
+    return 2
+  }
+}
+
+fresh_normalize_wasix_core_profile() {
+  case "${1:-safe-o2}" in
+    current|baseline|safe|safe-o2) echo "safe-o2" ;;
+    o3) echo "o3" ;;
+    o3-wasmopt|o3-wasm-opt) echo "o3-wasmopt" ;;
+    o3-thinlto) echo "o3-thinlto" ;;
+    release-o3|perf|production) echo "release-o3" ;;
+    release-o3-symbols|perf-symbols|profile-o3) echo "release-o3-symbols" ;;
+    *)
+      echo "unknown WASIX_CORE_PROFILE=$1; expected safe-o2, o3, o3-wasmopt, o3-thinlto, release-o3, or release-o3-symbols" >&2
+      return 2
+      ;;
+  esac
+}
+
+WASIX_CORE_PROFILE="$(fresh_normalize_wasix_core_profile "${WASIX_CORE_PROFILE:-release-o3}")"
+export WASIX_CORE_PROFILE
+
+fresh_wasix_core_profile_suffix_for() {
+  case "$(fresh_normalize_wasix_core_profile "$1")" in
+    safe-o2) printf '' ;;
+    *) printf -- '-%s' "$(fresh_normalize_wasix_core_profile "$1")" ;;
+  esac
+}
+
+fresh_wasix_core_build_dir_for() {
+  printf '%s/builds/wasix-core%s\n' "$FRESH_WORK_ROOT" "$(fresh_wasix_core_profile_suffix_for "$1")"
+}
+
+source "$FRESH_ROOT/lib/guest-generation.sh"
+
+fresh_wasix_core_install_base_for() {
+  printf '%s/install/wasix-core%s\n' "$FRESH_WORK_ROOT" "$(fresh_wasix_core_profile_suffix_for "$1")"
+}
+
+fresh_wasix_core_install_dir_for() {
+  fresh_resolve_guest_generation "$(fresh_wasix_core_install_base_for "$1")"
+}
+
+fresh_wasix_core_report_dir_for() {
+  case "$(fresh_normalize_wasix_core_profile "$1")" in
+    safe-o2) printf '%s/reports\n' "$FRESH_WORK_ROOT" ;;
+    *) printf '%s/reports/%s\n' "$FRESH_WORK_ROOT" "$(fresh_normalize_wasix_core_profile "$1")" ;;
+  esac
+}
+
+fresh_wasix_core_run_dir_for() {
+  case "$(fresh_normalize_wasix_core_profile "$1")" in
+    safe-o2) printf '%s/run\n' "$FRESH_WORK_ROOT" ;;
+    *) printf '%s/run/%s\n' "$FRESH_WORK_ROOT" "$(fresh_normalize_wasix_core_profile "$1")" ;;
+  esac
+}
+
+export WASIX_BUILD_DIR="${WASIX_BUILD_DIR:-$(fresh_wasix_core_build_dir_for "$WASIX_CORE_PROFILE")}"
+export WASIX_INSTALL_DIR="${WASIX_INSTALL_DIR:-$(fresh_wasix_core_install_dir_for "$WASIX_CORE_PROFILE")}"
+export REPORT_DIR="${REPORT_DIR:-$(fresh_wasix_core_report_dir_for "$WASIX_CORE_PROFILE")}"
+export RUN_DIR="${RUN_DIR:-$(fresh_wasix_core_run_dir_for "$WASIX_CORE_PROFILE")}"
+
+fresh_resolve_wasix_core_profile() {
+  local profile="${1:-$WASIX_CORE_PROFILE}"
+  profile="$(fresh_normalize_wasix_core_profile "$profile")"
+
+  case "$profile" in
+    safe-o2)
+      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="current conservative bring-up profile: O2, no wasm-opt, SIMD/vectorizers disabled"
+      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O2 -g0 -mno-simd128 -fno-vectorize -fno-slp-vectorize -fno-inline-functions-called-once -fno-unroll-loops -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
+      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-fPIC -pthread -sWASM_EXCEPTIONS=yes"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT="no"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS=""
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL="275"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL="233"
+      ;;
+    o3)
+      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="O3 codegen profile without LTO or Binaryen post-link optimization"
+      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
+      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-fPIC -pthread -sWASM_EXCEPTIONS=yes"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT="no"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS=""
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL=""
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=""
+      ;;
+    o3-wasmopt)
+      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="O3 plus Binaryen post-link converge/strip, without ThinLTO"
+      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
+      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-fPIC -pthread -sWASM_EXCEPTIONS=yes"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT="yes"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS="--converge:--strip-debug:--strip-producers"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL=""
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=""
+      ;;
+    o3-thinlto)
+      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="O3 plus ThinLTO, without Binaryen post-link optimization"
+      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
+      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT="no"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS=""
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL="1111"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=""
+      ;;
+    release-o3)
+      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="release-lane performance profile: O3, ThinLTO, and Binaryen converge/strip"
+      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
+      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT="yes"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS="--converge:--strip-debug:--strip-producers"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL="1111"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL="995"
+      ;;
+    release-o3-symbols)
+      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="release-lane profiling profile: O3, ThinLTO, and Binaryen converge while retaining Wasm symbol names"
+      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
+      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT="yes"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS="--converge:--debuginfo"
+      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL="1111"
+      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=""
+      ;;
+  esac
+
+  FRESH_WASIX_CORE_EFFECTIVE_CFLAGS="${WASIX_CORE_CFLAGS:-$FRESH_WASIX_CORE_PROFILE_CFLAGS}"
+  FRESH_WASIX_CORE_EFFECTIVE_LDFLAGS="${WASIX_CORE_LDFLAGS:-$FRESH_WASIX_CORE_PROFILE_LDFLAGS}"
+  FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT="${WASIXCC_RUN_WASM_OPT:-$FRESH_WASIX_CORE_PROFILE_WASM_OPT}"
+  FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_FLAGS="${WASIXCC_WASM_OPT_FLAGS:-$FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS}"
+  FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT="${WASIXCC_WASM_OPT_SUPPRESS_DEFAULT:-$FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT}"
+  FRESH_WASIX_CORE_EXPECTED_ATOMIC_FENCE_TOTAL="$FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL"
+  FRESH_WASIX_CORE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL="$FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL"
+
+  case "$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT" in
+    yes|true|1) FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT="yes" ;;
+    no|false|0) FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT="no" ;;
+    *)
+      printf 'invalid WASIXCC_WASM_OPT_SUPPRESS_DEFAULT=%s; expected yes or no\n' \
+        "$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT" >&2
+      return 2
+      ;;
+  esac
+}
+
+fresh_jobs() {
+  if command -v sysctl >/dev/null 2>&1; then
+    sysctl -n hw.ncpu 2>/dev/null && return
+  fi
+  if command -v nproc >/dev/null 2>&1; then
+    nproc 2>/dev/null && return
+  fi
+  echo 4
+}
+
+fresh_timestamp() {
+  date -u +"%Y-%m-%dT%H:%M:%SZ"
+}
+
+fresh_require_command() {
+  local name="$1"
+  if ! command -v "$name" >/dev/null 2>&1; then
+    echo "missing required command: $name" >&2
+    return 127
+  fi
+}
+
+# Return the stable repository identity for a file in this product source
+# tree.  Measurement tools may execute from a content-addressed physical copy
+# under target/, but build receipts must continue naming the canonical source
+# location.  Mixing those two identities makes byte-identical frozen tools
+# reject artifacts produced from the ordinary checkout.
+fresh_project_source_identity_path() {
+  local path="${1-}"
+  local relative
+
+  [ "$#" -eq 1 ] && [ -n "$path" ] && [ "${path#/}" != "$path" ] || {
+    printf 'fresh_project_source_identity_path requires one absolute path\n' >&2
+    return 2
+  }
+  case "$path" in
+    "$FRESH_ROOT"/*)
+      relative="${path#"$FRESH_ROOT"/}"
+      ;;
+    *)
+      printf 'source path is outside FRESH_ROOT: %s\n' "$path" >&2
+      return 2
+      ;;
+  esac
+  case "$relative" in
+    ""|/*|.|..|*/../*|../*|*/..|*/./*|./*|*/.)
+      printf 'source path is not canonical beneath FRESH_ROOT: %s\n' "$path" >&2
+      return 2
+      ;;
+  esac
+  printf '%s/%s\n' "$FRESH_PROJECT_SOURCE_ID_PREFIX" "$relative"
+}
+
+fresh_require_patched_wasixcc_sysroot() {
+  local carrier_manifest="$WASIXCC_SYSROOT_PREFIX/.oliphaunt-patched-sysroots.manifest"
+  local variant_manifest="$WASIXCC_SYSROOT/.oliphaunt-patched-sysroot.manifest"
+  local validator="$FRESH_ROOT/wasmer/bin/validate-runtime-capabilities.sh"
+
+  if [ ! -f "$carrier_manifest" ] || [ ! -f "$variant_manifest" ]; then
+    {
+      printf 'missing exact patched WASIX libc carrier: %s\n' "$WASIXCC_SYSROOT"
+      printf 'Run %s/wasmer/bin/build-patched-wasix-libc-sysroot.sh after preparing the pinned runtime sources.\n' "$FRESH_ROOT"
+    } >&2
+    return 2
+  fi
+
+  [ -x "$validator" ] || {
+    printf 'missing exact patched WASIX libc validator: %s\n' "$validator" >&2
+    return 2
+  }
+  UPSTREAM_WORK_ROOT="$FRESH_WORK_ROOT/runtime" \
+    WASIXCC_SYSROOT_PREFIX="$WASIXCC_SYSROOT_PREFIX" \
+    WASIXCC_SYSROOT_VARIANT="$WASIXCC_SYSROOT_VARIANT" \
+    WASIXCC_SYSROOT="$WASIXCC_SYSROOT" \
+    "$validator" --validate-sysroot-only >/dev/null
+}
+
+fresh_docker_bin() {
+  if command -v docker >/dev/null 2>&1; then
+    command -v docker
+    return
+  fi
+  echo "missing required command: docker" >&2
+  return 127
+}
+
+fresh_docker_path_for() {
+  local path="$1"
+
+  case "$path" in
+    "$REPO_ROOT")
+      printf '/work\n'
+      ;;
+    "$REPO_ROOT"/*)
+      printf '/work/%s\n' "${path#$REPO_ROOT/}"
+      ;;
+    *)
+      printf '%s\n' "$path"
+      ;;
+  esac
+}
+
+fresh_managed_generated_root() {
+  printf '%s/target/oliphaunt-wasix-postmaster\n' "$_fresh_source_repo_root"
+}
+
+# Fail closed before a builder removes or replaces generated output.  The
+# trust root is derived physically from this file, rather than from the
+# overridable REPO_ROOT or FRESH_WORK_ROOT variables. Rejecting every existing
+# symlink component is deliberately stricter than resolving and following it.
+fresh_require_managed_generated_path() {
+  local candidate="${1-}"
+  local label="${2:-generated path}"
+  local managed_root
+  local remainder
+  local component
+  local current=""
+  local has_more
+
+  if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
+    printf 'fresh_require_managed_generated_path expects a path and optional label\n' >&2
+    return 2
+  fi
+
+  managed_root="$(fresh_managed_generated_root)"
+  if [ -z "$candidate" ]; then
+    printf 'refusing empty %s\n' "$label" >&2
+    return 2
+  fi
+  case "$candidate" in
+    /*) ;;
+    *)
+      printf 'refusing non-absolute %s: %s\n' "$label" "$candidate" >&2
+      return 2
+      ;;
+  esac
+  if [ "$candidate" = "/" ] || [ "$candidate" = "$managed_root" ]; then
+    printf 'refusing unsafe %s root: %s\n' "$label" "$candidate" >&2
+    return 2
+  fi
+  case "$candidate" in
+    "$managed_root"/*) ;;
+    *)
+      printf 'refusing %s outside managed generated root %s: %s\n' \
+        "$label" "$managed_root" "$candidate" >&2
+      return 2
+      ;;
+  esac
+
+  remainder="${candidate#/}"
+  while :; do
+    case "$remainder" in
+      */*)
+        component="${remainder%%/*}"
+        remainder="${remainder#*/}"
+        has_more=1
+        ;;
+      *)
+        component="$remainder"
+        remainder=""
+        has_more=0
+        ;;
+    esac
+
+    case "$component" in
+      ""|.|..)
+        printf 'refusing non-canonical %s component in: %s\n' "$label" "$candidate" >&2
+        return 2
+        ;;
+    esac
+
+    current="$current/$component"
+    if [ -L "$current" ]; then
+      printf 'refusing symlink component in %s: %s\n' "$label" "$current" >&2
+      return 2
+    fi
+    if [ "$has_more" -eq 1 ] && [ -e "$current" ] && [ ! -d "$current" ]; then
+      printf 'refusing non-directory component in %s: %s\n' "$label" "$current" >&2
+      return 2
+    fi
+    [ "$has_more" -eq 1 ] || break
+  done
+}
+
+# Reserve one or more generated leaf directories without replacement. Parents
+# may be shared, but each requested leaf is claimed with plain mkdir so two
+# equal qualification labels cannot enter the same evidence namespace. No
+# caller writes until every leaf is held; a partial claim is rolled back only
+# while it remains empty.
+fresh_claim_generated_directories() {
+  local -a requested=("$@")
+  local -a claimed=()
+  local path other parent
+  local index
+
+  [ "${#requested[@]}" -gt 0 ] || {
+    printf 'fresh_claim_generated_directories requires at least one path\n' >&2
+    return 2
+  }
+  for path in "${requested[@]}"; do
+    fresh_require_managed_generated_path "$path" "generated directory claim" ||
+      return
+    for other in "${claimed[@]}"; do
+      [ "$path" != "$other" ] || {
+        printf 'duplicate generated directory claim: %s\n' "$path" >&2
+        return 2
+      }
+    done
+    claimed+=("$path")
+  done
+
+  claimed=()
+  for path in "${requested[@]}"; do
+    parent="$(dirname "$path")"
+    fresh_require_managed_generated_path "$parent" "generated claim parent" ||
+      return
+    mkdir -p "$parent" || return
+    fresh_require_managed_generated_path "$path" "generated directory claim" ||
+      return
+  done
+  for path in "${requested[@]}"; do
+    if ! mkdir -- "$path"; then
+      printf 'generated directory is already claimed: %s\n' "$path" >&2
+      for ((index = ${#claimed[@]} - 1; index >= 0; index--)); do
+        rmdir -- "${claimed[$index]}" 2>/dev/null || true
+      done
+      return 2
+    fi
+    claimed+=("$path")
+  done
+}
+
+fresh_ensure_dirs() {
+  mkdir -p "$REPORT_DIR" "$RUN_DIR" "$FRESH_WORK_ROOT/sources" "$FRESH_WORK_ROOT/work" \
+    "$FRESH_WORK_ROOT/builds" "$FRESH_WORK_ROOT/install" "$FRESH_WORK_ROOT/tools"
+}
+
+# Serialize publication and consumption of the canonical PostgreSQL baseline.
+# Callers keep the descriptor open for the complete interval in which they read
+# BASELINE_DIR. The permanent lock file lives outside that replaceable directory,
+# so staged publication cannot change the synchronization object.
+fresh_lock_postgres_baseline() {
+  local mode="${1-}"
+  local lock_dir="$FRESH_WORK_ROOT/baseline-locks"
+  local lock_path
+
+  [ "$#" -eq 1 ] || {
+    printf 'fresh_lock_postgres_baseline expects shared or exclusive\n' >&2
+    return 2
+  }
+  case "$mode" in
+    shared) mode=-s ;;
+    exclusive) mode=-x ;;
+    *)
+      printf 'invalid PostgreSQL baseline lock mode: %s\n' "$mode" >&2
+      return 2
+      ;;
+  esac
+  [ -z "${FRESH_POSTGRES_BASELINE_LOCK_FD:-}" ] || {
+    printf 'PostgreSQL baseline lock is already held by this shell\n' >&2
+    return 2
+  }
+  fresh_require_command flock || return
+  fresh_require_managed_generated_path "$BASELINE_DIR" BASELINE_DIR || return
+  fresh_require_managed_generated_path "$lock_dir" postgres-baseline-locks || return
+  mkdir -p "$lock_dir"
+  [ -d "$lock_dir" ] && [ ! -L "$lock_dir" ] || {
+    printf 'unsafe PostgreSQL baseline lock directory: %s\n' "$lock_dir" >&2
+    return 2
+  }
+  lock_path="$lock_dir/postgres-baseline.lock"
+  fresh_require_managed_generated_path "$lock_path" postgres-baseline-lock || return
+  [ ! -L "$lock_path" ] || {
+    printf 'unsafe PostgreSQL baseline lock: %s\n' "$lock_path" >&2
+    return 2
+  }
+  exec {FRESH_POSTGRES_BASELINE_LOCK_FD}>"$lock_path"
+  [ -f "$lock_path" ] && [ ! -L "$lock_path" ] || {
+    printf 'PostgreSQL baseline lock changed while opening: %s\n' "$lock_path" >&2
+    exec {FRESH_POSTGRES_BASELINE_LOCK_FD}>&-
+    unset FRESH_POSTGRES_BASELINE_LOCK_FD
+    return 2
+  }
+  flock "$mode" "$FRESH_POSTGRES_BASELINE_LOCK_FD" || {
+    printf 'could not acquire PostgreSQL baseline lock: %s\n' "$lock_path" >&2
+    exec {FRESH_POSTGRES_BASELINE_LOCK_FD}>&-
+    unset FRESH_POSTGRES_BASELINE_LOCK_FD
+    return 2
+  }
+  FRESH_POSTGRES_BASELINE_LOCK_PATH="$lock_path"
+}
+
+fresh_unlock_postgres_baseline() {
+  if [ -n "${FRESH_POSTGRES_BASELINE_LOCK_FD:-}" ]; then
+    exec {FRESH_POSTGRES_BASELINE_LOCK_FD}>&-
+  fi
+  unset FRESH_POSTGRES_BASELINE_LOCK_FD
+  unset FRESH_POSTGRES_BASELINE_LOCK_PATH
+}
+
+fresh_postgres_baseline_fingerprint() {
+  local version
+  local archive_sha256
+
+  [ -f "$POSTGRES_SOURCE_TOML" ] && [ ! -L "$POSTGRES_SOURCE_TOML" ] || {
+    printf 'missing regular PostgreSQL source manifest: %s\n' "$POSTGRES_SOURCE_TOML" >&2
+    return 2
+  }
+  version="$(fresh_source_scalar "$POSTGRES_SOURCE_TOML" version)" || return 2
+  archive_sha256="$(fresh_source_scalar "$POSTGRES_SOURCE_TOML" sha256)" || return 2
+  [ "$version" = "$POSTGRES_VERSION" ] && fresh_is_sha256 "$archive_sha256" || {
+    printf 'invalid PostgreSQL baseline source identity in %s\n' \
+      "$POSTGRES_SOURCE_TOML" >&2
+    return 2
+  }
+  printf '%s:%s\n' "$version" "$archive_sha256"
+}
+
+# Validate that BASELINE_DIR is the exact clean Git tree materialized from the
+# pinned PostgreSQL archive.  The manifest lives inside the checkout so an
+# overridden BASELINE_DIR cannot accidentally inherit another checkout's
+# global fingerprint.
+fresh_require_postgres_baseline() {
+  local expected_fingerprint="${1-}"
+  local manifest="$BASELINE_DIR/.git/oliphaunt-baseline.manifest"
+  local head
+  local tree
+
+  [ "$#" -eq 1 ] && [ -n "$expected_fingerprint" ] || {
+    printf 'fresh_require_postgres_baseline requires an expected fingerprint\n' >&2
+    return 2
+  }
+  [ -d "$BASELINE_DIR" ] && [ ! -L "$BASELINE_DIR" ] &&
+    [ -d "$BASELINE_DIR/.git" ] && [ ! -L "$BASELINE_DIR/.git" ] &&
+    [ -f "$manifest" ] && [ ! -L "$manifest" ] || return 1
+  fresh_require_manifest_value "$manifest" schema \
+    oliphaunt.wasix-postmaster.postgres-baseline.v1 >/dev/null 2>&1 || return 1
+  fresh_require_manifest_value "$manifest" fingerprint \
+    "$expected_fingerprint" >/dev/null 2>&1 || return 1
+  head="$(git -C "$BASELINE_DIR" rev-parse --verify 'HEAD^{commit}' 2>/dev/null)" || return 1
+  tree="$(git -C "$BASELINE_DIR" rev-parse --verify 'HEAD^{tree}' 2>/dev/null)" || return 1
+  fresh_require_manifest_value "$manifest" head "$head" >/dev/null 2>&1 || return 1
+  fresh_require_manifest_value "$manifest" tree "$tree" >/dev/null 2>&1 || return 1
+  [ -z "$(git -C "$BASELINE_DIR" status --porcelain=v1 --untracked-files=all --ignored 2>/dev/null)" ] || return 1
+  FRESH_POSTGRES_BASELINE_HEAD="$head"
+  FRESH_POSTGRES_BASELINE_TREE="$tree"
+}
+
+fresh_host_arch() {
+  case "$(uname -s)-$(uname -m)" in
+    Darwin-arm64) echo "darwin-arm64" ;;
+    Darwin-x86_64) echo "darwin-amd64" ;;
+    Linux-x86_64) echo "linux-amd64" ;;
+    Linux-aarch64|Linux-arm64) echo "linux-arm64" ;;
+    *)
+      echo "unsupported host for patched Wasmer runtime: $(uname -s)-$(uname -m)" >&2
+      return 2
+      ;;
+  esac
+}
+
+fresh_host_abi() {
+  local ldd_version
+  local glibc_version
+
+  case "$(uname -s)" in
+    Darwin) echo "darwin" ;;
+    Linux)
+      glibc_version="$(getconf GNU_LIBC_VERSION 2>/dev/null || true)"
+      if [ -n "$glibc_version" ]; then
+        echo "linux-gnu"
+        return
+      fi
+      if command -v ldd >/dev/null 2>&1; then
+        ldd_version="$(ldd --version 2>&1 | head -1 || true)"
+        case "$ldd_version" in
+          *musl*|*Musl*) echo "linux-musl"; return ;;
+          *GLIBC*|*glibc*|*GNU*) echo "linux-gnu"; return ;;
+        esac
+      fi
+      echo "unable to identify Linux libc ABI for patched Wasmer receipt" >&2
+      return 2
+      ;;
+    MINGW*|MSYS*|CYGWIN*) echo "windows-gnu" ;;
+    *)
+      echo "unsupported host ABI for patched Wasmer receipt: $(uname -s)" >&2
+      return 2
+      ;;
+  esac
+}
+
+fresh_release_target_for_host_arch() {
+  case "$1" in
+    darwin-arm64) echo "macos-arm64" ;;
+    linux-arm64) echo "linux-arm64-gnu" ;;
+    linux-amd64) echo "linux-x64-gnu" ;;
+    *)
+      printf 'unsupported WASIX postmaster release host: %s\n' "$1" >&2
+      return 2
+      ;;
+  esac
+}
+
+fresh_release_target() {
+  local host_arch
+  host_arch="$(fresh_host_arch)" || return
+  fresh_release_target_for_host_arch "$host_arch"
+}
+
+fresh_release_target_triple() {
+  case "$1" in
+    linux-arm64-gnu) echo "aarch64-unknown-linux-gnu" ;;
+    linux-x64-gnu) echo "x86_64-unknown-linux-gnu" ;;
+    macos-arm64) echo "aarch64-apple-darwin" ;;
+    *)
+      printf 'unsupported WASIX postmaster release target: %s\n' "$1" >&2
+      return 2
+      ;;
+  esac
+}
+
+fresh_manifest_value() {
+  local manifest="$1"
+  local key="$2"
+
+  awk -v expected_key="$key" '
+    {
+      separator = index($0, "=")
+      if (separator > 0 && substr($0, 1, separator - 1) == expected_key) {
+        count += 1
+        value = substr($0, separator + 1)
+      }
+    }
+    END {
+      if (count != 1) exit 2
+      print value
+    }
+  ' "$manifest"
+}
+
+fresh_require_manifest_value() {
+  local manifest="$1"
+  local key="$2"
+  local expected="$3"
+  local actual
+
+  if ! actual="$(fresh_manifest_value "$manifest" "$key")"; then
+    printf 'manifest must contain exactly one %s field: %s\n' "$key" "$manifest" >&2
+    return 2
+  fi
+  if [ "$actual" != "$expected" ]; then
+    printf 'manifest %s mismatch: expected %s, got %s\n' \
+      "$key" "$expected" "${actual:-}" >&2
+    return 2
+  fi
+}
+
+fresh_validate_wasmer_build_receipt_shape() {
+  local receipt="$1"
+
+  awk -F= '
+    BEGIN {
+      split("schema build_recipe_sha256 wasmer_source_commit wasmer_napi_commit wasmer_test_files_commit wasmer_spec_commit wasmer_patch_sha256 wasmer_prepared_signature_sha256 wasmer_cargo_lock_sha256 wasmer_binary_sha256 wasmer_features wasmer_headless_binary_sha256 wasmer_headless_features runtime_abi_id artifact_abi_version wasix_libc_source_commit wasix_libc_patch_sha256 wasix_libc_prepared_signature_sha256 sysroot_carrier_manifest_sha256 sysroot_variant sysroot_variant_manifest_sha256 host_platform host_abi rustc_host rustc_version llvm_version", fields, " ")
+      for (i in fields) allowed[fields[i]] = 1
+    }
+    index($0, "\r") || NF != 2 || $1 == "" || $2 == "" || !($1 in allowed) || seen[$1]++ || $1 != fields[NR] { exit 2 }
+    END {
+      if (NR != 26) exit 2
+      for (key in allowed) if (seen[key] != 1) exit 2
+    }
+  ' "$receipt" || {
+    printf 'invalid or non-canonical Wasmer build receipt: %s\n' "$receipt" >&2
+    return 2
+  }
+}
+
+fresh_validate_postmaster_executor_build_receipt_shape() {
+  local receipt="$1"
+
+  awk -F= '
+    BEGIN {
+      split("schema build_recipe_sha256 wasmer_build_receipt_sha256 wasmer_source_commit wasmer_patch_sha256 wasmer_prepared_signature_sha256 wasmer_cargo_lock_sha256 runtime_abi_id artifact_abi_version executor_package executor_binary executor_features executor_role runtime_policy_id cli_contract executor_binary_sha256 start_proof_binary start_proof_features start_proof_policy start_proof_binary_sha256 memory_profile_binary memory_profile_features linear_memory_profile_id memory_profile_binary_sha256 postmaster_compiler_binary postmaster_compiler_features compiler_cpu_policy compiler_cpu_features postmaster_compiler_binary_sha256 host_platform host_abi rustc_host rustc_version", fields, " ")
+      for (i in fields) allowed[fields[i]] = 1
+    }
+    index($0, "\r") || NF != 2 || $1 == "" || $2 == "" || !($1 in allowed) || seen[$1]++ || $1 != fields[NR] { exit 2 }
+    END {
+      if (NR != 33) exit 2
+      for (key in allowed) if (seen[key] != 1) exit 2
+    }
+  ' "$receipt" || {
+    printf 'invalid or non-canonical postmaster executor build receipt: %s\n' "$receipt" >&2
+    return 2
+  }
+}
+
+fresh_is_sha256() {
+  [ "${#1}" -eq 64 ] || return 1
+  case "$1" in
+    *[!0-9a-f]*) return 1 ;;
+    *) return 0 ;;
+  esac
+}
+
+fresh_require_receipt_sha256() {
+  local receipt="$1"
+  local key="$2"
+  local value
+
+  value="$(fresh_manifest_value "$receipt" "$key")" || {
+    printf 'Wasmer build receipt must contain exactly one %s field: %s\n' "$key" "$receipt" >&2
+    return 2
+  }
+  fresh_is_sha256 "$value" || {
+    printf 'Wasmer build receipt %s is not a lowercase SHA-256: %s\n' "$key" "$receipt" >&2
+    return 2
+  }
+}
+
+fresh_sha256_stream() {
+  if command -v sha256sum >/dev/null 2>&1; then
+    sha256sum | awk '{print $1}'
+  else
+    shasum -a 256 | awk '{print $1}'
+  fi
+}
+
+fresh_require_canonical_directory() {
+  local label="${1-}"
+  local path="${2-}"
+  local resolved
+
+  [ "$#" -eq 2 ] && [ -n "$label" ] && [ -n "$path" ] && [ "${path#/}" != "$path" ] || {
+    printf 'canonical directory validation requires a label and absolute path\n' >&2
+    return 2
+  }
+  resolved="$(cd -P -- "$path" 2>/dev/null && pwd -P)" || {
+    printf '%s is not an existing directory: %s\n' "$label" "$path" >&2
+    return 2
+  }
+  [ "$resolved" = "$path" ] || {
+    printf '%s is not an absolute canonical directory: %s (resolved %s)\n' \
+      "$label" "$path" "$resolved" >&2
+    return 2
+  }
+}
+
+fresh_wasix_builder_recipe_sha256() {
+  local file_sha256
+  local identity_mode
+  local path
+  local recipe_paths=(
+    "$WASIX_TOOLCHAIN_ROOT/docker/Dockerfile"
+    "$WASIX_TOOLCHAIN_ROOT/docker/isrg-root-x1.pem"
+    "$WASIX_TOOLCHAIN_ROOT/docker/install-pinned-apt-packages.sh"
+    "$WASIX_TOOLCHAIN_ROOT/docker/install-pinned-wasixcc.sh"
+    "$WASIX_TOOLCHAIN_ROOT/docker/pinned-wasixcc-assets.tsv"
+  )
+
+  fresh_require_canonical_directory REPO_ROOT "$REPO_ROOT" || return
+  fresh_require_canonical_directory WASIX_TOOLCHAIN_ROOT "$WASIX_TOOLCHAIN_ROOT" || return
+  {
+    printf '%s\0%s\0' schema oliphaunt.wasix-builder-recipe.v1
+    for path in "${recipe_paths[@]}"; do
+      [ -f "$path" ] && [ ! -L "$path" ] || {
+        printf 'missing regular WASIX builder-recipe input: %s\n' "$path" >&2
+        return 2
+      }
+      file_sha256="$(fresh_wasmer_bin_hash "$path")" || return
+      fresh_is_sha256 "$file_sha256" || {
+        printf 'failed to hash WASIX builder-recipe input: %s\n' "$path" >&2
+        return 2
+      }
+      if [ -x "$path" ]; then
+        identity_mode=executable
+      else
+        identity_mode=data
+      fi
+      printf '%s\0%s\0%s\0' "${path#"$WASIX_TOOLCHAIN_ROOT"/}" "$file_sha256" "$identity_mode"
+    done
+  } | fresh_sha256_stream
+}
+
+fresh_executor_source_sha256() {
+  local path digest
+  fresh_require_canonical_directory executor "$FRESH_ROOT/executor" || return
+  [ -f "$FRESH_ROOT/executor/Cargo.toml" ] || return 2
+  fresh_require_canonical_directory executor-source "$FRESH_ROOT/executor/src" || return
+  (
+    cd "$FRESH_ROOT/executor"
+    while IFS= read -r -d '' path; do
+      [ -f "$path" ] && [ ! -L "$path" ] || exit 2
+      digest="$(fresh_wasmer_bin_hash "$path")" || exit 2
+      fresh_is_sha256 "$digest" || exit 2
+      printf '%s\0%s\0' "$path" "$digest"
+      if [ -x "$path" ]; then printf 'executable\0'; else printf 'data\0'; fi
+    done < <(find Cargo.toml Cargo.lock prepare-paths.mts src \( -type f -o -type l \) -print0 | LC_ALL=C sort -z)
+  ) | fresh_sha256_stream
+}
+
+fresh_runtime_build_recipe_sha256() {
+  local builder_recipe_sha256
+  local file_sha256
+  local identity_path
+  local identity_mode
+  local path
+  local recipe_paths=(
+    "$FRESH_ROOT/lib/common.sh"
+    "$FRESH_POSTMASTER_TASK_BUDGET_PROFILE"
+    "$FRESH_POSTMASTER_RUNTIME_FOOTPRINT_PROFILE"
+    "$FRESH_ROOT/wasmer/bin/prepare-upstream-checkouts.sh"
+    "$FRESH_ROOT/wasmer/bin/build-runtime.sh"
+    "$FRESH_ROOT/wasmer/bin/build-patched-wasix-libc-sysroot.sh"
+    "$FRESH_ROOT/wasmer/bin/validate-runtime-capabilities.sh"
+    "$WASIX_TOOLCHAIN_ROOT/docker_wasix_env.sh"
+  )
+
+  fresh_require_canonical_directory FRESH_ROOT "$FRESH_ROOT" || return
+  fresh_require_canonical_directory REPO_ROOT "$REPO_ROOT" || return
+  fresh_require_canonical_directory WASIX_TOOLCHAIN_ROOT "$WASIX_TOOLCHAIN_ROOT" || return
+
+  for path in "${recipe_paths[@]}"; do
+    [ -f "$path" ] && [ ! -L "$path" ] || {
+      printf 'missing regular runtime build-recipe input: %s\n' "$path" >&2
+      return 2
+    }
+  done
+  builder_recipe_sha256="$(fresh_wasix_builder_recipe_sha256)" || return
+  fresh_is_sha256 "$builder_recipe_sha256" || {
+    printf 'failed to derive WASIX builder-recipe identity\n' >&2
+    return 2
+  }
+  {
+    printf '%s\0%s\0' schema oliphaunt.wasix-postmaster.runtime-build-recipe.v3
+    printf '%s\0%s\0' wasix-builder-recipe-sha256 "$builder_recipe_sha256"
+    printf '%s\0%s\0' executor-source-sha256 "$(fresh_executor_source_sha256)"
+    for path in "${recipe_paths[@]}"; do
+      case "$path" in
+        "$FRESH_ROOT"/*)
+          identity_path="$(fresh_project_source_identity_path "$path")" || return
+          ;;
+        "$REPO_ROOT"/*)
+          identity_path="${path#"$REPO_ROOT"/}"
+          ;;
+        *)
+          # An explicitly overridden external toolchain remains bound to its
+          # absolute location. Product-local sources must always use the
+          # canonical repository identity above so a byte-identical frozen
+          # measurement closure validates the same receipt.
+          identity_path="$path"
+          ;;
+      esac
+      file_sha256="$(fresh_wasmer_bin_hash "$path")" || return
+      fresh_is_sha256 "$file_sha256" || {
+        printf 'failed to hash runtime build-recipe input: %s\n' "$path" >&2
+        return 2
+      }
+      if [ -x "$path" ]; then
+        identity_mode=executable
+      else
+        identity_mode=data
+      fi
+      printf '%s\0%s\0%s\0' "$identity_path" "$file_sha256" "$identity_mode"
+    done
+  } | fresh_sha256_stream
+}
+
+# This identity is embedded into both native executors at compile time and into
+# every sealed AOT carrier.  Keep the serialization explicit and
+# length-unambiguous: changing a source pin, patch, Cargo resolution, native
+# target/ABI, feature set, artifact ABI, or tracked build recipe changes the
+# identity and makes old compiler output fail closed under the new executor.
+fresh_runtime_abi_id() {
+  local cargo_lock_sha256="$1"
+  local target_triple="$2"
+  local host_platform="$3"
+  local host_abi="$4"
+  local wasmer_patch="$FRESH_ROOT/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch"
+  local wasix_libc_patch="$FRESH_ROOT/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
+
+  fresh_is_sha256 "$cargo_lock_sha256" || {
+    printf 'runtime ABI Cargo.lock identity is not a lowercase SHA-256\n' >&2
+    return 2
+  }
+  [ -n "$target_triple" ] && [ -n "$host_platform" ] && [ -n "$host_abi" ] || {
+    printf 'runtime ABI target and host identity fields must be nonempty\n' >&2
+    return 2
+  }
+  [ -f "$wasmer_patch" ] && [ ! -L "$wasmer_patch" ] || return 2
+  [ -f "$wasix_libc_patch" ] && [ ! -L "$wasix_libc_patch" ] || return 2
+
+  {
+    printf '%s\0%s\0' schema oliphaunt.wasix-postmaster.runtime-abi.v1
+    printf '%s\0%s\0' wasmer-source-commit "$FRESH_WASMER_SOURCE_COMMIT"
+    printf '%s\0%s\0' wasmer-napi-commit "$FRESH_WASMER_NAPI_COMMIT"
+    printf '%s\0%s\0' wasmer-test-files-commit "$FRESH_WASMER_TEST_FILES_COMMIT"
+    printf '%s\0%s\0' wasmer-spec-commit "$FRESH_WASMER_SPEC_COMMIT"
+    printf '%s\0%s\0' wasmer-patch-sha256 "$(fresh_wasmer_bin_hash "$wasmer_patch")"
+    printf '%s\0%s\0' wasmer-cargo-lock-sha256 "$cargo_lock_sha256"
+    printf '%s\0%s\0' wasix-libc-source-commit "$FRESH_WASIX_LIBC_SOURCE_COMMIT"
+    printf '%s\0%s\0' wasix-libc-patch-sha256 "$(fresh_wasmer_bin_hash "$wasix_libc_patch")"
+    printf '%s\0%s\0' sysroot-variant "$WASIXCC_SYSROOT_VARIANT"
+    printf '%s\0%s\0' target-triple "$target_triple"
+    printf '%s\0%s\0' host-platform "$host_platform"
+    printf '%s\0%s\0' host-abi "$host_abi"
+    printf '%s\0%s\0' wasmer-version "$FRESH_WASMER_VERSION"
+    printf '%s\0%s\0' wasmer-wasix-version "$FRESH_WASMER_WASIX_VERSION"
+    printf '%s\0%s\0' compiler-features "$FRESH_WASMER_COMPILER_FEATURES"
+    printf '%s\0%s\0' headless-features "$FRESH_WASMER_HEADLESS_FEATURES"
+    printf '%s\0%s\0' artifact-abi-version "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
+    printf '%s\0%s\0' build-recipe-sha256 "$(fresh_runtime_build_recipe_sha256)"
+  } | fresh_sha256_stream
+}
+
+fresh_runtime_worktree_state_hash() {
+  local root="$1"
+  local path
+
+  {
+    git -C "$root" diff --binary HEAD
+    git -C "$root" ls-files --others --exclude-standard -z |
+      while IFS= read -r -d '' path; do
+        printf 'untracked:%s\n' "$path"
+        fresh_wasmer_bin_hash "$root/$path"
+      done
+  } | fresh_sha256_stream
+}
+
+fresh_require_prepared_worktree() {
+  local label="$1"
+  local root="$2"
+  local source_commit="$3"
+  local patch_hash="$4"
+  local extra_signature="$5"
+  local signature_file="$6"
+  local expected_signature
+
+  [ -d "$root/.git" ] && [ ! -L "$root" ] || {
+    printf 'missing prepared %s worktree: %s\n' "$label" "$root" >&2
+    return 2
+  }
+  [ -f "$signature_file" ] && [ ! -L "$signature_file" ] || {
+    printf 'missing regular prepared %s signature: %s\n' "$label" "$signature_file" >&2
+    return 2
+  }
+  [ "$(git -C "$root" rev-parse HEAD)" = "$source_commit" ] || {
+    printf 'prepared %s worktree is not at %s: %s\n' "$label" "$source_commit" "$root" >&2
+    return 2
+  }
+  expected_signature="$source_commit:$patch_hash:$extra_signature:$(fresh_runtime_worktree_state_hash "$root")"
+  [ "$(cat "$signature_file")" = "$expected_signature" ] || {
+    printf 'prepared %s worktree no longer matches its source-and-patch signature: %s\n' "$label" "$root" >&2
+    return 2
+  }
+}
+
+# Builder-only provenance verification. Runtime selection does not depend on
+# disposable source worktrees or the compilation sysroot being present.
+fresh_require_local_wasmer_build_state() {
+  local receipt="$1"
+  local runtime_root="$FRESH_WORK_ROOT/runtime"
+  local wasmer_root="$runtime_root/wasmer"
+  local wasix_libc_root="$runtime_root/wasix-libc"
+  local wasmer_signature="$runtime_root/.prepared/wasmer.signature"
+  local wasix_libc_signature="$runtime_root/.prepared/wasix-libc.signature"
+  local carrier_manifest="$WASIXCC_SYSROOT_PREFIX/.oliphaunt-patched-sysroots.manifest"
+  local variant_manifest="$WASIXCC_SYSROOT/.oliphaunt-patched-sysroot.manifest"
+  local wasmer_patch="$FRESH_ROOT/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch"
+  local wasix_libc_patch="$FRESH_ROOT/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
+  local wasmer_patch_hash
+  local wasix_libc_patch_hash
+
+  fresh_require_command git || return
+  wasmer_patch_hash="$(fresh_wasmer_bin_hash "$wasmer_patch")"
+  wasix_libc_patch_hash="$(fresh_wasmer_bin_hash "$wasix_libc_patch")"
+  fresh_require_prepared_worktree \
+    Wasmer "$wasmer_root" "$FRESH_WASMER_SOURCE_COMMIT" "$wasmer_patch_hash" \
+    "$FRESH_WASMER_NAPI_COMMIT:$FRESH_WASMER_TEST_FILES_COMMIT:$FRESH_WASMER_SPEC_COMMIT:$(fresh_executor_source_sha256)" \
+    "$wasmer_signature" || return
+  fresh_require_prepared_worktree \
+    wasix-libc "$wasix_libc_root" "$FRESH_WASIX_LIBC_SOURCE_COMMIT" "$wasix_libc_patch_hash" \
+    "" "$wasix_libc_signature" || return
+  [ -f "$wasmer_root/Cargo.lock" ] && [ ! -L "$wasmer_root/Cargo.lock" ] || {
+    printf 'missing regular Wasmer Cargo.lock: %s\n' "$wasmer_root/Cargo.lock" >&2
+    return 2
+  }
+  fresh_require_patched_wasixcc_sysroot || return
+  fresh_require_manifest_value \
+    "$receipt" wasmer_prepared_signature_sha256 "$(fresh_wasmer_bin_hash "$wasmer_signature")" || return
+  fresh_require_manifest_value \
+    "$receipt" build_recipe_sha256 "$(fresh_runtime_build_recipe_sha256)" || return
+  fresh_require_manifest_value \
+    "$receipt" wasmer_cargo_lock_sha256 "$(fresh_wasmer_bin_hash "$wasmer_root/Cargo.lock")" || return
+  fresh_require_manifest_value \
+    "$receipt" wasix_libc_prepared_signature_sha256 "$(fresh_wasmer_bin_hash "$wasix_libc_signature")" || return
+  fresh_require_manifest_value \
+    "$receipt" sysroot_carrier_manifest_sha256 "$(fresh_wasmer_bin_hash "$carrier_manifest")" || return
+  fresh_require_manifest_value \
+    "$receipt" sysroot_variant_manifest_sha256 "$(fresh_wasmer_bin_hash "$variant_manifest")" || return
+}
+
+fresh_require_patched_wasmer_receipt() {
+  local manifest="${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}"
+  local wasmer_patch="$FRESH_ROOT/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch"
+  local wasix_libc_patch="$FRESH_ROOT/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
+
+  [ -f "$manifest" ] && [ ! -L "$manifest" ] || {
+    printf 'missing regular Wasmer build receipt: %s\n' "$manifest" >&2
+    printf 'Run %s/wasmer/bin/build-runtime.sh, or provide a matching WASMER_BUILD_RECEIPT.\n' "$FRESH_ROOT" >&2
+    return 2
+  }
+  [ -f "$wasmer_patch" ] && [ ! -L "$wasmer_patch" ] || return 2
+  [ -f "$wasix_libc_patch" ] && [ ! -L "$wasix_libc_patch" ] || return 2
+
+  fresh_validate_wasmer_build_receipt_shape "$manifest" || return
+  fresh_require_manifest_value \
+    "$manifest" schema oliphaunt.wasix-postmaster.wasmer-build.v2 || return
+  fresh_require_manifest_value \
+    "$manifest" build_recipe_sha256 "$(fresh_runtime_build_recipe_sha256)" || return
+  fresh_require_manifest_value \
+    "$manifest" wasmer_source_commit "$FRESH_WASMER_SOURCE_COMMIT" || return
+  fresh_require_manifest_value \
+    "$manifest" wasmer_napi_commit "$FRESH_WASMER_NAPI_COMMIT" || return
+  fresh_require_manifest_value \
+    "$manifest" wasmer_test_files_commit "$FRESH_WASMER_TEST_FILES_COMMIT" || return
+  fresh_require_manifest_value \
+    "$manifest" wasmer_spec_commit "$FRESH_WASMER_SPEC_COMMIT" || return
+  fresh_require_manifest_value \
+    "$manifest" wasix_libc_source_commit "$FRESH_WASIX_LIBC_SOURCE_COMMIT" || return
+  fresh_require_manifest_value \
+    "$manifest" wasmer_patch_sha256 "$(fresh_wasmer_bin_hash "$wasmer_patch")" || return
+  fresh_require_manifest_value \
+    "$manifest" wasix_libc_patch_sha256 "$(fresh_wasmer_bin_hash "$wasix_libc_patch")" || return
+  fresh_require_manifest_value \
+    "$manifest" wasmer_features "$FRESH_WASMER_COMPILER_FEATURES" || return
+  fresh_require_manifest_value \
+    "$manifest" wasmer_headless_features "$FRESH_WASMER_HEADLESS_FEATURES" || return
+  fresh_require_manifest_value \
+    "$manifest" artifact_abi_version "$FRESH_WASMER_ARTIFACT_ABI_VERSION" || return
+  fresh_require_manifest_value \
+    "$manifest" host_platform "$(fresh_host_arch)" || return
+  fresh_require_manifest_value \
+    "$manifest" host_abi "$(fresh_host_abi)" || return
+  fresh_require_manifest_value \
+    "$manifest" runtime_abi_id "$(fresh_runtime_abi_id \
+      "$(fresh_manifest_value "$manifest" wasmer_cargo_lock_sha256)" \
+      "$(fresh_manifest_value "$manifest" rustc_host)" \
+      "$(fresh_manifest_value "$manifest" host_platform)" \
+      "$(fresh_manifest_value "$manifest" host_abi)")" || return
+
+  local hash_field
+  for hash_field in \
+    build_recipe_sha256 \
+    wasmer_patch_sha256 \
+    wasmer_prepared_signature_sha256 \
+    wasmer_cargo_lock_sha256 \
+    wasmer_binary_sha256 \
+    wasmer_headless_binary_sha256 \
+    runtime_abi_id \
+    wasix_libc_patch_sha256 \
+    wasix_libc_prepared_signature_sha256 \
+    sysroot_carrier_manifest_sha256 \
+    sysroot_variant_manifest_sha256
+  do
+    fresh_require_receipt_sha256 "$manifest" "$hash_field" || return
+  done
+}
+
+fresh_require_patched_wasmer() {
+  local wasmer_bin="$1"
+  local manifest="${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}"
+
+  [ -f "$wasmer_bin" ] && [ ! -L "$wasmer_bin" ] && [ -x "$wasmer_bin" ] || {
+    printf 'missing executable patched Wasmer binary: %s\n' "$wasmer_bin" >&2
+    return 2
+  }
+  fresh_require_patched_wasmer_receipt || return
+  fresh_require_manifest_value \
+    "$manifest" wasmer_binary_sha256 "$(fresh_wasmer_bin_hash "$wasmer_bin")"
+}
+
+fresh_require_patched_wasmer_headless() {
+  local wasmer_bin="$1"
+  local manifest="${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}"
+
+  [ -f "$wasmer_bin" ] && [ ! -L "$wasmer_bin" ] && [ -x "$wasmer_bin" ] || {
+    printf 'missing executable patched headless Wasmer binary: %s\n' "$wasmer_bin" >&2
+    return 2
+  }
+  fresh_require_patched_wasmer_receipt || return
+  fresh_require_manifest_value \
+    "$manifest" wasmer_headless_binary_sha256 "$(fresh_wasmer_bin_hash "$wasmer_bin")"
+}
+
+# Select the product-specific sealed-postmaster executor independently from the
+# general compiler-free Wasmer CLI.  Its receipt binds the exact parent runtime
+# receipt as well as the isolated Cargo feature/package build, so a carrier can
+# retain the established AOT manifest format without treating two native
+# executors as interchangeable.
+fresh_require_patched_postmaster_executor() {
+  local executor_bin="$1"
+  local executor_receipt="${2:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
+  local wasmer_receipt="${3:-${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}}"
+  local hash_field
+
+  [ -f "$executor_bin" ] && [ ! -L "$executor_bin" ] && [ -x "$executor_bin" ] || {
+    printf 'missing executable postmaster executor binary: %s\n' "$executor_bin" >&2
+    return 2
+  }
+  [ -f "$executor_receipt" ] && [ ! -L "$executor_receipt" ] || {
+    printf 'missing regular postmaster executor build receipt: %s\n' "$executor_receipt" >&2
+    return 2
+  }
+  [ -f "$wasmer_receipt" ] && [ ! -L "$wasmer_receipt" ] || {
+    printf 'missing regular parent Wasmer build receipt: %s\n' "$wasmer_receipt" >&2
+    return 2
+  }
+
+  WASMER_BUILD_RECEIPT="$wasmer_receipt" fresh_require_patched_wasmer_receipt || return
+  fresh_validate_postmaster_executor_build_receipt_shape "$executor_receipt" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" schema \
+    oliphaunt.wasix-postmaster.postmaster-executor-build.v3 || return
+  fresh_require_manifest_value \
+    "$executor_receipt" build_recipe_sha256 \
+    "$(fresh_runtime_build_recipe_sha256)" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" wasmer_build_receipt_sha256 \
+    "$(fresh_wasmer_bin_hash "$wasmer_receipt")" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" wasmer_source_commit "$FRESH_WASMER_SOURCE_COMMIT" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" wasmer_patch_sha256 \
+    "$(fresh_wasmer_bin_hash "$FRESH_ROOT/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch")" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" wasmer_prepared_signature_sha256 \
+    "$(fresh_manifest_value "$wasmer_receipt" wasmer_prepared_signature_sha256)" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" wasmer_cargo_lock_sha256 \
+    "$(fresh_manifest_value "$wasmer_receipt" wasmer_cargo_lock_sha256)" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" runtime_abi_id \
+    "$(fresh_manifest_value "$wasmer_receipt" runtime_abi_id)" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" artifact_abi_version "$FRESH_WASMER_ARTIFACT_ABI_VERSION" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" executor_package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" executor_binary "$FRESH_POSTMASTER_EXECUTOR_BINARY" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" executor_features "$FRESH_POSTMASTER_EXECUTOR_FEATURES" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" executor_role "$FRESH_POSTMASTER_EXECUTOR_ROLE" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" runtime_policy_id \
+    "$FRESH_POSTMASTER_EXECUTOR_RUNTIME_POLICY_ID" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" cli_contract "$FRESH_POSTMASTER_EXECUTOR_CLI_CONTRACT" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" executor_binary_sha256 \
+    "$(fresh_wasmer_bin_hash "$executor_bin")" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" start_proof_binary "$FRESH_START_PROOF_BINARY" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" start_proof_features "$FRESH_START_PROOF_FEATURES" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" start_proof_policy "$FRESH_START_PROOF_POLICY" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" memory_profile_binary "$FRESH_MEMORY_PROFILE_BINARY" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" memory_profile_features "$FRESH_MEMORY_PROFILE_FEATURES" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" linear_memory_profile_id "$FRESH_LINEAR_MEMORY_PROFILE_ID" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" postmaster_compiler_binary "$FRESH_POSTMASTER_COMPILER_BINARY" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" postmaster_compiler_features "$FRESH_POSTMASTER_COMPILER_FEATURES" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" compiler_cpu_policy generic-baseline || return
+  fresh_require_manifest_value \
+    "$executor_receipt" compiler_cpu_features none || return
+  fresh_require_manifest_value \
+    "$executor_receipt" host_platform "$(fresh_host_arch)" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" host_abi "$(fresh_host_abi)" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" rustc_host \
+    "$(fresh_manifest_value "$wasmer_receipt" rustc_host)" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" rustc_version \
+    "$(fresh_manifest_value "$wasmer_receipt" rustc_version)" || return
+
+  for hash_field in \
+    build_recipe_sha256 \
+    wasmer_build_receipt_sha256 \
+    wasmer_patch_sha256 \
+    wasmer_prepared_signature_sha256 \
+    wasmer_cargo_lock_sha256 \
+    runtime_abi_id \
+    executor_binary_sha256 \
+    start_proof_binary_sha256 \
+    memory_profile_binary_sha256 \
+    postmaster_compiler_binary_sha256
+  do
+    fresh_require_receipt_sha256 "$executor_receipt" "$hash_field" || return
+  done
+}
+
+fresh_require_memory_profile_tool() {
+  local profile_bin="${1:-$FRESH_MEMORY_PROFILE_BIN}"
+  local executor_receipt="${2:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
+  local actual_id
+
+  [ -f "$profile_bin" ] && [ ! -L "$profile_bin" ] && [ -x "$profile_bin" ] || {
+    printf 'missing executable linear-memory profile tool: %s\n' "$profile_bin" >&2
+    return 2
+  }
+  fresh_validate_postmaster_executor_build_receipt_shape "$executor_receipt" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" schema \
+    oliphaunt.wasix-postmaster.postmaster-executor-build.v3 || return
+  fresh_require_manifest_value \
+    "$executor_receipt" memory_profile_binary "$FRESH_MEMORY_PROFILE_BINARY" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" memory_profile_features "$FRESH_MEMORY_PROFILE_FEATURES" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" linear_memory_profile_id "$FRESH_LINEAR_MEMORY_PROFILE_ID" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" memory_profile_binary_sha256 \
+    "$(fresh_wasmer_bin_hash "$profile_bin")" || return
+  actual_id="$("$profile_bin" --profile-json | bun "$FRESH_ROOT/lib/linear-memory-profile.mts" profile-id)" || {
+    printf 'could not read linear-memory profile identity from %s\n' "$profile_bin" >&2
+    return 2
+  }
+  [ "$actual_id" = "$FRESH_LINEAR_MEMORY_PROFILE_ID" ] || {
+    printf 'linear-memory profile tool identity mismatch: expected %s, got %s\n' \
+      "$FRESH_LINEAR_MEMORY_PROFILE_ID" "$actual_id" >&2
+    return 2
+  }
+}
+
+fresh_require_patched_postmaster_compiler() {
+  local compiler_bin="${1:-$FRESH_POSTMASTER_COMPILER_BIN}"
+  local executor_receipt="${2:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
+  local wasmer_receipt="${3:-${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}}"
+  local executor_bin="${4:-$FRESH_POSTMASTER_EXECUTOR_BIN}"
+  local version profile_id
+
+  [ -f "$compiler_bin" ] && [ ! -L "$compiler_bin" ] && [ -x "$compiler_bin" ] || {
+    printf 'missing executable postmaster product compiler: %s\n' "$compiler_bin" >&2
+    return 2
+  }
+  fresh_require_patched_postmaster_executor \
+    "$executor_bin" "$executor_receipt" "$wasmer_receipt" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" postmaster_compiler_binary \
+    "$FRESH_POSTMASTER_COMPILER_BINARY" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" postmaster_compiler_features \
+    "$FRESH_POSTMASTER_COMPILER_FEATURES" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" compiler_cpu_policy generic-baseline || return
+  fresh_require_manifest_value \
+    "$executor_receipt" compiler_cpu_features none || return
+  fresh_require_manifest_value \
+    "$executor_receipt" postmaster_compiler_binary_sha256 \
+    "$(fresh_wasmer_bin_hash "$compiler_bin")" || return
+  version="$("$compiler_bin" --version)" || {
+    printf 'could not read postmaster product compiler identity: %s\n' \
+      "$compiler_bin" >&2
+    return 2
+  }
+  profile_id="${version##* }"
+  [ "${version%% *}" = "$FRESH_POSTMASTER_COMPILER_BINARY" ] && \
+    [ "$profile_id" = "$FRESH_LINEAR_MEMORY_PROFILE_ID" ] || {
+    printf 'postmaster product compiler profile identity differs: %s\n' \
+      "${version:-}" >&2
+    return 2
+  }
+}
+
+fresh_require_start_proof_tool() {
+  local proof_bin="${1:-$FRESH_START_PROOF_BIN}"
+  local executor_receipt="${2:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
+  local actual_policy
+
+  [ -f "$proof_bin" ] && [ ! -L "$proof_bin" ] && [ -x "$proof_bin" ] || {
+    printf 'missing executable deterministic-start proof tool: %s\n' "$proof_bin" >&2
+    return 2
+  }
+  fresh_validate_postmaster_executor_build_receipt_shape "$executor_receipt" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" start_proof_binary "$FRESH_START_PROOF_BINARY" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" start_proof_features "$FRESH_START_PROOF_FEATURES" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" start_proof_policy "$FRESH_START_PROOF_POLICY" || return
+  fresh_require_manifest_value \
+    "$executor_receipt" start_proof_binary_sha256 \
+    "$(fresh_wasmer_bin_hash "$proof_bin")" || return
+  actual_policy="$("$proof_bin" --policy-id)" || return
+  [ "$actual_policy" = "$FRESH_START_PROOF_POLICY" ] || {
+    printf 'deterministic-start proof policy mismatch: expected %s, got %s\n' \
+      "$FRESH_START_PROOF_POLICY" "${actual_policy:-}" >&2
+    return 2
+  }
+}
+
+fresh_wasmer_bin() {
+  local candidate
+
+  if [ -n "${WASMER_BIN:-}" ]; then
+    if command -v "$WASMER_BIN" >/dev/null 2>&1; then
+      candidate="$(command -v "$WASMER_BIN")"
+    elif [ -x "$WASMER_BIN" ]; then
+      candidate="$WASMER_BIN"
+    else
+      echo "WASMER_BIN is set but not executable: $WASMER_BIN" >&2
+      return 127
+    fi
+  else
+    candidate="$FRESH_UPSTREAM_WASMER_BIN"
+  fi
+
+  fresh_require_patched_wasmer "$candidate" || return
+  printf '%s\n' "$candidate"
+}
+
+fresh_wasmer_bin_hash() {
+  local wasmer_bin="$1"
+  if command -v sha256sum >/dev/null 2>&1; then
+    sha256sum "$wasmer_bin" | awk '{print $1}'
+  else
+    shasum -a 256 "$wasmer_bin" | awk '{print $1}'
+  fi
+}
+
+fresh_wasmer_metadata_dir() {
+  printf '%s/tools/wasmer-home\n' "$FRESH_WORK_ROOT"
+}
+
+fresh_wasmer_metadata_cache_dir() {
+  printf '%s/tools/wasmer-cache/metadata\n' "$FRESH_WORK_ROOT"
+}
+
+fresh_wasmer_version() {
+  local wasmer_bin="$1"
+  local metadata_dir
+  local metadata_cache_dir
+
+  metadata_dir="$(fresh_wasmer_metadata_dir)"
+  metadata_cache_dir="$(fresh_wasmer_metadata_cache_dir)"
+  mkdir -p "$metadata_dir" "$metadata_cache_dir"
+  env \
+    WASMER_DIR="$metadata_dir" \
+    WASMER_CACHE_DIR="$metadata_cache_dir" \
+    "$wasmer_bin" --version
+}
+
+fresh_wasmer_cache_dir() {
+  local wasmer_bin="$1"
+  if [ -n "${FRESH_PINNED_WASMER_CACHE_DIR:-}" ]; then
+    printf '%s\n' "$FRESH_PINNED_WASMER_CACHE_DIR"
+    return
+  fi
+  printf '%s/tools/wasmer-cache/%s\n' "$FRESH_WORK_ROOT" "$(fresh_wasmer_bin_hash "$wasmer_bin")"
+}
+
+fresh_wasmer_llvm_opt_suffix() {
+  [ "${1:-aggressive}" = aggressive ] || {
+    echo "the postmaster product compiler is fixed to aggressive LLVM optimization" >&2
+    return 2
+  }
+  echo opta
+}
+
+fresh_normalize_wasmer_compiler() {
+  [ "${1:-llvm}" = llvm ] || {
+    echo "the postmaster product compiler is fixed to llvm" >&2
+    return 2
+  }
+  echo llvm
+}
+
+fresh_wasmer_compiler() {
+  printf '%s\n' llvm
+}
+
+fresh_wasmer_compiler_cli_flag() {
+  fresh_normalize_wasmer_compiler "$1" >/dev/null || return
+  printf '%s\n' --llvm
+}
+
+fresh_wasmer_cli_has_option() {
+  local wasmer_bin="$1"
+  local subcommand="$2"
+  local option="$3"
+
+  local metadata_dir
+  local metadata_cache_dir
+
+  metadata_dir="$(fresh_wasmer_metadata_dir)"
+  metadata_cache_dir="$(fresh_wasmer_metadata_cache_dir)"
+  mkdir -p "$metadata_dir" "$metadata_cache_dir"
+
+  env \
+    WASMER_DIR="$metadata_dir" \
+    WASMER_CACHE_DIR="$metadata_cache_dir" \
+    "$wasmer_bin" "$subcommand" --help 2>/dev/null |
+    grep -Eq "(^|[[:space:]])${option//-/\\-}([[:space:],]|$)"
+}
+
+fresh_require_wasmer_compiler_cli() {
+  local wasmer_bin="$1"
+  local compiler="$2"
+  shift 2
+
+  local flag
+  flag="$(fresh_wasmer_compiler_cli_flag "$compiler")"
+
+  local subcommand
+  for subcommand in "$@"; do
+    if ! fresh_wasmer_cli_has_option "$wasmer_bin" "$subcommand" "$flag"; then
+      {
+        printf 'the postmaster LLVM compiler requires `%s %s`, but `%s %s --help` does not expose that option.\n' \
+          "$(basename "$wasmer_bin")" "$flag" "$wasmer_bin" "$subcommand"
+        printf 'Build or select the receipt-bound postmaster compiler.\n'
+      } >&2
+      return 2
+    fi
+  done
+}
+
+fresh_wasmer_compiler_args_for() {
+  local wasmer_bin="$1"
+  local subcommand="$2"
+  shift 2
+  local compiler="$1"
+  local llvm_opt_level="$2"
+  local compiler_threads="$3"
+  [ "$llvm_opt_level" = aggressive ] || {
+    echo "the postmaster product compiler is fixed to aggressive LLVM optimization" >&2
+    return 2
+  }
+
+  case "$(fresh_normalize_wasmer_compiler "$compiler")" in
+    llvm)
+      printf '%s\n' --llvm
+      if [ -n "$wasmer_bin" ] &&
+        [ -n "$subcommand" ] &&
+        fresh_wasmer_cli_has_option "$wasmer_bin" "$subcommand" "--llvm-opt-level"; then
+        printf '%s\n' --llvm-opt-level "$llvm_opt_level"
+      fi
+      ;;
+  esac
+  if [ -n "$compiler_threads" ]; then
+    printf '%s\n' --compiler-threads "$compiler_threads"
+  fi
+}
+
+fresh_wasmer_compiler_cache_bucket() {
+  local compiler="$1"
+  local llvm_opt_level="$2"
+  local artifact_version="$3"
+  [ "$llvm_opt_level" = aggressive ] || {
+    echo "the postmaster product compiler is fixed to aggressive LLVM optimization" >&2
+    return 2
+  }
+
+  case "$(fresh_normalize_wasmer_compiler "$compiler")" in
+    llvm)
+      printf 'llvm-%s-v%s\n' "$(fresh_wasmer_llvm_opt_suffix "$llvm_opt_level")" "$artifact_version"
+      ;;
+  esac
+}
+
+fresh_wasmer_module_hash() {
+  local wasm_path="$1"
+  shasum -a 256 "$wasm_path" | awk '{print toupper($1)}'
+}
+
+fresh_git_worktree_state_sha256() {
+  local excluded_path="${2:-}"
+  local file_sha256
+  local identity_mode
+  local path
+  local root="$1"
+  local source
+  local source_head
+  local symlink_target
+
+  source_head="$(git -C "$root" rev-parse --verify 'HEAD^{commit}')" || {
+    printf 'not a Git worktree: %s\n' "$root" >&2
+    return 2
+  }
+  {
+    printf '%s\0%s\0%s\0' \
+      schema oliphaunt.git-worktree-state.v1 "$source_head"
+    git -C "$root" diff --binary --full-index --no-ext-diff HEAD -- || return
+    git -C "$root" ls-files --others --exclude-standard -z |
+      LC_ALL=C sort -z |
+      while IFS= read -r -d '' path; do
+        [ -n "$excluded_path" ] && [ "$path" = "$excluded_path" ] && continue
+        source="$root/$path"
+        if [ -L "$source" ]; then
+          symlink_target="$(readlink "$source")" || return
+          printf 'untracked-symlink\0%s\0%s\0' "$path" "$symlink_target"
+        elif [ -f "$source" ]; then
+          file_sha256="$(fresh_wasmer_bin_hash "$source")" || return
+          fresh_is_sha256 "$file_sha256" || {
+            printf 'failed to hash untracked worktree input: %s\n' "$source" >&2
+            return 2
+          }
+          if [ -x "$source" ]; then
+            identity_mode=executable
+          else
+            identity_mode=data
+          fi
+          printf 'untracked-file\0%s\0%s\0%s\0' \
+            "$path" "$file_sha256" "$identity_mode"
+        else
+          printf 'unsupported untracked worktree entry: %s\n' "$source" >&2
+          return 2
+        fi
+      done || return
+  } | fresh_sha256_stream
+}
+
+fresh_overlay_digest() {
+  local overlay_dir="$FRESH_ROOT/postgres/overlays/wasix-core"
+  local series="$FRESH_ROOT/postgres/series"
+  local path
+  [ -f "$series" ] && [ ! -L "$series" ] || return 2
+  {
+    printf '%s\0%s\0' schema oliphaunt.wasix-postmaster.overlay.v3
+    if [ -d "$overlay_dir" ]; then
+      while IFS= read -r -d '' path; do
+        printf 'overlay\0%s\0%s\0' "${path#"$overlay_dir"/}" "$(fresh_wasmer_bin_hash "$path")"
+      done < <(find "$overlay_dir" -type f -print0 | LC_ALL=C sort -z)
+    fi
+    printf 'series\0%s\0' "$(fresh_wasmer_bin_hash "$series")"
+    while IFS= read -r path || [ -n "$path" ]; do
+      case "$path" in
+        ''|'#'*) continue ;;
+        /*|*..*|*\\*) return 2 ;;
+      esac
+      [ -f "$REPO_ROOT/$path" ] && [ ! -L "$REPO_ROOT/$path" ] || return 2
+      printf 'patch\0%s\0%s\0' "$path" "$(fresh_wasmer_bin_hash "$REPO_ROOT/$path")"
+    done < "$series"
+  } | fresh_sha256_stream
+}
+
+fresh_write_report_header() {
+  local report="$1"
+  local title="$2"
+  mkdir -p "$(dirname "$report")"
+  {
+    printf '# %s\n\n' "$title"
+    printf -- '- Generated: `%s`\n' "$(fresh_timestamp)"
+    printf -- '- Repository: `%s`\n' "$REPO_ROOT"
+    printf -- '- Project source root: `%s`\n' "$FRESH_ROOT"
+    printf -- '- Generated work root: `%s`\n' "$FRESH_WORK_ROOT"
+    printf -- '- PostgreSQL tag: `%s`\n\n' "$POSTGRES_TAG"
+  } >"$report"
+}
+
+fresh_ensure_docker_image() {
+  local docker_bin
+  local actual_recipe
+  local expected_recipe
+  local image="${1:-$FRESH_WASIX_DOCKER_IMAGE}"
+  local label=dev.oliphaunt.wasix-builder.recipe-sha256
+  local context="$WASIX_TOOLCHAIN_ROOT/docker"
+  docker_bin="$(fresh_docker_bin)"
+  expected_recipe="$(fresh_wasix_builder_recipe_sha256)" || return
+  actual_recipe="$("$docker_bin" image inspect \
+    --format "{{ index .Config.Labels \"$label\" }}" "$image" 2>/dev/null || true)"
+  if [ "$actual_recipe" = "$expected_recipe" ]; then
+    return
+  fi
+  "$docker_bin" build \
+    --label "$label=$expected_recipe" \
+    -f "$context/Dockerfile" \
+    -t "$image" \
+    "$context" || return
+  actual_recipe="$("$docker_bin" image inspect \
+    --format "{{ index .Config.Labels \"$label\" }}" "$image" 2>/dev/null || true)"
+  [ "$actual_recipe" = "$expected_recipe" ] || {
+    printf 'WASIX builder image recipe label mismatch after build: %s\n' "$image" >&2
+    return 2
+  }
+}
+
+fresh_wasix_builder_image_id() {
+  local actual_recipe
+  local docker_bin
+  local expected_recipe
+  local image="${1:-$FRESH_WASIX_DOCKER_IMAGE}"
+  local image_id
+  local label=dev.oliphaunt.wasix-builder.recipe-sha256
+  local record
+
+  docker_bin="$(fresh_docker_bin)" || return
+  expected_recipe="$(fresh_wasix_builder_recipe_sha256)" || return
+  record="$("$docker_bin" image inspect \
+    --format "{{.Id}}|{{ index .Config.Labels \"$label\" }}" \
+    "$image" 2>/dev/null)" || {
+    printf 'WASIX builder image is unavailable: %s\n' "$image" >&2
+    return 2
+  }
+  case "$record" in
+    *'|'*)
+      image_id="${record%%|*}"
+      actual_recipe="${record#*|}"
+      ;;
+    *)
+      printf 'WASIX builder image inspection returned an invalid record: %s\n' "$image" >&2
+      return 2
+      ;;
+  esac
+  [ "$actual_recipe" = "$expected_recipe" ] || {
+    printf 'WASIX builder image recipe label mismatch: %s\n' "$image" >&2
+    return 2
+  }
+  case "$image_id" in
+    sha256:*)
+      fresh_is_sha256 "${image_id#sha256:}" || {
+        printf 'WASIX builder image has an invalid immutable identity: %s\n' "$image" >&2
+        return 2
+      }
+      ;;
+    *)
+      printf 'WASIX builder image has an invalid immutable identity: %s\n' "$image" >&2
+      return 2
+      ;;
+  esac
+  printf '%s\n' "$image_id"
+}
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/common.test.sh
similarity index 91%
rename from src/runtimes/liboliphaunt/wasix-postmaster/lib/common.test.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/lib/common.test.sh
index 758b96144..8e4ee304e 100644
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.test.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/common.test.sh
@@ -30,6 +30,20 @@ unset WASMER_BIN
 
 source "$project_root/lib/common.sh"
 
+source_pin="$test_root/source.toml"
+printf 'commit = "abc123"\n' > "$source_pin"
+[ "$(fresh_source_scalar "$source_pin" commit)" = abc123 ]
+printf 'commit = "def456"\n' >> "$source_pin"
+if fresh_source_scalar "$source_pin" commit >/dev/null 2>&1; then
+  echo 'source pin accepted duplicate identities' >&2
+  exit 1
+fi
+printf 'commit = "../escape"\n' > "$source_pin"
+if fresh_source_scalar "$source_pin" commit >/dev/null 2>&1; then
+  echo 'source pin accepted a non-scalar identity' >&2
+  exit 1
+fi
+
 original_work_root="$FRESH_WORK_ROOT"
 original_baseline_dir="$BASELINE_DIR"
 mkdir -p "$(fresh_managed_generated_root)"
@@ -71,7 +85,7 @@ if expect_source_prefix_failure; then
   echo 'common library accepted a caller-controlled project source identity prefix' >&2
   exit 1
 fi
-if env FRESH_PROJECT_SOURCE_ID_PREFIX=src/runtimes/liboliphaunt/wasix-postmaster \
+if env FRESH_PROJECT_SOURCE_ID_PREFIX=src/runtimes/liboliphaunt-wasix-postmaster \
   bash -c 'source "$1/lib/common.sh"; FRESH_PROJECT_SOURCE_ID_PREFIX=mutable' \
   bash "$project_root" >/dev/null 2>&1; then
   echo 'inherited canonical project source identity prefix remained mutable' >&2
@@ -79,15 +93,15 @@ if env FRESH_PROJECT_SOURCE_ID_PREFIX=src/runtimes/liboliphaunt/wasix-postmaster
 fi
 
 [ "$(fresh_project_source_identity_path \
-  "$project_root/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch")" = \
-  "src/runtimes/liboliphaunt/wasix-postmaster/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch" ]
+  "$project_root/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch")" = \
+  "src/runtimes/liboliphaunt-wasix-postmaster/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch" ]
 original_fresh_root="$FRESH_ROOT"
 frozen_root="$test_root/measurement-tool-closures/example"
-mkdir -p "$frozen_root/runtime/patches/wasix-libc"
+mkdir -p "$frozen_root/wasmer/patches/wasix-libc"
 FRESH_ROOT="$frozen_root"
 [ "$(fresh_project_source_identity_path \
-  "$frozen_root/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch")" = \
-  "src/runtimes/liboliphaunt/wasix-postmaster/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch" ]
+  "$frozen_root/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch")" = \
+  "src/runtimes/liboliphaunt-wasix-postmaster/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch" ]
 expect_source_identity_failure() {
   fresh_project_source_identity_path "$1" >/dev/null 2>&1
 }
@@ -100,39 +114,42 @@ FRESH_ROOT="$original_fresh_root"
 live_runtime_recipe="$(fresh_runtime_build_recipe_sha256)"
 for relative in \
   lib/common.sh \
-  sources.lock.toml \
-  runtime/capabilities.tsv \
-  runtime/bin/prepare-upstream-checkouts.sh \
-  runtime/bin/build-runtime.sh \
-  runtime/bin/build-patched-wasix-libc-sysroot.sh \
-  runtime/bin/validate-runtime-capabilities.sh \
-  runtime/bin/verify-source-lock.py; do
+  wasmer/bin/prepare-upstream-checkouts.sh \
+  wasmer/bin/build-runtime.sh \
+  wasmer/bin/build-patched-wasix-libc-sysroot.sh \
+  wasmer/bin/validate-runtime-capabilities.sh; do
   mkdir -p "$frozen_root/$(dirname "$relative")"
   cp "$original_fresh_root/$relative" "$frozen_root/$relative"
   chmod u+w "$frozen_root/$relative"
 done
+cp -R "$original_fresh_root/executor" "$frozen_root/executor"
 FRESH_ROOT="$frozen_root"
+executor_source="$(fresh_executor_source_sha256)"
+mkdir -p "$frozen_root/executor/tests"
+printf 'standalone test fixture\n' >"$frozen_root/executor/tests/fixture.txt"
+[ "$(fresh_executor_source_sha256)" = "$executor_source" ]
 [ "$(fresh_runtime_build_recipe_sha256)" = "$live_runtime_recipe" ] || {
   echo 'runtime build recipe changed under a byte-identical frozen project relocation' >&2
   exit 1
 }
-chmod -x "$frozen_root/runtime/bin/build-runtime.sh"
+chmod -x "$frozen_root/wasmer/bin/build-runtime.sh"
+[ "$(fresh_executor_source_sha256)" = "$executor_source" ]
 [ "$(fresh_runtime_build_recipe_sha256)" != "$live_runtime_recipe" ] || {
   echo 'runtime build recipe ignored executable-mode drift' >&2
   exit 1
 }
-chmod +x "$frozen_root/runtime/bin/build-runtime.sh"
+chmod +x "$frozen_root/wasmer/bin/build-runtime.sh"
 [ "$(fresh_runtime_build_recipe_sha256)" = "$live_runtime_recipe" ] || {
   echo 'runtime build recipe did not recover after restoring executable mode' >&2
   exit 1
 }
-printf '\n# byte-drift probe\n' >>"$frozen_root/runtime/bin/verify-source-lock.py"
+printf '\n# byte-drift probe\n' >>"$frozen_root/wasmer/bin/validate-runtime-capabilities.sh"
 [ "$(fresh_runtime_build_recipe_sha256)" != "$live_runtime_recipe" ] || {
   echo 'runtime build recipe ignored producer validation byte drift' >&2
   exit 1
 }
-cp "$original_fresh_root/runtime/bin/verify-source-lock.py" \
-  "$frozen_root/runtime/bin/verify-source-lock.py"
+cp "$original_fresh_root/wasmer/bin/validate-runtime-capabilities.sh" \
+  "$frozen_root/wasmer/bin/validate-runtime-capabilities.sh"
 [ "$(fresh_runtime_build_recipe_sha256)" = "$live_runtime_recipe" ] || {
   echo 'runtime build recipe did not recover after restoring producer bytes' >&2
   exit 1
@@ -247,7 +264,7 @@ if fresh_runtime_build_recipe_sha256 >/dev/null 2>&1; then
   echo 'runtime build recipe accepted a relative toolchain root' >&2
   exit 1
 fi
-WASIX_TOOLCHAIN_ROOT="$REPO_ROOT/../$(basename "$REPO_ROOT")/src/runtimes/liboliphaunt/wasix/assets/build"
+WASIX_TOOLCHAIN_ROOT="$REPO_ROOT/../$(basename "$REPO_ROOT")/src/runtimes/liboliphaunt-wasix/assets/build"
 if fresh_runtime_build_recipe_sha256 >/dev/null 2>&1; then
   echo 'runtime build recipe accepted a non-canonical toolchain root' >&2
   exit 1
@@ -358,11 +375,14 @@ cp "$true_bin" "$FRESH_UPSTREAM_WASMER_HEADLESS_BIN"
 chmod u+wx "$FRESH_UPSTREAM_WASMER_HEADLESS_BIN"
 cp "$true_bin" "$FRESH_POSTMASTER_EXECUTOR_BIN"
 chmod u+wx "$FRESH_POSTMASTER_EXECUTOR_BIN"
-cp "$project_root/testdata/fake-start-proof.py" "$FRESH_START_PROOF_BIN"
+bun build --target=bun "$project_root/testdata/fake-start-proof.mts" --outfile "$FRESH_START_PROOF_BIN" >/dev/null
 chmod +x "$FRESH_START_PROOF_BIN"
-cp "$true_bin" "$FRESH_MEMORY_PROFILE_BIN"
+cat >"$FRESH_MEMORY_PROFILE_BIN" <<'MEMORY_PROFILE'
+#!/usr/bin/env bash
+printf '{"id":"%s"}\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
+MEMORY_PROFILE
 chmod u+wx "$FRESH_MEMORY_PROFILE_BIN"
-cp "$project_root/testdata/fake-postmaster-compiler.py" "$FRESH_POSTMASTER_COMPILER_BIN"
+bun build --target=bun "$project_root/testdata/fake-postmaster-compiler.mts" --outfile "$FRESH_POSTMASTER_COMPILER_BIN" >/dev/null
 chmod +x "$FRESH_POSTMASTER_COMPILER_BIN"
 
 write_receipt() {
@@ -382,7 +402,7 @@ write_receipt() {
     printf 'wasmer_napi_commit=706383f42391cb4e4e82e5fd5e63a0ebf81ae19d\n'
     printf 'wasmer_test_files_commit=7f27e84c69af3b772f751d6c4a733d9f448b2c70\n'
     printf 'wasmer_spec_commit=7e0b83aba9dbbb6e0623c9334b0f73b3bb584b90\n'
-    printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch")"
+    printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch")"
     printf 'wasmer_prepared_signature_sha256=%064d\n' 0
     printf 'wasmer_cargo_lock_sha256=%s\n' "$cargo_lock_sha256"
     printf 'wasmer_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_UPSTREAM_WASMER_BIN")"
@@ -392,7 +412,7 @@ write_receipt() {
     printf 'runtime_abi_id=%s\n' "$runtime_abi_id"
     printf 'artifact_abi_version=%s\n' "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
     printf 'wasix_libc_source_commit=34178a6272804f90448b5bd08dc7bcf0d85438e3\n'
-    printf 'wasix_libc_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch")"
+    printf 'wasix_libc_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch")"
     printf 'wasix_libc_prepared_signature_sha256=%064d\n' 0
     printf 'sysroot_carrier_manifest_sha256=%064d\n' 0
     printf 'sysroot_variant=%s\n' "$WASIXCC_SYSROOT_VARIANT"
@@ -413,7 +433,7 @@ write_postmaster_executor_receipt() {
     printf 'build_recipe_sha256=%s\n' "$(fresh_runtime_build_recipe_sha256)"
     printf 'wasmer_build_receipt_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_BUILD_RECEIPT")"
     printf 'wasmer_source_commit=%s\n' "$FRESH_WASMER_SOURCE_COMMIT"
-    printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch")"
+    printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch")"
     printf 'wasmer_prepared_signature_sha256=%s\n' \
       "$(fresh_manifest_value "$WASMER_BUILD_RECEIPT" wasmer_prepared_signature_sha256)"
     printf 'wasmer_cargo_lock_sha256=%s\n' \
@@ -759,6 +779,26 @@ fresh_require_patched_postmaster_compiler \
   "$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT" \
   "$WASMER_BUILD_RECEIPT" \
   "$FRESH_POSTMASTER_EXECUTOR_BIN"
+import_native_runtime() {
+  OLIPHAUNT_WASIX_POSTMASTER_NATIVE_INPUTS=1 OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS="${1:-1}" \
+    WASMER_BUILD_RECEIPT_OUT="$WASMER_BUILD_RECEIPT" \
+    bash "$project_root/wasmer/bin/build-runtime.sh" --build-only
+}
+import_native_runtime
+OLIPHAUNT_WASIX_POSTMASTER_NATIVE_INPUTS=1 OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS=1 \
+  bash "$project_root/wasmer/bin/prepare-upstream-checkouts.sh"
+[ ! -e "$FRESH_WORK_ROOT/runtime/wasmer" ]
+expect_failure import_native_runtime 0
+OLIPHAUNT_WASIX_POSTMASTER_NATIVE_INPUTS=1 OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS=0 \
+  expect_failure bash "$project_root/wasmer/bin/prepare-upstream-checkouts.sh"
+printf 'tampered' >> "$FRESH_UPSTREAM_WASMER_BIN"
+expect_failure import_native_runtime
+cp "$true_bin" "$FRESH_UPSTREAM_WASMER_BIN"
+chmod u+wx "$FRESH_UPSTREAM_WASMER_BIN"
+write_receipt wrong-host
+expect_failure import_native_runtime
+write_receipt
+write_postmaster_executor_receipt
 [ "$(fresh_wasmer_bin)" = "$FRESH_UPSTREAM_WASMER_BIN" ]
 
 default_cache_dir="$(fresh_wasmer_cache_dir "$FRESH_UPSTREAM_WASMER_BIN")"
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/durable-publication.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/durable-publication.mts
new file mode 100644
index 000000000..fdedd6a5e
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/durable-publication.mts
@@ -0,0 +1,350 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import * as fs from 'node:fs';
+import { basename, dirname, resolve } from 'node:path';
+import { stableRead } from './receipt-files.mts';
+
+const maxBytes = 256 * 1024 * 1024;
+type Source = { device: bigint; inode: bigint; size: number; sha256: string };
+const stat = (path: string) => fs.lstatSync(path, { bigint: true, throwIfNoEntry: false });
+const sameFile = (a: fs.BigIntStats, b: fs.BigIntStats | Source) =>
+  a.dev === ('device' in b ? b.device : b.dev) && a.ino === ('inode' in b ? b.inode : b.ino);
+const identity = (info: fs.BigIntStats) => [
+  info.dev,
+  info.ino,
+  info.mode,
+  info.size,
+  info.mtimeNs,
+  info.ctimeNs,
+];
+const token = (source: Source) =>
+  [source.device, source.inode, source.size, source.sha256].join('\t');
+export function parseToken(values: string[]): Source {
+  assert(
+    values.length === 4 && values.slice(0, 3).every((value) => /^(0|[1-9][0-9]*)$/.test(value)),
+    'invalid publication token',
+  );
+  const [device, inode, size] = values.slice(0, 3).map((value) => BigInt(value));
+  assert(
+    device > 0n && inode > 0n && size <= BigInt(maxBytes) && /^[0-9a-f]{64}$/.test(values[3]),
+    'invalid publication identity',
+  );
+  return { device, inode, size: Number(size), sha256: values[3] };
+}
+function openRegular(path: string) {
+  const before = stat(path);
+  assert(before?.isFile(), `publication source is not regular: ${path}`);
+  const fd = fs.openSync(path, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
+  try {
+    const opened = fs.fstatSync(fd, { bigint: true });
+    assert.deepEqual(
+      identity(opened),
+      identity(before),
+      'publication source changed while opening',
+    );
+    const current = stat(path);
+    assert(current?.isFile(), 'publication source disappeared');
+    assert.deepEqual(identity(current), identity(opened), 'publication source was replaced');
+    return { fd, info: opened };
+  } catch (error) {
+    fs.closeSync(fd);
+    throw error;
+  }
+}
+function descriptorHash(fd: number, size: number) {
+  assert(
+    Number.isSafeInteger(size) && size >= 0 && size <= maxBytes,
+    'publication exceeds size bound',
+  );
+  const hash = createHash('sha256'),
+    buffer = Buffer.alloc(1024 * 1024);
+  let position = 0;
+  while (position < size) {
+    const count = fs.readSync(fd, buffer, 0, Math.min(buffer.length, size - position), position);
+    assert(count > 0, 'publication was truncated');
+    hash.update(buffer.subarray(0, count));
+    position += count;
+  }
+  assert.equal(fs.readSync(fd, buffer, 0, 1, position), 0, 'publication grew');
+  return hash.digest('hex');
+}
+export function sourceIdentity(path: string): Source {
+  const hash = createHash('sha256');
+  const info = stableRead(
+    path,
+    (chunk) => {
+      hash.update(chunk);
+    },
+    maxBytes,
+  );
+  assert.equal(info.mode & 0o7777n, 0o444n, 'publication source must be sealed 0444');
+  return { device: info.dev, inode: info.ino, size: Number(info.size), sha256: hash.digest('hex') };
+}
+// One CLI process owns one directory for its entire operation. Relative I/O stays
+// anchored to that directory even if another process renames/replaces its path.
+// Do not call this from a process serving concurrent filesystem operations.
+export function anchorDirectory(path: string) {
+  const before = stat(path);
+  assert(before?.isDirectory(), 'publication parent is not a real directory');
+  process.chdir(path);
+  const fd = fs.openSync(
+    '.',
+    fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW,
+  );
+  try {
+    const current = fs.fstatSync(fd, { bigint: true });
+    assert(
+      current.isDirectory() && sameFile(current, before),
+      'publication parent changed while opening',
+    );
+    return fd;
+  } catch (error) {
+    fs.closeSync(fd);
+    throw error;
+  }
+}
+export function removePrivate(path: string, expected: Source, dirfd: number) {
+  const current = stat(path);
+  if (!current) return;
+  assert(current.isFile() && sameFile(current, expected), 'private publication generation changed');
+  fs.unlinkSync(path);
+  fs.fsyncSync(dirfd);
+}
+export function publish(source: string, destination: string, expected: Source, dirfd: number) {
+  assert(!stat(destination), 'publication destination already exists');
+  const { fd, info } = openRegular(source);
+  let linked: fs.BigIntStats | undefined,
+    committed = false;
+  try {
+    assert.equal(info.mode & 0o7777n, 0o444n, 'publication source is not sealed');
+    assert(
+      sameFile(info, expected) && info.size === BigInt(expected.size),
+      'publication source generation differs',
+    );
+    const digest = descriptorHash(fd, expected.size);
+    assert.equal(digest, expected.sha256, 'publication source bytes differ');
+    fs.fsyncSync(fd);
+    fs.linkSync(source, destination);
+    linked = stat(destination);
+    assert(linked, 'publication destination disappeared');
+    const published = openRegular(destination);
+    try {
+      assert(sameFile(info, published.info), 'publication destination identity differs');
+      const current = fs.fstatSync(fd, { bigint: true });
+      assert.deepEqual(
+        identity(current).slice(0, -1),
+        identity(info).slice(0, -1),
+        'publication source changed before commit',
+      );
+      assert.equal(
+        descriptorHash(fd, expected.size),
+        digest,
+        'publication source bytes changed before commit',
+      );
+      fs.fsyncSync(published.fd);
+    } finally {
+      fs.closeSync(published.fd);
+    }
+    fs.fsyncSync(dirfd);
+    committed = true;
+  } finally {
+    fs.closeSync(fd);
+    if (linked && !committed) {
+      const current = stat(destination);
+      if (current && sameFile(current, linked)) {
+        fs.unlinkSync(destination);
+        fs.fsyncSync(dirfd);
+      }
+    }
+  }
+  removePrivate(source, expected, dirfd);
+}
+function requireDestination(path: string, expected: Source, dirfd: number) {
+  const { fd, info } = openRegular(path);
+  try {
+    assert.equal(info.mode & 0o7777n, 0o444n, 'publication set destination is not sealed');
+    assert.equal(info.size, BigInt(expected.size), 'publication set destination size differs');
+    assert.equal(
+      descriptorHash(fd, expected.size),
+      expected.sha256,
+      'publication set destination bytes differ',
+    );
+    fs.fsyncSync(fd);
+    fs.fsyncSync(dirfd);
+  } finally {
+    fs.closeSync(fd);
+  }
+}
+export function publishSet(
+  pairs: { source: string; destination: string; expected?: Source }[],
+  dirfd: number,
+) {
+  assert(pairs.length >= 2, 'publication set requires two or more pairs');
+  const sources = new Set(pairs.map((pair) => pair.source)),
+    destinations = new Set(pairs.map((pair) => pair.destination));
+  assert(
+    sources.size === pairs.length &&
+      destinations.size === pairs.length &&
+      ![...sources].some((path) => destinations.has(path)),
+    'publication set names must be unique and disjoint',
+  );
+  const identified = pairs.map((pair) => {
+    const expected = sourceIdentity(pair.source);
+    if (pair.expected)
+      assert.deepEqual(expected, pair.expected, 'publication set generation differs');
+    return { ...pair, expected };
+  });
+  // Reject any conflicting existing member before creating a new partial set.
+  for (const pair of identified)
+    if (stat(pair.destination)) requireDestination(pair.destination, pair.expected, dirfd);
+  for (const { source, destination, expected } of identified) {
+    try {
+      publish(source, destination, expected, dirfd);
+    } catch {
+      requireDestination(destination, expected, dirfd);
+      removePrivate(source, expected, dirfd);
+    }
+  }
+}
+export async function writePrivate(
+  path: string,
+  chunks: AsyncIterable | Iterable,
+  dirfd: number,
+): Promise {
+  const fd = fs.openSync(
+    path,
+    fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_NOFOLLOW,
+    0o600,
+  );
+  const opened = fs.fstatSync(fd, { bigint: true }),
+    hash = createHash('sha256');
+  let size = 0;
+  try {
+    for await (const chunk of chunks) {
+      size += chunk.length;
+      assert(size <= maxBytes, 'publication input exceeds size bound');
+      hash.update(chunk);
+      for (let offset = 0; offset < chunk.length; ) {
+        const count = fs.writeSync(fd, chunk, offset);
+        assert(count > 0, 'short publication write');
+        offset += count;
+      }
+    }
+    fs.fchmodSync(fd, 0o444);
+    fs.fsyncSync(fd);
+    const final = fs.fstatSync(fd, { bigint: true }),
+      current = stat(path);
+    assert(
+      final.isFile() &&
+        sameFile(final, opened) &&
+        final.size === BigInt(size) &&
+        current?.isFile() &&
+        sameFile(current, final),
+      'publication changed while writing',
+    );
+    return { device: final.dev, inode: final.ino, size, sha256: hash.digest('hex') };
+  } catch (error) {
+    const current = stat(path);
+    if (current && sameFile(current, opened)) {
+      fs.unlinkSync(path);
+      fs.fsyncSync(dirfd);
+    }
+    throw error;
+  } finally {
+    fs.closeSync(fd);
+  }
+}
+export async function run(args: string[]) {
+  const [command, ...values] = args;
+  if (command === 'require-equal' && values.length === 2) {
+    const read = (path: string) => {
+      const chunks: Buffer[] = [];
+      stableRead(path, (chunk) => chunks.push(Buffer.from(chunk)), 16 * 1024 * 1024);
+      return Buffer.concat(chunks);
+    };
+    assert(read(values[0]).equals(read(values[1])), 'regular files differ');
+    return;
+  }
+  if (command === 'identify-source' && values.length === 1) {
+    console.log(token(sourceIdentity(values[0])));
+    return;
+  }
+  let paths: string[],
+    tokens: Source[] = [];
+  if (
+    (command === 'publish' && values.length === 2) ||
+    (command === 'publish-identified' && values.length === 6)
+  ) {
+    paths = values.slice(0, 2);
+    if (command === 'publish-identified') tokens = [parseToken(values.slice(2))];
+  } else if (command === 'publish-set' && values.length >= 4 && values.length % 2 === 0)
+    paths = values;
+  else if (command === 'publish-set-identified' && values.length >= 12 && values.length % 6 === 0) {
+    paths = [];
+    for (let index = 0; index < values.length; index += 6) {
+      paths.push(...values.slice(index, index + 2));
+      tokens.push(parseToken(values.slice(index + 2, index + 6)));
+    }
+  } else if (command === 'remove-private-identified' && values.length === 5) {
+    paths = values.slice(0, 1);
+    tokens = [parseToken(values.slice(1))];
+  } else if (
+    ['write-stdin', 'write-stdin-identified', 'discard-private', 'fsync-directory'].includes(
+      command,
+    ) &&
+    values.length === 1
+  )
+    paths = values;
+  else
+    assert.fail(
+      'usage: durable-publication.mts publish[-identified] | publish-set[-identified] | write-stdin[-identified] | identify-source | require-equal | discard-private | remove-private-identified | fsync-directory',
+    );
+  paths = paths.map((path) => resolve(path));
+  const parent = command === 'fsync-directory' ? paths[0] : dirname(paths[0]);
+  if (command !== 'fsync-directory')
+    assert(
+      paths.every((path) => dirname(path) === parent),
+      'publication paths must share one directory',
+    );
+  if (command.startsWith('publish'))
+    for (let index = 0; index < paths.length; index += 2)
+      assert(paths[index] !== paths[index + 1], 'publication source and destination must differ');
+  const fd = anchorDirectory(parent);
+  paths = paths.map((path) => basename(path));
+  try {
+    if (command === 'fsync-directory') fs.fsyncSync(fd);
+    else if (command.startsWith('write-stdin')) {
+      const source = await writePrivate(paths[0], process.stdin, fd);
+      if (command === 'write-stdin-identified') console.log(token(source));
+    } else if (command === 'discard-private') {
+      const info = stat(paths[0]);
+      if (info)
+        removePrivate(
+          paths[0],
+          { device: info.dev, inode: info.ino, size: Number(info.size), sha256: '' },
+          fd,
+        );
+    } else if (command === 'remove-private-identified') removePrivate(paths[0], tokens[0], fd);
+    else if (command.startsWith('publish-set'))
+      publishSet(
+        Array.from({ length: paths.length / 2 }, (_, index) => ({
+          source: paths[index * 2],
+          destination: paths[index * 2 + 1],
+          expected: tokens[index],
+        })),
+        fd,
+      );
+    else publish(paths[0], paths[1], tokens[0] ?? sourceIdentity(paths[0]), fd);
+  } finally {
+    fs.closeSync(fd);
+  }
+}
+if (import.meta.main) {
+  try {
+    await run(process.argv.slice(2));
+  } catch (error) {
+    console.error(`durable publication failed: ${error instanceof Error ? error.message : error}`);
+    process.exitCode = 2;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/durable-publication.test.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/durable-publication.test.mts
new file mode 100644
index 000000000..a89df906f
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/durable-publication.test.mts
@@ -0,0 +1,150 @@
+import assert from 'node:assert/strict';
+import * as fs from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { test, spyOn } from 'bun:test';
+import {
+  anchorDirectory,
+  writePrivate,
+  sourceIdentity,
+  publish,
+  publishSet,
+  removePrivate,
+  parseToken,
+} from './durable-publication.mts';
+async function fixture(check: (root: string, fd: number) => Promise | void) {
+  const previous = process.cwd(),
+    root = fs.mkdtempSync(join(tmpdir(), 'durable-publication-'));
+  const fd = anchorDirectory(root);
+  try {
+    await check(root, fd);
+  } finally {
+    fs.closeSync(fd);
+    process.chdir(previous);
+    fs.rmSync(root, { recursive: true, force: true });
+  }
+}
+const bytes = Buffer.from('exact durable evidence\n');
+const write = (name: string, fd: number) => writePrivate(name, [bytes], fd);
+test('identified publication preserves sealed bytes and never replaces a destination or a new source generation', async () =>
+  fixture(async (_root, fd) => {
+    const identity = await write('pending', fd);
+    assert.deepEqual(sourceIdentity('pending'), identity);
+    assert.equal(fs.statSync('pending').mode & 0o7777, 0o444);
+    publish('pending', 'admitted', identity, fd);
+    assert(fs.readFileSync('admitted').equals(bytes));
+    assert(!fs.existsSync('pending'));
+    const replay = await write('pending', fd);
+    assert.throws(() => publish('pending', 'admitted', replay, fd), /exists/);
+    fs.renameSync('pending', 'old-pending');
+    await write('pending', fd);
+    assert.throws(() => publish('pending', 'other', replay, fd), /generation/);
+    assert.throws(() => removePrivate('pending', replay, fd), /generation/);
+    assert(fs.readFileSync('pending').equals(bytes));
+    assert(!fs.existsSync('other'));
+    fs.symlinkSync('admitted', 'link');
+    await assert.rejects(() => write('link', fd));
+    assert.throws(() => sourceIdentity('link'));
+    for (const token of [
+      ['0', '1', '1', 'a'.repeat(64)],
+      ['1', '01', '1', 'a'.repeat(64)],
+      ['1', '1', '268435457', 'a'.repeat(64)],
+    ])
+      assert.throws(() => parseToken(token));
+  }));
+test('publication stays in the opened directory when its original path is replaced', async () =>
+  fixture(async (root, fd) => {
+    const renamed = `${root}.renamed`;
+    fs.renameSync(root, renamed);
+    fs.mkdirSync(root);
+    fs.writeFileSync(join(root, 'pending'), 'competitor');
+    try {
+      const identity = await write('pending', fd);
+      publish('pending', 'admitted', identity, fd);
+      assert.equal(fs.readFileSync(join(root, 'pending'), 'utf8'), 'competitor');
+      assert(fs.readFileSync(join(renamed, 'admitted')).equals(bytes));
+    } finally {
+      // Return the fixture's original directory to its name for cleanup.
+      fs.rmSync(root, { recursive: true });
+      fs.renameSync(renamed, root);
+    }
+  }));
+test('publication sets preflight conflicts, recover partial admission, and retain replaced private generations', async () =>
+  fixture(async (_root, fd) => {
+    const one = await write('one', fd);
+    publish('one', 'first', one, fd);
+    await write('one', fd);
+    await write('two', fd);
+    publishSet(
+      [
+        { source: 'one', destination: 'first' },
+        { source: 'two', destination: 'second' },
+      ],
+      fd,
+    );
+    assert(!fs.existsSync('one') && !fs.existsSync('two'));
+    assert(fs.readFileSync('second').equals(bytes));
+    await write('one', fd);
+    await write('two', fd);
+    fs.writeFileSync('conflict', 'other', { mode: 0o444 });
+    assert.throws(() =>
+      publishSet(
+        [
+          { source: 'one', destination: 'missing' },
+          { source: 'two', destination: 'conflict' },
+        ],
+        fd,
+      ),
+    );
+    assert(!fs.existsSync('missing'));
+    const realLink = fs.linkSync;
+    const spy = spyOn(fs, 'linkSync').mockImplementation((source, dest) => {
+      if (source === 'two') {
+        fs.renameSync('two', 'original-two');
+        fs.writeFileSync('two', 'replacement', { mode: 0o444 });
+      }
+      realLink(source, dest);
+    });
+    try {
+      assert.throws(() =>
+        publishSet(
+          [
+            { source: 'one', destination: 'missing' },
+            { source: 'two', destination: 'third' },
+          ],
+          fd,
+        ),
+      );
+      assert(fs.readFileSync('missing').equals(bytes));
+      assert(!fs.existsSync('third'));
+      assert.equal(fs.readFileSync('two', 'utf8'), 'replacement');
+    } finally {
+      spy.mockRestore();
+    }
+  }));
+test('failed post-link synchronization rolls back only the name this publisher created', async () =>
+  fixture(async (_root, fd) => {
+    const realSync = fs.fsyncSync;
+    for (const replace of [false, true]) {
+      const expected = await write('pending', fd);
+      let calls = 0;
+      const spy = spyOn(fs, 'fsyncSync').mockImplementation((descriptor) => {
+        if (++calls === 2) {
+          if (replace) {
+            fs.unlinkSync('admitted');
+            fs.writeFileSync('admitted', 'competitor', { mode: 0o444 });
+          }
+          throw Error('injected destination fsync failure');
+        }
+        realSync(descriptor);
+      });
+      try {
+        assert.throws(() => publish('pending', 'admitted', expected, fd), /injected/);
+      } finally {
+        spy.mockRestore();
+      }
+      assert.equal(fs.existsSync('admitted'), replace);
+      if (replace) assert.equal(fs.readFileSync('admitted', 'utf8'), 'competitor');
+      removePrivate('pending', expected, fd);
+    }
+  }));
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/durable-publication.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/durable-publication.test.sh
new file mode 100644
index 000000000..69e8e617d
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/durable-publication.test.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+set -euo pipefail
+project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+publication="$project_root/lib/durable-publication.mts"
+work="$(mktemp -d)"
+trap 'rm -rf "$work"' EXIT
+printf 'exact durable evidence\n' > "$work/expected"
+for point in source-fsync link destination-fsync commit-directory-fsync source-unlink cleanup-directory-fsync; do
+  mkdir "$work/$point"
+  pending="$work/$point/pending"
+  admitted="$work/$point/admitted"
+  bun "$publication" write-stdin "$pending" < "$work/expected"
+  status=0
+  bun "$project_root/testdata/crash-durable-publication.mts" "$point" "$pending" "$admitted" > "$work/$point/crash.log" 2>&1 || status=$?
+  [ "$status" -eq 137 ] || { cat "$work/$point/crash.log" >&2; exit 1; }
+  if [ -f "$admitted" ]; then
+    bun "$publication" require-equal "$work/expected" "$admitted"
+    bun "$publication" discard-private "$pending"
+  else
+    bun "$publication" publish "$pending" "$admitted"
+  fi
+  [ ! -e "$pending" ]
+  before="$(bun "$publication" identify-source "$admitted")"
+  bun "$publication" write-stdin "$pending" < "$work/expected"
+  bun "$publication" require-equal "$pending" "$admitted"
+  bun "$publication" discard-private "$pending"
+  [ "$(bun "$publication" identify-source "$admitted")" = "$before" ]
+done
+# Exercise a pipe larger than the comparison bound, including token handoff and
+# partial-set replay. The producer must stream without dropping pipe output.
+dd if=/dev/zero bs=1048576 count=17 2>/dev/null |
+  bun "$publication" write-stdin-identified "$work/large" > "$work/large.token"
+IFS=$'\t' read -r device inode size hash < "$work/large.token"
+[ "$size" -eq 17825792 ]
+bun "$publication" publish-identified "$work/large" "$work/large-published" "$device" "$inode" "$size" "$hash"
+printf 'wrong generation' > "$work/large"
+chmod 0444 "$work/large"
+if bun "$publication" publish-identified "$work/large" "$work/forbidden" "$device" "$inode" "$size" "$hash" >/dev/null 2>&1; then
+  exit 1
+fi
+[ ! -e "$work/forbidden" ]
+for name in first second; do
+  bun "$publication" write-stdin "$work/$name" < "$work/large-published"
+done
+bun "$publication" publish-set "$work/first" "$work/large-published" "$work/second" "$work/second-published"
+[ ! -e "$work/first" ] && [ ! -e "$work/second" ]
+cmp "$work/large-published" "$work/second-published"
+printf 'durable publication crash boundaries and streamed CLI handoff passed\n'
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-build-provenance.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-build-provenance.mts
new file mode 100644
index 000000000..214929031
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-build-provenance.mts
@@ -0,0 +1,282 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash, type Hash } from 'node:crypto';
+import * as fs from 'node:fs';
+import { dirname, join, posix, resolve } from 'node:path';
+
+const schema = 'oliphaunt.wasix-postmaster.guest-installed-closure.v1';
+const policy = new URL('../wasmer/policies/sealed-side-modules.v1.tsv', import.meta.url);
+const occupied = new Set();
+export const sideModulePolicy = fs
+  .readFileSync(policy, 'utf8')
+  .split('\n')
+  .filter((line) => line && !line.startsWith('#'))
+  .map((line) => {
+    const [relative, rawAliases, abi, extra] = line.split('\t');
+    assert(
+      relative?.startsWith('lib/') &&
+        /\.(so|so\.5\.18)$/.test(relative) &&
+        rawAliases &&
+        abi &&
+        extra === undefined,
+      'invalid side-module policy',
+    );
+    const aliases = rawAliases === '-' ? [] : rawAliases.split(',');
+    for (const path of [relative, ...aliases]) {
+      assert(
+        path.startsWith('lib/') &&
+          !path.split('/').some((part) => !part || part === '.' || part === '..') &&
+          !occupied.has(path),
+        `invalid or duplicate side-module path: ${path}`,
+      );
+      occupied.add(path);
+    }
+    return { relative, aliases };
+  });
+assert(sideModulePolicy.length, 'empty side-module policy');
+export const requiredModules = [
+  'bin/initdb',
+  'bin/postgres',
+  ...sideModulePolicy.map((row) => row.relative),
+];
+const identity = (stat: fs.BigIntStats) => [
+  stat.dev,
+  stat.ino,
+  stat.mode,
+  stat.size,
+  stat.mtimeNs,
+  stat.ctimeNs,
+];
+const sorted = (paths: string[]) =>
+  paths.sort((a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
+const stat = (path: string) => fs.lstatSync(path, { bigint: true });
+
+function withRegular(
+  path: string,
+  directory: boolean,
+  read: (fd: number, opened: fs.BigIntStats) => T,
+): T {
+  const before = stat(path);
+  assert(
+    directory ? before.isDirectory() : before.isFile(),
+    `non-regular guest ${directory ? 'directory' : 'file'}: ${path}`,
+  );
+  const fd = fs.openSync(
+    path,
+    fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | (directory ? fs.constants.O_DIRECTORY : 0),
+  );
+  try {
+    const opened = fs.fstatSync(fd, { bigint: true });
+    assert.deepEqual(
+      identity(opened),
+      identity(before),
+      `guest entry changed while opening: ${path}`,
+    );
+    const result = read(fd, opened);
+    assert.deepEqual(
+      identity(fs.fstatSync(fd, { bigint: true })),
+      identity(opened),
+      `guest entry changed during read/sync: ${path}`,
+    );
+    assert.deepEqual(
+      identity(stat(path)),
+      identity(opened),
+      `guest entry replaced during read/sync: ${path}`,
+    );
+    return result;
+  } finally {
+    fs.closeSync(fd);
+  }
+}
+
+function readRegular(path: string, synchronize: boolean) {
+  return withRegular(path, false, (fd, opened) => {
+    const hash = createHash('sha256');
+    const buffer = Buffer.allocUnsafe(1024 * 1024);
+    let size = 0;
+    for (;;) {
+      const count = fs.readSync(fd, buffer);
+      if (!count) break;
+      hash.update(buffer.subarray(0, count));
+      size += count;
+      assert(BigInt(size) <= opened.size, `guest file grew while hashing: ${path}`);
+    }
+    assert(BigInt(size) === opened.size, `guest file changed while hashing: ${path}`);
+    if (synchronize) fs.fsyncSync(fd);
+    return { size, sha256: hash.digest('hex'), identity: identity(opened) };
+  });
+}
+
+export function closureFiles(root: string): string[] {
+  assert(stat(root).isDirectory(), 'guest install root is not a non-symlink directory');
+  const files = [...requiredModules];
+  for (const relative of files)
+    assert(stat(join(root, relative)).isFile(), `missing regular guest module: ${relative}`);
+  const visit = (relative: string) => {
+    const directory = join(root, relative);
+    assert(stat(directory).isDirectory(), `non-directory in guest closure: ${relative}`);
+    for (const name of fs.readdirSync(directory, { encoding: 'buffer' })) {
+      const decoded = new TextDecoder('utf-8', { fatal: true }).decode(name);
+      const child = `${relative}/${decoded}`;
+      const entry = stat(join(root, child));
+      if (entry.isDirectory()) visit(child);
+      else {
+        assert(entry.isFile(), `non-regular guest closure member: ${child}`);
+        files.push(child);
+      }
+    }
+  };
+  visit('share/postgresql');
+  assert(files.length > requiredModules.length, 'PostgreSQL share closure is empty');
+  assert(new Set(files).size === files.length, 'duplicate guest closure paths');
+  return sorted(files);
+}
+
+function frame(hash: Hash, value: string) {
+  const bytes = Buffer.from(value);
+  const length = Buffer.alloc(8);
+  length.writeBigUInt64BE(BigInt(bytes.length));
+  hash.update(length).update(bytes);
+}
+
+export function installedClosureIdentityFromRecords(
+  records: { relative: string; size: number; sha256: string }[],
+) {
+  assert(records.length, 'empty guest closure records');
+  const paths = records.map((record) => record.relative);
+  assert.deepEqual(
+    paths,
+    sorted([...new Set(paths)]),
+    'guest closure records must be sorted and unique',
+  );
+  const hash = createHash('sha256');
+  frame(hash, schema);
+  for (const { relative, size, sha256 } of records) {
+    assert(
+      Number.isSafeInteger(size) && size >= 0 && /^[0-9a-f]{64}$/.test(sha256),
+      'invalid guest closure size or SHA-256',
+    );
+    for (const field of [relative, String(size), sha256]) frame(hash, field);
+  }
+  return hash.digest('hex');
+}
+
+export function installedClosureIdentity(root: string, synchronize = false): string {
+  root = resolve(root);
+  const files = closureFiles(root);
+  const records = files.map((relative) => ({
+    relative,
+    ...readRegular(join(root, relative), synchronize),
+  }));
+  if (synchronize) {
+    const directories = new Set(['.']);
+    for (const file of files) {
+      for (let parent = posix.dirname(file); parent !== '.'; parent = posix.dirname(parent))
+        directories.add(parent);
+    }
+    const directoryIdentities = new Map();
+    // Children must be durable before their containing directory and install root.
+    for (const relative of sorted([...directories]).sort(
+      (a, b) => b.split('/').length - a.split('/').length || (a === '.' ? 1 : b === '.' ? -1 : 0),
+    )) {
+      directoryIdentities.set(
+        relative,
+        withRegular(join(root, relative), true, (fd, opened) => {
+          fs.fsyncSync(fd);
+          return identity(opened);
+        }),
+      );
+    }
+    withRegular(dirname(root), true, (fd) => {
+      assert.deepEqual(
+        identity(stat(root)),
+        directoryIdentities.get('.'),
+        'guest root changed before parent sync',
+      );
+      fs.fsyncSync(fd);
+      assert.deepEqual(
+        identity(stat(root)),
+        directoryIdentities.get('.'),
+        'guest root changed during parent sync',
+      );
+    });
+    assert.deepEqual(closureFiles(root), files, 'guest closure inventory changed after sync');
+    assert.deepEqual(
+      files.map((relative) => ({ relative, ...readRegular(join(root, relative), false) })),
+      records,
+      'guest closure changed after sync',
+    );
+    for (const [relative, expected] of directoryIdentities)
+      assert.deepEqual(
+        identity(stat(join(root, relative))),
+        expected,
+        `guest directory changed after sync: ${relative}`,
+      );
+  }
+  return installedClosureIdentityFromRecords(records);
+}
+
+// Generation publication also distributes headers and client tools. Keep its
+// whole-prefix identity separate from the admitted runtime closure above.
+export function generationIdentity(root: string, synchronize = false): string {
+  root = resolve(root);
+  const hash = createHash('sha256');
+  frame(hash, 'oliphaunt.wasix-postmaster.guest-generation.v1');
+  function visit(relative: string) {
+    const path = join(root, relative);
+    const before = stat(path);
+    frame(hash, relative);
+    frame(hash, String(before.mode & 0o7777n));
+    if (before.isDirectory()) {
+      frame(hash, 'directory');
+      withRegular(path, true, (fd) => {
+        const names = sorted(fs.readdirSync(path));
+        for (const name of names) visit(relative === '.' ? name : `${relative}/${name}`);
+        assert.deepEqual(sorted(fs.readdirSync(path)), names, 'generation inventory changed');
+        if (synchronize) fs.fsyncSync(fd);
+      });
+    } else if (before.isFile()) {
+      frame(hash, 'file');
+      const value = readRegular(path, synchronize);
+      frame(hash, String(value.size));
+      frame(hash, value.sha256);
+    } else {
+      assert(before.isSymbolicLink(), `special generation entry: ${relative}`);
+      const target = fs.readlinkSync(path);
+      assert(!posix.isAbsolute(target), `absolute generation link: ${relative}`);
+      const resolved = fs.realpathSync(path);
+      assert(resolved.startsWith(`${root}/`), `escaping generation link: ${relative}`);
+      frame(hash, 'symlink');
+      frame(hash, target);
+    }
+    assert.deepEqual(
+      identity(stat(path)),
+      identity(before),
+      `generation entry changed: ${relative}`,
+    );
+  }
+  visit('.');
+  return hash.digest('hex');
+}
+
+if (import.meta.main) {
+  try {
+    const [mode, root, extra] = process.argv.slice(2);
+    assert(
+      root &&
+        !extra &&
+        ['identity', 'seal-identity', 'generation-identity', 'seal-generation-identity'].includes(
+          mode!,
+        ),
+      'usage: guest-build-provenance.mts [seal-]identity|[seal-]generation-identity INSTALL_ROOT',
+    );
+    console.log(
+      mode.endsWith('generation-identity')
+        ? generationIdentity(root, mode === 'seal-generation-identity')
+        : installedClosureIdentity(root, mode === 'seal-identity'),
+    );
+  } catch (error) {
+    console.error(`guest build provenance failed: ${(error as Error).message}`);
+    process.exitCode = 2;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-build-provenance.test.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-build-provenance.test.mts
new file mode 100644
index 000000000..ca6f052b4
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-build-provenance.test.mts
@@ -0,0 +1,104 @@
+import { spyOn, test } from 'bun:test';
+import assert from 'node:assert/strict';
+import * as fs from 'node:fs';
+import { tmpdir } from 'node:os';
+import { dirname, join } from 'node:path';
+import {
+  generationIdentity,
+  installedClosureIdentity,
+  requiredModules,
+} from './guest-build-provenance.mts';
+
+function fixture(run: (root: string) => void) {
+  const root = fs.mkdtempSync(join(tmpdir(), 'guest-provenance-'));
+  try {
+    for (const relative of [
+      ...requiredModules,
+      'share/postgresql/postgres.bki',
+      'share/postgresql/nested/data.txt',
+    ]) {
+      fs.mkdirSync(dirname(join(root, relative)), { recursive: true });
+      fs.writeFileSync(join(root, relative), `module:${relative}\n`);
+    }
+    run(root);
+  } finally {
+    fs.rmSync(root, { recursive: true, force: true });
+  }
+}
+
+test('generation identity binds headers, tools, modes and contained links without changing runtime identity', () =>
+  fixture((root) => {
+    const runtime = installedClosureIdentity(root);
+    fs.mkdirSync(join(root, 'include'));
+    fs.writeFileSync(join(root, 'include/postgres.h'), 'header one');
+    fs.writeFileSync(join(root, 'bin/psql'), 'client tool');
+    const original = generationIdentity(root, true);
+    assert.equal(generationIdentity(root), original);
+    fs.writeFileSync(join(root, 'include/postgres.h'), 'header two');
+    assert.notEqual(generationIdentity(root), original);
+    assert.equal(installedClosureIdentity(root), runtime);
+    const withHeader = generationIdentity(root);
+    fs.chmodSync(join(root, 'bin/psql'), 0o755);
+    assert.notEqual(generationIdentity(root), withHeader);
+    fs.symlinkSync('psql', join(root, 'bin/client'));
+    const withLink = generationIdentity(root, true);
+    fs.unlinkSync(join(root, 'bin/client'));
+    fs.symlinkSync('postgres', join(root, 'bin/client'));
+    assert.notEqual(generationIdentity(root), withLink);
+    fs.unlinkSync(join(root, 'bin/client'));
+    fs.symlinkSync('/etc/passwd', join(root, 'bin/client'));
+    assert.throws(() => generationIdentity(root), /absolute generation link/);
+  }));
+
+test('guest seal preserves the published closure hash and synchronizes files before directories', () =>
+  fixture((root) => {
+    const sync = fs.fsyncSync;
+    const order: string[] = [];
+    const spy = spyOn(fs, 'fsyncSync').mockImplementation((fd) => {
+      order.push(fs.fstatSync(fd).isDirectory() ? 'directory' : 'file');
+      sync(fd);
+    });
+    try {
+      const expected = 'fe88edce48c0306782f68aad3d76960909946932928142022c8c2d3e77a0f949';
+      assert.equal(installedClosureIdentity(root), expected);
+      assert.equal(order.length, 0);
+      assert.equal(installedClosureIdentity(root, true), expected);
+      assert.equal(order.filter((type) => type === 'file').length, requiredModules.length + 2);
+      assert(!order.slice(order.indexOf('directory')).includes('file'));
+      assert(order.filter((type) => type === 'directory').length >= 7);
+    } finally {
+      spy.mockRestore();
+    }
+  }));
+
+test('guest seal rejects symlinked directories and non-regular share entries', () =>
+  fixture((root) => {
+    const directory = join(root, 'lib/postgresql');
+    fs.renameSync(directory, `${directory}.actual`);
+    fs.symlinkSync('postgresql.actual', directory);
+    assert.throws(() => installedClosureIdentity(root, true), /non-regular guest directory/);
+    fs.unlinkSync(directory);
+    fs.renameSync(`${directory}.actual`, directory);
+    fs.symlinkSync('postgres.bki', join(root, 'share/postgresql/alias'));
+    assert.throws(() => installedClosureIdentity(root, true), /non-regular guest closure/);
+  }));
+
+test('guest seal rejects same-byte file replacement after directory synchronization', () =>
+  fixture((root) => {
+    const sync = fs.fsyncSync;
+    let replaced = false;
+    const spy = spyOn(fs, 'fsyncSync').mockImplementation((fd) => {
+      sync(fd);
+      if (!replaced && fs.fstatSync(fd).isDirectory()) {
+        replaced = true;
+        const postgres = join(root, 'bin/postgres');
+        fs.writeFileSync(`${postgres}.replacement`, fs.readFileSync(postgres));
+        fs.renameSync(`${postgres}.replacement`, postgres);
+      }
+    });
+    try {
+      assert.throws(() => installedClosureIdentity(root, true), /guest closure changed after sync/);
+    } finally {
+      spy.mockRestore();
+    }
+  }));
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-generation.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-generation.sh
new file mode 100644
index 000000000..589f83ce7
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-generation.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+# Readers resolve once; publishing a selection never changes a directory in use.
+fresh_resolve_guest_generation() {
+  local base="$1" identity generation
+  if [ ! -e "$base.current" ] && [ ! -L "$base.current" ]; then
+    printf '%s\n' "$base"
+    return
+  fi
+  [ -f "$base.current" ] && [ ! -L "$base.current" ] || return 2
+  identity="$(cat "$base.current")" || return 2
+  [[ "$identity" =~ ^[0-9a-f]{64}$ ]] || return 2
+  generation="$base.generations/$identity"
+  [ -d "$base.generations" ] && [ ! -L "$base.generations" ] &&
+    [ -d "$generation" ] && [ ! -L "$generation" ] &&
+    [ -f "$generation/guest-build.receipt" ] && [ ! -L "$generation/guest-build.receipt" ] || return 2
+  printf '%s\n' "$generation"
+}
+
+fresh_publish_guest_generation() {
+  local stage="$1" base="$2" identity destination existing
+  identity="$(bun "$FRESH_ROOT/lib/guest-build-provenance.mts" seal-generation-identity "$stage")" || return
+  fresh_is_sha256 "$identity" || return 2
+  destination="$base.generations/$identity"
+  [ "$(dirname "$stage")" = "$base.generations" ] || return 2
+  existing="$(fresh_manifest_value "$stage/guest-build.receipt" installed_closure_sha256)" || return
+  [ "$(bun "$FRESH_ROOT/lib/guest-build-provenance.mts" seal-identity "$stage")" = "$existing" ] || return 2
+  if [ -e "$destination" ] || [ -L "$destination" ]; then
+    [ -d "$destination" ] && [ ! -L "$destination" ] &&
+      cmp -s "$stage/guest-build.receipt" "$destination/guest-build.receipt" &&
+      [ "$(bun "$FRESH_ROOT/lib/guest-build-provenance.mts" generation-identity "$destination")" = "$identity" ] || return 2
+    rm -rf -- "$stage"
+  else
+    fresh_atomic_publish_directory_noreplace "$stage" "$destination" || return
+  fi
+  bun "$FRESH_ROOT/lib/select-guest-generation.mts" "$base.current" "$identity" || return
+  printf '%s\n' "$destination"
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-generation.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-generation.test.sh
new file mode 100644
index 000000000..f1a893423
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/guest-generation.test.sh
@@ -0,0 +1,98 @@
+#!/usr/bin/env bash
+set -euo pipefail
+project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
+source "$project_root/lib/common.sh"
+source "$project_root/lib/sealed-carrier.sh"
+work="$(mktemp -d)"
+trap 'rm -rf "$work"' EXIT
+base="$work/guest"
+mkdir -p "$base.generations" "$work/bin"
+real_bun="$(command -v bun)"
+
+fixture() {
+  local stage relative _aliases _abi _extra
+  stage="$(mktemp -d "$base.generations/.pending.XXXXXXXX")"
+  mkdir -p "$stage/bin" "$stage/include" "$stage/lib/postgresql" "$stage/share/postgresql"
+  printf 'header\n' >"$stage/include/postgres.h"
+  printf '%s\n' "$1" >"$stage/bin/postgres"
+  cp "$stage/bin/postgres" "$stage/bin/initdb"
+  while IFS=$'\t' read -r relative _aliases _abi _extra; do
+    case "$relative" in ''|'#'*) continue ;; esac
+    mkdir -p "$(dirname "$stage/$relative")"
+    printf 'side module\n' >"$stage/$relative"
+  done <"$project_root/wasmer/policies/sealed-side-modules.v1.tsv"
+  printf 'proof for %s\n' "$1" >"$stage/share/postgresql/proof.receipt"
+  printf 'installed_closure_sha256=%s\n' \
+    "$(bun "$project_root/lib/guest-build-provenance.mts" identity "$stage")" >"$stage/guest-build.receipt"
+  printf '%s\n' "$stage"
+}
+
+old="$(fresh_publish_guest_generation "$(fixture old)" "$base")"
+[ "$(fresh_resolve_guest_generation "$base")" = "$old" ]
+[ "$(fresh_publish_guest_generation "$(fixture old)" "$base")" = "$old" ]
+[ "$(cat "$old/bin/postgres")" = old ]
+
+# Kill the real publisher at observable pre-publication/selection boundaries.
+# Only the process boundary is shimmed; all hashing, fsync and renames are real.
+cat >"$work/bin/bun" <<'EOF'
+#!/usr/bin/env bash
+set -euo pipefail
+case "$1:${2:-}" in
+  */guest-build-provenance.mts:seal-identity)
+    if [ "$KILL_POINT" = before-directory ]; then kill -KILL "$GENERATION_PUBLISHER_PID"; exit 137; fi ;;
+  */select-guest-generation.mts:*)
+    if [ "$KILL_POINT" = before-selection ]; then kill -KILL "$GENERATION_PUBLISHER_PID"; exit 137; fi
+    "$REAL_BUN" "$@"
+    if [ "$KILL_POINT" = after-selection ]; then kill -KILL "$GENERATION_PUBLISHER_PID"; exit 137; fi
+    exit 0 ;;
+esac
+exec "$REAL_BUN" "$@"
+EOF
+chmod +x "$work/bin/bun"
+for point in before-directory before-selection after-selection; do
+  stage="$(fixture "$point")"
+  prior="$(fresh_resolve_guest_generation "$base")"
+  if env PATH="$work/bin:$PATH" REAL_BUN="$real_bun" KILL_POINT="$point" \
+    bash -c 'set -euo pipefail; source "$1/lib/common.sh"; source "$1/lib/sealed-carrier.sh"; export GENERATION_PUBLISHER_PID=$$; fresh_publish_guest_generation "$2" "$3"' \
+    bash "$project_root" "$stage" "$base" >"$work/$point.log" 2>&1; then
+    echo "publisher did not stop at $point" >&2; exit 1
+  fi
+  selected="$(fresh_resolve_guest_generation "$base")"
+  if [ "$point" = after-selection ]; then
+    [ "$(cat "$selected/bin/postgres")" = "$point" ]
+  else
+    [ "$selected" = "$prior" ]
+  fi
+  [ "$(cat "$old/bin/postgres")" = old ]
+  # A retry either admits the new stage or verifies the already published tree.
+  recovered="$(fresh_publish_guest_generation "$(fixture "$point")" "$base")"
+  [ "$(cat "$recovered/bin/postgres")" = "$point" ]
+done
+
+# Concurrent publishers cannot replace or nest beneath the admitted directory.
+first="$(fixture concurrent)"
+second="$(fixture concurrent)"
+fresh_publish_guest_generation "$first" "$base" >"$work/first.out" 2>"$work/first.err" &
+first_pid=$!
+fresh_publish_guest_generation "$second" "$base" >"$work/second.out" 2>"$work/second.err" &
+second_pid=$!
+first_status=0
+second_status=0
+wait "$first_pid" || first_status=$?
+wait "$second_pid" || second_status=$?
+[ "$first_status" = 0 ] || [ "$second_status" = 0 ]
+selected="$(fresh_resolve_guest_generation "$base")"
+[ "$(cat "$selected/bin/postgres")" = concurrent ]
+[ "$(find "$selected" -name '.pending.*' | wc -l)" = 0 ]
+[ "$(cat "$old/bin/postgres")" = old ]
+
+# Corruption cannot be hidden by a matching generation directory name.
+printf 'corrupt\n' >"$recovered/include/postgres.h"
+if fresh_publish_guest_generation "$(fixture after-selection)" "$base" >/dev/null 2>&1; then
+  echo 'corrupt existing generation accepted' >&2; exit 1
+fi
+printf '../escape\n' >"$base.current"
+if fresh_resolve_guest_generation "$base" >/dev/null 2>&1; then
+  echo 'escaping generation selection accepted' >&2; exit 1
+fi
+printf 'completed guest generation publication tests passed\n'
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-carrier.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-carrier.mts
new file mode 100644
index 000000000..14ec669f3
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-carrier.mts
@@ -0,0 +1,733 @@
+import assert from 'node:assert/strict';
+import { createHash, randomUUID } from 'node:crypto';
+import * as fs from 'node:fs';
+import { basename, dirname, isAbsolute, resolve } from 'node:path';
+import { parseArgs } from 'node:util';
+import { parseStrictJson } from '../../../../tools/packaging/strict-json.mts';
+import { requiredModules } from './guest-build-provenance.mts';
+import { parsePayloadInventory } from './verify-sealed-carrier.mts';
+import { safeRelative } from './receipt-files.mts';
+import { publish, writePrivate } from './durable-publication.mts';
+
+export const SCHEMA = 'oliphaunt.wasix-postmaster.immutable-carrier-deployment.v2';
+export const POLICY = 'linux-ext-fs-immutable-sealed-closure-v2';
+export const IMMUTABLE = 0x10;
+export const EXT_MAGIC = 0xef53;
+const c = fs.constants;
+const READ = c.O_RDONLY | c.O_NOFOLLOW | c.O_NONBLOCK;
+const identityNames = [
+  'manifest.json',
+  'wasmer-build.receipt',
+  'payload.files',
+  'bin/wasmer-headless',
+];
+const identityFields = [
+  'manifest-sha256',
+  'wasmer-build-receipt-sha256',
+  'payload-inventory-sha256',
+  'headless-sha256',
+];
+const expectedCount = requiredModules.length;
+type Ops = {
+  getFlags(fd: number): number;
+  setFlags(fd: number, flags: number): void;
+  filesystemMagic(fd: number): number;
+};
+type Entry = { fd: number; row: any };
+const fdPath = (fd: number, name = '') => `/proc/self/fd/${fd}${name ? `/${name}` : ''}`;
+const sha = (data: Uint8Array | string) => createHash('sha256').update(data).digest('hex');
+const requireSha = (value: unknown) =>
+  assert(typeof value === 'string' && /^[0-9a-f]{64}$/.test(value), 'invalid SHA-256');
+const sameInode = (a: fs.BigIntStats, b: fs.BigIntStats) => a.dev === b.dev && a.ino === b.ino;
+const mode = (info: fs.BigIntStats) => (info.mode & 0o7777n).toString(8).padStart(4, '0');
+const hex = (value: number) => `0x${(value >>> 0).toString(16).padStart(8, '0')}`;
+const postFlags = (value: number) => (value | IMMUTABLE) >>> 0;
+const keys = (value: any, expected: string[]) =>
+  assert.deepEqual(Object.keys(value).sort(), [...expected].sort(), 'receipt fields differ');
+const ordered = (entries: Entry[]) =>
+  [...entries].sort(
+    (a, b) =>
+      Number(a.row.path !== '.') - Number(b.row.path !== '.') ||
+      (a.row.path < b.row.path ? -1 : a.row.path > b.row.path ? 1 : 0),
+  );
+
+export function canonicalJson(value: any): string {
+  if (typeof value === 'bigint') return value.toString();
+  if (Array.isArray(value)) return `[${value.map(canonicalJson).join(',')}]`;
+  if (value && typeof value === 'object')
+    return `{${Object.keys(value)
+      .sort()
+      .map((key) => `${canonicalJson(key)}:${canonicalJson(value[key])}`)
+      .join(',')}}`;
+  return JSON.stringify(value).replace(
+    /[\u0080-\uffff]/g,
+    (char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`,
+  );
+}
+function json(data: Buffer) {
+  const text = new TextDecoder('utf-8', { fatal: true }).decode(data);
+  assert(!text.includes('\r'), 'JSON contains a carriage return');
+  return parseStrictJson(text, (_key, value, context) => {
+    if (typeof value !== 'number') return value;
+    assert(/^-?(0|[1-9][0-9]*)$/.test(context.source), 'JSON identity must use integer numbers');
+    return BigInt(context.source);
+  }) as any;
+}
+export function kernelOps(): Ops {
+  assert(process.platform === 'linux', 'immutable deployment requires Linux');
+  assert(
+    process.env.OLIPHAUNT_IMMUTABLE_KERNEL,
+    'immutable kernel binding is missing; use the Shell entry point',
+  );
+  const kernel = require(process.env.OLIPHAUNT_IMMUTABLE_KERNEL);
+  return { ...kernel, filesystemMagic: (fd: number) => fs.statfsSync(fdPath(fd)).type };
+}
+export function requireCapability() {
+  assert(process.geteuid!() === 0, 'immutable deployment/removal requires effective UID 0');
+  const capabilities = /^CapEff:\s+([0-9a-f]+)$/m.exec(
+    fs.readFileSync('/proc/self/status', 'ascii'),
+  );
+  assert(
+    capabilities && BigInt(`0x${capabilities[1]}`) & (1n << 9n),
+    'immutable deployment/removal requires effective CAP_LINUX_IMMUTABLE',
+  );
+}
+function openRoot(path: string) {
+  assert(process.platform === 'linux', 'immutable deployment requires Linux');
+  assert(
+    isAbsolute(path) && fs.realpathSync(path) === path,
+    'path must already be canonical and absolute',
+  );
+  const before = fs.lstatSync(path, { bigint: true });
+  assert(before.isDirectory(), 'root must be a non-symlink directory');
+  const fd = fs.openSync(path, READ | c.O_DIRECTORY);
+  try {
+    assert(sameInode(before, fs.fstatSync(fd, { bigint: true })), 'root changed while opening');
+    return fd;
+  } catch (error) {
+    fs.closeSync(fd);
+    throw error;
+  }
+}
+export function openBeneath(root: number, path: string, directory = false) {
+  if (path !== '.') safeRelative(path);
+  // /proc/self/fd holds the same open directory inode if its original path is replaced.
+  let fd = fs.openSync(fdPath(root), c.O_RDONLY | c.O_DIRECTORY);
+  try {
+    const parts = path === '.' ? [] : path.split('/');
+    for (let index = 0; index < parts.length; index++) {
+      const child = fs.openSync(
+        fdPath(fd, parts[index]),
+        READ | (index < parts.length - 1 || directory ? c.O_DIRECTORY : 0),
+      );
+      fs.closeSync(fd);
+      fd = child;
+    }
+    const info = fs.fstatSync(fd, { bigint: true });
+    assert(directory ? info.isDirectory() : info.isFile(), 'carrier entry type differs');
+    return fd;
+  } catch (error) {
+    fs.closeSync(fd);
+    throw error;
+  }
+}
+function readFd(fd: number, retain = false) {
+  const before = fs.fstatSync(fd, { bigint: true });
+  assert(before.isFile(), 'expected regular file');
+  if (retain) assert(before.size <= 16n * 1024n ** 2n, 'receipt exceeds 16 MiB');
+  const hash = createHash('sha256'),
+    chunks: Buffer[] = [],
+    buffer = Buffer.alloc(1024 * 1024);
+  let position = 0;
+  for (;;) {
+    const count = fs.readSync(fd, buffer, 0, buffer.length, position);
+    if (!count) break;
+    position += count;
+    assert(BigInt(position) <= before.size, 'file grew while reading');
+    hash.update(buffer.subarray(0, count));
+    if (retain) chunks.push(Buffer.from(buffer.subarray(0, count)));
+  }
+  const after = fs.fstatSync(fd, { bigint: true });
+  assert(
+    BigInt(position) === before.size &&
+      before.size === after.size &&
+      before.mtimeNs === after.mtimeNs &&
+      before.ctimeNs === after.ctimeNs,
+    'file changed while reading',
+  );
+  return { hash: hash.digest('hex'), data: Buffer.concat(chunks) };
+}
+function identity(root: number) {
+  const hashes: Record = {},
+    contents: Record = {};
+  for (const name of identityNames) {
+    const fd = openBeneath(root, name);
+    try {
+      const result = readFd(fd, name === 'manifest.json' || name === 'payload.files');
+      hashes[name] = result.hash;
+      contents[name] = result.data;
+    } finally {
+      fs.closeSync(fd);
+    }
+  }
+  return { hashes, contents };
+}
+function expectedIdentity(actual: Record, expected?: Record) {
+  if (expected)
+    for (const name of identityNames) {
+      requireSha(expected[name]);
+      assert.equal(actual[name], expected[name], `carrier identity changed: ${name}`);
+    }
+}
+function carrierIdentity(path: string, root: fs.BigIntStats, hashes: Record) {
+  return {
+    'closure-identity': sha(
+      [
+        'oliphaunt.wasix-postmaster.qualification-carrier.v1',
+        ...identityNames.map((name) => hashes[name]),
+        '',
+      ].join('\0'),
+    ),
+    device: root.dev,
+    inode: root.ino,
+    path,
+    ...Object.fromEntries(
+      identityFields.map((field, index) => [field, hashes[identityNames[index]]]),
+    ),
+  };
+}
+function provenance(data: Buffer) {
+  const manifest = json(data);
+  assert(
+    manifest['format-version'] === 6n &&
+      manifest.schema === 'oliphaunt.wasix-postmaster.sealed-aot.v5',
+    'manifest provenance schema differs',
+  );
+  assert(['release-o3', 'safe-o2'].includes(manifest['core-profile']), 'invalid core profile');
+  requireSha(manifest['guest-build-recipe-sha256']);
+  return {
+    core_profile: manifest['core-profile'],
+    guest_build_recipe_sha256: manifest['guest-build-recipe-sha256'],
+  };
+}
+function directPaths(data: Buffer) {
+  const artifacts = json(data).artifacts;
+  assert(
+    Array.isArray(artifacts) && artifacts.length === expectedCount,
+    'manifest AOT count differs',
+  );
+  const paths = new Map();
+  for (const artifact of artifacts) {
+    assert(
+      typeof artifact.path === 'string' &&
+        /^aot\/[0-9A-F]{64}\.bin$/.test(artifact.path) &&
+        !paths.has(artifact.path),
+      'invalid or duplicate AOT path',
+    );
+    requireSha(artifact.sha256);
+    paths.set(artifact.path, artifact.sha256);
+  }
+  return paths;
+}
+function inventory(data: Buffer) {
+  return new Map(
+    [...parsePayloadInventory(data)].map(([path, record]) => [
+      path,
+      { size: BigInt(record.size), hash: record.sha256 },
+    ]),
+  );
+}
+function closeAll(entries: Entry[]) {
+  for (const entry of entries) fs.closeSync(entry.fd);
+}
+function closure(root: number, contents: Record, ops: Ops): Entry[] {
+  const files = inventory(contents['payload.files']),
+    direct = directPaths(contents['manifest.json']),
+    entries: Entry[] = [];
+  files.set('payload.files', {
+    size: BigInt(contents['payload.files'].length),
+    hash: sha(contents['payload.files']),
+  });
+  function walk(path: string, directory: boolean, before?: fs.BigIntStats) {
+    const fd = openBeneath(root, path, directory);
+    const entry = { fd, row: {} as any };
+    entries.push(entry);
+    const info = fs.fstatSync(fd, { bigint: true }),
+      permissions = mode(info);
+    assert(
+      directory ? permissions === '0555' : ['0444', '0555'].includes(permissions),
+      `sealed mode differs: ${path}`,
+    );
+    assert.equal(
+      ops.filesystemMagic(fd),
+      EXT_MAGIC,
+      'carrier entry must reside on ext-family filesystem',
+    );
+    if (before) assert(sameInode(before, info), 'carrier entry changed while opening');
+    const hash = directory ? null : readFd(fd).hash;
+    if (!directory) {
+      assert.deepEqual({ size: info.size, hash }, files.get(path), `payload differs: ${path}`);
+      if (direct.has(path))
+        assert.equal(hash, direct.get(path), `direct-loader SHA-256 differs: ${path}`);
+    }
+    const flags = ops.getFlags(fd);
+    entry.row = {
+      device: info.dev,
+      inode: info.ino,
+      size: info.size,
+      uid: info.uid,
+      gid: info.gid,
+      mode: permissions,
+      path,
+      'entry-type': directory ? 'directory' : 'file',
+      'direct-loader-kind': direct.has(path) ? 'aot' : 'none',
+      sha256: hash,
+      'pre-flags': hex(flags),
+      'post-flags': hex(postFlags(flags)),
+    };
+    if (directory)
+      for (const name of fs.readdirSync(fdPath(fd)).sort()) {
+        const relative = path === '.' ? name : `${path}/${name}`;
+        safeRelative(relative);
+        const before = fs.lstatSync(fdPath(fd, name), { bigint: true });
+        assert(
+          before.isFile() || before.isDirectory(),
+          'carrier contains a symlink or special entry',
+        );
+        walk(relative, before.isDirectory(), before);
+      }
+  }
+  try {
+    walk('.', true);
+    assert.deepEqual(
+      entries
+        .filter((e) => e.row['entry-type'] === 'file')
+        .map((e) => e.row.path)
+        .sort(),
+      [...files.keys()].sort(),
+      'carrier file closure differs',
+    );
+    assert.deepEqual(
+      entries
+        .filter((e) => e.row['direct-loader-kind'] === 'aot')
+        .map((e) => e.row.path)
+        .sort(),
+      [...direct.keys()].sort(),
+      'direct-loader closure differs',
+    );
+    return entries;
+  } catch (error) {
+    closeAll(entries);
+    throw error;
+  }
+}
+
+function receiptParent(path: string, carrier: string) {
+  assert(isAbsolute(path) && resolve(path) === path, 'receipt path must be canonical and absolute');
+  assert(
+    path !== carrier && !path.startsWith(`${carrier}/`),
+    'receipt must be outside the carrier',
+  );
+  return openRoot(dirname(path));
+}
+function readReceipt(path: string, carrier: string, ops: Ops, owner: bigint, immutable: boolean) {
+  const parent = receiptParent(path, carrier);
+  let fd = -1;
+  try {
+    fd = openBeneath(parent, basename(path));
+    const info = fs.fstatSync(fd, { bigint: true });
+    assert(
+      info.uid === owner && mode(info) === '0444',
+      'deployment receipt must be root-owned with mode 0444',
+    );
+    assert.equal(
+      ops.filesystemMagic(fd),
+      EXT_MAGIC,
+      'deployment receipt must reside on ext-family filesystem',
+    );
+    if (immutable)
+      assert(ops.getFlags(fd) & IMMUTABLE, 'deployment receipt inode is not immutable');
+    const { data, hash } = readFd(fd, true),
+      receipt = json(data);
+    assert.equal(
+      `${canonicalJson(receipt)}\n`,
+      data.toString('utf8'),
+      'deployment receipt is not canonical JSON',
+    );
+    keys(receipt, [
+      'carrier',
+      'core_profile',
+      'direct-loader-paths',
+      'entries',
+      'filesystem',
+      'guest_build_recipe_sha256',
+      'policy',
+      'schema',
+    ]);
+    assert(
+      receipt.schema === SCHEMA && receipt.policy === POLICY,
+      'deployment receipt policy differs',
+    );
+    assert(
+      ['release-o3', 'safe-o2'].includes(receipt.core_profile),
+      'deployment receipt core profile differs',
+    );
+    requireSha(receipt.guest_build_recipe_sha256);
+    return { receipt, info, hash };
+  } finally {
+    if (fd >= 0) fs.closeSync(fd);
+    fs.closeSync(parent);
+  }
+}
+function unlinkReceipt(path: string, info: fs.BigIntStats, hash: string, ops: Ops) {
+  const parent = receiptParent(path, '/nonexistent-carrier-placeholder');
+  let fd = -1;
+  try {
+    const name = fdPath(parent, basename(path));
+    fd = openBeneath(parent, basename(path));
+    assert(
+      sameInode(info, fs.fstatSync(fd, { bigint: true })),
+      'receipt identity changed before removal',
+    );
+    assert.equal(readFd(fd).hash, hash, 'receipt content changed before removal');
+    const flags = (ops.getFlags(fd) & ~IMMUTABLE) >>> 0;
+    ops.setFlags(fd, flags);
+    assert.equal(ops.getFlags(fd), flags, 'receipt immutable flag could not be cleared');
+    assert(
+      sameInode(info, fs.lstatSync(name, { bigint: true })),
+      'receipt path changed before removal',
+    );
+    fs.unlinkSync(name);
+    fs.fsyncSync(parent);
+  } finally {
+    if (fd >= 0) fs.closeSync(fd);
+    fs.closeSync(parent);
+  }
+}
+async function writeReceipt(path: string, carrier: string, data: Buffer, ops: Ops, owner: bigint) {
+  const parent = receiptParent(path, carrier);
+  const temporary = fdPath(parent, `.${basename(path)}.pending.${randomUUID()}`),
+    destination = fdPath(parent, basename(path));
+  let fd = -1,
+    published = false;
+  try {
+    const source = await writePrivate(
+      temporary,
+      (async function* () {
+        yield data;
+      })(),
+      parent,
+    );
+    fd = fs.openSync(temporary, READ);
+    const info = fs.fstatSync(fd, { bigint: true });
+    assert.equal(info.uid, owner, 'deployment receipt has the wrong owner');
+    assert.equal(
+      ops.filesystemMagic(fd),
+      EXT_MAGIC,
+      'deployment receipt must reside on ext-family filesystem',
+    );
+    const flags = ops.getFlags(fd);
+    assert(!(flags & IMMUTABLE), 'new deployment receipt unexpectedly begins immutable');
+    publish(temporary, destination, source, parent);
+    published = true;
+    ops.setFlags(fd, postFlags(flags));
+    assert.equal(ops.getFlags(fd), postFlags(flags), 'receipt immutable flag did not stick');
+    fs.fsyncSync(fd);
+    fs.fsyncSync(parent);
+    return { info, hash: sha(data) };
+  } catch (error) {
+    if (published && fd >= 0) {
+      const info = fs.fstatSync(fd, { bigint: true });
+      try {
+        unlinkReceipt(path, info, sha(data), ops);
+      } catch {
+        /* Keep the journal if exact cleanup fails. */
+      }
+    }
+    try {
+      fs.unlinkSync(temporary);
+      fs.fsyncSync(parent);
+    } catch (cleanup) {
+      if (cleanup.code !== 'ENOENT')
+        throw new AggregateError([error, cleanup], 'receipt cleanup failed');
+    }
+    throw error;
+  } finally {
+    if (fd >= 0) fs.closeSync(fd);
+    fs.closeSync(parent);
+  }
+}
+function transitionOrder(entries: Entry[]) {
+  const rank = (row: any) => (row['entry-type'] === 'file' ? 0 : row.path === '.' ? 2 : 1);
+  return [...entries].sort(
+    (a, b) =>
+      rank(a.row) - rank(b.row) ||
+      (a.row['entry-type'] === 'directory'
+        ? b.row.path.split('/').length - a.row.path.split('/').length
+        : 0) ||
+      (a.row.path < b.row.path ? -1 : a.row.path > b.row.path ? 1 : 0),
+  );
+}
+function transition(entries: Entry[], ops: Ops, freeze: boolean) {
+  const errors: unknown[] = [];
+  for (const { fd, row } of entries)
+    try {
+      const pre = Number(row['pre-flags']),
+        post = Number(row['post-flags']),
+        desired = freeze ? post : pre;
+      const current = ops.getFlags(fd);
+      assert(current === pre || current === post, `inode flags diverged: ${row.path}`);
+      if (current !== desired) ops.setFlags(fd, desired);
+      assert.equal(ops.getFlags(fd), desired, `flag transition did not stick: ${row.path}`);
+    } catch (error) {
+      errors.push(error);
+    }
+  if (errors.length) throw new AggregateError(errors, 'failed to transition inode flags');
+}
+function receiptEntries(receipt: any, remove = false) {
+  assert(Array.isArray(receipt.entries) && receipt.entries.length, 'empty receipt closure');
+  let previous = '';
+  for (const row of receipt.entries) {
+    const fields = [
+      'device',
+      'direct-loader-kind',
+      'entry-type',
+      'inode',
+      'mode',
+      'path',
+      'post-flags',
+      'pre-flags',
+      'sha256',
+      'size',
+    ];
+    if (!remove || 'uid' in row || 'gid' in row) fields.push('uid', 'gid');
+    keys(row, fields);
+    if (row.path !== '.') safeRelative(row.path);
+    assert(
+      !previous ||
+        (previous === '.' && row.path !== '.') ||
+        (previous !== '.' && row.path > previous),
+      'receipt paths must be strictly sorted with root first',
+    );
+    previous = row.path;
+    assert(
+      ['file', 'directory'].includes(row['entry-type']) &&
+        ['none', 'aot'].includes(row['direct-loader-kind']),
+      'invalid receipt entry type',
+    );
+    for (const field of ['device', 'inode', 'size', ...('uid' in row ? ['uid', 'gid'] : [])])
+      assert(
+        typeof row[field] === 'bigint' && row[field] >= (field === 'inode' ? 1n : 0n),
+        `invalid receipt ${field}`,
+      );
+    if (row['entry-type'] === 'file') {
+      requireSha(row.sha256);
+      assert(['0444', '0555'].includes(row.mode), 'file mode differs');
+    } else
+      assert(
+        row.sha256 === null && row.mode === '0555' && row['direct-loader-kind'] === 'none',
+        'directory identity differs',
+      );
+    for (const field of ['pre-flags', 'post-flags'])
+      assert(/^0x[0-9a-f]{8}$/.test(row[field]), 'invalid flag encoding');
+    assert.equal(
+      Number(row['post-flags']),
+      postFlags(Number(row['pre-flags'])),
+      'invalid immutable transition',
+    );
+  }
+  assert(
+    receipt.entries[0].path === '.' && receipt.entries[0]['entry-type'] === 'directory',
+    'receipt must begin with root',
+  );
+  const direct = receipt.entries
+    .filter((row) => row['direct-loader-kind'] === 'aot')
+    .map((row) => row.path);
+  assert.deepEqual(receipt['direct-loader-paths'], direct, 'receipt direct-loader subset differs');
+  assert.equal(direct.length, expectedCount, 'receipt AOT count differs');
+  return receipt.entries;
+}
+function checkLive(fd: number, row: any, ops: Ops, remove = false) {
+  const info = fs.fstatSync(fd, { bigint: true });
+  assert.deepEqual(
+    [info.dev, info.ino, info.size],
+    [row.device, row.inode, row.size],
+    `deployment inode identity differs: ${row.path}`,
+  );
+  assert.equal(mode(info), row.mode, `deployment entry mode differs: ${row.path}`);
+  if ('uid' in row)
+    assert.deepEqual(
+      [info.uid, info.gid],
+      [row.uid, row.gid],
+      `deployment entry ownership differs: ${row.path}`,
+    );
+  else assert(remove, 'deployment ownership is not receipt-bound');
+  const flags = ops.getFlags(fd);
+  assert(
+    flags === Number(row['post-flags']) || (remove && flags === Number(row['pre-flags'])),
+    `deployment inode flags differ: ${row.path}`,
+  );
+}
+function verifyRoot(receipt: any, path: string, fd: number, expected?: Record) {
+  const hashes = Object.fromEntries(
+    identityNames.map((name, index) => [name, receipt.carrier[identityFields[index]]]),
+  );
+  for (const hash of Object.values(hashes)) requireSha(hash);
+  expectedIdentity(hashes, expected);
+  assert.deepEqual(
+    receipt.carrier,
+    carrierIdentity(path, fs.fstatSync(fd, { bigint: true }), hashes),
+    'receipt carrier identity differs',
+  );
+  assert.deepEqual(
+    receipt.filesystem,
+    { magic: '0xef53', type: 'ext-family' },
+    'receipt filesystem differs',
+  );
+}
+export async function operate(
+  action: 'deploy' | 'verify' | 'verify-fast' | 'remove',
+  carrier: string,
+  receiptPath: string,
+  expected?: Record,
+  ops: Ops = kernelOps(),
+  checkCapability = requireCapability,
+  owner = 0n,
+) {
+  if (action === 'deploy' || action === 'remove') checkCapability();
+  assert(
+    action === 'verify-fast' || expected,
+    'full operations require all carrier identity hashes',
+  );
+  const root = openRoot(carrier);
+  let entries: Entry[] = [];
+  try {
+    assert.equal(
+      ops.filesystemMagic(root),
+      EXT_MAGIC,
+      'carrier root must reside on ext-family filesystem',
+    );
+    if (action === 'deploy') {
+      const { hashes, contents } = identity(root);
+      expectedIdentity(hashes, expected);
+      entries = closure(root, contents, ops);
+      const receipt = {
+        carrier: carrierIdentity(carrier, fs.fstatSync(root, { bigint: true }), hashes),
+        filesystem: { magic: '0xef53', type: 'ext-family' },
+        ...provenance(contents['manifest.json']),
+        'direct-loader-paths': ordered(entries)
+          .filter((entry) => entry.row['direct-loader-kind'] === 'aot')
+          .map((entry) => entry.row.path),
+        entries: ordered(entries).map((entry) => entry.row),
+        policy: POLICY,
+        schema: SCHEMA,
+      };
+      const journal = await writeReceipt(
+        receiptPath,
+        carrier,
+        Buffer.from(`${canonicalJson(receipt)}\n`),
+        ops,
+        owner,
+      );
+      try {
+        transition(transitionOrder(entries), ops, true);
+        assert.deepEqual(
+          identity(root).hashes,
+          hashes,
+          'carrier identity changed during deployment',
+        );
+      } catch (error) {
+        transition(transitionOrder(entries).reverse(), ops, false);
+        unlinkReceipt(receiptPath, journal.info, journal.hash, ops);
+        throw error;
+      }
+      return receipt;
+    }
+    const loaded = readReceipt(receiptPath, carrier, ops, owner, action !== 'remove'),
+      receipt = loaded.receipt;
+    verifyRoot(receipt, carrier, root, expected);
+    const rows = receiptEntries(receipt, action === 'remove');
+    if (action === 'verify-fast') {
+      for (const row of rows) {
+        const fd = openBeneath(root, row.path, row['entry-type'] === 'directory');
+        entries.push({ fd, row });
+        checkLive(fd, row, ops);
+      }
+      return receipt;
+    }
+    const { hashes, contents } = identity(root);
+    expectedIdentity(hashes, expected);
+    assert.deepEqual(
+      receipt.carrier,
+      carrierIdentity(carrier, fs.fstatSync(root, { bigint: true }), hashes),
+      'receipt carrier hashes differ',
+    );
+    const guest = provenance(contents['manifest.json']);
+    assert(
+      receipt.core_profile === guest.core_profile &&
+        receipt.guest_build_recipe_sha256 === guest.guest_build_recipe_sha256,
+      'receipt provenance differs',
+    );
+    entries = closure(root, contents, ops);
+    const sorted = ordered(entries);
+    assert.deepEqual(
+      sorted.map((entry) => entry.row.path),
+      rows.map((row) => row.path),
+      'receipt carrier closure differs',
+    );
+    for (let index = 0; index < rows.length; index++) {
+      const entry = sorted[index],
+        row = rows[index];
+      checkLive(entry.fd, row, ops, action === 'remove');
+      for (const key of ['sha256', 'entry-type', 'direct-loader-kind'])
+        assert.equal(entry.row[key], row[key], `receipt ${key} differs`);
+      entry.row = row;
+    }
+    if (action === 'remove') {
+      try {
+        transition(transitionOrder(entries).reverse(), ops, false);
+      } catch (error) {
+        transition(transitionOrder(entries), ops, true);
+        throw error;
+      }
+      unlinkReceipt(receiptPath, loaded.info, loaded.hash, ops);
+    }
+    return receipt;
+  } finally {
+    closeAll(entries);
+    fs.closeSync(root);
+  }
+}
+if (import.meta.main) {
+  try {
+    const actions = ['deploy', 'verify', 'verify-fast', 'remove'] as const;
+    const options = Object.fromEntries([
+      ...actions.map((action) => [action, { type: 'boolean' }]),
+      ...['carrier', 'receipt', ...identityFields].map((name) => [name, { type: 'string' }]),
+    ]);
+    const { values } = parseArgs({ options });
+    const selected = actions.filter((action) => values[action]);
+    assert(
+      selected.length === 1 && values.carrier && values.receipt,
+      'select exactly one operation with --carrier and --receipt',
+    );
+    const hashes = identityFields.map((field) => values[field]);
+    assert(
+      hashes.every(Boolean) ||
+        (selected[0] === 'verify-fast' && hashes.every((value) => value === undefined)),
+      'identity hashes must be all present or all absent',
+    );
+    await operate(
+      selected[0],
+      values.carrier,
+      values.receipt,
+      hashes.every(Boolean)
+        ? Object.fromEntries(identityNames.map((name, i) => [name, hashes[i]]))
+        : undefined,
+    );
+    console.log(`${selected[0]} immutable sealed carrier closure: ${values.carrier}`);
+  } catch (error) {
+    console.error('immutable carrier deployment failed:', error);
+    process.exitCode = 2;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-carrier.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-carrier.sh
new file mode 100644
index 000000000..cd12fe773
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-carrier.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# Shell owns compilation; TypeScript owns the deployment transaction.
+fresh_immutable_kernel() (
+  set -euo pipefail
+  [ "$(uname -s)" = Linux ] || { echo 'immutable deployment requires Linux' >&2; exit 2; }
+  local source="$FRESH_ROOT/lib/immutable-kernel.c"
+  local directory="$FRESH_WORK_ROOT/immutable-kernel/$(uname -m)/$(fresh_wasmer_bin_hash "$source")"
+  local binding="$directory/kernel.node" temporary=""
+  if [ ! -f "$binding" ] || [ -L "$binding" ]; then
+    mkdir -p "$directory"
+    temporary="$(mktemp "$directory/.kernel.XXXXXX")"
+    trap 'rm -f "$temporary"' EXIT
+    "${HOST_CC:-cc}" -shared -fPIC -std=c11 -Wall -Wextra -Werror "$source" -o "$temporary"
+    mv -f "$temporary" "$binding"
+  fi
+  printf '%s\n' "$binding"
+)
+
+fresh_immutable_carrier() {
+  local binding
+  binding="$(fresh_immutable_kernel)" || return
+  OLIPHAUNT_IMMUTABLE_KERNEL="$binding" bun "$FRESH_ROOT/lib/immutable-carrier.mts" "$@"
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-carrier.test.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-carrier.test.mts
new file mode 100644
index 000000000..7306e26ae
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-carrier.test.mts
@@ -0,0 +1,238 @@
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import * as fs from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { test } from 'node:test';
+import { canonicalJson, EXT_MAGIC, IMMUTABLE, openBeneath, operate } from './immutable-carrier.mts';
+
+const sha = (data: string | Buffer) => createHash('sha256').update(data).digest('hex');
+function fixture() {
+  const directory = fs.mkdtempSync(join(tmpdir(), 'immutable-carrier-')),
+    carrier = join(directory, 'carrier'),
+    receipt = join(directory, 'deployment.json');
+  fs.mkdirSync(join(carrier, 'aot'), { recursive: true });
+  fs.mkdirSync(join(carrier, 'bin'));
+  const files = new Map();
+  const artifacts = Array.from({ length: 29 }, (_, index) => {
+    const path = `aot/${(index + 1).toString(16).toUpperCase().padStart(64, '0')}.bin`,
+      data = `artifact-${index}\n`;
+    files.set(path, data);
+    return { path, sha256: sha(data) };
+  });
+  files.set(
+    'manifest.json',
+    `${canonicalJson({
+      artifacts,
+      'core-profile': 'release-o3',
+      'format-version': 6,
+      'guest-build-recipe-sha256': '9'.repeat(64),
+      schema: 'oliphaunt.wasix-postmaster.sealed-aot.v5',
+    })}\n`,
+  );
+  files.set('wasmer-build.receipt', 'schema=fake\n');
+  files.set('bin/wasmer-headless', 'fake-headless\n');
+  files.set(
+    'payload.files',
+    [
+      'schema=oliphaunt.wasix-postmaster.payload-files.v1',
+      ...[...files]
+        .sort(([a], [b]) => (a < b ? -1 : 1))
+        .map(([path, data]) => `${sha(data)}\t${Buffer.byteLength(data)}\t${path}`),
+      '',
+    ].join('\n'),
+  );
+  for (const [path, data] of files) fs.writeFileSync(join(carrier, path), data, { mode: 0o444 });
+  for (const path of ['aot', 'bin', '.']) fs.chmodSync(join(carrier, path), 0o555);
+  const expected = Object.fromEntries(
+    ['manifest.json', 'wasmer-build.receipt', 'payload.files', 'bin/wasmer-headless'].map(
+      (path) => [path, sha(files.get(path)!)],
+    ),
+  );
+  const flags = new Map();
+  let calls = 0,
+    failAt = -1;
+  const key = (fd: number) => {
+    const info = fs.fstatSync(fd, { bigint: true });
+    return `${info.dev}:${info.ino}`;
+  };
+  const ops = {
+    filesystemMagic: () => EXT_MAGIC,
+    getFlags(fd: number) {
+      const k = key(fd);
+      if (!flags.has(k)) flags.set(k, 0x80000);
+      return flags.get(k)!;
+    },
+    setFlags(fd: number, value: number) {
+      if (++calls === failAt) throw Error('injected transition failure');
+      flags.set(key(fd), value);
+    },
+  };
+  return {
+    directory,
+    carrier,
+    receipt,
+    expected,
+    flags,
+    ops,
+    failNext(offset: number) {
+      failAt = calls + offset;
+    },
+    run: (action: Parameters[0], fast = false) =>
+      operate(
+        action,
+        carrier,
+        receipt,
+        fast ? undefined : expected,
+        ops,
+        () => {},
+        BigInt(process.geteuid!()),
+      ),
+    rewrite(value: unknown) {
+      fs.chmodSync(receipt, 0o644);
+      fs.writeFileSync(receipt, `${canonicalJson(value)}\n`);
+      fs.chmodSync(receipt, 0o444);
+    },
+    cleanup() {
+      for (const path of ['aot', 'bin', '.']) fs.chmodSync(join(carrier, path), 0o755);
+      fs.rmSync(directory, { recursive: true, force: true });
+    },
+  };
+}
+
+test('immutable deployment retains exact receipts, fast verification and removal', {
+  skip: process.platform !== 'linux',
+}, async () => {
+  const f = fixture();
+  try {
+    const receipt = await f.run('deploy');
+    assert.equal(fs.readFileSync(f.receipt, 'utf8'), `${canonicalJson(receipt)}\n`);
+    assert.equal(receipt['direct-loader-paths'].length, 29);
+    assert([...f.flags.values()].every((flags) => flags & IMMUTABLE));
+    assert.deepEqual(await f.run('verify'), receipt);
+    // Fast verification checks inode metadata; the full verification must detect changed payload bytes.
+    const file = join(f.carrier, receipt['direct-loader-paths'][0]);
+    const data = fs.readFileSync(file);
+    fs.chmodSync(file, 0o644);
+    fs.writeFileSync(file, Buffer.alloc(data.length, 65));
+    fs.chmodSync(file, 0o444);
+    assert.deepEqual(await f.run('verify-fast', true), receipt);
+    await assert.rejects(f.run('verify'), /payload differs/);
+    fs.chmodSync(file, 0o644);
+    fs.writeFileSync(file, data);
+    fs.chmodSync(file, 0o444);
+    await f.run('remove');
+    assert(!fs.existsSync(f.receipt));
+    assert([...f.flags.values()].every((flags) => flags === 0x80000));
+  } finally {
+    f.cleanup();
+  }
+});
+
+test('immutable transition failures restore exact flags and retain recoverable journals', {
+  skip: process.platform !== 'linux',
+}, async () => {
+  const f = fixture();
+  try {
+    f.failNext(4);
+    await assert.rejects(f.run('deploy'), /transition/);
+    assert(!fs.existsSync(f.receipt));
+    assert([...f.flags.values()].every((flags) => flags === 0x80000));
+    const receipt = await f.run('deploy');
+    f.failNext(3);
+    await assert.rejects(f.run('remove'), /transition/);
+    assert.deepEqual(await f.run('verify-fast'), receipt);
+    const first = receipt.entries[0];
+    f.flags.set(`${first.device}:${first.inode}`, Number(first['pre-flags']));
+    const receiptInfo = fs.statSync(f.receipt, { bigint: true });
+    f.flags.set(`${receiptInfo.dev}:${receiptInfo.ino}`, 0x80000);
+    // Recovery accepts journals predating ownership fields, but normal verification never does.
+    for (const entry of receipt.entries) {
+      delete entry.uid;
+      delete entry.gid;
+    }
+    f.rewrite(receipt);
+    await assert.rejects(f.run('verify-fast'));
+    await f.run('remove');
+    assert(!fs.existsSync(f.receipt));
+    assert([...f.flags.values()].every((flags) => flags === 0x80000));
+  } finally {
+    f.cleanup();
+  }
+});
+
+test('immutable verification rejects changed ownership and same-byte replacement inodes', {
+  skip: process.platform !== 'linux',
+}, async () => {
+  const f = fixture();
+  try {
+    const receipt = await f.run('deploy');
+    receipt.entries[0].uid += 1n;
+    f.rewrite(receipt);
+    await assert.rejects(f.run('verify-fast'), /ownership differs/);
+    receipt.entries[0].uid -= 1n;
+    f.rewrite(receipt);
+    const file = join(f.carrier, receipt['direct-loader-paths'][0]);
+    fs.chmodSync(join(f.carrier, 'aot'), 0o755);
+    fs.writeFileSync(`${file}.replacement`, fs.readFileSync(file), { mode: 0o444 });
+    fs.renameSync(`${file}.replacement`, file);
+    fs.chmodSync(join(f.carrier, 'aot'), 0o555);
+    await assert.rejects(f.run('verify'), /inode identity differs/);
+  } finally {
+    f.cleanup();
+  }
+});
+
+test('open descriptor traversal survives parent replacement and rejects symlinks', {
+  skip: process.platform !== 'linux',
+}, () => {
+  const parent = fs.mkdtempSync(join(tmpdir(), 'immutable-descriptor-'));
+  let root = -1;
+  try {
+    fs.mkdirSync(join(parent, 'root'));
+    fs.writeFileSync(join(parent, 'root', 'file'), 'original');
+    root = fs.openSync(join(parent, 'root'), fs.constants.O_RDONLY | fs.constants.O_DIRECTORY);
+    fs.renameSync(join(parent, 'root'), join(parent, 'moved'));
+    fs.mkdirSync(join(parent, 'root'));
+    fs.writeFileSync(join(parent, 'root', 'file'), 'replacement');
+    const fd = openBeneath(root, 'file');
+    try {
+      assert.equal(fs.readFileSync(fd, 'utf8'), 'original');
+    } finally {
+      fs.closeSync(fd);
+    }
+    fs.symlinkSync('/etc/passwd', join(parent, 'moved', 'link'));
+    assert.throws(() => openBeneath(root, 'link'));
+    assert.throws(() => openBeneath(root, '../file'));
+    assert.equal(
+      canonicalJson({ inode: 18446744073709551615n, unicode: 'é' }),
+      '{"inode":18446744073709551615,"unicode":"\\u00e9"}',
+    );
+  } finally {
+    if (root >= 0) fs.closeSync(root);
+    fs.rmSync(parent, { recursive: true, force: true });
+  }
+});
+
+test('native immutable binding queries exact descriptors and enforces privileges', {
+  skip: !process.env.OLIPHAUNT_IMMUTABLE_KERNEL,
+}, async () => {
+  const { kernelOps, requireCapability } = await import('./immutable-carrier.mts');
+  const directory = fs.mkdtempSync(join(tmpdir(), 'immutable-kernel-'));
+  const fd = fs.openSync(join(directory, 'file'), 'wx');
+  try {
+    const ops = kernelOps(),
+      flags = ops.getFlags(fd);
+    assert.equal(ops.filesystemMagic(fd), EXT_MAGIC);
+    ops.setFlags(fd, flags);
+    assert.equal(ops.getFlags(fd), flags);
+    assert.throws(() => ops.getFlags(-1));
+    if (process.geteuid!() !== 0) {
+      assert.throws(requireCapability, /effective UID 0/);
+      assert.throws(() => ops.setFlags(fd, flags | IMMUTABLE));
+    }
+  } finally {
+    fs.closeSync(fd);
+    fs.rmSync(directory, { recursive: true, force: true });
+  }
+});
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-kernel.c b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-kernel.c
new file mode 100644
index 000000000..e8f0557f0
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-kernel.c
@@ -0,0 +1,49 @@
+/* Stable Node-API entry points; this tiny Linux ioctl binding needs no SDK headers. */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+typedef struct napi_env__ *napi_env;
+typedef struct napi_value__ *napi_value;
+typedef struct napi_callback_info__ *napi_callback_info;
+typedef napi_value (*napi_callback)(napi_env, napi_callback_info);
+extern int napi_get_cb_info(napi_env, napi_callback_info, size_t *, napi_value *, napi_value *, void **);
+extern int napi_get_value_int32(napi_env, napi_value, int32_t *);
+extern int napi_get_value_uint32(napi_env, napi_value, uint32_t *);
+extern int napi_create_uint32(napi_env, uint32_t, napi_value *);
+extern int napi_throw_error(napi_env, const char *, const char *);
+extern int napi_create_function(napi_env, const char *, size_t, napi_callback, void *, napi_value *);
+extern int napi_set_named_property(napi_env, napi_value, const char *, napi_value);
+
+static napi_value flags(napi_env env, napi_callback_info info) {
+    napi_value args[2], result;
+    size_t count = 2;
+    void *operation;
+    int32_t fd;
+    uint32_t value = 0;
+    if (napi_get_cb_info(env, info, &count, args, NULL, &operation) ||
+        count != ((uintptr_t)operation == FS_IOC_SETFLAGS ? 2u : 1u) ||
+        napi_get_value_int32(env, args[0], &fd) || fd < 0 ||
+        (count == 2 && napi_get_value_uint32(env, args[1], &value))) {
+        napi_throw_error(env, NULL, "invalid immutable ioctl arguments");
+        return NULL;
+    }
+    if (ioctl(fd, (unsigned long)(uintptr_t)operation, &value) < 0) {
+        napi_throw_error(env, NULL, strerror(errno));
+        return NULL;
+    }
+    if (napi_create_uint32(env, value, &result)) return NULL;
+    return result;
+}
+
+napi_value napi_register_module_v1(napi_env env, napi_value exports) {
+    napi_value get, set;
+    if (napi_create_function(env, "getFlags", 8, flags, (void *)(uintptr_t)FS_IOC_GETFLAGS, &get) ||
+        napi_create_function(env, "setFlags", 8, flags, (void *)(uintptr_t)FS_IOC_SETFLAGS, &set) ||
+        napi_set_named_property(env, exports, "getFlags", get) ||
+        napi_set_named_property(env, exports, "setFlags", set)) return NULL;
+    return exports;
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-kernel.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-kernel.test.sh
new file mode 100644
index 000000000..d9b063407
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/immutable-kernel.test.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+set -euo pipefail
+[ "$(uname -s)" = Linux ] || exit 0
+lib="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+temporary="$(mktemp -d)"
+trap 'rm -rf "$temporary"' EXIT
+source "$lib/common.sh"
+source "$lib/immutable-carrier.sh"
+export FRESH_WORK_ROOT="$temporary"
+binding="$(fresh_immutable_kernel)"
+[ "$(HOST_CC=false fresh_immutable_kernel)" = "$binding" ]
+OLIPHAUNT_IMMUTABLE_KERNEL="$binding" bun test "$lib/immutable-carrier.test.mts" -t 'native immutable'
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/linear-memory-profile.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/linear-memory-profile.mts
new file mode 100644
index 000000000..19ff0e0f6
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/linear-memory-profile.mts
@@ -0,0 +1,132 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { readFileSync, writeFileSync } from 'node:fs';
+import { parseStrictJson } from '../../../../tools/packaging/strict-json.mts';
+import { atomicFile, member, readJson, safeRelative } from './receipt-files.mts';
+
+export const profileId =
+  'oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1';
+export const profile = {
+  'address-width': 'wasm32',
+  'supported-host-pointer-width': 'u64',
+  'maximum-pages': 4096,
+  'maximum-bytes': 268435456,
+  'static-bound-pages': 65536,
+  'static-offset-guard-bytes': 2147483648,
+  'requires-shared': true,
+  'requires-import': 'env.memory',
+  'excludes-wasm32-end-wrap': true,
+  'static-access-lowering': 'wasmer-llvm-unchecked-reservation-and-guard-v1',
+};
+export const fields = [
+  'source-module-sha256',
+  'module-sha256',
+  'initial-pages',
+  'maximum-pages',
+  'maximum-bytes',
+  'shared',
+  'import-module',
+  'import-name',
+  'transformation',
+];
+
+export function closureHash(records: Record[], field: string) {
+  const digest = createHash('sha256');
+  const values = [
+    'oliphaunt.wasix-postmaster.linear-memory-install-closure.v1',
+    field,
+    ...records.flatMap((record) => [record.path, record[field]]),
+  ];
+  for (const value of values) {
+    assert(typeof value === 'string', 'invalid closure hash field');
+    const encoded = Buffer.from(value),
+      length = Buffer.alloc(8);
+    length.writeBigUInt64BE(BigInt(encoded.length));
+    digest.update(length).update(encoded);
+  }
+  return digest.digest('hex');
+}
+
+function aggregate(
+  stage: string,
+  index: string,
+  predecessor: string,
+  predecessorHash: string,
+  destination: string,
+) {
+  const observed = parseStrictJson(process.env.PROFILE_JSON ?? '') as Record;
+  assert.equal(observed.id, profileId, 'memory profile ID differs');
+  for (const [key, expected] of Object.entries(profile))
+    assert.equal(observed[key], expected, `memory profile differs: ${key}`);
+  const records = readFileSync(index, 'utf8')
+    .trimEnd()
+    .split('\n')
+    .map((line) => {
+      const parts = line.split('\t');
+      assert(parts.length === 2, 'invalid module index');
+      const [path, receiptPath] = parts;
+      safeRelative(path);
+      const receipt = readJson(member(stage, receiptPath));
+      assert(
+        receipt.schema === 'oliphaunt.wasix-postmaster.linear-memory-module.v1' &&
+          receipt['profile-id'] === profileId,
+        `module profile differs: ${path}`,
+      );
+      const record: Record = { path };
+      for (const key of fields) {
+        assert(key in receipt, `module receipt lacks ${key}`);
+        record[key] = receipt[key];
+      }
+      return record;
+    })
+    .sort((a, b) =>
+      String(a.path) < String(b.path) ? -1 : String(a.path) > String(b.path) ? 1 : 0,
+    );
+  assert.equal(
+    new Set(records.map((record) => record.path)).size,
+    records.length,
+    'duplicate module paths',
+  );
+  const result = {
+    schema: 'oliphaunt.wasix-postmaster.linear-memory-install.v1',
+    'profile-id': profileId,
+    ...profile,
+    'predecessor-export-closure-receipt': predecessor,
+    'predecessor-export-closure-receipt-sha256': predecessorHash,
+    'source-module-closure-sha256': closureHash(records, 'source-module-sha256'),
+    'module-closure-sha256': closureHash(records, 'module-sha256'),
+    'module-count': records.length,
+    modules: records,
+  };
+  atomicFile(destination, (fd) => writeFileSync(fd, `${JSON.stringify(result, null, 2)}\n`), true);
+}
+
+if (import.meta.main) {
+  try {
+    const [command, ...args] = process.argv.slice(2);
+    if (command === 'profile-id') {
+      assert(args.length === 0, 'profile-id reads JSON from stdin');
+      const value = parseStrictJson(readFileSync(0, 'utf8'));
+      assert(typeof value.id === 'string', 'memory profile lacks an ID');
+      console.log(value.id);
+    } else if (command === 'modules') {
+      assert(args.length === 1, 'modules requires a receipt');
+      const receipt = readJson(args[0]);
+      assert(Array.isArray(receipt.modules), 'receipt has no modules');
+      for (const row of receipt.modules) {
+        safeRelative(row.path);
+        console.log(row.path);
+      }
+    } else {
+      assert(
+        command === 'aggregate' && args.length === 5,
+        'aggregate requires STAGE INDEX PREDECESSOR HASH OUTPUT',
+      );
+      aggregate(args[0], args[1], args[2], args[3], args[4]);
+    }
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : error);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/postgres-profiles.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/postgres-profiles.sh
similarity index 92%
rename from src/runtimes/liboliphaunt/wasix-postmaster/lib/postgres-profiles.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/lib/postgres-profiles.sh
index e4f3d489c..65e0117a9 100644
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/postgres-profiles.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/postgres-profiles.sh
@@ -292,7 +292,7 @@ fresh_write_postgres_profile_evidence() {
     return 2
   fi
   [ -d "$(dirname "$inputs")" ] && [ -d "$(dirname "$resolution")" ] || return 2
-  publication_tool="$FRESH_ROOT/lib/durable_publication.py"
+  publication_tool="$FRESH_ROOT/lib/durable-publication.mts"
   [ -f "$publication_tool" ] && [ ! -L "$publication_tool" ] || {
     printf 'missing regular durable-publication helper: %s\n' \
       "$publication_tool" >&2
@@ -304,21 +304,21 @@ fresh_write_postgres_profile_evidence() {
   if ! inputs_identity="$({
     printf 'kind\tid\tpath\tsha256\n'
     for row in "${FRESH_POSTGRES_PROFILE_INPUT_ROWS[@]}"; do printf '%s\n' "$row"; done
-  } | python3 "$publication_tool" write-stdin-identified "$pending_inputs")"; then
-    python3 "$publication_tool" discard-private "$pending_inputs" >/dev/null 2>&1 || true
+  } | bun "$publication_tool" write-stdin-identified "$pending_inputs")"; then
+    bun "$publication_tool" discard-private "$pending_inputs" >/dev/null 2>&1 || true
     return 1
   fi
   if ! resolution_identity="$({
     printf 'name\tvalue\tsource\tprofile_id\tprofile_path\tprofile_sha256\tprecedence\n'
     for row in "${FRESH_POSTGRES_PROFILE_EVIDENCE_ROWS[@]}"; do printf '%s\n' "$row"; done
-  } | python3 "$publication_tool" write-stdin-identified "$pending_resolution")"; then
-    python3 "$publication_tool" discard-private "$pending_inputs" >/dev/null 2>&1 || true
-    python3 "$publication_tool" discard-private "$pending_resolution" >/dev/null 2>&1 || true
+  } | bun "$publication_tool" write-stdin-identified "$pending_resolution")"; then
+    bun "$publication_tool" discard-private "$pending_inputs" >/dev/null 2>&1 || true
+    bun "$publication_tool" discard-private "$pending_resolution" >/dev/null 2>&1 || true
     return 1
   fi
   if ! fresh_assert_postgres_profile_inputs; then
-    python3 "$publication_tool" discard-private "$pending_inputs" >/dev/null 2>&1 || true
-    python3 "$publication_tool" discard-private "$pending_resolution" >/dev/null 2>&1 || true
+    bun "$publication_tool" discard-private "$pending_inputs" >/dev/null 2>&1 || true
+    bun "$publication_tool" discard-private "$pending_resolution" >/dev/null 2>&1 || true
     return 1
   fi
   IFS=$'\t' read -r inputs_dev inputs_ino inputs_size inputs_sha \
@@ -338,9 +338,9 @@ fresh_write_postgres_profile_evidence() {
       "$pending_inputs" "$inputs" "$inputs_dev" "$inputs_ino" "$inputs_size" "$inputs_sha"
     )
   fi
-  if ! python3 "$publication_tool" publish-set-identified "${publication_pairs[@]}"; then
-    python3 "$publication_tool" discard-private "$pending_inputs" >/dev/null 2>&1 || true
-    python3 "$publication_tool" discard-private "$pending_resolution" >/dev/null 2>&1 || true
+  if ! bun "$publication_tool" publish-set-identified "${publication_pairs[@]}"; then
+    bun "$publication_tool" discard-private "$pending_inputs" >/dev/null 2>&1 || true
+    bun "$publication_tool" discard-private "$pending_resolution" >/dev/null 2>&1 || true
     return 1
   fi
 }
@@ -379,7 +379,7 @@ fresh_validate_postgres_profile_settings() {
     printf 'refusing to replace PostgreSQL profile validation: %s\n' "$output" >&2
     return 2
   }
-  publication_tool="$FRESH_ROOT/lib/durable_publication.py"
+  publication_tool="$FRESH_ROOT/lib/durable-publication.mts"
   [ -f "$publication_tool" ] && [ ! -L "$publication_tool" ] || {
     printf 'missing regular durable-publication helper: %s\n' \
       "$publication_tool" >&2
@@ -424,20 +424,20 @@ fresh_validate_postgres_profile_settings() {
       exit failed ? 1 : 0
     }
   ' <(printf '%s\n' "$expected") "$settings" |
-    python3 "$publication_tool" write-stdin-identified "$pending")"; then
+    bun "$publication_tool" write-stdin-identified "$pending")"; then
     status=0
   else
     status=$?
   fi
   if [ "$status" -gt 1 ] || [ ! -f "$pending" ] || [ -L "$pending" ]; then
-    python3 "$publication_tool" discard-private "$pending" >/dev/null 2>&1 || true
+    bun "$publication_tool" discard-private "$pending" >/dev/null 2>&1 || true
     return 2
   fi
   IFS=$'\t' read -r pending_dev pending_ino pending_size pending_sha \
     <<<"$pending_identity"
-  if ! python3 "$publication_tool" publish-identified "$pending" "$output" \
+  if ! bun "$publication_tool" publish-identified "$pending" "$output" \
     "$pending_dev" "$pending_ino" "$pending_size" "$pending_sha"; then
-    python3 "$publication_tool" discard-private "$pending" >/dev/null 2>&1 || true
+    bun "$publication_tool" discard-private "$pending" >/dev/null 2>&1 || true
     return 2
   fi
   return "$status"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/postgres-profiles.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/postgres-profiles.test.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/lib/postgres-profiles.test.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/lib/postgres-profiles.test.sh
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/process-supervision.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/process-supervision.sh
similarity index 99%
rename from src/runtimes/liboliphaunt/wasix-postmaster/lib/process-supervision.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/lib/process-supervision.sh
index 1b49bda71..625ef2cc0 100644
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/process-supervision.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/process-supervision.sh
@@ -80,7 +80,7 @@ fresh_signal_owned_pid() {
     return 0
   fi
   if [ "$(uname -s 2>/dev/null || true)" = Linux ]; then
-    python3 "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/signal-owned-pid.py" \
+    bash "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/signal-owned-pid.sh" \
       --signal "$signal" --pid "$pid" --identity "$identity"
     return
   fi
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/process-supervision.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/process-supervision.test.sh
similarity index 96%
rename from src/runtimes/liboliphaunt/wasix-postmaster/lib/process-supervision.test.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/lib/process-supervision.test.sh
index 6274b7a13..c0af97b60 100644
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/process-supervision.test.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/process-supervision.test.sh
@@ -10,6 +10,11 @@ TIMEOUT_TREE="$TEST_ROOT/timeout-tree.sh"
 RESIDUE_TREE="$TEST_ROOT/residue-tree.sh"
 
 cleanup() {
+  if [ -n "${FRESH_PROCESS_GROUP_IDENTITY:-}" ]; then
+    fresh_terminate_owned_process_group \
+      "$FRESH_PROCESS_GROUP_PGID" "$FRESH_PROCESS_GROUP_PID" \
+      "$FRESH_PROCESS_GROUP_IDENTITY" 0 3000 >/dev/null 2>&1 || true
+  fi
   local pid_file pid
   for pid_file in "$TEST_ROOT"/*.pid; do
     [ -s "$pid_file" ] || continue
@@ -182,7 +187,6 @@ fresh_supervision_pid_running "$owned_pid" || {
   echo "identity-mismatch guard killed the owned fixture" >&2
   exit 1
 }
-grep -Fq 'refusing to signal reused process identity' "$TEST_ROOT/reused.err"
 WASIX_PROCESS_TERM_GRACE_MS=100 \
 WASIX_PROCESS_KILL_GRACE_MS=3000 \
   fresh_terminate_owned_process_group "$owned_pgid" "$owned_pid" "$owned_identity"
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/publish-directory.c b/src/runtimes/liboliphaunt-wasix-postmaster/lib/publish-directory.c
new file mode 100644
index 000000000..eed297c61
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/publish-directory.c
@@ -0,0 +1,36 @@
+#define _GNU_SOURCE
+#define _DARWIN_C_SOURCE
+#include 
+#include 
+#include 
+#include 
+#include 
+
+// Node's filesystem API cannot request an atomic no-replace directory rename.
+// Keep that native operation here; never fall back to a check-then-rename.
+int main(int argc, char **argv) {
+  if (argc != 4) return 2;
+  for (int i = 2; i < 4; i++)
+    if (!*argv[i] || strchr(argv[i], '/') || !strcmp(argv[i], ".") ||
+        !strcmp(argv[i], "..")) return 2;
+  int parent = open(argv[1], O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+  if (parent < 0) { perror("open publication parent"); return 1; }
+  struct stat source;
+  int result = fstatat(parent, argv[2], &source, AT_SYMLINK_NOFOLLOW);
+  if (result || !S_ISDIR(source.st_mode)) {
+    fprintf(stderr, "publication source is not a regular directory\n");
+    close(parent);
+    return 1;
+  }
+#if defined(__linux__)
+  result = renameat2(parent, argv[2], parent, argv[3], RENAME_NOREPLACE);
+#elif defined(__APPLE__)
+  result = renameatx_np(parent, argv[2], parent, argv[3], RENAME_EXCL);
+#else
+#error "Atomic directory publication requires Linux or macOS"
+#endif
+  if (result) perror("atomic no-replace directory publication");
+  else if ((result = fsync(parent))) perror("sync published directory parent");
+  close(parent);
+  return result ? 1 : 0;
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/qualification-identities.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/qualification-identities.sh
new file mode 100644
index 000000000..6d0bf3f51
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/qualification-identities.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Shared, fail-closed identity capture for qualification runners.  Callers must
+# source common.sh and sealed-carrier.sh first.
+
+fresh_capture_stable_regular_file_identity() {
+  local path="$1"
+  local identity
+
+  identity="$(bun "$FRESH_ROOT/lib/verify-sealed-carrier.mts" regular-identity "$path"
+  )" || return
+  IFS=$'\t' read -r FRESH_QUALIFICATION_REGULAR_FILE_SHA256 \
+    FRESH_QUALIFICATION_REGULAR_FILE_DEVICE \
+    FRESH_QUALIFICATION_REGULAR_FILE_INODE <<<"$identity"
+  [ "${#FRESH_QUALIFICATION_REGULAR_FILE_SHA256}" -eq 64 ] || return 2
+  case "$FRESH_QUALIFICATION_REGULAR_FILE_SHA256" in
+    *[!0-9a-f]*) return 2 ;;
+  esac
+  case "$FRESH_QUALIFICATION_REGULAR_FILE_DEVICE:$FRESH_QUALIFICATION_REGULAR_FILE_INODE" in
+    *[!0-9:]*) return 2 ;;
+    :*|*:|*:*:*) return 2 ;;
+  esac
+  export FRESH_QUALIFICATION_REGULAR_FILE_SHA256
+  export FRESH_QUALIFICATION_REGULAR_FILE_DEVICE
+  export FRESH_QUALIFICATION_REGULAR_FILE_INODE
+}
+fresh_capture_qualification_carrier_identity() {
+  local carrier="$1"
+  local manifest receipt payload headless identities provenance digest
+
+  manifest="$carrier/manifest.json"
+  receipt="$carrier/wasmer-build.receipt"
+  payload="$carrier/payload.files"
+  headless="$carrier/bin/wasmer-headless"
+  fresh_verify_sealed_headless_carrier "$carrier" || return
+  identities="$(
+    printf '%s\t%s\t%s\t%s\n' \
+      "$(fresh_wasmer_bin_hash "$manifest")" \
+      "$(fresh_wasmer_bin_hash "$receipt")" \
+      "$(fresh_wasmer_bin_hash "$payload")" \
+      "$(fresh_wasmer_bin_hash "$headless")"
+  )" || return
+  IFS=$'\t' read -r FRESH_QUALIFICATION_CARRIER_MANIFEST_SHA256 \
+    FRESH_QUALIFICATION_CARRIER_RECEIPT_SHA256 \
+    FRESH_QUALIFICATION_CARRIER_PAYLOAD_SHA256 \
+    FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256 <<<"$identities"
+  for digest in \
+    "$FRESH_QUALIFICATION_CARRIER_MANIFEST_SHA256" \
+    "$FRESH_QUALIFICATION_CARRIER_RECEIPT_SHA256" \
+    "$FRESH_QUALIFICATION_CARRIER_PAYLOAD_SHA256" \
+    "$FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256"
+  do
+    [ "${#digest}" -eq 64 ] || return 2
+    case "$digest" in
+      *[!0-9a-f]*) return 2 ;;
+    esac
+  done
+  provenance="$(bun "$FRESH_ROOT/lib/verify-sealed-carrier.mts" provenance "$carrier"
+  )" || return
+  IFS=$'\t' read -r FRESH_QUALIFICATION_CORE_PROFILE \
+    FRESH_QUALIFICATION_GUEST_BUILD_RECIPE_SHA256 <<<"$provenance"
+  FRESH_QUALIFICATION_CARRIER_CLOSURE_IDENTITY="$(
+    {
+      printf '%s\0' oliphaunt.wasix-postmaster.qualification-carrier.v1
+      printf '%s\0' "$FRESH_QUALIFICATION_CARRIER_MANIFEST_SHA256"
+      printf '%s\0' "$FRESH_QUALIFICATION_CARRIER_RECEIPT_SHA256"
+      printf '%s\0' "$FRESH_QUALIFICATION_CARRIER_PAYLOAD_SHA256"
+      printf '%s\0' "$FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256"
+    } | fresh_sha256_stream
+  )" || return
+  export FRESH_QUALIFICATION_CARRIER_CLOSURE_IDENTITY
+  export FRESH_QUALIFICATION_CARRIER_MANIFEST_SHA256
+  export FRESH_QUALIFICATION_CARRIER_RECEIPT_SHA256
+  export FRESH_QUALIFICATION_CARRIER_PAYLOAD_SHA256
+  export FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256
+  export FRESH_QUALIFICATION_CORE_PROFILE
+  export FRESH_QUALIFICATION_GUEST_BUILD_RECIPE_SHA256
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/receipt-files.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/receipt-files.mts
new file mode 100644
index 000000000..a52117c12
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/receipt-files.mts
@@ -0,0 +1,110 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { randomUUID } from 'node:crypto';
+import {
+  closeSync,
+  constants,
+  fstatSync,
+  fsyncSync,
+  linkSync,
+  lstatSync,
+  mkdirSync,
+  openSync,
+  readSync,
+  renameSync,
+  unlinkSync,
+} from 'node:fs';
+import { dirname, join } from 'node:path';
+import { parseStrictJson } from '../../../../tools/packaging/strict-json.mts';
+export const AGGREGATE_RELATIVE =
+  'share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json';
+const present = (file: string) => lstatSync(file, { throwIfNoEntry: false });
+const object = (value: unknown): value is Record =>
+  value !== null && typeof value === 'object' && !Array.isArray(value);
+export function safeRelative(value: unknown): asserts value is string {
+  assert(
+    typeof value === 'string' &&
+      !/[\0\t\r\n\\]/u.test(value) &&
+      value.split('/').every((part) => part && part !== '.' && part !== '..'),
+    'unsafe receipt path',
+  );
+}
+export function member(root: string, relative: string) {
+  safeRelative(relative);
+  let parent = root;
+  const parts = relative.split('/');
+  for (const part of parts.slice(0, -1)) {
+    parent = join(parent, part);
+    const info = present(parent);
+    assert(!info || info.isDirectory(), `unsafe receipt parent: ${parent}`);
+  }
+  return join(root, relative);
+}
+function syncDirectory(dir: string) {
+  const fd = openSync(dir, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
+  try {
+    fsyncSync(fd);
+  } finally {
+    closeSync(fd);
+  }
+}
+export function stableRead(
+  file: string,
+  consume: (chunk: Buffer) => void,
+  max = Number.MAX_SAFE_INTEGER,
+) {
+  const named = lstatSync(file, { bigint: true });
+  const fd = openSync(file, constants.O_RDONLY | constants.O_NOFOLLOW);
+  try {
+    const before = fstatSync(fd, { bigint: true });
+    for (const key of ['dev', 'ino', 'mode', 'size', 'mtimeNs', 'ctimeNs'] as const)
+      assert.equal(named[key], before[key], `input replaced while opening: ${file}`);
+    assert(before.isFile() && before.size <= BigInt(max), `not a bounded regular file: ${file}`);
+    const buffer = Buffer.alloc(1024 * 1024);
+    let size = 0;
+    for (;;) {
+      const count = readSync(fd, buffer, 0, Math.min(buffer.length, max - size + 1), null);
+      if (!count) break;
+      size += count;
+      assert(size <= max, `receipt input grew: ${file}`);
+      consume(buffer.subarray(0, count));
+    }
+    const after = fstatSync(fd, { bigint: true });
+    const current = lstatSync(file, { bigint: true });
+    for (const key of ['dev', 'ino', 'mode', 'size', 'mtimeNs', 'ctimeNs'] as const)
+      assert(before[key] === after[key] && after[key] === current[key], `input changed: ${file}`);
+    assert.equal(BigInt(size), before.size, `input size changed: ${file}`);
+    return before;
+  } finally {
+    closeSync(fd);
+  }
+}
+export function readJson(file: string) {
+  const chunks: Buffer[] = [];
+  stableRead(file, (chunk) => chunks.push(Buffer.from(chunk)), 16 * 1024 * 1024);
+  const value = parseStrictJson(
+    new TextDecoder('utf-8', { fatal: true }).decode(Buffer.concat(chunks)),
+  );
+  assert(object(value), 'receipt JSON must be an object');
+  return value;
+}
+export function atomicFile(destination: string, write: (fd: number) => void, exclusive = false) {
+  mkdirSync(dirname(destination), { recursive: true });
+  const temporary = `${destination}.tmp.${randomUUID()}`;
+  const fd = openSync(temporary, 'wx', 0o600);
+  try {
+    try {
+      write(fd);
+      fsyncSync(fd);
+    } finally {
+      closeSync(fd);
+    }
+    if (exclusive) {
+      linkSync(temporary, destination);
+      unlinkSync(temporary);
+    } else renameSync(temporary, destination);
+    syncDirectory(dirname(destination));
+  } finally {
+    if (present(temporary)) unlinkSync(temporary);
+  }
+}
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/sealed-carrier.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-carrier.sh
similarity index 84%
rename from src/runtimes/liboliphaunt/wasix-postmaster/lib/sealed-carrier.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-carrier.sh
index 816fc98cf..41c227118 100644
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/sealed-carrier.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-carrier.sh
@@ -8,62 +8,20 @@
 # beneath a concurrently created destination.  There is no race-free POSIX
 # fallback for this operation, so unsupported hosts fail closed instead of
 # weakening publication to a check-then-rename sequence.
-fresh_atomic_publish_directory_noreplace() {
-  local source="$1"
-  local destination="$2"
-
-  python3 - "$source" "$destination" <<'PY'
-import ctypes
-import errno
-import os
-from pathlib import Path
-import stat
-import sys
-
-source = Path(sys.argv[1])
-destination = Path(sys.argv[2])
-source_info = os.lstat(source)
-if not stat.S_ISDIR(source_info.st_mode) or stat.S_ISLNK(source_info.st_mode):
-    raise SystemExit(f"atomic publication source is not a directory: {source}")
-if source.parent.resolve(strict=True) != destination.parent.resolve(strict=True):
-    raise SystemExit("atomic publication requires source and destination siblings")
-
-libc = ctypes.CDLL(None, use_errno=True)
-source_bytes = os.fsencode(source)
-destination_bytes = os.fsencode(destination)
-if sys.platform.startswith("linux"):
-    rename = getattr(libc, "renameat2", None)
-    if rename is None:
-        raise SystemExit("host libc has no atomic no-replace directory rename")
-    rename.argtypes = [
-        ctypes.c_int,
-        ctypes.c_char_p,
-        ctypes.c_int,
-        ctypes.c_char_p,
-        ctypes.c_uint,
-    ]
-    rename.restype = ctypes.c_int
-    result = rename(-100, source_bytes, -100, destination_bytes, 1)
-elif sys.platform == "darwin":
-    rename = getattr(libc, "renamex_np", None)
-    if rename is None:
-        raise SystemExit("host libc has no atomic exclusive directory rename")
-    rename.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint]
-    rename.restype = ctypes.c_int
-    result = rename(source_bytes, destination_bytes, 0x00000004)
-else:
-    raise SystemExit(
-        f"no audited atomic no-replace directory publication for {sys.platform}"
-    )
-if result != 0:
-    error = ctypes.get_errno()
-    if error in (errno.EEXIST, errno.ENOTEMPTY):
-        raise SystemExit(f"atomic publication destination already exists: {destination}")
-    raise SystemExit(
-        f"atomic no-replace directory publication failed: {os.strerror(error)}"
-    )
-PY
-}
+fresh_atomic_publish_directory_noreplace() (
+  set -e
+  source_parent="$(cd "$(dirname "$1")" && pwd -P)"
+  destination_parent="$(cd "$(dirname "$2")" && pwd -P)"
+  [ "$source_parent" = "$destination_parent" ] || {
+    printf 'atomic publication requires sibling directories\n' >&2
+    exit 2
+  }
+  native="$(mktemp -d)"
+  trap 'rm -rf "$native"' EXIT
+  "${HOST_CC:-cc}" -std=c11 -Wall -Wextra -Werror \
+    "$FRESH_ROOT/lib/publish-directory.c" -o "$native/publish-directory"
+  "$native/publish-directory" "$source_parent" "$(basename "$1")" "$(basename "$2")"
+)
 
 # Identity of the exact AOT production recipe, separate from runtime ABI
 # compatibility. The receipt binds native binaries and their build recipe;
@@ -78,8 +36,10 @@ fresh_aot_producer_recipe_sha256() {
   local precompile_script="$FRESH_ROOT/bin/precompile-wasix-core.sh"
   local carrier_builder="$FRESH_ROOT/bin/build-sealed-headless-carrier.sh"
   local carrier_policy="$FRESH_ROOT/lib/sealed-carrier.sh"
-  local carrier_verifier="$FRESH_ROOT/lib/verify-sealed-carrier.py"
-  local export_chain_verifier="$FRESH_ROOT/lib/sealed_export_chain.py"
+  local carrier_verifier="$FRESH_ROOT/lib/verify-sealed-carrier.mts"
+  local export_chain_verifier="$FRESH_ROOT/lib/sealed-export-chain.mts"
+  local guest_provenance="$FRESH_ROOT/lib/guest-build-provenance.mts"
+  local guest_input
   local capture_stack_size="${WASMER_STACK_SIZE:-33554432}"
   local compiler_sha256
 
@@ -113,6 +73,22 @@ fresh_aot_producer_recipe_sha256() {
       "$export_chain_verifier" >&2
     return 2
   }
+  local verifier_inputs=(
+    "$guest_provenance"
+    "$FRESH_ROOT/lib/build-sealed-carrier.mts"
+    "$FRESH_ROOT/lib/publish-directory.c"
+    "$FRESH_ROOT/lib/linear-memory-profile.mts"
+    "$FRESH_ROOT/lib/receipt-files.mts"
+    "$FRESH_ROOT/wasmer/bin/verify-postmaster-concurrency-contract.mts"
+    "$FRESH_ROOT/wasmer/bin/verify-postmaster-wasm-import.mts"
+    "$REPO_ROOT/tools/packaging/strict-json.mts"
+  )
+  for guest_input in "${verifier_inputs[@]}"; do
+    [ -f "$guest_input" ] && [ ! -L "$guest_input" ] || {
+      printf 'missing regular guest provenance input: %s\n' "$guest_input" >&2
+      return 2
+    }
+  done
   [ -n "$compiler_config" ] && [ -n "$target_triple" ] || {
     printf 'AOT producer compiler config and target must be nonempty\n' >&2
     return 2
@@ -176,6 +152,9 @@ fresh_aot_producer_recipe_sha256() {
     printf '%s\0%s\0' carrier-policy-sha256 "$(fresh_wasmer_bin_hash "$carrier_policy")"
     printf '%s\0%s\0' carrier-verifier-sha256 "$(fresh_wasmer_bin_hash "$carrier_verifier")"
     printf '%s\0%s\0' sealed-export-chain-verifier-sha256 "$(fresh_wasmer_bin_hash "$export_chain_verifier")"
+    for guest_input in "${verifier_inputs[@]}"; do
+      printf '%s\0%s\0' verifier-input-sha256 "$(fresh_wasmer_bin_hash "$guest_input")"
+    done
     printf '%s\0%s\0' producer-engine llvm-opta
     printf '%s\0%s\0' compiler-config "$compiler_config"
     printf '%s\0%s\0' target-triple "$target_triple"
@@ -247,10 +226,10 @@ fresh_select_current_sealed_carrier() {
 # Resolve the exact product executor identity from the verified carrier closure.
 fresh_sealed_executor_selection() {
   local carrier_root="$1"
-  local verifier="$FRESH_ROOT/lib/verify-sealed-carrier.py"
+  local verifier="$FRESH_ROOT/lib/verify-sealed-carrier.mts"
   local selection extra
 
-  selection="$(python3 "$verifier" executor-selection "$carrier_root")" || return
+  selection="$(bun "$verifier" executor-selection "$carrier_root")" || return
   IFS=$'\t' read -r \
     FRESH_SEALED_EXECUTOR_ROLE \
     FRESH_SEALED_EXECUTOR_RECEIPT_RELATIVE \
@@ -287,7 +266,7 @@ fresh_verify_sealed_headless_carrier() {
   local manifest
   local receipt
   local headless
-  local verifier="$FRESH_ROOT/lib/verify-sealed-carrier.py"
+  local verifier="$FRESH_ROOT/lib/verify-sealed-carrier.mts"
   local manifest_recipe_inputs
   local remaining_recipe_inputs
   local compiler_config
@@ -309,7 +288,7 @@ fresh_verify_sealed_headless_carrier() {
     printf 'missing regular sealed carrier verifier: %s\n' "$verifier" >&2
     return 2
   fi
-  fresh_require_command python3 || return
+  fresh_require_command bun || return
   if [ ! -f "$manifest" ] || [ -L "$manifest" ]; then
     printf 'missing regular sealed carrier manifest: %s\n' "$manifest" >&2
     return 2
@@ -336,7 +315,7 @@ fresh_verify_sealed_headless_carrier() {
   }
 
   manifest_recipe_inputs="$(
-    python3 "$verifier" recipe-inputs "$carrier_root"
+    bun "$verifier" recipe-inputs "$carrier_root"
   )" || return
   case "$manifest_recipe_inputs" in
     *$'\n'*) ;;
@@ -366,7 +345,7 @@ fresh_verify_sealed_headless_carrier() {
     "$receipt" "$product_receipt" "$compiler_config" \
     "$target_triple" "$source_fingerprint")" || return
 
-  python3 "$verifier" verify \
+  bun "$verifier" verify \
     "$carrier_root" \
     "$expected_producer_recipe" \
     "$POSTGRES_VERSION" \
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-export-chain.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-export-chain.mts
new file mode 100644
index 000000000..931378d97
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-export-chain.mts
@@ -0,0 +1,301 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { lstatSync } from 'node:fs';
+import { join } from 'node:path';
+import { parseArgs } from 'node:util';
+import { parseStrictJson } from '../../../../tools/packaging/strict-json.mts';
+import { closureHash, fields, profile, profileId } from './linear-memory-profile.mts';
+import { AGGREGATE_RELATIVE, member, safeRelative, stableRead } from './receipt-files.mts';
+
+export const receiptRelative = 'share/postgresql/wasix-postmaster.sealed-export.structure.receipt';
+const prefix = 'share/postgresql/wasix-postmaster.sealed-export.';
+const policyId = 'oliphaunt.wasix-postmaster.sealed-export-closure.v1';
+const maxBytes = 512 * 1024 * 1024;
+export type Inventory = Map;
+type Record = { [key: string]: any };
+export const sha256 = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex');
+export function exactKeys(value: unknown, keys: string[], label: string): asserts value is Record {
+  assert(value && typeof value === 'object' && !Array.isArray(value), `${label} must be an object`);
+  assert.deepEqual(Object.keys(value).sort(), [...keys].sort(), `${label} fields differ`);
+}
+const names = (value: string) => value.trim().split(/\s+/);
+const receiptKeys = names(`schema policy-id analyzer-version analyzer-binary-sha256 dce-tool-sha256
+ dce-tool-version dce-passes mandatory-policy-sha256 declared-main-dlsym-policy-sha256
+ side-manifest-sha256 allowlist-sha256 seed-proof-sha256 final-proof-sha256 seed final-module sides`);
+const snapshotKeys =
+  names(`sha256 bytes exports local-functions local-globals element-function-entries
+ element-unique-function-indices start-function-index`);
+const proofKeys =
+  names(`schema policy-id analyzer-version mandatory-policy-sha256 declared-main-dlsym-policy-sha256
+ main sides mandatory-runtime-exports declared-main-dlsym-exports side-dynamic-imports retained-main-exports
+ retained-main-export-descriptors removed-main-export-count removed-main-export-names-sha256
+ unresolved-main-requirements mismatched-main-requirements unresolved-side-dependencies retained-counts removed-counts`);
+const moduleKeys =
+  names(`path sha256 bytes non-export-sections-sha256 dylink-needed imported-functions local-functions
+ imported-globals local-globals imported-tables local-tables element-function-entries element-unique-function-indices
+ element-max-function-index start-function-index imports export-counts exported-global-type-counts
+ exported-immutable-i32-globals exported-local-functions exported-imported-functions`);
+
+export function requireSha(value: unknown): asserts value is string {
+  assert(typeof value === 'string' && /^[0-9a-f]{64}$/.test(value), 'invalid SHA-256');
+}
+export function parseJson(data: Uint8Array): Record {
+  const text = new TextDecoder('utf8', { fatal: true }).decode(data);
+  assert(!/[\0\r]/.test(text), 'non-canonical JSON text');
+  const value = parseStrictJson(text, (_key, value) => {
+    if (typeof value === 'number') assert(Number.isSafeInteger(value), 'unsafe JSON integer');
+    return value;
+  });
+  assert(value && typeof value === 'object' && !Array.isArray(value), 'JSON must be an object');
+  return value;
+}
+export function readRegular(root: string, relative: string, inventory?: Inventory) {
+  safeRelative(relative);
+  const expected = inventory?.get(relative);
+  if (inventory) assert(expected, `sealed-export input is not inventoried: ${relative}`);
+  const bound = expected?.size ?? maxBytes;
+  assert(Number.isSafeInteger(bound) && bound >= 0 && bound <= maxBytes, 'invalid inventory size');
+  const chunks: Buffer[] = [];
+  stableRead(member(root, relative), (chunk) => chunks.push(Buffer.from(chunk)), bound);
+  const bytes = Buffer.concat(chunks);
+  if (expected) {
+    assert.equal(bytes.length, expected.size, `inventory size differs: ${relative}`);
+    assert.equal(sha256(bytes), expected.sha256, `inventory digest differs: ${relative}`);
+  }
+  return bytes;
+}
+function trackedHash(path: string) {
+  const hash = createHash('sha256');
+  stableRead(
+    path,
+    (chunk) => {
+      hash.update(chunk);
+    },
+    maxBytes,
+  );
+  return hash.digest('hex');
+}
+export function sideManifestPaths(projectRoot: string) {
+  const policy = readRegular(projectRoot, 'wasmer/policies/sealed-side-modules.v1.tsv');
+  const lines = new TextDecoder('utf8', { fatal: true }).decode(policy).split(/\r?\n/);
+  assert.equal(
+    lines[0],
+    '# schema=oliphaunt.wasix-postmaster.sealed-side-modules.v1',
+    'side manifest schema differs',
+  );
+  const paths = lines
+    .filter((line) => line && !line.startsWith('#'))
+    .map((line) => {
+      const fields = line.split('\t');
+      assert.equal(fields.length, 3, 'side manifest row differs');
+      safeRelative(fields[0]);
+      return fields[0];
+    });
+  assert(
+    paths.length === 27 && new Set(paths).size === 27,
+    'side manifest must contain exactly 27 paths',
+  );
+  return paths;
+}
+function validateProof(proof: Record, receipt: Record, mainHash: string, sides: Record[]) {
+  exactKeys(proof, proofKeys, 'sealed-export proof');
+  assert.equal(proof.schema, 'oliphaunt.wasix-postmaster.sealed-export-closure-proof.v2');
+  assert.equal(proof['policy-id'], policyId);
+  for (const field of [
+    'analyzer-version',
+    'mandatory-policy-sha256',
+    'declared-main-dlsym-policy-sha256',
+  ])
+    assert.equal(proof[field], receipt[field], `proof identity differs: ${field}`);
+  exactKeys(proof.main, moduleKeys, 'proof main');
+  assert.equal(proof.main.path, 'bin/postgres');
+  assert.equal(proof.main.sha256, mainHash, 'proof main identity differs');
+  assert(
+    Array.isArray(proof.sides) && proof.sides.length === sides.length,
+    'proof side closure differs',
+  );
+  for (const [index, expected] of sides.entries()) {
+    const module = proof.sides[index];
+    exactKeys(module, moduleKeys, 'proof side');
+    assert.deepEqual(
+      [module.path, module.sha256],
+      [expected.path, expected.sha256],
+      'proof side identity differs',
+    );
+  }
+  for (const field of [
+    'unresolved-main-requirements',
+    'mismatched-main-requirements',
+    'unresolved-side-dependencies',
+  ])
+    assert.deepEqual(proof[field], [], `export graph is not closed: ${field}`);
+}
+export function validateExportChain(
+  root: string,
+  projectRoot: string,
+  sourceHashes: Map,
+  inventory?: Inventory,
+) {
+  const receipt = parseJson(readRegular(root, receiptRelative, inventory));
+  exactKeys(receipt, receiptKeys, 'sealed-export receipt');
+  assert.equal(receipt.schema, 'oliphaunt.wasix-postmaster.sealed-export-structure.v1');
+  assert.equal(receipt['policy-id'], policyId);
+  assert.deepEqual(receipt['dce-passes'], ['--remove-unused-module-elements']);
+  for (const key of receiptKeys.filter((key) => key.endsWith('-sha256'))) requireSha(receipt[key]);
+  for (const key of ['analyzer-version', 'dce-tool-version'])
+    assert(
+      typeof receipt[key] === 'string' && receipt[key] && !/[\r\n\0]/.test(receipt[key]),
+      'invalid tool version',
+    );
+  for (const [key, file] of [
+    ['mandatory-policy-sha256', 'sealed-main-runtime-exports.v1.txt'],
+    ['declared-main-dlsym-policy-sha256', 'sealed-main-dlsym-exports.v1.txt'],
+    ['side-manifest-sha256', 'sealed-side-modules.v1.tsv'],
+  ])
+    assert.equal(
+      receipt[key],
+      trackedHash(join(projectRoot, 'wasmer/policies', file)),
+      `tracked policy differs: ${file}`,
+    );
+  exactKeys(receipt.seed, snapshotKeys, 'seed snapshot');
+  exactKeys(receipt['final-module'], snapshotKeys, 'final snapshot');
+  const seedHash = receipt.seed.sha256,
+    finalHash = receipt['final-module'].sha256;
+  requireSha(seedHash);
+  requireSha(finalHash);
+  assert.equal(
+    sourceHashes.get('bin/postgres'),
+    finalHash,
+    'final module is not the memory-seal predecessor',
+  );
+  const sidePaths = sideManifestPaths(projectRoot);
+  assert(
+    Array.isArray(receipt.sides) && receipt.sides.length === sidePaths.length,
+    'side closure differs',
+  );
+  for (const [index, path] of sidePaths.entries()) {
+    const side = receipt.sides[index];
+    exactKeys(side, ['path', 'sha256'], 'side receipt');
+    requireSha(side.sha256);
+    assert.equal(side.path, path, 'side order/path differs');
+    assert.equal(
+      sourceHashes.get(path),
+      side.sha256,
+      `side is not the memory-seal predecessor: ${path}`,
+    );
+  }
+  for (const [suffix, field, hash] of [
+    ['allowlist', 'allowlist-sha256', undefined],
+    ['seed-proof.json', 'seed-proof-sha256', seedHash],
+    ['final-proof.json', 'final-proof-sha256', finalHash],
+  ] as const) {
+    const bytes = readRegular(root, prefix + suffix, inventory);
+    assert.equal(sha256(bytes), receipt[field], `installed proof bytes differ: ${suffix}`);
+    if (hash) validateProof(parseJson(bytes), receipt, hash, receipt.sides);
+  }
+  return receipt;
+}
+export function linearMemorySourceHashes(root: string, inventory?: Inventory) {
+  const receipt = parseJson(readRegular(root, AGGREGATE_RELATIVE, inventory));
+  exactKeys(
+    receipt,
+    [
+      'schema',
+      'profile-id',
+      ...Object.keys(profile),
+      'predecessor-export-closure-receipt',
+      'predecessor-export-closure-receipt-sha256',
+      'source-module-closure-sha256',
+      'module-closure-sha256',
+      'module-count',
+      'modules',
+    ],
+    'memory install receipt',
+  );
+  assert.equal(receipt.schema, 'oliphaunt.wasix-postmaster.linear-memory-install.v1');
+  assert.equal(receipt['profile-id'], profileId);
+  for (const [key, expected] of Object.entries(profile))
+    assert.equal(receipt[key], expected, `memory profile differs: ${key}`);
+  assert.equal(receipt['predecessor-export-closure-receipt'], receiptRelative);
+  assert.equal(
+    sha256(readRegular(root, receiptRelative, inventory)),
+    receipt['predecessor-export-closure-receipt-sha256'],
+    'predecessor digest differs',
+  );
+  assert(
+    Array.isArray(receipt.modules) &&
+      receipt.modules.length > 0 &&
+      receipt['module-count'] === receipt.modules.length,
+    'memory module count differs',
+  );
+  const hashes = new Map();
+  for (const module of receipt.modules) {
+    exactKeys(module, ['path', ...fields], 'memory module');
+    const path = module.path;
+    safeRelative(path);
+    for (const key of ['source-module-sha256', 'module-sha256']) requireSha(module[key]);
+    assert(
+      Number.isSafeInteger(module['initial-pages']) &&
+        module['initial-pages'] >= 0 &&
+        module['initial-pages'] <= 4096,
+      'invalid initial pages',
+    );
+    for (const [key, expected] of Object.entries({
+      'maximum-pages': 4096,
+      'maximum-bytes': 268435456,
+      shared: true,
+      'import-module': 'env',
+      'import-name': 'memory',
+      transformation: 'pinned-wasixcc-65536-to-embedded-4096-reversible-v1',
+    }))
+      assert.equal(module[key], expected, `memory module differs: ${path} ${key}`);
+    // The install receipt also covers tools omitted from the runtime carrier.
+    // Validate all receipt records, and bind bytes for every shipped module.
+    if (!inventory || inventory.has(path))
+      assert.equal(
+        sha256(readRegular(root, path, inventory)),
+        module['module-sha256'],
+        `memory module bytes differ: ${path}`,
+      );
+    assert(!hashes.has(path), `duplicate memory module: ${path}`);
+    hashes.set(path, module['source-module-sha256']);
+  }
+  const paths = [...hashes.keys()];
+  assert.deepEqual(paths, [...paths].sort(), 'memory modules are not sorted');
+  for (const field of ['source-module-sha256', 'module-sha256'])
+    assert.equal(
+      closureHash(receipt.modules, field),
+      receipt[field.replace('module-sha256', 'module-closure-sha256')],
+      'memory closure digest differs',
+    );
+  return hashes;
+}
+if (import.meta.main) {
+  try {
+    const { values } = parseArgs({
+      options: {
+        'install-root': { type: 'string' },
+        'project-root': { type: 'string' },
+        'allow-linear-memory-descendant': { type: 'boolean' },
+      },
+    });
+    const root = values['install-root'],
+      project = values['project-root'];
+    assert(root && project, '--install-root and --project-root are required');
+    const hashes =
+      values['allow-linear-memory-descendant'] &&
+      lstatSync(member(root, AGGREGATE_RELATIVE), { throwIfNoEntry: false })
+        ? linearMemorySourceHashes(root)
+        : new Map(
+            ['bin/postgres', ...sideManifestPaths(project)].map((path) => [
+              path,
+              sha256(readRegular(root, path)),
+            ]),
+          );
+    validateExportChain(root, project, hashes);
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : error);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-export-chain.test.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-export-chain.test.mts
new file mode 100644
index 000000000..606c625d6
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-export-chain.test.mts
@@ -0,0 +1,73 @@
+import assert from 'node:assert/strict';
+import { mkdtempSync, mkdirSync, rmSync, writeFileSync, symlinkSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join, dirname } from 'node:path';
+import { test } from 'node:test';
+import {
+  makeSealedExportFixture,
+  makeLinearMemoryFixture,
+} from '../testdata/make-sealed-export-fixture.mts';
+import { AGGREGATE_RELATIVE } from './receipt-files.mts';
+import {
+  receiptRelative,
+  sha256,
+  readRegular,
+  sideManifestPaths,
+  validateExportChain,
+  linearMemorySourceHashes,
+  parseJson,
+} from './sealed-export-chain.mts';
+const project = join(import.meta.dirname, '..');
+test('sealed export and memory receipts bind actual modules, proofs and inventoried inputs', () => {
+  const root = mkdtempSync(join(tmpdir(), 'sealed-export-chain-'));
+  try {
+    const module = Buffer.from('0061736d0100000002120103656e76066d656d6f7279020301808004', 'hex');
+    for (const relative of ['bin/initdb', 'bin/postgres', 'lib/libpq.so.5.18']) {
+      mkdirSync(dirname(join(root, relative)), { recursive: true });
+      writeFileSync(join(root, relative), module);
+    }
+    makeSealedExportFixture(root, project);
+    const paths = ['bin/initdb', 'bin/postgres', ...sideManifestPaths(project)].sort();
+    const hashes = new Map(paths.map((path) => [path, sha256(readRegular(root, path))]));
+    validateExportChain(root, project, hashes);
+    const receipt = makeLinearMemoryFixture(root),
+      modules = receipt.modules;
+    hashes.set('bin/pg_config', hashes.get('bin/initdb')!);
+    const writeMemory = () =>
+      writeFileSync(join(root, AGGREGATE_RELATIVE), JSON.stringify(receipt));
+    writeMemory();
+    assert.deepEqual(linearMemorySourceHashes(root), hashes);
+    validateExportChain(root, project, linearMemorySourceHashes(root));
+    for (const invalid of [true, 4097]) {
+      (modules[0] as any)['initial-pages'] = invalid;
+      writeMemory();
+      assert.throws(() => linearMemorySourceHashes(root));
+    }
+    modules[0]['initial-pages'] = 1;
+    writeMemory();
+    writeFileSync(join(root, 'bin/initdb'), Buffer.concat([module, Buffer.from('changed')]));
+    assert.throws(() => linearMemorySourceHashes(root), /bytes differ/);
+    const proofPath = 'share/postgresql/wasix-postmaster.sealed-export.seed-proof.json';
+    const proof = parseJson(readRegular(root, proofPath));
+    proof['analyzer-version'] = 'different';
+    writeFileSync(join(root, proofPath), JSON.stringify(proof));
+    const structural = parseJson(readRegular(root, receiptRelative));
+    structural['seed-proof-sha256'] = sha256(readRegular(root, proofPath));
+    writeFileSync(join(root, receiptRelative), JSON.stringify(structural));
+    assert.throws(() => validateExportChain(root, project, hashes), /proof identity/);
+    symlinkSync('bin/postgres', join(root, 'link'));
+    assert.throws(() => readRegular(root, 'link'));
+    assert.throws(() =>
+      readRegular(
+        root,
+        'bin/postgres',
+        new Map([['bin/postgres', { size: 1, sha256: '0'.repeat(64) }]]),
+      ),
+    );
+    assert.throws(() => readRegular(root, 'bin/postgres', new Map()));
+    assert.throws(() => parseJson(Buffer.from('{"a":1,"a":2}')), /duplicate/i);
+    assert.throws(() => parseJson(Buffer.from('{"a":9007199254740993}')), /unsafe JSON integer/);
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/select-guest-generation.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/select-guest-generation.mts
new file mode 100644
index 000000000..c941e0bc8
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/select-guest-generation.mts
@@ -0,0 +1,13 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { lstatSync, writeFileSync } from 'node:fs';
+import { atomicFile } from './receipt-files.mts';
+
+const [destination, identity, ...extra] = process.argv.slice(2);
+assert(
+  destination && /^[0-9a-f]{64}$/.test(identity ?? '') && !extra.length,
+  'expected selection file and completed guest generation SHA-256',
+);
+const existing = lstatSync(destination, { throwIfNoEntry: false });
+assert(!existing || existing.isFile(), 'guest selection is not a regular file');
+atomicFile(destination, (fd) => writeFileSync(fd, `${identity}\n`));
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/server-lifecycle.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/server-lifecycle.mts
new file mode 100644
index 000000000..741cfa71e
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/server-lifecycle.mts
@@ -0,0 +1,47 @@
+import assert from 'node:assert/strict';
+import { writeFileSync } from 'node:fs';
+import { createConnection, createServer } from 'node:net';
+
+const [command, value, port] = process.argv.slice(2);
+if (command === 'probe') {
+  const socket = createConnection({ host: value, port: Number(port) });
+  process.exitCode = await new Promise((resolve) => {
+    const finish = (code: number) => {
+      socket.destroy();
+      resolve(code);
+    };
+    socket
+      .once('connect', () => finish(0))
+      .once('error', () => finish(1))
+      .setTimeout(200, () => finish(1));
+  });
+} else if (command === 'size') {
+  const match = /^(\d+)([KMGTPE])?(?:i?B)?$/.exec(value);
+  assert(match, 'invalid cgroup size');
+  const bytes = BigInt(match[1]) * 1024n ** BigInt(match[2] ? 'KMGTPE'.indexOf(match[2]) + 1 : 0);
+  assert(bytes <= 2n ** 63n - 1n, 'cgroup size exceeds signed 64-bit range');
+  console.log(bytes.toString());
+} else {
+  assert(command === 'available-port' || command === 'listen', 'unknown server lifecycle command');
+  let candidate = command === 'listen' ? 0 : Number(value);
+  assert(Number.isInteger(candidate) && candidate >= 0 && candidate < 65536, 'invalid TCP port');
+  for (;;) {
+    const server = createServer((socket) => socket.destroy());
+    try {
+      await new Promise((resolve, reject) => {
+        server.once('error', reject).listen(candidate, '127.0.0.1', resolve);
+      });
+      const selected = (server.address() as { port: number }).port;
+      if (command === 'listen') writeFileSync(value, String(selected));
+      else {
+        await new Promise((resolve, reject) =>
+          server.close((error) => (error ? reject(error) : resolve())),
+        );
+        console.log(selected);
+      }
+      break;
+    } catch (error) {
+      if (command === 'listen' || error.code !== 'EADDRINUSE' || ++candidate >= 65536) throw error;
+    }
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/server-lifecycle.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/server-lifecycle.sh
new file mode 100644
index 000000000..aa4b9c906
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/server-lifecycle.sh
@@ -0,0 +1,128 @@
+#!/usr/bin/env bash
+
+# Requires process-supervision.sh.
+_fresh_server_lifecycle_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+fresh_path_identity() {
+  local path="$1"
+  if stat -Lc '%d:%i' "$path" >/dev/null 2>&1; then
+    stat -Lc '%d:%i' "$path"
+  elif stat -f '%d:%i' "$path" >/dev/null 2>&1; then
+    stat -f '%d:%i' "$path"
+  else
+    return 1
+  fi
+}
+
+fresh_wait_cgroup_empty() {
+  local cgroup_dir="$1"
+  local expected_identity="$2"
+  local timeout_ms="$3"
+  local deadline actual_identity members
+
+  [ -n "$cgroup_dir" ] || return 0
+  case "$timeout_ms" in ""|*[!0-9]*) return 125 ;; esac
+  deadline=$(( $(fresh_supervision_now_ms) + timeout_ms ))
+  while :; do
+    [ -e "$cgroup_dir" ] || return 0
+    actual_identity="$(fresh_path_identity "$cgroup_dir" 2>/dev/null)" || return 125
+    if [ "$actual_identity" != "$expected_identity" ]; then
+      printf 'refusing reused cgroup identity: path=%s expected=%s actual=%s\n' \
+        "$cgroup_dir" "$expected_identity" "$actual_identity" >&2
+      return 125
+    fi
+    [ -r "$cgroup_dir/cgroup.procs" ] || {
+      printf 'tracked cgroup.procs became unreadable: %s\n' "$cgroup_dir" >&2
+      return 125
+    }
+    members="$(tr -d '[:space:]' <"$cgroup_dir/cgroup.procs")"
+    [ -z "$members" ] && return 0
+    [ "$(fresh_supervision_now_ms)" -lt "$deadline" ] || {
+      printf 'tracked cgroup retained processes after shutdown: %s (%s)\n' \
+        "$cgroup_dir" "$members" >&2
+      return 125
+    }
+    sleep 0.05
+  done
+}
+
+fresh_tcp_port_open() {
+  local host="$1"
+  local port="$2"
+  bun "$_fresh_server_lifecycle_root/server-lifecycle.mts" probe "$host" "$port"
+}
+
+fresh_wait_tcp_port_closed() {
+  local host="$1"
+  local port="$2"
+  local timeout_ms="$3"
+  local deadline
+
+  case "$port:$timeout_ms" in *[!0-9:]*|:*|*:) return 125 ;; esac
+  deadline=$(( $(fresh_supervision_now_ms) + timeout_ms ))
+  while fresh_tcp_port_open "$host" "$port"; do
+    [ "$(fresh_supervision_now_ms)" -lt "$deadline" ] || {
+      printf 'TCP listener survived shutdown: %s:%s\n' "$host" "$port" >&2
+      return 125
+    }
+    sleep 0.05
+  done
+}
+
+wait_for_unassisted_exit() {
+  local exit_evidence="$1"
+  local deadline wait_status group_deadline cgroup_empty=not-requested
+
+  deadline=$(( $(fresh_supervision_now_ms) + timeout_seconds * 1000 ))
+  while fresh_supervision_pid_running "$active_pid"; do
+    if ! fresh_pid_matches_birth_identity "$active_pid" "$active_identity"; then
+      # The leader can exit between the liveness check above and reading its
+      # immutable birth identity.  Only classify an identity mismatch as PID
+      # reuse when the numeric PID is still live after that failed read.
+      fresh_supervision_pid_running "$active_pid" && return 125
+      break
+    fi
+    [ "$(fresh_supervision_now_ms)" -lt "$deadline" ] || {
+      printf 'server did not exit after bridged signal without escalation\n' >&2
+      return 124
+    }
+    sleep 0.05
+  done
+  fresh_reap_process_group_leader "$active_pid"
+  wait_status="$FRESH_PROCESS_GROUP_WAIT_STATUS"
+  group_deadline=$(( $(fresh_supervision_now_ms) + timeout_seconds * 1000 ))
+  while fresh_process_group_exists "$active_pgid"; do
+    [ "$(fresh_supervision_now_ms)" -lt "$group_deadline" ] || {
+      printf 'server process group remained after leader exit: %s\n' "$active_pgid" >&2
+      return 124
+    }
+    sleep 0.05
+  done
+  if [ -n "$active_cgroup_dir" ] && [ -n "$active_cgroup_identity" ]; then
+    fresh_wait_cgroup_empty "$active_cgroup_dir" "$active_cgroup_identity" \
+      "$((timeout_seconds * 1000))"
+    cgroup_empty=true
+  fi
+  fresh_wait_tcp_port_closed 127.0.0.1 "$port" "$((timeout_seconds * 1000))"
+  [ -z "$(find "$dev_shm" -mindepth 1 -print -quit)" ] || {
+    printf 'shared objects survived normal guest shutdown: %s\n' "$dev_shm" >&2
+    return 1
+  }
+  [ "$wait_status" -eq 0 ] || {
+    printf 'server leader exited nonzero after unassisted guest shutdown: phase=%s status=%s\n' \
+      "$active_phase" "$wait_status" >&2
+    return 1
+  }
+  {
+    printf 'phase\twait_status\tprocess_group_empty\tcgroup_empty\tport_closed\tshared_objects_empty\tescalation_used\n'
+    printf '%s\t%s\ttrue\t%s\ttrue\ttrue\tfalse\n' \
+      "$active_phase" "$wait_status" "$cgroup_empty"
+  } >"$exit_evidence"
+  active_pid=""
+  active_pgid=""
+  active_identity=""
+  active_phase=""
+  active_cgroup_unit=""
+  active_cgroup_dir=""
+  active_cgroup_identity=""
+}
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/server-lifecycle.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/server-lifecycle.test.sh
similarity index 77%
rename from src/runtimes/liboliphaunt/wasix-postmaster/lib/server-lifecycle.test.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/lib/server-lifecycle.test.sh
index e9e19a7c2..fe021770a 100644
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/server-lifecycle.test.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/server-lifecycle.test.sh
@@ -30,15 +30,7 @@ if fresh_wait_cgroup_empty "$fixture/empty" wrong-identity 10 >/dev/null 2>&1; t
 fi
 
 port_file="$fixture/listener.port"
-python3 - "$port_file" >"$fixture/listener.log" 2>&1 <<'PY' &
-import http.server
-import pathlib
-import sys
-
-server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), http.server.SimpleHTTPRequestHandler)
-pathlib.Path(sys.argv[1]).write_text(str(server.server_address[1]), encoding="ascii")
-server.serve_forever()
-PY
+bun "$root/server-lifecycle.mts" listen "$port_file" >"$fixture/listener.log" 2>&1 &
 listener_pid="$!"
 # Release qualification runs this dependency beside the Rust runtime build on
 # three-core macOS runners. Keep fixture startup bounded, but allow for the
@@ -64,6 +56,18 @@ if fresh_wait_tcp_port_closed 127.0.0.1 "$port" 10 >/dev/null 2>&1; then
   echo "live TCP listener passed residue gate" >&2
   exit 1
 fi
+if [ "$port" -lt 65535 ]; then
+  available="$(bun "$root/server-lifecycle.mts" available-port "$port")"
+  [ "$available" -gt "$port" ]
+  if fresh_tcp_port_open 127.0.0.1 "$available"; then
+    echo 'port selection left its probe listener running' >&2; exit 1
+  fi
+fi
+[ "$(bun "$root/server-lifecycle.mts" size 8GiB)" = 8589934592 ]
+[ "$(bun "$root/server-lifecycle.mts" size 9223372036854775807)" = 9223372036854775807 ]
+if bun "$root/server-lifecycle.mts" size 8E >/dev/null 2>&1; then
+  echo 'cgroup size overflow was accepted' >&2; exit 1
+fi
 kill "$listener_pid"
 wait "$listener_pid" 2>/dev/null || true
 listener_pid=""
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/signal-owned-pid.c b/src/runtimes/liboliphaunt-wasix-postmaster/lib/signal-owned-pid.c
new file mode 100644
index 000000000..1d451a31c
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/signal-owned-pid.c
@@ -0,0 +1,85 @@
+#define _GNU_SOURCE
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static unsigned long long positive(const char *text) {
+  char *end;
+  errno = 0;
+  unsigned long long value = strtoull(text, &end, 10);
+  return text[0] >= '1' && text[0] <= '9' && !*end && !errno ? value : 0;
+}
+
+static int exited(int fd) {
+  struct pollfd entry = {.fd = fd, .events = POLLIN};
+  return poll(&entry, 1, 0) == 1 && (entry.revents & POLLIN);
+}
+
+int main(int argc, char **argv) {
+  unsigned long long pid = 0, expected = 0;
+  int signum = 0;
+  for (int i = 1; i + 1 < argc; i += 2) {
+    if (!strcmp(argv[i], "--pid") && !pid) pid = positive(argv[i + 1]);
+    else if (!strcmp(argv[i], "--identity") && !expected &&
+             !strncmp(argv[i + 1], "linux-starttime:", 16))
+      expected = positive(argv[i + 1] + 16);
+    else if (!strcmp(argv[i], "--signal") && !signum) {
+      const char *name = argv[i + 1];
+      if (!strncmp(name, "SIG", 3)) name += 3;
+      if (!strcasecmp(name, "TERM")) signum = SIGTERM;
+      else if (!strcasecmp(name, "KILL")) signum = SIGKILL;
+      else if (!strcasecmp(name, "INT")) signum = SIGINT;
+      else if (!strcasecmp(name, "QUIT")) signum = SIGQUIT;
+      else {
+        unsigned long long value = positive(name);
+        if (value < NSIG) signum = (int)value;
+      }
+    } else return 2;
+  }
+  if (argc != 7 || !pid || pid > INT_MAX || !expected || !signum) return 2;
+
+  // Pin the process before reading its birth identity. A reused numeric PID
+  // must never redirect the signal to a different process.
+  int fd = (int)syscall(SYS_pidfd_open, (int)pid, 0);
+  if (fd < 0) {
+    if (errno == ESRCH) return 0;
+    perror("pidfd_open");
+    return 125;
+  }
+  char path[64], *record = NULL;
+  size_t capacity = 0;
+  snprintf(path, sizeof(path), "/proc/%llu/stat", pid);
+  FILE *stream = fopen(path, "r");
+  unsigned long long actual = 0;
+  if (stream) {
+    if (getline(&record, &capacity, stream) >= 0) {
+      char *field = strrchr(record, ')');
+      if (field && field[1] == ' ') {
+        char *state;
+        field = strtok_r(field + 2, " \n", &state);
+        for (int i = 0; i < 19 && field; i++) field = strtok_r(NULL, " \n", &state);
+        if (field) actual = positive(field);
+      }
+    }
+    fclose(stream);
+  }
+  free(record);
+  int status = 0;
+  if (actual != expected) {
+    if (!exited(fd)) {
+      fprintf(stderr, "refusing to signal reused or unreadable process identity: pid=%llu expected=linux-starttime:%llu actual=linux-starttime:%llu\n", pid, expected, actual);
+      status = 125;
+    }
+  } else if (syscall(SYS_pidfd_send_signal, fd, signum, NULL, 0) < 0 && errno != ESRCH) {
+    perror("pidfd_send_signal");
+    status = 125;
+  }
+  close(fd);
+  return status;
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/signal-owned-pid.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/signal-owned-pid.sh
new file mode 100644
index 000000000..b952a3f2e
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/signal-owned-pid.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+set -euo pipefail
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+work="$(mktemp -d)"
+trap 'rm -rf "$work"' EXIT
+"${HOST_CC:-cc}" -std=c11 -O2 -Wall -Wextra -Werror "$script_dir/signal-owned-pid.c" -o "$work/signal-owned-pid"
+"$work/signal-owned-pid" "$@"
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/signal-owned-pid.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/signal-owned-pid.test.sh
new file mode 100644
index 000000000..b4147da8b
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/signal-owned-pid.test.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+set -euo pipefail
+[ "$(uname -s)" = Linux ] || exit 0
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+source "$script_dir/process-supervision.sh"
+sleep 30 &
+pid=$!
+trap 'kill "$pid" 2>/dev/null || true; wait "$pid" 2>/dev/null || true' EXIT
+identity="$(fresh_process_birth_identity "$pid")"
+status=0
+bash "$script_dir/signal-owned-pid.sh" --pid "$pid" --identity linux-starttime:1 --signal TERM || status=$?
+[ "$status" = 125 ]
+kill -0 "$pid"
+bash "$script_dir/signal-owned-pid.sh" --pid "$pid" --identity "$identity" --signal TERM
+status=0
+wait "$pid" || status=$?
+[ "$status" = 143 ]
+trap - EXIT
+# A reaped process is already stopped; repeating shutdown succeeds.
+bash "$script_dir/signal-owned-pid.sh" --pid "$pid" --identity "$identity" --signal TERM
+status=0
+bash "$script_dir/signal-owned-pid.sh" --pid -1 --identity "$identity" --signal TERM || status=$?
+[ "$status" = 2 ]
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/lib/verify-sealed-carrier.mts b/src/runtimes/liboliphaunt-wasix-postmaster/lib/verify-sealed-carrier.mts
new file mode 100644
index 000000000..2b8dad39c
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/lib/verify-sealed-carrier.mts
@@ -0,0 +1,535 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { type Stats, lstatSync, readdirSync } from 'node:fs';
+import { join, basename, posix, resolve } from 'node:path';
+import { member, safeRelative, stableRead, AGGREGATE_RELATIVE } from './receipt-files.mts';
+import { profileId, profile } from './linear-memory-profile.mts';
+import {
+  type Inventory,
+  exactKeys,
+  requireSha,
+  parseJson,
+  readRegular,
+  linearMemorySourceHashes,
+  validateExportChain,
+} from './sealed-export-chain.mts';
+import {
+  sideModulePolicy,
+  requiredModules,
+  installedClosureIdentityFromRecords,
+} from './guest-build-provenance.mts';
+import { verifyReceipt } from '../wasmer/bin/verify-postmaster-concurrency-contract.mts';
+const names = (value: string) => value.trim().split(/\s+/);
+const TOP_LEVEL_MANIFEST_KEYS = names(
+  `format-version schema source-lane source-fingerprint core-profile guest-build-recipe-sha256 postgres-version target-triple host-abi engine compiler-config cpu-policy cpu-features wasmer-version wasmer-wasix-version wasmer-source-commit wasmer-patch-sha256 wasmer-cargo-lock-sha256 artifact-abi-version runtime-abi-id producer-recipe-sha256 executor-engine executor-sha256 executor-size linear-memory-profile wasm-features entrypoint artifacts`,
+);
+const ARTIFACT_KEYS = names(
+  `name kind path module-path sha256 raw-sha256 raw-size module-sha256 module-size linear-memory compressed exec-aliases`,
+);
+const RECEIPT_KEYS = names(
+  `schema build_recipe_sha256 wasmer_source_commit wasmer_napi_commit wasmer_test_files_commit wasmer_spec_commit wasmer_patch_sha256 wasmer_prepared_signature_sha256 wasmer_cargo_lock_sha256 wasmer_binary_sha256 wasmer_features wasmer_headless_binary_sha256 wasmer_headless_features runtime_abi_id artifact_abi_version wasix_libc_source_commit wasix_libc_patch_sha256 wasix_libc_prepared_signature_sha256 sysroot_carrier_manifest_sha256 sysroot_variant sysroot_variant_manifest_sha256 host_platform host_abi rustc_host rustc_version llvm_version`,
+);
+const POSTMASTER_EXECUTOR_RECEIPT_KEYS = names(
+  `schema build_recipe_sha256 wasmer_build_receipt_sha256 wasmer_source_commit wasmer_patch_sha256 wasmer_prepared_signature_sha256 wasmer_cargo_lock_sha256 runtime_abi_id artifact_abi_version executor_package executor_binary executor_features executor_role runtime_policy_id cli_contract executor_binary_sha256 start_proof_binary start_proof_features start_proof_policy start_proof_binary_sha256 memory_profile_binary memory_profile_features linear_memory_profile_id memory_profile_binary_sha256 postmaster_compiler_binary postmaster_compiler_features compiler_cpu_policy compiler_cpu_features postmaster_compiler_binary_sha256 host_platform host_abi rustc_host rustc_version`,
+);
+const GUEST_BUILD_RECEIPT_KEYS = names(
+  `schema core_profile guest_source_signature_sha256 docker_image_id installed_closure_sha256 child_backend effective_cflags effective_ldflags effective_wasm_opt effective_wasm_opt_flags effective_wasm_opt_suppress_default atomic_fence_total atomic_fence_set_latch atomic_fence_reset_latch atomic_fence_wait_event_set_wait latch_state_contract final_wasm_concurrency_receipt_sha256 linear_memory_profile_id linear_memory_install_receipt_sha256 postgres_tag postgres_version sysroot_variant`,
+);
+const concurrencyPath = 'share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt';
+const rootFiles = [
+  'guest-build.receipt',
+  'manifest.json',
+  'postmaster-executor.receipt',
+  'wasmer-build.receipt',
+];
+const expectedArtifacts = [
+  { name: 'runtime:initdb', kind: 'executable', path: 'bin/initdb', aliases: ['/bin/initdb'] },
+  {
+    name: 'runtime:postgres',
+    kind: 'executable',
+    path: 'bin/postgres',
+    aliases: ['/bin/postgres'],
+  },
+  ...sideModulePolicy.map(({ relative }) => ({
+    name: `runtime:${basename(relative)}`,
+    kind: 'side-module',
+    path: relative,
+    aliases: [],
+  })),
+];
+const equal = (actual: unknown, expected: unknown, label: string) =>
+  assert.deepEqual(actual, expected, `${label} differs`);
+const setEqual = (actual: Iterable, expected: Iterable, label: string) =>
+  equal([...actual].sort(), [...expected].sort(), label);
+const text = (bytes: Uint8Array) => {
+  const value = new TextDecoder('utf8', { fatal: true }).decode(bytes);
+  assert(
+    !/[\r\0]/.test(value) && value.endsWith('\n'),
+    'receipt must be canonical newline-terminated text',
+  );
+  return value;
+};
+function identity(inventory: Inventory, path: string) {
+  safeRelative(path);
+  const value = inventory.get(path);
+  assert(value, `path is not inventoried: ${path}`);
+  return value;
+}
+function objectValues(
+  actual: { [key: string]: any },
+  expected: { [key: string]: any },
+  label: string,
+) {
+  for (const [key, value] of Object.entries(expected)) equal(actual[key], value, `${label} ${key}`);
+}
+function integer(value: unknown, minimum = 0): asserts value is number {
+  assert(Number.isSafeInteger(value) && (value as number) >= minimum, 'invalid integer');
+}
+export function parseReceipt(
+  root: string,
+  inventory: Inventory | undefined,
+  path: string,
+  keys: string[],
+  flags = false,
+) {
+  const lines = text(readRegular(root, path, inventory))
+    .slice(0, -1)
+    .split('\n');
+  assert.equal(lines.length, keys.length, `${path} field count differs`);
+  return Object.fromEntries(
+    lines.map((line, index) => {
+      const separator = line.indexOf('='),
+        key = line.slice(0, separator),
+        value = line.slice(separator + 1);
+      assert(
+        separator > 0 && key === keys[index] && value && (flags || !value.includes('=')),
+        `${path} non-canonical field: ${keys[index]}`,
+      );
+      return [key, value];
+    }),
+  );
+}
+export function executorReceipt(
+  root: string,
+  inventory: Inventory,
+  wasmer: { [key: string]: string },
+) {
+  const receipt = parseReceipt(
+    root,
+    inventory,
+    'postmaster-executor.receipt',
+    POSTMASTER_EXECUTOR_RECEIPT_KEYS,
+  );
+  for (const key of POSTMASTER_EXECUTOR_RECEIPT_KEYS.filter(
+    (key) => key.endsWith('_sha256') || key === 'runtime_abi_id',
+  ))
+    requireSha(receipt[key]);
+  const common =
+    names(`build_recipe_sha256 wasmer_source_commit wasmer_patch_sha256 wasmer_prepared_signature_sha256
+ wasmer_cargo_lock_sha256 runtime_abi_id artifact_abi_version host_platform host_abi rustc_host rustc_version`);
+  for (const key of common) equal(receipt[key], wasmer[key], `executor/Wasmer receipt ${key}`);
+  objectValues(
+    receipt,
+    {
+      schema: 'oliphaunt.wasix-postmaster.postmaster-executor-build.v3',
+      wasmer_build_receipt_sha256: identity(inventory, 'wasmer-build.receipt').sha256,
+      executor_binary_sha256: identity(inventory, 'bin/wasmer-headless').sha256,
+      executor_package: 'oliphaunt-wasix-postmaster-executor',
+      executor_binary: 'oliphaunt-wasix-postmaster-executor',
+      executor_features: 'product-executor',
+      executor_role: 'postmaster-product',
+      runtime_policy_id:
+        'oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2',
+      cli_contract: 'sealed-postmaster-run-v1',
+      start_proof_binary: 'oliphaunt-wasix-start-proof',
+      start_proof_features: 'start-proof-tool',
+      start_proof_policy: 'llvm-shared-memory-init-restricted-effects.v1',
+      memory_profile_binary: 'oliphaunt-wasix-memory-profile',
+      memory_profile_features: 'memory-profile-tool',
+      linear_memory_profile_id: profileId,
+      postmaster_compiler_binary: 'oliphaunt-wasix-postmaster-compiler',
+      postmaster_compiler_features: 'product-compiler',
+      compiler_cpu_policy: 'generic-baseline',
+      compiler_cpu_features: 'none',
+    },
+    'executor receipt',
+  );
+  return receipt;
+}
+export function guestReceipt(root: string, inventory?: Inventory) {
+  const receipt = parseReceipt(
+    root,
+    inventory,
+    'guest-build.receipt',
+    GUEST_BUILD_RECEIPT_KEYS,
+    true,
+  );
+  for (const key of GUEST_BUILD_RECEIPT_KEYS.filter((key) => key.endsWith('_sha256')))
+    requireSha(receipt[key]);
+  assert(
+    /^sha256:[0-9a-f]{64}$/.test(receipt.docker_image_id),
+    'guest builder must be an immutable Docker image',
+  );
+  assert(['yes', 'no'].includes(receipt.effective_wasm_opt), 'invalid wasm-opt mode');
+  assert(/^[1-9][0-9]*$/.test(receipt.atomic_fence_total), 'invalid fence total');
+  objectValues(
+    receipt,
+    {
+      schema: 'oliphaunt.wasix-postmaster.guest-build.v5',
+      core_profile: 'release-o3',
+      child_backend: 'exec',
+      effective_wasm_opt_suppress_default: 'yes',
+      atomic_fence_set_latch: '2',
+      atomic_fence_reset_latch: '1',
+      atomic_fence_wait_event_set_wait: '1',
+      latch_state_contract: 'packed-atomic-v1',
+      linear_memory_profile_id: profileId,
+    },
+    'guest receipt',
+  );
+  return receipt;
+}
+export function carrierTree(root: string) {
+  const entries = new Map();
+  function walk(relative: string) {
+    const path = relative === '.' ? root : member(root, relative),
+      info = lstatSync(path);
+    assert(info.isDirectory(), `carrier parent is not a real directory: ${path}`);
+    entries.set(relative, info);
+    const directories: string[] = [];
+    for (const name of readdirSync(path).sort()) {
+      const child = relative === '.' ? name : `${relative}/${name}`;
+      safeRelative(child);
+      const info = lstatSync(join(path, name));
+      if (info.isDirectory()) directories.push(child);
+      else {
+        assert(info.isFile(), `carrier entry is not a regular file: ${child}`);
+        entries.set(child, info);
+      }
+    }
+    for (const child of directories) walk(child);
+  }
+  walk('.');
+  return entries;
+}
+export function hashRegular(path: string) {
+  const hash = createHash('sha256');
+  const info = stableRead(path, (chunk) => {
+    hash.update(chunk);
+  });
+  return { size: Number(info.size), sha256: hash.digest('hex') };
+}
+export function parsePayloadInventory(data: Buffer) {
+  const lines = text(data).slice(0, -1).split('\n');
+  equal(lines.shift(), 'schema=oliphaunt.wasix-postmaster.payload-files.v1', 'payload schema');
+  const inventory: Inventory = new Map();
+  let previous = '';
+  for (const line of lines) {
+    const [digest, sizeText, path, extra] = line.split('\t');
+    assert(extra === undefined && path, 'payload row must have three fields');
+    requireSha(digest);
+    assert(/^(0|[1-9][0-9]*)$/.test(sizeText), 'invalid payload size');
+    safeRelative(path);
+    assert(path !== 'payload.files' && path > previous, 'payload paths must be sorted and unique');
+    previous = path;
+    const size = Number(sizeText);
+    integer(size);
+    inventory.set(path, { size, sha256: digest });
+  }
+  assert(inventory.size, 'empty inventory');
+  return inventory;
+}
+export function verifyInventory(root: string) {
+  const files = new Set(),
+    directories = new Set();
+  for (const [path, info] of carrierTree(root)) {
+    const mode = info.mode & 0o7777;
+    assert(
+      info.isDirectory() ? mode === 0o555 : [0o444, 0o555].includes(mode),
+      `carrier entry is not read-only: ${path}`,
+    );
+    if (path !== '.') (info.isDirectory() ? directories : files).add(path);
+  }
+  const inventory = parsePayloadInventory(readRegular(root, 'payload.files'));
+  const expectedFiles = new Set([...inventory.keys(), 'payload.files']),
+    expectedDirs = new Set();
+  for (const path of expectedFiles)
+    for (let parent = posix.dirname(path); parent !== '.'; parent = posix.dirname(parent))
+      expectedDirs.add(parent);
+  setEqual(files, expectedFiles, 'inventory file closure');
+  setEqual(directories, expectedDirs, 'inventory directory closure');
+  for (const [path, expected] of inventory) {
+    const hash = createHash('sha256');
+    const info = stableRead(
+      member(root, path),
+      (chunk) => {
+        hash.update(chunk);
+      },
+      expected.size,
+    );
+    equal(Number(info.size), expected.size, `payload size ${path}`);
+    equal(hash.digest('hex'), expected.sha256, `payload digest ${path}`);
+  }
+  const paths = [...inventory.keys()];
+  setEqual(
+    paths.filter((path) => !path.includes('/')),
+    rootFiles,
+    'carrier root',
+  );
+  setEqual(
+    paths.filter((path) => path.startsWith('bin/')),
+    ['bin/initdb', 'bin/postgres', 'bin/wasmer-headless'],
+    'carrier bin',
+  );
+  setEqual(
+    paths.filter((path) => path.startsWith('lib/')),
+    sideModulePolicy.flatMap(({ relative, aliases }) => [relative, ...aliases]),
+    'carrier lib',
+  );
+  assert(
+    paths.some((path) => path.startsWith('share/postgresql/')),
+    'empty PostgreSQL share tree',
+  );
+  assert(
+    paths.every(
+      (path) =>
+        rootFiles.includes(path) || /^(bin\/|lib\/|share\/postgresql\/|aot\/|memory\/)/.test(path),
+    ),
+    'file outside carrier closure',
+  );
+  for (const { relative, aliases } of sideModulePolicy)
+    for (const alias of aliases)
+      equal(identity(inventory, alias), identity(inventory, relative), `alias ${alias}`);
+  return inventory;
+}
+export function sourceFingerprint(root: string, inventory?: Inventory) {
+  const hash = createHash('sha256');
+  for (const [path, info] of carrierTree(root)) {
+    if (!info.isFile() || !/^(bin|lib|share)\//.test(path) || path === 'bin/wasmer-headless')
+      continue;
+    const { size, sha256 } = inventory
+      ? identity(inventory, path)
+      : hashRegular(member(root, path));
+    for (const value of [path, String(size), sha256]) {
+      const bytes = Buffer.from(value),
+        length = Buffer.alloc(8);
+      length.writeBigUInt64BE(BigInt(bytes.length));
+      hash.update(length).update(bytes);
+    }
+  }
+  return hash.digest('hex');
+}
+export function verify(
+  root: string,
+  producer: string,
+  pgVersion: string,
+  wasmerVersion: string,
+  wasixVersion: string,
+  abi: number,
+  canonicalRoot: string,
+) {
+  equal(resolve(root), resolve(canonicalRoot), 'canonical carrier root');
+  requireSha(producer);
+  integer(abi);
+  const inventory = verifyInventory(root);
+  const json = (path: string) => parseJson(readRegular(root, path, inventory));
+  const wasmer = parseReceipt(root, inventory, 'wasmer-build.receipt', RECEIPT_KEYS);
+  const executor = executorReceipt(root, inventory, wasmer),
+    guest = guestReceipt(root, inventory);
+  equal(
+    identity(inventory, concurrencyPath).sha256,
+    guest.final_wasm_concurrency_receipt_sha256,
+    'guest concurrency binding',
+  );
+  const concurrency = verifyReceipt(
+    text(readRegular(root, concurrencyPath, inventory)),
+    readRegular(root, 'bin/postgres', inventory),
+  );
+  equal(concurrency.atomic_fence_total, guest.atomic_fence_total, 'final fence total');
+  const manifest = json('manifest.json');
+  exactKeys(manifest, TOP_LEVEL_MANIFEST_KEYS, 'sealed manifest');
+  const headless = identity(inventory, 'bin/wasmer-headless');
+  integer(headless.size, 1);
+  objectValues(
+    manifest,
+    {
+      'format-version': 6,
+      schema: 'oliphaunt.wasix-postmaster.sealed-aot.v5',
+      'source-lane': 'wasix-postmaster',
+      'core-profile': 'release-o3',
+      'guest-build-recipe-sha256': identity(inventory, 'guest-build.receipt').sha256,
+      'postgres-version': pgVersion,
+      'target-triple': wasmer.rustc_host,
+      'host-abi': wasmer.host_abi,
+      engine: 'llvm-opta',
+      'cpu-policy': 'generic-baseline',
+      'cpu-features': [],
+      'wasmer-version': wasmerVersion,
+      'wasmer-wasix-version': wasixVersion,
+      'wasmer-source-commit': wasmer.wasmer_source_commit,
+      'wasmer-patch-sha256': wasmer.wasmer_patch_sha256,
+      'wasmer-cargo-lock-sha256': wasmer.wasmer_cargo_lock_sha256,
+      'artifact-abi-version': abi,
+      'runtime-abi-id': wasmer.runtime_abi_id,
+      'producer-recipe-sha256': producer,
+      'executor-engine': 'engine-headless',
+      'executor-sha256': headless.sha256,
+      'executor-size': headless.size,
+      'wasm-features': ['exceptions', 'threads'],
+      entrypoint: 'runtime:postgres',
+      'source-fingerprint': sourceFingerprint(root, inventory),
+    },
+    'sealed manifest',
+  );
+  assert(
+    typeof manifest['compiler-config'] === 'string' && manifest['compiler-config'],
+    'empty compiler config',
+  );
+  equal(wasmer.artifact_abi_version, String(abi), 'Wasmer ABI');
+  equal(executor.executor_binary_sha256, headless.sha256, 'selected executor');
+  objectValues(
+    guest,
+    { postgres_version: pgVersion, sysroot_variant: wasmer.sysroot_variant },
+    'guest receipt',
+  );
+  const linear = identity(inventory, AGGREGATE_RELATIVE);
+  integer(linear.size, 1);
+  const profileKeys = names(
+    'address-width supported-host-pointer-width maximum-pages maximum-bytes static-bound-pages static-offset-guard-bytes static-access-lowering',
+  );
+  equal(
+    manifest['linear-memory-profile'],
+    {
+      id: profileId,
+      ...Object.fromEntries(profileKeys.map((key) => [key, profile[key]])),
+      'install-receipt-path': AGGREGATE_RELATIVE,
+      'install-receipt-sha256': linear.sha256,
+    },
+    'manifest memory profile',
+  );
+  equal(guest.linear_memory_install_receipt_sha256, linear.sha256, 'guest memory binding');
+  const sources = linearMemorySourceHashes(root, inventory);
+  validateExportChain(root, join(import.meta.dirname, '..'), sources, inventory);
+  const guestPaths = [
+    ...new Set(
+      [...requiredModules, ...inventory.keys()].filter(
+        (path) => requiredModules.includes(path) || path.startsWith('share/postgresql/'),
+      ),
+    ),
+  ].sort();
+  equal(
+    guest.installed_closure_sha256,
+    installedClosureIdentityFromRecords(
+      guestPaths.map((relative) => ({ relative, ...identity(inventory, relative) })),
+    ),
+    'guest installed closure',
+  );
+  assert(
+    Array.isArray(manifest.artifacts) && manifest.artifacts.length === expectedArtifacts.length,
+    'artifact closure differs',
+  );
+  const aotPaths = new Set(),
+    moduleHashes = new Set();
+  for (const [index, expected] of expectedArtifacts.entries()) {
+    const artifact = manifest.artifacts[index];
+    exactKeys(artifact, ARTIFACT_KEYS, 'artifact');
+    const module = identity(inventory, expected.path);
+    assert(!moduleHashes.has(module.sha256), 'duplicate module digest');
+    moduleHashes.add(module.sha256);
+    const path = `aot/${module.sha256.toUpperCase()}.bin`,
+      aot = identity(inventory, path);
+    aotPaths.add(path);
+    assert(sources.has(expected.path), `memory receipt lacks ${expected.path}`);
+    objectValues(
+      artifact,
+      {
+        name: expected.name,
+        kind: expected.kind,
+        'module-path': expected.path,
+        'exec-aliases': expected.aliases,
+        compressed: false,
+        'module-sha256': module.sha256,
+        'module-size': module.size,
+        path,
+        sha256: aot.sha256,
+        'raw-sha256': aot.sha256,
+        'raw-size': aot.size,
+        'linear-memory': {
+          'profile-id': profileId,
+          'install-receipt-sha256': linear.sha256,
+          'source-module-sha256': sources.get(expected.path),
+        },
+      },
+      `artifact ${expected.name}`,
+    );
+  }
+  setEqual(
+    [...inventory.keys()].filter((path) => path.startsWith('aot/')),
+    aotPaths,
+    'AOT closure',
+  );
+  assert(
+    ![...inventory.keys()].some((path) => path.startsWith('memory/')),
+    'unsupported preinitialized-memory payloads',
+  );
+}
+if (import.meta.main) {
+  try {
+    const [command, root, ...args] = process.argv.slice(2);
+    assert(root, 'carrier root is required');
+    if (command === 'regular-identity' && !args.length) {
+      const hash = createHash('sha256');
+      const info = stableRead(root, (chunk) => {
+        hash.update(chunk);
+      });
+      console.log([hash.digest('hex'), info.dev, info.ino].join('\t'));
+    } else if (command === 'provenance' && !args.length) {
+      const manifest = parseJson(readRegular(root, 'manifest.json'));
+      assert(
+        ['release-o3', 'safe-o2'].includes(manifest['core-profile']),
+        'sealed carrier core profile differs',
+      );
+      requireSha(manifest['guest-build-recipe-sha256']);
+      console.log([manifest['core-profile'], manifest['guest-build-recipe-sha256']].join('\t'));
+    } else if (command === 'recipe-inputs' && !args.length) {
+      assert(lstatSync(root).isDirectory(), 'carrier root must be a non-symlink directory');
+      const manifest = parseJson(readRegular(root, 'manifest.json'));
+      const values = ['compiler-config', 'target-triple', 'source-fingerprint'].map((key) => {
+        const value = manifest[key];
+        assert(typeof value === 'string' && value && !/[\r\n\0]/.test(value), `invalid ${key}`);
+        return value;
+      });
+      requireSha(values[2]);
+      console.log(values.join('\n'));
+    } else if (command === 'executor-selection' && !args.length) {
+      const inventory = verifyInventory(root),
+        wasmer = parseReceipt(root, inventory, 'wasmer-build.receipt', RECEIPT_KEYS);
+      executorReceipt(root, inventory, wasmer);
+      const manifest = parseJson(readRegular(root, 'manifest.json', inventory)),
+        executor = identity(inventory, 'bin/wasmer-headless');
+      equal(manifest['executor-sha256'], executor.sha256, 'selected executor digest');
+      equal(manifest['executor-size'], executor.size, 'selected executor size');
+      console.log(
+        [
+          'postmaster-product',
+          'postmaster-executor.receipt',
+          identity(inventory, 'postmaster-executor.receipt').sha256,
+          executor.sha256,
+        ].join('\t'),
+      );
+    } else {
+      assert(
+        command === 'verify' && args.length === 6,
+        'usage: verify-sealed-carrier.mts recipe-inputs ROOT | executor-selection ROOT | verify ROOT PRODUCER PG WASMER WASIX ABI CANONICAL_ROOT',
+      );
+      assert(/^(0|[1-9][0-9]*)$/.test(args[4]), 'invalid artifact ABI');
+      verify(root, args[0], args[1], args[2], args[3], Number(args[4]), args[5]);
+    }
+  } catch (error) {
+    console.error(
+      `sealed carrier verification failed: ${error instanceof Error ? error.message : error}`,
+    );
+    process.exitCode = 2;
+  }
+}
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/wasix-build-lock.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/wasix-build-lock.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/lib/wasix-build-lock.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/lib/wasix-build-lock.sh
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/wasix-build-lock.test.sh b/src/runtimes/liboliphaunt-wasix-postmaster/lib/wasix-build-lock.test.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/lib/wasix-build-lock.test.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/lib/wasix-build-lock.test.sh
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/moon.yml b/src/runtimes/liboliphaunt-wasix-postmaster/moon.yml
new file mode 100644
index 000000000..e294fd28f
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/moon.yml
@@ -0,0 +1,448 @@
+$schema: https://moonrepo.dev/schemas/project.json
+id: liboliphaunt-wasix-postmaster
+language: c
+layer: library
+stack: systems
+tags:
+  - javascript-quality
+  - runtime
+  - wasix
+  - wasm
+  - postgres
+  - release-product
+dependsOn:
+  - id: postgres18
+    scope: build
+  - id: third-party-icu
+    scope: build
+  - id: third-party-openssl
+    scope: build
+  - id: liboliphaunt-wasix
+    scope: build
+project:
+  title: liboliphaunt WASIX Postmaster
+  description: Concurrent PostgreSQL 18 postmaster runtime with isolated WASIX backends.
+  owner: oliphaunt
+  release:
+    component: liboliphaunt-wasix-postmaster
+    packagePath: src/runtimes/liboliphaunt-wasix-postmaster
+    artifactTargets:
+      preset: liboliphaunt-wasix-postmaster
+      targets:
+        - linux-arm64-gnu
+        - linux-x64-gnu
+        - macos-arm64
+owners:
+  defaultOwner: "@oliphaunt/wasix"
+  paths:
+    "**/*":
+      - "@oliphaunt/wasix"
+fileGroups:
+  guest-sealing:
+    - bin/apply-wasix-core-overlay.sh
+    - "bin/seal-wasix-{core-exports,linear-memory}.sh"
+    - "lib/{wasix-build-lock.sh,guest-generation.sh,select-guest-generation.mts,publish-directory.c,guest-build-provenance.mts,receipt-files.mts,linear-memory-profile.mts,sealed-export-chain.mts,durable-publication.mts}"
+    - "wasmer/bin/{verify-postmaster-wasm-import.mts,verify-postmaster-concurrency-contract.mts,analyze-wasm-concurrency.sh}"
+    - wasmer/policies/sealed-*
+    - "tools/sealed-export-closure/Cargo.{toml,lock}"
+    - "tools/sealed-export-closure/src/**/*"
+    - /tools/packaging/strict-json.mts
+  runtime-source:
+    - wasmer/**/*
+    - "executor/{Cargo.toml,Cargo.lock,prepare-paths.mts}"
+    - "executor/src/**/*"
+    - "!wasmer/tests.sh"
+    - "!wasmer/capabilities.tsv"
+    - "!wasmer/**/*.md"
+    - "!wasmer/**/*.test.mts"
+tasks:
+  executor-build:
+    script: "cd executor\ncargo build --locked --release --no-default-features --features product-executor --bin oliphaunt-wasix-postmaster-executor --target-dir ../../../target/oliphaunt-wasix-postmaster/runtime/postmaster-executor-target\n"
+    deps:
+      - liboliphaunt-wasix-postmaster:prepare-runtime
+    inputs:
+      - "@group(runtime-source)"
+    options:
+      cache: false
+      runInCI: false
+  executor-test:
+    script: "cd executor\ncargo test --locked --release --no-default-features --features product-executor --lib --target-dir ../../../target/oliphaunt-wasix-postmaster/runtime/postmaster-executor-target\n"
+    deps:
+      - liboliphaunt-wasix-postmaster:prepare-runtime
+    inputs:
+      - "@group(runtime-source)"
+    options:
+      cache: false
+      runInCI: false
+  lint:
+    tags:
+      - quality
+      - static
+    script: "set -e\nwhile IFS= read -r script; do bash -n \"$script\"; done < <(find src/runtimes/liboliphaunt-wasix-postmaster -type f -name '*.sh' | LC_ALL=C sort)\n"
+    inputs:
+      - "**/*.sh"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  test:
+    tags:
+      - quality
+      - unit
+      - requires-rust
+    script: "set -e\nbun test ./src/runtimes/liboliphaunt-wasix-postmaster\ncargo test --locked --manifest-path src/runtimes/liboliphaunt-wasix-postmaster/tools/sealed-export-closure/Cargo.toml --target-dir target/oliphaunt-wasix-postmaster/runtime/sealed-export-closure-target\nwhile IFS= read -r test_file; do bash \"$test_file\"; done < <(find src/runtimes/liboliphaunt-wasix-postmaster -type f -name '*.test.sh' ! -name 'seal-wasix-linear-memory.test.sh' | LC_ALL=C sort)\n"
+    inputs:
+      - "**/*"
+      - /tools/packaging/strict-json.mts
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  prepare-postgres:
+    tags:
+      - runtime
+      - source
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/apply-wasix-core-overlay.sh
+    deps:
+      - source-inputs:source-fetch-wasix-postmaster-runtime
+    inputs:
+      - /src/third-party/postgres/source.toml
+      - /src/third-party/postgres/**/*
+      - "!/src/third-party/postgres/**/*.test.*"
+      - "!/src/third-party/postgres/testdata/**/*"
+      - /src/runtimes/liboliphaunt-wasix-postmaster/postgres/**/*
+      - /src/runtimes/liboliphaunt-wasix-postmaster/bin/prepare-baseline.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/bin/apply-wasix-core-overlay.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  prepare-runtime:
+    tags:
+      - runtime
+      - source
+      - rust
+    command: UPSTREAM_WORK_ROOT=$PWD/target/oliphaunt-wasix-postmaster/runtime bash src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/prepare-upstream-checkouts.sh
+    deps:
+      - source-inputs:source-fetch-wasix-postmaster-runtime
+    inputs:
+      - "@group(runtime-source)"
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  runtime-build:
+    tags:
+      - runtime
+      - wasix
+      - rust
+      - build
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/build-runtime.sh --build-only
+    deps:
+      - liboliphaunt-wasix-postmaster:prepare-runtime
+    inputs:
+      - "@group(cargo-workspace)"
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker/**/*
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+      - "@group(runtime-source)"
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
+    outputs:
+      - /target/oliphaunt-wasix-postmaster/runtime/build/**/*
+      - /target/oliphaunt-wasix-postmaster/runtime/wasmer/target/release/wasmer
+      - /target/oliphaunt-wasix-postmaster/runtime/wasmer/target/release/wasmer-headless
+      - /target/oliphaunt-wasix-postmaster/runtime/postmaster-executor-target/release/oliphaunt-wasix-postmaster-executor
+      - /target/oliphaunt-wasix-postmaster/runtime/postmaster-executor-target/release/oliphaunt-wasix-start-proof
+      - /target/oliphaunt-wasix-postmaster/runtime/postmaster-executor-target/release/oliphaunt-wasix-memory-profile
+      - /target/oliphaunt-wasix-postmaster/runtime/postmaster-compiler-target/release/oliphaunt-wasix-postmaster-compiler
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  runtime-patch-tests:
+    tags:
+      - runtime
+      - wasix
+      - test
+      - requires-rust
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/build-runtime.sh --tests-only
+    deps:
+      - liboliphaunt-wasix-postmaster:prepare-runtime
+    inputs:
+      - "@group(cargo-workspace)"
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker/**/*
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+      - "@group(runtime-source)"
+      - wasmer/tests.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  configure:
+    tags:
+      - runtime
+      - wasix
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.sh --configure-only
+    deps:
+      - liboliphaunt-wasix-postmaster:prepare-postgres
+      - liboliphaunt-wasix-postmaster:runtime-build
+    inputs:
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker/**/*
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  postgres-build:
+    tags:
+      - runtime
+      - wasix
+      - postgres
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.sh
+    deps:
+      - liboliphaunt-wasix-postmaster:configure
+    inputs:
+      - "@group(guest-sealing)"
+      - /src/third-party/postgres/source.toml
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker/**/*
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+      - /src/third-party/postgres/**/*
+      - "!/src/third-party/postgres/**/*.test.*"
+      - "!/src/third-party/postgres/testdata/**/*"
+      - /src/runtimes/liboliphaunt-wasix-postmaster/postgres/**/*
+      - /src/runtimes/liboliphaunt-wasix-postmaster/bin/build-wasix-core.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
+    outputs:
+      - /target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3.current
+      - /target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3.generations/[0-9a-f]*/**/*
+      - /target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3/**/*
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  runtime-capabilities:
+    tags:
+      - runtime
+      - wasix
+      - rust
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/qualify-runtime-capabilities.sh
+    deps:
+      - liboliphaunt-wasix-postmaster:runtime-build
+    inputs:
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker/**/*
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+      - "@group(runtime-source)"
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  linear-memory-integration:
+    tags:
+      - runtime
+      - wasix
+      - test
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-linear-memory.test.sh
+    deps:
+      - liboliphaunt-wasix-postmaster:runtime-build
+    inputs:
+      - /src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-linear-memory.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/bin/seal-wasix-linear-memory.test.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/receipt-files.mts
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/linear-memory-profile.mts
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/sealed-export-chain.mts
+      - /tools/packaging/strict-json.mts
+      - /src/runtimes/liboliphaunt-wasix-postmaster/testdata/make-sealed-export-fixture.mts
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  initdb-smoke:
+    tags:
+      - runtime
+      - wasix
+      - postgres
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-core.sh
+    deps:
+      - liboliphaunt-wasix-postmaster:runtime-capabilities
+      - liboliphaunt-wasix-postmaster:postgres-build
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  initdb-stress:
+    tags:
+      - runtime
+      - wasix
+      - postgres
+      - reliability
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/stress-wasix-initdb.sh --iterations 20
+    deps:
+      - liboliphaunt-wasix-postmaster:regression
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  smoke:
+    tags:
+      - runtime
+      - wasix
+      - postgres
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/smoke-wasix-concurrent-connections.sh
+    deps:
+      - liboliphaunt-wasix-postmaster:initdb-smoke
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  regression:
+    tags:
+      - runtime
+      - wasix
+      - postgres
+      - regression
+    command: WASIX_SKIP_PRECOMPILE=1 WASIX_REGRESS_SUITE_NAME=wasix-regress-acceptance bash src/runtimes/liboliphaunt-wasix-postmaster/bin/run-wasix-regress-subset.sh boolean case copy
+    deps:
+      - liboliphaunt-wasix-postmaster:smoke
+    inputs:
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker/**/*
+      - /src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/bin/run-wasix-regress-subset.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/bin/wasix-make.sh
+      - /src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  carrier:
+    tags:
+      - runtime
+      - artifact
+    script: "set -e\nexport WASIX_CORE_PROFILE=release-o3\nbash src/runtimes/liboliphaunt-wasix-postmaster/bin/precompile-wasix-core.sh\nbash src/runtimes/liboliphaunt-wasix-postmaster/bin/build-sealed-headless-carrier.sh\n"
+    deps:
+      - liboliphaunt-wasix-postmaster:postgres-build
+      - liboliphaunt-wasix-postmaster:runtime-capabilities
+    inputs:
+      - "@group(legal-files)"
+      - "@group(cargo-workspace)"
+      - "**/*"
+      - /src/runtimes/liboliphaunt-wasix-postmaster/sources/*.toml
+      - "/tools/packaging/*.{mjs,mts}"
+    outputs:
+      - /target/oliphaunt-wasix-postmaster/carriers/**/*
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  release-assets:
+    tags:
+      - release
+      - artifact
+      - in-place-finalizer-input
+      - ci-wasix-postmaster
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/package-release-assets.sh
+    deps:
+      - liboliphaunt-wasix-postmaster:carrier
+    inputs:
+      - "@group(legal-files)"
+      - "**/*"
+      - /src/runtimes/liboliphaunt-wasix-postmaster/sources/*.toml
+      - "/tools/packaging/*.{mjs,mts}"
+      - /target/oliphaunt-wasix-postmaster/carriers/**/*
+    outputs:
+      - /target/oliphaunt-wasix-postmaster/release-assets/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  backend-wave-stress:
+    tags:
+      - runtime
+      - wasix
+      - postgres
+      - reliability
+    script: "set -e\nsource src/runtimes/liboliphaunt-wasix-postmaster/lib/common.sh\nsource \"$FRESH_ROOT/lib/sealed-carrier.sh\"\ncarrier=\"$(fresh_select_current_sealed_carrier)\"\nbash src/runtimes/liboliphaunt-wasix-postmaster/bin/stress-wasix-backend-waves.sh \\\n  --sealed-carrier \"$carrier\" \\\n  --attempts 10\n"
+    deps:
+      - liboliphaunt-wasix-postmaster:carrier
+      - liboliphaunt-wasix-postmaster:initdb-stress
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+      runInCI: true
+  immediate-recovery:
+    tags:
+      - runtime
+      - wasix
+      - postgres
+      - recovery
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/qualify-release-carrier.sh
+    deps:
+      - liboliphaunt-wasix-postmaster:carrier
+      - liboliphaunt-wasix-postmaster:backend-wave-stress
+    inputs:
+      - "**/*"
+      - /target/oliphaunt-wasix-postmaster/carriers/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  portable-inputs:
+    tags:
+      - runtime
+      - artifact
+      - ci-wasix-postmaster
+    command: bash src/runtimes/liboliphaunt-wasix-postmaster/bin/package-portable-build-inputs.sh
+    deps:
+      - liboliphaunt-wasix-postmaster:postgres-build
+      - liboliphaunt-wasix-postmaster:runtime-capabilities
+    inputs:
+      - "**/*"
+      - /src/runtimes/liboliphaunt-wasix-postmaster/sources/*.toml
+      - "/tools/packaging/*.{mjs,mts}"
+      - /target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3.current
+      - /target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3.generations/[0-9a-f]*/**/*
+      - /target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3/**/*
+      - /target/oliphaunt-wasix-postmaster/runtime/build/patched-wasixcc-sysroot/**/*
+      - /target/oliphaunt-wasix-postmaster/runtime/build/probes/**/*
+    outputs:
+      - /target/oliphaunt-wasix-postmaster/portable-inputs/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  finalize-release-assets:
+    tags:
+      - release
+      - artifact-package
+      - in-place-finalizer
+      - ci-wasix-postmaster
+    script: "set -eu\nversion=\"$(tr -d '\\r\\n' < src/runtimes/liboliphaunt-wasix-postmaster/VERSION)\"\nbun src/runtimes/liboliphaunt-wasix-postmaster/tools/merge-product-release-assets.mts \\\n  --product liboliphaunt-wasix-postmaster \\\n  --version \"$version\" \\\n  --asset-dir target/oliphaunt-wasix-postmaster/release-assets\n"
+    deps:
+      - liboliphaunt-wasix-postmaster:release-assets
+    inputs:
+      - /src/runtimes/liboliphaunt-wasix-postmaster/VERSION
+      - /src/runtimes/liboliphaunt-wasix-postmaster/moon.yml
+      - /src/runtimes/liboliphaunt-wasix-postmaster/tools/merge-product-release-assets.mts
+      - /tools/release/platform-compatibility-policy.mts
+      - /tools/release/release-artifact-targets.mts
+      - /tools/release/release-graph.mts
+      - /target/oliphaunt-wasix-postmaster/release-assets/**/*
+    outputs:
+      - /target/oliphaunt-wasix-postmaster/release-assets/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/backend/port/sysv_shmem.c b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/backend/port/sysv_shmem.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/backend/port/sysv_shmem.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/backend/port/sysv_shmem.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/backend/postmaster/fork_process.c b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/backend/postmaster/fork_process.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/backend/postmaster/fork_process.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/backend/postmaster/fork_process.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/include/port/wasix-core.h b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/include/port/wasix-core.h
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/include/port/wasix-core.h
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/include/port/wasix-core.h
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/interfaces/libpq/wasix_encoding_shim.c b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/interfaces/libpq/wasix_encoding_shim.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/interfaces/libpq/wasix_encoding_shim.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/interfaces/libpq/wasix_encoding_shim.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/makefiles/Makefile.wasix-core b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/makefiles/Makefile.wasix-core
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/makefiles/Makefile.wasix-core
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/makefiles/Makefile.wasix-core
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/template/wasix-core b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/template/wasix-core
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/overlays/wasix-core/src/template/wasix-core
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/overlays/wasix-core/src/template/wasix-core
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0001-wasix-use-posix-dsm-not-sysv.patch b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0001-wasix-use-posix-dsm-not-sysv.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0001-wasix-use-posix-dsm-not-sysv.patch
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0001-wasix-use-posix-dsm-not-sysv.patch
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0003-wasix-libpq-static-encoding-shim.patch b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0003-wasix-libpq-static-encoding-shim.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0003-wasix-libpq-static-encoding-shim.patch
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0003-wasix-libpq-static-encoding-shim.patch
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0004-wasix-core-execbackend-initdb-runtime.patch b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0004-wasix-core-execbackend-initdb-runtime.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0004-wasix-core-execbackend-initdb-runtime.patch
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0004-wasix-core-execbackend-initdb-runtime.patch
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0006-wasix-retry-proc-join-on-eintr.patch b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0006-wasix-retry-proc-join-on-eintr.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0006-wasix-retry-proc-join-on-eintr.patch
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0006-wasix-retry-proc-join-on-eintr.patch
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0008-wasix-packed-atomic-latch-state.patch b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0008-wasix-packed-atomic-latch-state.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0008-wasix-packed-atomic-latch-state.patch
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0008-wasix-packed-atomic-latch-state.patch
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/product-patch-provenance.toml b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/product-patch-provenance.toml
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/postgres/product-patch-provenance.toml
rename to src/runtimes/liboliphaunt-wasix-postmaster/postgres/product-patch-provenance.toml
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/postgres/series b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/series
new file mode 100644
index 000000000..46abae0f7
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/postgres/series
@@ -0,0 +1,14 @@
+# PostgreSQL 18.4. Ordered repository-relative patch paths.
+# Retain concurrent atomics/spinlocks; do not select embedded patches 0035/0036.
+src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0001-wasix-use-posix-dsm-not-sysv.patch
+src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0003-wasix-libpq-static-encoding-shim.patch
+src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0004-wasix-core-execbackend-initdb-runtime.patch
+src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0006-wasix-retry-proc-join-on-eintr.patch
+src/runtimes/liboliphaunt-wasix-postmaster/postgres/patches/0008-wasix-packed-atomic-latch-state.patch
+src/third-party/postgres/patches/wasix/0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch
+src/third-party/postgres/patches/wasix/0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch
+src/third-party/postgres/patches/wasix/0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch
+src/third-party/postgres/patches/wasix/0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch
+src/third-party/postgres/patches/wasix/0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch
+src/third-party/postgres/patches/wasix/0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch
+src/third-party/postgres/patches/wasix/0037-oliphaunt-wasix-buffer-strong-random.patch
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/profiles/durability/safe-v1.gucs b/src/runtimes/liboliphaunt-wasix-postmaster/profiles/durability/safe-v1.gucs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/profiles/durability/safe-v1.gucs
rename to src/runtimes/liboliphaunt-wasix-postmaster/profiles/durability/safe-v1.gucs
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/profiles/runtime-footprints/embedded-concurrent-v1.gucs b/src/runtimes/liboliphaunt-wasix-postmaster/profiles/runtime-footprints/embedded-concurrent-v1.gucs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/profiles/runtime-footprints/embedded-concurrent-v1.gucs
rename to src/runtimes/liboliphaunt-wasix-postmaster/profiles/runtime-footprints/embedded-concurrent-v1.gucs
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/profiles/runtime-task-budgets/embedded-postmaster-v1.tsv b/src/runtimes/liboliphaunt-wasix-postmaster/profiles/runtime-task-budgets/embedded-postmaster-v1.tsv
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/profiles/runtime-task-budgets/embedded-postmaster-v1.tsv
rename to src/runtimes/liboliphaunt-wasix-postmaster/profiles/runtime-task-budgets/embedded-postmaster-v1.tsv
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/release.toml b/src/runtimes/liboliphaunt-wasix-postmaster/release.toml
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/release.toml
rename to src/runtimes/liboliphaunt-wasix-postmaster/release.toml
diff --git a/src/sources/third-party/wasix-postmaster/wasix-libc.toml b/src/runtimes/liboliphaunt-wasix-postmaster/sources/wasix-libc.toml
similarity index 100%
rename from src/sources/third-party/wasix-postmaster/wasix-libc.toml
rename to src/runtimes/liboliphaunt-wasix-postmaster/sources/wasix-libc.toml
diff --git a/src/sources/third-party/wasix-postmaster/wasmer-napi.toml b/src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer-napi.toml
similarity index 100%
rename from src/sources/third-party/wasix-postmaster/wasmer-napi.toml
rename to src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer-napi.toml
diff --git a/src/sources/third-party/wasix-postmaster/wasmer-test-files.toml b/src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer-test-files.toml
similarity index 100%
rename from src/sources/third-party/wasix-postmaster/wasmer-test-files.toml
rename to src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer-test-files.toml
diff --git a/src/sources/third-party/wasix-postmaster/wasmer.toml b/src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer.toml
similarity index 100%
rename from src/sources/third-party/wasix-postmaster/wasmer.toml
rename to src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer.toml
diff --git a/src/sources/third-party/wasix-postmaster/webassembly-testsuite.toml b/src/runtimes/liboliphaunt-wasix-postmaster/sources/webassembly-testsuite.toml
similarity index 100%
rename from src/sources/third-party/wasix-postmaster/webassembly-testsuite.toml
rename to src/runtimes/liboliphaunt-wasix-postmaster/sources/webassembly-testsuite.toml
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/testdata/check-carrier-receipts.mts b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/check-carrier-receipts.mts
new file mode 100644
index 000000000..a3aad97cf
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/check-carrier-receipts.mts
@@ -0,0 +1,135 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { mkdtempSync, readFileSync, writeFileSync, rmSync, existsSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import {
+  guestReceipt,
+  executorReceipt,
+  verifyInventory,
+  carrierTree,
+  hashRegular,
+} from '../lib/verify-sealed-carrier.mts';
+import { sha256 } from '../lib/sealed-export-chain.mts';
+const [root, input, field] = process.argv.slice(2);
+if (root.startsWith('--')) {
+  if (root === '--field') console.log(JSON.parse(readFileSync(input, 'utf8'))[field]);
+  else if (root === '--patch-manifest')
+    writeFileSync(
+      input,
+      JSON.stringify({
+        ...JSON.parse(readFileSync(input, 'utf8')),
+        ...JSON.parse(await Bun.stdin.text()),
+      }) + '\n',
+    );
+  else if (root === '--reindex') {
+    const rows = [...carrierTree(input)]
+      .filter(([path, info]) => path !== 'payload.files' && info.isFile())
+      .sort(([a], [b]) => (a < b ? -1 : 1))
+      .map(([path]) => {
+        const { size, sha256 } = hashRegular(join(input, path));
+        return sha256 + '\t' + size + '\t' + path;
+      });
+    writeFileSync(
+      join(input, 'payload.files'),
+      ['schema=oliphaunt.wasix-postmaster.payload-files.v1', ...rows, ''].join('\n'),
+    );
+  } else if (root === '--validation-log') {
+    const records = readFileSync(input, 'utf8')
+      .trimEnd()
+      .split('\n')
+      .map((line) => JSON.parse(line));
+    assert.deepEqual(
+      records.map((row) => row.program),
+      ['postgres', 'initdb'],
+    );
+    assert.deepEqual(records[0].arguments, ['--version']);
+    assert.deepEqual(records[1].arguments, [
+      '-D',
+      '/pgdata',
+      '-A',
+      'trust',
+      '--no-locale',
+      '--encoding=UTF8',
+      '--no-instructions',
+    ]);
+    for (const record of records) {
+      const volumes = new Map();
+      for (const volume of record.volumes) {
+        const colon = volume.lastIndexOf(':'),
+          host = volume.slice(0, colon),
+          guest = volume.slice(colon + 1);
+        assert(!volumes.has(guest));
+        volumes.set(guest, host);
+      }
+      const carrier = [...volumes].find(([guest, host]) => guest === host)![1];
+      assert.equal(volumes.get('/lib'), join(carrier, 'lib'));
+      assert.equal(volumes.get('/share'), join(carrier, 'share'));
+      for (const guest of ['/pgdata', '/dev/shm']) assert(!existsSync(volumes.get(guest)!));
+    }
+  } else assert.fail('unknown carrier fixture operation');
+  process.exit(0);
+}
+assert(root, 'carrier root is required');
+const inventory = verifyInventory(root);
+const wasmer = Object.fromEntries(
+  readFileSync(join(root, 'wasmer-build.receipt'), 'utf8')
+    .trimEnd()
+    .split('\n')
+    .map((line) => line.split('=')),
+);
+const directory = mkdtempSync(join(tmpdir(), 'carrier-receipt-checks-'));
+try {
+  for (const [path, mutations, parse] of [
+    [
+      'guest-build.receipt',
+      {
+        schema: 'oliphaunt.wasix-postmaster.guest-build.v4',
+        docker_image_id: 'sha256:mutable',
+        atomic_fence_total: '01',
+        atomic_fence_set_latch: '1',
+        latch_state_contract: 'none',
+        linear_memory_profile_id: 'unbounded',
+      },
+      (root: string) => guestReceipt(root, inventory),
+    ],
+    [
+      'postmaster-executor.receipt',
+      {
+        schema: 'oliphaunt.wasix-postmaster.postmaster-executor-build.v2',
+        start_proof_binary: 'another-tool',
+        start_proof_features: '',
+        start_proof_policy: 'unrestricted',
+        start_proof_binary_sha256: 'not-a-digest',
+        memory_profile_binary: 'another-tool',
+        memory_profile_features: '',
+        linear_memory_profile_id: 'unbounded',
+        memory_profile_binary_sha256: 'not-a-digest',
+        postmaster_compiler_binary: 'another-tool',
+        postmaster_compiler_features: '',
+        compiler_cpu_policy: 'host-native',
+        compiler_cpu_features: 'avx2',
+        postmaster_compiler_binary_sha256: 'not-a-digest',
+      },
+      (root: string) => executorReceipt(root, inventory, wasmer),
+    ],
+  ] as const) {
+    const lines = readFileSync(join(root, path), 'utf8').trimEnd().split('\n');
+    function check(candidate: string[], valid = false) {
+      const bytes = Buffer.from(`${candidate.join('\n')}\n`);
+      writeFileSync(join(directory, path), bytes);
+      inventory.set(path, { size: bytes.length, sha256: sha256(bytes) });
+      if (valid) parse(directory);
+      else assert.throws(() => parse(directory));
+    }
+    check(lines, true);
+    for (const [key, value] of Object.entries(mutations))
+      check(lines.map((line) => (line.startsWith(`${key}=`) ? `${key}=${value}` : line)));
+    check(lines.slice(1));
+    check([...lines].reverse());
+    check([...lines, lines[0]]);
+  }
+  console.log('carrier receipts reject weakened provenance and ambiguous fields');
+} finally {
+  rmSync(directory, { recursive: true, force: true });
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/testdata/crash-durable-publication.mts b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/crash-durable-publication.mts
new file mode 100644
index 000000000..cd8c9a6b7
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/crash-durable-publication.mts
@@ -0,0 +1,29 @@
+#!/usr/bin/env bun
+import * as fs from 'node:fs';
+import { spyOn } from 'bun:test';
+import { run } from '../lib/durable-publication.mts';
+const [point, source, destination] = process.argv.slice(2);
+const sync = fs.fsyncSync,
+  link = fs.linkSync,
+  unlink = fs.unlinkSync;
+const crash = () => process.kill(process.pid, 'SIGKILL');
+let syncs = 0;
+spyOn(fs, 'fsyncSync').mockImplementation((fd) => {
+  sync(fd);
+  if (
+    ['source-fsync', 'destination-fsync', 'commit-directory-fsync', 'cleanup-directory-fsync'][
+      syncs++
+    ] === point
+  )
+    crash();
+});
+spyOn(fs, 'linkSync').mockImplementation((source, destination) => {
+  link(source, destination);
+  if (point === 'link') crash();
+});
+spyOn(fs, 'unlinkSync').mockImplementation((path) => {
+  unlink(path);
+  if (point === 'source-unlink') crash();
+});
+await run(['publish', source, destination]);
+throw Error('publication did not hit the requested crash point');
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/testdata/fake-postmaster-compiler.mts b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/fake-postmaster-compiler.mts
new file mode 100755
index 000000000..d6a041878
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/fake-postmaster-compiler.mts
@@ -0,0 +1,30 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { readFileSync, writeFileSync } from 'node:fs';
+const args = process.argv.slice(2);
+if (args.length === 1 && args[0] === '--version') {
+  console.log(
+    'oliphaunt-wasix-postmaster-compiler fixture oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1',
+  );
+} else {
+  const verify = args[0] === 'verify-aot';
+  const input = verify ? args[1] : args.at(-1);
+  const outputIndex = args.indexOf('-o');
+  assert(
+    verify ? args.length === 3 : outputIndex >= 0 && args[outputIndex + 1],
+    'compiler requires -o OUTPUT MODULE',
+  );
+  const digest = createHash('sha256').update(readFileSync(input!)).digest();
+  const expected = Buffer.concat([Buffer.from('fake-product-aot\0'), digest]);
+  if (verify) {
+    assert.deepEqual(readFileSync(args[2]), expected, 'fake product AOT identity differs');
+    console.log(digest.toString('hex'));
+  } else {
+    assert(
+      ['--llvm', '--enable-exceptions', '--enable-threads'].every((flag) => args.includes(flag)),
+      'compiler requires LLVM, exceptions, and threads',
+    );
+    writeFileSync(args[outputIndex + 1], expected);
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/testdata/fake-sealed-wasmer.mts b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/fake-sealed-wasmer.mts
new file mode 100755
index 000000000..2e1eadc17
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/fake-sealed-wasmer.mts
@@ -0,0 +1,120 @@
+#!/usr/bin/env bun
+// Exercises carrier argument validation and failure cleanup without executing Wasm.
+import assert from 'node:assert/strict';
+import {
+  accessSync,
+  appendFileSync,
+  constants,
+  mkdirSync,
+  readFileSync,
+  realpathSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import { basename, dirname, join, relative } from 'node:path';
+const args = process.argv.slice(2);
+if (args[0] === 'run') {
+  const values = new Map();
+  const flags = new Set();
+  const volumes: string[] = [];
+  const valueOptions = ['--stack-size', '--sealed-module-manifest'];
+  const flagOptions = [
+    '--disable-cache',
+    '--enable-exceptions',
+    '--enable-threads',
+    '--net',
+    '--quiet',
+  ];
+  let modulePath = '';
+  let guestArgs: string[] = [];
+  for (let i = 1; i < args.length; i++) {
+    const arg = args[i];
+    if (arg === '--') {
+      guestArgs = args.slice(i + 1);
+      break;
+    }
+    if (arg === '--volume' || valueOptions.includes(arg)) {
+      assert(args[i + 1], `${arg} has no value`);
+      if (arg === '--volume') volumes.push(args[++i]);
+      else {
+        assert(!values.has(arg), `duplicate option ${arg}`);
+        values.set(arg, args[++i]);
+      }
+    } else if (flagOptions.includes(arg)) {
+      assert(!flags.has(arg), `duplicate option ${arg}`);
+      flags.add(arg);
+    } else {
+      assert(!arg.startsWith('-') && !modulePath, `unknown argument ${arg}`);
+      modulePath = arg;
+    }
+  }
+  assert(
+    modulePath && flagOptions.slice(0, 4).every((flag) => flags.has(flag)),
+    'run lacks module or required flags',
+  );
+  const manifestPath = values.get('--sealed-module-manifest');
+  assert(manifestPath, 'run did not receive a sealed manifest');
+  const root = dirname(realpathSync(manifestPath));
+  const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
+  assert(
+    manifest['format-version'] === 6 &&
+      manifest.schema === 'oliphaunt.wasix-postmaster.sealed-aot.v5',
+    'expected final manifest',
+  );
+  assert(
+    manifest.artifacts.every((artifact: object) => !('preinitialized-memory' in artifact)),
+    'final artifact has a memory image',
+  );
+  function volume(guest: string) {
+    const matches = volumes.filter((value) => value.slice(value.lastIndexOf(':') + 1) === guest);
+    assert(matches.length === 1, `expected one volume at ${guest}`);
+    return matches[0].slice(0, matches[0].lastIndexOf(':'));
+  }
+  for (const [guest, host] of [
+    ['/lib', join(root, 'lib')],
+    ['/share', join(root, 'share')],
+    [root, root],
+  ]) {
+    assert.equal(volume(guest), host, `incorrect mount at ${guest}`);
+  }
+  const program = basename(modulePath);
+  assert.equal(
+    realpathSync(modulePath),
+    join(root, 'bin', program),
+    'module is outside staged carrier',
+  );
+  if (process.env.FAKE_WASMER_VALIDATION_LOG) {
+    appendFileSync(
+      process.env.FAKE_WASMER_VALIDATION_LOG,
+      `${JSON.stringify({ program, arguments: guestArgs, volumes })}\n`,
+    );
+  }
+  if (program === 'postgres') assert.deepEqual(guestArgs, ['--version']);
+  else {
+    assert.equal(program, 'initdb');
+    assert.deepEqual(guestArgs, [
+      '-D',
+      '/pgdata',
+      '-A',
+      'trust',
+      '--no-locale',
+      '--encoding=UTF8',
+      '--no-instructions',
+    ]);
+    const data = realpathSync(volume('/pgdata'));
+    for (const dir of [data, realpathSync(volume('/dev/shm'))]) {
+      assert(statSync(dir).isDirectory());
+      accessSync(dir, constants.W_OK);
+      assert(relative(root, dir).startsWith('../'), 'writable directory overlaps staged carrier');
+    }
+    assert(
+      process.env.FAKE_WASMER_FAIL_FINAL_INITDB !== '1',
+      'requested final initdb lifecycle failure',
+    );
+    if (process.env.FAKE_WASMER_SKIP_INITDB_OUTPUT !== '1') {
+      mkdirSync(join(data, 'global'));
+      writeFileSync(join(data, 'PG_VERSION'), '18\n');
+      writeFileSync(join(data, 'global/pg_control'), 'fake-pg-control\n');
+    }
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/testdata/fake-start-proof.mts b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/fake-start-proof.mts
new file mode 100755
index 000000000..cd579839f
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/fake-start-proof.mts
@@ -0,0 +1,39 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { lstatSync, readFileSync } from 'node:fs';
+const policy = 'llvm-shared-memory-init-restricted-effects.v1';
+const args = process.argv.slice(2);
+const hash = (data: string | Buffer) => createHash('sha256').update(data).digest('hex');
+if (args.length === 1 && args[0] === '--policy-id') {
+  console.log(policy);
+} else {
+  assert(args.length === 1 && lstatSync(args[0]).isFile(), 'expected a regular module');
+  const digest =
+    process.env.FAKE_START_PROOF_WRONG_MODULE === '1'
+      ? 'ff'.repeat(32)
+      : hash(readFileSync(args[0]));
+  console.log(
+    JSON.stringify(
+      {
+        schema: 'oliphaunt.wasix-postmaster.deterministic-start-proof.v1',
+        'analyzer-policy': policy,
+        'module-sha256': digest,
+        'proof-sha256': hash(`${policy}\0${digest}\0fake-restricted-start-closure`),
+        'start-function-index': 147,
+        'start-function-export': '__wasm_init_memory',
+        'transitive-function-indices': [147, 148],
+        'imported-function-calls': process.env.FAKE_START_PROOF_INVALID === '1' ? 1 : 0,
+        'memory-reads': 'fresh-zero-atomic-guard-only',
+        'memory-effects': 'passive-data-init-zero-fill-atomic-guard-only',
+        'global-effects': 'local-numeric-relocations-only',
+        'table-effects': 'none',
+        'requires-fresh-zeroed-memory': true,
+        'ordinary-start-execution-per-instance': true,
+        'first-instance-full-byte-validation': true,
+      },
+      null,
+      2,
+    ),
+  );
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/testdata/make-sealed-export-fixture.mts b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/make-sealed-export-fixture.mts
new file mode 100644
index 000000000..366ef2a41
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/make-sealed-export-fixture.mts
@@ -0,0 +1,212 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { requiredModules } from '../lib/guest-build-provenance.mts';
+import { profile, profileId, closureHash } from '../lib/linear-memory-profile.mts';
+import { AGGREGATE_RELATIVE } from '../lib/receipt-files.mts';
+import { createHash } from 'node:crypto';
+import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
+import { dirname, join } from 'node:path';
+import { parseArgs } from 'node:util';
+export const digest = (data: Buffer | string) => createHash('sha256').update(data).digest('hex');
+function canonical(value: unknown): unknown {
+  if (Array.isArray(value)) return value.map(canonical);
+  if (value && typeof value === 'object')
+    return Object.fromEntries(
+      Object.entries(value)
+        .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
+        .map(([key, item]) => [key, canonical(item)]),
+    );
+  return value;
+}
+export const jsonBytes = (value: object) =>
+  Buffer.from(`${JSON.stringify(canonical(value), null, 2)}\n`);
+function uleb(value: number) {
+  const bytes: number[] = [];
+  do {
+    const byte = value & 127;
+    value >>>= 7;
+    bytes.push(byte | (value ? 128 : 0));
+  } while (value);
+  return Buffer.from(bytes);
+}
+export function summary(path: string, sha256: string, bytes: number) {
+  return {
+    path,
+    sha256,
+    bytes,
+    'non-export-sections-sha256': digest(`sections:${path}`),
+    'dylink-needed': [],
+    'imported-functions': 0,
+    'local-functions': 1,
+    'imported-globals': 0,
+    'local-globals': 0,
+    'imported-tables': 0,
+    'local-tables': 1,
+    'element-function-entries': 1,
+    'element-unique-function-indices': 1,
+    'element-max-function-index': 0,
+    'start-function-index': 0,
+    imports: [],
+    'export-counts': {},
+    'exported-global-type-counts': {},
+    'exported-immutable-i32-globals': 0,
+    'exported-local-functions': 0,
+    'exported-imported-functions': 0,
+  };
+}
+export function proof(
+  main: ReturnType,
+  sides: ReturnType[],
+  mandatory: string,
+  dlsym: string,
+) {
+  return {
+    schema: 'oliphaunt.wasix-postmaster.sealed-export-closure-proof.v2',
+    'policy-id': 'oliphaunt.wasix-postmaster.sealed-export-closure.v1',
+    'analyzer-version': 'fixture',
+    'mandatory-policy-sha256': mandatory,
+    'declared-main-dlsym-policy-sha256': dlsym,
+    main,
+    sides,
+    'mandatory-runtime-exports': [],
+    'declared-main-dlsym-exports': [],
+    'side-dynamic-imports': [],
+    'retained-main-exports': [],
+    'retained-main-export-descriptors': [],
+    'removed-main-export-count': 1,
+    'removed-main-export-names-sha256': digest('fixture-removed'),
+    'unresolved-main-requirements': [],
+    'mismatched-main-requirements': [],
+    'unresolved-side-dependencies': [],
+    'retained-counts': {},
+    'removed-counts': { function: 1 },
+  };
+}
+export function snapshot(sha256: string, bytes: number) {
+  return {
+    sha256,
+    bytes,
+    exports: 0,
+    'local-functions': 1,
+    'local-globals': 0,
+    'element-function-entries': 1,
+    'element-unique-function-indices': 1,
+    'start-function-index': 0,
+  };
+}
+export function makeSealedExportFixture(root: string, projectRoot: string) {
+  const policyRoot = join(projectRoot, 'wasmer/policies');
+  const sideManifest = readFileSync(join(policyRoot, 'sealed-side-modules.v1.tsv'));
+  const sidePaths = sideManifest
+    .toString('utf8')
+    .split('\n')
+    .filter((line) => line && !line.startsWith('#'))
+    .map((line) => line.split('\t')[0]);
+  const template = readFileSync(join(root, 'lib/libpq.so.5.18'));
+  for (const relative of sidePaths) {
+    const file = join(root, relative);
+    mkdirSync(dirname(file), { recursive: true });
+    if (!existsSync(file)) {
+      const name = Buffer.from('oliphaunt.fixture'),
+        payload = Buffer.concat([uleb(name.length), name, Buffer.from(relative)]);
+      writeFileSync(
+        file,
+        Buffer.concat([template, Buffer.from([0]), uleb(payload.length), payload]),
+      );
+    }
+  }
+  const mandatory = digest(readFileSync(join(policyRoot, 'sealed-main-runtime-exports.v1.txt'))),
+    dlsym = digest(readFileSync(join(policyRoot, 'sealed-main-dlsym-exports.v1.txt')));
+  const sides = sidePaths.map((path) =>
+    summary(path, digest(readFileSync(join(root, path))), statSync(join(root, path)).size),
+  );
+  const postgres = readFileSync(join(root, 'bin/postgres')),
+    seedHash = digest(Buffer.concat([Buffer.from('pre-dce-fixture\0'), postgres]));
+  const seedProof = jsonBytes(
+      proof(summary('bin/postgres', seedHash, postgres.length + 16), sides, mandatory, dlsym),
+    ),
+    finalProof = jsonBytes(
+      proof(summary('bin/postgres', digest(postgres), postgres.length), sides, mandatory, dlsym),
+    );
+  const share = join(root, 'share/postgresql');
+  mkdirSync(share, { recursive: true });
+  for (const [name, data] of [
+    ['seed-proof.json', seedProof],
+    ['final-proof.json', finalProof],
+    ['allowlist', Buffer.from('fixture-export\n')],
+  ] as const)
+    writeFileSync(join(share, `wasix-postmaster.sealed-export.${name}`), data);
+  writeFileSync(
+    join(share, 'wasix-postmaster.sealed-export.structure.receipt'),
+    jsonBytes({
+      schema: 'oliphaunt.wasix-postmaster.sealed-export-structure.v1',
+      'policy-id': 'oliphaunt.wasix-postmaster.sealed-export-closure.v1',
+      'analyzer-version': 'fixture',
+      'analyzer-binary-sha256': '0'.repeat(64),
+      'dce-tool-sha256': '1'.repeat(64),
+      'dce-tool-version': 'fixture-wasm-opt',
+      'dce-passes': ['--remove-unused-module-elements'],
+      'mandatory-policy-sha256': mandatory,
+      'declared-main-dlsym-policy-sha256': dlsym,
+      'side-manifest-sha256': digest(sideManifest),
+      'allowlist-sha256': digest('fixture-export\n'),
+      'seed-proof-sha256': digest(seedProof),
+      'final-proof-sha256': digest(finalProof),
+      seed: snapshot(seedHash, postgres.length + 16),
+      'final-module': snapshot(digest(postgres), postgres.length),
+      sides: sides.map(({ path, sha256 }) => ({ path, sha256 })),
+    }),
+  );
+}
+
+export function makeLinearMemoryFixture(root: string, descendant = false) {
+  const predecessor = 'share/postgresql/wasix-postmaster.sealed-export.structure.receipt';
+  // The full install includes client tools that the runtime carrier omits.
+  writeFileSync(join(root, 'bin/pg_config'), readFileSync(join(root, 'bin/initdb')));
+  const modules = ['bin/pg_config', ...requiredModules].sort().map((path) => {
+    const source = readFileSync(join(root, path)),
+      hash = digest(source);
+    const sealed = descendant ? Buffer.concat([source, Buffer.from([0, 1, 0])]) : source;
+    if (descendant) writeFileSync(join(root, path), sealed);
+    return {
+      path,
+      'source-module-sha256': hash,
+      'module-sha256': digest(sealed),
+      'initial-pages': 1,
+      'maximum-pages': 4096,
+      'maximum-bytes': 268435456,
+      shared: true,
+      'import-module': 'env',
+      'import-name': 'memory',
+      transformation: 'pinned-wasixcc-65536-to-embedded-4096-reversible-v1',
+    };
+  });
+  const receipt = {
+    schema: 'oliphaunt.wasix-postmaster.linear-memory-install.v1',
+    'profile-id': profileId,
+    ...profile,
+    'predecessor-export-closure-receipt': predecessor,
+    'predecessor-export-closure-receipt-sha256': digest(readFileSync(join(root, predecessor))),
+    'source-module-closure-sha256': closureHash(modules, 'source-module-sha256'),
+    'module-closure-sha256': closureHash(modules, 'module-sha256'),
+    'module-count': modules.length,
+    modules,
+  };
+  writeFileSync(join(root, AGGREGATE_RELATIVE), jsonBytes(receipt), { flag: 'wx' });
+  return receipt;
+}
+
+if (import.meta.main) {
+  const { values } = parseArgs({
+    options: {
+      'install-root': { type: 'string' },
+      'project-root': { type: 'string' },
+      'linear-memory': { type: 'boolean' },
+      'linear-memory-descendant': { type: 'boolean' },
+    },
+  });
+  assert(values['install-root'] && values['project-root']);
+  if (values['linear-memory'] || values['linear-memory-descendant'])
+    makeLinearMemoryFixture(values['install-root'], values['linear-memory-descendant']);
+  else makeSealedExportFixture(values['install-root'], values['project-root']);
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/testdata/minimal-postmaster.mts b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/minimal-postmaster.mts
new file mode 100644
index 000000000..f926a8479
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/testdata/minimal-postmaster.mts
@@ -0,0 +1,46 @@
+import { writeFileSync } from 'node:fs';
+const bytes = (...values: (number | Uint8Array)[]) =>
+  Buffer.concat(
+    values.map((value) => (typeof value === 'number' ? Buffer.from([value]) : Buffer.from(value))),
+  );
+const leb = (value: number): Buffer =>
+  value < 128 ? bytes(value) : bytes((value & 127) | 128, leb(Math.floor(value / 128)));
+const name = (value: string) => bytes(leb(Buffer.byteLength(value)), Buffer.from(value));
+const vector = (rows: Uint8Array[]) => bytes(leb(rows.length), ...rows);
+const section = (id: number, data: Uint8Array) => bytes(id, leb(data.length), data);
+export function minimalPostmaster(shared = true, lookalike = false, extraFences = 0) {
+  const entries = [
+    ['SetLatch', 2],
+    ['ResetLatch', 1],
+    ['WaitEventSetWait', 1],
+  ] as const;
+  const bodies = entries.map(([, count]) =>
+    bytes(0, ...Array.from({ length: count }, () => bytes(254, 3, 0)), 11),
+  );
+  bodies.push(
+    bytes(
+      0,
+      ...Array.from({ length: extraFences }, () => bytes(254, 3, 0)),
+      ...(lookalike ? [bytes(0x41, 0xfe, 3, 0)] : []),
+      11,
+    ),
+  );
+  return bytes(
+    Buffer.from('0061736d01000000', 'hex'),
+    section(1, vector([bytes(0x60, 4, 0x7f, 0x7e, 0x7e, 0x7f, 1, 0x7f), bytes(0x60, 0, 0)])),
+    section(
+      2,
+      vector([
+        bytes(name('oliphaunt_postmaster_v1'), name('fd_sync_range'), 0, 0),
+        bytes(name('env'), name('memory'), 2, shared ? 3 : 1, 1, 2),
+      ]),
+    ),
+    section(3, vector(bodies.map(() => bytes(1)))),
+    section(7, vector(entries.map(([key], index) => bytes(name(key), 0, leb(index + 1))))),
+    section(10, vector(bodies.map((body) => bytes(leb(body.length), body)))),
+  );
+}
+if (import.meta.main) {
+  if (process.argv.length !== 3) throw new Error('usage: minimal-postmaster.mts OUTPUT');
+  writeFileSync(process.argv[2]!, minimalPostmaster(true, false, 3));
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/tools/merge-product-release-assets.mts b/src/runtimes/liboliphaunt-wasix-postmaster/tools/merge-product-release-assets.mts
new file mode 100644
index 000000000..a06ac5336
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/tools/merge-product-release-assets.mts
@@ -0,0 +1,153 @@
+#!/usr/bin/env bun
+
+import { createHash, randomUUID } from 'node:crypto';
+import {
+  chmodSync,
+  createReadStream,
+  linkSync,
+  lstatSync,
+  readdirSync,
+  readFileSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+
+import {
+  compareText,
+  expectedAssetRows,
+} from '../../../../tools/release/release-artifact-targets.mts';
+
+const TOOL = 'merge-product-release-assets.mts';
+
+function fail(message) {
+  throw new Error(`${TOOL}: ${message}`);
+}
+
+function parseOptions(argv) {
+  const options = {};
+  for (let index = 0; index < argv.length; index += 1) {
+    const flag = argv[index];
+    if (!['--asset-dir', '--product', '--version'].includes(flag) || index + 1 >= argv.length) {
+      fail(`usage: ${TOOL} --product PRODUCT --version VERSION --asset-dir DIR`);
+    }
+    const field = flag.slice(2).replace('-', '_');
+    if (options[field] !== undefined) {
+      fail(`${flag} may only be provided once`);
+    }
+    options[field] = argv[index + 1];
+    index += 1;
+  }
+  for (const field of ['asset_dir', 'product', 'version']) {
+    if (typeof options[field] !== 'string' || options[field].length === 0) {
+      fail(`--${field.replace('_', '-')} is required`);
+    }
+  }
+  return options;
+}
+
+async function sha256File(file) {
+  const hash = createHash('sha256');
+  for await (const chunk of createReadStream(file)) {
+    hash.update(chunk);
+  }
+  return hash.digest('hex');
+}
+
+function exactRegularFiles(directory) {
+  const directoryEntry = lstatSync(directory);
+  if (!directoryEntry.isDirectory() || directoryEntry.isSymbolicLink()) {
+    fail(`asset directory must be a regular directory: ${directory}`);
+  }
+  return readdirSync(directory)
+    .map((name) => {
+      const file = path.join(directory, name);
+      const entry = lstatSync(file);
+      if (!entry.isFile() || entry.isSymbolicLink()) {
+        fail(`asset directory contains a non-regular entry: ${file}`);
+      }
+      return name;
+    })
+    .sort(compareText);
+}
+
+function canonicalAssetNames(rows, product) {
+  const names = rows.map(({ assetName }) => assetName);
+  for (const name of names) {
+    if (
+      typeof name !== 'string' ||
+      name.length === 0 ||
+      name === '.' ||
+      name === '..' ||
+      name.includes('/') ||
+      name.includes('\\') ||
+      path.basename(name) !== name
+    ) {
+      fail(`${product} declares a non-canonical release asset name: ${JSON.stringify(name)}`);
+    }
+  }
+  if (new Set(names).size !== names.length) {
+    fail(`${product} declares duplicate release asset names`);
+  }
+}
+
+export async function mergeProductReleaseAssets({ assetDir, product, version }) {
+  const directory = path.resolve(assetDir);
+  const expected = expectedAssetRows({ product, version }, TOOL);
+  canonicalAssetNames(expected, product);
+  const checksumRows = expected.filter(({ kind }) => kind === 'checksums');
+  if (checksumRows.length !== 1) {
+    fail(`${product} must declare exactly one checksum release asset`);
+  }
+  const checksumName = checksumRows[0].assetName;
+  const payloadNames = expected
+    .filter(({ assetName }) => assetName !== checksumName)
+    .map(({ assetName }) => assetName)
+    .sort(compareText);
+  const actualNames = exactRegularFiles(directory);
+  if (
+    JSON.stringify(actualNames.filter((name) => name !== checksumName)) !==
+    JSON.stringify(payloadNames)
+  ) {
+    fail(
+      `${product} release payload set differs: expected=${JSON.stringify(payloadNames)}, actual=${JSON.stringify(actualNames)}`,
+    );
+  }
+
+  const checksum = path.join(directory, checksumName);
+  const temporary = path.join(directory, `.${checksumName}.tmp-${randomUUID()}`);
+  const lines = [];
+  for (const name of payloadNames) {
+    lines.push(`${await sha256File(path.join(directory, name))}  ./${name}`);
+  }
+  const contents = `${lines.join('\n')}\n`;
+  if (actualNames.includes(checksumName)) {
+    if (readFileSync(checksum, 'utf8') !== contents) {
+      fail(`${product} existing checksum differs from release payloads`);
+    }
+    chmodSync(checksum, 0o444);
+    return checksum;
+  }
+  try {
+    writeFileSync(temporary, contents, {
+      encoding: 'utf8',
+      flag: 'wx',
+      mode: 0o444,
+    });
+    linkSync(temporary, checksum);
+  } finally {
+    rmSync(temporary, { force: true });
+  }
+  chmodSync(checksum, 0o444);
+  return checksum;
+}
+
+if (import.meta.main) {
+  const options = parseOptions(Bun.argv.slice(2));
+  const checksum = await mergeProductReleaseAssets({
+    assetDir: options.asset_dir,
+    product: options.product,
+    version: options.version,
+  });
+  console.log(`merged ${options.product} release assets: ${checksum}`);
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/tools/merge-product-release-assets.test.mts b/src/runtimes/liboliphaunt-wasix-postmaster/tools/merge-product-release-assets.test.mts
new file mode 100644
index 000000000..c7f54645b
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/tools/merge-product-release-assets.test.mts
@@ -0,0 +1,87 @@
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { test } from 'node:test';
+import { expectedAssetRows } from '../../../../tools/release/release-artifact-targets.mts';
+import { mergeProductReleaseAssets } from './merge-product-release-assets.mts';
+
+function sha256(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function fixture() {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-postmaster-release-assets-'));
+  const product = 'liboliphaunt-wasix-postmaster';
+  const version = '0.0.0';
+  const rows = expectedAssetRows({ product, version }, 'merge-product-release-assets.test.mts');
+  const checksumName = rows.find(({ kind }) => kind === 'checksums').assetName;
+  const payloadRows = rows.filter(({ assetName }) => assetName !== checksumName);
+  return { root, assetDir: root, product, version, checksumName, payloadRows };
+}
+
+function writePayloads(root, rows) {
+  for (const row of rows) {
+    writeFileSync(path.join(root, row.assetName), `${row.target}\n`, 'utf8');
+  }
+}
+
+function cleanup(root) {
+  chmodSync(root, 0o755);
+  rmSync(root, { recursive: true, force: true });
+}
+
+test('postmaster aggregation is repeatable and rejects changes to finalized payloads', async () => {
+  const { root, product, version, checksumName, payloadRows } = fixture();
+  try {
+    writePayloads(root, payloadRows);
+
+    const checksum = await mergeProductReleaseAssets({ assetDir: root, product, version });
+    assert.equal(path.basename(checksum), checksumName);
+    assert.equal(
+      readFileSync(checksum, 'utf8'),
+      `${payloadRows
+        .map(({ assetName, target }) => `${sha256(`${target}\n`)}  ./${assetName}`)
+        .join('\n')}\n`,
+    );
+    assert.equal(await mergeProductReleaseAssets({ assetDir: root, product, version }), checksum);
+    writeFileSync(path.join(root, payloadRows[0].assetName), 'changed payload\n');
+    await assert.rejects(
+      mergeProductReleaseAssets({ assetDir: root, product, version }),
+      /existing checksum differs/u,
+    );
+  } finally {
+    cleanup(root);
+  }
+});
+
+test('postmaster aggregation rejects missing and extra payloads', async () => {
+  const missing = fixture();
+  const extra = fixture();
+  try {
+    writePayloads(missing.root, missing.payloadRows.slice(1));
+    await assert.rejects(mergeProductReleaseAssets(missing), /release payload set differs/u);
+
+    writePayloads(extra.root, extra.payloadRows);
+    writeFileSync(path.join(extra.root, 'unexpected.tar.zst'), 'unexpected\n', 'utf8');
+    await assert.rejects(mergeProductReleaseAssets(extra), /release payload set differs/u);
+  } finally {
+    cleanup(missing.root);
+    cleanup(extra.root);
+  }
+});
+
+test('postmaster aggregation rejects non-regular entries', async () => {
+  const release = fixture();
+  try {
+    writePayloads(release.root, release.payloadRows);
+    mkdirSync(path.join(release.root, 'nested'));
+    await assert.rejects(
+      mergeProductReleaseAssets(release),
+      /asset directory contains a non-regular entry/u,
+    );
+  } finally {
+    cleanup(release.root);
+  }
+});
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/tools/sealed-export-closure/Cargo.lock b/src/runtimes/liboliphaunt-wasix-postmaster/tools/sealed-export-closure/Cargo.lock
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/tools/sealed-export-closure/Cargo.lock
rename to src/runtimes/liboliphaunt-wasix-postmaster/tools/sealed-export-closure/Cargo.lock
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/tools/sealed-export-closure/Cargo.toml b/src/runtimes/liboliphaunt-wasix-postmaster/tools/sealed-export-closure/Cargo.toml
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/tools/sealed-export-closure/Cargo.toml
rename to src/runtimes/liboliphaunt-wasix-postmaster/tools/sealed-export-closure/Cargo.toml
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/tools/sealed-export-closure/src/main.rs b/src/runtimes/liboliphaunt-wasix-postmaster/tools/sealed-export-closure/src/main.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/tools/sealed-export-closure/src/main.rs
rename to src/runtimes/liboliphaunt-wasix-postmaster/tools/sealed-export-closure/src/main.rs
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/README.md b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/README.md
new file mode 100644
index 000000000..94a5a07ed
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/README.md
@@ -0,0 +1,44 @@
+# Patched WASIX postmaster runtime
+
+This subtree builds the host runtime for
+`liboliphaunt-wasix-postmaster`. Repository-pinned Wasmer and wasix-libc inputs
+are copied into disposable worktrees, patched, tested, and built into a
+compiler-bearing producer plus a compiler-free product executor.
+
+Tracked product inputs are:
+
+- `patches/wasmer/0001-postgres-wasix-blockers.patch`;
+- `patches/wasix-libc/0001-postgres-wasix-blockers.patch`;
+- the current contract inventory in `capabilities.tsv`;
+- focused capability fixtures under `probes/`;
+- preparation, build, verification, and qualification entrypoints under `bin/`.
+
+Immutable upstream checkouts live under
+`target/oliphaunt-sources/checkouts/`. Patched worktrees, sysroots, build
+outputs, caches, and reports live under
+`target/oliphaunt-wasix-postmaster/runtime/` and are never patched into the
+source checkout.
+
+`build-runtime.sh` produces a Wasmer build receipt and a separate product
+executor receipt. Together they bind source pins, patch digests, prepared-tree
+identities, Cargo.lock, sysroot manifests, compiler/executor features, host ABI,
+Rust and LLVM versions, artifact ABI, runtime ABI, CPU policy, and binary
+hashes. Runtime selection never falls back to a stock or `PATH` Wasmer.
+
+The product executor accepts only an independently verified sealed carrier. It
+does not expose the general Wasmer package, registry, network, or compilation
+command graph. AOT production uses an explicit generic CPU baseline; native CPU
+tuning is rejected for release carriers.
+
+From the repository root:
+
+```sh
+moon run source-inputs:source-fetch-wasix-postmaster-runtime
+moon run liboliphaunt-wasix-postmaster:prepare-runtime
+moon run liboliphaunt-wasix-postmaster:runtime-build
+moon run liboliphaunt-wasix-postmaster:runtime-patch-tests
+moon run liboliphaunt-wasix-postmaster:runtime-capabilities
+```
+
+The architectural and operational rationale is maintained in
+`src/docs/maintainers/wasix-postmaster.md`.
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/analyze-wasm-concurrency.sh b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/analyze-wasm-concurrency.sh
new file mode 100644
index 000000000..f9afa4818
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/analyze-wasm-concurrency.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+set -euo pipefail
+here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+repo="$(git -C "$here" rev-parse --show-toplevel)"
+docker="${1:?Docker executable required}"
+image="${2:?Builder image identity required}"
+module="${3:?PostgreSQL module required}"
+shift 3
+case "$module" in "$repo"/*) ;; *) echo 'module must be under the mounted repository' >&2; exit 2 ;; esac
+output="$(mktemp)"
+trap 'rm -f "$output"' EXIT
+"$docker" run --rm --user "$(id -u):$(id -g)" -v "$repo:/work" -w /work "$image" \
+  bash -euo pipefail -c '
+    tool=/opt/wasixcc-home/.wasixcc/binaryen/bin/wasm-dis
+    version="$(timeout 30 "$tool" --version 2>&1)"
+    case "$version" in ""|*$'"'"'\n'"'"'*|*$'"'"'\r'"'"'*) echo "non-canonical wasm-dis version" >&2; exit 1 ;; esac
+    sha256sum "$tool" | cut -d " " -f 1
+    printf "%s\n" "$version"
+    "$tool" "$1"
+  ' bash "/work/${module#"$repo"/}" > "$output"
+# Do not admit a receipt until Binaryen and Docker have both exited successfully.
+bun "$here/verify-postmaster-concurrency-contract.mts" --wasm-dis-output "$output" "$@" "$module"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/build-patched-wasix-libc-sysroot.sh b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/build-patched-wasix-libc-sysroot.sh
similarity index 99%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/build-patched-wasix-libc-sysroot.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/build-patched-wasix-libc-sysroot.sh
index 21a9d98ce..ad417d174 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/build-patched-wasix-libc-sysroot.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/build-patched-wasix-libc-sysroot.sh
@@ -4,7 +4,7 @@ set -euo pipefail
 
 FRESH_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
 source "$FRESH_ROOT/lib/common.sh"
-UPSTREAM_SOURCE_ROOT="$FRESH_ROOT/runtime"
+UPSTREAM_SOURCE_ROOT="$FRESH_ROOT/wasmer"
 UPSTREAM_WORK_ROOT="${UPSTREAM_WORK_ROOT:-$FRESH_WORK_ROOT/runtime}"
 
 DOCKER_IMAGE="${DOCKER_IMAGE:-$FRESH_WASIX_DOCKER_IMAGE}"
@@ -364,7 +364,7 @@ fi
 	"$DOCKER_IMAGE_ID" \
 	bash -lc '
 		set -euo pipefail
-		source ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
+		source ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
 		export PATH=/opt/wasixcc-home/.wasixcc/llvm/bin:$PATH
 
 		restore_host_ownership() {
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/build-runtime.sh b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/build-runtime.sh
new file mode 100755
index 000000000..cc85410ee
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/build-runtime.sh
@@ -0,0 +1,393 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+FRESH_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+source "$FRESH_ROOT/lib/common.sh"
+
+mode="all"
+case "${1:-}" in
+	"") ;;
+	--build-only) mode="build"; shift ;;
+	--tests-only) mode="tests"; shift ;;
+	*) printf 'unknown argument: %s\n' "$1" >&2; exit 2 ;;
+esac
+[ "$#" -eq 0 ] || {
+	printf 'unexpected argument: %s\n' "$1" >&2
+	exit 2
+}
+
+UPSTREAM_WORK_ROOT="${UPSTREAM_WORK_ROOT:-$FRESH_WORK_ROOT/runtime}"
+WASMER_ROOT="${WASMER_ROOT:-$UPSTREAM_WORK_ROOT/wasmer}"
+LLVM_MAJOR=22
+WASMER_PATCH="$FRESH_ROOT/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch"
+WASIX_LIBC_PATCH="$FRESH_ROOT/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
+WASMER_BUILD_RECEIPT_OUT="${WASMER_BUILD_RECEIPT_OUT:-$FRESH_WASMER_BUILD_RECEIPT}"
+POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT="${POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
+WASMER_TARGET_DIR="$WASMER_ROOT/target"
+POSTMASTER_EXECUTOR_TARGET_DIR="$FRESH_POSTMASTER_EXECUTOR_TARGET_DIR"
+POSTMASTER_COMPILER_TARGET_DIR="$FRESH_POSTMASTER_COMPILER_TARGET_DIR"
+PORTABLE_INPUTS="${OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS:-0}"
+NATIVE_INPUTS="${OLIPHAUNT_WASIX_POSTMASTER_NATIVE_INPUTS:-0}"
+
+case "$NATIVE_INPUTS" in
+	0|1) ;;
+	*) printf 'OLIPHAUNT_WASIX_POSTMASTER_NATIVE_INPUTS must be 0 or 1\n' >&2; exit 2 ;;
+esac
+
+case "$PORTABLE_INPUTS" in
+	0|1) ;;
+	*)
+		printf 'OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS must be 0 or 1\n' >&2
+		exit 2
+		;;
+esac
+
+if [ -n "${CARGO_TARGET_DIR:-}" ] || [ -n "${CARGO_BUILD_TARGET:-}" ] ||
+	{ [ -n "${CARGO_INCREMENTAL:-}" ] && [ "$CARGO_INCREMENTAL" != 0 ]; }; then
+	printf 'build-runtime.sh owns Cargo target selection and disables incremental compilation; unset CARGO_TARGET_DIR/CARGO_BUILD_TARGET and use CARGO_INCREMENTAL=0\n' >&2
+	exit 2
+fi
+export CARGO_INCREMENTAL=0
+
+if [ "$NATIVE_INPUTS" -eq 1 ]; then
+	[ "$PORTABLE_INPUTS" -eq 1 ] || {
+		printf 'imported native inputs require OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS=1 for the sysroot and guest inputs\n' >&2
+		exit 2
+	}
+	[ "$mode" = build ] || {
+		printf 'imported native inputs require --build-only; runtime tests remain explicit\n' >&2
+		exit 2
+	}
+	WASMER_BUILD_RECEIPT="$WASMER_BUILD_RECEIPT_OUT" fresh_require_patched_wasmer "$FRESH_UPSTREAM_WASMER_BIN"
+	WASMER_BUILD_RECEIPT="$WASMER_BUILD_RECEIPT_OUT" fresh_require_patched_wasmer_headless "$FRESH_UPSTREAM_WASMER_HEADLESS_BIN"
+	fresh_require_patched_postmaster_executor "$FRESH_POSTMASTER_EXECUTOR_BIN" \
+		"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT" "$WASMER_BUILD_RECEIPT_OUT"
+	fresh_require_start_proof_tool "$FRESH_START_PROOF_BIN" "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
+	fresh_require_memory_profile_tool "$FRESH_MEMORY_PROFILE_BIN" "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
+	fresh_require_patched_postmaster_compiler "$FRESH_POSTMASTER_COMPILER_BIN" \
+		"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT" "$WASMER_BUILD_RECEIPT_OUT" "$FRESH_POSTMASTER_EXECUTOR_BIN"
+	printf 'validated imported native runtime binaries and build receipts\n'
+	exit 0
+fi
+
+find_llvm_prefix() {
+	local candidate
+	local version
+
+	if [ -n "${LLVM_SYS_221_PREFIX:-}" ]; then
+		printf '%s\n' "$LLVM_SYS_221_PREFIX"
+		return
+	fi
+
+	for candidate in llvm-config-22 llvm-config; do
+		if ! command -v "$candidate" >/dev/null 2>&1; then
+			continue
+		fi
+		version="$("$candidate" --version 2>/dev/null || true)"
+		case "$version" in
+			22|22.*)
+				"$candidate" --prefix
+				return
+				;;
+		esac
+	done
+
+	printf 'Wasmer LLVM builds require LLVM %s. Set LLVM_SYS_221_PREFIX or install llvm-config-%s.\n' \
+		"$LLVM_MAJOR" "$LLVM_MAJOR" >&2
+	return 2
+}
+
+fresh_require_command cargo
+fresh_require_command git
+fresh_validate_postmaster_task_budget_profile
+
+
+LLVM_SYS_221_PREFIX="$(find_llvm_prefix)"
+export LLVM_SYS_221_PREFIX
+
+UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
+	"$FRESH_ROOT/wasmer/bin/prepare-upstream-checkouts.sh"
+[ -f "$WASMER_ROOT/lib/cli/Cargo.toml" ] || {
+	printf 'missing prepared Wasmer checkout: %s\n' "$WASMER_ROOT" >&2
+	exit 2
+}
+wasmer_cargo_lock="$WASMER_ROOT/Cargo.lock"
+[ -f "$wasmer_cargo_lock" ] && [ ! -L "$wasmer_cargo_lock" ] || {
+	printf 'missing regular Wasmer Cargo.lock: %s\n' "$wasmer_cargo_lock" >&2
+	exit 2
+}
+rustc_host="$(rustc -vV | awk '/^host:/ {print $2}')"
+[ -n "$rustc_host" ] || {
+	printf 'rustc did not report a host target\n' >&2
+	exit 2
+}
+runtime_abi_id="$(fresh_runtime_abi_id \
+	"$(fresh_wasmer_bin_hash "$wasmer_cargo_lock")" \
+	"$rustc_host" \
+	"$(fresh_host_arch)" \
+	"$(fresh_host_abi)")"
+export OLIPHAUNT_WASIX_RUNTIME_ABI_ID="$runtime_abi_id"
+
+source_wasmer_version="$(awk '
+	$0 == "[workspace.package]" { in_package = 1; next }
+	in_package && /^\[/ { exit }
+	in_package && $1 == "version" { gsub(/"/, "", $3); print $3; exit }
+' "$WASMER_ROOT/Cargo.toml")"
+source_wasmer_wasix_version="$(awk '
+	$0 == "[package]" { in_package = 1; next }
+	in_package && /^\[/ { exit }
+	in_package && $1 == "version" { gsub(/"/, "", $3); print $3; exit }
+' "$WASMER_ROOT/lib/wasix/Cargo.toml")"
+[ "$source_wasmer_version" = "$FRESH_WASMER_VERSION" ] || {
+	printf 'prepared Wasmer version mismatch: expected %s, got %s\n' \
+		"$FRESH_WASMER_VERSION" "${source_wasmer_version:-}" >&2
+	exit 2
+}
+[ "$source_wasmer_wasix_version" = "$FRESH_WASMER_WASIX_VERSION" ] || {
+	printf 'prepared wasmer-wasix version mismatch: expected %s, got %s\n' \
+		"$FRESH_WASMER_WASIX_VERSION" "${source_wasmer_wasix_version:-}" >&2
+	exit 2
+}
+
+if [ "$mode" != build ]; then
+  cd "$FRESH_ROOT/executor"
+	source "$FRESH_ROOT/wasmer/tests.sh"
+fi
+
+if [ "$mode" = tests ]; then
+	printf 'patched Wasmer and Postmaster runtime tests passed\n'
+	exit 0
+fi
+
+cd "$FRESH_ROOT/executor"
+cargo build \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/cli/Cargo.toml" \
+	--bin wasmer \
+	--release \
+	--no-default-features \
+	--features "$FRESH_WASMER_COMPILER_FEATURES"
+cargo build \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/cli/Cargo.toml" \
+	--bin wasmer-headless \
+	--release \
+	--no-default-features \
+	--features "$FRESH_WASMER_HEADLESS_FEATURES"
+cargo build \
+	--locked \
+	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
+	--manifest-path "$FRESH_ROOT/executor/Cargo.toml" \
+	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
+	--bin "$FRESH_POSTMASTER_EXECUTOR_BINARY" \
+	--release \
+	--no-default-features \
+	--features "$FRESH_POSTMASTER_EXECUTOR_FEATURES"
+cargo build \
+	--locked \
+	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
+	--manifest-path "$FRESH_ROOT/executor/Cargo.toml" \
+	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
+	--bin "$FRESH_START_PROOF_BINARY" \
+	--release \
+	--no-default-features \
+	--features "$FRESH_START_PROOF_FEATURES"
+cargo build \
+	--locked \
+	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
+	--manifest-path "$FRESH_ROOT/executor/Cargo.toml" \
+	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
+	--bin "$FRESH_MEMORY_PROFILE_BINARY" \
+	--release \
+	--no-default-features \
+	--features "$FRESH_MEMORY_PROFILE_FEATURES"
+cargo build \
+	--locked \
+	--target-dir "$POSTMASTER_COMPILER_TARGET_DIR" \
+	--manifest-path "$FRESH_ROOT/executor/Cargo.toml" \
+	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
+	--bin "$FRESH_POSTMASTER_COMPILER_BINARY" \
+	--release \
+	--no-default-features \
+	--features "$FRESH_POSTMASTER_COMPILER_FEATURES"
+if [ "$PORTABLE_INPUTS" -eq 1 ]; then
+	UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
+		"$FRESH_ROOT/wasmer/bin/build-patched-wasix-libc-sysroot.sh" \
+		--no-build --portable-inputs
+elif [ -f "$WASIXCC_SYSROOT_PREFIX/.oliphaunt-patched-sysroots.manifest" ] && \
+	UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
+	"$FRESH_ROOT/wasmer/bin/build-patched-wasix-libc-sysroot.sh" --no-build; then
+	:
+else
+	UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
+	"$FRESH_ROOT/wasmer/bin/build-patched-wasix-libc-sysroot.sh"
+fi
+
+UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
+	"$FRESH_ROOT/wasmer/bin/prepare-upstream-checkouts.sh"
+
+wasmer_bin="$WASMER_TARGET_DIR/release/wasmer"
+wasmer_headless_bin="$WASMER_TARGET_DIR/release/wasmer-headless"
+postmaster_executor_bin="$POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_POSTMASTER_EXECUTOR_BINARY"
+start_proof_bin="$POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_START_PROOF_BINARY"
+memory_profile_bin="$POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_MEMORY_PROFILE_BINARY"
+postmaster_compiler_bin="$POSTMASTER_COMPILER_TARGET_DIR/release/$FRESH_POSTMASTER_COMPILER_BINARY"
+carrier_manifest="$WASIXCC_SYSROOT_PREFIX/.oliphaunt-patched-sysroots.manifest"
+variant_manifest="$WASIXCC_SYSROOT/.oliphaunt-patched-sysroot.manifest"
+prepared_signature="$UPSTREAM_WORK_ROOT/.prepared/wasmer.signature"
+libc_prepared_signature="$UPSTREAM_WORK_ROOT/.prepared/wasix-libc.signature"
+for required in \
+	"$wasmer_bin" \
+	"$wasmer_headless_bin" \
+	"$postmaster_executor_bin" \
+	"$start_proof_bin" \
+	"$memory_profile_bin" \
+	"$postmaster_compiler_bin" \
+	"$WASMER_PATCH" \
+	"$WASIX_LIBC_PATCH" \
+	"$carrier_manifest" \
+	"$variant_manifest" \
+	"$prepared_signature" \
+	"$libc_prepared_signature" \
+	"$WASMER_ROOT/Cargo.lock"
+do
+	[ -f "$required" ] || {
+		printf 'missing Wasmer build-receipt input: %s\n' "$required" >&2
+		exit 2
+	}
+done
+
+mkdir -p "$(dirname "$WASMER_BUILD_RECEIPT_OUT")"
+temporary_manifest="$WASMER_BUILD_RECEIPT_OUT.tmp.$$"
+trap 'rm -f "$temporary_manifest"' EXIT
+{
+	printf 'schema=oliphaunt.wasix-postmaster.wasmer-build.v2\n'
+	printf 'build_recipe_sha256=%s\n' "$(fresh_runtime_build_recipe_sha256)"
+	printf 'wasmer_source_commit=%s\n' "$(git -C "$WASMER_ROOT" rev-parse HEAD)"
+	printf 'wasmer_napi_commit=%s\n' "$(git -C "$WASMER_ROOT/lib/napi" rev-parse HEAD)"
+	printf 'wasmer_test_files_commit=%s\n' "$(git -C "$WASMER_ROOT/wasmer-test-files" rev-parse HEAD)"
+	printf 'wasmer_spec_commit=%s\n' "$(git -C "$WASMER_ROOT/tests/wast/spec" rev-parse HEAD)"
+	printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_PATCH")"
+	printf 'wasmer_prepared_signature_sha256=%s\n' "$(fresh_wasmer_bin_hash "$prepared_signature")"
+	printf 'wasmer_cargo_lock_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_ROOT/Cargo.lock")"
+	printf 'wasmer_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$wasmer_bin")"
+	printf 'wasmer_features=%s\n' "$FRESH_WASMER_COMPILER_FEATURES"
+	printf 'wasmer_headless_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$wasmer_headless_bin")"
+	printf 'wasmer_headless_features=%s\n' "$FRESH_WASMER_HEADLESS_FEATURES"
+	printf 'runtime_abi_id=%s\n' "$runtime_abi_id"
+	printf 'artifact_abi_version=%s\n' "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
+	printf 'wasix_libc_source_commit=%s\n' "$(git -C "$UPSTREAM_WORK_ROOT/wasix-libc" rev-parse HEAD)"
+	printf 'wasix_libc_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASIX_LIBC_PATCH")"
+	printf 'wasix_libc_prepared_signature_sha256=%s\n' "$(fresh_wasmer_bin_hash "$libc_prepared_signature")"
+	printf 'sysroot_carrier_manifest_sha256=%s\n' "$(fresh_wasmer_bin_hash "$carrier_manifest")"
+	printf 'sysroot_variant=%s\n' "$WASIXCC_SYSROOT_VARIANT"
+	printf 'sysroot_variant_manifest_sha256=%s\n' "$(fresh_wasmer_bin_hash "$variant_manifest")"
+	printf 'host_platform=%s\n' "$(fresh_host_arch)"
+	printf 'host_abi=%s\n' "$(fresh_host_abi)"
+	printf 'rustc_host=%s\n' "$rustc_host"
+	printf 'rustc_version=%s\n' "$(rustc --version)"
+	printf 'llvm_version=%s\n' "$("$LLVM_SYS_221_PREFIX/bin/llvm-config" --version)"
+} >"$temporary_manifest"
+fresh_validate_wasmer_build_receipt_shape "$temporary_manifest"
+fresh_require_local_wasmer_build_state "$temporary_manifest"
+WASMER_BUILD_RECEIPT="$temporary_manifest" fresh_require_patched_wasmer "$wasmer_bin"
+WASMER_BUILD_RECEIPT="$temporary_manifest" fresh_require_patched_wasmer_headless "$wasmer_headless_bin"
+mv "$temporary_manifest" "$WASMER_BUILD_RECEIPT_OUT"
+trap - EXIT
+WASMER_BUILD_RECEIPT="$WASMER_BUILD_RECEIPT_OUT" fresh_require_patched_wasmer "$wasmer_bin"
+WASMER_BUILD_RECEIPT="$WASMER_BUILD_RECEIPT_OUT" fresh_require_patched_wasmer_headless "$wasmer_headless_bin"
+
+mkdir -p "$(dirname "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT")"
+temporary_executor_receipt="$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT.tmp.$$"
+trap 'rm -f "$temporary_executor_receipt"' EXIT
+{
+	printf 'schema=oliphaunt.wasix-postmaster.postmaster-executor-build.v3\n'
+	printf 'build_recipe_sha256=%s\n' "$(fresh_runtime_build_recipe_sha256)"
+	printf 'wasmer_build_receipt_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_BUILD_RECEIPT_OUT")"
+	printf 'wasmer_source_commit=%s\n' "$(git -C "$WASMER_ROOT" rev-parse HEAD)"
+	printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_PATCH")"
+	printf 'wasmer_prepared_signature_sha256=%s\n' "$(fresh_wasmer_bin_hash "$prepared_signature")"
+	printf 'wasmer_cargo_lock_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_ROOT/Cargo.lock")"
+	printf 'runtime_abi_id=%s\n' "$runtime_abi_id"
+	printf 'artifact_abi_version=%s\n' "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
+	printf 'executor_package=%s\n' "$FRESH_POSTMASTER_EXECUTOR_PACKAGE"
+	printf 'executor_binary=%s\n' "$FRESH_POSTMASTER_EXECUTOR_BINARY"
+	printf 'executor_features=%s\n' "$FRESH_POSTMASTER_EXECUTOR_FEATURES"
+	printf 'executor_role=%s\n' "$FRESH_POSTMASTER_EXECUTOR_ROLE"
+	printf 'runtime_policy_id=%s\n' "$FRESH_POSTMASTER_EXECUTOR_RUNTIME_POLICY_ID"
+	printf 'cli_contract=%s\n' "$FRESH_POSTMASTER_EXECUTOR_CLI_CONTRACT"
+	printf 'executor_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$postmaster_executor_bin")"
+	printf 'start_proof_binary=%s\n' "$FRESH_START_PROOF_BINARY"
+	printf 'start_proof_features=%s\n' "$FRESH_START_PROOF_FEATURES"
+	printf 'start_proof_policy=%s\n' "$FRESH_START_PROOF_POLICY"
+	printf 'start_proof_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$start_proof_bin")"
+	printf 'memory_profile_binary=%s\n' "$FRESH_MEMORY_PROFILE_BINARY"
+	printf 'memory_profile_features=%s\n' "$FRESH_MEMORY_PROFILE_FEATURES"
+	printf 'linear_memory_profile_id=%s\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
+	printf 'memory_profile_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$memory_profile_bin")"
+	printf 'postmaster_compiler_binary=%s\n' "$FRESH_POSTMASTER_COMPILER_BINARY"
+	printf 'postmaster_compiler_features=%s\n' "$FRESH_POSTMASTER_COMPILER_FEATURES"
+	printf 'compiler_cpu_policy=generic-baseline\n'
+	printf 'compiler_cpu_features=none\n'
+	printf 'postmaster_compiler_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$postmaster_compiler_bin")"
+	printf 'host_platform=%s\n' "$(fresh_host_arch)"
+	printf 'host_abi=%s\n' "$(fresh_host_abi)"
+	printf 'rustc_host=%s\n' "$rustc_host"
+	printf 'rustc_version=%s\n' "$(rustc --version)"
+} >"$temporary_executor_receipt"
+fresh_validate_postmaster_executor_build_receipt_shape "$temporary_executor_receipt"
+fresh_require_patched_postmaster_executor \
+	"$postmaster_executor_bin" \
+	"$temporary_executor_receipt" \
+	"$WASMER_BUILD_RECEIPT_OUT"
+fresh_require_start_proof_tool \
+	"$start_proof_bin" \
+	"$temporary_executor_receipt"
+fresh_require_memory_profile_tool \
+	"$memory_profile_bin" \
+	"$temporary_executor_receipt"
+fresh_require_patched_postmaster_compiler \
+	"$postmaster_compiler_bin" \
+	"$temporary_executor_receipt" \
+	"$WASMER_BUILD_RECEIPT_OUT" \
+	"$postmaster_executor_bin"
+mv "$temporary_executor_receipt" "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
+trap - EXIT
+fresh_require_patched_postmaster_executor \
+	"$postmaster_executor_bin" \
+	"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT" \
+	"$WASMER_BUILD_RECEIPT_OUT"
+fresh_require_start_proof_tool \
+	"$start_proof_bin" \
+	"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
+fresh_require_memory_profile_tool \
+	"$memory_profile_bin" \
+	"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
+fresh_require_patched_postmaster_compiler \
+	"$postmaster_compiler_bin" \
+	"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT" \
+	"$WASMER_BUILD_RECEIPT_OUT" \
+	"$postmaster_executor_bin"
+
+printf 'built patched Wasmer: %s\n' "$wasmer_bin"
+printf 'Wasmer sha256: %s\n' "$(fresh_wasmer_bin_hash "$wasmer_bin")"
+printf 'built patched headless Wasmer: %s\n' "$wasmer_headless_bin"
+printf 'Headless Wasmer sha256: %s\n' "$(fresh_wasmer_bin_hash "$wasmer_headless_bin")"
+printf 'built postmaster product executor: %s\n' "$postmaster_executor_bin"
+printf 'Postmaster executor sha256: %s\n' "$(fresh_wasmer_bin_hash "$postmaster_executor_bin")"
+printf 'built deterministic-start proof tool: %s\n' "$start_proof_bin"
+printf 'Start proof tool sha256: %s\n' "$(fresh_wasmer_bin_hash "$start_proof_bin")"
+printf 'built linear-memory profile tool: %s\n' "$memory_profile_bin"
+printf 'Linear-memory profile tool sha256: %s\n' "$(fresh_wasmer_bin_hash "$memory_profile_bin")"
+printf 'built postmaster product compiler: %s\n' "$postmaster_compiler_bin"
+printf 'Postmaster product compiler sha256: %s\n' "$(fresh_wasmer_bin_hash "$postmaster_compiler_bin")"
+printf 'Runtime ABI ID: %s\n' "$runtime_abi_id"
+printf 'WASIX libc carrier: %s\n' "$WASIXCC_SYSROOT_PREFIX"
+printf 'Wasmer build receipt: %s\n' "$WASMER_BUILD_RECEIPT_OUT"
+printf 'Receipt sha256: %s\n' "$(fresh_wasmer_bin_hash "$WASMER_BUILD_RECEIPT_OUT")"
+printf 'Postmaster executor build receipt: %s\n' "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
+printf 'Postmaster executor receipt sha256: %s\n' \
+	"$(fresh_wasmer_bin_hash "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT")"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/prepare-upstream-checkouts.sh b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/prepare-upstream-checkouts.sh
similarity index 89%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/prepare-upstream-checkouts.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/prepare-upstream-checkouts.sh
index 4e56a6685..f5c931a4f 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/prepare-upstream-checkouts.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/prepare-upstream-checkouts.sh
@@ -4,7 +4,7 @@ set -euo pipefail
 
 FRESH_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
 source "$FRESH_ROOT/lib/common.sh"
-UPSTREAM_SOURCE_ROOT="$FRESH_ROOT/runtime"
+UPSTREAM_SOURCE_ROOT="$FRESH_ROOT/wasmer"
 UPSTREAM_WORK_ROOT="${UPSTREAM_WORK_ROOT:-$FRESH_WORK_ROOT/runtime}"
 SOURCE_CHECKOUT_ROOT="${SOURCE_CHECKOUT_ROOT:-$REPO_ROOT/target/oliphaunt-sources/checkouts}"
 
@@ -23,8 +23,6 @@ WASMER_ROOT="${WASMER_ROOT:-$UPSTREAM_WORK_ROOT/wasmer}"
 WASIX_LIBC_ROOT="${WASIX_LIBC_ROOT:-$UPSTREAM_WORK_ROOT/wasix-libc}"
 SIGNATURE_ROOT="$UPSTREAM_WORK_ROOT/.prepared"
 
-fresh_require_command python3
-python3 "$UPSTREAM_SOURCE_ROOT/bin/verify-source-lock.py"
 
 FORCE=0
 SKIP_PATCHES=0
@@ -67,6 +65,15 @@ while [ "$#" -gt 0 ]; do
 	shift
 done
 
+if [ "${OLIPHAUNT_WASIX_POSTMASTER_NATIVE_INPUTS:-0}" = 1 ]; then
+	[ "${OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS:-0}" = 1 ] || {
+		printf 'imported native inputs require OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS=1 for the sysroot and guest inputs\n' >&2
+		exit 2
+	}
+	printf 'imported native inputs: runtime-build validates binaries and receipts without source worktrees\n'
+	exit 0
+fi
+
 fresh_require_managed_generated_path "$UPSTREAM_WORK_ROOT" UPSTREAM_WORK_ROOT
 fresh_require_managed_generated_path "$WASMER_ROOT" WASMER_ROOT
 fresh_require_managed_generated_path "$WASIX_LIBC_ROOT" WASIX_LIBC_ROOT
@@ -110,18 +117,6 @@ verify_durable_source() {
 	}
 }
 
-worktree_state_hash() {
-	local root="$1"
-	{
-		git -C "$root" diff --binary HEAD
-		git -C "$root" ls-files --others --exclude-standard -z |
-			while IFS= read -r -d '' path; do
-				printf 'untracked:%s\n' "$path"
-				sha256_file "$root/$path"
-			done
-	} | sha256_stream
-}
-
 worktree_is_prepared() {
 	local root="$1"
 	local ref="$2"
@@ -132,7 +127,7 @@ worktree_is_prepared() {
 	[ "$(git -C "$root" rev-parse HEAD)" = "$ref" ] || return 1
 	[ -f "$signature_file" ] || return 1
 	local expected
-	expected="${input_signature}:$(worktree_state_hash "$root")"
+	expected="${input_signature}:$(fresh_runtime_worktree_state_hash "$root")"
 	[ "$(cat "$signature_file")" = "$expected" ]
 }
 
@@ -206,10 +201,16 @@ prepare_patched_worktree() {
 	if [ "$SKIP_PATCHES" -ne 1 ]; then
 		patch_signature="$(sha256_file "$patch")"
 	fi
-	local input_signature="$ref:$patch_signature:$extra_signature"
+	if [ "$name" = "wasmer" ] && [ "$SKIP_PATCHES" -ne 1 ]; then
+    extra_signature="$extra_signature:$(fresh_executor_source_sha256)"
+  fi
+  local input_signature="$ref:$patch_signature:$extra_signature"
 	local signature_file="$SIGNATURE_ROOT/$name.signature"
 
 	if [ "$FORCE" -ne 1 ] && worktree_is_prepared "$root" "$ref" "$input_signature" "$signature_file"; then
+		if [ "$name" = wasmer ] && [ "$SKIP_PATCHES" -ne 1 ]; then
+			bun "$FRESH_ROOT/executor/prepare-paths.mts" "$root"
+		fi
 		printf '%s generated worktree already matches the recorded patch signature\n' "$name"
 		return
 	fi
@@ -223,9 +224,12 @@ prepare_patched_worktree() {
 	if [ "$SKIP_PATCHES" -ne 1 ]; then
 		git -C "$root" apply --check "$patch"
 		git -C "$root" apply "$patch"
+    if [ "$name" = "wasmer" ]; then
+      bun "$FRESH_ROOT/executor/prepare-paths.mts" "$root"
+    fi
 	fi
 	mkdir -p "$SIGNATURE_ROOT"
-	printf '%s:%s' "$input_signature" "$(worktree_state_hash "$root")" >"$signature_file"
+	printf '%s:%s' "$input_signature" "$(fresh_runtime_worktree_state_hash "$root")" >"$signature_file"
 }
 
 verify_durable_source "Wasmer" "$WASMER_SOURCE_ROOT" "$WASMER_REF"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/qualify-runtime-capabilities.sh b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/qualify-runtime-capabilities.sh
similarity index 95%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/qualify-runtime-capabilities.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/qualify-runtime-capabilities.sh
index 7d5fb6509..c14afea6f 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/qualify-runtime-capabilities.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/qualify-runtime-capabilities.sh
@@ -54,7 +54,7 @@ for probe in "${probes[@]}"; do
 done
 
 exec env UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
-	"$FRESH_ROOT/runtime/bin/validate-runtime-capabilities.sh" \
+	"$FRESH_ROOT/wasmer/bin/validate-runtime-capabilities.sh" \
 	--wasmer-bin "$WASMER_BIN" \
 	"${portable_args[@]}" \
 	--strict \
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/validate-runtime-capabilities.sh b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/validate-runtime-capabilities.sh
similarity index 99%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/validate-runtime-capabilities.sh
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/validate-runtime-capabilities.sh
index 5e68fb46b..03a46088d 100755
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/validate-runtime-capabilities.sh
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/validate-runtime-capabilities.sh
@@ -4,7 +4,7 @@ set -euo pipefail
 
 FRESH_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
 source "$FRESH_ROOT/lib/common.sh"
-UPSTREAM_SOURCE_ROOT="$FRESH_ROOT/runtime"
+UPSTREAM_SOURCE_ROOT="$FRESH_ROOT/wasmer"
 UPSTREAM_WORK_ROOT="${UPSTREAM_WORK_ROOT:-$FRESH_WORK_ROOT/runtime}"
 PROBE_SOURCE_DIR="$UPSTREAM_SOURCE_ROOT/probes"
 
@@ -376,8 +376,8 @@ validate_exact_sysroot() {
 
 	require_manifest_value "$PATCHED_SYSROOT_MANIFEST" schema oliphaunt.wasix-libc-sysroot.v1
 	require_manifest_value "$PATCHED_SYSROOT_MANIFEST" variant "$WASIXCC_SYSROOT_VARIANT"
-	require_manifest_value "$PATCHED_SYSROOT_MANIFEST" source_patch \
-		"$(fresh_project_source_identity_path "$expected_patch")"
+	# source_patch is descriptive provenance; relocation does not change the
+	# patch. Its exact bytes are checked by source_patch_sha256 below.
 	require_manifest_value "$PATCHED_SYSROOT_MANIFEST" docker_image "$DOCKER_IMAGE"
 	require_manifest_value "$PATCHED_SYSROOT_MANIFEST" makefile Makefile-eh
 	require_manifest_value "$PATCHED_SYSROOT_MANIFEST" make_jobs 2
@@ -715,7 +715,7 @@ compile_probes() {
 		"$CURRENT_DOCKER_IMAGE_ID" \
 		bash -lc '
 			set -euo pipefail
-			source ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
+			source ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
 			restore_host_ownership() {
 				local command_status="$?"
 
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-concurrency-contract.mts b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-concurrency-contract.mts
new file mode 100644
index 000000000..56ec73205
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-concurrency-contract.mts
@@ -0,0 +1,379 @@
+#!/usr/bin/env bun
+// Verify the final linked module, after optimizers could erase synchronization.
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { createReadStream, fchmodSync, readFileSync, writeFileSync } from 'node:fs';
+import { createInterface } from 'node:readline';
+import { Readable } from 'node:stream';
+import { parseArgs } from 'node:util';
+import { atomicFile } from '../../lib/receipt-files.mts';
+import { Reader } from './verify-postmaster-wasm-import.mts';
+
+const schema = 'oliphaunt.wasix-postmaster.final-wasm-concurrency.v1';
+const packed = 'packed-atomic-v1';
+export const fences = { SetLatch: 2, ResetLatch: 1, WaitEventSetWait: 1 };
+const opcodes = [
+  'atomic.fence',
+  'i32.atomic.load',
+  'i32.atomic.rmw.and',
+  'i32.atomic.rmw.or',
+] as const;
+type Counts = Record<(typeof opcodes)[number], number>;
+type Inventory = { total: Counts; functions: Record };
+const empty = (): Counts => ({
+  'atomic.fence': 0,
+  'i32.atomic.load': 0,
+  'i32.atomic.rmw.and': 0,
+  'i32.atomic.rmw.or': 0,
+});
+const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex');
+const requireDigest = (value: string) =>
+  assert(/^[0-9a-f]{64}$/u.test(value), 'invalid concurrency SHA-256');
+const done = (reader: Reader) =>
+  assert.equal(reader.offset, reader.data.length, 'trailing section bytes');
+const numericFields = {
+  atomic_fence_total: ['atomic.fence'],
+  atomic_fence_set_latch: ['atomic.fence', 'SetLatch'],
+  atomic_fence_reset_latch: ['atomic.fence', 'ResetLatch'],
+  atomic_fence_wait_event_set_wait: ['atomic.fence', 'WaitEventSetWait'],
+  i32_atomic_load_total: ['i32.atomic.load'],
+  i32_atomic_load_wait_event_set_wait: ['i32.atomic.load', 'WaitEventSetWait'],
+  i32_atomic_rmw_and_total: ['i32.atomic.rmw.and'],
+  i32_atomic_rmw_and_reset_latch: ['i32.atomic.rmw.and', 'ResetLatch'],
+  i32_atomic_rmw_and_wait_event_set_wait: ['i32.atomic.rmw.and', 'WaitEventSetWait'],
+  i32_atomic_rmw_or_total: ['i32.atomic.rmw.or'],
+  i32_atomic_rmw_or_set_latch: ['i32.atomic.rmw.or', 'SetLatch'],
+  i32_atomic_rmw_or_wait_event_set_wait: ['i32.atomic.rmw.or', 'WaitEventSetWait'],
+} as const;
+const receiptKeys = [
+  'schema',
+  'postgres_sha256',
+  'wasm_dis_sha256',
+  'wasm_dis_version',
+  'latch_state_contract',
+  ...Object.keys(numericFields),
+];
+
+export function structure(data: Uint8Array) {
+  const reader = new Reader(data);
+  assert(
+    Buffer.from(reader.take(8)).equals(Buffer.from('0061736d01000000', 'hex')),
+    'not a core WebAssembly version-1 module',
+  );
+  const sections = new Map();
+  while (reader.offset < data.length) {
+    const id = reader.byte(),
+      section = new Reader(reader.take(reader.size()));
+    if (id === 0) continue;
+    assert(!sections.has(id), `duplicate section ${id}`);
+    sections.set(id, section);
+  }
+  for (const id of [2, 3, 7, 10]) assert(sections.has(id), `missing section ${id}`);
+  const imports = sections.get(2)!;
+  const memories: number[] = [];
+  let imported = 0;
+  for (let count = imports.size(); count > 0; count--) {
+    const module = imports.name(),
+      name = imports.name();
+    switch (imports.byte()) {
+      case 0:
+        imports.size();
+        imported++;
+        break;
+      case 1:
+        imports.byte();
+        imports.limits();
+        break;
+      case 2: {
+        const flags = imports.limits();
+        if (module === 'env' && name === 'memory') memories.push(flags);
+        break;
+      }
+      case 3:
+        imports.byte();
+        imports.byte();
+        break;
+      case 4:
+        imports.byte();
+        imports.size();
+        break;
+      default:
+        throw new Error('unknown import kind');
+    }
+  }
+  done(imports);
+  assert(
+    memories.length === 1 && memories[0]! & 2,
+    'env.memory is not declared shared exactly once',
+  );
+  const functions = sections.get(3)!;
+  const defined = functions.size();
+  for (let i = 0; i < defined; i++) functions.size();
+  done(functions);
+  const exports = sections.get(7)!,
+    indices = new Map();
+  for (let count = exports.size(); count > 0; count--) {
+    const name = exports.name(),
+      kind = exports.byte(),
+      index = exports.size();
+    if (kind !== 0) continue;
+    assert(!indices.has(name), `duplicate function export ${name}`);
+    indices.set(name, index);
+  }
+  done(exports);
+  const code = sections.get(10)!;
+  assert.equal(code.size(), defined, 'function/code count mismatch');
+  const bodies: Uint8Array[] = [];
+  for (let i = 0; i < defined; i++) bodies.push(code.take(code.size()));
+  done(code);
+  const critical: Record = {};
+  for (const name of Object.keys(fences)) {
+    const index = indices.get(name);
+    assert(
+      index !== undefined && index >= imported && index - imported < defined,
+      `${name} does not refer to a defined function`,
+    );
+    critical[name] = bodies[index - imported]!;
+  }
+  return { bodies, critical };
+}
+export async function watInventory(
+  lines: AsyncIterable | Iterable,
+): Promise {
+  const targets = new Map(),
+    exports = new Set(),
+    seen = new Set();
+  const inventory: Inventory = {
+    total: empty(),
+    functions: Object.fromEntries(Object.keys(fences).map((name) => [name, empty()])),
+  };
+  let current: string | undefined;
+  for await (const raw of lines) {
+    const line = raw.replace(/\n$/u, '');
+    assert(!line.includes('\r'), 'wasm-dis emitted non-canonical CR text');
+    const exported = /^ \(export "([^"]+)" \(func (\$[^ ()]+)\)\)$/u.exec(line);
+    if (exported && Object.hasOwn(fences, exported[1]!)) {
+      const [, name, id] = exported;
+      assert(!exports.has(name!), `duplicate export ${name}`);
+      assert(!targets.has(id!), 'critical exports share one function identifier');
+      exports.add(name!);
+      targets.set(id!, name!);
+    }
+    const fn = /^ \(func (\$[^ ()]+)(?:[ ()]|$)/u.exec(line);
+    if (fn) {
+      current = targets.get(fn[1]!);
+      if (current) {
+        assert(!seen.has(current), `duplicate function body ${current}`);
+        seen.add(current);
+      }
+    }
+    const opcode =
+      /^ +\((atomic\.fence|i32\.atomic\.load|i32\.atomic\.rmw\.and|i32\.atomic\.rmw\.or)\b/u.exec(
+        line,
+      )?.[1] as (typeof opcodes)[number] | undefined;
+    if (opcode) {
+      inventory.total[opcode]++;
+      if (current) inventory.functions[current]![opcode]++;
+    }
+    if (line === ' )') current = undefined;
+  }
+  assert.equal(exports.size, 3, 'wasm-dis lacks critical exports');
+  assert.equal(seen.size, 3, 'wasm-dis lacks critical function bodies');
+  return inventory;
+}
+export function checkInventory(inventory: Inventory, expected?: number, packedContract = true) {
+  const { total, functions } = inventory;
+  if (expected !== undefined)
+    assert.equal(total['atomic.fence'], expected, 'module fence total differs');
+  for (const [name, count] of Object.entries(fences))
+    assert.equal(functions[name]!['atomic.fence'], count, `${name} atomic.fence differs`);
+  assert(total['atomic.fence'] >= 4, 'module has too few fences');
+  if (!packedContract) return;
+  for (const [name, opcode, count] of [
+    ['SetLatch', 'i32.atomic.rmw.or', 1],
+    ['ResetLatch', 'i32.atomic.rmw.and', 1],
+    ['WaitEventSetWait', 'i32.atomic.rmw.and', 2],
+    ['WaitEventSetWait', 'i32.atomic.rmw.or', 1],
+  ] as const)
+    assert.equal(functions[name]![opcode], count, `${name} ${opcode} differs`);
+  assert(
+    functions.WaitEventSetWait!['i32.atomic.load'] >= 1,
+    'waiter needs at least one atomic load',
+  );
+}
+export function receipt(data: Uint8Array, inventory: Inventory, disHash: string, version: string) {
+  requireDigest(disHash);
+  assert(version && !/[\r\n]/u.test(version), 'wasm-dis must provide one canonical version line');
+  const values: Record = {
+    schema,
+    postgres_sha256: digest(data),
+    wasm_dis_sha256: disHash,
+    wasm_dis_version: version,
+    latch_state_contract: packed,
+  };
+  for (const [key, [opcode, name]] of Object.entries(numericFields))
+    values[key] = name ? inventory.functions[name]![opcode] : inventory.total[opcode];
+  return Object.entries(values)
+    .map(([key, value]) => `${key}=${value}\n`)
+    .join('');
+}
+export function verifyReceipt(contents: string, data: Uint8Array, expected?: number) {
+  assert(contents.endsWith('\n') && !contents.includes('\r'), 'non-canonical receipt text');
+  const lines = contents.slice(0, -1).split('\n');
+  assert.equal(lines.length, receiptKeys.length, 'receipt field count differs');
+  const values: Record = {};
+  for (const [index, line] of lines.entries()) {
+    const separator = line.indexOf('=');
+    const key = line.slice(0, separator),
+      value = line.slice(separator + 1);
+    assert(separator > 0 && key === receiptKeys[index] && value, 'non-canonical receipt field');
+    values[key] = value;
+  }
+  assert.equal(values.schema, schema, 'receipt schema differs');
+  assert.equal(values.latch_state_contract, packed, 'receipt latch contract differs');
+  requireDigest(values.postgres_sha256!);
+  requireDigest(values.wasm_dis_sha256!);
+  assert.equal(values.postgres_sha256, digest(data), 'receipt does not identify PostgreSQL module');
+  const numbers: Record = {};
+  for (const key of Object.keys(numericFields)) {
+    assert(/^(0|[1-9][0-9]*)$/u.test(values[key]!), `${key} is not a canonical integer`);
+    numbers[key] = BigInt(values[key]!);
+  }
+  if (expected !== undefined)
+    assert.equal(numbers.atomic_fence_total, BigInt(expected), 'receipt fence total differs');
+  for (const [key, value] of Object.entries({
+    atomic_fence_set_latch: 2n,
+    atomic_fence_reset_latch: 1n,
+    atomic_fence_wait_event_set_wait: 1n,
+    i32_atomic_rmw_and_reset_latch: 1n,
+    i32_atomic_rmw_and_wait_event_set_wait: 2n,
+    i32_atomic_rmw_or_set_latch: 1n,
+    i32_atomic_rmw_or_wait_event_set_wait: 1n,
+  }))
+    assert.equal(numbers[key], value, `receipt contract differs: ${key}`);
+  assert(
+    numbers.i32_atomic_load_wait_event_set_wait! >= 1n &&
+      numbers.i32_atomic_load_total! >= numbers.i32_atomic_load_wait_event_set_wait! &&
+      numbers.i32_atomic_rmw_and_total! >= 3n &&
+      numbers.i32_atomic_rmw_or_total! >= 2n,
+    'receipt atomic totals are inconsistent',
+  );
+  return values;
+}
+if (import.meta.main) {
+  try {
+    const { values, positionals } = parseArgs({
+      allowPositionals: true,
+      options: {
+        'expected-total': { type: 'string' },
+        'latch-state-contract': { type: 'string', default: 'upstream-sig-atomic-v1' },
+        'wasm-dis-output': { type: 'string' },
+        receipt: { type: 'string' },
+        'verified-receipt': { type: 'string' },
+        'receipt-only': { type: 'boolean' },
+      },
+    });
+    assert.equal(positionals.length, 1, 'one PostgreSQL module is required');
+    const expected =
+      values['expected-total'] === undefined ? undefined : Number(values['expected-total']);
+    assert(
+      expected === undefined || (Number.isSafeInteger(expected) && expected >= 4),
+      '--expected-total must be at least four',
+    );
+    const contract = values['latch-state-contract'];
+    assert([packed, 'upstream-sig-atomic-v1'].includes(contract!), 'unknown latch contract');
+    const disassembly = values['wasm-dis-output'],
+      verified = values['verified-receipt'];
+    assert(!(disassembly && verified), 'disassembly and verified receipt are exclusive');
+    assert(
+      contract !== packed || disassembly || verified,
+      'packed contract requires disassembly or verified receipt',
+    );
+    assert(
+      !values.receipt || (disassembly && contract === packed),
+      'receipt requires packed disassembly',
+    );
+    assert(
+      !values['receipt-only'] ||
+        (verified &&
+          expected !== undefined &&
+          contract === packed &&
+          !disassembly &&
+          !values.receipt),
+      'receipt-only requires a packed verified receipt and expected total',
+    );
+    const data = readFileSync(positionals[0]!);
+    let total: string | number;
+    if (verified) {
+      if (!values['receipt-only']) structure(data);
+      const checked = verifyReceipt(readFileSync(verified, 'utf8'), data, expected);
+      total = checked.atomic_fence_total!;
+    } else {
+      const module = structure(data);
+      if (disassembly) {
+        const input = createReadStream(disassembly);
+        const decoder = new TextDecoderStream('utf-8', { fatal: true });
+        const stream = Readable.toWeb(input)
+          .pipeThrough(decoder)
+          .pipeThrough(
+            new TransformStream({
+              transform(chunk, controller) {
+                assert(!chunk.includes('\r'), 'wasm-dis emitted non-canonical CR text');
+                controller.enqueue(chunk);
+              },
+            }),
+          );
+        const lines = createInterface({ input: Readable.fromWeb(stream), crlfDelay: Infinity });
+        try {
+          const iterator = lines[Symbol.asyncIterator]();
+          const disHash = (await iterator.next()).value,
+            version = (await iterator.next()).value;
+          assert(
+            typeof disHash === 'string' && typeof version === 'string',
+            'missing Binaryen identity',
+          );
+          requireDigest(disHash);
+          assert(version, 'missing Binaryen version');
+          const inventory = await watInventory({ [Symbol.asyncIterator]: () => iterator });
+          checkInventory(inventory, expected, contract === packed);
+          total = inventory.total['atomic.fence'];
+          if (values.receipt) {
+            const contents = receipt(data, inventory, disHash, version);
+            atomicFile(values.receipt, (fd) => {
+              writeFileSync(fd, contents);
+              fchmodSync(fd, 0o444);
+            });
+          }
+        } finally {
+          lines.close();
+          input.destroy();
+        }
+      } else {
+        // Only legacy unsealed development profiles use byte inventory. Packed
+        // release profiles always use Binaryen's decoded instructions above.
+        const count = (bytes: Uint8Array) => {
+          const body = Buffer.from(bytes);
+          let result = 0;
+          const fence = Buffer.from([254, 3, 0]);
+          for (
+            let offset = body.indexOf(fence);
+            offset !== -1;
+            offset = body.indexOf(fence, offset + 3)
+          )
+            result++;
+          return result;
+        };
+        for (const [name, required] of Object.entries(fences))
+          assert.equal(count(module.critical[name]!), required, `${name} fence count differs`);
+        total = module.bodies.reduce((sum, body) => sum + count(body), 0);
+        if (expected !== undefined) assert.equal(total, expected, 'module fence total differs');
+      }
+    }
+    console.log(
+      `verified PostgreSQL Wasm concurrency contract: total=${total} SetLatch=2 ResetLatch=1 WaitEventSetWait=1`,
+    );
+  } catch (error) {
+    console.error(`verify-postmaster-concurrency-contract: ${(error as Error).message}`);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-concurrency-contract.test.mts b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-concurrency-contract.test.mts
new file mode 100644
index 000000000..0c60434c0
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-concurrency-contract.test.mts
@@ -0,0 +1,100 @@
+import assert from 'node:assert/strict';
+import test from 'node:test';
+import {
+  fences,
+  structure,
+  watInventory,
+  checkInventory,
+  receipt,
+  verifyReceipt,
+} from './verify-postmaster-concurrency-contract.mts';
+
+import { minimalPostmaster as moduleBytes } from '../../testdata/minimal-postmaster.mts';
+export function packedWat(loads = 1, ands = 2) {
+  return [
+    ' (export "SetLatch" (func $19))',
+    ' (export "ResetLatch" (func $20))',
+    ' (export "WaitEventSetWait" (func $21))',
+    ' (data $0 (i32.const 0) "(atomic.fence) is data, not code")',
+    ' (func $19 (param $0 i32)',
+    '  (atomic.fence)',
+    '  (i32.atomic.rmw.or (local.get $0) (i32.const 1))',
+    '  (atomic.fence)',
+    ' )',
+    ' (func $20 (param $0 i32)',
+    '  (i32.atomic.rmw.and (local.get $0) (i32.const -2))',
+    '  (atomic.fence)',
+    ' )',
+    ' (func $21 (param $0 i32)',
+    '  (i32.atomic.rmw.or (local.get $0) (i32.const 2))',
+    ...Array.from({ length: loads }, () => '  (i32.atomic.load (local.get $0))'),
+    ...Array.from({ length: ands }, () => '  (i32.atomic.rmw.and (local.get $0) (i32.const -3))'),
+    '  (atomic.fence)',
+    ' )',
+  ];
+}
+test('verifies final-module structure and decoded latch atomics, rejecting drift and aliases', async () => {
+  const data = moduleBytes(true, true);
+  assert.equal(structure(data).bodies.length, 4);
+  assert.throws(() => structure(moduleBytes(false)), /shared/);
+  assert.throws(() => structure(data.subarray(0, -1)), /truncated/);
+  assert.throws(
+    () => structure(Buffer.concat([data, Buffer.from([3, 1, 0])])),
+    /duplicate section/,
+  );
+  const inventory = await watInventory(packedWat());
+  assert.equal(inventory.total['atomic.fence'], 4);
+  checkInventory(inventory, 4);
+  assert.throws(() => checkInventory(inventory, 5), /total differs/);
+  assert.throws(
+    () =>
+      checkInventory({
+        ...inventory,
+        functions: {
+          ...inventory.functions,
+          SetLatch: { ...inventory.functions.SetLatch!, 'atomic.fence': 1 },
+        },
+      }),
+    /SetLatch/,
+  );
+  for (const [loads, ands] of [
+    [0, 2],
+    [1, 1],
+  ]) {
+    const invalid = await watInventory(packedWat(loads, ands));
+    assert.throws(() => checkInventory(invalid));
+  }
+  await assert.rejects(
+    watInventory(
+      packedWat().map((line) => line.replace('"SetLatch" (func $19)', '"SetLatch" (func $20)')),
+    ),
+    /share one/,
+  );
+  await assert.rejects(watInventory(packedWat().map((line) => `${line}\r`)), /CR text/);
+  await assert.rejects(
+    watInventory(packedWat().filter((line) => !line.startsWith(' (func $19'))),
+    /function bodies/,
+  );
+});
+
+test('receipt binds exact module bytes and preserves exact numeric and field contracts', async () => {
+  const data = moduleBytes();
+  const text = receipt(
+    data,
+    await watInventory(packedWat()),
+    '2'.repeat(64),
+    'wasm-dis version 130',
+  );
+  assert.equal(verifyReceipt(text, data, 4).atomic_fence_total, '4');
+  for (const changed of [
+    text.replace('i32_atomic_rmw_or_set_latch=1', 'i32_atomic_rmw_or_set_latch=0'),
+    text.replace('atomic_fence_total=4', 'atomic_fence_total=04'),
+    text.replace('atomic_fence_total=4', 'atomic_fence_total=4.0'),
+    text.replace('i32_atomic_load_total=1', 'i32_atomic_load_total=0'),
+    text.replace('schema=', 'extra='),
+    text.slice(0, -1),
+    text.replaceAll('\n', '\r\n'),
+  ])
+    assert.throws(() => verifyReceipt(changed, data, 4));
+  assert.throws(() => verifyReceipt(text, moduleBytes(true, true), 4), /does not identify/);
+});
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-wasm-import.mts b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-wasm-import.mts
new file mode 100644
index 000000000..a8b7125f8
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-wasm-import.mts
@@ -0,0 +1,132 @@
+#!/usr/bin/env bun
+import { readFileSync } from 'node:fs';
+
+const namespace = 'oliphaunt_postmaster_v1';
+const valueTypes = new Set([0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x70, 0x6f, 0x69]);
+
+export class Reader {
+  offset = 0;
+  constructor(readonly data: Uint8Array) {}
+  byte(): number {
+    if (this.offset >= this.data.length) throw new Error('truncated WebAssembly module');
+    return this.data[this.offset++]!;
+  }
+  uleb(bits = 32): bigint {
+    let value = 0n;
+    for (let shift = 0; shift < bits; shift += 7) {
+      const byte = this.byte();
+      value |= BigInt(byte & 127) << BigInt(shift);
+      if (!(byte & 128)) {
+        if (value >= 1n << BigInt(bits)) break;
+        return value;
+      }
+    }
+    throw new Error('out-of-range unsigned LEB');
+  }
+  size(): number {
+    return Number(this.uleb());
+  }
+  take(size: number): Uint8Array {
+    if (size > this.data.length - this.offset) throw new Error('truncated WebAssembly section');
+    const bytes = this.data.subarray(this.offset, this.offset + size);
+    this.offset += size;
+    return bytes;
+  }
+  name(): string {
+    return new TextDecoder('utf-8', { fatal: true }).decode(this.take(this.size()));
+  }
+  valueType(): number {
+    const value = this.byte();
+    if (!valueTypes.has(value)) throw new Error(`unsupported value type ${value}`);
+    return value;
+  }
+  limits(): number {
+    const flags = this.size();
+    if (flags & ~7) throw new Error('unsupported import limits flags');
+    this.uleb(flags & 4 ? 64 : 32);
+    if (flags & 1) this.uleb(flags & 4 ? 64 : 32);
+    return flags;
+  }
+}
+
+export function verify(data: Uint8Array): void {
+  const reader = new Reader(data);
+  if (!Buffer.from(reader.take(8)).equals(Buffer.from([0, 97, 115, 109, 1, 0, 0, 0]))) {
+    throw new Error('not a core WebAssembly version-1 module');
+  }
+  const types: number[][][] = [];
+  const imports: { module: string; name: string; type?: number }[] = [];
+  const seen = new Set();
+  while (reader.offset < data.length) {
+    const id = reader.byte();
+    const section = new Reader(reader.take(reader.size()));
+    if (id !== 1 && id !== 2) continue;
+    if (seen.has(id)) throw new Error(`duplicate section ${id}`);
+    seen.add(id);
+    const count = section.size();
+    for (let i = 0; i < count; i++) {
+      if (id === 1) {
+        if (section.byte() !== 0x60) throw new Error('non-function type in postmaster module');
+        const signature: number[][] = [];
+        for (let vector = 0; vector < 2; vector++) {
+          const values: number[] = [];
+          const length = section.size();
+          for (let j = 0; j < length; j++) values.push(section.valueType());
+          signature.push(values);
+        }
+        types.push(signature);
+      } else {
+        const entry: (typeof imports)[number] = { module: section.name(), name: section.name() };
+        const kind = section.byte();
+        switch (kind) {
+          case 0:
+            entry.type = section.size();
+            break;
+          case 1:
+            section.valueType();
+            section.limits();
+            break;
+          case 2:
+            section.limits();
+            break;
+          case 3:
+            section.valueType();
+            section.byte();
+            break;
+          case 4:
+            section.byte();
+            section.size();
+            break;
+          default:
+            throw new Error(`unknown import kind ${kind}`);
+        }
+        imports.push(entry);
+      }
+    }
+    if (section.offset !== section.data.length) throw new Error(`trailing bytes in section ${id}`);
+  }
+  const named = imports.filter((entry) => entry.name === 'fd_sync_range');
+  if (named.some((entry) => entry.module !== namespace))
+    throw new Error('forbidden fd_sync_range import alias');
+  if (named.length !== 1) throw new Error(`expected exactly one ${namespace}.fd_sync_range import`);
+  const index = named[0]!.type;
+  if (index === undefined || index >= types.length)
+    throw new Error('invalid function type index for fd_sync_range');
+  if (JSON.stringify(types[index]) !== '[[127,126,126,127],[127]]') {
+    throw new Error('fd_sync_range signature must be (i32,i64,i64,i32)->(i32)');
+  }
+}
+
+if (import.meta.main) {
+  try {
+    if (process.argv.length !== 3)
+      throw new Error('usage: verify-postmaster-wasm-import.mts POSTGRES_WASM');
+    verify(readFileSync(process.argv[2]!));
+    console.log(
+      `verified required postmaster imports: ${namespace}.fd_sync_range(i32,i64,i64,i32)->(i32)`,
+    );
+  } catch (error) {
+    console.error(`verify-postmaster-wasm-import: ${(error as Error).message}`);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-wasm-import.test.mts b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-wasm-import.test.mts
new file mode 100644
index 000000000..dede915b5
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-wasm-import.test.mts
@@ -0,0 +1,34 @@
+import { test } from 'bun:test';
+import { strict as assert } from 'node:assert';
+import { verify } from './verify-postmaster-wasm-import.mts';
+
+const header = [0, 97, 115, 109, 1, 0, 0, 0];
+const name = (text: string) => [text.length, ...Buffer.from(text)];
+function module(
+  namespace = 'oliphaunt_postmaster_v1',
+  field = 'fd_sync_range',
+  params = [127, 126, 126, 127],
+  copies = 1,
+) {
+  const type = [1, 96, params.length, ...params, 1, 127];
+  const entry = [...name(namespace), ...name(field), 0, 0];
+  const imports = [copies, ...Array.from({ length: copies }, () => entry).flat()];
+  return Buffer.from([...header, 1, type.length, ...type, 2, imports.length, ...imports]);
+}
+
+test('required postmaster import preserves namespace, uniqueness, and ABI', () => {
+  verify(module());
+  assert.throws(() => verify(module('wasix_32v1')), /forbidden/);
+  assert.throws(() => verify(module(undefined, 'fd_sync')), /exactly one/);
+  assert.throws(() => verify(module(undefined, undefined, [127])), /signature/);
+  assert.throws(() => verify(module(undefined, undefined, undefined, 2)), /exactly one/);
+  assert.throws(() => verify(module(undefined, undefined, undefined, 0)), /exactly one/);
+  const valid = module();
+  for (let length = 0; length < valid.length; length++)
+    assert.throws(() => verify(valid.subarray(0, length)));
+  assert.throws(() => verify(Buffer.concat([valid, Buffer.from([1, 1, 0])])), /duplicate/);
+  assert.throws(() => verify(Buffer.from([...header, 1, 255, 255, 255, 255, 31])), /LEB/);
+  const invalidIndex = Buffer.from(valid);
+  invalidIndex[invalidIndex.length - 1] = 1;
+  assert.throws(() => verify(invalidIndex), /type index/);
+});
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/capabilities.tsv b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/capabilities.tsv
similarity index 78%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/capabilities.tsv
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/capabilities.tsv
index 0e3245d92..2e64be3d2 100644
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/capabilities.tsv
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/capabilities.tsv
@@ -1,10 +1,10 @@
 # id	owner	basis	source_paths	probe	postgres_behavior	status
-source-identity	oliphaunt	pinned-production-inputs	project:sources.lock.toml;project:runtime/bin/verify-source-lock.py	source-lock	Reject mismatched PostgreSQL, Wasmer, wasix-libc, gitlink, or patch inputs before building	supported
+source-identity	oliphaunt	pinned-production-inputs	project:runtime/bin/prepare-upstream-checkouts.sh;project:lib/common.sh	source-checkout	Verify exact clean source pins and bind applied patches to build receipts	supported
 runtime-build-receipt	oliphaunt	exact-build-provenance	project:lib/common.sh;project:runtime/bin/build-runtime.sh	common-receipt-negative-tests	Select only the receipt-bound producer and executor for the current host ABI	supported
-postmaster-product-executor	oliphaunt+wasmer	compiler-free-product-role	project:runtime/bin/build-runtime.sh;project:bin/build-sealed-headless-carrier.sh;project:lib/verify-sealed-carrier.py	unit:postmaster-executor-cli	Run only the admitted initdb/postgres carrier without general Wasmer commands	supported
+postmaster-product-executor	oliphaunt+wasmer	compiler-free-product-role	project:runtime/bin/build-runtime.sh;project:bin/build-sealed-headless-carrier.sh;project:lib/verify-sealed-carrier.mts	unit:postmaster-executor-cli	Run only the admitted initdb/postgres carrier without general Wasmer commands	supported
 postmaster-host-task-budget	oliphaunt+wasmer	bounded-product-profile	project:profiles/runtime-task-budgets/embedded-postmaster-v1.tsv;project:profiles/runtime-footprints/embedded-concurrent-v1.gucs	unit:concurrent-task-CAS	Reject work beyond the receipt-bound process and blocking-worker budget	supported
-sealed-host-carrier	oliphaunt	immutable-complete-payload	project:bin/build-sealed-headless-carrier.sh;project:bin/verify-sealed-headless-carrier.sh;project:lib/verify-sealed-carrier.py	sealed-carrier-builder-tests	Verify every payload byte, module, AOT artifact, receipt, and manifest before execution	supported
-sealed-side-module-closure	oliphaunt+postgres	policy-derived-complete-closure	project:runtime/policies/sealed-side-modules.v1.tsv;project:lib/guest_build_provenance.py;project:lib/verify-sealed-carrier.py	sealed-carrier-builder-tests	Package every declared PostgreSQL loadable side module and byte-identical alias	supported
+sealed-host-carrier	oliphaunt	immutable-complete-payload	project:bin/build-sealed-headless-carrier.sh;project:bin/verify-sealed-headless-carrier.sh;project:lib/verify-sealed-carrier.mts	sealed-carrier-builder-tests	Verify every payload byte, module, AOT artifact, receipt, and manifest before execution	supported
+sealed-side-module-closure	oliphaunt+postgres	policy-derived-complete-closure	project:runtime/policies/sealed-side-modules.v1.tsv;project:lib/guest-build-provenance.mts;project:lib/verify-sealed-carrier.mts	sealed-carrier-builder-tests	Package every declared PostgreSQL loadable side module and byte-identical alias	supported
 exec-backend-fresh-instance	wasmer+postgres	selected-process-model	wasmer:lib/wasix/src/bin_factory/exec.rs;project:postgres/patches/0004-wasix-core-execbackend-initdb-runtime.patch	spawn-shmem-reattach	Create each backend in a fresh instance and restore only explicit PostgreSQL handoff state	supported
 dynamic-linking	wasmer+postgres	sealed-declared-modules	wasmer:lib/wasix/src/state/linker.rs;project:runtime/policies/sealed-side-modules.v1.tsv	dynamic-dlopen	Load only carrier-declared PostgreSQL side modules through the sealed linker	supported
 shared-file-mmap	wasmer+wasix-libc+postgres	fixed-address-shared-backing	wasmer:lib/wasix/src/syscalls/wasix/mem_mmap.rs;project:postgres/overlays/wasix-core/src/backend/port/sysv_shmem.c	mmap-fixed;spawn-shmem-reattach	Reattach coherent PostgreSQL shared memory at the exact guest address	supported-linux-gnu
@@ -13,7 +13,7 @@ shared-mapping-lifecycle	wasmer	generation-safe-owned-registry	wasmer:lib/wasix/
 cross-instance-latch-order	wasmer+postgres	packed-atomic-state-and-fences	wasmer:lib/compiler-llvm/src/translator/code.rs;project:postgres/patches/0008-wasix-packed-atomic-latch-state.patch	final-module:atomic-latch-state;stress:backend-wave	Preserve PostgreSQL latch progress across instances sharing one backing	supported
 listener-epoll	wasmer+wasix-libc	open-file-description-lifecycle	wasmer:lib/wasix/src/os/epoll/mod.rs;project:runtime/probes/epoll_ofd_lifecycle_probe.c	epoll-ofd-lifecycle	Keep listener readiness and duplicated descriptor registration semantics correct	supported-linux-gnu
 child-wait-and-signals	wasmer+wasix-libc+postgres	retry-and-owned-process-state	project:postgres/patches/0006-wasix-retry-proc-join-on-eintr.patch;wasmer:lib/wasix/src/os/task/process.rs	exec-wait-signal	Preserve child exit, signal, interruption, and cleanup semantics	supported
-aot-artifact-identity	wasmer+oliphaunt	receipt-bound-generic-baseline	wasmer:lib/compiler-llvm/src/compiler.rs;wasmer:lib/oliphaunt-wasix-postmaster-executor/src/bin/compiler.rs;project:lib/verify-sealed-carrier.py	unit:sealed-manifest-cpu-policy	Reject AOT from another target, CPU policy, runtime ABI, artifact ABI, or guest module	supported
+aot-artifact-identity	wasmer+oliphaunt	receipt-bound-generic-baseline	wasmer:lib/compiler-llvm/src/compiler.rs;wasmer:lib/oliphaunt-wasix-postmaster-executor/src/bin/compiler.rs;project:lib/verify-sealed-carrier.mts	unit:sealed-manifest-cpu-policy	Reject AOT from another target, CPU policy, runtime ABI, artifact ABI, or guest module	supported
 directory-durability	wasmer+postgres	exact-open-directory-fsync	wasmer:lib/virtual-fs/src/host_fs.rs;project:runtime/probes/directory_fsync_probe.c	directory-fsync	Apply PostgreSQL directory durability barriers to the exact opened directory	supported-linux-gnu
 regression-subset	postgres	product-lifecycle-harness	project:bin/run-wasix-regress-subset.sh	pg-regress-subset	Run PostgreSQL regression cases through the real postmaster and libpq	supported
-immutable-deployment	oliphaunt	atomic-no-replace-publication	project:bin/deploy-immutable-sealed-carrier.sh;project:bin/verify-immutable-sealed-carrier.sh;project:lib/immutable-carrier.py	immutable-carrier-tests	Deploy and verify one immutable carrier closure without mixed-build payloads	supported-linux-gnu
+immutable-deployment	oliphaunt	atomic-no-replace-publication	project:bin/deploy-immutable-sealed-carrier.sh;project:bin/verify-immutable-sealed-carrier.sh;project:lib/immutable-carrier.mts	immutable-carrier-tests	Deploy and verify one immutable carrier closure without mixed-build payloads	supported-linux-gnu
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch
similarity index 85%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch
index 850ff2721..0462a8b78 100644
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch
@@ -20,7 +20,7 @@ index 19464e5..8c36cb7 100644
  [[package]]
  name = "bytecheck"
  version = "0.8.2"
-@@ -3716,6 +3705,32 @@ dependencies = [
+@@ -3716,6 +3705,26 @@ dependencies = [
   "ruzstd",
  ]
  
@@ -31,23 +31,17 @@ index 19464e5..8c36cb7 100644
 + "anyhow",
 + "async-trait",
 + "dirs",
-+ "futures",
 + "hex",
 + "libc",
 + "serde",
 + "serde_json",
 + "sha2 0.11.0",
 + "tempfile",
-+ "tokio",
 + "tracing",
 + "wasmer",
-+ "wasmer-compiler-cranelift",
-+ "wasmer-compiler-llvm",
 + "wasmer-types",
 + "wasmer-vm",
 + "wasmer-wasix",
-+ "wasmparser 0.247.0",
-+ "wat",
 +]
 +
  [[package]]
@@ -81,14 +75,6 @@ diff --git a/Cargo.toml b/Cargo.toml
 index 6ce7557..fa7d8dc 100644
 --- a/Cargo.toml
 +++ b/Cargo.toml
-@@ -63,6 +63,7 @@ members = [
- 	"lib/wasi-types",
- 	"lib/wasix",
- 	"lib/journal",
-+	"lib/oliphaunt-wasix-postmaster-executor",
- 	"lib/swift",
- 	"lib/package",
- 	"tests/integration/cli",
 @@ -110,7 +111,6 @@ bindgen = "0.72.1"
  bitflags = "2.11.0"
  blake3 = "1.0"
@@ -6480,6339 +6466,6 @@ index abee089..9d51660 100644
 +        );
 +    }
 +}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/Cargo.toml b/lib/oliphaunt-wasix-postmaster-executor/Cargo.toml
-new file mode 100644
-index 0000000..29fbc87
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/Cargo.toml
-@@ -0,0 +1,112 @@
-+[package]
-+name = "oliphaunt-wasix-postmaster-executor"
-+description = "Compiler-free sealed executor for the Oliphaunt WASIX PostgreSQL postmaster product"
-+publish = false
-+authors.workspace = true
-+edition.workspace = true
-+homepage.workspace = true
-+license.workspace = true
-+repository.workspace = true
-+rust-version.workspace = true
-+version.workspace = true
-+
-+[[bin]]
-+name = "oliphaunt-wasix-postmaster-executor"
-+path = "src/bin/executor.rs"
-+doc = false
-+required-features = ["product-executor"]
-+
-+[[bin]]
-+name = "oliphaunt-wasix-start-proof"
-+path = "src/bin/start-proof.rs"
-+doc = false
-+required-features = ["start-proof-tool"]
-+
-+[[bin]]
-+name = "oliphaunt-wasix-memory-profile"
-+path = "src/bin/memory-profile.rs"
-+doc = false
-+required-features = ["memory-profile-tool"]
-+
-+[[bin]]
-+name = "oliphaunt-wasix-postmaster-compiler"
-+path = "src/bin/compiler.rs"
-+doc = false
-+required-features = ["product-compiler"]
-+
-+[features]
-+default = []
-+product-executor = [
-+	"memory-profile-core",
-+	"dep:tokio",
-+	"wasmer-wasix/ctrlc",
-+	"wasmer-wasix/disable-all-logging",
-+	"wasmer-wasix/host-fs",
-+	"wasmer-wasix/host-threads",
-+	"wasmer-wasix/host-vnet",
-+	"wasmer-wasix/sys-poll",
-+]
-+# Build-time-only analyzer for the exact raw executable's WebAssembly start
-+# closure. This binary is never copied into the compiler-free carrier.
-+start-proof-tool = ["dep:wasmparser"]
-+# Build-time-only exact WebAssembly memory-contract sealer. This binary is
-+# never copied into the compiler-free carrier.
-+memory-profile-core = ["dep:wasmer-vm"]
-+memory-profile-tool = ["memory-profile-core", "dep:wasmparser"]
-+# Build-time-only LLVM AOT producer with the product's explicit static-memory
-+# tunables. Build it in a target directory separate from product-executor so
-+# the shipped executor remains compiler-free.
-+product-compiler = [
-+	"memory-profile-tool",
-+	"dep:wasmer-compiler-llvm",
-+	"wasmer/llvm",
-+]
-+# Preserve the generic CLI's historical writable-snapshot search path without
-+# making a user cache-directory resolver part of the product executor closure.
-+compat-cache-dir = ["dep:dirs"]
-+# These features exist only for the sealed artifact loader's positive-path
-+# tests. Production builds must use --no-default-features and never enable
-+# either compiler-bearing test feature.
-+cranelift = ["memory-profile-core", "dep:wasmer-compiler-cranelift", "wasmer/cranelift"]
-+wat = ["wasmer/wat"]
-+
-+[dependencies]
-+anyhow.workspace = true
-+async-trait.workspace = true
-+dirs = { workspace = true, optional = true }
-+hex.workspace = true
-+libc.workspace = true
-+serde = { workspace = true, features = ["derive"] }
-+serde_json.workspace = true
-+sha2.workspace = true
-+tempfile.workspace = true
-+tokio = { workspace = true, default-features = false, optional = true, features = [
-+	"rt-multi-thread",
-+	"time",
-+] }
-+tracing.workspace = true
-+wasmer = { version = "=7.2.0-alpha.2", path = "../api", default-features = false, features = [
-+	"headless",
-+	"sys",
-+] }
-+wasmer-compiler-cranelift = { version = "=7.2.0-alpha.2", path = "../compiler-cranelift", optional = true }
-+wasmer-compiler-llvm = { version = "=7.2.0-alpha.2", path = "../compiler-llvm", optional = true }
-+wasmer-types = { version = "=7.2.0-alpha.2", path = "../types", default-features = false, features = [
-+	"std",
-+] }
-+wasmer-vm = { version = "=7.2.0-alpha.2", path = "../vm", default-features = false, optional = true }
-+wasmparser = { workspace = true, optional = true }
-+wasmer-wasix = { version = "=0.702.0-alpha.2", path = "../wasix", default-features = false, features = [
-+	"sys-minimal",
-+] }
-+
-+[dev-dependencies]
-+futures.workspace = true
-+wat.workspace = true
-+
-+[package.metadata.oliphaunt-executor-policy]
-+compiler-free = true
-+exact-module-count = 29
-+network = "host-only"
-+package-resolution = false
-+runtime-compilation = false
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/args.rs b/lib/oliphaunt-wasix-postmaster-executor/src/args.rs
-new file mode 100644
-index 0000000..0a9b33b
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/args.rs
-@@ -0,0 +1,436 @@
-+//! Strict command-line contract for the sealed PostgreSQL executor.
-+
-+use std::{collections::HashSet, ffi::OsString, path::PathBuf};
-+
-+use anyhow::{Context, Error, bail, ensure};
-+
-+/// Parsed top-level product command.
-+#[derive(Debug, Clone, PartialEq, Eq)]
-+pub enum Command {
-+    /// Print the executor version without initializing a runtime.
-+    Version,
-+    /// Execute one member of an exact sealed PostgreSQL carrier.
-+    Run(RunOptions),
-+}
-+
-+/// One explicit host-to-guest directory mapping.
-+#[derive(Debug, Clone, PartialEq, Eq)]
-+pub struct VolumeSpec {
-+    /// Host directory, canonicalized immediately before execution.
-+    pub host: PathBuf,
-+    /// Absolute normalized Unix-style guest path.
-+    pub guest: String,
-+}
-+
-+/// Complete, closed execution request.
-+#[derive(Debug, Clone, PartialEq, Eq)]
-+pub struct RunOptions {
-+    /// Suppress executor-owned informational output.
-+    pub quiet: bool,
-+    /// Exact sealed carrier manifest.
-+    pub manifest: PathBuf,
-+    /// Wasmer host stack allocation requested by the carrier recipe.
-+    pub stack_size: usize,
-+    /// Explicit host filesystem mappings.
-+    pub volumes: Vec,
-+    /// Selected `bin/initdb` or `bin/postgres` carrier member.
-+    pub input: PathBuf,
-+    /// Arguments passed to the selected PostgreSQL executable.
-+    pub guest_args: Vec,
-+}
-+
-+#[derive(Default)]
-+struct SeenOptions {
-+    quiet: bool,
-+    disable_cache: bool,
-+    manifest: bool,
-+    stack_size: bool,
-+    exceptions: bool,
-+    threads: bool,
-+    networking: bool,
-+}
-+
-+impl SeenOptions {
-+    fn once(slot: &mut bool, option: &str) -> Result<(), Error> {
-+        ensure!(!*slot, "duplicate product executor option '{option}'");
-+        *slot = true;
-+        Ok(())
-+    }
-+}
-+
-+/// Parse the exact product command from an argv sequence, including argv[0].
-+pub fn parse_from(arguments: I) -> Result
-+where
-+    I: IntoIterator,
-+    S: Into,
-+{
-+    let arguments = arguments.into_iter().map(Into::into).collect::>();
-+    ensure!(!arguments.is_empty(), "product executor argv is empty");
-+    let tail = &arguments[1..];
-+
-+    if tail == [OsString::from("--version")] {
-+        return Ok(Command::Version);
-+    }
-+    ensure!(
-+        tail.first().is_some_and(|value| value == "run"),
-+        "expected exactly 'run' or '--version'"
-+    );
-+
-+    parse_run(&tail[1..]).map(Command::Run)
-+}
-+
-+fn parse_run(arguments: &[OsString]) -> Result {
-+    let mut seen = SeenOptions::default();
-+    let mut manifest = None;
-+    let mut stack_size = None;
-+    let mut volumes = Vec::new();
-+    let mut input = None;
-+    let mut index = 0;
-+
-+    while index < arguments.len() {
-+        let argument = &arguments[index];
-+        if argument == "--" {
-+            bail!("guest argument separator '--' appeared before the carrier executable");
-+        }
-+
-+        let Some(text) = argument.to_str() else {
-+            input = Some(PathBuf::from(argument));
-+            index += 1;
-+            break;
-+        };
-+        if !text.starts_with("--") {
-+            input = Some(PathBuf::from(argument));
-+            index += 1;
-+            break;
-+        }
-+
-+        let (name, inline_value) = text
-+            .split_once('=')
-+            .map_or((text, None), |(name, value)| (name, Some(value)));
-+        match name {
-+            "--quiet" => {
-+                reject_inline_value(name, inline_value)?;
-+                SeenOptions::once(&mut seen.quiet, name)?;
-+            }
-+            "--disable-cache" => {
-+                reject_inline_value(name, inline_value)?;
-+                SeenOptions::once(&mut seen.disable_cache, name)?;
-+            }
-+            "--enable-exceptions" => {
-+                reject_inline_value(name, inline_value)?;
-+                SeenOptions::once(&mut seen.exceptions, name)?;
-+            }
-+            "--enable-threads" => {
-+                reject_inline_value(name, inline_value)?;
-+                SeenOptions::once(&mut seen.threads, name)?;
-+            }
-+            "--net" => {
-+                reject_inline_value(name, inline_value)?;
-+                SeenOptions::once(&mut seen.networking, name)?;
-+            }
-+            "--sealed-module-manifest" => {
-+                SeenOptions::once(&mut seen.manifest, name)?;
-+                manifest = Some(PathBuf::from(take_os_value(
-+                    arguments,
-+                    &mut index,
-+                    name,
-+                    inline_value,
-+                )?));
-+            }
-+            "--stack-size" => {
-+                SeenOptions::once(&mut seen.stack_size, name)?;
-+                let value = take_utf8_value(arguments, &mut index, name, inline_value)?;
-+                let parsed = value
-+                    .parse::()
-+                    .with_context(|| format!("invalid value for {name}: '{value}'"))?;
-+                ensure!(parsed > 0, "{name} must be greater than zero");
-+                stack_size = Some(parsed);
-+            }
-+            "--volume" => {
-+                let value = take_utf8_value(arguments, &mut index, name, inline_value)?;
-+                volumes.push(parse_volume(&value)?);
-+            }
-+            _ => bail!("unsupported product executor option '{name}'"),
-+        }
-+        index += 1;
-+    }
-+
-+    let input = input.context("sealed carrier executable is required")?;
-+    let guest_args = if index == arguments.len() {
-+        Vec::new()
-+    } else {
-+        ensure!(
-+            arguments[index] == "--",
-+            "arguments after the carrier executable require the '--' separator"
-+        );
-+        arguments[index + 1..]
-+            .iter()
-+            .map(|argument| {
-+                argument
-+                    .to_str()
-+                    .map(ToOwned::to_owned)
-+                    .context("PostgreSQL guest arguments must be valid UTF-8")
-+            })
-+            .collect::, _>>()?
-+    };
-+
-+    ensure!(
-+        seen.disable_cache,
-+        "--disable-cache is required by the sealed executor contract"
-+    );
-+    ensure!(
-+        seen.exceptions,
-+        "--enable-exceptions is required by the sealed carrier ABI"
-+    );
-+    ensure!(
-+        seen.threads,
-+        "--enable-threads is required by the sealed carrier ABI"
-+    );
-+    ensure!(
-+        seen.networking,
-+        "--net is required by the PostgreSQL postmaster contract"
-+    );
-+    ensure!(
-+        !volumes.is_empty(),
-+        "at least one explicit --volume is required"
-+    );
-+
-+    let manifest = manifest.context("--sealed-module-manifest is required")?;
-+    let stack_size = stack_size.context("--stack-size is required")?;
-+    let mut guest_mounts = HashSet::new();
-+    for volume in &volumes {
-+        ensure!(
-+            guest_mounts.insert(volume.guest.as_str()),
-+            "duplicate guest volume mount '{}'",
-+            volume.guest
-+        );
-+    }
-+
-+    Ok(RunOptions {
-+        quiet: seen.quiet,
-+        manifest,
-+        stack_size,
-+        volumes,
-+        input,
-+        guest_args,
-+    })
-+}
-+
-+fn reject_inline_value(option: &str, value: Option<&str>) -> Result<(), Error> {
-+    ensure!(value.is_none(), "flag '{option}' does not accept a value");
-+    Ok(())
-+}
-+
-+fn take_os_value(
-+    arguments: &[OsString],
-+    index: &mut usize,
-+    option: &str,
-+    inline_value: Option<&str>,
-+) -> Result {
-+    if let Some(value) = inline_value {
-+        ensure!(!value.is_empty(), "{option} requires a non-empty value");
-+        return Ok(OsString::from(value));
-+    }
-+    *index = index.checked_add(1).context("argument index overflow")?;
-+    let value = arguments
-+        .get(*index)
-+        .with_context(|| format!("{option} requires a value"))?;
-+    ensure!(!value.is_empty(), "{option} requires a non-empty value");
-+    Ok(value.clone())
-+}
-+
-+fn take_utf8_value(
-+    arguments: &[OsString],
-+    index: &mut usize,
-+    option: &str,
-+    inline_value: Option<&str>,
-+) -> Result {
-+    let value = take_os_value(arguments, index, option, inline_value)?;
-+    value
-+        .into_string()
-+        .map_err(|_| anyhow::anyhow!("{option} requires a valid UTF-8 value"))
-+}
-+
-+fn parse_volume(value: &str) -> Result {
-+    let (host, guest) = value
-+        .rsplit_once(':')
-+        .context("--volume requires an explicit HOST_DIR:GUEST_DIR mapping")?;
-+    ensure!(
-+        !host.is_empty(),
-+        "--volume host directory must not be empty"
-+    );
-+    validate_guest_path(guest)?;
-+    Ok(VolumeSpec {
-+        host: PathBuf::from(host),
-+        guest: guest.to_owned(),
-+    })
-+}
-+
-+pub(crate) fn validate_guest_path(path: &str) -> Result<(), Error> {
-+    ensure!(
-+        path.starts_with('/'),
-+        "--volume guest path must be absolute"
-+    );
-+    ensure!(
-+        path == "/" || !path.ends_with('/'),
-+        "--volume guest path must be normalized"
-+    );
-+    ensure!(
-+        !path.contains("//"),
-+        "--volume guest path must be normalized"
-+    );
-+    ensure!(
-+        path.split('/')
-+            .all(|component| component != "." && component != ".."),
-+        "--volume guest path must not contain '.' or '..' components"
-+    );
-+    Ok(())
-+}
-+
-+#[cfg(test)]
-+mod tests {
-+    use super::*;
-+
-+    fn valid_args() -> Vec {
-+        [
-+            "executor",
-+            "run",
-+            "--quiet",
-+            "--disable-cache",
-+            "--stack-size",
-+            "33554432",
-+            "--sealed-module-manifest",
-+            "/carrier/manifest.json",
-+            "--enable-exceptions",
-+            "--enable-threads",
-+            "--net",
-+            "--volume",
-+            "/carrier:/carrier",
-+            "--volume=/runtime/lib:/lib",
-+            "/carrier/bin/postgres",
-+            "--",
-+            "-D",
-+            "/pgdata",
-+        ]
-+        .into_iter()
-+        .map(OsString::from)
-+        .collect()
-+    }
-+
-+    #[test]
-+    fn parses_the_complete_closed_product_contract() {
-+        let command = parse_from(valid_args()).unwrap();
-+        let Command::Run(run) = command else {
-+            panic!("expected run command");
-+        };
-+        assert!(run.quiet);
-+        assert_eq!(run.stack_size, 33_554_432);
-+        assert_eq!(run.manifest, PathBuf::from("/carrier/manifest.json"));
-+        assert_eq!(run.input, PathBuf::from("/carrier/bin/postgres"));
-+        assert_eq!(run.guest_args, ["-D", "/pgdata"]);
-+        assert_eq!(run.volumes.len(), 2);
-+    }
-+
-+    #[test]
-+    fn version_is_the_only_non_run_surface() {
-+        assert_eq!(
-+            parse_from(["executor", "--version"]).unwrap(),
-+            Command::Version
-+        );
-+        assert!(parse_from(["executor", "--help"]).is_err());
-+        assert!(parse_from(["executor", "package", "list"]).is_err());
-+        assert!(parse_from(["executor", "--version", "extra"]).is_err());
-+    }
-+
-+    #[test]
-+    fn denies_unknown_generic_wasmer_options() {
-+        for denied in [
-+            "--llvm",
-+            "--cranelift",
-+            "--singlepass",
-+            "--use",
-+            "--include-webc",
-+            "--map-command",
-+            "--env",
-+            "--http-client",
-+            "--invoke",
-+            "--entrypoint",
-+            "--enable-simd",
-+            "--net=ipv4:allow=127.0.0.1:*",
-+        ] {
-+            let mut args = valid_args();
-+            args.insert(2, OsString::from(denied));
-+            assert!(parse_from(args).is_err(), "accepted denied option {denied}");
-+        }
-+    }
-+
-+    #[test]
-+    fn required_abi_and_cache_assertions_fail_closed() {
-+        for required in [
-+            "--disable-cache",
-+            "--enable-exceptions",
-+            "--enable-threads",
-+            "--net",
-+            "--stack-size",
-+            "--sealed-module-manifest",
-+        ] {
-+            let mut args = valid_args();
-+            let index = args.iter().position(|arg| arg == required).unwrap();
-+            args.remove(index);
-+            if matches!(required, "--stack-size" | "--sealed-module-manifest") {
-+                args.remove(index);
-+            }
-+            assert!(
-+                parse_from(args).is_err(),
-+                "accepted request without {required}"
-+            );
-+        }
-+    }
-+
-+    #[test]
-+    fn duplicate_scalar_options_and_guest_mounts_are_rejected() {
-+        let mut duplicate_flag = valid_args();
-+        duplicate_flag.insert(2, OsString::from("--enable-threads"));
-+        assert!(parse_from(duplicate_flag).is_err());
-+
-+        let mut duplicate_mount = valid_args();
-+        duplicate_mount.splice(
-+            2..2,
-+            [OsString::from("--volume"), OsString::from("/other:/lib")],
-+        );
-+        assert!(parse_from(duplicate_mount).is_err());
-+    }
-+
-+    #[test]
-+    fn executable_and_guest_arguments_have_an_unambiguous_boundary() {
-+        let mut missing_separator = valid_args();
-+        let separator = missing_separator
-+            .iter()
-+            .position(|arg| arg == "--")
-+            .unwrap();
-+        missing_separator.remove(separator);
-+        assert!(parse_from(missing_separator).is_err());
-+
-+        let mut separator_before_input = valid_args();
-+        let input = separator_before_input
-+            .iter()
-+            .position(|arg| arg == "/carrier/bin/postgres")
-+            .unwrap();
-+        separator_before_input.insert(input, OsString::from("--"));
-+        assert!(parse_from(separator_before_input).is_err());
-+    }
-+
-+    #[test]
-+    fn volumes_require_normalized_absolute_guest_paths() {
-+        for invalid in [
-+            "/host:relative",
-+            "/host:/a/../b",
-+            "/host:/a//b",
-+            "/host:/a/",
-+            ":/guest",
-+        ] {
-+            assert!(parse_volume(invalid).is_err(), "accepted {invalid}");
-+        }
-+        assert_eq!(parse_volume("C:\\data:/data").unwrap().guest, "/data");
-+    }
-+}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/bin/compiler.rs b/lib/oliphaunt-wasix-postmaster-executor/src/bin/compiler.rs
-new file mode 100644
-index 0000000..c323d4d
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/bin/compiler.rs
-@@ -0,0 +1,211 @@
-+use std::{env, ffi::OsString, fs, num::NonZeroUsize, path::PathBuf};
-+
-+use anyhow::{Context, Result, bail, ensure};
-+use oliphaunt_wasix_postmaster_executor::memory_profile::{
-+    LinearMemoryProfile, compiler_tunables_for_target, derived_static_style,
-+    validate_serialized_memory_plans, verify_module_bytes,
-+};
-+use wasmer::{
-+    Engine, Module,
-+    sys::{CompilerConfig, NativeEngineExt},
-+};
-+use wasmer_compiler_llvm::{LLVM, LLVMOptLevel};
-+use wasmer_types::{
-+    Features, ModuleHash,
-+    target::{CpuFeature, Target, Triple},
-+};
-+
-+const USAGE: &str = "usage: oliphaunt-wasix-postmaster-compiler --llvm --llvm-opt-level aggressive [--compiler-threads N] --enable-exceptions --enable-threads -o OUTPUT MODULE\n       oliphaunt-wasix-postmaster-compiler verify-aot MODULE ARTIFACT";
-+
-+#[derive(Debug)]
-+struct Options {
-+    input: PathBuf,
-+    output: PathBuf,
-+    compiler_threads: Option,
-+}
-+
-+fn take_value(arguments: &[OsString], index: &mut usize, option: &str) -> Result {
-+    *index += 1;
-+    arguments
-+        .get(*index)
-+        .cloned()
-+        .with_context(|| format!("{option} requires a value; {USAGE}"))
-+}
-+
-+fn parse() -> Result> {
-+    let arguments: Vec<_> = env::args_os().skip(1).collect();
-+    if arguments.len() == 1 && arguments[0] == "--version" {
-+        println!(
-+            "oliphaunt-wasix-postmaster-compiler {} {}",
-+            oliphaunt_wasix_postmaster_executor::VERSION,
-+            LinearMemoryProfile::embedded().id()
-+        );
-+        return Ok(None);
-+    }
-+
-+    let mut llvm = false;
-+    let mut exceptions = false;
-+    let mut threads = false;
-+    let mut output = None;
-+    let mut input = None;
-+    let mut compiler_threads = None;
-+    let mut index = 0;
-+    while index < arguments.len() {
-+        let argument = &arguments[index];
-+        match argument.to_str() {
-+            Some("--llvm") => llvm = true,
-+            Some("--enable-exceptions") => exceptions = true,
-+            Some("--enable-threads") => threads = true,
-+            Some("--llvm-opt-level") => {
-+                let value =
-+                    take_value(&arguments, &mut index, argument.to_string_lossy().as_ref())?;
-+                ensure!(
-+                    value == "aggressive",
-+                    "the product compiler requires --llvm-opt-level aggressive"
-+                );
-+            }
-+            Some("--compiler-threads") => {
-+                let value =
-+                    take_value(&arguments, &mut index, argument.to_string_lossy().as_ref())?;
-+                let parsed = value
-+                    .to_str()
-+                    .context("compiler thread count is not UTF-8")?
-+                    .parse::()
-+                    .context("compiler thread count is not an integer")?;
-+                compiler_threads = Some(
-+                    NonZeroUsize::new(parsed).context("compiler thread count must be positive")?,
-+                );
-+            }
-+            Some("-o") => {
-+                ensure!(output.is_none(), "output path was supplied more than once");
-+                output = Some(PathBuf::from(take_value(&arguments, &mut index, "-o")?));
-+            }
-+            Some(value) if value.starts_with('-') => {
-+                bail!("unsupported option '{value}'; {USAGE}")
-+            }
-+            _ => {
-+                ensure!(
-+                    input.is_none(),
-+                    "more than one input module was supplied; {USAGE}"
-+                );
-+                input = Some(PathBuf::from(argument));
-+            }
-+        }
-+        index += 1;
-+    }
-+    ensure!(llvm, "the product compiler requires --llvm");
-+    ensure!(
-+        exceptions,
-+        "the product compiler requires --enable-exceptions"
-+    );
-+    ensure!(threads, "the product compiler requires --enable-threads");
-+    Ok(Some(Options {
-+        input: input.with_context(|| USAGE.to_owned())?,
-+        output: output.with_context(|| USAGE.to_owned())?,
-+        compiler_threads,
-+    }))
-+}
-+
-+fn main() -> Result<()> {
-+    let arguments: Vec<_> = env::args_os().skip(1).collect();
-+    if arguments.first().and_then(|value| value.to_str()) == Some("verify-aot") {
-+        ensure!(arguments.len() == 3, "verify-aot requires MODULE ARTIFACT");
-+        return verify_aot(PathBuf::from(&arguments[1]), PathBuf::from(&arguments[2]));
-+    }
-+    let Some(options) = parse()? else {
-+        return Ok(());
-+    };
-+    let module_bytes = fs::read(&options.input)
-+        .with_context(|| format!("read sealed module {}", options.input.display()))?;
-+    verify_module_bytes(&module_bytes)
-+        .with_context(|| format!("admit sealed module {}", options.input.display()))?;
-+
-+    let mut compiler = LLVM::new();
-+    compiler
-+        .opt_level(LLVMOptLevel::Aggressive)
-+        .non_volatile_memops(true)
-+        .readonly_funcref_table(true);
-+    if let Some(threads) = options.compiler_threads {
-+        compiler.num_threads(threads);
-+    }
-+
-+    // The carrier promises a relocatable architecture baseline. Never inherit
-+    // host features here: doing so would make an otherwise receipt-identical
-+    // artifact capable of trapping with SIGILL on an older embedded host.
-+    let target = Target::new(Triple::host(), CpuFeature::set());
-+    let tunables = compiler_tunables_for_target(&target)
-+        .context("derive product compiler linear-memory profile")?;
-+    let (static_bound_pages, static_offset_guard_bytes) = derived_static_style(&tunables, 0)
-+        .context("prove product compiler linear-memory allocation style")?;
-+    let mut features = Features::default();
-+    features.threads(true).exceptions(true);
-+    let mut engine = Engine::new(
-+        Box::new(compiler) as Box,
-+        target,
-+        features,
-+    );
-+    engine.set_tunables(tunables);
-+
-+    eprintln!(
-+        "Compiler: llvm; profile: {}; guest-max-pages: {}; static-bound-pages: {}; static-offset-guard-bytes: {}",
-+        LinearMemoryProfile::embedded().id(),
-+        LinearMemoryProfile::embedded().maximum_pages(),
-+        static_bound_pages,
-+        static_offset_guard_bytes
-+    );
-+    let module = Module::new(&engine, &module_bytes)
-+        .with_context(|| format!("compile sealed module {}", options.input.display()))?;
-+    module
-+        .serialize_to_file(&options.output)
-+        .with_context(|| format!("write AOT artifact {}", options.output.display()))?;
-+    Ok(())
-+}
-+
-+fn verify_aot(module_path: PathBuf, artifact_path: PathBuf) -> Result<()> {
-+    let module_bytes = fs::read(&module_path)
-+        .with_context(|| format!("read sealed module {}", module_path.display()))?;
-+    verify_module_bytes(&module_bytes)
-+        .with_context(|| format!("admit sealed module {}", module_path.display()))?;
-+    let target = Target::new(Triple::host(), CpuFeature::set());
-+    let tunables = compiler_tunables_for_target(&target)
-+        .context("derive product verifier linear-memory profile")?;
-+    let mut features = Features::default();
-+    features.threads(true).exceptions(true);
-+    let mut compiler = LLVM::new();
-+    compiler
-+        .opt_level(LLVMOptLevel::Aggressive)
-+        .non_volatile_memops(true)
-+        .readonly_funcref_table(true);
-+    let mut engine = Engine::new(
-+        Box::new(compiler) as Box,
-+        target,
-+        features,
-+    );
-+    engine.set_tunables(tunables);
-+
-+    let file = fs::File::open(&artifact_path)
-+        .with_context(|| format!("open AOT artifact {}", artifact_path.display()))?;
-+    let mapping = wasmer::sys::OwnedBuffer::from_file(&file)
-+        .with_context(|| format!("map AOT artifact {}", artifact_path.display()))?;
-+    let expected_hash = ModuleHash::new(&module_bytes);
-+    let inspected = engine
-+        .inspect_serialized_artifact(&mapping)
-+        .with_context(|| format!("inspect AOT artifact {}", artifact_path.display()))?;
-+    ensure!(
-+        inspected == expected_hash,
-+        "AOT embedded module hash differs"
-+    );
-+    // SAFETY: the exact opened artifact was structurally inspected above and
-+    // remains owned by this process. Dropping the pending activation rolls all
-+    // code registrations back after the allocation plan is attested.
-+    let pending = unsafe { engine.deserialize_from_mmapped_buffer_detached_pending(mapping) }
-+        .with_context(|| format!("admit AOT artifact {}", artifact_path.display()))?;
-+    ensure!(
-+        pending.module_hash() == Some(expected_hash),
-+        "activated AOT embedded module hash differs"
-+    );
-+    validate_serialized_memory_plans(&pending.linear_memory_plans())
-+        .context("AOT linear-memory allocation plan differs")?;
-+    println!("{}", expected_hash);
-+    Ok(())
-+}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/bin/executor.rs b/lib/oliphaunt-wasix-postmaster-executor/src/bin/executor.rs
-new file mode 100644
-index 0000000..f7c24a4
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/bin/executor.rs
-@@ -0,0 +1,3 @@
-+fn main() {
-+    std::process::exit(oliphaunt_wasix_postmaster_executor::run_from_env());
-+}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/bin/memory-profile.rs b/lib/oliphaunt-wasix-postmaster-executor/src/bin/memory-profile.rs
-new file mode 100644
-index 0000000..a6eb793
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/bin/memory-profile.rs
-@@ -0,0 +1,48 @@
-+use std::{env, ffi::OsString, path::PathBuf};
-+
-+use anyhow::{Context, Result, bail, ensure};
-+use oliphaunt_wasix_postmaster_executor::memory_profile::{
-+    profile_json, seal_module, verify_module,
-+};
-+
-+const USAGE: &str = "usage: oliphaunt-wasix-memory-profile --profile-json\n       oliphaunt-wasix-memory-profile verify MODULE\n       oliphaunt-wasix-memory-profile seal --output SEALED --receipt RECEIPT MODULE";
-+
-+fn take_path(arguments: &mut impl Iterator, name: &str) -> Result {
-+    arguments
-+        .next()
-+        .map(PathBuf::from)
-+        .with_context(|| format!("missing {name}; {USAGE}"))
-+}
-+
-+fn main() -> Result<()> {
-+    let mut arguments = env::args_os().skip(1);
-+    let command = arguments.next().with_context(|| USAGE.to_owned())?;
-+    if command == "--profile-json" {
-+        ensure!(arguments.next().is_none(), "{USAGE}");
-+        println!("{}", profile_json()?);
-+        return Ok(());
-+    }
-+    if command == "verify" {
-+        let module = take_path(&mut arguments, "MODULE")?;
-+        ensure!(arguments.next().is_none(), "{USAGE}");
-+        println!("{}", verify_module(&module)?);
-+        return Ok(());
-+    }
-+    if command == "seal" {
-+        ensure!(
-+            arguments.next().as_deref() == Some("--output".as_ref()),
-+            "{USAGE}"
-+        );
-+        let output = take_path(&mut arguments, "SEALED")?;
-+        ensure!(
-+            arguments.next().as_deref() == Some("--receipt".as_ref()),
-+            "{USAGE}"
-+        );
-+        let receipt = take_path(&mut arguments, "RECEIPT")?;
-+        let module = take_path(&mut arguments, "MODULE")?;
-+        ensure!(arguments.next().is_none(), "{USAGE}");
-+        seal_module(&module, &output, &receipt)?;
-+        return Ok(());
-+    }
-+    bail!("unknown command '{}'; {USAGE}", command.to_string_lossy())
-+}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/bin/start-proof.rs b/lib/oliphaunt-wasix-postmaster-executor/src/bin/start-proof.rs
-new file mode 100644
-index 0000000..558aa5c
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/bin/start-proof.rs
-@@ -0,0 +1,561 @@
-+use std::{
-+    collections::{BTreeMap, BTreeSet, VecDeque},
-+    env, fs,
-+    ops::Range,
-+};
-+
-+use anyhow::{Context, Result, bail, ensure};
-+use serde::Serialize;
-+use sha2::{Digest, Sha256};
-+use wasmparser::{ExternalKind, Operator, Parser, Payload, TypeRef, Validator, WasmFeatures};
-+
-+const PROOF_SCHEMA: &str = "oliphaunt.wasix-postmaster.deterministic-start-proof.v1";
-+const POLICY: &str = "llvm-shared-memory-init-restricted-effects.v1";
-+const START_EXPORT: &str = "__wasm_init_memory";
-+
-+#[derive(Debug, Default)]
-+struct Effects {
-+    allowed: bool,
-+    rejection: Option,
-+    calls: BTreeMap,
-+    global_gets: BTreeSet,
-+    global_sets: BTreeSet,
-+    memory_init: Vec,
-+    data_drop: Vec,
-+    block_count: u32,
-+    br_count: u32,
-+    br_table_count: u32,
-+    memory_fill_count: u32,
-+    cmpxchg_count: u32,
-+    atomic_store_count: u32,
-+    atomic_notify_count: u32,
-+    atomic_wait_count: u32,
-+}
-+
-+#[derive(Debug)]
-+struct BodySummary {
-+    range: Range,
-+    effects: Effects,
-+}
-+
-+#[derive(Debug, Serialize)]
-+#[serde(rename_all = "kebab-case")]
-+struct Proof {
-+    schema: &'static str,
-+    analyzer_policy: &'static str,
-+    module_sha256: String,
-+    proof_sha256: String,
-+    start_function_index: u32,
-+    start_function_export: &'static str,
-+    transitive_function_indices: Vec,
-+    imported_function_calls: u32,
-+    memory_reads: &'static str,
-+    memory_effects: &'static str,
-+    global_effects: &'static str,
-+    table_effects: &'static str,
-+    requires_fresh_zeroed_memory: bool,
-+    ordinary_start_execution_per_instance: bool,
-+    first_instance_full_byte_validation: bool,
-+}
-+
-+fn main() -> Result<()> {
-+    let mut arguments = env::args().skip(1);
-+    let path = arguments
-+        .next()
-+        .context("usage: oliphaunt-wasix-start-proof MODULE | --policy-id")?;
-+    if path == "--policy-id" {
-+        ensure!(
-+            arguments.next().is_none(),
-+            "--policy-id accepts no arguments"
-+        );
-+        println!("{POLICY}");
-+        return Ok(());
-+    }
-+    ensure!(
-+        arguments.next().is_none(),
-+        "analyzer accepts exactly one module"
-+    );
-+    let bytes = fs::read(&path).with_context(|| format!("read {path}"))?;
-+    Validator::new_with_features(WasmFeatures::default() | WasmFeatures::THREADS)
-+        .validate_all(&bytes)
-+        .context("validate input WebAssembly")?;
-+
-+    let module_sha256 = hex::encode(Sha256::digest(&bytes));
-+    let mut imported_functions = 0_u32;
-+    let mut imported_globals = Vec::new();
-+    let mut shared_memory_imports = 0_u32;
-+    let mut start = None;
-+    let mut function_exports = BTreeMap::new();
-+    let mut bodies = BTreeMap::new();
-+    let mut local_body = 0_u32;
-+    let mut passive_data = BTreeMap::new();
-+
-+    for payload in Parser::new(0).parse_all(&bytes) {
-+        match payload? {
-+            Payload::ImportSection(section) => {
-+                for import in section.into_imports() {
-+                    let import = import?;
-+                    match import.ty {
-+                        TypeRef::Func(_) | TypeRef::FuncExact(_) => imported_functions += 1,
-+                        TypeRef::Global(ty) => {
-+                            imported_globals.push((
-+                                import.module.to_owned(),
-+                                import.name.to_owned(),
-+                                ty,
-+                            ));
-+                        }
-+                        TypeRef::Memory(ty)
-+                            if import.module == "env" && import.name == "memory" && ty.shared =>
-+                        {
-+                            shared_memory_imports += 1;
-+                        }
-+                        _ => {}
-+                    }
-+                }
-+            }
-+            Payload::ExportSection(section) => {
-+                for export in section {
-+                    let export = export?;
-+                    if export.kind == ExternalKind::Func {
-+                        function_exports.insert(export.name.to_owned(), export.index);
-+                    }
-+                }
-+            }
-+            Payload::StartSection { func, .. } => start = Some(func),
-+            Payload::CodeSectionEntry(body) => {
-+                let index = imported_functions + local_body;
-+                local_body += 1;
-+                bodies.insert(
-+                    index,
-+                    BodySummary {
-+                        range: body.range(),
-+                        effects: analyze_body(body)?,
-+                    },
-+                );
-+            }
-+            Payload::DataSection(section) => {
-+                for (index, data) in section.into_iter().enumerate() {
-+                    let data = data?;
-+                    ensure!(
-+                        matches!(data.kind, wasmparser::DataKind::Passive),
-+                        "deterministic-start policy rejects active data segment {index}"
-+                    );
-+                    passive_data.insert(index as u32, data.data.len());
-+                }
-+            }
-+            _ => {}
-+        }
-+    }
-+
-+    ensure!(
-+        shared_memory_imports == 1,
-+        "policy requires one shared env.memory import"
-+    );
-+    let start = start.context("module has no start section")?;
-+    ensure!(
-+        function_exports.get(START_EXPORT) == Some(&start),
-+        "module start is not exported as {START_EXPORT}"
-+    );
-+    ensure!(start >= imported_functions, "module start is imported");
-+
-+    let mut closure = BTreeSet::new();
-+    let mut queue = VecDeque::from([start]);
-+    while let Some(index) = queue.pop_front() {
-+        if !closure.insert(index) {
-+            continue;
-+        }
-+        ensure!(
-+            index >= imported_functions,
-+            "start closure calls imported function {index}"
-+        );
-+        let body = bodies
-+            .get(&index)
-+            .with_context(|| format!("missing body for local function {index}"))?;
-+        ensure!(
-+            body.effects.allowed,
-+            "function {index} is outside restricted-effects policy: {}",
-+            body.effects
-+                .rejection
-+                .as_deref()
-+                .unwrap_or("unknown operator")
-+        );
-+        for called in body.effects.calls.keys() {
-+            if *called < imported_functions {
-+                bail!("start closure calls imported function {called}");
-+            }
-+            queue.push_back(*called);
-+        }
-+    }
-+
-+    validate_call_shape(start, &closure, &bodies)?;
-+    let start_effects = &bodies.get(&start).unwrap().effects;
-+    ensure!(
-+        start_effects.block_count == 3,
-+        "unexpected LLVM init guard block shape"
-+    );
-+    ensure!(
-+        start_effects.br_table_count == 1 && start_effects.br_count == 1,
-+        "unexpected LLVM init guard branches"
-+    );
-+    ensure!(
-+        start_effects.cmpxchg_count == 1,
-+        "policy requires one initialization-guard cmpxchg"
-+    );
-+    ensure!(
-+        start_effects.atomic_store_count == 1,
-+        "policy requires one initialization-guard store"
-+    );
-+    ensure!(
-+        start_effects.atomic_notify_count == 1,
-+        "policy requires one initialization-guard notify"
-+    );
-+    ensure!(
-+        start_effects.atomic_wait_count == 1,
-+        "policy requires one initialization-guard wait"
-+    );
-+    ensure!(
-+        start_effects.memory_fill_count == 1,
-+        "policy requires one deterministic BSS fill"
-+    );
-+    ensure!(
-+        start_effects.memory_init.len() == passive_data.len(),
-+        "every passive data segment must be initialized exactly once"
-+    );
-+    ensure!(
-+        start_effects
-+            .memory_init
-+            .iter()
-+            .copied()
-+            .collect::>()
-+            == passive_data.keys().copied().collect::>(),
-+        "memory.init coverage differs from passive data segments"
-+    );
-+    ensure!(
-+        start_effects.data_drop == vec![1, 2],
-+        "policy requires LLVM TLS segment 0 retained and segments 1/2 dropped"
-+    );
-+    ensure!(
-+        passive_data.len() == 3,
-+        "policy expects LLVM TLS/data/BSS passive segment layout"
-+    );
-+
-+    let memory_base_import = imported_globals
-+        .iter()
-+        .enumerate()
-+        .find(|(_, (module, name, ty))| {
-+            module == "env"
-+                && name == "__memory_base"
-+                && !ty.mutable
-+                && ty.content_type == wasmparser::ValType::I32
-+        })
-+        .map(|(index, _)| index as u32)
-+        .context("missing immutable i32 env.__memory_base import")?;
-+    let all_gets = closure
-+        .iter()
-+        .flat_map(|index| bodies[index].effects.global_gets.iter().copied())
-+        .collect::>();
-+    let all_sets = closure
-+        .iter()
-+        .flat_map(|index| bodies[index].effects.global_sets.iter().copied())
-+        .collect::>();
-+    ensure!(
-+        all_gets
-+            .iter()
-+            .all(|index| { *index == memory_base_import || all_sets.contains(index) }),
-+        "start closure reads a global not derived from __memory_base"
-+    );
-+    ensure!(
-+        all_sets
-+            .iter()
-+            .all(|index| *index >= imported_globals.len() as u32),
-+        "start closure mutates an imported global"
-+    );
-+    ensure!(
-+        !all_sets.is_empty(),
-+        "policy requires local numeric relocation globals"
-+    );
-+
-+    let mut proof_hasher = Sha256::new();
-+    proof_hasher.update(POLICY.as_bytes());
-+    proof_hasher.update([0]);
-+    proof_hasher.update(module_sha256.as_bytes());
-+    for index in &closure {
-+        let body = &bodies[index];
-+        proof_hasher.update(index.to_le_bytes());
-+        proof_hasher.update((body.range.len() as u64).to_le_bytes());
-+        proof_hasher.update(&bytes[body.range.clone()]);
-+    }
-+
-+    let proof = Proof {
-+        schema: PROOF_SCHEMA,
-+        analyzer_policy: POLICY,
-+        module_sha256,
-+        proof_sha256: hex::encode(proof_hasher.finalize()),
-+        start_function_index: start,
-+        start_function_export: START_EXPORT,
-+        transitive_function_indices: closure.into_iter().collect(),
-+        imported_function_calls: 0,
-+        memory_reads: "fresh-zero-atomic-guard-only",
-+        memory_effects: "passive-data-init-zero-fill-atomic-guard-only",
-+        global_effects: "local-numeric-relocations-only",
-+        table_effects: "none",
-+        requires_fresh_zeroed_memory: true,
-+        ordinary_start_execution_per_instance: true,
-+        first_instance_full_byte_validation: true,
-+    };
-+    serde_json::to_writer_pretty(std::io::stdout().lock(), &proof)?;
-+    println!();
-+    Ok(())
-+}
-+
-+fn analyze_body(body: wasmparser::FunctionBody<'_>) -> Result {
-+    let mut effects = Effects {
-+        allowed: true,
-+        ..Effects::default()
-+    };
-+    for operator in body.get_operators_reader()? {
-+        let operator = operator?;
-+        match operator {
-+            Operator::GlobalGet { global_index } => {
-+                effects.global_gets.insert(global_index);
-+            }
-+            Operator::GlobalSet { global_index } => {
-+                effects.global_sets.insert(global_index);
-+            }
-+            Operator::Call { function_index } => {
-+                let count = effects.calls.entry(function_index).or_default();
-+                *count = count.checked_add(1).context("direct call count overflow")?;
-+            }
-+            Operator::MemoryInit { data_index, mem: 0 } => effects.memory_init.push(data_index),
-+            Operator::DataDrop { data_index } => effects.data_drop.push(data_index),
-+            Operator::MemoryFill { mem: 0 } => effects.memory_fill_count += 1,
-+            Operator::I32AtomicRmwCmpxchg { memarg }
-+                if memarg.memory == 0 && memarg.offset == 0 && memarg.align == 2 =>
-+            {
-+                effects.cmpxchg_count += 1;
-+            }
-+            Operator::I32AtomicStore { memarg }
-+                if memarg.memory == 0 && memarg.offset == 0 && memarg.align == 2 =>
-+            {
-+                effects.atomic_store_count += 1;
-+            }
-+            Operator::MemoryAtomicNotify { memarg }
-+                if memarg.memory == 0 && memarg.offset == 0 && memarg.align == 2 =>
-+            {
-+                effects.atomic_notify_count += 1;
-+            }
-+            Operator::MemoryAtomicWait32 { memarg }
-+                if memarg.memory == 0 && memarg.offset == 0 && memarg.align == 2 =>
-+            {
-+                effects.atomic_wait_count += 1;
-+            }
-+            Operator::Block { .. } => effects.block_count += 1,
-+            Operator::Br { .. } => effects.br_count += 1,
-+            Operator::BrTable { .. } => effects.br_table_count += 1,
-+            Operator::I32Const { .. }
-+            | Operator::I64Const { .. }
-+            | Operator::I32Add
-+            | Operator::LocalGet { .. }
-+            | Operator::LocalSet { .. }
-+            | Operator::LocalTee { .. }
-+            | Operator::Drop
-+            | Operator::End => {}
-+            rejected => {
-+                effects.allowed = false;
-+                effects.rejection = Some(format!("{rejected:?}"));
-+                break;
-+            }
-+        }
-+    }
-+    Ok(effects)
-+}
-+
-+fn has_call_cycle(
-+    start: u32,
-+    closure: &BTreeSet,
-+    bodies: &BTreeMap,
-+) -> Result {
-+    fn visit(
-+        index: u32,
-+        closure: &BTreeSet,
-+        bodies: &BTreeMap,
-+        visiting: &mut BTreeSet,
-+        visited: &mut BTreeSet,
-+    ) -> Result {
-+        if visiting.contains(&index) {
-+            return Ok(true);
-+        }
-+        if !visited.insert(index) {
-+            return Ok(false);
-+        }
-+        visiting.insert(index);
-+        for called in bodies
-+            .get(&index)
-+            .context("missing call-graph body")?
-+            .effects
-+            .calls
-+            .keys()
-+        {
-+            ensure!(
-+                closure.contains(called),
-+                "call graph escaped analyzed closure"
-+            );
-+            if visit(*called, closure, bodies, visiting, visited)? {
-+                return Ok(true);
-+            }
-+        }
-+        visiting.remove(&index);
-+        Ok(false)
-+    }
-+
-+    visit(
-+        start,
-+        closure,
-+        bodies,
-+        &mut BTreeSet::new(),
-+        &mut BTreeSet::new(),
-+    )
-+}
-+
-+fn validate_call_shape(
-+    start: u32,
-+    closure: &BTreeSet,
-+    bodies: &BTreeMap,
-+) -> Result<()> {
-+    ensure!(
-+        closure.len() == 2,
-+        "LLVM init policy expects start plus one relocation helper"
-+    );
-+    ensure!(
-+        !has_call_cycle(start, closure, bodies)?,
-+        "start call graph is cyclic"
-+    );
-+    let helper = *closure
-+        .iter()
-+        .find(|index| **index != start)
-+        .context("relocation helper is missing")?;
-+    let start_effects = &bodies
-+        .get(&start)
-+        .context("start function body is missing")?
-+        .effects;
-+    let helper_effects = &bodies
-+        .get(&helper)
-+        .context("relocation helper body is missing")?
-+        .effects;
-+    ensure!(
-+        start_effects.calls == BTreeMap::from([(helper, 1)]),
-+        "start must call only its relocation helper exactly once"
-+    );
-+    ensure!(
-+        helper_effects.calls.is_empty(),
-+        "relocation helper must be a leaf"
-+    );
-+    Ok(())
-+}
-+
-+#[cfg(test)]
-+mod tests {
-+    use super::*;
-+
-+    fn first_body_effects(wat_source: &str) -> Effects {
-+        let bytes = wat::parse_str(wat_source).unwrap();
-+        for payload in Parser::new(0).parse_all(&bytes) {
-+            if let Payload::CodeSectionEntry(body) = payload.unwrap() {
-+                return analyze_body(body).unwrap();
-+            }
-+        }
-+        panic!("fixture has no function body");
-+    }
-+
-+    #[test]
-+    fn policy_rejects_memory_reads() {
-+        let effects =
-+            first_body_effects("(module (memory 1) (func (drop (i32.load (i32.const 0)))))");
-+        assert!(!effects.allowed);
-+        assert!(effects.rejection.unwrap().starts_with("I32Load"));
-+    }
-+
-+    #[test]
-+    fn policy_rejects_indirect_calls_and_table_effects() {
-+        let indirect = first_body_effects(
-+            "(module (type (func)) (table 1 funcref) (func (call_indirect (type 0) (i32.const 0))))",
-+        );
-+        assert!(!indirect.allowed);
-+        assert!(indirect.rejection.unwrap().starts_with("CallIndirect"));
-+
-+        let table = first_body_effects("(module (table 1 funcref) (func (drop (table.size 0))))");
-+        assert!(!table.allowed);
-+        assert!(table.rejection.unwrap().starts_with("TableSize"));
-+    }
-+
-+    #[test]
-+    fn policy_rejects_unrecognized_atomic_reads() {
-+        let effects = first_body_effects(
-+            "(module (memory 1 1 shared) (func (drop (i32.atomic.load (i32.const 0)))))",
-+        );
-+        assert!(!effects.allowed);
-+        assert!(effects.rejection.unwrap().starts_with("I32AtomicLoad"));
-+    }
-+
-+    #[test]
-+    fn call_graph_cycle_is_rejected() {
-+        let mut bodies = BTreeMap::new();
-+        let mut first = Effects {
-+            allowed: true,
-+            ..Effects::default()
-+        };
-+        first.calls.insert(11, 1);
-+        let mut second = Effects {
-+            allowed: true,
-+            ..Effects::default()
-+        };
-+        second.calls.insert(10, 1);
-+        bodies.insert(
-+            10,
-+            BodySummary {
-+                range: 0..0,
-+                effects: first,
-+            },
-+        );
-+        bodies.insert(
-+            11,
-+            BodySummary {
-+                range: 0..0,
-+                effects: second,
-+            },
-+        );
-+        assert!(has_call_cycle(10, &BTreeSet::from([10, 11]), &bodies).unwrap());
-+    }
-+
-+    #[test]
-+    fn duplicate_relocation_helper_call_is_rejected() {
-+        let mut bodies = BTreeMap::new();
-+        let mut start = Effects {
-+            allowed: true,
-+            ..Effects::default()
-+        };
-+        start.calls.insert(11, 2);
-+        bodies.insert(
-+            10,
-+            BodySummary {
-+                range: 0..0,
-+                effects: start,
-+            },
-+        );
-+        bodies.insert(
-+            11,
-+            BodySummary {
-+                range: 0..0,
-+                effects: Effects {
-+                    allowed: true,
-+                    ..Effects::default()
-+                },
-+            },
-+        );
-+
-+        let error = validate_call_shape(10, &BTreeSet::from([10, 11]), &bodies)
-+            .unwrap_err()
-+            .to_string();
-+        assert!(error.contains("exactly once"), "unexpected error: {error}");
-+    }
-+}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/execute.rs b/lib/oliphaunt-wasix-postmaster-executor/src/execute.rs
-new file mode 100644
-index 0000000..dc3eaad
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/execute.rs
-@@ -0,0 +1,246 @@
-+use std::{collections::HashSet, io::Write as _, sync::Arc};
-+
-+use anyhow::{Context, Error, ensure};
-+use wasmer_wasix::{
-+    Runtime, WasiError, WasiRuntimeError,
-+    runners::{
-+        MappedDirectory,
-+        wasi::{RuntimeOrEngine, WasiRunner},
-+    },
-+};
-+
-+#[cfg(any(unix, windows))]
-+use wasmer_wasix::os::task::HostLifecycleSupervisor;
-+
-+use crate::{
-+    VERSION,
-+    args::{Command, RunOptions, VolumeSpec},
-+    runtime::{
-+        HOST_TASK_BUDGET, SealedPostmasterRuntime, build_tokio_runtime, configure_stack,
-+        headless_engine, prepare_system_tty,
-+    },
-+    sealed,
-+};
-+
-+/// Parse process arguments and execute the requested product command.
-+pub fn run_from_env() -> i32 {
-+    let command = match crate::args::parse_from(std::env::args_os()) {
-+        Ok(command) => command,
-+        Err(error) => {
-+            eprintln!("error: {error:#}");
-+            return 2;
-+        }
-+    };
-+
-+    match command {
-+        Command::Version => {
-+            println!("oliphaunt-wasix-postmaster-executor {VERSION}");
-+            0
-+        }
-+        Command::Run(options) => exit_code_for_result(execute(options)),
-+    }
-+}
-+
-+/// Execute one strictly parsed sealed PostgreSQL request.
-+pub fn execute(options: RunOptions) -> Result<(), Error> {
-+    ensure!(
-+        options.stack_size > 0,
-+        "stack size must be greater than zero"
-+    );
-+    ensure!(
-+        !options.volumes.is_empty(),
-+        "at least one explicit host volume is required"
-+    );
-+    let resource_limits = configure_stack(options.stack_size);
-+    // This owner must remain in this stack frame until `run_wasm` has joined
-+    // the root and all fresh EXEC_BACKEND tasks. The task manager intentionally
-+    // receives only a Handle; dropping this owner earlier would stop its reactor.
-+    let tokio_runtime = build_tokio_runtime()?;
-+    let handle = tokio_runtime.handle().clone();
-+    let _runtime_guard = handle.enter();
-+
-+    let prepared = sealed::prepare(&options.manifest, &options.input)?;
-+    prepared
-+        .runtime_identity()
-+        .context("sealed manifest selected no product runtime identity")?;
-+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-+    let (code_memory_directory, code_memory_device, code_memory_inode) =
-+        prepared.strict_code_memory_directory()?;
-+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-+    let engine = headless_engine(Some((
-+        &code_memory_directory,
-+        code_memory_device,
-+        code_memory_inode,
-+    )))?;
-+    #[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
-+    let engine = headless_engine(None)?;
-+    let loaded = sealed::load(prepared, &engine)?;
-+
-+    // This scope-owned guard restores host terminal state after every normal
-+    // return, error propagation, or unwind, independent of runtime Arc clones.
-+    let (tty, _tty_restore_guard) = prepare_system_tty();
-+    let runtime = Arc::new(SealedPostmasterRuntime::new(
-+        handle,
-+        engine,
-+        loaded.module_cache.clone(),
-+        resource_limits,
-+        tty,
-+    ));
-+    let runtime: Arc = runtime;
-+
-+    let mapped_directories = resolve_volumes(&options.volumes)?;
-+    let mut runner = WasiRunner::new();
-+    apply_host_task_budget(&mut runner);
-+    runner
-+        .with_args(options.guest_args)
-+        .with_mapped_directories(mapped_directories);
-+    attach_host_lifecycle(&mut runner)?;
-+    for (guest_path, module_hash) in loaded.executables {
-+        runner.with_sealed_module(guest_path, module_hash, None);
-+    }
-+
-+    ensure!(
-+        wasmer_wasix::is_wasix_module(&loaded.module),
-+        "sealed PostgreSQL entrypoint is not a WASIX module"
-+    );
-+    let program_name = loaded.path.display().to_string();
-+    runner.run_wasm(
-+        RuntimeOrEngine::Runtime(runtime),
-+        &program_name,
-+        loaded.module,
-+        loaded.module_hash,
-+    )
-+}
-+
-+fn apply_host_task_budget(runner: &mut WasiRunner) {
-+    // WasiEnvBuilder creates the one process-tree control plane from these
-+    // capabilities. Its exact CAS admission guard therefore shares the same
-+    // receipt-bound ceiling as the host blocking-worker pool.
-+    runner.capabilities_mut().threading.max_threads = Some(HOST_TASK_BUDGET);
-+}
-+
-+fn resolve_volumes(volumes: &[VolumeSpec]) -> Result, Error> {
-+    let mut canonical_hosts = HashSet::new();
-+    let mut guest_mounts = HashSet::new();
-+    volumes
-+        .iter()
-+        .map(|volume| {
-+            crate::args::validate_guest_path(&volume.guest)?;
-+            ensure!(
-+                guest_mounts.insert(volume.guest.clone()),
-+                "duplicate guest volume mount '{}'",
-+                volume.guest
-+            );
-+            let host = volume.host.canonicalize().with_context(|| {
-+                format!(
-+                    "canonicalize host directory for --volume {}:{}",
-+                    volume.host.display(),
-+                    volume.guest
-+                )
-+            })?;
-+            ensure!(
-+                host.is_dir(),
-+                "--volume host path '{}' is not a directory",
-+                host.display()
-+            );
-+            ensure!(
-+                canonical_hosts.insert((host.clone(), volume.guest.clone())),
-+                "duplicate canonical --volume mapping '{}:{}'",
-+                host.display(),
-+                volume.guest
-+            );
-+            Ok(MappedDirectory {
-+                host,
-+                guest: volume.guest.clone(),
-+            })
-+        })
-+        .collect()
-+}
-+
-+#[cfg(any(unix, windows))]
-+fn attach_host_lifecycle(runner: &mut WasiRunner) -> Result<(), Error> {
-+    let supervisor = HostLifecycleSupervisor::install()
-+        .context("install exclusive product executor host lifecycle supervision")?;
-+    runner.with_host_lifecycle_supervisor(Arc::new(supervisor));
-+    Ok(())
-+}
-+
-+#[cfg(not(any(unix, windows)))]
-+fn attach_host_lifecycle(_runner: &mut WasiRunner) -> Result<(), Error> {
-+    Ok(())
-+}
-+
-+/// Convert an execution result to the process status used by the full CLI.
-+pub fn exit_code_for_result(result: Result<(), Error>) -> i32 {
-+    let exit_code = match result {
-+        Ok(()) => 0,
-+        Err(error) => {
-+            if let Some(exit_code) = error.chain().find_map(wasi_exit_code) {
-+                exit_code.raw()
-+            } else {
-+                eprintln!("error: {error:#}");
-+                1
-+            }
-+        }
-+    };
-+
-+    std::io::stdout().flush().ok();
-+    std::io::stderr().flush().ok();
-+    exit_code
-+}
-+
-+fn wasi_exit_code(
-+    error: &(dyn std::error::Error + 'static),
-+) -> Option {
-+    if let Some(WasiError::Exit(exit_code)) = error.downcast_ref() {
-+        return Some(*exit_code);
-+    }
-+    error
-+        .downcast_ref::()
-+        .and_then(WasiRuntimeError::as_exit_code)
-+}
-+
-+#[cfg(test)]
-+mod tests {
-+    use super::*;
-+
-+    #[test]
-+    fn product_runtime_policy_is_declared_at_the_execution_boundary() {
-+        assert_eq!(
-+            crate::runtime::POLICY_ID,
-+            "oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2"
-+        );
-+    }
-+
-+    #[test]
-+    fn product_runner_applies_the_same_guest_and_host_task_budget() {
-+        let mut runner = WasiRunner::new();
-+        apply_host_task_budget(&mut runner);
-+
-+        assert_eq!(
-+            runner.capabilities_mut().threading.max_threads,
-+            Some(crate::runtime::HOST_TASK_BUDGET)
-+        );
-+        assert_eq!(crate::runtime::HOST_TASK_BUDGET, 96);
-+    }
-+
-+    #[test]
-+    fn success_maps_to_zero() {
-+        assert_eq!(exit_code_for_result(Ok(())), 0);
-+    }
-+
-+    #[test]
-+    fn wasi_exit_status_is_preserved() {
-+        let error = Error::new(WasiError::Exit(7_u16.into()));
-+        assert_eq!(exit_code_for_result(Err(error)), 7);
-+    }
-+
-+    #[test]
-+    fn volume_resolution_requires_existing_directories() {
-+        let missing = VolumeSpec {
-+            host: std::path::Path::new("/path/that/must/not/exist").to_path_buf(),
-+            guest: "/data".to_owned(),
-+        };
-+        assert!(resolve_volumes(&[missing]).is_err());
-+    }
-+}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/lib.rs b/lib/oliphaunt-wasix-postmaster-executor/src/lib.rs
-new file mode 100644
-index 0000000..724f31e
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/lib.rs
-@@ -0,0 +1,26 @@
-+//! Closed, compiler-free executor for Oliphaunt's WASIX PostgreSQL product.
-+//!
-+//! This crate deliberately does not depend on `wasmer-cli`. Its public API is
-+//! the complete product boundary: an exact sealed carrier, host filesystem
-+//! mappings, required host networking, and PostgreSQL guest arguments.
-+
-+#![deny(missing_docs, unsafe_op_in_unsafe_fn)]
-+
-+pub mod args;
-+#[cfg(feature = "product-executor")]
-+mod execute;
-+#[cfg(feature = "memory-profile-core")]
-+pub mod memory_profile;
-+#[cfg(feature = "product-executor")]
-+mod runtime;
-+pub mod sealed;
-+
-+#[cfg(feature = "product-executor")]
-+pub use execute::{execute, exit_code_for_result, run_from_env};
-+
-+/// Exact receipt identity for the reversible bounded memory-maximum rewrite.
-+pub(crate) const SEALED_MODULE_TRANSFORMATION_ID: &str =
-+    "pinned-wasixcc-65536-to-embedded-4096-reversible-v1";
-+
-+/// Exact product executor version.
-+pub const VERSION: &str = env!("CARGO_PKG_VERSION");
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/memory_profile.rs b/lib/oliphaunt-wasix-postmaster-executor/src/memory_profile.rs
-new file mode 100644
-index 0000000..e439e32
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/memory_profile.rs
-@@ -0,0 +1,812 @@
-+//! Versioned, fail-closed linear-memory policy for the embedded postmaster.
-+//!
-+//! This is intentionally a product profile rather than a change to Wasmer's
-+//! generic defaults. The AOT producer and compiler-free executor select the
-+//! same profile without an environment or CLI override, while carrier
-+//! admission checks the resulting serialized allocation plan.
-+
-+use anyhow::{Error, Result, bail, ensure};
-+use wasmer::sys::{
-+    BaseTunables, SerializedLinearMemoryPlan, SerializedLinearMemoryStyle, Tunables,
-+};
-+use wasmer_types::{MemoryType, Pages, target::PointerWidth, target::Target};
-+use wasmer_vm::MemoryStyle;
-+
-+/// Identifier of the first bounded embedded-postmaster linear-memory profile.
-+pub const EMBEDDED_256M_V1_ID: &str =
-+    "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1";
-+
-+/// WebAssembly page size used by the profile.
-+pub const WASM_PAGE_BYTES: u64 = 65_536;
-+
-+/// Exact guest-visible maximum, in WebAssembly pages.
-+pub const EMBEDDED_256M_V1_MAXIMUM_PAGES: u32 = 4_096;
-+
-+/// Exact maximum and static reservation bound, in bytes.
-+pub const EMBEDDED_256M_V1_MAXIMUM_BYTES: u64 =
-+    (EMBEDDED_256M_V1_MAXIMUM_PAGES as u64) * WASM_PAGE_BYTES;
-+
-+/// Exact U64 static reservation required by Wasmer's unchecked LLVM accesses.
-+pub const EMBEDDED_256M_V1_STATIC_BOUND_PAGES: u32 = 65_536;
-+
-+/// Exact U64 offset guard required by Wasmer's unchecked LLVM accesses.
-+pub const EMBEDDED_256M_V1_OFFSET_GUARD_BYTES: u64 = 0x8000_0000;
-+
-+/// Maximum injected by the pinned WASIX compiler wrapper before sealing.
-+pub const PINNED_WASIXCC_MAXIMUM_PAGES: u32 = 65_536;
-+
-+/// A closed set of product linear-memory profiles.
-+///
-+/// Adding a profile requires a new enum variant, carrier schema identity, and
-+/// qualification evidence. Runtime strings never construct arbitrary bounds.
-+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-+pub enum LinearMemoryProfile {
-+    /// 256 MiB guest maximum with Wasmer's U64 4 GiB + 2 GiB trap reservation.
-+    Embedded256MiBV1,
-+}
-+
-+impl LinearMemoryProfile {
-+    /// Return the only profile selected by the current embedded product.
-+    pub const fn embedded() -> Self {
-+        Self::Embedded256MiBV1
-+    }
-+
-+    /// Return the stable profile identifier.
-+    pub const fn id(self) -> &'static str {
-+        match self {
-+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_ID,
-+        }
-+    }
-+
-+    /// Return the maximum number of WebAssembly pages.
-+    pub const fn maximum_pages(self) -> u32 {
-+        match self {
-+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_MAXIMUM_PAGES,
-+        }
-+    }
-+
-+    /// Return the maximum number of linear-memory bytes.
-+    pub const fn maximum_bytes(self) -> u64 {
-+        match self {
-+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_MAXIMUM_BYTES,
-+        }
-+    }
-+
-+    /// Return the static reservation bound in WebAssembly pages.
-+    pub const fn static_bound_pages(self) -> u32 {
-+        match self {
-+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_STATIC_BOUND_PAGES,
-+        }
-+    }
-+
-+    /// Return the static offset guard in bytes.
-+    pub const fn offset_guard_bytes(self) -> u64 {
-+        match self {
-+            Self::Embedded256MiBV1 => EMBEDDED_256M_V1_OFFSET_GUARD_BYTES,
-+        }
-+    }
-+
-+    fn tunables(self, target: &Target, boundary: &str) -> Result {
-+        let pointer_width = target.triple().pointer_width().map_err(|error| {
-+            Error::msg(format!("derive {boundary} host pointer width: {error:?}"))
-+        })?;
-+        ensure!(
-+            pointer_width == PointerWidth::U64,
-+            "{boundary} profile '{}' requires a U64 host because Wasmer's LLVM static-memory access lowering relies on the 4 GiB reservation and 2 GiB guard; got {pointer_width:?}",
-+            self.id()
-+        );
-+        ensure!(
-+            self.maximum_pages() < PINNED_WASIXCC_MAXIMUM_PAGES,
-+            "bounded profile must exclude the Wasm32 65536th-page end-wrap boundary"
-+        );
-+        let tunables = BaseTunables::for_target(target);
-+        ensure!(
-+            tunables.static_memory_bound.0 == self.static_bound_pages()
-+                && tunables.static_memory_offset_guard_size == self.offset_guard_bytes(),
-+            "{boundary} Wasmer U64 defaults drifted from profile '{}': bound={} guard={}",
-+            self.id(),
-+            tunables.static_memory_bound.0,
-+            tunables.static_memory_offset_guard_size
-+        );
-+        Ok(tunables)
-+    }
-+}
-+
-+/// Derive compiler tunables for the explicit embedded profile.
-+pub fn compiler_tunables_for_target(target: &Target) -> Result {
-+    LinearMemoryProfile::embedded().tunables(target, "AOT compiler")
-+}
-+
-+/// Derive compiler-free executor tunables for the explicit embedded profile.
-+pub fn executor_tunables_for_target(target: &Target) -> Result {
-+    LinearMemoryProfile::embedded().tunables(target, "headless executor")
-+}
-+
-+/// Return the expected module memory type used to prove the selected tunables.
-+pub fn admitted_memory_type(minimum_pages: u32) -> Result {
-+    let profile = LinearMemoryProfile::embedded();
-+    ensure!(
-+        minimum_pages <= profile.maximum_pages(),
-+        "initial memory exceeds profile maximum"
-+    );
-+    Ok(MemoryType::new(
-+        Pages(minimum_pages),
-+        Some(Pages(profile.maximum_pages())),
-+        true,
-+    ))
-+}
-+
-+/// Describe and validate the style derived by one tunables boundary.
-+pub fn derived_static_style(tunables: &BaseTunables, minimum_pages: u32) -> Result<(u32, u64)> {
-+    let profile = LinearMemoryProfile::embedded();
-+    match tunables.memory_style(&admitted_memory_type(minimum_pages)?) {
-+        MemoryStyle::Static {
-+            bound,
-+            offset_guard_size,
-+        } => {
-+            ensure!(
-+                bound.0 == profile.static_bound_pages()
-+                    && offset_guard_size == profile.offset_guard_bytes(),
-+                "derived static style differs from profile '{}'",
-+                profile.id()
-+            );
-+            Ok((bound.0, offset_guard_size))
-+        }
-+        MemoryStyle::Dynamic { .. } => {
-+            bail!("bounded profile unexpectedly derived a moving dynamic memory style")
-+        }
-+    }
-+}
-+
-+/// Reject an AOT artifact unless its module type and compiled allocation plan
-+/// exactly match the selected U64 trap-preserving embedded profile.
-+pub fn validate_serialized_memory_plans(plans: &[SerializedLinearMemoryPlan]) -> Result<()> {
-+    let profile = LinearMemoryProfile::embedded();
-+    ensure!(
-+        plans.len() == 1,
-+        "profile '{}' requires exactly one linear memory, found {}",
-+        profile.id(),
-+        plans.len()
-+    );
-+    let plan = plans[0];
-+    ensure!(
-+        plan.minimum_pages <= profile.maximum_pages(),
-+        "artifact initial memory exceeds profile maximum"
-+    );
-+    ensure!(
-+        plan.maximum_pages == Some(profile.maximum_pages()),
-+        "artifact maximum memory differs from profile '{}': {:?}",
-+        profile.id(),
-+        plan.maximum_pages
-+    );
-+    ensure!(plan.shared, "artifact linear memory is not shared");
-+    ensure!(
-+        plan.maximum_pages.unwrap() < PINNED_WASIXCC_MAXIMUM_PAGES,
-+        "artifact admits the Wasm32 65536th-page end-wrap boundary"
-+    );
-+    ensure!(
-+        plan.style
-+            == SerializedLinearMemoryStyle::Static {
-+                bound_pages: profile.static_bound_pages(),
-+                offset_guard_bytes: profile.offset_guard_bytes(),
-+            },
-+        "artifact linear-memory style is not the exact nonmoving profile: {:?}",
-+        plan.style
-+    );
-+    Ok(())
-+}
-+
-+#[cfg(feature = "memory-profile-tool")]
-+mod wasm_tool {
-+    use std::{
-+        fs::{self, OpenOptions},
-+        io::Write,
-+        ops::Range,
-+        path::Path,
-+    };
-+
-+    use anyhow::{Context, Result, bail, ensure};
-+    use serde::Serialize;
-+    use sha2::{Digest, Sha256};
-+    use wasmparser::{BinaryReader, Imports, Parser, Payload, TypeRef, Validator, WasmFeatures};
-+
-+    use super::{LinearMemoryProfile, PINNED_WASIXCC_MAXIMUM_PAGES};
-+    use crate::SEALED_MODULE_TRANSFORMATION_ID;
-+
-+    /// Schema emitted by the exact module memory-contract sealer.
-+    pub const RECEIPT_SCHEMA: &str = "oliphaunt.wasix-postmaster.linear-memory-module.v1";
-+
-+    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
-+    struct RawMemoryContract {
-+        initial_pages: u64,
-+        maximum_pages: Option,
-+        shared: bool,
-+        memory64: bool,
-+        page_size_log2: Option,
-+    }
-+
-+    #[derive(Debug, Serialize)]
-+    #[serde(rename_all = "kebab-case")]
-+    struct ModuleReceipt<'a> {
-+        schema: &'static str,
-+        profile_id: &'static str,
-+        module_sha256: String,
-+        source_module_sha256: Option,
-+        import_module: &'static str,
-+        import_name: &'static str,
-+        address_width: &'static str,
-+        initial_pages: u64,
-+        maximum_pages: u64,
-+        maximum_bytes: u64,
-+        shared: bool,
-+        static_bound_pages: u32,
-+        static_offset_guard_bytes: u64,
-+        excludes_wasm32_end_wrap: bool,
-+        transformation: &'a str,
-+    }
-+
-+    fn validate_wasm(bytes: &[u8]) -> Result<()> {
-+        Validator::new_with_features(WasmFeatures::default() | WasmFeatures::THREADS)
-+            .validate_all(bytes)
-+            .context("validate WebAssembly module")?;
-+        Ok(())
-+    }
-+
-+    fn raw_memory_contract(bytes: &[u8]) -> Result {
-+        validate_wasm(bytes)?;
-+        let mut memory_imports = Vec::new();
-+        let mut defined_memories = 0_u32;
-+        for payload in Parser::new(0).parse_all(bytes) {
-+            match payload? {
-+                Payload::ImportSection(section) => {
-+                    for import in section.into_imports() {
-+                        let import = import?;
-+                        if let TypeRef::Memory(memory) = import.ty {
-+                            memory_imports.push((
-+                                import.module.to_owned(),
-+                                import.name.to_owned(),
-+                                RawMemoryContract {
-+                                    initial_pages: memory.initial,
-+                                    maximum_pages: memory.maximum,
-+                                    shared: memory.shared,
-+                                    memory64: memory.memory64,
-+                                    page_size_log2: memory.page_size_log2,
-+                                },
-+                            ));
-+                        }
-+                    }
-+                }
-+                Payload::MemorySection(section) => {
-+                    defined_memories += section.count();
-+                }
-+                _ => {}
-+            }
-+        }
-+        ensure!(
-+            defined_memories == 0,
-+            "profile requires imported linear memory; found {defined_memories} defined memories"
-+        );
-+        ensure!(
-+            memory_imports.len() == 1,
-+            "profile requires exactly one memory import, found {}",
-+            memory_imports.len()
-+        );
-+        let (module, name, memory) = memory_imports.pop().unwrap();
-+        ensure!(
-+            module == "env" && name == "memory",
-+            "profile requires the exact env.memory import, found {module}.{name}"
-+        );
-+        ensure!(!memory.memory64, "profile requires Wasm32 linear memory");
-+        ensure!(memory.shared, "profile requires shared linear memory");
-+        ensure!(
-+            matches!(memory.page_size_log2, None | Some(16)),
-+            "profile requires the standard 64 KiB WebAssembly page"
-+        );
-+        let maximum = memory
-+            .maximum_pages
-+            .context("shared memory has no explicit maximum")?;
-+        ensure!(
-+            maximum <= u64::from(PINNED_WASIXCC_MAXIMUM_PAGES),
-+            "memory maximum exceeds Wasm32"
-+        );
-+        ensure!(
-+            memory.initial_pages <= maximum,
-+            "memory minimum exceeds maximum"
-+        );
-+        Ok(memory)
-+    }
-+
-+    fn imported_memory_maximum_span(
-+        bytes: &[u8],
-+        expected: RawMemoryContract,
-+    ) -> Result> {
-+        let mut maximum_span = None;
-+        for payload in Parser::new(0).parse_all(bytes) {
-+            let Payload::ImportSection(section) = payload? else {
-+                continue;
-+            };
-+            let section_end = section.range().end;
-+            for imports in section {
-+                let Imports::Single(offset, import) = imports? else {
-+                    bail!("compact import encodings are not supported by the memory sealer");
-+                };
-+                let TypeRef::Memory(memory) = import.ty else {
-+                    continue;
-+                };
-+                ensure!(
-+                    maximum_span.is_none(),
-+                    "profile requires exactly one memory import"
-+                );
-+                ensure!(
-+                    import.module == "env" && import.name == "memory",
-+                    "profile requires the exact env.memory import"
-+                );
-+
-+                // Parse only the validated import entry to locate its encoded
-+                // maximum. Re-encoding the module would also canonicalize
-+                // wasm-ld's relocation-width LEBs and invalidate raw custom
-+                // sections such as DWARF.
-+                let mut reader = BinaryReader::new(&bytes[offset..section_end], offset);
-+                ensure!(
-+                    reader.read_string()? == import.module,
-+                    "import module drifted"
-+                );
-+                ensure!(reader.read_string()? == import.name, "import name drifted");
-+                ensure!(reader.read_u8()? == 0x02, "memory import kind drifted");
-+                let flags = reader.read_u8()?;
-+                ensure!(flags & !0b1111 == 0, "invalid memory limits flags");
-+                let has_maximum = flags & 0b0001 != 0;
-+                let shared = flags & 0b0010 != 0;
-+                let memory64 = flags & 0b0100 != 0;
-+                let has_page_size = flags & 0b1000 != 0;
-+                ensure!(!memory64, "profile requires Wasm32 linear memory");
-+                ensure!(shared, "profile requires shared linear memory");
-+                ensure!(has_maximum, "shared memory has no explicit maximum");
-+
-+                let initial = u64::from(reader.read_var_u32()?);
-+                let start = reader.original_position();
-+                let maximum = u64::from(reader.read_var_u32()?);
-+                let end = reader.original_position();
-+                let page_size_log2 = has_page_size.then(|| reader.read_var_u32()).transpose()?;
-+                ensure!(
-+                    initial == memory.initial
-+                        && maximum == memory.maximum.context("memory maximum disappeared")?
-+                        && memory64 == memory.memory64
-+                        && shared == memory.shared
-+                        && page_size_log2 == memory.page_size_log2,
-+                    "raw memory import differs from its parsed contract"
-+                );
-+                ensure!(
-+                    expected
-+                        == (RawMemoryContract {
-+                            initial_pages: initial,
-+                            maximum_pages: Some(maximum),
-+                            shared,
-+                            memory64,
-+                            page_size_log2,
-+                        }),
-+                    "located memory import differs from the validated module contract"
-+                );
-+                maximum_span = Some(start..end);
-+            }
-+        }
-+        maximum_span.context("validated env.memory import was not located")
-+    }
-+
-+    fn encode_u32_leb_exact_width(value: u32, width: usize) -> Result> {
-+        ensure!((1..=5).contains(&width), "invalid u32 LEB width {width}");
-+        let mut remaining = u64::from(value);
-+        let mut encoded = Vec::with_capacity(width);
-+        for index in 0..width {
-+            let last = index + 1 == width;
-+            let byte = (remaining & 0x7f) as u8;
-+            remaining >>= 7;
-+            if last {
-+                ensure!(
-+                    remaining == 0,
-+                    "value {value} does not fit LEB width {width}"
-+                );
-+                encoded.push(byte);
-+            } else {
-+                encoded.push(byte | 0x80);
-+            }
-+        }
-+        Ok(encoded)
-+    }
-+
-+    fn rewrite_memory_maximum(
-+        bytes: &[u8],
-+        contract: RawMemoryContract,
-+        maximum_pages: u32,
-+    ) -> Result<(Vec, Range)> {
-+        let span = imported_memory_maximum_span(bytes, contract)?;
-+        let replacement = encode_u32_leb_exact_width(maximum_pages, span.len())?;
-+        let mut rewritten = bytes.to_vec();
-+        rewritten[span.clone()].copy_from_slice(&replacement);
-+        ensure!(
-+            rewritten.len() == bytes.len(),
-+            "memory rewrite changed module length"
-+        );
-+        ensure!(
-+            rewritten[..span.start] == bytes[..span.start]
-+                && rewritten[span.end..] == bytes[span.end..],
-+            "memory rewrite changed bytes outside the maximum field"
-+        );
-+        Ok((rewritten, span))
-+    }
-+
-+    fn receipt<'a>(
-+        bytes: &[u8],
-+        source_bytes: Option<&[u8]>,
-+        contract: RawMemoryContract,
-+        transformation: &'a str,
-+    ) -> Result> {
-+        let profile = LinearMemoryProfile::embedded();
-+        ensure!(
-+            contract.maximum_pages == Some(u64::from(profile.maximum_pages())),
-+            "module maximum does not match profile '{}'",
-+            profile.id()
-+        );
-+        ensure!(
-+            contract.initial_pages <= u64::from(profile.maximum_pages()),
-+            "module minimum exceeds profile maximum"
-+        );
-+        ensure!(
-+            profile.maximum_pages() < PINNED_WASIXCC_MAXIMUM_PAGES,
-+            "profile does not exclude the Wasm32 65536th-page boundary"
-+        );
-+        Ok(ModuleReceipt {
-+            schema: RECEIPT_SCHEMA,
-+            profile_id: profile.id(),
-+            module_sha256: hex::encode(Sha256::digest(bytes)),
-+            source_module_sha256: source_bytes.map(|source| hex::encode(Sha256::digest(source))),
-+            import_module: "env",
-+            import_name: "memory",
-+            address_width: "wasm32",
-+            initial_pages: contract.initial_pages,
-+            maximum_pages: profile.maximum_pages().into(),
-+            maximum_bytes: profile.maximum_bytes(),
-+            shared: contract.shared,
-+            static_bound_pages: profile.static_bound_pages(),
-+            static_offset_guard_bytes: profile.offset_guard_bytes(),
-+            excludes_wasm32_end_wrap: true,
-+            transformation,
-+        })
-+    }
-+
-+    fn write_new(path: &Path, bytes: &[u8]) -> Result<()> {
-+        let mut output = OpenOptions::new()
-+            .write(true)
-+            .create_new(true)
-+            .open(path)
-+            .with_context(|| format!("create {}", path.display()))?;
-+        output
-+            .write_all(bytes)
-+            .with_context(|| format!("write {}", path.display()))?;
-+        output
-+            .sync_all()
-+            .with_context(|| format!("sync {}", path.display()))?;
-+        Ok(())
-+    }
-+
-+    /// Verify a module already sealed to the selected profile and emit its
-+    /// canonical receipt JSON.
-+    pub fn verify_module_bytes(bytes: &[u8]) -> Result {
-+        let contract = raw_memory_contract(bytes)?;
-+        let receipt = receipt(bytes, None, contract, "verified-existing-v1")?;
-+        serde_json::to_string_pretty(&receipt).context("serialize module memory receipt")
-+    }
-+
-+    /// Verify a module file already sealed to the selected profile and emit
-+    /// its canonical receipt JSON.
-+    pub fn verify_module(path: &Path) -> Result {
-+        let bytes = fs::read(path).with_context(|| format!("read {}", path.display()))?;
-+        verify_module_bytes(&bytes)
-+    }
-+
-+    /// Rewrite only a pinned-toolchain module's encoded memory maximum into
-+    /// the selected profile, prove the same-width edit is byte-reversible, and
-+    /// write new module/receipt files.
-+    pub fn seal_module(input: &Path, output: &Path, receipt_path: &Path) -> Result<()> {
-+        let source = fs::read(input).with_context(|| format!("read {}", input.display()))?;
-+        let source_contract = raw_memory_contract(&source)?;
-+        ensure!(
-+            source_contract.maximum_pages == Some(u64::from(PINNED_WASIXCC_MAXIMUM_PAGES)),
-+            "sealer input must carry the pinned wasixcc {}-page maximum, found {:?}",
-+            PINNED_WASIXCC_MAXIMUM_PAGES,
-+            source_contract.maximum_pages
-+        );
-+        let profile = LinearMemoryProfile::embedded();
-+        ensure!(
-+            source_contract.initial_pages <= u64::from(profile.maximum_pages()),
-+            "module minimum cannot fit the selected profile"
-+        );
-+        let (sealed, maximum_span) =
-+            rewrite_memory_maximum(&source, source_contract, profile.maximum_pages())?;
-+        let sealed_contract = raw_memory_contract(&sealed)?;
-+        ensure!(
-+            sealed_contract.maximum_pages == Some(u64::from(profile.maximum_pages())),
-+            "sealed module maximum differs"
-+        );
-+        let sealed_span = imported_memory_maximum_span(&sealed, sealed_contract)?;
-+        ensure!(
-+            sealed_span == maximum_span,
-+            "memory-maximum field moved during the same-width rewrite"
-+        );
-+        let (reversed, reversed_span) =
-+            rewrite_memory_maximum(&sealed, sealed_contract, PINNED_WASIXCC_MAXIMUM_PAGES)?;
-+        ensure!(
-+            reversed_span == maximum_span && reversed == source,
-+            "memory-maximum transformation changed bytes outside its reversible field"
-+        );
-+        let receipt = receipt(
-+            &sealed,
-+            Some(&source),
-+            sealed_contract,
-+            SEALED_MODULE_TRANSFORMATION_ID,
-+        )?;
-+        let mut receipt_bytes =
-+            serde_json::to_vec_pretty(&receipt).context("serialize module memory receipt")?;
-+        receipt_bytes.push(b'\n');
-+        write_new(output, &sealed)?;
-+        if let Err(error) = write_new(receipt_path, &receipt_bytes) {
-+            let _ = fs::remove_file(output);
-+            return Err(error);
-+        }
-+        Ok(())
-+    }
-+
-+    /// Return a canonical JSON object describing the selected profile.
-+    pub fn profile_json() -> Result {
-+        let profile = LinearMemoryProfile::embedded();
-+        #[derive(Serialize)]
-+        #[serde(rename_all = "kebab-case")]
-+        struct Profile {
-+            id: &'static str,
-+            address_width: &'static str,
-+            supported_host_pointer_width: &'static str,
-+            maximum_pages: u32,
-+            maximum_bytes: u64,
-+            static_bound_pages: u32,
-+            static_offset_guard_bytes: u64,
-+            static_access_lowering: &'static str,
-+            requires_shared: bool,
-+            requires_import: &'static str,
-+            excludes_wasm32_end_wrap: bool,
-+        }
-+        serde_json::to_string_pretty(&Profile {
-+            id: profile.id(),
-+            address_width: "wasm32",
-+            supported_host_pointer_width: "u64",
-+            maximum_pages: profile.maximum_pages(),
-+            maximum_bytes: profile.maximum_bytes(),
-+            static_bound_pages: profile.static_bound_pages(),
-+            static_offset_guard_bytes: profile.offset_guard_bytes(),
-+            static_access_lowering: "wasmer-llvm-unchecked-reservation-and-guard-v1",
-+            requires_shared: true,
-+            requires_import: "env.memory",
-+            excludes_wasm32_end_wrap: true,
-+        })
-+        .context("serialize linear-memory profile")
-+    }
-+
-+    #[cfg(test)]
-+    mod tests {
-+        use super::*;
-+
-+        #[test]
-+        fn selected_profile_is_strictly_below_wasm32_end_wrap() {
-+            let profile = LinearMemoryProfile::embedded();
-+            assert_eq!(profile.maximum_pages(), 4_096);
-+            assert_eq!(profile.maximum_bytes(), 256 * 1024 * 1024);
-+            assert!(profile.maximum_pages() < PINNED_WASIXCC_MAXIMUM_PAGES);
-+            assert_eq!(super::super::WASM_PAGE_BYTES, 65_536);
-+        }
-+
-+        #[test]
-+        fn sealer_changes_only_the_explicit_memory_maximum() {
-+            let source = wat::parse_str(
-+                r#"(module $named_module
-+                    (import "env" "memory" (memory 2 65536 shared))
-+                    (func $read (export "read") (result i32)
-+                        i32.const 0
-+                        i32.load))"#,
-+            )
-+            .unwrap();
-+            let directory = tempfile::tempdir().unwrap();
-+            let input = directory.path().join("input.wasm");
-+            let output = directory.path().join("sealed.wasm");
-+            let receipt_path = directory.path().join("receipt.json");
-+            fs::write(&input, &source).unwrap();
-+
-+            seal_module(&input, &output, &receipt_path).unwrap();
-+            let sealed = fs::read(&output).unwrap();
-+            let contract = raw_memory_contract(&sealed).unwrap();
-+            assert_eq!(contract.maximum_pages, Some(4_096));
-+            assert_eq!(contract.initial_pages, 2);
-+            assert!(contract.shared);
-+            let receipt: serde_json::Value =
-+                serde_json::from_slice(&fs::read(receipt_path).unwrap()).unwrap();
-+            assert_eq!(
-+                receipt["source-module-sha256"],
-+                hex::encode(Sha256::digest(&source))
-+            );
-+            assert_eq!(
-+                receipt["module-sha256"],
-+                hex::encode(Sha256::digest(&sealed))
-+            );
-+            assert_eq!(receipt["transformation"], SEALED_MODULE_TRANSFORMATION_ID);
-+            verify_module_bytes(&sealed).unwrap();
-+        }
-+
-+        #[test]
-+        fn sealer_preserves_relocation_width_immediates() {
-+            // wasm-ld emits padded relocation-width LEBs. The function body
-+            // contains global.get 0 as `23 80 80 80 80 00`; canonicalizing it
-+            // would shift code offsets without updating raw DWARF sections.
-+            let source = hex::decode(concat!(
-+                "0061736d01000000010401600000021b0203656e76066d656d6f7279",
-+                "02030280800403656e760167037f00030201000a0b0109002380808080001a0b"
-+            ))
-+            .unwrap();
-+            validate_wasm(&source).unwrap();
-+            let source_contract = raw_memory_contract(&source).unwrap();
-+            let maximum_span = imported_memory_maximum_span(&source, source_contract).unwrap();
-+            assert_eq!(maximum_span, 31..34);
-+            assert_eq!(&source[maximum_span.clone()], &[0x80, 0x80, 0x04]);
-+
-+            let directory = tempfile::tempdir().unwrap();
-+            let input = directory.path().join("input.wasm");
-+            let output = directory.path().join("sealed.wasm");
-+            let receipt = directory.path().join("receipt.json");
-+            fs::write(&input, &source).unwrap();
-+            seal_module(&input, &output, &receipt).unwrap();
-+
-+            let sealed = fs::read(output).unwrap();
-+            assert_eq!(sealed.len(), source.len());
-+            assert_eq!(&sealed[maximum_span.clone()], &[0x80, 0xa0, 0x00]);
-+            assert_eq!(&sealed[..maximum_span.start], &source[..maximum_span.start]);
-+            assert_eq!(&sealed[maximum_span.end..], &source[maximum_span.end..]);
-+            assert!(
-+                sealed
-+                    .windows(6)
-+                    .any(|bytes| bytes == [0x23, 0x80, 0x80, 0x80, 0x80, 0x00])
-+            );
-+            let changed: Vec<_> = source
-+                .iter()
-+                .zip(&sealed)
-+                .enumerate()
-+                .filter_map(|(index, (before, after))| (before != after).then_some(index))
-+                .collect();
-+            assert_eq!(changed, [32, 33]);
-+
-+            let sealed_contract = raw_memory_contract(&sealed).unwrap();
-+            assert_eq!(sealed_contract.maximum_pages, Some(4_096));
-+            let (restored, restored_span) =
-+                rewrite_memory_maximum(&sealed, sealed_contract, PINNED_WASIXCC_MAXIMUM_PAGES)
-+                    .unwrap();
-+            assert_eq!(restored_span, maximum_span);
-+            assert_eq!(restored, source);
-+            verify_module_bytes(&sealed).unwrap();
-+        }
-+
-+        #[test]
-+        fn exact_width_u32_leb_encoding_fails_closed() {
-+            assert_eq!(
-+                encode_u32_leb_exact_width(4_096, 3).unwrap(),
-+                [0x80, 0xa0, 0x00]
-+            );
-+            assert_eq!(
-+                encode_u32_leb_exact_width(65_536, 3).unwrap(),
-+                [0x80, 0x80, 0x04]
-+            );
-+            assert_eq!(
-+                encode_u32_leb_exact_width(u32::MAX, 5).unwrap(),
-+                [0xff, 0xff, 0xff, 0xff, 0x0f]
-+            );
-+            assert!(encode_u32_leb_exact_width(128, 1).is_err());
-+            assert!(encode_u32_leb_exact_width(0, 0).is_err());
-+            assert!(encode_u32_leb_exact_width(0, 6).is_err());
-+        }
-+
-+        #[test]
-+        fn invalid_memory_import_shapes_fail_closed() {
-+            for wat in [
-+                r#"(module (import "other" "memory" (memory 2 65536 shared)))"#,
-+                r#"(module (memory 2 4 shared))"#,
-+                r#"(module
-+                    (import "env" "memory" (memory 2 65536 shared))
-+                    (memory 2 4 shared))"#,
-+                r#"(module
-+                    (import "env" "memory" (memory 2 65536 shared))
-+                    (import "env" "memory2" (memory 2 65536 shared)))"#,
-+            ] {
-+                assert!(raw_memory_contract(&wat::parse_str(wat).unwrap()).is_err());
-+            }
-+
-+            let compact = hex::decode(concat!(
-+                "0061736d0100000002150103656e76007f01066d656d6f7279",
-+                "020302808004"
-+            ))
-+            .unwrap();
-+            let expected = RawMemoryContract {
-+                initial_pages: 2,
-+                maximum_pages: Some(65_536),
-+                shared: true,
-+                memory64: false,
-+                page_size_log2: None,
-+            };
-+            assert!(imported_memory_maximum_span(&compact, expected).is_err());
-+        }
-+    }
-+}
-+
-+#[cfg(feature = "memory-profile-tool")]
-+pub use wasm_tool::{profile_json, seal_module, verify_module, verify_module_bytes};
-+
-+#[cfg(test)]
-+mod tests {
-+    use std::str::FromStr;
-+
-+    use wasmer_types::target::{CpuFeature, Target, Triple};
-+
-+    use super::*;
-+
-+    fn target(triple: &str) -> Target {
-+        Target::new(Triple::from_str(triple).unwrap(), CpuFeature::set())
-+    }
-+
-+    #[test]
-+    fn compiler_and_executor_independently_derive_exact_u64_trap_style() {
-+        let target = target("x86_64-unknown-linux-gnu");
-+        let compiler = compiler_tunables_for_target(&target).unwrap();
-+        let executor = executor_tunables_for_target(&target).unwrap();
-+        assert_eq!(
-+            derived_static_style(&compiler, 41).unwrap(),
-+            (65_536, 2_147_483_648)
-+        );
-+        assert_eq!(
-+            derived_static_style(&executor, 41).unwrap(),
-+            (65_536, 2_147_483_648)
-+        );
-+    }
-+
-+    #[test]
-+    fn u32_host_fails_closed_instead_of_using_unchecked_compact_static_memory() {
-+        let target = target("i686-unknown-linux-gnu");
-+        assert!(compiler_tunables_for_target(&target).is_err());
-+        assert!(executor_tunables_for_target(&target).is_err());
-+    }
-+
-+    #[test]
-+    fn serialized_plan_rejects_dynamic_or_wasm32_end_wrap_profiles() {
-+        let valid = SerializedLinearMemoryPlan {
-+            minimum_pages: 41,
-+            maximum_pages: Some(4_096),
-+            shared: true,
-+            style: SerializedLinearMemoryStyle::Static {
-+                bound_pages: 65_536,
-+                offset_guard_bytes: 2_147_483_648,
-+            },
-+        };
-+        validate_serialized_memory_plans(&[valid]).unwrap();
-+
-+        let dynamic = SerializedLinearMemoryPlan {
-+            style: SerializedLinearMemoryStyle::Dynamic {
-+                offset_guard_bytes: 2_147_483_648,
-+            },
-+            ..valid
-+        };
-+        assert!(validate_serialized_memory_plans(&[dynamic]).is_err());
-+
-+        let wrap = SerializedLinearMemoryPlan {
-+            maximum_pages: Some(65_536),
-+            style: SerializedLinearMemoryStyle::Static {
-+                bound_pages: 65_536,
-+                offset_guard_bytes: 2_147_483_648,
-+            },
-+            ..valid
-+        };
-+        assert!(validate_serialized_memory_plans(&[wrap]).is_err());
-+    }
-+}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/runtime.rs b/lib/oliphaunt-wasix-postmaster-executor/src/runtime.rs
-new file mode 100644
-index 0000000..267665b
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/runtime.rs
-@@ -0,0 +1,359 @@
-+use std::{path::Path, sync::Arc, time::Duration};
-+
-+use anyhow::{Context, Error};
-+#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-+use wasmer::sys::CodeMemoryPolicy;
-+use wasmer::{Engine, Store, sys::NativeEngineExt};
-+use wasmer_wasix::{
-+    LocalNetworking, ResourceLimits, Runtime, VirtualTaskManager,
-+    os::{TtyBridge, tty_sys::SysTty},
-+    runtime::{
-+        module_cache::ModuleCache,
-+        resolver::{MultiSource, Source},
-+        task_manager::tokio::{TokioTaskManager, TokioTaskManagerConfig},
-+    },
-+    virtual_net::DynVirtualNetworking,
-+};
-+
-+use crate::{
-+    memory_profile::{LinearMemoryProfile, derived_static_style, executor_tunables_for_target},
-+    sealed::SealedModuleCache,
-+};
-+
-+pub(crate) const POLICY_ID: &str =
-+    "oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2";
-+pub(crate) const CODE_MEMORY_POLICY_ID: &str =
-+    "wasmer.code-memory.relocated-regular-file.linux-x86_64.v1";
-+const TOKIO_WORKER_THREADS: usize = 2;
-+pub(crate) const HOST_TASK_BUDGET: usize = 96;
-+const BLOCKING_CORE_THREADS: usize = 1;
-+const BLOCKING_WORKER_IDLE_TIMEOUT: Duration = Duration::from_millis(1_000);
-+const WASIX_STACK_RLIMIT_DIVISOR: u64 = 8;
-+
-+fn task_manager_config() -> TokioTaskManagerConfig {
-+    TokioTaskManagerConfig {
-+        core_threads: BLOCKING_CORE_THREADS,
-+        max_threads: HOST_TASK_BUDGET,
-+        idle_timeout: BLOCKING_WORKER_IDLE_TIMEOUT,
-+    }
-+}
-+
-+pub(crate) fn build_tokio_runtime() -> Result {
-+    tokio::runtime::Builder::new_multi_thread()
-+        .worker_threads(TOKIO_WORKER_THREADS)
-+        .enable_all()
-+        .build()
-+        .context("build sealed WASIX-postmaster Tokio runtime")
-+}
-+
-+pub(crate) fn headless_engine(
-+    strict_directory: Option<(&Path, u64, u64)>,
-+) -> Result {
-+    // In a compiler-free build EngineBuilder cannot apply a new Features set;
-+    // the serialized artifact carries its compiled feature contract. The CLI
-+    // flags are compatibility assertions and sealed manifest admission checks
-+    // the exact {threads, exceptions} set before this engine activates bytes.
-+    let mut engine = Engine::headless();
-+    let memory_tunables = executor_tunables_for_target(engine.target())
-+        .context("derive sealed executor linear-memory profile")?;
-+    let (static_bound_pages, static_offset_guard_bytes) = derived_static_style(&memory_tunables, 0)
-+        .context("prove sealed executor linear-memory allocation style")?;
-+    tracing::debug!(
-+        linear_memory_profile_id = LinearMemoryProfile::embedded().id(),
-+        guest_maximum_pages = LinearMemoryProfile::embedded().maximum_pages(),
-+        static_bound_pages,
-+        static_offset_guard_bytes,
-+        "configure trap-preserving sealed linear-memory profile"
-+    );
-+    engine.set_tunables(memory_tunables);
-+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-+    {
-+        let (directory, expected_device, expected_inode) = strict_directory.context(
-+            "Linux x86-64 sealed execution requires an explicit strict code-memory directory",
-+        )?;
-+        let policy = CodeMemoryPolicy::strict_linux_x86_64_file_backed(directory)
-+            .map_err(Error::msg)
-+            .with_context(|| {
-+                format!(
-+                    "configure strict file-backed code memory in {}",
-+                    directory.display()
-+                )
-+            })?;
-+        anyhow::ensure!(
-+            policy.id() == CODE_MEMORY_POLICY_ID,
-+            "strict code-memory policy identity drifted: {}",
-+            policy.id()
-+        );
-+        anyhow::ensure!(
-+            policy.pinned_directory_device() == Some(expected_device),
-+            "strict code-memory directory is not on the admitted carrier-state device"
-+        );
-+        anyhow::ensure!(
-+            policy.pinned_directory_inode() == Some(expected_inode),
-+            "strict code-memory directory changed identity before its descriptor was pinned"
-+        );
-+        tracing::debug!(
-+            code_memory_policy_id = policy.id(),
-+            code_memory_directory = %policy
-+                .pinned_directory()
-+                .expect("strict policy has a pinned directory")
-+                .display(),
-+            code_memory_directory_device = expected_device,
-+            code_memory_directory_inode = expected_inode,
-+            "configure sealed WASIX-postmaster code-memory ownership"
-+        );
-+        engine
-+            .set_code_memory_policy(policy)
-+            .map_err(Error::msg)
-+            .context("install strict code-memory policy before AOT deserialization")?;
-+    }
-+    #[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
-+    {
-+        anyhow::ensure!(
-+            strict_directory.is_none(),
-+            "strict Linux x86-64 code-memory directory was supplied on an unsupported platform"
-+        );
-+        tracing::debug!(
-+            code_memory_policy_id = "wasmer.code-memory.anonymous.v1",
-+            "configure portable sealed WASIX-postmaster code-memory ownership"
-+        );
-+    }
-+    Ok(engine)
-+}
-+
-+pub(crate) fn configure_stack(stack_size: usize) -> ResourceLimits {
-+    wasmer_vm::set_stack_size(stack_size);
-+    ResourceLimits {
-+        stack: Some(((wasmer_vm::get_stack_size() as u64) / WASIX_STACK_RLIMIT_DIVISOR).max(1)),
-+    }
-+}
-+
-+pub(crate) struct TtyRestoreGuard {
-+    tty: Arc,
-+    original: wasmer_wasix::WasiTtyState,
-+}
-+
-+impl TtyRestoreGuard {
-+    fn new(tty: Arc) -> Self {
-+        Self {
-+            original: tty.tty_get(),
-+            tty,
-+        }
-+    }
-+}
-+
-+impl Drop for TtyRestoreGuard {
-+    fn drop(&mut self) {
-+        self.tty.tty_set(self.original.clone());
-+    }
-+}
-+
-+pub(crate) fn prepare_system_tty() -> (Arc, TtyRestoreGuard) {
-+    let tty = Arc::new(SysTty);
-+    let guard = TtyRestoreGuard::new(tty.clone());
-+    tty.reset();
-+    (tty, guard)
-+}
-+
-+/// Runtime with no compiler, package resolver, registry, or HTTP client.
-+#[derive(Debug)]
-+pub(crate) struct SealedPostmasterRuntime {
-+    tasks: Arc,
-+    networking: DynVirtualNetworking,
-+    engine: Engine,
-+    module_cache: Arc,
-+    resource_limits: ResourceLimits,
-+    source: Arc,
-+    tty: Arc,
-+}
-+
-+impl SealedPostmasterRuntime {
-+    pub(crate) fn new(
-+        handle: tokio::runtime::Handle,
-+        engine: Engine,
-+        module_cache: Arc,
-+        resource_limits: ResourceLimits,
-+        tty: Arc,
-+    ) -> Self {
-+        tracing::debug!(
-+            runtime_policy_id = POLICY_ID,
-+            async_worker_threads = TOKIO_WORKER_THREADS,
-+            host_task_budget = HOST_TASK_BUDGET,
-+            blocking_core_threads = BLOCKING_CORE_THREADS,
-+            blocking_worker_idle_timeout_ms = BLOCKING_WORKER_IDLE_TIMEOUT.as_millis(),
-+            "construct sealed WASIX-postmaster runtime"
-+        );
-+        let tasks: Arc = Arc::new(TokioTaskManager::new_with_config(
-+            handle,
-+            task_manager_config(),
-+        ));
-+        let networking: DynVirtualNetworking = Arc::new(LocalNetworking::default());
-+        Self {
-+            tasks,
-+            networking,
-+            engine,
-+            module_cache,
-+            resource_limits,
-+            source: Arc::new(MultiSource::default()),
-+            tty,
-+        }
-+    }
-+}
-+
-+impl Runtime for SealedPostmasterRuntime {
-+    fn networking(&self) -> &DynVirtualNetworking {
-+        &self.networking
-+    }
-+
-+    fn task_manager(&self) -> &Arc {
-+        &self.tasks
-+    }
-+
-+    fn resource_limits(&self) -> ResourceLimits {
-+        self.resource_limits
-+    }
-+
-+    fn module_cache(&self) -> Arc {
-+        self.module_cache.clone()
-+    }
-+
-+    fn source(&self) -> Arc {
-+        self.source.clone()
-+    }
-+
-+    fn engine(&self) -> Engine {
-+        self.engine.clone()
-+    }
-+
-+    fn new_store(&self) -> Store {
-+        // `wasmer-wasix/sys-minimal` does not enable its broad `sys` cfg, so
-+        // relying on Runtime's default would construct a default store rather
-+        // than one tied to this exact admitted headless engine.
-+        Store::new(self.engine.clone())
-+    }
-+
-+    fn tty(&self) -> Option<&(dyn TtyBridge + Send + Sync)> {
-+        Some(self.tty.as_ref())
-+    }
-+}
-+
-+#[cfg(test)]
-+mod tests {
-+    use super::*;
-+
-+    #[test]
-+    fn runtime_policy_identity_is_stable() {
-+        assert_eq!(
-+            POLICY_ID,
-+            "oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2"
-+        );
-+        assert_eq!(TOKIO_WORKER_THREADS, 2);
-+        assert_eq!(HOST_TASK_BUDGET, 96);
-+        assert_eq!(
-+            CODE_MEMORY_POLICY_ID,
-+            "wasmer.code-memory.relocated-regular-file.linux-x86_64.v1"
-+        );
-+    }
-+
-+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-+    #[test]
-+    fn headless_product_engine_requires_the_exact_admitted_state_identity() {
-+        use std::os::unix::fs::{MetadataExt, PermissionsExt};
-+
-+        let directory = tempfile::Builder::new()
-+            .prefix("oliphaunt-code-memory-engine-test-")
-+            .tempdir_in("/var/tmp")
-+            .unwrap();
-+        std::fs::set_permissions(directory.path(), std::fs::Permissions::from_mode(0o700)).unwrap();
-+        let device = directory.path().metadata().unwrap().dev();
-+        let inode = directory.path().metadata().unwrap().ino();
-+        headless_engine(Some((directory.path(), device, inode))).unwrap();
-+
-+        let error = headless_engine(Some((directory.path(), device.wrapping_add(1), inode)))
-+            .err()
-+            .expect("mismatched device must be rejected");
-+        assert!(error.to_string().contains("admitted carrier-state device"));
-+
-+        let error = headless_engine(Some((directory.path(), device, inode.wrapping_add(1))))
-+            .err()
-+            .expect("mismatched inode must be rejected");
-+        assert!(error.to_string().contains("changed identity"));
-+    }
-+
-+    #[test]
-+    fn runtime_has_exactly_two_tokio_workers() {
-+        let runtime = build_tokio_runtime().unwrap();
-+        assert_eq!(runtime.metrics().num_workers(), 2);
-+    }
-+
-+    #[test]
-+    fn blocking_worker_growth_is_bounded_by_the_host_task_budget() {
-+        let owner = build_tokio_runtime().unwrap();
-+        let manager =
-+            TokioTaskManager::new_with_config(owner.handle().clone(), task_manager_config());
-+
-+        assert_eq!(
-+            manager.config(),
-+            TokioTaskManagerConfig {
-+                core_threads: 1,
-+                max_threads: HOST_TASK_BUDGET,
-+                idle_timeout: Duration::from_millis(1_000),
-+            }
-+        );
-+    }
-+
-+    #[test]
-+    fn owned_tokio_runtime_keeps_handle_consumers_live() {
-+        use wasmer_wasix::runtime::task_manager::VirtualTaskManagerExt as _;
-+
-+        let owner = build_tokio_runtime().unwrap();
-+        let tasks = Arc::new(TokioTaskManager::new_with_config(
-+            owner.handle().clone(),
-+            task_manager_config(),
-+        ));
-+        let answer = tasks
-+            .spawn_and_block_on(async {
-+                tokio::time::sleep(std::time::Duration::from_millis(1)).await;
-+                42_u8
-+            })
-+            .unwrap();
-+        assert_eq!(answer, 42);
-+        drop(tasks);
-+        drop(owner);
-+    }
-+
-+    #[test]
-+    fn tty_guard_restores_state_during_unwind() {
-+        use std::sync::Mutex;
-+
-+        #[derive(Debug)]
-+        struct FakeTty(Mutex);
-+
-+        impl TtyBridge for FakeTty {
-+            fn reset(&self) {}
-+
-+            fn tty_get(&self) -> wasmer_wasix::WasiTtyState {
-+                self.0.lock().unwrap().clone()
-+            }
-+
-+            fn tty_set(&self, state: wasmer_wasix::WasiTtyState) {
-+                *self.0.lock().unwrap() = state;
-+            }
-+        }
-+
-+        let original = wasmer_wasix::WasiTtyState::default();
-+        let tty = Arc::new(FakeTty(Mutex::new(original.clone())));
-+        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe({
-+            let tty = tty.clone();
-+            move || {
-+                let _guard = TtyRestoreGuard::new(tty.clone());
-+                let mut changed = tty.tty_get();
-+                changed.echo = !changed.echo;
-+                tty.tty_set(changed);
-+                panic!("exercise unwind restoration");
-+            }
-+        }));
-+        assert!(result.is_err());
-+        assert_eq!(tty.tty_get(), original);
-+    }
-+}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/src/sealed.rs b/lib/oliphaunt-wasix-postmaster-executor/src/sealed.rs
-new file mode 100644
-index 0000000..d92c985
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/src/sealed.rs
-@@ -0,0 +1,3382 @@
-+//! Exact-five sealed carrier admission and immutable lazy AOT activation.
-+
-+use std::{
-+    collections::{BTreeMap, BTreeSet, HashMap, HashSet},
-+    fmt,
-+    fs::{self, File, OpenOptions},
-+    io::{Read, Write},
-+    path::{Component, Path, PathBuf},
-+    sync::{Arc, Mutex, OnceLock},
-+};
-+
-+use anyhow::{Context, Error, bail, ensure};
-+use serde::{Deserialize, Serialize};
-+use sha2::{Digest, Sha256};
-+use wasmer::{
-+    Engine, Module,
-+    sys::{NativeEngineExt, PendingModuleActivation},
-+};
-+use wasmer_types::{ModuleHash, target::Target};
-+use wasmer_wasix::{
-+    IntrinsicFileImmutability, intrinsic_file_immutability,
-+    runtime::{
-+        module_cache::{CacheError, ModuleCache},
-+        sealed_loader_audit::{
-+            FileAdviceAudit, FileResidencyAudit, advise_file_away, advise_file_for_one_shot_read,
-+            file_residency,
-+        },
-+    },
-+};
-+
-+use crate::SEALED_MODULE_TRANSFORMATION_ID;
-+#[cfg(feature = "memory-profile-core")]
-+use crate::memory_profile::validate_serialized_memory_plans;
-+
-+const MANIFEST_SCHEMA: &str = "oliphaunt.wasix-postmaster.sealed-aot.v5";
-+const MANIFEST_FORMAT_VERSION: u32 = 6;
-+const ARTIFACT_ABI_VERSION: u32 = 21;
-+const LINEAR_MEMORY_INSTALL_RECEIPT_SCHEMA: &str =
-+    "oliphaunt.wasix-postmaster.linear-memory-install.v1";
-+const SEALED_EXPORT_RECEIPT_PATH: &str =
-+    "share/postgresql/wasix-postmaster.sealed-export.structure.receipt";
-+const SEALED_EXPORT_SEED_PROOF_PATH: &str =
-+    "share/postgresql/wasix-postmaster.sealed-export.seed-proof.json";
-+const SEALED_EXPORT_FINAL_PROOF_PATH: &str =
-+    "share/postgresql/wasix-postmaster.sealed-export.final-proof.json";
-+const SEALED_EXPORT_ALLOWLIST_PATH: &str =
-+    "share/postgresql/wasix-postmaster.sealed-export.allowlist";
-+const SEALED_EXPORT_RECEIPT_SCHEMA: &str = "oliphaunt.wasix-postmaster.sealed-export-structure.v1";
-+const SEALED_EXPORT_PROOF_SCHEMA: &str =
-+    "oliphaunt.wasix-postmaster.sealed-export-closure-proof.v2";
-+const SEALED_EXPORT_POLICY_ID: &str = "oliphaunt.wasix-postmaster.sealed-export-closure.v1";
-+const SEALED_EXPORT_MANDATORY_POLICY_SHA256: &str =
-+    "a129bd8c380dfd148bfcd96ca4f008ac1db7976b2565bae43fea382b249f4575";
-+const SEALED_EXPORT_DLSYM_POLICY_SHA256: &str =
-+    "b695f84830efdf23cb0cc2b025dc6d0e59645139272063f4e717303c201b1637";
-+const SEALED_EXPORT_SIDE_MANIFEST_SHA256: &str =
-+    "d2759bb82f0b17f6d6314fd72b500d92a7b7c2fc5f3755fffa277038ed515b55";
-+const LINEAR_MEMORY_PROFILE_ID: &str =
-+    "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1";
-+const LINEAR_MEMORY_MAXIMUM_PAGES: u32 = 4_096;
-+const LINEAR_MEMORY_MAXIMUM_BYTES: u64 = 268_435_456;
-+const LINEAR_MEMORY_STATIC_BOUND_PAGES: u32 = 65_536;
-+const LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES: u64 = 2_147_483_648;
-+const MAX_LINEAR_MEMORY_RECEIPT_BYTES: u64 = 4 * 1024 * 1024;
-+const MAX_SEALED_EXPORT_PROOF_BYTES: u64 = 16 * 1024 * 1024;
-+const MAX_MANIFEST_BYTES: u64 = 1024 * 1024;
-+const SEALED_EXPORT_SIDE_PATHS: [&str; 27] = [
-+    "lib/libpq.so.5.18",
-+    "lib/postgresql/cyrillic_and_mic.so",
-+    "lib/postgresql/dict_snowball.so",
-+    "lib/postgresql/euc2004_sjis2004.so",
-+    "lib/postgresql/euc_cn_and_mic.so",
-+    "lib/postgresql/euc_jp_and_sjis.so",
-+    "lib/postgresql/euc_kr_and_mic.so",
-+    "lib/postgresql/euc_tw_and_big5.so",
-+    "lib/postgresql/latin2_and_win1250.so",
-+    "lib/postgresql/latin_and_mic.so",
-+    "lib/postgresql/plpgsql.so",
-+    "lib/postgresql/utf8_and_big5.so",
-+    "lib/postgresql/utf8_and_cyrillic.so",
-+    "lib/postgresql/utf8_and_euc2004.so",
-+    "lib/postgresql/utf8_and_euc_cn.so",
-+    "lib/postgresql/utf8_and_euc_jp.so",
-+    "lib/postgresql/utf8_and_euc_kr.so",
-+    "lib/postgresql/utf8_and_euc_tw.so",
-+    "lib/postgresql/utf8_and_gb18030.so",
-+    "lib/postgresql/utf8_and_gbk.so",
-+    "lib/postgresql/utf8_and_iso8859.so",
-+    "lib/postgresql/utf8_and_iso8859_1.so",
-+    "lib/postgresql/utf8_and_johab.so",
-+    "lib/postgresql/utf8_and_sjis.so",
-+    "lib/postgresql/utf8_and_sjis2004.so",
-+    "lib/postgresql/utf8_and_uhc.so",
-+    "lib/postgresql/utf8_and_win.so",
-+];
-+const EXPECTED_WASM_FEATURES: [&str; 2] = ["exceptions", "threads"];
-+const WASIX_POSTMASTER_SOURCE_LANE: &str = "wasix-postmaster";
-+const WASIX_POSTMASTER_ENTRYPOINT: &str = "runtime:postgres";
-+const REQUIRE_ZERO_WRITE_AOT_ENV: &str = "OLIPHAUNT_WASIX_REQUIRE_ZERO_WRITE_AOT";
-+const SEALED_LOADER_AUDIT_FILE_ENV: &str = "OLIPHAUNT_WASIX_SEALED_LOADER_AUDIT_FILE";
-+#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-+const CODE_MEMORY_STATE_DIRECTORY: &str = ".oliphaunt-wasix-postmaster-code-memory-v1";
-+
-+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-+enum SealedActivationPolicy {
-+    Compatibility,
-+    RequireDirectImmutable,
-+}
-+
-+impl SealedActivationPolicy {
-+    fn from_environment() -> Result {
-+        match std::env::var_os(REQUIRE_ZERO_WRITE_AOT_ENV) {
-+            None => Ok(Self::Compatibility),
-+            Some(value) if value == "0" => Ok(Self::Compatibility),
-+            Some(value) if value == "1" => Ok(Self::RequireDirectImmutable),
-+            Some(value) => bail!(
-+                "{REQUIRE_ZERO_WRITE_AOT_ENV} must be exactly 0 or 1, got {:?}",
-+                value
-+            ),
-+        }
-+    }
-+
-+    const fn requires_direct_immutable(self) -> bool {
-+        matches!(self, Self::RequireDirectImmutable)
-+    }
-+}
-+
-+/// Product executable selected from the exact sealed closure.
-+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-+pub enum SealedRuntimeIdentity {
-+    /// The carrier's `bin/initdb` executable.
-+    WasixPostmasterInitdb,
-+    /// The carrier's `bin/postgres` executable.
-+    WasixPostmasterPostgres,
-+}
-+
-+impl SealedRuntimeIdentity {
-+    /// Stable workload identity used by product-owned runtime policy.
-+    pub const fn workload_id(self) -> &'static str {
-+        match self {
-+            Self::WasixPostmasterInitdb => "runtime:initdb",
-+            Self::WasixPostmasterPostgres => "runtime:postgres",
-+        }
-+    }
-+}
-+
-+#[derive(Debug, Clone, Copy)]
-+struct ExpectedWasixPostmasterArtifact {
-+    kind: &'static str,
-+    module_path: &'static str,
-+    exec_aliases: &'static [&'static str],
-+    executable: Option,
-+}
-+
-+const EXPECTED_WASIX_POSTMASTER_EXECUTABLES: [ExpectedWasixPostmasterArtifact; 2] = [
-+    ExpectedWasixPostmasterArtifact {
-+        kind: "executable",
-+        module_path: "bin/initdb",
-+        exec_aliases: &["/bin/initdb"],
-+        executable: Some(SealedRuntimeIdentity::WasixPostmasterInitdb),
-+    },
-+    ExpectedWasixPostmasterArtifact {
-+        kind: "executable",
-+        module_path: "bin/postgres",
-+        exec_aliases: &["/bin/postgres"],
-+        executable: Some(SealedRuntimeIdentity::WasixPostmasterPostgres),
-+    },
-+];
-+
-+/// Activated entrypoint plus the still-lazy authoritative carrier closure.
-+#[derive(Debug)]
-+pub struct LoadedSealedModules {
-+    /// Selected compiler-free entrypoint module.
-+    pub module: Module,
-+    /// Hash of the selected entrypoint's raw Wasm module.
-+    pub module_hash: ModuleHash,
-+    /// Exact host spelling of the selected carrier executable.
-+    pub path: PathBuf,
-+    /// Closed executable alias registry shared by all fresh EXEC_BACKEND environments.
-+    pub executables: Vec<(String, ModuleHash)>,
-+    /// Authoritative, immutable full-closure AOT cache.
-+    pub module_cache: Arc,
-+}
-+
-+/// The manifest and path identities captured by the single authoritative read.
-+#[derive(Debug)]
-+pub struct PreparedSealedManifest {
-+    manifest: SealedManifest,
-+    carrier_root: PathBuf,
-+    input_path: PathBuf,
-+    input_canonical: PathBuf,
-+    runtime_identity: Option,
-+}
-+
-+impl PreparedSealedManifest {
-+    /// Return the exact initdb/postgres identity selected by the input path.
-+    pub const fn runtime_identity(&self) -> Option {
-+        self.runtime_identity
-+    }
-+
-+    /// Create or validate the product-owned strict code-memory state directory.
-+    ///
-+    /// The exact admitted carrier root is already canonical. The state directory
-+    /// is one deterministic sibling beneath its owned carrier parent;
-+    /// there is no environment lookup, temporary-directory search, or fallback.
-+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-+    pub fn strict_code_memory_directory(&self) -> Result<(PathBuf, u64, u64), Error> {
-+        strict_code_memory_directory_for_carrier(&self.carrier_root)
-+    }
-+}
-+
-+#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-+fn strict_code_memory_directory_for_carrier(
-+    carrier_root: &Path,
-+) -> Result<(PathBuf, u64, u64), Error> {
-+    use std::os::unix::{fs::DirBuilderExt, fs::MetadataExt};
-+
-+    let carrier_parent = carrier_root
-+        .parent()
-+        .context("sealed carrier root must have a parent directory")?;
-+    let parent_metadata = fs::metadata(carrier_parent).with_context(|| {
-+        format!(
-+            "inspect strict code-memory parent {}",
-+            carrier_parent.display()
-+        )
-+    })?;
-+    ensure!(
-+        parent_metadata.is_dir(),
-+        "strict code-memory parent is not a directory: {}",
-+        carrier_parent.display()
-+    );
-+    ensure!(
-+        parent_metadata.uid() == unsafe { libc::geteuid() },
-+        "strict code-memory parent is not owned by the effective user: {}",
-+        carrier_parent.display()
-+    );
-+
-+    let directory = carrier_parent.join(CODE_MEMORY_STATE_DIRECTORY);
-+    let mut builder = fs::DirBuilder::new();
-+    builder.mode(0o700);
-+    match builder.create(&directory) {
-+        Ok(()) => {}
-+        Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => {}
-+        Err(error) => {
-+            return Err(error).with_context(|| {
-+                format!(
-+                    "create strict code-memory directory {}",
-+                    directory.display()
-+                )
-+            });
-+        }
-+    }
-+
-+    // lstat rejects a path substitution before the engine independently opens
-+    // and pins its O_DIRECTORY descriptor. The engine repeats the owner/mode
-+    // checks on that descriptor to close the validation/open race rather than
-+    // trusting these path-based observations alone.
-+    let metadata = fs::symlink_metadata(&directory).with_context(|| {
-+        format!(
-+            "inspect strict code-memory directory {}",
-+            directory.display()
-+        )
-+    })?;
-+    ensure!(
-+        !metadata.file_type().is_symlink() && metadata.is_dir(),
-+        "strict code-memory path must be a non-symlink directory: {}",
-+        directory.display()
-+    );
-+    ensure!(
-+        metadata.uid() == unsafe { libc::geteuid() },
-+        "strict code-memory directory is not owned by the effective user: {}",
-+        directory.display()
-+    );
-+    ensure!(
-+        metadata.mode() & 0o7777 == 0o700,
-+        "strict code-memory directory must have exact mode 0700: {}",
-+        directory.display()
-+    );
-+    ensure!(
-+        metadata.dev() == parent_metadata.dev(),
-+        "strict code-memory directory changed filesystem device: {}",
-+        directory.display()
-+    );
-+    Ok((directory, parent_metadata.dev(), metadata.ino()))
-+}
-+
-+/// The exact, immutable AOT closure admitted by a sealed carrier.
-+#[derive(Debug)]
-+pub struct SealedModuleCache {
-+    engine_id: wasmer::EngineId,
-+    engine_kind: String,
-+    artifacts: HashMap>,
-+}
-+
-+impl SealedModuleCache {
-+    fn new(engine: &Engine, artifacts: HashMap>) -> Self {
-+        Self {
-+            engine_id: engine.id(),
-+            engine_kind: engine.deterministic_id(),
-+            artifacts,
-+        }
-+    }
-+
-+    fn load_exact(&self, key: ModuleHash, engine: &Engine) -> Result {
-+        if engine.id() != self.engine_id {
-+            return Err(sealed_cache_error(format!(
-+                "sealed module cache engine mismatch: cache={:?}/{} requested={:?}/{}",
-+                self.engine_id,
-+                self.engine_kind,
-+                engine.id(),
-+                engine.deterministic_id(),
-+            )));
-+        }
-+        self.artifacts
-+            .get(&key)
-+            .ok_or(CacheError::NotFound)?
-+            .activate(engine)
-+    }
-+}
-+
-+#[async_trait::async_trait]
-+impl ModuleCache for SealedModuleCache {
-+    fn is_authoritative(&self) -> bool {
-+        true
-+    }
-+
-+    async fn load(&self, key: ModuleHash, engine: &Engine) -> Result {
-+        self.load_exact(key, engine)
-+    }
-+
-+    async fn contains(&self, key: ModuleHash, engine: &Engine) -> Result {
-+        if engine.id() != self.engine_id {
-+            return Err(sealed_cache_error(format!(
-+                "sealed module cache engine mismatch: cache={:?}/{} requested={:?}/{}",
-+                self.engine_id,
-+                self.engine_kind,
-+                engine.id(),
-+                engine.deterministic_id(),
-+            )));
-+        }
-+        Ok(self.artifacts.contains_key(&key))
-+    }
-+
-+    async fn save(
-+        &self,
-+        key: ModuleHash,
-+        _engine: &Engine,
-+        _module: &Module,
-+    ) -> Result<(), CacheError> {
-+        Err(sealed_cache_error(format!(
-+            "sealed module cache is immutable; refusing save for {key}"
-+        )))
-+    }
-+}
-+
-+fn sealed_cache_error(message: impl Into) -> CacheError {
-+    CacheError::other(std::io::Error::new(
-+        std::io::ErrorKind::PermissionDenied,
-+        message.into(),
-+    ))
-+}
-+
-+struct LazySealedArtifact {
-+    module_hash: ModuleHash,
-+    expected_digest: [u8; 32],
-+    policy: SealedActivationPolicy,
-+    source: Mutex>,
-+    activation: OnceLock>>,
-+    #[cfg(test)]
-+    activation_attempts: std::sync::atomic::AtomicUsize,
-+}
-+
-+impl fmt::Debug for LazySealedArtifact {
-+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-+        formatter
-+            .debug_struct("LazySealedArtifact")
-+            .field("module_hash", &self.module_hash)
-+            .field("activated", &self.activation.get().is_some())
-+            .finish_non_exhaustive()
-+    }
-+}
-+
-+impl LazySealedArtifact {
-+    fn new(
-+        module_hash: ModuleHash,
-+        expected_digest: [u8; 32],
-+        source: SealedArtifactSource,
-+        policy: SealedActivationPolicy,
-+    ) -> Self {
-+        Self {
-+            module_hash,
-+            expected_digest,
-+            policy,
-+            source: Mutex::new(Some(source)),
-+            activation: OnceLock::new(),
-+            #[cfg(test)]
-+            activation_attempts: std::sync::atomic::AtomicUsize::new(0),
-+        }
-+    }
-+
-+    fn activate(&self, engine: &Engine) -> Result {
-+        self.activate_with_audit(engine, emit_loader_audit)
-+    }
-+
-+    fn activate_with_audit(
-+        &self,
-+        engine: &Engine,
-+        emit_audit: impl FnOnce(LoaderAuditRecord) -> Result<(), Error>,
-+    ) -> Result {
-+        self.activation
-+            .get_or_init(|| {
-+                #[cfg(test)]
-+                self.activation_attempts
-+                    .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
-+
-+                let source = self
-+                    .source
-+                    .lock()
-+                    .map_err(|_| Arc::::from("sealed artifact source lock poisoned"))?
-+                    .take()
-+                    .ok_or_else(|| Arc::::from("sealed artifact source already consumed"))?;
-+                let snapshot = immutable_artifact_snapshot(source, self.policy).map_err(|error| {
-+                    Arc::::from(format!("snapshot sealed AOT artifact: {error:#}"))
-+                })?;
-+                let read_advice = snapshot.advise_for_one_shot_read();
-+                let audit = snapshot.audit;
-+                let activation = (|| -> Result<
-+                    (
-+                        PendingModuleActivation,
-+                        FileResidencyAudit,
-+                        FileResidencyAudit,
-+                    ),
-+                    Arc,
-+                > {
-+                    let mapping = snapshot.mapping().map_err(|error| {
-+                        Arc::::from(format!(
-+                            "map immutable sealed artifact snapshot: {error:#}"
-+                        ))
-+                    })?;
-+
-+                    let actual_digest: [u8; 32] = Sha256::digest(mapping.as_slice()).into();
-+                    if actual_digest != self.expected_digest {
-+                        return Err(Arc::::from(format!(
-+                            "sealed AOT artifact SHA-256 mismatch: expected={} actual={}",
-+                            hex::encode(self.expected_digest),
-+                            hex::encode(actual_digest)
-+                        )));
-+                    }
-+                    let inspected_hash = engine
-+                        .inspect_serialized_artifact(&mapping)
-+                        .map_err(|error| {
-+                            Arc::::from(format!("inspect sealed AOT artifact: {error}"))
-+                        })?;
-+                    if inspected_hash != self.module_hash {
-+                        return Err(Arc::::from(format!(
-+                            "sealed AOT artifact embedded hash mismatch: expected={} actual={inspected_hash}",
-+                            self.module_hash
-+                        )));
-+                    }
-+                    let residency_after_hash_inspect =
-+                        snapshot.residency();
-+
-+                    // SAFETY: this exact immutable mapping was just hashed and
-+                    // inspected. The checked deserializer consumes that same
-+                    // mapping; no path is reopened between verification/use.
-+                    let pending = unsafe {
-+                        engine.deserialize_from_mmapped_buffer_detached_pending(mapping)
-+                    }
-+                    .map_err(|error| {
-+                        Arc::::from(format!("activate sealed AOT artifact: {error}"))
-+                    })?;
-+                    // The detached deserializer consumed and released the
-+                    // archive mapping before returning. This descriptor-only
-+                    // mincore probe cannot touch executable or payload bytes.
-+                    let residency_after_archive_release = snapshot.residency();
-+                    let embedded_hash = pending.module_hash().ok_or_else(|| {
-+                        Arc::::from("activated sealed artifact has no embedded module hash")
-+                    })?;
-+                    if embedded_hash != self.module_hash {
-+                        return Err(Arc::::from(format!(
-+                            "activated sealed artifact hash mismatch: expected={} actual={embedded_hash}",
-+                            self.module_hash
-+                        )));
-+                    }
-+                    #[cfg(feature = "memory-profile-core")]
-+                    validate_serialized_memory_plans(&pending.linear_memory_plans()).map_err(
-+                        |error| {
-+                            Arc::::from(format!(
-+                                "activated sealed artifact linear-memory profile mismatch: {error:#}"
-+                            ))
-+                        },
-+                    )?;
-+                    Ok((
-+                        pending,
-+                        residency_after_hash_inspect,
-+                        residency_after_archive_release,
-+                    ))
-+                })();
-+                let source_residency_before_eviction = snapshot.source_residency();
-+                let source_cache_eviction = snapshot.advise_source_away();
-+                let source_residency_after_eviction = snapshot.source_residency();
-+                let snapshot_cache_eviction = snapshot.advise_snapshot_away();
-+                let residency_after_eviction = snapshot.residency();
-+                let (pending, residency_after_hash_inspect, residency_after_archive_release) =
-+                    activation?;
-+                tracing::debug!(
-+                    target: "wasmer_cli::sealed_loader_audit",
-+                    audit_schema = "oliphaunt.wasix-postmaster.sealed-loader-audit.v2",
-+                    artifact_kind = "aot",
-+                    module_sha256 = %self.module_hash,
-+                    activation_state = "active",
-+                    snapshot_mode = audit.mode.as_str(),
-+                    logical_bytes = audit.logical_bytes,
-+                    source_bytes_read = audit.source_bytes_read,
-+                    snapshot_bytes_written = audit.snapshot_bytes_written,
-+                    source_bytes_written = 0_u64,
-+                    mapping_bytes_hashed = audit.mapping_bytes_hashed,
-+                    sync_calls = audit.sync_calls,
-+                    read_advice_calls = read_advice.calls,
-+                    read_advice_successes = read_advice.successes,
-+                    read_advice_first_errno = read_advice.first_errno,
-+                    source_cache_eviction_supported = source_cache_eviction.supported,
-+                    source_cache_eviction_calls = source_cache_eviction.calls,
-+                    source_cache_eviction_successes = source_cache_eviction.successes,
-+                    source_cache_eviction_errno = source_cache_eviction.first_errno,
-+                    snapshot_cache_eviction_applicable = snapshot.has_distinct_source(),
-+                    snapshot_cache_eviction_supported = snapshot_cache_eviction.supported,
-+                    snapshot_cache_eviction_calls = snapshot_cache_eviction.calls,
-+                    snapshot_cache_eviction_successes = snapshot_cache_eviction.successes,
-+                    snapshot_cache_eviction_errno = snapshot_cache_eviction.first_errno,
-+                    residency_after_hash_inspect_state = residency_after_hash_inspect.state.as_str(),
-+                    residency_after_hash_inspect_pages = residency_after_hash_inspect.resident_pages,
-+                    residency_after_archive_release_state = residency_after_archive_release.state.as_str(),
-+                    residency_after_archive_release_pages = residency_after_archive_release.resident_pages,
-+                    residency_after_eviction_state = residency_after_eviction.state.as_str(),
-+                    residency_after_eviction_pages = residency_after_eviction.resident_pages,
-+                    write_policy = audit.mode.write_policy(),
-+                    "activated sealed artifact"
-+                );
-+                emit_audit(LoaderAuditRecord {
-+                    artifact_kind: "aot",
-+                    module_sha256: canonical_module_sha256(self.module_hash),
-+                    snapshot_mode: audit.mode.as_str(),
-+                    logical_bytes: audit.logical_bytes,
-+                    source_bytes_read: audit.source_bytes_read,
-+                    source_bytes_written: 0,
-+                    snapshot_bytes_written: audit.snapshot_bytes_written,
-+                    mapping_bytes_hashed: audit.mapping_bytes_hashed,
-+                    sync_calls: audit.sync_calls,
-+                    read_advice_applicable: true,
-+                    read_advice_supported: read_advice.supported,
-+                    read_advice_calls: read_advice.calls,
-+                    read_advice_successes: read_advice.successes,
-+                    read_advice_first_errno: read_advice.first_errno,
-+                    source_cache_eviction_applicable: true,
-+                    source_cache_eviction_supported: source_cache_eviction.supported,
-+                    source_cache_eviction_calls: source_cache_eviction.calls,
-+                    source_cache_eviction_successes: source_cache_eviction.successes,
-+                    source_cache_eviction_errno: source_cache_eviction.first_errno,
-+                    snapshot_cache_eviction_applicable: snapshot.has_distinct_source(),
-+                    snapshot_cache_eviction_supported: snapshot_cache_eviction.supported,
-+                    snapshot_cache_eviction_calls: snapshot_cache_eviction.calls,
-+                    snapshot_cache_eviction_successes: snapshot_cache_eviction.successes,
-+                    snapshot_cache_eviction_errno: snapshot_cache_eviction.first_errno,
-+                    mapping_cache_eviction_applicable: false,
-+                    mapping_cache_eviction_supported: true,
-+                    mapping_cache_eviction_calls: 0,
-+                    mapping_cache_eviction_successes: 0,
-+                    mapping_cache_eviction_errno: None,
-+                    residency_after_hash_inspect: residency_after_hash_inspect.into(),
-+                    residency_after_archive_release: residency_after_archive_release.into(),
-+                    source_residency_before_eviction: source_residency_before_eviction.into(),
-+                    source_residency_after_eviction: source_residency_after_eviction.into(),
-+                    residency_after_eviction: residency_after_eviction.into(),
-+                    write_policy: audit.mode.write_policy(),
-+                })
-+                .map_err(|error| {
-+                    Arc::::from(format!("write sealed loader audit receipt: {error:#}"))
-+                })?;
-+                Ok(pending.commit())
-+            })
-+            .clone()
-+            .map_err(|message| sealed_cache_error(message.to_string()))
-+    }
-+}
-+
-+struct SealedArtifactSource {
-+    file: File,
-+    path: PathBuf,
-+    carrier_root: PathBuf,
-+    expected_size: u64,
-+}
-+
-+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-+enum ArtifactSnapshotMode {
-+    DirectIntrinsic(IntrinsicFileImmutability),
-+    Reflink,
-+    StreamedCopy,
-+}
-+
-+impl ArtifactSnapshotMode {
-+    const fn as_str(self) -> &'static str {
-+        match self {
-+            Self::DirectIntrinsic(IntrinsicFileImmutability::ReadOnlyFilesystem) => {
-+                "direct-read-only-filesystem"
-+            }
-+            Self::DirectIntrinsic(IntrinsicFileImmutability::ImmutableInode) => {
-+                "direct-immutable-inode"
-+            }
-+            Self::Reflink => "reflink",
-+            Self::StreamedCopy => "streamed-copy",
-+        }
-+    }
-+
-+    const fn write_policy(self) -> &'static str {
-+        match self {
-+            Self::DirectIntrinsic(_) => "none-immutable-source",
-+            Self::Reflink => "private-reflink-no-userspace-payload-write",
-+            Self::StreamedCopy => "private-streamed-copy-no-sync",
-+        }
-+    }
-+}
-+
-+#[derive(Debug, Serialize)]
-+struct LoaderAuditRecord {
-+    artifact_kind: &'static str,
-+    module_sha256: String,
-+    snapshot_mode: &'static str,
-+    logical_bytes: u64,
-+    source_bytes_read: u64,
-+    source_bytes_written: u64,
-+    snapshot_bytes_written: u64,
-+    mapping_bytes_hashed: u64,
-+    sync_calls: u64,
-+    read_advice_applicable: bool,
-+    read_advice_supported: bool,
-+    read_advice_calls: u64,
-+    read_advice_successes: u64,
-+    read_advice_first_errno: Option,
-+    source_cache_eviction_applicable: bool,
-+    source_cache_eviction_supported: bool,
-+    source_cache_eviction_calls: u64,
-+    source_cache_eviction_successes: u64,
-+    source_cache_eviction_errno: Option,
-+    snapshot_cache_eviction_applicable: bool,
-+    snapshot_cache_eviction_supported: bool,
-+    snapshot_cache_eviction_calls: u64,
-+    snapshot_cache_eviction_successes: u64,
-+    snapshot_cache_eviction_errno: Option,
-+    mapping_cache_eviction_applicable: bool,
-+    mapping_cache_eviction_supported: bool,
-+    mapping_cache_eviction_calls: u64,
-+    mapping_cache_eviction_successes: u64,
-+    mapping_cache_eviction_errno: Option,
-+    residency_after_hash_inspect: LoaderResidencyRecord,
-+    residency_after_archive_release: LoaderResidencyRecord,
-+    source_residency_before_eviction: LoaderResidencyRecord,
-+    source_residency_after_eviction: LoaderResidencyRecord,
-+    residency_after_eviction: LoaderResidencyRecord,
-+    write_policy: &'static str,
-+}
-+
-+fn canonical_module_sha256(module_hash: ModuleHash) -> String {
-+    hex::encode(module_hash.as_bytes())
-+}
-+
-+#[derive(Debug, Serialize)]
-+struct LoaderResidencyRecord {
-+    state: &'static str,
-+    page_size: Option,
-+    total_pages: Option,
-+    resident_pages: Option,
-+    resident_bytes: Option,
-+    errno: Option,
-+}
-+
-+impl From for LoaderResidencyRecord {
-+    fn from(audit: FileResidencyAudit) -> Self {
-+        Self {
-+            state: audit.state.as_str(),
-+            page_size: audit.page_size,
-+            total_pages: audit.total_pages,
-+            resident_pages: audit.resident_pages,
-+            resident_bytes: audit.resident_bytes,
-+            errno: audit.errno,
-+        }
-+    }
-+}
-+
-+#[derive(Serialize)]
-+struct LoaderAuditEnvelope<'a> {
-+    schema: &'static str,
-+    pid: u32,
-+    #[serde(flatten)]
-+    record: &'a LoaderAuditRecord,
-+}
-+
-+fn emit_loader_audit(record: LoaderAuditRecord) -> Result<(), Error> {
-+    let Some(path) = std::env::var_os(SEALED_LOADER_AUDIT_FILE_ENV) else {
-+        return Ok(());
-+    };
-+    let path = PathBuf::from(path);
-+    ensure!(
-+        !path.as_os_str().is_empty(),
-+        "{SEALED_LOADER_AUDIT_FILE_ENV} must not be empty"
-+    );
-+    emit_loader_audit_to_path(&path, &record)
-+}
-+
-+#[cfg(unix)]
-+fn emit_loader_audit_to_path(path: &Path, record: &LoaderAuditRecord) -> Result<(), Error> {
-+    let envelope = LoaderAuditEnvelope {
-+        schema: "oliphaunt.wasix-postmaster.sealed-loader-receipt.v2",
-+        pid: std::process::id(),
-+        record,
-+    };
-+    append_sealed_loader_audit_record(path, &envelope)
-+}
-+
-+#[cfg(unix)]
-+fn append_sealed_loader_audit_record(path: &Path, record: &impl Serialize) -> Result<(), Error> {
-+    use std::os::{
-+        fd::AsRawFd,
-+        unix::fs::{MetadataExt, OpenOptionsExt},
-+    };
-+
-+    let mut options = OpenOptions::new();
-+    options
-+        .create(true)
-+        .append(true)
-+        .mode(0o600)
-+        .custom_flags(libc::O_CLOEXEC | libc::O_NOFOLLOW);
-+    let file = options
-+        .open(path)
-+        .with_context(|| format!("open sealed loader audit receipt {}", path.display()))?;
-+    let metadata = file.metadata()?;
-+    ensure!(
-+        metadata.is_file(),
-+        "sealed loader audit receipt is not a regular file"
-+    );
-+    ensure!(
-+        metadata.uid() == unsafe { libc::geteuid() },
-+        "sealed loader audit receipt is not owned by the runtime uid"
-+    );
-+    ensure!(
-+        metadata.nlink() == 1,
-+        "sealed loader audit receipt must have exactly one link"
-+    );
-+    ensure!(
-+        metadata.mode() & 0o077 == 0,
-+        "sealed loader audit receipt exposes group/other permissions"
-+    );
-+
-+    let mut line = serde_json::to_vec(record).context("encode sealed loader audit record")?;
-+    line.push(b'\n');
-+    ensure!(
-+        line.len() <= 4096,
-+        "sealed loader audit record exceeds atomic-write bound"
-+    );
-+    // SAFETY: the buffer remains live for this single O_APPEND write. One
-+    // syscall keeps concurrent process records contiguous; short writes fail
-+    // activation so qualification cannot accept a partial receipt.
-+    let written = unsafe { libc::write(file.as_raw_fd(), line.as_ptr().cast(), line.len()) };
-+    if written < 0 {
-+        return Err(std::io::Error::last_os_error()).context("append sealed loader audit record");
-+    }
-+    ensure!(
-+        usize::try_from(written).ok() == Some(line.len()),
-+        "short sealed loader audit write: expected={} actual={written}",
-+        line.len()
-+    );
-+    Ok(())
-+}
-+
-+#[cfg(not(unix))]
-+fn emit_loader_audit_to_path(_path: &Path, _record: &LoaderAuditRecord) -> Result<(), Error> {
-+    bail!("sealed loader audit receipts require Unix O_APPEND/O_NOFOLLOW semantics")
-+}
-+
-+#[cfg(not(unix))]
-+fn append_sealed_loader_audit_record(_path: &Path, _record: &impl Serialize) -> Result<(), Error> {
-+    bail!("sealed loader audit receipts require Unix O_APPEND/O_NOFOLLOW semantics")
-+}
-+
-+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-+struct ArtifactSnapshotAudit {
-+    mode: ArtifactSnapshotMode,
-+    logical_bytes: u64,
-+    source_bytes_read: u64,
-+    snapshot_bytes_written: u64,
-+    mapping_bytes_hashed: u64,
-+    sync_calls: u64,
-+}
-+
-+struct ImmutableArtifactSnapshot {
-+    file: File,
-+    /// Retained only when activation uses a private reflink/streamed snapshot.
-+    /// This is the exact already-open carrier source, never a reopened path.
-+    source_file: Option,
-+    len: u64,
-+    audit: ArtifactSnapshotAudit,
-+}
-+
-+impl fmt::Debug for ImmutableArtifactSnapshot {
-+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-+        formatter
-+            .debug_struct("ImmutableArtifactSnapshot")
-+            .field("len", &self.len)
-+            .field("has_distinct_source", &self.source_file.is_some())
-+            .finish_non_exhaustive()
-+    }
-+}
-+
-+impl ImmutableArtifactSnapshot {
-+    fn mapping(&self) -> Result {
-+        let mapping = wasmer::sys::OwnedBuffer::from_file(&self.file)
-+            .context("memory-map immutable sealed artifact snapshot")?;
-+        ensure!(
-+            u64::try_from(mapping.len()).ok() == Some(self.len),
-+            "immutable sealed artifact snapshot changed size"
-+        );
-+        Ok(mapping)
-+    }
-+
-+    fn advise_for_one_shot_read(&self) -> FileAdviceAudit {
-+        advise_file_for_one_shot_read(&self.file)
-+    }
-+
-+    fn advise_source_away(&self) -> FileAdviceAudit {
-+        advise_file_away(self.source_file.as_ref().unwrap_or(&self.file))
-+    }
-+
-+    fn advise_snapshot_away(&self) -> FileAdviceAudit {
-+        self.source_file
-+            .as_ref()
-+            .map_or_else(FileAdviceAudit::not_applicable, |_| {
-+                advise_file_away(&self.file)
-+            })
-+    }
-+
-+    fn residency(&self) -> FileResidencyAudit {
-+        file_residency(&self.file, self.len)
-+    }
-+
-+    fn source_residency(&self) -> FileResidencyAudit {
-+        file_residency(self.source_file.as_ref().unwrap_or(&self.file), self.len)
-+    }
-+
-+    fn has_distinct_source(&self) -> bool {
-+        self.source_file.is_some()
-+    }
-+}
-+
-+enum WritableArtifactSnapshot {
-+    #[cfg(target_os = "linux")]
-+    Anonymous(File),
-+    Named {
-+        temp_dir: tempfile::TempDir,
-+        file: tempfile::NamedTempFile,
-+    },
-+}
-+
-+impl WritableArtifactSnapshot {
-+    fn file_mut(&mut self) -> &mut File {
-+        match self {
-+            #[cfg(target_os = "linux")]
-+            Self::Anonymous(file) => file,
-+            Self::Named { file, .. } => file.as_file_mut(),
-+        }
-+    }
-+
-+    fn finalize(
-+        self,
-+        expected_size: u64,
-+        audit: ArtifactSnapshotAudit,
-+    ) -> Result {
-+        match self {
-+            #[cfg(target_os = "linux")]
-+            Self::Anonymous(file) => finalize_anonymous_snapshot(file, expected_size, audit),
-+            Self::Named { temp_dir, file } => {
-+                finalize_named_snapshot(temp_dir, file, expected_size, audit)
-+            }
-+        }
-+    }
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[cfg_attr(test, derive(serde::Serialize))]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+struct SealedManifest {
-+    format_version: u32,
-+    schema: String,
-+    source_lane: String,
-+    source_fingerprint: String,
-+    core_profile: String,
-+    guest_build_recipe_sha256: String,
-+    postgres_version: String,
-+    target_triple: String,
-+    host_abi: String,
-+    engine: String,
-+    compiler_config: String,
-+    cpu_policy: String,
-+    cpu_features: Vec,
-+    wasmer_version: String,
-+    wasmer_wasix_version: String,
-+    wasmer_source_commit: String,
-+    wasmer_patch_sha256: String,
-+    wasmer_cargo_lock_sha256: String,
-+    artifact_abi_version: u32,
-+    runtime_abi_id: String,
-+    producer_recipe_sha256: String,
-+    executor_engine: String,
-+    executor_sha256: String,
-+    executor_size: u64,
-+    linear_memory_profile: SealedLinearMemoryProfile,
-+    wasm_features: Vec,
-+    entrypoint: String,
-+    artifacts: Vec,
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[cfg_attr(test, derive(serde::Serialize))]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+struct SealedLinearMemoryProfile {
-+    id: String,
-+    address_width: String,
-+    supported_host_pointer_width: String,
-+    maximum_pages: u32,
-+    maximum_bytes: u64,
-+    static_bound_pages: u32,
-+    static_offset_guard_bytes: u64,
-+    static_access_lowering: String,
-+    install_receipt_path: String,
-+    install_receipt_sha256: String,
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[cfg_attr(test, derive(serde::Serialize))]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+struct SealedArtifact {
-+    name: String,
-+    kind: String,
-+    path: String,
-+    module_path: String,
-+    sha256: String,
-+    raw_sha256: String,
-+    raw_size: u64,
-+    module_sha256: String,
-+    module_size: u64,
-+    linear_memory: SealedArtifactLinearMemory,
-+    compressed: bool,
-+    exec_aliases: Vec,
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[cfg_attr(test, derive(serde::Serialize))]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+struct SealedArtifactLinearMemory {
-+    profile_id: String,
-+    source_module_sha256: String,
-+    install_receipt_sha256: String,
-+}
-+
-+/// Read and structurally admit an exact sealed manifest for one local executable.
-+pub fn prepare(manifest_path: &Path, input_path: &Path) -> Result {
-+    let manifest = read_manifest(manifest_path)?;
-+    ensure!(
-+        has_exact_wasix_postmaster_identity(&manifest),
-+        "sealed manifest is not the exact WASIX-postmaster artifact closure"
-+    );
-+    let carrier_root = manifest_path
-+        .parent()
-+        .context("sealed manifest must have a parent directory")?
-+        .canonicalize()
-+        .with_context(|| format!("resolve carrier root for {}", manifest_path.display()))?;
-+    validate_linear_memory_install_receipt(&manifest, &carrier_root)?;
-+    let input_canonical = input_path
-+        .canonicalize()
-+        .with_context(|| format!("resolve sealed executable input {}", input_path.display()))?;
-+    let runtime_identity = EXPECTED_WASIX_POSTMASTER_EXECUTABLES
-+        .iter()
-+        .filter_map(|artifact| artifact.executable.map(|identity| (artifact, identity)))
-+        .find_map(|(artifact, identity)| {
-+            let expected_path = carrier_root
-+                .join(artifact.module_path)
-+                .canonicalize()
-+                .ok()?;
-+            (expected_path == input_canonical).then_some(identity)
-+        });
-+    ensure!(
-+        runtime_identity.is_some(),
-+        "input '{}' is not an executable in the exact WASIX-postmaster closure",
-+        input_path.display()
-+    );
-+    Ok(PreparedSealedManifest {
-+        manifest,
-+        carrier_root,
-+        input_path: input_path.to_path_buf(),
-+        input_canonical,
-+        runtime_identity,
-+    })
-+}
-+
-+fn validate_linear_memory_profile(profile: &SealedLinearMemoryProfile) -> Result<(), Error> {
-+    ensure!(
-+        profile.id == LINEAR_MEMORY_PROFILE_ID
-+            && profile.address_width == "wasm32"
-+            && profile.supported_host_pointer_width == "u64"
-+            && profile.maximum_pages == LINEAR_MEMORY_MAXIMUM_PAGES
-+            && profile.maximum_bytes == LINEAR_MEMORY_MAXIMUM_BYTES
-+            && profile.static_bound_pages == LINEAR_MEMORY_STATIC_BOUND_PAGES
-+            && profile.static_offset_guard_bytes == LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES
-+            && profile.static_access_lowering == "wasmer-llvm-unchecked-reservation-and-guard-v1",
-+        "sealed manifest linear-memory profile does not match the exact trap-preserving product profile"
-+    );
-+    ensure_nonempty(
-+        "linear-memory-profile.install-receipt-path",
-+        &profile.install_receipt_path,
-+    )?;
-+    parse_sha256(
-+        "linear-memory-profile.install-receipt-sha256",
-+        &profile.install_receipt_sha256,
-+    )?;
-+    Ok(())
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[cfg_attr(test, derive(serde::Serialize))]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+struct LinearMemoryInstallReceipt {
-+    schema: String,
-+    profile_id: String,
-+    address_width: String,
-+    supported_host_pointer_width: String,
-+    maximum_pages: u32,
-+    maximum_bytes: u64,
-+    static_bound_pages: u32,
-+    static_offset_guard_bytes: u64,
-+    static_access_lowering: String,
-+    requires_shared: bool,
-+    requires_import: String,
-+    excludes_wasm32_end_wrap: bool,
-+    predecessor_export_closure_receipt: String,
-+    predecessor_export_closure_receipt_sha256: String,
-+    source_module_closure_sha256: String,
-+    module_closure_sha256: String,
-+    module_count: usize,
-+    modules: Vec,
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[cfg_attr(test, derive(serde::Serialize))]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+struct LinearMemoryInstallModule {
-+    path: String,
-+    source_module_sha256: String,
-+    module_sha256: String,
-+    initial_pages: u64,
-+    maximum_pages: u64,
-+    maximum_bytes: u64,
-+    shared: bool,
-+    import_module: String,
-+    import_name: String,
-+    transformation: String,
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+#[allow(dead_code)] // Receipt schema fields are authenticated even when not consumed at runtime.
-+struct SealedExportSnapshot {
-+    sha256: String,
-+    bytes: usize,
-+    exports: usize,
-+    local_functions: u32,
-+    local_globals: u32,
-+    element_function_entries: u32,
-+    element_unique_function_indices: u32,
-+    start_function_index: u32,
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+struct SealedExportSideIdentity {
-+    path: String,
-+    sha256: String,
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+#[allow(dead_code)] // Receipt schema fields are authenticated even when not consumed at runtime.
-+struct SealedExportStructureReceipt {
-+    schema: String,
-+    policy_id: String,
-+    analyzer_version: String,
-+    analyzer_binary_sha256: String,
-+    dce_tool_sha256: String,
-+    dce_tool_version: String,
-+    dce_passes: Vec,
-+    mandatory_policy_sha256: String,
-+    declared_main_dlsym_policy_sha256: String,
-+    side_manifest_sha256: String,
-+    allowlist_sha256: String,
-+    seed_proof_sha256: String,
-+    final_proof_sha256: String,
-+    seed: SealedExportSnapshot,
-+    final_module: SealedExportSnapshot,
-+    sides: Vec,
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+#[allow(dead_code)] // Proof schema fields are authenticated even when not consumed at runtime.
-+struct SealedExportProofModule {
-+    path: String,
-+    sha256: String,
-+    bytes: usize,
-+    non_export_sections_sha256: String,
-+    dylink_needed: Vec,
-+    imported_functions: u32,
-+    local_functions: u32,
-+    imported_globals: u32,
-+    local_globals: u32,
-+    imported_tables: u32,
-+    local_tables: u32,
-+    element_function_entries: u32,
-+    element_unique_function_indices: u32,
-+    element_max_function_index: Option,
-+    start_function_index: Option,
-+    imports: Vec,
-+    export_counts: BTreeMap,
-+    exported_global_type_counts: BTreeMap,
-+    exported_immutable_i32_globals: u32,
-+    exported_local_functions: u32,
-+    exported_imported_functions: u32,
-+}
-+
-+#[derive(Debug, Deserialize)]
-+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-+#[allow(dead_code)] // Proof schema fields are authenticated even when not consumed at runtime.
-+struct SealedExportClosureProof {
-+    schema: String,
-+    policy_id: String,
-+    analyzer_version: String,
-+    mandatory_policy_sha256: String,
-+    declared_main_dlsym_policy_sha256: String,
-+    main: SealedExportProofModule,
-+    sides: Vec,
-+    mandatory_runtime_exports: Vec,
-+    declared_main_dlsym_exports: Vec,
-+    side_dynamic_imports: Vec,
-+    retained_main_exports: Vec,
-+    retained_main_export_descriptors: Vec,
-+    removed_main_export_count: usize,
-+    removed_main_export_names_sha256: String,
-+    unresolved_main_requirements: Vec,
-+    mismatched_main_requirements: Vec,
-+    unresolved_side_dependencies: Vec,
-+    retained_counts: BTreeMap,
-+    removed_counts: BTreeMap,
-+}
-+
-+fn update_framed(digest: &mut Sha256, value: &str) {
-+    digest.update((value.len() as u64).to_be_bytes());
-+    digest.update(value.as_bytes());
-+}
-+
-+fn linear_memory_closure_sha256(modules: &[LinearMemoryInstallModule], hash_field: &str) -> String {
-+    let mut digest = Sha256::new();
-+    update_framed(
-+        &mut digest,
-+        "oliphaunt.wasix-postmaster.linear-memory-install-closure.v1",
-+    );
-+    update_framed(&mut digest, hash_field);
-+    for module in modules {
-+        update_framed(&mut digest, &module.path);
-+        update_framed(
-+            &mut digest,
-+            if hash_field == "source-module-sha256" {
-+                &module.source_module_sha256
-+            } else {
-+                &module.module_sha256
-+            },
-+        );
-+    }
-+    hex::encode(digest.finalize())
-+}
-+
-+fn validate_sealed_export_proof(
-+    proof: &SealedExportClosureProof,
-+    label: &str,
-+    receipt: &SealedExportStructureReceipt,
-+    expected_main_sha256: &str,
-+) -> Result<(), Error> {
-+    ensure!(
-+        proof.schema == SEALED_EXPORT_PROOF_SCHEMA
-+            && proof.policy_id == SEALED_EXPORT_POLICY_ID
-+            && proof.analyzer_version == receipt.analyzer_version
-+            && proof.mandatory_policy_sha256 == receipt.mandatory_policy_sha256
-+            && proof.declared_main_dlsym_policy_sha256 == receipt.declared_main_dlsym_policy_sha256,
-+        "{label} schema/policy identity differs"
-+    );
-+    ensure!(
-+        proof.main.path == "bin/postgres" && proof.main.sha256 == expected_main_sha256,
-+        "{label} main module identity differs"
-+    );
-+    ensure!(
-+        proof.sides.len() == receipt.sides.len(),
-+        "{label} side-module count differs"
-+    );
-+    for (module, expected) in proof.sides.iter().zip(&receipt.sides) {
-+        ensure!(
-+            module.path == expected.path && module.sha256 == expected.sha256,
-+            "{label} side-module identity differs for '{}'",
-+            expected.path
-+        );
-+    }
-+    ensure!(
-+        proof.unresolved_main_requirements.is_empty()
-+            && proof.mismatched_main_requirements.is_empty()
-+            && proof.unresolved_side_dependencies.is_empty(),
-+        "{label} does not prove a closed export graph"
-+    );
-+    parse_sha256(
-+        &format!("{label} removed export names"),
-+        &proof.removed_main_export_names_sha256,
-+    )?;
-+    ensure_nonempty(
-+        &format!("{label} analyzer version"),
-+        &proof.analyzer_version,
-+    )?;
-+    Ok(())
-+}
-+
-+fn validate_sealed_export_predecessor(
-+    carrier_root: &Path,
-+    linear_receipt: &LinearMemoryInstallReceipt,
-+) -> Result<(), Error> {
-+    ensure!(
-+        linear_receipt.predecessor_export_closure_receipt == SEALED_EXPORT_RECEIPT_PATH,
-+        "linear-memory predecessor must be the canonical sealed-export receipt"
-+    );
-+    let source_modules = linear_receipt
-+        .modules
-+        .iter()
-+        .map(|module| (module.path.as_str(), module.source_module_sha256.as_str()))
-+        .collect::>();
-+    let receipt_path = carrier_file_path(carrier_root, SEALED_EXPORT_RECEIPT_PATH)?;
-+    let receipt_bytes = read_small_regular_file(&receipt_path, MAX_SEALED_EXPORT_PROOF_BYTES)?;
-+    ensure!(
-+        hex::encode(Sha256::digest(&receipt_bytes))
-+            == linear_receipt.predecessor_export_closure_receipt_sha256,
-+        "linear-memory predecessor sealed-export receipt SHA-256 differs"
-+    );
-+    let receipt: SealedExportStructureReceipt =
-+        serde_json::from_slice(&receipt_bytes).context("parse sealed-export structural receipt")?;
-+    ensure!(
-+        receipt.schema == SEALED_EXPORT_RECEIPT_SCHEMA
-+            && receipt.policy_id == SEALED_EXPORT_POLICY_ID
-+            && receipt.dce_passes == ["--remove-unused-module-elements"]
-+            && receipt.mandatory_policy_sha256 == SEALED_EXPORT_MANDATORY_POLICY_SHA256
-+            && receipt.declared_main_dlsym_policy_sha256 == SEALED_EXPORT_DLSYM_POLICY_SHA256
-+            && receipt.side_manifest_sha256 == SEALED_EXPORT_SIDE_MANIFEST_SHA256,
-+        "sealed-export structural receipt policy differs"
-+    );
-+    for (label, value) in [
-+        ("analyzer binary", receipt.analyzer_binary_sha256.as_str()),
-+        ("DCE tool", receipt.dce_tool_sha256.as_str()),
-+        ("allowlist", receipt.allowlist_sha256.as_str()),
-+        ("seed proof", receipt.seed_proof_sha256.as_str()),
-+        ("final proof", receipt.final_proof_sha256.as_str()),
-+        ("seed module", receipt.seed.sha256.as_str()),
-+        ("final module", receipt.final_module.sha256.as_str()),
-+    ] {
-+        parse_sha256(&format!("sealed-export {label}"), value)?;
-+    }
-+    ensure_nonempty("sealed-export analyzer version", &receipt.analyzer_version)?;
-+    ensure_nonempty("sealed-export DCE tool version", &receipt.dce_tool_version)?;
-+    ensure!(
-+        source_modules.get("bin/postgres").copied() == Some(receipt.final_module.sha256.as_str()),
-+        "sealed-export final module is not bin/postgres's linear-memory predecessor"
-+    );
-+    ensure!(
-+        receipt.sides.len() == SEALED_EXPORT_SIDE_PATHS.len(),
-+        "sealed-export structural receipt side count differs"
-+    );
-+    for (side, expected_path) in receipt.sides.iter().zip(SEALED_EXPORT_SIDE_PATHS) {
-+        parse_sha256("sealed-export side module", &side.sha256)?;
-+        ensure!(
-+            side.path == expected_path
-+                && source_modules.get(expected_path).copied() == Some(side.sha256.as_str()),
-+            "sealed-export side is not the linear-memory predecessor for '{expected_path}'"
-+        );
-+    }
-+
-+    let read_bound = |relative: &str, expected: &str| -> Result, Error> {
-+        let path = carrier_file_path(carrier_root, relative)?;
-+        let bytes = read_small_regular_file(&path, MAX_SEALED_EXPORT_PROOF_BYTES)?;
-+        ensure!(
-+            hex::encode(Sha256::digest(&bytes)) == expected,
-+            "sealed-export installed proof differs: {relative}"
-+        );
-+        Ok(bytes)
-+    };
-+    let _allowlist = read_bound(SEALED_EXPORT_ALLOWLIST_PATH, &receipt.allowlist_sha256)?;
-+    let seed_bytes = read_bound(SEALED_EXPORT_SEED_PROOF_PATH, &receipt.seed_proof_sha256)?;
-+    let final_bytes = read_bound(SEALED_EXPORT_FINAL_PROOF_PATH, &receipt.final_proof_sha256)?;
-+    let seed: SealedExportClosureProof =
-+        serde_json::from_slice(&seed_bytes).context("parse sealed-export seed proof")?;
-+    let final_proof: SealedExportClosureProof =
-+        serde_json::from_slice(&final_bytes).context("parse sealed-export final proof")?;
-+    validate_sealed_export_proof(
-+        &seed,
-+        "sealed-export seed proof",
-+        &receipt,
-+        &receipt.seed.sha256,
-+    )?;
-+    validate_sealed_export_proof(
-+        &final_proof,
-+        "sealed-export final proof",
-+        &receipt,
-+        &receipt.final_module.sha256,
-+    )?;
-+    Ok(())
-+}
-+
-+fn validate_linear_memory_install_receipt(
-+    manifest: &SealedManifest,
-+    carrier_root: &Path,
-+) -> Result<(), Error> {
-+    let profile = &manifest.linear_memory_profile;
-+    validate_linear_memory_profile(profile)?;
-+    let receipt_path = carrier_file_path(carrier_root, &profile.install_receipt_path)?;
-+    let bytes = read_small_regular_file(&receipt_path, MAX_LINEAR_MEMORY_RECEIPT_BYTES)
-+        .with_context(|| {
-+            format!(
-+                "read linear-memory install receipt {}",
-+                receipt_path.display()
-+            )
-+        })?;
-+    let actual_sha256 = hex::encode(Sha256::digest(&bytes));
-+    ensure!(
-+        actual_sha256.eq_ignore_ascii_case(&profile.install_receipt_sha256),
-+        "linear-memory install receipt SHA-256 mismatch"
-+    );
-+    let receipt: LinearMemoryInstallReceipt =
-+        serde_json::from_slice(&bytes).context("parse linear-memory install receipt")?;
-+    ensure!(
-+        receipt.schema == LINEAR_MEMORY_INSTALL_RECEIPT_SCHEMA
-+            && receipt.profile_id == profile.id
-+            && receipt.address_width == profile.address_width
-+            && receipt.supported_host_pointer_width == profile.supported_host_pointer_width
-+            && receipt.maximum_pages == profile.maximum_pages
-+            && receipt.maximum_bytes == profile.maximum_bytes
-+            && receipt.static_bound_pages == profile.static_bound_pages
-+            && receipt.static_offset_guard_bytes == profile.static_offset_guard_bytes
-+            && receipt.static_access_lowering == profile.static_access_lowering
-+            && receipt.requires_shared
-+            && receipt.requires_import == "env.memory"
-+            && receipt.excludes_wasm32_end_wrap,
-+        "linear-memory install receipt profile differs from sealed manifest"
-+    );
-+    ensure!(
-+        receipt.module_count == receipt.modules.len() && receipt.module_count > 0,
-+        "linear-memory install receipt module count is invalid"
-+    );
-+    parse_sha256(
-+        "linear-memory predecessor export receipt",
-+        &receipt.predecessor_export_closure_receipt_sha256,
-+    )?;
-+    ensure_nonempty(
-+        "linear-memory predecessor export receipt path",
-+        &receipt.predecessor_export_closure_receipt,
-+    )?;
-+    parse_sha256(
-+        "linear-memory source closure",
-+        &receipt.source_module_closure_sha256,
-+    )?;
-+    parse_sha256(
-+        "linear-memory sealed closure",
-+        &receipt.module_closure_sha256,
-+    )?;
-+
-+    let mut paths = BTreeSet::new();
-+    let mut previous = None;
-+    for module in &receipt.modules {
-+        ensure!(
-+            previous.is_none_or(|path: &str| path < module.path.as_str()),
-+            "linear-memory install receipt modules are not strictly path-sorted"
-+        );
-+        previous = Some(module.path.as_str());
-+        ensure!(
-+            paths.insert(module.path.as_str()),
-+            "duplicate linear-memory module path"
-+        );
-+        parse_sha256("linear-memory source module", &module.source_module_sha256)?;
-+        parse_sha256("linear-memory sealed module", &module.module_sha256)?;
-+        ensure!(
-+            module.initial_pages <= u64::from(LINEAR_MEMORY_MAXIMUM_PAGES)
-+                && module.maximum_pages == u64::from(LINEAR_MEMORY_MAXIMUM_PAGES)
-+                && module.maximum_bytes == LINEAR_MEMORY_MAXIMUM_BYTES
-+                && module.shared
-+                && module.import_module == "env"
-+                && module.import_name == "memory"
-+                && module.transformation == SEALED_MODULE_TRANSFORMATION_ID,
-+            "linear-memory install module '{}' has a noncanonical contract",
-+            module.path
-+        );
-+    }
-+    ensure!(
-+        linear_memory_closure_sha256(&receipt.modules, "source-module-sha256")
-+            == receipt.source_module_closure_sha256
-+            && linear_memory_closure_sha256(&receipt.modules, "module-sha256")
-+                == receipt.module_closure_sha256,
-+        "linear-memory install receipt closure hash mismatch"
-+    );
-+    validate_sealed_export_predecessor(carrier_root, &receipt)?;
-+
-+    for artifact in &manifest.artifacts {
-+        let module = receipt
-+            .modules
-+            .iter()
-+            .find(|module| module.path == artifact.module_path)
-+            .with_context(|| {
-+                format!(
-+                    "linear-memory install receipt has no record for '{}'",
-+                    artifact.module_path
-+                )
-+            })?;
-+        ensure!(
-+            artifact.linear_memory.profile_id == profile.id
-+                && artifact.linear_memory.install_receipt_sha256 == profile.install_receipt_sha256
-+                && artifact.linear_memory.source_module_sha256 == module.source_module_sha256
-+                && artifact
-+                    .module_sha256
-+                    .eq_ignore_ascii_case(&module.module_sha256),
-+            "sealed artifact '{}' linear-memory binding differs from install receipt",
-+            artifact.name
-+        );
-+    }
-+    Ok(())
-+}
-+
-+fn read_manifest(manifest_path: &Path) -> Result {
-+    let manifest_bytes = read_small_regular_file(manifest_path, MAX_MANIFEST_BYTES)
-+        .with_context(|| format!("read sealed manifest {}", manifest_path.display()))?;
-+    serde_json::from_slice(&manifest_bytes)
-+        .with_context(|| format!("parse sealed manifest {}", manifest_path.display()))
-+}
-+
-+fn has_exact_wasix_postmaster_identity(manifest: &SealedManifest) -> bool {
-+    if manifest.format_version != MANIFEST_FORMAT_VERSION
-+        || manifest.schema != MANIFEST_SCHEMA
-+        || manifest.source_lane != WASIX_POSTMASTER_SOURCE_LANE
-+        || !matches!(manifest.core_profile.as_str(), "release-o3" | "safe-o2")
-+        || parse_sha256(
-+            "guest-build-recipe-sha256",
-+            &manifest.guest_build_recipe_sha256,
-+        )
-+        .is_err()
-+        || validate_linear_memory_profile(&manifest.linear_memory_profile).is_err()
-+        || manifest.entrypoint != WASIX_POSTMASTER_ENTRYPOINT
-+        || manifest.wasm_features.len() != EXPECTED_WASM_FEATURES.len()
-+        || EXPECTED_WASM_FEATURES.iter().any(|expected| {
-+            !manifest
-+                .wasm_features
-+                .iter()
-+                .any(|actual| actual == expected)
-+        })
-+        || manifest.artifacts.len()
-+            != EXPECTED_WASIX_POSTMASTER_EXECUTABLES.len() + SEALED_EXPORT_SIDE_PATHS.len()
-+    {
-+        return false;
-+    }
-+
-+    let mut names = HashSet::new();
-+    let mut module_paths = HashSet::new();
-+    let mut artifact_paths = HashSet::new();
-+    for (index, artifact) in manifest.artifacts.iter().enumerate() {
-+        let (kind, module_path, exec_aliases, _executable) =
-+            if let Some(expected) = EXPECTED_WASIX_POSTMASTER_EXECUTABLES.get(index) {
-+                (
-+                    expected.kind,
-+                    expected.module_path,
-+                    expected.exec_aliases,
-+                    expected.executable,
-+                )
-+            } else {
-+                let side_index = index - EXPECTED_WASIX_POSTMASTER_EXECUTABLES.len();
-+                (
-+                    "side-module",
-+                    SEALED_EXPORT_SIDE_PATHS[side_index],
-+                    &[] as &[&str],
-+                    None,
-+                )
-+            };
-+        let expected_name = format!(
-+            "runtime:{}",
-+            module_path
-+                .rsplit_once('/')
-+                .map_or(module_path, |(_, basename)| basename)
-+        );
-+        let expected_aliases = exec_aliases.iter().copied();
-+        let module_digest_is_valid = parse_sha256("module-sha256", &artifact.module_sha256).is_ok();
-+        let expected_artifact_path =
-+            format!("aot/{}.bin", artifact.module_sha256.to_ascii_uppercase());
-+        if artifact.name != expected_name
-+            || artifact.kind != kind
-+            || artifact.module_path != module_path
-+            || artifact
-+                .exec_aliases
-+                .iter()
-+                .map(String::as_str)
-+                .ne(expected_aliases)
-+            || artifact.compressed
-+            || artifact.linear_memory.profile_id != manifest.linear_memory_profile.id
-+            || artifact.linear_memory.install_receipt_sha256
-+                != manifest.linear_memory_profile.install_receipt_sha256
-+            || parse_sha256(
-+                "linear-memory-source-module-sha256",
-+                &artifact.linear_memory.source_module_sha256,
-+            )
-+            .is_err()
-+            || !module_digest_is_valid
-+            || artifact.path != expected_artifact_path
-+            || !names.insert(artifact.name.as_str())
-+            || !module_paths.insert(artifact.module_path.as_str())
-+            || !artifact_paths.insert(artifact.path.as_str())
-+        {
-+            return false;
-+        }
-+    }
-+    true
-+}
-+
-+/// Activate only the selected AOT entrypoint and retain the remaining exact closure lazily.
-+pub fn load(
-+    prepared: PreparedSealedManifest,
-+    engine: &Engine,
-+) -> Result {
-+    let PreparedSealedManifest {
-+        manifest,
-+        carrier_root,
-+        input_path,
-+        input_canonical,
-+        runtime_identity: _,
-+    } = prepared;
-+    validate_manifest_identity(&manifest, engine)?;
-+    let activation_policy = SealedActivationPolicy::from_environment()?;
-+    audit_executor_trust_boundary(&manifest);
-+
-+    ensure!(
-+        !manifest.artifacts.is_empty(),
-+        "sealed manifest has no artifacts"
-+    );
-+    let mut names = HashSet::new();
-+    let mut aliases = HashMap::::new();
-+    let mut artifact_paths = HashSet::new();
-+    let mut module_paths = HashSet::new();
-+    let mut executables = Vec::new();
-+    let mut artifacts = HashMap::new();
-+    let mut declared_entrypoint = false;
-+    let mut selected: Option = None;
-+    let input_name = input_path.to_string_lossy();
-+
-+    for artifact in &manifest.artifacts {
-+        ensure!(
-+            names.insert(artifact.name.as_str()),
-+            "sealed manifest contains duplicate artifact name '{}'",
-+            artifact.name
-+        );
-+        ensure!(
-+            matches!(artifact.kind.as_str(), "executable" | "side-module"),
-+            "sealed artifact '{}' has unsupported kind '{}'",
-+            artifact.name,
-+            artifact.kind
-+        );
-+        ensure!(
-+            !artifact.compressed,
-+            "sealed artifact '{}' must be an uncompressed, directly mappable AOT file",
-+            artifact.name
-+        );
-+        ensure!(
-+            artifact.sha256.eq_ignore_ascii_case(&artifact.raw_sha256),
-+            "sealed artifact '{}' must use the same packaged and raw digest when uncompressed",
-+            artifact.name
-+        );
-+        if artifact.kind == "executable" {
-+            ensure!(
-+                !artifact.exec_aliases.is_empty(),
-+                "sealed executable '{}' has no aliases",
-+                artifact.name
-+            );
-+        } else {
-+            ensure!(
-+                artifact.exec_aliases.is_empty(),
-+                "sealed side module '{}' must not declare executable aliases",
-+                artifact.name
-+            );
-+        }
-+
-+        let module_path = carrier_file_path(&carrier_root, &artifact.module_path)?;
-+        ensure!(
-+            module_paths.insert(module_path.clone()),
-+            "sealed manifest contains duplicate module path '{}'",
-+            artifact.module_path
-+        );
-+        // Raw module bytes do not authorize execution. Executables resolve
-+        // directly to the manifest hash, and guest-loaded side modules are
-+        // hashed by the loader before the authoritative cache lookup. A
-+        // changed raw module therefore resolves to NotFound. Avoid faulting
-+        // every inactive raw module into the cold-start cgroup here; validate
-+        // only its path/type/size and derive the admitted key from the strict
-+        // manifest. The AOT activation independently hashes its immutable
-+        // snapshot and checks the archive's embedded module hash.
-+        let raw_module = open_regular(&module_path)?;
-+        let raw_module_size = raw_module.metadata()?.len();
-+        ensure!(
-+            raw_module_size == artifact.module_size,
-+            "size mismatch for {}: manifest={} actual={}",
-+            module_path.display(),
-+            artifact.module_size,
-+            raw_module_size
-+        );
-+        let module_digest = parse_sha256("module-sha256", &artifact.module_sha256)?;
-+        let module_hash = ModuleHash::from_bytes(module_digest);
-+        tracing::debug!(
-+            target: "wasmer_cli::sealed_loader_audit",
-+            audit_schema = "oliphaunt.wasix-postmaster.sealed-loader-audit.v1",
-+            artifact_name = artifact.name.as_str(),
-+            artifact_kind = "raw-module",
-+            module_sha256 = %module_hash,
-+            activation_state = "inactive",
-+            snapshot_mode = "metadata-only-authoritative-on-use",
-+            logical_bytes = artifact.module_size,
-+            source_bytes_read = 0_u64,
-+            snapshot_bytes_written = 0_u64,
-+            mapping_bytes_hashed = 0_u64,
-+            sync_calls = 0_u64,
-+            write_policy = "none",
-+            "prepared sealed raw module identity"
-+        );
-+        drop(raw_module);
-+
-+        let artifact_path = carrier_file_path(&carrier_root, &artifact.path)?;
-+        ensure!(
-+            artifact_paths.insert(artifact_path.clone()),
-+            "sealed manifest contains duplicate AOT artifact path '{}'",
-+            artifact.path
-+        );
-+        ensure!(
-+            !artifacts.contains_key(&module_hash),
-+            "sealed manifest contains duplicate module hash {module_hash} for '{}'",
-+            artifact.name
-+        );
-+        ensure!(
-+            usize::try_from(artifact.raw_size).is_ok(),
-+            "AOT artifact '{}' is too large to map on this host",
-+            artifact.name
-+        );
-+        let artifact_source = open_regular(&artifact_path)?;
-+        ensure!(
-+            artifact_source.metadata()?.len() == artifact.raw_size,
-+            "size mismatch for {}: manifest={} actual={}",
-+            artifact_path.display(),
-+            artifact.raw_size,
-+            artifact_source.metadata()?.len()
-+        );
-+        let expected_artifact_digest = parse_sha256("raw-sha256", &artifact.raw_sha256)?;
-+        tracing::debug!(
-+            target: "wasmer_cli::sealed_loader_audit",
-+            audit_schema = "oliphaunt.wasix-postmaster.sealed-loader-audit.v1",
-+            artifact_name = artifact.name.as_str(),
-+            artifact_kind = "aot",
-+            module_sha256 = %module_hash,
-+            activation_state = "inactive",
-+            snapshot_mode = "deferred-open-fd",
-+            logical_bytes = artifact.raw_size,
-+            source_bytes_read = 0_u64,
-+            snapshot_bytes_written = 0_u64,
-+            mapping_bytes_hashed = 0_u64,
-+            sync_calls = 0_u64,
-+            write_policy = "none",
-+            "prepared sealed artifact descriptor"
-+        );
-+
-+        let input_matches = artifact.kind == "executable" && module_path == input_canonical;
-+        if artifact.kind == "executable" {
-+            let carrier_exec_path = module_path.to_string_lossy().into_owned();
-+            ensure!(
-+                aliases
-+                    .insert(carrier_exec_path.clone(), module_hash)
-+                    .is_none(),
-+                "sealed manifest contains duplicate executable alias '{carrier_exec_path}'"
-+            );
-+            executables.push((carrier_exec_path, module_hash));
-+        }
-+        for alias in &artifact.exec_aliases {
-+            validate_guest_alias(alias)?;
-+            ensure!(
-+                aliases.insert(alias.clone(), module_hash).is_none(),
-+                "sealed manifest contains duplicate executable alias '{alias}'"
-+            );
-+            executables.push((alias.clone(), module_hash));
-+        }
-+
-+        // The host input path selects an executable by its carrier-relative
-+        // module-path. Guest aliases remain Unix-style WASIX paths and are not
-+        // overloaded with host path syntax, which keeps the manifest portable
-+        // across Linux, macOS, and Windows hosts. Register the exact argv[0]
-+        // spelling as well so an EXEC_BACKEND using that path remains sealed.
-+        if input_matches {
-+            match aliases.get(input_name.as_ref()) {
-+                Some(existing_hash) => ensure!(
-+                    *existing_hash == module_hash,
-+                    "selected executable spelling '{}' belongs to a different sealed artifact",
-+                    input_name
-+                ),
-+                None => {
-+                    aliases.insert(input_name.to_string(), module_hash);
-+                    executables.push((input_name.to_string(), module_hash));
-+                }
-+            }
-+        }
-+
-+        artifacts.insert(
-+            module_hash,
-+            Arc::new(LazySealedArtifact::new(
-+                module_hash,
-+                expected_artifact_digest,
-+                SealedArtifactSource {
-+                    file: artifact_source,
-+                    path: artifact_path,
-+                    carrier_root: carrier_root.clone(),
-+                    expected_size: artifact.raw_size,
-+                },
-+                activation_policy,
-+            )),
-+        );
-+
-+        if artifact.name == manifest.entrypoint {
-+            ensure!(
-+                artifact.kind == "executable",
-+                "sealed manifest entrypoint '{}' is not executable",
-+                manifest.entrypoint
-+            );
-+            declared_entrypoint = true;
-+        }
-+
-+        if input_matches {
-+            ensure!(
-+                selected.is_none(),
-+                "input '{}' matches more than one sealed executable",
-+                input_path.display()
-+            );
-+            selected = Some(module_hash);
-+        }
-+    }
-+
-+    ensure!(
-+        declared_entrypoint,
-+        "sealed manifest entrypoint '{}' is not present in artifacts",
-+        manifest.entrypoint
-+    );
-+    let module_hash = selected.with_context(|| {
-+        format!(
-+            "input '{}' is not an alias of any sealed executable",
-+            input_path.display()
-+        )
-+    })?;
-+    let module_cache = Arc::new(SealedModuleCache::new(engine, artifacts));
-+    // The selected executable is the only artifact activated at startup. All
-+    // remaining executable and side-module descriptors stay file-backed and
-+    // cold until an exact alias/hash lookup reaches the authoritative cache.
-+    let module = module_cache
-+        .load_exact(module_hash, engine)
-+        .with_context(|| format!("activate selected sealed executable {module_hash}"))?;
-+
-+    Ok(LoadedSealedModules {
-+        module,
-+        module_hash,
-+        path: input_path.clone(),
-+        executables,
-+        module_cache,
-+    })
-+}
-+
-+fn validate_manifest_identity(manifest: &SealedManifest, engine: &Engine) -> Result<(), Error> {
-+    ensure!(
-+        manifest.format_version == MANIFEST_FORMAT_VERSION,
-+        "sealed manifest format mismatch: manifest={} runtime={MANIFEST_FORMAT_VERSION}",
-+        manifest.format_version
-+    );
-+    ensure!(
-+        manifest.schema == MANIFEST_SCHEMA,
-+        "sealed manifest schema mismatch: manifest={} runtime={MANIFEST_SCHEMA}",
-+        manifest.schema
-+    );
-+    ensure!(
-+        manifest.source_lane == "wasix-postmaster",
-+        "sealed manifest source lane must be 'wasix-postmaster'"
-+    );
-+    ensure_nonempty("source-fingerprint", &manifest.source_fingerprint)?;
-+    ensure!(
-+        matches!(manifest.core_profile.as_str(), "release-o3" | "safe-o2"),
-+        "sealed manifest core-profile must be release-o3 candidate or safe-o2 control"
-+    );
-+    ensure_nonempty("postgres-version", &manifest.postgres_version)?;
-+    ensure_nonempty("host-abi", &manifest.host_abi)?;
-+    ensure!(
-+        manifest.target_triple == Target::default().triple().to_string(),
-+        "sealed manifest target mismatch: manifest={} runtime={}",
-+        manifest.target_triple,
-+        Target::default().triple()
-+    );
-+    ensure!(
-+        manifest.engine == "llvm-opta",
-+        "sealed manifest producer engine must be 'llvm-opta'"
-+    );
-+    ensure_nonempty("compiler-config", &manifest.compiler_config)?;
-+    ensure!(
-+        manifest.cpu_policy == "generic-baseline" && manifest.cpu_features.is_empty(),
-+        "sealed manifest currently requires generic-baseline CPU policy with no host-specific features"
-+    );
-+    ensure!(
-+        manifest.wasmer_version == env!("CARGO_PKG_VERSION"),
-+        "sealed manifest Wasmer version mismatch: manifest={} runtime={}",
-+        manifest.wasmer_version,
-+        env!("CARGO_PKG_VERSION")
-+    );
-+    ensure!(
-+        manifest.wasmer_wasix_version == wasmer_wasix::VERSION,
-+        "sealed manifest wasmer-wasix version mismatch: manifest={} runtime={}",
-+        manifest.wasmer_wasix_version,
-+        wasmer_wasix::VERSION
-+    );
-+    ensure!(
-+        manifest.artifact_abi_version == ARTIFACT_ABI_VERSION,
-+        "sealed manifest artifact ABI mismatch: manifest={} runtime={ARTIFACT_ABI_VERSION}",
-+        manifest.artifact_abi_version
-+    );
-+    let runtime_abi_id = option_env!("OLIPHAUNT_WASIX_RUNTIME_ABI_ID").context(
-+        "this headless executor was not built with OLIPHAUNT_WASIX_RUNTIME_ABI_ID and cannot load sealed carriers",
-+    )?;
-+    ensure!(
-+        manifest.runtime_abi_id.eq_ignore_ascii_case(runtime_abi_id),
-+        "sealed manifest runtime ABI mismatch: manifest={} runtime={runtime_abi_id}",
-+        manifest.runtime_abi_id
-+    );
-+    ensure!(
-+        engine.deterministic_id() == manifest.executor_engine,
-+        "sealed manifest executor mismatch: manifest={} runtime={}",
-+        manifest.executor_engine,
-+        engine.deterministic_id()
-+    );
-+    ensure!(
-+        manifest.executor_engine == "engine-headless",
-+        "sealed modules require the compiler-free headless executor"
-+    );
-+    validate_linear_memory_profile(&manifest.linear_memory_profile)?;
-+
-+    validate_git_sha1("wasmer-source-commit", &manifest.wasmer_source_commit)?;
-+    for (field, value) in [
-+        ("wasmer-patch-sha256", manifest.wasmer_patch_sha256.as_str()),
-+        (
-+            "wasmer-cargo-lock-sha256",
-+            manifest.wasmer_cargo_lock_sha256.as_str(),
-+        ),
-+        (
-+            "producer-recipe-sha256",
-+            manifest.producer_recipe_sha256.as_str(),
-+        ),
-+        (
-+            "guest-build-recipe-sha256",
-+            manifest.guest_build_recipe_sha256.as_str(),
-+        ),
-+        ("runtime-abi-id", manifest.runtime_abi_id.as_str()),
-+        ("executor-sha256", manifest.executor_sha256.as_str()),
-+    ] {
-+        parse_sha256(field, value)?;
-+    }
-+    ensure!(
-+        manifest.executor_size > 0,
-+        "sealed manifest executor-size must be positive"
-+    );
-+    let mut features = BTreeSet::new();
-+    for feature in &manifest.wasm_features {
-+        ensure!(
-+            features.insert(feature.as_str()),
-+            "sealed manifest contains duplicate Wasm feature '{feature}'"
-+        );
-+    }
-+    for expected in EXPECTED_WASM_FEATURES {
-+        ensure!(
-+            features.contains(expected),
-+            "sealed manifest is missing required Wasm feature '{expected}'"
-+        );
-+    }
-+    ensure!(
-+        features.len() == EXPECTED_WASM_FEATURES.len(),
-+        "sealed manifest Wasm feature set must be exact: expected={:?} actual={:?}",
-+        EXPECTED_WASM_FEATURES,
-+        features
-+    );
-+    Ok(())
-+}
-+
-+fn audit_executor_trust_boundary(manifest: &SealedManifest) {
-+    // The executor digest comes from the same manifest and therefore cannot
-+    // authenticate that manifest or the running executable. The carrier's
-+    // external verifier/install boundary binds these bytes; compile-time ABI
-+    // and deterministic engine checks above enforce runtime compatibility.
-+    // Re-reading /proc/self/exe here would fault the whole executor into the
-+    // embedded cgroup without adding a cryptographic trust anchor.
-+    tracing::debug!(
-+        target: "wasmer_cli::sealed_loader_audit",
-+        audit_schema = "oliphaunt.wasix-postmaster.sealed-loader-audit.v1",
-+        artifact_kind = "headless-executor",
-+        activation_state = "external-verifier-trust-boundary",
-+        snapshot_mode = "metadata-only-no-runtime-read",
-+        logical_bytes = manifest.executor_size,
-+        source_bytes_read = 0_u64,
-+        source_bytes_written = 0_u64,
-+        snapshot_bytes_written = 0_u64,
-+        mapping_bytes_hashed = 0_u64,
-+        sync_calls = 0_u64,
-+        write_policy = "none",
-+        trust_binding = "external-carrier-verifier-plus-compile-time-runtime-abi",
-+        "accepted externally verified headless executor identity"
-+    );
-+}
-+
-+fn read_small_regular_file(path: &Path, max_size: u64) -> Result, Error> {
-+    let file = open_regular(path)?;
-+    let len = file.metadata()?.len();
-+    ensure!(len <= max_size, "file exceeds {max_size} byte limit");
-+    let read_limit = max_size
-+        .checked_add(1)
-+        .context("small regular file limit overflow")?;
-+    let capacity = usize::try_from(len.min(read_limit))
-+        .context("small regular file exceeds host address width")?;
-+    let mut bytes = Vec::with_capacity(capacity);
-+    file.take(read_limit).read_to_end(&mut bytes)?;
-+    ensure!(
-+        u64::try_from(bytes.len())
-+            .ok()
-+            .is_some_and(|len| len <= max_size),
-+        "file grew beyond {max_size} byte limit while being read"
-+    );
-+    Ok(bytes)
-+}
-+
-+fn immutable_artifact_snapshot(
-+    source: SealedArtifactSource,
-+    policy: SealedActivationPolicy,
-+) -> Result {
-+    let expected_size = source.expected_size;
-+    ensure!(
-+        usize::try_from(expected_size).is_ok(),
-+        "AOT artifact is too large to map on this host"
-+    );
-+    let metadata = source.file.metadata()?;
-+    ensure!(
-+        metadata.len() == expected_size,
-+        "size mismatch for {}: manifest={} actual={}",
-+        source.path.display(),
-+        expected_size,
-+        metadata.len()
-+    );
-+
-+    #[cfg(windows)]
-+    bail!(
-+        "sealed AOT activation is disabled on Windows until a pathless, deny-write snapshot lifecycle is implemented"
-+    );
-+
-+    #[cfg(target_os = "linux")]
-+    if let Ok(snapshot) = direct_immutable_artifact_snapshot(&source) {
-+        return Ok(snapshot);
-+    }
-+
-+    if policy.requires_direct_immutable() {
-+        bail!(
-+            "{REQUIRE_ZERO_WRITE_AOT_ENV}=1 requires direct activation from a SquashFS/EROFS or immutable-inode AOT source; refusing reflink and streamed-copy compatibility modes for {}",
-+            source.path.display()
-+        );
-+    }
-+
-+    #[cfg(target_os = "linux")]
-+    if let Ok(snapshot) = reflink_artifact_snapshot(&source) {
-+        return Ok(snapshot);
-+    }
-+
-+    streamed_artifact_snapshot(source)
-+}
-+
-+#[cfg(target_os = "linux")]
-+fn direct_immutable_artifact_snapshot(
-+    source: &SealedArtifactSource,
-+) -> Result {
-+    let immutable = intrinsic_file_immutability(&source.file).map_err(Error::msg)?;
-+    direct_artifact_snapshot_from_proof(source, immutable)
-+}
-+
-+#[cfg(target_os = "linux")]
-+fn direct_artifact_snapshot_from_proof(
-+    source: &SealedArtifactSource,
-+    immutable: IntrinsicFileImmutability,
-+) -> Result {
-+    let file = source
-+        .file
-+        .try_clone()
-+        .context("duplicate direct immutable AOT descriptor")?;
-+    ensure!(
-+        file.metadata()?.len() == source.expected_size,
-+        "direct immutable AOT artifact changed size"
-+    );
-+    Ok(ImmutableArtifactSnapshot {
-+        file,
-+        source_file: None,
-+        len: source.expected_size,
-+        audit: ArtifactSnapshotAudit {
-+            mode: ArtifactSnapshotMode::DirectIntrinsic(immutable),
-+            logical_bytes: source.expected_size,
-+            // The digest walks the source-backed mapping exactly once.
-+            source_bytes_read: source.expected_size,
-+            snapshot_bytes_written: 0,
-+            mapping_bytes_hashed: source.expected_size,
-+            sync_calls: 0,
-+        },
-+    })
-+}
-+
-+fn streamed_artifact_snapshot(
-+    mut source: SealedArtifactSource,
-+) -> Result {
-+    let expected_size = source.expected_size;
-+    let mut snapshot = create_disk_backed_snapshot_file(&source.carrier_root)?;
-+    let mut copied = 0_u64;
-+    let mut buffer = [0_u8; 128 * 1024];
-+    loop {
-+        let count = source.file.read(&mut buffer)?;
-+        if count == 0 {
-+            break;
-+        }
-+        copied = copied
-+            .checked_add(count as u64)
-+            .context("AOT artifact size overflow while creating immutable snapshot")?;
-+        ensure!(
-+            copied <= expected_size,
-+            "size mismatch for {}: manifest={} actual exceeds manifest size",
-+            source.path.display(),
-+            expected_size
-+        );
-+        snapshot.file_mut().write_all(&buffer[..count])?;
-+    }
-+    ensure!(
-+        copied == expected_size,
-+        "size mismatch for {}: manifest={} copied={copied}",
-+        source.path.display(),
-+        expected_size
-+    );
-+    let mut finalized = snapshot.finalize(
-+        expected_size,
-+        ArtifactSnapshotAudit {
-+            mode: ArtifactSnapshotMode::StreamedCopy,
-+            logical_bytes: expected_size,
-+            source_bytes_read: copied,
-+            snapshot_bytes_written: copied,
-+            mapping_bytes_hashed: expected_size,
-+            sync_calls: 0,
-+        },
-+    )?;
-+    finalized.source_file = Some(source.file);
-+    Ok(finalized)
-+}
-+
-+#[cfg(target_os = "linux")]
-+fn reflink_artifact_snapshot(
-+    source: &SealedArtifactSource,
-+) -> Result {
-+    use std::os::fd::AsRawFd;
-+
-+    let mut candidates = vec![
-+        source
-+            .path
-+            .parent()
-+            .context("sealed AOT artifact must have a parent directory")?
-+            .to_path_buf(),
-+    ];
-+    candidates.extend(artifact_snapshot_directories(&source.carrier_root));
-+    let mut seen = HashSet::new();
-+    let mut failures = Vec::new();
-+    for directory in candidates {
-+        if !seen.insert(directory.clone()) || !directory.is_dir() {
-+            continue;
-+        }
-+        let attempt = (|| -> Result<_, Error> {
-+            let destination = create_anonymous_snapshot_file(&directory)?;
-+            // SAFETY: both descriptors remain live for the ioctl. FICLONE
-+            // creates a copy-on-write clone and does not share later writes.
-+            // The kernel also rejects a destination on a different filesystem.
-+            let result = unsafe {
-+                libc::ioctl(
-+                    destination.as_raw_fd(),
-+                    libc::FICLONE,
-+                    source.file.as_raw_fd(),
-+                )
-+            };
-+            if result != 0 {
-+                return Err(std::io::Error::last_os_error()).context("reflink sealed AOT artifact");
-+            }
-+            ensure!(
-+                destination.metadata()?.len() == source.expected_size,
-+                "reflinked AOT artifact size mismatch"
-+            );
-+            let mut snapshot = WritableArtifactSnapshot::Anonymous(destination).finalize(
-+                source.expected_size,
-+                ArtifactSnapshotAudit {
-+                    mode: ArtifactSnapshotMode::Reflink,
-+                    logical_bytes: source.expected_size,
-+                    source_bytes_read: 0,
-+                    snapshot_bytes_written: 0,
-+                    mapping_bytes_hashed: source.expected_size,
-+                    sync_calls: 0,
-+                },
-+            )?;
-+            snapshot.source_file = Some(
-+                source
-+                    .file
-+                    .try_clone()
-+                    .context("duplicate reflink AOT source descriptor")?,
-+            );
-+            Ok(snapshot)
-+        })();
-+        match attempt {
-+            Ok(snapshot) => return Ok(snapshot),
-+            Err(error) => failures.push(format!("{}: {error:#}", directory.display())),
-+        }
-+    }
-+    bail!(
-+        "no writable same-filesystem O_TMPFILE destination accepted FICLONE{}",
-+        if failures.is_empty() {
-+            String::new()
-+        } else {
-+            format!(": {}", failures.join("; "))
-+        }
-+    )
-+}
-+
-+fn artifact_snapshot_directories(carrier_root: &Path) -> Vec {
-+    let mut candidates = Vec::new();
-+    if let Some(explicit) = std::env::var_os("OLIPHAUNT_WASIX_ARTIFACT_SNAPSHOT_DIR") {
-+        candidates.push(PathBuf::from(explicit));
-+    }
-+    candidates.push(carrier_root.to_path_buf());
-+    #[cfg(unix)]
-+    candidates.push(PathBuf::from("/var/tmp"));
-+    candidates.push(std::env::temp_dir());
-+    #[cfg(feature = "compat-cache-dir")]
-+    {
-+        if let Some(cache_dir) = dirs::cache_dir() {
-+            candidates.push(cache_dir);
-+        }
-+    }
-+    candidates
-+}
-+
-+fn create_disk_backed_snapshot_file(
-+    carrier_root: &Path,
-+) -> Result {
-+    let mut seen = HashSet::new();
-+    let mut failures = Vec::new();
-+    for candidate in artifact_snapshot_directories(carrier_root) {
-+        if !seen.insert(candidate.clone()) || !candidate.is_dir() {
-+            continue;
-+        }
-+        #[cfg(target_os = "linux")]
-+        match create_anonymous_snapshot_file(&candidate) {
-+            Ok(file) => return Ok(WritableArtifactSnapshot::Anonymous(file)),
-+            Err(error) => failures.push(format!("{} (O_TMPFILE): {error:#}", candidate.display())),
-+        }
-+        let attempt = (|| -> Result<_, Error> {
-+            let temp_dir = tempfile::Builder::new()
-+                .prefix(".wasmer-sealed-aot-")
-+                .tempdir_in(&candidate)
-+                .with_context(|| {
-+                    format!(
-+                        "create private snapshot directory in {}",
-+                        candidate.display()
-+                    )
-+                })?;
-+            #[cfg(unix)]
-+            {
-+                use std::os::unix::fs::PermissionsExt;
-+                fs::set_permissions(temp_dir.path(), fs::Permissions::from_mode(0o700))?;
-+            }
-+            let snapshot = tempfile::Builder::new()
-+                .prefix("artifact-")
-+                .tempfile_in(temp_dir.path())
-+                .context("create private snapshot file")?;
-+            ensure_disk_backed(snapshot.as_file())?;
-+            Ok(WritableArtifactSnapshot::Named {
-+                temp_dir,
-+                file: snapshot,
-+            })
-+        })();
-+        match attempt {
-+            Ok(snapshot) => return Ok(snapshot),
-+            Err(error) => failures.push(format!("{}: {error:#}", candidate.display())),
-+        }
-+    }
-+
-+    bail!(
-+        "unable to create a private disk-backed AOT snapshot{}",
-+        if failures.is_empty() {
-+            String::new()
-+        } else {
-+            format!(": {}", failures.join("; "))
-+        }
-+    )
-+}
-+
-+#[cfg(target_os = "linux")]
-+fn create_anonymous_snapshot_file(directory: &Path) -> Result {
-+    use std::os::unix::fs::OpenOptionsExt;
-+
-+    let mut options = OpenOptions::new();
-+    options
-+        .read(true)
-+        .write(true)
-+        .mode(0o600)
-+        .custom_flags(libc::O_TMPFILE | libc::O_CLOEXEC);
-+    let file = options
-+        .open(directory)
-+        .with_context(|| format!("create anonymous snapshot in {}", directory.display()))?;
-+    ensure_disk_backed(&file)?;
-+
-+    // Verify up front that this host exposes a safe way to downgrade the
-+    // anonymous inode to a read-only descriptor after the copy. If /proc is
-+    // unavailable, the caller will use the private named/unlink fallback.
-+    let probe = reopen_anonymous_snapshot_read_only(&file)?;
-+    verify_same_unix_file(&file, &probe)?;
-+    Ok(file)
-+}
-+
-+#[cfg(target_os = "linux")]
-+fn reopen_anonymous_snapshot_read_only(file: &File) -> Result {
-+    use std::os::{fd::AsRawFd, unix::fs::OpenOptionsExt};
-+
-+    let descriptor_path = PathBuf::from(format!("/proc/self/fd/{}", file.as_raw_fd()));
-+    let mut options = OpenOptions::new();
-+    options.read(true).custom_flags(libc::O_CLOEXEC);
-+    options.open(&descriptor_path).with_context(|| {
-+        format!(
-+            "reopen anonymous snapshot via {}",
-+            descriptor_path.display()
-+        )
-+    })
-+}
-+
-+#[cfg(target_os = "linux")]
-+fn verify_same_unix_file(first: &File, second: &File) -> Result<(), Error> {
-+    use std::os::unix::fs::MetadataExt;
-+
-+    let first = first.metadata()?;
-+    let second = second.metadata()?;
-+    ensure!(
-+        first.dev() == second.dev() && first.ino() == second.ino(),
-+        "private snapshot changed identity while being sealed"
-+    );
-+    Ok(())
-+}
-+
-+#[cfg(target_os = "linux")]
-+fn ensure_disk_backed(file: &File) -> Result<(), Error> {
-+    use std::os::fd::AsRawFd;
-+
-+    let mut stat = std::mem::MaybeUninit::::uninit();
-+    // SAFETY: `stat` points to writable storage and the file descriptor remains
-+    // open for the duration of the call.
-+    let result = unsafe { libc::fstatfs(file.as_raw_fd(), stat.as_mut_ptr()) };
-+    if result != 0 {
-+        return Err(std::io::Error::last_os_error()).context("identify snapshot filesystem");
-+    }
-+    // SAFETY: a successful fstatfs initialized the structure.
-+    let filesystem_type = unsafe { stat.assume_init() }.f_type as u64;
-+    const TMPFS_MAGIC: u64 = 0x0102_1994;
-+    const RAMFS_MAGIC: u64 = 0x8584_58f6;
-+    const HUGETLBFS_MAGIC: u64 = 0x9584_58f6;
-+    ensure!(
-+        !matches!(filesystem_type, TMPFS_MAGIC | RAMFS_MAGIC | HUGETLBFS_MAGIC),
-+        "snapshot filesystem is memory-backed (type 0x{filesystem_type:x})"
-+    );
-+    Ok(())
-+}
-+
-+#[cfg(not(target_os = "linux"))]
-+fn ensure_disk_backed(_file: &File) -> Result<(), Error> {
-+    Ok(())
-+}
-+
-+#[cfg(target_os = "linux")]
-+fn finalize_anonymous_snapshot(
-+    snapshot: File,
-+    expected_size: u64,
-+    audit: ArtifactSnapshotAudit,
-+) -> Result {
-+    use std::os::unix::fs::{MetadataExt, PermissionsExt};
-+
-+    snapshot.set_permissions(fs::Permissions::from_mode(0o400))?;
-+    let read_only = reopen_anonymous_snapshot_read_only(&snapshot)?;
-+    verify_same_unix_file(&snapshot, &read_only)?;
-+    ensure!(
-+        read_only.metadata()?.len() == expected_size,
-+        "anonymous snapshot changed size while being sealed"
-+    );
-+    ensure!(
-+        read_only.metadata()?.nlink() == 0,
-+        "anonymous snapshot unexpectedly acquired a filesystem path"
-+    );
-+    drop(snapshot);
-+    advise_file_away(&read_only);
-+    Ok(ImmutableArtifactSnapshot {
-+        file: read_only,
-+        source_file: None,
-+        len: expected_size,
-+        audit,
-+    })
-+}
-+
-+#[cfg(unix)]
-+fn finalize_named_snapshot(
-+    temp_dir: tempfile::TempDir,
-+    snapshot: tempfile::NamedTempFile,
-+    expected_size: u64,
-+    audit: ArtifactSnapshotAudit,
-+) -> Result {
-+    use std::os::unix::fs::{MetadataExt, OpenOptionsExt, PermissionsExt};
-+
-+    snapshot
-+        .as_file()
-+        .set_permissions(fs::Permissions::from_mode(0o400))?;
-+    let writer_metadata = snapshot.as_file().metadata()?;
-+    let path = snapshot.path().to_path_buf();
-+    let mut options = OpenOptions::new();
-+    options
-+        .read(true)
-+        .custom_flags(libc::O_CLOEXEC | libc::O_NOFOLLOW);
-+    let read_only = options
-+        .open(&path)
-+        .with_context(|| format!("reopen immutable snapshot {} read-only", path.display()))?;
-+    let reader_metadata = read_only.metadata()?;
-+    ensure!(
-+        writer_metadata.dev() == reader_metadata.dev()
-+            && writer_metadata.ino() == reader_metadata.ino(),
-+        "private snapshot changed identity while being sealed"
-+    );
-+    ensure!(
-+        reader_metadata.len() == expected_size,
-+        "private snapshot changed size while being sealed"
-+    );
-+
-+    fs::remove_file(&path)
-+        .with_context(|| format!("unlink immutable snapshot {}", path.display()))?;
-+    drop(snapshot);
-+    drop(temp_dir);
-+
-+    #[cfg(target_os = "linux")]
-+    ensure!(
-+        read_only.metadata()?.nlink() == 0,
-+        "immutable snapshot remained reachable by a filesystem path"
-+    );
-+    advise_file_away(&read_only);
-+    Ok(ImmutableArtifactSnapshot {
-+        file: read_only,
-+        source_file: None,
-+        len: expected_size,
-+        audit,
-+    })
-+}
-+
-+#[cfg(windows)]
-+fn finalize_named_snapshot(
-+    _temp_dir: tempfile::TempDir,
-+    _snapshot: tempfile::NamedTempFile,
-+    _expected_size: u64,
-+    _audit: ArtifactSnapshotAudit,
-+) -> Result {
-+    bail!(
-+        "Windows named-temp AOT snapshots are disabled: the prior close/reopen lifecycle could delete the path before establishing the final deny-write handle"
-+    )
-+}
-+
-+#[cfg(not(any(unix, windows)))]
-+fn finalize_named_snapshot(
-+    _temp_dir: tempfile::TempDir,
-+    _snapshot: tempfile::NamedTempFile,
-+    _expected_size: u64,
-+    _audit: ArtifactSnapshotAudit,
-+) -> Result {
-+    bail!("immutable sealed AOT snapshots are not implemented on this host")
-+}
-+
-+fn open_regular(path: &Path) -> Result {
-+    let mut options = OpenOptions::new();
-+    options.read(true);
-+    #[cfg(unix)]
-+    {
-+        use std::os::unix::fs::OpenOptionsExt;
-+        options.custom_flags(libc::O_CLOEXEC | libc::O_NOFOLLOW);
-+    }
-+    #[cfg(windows)]
-+    {
-+        use std::os::windows::fs::OpenOptionsExt;
-+        use windows_sys::Win32::Storage::FileSystem::FILE_SHARE_READ;
-+        // Keep the exact carrier inode stable for the duration of validation:
-+        // other handles may read it, but cannot obtain write/delete sharing.
-+        options.share_mode(FILE_SHARE_READ);
-+    }
-+    let file = options
-+        .open(path)
-+        .with_context(|| format!("open regular file {}", path.display()))?;
-+    ensure!(
-+        file.metadata()?.is_file(),
-+        "carrier path is not a regular file: {}",
-+        path.display()
-+    );
-+    Ok(file)
-+}
-+
-+fn carrier_file_path(root: &Path, relative: &str) -> Result {
-+    ensure_nonempty("carrier file path", relative)?;
-+    let relative_path = Path::new(relative);
-+    ensure!(
-+        relative_path
-+            .components()
-+            .all(|component| matches!(component, Component::Normal(_))),
-+        "carrier file path must be a normalized relative path: {relative}"
-+    );
-+    let canonical_root = root
-+        .canonicalize()
-+        .with_context(|| format!("resolve carrier root {}", root.display()))?;
-+    let path = canonical_root.join(relative_path);
-+    let canonical = path
-+        .canonicalize()
-+        .with_context(|| format!("resolve carrier file {}", path.display()))?;
-+    ensure!(
-+        canonical.starts_with(&canonical_root),
-+        "carrier file escapes carrier root: {relative}"
-+    );
-+    Ok(canonical)
-+}
-+
-+fn validate_guest_alias(alias: &str) -> Result<(), Error> {
-+    ensure!(
-+        alias.starts_with('/'),
-+        "guest executable alias must be absolute: {alias}"
-+    );
-+    ensure!(
-+        !alias.contains('\\')
-+            && alias
-+                .split('/')
-+                .skip(1)
-+                .all(|component| !component.is_empty() && component != "." && component != ".."),
-+        "guest executable alias must be normalized: {alias}"
-+    );
-+    Ok(())
-+}
-+
-+fn ensure_nonempty(field: &str, value: &str) -> Result<(), Error> {
-+    ensure!(
-+        !value.trim().is_empty(),
-+        "sealed manifest field '{field}' is empty"
-+    );
-+    Ok(())
-+}
-+
-+fn parse_sha256(field: &str, value: &str) -> Result<[u8; 32], Error> {
-+    ensure!(
-+        value.len() == 64,
-+        "sealed manifest field '{field}' is not a SHA-256 digest"
-+    );
-+    let mut digest = [0_u8; 32];
-+    hex::decode_to_slice(value, &mut digest)
-+        .with_context(|| format!("sealed manifest field '{field}' is not hexadecimal"))?;
-+    Ok(digest)
-+}
-+
-+fn validate_git_sha1(field: &str, value: &str) -> Result<(), Error> {
-+    ensure!(
-+        value.len() == 40,
-+        "sealed manifest field '{field}' is not a Git SHA-1"
-+    );
-+    ensure!(
-+        value.bytes().all(|byte| byte.is_ascii_hexdigit()),
-+        "sealed manifest field '{field}' is not hexadecimal"
-+    );
-+    Ok(())
-+}
-+
-+#[cfg(test)]
-+mod tests {
-+    use super::*;
-+
-+    fn test_artifact(expected: ExpectedWasixPostmasterArtifact, digest_byte: u8) -> SealedArtifact {
-+        let module_sha256 = format!("{digest_byte:02x}").repeat(32);
-+        let artifact_sha256 = format!("{:02x}", digest_byte.wrapping_add(32)).repeat(32);
-+        SealedArtifact {
-+            name: format!(
-+                "runtime:{}",
-+                expected
-+                    .module_path
-+                    .rsplit_once('/')
-+                    .map_or(expected.module_path, |(_, basename)| basename)
-+            ),
-+            kind: expected.kind.to_string(),
-+            path: format!("aot/{}.bin", module_sha256.to_ascii_uppercase()),
-+            module_path: expected.module_path.to_string(),
-+            sha256: artifact_sha256.clone(),
-+            raw_sha256: artifact_sha256,
-+            raw_size: 1,
-+            module_sha256,
-+            module_size: 1,
-+            linear_memory: SealedArtifactLinearMemory {
-+                profile_id: LINEAR_MEMORY_PROFILE_ID.to_string(),
-+                source_module_sha256: format!("{:02x}", digest_byte.wrapping_add(96)).repeat(32),
-+                install_receipt_sha256: "8".repeat(64),
-+            },
-+            compressed: false,
-+            exec_aliases: expected
-+                .exec_aliases
-+                .iter()
-+                .map(|alias| (*alias).to_string())
-+                .collect(),
-+        }
-+    }
-+
-+    fn test_wasix_postmaster_manifest() -> SealedManifest {
-+        SealedManifest {
-+            format_version: MANIFEST_FORMAT_VERSION,
-+            schema: MANIFEST_SCHEMA.to_string(),
-+            source_lane: WASIX_POSTMASTER_SOURCE_LANE.to_string(),
-+            source_fingerprint: "source-fingerprint".to_string(),
-+            core_profile: "release-o3".to_string(),
-+            guest_build_recipe_sha256: "7".repeat(64),
-+            postgres_version: "18.4".to_string(),
-+            target_triple: "test-target".to_string(),
-+            host_abi: "test-abi".to_string(),
-+            engine: "llvm-opta".to_string(),
-+            compiler_config: "test-compiler".to_string(),
-+            cpu_policy: "generic-baseline".to_string(),
-+            cpu_features: Vec::new(),
-+            wasmer_version: "test-wasmer".to_string(),
-+            wasmer_wasix_version: "test-wasmer-wasix".to_string(),
-+            wasmer_source_commit: "1".repeat(40),
-+            wasmer_patch_sha256: "2".repeat(64),
-+            wasmer_cargo_lock_sha256: "3".repeat(64),
-+            artifact_abi_version: ARTIFACT_ABI_VERSION,
-+            runtime_abi_id: "4".repeat(64),
-+            producer_recipe_sha256: "5".repeat(64),
-+            executor_engine: "engine-headless".to_string(),
-+            executor_sha256: "6".repeat(64),
-+            executor_size: 1,
-+            linear_memory_profile: SealedLinearMemoryProfile {
-+                id: LINEAR_MEMORY_PROFILE_ID.to_string(),
-+                address_width: "wasm32".to_string(),
-+                supported_host_pointer_width: "u64".to_string(),
-+                maximum_pages: LINEAR_MEMORY_MAXIMUM_PAGES,
-+                maximum_bytes: LINEAR_MEMORY_MAXIMUM_BYTES,
-+                static_bound_pages: LINEAR_MEMORY_STATIC_BOUND_PAGES,
-+                static_offset_guard_bytes: LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES,
-+                static_access_lowering: "wasmer-llvm-unchecked-reservation-and-guard-v1"
-+                    .to_string(),
-+                install_receipt_path: "receipts/linear-memory-profile.json".to_string(),
-+                install_receipt_sha256: "8".repeat(64),
-+            },
-+            wasm_features: EXPECTED_WASM_FEATURES
-+                .iter()
-+                .map(|feature| (*feature).to_string())
-+                .collect(),
-+            entrypoint: WASIX_POSTMASTER_ENTRYPOINT.to_string(),
-+            artifacts: EXPECTED_WASIX_POSTMASTER_EXECUTABLES
-+                .iter()
-+                .copied()
-+                .enumerate()
-+                .map(|(index, expected)| test_artifact(expected, index as u8 + 1))
-+                .chain(
-+                    SEALED_EXPORT_SIDE_PATHS
-+                        .iter()
-+                        .enumerate()
-+                        .map(|(index, module_path)| {
-+                            test_artifact(
-+                                ExpectedWasixPostmasterArtifact {
-+                                    kind: "side-module",
-+                                    module_path,
-+                                    exec_aliases: &[],
-+                                    executable: None,
-+                                },
-+                                index as u8 + 3,
-+                            )
-+                        }),
-+                )
-+                .collect(),
-+        }
-+    }
-+
-+    fn write_test_manifest(root: &Path) -> PathBuf {
-+        let mut manifest = test_wasix_postmaster_manifest();
-+        let mut modules: Vec<_> = manifest
-+            .artifacts
-+            .iter()
-+            .map(|artifact| LinearMemoryInstallModule {
-+                path: artifact.module_path.clone(),
-+                source_module_sha256: artifact.linear_memory.source_module_sha256.clone(),
-+                module_sha256: artifact.module_sha256.clone(),
-+                initial_pages: 1,
-+                maximum_pages: u64::from(LINEAR_MEMORY_MAXIMUM_PAGES),
-+                maximum_bytes: LINEAR_MEMORY_MAXIMUM_BYTES,
-+                shared: true,
-+                import_module: "env".to_string(),
-+                import_name: "memory".to_string(),
-+                transformation: SEALED_MODULE_TRANSFORMATION_ID.to_string(),
-+            })
-+            .collect();
-+        for (index, path) in SEALED_EXPORT_SIDE_PATHS.iter().enumerate() {
-+            if modules.iter().any(|module| module.path == *path) {
-+                continue;
-+            }
-+            modules.push(LinearMemoryInstallModule {
-+                path: (*path).to_string(),
-+                source_module_sha256: format!("{:02x}", 0x80 + index as u8).repeat(32),
-+                module_sha256: format!("{:02x}", 0xa0 + index as u8).repeat(32),
-+                initial_pages: 1,
-+                maximum_pages: u64::from(LINEAR_MEMORY_MAXIMUM_PAGES),
-+                maximum_bytes: LINEAR_MEMORY_MAXIMUM_BYTES,
-+                shared: true,
-+                import_module: "env".to_string(),
-+                import_name: "memory".to_string(),
-+                transformation: SEALED_MODULE_TRANSFORMATION_ID.to_string(),
-+            });
-+        }
-+        modules.sort_by(|left, right| left.path.cmp(&right.path));
-+        let source_sha256 = |path: &str| {
-+            modules
-+                .iter()
-+                .find(|module| module.path == path)
-+                .unwrap()
-+                .source_module_sha256
-+                .clone()
-+        };
-+        let side_identities = SEALED_EXPORT_SIDE_PATHS
-+            .iter()
-+            .map(|path| serde_json::json!({"path": path, "sha256": source_sha256(path)}))
-+            .collect::>();
-+        let proof_module = |path: &str, sha256: String| {
-+            serde_json::json!({
-+                "path": path,
-+                "sha256": sha256,
-+                "bytes": 1,
-+                "non-export-sections-sha256": "b".repeat(64),
-+                "dylink-needed": [],
-+                "imported-functions": 0,
-+                "local-functions": 1,
-+                "imported-globals": 0,
-+                "local-globals": 0,
-+                "imported-tables": 0,
-+                "local-tables": 1,
-+                "element-function-entries": 1,
-+                "element-unique-function-indices": 1,
-+                "element-max-function-index": 0,
-+                "start-function-index": 0,
-+                "imports": [],
-+                "export-counts": {},
-+                "exported-global-type-counts": {},
-+                "exported-immutable-i32-globals": 0,
-+                "exported-local-functions": 0,
-+                "exported-imported-functions": 0
-+            })
-+        };
-+        let proof = |main_sha256: String| {
-+            serde_json::json!({
-+                "schema": SEALED_EXPORT_PROOF_SCHEMA,
-+                "policy-id": SEALED_EXPORT_POLICY_ID,
-+                "analyzer-version": "fixture",
-+                "mandatory-policy-sha256": SEALED_EXPORT_MANDATORY_POLICY_SHA256,
-+                "declared-main-dlsym-policy-sha256": SEALED_EXPORT_DLSYM_POLICY_SHA256,
-+                "main": proof_module("bin/postgres", main_sha256),
-+                "sides": SEALED_EXPORT_SIDE_PATHS.iter().map(|path| {
-+                    proof_module(path, source_sha256(path))
-+                }).collect::>(),
-+                "mandatory-runtime-exports": [],
-+                "declared-main-dlsym-exports": [],
-+                "side-dynamic-imports": [],
-+                "retained-main-exports": [],
-+                "retained-main-export-descriptors": [],
-+                "removed-main-export-count": 1,
-+                "removed-main-export-names-sha256": "c".repeat(64),
-+                "unresolved-main-requirements": [],
-+                "mismatched-main-requirements": [],
-+                "unresolved-side-dependencies": [],
-+                "retained-counts": {},
-+                "removed-counts": {"function": 1}
-+            })
-+        };
-+        let seed_sha256 = "d".repeat(64);
-+        let final_sha256 = source_sha256("bin/postgres");
-+        let seed_proof_bytes = serde_json::to_vec(&proof(seed_sha256.clone())).unwrap();
-+        let final_proof_bytes = serde_json::to_vec(&proof(final_sha256.clone())).unwrap();
-+        let allowlist_bytes = b"fixture-export\n";
-+        let share = root.join("share/postgresql");
-+        fs::create_dir_all(&share).unwrap();
-+        fs::write(root.join(SEALED_EXPORT_SEED_PROOF_PATH), &seed_proof_bytes).unwrap();
-+        fs::write(
-+            root.join(SEALED_EXPORT_FINAL_PROOF_PATH),
-+            &final_proof_bytes,
-+        )
-+        .unwrap();
-+        fs::write(root.join(SEALED_EXPORT_ALLOWLIST_PATH), allowlist_bytes).unwrap();
-+        let snapshot = |sha256: String| {
-+            serde_json::json!({
-+                "sha256": sha256,
-+                "bytes": 1,
-+                "exports": 0,
-+                "local-functions": 1,
-+                "local-globals": 0,
-+                "element-function-entries": 1,
-+                "element-unique-function-indices": 1,
-+                "start-function-index": 0
-+            })
-+        };
-+        let export_receipt = serde_json::json!({
-+            "schema": SEALED_EXPORT_RECEIPT_SCHEMA,
-+            "policy-id": SEALED_EXPORT_POLICY_ID,
-+            "analyzer-version": "fixture",
-+            "analyzer-binary-sha256": "e".repeat(64),
-+            "dce-tool-sha256": "f".repeat(64),
-+            "dce-tool-version": "fixture-wasm-opt",
-+            "dce-passes": ["--remove-unused-module-elements"],
-+            "mandatory-policy-sha256": SEALED_EXPORT_MANDATORY_POLICY_SHA256,
-+            "declared-main-dlsym-policy-sha256": SEALED_EXPORT_DLSYM_POLICY_SHA256,
-+            "side-manifest-sha256": SEALED_EXPORT_SIDE_MANIFEST_SHA256,
-+            "allowlist-sha256": hex::encode(Sha256::digest(allowlist_bytes)),
-+            "seed-proof-sha256": hex::encode(Sha256::digest(&seed_proof_bytes)),
-+            "final-proof-sha256": hex::encode(Sha256::digest(&final_proof_bytes)),
-+            "seed": snapshot(seed_sha256),
-+            "final-module": snapshot(final_sha256),
-+            "sides": side_identities
-+        });
-+        let export_receipt_bytes = serde_json::to_vec(&export_receipt).unwrap();
-+        fs::write(root.join(SEALED_EXPORT_RECEIPT_PATH), &export_receipt_bytes).unwrap();
-+        let receipt = LinearMemoryInstallReceipt {
-+            schema: LINEAR_MEMORY_INSTALL_RECEIPT_SCHEMA.to_string(),
-+            profile_id: LINEAR_MEMORY_PROFILE_ID.to_string(),
-+            address_width: "wasm32".to_string(),
-+            supported_host_pointer_width: "u64".to_string(),
-+            maximum_pages: LINEAR_MEMORY_MAXIMUM_PAGES,
-+            maximum_bytes: LINEAR_MEMORY_MAXIMUM_BYTES,
-+            static_bound_pages: LINEAR_MEMORY_STATIC_BOUND_PAGES,
-+            static_offset_guard_bytes: LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES,
-+            static_access_lowering: "wasmer-llvm-unchecked-reservation-and-guard-v1".to_string(),
-+            requires_shared: true,
-+            requires_import: "env.memory".to_string(),
-+            excludes_wasm32_end_wrap: true,
-+            predecessor_export_closure_receipt: SEALED_EXPORT_RECEIPT_PATH.to_string(),
-+            predecessor_export_closure_receipt_sha256: hex::encode(Sha256::digest(
-+                &export_receipt_bytes,
-+            )),
-+            source_module_closure_sha256: linear_memory_closure_sha256(
-+                &modules,
-+                "source-module-sha256",
-+            ),
-+            module_closure_sha256: linear_memory_closure_sha256(&modules, "module-sha256"),
-+            module_count: modules.len(),
-+            modules,
-+        };
-+        let receipt_bytes = serde_json::to_vec(&receipt).unwrap();
-+        let receipt_sha256 = hex::encode(Sha256::digest(&receipt_bytes));
-+        manifest.linear_memory_profile.install_receipt_sha256 = receipt_sha256.clone();
-+        for artifact in &mut manifest.artifacts {
-+            artifact.linear_memory.install_receipt_sha256 = receipt_sha256.clone();
-+        }
-+        let receipt_path = root.join(&manifest.linear_memory_profile.install_receipt_path);
-+        fs::create_dir_all(receipt_path.parent().unwrap()).unwrap();
-+        fs::write(receipt_path, receipt_bytes).unwrap();
-+        let manifest_path = root.join("manifest.json");
-+        fs::write(&manifest_path, serde_json::to_vec(&manifest).unwrap()).unwrap();
-+        manifest_path
-+    }
-+
-+    fn source_from_bytes(carrier_root: &Path, name: &str, bytes: &[u8]) -> SealedArtifactSource {
-+        let path = carrier_root.join(name);
-+        fs::write(&path, bytes).unwrap();
-+        SealedArtifactSource {
-+            file: open_regular(&path).unwrap(),
-+            path,
-+            carrier_root: carrier_root.to_path_buf(),
-+            expected_size: bytes.len() as u64,
-+        }
-+    }
-+
-+    fn snapshot_from_bytes(
-+        carrier_root: &Path,
-+        name: &str,
-+        bytes: &[u8],
-+    ) -> ImmutableArtifactSnapshot {
-+        immutable_artifact_snapshot(
-+            source_from_bytes(carrier_root, name, bytes),
-+            SealedActivationPolicy::Compatibility,
-+        )
-+        .unwrap()
-+    }
-+
-+    fn lazy_artifact_from_bytes(
-+        carrier_root: &Path,
-+        name: &str,
-+        bytes: &[u8],
-+        module_hash: ModuleHash,
-+    ) -> LazySealedArtifact {
-+        LazySealedArtifact::new(
-+            module_hash,
-+            Sha256::digest(bytes).into(),
-+            source_from_bytes(carrier_root, name, bytes),
-+            SealedActivationPolicy::Compatibility,
-+        )
-+    }
-+
-+    #[test]
-+    fn runtime_policy_identity_requires_the_exact_postmaster_closure() {
-+        assert!(has_exact_wasix_postmaster_identity(
-+            &test_wasix_postmaster_manifest()
-+        ));
-+
-+        let mut missing = test_wasix_postmaster_manifest();
-+        missing.artifacts.pop();
-+        assert!(!has_exact_wasix_postmaster_identity(&missing));
-+
-+        let mut duplicate_path = test_wasix_postmaster_manifest();
-+        duplicate_path.artifacts[1].module_path = duplicate_path.artifacts[0].module_path.clone();
-+        assert!(!has_exact_wasix_postmaster_identity(&duplicate_path));
-+
-+        let mut reordered = test_wasix_postmaster_manifest();
-+        reordered.artifacts.swap(0, 1);
-+        assert!(!has_exact_wasix_postmaster_identity(&reordered));
-+
-+        let mut extra_feature = test_wasix_postmaster_manifest();
-+        extra_feature.wasm_features.push("simd".to_string());
-+        assert!(!has_exact_wasix_postmaster_identity(&extra_feature));
-+
-+        let mut unsupported_profile = test_wasix_postmaster_manifest();
-+        unsupported_profile.core_profile = "o3".to_string();
-+        assert!(!has_exact_wasix_postmaster_identity(&unsupported_profile));
-+
-+        let mut invalid_guest_recipe = test_wasix_postmaster_manifest();
-+        invalid_guest_recipe.guest_build_recipe_sha256 = "not-a-digest".to_string();
-+        assert!(!has_exact_wasix_postmaster_identity(&invalid_guest_recipe));
-+
-+        let mut superseded_schema = test_wasix_postmaster_manifest();
-+        superseded_schema.format_version = 5;
-+        superseded_schema.schema = "oliphaunt.wasix-postmaster.sealed-aot.v4".to_string();
-+        assert!(!has_exact_wasix_postmaster_identity(&superseded_schema));
-+    }
-+
-+    #[test]
-+    fn runtime_policy_identity_parser_rejects_unknown_manifest_fields() {
-+        let mut manifest = serde_json::to_value(test_wasix_postmaster_manifest()).unwrap();
-+        manifest
-+            .as_object_mut()
-+            .unwrap()
-+            .insert("runtime-policy".to_string(), serde_json::json!("unknown"));
-+        assert!(serde_json::from_value::(manifest).is_err());
-+
-+        let mut artifact_manifest = serde_json::to_value(test_wasix_postmaster_manifest()).unwrap();
-+        artifact_manifest["artifacts"][0]
-+            .as_object_mut()
-+            .unwrap()
-+            .insert("identity-extension".to_string(), serde_json::json!(true));
-+        assert!(serde_json::from_value::(artifact_manifest).is_err());
-+    }
-+
-+    #[test]
-+    fn small_regular_file_read_enforces_a_hard_stream_limit() {
-+        let root = tempfile::tempdir().unwrap();
-+        let path = root.path().join("bounded");
-+        fs::write(&path, b"12345678").unwrap();
-+        assert_eq!(read_small_regular_file(&path, 8).unwrap(), b"12345678");
-+
-+        fs::write(&path, b"123456789").unwrap();
-+        assert!(read_small_regular_file(&path, 8).is_err());
-+    }
-+
-+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
-+    #[test]
-+    fn strict_code_memory_state_directory_is_deterministic_private_and_deny_symlink() {
-+        use std::os::unix::{fs::MetadataExt, fs::PermissionsExt, fs::symlink};
-+
-+        let parent = tempfile::Builder::new()
-+            .prefix("oliphaunt-code-memory-state-test-")
-+            .tempdir_in("/var/tmp")
-+            .unwrap();
-+        let carrier = parent.path().join("immutable-carrier");
-+        fs::create_dir(&carrier).unwrap();
-+
-+        let (directory, device, inode) =
-+            strict_code_memory_directory_for_carrier(&carrier).unwrap();
-+        assert_eq!(directory, parent.path().join(CODE_MEMORY_STATE_DIRECTORY));
-+        let metadata = fs::symlink_metadata(&directory).unwrap();
-+        assert!(metadata.is_dir());
-+        assert!(!metadata.file_type().is_symlink());
-+        assert_eq!(metadata.uid(), unsafe { libc::geteuid() });
-+        assert_eq!(metadata.mode() & 0o7777, 0o700);
-+        assert_eq!(metadata.dev(), device);
-+        assert_eq!(metadata.ino(), inode);
-+        assert_eq!(
-+            strict_code_memory_directory_for_carrier(&carrier)
-+                .unwrap()
-+                .0,
-+            directory
-+        );
-+
-+        fs::remove_dir(&directory).unwrap();
-+        let redirect = parent.path().join("redirect");
-+        fs::create_dir(&redirect).unwrap();
-+        fs::set_permissions(&redirect, fs::Permissions::from_mode(0o700)).unwrap();
-+        symlink(&redirect, &directory).unwrap();
-+        let error = strict_code_memory_directory_for_carrier(&carrier).unwrap_err();
-+        assert!(error.to_string().contains("non-symlink"));
-+    }
-+
-+    #[test]
-+    fn runtime_policy_identity_selects_only_product_executables() {
-+        let root = tempfile::tempdir().unwrap();
-+        fs::create_dir_all(root.path().join("bin")).unwrap();
-+        let initdb = root.path().join("bin/initdb");
-+        let postgres = root.path().join("bin/postgres");
-+        let unrelated = root.path().join("bin/unrelated");
-+        fs::write(&initdb, b"initdb").unwrap();
-+        fs::write(&postgres, b"postgres").unwrap();
-+        fs::write(&unrelated, b"unrelated").unwrap();
-+        let manifest_path = write_test_manifest(root.path());
-+
-+        let prepared_initdb = prepare(&manifest_path, &initdb).unwrap();
-+        assert_eq!(
-+            prepared_initdb.runtime_identity(),
-+            Some(SealedRuntimeIdentity::WasixPostmasterInitdb)
-+        );
-+        let prepared_postgres = prepare(&manifest_path, &postgres).unwrap();
-+        assert_eq!(
-+            prepared_postgres.runtime_identity(),
-+            Some(SealedRuntimeIdentity::WasixPostmasterPostgres)
-+        );
-+        assert!(prepare(&manifest_path, &unrelated).is_err());
-+
-+        fs::write(&manifest_path, b"{").unwrap();
-+        assert!(prepare(&manifest_path, &root.path().join("bin/postgres")).is_err());
-+    }
-+
-+    #[test]
-+    fn carrier_paths_are_relative_and_normalized() {
-+        let root = tempfile::tempdir().unwrap();
-+        fs::write(root.path().join("artifact.bin"), b"artifact").unwrap();
-+        assert!(carrier_file_path(root.path(), "artifact.bin").is_ok());
-+        assert!(carrier_file_path(root.path(), "../artifact.bin").is_err());
-+        assert!(carrier_file_path(root.path(), "/artifact.bin").is_err());
-+        assert!(carrier_file_path(root.path(), "a/../artifact.bin").is_err());
-+    }
-+
-+    #[test]
-+    fn guest_aliases_are_absolute_and_normalized() {
-+        assert!(validate_guest_alias("/bin/postgres").is_ok());
-+        assert!(validate_guest_alias("bin/postgres").is_err());
-+        assert!(validate_guest_alias("/bin/../postgres").is_err());
-+        assert!(validate_guest_alias("/bin//postgres").is_err());
-+    }
-+
-+    #[test]
-+    fn sha256_fields_are_exact() {
-+        assert!(parse_sha256("digest", &"ab".repeat(32)).is_ok());
-+        assert!(parse_sha256("digest", &"ab".repeat(31)).is_err());
-+        assert!(parse_sha256("digest", &"zz".repeat(32)).is_err());
-+    }
-+
-+    #[test]
-+    fn artifact_snapshot_is_pathless_read_only_and_stable() {
-+        let root = tempfile::tempdir().unwrap();
-+        let original = b"verified artifact bytes";
-+        let snapshot = snapshot_from_bytes(root.path(), "artifact.bin", original);
-+
-+        assert_eq!(snapshot.audit.logical_bytes, original.len() as u64);
-+        assert_eq!(snapshot.audit.mapping_bytes_hashed, original.len() as u64);
-+        assert_eq!(snapshot.audit.sync_calls, 0);
-+        match snapshot.audit.mode {
-+            ArtifactSnapshotMode::DirectIntrinsic(_) => {
-+                assert_eq!(snapshot.audit.source_bytes_read, original.len() as u64);
-+                assert_eq!(snapshot.audit.snapshot_bytes_written, 0);
-+            }
-+            ArtifactSnapshotMode::Reflink => {
-+                assert_eq!(snapshot.audit.source_bytes_read, 0);
-+                assert_eq!(snapshot.audit.snapshot_bytes_written, 0);
-+            }
-+            ArtifactSnapshotMode::StreamedCopy => {
-+                assert_eq!(snapshot.audit.source_bytes_read, original.len() as u64);
-+                assert_eq!(snapshot.audit.snapshot_bytes_written, original.len() as u64);
-+            }
-+        }
-+
-+        fs::write(root.path().join("artifact.bin"), b"mutated artifact bytes!").unwrap();
-+        assert_eq!(snapshot.mapping().unwrap().as_slice(), original);
-+
-+        #[cfg(target_os = "linux")]
-+        {
-+            use std::os::{fd::AsRawFd, unix::fs::MetadataExt};
-+            assert_eq!(snapshot.file.metadata().unwrap().nlink(), 0);
-+            let flags = unsafe { libc::fcntl(snapshot.file.as_raw_fd(), libc::F_GETFL) };
-+            assert_ne!(flags, -1);
-+            assert_eq!(flags & libc::O_ACCMODE, libc::O_RDONLY);
-+        }
-+    }
-+
-+    #[test]
-+    fn streamed_snapshot_fallback_accounts_copy_without_sync() {
-+        let root = tempfile::tempdir().unwrap();
-+        let bytes = b"forced streamed snapshot bytes";
-+        let snapshot =
-+            streamed_artifact_snapshot(source_from_bytes(root.path(), "streamed.aot", bytes))
-+                .unwrap();
-+
-+        assert_eq!(snapshot.audit.mode, ArtifactSnapshotMode::StreamedCopy);
-+        assert_eq!(snapshot.audit.logical_bytes, bytes.len() as u64);
-+        assert_eq!(snapshot.audit.source_bytes_read, bytes.len() as u64);
-+        assert_eq!(snapshot.audit.snapshot_bytes_written, bytes.len() as u64);
-+        assert_eq!(snapshot.audit.mapping_bytes_hashed, bytes.len() as u64);
-+        assert_eq!(snapshot.audit.sync_calls, 0);
-+        assert_eq!(snapshot.mapping().unwrap().as_slice(), bytes);
-+        assert!(snapshot.has_distinct_source());
-+
-+        #[cfg(target_os = "linux")]
-+        {
-+            use std::os::unix::fs::MetadataExt;
-+
-+            let source = snapshot.source_file.as_ref().unwrap().metadata().unwrap();
-+            let private = snapshot.file.metadata().unwrap();
-+            assert_ne!((source.dev(), source.ino()), (private.dev(), private.ino()));
-+            let source_advice = snapshot.advise_source_away();
-+            let snapshot_advice = snapshot.advise_snapshot_away();
-+            assert_eq!(source_advice.calls, 1);
-+            assert_eq!(source_advice.successes, 1);
-+            assert_eq!(snapshot_advice.calls, 1);
-+            assert_eq!(snapshot_advice.successes, 1);
-+        }
-+    }
-+
-+    #[cfg(target_os = "linux")]
-+    #[test]
-+    fn direct_snapshot_accounts_no_payload_writes() {
-+        let root = tempfile::tempdir().unwrap();
-+        let bytes = b"direct immutable snapshot bytes";
-+        let source = source_from_bytes(root.path(), "direct.aot", bytes);
-+        // The kernel-proof classifier is covered in wasmer-wasix. Supplying a
-+        // proof here isolates accounting and live-FD mapping behavior.
-+        let snapshot =
-+            direct_artifact_snapshot_from_proof(&source, IntrinsicFileImmutability::ImmutableInode)
-+                .unwrap();
-+
-+        assert_eq!(
-+            snapshot.audit.mode,
-+            ArtifactSnapshotMode::DirectIntrinsic(IntrinsicFileImmutability::ImmutableInode)
-+        );
-+        assert_eq!(snapshot.audit.source_bytes_read, bytes.len() as u64);
-+        assert_eq!(snapshot.audit.snapshot_bytes_written, 0);
-+        assert_eq!(snapshot.audit.sync_calls, 0);
-+        assert_eq!(snapshot.mapping().unwrap().as_slice(), bytes);
-+        assert!(!snapshot.has_distinct_source());
-+        assert_eq!(
-+            snapshot.advise_snapshot_away(),
-+            FileAdviceAudit::not_applicable()
-+        );
-+    }
-+
-+    #[cfg(target_os = "linux")]
-+    #[test]
-+    fn required_zero_write_rejects_mutable_source_before_compatibility_copy() {
-+        let root = tempfile::tempdir().unwrap();
-+        let bytes = b"mutable AOT bytes";
-+        let source = source_from_bytes(root.path(), "mutable.aot", bytes);
-+        let error =
-+            immutable_artifact_snapshot(source, SealedActivationPolicy::RequireDirectImmutable)
-+                .unwrap_err();
-+
-+        assert!(error.to_string().contains("requires direct activation"));
-+        assert_eq!(fs::read(root.path().join("mutable.aot")).unwrap(), bytes);
-+        assert_eq!(fs::read_dir(root.path()).unwrap().count(), 1);
-+    }
-+
-+    #[cfg(unix)]
-+    #[test]
-+    fn loader_audit_receipt_is_owned_compact_jsonl() {
-+        use std::os::unix::fs::PermissionsExt;
-+
-+        let root = tempfile::tempdir().unwrap();
-+        let path = root.path().join("loader.jsonl");
-+        let record = LoaderAuditRecord {
-+            artifact_kind: "aot",
-+            module_sha256: "ab".repeat(32),
-+            snapshot_mode: "direct-immutable-inode",
-+            logical_bytes: 17,
-+            source_bytes_read: 0,
-+            source_bytes_written: 0,
-+            snapshot_bytes_written: 0,
-+            mapping_bytes_hashed: 17,
-+            sync_calls: 0,
-+            read_advice_applicable: true,
-+            read_advice_supported: true,
-+            read_advice_calls: 2,
-+            read_advice_successes: 2,
-+            read_advice_first_errno: None,
-+            source_cache_eviction_applicable: true,
-+            source_cache_eviction_supported: true,
-+            source_cache_eviction_calls: 1,
-+            source_cache_eviction_successes: 1,
-+            source_cache_eviction_errno: None,
-+            snapshot_cache_eviction_applicable: false,
-+            snapshot_cache_eviction_supported: true,
-+            snapshot_cache_eviction_calls: 0,
-+            snapshot_cache_eviction_successes: 0,
-+            snapshot_cache_eviction_errno: None,
-+            mapping_cache_eviction_applicable: false,
-+            mapping_cache_eviction_supported: true,
-+            mapping_cache_eviction_calls: 0,
-+            mapping_cache_eviction_successes: 0,
-+            mapping_cache_eviction_errno: None,
-+            residency_after_hash_inspect: LoaderResidencyRecord {
-+                state: "measured",
-+                page_size: Some(4096),
-+                total_pages: Some(1),
-+                resident_pages: Some(1),
-+                resident_bytes: Some(17),
-+                errno: None,
-+            },
-+            residency_after_archive_release: LoaderResidencyRecord {
-+                state: "measured",
-+                page_size: Some(4096),
-+                total_pages: Some(1),
-+                resident_pages: Some(1),
-+                resident_bytes: Some(17),
-+                errno: None,
-+            },
-+            source_residency_before_eviction: LoaderResidencyRecord {
-+                state: "measured",
-+                page_size: Some(4096),
-+                total_pages: Some(1),
-+                resident_pages: Some(1),
-+                resident_bytes: Some(17),
-+                errno: None,
-+            },
-+            source_residency_after_eviction: LoaderResidencyRecord {
-+                state: "measured",
-+                page_size: Some(4096),
-+                total_pages: Some(1),
-+                resident_pages: Some(0),
-+                resident_bytes: Some(0),
-+                errno: None,
-+            },
-+            residency_after_eviction: LoaderResidencyRecord {
-+                state: "measured",
-+                page_size: Some(4096),
-+                total_pages: Some(1),
-+                resident_pages: Some(0),
-+                resident_bytes: Some(0),
-+                errno: None,
-+            },
-+            write_policy: "none-immutable-source",
-+        };
-+        emit_loader_audit_to_path(&path, &record).unwrap();
-+
-+        let text = fs::read_to_string(&path).unwrap();
-+        assert_eq!(text.lines().count(), 1);
-+        let parsed: serde_json::Value = serde_json::from_str(text.trim()).unwrap();
-+        assert_eq!(
-+            parsed["schema"],
-+            "oliphaunt.wasix-postmaster.sealed-loader-receipt.v2"
-+        );
-+        assert_eq!(parsed["snapshot_mode"], "direct-immutable-inode");
-+        assert_eq!(parsed["source_bytes_written"], 0);
-+        assert_eq!(parsed["snapshot_bytes_written"], 0);
-+        assert_eq!(parsed["sync_calls"], 0);
-+        assert_eq!(parsed["read_advice_calls"], 2);
-+        assert_eq!(parsed["source_cache_eviction_successes"], 1);
-+        assert_eq!(parsed["snapshot_cache_eviction_applicable"], false);
-+        assert_eq!(parsed["mapping_cache_eviction_applicable"], false);
-+        assert_eq!(parsed["residency_after_eviction"]["resident_pages"], 0);
-+        assert_eq!(
-+            fs::metadata(path).unwrap().permissions().mode() & 0o777,
-+            0o600
-+        );
-+    }
-+
-+    #[test]
-+    fn loader_audit_module_hash_is_canonical_lowercase_sha256() {
-+        let module_hash = ModuleHash::from_bytes([0xab; 32]);
-+        assert_eq!(canonical_module_sha256(module_hash), "ab".repeat(32));
-+    }
-+
-+    #[test]
-+    fn failed_activation_is_single_flight_and_stable() {
-+        use std::sync::{Barrier, atomic::Ordering};
-+
-+        let root = tempfile::tempdir().unwrap();
-+        let module_hash = ModuleHash::from_bytes([0x11; 32]);
-+        let artifact = Arc::new(lazy_artifact_from_bytes(
-+            root.path(),
-+            "invalid.aot",
-+            b"not a Wasmer artifact",
-+            module_hash,
-+        ));
-+        let engine = Engine::headless();
-+        let cache = Arc::new(SealedModuleCache::new(
-+            &engine,
-+            HashMap::from([(module_hash, artifact.clone())]),
-+        ));
-+        let barrier = Arc::new(Barrier::new(8));
-+        let threads = (0..8)
-+            .map(|_| {
-+                let barrier = barrier.clone();
-+                let cache = cache.clone();
-+                let engine = engine.clone();
-+                std::thread::spawn(move || {
-+                    barrier.wait();
-+                    cache
-+                        .load_exact(module_hash, &engine)
-+                        .unwrap_err()
-+                        .to_string()
-+                })
-+            })
-+            .collect::>();
-+        let errors = threads
-+            .into_iter()
-+            .map(|thread| thread.join().unwrap())
-+            .collect::>();
-+
-+        assert!(errors.iter().all(|error| error == &errors[0]));
-+        assert_eq!(artifact.activation_attempts.load(Ordering::Relaxed), 1);
-+        assert!(matches!(
-+            cache.load_exact(ModuleHash::from_bytes([0x22; 32]), &engine),
-+            Err(CacheError::NotFound)
-+        ));
-+        let different_engine = Engine::headless();
-+        let engine_mismatch = cache
-+            .load_exact(module_hash, &different_engine)
-+            .unwrap_err();
-+        assert!(engine_mismatch.to_string().contains("engine mismatch"));
-+
-+        let fallback_error = futures::executor::block_on(wasmer_wasix::runtime::load_module(
-+            &engine,
-+            cache.as_ref(),
-+            wasmer_wasix::runtime::ModuleInput::Bytes(std::borrow::Cow::Borrowed(
-+                b"\0asm\x01\0\0\0",
-+            )),
-+            None,
-+        ))
-+        .unwrap_err();
-+        assert!(matches!(
-+            fallback_error,
-+            wasmer_wasix::SpawnError::CacheError(CacheError::NotFound)
-+        ));
-+    }
-+
-+    #[cfg(all(feature = "cranelift", feature = "wat"))]
-+    fn serialized_artifact(wat: &str) -> (Vec, ModuleHash) {
-+        let compiler_engine = Engine::new(
-+            Box::new(wasmer_compiler_cranelift::Cranelift::default()),
-+            Target::default(),
-+            wasmer_types::Features::default(),
-+        );
-+        let wasm = wasmer::wat2wasm(wat.as_bytes()).unwrap();
-+        let module_hash = ModuleHash::new(wasm.as_ref());
-+        let module = Module::new(&compiler_engine, wasm.as_ref()).unwrap();
-+        (module.serialize().unwrap().to_vec(), module_hash)
-+    }
-+
-+    #[cfg(all(
-+        feature = "cranelift",
-+        feature = "wat",
-+        target_os = "linux",
-+        target_arch = "x86_64"
-+    ))]
-+    #[test]
-+    fn post_publication_audit_failure_rolls_back_strict_code_memory() {
-+        use std::os::unix::fs::PermissionsExt;
-+
-+        let carrier_root = tempfile::tempdir().unwrap();
-+        let (bytes, module_hash) =
-+            serialized_artifact("(module (memory 1 4096 shared) (func (export \"selected\")))");
-+        let artifact =
-+            lazy_artifact_from_bytes(carrier_root.path(), "selected.aot", &bytes, module_hash);
-+
-+        let code_root = tempfile::Builder::new()
-+            .prefix("wasmer-sealed-pending-code-memory-test-")
-+            .tempdir_in("/var/tmp")
-+            .unwrap();
-+        fs::set_permissions(code_root.path(), fs::Permissions::from_mode(0o700)).unwrap();
-+        let policy =
-+            wasmer::sys::CodeMemoryPolicy::strict_linux_x86_64_file_backed(code_root.path())
-+                .unwrap();
-+        let mut engine = Engine::headless();
-+        engine.set_code_memory_policy(policy).unwrap();
-+        let baseline = engine.as_sys().code_memory_allocation_count();
-+
-+        let error = artifact
-+            .activate_with_audit(&engine, |_| {
-+                assert_eq!(
-+                    engine.as_sys().code_memory_allocation_count(),
-+                    baseline + 1,
-+                    "published code must remain transaction-owned during audit"
-+                );
-+                Err(anyhow::anyhow!("injected post-publication audit failure"))
-+            })
-+            .unwrap_err();
-+        assert!(
-+            error.to_string().contains("post-publication audit failure"),
-+            "unexpected activation failure: {error}"
-+        );
-+        assert_eq!(
-+            engine.as_sys().code_memory_allocation_count(),
-+            baseline,
-+            "failed admission must deregister and unmap its exact allocation"
-+        );
-+    }
-+
-+    #[cfg(all(feature = "cranelift", feature = "wat"))]
-+    #[test]
-+    fn selected_only_activation_and_success_are_single_flight() {
-+        use std::sync::{Barrier, atomic::Ordering};
-+
-+        let root = tempfile::tempdir().unwrap();
-+        let (selected_bytes, selected_hash) =
-+            serialized_artifact("(module (memory 1 4096 shared) (func (export \"selected\")))");
-+        let (cold_bytes, cold_hash) =
-+            serialized_artifact("(module (memory 1 4096 shared) (func (export \"cold\")))");
-+        let selected = Arc::new(lazy_artifact_from_bytes(
-+            root.path(),
-+            "selected.aot",
-+            &selected_bytes,
-+            selected_hash,
-+        ));
-+        let cold = Arc::new(lazy_artifact_from_bytes(
-+            root.path(),
-+            "cold.aot",
-+            &cold_bytes,
-+            cold_hash,
-+        ));
-+        let engine = Engine::headless();
-+        let cache = Arc::new(SealedModuleCache::new(
-+            &engine,
-+            HashMap::from([(selected_hash, selected.clone()), (cold_hash, cold.clone())]),
-+        ));
-+
-+        let selected_module = cache.load_exact(selected_hash, &engine).unwrap();
-+        assert_eq!(selected.activation_attempts.load(Ordering::Relaxed), 1);
-+        assert_eq!(cold.activation_attempts.load(Ordering::Relaxed), 0);
-+
-+        let barrier = Arc::new(Barrier::new(8));
-+        let threads = (0..8)
-+            .map(|_| {
-+                let barrier = barrier.clone();
-+                let cache = cache.clone();
-+                let engine = engine.clone();
-+                std::thread::spawn(move || {
-+                    barrier.wait();
-+                    cache.load_exact(selected_hash, &engine).unwrap();
-+                })
-+            })
-+            .collect::>();
-+        for thread in threads {
-+            thread.join().unwrap();
-+        }
-+        assert_eq!(selected.activation_attempts.load(Ordering::Relaxed), 1);
-+        assert_eq!(cold.activation_attempts.load(Ordering::Relaxed), 0);
-+
-+        cache.load_exact(cold_hash, &engine).unwrap();
-+        assert_eq!(cold.activation_attempts.load(Ordering::Relaxed), 1);
-+        drop(selected_module);
-+    }
-+}
-diff --git a/lib/oliphaunt-wasix-postmaster-executor/tests/check-dependency-policy.sh b/lib/oliphaunt-wasix-postmaster-executor/tests/check-dependency-policy.sh
-new file mode 100755
-index 0000000..53d8c63
---- /dev/null
-+++ b/lib/oliphaunt-wasix-postmaster-executor/tests/check-dependency-policy.sh
-@@ -0,0 +1,65 @@
-+#!/bin/sh
-+set -eu
-+
-+script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
-+workspace_root="$(CDPATH= cd -- "$script_dir/../../.." && pwd)"
-+package="oliphaunt-wasix-postmaster-executor"
-+
-+tree_file="$(mktemp)"
-+trap 'rm -f "$tree_file"' EXIT HUP INT TERM
-+
-+cd "$workspace_root"
-+cargo tree \
-+  --locked \
-+  --package "$package" \
-+  --no-default-features \
-+  --features product-executor \
-+  --edges normal \
-+  --prefix none \
-+  --format '{p}' >"$tree_file"
-+
-+# These roots are outside the product executor's closed compiler-free role.
-+# Check the resolved normal graph, not Cargo.lock: the workspace lock is also
-+# used by the compiler-bearing producer and therefore contains many of them.
-+for forbidden in \
-+  aws-lc-rs \
-+  aws-lc-sys \
-+  clap \
-+  clap_builder \
-+  clap_complete \
-+  clap_derive \
-+  clap_mangen \
-+  dirs \
-+  dirs-sys \
-+  hyper \
-+  hyper-rustls \
-+  hyper-tungstenite \
-+  reqwest \
-+  rustls \
-+  tokio-tungstenite \
-+  wasmer-backend-api \
-+  wasmer-cli \
-+  wasmer-compiler-cranelift \
-+  wasmer-compiler-llvm \
-+  wasmer-compiler-singlepass \
-+  wasmer-sdk \
-+  wasmer-wast \
-+  wast \
-+  wat \
-+  wcgi \
-+  wcgi-host
-+do
-+  if awk -v package="$forbidden" '$1 == package { found = 1 } END { exit !found }' "$tree_file"; then
-+    echo "forbidden product executor dependency is reachable: $forbidden" >&2
-+    exit 1
-+  fi
-+done
-+
-+for required in wasmer wasmer-vm wasmer-wasix virtual-fs virtual-net; do
-+  if ! awk -v package="$required" '$1 == package { found = 1 } END { exit !found }' "$tree_file"; then
-+    echo "required product executor runtime dependency is missing: $required" >&2
-+    exit 1
-+  fi
-+done
-+
-+printf '%s\n' "product executor dependency policy: ok"
 diff --git a/lib/types/src/libcalls.rs b/lib/types/src/libcalls.rs
 index 7aaada0..f38de45 100644
 --- a/lib/types/src/libcalls.rs
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/policies/sealed-main-dlsym-exports.v1.txt b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/policies/sealed-main-dlsym-exports.v1.txt
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/policies/sealed-main-dlsym-exports.v1.txt
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/policies/sealed-main-dlsym-exports.v1.txt
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/policies/sealed-main-runtime-exports.v1.txt b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/policies/sealed-main-runtime-exports.v1.txt
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/policies/sealed-main-runtime-exports.v1.txt
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/policies/sealed-main-runtime-exports.v1.txt
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/policies/sealed-side-modules.v1.tsv b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/policies/sealed-side-modules.v1.tsv
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/policies/sealed-side-modules.v1.tsv
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/policies/sealed-side-modules.v1.tsv
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/dir_readdir_unlink_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/dir_readdir_unlink_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/dir_readdir_unlink_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/dir_readdir_unlink_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/directory_fsync_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/directory_fsync_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/directory_fsync_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/directory_fsync_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/dynamic_dlopen_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/dynamic_dlopen_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/dynamic_dlopen_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/dynamic_dlopen_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/dynamic_probe_side.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/dynamic_probe_side.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/dynamic_probe_side.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/dynamic_probe_side.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/dynamic_vfork_exec_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/dynamic_vfork_exec_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/dynamic_vfork_exec_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/dynamic_vfork_exec_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_listen_accept_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_listen_accept_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_listen_accept_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_listen_accept_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_listen_after_vfork_exec_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_listen_after_vfork_exec_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_listen_after_vfork_exec_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_listen_after_vfork_exec_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_listen_external_after_pipe_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_listen_external_after_pipe_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_listen_external_after_pipe_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_listen_external_after_pipe_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_listen_external_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_listen_external_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_listen_external_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_listen_external_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_ofd_lifecycle_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_ofd_lifecycle_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/epoll_ofd_lifecycle_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/epoll_ofd_lifecycle_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/exec_shared_latch_sigurg_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/exec_shared_latch_sigurg_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/exec_shared_latch_sigurg_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/exec_shared_latch_sigurg_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/futex_timeout_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/futex_timeout_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/futex_timeout_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/futex_timeout_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/mmap_fixed_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/mmap_fixed_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/mmap_fixed_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/mmap_fixed_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/mmap_writeback_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/mmap_writeback_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/mmap_writeback_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/mmap_writeback_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/posix_spawn_blocking_wait_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/posix_spawn_blocking_wait_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/posix_spawn_blocking_wait_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/posix_spawn_blocking_wait_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/posix_spawn_pipe_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/posix_spawn_pipe_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/posix_spawn_pipe_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/posix_spawn_pipe_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/posix_spawn_sigchld_default_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/posix_spawn_sigchld_default_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/posix_spawn_sigchld_default_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/posix_spawn_sigchld_default_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/posix_spawn_sigchld_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/posix_spawn_sigchld_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/posix_spawn_sigchld_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/posix_spawn_sigchld_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/postgres_shmem_reattach_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/postgres_shmem_reattach_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/postgres_shmem_reattach_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/postgres_shmem_reattach_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/rlimit_stack_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/rlimit_stack_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/rlimit_stack_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/rlimit_stack_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/socket_nonblock_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/socket_nonblock_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/socket_nonblock_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/socket_nonblock_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/spawn_shmem_reattach_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/spawn_shmem_reattach_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/spawn_shmem_reattach_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/spawn_shmem_reattach_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/sync_file_range_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/sync_file_range_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/sync_file_range_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/sync_file_range_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/waitpid_wnohang_any_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/waitpid_wnohang_any_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/waitpid_wnohang_any_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/waitpid_wnohang_any_probe.c
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/wasm_eh_sjlj_probe.c b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/wasm_eh_sjlj_probe.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix-postmaster/runtime/probes/wasm_eh_sjlj_probe.c
rename to src/runtimes/liboliphaunt-wasix-postmaster/wasmer/probes/wasm_eh_sjlj_probe.c
diff --git a/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/tests.sh b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/tests.sh
new file mode 100644
index 000000000..97c9c7e91
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix-postmaster/wasmer/tests.sh
@@ -0,0 +1,263 @@
+#!/usr/bin/env bash
+# Sourced by bin/build-runtime.sh --tests-only after preparing the pinned runtime.
+
+run_tests() {
+	local log
+	log="$(mktemp)"
+	if ! cargo test "$@" --color never 2>&1 | tee "$log"; then
+		rm -f "$log"
+		return 1
+	fi
+	if ! grep -Eq '^test result: ok\. [1-9][0-9]* passed;' "$log"; then
+		printf 'runtime test selection ran no tests: %s\n' "$*" >&2
+		rm -f "$log"
+		return 1
+	fi
+	rm -f "$log"
+}
+
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/vm/Cargo.toml" \
+	-- \
+	remap_shared_file_fixed_replaces_only_requested_pages \
+	remap_shared_file_fixed_accepts_a_partial_final_file_page \
+	remap_private_file_fixed_shares_clean_bytes_but_isolates_writes \
+	immutable_function_tables_are_shared_by_two_instances \
+	shared_function_tables_outlive_artifact_owner_and_peer_instance
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/vm/Cargo.toml" \
+	-- \
+	--exact \
+	instance::allocator::tests::cached_offsets_produce_the_same_allocator_layout \
+	trap::traphandlers::tests::tls_stack_reuses_mapping_without_global_queue
+if [ "$(uname -s)-$(uname -m)" = Linux-x86_64 ]; then
+	run_tests \
+		--locked \
+		--target-dir "$WASMER_TARGET_DIR" \
+		--manifest-path "$WASMER_ROOT/lib/compiler/Cargo.toml" \
+		-- \
+		--exact \
+		engine::code_memory::tests::strict_linux_x86_64::relocated_regular_file_preserves_base_bytes_permissions_and_execution
+fi
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/compiler/Cargo.toml" \
+	--lib \
+	-- \
+	engine::trap::frame_info::tests
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
+	--lib \
+	--no-default-features \
+	--features sys-minimal,wasmer/cranelift \
+	-- \
+	shared_memory_mapping \
+	state::linker::dynamic_instance_export_tests \
+	state::linker::single_slot_broadcast_tests \
+	runtime::sealed_loader_audit::tests \
+	state::preinitialized_memory_image::tests \
+	syscalls::wasix::path_open2::tests \
+	syscalls::wasi::fd_advise::tests \
+	syscalls::wasix::fd_sync_range::tests \
+	required_import_tests \
+	os::task::control_plane::tests \
+	state::env::tests \
+	runtime::task_manager::lifecycle_tests \
+	runtime::task_manager::tokio::tests \
+	bin_factory::exec::lifecycle_tests \
+	syscalls::wasix::proc_signal::tests \
+	state::tests \
+	syscalls::wasix::proc_join::tests \
+	fs::fd_list::tests::renumber \
+	epoll
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
+	--lib \
+	--no-default-features \
+	--features sys-minimal,host-fs,wasmer/cranelift \
+	-- \
+	--exact \
+	fs::tests::host_file_size_refresh_observes_another_process_extension
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
+	-- \
+	host_file_defers_async_descriptor_until_async_io_is_requested \
+	file_advice \
+	shared_positioned_read \
+	file_writeback
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
+	--lib \
+	--features wasmer/cranelift \
+	-- \
+	--exact \
+	state::tests::live_shared_mapping_registry_blocks_backing_file_shrink
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
+	--lib \
+	--features wasmer/cranelift \
+	-- \
+	utils::store::tests
+if [ "$(uname -s)" = Linux ]; then
+	run_tests \
+		--locked \
+		--target-dir "$WASMER_TARGET_DIR" \
+		--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
+		-- \
+		host_file_range_writeback
+fi
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
+	--lib \
+	--no-default-features \
+	--features sys-minimal,wasmer/cranelift,ctrlc \
+	-- \
+	--test-threads=1 \
+	os::task::task_join_handle::tests
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
+	--lib \
+	--no-default-features \
+	--features sys-minimal,wasmer/cranelift,ctrlc \
+	-- \
+	runners::wasi::
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
+	--test memory \
+	--no-default-features \
+	--features sys,headless \
+	-- \
+	--exact \
+	private_file_remap_preserves_memory_base_growth_and_mapping_lifetime
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/Cargo.toml" \
+	--test compilers \
+	--features test-llvm \
+	-- \
+	--exact \
+	issues::llvm_rotates_and_atomic_fence_emit_expected_ir \
+	wast::spec::data_drop0::llvm::llvm \
+	wast::spec::memory_init::llvm::llvm
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$FRESH_ROOT/executor/Cargo.toml" \
+	--lib \
+	--no-default-features \
+	--features "$FRESH_POSTMASTER_EXECUTOR_FEATURES" \
+	-- \
+	sealed::tests::runtime_policy_identity_
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$FRESH_ROOT/executor/Cargo.toml" \
+	--lib \
+	--no-default-features \
+	--features cranelift,wat \
+	-- \
+	--exact \
+	sealed::tests::selected_only_activation_and_success_are_single_flight
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$FRESH_ROOT/executor/Cargo.toml" \
+	--bin "$FRESH_START_PROOF_BINARY" \
+	--no-default-features \
+	--features "$FRESH_START_PROOF_FEATURES" \
+	--
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/cli/Cargo.toml" \
+	--lib \
+	--no-default-features \
+	--features "$FRESH_WASMER_HEADLESS_FEATURES" \
+	-- \
+	commands::run::runtime::tests \
+	commands::run::tests
+run_tests \
+	--locked \
+	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
+	--manifest-path "$FRESH_ROOT/executor/Cargo.toml" \
+	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
+	--no-default-features \
+	--features "$FRESH_POSTMASTER_EXECUTOR_FEATURES" \
+	--
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
+	--test module \
+	-- \
+	serialized_artifact_inspector
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
+	--test module \
+	-- \
+	--exact \
+	detached_module_executes_from_strict_relocated_regular_file_code_memory \
+	detached_mmapped_module_executes_without_retaining_serializable_state
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
+	--test instance \
+	-- \
+	--exact \
+	selectively_materialized_exports_remain_available_by_module_identity
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
+	--test instance \
+	--no-default-features \
+	--features sys,llvm,wat \
+	-- \
+	--exact \
+	passive_data_drop_is_local_to_each_instance \
+	passive_data_memory_init_preserves_contents_and_bounds
+run_tests \
+	--locked \
+	--target-dir "$WASMER_TARGET_DIR" \
+	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
+	--test module \
+	--no-default-features \
+	--features sys,llvm,wat \
+	-- \
+	--exact \
+	detached_artifact_passive_data_has_instance_local_drop_state
+run_tests \
+	--locked \
+	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
+	--manifest-path "$FRESH_ROOT/executor/Cargo.toml" \
+	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
+	--lib \
+	--no-default-features \
+	--features "$FRESH_MEMORY_PROFILE_FEATURES" \
+	-- \
+	memory_profile::wasm_tool::tests
diff --git a/src/runtimes/liboliphaunt-wasix/CHANGELOG.md b/src/runtimes/liboliphaunt-wasix/CHANGELOG.md
new file mode 100644
index 000000000..bdb402b44
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/CHANGELOG.md
@@ -0,0 +1,49 @@
+# Changelog
+
+## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-wasix-v0.1.1...liboliphaunt-wasix-v0.2.0) (2026-09-05)
+
+
+### ⚠ BREAKING CHANGES
+
+* **wasix-ts:** run host runtimes through Rust Node-API ([#156](https://github.com/f0rr0/oliphaunt/issues/156))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
+
+### Features
+
+* **contrib:** shared contrib carrier source: simplify releases and make contrib runtime-owned (#127) (c45082dc)
+* **contrib:** shared contrib carrier source: unify native and WASIX runtimes and SDKs (#129) (fae2bd7b)
+* **contrib:** shared contrib carrier source: model independent product dependencies (#173) (2d5f90c8)
+* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
+* **wasix-ts:** run host runtimes through Rust Node-API ([#156](https://github.com/f0rr0/oliphaunt/issues/156)) ([28e07be](https://github.com/f0rr0/oliphaunt/commit/28e07be782388915b28ad3fd30e3e78143710d28))
+
+
+### Bug Fixes
+
+* **wasix:** align WAL sync patch identity ([#163](https://github.com/f0rr0/oliphaunt/issues/163)) ([1708ef4](https://github.com/f0rr0/oliphaunt/commit/1708ef43aa092645cac57564c20bbd40e89d3894))
+* **wasix:** reject unsupported WAL open-sync modes ([#159](https://github.com/f0rr0/oliphaunt/issues/159)) ([6e9f903](https://github.com/f0rr0/oliphaunt/commit/6e9f9032ef802a970dc1d763e29b66b8e5d17f2f))
+
+
+### Performance Improvements
+
+* **wasix:** cache JSONB constructor metadata ([#164](https://github.com/f0rr0/oliphaunt/issues/164)) ([31bb5e1](https://github.com/f0rr0/oliphaunt/commit/31bb5e19b13ea002b311dfb57f110dfc54cf563e))
+
+
+### Code Refactoring
+
+* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
+* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
+
+## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-wasix-v0.1.0...liboliphaunt-wasix-v0.1.1) (2026-08-08)
+
+
+### Bug Fixes
+
+* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))
+
+## 0.1.0 (2026-07-28)
+
+
+### Features
+
+* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/runtimes/liboliphaunt/wasix/VERSION b/src/runtimes/liboliphaunt-wasix/VERSION
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/VERSION
rename to src/runtimes/liboliphaunt-wasix/VERSION
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/.gitignore b/src/runtimes/liboliphaunt-wasix/assets/build/.gitignore
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/.gitignore
rename to src/runtimes/liboliphaunt-wasix/assets/build/.gitignore
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/analyze_pgl_stubs.sh b/src/runtimes/liboliphaunt-wasix/assets/build/analyze_pgl_stubs.sh
similarity index 98%
rename from src/runtimes/liboliphaunt/wasix/assets/build/analyze_pgl_stubs.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/analyze_pgl_stubs.sh
index 2d5d4c4ed..25b8de33c 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/analyze_pgl_stubs.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/analyze_pgl_stubs.sh
@@ -7,7 +7,7 @@ REPO_ROOT="$(oliphaunt_wasix_repo_root "$ROOT")"
 
 IMAGE="${IMAGE:-oliphaunt-wasix-wasix-build:local}"
 JOBS="${JOBS:-4}"
-CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt/wasix/assets/build}"
+CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt-wasix/assets/build}"
 CONTAINER_GENERATED_ROOT="${CONTAINER_GENERATED_ROOT:-/work/target/oliphaunt-wasix/wasix-build}"
 CONTAINER_BUILD_DIR="${CONTAINER_BUILD_DIR:-$CONTAINER_GENERATED_ROOT/work/docker-oliphaunt}"
 CONTAINER_PGSRC="${CONTAINER_PGSRC:-$CONTAINER_GENERATED_ROOT/work/postgres18-wasix-src}"
@@ -39,7 +39,7 @@ fi
   "$IMAGE" \
   bash -lc '
     set -euo pipefail
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
     test -f "$BUILD_DIR/src/backend/oliphaunt"
 
     mkdir -p "$CONTAINER_GENERATED_ROOT/build/link-analysis"
diff --git a/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_geos.sh b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_geos.sh
new file mode 100755
index 000000000..6368e4b2a
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_geos.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+. "$ROOT/wasix_third_party.sh"
+
+REPO_ROOT="$(oliphaunt_wasix_repo_root "$ROOT")"
+GEOS_SOURCE_DIR="${GEOS_SOURCE_DIR:-$REPO_ROOT/target/oliphaunt-sources/checkouts/geos}"
+GENERATED_ROOT="$(oliphaunt_wasix_generated_root "$REPO_ROOT")"
+GEOS_PREFIX="${GEOS_PREFIX:-$GENERATED_ROOT/work/geos-wasix}"
+GEOS_BUILD_DIR="${GEOS_BUILD_DIR:-$GENERATED_ROOT/work/geos-wasix-build}"
+JOBS="${JOBS:-4}"
+
+if [ ! -f "$GEOS_SOURCE_DIR/CMakeLists.txt" ]; then
+  echo "missing GEOS source checkout at $GEOS_SOURCE_DIR; run bash src/third-party/tools/fetch-sources.sh wasix-runtime --force first" >&2
+  exit 1
+fi
+
+. "$ROOT/docker_wasix_env.sh"
+. "$ROOT/profile_flags.sh"
+oliphaunt_wasix_apply_wasix_profile build
+
+source_commit="$(oliphaunt_wasix_source_commit "$GEOS_SOURCE_DIR")"
+script_sha256="$(oliphaunt_wasix_script_sha256 "$0")"
+helper_sha256="$(oliphaunt_wasix_script_sha256 "$ROOT/wasix_third_party.sh")"
+wasixcc_version="$(wasixcc --version 2>/dev/null)"
+wasixcc_version="${wasixcc_version%%$'\n'*}"
+stamp="source=$source_commit
+script=$script_sha256
+helper=$helper_sha256
+profile=$(oliphaunt_wasix_wasix_profile_signature)
+wasixcc=$wasixcc_version
+cmake=static-libs-only-no-tests"
+
+if [ -f "$GEOS_PREFIX/.oliphaunt-wasix-geos-build" ] &&
+   [ -f "$GEOS_PREFIX/include/geos_c.h" ] &&
+   [ -f "$GEOS_PREFIX/lib/libgeos_c.a" ] &&
+   [ -f "$GEOS_PREFIX/lib/libgeos.a" ] &&
+   [ "$(cat "$GEOS_PREFIX/.oliphaunt-wasix-geos-build")" = "$stamp" ]; then
+  echo "$GEOS_PREFIX"
+  exit 0
+fi
+
+{
+  rm -rf "$GEOS_BUILD_DIR"
+  mkdir -p "$GEOS_BUILD_DIR" "$(dirname "$GEOS_PREFIX")"
+  install_stage="$(mktemp -d "$GEOS_PREFIX.install.XXXXXX")"
+  staged_prefix="$install_stage$GEOS_PREFIX"
+  trap 'rm -rf "$install_stage"' EXIT
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
+  DESTDIR="$install_stage" oliphaunt_wasix_static_cmake_build \
+    "$GEOS_SOURCE_DIR" \
+    "$GEOS_BUILD_DIR" \
+    "$GEOS_PREFIX" \
+    -DBUILD_TESTING=OFF \
+    -DBUILD_BENCHMARKS=OFF \
+    -DBUILD_GEOSOP=OFF \
+    -DGEOS_BUILD_DEVELOPER=OFF
+} >&2
+
+test -f "$staged_prefix/include/geos_c.h"
+test -f "$staged_prefix/lib/libgeos_c.a"
+test -f "$staged_prefix/lib/libgeos.a"
+printf '%s\n' "$stamp" > "$staged_prefix/.oliphaunt-wasix-geos-build"
+oliphaunt_wasix_publish_prefix "$staged_prefix" "$GEOS_PREFIX"
+echo "$GEOS_PREFIX"
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_icu.sh
similarity index 77%
rename from src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_icu.sh
index 31a22af7d..e7685e799 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_icu.sh
@@ -5,8 +5,8 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 . "$ROOT/wasix_third_party.sh"
 
 REPO_ROOT="$(oliphaunt_wasix_repo_root "$ROOT")"
-NATIVE_ICU_HELPER="$REPO_ROOT/src/runtimes/liboliphaunt/native/bin/icu.sh"
-. "$NATIVE_ICU_HELPER"
+ICU_HELPER="$REPO_ROOT/src/third-party/icu/tools/build.sh"
+. "$ICU_HELPER"
 ICU_SOURCE_DIR="${ICU_SOURCE_DIR:-$REPO_ROOT/target/oliphaunt-sources/checkouts/icu/icu4c/source}"
 GENERATED_ROOT="$(oliphaunt_wasix_generated_root "$REPO_ROOT")"
 ICU_NATIVE_BUILD_DIR="${ICU_NATIVE_BUILD_DIR:-$GENERATED_ROOT/work/icu-native}"
@@ -15,7 +15,7 @@ ICU_BUILD_DIR="${ICU_BUILD_DIR:-$GENERATED_ROOT/work/icu-wasix-build}"
 JOBS="${JOBS:-4}"
 
 if [ ! -x "$ICU_SOURCE_DIR/configure" ]; then
-  echo "missing ICU source checkout at $ICU_SOURCE_DIR; run \`cargo run -p xtask -- assets fetch\` first" >&2
+  echo "missing ICU source checkout at $ICU_SOURCE_DIR; run \`bash src/third-party/tools/fetch-sources.sh wasix-runtime --force\` first" >&2
   exit 1
 fi
 
@@ -26,14 +26,14 @@ oliphaunt_wasix_apply_wasix_profile build
 source_commit="$(oliphaunt_wasix_source_commit "$ICU_SOURCE_DIR/../../")"
 script_sha256="$(oliphaunt_wasix_script_sha256 "$0")"
 helper_sha256="$(oliphaunt_wasix_script_sha256 "$ROOT/wasix_third_party.sh")"
-native_icu_helper_sha256="$(oliphaunt_wasix_script_sha256 "$NATIVE_ICU_HELPER")"
+icu_helper_sha256="$(oliphaunt_wasix_script_sha256 "$ICU_HELPER")"
 wasixcc_version="$(wasixcc --version 2>/dev/null)"
 wasixcc_version="${wasixcc_version%%$'\n'*}"
 stamp="schema=oliphaunt-wasix-icu-v8
 source=$source_commit
 script=$script_sha256
 helper=$helper_sha256
-native-icu-helper=$native_icu_helper_sha256
+icu-helper=$icu_helper_sha256
 profile=$(oliphaunt_wasix_wasix_profile_signature)
 wasixcc=$wasixcc_version
 canonical-data-sha256=$(oliphaunt_icu_canonical_data_sha256)
@@ -60,11 +60,15 @@ if [ -f "$ICU_PREFIX/.oliphaunt-wasix-icu-build" ] &&
 fi
 
 {
-  rm -rf "$ICU_BUILD_DIR" "$ICU_PREFIX"
+  rm -rf "$ICU_BUILD_DIR"
   mkdir -p "$ICU_BUILD_DIR" "$(dirname "$ICU_PREFIX")"
+  install_stage="$(mktemp -d "$ICU_PREFIX.install.XXXXXX")"
+  staged_prefix="$install_stage$ICU_PREFIX"
+  trap 'rm -rf "$install_stage"' EXIT
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
   oliphaunt_icu_build_native_tools \
     "$ICU_SOURCE_DIR" \
-    "$(dirname "$NATIVE_ICU_HELPER")" \
     "$ICU_NATIVE_BUILD_DIR" \
     "$JOBS"
   oliphaunt_icu_require_canonical_data "$(oliphaunt_icu_canonical_data_archive "$ICU_SOURCE_DIR")"
@@ -108,18 +112,19 @@ fi
     # file before parallel data generators can map a partially written file.
     make -j1 -C data "out/build/$icu_data_name/cnvalias.icu" PKGDATA_OPTS="$icu_pkgdata_opts"
     make -j"$JOBS" PKGDATA_OPTS="$icu_pkgdata_opts"
-    oliphaunt_icu_prepare_files_data_install_dirs "$ICU_BUILD_DIR" "$ICU_PREFIX"
-    make install PKGDATA_OPTS="$icu_pkgdata_opts"
+    oliphaunt_icu_prepare_files_data_install_dirs "$ICU_BUILD_DIR" "$staged_prefix"
+    make install DESTDIR="$install_stage" PKGDATA_OPTS="$icu_pkgdata_opts"
     make -j"$JOBS" -C data packagedata PKGDATA_OPTS="$icu_pkgdata_opts"
-    oliphaunt_icu_install_canonical_files_data "$ICU_SOURCE_DIR" "$ICU_NATIVE_BUILD_DIR" "$ICU_PREFIX"
-    oliphaunt_icu_install_stub_data_archive "$ICU_BUILD_DIR" "$ICU_PREFIX"
+    oliphaunt_icu_install_canonical_data "$(oliphaunt_icu_canonical_data_archive "$ICU_SOURCE_DIR")" "$staged_prefix/share/icu"
+    oliphaunt_icu_install_stub_data_archive "$ICU_BUILD_DIR" "$staged_prefix"
   )
 } >&2
 
-test -f "$ICU_PREFIX/include/unicode/ucol.h"
-test -f "$ICU_PREFIX/lib/libicui18n.a"
-test -f "$ICU_PREFIX/lib/libicuuc.a"
-oliphaunt_icu_stub_data_archive_ready "$ICU_PREFIX/lib/libicudata.a"
-oliphaunt_icu_files_data_ready "$ICU_PREFIX/share/icu"
-printf '%s\n' "$stamp" > "$ICU_PREFIX/.oliphaunt-wasix-icu-build"
+test -f "$staged_prefix/include/unicode/ucol.h"
+test -f "$staged_prefix/lib/libicui18n.a"
+test -f "$staged_prefix/lib/libicuuc.a"
+oliphaunt_icu_stub_data_archive_ready "$staged_prefix/lib/libicudata.a"
+oliphaunt_icu_files_data_ready "$staged_prefix/share/icu"
+printf '%s\n' "$stamp" > "$staged_prefix/.oliphaunt-wasix-icu-build"
+oliphaunt_icu_publish_prefix "$staged_prefix" "$ICU_PREFIX"
 echo "$ICU_PREFIX"
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_jsonc.sh b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_jsonc.sh
similarity index 96%
rename from src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_jsonc.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_jsonc.sh
index 28444b57f..b47c8aac8 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_jsonc.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_jsonc.sh
@@ -12,7 +12,7 @@ JSONC_BUILD_DIR="${JSONC_BUILD_DIR:-$GENERATED_ROOT/work/json-c-wasix-build}"
 JOBS="${JOBS:-4}"
 
 if [ ! -f "$JSONC_SOURCE_DIR/CMakeLists.txt" ]; then
-  echo "missing JSON-C source checkout at $JSONC_SOURCE_DIR; run assets fetch/source-spine first" >&2
+  echo "missing JSON-C source checkout at $JSONC_SOURCE_DIR; run bash src/third-party/tools/fetch-sources.sh wasix-runtime --force first" >&2
   exit 1
 fi
 
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libiconv.sh b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_libiconv.sh
similarity index 90%
rename from src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libiconv.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_libiconv.sh
index 40a558905..9f5bbe697 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libiconv.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_libiconv.sh
@@ -18,10 +18,10 @@ JOBS="${JOBS:-4}"
 oliphaunt_wasix_apply_wasix_profile configure
 
 if [ ! -f "$LIBICONV_SOURCE_DIR/configure" ] || [ ! -f "$LIBICONV_SOURCE_PIN" ]; then
-  echo "pinned libiconv source checkout is missing; run tools/dev/bun.sh src/sources/tools/fetch-sources.mjs wasix-runtime --force" >&2
+  echo "pinned libiconv source checkout is missing; run bash src/third-party/tools/fetch-sources.sh wasix-runtime --force" >&2
   exit 1
 fi
-source_tree_sha256="$(python3 "$REPO_ROOT/src/sources/tools/verify-source-tree.py" \
+source_tree_sha256="$(bash "$REPO_ROOT/tools/dev/bun.sh" "$REPO_ROOT/src/runtimes/liboliphaunt-wasix/tools/verify-source-tree.mts" \
   --checkout "$LIBICONV_SOURCE_DIR" \
   --manifest "$LIBICONV_SOURCE_MANIFEST")"
 
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libxml2.sh b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_libxml2.sh
similarity index 96%
rename from src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libxml2.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_libxml2.sh
index a8a89ea5c..6f7969079 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libxml2.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_libxml2.sh
@@ -12,7 +12,7 @@ LIBXML2_BUILD_DIR="${LIBXML2_BUILD_DIR:-$GENERATED_ROOT/work/libxml2-wasix-build
 JOBS="${JOBS:-4}"
 
 if [ ! -f "$LIBXML2_SOURCE_DIR/CMakeLists.txt" ]; then
-  echo "missing libxml2 source checkout at $LIBXML2_SOURCE_DIR; run assets fetch/source-spine first" >&2
+  echo "missing libxml2 source checkout at $LIBXML2_SOURCE_DIR; run bash src/third-party/tools/fetch-sources.sh wasix-runtime --force first" >&2
   exit 1
 fi
 
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_openssl.sh b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_openssl.sh
similarity index 77%
rename from src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_openssl.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_openssl.sh
index 1f596f861..95997dbb2 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_openssl.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_openssl.sh
@@ -12,7 +12,7 @@ OPENSSL_BUILD_DIR="${OPENSSL_BUILD_DIR:-$GENERATED_ROOT/work/openssl-wasix-build
 JOBS="${JOBS:-4}"
 
 if [ ! -f "$OPENSSL_SOURCE_DIR/Configure" ]; then
-  echo "missing OpenSSL source checkout at $OPENSSL_SOURCE_DIR; run assets fetch/source-spine first" >&2
+  echo "missing OpenSSL source checkout at $OPENSSL_SOURCE_DIR; run bash src/third-party/tools/fetch-sources.sh wasix-runtime --force first" >&2
   exit 1
 fi
 
@@ -26,6 +26,7 @@ wasixcc_version="$(wasixcc --version 2>/dev/null)"
 wasixcc_version="${wasixcc_version%%$'\n'*}"
 stamp="source=$source_commit
 script=$script_sha256
+helper=$(oliphaunt_wasix_script_sha256 "$ROOT/wasix_third_party.sh")
 profile=$(oliphaunt_wasix_wasix_profile_signature)
 wasixcc=$wasixcc_version
 configure=no-asm no-shared no-tests no-apps no-docs no-module no-engine no-dso no-zlib no-pinshared no-dgram no-sock no-threads no-secure-memory"
@@ -39,8 +40,13 @@ if [ -f "$OPENSSL_PREFIX/.oliphaunt-wasix-openssl-build" ] &&
 fi
 
 {
-  rm -rf "$OPENSSL_BUILD_DIR" "$OPENSSL_PREFIX"
+  rm -rf "$OPENSSL_BUILD_DIR"
   mkdir -p "$OPENSSL_BUILD_DIR" "$(dirname "$OPENSSL_PREFIX")"
+  install_stage="$(mktemp -d "$OPENSSL_PREFIX.install.XXXXXX")"
+  staged_prefix="$install_stage$OPENSSL_PREFIX"
+  trap 'rm -rf "$install_stage"' EXIT
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
   cp -a "$OPENSSL_SOURCE_DIR/." "$OPENSSL_BUILD_DIR/"
   rm -rf "$OPENSSL_BUILD_DIR/.git"
 
@@ -68,11 +74,12 @@ fi
       --openssldir="$OPENSSL_PREFIX/ssl" \
       CFLAGS="$OLIPHAUNT_WASM_PROFILE_CFLAGS -fPIC -Wno-unused-command-line-argument"
     make -s -j"$JOBS" build_libs
-    make -s install_dev >/dev/null
+    make -s install_dev DESTDIR="$install_stage" >/dev/null
   )
 } >&2
 
-test -f "$OPENSSL_PREFIX/include/openssl/evp.h"
-test -f "$OPENSSL_PREFIX/lib/libcrypto.a"
-printf '%s\n' "$stamp" > "$OPENSSL_PREFIX/.oliphaunt-wasix-openssl-build"
+test -f "$staged_prefix/include/openssl/evp.h"
+test -f "$staged_prefix/lib/libcrypto.a"
+printf '%s\n' "$stamp" > "$staged_prefix/.oliphaunt-wasix-openssl-build"
+oliphaunt_wasix_publish_prefix "$staged_prefix" "$OPENSSL_PREFIX"
 echo "$OPENSSL_PREFIX"
diff --git a/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_proj.sh b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_proj.sh
new file mode 100755
index 000000000..196210bfa
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_proj.sh
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+. "$ROOT/wasix_third_party.sh"
+
+REPO_ROOT="$(oliphaunt_wasix_repo_root "$ROOT")"
+PROJ_SOURCE_DIR="${PROJ_SOURCE_DIR:-$REPO_ROOT/target/oliphaunt-sources/checkouts/proj}"
+GENERATED_ROOT="$(oliphaunt_wasix_generated_root "$REPO_ROOT")"
+PROJ_PREFIX="${PROJ_PREFIX:-$GENERATED_ROOT/work/proj-wasix}"
+PROJ_BUILD_DIR="${PROJ_BUILD_DIR:-$GENERATED_ROOT/work/proj-wasix-build}"
+SQLITE_PREFIX="${SQLITE_PREFIX:-$("$ROOT/build_wasix_sqlite.sh")}"
+JOBS="${JOBS:-4}"
+
+if [ ! -f "$PROJ_SOURCE_DIR/CMakeLists.txt" ]; then
+  echo "missing PROJ source checkout at $PROJ_SOURCE_DIR; run bash src/third-party/tools/fetch-sources.sh wasix-runtime --force first" >&2
+  exit 1
+fi
+
+. "$ROOT/docker_wasix_env.sh"
+. "$ROOT/profile_flags.sh"
+oliphaunt_wasix_apply_wasix_profile build
+
+source_commit="$(oliphaunt_wasix_source_commit "$PROJ_SOURCE_DIR")"
+sqlite_stamp="$(cat "$SQLITE_PREFIX/.oliphaunt-wasix-sqlite-build")"
+script_sha256="$(oliphaunt_wasix_script_sha256 "$0")"
+helper_sha256="$(oliphaunt_wasix_script_sha256 "$ROOT/wasix_third_party.sh")"
+sqlite_script_sha256="$(oliphaunt_wasix_script_sha256 "$ROOT/build_wasix_sqlite.sh")"
+wasixcc_version="$(wasixcc --version 2>/dev/null)"
+wasixcc_version="${wasixcc_version%%$'\n'*}"
+stamp="source=$source_commit
+sqlite=$sqlite_stamp
+script=$script_sha256
+sqlite_script=$sqlite_script_sha256
+helper=$helper_sha256
+profile=$(oliphaunt_wasix_wasix_profile_signature)
+wasixcc=$wasixcc_version
+cmake=static-libs-only-no-tiff-no-curl-no-libdl-embedded-projdb-install-projdb"
+
+if [ -f "$PROJ_PREFIX/.oliphaunt-wasix-proj-build" ] &&
+   [ -f "$PROJ_PREFIX/include/proj.h" ] &&
+   [ -f "$PROJ_PREFIX/lib/libproj.a" ] &&
+   [ -f "$PROJ_PREFIX/share/proj/proj.db" ] &&
+   [ "$(cat "$PROJ_PREFIX/.oliphaunt-wasix-proj-build")" = "$stamp" ]; then
+  echo "$PROJ_PREFIX"
+  exit 0
+fi
+
+{
+  rm -rf "$PROJ_BUILD_DIR"
+  mkdir -p "$PROJ_BUILD_DIR" "$(dirname "$PROJ_PREFIX")"
+  install_stage="$(mktemp -d "$PROJ_PREFIX.install.XXXXXX")"
+  staged_prefix="$install_stage$PROJ_PREFIX"
+  trap 'rm -rf "$install_stage"' EXIT
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
+  DESTDIR="$install_stage" oliphaunt_wasix_static_cmake_build \
+    "$PROJ_SOURCE_DIR" \
+    "$PROJ_BUILD_DIR" \
+    "$PROJ_PREFIX" \
+    -DSQLite3_INCLUDE_DIR="$SQLITE_PREFIX/include" \
+    -DSQLite3_LIBRARY="$SQLITE_PREFIX/lib/libsqlite3.a" \
+    -DEXE_SQLITE3="$(command -v sqlite3)" \
+    -DENABLE_TIFF=OFF \
+    -DENABLE_CURL=OFF \
+    -DENABLE_EMSCRIPTEN_FETCH=OFF \
+    -DHAVE_LIBDL=OFF \
+    -DBUILD_APPS=OFF \
+    -DBUILD_TESTING=OFF \
+    -DBUILD_EXAMPLES=OFF \
+    -DEMBED_RESOURCE_FILES=ON \
+    -DUSE_ONLY_EMBEDDED_RESOURCE_FILES=ON
+  mkdir -p "$staged_prefix/share/proj"
+  cp "$PROJ_BUILD_DIR/data/proj.db" "$staged_prefix/share/proj/proj.db"
+} >&2
+
+test -f "$staged_prefix/include/proj.h"
+test -f "$staged_prefix/lib/libproj.a"
+test -f "$staged_prefix/share/proj/proj.db"
+printf '%s\n' "$stamp" > "$staged_prefix/.oliphaunt-wasix-proj-build"
+oliphaunt_wasix_publish_prefix "$staged_prefix" "$PROJ_PREFIX"
+echo "$PROJ_PREFIX"
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_sqlite.sh b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_sqlite.sh
similarity index 97%
rename from src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_sqlite.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_sqlite.sh
index 16c62f475..58b966fab 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_sqlite.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_sqlite.sh
@@ -12,7 +12,7 @@ SQLITE_BUILD_DIR="${SQLITE_BUILD_DIR:-$GENERATED_ROOT/work/sqlite-wasix-build}"
 JOBS="${JOBS:-4}"
 
 if [ ! -x "$SQLITE_SOURCE_DIR/configure" ]; then
-  echo "missing SQLite source checkout at $SQLITE_SOURCE_DIR; run assets fetch/source-spine first" >&2
+  echo "missing SQLite source checkout at $SQLITE_SOURCE_DIR; run bash src/third-party/tools/fetch-sources.sh wasix-runtime --force first" >&2
   exit 1
 fi
 
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/configure_wasix_dl.sh b/src/runtimes/liboliphaunt-wasix/assets/build/configure_wasix_dl.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/configure_wasix_dl.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/configure_wasix_dl.sh
diff --git a/src/runtimes/liboliphaunt-wasix/assets/build/dependency-prefix.test.sh b/src/runtimes/liboliphaunt-wasix/assets/build/dependency-prefix.test.sh
new file mode 100644
index 000000000..6ab94851d
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/dependency-prefix.test.sh
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+set -euo pipefail
+owner="$(cd "$(dirname "$0")" && pwd)"
+root="$(git -C "$owner" rev-parse --show-toplevel)"
+mkdir -p "$root/target"
+scratch="$(mktemp -d "$root/target/dependency-prefix-test.XXXXXX")"
+trap 'rm -rf "$scratch"' EXIT
+mkdir -p "$scratch/recipes" "$scratch/bin" "$scratch/sqlite"
+cp "$owner"/build_wasix_{geos,proj,openssl,sqlite}.sh "$owner/wasix_third_party.sh" "$owner/profile_flags.sh" "$scratch/recipes/"
+# Compiler provisioning is separate; exercise the real recipes with tiny
+# command fixtures instead of compiling complete upstream dependency trees.
+: > "$scratch/recipes/docker_wasix_env.sh"
+printf sqlite > "$scratch/sqlite/.oliphaunt-wasix-sqlite-build"
+export SQLITE_PREFIX="$scratch/sqlite" PATH="$scratch/bin:$PATH"
+export DEPENDENCY_INPUT=one DEPENDENCY_LOG="$scratch/commands"
+cat > "$scratch/bin/wasixcc" <<'SH'
+#!/bin/sh
+printf '%s\n' "$DEPENDENCY_INPUT"
+SH
+cat > "$scratch/bin/sqlite3" <<'SH'
+#!/bin/sh
+exit 0
+SH
+cat > "$scratch/bin/cmake" <<'SH'
+#!/usr/bin/env bash
+set -eu
+echo "$*" >> "$DEPENDENCY_LOG"
+case "$1" in
+  -S)
+    [[ ${DEPENDENCY_FAIL:-} != configure ]]
+    source=$2; build=$4
+    for arg; do case "$arg" in -DCMAKE_INSTALL_PREFIX=*) prefix=${arg#*=};; esac; done
+    mkdir -p "$build/data"
+    printf '%s' "$prefix" > "$build/prefix"
+    printf '%s' "$DEPENDENCY_INPUT" > "$build/data/proj.db"
+    ;;
+  --build) [[ ${DEPENDENCY_FAIL:-} != build ]];;
+  --install)
+    build=$2
+    prefix="${DESTDIR:?}$(cat "$build/prefix")"
+    mkdir -p "$prefix/include" "$prefix/lib"
+    touch "$prefix/include/geos_c.h" "$prefix/include/proj.h"
+    for name in geos geos_c proj; do printf '%s' "$DEPENDENCY_INPUT" > "$prefix/lib/lib$name.a"; done
+    [[ ${DEPENDENCY_FAIL:-} != install ]]
+    ;;
+esac
+SH
+cat > "$scratch/bin/make" <<'SH'
+#!/usr/bin/env bash
+set -eu
+echo "$*" >> "$DEPENDENCY_LOG"
+case " $* " in
+  *' install_dev '*)
+    for arg; do case "$arg" in DESTDIR=*) stage=${arg#*=};; esac; done
+    prefix="${stage:?}$(cat prefix)"
+    mkdir -p "$prefix/include/openssl" "$prefix/lib"
+    touch "$prefix/include/openssl/evp.h"
+    printf '%s' "$DEPENDENCY_INPUT" > "$prefix/lib/libcrypto.a"
+    [[ ${DEPENDENCY_FAIL:-} != install ]]
+    ;;
+  *) [[ ${DEPENDENCY_FAIL:-} != build ]];;
+esac
+SH
+chmod +x "$scratch/bin/"*
+for name in geos proj openssl; do
+  mkdir -p "$scratch/source-$name"
+  touch "$scratch/source-$name/CMakeLists.txt"
+done
+cat > "$scratch/source-openssl/Configure" <<'SH'
+#!/usr/bin/env bash
+set -eu
+[[ ${DEPENDENCY_FAIL:-} != configure ]]
+for arg; do case "$arg" in --prefix=*) printf '%s' "${arg#*=}" > prefix;; esac; done
+SH
+chmod +x "$scratch/source-openssl/Configure"
+export GEOS_SOURCE_DIR="$scratch/source-geos" PROJ_SOURCE_DIR="$scratch/source-proj" OPENSSL_SOURCE_DIR="$scratch/source-openssl"
+export OLIPHAUNT_WASM_GENERATED_ROOT="$scratch/generated"
+for name in geos proj openssl; do
+  recipe="$scratch/recipes/build_wasix_$name.sh"
+  prefix="$scratch/generated/work/$name-wasix"
+  archive="$prefix/lib/lib$name.a"
+  [[ $name != openssl ]] || archive="$prefix/lib/libcrypto.a"
+  export DEPENDENCY_INPUT=one
+  bash "$recipe" > "$scratch/recipe.log" 2>&1
+  initial_stamp=$(cat "$prefix/.oliphaunt-wasix-$name-build")
+  calls=$(wc -l < "$DEPENDENCY_LOG")
+  bash "$recipe" >> "$scratch/recipe.log" 2>&1
+  [[ $(wc -l < "$DEPENDENCY_LOG") == "$calls" ]]
+  export DEPENDENCY_INPUT=two
+  for phase in configure build install; do
+    export DEPENDENCY_FAIL=$phase
+    if bash "$recipe" >> "$scratch/recipe.log" 2>&1; then
+      echo "$name unexpectedly accepted $phase failure" >&2; exit 1
+    fi
+    [[ $(cat "$archive") == one ]]
+    [[ $(cat "$prefix/.oliphaunt-wasix-$name-build") == "$initial_stamp" ]]
+  done
+  unset DEPENDENCY_FAIL
+  bash "$recipe" >> "$scratch/recipe.log" 2>&1
+  [[ $(cat "$archive") == two ]]
+  [[ $(cat "$prefix/.oliphaunt-wasix-$name-build") != "$initial_stamp" ]]
+  calls=$(wc -l < "$DEPENDENCY_LOG")
+  bash "$recipe" >> "$scratch/recipe.log" 2>&1
+  [[ $(wc -l < "$DEPENDENCY_LOG") == "$calls" ]]
+  echo "$name repeat/change-input and configure/build/install failure retention passed"
+done
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker/Dockerfile b/src/runtimes/liboliphaunt-wasix/assets/build/docker/Dockerfile
similarity index 97%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker/Dockerfile
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker/Dockerfile
index ff8198916..067871df4 100644
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker/Dockerfile
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker/Dockerfile
@@ -6,7 +6,7 @@ ENV DEBIAN_FRONTEND=noninteractive
 # The base filesystem and Ubuntu package view are immutable inputs. The helper
 # writes a minimal fail-closed snapshot source, retries complete transactions,
 # and verifies every request with the committed snapshot-service trust root.
-# Rotate the trust root before the manifest-declared expiry boundary.
+# Rotate isrg-root-x1.pem before its certificate expires (2035-06-04).
 ARG OLIPHAUNT_UBUNTU_APT_SNAPSHOT=20260715T000000Z
 ARG OLIPHAUNT_UBUNTU_SNAPSHOT_TLS_ROOT_SHA256=22b557a27055b33606b6559f37703928d3e4ad79f110b407d04986e1843543d1
 LABEL dev.oliphaunt.ubuntu-apt-snapshot="${OLIPHAUNT_UBUNTU_APT_SNAPSHOT}" \
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-apt-packages.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-apt-packages.sh
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.test.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-apt-packages.test.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.test.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-apt-packages.test.sh
diff --git a/src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.fixture.mts b/src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.fixture.mts
new file mode 100644
index 000000000..95dec93bf
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.fixture.mts
@@ -0,0 +1,14 @@
+import { readFileSync, writeFileSync } from 'node:fs';
+import { tarArchive } from '../../../../../../tools/packaging/testdata/tar-fixture.mts';
+
+const [kind, destination, driverPath] = process.argv.slice(2);
+const driver = { name: 'wasixccenv', mode: 0o755, data: readFileSync(driverPath) };
+const malicious = {
+  traversal: { name: '../escaped', data: 'fixture' },
+  duplicate: driver,
+  symlink: { name: 'escape-symlink', type: '2', linkTarget: '/etc/passwd' },
+  hardlink: { name: 'escape-hardlink', type: '1', linkTarget: '../outside' },
+  device: { name: 'device', type: '3' },
+}[kind];
+if (!malicious) throw new Error(`unknown malicious archive kind: ${kind}`);
+writeFileSync(destination, tarArchive([driver, malicious]));
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-wasixcc.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.sh
similarity index 80%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-wasixcc.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.sh
index 27f7a589c..82942e036 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-wasixcc.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.sh
@@ -52,7 +52,7 @@ if [ -e "$install_root" ] || [ -L "$install_root" ]; then
   fail "install root already exists; refusing a non-atomic replacement: $install_root"
 fi
 
-for command_name in awk basename cp curl dirname find grep install mktemp mv od python3 readlink sha256sum sort tar wc; do
+for command_name in awk basename cp curl dirname find grep install mktemp mv od readlink sha256sum sort tar wc; do
   command -v "$command_name" >/dev/null 2>&1 || fail "missing required command: $command_name"
 done
 
@@ -76,77 +76,57 @@ validate_archive_members() {
   local archive="$1"
   local asset_name="$2"
 
-  if ! python3 - "$archive" "$asset_name" <<'PY'
-import posixpath
-import sys
-import tarfile
-
-archive_path = sys.argv[1]
-asset_name = sys.argv[2]
-max_members = 200_000
-max_member_bytes = 2_000_000_000
-max_expanded_bytes = 4_000_000_000
-
-
-def safe_name(value: str, label: str) -> str:
-    if not value or "\\" in value or "\x00" in value or any(ord(char) < 32 or ord(char) == 127 for char in value):
-        raise ValueError(f"{label} contains invalid characters: {value!r}")
-    if value.startswith("/"):
-        raise ValueError(f"{label} is absolute: {value!r}")
-    trimmed = value[:-1] if value.endswith("/") else value
-    parts = trimmed.split("/")
-    if not trimmed or any(part in {"", ".", ".."} for part in parts):
-        raise ValueError(f"{label} is unsafe: {value!r}")
-    return trimmed
-
-
-try:
-    with tarfile.open(archive_path, mode="r:gz") as archive:
-        members = archive.getmembers()
-        if not members:
-            raise ValueError("archive is empty")
-        if len(members) > max_members:
-            raise ValueError(f"archive has too many members: {len(members)}")
-
-        seen = {}
-        links = []
-        expanded_bytes = 0
-        for member in members:
-            name = safe_name(member.name, "archive member")
-            if name in seen:
-                raise ValueError(f"duplicate archive member: {name!r}")
-            seen[name] = member
-
-            if member.isdir():
-                continue
-            if member.isreg():
-                if member.size < 0 or member.size > max_member_bytes:
-                    raise ValueError(f"archive member has invalid size: {name!r} ({member.size})")
-                expanded_bytes += member.size
-                if expanded_bytes > max_expanded_bytes:
-                    raise ValueError(f"archive expands beyond {max_expanded_bytes} bytes")
-                continue
-            if member.issym() or member.islnk():
-                safe_name(member.linkname, f"link target for {name}")
-                links.append((name, member.linkname, member.issym()))
-                continue
-            raise ValueError(f"unsupported archive member type for {name!r}")
-
-        for name, linkname, symbolic in links:
-            if symbolic:
-                target = posixpath.normpath(posixpath.join(posixpath.dirname(name), linkname))
-            else:
-                target = posixpath.normpath(linkname)
-            if target == ".." or target.startswith("../") or target.startswith("/"):
-                raise ValueError(f"link escapes archive root: {name!r} -> {linkname!r}")
-            if target not in seen:
-                raise ValueError(f"link target is absent from archive: {name!r} -> {linkname!r}")
-except (OSError, tarfile.TarError, ValueError) as error:
-    raise SystemExit(f"{asset_name} failed safe archive validation: {error}")
-PY
-  then
-    fail "$asset_name failed archive safety validation"
-  fi
+  local listing="$work_root/archive-members.txt"
+  # ponytail: pinned Linux toolchains use ASCII names without spaces; widen only with a fixture for a new pin.
+  LC_ALL=C tar --list --absolute-names --verbose --numeric-owner --full-time --quoting-style=escape \
+    --gzip --file "$archive" >"$listing" || fail "$asset_name failed archive safety validation"
+  LC_ALL=C awk '
+    function fail(message) { print message > "/dev/stderr"; failed = 1; exit 1 }
+    function safe(name, label, parts, count, i) {
+      if (name !~ /^[A-Za-z0-9_+./@=-]+$/ || name ~ /^\//) fail(label " is unsafe")
+      sub(/\/$/, "", name)
+      count = split(name, parts, "/")
+      for (i = 1; i <= count; i++) if (parts[i] == "" || parts[i] == "." || parts[i] == "..") fail(label " is unsafe")
+      return name
+    }
+    {
+      if (NR > 200000) fail("archive has too many members")
+      type = substr($1, 1, 1)
+      if (length($1) != 10 || $1 ~ /[sStT]/ || (type != "-" && type != "d" && type != "l" && type != "h")) fail("unsupported archive member type or mode")
+      if ((type == "l" && (NF != 8 || $7 != "->")) ||
+          (type == "h" && (NF != 9 || $7 != "link" || $8 != "to")) ||
+          ((type == "-" || type == "d") && NF != 6)) fail("ambiguous archive member")
+      name = safe($6, "archive member")
+      if (name in kinds) fail("duplicate archive member")
+      kinds[name] = type
+      if ($3 !~ /^[0-9]+$/ || $3 > 2000000000) fail("invalid archive member size")
+      expanded += $3
+      if (expanded > 4000000000) fail("archive expands beyond its size limit")
+      if (type == "l" || type == "h") {
+        target = safe($NF, "link target")
+        if (type == "l" && name ~ /\//) { parent = name; sub(/[^/]+$/, "", parent); target = parent target }
+        links[name] = target
+      }
+    }
+    END {
+      if (failed) exit 1
+      if (!NR) fail("archive is empty")
+      for (name in kinds) {
+        parent = name
+        while (sub(/\/[^/]+$/, "", parent)) if ((parent in kinds) && kinds[parent] != "d") fail("archive member descends through a non-directory")
+      }
+      for (name in links) {
+        target = links[name]
+        if (!(target in kinds)) fail("archive link target is absent")
+        if (kinds[name] == "h" && kinds[target] != "-") fail("hard link must target a regular file")
+        delete visited
+        while (target in links) {
+          if (target in visited) fail("archive link cycle")
+          visited[target] = 1; target = links[target]
+        }
+      }
+    }
+  ' "$listing" || fail "$asset_name failed archive safety validation"
 }
 
 validate_extracted_links() {
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-wasixcc.test.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.test.sh
similarity index 83%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-wasixcc.test.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.test.sh
index 9a22a72ff..b602f013c 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-wasixcc.test.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.test.sh
@@ -5,9 +5,6 @@ export LC_ALL=C
 
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 installer="$script_dir/install-pinned-wasixcc.sh"
-production_manifest="$script_dir/pinned-wasixcc-assets.tsv"
-dockerfile="$script_dir/Dockerfile"
-expected_production_manifest_sha256="9b0ee1aabcfecda1be72c94a9f14a16c9d8a2fc020f3dc471394d5335766c519"
 
 fail() {
   echo "install-pinned-wasixcc.test: $*" >&2
@@ -207,49 +204,7 @@ assert_no_partial_install() {
 malicious_driver_archive() {
   local kind="$1"
   local destination="$2"
-  python3 - "$kind" "$destination" "$work_root/fake-wasixccenv" <<'PY'
-import io
-import sys
-import tarfile
-from pathlib import Path
-
-kind = sys.argv[1]
-destination = sys.argv[2]
-driver = Path(sys.argv[3]).read_bytes()
-
-
-def regular(archive, name, data=b"fixture"):
-    member = tarfile.TarInfo(name)
-    member.mode = 0o755 if name == "wasixccenv" else 0o644
-    member.size = len(data)
-    archive.addfile(member, io.BytesIO(data))
-
-
-with tarfile.open(destination, "w:gz") as archive:
-    regular(archive, "wasixccenv", driver)
-    if kind == "traversal":
-        regular(archive, "../escaped")
-    elif kind == "duplicate":
-        regular(archive, "wasixccenv", driver)
-    elif kind == "symlink":
-        member = tarfile.TarInfo("escape-symlink")
-        member.type = tarfile.SYMTYPE
-        member.linkname = "/etc/passwd"
-        archive.addfile(member)
-    elif kind == "hardlink":
-        member = tarfile.TarInfo("escape-hardlink")
-        member.type = tarfile.LNKTYPE
-        member.linkname = "../outside"
-        archive.addfile(member)
-    elif kind == "device":
-        member = tarfile.TarInfo("device")
-        member.type = tarfile.CHRTYPE
-        member.devmajor = 1
-        member.devminor = 3
-        archive.addfile(member)
-    else:
-        raise SystemExit(f"unknown malicious archive kind: {kind}")
-PY
+  bun "$script_dir/install-pinned-wasixcc.fixture.mts" "$kind" "$destination" "$work_root/fake-wasixccenv"
 }
 
 run_malicious_archive_case() {
@@ -270,27 +225,6 @@ run_malicious_archive_case() {
   [ ! -e "$case_root/escaped" ] || fail "$kind archive wrote outside its extraction root"
 }
 
-actual_production_manifest_sha256="$(sha256sum "$production_manifest" | awk '{print $1}')"
-[ "$actual_production_manifest_sha256" = "$expected_production_manifest_sha256" ] ||
-  fail "production manifest identity changed without updating its Docker/source metadata pin"
-if grep -Fq 'raw.githubusercontent.com/wasix-org/wasixcc' "$dockerfile"; then
-  fail "Dockerfile still uses the upstream remote installer"
-fi
-if grep -Eq '(^|[^A-Za-z])latest([^A-Za-z]|$)' "$dockerfile" "$production_manifest"; then
-  fail "Docker toolchain inputs must not use latest resolution"
-fi
-for required_flag in \
-  '--retry-all-errors' \
-  '--retry-max-time' \
-  '--connect-timeout' \
-  '--max-time' \
-  '--max-filesize' \
-  '--proto' \
-  '--proto-redir' \
-  '--remove-on-error'; do
-  grep -F -- "$required_flag" "$installer" >/dev/null || fail "installer is missing curl flag $required_flag"
-done
-
 fixture_manifest="$work_root/fixture-assets.tsv"
 write_manifest "$fixtures" "$fixture_manifest"
 success_root="$work_root/success/.wasixcc"
@@ -353,8 +287,8 @@ assert_no_partial_install "$invalid_root" "invalid archive"
 
 run_malicious_archive_case traversal "archive member is unsafe"
 run_malicious_archive_case duplicate "duplicate archive member"
-run_malicious_archive_case symlink "link target for escape-symlink is absolute"
-run_malicious_archive_case hardlink "link target for escape-hardlink is unsafe"
+run_malicious_archive_case symlink "link target is unsafe"
+run_malicious_archive_case hardlink "link target is unsafe"
 run_malicious_archive_case device "unsupported archive member type"
 
 version_fixtures="$work_root/version-fixtures"
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker/isrg-root-x1.pem b/src/runtimes/liboliphaunt-wasix/assets/build/docker/isrg-root-x1.pem
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker/isrg-root-x1.pem
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker/isrg-root-x1.pem
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv b/src/runtimes/liboliphaunt-wasix/assets/build/docker/pinned-wasixcc-assets.tsv
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker/pinned-wasixcc-assets.tsv
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker_contrib_extensions.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker_contrib_extensions.sh
similarity index 95%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker_contrib_extensions.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker_contrib_extensions.sh
index 4898cbca2..267e221df 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker_contrib_extensions.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker_contrib_extensions.sh
@@ -9,7 +9,7 @@ SOURCE_LANE="$(oliphaunt_wasix_source_lane)"
 
 IMAGE="${IMAGE:-oliphaunt-wasix-wasix-build:local}"
 JOBS="${JOBS:-4}"
-CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt/wasix/assets/build}"
+CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt-wasix/assets/build}"
 CONTAINER_GENERATED_ROOT="${CONTAINER_GENERATED_ROOT:-/work/target/oliphaunt-wasix/wasix-build}"
 CONTAINER_BUILD_DIR="${CONTAINER_BUILD_DIR:-$(oliphaunt_wasix_default_build_dir "$SOURCE_LANE")}"
 CONTAINER_PGSRC="${CONTAINER_PGSRC:-$(oliphaunt_wasix_prepare_source_for_docker "$SOURCE_LANE")}"
@@ -72,9 +72,9 @@ fi
   "$IMAGE" \
   bash -lc '
     set -euo pipefail
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/source_lane.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/source_lane.sh
     oliphaunt_wasix_apply_wasix_profile build
 
     test -f "$BUILD_DIR/config.status"
@@ -92,7 +92,7 @@ fi
     UUID_PREFIX=
     build_portable_uuid() {
       local prefix="$CONTAINER_GENERATED_ROOT/dependencies/uuid"
-      local source_dir="/work/src/runtimes/liboliphaunt/native/portable-uuid"
+      local source_dir="/work/src/runtimes/liboliphaunt-native/portable-uuid"
       local object="$prefix/portable_uuid.o"
       local archive="$prefix/lib/libuuid.a"
       if [ -f "$archive" ] && [ -d "$prefix/include/uuid" ]; then
@@ -147,7 +147,7 @@ fi
         esac
       done < <(
         /work/tools/dev/bun.sh \
-          /work/src/extensions/tools/native-component-contract.mjs \
+          /work/src/extensions/tools/native-component-contract.mts \
           field "$sql_name" wasix wasix-runtime wasix-portable components
       )
       if [ "${#extra_make_args[@]}" -gt 0 ]; then
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker_initdb.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker_initdb.sh
similarity index 94%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker_initdb.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker_initdb.sh
index d78b28c80..9ee9f40ea 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker_initdb.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker_initdb.sh
@@ -9,7 +9,7 @@ SOURCE_LANE="$(oliphaunt_wasix_source_lane)"
 
 IMAGE="${IMAGE:-oliphaunt-wasix-wasix-build:local}"
 JOBS="${JOBS:-4}"
-CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt/wasix/assets/build}"
+CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt-wasix/assets/build}"
 CONTAINER_GENERATED_ROOT="${CONTAINER_GENERATED_ROOT:-/work/target/oliphaunt-wasix/wasix-build}"
 CONTAINER_BUILD_DIR="${CONTAINER_BUILD_DIR:-$(oliphaunt_wasix_default_build_dir "$SOURCE_LANE")}"
 CONTAINER_PGSRC="${CONTAINER_PGSRC:-$(oliphaunt_wasix_prepare_source_for_docker "$SOURCE_LANE")}"
@@ -70,10 +70,10 @@ fi
   "$IMAGE" \
   bash -lc '
     set -euo pipefail
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/source_lane.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/wasix_icu_link.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/source_lane.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/wasix_icu_link.sh
     oliphaunt_wasix_apply_wasix_profile build
     export AR=wasixar
     export RANLIB=wasixranlib
@@ -85,7 +85,7 @@ fi
     sha256sum -c "$BUILD_DIR/.oliphaunt-wasix-bridge-sha256" >/dev/null
     test "$(oliphaunt_wasix_wasix_profile_signature)" = "$(cat "$BUILD_DIR/.oliphaunt-wasix-build-profile")"
 
-    ICU_PREFIX="$(./src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh)"
+    ICU_PREFIX="$(./src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_icu.sh)"
     ICU_CFLAGS="$(oliphaunt_wasix_icu_cflags "$ICU_PREFIX")"
     ICU_LIBS="$(oliphaunt_wasix_icu_libs "$ICU_PREFIX")"
 
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker_oliphaunt.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker_oliphaunt.sh
similarity index 93%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker_oliphaunt.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker_oliphaunt.sh
index 9f1802229..5fd1a7306 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker_oliphaunt.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker_oliphaunt.sh
@@ -9,7 +9,7 @@ SOURCE_LANE="$(oliphaunt_wasix_source_lane)"
 
 IMAGE="${IMAGE:-oliphaunt-wasix-wasix-build:local}"
 JOBS="${JOBS:-4}"
-CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt/wasix/assets/build}"
+CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt-wasix/assets/build}"
 CONTAINER_GENERATED_ROOT="${CONTAINER_GENERATED_ROOT:-/work/target/oliphaunt-wasix/wasix-build}"
 CONTAINER_BUILD_DIR="${CONTAINER_BUILD_DIR:-$(oliphaunt_wasix_default_build_dir "$SOURCE_LANE")}"
 DOCKER="${DOCKER:-$(command -v docker 2>/dev/null || true)}"
@@ -73,12 +73,12 @@ fi
   "$IMAGE" \
   bash -lc '
     set -euo pipefail
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
     oliphaunt_wasix_apply_wasix_profile configure
     profile_signature="$(oliphaunt_wasix_wasix_profile_signature)"
-    configure_script=./src/runtimes/liboliphaunt/wasix/assets/build/configure_wasix_dl.sh
-    icu_prefix="$(./src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh)"
+    configure_script=./src/runtimes/liboliphaunt-wasix/assets/build/configure_wasix_dl.sh
+    icu_prefix="$(./src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_icu.sh)"
     export ICU_PREFIX="$icu_prefix"
     icu_stamp="$icu_prefix/.oliphaunt-wasix-icu-build"
 
@@ -116,7 +116,7 @@ fi
       "$configure_script"
       cp "$PGSRC/.oliphaunt-wasix-source-fingerprint" "$BUILD_DIR/.oliphaunt-wasix-source-fingerprint"
       cp "$PGSRC/.oliphaunt-wasix-postgres-version" "$BUILD_DIR/.oliphaunt-wasix-postgres-version"
-      sha256sum ./src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge.c \
+      sha256sum ./src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge.c \
         > "$BUILD_DIR/.oliphaunt-wasix-bridge-sha256"
       sha256sum "$configure_script" > "$BUILD_DIR/.oliphaunt-wasix-configure-sha256"
       cp "$icu_stamp" "$BUILD_DIR/.oliphaunt-wasix-icu-build"
@@ -138,10 +138,10 @@ fi
     make -s -C "$BUILD_DIR/src/backend" generated-headers
     make -s -C "$BUILD_DIR/src/backend" submake-libpgport
     make -s -j"$JOBS" -C "$BUILD_DIR/src/backend" oliphaunt
-    ./src/runtimes/liboliphaunt/wasix/assets/build/link_wasix_runtime.sh \
+    ./src/runtimes/liboliphaunt-wasix/assets/build/link_wasix_runtime.sh \
       "$BUILD_DIR" \
       "$ICU_PREFIX" \
       "$CONTAINER_GENERATED_ROOT/build/wasix-oliphaunt/oliphaunt_wasix_bridge.o" \
-      ./src/runtimes/liboliphaunt/wasix/assets/generated/wasix-dl.exports \
+      ./src/runtimes/liboliphaunt-wasix/assets/generated/wasix-dl.exports \
       "$oliphaunt_wasix_wasix_profile"
   '
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker_pgdump.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker_pgdump.sh
similarity index 93%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker_pgdump.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker_pgdump.sh
index 5386d7a9f..596866702 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker_pgdump.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker_pgdump.sh
@@ -9,7 +9,7 @@ SOURCE_LANE="$(oliphaunt_wasix_source_lane)"
 
 IMAGE="${IMAGE:-oliphaunt-wasix-wasix-build:local}"
 JOBS="${JOBS:-4}"
-CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt/wasix/assets/build}"
+CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt-wasix/assets/build}"
 CONTAINER_GENERATED_ROOT="${CONTAINER_GENERATED_ROOT:-/work/target/oliphaunt-wasix/wasix-build}"
 CONTAINER_BUILD_DIR="${CONTAINER_BUILD_DIR:-$(oliphaunt_wasix_default_build_dir "$SOURCE_LANE")}"
 CONTAINER_PGSRC="${CONTAINER_PGSRC:-$(oliphaunt_wasix_prepare_source_for_docker "$SOURCE_LANE")}"
@@ -70,10 +70,10 @@ fi
   "$IMAGE" \
   bash -lc '
     set -euo pipefail
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/source_lane.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/wasix_frontend_tools.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/source_lane.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/wasix_frontend_tools.sh
     oliphaunt_wasix_apply_wasix_profile build
     export AR=wasixar
     export RANLIB=wasixranlib
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker_pgxs_extensions.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker_pgxs_extensions.sh
similarity index 92%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker_pgxs_extensions.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker_pgxs_extensions.sh
index dd273d562..a8a46e690 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker_pgxs_extensions.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker_pgxs_extensions.sh
@@ -9,7 +9,7 @@ SOURCE_LANE="$(oliphaunt_wasix_source_lane)"
 
 IMAGE="${IMAGE:-oliphaunt-wasix-wasix-build:local}"
 JOBS="${JOBS:-4}"
-CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt/wasix/assets/build}"
+CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt-wasix/assets/build}"
 CONTAINER_GENERATED_ROOT="${CONTAINER_GENERATED_ROOT:-/work/target/oliphaunt-wasix/wasix-build}"
 CONTAINER_BUILD_DIR="${CONTAINER_BUILD_DIR:-$(oliphaunt_wasix_default_build_dir "$SOURCE_LANE")}"
 CONTAINER_PGSRC="${CONTAINER_PGSRC:-$(oliphaunt_wasix_prepare_source_for_docker "$SOURCE_LANE")}"
@@ -72,9 +72,9 @@ fi
   "$IMAGE" \
   bash -lc '
     set -euo pipefail
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/source_lane.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/source_lane.sh
     oliphaunt_wasix_apply_wasix_profile build
 
     test -f "$BUILD_DIR/config.status"
@@ -116,10 +116,6 @@ fi
 	        OPTFLAGS="" \
 	        "${extra_make_args[@]}" \
 	        all
-	      if [ "$id" = "age" ] && grep -q "^  PASSEDBYVALUE,$" "$extension_dir/age--1.7.0.sql"; then
-	        echo "AGE generated SQL still declares graphid PASSEDBYVALUE on wasm32" >&2
-	        exit 1
-	      fi
 	      if [ "$module_file" = "-" ]; then
 	        continue
 	      fi
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker_psql.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker_psql.sh
similarity index 93%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker_psql.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker_psql.sh
index 0b0d02805..b65df16f4 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker_psql.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker_psql.sh
@@ -9,7 +9,7 @@ SOURCE_LANE="$(oliphaunt_wasix_source_lane)"
 
 IMAGE="${IMAGE:-oliphaunt-wasix-wasix-build:local}"
 JOBS="${JOBS:-4}"
-CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt/wasix/assets/build}"
+CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt-wasix/assets/build}"
 CONTAINER_GENERATED_ROOT="${CONTAINER_GENERATED_ROOT:-/work/target/oliphaunt-wasix/wasix-build}"
 CONTAINER_BUILD_DIR="${CONTAINER_BUILD_DIR:-$(oliphaunt_wasix_default_build_dir "$SOURCE_LANE")}"
 CONTAINER_PGSRC="${CONTAINER_PGSRC:-$(oliphaunt_wasix_prepare_source_for_docker "$SOURCE_LANE")}"
@@ -70,10 +70,10 @@ fi
   "$IMAGE" \
   bash -lc '
     set -euo pipefail
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/source_lane.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/wasix_frontend_tools.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/source_lane.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/wasix_frontend_tools.sh
     oliphaunt_wasix_apply_wasix_profile build
     export AR=wasixar
     export RANLIB=wasixranlib
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker_runtime_support.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker_runtime_support.sh
similarity index 94%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker_runtime_support.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker_runtime_support.sh
index 8e55e7cfc..7843398c0 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/docker_runtime_support.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/docker_runtime_support.sh
@@ -9,7 +9,7 @@ SOURCE_LANE="$(oliphaunt_wasix_source_lane)"
 
 IMAGE="${IMAGE:-oliphaunt-wasix-wasix-build:local}"
 JOBS="${JOBS:-4}"
-CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt/wasix/assets/build}"
+CONTAINER_ROOT="${CONTAINER_ROOT:-/work/src/runtimes/liboliphaunt-wasix/assets/build}"
 CONTAINER_GENERATED_ROOT="${CONTAINER_GENERATED_ROOT:-/work/target/oliphaunt-wasix/wasix-build}"
 CONTAINER_BUILD_DIR="${CONTAINER_BUILD_DIR:-$(oliphaunt_wasix_default_build_dir "$SOURCE_LANE")}"
 CONTAINER_PGSRC="${CONTAINER_PGSRC:-$(oliphaunt_wasix_prepare_source_for_docker "$SOURCE_LANE")}"
@@ -70,9 +70,9 @@ fi
   "$IMAGE" \
   bash -lc '
     set -euo pipefail
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh
-    . ./src/runtimes/liboliphaunt/wasix/assets/build/source_lane.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
+    . ./src/runtimes/liboliphaunt-wasix/assets/build/source_lane.sh
     oliphaunt_wasix_apply_wasix_profile build
 
     test -f "$BUILD_DIR/config.status"
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh b/src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/docker_wasix_env.sh
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/link_wasix_runtime.sh b/src/runtimes/liboliphaunt-wasix/assets/build/link_wasix_runtime.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/link_wasix_runtime.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/link_wasix_runtime.sh
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/pg_config_wasix.sh b/src/runtimes/liboliphaunt-wasix/assets/build/pg_config_wasix.sh
similarity index 88%
rename from src/runtimes/liboliphaunt/wasix/assets/build/pg_config_wasix.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/pg_config_wasix.sh
index fc96d2453..a4ba9ab90 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/pg_config_wasix.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/pg_config_wasix.sh
@@ -50,14 +50,6 @@ postgres_version() {
       fi
     fi
   done
-  source_toml="$ROOT/postgres/source.toml"
-  if [ -f "$source_toml" ]; then
-    version="$(awk -F'=' '/^[[:space:]]*version[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); gsub(/^"|"$/, "", $2); print $2; exit}' "$source_toml")"
-    if [ -n "$version" ]; then
-      printf '%s-wasix-oliphaunt\n' "$version"
-      return
-    fi
-  fi
   echo "unable to determine pinned PostgreSQL version" >&2
   return 2
 }
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0002-oliphaunt-wasix-add-backend-host-io-hooks.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0002-oliphaunt-wasix-add-backend-host-io-hooks.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0002-oliphaunt-wasix-add-backend-host-io-hooks.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0002-oliphaunt-wasix-add-backend-host-io-hooks.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0003-oliphaunt-wasix-export-startup-packet-parser.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0003-oliphaunt-wasix-export-startup-packet-parser.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0003-oliphaunt-wasix-export-startup-packet-parser.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0003-oliphaunt-wasix-export-startup-packet-parser.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0004-oliphaunt-wasix-add-host-lifecycle-exports.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0004-oliphaunt-wasix-add-host-lifecycle-exports.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0004-oliphaunt-wasix-add-host-lifecycle-exports.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0004-oliphaunt-wasix-add-host-lifecycle-exports.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0006-oliphaunt-wasix-report-copy-protocol-state.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0006-oliphaunt-wasix-report-copy-protocol-state.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0006-oliphaunt-wasix-report-copy-protocol-state.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0006-oliphaunt-wasix-report-copy-protocol-state.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0009-oliphaunt-wasix-route-process-identity-through-port.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0009-oliphaunt-wasix-route-process-identity-through-port.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0009-oliphaunt-wasix-route-process-identity-through-port.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0009-oliphaunt-wasix-route-process-identity-through-port.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0011-oliphaunt-wasix-prefer-posix-semaphores.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0011-oliphaunt-wasix-prefer-posix-semaphores.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0011-oliphaunt-wasix-prefer-posix-semaphores.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0011-oliphaunt-wasix-prefer-posix-semaphores.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0012-oliphaunt-wasix-capture-startup-errors.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0012-oliphaunt-wasix-capture-startup-errors.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0012-oliphaunt-wasix-capture-startup-errors.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0012-oliphaunt-wasix-capture-startup-errors.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0021-oliphaunt-wasix-declare-wasix-fork.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0021-oliphaunt-wasix-declare-wasix-fork.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0021-oliphaunt-wasix-declare-wasix-fork.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0021-oliphaunt-wasix-declare-wasix-fork.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0029-oliphaunt-wasix-set-embedded-postmaster-environment.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0029-oliphaunt-wasix-set-embedded-postmaster-environment.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0029-oliphaunt-wasix-set-embedded-postmaster-environment.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0029-oliphaunt-wasix-set-embedded-postmaster-environment.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0030-oliphaunt-wasix-avoid-xlogwrite-prevseg-division.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0030-oliphaunt-wasix-avoid-xlogwrite-prevseg-division.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0030-oliphaunt-wasix-avoid-xlogwrite-prevseg-division.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0030-oliphaunt-wasix-avoid-xlogwrite-prevseg-division.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0031-oliphaunt-wasix-skip-activity-id-reporting.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0031-oliphaunt-wasix-skip-activity-id-reporting.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0031-oliphaunt-wasix-skip-activity-id-reporting.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0031-oliphaunt-wasix-skip-activity-id-reporting.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0035-oliphaunt-wasix-use-single-backend-spinlocks.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0035-oliphaunt-wasix-use-single-backend-spinlocks.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0035-oliphaunt-wasix-use-single-backend-spinlocks.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0035-oliphaunt-wasix-use-single-backend-spinlocks.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0036-oliphaunt-wasix-specialize-single-backend-atomics.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0036-oliphaunt-wasix-specialize-single-backend-atomics.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0036-oliphaunt-wasix-specialize-single-backend-atomics.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0036-oliphaunt-wasix-specialize-single-backend-atomics.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0039-oliphaunt-wasix-inline-sigsetjmp.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0039-oliphaunt-wasix-inline-sigsetjmp.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0039-oliphaunt-wasix-inline-sigsetjmp.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0039-oliphaunt-wasix-inline-sigsetjmp.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch b/src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch
rename to src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/prepare_postgres_source.sh b/src/runtimes/liboliphaunt-wasix/assets/build/prepare_postgres_source.sh
similarity index 84%
rename from src/runtimes/liboliphaunt/wasix/assets/build/prepare_postgres_source.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/prepare_postgres_source.sh
index d7adf19a5..908b00ddf 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/prepare_postgres_source.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/prepare_postgres_source.sh
@@ -4,10 +4,10 @@ set -euo pipefail
 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 . "$SCRIPT_DIR/wasix_third_party.sh"
 REPO_ROOT="$(oliphaunt_wasix_repo_root "$SCRIPT_DIR")"
-. "$REPO_ROOT/src/postgres/versions/18/fetch-source.sh"
-SOURCE_ROOT="$SCRIPT_DIR/postgres"
-SOURCE_TOML="$REPO_ROOT/src/postgres/versions/18/source.toml"
-PATCH_DIR="$SOURCE_ROOT/patches"
+. "$REPO_ROOT/src/third-party/postgres/fetch-source.sh"
+SOURCE_TOML="$REPO_ROOT/src/third-party/postgres/source.toml"
+PATCH_DIR="$REPO_ROOT"
+PATCH_SERIES="$REPO_ROOT/src/runtimes/liboliphaunt-wasix/postgres/series"
 
 read_toml_value() {
   local key="$1"
@@ -77,10 +77,11 @@ fi
 
 series_hash="$(
   {
-    sha256_text_lf "$PATCH_DIR/series"
-    for patch_file in "$PATCH_DIR"/*.patch; do
-      sha256_text_lf "$patch_file"
-    done
+    sha256_text_lf "$PATCH_SERIES"
+    while IFS= read -r patch_name; do
+      [[ -z "$patch_name" || "$patch_name" =~ ^# ]] && continue
+      sha256_text_lf "$PATCH_DIR/$patch_name"
+    done < "$PATCH_SERIES"
   } | sha256_stream
 )"
 new_fingerprint="$PG_VERSION:$PG_SHA256:$series_hash"
@@ -100,11 +101,7 @@ rm -rf "$PATCHED_PGSRC"
 tar -xjf "$TARBALL" -C "$WORK_ROOT/work"
 mv "$WORK_ROOT/work/postgresql-$PG_VERSION" "$PATCHED_PGSRC"
 
-while IFS= read -r patch_name; do
-  [[ -z "$patch_name" || "$patch_name" =~ ^# ]] && continue
-  echo "prepare_postgres_source: applying $patch_name" >&2
-  (cd "$PATCHED_PGSRC" && patch --no-backup-if-mismatch -p1 < "$PATCH_DIR/$patch_name") >&2
-done < "$PATCH_DIR/series"
+bash "$REPO_ROOT/src/third-party/postgres/apply-series.sh" "$PATCHED_PGSRC" "$PATCH_SERIES" --context-fuzz >&2
 
 if source_has_patch_artifacts "$PATCHED_PGSRC"; then
   echo "prepare_postgres_source: patch backup/reject files were left in $PATCHED_PGSRC" >&2
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh b/src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
similarity index 94%
rename from src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
index fe7cbd2d9..173e87c94 100644
--- a/src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/profile_flags.sh
@@ -103,10 +103,10 @@ oliphaunt_wasix_wasix_profile_signature() {
   printf 'wasm_opt_preserve_unoptimized=%s\n' "${OLIPHAUNT_WASM_WASM_OPT_PRESERVE_UNOPTIMIZED:-}"
   printf 'compiler_flags=%s\n' "${OLIPHAUNT_WASM_WASIX_COMPILER_FLAGS:-}"
   printf 'linker_flags=%s\n' "${OLIPHAUNT_WASM_WASIX_LINKER_FLAGS:-}"
-  if [ -f ./src/runtimes/liboliphaunt/wasix/assets/build/configure_wasix_dl.sh ]; then
-    printf 'configure_postgres_wasix_dl_sha256=%s\n' "$(sha256sum ./src/runtimes/liboliphaunt/wasix/assets/build/configure_wasix_dl.sh | awk '{print $1}')"
+  if [ -f ./src/runtimes/liboliphaunt-wasix/assets/build/configure_wasix_dl.sh ]; then
+    printf 'configure_postgres_wasix_dl_sha256=%s\n' "$(sha256sum ./src/runtimes/liboliphaunt-wasix/assets/build/configure_wasix_dl.sh | awk '{print $1}')"
   fi
-  if [ -f ./src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh ]; then
-    printf 'build_wasix_icu_sha256=%s\n' "$(sha256sum ./src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh | awk '{print $1}')"
+  if [ -f ./src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_icu.sh ]; then
+    printf 'build_wasix_icu_sha256=%s\n' "$(sha256sum ./src/runtimes/liboliphaunt-wasix/assets/build/build_wasix_icu.sh | awk '{print $1}')"
   fi
 }
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/source_lane.sh b/src/runtimes/liboliphaunt-wasix/assets/build/source_lane.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/source_lane.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/source_lane.sh
diff --git a/src/runtimes/liboliphaunt-wasix/assets/build/wasix-toml-value.mts b/src/runtimes/liboliphaunt-wasix/assets/build/wasix-toml-value.mts
new file mode 100644
index 000000000..23bbf400a
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/wasix-toml-value.mts
@@ -0,0 +1,46 @@
+#!/usr/bin/env bun
+
+function fail(message) {
+  console.error(message);
+  process.exit(2);
+}
+
+function usage() {
+  fail('usage: wasix-toml-value.mts string|string-list  ');
+}
+
+function isObject(value) {
+  return value !== null && typeof value === 'object' && !Array.isArray(value);
+}
+
+const [mode, file, key] = Bun.argv.slice(2);
+if ((mode !== 'string' && mode !== 'string-list') || !file || !key) {
+  usage();
+}
+
+let data;
+try {
+  data = Bun.TOML.parse(await Bun.file(file).text());
+} catch (error) {
+  fail(`could not read TOML file ${file}: ${error.message}`);
+}
+
+if (!isObject(data)) {
+  fail(`${file} must contain a TOML table`);
+}
+
+if (mode === 'string-list') {
+  const values = Object.hasOwn(data, key) ? data[key] : [];
+  if (!Array.isArray(values) || !values.every((value) => typeof value === 'string')) {
+    fail(`${file} field ${key} must be an array of strings`);
+  }
+  for (const value of values) {
+    console.log(value);
+  }
+} else {
+  const value = data[key];
+  if (typeof value !== 'string' || value.length === 0) {
+    fail(`${file} field ${key} must be a non-empty string`);
+  }
+  console.log(value);
+}
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_frontend_tools.sh b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_frontend_tools.sh
similarity index 94%
rename from src/runtimes/liboliphaunt/wasix/assets/build/wasix_frontend_tools.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/wasix_frontend_tools.sh
index caa7afe91..d4eeb0582 100644
--- a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_frontend_tools.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_frontend_tools.sh
@@ -6,7 +6,6 @@
 
 oliphaunt_wasix_prepare_frontend_tools() {
   local helper_root
-  local icu_native_build_dir
   local icu_build_dir
   local tool_shim
   local tool_stamp
@@ -15,13 +14,11 @@ oliphaunt_wasix_prepare_frontend_tools() {
   helper_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
   . "$helper_root/wasix_icu_link.sh"
 
-  icu_native_build_dir="$CONTAINER_GENERATED_ROOT/work/icu-native-tools"
   OLIPHAUNT_WASIX_FRONTEND_ICU_PREFIX="$CONTAINER_GENERATED_ROOT/work/icu-wasix-tools"
   icu_build_dir="$CONTAINER_GENERATED_ROOT/work/icu-wasix-tools-build"
   OLIPHAUNT_WASIX_FRONTEND_ICU_PREFIX="$(
     env -u AR -u RANLIB -u NM -u LLVM_NM \
       ICU_PREFIX="$OLIPHAUNT_WASIX_FRONTEND_ICU_PREFIX" \
-      ICU_NATIVE_BUILD_DIR="$icu_native_build_dir" \
       ICU_BUILD_DIR="$icu_build_dir" \
       OLIPHAUNT_WASM_BUILD_PROFILE=release-os \
       OLIPHAUNT_WASM_WASIX_COPT="-O2 -g0" \
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_icu_link.sh b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_icu_link.sh
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/wasix_icu_link.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/wasix_icu_link.sh
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge.c b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge.c
rename to src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge.c
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge_abi_test.c b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge_abi_test.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge_abi_test.c
rename to src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge_abi_test.c
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim.c b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim.c
rename to src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim.c
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim_abi_test.c b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim_abi_test.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim_abi_test.c
rename to src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim_abi_test.c
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_shim.c b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_shim.c
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_shim.c
rename to src/runtimes/liboliphaunt-wasix/assets/build/wasix_shim/oliphaunt_wasix_shim.c
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_third_party.sh b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_third_party.sh
similarity index 92%
rename from src/runtimes/liboliphaunt/wasix/assets/build/wasix_third_party.sh
rename to src/runtimes/liboliphaunt-wasix/assets/build/wasix_third_party.sh
index c9595d1e1..f8df991a2 100755
--- a/src/runtimes/liboliphaunt/wasix/assets/build/wasix_third_party.sh
+++ b/src/runtimes/liboliphaunt-wasix/assets/build/wasix_third_party.sh
@@ -15,7 +15,7 @@ oliphaunt_wasix_repo_root() {
   repo_root="$root"
   while [ "$repo_root" != "/" ]; do
     if [ -f "$repo_root/package.json" ] &&
-       [ -d "$repo_root/src/runtimes/liboliphaunt/wasix/assets/build" ]; then
+       [ -d "$repo_root/src/runtimes/liboliphaunt-wasix/assets/build" ]; then
       printf '%s\n' "$repo_root"
       return 0
     fi
@@ -112,7 +112,7 @@ oliphaunt_wasix_extension_wasix_target_values() {
   local key="$3"
   local target="$repo_root/src/extensions/external/$extension/targets/wasix.toml"
   "$repo_root/tools/dev/bun.sh" \
-    "$repo_root/src/runtimes/liboliphaunt/wasix/assets/build/wasix-toml-value.mjs" \
+    "$repo_root/src/runtimes/liboliphaunt-wasix/assets/build/wasix-toml-value.mts" \
     string-list \
     "$target" \
     "$key"
@@ -124,7 +124,7 @@ oliphaunt_wasix_extension_recipe_value() {
   local key="$3"
   local recipe="$repo_root/src/extensions/external/$extension/recipe.toml"
   "$repo_root/tools/dev/bun.sh" \
-    "$repo_root/src/runtimes/liboliphaunt/wasix/assets/build/wasix-toml-value.mjs" \
+    "$repo_root/src/runtimes/liboliphaunt-wasix/assets/build/wasix-toml-value.mts" \
     string \
     "$recipe" \
     "$key"
@@ -148,7 +148,7 @@ oliphaunt_wasix_extension_wasix_dependencies() {
   local repo_root="$1"
   local extension="$2"
   "$repo_root/tools/dev/bun.sh" \
-    "$repo_root/src/extensions/tools/native-component-contract.mjs" \
+    "$repo_root/src/extensions/tools/native-component-contract.mts" \
     field "$extension" wasix wasix-runtime wasix-portable components
 }
 
@@ -334,3 +334,17 @@ oliphaunt_wasix_static_cmake_build() {
   cmake --build "$build_dir" --parallel "$JOBS"
   cmake --install "$build_dir"
 }
+
+# Publish only a completely installed and validated dependency prefix.
+# ponytail: Callers must serialize a shared prefix. Concurrent writers or
+# SIGKILL between these renames require generation-based publication first.
+oliphaunt_wasix_publish_prefix() (
+  set -e
+  local staged="$1" prefix="$2" backup
+  backup="$(mktemp -d "$prefix.previous.XXXXXX")"
+  trap 'status=$?; if [ "$status" -ne 0 ] && [ ! -e "$prefix" ] && [ -d "$backup/prefix" ]; then mv "$backup/prefix" "$prefix" || exit "$status"; fi; rm -rf "$backup"' EXIT
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
+  if [ -e "$prefix" ]; then mv "$prefix" "$backup/prefix"; fi
+  mv "$staged" "$prefix"
+)
diff --git a/src/runtimes/liboliphaunt/wasix/assets/generated/wasix-dl.exports b/src/runtimes/liboliphaunt-wasix/assets/generated/wasix-dl.exports
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/generated/wasix-dl.exports
rename to src/runtimes/liboliphaunt-wasix/assets/generated/wasix-dl.exports
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/Cargo.toml b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/Cargo.toml
new file mode 100644
index 000000000..39c61b2a3
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "liboliphaunt-wasix-aot-aarch64-apple-darwin"
+version = "0.2.0"
+edition = "2024"
+rust-version = "1.93"
+description = "Wasmer AOT runtime artifacts for oliphaunt-wasix on aarch64-apple-darwin"
+repository = "https://github.com/f0rr0/oliphaunt"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_liboliphaunt_wasix_aot_macos_arm64"
+include = ["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+serde_json = "1"
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/README.md b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/README.md
rename to src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/README.md
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/build-support.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/build-support.rs
new file mode 100644
index 000000000..a4821a382
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/build-support.rs
@@ -0,0 +1,297 @@
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
+const ARTIFACT_KIND: &str = "wasix-aot";
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
+
+    let target = env::var("CARGO_PKG_NAME")
+        .expect("CARGO_PKG_NAME is set by Cargo")
+        .strip_prefix("liboliphaunt-wasix-aot-")
+        .expect("AOT crate name starts with liboliphaunt-wasix-aot-")
+        .to_owned();
+    emit_expected_artifact_inputs(&target);
+
+    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
+        .join("generated_aot.rs");
+    if let Some(artifact_dir) = find_artifact_dir(&target) {
+        emit_rerun_directives(&artifact_dir);
+        write_generated_aot(&out, &target, &artifact_dir);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX AOT artifacts for {target}");
+    } else {
+        write_source_only_aot(&out, &target);
+    }
+}
+
+fn emit_expected_artifact_inputs(target: &str) {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        emit_manifest_probe(&candidate);
+    }
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
+    }
+    emit_manifest_probe(&manifest_dir.join("artifacts"));
+}
+
+fn emit_manifest_probe(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("manifest.json").display()
+    );
+}
+
+fn find_artifact_dir(target: &str) -> Option {
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let package_artifacts = manifest_dir.join("artifacts");
+    if package_artifacts.join("manifest.json").is_file() {
+        return Some(package_artifacts);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local artifacts");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        if candidate.join("manifest.json").is_file() {
+            return Some(candidate);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
+        if target_artifacts.join("manifest.json").is_file() {
+            return Some(target_artifacts);
+        }
+    }
+
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
+    manifest_dir.ancestors().find(|candidate| {
+        candidate.join("Cargo.toml").is_file()
+            && candidate.join("src/sdks/rust-wasix/Cargo.toml").is_file()
+    })
+}
+
+fn emit_rerun_directives(artifact_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", artifact_dir.display());
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        for entry in entries.flatten() {
+            let path = entry.path();
+            if path.is_file() {
+                println!("cargo:rerun-if-changed={}", path.display());
+            }
+        }
+    }
+}
+
+fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
+    let manifest = artifact_dir.join("manifest.json");
+    let generated_manifest = out
+        .parent()
+        .expect("generated AOT output has parent")
+        .join("manifest.json");
+    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
+    for relative in &retained_paths {
+        assert!(
+            artifact_dir.join(relative).is_file(),
+            "missing declared WASIX AOT artifact: {relative}"
+        );
+    }
+    let mut cases = String::new();
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        let mut files = entries
+            .flatten()
+            .map(|entry| entry.path())
+            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
+            .collect::>();
+        files.sort();
+        for file in files {
+            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
+                continue;
+            };
+            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
+                continue;
+            };
+            let artifact_name = artifact_name_from_file_stem(stem);
+            if !artifact_belongs_to_crate(&artifact_name) {
+                continue;
+            }
+            cases.push_str(&format!(
+                "        {:?} => Some(include_bytes!({})),\n",
+                artifact_name,
+                rust_string_literal(&file)
+            ));
+        }
+    }
+    cases.push_str("        _ => None,\n");
+
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = true;\n\
+         pub const MANIFEST_JSON: &str = include_str!({});\n\
+         #[rustfmt::skip]\n\
+         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
+             match name {{\n\
+         {cases}    }}\n\
+         }}\n",
+        target,
+        rust_string_literal(&generated_manifest)
+    );
+    fs::write(out, text).expect("write generated AOT include module");
+    let mut manifest_files = vec![generated_manifest];
+    for relative in retained_paths {
+        manifest_files.push(artifact_dir.join(relative));
+    }
+    emit_artifact_manifest(
+        out.parent().expect("generated AOT output has parent"),
+        target,
+        artifact_dir,
+        &manifest_files,
+    );
+}
+
+fn write_source_only_aot(out: &Path, target: &str) {
+    let manifest = format!(
+        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
+    );
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {target:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = false;\n\
+         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
+         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
+    );
+    fs::write(out, text).expect("write source-only AOT include module");
+}
+
+fn artifact_name_from_file_stem(stem: &str) -> String {
+    match stem {
+        "oliphaunt" => "runtime:oliphaunt".to_owned(),
+        "pg_dump" => "tool:pg_dump".to_owned(),
+        "psql" => "tool:psql".to_owned(),
+        "initdb" => "tool:initdb".to_owned(),
+        "plpgsql" => "runtime-support:plpgsql".to_owned(),
+        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
+        extension_support if extension_support.ends_with("_deps") => {
+            let sql_name = extension_support.trim_end_matches("_deps");
+            format!("extension:{sql_name}:{extension_support}")
+        }
+        extension => format!("extension:{extension}"),
+    }
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn artifact_belongs_to_crate(name: &str) -> bool {
+    match ARTIFACT_KIND {
+        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
+        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
+    }
+}
+
+fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
+    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
+    let mut manifest: serde_json::Value =
+        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
+    let artifacts = manifest
+        .get_mut("artifacts")
+        .and_then(|value| value.as_array_mut())
+        .expect("generated WASIX AOT manifest has artifacts array");
+    let mut retained = Vec::new();
+    let mut paths = Vec::new();
+    for artifact in artifacts.drain(..) {
+        let name = artifact
+            .get("name")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has name")
+            .to_owned();
+        if !artifact_belongs_to_crate(&name) {
+            continue;
+        }
+        let path = artifact
+            .get("path")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has path")
+            .to_owned();
+        paths.push(path);
+        retained.push(artifact);
+    }
+    *artifacts = retained;
+    let rendered =
+        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
+    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
+    paths
+}
+
+fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
+    );
+    for file in files {
+        if !file.is_file() {
+            continue;
+        }
+        let relative = file
+            .strip_prefix(artifact_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| "manifest.json".to_owned());
+        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/build.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/src/lib.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/src/lib.rs
rename to src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin/src/lib.rs
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/Cargo.toml b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/Cargo.toml
new file mode 100644
index 000000000..0366f529b
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu"
+version = "0.2.0"
+edition = "2024"
+rust-version = "1.93"
+description = "Wasmer AOT runtime artifacts for oliphaunt-wasix on aarch64-unknown-linux-gnu"
+repository = "https://github.com/f0rr0/oliphaunt"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_liboliphaunt_wasix_aot_linux_arm64_gnu"
+include = ["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+serde_json = "1"
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/README.md b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/README.md
rename to src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/README.md
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/build-support.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/build-support.rs
new file mode 100644
index 000000000..a4821a382
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/build-support.rs
@@ -0,0 +1,297 @@
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
+const ARTIFACT_KIND: &str = "wasix-aot";
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
+
+    let target = env::var("CARGO_PKG_NAME")
+        .expect("CARGO_PKG_NAME is set by Cargo")
+        .strip_prefix("liboliphaunt-wasix-aot-")
+        .expect("AOT crate name starts with liboliphaunt-wasix-aot-")
+        .to_owned();
+    emit_expected_artifact_inputs(&target);
+
+    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
+        .join("generated_aot.rs");
+    if let Some(artifact_dir) = find_artifact_dir(&target) {
+        emit_rerun_directives(&artifact_dir);
+        write_generated_aot(&out, &target, &artifact_dir);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX AOT artifacts for {target}");
+    } else {
+        write_source_only_aot(&out, &target);
+    }
+}
+
+fn emit_expected_artifact_inputs(target: &str) {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        emit_manifest_probe(&candidate);
+    }
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
+    }
+    emit_manifest_probe(&manifest_dir.join("artifacts"));
+}
+
+fn emit_manifest_probe(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("manifest.json").display()
+    );
+}
+
+fn find_artifact_dir(target: &str) -> Option {
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let package_artifacts = manifest_dir.join("artifacts");
+    if package_artifacts.join("manifest.json").is_file() {
+        return Some(package_artifacts);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local artifacts");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        if candidate.join("manifest.json").is_file() {
+            return Some(candidate);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
+        if target_artifacts.join("manifest.json").is_file() {
+            return Some(target_artifacts);
+        }
+    }
+
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
+    manifest_dir.ancestors().find(|candidate| {
+        candidate.join("Cargo.toml").is_file()
+            && candidate.join("src/sdks/rust-wasix/Cargo.toml").is_file()
+    })
+}
+
+fn emit_rerun_directives(artifact_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", artifact_dir.display());
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        for entry in entries.flatten() {
+            let path = entry.path();
+            if path.is_file() {
+                println!("cargo:rerun-if-changed={}", path.display());
+            }
+        }
+    }
+}
+
+fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
+    let manifest = artifact_dir.join("manifest.json");
+    let generated_manifest = out
+        .parent()
+        .expect("generated AOT output has parent")
+        .join("manifest.json");
+    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
+    for relative in &retained_paths {
+        assert!(
+            artifact_dir.join(relative).is_file(),
+            "missing declared WASIX AOT artifact: {relative}"
+        );
+    }
+    let mut cases = String::new();
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        let mut files = entries
+            .flatten()
+            .map(|entry| entry.path())
+            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
+            .collect::>();
+        files.sort();
+        for file in files {
+            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
+                continue;
+            };
+            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
+                continue;
+            };
+            let artifact_name = artifact_name_from_file_stem(stem);
+            if !artifact_belongs_to_crate(&artifact_name) {
+                continue;
+            }
+            cases.push_str(&format!(
+                "        {:?} => Some(include_bytes!({})),\n",
+                artifact_name,
+                rust_string_literal(&file)
+            ));
+        }
+    }
+    cases.push_str("        _ => None,\n");
+
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = true;\n\
+         pub const MANIFEST_JSON: &str = include_str!({});\n\
+         #[rustfmt::skip]\n\
+         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
+             match name {{\n\
+         {cases}    }}\n\
+         }}\n",
+        target,
+        rust_string_literal(&generated_manifest)
+    );
+    fs::write(out, text).expect("write generated AOT include module");
+    let mut manifest_files = vec![generated_manifest];
+    for relative in retained_paths {
+        manifest_files.push(artifact_dir.join(relative));
+    }
+    emit_artifact_manifest(
+        out.parent().expect("generated AOT output has parent"),
+        target,
+        artifact_dir,
+        &manifest_files,
+    );
+}
+
+fn write_source_only_aot(out: &Path, target: &str) {
+    let manifest = format!(
+        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
+    );
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {target:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = false;\n\
+         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
+         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
+    );
+    fs::write(out, text).expect("write source-only AOT include module");
+}
+
+fn artifact_name_from_file_stem(stem: &str) -> String {
+    match stem {
+        "oliphaunt" => "runtime:oliphaunt".to_owned(),
+        "pg_dump" => "tool:pg_dump".to_owned(),
+        "psql" => "tool:psql".to_owned(),
+        "initdb" => "tool:initdb".to_owned(),
+        "plpgsql" => "runtime-support:plpgsql".to_owned(),
+        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
+        extension_support if extension_support.ends_with("_deps") => {
+            let sql_name = extension_support.trim_end_matches("_deps");
+            format!("extension:{sql_name}:{extension_support}")
+        }
+        extension => format!("extension:{extension}"),
+    }
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn artifact_belongs_to_crate(name: &str) -> bool {
+    match ARTIFACT_KIND {
+        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
+        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
+    }
+}
+
+fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
+    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
+    let mut manifest: serde_json::Value =
+        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
+    let artifacts = manifest
+        .get_mut("artifacts")
+        .and_then(|value| value.as_array_mut())
+        .expect("generated WASIX AOT manifest has artifacts array");
+    let mut retained = Vec::new();
+    let mut paths = Vec::new();
+    for artifact in artifacts.drain(..) {
+        let name = artifact
+            .get("name")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has name")
+            .to_owned();
+        if !artifact_belongs_to_crate(&name) {
+            continue;
+        }
+        let path = artifact
+            .get("path")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has path")
+            .to_owned();
+        paths.push(path);
+        retained.push(artifact);
+    }
+    *artifacts = retained;
+    let rendered =
+        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
+    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
+    paths
+}
+
+fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
+    );
+    for file in files {
+        if !file.is_file() {
+            continue;
+        }
+        let relative = file
+            .strip_prefix(artifact_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| "manifest.json".to_owned());
+        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/build.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/src/lib.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/src/lib.rs
rename to src/runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu/src/lib.rs
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/Cargo.toml b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/Cargo.toml
new file mode 100644
index 000000000..f26d5abf5
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc"
+version = "0.2.0"
+edition = "2024"
+rust-version = "1.93"
+description = "Wasmer AOT runtime artifacts for oliphaunt-wasix on x86_64-pc-windows-msvc"
+repository = "https://github.com/f0rr0/oliphaunt"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_liboliphaunt_wasix_aot_windows_x64_msvc"
+include = ["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+serde_json = "1"
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/README.md b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/README.md
rename to src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/README.md
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/build-support.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/build-support.rs
new file mode 100644
index 000000000..a4821a382
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/build-support.rs
@@ -0,0 +1,297 @@
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
+const ARTIFACT_KIND: &str = "wasix-aot";
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
+
+    let target = env::var("CARGO_PKG_NAME")
+        .expect("CARGO_PKG_NAME is set by Cargo")
+        .strip_prefix("liboliphaunt-wasix-aot-")
+        .expect("AOT crate name starts with liboliphaunt-wasix-aot-")
+        .to_owned();
+    emit_expected_artifact_inputs(&target);
+
+    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
+        .join("generated_aot.rs");
+    if let Some(artifact_dir) = find_artifact_dir(&target) {
+        emit_rerun_directives(&artifact_dir);
+        write_generated_aot(&out, &target, &artifact_dir);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX AOT artifacts for {target}");
+    } else {
+        write_source_only_aot(&out, &target);
+    }
+}
+
+fn emit_expected_artifact_inputs(target: &str) {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        emit_manifest_probe(&candidate);
+    }
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
+    }
+    emit_manifest_probe(&manifest_dir.join("artifacts"));
+}
+
+fn emit_manifest_probe(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("manifest.json").display()
+    );
+}
+
+fn find_artifact_dir(target: &str) -> Option {
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let package_artifacts = manifest_dir.join("artifacts");
+    if package_artifacts.join("manifest.json").is_file() {
+        return Some(package_artifacts);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local artifacts");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        if candidate.join("manifest.json").is_file() {
+            return Some(candidate);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
+        if target_artifacts.join("manifest.json").is_file() {
+            return Some(target_artifacts);
+        }
+    }
+
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
+    manifest_dir.ancestors().find(|candidate| {
+        candidate.join("Cargo.toml").is_file()
+            && candidate.join("src/sdks/rust-wasix/Cargo.toml").is_file()
+    })
+}
+
+fn emit_rerun_directives(artifact_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", artifact_dir.display());
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        for entry in entries.flatten() {
+            let path = entry.path();
+            if path.is_file() {
+                println!("cargo:rerun-if-changed={}", path.display());
+            }
+        }
+    }
+}
+
+fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
+    let manifest = artifact_dir.join("manifest.json");
+    let generated_manifest = out
+        .parent()
+        .expect("generated AOT output has parent")
+        .join("manifest.json");
+    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
+    for relative in &retained_paths {
+        assert!(
+            artifact_dir.join(relative).is_file(),
+            "missing declared WASIX AOT artifact: {relative}"
+        );
+    }
+    let mut cases = String::new();
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        let mut files = entries
+            .flatten()
+            .map(|entry| entry.path())
+            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
+            .collect::>();
+        files.sort();
+        for file in files {
+            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
+                continue;
+            };
+            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
+                continue;
+            };
+            let artifact_name = artifact_name_from_file_stem(stem);
+            if !artifact_belongs_to_crate(&artifact_name) {
+                continue;
+            }
+            cases.push_str(&format!(
+                "        {:?} => Some(include_bytes!({})),\n",
+                artifact_name,
+                rust_string_literal(&file)
+            ));
+        }
+    }
+    cases.push_str("        _ => None,\n");
+
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = true;\n\
+         pub const MANIFEST_JSON: &str = include_str!({});\n\
+         #[rustfmt::skip]\n\
+         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
+             match name {{\n\
+         {cases}    }}\n\
+         }}\n",
+        target,
+        rust_string_literal(&generated_manifest)
+    );
+    fs::write(out, text).expect("write generated AOT include module");
+    let mut manifest_files = vec![generated_manifest];
+    for relative in retained_paths {
+        manifest_files.push(artifact_dir.join(relative));
+    }
+    emit_artifact_manifest(
+        out.parent().expect("generated AOT output has parent"),
+        target,
+        artifact_dir,
+        &manifest_files,
+    );
+}
+
+fn write_source_only_aot(out: &Path, target: &str) {
+    let manifest = format!(
+        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
+    );
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {target:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = false;\n\
+         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
+         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
+    );
+    fs::write(out, text).expect("write source-only AOT include module");
+}
+
+fn artifact_name_from_file_stem(stem: &str) -> String {
+    match stem {
+        "oliphaunt" => "runtime:oliphaunt".to_owned(),
+        "pg_dump" => "tool:pg_dump".to_owned(),
+        "psql" => "tool:psql".to_owned(),
+        "initdb" => "tool:initdb".to_owned(),
+        "plpgsql" => "runtime-support:plpgsql".to_owned(),
+        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
+        extension_support if extension_support.ends_with("_deps") => {
+            let sql_name = extension_support.trim_end_matches("_deps");
+            format!("extension:{sql_name}:{extension_support}")
+        }
+        extension => format!("extension:{extension}"),
+    }
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn artifact_belongs_to_crate(name: &str) -> bool {
+    match ARTIFACT_KIND {
+        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
+        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
+    }
+}
+
+fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
+    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
+    let mut manifest: serde_json::Value =
+        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
+    let artifacts = manifest
+        .get_mut("artifacts")
+        .and_then(|value| value.as_array_mut())
+        .expect("generated WASIX AOT manifest has artifacts array");
+    let mut retained = Vec::new();
+    let mut paths = Vec::new();
+    for artifact in artifacts.drain(..) {
+        let name = artifact
+            .get("name")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has name")
+            .to_owned();
+        if !artifact_belongs_to_crate(&name) {
+            continue;
+        }
+        let path = artifact
+            .get("path")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has path")
+            .to_owned();
+        paths.push(path);
+        retained.push(artifact);
+    }
+    *artifacts = retained;
+    let rendered =
+        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
+    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
+    paths
+}
+
+fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
+    );
+    for file in files {
+        if !file.is_file() {
+            continue;
+        }
+        let relative = file
+            .strip_prefix(artifact_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| "manifest.json".to_owned());
+        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/build.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/src/lib.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/src/lib.rs
rename to src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc/src/lib.rs
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/Cargo.toml b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/Cargo.toml
new file mode 100644
index 000000000..d677bd150
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu"
+version = "0.2.0"
+edition = "2024"
+rust-version = "1.93"
+description = "Wasmer AOT runtime artifacts for oliphaunt-wasix on x86_64-unknown-linux-gnu"
+repository = "https://github.com/f0rr0/oliphaunt"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_liboliphaunt_wasix_aot_linux_x64_gnu"
+include = ["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
+
+[lib]
+path = "src/lib.rs"
+
+[build-dependencies]
+serde_json = "1"
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/README.md b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/README.md
rename to src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/README.md
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/build-support.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/build-support.rs
new file mode 100644
index 000000000..a4821a382
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/build-support.rs
@@ -0,0 +1,297 @@
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
+const ARTIFACT_KIND: &str = "wasix-aot";
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
+
+    let target = env::var("CARGO_PKG_NAME")
+        .expect("CARGO_PKG_NAME is set by Cargo")
+        .strip_prefix("liboliphaunt-wasix-aot-")
+        .expect("AOT crate name starts with liboliphaunt-wasix-aot-")
+        .to_owned();
+    emit_expected_artifact_inputs(&target);
+
+    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
+        .join("generated_aot.rs");
+    if let Some(artifact_dir) = find_artifact_dir(&target) {
+        emit_rerun_directives(&artifact_dir);
+        write_generated_aot(&out, &target, &artifact_dir);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX AOT artifacts for {target}");
+    } else {
+        write_source_only_aot(&out, &target);
+    }
+}
+
+fn emit_expected_artifact_inputs(target: &str) {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        emit_manifest_probe(&candidate);
+    }
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
+    }
+    emit_manifest_probe(&manifest_dir.join("artifacts"));
+}
+
+fn emit_manifest_probe(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("manifest.json").display()
+    );
+}
+
+fn find_artifact_dir(target: &str) -> Option {
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let package_artifacts = manifest_dir.join("artifacts");
+    if package_artifacts.join("manifest.json").is_file() {
+        return Some(package_artifacts);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local artifacts");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
+        let path = PathBuf::from(path);
+        let candidate = if path.ends_with(target) {
+            path
+        } else {
+            path.join(target)
+        };
+        if candidate.join("manifest.json").is_file() {
+            return Some(candidate);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
+        if target_artifacts.join("manifest.json").is_file() {
+            return Some(target_artifacts);
+        }
+    }
+
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
+    manifest_dir.ancestors().find(|candidate| {
+        candidate.join("Cargo.toml").is_file()
+            && candidate.join("src/sdks/rust-wasix/Cargo.toml").is_file()
+    })
+}
+
+fn emit_rerun_directives(artifact_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", artifact_dir.display());
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        for entry in entries.flatten() {
+            let path = entry.path();
+            if path.is_file() {
+                println!("cargo:rerun-if-changed={}", path.display());
+            }
+        }
+    }
+}
+
+fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
+    let manifest = artifact_dir.join("manifest.json");
+    let generated_manifest = out
+        .parent()
+        .expect("generated AOT output has parent")
+        .join("manifest.json");
+    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
+    for relative in &retained_paths {
+        assert!(
+            artifact_dir.join(relative).is_file(),
+            "missing declared WASIX AOT artifact: {relative}"
+        );
+    }
+    let mut cases = String::new();
+    if let Ok(entries) = fs::read_dir(artifact_dir) {
+        let mut files = entries
+            .flatten()
+            .map(|entry| entry.path())
+            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
+            .collect::>();
+        files.sort();
+        for file in files {
+            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
+                continue;
+            };
+            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
+                continue;
+            };
+            let artifact_name = artifact_name_from_file_stem(stem);
+            if !artifact_belongs_to_crate(&artifact_name) {
+                continue;
+            }
+            cases.push_str(&format!(
+                "        {:?} => Some(include_bytes!({})),\n",
+                artifact_name,
+                rust_string_literal(&file)
+            ));
+        }
+    }
+    cases.push_str("        _ => None,\n");
+
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = true;\n\
+         pub const MANIFEST_JSON: &str = include_str!({});\n\
+         #[rustfmt::skip]\n\
+         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
+             match name {{\n\
+         {cases}    }}\n\
+         }}\n",
+        target,
+        rust_string_literal(&generated_manifest)
+    );
+    fs::write(out, text).expect("write generated AOT include module");
+    let mut manifest_files = vec![generated_manifest];
+    for relative in retained_paths {
+        manifest_files.push(artifact_dir.join(relative));
+    }
+    emit_artifact_manifest(
+        out.parent().expect("generated AOT output has parent"),
+        target,
+        artifact_dir,
+        &manifest_files,
+    );
+}
+
+fn write_source_only_aot(out: &Path, target: &str) {
+    let manifest = format!(
+        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
+    );
+    let text = format!(
+        "pub const TARGET_TRIPLE: &str = {target:?};\n\
+         pub const ENGINE: &str = \"llvm-opta\";\n\
+         pub const HAS_EMBEDDED_AOT: bool = false;\n\
+         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
+         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
+    );
+    fs::write(out, text).expect("write source-only AOT include module");
+}
+
+fn artifact_name_from_file_stem(stem: &str) -> String {
+    match stem {
+        "oliphaunt" => "runtime:oliphaunt".to_owned(),
+        "pg_dump" => "tool:pg_dump".to_owned(),
+        "psql" => "tool:psql".to_owned(),
+        "initdb" => "tool:initdb".to_owned(),
+        "plpgsql" => "runtime-support:plpgsql".to_owned(),
+        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
+        extension_support if extension_support.ends_with("_deps") => {
+            let sql_name = extension_support.trim_end_matches("_deps");
+            format!("extension:{sql_name}:{extension_support}")
+        }
+        extension => format!("extension:{extension}"),
+    }
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn artifact_belongs_to_crate(name: &str) -> bool {
+    match ARTIFACT_KIND {
+        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
+        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
+    }
+}
+
+fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
+    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
+    let mut manifest: serde_json::Value =
+        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
+    let artifacts = manifest
+        .get_mut("artifacts")
+        .and_then(|value| value.as_array_mut())
+        .expect("generated WASIX AOT manifest has artifacts array");
+    let mut retained = Vec::new();
+    let mut paths = Vec::new();
+    for artifact in artifacts.drain(..) {
+        let name = artifact
+            .get("name")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has name")
+            .to_owned();
+        if !artifact_belongs_to_crate(&name) {
+            continue;
+        }
+        let path = artifact
+            .get("path")
+            .and_then(|value| value.as_str())
+            .expect("AOT artifact has path")
+            .to_owned();
+        paths.push(path);
+        retained.push(artifact);
+    }
+    *artifacts = retained;
+    let rendered =
+        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
+    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
+    paths
+}
+
+fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
+    );
+    for file in files {
+        if !file.is_file() {
+            continue;
+        }
+        let relative = file
+            .strip_prefix(artifact_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| "manifest.json".to_owned());
+        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/build.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/src/lib.rs b/src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/src/lib.rs
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/src/lib.rs
rename to src/runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu/src/lib.rs
diff --git a/src/runtimes/liboliphaunt-wasix/crates/assets/Cargo.toml b/src/runtimes/liboliphaunt-wasix/crates/assets/Cargo.toml
new file mode 100644
index 000000000..81020af17
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/assets/Cargo.toml
@@ -0,0 +1,76 @@
+[package]
+name = "liboliphaunt-wasix-portable"
+version = "0.2.0"
+edition = "2024"
+rust-version = "1.93"
+description = "Portable WASIX runtime assets for oliphaunt-wasix"
+repository = "https://github.com/f0rr0/oliphaunt"
+homepage = "https://oliphaunt.dev"
+documentation = "https://docs.rs/liboliphaunt-wasix-portable"
+license = "MIT AND PostgreSQL AND Unicode-3.0"
+publish = false
+links = "oliphaunt_artifact_liboliphaunt_wasix_runtime"
+include = [
+  "Cargo.toml",
+  "build.rs", "build-support.rs",
+  "README.md",
+  "src/**",
+  "payload/**",
+  "LICENSE",
+  "THIRD_PARTY_NOTICES.md",
+  "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
+  "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
+  "THIRD_PARTY_LICENSES/ICU-LICENSE",
+]
+
+[features]
+extension-amcheck = []
+extension-auto-explain = []
+extension-bloom = []
+extension-btree-gin = []
+extension-btree-gist = []
+extension-citext = []
+extension-cube = []
+extension-dict-int = []
+extension-dict-xsyn = []
+extension-earthdistance = ["extension-cube"]
+extension-file-fdw = []
+extension-fuzzystrmatch = []
+extension-hstore = []
+extension-intarray = []
+extension-isn = []
+extension-lo = []
+extension-ltree = []
+extension-pageinspect = []
+extension-pg-buffercache = []
+extension-pg-freespacemap = []
+extension-pg-hashids = []
+extension-pg-ivm = []
+extension-pg-surgery = []
+extension-pg-textsearch = []
+extension-pg-trgm = []
+extension-pg-uuidv7 = []
+extension-pg-visibility = []
+extension-pg-walinspect = []
+extension-pgcrypto = []
+extension-pgtap = []
+extension-postgis = []
+extension-seg = []
+extension-tablefunc = []
+extension-tcn = []
+extension-tsm-system-rows = []
+extension-tsm-system-time = []
+extension-unaccent = []
+extension-uuid-ossp = []
+extension-vector = []
+
+[lib]
+path = "src/lib.rs"
+
+[dependencies]
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+
+[build-dependencies]
+serde_json = "1"
+sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/assets/README.md b/src/runtimes/liboliphaunt-wasix/crates/assets/README.md
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/crates/assets/README.md
rename to src/runtimes/liboliphaunt-wasix/crates/assets/README.md
diff --git a/src/runtimes/liboliphaunt-wasix/crates/assets/build-support.rs b/src/runtimes/liboliphaunt-wasix/crates/assets/build-support.rs
new file mode 100644
index 000000000..1808b300e
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/assets/build-support.rs
@@ -0,0 +1,1160 @@
+use std::collections::BTreeSet;
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Component, Path, PathBuf};
+
+use sha2::{Digest, Sha256};
+
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
+const ARTIFACT_KIND: &str = "wasix-runtime";
+const ARTIFACT_TARGET: &str = "portable";
+
+#[derive(Debug, Clone, Copy)]
+struct ExtensionPackage {
+    #[allow(dead_code)]
+    feature: &'static str,
+    env: &'static str,
+    product: &'static str,
+    sql_name: &'static str,
+    crate_ident: &'static str,
+}
+
+#[derive(Debug)]
+struct SelectedExtension {
+    package: ExtensionPackage,
+    archive: ExtensionArchiveSource,
+    aot_packages: Vec,
+}
+
+#[derive(Debug)]
+enum ExtensionArchiveSource {
+    Crate,
+    Local {
+        path: PathBuf,
+        sha256: String,
+        size: u64,
+    },
+    Missing,
+}
+
+#[derive(Debug, Clone, Copy)]
+struct ExtensionAotTarget {
+    id: &'static str,
+    target: &'static str,
+    cfg: &'static str,
+}
+
+#[derive(Debug)]
+struct SelectedExtensionAotPackage {
+    target: ExtensionAotTarget,
+    source: ExtensionAotSource,
+}
+
+#[derive(Debug)]
+enum ExtensionAotSource {
+    Crate {
+        crate_ident: String,
+    },
+    Local {
+        manifest: PathBuf,
+        artifacts: Vec,
+    },
+}
+
+#[derive(Debug)]
+struct LocalExtensionAotArtifact {
+    name: String,
+    path: PathBuf,
+}
+
+const EXTENSION_AOT_TARGETS: &[ExtensionAotTarget] = &[
+    ExtensionAotTarget {
+        id: "macos-arm64",
+        target: "aarch64-apple-darwin",
+        cfg: r#"all(target_os = "macos", target_arch = "aarch64")"#,
+    },
+    ExtensionAotTarget {
+        id: "linux-arm64-gnu",
+        target: "aarch64-unknown-linux-gnu",
+        cfg: r#"all(target_os = "linux", target_arch = "aarch64", target_env = "gnu")"#,
+    },
+    ExtensionAotTarget {
+        id: "linux-x64-gnu",
+        target: "x86_64-unknown-linux-gnu",
+        cfg: r#"all(target_os = "linux", target_arch = "x86_64", target_env = "gnu")"#,
+    },
+    ExtensionAotTarget {
+        id: "windows-x64-msvc",
+        target: "x86_64-pc-windows-msvc",
+        cfg: r#"all(target_os = "windows", target_arch = "x86_64", target_env = "msvc")"#,
+    },
+];
+
+const EXTENSION_PACKAGES: &[ExtensionPackage] = &[
+    ExtensionPackage {
+        feature: "extension-amcheck",
+        env: "CARGO_FEATURE_EXTENSION_AMCHECK",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "amcheck",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-auto-explain",
+        env: "CARGO_FEATURE_EXTENSION_AUTO_EXPLAIN",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "auto_explain",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-bloom",
+        env: "CARGO_FEATURE_EXTENSION_BLOOM",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "bloom",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-btree-gin",
+        env: "CARGO_FEATURE_EXTENSION_BTREE_GIN",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "btree_gin",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-btree-gist",
+        env: "CARGO_FEATURE_EXTENSION_BTREE_GIST",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "btree_gist",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-citext",
+        env: "CARGO_FEATURE_EXTENSION_CITEXT",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "citext",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-cube",
+        env: "CARGO_FEATURE_EXTENSION_CUBE",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "cube",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-dict-int",
+        env: "CARGO_FEATURE_EXTENSION_DICT_INT",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "dict_int",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-dict-xsyn",
+        env: "CARGO_FEATURE_EXTENSION_DICT_XSYN",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "dict_xsyn",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-earthdistance",
+        env: "CARGO_FEATURE_EXTENSION_EARTHDISTANCE",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "earthdistance",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-file-fdw",
+        env: "CARGO_FEATURE_EXTENSION_FILE_FDW",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "file_fdw",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-fuzzystrmatch",
+        env: "CARGO_FEATURE_EXTENSION_FUZZYSTRMATCH",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "fuzzystrmatch",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-hstore",
+        env: "CARGO_FEATURE_EXTENSION_HSTORE",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "hstore",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-intarray",
+        env: "CARGO_FEATURE_EXTENSION_INTARRAY",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "intarray",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-isn",
+        env: "CARGO_FEATURE_EXTENSION_ISN",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "isn",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-lo",
+        env: "CARGO_FEATURE_EXTENSION_LO",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "lo",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-ltree",
+        env: "CARGO_FEATURE_EXTENSION_LTREE",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "ltree",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-pageinspect",
+        env: "CARGO_FEATURE_EXTENSION_PAGEINSPECT",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "pageinspect",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-buffercache",
+        env: "CARGO_FEATURE_EXTENSION_PG_BUFFERCACHE",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "pg_buffercache",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-freespacemap",
+        env: "CARGO_FEATURE_EXTENSION_PG_FREESPACEMAP",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "pg_freespacemap",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-surgery",
+        env: "CARGO_FEATURE_EXTENSION_PG_SURGERY",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "pg_surgery",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-trgm",
+        env: "CARGO_FEATURE_EXTENSION_PG_TRGM",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "pg_trgm",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-visibility",
+        env: "CARGO_FEATURE_EXTENSION_PG_VISIBILITY",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "pg_visibility",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-walinspect",
+        env: "CARGO_FEATURE_EXTENSION_PG_WALINSPECT",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "pg_walinspect",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-pgcrypto",
+        env: "CARGO_FEATURE_EXTENSION_PGCRYPTO",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "pgcrypto",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-seg",
+        env: "CARGO_FEATURE_EXTENSION_SEG",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "seg",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-tablefunc",
+        env: "CARGO_FEATURE_EXTENSION_TABLEFUNC",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "tablefunc",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-tcn",
+        env: "CARGO_FEATURE_EXTENSION_TCN",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "tcn",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-tsm-system-rows",
+        env: "CARGO_FEATURE_EXTENSION_TSM_SYSTEM_ROWS",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "tsm_system_rows",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-tsm-system-time",
+        env: "CARGO_FEATURE_EXTENSION_TSM_SYSTEM_TIME",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "tsm_system_time",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-unaccent",
+        env: "CARGO_FEATURE_EXTENSION_UNACCENT",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "unaccent",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-uuid-ossp",
+        env: "CARGO_FEATURE_EXTENSION_UUID_OSSP",
+        product: "oliphaunt-extension-contrib-pg18",
+        sql_name: "uuid-ossp",
+        crate_ident: "oliphaunt_extension_contrib_pg18",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-hashids",
+        env: "CARGO_FEATURE_EXTENSION_PG_HASHIDS",
+        product: "oliphaunt-extension-pg-hashids",
+        sql_name: "pg_hashids",
+        crate_ident: "oliphaunt_extension_pg_hashids",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-ivm",
+        env: "CARGO_FEATURE_EXTENSION_PG_IVM",
+        product: "oliphaunt-extension-pg-ivm",
+        sql_name: "pg_ivm",
+        crate_ident: "oliphaunt_extension_pg_ivm",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-textsearch",
+        env: "CARGO_FEATURE_EXTENSION_PG_TEXTSEARCH",
+        product: "oliphaunt-extension-pg-textsearch",
+        sql_name: "pg_textsearch",
+        crate_ident: "oliphaunt_extension_pg_textsearch",
+    },
+    ExtensionPackage {
+        feature: "extension-pg-uuidv7",
+        env: "CARGO_FEATURE_EXTENSION_PG_UUIDV7",
+        product: "oliphaunt-extension-pg-uuidv7",
+        sql_name: "pg_uuidv7",
+        crate_ident: "oliphaunt_extension_pg_uuidv7",
+    },
+    ExtensionPackage {
+        feature: "extension-pgtap",
+        env: "CARGO_FEATURE_EXTENSION_PGTAP",
+        product: "oliphaunt-extension-pgtap",
+        sql_name: "pgtap",
+        crate_ident: "oliphaunt_extension_pgtap",
+    },
+    ExtensionPackage {
+        feature: "extension-postgis",
+        env: "CARGO_FEATURE_EXTENSION_POSTGIS",
+        product: "oliphaunt-extension-postgis",
+        sql_name: "postgis",
+        crate_ident: "oliphaunt_extension_postgis",
+    },
+    ExtensionPackage {
+        feature: "extension-vector",
+        env: "CARGO_FEATURE_EXTENSION_VECTOR",
+        product: "oliphaunt-extension-vector",
+        sql_name: "vector",
+        crate_ident: "oliphaunt_extension_vector",
+    },
+];
+
+fn main() {
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR");
+    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT");
+    for package in EXTENSION_PACKAGES {
+        println!("cargo:rerun-if-env-changed={}", package.env);
+    }
+    emit_expected_asset_inputs();
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"));
+    let out = out_dir.join("generated_assets.rs");
+    let manifest_text =
+        fs::read_to_string(manifest_dir.join("Cargo.toml")).expect("read Cargo.toml");
+    let selected_extensions = selected_extensions(&manifest_dir, &manifest_text);
+
+    if let Some(asset_dir) = find_asset_dir() {
+        emit_rerun_directives(&asset_dir);
+        write_generated_assets(&out, &asset_dir, &selected_extensions);
+    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
+        panic!("release packaging requires package-local WASIX runtime payload");
+    } else {
+        write_source_only_assets(&out, &selected_extensions);
+    }
+}
+
+fn emit_expected_asset_inputs() {
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR") {
+        emit_manifest_probe(&PathBuf::from(path));
+    }
+
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/assets"));
+    }
+    emit_manifest_probe(&manifest_dir.join("payload"));
+}
+
+fn emit_manifest_probe(dir: &Path) {
+    println!("cargo:rerun-if-changed={}", dir.display());
+    println!(
+        "cargo:rerun-if-changed={}",
+        dir.join("manifest.json").display()
+    );
+}
+
+fn find_asset_dir() -> Option {
+    let manifest_dir = PathBuf::from(
+        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
+    );
+    let package_payload = manifest_dir.join("payload");
+    if package_payload.join("manifest.json").is_file() {
+        return Some(package_payload);
+    }
+
+    if PACKAGE_LOCAL {
+        panic!("published WASIX carrier requires package-local payload");
+    }
+
+    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR") {
+        let path = PathBuf::from(path);
+        if path.join("manifest.json").is_file() {
+            return Some(path);
+        }
+    }
+
+    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
+        let target_assets = repo_root.join("target/oliphaunt-wasix/assets");
+        if target_assets.join("manifest.json").is_file() {
+            return Some(target_assets);
+        }
+    }
+
+    None
+}
+
+fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
+    manifest_dir.ancestors().find(|candidate| {
+        candidate.join("Cargo.toml").is_file()
+            && candidate
+                .join("src/runtimes/liboliphaunt-wasix/crates/assets/Cargo.toml")
+                .is_file()
+    })
+}
+
+fn emit_rerun_directives(asset_dir: &Path) {
+    println!("cargo:rerun-if-changed={}", asset_dir.display());
+    visit_files(asset_dir, &mut |path| {
+        println!("cargo:rerun-if-changed={}", path.display());
+    });
+}
+
+fn visit_files(path: &Path, f: &mut impl FnMut(&Path)) {
+    let Ok(entries) = fs::read_dir(path) else {
+        return;
+    };
+    for entry in entries.flatten() {
+        let path = entry.path();
+        if path.is_dir() {
+            visit_files(&path, f);
+        } else if path.is_file() {
+            f(&path);
+        }
+    }
+}
+
+fn write_generated_assets(out: &Path, asset_dir: &Path, selected_extensions: &[SelectedExtension]) {
+    let manifest = asset_dir.join("manifest.json");
+    let generated_manifest = out
+        .parent()
+        .expect("generated asset output has parent")
+        .join("manifest.json");
+    write_core_manifest(&manifest, &generated_manifest, selected_extensions);
+    let runtime = asset_dir.join("oliphaunt.wasix.tar.zst");
+    let initdb = asset_dir.join("bin/initdb.wasix.wasm");
+
+    for required in [&manifest, &runtime, &initdb] {
+        assert!(
+            required.is_file(),
+            "generated asset directory {} is missing required file {}",
+            asset_dir.display(),
+            required.display()
+        );
+    }
+
+    let extension_sql_names = selected_extension_sql_names_body(selected_extensions);
+    let extension_aot_sql_names = selected_extension_aot_sql_names_body(selected_extensions);
+    let extension_archive_body = extension_archive_body(selected_extensions);
+    let extension_sha256_body = expected_extension_archive_sha256_body(selected_extensions);
+    let extension_aot_manifest_body = extension_aot_manifest_json_body(selected_extensions);
+    let extension_aot_bytes_body = extension_aot_artifact_bytes_body(selected_extensions);
+
+    let text = format!(
+        "pub const HAS_EMBEDDED_ASSETS: bool = true;\n\
+         pub const SELECTED_EXTENSION_SQL_NAMES: &[&str] = {extension_sql_names};\n\
+         pub const SELECTED_EXTENSION_AOT_SQL_NAMES: &[&str] = {extension_aot_sql_names};\n\
+         pub const MANIFEST_JSON: &str = include_str!({manifest});\n\
+         pub fn runtime_archive() -> Option<&'static [u8]> {{ Some(include_bytes!({runtime})) }}\n\
+         pub fn initdb_wasm() -> Option<&'static [u8]> {{ Some(include_bytes!({initdb})) }}\n\
+         pub fn extension_archive(name: &str) -> Option<&'static [u8]> {{\n{extension_archive_body}         }}\n\
+         pub fn expected_extension_archive_sha256(name: &str) -> Option<&'static str> {{\n{extension_sha256_body}         }}\n\
+         #[allow(clippy::match_single_binding)] // Target cfgs can remove every generated match arm.\n\
+         pub fn extension_aot_manifest_json(target: &str, sql_name: &str) -> Option<&'static str> {{\n{extension_aot_manifest_body}         }}\n\
+         pub fn extension_aot_artifact_bytes(target: &str, name: &str) -> Option<&'static [u8]> {{\n{extension_aot_bytes_body}         }}\n",
+        manifest = rust_string_literal(&generated_manifest),
+        runtime = rust_string_literal(&runtime),
+        initdb = rust_string_literal(&initdb),
+        extension_sql_names = extension_sql_names,
+        extension_aot_sql_names = extension_aot_sql_names,
+        extension_archive_body = extension_archive_body,
+        extension_sha256_body = extension_sha256_body,
+        extension_aot_manifest_body = extension_aot_manifest_body,
+        extension_aot_bytes_body = extension_aot_bytes_body,
+    );
+    fs::write(out, text).expect("write generated asset include module");
+    emit_artifact_manifest(
+        out.parent().expect("generated asset output has parent"),
+        asset_dir,
+        &[&generated_manifest, &runtime, &initdb],
+    );
+}
+
+fn write_source_only_assets(out: &Path, selected_extensions: &[SelectedExtension]) {
+    let extension_sql_names = selected_extension_sql_names_body(selected_extensions);
+    let extension_aot_sql_names = selected_extension_aot_sql_names_body(selected_extensions);
+    let extension_archive_body = extension_archive_body(selected_extensions);
+    let extension_sha256_body = expected_extension_archive_sha256_body(selected_extensions);
+    let extension_aot_manifest_body = extension_aot_manifest_json_body(selected_extensions);
+    let extension_aot_bytes_body = extension_aot_artifact_bytes_body(selected_extensions);
+    let mut text = format!(
+        "pub const HAS_EMBEDDED_ASSETS: bool = false;\n\
+         pub const SELECTED_EXTENSION_SQL_NAMES: &[&str] = {extension_sql_names};\n\
+         pub const SELECTED_EXTENSION_AOT_SQL_NAMES: &[&str] = {extension_aot_sql_names};\n"
+    );
+    text.push_str(
+        r##"pub const MANIFEST_JSON: &str = r#"{"format-version":2,"runtime":{"archive":"","sha256":"","module-sha256":"","postgres-version":"","runtime-kind":"source-only-template"},"runtime-support":[],"extensions":[],"sources":[]}"#;
+pub fn runtime_archive() -> Option<&'static [u8]> { None }
+pub fn initdb_wasm() -> Option<&'static [u8]> { None }
+"##,
+    );
+    text.push_str(&format!(
+        "pub fn extension_archive(name: &str) -> Option<&'static [u8]> {{\n\
+{extension_archive_body}}}\n\
+         pub fn expected_extension_archive_sha256(name: &str) -> Option<&'static str> {{\n\
+{extension_sha256_body}}}\n\
+         #[allow(clippy::match_single_binding)] // Target cfgs can remove every generated match arm.\n\
+         pub fn extension_aot_manifest_json(target: &str, sql_name: &str) -> Option<&'static str> {{\n\
+{extension_aot_manifest_body}}}\n\
+         pub fn extension_aot_artifact_bytes(target: &str, name: &str) -> Option<&'static [u8]> {{\n\
+{extension_aot_bytes_body}}}\n"
+    ));
+    fs::write(out, text).expect("write source-only asset include module");
+}
+
+fn rust_string_literal(path: &Path) -> String {
+    format!("{:?}", path.to_string_lossy())
+}
+
+fn write_core_manifest(
+    source: &Path,
+    destination: &Path,
+    selected_extensions: &[SelectedExtension],
+) {
+    let text = fs::read_to_string(source).expect("read generated WASIX asset manifest");
+    let mut manifest: serde_json::Value =
+        serde_json::from_str(&text).expect("parse generated WASIX asset manifest");
+    manifest["extensions"] = serde_json::Value::Array(
+        selected_extensions
+            .iter()
+            .filter_map(extension_manifest_entry)
+            .collect(),
+    );
+    let object = manifest
+        .as_object_mut()
+        .expect("generated WASIX asset manifest is an object");
+    object.remove("cluster-seeds");
+    object.remove("pg-dump");
+    object.remove("psql");
+    let rendered =
+        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX asset manifest");
+    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX asset manifest");
+}
+
+fn selected_extensions(manifest_dir: &Path, manifest_text: &str) -> Vec {
+    let repo_root = repo_root_from_manifest_dir(manifest_dir).map(Path::to_path_buf);
+    EXTENSION_PACKAGES
+        .iter()
+        .copied()
+        .filter_map(|package| {
+            env::var_os(package.env)?;
+            let archive_package = extension_wasix_package_name(package);
+            let archive = if manifest_declares_dependency(manifest_text, &archive_package) {
+                ExtensionArchiveSource::Crate
+            } else if PACKAGE_LOCAL {
+                panic!("published WASIX carrier requires declared extension dependency {archive_package}");
+            } else if let Some(path) =
+                find_local_extension_archive(manifest_dir, repo_root.as_deref(), package)
+            {
+                println!("cargo:rerun-if-changed={}", path.display());
+                let sha256 =
+                    sha256_file(&path).expect("hash selected local WASIX extension archive");
+                let size = path
+                    .metadata()
+                    .expect("stat selected local WASIX extension archive")
+                    .len();
+                ExtensionArchiveSource::Local { path, sha256, size }
+            } else {
+                if let Some(root) = env::var_os("OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT") {
+                    panic!(
+                        "explicit local extension artifact root {} is missing the canonical WASIX archive for selected extension {}",
+                        Path::new(&root).display(),
+                        package.sql_name,
+                    );
+                }
+                ExtensionArchiveSource::Missing
+            };
+            let aot_packages = selected_extension_aot_packages(manifest_text, package);
+            Some(SelectedExtension {
+                package,
+                archive,
+                aot_packages,
+            })
+        })
+        .collect()
+}
+
+fn selected_extension_aot_packages(
+    manifest_text: &str,
+    package: ExtensionPackage,
+) -> Vec {
+    let dependencies = EXTENSION_AOT_TARGETS
+        .iter()
+        .copied()
+        .filter_map(|target| {
+            let package_name = extension_aot_package_name(package, target);
+            manifest_declares_dependency(manifest_text, &package_name).then(|| {
+                SelectedExtensionAotPackage {
+                    target,
+                    source: ExtensionAotSource::Crate {
+                        crate_ident: crate_ident(&package_name),
+                    },
+                }
+            })
+        })
+        .collect::>();
+    if !dependencies.is_empty() {
+        return dependencies;
+    }
+    if PACKAGE_LOCAL {
+        return Vec::new();
+    }
+    local_extension_aot_package(package).into_iter().collect()
+}
+
+fn local_extension_product_roots(root: &Path, product: &str) -> [PathBuf; 4] {
+    let packaged = root.join("oliphaunt-extension-package-artifacts");
+    [
+        root.join(ARTIFACT_PRODUCT).join(product),
+        root.join(product),
+        packaged.join(ARTIFACT_PRODUCT).join(product),
+        packaged.join(product),
+    ]
+}
+
+fn find_local_extension_product_root(root: &Path, package: ExtensionPackage) -> Option {
+    local_extension_product_roots(root, package.product)
+        .into_iter()
+        .find(|candidate| candidate.join("extension-artifacts.json").is_file())
+}
+
+fn local_extension_aot_package(package: ExtensionPackage) -> Option {
+    let root = PathBuf::from(env::var_os("OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT")?);
+    let product_root = find_local_extension_product_root(&root, package).unwrap_or_else(|| {
+        panic!(
+            "local extension artifact root {} has no manifest for {}",
+            root.display(),
+            package.product,
+        )
+    });
+    let product_manifest = product_root.join("extension-artifacts.json");
+    let product_value: serde_json::Value = serde_json::from_str(
+        &fs::read_to_string(&product_manifest).unwrap_or_else(|error| {
+            panic!(
+                "read local extension artifact manifest {}: {error}",
+                product_manifest.display()
+            )
+        }),
+    )
+    .unwrap_or_else(|error| {
+        panic!(
+            "parse local extension artifact manifest {}: {error}",
+            product_manifest.display()
+        )
+    });
+    assert_eq!(
+        product_value
+            .get("product")
+            .and_then(serde_json::Value::as_str),
+        Some(package.product),
+        "local extension artifact manifest {} has the wrong product",
+        product_manifest.display(),
+    );
+    let schema = product_value
+        .get("schema")
+        .and_then(serde_json::Value::as_str)
+        .unwrap_or_else(|| {
+            panic!(
+                "local extension artifact manifest {} has no schema",
+                product_manifest.display()
+            )
+        });
+    let member = match schema {
+        "oliphaunt-extension-ci-artifacts-v1" => {
+            assert_eq!(
+                product_value
+                    .get("sqlName")
+                    .and_then(serde_json::Value::as_str),
+                Some(package.sql_name),
+                "local extension artifact manifest {} has the wrong SQL name",
+                product_manifest.display(),
+            );
+            &product_value
+        }
+        "oliphaunt-extension-ci-artifacts-v2" => product_value
+            .get("extensions")
+            .and_then(serde_json::Value::as_array)
+            .and_then(|rows| {
+                rows.iter().find(|row| {
+                    row.get("sqlName").and_then(serde_json::Value::as_str) == Some(package.sql_name)
+                })
+            })
+            .unwrap_or_else(|| {
+                panic!(
+                    "local extension artifact manifest {} lacks bundle member {}",
+                    product_manifest.display(),
+                    package.sql_name
+                )
+            }),
+        other => panic!(
+            "local extension artifact manifest {} has unsupported schema {other}",
+            product_manifest.display()
+        ),
+    };
+    let requires_aot = match member.get("nativeModuleStem") {
+        Some(serde_json::Value::String(value)) if !value.is_empty() => true,
+        Some(serde_json::Value::Null) => false,
+        other => panic!(
+            "local extension artifact manifest {} has invalid nativeModuleStem {other:?}",
+            product_manifest.display(),
+        ),
+    };
+    if !requires_aot {
+        return None;
+    }
+
+    let build_target = env::var("TARGET").expect("Cargo sets TARGET for build scripts");
+    let target = EXTENSION_AOT_TARGETS
+        .iter()
+        .copied()
+        .find(|target| target.target == build_target)
+        .unwrap_or_else(|| panic!("unsupported local extension AOT build target {build_target}"));
+    let target_root = product_root.join("wasix-aot").join(target.id);
+    let aot_dir = if schema == "oliphaunt-extension-ci-artifacts-v2" {
+        target_root.join(package.sql_name)
+    } else {
+        target_root
+    };
+    let manifest = aot_dir.join("manifest.json");
+    let manifest_value: serde_json::Value =
+        serde_json::from_str(&fs::read_to_string(&manifest).unwrap_or_else(|error| {
+            panic!(
+                "read local extension AOT manifest {}: {error}",
+                manifest.display()
+            )
+        }))
+        .unwrap_or_else(|error| {
+            panic!(
+                "parse local extension AOT manifest {}: {error}",
+                manifest.display()
+            )
+        });
+    assert_eq!(
+        manifest_value
+            .get("format-version")
+            .and_then(serde_json::Value::as_u64),
+        Some(1),
+        "local extension AOT manifest {} has an unsupported format",
+        manifest.display(),
+    );
+    assert_eq!(
+        manifest_value
+            .get("target-triple")
+            .and_then(serde_json::Value::as_str),
+        Some(target.target),
+        "local extension AOT manifest {} targets the wrong platform",
+        manifest.display(),
+    );
+    let rows = manifest_value
+        .get("artifacts")
+        .and_then(serde_json::Value::as_array)
+        .filter(|rows| !rows.is_empty())
+        .unwrap_or_else(|| {
+            panic!(
+                "local extension AOT manifest {} has no artifacts",
+                manifest.display()
+            )
+        });
+    let mut names = BTreeSet::new();
+    let mut artifacts = Vec::new();
+    for row in rows {
+        let name = row
+            .get("name")
+            .and_then(serde_json::Value::as_str)
+            .unwrap_or_else(|| {
+                panic!(
+                    "local extension AOT manifest {} has an artifact without a name",
+                    manifest.display()
+                )
+            });
+        let expected_prefix = format!("extension:{}", package.sql_name);
+        assert!(
+            name == expected_prefix || name.starts_with(&format!("{expected_prefix}:")),
+            "local extension AOT manifest {} contains foreign artifact {name}",
+            manifest.display(),
+        );
+        assert!(
+            names.insert(name.to_owned()),
+            "local extension AOT manifest {} repeats artifact {name}",
+            manifest.display()
+        );
+        let relative = row
+            .get("path")
+            .and_then(serde_json::Value::as_str)
+            .map(Path::new)
+            .unwrap_or_else(|| {
+                panic!(
+                    "local extension AOT manifest {} has an artifact without a path",
+                    manifest.display()
+                )
+            });
+        assert!(
+            !relative.is_absolute()
+                && relative
+                    .components()
+                    .all(|component| matches!(component, Component::Normal(_))),
+            "local extension AOT manifest {} contains unsafe path {}",
+            manifest.display(),
+            relative.display(),
+        );
+        let artifact = aot_dir.join(relative);
+        assert!(
+            artifact.is_file(),
+            "local extension AOT manifest {} references missing {}",
+            manifest.display(),
+            artifact.display()
+        );
+        let expected_sha256 = row
+            .get("sha256")
+            .and_then(serde_json::Value::as_str)
+            .filter(|value| value.len() == 64 && value.bytes().all(|byte| byte.is_ascii_hexdigit()))
+            .unwrap_or_else(|| {
+                panic!(
+                    "local extension AOT manifest {} has an invalid artifact sha256",
+                    manifest.display()
+                )
+            });
+        let actual_sha256 = sha256_file(&artifact).unwrap_or_else(|error| {
+            panic!(
+                "hash local extension AOT artifact {}: {error}",
+                artifact.display()
+            )
+        });
+        assert_eq!(
+            actual_sha256,
+            expected_sha256,
+            "local extension AOT artifact {} does not match its manifest",
+            artifact.display()
+        );
+        println!("cargo:rerun-if-changed={}", artifact.display());
+        artifacts.push(LocalExtensionAotArtifact {
+            name: name.to_owned(),
+            path: artifact,
+        });
+    }
+    println!("cargo:rerun-if-changed={}", product_manifest.display());
+    println!("cargo:rerun-if-changed={}", manifest.display());
+    Some(SelectedExtensionAotPackage {
+        target,
+        source: ExtensionAotSource::Local {
+            manifest,
+            artifacts,
+        },
+    })
+}
+
+fn extension_aot_package_name(package: ExtensionPackage, target: ExtensionAotTarget) -> String {
+    let suffix = match target.id {
+        "macos-arm64" => "macos-arm64",
+        "linux-arm64-gnu" => "linux-arm64",
+        "linux-x64-gnu" => "linux-x64",
+        "windows-x64-msvc" => "windows-x64",
+        other => panic!("unsupported extension AOT target id {other}"),
+    };
+    format!("{}-aot-{suffix}", package.product)
+}
+
+fn extension_wasix_package_name(package: ExtensionPackage) -> String {
+    format!("{}-wasix", package.product)
+}
+
+fn crate_ident(package_name: &str) -> String {
+    package_name.replace('-', "_")
+}
+
+fn manifest_declares_dependency(manifest_text: &str, package_name: &str) -> bool {
+    manifest_text
+        .lines()
+        .any(|line| line.trim_start().starts_with(&format!("{package_name} =")))
+}
+
+fn find_local_extension_archive(
+    manifest_dir: &Path,
+    repo_root: Option<&Path>,
+    package: ExtensionPackage,
+) -> Option {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let archive_name = format!("{}-{version}-wasix-portable.tar.zst", package.product);
+    let roots = if let Some(path) = env::var_os("OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT") {
+        // An explicit root takes precedence over workspace and package assets.
+        vec![PathBuf::from(path)]
+    } else {
+        let mut roots = Vec::new();
+        if let Some(repo_root) = repo_root {
+            roots.push(repo_root.join("target/extension-artifacts"));
+        }
+        roots.push(manifest_dir.join("extension-artifacts"));
+        roots
+    };
+
+    for root in roots {
+        for product_root in local_extension_product_roots(&root, package.product) {
+            for candidate in [
+                product_root
+                    .join("member-assets")
+                    .join(package.sql_name)
+                    .join(&archive_name),
+                product_root.join("release-assets").join(&archive_name),
+            ] {
+                if candidate.is_file() {
+                    return Some(candidate);
+                }
+            }
+        }
+    }
+    None
+}
+
+fn selected_extension_sql_names_body(selected_extensions: &[SelectedExtension]) -> String {
+    let sql_names = selected_extensions
+        .iter()
+        .map(|extension| format!("{:?}", extension.package.sql_name))
+        .collect::>()
+        .join(", ");
+    format!("&[{sql_names}]")
+}
+
+fn selected_extension_aot_sql_names_body(selected_extensions: &[SelectedExtension]) -> String {
+    let sql_names = selected_extensions
+        .iter()
+        .filter(|extension| !extension.aot_packages.is_empty())
+        .map(|extension| format!("{:?}", extension.package.sql_name))
+        .collect::>()
+        .join(", ");
+    format!("&[{sql_names}]")
+}
+
+fn extension_archive_body(selected_extensions: &[SelectedExtension]) -> String {
+    if selected_extensions.is_empty() {
+        return "            let _ = name;\n            None\n".to_owned();
+    }
+    let mut body = String::from("            match name {\n");
+    for extension in selected_extensions {
+        let sql_name = extension.package.sql_name;
+        let expression = match &extension.archive {
+            ExtensionArchiveSource::Crate => {
+                format!(
+                    "{}::archive({sql_name:?})",
+                    extension_wasix_crate_ident(extension.package),
+                )
+            }
+            ExtensionArchiveSource::Local { path, .. } => {
+                format!("Some(include_bytes!({}))", rust_string_literal(path))
+            }
+            ExtensionArchiveSource::Missing => "None".to_owned(),
+        };
+        body.push_str(&format!("                {sql_name:?} => {expression},\n"));
+    }
+    body.push_str("                _ => None,\n            }\n");
+    body
+}
+
+fn expected_extension_archive_sha256_body(selected_extensions: &[SelectedExtension]) -> String {
+    if selected_extensions.is_empty() {
+        return "            let _ = name;\n            None\n".to_owned();
+    }
+    let mut body = String::from("            match name {\n");
+    for extension in selected_extensions {
+        let sql_name = extension.package.sql_name;
+        let expression = match &extension.archive {
+            ExtensionArchiveSource::Crate => {
+                format!(
+                    "{}::archive_sha256({sql_name:?})",
+                    extension_wasix_crate_ident(extension.package),
+                )
+            }
+            ExtensionArchiveSource::Local { sha256, .. } => {
+                format!("Some({sha256:?})")
+            }
+            ExtensionArchiveSource::Missing => "None".to_owned(),
+        };
+        body.push_str(&format!("                {sql_name:?} => {expression},\n"));
+    }
+    body.push_str("                _ => None,\n            }\n");
+    body
+}
+
+fn extension_aot_manifest_json_body(selected_extensions: &[SelectedExtension]) -> String {
+    let mut body = String::from("            match (target, sql_name) {\n");
+    for extension in selected_extensions {
+        let sql_name = extension.package.sql_name;
+        for aot in &extension.aot_packages {
+            let expression = match &aot.source {
+                ExtensionAotSource::Crate { crate_ident } => {
+                    format!("{crate_ident}::aot_manifest_json({sql_name:?})")
+                }
+                ExtensionAotSource::Local { manifest, .. } => {
+                    format!("Some(include_str!({}))", rust_string_literal(manifest))
+                }
+            };
+            body.push_str(&format!(
+                "                #[cfg({})]\n                ({:?}, {:?}) => {expression},\n",
+                aot.target.cfg, aot.target.target, sql_name,
+            ));
+        }
+    }
+    body.push_str("                _ => None,\n            }\n");
+    body
+}
+
+fn extension_aot_artifact_bytes_body(selected_extensions: &[SelectedExtension]) -> String {
+    let mut body = String::from("            let _ = (target, name);\n");
+    let mut emitted_crates = BTreeSet::new();
+    for extension in selected_extensions {
+        for aot in &extension.aot_packages {
+            match &aot.source {
+                ExtensionAotSource::Crate { crate_ident } => {
+                    if !emitted_crates.insert((aot.target.target, crate_ident.as_str())) {
+                        continue;
+                    }
+                    body.push_str(&format!(
+                        "            #[cfg({})]\n            if target == {:?} {{\n                if let Some(bytes) = {}::aot_artifact_bytes(name) {{\n                    return Some(bytes);\n                }}\n            }}\n",
+                        aot.target.cfg,
+                        aot.target.target,
+                        crate_ident,
+                    ));
+                }
+                ExtensionAotSource::Local { artifacts, .. } => {
+                    body.push_str(&format!(
+                        "            #[cfg({})]\n            if target == {:?} {{\n                match name {{\n",
+                        aot.target.cfg,
+                        aot.target.target,
+                    ));
+                    for artifact in artifacts {
+                        body.push_str(&format!(
+                            "                    {:?} => return Some(include_bytes!({})),\n",
+                            artifact.name,
+                            rust_string_literal(&artifact.path),
+                        ));
+                    }
+                    body.push_str(
+                        "                    _ => {}\n                }\n            }\n",
+                    );
+                }
+            }
+        }
+    }
+    body.push_str("            None\n");
+    body
+}
+
+fn extension_manifest_entry(extension: &SelectedExtension) -> Option {
+    match &extension.archive {
+        ExtensionArchiveSource::Local { sha256, size, .. } => Some(serde_json::json!({
+            "name": extension.package.sql_name,
+            "sql-name": extension.package.sql_name,
+            "archive": format!("extensions/{}.tar.zst", extension.package.sql_name),
+            "sha256": sha256,
+            "size": size,
+        })),
+        ExtensionArchiveSource::Crate | ExtensionArchiveSource::Missing => None,
+    }
+}
+
+fn extension_wasix_crate_ident(package: ExtensionPackage) -> String {
+    format!("{}_wasix", package.crate_ident)
+}
+
+fn emit_artifact_manifest(out_dir: &Path, asset_dir: &Path, files: &[&Path]) {
+    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
+    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
+    let mut text = format!(
+        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {ARTIFACT_TARGET:?}\n"
+    );
+    for file in files {
+        if !file.is_file() {
+            continue;
+        }
+        let relative = file
+            .strip_prefix(asset_dir)
+            .ok()
+            .map(|path| path.to_string_lossy().replace('\\', "/"))
+            .unwrap_or_else(|| "manifest.json".to_owned());
+        let sha256 = sha256_file(file).expect("hash WASIX runtime artifact file");
+        text.push_str(&format!(
+            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
+            file.display().to_string(),
+            relative,
+            sha256,
+        ));
+    }
+    fs::write(&manifest_path, text).expect("write WASIX runtime Cargo artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest_path.display());
+}
+
+fn sha256_file(path: &Path) -> io::Result {
+    let mut file = fs::File::open(path)?;
+    let mut hasher = Sha256::new();
+    let mut buffer = [0u8; 128 * 1024];
+    loop {
+        let read = file.read(&mut buffer)?;
+        if read == 0 {
+            break;
+        }
+        hasher.update(&buffer[..read]);
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/runtimes/liboliphaunt-wasix/crates/assets/build.rs b/src/runtimes/liboliphaunt-wasix/crates/assets/build.rs
new file mode 100644
index 000000000..1b5c6bfc3
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/assets/build.rs
@@ -0,0 +1,2 @@
+const PACKAGE_LOCAL: bool = false;
+include!("build-support.rs");
diff --git a/src/runtimes/liboliphaunt-wasix/crates/assets/src/lib.rs b/src/runtimes/liboliphaunt-wasix/crates/assets/src/lib.rs
new file mode 100644
index 000000000..c5a9ea401
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/crates/assets/src/lib.rs
@@ -0,0 +1,216 @@
+#![deny(unsafe_code)]
+
+use serde::{Deserialize, Serialize};
+
+include!(concat!(env!("OUT_DIR"), "/generated_assets.rs"));
+
+/// PostgreSQL major whose on-disk layout is carried by this runtime family.
+pub const POSTGRES_MAJOR: u32 = 18;
+/// Version of the runtime payload selected by Cargo.
+#[doc(hidden)]
+pub const PACKAGE_VERSION: &str = env!("CARGO_PKG_VERSION");
+/// Stable WASIX physical-storage compatibility identity.
+pub const PHYSICAL_FORMAT: &str = "wasix-pg18-v1";
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct AssetManifest {
+    pub format_version: u32,
+    #[serde(default)]
+    pub source_lane: Option,
+    #[serde(default)]
+    pub source_fingerprint: Option,
+    pub runtime: RuntimeAsset,
+    #[serde(default)]
+    pub runtime_support: Vec,
+    #[serde(default)]
+    pub initdb: Option,
+    #[serde(default)]
+    pub extensions: Vec,
+    #[serde(default)]
+    pub sources: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct RuntimeAsset {
+    pub archive: String,
+    pub sha256: String,
+    #[serde(default)]
+    pub module_sha256: String,
+    pub postgres_version: String,
+    pub runtime_kind: String,
+    #[serde(default)]
+    pub link: Option,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct BinaryAsset {
+    pub name: String,
+    pub path: String,
+    pub sha256: String,
+    #[serde(default)]
+    pub module_sha256: String,
+    #[serde(default)]
+    pub native_module: Option,
+    pub size: u64,
+    #[serde(default)]
+    pub link: Option,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct ExtensionAsset {
+    pub name: String,
+    pub sql_name: String,
+    #[serde(default)]
+    pub source_kind: String,
+    pub archive: String,
+    pub sha256: String,
+    #[serde(default)]
+    pub module_sha256: String,
+    #[serde(default)]
+    pub native_modules: Vec,
+    pub size: u64,
+    #[serde(default)]
+    pub control_files: Vec,
+    #[serde(default)]
+    pub dependencies: Vec,
+    #[serde(default)]
+    pub load_order: Vec,
+    #[serde(default)]
+    pub lifecycle: Option,
+    #[serde(default)]
+    pub extension_imports: Vec,
+    #[serde(default)]
+    pub core_exports_required: Vec,
+    #[serde(default)]
+    pub unresolved_imports: Vec,
+    #[serde(default)]
+    pub installed_files: Vec,
+    #[serde(default)]
+    pub link: Option,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct ExtensionLifecycle {
+    pub create_extension: bool,
+    #[serde(default)]
+    pub create_schema: Option,
+    #[serde(default)]
+    pub load_sql: Vec,
+    #[serde(default)]
+    pub post_create_sql: Vec,
+    #[serde(default)]
+    pub startup_config: Vec,
+    #[serde(default)]
+    pub preload_required: bool,
+    #[serde(default)]
+    pub restart_required: bool,
+    #[serde(default)]
+    pub shared_memory_required: bool,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct WasmLinkMetadata {
+    pub has_dylink0: bool,
+    #[serde(default)]
+    pub dylink_needed: Vec,
+    #[serde(default)]
+    pub dylink_runtime_paths: Vec,
+    #[serde(default)]
+    pub dylink_memory: Option,
+    #[serde(default)]
+    pub dylink_imports: Vec,
+    #[serde(default)]
+    pub dylink_exports: Vec,
+    #[serde(default)]
+    pub imports: Vec,
+    #[serde(default)]
+    pub exports: Vec,
+    #[serde(default)]
+    pub memories: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct WasmDylinkMemory {
+    pub memory_size: u32,
+    pub memory_alignment: u32,
+    pub table_size: u32,
+    pub table_alignment: u32,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct WasmDylinkSymbol {
+    pub module: Option,
+    pub name: String,
+    pub flags: u32,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct WasmImport {
+    pub module: String,
+    pub name: String,
+    pub kind: String,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct WasmExport {
+    pub name: String,
+    pub kind: String,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct WasmMemory {
+    pub initial_pages: u64,
+    pub maximum_pages: Option,
+    pub memory64: bool,
+    pub shared: bool,
+    pub page_size_log2: Option,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub struct SourcePin {
+    pub name: String,
+    pub url: String,
+    pub branch: String,
+    pub commit: String,
+}
+
+pub fn manifest() -> Result {
+    serde_json::from_str(MANIFEST_JSON)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn manifest_parses_and_keeps_core_payload_extension_free() {
+        let manifest = manifest().expect("asset manifest should parse");
+        if !HAS_EMBEDDED_ASSETS {
+            assert_eq!(manifest.runtime.runtime_kind, "source-only-template");
+            if SELECTED_EXTENSION_SQL_NAMES.is_empty() {
+                assert!(manifest.extensions.is_empty());
+            }
+            return;
+        }
+        assert_eq!(
+            manifest.runtime.postgres_version.split('.').next(),
+            Some(POSTGRES_MAJOR.to_string().as_str())
+        );
+        assert_eq!(manifest.runtime.runtime_kind, "wasix-dynamic-main");
+        if SELECTED_EXTENSION_SQL_NAMES.is_empty() {
+            assert!(manifest.extensions.is_empty());
+        }
+    }
+}
diff --git a/src/runtimes/liboliphaunt-wasix/moon.yml b/src/runtimes/liboliphaunt-wasix/moon.yml
new file mode 100644
index 000000000..fbab66347
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/moon.yml
@@ -0,0 +1,360 @@
+$schema: https://moonrepo.dev/schemas/project.json
+id: liboliphaunt-wasix
+language: rust
+layer: library
+stack: systems
+tags:
+  - javascript-quality
+  - runtime
+  - wasix
+  - wasm
+  - postgres
+  - release-product
+dependsOn:
+  - id: postgres18
+    scope: build
+  - id: third-party-icu
+    scope: build
+  - id: third-party-openssl
+    scope: build
+  - id: extensions
+    scope: build
+  - id: extension-runtime-contract
+    scope: build
+  - id: oliphaunt-extension-contrib-pg18
+    scope: build
+project:
+  title: liboliphaunt WASIX
+  description: "WASIX PostgreSQL runtime, portable assets, and AOT artifact carriers."
+  owner: oliphaunt
+  release:
+    component: liboliphaunt-wasix
+    packagePath: src/runtimes/liboliphaunt-wasix
+    artifactTargets:
+      preset: liboliphaunt-wasix
+      targets:
+        - portable
+        - linux-arm64-gnu
+        - linux-x64-gnu
+        - macos-arm64
+        - windows-x64-msvc
+owners:
+  defaultOwner: "@oliphaunt/wasix"
+  paths:
+    assets/**:
+      - "@oliphaunt/wasix"
+    crates/**:
+      - "@oliphaunt/wasix"
+    tools/**:
+      - "@oliphaunt/wasix"
+fileGroups:
+  version:
+    - VERSION
+  release-metadata:
+    - VERSION
+    - release.toml
+  crates:
+    - crates/**/*
+  cargo-carrier-sources:
+    - crates/**/*.rs
+    - crates/**/Cargo.toml
+  extension-smoke-inputs:
+    - /src/pgwire-server/Cargo.toml
+    - /src/pgwire-server/tests/extensions.rs
+    - /src/sdks/rust-query/src/lib.rs
+    - /src/test-fixtures/**/*
+    - tools/runtime-smoke.sh
+    - tools/wasix-extension-features.mts
+    - tools/wasix-aot-manifest.mts
+    - tools/wasix-cargo-artifact-contract.mts
+    - "/src/extensions/artifacts/packages/tools/{build-extension-ci-artifacts,contrib-carriers,extension-registry-packages,extension-runtime-asset-contract}.mts"
+    - /tools/packaging/archive-directory.mts
+    - /tools/packaging/cargo-source-package.mts
+    - /src/sdks/swift/tools/ios-carrier-manifest.mts
+    - /tools/packaging/portable-archive.mts
+    - /tools/packaging/release-directory-safety.mts
+    - /tools/packaging/release-notices.mts
+    - "/src/extensions/contracts/{extension-target-profiles,wasix-extension-install}.mts"
+    - /tools/release/platform-compatibility-policy.mts
+    - /tools/release/release-artifact-targets.mts
+    - /tools/release/release-graph.mts
+    - /tools/release/release-history.mts
+    - /src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.mts
+    - /tools/dev/bun.sh
+tasks:
+  build-orchestration-test:
+    tags:
+      - quality
+      - unit
+    script: "set -e\nbash src/runtimes/liboliphaunt-wasix/tools/build-runtime-portable.test.sh\nbash src/runtimes/liboliphaunt-wasix/tools/serialize-aot.test.sh\nbash src/runtimes/liboliphaunt-wasix/assets/build/dependency-prefix.test.sh\n"
+    inputs:
+      - assets/build/dependency-prefix.test.sh
+      - assets/build/build_wasix_geos.sh
+      - assets/build/build_wasix_proj.sh
+      - assets/build/build_wasix_openssl.sh
+      - assets/build/build_wasix_sqlite.sh
+      - assets/build/wasix_third_party.sh
+      - assets/build/profile_flags.sh
+      - tools/build-compiler-output.sh
+      - tools/build-runtime-portable.sh
+      - tools/build-runtime-portable.test.sh
+      - tools/extension-build-scripts.mts
+      - tools/serialize-aot.sh
+      - tools/serialize-aot.test.sh
+    options:
+      runFromWorkspaceRoot: true
+  test:
+    tags:
+      - quality
+      - unit
+    script: "set -e\nbash src/runtimes/liboliphaunt-wasix/tools/check-shim-abi.sh\nbash src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-apt-packages.test.sh\nbash src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.test.sh\n"
+    inputs:
+      - assets/build/docker/**/*
+      - assets/build/wasix_shim/**/*
+      - tools/check-shim-abi.sh
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  lint:
+    tags:
+      - quality
+      - static
+    script: "set -e\nwhile IFS= read -r -d '' script; do bash -n \"$script\"; done < <(find src/runtimes/liboliphaunt-wasix -type f \\( -name '*.sh' -o -name '*.bash' \\) -print0)\n"
+    inputs:
+      - "**/*.sh"
+      - "**/*.bash"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  compiler-output:
+    tags:
+      - runtime
+      - artifact
+    command: bash src/runtimes/liboliphaunt-wasix/tools/build-compiler-output.sh
+    deps:
+      - source-inputs:source-fetch-wasix-runtime
+    inputs:
+      - "@group(legal-files)"
+      - "@group(cargo-workspace)"
+      - /src/sdks/rust-wasix/THIRD_PARTY_NOTICES.md
+      - "@group(upstream-licenses)"
+      - project: postgres18
+        group: source
+      - /src/runtimes/liboliphaunt-wasix/toolchain.toml
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - project: extensions
+        group: build
+      - project: extension-runtime-contract
+        group: contract
+      - assets/build/**/*
+      - postgres/**/*
+      - /src/third-party/postgres/**/*
+      - "!/src/third-party/postgres/**/*.test.*"
+      - "!/src/third-party/postgres/testdata/**/*"
+      - tools/build-compiler-output.sh
+      - tools/extension-build-scripts.mts
+      - "!assets/generated"
+      - "!assets/generated/**"
+      - /src/sdks/rust-wasix/Cargo.toml
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/**/*
+      - "@group(release-archive-contract)"
+      - /src/runtimes/liboliphaunt-wasix/tools/verify-source-tree.mts
+    outputs:
+      - /target/oliphaunt-wasix/wasix-build/build/install/**/*
+      - /target/oliphaunt-wasix/wasix-build/work/docker-oliphaunt/**/*
+    options:
+      # Container Makefiles link to /work; keep this incremental build tree local
+      # to the compiler. Docker owns its cache; portable artifacts retain Moon CAS.
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  runtime-portable:
+    tags:
+      - runtime
+      - artifact
+      - ci-liboliphaunt-wasix-runtime
+    command: bash src/runtimes/liboliphaunt-wasix/tools/build-runtime-portable.sh --package-only
+    deps:
+      - liboliphaunt-wasix:compiler-output
+    inputs:
+      - "@group(legal-files)"
+      - "@group(cargo-workspace)"
+      - "@group(release-archive-contract)"
+      - /src/sdks/rust-wasix/THIRD_PARTY_NOTICES.md
+      - "@group(upstream-licenses)"
+      - tools/build-runtime-portable.sh
+      - tools/xtask/**/*
+    outputs:
+      - /target/oliphaunt-wasix/wasix-build/build/package-stage/**/*
+      - /target/oliphaunt-wasix/assets/**/*
+      - /src/runtimes/liboliphaunt-wasix/assets/generated/**/*
+    options:
+      cache: local
+      runFromWorkspaceRoot: true
+      runInCI: true
+  runtime-aot:
+    tags:
+      - runtime
+      - artifact
+      - ci-liboliphaunt-wasix-aot
+    command: bash src/runtimes/liboliphaunt-wasix/tools/build-aot-target.sh
+    deps:
+      - liboliphaunt-wasix:runtime-portable
+    inputs:
+      - "@group(legal-files)"
+      - "@group(cargo-workspace)"
+      - "@group(upstream-licenses)"
+      - project: postgres18
+        group: source
+      - /src/runtimes/liboliphaunt-wasix/toolchain.toml
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - project: extensions
+        group: build
+      - project: extension-runtime-contract
+        group: contract
+      - tools/build-aot-target.sh
+      - tools/serialize-aot.sh
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/**/*
+      - "@group(release-archive-contract)"
+      - /src/runtimes/liboliphaunt-wasix/tools/verify-source-tree.mts
+    outputs:
+      - /target/oliphaunt-wasix/aot/**/*
+      - /src/runtimes/liboliphaunt-wasix/crates/aot/*/artifacts/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  release-assets:
+    tags:
+      - release
+      - artifact
+      - ci-liboliphaunt-wasix-release-assets
+    command: bun src/runtimes/liboliphaunt-wasix/tools/package-release-assets.mts
+    deps:
+      - liboliphaunt-wasix:runtime-portable
+      - liboliphaunt-wasix:runtime-aot
+    inputs:
+      - "@group(legal-files)"
+      - "@group(cargo-workspace)"
+      - /src/sdks/rust-wasix/THIRD_PARTY_NOTICES.md
+      - /src/third-party/postgres/source.toml
+      - "@group(upstream-licenses)"
+      - assets/generated/**/*
+      - crates/**/*
+      - /src/third-party/icu/source.toml
+      - /src/sdks/rust-wasix/Cargo.toml
+      - /src/runtimes/liboliphaunt-wasix/crates/assets/**/*
+      - /src/runtimes/liboliphaunt-wasix/crates/aot/**/*
+      - tools/package-release-assets.mts
+      - tools/wasix-cargo-artifact-contract.mts
+      - tools/wasix-aot-manifest.mts
+      - /tools/packaging/**/*.mts
+      - /src/database-resources/contracts/*.mts
+      - /tools/release/**/*.mts
+      - assets/build/postgres/patches/**/*
+      - postgres/**/*
+      - /src/third-party/postgres/**/*
+      - "!/src/third-party/postgres/**/*.test.*"
+      - "!/src/third-party/postgres/testdata/**/*"
+      - /src/runtimes/liboliphaunt-wasix/tools/check-release-assets.mts
+      - "@group(release-archive-contract)"
+      - /src/runtimes/liboliphaunt-wasix/tools/verify-source-tree.mts
+      - /target/oliphaunt-wasix/wasix-build/build/**/*
+      - /target/oliphaunt-wasix/wasix-build/work/icu-wasix/share/icu/**/*
+      - /target/oliphaunt-wasix/assets/**/*
+      - /target/oliphaunt-wasix/aot/**/*
+    outputs:
+      - /target/oliphaunt-wasix/release-assets/**/*
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+  smoke:
+    tags:
+      - runtime
+      - smoke
+    command: bash src/runtimes/liboliphaunt-wasix/tools/runtime-smoke.sh
+    deps:
+      - liboliphaunt-wasix:runtime-aot
+    inputs:
+      - "@group(extension-smoke-inputs)"
+      - "@group(cargo-workspace)"
+      - project: postgres18
+        group: source
+      - /src/runtimes/liboliphaunt-wasix/toolchain.toml
+      - project: third-party-icu
+        group: sources
+      - project: third-party-openssl
+        group: sources
+      - project: extensions
+        group: build
+      - tools/cargo-test-filter.sh
+      - tools/runtime-preflight.sh
+      - tools/runtime-smoke.sh
+      - /src/sdks/rust-wasix/**/*
+      - /src/runtimes/liboliphaunt-wasix/tools/runtime-preflight.sh
+      - /src/runtimes/liboliphaunt-wasix/tools/xtask/**/*
+      - /src/runtimes/liboliphaunt-wasix/tools/verify-source-tree.mts
+    options:
+      cache: local
+      runFromWorkspaceRoot: true
+      runInCI: false
+  rust-format-check:
+    tags:
+      - quality
+      - static
+      - format
+      - requires-rust
+    command: cargo fmt -p liboliphaunt-wasix-portable -p liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu -p liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu -p liboliphaunt-wasix-aot-aarch64-apple-darwin -p liboliphaunt-wasix-aot-x86_64-pc-windows-msvc --check
+    inputs:
+      - "@group(cargo-carrier-sources)"
+      - "@group(cargo-workspace)"
+    options:
+      runFromWorkspaceRoot: true
+  rust-lint:
+    tags:
+      - quality
+      - static
+      - requires-rust
+    command: cargo clippy -p liboliphaunt-wasix-portable -p liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu -p liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu -p liboliphaunt-wasix-aot-aarch64-apple-darwin -p liboliphaunt-wasix-aot-x86_64-pc-windows-msvc --all-targets --locked -- -D warnings
+    env:
+      CARGO_TARGET_DIR: target
+    inputs:
+      - "@group(cargo-carrier-sources)"
+      - "@group(cargo-workspace)"
+      - /clippy.toml
+    options:
+      runFromWorkspaceRoot: true
+  packaging-unit:
+    tags:
+      - quality
+      - unit
+      - requires-rust
+    command: bash src/runtimes/liboliphaunt-wasix/tools/test-packaging.sh
+    inputs:
+      - "@group(crates)"
+      - tools/*.sh
+      - /src/extensions/tools/extension-upstream-licenses.mts
+      - /src/extensions/external/**/upstream-license-data.json
+      - /src/extensions/external/**/upstream-licenses/**/*
+      - /src/database-resources/contracts/*.mts
+      - "@group(upstream-licenses)"
+      - THIRD_PARTY_NOTICES.md
+      - "@group(legal-files)"
+      - "@group(release-target-contract)"
+      - "@group(package-test-metadata)"
+      - "**/*.{mjs,mts}"
+      - /tools/packaging/testdata/**/*
+      - /tools/dev/bun.sh
+      - "/tools/packaging/*.{mts,sh}"
+      - /src/database-resources/contracts/*.mts
+      - "/tools/release/*.{mjs,mts}"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/runtimes/liboliphaunt-wasix/postgres/series b/src/runtimes/liboliphaunt-wasix/postgres/series
new file mode 100644
index 000000000..a54817ebb
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/postgres/series
@@ -0,0 +1,44 @@
+# PostgreSQL 18.4. Ordered repository-relative patch paths.
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0002-oliphaunt-wasix-add-backend-host-io-hooks.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0003-oliphaunt-wasix-export-startup-packet-parser.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0004-oliphaunt-wasix-add-host-lifecycle-exports.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0006-oliphaunt-wasix-report-copy-protocol-state.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0009-oliphaunt-wasix-route-process-identity-through-port.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0011-oliphaunt-wasix-prefer-posix-semaphores.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0012-oliphaunt-wasix-capture-startup-errors.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch
+src/third-party/postgres/patches/wasix/0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch
+src/third-party/postgres/patches/wasix/0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch
+src/third-party/postgres/patches/wasix/0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch
+src/third-party/postgres/patches/wasix/0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0021-oliphaunt-wasix-declare-wasix-fork.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch
+src/third-party/postgres/patches/wasix/0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch
+src/third-party/postgres/patches/wasix/0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0029-oliphaunt-wasix-set-embedded-postmaster-environment.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0030-oliphaunt-wasix-avoid-xlogwrite-prevseg-division.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0031-oliphaunt-wasix-skip-activity-id-reporting.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch
+src/third-party/postgres/patches/common/control-initdb-collation-discovery.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0035-oliphaunt-wasix-use-single-backend-spinlocks.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0036-oliphaunt-wasix-specialize-single-backend-atomics.patch
+src/third-party/postgres/patches/wasix/0037-oliphaunt-wasix-buffer-strong-random.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0039-oliphaunt-wasix-inline-sigsetjmp.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch
+src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch
diff --git a/src/runtimes/liboliphaunt-wasix/release.toml b/src/runtimes/liboliphaunt-wasix/release.toml
new file mode 100644
index 000000000..03506eedd
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/release.toml
@@ -0,0 +1,16 @@
+id = "liboliphaunt-wasix"
+owner = "@oliphaunt/wasix"
+kind = "wasm-runtime"
+publish_targets = ["github-release-assets", "crates-io", "npm"]
+registry_packages = [
+  "crates:liboliphaunt-wasix-portable",
+  "crates:liboliphaunt-wasix-aot-aarch64-apple-darwin",
+  "crates:liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu",
+  "crates:liboliphaunt-wasix-aot-x86_64-pc-windows-msvc",
+  "crates:liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu",
+  "npm:@oliphaunt/liboliphaunt-wasix",
+  "npm:@oliphaunt/wasix-icu",
+]
+release_artifacts = [
+  "release-assets",
+]
diff --git a/src/runtimes/liboliphaunt-wasix/toolchain.toml b/src/runtimes/liboliphaunt-wasix/toolchain.toml
new file mode 100644
index 000000000..78ddde979
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/toolchain.toml
@@ -0,0 +1,4 @@
+[toolchain]
+wasmer = "7.2.1"
+wasmer-wasix = "0.702.1"
+webc = "12.0.0"
diff --git a/src/runtimes/liboliphaunt-wasix/tools/build-aot-target.sh b/src/runtimes/liboliphaunt-wasix/tools/build-aot-target.sh
new file mode 100755
index 000000000..aa6915681
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/build-aot-target.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "unable to determine repository root from $script_dir; run this script from a Git checkout" >&2
+  exit 1
+}
+[ -f "$root/package.json" ] && [ -d "$root/src/runtimes/liboliphaunt-wasix" ] || {
+  echo "must run inside the Oliphaunt workspace" >&2
+  exit 1
+}
+cd "$root"
+
+target="${AOT_TARGET:-${1:-}}"
+if [ -z "$target" ]; then
+  target="$(rustc -vV | awk '/^host:/{print $2}')"
+fi
+host="$(rustc -vV | awk '/^host:/{print $2}')"
+if [ "$target" != "$host" ]; then
+  echo "target AOT execution requires the builder host $host to match AOT target $target" >&2
+  exit 1
+fi
+
+bash src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh --target-triple "$target"
+cargo run -p xtask -- assets package-aot --target-triple "$target"
+cargo run -p xtask -- assets check-aot --target-triple "$target"
diff --git a/src/runtimes/liboliphaunt-wasix/tools/build-compiler-output.sh b/src/runtimes/liboliphaunt-wasix/tools/build-compiler-output.sh
new file mode 100755
index 000000000..a123413fb
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/build-compiler-output.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "unable to determine repository root from $script_dir; run this script from a Git checkout" >&2
+  exit 1
+}
+[ -f "$root/package.json" ] && [ -d "$root/src/runtimes/liboliphaunt-wasix" ] || {
+  echo "must run inside the Oliphaunt workspace" >&2
+  exit 1
+}
+cd "$root"
+
+asset_profile="${ASSET_PROFILE:-release}"
+image="${IMAGE:-oliphaunt-wasix-wasix-build:local}"
+export IMAGE="$image"
+if [ -z "${DOCKER_CONFIG:-}" ]; then
+  docker_config="$root/target/docker/public-config"
+  mkdir -p "$docker_config"
+  [ -f "$docker_config/config.json" ] || printf '{}\n' >"$docker_config/config.json"
+  if [ -d "$HOME/.docker/cli-plugins" ]; then
+    mkdir -p "$docker_config/cli-plugins"
+    for plugin in "$HOME/.docker/cli-plugins/"*; do
+      [ -e "$plugin" ] || continue
+      ln -sf "$plugin" "$docker_config/cli-plugins/$(basename "$plugin")"
+    done
+  fi
+  export DOCKER_CONFIG="$docker_config"
+fi
+export DOCKER_BUILDKIT="${DOCKER_BUILDKIT:-1}"
+
+export OLIPHAUNT_WASM_BUILD_PROFILE="$asset_profile"
+bash src/third-party/tools/fetch-sources.sh wasix-runtime --verify-only
+bash src/runtimes/liboliphaunt-wasix/assets/build/prepare_postgres_source.sh >/dev/null
+build=src/runtimes/liboliphaunt-wasix/assets/build
+if [ "${OLIPHAUNT_SKIP_BUILD:-0}" != "1" ]; then
+  for script in docker_oliphaunt docker_runtime_support docker_initdb; do
+    bash "$build/$script.sh"
+  done
+fi
+awk -v profile="$asset_profile" '$0 == "profile=" profile {found=1} END {exit !found}' \
+  target/oliphaunt-wasix/wasix-build/work/docker-oliphaunt/.oliphaunt-wasix-build-profile
+cargo run -p xtask -- assets stage-runtime
diff --git a/src/runtimes/liboliphaunt-wasix/tools/build-runtime-portable.sh b/src/runtimes/liboliphaunt-wasix/tools/build-runtime-portable.sh
new file mode 100755
index 000000000..3c3ca2963
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/build-runtime-portable.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "unable to determine repository root from $script_dir; run this script from a Git checkout" >&2
+  exit 1
+}
+[ -f "$root/package.json" ] && [ -d "$root/src/runtimes/liboliphaunt-wasix" ] || {
+  echo "must run inside the Oliphaunt workspace" >&2
+  exit 1
+}
+cd "$root"
+
+case "${1:-}" in
+  "") bash "$script_dir/build-compiler-output.sh" ;;
+  --package-only) ;;
+  *) echo "usage: ${0##*/} [--package-only]" >&2; exit 2 ;;
+esac
+cargo run -p xtask -- assets package --skip-aot
+cargo run -p xtask -- assets check --strict-generated
diff --git a/src/runtimes/liboliphaunt-wasix/tools/build-runtime-portable.test.sh b/src/runtimes/liboliphaunt-wasix/tools/build-runtime-portable.test.sh
new file mode 100755
index 000000000..233bbef0d
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/build-runtime-portable.test.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+set -euo pipefail
+script="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/build-runtime-portable.sh"
+fixture="$(mktemp -d)"
+trap 'rm -rf "$fixture"' EXIT
+git -C "$fixture" init -q
+owner=src/runtimes/liboliphaunt-wasix
+mkdir -p "$fixture/$owner/tools" "$fixture/$owner/assets/build" "$fixture/bin"
+cp "$script" "$(dirname "$script")/build-compiler-output.sh" "$fixture/$owner/tools/"
+touch "$fixture/package.json"
+mkdir -p "$fixture/src/third-party/tools"
+printf 'echo verify-sources >> "$BUILD_LOG"\n' > "$fixture/src/third-party/tools/fetch-sources.sh"
+export BUILD_LOG="$fixture/log" DOCKER_CONFIG="$fixture/docker" ASSET_PROFILE=release
+export OLIPHAUNT_SKIP_BUILD=0
+export PATH="$fixture/bin:$PATH"
+cat > "$fixture/bin/cargo" <<'CARGO'
+#!/usr/bin/env bash
+printf 'cargo %s\n' "$*" >> "$BUILD_LOG"
+CARGO
+chmod +x "$fixture/bin/"*
+for name in prepare_postgres_source docker_oliphaunt docker_runtime_support docker_initdb ; do
+  cat > "$fixture/$owner/assets/build/$name.sh" <<'BUILD'
+#!/usr/bin/env bash
+name="${0##*/}"
+printf '%s\n' "${name%.sh}" >> "$BUILD_LOG"
+[ "${FAIL_BUILD:-}" != "${name%.sh}" ] || exit 9
+BUILD
+done
+receipt="$fixture/target/oliphaunt-wasix/wasix-build/work/docker-oliphaunt/.oliphaunt-wasix-build-profile"
+mkdir -p "$(dirname "$receipt")"
+echo profile=release > "$receipt"
+bash "$fixture/$owner/tools/build-runtime-portable.sh"
+cat > "$fixture/expected" <<'EXPECTED'
+verify-sources
+prepare_postgres_source
+docker_oliphaunt
+docker_runtime_support
+docker_initdb
+cargo run -p xtask -- assets stage-runtime
+cargo run -p xtask -- assets package --skip-aot
+cargo run -p xtask -- assets check --strict-generated
+EXPECTED
+diff -u "$fixture/expected" "$BUILD_LOG"
+: > "$BUILD_LOG"
+if FAIL_BUILD=docker_runtime_support bash "$fixture/$owner/tools/build-runtime-portable.sh"; then exit 1; fi
+[ "$(tail -1 "$BUILD_LOG")" = docker_runtime_support ]
+: > "$BUILD_LOG"
+bash "$fixture/$owner/tools/build-runtime-portable.sh" --package-only
+[ "$(wc -l < "$BUILD_LOG" | tr -d ' ')" = 2 ]
+[ "$(head -1 "$BUILD_LOG")" = 'cargo run -p xtask -- assets package --skip-aot' ]
+: > "$BUILD_LOG"
+echo profile=debug > "$receipt"
+if OLIPHAUNT_SKIP_BUILD=1 bash "$fixture/$owner/tools/build-runtime-portable.sh"; then exit 1; fi
+[ "$(tail -1 "$BUILD_LOG")" = prepare_postgres_source ]
+echo 'WASIX build order, core-only selection, failure propagation, and stale-profile refusal passed.'
diff --git a/src/runtimes/liboliphaunt-wasix/tools/cargo-test-filter.sh b/src/runtimes/liboliphaunt-wasix/tools/cargo-test-filter.sh
new file mode 100755
index 000000000..96f63e932
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/cargo-test-filter.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+# Cargo treats a test-name filter that matches nothing as success. Runtime
+# smoke lanes must actually select tests, without coupling to a suite's size.
+oliphaunt_require_cargo_test_filter() {
+  local filter="$1"
+  shift
+
+  local listed_tests
+  local test_count
+  listed_tests="$("$@" -- --list)" || return
+  test_count="$(awk -v filter="$filter" '
+    index($0, filter) && /: test$/ { count += 1 }
+    END { print count + 0 }
+  ' <<<"$listed_tests")"
+  if [ "$test_count" -eq 0 ]; then
+    printf '%s\n' "$listed_tests" >&2
+    echo "no tests match $filter" >&2
+    return 1
+  fi
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/check-release-assets.mts b/src/runtimes/liboliphaunt-wasix/tools/check-release-assets.mts
new file mode 100644
index 000000000..94b0636af
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/check-release-assets.mts
@@ -0,0 +1,645 @@
+#!/usr/bin/env bun
+import { createHash } from 'node:crypto';
+import { existsSync, lstatSync, readdirSync, readFileSync } from 'node:fs';
+import path from 'node:path';
+import {
+  DEFAULT_PORTABLE_ARCHIVE_LIMITS,
+  decompressSingleZstdFrame,
+  portableMemberName,
+  readPortableArchiveEntries,
+  readPortableTarZstdBufferEntries,
+} from '../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInEntries,
+  releaseNoticeRows,
+} from '../../../../tools/packaging/release-notices.mts';
+import {
+  compareText,
+  currentProductVersionSync,
+  expectedAssetRows,
+  ROOT,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { assertCanonicalWasixAotManifest } from './wasix-aot-manifest.mts';
+import {
+  AOT_TARGET_TRIPLES,
+  CORE_RUNTIME_ARCHIVE_FILES,
+} from './wasix-cargo-artifact-contract.mts';
+import { WASIX_PORTABLE_RELEASE_MEMBERS } from './wasix-runtime-npm-contract.mts';
+
+const TOOL = 'check-liboliphaunt-wasix-release-assets.mts';
+const PRODUCT = 'liboliphaunt-wasix';
+const DEFAULT_ASSET_DIR = 'target/oliphaunt-wasix/release-assets';
+const PORTABLE_RUNTIME_ARCHIVE_MEMBER = WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive;
+const PORTABLE_MANIFEST_MEMBER = WASIX_PORTABLE_RELEASE_MEMBERS.manifest;
+const FORBIDDEN_PORTABLE_ASSET_MEMBERS = new Set([
+  'target/oliphaunt-wasix/assets/bin/pg_ctl.wasix.wasm',
+]);
+const CORE_RUNTIME_MEMBERS = new Set(CORE_RUNTIME_ARCHIVE_FILES);
+const FORBIDDEN_RUNTIME_MEMBERS = new Set([
+  'oliphaunt/bin/pg_ctl',
+  'oliphaunt/bin/pg_dump',
+  'oliphaunt/bin/psql',
+]);
+const LOWER_SHA256 = /^[0-9a-f]{64}$/u;
+const UTF8 = new TextDecoder('utf-8', { fatal: true });
+
+function fail(message) {
+  throw new Error(`${TOOL}: ${message}`);
+}
+
+function rel(file) {
+  const relative = path.relative(ROOT, String(file));
+  if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
+    return String(file).split(path.sep).join('/');
+  }
+  return relative.split(path.sep).join('/');
+}
+
+function isFile(file) {
+  try {
+    const metadata = lstatSync(file);
+    return metadata.isFile() && !metadata.isSymbolicLink();
+  } catch {
+    return false;
+  }
+}
+
+function isDirectory(file) {
+  try {
+    const metadata = lstatSync(file);
+    return metadata.isDirectory() && !metadata.isSymbolicLink();
+  } catch {
+    return false;
+  }
+}
+
+function sha256File(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function sha256Bytes(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function readArchiveJsonEntry(entries, member, archive) {
+  const entry = entries.get(member);
+  if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) {
+    fail(`${rel(archive)} must contain ${member} as one non-empty regular file`);
+  }
+  let data;
+  try {
+    data = UTF8.decode(entry.data());
+  } catch {
+    fail(`${rel(archive)} ${member} is not valid UTF-8`);
+  }
+  try {
+    return JSON.parse(data);
+  } catch (error) {
+    fail(`${rel(archive)} ${member} is not valid JSON: ${error.message}`);
+  }
+}
+
+function checkedSha256(value, context) {
+  if (typeof value !== 'string' || !LOWER_SHA256.test(value)) {
+    throw new Error(`${context} must be a lowercase SHA-256 digest`);
+  }
+  return value;
+}
+
+function checkedAotArtifactName(value, context) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value !== value.trim() ||
+    value !== value.normalize('NFC') ||
+    Buffer.byteLength(value, 'utf8') > 255 ||
+    /[\u0000-\u001f\u007f/\\]/u.test(value)
+  ) {
+    throw new Error(`${context} name must be a normalized portable non-empty string`);
+  }
+  return value;
+}
+
+export function assertWasixAotArtifactPayloads(
+  manifest,
+  {
+    context = 'WASIX AOT manifest',
+    readArtifact,
+    maxRawBytes = DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntryBytes,
+  } = {},
+) {
+  if (!Array.isArray(manifest?.artifacts) || manifest.artifacts.length === 0) {
+    throw new Error(`${context} must contain a non-empty artifacts array`);
+  }
+  if (typeof readArtifact !== 'function') {
+    throw new Error(`${context} requires an artifact byte reader`);
+  }
+  if (!Number.isSafeInteger(maxRawBytes) || maxRawBytes <= 0) {
+    throw new Error(`${context} maxRawBytes must be a positive safe integer`);
+  }
+
+  const expectedKeys = [
+    'compressed',
+    'module-sha256',
+    'name',
+    'path',
+    'raw-sha256',
+    'raw-size',
+    'sha256',
+  ];
+  const names = new Set();
+  const portableNames = new Map();
+  const paths = new Set();
+  const portablePaths = new Map();
+  const rows = [];
+  for (const [index, artifact] of manifest.artifacts.entries()) {
+    const artifactContext = `${context} artifact[${index}]`;
+    if (artifact === null || Array.isArray(artifact) || typeof artifact !== 'object') {
+      throw new Error(`${artifactContext} must be an object`);
+    }
+    const actualKeys = Object.keys(artifact).sort(compareText);
+    if (JSON.stringify(actualKeys) !== JSON.stringify(expectedKeys)) {
+      throw new Error(
+        `${artifactContext} metadata fields must be exactly ${JSON.stringify(expectedKeys)}, got ${JSON.stringify(actualKeys)}`,
+      );
+    }
+    const name = checkedAotArtifactName(artifact.name, artifactContext);
+    if (names.has(name)) throw new Error(`${context} repeats AOT artifact name ${name}`);
+    names.add(name);
+    const portableName = name.toLowerCase();
+    const priorName = portableNames.get(portableName);
+    if (priorName !== undefined) {
+      throw new Error(`${context} has case-colliding AOT artifact names ${priorName} and ${name}`);
+    }
+    portableNames.set(portableName, name);
+
+    if (typeof artifact.path !== 'string' || artifact.path.length === 0) {
+      throw new Error(`${artifactContext} path must be a non-empty string`);
+    }
+    let artifactPath;
+    try {
+      artifactPath = portableMemberName(artifact.path, 'file', artifactContext);
+    } catch (error) {
+      throw new Error(error.message);
+    }
+    if (artifactPath !== artifact.path) {
+      throw new Error(
+        `${artifactContext} path must already be normalized, got ${JSON.stringify(artifact.path)}`,
+      );
+    }
+    if (paths.has(artifactPath))
+      throw new Error(`${context} repeats AOT artifact path ${artifactPath}`);
+    paths.add(artifactPath);
+    const portablePath = artifactPath.toLowerCase();
+    const priorPath = portablePaths.get(portablePath);
+    if (priorPath !== undefined) {
+      throw new Error(
+        `${context} has case-colliding AOT artifact paths ${priorPath} and ${artifactPath}`,
+      );
+    }
+    portablePaths.set(portablePath, artifactPath);
+
+    const sha256 = checkedSha256(artifact.sha256, `${artifactContext} sha256`);
+    const rawSha256 = checkedSha256(artifact['raw-sha256'], `${artifactContext} raw-sha256`);
+    checkedSha256(artifact['module-sha256'], `${artifactContext} module-sha256`);
+    const rawSize = artifact['raw-size'];
+    if (!Number.isSafeInteger(rawSize) || rawSize <= 0 || rawSize > maxRawBytes) {
+      throw new Error(`${artifactContext} raw-size must be an integer in 1..${maxRawBytes}`);
+    }
+    if (typeof artifact.compressed !== 'boolean') {
+      throw new Error(`${artifactContext} compressed must be a Boolean`);
+    }
+    if (artifact.compressed !== artifactPath.endsWith('.zst')) {
+      throw new Error(`${artifactContext} compressed metadata must match the .zst path suffix`);
+    }
+
+    const value = readArtifact(artifactPath, artifact);
+    if (!Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
+      throw new Error(`${artifactContext} byte reader did not return a Buffer or Uint8Array`);
+    }
+    const bytes = Buffer.isBuffer(value)
+      ? value
+      : Buffer.from(value.buffer, value.byteOffset, value.byteLength);
+    if (bytes.length <= 0 || bytes.length > DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntryBytes) {
+      throw new Error(`${artifactContext} must reference a non-empty bounded regular file`);
+    }
+    const actualSha256 = sha256Bytes(bytes);
+    if (actualSha256 !== sha256) {
+      throw new Error(
+        `${artifactContext} compressed SHA-256 mismatch: expected ${sha256}, got ${actualSha256}`,
+      );
+    }
+    const raw = artifact.compressed
+      ? decompressSingleZstdFrame(bytes, {
+          label: `${artifactContext} ${artifactPath}`,
+          maxInputBytes: DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntryBytes,
+          maxOutputBytes: rawSize,
+        })
+      : bytes;
+    if (raw.length !== rawSize) {
+      throw new Error(
+        `${artifactContext} raw-size mismatch: expected ${rawSize}, got ${raw.length}`,
+      );
+    }
+    const actualRawSha256 = sha256Bytes(raw);
+    if (actualRawSha256 !== rawSha256) {
+      throw new Error(
+        `${artifactContext} raw SHA-256 mismatch: expected ${rawSha256}, got ${actualRawSha256}`,
+      );
+    }
+    rows.push(Object.freeze({ artifact, bytes, name, path: artifactPath, raw }));
+  }
+  return Object.freeze(rows);
+}
+
+function expectedParentDirs(paths) {
+  const parents = new Set();
+  for (const item of paths) {
+    const parts = item.split('/');
+    for (let index = 1; index < parts.length; index += 1) {
+      parents.add(parts.slice(0, index).join('/'));
+    }
+  }
+  return parents;
+}
+
+export function expectedReleaseNoticeFiles(profile, prefix = '') {
+  const marker = prefix ? `${prefix}/` : '';
+  return new Set(releaseNoticeRows({ profile }).map((row) => `${marker}${row.member}`));
+}
+
+export function unexpectedTreeMembers(members, expectedMembers) {
+  const expected = new Set(expectedMembers);
+  for (const parent of expectedParentDirs(expected)) expected.add(parent);
+  return [...members].filter((member) => !expected.has(member)).sort(compareText);
+}
+
+export function assertWasixReleaseNoticeEntries(entries, profile, prefix = '') {
+  return assertReleaseNoticesInEntries(entries, { prefix, profile });
+}
+
+function checkedWasixArchiveEntries(archive, profile, prefix = '') {
+  const entries = readPortableArchiveEntries(archive);
+  assertWasixReleaseNoticeEntries(entries, profile, prefix);
+  return entries;
+}
+
+function parseChecksumManifest(file) {
+  const checksums = new Map();
+  for (const [index, rawLine] of readFileSync(file, 'utf8').split(/\r?\n/u).entries()) {
+    const line = rawLine.trim();
+    if (!line) {
+      continue;
+    }
+    const match = line.match(/^([0-9a-f]{64})  \.\/([^/]+)$/u);
+    if (match === null) {
+      fail(`${rel(file)}:${index + 1} must use '  ./' entries`);
+    }
+    const [, sha256, assetName] = match;
+    if (checksums.has(assetName)) {
+      fail(`${rel(file)}:${index + 1} declares duplicate checksum for ${assetName}`);
+    }
+    checksums.set(assetName, sha256);
+  }
+  return checksums;
+}
+
+function expectedAssetNames(version) {
+  return expectedAssetRows({ product: PRODUCT, version }, TOOL)
+    .map((row) => row.assetName)
+    .sort(compareText);
+}
+
+export function exactRegularAssetDirectoryNames(assetDir) {
+  const entries = readdirSync(assetDir, { withFileTypes: true });
+  const invalid = entries
+    .filter((entry) => !entry.isFile() || entry.isSymbolicLink())
+    .map((entry) => entry.name)
+    .sort(compareText);
+  if (invalid.length > 0) {
+    fail(
+      `${PRODUCT} staged release asset directory must contain only regular non-symlink files: ${invalid.join(', ')}`,
+    );
+  }
+  return entries.map((entry) => entry.name).sort(compareText);
+}
+
+function validateAssetSet(assetDir, version) {
+  const expected = new Set(expectedAssetNames(version));
+  const actual = new Set(exactRegularAssetDirectoryNames(assetDir));
+  if (
+    JSON.stringify([...actual].sort(compareText)) !==
+    JSON.stringify([...expected].sort(compareText))
+  ) {
+    fail(
+      `${PRODUCT} staged release assets must match release metadata exactly: ` +
+        `expected=${JSON.stringify([...expected].sort(compareText))}, actual=${JSON.stringify([...actual].sort(compareText))}`,
+    );
+  }
+
+  const checksumName = `${PRODUCT}-${version}-release-assets.sha256`;
+  const checksumPath = path.join(assetDir, checksumName);
+  if (!isFile(checksumPath)) {
+    fail(`${PRODUCT} staged release assets are missing checksum manifest ${checksumName}`);
+  }
+  const checksums = parseChecksumManifest(checksumPath);
+  const expectedChecksumAssets = new Set([...expected].filter((name) => name !== checksumName));
+  const actualChecksumAssets = new Set(checksums.keys());
+  if (
+    JSON.stringify([...actualChecksumAssets].sort(compareText)) !==
+    JSON.stringify([...expectedChecksumAssets].sort(compareText))
+  ) {
+    fail(
+      `${PRODUCT} checksum manifest must cover release assets exactly: ` +
+        `expected=${JSON.stringify([...expectedChecksumAssets].sort(compareText))}, ` +
+        `actual=${JSON.stringify([...actualChecksumAssets].sort(compareText))}`,
+    );
+  }
+  for (const [assetName, expectedSha] of checksums) {
+    const actualSha = sha256File(path.join(assetDir, assetName));
+    if (actualSha !== expectedSha) {
+      fail(`${PRODUCT} release asset ${assetName} checksum mismatch`);
+    }
+  }
+}
+
+export function validatePortableReleaseAsset(archive) {
+  const entries = checkedWasixArchiveEntries(archive, 'wasix-runtime');
+  const members = new Set(entries.keys());
+  const extensionMembers = [...members]
+    .filter((member) => member.startsWith('target/oliphaunt-wasix/assets/extensions/'))
+    .sort(compareText);
+  if (extensionMembers.length > 0) {
+    fail(
+      `${rel(archive)} must not contain extension payloads: ${extensionMembers.slice(0, 5).join(', ')}`,
+    );
+  }
+  const forbiddenPortableMembers = [...members]
+    .filter((member) => FORBIDDEN_PORTABLE_ASSET_MEMBERS.has(member))
+    .sort(compareText);
+  if (forbiddenPortableMembers.length > 0) {
+    fail(
+      `${rel(archive)} must not contain WASIX pg_ctl payloads: ${forbiddenPortableMembers.join(', ')}`,
+    );
+  }
+
+  const manifest = readArchiveJsonEntry(entries, PORTABLE_MANIFEST_MEMBER, archive);
+  if (
+    Object.hasOwn(manifest, 'cluster-seeds') ||
+    [...members].some((member) => member.startsWith('target/oliphaunt-wasix/assets/cluster-seeds/'))
+  ) {
+    fail(`${rel(archive)} must not bundle independently packaged cluster seeds`);
+  }
+  if (JSON.stringify(manifest.extensions) !== '[]') {
+    fail(`${rel(archive)} asset manifest must contain an empty extensions array`);
+  }
+  for (const key of ['pg-dump', 'psql']) {
+    if (Object.hasOwn(manifest, key)) {
+      fail(`${rel(archive)} asset manifest must not contain split WASIX tool entry ${key}`);
+    }
+  }
+
+  const icuSidecarMembers = [...members]
+    .filter(
+      (member) =>
+        member === 'target/oliphaunt-wasix/icu' || member.startsWith('target/oliphaunt-wasix/icu/'),
+    )
+    .sort(compareText);
+  if (icuSidecarMembers.length > 0) {
+    fail(
+      `${rel(archive)} must not contain ICU data sidecar files: ${icuSidecarMembers.slice(0, 5).join(', ')}`,
+    );
+  }
+
+  if (
+    manifest.runtime === null ||
+    Array.isArray(manifest.runtime) ||
+    typeof manifest.runtime !== 'object'
+  ) {
+    fail(`${rel(archive)} asset manifest must contain runtime metadata`);
+  }
+  if (manifest.runtime.archive !== path.basename(PORTABLE_RUNTIME_ARCHIVE_MEMBER)) {
+    fail(
+      `${rel(archive)} asset manifest runtime.archive must be ${path.basename(PORTABLE_RUNTIME_ARCHIVE_MEMBER)}`,
+    );
+  }
+  if (typeof manifest.runtime.sha256 !== 'string' || !LOWER_SHA256.test(manifest.runtime.sha256)) {
+    fail(`${rel(archive)} asset manifest runtime.sha256 must be a lowercase SHA-256 digest`);
+  }
+  const runtimeEntry = entries.get(PORTABLE_RUNTIME_ARCHIVE_MEMBER);
+  if (
+    runtimeEntry === undefined ||
+    !runtimeEntry.isFile ||
+    runtimeEntry.isSymbolicLink ||
+    runtimeEntry.size <= 0
+  ) {
+    fail(
+      `${rel(archive)} must contain ${PORTABLE_RUNTIME_ARCHIVE_MEMBER} as one non-empty regular file`,
+    );
+  }
+  const runtimeArchive = runtimeEntry.data();
+  const runtimeSha256 = sha256Bytes(runtimeArchive);
+  if (runtimeSha256 !== manifest.runtime.sha256) {
+    fail(
+      `${rel(archive)} asset manifest runtime.sha256 mismatch: ` +
+        `expected ${manifest.runtime.sha256}, got ${runtimeSha256}`,
+    );
+  }
+  let runtimeEntries;
+  try {
+    runtimeEntries = readPortableTarZstdBufferEntries(runtimeArchive, {
+      label: `${rel(archive)} ${PORTABLE_RUNTIME_ARCHIVE_MEMBER}`,
+    });
+  } catch (error) {
+    fail(error.message);
+  }
+  const runtimeMembers = new Set(runtimeEntries.keys());
+  const missing = [...CORE_RUNTIME_MEMBERS]
+    .filter((member) => {
+      const entry = runtimeEntries.get(member);
+      return entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0;
+    })
+    .sort(compareText);
+  if (missing.length > 0) {
+    fail(
+      `${rel(archive)} must bundle the core WASIX runtime closure inside ${PORTABLE_RUNTIME_ARCHIVE_MEMBER}: ${missing.join(', ')}`,
+    );
+  }
+  const bundledIcu = [...runtimeMembers]
+    .filter(
+      (member) => member === 'oliphaunt/share/icu' || member.startsWith('oliphaunt/share/icu/'),
+    )
+    .sort(compareText);
+  if (bundledIcu.length > 0) {
+    fail(
+      `${rel(archive)} must not bundle ICU data inside ${PORTABLE_RUNTIME_ARCHIVE_MEMBER}: ${bundledIcu.slice(0, 5).join(', ')}`,
+    );
+  }
+  const bundledTools = [...runtimeMembers]
+    .filter((member) => FORBIDDEN_RUNTIME_MEMBERS.has(member))
+    .sort(compareText);
+  if (bundledTools.length > 0) {
+    fail(
+      `${rel(archive)} must not bundle standalone tools inside ${PORTABLE_RUNTIME_ARCHIVE_MEMBER}: ${bundledTools.join(', ')}`,
+    );
+  }
+}
+
+export function validateAotReleaseAsset(archive, expectedTarget) {
+  const entries = checkedWasixArchiveEntries(
+    archive,
+    'wasix-aot',
+    `target/oliphaunt-wasix/aot/${expectedTarget}`,
+  );
+  const members = new Set(entries.keys());
+  const manifestMembers = [...members]
+    .filter(
+      (member) =>
+        member.startsWith('target/oliphaunt-wasix/aot/') && member.endsWith('/manifest.json'),
+    )
+    .sort(compareText);
+  if (manifestMembers.length !== 1) {
+    fail(
+      `${rel(archive)} must contain exactly one AOT manifest, got ${JSON.stringify(manifestMembers)}`,
+    );
+  }
+  const manifestPath = manifestMembers[0];
+  const aotRoot = manifestPath.slice(0, -'/manifest.json'.length);
+  if (aotRoot !== `target/oliphaunt-wasix/aot/${expectedTarget}`) {
+    fail(`${rel(archive)} AOT archive root ${aotRoot} does not match target ${expectedTarget}`);
+  }
+  const manifest = readArchiveJsonEntry(entries, manifestPath, archive);
+  try {
+    assertCanonicalWasixAotManifest(manifest, {
+      context: `${rel(archive)} ${manifestPath}`,
+      expectedTarget,
+    });
+  } catch (error) {
+    fail(error.message);
+  }
+  const expectedFiles = new Set([
+    manifestPath,
+    ...expectedReleaseNoticeFiles('wasix-aot', aotRoot),
+  ]);
+  let artifactRows;
+  try {
+    artifactRows = assertWasixAotArtifactPayloads(manifest, {
+      context: `${rel(archive)} ${manifestPath}`,
+      readArtifact(artifactPath) {
+        const member = `${aotRoot}/${artifactPath}`;
+        const entry = entries.get(member);
+        if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) {
+          throw new Error(
+            `${rel(archive)} AOT artifact ${artifactPath} must be a non-empty regular file`,
+          );
+        }
+        return entry.data();
+      },
+    });
+  } catch (error) {
+    fail(error.message);
+  }
+  for (const row of artifactRows) {
+    if (row.name.startsWith('extension:')) {
+      fail(`${rel(archive)} must not contain extension AOT artifact ${row.name}`);
+    }
+    expectedFiles.add(`${aotRoot}/${row.path}`);
+  }
+
+  const unexpected = unexpectedTreeMembers(members, expectedFiles);
+  if (unexpected.length > 0 || [...expectedFiles].some((member) => !members.has(member))) {
+    fail(
+      `${rel(archive)} AOT file set mismatch: ` +
+        `expected ${JSON.stringify([...expectedFiles].sort(compareText))}, got ${JSON.stringify([...members].sort(compareText))}`,
+    );
+  }
+}
+
+function validateAssetContents(assetDir, version) {
+  validatePortableReleaseAsset(
+    path.join(assetDir, `${PRODUCT}-${version}-runtime-portable.tar.zst`),
+  );
+  const aotArchives = readdirSync(assetDir)
+    .filter(
+      (name) => name.startsWith(`${PRODUCT}-${version}-runtime-aot-`) && name.endsWith('.tar.zst'),
+    )
+    .map((name) => path.join(assetDir, name))
+    .sort(compareText);
+  if (aotArchives.length === 0) {
+    fail(`${PRODUCT} release assets are missing target AOT archives`);
+  }
+  for (const archive of aotArchives) {
+    const name = path.basename(archive);
+    const prefix = `${PRODUCT}-${version}-runtime-aot-`;
+    const targetId = name.slice(prefix.length, -'.tar.zst'.length);
+    const expectedTarget = AOT_TARGET_TRIPLES[targetId];
+    if (expectedTarget === undefined) {
+      fail(`${PRODUCT} release asset ${name} has unknown AOT target id ${targetId}`);
+    }
+    validateAotReleaseAsset(archive, expectedTarget);
+  }
+}
+
+function usage() {
+  console.log(`usage: src/runtimes/liboliphaunt-wasix/tools/check-release-assets.mts [--asset-dir DIR] [--version VERSION]
+
+Validates staged liboliphaunt-wasix GitHub release assets, their checksum
+manifest, and runtime/AOT archive boundaries.
+`);
+}
+
+function optionValue(argv, index) {
+  const value = argv[index + 1];
+  if (value === undefined || value.startsWith('--')) {
+    usage();
+    fail(`${argv[index]} requires a value`);
+  }
+  return value;
+}
+
+function parseArgs(argv) {
+  const args = {
+    assetDir: DEFAULT_ASSET_DIR,
+    version: null,
+  };
+  for (let index = 0; index < argv.length; ) {
+    const arg = argv[index];
+    if (arg === '--asset-dir') {
+      args.assetDir = optionValue(argv, index);
+      index += 2;
+    } else if (arg === '--version') {
+      args.version = optionValue(argv, index);
+      index += 2;
+    } else if (arg === '-h' || arg === '--help') {
+      usage();
+      process.exit(0);
+    } else {
+      usage();
+      fail(`unknown argument ${arg}`);
+    }
+  }
+  return {
+    assetDir: path.isAbsolute(args.assetDir) ? args.assetDir : path.join(ROOT, args.assetDir),
+    version: args.version ?? currentProductVersionSync(PRODUCT, TOOL),
+  };
+}
+
+export function main(argv = Bun.argv.slice(2)) {
+  const args = parseArgs(argv);
+  if (!existsSync(args.assetDir) || !isDirectory(args.assetDir)) {
+    fail(`${PRODUCT} release asset directory does not exist: ${rel(args.assetDir)}`);
+  }
+  validateAssetSet(args.assetDir, args.version);
+  validateAssetContents(args.assetDir, args.version);
+  console.log(`validated ${PRODUCT} staged release assets under ${rel(args.assetDir)}`);
+}
+
+if (import.meta.main) {
+  try {
+    main();
+  } catch (error) {
+    const message = error instanceof Error ? error.message : String(error);
+    console.error(message.startsWith(`${TOOL}:`) ? message : `${TOOL}: ${message}`);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/check-release-assets.test.mts b/src/runtimes/liboliphaunt-wasix/tools/check-release-assets.test.mts
new file mode 100644
index 000000000..7b465c661
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/check-release-assets.test.mts
@@ -0,0 +1,328 @@
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { zstdCompressSync } from 'node:zlib';
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts';
+import {
+  exactRegularAssetDirectoryNames,
+  expectedReleaseNoticeFiles,
+  unexpectedTreeMembers,
+  validateAotReleaseAsset,
+  validatePortableReleaseAsset,
+} from './check-release-assets.mts';
+import { canonicalWasixAotMetadata } from './wasix-aot-manifest.mts';
+import {
+  AOT_TARGET_TRIPLES,
+  CORE_RUNTIME_ARCHIVE_FILES,
+} from './wasix-cargo-artifact-contract.mts';
+
+function fixture(t) {
+  const root = mkdtempSync(path.join(tmpdir(), 'wasix-release-assets-check-test-'));
+  t.after(() => rmSync(root, { force: true, recursive: true }));
+  return root;
+}
+
+function archiveStage(stage, archive, archiveRoot) {
+  const tar = createDeterministicTar(stage, archiveRoot, {
+    fail(message) {
+      throw new Error(message);
+    },
+    fixedFileMode: 0o644,
+  });
+  writeFileSync(archive, zstdCompressSync(tar));
+  return archive;
+}
+
+function stageAotPayload(stage, target, profile = 'wasix-aot') {
+  const canonical = canonicalWasixAotMetadata();
+  const raw = Buffer.from(`aot-payload:${target}\n`);
+  const compressed = zstdCompressSync(raw);
+  const manifest = {
+    'format-version': 1,
+    'source-lane': canonical.sourceLane,
+    'target-triple': target,
+    engine: canonical.engine,
+    'wasmer-version': canonical.wasmerVersion,
+    'wasmer-wasix-version': canonical.wasmerWasixVersion,
+    artifacts: [
+      {
+        name: 'runtime:oliphaunt',
+        path: 'runtime.bin.zst',
+        sha256: sha256(compressed),
+        'raw-sha256': sha256(raw),
+        'raw-size': raw.length,
+        'module-sha256': sha256(Buffer.from('runtime-module')),
+        compressed: true,
+      },
+    ],
+  };
+  mkdirSync(stage, { recursive: true });
+  writeFileSync(path.join(stage, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
+  writeFileSync(path.join(stage, 'runtime.bin.zst'), compressed);
+  stageReleaseNotices(stage, { profile });
+  return {
+    artifact: path.join(stage, 'runtime.bin.zst'),
+    manifest: path.join(stage, 'manifest.json'),
+    raw,
+  };
+}
+
+function sha256(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function stagePortablePayload(stage, runtimeBytes) {
+  const root = path.join(stage, 'target/oliphaunt-wasix/assets');
+  mkdirSync(path.join(root, 'bin'), { recursive: true });
+  writeFileSync(path.join(root, 'oliphaunt.wasix.tar.zst'), runtimeBytes);
+  writeFileSync(
+    path.join(root, 'manifest.json'),
+    `${JSON.stringify(
+      {
+        'format-version': 2,
+        runtime: {
+          archive: 'oliphaunt.wasix.tar.zst',
+          sha256: sha256(runtimeBytes),
+        },
+        extensions: [],
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  stageReleaseNotices(stage, { profile: 'wasix-runtime' });
+}
+
+function runtimeArchive(root, name = 'runtime.tar.zst') {
+  const stage = path.join(root, `${name}-stage`, 'oliphaunt');
+  for (const member of CORE_RUNTIME_ARCHIVE_FILES) {
+    const relative = member.replace(/^oliphaunt\//u, '');
+    const file = path.join(stage, relative);
+    mkdirSync(path.dirname(file), { recursive: true });
+    writeFileSync(file, `${relative}\n`);
+  }
+  return readFileSync(archiveStage(stage, path.join(root, name), 'oliphaunt'));
+}
+
+function withParents(files) {
+  const members = new Set(files);
+  for (const file of files) {
+    const parts = file.split('/');
+    for (let index = 1; index < parts.length; index += 1) {
+      members.add(parts.slice(0, index).join('/'));
+    }
+  }
+  return members;
+}
+
+test('the release asset directory rejects entries hidden from a regular-file inventory', (t) => {
+  const root = fixture(t);
+  const asset = path.join(root, 'asset.tar.zst');
+  writeFileSync(asset, 'asset\n');
+  assert.deepEqual(exactRegularAssetDirectoryNames(root), ['asset.tar.zst']);
+
+  const directory = path.join(root, 'unexpected-directory');
+  mkdirSync(directory);
+  assert.throws(
+    () => exactRegularAssetDirectoryNames(root),
+    /only regular non-symlink files: unexpected-directory/u,
+  );
+  rmSync(directory, { recursive: true });
+
+  if (process.platform !== 'win32') {
+    symlinkSync(asset, path.join(root, 'unexpected-link.tar.zst'));
+    assert.throws(
+      () => exactRegularAssetDirectoryNames(root),
+      /only regular non-symlink files: unexpected-link[.]tar[.]zst/u,
+    );
+  }
+});
+
+test('every AOT target admits its prefixed canonical notice closure and rejects extras', () => {
+  for (const target of Object.values(AOT_TARGET_TRIPLES).sort()) {
+    const root = `target/oliphaunt-wasix/aot/${target}`;
+    const notices = expectedReleaseNoticeFiles('wasix-aot', root);
+    assert.ok(notices.has(`${root}/LICENSE`), target);
+    assert.ok(notices.has(`${root}/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT`), target);
+    assert.ok(notices.has(`${root}/THIRD_PARTY_LICENSES/ICU-LICENSE`), target);
+
+    const expected = new Set([`${root}/manifest.json`, `${root}/runtime.cwasm`, ...notices]);
+    const members = withParents(expected);
+    assert.deepEqual(unexpectedTreeMembers(members, expected), [], target);
+
+    const extra = `${root}/THIRD_PARTY_LICENSES/Unknown-LICENSE`;
+    members.add(extra);
+    assert.deepEqual(unexpectedTreeMembers(members, expected), [extra], target);
+  }
+});
+
+test('the real AOT validator accepts every target and rejects extra or incomplete notices', (t) => {
+  const root = fixture(t);
+  const targets = Object.values(AOT_TARGET_TRIPLES).sort();
+  for (const [index, target] of targets.entries()) {
+    const stage = path.join(root, `aot-valid-${index}`);
+    const archiveRoot = `target/oliphaunt-wasix/aot/${target}`;
+    stageAotPayload(stage, target);
+    const archive = archiveStage(stage, path.join(root, `aot-valid-${index}.tar.zst`), archiveRoot);
+    assert.doesNotThrow(() => validateAotReleaseAsset(archive, target), target);
+  }
+
+  const target = targets[0];
+  const archiveRoot = `target/oliphaunt-wasix/aot/${target}`;
+  const extraStage = path.join(root, 'aot-extra');
+  stageAotPayload(extraStage, target);
+  writeFileSync(path.join(extraStage, 'THIRD_PARTY_LICENSES/Unknown-LICENSE'), 'unknown\n');
+  const extra = archiveStage(extraStage, path.join(root, 'aot-extra.tar.zst'), archiveRoot);
+  assert.throws(
+    () => validateAotReleaseAsset(extra, target),
+    new RegExp(`${archiveRoot}/THIRD_PARTY_LICENSES/Unknown-LICENSE`, 'u'),
+  );
+
+  const wrongStage = path.join(root, 'aot-wrong-profile');
+  stageAotPayload(wrongStage, target, 'code-facade');
+  const wrong = archiveStage(wrongStage, path.join(root, 'aot-wrong-profile.tar.zst'), archiveRoot);
+  assert.throws(
+    () => validateAotReleaseAsset(wrong, target),
+    new RegExp(`${archiveRoot}/THIRD_PARTY_NOTICES[.]oliphaunt-wasix[.]md`, 'u'),
+  );
+});
+
+test('the portable validator strictly checks nested runtime bytes and their manifest digest', (t) => {
+  const root = fixture(t);
+  const runtime = runtimeArchive(root);
+  const validStage = path.join(root, 'portable-valid');
+  stagePortablePayload(validStage, runtime);
+  const valid = archiveStage(validStage, path.join(root, 'portable-valid.tar.zst'), '.');
+  assert.doesNotThrow(() => validatePortableReleaseAsset(valid));
+
+  const badDigestStage = path.join(root, 'portable-bad-digest');
+  stagePortablePayload(badDigestStage, runtime);
+  const manifestPath = path.join(badDigestStage, 'target/oliphaunt-wasix/assets/manifest.json');
+  const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
+  manifest.runtime.sha256 = '0'.repeat(64);
+  writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
+  const badDigest = archiveStage(
+    badDigestStage,
+    path.join(root, 'portable-bad-digest.tar.zst'),
+    '.',
+  );
+  assert.throws(() => validatePortableReleaseAsset(badDigest), /runtime[.]sha256 mismatch/u);
+
+  const concatenatedStage = path.join(root, 'portable-concatenated');
+  stagePortablePayload(concatenatedStage, Buffer.concat([runtime, runtime]));
+  const concatenated = archiveStage(
+    concatenatedStage,
+    path.join(root, 'portable-concatenated.tar.zst'),
+    '.',
+  );
+  assert.throws(
+    () => validatePortableReleaseAsset(concatenated),
+    /trailing data or multiple Zstandard frames/u,
+  );
+});
+
+test('the AOT validator rejects duplicate metadata, tampering, and non-canonical zstd payloads', (t) => {
+  const root = fixture(t);
+  const target = Object.values(AOT_TARGET_TRIPLES).sort()[0];
+  const archiveRoot = `target/oliphaunt-wasix/aot/${target}`;
+
+  function rejected(name, mutate, pattern) {
+    const stage = path.join(root, name);
+    const fixtureData = stageAotPayload(stage, target);
+    const manifest = JSON.parse(readFileSync(fixtureData.manifest, 'utf8'));
+    mutate({ ...fixtureData, manifest });
+    writeFileSync(fixtureData.manifest, `${JSON.stringify(manifest, null, 2)}\n`);
+    const archive = archiveStage(stage, path.join(root, `${name}.tar.zst`), archiveRoot);
+    assert.throws(() => validateAotReleaseAsset(archive, target), pattern, name);
+  }
+
+  rejected(
+    'duplicate-name',
+    ({ manifest }) => {
+      manifest.artifacts.push({ ...manifest.artifacts[0], path: 'second.bin.zst' });
+    },
+    /repeats AOT artifact name/u,
+  );
+
+  rejected(
+    'duplicate-path',
+    ({ manifest }) => {
+      manifest.artifacts.push({ ...manifest.artifacts[0], name: 'runtime-support:other' });
+    },
+    /repeats AOT artifact path/u,
+  );
+
+  rejected(
+    'unnormalized-path',
+    ({ manifest }) => {
+      manifest.artifacts[0].path = './runtime.bin.zst';
+    },
+    /path must already be normalized/u,
+  );
+
+  rejected(
+    'tampered-compressed',
+    ({ artifact }) => {
+      const bytes = Buffer.from(readFileSync(artifact));
+      bytes[bytes.length - 1] ^= 1;
+      writeFileSync(artifact, bytes);
+    },
+    /compressed SHA-256 mismatch/u,
+  );
+
+  rejected(
+    'concatenated-zstd',
+    ({ artifact, manifest }) => {
+      const bytes = readFileSync(artifact);
+      const concatenated = Buffer.concat([bytes, bytes]);
+      writeFileSync(artifact, concatenated);
+      manifest.artifacts[0].sha256 = sha256(concatenated);
+    },
+    /trailing data or multiple Zstandard frames/u,
+  );
+
+  rejected(
+    'wrong-raw-size',
+    ({ manifest }) => {
+      manifest.artifacts[0]['raw-size'] += 1;
+    },
+    /bounded readable Zstandard stream|raw-size mismatch/u,
+  );
+
+  rejected(
+    'wrong-raw-digest',
+    ({ manifest }) => {
+      manifest.artifacts[0]['raw-sha256'] = '0'.repeat(64);
+    },
+    /raw SHA-256 mismatch/u,
+  );
+
+  rejected(
+    'malformed-compressed',
+    ({ manifest }) => {
+      manifest.artifacts[0].compressed = 'true';
+    },
+    /compressed must be a Boolean/u,
+  );
+
+  rejected(
+    'extra-metadata',
+    ({ manifest }) => {
+      manifest.artifacts[0].unexpected = true;
+    },
+    /metadata fields must be exactly/u,
+  );
+
+  rejected(
+    'empty-artifact',
+    ({ artifact, manifest }) => {
+      writeFileSync(artifact, Buffer.alloc(0));
+      manifest.artifacts[0].sha256 = sha256(Buffer.alloc(0));
+    },
+    /non-empty regular file/u,
+  );
+});
diff --git a/src/runtimes/liboliphaunt-wasix/tools/check-shim-abi.sh b/src/runtimes/liboliphaunt-wasix/tools/check-shim-abi.sh
new file mode 100644
index 000000000..db0d06f60
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/check-shim-abi.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+set -euo pipefail
+case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) exit 0 ;; esac
+shim="$(cd "$(dirname "${BASH_SOURCE[0]}")/../assets/build/wasix_shim" && pwd)"
+output="$(mktemp -d)"
+trap 'rm -rf "$output"' EXIT
+for name in oliphaunt_wasix_bridge oliphaunt_wasix_initdb_shim; do
+  "${CC:-cc}" -std=c11 -Wall -Wextra "$shim/$name.c" "$shim/${name}_abi_test.c" -o "$output/$name"
+  "$output/$name"
+done
diff --git a/src/runtimes/liboliphaunt-wasix/tools/download-assets.sh b/src/runtimes/liboliphaunt-wasix/tools/download-assets.sh
new file mode 100755
index 000000000..b4e13b498
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/download-assets.sh
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+cd "$root"
+run_id= sha= release= required_job= target= all=false
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --all-targets) all=true; shift ;;
+    --run-id|--sha|--release|--required-job|--target|--target-triple)
+      [ "$#" -ge 2 ] && [ -n "$2" ] || { echo "$1 requires a value" >&2; exit 2; }
+      case "$1" in
+        --run-id) run_id="$2" ;; --sha) sha="$2" ;; --release) release="$2" ;;
+        --required-job) required_job="$2" ;; *) target="$2" ;;
+      esac
+      shift 2 ;;
+    *) echo "unknown download option: $1" >&2; exit 2 ;;
+  esac
+done
+[ "$all" = false ] || [ -z "$target" ] || { echo 'choose --all-targets or --target' >&2; exit 2; }
+if [ -n "$release" ]; then
+  [ -z "$run_id$sha$required_job" ] && [[ "$release" =~ ^[A-Za-z0-9._-]+$ ]] || { echo 'release requires one valid tag and no workflow selector' >&2; exit 2; }
+else
+  [ -n "$run_id$sha" ] || { echo '--run-id or --sha is required' >&2; exit 2; }
+fi
+if [ "$all" = true ]; then target=all; elif [ -z "$target" ]; then target="$(rustc -vV | awk '/^host:/{print $2}')"; fi
+rows="$(tools/dev/bun.sh src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts "$target")"
+stage="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-wasix-download.XXXXXX")"
+trap 'rm -rf "$stage"' EXIT
+payload="$stage/payload"
+mkdir "$payload"
+install_args=(--from "$payload")
+if [ -n "$release" ]; then
+  version="${release##*-v}"
+  checksum="liboliphaunt-wasix-$version-release-assets.sha256"
+  curl_args=(--fail --location --proto '=https' --proto-redir '=https' --connect-timeout 30 --max-time 600 --retry 3 --retry-max-time 1800)
+  case "$(uname -s)" in MINGW*|MSYS*) curl_args+=(--ssl-revoke-best-effort) ;; esac
+  url="https://github.com/f0rr0/oliphaunt/releases/download/$release"
+  curl "${curl_args[@]}" "$url/$checksum" --output "$stage/$checksum"
+  archives=("liboliphaunt-wasix-$version-runtime-portable.tar.zst")
+  while IFS=$'\t' read -r triple artifact id; do
+    archives+=("liboliphaunt-wasix-$version-runtime-aot-$id.tar.zst")
+    install_args+=(--target-triple "$triple")
+  done <<<"$rows"
+  if command -v sha256sum >/dev/null; then hash=(sha256sum); else hash=(shasum -a 256); fi
+  for archive in "${archives[@]}"; do
+    expected="$(awk -v asset="$archive" '
+      NF != 2 || length($1) != 64 || $1 ~ /[^a-fA-F0-9]/ { bad=1 }
+      { name=$2; sub(/^\*/, "", name); sub(/^\.\//, "", name); if (name == asset) { count++; digest=tolower($1) } }
+      END { if (bad || count != 1) exit 1; print digest }
+    ' "$stage/$checksum")"
+    curl "${curl_args[@]}" "$url/$archive" --output "$stage/$archive"
+    printf '%s  %s\n' "$expected" "$stage/$archive" | "${hash[@]}" -c -
+    cargo run --quiet --locked -p xtask -- assets unpack "$stage/$archive" "$payload"
+  done
+else
+  export GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-}}"
+  : "${GH_TOKEN:?GitHub authentication is required}"
+  export GH_REPO="${GH_REPO:-${GITHUB_REPOSITORY:-$(gh repo view --json nameWithOwner --jq .nameWithOwner)}}"
+  if [ -z "$sha" ]; then sha="$(gh run view "$run_id" --json headSha --jq .headSha)"; fi
+  [[ "$sha" =~ ^[a-fA-F0-9]{40}$ ]] || { echo '--sha must be a full commit SHA' >&2; exit 2; }
+  if [ -z "$run_id" ]; then
+    run_id="$(gh run list --workflow CI --commit "$sha" --status success --limit 1 --json databaseId --jq '.[0].databaseId // empty')"
+    : "${run_id:?no successful CI run exists for the requested commit}"
+  fi
+  download_args=()
+  [ -z "$run_id" ] || download_args+=(--run-id "$run_id")
+  [ -z "$required_job" ] || download_args+=(--job "$required_job")
+  bash .github/scripts/download-build-artifacts.sh CI "$sha" "$payload" "${download_args[@]}" --artifact liboliphaunt-wasix-runtime-portable
+  while IFS=$'\t' read -r triple artifact id; do
+    bash .github/scripts/download-build-artifacts.sh CI "$sha" "$payload/target/oliphaunt-wasix/aot/$triple" "${download_args[@]}" --artifact "$artifact"
+    install_args+=(--target-triple "$triple")
+  done <<<"$rows"
+fi
+cargo run --quiet --locked -p xtask -- assets import-download "${install_args[@]}"
diff --git a/src/runtimes/liboliphaunt-wasix/tools/extension-build-scripts.mts b/src/runtimes/liboliphaunt-wasix/tools/extension-build-scripts.mts
new file mode 100644
index 000000000..2a346de08
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/extension-build-scripts.mts
@@ -0,0 +1,19 @@
+import assert from 'node:assert/strict';
+import { existsSync, readFileSync } from 'node:fs';
+import path from 'node:path';
+
+const root = path.resolve(import.meta.dirname, '../../../..');
+const { extensions } = JSON.parse(
+  readFileSync(path.join(root, 'src/extensions/generated/extensions.catalog.json'), 'utf8'),
+);
+for (const name of extensions.map((row) => row['sql-name']).sort()) {
+  const recipe = path.join(root, 'src/extensions/external', name, 'targets/wasix.toml');
+  if (!existsSync(recipe)) continue;
+  const target = Bun.TOML.parse(readFileSync(recipe, 'utf8'));
+  if (target.build_kind !== 'autotools') continue;
+  assert(
+    typeof target.build_script === 'string' && target.build_script.length > 0,
+    `${name} has no WASIX build script`,
+  );
+  console.log(target.build_script);
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/package-carriers.mts b/src/runtimes/liboliphaunt-wasix/tools/package-carriers.mts
new file mode 100644
index 000000000..1bc3b6535
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/package-carriers.mts
@@ -0,0 +1,212 @@
+#!/usr/bin/env bun
+import { readdirSync, readFileSync } from 'node:fs';
+import path from 'node:path';
+import {
+  extensionPackageDir,
+  packageExtensionNpmCarriers,
+} from '../../../extensions/artifacts/packages/tools/package-carriers.mts';
+import {
+  assertSameStringSet,
+  copyStagedRuntimeAssets,
+  fail,
+  isDirectory,
+  isFile,
+  rel,
+  TOOL,
+} from '../../../../tools/packaging/release-carrier.mts';
+import { writeChecksumManifest } from '../../../../tools/packaging/write-checksum-manifest.mts';
+import {
+  compareText,
+  contribCarrierDescriptor,
+  currentProductVersionSync,
+  ROOT,
+  registryPackageRows,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { main as checkWasixReleaseAssets } from './check-release-assets.mts';
+import { packageWasixCargoArtifacts } from './package_liboliphaunt_wasix_cargo_artifacts.mts';
+import {
+  WASIX_CARGO_ARTIFACT_SCHEMA,
+  publicCargoPackageNames as wasixPublicCargoPackageNames,
+} from './wasix-cargo-artifact-contract.mts';
+import {
+  expectedWasixExtensionPackageInventory,
+  isExpectedWasixExtensionPackage,
+  validateWasixExtensionArtifactInventory,
+} from './wasix-extension-cargo-artifact-inventory.mts';
+import { packWasixRuntimeNpmCarrier } from './wasix-runtime-npm-carrier.mts';
+
+export const WASIX_PRODUCT = 'liboliphaunt-wasix';
+
+function hasWasixReleaseArchive(assetDir) {
+  if (!isDirectory(assetDir)) {
+    return false;
+  }
+  return readdirSync(assetDir).some(
+    (name) => name.startsWith('liboliphaunt-wasix-') && name.endsWith('.tar.zst'),
+  );
+}
+
+async function ensureWasixReleaseAssets() {
+  const assetDir = path.join(ROOT, 'target/oliphaunt-wasix/release-assets');
+  if (!hasWasixReleaseArchive(assetDir)) {
+    copyStagedRuntimeAssets({
+      product: WASIX_PRODUCT,
+      destination: assetDir,
+      envName: 'OLIPHAUNT_WASIX_RELEASE_ASSET_INPUT_DIRS',
+      patterns: ['liboliphaunt-wasix-*.tar.zst'],
+    });
+  }
+  const version = currentProductVersionSync(WASIX_PRODUCT, TOOL);
+  await writeChecksumManifest([
+    '--asset-dir',
+    rel(assetDir),
+    '--output',
+    `liboliphaunt-wasix-${version}-release-assets.sha256`,
+    '--pattern',
+    'liboliphaunt-wasix-*.tar.zst',
+  ]);
+  checkWasixReleaseAssets(['--asset-dir', rel(assetDir), '--version', version]);
+}
+
+export function validateWasixCargoArtifacts(outputDir) {
+  const manifestPath = path.join(outputDir, 'packages.json');
+  if (!isFile(manifestPath)) {
+    fail(`missing generated ${WASIX_PRODUCT} Cargo artifact manifest: ${rel(manifestPath)}`);
+  }
+  let data;
+  try {
+    data = JSON.parse(readFileSync(manifestPath, 'utf8'));
+  } catch (error) {
+    fail(`${rel(manifestPath)} is not valid JSON: ${error.message}`);
+  }
+  if (data?.schema !== WASIX_CARGO_ARTIFACT_SCHEMA || !Array.isArray(data.packages)) {
+    fail(`${rel(manifestPath)} has an invalid WASIX Cargo artifact schema`);
+  }
+
+  const contribProduct = contribCarrierDescriptor(TOOL).artifactProduct;
+  const expectedBaseCrates = new Set(wasixPublicCargoPackageNames());
+  const expectedExtensionInventory = expectedWasixExtensionPackageInventory(TOOL, [contribProduct]);
+  const expectedConfiguredCrates = new Set([
+    ...expectedBaseCrates,
+    ...expectedExtensionInventory.expectedPackageKinds.keys(),
+  ]);
+  const configuredCrates = new Set(
+    registryPackageRows({ product: WASIX_PRODUCT, packageKind: 'crates' }, TOOL).map(
+      (row) => row.packageName,
+    ),
+  );
+  assertSameStringSet(
+    `${WASIX_PRODUCT} crates.io packages must match WASIX runtime/AOT artifact packages`,
+    configuredCrates,
+    expectedConfiguredCrates,
+  );
+  const generatedCrates = new Set();
+  const expectedCratePaths = new Set();
+  try {
+    validateWasixExtensionArtifactInventory(data.packages, expectedExtensionInventory);
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+  const packages = [];
+  const allowedKinds = new Set([
+    'wasix-runtime',
+    'wasix-aot',
+    'wasix-extension',
+    'wasix-extension-aot',
+  ]);
+  for (const item of data.packages) {
+    if (item === null || Array.isArray(item) || typeof item !== 'object') {
+      fail(`${rel(manifestPath)} package entries must be objects`);
+    }
+    const { name, role, kind, manifestPath: rawManifest, cratePath: rawCrate } = item;
+    if (
+      ![name, role, kind, rawManifest].every(
+        (value) => typeof value === 'string' && value.length > 0,
+      )
+    ) {
+      fail(`${rel(manifestPath)} has an invalid package row: ${JSON.stringify(item)}`);
+    }
+    if (role !== 'artifact') {
+      fail(
+        `${rel(manifestPath)} must contain direct WASIX artifact packages, got role ${JSON.stringify(role)}`,
+      );
+    }
+    if (!allowedKinds.has(kind)) {
+      fail(
+        `${rel(manifestPath)} has unsupported WASIX Cargo artifact kind ${JSON.stringify(kind)}`,
+      );
+    }
+    if (
+      !expectedBaseCrates.has(name) &&
+      !isExpectedWasixExtensionPackage(name, kind, expectedExtensionInventory)
+    ) {
+      fail(`unexpected ${WASIX_PRODUCT} Cargo artifact crate ${name}`);
+    }
+    const sourceManifest = path.join(ROOT, rawManifest);
+    if (!isFile(sourceManifest)) {
+      fail(`missing generated ${WASIX_PRODUCT} Cargo source manifest: ${rawManifest}`);
+    }
+    if (typeof rawCrate !== 'string' || rawCrate.length === 0) {
+      fail(`generated ${WASIX_PRODUCT} Cargo artifact ${name} must have a cratePath`);
+    }
+    const cratePath = path.join(ROOT, rawCrate);
+    if (!isFile(cratePath)) {
+      fail(`missing generated ${WASIX_PRODUCT} Cargo artifact crate for ${name}: ${rawCrate}`);
+    }
+    generatedCrates.add(name);
+    expectedCratePaths.add(path.resolve(cratePath));
+    packages.push({ name, cratePath, manifestPath: sourceManifest });
+  }
+
+  const missingBaseCrates = [...expectedBaseCrates]
+    .filter((name) => !generatedCrates.has(name))
+    .sort(compareText);
+  if (missingBaseCrates.length > 0) {
+    fail(
+      `generated ${WASIX_PRODUCT} Cargo artifacts are missing configured runtime crates: ${missingBaseCrates.join(', ')}`,
+    );
+  }
+  const unexpected = readdirSync(outputDir)
+    .filter((name) => name.endsWith('.crate'))
+    .map((name) => path.join(outputDir, name))
+    .filter((file) => !expectedCratePaths.has(path.resolve(file)))
+    .map((file) => path.basename(file))
+    .sort(compareText);
+  if (unexpected.length > 0) {
+    fail(`unexpected ${WASIX_PRODUCT} Cargo artifact crate(s): ${unexpected.join(', ')}`);
+  }
+  return packages.sort((left, right) => compareText(left.name, right.name));
+}
+
+export async function liboliphauntWasixCargoArtifactPackages(
+  version = currentProductVersionSync(WASIX_PRODUCT, TOOL),
+  { extensionArtifactRoots = [] } = {},
+) {
+  const outputDir = path.join(ROOT, 'target/oliphaunt-wasix/cargo-artifacts');
+  await ensureWasixReleaseAssets();
+  const args = ['--version', version, '--output-dir', rel(outputDir)];
+  for (const root of extensionArtifactRoots) {
+    args.push('--extension-artifact-root', rel(root));
+  }
+  packageWasixCargoArtifacts(args);
+  return validateWasixCargoArtifacts(outputDir);
+}
+
+export async function packageWasixRuntimeCarriers() {
+  const contrib = contribCarrierDescriptor(TOOL);
+  const version = currentProductVersionSync(WASIX_PRODUCT, TOOL);
+  await liboliphauntWasixCargoArtifactPackages(version, {
+    extensionArtifactRoots: [extensionPackageDir(contrib.artifactProduct, 'wasix')],
+  });
+  const portableReleaseArchive = path.join(
+    ROOT,
+    `target/oliphaunt-wasix/release-assets/liboliphaunt-wasix-${version}-runtime-portable.tar.zst`,
+  );
+  packWasixRuntimeNpmCarrier({
+    version,
+    portableReleaseArchive,
+  });
+  packageExtensionNpmCarriers(contrib.artifactProduct, { family: 'wasix' });
+}
+
+if (import.meta.main) await packageWasixRuntimeCarriers();
diff --git a/src/runtimes/liboliphaunt-wasix/tools/package-liboliphaunt-wasix-cargo-artifacts.test.mts b/src/runtimes/liboliphaunt-wasix/tools/package-liboliphaunt-wasix-cargo-artifacts.test.mts
new file mode 100644
index 000000000..dffafbf02
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/package-liboliphaunt-wasix-cargo-artifacts.test.mts
@@ -0,0 +1,537 @@
+#!/usr/bin/env bun
+import { describe, expect, test } from 'bun:test';
+import { createHash } from 'node:crypto';
+import {
+  chmodSync,
+  cpSync,
+  mkdirSync,
+  mkdtempSync,
+  readFileSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { gzipSync, zstdCompressSync } from 'node:zlib';
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import { canonicalGzipSync } from '../../../../tools/packaging/portable-archive.mts';
+import {
+  extensionReleaseProduct,
+  extensionReleaseVersion,
+  extensionSqlNames,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  extractArchiveMemberToFile,
+  extractTarZstd,
+  injectRuntimeExtensionDependencies,
+  packageWasixCargoArtifacts,
+  validateRuntimePayload,
+} from './package_liboliphaunt_wasix_cargo_artifacts.mts';
+import { canonicalWasixAotMetadata } from './wasix-aot-manifest.mts';
+import {
+  AOT_TARGET_TRIPLES,
+  CORE_RUNTIME_ARCHIVE_FILES,
+  wasixExtensionAotPackageName,
+} from './wasix-cargo-artifact-contract.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../../../..');
+const scratch = process.env.OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT;
+if (!scratch) throw new Error('Run bash src/runtimes/liboliphaunt-wasix/tools/test-packaging.sh');
+function supportedRustcHostTriple() {
+  const host = process.env.OLIPHAUNT_TEST_RUST_HOST;
+  if (!Object.values(AOT_TARGET_TRIPLES).includes(host))
+    throw new Error(`Unsupported Rust test host: ${host}`);
+  return host;
+}
+
+function sha256(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function sha256Bytes(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function tarOctal(value, length) {
+  return Buffer.from(`${value.toString(8).padStart(length - 1, '0')}\0`, 'ascii');
+}
+
+function adversarialTar(rows) {
+  const records = [];
+  for (const row of rows) {
+    const data = Buffer.from(row.data ?? '');
+    const header = Buffer.alloc(512);
+    Buffer.from(row.name).copy(header, 0);
+    tarOctal(row.mode ?? 0o644, 8).copy(header, 100);
+    tarOctal(0, 8).copy(header, 108);
+    tarOctal(0, 8).copy(header, 116);
+    tarOctal(data.length, 12).copy(header, 124);
+    tarOctal(0, 12).copy(header, 136);
+    header.fill(0x20, 148, 156);
+    header[156] = (row.type ?? '0').charCodeAt(0);
+    if (row.link) Buffer.from(`${row.link}\0`).copy(header, 157);
+    Buffer.from('ustar\0', 'binary').copy(header, 257);
+    Buffer.from('00').copy(header, 263);
+    const checksum = header.reduce((sum, byte) => sum + byte, 0);
+    Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `, 'ascii').copy(header, 148);
+    records.push(header, data, Buffer.alloc((512 - (data.length % 512)) % 512));
+  }
+  return Buffer.concat([...records, Buffer.alloc(1024)]);
+}
+
+function adversarialTarGz(rows) {
+  return gzipSync(adversarialTar(rows), { mtime: 0 });
+}
+
+function aggregateFixture(root, { nestedOwner = false } = {}) {
+  const product = 'oliphaunt-extension-contrib-pg18';
+  const version = extensionReleaseVersion(
+    product,
+    'wasix',
+    'package-liboliphaunt-wasix-cargo-artifacts.test',
+  );
+  const releaseProduct = extensionReleaseProduct(
+    product,
+    'wasix',
+    'package-liboliphaunt-wasix-cargo-artifacts.test',
+  );
+  const productRoot = path.join(root, ...(nestedOwner ? [releaseProduct, product] : [product]));
+  const releaseAssets = path.join(productRoot, 'release-assets');
+  const archiveRoot = `${product}-${version}-wasix-wasix-portable-bundle`;
+  const carrierName = `${archiveRoot}.tar.gz`;
+  const stage = path.join(root, 'stage', archiveRoot);
+  const extensions = [];
+  const sqlNames = extensionSqlNames(product, 'package-liboliphaunt-wasix-cargo-artifacts.test');
+  for (const sqlName of sqlNames) {
+    const name = `${product}-${version}-wasix-portable.tar.zst`;
+    const memberPath = `extensions/${sqlName}/${name}`;
+    const file = path.join(stage, ...memberPath.split('/'));
+    mkdirSync(path.dirname(file), { recursive: true });
+    writeFileSync(file, Buffer.from(`${sqlName}:`.repeat(20)));
+    extensions.push({
+      sqlName,
+      dependencies: sqlName === 'earthdistance' ? ['cube'] : [],
+      nativeModuleStem: ['cube', 'earthdistance'].includes(sqlName) ? sqlName : null,
+      assets: [
+        {
+          name,
+          family: 'wasix',
+          target: 'wasix-portable',
+          kind: 'wasix-runtime',
+          identity: null,
+          path: file,
+          sha256: sha256(file),
+          bytes: statSync(file).size,
+          carrierAsset: carrierName,
+          carrierRoot: archiveRoot,
+          memberPath,
+        },
+      ],
+    });
+  }
+  mkdirSync(releaseAssets, { recursive: true });
+  const carrier = path.join(releaseAssets, carrierName);
+  writeFileSync(
+    carrier,
+    canonicalGzipSync(
+      createDeterministicTar(stage, archiveRoot, {
+        fail(message) {
+          throw new Error(message);
+        },
+        fixedFileMode: 0o644,
+      }),
+    ),
+  );
+  writeFileSync(
+    path.join(productRoot, 'extension-artifacts.json'),
+    `${JSON.stringify(
+      {
+        schema: 'oliphaunt-extension-ci-artifacts-v2',
+        product,
+        releaseProduct,
+        family: 'wasix',
+        version,
+        extensions,
+        carrierAssets: [
+          {
+            name: carrierName,
+            family: 'wasix',
+            target: 'wasix-portable',
+            kind: 'extension-bundle',
+            sha256: sha256(carrier),
+            bytes: statSync(carrier).size,
+            memberCount: sqlNames.length,
+          },
+        ],
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  const canonicalAot = canonicalWasixAotMetadata();
+  for (const [targetId, targetTriple] of Object.entries(AOT_TARGET_TRIPLES)) {
+    for (const sqlName of ['cube', 'earthdistance']) {
+      const directory = path.join(productRoot, 'wasix-aot', targetId, sqlName);
+      const artifactName = `${sqlName}.bin.zst`;
+      const artifact = path.join(directory, artifactName);
+      const raw = Buffer.concat(
+        Array.from({ length: 64 }, (_, index) =>
+          createHash('sha256').update(`${targetTriple}:${sqlName}:${index}`).digest(),
+        ),
+      );
+      const compressed = zstdCompressSync(raw);
+      mkdirSync(directory, { recursive: true });
+      writeFileSync(artifact, compressed);
+      writeFileSync(
+        path.join(directory, 'manifest.json'),
+        `${JSON.stringify(
+          {
+            'format-version': 1,
+            'source-lane': canonicalAot.sourceLane,
+            engine: canonicalAot.engine,
+            'wasmer-version': canonicalAot.wasmerVersion,
+            'wasmer-wasix-version': canonicalAot.wasmerWasixVersion,
+            'target-triple': targetTriple,
+            artifacts: [
+              {
+                name: `extension:${sqlName}`,
+                path: artifactName,
+                sha256: sha256(artifact),
+                'raw-sha256': sha256Bytes(raw),
+                'raw-size': raw.length,
+                'module-sha256': sha256Bytes(Buffer.from(`module:${sqlName}`)),
+                compressed: true,
+              },
+            ],
+          },
+          null,
+          2,
+        )}\n`,
+      );
+    }
+  }
+  return productRoot;
+}
+
+describe('aggregate WASIX Cargo artifact packaging', () => {
+  test('runtime source build resolves runtime-owned contrib archives and AOT under the WASIX owner', {
+    timeout: 180_000,
+  }, () => {
+    const root = path.join(scratch, 'nested-owner');
+    mkdirSync(root);
+    const productRoot = aggregateFixture(root, { nestedOwner: true });
+    const manifest = JSON.parse(
+      readFileSync(path.join(productRoot, 'extension-artifacts.json'), 'utf8'),
+    );
+    const cube = manifest.extensions.find((row) => row.sqlName === 'cube');
+    const archive = path.join(productRoot, 'member-assets', 'cube', cube.assets[0].name);
+    mkdirSync(path.dirname(archive), { recursive: true });
+    cpSync(cube.assets[0].path, archive);
+
+    const hostTriple = supportedRustcHostTriple();
+    const app = path.join(root, 'app');
+    mkdirSync(path.join(app, 'src'), { recursive: true });
+    writeFileSync(
+      path.join(app, 'Cargo.toml'),
+      `[package]
+name = "wasix-nested-owner-proof"
+version = "0.0.0"
+edition = "2024"
+
+[dependencies]
+liboliphaunt-wasix-portable = { path = ${JSON.stringify(path.join(ROOT, 'src/runtimes/liboliphaunt-wasix/crates/assets'))}, features = ["extension-cube"] }
+
+[workspace]
+`,
+    );
+    writeFileSync(
+      path.join(app, 'src/main.rs'),
+      `fn main() {
+    assert!(liboliphaunt_wasix_portable::extension_archive("cube").is_some());
+    assert!(liboliphaunt_wasix_portable::extension_aot_manifest_json(${JSON.stringify(hostTriple)}, "cube").is_some());
+}
+`,
+    );
+  });
+
+  test('streams large nested portable archive members without truncation', () => {
+    const root = mkdtempSync(path.join(scratch, 'stream-'));
+    const carrierRoot = 'aggregate-carrier';
+    const member = `${carrierRoot}/extensions/pgcrypto/extension.tar.zst`;
+    const source = path.join(root, 'stage', ...member.split('/'));
+    const expected = Buffer.alloc(2 * 1024 * 1024 + 17, 0x5a);
+    mkdirSync(path.dirname(source), { recursive: true });
+    writeFileSync(source, expected);
+    const carrier = path.join(root, 'carrier.tar.gz');
+    writeFileSync(
+      carrier,
+      canonicalGzipSync(
+        createDeterministicTar(path.join(root, 'stage', carrierRoot), carrierRoot, {}),
+      ),
+    );
+
+    const destination = path.join(root, 'materialized', 'extension.tar.zst');
+    extractArchiveMemberToFile(carrier, member, destination);
+    expect(readFileSync(destination)).toEqual(expected);
+  });
+
+  test('rejects duplicate and symlink carrier entries before materializing a member', () => {
+    const root = mkdtempSync(path.join(scratch, 'adversarial-'));
+
+    const duplicate = path.join(root, 'duplicate.tar.gz');
+    writeFileSync(
+      duplicate,
+      adversarialTarGz([
+        { name: 'payload.bin', data: 'first\n' },
+        { name: 'payload.bin', data: 'second\n' },
+      ]),
+    );
+    const duplicateDestination = path.join(root, 'duplicate-output.bin');
+    expect(() =>
+      extractArchiveMemberToFile(duplicate, 'payload.bin', duplicateDestination),
+    ).toThrow(/repeats archive member payload[.]bin/u);
+    expect(() => statSync(duplicateDestination)).toThrow();
+
+    const linked = path.join(root, 'linked.tar.gz');
+    writeFileSync(
+      linked,
+      adversarialTarGz([{ name: 'payload-link', type: '2', link: 'payload.bin' }]),
+    );
+    const linkedDestination = path.join(root, 'linked-output.bin');
+    expect(() => extractArchiveMemberToFile(linked, 'payload-link', linkedDestination)).toThrow(
+      /link or special ustar entry/u,
+    );
+    expect(() => statSync(linkedDestination)).toThrow();
+  });
+
+  test('direct tar.zst materialization preserves exact modes despite umask and read-only directories', () => {
+    if (process.platform === 'win32') return;
+    const root = mkdtempSync(path.join(scratch, 'materialization-mode-'));
+    const archive = path.join(root, 'payload.tar.zst');
+    const expected = Buffer.from('executable payload\n');
+    writeFileSync(
+      archive,
+      zstdCompressSync(
+        adversarialTar([
+          { name: 'payload/', type: '5', mode: 0o555 },
+          { name: 'payload/read-only/', type: '5', mode: 0o500 },
+          { name: 'payload/read-only/tool', mode: 0o751, data: expected },
+        ]),
+      ),
+    );
+
+    const destination = path.join(root, 'extracted');
+    const previousUmask = process.umask(0o077);
+    try {
+      extractTarZstd(archive, destination);
+    } finally {
+      process.umask(previousUmask);
+    }
+
+    const payload = path.join(destination, 'payload');
+    const readOnly = path.join(payload, 'read-only');
+    const executable = path.join(readOnly, 'tool');
+    expect(statSync(payload).mode & 0o777).toBe(0o555);
+    expect(statSync(readOnly).mode & 0o777).toBe(0o500);
+    expect(statSync(executable).mode & 0o777).toBe(0o751);
+    expect(readFileSync(executable)).toEqual(expected);
+
+    // Restore cleanup access after proving the final archived modes.
+    chmodSync(payload, 0o755);
+    chmodSync(readOnly, 0o755);
+  });
+
+  test('package-side runtime validation binds the manifest to strict nested bytes', () => {
+    const root = mkdtempSync(path.join(scratch, 'runtime-validation-'));
+    const runtimeSource = path.join(root, 'runtime-source', 'oliphaunt');
+    for (const member of CORE_RUNTIME_ARCHIVE_FILES) {
+      const relative = member.replace(/^oliphaunt\//u, '');
+      const file = path.join(runtimeSource, relative);
+      mkdirSync(path.dirname(file), { recursive: true });
+      writeFileSync(file, `${relative}\n`);
+    }
+    const runtimeBytes = zstdCompressSync(
+      createDeterministicTar(runtimeSource, 'oliphaunt', {
+        fail(message) {
+          throw new Error(message);
+        },
+        fixedFileMode: 0o644,
+      }),
+    );
+
+    const payload = path.join(root, 'payload');
+    mkdirSync(path.join(payload, 'bin'), { recursive: true });
+    writeFileSync(path.join(payload, 'bin/initdb.wasix.wasm'), 'initdb-wasm\n');
+    writeFileSync(path.join(payload, 'oliphaunt.wasix.tar.zst'), runtimeBytes);
+    const manifestPath = path.join(payload, 'manifest.json');
+    const manifest = {
+      runtime: {
+        archive: 'oliphaunt.wasix.tar.zst',
+        sha256: sha256Bytes(runtimeBytes),
+      },
+      extensions: [],
+    };
+    writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
+    expect(() => validateRuntimePayload(payload)).not.toThrow();
+
+    manifest.runtime.sha256 = '0'.repeat(64);
+    writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
+    expect(() => validateRuntimePayload(payload)).toThrow(/runtime[.]sha256 mismatch/u);
+
+    const concatenated = Buffer.concat([runtimeBytes, runtimeBytes]);
+    writeFileSync(path.join(payload, 'oliphaunt.wasix.tar.zst'), concatenated);
+    manifest.runtime.sha256 = sha256Bytes(concatenated);
+    writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
+    expect(() => validateRuntimePayload(payload)).toThrow(
+      /trailing data or multiple Zstandard frames/u,
+    );
+  });
+
+  test('extension packaging rejects AOT raw-digest tampering before Cargo packaging', () => {
+    const root = mkdtempSync(path.join(scratch, 'extension-aot-tamper-'));
+    const extensionRoot = aggregateFixture(root);
+    const targetId = Object.keys(AOT_TARGET_TRIPLES).sort()[0];
+    const manifestPath = path.join(extensionRoot, 'wasix-aot', targetId, 'cube', 'manifest.json');
+    const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
+    manifest.artifacts[0]['raw-sha256'] = '0'.repeat(64);
+    writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
+
+    expect(() =>
+      packageWasixCargoArtifacts([
+        '--extensions-only',
+        '--extension-artifact-root',
+        extensionRoot,
+        '--output-dir',
+        path.join(root, 'output'),
+        '--work-dir',
+        path.join(root, 'work'),
+        '--version',
+        '0.1.0',
+      ]),
+    ).toThrow(/raw SHA-256 mismatch/u);
+  });
+
+  test('splits from part-001 and a single carrier feature selects earthdistance plus cube only', {
+    timeout: 180_000,
+  }, () => {
+    const root = path.join(scratch, 'aggregate');
+    mkdirSync(root);
+    const extensionRoot = aggregateFixture(root);
+    const output = path.join(root, 'output');
+    const work = path.join(root, 'work');
+    packageWasixCargoArtifacts([
+      '--extensions-only',
+      '--extension-artifact-root',
+      extensionRoot,
+      '--extension-part-bytes',
+      '256',
+      '--output-dir',
+      output,
+      '--work-dir',
+      work,
+      '--version',
+      '0.1.0',
+    ]);
+
+    const sources = path.join(work, 'cargo-package-sources');
+    const carrierName = 'oliphaunt-extension-contrib-pg18-wasix';
+    const extensionVersion = extensionReleaseVersion(
+      'oliphaunt-extension-contrib-pg18',
+      'wasix',
+      'package-liboliphaunt-wasix-cargo-artifacts.test',
+    );
+    const carrierManifest = Bun.TOML.parse(
+      readFileSync(path.join(sources, carrierName, 'Cargo.toml'), 'utf8'),
+    );
+    const partNames = Object.keys(carrierManifest['build-dependencies'])
+      .filter((name) => name.startsWith(`${carrierName}-part-`))
+      .sort();
+    expect(partNames.length).toBeGreaterThan(1);
+    expect(partNames[0]).toBe(`${carrierName}-part-001`);
+    expect(partNames).toEqual(
+      partNames.map((_, index) => `${carrierName}-part-${String(index + 1).padStart(3, '0')}`),
+    );
+    expect(partNames.every((name) => name.length <= 64)).toBe(true);
+
+    const runtimeName = 'liboliphaunt-wasix-portable';
+    const runtimeSource = path.join(sources, runtimeName);
+    cpSync(path.join(ROOT, 'src/runtimes/liboliphaunt-wasix/crates/assets'), runtimeSource, {
+      recursive: true,
+      filter: (source) => !['target', 'payload', 'artifacts'].includes(path.basename(source)),
+    });
+    const members = extensionSqlNames(
+      'oliphaunt-extension-contrib-pg18',
+      'package-liboliphaunt-wasix-cargo-artifacts.test',
+    ).map((sqlName) => ({ sqlName, dependencies: sqlName === 'earthdistance' ? ['cube'] : [] }));
+    const runtimeCargoToml = path.join(runtimeSource, 'Cargo.toml');
+    const aotSources = Object.values(AOT_TARGET_TRIPLES).map((target) => ({
+      spec: {
+        name: wasixExtensionAotPackageName('oliphaunt-extension-contrib-pg18', target),
+        product: 'oliphaunt-extension-contrib-pg18',
+        target,
+        dependencyRequirement: `=${extensionVersion}`,
+      },
+    }));
+    writeFileSync(
+      runtimeCargoToml,
+      injectRuntimeExtensionDependencies(
+        readFileSync(runtimeCargoToml, 'utf8'),
+        [
+          {
+            spec: {
+              name: carrierName,
+              product: 'oliphaunt-extension-contrib-pg18',
+              dependencyRequirement: `=${extensionVersion}`,
+              members,
+            },
+          },
+        ],
+        aotSources,
+      ),
+    );
+    const hostTriple = supportedRustcHostTriple();
+    const app = path.join(root, 'app');
+    mkdirSync(path.join(app, 'src'), { recursive: true });
+    writeFileSync(
+      path.join(app, 'Cargo.toml'),
+      `[package]
+name = "wasix-selection-proof"
+version = "0.0.0"
+edition = "2024"
+
+[dependencies]
+liboliphaunt-wasix-portable = { path = ${JSON.stringify(path.join(sources, runtimeName))}, features = ["extension-earthdistance"] }
+
+[workspace]
+`,
+    );
+    writeFileSync(
+      path.join(app, 'src/main.rs'),
+      `fn main() {
+    let selected = liboliphaunt_wasix_portable::SELECTED_EXTENSION_SQL_NAMES;
+    assert!(selected.contains(&"earthdistance"));
+    assert!(selected.contains(&"cube"));
+    assert!(!selected.contains(&"hstore"));
+    assert!(liboliphaunt_wasix_portable::extension_archive("earthdistance").is_some());
+    assert!(liboliphaunt_wasix_portable::extension_archive("cube").is_some());
+    assert!(liboliphaunt_wasix_portable::extension_archive("hstore").is_none());
+    assert!(liboliphaunt_wasix_portable::SELECTED_EXTENSION_AOT_SQL_NAMES.contains(&"earthdistance"));
+    assert!(liboliphaunt_wasix_portable::SELECTED_EXTENSION_AOT_SQL_NAMES.contains(&"cube"));
+    assert!(!liboliphaunt_wasix_portable::SELECTED_EXTENSION_AOT_SQL_NAMES.contains(&"hstore"));
+    assert!(liboliphaunt_wasix_portable::extension_aot_manifest_json(${JSON.stringify(hostTriple)}, "earthdistance").is_some());
+    assert!(liboliphaunt_wasix_portable::extension_aot_manifest_json(${JSON.stringify(hostTriple)}, "cube").is_some());
+    assert!(liboliphaunt_wasix_portable::extension_aot_manifest_json(${JSON.stringify(hostTriple)}, "hstore").is_none());
+}
+`,
+    );
+    const packages = JSON.parse(readFileSync(path.join(output, 'packages.json'), 'utf8')).packages;
+    expect(packages.filter((row) => row.name.startsWith(`${carrierName}-part-`)).length).toBe(
+      partNames.length,
+    );
+    for (const target of Object.values(AOT_TARGET_TRIPLES)) {
+      const parent = wasixExtensionAotPackageName('oliphaunt-extension-contrib-pg18', target);
+      expect(packages.some((row) => row.name === parent)).toBe(true);
+      expect(packages.some((row) => row.name === `${parent}-part-001`)).toBe(true);
+    }
+    expect(packages.every((row) => row.size <= 10 * 1024 * 1024)).toBe(true);
+  });
+});
diff --git a/src/runtimes/liboliphaunt-wasix/tools/package-release-assets.mts b/src/runtimes/liboliphaunt-wasix/tools/package-release-assets.mts
new file mode 100644
index 000000000..d43deac44
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/package-release-assets.mts
@@ -0,0 +1,202 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { requireSafeDirectoryChain } from '../../../../tools/packaging/release-directory-safety.mts';
+import {
+  cpSync,
+  lstatSync,
+  mkdirSync,
+  mkdtempSync,
+  readdirSync,
+  readFileSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { createDeterministicTar } from '../../../../tools/packaging/archive-directory.mts';
+import {
+  portableMemberName,
+  releaseZstdCompressSync,
+} from '../../../../tools/packaging/portable-archive.mts';
+import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts';
+import {
+  ROOT,
+  currentProductVersionSync,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { assertCanonicalWasixAotManifest } from './wasix-aot-manifest.mts';
+import { AOT_TARGET_TRIPLES } from './wasix-cargo-artifact-contract.mts';
+import { main as checkReleaseAssets } from './check-release-assets.mts';
+
+const ASSETS = 'target/oliphaunt-wasix/assets';
+const AOT = 'target/oliphaunt-wasix/aot';
+const json = (file) => {
+  requireSafeDirectoryChain(path.dirname(file));
+  assert(regularEntry(file).isFile(), 'manifest must be a regular file: ' + file);
+  return JSON.parse(readFileSync(file, 'utf8'));
+};
+const writeJson = (file, value) => writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
+const sha256 = (bytes) => createHash('sha256').update(bytes).digest('hex');
+
+function regularEntry(file) {
+  const stat = lstatSync(file);
+  assert(
+    stat.isDirectory() || stat.isFile(),
+    `payload must contain only regular files and directories: ${file}`,
+  );
+  return stat;
+}
+
+function copyTree(source, destination) {
+  requireSafeDirectoryChain(path.dirname(source));
+  mkdirSync(path.dirname(destination), { recursive: true });
+  cpSync(source, destination, {
+    recursive: true,
+    filter(file) {
+      regularEntry(file);
+      return true;
+    },
+  });
+}
+
+export function postgresSourceFingerprint() {
+  const { postgresql } = Bun.TOML.parse(
+    readFileSync(path.join(ROOT, 'src/third-party/postgres/source.toml'), 'utf8'),
+  );
+  const patches = ROOT;
+  const series = 'src/runtimes/liboliphaunt-wasix/postgres/series';
+  const names = readFileSync(path.join(patches, series), 'utf8')
+    .split(/\r?\n/)
+    .map((line) => line.trim())
+    .filter((line) => line && !line.startsWith('#'));
+  assert(
+    names.length &&
+      new Set(names).size === names.length &&
+      names.every(
+        (name) =>
+          name.endsWith('.patch') &&
+          !path.isAbsolute(name) &&
+          !name.includes('\\') &&
+          !name.split('/').includes('..'),
+      ),
+    'invalid PostgreSQL patch series',
+  );
+  const hashes = [series, ...names]
+    .map(
+      (name) =>
+        sha256(readFileSync(path.join(patches, name), 'utf8').replaceAll('\r\n', '\n')) + '\n',
+    )
+    .join('');
+  return `${postgresql.version}:${postgresql.sha256}:${sha256(hashes)}`;
+}
+
+function assertSource(manifest, fingerprint) {
+  assert.equal(manifest['source-fingerprint'], fingerprint, 'stale PostgreSQL source fingerprint');
+  assert.equal(manifest['source-lane'] ?? 'stable', 'stable', 'unsupported WASIX source lane');
+  assert.match(
+    manifest.runtime?.['postgres-version'] ?? manifest['postgres-version'] ?? '18.',
+    /^18\./,
+  );
+}
+
+export function stagePortableAssets(source, destination, fingerprint) {
+  const manifest = json(path.join(source, 'manifest.json'));
+  assertSource(manifest, fingerprint);
+  assert(
+    !Object.hasOwn(manifest, 'cluster-seeds'),
+    'runtime manifest still bundles cluster seeds; rebuild runtime assets',
+  );
+  assert(Array.isArray(manifest.extensions), 'portable manifest must contain an extensions array');
+  cpSync(source, destination, {
+    recursive: true,
+    filter(file) {
+      const relative = path.relative(source, file).split(path.sep).join('/');
+      if (['extensions', 'cluster-seeds'].includes(relative.split('/')[0])) return false;
+      if (
+        ['bin/pg_dump.wasix.wasm', 'bin/psql.wasix.wasm', 'bin/pg_ctl.wasix.wasm'].includes(
+          relative,
+        )
+      )
+        return false;
+      regularEntry(file);
+      return true;
+    },
+  });
+  manifest.extensions = [];
+  delete manifest['pg-dump'];
+  delete manifest.psql;
+  writeJson(path.join(destination, 'manifest.json'), manifest);
+}
+
+export function stageAotAssets(source, destination, target, fingerprint) {
+  const manifest = json(path.join(source, 'manifest.json'));
+  assertCanonicalWasixAotManifest(manifest, { expectedTarget: target });
+  assertSource(manifest, fingerprint);
+  assert(
+    Array.isArray(manifest.artifacts) && manifest.artifacts.length,
+    'empty AOT artifact manifest',
+  );
+  mkdirSync(destination, { recursive: true });
+  manifest.artifacts = manifest.artifacts.filter((artifact) => {
+    assert.equal(typeof artifact.name, 'string', 'missing AOT artifact name');
+    assert.equal(typeof artifact.path, 'string', 'missing AOT artifact path');
+    assert.equal(
+      portableMemberName(artifact.path, 'file', source),
+      artifact.path,
+      'noncanonical AOT artifact path',
+    );
+    if (artifact.name.startsWith('extension:') || artifact.name.startsWith('tool:')) return false;
+    copyTree(path.join(source, artifact.path), path.join(destination, artifact.path));
+    return true;
+  });
+  writeJson(path.join(destination, 'manifest.json'), manifest);
+}
+
+async function main() {
+  const output = path.join(ROOT, 'target/oliphaunt-wasix/release-assets');
+  const version = currentProductVersionSync('liboliphaunt-wasix');
+  const fingerprint = postgresSourceFingerprint();
+  mkdirSync(output, { recursive: true });
+  const staging = mkdtempSync(path.join(output, '.staging-'));
+  const checksums = [];
+  async function archive(stage, name) {
+    const bytes = releaseZstdCompressSync(await createDeterministicTar(stage));
+    writeFileSync(path.join(staging, name), bytes);
+    checksums.push(`${sha256(bytes)}  ./${name}`);
+    rmSync(stage, { recursive: true });
+  }
+  try {
+    const portable = path.join(staging, 'portable');
+    stagePortableAssets(path.join(ROOT, ASSETS), path.join(portable, ASSETS), fingerprint);
+    for (const generated of [
+      'src/extensions/generated',
+      'src/runtimes/liboliphaunt-wasix/assets/generated',
+    ]) {
+      copyTree(path.join(ROOT, generated), path.join(portable, generated));
+    }
+    stageReleaseNotices(portable, { profile: 'wasix-runtime' });
+    await archive(portable, `liboliphaunt-wasix-${version}-runtime-portable.tar.zst`);
+    for (const [id, triple] of Object.entries(AOT_TARGET_TRIPLES)) {
+      const stage = path.join(staging, id);
+      const payload = path.join(stage, AOT, triple);
+      stageAotAssets(path.join(ROOT, AOT, triple), payload, triple, fingerprint);
+      stageReleaseNotices(payload, { profile: 'wasix-aot' });
+      await archive(stage, `liboliphaunt-wasix-${version}-runtime-aot-${id}.tar.zst`);
+    }
+    writeFileSync(
+      path.join(staging, `liboliphaunt-wasix-${version}-release-assets.sha256`),
+      checksums.sort().join('\n') + '\n',
+    );
+    checkReleaseAssets(['--asset-dir', staging, '--version', version]);
+    for (const name of readdirSync(output)) {
+      if (name !== path.basename(staging))
+        rmSync(path.join(output, name), { recursive: true, force: true });
+    }
+    for (const name of readdirSync(staging))
+      copyTree(path.join(staging, name), path.join(output, name));
+    console.log(`packaged public release assets in ${output}`);
+  } finally {
+    rmSync(staging, { recursive: true, force: true });
+  }
+}
+
+if (import.meta.main) await main();
diff --git a/src/runtimes/liboliphaunt-wasix/tools/package-release-assets.test.mts b/src/runtimes/liboliphaunt-wasix/tools/package-release-assets.test.mts
new file mode 100644
index 000000000..f11b1b262
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/package-release-assets.test.mts
@@ -0,0 +1,93 @@
+import assert from 'node:assert/strict';
+import {
+  mkdirSync,
+  mkdtempSync,
+  readFileSync,
+  readdirSync,
+  rmSync,
+  symlinkSync,
+  writeFileSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { stageAotAssets, stagePortableAssets } from './package-release-assets.mts';
+import { canonicalWasixAotMetadata } from './wasix-aot-manifest.mts';
+
+test('release staging excludes independent tools and extensions, and rejects stale or unsafe inputs', (t) => {
+  const root = mkdtempSync(path.join(tmpdir(), 'wasix-release-stage-'));
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+  const write = (name, bytes) => {
+    const file = path.join(root, name);
+    mkdirSync(path.dirname(file), { recursive: true });
+    writeFileSync(file, bytes);
+    return file;
+  };
+  const portable = path.join(root, 'portable');
+  write('portable/oliphaunt.wasix.tar.zst', 'runtime');
+  write('portable/bin/pg_dump.wasix.wasm', 'dump');
+  write('portable/bin/psql.wasix.wasm', 'sql');
+  write('portable/extensions/pgvector.tar.zst', 'extension');
+  write(
+    'portable/manifest.json',
+    JSON.stringify({
+      'source-fingerprint': 'source',
+      runtime: { 'postgres-version': '18.4' },
+      extensions: ['pgvector'],
+      'pg-dump': {},
+      psql: {},
+    }),
+  );
+  stagePortableAssets(portable, path.join(root, 'portable-out'), 'source');
+  assert.equal(
+    readFileSync(path.join(root, 'portable-out/oliphaunt.wasix.tar.zst'), 'utf8'),
+    'runtime',
+  );
+  assert(!readdirSync(path.join(root, 'portable-out')).includes('extensions'));
+  assert.deepEqual(readdirSync(path.join(root, 'portable-out/bin')), []);
+  const manifest = JSON.parse(readFileSync(path.join(root, 'portable-out/manifest.json'), 'utf8'));
+  assert.deepEqual(manifest.extensions, []);
+  assert(!('pg-dump' in manifest) && !('psql' in manifest));
+  assert.throws(
+    () => stagePortableAssets(portable, path.join(root, 'stale'), 'new-source'),
+    /fingerprint/,
+  );
+
+  const canonical = canonicalWasixAotMetadata();
+  const aot = {
+    'format-version': 1,
+    'source-lane': 'stable',
+    'source-fingerprint': 'source',
+    'target-triple': 'x86_64-unknown-linux-gnu',
+    engine: canonical.engine,
+    'wasmer-version': canonical.wasmerVersion,
+    'wasmer-wasix-version': canonical.wasmerWasixVersion,
+    artifacts: [
+      { name: 'runtime:oliphaunt', path: 'nested/runtime.bin.zst' },
+      { name: 'tool:pg_dump', path: 'pg_dump.bin.zst' },
+      { name: 'tool:psql', path: 'psql.bin.zst' },
+      { name: 'extension:vector:module', path: 'vector.bin.zst' },
+    ],
+  };
+  const source = path.join(root, 'aot');
+  const save = () => write('aot/manifest.json', JSON.stringify(aot));
+  save();
+  for (const artifact of aot.artifacts) write(`aot/${artifact.path}`, artifact.name);
+  const stage = (name) =>
+    stageAotAssets(source, path.join(root, name), aot['target-triple'], 'source');
+  stage('aot-out');
+  assert.equal(
+    readFileSync(path.join(root, 'aot-out/nested/runtime.bin.zst'), 'utf8'),
+    'runtime:oliphaunt',
+  );
+  assert.deepEqual(readdirSync(path.join(root, 'aot-out')).sort(), ['manifest.json', 'nested']);
+  aot.artifacts[0].path = '../outside';
+  save();
+  assert.throws(() => stage('traversal'), /unsafe|relative|component/);
+  aot.artifacts[0].path = 'linked/file';
+  save();
+  write('outside/file', 'outside');
+  if (process.platform === 'win32') return;
+  symlinkSync(path.join(root, 'outside'), path.join(source, 'linked'), 'dir');
+  assert.throws(() => stage('linked'), /symbolic|symlink/);
+});
diff --git a/src/runtimes/liboliphaunt-wasix/tools/package_liboliphaunt_wasix_cargo_artifacts.mts b/src/runtimes/liboliphaunt-wasix/tools/package_liboliphaunt_wasix_cargo_artifacts.mts
new file mode 100755
index 000000000..2fa9d3964
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/package_liboliphaunt_wasix_cargo_artifacts.mts
@@ -0,0 +1,1792 @@
+#!/usr/bin/env bun
+import { createHash } from 'node:crypto';
+import fs, {
+  chmodSync,
+  copyFileSync,
+  cpSync,
+  existsSync,
+  lstatSync,
+  mkdirSync,
+  readFileSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import {
+  assertExtensionUpstreamLicensesInArchive,
+  assertExtensionUpstreamLicensesInDirectory,
+  extensionRegistryLicense,
+  stageExtensionUpstreamLicenses,
+} from '../../../extensions/tools/extension-upstream-licenses.mts';
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import {
+  portableMemberName,
+  readPortableArchiveEntries,
+  readPortableTarZstdBufferEntries,
+  releaseZstdCompressSync,
+} from '../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  releaseNoticeRows,
+  releaseProfilePackageLicense,
+  stageReleaseNotices,
+} from '../../../../tools/packaging/release-notices.mts';
+import { RUST_BUILD_SCRIPT_SHA256 } from '../../../../tools/packaging/rust-build-script-sha256.mts';
+import {
+  cargoPackage,
+  packageSpec,
+  validateCrateSize,
+} from '../../../../tools/packaging/wasix-cargo-payload.mts';
+import {
+  currentProductVersionSync,
+  extensionMetadata,
+  extensionReleaseProduct,
+  extensionReleaseVersion,
+  extensionSqlNames,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { compareText } from '../../../../tools/release/release-graph.mts';
+import { assertWasixAotArtifactPayloads } from './check-release-assets.mts';
+import { assertCanonicalWasixAotManifest } from './wasix-aot-manifest.mts';
+import {
+  AOT_PACKAGES,
+  AOT_TARGET_CFGS,
+  AOT_TARGET_TRIPLES,
+  CORE_RUNTIME_ARCHIVE_FILES,
+  expectedExtensionAotTargets,
+  FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES,
+  RUNTIME_PACKAGE,
+  TOOLS_AOT_ARTIFACTS,
+  TOOLS_PAYLOAD_FILES,
+  WASIX_CARGO_ARTIFACT_SCHEMA,
+  wasixExtensionAotPackageName,
+  wasixExtensionPackageName,
+} from './wasix-cargo-artifact-contract.mts';
+
+const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
+const PRODUCT = 'liboliphaunt-wasix';
+const PREFIX = 'package_liboliphaunt_wasix_cargo_artifacts.mts';
+const DEFAULT_EXTENSION_PART_BYTES = 8 * 1024 * 1024;
+const EXPECTED_EXTENSION_AOT_TARGETS = new Set(expectedExtensionAotTargets());
+
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+
+function rel(file) {
+  const relative = path.relative(ROOT, String(file));
+  if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
+    return String(file).split(path.sep).join('/');
+  }
+  return relative.split(path.sep).join('/');
+}
+
+function isFile(file) {
+  try {
+    const metadata = lstatSync(file);
+    return metadata.isFile() && !metadata.isSymbolicLink();
+  } catch {
+    return false;
+  }
+}
+
+function isDirectory(file) {
+  try {
+    const metadata = lstatSync(file);
+    return metadata.isDirectory() && !metadata.isSymbolicLink();
+  } catch {
+    return false;
+  }
+}
+
+function sha256File(file) {
+  const digest = createHash('sha256');
+  const data = readFileSync(file);
+  digest.update(data);
+  return digest.digest('hex');
+}
+
+function checkedTarMember(name, archive) {
+  if (typeof name !== 'string' || name.length === 0) {
+    fail(`${rel(archive)} contains an empty archive member path`);
+  }
+  let normalized;
+  try {
+    normalized = portableMemberName(name, 'file', rel(archive));
+  } catch (error) {
+    fail(error.message);
+  }
+  if (normalized !== name) {
+    fail(`${rel(archive)} archive member path must already be normalized: ${JSON.stringify(name)}`);
+  }
+  return normalized;
+}
+
+function tarZstdMembers(archive) {
+  try {
+    return [...readPortableArchiveEntries(archive, { format: 'tar.zst' }).keys()];
+  } catch (error) {
+    fail(error.message);
+  }
+}
+
+export function extractTarZstd(archive, destination) {
+  let entries;
+  try {
+    entries = readPortableArchiveEntries(archive, { format: 'tar.zst' });
+  } catch (error) {
+    fail(error.message);
+  }
+  rmSync(destination, { recursive: true, force: true });
+  const root = path.resolve(destination);
+  mkdirSync(root, { recursive: true, mode: 0o700 });
+  chmodSync(root, 0o700);
+
+  const outputPath = (member) => {
+    const output = path.resolve(root, ...member.split('/'));
+    if (!output.startsWith(`${root}${path.sep}`)) {
+      fail(`${rel(archive)} resolved outside its extraction destination: ${member}`);
+    }
+    return output;
+  };
+  const directoryModes = new Map();
+  for (const entry of entries.values()) {
+    const parts = entry.name.split('/');
+    const parentLength = entry.isDirectory ? parts.length : parts.length - 1;
+    for (let length = 1; length <= parentLength; length += 1) {
+      const member = parts.slice(0, length).join('/');
+      if (!directoryModes.has(member)) directoryModes.set(member, 0o755);
+    }
+    if (entry.isDirectory) directoryModes.set(entry.name, entry.mode & 0o777);
+  }
+  const directories = [...directoryModes].sort(([left], [right]) => {
+    const depth = left.split('/').length - right.split('/').length;
+    return depth || compareText(left, right);
+  });
+  for (const [member, finalMode] of directories) {
+    const output = outputPath(member);
+    mkdirSync(output, { recursive: true, mode: finalMode | 0o700 });
+    // Creation modes are filtered by the process umask. Keep the complete
+    // tree owner-writable/traversable until every descendant has been staged.
+    chmodSync(output, finalMode | 0o700);
+  }
+
+  const files = [...entries.values()]
+    .filter((entry) => !entry.isDirectory)
+    .sort((left, right) => compareText(left.name, right.name));
+  for (const entry of files) {
+    const output = outputPath(entry.name);
+    if (!entry.isFile || entry.isSymbolicLink) {
+      fail(`${rel(archive)} contains a non-regular extraction member ${entry.name}`);
+    }
+    writeFileSync(output, entry.data(), { flag: 'wx', mode: 0o600 });
+    // chmod after creation makes the archive contract independent of umask.
+    chmodSync(output, entry.mode & 0o777);
+  }
+
+  for (const [member, finalMode] of directories.reverse()) {
+    chmodSync(outputPath(member), finalMode);
+  }
+}
+
+function writeTarZstdArchive(sourceRoot, output, archiveRoot) {
+  mkdirSync(path.dirname(output), { recursive: true });
+  rmSync(output, { force: true });
+  const tar = createDeterministicTar(sourceRoot, archiveRoot, { fail });
+  writeFileSync(output, releaseZstdCompressSync(tar));
+}
+
+function payloadFiles(sourceRoot) {
+  const files = [];
+  if (!existsSync(sourceRoot)) {
+    return files;
+  }
+  for (const entry of fs.readdirSync(sourceRoot, { withFileTypes: true })) {
+    const fullPath = path.join(sourceRoot, entry.name);
+    if (entry.isDirectory()) {
+      files.push(...payloadFiles(fullPath));
+    } else if (entry.isFile()) {
+      files.push(fullPath);
+    }
+  }
+  return files.sort(compareText);
+}
+
+function targetAssetRoot(extracted) {
+  const root = path.join(extracted, 'target/oliphaunt-wasix/assets');
+  if (!isFile(path.join(root, 'manifest.json'))) {
+    fail(`${rel(extracted)} does not contain target/oliphaunt-wasix/assets/manifest.json`);
+  }
+  return root;
+}
+
+function targetAotRoot(extracted, triple) {
+  const root = path.join(extracted, 'target/oliphaunt-wasix/aot', triple);
+  if (!isFile(path.join(root, 'manifest.json'))) {
+    fail(`${rel(extracted)} does not contain target/oliphaunt-wasix/aot/${triple}/manifest.json`);
+  }
+  return root;
+}
+
+function readJson(file) {
+  try {
+    return JSON.parse(readFileSync(file, 'utf8'));
+  } catch (error) {
+    fail(`${rel(file)} is not valid JSON: ${error.message}`);
+  }
+}
+
+function validateCanonicalAotManifest(manifest, manifestPath, expectedTarget) {
+  try {
+    assertCanonicalWasixAotManifest(manifest, {
+      context: rel(manifestPath),
+      expectedTarget,
+    });
+  } catch (error) {
+    fail(error.message);
+  }
+}
+
+export function validateRuntimePayload(root) {
+  const extensionRoot = path.join(root, 'extensions');
+  const extensionFiles = isDirectory(extensionRoot) ? payloadFiles(extensionRoot) : [];
+  if (extensionFiles.length > 0) {
+    fail(
+      `WASIX runtime Cargo payload must not contain extension archives: ${extensionFiles.slice(0, 5).map(rel).join(', ')}`,
+    );
+  }
+  const manifestPath = path.join(root, 'manifest.json');
+  const manifest = readJson(manifestPath);
+  if (JSON.stringify(manifest.extensions) !== '[]') {
+    fail(`${rel(manifestPath)} must have an empty extensions array`);
+  }
+  for (const toolKey of ['pg-dump', 'psql']) {
+    if (Object.hasOwn(manifest, toolKey)) {
+      fail(`${rel(manifestPath)} must not contain split WASIX tool entry ${toolKey}`);
+    }
+  }
+  for (const required of ['oliphaunt.wasix.tar.zst', 'bin/initdb.wasix.wasm']) {
+    if (!isFile(path.join(root, required))) {
+      fail(`WASIX runtime Cargo payload is missing ${required}`);
+    }
+  }
+  if (
+    manifest.runtime === null ||
+    Array.isArray(manifest.runtime) ||
+    typeof manifest.runtime !== 'object'
+  ) {
+    fail(`${rel(manifestPath)} is missing runtime metadata`);
+  }
+  if (manifest.runtime.archive !== 'oliphaunt.wasix.tar.zst') {
+    fail(`${rel(manifestPath)} runtime.archive must be oliphaunt.wasix.tar.zst`);
+  }
+  if (
+    typeof manifest.runtime.sha256 !== 'string' ||
+    !/^[0-9a-f]{64}$/u.test(manifest.runtime.sha256)
+  ) {
+    fail(`${rel(manifestPath)} runtime.sha256 must be a lowercase SHA-256 digest`);
+  }
+  const runtimeArchivePath = path.join(root, 'oliphaunt.wasix.tar.zst');
+  const runtimeBytes = readFileSync(runtimeArchivePath);
+  const runtimeSha256 = createHash('sha256').update(runtimeBytes).digest('hex');
+  if (runtimeSha256 !== manifest.runtime.sha256) {
+    fail(
+      `${rel(manifestPath)} runtime.sha256 mismatch: expected ${manifest.runtime.sha256}, got ${runtimeSha256}`,
+    );
+  }
+  let runtimeEntries;
+  try {
+    runtimeEntries = readPortableTarZstdBufferEntries(runtimeBytes, {
+      label: `${rel(manifestPath)} runtime archive`,
+    });
+  } catch (error) {
+    fail(error.message);
+  }
+  const runtimeMembers = [...runtimeEntries.keys()];
+  const missingCoreRuntimeFiles = CORE_RUNTIME_ARCHIVE_FILES.filter((member) => {
+    const entry = runtimeEntries.get(member);
+    return entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0;
+  }).sort(compareText);
+  if (missingCoreRuntimeFiles.length > 0) {
+    fail(
+      `WASIX runtime Cargo payload must bundle the core runtime closure inside oliphaunt.wasix.tar.zst; missing ${missingCoreRuntimeFiles.join(', ')}`,
+    );
+  }
+  const bundledIcu = runtimeMembers.filter(
+    (member) => member === 'oliphaunt/share/icu' || member.startsWith('oliphaunt/share/icu/'),
+  );
+  if (bundledIcu.length > 0) {
+    fail(
+      `WASIX runtime Cargo payload must not bundle ICU data; found ${bundledIcu[0]} in oliphaunt.wasix.tar.zst`,
+    );
+  }
+  const bundledTools = runtimeMembers
+    .filter((member) => FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES.includes(member))
+    .sort(compareText);
+  if (bundledTools.length > 0) {
+    fail(
+      `WASIX runtime Cargo payload must not bundle standalone tools inside oliphaunt.wasix.tar.zst; found ${bundledTools[0]}`,
+    );
+  }
+}
+
+function relPath(root, file) {
+  return path.relative(root, file).split(path.sep).join('/');
+}
+
+function sameSet(left, right) {
+  if (left.size !== right.size) {
+    return false;
+  }
+  for (const item of left) {
+    if (!right.has(item)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+function pruneEmptyDirs(root) {
+  if (!isDirectory(root)) {
+    return;
+  }
+  const dirs = [];
+  for (const item of fs.readdirSync(root, { withFileTypes: true })) {
+    const fullPath = path.join(root, item.name);
+    if (item.isDirectory()) {
+      pruneEmptyDirs(fullPath);
+      dirs.push(fullPath);
+    }
+  }
+  for (const dir of dirs.sort(compareText).reverse()) {
+    try {
+      fs.rmdirSync(dir);
+    } catch {
+      // Directory still has payload files.
+    }
+  }
+}
+
+function pruneRuntimeArchiveTools(archive, scratch) {
+  const runtimeMembers = tarZstdMembers(archive);
+  if (!runtimeMembers.some((member) => FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES.includes(member))) {
+    return;
+  }
+  extractTarZstd(archive, scratch);
+  for (const member of FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES) {
+    const file = path.join(scratch, member);
+    if (existsSync(file)) {
+      fs.unlinkSync(file);
+    }
+  }
+  pruneEmptyDirs(scratch);
+  const replacement = `${archive}.tmp`;
+  writeTarZstdArchive(path.join(scratch, 'oliphaunt'), replacement, 'oliphaunt');
+  fs.renameSync(replacement, archive);
+}
+
+function rewriteRuntimeCoreManifest(root) {
+  const manifestPath = path.join(root, 'manifest.json');
+  const manifest = readJson(manifestPath);
+  if (
+    !manifest.runtime ||
+    typeof manifest.runtime !== 'object' ||
+    Array.isArray(manifest.runtime)
+  ) {
+    fail(`${rel(manifestPath)} is missing runtime metadata`);
+  }
+  manifest.runtime.sha256 = sha256File(path.join(root, 'oliphaunt.wasix.tar.zst'));
+  manifest.extensions = [];
+  delete manifest['pg-dump'];
+  delete manifest.psql;
+  writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
+}
+
+function runtimeCorePayload(runtimeRoot, extractRoot) {
+  const coreRoot = path.join(extractRoot, 'runtime-core-payload');
+  rmSync(coreRoot, { recursive: true, force: true });
+  cpSync(runtimeRoot, coreRoot, { recursive: true });
+  rmSync(path.join(coreRoot, 'extensions'), { recursive: true, force: true });
+  for (const relative of TOOLS_PAYLOAD_FILES)
+    rmSync(path.join(coreRoot, relative), { force: true });
+  pruneRuntimeArchiveTools(
+    path.join(coreRoot, 'oliphaunt.wasix.tar.zst'),
+    path.join(extractRoot, 'runtime-archive-core-pruned'),
+  );
+  rewriteRuntimeCoreManifest(coreRoot);
+  pruneEmptyDirs(coreRoot);
+  return coreRoot;
+}
+
+export function validateAotPayload(root, expectedTarget) {
+  const manifestPath = path.join(root, 'manifest.json');
+  const manifest = readJson(manifestPath);
+  validateCanonicalAotManifest(manifest, manifestPath, expectedTarget);
+  let artifactRows;
+  try {
+    artifactRows = assertWasixAotArtifactPayloads(manifest, {
+      context: rel(manifestPath),
+      readArtifact(artifactPath) {
+        const file = path.join(root, ...artifactPath.split('/'));
+        if (!isFile(file) || statSync(file).size <= 0) {
+          throw new Error(
+            `${rel(manifestPath)} AOT artifact ${artifactPath} must be a non-empty regular file`,
+          );
+        }
+        return readFileSync(file);
+      },
+    });
+  } catch (error) {
+    fail(error.message);
+  }
+  const expected = new Set([
+    'manifest.json',
+    ...releaseNoticeRows({ profile: 'wasix-aot' }).map((row) => row.member),
+  ]);
+  for (const row of artifactRows) {
+    if (row.name.startsWith('extension:')) {
+      fail(`WASIX AOT Cargo payload must not contain extension artifact ${row.name}`);
+    }
+    expected.add(row.path);
+  }
+  assertReleaseNoticesInDirectory(root, { profile: 'wasix-aot' });
+  const actual = new Set(payloadFiles(root).map((file) => relPath(root, file)));
+  if (!sameSet(actual, expected)) {
+    fail(
+      `WASIX AOT Cargo payload file set mismatch for ${rel(root)}: expected ${JSON.stringify([...expected].sort(compareText))}, got ${JSON.stringify([...actual].sort(compareText))}`,
+    );
+  }
+}
+
+function runtimeAotPayload(aotRoot, extractRoot, targetId) {
+  const manifest = readJson(path.join(aotRoot, 'manifest.json'));
+  const artifacts = manifest.artifacts.filter((row) => !TOOLS_AOT_ARTIFACTS.includes(row.name));
+  if (artifacts.length === 0) fail('WASIX AOT runtime contains no runtime artifacts');
+  const destination = path.join(extractRoot, `${targetId}-aot-core-payload`);
+  rmSync(destination, { recursive: true, force: true });
+  mkdirSync(destination, { recursive: true });
+  for (const row of artifacts) {
+    const file = path.join(destination, row.path);
+    mkdirSync(path.dirname(file), { recursive: true });
+    copyFileSync(path.join(aotRoot, row.path), file);
+  }
+  writeFileSync(
+    path.join(destination, 'manifest.json'),
+    `${JSON.stringify({ ...manifest, artifacts }, null, 2)}\n`,
+  );
+  return destination;
+}
+
+function extensionSqlFeatureName(sqlName) {
+  if (typeof sqlName !== 'string' || !/^[a-z0-9][a-z0-9_-]*$/u.test(sqlName)) {
+    fail(`invalid extension SQL feature name ${JSON.stringify(sqlName)}`);
+  }
+  return `extension-${sqlName.replaceAll('_', '-')}`;
+}
+
+export function extensionDependencyRequirement(version, versioning) {
+  const match = version.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)$/u);
+  if (match === null) {
+    fail(`extension dependency version must be stable x.y.z, got ${JSON.stringify(version)}`);
+  }
+  if (versioning !== 'upstream-bound') {
+    return `=${version}`;
+  }
+  const major = Number.parseInt(match[1], 10);
+  const minor = Number.parseInt(match[2], 10);
+  const upper = major >= 1 ? `${major + 1}.0.0` : `0.${minor + 1}.0`;
+  return `>=${version},<${upper}`;
+}
+
+export function injectRuntimeExtensionDependencies(text, extensionSources, extensionAotSources) {
+  const dependencyLines = [];
+  const targetDependencyLines = new Map();
+  const aotByExtension = new Map();
+  for (const source of extensionAotSources) {
+    const list = aotByExtension.get(source.spec.product) ?? [];
+    list.push(source);
+    aotByExtension.set(source.spec.product, list);
+  }
+  for (const source of extensionSources) {
+    const packageName = source.spec.name;
+    dependencyLines.push(
+      `${packageName} = { version = "${source.spec.dependencyRequirement}", path = "../${packageName}", optional = true }`,
+    );
+    const carrierDependencies = [`dep:${packageName}`];
+    for (const aotSource of (aotByExtension.get(source.spec.product) ?? []).sort((left, right) =>
+      compareText(left.spec.name, right.spec.name),
+    )) {
+      carrierDependencies.push(`dep:${aotSource.spec.name}`);
+    }
+    for (const member of source.spec.members) {
+      const feature = extensionSqlFeatureName(member.sqlName);
+      const closureFeatures = member.dependencies.map(extensionSqlFeatureName);
+      const featureDeps = [...new Set([...closureFeatures, ...carrierDependencies])];
+      const replacement = `${feature} = [${featureDeps.map((dep) => JSON.stringify(dep)).join(', ')}]`;
+      const pattern = new RegExp(`^${escapeRegExp(feature)} = \\[[^\\n]*\\]$`, 'mu');
+      if (pattern.test(text)) {
+        text = text.replace(pattern, replacement);
+      } else {
+        text = text.replace('[features]\n', `[features]\n${replacement}\n`);
+      }
+    }
+  }
+  for (const source of extensionAotSources) {
+    const cfg = AOT_TARGET_CFGS[source.spec.target];
+    if (cfg === undefined) {
+      fail(`unsupported extension AOT target ${source.spec.target}`);
+    }
+    const line = `${source.spec.name} = { version = "${source.spec.dependencyRequirement}", path = "../${source.spec.name}", optional = true }`;
+    const lines = targetDependencyLines.get(cfg) ?? [];
+    lines.push(line);
+    targetDependencyLines.set(cfg, lines);
+  }
+  if (dependencyLines.length > 0) {
+    text = text.replace(
+      '\n[build-dependencies]',
+      `\n${dependencyLines.join('\n')}\n\n[build-dependencies]`,
+    );
+  }
+  if (targetDependencyLines.size > 0) {
+    const blocks = [...targetDependencyLines.entries()]
+      .sort(([left], [right]) => compareText(left, right))
+      .map(
+        ([cfg, lines]) => `[target.'${cfg}'.dependencies]\n${lines.sort(compareText).join('\n')}`,
+      );
+    text = text.replace(
+      '\n[build-dependencies]',
+      `\n${blocks.join('\n\n')}\n\n[build-dependencies]`,
+    );
+  }
+  return text;
+}
+
+function escapeRegExp(value) {
+  return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
+}
+
+function wasixExtensionPartPackageName(packageName, index) {
+  if (!Number.isSafeInteger(index) || index < 1 || index > 999) {
+    fail(
+      `WASIX extension Cargo part index must be 1-based in the range 1..999, got ${JSON.stringify(index)}`,
+    );
+  }
+  return `${packageName}-part-${String(index).padStart(3, '0')}`;
+}
+
+function rustCrateIdent(packageName) {
+  return packageName.replaceAll('-', '_');
+}
+
+function extensionCarrierLegal(spec, carriesBytes) {
+  if (!carriesBytes) {
+    return { profile: 'code-facade', packageSpdx: 'MIT', upstreamMembers: [] };
+  }
+  const sqlNames = spec.members.map((member) => member.sqlName);
+  const registry = extensionRegistryLicense(spec.product, sqlNames);
+  const contrib = spec.product === 'oliphaunt-extension-contrib-pg18';
+  const profile = contrib
+    ? sqlNames.includes('pgcrypto')
+      ? 'contrib-wasix-openssl'
+      : 'contrib-wasix'
+    : 'external-wasix';
+  return {
+    profile,
+    packageSpdx: contrib ? releaseProfilePackageLicense(profile).spdx : registry.packageSpdx,
+    upstreamMembers: contrib ? [] : sqlNames,
+  };
+}
+
+function stageExtensionCarrierLegal(crateDir, spec, carriesBytes) {
+  const legal = extensionCarrierLegal(spec, carriesBytes);
+  stageReleaseNotices(crateDir, { profile: legal.profile });
+  if (legal.upstreamMembers.length > 0) {
+    for (const sqlName of legal.upstreamMembers) stageExtensionUpstreamLicenses(sqlName, crateDir);
+    assertExtensionUpstreamLicensesInDirectory(legal.upstreamMembers, crateDir);
+  }
+  assertReleaseNoticesInDirectory(crateDir, { profile: legal.profile });
+  return legal;
+}
+
+function extensionCargoIncludes(crateDir, profile, values) {
+  const legal = releaseNoticeRows({ profile }).map((row) => row.member);
+  if (isDirectory(path.join(crateDir, 'share/licenses'))) legal.push('share/licenses/**');
+  return [...new Set([...values, ...legal])];
+}
+
+function writeExtensionPayloadPartSources({
+  parentName,
+  product,
+  version,
+  target,
+  subject,
+  members,
+  files,
+  sourceRoot,
+  partBytes,
+}) {
+  if (
+    !Number.isSafeInteger(partBytes) ||
+    partBytes < 1 ||
+    partBytes > DEFAULT_EXTENSION_PART_BYTES
+  ) {
+    fail(
+      `extension Cargo --part-bytes must be an integer in 1..${DEFAULT_EXTENSION_PART_BYTES}, got ${JSON.stringify(partBytes)}`,
+    );
+  }
+  const sortedFiles = [...files].sort((left, right) =>
+    compareText(left.payloadRelative, right.payloadRelative),
+  );
+  if (new Set(sortedFiles.map((file) => file.payloadRelative)).size !== sortedFiles.length) {
+    fail(`${product} ${target} extension Cargo payload repeats a relative file path`);
+  }
+  const parts = [];
+  let current = null;
+  const startPart = () => {
+    const index = parts.length + 1;
+    const name = wasixExtensionPartPackageName(parentName, index);
+    if (name.length > 64) fail(`generated crates.io package name exceeds 64 characters: ${name}`);
+    const sourceDir = path.join(sourceRoot, name);
+    if (existsSync(sourceDir))
+      fail(`duplicate generated WASIX extension Cargo part source: ${rel(sourceDir)}`);
+    mkdirSync(path.join(sourceDir, 'src'), { recursive: true });
+    current = { index, name, sourceDir, size: 0, target, version };
+    parts.push(current);
+    return current;
+  };
+  for (const file of sortedFiles) {
+    checkedTarMember(file.payloadRelative, file.source);
+    const size = statSync(file.source).size;
+    if (size > partBytes) {
+      current = null;
+      const bytes = readFileSync(file.source);
+      for (let offset = 0, chunk = 0; offset < bytes.length; offset += partBytes, chunk += 1) {
+        const part = startPart();
+        const destination = path.join(
+          part.sourceDir,
+          'payload/chunks',
+          `${file.payloadRelative}.part${String(chunk).padStart(6, '0')}`,
+        );
+        mkdirSync(path.dirname(destination), { recursive: true });
+        writeFileSync(
+          destination,
+          bytes.subarray(offset, Math.min(offset + partBytes, bytes.length)),
+        );
+        part.size = Math.min(partBytes, bytes.length - offset);
+      }
+      current = null;
+      continue;
+    }
+    if (current === null || current.size + size > partBytes) startPart();
+    const destination = path.join(current.sourceDir, 'payload/files', file.payloadRelative);
+    mkdirSync(path.dirname(destination), { recursive: true });
+    copyFileSync(file.source, destination);
+    current.size += size;
+  }
+  if (parts.length > 999)
+    fail(`${product}@${version} requires more than 999 Cargo payload parts for ${target}`);
+  for (const part of parts) {
+    const spec = { product, members };
+    const legal = stageExtensionCarrierLegal(part.sourceDir, spec, true);
+    part.noticeProfile = legal.profile;
+    part.upstreamMembers = legal.upstreamMembers;
+    const includes = extensionCargoIncludes(part.sourceDir, legal.profile, [
+      'Cargo.toml',
+      'README.md',
+      'src/**',
+      'payload/**',
+    ]);
+    writeFileSync(
+      path.join(part.sourceDir, 'README.md'),
+      [
+        `# ${part.name}`,
+        '',
+        `Cargo payload part ${String(part.index).padStart(3, '0')} for the ${subject} on \`${target}\`.`,
+        'Applications do not depend on this crate directly.',
+        '',
+      ].join('\n'),
+    );
+    writeFileSync(
+      path.join(part.sourceDir, 'Cargo.toml'),
+      [
+        '[package]',
+        `name = ${JSON.stringify(part.name)}`,
+        `version = ${JSON.stringify(version)}`,
+        'edition = "2024"',
+        'rust-version = "1.93"',
+        `description = ${JSON.stringify(`Cargo payload part for the ${subject} on ${target}`)}`,
+        'repository = "https://github.com/f0rr0/oliphaunt"',
+        'homepage = "https://oliphaunt.dev"',
+        `license = ${JSON.stringify(legal.packageSpdx)}`,
+        `include = [${includes.map((value) => JSON.stringify(value)).join(', ')}]`,
+        '',
+        '[lib]',
+        'path = "src/lib.rs"',
+        '',
+        '[workspace]',
+        '',
+      ].join('\n'),
+    );
+    writeFileSync(
+      path.join(part.sourceDir, 'src/lib.rs'),
+      [
+        '#![deny(unsafe_code)]',
+        `pub const PRODUCT: &str = ${JSON.stringify(product)};`,
+        `pub const TARGET: &str = ${JSON.stringify(target)};`,
+        `pub const PART_INDEX: usize = ${part.index};`,
+        'pub const PAYLOAD_ROOT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/payload");',
+        '',
+      ].join('\n'),
+    );
+  }
+  return parts;
+}
+
+function extensionArtifactBuildRs(spec, files, partSources) {
+  const schema =
+    spec.members.length > 1 ? 'oliphaunt-artifact-manifest-v2' : 'oliphaunt-artifact-manifest-v1';
+  const extensionRows = spec.members
+    .map(
+      (member) =>
+        `    (${JSON.stringify(member.sqlName)}, &[${member.dependencies.map((dependency) => JSON.stringify(dependency)).join(', ')}]),`,
+    )
+    .join('\n');
+  const fileRows = files
+    .map(
+      (file) =>
+        `    (${JSON.stringify(file.sqlName)}, ${JSON.stringify(file.payloadRelative)}, ${JSON.stringify(file.artifactRelative)}, ${JSON.stringify(file.sha256)}),`,
+    )
+    .join('\n');
+  const partRoots = partSources
+    .map((part) => `    ${rustCrateIdent(part.name)}::PAYLOAD_ROOT,`)
+    .join('\n');
+  return `use std::collections::{BTreeMap, BTreeSet};
+use std::env;
+use std::fs;
+use std::io::{self, Read};
+use std::path::{Path, PathBuf};
+
+const SCHEMA: &str = ${JSON.stringify(schema)};
+const PRODUCT: &str = ${JSON.stringify(spec.product)};
+const VERSION: &str = env!("CARGO_PKG_VERSION");
+const TARGET: &str = ${JSON.stringify(spec.target ?? 'portable')};
+const RUNTIME_PRODUCT: &str = ${JSON.stringify(spec.runtimeProduct)};
+const RUNTIME_VERSION: &str = ${JSON.stringify(spec.runtimeVersion)};
+const EXTENSIONS: &[(&str, &[&str])] = &[
+${extensionRows}
+];
+const FILES: &[(&str, &str, &str, &str)] = &[
+${fileRows}
+];
+const PART_ROOTS: &[&str] = &[
+${partRoots}
+];
+
+fn main() {
+    let manifest_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
+    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR"));
+    let payload = out.join("payload");
+    if payload.exists() { fs::remove_dir_all(&payload).expect("remove stale extension payload"); }
+    fs::create_dir_all(&payload).expect("create extension payload");
+    let roots: Vec = if PART_ROOTS.is_empty() {
+        vec![manifest_dir.join("payload")]
+    } else {
+        PART_ROOTS.iter().map(PathBuf::from).collect()
+    };
+    let mut chunks: BTreeMap> = BTreeMap::new();
+    for root in roots {
+        println!("cargo::rerun-if-changed={}", root.display());
+        copy_complete_files(&root.join("files"), &payload).expect("copy extension payload files");
+        collect_chunks(&root.join("chunks"), &root.join("chunks"), &mut chunks).expect("collect extension payload chunks");
+    }
+    for (relative, mut rows) in chunks {
+        rows.sort_by_key(|(index, _)| *index);
+        for (expected, (actual, _)) in rows.iter().enumerate() {
+            if *actual != expected { panic!("non-contiguous extension chunks for {relative}"); }
+        }
+        let destination = payload.join(&relative);
+        fs::create_dir_all(destination.parent().expect("payload parent")).expect("create payload parent");
+        let mut writer = fs::File::create(&destination).expect("create reconstructed payload");
+        for (_, chunk) in rows {
+            let mut reader = fs::File::open(chunk).expect("open payload chunk");
+            io::copy(&mut reader, &mut writer).expect("append payload chunk");
+        }
+    }
+    let actual: BTreeSet = collect_files(&payload).expect("collect payload")
+        .into_iter().map(|file| file.strip_prefix(&payload).expect("payload relative").to_string_lossy().replace(std::path::MAIN_SEPARATOR, "/")).collect();
+    let expected: BTreeSet = FILES.iter().map(|(_, relative, _, _)| (*relative).to_owned()).collect();
+    if actual != expected { panic!("extension Cargo payload file set mismatch: expected {expected:?}, got {actual:?}"); }
+    let mut text = format!("schema = {SCHEMA:?}\\nproduct = {PRODUCT:?}\\nversion = {VERSION:?}\\nkind = \\"extension\\"\\ntarget = {TARGET:?}\\nruntime-product = {RUNTIME_PRODUCT:?}\\nruntime-version = {RUNTIME_VERSION:?}\\n");
+    for (extension, dependencies) in EXTENSIONS {
+        if SCHEMA == "oliphaunt-artifact-manifest-v1" {
+            text.push_str(&format!("extension = {extension:?}\\ndependencies = {dependencies:?}\\n"));
+        } else {
+            text.push_str(&format!("\\n[[extensions]]\\nextension = {extension:?}\\ndependencies = {dependencies:?}\\n"));
+        }
+        for (_, payload_relative, artifact_relative, expected_sha256) in FILES.iter().filter(|(owner, _, _, _)| owner == extension) {
+            let source = payload.join(payload_relative);
+            let actual_sha256 = sha256_file(&source).expect("hash extension payload");
+            if actual_sha256 != *expected_sha256 { panic!("extension payload digest mismatch for {}", source.display()); }
+            let table = if SCHEMA == "oliphaunt-artifact-manifest-v1" { "[[files]]" } else { "[[extensions.files]]" };
+            text.push_str(&format!("\\n{table}\\nsource = {:?}\\nrelative = {artifact_relative:?}\\nsha256 = {expected_sha256:?}\\nexecutable = false\\n", source.display().to_string()));
+        }
+    }
+    let manifest = out.join("oliphaunt-artifact.toml");
+    fs::write(&manifest, text).expect("write extension artifact manifest");
+    println!("cargo::metadata=manifest={}", manifest.display());
+}
+
+fn copy_complete_files(source: &Path, destination: &Path) -> io::Result<()> {
+    if !source.is_dir() { return Ok(()); }
+    for entry in fs::read_dir(source)? {
+        let entry = entry?;
+        let path = entry.path();
+        let target = destination.join(entry.file_name());
+        if entry.file_type()?.is_dir() { copy_complete_files(&path, &target)?; }
+        else { fs::create_dir_all(target.parent().expect("file parent"))?; fs::copy(path, target)?; }
+    }
+    Ok(())
+}
+
+fn collect_chunks(root: &Path, current: &Path, output: &mut BTreeMap>) -> io::Result<()> {
+    if !current.is_dir() { return Ok(()); }
+    for entry in fs::read_dir(current)? {
+        let entry = entry?;
+        let path = entry.path();
+        if entry.file_type()?.is_dir() { collect_chunks(root, &path, output)?; continue; }
+        let relative = path.strip_prefix(root).expect("chunk relative").to_string_lossy().replace(std::path::MAIN_SEPARATOR, "/");
+        let (name, suffix) = relative.rsplit_once(".part").unwrap_or_else(|| panic!("invalid extension chunk {relative}"));
+        let index = suffix.parse::().unwrap_or_else(|_| panic!("invalid extension chunk index {relative}"));
+        output.entry(name.to_owned()).or_default().push((index, path));
+    }
+    Ok(())
+}
+
+fn collect_files(root: &Path) -> io::Result> {
+    fn visit(root: &Path, output: &mut Vec) -> io::Result<()> {
+        for entry in fs::read_dir(root)? {
+            let entry = entry?;
+            let path = entry.path();
+            if entry.file_type()?.is_dir() { visit(&path, output)?; } else { output.push(path); }
+        }
+        Ok(())
+    }
+    let mut output = Vec::new();
+    visit(root, &mut output)?;
+    output.sort();
+    Ok(output)
+}
+
+${RUST_BUILD_SCRIPT_SHA256}
+`;
+}
+
+function discoverExtensionManifests(roots) {
+  const manifests = [];
+  for (const root of roots) {
+    if (isFile(root) && path.basename(root) === 'extension-artifacts.json') {
+      manifests.push(root);
+      continue;
+    }
+    if (isDirectory(root)) {
+      for (const file of payloadFiles(root)) {
+        if (path.basename(file) === 'extension-artifacts.json') {
+          manifests.push(file);
+        }
+      }
+    }
+  }
+  return [...new Set(manifests)].sort(compareText);
+}
+
+function extensionManifestMembers(manifest) {
+  if (manifest?.schema === 'oliphaunt-extension-ci-artifacts-v1') {
+    return typeof manifest.sqlName === 'string' && manifest.sqlName ? [manifest] : [];
+  }
+  if (manifest?.schema === 'oliphaunt-extension-ci-artifacts-v2') {
+    return Array.isArray(manifest.extensions) ? manifest.extensions : [];
+  }
+  return [];
+}
+
+export function extractArchiveMemberToFile(archive, member, destination) {
+  const normalized = checkedTarMember(member, archive);
+  let entries;
+  try {
+    entries = readPortableArchiveEntries(archive);
+  } catch (error) {
+    fail(error.message);
+  }
+  const entry = entries.get(normalized);
+  if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) {
+    fail(`${rel(archive)} member ${normalized} must be exactly one non-empty regular file`);
+  }
+  mkdirSync(path.dirname(destination), { recursive: true });
+  try {
+    writeFileSync(destination, entry.data(), { flag: 'wx', mode: 0o600 });
+  } catch (error) {
+    fail(`cannot materialize ${normalized} from ${rel(archive)}: ${error.message}`);
+  }
+  const metadata = lstatSync(destination);
+  if (!metadata.isFile() || metadata.isSymbolicLink()) {
+    rmSync(destination, { force: true });
+    fail(`extracted ${normalized} from ${rel(archive)} is not a regular non-symlink file`);
+  }
+  return destination;
+}
+
+function extensionWasixMembers(extensionDir, manifest, materializeRoot) {
+  const members = extensionManifestMembers(manifest);
+  if (members.length === 0) return [];
+  const rows = members.map((member) => {
+    const matches = Array.isArray(member.assets)
+      ? member.assets.filter(
+          (asset) =>
+            asset?.family === 'wasix' &&
+            asset.kind === 'wasix-runtime' &&
+            asset.target === 'wasix-portable',
+        )
+      : [];
+    if (matches.length !== 1) {
+      fail(
+        `${manifest.product}/${member.sqlName} must declare exactly one portable WASIX runtime asset`,
+      );
+    }
+    return { member, asset: matches[0] };
+  });
+  if (manifest.schema === 'oliphaunt-extension-ci-artifacts-v1') {
+    const [{ member, asset }] = rows;
+    const archive = path.join(extensionDir, 'release-assets', asset.name);
+    if (
+      !isFile(archive) ||
+      sha256File(archive) !== asset.sha256 ||
+      statSync(archive).size !== asset.bytes
+    ) {
+      fail(`${manifest.product}/${member.sqlName} portable WASIX asset is missing or changed`);
+    }
+    return [
+      {
+        sqlName: member.sqlName,
+        dependencies: [...(member.dependencies ?? [])],
+        nativeModuleStem: member.nativeModuleStem,
+        archive,
+        sha256: asset.sha256,
+        size: asset.bytes,
+      },
+    ];
+  }
+
+  const carrierNames = new Set(rows.map(({ asset }) => asset.carrierAsset));
+  if (carrierNames.size !== 1 || carrierNames.has(undefined)) {
+    fail(`${manifest.product} portable WASIX members must share one aggregate carrier`);
+  }
+  const carrierName = [...carrierNames][0];
+  const carrierRows = Array.isArray(manifest.carrierAssets)
+    ? manifest.carrierAssets.filter(
+        (carrier) =>
+          carrier?.name === carrierName &&
+          carrier.family === 'wasix' &&
+          carrier.target === 'wasix-portable' &&
+          carrier.kind === 'extension-bundle',
+      )
+    : [];
+  if (carrierRows.length !== 1) {
+    fail(`${manifest.product} must declare exactly one portable WASIX aggregate carrier row`);
+  }
+  const carrier = carrierRows[0];
+  const carrierPath = path.join(extensionDir, 'release-assets', carrierName);
+  if (
+    !isFile(carrierPath) ||
+    sha256File(carrierPath) !== carrier.sha256 ||
+    statSync(carrierPath).size !== carrier.bytes
+  ) {
+    fail(`${manifest.product} portable WASIX aggregate carrier is missing or changed`);
+  }
+  return rows.map(({ member, asset }) => {
+    const expectedRoot = carrierName.replace(/\.tar\.gz$/u, '');
+    if (asset.carrierRoot !== expectedRoot || typeof asset.memberPath !== 'string') {
+      fail(`${manifest.product}/${member.sqlName} has an invalid aggregate carrier locator`);
+    }
+    const archive = path.join(
+      materializeRoot,
+      manifest.product,
+      member.sqlName,
+      'extension.tar.zst',
+    );
+    extractArchiveMemberToFile(carrierPath, `${asset.carrierRoot}/${asset.memberPath}`, archive);
+    if (statSync(archive).size !== asset.bytes || sha256File(archive) !== asset.sha256) {
+      rmSync(archive, { force: true });
+      fail(
+        `${manifest.product}/${member.sqlName} nested portable WASIX bytes do not match the frozen member digest`,
+      );
+    }
+    return {
+      sqlName: member.sqlName,
+      dependencies: [...(member.dependencies ?? [])],
+      nativeModuleStem: member.nativeModuleStem,
+      archive,
+      sha256: asset.sha256,
+      size: asset.bytes,
+    };
+  });
+}
+
+function extensionAotSpecs(
+  extensionDir,
+  { product, version, members, versioning, dependencyRequirement, runtimeProduct, runtimeVersion },
+) {
+  const aotRoot = path.join(extensionDir, 'wasix-aot');
+  if (!isDirectory(aotRoot)) {
+    return [];
+  }
+  const specs = [];
+  const seenTargets = new Set();
+  for (const targetDir of fs
+    .readdirSync(aotRoot)
+    .map((name) => path.join(aotRoot, name))
+    .filter(isDirectory)
+    .sort(compareText)) {
+    const targetId = path.basename(targetDir);
+    const expectedTarget = AOT_TARGET_TRIPLES[targetId];
+    if (expectedTarget === undefined) {
+      fail(`${rel(aotRoot)} contains unknown extension AOT target id ${targetId}`);
+    }
+    const aotMembers = [];
+    for (const member of members.filter((candidate) => candidate.requiresAot)) {
+      const sourceDir = isFile(path.join(targetDir, 'manifest.json'))
+        ? targetDir
+        : path.join(targetDir, member.sqlName);
+      const manifestPath = path.join(sourceDir, 'manifest.json');
+      if (!isFile(manifestPath)) {
+        fail(`${product}/${member.sqlName} is missing WASIX AOT manifest for ${targetId}`);
+      }
+      const data = readJson(manifestPath);
+      validateCanonicalAotManifest(data, manifestPath, expectedTarget);
+      let artifactRows;
+      try {
+        artifactRows = assertWasixAotArtifactPayloads(data, {
+          context: rel(manifestPath),
+          readArtifact(artifactPath) {
+            const file = path.join(sourceDir, ...artifactPath.split('/'));
+            if (!isFile(file) || statSync(file).size <= 0) {
+              throw new Error(
+                `${rel(manifestPath)} references missing or empty AOT artifact ${artifactPath}`,
+              );
+            }
+            return readFileSync(file);
+          },
+        });
+      } catch (error) {
+        fail(error.message);
+      }
+      const expectedPrefix = `extension:${member.sqlName}`;
+      for (const artifact of artifactRows) {
+        const { name, path: artifactPath } = artifact;
+        if (
+          typeof name !== 'string' ||
+          !(name === expectedPrefix || name.startsWith(`${expectedPrefix}:`))
+        ) {
+          fail(
+            `${rel(manifestPath)} contains AOT artifact ${JSON.stringify(name)} for ${member.sqlName}`,
+          );
+        }
+      }
+      aotMembers.push({
+        sqlName: member.sqlName,
+        dependencies: member.dependencies,
+        sourceDir,
+      });
+    }
+    if (aotMembers.length === 0) continue;
+    if (seenTargets.has(expectedTarget))
+      fail(`${rel(aotRoot)} has duplicate extension AOT target ${expectedTarget}`);
+    seenTargets.add(expectedTarget);
+    specs.push({
+      name: wasixExtensionAotPackageName(product, expectedTarget),
+      product,
+      version,
+      members: aotMembers,
+      target: expectedTarget,
+      versioning,
+      dependencyRequirement,
+      runtimeProduct,
+      runtimeVersion,
+    });
+  }
+  return specs.sort((left, right) => compareText(left.target, right.target));
+}
+
+function extensionCargoSpecs(extensionRoots, materializeRoot) {
+  const specs = [];
+  for (const manifestPath of discoverExtensionManifests(extensionRoots)) {
+    const manifest = readJson(manifestPath);
+    if (manifest.family === 'native') {
+      continue;
+    }
+    const product = manifest.artifactProduct ?? manifest.product;
+    const { version } = manifest;
+    if (![product, version].every((value) => typeof value === 'string' && value)) {
+      fail(`${rel(manifestPath)} is missing artifactProduct/product or version`);
+    }
+    const releaseProduct = extensionReleaseProduct(product, 'wasix', PREFIX);
+    const expectedVersion = extensionReleaseVersion(product, 'wasix', PREFIX);
+    if ((manifest.releaseProduct ?? product) !== releaseProduct || version !== expectedVersion) {
+      fail(
+        `${rel(manifestPath)} must bind ${product} WASIX carriers to ${releaseProduct}@${expectedVersion}`,
+      );
+    }
+    if (releaseProduct !== product && manifest.family !== 'wasix') {
+      fail(`${rel(manifestPath)} runtime-owned WASIX carrier manifest must declare family=wasix`);
+    }
+    const metadata = extensionMetadata(product, PREFIX);
+    const expectedMembers = extensionSqlNames(product, PREFIX);
+    const manifestMembers = extensionManifestMembers(manifest).map((member) => member.sqlName);
+    if (JSON.stringify(manifestMembers) !== JSON.stringify(expectedMembers)) {
+      fail(`${rel(manifestPath)} member set does not match ${product} release metadata`);
+    }
+    const runtimeProduct = metadata.compatibility.wasixRuntimeProduct;
+    const runtimeVersion = metadata.compatibility.wasixRuntimeVersion;
+    const members = extensionWasixMembers(
+      path.dirname(manifestPath),
+      manifest,
+      materializeRoot,
+    ).map((member) => ({
+      ...member,
+      requiresAot: typeof member.nativeModuleStem === 'string' && Boolean(member.nativeModuleStem),
+    }));
+    const dependencyRequirement = extensionDependencyRequirement(version, metadata.versioning);
+    const spec = {
+      name: wasixExtensionPackageName(product),
+      product,
+      version,
+      members,
+      versioning: metadata.versioning,
+      dependencyRequirement,
+      runtimeProduct,
+      runtimeVersion,
+    };
+    spec.aotTargets = extensionAotSpecs(path.dirname(manifestPath), {
+      ...spec,
+      versioning: metadata.versioning,
+      dependencyRequirement,
+    });
+    specs.push(spec);
+  }
+  return specs.sort((left, right) => compareText(left.name, right.name));
+}
+
+function validateExtensionAotCoverage(extensionSpecs) {
+  for (const spec of extensionSpecs) {
+    if (!spec.members.some((member) => member.requiresAot)) {
+      continue;
+    }
+    const actualTargets = new Set(spec.aotTargets.map((aotSpec) => aotSpec.target));
+    if (!sameSet(actualTargets, EXPECTED_EXTENSION_AOT_TARGETS)) {
+      fail(
+        `${spec.product} has a WASIX native module but incomplete extension AOT artifacts; expected=${JSON.stringify([...EXPECTED_EXTENSION_AOT_TARGETS].sort(compareText))}, actual=${JSON.stringify([...actualTargets].sort(compareText))}`,
+      );
+    }
+  }
+}
+
+function writeExtensionCargoSource(spec, sourceRoot, partBytes) {
+  const crateDir = path.join(sourceRoot, spec.name);
+  if (existsSync(crateDir)) {
+    fail(`duplicate generated WASIX extension Cargo package source: ${rel(crateDir)}`);
+  }
+  mkdirSync(path.join(crateDir, 'src'), { recursive: true });
+  const subject =
+    spec.members.length === 1
+      ? spec.members[0].sqlName
+      : `${spec.members.length}-member PostgreSQL 18 contrib bundle`;
+  const files = spec.members.map((member) => ({
+    sqlName: member.sqlName,
+    source: member.archive,
+    payloadRelative: `extensions/${member.sqlName}/extension.tar.zst`,
+    artifactRelative: `extensions/${member.sqlName}.tar.zst`,
+    sha256: member.sha256,
+  }));
+  const split = files.reduce((sum, file) => sum + statSync(file.source).size, 0) > partBytes;
+  const partSources = split
+    ? writeExtensionPayloadPartSources({
+        parentName: spec.name,
+        product: spec.product,
+        version: spec.version,
+        target: 'portable',
+        subject: `${subject} Oliphaunt WASIX extension carrier`,
+        members: spec.members,
+        files,
+        sourceRoot,
+        partBytes,
+      })
+    : [];
+  if (!split) {
+    for (const file of files) {
+      const destination = path.join(crateDir, 'payload/files', file.payloadRelative);
+      mkdirSync(path.dirname(destination), { recursive: true });
+      copyFileSync(file.source, destination);
+    }
+  }
+  const legal = stageExtensionCarrierLegal(crateDir, spec, !split);
+  const includes = extensionCargoIncludes(crateDir, legal.profile, [
+    'Cargo.toml',
+    'README.md',
+    'build.rs',
+    'src/**',
+    ...(split ? [] : ['payload/**']),
+  ]);
+  const links = `oliphaunt_artifact_extension_${spec.product.replace(/^oliphaunt-extension-/u, '').replaceAll('-', '_')}_wasix`;
+  writeFileSync(
+    path.join(crateDir, 'README.md'),
+    [
+      `# ${spec.name}`,
+      '',
+      `Cargo artifact package for the ${subject} Oliphaunt WASIX extension carrier.`,
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(
+    path.join(crateDir, 'Cargo.toml'),
+    [
+      '[package]',
+      `name = "${spec.name}"`,
+      `version = "${spec.version}"`,
+      'edition = "2024"',
+      'rust-version = "1.93"',
+      `description = "Oliphaunt WASIX artifact package for the ${subject}"`,
+      'repository = "https://github.com/f0rr0/oliphaunt"',
+      'homepage = "https://oliphaunt.dev"',
+      `license = ${JSON.stringify(legal.packageSpdx)}`,
+      `links = "${links}"`,
+      'build = "build.rs"',
+      `include = [${includes.map((value) => JSON.stringify(value)).join(', ')}]`,
+      '',
+      '[lib]',
+      'path = "src/lib.rs"',
+      '',
+      '[build-dependencies]',
+      'sha2 = "0.10"',
+      ...partSources.map(
+        (part) => `${part.name} = { version = "=${spec.version}", path = "../${part.name}" }`,
+      ),
+      '',
+      '[workspace]',
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(
+    path.join(crateDir, 'src/lib.rs'),
+    [
+      '#![deny(unsafe_code)]',
+      '',
+      `pub const SQL_NAMES: &[&str] = &[${spec.members.map((member) => JSON.stringify(member.sqlName)).join(', ')}];`,
+      ...(spec.members.length === 1
+        ? [`pub const SQL_NAME: &str = ${JSON.stringify(spec.members[0].sqlName)};`]
+        : []),
+      '',
+      "pub fn archive(sql_name: &str) -> Option<&'static [u8]> {",
+      '    match sql_name {',
+      ...spec.members.map(
+        (member) =>
+          `        ${JSON.stringify(member.sqlName)} => Some(include_bytes!(concat!(env!("OUT_DIR"), "/payload/extensions/${member.sqlName}/extension.tar.zst"))),`,
+      ),
+      '        _ => None,',
+      '    }',
+      '}',
+      '',
+      "pub fn archive_sha256(sql_name: &str) -> Option<&'static str> {",
+      '    match sql_name {',
+      ...spec.members.map(
+        (member) =>
+          `        ${JSON.stringify(member.sqlName)} => Some(${JSON.stringify(member.sha256)}),`,
+      ),
+      '        _ => None,',
+      '    }',
+      '}',
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(
+    path.join(crateDir, 'build.rs'),
+    extensionArtifactBuildRs({ ...spec, target: 'portable' }, files, partSources),
+  );
+  return {
+    spec,
+    sourceDir: crateDir,
+    partSources,
+    noticeProfile: legal.profile,
+    upstreamMembers: legal.upstreamMembers,
+  };
+}
+
+function writeExtensionAotCargoSource(spec, sourceRoot, partBytes) {
+  const crateDir = path.join(sourceRoot, spec.name);
+  if (existsSync(crateDir)) {
+    fail(`duplicate generated WASIX extension AOT Cargo package source: ${rel(crateDir)}`);
+  }
+  mkdirSync(path.join(crateDir, 'src'), { recursive: true });
+  const artifacts = [];
+  for (const member of spec.members) {
+    const manifestPath = path.join(member.sourceDir, 'manifest.json');
+    const manifest = readJson(manifestPath);
+    const manifestDestination = path.join(crateDir, 'manifests', `${member.sqlName}.json`);
+    mkdirSync(path.dirname(manifestDestination), { recursive: true });
+    copyFileSync(manifestPath, manifestDestination);
+    for (const artifact of [...(manifest.artifacts ?? [])].sort((left, right) =>
+      compareText(left?.name ?? '', right?.name ?? ''),
+    )) {
+      const name = artifact?.name;
+      const artifactPath = artifact?.path;
+      if (typeof name !== 'string' || typeof artifactPath !== 'string') {
+        fail(`${rel(manifestPath)} contains an AOT artifact without name/path`);
+      }
+      const source = path.join(member.sourceDir, artifactPath);
+      if (!isFile(source))
+        fail(`${rel(manifestPath)} references missing AOT artifact ${artifactPath}`);
+      artifacts.push({
+        sqlName: member.sqlName,
+        name,
+        source,
+        payloadRelative: `extensions/${member.sqlName}/${artifactPath}`,
+        artifactRelative: `extensions/${member.sqlName}/${artifactPath}`,
+        sha256: sha256File(source),
+      });
+    }
+  }
+  if (artifacts.length === 0) {
+    fail(`${spec.product} ${spec.target} must contain extension AOT artifacts`);
+  }
+  if (new Set(artifacts.map((artifact) => artifact.name)).size !== artifacts.length) {
+    fail(`${spec.product} ${spec.target} repeats an extension AOT artifact name`);
+  }
+  const split =
+    artifacts.reduce((sum, artifact) => sum + statSync(artifact.source).size, 0) > partBytes;
+  const partSources = split
+    ? writeExtensionPayloadPartSources({
+        parentName: spec.name,
+        product: spec.product,
+        version: spec.version,
+        target: spec.target,
+        subject: `${spec.members.length}-member Oliphaunt WASIX extension AOT carrier`,
+        members: spec.members,
+        files: artifacts,
+        sourceRoot,
+        partBytes,
+      })
+    : [];
+  if (!split) {
+    for (const artifact of artifacts) {
+      const destination = path.join(crateDir, 'payload/files', artifact.payloadRelative);
+      mkdirSync(path.dirname(destination), { recursive: true });
+      copyFileSync(artifact.source, destination);
+    }
+  }
+  const legal = stageExtensionCarrierLegal(crateDir, spec, !split);
+  const includes = extensionCargoIncludes(crateDir, legal.profile, [
+    'Cargo.toml',
+    'README.md',
+    'build.rs',
+    'src/**',
+    'manifests/**',
+    ...(split ? [] : ['payload/**']),
+  ]);
+  const subject =
+    spec.members.length === 1 ? spec.members[0].sqlName : `${spec.members.length}-member bundle`;
+  const links = `oliphaunt_artifact_extension_${spec.product.replace(/^oliphaunt-extension-/u, '').replaceAll('-', '_')}_aot_${spec.target.replaceAll('-', '_')}`;
+  writeFileSync(
+    path.join(crateDir, 'README.md'),
+    [
+      `# ${spec.name}`,
+      '',
+      `Cargo artifact package for the ${subject} Oliphaunt WASIX AOT artifacts on \`${spec.target}\`.`,
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(
+    path.join(crateDir, 'Cargo.toml'),
+    [
+      '[package]',
+      `name = "${spec.name}"`,
+      `version = "${spec.version}"`,
+      'edition = "2024"',
+      'rust-version = "1.93"',
+      `description = "Oliphaunt WASIX AOT artifact package for the ${subject} on ${spec.target}"`,
+      'repository = "https://github.com/f0rr0/oliphaunt"',
+      'homepage = "https://oliphaunt.dev"',
+      `license = ${JSON.stringify(legal.packageSpdx)}`,
+      `links = ${JSON.stringify(links)}`,
+      'build = "build.rs"',
+      `include = [${includes.map((value) => JSON.stringify(value)).join(', ')}]`,
+      '',
+      '[lib]',
+      'path = "src/lib.rs"',
+      '',
+      '[build-dependencies]',
+      'sha2 = "0.10"',
+      ...partSources.map(
+        (part) => `${part.name} = { version = "=${spec.version}", path = "../${part.name}" }`,
+      ),
+      '',
+      '[workspace]',
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(
+    path.join(crateDir, 'src/lib.rs'),
+    [
+      '#![deny(unsafe_code)]',
+      '',
+      `pub const SQL_NAMES: &[&str] = &[${spec.members.map((member) => JSON.stringify(member.sqlName)).join(', ')}];`,
+      ...(spec.members.length === 1
+        ? [`pub const SQL_NAME: &str = ${JSON.stringify(spec.members[0].sqlName)};`]
+        : []),
+      `pub const TARGET_TRIPLE: &str = "${spec.target}";`,
+      '',
+      "pub fn aot_manifest_json(sql_name: &str) -> Option<&'static str> {",
+      '    match sql_name {',
+      ...spec.members.map(
+        (member) =>
+          `        ${JSON.stringify(member.sqlName)} => Some(include_str!("../manifests/${member.sqlName}.json")),`,
+      ),
+      '        _ => None,',
+      '    }',
+      '}',
+      '',
+      "pub fn aot_artifact_bytes(name: &str) -> Option<&'static [u8]> {",
+      '    match name {',
+      ...artifacts.map(
+        (artifact) =>
+          `        ${JSON.stringify(artifact.name)} => Some(include_bytes!(concat!(env!("OUT_DIR"), "/payload/${artifact.payloadRelative}"))),`,
+      ),
+      '        _ => None,',
+      '    }',
+      '}',
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(
+    path.join(crateDir, 'build.rs'),
+    extensionArtifactBuildRs(spec, artifacts, partSources),
+  );
+  return {
+    spec,
+    sourceDir: crateDir,
+    partSources,
+    noticeProfile: legal.profile,
+    upstreamMembers: legal.upstreamMembers,
+  };
+}
+
+function assertPackedExtensionLegal(output, carrier) {
+  const prefix = `${carrier.name ?? carrier.spec.name}-${carrier.version ?? carrier.spec.version}`;
+  assertReleaseNoticesInArchive(output, {
+    prefix,
+    profile: carrier.noticeProfile,
+  });
+  if (carrier.upstreamMembers.length > 0) {
+    assertExtensionUpstreamLicensesInArchive(carrier.upstreamMembers, output, { prefix });
+  }
+}
+
+function packageExtensionSource(source, { outputDir, cargoTargetDir }) {
+  const packages = [];
+  for (const part of source.partSources ?? []) {
+    const cratePath = cargoPackage(part.sourceDir, cargoTargetDir);
+    validateCrateSize(cratePath);
+    const output = path.join(outputDir, path.basename(cratePath));
+    copyFileSync(cratePath, output);
+    assertPackedExtensionLegal(output, part);
+    packages.push({
+      name: part.name,
+      manifestPath: path.join(part.sourceDir, 'Cargo.toml'),
+      cratePath: output,
+      target: 'wasix-portable',
+      kind: 'wasix-extension',
+      size: statSync(output).size,
+      sha256: sha256File(output),
+      versioning: source.spec.versioning,
+      dependencyRequirement: source.spec.dependencyRequirement,
+    });
+  }
+  const cratePath = cargoPackage(source.sourceDir, cargoTargetDir);
+  validateCrateSize(cratePath);
+  const output = path.join(outputDir, path.basename(cratePath));
+  copyFileSync(cratePath, output);
+  assertPackedExtensionLegal(output, source);
+  packages.push({
+    name: source.spec.name,
+    manifestPath: path.join(source.sourceDir, 'Cargo.toml'),
+    cratePath: output,
+    target: 'wasix-portable',
+    kind: 'wasix-extension',
+    size: statSync(output).size,
+    sha256: sha256File(output),
+    versioning: source.spec.versioning,
+    dependencyRequirement: source.spec.dependencyRequirement,
+  });
+  return packages;
+}
+
+function packageExtensionAotSource(source, { outputDir, cargoTargetDir }) {
+  const packages = [];
+  for (const part of source.partSources ?? []) {
+    const cratePath = cargoPackage(part.sourceDir, cargoTargetDir);
+    validateCrateSize(cratePath);
+    const output = path.join(outputDir, path.basename(cratePath));
+    copyFileSync(cratePath, output);
+    assertPackedExtensionLegal(output, part);
+    packages.push({
+      name: part.name,
+      manifestPath: path.join(part.sourceDir, 'Cargo.toml'),
+      cratePath: output,
+      target: part.target,
+      kind: 'wasix-extension-aot',
+      size: statSync(output).size,
+      sha256: sha256File(output),
+      versioning: source.spec.versioning,
+      dependencyRequirement: source.spec.dependencyRequirement,
+    });
+  }
+  const cratePath = cargoPackage(source.sourceDir, cargoTargetDir);
+  validateCrateSize(cratePath);
+  const output = path.join(outputDir, path.basename(cratePath));
+  copyFileSync(cratePath, output);
+  assertPackedExtensionLegal(output, source);
+  packages.push({
+    name: source.spec.name,
+    manifestPath: path.join(source.sourceDir, 'Cargo.toml'),
+    cratePath: output,
+    target: source.spec.target,
+    kind: 'wasix-extension-aot',
+    size: statSync(output).size,
+    sha256: sha256File(output),
+    versioning: source.spec.versioning,
+    dependencyRequirement: source.spec.dependencyRequirement,
+  });
+  return packages;
+}
+
+function packageSpecs(assetDir, extractRoot, version) {
+  const specs = [];
+  const runtimeArchive = path.join(
+    assetDir,
+    `liboliphaunt-wasix-${version}-runtime-portable.tar.zst`,
+  );
+  if (!isFile(runtimeArchive)) {
+    fail(`missing WASIX portable runtime release asset: ${rel(runtimeArchive)}`);
+  }
+  const runtimeExtract = path.join(extractRoot, 'runtime-extracted');
+  extractTarZstd(runtimeArchive, runtimeExtract);
+  const runtimeRoot = targetAssetRoot(runtimeExtract);
+  validateRuntimePayload(runtimeRoot);
+  const runtimeCoreRoot = runtimeCorePayload(runtimeRoot, extractRoot);
+  validateRuntimePayload(runtimeCoreRoot);
+  specs.push({
+    name: RUNTIME_PACKAGE,
+    target: 'portable',
+    kind: 'wasix-runtime',
+    templateDir: path.join(ROOT, 'src/runtimes/liboliphaunt-wasix/crates/assets'),
+    payloadRoot: runtimeCoreRoot,
+    payloadDirName: 'payload',
+  });
+
+  for (const [targetId, packageName] of Object.entries(AOT_PACKAGES).sort(([left], [right]) =>
+    compareText(left, right),
+  )) {
+    const archive = path.join(
+      assetDir,
+      `liboliphaunt-wasix-${version}-runtime-aot-${targetId}.tar.zst`,
+    );
+    if (!isFile(archive)) {
+      fail(`missing WASIX AOT release asset: ${rel(archive)}`);
+    }
+    const extracted = path.join(extractRoot, `${targetId}-extracted`);
+    extractTarZstd(archive, extracted);
+    const triple = AOT_TARGET_TRIPLES[targetId];
+    const aotRoot = targetAotRoot(extracted, triple);
+    validateAotPayload(aotRoot, triple);
+    const aotCoreRoot = runtimeAotPayload(aotRoot, extractRoot, targetId);
+    specs.push({
+      name: packageName,
+      target: triple,
+      kind: 'wasix-aot',
+      templateDir: path.join(ROOT, 'src/runtimes/liboliphaunt-wasix/crates/aot', triple),
+      payloadRoot: aotCoreRoot,
+      payloadDirName: 'artifacts',
+    });
+  }
+  return specs;
+}
+
+function writePackagesManifest(packages, outputDir) {
+  const data = {
+    schema: WASIX_CARGO_ARTIFACT_SCHEMA,
+    product: PRODUCT,
+    packages: packages.map((packageData) => ({
+      name: packageData.name,
+      target: packageData.target,
+      kind: packageData.kind,
+      role: 'artifact',
+      manifestPath: rel(packageData.manifestPath),
+      cratePath: rel(packageData.cratePath),
+      size: packageData.size,
+      sha256: packageData.sha256,
+      ...(packageData.dependencyRequirement === undefined
+        ? {}
+        : {
+            versioning: packageData.versioning,
+            dependencyRequirement: packageData.dependencyRequirement,
+          }),
+    })),
+  };
+  writeFileSync(path.join(outputDir, 'packages.json'), `${JSON.stringify(data, null, 2)}\n`);
+}
+
+function parseArgs(argv) {
+  const args = {
+    assetDir: 'target/oliphaunt-wasix/release-assets',
+    extensionsOnly: false,
+    outputDir: 'target/oliphaunt-wasix/cargo-artifacts',
+    workDir: 'target/oliphaunt-wasix',
+    version: null,
+    extensionArtifactRoots: [],
+    extensionPartBytes: DEFAULT_EXTENSION_PART_BYTES,
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const value = argv[index];
+    if (value === '--help' || value === '-h') {
+      console.log(
+        'usage: src/runtimes/liboliphaunt-wasix/tools/package_liboliphaunt_wasix_cargo_artifacts.mts [--asset-dir DIR] [--extensions-only] [--extension-part-bytes BYTES] [--output-dir DIR] [--work-dir DIR] [--version VERSION] [--extension-artifact-root DIR...]',
+      );
+      process.exit(0);
+    } else if (value === '--asset-dir') {
+      args.assetDir = requiredValue(argv, ++index, value);
+    } else if (value.startsWith('--asset-dir=')) {
+      args.assetDir = value.slice('--asset-dir='.length);
+    } else if (value === '--extensions-only') {
+      args.extensionsOnly = true;
+    } else if (value === '--output-dir') {
+      args.outputDir = requiredValue(argv, ++index, value);
+    } else if (value.startsWith('--output-dir=')) {
+      args.outputDir = value.slice('--output-dir='.length);
+    } else if (value === '--work-dir') {
+      args.workDir = requiredValue(argv, ++index, value);
+    } else if (value.startsWith('--work-dir=')) {
+      args.workDir = value.slice('--work-dir='.length);
+    } else if (value === '--version') {
+      args.version = requiredValue(argv, ++index, value);
+    } else if (value.startsWith('--version=')) {
+      args.version = value.slice('--version='.length);
+    } else if (value === '--extension-artifact-root') {
+      args.extensionArtifactRoots.push(requiredValue(argv, ++index, value));
+    } else if (value.startsWith('--extension-artifact-root=')) {
+      args.extensionArtifactRoots.push(value.slice('--extension-artifact-root='.length));
+    } else if (value === '--extension-part-bytes') {
+      args.extensionPartBytes = Number(requiredValue(argv, ++index, value));
+    } else if (value.startsWith('--extension-part-bytes=')) {
+      args.extensionPartBytes = Number(value.slice('--extension-part-bytes='.length));
+    } else {
+      fail(`unknown argument ${value}`);
+    }
+  }
+  if (args.extensionArtifactRoots.length === 0) {
+    args.extensionArtifactRoots.push('target/extension-artifacts');
+  }
+  if (
+    !Number.isSafeInteger(args.extensionPartBytes) ||
+    args.extensionPartBytes < 1 ||
+    args.extensionPartBytes > DEFAULT_EXTENSION_PART_BYTES
+  ) {
+    fail(`--extension-part-bytes must be an integer in 1..${DEFAULT_EXTENSION_PART_BYTES}`);
+  }
+  args.version ??= currentProductVersionSync(PRODUCT, PREFIX);
+  return args;
+}
+
+function requiredValue(argv, index, option) {
+  const value = argv[index];
+  if (value === undefined || value.startsWith('--')) {
+    fail(`${option} requires a value`);
+  }
+  return value;
+}
+
+function repoPath(value) {
+  return path.isAbsolute(value) ? value : path.join(ROOT, value);
+}
+
+export function packageWasixCargoArtifacts(argv) {
+  const args = parseArgs(argv);
+  const assetDir = repoPath(args.assetDir);
+  const outputDir = repoPath(args.outputDir);
+  const workDir = repoPath(args.workDir);
+  const extensionRoots = args.extensionArtifactRoots.map(repoPath);
+  if (!args.extensionsOnly && !isDirectory(assetDir)) {
+    fail(`WASIX release asset directory does not exist: ${rel(assetDir)}`);
+  }
+
+  const sourceRoot = path.join(workDir, 'cargo-package-sources');
+  const extractRoot = path.join(workDir, 'cargo-package-extracted');
+  const cargoTargetDir = path.join(workDir, 'cargo-package-target');
+  rmSync(sourceRoot, { recursive: true, force: true });
+  rmSync(extractRoot, { recursive: true, force: true });
+  rmSync(outputDir, { recursive: true, force: true });
+  rmSync(cargoTargetDir, { recursive: true, force: true });
+  mkdirSync(sourceRoot, { recursive: true });
+  mkdirSync(extractRoot, { recursive: true });
+  mkdirSync(outputDir, { recursive: true });
+
+  const extensionSpecs = extensionCargoSpecs(extensionRoots, extractRoot);
+  validateExtensionAotCoverage(extensionSpecs);
+  const extensionSources = extensionSpecs.map((spec) =>
+    writeExtensionCargoSource(spec, sourceRoot, args.extensionPartBytes),
+  );
+  const extensionAotSources = extensionSpecs.flatMap((spec) =>
+    spec.aotTargets.map((aotSpec) =>
+      writeExtensionAotCargoSource(aotSpec, sourceRoot, args.extensionPartBytes),
+    ),
+  );
+  const specs = args.extensionsOnly ? [] : packageSpecs(assetDir, extractRoot, args.version);
+  const packages = [
+    ...extensionSources.flatMap((source) =>
+      packageExtensionSource(source, { outputDir, cargoTargetDir }),
+    ),
+    ...extensionAotSources.flatMap((source) =>
+      packageExtensionAotSource(source, { outputDir, cargoTargetDir }),
+    ),
+    ...specs.map((spec) =>
+      packageSpec(spec, {
+        version: args.version,
+        sourceRoot,
+        outputDir,
+        cargoTargetDir,
+        transformManifest:
+          spec.name === RUNTIME_PACKAGE
+            ? (text) =>
+                injectRuntimeExtensionDependencies(text, extensionSources, extensionAotSources)
+            : undefined,
+      }),
+    ),
+  ];
+  writePackagesManifest(packages, outputDir);
+  console.log(
+    args.extensionsOnly
+      ? 'generated WASIX extension Cargo artifact crates:'
+      : 'generated liboliphaunt-wasix Cargo artifact crates:',
+  );
+  for (const packageData of packages) {
+    console.log(`${packageData.name} ${rel(packageData.cratePath)} ${packageData.size} bytes`);
+  }
+}
+
+if (import.meta.main) {
+  try {
+    packageWasixCargoArtifacts(Bun.argv.slice(2));
+  } catch (error) {
+    const message = error instanceof Error ? error.message : String(error);
+    console.error(message.startsWith(`${PREFIX}:`) ? message : `${PREFIX}: ${message}`);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/runtime-preflight.sh b/src/runtimes/liboliphaunt-wasix/tools/runtime-preflight.sh
new file mode 100644
index 000000000..1e9e92c9e
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/runtime-preflight.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env sh
+
+oliphaunt_runtime_wasm_host_triple() {
+  rustc -vV | awk '/^host:/{print $2}'
+}
+
+oliphaunt_runtime_wasm_require() {
+  oliphaunt_runtime_mode="${1:-smoke}"
+  oliphaunt_runtime_host="$(oliphaunt_runtime_wasm_host_triple)"
+  [ -f "target/oliphaunt-wasix/assets/manifest.json" ] || {
+    echo "missing generated portable WASIX assets at target/oliphaunt-wasix/assets" >&2
+    return 1
+  }
+  [ -f "target/oliphaunt-wasix/aot/$oliphaunt_runtime_host/manifest.json" ] ||
+    [ -f "src/runtimes/liboliphaunt-wasix/crates/aot/$oliphaunt_runtime_host/artifacts/manifest.json" ] || {
+    echo "missing host WASIX AOT artifacts for $oliphaunt_runtime_host" >&2
+    return 1
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/runtime-smoke.sh b/src/runtimes/liboliphaunt-wasix/tools/runtime-smoke.sh
new file mode 100755
index 000000000..4f6697229
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/runtime-smoke.sh
@@ -0,0 +1,94 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "unable to determine repository root from $script_dir; run this script from a Git checkout" >&2
+  exit 1
+}
+[ -f "$root/package.json" ] && [ -d "$root/src/runtimes/liboliphaunt-wasix" ] || {
+  echo "must run inside the Oliphaunt workspace" >&2
+  exit 1
+}
+cd "$root"
+
+. "$root/src/runtimes/liboliphaunt-wasix/tools/runtime-preflight.sh"
+. "$root/src/runtimes/liboliphaunt-wasix/tools/cargo-test-filter.sh"
+
+mode="${1:-smoke}"
+case "$mode" in
+  smoke|regression|core-smoke)
+    ;;
+  *)
+    echo "usage: src/runtimes/liboliphaunt-wasix/tools/runtime-smoke.sh [smoke|regression|core-smoke]" >&2
+    exit 2
+    ;;
+esac
+
+host="$(oliphaunt_runtime_wasm_host_triple)"
+preflight_mode="$mode"
+if [ "$mode" = "core-smoke" ]; then
+  preflight_mode="smoke"
+fi
+oliphaunt_runtime_wasm_require "$preflight_mode"
+asset_mode=core
+if [ "$mode" = "regression" ]; then asset_mode=full; fi
+full_evidence_features=""
+if [ "$asset_mode" = "full" ]; then
+  if [ -z "${OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT:-}" ]; then
+    export OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="$root/target/wasix-smoke/extension-artifacts"
+    OLIPHAUNT_WASIX_GENERATED_ASSET_ROOT="$root/target/extensions/wasix/assets" \
+    OLIPHAUNT_WASIX_EXTENSION_AOT_ARTIFACT_ROOT="$root/target/extensions/wasix/aot-artifacts" \
+      tools/dev/bun.sh src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts \
+        --output-root "$OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT" \
+        --all --family wasix --require-wasix
+  fi
+  full_evidence_features="$(
+    tools/dev/bun.sh src/runtimes/liboliphaunt-wasix/tools/wasix-extension-features.mts \
+      "$root/target/extensions/wasix/assets/manifest.json"
+  )"
+fi
+
+oliphaunt_wasix_cargo_test() {
+  if [ "$asset_mode" = "full" ]; then
+    # Full evidence enables every catalogued extension plus the tool features
+    # needed by the separate extension and logical dump/restore proofs below.
+    cargo test -p oliphaunt-wasix --locked --no-default-features \
+      --features "$full_evidence_features" "$@"
+  else
+    cargo test -p oliphaunt-wasix --locked --no-default-features "$@"
+  fi
+}
+
+oliphaunt_wasix_library_tests() {
+  local filter="$1"
+  local command=(oliphaunt_wasix_cargo_test --lib "$filter")
+  oliphaunt_require_cargo_test_filter "$filter" "${command[@]}"
+  "${command[@]}" -- --nocapture --test-threads=1
+}
+
+cargo run -p xtask -- assets install-local --target-triple "$host"
+export OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR="$root/target/oliphaunt-wasix/assets"
+export OLIPHAUNT_WASM_GENERATED_AOT_DIR="$root/target/oliphaunt-wasix/aot"
+export RUST_BACKTRACE="${RUST_BACKTRACE:-full}"
+
+oliphaunt_wasix_cargo_test \
+  --test runtime_smoke \
+  --test extensions_smoke \
+  --test postgres_regression \
+  -- --nocapture --test-threads=1
+if [ "$asset_mode" = "full" ]; then
+  # Each extension must pass direct execution, restart, physical backup/restore,
+  # server execution and materialization. Tests record only completed modes.
+  oliphaunt_wasix_library_tests extension_tests::public_extensions
+  server_command=(cargo test -p oliphaunt-pgwire-server --locked --no-default-features
+    --features "${full_evidence_features/,tools/}" --test extensions public_extensions_pass_server_smoke)
+  oliphaunt_require_cargo_test_filter public_extensions_pass_server_smoke "${server_command[@]}"
+  "${server_command[@]}" -- --ignored --exact --nocapture --test-threads=1
+  tools_filter="oliphaunt::tools::tests::public_tools_round_trip_shared_logical_fixture"
+  tools_command=(oliphaunt_wasix_cargo_test --lib "$tools_filter")
+  oliphaunt_require_cargo_test_filter "$tools_filter" "${tools_command[@]}"
+  "${tools_command[@]}" -- --exact --nocapture --test-threads=1
+else
+  echo "runtime smoke complete; extension and tools behavior belongs to regression and owner consumer tasks"
+fi
diff --git a/src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh b/src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh
new file mode 100644
index 000000000..acb05b2da
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+
+export CARGO_INCREMENTAL=0
+if [[ -z "${LLVM_SYS_221_PREFIX:-}" && -d /opt/homebrew/opt/llvm ]]; then
+  export LLVM_SYS_221_PREFIX=/opt/homebrew/opt/llvm
+fi
+suffix=
+case "$(uname -s)" in
+  MINGW* | MSYS* | CYGWIN*)
+    suffix=.exe
+    llvm_prefix="${LLVM_SYS_221_PREFIX:-${LLVM_PATH:-}}"
+    if [[ -n "$llvm_prefix" && -d "$llvm_prefix/lib" ]]; then
+      export LIB="$(cygpath -aw "$llvm_prefix/lib")${LIB:+;$LIB}"
+    fi
+    ;;
+esac
+
+cargo build -p xtask --release --locked --features aot-serializer
+serializer="${CARGO_TARGET_DIR:-target}/release/xtask$suffix"
+[[ -f "$serializer" ]] || {
+  echo "missing AOT serializer: $serializer" >&2
+  exit 1
+}
+inputs="$(cargo run -p xtask --locked -- assets prepare-aot "$@")"
+[[ -n "$inputs" ]] || {
+  echo 'no WASIX modules selected for AOT' >&2
+  exit 1
+}
+while IFS=$'\t' read -r input output; do
+  [[ -n "$input" && -n "$output" ]] || {
+    echo 'incomplete AOT module paths' >&2
+    exit 1
+  }
+  "$serializer" aot-serializer serialize --input "$input" --output "$output"
+done <<<"$inputs"
diff --git a/src/runtimes/liboliphaunt-wasix/tools/serialize-aot.test.sh b/src/runtimes/liboliphaunt-wasix/tools/serialize-aot.test.sh
new file mode 100644
index 000000000..52d04ba03
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/serialize-aot.test.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+set -euo pipefail
+script="$(git rev-parse --show-toplevel)/src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh"
+fixture="$(mktemp -d)"
+trap 'rm -rf "$fixture"' EXIT
+export AOT_FIXTURE_ROOT="$fixture"
+export CARGO_TARGET_DIR="$fixture/compiler output"
+mkdir -p "$fixture/bin" "$CARGO_TARGET_DIR/release"
+cat >"$fixture/bin/git" <<'SH'
+#!/usr/bin/env bash
+printf '%s\n' "$AOT_FIXTURE_ROOT"
+SH
+cat >"$fixture/bin/uname" <<'SH'
+#!/usr/bin/env bash
+printf 'Linux\n'
+SH
+cat >"$fixture/bin/cargo" <<'SH'
+#!/usr/bin/env bash
+set -euo pipefail
+if [[ "$1" == build ]]; then exit "${FAIL_BUILD:-0}"; fi
+[[ "$*" == 'run -p xtask --locked -- assets prepare-aot --target-triple fixture' ]]
+printf 'input one.wasm\toutput one.zst\ninput two.wasm\toutput two.zst\n'
+SH
+cat >"$CARGO_TARGET_DIR/release/xtask" <<'SH'
+#!/usr/bin/env bash
+set -euo pipefail
+[[ "$#" == 6 && "$1 $2 $3 $5" == 'aot-serializer serialize --input --output' ]]
+printf '%s\t%s\n' "$4" "$6" >> "$AOT_FIXTURE_ROOT/serialized"
+exit "${FAIL_SERIALIZE:-0}"
+SH
+chmod +x "$fixture/bin/"* "$CARGO_TARGET_DIR/release/xtask"
+export PATH="$fixture/bin:$PATH"
+bash "$script" --target-triple fixture
+printf 'input one.wasm\toutput one.zst\ninput two.wasm\toutput two.zst\n' >"$fixture/expected"
+cmp "$fixture/expected" "$fixture/serialized"
+rm "$fixture/serialized"
+if FAIL_BUILD=1 bash "$script" --target-triple fixture; then exit 1; fi
+[[ ! -e "$fixture/serialized" ]]
+if FAIL_SERIALIZE=1 bash "$script" --target-triple fixture; then exit 1; fi
+[[ "$(wc -l <"$fixture/serialized")" -eq 1 ]]
+echo 'AOT Shell dispatch preserves module paths and stops on compiler failures'
diff --git a/src/runtimes/liboliphaunt-wasix/tools/test-packaging.sh b/src/runtimes/liboliphaunt-wasix/tools/test-packaging.sh
new file mode 100644
index 000000000..1ad2db44a
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/test-packaging.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+export OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT OLIPHAUNT_TEST_RUST_HOST
+OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT="$(mktemp -d)"
+trap 'rm -rf "$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT"' EXIT
+OLIPHAUNT_TEST_RUST_HOST="$(rustc --print host-tuple)"
+contract=src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts
+bun "$contract" all > "$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT/targets.tsv"
+while IFS=$'\t' read -r triple artifact target; do
+  expected="$triple"$'\t'"$artifact"$'\t'"$target"
+  [[ "$(bun "$contract" "$target")" == "$expected" ]]
+  [[ "$(bun "$contract" "$triple")" == "$expected" ]]
+done < "$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT/targets.tsv"
+if bun "$contract" unsupported > /dev/null 2>&1; then
+  echo 'Unsupported AOT download target was accepted' >&2
+  exit 1
+fi
+bun test --timeout=30000 ./src/runtimes/liboliphaunt-wasix/tools
+node src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm.test-consumer.mts
+for scenario in nested-owner aggregate; do
+  root="$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT/$scenario"
+  # Keep registry dependencies at the qualified workspace versions; this
+  # disposable consumer only changes local carrier paths and feature selection.
+  cp Cargo.lock "$root/app/Cargo.lock"
+  cargo fetch --manifest-path "$root/app/Cargo.toml"
+  CARGO_TARGET_DIR="$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT/cargo-target" \
+    OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="$root" \
+    cargo run --locked --offline --manifest-path "$root/app/Cargo.toml"
+done
+root="$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT/aggregate"
+chunk="$(find "$root/work/cargo-package-sources/oliphaunt-extension-contrib-pg18-wasix-part-001/payload" -type f -print -quit)"
+printf 'corrupt' >> "$chunk"
+if CARGO_TARGET_DIR="$OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT/cargo-target" \
+  OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="$root" \
+  cargo check --locked --offline --manifest-path "$root/app/Cargo.toml" > "$root/corrupt.log" 2>&1; then
+  echo 'Corrupt extracted extension payload was accepted' >&2
+  exit 1
+fi
+rg -q 'extension payload digest mismatch' "$root/corrupt.log"
diff --git a/src/runtimes/liboliphaunt-wasix/tools/verify-source-tree.mts b/src/runtimes/liboliphaunt-wasix/tools/verify-source-tree.mts
new file mode 100644
index 000000000..2901cb07d
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/verify-source-tree.mts
@@ -0,0 +1,36 @@
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+import { parseArgs } from 'node:util';
+import {
+  archiveTreeDigest,
+  parseArchiveStamp,
+} from '../../../third-party/tools/source-fetch-core.mts';
+
+try {
+  const { values } = parseArgs({
+    options: { checkout: { type: 'string' }, manifest: { type: 'string' } },
+  });
+  if (!values.checkout || !values.manifest)
+    throw new Error('--checkout and --manifest are required');
+  const source = Bun.TOML.parse(readFileSync(values.manifest, 'utf8'));
+  if (source.kind !== 'archive') throw new Error('source manifest must describe an archive');
+  const marker = parseArchiveStamp(path.join(values.checkout, '.oliphaunt-source-pin'));
+  for (const key of ['name', 'kind', 'url', 'branch', 'commit', 'sha256', 'strip_prefix']) {
+    if (
+      typeof source[key] !== 'string' ||
+      !source[key] ||
+      marker.get(key.replace('_', '-')) !== source[key]
+    ) {
+      throw new Error(`source checkout marker does not match manifest ${key}`);
+    }
+  }
+  const actual = archiveTreeDigest(values.checkout);
+  if (actual !== marker.get('tree-sha256'))
+    throw new Error(
+      `source checkout was modified: expected tree ${marker.get('tree-sha256')}, got ${actual}`,
+    );
+  console.log(actual);
+} catch (error) {
+  console.error(`source checkout verification failed: ${error.message}`);
+  process.exitCode = 1;
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts
new file mode 100644
index 000000000..e81559ba5
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts
@@ -0,0 +1,54 @@
+import { ROOT } from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  WASIX_TOOLCHAIN_PATH,
+  canonicalWasixCargoToolchainVersions,
+} from './wasix-cargo-toolchain-policy.mts';
+
+export { WASIX_TOOLCHAIN_PATH };
+export const STABLE_WASIX_SOURCE_LANE = 'stable';
+export const WASIX_AOT_ENGINE = 'llvm-opta';
+
+function requiredString(value, context) {
+  if (typeof value !== 'string' || value.length === 0) {
+    throw new Error(`${context} must be a non-empty string`);
+  }
+  return value;
+}
+
+export function canonicalWasixAotMetadata(root = ROOT) {
+  const toolchain = canonicalWasixCargoToolchainVersions(root);
+  return {
+    sourceLane: STABLE_WASIX_SOURCE_LANE,
+    engine: WASIX_AOT_ENGINE,
+    wasmerVersion: toolchain.wasmer,
+    wasmerWasixVersion: toolchain.wasmerWasix,
+  };
+}
+
+export function assertCanonicalWasixAotManifest(
+  manifest,
+  { context = 'WASIX AOT manifest', expectedTarget, canonical = canonicalWasixAotMetadata() } = {},
+) {
+  if (manifest === null || typeof manifest !== 'object' || Array.isArray(manifest)) {
+    throw new Error(`${context} must be a JSON object`);
+  }
+  const expected = [
+    ['format-version', 1],
+    ['source-lane', canonical.sourceLane],
+    ['engine', canonical.engine],
+    ['wasmer-version', canonical.wasmerVersion],
+    ['wasmer-wasix-version', canonical.wasmerWasixVersion],
+  ];
+  if (expectedTarget !== undefined) {
+    expected.push(['target-triple', requiredString(expectedTarget, `${context} expected target`)]);
+  }
+  for (const [field, expectedValue] of expected) {
+    const actualValue = manifest[field];
+    if (actualValue !== expectedValue) {
+      throw new Error(
+        `${context} ${field} must match canonical WASIX metadata: ` +
+          `expected ${JSON.stringify(expectedValue)}, got ${JSON.stringify(actualValue)}`,
+      );
+    }
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.test.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.test.mts
new file mode 100644
index 000000000..2303ec2d8
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.test.mts
@@ -0,0 +1,64 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import test from 'node:test';
+
+import {
+  assertCanonicalWasixAotManifest,
+  canonicalWasixAotMetadata,
+} from './wasix-aot-manifest.mts';
+
+function manifest(overrides = {}) {
+  const canonical = canonicalWasixAotMetadata();
+  return {
+    'format-version': 1,
+    'source-lane': canonical.sourceLane,
+    'target-triple': 'x86_64-unknown-linux-gnu',
+    engine: canonical.engine,
+    'wasmer-version': canonical.wasmerVersion,
+    'wasmer-wasix-version': canonical.wasmerWasixVersion,
+    artifacts: [{ name: 'runtime:oliphaunt', path: 'oliphaunt.aot.zst' }],
+    ...overrides,
+  };
+}
+
+test('accepts AOT metadata that exactly matches the canonical WASIX toolchain', () => {
+  assert.doesNotThrow(() =>
+    assertCanonicalWasixAotManifest(manifest(), {
+      expectedTarget: 'x86_64-unknown-linux-gnu',
+    }),
+  );
+});
+
+test('rejects stale prerelease Wasmer metadata', () => {
+  assert.throws(
+    () =>
+      assertCanonicalWasixAotManifest(
+        manifest({
+          'wasmer-version': '7.2.1-alpha.3',
+          'wasmer-wasix-version': '0.702.1-alpha.3',
+        }),
+        { expectedTarget: 'x86_64-unknown-linux-gnu' },
+      ),
+    /wasmer-version must match canonical WASIX metadata/u,
+  );
+});
+
+test('rejects stale prerelease Wasmer-WASIX metadata', () => {
+  assert.throws(
+    () =>
+      assertCanonicalWasixAotManifest(manifest({ 'wasmer-wasix-version': '0.702.1-alpha.3' }), {
+        expectedTarget: 'x86_64-unknown-linux-gnu',
+      }),
+    /wasmer-wasix-version must match canonical WASIX metadata/u,
+  );
+});
+
+test('rejects an AOT archive labeled for another target', () => {
+  assert.throws(
+    () =>
+      assertCanonicalWasixAotManifest(manifest(), {
+        expectedTarget: 'aarch64-apple-darwin',
+      }),
+    /target-triple must match canonical WASIX metadata/u,
+  );
+});
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts
new file mode 100644
index 000000000..61cbc3228
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts
@@ -0,0 +1,167 @@
+import { compareText } from '../../../../tools/release/release-graph.mts';
+
+export const WASIX_CARGO_ARTIFACT_SCHEMA = 'oliphaunt-liboliphaunt-wasix-cargo-artifacts-v2';
+export const EXTENSION_PORTABLE_TARGET = 'wasix-portable';
+export const RUNTIME_PACKAGE = 'liboliphaunt-wasix-portable';
+export const TOOLS_PACKAGE = 'oliphaunt-wasix-tools';
+export const ICU_PACKAGE = 'oliphaunt-icu';
+
+export const TOOLS_PAYLOAD_FILES = ['bin/pg_dump.wasix.wasm', 'bin/psql.wasix.wasm'];
+
+export const SNOWBALL_STOPWORD_LANGUAGES = [
+  'danish',
+  'dutch',
+  'english',
+  'finnish',
+  'french',
+  'german',
+  'hungarian',
+  'italian',
+  'nepali',
+  'norwegian',
+  'portuguese',
+  'russian',
+  'spanish',
+  'swedish',
+  'turkish',
+];
+
+export const CORE_RUNTIME_ARCHIVE_FILES = [
+  'oliphaunt/bin/initdb',
+  'oliphaunt/bin/postgres',
+  'oliphaunt/lib/postgresql/dict_snowball.so',
+  'oliphaunt/lib/postgresql/plpgsql.so',
+  'oliphaunt/share/postgresql/extension/plpgsql--1.0.sql',
+  'oliphaunt/share/postgresql/extension/plpgsql.control',
+  'oliphaunt/share/postgresql/snowball_create.sql',
+  ...SNOWBALL_STOPWORD_LANGUAGES.map(
+    (language) => `oliphaunt/share/postgresql/tsearch_data/${language}.stop`,
+  ),
+];
+
+export const FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES = [
+  'oliphaunt/bin/pg_ctl',
+  'oliphaunt/bin/pg_dump',
+  'oliphaunt/bin/psql',
+];
+
+export const TOOLS_AOT_ARTIFACTS = ['tool:pg_dump', 'tool:psql'];
+
+export const AOT_PACKAGES = {
+  'macos-arm64': 'liboliphaunt-wasix-aot-aarch64-apple-darwin',
+  'linux-arm64-gnu': 'liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu',
+  'linux-x64-gnu': 'liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu',
+  'windows-x64-msvc': 'liboliphaunt-wasix-aot-x86_64-pc-windows-msvc',
+};
+
+export const TOOLS_AOT_PACKAGES = {
+  'macos-arm64': 'oliphaunt-wasix-tools-aot-aarch64-apple-darwin',
+  'linux-arm64-gnu': 'oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu',
+  'linux-x64-gnu': 'oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu',
+  'windows-x64-msvc': 'oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc',
+};
+
+export const AOT_TARGET_TRIPLES = {
+  'macos-arm64': 'aarch64-apple-darwin',
+  'linux-arm64-gnu': 'aarch64-unknown-linux-gnu',
+  'linux-x64-gnu': 'x86_64-unknown-linux-gnu',
+  'windows-x64-msvc': 'x86_64-pc-windows-msvc',
+};
+
+// crates.io limits package names to 64 characters. Extension AOT carriers can
+// be split into `-part-NNN` crates, so their stable parent names must leave
+// nine characters of headroom. These aliases are package identities only;
+// manifests continue to record the full compilation triple.
+export const EXTENSION_AOT_PACKAGE_SUFFIXES = {
+  'aarch64-apple-darwin': 'macos-arm64',
+  'aarch64-unknown-linux-gnu': 'linux-arm64',
+  'x86_64-unknown-linux-gnu': 'linux-x64',
+  'x86_64-pc-windows-msvc': 'windows-x64',
+};
+
+export const AOT_TARGET_CFGS = {
+  'aarch64-apple-darwin': 'cfg(all(target_os = "macos", target_arch = "aarch64"))',
+  'aarch64-unknown-linux-gnu':
+    'cfg(all(target_os = "linux", target_arch = "aarch64", target_env = "gnu"))',
+  'x86_64-unknown-linux-gnu':
+    'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))',
+  'x86_64-pc-windows-msvc':
+    'cfg(all(target_os = "windows", target_arch = "x86_64", target_env = "msvc"))',
+};
+
+export function publicCargoPackageNames() {
+  return [RUNTIME_PACKAGE, ...Object.values(AOT_PACKAGES)].sort(compareText);
+}
+
+export function publicAotCargoDependencies() {
+  return Object.fromEntries(
+    Object.keys(AOT_PACKAGES)
+      .sort(compareText)
+      .map((target) => [AOT_TARGET_CFGS[AOT_TARGET_TRIPLES[target]], AOT_PACKAGES[target]]),
+  );
+}
+
+export function publicToolsAotCargoDependencies() {
+  return Object.fromEntries(
+    Object.keys(TOOLS_AOT_PACKAGES)
+      .sort(compareText)
+      .map((target) => [AOT_TARGET_CFGS[AOT_TARGET_TRIPLES[target]], TOOLS_AOT_PACKAGES[target]]),
+  );
+}
+
+export function publicToolsFeatureDependencies() {
+  return [
+    `dep:${TOOLS_PACKAGE}`,
+    ...Object.values(TOOLS_AOT_PACKAGES).map((name) => `dep:${name}`),
+  ].sort(compareText);
+}
+
+export function wasixExtensionPackageName(product) {
+  return `${product}-wasix`;
+}
+
+export function wasixExtensionAotPackageName(product, target) {
+  const suffix = EXTENSION_AOT_PACKAGE_SUFFIXES[target];
+  if (suffix === undefined) {
+    throw new TypeError(`unknown extension AOT package target ${JSON.stringify(target)}`);
+  }
+  return `${product}-aot-${suffix}`;
+}
+
+export function expectedExtensionAotTargets() {
+  return [...new Set(Object.values(AOT_TARGET_TRIPLES))].sort(compareText);
+}
+
+export function wasixCargoArtifactContract() {
+  return {
+    schema: WASIX_CARGO_ARTIFACT_SCHEMA,
+    extensionPortableTarget: EXTENSION_PORTABLE_TARGET,
+    runtimePackage: RUNTIME_PACKAGE,
+    toolsPackage: TOOLS_PACKAGE,
+    icuPackage: ICU_PACKAGE,
+    coreRuntimeArchiveFiles: [...CORE_RUNTIME_ARCHIVE_FILES],
+    toolsPayloadFiles: [...TOOLS_PAYLOAD_FILES],
+    forbiddenRuntimeArchiveToolFiles: [...FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES],
+    toolsAotArtifacts: [...TOOLS_AOT_ARTIFACTS],
+    aotPackages: { ...AOT_PACKAGES },
+    toolsAotPackages: { ...TOOLS_AOT_PACKAGES },
+    aotTargetTriples: { ...AOT_TARGET_TRIPLES },
+    aotTargetCfgs: { ...AOT_TARGET_CFGS },
+    extensionAotPackageSuffixes: { ...EXTENSION_AOT_PACKAGE_SUFFIXES },
+    expectedExtensionAotTargets: expectedExtensionAotTargets(),
+    publicCargoPackageNames: publicCargoPackageNames(),
+    publicAotCargoDependencies: publicAotCargoDependencies(),
+    publicToolsAotCargoDependencies: publicToolsAotCargoDependencies(),
+    publicToolsFeatureDependencies: publicToolsFeatureDependencies(),
+  };
+}
+
+if (import.meta.main) {
+  const requested = process.argv[2] ?? 'all';
+  const rows = Object.entries(AOT_TARGET_TRIPLES).filter(
+    ([id, triple]) => requested === 'all' || requested === id || requested === triple,
+  );
+  if (rows.length === 0) throw new Error('unsupported native AOT target: ' + requested);
+  for (const [id, triple] of rows)
+    console.log([triple, 'liboliphaunt-wasix-runtime-aot-' + id, id].join('\t'));
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.mts
new file mode 100644
index 000000000..72ebef503
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.mts
@@ -0,0 +1,144 @@
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
+const CARGO_DEPENDENCY_SOURCE_KEYS = Object.freeze([
+  'branch',
+  'git',
+  'path',
+  'registry',
+  'rev',
+  'tag',
+  'workspace',
+]);
+
+export const WASIX_TOOLCHAIN_PATH = 'src/runtimes/liboliphaunt-wasix/toolchain.toml';
+
+const REQUIRED_WASIX_TOOLCHAIN_PACKAGES = new Map([
+  ['wasmer', 'wasmer'],
+  ['wasmer-compiler', 'wasmer'],
+  ['wasmer-derive', 'wasmer'],
+  ['wasmer-types', 'wasmer'],
+  ['wasmer-vm', 'wasmer'],
+  ['wasmer-config', 'wasmerWasix'],
+  ['wasmer-journal', 'wasmerWasix'],
+  ['wasmer-package', 'wasmerWasix'],
+  ['wasmer-wasix', 'wasmerWasix'],
+  ['wasmer-wasix-types', 'wasmerWasix'],
+  ['virtual-fs', 'wasmerWasix'],
+  ['virtual-mio', 'wasmerWasix'],
+  ['virtual-net', 'wasmerWasix'],
+  ['webc', 'webc'],
+]);
+
+const REQUIRED_CONSUMER_PIN_POLICIES = new Map(
+  [...REQUIRED_WASIX_TOOLCHAIN_PACKAGES]
+    .filter(([, versionKey]) => versionKey === 'wasmerWasix')
+    .map(([name, versionKey]) => [
+      name,
+      Object.freeze({ versionKey, defaultFeaturesDisabled: true }),
+    ]),
+);
+REQUIRED_CONSUMER_PIN_POLICIES.set(
+  'webc',
+  Object.freeze({ versionKey: 'webc', defaultFeaturesDisabled: false }),
+);
+
+export const REQUIRED_WASIX_CONSUMER_PINS = Object.freeze([
+  ...REQUIRED_CONSUMER_PIN_POLICIES.keys(),
+]);
+
+function objectTable(value) {
+  return value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
+}
+
+function requiredString(value, context) {
+  if (typeof value !== 'string' || value.length === 0) {
+    throw new Error(`${context} must be a non-empty string`);
+  }
+  return value;
+}
+
+export function canonicalWasixCargoToolchainVersions(root = ROOT) {
+  const file = path.join(root, WASIX_TOOLCHAIN_PATH);
+  let data;
+  try {
+    data = Bun.TOML.parse(readFileSync(file, 'utf8'));
+  } catch (cause) {
+    throw new Error(`${WASIX_TOOLCHAIN_PATH} cannot be read as TOML: ${cause.message}`);
+  }
+  const toolchain = objectTable(data.toolchain);
+  return Object.freeze({
+    wasmer: requiredString(toolchain.wasmer, `${WASIX_TOOLCHAIN_PATH} toolchain.wasmer`),
+    wasmerWasix: requiredString(
+      toolchain['wasmer-wasix'],
+      `${WASIX_TOOLCHAIN_PATH} toolchain.wasmer-wasix`,
+    ),
+    webc: requiredString(toolchain.webc, `${WASIX_TOOLCHAIN_PATH} toolchain.webc`),
+  });
+}
+
+function dependencyVersion(spec) {
+  if (typeof spec === 'string') return spec;
+  return typeof spec?.version === 'string' ? spec.version : null;
+}
+
+function dependencyName(key, spec) {
+  return typeof spec?.package === 'string' ? spec.package : key;
+}
+
+export function validateWasixConsumerDependencyPins(
+  manifest,
+  { manifestPath = 'src/sdks/rust-wasix/Cargo.toml', toolchainVersions } = {},
+) {
+  const failures = [];
+  const dependencies = objectTable(manifest?.dependencies);
+  for (const [name, policy] of REQUIRED_CONSUMER_PIN_POLICIES) {
+    const expectedVersion = toolchainVersions?.[policy.versionKey];
+    if (typeof expectedVersion !== 'string' || expectedVersion.length === 0) {
+      failures.push(
+        `${manifestPath}: missing canonical ${policy.versionKey} toolchain version for ${name}`,
+      );
+      continue;
+    }
+    const matches = Object.entries(dependencies).filter(
+      ([key, spec]) => dependencyName(key, spec) === name,
+    );
+    if (matches.length !== 1) {
+      failures.push(
+        `${manifestPath} must declare non-optional ${name} exactly once, found ${matches.length}`,
+      );
+      continue;
+    }
+    const [[key, spec]] = matches;
+    const actualVersion = dependencyVersion(spec);
+    if (actualVersion !== `=${expectedVersion}`) {
+      failures.push(
+        `${manifestPath} dependencies.${key} must pin ${name} exactly to =${expectedVersion}, got ${JSON.stringify(actualVersion)}`,
+      );
+    }
+    if (typeof spec === 'object' && spec !== null && spec.optional === true) {
+      failures.push(`${manifestPath} dependencies.${key} must keep ${name} non-optional`);
+    }
+    if (
+      policy.defaultFeaturesDisabled &&
+      (typeof spec !== 'object' || spec === null || spec['default-features'] !== false)
+    ) {
+      failures.push(
+        `${manifestPath} dependencies.${key} must set default-features = false for ${name}`,
+      );
+    }
+    if (typeof spec === 'object' && spec !== null) {
+      const sourceKeys = CARGO_DEPENDENCY_SOURCE_KEYS.filter((sourceKey) =>
+        Object.hasOwn(spec, sourceKey),
+      );
+      if (sourceKeys.length > 0) {
+        failures.push(
+          `${manifestPath} dependencies.${key} must resolve ${name} from crates.io without source selectors, found ${sourceKeys.join(', ')}`,
+        );
+      }
+    }
+  }
+  return failures;
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.test.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.test.mts
new file mode 100644
index 000000000..541654a99
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.test.mts
@@ -0,0 +1,99 @@
+import { expect, test } from 'bun:test';
+import {
+  REQUIRED_WASIX_CONSUMER_PINS,
+  validateWasixConsumerDependencyPins,
+} from './wasix-cargo-toolchain-policy.mts';
+const toolchainVersions = { wasmer: '7.2.1', wasmerWasix: '0.702.1', webc: '12.0.0' };
+
+test('requires exact non-optional pins for the published WASIX family closure', () => {
+  const dependencies = Object.fromEntries(
+    REQUIRED_WASIX_CONSUMER_PINS.map((name) => [
+      name,
+      name === 'webc' ? '=12.0.0' : { version: '=0.702.1', 'default-features': false },
+    ]),
+  );
+  expect(
+    validateWasixConsumerDependencyPins(
+      { dependencies },
+      { manifestPath: 'fixture.toml', toolchainVersions },
+    ),
+  ).toEqual([]);
+
+  dependencies['virtual-mio'] = { version: '0.702.1', 'default-features': false };
+  dependencies['virtual-net'] = {
+    version: '=0.702.1',
+    optional: true,
+    'default-features': false,
+  };
+  delete dependencies['virtual-fs'];
+  expect(
+    validateWasixConsumerDependencyPins(
+      { dependencies },
+      { manifestPath: 'fixture.toml', toolchainVersions },
+    ),
+  ).toEqual([
+    'fixture.toml must declare non-optional virtual-fs exactly once, found 0',
+    'fixture.toml dependencies.virtual-mio must pin virtual-mio exactly to =0.702.1, got "0.702.1"',
+    'fixture.toml dependencies.virtual-net must keep virtual-net non-optional',
+  ]);
+});
+
+test('rejects default-feature and source substitutions in published WASIX pins', () => {
+  const dependencies = Object.fromEntries(
+    REQUIRED_WASIX_CONSUMER_PINS.map((name) => [
+      name,
+      name === 'webc' ? '=12.0.0' : { version: '=0.702.1', 'default-features': false },
+    ]),
+  );
+  delete dependencies['wasmer-config']['default-features'];
+  dependencies['wasmer-journal']['default-features'] = true;
+  dependencies['wasmer-package'].path = '../../substituted';
+  dependencies['wasmer-wasix-types'].git = 'https://example.invalid/wasix';
+  dependencies['virtual-fs'].registry = 'substituted';
+
+  expect(
+    validateWasixConsumerDependencyPins(
+      { dependencies },
+      { manifestPath: 'fixture.toml', toolchainVersions },
+    ),
+  ).toEqual([
+    'fixture.toml dependencies.wasmer-config must set default-features = false for wasmer-config',
+    'fixture.toml dependencies.wasmer-journal must set default-features = false for wasmer-journal',
+    'fixture.toml dependencies.wasmer-package must resolve wasmer-package from crates.io without source selectors, found path',
+    'fixture.toml dependencies.wasmer-wasix-types must resolve wasmer-wasix-types from crates.io without source selectors, found git',
+    'fixture.toml dependencies.virtual-fs must resolve virtual-fs from crates.io without source selectors, found registry',
+  ]);
+});
+
+test('rejects missing, ranged, optional, and source-substituted WebC pins', () => {
+  const dependencies = Object.fromEntries(
+    REQUIRED_WASIX_CONSUMER_PINS.map((name) => [
+      name,
+      name === 'webc' ? '=12.0.0' : { version: '=0.702.1', 'default-features': false },
+    ]),
+  );
+
+  delete dependencies.webc;
+  expect(
+    validateWasixConsumerDependencyPins(
+      { dependencies },
+      { manifestPath: 'missing.toml', toolchainVersions },
+    ),
+  ).toContain('missing.toml must declare non-optional webc exactly once, found 0');
+
+  dependencies.webc = {
+    version: '^12.0.0',
+    optional: true,
+    git: 'https://example.invalid/webc',
+  };
+  expect(
+    validateWasixConsumerDependencyPins(
+      { dependencies },
+      { manifestPath: 'substituted.toml', toolchainVersions },
+    ),
+  ).toEqual([
+    'substituted.toml dependencies.webc must pin webc exactly to =12.0.0, got "^12.0.0"',
+    'substituted.toml dependencies.webc must keep webc non-optional',
+    'substituted.toml dependencies.webc must resolve webc from crates.io without source selectors, found git',
+  ]);
+});
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-cargo-artifact-inventory.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-cargo-artifact-inventory.mts
new file mode 100644
index 000000000..7f2f8bca3
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-cargo-artifact-inventory.mts
@@ -0,0 +1,181 @@
+import {
+  exactExtensionProducts,
+  extensionReleaseProduct,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  declaredCarrierMap,
+  loadPublicationCatalog,
+  resolveActualCarrier,
+} from '../../../../tools/release/publication-catalog.mts';
+import {
+  expectedExtensionAotTargets,
+  wasixExtensionAotPackageName,
+  wasixExtensionPackageName,
+} from './wasix-cargo-artifact-contract.mts';
+
+const PORTABLE_KIND = 'wasix-extension';
+const AOT_KIND = 'wasix-extension-aot';
+const EXTENSION_KINDS = new Set([PORTABLE_KIND, AOT_KIND]);
+const ROLE_KINDS = new Map([
+  ['portable-leaf', PORTABLE_KIND],
+  ['aot-leaf', AOT_KIND],
+]);
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+export function expectedWasixExtensionPackageInventory(
+  tool = 'wasix-extension-cargo-artifact-inventory.mts',
+  products = exactExtensionProducts(tool),
+) {
+  const selectedProducts = [...new Set(products)].sort(compareText);
+  const releaseProducts = [
+    ...new Set(selectedProducts.map((product) => extensionReleaseProduct(product, 'wasix', tool))),
+  ].sort(compareText);
+  const catalog = loadPublicationCatalog(tool, { products: releaseProducts });
+  const expectedPackageKinds = new Map();
+  const portableProducts = new Set();
+  const carrierProducts = new Map();
+  for (const product of selectedProducts) {
+    carrierProducts.set(wasixExtensionPackageName(product), { kind: PORTABLE_KIND, product });
+    for (const target of expectedExtensionAotTargets()) {
+      carrierProducts.set(wasixExtensionAotPackageName(product, target), {
+        kind: AOT_KIND,
+        product,
+      });
+    }
+  }
+  for (const carrier of catalog.carriers) {
+    if (carrier.ecosystem !== 'cargo') {
+      continue;
+    }
+    const expected = carrierProducts.get(carrier.name);
+    if (expected === undefined || ROLE_KINDS.get(carrier.role) !== expected.kind) {
+      continue;
+    }
+    expectedPackageKinds.set(carrier.name, expected.kind);
+    if (carrier.role === 'portable-leaf') {
+      portableProducts.add(expected.product);
+    }
+  }
+  const missingPortable = selectedProducts.filter((product) => !portableProducts.has(product));
+  if (missingPortable.length > 0) {
+    throw new Error(
+      `public Cargo inventory is missing WASIX portable carriers for: ${missingPortable.join(', ')}`,
+    );
+  }
+  return {
+    catalog,
+    declaredCarriers: declaredCarrierMap(catalog),
+    expectedPackageKinds,
+    products: selectedProducts,
+  };
+}
+
+export function expectedWasixExtensionPackageKinds(
+  tool = 'wasix-extension-cargo-artifact-inventory.mts',
+  products = exactExtensionProducts(tool),
+) {
+  return expectedWasixExtensionPackageInventory(tool, products).expectedPackageKinds;
+}
+
+function expectedCarrier(inventory, name, prefix) {
+  const carrier = resolveActualCarrier(inventory.catalog, 'cargo', name, prefix);
+  const base =
+    carrier.role === 'payload-part'
+      ? inventory.declaredCarriers.get(carrier.parentCarrier)
+      : carrier;
+  const kind = base === undefined ? undefined : inventory.expectedPackageKinds.get(base.name);
+  if (kind === undefined) {
+    return null;
+  }
+  return { base, carrier, kind };
+}
+
+export function isExpectedWasixExtensionPackage(name, kind, inventory) {
+  try {
+    return expectedCarrier(inventory, name, 'WASIX extension Cargo inventory')?.kind === kind;
+  } catch {
+    return false;
+  }
+}
+
+export function validateWasixExtensionArtifactInventory(packages, inventory) {
+  const generatedBases = new Set();
+  const partsByParent = new Map();
+  const seenNames = new Set();
+  for (const item of packages) {
+    if (item === null || Array.isArray(item) || typeof item !== 'object') {
+      throw new Error('WASIX Cargo artifact package entries must be objects');
+    }
+    const { name, kind } = item;
+    if (typeof name !== 'string' || name.length === 0 || typeof kind !== 'string') {
+      throw new Error(
+        `WASIX Cargo artifact package entry has an invalid name/kind: ${JSON.stringify(item)}`,
+      );
+    }
+    if (seenNames.has(name)) {
+      throw new Error(`duplicate WASIX Cargo artifact package ${name}`);
+    }
+    seenNames.add(name);
+
+    let expected;
+    try {
+      expected = expectedCarrier(inventory, name, 'WASIX extension Cargo artifact inventory');
+    } catch (error) {
+      if (EXTENSION_KINDS.has(kind)) {
+        throw error;
+      }
+      continue;
+    }
+    if (expected === null) {
+      if (EXTENSION_KINDS.has(kind)) {
+        throw new Error(`unexpected WASIX extension Cargo artifact package ${name}`);
+      }
+      continue;
+    }
+    if (kind !== expected.kind) {
+      throw new Error(
+        `WASIX extension Cargo artifact package ${name} has kind ${kind}; expected ${expected.kind}`,
+      );
+    }
+    if (expected.carrier.role === 'payload-part') {
+      const parts = partsByParent.get(expected.carrier.parentCarrier) ?? [];
+      parts.push(expected.carrier.part);
+      partsByParent.set(expected.carrier.parentCarrier, parts);
+    } else {
+      generatedBases.add(expected.carrier.name);
+    }
+  }
+
+  const missing = [...inventory.expectedPackageKinds.keys()]
+    .filter((name) => !generatedBases.has(name))
+    .sort(compareText);
+  if (missing.length > 0) {
+    throw new Error(
+      `generated liboliphaunt-wasix Cargo artifacts are missing configured extension base crates: ${missing.join(', ')}`,
+    );
+  }
+
+  for (const [parent, numbers] of [...partsByParent].sort(([left], [right]) =>
+    compareText(left, right),
+  )) {
+    const parentName = parent.slice('cargo:'.length);
+    if (!generatedBases.has(parentName)) {
+      throw new Error(
+        `WASIX extension Cargo payload parts require their declared parent ${parent}`,
+      );
+    }
+    const actual = [...numbers].sort((left, right) => left - right);
+    const expected = Array.from({ length: actual.length }, (_, index) => index + 1);
+    if (
+      actual.length !== expected.length ||
+      actual.some((part, index) => part !== expected[index])
+    ) {
+      throw new Error(
+        `${parent} Cargo payload parts must be contiguous from part-001; found ${actual.map((part) => String(part).padStart(3, '0')).join(', ')}`,
+      );
+    }
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-features.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-features.mts
new file mode 100755
index 000000000..2aa9f7647
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-features.mts
@@ -0,0 +1,62 @@
+#!/usr/bin/env bun
+
+import { readFileSync } from 'node:fs';
+
+const TOOL = 'wasix-extension-features.mts';
+const DEFAULT_MANIFEST = 'target/extensions/wasix/assets/manifest.json';
+const SQL_NAME_RE = /^[a-z0-9][a-z0-9_-]*$/u;
+
+function invariant(condition, message) {
+  if (!condition) throw new Error(`${TOOL}: ${message}`);
+}
+
+export function extensionFeatures(manifest) {
+  invariant(
+    manifest !== null && typeof manifest === 'object' && !Array.isArray(manifest),
+    'asset manifest must be an object',
+  );
+  invariant(Array.isArray(manifest.extensions), 'asset manifest must contain an extensions array');
+
+  const features = [];
+  const sqlNames = new Set();
+  for (const extension of manifest.extensions) {
+    invariant(
+      extension !== null && typeof extension === 'object' && !Array.isArray(extension),
+      'extension manifest rows must be objects',
+    );
+    const sqlName = extension['sql-name'];
+    invariant(
+      typeof sqlName === 'string' && SQL_NAME_RE.test(sqlName),
+      'extensions must have a portable sql-name',
+    );
+    invariant(!sqlNames.has(sqlName), `asset manifest repeats extension ${sqlName}`);
+    sqlNames.add(sqlName);
+    features.push(`extension-${sqlName.replaceAll('_', '-')}`);
+  }
+
+  invariant(features.length > 0, 'full WASIX evidence requires at least one extension');
+  return features.sort();
+}
+
+export function fullEvidenceFeatures(manifest) {
+  return ['extensions', 'tools', ...extensionFeatures(manifest)].join(',');
+}
+
+function main(argv) {
+  if (argv.length > 1 || argv[0] === '--help' || argv[0] === '-h') {
+    console.log(`usage: ${TOOL} [ASSET_MANIFEST]`);
+    return;
+  }
+  const file = argv[0] ?? DEFAULT_MANIFEST;
+  const manifest = JSON.parse(readFileSync(file, 'utf8'));
+  console.log(fullEvidenceFeatures(manifest));
+}
+
+if (import.meta.main) {
+  try {
+    main(Bun.argv.slice(2));
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(1);
+  }
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-features.test.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-features.test.mts
new file mode 100644
index 000000000..2977c90aa
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-features.test.mts
@@ -0,0 +1,58 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+import test from 'node:test';
+
+import { extensionFeatures, fullEvidenceFeatures } from './wasix-extension-features.mts';
+
+const ROOT = path.resolve(import.meta.dirname, '../../../..');
+
+test('the live WASIX public surface includes the PostGIS product', () => {
+  const manifest = JSON.parse(
+    readFileSync(path.join(ROOT, 'src/extensions/generated/wasix/extensions.json'), 'utf8'),
+  );
+  assert.equal(
+    manifest.extensions.some((row) => row['sql-name'] === 'postgis'),
+    true,
+  );
+
+  for (const relative of [
+    'src/runtimes/liboliphaunt-wasix/crates/assets/Cargo.toml',
+    'src/sdks/rust-wasix/Cargo.toml',
+  ]) {
+    const cargo = Bun.TOML.parse(readFileSync(path.join(ROOT, relative), 'utf8'));
+    assert.equal(Object.hasOwn(cargo.features ?? {}, 'extension-postgis'), true, relative);
+  }
+});
+
+test('full WASIX evidence enables every extension feature', () => {
+  const manifest = {
+    extensions: [{ 'sql-name': 'vector' }, { 'sql-name': 'pg_trgm' }],
+  };
+
+  assert.deepEqual(extensionFeatures(manifest), ['extension-pg-trgm', 'extension-vector']);
+  assert.equal(
+    fullEvidenceFeatures(manifest),
+    'extensions,tools,extension-pg-trgm,extension-vector',
+  );
+});
+
+test('full WASIX evidence rejects empty or ambiguous extension identities', () => {
+  assert.throws(() => extensionFeatures({ extensions: [] }), /at least one extension/u);
+  assert.throws(
+    () =>
+      extensionFeatures({
+        extensions: [{ 'sql-name': 'vector' }, { 'sql-name': 'vector' }],
+      }),
+    /repeats extension vector/u,
+  );
+  assert.throws(
+    () =>
+      extensionFeatures({
+        extensions: [{ 'sql-name': 'bad/name' }],
+      }),
+    /portable sql-name/u,
+  );
+});
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-carrier.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-carrier.mts
new file mode 100644
index 000000000..820e4e775
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-carrier.mts
@@ -0,0 +1,459 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { chmodSync, lstatSync, mkdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
+import { isDeepStrictEqual } from 'node:util';
+import path from 'node:path';
+
+import { validatePortableReleaseAsset } from './check-release-assets.mts';
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import {
+  NPM_TRUSTED_PUBLISHING_REPOSITORY,
+  validateNpmTrustedPublishingManifest,
+} from '../../../../tools/packaging/npm-trusted-publishing.mts';
+import {
+  canonicalGzipSync,
+  readPortableArchiveEntries,
+  readPortableTarZstdBufferEntries,
+} from '../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  releaseNoticeRows,
+  releaseProfilePackageLicense,
+  stageReleaseNotices,
+} from '../../../../tools/packaging/release-notices.mts';
+import {
+  WASIX_PORTABLE_RELEASE_MEMBERS,
+  WASIX_RUNTIME_ARCHIVE_PATH,
+  WASIX_RUNTIME_NPM_ASSET_PATHS,
+  WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA,
+  WASIX_RUNTIME_NPM_PACKAGE,
+  WASIX_RUNTIME_NPM_TARGET,
+  WASIX_RUNTIME_PRODUCT,
+} from './wasix-runtime-npm-contract.mts';
+import {
+  renderWasixRuntimeDescriptorModule,
+  renderWasixRuntimeDescriptorTypes,
+} from './wasix-runtime-npm-descriptor.mts';
+
+export {
+  renderWasixRuntimeDescriptorModule,
+  renderWasixRuntimeDescriptorTypes,
+} from './wasix-runtime-npm-descriptor.mts';
+
+const TOOL = 'wasix-runtime-npm-carrier.mts';
+const ROOT = path.resolve(import.meta.dirname, '../../../..');
+const LOWER_SHA256 = /^[0-9a-f]{64}$/u;
+const SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/u;
+const RUNTIME_MODULE_MEMBER = 'oliphaunt/bin/postgres';
+const NPM_PACKAGE_SAFETY_LIMIT_BYTES = 100 * 1024 * 1024;
+const NOTICE_OPTIONS = Object.freeze({ profile: 'wasix-runtime' });
+
+function fail(message) {
+  throw new Error(`${TOOL}: ${message}`);
+}
+
+function rel(file) {
+  const relative = path.relative(ROOT, file).split(path.sep).join('/');
+  return relative && !relative.startsWith('../') ? relative : String(file);
+}
+
+function sha256Bytes(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function regularFile(file, label) {
+  let metadata;
+  try {
+    metadata = lstatSync(file);
+  } catch (cause) {
+    fail(`${label} cannot be inspected: ${cause.message}`);
+  }
+  if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) {
+    fail(`${label} must be a non-empty regular non-symlink file: ${rel(file)}`);
+  }
+  return metadata;
+}
+
+function parseJsonBytes(bytes, label) {
+  let value;
+  try {
+    value = JSON.parse(Buffer.from(bytes).toString('utf8'));
+  } catch (cause) {
+    fail(`${label} must contain UTF-8 JSON: ${cause.message}`);
+  }
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(`${label} must contain a JSON object`);
+  }
+  return value;
+}
+
+function object(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(`${label} must be an object`);
+  }
+  return value;
+}
+
+function nonEmptyString(value, label) {
+  if (typeof value !== 'string' || value.length === 0 || value.includes('\0')) {
+    fail(`${label} must be a non-empty string without NUL bytes`);
+  }
+  return value;
+}
+
+function checkedSha256(value, label) {
+  if (typeof value !== 'string' || !LOWER_SHA256.test(value)) {
+    fail(`${label} must be a lowercase SHA-256 digest`);
+  }
+  return value;
+}
+
+function safeRelativePath(value, label) {
+  const result = nonEmptyString(value, label);
+  const segments = result.split('/');
+  if (
+    result.startsWith('/') ||
+    result.includes('\\') ||
+    segments.some((segment) => segment.length === 0 || segment === '.' || segment === '..')
+  ) {
+    fail(`${label} must be a canonical safe relative path`);
+  }
+  return result;
+}
+
+function postgresMajor(value, label) {
+  return nonEmptyString(value, label).split('.')[0];
+}
+
+function requireRegularEntry(entries, member, label) {
+  const entry = entries.get(member);
+  if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) {
+    fail(`${label} must contain ${member} as one non-empty regular file`);
+  }
+  return entry;
+}
+
+/**
+ * Validate the complete core-manifest projection consumed by WASIX hosts.
+ * Keep this producer-side gate in lockstep with the binding's parser so a
+ * package cannot be publishable but unusable by every consumer.
+ */
+function assertCoreManifestContract(manifest, runtimeEntries) {
+  if (manifest['format-version'] !== 2) {
+    fail('frozen WASIX core manifest must use format-version 2');
+  }
+  nonEmptyString(manifest['source-fingerprint'], 'frozen WASIX core manifest source-fingerprint');
+  const runtime = object(manifest.runtime, 'frozen WASIX core manifest runtime');
+  safeRelativePath(runtime.archive, 'frozen WASIX core manifest runtime.archive');
+  checkedSha256(runtime.sha256, 'frozen WASIX core manifest runtime.sha256');
+  if (runtime.size !== undefined && (!Number.isSafeInteger(runtime.size) || runtime.size <= 0)) {
+    fail('frozen WASIX core manifest runtime.size must be a positive safe integer when present');
+  }
+  const runtimeModuleSha256 = checkedSha256(
+    runtime['module-sha256'],
+    'frozen WASIX core manifest runtime.module-sha256',
+  );
+  postgresMajor(runtime['postgres-version'], 'frozen WASIX core manifest runtime.postgres-version');
+  const link = object(runtime.link, 'frozen WASIX core manifest runtime.link');
+  if (!Array.isArray(link.exports)) {
+    fail('frozen WASIX core manifest runtime.link.exports must be an array');
+  }
+  for (const [index, value] of link.exports.entries()) {
+    const entry = object(value, `frozen WASIX core manifest runtime.link.exports[${index}]`);
+    nonEmptyString(entry.name, `frozen WASIX core manifest runtime.link.exports[${index}].name`);
+    nonEmptyString(entry.kind, `frozen WASIX core manifest runtime.link.exports[${index}].kind`);
+  }
+
+  if (!Array.isArray(manifest['runtime-support'])) {
+    fail('frozen WASIX core manifest runtime-support must be an array');
+  }
+  const supportNames = new Set();
+  const supportPaths = new Set();
+  for (const [index, value] of manifest['runtime-support'].entries()) {
+    const entry = object(value, `frozen WASIX core manifest runtime-support[${index}]`);
+    const name = nonEmptyString(
+      entry.name,
+      `frozen WASIX core manifest runtime-support[${index}].name`,
+    );
+    if (!SQL_NAME.test(name) || supportNames.has(name)) {
+      fail(`frozen WASIX core manifest runtime-support[${index}].name must be unique and portable`);
+    }
+    supportNames.add(name);
+    const supportPath = safeRelativePath(
+      entry.path,
+      `frozen WASIX core manifest runtime-support[${index}].path`,
+    );
+    if (!supportPath.startsWith('lib/postgresql/') || supportPaths.has(supportPath)) {
+      fail(
+        `frozen WASIX core manifest runtime-support[${index}].path must be unique under lib/postgresql/`,
+      );
+    }
+    supportPaths.add(supportPath);
+    checkedSha256(entry.sha256, `frozen WASIX core manifest runtime-support[${index}].sha256`);
+  }
+
+  const runtimeModule = requireRegularEntry(
+    runtimeEntries,
+    RUNTIME_MODULE_MEMBER,
+    'frozen WASIX runtime archive',
+  );
+  if (sha256Bytes(runtimeModule.data()) !== runtimeModuleSha256) {
+    fail('frozen WASIX runtime module does not match manifest runtime.module-sha256');
+  }
+}
+
+function checkedAssetMetadata(value, expectedArchive, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(`${label} must be an object`);
+  }
+  if (value.archive !== expectedArchive) {
+    fail(`${label}.archive must be ${expectedArchive}, got ${JSON.stringify(value.archive)}`);
+  }
+  if (typeof value.sha256 !== 'string' || !LOWER_SHA256.test(value.sha256)) {
+    fail(`${label}.sha256 must be a lowercase SHA-256 digest`);
+  }
+  return value;
+}
+
+function requireArchiveEntry(entries, member, archive) {
+  const entry = entries.get(member);
+  if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) {
+    fail(`${rel(archive)} must contain ${member} as one non-empty regular file`);
+  }
+  return Buffer.from(entry.data());
+}
+
+function checkedInputArchive(bytes, label) {
+  try {
+    return readPortableTarZstdBufferEntries(bytes, { label });
+  } catch (cause) {
+    fail(cause.message);
+  }
+}
+
+export function wasixRuntimeNpmInputs({ portableReleaseArchive }) {
+  const releaseArchive = path.resolve(portableReleaseArchive);
+  regularFile(releaseArchive, 'portable WASIX release archive');
+  validatePortableReleaseAsset(releaseArchive);
+
+  const releaseEntries = readPortableArchiveEntries(releaseArchive);
+  const manifestBytes = requireArchiveEntry(
+    releaseEntries,
+    WASIX_PORTABLE_RELEASE_MEMBERS.manifest,
+    releaseArchive,
+  );
+  const runtimeBytes = requireArchiveEntry(
+    releaseEntries,
+    WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive,
+    releaseArchive,
+  );
+  const manifest = parseJsonBytes(
+    manifestBytes,
+    `${rel(releaseArchive)} ${WASIX_PORTABLE_RELEASE_MEMBERS.manifest}`,
+  );
+  if (!Array.isArray(manifest.extensions) || manifest.extensions.length !== 0) {
+    fail('frozen WASIX core manifest must contain an empty extensions array');
+  }
+  if (Object.hasOwn(manifest, 'pg-dump') || Object.hasOwn(manifest, 'psql')) {
+    fail('frozen WASIX core manifest must not claim split tool payloads');
+  }
+  const runtime = checkedAssetMetadata(
+    manifest.runtime,
+    WASIX_RUNTIME_ARCHIVE_PATH,
+    'frozen WASIX core manifest runtime',
+  );
+  if (sha256Bytes(runtimeBytes) !== runtime.sha256) {
+    fail('frozen WASIX runtime archive does not match manifest.runtime.sha256');
+  }
+  if (runtime.size !== undefined && runtimeBytes.length !== runtime.size) {
+    fail('frozen WASIX runtime archive does not match manifest.runtime.size');
+  }
+  const runtimeEntries = checkedInputArchive(
+    runtimeBytes,
+    `${rel(releaseArchive)} runtime archive`,
+  );
+  assertCoreManifestContract(manifest, runtimeEntries);
+
+  return Object.freeze({
+    manifest: Object.freeze({
+      bytes: manifestBytes,
+      sha256: sha256Bytes(manifestBytes),
+      size: manifestBytes.length,
+    }),
+    runtimeArchive: Object.freeze({
+      archive: runtime.archive,
+      bytes: runtimeBytes,
+      sha256: runtime.sha256,
+      size: runtimeBytes.length,
+    }),
+  });
+}
+
+function writeJson(file, value) {
+  writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o644 });
+  chmodSync(file, 0o644);
+}
+
+function writeReadme(packageDir) {
+  writeFileSync(
+    path.join(packageDir, 'README.md'),
+    `# ${WASIX_RUNTIME_NPM_PACKAGE}
+
+Internal host-neutral portable runtime carrier for \`@oliphaunt/wasix-ts\`.
+Application code should depend on the binding, which selects this matching
+carrier automatically. The descriptor and assets can be consumed by browser
+or Node/Bun/Deno/Electron WASIX hosts; importing them alone is not a host-support claim.
+The public binding declares this carrier as an exact release-staged dependency;
+applications do not configure its package-relative assets.
+
+The carried manifest retains the exact qualified core identity projection and
+an empty extension inventory. Extension metadata and bytes remain in their
+independently versioned \`@oliphaunt/extension-*-wasix\` packages, so an
+extension release never mutates this runtime carrier.
+`,
+  );
+}
+
+export function stageWasixRuntimeNpmCarrier({ version, portableReleaseArchive, packageDir }) {
+  if (typeof version !== 'string' || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.test(version)) {
+    throw new TypeError(`${TOOL}: version must be an exact stable semantic version`);
+  }
+  const output = path.resolve(packageDir);
+  const inputs = wasixRuntimeNpmInputs({ portableReleaseArchive });
+  rmSync(output, { recursive: true, force: true });
+  mkdirSync(path.join(output, 'assets'), { recursive: true });
+  for (const [name, input] of Object.entries({
+    runtimeArchive: inputs.runtimeArchive,
+    manifest: inputs.manifest,
+  })) {
+    const destination = path.join(output, ...WASIX_RUNTIME_NPM_ASSET_PATHS[name].split('/'));
+    writeFileSync(destination, input.bytes, { flag: 'wx', mode: 0o644 });
+    chmodSync(destination, 0o644);
+  }
+
+  const descriptorInput = { version, ...inputs };
+  writeFileSync(path.join(output, 'index.js'), renderWasixRuntimeDescriptorModule(descriptorInput));
+  writeFileSync(path.join(output, 'index.d.ts'), renderWasixRuntimeDescriptorTypes());
+  chmodSync(path.join(output, 'index.js'), 0o644);
+  chmodSync(path.join(output, 'index.d.ts'), 0o644);
+  writeReadme(output);
+  chmodSync(path.join(output, 'README.md'), 0o644);
+  stageReleaseNotices(output, NOTICE_OPTIONS);
+
+  const noticeFiles = releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => member);
+  const packageJson = {
+    name: WASIX_RUNTIME_NPM_PACKAGE,
+    version,
+    description: 'Portable liboliphaunt WASIX runtime assets for Oliphaunt hosts.',
+    license: releaseProfilePackageLicense('wasix-runtime').spdx,
+    type: 'module',
+    sideEffects: false,
+    repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY },
+    oliphaunt: {
+      product: WASIX_RUNTIME_PRODUCT,
+      kind: 'wasix-runtime',
+      runtime: 'wasix',
+      target: WASIX_RUNTIME_NPM_TARGET,
+      descriptorSchema: WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA,
+      manifestProjection: 'core',
+    },
+    publishConfig: { access: 'public', provenance: true },
+    files: ['README.md', 'index.js', 'index.d.ts', 'assets', ...noticeFiles],
+    exports: {
+      '.': { types: './index.d.ts', import: './index.js', default: './index.js' },
+      './package.json': './package.json',
+    },
+  };
+  validateNpmTrustedPublishingManifest(
+    packageJson,
+    `${WASIX_RUNTIME_NPM_PACKAGE} generated package`,
+  );
+  writeJson(path.join(output, 'package.json'), packageJson);
+  assertReleaseNoticesInDirectory(output, NOTICE_OPTIONS);
+  return Object.freeze({
+    descriptor: descriptorInput,
+    packageDir: output,
+    packageName: WASIX_RUNTIME_NPM_PACKAGE,
+  });
+}
+
+function packedFileEntries(entries) {
+  return [...entries]
+    .filter(([, entry]) => entry.isFile)
+    .map(([member]) => member)
+    .sort();
+}
+
+export function assertWasixRuntimeNpmArchive(archive, { version, descriptor }) {
+  const file = path.resolve(archive);
+  regularFile(file, 'WASIX runtime npm carrier');
+  if (statSync(file).size > NPM_PACKAGE_SAFETY_LIMIT_BYTES) {
+    fail(
+      `${rel(file)} exceeds the ${NPM_PACKAGE_SAFETY_LIMIT_BYTES}-byte npm carrier safety limit`,
+    );
+  }
+  assertReleaseNoticesInArchive(file, { ...NOTICE_OPTIONS, prefix: 'package' });
+  const entries = readPortableArchiveEntries(file);
+  const expectedFiles = [
+    'package/package.json',
+    'package/README.md',
+    'package/index.js',
+    'package/index.d.ts',
+    ...Object.values(WASIX_RUNTIME_NPM_ASSET_PATHS).map((member) => `package/${member}`),
+    ...releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => `package/${member}`),
+  ].sort();
+  const actualFiles = packedFileEntries(entries);
+  if (!isDeepStrictEqual(actualFiles, expectedFiles)) {
+    fail(`${rel(file)} regular file inventory differs from the generated package allowlist`);
+  }
+  for (const [member, entry] of entries) {
+    if (entry.isSymbolicLink) fail(`${rel(file)} must not contain symbolic link ${member}`);
+  }
+
+  const packageJson = parseJsonBytes(
+    requireArchiveEntry(entries, 'package/package.json', file),
+    `${rel(file)} package/package.json`,
+  );
+  validateNpmTrustedPublishingManifest(packageJson, `${rel(file)} package/package.json`);
+  if (packageJson.name !== WASIX_RUNTIME_NPM_PACKAGE || packageJson.version !== version) {
+    fail(`${rel(file)} must identify ${WASIX_RUNTIME_NPM_PACKAGE}@${version}`);
+  }
+  for (const name of ['runtimeArchive', 'manifest']) {
+    const bytes = requireArchiveEntry(
+      entries,
+      `package/${WASIX_RUNTIME_NPM_ASSET_PATHS[name]}`,
+      file,
+    );
+    if (bytes.length !== descriptor[name].size || sha256Bytes(bytes) !== descriptor[name].sha256) {
+      fail(`${rel(file)} ${name} bytes differ from the generated descriptor`);
+    }
+  }
+  return packageJson;
+}
+
+export function packWasixRuntimeNpmCarrier({
+  version,
+  portableReleaseArchive,
+  packageDir = path.join(ROOT, 'target/release/npm-package-sources/liboliphaunt-wasix'),
+  tarballRoot = path.join(ROOT, 'target/release/npm-packages/liboliphaunt-wasix'),
+}) {
+  const staged = stageWasixRuntimeNpmCarrier({
+    version,
+    portableReleaseArchive,
+    packageDir,
+  });
+  const outputRoot = path.resolve(tarballRoot);
+  rmSync(outputRoot, { recursive: true, force: true });
+  mkdirSync(outputRoot, { recursive: true });
+  const tarball = path.join(outputRoot, `oliphaunt-liboliphaunt-wasix-${version}.tgz`);
+  writeFileSync(
+    tarball,
+    canonicalGzipSync(
+      createDeterministicTar(staged.packageDir, 'package', { fail, fixedFileMode: 0o644 }),
+    ),
+  );
+  assertWasixRuntimeNpmArchive(tarball, { version, descriptor: staged.descriptor });
+  return Object.freeze({ ...staged, tarball });
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-carrier.test.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-carrier.test.mts
new file mode 100644
index 000000000..c2161d260
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-carrier.test.mts
@@ -0,0 +1,181 @@
+#!/usr/bin/env bun
+import { afterAll, expect, test } from 'bun:test';
+import { createHash } from 'node:crypto';
+import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { zstdCompressSync } from 'node:zlib';
+
+import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts';
+import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts';
+import { CORE_RUNTIME_ARCHIVE_FILES } from './wasix-cargo-artifact-contract.mts';
+import { packWasixRuntimeNpmCarrier } from './wasix-runtime-npm-carrier.mts';
+import {
+  WASIX_PORTABLE_RELEASE_MEMBERS,
+  WASIX_RUNTIME_NPM_PACKAGE,
+} from './wasix-runtime-npm-contract.mts';
+
+const directories = [];
+
+afterAll(() => {
+  for (const directory of directories) rmSync(directory, { recursive: true, force: true });
+});
+
+function temporaryRoot(name) {
+  const root = mkdtempSync(path.join(os.tmpdir(), name));
+  directories.push(root);
+  return root;
+}
+
+function sha256(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function deterministicTar(stage, archiveRoot) {
+  return createDeterministicTar(stage, archiveRoot, {
+    fail(message) {
+      throw new Error(message);
+    },
+    fixedFileMode: 0o644,
+  });
+}
+
+function writeMember(stage, member, bytes) {
+  const output = path.join(stage, ...member.split('/'));
+  mkdirSync(path.dirname(output), { recursive: true });
+  writeFileSync(output, bytes);
+}
+
+function portableReleaseFixture(root, { transformManifest = (manifest) => manifest } = {}) {
+  const runtimeStage = path.join(root, 'runtime-stage');
+  for (const member of CORE_RUNTIME_ARCHIVE_FILES) {
+    expect(member.startsWith('oliphaunt/')).toBe(true);
+    writeMember(runtimeStage, member.slice('oliphaunt/'.length), `fixture:${member}\n`);
+  }
+  const runtimeBytes = zstdCompressSync(deterministicTar(runtimeStage, 'oliphaunt'));
+
+  const sourceFingerprint = 'fixture-postgres-source-fingerprint';
+  const runtimeModuleSha256 = sha256(Buffer.from('fixture:oliphaunt/bin/postgres\n'));
+  const manifest = transformManifest({
+    'format-version': 2,
+    'source-fingerprint': sourceFingerprint,
+    runtime: {
+      archive: 'oliphaunt.wasix.tar.zst',
+      sha256: sha256(runtimeBytes),
+      size: runtimeBytes.length,
+      'module-sha256': runtimeModuleSha256,
+      'postgres-version': '18.4',
+      link: { exports: [] },
+    },
+    'runtime-support': [],
+    extensions: [],
+  });
+  const manifestBytes = Buffer.from(`${JSON.stringify(manifest, null, 2)}\n`);
+  const releaseStage = path.join(root, 'release-stage');
+  writeMember(releaseStage, WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive, runtimeBytes);
+  writeMember(releaseStage, WASIX_PORTABLE_RELEASE_MEMBERS.manifest, manifestBytes);
+  stageReleaseNotices(releaseStage, { profile: 'wasix-runtime' });
+  const archive = path.join(root, 'liboliphaunt-wasix-7.8.9-runtime-portable.tar.zst');
+  writeFileSync(archive, zstdCompressSync(deterministicTar(releaseStage, '.')));
+  return { archive, manifestBytes, runtimeBytes };
+}
+
+test('rejects a core manifest that omits host-required identity metadata', () => {
+  const root = temporaryRoot('oliphaunt-wasix-runtime-invalid-manifest-');
+  const fixture = portableReleaseFixture(root, {
+    transformManifest(manifest) {
+      delete manifest.runtime.link;
+      return manifest;
+    },
+  });
+  expect(() =>
+    packWasixRuntimeNpmCarrier({
+      version: '7.8.9',
+      portableReleaseArchive: fixture.archive,
+      packageDir: path.join(root, 'package'),
+      tarballRoot: path.join(root, 'tarballs'),
+    }),
+  ).toThrow(/runtime[.]link must be an object/u);
+});
+
+test('rejects a core manifest whose optional runtime size differs from its bytes', () => {
+  const root = temporaryRoot('oliphaunt-wasix-runtime-invalid-size-');
+  const fixture = portableReleaseFixture(root, {
+    transformManifest(manifest) {
+      manifest.runtime.size += 1;
+      return manifest;
+    },
+  });
+  expect(() =>
+    packWasixRuntimeNpmCarrier({
+      version: '7.8.9',
+      portableReleaseArchive: fixture.archive,
+      packageDir: path.join(root, 'package'),
+      tarballRoot: path.join(root, 'tarballs'),
+    }),
+  ).toThrow(/runtime archive does not match manifest[.]runtime[.]size/u);
+});
+
+test('packs the exact qualified core projection as one host-neutral npm carrier', () => {
+  const parent = process.env.OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT;
+  if (!parent) throw new Error('Run bash src/runtimes/liboliphaunt-wasix/tools/test-packaging.sh');
+  const root = path.join(parent, 'npm-runtime');
+  mkdirSync(root);
+  const fixture = portableReleaseFixture(root);
+  const packed = packWasixRuntimeNpmCarrier({
+    version: '7.8.9',
+    portableReleaseArchive: fixture.archive,
+    packageDir: path.join(root, 'package'),
+    tarballRoot: path.join(root, 'tarballs'),
+  });
+  const packageJson = JSON.parse(
+    readFileSync(path.join(packed.packageDir, 'package.json'), 'utf8'),
+  );
+  expect(packageJson.name).toBe(WASIX_RUNTIME_NPM_PACKAGE);
+  expect(packageJson.version).toBe('7.8.9');
+  expect(packageJson.oliphaunt.manifestProjection).toBe('core');
+  expect(Object.keys(packed.descriptor).sort()).toEqual(['manifest', 'runtimeArchive', 'version']);
+  expect(readFileSync(path.join(packed.packageDir, 'assets/manifest.json'))).toEqual(
+    fixture.manifestBytes,
+  );
+});
+
+test('rejects stale bundled-seed manifests and a runtime module with the wrong identity', () => {
+  for (const [change, error] of [
+    [
+      (manifest) => {
+        manifest['cluster-seeds'] = {};
+      },
+      /must not bundle independently packaged cluster seeds/,
+    ],
+    [
+      (manifest) => {
+        manifest.runtime['module-sha256'] = '0'.repeat(64);
+      },
+      /runtime module does not match/,
+    ],
+  ]) {
+    const root = temporaryRoot('oliphaunt-wasix-runtime-identity-');
+    const fixture = portableReleaseFixture(root, {
+      transformManifest(manifest) {
+        change(manifest);
+        return manifest;
+      },
+    });
+    expect(() =>
+      packWasixRuntimeNpmCarrier({
+        version: '7.8.9',
+        portableReleaseArchive: fixture.archive,
+        packageDir: path.join(root, 'package'),
+        tarballRoot: path.join(root, 'tarballs'),
+      }),
+    ).toThrow(error);
+  }
+});
+
+test('rejects invalid generated carrier versions before touching staging paths', async () => {
+  const pack = packWasixRuntimeNpmCarrier;
+  for (const version of ['../outside', '01.2.3', '1.2', '1.2.3/../../outside']) {
+    expect(() => pack({ version })).toThrow(/semantic version/u);
+  }
+});
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-contract.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-contract.mts
new file mode 100644
index 000000000..bb7b67c25
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-contract.mts
@@ -0,0 +1,18 @@
+export const WASIX_RUNTIME_PRODUCT = 'liboliphaunt-wasix';
+export const WASIX_RUNTIME_NPM_PACKAGE = '@oliphaunt/liboliphaunt-wasix';
+export const WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA = 'oliphaunt-wasix-runtime-v2';
+export const WASIX_RUNTIME_NPM_TARGET = 'portable';
+
+export const WASIX_RUNTIME_ARCHIVE_PATH = 'oliphaunt.wasix.tar.zst';
+
+const RELEASE_ASSET_ROOT = 'target/oliphaunt-wasix/assets';
+
+export const WASIX_PORTABLE_RELEASE_MEMBERS = Object.freeze({
+  runtimeArchive: `${RELEASE_ASSET_ROOT}/${WASIX_RUNTIME_ARCHIVE_PATH}`,
+  manifest: `${RELEASE_ASSET_ROOT}/manifest.json`,
+});
+
+export const WASIX_RUNTIME_NPM_ASSET_PATHS = Object.freeze({
+  runtimeArchive: 'assets/oliphaunt.wasix.tar.zst',
+  manifest: 'assets/manifest.json',
+});
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-descriptor.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-descriptor.mts
new file mode 100644
index 000000000..94be87f0c
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-descriptor.mts
@@ -0,0 +1,102 @@
+import {
+  WASIX_RUNTIME_ARCHIVE_PATH,
+  WASIX_RUNTIME_NPM_ASSET_PATHS,
+  WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA,
+  WASIX_RUNTIME_PRODUCT,
+} from './wasix-runtime-npm-contract.mts';
+
+const TOOL = 'wasix-runtime-npm-carrier.mts';
+const LOWER_SHA256 = /^[0-9a-f]{64}$/u;
+
+function checkedDescriptorInput({ version, runtimeArchive, manifest }) {
+  if (typeof version !== 'string' || version.length === 0) {
+    throw new TypeError(`${TOOL}: runtime descriptor version must be a non-empty string`);
+  }
+  for (const [name, value] of Object.entries({
+    runtimeArchive,
+    manifest,
+  })) {
+    if (
+      value === null ||
+      Array.isArray(value) ||
+      typeof value !== 'object' ||
+      typeof value.sha256 !== 'string' ||
+      !LOWER_SHA256.test(value.sha256) ||
+      !Number.isSafeInteger(value.size) ||
+      value.size <= 0
+    ) {
+      throw new TypeError(`${TOOL}: invalid ${name} descriptor input`);
+    }
+  }
+  if (runtimeArchive.archive !== WASIX_RUNTIME_ARCHIVE_PATH) {
+    throw new TypeError(`${TOOL}: invalid runtime archive descriptor path`);
+  }
+}
+
+export function renderWasixRuntimeDescriptorModule(input) {
+  checkedDescriptorInput(input);
+  const { version, runtimeArchive, manifest } = input;
+  const asset = (value, sourcePath, includeArchive) =>
+    [
+      '  Object.freeze({',
+      ...(includeArchive ? [`    archive: ${JSON.stringify(value.archive)},`] : []),
+      `    sha256: ${JSON.stringify(value.sha256)},`,
+      `    size: ${value.size},`,
+      `    source: new URL(${JSON.stringify(`./${sourcePath}`)}, import.meta.url),`,
+      '  })',
+    ].join('\n');
+  return [
+    'export const POSTGRES_MAJOR = 18;',
+    'export const PHYSICAL_FORMAT = "wasix-pg18-v1";',
+    '',
+    'const runtimeArchive =',
+    `${asset(runtimeArchive, WASIX_RUNTIME_NPM_ASSET_PATHS.runtimeArchive, true)};`,
+    'const manifest =',
+    `${asset(manifest, WASIX_RUNTIME_NPM_ASSET_PATHS.manifest, false)};`,
+    '',
+    'const descriptor = Object.freeze({',
+    `  schema: ${JSON.stringify(WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA)},`,
+    '  runtime: "wasix",',
+    `  product: ${JSON.stringify(WASIX_RUNTIME_PRODUCT)},`,
+    `  version: ${JSON.stringify(version)},`,
+    '  runtimeArchive,',
+    '  manifest,',
+    '});',
+    '',
+    'export { descriptor };',
+    'export default descriptor;',
+    '',
+  ].join('\n');
+}
+
+export function renderWasixRuntimeDescriptorTypes() {
+  return `export declare const POSTGRES_MAJOR: 18;
+export declare const PHYSICAL_FORMAT: "wasix-pg18-v1";
+
+export type OliphauntWasixRuntimeAsset = Readonly<{
+  archive: string;
+  sha256: string;
+  size: number;
+  source: URL;
+}>;
+
+export type OliphauntWasixRuntimeManifest = Readonly<{
+  sha256: string;
+  size: number;
+  source: URL;
+}>;
+
+export type OliphauntWasixRuntimeDescriptor = Readonly<{
+  schema: "${WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA}";
+  runtime: "wasix";
+  product: "${WASIX_RUNTIME_PRODUCT}";
+  version: string;
+  runtimeArchive: OliphauntWasixRuntimeAsset;
+  manifest: OliphauntWasixRuntimeManifest;
+}>;
+
+declare const descriptor: OliphauntWasixRuntimeDescriptor;
+export { descriptor };
+export default descriptor;
+`;
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm.test-consumer.mts b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm.test-consumer.mts
new file mode 100644
index 000000000..57322cce1
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm.test-consumer.mts
@@ -0,0 +1,24 @@
+import assert from 'node:assert/strict';
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+import { pathToFileURL } from 'node:url';
+
+const parent = process.env.OLIPHAUNT_WASIX_PACKAGING_TEST_ROOT;
+if (!parent) throw new Error('Run bash src/runtimes/liboliphaunt-wasix/tools/test-packaging.sh');
+const root = path.join(parent, 'npm-runtime');
+const descriptor = (await import(pathToFileURL(path.join(root, 'package/index.js')).href)).default;
+assert.equal(descriptor.product, 'liboliphaunt-wasix');
+assert.equal(descriptor.runtime, 'wasix');
+assert(Object.isFrozen(descriptor));
+for (const asset of [descriptor.runtimeArchive, descriptor.manifest])
+  assert(Object.isFrozen(asset));
+assert.deepEqual(
+  readFileSync(descriptor.runtimeArchive.source),
+  readFileSync(
+    path.join(root, 'release-stage/target/oliphaunt-wasix/assets/oliphaunt.wasix.tar.zst'),
+  ),
+);
+assert.deepEqual(
+  readFileSync(descriptor.manifest.source),
+  readFileSync(path.join(root, 'release-stage/target/oliphaunt-wasix/assets/manifest.json')),
+);
diff --git a/src/runtimes/liboliphaunt-wasix/tools/xtask/Cargo.toml b/src/runtimes/liboliphaunt-wasix/tools/xtask/Cargo.toml
new file mode 100644
index 000000000..368e33340
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/Cargo.toml
@@ -0,0 +1,32 @@
+[package]
+name = "xtask"
+version = "0.0.0"
+edition = "2024"
+rust-version = "1.93"
+license.workspace = true
+publish = false
+
+[features]
+default = []
+aot-serializer = [
+  "dep:wasmer",
+  "wasmer/llvm",
+  "wasmer/wasmer-artifact-create",
+  "dep:wasmer-types",
+]
+
+[dependencies]
+anyhow = "1"
+async-trait = "0.1"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+sha2 = "0.10"
+tar = "0.4"
+toml = "0.9"
+walkdir = "2"
+wasmer = { version = "=7.2.1", default-features = false, features = [
+  "sys",
+], optional = true }
+wasmer-types = { version = "=7.2.1", optional = true }
+wasmparser = "0.250.0"
+zstd = "0.13"
diff --git a/src/runtimes/liboliphaunt-wasix/tools/xtask/moon.yml b/src/runtimes/liboliphaunt-wasix/tools/xtask/moon.yml
new file mode 100644
index 000000000..67f371f51
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/moon.yml
@@ -0,0 +1,59 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "xtask"
+language: "rust"
+layer: "tool"
+stack: "systems"
+tags: ["tools", "rust", "xtask", "wasix"]
+
+project:
+  title: "WASIX and Extension Asset Tooling"
+  description: "Rust checks and generators shared by WASIX runtime and extension assets."
+  owner: "oliphaunt"
+
+owners:
+  defaultOwner: "@oliphaunt/wasix"
+  paths:
+    "**/*.rs": ["@oliphaunt/wasix"]
+    "Cargo.toml": ["@oliphaunt/wasix"]
+
+tasks:
+  test:
+    tags: ["quality", "unit", "requires-rust"]
+    command: "cargo test -p xtask --locked"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - "**/*"
+      - "/src/extensions/generated/extensions.catalog.json"
+      - "/src/extensions/external/*/targets/wasix.toml"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  aot-serializer-typecheck:
+    tags: ["quality", "static", "requires-rust", "requires-wasmer-llvm"]
+    command: "cargo check -p xtask --features aot-serializer --locked"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - "**/*"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  rust-format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt -p xtask --check"
+    inputs: ["/src/runtimes/liboliphaunt-wasix/tools/xtask/**/*.rs","/src/runtimes/liboliphaunt-wasix/tools/xtask/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+  rust-lint:
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy -p xtask --all-targets --locked -- -D warnings"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs: ["/src/runtimes/liboliphaunt-wasix/tools/xtask/**/*.rs","/src/runtimes/liboliphaunt-wasix/tools/xtask/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
diff --git a/tools/xtask/src/aot_serializer.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/aot_serializer.rs
similarity index 100%
rename from tools/xtask/src/aot_serializer.rs
rename to src/runtimes/liboliphaunt-wasix/tools/xtask/src/aot_serializer.rs
diff --git a/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_checks.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_checks.rs
new file mode 100644
index 000000000..def8e444f
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_checks.rs
@@ -0,0 +1,407 @@
+use super::*;
+
+pub(crate) fn check_generated_manifest(manifest: &SourcesManifest, strict: bool) -> Result<()> {
+    check_generated_manifest_with_outputs(
+        manifest,
+        strict,
+        BuildOutputs::discover_for_source_lane(DEFAULT_SOURCE_LANE),
+    )
+}
+
+pub(crate) fn check_generated_manifest_for_aot(
+    manifest: &SourcesManifest,
+    strict: bool,
+) -> Result<()> {
+    check_generated_manifest_with_outputs(
+        manifest,
+        strict,
+        BuildOutputs::discover_for_aot(DEFAULT_SOURCE_LANE),
+    )
+}
+
+fn check_generated_manifest_with_outputs(
+    manifest: &SourcesManifest,
+    strict: bool,
+    outputs: Result,
+) -> Result<()> {
+    let source_lane = DEFAULT_SOURCE_LANE;
+    match outputs.and_then(|outputs| effective_source_pins(manifest, &outputs)) {
+        Ok(expected_sources) => check_generated_manifest_sources_in(
+            generated_assets_dir_for_source_lane(source_lane)?,
+            &expected_sources,
+            source_lane,
+            strict,
+        ),
+        Err(err) if !strict => {
+            eprintln!(
+                "warning: skipping generated asset manifest source-pin check for {source_lane}: {err:#}"
+            );
+            Ok(())
+        }
+        Err(err) => Err(err).context("derive expected generated asset manifest source pins"),
+    }
+}
+
+pub(crate) fn check_generated_manifest_sources_in(
+    asset_dir: &Path,
+    expected_sources: &[SourcePin],
+    expected_label: &str,
+    strict: bool,
+) -> Result<()> {
+    let path = asset_dir.join("manifest.json");
+    if !path.exists() {
+        if strict {
+            bail!("generated asset manifest is missing at {}", path.display());
+        }
+        eprintln!(
+            "warning: generated asset manifest is missing at {}",
+            path.display()
+        );
+        return Ok(());
+    }
+
+    let text = fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?;
+    let generated: GeneratedAssetManifest =
+        serde_json::from_str(&text).with_context(|| format!("parse {}", path.display()))?;
+    if expected_label == DEFAULT_SOURCE_LANE {
+        let actual = generated.source_lane.as_deref().unwrap_or("");
+        ensure_eq(
+            actual,
+            expected_label,
+            "generated asset manifest source-lane",
+        )?;
+    }
+
+    let mut drift = Vec::new();
+    for source in expected_sources {
+        match generated
+            .sources
+            .iter()
+            .find(|generated| generated.name == source.name)
+        {
+            Some(generated)
+                if generated.url == source.url
+                    && generated.branch == source.branch
+                    && generated.commit == source.commit => {}
+            Some(generated) => drift.push(format!(
+                "{} generated={}/{}@{} expected={}/{}@{}",
+                source.name,
+                generated.url,
+                generated.branch,
+                generated.commit,
+                source.url,
+                source.branch,
+                source.commit
+            )),
+            None => drift.push(format!("{} missing from generated manifest", source.name)),
+        }
+    }
+    let expected_source_names = expected_sources
+        .iter()
+        .map(|source| source.name.as_str())
+        .collect::>();
+    for source in &generated.sources {
+        if !expected_source_names.contains(source.name.as_str()) {
+            drift.push(format!(
+                "{} is unexpected in generated manifest",
+                source.name
+            ));
+        }
+    }
+
+    if drift.is_empty() {
+        println!("generated asset manifest source pins match {expected_label}");
+        return Ok(());
+    }
+
+    let details = drift.join("; ");
+    if strict {
+        bail!("generated asset manifest has stale source pins: {details}");
+    }
+    eprintln!("warning: generated asset manifest has stale source pins: {details}");
+    Ok(())
+}
+
+pub(crate) fn verify_asset_manifest_hashes() -> Result<()> {
+    let manifest_path = Path::new(GENERATED_ASSETS_DIR).join("manifest.json");
+    let text = fs::read_to_string(&manifest_path)
+        .with_context(|| format!("read {}", manifest_path.display()))?;
+    let manifest: AssetManifestOut =
+        serde_json::from_str(&text).context("parse generated asset manifest")?;
+    let base = Path::new(GENERATED_ASSETS_DIR);
+
+    let runtime_archive = base.join(&manifest.runtime.archive);
+    verify_file_sha256(
+        &runtime_archive,
+        &manifest.runtime.sha256,
+        "runtime archive",
+    )?;
+    let runtime_module = archive_entry_bytes(&runtime_archive, RUNTIME_MODULE_ARCHIVE_MEMBER)?;
+    ensure_eq(
+        &sha256_bytes(&runtime_module),
+        &manifest.runtime.module_sha256,
+        "runtime module sha256",
+    )?;
+    for module in &manifest.runtime_support {
+        let bytes = archive_entry_bytes(&runtime_archive, &format!("oliphaunt/{}", module.path))?;
+        ensure_eq(
+            &sha256_bytes(&bytes),
+            &module.sha256,
+            &format!("runtime support {} sha256", module.name),
+        )?;
+        ensure_eq(
+            &sha256_bytes(&bytes),
+            &module.module_sha256,
+            &format!("runtime support {} module sha256", module.name),
+        )?;
+    }
+
+    if let Some(pg_dump) = &manifest.pg_dump {
+        verify_file_sha256(&base.join(&pg_dump.path), &pg_dump.sha256, "pg_dump wasm")?;
+        ensure_eq(
+            &pg_dump.sha256,
+            &pg_dump.module_sha256,
+            "pg_dump module sha256",
+        )?;
+    }
+    if let Some(psql) = &manifest.psql {
+        verify_file_sha256(&base.join(&psql.path), &psql.sha256, "psql wasm")?;
+        ensure_eq(&psql.sha256, &psql.module_sha256, "psql module sha256")?;
+    }
+    if let Some(initdb) = &manifest.initdb {
+        verify_file_sha256(&base.join(&initdb.path), &initdb.sha256, "initdb wasm")?;
+        ensure_eq(
+            &initdb.sha256,
+            &initdb.module_sha256,
+            "initdb module sha256",
+        )?;
+    }
+
+    for extension in &manifest.extensions {
+        let archive = base.join(&extension.archive);
+        verify_file_sha256(
+            &archive,
+            &extension.sha256,
+            &format!("extension {} archive", extension.sql_name),
+        )?;
+        if let Some(native_module) = &extension.native_module {
+            let entry = format!("lib/postgresql/{native_module}");
+            let bytes = archive_entry_bytes(&archive, &entry)?;
+            ensure_eq(
+                &sha256_bytes(&bytes),
+                &extension.module_sha256,
+                &format!("extension {} module sha256", extension.sql_name),
+            )?;
+        }
+        for module in &extension.native_modules {
+            let bytes = archive_entry_bytes(&archive, &module.path)?;
+            ensure_eq(
+                &sha256_bytes(&bytes),
+                &module.module_sha256,
+                &format!(
+                    "extension {} native module {} sha256",
+                    extension.sql_name, module.name
+                ),
+            )?;
+        }
+    }
+
+    println!("generated asset hashes match manifests");
+    Ok(())
+}
+
+fn verify_file_sha256(path: &Path, expected: &str, field: &str) -> Result<()> {
+    ensure_file(path)?;
+    let actual = sha256_file(path)?;
+    ensure_eq(&actual, expected, field)
+}
+
+const AOT_TARGETS: &[(&str, &str)] = &[
+    ("aarch64-apple-darwin", "macos-arm64"),
+    ("x86_64-unknown-linux-gnu", "linux-x64-gnu"),
+    ("aarch64-unknown-linux-gnu", "linux-arm64-gnu"),
+    ("x86_64-pc-windows-msvc", "windows-x64-msvc"),
+];
+
+pub(crate) fn aot_target_id_for_triple(target: &str) -> Result<&'static str> {
+    AOT_TARGETS
+        .iter()
+        .find(|(triple, _)| *triple == target)
+        .map(|(_, id)| *id)
+        .with_context(|| format!("unsupported AOT target triple {target}"))
+}
+
+pub(crate) fn ensure_supported_aot_target(target: &str) -> Result<()> {
+    aot_target_id_for_triple(target).map(|_| ())
+}
+
+pub(crate) fn verify_generated_extension_surface() -> Result<()> {
+    let manifest_path = Path::new("target/extensions/wasix/assets").join("manifest.json");
+    let manifest_text = fs::read_to_string(&manifest_path)
+        .with_context(|| format!("read {}", manifest_path.display()))?;
+    let manifest: AssetManifestOut =
+        serde_json::from_str(&manifest_text).context("parse committed asset manifest")?;
+    let catalog = crate::extension_catalog::manifest_metadata_by_sql_name()?;
+    let manifest_sql_names = manifest
+        .extensions
+        .iter()
+        .map(|extension| extension.sql_name.clone())
+        .collect::>();
+    let catalog_sql_names = catalog.keys().cloned().collect::>();
+    if manifest_sql_names != catalog_sql_names {
+        bail!(
+            "supported extension catalog and asset manifest disagree: manifest-only={:?} catalog-only={:?}",
+            manifest_sql_names
+                .difference(&catalog_sql_names)
+                .collect::>(),
+            catalog_sql_names
+                .difference(&manifest_sql_names)
+                .collect::>()
+        );
+    }
+
+    Ok(())
+}
+
+pub(crate) fn check_canonical_asset_layout(strict: bool) -> Result<()> {
+    check_canonical_asset_layout_in(Path::new(GENERATED_ASSETS_DIR), strict)
+}
+
+pub(crate) fn check_canonical_asset_layout_in(asset_dir: &Path, strict: bool) -> Result<()> {
+    let runtime_archive = asset_dir.join("oliphaunt.wasix.tar.zst");
+    if !runtime_archive.exists() {
+        if strict {
+            bail!(
+                "runtime asset archive is missing at {}",
+                runtime_archive.display()
+            );
+        }
+        eprintln!(
+            "warning: runtime asset archive is missing at {}",
+            runtime_archive.display()
+        );
+        return Ok(());
+    }
+
+    let runtime_entries = archive_entries(&runtime_archive)?;
+    let required_paths = [
+        RUNTIME_MODULE_ARCHIVE_MEMBER,
+        "oliphaunt/bin/initdb",
+        "oliphaunt/lib/postgresql/dict_snowball.so",
+        "oliphaunt/lib/postgresql/plpgsql.so",
+        "oliphaunt/share/postgresql/snowball_create.sql",
+        "oliphaunt/share/postgresql/extension/plpgsql--1.0.sql",
+        "oliphaunt/share/postgresql/extension/plpgsql.control",
+        "oliphaunt/share/postgresql/timezone/UTC",
+        "oliphaunt/share/postgresql/timezone/America/New_York",
+        "oliphaunt/share/postgresql/timezonesets/Default",
+    ];
+    for required in required_paths {
+        if !runtime_entries.contains(required) {
+            bail!(
+                "runtime archive {} is missing canonical path {required}",
+                runtime_archive.display()
+            );
+        }
+    }
+    for language in [
+        "danish",
+        "dutch",
+        "english",
+        "finnish",
+        "french",
+        "german",
+        "hungarian",
+        "italian",
+        "nepali",
+        "norwegian",
+        "portuguese",
+        "russian",
+        "spanish",
+        "swedish",
+        "turkish",
+    ] {
+        let required = format!("oliphaunt/share/postgresql/tsearch_data/{language}.stop");
+        if !runtime_entries.contains(required.as_str()) {
+            bail!(
+                "runtime archive {} is missing canonical path {required}",
+                runtime_archive.display()
+            );
+        }
+    }
+    if runtime_entries
+        .iter()
+        .any(|entry| entry == "oliphaunt/share/icu" || entry.starts_with("oliphaunt/share/icu/"))
+    {
+        bail!(
+            "runtime archive {} must not bundle ICU data under oliphaunt/share/icu; ICU is published as the separate oliphaunt-icu package",
+            runtime_archive.display()
+        );
+    }
+    for forbidden in [
+        "oliphaunt/share/extension",
+        "oliphaunt/share/timezonesets",
+        "oliphaunt/lib/plpgsql.so",
+        "oliphaunt/lib/dict_snowball.so",
+        "oliphaunt/bin/pg_dump",
+        "oliphaunt/bin/psql",
+        "oliphaunt/bin/oliphaunt",
+    ] {
+        if runtime_entries.contains(forbidden)
+            || runtime_entries
+                .iter()
+                .any(|entry| entry.starts_with(&format!("{forbidden}/")))
+        {
+            bail!(
+                "runtime archive {} contains non-canonical duplicate path {forbidden}",
+                runtime_archive.display()
+            );
+        }
+    }
+
+    let extensions_dir = asset_dir.join("extensions");
+    if extensions_dir.exists() {
+        for entry in fs::read_dir(&extensions_dir)
+            .with_context(|| format!("read {}", extensions_dir.display()))?
+        {
+            let path = entry?.path();
+            if path.extension().and_then(|ext| ext.to_str()) != Some("zst") {
+                continue;
+            }
+            check_extension_archive_layout(&path)?;
+        }
+    }
+
+    println!("canonical asset layout guard passed");
+    Ok(())
+}
+
+fn check_extension_archive_layout(path: &Path) -> Result<()> {
+    let entries = archive_entries(path)?;
+    for entry in entries {
+        if matches!(
+            entry.as_str(),
+            "lib"
+                | "lib/postgresql"
+                | "share"
+                | "share/proj"
+                | "share/postgresql"
+                | "share/postgresql/extension"
+                | "share/postgresql/tsearch_data"
+        ) {
+            continue;
+        }
+        if entry.starts_with("lib/postgresql/")
+            || entry.starts_with("share/proj/")
+            || entry.starts_with("share/postgresql/extension/")
+            || entry.starts_with("share/postgresql/tsearch_data/")
+        {
+            continue;
+        }
+        bail!(
+            "extension archive {} contains non-canonical path {entry}",
+            path.display()
+        );
+    }
+    Ok(())
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_io.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_io.rs
new file mode 100644
index 000000000..750cceebc
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_io.rs
@@ -0,0 +1,390 @@
+use super::*;
+use std::time::{SystemTime, UNIX_EPOCH};
+
+struct TemporaryDirectory {
+    path: PathBuf,
+    remove: bool,
+}
+
+impl TemporaryDirectory {
+    fn new(path: PathBuf) -> Self {
+        Self { path, remove: true }
+    }
+
+    fn path(&self) -> &Path {
+        &self.path
+    }
+
+    fn disarm(&mut self) {
+        self.remove = false;
+    }
+}
+
+impl Drop for TemporaryDirectory {
+    fn drop(&mut self) {
+        if self.remove {
+            let _ = fs::remove_dir_all(&self.path);
+        }
+    }
+}
+
+fn unique_sibling_directory(destination: &Path, label: &str) -> Result {
+    let parent = destination.parent().unwrap_or_else(|| Path::new("."));
+    fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?;
+    let basename = destination
+        .file_name()
+        .and_then(|name| name.to_str())
+        .unwrap_or("download");
+    let timestamp = SystemTime::now()
+        .duration_since(UNIX_EPOCH)
+        .unwrap_or_default()
+        .as_nanos();
+    for sequence in 0..100_u32 {
+        let candidate = parent.join(format!(
+            ".{basename}.{label}-{}-{timestamp}-{sequence}",
+            std::process::id()
+        ));
+        match fs::create_dir(&candidate) {
+            Ok(()) => return Ok(candidate),
+            Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => continue,
+            Err(error) => {
+                return Err(error).with_context(|| format!("create {}", candidate.display()));
+            }
+        }
+    }
+    bail!(
+        "could not allocate a unique sibling directory for {}",
+        destination.display()
+    )
+}
+
+fn normalize_downloaded_aot_artifact(target: &str, artifact_dir: &Path) -> Result<()> {
+    let marker = artifact_dir.join("target-triple.txt");
+    let files = artifact_dir.join("files");
+    if !marker.exists() && !files.exists() {
+        return Ok(());
+    }
+
+    ensure_file(&marker)?;
+    ensure!(
+        files.is_dir(),
+        "downloaded AOT artifact envelope is missing files directory: {}",
+        files.display()
+    );
+    let actual = fs::read_to_string(&marker)
+        .with_context(|| format!("read {}", marker.display()))?
+        .trim()
+        .to_owned();
+    ensure_eq(
+        &actual,
+        target,
+        "downloaded AOT artifact target-triple marker",
+    )?;
+
+    let normalized = artifact_dir.with_extension("normalized");
+    if normalized.exists() {
+        fs::remove_dir_all(&normalized)
+            .with_context(|| format!("remove {}", normalized.display()))?;
+    }
+    copy_dir_all(&files, &normalized)?;
+    fs::remove_dir_all(artifact_dir)
+        .with_context(|| format!("remove {}", artifact_dir.display()))?;
+    fs::rename(&normalized, artifact_dir).with_context(|| {
+        format!(
+            "rename normalized AOT artifact {} -> {}",
+            normalized.display(),
+            artifact_dir.display()
+        )
+    })?;
+    Ok(())
+}
+
+fn extract_tar_zst(archive: &Path, destination: &Path) -> Result<()> {
+    let file = fs::File::open(archive).with_context(|| format!("open {}", archive.display()))?;
+    let decoder = zstd::stream::read::Decoder::new(file)
+        .with_context(|| format!("create zstd decoder for {}", archive.display()))?;
+    let mut tar = tar::Archive::new(decoder);
+    tar.unpack(destination).with_context(|| {
+        format!(
+            "unpack {} into {}",
+            archive.display(),
+            destination.display()
+        )
+    })
+}
+
+fn validate_downloaded_artifacts(download_dir: &Path, targets: &[String]) -> Result<()> {
+    for entry in WalkDir::new(download_dir).follow_links(false) {
+        let entry = entry.with_context(|| format!("walk {}", download_dir.display()))?;
+        let file_type = entry.file_type();
+        ensure!(
+            file_type.is_dir() || file_type.is_file(),
+            "downloaded artifact envelope contains a symbolic link or special file: {}",
+            entry.path().display()
+        );
+    }
+    let downloaded_assets = download_dir.join(GENERATED_ASSETS_DIR);
+    ensure_file(&downloaded_assets.join("manifest.json"))?;
+    let downloaded_manifest = read_asset_manifest_from(&downloaded_assets)?;
+    ensure_packaged_asset_matches_source_lane(&downloaded_manifest, DEFAULT_SOURCE_LANE)?;
+
+    for target in targets {
+        let downloaded_aot = download_dir.join("target/oliphaunt-wasix/aot").join(target);
+        ensure_file(&downloaded_aot.join("manifest.json"))?;
+        ensure_aot_manifest_matches_source_lane(
+            &downloaded_aot.join("manifest.json"),
+            target,
+            DEFAULT_SOURCE_LANE,
+        )?;
+    }
+    Ok(())
+}
+
+struct PreparedPromotion {
+    backup: Option,
+    destination: PathBuf,
+    promoted: bool,
+    stage: TemporaryDirectory,
+}
+
+fn promote_directories_transactionally(entries: &[(PathBuf, PathBuf)]) -> Result<()> {
+    let mut prepared = Vec::new();
+    for (source, destination) in entries {
+        let stage_path = unique_sibling_directory(destination, "install")?;
+        let stage = TemporaryDirectory::new(stage_path);
+        copy_dir_all(source, stage.path()).with_context(|| {
+            format!(
+                "stage validated directory {} for {}",
+                source.display(),
+                destination.display()
+            )
+        })?;
+        let backup = if destination.exists() {
+            let backup = unique_sibling_directory(destination, "previous")?;
+            fs::remove_dir(&backup).with_context(|| format!("prepare {}", backup.display()))?;
+            Some(backup)
+        } else {
+            None
+        };
+        prepared.push(PreparedPromotion {
+            backup,
+            destination: destination.clone(),
+            promoted: false,
+            stage,
+        });
+    }
+
+    for index in 0..prepared.len() {
+        let destination = prepared[index].destination.clone();
+        if let Some(backup) = prepared[index].backup.clone()
+            && let Err(error) = fs::rename(&destination, &backup)
+        {
+            rollback_promotions(&mut prepared, index);
+            return Err(error).with_context(|| {
+                format!(
+                    "move existing install {} -> {}",
+                    destination.display(),
+                    backup.display()
+                )
+            });
+        }
+        if let Err(error) = fs::rename(prepared[index].stage.path(), &destination) {
+            if let Some(backup) = prepared[index].backup.take() {
+                let _ = fs::rename(backup, &destination);
+            }
+            rollback_promotions(&mut prepared, index);
+            return Err(error).with_context(|| {
+                format!(
+                    "promote validated install {} -> {}",
+                    prepared[index].stage.path().display(),
+                    destination.display()
+                )
+            });
+        }
+        prepared[index].stage.disarm();
+        prepared[index].promoted = true;
+    }
+    for item in &mut prepared {
+        if let Some(backup) = item.backup.take() {
+            fs::remove_dir_all(&backup)
+                .with_context(|| format!("remove prior install {}", backup.display()))?;
+        }
+    }
+    Ok(())
+}
+
+fn rollback_promotions(prepared: &mut [PreparedPromotion], before: usize) {
+    for item in prepared[..before].iter_mut().rev() {
+        if !item.promoted {
+            continue;
+        }
+        let _ = fs::remove_dir_all(&item.destination);
+        if let Some(backup) = item.backup.take() {
+            let _ = fs::rename(backup, &item.destination);
+        }
+        item.promoted = false;
+    }
+}
+
+fn install_downloaded_artifacts(download_dir: &Path, targets: &[String]) -> Result<()> {
+    validate_downloaded_artifacts(download_dir, targets)?;
+    let mut entries = vec![(
+        download_dir.join(GENERATED_ASSETS_DIR),
+        PathBuf::from(GENERATED_ASSETS_DIR),
+    )];
+    for target in targets {
+        entries.push((
+            download_dir.join("target/oliphaunt-wasix/aot").join(target),
+            generated_aot_dir(target),
+        ));
+    }
+    promote_directories_transactionally(&entries)
+}
+
+pub(super) fn ensure_aot_manifest_matches_source_lane(
+    manifest_path: &Path,
+    target: &str,
+    source_lane: &str,
+) -> Result<()> {
+    let expected = canonical_source_lane(source_lane)?;
+    let text = fs::read_to_string(manifest_path)
+        .with_context(|| format!("read {}", manifest_path.display()))?;
+    let manifest: AotManifest = serde_json::from_str(&text)
+        .with_context(|| format!("parse {}", manifest_path.display()))?;
+    ensure!(
+        manifest.format_version == AOT_MANIFEST_FORMAT_VERSION,
+        "AOT manifest format-version must be {AOT_MANIFEST_FORMAT_VERSION}, got {}",
+        manifest.format_version
+    );
+    let actual = manifest.source_lane.as_deref().unwrap_or("");
+    ensure_eq(actual, expected, "AOT manifest source-lane")?;
+    ensure_eq(
+        &manifest.target_triple,
+        target,
+        "AOT manifest target-triple",
+    )?;
+    let sources = load_wasix_toolchain_manifest()?;
+    ensure_eq(
+        &manifest.wasmer_version,
+        &sources.toolchain.wasmer,
+        "AOT manifest wasmer-version",
+    )?;
+    ensure_eq(
+        &manifest.wasmer_wasix_version,
+        &sources.toolchain.wasmer_wasix,
+        "AOT manifest wasmer-wasix-version",
+    )?;
+    ensure!(
+        !manifest.artifacts.is_empty(),
+        "AOT manifest {} contains no artifacts",
+        manifest_path.display()
+    );
+    match expected {
+        "stable" => {
+            ensure_postgres_source_fingerprint_matches_current(
+                manifest.source_fingerprint.as_deref(),
+                "PG18 AOT manifest source-fingerprint",
+            )?;
+            if let Some(postgres_version) = manifest.postgres_version.as_deref() {
+                ensure!(
+                    postgres_version.starts_with("18."),
+                    "AOT manifest is PostgreSQL {postgres_version}, not the PG18 WASIX runtime"
+                );
+            }
+        }
+        _ => unreachable!("canonical_source_lane returned an unsupported lane"),
+    }
+    Ok(())
+}
+
+pub(super) fn install_local_assets(args: &[String]) -> Result<()> {
+    let target = value_after(args, "--target-triple").unwrap_or(host_target_triple());
+    install_local_assets_for_target(target)
+}
+
+fn install_local_assets_for_target(target: &str) -> Result<()> {
+    ensure_supported_aot_target(target)?;
+    let generated_assets = Path::new(GENERATED_ASSETS_DIR);
+    ensure_file(&generated_assets.join("manifest.json"))?;
+    let generated_manifest = read_asset_manifest_from(generated_assets)?;
+    ensure_packaged_asset_matches_source_lane(&generated_manifest, DEFAULT_SOURCE_LANE)?;
+    check_canonical_asset_layout(true)?;
+    check_generated_manifest_for_aot(&load_sources_manifest()?, true)?;
+    verify_asset_manifest_hashes()?;
+
+    find_aot_artifact_dir(target)?;
+    check_aot_package_manifest(target, DEFAULT_SOURCE_LANE)?;
+    println!("local generated assets are installed for {target}");
+    Ok(())
+}
+
+pub(super) fn import_downloaded_assets(args: &[String]) -> Result<()> {
+    let directory = Path::new(
+        value_after(args, "--from").context("--from requires a staged download directory")?,
+    );
+    let targets: Vec = args
+        .windows(2)
+        .filter(|pair| pair[0] == "--target-triple")
+        .map(|pair| pair[1].clone())
+        .collect();
+    ensure!(
+        !targets.is_empty(),
+        "at least one --target-triple is required"
+    );
+    for target in &targets {
+        ensure_supported_aot_target(target)?;
+        normalize_downloaded_aot_artifact(target, &directory.join(generated_aot_dir(target)))?;
+    }
+    install_downloaded_artifacts(directory, &targets)?;
+    for target in targets {
+        install_local_assets_for_target(&target)?;
+    }
+    Ok(())
+}
+
+pub(super) fn unpack_downloaded_archive(args: &[String]) -> Result<()> {
+    ensure!(args.len() == 3, "usage: assets unpack ARCHIVE DIRECTORY");
+    extract_tar_zst(Path::new(&args[1]), Path::new(&args[2]))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    fn test_root(label: &str) -> PathBuf {
+        let nonce = SystemTime::now()
+            .duration_since(UNIX_EPOCH)
+            .unwrap()
+            .as_nanos();
+        let root = std::env::temp_dir().join(format!(
+            "oliphaunt-asset-io-{label}-{}-{nonce}",
+            std::process::id()
+        ));
+        fs::create_dir_all(&root).unwrap();
+        root
+    }
+
+    #[test]
+    fn install_staging_failure_cannot_partially_replace_destinations() {
+        let root = test_root("transaction");
+        let source = root.join("source");
+        let missing = root.join("missing");
+        let first = root.join("first");
+        let second = root.join("second");
+        fs::create_dir_all(&source).unwrap();
+        fs::create_dir_all(&first).unwrap();
+        fs::create_dir_all(&second).unwrap();
+        fs::write(source.join("new"), b"new").unwrap();
+        fs::write(first.join("old-first"), b"old-first").unwrap();
+        fs::write(second.join("old-second"), b"old-second").unwrap();
+        assert!(
+            promote_directories_transactionally(&[
+                (source, first.clone()),
+                (missing, second.clone())
+            ])
+            .is_err()
+        );
+        assert_eq!(fs::read(first.join("old-first")).unwrap(), b"old-first");
+        assert_eq!(fs::read(second.join("old-second")).unwrap(), b"old-second");
+        fs::remove_dir_all(root).unwrap();
+    }
+}
diff --git a/tools/xtask/src/asset_manifest.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_manifest.rs
similarity index 81%
rename from tools/xtask/src/asset_manifest.rs
rename to src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_manifest.rs
index 0b97b85f7..ae29397c8 100644
--- a/tools/xtask/src/asset_manifest.rs
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_manifest.rs
@@ -1,4 +1,3 @@
-use std::collections::BTreeMap;
 use std::fs;
 use std::path::{Path, PathBuf};
 
@@ -12,16 +11,12 @@ pub(super) const AOT_MANIFEST_FORMAT_VERSION: u32 = 1;
 #[derive(Debug, Deserialize)]
 pub(super) struct SourcesManifest {
     pub(super) toolchain: Toolchain,
-    pub(super) builder: WasixBuilder,
-    pub(super) build: BuildConfig,
     pub(super) sources: Vec,
 }
 
 #[derive(Debug, Deserialize)]
 pub(super) struct WasixToolchainManifest {
     pub(super) toolchain: Toolchain,
-    pub(super) builder: WasixBuilder,
-    pub(super) build: BuildConfig,
 }
 
 #[derive(Debug, Deserialize)]
@@ -36,7 +31,7 @@ pub(super) struct GeneratedAssetManifest {
 #[derive(Debug, Deserialize)]
 pub(super) struct PostgresSourceManifest {
     pub(super) postgresql: PostgresPostgresqlSource,
-    pub(super) patches: PostgresPatchManifest,
+    pub(super) patches: Vec,
 }
 
 #[derive(Debug, Deserialize)]
@@ -44,11 +39,6 @@ pub(super) struct PostgresSharedSourceManifest {
     pub(super) postgresql: PostgresPostgresqlSource,
 }
 
-#[derive(Debug, Deserialize)]
-pub(super) struct PostgresProductPatchManifest {
-    pub(super) patches: PostgresPatchManifest,
-}
-
 #[derive(Debug, Deserialize)]
 pub(super) struct PostgresPostgresqlSource {
     pub(super) version: String,
@@ -56,81 +46,11 @@ pub(super) struct PostgresPostgresqlSource {
     pub(super) sha256: String,
 }
 
-#[derive(Debug, Deserialize)]
-pub(super) struct PostgresPatchManifest {
-    pub(super) series: Vec,
-}
-
 #[derive(Debug, Deserialize)]
 pub(super) struct Toolchain {
     pub(super) wasmer: String,
     #[serde(rename = "wasmer-wasix")]
     pub(super) wasmer_wasix: String,
-    pub(super) webc: String,
-    pub(super) wasmer_llvm: String,
-    pub(super) assets_manifest: String,
-    pub(super) assets_manifest_sha256: String,
-    pub(super) wasixcc: WasixccTool,
-    pub(super) sysroots: WasixSysroots,
-    pub(super) llvm: WasixLlvm,
-    pub(super) binaryen: WasixBinaryen,
-}
-
-#[derive(Debug, Deserialize)]
-pub(super) struct WasixccTool {
-    pub(super) version: String,
-    pub(super) target: String,
-    pub(super) asset: String,
-    pub(super) sha256: String,
-}
-
-#[derive(Debug, Deserialize)]
-pub(super) struct WasixSysroots {
-    pub(super) version: String,
-    pub(super) sysroot_sha256: String,
-    pub(super) sysroot_eh_sha256: String,
-    pub(super) sysroot_ehpic_sha256: String,
-    pub(super) sysroot_exnref_eh_sha256: String,
-    pub(super) sysroot_exnref_ehpic_sha256: String,
-}
-
-#[derive(Debug, Deserialize)]
-pub(super) struct WasixLlvm {
-    pub(super) release: String,
-    pub(super) reported_version: String,
-    pub(super) asset: String,
-    pub(super) sha256: String,
-}
-
-#[derive(Debug, Deserialize)]
-pub(super) struct WasixBinaryen {
-    pub(super) release: String,
-    pub(super) reported_version: String,
-    pub(super) asset: String,
-    pub(super) sha256: String,
-}
-
-#[derive(Debug, Deserialize)]
-pub(super) struct WasixBuilder {
-    pub(super) base_image: String,
-    pub(super) base_image_digest: String,
-    pub(super) dockerfile_frontend: String,
-    pub(super) apt_snapshot: String,
-    pub(super) apt_snapshot_retention: String,
-    pub(super) snapshot_tls_root: String,
-    pub(super) snapshot_tls_root_sha256: String,
-    pub(super) snapshot_tls_root_not_after: String,
-}
-
-#[derive(Debug, Deserialize)]
-pub(super) struct BuildConfig {
-    pub(super) postgres_prefix: String,
-    pub(super) postgres_pkglibdir: String,
-    pub(super) postgres_sharedir: String,
-    pub(super) main_flags: Vec,
-    pub(super) extension_flags: Vec,
-    pub(super) archive_format: String,
-    pub(super) deterministic_archives: bool,
 }
 
 #[derive(Debug, Clone, Deserialize, Serialize)]
@@ -149,8 +69,6 @@ pub(super) struct SourcePin {
     pub(super) sha256: Option,
     #[serde(default, skip_serializing_if = "Option::is_none")]
     pub(super) strip_prefix: Option,
-    #[serde(skip)]
-    pub(super) origin: SourceOrigin,
 }
 
 #[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq)]
@@ -167,31 +85,6 @@ impl SourceKind {
     }
 }
 
-#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
-pub(super) enum SourceOrigin {
-    SharedThirdParty,
-    NativeThirdParty,
-    WasixThirdParty,
-    Extension,
-    #[default]
-    Generated,
-}
-
-impl SourcePin {
-    pub(super) fn archive_stamp(&self, tree_sha256: &str) -> String {
-        format!(
-            "safety=source-archive-v2\nname={}\nkind=archive\nurl={}\nbranch={}\ncommit={}\nsha256={}\nstrip-prefix={}\ntree-sha256={}\n",
-            self.name,
-            self.url,
-            self.branch,
-            self.commit,
-            self.sha256.as_deref().unwrap_or(""),
-            self.strip_prefix.as_deref().unwrap_or(""),
-            tree_sha256,
-        )
-    }
-}
-
 pub(super) struct ExtensionArtifact<'a> {
     pub(super) name: &'a str,
     pub(super) sql_name: &'a str,
@@ -265,8 +158,6 @@ pub(super) struct AssetManifestOut {
     pub(super) psql: Option,
     #[serde(default, skip_serializing_if = "Option::is_none")]
     pub(super) initdb: Option,
-    #[serde(default)]
-    pub(super) cluster_seeds: BTreeMap,
     pub(super) extensions: Vec,
     pub(super) sources: Vec,
 }
@@ -293,32 +184,6 @@ pub(super) struct BinaryAssetOut {
     pub(super) link: WasmLinkMetadataOut,
 }
 
-#[derive(Debug, Deserialize, Serialize)]
-#[serde(rename_all = "kebab-case")]
-pub(super) struct ClusterSeedAssetOut {
-    pub(super) artifact_role: String,
-    pub(super) catalog_profile: String,
-    pub(super) archive: String,
-    pub(super) manifest: String,
-    pub(super) sha256: String,
-    pub(super) size: u64,
-    pub(super) runtime_module_sha256: String,
-    pub(super) initdb_module_sha256: String,
-    pub(super) source_pins_sha256: String,
-    #[serde(default, skip_serializing_if = "Option::is_none")]
-    pub(super) source_lane: Option,
-    #[serde(default, skip_serializing_if = "Option::is_none")]
-    pub(super) source_fingerprint: Option,
-    pub(super) postgres_version: String,
-    pub(super) catalog_version: String,
-    pub(super) init_profile: String,
-    pub(super) wasmer_version: String,
-    pub(super) physical_format: String,
-    pub(super) compatibility_key: String,
-    #[serde(default, skip_serializing_if = "Option::is_none")]
-    pub(super) icu_data_tree_sha256: Option,
-}
-
 #[derive(Debug, Deserialize, Serialize)]
 #[serde(rename_all = "kebab-case")]
 pub(super) struct ExtensionAssetOut {
diff --git a/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_pipeline.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_pipeline.rs
new file mode 100644
index 000000000..711e92806
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/asset_pipeline.rs
@@ -0,0 +1,3097 @@
+use super::*;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(crate) enum AssetProduct {
+    Runtime,
+    Tools,
+    Extensions,
+}
+
+impl AssetProduct {
+    pub(crate) fn parse(value: &str) -> Result {
+        match value {
+            "runtime" => Ok(Self::Runtime),
+            "tools" => Ok(Self::Tools),
+            "extensions" => Ok(Self::Extensions),
+            _ => bail!("unknown asset product {value:?}"),
+        }
+    }
+    fn root(self) -> PathBuf {
+        PathBuf::from(match self {
+            Self::Runtime => "target/oliphaunt-wasix",
+            Self::Tools => "target/postgres-tools/wasix",
+            Self::Extensions => "target/extensions/wasix",
+        })
+    }
+    fn owns(self, name: &str) -> bool {
+        match self {
+            Self::Runtime => {
+                name.starts_with("runtime:")
+                    || name.starts_with("runtime-support:")
+                    || name == "tool:initdb"
+            }
+            Self::Tools => matches!(name, "tool:pg_dump" | "tool:psql"),
+            Self::Extensions => name.starts_with("extension:"),
+        }
+    }
+}
+
+pub(crate) struct BuildOutputs {
+    product: AssetProduct,
+    source_lane: String,
+    source_fingerprint: Option,
+    postgres_version: String,
+    build_dir: PathBuf,
+    source_dir: PathBuf,
+    package_stage: PathBuf,
+    modules: Vec,
+}
+
+struct BuildModuleOutput {
+    name: String,
+    kind: String,
+    path: PathBuf,
+    aot_file: String,
+    requires_aot: bool,
+}
+
+fn postgres_source_dir() -> Result {
+    let manifest = load_postgres_source_manifest()?;
+    let source = postgres_default_source_dir(&manifest);
+    ensure!(
+        source.join(".oliphaunt-wasix-source-fingerprint").is_file(),
+        "missing prepared PG18 WASIX source at {}; run {POSTGRES_PREPARE_SCRIPT}",
+        source.display()
+    );
+    check_prepared_postgres_source(&manifest, &source, Path::new(WASIX_POSTGRES_WORK_DIR))?;
+    Ok(source)
+}
+
+fn postgres_version_for_source_lane(source_lane: &str, source_dir: &Path) -> Result {
+    match source_lane {
+        "stable" => {
+            let version_path = source_dir.join(".oliphaunt-wasix-postgres-version");
+            let version = fs::read_to_string(&version_path)
+                .with_context(|| format!("read {}", version_path.display()))?;
+            let version = version.trim();
+            ensure!(
+                !version.is_empty(),
+                "{} must contain a PostgreSQL version",
+                version_path.display()
+            );
+            Ok(version.to_owned())
+        }
+        other => bail!("unsupported WASIX asset source lane {other:?}"),
+    }
+}
+
+fn source_fingerprint_for_source_lane(
+    source_lane: &str,
+    source_dir: &Path,
+) -> Result> {
+    match source_lane {
+        "stable" => {
+            let path = source_dir.join(".oliphaunt-wasix-source-fingerprint");
+            let fingerprint =
+                fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?;
+            let fingerprint = fingerprint.trim();
+            ensure!(
+                !fingerprint.is_empty(),
+                "{} must contain a PG18 source fingerprint",
+                path.display()
+            );
+            Ok(Some(fingerprint.to_owned()))
+        }
+        other => bail!("unsupported WASIX asset source lane {other:?}"),
+    }
+}
+
+fn expected_postgres_source_fingerprint() -> Result {
+    let manifest = load_postgres_source_manifest()?;
+    postgres_expected_source_fingerprint(&manifest)
+}
+
+pub(crate) fn ensure_postgres_source_fingerprint_matches_current(
+    actual: Option<&str>,
+    field: &str,
+) -> Result<()> {
+    let expected = expected_postgres_source_fingerprint()?;
+    ensure_eq(actual.unwrap_or(""), &expected, field)
+}
+
+pub(crate) fn ensure_packaged_asset_matches_source_lane(
+    manifest: &AssetManifestOut,
+    source_lane: &str,
+) -> Result<()> {
+    let expected = canonical_source_lane(source_lane)?;
+    if let Some(actual) = manifest.source_lane.as_deref() {
+        ensure_eq(actual, expected, "packaged asset manifest source-lane")?;
+    }
+    match expected {
+        "stable" => ensure!(
+            manifest.runtime.postgres_version.starts_with("18."),
+            "packaged assets are PostgreSQL {}, not the PG18 WASIX runtime",
+            manifest.runtime.postgres_version
+        ),
+        _ => unreachable!("canonical_source_lane returned an unsupported lane"),
+    }
+    if expected == "stable" {
+        ensure_postgres_source_fingerprint_matches_current(
+            manifest.source_fingerprint.as_deref(),
+            "packaged asset manifest source-fingerprint",
+        )?;
+    }
+    Ok(())
+}
+
+fn ensure_build_output_manifest_matches_source_lane(
+    manifest: &BuildOutputManifestOut,
+    source_lane: &str,
+) -> Result<()> {
+    let expected = canonical_source_lane(source_lane)?;
+    let actual = manifest.source_lane.as_deref().unwrap_or("");
+    match expected {
+        "stable" => {
+            ensure_eq(actual, "stable", "WASIX build output manifest source-lane")?;
+            let pg18 = load_postgres_source_manifest()?;
+            ensure_eq(
+                manifest.postgres_version.as_deref().unwrap_or(""),
+                pg18.postgresql.version.as_str(),
+                "WASIX build output manifest postgres-version",
+            )?;
+            ensure_postgres_source_fingerprint_matches_current(
+                manifest.source_fingerprint.as_deref(),
+                "WASIX build output manifest source-fingerprint",
+            )?;
+            ensure_postgres_build_output_manifest_paths_are_stable(manifest)?;
+        }
+        _ => unreachable!("canonical_source_lane returned an unsupported lane"),
+    }
+    if let Some(postgres_version) = manifest.postgres_version.as_deref() {
+        match expected {
+            "stable" => ensure!(
+                postgres_version.starts_with("18."),
+                "WASIX build output manifest is PostgreSQL {postgres_version}, not the PG18 WASIX runtime"
+            ),
+            _ => unreachable!("canonical_source_lane returned an unsupported lane"),
+        }
+    }
+    Ok(())
+}
+
+fn ensure_postgres_build_output_manifest_paths_are_stable(
+    manifest: &BuildOutputManifestOut,
+) -> Result<()> {
+    let postgres_root = Path::new(WASIX_POSTGRES_DOCKER_BUILD_DIR);
+    for module in &manifest.modules {
+        let path = Path::new(&module.path);
+        ensure!(
+            path.starts_with(postgres_root),
+            "PostgreSQL build output manifest module {} points outside the stable build root: {}",
+            module.name,
+            module.path
+        );
+    }
+    Ok(())
+}
+
+pub(crate) fn canonical_source_lane(source_lane: &str) -> Result<&'static str> {
+    match source_lane {
+        "stable" | "released" | "packaged" | "default" => Ok(DEFAULT_SOURCE_LANE),
+        other => bail!("unsupported WASIX asset source lane {other:?}"),
+    }
+}
+
+pub(crate) fn build_output_manifest_path_for_source_lane(
+    source_lane: &str,
+) -> Result<&'static Path> {
+    match canonical_source_lane(source_lane)? {
+        "stable" => Ok(Path::new(WASIX_POSTGRES_BUILD_MANIFEST_PATH)),
+        other => bail!("unsupported WASIX asset source lane {other:?}"),
+    }
+}
+
+pub(crate) fn generated_assets_dir_for_source_lane(source_lane: &str) -> Result<&'static Path> {
+    match canonical_source_lane(source_lane)? {
+        "stable" => Ok(Path::new(GENERATED_ASSETS_DIR)),
+        other => bail!("unsupported WASIX asset source lane {other:?}"),
+    }
+}
+
+pub(crate) fn generated_aot_dir_for_source_lane(
+    target: &str,
+    source_lane: &str,
+) -> Result {
+    match canonical_source_lane(source_lane)? {
+        "stable" => Ok(Path::new(GENERATED_AOT_DIR).join(target)),
+        _ => unreachable!("canonical_source_lane returned an unsupported lane"),
+    }
+}
+
+impl BuildOutputs {
+    pub(crate) fn discover_for_source_lane(source_lane: &str) -> Result {
+        Self::discover_product(source_lane, AssetProduct::Runtime)
+    }
+
+    fn discover_product(source_lane: &str, product: AssetProduct) -> Result {
+        let source_lane = canonical_source_lane(source_lane)?;
+        let (canonical_source_lane, build_dir, source_dir, package_stage) = match source_lane {
+            "stable" => (
+                "stable".to_owned(),
+                PathBuf::from(WASIX_POSTGRES_DOCKER_BUILD_DIR),
+                postgres_source_dir()?,
+                PathBuf::from(WASIX_POSTGRES_GENERATED_BUILD_DIR).join("package-stage"),
+            ),
+            other => unreachable!("canonical_source_lane returned an unsupported lane: {other}"),
+        };
+        let mut modules = vec![
+            BuildModuleOutput {
+                name: "runtime:oliphaunt".to_owned(),
+                kind: "runtime".to_owned(),
+                path: build_dir.join("src/backend/oliphaunt"),
+                aot_file: "oliphaunt-llvm-opta.bin.zst".to_owned(),
+                requires_aot: true,
+            },
+            BuildModuleOutput {
+                name: "runtime-support:plpgsql".to_owned(),
+                kind: "runtime-support".to_owned(),
+                path: build_dir.join("src/pl/plpgsql/src/plpgsql.so"),
+                aot_file: "plpgsql-llvm-opta.bin.zst".to_owned(),
+                requires_aot: true,
+            },
+            BuildModuleOutput {
+                name: "runtime-support:dict_snowball".to_owned(),
+                kind: "runtime-support".to_owned(),
+                path: build_dir.join("src/backend/snowball/dict_snowball.so"),
+                aot_file: "dict_snowball-llvm-opta.bin.zst".to_owned(),
+                requires_aot: true,
+            },
+            BuildModuleOutput {
+                name: "tool:initdb".to_owned(),
+                kind: "tool".to_owned(),
+                path: build_dir.join("src/bin/initdb/initdb"),
+                aot_file: "initdb-llvm-opta.bin.zst".to_owned(),
+                requires_aot: true,
+            },
+        ];
+        if product == AssetProduct::Tools {
+            modules.push(BuildModuleOutput {
+                name: "tool:pg_dump".to_owned(),
+                kind: "tool".to_owned(),
+                path: build_dir.join("src/bin/pg_dump/pg_dump"),
+                aot_file: "pg_dump-llvm-opta.bin.zst".to_owned(),
+                requires_aot: true,
+            });
+            modules.push(BuildModuleOutput {
+                name: "tool:psql".to_owned(),
+                kind: "tool".to_owned(),
+                path: build_dir.join("src/bin/psql/psql"),
+                aot_file: "psql-llvm-opta.bin.zst".to_owned(),
+                requires_aot: true,
+            });
+        }
+        if product == AssetProduct::Extensions {
+            for extension in extension_catalog::extension_build_specs()? {
+                for support_module in &extension.native_support_modules {
+                    modules.push(BuildModuleOutput {
+                        name: format!("extension:{}:{}", extension.sql_name, support_module.name),
+                        kind: "extension".to_owned(),
+                        path: build_dir.join(&support_module.build_path),
+                        aot_file: support_module.aot_file.clone(),
+                        requires_aot: true,
+                    });
+                }
+                if extension.module_file.is_some() {
+                    modules.push(BuildModuleOutput {
+                        name: format!("extension:{}", extension.sql_name),
+                        kind: "extension".to_owned(),
+                        path: extension_build_module_path(&build_dir, &extension)?,
+                        aot_file: format!(
+                            "{}-llvm-opta.bin.zst",
+                            extension_aot_file_stem(&extension)
+                        ),
+                        requires_aot: true,
+                    });
+                }
+            }
+        }
+
+        let outputs = Self {
+            product,
+            postgres_version: postgres_version_for_source_lane(
+                &canonical_source_lane,
+                &source_dir,
+            )?,
+            source_fingerprint: source_fingerprint_for_source_lane(
+                &canonical_source_lane,
+                &source_dir,
+            )?,
+            source_lane: canonical_source_lane,
+            build_dir,
+            source_dir,
+            package_stage,
+            modules,
+        };
+        outputs.ensure_required_files()?;
+        Ok(outputs)
+    }
+
+    pub(crate) fn discover_for_aot(source_lane: &str) -> Result {
+        Self::discover_product_for_aot(source_lane, AssetProduct::Runtime)
+    }
+
+    fn discover_product_for_aot(source_lane: &str, product: AssetProduct) -> Result {
+        let canonical = canonical_source_lane(source_lane)?;
+        if canonical == DEFAULT_SOURCE_LANE {
+            return Self::discover_product(source_lane, product).or_else(|build_err| {
+                eprintln!(
+                    "warning: transient WASIX build tree unavailable for {source_lane} AOT packaging: {build_err:#}"
+                );
+                Self::from_packaged_assets_for_source_lane(source_lane, product)
+            });
+        }
+        unreachable!("canonical_source_lane returned an unsupported lane: {canonical}")
+    }
+
+    fn from_packaged_assets_for_source_lane(
+        source_lane: &str,
+        product: AssetProduct,
+    ) -> Result {
+        let manifest_path = product.root().join("assets/manifest.json");
+        let manifest: AssetManifestOut = serde_json::from_str(
+            &fs::read_to_string(&manifest_path)
+                .with_context(|| format!("read {}", manifest_path.display()))?,
+        )?;
+        ensure_packaged_asset_matches_source_lane(&manifest, source_lane)?;
+        let canonical_source_lane = canonical_source_lane(source_lane)?;
+        let base = product.root().join("aot-inputs");
+        if base.exists() {
+            fs::remove_dir_all(&base).with_context(|| format!("remove {}", base.display()))?;
+        }
+        fs::create_dir_all(&base).with_context(|| format!("create {}", base.display()))?;
+
+        let assets_base = product.root().join("assets");
+        let runtime_archive =
+            generated_assets_dir_for_source_lane(source_lane)?.join(&manifest.runtime.archive);
+        let runtime_path = base.join("runtime/oliphaunt");
+        write_bytes_file(
+            &runtime_path,
+            &archive_entry_bytes(&runtime_archive, RUNTIME_MODULE_ARCHIVE_MEMBER)?,
+        )?;
+
+        let mut modules = vec![BuildModuleOutput {
+            name: "runtime:oliphaunt".to_owned(),
+            kind: "runtime".to_owned(),
+            path: runtime_path,
+            aot_file: "oliphaunt-llvm-opta.bin.zst".to_owned(),
+            requires_aot: true,
+        }];
+
+        for support in &manifest.runtime_support {
+            let path = base.join("runtime-support").join(&support.name);
+            write_bytes_file(
+                &path,
+                &archive_entry_bytes(&runtime_archive, &format!("oliphaunt/{}", support.path))?,
+            )?;
+            modules.push(BuildModuleOutput {
+                name: format!("runtime-support:{}", support.name),
+                kind: "runtime-support".to_owned(),
+                path,
+                aot_file: format!("{}-llvm-opta.bin.zst", support.name),
+                requires_aot: true,
+            });
+        }
+
+        if let Some(pg_dump) = &manifest.pg_dump {
+            let path = base.join("tools/pg_dump");
+            copy_file(&assets_base.join(&pg_dump.path), &path)?;
+            modules.push(BuildModuleOutput {
+                name: "tool:pg_dump".to_owned(),
+                kind: "tool".to_owned(),
+                path,
+                aot_file: "pg_dump-llvm-opta.bin.zst".to_owned(),
+                requires_aot: true,
+            });
+        }
+        if let Some(psql) = &manifest.psql {
+            let path = base.join("tools/psql");
+            copy_file(&assets_base.join(&psql.path), &path)?;
+            modules.push(BuildModuleOutput {
+                name: "tool:psql".to_owned(),
+                kind: "tool".to_owned(),
+                path,
+                aot_file: "psql-llvm-opta.bin.zst".to_owned(),
+                requires_aot: true,
+            });
+        }
+        if let Some(initdb) = &manifest.initdb {
+            let path = base.join("tools/initdb");
+            copy_file(
+                &generated_assets_dir_for_source_lane(source_lane)?.join(&initdb.path),
+                &path,
+            )?;
+            modules.push(BuildModuleOutput {
+                name: "tool:initdb".to_owned(),
+                kind: "tool".to_owned(),
+                path,
+                aot_file: "initdb-llvm-opta.bin.zst".to_owned(),
+                requires_aot: true,
+            });
+        }
+
+        for extension in &manifest.extensions {
+            let mut native_modules = extension.native_modules.clone();
+            if native_modules.is_empty()
+                && let Some(native_module) = extension.native_module.as_deref()
+                && !extension.module_sha256.is_empty()
+            {
+                native_modules.push(BinaryAssetOut {
+                    name: extension.sql_name.clone(),
+                    path: format!("lib/postgresql/{native_module}"),
+                    sha256: extension.module_sha256.clone(),
+                    module_sha256: extension.module_sha256.clone(),
+                    size: 0,
+                    link: extension.link.clone().unwrap_or_default(),
+                });
+            }
+            for native_module in native_modules {
+                if native_module.module_sha256.is_empty() {
+                    continue;
+                }
+                let path = base.join("extensions").join(&extension.sql_name).join(
+                    Path::new(&native_module.path)
+                        .file_name()
+                        .unwrap_or_default(),
+                );
+                write_bytes_file(
+                    &path,
+                    &archive_entry_bytes(
+                        &assets_base.join(&extension.archive),
+                        &native_module.path,
+                    )?,
+                )?;
+                modules.push(BuildModuleOutput {
+                    name: if native_module.name == extension.sql_name {
+                        format!("extension:{}", extension.sql_name)
+                    } else {
+                        format!("extension:{}:{}", extension.sql_name, native_module.name)
+                    },
+                    kind: "extension".to_owned(),
+                    path,
+                    aot_file: format!("{}-llvm-opta.bin.zst", native_module.name.replace('/', "_")),
+                    requires_aot: true,
+                });
+            }
+        }
+
+        let declared = build_output_modules_from_asset_manifest(&manifest);
+        for module in &modules {
+            let expected = declared
+                .iter()
+                .find(|row| row.name == module.name)
+                .ok_or_else(|| anyhow!("packaged manifest omits module {}", module.name))?;
+            ensure_eq(
+                &sha256_file(&module.path)?,
+                &expected.sha256,
+                &format!("packaged module {} sha256", module.name),
+            )?;
+        }
+
+        Ok(Self {
+            product,
+            source_lane: canonical_source_lane.to_owned(),
+            source_fingerprint: manifest.source_fingerprint.clone(),
+            postgres_version: manifest.runtime.postgres_version.clone(),
+            build_dir: base.clone(),
+            source_dir: base.clone(),
+            package_stage: base,
+            modules,
+        })
+    }
+
+    fn ensure_required_files(&self) -> Result<()> {
+        for module in &self.modules {
+            ensure_file(&module.path)?;
+        }
+        self.ensure_build_source_markers()?;
+        ensure_file(&self.build_dir.join("src/timezone/compiled/UTC"))?;
+        ensure_file(
+            &self
+                .build_dir
+                .join("src/backend/snowball/snowball_create.sql"),
+        )?;
+        for language in [
+            "danish",
+            "dutch",
+            "english",
+            "finnish",
+            "french",
+            "german",
+            "hungarian",
+            "italian",
+            "nepali",
+            "norwegian",
+            "portuguese",
+            "russian",
+            "spanish",
+            "swedish",
+            "turkish",
+        ] {
+            ensure_file(
+                &self
+                    .source_dir
+                    .join(format!("src/backend/snowball/stopwords/{language}.stop")),
+            )?;
+        }
+        Ok(())
+    }
+
+    fn ensure_build_source_markers(&self) -> Result<()> {
+        match self.source_lane.as_str() {
+            "stable" => {
+                let source_fingerprint = self
+                    .source_fingerprint
+                    .as_deref()
+                    .ok_or_else(|| anyhow!("PG18 build outputs are missing source fingerprint"))?;
+                ensure_matching_marker(
+                    source_fingerprint,
+                    &self.build_dir.join(".oliphaunt-wasix-source-fingerprint"),
+                    "PG18 build source fingerprint",
+                )?;
+                ensure_matching_marker(
+                    &self.postgres_version,
+                    &self.build_dir.join(".oliphaunt-wasix-postgres-version"),
+                    "PG18 build PostgreSQL version marker",
+                )?;
+            }
+            other => bail!("unsupported WASIX asset source lane {other:?}"),
+        }
+        Ok(())
+    }
+
+    fn module_path(&self, name: &str) -> Result<&Path> {
+        self.modules
+            .iter()
+            .find(|module| module.name == name)
+            .map(|module| module.path.as_path())
+            .ok_or_else(|| anyhow!("missing build output module {name}"))
+    }
+
+    fn manifest_path(&self) -> Result {
+        if self.product == AssetProduct::Runtime {
+            Ok(build_output_manifest_path_for_source_lane(&self.source_lane)?.to_owned())
+        } else {
+            Ok(self.product.root().join("build-output-manifest.json"))
+        }
+    }
+
+    fn write_manifest(&self) -> Result<()> {
+        let manifest = BuildOutputManifestOut {
+            format_version: 1,
+            source_lane: Some(self.source_lane.clone()),
+            source_fingerprint: self.source_fingerprint.clone(),
+            postgres_version: Some(self.postgres_version.clone()),
+            build_profile: fs::read_to_string(
+                self.build_dir.join(".oliphaunt-wasix-build-profile"),
+            )
+            .context("read WASIX build profile signature")?,
+            modules: self
+                .modules
+                .iter()
+                .map(|module| {
+                    Ok(BuildModuleManifestOut {
+                        name: module.name.clone(),
+                        kind: module.kind.clone(),
+                        path: module.path.to_string_lossy().into_owned(),
+                        sha256: sha256_file(&module.path)?,
+                        link: read_wasm_link_metadata(&module.path)?,
+                    })
+                })
+                .collect::>>()?,
+        };
+        for module in &manifest.modules {
+            validate_module_link_metadata(module)?;
+        }
+        ensure_build_output_manifest_matches_source_lane(&manifest, &self.source_lane)?;
+        let text = serde_json::to_string_pretty(&manifest)
+            .context("serialize WASIX build output manifest")?;
+        let path = self.manifest_path()?;
+        if let Some(parent) = path.parent() {
+            fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?;
+        }
+        fs::write(&path, format!("{text}\n")).with_context(|| format!("write {}", path.display()))
+    }
+}
+
+fn extension_build_module_path(
+    build_dir: &Path,
+    extension: &extension_catalog::ExtensionBuildSpec,
+) -> Result {
+    let module_file = extension
+        .module_file
+        .as_deref()
+        .ok_or_else(|| anyhow!("extension {} has no native module", extension.sql_name))?;
+    match extension.build_kind.as_str() {
+        "postgres-contrib" => {
+            let contrib_dir = extension
+                .contrib_dir
+                .as_deref()
+                .ok_or_else(|| anyhow!("contrib extension {} has no contrib_dir", extension.id))?;
+            Ok(build_dir
+                .join("contrib")
+                .join(contrib_dir)
+                .join(module_file))
+        }
+        kind if extension_catalog::is_pgxs_style_build_kind(kind) => {
+            Ok(pgxs_extension_build_dir(build_dir, extension).join(module_file))
+        }
+        kind if extension_catalog::is_recipe_staged_build_kind(kind) => {
+            let staging = extension
+                .staging
+                .as_ref()
+                .ok_or_else(|| anyhow!("extension {} has no staging metadata", extension.id))?;
+            let module_source_dir = staging.module_source_dir.as_deref().ok_or_else(|| {
+                anyhow!(
+                    "extension {} staging metadata has no module_source_dir",
+                    extension.id
+                )
+            })?;
+            Ok(build_dir.join(module_source_dir).join(module_file))
+        }
+        other => bail!(
+            "supported extension {} has unsupported build kind {other}",
+            extension.sql_name
+        ),
+    }
+}
+
+fn pgxs_extension_build_dir(
+    build_dir: &Path,
+    extension: &extension_catalog::ExtensionBuildSpec,
+) -> PathBuf {
+    build_dir.join("pgxs").join(&extension.id)
+}
+
+fn extension_aot_file_stem(extension: &extension_catalog::ExtensionBuildSpec) -> String {
+    extension.sql_name.replace('/', "_")
+}
+
+fn validate_module_link_metadata(module: &BuildModuleManifestOut) -> Result<()> {
+    if module.link.exports.is_empty() {
+        bail!("{} has no WASM exports", module.name);
+    }
+
+    match module.kind.as_str() {
+        "runtime" => {
+            let thread_spawn_imports = module
+                .link
+                .imports
+                .iter()
+                .filter(|import| is_thread_spawn_import(import))
+                .map(|import| format!("{}.{}", import.module, import.name))
+                .collect::>();
+            ensure!(
+                thread_spawn_imports.is_empty(),
+                "{} violates the single-backend contract with thread-spawn imports: {}",
+                module.name,
+                thread_spawn_imports.join(", ")
+            );
+            let missing = required_runtime_abi_exports()
+                .iter()
+                .copied()
+                .filter(|export| !has_wasm_export(&module.link, export))
+                .collect::>();
+            if !missing.is_empty() {
+                bail!(
+                    "{} is missing required Rust/WASIX ABI exports: {}",
+                    module.name,
+                    missing.join(", ")
+                );
+            }
+            for banned in [
+                "oliphaunt_wasix_initdb",
+                "oliphaunt_wasix_backend",
+                "PostgresRecoverProtocolError",
+            ] {
+                if has_wasm_export(&module.link, banned) {
+                    bail!(
+                        "{} exports legacy builder-branch lifecycle entrypoint {banned}",
+                        module.name
+                    );
+                }
+            }
+        }
+        "runtime-support" | "extension" => {
+            if !module.link.has_dylink0 {
+                bail!("{} is not a WASM dynamic-linking side module", module.name);
+            }
+            if module.link.imports.is_empty() && module.link.dylink_imports.is_empty() {
+                bail!(
+                    "{} has no imports; side-module linkage is suspicious",
+                    module.name
+                );
+            }
+        }
+        "tool" => {}
+        other => bail!("{} has unknown build output kind {other}", module.name),
+    }
+
+    Ok(())
+}
+
+fn is_thread_spawn_import(import: &WasmImportOut) -> bool {
+    matches!(
+        import.name.trim_start_matches('_'),
+        "thread-spawn"
+            | "thread_spawn"
+            | "thread_spawn_v2"
+            | "wasi_thread_spawn"
+            | "wasi_thread_spawn_v2"
+            | "pthread_create"
+    )
+}
+
+fn validate_build_output_link_closure(outputs: &BuildOutputs) -> Result<()> {
+    let runtime = outputs
+        .modules
+        .iter()
+        .find(|module| module.kind == "runtime")
+        .ok_or_else(|| anyhow!("build outputs are missing runtime module"))?;
+    let runtime_link = read_wasm_link_metadata(&runtime.path)?;
+    validate_sealed_runtime_exports(&runtime_link)?;
+    let side_modules = outputs
+        .modules
+        .iter()
+        .filter(|module| matches!(module.kind.as_str(), "runtime-support" | "extension"))
+        .collect::>();
+    let side_module_links = side_modules
+        .iter()
+        .map(|module| {
+            Ok::<_, anyhow::Error>((module.name.clone(), read_wasm_link_metadata(&module.path)?))
+        })
+        .collect::>>()?;
+    let side_module_basenames = side_module_basename_index(
+        side_modules
+            .iter()
+            .map(|module| (module.name.as_str(), module.path.as_path())),
+    )?;
+
+    let mut failures = Vec::new();
+    for module in side_modules {
+        let link = side_module_links
+            .get(&module.name)
+            .ok_or_else(|| anyhow!("missing link metadata for {}", module.name))?;
+        let provider_exports =
+            side_module_provider_exports(&module.name, &side_module_links, &side_module_basenames)?;
+        for import in &link.imports {
+            if !import_should_resolve_from_runtime(import) {
+                continue;
+            }
+            if import_resolves_from_wasm_exports(import, &provider_exports, &module.name)? {
+                continue;
+            }
+            if !import_resolves_from_wasm_exports(import, &runtime_link.exports, "runtime")? {
+                failures.push(format!(
+                    "{} imports {}.{}",
+                    module.name, import.module, import.name
+                ));
+            }
+        }
+    }
+
+    if !failures.is_empty() {
+        bail!(
+            "WASIX dynamic-link closure has unresolved side-module imports: {}",
+            failures.join(", ")
+        );
+    }
+    Ok(())
+}
+
+fn validate_sealed_runtime_exports(runtime: &WasmLinkMetadataOut) -> Result<()> {
+    let policy_path =
+        repo_relative_path("src/runtimes/liboliphaunt-wasix/assets/generated/wasix-dl.exports");
+    let policy = fs::read_to_string(&policy_path)
+        .with_context(|| format!("read {}", policy_path.display()))?;
+    let mut expected = policy
+        .lines()
+        .filter(|line| !line.is_empty())
+        .map(str::to_owned)
+        .collect::>();
+    expected.extend(
+        WASIX_LINKER_RUNTIME_EXPORTS
+            .iter()
+            .map(|name| (*name).to_owned()),
+    );
+    let actual = runtime
+        .exports
+        .iter()
+        .map(|export| export.name.clone())
+        .collect::>();
+    ensure_exact_runtime_export_surface(&actual, &expected)
+}
+
+fn ensure_exact_runtime_export_surface(
+    actual: &BTreeSet,
+    expected: &BTreeSet,
+) -> Result<()> {
+    let missing = expected.difference(actual).cloned().collect::>();
+    let unexpected = actual.difference(expected).cloned().collect::>();
+    ensure!(
+        missing.is_empty() && unexpected.is_empty(),
+        "sealed WASIX runtime export surface differs: missing={missing:?} unexpected={unexpected:?}"
+    );
+    Ok(())
+}
+
+fn side_module_provider_exports(
+    module_name: &str,
+    links_by_name: &BTreeMap,
+    names_by_basename: &BTreeMap,
+) -> Result> {
+    let mut provider_names = BTreeSet::from([module_name.to_owned()]);
+    let mut pending = vec![module_name.to_owned()];
+    while let Some(name) = pending.pop() {
+        let link = links_by_name
+            .get(&name)
+            .ok_or_else(|| anyhow!("missing side-module link metadata for {name}"))?;
+        for needed in &link.dylink_needed {
+            let dependency = names_by_basename.get(needed).ok_or_else(|| {
+                anyhow!("{name} declares missing WASIX dynamic dependency {needed}")
+            })?;
+            if provider_names.insert(dependency.clone()) {
+                pending.push(dependency.clone());
+            }
+        }
+    }
+    Ok(provider_names
+        .into_iter()
+        .flat_map(|name| {
+            links_by_name
+                .get(&name)
+                .into_iter()
+                .flat_map(|link| link.exports.iter().cloned())
+        })
+        .collect())
+}
+
+fn side_module_basename_index<'a>(
+    modules: impl IntoIterator,
+) -> Result> {
+    let mut names_by_basename = BTreeMap::new();
+    for (name, path) in modules {
+        let basename = path
+            .file_name()
+            .and_then(|value| value.to_str())
+            .ok_or_else(|| anyhow!("side-module {name} path has no UTF-8 basename"))?;
+        if let Some(previous) = names_by_basename.insert(basename.to_owned(), name.to_owned()) {
+            bail!("WASIX side modules {previous} and {name} share dynamic basename {basename}");
+        }
+    }
+    Ok(names_by_basename)
+}
+
+fn extension_module_sql_name(module_name: &str) -> Option<&str> {
+    module_name
+        .strip_prefix("extension:")
+        .and_then(|rest| rest.split(':').next())
+        .filter(|sql_name| !sql_name.is_empty())
+}
+
+pub(crate) fn generate_wasix_export_list(write: bool, source_lane: &str) -> Result<()> {
+    let output = wasix_export_list_text(source_lane)?;
+    if write {
+        let path = Path::new("src/runtimes/liboliphaunt-wasix/assets/generated/wasix-dl.exports");
+        if let Some(parent) = path.parent() {
+            fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?;
+        }
+        fs::write(path, output).with_context(|| format!("write {}", path.display()))?;
+    } else {
+        print!("{output}");
+    }
+    Ok(())
+}
+
+pub(crate) fn check_generated_wasix_export_list(strict: bool) -> Result<()> {
+    let expected = match wasix_export_list_text(DEFAULT_SOURCE_LANE) {
+        Ok(expected) => expected,
+        Err(err) if !strict => {
+            eprintln!("warning: skipping generated WASIX export-list check: {err:#}");
+            return Ok(());
+        }
+        Err(err) => return Err(err).context("generate expected WASIX export list"),
+    };
+    let path = Path::new("src/runtimes/liboliphaunt-wasix/assets/generated/wasix-dl.exports");
+    if !path.exists() {
+        if strict {
+            bail!(
+                "generated WASIX export list is missing at {}; run `cargo run -p xtask -- assets export-list --write`",
+                path.display()
+            );
+        }
+        eprintln!(
+            "warning: generated WASIX export list is missing at {}",
+            path.display()
+        );
+        return Ok(());
+    }
+    let actual = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?;
+    if actual != expected {
+        if strict {
+            bail!(
+                "generated WASIX export list is stale at {}; run `cargo run -p xtask -- assets export-list --write`",
+                path.display()
+            );
+        }
+        eprintln!(
+            "warning: generated WASIX export list is stale at {}",
+            path.display()
+        );
+    }
+    Ok(())
+}
+
+fn wasix_export_list_text(source_lane: &str) -> Result {
+    for manifest_path in [Path::new(
+        "target/extensions/wasix/build-output-manifest.json",
+    )] {
+        if !manifest_path.exists() {
+            continue;
+        }
+        let manifest = read_build_output_manifest(manifest_path)?;
+        match ensure_build_output_manifest_matches_source_lane(&manifest, source_lane) {
+            Ok(()) => return wasix_export_list_from_modules(&manifest.modules),
+            Err(err) => {
+                eprintln!(
+                    "warning: ignoring WASIX build output manifest {} while generating export list for {source_lane}: {err:#}",
+                    manifest_path.display()
+                );
+            }
+        }
+    }
+    let asset_dir = Path::new("target/extensions/wasix/assets");
+    if asset_dir.join("manifest.json").exists() {
+        let manifest: AssetManifestOut =
+            serde_json::from_str(&fs::read_to_string(asset_dir.join("manifest.json"))?)?;
+        if ensure_packaged_asset_matches_source_lane(&manifest, source_lane).is_ok() {
+            let modules = build_output_modules_from_asset_manifest(&manifest);
+            return wasix_export_list_from_modules(&modules);
+        }
+        eprintln!(
+            "warning: ignoring generated asset manifest for PostgreSQL {} while generating export list for {source_lane}",
+            manifest.runtime.postgres_version
+        );
+    }
+
+    let outputs = BuildOutputs::discover_product(source_lane, AssetProduct::Extensions)?;
+    let modules = outputs
+        .modules
+        .iter()
+        .map(|module| {
+            Ok(BuildModuleManifestOut {
+                name: module.name.clone(),
+                kind: module.kind.clone(),
+                path: module.path.to_string_lossy().into_owned(),
+                sha256: String::new(),
+                link: read_wasm_link_metadata(&module.path)?,
+            })
+        })
+        .collect::>>()?;
+    wasix_export_list_from_modules(&modules)
+}
+
+fn read_build_output_manifest(path: &Path) -> Result {
+    let text = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?;
+    serde_json::from_str(&text).with_context(|| format!("parse {}", path.display()))
+}
+
+pub(crate) fn read_asset_manifest_from(asset_dir: &Path) -> Result {
+    let path = asset_dir.join("manifest.json");
+    let text = fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?;
+    let manifest: AssetManifestOut =
+        serde_json::from_str(&text).with_context(|| format!("parse {}", path.display()))?;
+    ensure!(
+        manifest.format_version == ASSET_MANIFEST_FORMAT_VERSION,
+        "{} must use WASIX asset manifest format {}",
+        path.display(),
+        ASSET_MANIFEST_FORMAT_VERSION,
+    );
+    Ok(manifest)
+}
+
+fn build_output_modules_from_asset_manifest(
+    manifest: &AssetManifestOut,
+) -> Vec {
+    let mut modules = vec![BuildModuleManifestOut {
+        name: "runtime:oliphaunt".to_owned(),
+        kind: "runtime".to_owned(),
+        path: manifest.runtime.archive.clone(),
+        sha256: manifest.runtime.module_sha256.clone(),
+        link: manifest.runtime.link.clone(),
+    }];
+
+    modules.extend(
+        manifest
+            .runtime_support
+            .iter()
+            .map(|module| BuildModuleManifestOut {
+                name: format!("runtime-support:{}", module.name),
+                kind: "runtime-support".to_owned(),
+                path: module.path.clone(),
+                sha256: module.module_sha256.clone(),
+                link: module.link.clone(),
+            }),
+    );
+
+    if let Some(pg_dump) = &manifest.pg_dump {
+        modules.push(BuildModuleManifestOut {
+            name: "tool:pg_dump".to_owned(),
+            kind: "tool".to_owned(),
+            path: pg_dump.path.clone(),
+            sha256: pg_dump.module_sha256.clone(),
+            link: pg_dump.link.clone(),
+        });
+    }
+    if let Some(psql) = &manifest.psql {
+        modules.push(BuildModuleManifestOut {
+            name: "tool:psql".to_owned(),
+            kind: "tool".to_owned(),
+            path: psql.path.clone(),
+            sha256: psql.module_sha256.clone(),
+            link: psql.link.clone(),
+        });
+    }
+    if let Some(initdb) = &manifest.initdb {
+        modules.push(BuildModuleManifestOut {
+            name: "tool:initdb".to_owned(),
+            kind: "tool".to_owned(),
+            path: initdb.path.clone(),
+            sha256: initdb.module_sha256.clone(),
+            link: initdb.link.clone(),
+        });
+    }
+
+    for extension in &manifest.extensions {
+        for native_module in &extension.native_modules {
+            modules.push(BuildModuleManifestOut {
+                name: if native_module.name == extension.sql_name {
+                    format!("extension:{}", extension.sql_name)
+                } else {
+                    format!("extension:{}:{}", extension.sql_name, native_module.name)
+                },
+                kind: "extension".to_owned(),
+                path: native_module.path.clone(),
+                sha256: native_module.module_sha256.clone(),
+                link: native_module.link.clone(),
+            });
+        }
+        let has_primary_native_module = extension
+            .native_modules
+            .iter()
+            .any(|module| module.name == extension.sql_name);
+        if !has_primary_native_module && let Some(link) = extension.link.clone() {
+            modules.push(BuildModuleManifestOut {
+                name: format!("extension:{}", extension.sql_name),
+                kind: "extension".to_owned(),
+                path: extension.archive.clone(),
+                sha256: extension.module_sha256.clone(),
+                link,
+            });
+        }
+    }
+
+    modules
+}
+
+fn wasix_export_list_from_modules(modules: &[BuildModuleManifestOut]) -> Result {
+    for module in modules {
+        validate_module_link_metadata(module)?;
+    }
+
+    let _runtime = modules
+        .iter()
+        .find(|module| module.kind == "runtime")
+        .ok_or_else(|| anyhow!("build outputs are missing runtime module"))?;
+    let side_modules = modules
+        .iter()
+        .filter(|module| matches!(module.kind.as_str(), "runtime-support" | "extension"))
+        .collect::>();
+    let side_module_links = side_modules
+        .iter()
+        .map(|module| (module.name.clone(), module.link.clone()))
+        .collect::>();
+    let side_module_basenames = side_module_basename_index(
+        side_modules
+            .iter()
+            .map(|module| (module.name.as_str(), Path::new(&module.path))),
+    )?;
+    let mut required_exports = BTreeSet::::new();
+
+    for &abi_export in required_runtime_abi_exports() {
+        required_exports.insert(abi_export.to_owned());
+    }
+
+    for module in side_modules {
+        let module_exports =
+            side_module_provider_exports(&module.name, &side_module_links, &side_module_basenames)?;
+        for import in &module.link.imports {
+            if !import_should_resolve_from_runtime(import) {
+                continue;
+            }
+            if import_resolves_from_wasm_exports(import, &module_exports, &module.name)? {
+                continue;
+            }
+            // The strict final link proves that the runtime defines every policy symbol. Do not
+            // consult the previously sealed runtime here: doing so would make adding a new side
+            // module import impossible without first restoring an ambient export surface.
+            required_exports.insert(runtime_export_name_for_side_import(import));
+        }
+    }
+
+    Ok(required_exports.into_iter().collect::>().join("\n") + "\n")
+}
+
+pub(crate) fn required_runtime_abi_exports() -> &'static [&'static str] {
+    REQUIRED_RUNTIME_ABI_EXPORTS
+}
+
+const WASIX_LINKER_RUNTIME_EXPORTS: &[&str] = &[
+    "__data_end",
+    "__tls_align",
+    "__tls_base",
+    "__tls_size",
+    "__wasm_apply_data_relocs",
+    "__wasm_call_ctors",
+    "__wasm_init_tls",
+    "__wasm_sigaction",
+    "__wasm_signal",
+    "wasi_thread_start",
+];
+
+fn import_should_resolve_from_runtime(import: &WasmImportOut) -> bool {
+    if import_is_wasix_linker_provided(import) {
+        return false;
+    }
+    matches!(import.module.as_str(), "env" | "GOT.func" | "GOT.mem")
+}
+
+fn import_is_wasix_linker_provided(import: &WasmImportOut) -> bool {
+    matches!(
+        (import.module.as_str(), import.name.as_str()),
+        (
+            "env",
+            "__c_longjmp"
+                | "__cpp_exception"
+                | "__indirect_function_table"
+                | "__memory_base"
+                | "__stack_pointer"
+                | "__table_base"
+                | "memory",
+        ) | ("GOT.mem", "__heap_base" | "__stack_high" | "__stack_low")
+    )
+}
+
+fn import_resolves_from_wasm_exports(
+    import: &WasmImportOut,
+    exports: &[WasmExportOut],
+    provider: &str,
+) -> Result {
+    Ok(resolved_wasm_export_name(import, exports, provider)?.is_some())
+}
+
+fn resolved_wasm_export_name(
+    import: &WasmImportOut,
+    exports: &[WasmExportOut],
+    provider: &str,
+) -> Result> {
+    let mut candidates = exports
+        .iter()
+        .filter(|export| export.name == import.name)
+        .collect::>();
+    if candidates.is_empty() {
+        let normalized = import.name.trim_start_matches('_');
+        candidates = exports
+            .iter()
+            .filter(|export| export.name.trim_start_matches('_') == normalized)
+            .collect();
+    }
+    if candidates.is_empty() {
+        return Ok(None);
+    }
+    let expected_kind = match import.module.as_str() {
+        "GOT.func" => "func",
+        "GOT.mem" => "global",
+        _ => import.kind.as_str(),
+    };
+    ensure!(
+        candidates.iter().any(|export| export.kind == expected_kind),
+        "{provider} provides {}.{} as {:?}, expected {expected_kind}",
+        import.module,
+        import.name,
+        candidates
+            .iter()
+            .map(|export| export.kind.as_str())
+            .collect::>()
+    );
+    Ok(candidates
+        .into_iter()
+        .find(|export| export.kind == expected_kind)
+        .map(|export| export.name.clone()))
+}
+
+fn runtime_export_name_for_side_import(import: &WasmImportOut) -> String {
+    import.name.clone()
+}
+
+fn extension_asset_provider_exports(
+    primary_link: &WasmLinkMetadataOut,
+    primary_path: &Path,
+    sql_name: &str,
+    native_modules: &[OwnedExtensionNativeModule],
+    native_module_links: &BTreeMap,
+) -> Result> {
+    let root_name = format!("extension:{sql_name}");
+    let mut links = BTreeMap::from([(root_name.clone(), primary_link.clone())]);
+    let mut paths = vec![(root_name.as_str(), primary_path)];
+    let mut dependency_names = Vec::new();
+    for module in native_modules {
+        if module.name == sql_name {
+            continue;
+        }
+        let name = format!("extension:{sql_name}:{}", module.name);
+        let link = native_module_links
+            .get(&module.name)
+            .ok_or_else(|| anyhow!("missing link metadata for {name}"))?;
+        links.insert(name.clone(), link.clone());
+        dependency_names.push((name, module.path.as_path()));
+    }
+    paths.extend(
+        dependency_names
+            .iter()
+            .map(|(name, path)| (name.as_str(), *path)),
+    );
+    let basenames = side_module_basename_index(paths)?;
+    side_module_provider_exports(&root_name, &links, &basenames)
+}
+
+fn has_wasm_export(link: &WasmLinkMetadataOut, name: &str) -> bool {
+    link.exports
+        .iter()
+        .any(|export| export.name == name || export.name == format!("_{name}"))
+}
+
+pub(crate) fn prepare_aot_artifacts(
+    target: &str,
+    source_lane: &str,
+    product: AssetProduct,
+) -> Result<()> {
+    ensure_supported_aot_target(target)?;
+    let outputs = BuildOutputs::discover_product_for_aot(source_lane, product)?;
+    let source_dir = outputs.product.root().join("aot-source").join(target);
+    if source_dir.exists() {
+        fs::remove_dir_all(&source_dir)
+            .with_context(|| format!("remove {}", source_dir.display()))?;
+    }
+    fs::create_dir_all(&source_dir).with_context(|| format!("create {}", source_dir.display()))?;
+
+    for module in outputs
+        .modules
+        .iter()
+        .filter(|module| module.requires_aot && product.owns(&module.name))
+    {
+        let output = source_dir.join(&module.aot_file);
+        let input = fs::canonicalize(&module.path)
+            .with_context(|| format!("canonicalize {}", module.path.display()))?;
+        let input = input.to_str().context("AOT input path is not UTF-8")?;
+        let output = output.to_str().context("AOT output path is not UTF-8")?;
+        ensure!(
+            !input.contains(['\t', '\r', '\n']) && !output.contains(['\t', '\r', '\n']),
+            "AOT paths must not contain control delimiters"
+        );
+        println!("{input}\t{output}");
+    }
+    Ok(())
+}
+
+fn is_core_aot_module(name: &str) -> bool {
+    !name.starts_with("extension:")
+}
+
+pub(crate) fn package_aot_only(
+    manifest: &SourcesManifest,
+    target: &str,
+    source_lane: &str,
+    product: AssetProduct,
+) -> Result<()> {
+    let outputs = BuildOutputs::discover_product_for_aot(source_lane, product)?;
+    package_aot_artifacts(target, &outputs, manifest)?;
+    check_aot_product_manifest(target, source_lane, product)
+}
+
+pub(crate) fn package_assets(
+    manifest: &SourcesManifest,
+    target: &str,
+    source_lane: &str,
+) -> Result<()> {
+    package_assets_with_options(manifest, target, true, source_lane, AssetProduct::Runtime)
+}
+
+pub(crate) fn package_assets_without_aot(
+    manifest: &SourcesManifest,
+    source_lane: &str,
+) -> Result<()> {
+    package_assets_with_options(
+        manifest,
+        host_target_triple(),
+        false,
+        source_lane,
+        AssetProduct::Runtime,
+    )
+}
+
+pub(crate) fn package_product_assets(
+    manifest: &SourcesManifest,
+    source_lane: &str,
+    product: AssetProduct,
+) -> Result<()> {
+    package_assets_with_options(manifest, host_target_triple(), false, source_lane, product)
+}
+
+fn package_assets_with_options(
+    manifest: &SourcesManifest,
+    target: &str,
+    include_aot: bool,
+    source_lane: &str,
+    product: AssetProduct,
+) -> Result<()> {
+    let outputs = BuildOutputs::discover_product(source_lane, product)?;
+    outputs.write_manifest()?;
+    validate_build_output_link_closure(&outputs)?;
+    let build = &outputs.build_dir;
+    let source = &outputs.source_dir;
+    let stage_path = if product == AssetProduct::Runtime {
+        outputs.package_stage.clone()
+    } else {
+        product.root().join("package-stage")
+    };
+    let stage = &stage_path;
+
+    if stage.exists() {
+        fs::remove_dir_all(stage).with_context(|| format!("remove {}", stage.display()))?;
+    }
+    fs::create_dir_all(stage).with_context(|| format!("create {}", stage.display()))?;
+
+    let runtime_stage = stage.join("runtime/oliphaunt");
+    if product == AssetProduct::Runtime {
+        stage_runtime_tree(build, source, &runtime_stage)?;
+    }
+    let assets_path = product.root().join("assets");
+    let assets_dir = &assets_path;
+    if assets_dir.exists() {
+        fs::remove_dir_all(assets_dir)
+            .with_context(|| format!("remove {}", assets_dir.display()))?;
+    }
+    fs::create_dir_all(assets_dir).with_context(|| format!("create {}", assets_dir.display()))?;
+    let runtime_archive =
+        generated_assets_dir_for_source_lane(source_lane)?.join("oliphaunt.wasix.tar.zst");
+    if product == AssetProduct::Runtime {
+        deterministic_tar_zst(&runtime_stage, Path::new("oliphaunt"), &runtime_archive)?;
+    }
+
+    let pg_dump = if product != AssetProduct::Tools {
+        None
+    } else {
+        let pg_dump = assets_dir.join("bin/pg_dump.wasix.wasm");
+        copy_file(outputs.module_path("tool:pg_dump")?, &pg_dump)?;
+        Some(pg_dump)
+    };
+    let psql = if product != AssetProduct::Tools {
+        None
+    } else {
+        let psql = assets_dir.join("bin/psql.wasix.wasm");
+        copy_file(outputs.module_path("tool:psql")?, &psql)?;
+        Some(psql)
+    };
+    let initdb = generated_assets_dir_for_source_lane(source_lane)?.join("bin/initdb.wasix.wasm");
+    if product == AssetProduct::Runtime {
+        copy_file(outputs.module_path("tool:initdb")?, &initdb)?;
+    }
+
+    let extension_artifacts = if product == AssetProduct::Extensions {
+        build_extension_artifacts(source, build, stage, assets_dir, &outputs)?
+    } else {
+        Vec::new()
+    };
+    let extension_artifact_refs = extension_artifacts
+        .iter()
+        .map(|extension| ExtensionArtifact {
+            name: extension.name.as_str(),
+            sql_name: extension.sql_name.as_str(),
+            archive: extension.archive.as_str(),
+            path: extension.path.as_path(),
+            module_path: extension.module_path.as_deref(),
+            native_module: extension.native_module.as_deref(),
+            native_modules: &extension.native_modules,
+        })
+        .collect::>();
+
+    if include_aot {
+        package_aot_artifacts(target, &outputs, manifest)?;
+    }
+    write_asset_manifest(
+        manifest,
+        &outputs,
+        assets_dir,
+        outputs.module_path("runtime:oliphaunt")?,
+        &runtime_archive,
+        pg_dump.as_deref(),
+        psql.as_deref(),
+        &initdb,
+        &[
+            BinaryPackage {
+                name: "plpgsql",
+                path: outputs.module_path("runtime-support:plpgsql")?,
+                runtime_path: "lib/postgresql/plpgsql.so",
+            },
+            BinaryPackage {
+                name: "dict_snowball",
+                path: outputs.module_path("runtime-support:dict_snowball")?,
+                runtime_path: "lib/postgresql/dict_snowball.so",
+            },
+        ],
+        &extension_artifact_refs,
+    )?;
+
+    if product == AssetProduct::Extensions {
+        verify_generated_extension_surface()?;
+        check_generated_wasix_export_list(true)?;
+    }
+    println!("packaged {product:?} assets into {}", assets_dir.display());
+    if include_aot {
+        println!("packaged {target} AOT artifacts");
+    } else {
+        println!("skipped {target} AOT artifact packaging by request");
+    }
+    Ok(())
+}
+
+pub(crate) fn stage_compiler_runtime(source_lane: &str) -> Result<()> {
+    let outputs = BuildOutputs::discover_for_source_lane(source_lane)?;
+    let install = Path::new(WASIX_POSTGRES_GENERATED_BUILD_DIR).join("install");
+    if install.exists() {
+        fs::remove_dir_all(&install).with_context(|| format!("remove {}", install.display()))?;
+    }
+    stage_runtime_tree(&outputs.build_dir, &outputs.source_dir, &install)
+}
+
+fn build_extension_artifacts(
+    source: &Path,
+    build: &Path,
+    stage: &Path,
+    assets_dir: &Path,
+    outputs: &BuildOutputs,
+) -> Result> {
+    let mut packages = Vec::new();
+    for extension in extension_catalog::extension_build_specs()? {
+        let extension_stage = stage.join("extensions").join(&extension.sql_name);
+        stage_extension(source, build, &extension, &extension_stage)?;
+        let archive_path = assets_dir.join(&extension.archive);
+        deterministic_tar_zst(&extension_stage, Path::new(""), &archive_path)?;
+        let native_modules = extension_native_module_artifacts(&extension, outputs)?;
+        packages.push(OwnedExtensionArtifact {
+            name: extension.display_name,
+            sql_name: extension.sql_name.clone(),
+            archive: extension.archive.clone(),
+            path: archive_path,
+            module_path: if extension.module_file.is_some() {
+                Some(
+                    outputs
+                        .module_path(&format!("extension:{}", extension.sql_name))?
+                        .to_path_buf(),
+                )
+            } else {
+                None
+            },
+            native_module: extension.module_file.clone(),
+            native_modules,
+        });
+    }
+    Ok(packages)
+}
+
+fn extension_native_module_artifacts(
+    extension: &extension_catalog::ExtensionBuildSpec,
+    outputs: &BuildOutputs,
+) -> Result> {
+    let mut modules = Vec::new();
+    for support_module in &extension.native_support_modules {
+        modules.push(OwnedExtensionNativeModule {
+            name: support_module.name.clone(),
+            runtime_path: support_module.runtime_path.clone(),
+            path: outputs
+                .module_path(&format!(
+                    "extension:{}:{}",
+                    extension.sql_name, support_module.name
+                ))?
+                .to_path_buf(),
+        });
+    }
+    if let Some(module_file) = &extension.module_file {
+        modules.push(OwnedExtensionNativeModule {
+            name: extension.sql_name.clone(),
+            runtime_path: format!("lib/postgresql/{module_file}"),
+            path: outputs
+                .module_path(&format!("extension:{}", extension.sql_name))?
+                .to_path_buf(),
+        });
+    }
+    Ok(modules)
+}
+
+fn stage_extension(
+    source: &Path,
+    build: &Path,
+    extension: &extension_catalog::ExtensionBuildSpec,
+    stage: &Path,
+) -> Result<()> {
+    match extension.build_kind.as_str() {
+        "postgres-contrib" => stage_contrib_extension(source, build, extension, stage),
+        kind if extension_catalog::is_pgxs_style_build_kind(kind) => {
+            stage_pgxs_style_extension(build, extension, stage)
+        }
+        kind if extension_catalog::is_recipe_staged_build_kind(kind) => {
+            stage_recipe_staged_extension(build, extension, stage)
+        }
+        other => bail!(
+            "supported extension {} has unsupported packaging build kind {other}",
+            extension.sql_name
+        ),
+    }
+}
+
+fn stage_recipe_staged_extension(
+    build: &Path,
+    extension: &extension_catalog::ExtensionBuildSpec,
+    stage: &Path,
+) -> Result<()> {
+    let staging = extension
+        .staging
+        .as_ref()
+        .ok_or_else(|| anyhow!("extension {} has no staging metadata", extension.id))?;
+    let extension_sql_dir = stage.join("share/postgresql/extension");
+    let module_dir = stage.join("lib/postgresql");
+    fs::create_dir_all(&extension_sql_dir)
+        .with_context(|| format!("create {}", extension_sql_dir.display()))?;
+    fs::create_dir_all(&module_dir).with_context(|| format!("create {}", module_dir.display()))?;
+
+    let module_file = extension
+        .module_file
+        .as_deref()
+        .ok_or_else(|| anyhow!("extension {} has no native module file", extension.id))?;
+    let module_source_dir = staging.module_source_dir.as_deref().ok_or_else(|| {
+        anyhow!(
+            "extension {} staging metadata has no module_source_dir",
+            extension.id
+        )
+    })?;
+    copy_file(
+        &build.join(module_source_dir).join(module_file),
+        &module_dir.join(module_file),
+    )?;
+    for support_module in &extension.native_support_modules {
+        let source = build.join(&support_module.build_path);
+        ensure!(
+            source.is_file(),
+            "extension {} build did not produce support module {}",
+            extension.id,
+            source.display()
+        );
+        copy_file(&source, &stage.join(&support_module.runtime_path))?;
+    }
+    let control_source = staging.control_source.as_deref().ok_or_else(|| {
+        anyhow!(
+            "extension {} staging metadata has no control_source",
+            extension.id
+        )
+    })?;
+    let control_source = build.join(control_source);
+    let control_file_name = control_source.file_name().ok_or_else(|| {
+        anyhow!(
+            "control source has no file name: {}",
+            control_source.display()
+        )
+    })?;
+    copy_file(&control_source, &extension_sql_dir.join(control_file_name))?;
+
+    let sql_source_dir = staging.sql_source_dir.as_deref().ok_or_else(|| {
+        anyhow!(
+            "extension {} staging metadata has no sql_source_dir",
+            extension.id
+        )
+    })?;
+    let sql_source_dir = build.join(sql_source_dir);
+    let copied_sql = copy_extension_sql_dir(&sql_source_dir, &extension_sql_dir)?;
+    ensure!(
+        copied_sql,
+        "extension {} build did not produce extension SQL files under {}",
+        extension.id,
+        sql_source_dir.display()
+    );
+    for excluded in &extension.excluded_sql_extensions {
+        let excluded_control = format!("{excluded}.control");
+        ensure!(
+            !extension_sql_dir.join(&excluded_control).exists(),
+            "extension {} archive must not include excluded extension control file {excluded_control}",
+            extension.id
+        );
+    }
+    for data_dir in &staging.data_dirs {
+        let source = build.join(&data_dir.source);
+        ensure!(
+            source.is_dir(),
+            "extension {} staging data directory is missing: {}",
+            extension.id,
+            source.display()
+        );
+        copy_dir_all(&source, &stage.join(&data_dir.destination))?;
+    }
+    Ok(())
+}
+
+fn stage_pgxs_style_extension(
+    build: &Path,
+    extension: &extension_catalog::ExtensionBuildSpec,
+    stage: &Path,
+) -> Result<()> {
+    let source = Path::new(&extension.source_dir);
+    let build_dir = pgxs_extension_build_dir(build, extension);
+    let sql_name = extension.sql_name.as_str();
+    let extension_sql_dir = stage.join("share/postgresql/extension");
+    fs::create_dir_all(stage.join("share/postgresql/extension"))
+        .with_context(|| format!("create {}", extension_sql_dir.display()))?;
+    if let Some(module_file) = &extension.module_file {
+        fs::create_dir_all(stage.join("lib/postgresql"))
+            .with_context(|| format!("create {}", stage.join("lib/postgresql").display()))?;
+        copy_file(
+            &build_dir.join(module_file),
+            &stage.join("lib/postgresql").join(module_file),
+        )?;
+    }
+    if extension.lifecycle.create_extension || extension.control_file.is_some() {
+        let control_file = extension
+            .control_file
+            .as_deref()
+            .map(Path::new)
+            .filter(|path| path.is_file())
+            .map(Path::to_path_buf)
+            .unwrap_or_else(|| source.join(format!("{sql_name}.control")));
+        copy_file(
+            &control_file,
+            &stage
+                .join("share/postgresql/extension")
+                .join(control_file.file_name().unwrap_or_default()),
+        )?;
+    }
+    let mut copied_root_sql = copy_extension_sql_files(&build_dir, sql_name, &extension_sql_dir)?;
+    if !copied_root_sql {
+        copied_root_sql = copy_extension_sql_files(source, sql_name, &extension_sql_dir)?;
+    }
+    if !copied_root_sql {
+        let copied_build_sql_dir =
+            copy_extension_sql_dir(&build_dir.join("sql"), &extension_sql_dir)?;
+        if !copied_build_sql_dir {
+            copy_extension_sql_dir(&source.join("sql"), &extension_sql_dir)?;
+        }
+    }
+    Ok(())
+}
+
+fn copy_extension_sql_files(source: &Path, sql_name: &str, destination: &Path) -> Result {
+    if !source.is_dir() {
+        return Ok(false);
+    }
+    let mut copied = false;
+    for entry in sorted_children(source)? {
+        if !entry.is_file() {
+            continue;
+        }
+        let Some(name) = entry.file_name().and_then(|name| name.to_str()) else {
+            continue;
+        };
+        if (name.starts_with(&format!("{sql_name}--")) || name == format!("{sql_name}.sql"))
+            && name.ends_with(".sql")
+        {
+            copy_file(&entry, &destination.join(name))?;
+            copied = true;
+        }
+    }
+    Ok(copied)
+}
+
+fn copy_extension_sql_dir(source: &Path, destination: &Path) -> Result {
+    if !source.is_dir() {
+        return Ok(false);
+    }
+    let mut copied = false;
+    for entry in sorted_files(source)? {
+        if entry.extension().and_then(|ext| ext.to_str()) != Some("sql") {
+            continue;
+        }
+        let file_name = entry
+            .file_name()
+            .ok_or_else(|| anyhow!("SQL file has no name: {}", entry.display()))?;
+        copy_file(&entry, &destination.join(file_name))?;
+        copied = true;
+    }
+    Ok(copied)
+}
+
+fn stage_contrib_extension(
+    source: &Path,
+    build: &Path,
+    extension: &extension_catalog::ExtensionBuildSpec,
+    stage: &Path,
+) -> Result<()> {
+    let contrib_dir = extension
+        .contrib_dir
+        .as_deref()
+        .ok_or_else(|| anyhow!("contrib extension {} has no contrib_dir", extension.id))?;
+    let extension_source = source.join("contrib").join(contrib_dir);
+    fs::create_dir_all(stage.join("share/postgresql/extension")).with_context(|| {
+        format!(
+            "create {}",
+            stage.join("share/postgresql/extension").display()
+        )
+    })?;
+    if let Some(module_file) = &extension.module_file {
+        fs::create_dir_all(stage.join("lib/postgresql"))
+            .with_context(|| format!("create {}", stage.join("lib/postgresql").display()))?;
+        copy_file(
+            &build.join("contrib").join(contrib_dir).join(module_file),
+            &stage.join("lib/postgresql").join(module_file),
+        )?;
+    }
+    if extension.lifecycle.create_extension || extension.control_file.is_some() {
+        let control_file = extension_source.join(format!("{}.control", extension.sql_name));
+        copy_file(
+            &control_file,
+            &stage
+                .join("share/postgresql/extension")
+                .join(control_file.file_name().unwrap_or_default()),
+        )?;
+    }
+    for entry in sorted_children(&extension_source)? {
+        if !entry.is_file() {
+            continue;
+        }
+        let Some(name) = entry.file_name().and_then(|name| name.to_str()) else {
+            continue;
+        };
+        if (name.starts_with(&format!("{}--", extension.sql_name))
+            || name == format!("{}.sql", extension.sql_name))
+            && name.ends_with(".sql")
+        {
+            copy_file(&entry, &stage.join("share/postgresql/extension").join(name))?;
+        } else if name.ends_with(".rules") {
+            let tsearch_data = stage.join("share/postgresql/tsearch_data");
+            fs::create_dir_all(&tsearch_data)
+                .with_context(|| format!("create {}", tsearch_data.display()))?;
+            copy_file(&entry, &tsearch_data.join(name))?;
+        }
+    }
+    Ok(())
+}
+
+fn stage_runtime_tree(build: &Path, source: &Path, runtime: &Path) -> Result<()> {
+    let bin = runtime.join("bin");
+    let lib = runtime.join("lib/postgresql");
+    let share = runtime.join("share/postgresql");
+    fs::create_dir_all(&bin).with_context(|| format!("create {}", bin.display()))?;
+    fs::create_dir_all(&lib).with_context(|| format!("create {}", lib.display()))?;
+    fs::create_dir_all(&share).with_context(|| format!("create {}", share.display()))?;
+
+    copy_file(&build.join("src/backend/oliphaunt"), &bin.join("postgres"))?;
+    copy_file(&build.join("src/bin/initdb/initdb"), &bin.join("initdb"))?;
+    fs::write(runtime.join("password"), b"password\n")
+        .with_context(|| format!("write {}", runtime.join("password").display()))?;
+
+    copy_file(
+        &build.join("src/include/catalog/postgres.bki"),
+        &share.join("postgres.bki"),
+    )?;
+    copy_file(
+        &build.join("src/include/catalog/system_constraints.sql"),
+        &share.join("system_constraints.sql"),
+    )?;
+    for relative in [
+        "src/backend/catalog/system_functions.sql",
+        "src/backend/catalog/system_views.sql",
+        "src/backend/catalog/information_schema.sql",
+        "src/backend/catalog/sql_features.txt",
+        "src/backend/libpq/pg_hba.conf.sample",
+        "src/backend/libpq/pg_ident.conf.sample",
+        "src/backend/utils/misc/postgresql.conf.sample",
+    ] {
+        let source_path = source.join(relative);
+        let file_name = source_path
+            .file_name()
+            .ok_or_else(|| anyhow!("source file has no name: {}", source_path.display()))?;
+        copy_file(&source_path, &share.join(file_name))?;
+    }
+
+    copy_file(
+        &build.join("src/backend/snowball/snowball_create.sql"),
+        &share.join("snowball_create.sql"),
+    )?;
+    copy_file(
+        &build.join("src/backend/snowball/dict_snowball.so"),
+        &lib.join("dict_snowball.so"),
+    )?;
+    copy_file(
+        &build.join("src/pl/plpgsql/src/plpgsql.so"),
+        &lib.join("plpgsql.so"),
+    )?;
+
+    let extension_dir = share.join("extension");
+    fs::create_dir_all(&extension_dir)
+        .with_context(|| format!("create {}", extension_dir.display()))?;
+    for relative in [
+        "src/pl/plpgsql/src/plpgsql.control",
+        "src/pl/plpgsql/src/plpgsql--1.0.sql",
+    ] {
+        let source_path = source.join(relative);
+        let file_name = source_path
+            .file_name()
+            .ok_or_else(|| anyhow!("source file has no name: {}", source_path.display()))?;
+        copy_file(&source_path, &extension_dir.join(file_name))?;
+    }
+
+    copy_tree_filtered(
+        &source.join("src/backend/tsearch/dicts"),
+        &share.join("tsearch_data"),
+        None,
+    )?;
+    copy_tree_filtered(
+        &source.join("src/backend/snowball/stopwords"),
+        &share.join("tsearch_data"),
+        None,
+    )?;
+    copy_tree_filtered(
+        &source.join("src/timezone/tznames"),
+        &share.join("timezonesets"),
+        Some(&["Makefile", "meson.build", "README"]),
+    )?;
+    stage_timezone_database(source, build, &share)?;
+    Ok(())
+}
+
+fn stage_timezone_database(source: &Path, build: &Path, share: &Path) -> Result<()> {
+    let tzdata = source.join("src/timezone/data/tzdata.zi");
+    ensure_file(&tzdata)?;
+    let compiled_timezone_dir = build.join("src/timezone/compiled");
+
+    let timezone_dir = share.join("timezone");
+    if timezone_dir.exists() {
+        fs::remove_dir_all(&timezone_dir)
+            .with_context(|| format!("remove {}", timezone_dir.display()))?;
+    }
+    fs::create_dir_all(&timezone_dir)
+        .with_context(|| format!("create {}", timezone_dir.display()))?;
+    copy_tree_filtered(&compiled_timezone_dir, &timezone_dir, None).with_context(|| {
+        format!(
+            "copy compiled PostgreSQL timezone database from {}",
+            compiled_timezone_dir.display()
+        )
+    })?;
+
+    for required in ["UTC", "GMT", "Etc/UTC", "America/New_York"] {
+        let path = timezone_dir.join(required);
+        if !path.is_file() {
+            bail!(
+                "compiled PostgreSQL timezone database is missing required zone {}",
+                path.display()
+            );
+        }
+    }
+    Ok(())
+}
+
+fn package_aot_artifacts(
+    target: &str,
+    outputs: &BuildOutputs,
+    sources: &SourcesManifest,
+) -> Result<()> {
+    let source_dir = outputs.product.root().join("aot-source").join(target);
+    if !source_dir.exists() {
+        let source_lane_arg = if outputs.source_lane == DEFAULT_SOURCE_LANE {
+            String::new()
+        } else {
+            format!(" --source-lane {}", outputs.source_lane)
+        };
+        bail!(
+            "AOT source directory {} is missing; run `bash src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh --target-triple {target}{source_lane_arg}` before packaging",
+            source_dir.display()
+        );
+    }
+
+    let artifacts_dir = outputs.product.root().join("aot").join(target);
+    if artifacts_dir.exists() {
+        fs::remove_dir_all(&artifacts_dir)
+            .with_context(|| format!("remove {}", artifacts_dir.display()))?;
+    }
+    fs::create_dir_all(&artifacts_dir)
+        .with_context(|| format!("create {}", artifacts_dir.display()))?;
+
+    let mut manifest_artifacts = Vec::new();
+    for module in outputs
+        .modules
+        .iter()
+        .filter(|module| module.requires_aot && outputs.product.owns(&module.name))
+    {
+        let name = module.name.as_str();
+        let file = module.aot_file.as_str();
+        let source = source_dir.join(file);
+        if !source.exists() {
+            bail!(
+                "missing AOT artifact {}; run AOT generation for target {target} before packaging",
+                source.display()
+            );
+        }
+        let destination = artifacts_dir.join(file);
+        copy_file(&source, &destination)?;
+        let raw_artifact = decode_zstd_file(&destination)
+            .with_context(|| format!("decode AOT artifact {}", destination.display()))?;
+        let module_sha256 = outputs
+            .modules
+            .iter()
+            .find(|module| module.name == name)
+            .map(|module| sha256_file(&module.path))
+            .transpose()?
+            .ok_or_else(|| anyhow!("missing build output module {name} for AOT manifest"))?;
+        manifest_artifacts.push(AotManifestArtifact {
+            name: name.to_owned(),
+            path: file.to_owned(),
+            sha256: sha256_file(&destination)?,
+            raw_sha256: sha256_bytes(&raw_artifact),
+            raw_size: raw_artifact.len() as u64,
+            module_sha256,
+            compressed: true,
+        });
+    }
+    ensure!(
+        !manifest_artifacts.is_empty(),
+        "AOT packaging produced an empty manifest for {target}"
+    );
+
+    let manifest = AotManifest {
+        format_version: AOT_MANIFEST_FORMAT_VERSION,
+        source_lane: Some(outputs.source_lane.clone()),
+        source_fingerprint: outputs.source_fingerprint.clone(),
+        postgres_version: Some(outputs.postgres_version.clone()),
+        target_triple: target.to_owned(),
+        engine: "llvm-opta".to_owned(),
+        wasmer_version: sources.toolchain.wasmer.clone(),
+        wasmer_wasix_version: sources.toolchain.wasmer_wasix.clone(),
+        artifacts: manifest_artifacts,
+    };
+    let manifest_json =
+        serde_json::to_string_pretty(&manifest).context("serialize AOT manifest")?;
+    fs::write(
+        artifacts_dir.join("manifest.json"),
+        format!("{manifest_json}\n"),
+    )
+    .with_context(|| format!("write {}", artifacts_dir.join("manifest.json").display()))?;
+    Ok(())
+}
+
+pub(crate) fn package_extension_aot_artifacts(
+    sources: &SourcesManifest,
+    target: &str,
+    source_lane: &str,
+) -> Result<()> {
+    let outputs = BuildOutputs::discover_product_for_aot(source_lane, AssetProduct::Extensions)?;
+    let source_dir = outputs.product.root().join("aot-source").join(target);
+    if !source_dir.exists() {
+        let source_lane_arg = if outputs.source_lane == DEFAULT_SOURCE_LANE {
+            String::new()
+        } else {
+            format!(" --source-lane {}", outputs.source_lane)
+        };
+        bail!(
+            "AOT source directory {} is missing; run `bash src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh --target-triple {target}{source_lane_arg}` before packaging extension AOT artifacts",
+            source_dir.display()
+        );
+    }
+
+    let target_id = aot_target_id_for_triple(target)?;
+    let artifacts_root = Path::new("target/extensions/wasix/aot-artifacts").join(target_id);
+    if artifacts_root.exists() {
+        fs::remove_dir_all(&artifacts_root)
+            .with_context(|| format!("remove {}", artifacts_root.display()))?;
+    }
+    fs::create_dir_all(&artifacts_root)
+        .with_context(|| format!("create {}", artifacts_root.display()))?;
+
+    let mut grouped: BTreeMap> = BTreeMap::new();
+    for module in outputs
+        .modules
+        .iter()
+        .filter(|module| module.requires_aot && !is_core_aot_module(&module.name))
+    {
+        let Some(sql_name) = extension_module_sql_name(&module.name) else {
+            bail!("extension AOT module has invalid name {}", module.name);
+        };
+        let source = source_dir.join(&module.aot_file);
+        if !source.exists() {
+            bail!(
+                "missing extension AOT artifact {}; run AOT generation for target {target} before packaging",
+                source.display()
+            );
+        }
+        let extension_dir = artifacts_root.join(sql_name);
+        fs::create_dir_all(&extension_dir)
+            .with_context(|| format!("create {}", extension_dir.display()))?;
+        let destination = extension_dir.join(&module.aot_file);
+        copy_file(&source, &destination)?;
+        let raw_artifact = decode_zstd_file(&destination)
+            .with_context(|| format!("decode extension AOT artifact {}", destination.display()))?;
+        grouped
+            .entry(sql_name.to_owned())
+            .or_default()
+            .push(AotManifestArtifact {
+                name: module.name.clone(),
+                path: module.aot_file.clone(),
+                sha256: sha256_file(&destination)?,
+                raw_sha256: sha256_bytes(&raw_artifact),
+                raw_size: raw_artifact.len() as u64,
+                module_sha256: sha256_file(&module.path)?,
+                compressed: true,
+            });
+    }
+
+    ensure!(
+        !grouped.is_empty(),
+        "extension AOT packaging produced no artifacts for {target}"
+    );
+
+    for (sql_name, mut artifacts) in grouped {
+        artifacts.sort_by(|left, right| left.name.cmp(&right.name));
+        let manifest = AotManifest {
+            format_version: AOT_MANIFEST_FORMAT_VERSION,
+            source_lane: Some(outputs.source_lane.clone()),
+            source_fingerprint: outputs.source_fingerprint.clone(),
+            postgres_version: Some(outputs.postgres_version.clone()),
+            target_triple: target.to_owned(),
+            engine: "llvm-opta".to_owned(),
+            wasmer_version: sources.toolchain.wasmer.clone(),
+            wasmer_wasix_version: sources.toolchain.wasmer_wasix.clone(),
+            artifacts,
+        };
+        let manifest_json =
+            serde_json::to_string_pretty(&manifest).context("serialize extension AOT manifest")?;
+        let manifest_path = artifacts_root.join(&sql_name).join("manifest.json");
+        fs::write(&manifest_path, format!("{manifest_json}\n"))
+            .with_context(|| format!("write {}", manifest_path.display()))?;
+    }
+    Ok(())
+}
+
+pub(crate) fn check_aot_package_manifest(target: &str, source_lane: &str) -> Result<()> {
+    check_aot_product_manifest(target, source_lane, AssetProduct::Runtime)
+}
+
+pub(crate) fn check_aot_product_manifest(
+    target: &str,
+    source_lane: &str,
+    product: AssetProduct,
+) -> Result<()> {
+    let sources = load_wasix_toolchain_manifest()?;
+    let outputs = BuildOutputs::discover_product_for_aot(source_lane, product)?;
+    let artifacts_dir = product.root().join("aot").join(target);
+    let manifest_path = artifacts_dir.join("manifest.json");
+    ensure_file(&manifest_path)?;
+    let text = fs::read_to_string(&manifest_path)
+        .with_context(|| format!("read {}", manifest_path.display()))?;
+    let manifest: AotManifest = serde_json::from_str(&text)
+        .with_context(|| format!("parse {}", manifest_path.display()))?;
+    ensure!(
+        manifest.format_version == AOT_MANIFEST_FORMAT_VERSION,
+        "AOT manifest format-version must be {AOT_MANIFEST_FORMAT_VERSION}, got {}",
+        manifest.format_version
+    );
+    let actual_lane = manifest.source_lane.as_deref().unwrap_or("");
+    ensure_eq(
+        actual_lane,
+        outputs.source_lane.as_str(),
+        "AOT manifest source-lane",
+    )?;
+    if let Some(source_fingerprint) = outputs.source_fingerprint.as_deref() {
+        ensure_eq(
+            manifest
+                .source_fingerprint
+                .as_deref()
+                .unwrap_or(""),
+            source_fingerprint,
+            "AOT manifest source-fingerprint",
+        )?;
+    }
+    if let Some(postgres_version) = manifest.postgres_version.as_deref() {
+        ensure_eq(
+            postgres_version,
+            outputs.postgres_version.as_str(),
+            "AOT manifest postgres-version",
+        )?;
+    }
+    ensure_eq(
+        &manifest.target_triple,
+        target,
+        "AOT manifest target-triple",
+    )?;
+    ensure_eq(&manifest.engine, "llvm-opta", "AOT manifest engine")?;
+    ensure_eq(
+        &manifest.wasmer_version,
+        &sources.toolchain.wasmer,
+        "AOT manifest wasmer-version",
+    )?;
+    ensure_eq(
+        &manifest.wasmer_wasix_version,
+        &sources.toolchain.wasmer_wasix,
+        "AOT manifest wasmer-wasix-version",
+    )?;
+    ensure!(
+        !manifest.artifacts.is_empty(),
+        "AOT manifest {} contains no artifacts",
+        manifest_path.display()
+    );
+
+    for artifact in &manifest.artifacts {
+        let artifact_relative_path = Path::new(&artifact.path);
+        ensure!(
+            artifact_relative_path.is_relative()
+                && artifact_relative_path
+                    .components()
+                    .all(|component| matches!(component, std::path::Component::Normal(_))),
+            "AOT artifact {} path must be a simple relative file path, got {}",
+            artifact.name,
+            artifact.path
+        );
+        let path = artifacts_dir.join(&artifact.path);
+        ensure_file(&path)?;
+        let actual_hash = sha256_file(&path)?;
+        ensure_eq(
+            &actual_hash,
+            &artifact.sha256,
+            &format!("AOT artifact {} sha256", artifact.name),
+        )?;
+        if artifact.compressed {
+            let raw = decode_zstd_file(&path)
+                .with_context(|| format!("decode AOT artifact {}", path.display()))?;
+            ensure_eq(
+                &sha256_bytes(&raw),
+                &artifact.raw_sha256,
+                &format!("AOT artifact {} raw sha256", artifact.name),
+            )?;
+            let actual_raw_size = raw.len() as u64;
+            if actual_raw_size != artifact.raw_size {
+                bail!(
+                    "AOT artifact {} raw size mismatch: expected {} got {}",
+                    artifact.name,
+                    artifact.raw_size,
+                    actual_raw_size
+                );
+            }
+        }
+        let module = outputs
+            .modules
+            .iter()
+            .find(|module| module.name == artifact.name)
+            .ok_or_else(|| anyhow!("AOT manifest references unknown module {}", artifact.name))?;
+        ensure!(
+            module.requires_aot,
+            "AOT manifest references non-release-AOT module {}",
+            artifact.name
+        );
+        ensure!(
+            product.owns(&artifact.name),
+            "core AOT manifest must not reference extension module {}",
+            artifact.name
+        );
+        let module_hash = sha256_file(&module.path)?;
+        ensure_eq(
+            &module_hash,
+            &artifact.module_sha256,
+            &format!("AOT artifact {} source module sha256", artifact.name),
+        )?;
+    }
+    let expected = outputs
+        .modules
+        .iter()
+        .filter(|module| module.requires_aot && outputs.product.owns(&module.name))
+        .map(|module| module.name.as_str())
+        .collect::>();
+    let actual = manifest
+        .artifacts
+        .iter()
+        .map(|artifact| artifact.name.as_str())
+        .collect::>();
+    ensure!(
+        actual == expected,
+        "AOT manifest module set mismatch: expected {expected:?} got {actual:?}"
+    );
+    let expected_files = manifest
+        .artifacts
+        .iter()
+        .map(|artifact| artifact.path.as_str())
+        .collect::>();
+    let actual_files = sorted_files(&artifacts_dir)?
+        .into_iter()
+        .map(|path| {
+            path.strip_prefix(&artifacts_dir)
+                .with_context(|| {
+                    format!("strip {} from {}", artifacts_dir.display(), path.display())
+                })
+                .and_then(|relative| {
+                    relative.to_str().map(str::to_owned).ok_or_else(|| {
+                        anyhow!("AOT artifact path is not UTF-8: {}", path.display())
+                    })
+                })
+        })
+        .collect::>>()?;
+    let mut expected_package_files = expected_files
+        .into_iter()
+        .map(str::to_owned)
+        .collect::>();
+    expected_package_files.insert("manifest.json".to_owned());
+    ensure!(
+        actual_files == expected_package_files,
+        "AOT artifact file set mismatch: expected {expected_package_files:?} got {actual_files:?}"
+    );
+    Ok(())
+}
+
+pub(crate) fn generated_aot_dir(target: &str) -> PathBuf {
+    Path::new(GENERATED_AOT_DIR).join(target)
+}
+
+fn crate_aot_artifact_dir(target: &str) -> PathBuf {
+    Path::new("src/runtimes/liboliphaunt-wasix/crates/aot")
+        .join(target)
+        .join("artifacts")
+}
+
+pub(crate) fn find_aot_artifact_dir(target: &str) -> Result {
+    find_aot_artifact_dir_for_source_lane(target, DEFAULT_SOURCE_LANE)
+}
+
+fn find_aot_artifact_dir_for_source_lane(target: &str, source_lane: &str) -> Result {
+    let generated = generated_aot_dir_for_source_lane(target, source_lane)?;
+    if generated.join("manifest.json").is_file() {
+        return Ok(generated);
+    }
+    let crate_dir = crate_aot_artifact_dir(target);
+    if crate_dir.join("manifest.json").is_file() {
+        return Ok(crate_dir);
+    }
+    bail!(
+        "missing AOT artifacts for {target}; expected {} or {}",
+        generated.display(),
+        crate_dir.display()
+    )
+}
+
+#[allow(clippy::too_many_arguments)] // Each parameter is a distinct frozen asset-manifest input.
+fn write_asset_manifest(
+    sources: &SourcesManifest,
+    outputs: &BuildOutputs,
+    assets_dir: &Path,
+    runtime_module: &Path,
+    runtime_archive: &Path,
+    pg_dump: Option<&Path>,
+    psql: Option<&Path>,
+    initdb: &Path,
+    runtime_support: &[BinaryPackage<'_>],
+    extensions: &[ExtensionArtifact<'_>],
+) -> Result<()> {
+    let runtime_link = read_wasm_link_metadata(runtime_module)?;
+    let extension_metadata = extension_catalog::manifest_metadata_by_sql_name()?;
+    let effective_sources = effective_source_pins(sources, outputs)?;
+    let manifest = AssetManifestOut {
+        format_version: ASSET_MANIFEST_FORMAT_VERSION,
+        source_lane: Some(outputs.source_lane.clone()),
+        source_fingerprint: outputs.source_fingerprint.clone(),
+        runtime: RuntimeAssetOut {
+            archive: "oliphaunt.wasix.tar.zst".to_owned(),
+            sha256: sha256_file(runtime_archive)?,
+            module_sha256: sha256_file(runtime_module)?,
+            postgres_version: outputs.postgres_version.clone(),
+            runtime_kind: "wasix-dynamic-main".to_owned(),
+            link: runtime_link.clone(),
+        },
+        runtime_support: runtime_support
+            .iter()
+            .map(|module| {
+                Ok::<_, anyhow::Error>(BinaryAssetOut {
+                    name: module.name.to_owned(),
+                    path: module.runtime_path.to_owned(),
+                    sha256: sha256_file(module.path)?,
+                    module_sha256: sha256_file(module.path)?,
+                    size: fs::metadata(module.path)
+                        .with_context(|| format!("metadata {}", module.path.display()))?
+                        .len(),
+                    link: read_wasm_link_metadata(module.path)?,
+                })
+            })
+            .collect::>>()?,
+        pg_dump: pg_dump
+            .map(|pg_dump| {
+                Ok::<_, anyhow::Error>(BinaryAssetOut {
+                    name: "pg_dump".to_owned(),
+                    path: "bin/pg_dump.wasix.wasm".to_owned(),
+                    sha256: sha256_file(pg_dump)?,
+                    module_sha256: sha256_file(pg_dump)?,
+                    size: fs::metadata(pg_dump)
+                        .with_context(|| format!("metadata {}", pg_dump.display()))?
+                        .len(),
+                    link: read_wasm_link_metadata(pg_dump)?,
+                })
+            })
+            .transpose()?,
+        psql: psql
+            .map(|psql| {
+                Ok::<_, anyhow::Error>(BinaryAssetOut {
+                    name: "psql".to_owned(),
+                    path: "bin/psql.wasix.wasm".to_owned(),
+                    sha256: sha256_file(psql)?,
+                    module_sha256: sha256_file(psql)?,
+                    size: fs::metadata(psql)
+                        .with_context(|| format!("metadata {}", psql.display()))?
+                        .len(),
+                    link: read_wasm_link_metadata(psql)?,
+                })
+            })
+            .transpose()?,
+        initdb: Some(BinaryAssetOut {
+            name: "initdb".to_owned(),
+            path: "bin/initdb.wasix.wasm".to_owned(),
+            sha256: sha256_file(initdb)?,
+            module_sha256: sha256_file(initdb)?,
+            size: fs::metadata(initdb)
+                .with_context(|| format!("metadata {}", initdb.display()))?
+                .len(),
+            link: read_wasm_link_metadata(initdb)?,
+        }),
+        extensions: extensions
+            .iter()
+            .map(|extension| {
+                let link = extension
+                    .module_path
+                    .map(read_wasm_link_metadata)
+                    .transpose()?;
+                let native_module_links = extension
+                    .native_modules
+                    .iter()
+                    .map(|module| {
+                        Ok::<_, anyhow::Error>((
+                            module.name.clone(),
+                            read_wasm_link_metadata(&module.path)?,
+                        ))
+                    })
+                    .collect::>>()?;
+                let metadata = extension_metadata.get(extension.sql_name).ok_or_else(|| {
+                    anyhow!(
+                        "extension {} is missing from generated extension catalog",
+                        extension.sql_name
+                    )
+                })?;
+                let mut core_exports_required = Vec::new();
+                let mut unresolved_imports = Vec::new();
+                if let Some(link) = &link {
+                    let primary_path = extension.module_path.ok_or_else(|| {
+                        anyhow!(
+                            "extension {} has link metadata without a module",
+                            extension.sql_name
+                        )
+                    })?;
+                    let module_exports = extension_asset_provider_exports(
+                        link,
+                        primary_path,
+                        extension.sql_name,
+                        extension.native_modules,
+                        &native_module_links,
+                    )?;
+                    for import in &link.imports {
+                        if !import_should_resolve_from_runtime(import) {
+                            continue;
+                        }
+                        if import_resolves_from_wasm_exports(
+                            import,
+                            &module_exports,
+                            extension.sql_name,
+                        )? {
+                            continue;
+                        }
+                        if let Some(name) =
+                            resolved_wasm_export_name(import, &runtime_link.exports, "runtime")?
+                        {
+                            core_exports_required.push(name);
+                        } else {
+                            unresolved_imports.push(import.clone());
+                        }
+                    }
+                }
+                core_exports_required.sort();
+                core_exports_required.dedup();
+                let installed_files = archive_file_list(extension.path)?;
+                let control_files = extension_control_files_for_asset_manifest(
+                    outputs.source_lane.as_str(),
+                    metadata,
+                    &installed_files,
+                    extension.sql_name,
+                )?;
+                let native_modules = extension
+                    .native_modules
+                    .iter()
+                    .map(|module| {
+                        let link = native_module_links
+                            .get(&module.name)
+                            .cloned()
+                            .ok_or_else(|| anyhow!("missing link metadata for {}", module.name))?;
+                        Ok::<_, anyhow::Error>(BinaryAssetOut {
+                            name: module.name.clone(),
+                            path: module.runtime_path.clone(),
+                            sha256: sha256_file(&module.path)?,
+                            module_sha256: sha256_file(&module.path)?,
+                            size: fs::metadata(&module.path)
+                                .with_context(|| format!("metadata {}", module.path.display()))?
+                                .len(),
+                            link,
+                        })
+                    })
+                    .collect::>>()?;
+                Ok(ExtensionAssetOut {
+                    name: extension.name.to_owned(),
+                    sql_name: extension.sql_name.to_owned(),
+                    source_kind: metadata.source_kind.clone(),
+                    archive: extension.archive.to_owned(),
+                    sha256: sha256_file(extension.path)?,
+                    module_sha256: extension
+                        .module_path
+                        .map(sha256_file)
+                        .transpose()?
+                        .unwrap_or_default(),
+                    native_module: extension.native_module.map(str::to_owned),
+                    native_modules,
+                    size: fs::metadata(extension.path)
+                        .with_context(|| format!("metadata {}", extension.path.display()))?
+                        .len(),
+                    control_files,
+                    dependencies: metadata.dependencies.clone(),
+                    load_order: metadata.load_order.clone(),
+                    lifecycle: ExtensionLifecycleOut {
+                        create_extension: metadata.lifecycle.create_extension,
+                        create_schema: metadata.lifecycle.create_schema.clone(),
+                        load_sql: metadata.lifecycle.load_sql.clone(),
+                        post_create_sql: metadata.lifecycle.post_create_sql.clone(),
+                        startup_config: metadata.lifecycle.startup_config.clone(),
+                        preload_required: metadata.lifecycle.preload_required,
+                        restart_required: metadata.lifecycle.restart_required,
+                        shared_memory_required: metadata.lifecycle.shared_memory_required,
+                    },
+                    extension_imports: link
+                        .as_ref()
+                        .map(|link| link.imports.clone())
+                        .unwrap_or_default(),
+                    core_exports_required,
+                    unresolved_imports,
+                    installed_files,
+                    link,
+                })
+            })
+            .collect::>>()?,
+        sources: effective_sources,
+    };
+
+    let text = serde_json::to_string_pretty(&manifest).context("serialize asset manifest")?;
+    let manifest_path = assets_dir.join("manifest.json");
+    fs::write(&manifest_path, format!("{text}\n"))
+        .with_context(|| format!("write {}", manifest_path.display()))?;
+    Ok(())
+}
+
+fn extension_control_files_for_asset_manifest(
+    source_lane: &str,
+    metadata: &extension_catalog::ManifestExtensionMetadata,
+    installed_files: &[String],
+    sql_name: &str,
+) -> Result> {
+    ensure_eq(
+        canonical_source_lane(source_lane)?,
+        DEFAULT_SOURCE_LANE,
+        "extension manifest source lane",
+    )?;
+
+    let mut control_files = installed_files
+        .iter()
+        .filter(|path| {
+            path.starts_with("share/postgresql/extension/") && path.ends_with(".control")
+        })
+        .cloned()
+        .collect::>();
+    control_files.sort();
+    control_files.dedup();
+    if metadata.lifecycle.create_extension || !metadata.control_files.is_empty() {
+        ensure!(
+            !control_files.is_empty(),
+            "PG18 extension {sql_name} manifest control-files must come from packaged extension archive contents"
+        );
+    }
+    ensure!(
+        control_files
+            .iter()
+            .all(|path| !path.contains("removed-fork")),
+        "PG18 extension {sql_name} manifest control-files must not reference removed source paths"
+    );
+    Ok(control_files)
+}
+
+#[allow(clippy::items_after_test_module)] // Later helpers are shared by production and these focused tests.
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn manifest_extension_metadata(
+        create_extension: bool,
+        control_files: Vec<&str>,
+    ) -> extension_catalog::ManifestExtensionMetadata {
+        extension_catalog::ManifestExtensionMetadata {
+            source_kind: "postgres-contrib".to_owned(),
+            control_files: control_files.into_iter().map(str::to_owned).collect(),
+            dependencies: Vec::new(),
+            load_order: Vec::new(),
+            lifecycle: extension_catalog::ManifestExtensionLifecycle {
+                create_extension,
+                create_schema: None,
+                load_sql: Vec::new(),
+                post_create_sql: Vec::new(),
+                startup_config: Vec::new(),
+                preload_required: false,
+                restart_required: false,
+                shared_memory_required: false,
+            },
+        }
+    }
+
+    #[test]
+    fn pg18_lane_uses_packaged_control_files() {
+        let metadata = manifest_extension_metadata(
+            true,
+            vec!["target/oliphaunt-sources/checkouts/removed-fork/contrib/pg_trgm/pg_trgm.control"],
+        );
+        let installed_files = vec![
+            "share/postgresql/extension/pg_trgm.control".to_owned(),
+            "share/postgresql/extension/pg_trgm--1.6.sql".to_owned(),
+            "share/postgresql/extension/pg_trgm.control".to_owned(),
+        ];
+
+        let control_files = extension_control_files_for_asset_manifest(
+            "stable",
+            &metadata,
+            &installed_files,
+            "pg_trgm",
+        )
+        .expect("PG18 packaged control files");
+
+        assert_eq!(
+            control_files,
+            vec!["share/postgresql/extension/pg_trgm.control"]
+        );
+    }
+
+    #[test]
+    fn legacy_pg17_lane_is_not_selectable_for_control_files() {
+        let metadata = manifest_extension_metadata(
+            true,
+            vec!["target/oliphaunt-sources/checkouts/removed-fork/contrib/pg_trgm/pg_trgm.control"],
+        );
+        let installed_files = vec!["share/postgresql/extension/pg_trgm.control".to_owned()];
+
+        let error = extension_control_files_for_asset_manifest(
+            "pg17",
+            &metadata,
+            &installed_files,
+            "pg_trgm",
+        )
+        .expect_err("PG17 lane must no longer be selectable");
+
+        assert!(
+            error
+                .to_string()
+                .contains("unsupported WASIX asset source lane")
+        );
+    }
+
+    #[test]
+    fn pg18_lane_requires_packaged_control_files_for_create_extension() {
+        let metadata = manifest_extension_metadata(
+            true,
+            vec!["target/oliphaunt-sources/checkouts/removed-fork/contrib/pg_trgm/pg_trgm.control"],
+        );
+        let error = extension_control_files_for_asset_manifest("stable", &metadata, &[], "pg_trgm")
+            .expect_err("PG18 missing packaged control file should fail");
+
+        assert!(
+            error
+                .to_string()
+                .contains("must come from packaged extension archive contents")
+        );
+    }
+
+    #[test]
+    fn pg18_lane_rejects_released_control_paths() {
+        let metadata = manifest_extension_metadata(true, Vec::new());
+        let installed_files =
+            vec!["share/postgresql/extension/removed-fork-leak.control".to_owned()];
+        let error = extension_control_files_for_asset_manifest(
+            "stable",
+            &metadata,
+            &installed_files,
+            "pg_trgm",
+        )
+        .expect_err("PG18 released path leak should fail");
+
+        assert!(
+            error
+                .to_string()
+                .contains("must not reference removed source paths")
+        );
+    }
+
+    fn temp_aot_manifest_path(label: &str) -> PathBuf {
+        let now = std::time::SystemTime::now()
+            .duration_since(std::time::UNIX_EPOCH)
+            .expect("system time")
+            .as_nanos();
+        std::env::temp_dir().join(format!(
+            "oliphaunt-xtask-aot-manifest-{}-{now}-{label}.json",
+            std::process::id()
+        ))
+    }
+
+    fn write_downloaded_aot_manifest(
+        path: &Path,
+        source_lane: Option<&str>,
+        source_fingerprint: Option<&str>,
+        postgres_version: Option<&str>,
+    ) {
+        let manifest = AotManifest {
+            format_version: AOT_MANIFEST_FORMAT_VERSION,
+            source_lane: source_lane.map(str::to_owned),
+            source_fingerprint: source_fingerprint.map(str::to_owned),
+            postgres_version: postgres_version.map(str::to_owned),
+            target_triple: "aarch64-apple-darwin".to_owned(),
+            engine: "llvm-opta".to_owned(),
+            wasmer_version: "7.2.1".to_owned(),
+            wasmer_wasix_version: "0.702.1".to_owned(),
+            artifacts: vec![AotManifestArtifact {
+                name: "runtime:oliphaunt".to_owned(),
+                path: "oliphaunt.aot.zst".to_owned(),
+                sha256: "archive".to_owned(),
+                raw_sha256: "raw".to_owned(),
+                raw_size: 1,
+                module_sha256: "module".to_owned(),
+                compressed: true,
+            }],
+        };
+        fs::write(
+            path,
+            serde_json::to_string(&manifest).expect("serialize AOT manifest"),
+        )
+        .expect("write AOT manifest");
+    }
+
+    #[test]
+    fn downloaded_stable_pg18_aot_manifest_is_validated_before_install() {
+        let path = temp_aot_manifest_path("pg18-ok");
+        let fingerprint = expected_postgres_source_fingerprint().expect("PG18 fingerprint");
+        write_downloaded_aot_manifest(
+            &path,
+            Some("stable"),
+            Some(&fingerprint),
+            Some("18.4-wasix-oliphaunt"),
+        );
+
+        ensure_aot_manifest_matches_source_lane(&path, "aarch64-apple-darwin", DEFAULT_SOURCE_LANE)
+            .expect("stable downloaded AOT manifest");
+
+        let _ = fs::remove_file(path);
+    }
+
+    #[test]
+    fn downloaded_stable_pg18_aot_manifest_requires_source_fingerprint() {
+        let path = temp_aot_manifest_path("pg18-missing-fingerprint");
+        write_downloaded_aot_manifest(&path, Some("stable"), None, Some("18.4-wasix-oliphaunt"));
+
+        let error = ensure_aot_manifest_matches_source_lane(
+            &path,
+            "aarch64-apple-darwin",
+            DEFAULT_SOURCE_LANE,
+        )
+        .expect_err("PG18 downloaded AOT manifest should require source fingerprint");
+
+        assert!(
+            error
+                .to_string()
+                .contains("PG18 AOT manifest source-fingerprint")
+        );
+        let _ = fs::remove_file(path);
+    }
+
+    #[test]
+    fn downloaded_stable_aot_manifest_rejects_noncanonical_format_version() {
+        let path = temp_aot_manifest_path("wrong-format-version");
+        let fingerprint = expected_postgres_source_fingerprint().expect("PG18 fingerprint");
+        write_downloaded_aot_manifest(
+            &path,
+            Some("stable"),
+            Some(&fingerprint),
+            Some("18.4-wasix-oliphaunt"),
+        );
+        let mut manifest: AotManifest =
+            serde_json::from_str(&fs::read_to_string(&path).expect("read AOT manifest"))
+                .expect("parse AOT manifest");
+        manifest.format_version = AOT_MANIFEST_FORMAT_VERSION + 1;
+        fs::write(
+            &path,
+            serde_json::to_string(&manifest).expect("serialize AOT manifest"),
+        )
+        .expect("write AOT manifest");
+
+        let error = ensure_aot_manifest_matches_source_lane(
+            &path,
+            "aarch64-apple-darwin",
+            DEFAULT_SOURCE_LANE,
+        )
+        .expect_err("downloaded AOT manifest with a noncanonical format version should fail");
+
+        assert!(
+            error.to_string().contains("AOT manifest format-version"),
+            "unexpected validation error: {error:#}"
+        );
+        let _ = fs::remove_file(path);
+    }
+
+    #[test]
+    fn downloaded_stable_aot_manifest_rejects_stale_wasmer_metadata() {
+        let path = temp_aot_manifest_path("stale-wasmer");
+        let fingerprint = expected_postgres_source_fingerprint().expect("PG18 fingerprint");
+        write_downloaded_aot_manifest(
+            &path,
+            Some("stable"),
+            Some(&fingerprint),
+            Some("18.4-wasix-oliphaunt"),
+        );
+        let mut manifest: AotManifest =
+            serde_json::from_str(&fs::read_to_string(&path).expect("read AOT manifest"))
+                .expect("parse AOT manifest");
+        manifest.wasmer_version = "7.2.1-alpha.3".to_owned();
+        manifest.wasmer_wasix_version = "0.702.1-alpha.3".to_owned();
+        fs::write(
+            &path,
+            serde_json::to_string(&manifest).expect("serialize AOT manifest"),
+        )
+        .expect("write AOT manifest");
+
+        let error = ensure_aot_manifest_matches_source_lane(
+            &path,
+            "aarch64-apple-darwin",
+            DEFAULT_SOURCE_LANE,
+        )
+        .expect_err("downloaded AOT manifest with stale Wasmer metadata should fail");
+
+        let error = format!("{error:#}");
+        assert!(
+            error.contains("AOT manifest wasmer-version"),
+            "unexpected validation error: {error}"
+        );
+        let _ = fs::remove_file(path);
+    }
+
+    fn wasm_import(module: &str, name: &str, kind: &str) -> WasmImportOut {
+        WasmImportOut {
+            module: module.to_owned(),
+            name: name.to_owned(),
+            kind: kind.to_owned(),
+        }
+    }
+
+    fn wasm_export(name: &str, kind: &str) -> WasmExportOut {
+        WasmExportOut {
+            name: name.to_owned(),
+            kind: kind.to_owned(),
+        }
+    }
+
+    #[test]
+    fn wasix_linker_provided_imports_do_not_require_runtime_exports() {
+        for import in [
+            wasm_import("env", "memory", "memory"),
+            wasm_import("env", "__indirect_function_table", "table"),
+            wasm_import("env", "__stack_pointer", "global"),
+            wasm_import("env", "__c_longjmp", "tag"),
+            wasm_import("env", "__cpp_exception", "tag"),
+            wasm_import("env", "__memory_base", "global"),
+            wasm_import("env", "__table_base", "global"),
+            wasm_import("GOT.mem", "__heap_base", "global"),
+            wasm_import("GOT.mem", "__stack_high", "global"),
+            wasm_import("GOT.mem", "__stack_low", "global"),
+        ] {
+            assert!(
+                !import_should_resolve_from_runtime(&import),
+                "{import:?} should be provided by the WASIX dynamic linker"
+            );
+        }
+    }
+
+    #[test]
+    fn single_backend_runtime_rejects_thread_creation_imports() {
+        for import in [
+            wasm_import("wasi", "thread-spawn", "func"),
+            wasm_import("wasix_32v1", "thread_spawn_v2", "func"),
+            wasm_import("env", "__pthread_create", "func"),
+        ] {
+            assert!(is_thread_spawn_import(&import), "{import:?}");
+        }
+
+        for import in [
+            wasm_import("wasix_32v1", "thread_exit", "func"),
+            wasm_import("wasix_32v1", "thread_signal", "func"),
+            wasm_import("wasix_32v1", "thread_parallelism", "func"),
+        ] {
+            assert!(!is_thread_spawn_import(&import), "{import:?}");
+        }
+    }
+
+    #[test]
+    fn side_module_exports_satisfy_their_own_dynamic_symbol_imports() {
+        let module_exports = vec![
+            wasm_export("GEOSArea_r", "func"),
+            wasm_export("_ZN10FlatGeobuf11PackedRTree4initEt", "func"),
+            wasm_export("ZN10FlatGeobuf11PackedRTree4initEt", "func"),
+        ];
+
+        for import in [
+            wasm_import("env", "GEOSArea_r", "func"),
+            wasm_import("GOT.func", "_ZN10FlatGeobuf11PackedRTree4initEt", "global"),
+            wasm_import("GOT.func", "ZN10FlatGeobuf11PackedRTree4initEt", "global"),
+        ] {
+            assert!(import_should_resolve_from_runtime(&import));
+            assert!(
+                import_resolves_from_wasm_exports(&import, &module_exports, "test module")
+                    .expect("valid typed provider"),
+                "{import:?} should be self-resolved by the linked side module"
+            );
+        }
+    }
+
+    #[test]
+    fn new_extension_imports_extend_the_sealed_runtime_policy() {
+        let runtime_import = wasm_import("env", "SearchSysCache1", "func");
+        let module_exports = vec![wasm_export("GEOSArea_r", "func")];
+
+        assert!(import_should_resolve_from_runtime(&runtime_import));
+        assert!(
+            !import_resolves_from_wasm_exports(&runtime_import, &module_exports, "test module")
+                .expect("absent export")
+        );
+        assert_eq!(
+            runtime_export_name_for_side_import(&runtime_import),
+            "SearchSysCache1"
+        );
+    }
+
+    #[test]
+    fn side_module_provider_kinds_must_match_dynamic_imports() {
+        let error = import_resolves_from_wasm_exports(
+            &wasm_import("GOT.func", "SearchSysCache1", "global"),
+            &[wasm_export("SearchSysCache1", "global")],
+            "test module",
+        )
+        .expect_err("function-address imports must resolve to functions");
+        assert!(error.to_string().contains("expected func"));
+    }
+
+    #[test]
+    fn side_module_providers_follow_declared_dynamic_dependencies() {
+        let root = WasmLinkMetadataOut {
+            dylink_needed: vec!["declared.so".to_owned()],
+            exports: vec![wasm_export("root_symbol", "func")],
+            ..Default::default()
+        };
+        let declared = WasmLinkMetadataOut {
+            exports: vec![wasm_export("declared_symbol", "func")],
+            ..Default::default()
+        };
+        let undeclared = WasmLinkMetadataOut {
+            exports: vec![wasm_export("undeclared_symbol", "func")],
+            ..Default::default()
+        };
+        let links = BTreeMap::from([
+            ("extension:test".to_owned(), root),
+            ("extension:test:declared".to_owned(), declared),
+            ("extension:test:undeclared".to_owned(), undeclared),
+        ]);
+        let basenames = BTreeMap::from([
+            ("root.so".to_owned(), "extension:test".to_owned()),
+            (
+                "declared.so".to_owned(),
+                "extension:test:declared".to_owned(),
+            ),
+            (
+                "undeclared.so".to_owned(),
+                "extension:test:undeclared".to_owned(),
+            ),
+        ]);
+
+        let exports = side_module_provider_exports("extension:test", &links, &basenames)
+            .expect("declared provider graph");
+        assert!(
+            import_resolves_from_wasm_exports(
+                &wasm_import("env", "declared_symbol", "func"),
+                &exports,
+                "test graph",
+            )
+            .expect("declared provider")
+        );
+        assert!(
+            !import_resolves_from_wasm_exports(
+                &wasm_import("env", "undeclared_symbol", "func"),
+                &exports,
+                "test graph",
+            )
+            .expect("undeclared provider")
+        );
+    }
+
+    #[test]
+    fn sealed_runtime_export_policy_requires_exact_surface() {
+        let expected = BTreeSet::from(["_start".to_owned(), "runtime_abi".to_owned()]);
+        ensure_exact_runtime_export_surface(&expected, &expected).expect("exact export surface");
+
+        let error = ensure_exact_runtime_export_surface(
+            &BTreeSet::from(["_start".to_owned(), "ambient".to_owned()]),
+            &expected,
+        )
+        .expect_err("ambient export must fail");
+        let message = error.to_string();
+        assert!(message.contains("runtime_abi"));
+        assert!(message.contains("ambient"));
+    }
+}
+
+pub(crate) fn effective_source_pins(
+    sources: &SourcesManifest,
+    outputs: &BuildOutputs,
+) -> Result> {
+    let mut pins = sources
+        .sources
+        .iter()
+        .filter(|source| !is_released_source_pin_for_pg18_manifest(source))
+        .cloned()
+        .collect::>();
+    let pg18 = load_postgres_source_manifest()?;
+    pins.push(SourcePin {
+        name: "postgresql".to_owned(),
+        kind: SourceKind::Git,
+        url: pg18.postgresql.url,
+        mirror_url: None,
+        branch: format!("v{}", pg18.postgresql.version),
+        commit: pg18.postgresql.sha256,
+        source_date_epoch: None,
+        sha256: None,
+        strip_prefix: None,
+    });
+
+    let fingerprint = if let Some(fingerprint) = outputs.source_fingerprint.as_deref() {
+        fingerprint.to_owned()
+    } else {
+        let fingerprint_path = outputs
+            .source_dir
+            .join(".oliphaunt-wasix-source-fingerprint");
+        fs::read_to_string(&fingerprint_path)
+            .with_context(|| format!("read {}", fingerprint_path.display()))?
+            .trim()
+            .to_owned()
+    };
+    let patch_fingerprint = fingerprint
+        .trim()
+        .rsplit(':')
+        .next()
+        .filter(|value| !value.is_empty())
+        .ok_or_else(|| anyhow!("PG18 source fingerprint is invalid: {fingerprint:?}"))?;
+    pins.push(SourcePin {
+        name: "oliphaunt-wasix-stable-patches".to_owned(),
+        kind: SourceKind::Git,
+        url: "src/runtimes/liboliphaunt-wasix/postgres/series".to_owned(),
+        mirror_url: None,
+        branch: "series".to_owned(),
+        commit: patch_fingerprint.to_owned(),
+        source_date_epoch: None,
+        sha256: None,
+        strip_prefix: None,
+    });
+
+    Ok(pins)
+}
+
+fn is_released_source_pin_for_pg18_manifest(source: &SourcePin) -> bool {
+    source.name.contains("removed-fork")
+        || source.branch.contains("removed-fork")
+        || source.url.contains("removed-fork")
+}
+
+pub(crate) fn load_postgres_source_manifest() -> Result {
+    let shared_path = repo_relative_path(POSTGRES_SHARED_SOURCE_MANIFEST_PATH);
+    let shared_text = fs::read_to_string(&shared_path)
+        .with_context(|| format!("read {}", shared_path.display()))?;
+    let shared: PostgresSharedSourceManifest =
+        toml::from_str(&shared_text).with_context(|| format!("parse {}", shared_path.display()))?;
+    let series = fs::read_to_string(repo_relative_path(POSTGRES_PATCH_SERIES_PATH))?;
+    let mut seen = BTreeSet::new();
+    let mut patches = Vec::new();
+    for name in series
+        .lines()
+        .map(str::trim)
+        .filter(|line| !line.is_empty() && !line.starts_with('#'))
+    {
+        ensure!(
+            name.ends_with(".patch")
+                && !Path::new(name).is_absolute()
+                && !name.contains('\\')
+                && !name.split('/').any(|part| part == "..")
+                && seen.insert(name),
+            "invalid or duplicate PostgreSQL patch: {name}"
+        );
+        patches.push(name.to_owned());
+    }
+    ensure!(!patches.is_empty(), "PostgreSQL patch series is empty");
+    Ok(PostgresSourceManifest {
+        postgresql: shared.postgresql,
+        patches,
+    })
+}
+
+pub(crate) fn repo_relative_path(path: impl AsRef) -> PathBuf {
+    let path = path.as_ref();
+    if path.is_absolute() || path.exists() {
+        return path.to_path_buf();
+    }
+    Path::new(env!("CARGO_MANIFEST_DIR"))
+        .join("../../../../..")
+        .join(path)
+}
+
+fn ensure_matching_marker(expected: &str, actual_path: &Path, field: &str) -> Result<()> {
+    let actual = fs::read_to_string(actual_path)
+        .with_context(|| format!("read {}", actual_path.display()))?;
+    ensure_eq(actual.trim(), expected, field)
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/xtask/src/extension_catalog.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/extension_catalog.rs
new file mode 100644
index 000000000..d79407c61
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/extension_catalog.rs
@@ -0,0 +1,380 @@
+use std::collections::BTreeMap;
+use std::fs;
+use std::path::Path;
+
+use anyhow::{Context, Result, anyhow, bail, ensure};
+use serde::{Deserialize, Serialize};
+
+const CATALOG_PATH: &str = "src/extensions/generated/extensions.catalog.json";
+const POSTGRES_CONTRIB: &str = "src/third-party/postgres/contrib";
+const EXTERNAL_EXTENSION_RECIPE_ROOT: &str = "src/extensions/external";
+const PGVECTOR_CHECKOUT: &str = "target/oliphaunt-sources/checkouts/pgvector";
+const EXTERNAL_EXTENSION_CHECKOUT_ROOT: &str = "target/oliphaunt-sources/checkouts";
+
+pub(crate) fn manifest_metadata_by_sql_name() -> Result>
+{
+    let catalog = read_catalog()?;
+    Ok(catalog
+        .extensions
+        .into_iter()
+        .map(|extension| {
+            (
+                extension.sql_name.clone(),
+                manifest_metadata_from_catalog_entry(extension),
+            )
+        })
+        .collect())
+}
+
+pub(crate) fn extension_build_specs() -> Result> {
+    let catalog = read_catalog()?;
+    build_specs(&catalog)
+}
+
+fn build_specs(catalog: &ExtensionCatalog) -> Result> {
+    build_specs_at(catalog, Path::new("."))
+}
+
+fn build_specs_at(
+    catalog: &ExtensionCatalog,
+    repository_root: &Path,
+) -> Result> {
+    let mut specs = Vec::new();
+    for extension in &catalog.extensions {
+        let archive = format!("extensions/{}.tar.zst", extension.sql_name);
+        let wasix_target = wasix_target_recipe_at(repository_root, &extension.sql_name)?;
+        let mut native_support_modules = wasix_target
+            .as_ref()
+            .map(|target| target.native_support_modules.clone())
+            .unwrap_or_default();
+        native_support_modules.sort_by(|left, right| left.name.cmp(&right.name));
+        let build_kind = build_kind(extension, wasix_target.as_ref())?;
+        specs.push(ExtensionBuildSpec {
+            id: extension.id.clone(),
+            display_name: extension.display_name.clone(),
+            sql_name: extension.sql_name.clone(),
+            build_kind,
+            source_dir: extension_source_dir(extension),
+            contrib_dir: (extension.source_kind == "postgres-contrib")
+                .then(|| extension_contrib_dir_name(&extension.id)),
+            module_file: extension.native_module_file.clone(),
+            archive,
+            control_file: extension.control_file.clone(),
+            native_support_modules,
+            excluded_sql_extensions: wasix_target
+                .as_ref()
+                .map(|target| target.excluded_sql_extensions.clone())
+                .unwrap_or_default(),
+            staging: wasix_target.and_then(|target| target.staging),
+            lifecycle: extension.lifecycle.clone(),
+        });
+    }
+    specs.sort_by(|left, right| left.sql_name.cmp(&right.sql_name));
+    Ok(specs)
+}
+
+#[derive(Debug, Clone)]
+pub(crate) struct ExtensionBuildSpec {
+    pub(crate) id: String,
+    pub(crate) display_name: String,
+    pub(crate) sql_name: String,
+    pub(crate) build_kind: String,
+    pub(crate) source_dir: String,
+    pub(crate) contrib_dir: Option,
+    pub(crate) module_file: Option,
+    pub(crate) archive: String,
+    pub(crate) control_file: Option,
+    pub(crate) native_support_modules: Vec,
+    pub(crate) excluded_sql_extensions: Vec,
+    pub(crate) staging: Option,
+    pub(crate) lifecycle: ExtensionLifecycle,
+}
+
+#[derive(Debug, Clone)]
+pub(crate) struct ManifestExtensionMetadata {
+    pub(crate) source_kind: String,
+    pub(crate) control_files: Vec,
+    pub(crate) dependencies: Vec,
+    pub(crate) load_order: Vec,
+    pub(crate) lifecycle: ManifestExtensionLifecycle,
+}
+
+#[derive(Debug, Clone)]
+pub(crate) struct ManifestExtensionLifecycle {
+    pub(crate) create_extension: bool,
+    pub(crate) create_schema: Option,
+    pub(crate) load_sql: Vec,
+    pub(crate) post_create_sql: Vec,
+    pub(crate) startup_config: Vec,
+    pub(crate) preload_required: bool,
+    pub(crate) restart_required: bool,
+    pub(crate) shared_memory_required: bool,
+}
+
+fn manifest_metadata_from_catalog_entry(
+    extension: ExtensionCatalogEntry,
+) -> ManifestExtensionMetadata {
+    ManifestExtensionMetadata {
+        source_kind: extension.source_kind,
+        control_files: extension.control_file.into_iter().collect(),
+        dependencies: extension.dependencies,
+        load_order: extension.load_order,
+        lifecycle: manifest_lifecycle_from_extension(extension.lifecycle),
+    }
+}
+
+fn manifest_lifecycle_from_extension(lifecycle: ExtensionLifecycle) -> ManifestExtensionLifecycle {
+    ManifestExtensionLifecycle {
+        create_extension: lifecycle.create_extension,
+        create_schema: lifecycle.create_schema,
+        load_sql: lifecycle.load_sql,
+        post_create_sql: lifecycle.post_create_sql,
+        startup_config: lifecycle.startup_config,
+        preload_required: lifecycle.preload_required,
+        restart_required: lifecycle.restart_required,
+        shared_memory_required: lifecycle.shared_memory_required,
+    }
+}
+
+fn wasix_target_recipe_at(
+    repository_root: &Path,
+    sql_name: &str,
+) -> Result> {
+    let path = repository_root
+        .join(EXTERNAL_EXTENSION_RECIPE_ROOT)
+        .join(sql_name)
+        .join("targets/wasix.toml");
+    if !path.exists() {
+        return Ok(None);
+    }
+    let text = fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?;
+    let mut recipe: ExtensionTargetRecipe =
+        toml::from_str(&text).with_context(|| format!("parse {}", path.display()))?;
+    recipe
+        .native_support_modules
+        .sort_by(|left, right| left.name.cmp(&right.name));
+    recipe.excluded_sql_extensions.sort();
+    Ok(Some(recipe))
+}
+
+pub(crate) fn is_pgxs_style_build_kind(kind: &str) -> bool {
+    matches!(kind, "pgxs-external" | "pgxs-sql-only")
+}
+
+pub(crate) fn is_recipe_staged_build_kind(kind: &str) -> bool {
+    matches!(kind, "autotools")
+}
+
+fn build_kind(
+    extension: &ExtensionCatalogEntry,
+    wasix_target: Option<&ExtensionTargetRecipe>,
+) -> Result {
+    match extension.source_kind.as_str() {
+        "postgres-contrib" => Ok("postgres-contrib".to_owned()),
+        "oliphaunt-other-extension" => {
+            let Some(kind) = wasix_target
+                .and_then(|target| target.build_kind.as_deref())
+                .filter(|kind| !kind.is_empty())
+            else {
+                return Ok("pgxs-external".to_owned());
+            };
+            ensure!(
+                is_pgxs_style_build_kind(kind),
+                "extension {} has unsupported oliphaunt-other-extension WASIX build kind {kind}",
+                extension.id
+            );
+            Ok(kind.to_owned())
+        }
+        "postgis" => {
+            let kind = wasix_target
+                .and_then(|target| target.build_kind.as_deref())
+                .ok_or_else(|| {
+                    anyhow!("extension {} has no WASIX target build_kind", extension.id)
+                })?;
+            ensure!(
+                is_recipe_staged_build_kind(kind),
+                "extension {} has unsupported recipe-staged WASIX build kind {kind}",
+                extension.id
+            );
+            Ok(kind.to_owned())
+        }
+        other => bail!(
+            "extension {} has unsupported source kind {other}",
+            extension.id
+        ),
+    }
+}
+
+fn extension_source_dir(extension: &ExtensionCatalogEntry) -> String {
+    extension_source_dir_for(&extension.id, &extension.source_kind)
+}
+
+fn extension_source_dir_for(id: &str, source_kind: &str) -> String {
+    match source_kind {
+        "postgres-contrib" => Path::new(POSTGRES_CONTRIB)
+            .join(extension_contrib_dir_name(id))
+            .to_string_lossy()
+            .replace('\\', "/"),
+        "oliphaunt-other-extension" if id == "vector" => PGVECTOR_CHECKOUT.to_owned(),
+        "oliphaunt-other-extension" | "postgis" => Path::new(EXTERNAL_EXTENSION_CHECKOUT_ROOT)
+            .join(id)
+            .to_string_lossy()
+            .replace('\\', "/"),
+        _ => String::new(),
+    }
+}
+
+fn extension_contrib_dir_name(id: &str) -> String {
+    match id {
+        "uuid_ossp" => "uuid-ossp".to_owned(),
+        other => other.to_owned(),
+    }
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+struct ExtensionCatalog {
+    format_version: u32,
+    #[serde(default)]
+    generated_from: Vec,
+    extensions: Vec,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+struct CatalogInput {
+    name: String,
+    path: String,
+}
+
+#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
+struct ExtensionTargetRecipe {
+    #[serde(default)]
+    build_kind: Option,
+    #[serde(default)]
+    required_build_files: Vec,
+    #[serde(default)]
+    required_build_globs: Vec,
+    #[serde(default)]
+    native_support_modules: Vec,
+    #[serde(default)]
+    excluded_sql_extensions: Vec,
+    #[serde(default)]
+    staging: Option,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(deny_unknown_fields)]
+pub(crate) struct NativeSupportModuleSpec {
+    pub(crate) name: String,
+    #[serde(rename = "runtime-path", alias = "runtime_path")]
+    pub(crate) runtime_path: String,
+    #[serde(rename = "build-path", alias = "build_path")]
+    pub(crate) build_path: String,
+    #[serde(rename = "aot-file", alias = "aot_file")]
+    pub(crate) aot_file: String,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(deny_unknown_fields)]
+pub(crate) struct ExtensionStagingSpec {
+    #[serde(rename = "module-source-dir", alias = "module_source_dir")]
+    pub(crate) module_source_dir: Option,
+    #[serde(rename = "control-source", alias = "control_source")]
+    pub(crate) control_source: Option,
+    #[serde(rename = "sql-source-dir", alias = "sql_source_dir")]
+    pub(crate) sql_source_dir: Option,
+    #[serde(default, rename = "data-dirs", alias = "data_dirs")]
+    pub(crate) data_dirs: Vec,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(deny_unknown_fields)]
+pub(crate) struct ExtensionStagingDataDirSpec {
+    pub(crate) source: String,
+    pub(crate) destination: String,
+}
+
+#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+struct ExtensionCatalogEntry {
+    id: String,
+    sql_name: String,
+    rust_constant: String,
+    display_name: String,
+    source_kind: String,
+    upstream_import_name: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    upstream_import_path: Option,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    package_export: Option,
+    tags: Vec,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    bundle_size: Option,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    control_file: Option,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    control: Option,
+    dependencies: Vec,
+    load_order: Vec,
+    lifecycle: ExtensionLifecycle,
+    tests: Vec,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    native_module_file: Option,
+    notes: Vec,
+}
+
+#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+struct ControlMetadata {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    default_version: Option,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    module_pathname: Option,
+    requires: Vec,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    relocatable: Option,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    schema: Option,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "kebab-case")]
+pub(crate) struct ExtensionLifecycle {
+    pub(crate) create_extension: bool,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub(crate) create_schema: Option,
+    pub(crate) load_sql: Vec,
+    pub(crate) post_create_sql: Vec,
+    pub(crate) startup_config: Vec,
+    pub(crate) preload_required: bool,
+    pub(crate) restart_required: bool,
+    pub(crate) shared_memory_required: bool,
+}
+
+fn read_catalog() -> Result {
+    let text = fs::read_to_string(CATALOG_PATH).context("read generated extension catalog")?;
+    serde_json::from_str(&text).context("parse generated extension catalog")
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn repository_catalog_resolves_external_wasix_recipes() {
+        let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../../../..");
+        let catalog: ExtensionCatalog =
+            serde_json::from_str(&fs::read_to_string(root.join(CATALOG_PATH)).unwrap()).unwrap();
+        let specs = build_specs_at(&catalog, &root).unwrap();
+        let postgis = specs.iter().find(|spec| spec.id == "postgis").unwrap();
+        assert_eq!(postgis.build_kind, "autotools");
+        assert!(postgis.staging.is_some());
+        assert!(
+            postgis
+                .native_support_modules
+                .iter()
+                .any(|module| module.name == "postgis_deps")
+        );
+    }
+}
diff --git a/tools/xtask/src/fs_utils.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/fs_utils.rs
similarity index 99%
rename from tools/xtask/src/fs_utils.rs
rename to src/runtimes/liboliphaunt-wasix/tools/xtask/src/fs_utils.rs
index f632a3459..aa6605125 100644
--- a/tools/xtask/src/fs_utils.rs
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/fs_utils.rs
@@ -163,7 +163,7 @@ fn append_tree(
             header.set_cksum();
             // Keep the path marker and the authoritative tar type flag in
             // agreement. The marker is significant to portable extractors and
-            // to src/shared/artifact-packaging/portable-archive.mjs on every host OS.
+            // to tools/packaging/portable-archive.mts on every host OS.
             let directory_archive_path = archive_path.join("");
             builder
                 .append_data(&mut header, &directory_archive_path, io::empty())
diff --git a/src/runtimes/liboliphaunt-wasix/tools/xtask/src/main.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/main.rs
new file mode 100644
index 000000000..132615a2e
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/main.rs
@@ -0,0 +1,222 @@
+use std::collections::{BTreeMap, BTreeSet};
+use std::env;
+use std::fs;
+use std::path::{Path, PathBuf};
+
+use anyhow::{Context, Result, anyhow, bail, ensure};
+use sha2::{Digest, Sha256};
+use walkdir::WalkDir;
+
+mod aot_serializer;
+mod asset_checks;
+mod asset_io;
+mod asset_manifest;
+mod asset_pipeline;
+mod extension_catalog;
+mod fs_utils;
+mod postgres_guard;
+mod source_spine;
+
+use crate::aot_serializer::aot_serializer;
+use crate::asset_checks::*;
+#[cfg(test)]
+use crate::asset_io::ensure_aot_manifest_matches_source_lane;
+use crate::asset_io::{import_downloaded_assets, install_local_assets, unpack_downloaded_archive};
+use crate::asset_manifest::*;
+use crate::asset_pipeline::*;
+use crate::fs_utils::*;
+use crate::postgres_guard::{
+    check_postgres_source_spine, check_prepared_postgres_source, postgres_default_source_dir,
+    postgres_expected_source_fingerprint,
+};
+use crate::source_spine::{
+    check_sources_manifest, load_sources_manifest, load_wasix_toolchain_manifest,
+};
+
+const WASIX_GENERATED_BUILD_DIR: &str = "target/oliphaunt-wasix/wasix-build/build";
+const WASIX_DOCKER_BUILD_DIR: &str = "target/oliphaunt-wasix/wasix-build/work/docker-oliphaunt";
+const WASIX_POSTGRES_WORK_DIR: &str = "target/oliphaunt-wasix/wasix-build";
+const WASIX_POSTGRES_GENERATED_BUILD_DIR: &str = WASIX_GENERATED_BUILD_DIR;
+const WASIX_POSTGRES_DOCKER_BUILD_DIR: &str = WASIX_DOCKER_BUILD_DIR;
+const WASIX_BUILD_MANIFEST_PATH: &str = "target/oliphaunt-wasix/wasix-build/build/outputs.json";
+const WASIX_POSTGRES_BUILD_MANIFEST_PATH: &str = WASIX_BUILD_MANIFEST_PATH;
+const POSTGRES_SHARED_SOURCE_MANIFEST_PATH: &str = "src/third-party/postgres/source.toml";
+const POSTGRES_PATCH_SERIES_PATH: &str = "src/runtimes/liboliphaunt-wasix/postgres/series";
+const POSTGRES_PREPARE_SCRIPT: &str =
+    "src/runtimes/liboliphaunt-wasix/assets/build/prepare_postgres_source.sh";
+const DEFAULT_SOURCE_LANE: &str = "stable";
+const GENERATED_ASSETS_DIR: &str = "target/oliphaunt-wasix/assets";
+const GENERATED_AOT_DIR: &str = "target/oliphaunt-wasix/aot";
+const RUNTIME_MODULE_ARCHIVE_MEMBER: &str = "oliphaunt/bin/postgres";
+const REQUIRED_RUNTIME_ABI_EXPORTS: &[&str] = &[
+    "_start",
+    "oliphaunt_wasix_set_active",
+    "oliphaunt_wasix_start",
+    "oliphaunt_wasix_get_proc_port",
+    "ProcessStartupPacket",
+    "oliphaunt_wasix_send_conn_data",
+    "oliphaunt_wasix_pq_flush",
+    "pq_buffer_remaining_data",
+    "PostgresMainLoopOnce",
+    "PostgresSendReadyForQueryIfNecessary",
+    "PostgresMainLongJmp",
+    "oliphaunt_wasix_set_force_host_error_recovery",
+    "oliphaunt_wasix_protocol_stream_active",
+    "oliphaunt_wasix_input_reset",
+    "oliphaunt_wasix_input_reserve",
+    "oliphaunt_wasix_input_commit",
+    "oliphaunt_wasix_input_available",
+    "oliphaunt_wasix_output_reset",
+    "oliphaunt_wasix_output_len",
+    "oliphaunt_wasix_output_data",
+    "oliphaunt_wasix_output_contains_error",
+    "oliphaunt_wasix_set_protocol_transport",
+];
+fn main() -> Result<()> {
+    let mut args = env::args().skip(1);
+    match args.next().as_deref() {
+        Some("assets") => assets(args.collect()),
+        Some("aot-serializer") => aot_serializer(args.collect()),
+        Some("help") | None => {
+            print_usage();
+            Ok(())
+        }
+        Some(other) => bail!("unknown xtask command: {other}"),
+    }
+}
+
+fn assets(args: Vec) -> Result<()> {
+    match args.first().map(String::as_str) {
+        Some("check") => {
+            let strict_generated = args.iter().any(|arg| arg == "--strict-generated");
+            let manifest = check_sources_manifest()?;
+            check_postgres_source_spine()?;
+
+            check_canonical_asset_layout(strict_generated)?;
+            check_generated_manifest(&manifest, strict_generated)?;
+            if strict_generated {
+                verify_asset_manifest_hashes()?;
+            }
+            Ok(())
+        }
+        Some("stage-runtime") => {
+            let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE);
+            stage_compiler_runtime(source_lane)
+        }
+        Some("import-download") => import_downloaded_assets(&args),
+        Some("unpack") => unpack_downloaded_archive(&args),
+        Some("install-local") => install_local_assets(&args),
+        Some("package") => {
+            let manifest = check_sources_manifest()?;
+            let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple());
+            let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE);
+            if args.iter().any(|arg| arg == "--skip-aot") {
+                package_assets_without_aot(&manifest, source_lane)
+            } else {
+                package_assets(&manifest, target, source_lane)
+            }
+        }
+        Some("package-tools" | "package-extensions") => {
+            let manifest = check_sources_manifest()?;
+            let product = if args.first().map(String::as_str) == Some("package-tools") {
+                AssetProduct::Tools
+            } else {
+                AssetProduct::Extensions
+            };
+            package_product_assets(&manifest, DEFAULT_SOURCE_LANE, product)
+        }
+        Some("package-aot") => {
+            let manifest = check_sources_manifest()?;
+            let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple());
+            let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE);
+            package_aot_only(
+                &manifest,
+                target,
+                source_lane,
+                AssetProduct::parse(value_after(&args, "--product").unwrap_or("runtime"))?,
+            )
+        }
+        Some("package-extension-aot") => {
+            let manifest = check_sources_manifest()?;
+            let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple());
+            let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE);
+            package_extension_aot_artifacts(&manifest, target, source_lane)
+        }
+        Some("check-aot") => {
+            let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple());
+            let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE);
+            check_aot_package_manifest(target, source_lane)
+        }
+        Some("export-list") => {
+            let write = args.iter().any(|arg| arg == "--write");
+            let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE);
+            generate_wasix_export_list(write, source_lane)
+        }
+        Some("prepare-aot") => {
+            let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple());
+            let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE);
+            prepare_aot_artifacts(
+                target,
+                source_lane,
+                AssetProduct::parse(value_after(&args, "--product").unwrap_or("runtime"))?,
+            )
+        }
+        Some(other) => bail!("unknown assets subcommand: {other}"),
+        None => {
+            bail!(
+                "usage: cargo run -p xtask -- assets "
+            )
+        }
+    }
+}
+
+fn host_target_triple() -> &'static str {
+    #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
+    {
+        return "aarch64-apple-darwin";
+    }
+    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
+    {
+        return "x86_64-unknown-linux-gnu";
+    }
+    #[cfg(all(target_os = "linux", target_arch = "aarch64"))]
+    {
+        return "aarch64-unknown-linux-gnu";
+    }
+    #[cfg(all(target_os = "windows", target_arch = "x86_64"))]
+    {
+        return "x86_64-pc-windows-msvc";
+    }
+    #[allow(unreachable_code)]
+    "unsupported"
+}
+
+fn ensure_eq(actual: &str, expected: &str, field: &str) -> Result<()> {
+    if actual != expected {
+        bail!("{field} must be '{expected}', got '{actual}'");
+    }
+    Ok(())
+}
+
+pub(crate) fn value_after<'a>(args: &'a [String], name: &str) -> Option<&'a str> {
+    args.windows(2)
+        .find(|window| window[0] == name)
+        .map(|window| window[1].as_str())
+}
+
+fn print_usage() {
+    eprintln!("usage:");
+    eprintln!("  cargo run -p xtask -- assets check [--strict-generated]");
+    eprintln!("  cargo run -p xtask -- assets stage-runtime");
+    eprintln!("  cargo run -p xtask -- assets install-local --target-triple ");
+    eprintln!(
+        "  bash src/runtimes/liboliphaunt-wasix/tools/serialize-aot.sh --target-triple "
+    );
+    eprintln!(
+        "  cargo run -p xtask --features aot-serializer -- assets package [--target-triple ] [--skip-aot]"
+    );
+    eprintln!("  cargo run -p xtask -- assets package-aot [--target-triple ]");
+    eprintln!("  cargo run -p xtask -- assets package-extension-aot [--target-triple ]");
+    eprintln!("  cargo run -p xtask -- assets check-aot [--target-triple ]");
+    eprintln!("  cargo run -p xtask -- assets export-list [--write]");
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/xtask/src/postgres_guard.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/postgres_guard.rs
new file mode 100644
index 000000000..b34eab2a9
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/postgres_guard.rs
@@ -0,0 +1,82 @@
+use super::*;
+
+pub(crate) fn check_postgres_source_spine() -> Result<()> {
+    let manifest = load_postgres_source_manifest()?;
+    let source = postgres_default_source_dir(&manifest);
+    if source.exists() {
+        check_prepared_postgres_source(&manifest, &source, Path::new(WASIX_POSTGRES_WORK_DIR))?;
+    }
+    Ok(())
+}
+
+pub(crate) fn check_prepared_postgres_source(
+    manifest: &PostgresSourceManifest,
+    source: &Path,
+    work_root: &Path,
+) -> Result<()> {
+    ensure!(
+        source.is_dir(),
+        "prepared PG18 source path is not a directory: {}",
+        source.display()
+    );
+
+    let version_path = source.join(".oliphaunt-wasix-postgres-version");
+    let version = fs::read_to_string(&version_path)
+        .with_context(|| format!("read {}", version_path.display()))?;
+    ensure_eq(
+        version.trim(),
+        manifest.postgresql.version.as_str(),
+        "prepared PG18 source version marker",
+    )?;
+    let expected_fingerprint = postgres_expected_source_fingerprint(manifest)?;
+    let source_fingerprint_path = source.join(".oliphaunt-wasix-source-fingerprint");
+    let source_fingerprint = fs::read_to_string(&source_fingerprint_path)
+        .with_context(|| format!("read {}", source_fingerprint_path.display()))?;
+    ensure_eq(
+        source_fingerprint.trim(),
+        &expected_fingerprint,
+        "prepared PG18 source fingerprint marker",
+    )?;
+    let work_fingerprint_path = work_root.join(".source-fingerprint");
+    let work_fingerprint = fs::read_to_string(&work_fingerprint_path)
+        .with_context(|| format!("read {}", work_fingerprint_path.display()))?;
+    ensure_eq(
+        work_fingerprint.trim(),
+        &expected_fingerprint,
+        "prepared PG18 work fingerprint marker",
+    )?;
+
+    Ok(())
+}
+
+pub(crate) fn postgres_default_source_dir(manifest: &PostgresSourceManifest) -> PathBuf {
+    Path::new(WASIX_POSTGRES_WORK_DIR)
+        .join("work")
+        .join(format!(
+            "postgresql-{}-oliphaunt-wasix-src",
+            manifest.postgresql.version
+        ))
+}
+
+pub(crate) fn postgres_expected_source_fingerprint(
+    manifest: &PostgresSourceManifest,
+) -> Result {
+    Ok(format!(
+        "{}:{}:{}",
+        manifest.postgresql.version,
+        manifest.postgresql.sha256,
+        postgres_patch_series_hash(&manifest.patches)?
+    ))
+}
+
+fn postgres_patch_series_hash(patches: &[String]) -> Result {
+    let mut hasher = Sha256::new();
+    let inputs = std::iter::once(repo_relative_path(POSTGRES_PATCH_SERIES_PATH))
+        .chain(patches.iter().map(repo_relative_path));
+    for path in inputs {
+        let hash = sha256_text_file_lf(&path)?;
+        hasher.update(hash.as_bytes());
+        hasher.update(b"\n");
+    }
+    Ok(format!("{:x}", hasher.finalize()))
+}
diff --git a/src/runtimes/liboliphaunt-wasix/tools/xtask/src/source_spine.rs b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/source_spine.rs
new file mode 100644
index 000000000..9d968f55b
--- /dev/null
+++ b/src/runtimes/liboliphaunt-wasix/tools/xtask/src/source_spine.rs
@@ -0,0 +1,451 @@
+use std::collections::BTreeSet;
+use std::fs;
+use std::path::{Path, PathBuf};
+
+use anyhow::{Context, Result, anyhow, bail};
+
+use super::*;
+
+pub(super) fn check_sources_manifest() -> Result {
+    let manifest = load_sources_manifest()?;
+    validate_sources_manifest(&manifest)?;
+    println!("validated {} pinned asset sources", manifest.sources.len());
+    Ok(manifest)
+}
+
+fn archive_sha256(source: &SourcePin) -> Result {
+    let sha256 = source
+        .sha256
+        .as_deref()
+        .ok_or_else(|| anyhow!("archive source '{}' is missing sha256", source.name))?;
+    ensure!(
+        sha256.len() == 64
+            && sha256
+                .chars()
+                .all(|ch| ch.is_ascii_digit() || ('a'..='f').contains(&ch)),
+        "archive source '{}' has invalid lowercase sha256 {}",
+        source.name,
+        sha256
+    );
+    Ok(sha256.to_owned())
+}
+
+fn archive_strip_prefix(source: &SourcePin) -> Result<&str> {
+    source
+        .strip_prefix
+        .as_deref()
+        .filter(|prefix| {
+            *prefix == "."
+                || (!prefix.is_empty()
+                    && !prefix.contains("..")
+                    && prefix
+                        .chars()
+                        .next()
+                        .is_some_and(|ch| ch.is_ascii_alphanumeric())
+                    && prefix.chars().all(|ch| {
+                        ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.' | '+')
+                    }))
+        })
+        .ok_or_else(|| anyhow!("archive source '{}' has invalid strip-prefix", source.name))
+}
+fn valid_source_name_component(name: &str) -> bool {
+    !name.is_empty()
+        && !name.contains("..")
+        && !name.contains('/')
+        && !name.contains('\\')
+        && name
+            .chars()
+            .all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.'))
+}
+
+fn valid_https_source_url(url: &str) -> bool {
+    let Some(rest) = url.strip_prefix("https://") else {
+        return false;
+    };
+    if rest.is_empty()
+        || rest.contains('#')
+        || rest.contains('\\')
+        || rest.chars().any(char::is_whitespace)
+    {
+        return false;
+    }
+    let authority = rest.split(['/', '?']).next().unwrap_or_default();
+    if authority.is_empty() || authority.contains('@') {
+        return false;
+    }
+    let (host, valid_port) = match authority.rsplit_once(':') {
+        Some((host, port)) => (
+            host,
+            !port.is_empty() && port.chars().all(|ch| ch.is_ascii_digit()),
+        ),
+        None => (authority, true),
+    };
+    valid_port
+        && !host.is_empty()
+        && host
+            .chars()
+            .all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '-' | '.'))
+}
+
+fn valid_git_branch_name(branch: &str) -> bool {
+    !branch.is_empty()
+        && !branch.starts_with(['-', '/'])
+        && !branch.ends_with(['/', '.'])
+        && !branch.contains("..")
+        && !branch.contains("@{")
+        && !branch.chars().any(|ch| {
+            ch.is_ascii_control()
+                || ch.is_ascii_whitespace()
+                || matches!(ch, '~' | '^' | ':' | '?' | '*' | '[' | '\\')
+        })
+        && branch
+            .split('/')
+            .all(|part| !part.is_empty() && !part.ends_with(".lock"))
+}
+
+pub(super) fn load_wasix_toolchain_manifest() -> Result {
+    let toolchain_path = Path::new(env!("CARGO_MANIFEST_DIR"))
+        .join("../../../../..")
+        .join("src/runtimes/liboliphaunt-wasix/toolchain.toml");
+    let toolchain_text = fs::read_to_string(&toolchain_path)
+        .with_context(|| format!("read {}", toolchain_path.display()))?;
+    toml::from_str(&toolchain_text).with_context(|| format!("parse {}", toolchain_path.display()))
+}
+
+pub(super) fn load_sources_manifest() -> Result {
+    let wasix = load_wasix_toolchain_manifest()?;
+
+    let mut sources = Vec::new();
+    let mut names = BTreeSet::new();
+    push_source_pin(
+        &mut sources,
+        &mut names,
+        Path::new("src/database-resources/icu/source.toml"),
+    )?;
+    let sources_root = Path::new("third-party");
+    for domain in ["icu", "openssl"] {
+        let domain_dir = sources_root.join(domain);
+        if !domain_dir.exists() {
+            continue;
+        }
+        let mut entries = fs::read_dir(&domain_dir)
+            .with_context(|| format!("read {}", domain_dir.display()))?
+            .collect::>>()
+            .with_context(|| format!("list {}", domain_dir.display()))?;
+        entries.sort_by_key(|entry| entry.path());
+        for entry in entries {
+            let path = entry.path();
+            if path.extension().and_then(|ext| ext.to_str()) != Some("toml") {
+                continue;
+            }
+            push_source_pin(&mut sources, &mut names, &path)?;
+        }
+    }
+    for path in extension_source_pin_paths()? {
+        push_source_pin(&mut sources, &mut names, &path)?;
+    }
+
+    Ok(SourcesManifest {
+        toolchain: wasix.toolchain,
+        sources,
+    })
+}
+
+pub(super) fn validate_sources_manifest(manifest: &SourcesManifest) -> Result<()> {
+    if manifest.sources.is_empty() {
+        bail!("source metadata must contain at least one source pin");
+    }
+    for source in &manifest.sources {
+        validate_source_pin(source)?;
+    }
+    Ok(())
+}
+
+fn validate_source_pin(source: &SourcePin) -> Result<()> {
+    if !valid_source_name_component(&source.name)
+        || !valid_https_source_url(&source.url)
+        || source
+            .mirror_url
+            .as_deref()
+            .is_some_and(|url| !valid_https_source_url(url))
+        || !valid_git_branch_name(&source.branch)
+    {
+        bail!("invalid source pin in source metadata: {source:?}");
+    }
+    if source
+        .source_date_epoch
+        .is_some_and(|epoch| epoch == 0 || epoch > 253_402_300_799)
+    {
+        bail!(
+            "source '{}' source_date_epoch must be within the portable UTC range 1..=253402300799",
+            source.name
+        );
+    }
+    if source.name == "postgis" && source.source_date_epoch.is_none() {
+        bail!("PostGIS source metadata must pin source_date_epoch");
+    }
+    match source.kind {
+        SourceKind::Git => {
+            if source.commit.len() != 40
+                || !source
+                    .commit
+                    .chars()
+                    .all(|ch| ch.is_ascii_digit() || ('a'..='f').contains(&ch))
+            {
+                bail!(
+                    "git source '{}' must pin an exact lowercase 40-hex commit",
+                    source.name
+                );
+            }
+            if source.sha256.is_some() || source.strip_prefix.is_some() {
+                bail!(
+                    "git source '{}' must not set sha256 or strip-prefix",
+                    source.name
+                );
+            }
+            if source.mirror_url.as_deref() == Some(source.url.as_str()) {
+                bail!(
+                    "git source '{}' mirror URL must differ from its primary URL",
+                    source.name
+                );
+            }
+        }
+        SourceKind::Archive => {
+            if source.mirror_url.as_deref() == Some(source.url.as_str()) {
+                bail!(
+                    "archive source '{}' mirror URL must differ from its primary URL",
+                    source.name
+                );
+            }
+            let sha256 = archive_sha256(source)?;
+            archive_strip_prefix(source)?;
+            ensure_eq(
+                &source.commit,
+                &sha256,
+                &format!("{} archive commit must equal archive sha256", source.name),
+            )?;
+            let url_path = source.url.split('?').next().unwrap_or_default();
+            if !url_path.ends_with(".tar.gz")
+                && !url_path.ends_with(".tgz")
+                && !url_path.ends_with(".zip")
+            {
+                bail!(
+                    "archive source '{}' must point at a .tar.gz, .tgz, or .zip URL",
+                    source.name
+                );
+            }
+            if source.strip_prefix.as_deref() == Some(".") && !url_path.ends_with(".zip") {
+                bail!(
+                    "archive source '{}' may use a rootless strip prefix only for ZIP releases",
+                    source.name
+                );
+            }
+        }
+    }
+    Ok(())
+}
+
+fn extension_source_pin_paths() -> Result> {
+    let root = Path::new("src/extensions/external");
+    if !root.exists() {
+        return Ok(Vec::new());
+    }
+    let mut paths = Vec::new();
+    collect_extension_source_pin_paths(root, &mut paths)?;
+    paths.sort();
+    Ok(paths)
+}
+
+fn collect_extension_source_pin_paths(dir: &Path, paths: &mut Vec) -> Result<()> {
+    let mut entries = fs::read_dir(dir)
+        .with_context(|| format!("read {}", dir.display()))?
+        .collect::>>()
+        .with_context(|| format!("list {}", dir.display()))?;
+    entries.sort_by_key(|entry| entry.path());
+    for entry in entries {
+        let path = entry.path();
+        if path.is_dir() {
+            collect_extension_source_pin_paths(&path, paths)?;
+        } else if path.file_name().and_then(|name| name.to_str()) == Some("source.toml") {
+            paths.push(path);
+        }
+    }
+    Ok(())
+}
+
+fn push_source_pin(
+    sources: &mut Vec,
+    names: &mut BTreeSet,
+    path: &Path,
+) -> Result<()> {
+    let text = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?;
+    let source: SourcePin =
+        toml::from_str(&text).with_context(|| format!("parse {}", path.display()))?;
+    if !names.insert(source.name.clone()) {
+        bail!("duplicate source pin '{}' in source metadata", source.name);
+    }
+    sources.push(source);
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{valid_git_branch_name, valid_https_source_url, validate_source_pin};
+    use crate::{SourceKind, SourcePin};
+
+    fn git_source(mirror_url: Option<&str>) -> SourcePin {
+        SourcePin {
+            name: "libxml2".to_owned(),
+            kind: SourceKind::Git,
+            url: "https://gitlab.gnome.org/GNOME/libxml2.git".to_owned(),
+            mirror_url: mirror_url.map(str::to_owned),
+            branch: "v2.14.6".to_owned(),
+            commit: "d23960a130c5bb82779c9405fbbf85e65fb3c57c".to_owned(),
+            source_date_epoch: None,
+            sha256: None,
+            strip_prefix: None,
+        }
+    }
+
+    #[test]
+    fn source_transport_and_branch_validation_reject_unsafe_inputs() {
+        assert!(valid_https_source_url(
+            "https://github.com/example/source.git"
+        ));
+        assert!(valid_https_source_url(
+            "https://example.test:8443/source.tgz?mirror=1"
+        ));
+        for url in [
+            "http://github.com/example/source.git",
+            "ssh://git@github.com/example/source.git",
+            "https://user:secret@example.test/source.git",
+            "https://example.test/source.git#mutable",
+            "https://example.test\\source.git",
+        ] {
+            assert!(!valid_https_source_url(url), "unexpectedly accepted {url}");
+        }
+
+        assert!(valid_git_branch_name("oliphaunt/pinned-source"));
+        for branch in ["", "-force", "../main", "main.lock", "main~1", "bad name"] {
+            assert!(
+                !valid_git_branch_name(branch),
+                "unexpectedly accepted {branch}"
+            );
+        }
+    }
+
+    #[test]
+    fn git_source_mirror_must_be_a_distinct_canonical_https_url() {
+        validate_source_pin(&git_source(Some("https://github.com/GNOME/libxml2.git")))
+            .expect("valid HTTPS mirror");
+
+        for mirror_url in [
+            "http://github.com/GNOME/libxml2.git",
+            "https://user:secret@github.com/GNOME/libxml2.git",
+            "https://github.com/GNOME/libxml2.git#mutable",
+        ] {
+            let error = validate_source_pin(&git_source(Some(mirror_url)))
+                .expect_err("unsafe mirror URL must fail");
+            assert!(
+                error.to_string().contains("invalid source pin"),
+                "unexpected error for {mirror_url}: {error:#}"
+            );
+        }
+
+        let primary = "https://gitlab.gnome.org/GNOME/libxml2.git";
+        let error = validate_source_pin(&git_source(Some(primary)))
+            .expect_err("primary URL reused as mirror must fail");
+        assert!(
+            error
+                .to_string()
+                .contains("mirror URL must differ from its primary URL"),
+            "unexpected error: {error:#}"
+        );
+    }
+
+    #[test]
+    fn postgis_requires_one_portable_source_date_epoch() {
+        let mut source = git_source(None);
+        source.name = "postgis".to_owned();
+        source.url = "https://github.com/postgis/postgis.git".to_owned();
+        source.branch = "3.6.3".to_owned();
+        source.commit = "3d12666588a84b23a3147618eaa9b40b0fe5e796".to_owned();
+
+        let error = validate_source_pin(&source).expect_err("missing epoch must fail");
+        assert!(
+            error
+                .to_string()
+                .contains("PostGIS source metadata must pin source_date_epoch"),
+            "unexpected error: {error:#}"
+        );
+
+        for invalid_epoch in [0, 253_402_300_800] {
+            source.source_date_epoch = Some(invalid_epoch);
+            let error = validate_source_pin(&source).expect_err("invalid epoch must fail");
+            assert!(
+                error
+                    .to_string()
+                    .contains("source_date_epoch must be within the portable UTC range"),
+                "unexpected error for {invalid_epoch}: {error:#}"
+            );
+        }
+
+        source.source_date_epoch = Some(1_776_193_981);
+        validate_source_pin(&source).expect("canonical PostGIS epoch must pass");
+    }
+
+    #[test]
+    fn archive_sources_allow_distinct_https_mirrors_with_the_same_pin() {
+        let sha256 = "88dd96a8c0464eca144fc791ae60cd31cd8ee78321e67397e25fc095c4a19aa6";
+        let mut source = SourcePin {
+            name: "libiconv".to_owned(),
+            kind: SourceKind::Archive,
+            url: "https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz".to_owned(),
+            mirror_url: Some("https://example.test/libiconv-1.19.tar.gz".to_owned()),
+            branch: "1.19".to_owned(),
+            commit: sha256.to_owned(),
+            source_date_epoch: None,
+            sha256: Some(sha256.to_owned()),
+            strip_prefix: Some("libiconv-1.19".to_owned()),
+        };
+
+        validate_source_pin(&source).expect("pinned HTTPS archive mirror must pass");
+        for mirror in [
+            source.url.clone(),
+            "http://example.test/archive.tar.gz".to_owned(),
+        ] {
+            source.mirror_url = Some(mirror);
+            assert!(validate_source_pin(&source).is_err());
+        }
+        source.mirror_url = Some("https://example.test/archive.tar.gz".to_owned());
+        source.sha256 = Some("0".repeat(64));
+        assert!(validate_source_pin(&source).is_err());
+    }
+
+    #[test]
+    fn rootless_zip_release_is_a_valid_pinned_archive_source() {
+        let sha256 = "8577bb036a5c08204b1622a85485b92cdfaea521c251d22fd36899e99e426d9a";
+        let mut source = SourcePin {
+            name: "icu-data".to_owned(),
+            kind: SourceKind::Archive,
+            url: "https://github.com/unicode-org/icu/releases/download/release-76-1/icu4c-76_1-data-bin-l.zip".to_owned(),
+            mirror_url: None,
+            branch: "release-76-1".to_owned(),
+            commit: sha256.to_owned(),
+            source_date_epoch: None,
+            sha256: Some(sha256.to_owned()),
+            strip_prefix: Some(".".to_owned()),
+        };
+        validate_source_pin(&source).expect("pinned rootless ZIP release must pass");
+
+        source.url = "https://example.test/icu-data.tar.gz".to_owned();
+        let error = validate_source_pin(&source)
+            .expect_err("rootless tar releases must remain unsupported");
+        assert!(
+            error
+                .to_string()
+                .contains("rootless strip prefix only for ZIP releases"),
+            "unexpected error: {error:#}"
+        );
+    }
+}
diff --git a/src/runtimes/liboliphaunt/icu/Cargo.toml b/src/runtimes/liboliphaunt/icu/Cargo.toml
deleted file mode 100644
index f8d4c7f6a..000000000
--- a/src/runtimes/liboliphaunt/icu/Cargo.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-[package]
-name = "oliphaunt-icu"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Optional ICU data files for Oliphaunt runtimes."
-readme = "README.md"
-repository = "https://github.com/f0rr0/oliphaunt"
-homepage = "https://oliphaunt.dev"
-documentation = "https://docs.rs/oliphaunt-icu"
-license = "MIT AND Unicode-3.0"
-links = "oliphaunt_artifact_oliphaunt_icu"
-build = "build.rs"
-include = [
-  "Cargo.toml",
-  "README.md",
-  "build.rs",
-  "src/**",
-  "payload/**",
-  "LICENSE",
-  "THIRD_PARTY_NOTICES.md",
-  "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
-  "THIRD_PARTY_LICENSES/ICU-LICENSE",
-]
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-sha2 = "0.10"
-tar = "0.4"
-zstd = { version = "0.13", default-features = false }
diff --git a/src/runtimes/liboliphaunt/icu/build.rs b/src/runtimes/liboliphaunt/icu/build.rs
deleted file mode 100644
index 84b515488..000000000
--- a/src/runtimes/liboliphaunt/icu/build.rs
+++ /dev/null
@@ -1,346 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Component, Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "oliphaunt-icu";
-const ARTIFACT_KIND: &str = "icu-data";
-const ARTIFACT_TARGET: &str = "portable";
-const PACKAGED_ICU_ARCHIVE: &str = "payload/icu-data.tar.zst";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_ICU_DATA_DIR");
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD");
-
-    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"));
-    let out = out_dir.join("generated_icu.rs");
-    if let Some(archive) = find_packaged_icu_archive() {
-        println!("cargo:rerun-if-changed={}", archive.display());
-        let extracted_root = unpack_icu_archive(&archive, &out_dir.join("icu-data-expanded"));
-        emit_icu_artifact(&out, &out_dir, &archive, &extracted_root);
-    } else if let Some(icu_root) = find_icu_data_root() {
-        emit_rerun_directives(&icu_root);
-        let archive = out_dir.join("icu-data.tar.zst");
-        write_icu_archive(&icu_root, &archive);
-        emit_icu_artifact(&out, &out_dir, &archive, &icu_root);
-    } else {
-        if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-            panic!(
-                "release packaging requires package-local ICU data under payload/icu-data.tar.zst or payload/share/icu"
-            );
-        }
-        write_generated_icu(&out, None);
-    }
-}
-
-fn emit_icu_artifact(out: &Path, out_dir: &Path, archive: &Path, icu_root: &Path) {
-    let archive_sha256 = sha256_file(archive).expect("digest ICU data archive");
-    let data_tree_sha256 = logical_tree_sha256(icu_root).expect("digest ICU logical data tree");
-    write_generated_icu(out, Some((archive, &archive_sha256, &data_tree_sha256)));
-    emit_artifact_manifest(out_dir, icu_root, &data_tree_sha256);
-}
-
-fn find_packaged_icu_archive() -> Option {
-    let manifest_dir =
-        PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set"));
-    let archive = manifest_dir.join(PACKAGED_ICU_ARCHIVE);
-    archive.is_file().then_some(archive)
-}
-
-fn find_icu_data_root() -> Option {
-    let manifest_dir =
-        PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set"));
-    for candidate in icu_candidates(&manifest_dir) {
-        if let Some(root) = canonical_icu_data_root(&candidate) {
-            return Some(root);
-        }
-    }
-    None
-}
-
-fn icu_candidates(manifest_dir: &Path) -> Vec {
-    let mut candidates = Vec::new();
-    candidates.push(manifest_dir.join("payload/share/icu"));
-    if let Some(path) = env::var_os("OLIPHAUNT_ICU_DATA_DIR") {
-        candidates.push(PathBuf::from(path));
-    }
-    candidates
-}
-
-fn unpack_icu_archive(archive: &Path, destination: &Path) -> PathBuf {
-    if destination.exists() {
-        fs::remove_dir_all(destination).expect("remove previously unpacked ICU data archive");
-    }
-    fs::create_dir_all(destination).expect("create ICU data archive destination");
-    let file = fs::File::open(archive).expect("open packaged ICU data archive");
-    let decoder = zstd::stream::read::Decoder::new(file).expect("decode packaged ICU data archive");
-    let mut archive_reader = tar::Archive::new(decoder);
-    let entries = archive_reader
-        .entries()
-        .expect("read packaged ICU data archive entries");
-    let mut entry_count = 0_usize;
-    for entry in entries {
-        entry_count += 1;
-        assert!(
-            entry_count <= 8192,
-            "packaged ICU data archive has too many entries"
-        );
-        let mut entry = entry.expect("read packaged ICU data archive entry");
-        let path = entry
-            .path()
-            .expect("read packaged ICU data archive entry path")
-            .into_owned();
-        let relative = icu_archive_relative_path(&path);
-        let destination_path = destination.join(&relative);
-        let entry_type = entry.header().entry_type();
-        if entry_type.is_dir() {
-            fs::create_dir_all(&destination_path).expect("create ICU data archive directory");
-            continue;
-        }
-        if !entry_type.is_file() {
-            panic!(
-                "packaged ICU data archive entry {} has unsupported type {:?}",
-                path.display(),
-                entry_type
-            );
-        }
-        if let Some(parent) = destination_path.parent() {
-            fs::create_dir_all(parent).expect("create ICU data archive entry parent");
-        }
-        entry
-            .unpack(&destination_path)
-            .expect("unpack packaged ICU data archive entry");
-    }
-    let root = destination.join("share/icu");
-    canonical_icu_data_root(&root).expect("packaged ICU data archive contains share/icu data")
-}
-
-fn icu_archive_relative_path(path: &Path) -> PathBuf {
-    let mut relative = PathBuf::new();
-    let mut components = Vec::new();
-    for component in path.components() {
-        match component {
-            Component::CurDir => {}
-            Component::Normal(part) => {
-                relative.push(part);
-                components.push(part.to_owned());
-            }
-            _ => panic!("unsafe packaged ICU data archive entry {}", path.display()),
-        }
-    }
-    let under_share_icu = components.first().and_then(|part| part.to_str()) == Some("share")
-        && components.get(1).and_then(|part| part.to_str()) == Some("icu");
-    if !under_share_icu {
-        panic!(
-            "packaged ICU data archive entry {} must stay under share/icu",
-            path.display()
-        );
-    }
-    relative
-}
-
-fn canonical_icu_data_root(candidate: &Path) -> Option {
-    if icu_root_contains_data(candidate) {
-        return Some(candidate.to_path_buf());
-    }
-    let entries = fs::read_dir(candidate).ok()?;
-    let mut dirs = entries
-        .filter_map(Result::ok)
-        .map(|entry| entry.path())
-        .filter(|path| path.is_dir())
-        .collect::>();
-    dirs.sort();
-    dirs.into_iter().find(|path| icu_root_contains_data(path))
-}
-
-fn icu_root_contains_data(root: &Path) -> bool {
-    let Ok(entries) = fs::read_dir(root) else {
-        return false;
-    };
-    for entry in entries.flatten() {
-        let path = entry.path();
-        let name = entry.file_name().to_string_lossy().into_owned();
-        if path.is_file() && name.starts_with("icudt") && name.ends_with(".dat") {
-            return true;
-        }
-        if path.is_dir() && name.starts_with("icudt") && directory_has_file(&path) {
-            return true;
-        }
-    }
-    false
-}
-
-fn directory_has_file(path: &Path) -> bool {
-    fs::read_dir(path)
-        .ok()
-        .into_iter()
-        .flatten()
-        .flatten()
-        .any(|entry| entry.path().is_file())
-}
-
-fn emit_rerun_directives(root: &Path) {
-    println!("cargo:rerun-if-changed={}", root.display());
-    for path in collect_files(root).expect("collect ICU data files for rerun tracking") {
-        println!("cargo:rerun-if-changed={}", path.display());
-    }
-}
-
-fn write_icu_archive(icu_root: &Path, archive: &Path) {
-    let file = fs::File::create(archive).expect("create ICU data archive");
-    let encoder = zstd::stream::write::Encoder::new(file, 19).expect("create zstd encoder");
-    let mut builder = tar::Builder::new(encoder);
-    for source in collect_files(icu_root).expect("collect ICU data files") {
-        let relative = source
-            .strip_prefix(icu_root)
-            .expect("ICU file stays under ICU root");
-        let archive_path = Path::new("share/icu").join(relative);
-        let bytes = fs::read(&source).expect("read ICU data file");
-        let mut header = tar::Header::new_gnu();
-        header.set_size(bytes.len() as u64);
-        header.set_mode(0o644);
-        header.set_uid(0);
-        header.set_gid(0);
-        header.set_mtime(0);
-        header.set_cksum();
-        builder
-            .append_data(&mut header, &archive_path, bytes.as_slice())
-            .expect("append ICU data file");
-    }
-    let encoder = builder.into_inner().expect("finish ICU tar archive");
-    encoder.finish().expect("finish ICU zstd archive");
-}
-
-fn write_generated_icu(out: &Path, archive: Option<(&Path, &str, &str)>) {
-    let text = match archive {
-        Some((archive, archive_sha256, data_tree_sha256)) => format!(
-            "pub const HAS_ICU_DATA: bool = true;\n\
-             pub const ICU_DATA_ARCHIVE_SHA256: Option<&str> = Some({archive_sha256:?});\n\
-             pub const ICU_DATA_TREE_SHA256: Option<&str> = Some({data_tree_sha256:?});\n\
-             pub fn icu_data_archive() -> Option<&'static [u8]> {{ Some(include_bytes!({archive:?})) }}\n",
-            archive = archive.to_string_lossy(),
-        ),
-        None => "pub const HAS_ICU_DATA: bool = false;\n\
-                 pub const ICU_DATA_ARCHIVE_SHA256: Option<&str> = None;\n\
-                 pub const ICU_DATA_TREE_SHA256: Option<&str> = None;\n\
-                 pub fn icu_data_archive() -> Option<&'static [u8]> { None }\n"
-            .to_owned(),
-    };
-    fs::write(out, text).expect("write generated ICU data module");
-}
-
-fn emit_artifact_manifest(out_dir: &Path, icu_root: &Path, data_tree_sha256: &str) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let files = collect_files(icu_root).expect("collect ICU data files for manifest");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {ARTIFACT_TARGET:?}\ndata_tree_sha256 = {data_tree_sha256:?}\ndata_version = \"76.1\"\ndata_form = \"files-le\"\n"
-    );
-    for file in files {
-        let relative = file
-            .strip_prefix(icu_root)
-            .expect("ICU file stays under ICU root")
-            .to_string_lossy()
-            .replace('\\', "/");
-        let sha256 = sha256_file(&file).expect("hash ICU data file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            format!("share/icu/{relative}"),
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write ICU Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn collect_files(root: &Path) -> io::Result> {
-    let mut files = Vec::new();
-    collect_files_inner(root, &mut files)?;
-    let mut files = files
-        .into_iter()
-        .map(|file| {
-            let relative = file
-                .strip_prefix(root)
-                .expect("ICU file stays under ICU root")
-                .to_str()
-                .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "ICU path is not UTF-8"))?
-                .replace('\\', "/");
-            Ok((relative, file))
-        })
-        .collect::>>()?;
-    files.sort_by(|left, right| left.0.as_bytes().cmp(right.0.as_bytes()));
-    Ok(files.into_iter().map(|(_, file)| file).collect())
-}
-
-fn collect_files_inner(path: &Path, files: &mut Vec) -> io::Result<()> {
-    if !path.is_dir() {
-        return Ok(());
-    }
-    for entry in fs::read_dir(path)? {
-        let entry = entry?;
-        let path = entry.path();
-        let metadata = fs::symlink_metadata(&path)?;
-        if metadata.file_type().is_symlink() {
-            return Err(io::Error::new(
-                io::ErrorKind::InvalidData,
-                format!("ICU data must not contain symlinks: {}", path.display()),
-            ));
-        }
-        if metadata.is_dir() {
-            collect_files_inner(&path, files)?;
-        } else if metadata.is_file() {
-            files.push(path);
-        } else {
-            return Err(io::Error::new(
-                io::ErrorKind::InvalidData,
-                format!("ICU data contains an unsupported entry: {}", path.display()),
-            ));
-        }
-    }
-    Ok(())
-}
-
-fn logical_tree_sha256(root: &Path) -> io::Result {
-    let files = collect_files(root)?;
-    if files.is_empty() {
-        return Err(io::Error::new(
-            io::ErrorKind::InvalidData,
-            "ICU data tree is empty",
-        ));
-    }
-    let mut digest = Sha256::new();
-    for file in files {
-        let relative = file
-            .strip_prefix(root)
-            .expect("ICU file stays below logical root")
-            .to_str()
-            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "ICU path is not UTF-8"))?
-            .replace('\\', "/");
-        let bytes = fs::read(&file)?;
-        digest.update(relative.as_bytes());
-        digest.update([0]);
-        digest.update(bytes.len().to_string().as_bytes());
-        digest.update([0]);
-        digest.update(bytes);
-        digest.update([b'\n']);
-    }
-    Ok(format!("{:x}", digest.finalize()))
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0_u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/native/CHANGELOG.md b/src/runtimes/liboliphaunt/native/CHANGELOG.md
deleted file mode 100644
index 3474dff5d..000000000
--- a/src/runtimes/liboliphaunt/native/CHANGELOG.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# Changelog
-
-## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-native-v0.1.1...liboliphaunt-native-v0.2.0) (2026-09-05)
-
-
-### ⚠ BREAKING CHANGES
-
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
-
-### Features
-
-* **contrib:** shared contrib carrier source: simplify releases and make contrib runtime-owned (#127) (c45082dc)
-* **contrib:** shared contrib carrier source: unify native and WASIX runtimes and SDKs (#129) (fae2bd7b)
-* **contrib:** shared contrib carrier source: model independent product dependencies (#173) (2d5f90c8)
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))
-* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
-
-
-### Code Refactoring
-
-* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
-* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
-
-## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-native-v0.1.0...liboliphaunt-native-v0.1.1) (2026-08-08)
-
-
-### Bug Fixes
-
-* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))
-
-## 0.1.0 (2026-07-28)
-
-
-### Features
-
-* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/runtimes/liboliphaunt/native/README.md b/src/runtimes/liboliphaunt/native/README.md
deleted file mode 100644
index 998ac1c6e..000000000
--- a/src/runtimes/liboliphaunt/native/README.md
+++ /dev/null
@@ -1,238 +0,0 @@
-# liboliphaunt
-
-`liboliphaunt` is the native C boundary for embedded PostgreSQL. It owns the
-PostgreSQL 18 source pin, upstreamable patch stack, C ABI header, native shim,
-and local smoke/build scripts.
-
-This directory is intentionally not an app SDK. Rust, Swift, Kotlin, desktop
-TypeScript, and React Native bind to this C ABI instead of reaching into
-PostgreSQL internals.
-
-## Layout
-
-- `include/oliphaunt.h`: public C ABI.
-- `src/liboliphaunt_native.c`: direct-mode lifecycle, backend thread ownership,
-  and non-query public ABI entrypoints.
-- `src/liboliphaunt_error.c`: synchronized shared errors plus nested,
-  operation-local error attribution for binding-safe copies.
-- `src/liboliphaunt_runtime.c`: embedded backend argv/default-GUC construction
-  and backend thread stack sizing policy.
-- `src/liboliphaunt_protocol.c`: raw protocol execution, streaming backpressure,
-  readiness scanning, and embedded backend read/write callbacks.
-- `src/liboliphaunt_config.c`: configuration copying, PostgreSQL executable
-  resolution, and startup argument copying.
-- `src/liboliphaunt_process.c`: process-wide direct-mode instance guard and
-  desktop dynamic-extension symbol-scope promotion.
-- `src/liboliphaunt_static_extensions.c`: process-wide static extension registry
-  used by mobile-style builds that link extension modules into the app binary.
-- `src/liboliphaunt_trace.c`: low-overhead protocol timing counters.
-- `src/liboliphaunt_backup_state.c`: physical-backup phase validation and
-  one-attempt failure cleanup.
-- `src/liboliphaunt_archive.c`: backup/restore lifecycle over the C ABI.
-- `src/liboliphaunt_archive_tar.c`: private ustar read/write implementation for
-  same-version physical archives.
-- `src/liboliphaunt_fs.c`: private filesystem/path helpers shared by archive and
-  restore code.
-- `src/liboliphaunt_internal.h`: private helpers shared between C translation
-  units; not part of the public ABI.
-- `patches/postgresql-18.4/`: minimal PostgreSQL patch stack.
-- `postgres18/source.toml`: pinned PostgreSQL source manifest.
-- `postgres18/external-extensions.toml`: pinned external PG18 extension
-  candidate manifest for pgrx-backed extensions such as pgGraph and ParadeDB
-  `pg_search`.
-- `bin/build-postgres18-macos.sh`: macOS build harness.
-- `bin/check-external-extension-pins.sh`: no-network source-pin checker for
-  external extension candidates.
-- `bin/build-external-pgrx-extensions-macos.sh`: opt-in pgrx artifact harness
-  for SDK-known external extension candidates, producing both normal server modules and
-  liboliphaunt-linked embedded modules.
-- `tools/run-host-c-smoke.mjs --abi-only`: consumer-style C ABI check that
-  includes only `oliphaunt.h`, links the public dylib, and verifies stable
-  constants, structs, exported symbols, and safe global calls.
-- `bin/smoke-host-happy-path.sh`: host C ABI smoke harness for macOS, Linux,
-  and Windows.
-
-## Build
-
-```sh
-src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh
-```
-
-The default output root is `target/liboliphaunt-pg18`. Use `OLIPHAUNT_*` for runtime and build controls. `LIBOLIPHAUNT_PATH` is reserved
-for the literal C library artifact path.
-
-The direct build produces PostgreSQL runtime artifacts without optional
-extension artifacts by default. Set `OLIPHAUNT_BUILD_EXTENSIONS=1` only when
-refreshing or validating exact extension artifacts; the
-`extension-artifacts-native:build-target` sets that flag when building extension artifacts.
-
-External pgrx extensions are not folded into the first-party extension build by
-default. Their source pins live in
-`src/runtimes/liboliphaunt/native/postgres18/external-extensions.toml`; the native validation wrapper
-runs `src/runtimes/liboliphaunt/native/bin/check-external-extension-pins.sh` without network access and
-verifies any local checkout that exists under `target/oliphaunt-sources/checkouts`. Use
-`src/runtimes/liboliphaunt/native/bin/check-external-extension-pins.sh --online` when intentionally
-refreshing the pins against upstream refs.
-
-Build the opt-in pgrx artifacts with:
-
-```sh
-src/runtimes/liboliphaunt/native/bin/build-external-pgrx-extensions-macos.sh --fetch
-src/runtimes/liboliphaunt/native/bin/build-external-pgrx-extensions-macos.sh
-```
-
-`--fetch` never changes a durable checkout in place. It fetches only the exact
-manifest commit over credential-free HTTPS into a unique sibling stage, with a
-wall-clock deadline, low-speed cutoff, shallow/no-submodule transport, and
-per-extension source-size bound. A small bounded retry budget uses linear
-backoff and a newly initialized stage for every attempt; retries always request
-the immutable commit, never its mutable provenance ref. Git object integrity,
-the detached `HEAD`, and the clean worktree are verified before a
-same-filesystem rename. A failed or interrupted promotion restores the prior
-clean checkout. Any tracked, staged, or untracked local state makes fetch fail
-without network access or mutation; `OLIPHAUNT_EXTERNAL_PGRX_ALLOW_DIRTY=1`
-permits local build experiments but does not authorize source replacement.
-
-The harness requires the manifest-pinned `cargo-pgrx` version and automatically
-uses `target/liboliphaunt-tools/bin/cargo-pgrx` when it exists. It packages each
-selected extension once for the normal PostgreSQL server module path and once
-with linker flags that bind PostgreSQL symbols to `@rpath/liboliphaunt.dylib` for
-direct/broker embedded loading. Use
-`OLIPHAUNT_EXTERNAL_PGRX_EXTENSIONS=pggraph` or
-`OLIPHAUNT_EXTERNAL_PGRX_EXTENSIONS=paradedb-pg-search` to restrict the build.
-The ParadeDB lane is intentionally disk-guarded because `pg_search` pulls a
-large DataFusion/Tantivy release build; free target space first, or set
-`OLIPHAUNT_EXTERNAL_PGRX_SKIP_DISK_PREFLIGHT=1` only for local experiments.
-Run `src/runtimes/liboliphaunt/native/bin/build-external-pgrx-extensions-macos.sh --check-current`
-for the no-build freshness gate.
-The build-input digest excludes harness prose and other non-build text.
-When only the digest schema changes, use `--refresh-current-stamps` to
-validate the existing normal/embedded payloads and restamp them without running
-the expensive pgrx packaging step.
-
-`OLIPHAUNT_STARTUP_TIMEOUT_MS` bounds only initial backend startup readiness.
-Normal `oliphaunt_exec_protocol`, `oliphaunt_exec_simple_query`, and streaming
-execution do not impose a synthetic query timeout; callers should use
-`oliphaunt_cancel` to interrupt long-running SQL. Ordinary SDK close is a
-lifecycle detach/wait boundary, not an implicit query cancellation primitive.
-
-Hosts serialize ordinary non-cancel calls on one logical C handle;
-`oliphaunt_cancel` is the cross-thread exception. Streaming callbacks borrow
-each byte chunk only for the callback invocation. They may copy it, inspect an
-error, or cancel, but same-handle query, backup, detach, close, and nested stream
-calls fail busy until streaming drains to `ReadyForQuery`. This guard applies
-while the callback lock is released as well, preventing callback reentrancy or a
-concurrent close from corrupting protocol state or freeing the active handle.
-
-FFI schedulers that resume on a different thread use the ABI 10 `_with_error`
-variants with one caller-owned `OliphauntErrorCapture` per invocation. The
-worker fills that fixed-layout capture before its handle lease ends; synchronous
-callers may continue copying the operation-local error immediately with
-`oliphaunt_copy_last_error`.
-
-The C runtime keeps throughput-oriented PostgreSQL defaults for direct callers:
-`shared_buffers=128MB`, `wal_buffers=4MB`, and `min_wal_size=80MB`. SDKs that
-need different PostgreSQL settings do not need a new C ABI; they pass validated
-`-c name=value` startup arguments through `OliphauntConfig.startup_args`. Later
-arguments win, so SDKs and benchmark harnesses can apply concrete PostgreSQL
-GUC overrides above the stable C boundary without inventing tuning profiles.
-
-SDKs must hydrate PGDATA from a packaged cluster seed before calling
-`oliphaunt_init`; the C boundary never runs `initdb` or initializes an empty
-root. `tools/run-host-c-smoke.mjs` performs that preparation explicitly before
-running the C consumer and includes a fast iOS simulator syntax
-check over the liboliphaunt C shim files. `bin/check-postgres18-ios-simulator.sh`
-then validates the upstream PostgreSQL patch touchpoints that matter for the
-embedded path: host I/O callbacks, the embedded backend entrypoint, lifecycle
-cleanup, static extension lookup, and shell-command exclusion on Apple mobile
-SDKs.
-`bin/build-postgres18-ios-simulator.sh` is the fast simulator artifact lane for
-Expo/RN and Swift validation. `bin/build-postgres18-ios-device.sh` builds the
-matching `IOS` device slice, and `bin/build-ios-xcframework.sh` packages both
-validated dylibs with public headers as
-`target/liboliphaunt-ios-xcframework/out/liboliphaunt.xcframework`. Each lane
-cross-builds the patched PostgreSQL backend object graph, tolerates the final
-PostgreSQL executable/tool link failure after the embedded objects exist,
-links target-specific static ICU code for PostgreSQL collation support, stages
-ICU data into the optional ICU package sidecar instead of the base runtime
-install, validates the exported C ABI symbols, and reuses the result through
-stamped ccache-friendly paths.
-
-## Static Extension Registry
-
-Mobile-style packages cannot rely on PostgreSQL dynamically loading every
-extension module from the app bundle. `oliphaunt_register_static_extensions`
-registers statically linked modules before `oliphaunt_init`, and the PostgreSQL
-`dfmgr` patch resolves those entries through the same normal `CREATE
-EXTENSION`/`LOAD` path that dynamic modules use. The registry is process-wide,
-validates extension names, magic functions, symbol names, duplicate symbols,
-and ABI versions, and becomes immutable at backend startup.
-
-The runtime-resource `--mobile-static-module ` flag is only release
-metadata. It must match modules that the platform package actually links and
-registers through this C ABI before opening the database.
-
-The macOS arm64, iOS simulator, iOS device, and Android build lanes also emit
-per-extension static archives beside the generated object lists:
-`out/extensions//liboliphaunt_extension_.a`. Those archives are the
-release artifact boundary for exact mobile extension selection; SDK packaging
-can link only the archives for the extensions an app requested instead of
-shipping one bundled extension set or rebuilding extension source in the app.
-`bin/build-ios-extension-xcframeworks.sh` packages selected macOS arm64, iOS
-simulator arm64, and iOS device arm64 archives into per-extension and
-per-dependency XCFrameworks for Apple SDK and Xcode consumers without rebuilding
-extension sources. Packaging rejects any such XCFramework that lacks one of
-those three claimed slices.
-
-## Root Ownership
-
-Direct init and restore each take one non-blocking sibling lease for the target
-root by default. The Rust SDK acquires the byte-identical sibling lease while
-preparing direct, broker, and server roots, then passes
-`OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK` for direct init so the C runtime does not
-try to acquire the same lease twice. Other C ABI consumers leave the flag clear
-and rely on the C runtime. The flag is only an ownership handoff; callers must
-already hold the stable lease for the full native handle lifetime.
-Detached reopens of a resident runtime must repeat the same root-lock ownership
-mode; changing the flag is rejected rather than silently changing who protects
-the live root.
-
-`oliphaunt_init` only validates an existing managed root. It requires the exact
-five-field `/.oliphaunt.json`, a real `/pgdata` directory,
-PostgreSQL 18 `PG_VERSION`, nonempty `global/pg_control`, and a real `pg_wal`
-directory. Exact native and WASIX descriptor tuples are accepted; unknown,
-missing, duplicated, or mismatched fields and other PGDATA leaf names are
-rejected without changing the root. SDK initialization creates PGDATA first and
-publishes the descriptor last.
-
-## Physical Archive Contract
-
-`oliphaunt_backup` emits one PostgreSQL 18 physical archive format with no
-format switch or generated-file hook. Every archive contains the exact
-five-key `.oliphaunt/backup-manifest.properties`; restore requires and consumes
-that manifest. The destination-owned `.oliphaunt.json` is not archive content,
-and restore publishes only to a new or existing-empty destination. The C ABI
-accepts only regular
-files and directories under `pgdata`; symlinks, hardlinks, device nodes, FIFOs,
-sockets, sparse/special tar records, external tablespaces, and linked WAL
-directories are rejected. `oliphaunt_restore` enforces the same rule before
-consuming archive metadata and publishing a restored root, so Swift, Kotlin,
-React Native, and Rust SDK callers inherit one portable archive contract instead
-of platform-specific tar behavior.
-
-## Fast Native Iteration
-
-Run the narrow product boundary instead of a workspace-wide track wrapper:
-
-```sh
-moon run liboliphaunt-native:host-smoke
-moon run oliphaunt-rust:regression
-moon run extension-artifacts-native:build-target oliphaunt-rust:extension-regression
-```
-
-`liboliphaunt-native:host-smoke` is the no-build host C ABI smoke for the current platform.
-It reuses the release-runtime artifact produced for macOS, Linux, or Windows
-and fails if that artifact is missing or stale. The Rust regression checks direct,
-broker, and server behavior; the separate extension pair checks packaged extension behavior.
-See [`docs/maintainers/sdk-parity-policy.md`](../../../../docs/maintainers/sdk-parity-policy.md)
-for the SDK ownership contract.
diff --git a/src/runtimes/liboliphaunt/native/THIRD_PARTY_NOTICES.md b/src/runtimes/liboliphaunt/native/THIRD_PARTY_NOTICES.md
deleted file mode 100644
index d63649bc1..000000000
--- a/src/runtimes/liboliphaunt/native/THIRD_PARTY_NOTICES.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# liboliphaunt Third-Party Notices
-
-`liboliphaunt` ships native embedded PostgreSQL runtime artifacts, selected SQL
-extensions, and supporting runtime resources.
-
-The PostgreSQL runtime is derived from PostgreSQL 18 source pinned under
-`src/postgres/versions/18/` and built with the native patch stack owned by
-`src/runtimes/liboliphaunt/native/`. Selected runtime and extension carriers
-also embed ICU 76.1 and OpenSSL 3.5.6.
-
-Every carrier that embeds these components includes their exact pinned license
-bytes under `THIRD_PARTY_LICENSES/`:
-
-- `PostgreSQL-COPYRIGHT` — PostgreSQL 18.4, source SHA-256
-  `81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094`.
-- `ICU-LICENSE` — ICU commit `8eca245c7484ac6cc179e3e5f7c1ea7680810f39`.
-- `OpenSSL-LICENSE.txt` — OpenSSL commit
-  `286ddeaac037533bbdce65b3c689e3f7ffebf0f6`.
-
-Third-party source pins for optional external extensions and supporting native
-libraries are maintained in `src/sources/third-party/`. Exact SQL extension selection is
-modeled in `src/extensions/`; release artifacts must include only the extension
-artifacts explicitly selected by the application developer.
diff --git a/src/runtimes/liboliphaunt/native/bin/build-external-pgrx-extensions-macos.sh b/src/runtimes/liboliphaunt/native/bin/build-external-pgrx-extensions-macos.sh
deleted file mode 100755
index 31a165e75..000000000
--- a/src/runtimes/liboliphaunt/native/bin/build-external-pgrx-extensions-macos.sh
+++ /dev/null
@@ -1,605 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-. "$script_dir/common.sh"
-repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
-macos_deployment_target="${MACOSX_DEPLOYMENT_TARGET:-11.0}"
-case "$macos_deployment_target" in
-  ""|*[!0-9.]*)
-    echo "MACOSX_DEPLOYMENT_TARGET must be a numeric dotted version" >&2
-    exit 2
-    ;;
-esac
-export MACOSX_DEPLOYMENT_TARGET="$macos_deployment_target"
-work_root="${OLIPHAUNT_WORK_ROOT:-$repo_root/target/liboliphaunt-pg18}"
-repo_tools_bin="$repo_root/target/liboliphaunt-tools/bin"
-install_dir="$work_root/install"
-out_dir="$work_root/out"
-lib_out="$out_dir/liboliphaunt.dylib"
-embedded_modules_dir="$out_dir/modules"
-package_root="$work_root/external-pgrx/packages"
-target_root="$work_root/external-pgrx/target"
-source_stage_root="$work_root/external-pgrx/sources"
-pgrx_home="${PGRX_HOME:-$work_root/external-pgrx/pgrx-home}"
-stamp_root="$out_dir/external-pgrx"
-script_mode="${1:-build}"
-selected_extensions="${OLIPHAUNT_EXTERNAL_PGRX_EXTENSIONS:-all}"
-build_fingerprint_schema="liboliphaunt-external-pgrx-build-v3"
-pinned_git_fetcher="$script_dir/fetch-pinned-git-checkout.sh"
-
-if [ -x "$repo_tools_bin/cargo-pgrx" ]; then
-  case ":$PATH:" in
-    *":$repo_tools_bin:"*) ;;
-    *) export PATH="$repo_tools_bin:$PATH" ;;
-  esac
-fi
-
-ids=(pggraph paradedb-pg-search)
-sql_names=(graph pg_search)
-module_stems=(graph pg_search)
-repos=(
-  https://github.com/evokoa/pggraph.git
-  https://github.com/paradedb/paradedb.git
-)
-refs=(HEAD refs/tags/v0.23.4)
-commits=(
-  4ea3c3206811deda03de136b4f465a2cf9bc8e72
-  c07921a78f3d24cbb0251b31a1150a7db600af5a
-)
-checkouts=(
-  "$repo_root/target/oliphaunt-sources/checkouts/pggraph"
-  "$repo_root/target/oliphaunt-sources/checkouts/paradedb"
-)
-source_subdirs=(graph pg_search)
-pgrx_versions=(0.18.0 0.18.0)
-pg_features=(pg18 pg18)
-min_free_kib=(2097152 12582912)
-max_checkout_kib=(524288 4194304)
-
-usage() {
-  cat >&2 <<'MSG'
-usage: src/runtimes/liboliphaunt/native/bin/build-external-pgrx-extensions-macos.sh [build|--fetch|--check-current|--refresh-current-stamps|--print-required-artifacts]
-
-Environment:
-  OLIPHAUNT_EXTERNAL_PGRX_EXTENSIONS=all|pggraph,paradedb-pg-search
-  OLIPHAUNT_EXTERNAL_PGRX_SKIP_DISK_PREFLIGHT=1 to bypass disk checks
-  OLIPHAUNT_EXTERNAL_PGRX_FETCH_TIMEOUT_SECONDS=300 bounds each exact-commit fetch
-  OLIPHAUNT_EXTERNAL_PGRX_FETCH_ATTEMPTS=3 sets the bounded attempt count (maximum 4)
-  OLIPHAUNT_EXTERNAL_PGRX_FETCH_RETRY_DELAY_SECONDS=2 sets linear backoff (maximum 5)
-
-The build mode requires cargo-pgrx. The default fast native validation does not
-run this expensive lane; it is the opt-in artifact builder for SDK-known pgrx
-extensions.
-MSG
-}
-
-run() {
-  printf '\n==> %s\n' "$*"
-  "$@"
-}
-
-require_command() {
-  if ! command -v "$1" >/dev/null 2>&1; then
-    echo "missing required command for external pgrx extension build: $1" >&2
-    exit 1
-  fi
-}
-
-available_kib_for_path() {
-  local path="$1"
-  mkdir -p "$path"
-  df -Pk "$path" | awk 'NR == 2 { print $4 }'
-}
-
-format_gib_from_kib() {
-  awk -v kib="$1" 'BEGIN { printf "%.1f GiB", kib / 1048576 }'
-}
-
-require_free_space_for_candidate() {
-  local index="$1"
-  [ "${OLIPHAUNT_EXTERNAL_PGRX_SKIP_DISK_PREFLIGHT:-0}" = "1" ] && return 0
-
-  local required="${min_free_kib[$index]}"
-  local available
-  available="$(available_kib_for_path "$work_root")"
-  if [ -z "$available" ] || [ "$available" -lt "$required" ]; then
-    echo "external pgrx build for ${ids[$index]} needs at least $(format_gib_from_kib "$required") free under $work_root; available: $(format_gib_from_kib "${available:-0}")" >&2
-    echo "free disk space or set OLIPHAUNT_EXTERNAL_PGRX_SKIP_DISK_PREFLIGHT=1 for a local experiment" >&2
-    exit 1
-  fi
-}
-
-candidate_selected() {
-  local id="$1"
-  local raw="$selected_extensions"
-  [ "$raw" = "all" ] && return 0
-  IFS=',' read -r -a selected <<< "$raw"
-  local candidate
-  for candidate in "${selected[@]}"; do
-    candidate="${candidate#"${candidate%%[![:space:]]*}"}"
-    candidate="${candidate%"${candidate##*[![:space:]]}"}"
-    if [ "$candidate" = "$id" ]; then
-      return 0
-    fi
-  done
-  return 1
-}
-
-selected_indices() {
-  local index
-  for index in "${!ids[@]}"; do
-    if candidate_selected "${ids[$index]}"; then
-      printf '%s\n' "$index"
-    fi
-  done
-}
-
-assert_known_selection() {
-  [ "$selected_extensions" = "all" ] && return 0
-  IFS=',' read -r -a selected <<< "$selected_extensions"
-  local candidate
-  for candidate in "${selected[@]}"; do
-    candidate="${candidate#"${candidate%%[![:space:]]*}"}"
-    candidate="${candidate%"${candidate##*[![:space:]]}"}"
-    [ -n "$candidate" ] || continue
-    local found=0
-    local id
-    for id in "${ids[@]}"; do
-      if [ "$candidate" = "$id" ]; then
-        found=1
-      fi
-    done
-    if [ "$found" -eq 0 ]; then
-      echo "unknown external pgrx extension selection: $candidate" >&2
-      exit 2
-    fi
-  done
-}
-
-module_depends_on_liboliphaunt() {
-  local module="$1"
-  [ -f "$module" ] || return 1
-  case "$(otool -L "$module" 2>/dev/null || true)" in
-    *"@rpath/liboliphaunt.dylib"*) return 0 ;;
-    *) return 1 ;;
-  esac
-}
-
-module_has_postgres_symbols_bound_to_liboliphaunt() {
-  local module="$1"
-  nm -m "$module" 2>/dev/null |
-    awk 'index($0, "(from liboliphaunt)") { found = 1 } END { exit found ? 0 : 1 }'
-}
-
-normal_pgrx_rustflags() {
-  printf '%s -C link-arg=-Wl,-undefined,dynamic_lookup' "${RUSTFLAGS:-}"
-}
-
-embedded_pgrx_rustflags() {
-  printf '%s -C link-arg=-L%s -C link-arg=-loliphaunt -C link-arg=-Wl,-rpath,%s' \
-    "${RUSTFLAGS:-}" "$out_dir" "$out_dir"
-}
-
-checkout_clean_or_allowed() {
-  local checkout="$1"
-  [ "${OLIPHAUNT_EXTERNAL_PGRX_ALLOW_DIRTY:-0}" = "1" ] && return 0
-  if [ -n "$(git -C "$checkout" status --porcelain)" ]; then
-    echo "external extension checkout has local changes: $checkout" >&2
-    echo "set OLIPHAUNT_EXTERNAL_PGRX_ALLOW_DIRTY=1 only for local experiments" >&2
-    exit 1
-  fi
-}
-
-fetch_candidate() {
-  local index="$1"
-  local id="${ids[$index]}"
-  local checkout="${checkouts[$index]}"
-  local repo="${repos[$index]}"
-  local ref="${refs[$index]}"
-  local commit="${commits[$index]}"
-
-  run "$pinned_git_fetcher" \
-    "$id" \
-    "$repo" \
-    "$ref" \
-    "$commit" \
-    "$checkout" \
-    "${max_checkout_kib[$index]}"
-  echo "external pgrx checkout ready for $id at $commit"
-}
-
-fingerprint_source_state() {
-  local root="$1"
-  printf 'checkout_head=%s\n' "$(git -C "$root" rev-parse HEAD)"
-  if [ -n "$(git -C "$root" status --porcelain=v1)" ]; then
-    printf 'checkout_dirty=1\n'
-    git -C "$root" status --porcelain=v1 | LC_ALL=C sort | sed 's/^/checkout_status=/'
-    git -C "$root" diff --binary HEAD -- | shasum -a 256 | awk '{ print "checkout_diff_sha256=" $1 }'
-  else
-    printf 'checkout_dirty=0\n'
-  fi
-}
-
-prepare_source_stage() {
-  local index="$1"
-  local id="${ids[$index]}"
-  local checkout="${checkouts[$index]}"
-  local source_subdir="${source_subdirs[$index]}"
-  local stage="$source_stage_root/$id"
-
-  rm -rf "$stage"
-  mkdir -p "$stage"
-  rsync -a \
-    --exclude .git \
-    --exclude target \
-    --exclude .pgrx \
-    "$checkout/" "$stage/"
-  if [ ! -f "$stage/Cargo.toml" ]; then
-    cat > "$stage/Cargo.toml" < "$tmp"
-  shasum -a 256 "$tmp" | awk '{print $1}' > "$stamp"
-  mv "$tmp" "$inputs"
-}
-
-find_one_packaged_file() {
-  local root="$1"
-  local name="$2"
-  find "$root" -type f -name "$name" -print | LC_ALL=C sort | head -n 1
-}
-
-copy_sql_assets() {
-  local package_dir="$1"
-  local sql_name="$2"
-  local target="$install_dir/share/postgresql/extension"
-  mkdir -p "$target"
-
-  local control
-  control="$(find_one_packaged_file "$package_dir" "$sql_name.control")"
-  if [ -z "$control" ]; then
-    echo "pgrx package did not produce $sql_name.control under $package_dir" >&2
-    exit 1
-  fi
-  cp -p "$control" "$target/$sql_name.control"
-
-  local copied=0
-  while IFS= read -r sql_file; do
-    [ -n "$sql_file" ] || continue
-    cp -p "$sql_file" "$target/$(basename "$sql_file")"
-    copied=$((copied + 1))
-  done < <(find "$package_dir" -type f -name "$sql_name--*.sql" -print | LC_ALL=C sort)
-  if [ "$copied" -eq 0 ]; then
-    echo "pgrx package did not produce any $sql_name--*.sql files under $package_dir" >&2
-    exit 1
-  fi
-}
-
-find_packaged_module() {
-  local package_dir="$1"
-  local module_stem="$2"
-  local module
-  module="$(find_one_packaged_file "$package_dir" "$module_stem.dylib")"
-  if [ -n "$module" ]; then
-    printf '%s\n' "$module"
-    return 0
-  fi
-  module="$(find_one_packaged_file "$package_dir" "lib$module_stem.dylib")"
-  if [ -n "$module" ]; then
-    printf '%s\n' "$module"
-    return 0
-  fi
-  return 1
-}
-
-copy_module_asset() {
-  local package_dir="$1"
-  local module_stem="$2"
-  local target="$3"
-  local module
-  if ! module="$(find_packaged_module "$package_dir" "$module_stem")"; then
-    echo "pgrx package did not produce module $module_stem.dylib under $package_dir" >&2
-    exit 1
-  fi
-  mkdir -p "$(dirname "$target")"
-  cp -p "$module" "$target"
-}
-
-artifact_payload_ready() {
-  local index="$1"
-  local sql_name="${sql_names[$index]}"
-  local module_stem="${module_stems[$index]}"
-
-  [ -f "$install_dir/share/postgresql/extension/$sql_name.control" ] || return 1
-  compgen -G "$install_dir/share/postgresql/extension/$sql_name--*.sql" >/dev/null || return 1
-  [ -f "$install_dir/lib/postgresql/$module_stem.dylib" ] || return 1
-  [ -f "$embedded_modules_dir/$module_stem.dylib" ] || return 1
-  module_depends_on_liboliphaunt "$install_dir/lib/postgresql/$module_stem.dylib" && return 1
-  module_depends_on_liboliphaunt "$embedded_modules_dir/$module_stem.dylib" || return 1
-  module_has_postgres_symbols_bound_to_liboliphaunt "$embedded_modules_dir/$module_stem.dylib" || return 1
-}
-
-artifact_ready() {
-  local index="$1"
-  local id="${ids[$index]}"
-  local stamp
-  stamp="$(artifact_stamp "$id")"
-
-  artifact_payload_ready "$index" || return 1
-  [ -f "$stamp" ] || return 1
-  [ "$(cat "$stamp")" = "$(build_fingerprint "$index")" ] || return 1
-}
-
-refresh_candidate_stamp() {
-  local index="$1"
-  local id="${ids[$index]}"
-  if ! artifact_payload_ready "$index"; then
-    echo "external pgrx payload artifacts are missing or invalid for $id; rebuild before refreshing stamps" >&2
-    exit 1
-  fi
-  write_artifact_stamp "$index"
-  echo "external pgrx stamp refreshed for $id"
-}
-
-require_core_runtime() {
-  if ! "$repo_root/src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh" --check-oliphaunt-current >/dev/null; then
-    echo "native liboliphaunt core runtime is missing or stale; refreshing core runtime first"
-    OLIPHAUNT_BUILD_EXTENSIONS=0 "$repo_root/src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh"
-  fi
-  [ -x "$install_dir/bin/pg_config" ] || {
-    echo "native PostgreSQL install is missing pg_config at $install_dir/bin/pg_config" >&2
-    exit 1
-  }
-}
-
-require_pgrx_toolchain() {
-  require_command cargo
-  require_command rustc
-  require_command rsync
-  export PGRX_HOME="$pgrx_home"
-  cargo pgrx --version >/dev/null 2>&1 || {
-    cat >&2 <<'MSG'
-missing cargo-pgrx. Install the version declared in
-src/runtimes/liboliphaunt/native/postgres18/external-extensions.toml, for example:
-
-  cargo install --locked cargo-pgrx --version 0.18.0 --root target/liboliphaunt-tools
-MSG
-    exit 1
-  }
-}
-
-ensure_pgrx_home() {
-  export PGRX_HOME="$pgrx_home"
-  mkdir -p "$PGRX_HOME"
-  if [ ! -f "$PGRX_HOME/config.toml" ] ||
-    ! grep -q "$install_dir/bin/pg_config" "$PGRX_HOME/config.toml"; then
-    run cargo pgrx init --pg18 "$install_dir/bin/pg_config"
-  fi
-}
-
-verify_pgrx_version() {
-  local expected="$1"
-  local actual
-  actual="$(cargo pgrx --version | awk '{print $2}')"
-  if [ "$actual" != "$expected" ]; then
-    echo "cargo-pgrx version mismatch: expected $expected, got $actual" >&2
-    exit 1
-  fi
-}
-
-build_candidate() {
-  local index="$1"
-  local id="${ids[$index]}"
-  local checkout="${checkouts[$index]}"
-  local source_dir
-  local sql_name="${sql_names[$index]}"
-  local module_stem="${module_stems[$index]}"
-  local feature="${pg_features[$index]}"
-  local pgrx_version="${pgrx_versions[$index]}"
-  local normal_package="$package_root/$id/normal"
-  local embedded_package="$package_root/$id/embedded"
-  local normal_target="$target_root/$id/normal"
-  local embedded_target="$target_root/$id/embedded"
-  local stamp
-  stamp="$(artifact_stamp "$id")"
-
-  [ -d "$checkout/.git" ] || {
-    echo "external pgrx checkout is missing for $id: $checkout" >&2
-    echo "run: src/runtimes/liboliphaunt/native/bin/build-external-pgrx-extensions-macos.sh --fetch" >&2
-    exit 1
-  }
-  checkout_clean_or_allowed "$checkout"
-  if [ "$(git -C "$checkout" rev-parse HEAD)" != "${commits[$index]}" ]; then
-    echo "external pgrx checkout for $id is not at pinned commit ${commits[$index]}" >&2
-    exit 1
-  fi
-  [ -f "$checkout/${source_subdirs[$index]}/Cargo.toml" ] || {
-    echo "external pgrx source for $id is missing Cargo.toml at $checkout/${source_subdirs[$index]}" >&2
-    exit 1
-  }
-
-  verify_pgrx_version "$pgrx_version"
-  local desired_hash
-  desired_hash="$(build_fingerprint "$index")"
-  if [ "${OLIPHAUNT_FORCE_EXTERNAL_PGRX_REBUILD:-0}" != "1" ] &&
-    [ -f "$stamp" ] &&
-    [ "$(cat "$stamp")" = "$desired_hash" ] &&
-    artifact_ready "$index"; then
-    echo "reusing external pgrx artifacts for $id"
-    return
-  fi
-
-  require_free_space_for_candidate "$index"
-  rm -rf "$normal_package" "$embedded_package"
-  mkdir -p "$normal_package" "$embedded_package" "$normal_target" "$embedded_target" "$stamp_root"
-  source_dir="$(prepare_source_stage "$index")"
-
-  run env CARGO_TARGET_DIR="$normal_target" \
-    RUSTFLAGS="$(normal_pgrx_rustflags)" \
-    cargo pgrx package \
-      --manifest-path "$source_dir/Cargo.toml" \
-      --pg-config "$install_dir/bin/pg_config" \
-      --out-dir "$normal_package" \
-      --no-default-features \
-      --features "$feature"
-
-  copy_sql_assets "$normal_package" "$sql_name"
-  copy_module_asset "$normal_package" "$module_stem" "$install_dir/lib/postgresql/$module_stem.dylib"
-  if module_depends_on_liboliphaunt "$install_dir/lib/postgresql/$module_stem.dylib"; then
-    echo "normal server module for $id unexpectedly links against liboliphaunt" >&2
-    exit 1
-  fi
-
-  run env CARGO_TARGET_DIR="$embedded_target" \
-    RUSTFLAGS="$(embedded_pgrx_rustflags)" \
-    cargo pgrx package \
-      --manifest-path "$source_dir/Cargo.toml" \
-      --pg-config "$install_dir/bin/pg_config" \
-      --out-dir "$embedded_package" \
-      --no-default-features \
-      --features "$feature"
-
-  copy_module_asset "$embedded_package" "$module_stem" "$embedded_modules_dir/$module_stem.dylib"
-  if ! module_depends_on_liboliphaunt "$embedded_modules_dir/$module_stem.dylib"; then
-    echo "embedded module for $id is not linked against @rpath/liboliphaunt.dylib" >&2
-    exit 1
-  fi
-  if ! module_has_postgres_symbols_bound_to_liboliphaunt "$embedded_modules_dir/$module_stem.dylib"; then
-    echo "embedded module for $id does not bind PostgreSQL symbols to liboliphaunt" >&2
-    exit 1
-  fi
-
-  write_artifact_stamp "$index"
-  artifact_ready "$index" || {
-    echo "external pgrx artifact validation failed for $id after build" >&2
-    exit 1
-  }
-}
-
-assert_manifest_and_pins() {
-  run "$repo_root/src/runtimes/liboliphaunt/native/bin/check-external-extension-pins.sh"
-}
-
-if [ "$(uname -s)" != "Darwin" ]; then
-  echo "external pgrx extension build currently targets the macOS native liboliphaunt lane" >&2
-  exit 2
-fi
-
-assert_known_selection
-
-case "$script_mode" in
-  --print-required-artifacts)
-    while IFS= read -r index; do
-      printf 'control:%s\n' "${sql_names[$index]}"
-      printf 'module:%s\n' "${module_stems[$index]}"
-    done < <(selected_indices)
-    exit 0
-    ;;
-  --fetch)
-    assert_manifest_and_pins
-    while IFS= read -r index; do
-      fetch_candidate "$index"
-    done < <(selected_indices)
-    assert_manifest_and_pins
-    exit 0
-    ;;
-  --check-current)
-    assert_manifest_and_pins
-    require_core_runtime
-    require_pgrx_toolchain
-    ensure_pgrx_home
-    while IFS= read -r index; do
-      if ! artifact_ready "$index"; then
-        echo "external pgrx artifacts are missing or stale for ${ids[$index]}" >&2
-        exit 1
-      fi
-    done < <(selected_indices)
-    echo "external pgrx artifacts are current"
-    exit 0
-    ;;
-  --refresh-current-stamps)
-    assert_manifest_and_pins
-    require_core_runtime
-    require_pgrx_toolchain
-    ensure_pgrx_home
-    while IFS= read -r index; do
-      refresh_candidate_stamp "$index"
-    done < <(selected_indices)
-    echo "external pgrx artifact stamps are current"
-    exit 0
-    ;;
-  build)
-    assert_manifest_and_pins
-    require_core_runtime
-    require_pgrx_toolchain
-    ensure_pgrx_home
-    while IFS= read -r index; do
-      build_candidate "$index"
-    done < <(selected_indices)
-    echo "external pgrx artifacts are ready"
-    ;;
-  *)
-    usage
-    exit 2
-    ;;
-esac
diff --git a/src/runtimes/liboliphaunt/native/bin/build-output.bash b/src/runtimes/liboliphaunt/native/bin/build-output.bash
deleted file mode 100644
index 2ad94b2f4..000000000
--- a/src/runtimes/liboliphaunt/native/bin/build-output.bash
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env bash
-
-oliphaunt_capture_build_artifact_path() {
-  local description="${1:?oliphaunt_capture_build_artifact_path requires a description}"
-  shift
-  local log_file="${1:?oliphaunt_capture_build_artifact_path requires a log file}"
-  shift
-  local log_dir tmp status artifact
-
-  log_dir="$(dirname "$log_file")"
-  mkdir -p "$log_dir"
-  tmp="$(mktemp "${TMPDIR:-/tmp}/oliphaunt-build-output.XXXXXX")"
-
-  set +e
-  "$@" 2>&1 | tee "$tmp" | tee "$log_file" >&2
-  status="${PIPESTATUS[0]}"
-  set -e
-
-  if [ "$status" -ne 0 ]; then
-    rm -f "$tmp"
-    echo "error: $description failed; see $log_file" >&2
-    return "$status"
-  fi
-
-  artifact=""
-  while IFS= read -r line; do
-    [ -n "$line" ] || continue
-    if [ -e "$line" ]; then
-      artifact="$line"
-    fi
-  done < "$tmp"
-  if [ -z "$artifact" ]; then
-    artifact="$(awk 'NF { line = $0 } END { if (line != "") print line }' "$tmp")"
-  fi
-  rm -f "$tmp"
-  if [ -z "$artifact" ]; then
-    echo "error: $description did not print an artifact path; see $log_file" >&2
-    return 1
-  fi
-
-  printf '%s\n' "$artifact"
-}
diff --git a/src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1 b/src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1
deleted file mode 100644
index 8056da193..000000000
--- a/src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1
+++ /dev/null
@@ -1,3323 +0,0 @@
-param(
-    [Alias("check-current")]
-    [switch]$CheckCurrent
-)
-
-$ErrorActionPreference = "Stop"
-Set-StrictMode -Version Latest
-
-$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
-$RepoRoot = $null
-try {
-    $RepoRoot = & git -C $ScriptDir rev-parse --show-toplevel 2>$null
-} catch {
-    $RepoRoot = $null
-}
-if (-not $RepoRoot) {
-    $RepoRoot = (Resolve-Path (Join-Path $ScriptDir "../../../../..")).Path
-} else {
-    $RepoRoot = (Resolve-Path $RepoRoot).Path
-}
-$PgVersion = "18.4"
-$PgSha256 = "81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094"
-$PgUrl = "https://ftp.postgresql.org/pub/source/v$PgVersion/postgresql-$PgVersion.tar.bz2"
-$PgUrls = @(
-    $PgUrl,
-    "https://fossies.org/linux/misc/postgresql-$PgVersion.tar.bz2"
-)
-$SourceManifest = Join-Path $RepoRoot "src/runtimes/liboliphaunt/native/postgres18/source.toml"
-$PatchDir = Join-Path $RepoRoot "src/runtimes/liboliphaunt/native/patches/postgresql-$PgVersion"
-$TargetId = "windows-x64-msvc"
-$WorkRoot = if ($env:OLIPHAUNT_WINDOWS_WORK_ROOT) {
-    $env:OLIPHAUNT_WINDOWS_WORK_ROOT
-} elseif ($env:OLIPHAUNT_WORK_ROOT) {
-    $env:OLIPHAUNT_WORK_ROOT
-} else {
-    Join-Path $RepoRoot "target/liboliphaunt-pg18-$TargetId"
-}
-$SourceCache = Join-Path $WorkRoot "source"
-$Tarball = Join-Path $SourceCache "postgresql-$PgVersion.tar.bz2"
-$BuildDir = Join-Path $WorkRoot "postgresql-$PgVersion"
-$RuntimeBuildDir = Join-Path $WorkRoot "meson-runtime"
-$EmbeddedBuildDir = Join-Path $WorkRoot "meson-embedded"
-$RuntimeNativeFile = Join-Path $WorkRoot "meson-runtime-native.ini"
-$EmbeddedNativeFile = Join-Path $WorkRoot "meson-embedded-native.ini"
-$InstallDir = Join-Path $WorkRoot "install"
-$OutDir = Join-Path $WorkRoot "out"
-$ObjDir = Join-Path $OutDir "obj"
-$DllOut = Join-Path $OutDir "bin/oliphaunt.dll"
-$ImportLibOut = Join-Path $OutDir "lib/oliphaunt.lib"
-$EmbeddedModulesDir = Join-Path $OutDir "modules"
-$EmbeddedCoreModuleStems = @("dict_snowball", "plpgsql")
-$SnowballStopwordFiles = @(
-    "danish.stop",
-    "dutch.stop",
-    "english.stop",
-    "finnish.stop",
-    "french.stop",
-    "german.stop",
-    "hungarian.stop",
-    "italian.stop",
-    "nepali.stop",
-    "norwegian.stop",
-    "portuguese.stop",
-    "russian.stop",
-    "spanish.stop",
-    "swedish.stop",
-    "turkish.stop"
-)
-$VcRuntimeClosureTool = Join-Path $RepoRoot "tools/release/windows-vc-runtime-closure.mjs"
-$Stamp = Join-Path $OutDir "oliphaunt-windows.inputs.sha256"
-$ExternalCheckoutRoot = Join-Path $RepoRoot "target/oliphaunt-sources/checkouts"
-$OpenSslSourceManifest = Join-Path $RepoRoot "src/sources/third-party/shared/openssl.toml"
-$IcuDataSourceManifest = Join-Path $RepoRoot "src/sources/third-party/shared/icu-data.toml"
-$IcuWindowsSourceManifest = Join-Path $RepoRoot "src/sources/third-party/native/icu-windows.toml"
-$IcuDataArchive = Join-Path $ExternalCheckoutRoot "icu-data/icudt76l.dat"
-$IcuWindowsRoot = Join-Path $ExternalCheckoutRoot "icu-windows"
-$IcuDataRoot = Join-Path $WorkRoot "icu/share/icu"
-$IcuDataArchiveSha256 = "dbc14e1c48ef209f230adc2aa6854bd4d6bba8f5e6733e75897a4263d97920f0"
-$IcuDataTreeSha256 = "0523cc164d698d95d844e3683bbe23d415b575b84f4a04287d372e1c132cf1d1"
-$IcuRuntimeDllNames = @("icudt76.dll", "icuin76.dll", "icuuc76.dll")
-$NativeComponentTool = Join-Path $RepoRoot "src/extensions/tools/native-component-contract.mjs"
-$PgxsBuildPlan = Join-Path $RepoRoot "src/extensions/generated/pgxs-build.tsv"
-$PortableUuidDir = Join-Path $RepoRoot "src/runtimes/liboliphaunt/native/portable-uuid"
-$PortableUuidIncludeDir = Join-Path $PortableUuidDir "include"
-$OpenSslDependencyPrefix = Join-Path $WorkRoot "windows-dependencies/openssl"
-$PostgisDependencyPrefix = Join-Path $WorkRoot "windows-dependencies/postgis"
-$OliphauntContribDir = Join-Path $BuildDir "contrib/oliphaunt_external"
-$BuildExtensions = if ($env:OLIPHAUNT_BUILD_EXTENSIONS) { $env:OLIPHAUNT_BUILD_EXTENSIONS } else { "0" }
-$NativeExtensionSqlNames = if ($env:OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES) {
-    $env:OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES
-} elseif ($env:OLIPHAUNT_EXTENSION_SQL_NAMES) {
-    $env:OLIPHAUNT_EXTENSION_SQL_NAMES
-} else {
-    ""
-}
-$SelectedNativeExtensionSqlNames = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
-foreach ($name in ($NativeExtensionSqlNames -split ",")) {
-    $trimmed = $name.Trim()
-    if ($trimmed) {
-        [void]$SelectedNativeExtensionSqlNames.Add($trimmed)
-    }
-}
-$ExactExtensionCatalogRows = $null
-
-$LiboliphauntSources = @(
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_native.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_error.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_runtime.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_protocol.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_config.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_trace.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_backup_state.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_archive.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_archive_tar.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_static_extensions.c",
-    "src/runtimes/liboliphaunt/native/src/liboliphaunt_builtin_extensions.c"
-) | ForEach-Object { Join-Path $RepoRoot $_ }
-
-function Fail($Message) {
-    Write-Error "build-postgres18-windows.ps1: $Message"
-    exit 1
-}
-
-function Require-Command($Name) {
-    if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) {
-        Fail "missing required command: $Name"
-    }
-}
-
-function Normalize-PathEntry([string]$PathEntry) {
-    $trimmed = $PathEntry.Trim().TrimEnd([char[]]@('\', '/'))
-    if (-not $trimmed) {
-        return ""
-    }
-    try {
-        [System.IO.Path]::GetFullPath($trimmed).TrimEnd([char[]]@('\', '/')).ToLowerInvariant()
-    } catch {
-        $trimmed.ToLowerInvariant()
-    }
-}
-
-function Set-ProcessPath([string[]]$Entries) {
-    $seen = @{}
-    $clean = New-Object System.Collections.Generic.List[string]
-    foreach ($entry in $Entries) {
-        if ([string]::IsNullOrWhiteSpace($entry)) {
-            continue
-        }
-        $trimmed = $entry.Trim()
-        $key = Normalize-PathEntry $trimmed
-        if ($key -and -not $seen.ContainsKey($key)) {
-            $seen[$key] = $true
-            $clean.Add($trimmed) | Out-Null
-        }
-    }
-    Set-Item -Path Env:Path -Value ([string]::Join(";", $clean))
-}
-
-function Prepend-ProcessPath([string[]]$Entries) {
-    Set-ProcessPath (@($Entries) + @($env:Path -split ";"))
-}
-
-function Is-MsysToolPath([string]$PathEntry) {
-    $normalized = Normalize-PathEntry $PathEntry
-    return $normalized -match '\\git\\usr\\bin$' -or
-        $normalized -match '\\git\\mingw64\\bin$' -or
-        $normalized -match '\\mingw64\\bin$'
-}
-
-function Resolve-ApplicationPath([string]$Name) {
-    $command = Get-Command $Name -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1
-    if (-not $command) {
-        Fail "missing required command: $Name"
-    }
-    $command.Source
-}
-
-function Get-PythonCommand {
-    $python = Get-Command python -ErrorAction SilentlyContinue
-    if ($python) {
-        return [PSCustomObject]@{
-            Command = $python.Source
-            Arguments = @()
-        }
-    }
-    $py = Get-Command py -ErrorAction SilentlyContinue
-    if ($py) {
-        return [PSCustomObject]@{
-            Command = $py.Source
-            Arguments = @("-3")
-        }
-    }
-    Fail "missing required command: python"
-}
-
-function Invoke-Python([string[]]$Arguments) {
-    $python = Get-PythonCommand
-    & $python.Command @($python.Arguments) @Arguments
-    if ($LASTEXITCODE -ne 0) {
-        Fail "python command failed: $($Arguments -join ' ')"
-    }
-}
-
-function Get-NativeExtensionComponentField([string]$SqlName, [string]$Field) {
-    Require-Command bun
-    $values = @(& bun $NativeComponentTool field $SqlName native native-dynamic $TargetId $Field)
-    if ($LASTEXITCODE -ne 0) {
-        Fail "native component $Field resolution failed for $SqlName/$TargetId"
-    }
-    return @($values | Where-Object { $_ })
-}
-
-function Get-NativeExtensionComponents([string]$SqlName) {
-    return @(Get-NativeExtensionComponentField $SqlName "components")
-}
-
-function Get-NativeExtensionComponentSources([string]$SqlName) {
-    return @(Get-NativeExtensionComponentField $SqlName "sources")
-}
-
-function Add-PythonUserScriptsToPath {
-    $python = Get-PythonCommand
-    $script = @"
-import os
-import site
-import sysconfig
-
-paths = []
-for scheme in (None, "nt_user"):
-    try:
-        path = sysconfig.get_path("scripts", scheme=scheme) if scheme else sysconfig.get_path("scripts")
-    except Exception:
-        path = None
-    if path:
-        paths.append(path)
-user_base = getattr(site, "USER_BASE", None)
-if user_base:
-    paths.append(os.path.join(user_base, "Scripts"))
-seen = set()
-for path in paths:
-    normalized = os.path.normcase(os.path.normpath(path))
-    if normalized not in seen:
-        seen.add(normalized)
-        print(path)
-"@
-    $scriptPaths = & $python.Command @($python.Arguments) -c $script
-    foreach ($scripts in $scriptPaths) {
-        if ($scripts -and (Test-Path $scripts)) {
-            Prepend-ProcessPath @($scripts)
-        }
-    }
-}
-
-function Ensure-MesonTools {
-    Add-PythonUserScriptsToPath
-    if (-not (Get-Command meson -ErrorAction SilentlyContinue) -or -not (Get-Command ninja -ErrorAction SilentlyContinue)) {
-        Invoke-Python @("-m", "pip", "install", "--user", "meson==1.10.0", "ninja==1.13.0")
-        Add-PythonUserScriptsToPath
-    }
-    Require-Command meson
-    Require-Command ninja
-}
-
-function Import-MsvcEnvironment {
-    if (Get-Command cl.exe -ErrorAction SilentlyContinue) {
-        return
-    }
-    $vswhere = Join-Path ${env:ProgramFiles(x86)} "Microsoft Visual Studio/Installer/vswhere.exe"
-    if (-not (Test-Path $vswhere)) {
-        Fail "vswhere.exe was not found; install Visual Studio Build Tools with MSVC x64 tools"
-    }
-    $vsRoot = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
-    if (-not $vsRoot) {
-        Fail "Visual Studio Build Tools with MSVC x64 tools were not found"
-    }
-    $vsDevCmd = Join-Path $vsRoot "Common7/Tools/VsDevCmd.bat"
-    if (-not (Test-Path $vsDevCmd)) {
-        Fail "VsDevCmd.bat was not found at $vsDevCmd"
-    }
-    cmd.exe /s /c "`"$vsDevCmd`" -arch=x64 -host_arch=x64 >nul && set" |
-        ForEach-Object {
-            if ($_ -match "^(.*?)=(.*)$") {
-                Set-Item -Path "Env:$($Matches[1])" -Value $Matches[2]
-            }
-        }
-    Require-Command cl.exe
-    Require-Command link.exe
-    Require-Command dumpbin.exe
-}
-
-function Configure-MsvcToolchainPath {
-    if (-not $env:VCToolsInstallDir) {
-        Fail "VCToolsInstallDir is not set; run from an MSVC developer environment"
-    }
-    $msvcBin = Join-Path $env:VCToolsInstallDir "bin/HostX64/x64"
-    $requiredTools = @("cl.exe", "link.exe", "lib.exe", "dumpbin.exe")
-    foreach ($tool in $requiredTools) {
-        $toolPath = Join-Path $msvcBin $tool
-        if (-not (Test-Path $toolPath)) {
-            Fail "MSVC tool was not found at $toolPath"
-        }
-    }
-
-    $filteredPath = @($env:Path -split ";") | Where-Object { -not (Is-MsysToolPath $_) }
-    Set-ProcessPath (@($msvcBin) + $filteredPath)
-
-    foreach ($tool in $requiredTools) {
-        $resolved = Resolve-ApplicationPath $tool
-        if (-not $resolved.StartsWith($msvcBin, [System.StringComparison]::OrdinalIgnoreCase)) {
-            Fail "$tool resolved to $resolved instead of the MSVC tool directory $msvcBin"
-        }
-    }
-
-    $env:CC = "cl.exe"
-    $env:CXX = "cl.exe"
-    $env:AR = "lib.exe"
-    Write-Host "Using MSVC tools from $msvcBin"
-}
-
-function Prefer-NativePerl {
-    $candidateDirs = @(
-        "C:\Strawberry\perl\bin",
-        "C:\Perl64\bin"
-    )
-    foreach ($dir in $candidateDirs) {
-        if (Test-Path (Join-Path $dir "perl.exe")) {
-            Prepend-ProcessPath @($dir)
-            break
-        }
-    }
-    $perl = Get-Command perl.exe -ErrorAction SilentlyContinue
-    if (-not $perl) {
-        Fail "missing required command: perl.exe"
-    }
-    if ($perl.Source -like "*\Git\usr\bin\perl.exe") {
-        Fail "Git/MSYS Perl cannot drive PostgreSQL's MSVC build because it rewrites native tool arguments; install Strawberry Perl or another native Windows Perl"
-    }
-}
-
-function Get-FileSha256($Path) {
-    (Get-FileHash -Algorithm SHA256 -Path $Path).Hash.ToLowerInvariant()
-}
-
-function Invoke-VcRuntimeClosure([string[]]$Arguments) {
-    & bun $VcRuntimeClosureTool @Arguments
-    if ($LASTEXITCODE -ne 0) {
-        Fail "Windows x64 app-local VC runtime closure failed: $($Arguments -join ' ')"
-    }
-}
-
-function Stage-VcRuntimeClosure {
-    Invoke-VcRuntimeClosure @(
-        "stage",
-        "--root", $InstallDir,
-        "--profile", "provider",
-        "--destination", (Join-Path $InstallDir "bin")
-    )
-    Invoke-VcRuntimeClosure @(
-        "stage",
-        "--root", $OutDir,
-        "--profile", "provider",
-        "--destination", (Join-Path $OutDir "bin")
-    )
-    Invoke-VcRuntimeClosure @(
-        "verify",
-        "--root", $InstallDir,
-        "--profile", "provider",
-        "--search-root", (Join-Path $InstallDir "bin")
-    )
-    Invoke-VcRuntimeClosure @(
-        "verify",
-        "--root", $OutDir,
-        "--profile", "provider",
-        "--search-root", (Join-Path $OutDir "bin")
-    )
-}
-
-function Test-VcRuntimeClosure {
-    & bun $VcRuntimeClosureTool verify `
-        --root $InstallDir `
-        --profile provider `
-        --search-root (Join-Path $InstallDir "bin") *> $null
-    if ($LASTEXITCODE -ne 0) {
-        return $false
-    }
-    & bun $VcRuntimeClosureTool verify `
-        --root $OutDir `
-        --profile provider `
-        --search-root (Join-Path $OutDir "bin") *> $null
-    $LASTEXITCODE -eq 0
-}
-
-function Test-PostgresSourceArchive([string]$Path) {
-    if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
-        return $false
-    }
-    (Get-FileSha256 $Path) -eq $PgSha256
-}
-
-function Download-PostgresSourceArchive {
-    $partial = "$Tarball.partial.$PID.$([Guid]::NewGuid().ToString('N'))"
-    try {
-        foreach ($url in $PgUrls) {
-            Remove-Item -LiteralPath $partial -Force -ErrorAction SilentlyContinue
-            $curlExit = 1
-            try {
-                # Schannel can report transient revocation-service outages as curl
-                # error 35. Keep certificate and hostname validation, and still
-                # reject certificates that are known to be revoked, while allowing
-                # a download to proceed when only the revocation distribution point
-                # is offline. Retries and the independent pinned mirror cover the
-                # remaining bounded transport failures.
-                $curlArgs = @(
-                    "--location", "--fail", "--silent", "--show-error",
-                    "--retry", "4", "--retry-all-errors", "--retry-delay", "3",
-                    "--retry-max-time", "90", "--connect-timeout", "20", "--max-time", "60",
-                    "--max-filesize", "67108864",
-                    "--ssl-revoke-best-effort",
-                    "--proto", "=https", "--proto-redir", "=https", "--remove-on-error",
-                    "--output", $partial, $url
-                )
-                & curl.exe @curlArgs
-                $curlExit = $LASTEXITCODE
-            } catch {
-                Write-Warning "curl failed while downloading PostgreSQL $PgVersion from ${url}: $($_.Exception.Message)"
-            }
-
-            if ($curlExit -eq 0 -and (Test-PostgresSourceArchive $partial)) {
-                Move-Item -LiteralPath $partial -Destination $Tarball -Force
-                return
-            }
-            if ($curlExit -eq 0 -and (Test-Path -LiteralPath $partial -PathType Leaf)) {
-                $actual = Get-FileSha256 $partial
-                Write-Warning "discarding PostgreSQL $PgVersion from $url with checksum $actual instead of $PgSha256"
-            } else {
-                Write-Warning "PostgreSQL $PgVersion download from $url failed after bounded retries (curl exit $curlExit)"
-            }
-        }
-        Fail "failed to download verified PostgreSQL $PgVersion source from every pinned HTTPS location"
-    } finally {
-        Remove-Item -LiteralPath $partial -Force -ErrorAction SilentlyContinue
-    }
-}
-
-function NativeExtension-Selected([string]$SqlName) {
-    if ($BuildExtensions -eq "0") {
-        return $false
-    }
-    if ($SelectedNativeExtensionSqlNames.Count -eq 0) {
-        return $true
-    }
-    $SelectedNativeExtensionSqlNames.Contains($SqlName)
-}
-
-function Assert-WindowsNativeExtensionSelectionSupported {
-}
-
-function Meson-Quote([string]$Value) {
-    "'" + $Value.Replace("\", "/").Replace("'", "\'") + "'"
-}
-
-function Meson-Path([string]$Path) {
-    ([System.IO.Path]::GetFullPath($Path)).Replace("\", "/")
-}
-
-function Meson-List([string[]]$Values, [string]$Indent = "  ") {
-    if ($Values.Count -eq 0) {
-        return ""
-    }
-    (($Values | ForEach-Object { "$Indent$(Meson-Quote $_)" }) -join ",`n")
-}
-
-function Meson-DataInstall([string[]]$Files) {
-    $fileList = Meson-List $Files
-@"
-install_data(
-$fileList,
-  kwargs: contrib_data_args,
-)
-"@
-}
-
-function Copy-SourceTree([string]$Source, [string]$Destination) {
-    if (-not (Test-Path $Source)) {
-        Fail "missing source checkout: $Source"
-    }
-    Remove-Item -Recurse -Force $Destination -ErrorAction SilentlyContinue
-    New-Item -ItemType Directory -Force -Path $Destination | Out-Null
-    Copy-Item -Path (Join-Path $Source "*") -Destination $Destination -Recurse -Force
-    Remove-Item -Recurse -Force (Join-Path $Destination ".git") -ErrorAction SilentlyContinue
-}
-
-function External-Checkout([string]$CheckoutName) {
-    Join-Path $ExternalCheckoutRoot $CheckoutName
-}
-
-function Get-PatchSeries {
-    $inSeries = $false
-    foreach ($line in Get-Content $SourceManifest) {
-        if ($line -match "series\s*=\s*\[") {
-            $inSeries = $true
-            continue
-        }
-        if ($inSeries -and $line -match "\]") {
-            break
-        }
-        if ($inSeries -and $line -match '"([^"]+\.patch)"') {
-            $Matches[1]
-        }
-    }
-}
-
-function Get-DesiredHash {
-    $parts = New-Object System.Collections.Generic.List[string]
-    $parts.Add("pg_version=$PgVersion")
-    $parts.Add("pg_sha256=$PgSha256")
-    $parts.Add("target_id=$TargetId")
-    $parts.Add("build_extensions=$BuildExtensions")
-    $parts.Add("native_extension_sql_names=$NativeExtensionSqlNames")
-    $parts.Add("script=$(Get-FileSha256 $PSCommandPath)")
-    $parts.Add("source_manifest=$(Get-FileSha256 $SourceManifest)")
-    foreach ($patch in Get-PatchSeries) {
-        $parts.Add("patch:$patch=$(Get-FileSha256 (Join-Path $PatchDir $patch))")
-    }
-    foreach ($source in $LiboliphauntSources) {
-        $parts.Add("source:$source=$(Get-FileSha256 $source)")
-    }
-    $sourceInputs = @(
-        $OpenSslSourceManifest,
-        $IcuDataSourceManifest,
-        $IcuWindowsSourceManifest,
-        (Join-Path $RepoRoot "src/extensions/catalog/native-components.toml"),
-        $PgxsBuildPlan,
-        (Join-Path $PortableUuidDir "portable_uuid.c"),
-        (Join-Path $PortableUuidIncludeDir "uuid/uuid.h"),
-        (Join-Path $RepoRoot "src/extensions/external/pg_hashids/source.toml"),
-        (Join-Path $RepoRoot "src/extensions/external/pg_ivm/source.toml"),
-        (Join-Path $RepoRoot "src/extensions/external/pg_textsearch/source.toml"),
-        (Join-Path $RepoRoot "src/extensions/external/pg_uuidv7/source.toml"),
-        (Join-Path $RepoRoot "src/extensions/external/postgis/source.toml"),
-        (Join-Path $RepoRoot "src/extensions/external/pgtap/source.toml"),
-        (Join-Path $RepoRoot "src/extensions/external/vector/source.toml")
-    )
-    foreach ($dependency in @(Get-NativeExtensionComponentSources "postgis")) {
-        $sourceInputs += (Join-Path $RepoRoot "src/extensions/external/postgis/dependencies/$dependency/source.toml")
-    }
-    foreach ($source in $sourceInputs) {
-        if (Test-Path $source) {
-            $parts.Add("source-input:$source=$(Get-FileSha256 $source)")
-        }
-    }
-    $bytes = [System.Text.Encoding]::UTF8.GetBytes(($parts -join "`n") + "`n")
-    $sha = [System.Security.Cryptography.SHA256]::Create()
-    try {
-        (($sha.ComputeHash($bytes) | ForEach-Object { $_.ToString("x2") }) -join "")
-    } finally {
-        $sha.Dispose()
-    }
-}
-
-function Assert-WindowsIcuDependency {
-    foreach ($required in @(
-        (Join-Path $IcuWindowsRoot "include/unicode/ucol.h"),
-        (Join-Path $IcuWindowsRoot "lib64/icudt.lib"),
-        (Join-Path $IcuWindowsRoot "lib64/icuin.lib"),
-        (Join-Path $IcuWindowsRoot "lib64/icuuc.lib"),
-        (Join-Path $IcuWindowsRoot "bin64/icupkg.exe")
-    )) {
-        if (-not (Test-Path -LiteralPath $required -PathType Leaf)) {
-            Fail "missing pinned Windows ICU dependency file: $required"
-        }
-    }
-    foreach ($name in $IcuRuntimeDllNames) {
-        $dll = Join-Path $IcuWindowsRoot "bin64/$name"
-        if (-not (Test-Path -LiteralPath $dll -PathType Leaf)) {
-            Fail "missing pinned Windows ICU runtime DLL: $dll"
-        }
-    }
-    if (-not (Test-Path -LiteralPath $IcuDataArchive -PathType Leaf)) {
-        Fail "missing pinned ICU data archive: $IcuDataArchive"
-    }
-    $actualDataSha256 = Get-FileSha256 $IcuDataArchive
-    if ($actualDataSha256 -ne $IcuDataArchiveSha256) {
-        Fail "ICU data archive checksum mismatch: expected $IcuDataArchiveSha256, got $actualDataSha256"
-    }
-}
-
-function Prepare-WindowsIcuData {
-    Assert-WindowsIcuDependency
-    $receipt = Join-Path $WorkRoot "icu/manifest.properties"
-    $ready = (Test-Path -LiteralPath $IcuDataRoot -PathType Container) -and
-        (Test-Path -LiteralPath $receipt -PathType Leaf) -and
-        ((Get-Content -LiteralPath $receipt -Raw).Contains("icuDataTreeSha256=$IcuDataTreeSha256`n"))
-    if ($ready) {
-        & bun tools/release/native-icu-data-contract.mjs $IcuDataRoot $receipt
-        if ($LASTEXITCODE -eq 0 -and
-            (Get-Content -LiteralPath $receipt -Raw).Contains("icuDataTreeSha256=$IcuDataTreeSha256`n")) {
-            return
-        }
-    }
-
-    $icuRoot = Split-Path -Parent (Split-Path -Parent $IcuDataRoot)
-    Remove-Item -LiteralPath $icuRoot -Recurse -Force -ErrorAction SilentlyContinue
-    New-Item -ItemType Directory -Force -Path (Join-Path $IcuDataRoot "icudt76l") | Out-Null
-    $previousPath = $env:Path
-    try {
-        Prepend-ProcessPath @((Join-Path $IcuWindowsRoot "bin64"))
-        & (Join-Path $IcuWindowsRoot "bin64/icupkg.exe") -x "*" -d (Join-Path $IcuDataRoot "icudt76l") $IcuDataArchive
-        if ($LASTEXITCODE -ne 0) {
-            Fail "failed to extract pinned ICU data archive"
-        }
-    } finally {
-        Set-Item -Path Env:Path -Value $previousPath
-    }
-    $files = @(Get-ChildItem -LiteralPath (Join-Path $IcuDataRoot "icudt76l") -Recurse -File)
-    if ($files.Count -ne 4136) {
-        Fail "pinned ICU data archive must extract exactly 4136 files; found $($files.Count)"
-    }
-    & bun tools/release/native-icu-data-contract.mjs $IcuDataRoot $receipt
-    if ($LASTEXITCODE -ne 0 -or
-        -not (Get-Content -LiteralPath $receipt -Raw).Contains("icuDataTreeSha256=$IcuDataTreeSha256`n")) {
-        Fail "pinned ICU data tree does not have the canonical identity $IcuDataTreeSha256"
-    }
-}
-
-function Stage-WindowsIcuRuntime([string]$Destination) {
-    New-Item -ItemType Directory -Force -Path $Destination | Out-Null
-    foreach ($name in $IcuRuntimeDllNames) {
-        Copy-Item -LiteralPath (Join-Path $IcuWindowsRoot "bin64/$name") -Destination (Join-Path $Destination $name) -Force
-    }
-}
-
-function Invoke-Logged([string]$LogName, [scriptblock]$Block) {
-    $log = Join-Path $WorkRoot $LogName
-    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $log) | Out-Null
-    $global:LASTEXITCODE = 0
-    & $Block *> $log
-    if ($LASTEXITCODE -ne 0) {
-        [Console]::Error.WriteLine("==== $LogName tail ====")
-        if (Test-Path $log) {
-            Get-Content $log -Tail 160 | ForEach-Object { [Console]::Error.WriteLine($_) }
-        } else {
-            [Console]::Error.WriteLine("(log file was not created: $log)")
-        }
-        [Console]::Error.WriteLine("==== end $LogName tail ====")
-        Fail "$LogName failed; see $log"
-    }
-}
-
-function Expand-PostgresSourceArchive {
-    $script = @'
-import sys
-import tarfile
-from pathlib import Path
-
-archive = Path(sys.argv[1])
-destination = Path(sys.argv[2]).resolve()
-with tarfile.open(archive, "r:bz2") as source:
-    members = source.getmembers()
-    for member in members:
-        target = (destination / member.name).resolve()
-        if target != destination and destination not in target.parents:
-            raise SystemExit(f"archive member escapes extraction root: {member.name}")
-    try:
-        source.extractall(destination, members=members, filter="data")
-    except TypeError:
-        source.extractall(destination, members=members)
-'@
-    Invoke-Python @("-c", $script, $Tarball, $WorkRoot)
-}
-
-function Prepare-Source([string]$DesiredHash) {
-    New-Item -ItemType Directory -Force -Path $SourceCache, $WorkRoot, $OutDir, $ObjDir | Out-Null
-    if ((Test-Path -LiteralPath $Tarball -PathType Leaf) -and -not (Test-PostgresSourceArchive $Tarball)) {
-        $actual = Get-FileSha256 $Tarball
-        Write-Warning "discarding cached PostgreSQL $PgVersion source with checksum $actual instead of $PgSha256"
-        Remove-Item -LiteralPath $Tarball -Force
-    }
-    if (-not (Test-Path -LiteralPath $Tarball -PathType Leaf)) {
-        Download-PostgresSourceArchive
-    }
-    $actual = Get-FileSha256 $Tarball
-    if ($actual -ne $PgSha256) {
-        Fail "PostgreSQL source checksum mismatch: expected $PgSha256, got $actual"
-    }
-    $current = if (Test-Path $Stamp) { (Get-Content $Stamp -Raw).Trim() } else { "" }
-    if ((Test-Path $BuildDir) -and $current -ne $DesiredHash) {
-        Remove-Item -Recurse -Force $BuildDir, $RuntimeBuildDir, $EmbeddedBuildDir, $InstallDir, $OutDir -ErrorAction SilentlyContinue
-        New-Item -ItemType Directory -Force -Path $OutDir, $ObjDir | Out-Null
-    }
-    if (-not (Test-Path $BuildDir)) {
-        Expand-PostgresSourceArchive
-        Push-Location $BuildDir
-        try {
-            git init -q
-            foreach ($patch in Get-PatchSeries) {
-                git apply --whitespace=error-all (Join-Path $PatchDir $patch)
-                if ($LASTEXITCODE -ne 0) {
-                    Fail "failed to apply PostgreSQL patch $patch"
-                }
-            }
-        } finally {
-            Pop-Location
-        }
-    }
-    Assert-PatchedSource
-}
-
-function Assert-FileContains([string]$Path, [string]$Needle) {
-    if (-not (Test-Path $Path)) {
-        Fail "missing patched PostgreSQL source file $Path"
-    }
-    $text = Get-Content -Raw -Path $Path
-    if (-not $text.Contains($Needle)) {
-        Fail "patched PostgreSQL source file $Path does not contain required marker $Needle"
-    }
-}
-
-function Assert-PatchedSource {
-    Assert-FileContains (Join-Path $BuildDir "src/include/libpq/libpq-be.h") "OliphauntEmbeddedIO"
-    Assert-FileContains (Join-Path $BuildDir "src/backend/tcop/postgres.c") "oliphaunt_embedded_main"
-    Assert-FileContains (Join-Path $BuildDir "src/port/pqsignal.c") "oliphaunt_embedded_kill"
-    Assert-FileContains (Join-Path $BuildDir "src/port/pqsignal.c") "oliphaunt_embedded_raise"
-    Assert-FileContains (Join-Path $BuildDir "src/bin/initdb/initdb.c") 'OLIPHAUNT_INTERNAL_ICU_READY'
-    Assert-FileContains (Join-Path $BuildDir "meson_options.txt") "oliphaunt_embedded"
-    Assert-FileContains (Join-Path $BuildDir "meson_options.txt") "oliphaunt_embedded_module_provider"
-    Assert-FileContains (Join-Path $BuildDir "meson.build") "OLIPHAUNT_EMBEDDED"
-    Assert-FileContains (Join-Path $BuildDir "src/backend/meson.build") "oliphaunt_embedded_module_provider"
-}
-
-function Append-OliphauntContribSubdir([string]$Subdir) {
-    $contribMeson = Join-Path $BuildDir "contrib/meson.build"
-    $line = "subdir('oliphaunt_external/$Subdir')"
-    $text = Get-Content -Raw -Path $contribMeson
-    if (-not $text.Contains($line)) {
-        Add-Content -Path $contribMeson -Value $line
-    }
-}
-
-function Write-OliphauntMesonModule(
-    [string]$Subdir,
-    [string]$ModuleName,
-    [string[]]$Sources,
-    [string[]]$DataFiles,
-    [string[]]$CArgs = @(),
-    [string[]]$LinkArgs = @(),
-    [string[]]$LocalIncludeDirs = @()
-) {
-    $destination = Join-Path $OliphauntContribDir $Subdir
-    New-Item -ItemType Directory -Force -Path $destination | Out-Null
-    $variable = $Subdir.Replace("-", "_")
-    $sourceList = Meson-List $Sources
-    $extraKwargs = New-Object System.Collections.Generic.List[string]
-    if ($CArgs.Count -gt 0) {
-        $extraKwargs.Add("'c_args': [`n$(Meson-List $CArgs "    ")`n  ]")
-    }
-    if ($LinkArgs.Count -gt 0) {
-        $extraKwargs.Add("'link_args': [`n$(Meson-List $LinkArgs "    ")`n  ]")
-    }
-    $extraKwargsText = ""
-    if ($extraKwargs.Count -gt 0) {
-        $extraKwargsText = " + {`n  $($extraKwargs -join ",`n  ")`n}"
-    }
-    $includeText = ""
-    if ($LocalIncludeDirs.Count -gt 0) {
-        $includeText = "  include_directories: [$((($LocalIncludeDirs | ForEach-Object { "include_directories($(Meson-Quote $_))" }) -join ', '))],`n"
-    }
-    $dataInstall = Meson-DataInstall $DataFiles
-    $meson = @"
-$variable = shared_module(
-  $(Meson-Quote $ModuleName),
-  files(
-$sourceList,
-  ),
-  c_pch: pch_postgres_h,
-$includeText  kwargs: contrib_mod_args$extraKwargsText,
-)
-contrib_targets += $variable
-
-$dataInstall
-"@
-    Set-Content -Path (Join-Path $destination "meson.build") -Value $meson -Encoding UTF8
-    Append-OliphauntContribSubdir $Subdir
-}
-
-function Build-WindowsOpenSslDependency {
-    if (-not (NativeExtension-Selected "pgcrypto")) {
-        return
-    }
-    $includeDir = Join-Path $OpenSslDependencyPrefix "include/openssl"
-    $libCrypto = Join-Path $OpenSslDependencyPrefix "lib/libcrypto.lib"
-    if ((Test-Path $includeDir) -and (Test-Path $libCrypto)) {
-        return
-    }
-    Require-Command nmake.exe
-    $sourceDir = External-Checkout "openssl"
-    if (-not (Test-Path (Join-Path $sourceDir "Configure"))) {
-        Fail "missing OpenSSL checkout for pgcrypto: $sourceDir"
-    }
-    $buildRoot = Join-Path $WorkRoot "openssl-windows-build"
-    Remove-Item -Recurse -Force $buildRoot, $OpenSslDependencyPrefix -ErrorAction SilentlyContinue
-    Copy-SourceTree $sourceDir $buildRoot
-    Invoke-Logged "openssl-windows-build.log" {
-        Push-Location $buildRoot
-        try {
-            & perl Configure VC-WIN64A no-shared no-tests no-apps no-module no-asm `
-                "--prefix=$OpenSslDependencyPrefix" `
-                "--openssldir=$(Join-Path $OpenSslDependencyPrefix "ssl")"
-            if ($LASTEXITCODE -ne 0) { return }
-            & nmake.exe /nologo build_generated libcrypto.lib
-            if ($LASTEXITCODE -ne 0) { return }
-            & nmake.exe /nologo install_sw
-        } finally {
-            Pop-Location
-        }
-    }
-    if (-not (Test-Path $includeDir) -or -not (Test-Path $libCrypto)) {
-        Fail "OpenSSL Windows build did not produce include/openssl and lib/libcrypto.lib under $OpenSslDependencyPrefix"
-    }
-}
-
-function Find-FirstFileOrNull([string]$Root, [string[]]$Filters) {
-    if (-not (Test-Path $Root)) {
-        return $null
-    }
-    foreach ($filter in $Filters) {
-        $item = Get-ChildItem -Path $Root -Recurse -Filter $filter -File -ErrorAction SilentlyContinue | Select-Object -First 1
-        if ($item) {
-            return $item.FullName
-        }
-    }
-    $null
-}
-
-function Invoke-CmakeInstall(
-    [string]$Name,
-    [string]$SourceDir,
-    [string]$BuildRoot,
-    [string]$Prefix,
-    [string[]]$ConfigureArgs = @()
-) {
-    Require-Command cmake
-    Require-Command ninja
-    Remove-Item -Recurse -Force $BuildRoot, $Prefix -ErrorAction SilentlyContinue
-    New-Item -ItemType Directory -Force -Path $BuildRoot, $Prefix | Out-Null
-    $cmakeArgs = @(
-        "-S", $SourceDir,
-        "-B", $BuildRoot,
-        "-G", "Ninja",
-        "-DCMAKE_BUILD_TYPE=Release",
-        "-DCMAKE_INSTALL_PREFIX=$Prefix",
-        "-DCMAKE_C_COMPILER=cl.exe",
-        "-DCMAKE_CXX_COMPILER=cl.exe",
-        "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL"
-    ) + $ConfigureArgs
-    Invoke-Logged "postgis-$Name-cmake-configure.log" { cmake @cmakeArgs }
-    Invoke-Logged "postgis-$Name-cmake-install.log" { cmake --build $BuildRoot --config Release --target install }
-}
-
-function Build-WindowsPostgisJsonCDependency {
-    if (-not (NativeExtension-Selected "postgis")) {
-        return
-    }
-    $prefix = Join-Path $PostgisDependencyPrefix "json-c"
-    $archive = Find-FirstFileOrNull $prefix @("json-c.lib", "json-c-static.lib")
-    if ((Test-Path (Join-Path $prefix "include/json-c")) -and $archive) {
-        return
-    }
-    $sourceDir = External-Checkout "json-c"
-    if (-not (Test-Path (Join-Path $sourceDir "CMakeLists.txt"))) {
-        Fail "missing JSON-C checkout for PostGIS: $sourceDir"
-    }
-    Invoke-CmakeInstall "json-c" $sourceDir (Join-Path $WorkRoot "json-c-windows-build") $prefix @(
-        "-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
-        "-DBUILD_SHARED_LIBS=OFF",
-        "-DBUILD_STATIC_LIBS=ON",
-        "-DBUILD_APPS=OFF",
-        "-DBUILD_TESTING=OFF",
-        "-DDISABLE_WERROR=ON"
-    )
-    [void](First-File $prefix @("json-c.lib", "json-c-static.lib"))
-}
-
-function Build-WindowsPostgisSqliteDependency {
-    if (-not (NativeExtension-Selected "postgis")) {
-        return
-    }
-    $prefix = Join-Path $PostgisDependencyPrefix "sqlite"
-    $archive = Join-Path $prefix "lib/sqlite3.lib"
-    $shell = Join-Path $prefix "bin/sqlite3.exe"
-    if ((Test-Path $archive) -and (Test-Path $shell) -and (Test-Path (Join-Path $prefix "include/sqlite3.h"))) {
-        return
-    }
-    Require-Command nmake.exe
-    $sourceDir = External-Checkout "sqlite"
-    if (-not (Test-Path (Join-Path $sourceDir "Makefile.msc"))) {
-        Fail "missing SQLite checkout for PostGIS: $sourceDir"
-    }
-    $buildRoot = Join-Path $WorkRoot "sqlite-windows-build"
-    Remove-Item -Recurse -Force $buildRoot, $prefix -ErrorAction SilentlyContinue
-    Copy-SourceTree $sourceDir $buildRoot
-    Invoke-Logged "postgis-sqlite-windows-build.log" {
-        Push-Location $buildRoot
-        try {
-            # SQLite's MSVC makefile still injects /NODEFAULTLIB:msvcrt into
-            # host-tool links. Let the runner's MSVC/UCRT defaults resolve CRT
-            # symbols instead, and skip TCL artifacts that PostGIS does not use.
-            & nmake.exe /nologo /f Makefile.msc libsqlite3.lib sqlite3.exe `
-                USE_CRT_DLL=1 NO_TCL=1 LDFLAGS= `
-                OPTS="-DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION"
-        } finally {
-            Pop-Location
-        }
-    }
-    New-Item -ItemType Directory -Force -Path (Join-Path $prefix "include"), (Join-Path $prefix "lib"), (Join-Path $prefix "bin") | Out-Null
-    Copy-Item -Force (Join-Path $buildRoot "libsqlite3.lib") $archive
-    Copy-Item -Force (Join-Path $buildRoot "sqlite3.exe") $shell
-    Copy-Item -Force (Join-Path $buildRoot "sqlite3.h"), (Join-Path $buildRoot "sqlite3ext.h") (Join-Path $prefix "include")
-    if (-not (Test-Path $archive) -or -not (Test-Path $shell) -or -not (Test-Path (Join-Path $prefix "include/sqlite3.h"))) {
-        Fail "SQLite Windows build did not produce sqlite3.lib, sqlite3.exe, and headers under $prefix"
-    }
-}
-
-function Build-WindowsPostgisGeosDependency {
-    if (-not (NativeExtension-Selected "postgis")) {
-        return
-    }
-    $prefix = Join-Path $PostgisDependencyPrefix "geos"
-    if ((Test-Path (Join-Path $prefix "include/geos_c.h")) -and
-        (Find-FirstFileOrNull $prefix @("geos_c.lib")) -and
-        (Find-FirstFileOrNull $prefix @("geos.lib"))) {
-        return
-    }
-    $sourceDir = External-Checkout "geos"
-    if (-not (Test-Path (Join-Path $sourceDir "CMakeLists.txt"))) {
-        Fail "missing GEOS checkout for PostGIS: $sourceDir"
-    }
-    Invoke-CmakeInstall "geos" $sourceDir (Join-Path $WorkRoot "geos-windows-build") $prefix @(
-        "-DBUILD_SHARED_LIBS=OFF",
-        "-DBUILD_TESTING=OFF",
-        "-DBUILD_BENCHMARKS=OFF",
-        "-DBUILD_GEOSOP=OFF",
-        "-DGEOS_BUILD_DEVELOPER=OFF"
-    )
-    [void](First-File $prefix @("geos_c.lib"))
-    [void](First-File $prefix @("geos.lib"))
-}
-
-function Build-WindowsPostgisLibxml2Dependency {
-    if (-not (NativeExtension-Selected "postgis")) {
-        return
-    }
-    $prefix = Join-Path $PostgisDependencyPrefix "libxml2"
-    if ((Test-Path (Join-Path $prefix "include/libxml2/libxml/parser.h")) -and
-        (Find-FirstFileOrNull $prefix @("libxml2s.lib", "libxml2.lib", "xml2.lib"))) {
-        return
-    }
-    $sourceDir = External-Checkout "libxml2"
-    if (-not (Test-Path (Join-Path $sourceDir "CMakeLists.txt"))) {
-        Fail "missing libxml2 checkout for PostGIS: $sourceDir"
-    }
-    Invoke-CmakeInstall "libxml2" $sourceDir (Join-Path $WorkRoot "libxml2-windows-build") $prefix @(
-        "-DBUILD_SHARED_LIBS=OFF",
-        "-DLIBXML2_WITH_PROGRAMS=OFF",
-        "-DLIBXML2_WITH_TESTS=OFF",
-        "-DLIBXML2_WITH_PYTHON=OFF",
-        "-DLIBXML2_WITH_THREADS=OFF",
-        "-DLIBXML2_WITH_MODULES=OFF",
-        "-DLIBXML2_WITH_ICONV=OFF",
-        "-DLIBXML2_WITH_ZLIB=OFF",
-        "-DLIBXML2_WITH_LZMA=OFF",
-        "-DLIBXML2_WITH_HTTP=OFF"
-    )
-    [void](First-File $prefix @("libxml2s.lib", "libxml2.lib", "xml2.lib"))
-}
-
-function Build-WindowsPostgisProjDependency {
-    if (-not (NativeExtension-Selected "postgis")) {
-        return
-    }
-    Build-WindowsPostgisSqliteDependency
-    $prefix = Join-Path $PostgisDependencyPrefix "proj"
-    if ((Test-Path (Join-Path $prefix "include/proj.h")) -and
-        (Test-Path (Join-Path $prefix "share/proj/proj.db")) -and
-        (Find-FirstFileOrNull $prefix @("proj.lib", "libproj.lib"))) {
-        return
-    }
-    $sourceDir = External-Checkout "proj"
-    if (-not (Test-Path (Join-Path $sourceDir "CMakeLists.txt"))) {
-        Fail "missing PROJ checkout for PostGIS: $sourceDir"
-    }
-    $sqlitePrefix = Join-Path $PostgisDependencyPrefix "sqlite"
-    $sqliteInclude = Join-Path $sqlitePrefix "include"
-    $sqliteLib = Join-Path $sqlitePrefix "lib/sqlite3.lib"
-    $sqliteExe = Join-Path $sqlitePrefix "bin/sqlite3.exe"
-    $buildRoot = Join-Path $WorkRoot "proj-windows-build"
-    Invoke-CmakeInstall "proj" $sourceDir $buildRoot $prefix @(
-        "-DBUILD_SHARED_LIBS=OFF",
-        "-DSQLite3_INCLUDE_DIR=$sqliteInclude",
-        "-DSQLite3_LIBRARY=$sqliteLib",
-        "-DEXE_SQLITE3=$sqliteExe",
-        "-DENABLE_TIFF=OFF",
-        "-DENABLE_CURL=OFF",
-        "-DENABLE_EMSCRIPTEN_FETCH=OFF",
-        "-DHAVE_LIBDL=OFF",
-        "-DBUILD_APPS=OFF",
-        "-DBUILD_TESTING=OFF",
-        "-DBUILD_EXAMPLES=OFF",
-        "-DEMBED_RESOURCE_FILES=ON",
-        "-DUSE_ONLY_EMBEDDED_RESOURCE_FILES=ON"
-    )
-    $projDb = Join-Path $prefix "share/proj/proj.db"
-    if (-not (Test-Path $projDb) -and (Test-Path (Join-Path $buildRoot "data/proj.db"))) {
-        New-Item -ItemType Directory -Force -Path (Split-Path -Parent $projDb) | Out-Null
-        Copy-Item -Force (Join-Path $buildRoot "data/proj.db") $projDb
-    }
-    [void](First-File $prefix @("proj.lib", "libproj.lib"))
-    if (-not (Test-Path $projDb)) {
-        Fail "PROJ Windows build did not produce proj.db under $prefix"
-    }
-}
-
-function Build-WindowsPostgisDependencies {
-    if (-not (NativeExtension-Selected "postgis")) {
-        return
-    }
-    foreach ($component in @(Get-NativeExtensionComponents "postgis")) {
-        switch ($component) {
-            "geos" { Build-WindowsPostgisGeosDependency }
-            "sqlite" { Build-WindowsPostgisSqliteDependency }
-            "proj" { Build-WindowsPostgisProjDependency }
-            "libxml2" { Build-WindowsPostgisLibxml2Dependency }
-            "json-c" { Build-WindowsPostgisJsonCDependency }
-            default { Fail "unsupported native PostGIS component for ${TargetId}: $component" }
-        }
-    }
-}
-
-function Read-PostgisVersionConfig([string]$PostgisSourceDir) {
-    $versionPath = Join-Path $PostgisSourceDir "Version.config"
-    if (-not (Test-Path $versionPath)) {
-        Fail "missing PostGIS Version.config: $versionPath"
-    }
-    $values = @{}
-    foreach ($line in Get-Content $versionPath) {
-        if ($line -match "^([A-Z0-9_]+)=(.*)$") {
-            $values[$Matches[1]] = $Matches[2].Trim()
-        }
-    }
-    foreach ($key in @("POSTGIS_MAJOR_VERSION", "POSTGIS_MINOR_VERSION", "POSTGIS_MICRO_VERSION")) {
-        if (-not $values.ContainsKey($key)) {
-            Fail "PostGIS Version.config does not define $key"
-        }
-    }
-    [PSCustomObject]@{
-        Major = $values["POSTGIS_MAJOR_VERSION"]
-        Minor = $values["POSTGIS_MINOR_VERSION"]
-        Micro = $values["POSTGIS_MICRO_VERSION"]
-        Version = "$($values["POSTGIS_MAJOR_VERSION"]).$($values["POSTGIS_MINOR_VERSION"]).$($values["POSTGIS_MICRO_VERSION"])"
-        MajorMinor = "$($values["POSTGIS_MAJOR_VERSION"]).$($values["POSTGIS_MINOR_VERSION"])"
-    }
-}
-
-function Get-PostgisSourceRevision([string]$PostgisSourceDir, [string]$FallbackVersion) {
-    $revision = ""
-    try {
-        $revision = (& git -C $PostgisSourceDir describe --always --dirty=never 2>$null | Select-Object -First 1).Trim()
-    } catch {
-        $revision = ""
-    }
-    if (-not $revision) {
-        $revision = $FallbackVersion
-    }
-    $revision
-}
-
-function Get-PostgisSourceDateEpoch {
-    $manifest = Join-Path $RepoRoot "src/extensions/external/postgis/source.toml"
-    if (-not (Test-Path -PathType Leaf $manifest)) {
-        Fail "missing canonical PostGIS source manifest: $manifest"
-    }
-    $keyLines = @(Select-String -Path $manifest -Pattern '^source_date_epoch\s*=')
-    if ($keyLines.Count -ne 1) {
-        Fail "$manifest must declare exactly one canonical source_date_epoch integer"
-    }
-    $match = [regex]::Match($keyLines[0].Line, '^source_date_epoch = ([1-9][0-9]{0,17})$')
-    if (-not $match.Success) {
-        Fail "$manifest source_date_epoch must be one canonical positive integer"
-    }
-    try {
-        $epoch = [Int64]::Parse($match.Groups[1].Value, [Globalization.CultureInfo]::InvariantCulture)
-    } catch {
-        Fail "$manifest source_date_epoch exceeds the signed 64-bit range"
-    }
-    if ($epoch -gt 253402300799) {
-        Fail "$manifest source_date_epoch exceeds the portable UTC range"
-    }
-    $epoch
-}
-
-function Format-PostgisSourceDate([Int64]$Epoch) {
-    [DateTimeOffset]::FromUnixTimeSeconds($Epoch).UtcDateTime.ToString(
-        "yyyy-MM-dd HH:mm:ss",
-        [Globalization.CultureInfo]::InvariantCulture
-    )
-}
-
-function Expand-PostgisTemplate([string]$InputPath, [string]$OutputPath, [hashtable]$Values) {
-    $text = Get-Content -Raw -Path $InputPath
-    foreach ($key in $Values.Keys) {
-        $text = $text.Replace("@$key@", [string]$Values[$key])
-    }
-    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $OutputPath) | Out-Null
-    Set-Content -Path $OutputPath -Encoding UTF8 -Value $text
-}
-
-function Initialize-WindowsPostgisGeneratedSource([string]$PostgisDir, [string]$OriginalSourceDir) {
-    $version = Read-PostgisVersionConfig $PostgisDir
-    $revision = Get-PostgisSourceRevision $OriginalSourceDir $version.Version
-    $sourceDateEpoch = Get-PostgisSourceDateEpoch
-    if ($env:SOURCE_DATE_EPOCH -ne [string]$sourceDateEpoch) {
-        Fail "Windows PostGIS generation must run under the canonical SOURCE_DATE_EPOCH"
-    }
-    $buildDate = Format-PostgisSourceDate $sourceDateEpoch
-    $geosVersionNumber = "31401"
-    $projVersionNumber = "90801"
-    $libXmlVersion = "2.14.6"
-    $postgisVersion = "$($version.Major).$($version.Minor) USE_GEOS=1 USE_PROJ=1 USE_STATS=1"
-    $localeDir = (Meson-Path (Join-Path $InstallDir "share/locale"))
-
-    Set-Content -Path (Join-Path $PostgisDir "postgis_revision.h") -Encoding UTF8 -Value "#define POSTGIS_REVISION $revision"
-    Set-Content -Path (Join-Path $PostgisDir "postgis_config.h") -Encoding UTF8 -Value @"
-/* postgis_config.h. Generated by Oliphaunt's Windows native producer. */
-#ifndef POSTGIS_CONFIG_H
-#define POSTGIS_CONFIG_H 1
-
-#include "postgis_revision.h"
-
-#define POSTGIS_DEBUG_LEVEL 0
-/* #undef ENABLE_NLS */
-/* #undef HAVE_GETTEXT */
-/* #undef WORDS_BIGENDIAN */
-/* #undef HAVE_ICONV */
-/* #undef HAVE_ICONVCTL */
-#define HAVE_IEEEFP_H 0
-#define HAVE_LIBGEOS_C 1
-/* #undef HAVE_LIBICONVCTL */
-/* #undef HAVE_LIBPROTOBUF */
-/* #undef LIBPROTOBUF_VERSION */
-#define HAVE_LIBJSON 1
-#define HAVE_LIBPQ 1
-#define HAVE_LIBPROJ 1
-#define HAVE_LIBXML2 1
-#define HAVE_LIBXML_PARSER_H 1
-#define HAVE_LIBXML_TREE_H 1
-#define HAVE_LIBXML_XPATHINTERNALS_H 1
-#define HAVE_LIBXML_XPATH_H 1
-/* #undef HAVE_UNISTD_H */
-/* #undef HAVE_SFCGAL */
-#define LT_OBJDIR ".libs/"
-#define PGSQL_LOCALEDIR "$localeDir"
-#define POSTGIS_BUILD_DATE "$buildDate"
-/* #undef POSTGIS_SFCGAL_VERSION */
-/* #undef POSTGIS_GDAL_VERSION */
-#define POSTGIS_GEOS_VERSION $geosVersionNumber
-#define POSTGIS_LIBXML2_VERSION "$libXmlVersion"
-#define POSTGIS_LIB_VERSION "$($version.Version)"
-#define POSTGIS_MAJOR_VERSION "$($version.Major)"
-#define POSTGIS_MINOR_VERSION "$($version.Minor)"
-#define POSTGIS_MICRO_VERSION "$($version.Micro)"
-#define POSTGIS_PGSQL_VERSION 180
-#define POSTGIS_PROJ_VERSION $projVersionNumber
-/* #undef POSTGIS_RASTER_WARN_ON_TRUNCATION */
-#define POSTGIS_SCRIPTS_VERSION "$($version.Version)"
-#define POSTGIS_VERSION "$postgisVersion"
-#define STDC_HEADERS 1
-#define YYTEXT_POINTER 1
-
-#endif /* POSTGIS_CONFIG_H */
-"@
-
-    $templateValues = @{
-        POSTGIS_PGSQL_VERSION = "180"
-        POSTGIS_PGSQL_HR_VERSION = "18.0"
-        POSTGIS_GEOS_VERSION = $geosVersionNumber
-        POSTGIS_PROJ_VERSION = $projVersionNumber
-        POSTGIS_LIB_VERSION = $version.Version
-        POSTGIS_LIBXML2_VERSION = $libXmlVersion
-        POSTGIS_SFCGAL_VERSION = "0"
-        POSTGIS_VERSION = $postgisVersion
-        POSTGIS_BUILD_DATE = $buildDate
-        POSTGIS_SCRIPTS_VERSION = $version.Version
-        SRID_MAX = "999999"
-        SRID_USR_MAX = "998999"
-        POSTGIS_MAJOR_VERSION = $version.Major
-        POSTGIS_MINOR_VERSION = $version.Minor
-    }
-    Expand-PostgisTemplate (Join-Path $PostgisDir "postgis/sqldefines.h.in") (Join-Path $PostgisDir "postgis/sqldefines.h") $templateValues
-    Expand-PostgisTemplate (Join-Path $PostgisDir "liblwgeom/liblwgeom.h.in") (Join-Path $PostgisDir "liblwgeom/liblwgeom.h") $templateValues
-    Expand-PostgisTemplate (Join-Path $PostgisDir "extensions/postgis/postgis.control.in") (Join-Path $PostgisDir "extensions/postgis/postgis.control") @{
-        EXTVERSION = $version.Version
-        EXTENSION = "postgis"
-        MODULEPATH = '$libdir/postgis-3'
-    }
-    $version
-}
-
-function Invoke-PostgisSqlPreprocessor([string]$InputPath, [string]$OutputPath, [string[]]$IncludeDirs) {
-    $script = @'
-import pathlib
-import re
-import sys
-
-source = pathlib.Path(sys.argv[1]).resolve()
-output = pathlib.Path(sys.argv[2]).resolve()
-include_dirs = [pathlib.Path(p).resolve() for p in sys.argv[3:]]
-macros = {}
-result = []
-include_stack = []
-token_re = re.compile(r"\b[A-Za-z_][A-Za-z0-9_]*\b")
-
-def expand_macros(text):
-    for _ in range(16):
-        changed = False
-        def repl(match):
-            nonlocal changed
-            name = match.group(0)
-            if name in macros:
-                changed = True
-                return macros[name]
-            return name
-        expanded = token_re.sub(repl, text)
-        text = expanded
-        if not changed:
-            break
-    return text
-
-def eval_expr(expr):
-    expr = expand_macros(expr)
-    expr = token_re.sub("0", expr)
-    expr = expr.replace("&&", " and ").replace("||", " or ")
-    if not re.match(r"^[0-9\s<>=!&|()+*/%.\-andor]+$", expr):
-        return False
-    try:
-        return bool(eval(expr, {"__builtins__": {}}, {}))
-    except Exception:
-        return False
-
-def find_include(name, current):
-    candidates = [current.parent] + include_dirs
-    for directory in candidates:
-        path = directory / name
-        if path.exists():
-            return path.resolve()
-    raise SystemExit(f"could not resolve SQL include {name} from {current}")
-
-def in_block_comment_after_line(line, in_block_comment):
-    offset = 0
-    while True:
-        if in_block_comment:
-            end = line.find("*/", offset)
-            if end == -1:
-                return True
-            in_block_comment = False
-            offset = end + 2
-            continue
-        start = line.find("/*", offset)
-        if start == -1:
-            return False
-        end = line.find("*/", start + 2)
-        if end == -1:
-            return True
-        offset = end + 2
-
-def process(path):
-    path = path.resolve()
-    if path in include_stack:
-        cycle = include_stack[include_stack.index(path):] + [path]
-        raise SystemExit("recursive SQL include: " + " -> ".join(str(item) for item in cycle))
-    include_stack.append(path)
-    active = True
-    stack = []
-    in_block_comment = False
-    try:
-        for raw in path.read_text(encoding="utf-8").splitlines(True):
-            stripped = raw.lstrip()
-            directive = None if in_block_comment or not stripped.startswith("#") else stripped[1:].strip()
-            if directive is None:
-                if active:
-                    result.append(expand_macros(raw))
-                in_block_comment = in_block_comment_after_line(raw, in_block_comment)
-                continue
-
-            if directive.startswith("include"):
-                if active:
-                    match = re.match(r'include\s+"([^"]+)"', directive)
-                    if not match:
-                        raise SystemExit(f"unsupported include directive in {path}: {raw.rstrip()}")
-                    process(find_include(match.group(1), path))
-                continue
-            if directive.startswith("define"):
-                if active:
-                    match = re.match(r"define\s+([A-Za-z_][A-Za-z0-9_]*)(?:\s+(.*?))?\s*$", directive)
-                    if match:
-                        macros[match.group(1)] = match.group(2) if match.group(2) is not None else "1"
-                continue
-            if directive.startswith("undef"):
-                if active:
-                    parts = directive.split()
-                    if len(parts) > 1:
-                        macros.pop(parts[1], None)
-                continue
-            if directive.startswith("ifdef"):
-                name = directive.split(None, 1)[1].strip()
-                cond = name in macros
-                stack.append([active, cond])
-                active = active and cond
-                continue
-            if directive.startswith("ifndef"):
-                name = directive.split(None, 1)[1].strip()
-                cond = name not in macros
-                stack.append([active, cond])
-                active = active and cond
-                continue
-            if directive.startswith("if"):
-                cond = eval_expr(directive[2:].strip()) if active else False
-                stack.append([active, cond])
-                active = active and cond
-                continue
-            if directive.startswith("elif"):
-                if not stack:
-                    raise SystemExit(f"orphan #elif in {path}")
-                parent, taken = stack[-1]
-                cond = (not taken) and eval_expr(directive[4:].strip()) if parent else False
-                stack[-1][1] = taken or cond
-                active = parent and cond
-                continue
-            if directive.startswith("else"):
-                if not stack:
-                    raise SystemExit(f"orphan #else in {path}")
-                parent, taken = stack[-1]
-                active = parent and not taken
-                stack[-1][1] = True
-                continue
-            if directive.startswith("endif"):
-                if not stack:
-                    raise SystemExit(f"orphan #endif in {path}")
-                parent, _ = stack.pop()
-                active = parent
-                continue
-
-            if active:
-                result.append(raw)
-    finally:
-        include_stack.pop()
-
-process(source)
-output.parent.mkdir(parents=True, exist_ok=True)
-output.write_text("".join(result), encoding="utf-8")
-'@
-    $args = @("-c", $script, $InputPath, $OutputPath) + $IncludeDirs
-    Invoke-Python $args
-}
-
-function New-PostgisSqlFromTemplate(
-    [string]$InputPath,
-    [string]$OutputPath,
-    [string[]]$IncludeDirs,
-    [string]$ModulePath,
-    [bool]$StripTransactionBlocks,
-    [bool]$RemoveExtschemaPrefix
-) {
-    $tmp = "$OutputPath.tmp"
-    Invoke-PostgisSqlPreprocessor $InputPath $tmp $IncludeDirs
-    $text = Get-Content -Raw -Path $tmp
-    Remove-Item -Force $tmp
-    $text = $text.Replace("MODULE_PATHNAME", $ModulePath)
-    if ($StripTransactionBlocks) {
-        $text = $text.Replace("BEGIN;", "").Replace("COMMIT;", "")
-    }
-    if ($RemoveExtschemaPrefix) {
-        $text = $text.Replace("@extschema@.", "")
-    }
-    Set-Content -Path $OutputPath -Encoding UTF8 -Value $text
-}
-
-function Invoke-PerlToFile([string[]]$Arguments, [string]$OutputPath) {
-    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $OutputPath) | Out-Null
-    $global:LASTEXITCODE = 0
-    & perl @Arguments > $OutputPath
-    if ($LASTEXITCODE -ne 0) {
-        Fail "perl command failed: $($Arguments -join ' ')"
-    }
-}
-
-function Invoke-PerlFromInputFile([string]$InputPath, [string[]]$Arguments, [string]$OutputPath) {
-    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $OutputPath) | Out-Null
-    $global:LASTEXITCODE = 0
-    Get-Content -Raw -Path $InputPath | & perl @Arguments > $OutputPath
-    if ($LASTEXITCODE -ne 0) {
-        Fail "perl command failed: $($Arguments -join ' ')"
-    }
-}
-
-function Join-TextFiles([string]$OutputPath, [string[]]$InputPaths, [string]$Prefix = "", [string]$Suffix = "") {
-    $builder = [System.Text.StringBuilder]::new()
-    if ($Prefix) {
-        [void]$builder.Append($Prefix)
-        if (-not $Prefix.EndsWith("`n")) {
-            [void]$builder.Append("`n")
-        }
-    }
-    foreach ($path in $InputPaths) {
-        [void]$builder.Append((Get-Content -Raw -Path $path))
-        if (-not $builder.ToString().EndsWith("`n")) {
-            [void]$builder.Append("`n")
-        }
-    }
-    if ($Suffix) {
-        [void]$builder.Append($Suffix)
-        if (-not $Suffix.EndsWith("`n")) {
-            [void]$builder.Append("`n")
-        }
-    }
-    Set-Content -Path $OutputPath -Encoding UTF8 -Value $builder.ToString()
-}
-
-function New-PostgisRasterUnpackageSql([string]$PostgisDir, [string]$SqlDir, [string[]]$RasterDropSqlFiles) {
-    $template = Join-Path $PostgisDir "extensions/postgis/unpackage_raster_if_needed.sql"
-    $prefix = [System.Text.StringBuilder]::new()
-    $suffix = [System.Text.StringBuilder]::new()
-    $pastMarker = $false
-    foreach ($line in Get-Content $template) {
-        if (-not $pastMarker) {
-            [void]$prefix.AppendLine($line)
-            if ($line.Contains("UNPACKAGE_CODE")) {
-                $pastMarker = $true
-            }
-        } else {
-            [void]$suffix.AppendLine($line)
-        }
-    }
-    $dropSql = Join-Path $SqlDir "raster_drop_all.sql"
-    Join-TextFiles $dropSql $RasterDropSqlFiles
-    $unpackageBody = Join-Path $SqlDir "raster_unpackage_body.sql"
-    Invoke-PerlFromInputFile $dropSql @((Join-Path $PostgisDir "utils/create_extension_unpackage.pl"), "postgis") $unpackageBody
-    $body = Get-Content -Raw -Path $unpackageBody
-    Set-Content -Path (Join-Path $SqlDir "raster_unpackage.sql") -Encoding UTF8 -Value ($prefix.ToString() + $body + $suffix.ToString())
-}
-
-function Convert-PostgisExtensionDropGuards([string]$InputPath, [string]$OutputPath) {
-    $text = (Get-Content -Raw -Path $InputPath).Replace("BEGIN;", "").Replace("COMMIT;", "")
-    $lines = New-Object System.Collections.Generic.List[string]
-    foreach ($line in ($text -split "`r?`n")) {
-        if ($line -match "^(DROP .*)\;") {
-            $drop = $Matches[1]
-            $lines.Add("SELECT @extschema@.postgis_extension_drop_if_exists('postgis', '$drop');")
-        }
-        $lines.Add($line)
-    }
-    Set-Content -Path $OutputPath -Encoding UTF8 -Value ($lines -join "`n")
-}
-
-function Build-WindowsPostgisSql([string]$PostgisDir, [pscustomobject]$Version) {
-    $sourceDateEpoch = Get-PostgisSourceDateEpoch
-    if ($env:SOURCE_DATE_EPOCH -ne [string]$sourceDateEpoch) {
-        Fail "Windows PostGIS SQL generation must run under the canonical SOURCE_DATE_EPOCH"
-    }
-    $buildDate = Format-PostgisSourceDate $sourceDateEpoch
-    $postgisSqlDir = Join-Path $PostgisDir "postgis"
-    $extensionDir = Join-Path $PostgisDir "extensions/postgis"
-    $extensionSqlDir = Join-Path $extensionDir "sql"
-    New-Item -ItemType Directory -Force -Path $extensionSqlDir | Out-Null
-    $includeDirs = @($postgisSqlDir)
-    $modulePath = '$libdir/postgis-3'
-
-    New-PostgisSqlFromTemplate (Join-Path $PostgisDir "extensions/postgis_extension_helper.sql.in") (Join-Path $PostgisDir "extensions/postgis_extension_helper.sql") @($PostgisDir, $postgisSqlDir) "" $false $false
-    New-PostgisSqlFromTemplate (Join-Path $postgisSqlDir "postgis.sql.in") (Join-Path $postgisSqlDir "postgis.sql") $includeDirs $modulePath $false $true
-    New-PostgisSqlFromTemplate (Join-Path $postgisSqlDir "legacy_minimal.sql.in") (Join-Path $postgisSqlDir "legacy_minimal.sql") $includeDirs $modulePath $false $true
-    New-PostgisSqlFromTemplate (Join-Path $postgisSqlDir "legacy.sql.in") (Join-Path $postgisSqlDir "legacy.sql") $includeDirs $modulePath $false $true
-    New-PostgisSqlFromTemplate (Join-Path $postgisSqlDir "legacy_gist.sql.in") (Join-Path $postgisSqlDir "legacy_gist.sql") $includeDirs $modulePath $false $true
-
-    Invoke-PerlToFile @((Join-Path $PostgisDir "utils/create_upgrade.pl"), (Join-Path $postgisSqlDir "postgis.sql")) (Join-Path $postgisSqlDir "postgis_upgrade.sql.in")
-    Join-TextFiles (Join-Path $postgisSqlDir "postgis_upgrade.sql") @(
-        (Join-Path $postgisSqlDir "common_before_upgrade.sql"),
-        (Join-Path $postgisSqlDir "postgis_before_upgrade.sql"),
-        (Join-Path $postgisSqlDir "postgis_upgrade.sql.in"),
-        (Join-Path $postgisSqlDir "postgis_after_upgrade.sql"),
-        (Join-Path $postgisSqlDir "common_after_upgrade.sql")
-    ) "BEGIN;" "COMMIT;"
-    Invoke-PerlToFile @((Join-Path $PostgisDir "utils/create_uninstall.pl"), (Join-Path $postgisSqlDir "postgis.sql"), "180") (Join-Path $postgisSqlDir "uninstall_postgis.sql")
-    Invoke-PerlToFile @((Join-Path $PostgisDir "utils/create_uninstall.pl"), (Join-Path $postgisSqlDir "legacy.sql"), "180") (Join-Path $postgisSqlDir "uninstall_legacy.sql")
-
-    New-PostgisSqlFromTemplate (Join-Path $postgisSqlDir "postgis.sql.in") (Join-Path $extensionSqlDir "postgis_for_extension.sql") $includeDirs $modulePath $true $false
-    $spatialRefExtension = Join-Path $extensionSqlDir "spatial_ref_sys.sql"
-    $spatialRefText = (Get-Content -Raw -Path (Join-Path $PostgisDir "spatial_ref_sys.sql")).Replace("BEGIN;", "").Replace("COMMIT;", "")
-    Set-Content -Path $spatialRefExtension -Encoding UTF8 -Value $spatialRefText
-    Invoke-PerlToFile @((Join-Path $PostgisDir "utils/create_spatial_ref_sys_config_dump.pl"), (Join-Path $PostgisDir "spatial_ref_sys.sql")) (Join-Path $extensionSqlDir "spatial_ref_sys_config_dump.sql")
-    Invoke-PerlToFile @((Join-Path $PostgisDir "utils/create_upgrade.pl"), (Join-Path $extensionSqlDir "postgis_for_extension.sql")) (Join-Path $extensionSqlDir "postgis_upgrade_for_extension.sql.in")
-    Join-TextFiles (Join-Path $extensionSqlDir "postgis_upgrade_for_extension.sql") @(
-        (Join-Path $postgisSqlDir "common_before_upgrade.sql"),
-        (Join-Path $postgisSqlDir "postgis_before_upgrade.sql"),
-        (Join-Path $extensionSqlDir "postgis_upgrade_for_extension.sql.in"),
-        (Join-Path $postgisSqlDir "postgis_after_upgrade.sql"),
-        (Join-Path $postgisSqlDir "common_after_upgrade.sql")
-    )
-    $upgradeForExtensionText = (Get-Content -Raw -Path (Join-Path $extensionSqlDir "postgis_upgrade_for_extension.sql")).Replace("BEGIN;", "").Replace("COMMIT;", "")
-    Set-Content -Path (Join-Path $extensionSqlDir "postgis_upgrade_for_extension.sql") -Encoding UTF8 -Value $upgradeForExtensionText
-    Convert-PostgisExtensionDropGuards (Join-Path $extensionSqlDir "postgis_upgrade_for_extension.sql") (Join-Path $extensionSqlDir "postgis_upgrade.sql")
-
-    $rasterDir = Join-Path $PostgisDir "raster/rt_pg"
-    $rasterIncludeDirs = @($postgisSqlDir, $rasterDir)
-    $rasterBaseSql = Join-Path $rasterDir "rtpostgis.sql"
-    New-PostgisSqlFromTemplate (Join-Path $rasterDir "rtpostgis.sql.in") $rasterBaseSql $rasterIncludeDirs '$libdir/rtpostgis-3' $false $true
-    $rasterDropSql = @()
-    foreach ($name in @("rtpostgis_upgrade_cleanup", "rtpostgis_drop")) {
-        $output = Join-Path $rasterDir "$name.sql"
-        New-PostgisSqlFromTemplate (Join-Path $rasterDir "$name.sql.in") $output $rasterIncludeDirs '$libdir/rtpostgis-3' $false $true
-        $rasterDropSql += $output
-    }
-    $rasterUninstallSql = Join-Path $rasterDir "uninstall_rtpostgis.sql"
-    Invoke-PerlToFile @((Join-Path $PostgisDir "utils/create_uninstall.pl"), $rasterBaseSql, "180") $rasterUninstallSql
-    $rasterDropSql += $rasterUninstallSql
-    New-PostgisRasterUnpackageSql $PostgisDir $extensionSqlDir $rasterDropSql
-
-    $installSql = Join-Path $extensionSqlDir "postgis--$($Version.Version).sql"
-    Join-TextFiles $installSql @(
-        (Join-Path $extensionSqlDir "postgis_for_extension.sql"),
-        (Join-Path $extensionSqlDir "spatial_ref_sys_config_dump.sql"),
-        (Join-Path $extensionSqlDir "spatial_ref_sys.sql")
-    ) '\echo Use "CREATE EXTENSION postgis" to load this file. \quit'
-
-    $anyUpgradeSql = Join-Path $extensionSqlDir "postgis--ANY--$($Version.Version).sql"
-    Join-TextFiles $anyUpgradeSql @(
-        (Join-Path $PostgisDir "extensions/postgis_extension_helper.sql"),
-        (Join-Path $extensionSqlDir "raster_unpackage.sql"),
-        (Join-Path $extensionSqlDir "postgis_upgrade.sql"),
-        (Join-Path $extensionSqlDir "spatial_ref_sys.sql"),
-        (Join-Path $extensionSqlDir "spatial_ref_sys_config_dump.sql"),
-        (Join-Path $PostgisDir "extensions/postgis_extension_helper_uninstall.sql")
-    ) '\echo Use "CREATE EXTENSION postgis" to load this file. \quit'
-
-    $templatedSql = Join-Path $extensionSqlDir "postgis--TEMPLATED--TO--ANY.sql"
-    Set-Content -Path $templatedSql -Encoding UTF8 -Value @"
--- Just tag extension postgis version as "ANY"
--- Installed by postgis $($Version.Version)
--- Built on $buildDate
-"@
-    Copy-Item -Force $templatedSql (Join-Path $extensionSqlDir "postgis--$($Version.Version)--ANY.sql")
-    Set-Content -Path (Join-Path $extensionSqlDir "postgis--unpackaged.sql") -Encoding UTF8 -Value "-- Nothing to do here"
-    $unpackagedVersionSql = Join-Path $extensionSqlDir "postgis--unpackaged--$($Version.Version).sql"
-    Invoke-PerlFromInputFile $installSql @((Join-Path $PostgisDir "utils/create_unpackaged.pl"), "postgis") $unpackagedVersionSql
-    Add-Content -Path $unpackagedVersionSql -Encoding UTF8 -Value (Get-Content -Raw -Path $anyUpgradeSql)
-}
-
-function Patch-WindowsPostgisFlatgeobufSource([string]$SourceDir) {
-    $geometryReader = Join-Path $SourceDir "geometryreader.cpp"
-    $text = Get-Content -Raw -Path $geometryReader
-    $pointLiteral = "pt = (POINT4D) { x, y, z, m };"
-    $pointAssignments = "pt.x = x;`n`tpt.y = y;`n`tpt.z = z;`n`tpt.m = m;"
-    $arrayLiteral = "pt = (POINT4D) { xv, yv, zv, mv };"
-    $arrayAssignments = "pt.x = xv;`n`t`tpt.y = yv;`n`t`tpt.z = zv;`n`t`tpt.m = mv;"
-    foreach ($expected in @($pointLiteral, $arrayLiteral)) {
-        if (-not $text.Contains($expected)) {
-            Fail "PostGIS FlatGeobuf geometryreader.cpp is missing expected MSVC patch anchor: $expected"
-        }
-    }
-    $text = $text.Replace($pointLiteral, $pointAssignments)
-    $text = $text.Replace($arrayLiteral, $arrayAssignments)
-    Set-Content -Path $geometryReader -Encoding UTF8 -Value $text
-}
-
-function Build-WindowsPostgisFlatgeobufLibrary([string]$PostgisDir) {
-    $prefix = Join-Path $PostgisDependencyPrefix "flatgeobuf"
-    $archive = Join-Path $prefix "lib/flatgeobuf.lib"
-    if (Test-Path $archive) {
-        return $archive
-    }
-    $sourceDir = Join-Path $PostgisDir "deps/flatgeobuf"
-    Patch-WindowsPostgisFlatgeobufSource $sourceDir
-    $buildRoot = Join-Path $WorkRoot "postgis-flatgeobuf-windows-build"
-    Remove-Item -Recurse -Force $buildRoot, $prefix -ErrorAction SilentlyContinue
-    New-Item -ItemType Directory -Force -Path $buildRoot, (Split-Path -Parent $archive) | Out-Null
-    $compatHeader = Join-Path $buildRoot "oliphaunt_flatgeobuf_windows_compat.h"
-    Set-Content -Path $compatHeader -Encoding UTF8 -Value @"
-#ifdef _MSC_VER
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#ifndef PROJ_DLL
-#define PROJ_DLL
-#endif
-#endif
-"@
-    $includeArgs = @(
-        "/I$(Join-Path $PostgisDir "liblwgeom")",
-        "/I$sourceDir",
-        "/I$(Join-Path $sourceDir "include")",
-        "/I$(Join-Path $PostgisDependencyPrefix "proj/include")"
-    )
-    $objects = New-Object System.Collections.Generic.List[string]
-    foreach ($source in @("flatgeobuf_c.cpp", "geometrywriter.cpp", "geometryreader.cpp", "packedrtree.cpp")) {
-        $sourcePath = Join-Path $sourceDir $source
-        $object = Join-Path $buildRoot ([System.IO.Path]::GetFileNameWithoutExtension($source) + ".obj")
-        Invoke-Logged "postgis-flatgeobuf-$([System.IO.Path]::GetFileNameWithoutExtension($source)).log" {
-            cl.exe /nologo /O2 /MD /EHsc /D_CRT_SECURE_NO_WARNINGS /Dflatbuffers=postgis_flatbuffers `
-                "/FI$compatHeader" `
-                @includeArgs `
-                /c $sourcePath "/Fo$object"
-        }
-        $objects.Add($object)
-    }
-    Invoke-Logged "postgis-flatgeobuf-lib.log" { lib.exe /nologo "/OUT:$archive" @objects }
-    if (-not (Test-Path $archive)) {
-        Fail "PostGIS FlatGeobuf Windows build did not produce $archive"
-    }
-    $archive
-}
-
-function Copy-WindowsPostgisRuntimeData([string]$PostgisDir) {
-    $projDb = Join-Path $PostgisDependencyPrefix "proj/share/proj/proj.db"
-    if (-not (Test-Path $projDb)) {
-        Fail "PostGIS PROJ dependency did not produce $projDb"
-    }
-    $destination = Join-Path $PostgisDir "share/proj"
-    New-Item -ItemType Directory -Force -Path $destination | Out-Null
-    Copy-Item -Force $projDb (Join-Path $destination "proj.db")
-}
-
-function Ensure-WindowsPostgisCommentsSql([string]$PostgisDir) {
-    $comments = Join-Path $PostgisDir "doc/postgis_comments.sql"
-    if (Test-Path $comments) {
-        return
-    }
-    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $comments) | Out-Null
-    Set-Content -Path $comments -Encoding UTF8 -Value "-- PostGIS SQL comments are optional and are not generated by the Windows native producer."
-}
-
-function Patch-WindowsPostgisSource([string]$PostgisDir) {
-    $compat = Join-Path $PostgisDir "oliphaunt_postgis_windows_compat.h"
-    Set-Content -Path $compat -Encoding UTF8 -Value @"
-#ifndef OLIPHAUNT_POSTGIS_WINDOWS_COMPAT_H
-#define OLIPHAUNT_POSTGIS_WINDOWS_COMPAT_H
-
-#ifdef _MSC_VER
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#ifndef __attribute
-#define __attribute(x)
-#endif
-#ifndef FALLTHROUGH
-#define FALLTHROUGH ((void)0)
-#endif
-#ifndef PROJ_DLL
-#define PROJ_DLL
-#endif
-#ifndef strcasecmp
-#define strcasecmp _stricmp
-#endif
-#ifndef strncasecmp
-#define strncasecmp _strnicmp
-#endif
-#endif
-
-#endif
-"@
-
-    $declarationPattern = "(?m)^\s*(?!(?:extern\s+)?PGDLLEXPORT\s+)(?:extern\s+)?Datum\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(PG_FUNCTION_ARGS\);\r?$"
-    $patchedDeclarationCount = 0
-    foreach ($subdir in @("postgis", "libpgcommon", "liblwgeom")) {
-        $root = Join-Path $PostgisDir $subdir
-        foreach ($file in Get-ChildItem -Path $root -Recurse -File | Where-Object { $_.Extension -in @(".c", ".h") }) {
-            $text = Get-Content -Raw -Path $file.FullName
-            $patchedDeclarationCount += [regex]::Matches($text, $declarationPattern).Count
-            $patched = [regex]::Replace(
-                $text,
-                $declarationPattern,
-                'extern PGDLLEXPORT Datum $1(PG_FUNCTION_ARGS);'
-            )
-            if ($patched -ne $text) {
-                Set-Content -Path $file.FullName -Encoding UTF8 -Value $patched
-            }
-        }
-    }
-
-    if ($patchedDeclarationCount -lt 50) {
-        Fail "PostGIS Windows source patch normalized only $patchedDeclarationCount SQL-callable declarations"
-    }
-
-    $legacySource = Join-Path $PostgisDir "postgis/postgis_legacy.c"
-    $legacyText = Get-Content -Raw -Path $legacySource
-    $legacyDeclarationPattern = "(?m)^([ \t]*)Datum[ \t]+funcname[ \t]*\(PG_FUNCTION_ARGS\);[ \t]*\\\r?$"
-    $legacyPatched = [regex]::Replace(
-        $legacyText,
-        $legacyDeclarationPattern,
-        '$1extern PGDLLEXPORT Datum funcname(PG_FUNCTION_ARGS); \'
-    )
-    if ($legacyPatched -eq $legacyText) {
-        Fail "PostGIS Windows source patch did not export POSTGIS_DEPRECATE declarations"
-    }
-    Set-Content -Path $legacySource -Encoding UTF8 -Value $legacyPatched
-
-    $requiredDeclarations = @(
-        @{
-            Path = "postgis/lwgeom_accum.c"
-            Functions = @(
-                "pgis_geometry_accum_transfn",
-                "pgis_geometry_collect_finalfn",
-                "pgis_geometry_polygonize_finalfn",
-                "pgis_geometry_makeline_finalfn",
-                "pgis_geometry_clusterintersecting_finalfn",
-                "pgis_geometry_clusterwithin_finalfn"
-            )
-        },
-        @{
-            Path = "postgis/lwgeom_union.c"
-            Functions = @(
-                "pgis_geometry_union_parallel_transfn",
-                "pgis_geometry_union_parallel_combinefn",
-                "pgis_geometry_union_parallel_serialfn",
-                "pgis_geometry_union_parallel_deserialfn",
-                "pgis_geometry_union_parallel_finalfn"
-            )
-        },
-        @{
-            Path = "postgis/lwgeom_spheroid.c"
-            Functions = @(
-                "ellipsoid_in",
-                "ellipsoid_out",
-                "LWGEOM_length2d_ellipsoid",
-                "LWGEOM_length_ellipsoid_linestring",
-                "LWGEOM_distance_ellipsoid",
-                "LWGEOM_distance_sphere",
-                "geometry_distance_spheroid"
-            )
-        }
-    )
-    foreach ($required in $requiredDeclarations) {
-        $text = Get-Content -Raw -Path (Join-Path $PostgisDir $required.Path)
-        foreach ($functionName in $required.Functions) {
-            $expected = "extern PGDLLEXPORT Datum $functionName(PG_FUNCTION_ARGS);"
-            if (-not $text.Contains($expected)) {
-                Fail "PostGIS Windows source patch did not export $functionName in $($required.Path)"
-            }
-        }
-    }
-}
-
-function Write-PostgisMesonModule([string]$PostgisDir, [pscustomobject]$Version, [string]$FlatgeobufLib) {
-    $jsonLib = First-File (Join-Path $PostgisDependencyPrefix "json-c") @("json-c.lib", "json-c-static.lib")
-    $sqliteLib = First-File (Join-Path $PostgisDependencyPrefix "sqlite") @("sqlite3.lib", "libsqlite3.lib")
-    $geosCLib = First-File (Join-Path $PostgisDependencyPrefix "geos") @("geos_c.lib")
-    $geosLib = First-File (Join-Path $PostgisDependencyPrefix "geos") @("geos.lib")
-    $libxml2Lib = First-File (Join-Path $PostgisDependencyPrefix "libxml2") @("libxml2s.lib", "libxml2.lib", "xml2.lib")
-    $projLib = First-File (Join-Path $PostgisDependencyPrefix "proj") @("proj.lib", "libproj.lib")
-
-    $sources = @(
-        "postgis/postgis_module.c",
-        "postgis/lwgeom_accum.c",
-        "postgis/lwgeom_union.c",
-        "postgis/lwgeom_spheroid.c",
-        "postgis/lwgeom_ogc.c",
-        "postgis/lwgeom_functions_analytic.c",
-        "postgis/lwgeom_functions_basic.c",
-        "postgis/lwgeom_inout.c",
-        "postgis/lwgeom_btree.c",
-        "postgis/lwgeom_box.c",
-        "postgis/lwgeom_box3d.c",
-        "postgis/lwgeom_geos.c",
-        "postgis/lwgeom_geos_predicates.c",
-        "postgis/lwgeom_geos_prepared.c",
-        "postgis/lwgeom_geos_clean.c",
-        "postgis/lwgeom_geos_relatematch.c",
-        "postgis/lwgeom_generate_grid.c",
-        "postgis/lwgeom_export.c",
-        "postgis/lwgeom_in_gml.c",
-        "postgis/lwgeom_in_kml.c",
-        "postgis/lwgeom_in_marc21.c",
-        "postgis/lwgeom_out_marc21.c",
-        "postgis/lwgeom_in_geohash.c",
-        "postgis/lwgeom_in_geojson.c",
-        "postgis/lwgeom_in_encoded_polyline.c",
-        "postgis/lwgeom_triggers.c",
-        "postgis/lwgeom_dump.c",
-        "postgis/lwgeom_dumppoints.c",
-        "postgis/lwgeom_functions_lrs.c",
-        "postgis/lwgeom_functions_temporal.c",
-        "postgis/lwgeom_rectree.c",
-        "postgis/lwgeom_itree.c",
-        "postgis/lwgeom_sqlmm.c",
-        "postgis/lwgeom_transform.c",
-        "postgis/lwgeom_window.c",
-        "postgis/gserialized_typmod.c",
-        "postgis/gserialized_gist_2d.c",
-        "postgis/gserialized_gist_nd.c",
-        "postgis/gserialized_supportfn.c",
-        "postgis/gserialized_spgist_2d.c",
-        "postgis/gserialized_spgist_3d.c",
-        "postgis/gserialized_spgist_nd.c",
-        "postgis/brin_2d.c",
-        "postgis/brin_nd.c",
-        "postgis/brin_common.c",
-        "postgis/gserialized_estimate.c",
-        "postgis/geography_inout.c",
-        "postgis/geography_btree.c",
-        "postgis/geography_centroid.c",
-        "postgis/geography_measurement.c",
-        "postgis/geography_measurement_trees.c",
-        "postgis/geometry_inout.c",
-        "postgis/postgis_libprotobuf.c",
-        "postgis/mvt.c",
-        "postgis/lwgeom_out_mvt.c",
-        "postgis/geobuf.c",
-        "postgis/lwgeom_out_geobuf.c",
-        "postgis/lwgeom_out_geojson.c",
-        "postgis/flatgeobuf.c",
-        "postgis/lwgeom_in_flatgeobuf.c",
-        "postgis/lwgeom_out_flatgeobuf.c",
-        "postgis/lwgeom_remove_irrelevant_points_for_view.c",
-        "postgis/lwgeom_remove_small_parts.c",
-        "postgis/postgis_legacy.c",
-        "libpgcommon/gserialized_gist.c",
-        "libpgcommon/lwgeom_transform.c",
-        "libpgcommon/lwgeom_cache.c",
-        "libpgcommon/lwgeom_pg.c",
-        "libpgcommon/shared_gserialized.c",
-        "liblwgeom/stringbuffer.c",
-        "liblwgeom/optionlist.c",
-        "liblwgeom/stringlist.c",
-        "liblwgeom/bytebuffer.c",
-        "liblwgeom/measures.c",
-        "liblwgeom/measures3d.c",
-        "liblwgeom/ptarray.c",
-        "liblwgeom/lookup3.c",
-        "liblwgeom/lwgeom_api.c",
-        "liblwgeom/lwgeom.c",
-        "liblwgeom/lwpoint.c",
-        "liblwgeom/lwline.c",
-        "liblwgeom/lwpoly.c",
-        "liblwgeom/lwtriangle.c",
-        "liblwgeom/lwmpoint.c",
-        "liblwgeom/lwmline.c",
-        "liblwgeom/lwmpoly.c",
-        "liblwgeom/lwboundingcircle.c",
-        "liblwgeom/lwcollection.c",
-        "liblwgeom/lwcircstring.c",
-        "liblwgeom/lwcompound.c",
-        "liblwgeom/lwcurvepoly.c",
-        "liblwgeom/lwmcurve.c",
-        "liblwgeom/lwmsurface.c",
-        "liblwgeom/lwpsurface.c",
-        "liblwgeom/lwtin.c",
-        "liblwgeom/lwout_wkb.c",
-        "liblwgeom/lwin_geojson.c",
-        "liblwgeom/lwin_wkb.c",
-        "liblwgeom/lwin_twkb.c",
-        "liblwgeom/lwiterator.c",
-        "liblwgeom/lwgeom_median.c",
-        "liblwgeom/lwout_wkt.c",
-        "liblwgeom/lwout_twkb.c",
-        "liblwgeom/lwin_wkt_parse.c",
-        "liblwgeom/lwin_wkt_lex.c",
-        "liblwgeom/lwin_wkt.c",
-        "liblwgeom/lwin_encoded_polyline.c",
-        "liblwgeom/lwutil.c",
-        "liblwgeom/lwhomogenize.c",
-        "liblwgeom/intervaltree.c",
-        "liblwgeom/lwalgorithm.c",
-        "liblwgeom/lwstroke.c",
-        "liblwgeom/lwlinearreferencing.c",
-        "liblwgeom/lwprint.c",
-        "liblwgeom/gbox.c",
-        "liblwgeom/gserialized.c",
-        "liblwgeom/gserialized1.c",
-        "liblwgeom/gserialized2.c",
-        "liblwgeom/lwgeodetic.c",
-        "liblwgeom/lwgeodetic_measures.c",
-        "liblwgeom/lwgeodetic_tree.c",
-        "liblwgeom/lwrandom.c",
-        "liblwgeom/lwtree.c",
-        "liblwgeom/lwout_gml.c",
-        "liblwgeom/lwout_kml.c",
-        "liblwgeom/lwout_geojson.c",
-        "liblwgeom/lwout_svg.c",
-        "liblwgeom/lwout_x3d.c",
-        "liblwgeom/lwout_encoded_polyline.c",
-        "liblwgeom/lwgeom_debug.c",
-        "liblwgeom/lwgeom_geos.c",
-        "liblwgeom/lwgeom_geos_clean.c",
-        "liblwgeom/lwgeom_geos_cluster.c",
-        "liblwgeom/lwgeom_geos_node.c",
-        "liblwgeom/lwgeom_geos_split.c",
-        "liblwgeom/topo/lwgeom_topo.c",
-        "liblwgeom/topo/lwgeom_topo_polygonizer.c",
-        "liblwgeom/topo/lwt_edgeend.c",
-        "liblwgeom/topo/lwt_edgeend_star.c",
-        "liblwgeom/topo/lwt_node_edges.c",
-        "liblwgeom/lwgeom_transform.c",
-        "liblwgeom/lwgeom_wrapx.c",
-        "liblwgeom/lwunionfind.c",
-        "liblwgeom/effectivearea.c",
-        "liblwgeom/lwchaikins.c",
-        "liblwgeom/lwmval.c",
-        "liblwgeom/lwkmeans.c",
-        "liblwgeom/varint.c",
-        "liblwgeom/lwgeom_remove_irrelevant_points_for_view.c",
-        "liblwgeom/lwspheroid.c",
-        "deps/ryu/d2s.c"
-    )
-    $extensionSqlFiles = @(
-        "extensions/postgis/postgis.control",
-        "extensions/postgis/sql/postgis--$($Version.Version).sql",
-        "extensions/postgis/sql/postgis--ANY--$($Version.Version).sql",
-        "extensions/postgis/sql/postgis--$($Version.Version)--ANY.sql",
-        "extensions/postgis/sql/postgis--TEMPLATED--TO--ANY.sql",
-        "extensions/postgis/sql/postgis--unpackaged.sql",
-        "extensions/postgis/sql/postgis--unpackaged--$($Version.Version).sql"
-    )
-    $contribDataFiles = @(
-        "postgis/legacy.sql",
-        "postgis/legacy_gist.sql",
-        "postgis/legacy_minimal.sql",
-        "postgis/postgis.sql",
-        "postgis/postgis_upgrade.sql",
-        "spatial_ref_sys.sql",
-        "postgis/uninstall_legacy.sql",
-        "postgis/uninstall_postgis.sql",
-        "doc/postgis_comments.sql"
-    )
-    $includeArgs = @(
-        "/I$(Meson-Path $PostgisDir)",
-        # liblwgeom has headers with the same basename as the PostgreSQL module.
-        # Source-local includes still win for postgis/*.c; this order keeps
-        # liblwgeom/topo/*.c from accidentally including server-side headers.
-        "/I$(Meson-Path (Join-Path $PostgisDir "liblwgeom"))",
-        "/I$(Meson-Path (Join-Path $PostgisDir "postgis"))",
-        "/I$(Meson-Path (Join-Path $PostgisDir "libpgcommon"))",
-        "/I$(Meson-Path (Join-Path $PostgisDir "deps"))",
-        "/I$(Meson-Path (Join-Path $PostgisDir "deps/flatgeobuf"))",
-        "/I$(Meson-Path (Join-Path $PostgisDir "deps/flatgeobuf/include"))",
-        "/I$(Meson-Path (Join-Path $PostgisDir "deps/ryu"))",
-        "/I$(Meson-Path (Join-Path $PostgisDependencyPrefix "geos/include"))",
-        "/I$(Meson-Path (Join-Path $PostgisDependencyPrefix "proj/include"))",
-        "/I$(Meson-Path (Join-Path $PostgisDependencyPrefix "json-c/include"))",
-        "/I$(Meson-Path (Join-Path $PostgisDependencyPrefix "json-c/include/json-c"))",
-        "/I$(Meson-Path (Join-Path $PostgisDependencyPrefix "libxml2/include/libxml2"))"
-    )
-    $cArgs = @(
-        "/D_CRT_SECURE_NO_WARNINGS",
-        "/D_USE_MATH_DEFINES",
-        "/DLIBXML_STATIC",
-        "/DRYU_NO_TRAILING_ZEROS",
-        "/FI$(Meson-Path (Join-Path $PostgisDir "oliphaunt_postgis_windows_compat.h"))"
-    ) + $includeArgs
-    $linkArgs = @(
-        (Meson-Path $FlatgeobufLib),
-        (Meson-Path $geosCLib),
-        (Meson-Path $geosLib),
-        (Meson-Path $projLib),
-        (Meson-Path $sqliteLib),
-        (Meson-Path $jsonLib),
-        (Meson-Path $libxml2Lib),
-        "ws2_32.lib",
-        "bcrypt.lib",
-        "advapi32.lib",
-        "shell32.lib",
-        "user32.lib"
-    )
-
-    $sourceList = Meson-List $sources
-    $cArgList = Meson-List $cArgs "    "
-    $linkArgList = Meson-List $linkArgs "    "
-    $extensionDataList = Meson-List $extensionSqlFiles
-    $contribDataList = Meson-List $contribDataFiles
-    $meson = @"
-postgis = shared_module(
-  'postgis-3',
-  files(
-$sourceList,
-  ),
-  c_pch: pch_postgres_h,
-  kwargs: contrib_mod_args + {
-    'c_args': [
-$cArgList
-    ],
-    'link_args': [
-$linkArgList
-    ],
-  },
-)
-contrib_targets += postgis
-
-install_data(
-$extensionDataList,
-  kwargs: contrib_data_args,
-)
-
-install_data(
-$contribDataList,
-  install_dir: dir_data / 'contrib' / 'postgis-$($Version.MajorMinor)',
-)
-
-install_data(
-  'share/proj/proj.db',
-  install_dir: dir_data / 'proj',
-)
-"@
-    Set-Content -Path (Join-Path $PostgisDir "meson.build") -Encoding UTF8 -Value $meson
-    Append-OliphauntContribSubdir "postgis"
-}
-
-function Add-PostgisMesonProducer {
-    if (-not (NativeExtension-Selected "postgis")) {
-        return
-    }
-    $previousSourceDateEpoch = $env:SOURCE_DATE_EPOCH
-    $env:SOURCE_DATE_EPOCH = [string](Get-PostgisSourceDateEpoch)
-    try {
-        Build-WindowsPostgisDependencies
-        $sourceDir = External-Checkout "postgis"
-        if (-not (Test-Path (Join-Path $sourceDir "Version.config"))) {
-            Fail "missing PostGIS checkout for Windows extension artifacts: $sourceDir"
-        }
-        $destination = Join-Path $OliphauntContribDir "postgis"
-        Copy-SourceTree $sourceDir $destination
-        $version = Initialize-WindowsPostgisGeneratedSource $destination $sourceDir
-        Build-WindowsPostgisSql $destination $version
-        Ensure-WindowsPostgisCommentsSql $destination
-        Patch-WindowsPostgisSource $destination
-        Copy-WindowsPostgisRuntimeData $destination
-        $flatgeobufLib = Build-WindowsPostgisFlatgeobufLibrary $destination
-        Write-PostgisMesonModule $destination $version $flatgeobufLib
-    } finally {
-        if ($null -eq $previousSourceDateEpoch) {
-            Remove-Item Env:SOURCE_DATE_EPOCH -ErrorAction SilentlyContinue
-        } else {
-            $env:SOURCE_DATE_EPOCH = $previousSourceDateEpoch
-        }
-    }
-}
-
-function Add-PgcryptoMesonProducer {
-    if (-not (NativeExtension-Selected "pgcrypto")) {
-        return
-    }
-    $components = @(Get-NativeExtensionComponents "pgcrypto")
-    if (($components -join ",") -ne "openssl") {
-        Fail "pgcrypto/$TargetId native component closure must be exactly openssl"
-    }
-    Build-WindowsOpenSslDependency
-    $opensslInclude = Meson-Path (Join-Path $OpenSslDependencyPrefix "include")
-    $libCrypto = Meson-Path (Join-Path $OpenSslDependencyPrefix "lib/libcrypto.lib")
-    Write-OliphauntMesonModule `
-        "pgcrypto" `
-        "pgcrypto" `
-        @(
-            "../../pgcrypto/crypt-blowfish.c",
-            "../../pgcrypto/crypt-des.c",
-            "../../pgcrypto/crypt-gensalt.c",
-            "../../pgcrypto/crypt-md5.c",
-            "../../pgcrypto/crypt-sha.c",
-            "../../pgcrypto/mbuf.c",
-            "../../pgcrypto/openssl.c",
-            "../../pgcrypto/pgcrypto.c",
-            "../../pgcrypto/pgp-armor.c",
-            "../../pgcrypto/pgp-cfb.c",
-            "../../pgcrypto/pgp-compress.c",
-            "../../pgcrypto/pgp-decrypt.c",
-            "../../pgcrypto/pgp-encrypt.c",
-            "../../pgcrypto/pgp-info.c",
-            "../../pgcrypto/pgp-mpi.c",
-            "../../pgcrypto/pgp-mpi-openssl.c",
-            "../../pgcrypto/pgp-pgsql.c",
-            "../../pgcrypto/pgp-pubdec.c",
-            "../../pgcrypto/pgp-pubenc.c",
-            "../../pgcrypto/pgp-pubkey.c",
-            "../../pgcrypto/pgp-s2k.c",
-            "../../pgcrypto/pgp.c",
-            "../../pgcrypto/px-crypt.c",
-            "../../pgcrypto/px-hmac.c",
-            "../../pgcrypto/px.c"
-        ) `
-        @(
-            "../../pgcrypto/pgcrypto--1.0--1.1.sql",
-            "../../pgcrypto/pgcrypto--1.1--1.2.sql",
-            "../../pgcrypto/pgcrypto--1.2--1.3.sql",
-            "../../pgcrypto/pgcrypto--1.3.sql",
-            "../../pgcrypto/pgcrypto--1.3--1.4.sql",
-            "../../pgcrypto/pgcrypto.control"
-        ) `
-        @("/I$opensslInclude") `
-        @($libCrypto, "crypt32.lib", "advapi32.lib", "bcrypt.lib", "ws2_32.lib", "user32.lib")
-}
-
-function Add-UuidOsspMesonProducer {
-    if (-not (NativeExtension-Selected "uuid-ossp")) {
-        return
-    }
-    $components = @(Get-NativeExtensionComponents "uuid-ossp")
-    if (($components -join ",") -ne "portable-uuid") {
-        Fail "uuid-ossp/$TargetId native component closure must be exactly portable-uuid"
-    }
-    $destination = Join-Path $OliphauntContribDir "uuid_ossp"
-    New-Item -ItemType Directory -Force -Path $destination | Out-Null
-    Copy-Item -Force (Join-Path $PortableUuidDir "portable_uuid.c") (Join-Path $destination "portable_uuid.c")
-    $portableUuidInclude = Meson-Path $PortableUuidIncludeDir
-    Write-OliphauntMesonModule `
-        "uuid_ossp" `
-        "uuid-ossp" `
-        @("../../uuid-ossp/uuid-ossp.c", "portable_uuid.c") `
-        @(
-            "../../uuid-ossp/uuid-ossp--1.0--1.1.sql",
-            "../../uuid-ossp/uuid-ossp--1.1.sql",
-            "../../uuid-ossp/uuid-ossp.control"
-        ) `
-        @("/I$portableUuidInclude", "/DHAVE_UUID_E2FS=1", "/DHAVE_UUID_UUID_H=1")
-}
-
-function Get-PgTextsearchMakefileList([string]$ExtensionDir, [string]$Variable) {
-    $makefile = Join-Path $ExtensionDir "Makefile"
-    if (-not (Test-Path -LiteralPath $makefile -PathType Leaf)) {
-        Fail "pg_textsearch checkout is missing its authoritative Makefile: $makefile"
-    }
-
-    $values = New-Object System.Collections.Generic.List[string]
-    $found = $false
-    $collecting = $false
-    $variablePattern = "^$([regex]::Escape($Variable))\s*=\s*(.*)$"
-    foreach ($line in Get-Content -Path $makefile) {
-        $fragment = $null
-        if (-not $collecting) {
-            if ($line -notmatch $variablePattern) {
-                continue
-            }
-            $found = $true
-            $collecting = $true
-            $fragment = $Matches[1].Trim()
-        } else {
-            $fragment = $line.Trim()
-        }
-
-        $continues = $fragment.EndsWith("\")
-        if ($continues) {
-            $fragment = $fragment.Substring(0, $fragment.Length - 1).TrimEnd()
-        }
-        if ($fragment) {
-            foreach ($value in ($fragment -split "\s+")) {
-                if ($value) {
-                    $values.Add($value) | Out-Null
-                }
-            }
-        }
-        if (-not $continues) {
-            break
-        }
-    }
-
-    if (-not $found) {
-        Fail "pg_textsearch Makefile is missing its $Variable assignment"
-    }
-    @($values)
-}
-
-function Assert-PgTextsearchWindowsPgxsManifest(
-    [string]$ExtensionDir,
-    [string[]]$Sources,
-    [string[]]$DataFiles
-) {
-    $expectedSources = @(
-        Get-PgTextsearchMakefileList $ExtensionDir "OBJS" |
-            ForEach-Object {
-                if (-not $_.EndsWith(".o", [System.StringComparison]::Ordinal)) {
-                    Fail "pg_textsearch Makefile OBJS contains a non-object entry: $_"
-                }
-                $_.Substring(0, $_.Length - 2) + ".c"
-            }
-    )
-    $expectedDataFiles = @(
-        @(Get-PgTextsearchMakefileList $ExtensionDir "DATA") +
-            @("pg_textsearch.control")
-    )
-    if (($Sources -join "`n") -ne ($expectedSources -join "`n")) {
-        Fail "pg_textsearch Windows sources differ from the pinned upstream Makefile: expected $($expectedSources -join ', '); got $($Sources -join ', ')"
-    }
-    if (($DataFiles -join "`n") -ne ($expectedDataFiles -join "`n")) {
-        Fail "pg_textsearch Windows SQL payload differs from the pinned upstream Makefile: expected $($expectedDataFiles -join ', '); got $($DataFiles -join ', ')"
-    }
-    foreach ($relativePath in @($Sources) + @($DataFiles)) {
-        $path = Join-Path $ExtensionDir $relativePath
-        if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
-            Fail "pg_textsearch Windows input declared by the pinned Makefile is missing: $relativePath"
-        }
-    }
-}
-
-function Get-PgTextsearchWindowsVersionDefine([string]$ExtensionDir) {
-    $control = Join-Path $ExtensionDir "pg_textsearch.control"
-    if (-not (Test-Path -LiteralPath $control -PathType Leaf)) {
-        Fail "pg_textsearch checkout is missing its control file: $control"
-    }
-
-    $controlText = Get-Content -Raw -Path $control
-    $versionMatches = [regex]::Matches(
-        $controlText,
-        "(?m)^\s*default_version\s*=\s*'([^']+)'\s*$"
-    )
-    if ($versionMatches.Count -ne 1) {
-        Fail "pg_textsearch control must declare exactly one single-quoted default_version; found $($versionMatches.Count)"
-    }
-    $version = $versionMatches[0].Groups[1].Value
-    if ($version -notmatch '^[0-9]+\.[0-9]+\.[0-9]+$') {
-        Fail "pg_textsearch control has unsupported default_version '$version'"
-    }
-
-    $makefile = Join-Path $ExtensionDir "Makefile"
-    $makefileText = Get-Content -Raw -Path $makefile
-    if (-not $makefileText.Contains('-DPG_TEXTSEARCH_VERSION=\"$(EXTVERSION)\"')) {
-        Fail "pg_textsearch Makefile no longer defines PG_TEXTSEARCH_VERSION from EXTVERSION"
-    }
-
-    # Keep the embedded quotes in one Meson argument. Meson/Ninja preserves
-    # them for cl.exe, so the macro expands to a C string literal.
-    "/DPG_TEXTSEARCH_VERSION=`"$version`""
-}
-
-function Patch-PgTextsearchWindowsTypeLayout(
-    [string]$Text,
-    [string]$TypeName,
-    [string]$Attribute,
-    [int]$Pack,
-    [int]$ExpectedSize,
-    [int]$ExpectedAlignment
-) {
-    $escapedTypeName = [regex]::Escape($TypeName)
-    $escapedAttribute = [regex]::Escape($Attribute)
-    $declarationPattern = "(?m)^typedef struct $escapedTypeName\r?$"
-    $closingPattern = "(?m)^} __attribute__\(\($escapedAttribute\)\) $escapedTypeName;\r?$"
-    $declarationMatches = [regex]::Matches($Text, $declarationPattern)
-    $closingMatches = [regex]::Matches($Text, $closingPattern)
-    if ($declarationMatches.Count -ne 1 -or $closingMatches.Count -ne 1) {
-        Fail "pg_textsearch $TypeName layout changed upstream; expected one declaration and one __attribute__(($Attribute)) closing, found $($declarationMatches.Count) and $($closingMatches.Count)"
-    }
-
-    $newline = if ($Text.Contains("`r`n")) { "`r`n" } else { "`n" }
-    $declaration = "#ifdef _MSC_VER${newline}#pragma pack(push, $Pack)${newline}#endif${newline}typedef struct $TypeName"
-    $closing = "} $TypeName;${newline}#ifdef _MSC_VER${newline}#pragma pack(pop)${newline}StaticAssertDecl(sizeof($TypeName) == $ExpectedSize, `"$TypeName must remain $ExpectedSize bytes on Windows`");${newline}StaticAssertDecl(__alignof($TypeName) == $ExpectedAlignment, `"$TypeName must remain $ExpectedAlignment-byte aligned on Windows`");${newline}#endif"
-    $Text = [regex]::Replace($Text, $declarationPattern, $declaration)
-    $Text = [regex]::Replace($Text, $closingPattern, $closing)
-    $Text
-}
-
-function Patch-PgTextsearchWindowsSource([string]$ExtensionDir) {
-    $compat = Join-Path $ExtensionDir "src/oliphaunt_windows_compat.h"
-    Set-Content -Path $compat -Encoding UTF8 -Value @"
-#ifdef _MSC_VER
-#ifndef __attribute__
-#define __attribute__(x)
-#endif
-#endif
-"@
-    Set-Content -Path (Join-Path $ExtensionDir "src/unistd.h") -Encoding UTF8 -Value @"
-#ifndef OLIPHAUNT_PG_TEXTSEARCH_WINDOWS_UNISTD_H
-#define OLIPHAUNT_PG_TEXTSEARCH_WINDOWS_UNISTD_H
-#endif
-"@
-    $segmentHeader = Join-Path $ExtensionDir "src/segment/segment.h"
-    $text = Get-Content -Raw -Path $segmentHeader
-    $text = Patch-PgTextsearchWindowsTypeLayout $text "TpDictEntryV3" "aligned(4)" 4 12 4
-    $text = Patch-PgTextsearchWindowsTypeLayout $text "TpDictEntry" "aligned(8)" 8 16 8
-    $text = Patch-PgTextsearchWindowsTypeLayout $text "TpSegmentPosting" "packed" 1 14 1
-    $text = Patch-PgTextsearchWindowsTypeLayout $text "TpSkipEntryV3" "packed" 1 16 1
-    $text = Patch-PgTextsearchWindowsTypeLayout $text "TpSkipEntry" "packed" 1 20 1
-    $text = Patch-PgTextsearchWindowsTypeLayout $text "TpCtidMapEntry" "packed" 1 6 1
-    Set-Content -Path $segmentHeader -Encoding UTF8 -Value $text
-
-    $expullHeader = Join-Path $ExtensionDir "src/memtable/expull.h"
-    $text = Get-Content -Raw -Path $expullHeader
-    $text = Patch-PgTextsearchWindowsTypeLayout $text "TpExpullEntry" "packed" 1 7 1
-    Set-Content -Path $expullHeader -Encoding UTF8 -Value $text
-
-    $amHeader = Join-Path $ExtensionDir "src/am/am.h"
-    $text = Get-Content -Raw -Path $amHeader
-    $original = "Datum tp_handler(PG_FUNCTION_ARGS);"
-    $replacement = "extern PGDLLEXPORT Datum tp_handler(PG_FUNCTION_ARGS);"
-    if (-not $text.Contains($original)) {
-        Fail "pg_textsearch am.h is missing expected tp_handler declaration"
-    }
-    $text = $text.Replace($original, $replacement)
-    Set-Content -Path $amHeader -Encoding UTF8 -Value $text
-
-    $vectorHeader = Join-Path $ExtensionDir "src/types/vector.h"
-    $text = Get-Content -Raw -Path $vectorHeader
-    foreach ($functionName in @("tpvector_in", "tpvector_out", "tpvector_recv", "tpvector_send", "to_tpvector", "tpvector_eq")) {
-        $original = "Datum $($functionName)(PG_FUNCTION_ARGS);"
-        $replacement = "extern PGDLLEXPORT Datum $($functionName)(PG_FUNCTION_ARGS);"
-        if (-not $text.Contains($original)) {
-            Fail "pg_textsearch vector.h is missing expected $functionName declaration"
-        }
-        $text = $text.Replace($original, $replacement)
-    }
-    Set-Content -Path $vectorHeader -Encoding UTF8 -Value $text
-
-    $queryHeader = Join-Path $ExtensionDir "src/types/query.h"
-    $text = Get-Content -Raw -Path $queryHeader
-    foreach ($functionName in @(
-        "tpquery_in",
-        "tpquery_out",
-        "tpquery_recv",
-        "tpquery_send",
-        "to_tpquery_text",
-        "to_tpquery_text_index",
-        "bm25_text_bm25query_score",
-        "bm25_text_text_score",
-        "tpquery_eq"
-    )) {
-        $original = "Datum $($functionName)(PG_FUNCTION_ARGS);"
-        $replacement = "extern PGDLLEXPORT Datum $($functionName)(PG_FUNCTION_ARGS);"
-        if (-not $text.Contains($original)) {
-            Fail "pg_textsearch query.h is missing expected $functionName declaration"
-        }
-        $text = $text.Replace($original, $replacement)
-    }
-    Set-Content -Path $queryHeader -Encoding UTF8 -Value $text
-}
-
-function Patch-PgUuidv7WindowsSource([string]$ExtensionDir) {
-    $source = Join-Path $ExtensionDir "pg_uuidv7.c"
-    $text = Get-Content -Raw -Path $source
-    $epochDefine = "#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)"
-    $compat = @"
-#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)
-
-#ifdef _WIN32
-#ifndef CLOCK_REALTIME
-#define CLOCK_REALTIME 0
-#endif
-static int
-oliphaunt_pg_uuidv7_clock_gettime(int clock_id, struct timespec *ts)
-{
-	TimestampTz unix_usecs;
-
-	if (clock_id != CLOCK_REALTIME || ts == NULL)
-		return -1;
-
-	unix_usecs = GetCurrentTimestamp() + EPOCH_DIFF_USECS;
-	ts->tv_sec = (time_t) (unix_usecs / USECS_PER_SEC);
-	ts->tv_nsec = (long) ((unix_usecs % USECS_PER_SEC) * 1000);
-	return 0;
-}
-#define clock_gettime oliphaunt_pg_uuidv7_clock_gettime
-#endif
-"@
-    if (-not $text.Contains($epochDefine)) {
-        Fail "pg_uuidv7.c is missing expected epoch define"
-    }
-    $text = $text.Replace($epochDefine, $compat)
-    Set-Content -Path $source -Encoding UTF8 -Value $text
-}
-
-function Add-ExternalPgxsMesonProducer(
-    [string]$SqlName,
-    [string]$CheckoutName,
-    [string]$Subdir,
-    [string]$ModuleName,
-    [string[]]$Sources,
-    [string[]]$DataFiles,
-    [string[]]$CArgs = @(),
-    [string[]]$LocalIncludeDirs = @()
-) {
-    if (-not (NativeExtension-Selected $SqlName)) {
-        return
-    }
-    $destination = Join-Path $OliphauntContribDir $Subdir
-    Copy-SourceTree (External-Checkout $CheckoutName) $destination
-    if ($SqlName -eq "pg_uuidv7") {
-        Patch-PgUuidv7WindowsSource $destination
-    }
-    if ($SqlName -eq "pg_textsearch") {
-        Assert-PgTextsearchWindowsPgxsManifest $destination $Sources $DataFiles
-        Patch-PgTextsearchWindowsSource $destination
-        $compatHeader = Meson-Path (Join-Path $destination "src/oliphaunt_windows_compat.h")
-        $versionDefine = Get-PgTextsearchWindowsVersionDefine $destination
-        $CArgs = @($CArgs) + @($versionDefine, "/FI$compatHeader")
-    }
-    if ($SqlName -eq "vector") {
-        Copy-Item -Force (Join-Path $destination "sql/vector.sql") (Join-Path $destination "sql/vector--0.8.2.sql")
-    }
-    Write-OliphauntMesonModule $Subdir $ModuleName $Sources $DataFiles $CArgs @() $LocalIncludeDirs
-}
-
-function Add-ExternalPgxsMesonProducers {
-    Add-ExternalPgxsMesonProducer `
-        "pg_hashids" "pg_hashids" "pg_hashids" "pg_hashids" `
-        @("pg_hashids.c", "hashids.c") `
-        @(
-            "pg_hashids--1.3.sql",
-            "pg_hashids--1.2.1--1.3.sql",
-            "pg_hashids--1.2--1.3.sql",
-            "pg_hashids--1.1--1.2.sql",
-            "pg_hashids--1.0--1.1.sql",
-            "pg_hashids.control"
-        )
-    Add-ExternalPgxsMesonProducer `
-        "pg_ivm" "pg_ivm" "pg_ivm" "pg_ivm" `
-        @("createas.c", "matview.c", "pg_ivm.c", "ruleutils.c", "subselect.c") `
-        @(
-            "pg_ivm--1.0.sql",
-            "pg_ivm--1.0--1.1.sql",
-            "pg_ivm--1.1--1.2.sql",
-            "pg_ivm--1.2--1.3.sql",
-            "pg_ivm--1.3--1.4.sql",
-            "pg_ivm--1.4--1.5.sql",
-            "pg_ivm--1.5--1.6.sql",
-            "pg_ivm--1.6--1.7.sql",
-            "pg_ivm--1.7--1.8.sql",
-            "pg_ivm--1.8--1.9.sql",
-            "pg_ivm--1.9--1.10.sql",
-            "pg_ivm--1.10.sql",
-            "pg_ivm--1.10--1.11.sql",
-            "pg_ivm--1.11--1.12.sql",
-            "pg_ivm--1.12--1.13.sql",
-            "pg_ivm.control"
-        )
-    Add-ExternalPgxsMesonProducer `
-        "pg_uuidv7" "pg_uuidv7" "pg_uuidv7" "pg_uuidv7" `
-        @("pg_uuidv7.c") `
-        @(
-            "sql/pg_uuidv7--1.7.sql",
-            "pg_uuidv7.control"
-        )
-    Add-ExternalPgxsMesonProducer `
-        "pg_textsearch" "pg_textsearch" "pg_textsearch" "pg_textsearch" `
-        @(
-            "src/mod.c",
-            "src/source.c",
-            "src/am/handler.c",
-            "src/am/build.c",
-            "src/am/build_context.c",
-            "src/am/build_parallel.c",
-            "src/am/scan.c",
-            "src/am/vacuum.c",
-            "src/memtable/arena.c",
-            "src/memtable/expull.c",
-            "src/memtable/memtable.c",
-            "src/memtable/posting.c",
-            "src/memtable/stringtable.c",
-            "src/memtable/scan.c",
-            "src/memtable/source.c",
-            "src/segment/segment.c",
-            "src/segment/dictionary.c",
-            "src/segment/scan.c",
-            "src/segment/merge.c",
-            "src/segment/docmap.c",
-            "src/segment/compression.c",
-            "src/query/bmw.c",
-            "src/query/score.c",
-            "src/types/vector.c",
-            "src/types/query.c",
-            "src/state/state.c",
-            "src/state/registry.c",
-            "src/state/metapage.c",
-            "src/state/limit.c",
-            "src/planner/hooks.c",
-            "src/planner/cost.c",
-            "src/debug/dump.c"
-        ) `
-        @(
-            "sql/pg_textsearch--0.6.1.sql",
-            "sql/pg_textsearch--0.0.1--0.0.2.sql",
-            "sql/pg_textsearch--0.0.2--0.0.3.sql",
-            "sql/pg_textsearch--0.0.3--0.0.4.sql",
-            "sql/pg_textsearch--0.0.4--0.0.5.sql",
-            "sql/pg_textsearch--0.0.5--0.1.0.sql",
-            "sql/pg_textsearch--0.1.0--0.2.0.sql",
-            "sql/pg_textsearch--0.2.0--0.3.0.sql",
-            "sql/pg_textsearch--0.3.0--0.4.0.sql",
-            "sql/pg_textsearch--0.4.0--0.4.1.sql",
-            "sql/pg_textsearch--0.4.1--0.4.2.sql",
-            "sql/pg_textsearch--0.4.2--0.5.0.sql",
-            "sql/pg_textsearch--0.5.0--0.6.1.sql",
-            "sql/pg_textsearch--0.5.1--0.6.1.sql",
-            "sql/pg_textsearch--0.6.0--0.6.1.sql",
-            "pg_textsearch.control"
-        ) `
-        @("/D_CRT_SECURE_NO_WARNINGS") `
-        @("src")
-    Add-ExternalPgxsMesonProducer `
-        "vector" "pgvector" "vector" "vector" `
-        @(
-            "src/bitutils.c",
-            "src/bitvec.c",
-            "src/halfutils.c",
-            "src/halfvec.c",
-            "src/hnsw.c",
-            "src/hnswbuild.c",
-            "src/hnswinsert.c",
-            "src/hnswscan.c",
-            "src/hnswutils.c",
-            "src/hnswvacuum.c",
-            "src/ivfbuild.c",
-            "src/ivfflat.c",
-            "src/ivfinsert.c",
-            "src/ivfkmeans.c",
-            "src/ivfscan.c",
-            "src/ivfutils.c",
-            "src/ivfvacuum.c",
-            "src/sparsevec.c",
-            "src/vector.c"
-        ) `
-        @(
-            "sql/vector--0.1.0--0.1.1.sql",
-            "sql/vector--0.1.1--0.1.3.sql",
-            "sql/vector--0.1.3--0.1.4.sql",
-            "sql/vector--0.1.4--0.1.5.sql",
-            "sql/vector--0.1.5--0.1.6.sql",
-            "sql/vector--0.1.6--0.1.7.sql",
-            "sql/vector--0.1.7--0.1.8.sql",
-            "sql/vector--0.1.8--0.2.0.sql",
-            "sql/vector--0.2.0--0.2.1.sql",
-            "sql/vector--0.2.1--0.2.2.sql",
-            "sql/vector--0.2.2--0.2.3.sql",
-            "sql/vector--0.2.3--0.2.4.sql",
-            "sql/vector--0.2.4--0.2.5.sql",
-            "sql/vector--0.2.5--0.2.6.sql",
-            "sql/vector--0.2.6--0.2.7.sql",
-            "sql/vector--0.2.7--0.3.0.sql",
-            "sql/vector--0.3.0--0.3.1.sql",
-            "sql/vector--0.3.1--0.3.2.sql",
-            "sql/vector--0.3.2--0.4.0.sql",
-            "sql/vector--0.4.0--0.4.1.sql",
-            "sql/vector--0.4.1--0.4.2.sql",
-            "sql/vector--0.4.2--0.4.3.sql",
-            "sql/vector--0.4.3--0.4.4.sql",
-            "sql/vector--0.4.4--0.5.0.sql",
-            "sql/vector--0.5.0--0.5.1.sql",
-            "sql/vector--0.5.1--0.6.0.sql",
-            "sql/vector--0.6.0--0.6.1.sql",
-            "sql/vector--0.6.1--0.6.2.sql",
-            "sql/vector--0.6.2--0.7.0.sql",
-            "sql/vector--0.7.0--0.7.1.sql",
-            "sql/vector--0.7.1--0.7.2.sql",
-            "sql/vector--0.7.2--0.7.3.sql",
-            "sql/vector--0.7.3--0.7.4.sql",
-            "sql/vector--0.7.4--0.8.0.sql",
-            "sql/vector--0.8.0--0.8.1.sql",
-            "sql/vector--0.8.1--0.8.2.sql",
-            "sql/vector--0.8.2.sql",
-            "vector.control"
-        ) `
-        @("/fp:fast")
-}
-
-function Prepare-WindowsExtensionInputs {
-    if ($BuildExtensions -eq "0") {
-        return
-    }
-    Assert-WindowsNativeExtensionSelectionSupported
-    Add-PgcryptoMesonProducer
-    Add-UuidOsspMesonProducer
-    Add-ExternalPgxsMesonProducers
-    Add-PostgisMesonProducer
-}
-
-function Expand-PgtapSqlTemplate([string]$InputPath, [string]$OutputPath, [string]$ModulePath) {
-    $text = Get-Content -Raw -Path $InputPath
-    $text = $text.Replace("MODULE_PATHNAME", $ModulePath)
-    $text = $text.Replace("__OS__", "MSWin32")
-    $text = $text.Replace("__VERSION__", "1.3")
-    Set-Content -Path $OutputPath -Encoding UTF8 -Value $text
-}
-
-function Install-WindowsPgtapExtension {
-    if (-not (NativeExtension-Selected "pgtap")) {
-        return
-    }
-    $sourceDir = External-Checkout "pgtap"
-    if (-not (Test-Path (Join-Path $sourceDir "pgtap.control"))) {
-        Fail "missing pgTAP checkout for Windows extension artifact staging: $sourceDir"
-    }
-    $buildDir = Join-Path $WorkRoot "pgtap-windows"
-    Copy-SourceTree $sourceDir $buildDir
-    $sqlDir = Join-Path $buildDir "sql"
-    Expand-PgtapSqlTemplate (Join-Path $sqlDir "pgtap.sql.in") (Join-Path $sqlDir "pgtap.sql") "pgtap"
-    foreach ($input in Get-ChildItem -Path $sqlDir -Filter "*.sql.in" -File) {
-        $output = Join-Path $sqlDir ($input.Name.Substring(0, $input.Name.Length - 3))
-        if (-not (Test-Path $output)) {
-            Copy-Item -Force $input.FullName $output
-        }
-    }
-    Expand-PgtapSqlTemplate (Join-Path $sqlDir "pgtap.sql.in") (Join-Path $sqlDir "pgtap-static.sql") '$libdir/pgtap'
-    $coreSql = Join-Path $sqlDir "pgtap-core.sql"
-    $schemaSql = Join-Path $sqlDir "pgtap-schema.sql"
-    & perl (Join-Path $buildDir "compat/gencore") 0 (Join-Path $sqlDir "pgtap-static.sql") > $coreSql
-    if ($LASTEXITCODE -ne 0) {
-        Fail "pgTAP core SQL generation failed"
-    }
-    & perl (Join-Path $buildDir "compat/gencore") 1 (Join-Path $sqlDir "pgtap-static.sql") > $schemaSql
-    if ($LASTEXITCODE -ne 0) {
-        Fail "pgTAP schema SQL generation failed"
-    }
-    $uninstallSql = Join-Path $sqlDir "uninstall_pgtap.sql"
-    & perl -e 'for (grep { /^CREATE /} reverse <>) { chomp; s/CREATE (OR REPLACE )?/DROP /; s/DROP (FUNCTION|VIEW|TYPE) /DROP $1 IF EXISTS /; s/ (DEFAULT|=)[ ]+[a-zA-Z0-9]+//g; print "$_;\n" }' (Join-Path $sqlDir "pgtap.sql") > $uninstallSql
-    if ($LASTEXITCODE -ne 0) {
-        Fail "pgTAP uninstall SQL generation failed"
-    }
-    Copy-Item -Force (Join-Path $sqlDir "pgtap.sql") (Join-Path $sqlDir "pgtap--1.3.5.sql")
-    Copy-Item -Force $coreSql (Join-Path $sqlDir "pgtap-core--1.3.5.sql")
-    Copy-Item -Force $schemaSql (Join-Path $sqlDir "pgtap-schema--1.3.5.sql")
-
-    $extensionDir = Join-Path $InstallDir "share/postgresql/extension"
-    New-Item -ItemType Directory -Force -Path $extensionDir | Out-Null
-    Copy-Item -Force (Join-Path $buildDir "pgtap.control") (Join-Path $extensionDir "pgtap.control")
-    Copy-Item -Force (Join-Path $sqlDir "pgtap*.sql") $extensionDir
-    Copy-Item -Force $uninstallSql $extensionDir
-    if (-not (Test-Path (Join-Path $extensionDir "pgtap--1.3.5.sql"))) {
-        Fail "pgTAP Windows staging did not produce pgtap--1.3.5.sql"
-    }
-}
-
-function Get-ExactExtensionCatalogRows([string]$Purpose) {
-    if ($null -eq $script:ExactExtensionCatalogRows) {
-        Push-Location $RepoRoot
-        try {
-            $catalogText = cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked -- --list-extensions
-            $exitCode = $LASTEXITCODE
-        } finally {
-            Pop-Location
-        }
-        if ($exitCode -ne 0 -or -not $catalogText) {
-            Fail "failed to read exact extension catalog for $Purpose"
-        }
-        $script:ExactExtensionCatalogRows = @($catalogText | Select-Object -Skip 1)
-    }
-    $script:ExactExtensionCatalogRows
-}
-
-function Get-SelectedEmbeddedExtensionModules {
-    if ($BuildExtensions -eq "0") {
-        return
-    }
-    $seen = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal)
-    foreach ($row in (Get-ExactExtensionCatalogRows "Windows embedded extension module linkage")) {
-        if (-not $row) {
-            continue
-        }
-        $columns = $row -split "`t", 12
-        if ($columns.Count -lt 12) {
-            Fail "malformed extension catalog row while selecting Windows embedded modules: $row"
-        }
-        $sqlName = $columns[0]
-        $stem = $columns[3]
-        if (-not (NativeExtension-Selected $sqlName) -or -not $stem -or $stem -eq "-") {
-            continue
-        }
-        if ($seen.Add($stem)) {
-            [PSCustomObject]@{
-                SqlName = $sqlName
-                Stem = $stem
-            }
-        }
-    }
-}
-
-function Test-SnowballRuntimeClosure {
-    $requiredFiles = @(
-        (Join-Path $InstallDir "lib/postgresql/dict_snowball.dll"),
-        (Join-Path $InstallDir "share/postgresql/snowball_create.sql")
-    )
-    foreach ($stopword in $SnowballStopwordFiles) {
-        $requiredFiles += (Join-Path $InstallDir "share/postgresql/tsearch_data/$stopword")
-    }
-    foreach ($required in $requiredFiles) {
-        if (-not (Test-Path -LiteralPath $required -PathType Leaf)) {
-            return $false
-        }
-        $file = Get-Item -LiteralPath $required -Force
-        if (($file.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0 -or $file.Length -le 0) {
-            return $false
-        }
-    }
-    return $true
-}
-
-function Runtime-Installed([string]$DesiredHash) {
-    $icuRuntimeReady = $true
-    foreach ($name in $IcuRuntimeDllNames) {
-        if (-not (Test-Path -LiteralPath (Join-Path $InstallDir "bin/$name") -PathType Leaf)) {
-            $icuRuntimeReady = $false
-            break
-        }
-    }
-    return $icuRuntimeReady -and
-        (Test-Path (Join-Path $InstallDir "bin/initdb.exe")) -and
-        (Test-Path (Join-Path $InstallDir "bin/postgres.exe")) -and
-        (Test-Path (Join-Path $InstallDir "bin/pg_config.exe")) -and
-        (Test-Path (Join-Path $InstallDir "include/pg_config.h")) -and
-        ((Get-Content -LiteralPath (Join-Path $InstallDir "include/pg_config.h") -Raw).Contains("#define USE_ICU 1")) -and
-        (Test-Path (Join-Path $InstallDir "share/postgresql/postgresql.conf.sample")) -and
-        (Test-Path (Join-Path $InstallDir "share/postgresql/timezone/UTC")) -and
-        (Test-SnowballRuntimeClosure) -and
-        (Test-Path (Join-Path $InstallDir ".oliphaunt-postgres-runtime.sha256")) -and
-        ((Get-Content (Join-Path $InstallDir ".oliphaunt-postgres-runtime.sha256") -Raw).Trim() -eq $DesiredHash) -and
-        (($BuildExtensions -ne "0") -or (BaseRuntimeOptionalExtensionsAbsent))
-}
-
-function Build-Runtime([string]$DesiredHash) {
-    if (Runtime-Installed $DesiredHash) {
-        return
-    }
-    Write-MesonNativeFile $RuntimeNativeFile $false
-    $options = @(
-        "--native-file", $RuntimeNativeFile,
-        "--prefix", $InstallDir,
-        "--buildtype=release",
-        "-Db_pch=false",
-        "-Dreadline=disabled",
-        "-Dicu=enabled",
-        "-Dldap=disabled",
-        "-Dllvm=disabled",
-        "-Dzlib=disabled",
-        "-Dzstd=disabled",
-        "-Dlz4=disabled",
-        "-Dnls=disabled",
-        "-Dssl=none",
-        "-Ddocs=disabled",
-        "-Dtap_tests=disabled",
-        "-Dplperl=disabled",
-        "-Dplpython=disabled",
-        "-Dpltcl=disabled"
-    )
-    if (-not (Test-Path $RuntimeBuildDir)) {
-        Invoke-Logged "meson-runtime-setup.log" { meson setup $RuntimeBuildDir $BuildDir @options }
-    }
-    Invoke-Logged "meson-runtime-compile.log" { meson compile -C $RuntimeBuildDir }
-    Invoke-Logged "meson-runtime-install.log" { meson install -C $RuntimeBuildDir }
-    Stage-WindowsIcuRuntime (Join-Path $InstallDir "bin")
-    New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
-    Install-WindowsPgtapExtension
-    Prune-BaseRuntimeOptionalExtensions
-    Set-Content -Path (Join-Path $InstallDir ".oliphaunt-postgres-runtime.sha256") -Value $DesiredHash -NoNewline
-    if (-not (Runtime-Installed $DesiredHash)) {
-        Fail "PostgreSQL Windows runtime install is incomplete"
-    }
-}
-
-function Prune-BaseRuntimeOptionalExtensions {
-    if ($BuildExtensions -ne "0") {
-        return
-    }
-
-    $extensionDir = Join-Path $InstallDir "share/postgresql/extension"
-    $moduleDir = Join-Path $InstallDir "lib/postgresql"
-    $shareDir = Join-Path $InstallDir "share/postgresql"
-    foreach ($row in (Get-ExactExtensionCatalogRows "base Windows runtime pruning")) {
-        if (-not $row) {
-            continue
-        }
-        $columns = $row -split "`t", 12
-        if ($columns.Count -lt 12) {
-            Fail "malformed extension catalog row while pruning Windows base runtime: $row"
-        }
-
-        $sqlName = $columns[0]
-        $stem = $columns[3]
-        $dataFiles = $columns[10]
-        if (Test-Path $extensionDir) {
-            Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $extensionDir "$sqlName.control")
-            Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $extensionDir "$sqlName--*.sql")
-        }
-        if ((Test-Path $moduleDir) -and $stem -and $stem -ne "-") {
-            foreach ($suffix in @("dll", "so", "dylib")) {
-                Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $moduleDir "$stem.$suffix")
-            }
-        }
-        if ($dataFiles -and $dataFiles -ne "-") {
-            foreach ($dataFile in $dataFiles.Split(",")) {
-                if ($dataFile) {
-                    Remove-Item -Recurse -Force -ErrorAction SilentlyContinue (Join-Path $shareDir $dataFile)
-                }
-            }
-        }
-    }
-
-    if (Test-Path $extensionDir) {
-        Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $extensionDir "postgis*.sql")
-        Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $extensionDir "rtpostgis*.sql")
-        Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $extensionDir "uninstall_postgis.sql")
-        Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $extensionDir "uninstall_legacy.sql")
-        Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $extensionDir "pgtap-*.sql")
-        Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $extensionDir "uninstall_pgtap.sql")
-    }
-    Remove-Item -Recurse -Force -ErrorAction SilentlyContinue (Join-Path $shareDir "contrib")
-    Remove-Item -Recurse -Force -ErrorAction SilentlyContinue (Join-Path $shareDir "proj")
-}
-
-function BaseRuntimeOptionalExtensionsAbsent {
-    if (-not (Test-Path $InstallDir)) {
-        return $false
-    }
-
-    $extensionDir = Join-Path $InstallDir "share/postgresql/extension"
-    $moduleDir = Join-Path $InstallDir "lib/postgresql"
-    $shareDir = Join-Path $InstallDir "share/postgresql"
-    foreach ($row in (Get-ExactExtensionCatalogRows "base Windows runtime validation")) {
-        if (-not $row) {
-            continue
-        }
-        $columns = $row -split "`t", 12
-        if ($columns.Count -lt 12) {
-            Fail "malformed extension catalog row while validating Windows base runtime: $row"
-        }
-
-        $sqlName = $columns[0]
-        $stem = $columns[3]
-        $dataFiles = $columns[10]
-        if ((Test-Path $extensionDir) -and (Test-Path (Join-Path $extensionDir "$sqlName.control"))) {
-            return $false
-        }
-        if ((Test-Path $extensionDir) -and (Get-ChildItem -Path $extensionDir -Filter "$sqlName--*.sql" -File -ErrorAction SilentlyContinue | Select-Object -First 1)) {
-            return $false
-        }
-        if ((Test-Path $moduleDir) -and $stem -and $stem -ne "-") {
-            foreach ($suffix in @("dll", "so", "dylib")) {
-                if (Test-Path (Join-Path $moduleDir "$stem.$suffix")) {
-                    return $false
-                }
-            }
-        }
-        if ($dataFiles -and $dataFiles -ne "-") {
-            foreach ($dataFile in $dataFiles.Split(",")) {
-                if ($dataFile -and (Test-Path (Join-Path $shareDir $dataFile))) {
-                    return $false
-                }
-            }
-        }
-    }
-
-    if ((Test-Path (Join-Path $shareDir "contrib")) -or (Test-Path (Join-Path $shareDir "proj"))) {
-        return $false
-    }
-
-    return $true
-}
-
-function Write-MesonNativeFile([string]$Path, [bool]$UseCrtSecureNoWarnings) {
-    $content = @(
-        "[binaries]",
-        "c = 'cl.exe'",
-        "cpp = 'cl.exe'",
-        "ar = 'lib.exe'"
-    )
-    if ($UseCrtSecureNoWarnings) {
-        $content += @(
-            "",
-            "[built-in options]",
-            "c_args = ['/D_CRT_SECURE_NO_WARNINGS']"
-        )
-    }
-    Set-Content -Path $Path -Value ($content -join "`n") -Encoding UTF8
-}
-
-function Build-EmbeddedBackend {
-    Write-MesonNativeFile $EmbeddedNativeFile $true
-    $options = @(
-        "--native-file", $EmbeddedNativeFile,
-        "--prefix", $InstallDir,
-        "--buildtype=release",
-        "-Doliphaunt_embedded=true",
-        "-Doliphaunt_embedded_module_provider=",
-        "-Db_pch=false",
-        "-Dreadline=disabled",
-        "-Dicu=enabled",
-        "-Dldap=disabled",
-        "-Dllvm=disabled",
-        "-Dzlib=disabled",
-        "-Dzstd=disabled",
-        "-Dlz4=disabled",
-        "-Dnls=disabled",
-        "-Dssl=none",
-        "-Ddocs=disabled",
-        "-Dtap_tests=disabled",
-        "-Dplperl=disabled",
-        "-Dplpython=disabled",
-        "-Dpltcl=disabled"
-    )
-    $previousCflags = $env:CFLAGS
-    $env:CFLAGS = ""
-    try {
-        if (-not (Test-Path $EmbeddedBuildDir)) {
-            Invoke-Logged "meson-embedded-setup.log" { meson setup $EmbeddedBuildDir $BuildDir @options }
-        }
-        Invoke-Logged "meson-embedded-bootstrap-provider.log" {
-            meson configure $EmbeddedBuildDir "-Doliphaunt_embedded_module_provider="
-        }
-        Invoke-Logged "meson-embedded-postgres-lib.log" { meson compile -C $EmbeddedBuildDir postgres_lib }
-        Invoke-Logged "meson-embedded-postgres-def.log" { meson compile -C $EmbeddedBuildDir postgres.def }
-        Invoke-Logged "meson-embedded-plpgsql.log" { meson compile -C $EmbeddedBuildDir plpgsql }
-    } finally {
-        $env:CFLAGS = $previousCflags
-    }
-}
-
-function Assert-SymbolPresent([string]$Binary, [string]$Symbol) {
-    $stem = [System.IO.Path]::GetFileNameWithoutExtension($Binary)
-    $log = Join-Path $WorkRoot "dumpbin-symbols-$stem.log"
-    dumpbin.exe /symbols $Binary *> $log
-    if ($LASTEXITCODE -ne 0) {
-        Get-Content $log -Tail 160 | Write-Error
-        Fail "dumpbin failed while inspecting $Binary"
-    }
-    $symbols = Get-Content $log -Raw
-    if ($symbols -notmatch "(^|[^A-Za-z0-9_])_?$([regex]::Escape($Symbol))([^A-Za-z0-9_]|$)") {
-        Get-Content $log -Tail 160 | Write-Error
-        Fail "$Binary does not define required embedded PostgreSQL symbol $Symbol"
-    }
-}
-
-function First-File([string]$Root, [string[]]$Filters) {
-    foreach ($filter in $Filters) {
-        $item = Get-ChildItem -Path $Root -Recurse -Filter $filter -File | Select-Object -First 1
-        if ($item) {
-            return $item.FullName
-        }
-    }
-    Fail "could not find any of $($Filters -join ', ') under $Root"
-}
-
-function First-PostgresArchive([string]$Root, [string]$BaseName) {
-    $file = First-File $Root @("$BaseName.lib", "$BaseName.a")
-    if (-not $file) {
-        Fail "could not find PostgreSQL archive $BaseName under $Root"
-    }
-    $file
-}
-
-function First-PlpgsqlObject([string]$Source) {
-    $root = Join-Path $EmbeddedBuildDir "src/pl/plpgsql/src"
-    if (-not (Test-Path $root)) {
-        Fail "could not find embedded PL/pgSQL object root under $root"
-    }
-    $matches = New-Object System.Collections.Generic.List[string]
-    foreach ($filter in @("$Source.c.obj", "meson-generated_*_$Source.c.obj", "*$Source.c.obj")) {
-        Get-ChildItem -Path $root -Recurse -Filter $filter -File |
-            ForEach-Object { $matches.Add($_.FullName) | Out-Null }
-    }
-    $unique = @($matches | Sort-Object -Unique)
-    if ($unique.Count -eq 1) {
-        return $unique[0]
-    }
-    if ($unique.Count -eq 0) {
-        Fail "could not find embedded PL/pgSQL object for $Source under $root"
-    }
-    Fail "ambiguous embedded PL/pgSQL object for $Source under $root`: $($unique -join ', ')"
-}
-
-function Embedded-PlpgsqlObjects {
-    $objects = New-Object System.Collections.Generic.List[string]
-    foreach ($source in @("pl_comp", "pl_exec", "pl_funcs", "pl_gram", "pl_handler", "pl_scanner")) {
-        $objects.Add((First-PlpgsqlObject $source)) | Out-Null
-    }
-    Assert-SymbolPresent (First-PlpgsqlObject "pl_gram") "plpgsql_yyparse"
-    Assert-SymbolPresent (First-PlpgsqlObject "pl_handler") "plpgsql_call_handler"
-    $objects
-}
-
-function Compile-LiboliphauntSources {
-    Remove-Item -Recurse -Force $ObjDir -ErrorAction SilentlyContinue
-    New-Item -ItemType Directory -Force -Path $ObjDir | Out-Null
-    $objects = New-Object System.Collections.Generic.List[string]
-    foreach ($source in $LiboliphauntSources) {
-        $object = Join-Path $ObjDir ([System.IO.Path]::GetFileNameWithoutExtension($source) + ".obj")
-        $sourceName = [System.IO.Path]::GetFileNameWithoutExtension($source)
-        Invoke-Logged "compile-liboliphaunt-$sourceName.log" {
-            cl.exe /nologo /std:c11 /O2 /Zi /MD /DOLIPHAUNT_EMBEDDED /DOLIPHAUNT_BUILTIN_PLPGSQL /DOLIPHAUNT_BUILDING_DLL /D_CRT_SECURE_NO_WARNINGS `
-                "/I$(Join-Path $RepoRoot "src/runtimes/liboliphaunt/native/include")" `
-                "/I$(Join-Path $RepoRoot "src/runtimes/liboliphaunt/native/src")" `
-                /c $source "/Fo$object"
-        }
-        $objects.Add($object)
-    }
-    $objects
-}
-
-function Link-LiboliphauntDll([System.Collections.Generic.List[string]]$Objects) {
-    New-Item -ItemType Directory -Force -Path (Split-Path -Parent $DllOut), (Split-Path -Parent $ImportLibOut) | Out-Null
-    $postgresLib = First-PostgresArchive $EmbeddedBuildDir "postgres_lib"
-    $postgresDef = First-File $EmbeddedBuildDir "postgres.def"
-    Assert-SymbolPresent $postgresLib "oliphaunt_embedded_main"
-    $exports = @(
-        "oliphaunt_init",
-        "oliphaunt_exec_protocol",
-        "oliphaunt_exec_simple_query",
-        "oliphaunt_exec_protocol_raw_stream",
-        "oliphaunt_backup",
-        "oliphaunt_restore",
-        "oliphaunt_init_with_error",
-        "oliphaunt_exec_protocol_with_error",
-        "oliphaunt_exec_simple_query_with_error",
-        "oliphaunt_exec_protocol_raw_stream_with_error",
-        "oliphaunt_backup_with_error",
-        "oliphaunt_restore_with_error",
-        "oliphaunt_detach_with_error",
-        "oliphaunt_cancel",
-        "oliphaunt_detach",
-        "oliphaunt_logical_generation",
-        "oliphaunt_close_if_generation",
-        "oliphaunt_close",
-        "oliphaunt_register_static_extensions",
-        "oliphaunt_copy_last_error",
-        "oliphaunt_version",
-        "oliphaunt_free_response",
-        "oliphaunt_embedded_kill",
-        "oliphaunt_embedded_raise"
-    )
-    $response = Join-Path $OutDir "link-oliphaunt.rsp"
-    $lines = @(
-        "/nologo",
-        "/DLL",
-        "/INCREMENTAL:NO",
-        "/OUT:$DllOut",
-        "/IMPLIB:$ImportLibOut",
-        "/PDB:$(Join-Path $OutDir "bin/oliphaunt.pdb")",
-        "/DEF:$postgresDef",
-        "/WHOLEARCHIVE:$postgresLib"
-    )
-    foreach ($export in $exports) {
-        $lines += "/EXPORT:$export"
-    }
-    foreach ($object in $Objects) {
-        $lines += $object
-    }
-    foreach ($object in (Embedded-PlpgsqlObjects)) {
-        $lines += $object
-    }
-    $lines += @(
-        (Join-Path $IcuWindowsRoot "lib64/icuin.lib"),
-        (Join-Path $IcuWindowsRoot "lib64/icuuc.lib"),
-        (Join-Path $IcuWindowsRoot "lib64/icudt.lib"),
-        "ws2_32.lib",
-        "secur32.lib",
-        "advapi32.lib",
-        "shell32.lib",
-        "user32.lib",
-        "bcrypt.lib"
-    )
-    Set-Content -Path $response -Value ($lines -join "`r`n")
-    link.exe "@$response"
-    if ($LASTEXITCODE -ne 0) {
-        Fail "failed to link $DllOut"
-    }
-}
-
-function Get-ModuleHostBinding([string]$Binary) {
-    if (-not (Test-Path -LiteralPath $Binary -PathType Leaf)) {
-        return "missing"
-    }
-    $dependencies = dumpbin.exe /dependents $Binary 2>$null | Out-String
-    if ($LASTEXITCODE -ne 0) {
-        return "invalid"
-    }
-    $serverBound = $dependencies -match '(?im)^\s*postgres\.exe\s*$'
-    $embeddedBound = $dependencies -match '(?im)^\s*oliphaunt\.dll\s*$'
-    if ($serverBound -and $embeddedBound) {
-        return "crossed"
-    }
-    if ($serverBound) {
-        return "server"
-    }
-    if ($embeddedBound) {
-        return "embedded"
-    }
-    return "neutral"
-}
-
-function Test-EmbeddedModuleHostContract([string]$Binary, [bool]$RequireProvider = $false) {
-    $binding = Get-ModuleHostBinding $Binary
-    if ($RequireProvider) {
-        return $binding -eq "embedded"
-    }
-    return $binding -eq "embedded" -or $binding -eq "neutral"
-}
-
-function Assert-EmbeddedModuleHostContract([string]$Binary, [bool]$RequireProvider = $false) {
-    if (-not (Test-EmbeddedModuleHostContract $Binary $RequireProvider)) {
-        $binding = Get-ModuleHostBinding $Binary
-        $dependencies = if (Test-Path -LiteralPath $Binary -PathType Leaf) {
-            (dumpbin.exe /dependents $Binary 2>$null | Out-String).Trim()
-        } else {
-            ""
-        }
-        $expectation = if ($RequireProvider) {
-            "must import oliphaunt.dll and must not import postgres.exe"
-        } else {
-            "must not import postgres.exe and may be host-neutral or import oliphaunt.dll"
-        }
-        Fail "$Binary violates the embedded module host contract: $expectation; observed binding: $binding; dependencies: $dependencies"
-    }
-}
-
-function Test-ServerModuleHostContract([string]$Binary) {
-    $binding = Get-ModuleHostBinding $Binary
-    return $binding -eq "server" -or $binding -eq "neutral"
-}
-
-function Assert-ServerModuleHostContract([string]$Binary) {
-    if (-not (Test-ServerModuleHostContract $Binary)) {
-        $binding = Get-ModuleHostBinding $Binary
-        $dependencies = if (Test-Path -LiteralPath $Binary -PathType Leaf) {
-            (dumpbin.exe /dependents $Binary 2>$null | Out-String).Trim()
-        } else {
-            ""
-        }
-        Fail "$Binary violates the server module host contract: must not import oliphaunt.dll and may be host-neutral or import postgres.exe; observed binding: $binding; dependencies: $dependencies"
-    }
-}
-
-function Test-CompatibleModuleProfiles([string]$ServerBinary, [string]$EmbeddedBinary) {
-    if (-not (Test-ServerModuleHostContract $ServerBinary) -or
-        -not (Test-EmbeddedModuleHostContract $EmbeddedBinary)) {
-        return $false
-    }
-    $serverSha256 = Get-FileSha256 $ServerBinary
-    $embeddedSha256 = Get-FileSha256 $EmbeddedBinary
-    if ($serverSha256 -ne $embeddedSha256) {
-        return $true
-    }
-    return (Get-ModuleHostBinding $ServerBinary) -eq "neutral" -and
-        (Get-ModuleHostBinding $EmbeddedBinary) -eq "neutral"
-}
-
-function Assert-CompatibleModuleProfiles([string]$ServerBinary, [string]$EmbeddedBinary) {
-    Assert-ServerModuleHostContract $ServerBinary
-    Assert-EmbeddedModuleHostContract $EmbeddedBinary
-    $serverSha256 = Get-FileSha256 $ServerBinary
-    $embeddedSha256 = Get-FileSha256 $EmbeddedBinary
-    if ($serverSha256 -eq $embeddedSha256 -and
-        ((Get-ModuleHostBinding $ServerBinary) -ne "neutral" -or
-         (Get-ModuleHostBinding $EmbeddedBinary) -ne "neutral")) {
-        Fail "Windows host-bound extension module server and embedded profiles must have distinct bytes: $ServerBinary and $EmbeddedBinary both have SHA-256 $serverSha256"
-    }
-}
-
-function Find-EmbeddedModuleBinary([string]$Stem) {
-    $matches = @(
-        Get-ChildItem -Path $EmbeddedBuildDir -Recurse -Filter "$Stem.dll" -File |
-            Sort-Object -Property FullName
-    )
-    if ($matches.Count -ne 1) {
-        $observed = if ($matches.Count -eq 0) { "" } else { ($matches.FullName -join ", ") }
-        Fail "expected exactly one Meson embedded module output for $Stem.dll; observed $observed"
-    }
-    $matches[0].FullName
-}
-
-function Remove-EmbeddedModuleStage {
-    if (-not (Test-Path -LiteralPath $EmbeddedModulesDir)) {
-        return
-    }
-    $embeddedModulesInfo = Get-Item -LiteralPath $EmbeddedModulesDir -Force
-    if (($embeddedModulesInfo.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) {
-        Remove-Item -LiteralPath $EmbeddedModulesDir -Force
-    } else {
-        Remove-Item -LiteralPath $EmbeddedModulesDir -Recurse -Force
-    }
-}
-
-function Build-EmbeddedModules {
-    if (-not (Test-Path -LiteralPath $ImportLibOut -PathType Leaf)) {
-        Fail "cannot build embedded extension modules before the host import library exists at $ImportLibOut"
-    }
-
-    $selectedModules = @(Get-SelectedEmbeddedExtensionModules)
-    $targetNames = @($EmbeddedCoreModuleStems) + @($selectedModules | ForEach-Object { $_.Stem })
-    $targetNames = @($targetNames | Sort-Object -Unique)
-    $provider = Meson-Path $ImportLibOut
-    Invoke-Logged "meson-embedded-module-provider.log" {
-        meson configure $EmbeddedBuildDir "-Doliphaunt_embedded_module_provider=$provider"
-    }
-    Invoke-Logged "meson-embedded-modules.log" {
-        meson compile -C $EmbeddedBuildDir @targetNames
-    }
-
-    Remove-EmbeddedModuleStage
-    New-Item -ItemType Directory -Force -Path $EmbeddedModulesDir | Out-Null
-    foreach ($stem in $EmbeddedCoreModuleStems) {
-        $source = Find-EmbeddedModuleBinary $stem
-        Assert-EmbeddedModuleHostContract $source $true
-        $staged = Join-Path $EmbeddedModulesDir "$stem.dll"
-        Copy-Item -LiteralPath $source -Destination $staged -Force
-        Assert-EmbeddedModuleHostContract $staged $true
-    }
-
-    foreach ($module in $selectedModules) {
-        $source = Find-EmbeddedModuleBinary $module.Stem
-        Assert-EmbeddedModuleHostContract $source
-        $staged = Join-Path $EmbeddedModulesDir "$($module.Stem).dll"
-        Copy-Item -LiteralPath $source -Destination $staged -Force
-        Assert-EmbeddedModuleHostContract $staged
-    }
-
-    $installedModuleDir = Join-Path $InstallDir "lib/postgresql"
-    foreach ($stem in $EmbeddedCoreModuleStems) {
-        $server = Join-Path $installedModuleDir "$stem.dll"
-        $embedded = Join-Path $EmbeddedModulesDir "$stem.dll"
-        Assert-CompatibleModuleProfiles $server $embedded
-    }
-    foreach ($module in $selectedModules) {
-        $server = Join-Path $installedModuleDir "$($module.Stem).dll"
-        $embedded = Join-Path $EmbeddedModulesDir "$($module.Stem).dll"
-        Assert-CompatibleModuleProfiles $server $embedded
-    }
-}
-
-function Embedded-ModulesReady {
-    $installedModuleDir = Join-Path $InstallDir "lib/postgresql"
-    foreach ($stem in $EmbeddedCoreModuleStems) {
-        $server = Join-Path $installedModuleDir "$stem.dll"
-        $embedded = Join-Path $EmbeddedModulesDir "$stem.dll"
-        if (-not (Test-EmbeddedModuleHostContract $embedded $true) -or
-            -not (Test-CompatibleModuleProfiles $server $embedded)) {
-            return $false
-        }
-    }
-    foreach ($module in @(Get-SelectedEmbeddedExtensionModules)) {
-        $server = Join-Path $InstallDir "lib/postgresql/$($module.Stem).dll"
-        $embedded = Join-Path $EmbeddedModulesDir "$($module.Stem).dll"
-        if (-not (Test-CompatibleModuleProfiles $server $embedded)) {
-            return $false
-        }
-    }
-    return $true
-}
-
-function Artifact-Ready {
-    if (-not (Test-Path $DllOut) -or
-        -not (Test-Path $ImportLibOut) -or
-        -not (Embedded-ModulesReady)) {
-        return $false
-    }
-    foreach ($name in $IcuRuntimeDllNames) {
-        if (-not (Test-Path -LiteralPath (Join-Path $OutDir "bin/$name") -PathType Leaf)) {
-            return $false
-        }
-    }
-    if (-not (Test-VcRuntimeClosure)) {
-        return $false
-    }
-    $exports = dumpbin.exe /exports $DllOut 2>$null | Out-String
-    foreach ($symbol in @(
-        "oliphaunt_init",
-        "oliphaunt_exec_protocol",
-        "oliphaunt_exec_simple_query",
-        "oliphaunt_exec_protocol_raw_stream",
-        "oliphaunt_backup",
-        "oliphaunt_restore",
-        "oliphaunt_init_with_error",
-        "oliphaunt_exec_protocol_with_error",
-        "oliphaunt_exec_simple_query_with_error",
-        "oliphaunt_exec_protocol_raw_stream_with_error",
-        "oliphaunt_backup_with_error",
-        "oliphaunt_restore_with_error",
-        "oliphaunt_detach_with_error",
-        "oliphaunt_cancel",
-        "oliphaunt_detach",
-        "oliphaunt_logical_generation",
-        "oliphaunt_close_if_generation",
-        "oliphaunt_close",
-        "oliphaunt_register_static_extensions",
-        "oliphaunt_copy_last_error",
-        "oliphaunt_version",
-        "oliphaunt_free_response"
-    )) {
-        if ($exports -notmatch "\b$symbol\b") {
-            return $false
-        }
-    }
-    $true
-}
-
-if (-not $IsWindows) {
-    Fail "Windows liboliphaunt build must run on Windows"
-}
-
-Require-Command git
-Require-Command curl.exe
-Require-Command bun
-Require-Command cargo
-Import-MsvcEnvironment
-Prefer-NativePerl
-$env:CCACHE_DISABLE = "1"
-Ensure-MesonTools
-Configure-MsvcToolchainPath
-
-$desiredHash = Get-DesiredHash
-Prepare-Source $desiredHash
-Prepare-WindowsExtensionInputs
-Prepare-WindowsIcuData
-$env:ICU_ROOT = $IcuWindowsRoot
-
-if ($CheckCurrent) {
-    if ((Runtime-Installed $desiredHash) -and (Artifact-Ready) -and (Test-Path $Stamp) -and ((Get-Content $Stamp -Raw).Trim() -eq $desiredHash)) {
-        Write-Output "Windows $TargetId liboliphaunt DLL is current"
-        exit 0
-    }
-    Write-Error "Windows $TargetId liboliphaunt DLL is missing or stale"
-    exit 1
-}
-
-Build-Runtime $desiredHash
-Build-EmbeddedBackend
-$objects = Compile-LiboliphauntSources
-Link-LiboliphauntDll $objects
-Stage-WindowsIcuRuntime (Join-Path $OutDir "bin")
-Build-EmbeddedModules
-Stage-VcRuntimeClosure
-if (-not (Artifact-Ready)) {
-    Fail "Windows liboliphaunt DLL did not pass export checks"
-}
-Set-Content -Path $Stamp -Value $desiredHash -NoNewline
-Write-Output $DllOut
diff --git a/src/runtimes/liboliphaunt/native/bin/check-external-extension-pins.sh b/src/runtimes/liboliphaunt/native/bin/check-external-extension-pins.sh
deleted file mode 100755
index a38bb3981..000000000
--- a/src/runtimes/liboliphaunt/native/bin/check-external-extension-pins.sh
+++ /dev/null
@@ -1,142 +0,0 @@
-#!/usr/bin/env sh
-set -eu
-
-script_dir="$(cd "$(dirname "$0")" && pwd)"
-. "$script_dir/common.sh"
-root="$(oliphaunt_resolve_repo_root "$script_dir")"
-manifest="$root/src/runtimes/liboliphaunt/native/postgres18/external-extensions.toml"
-online=0
-
-case "${1:-}" in
-  "")
-    ;;
-  --online)
-    online=1
-    ;;
-  *)
-    echo "usage: src/runtimes/liboliphaunt/native/bin/check-external-extension-pins.sh [--online]" >&2
-    exit 2
-    ;;
-esac
-
-require_line() {
-  line="$1"
-  if ! grep -Fxq "$line" "$manifest"; then
-    echo "external extension source manifest is missing: $line" >&2
-    exit 1
-  fi
-}
-
-check_checkout_if_present() {
-  name="$1"
-  relative_checkout="$2"
-  expected_commit="$3"
-  checkout="$root/$relative_checkout"
-
-  if [ ! -d "$checkout/.git" ]; then
-    echo "external extension checkout not present for $name: $relative_checkout"
-    return 0
-  fi
-
-  actual_commit="$(git -C "$checkout" rev-parse HEAD)"
-  if [ "$actual_commit" != "$expected_commit" ]; then
-    cat >&2 <&2 <}
-MSG
-    exit 1
-  fi
-  echo "external extension remote pin verified for $name: $ref -> $expected_commit"
-}
-
-[ -f "$manifest" ] || {
-  echo "missing external extension source manifest: $manifest" >&2
-  exit 1
-}
-
-require_line 'schema = "liboliphaunt-external-extensions-v2"'
-require_line 'pg_major = 18'
-
-if grep -Eq '^[[:space:]]*pack[[:space:]]*=' "$manifest"; then
-  echo "external extension manifest must not declare extension selection aliases; select exact extensions only" >&2
-  exit 1
-fi
-
-require_line 'id = "pggraph"'
-require_line 'sql_name = "graph"'
-require_line 'module_stem = "graph"'
-require_line 'upstream = "https://github.com/evokoa/pggraph.git"'
-require_line 'source_ref = "main"'
-require_line 'commit = "4ea3c3206811deda03de136b4f465a2cf9bc8e72"'
-require_line 'checkout = "target/oliphaunt-sources/checkouts/pggraph"'
-require_line 'source_subdir = "graph"'
-require_line 'license = "Apache-2.0"'
-require_line 'redistribution = "allowed"'
-require_line 'pgrx_version = "0.18.0"'
-require_line 'pg_feature = "pg18"'
-
-require_line 'id = "paradedb-pg-search"'
-require_line 'sql_name = "pg_search"'
-require_line 'module_stem = "pg_search"'
-require_line 'upstream = "https://github.com/paradedb/paradedb.git"'
-require_line 'source_ref = "v0.23.4"'
-require_line 'commit = "c07921a78f3d24cbb0251b31a1150a7db600af5a"'
-require_line 'checkout = "target/oliphaunt-sources/checkouts/paradedb"'
-require_line 'source_subdir = "pg_search"'
-require_line 'license = "AGPL-3.0"'
-require_line 'redistribution = "requires-commercial-license"'
-require_line 'pgrx_version = "0.18.0"'
-require_line 'pg_feature = "pg18"'
-require_line 'requires_shared_preload = true'
-
-check_checkout_if_present \
-  pggraph \
-  target/oliphaunt-sources/checkouts/pggraph \
-  4ea3c3206811deda03de136b4f465a2cf9bc8e72
-
-check_checkout_if_present \
-  paradedb-pg-search \
-  target/oliphaunt-sources/checkouts/paradedb \
-  c07921a78f3d24cbb0251b31a1150a7db600af5a
-
-check_remote_if_requested \
-  pggraph \
-  https://github.com/evokoa/pggraph.git \
-  HEAD \
-  4ea3c3206811deda03de136b4f465a2cf9bc8e72
-
-check_remote_if_requested \
-  paradedb-pg-search \
-  https://github.com/paradedb/paradedb.git \
-  refs/tags/v0.23.4 \
-  c07921a78f3d24cbb0251b31a1150a7db600af5a
-
-echo "external extension source pins passed"
diff --git a/src/runtimes/liboliphaunt/native/bin/common.sh b/src/runtimes/liboliphaunt/native/bin/common.sh
deleted file mode 100755
index b40fd560c..000000000
--- a/src/runtimes/liboliphaunt/native/bin/common.sh
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/env sh
-
-oliphaunt_resolve_repo_root() {
-  script_dir="${1:?oliphaunt_resolve_repo_root requires a script directory}"
-  if repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)"; then
-    printf '%s\n' "$repo_root"
-    return 0
-  fi
-  cd "$script_dir/../../../../.." && pwd
-}
-
-oliphaunt_native_release_cflags() {
-  printf '%s' '-O2'
-  case "${OLIPHAUNT_NATIVE_DEBUG_SYMBOLS:-0}" in
-    1|true|TRUE|yes|YES|on|ON)
-      printf ' %s' '-g'
-      ;;
-  esac
-  while [ "$#" -gt 0 ]; do
-    printf ' %s' "$1"
-    shift
-  done
-}
-
-# Read the complete diagnostic payload before deciding whether it matches.
-# A producer piped into `grep -q`/`rg -q` can receive SIGPIPE after the matcher
-# exits on its first hit. Under `set -o pipefail`, that turns a successful
-# readiness probe into a false failure. These helpers deliberately consume the
-# complete payload so callers remain deterministic for large symbol tables.
-oliphaunt_text_matches_ere() {
-  [ "$#" -eq 2 ] || {
-    echo "oliphaunt_text_matches_ere requires text and an extended regular expression" >&2
-    return 2
-  }
-  printf '%s\n' "$1" | awk -v oliphaunt_pattern="$2" '
-    $0 ~ oliphaunt_pattern { oliphaunt_found = 1 }
-    END { exit oliphaunt_found ? 0 : 1 }
-  '
-}
-
-oliphaunt_text_has_nm_symbol() {
-  [ "$#" -eq 2 ] || {
-    echo "oliphaunt_text_has_nm_symbol requires nm output and a symbol" >&2
-    return 2
-  }
-  printf '%s\n' "$1" | awk -v oliphaunt_symbol="$2" '
-    $NF == oliphaunt_symbol || $NF == "_" oliphaunt_symbol { oliphaunt_found = 1 }
-    END { exit oliphaunt_found ? 0 : 1 }
-  '
-}
-
-oliphaunt_tail_log_excerpt() {
-  [ "$#" -ge 1 ] && [ "$#" -le 3 ] || {
-    echo "oliphaunt_tail_log_excerpt requires a path and optional line/column limits" >&2
-    return 2
-  }
-  [ -f "$1" ] || return 0
-  tail -n "${2:-40}" "$1" | awk -v oliphaunt_columns="${3:-2000}" '
-    length($0) > oliphaunt_columns {
-      print substr($0, 1, oliphaunt_columns) " ... [line truncated]"
-      next
-    }
-    { print }
-  '
-}
-
-oliphaunt_native_external_extension_source_rel() {
-  [ "$#" -eq 2 ] || {
-    echo "oliphaunt_native_external_extension_source_rel requires a repository root and extension id" >&2
-    return 2
-  }
-  case "$2" in
-    postgis)
-      printf '%s\n' 'target/oliphaunt-sources/checkouts/postgis'
-      ;;
-    *)
-      awk -F '\t' -v extension="$2" '
-        NR > 1 && ($1 == extension || $3 == "target/oliphaunt-sources/checkouts/" extension) {
-          print $3
-          found = 1
-          exit
-        }
-        END { exit found ? 0 : 1 }
-      ' "$1/src/extensions/generated/pgxs-build.tsv"
-      ;;
-  esac
-}
diff --git a/src/runtimes/liboliphaunt/native/bin/icu.sh b/src/runtimes/liboliphaunt/native/bin/icu.sh
deleted file mode 100755
index 131d5c108..000000000
--- a/src/runtimes/liboliphaunt/native/bin/icu.sh
+++ /dev/null
@@ -1,449 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-oliphaunt_icu_source_dir() {
-  local repo_root="${1:?repo root is required}"
-  printf '%s\n' "${OLIPHAUNT_ICU_SOURCE_DIR:-$repo_root/target/oliphaunt-sources/checkouts/icu/icu4c/source}"
-}
-
-oliphaunt_icu_source_commit() {
-  local source_dir="${1:?ICU source dir is required}"
-  git -C "$source_dir/../../" rev-parse HEAD
-}
-
-oliphaunt_icu_canonical_data_archive() {
-  local source_dir="${1:?ICU source dir is required}"
-  printf '%s\n' "${OLIPHAUNT_ICU_DATA_ARCHIVE:-$source_dir/../../../icu-data/icudt76l.dat}"
-}
-
-oliphaunt_icu_canonical_data_sha256() {
-  printf '%s\n' 'dbc14e1c48ef209f230adc2aa6854bd4d6bba8f5e6733e75897a4263d97920f0'
-}
-
-oliphaunt_icu_require_canonical_data() {
-  local archive="${1:?ICU data archive is required}"
-  [ -f "$archive" ] || {
-    echo "missing pinned ICU 76.1 data archive at $archive; run \`cargo run -p xtask -- assets fetch\` first" >&2
-    return 1
-  }
-  local actual
-  actual="$(shasum -a 256 "$archive" | awk '{print $1}')"
-  [ "$actual" = "$(oliphaunt_icu_canonical_data_sha256)" ] || {
-    echo "ICU data archive checksum mismatch: expected $(oliphaunt_icu_canonical_data_sha256), got $actual" >&2
-    return 1
-  }
-}
-
-oliphaunt_icu_script_sha256() {
-  local script_dir="${1:?script dir is required}"
-  shasum -a 256 "$script_dir/icu.sh" | awk '{print $1}'
-}
-
-oliphaunt_icu_native_tools_stamp() {
-  local source_dir="$1"
-  local script_dir="$2"
-  {
-    printf 'schema=oliphaunt-icu-native-tools-v4\n'
-    printf 'source=%s\n' "$(oliphaunt_icu_source_commit "$source_dir")"
-    printf 'script=%s\n' "$(oliphaunt_icu_script_sha256 "$script_dir")"
-    printf 'configure=static-no-tests-no-samples-no-extras-no-icuio-no-layoutex-tools-only\n'
-  } | shasum -a 256 | awk '{print $1}'
-}
-
-oliphaunt_icu_target_stamp() {
-  local source_dir="$1"
-  local script_dir="$2"
-  local target_label="$3"
-  local host="$4"
-  local cc="$5"
-  local cxx="$6"
-  local ar="$7"
-  local ranlib="$8"
-  local cflags="$9"
-  local cxxflags="${10}"
-  local ldflags="${11}"
-  {
-    printf 'schema=oliphaunt-icu-target-v8\n'
-    printf 'source=%s\n' "$(oliphaunt_icu_source_commit "$source_dir")"
-    printf 'script=%s\n' "$(oliphaunt_icu_script_sha256 "$script_dir")"
-    printf 'target=%s\n' "$target_label"
-    printf 'host=%s\n' "$host"
-    printf 'cc=%s\n' "$cc"
-    printf 'cxx=%s\n' "$cxx"
-    printf 'ar=%s\n' "$ar"
-    printf 'ranlib=%s\n' "$ranlib"
-    printf 'cflags=%s\n' "$cflags"
-    printf 'cxxflags=%s\n' "$cxxflags"
-    printf 'ldflags=%s\n' "$ldflags"
-    printf 'canonical-data-sha256=%s\n' "$(oliphaunt_icu_canonical_data_sha256)"
-    printf 'configure=files-data-static-libs-static-consumer-no-extra-target-tools-stub-data-archive-pinned-upstream-data\n'
-  } | shasum -a 256 | awk '{print $1}'
-}
-
-oliphaunt_icu_require_source() {
-  local source_dir="${1:?ICU source dir is required}"
-  if [ ! -x "$source_dir/configure" ]; then
-    echo "missing ICU source checkout at $source_dir; run \`cargo run -p xtask -- assets fetch\` first" >&2
-    return 1
-  fi
-}
-
-oliphaunt_icu_native_tool_names() {
-  printf '%s\n' \
-    makeconv \
-    gencnval \
-    gencfu \
-    genbrk \
-    gendict \
-    genrb \
-    gensprep \
-    icupkg \
-    pkgdata \
-    genccode \
-    gencmn
-}
-
-oliphaunt_icu_native_tools_ready() {
-  local native_build_dir="${1:?native build dir is required}"
-  [ -f "$native_build_dir/icudefs.mk" ] || return 1
-  [ -f "$native_build_dir/config/icucross.mk" ] || return 1
-  [ -f "$native_build_dir/config/icucross.inc" ] || return 1
-  [ -f "$native_build_dir/lib/libicui18n.a" ] || return 1
-  [ -f "$native_build_dir/lib/libicuuc.a" ] || return 1
-  [ -f "$native_build_dir/stubdata/libicudata.a" ] || return 1
-  [ -f "$native_build_dir/lib/libicutu.a" ] || return 1
-  local tool
-  while IFS= read -r tool; do
-    [ -x "$native_build_dir/bin/$tool" ] || return 1
-  done < <(oliphaunt_icu_native_tool_names)
-}
-
-oliphaunt_icu_stub_data_archive_ready() {
-  local archive="${1:?ICU data archive is required}"
-  [ -f "$archive" ] || return 1
-  local members
-  members="$(ar -t "$archive")" || return 1
-  grep -Eq '^stubdata\.ao/?$' <<< "$members" || return 1
-  ! grep -Eq '^icudt[0-9]+[a-z]*_dat\.o/?$' <<< "$members"
-}
-
-oliphaunt_icu_data_root_contains_data() {
-  local data_root="${1:?ICU data root is required}"
-  [ -d "$data_root" ] || return 1
-  local root_name
-  root_name="$(basename "$data_root")"
-  if [[ "$root_name" == icudt* ]] &&
-     find "$data_root" -mindepth 1 -type f -print -quit 2>/dev/null | grep -q .; then
-    return 0
-  fi
-  if compgen -G "$data_root/icudt*.dat" >/dev/null; then
-    return 0
-  fi
-  local child
-  while IFS= read -r child; do
-    if find "$child" -type f -print -quit 2>/dev/null | grep -q .; then
-      return 0
-    fi
-  done < <(find "$data_root" -mindepth 1 -maxdepth 1 -type d -name 'icudt*' 2>/dev/null | LC_ALL=C sort)
-  return 1
-}
-
-oliphaunt_icu_files_data_ready() {
-  local data_root="${1:?ICU data root is required}"
-  oliphaunt_icu_data_root_contains_data "$data_root" && return 0
-  local child
-  while IFS= read -r child; do
-    if oliphaunt_icu_data_root_contains_data "$child"; then
-      return 0
-    fi
-  done < <(find "$data_root" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | LC_ALL=C sort)
-  return 1
-}
-
-oliphaunt_icu_artifacts_ready() {
-  local prefix="${1:?ICU prefix is required}"
-  [ -f "$prefix/.oliphaunt-icu-build" ] || return 1
-  [ -f "$prefix/include/unicode/ucol.h" ] || return 1
-  [ -f "$prefix/lib/libicui18n.a" ] || return 1
-  [ -f "$prefix/lib/libicuuc.a" ] || return 1
-  oliphaunt_icu_stub_data_archive_ready "$prefix/lib/libicudata.a" || return 1
-  oliphaunt_icu_files_data_ready "$prefix/share/icu"
-}
-
-oliphaunt_icu_linked_symbols_ready() {
-  local symbols="${1-}"
-  local data_symbol_re
-  data_symbol_re='(^|[[:space:]])_?icudt[0-9]+[a-z]*_dat($|[[:space:]])'
-  [ -n "$symbols" ] || return 1
-  grep -Eq '(^|[[:space:]])_?ucol_open(_[0-9]+)?($|[[:space:]])' <<< "$symbols" || return 1
-  ! grep -Eq '(^|[[:space:]])_?pg_register_static_icu_data($|[[:space:]])' <<< "$symbols" || return 1
-
-  local line address size_or_type type_or_symbol symbol_name
-  while IFS= read -r line; do
-    [[ "$line" =~ $data_symbol_re ]] || continue
-    read -r address size_or_type type_or_symbol symbol_name _ <<< "$line"
-    if [[ "$size_or_type" =~ ^[[:xdigit:]]+$ ]] && [[ "$type_or_symbol" =~ ^[A-Za-z]$ ]]; then
-      [ "$((16#$size_or_type))" -le 4096 ] || return 1
-    fi
-  done <<< "$symbols"
-}
-
-oliphaunt_icu_install_stub_data_archive() {
-  local target_build_dir="${1:?target ICU build dir is required}"
-  local prefix="${2:?ICU prefix is required}"
-  local built_archive="$target_build_dir/stubdata/libicudata.a"
-  local installed_archive="$prefix/lib/libicudata.a"
-  local tmp_archive="$installed_archive.tmp"
-
-  oliphaunt_icu_stub_data_archive_ready "$built_archive"
-  mkdir -p "$prefix/lib"
-  rm -f "$tmp_archive"
-  cp "$built_archive" "$tmp_archive"
-  chmod 0644 "$tmp_archive"
-  mv "$tmp_archive" "$installed_archive"
-}
-
-oliphaunt_icu_install_canonical_files_data() {
-  local source_dir="${1:?ICU source dir is required}"
-  local native_build_dir="${2:?native ICU build dir is required}"
-  local prefix="${3:?ICU prefix is required}"
-  local archive
-  archive="$(oliphaunt_icu_canonical_data_archive "$source_dir")"
-  oliphaunt_icu_require_canonical_data "$archive"
-  local icupkg="$native_build_dir/bin/icupkg"
-  [ -x "$icupkg" ] || {
-    echo "missing ICU package tool at $icupkg" >&2
-    return 1
-  }
-  local destination="$prefix/share/icu"
-  local tmp_destination="$prefix/share/icu.tmp"
-
-  rm -rf "$tmp_destination"
-  mkdir -p "$tmp_destination/icudt76l"
-  "$icupkg" -x '*' -d "$tmp_destination/icudt76l" "$archive"
-  [ "$(find "$tmp_destination/icudt76l" -type f | wc -l | tr -d '[:space:]')" = 4136 ] || {
-    echo "pinned ICU data archive did not extract the expected 4136 files" >&2
-    rm -rf "$tmp_destination"
-    return 1
-  }
-  rm -rf "$destination"
-  mv "$tmp_destination" "$destination"
-  oliphaunt_icu_files_data_ready "$prefix/share/icu"
-}
-
-oliphaunt_icu_prepare_files_data_install_dirs() {
-  local target_build_dir="${1:?target ICU build dir is required}"
-  local prefix="${2:?ICU prefix is required}"
-  local build_data_root="$target_build_dir/data/out/build"
-  [ -d "$build_data_root" ] || return 0
-
-  local version
-  version="$(
-    awk -F' = ' '$1 == "VERSION" { print $2; exit }' "$target_build_dir/config/Makefile.inc"
-  )"
-  [ -n "$version" ] || {
-    echo "unable to determine ICU version from $target_build_dir/config/Makefile.inc" >&2
-    return 1
-  }
-
-  local install_data_root="$prefix/share/icu/$version"
-  mkdir -p "$install_data_root"
-  while IFS= read -r dir; do
-    local relative="${dir#"$build_data_root"/}"
-    [ "$relative" != "$dir" ] || continue
-    mkdir -p "$install_data_root/$relative"
-  done < <(find "$build_data_root" -type d -print)
-}
-
-oliphaunt_icu_data_source_dir() {
-  local prefix="${1:?ICU prefix is required}"
-  local installed_icu="$prefix/share/icu"
-  if oliphaunt_icu_data_root_contains_data "$installed_icu"; then
-    printf '%s\n' "$installed_icu"
-    return 0
-  fi
-
-  local child
-  while IFS= read -r child; do
-    if [ -d "$child" ] && oliphaunt_icu_data_root_contains_data "$child"; then
-      printf '%s\n' "$child"
-      return 0
-    fi
-  done < <(find "$installed_icu" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | LC_ALL=C sort)
-  return 1
-}
-
-oliphaunt_icu_stage_data() {
-  local prefix="${1:?ICU prefix is required}"
-  local destination="${2:?destination ICU data root is required}"
-  local source
-  source="$(oliphaunt_icu_data_source_dir "$prefix")" || return 1
-  oliphaunt_icu_copy_files_data "$source" "$destination"
-}
-
-oliphaunt_icu_copy_files_data() {
-  local source="${1:?source ICU data root is required}"
-  local destination="${2:?destination ICU data root is required}"
-  [ -d "$source" ] || return 1
-  if find "$source" -type l -print -quit | grep -q .; then
-    echo "ICU files-data source must not contain symbolic links: $source" >&2
-    return 1
-  fi
-  rm -rf "$destination"
-  mkdir -p "$destination"
-  local copied=0
-  local child name
-  while IFS= read -r child; do
-    name="$(basename "$child")"
-    if [ -f "$child" ] && [[ "$name" =~ ^icudt[0-9]+[a-z]*[.]dat$ ]]; then
-      cp -p "$child" "$destination/$name"
-      copied=$((copied + 1))
-    elif [ -d "$child" ] && [[ "$name" =~ ^icudt[0-9]+[a-z]*$ ]] &&
-      find "$child" -type f -print -quit | grep -q .; then
-      cp -pR "$child" "$destination/$name"
-      copied=$((copied + 1))
-    fi
-  done < <(find "$source" -mindepth 1 -maxdepth 1 -print | LC_ALL=C sort)
-  if [ "$copied" -ne 1 ]; then
-    echo "ICU data root must contain exactly one canonical icudt files-data payload: $source" >&2
-    rm -rf "$destination"
-    return 1
-  fi
-  oliphaunt_icu_files_data_ready "$destination"
-}
-
-oliphaunt_icu_build_native_tools() {
-  local source_dir="${1:?ICU source dir is required}"
-  local script_dir="${2:?script dir is required}"
-  local native_build_dir="${3:?native build dir is required}"
-  local jobs="${4:?jobs is required}"
-
-  oliphaunt_icu_require_source "$source_dir"
-
-  local stamp_file="$native_build_dir/.oliphaunt-icu-native-tools"
-  local stamp
-  stamp="$(oliphaunt_icu_native_tools_stamp "$source_dir" "$script_dir")"
-  if [ -f "$stamp_file" ] &&
-     [ "$(cat "$stamp_file")" = "$stamp" ] &&
-     oliphaunt_icu_native_tools_ready "$native_build_dir"; then
-    return 0
-  fi
-
-  rm -rf "$native_build_dir"
-  mkdir -p "$native_build_dir"
-  (
-    cd "$native_build_dir"
-    "$source_dir/configure" \
-      --disable-shared \
-      --enable-static \
-      --disable-tests \
-      --disable-samples \
-      --disable-extras \
-      --disable-icuio \
-      --disable-layoutex
-    make all-local
-    mkdir -p lib bin
-    make -j"$jobs" -C stubdata
-    make -j"$jobs" -C common
-    make -j"$jobs" -C i18n
-    make -j"$jobs" -C tools/toolutil
-    local tool
-    while IFS= read -r tool; do
-      make -j"$jobs" -C "tools/$tool"
-    done < <(oliphaunt_icu_native_tool_names)
-  )
-  oliphaunt_icu_native_tools_ready "$native_build_dir"
-  printf '%s\n' "$stamp" > "$stamp_file"
-}
-
-oliphaunt_icu_build_target() {
-  local source_dir="${1:?ICU source dir is required}"
-  local script_dir="${2:?script dir is required}"
-  local native_build_dir="${3:?native build dir is required}"
-  local target_build_dir="${4:?target build dir is required}"
-  local prefix="${5:?prefix is required}"
-  local jobs="${6:?jobs is required}"
-  local target_label="${7:?target label is required}"
-  local host="${8:?host is required}"
-  local cc="${9:?cc is required}"
-  local cxx="${10:?cxx is required}"
-  local ar="${11:?ar is required}"
-  local ranlib="${12:?ranlib is required}"
-  local cflags="${13:-}"
-  local cxxflags="${14:-}"
-  local ldflags="${15:-}"
-
-  oliphaunt_icu_build_native_tools "$source_dir" "$script_dir" "$native_build_dir" "$jobs"
-  oliphaunt_icu_require_canonical_data "$(oliphaunt_icu_canonical_data_archive "$source_dir")"
-
-  local stamp_file="$prefix/.oliphaunt-icu-build"
-  local stamp
-  stamp="$(oliphaunt_icu_target_stamp "$source_dir" "$script_dir" "$target_label" "$host" "$cc" "$cxx" "$ar" "$ranlib" "$cflags" "$cxxflags" "$ldflags")"
-  if [ -f "$stamp_file" ] &&
-     [ "$(cat "$stamp_file")" = "$stamp" ] &&
-     oliphaunt_icu_artifacts_ready "$prefix"; then
-    return 0
-  fi
-
-  rm -rf "$target_build_dir" "$prefix"
-  mkdir -p "$target_build_dir" "$(dirname "$prefix")"
-  (
-    cd "$target_build_dir"
-    CC="$cc" \
-    CXX="$cxx" \
-    AR="$ar" \
-    RANLIB="$ranlib" \
-    CFLAGS="$cflags" \
-    CXXFLAGS="$cxxflags" \
-    LDFLAGS="$ldflags" \
-      "$source_dir/configure" \
-        --host="$host" \
-        --with-cross-build="$native_build_dir" \
-        --with-data-packaging=files \
-        --disable-shared \
-        --enable-static \
-        --disable-tests \
-        --disable-samples \
-        --disable-tools \
-        --disable-extras \
-        --disable-icuio \
-        --disable-layoutex \
-        --prefix="$prefix"
-    local icu_pkgdata_opts="-O $target_build_dir/data/icupkg.inc -w"
-    local icu_data_name
-    icu_data_name="$(
-      awk -F' = ' '$1 == "ICUDATA_NAME" { print $2; exit }' \
-        "$target_build_dir/config/Makefile.inc"
-    )"
-    if [[ ! "$icu_data_name" =~ ^icudt[0-9]+[a-z]+$ ]]; then
-      echo "invalid ICU data name in $target_build_dir/config/Makefile.inc: $icu_data_name" >&2
-      return 1
-    fi
-    # ICU 76.1 does not order genrb after cnvalias.icu. Complete the alias
-    # file before parallel data generators can map a partially written file.
-    make -j1 -C data "out/build/$icu_data_name/cnvalias.icu" PKGDATA_OPTS="$icu_pkgdata_opts"
-    make -j"$jobs" PKGDATA_OPTS="$icu_pkgdata_opts"
-    oliphaunt_icu_prepare_files_data_install_dirs "$target_build_dir" "$prefix"
-    make install PKGDATA_OPTS="$icu_pkgdata_opts"
-    make -j"$jobs" -C data packagedata PKGDATA_OPTS="$icu_pkgdata_opts"
-    oliphaunt_icu_install_canonical_files_data "$source_dir" "$native_build_dir" "$prefix"
-    oliphaunt_icu_install_stub_data_archive "$target_build_dir" "$prefix"
-  )
-
-  test -f "$prefix/include/unicode/ucol.h"
-  test -f "$prefix/lib/libicui18n.a"
-  test -f "$prefix/lib/libicuuc.a"
-  oliphaunt_icu_stub_data_archive_ready "$prefix/lib/libicudata.a"
-  oliphaunt_icu_files_data_ready "$prefix/share/icu"
-  printf '%s\n' "$stamp" > "$stamp_file"
-}
-
-oliphaunt_icu_cflags() {
-  local prefix="${1:?prefix is required}"
-  printf '%s\n' "-DU_STATIC_IMPLEMENTATION -I$prefix/include"
-}
-
-oliphaunt_icu_static_libs() {
-  local prefix="${1:?prefix is required}"
-  printf '%s\n' "$prefix/lib/libicui18n.a $prefix/lib/libicuuc.a $prefix/lib/libicudata.a"
-}
diff --git a/src/runtimes/liboliphaunt/native/bin/smoke-host-happy-path.sh b/src/runtimes/liboliphaunt/native/bin/smoke-host-happy-path.sh
deleted file mode 100755
index 505056054..000000000
--- a/src/runtimes/liboliphaunt/native/bin/smoke-host-happy-path.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env sh
-set -eu
-
-script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
-. "$script_dir/common.sh"
-repo_root="$(oliphaunt_resolve_repo_root "$script_dir")"
-cd "$repo_root"
-
-if [ "${1:-}" != "" ]; then
-  node src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs --smoke-only --root "$1"
-else
-  node src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs --smoke-only
-fi
diff --git a/src/runtimes/liboliphaunt/native/crates/tools/Cargo.toml b/src/runtimes/liboliphaunt/native/crates/tools/Cargo.toml
deleted file mode 100644
index d9973cc5e..000000000
--- a/src/runtimes/liboliphaunt/native/crates/tools/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-name = "oliphaunt-tools"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Target-selecting Cargo facade for Oliphaunt native PostgreSQL client tool artifacts."
-readme = "README.md"
-repository.workspace = true
-homepage.workspace = true
-license = "MIT"
-links = "oliphaunt_artifact_oliphaunt_tools_relay"
-build = "build.rs"
-include = [
-  "Cargo.toml",
-  "README.md",
-  "build.rs",
-  "build_support.rs",
-  "src/**",
-  "LICENSE",
-  "THIRD_PARTY_NOTICES.md",
-]
-
-[lib]
-path = "src/lib.rs"
diff --git a/src/runtimes/liboliphaunt/native/icu-npm/package.json b/src/runtimes/liboliphaunt/native/icu-npm/package.json
deleted file mode 100644
index 12ce65942..000000000
--- a/src/runtimes/liboliphaunt/native/icu-npm/package.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "name": "@oliphaunt/icu",
-  "version": "0.2.0",
-  "description": "Portable ICU data files for Oliphaunt runtimes.",
-  "license": "MIT AND Unicode-3.0",
-  "type": "commonjs",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/icu-npm"
-  },
-  "bugs": {
-    "url": "https://github.com/f0rr0/oliphaunt/issues"
-  },
-  "homepage": "https://oliphaunt.dev",
-  "oliphaunt": {
-    "product": "oliphaunt-icu",
-    "kind": "icu-data",
-    "target": "portable",
-    "dataRelativePath": "OliphauntICU.bundle/share/icu",
-    "manifestRelativePath": "OliphauntICU.bundle/manifest.properties",
-    "icuDataTreeSha256": "x-release-icu-data-tree-sha256"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "files": [
-    "OliphauntICU.bundle",
-    "OliphauntICU.podspec",
-    "react-native.config.js",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_LICENSES/ICU-LICENSE"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/include/oliphaunt.h b/src/runtimes/liboliphaunt/native/include/oliphaunt.h
deleted file mode 100644
index d96facff7..000000000
--- a/src/runtimes/liboliphaunt/native/include/oliphaunt.h
+++ /dev/null
@@ -1,257 +0,0 @@
-#ifndef OLIPHAUNT_H
-#define OLIPHAUNT_H
-
-#include 
-#include 
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define OLIPHAUNT_ABI_VERSION 10u
-#define OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION 1u
-#define OLIPHAUNT_ERROR_CAPTURE_CAPACITY 1024u
-#define OLIPHAUNT_STREAM_CALLBACK_ABORTED 1
-/* The caller already owns liboliphaunt's stable sibling root lease. */
-#define OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK (1ull << 0)
-
-#if defined(_WIN32) && defined(OLIPHAUNT_BUILDING_DLL)
-#define OLIPHAUNT_API __declspec(dllexport)
-#elif defined(_WIN32)
-#define OLIPHAUNT_API __declspec(dllimport)
-#else
-#define OLIPHAUNT_API
-#endif
-
-typedef struct OliphauntHandle OliphauntHandle;
-
-typedef struct OliphauntStaticExtensionSymbol {
-    const char *name;
-    void *address;
-} OliphauntStaticExtensionSymbol;
-
-typedef struct OliphauntStaticExtension {
-    uint32_t abi_version;
-    const char *name;
-    const void *(*magic)(void);
-    void (*init)(void);
-    const OliphauntStaticExtensionSymbol *symbols;
-    size_t symbol_count;
-    uint64_t reserved_flags;
-} OliphauntStaticExtension;
-
-/*
- * Direct-mode extension compatibility contract:
- *
- * oliphaunt_init sets the process PGDATA environment variable to this config's
- * pgdata path while the embedded backend is active, because PostgreSQL
- * extensions may read PGDATA through standard process APIs. oliphaunt_detach
- * releases a logical direct-mode lease but keeps the resident backend alive;
- * oliphaunt_close is terminal for the process lifetime and restores the caller's
- * previous PGDATA value, or unsets it if it was unset.
- *
- * Every successful oliphaunt_init establishes a current
- * logical lease generation. Hosts with independent cleanup owners must capture
- * its non-zero value immediately with oliphaunt_logical_generation and use
- * oliphaunt_close_if_generation: a stale owner then cannot terminate a newer
- * logical lease on the same resident handle.
- *
- * Callers that require process environment isolation should use broker/server
- * mode through the Rust SDK instead of keeping multiple direct-mode backends in
- * one process.
- */
-typedef struct OliphauntConfig {
-    uint32_t abi_version;
-    /* The pgdata child of an already-prepared managed root. Init does not create it. */
-    const char *pgdata;
-    const char *runtime_dir;
-    /*
-     * Exact PostgreSQL $libdir for the embedded handle. It must name an
-     * existing directory. Pass NULL to use OLIPHAUNT_EMBEDDED_MODULE_DIR and
-     * release-layout discovery.
-     */
-    const char *module_dir;
-    const char *username;
-    const char *database;
-    /* OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK or zero. */
-    uint64_t flags;
-    /* Zero or more `-c`, `name=value` pairs. Storage-routing GUCs are rejected. */
-    const char *const *startup_args;
-    size_t startup_arg_count;
-} OliphauntConfig;
-
-typedef struct OliphauntResponse {
-    uint8_t *data;
-    size_t len;
-} OliphauntResponse;
-
-/*
- * Operation-owned error storage for hosts whose FFI scheduler resumes the
- * caller on a different thread. The `_with_error` entry points below execute
- * the operation and capture its thread-local failure before that native
- * invocation returns. `length` excludes the trailing NUL and is at most
- * OLIPHAUNT_ERROR_CAPTURE_CAPACITY - 1; `message` is always NUL-terminated
- * and is empty on success. The entire capture is zeroed on success. Native
- * error sources use the same bound, so a valid runtime error is not
- * additionally truncated during capture.
- */
-typedef struct OliphauntErrorCapture {
-    uint32_t length;
-    char message[OLIPHAUNT_ERROR_CAPTURE_CAPACITY];
-} OliphauntErrorCapture;
-
-typedef struct OliphauntRestoreOptions {
-    uint32_t abi_version;
-    /* New or existing-empty managed-root path; this is not a PGDATA path. */
-    const char *destination;
-    /* Bytes in the single native physical archive format returned by oliphaunt_backup. */
-    const uint8_t *data;
-    size_t len;
-} OliphauntRestoreOptions;
-
-/*
- * Same-handle ownership and streaming contract:
- *
- * Hosts serialize ordinary non-cancel operations on one logical handle.
- * oliphaunt_cancel is the deliberate cross-thread exception and may interrupt
- * the active PostgreSQL operation. A successful detach ends that logical
- * lease; a successful close terminally invalidates the opaque handle, which
- * must never be dereferenced again.
- *
- * A raw-stream callback borrows data only for that callback invocation. It may
- * copy the bytes, inspect errors, or call oliphaunt_cancel. It must not call
- * query, backup, detach, close, or another raw-stream operation on the same
- * handle. Those calls fail with a busy error while streaming is active,
- * including from another thread, so the callback cannot corrupt protocol
- * ordering or free its own handle. A non-zero callback result stops later
- * callback delivery and drains the backend to ReadyForQuery. The stream then
- * returns OLIPHAUNT_STREAM_CALLBACK_ABORTED; negative results identify
- * validation, transport, backend, or recovery failures for which reuse may be
- * unsafe.
- */
-typedef int32_t (*OliphauntStreamCallback)(void *context, const uint8_t *data, size_t len);
-
-OLIPHAUNT_API int32_t oliphaunt_init(const OliphauntConfig *config, OliphauntHandle **out);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_exec_simple_query(
-    OliphauntHandle *handle,
-    const char *sql,
-    size_t sql_len,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context);
-/*
- * Creates a session-preserving online physical archive. If an error says that
- * backup-mode exit is unconfirmed, no later query is safe: detach/close the
- * handle and restart the process before reopening PostgreSQL.
- */
-OLIPHAUNT_API int32_t oliphaunt_backup(
-    OliphauntHandle *handle,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_restore(const OliphauntRestoreOptions *options);
-/*
- * Scheduler-safe variants for asynchronous FFI hosts. These preserve the
- * return code and response ownership of their corresponding operation while
- * filling a required caller-owned capture before returning.
- */
-OLIPHAUNT_API int32_t oliphaunt_init_with_error(
-    const OliphauntConfig *config,
-    OliphauntHandle **out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_with_error(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_simple_query_with_error(
-    OliphauntHandle *handle,
-    const char *sql,
-    size_t sql_len,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream_with_error(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_backup_with_error(
-    OliphauntHandle *handle,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_restore_with_error(
-    const OliphauntRestoreOptions *options,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_detach_with_error(
-    OliphauntHandle *handle,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_cancel(OliphauntHandle *handle);
-/* A poisoned backup session is terminally closed instead of retained. */
-OLIPHAUNT_API int32_t oliphaunt_detach(OliphauntHandle *handle);
-/*
- * Returns the non-zero generation of the currently published logical lease.
- * Returns zero for NULL, stale, terminally closed, or otherwise non-current
- * handles. The registry is validated before the opaque handle is dereferenced.
- */
-OLIPHAUNT_API uint64_t oliphaunt_logical_generation(OliphauntHandle *handle);
-/*
- * Terminally closes the process-wide resident handle only when generation
- * still owns its current logical lease. Returns 0 when terminal close completes
- * or had already completed, 1 for an active stale/non-owner generation no-op,
- * and -1 for generation zero or an internal failure.
- */
-OLIPHAUNT_API int32_t oliphaunt_close_if_generation(
-    uint64_t generation);
-/*
- * Unconditionally performs process-terminal close for the current published
- * resident handle. Hosts with multiple cleanup owners should use
- * oliphaunt_close_if_generation and retain only its generation token.
- */
-OLIPHAUNT_API int32_t oliphaunt_close(OliphauntHandle *handle);
-/*
- * Registers statically linked PostgreSQL extension modules for the embedded
- * backend's normal LOAD path.
- *
- * Call this before oliphaunt_init in processes that link extension code directly
- * into the application or SDK library. The registry is process-wide and becomes
- * immutable once backend startup begins. Each extension name is the module stem
- * used by SQL, for example AS 'vector', and each symbol row exposes the C
- * symbols PostgreSQL would otherwise resolve with dlsym().
- */
-OLIPHAUNT_API int32_t oliphaunt_register_static_extensions(const OliphauntStaticExtension *extensions, size_t count);
-/*
- * Copies an error into caller-owned storage. Immediately after a fallible C
- * operation returns failure, calls on that same thread read the operation's
- * owned snapshot. It takes precedence over the shared handle/global error and
- * remains stable across a size probe and repeated copies until the thread
- * begins another fallible C operation, even if another thread updates the
- * shared error. With no operation snapshot, this atomically reads the latest
- * handle error, or the process-global error when handle is NULL.
- *
- * The return value is the full UTF-8 byte length excluding the trailing NUL.
- * When capacity is non-zero, out must be non-NULL and is always
- * NUL-terminated; content is truncated when capacity is smaller than length +
- * 1.
- */
-OLIPHAUNT_API size_t oliphaunt_copy_last_error(
-    OliphauntHandle *handle,
-    char *out,
-    size_t capacity);
-OLIPHAUNT_API const char *oliphaunt_version(void);
-OLIPHAUNT_API void oliphaunt_free_response(OliphauntResponse *response);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/runtimes/liboliphaunt/native/moon.yml b/src/runtimes/liboliphaunt/native/moon.yml
deleted file mode 100644
index 264550cb1..000000000
--- a/src/runtimes/liboliphaunt/native/moon.yml
+++ /dev/null
@@ -1,528 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "liboliphaunt-native"
-language: "c"
-layer: "library"
-stack: "systems"
-tags: ["native", "postgres", "c-abi", "pg18", "release-product"]
-dependsOn:
-  - id: "artifact-packaging"
-    scope: "build"
-  - id: "extensions"
-    scope: "build"
-  - id: "shared-test-fixtures"
-    scope: "development"
-  - id: "postgres18"
-    scope: "build"
-  - id: "third-party-shared"
-    scope: "build"
-  - id: "third-party-native"
-    scope: "build"
-  - id: "extension-runtime-contract"
-    scope: "build"
-  - id: "oliphaunt-extension-contrib-pg18"
-    scope: "build"
-
-project:
-  title: "liboliphaunt Native"
-  description: "C ABI and PostgreSQL 18 patch stack for native embedded Oliphaunt."
-  owner: "oliphaunt"
-  release:
-    component: "liboliphaunt-native"
-    packagePath: "src/runtimes/liboliphaunt/native"
-    artifactTargets:
-      preset: "liboliphaunt-native"
-      targets:
-        - "android-arm64-v8a"
-        - "android-x86_64"
-        - "ios-xcframework"
-        - "linux-arm64-gnu"
-        - "linux-x64-gnu"
-        - "macos-arm64"
-        - "windows-x64-msvc"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "**/*": ["@oliphaunt/core"]
-
-fileGroups:
-  runtime:
-    - "**/*"
-    - "!**/*.md"
-    - "!moon.yml"
-
-tasks:
-  lint:
-    tags: ["quality", "static"]
-    command: "node src/runtimes/liboliphaunt/native/tools/check-patch-stack.mjs"
-    inputs:
-      - "bin/*postgres18*"
-      - "postgres18/**/*"
-      - "tools/check-patch-stack.mjs"
-      - "/docs/internal/OLIPHAUNT_PATCH_STACK.md"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  unit:
-    tags: ["quality", "unit"]
-    command: "true"
-    deps:
-      - "liboliphaunt-native:external-source-fetch-test"
-      - "liboliphaunt-native:error-attribution-test"
-      - "liboliphaunt-native:generation-lifecycle-test"
-      - "liboliphaunt-native:ios-extension-packager-test"
-      - "liboliphaunt-native:module-dir-resolver-test"
-      - "liboliphaunt-native:postgis-reproducible-time-test"
-      - "liboliphaunt-native:static-extension-registry-test"
-      - "liboliphaunt-native:symbol-scope-test"
-      - "liboliphaunt-native:tools-test"
-    inputs: []
-  tools-test:
-    tags: ["requires-rust"]
-    command: "cargo test -p oliphaunt-tools --locked"
-    env:
-      CARGO_TARGET_DIR: "target/moon/liboliphaunt-native/tools-test"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "/src/runtimes/liboliphaunt/native/crates/tools/**/*"
-    options:
-      cache: true
-      internal: true
-      runFromWorkspaceRoot: true
-  external-source-fetch-test:
-    command: "bash src/runtimes/liboliphaunt/native/bin/fetch-pinned-git-checkout.test.sh"
-    inputs:
-      - "/src/runtimes/liboliphaunt/native/bin/fetch-pinned-git-checkout.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/fetch-pinned-git-checkout.test.sh"
-    options:
-      cache: true
-      internal: true
-      runFromWorkspaceRoot: true
-  error-attribution-test:
-    command: "bash src/runtimes/liboliphaunt/native/tools/test-error-attribution.sh"
-    inputs:
-      - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_error.c"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_platform.h"
-      - "/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_error_attribution.c"
-      - "/src/runtimes/liboliphaunt/native/tools/test-error-attribution.sh"
-    options:
-      cache: true
-      internal: true
-      runFromWorkspaceRoot: true
-  generation-lifecycle-test:
-    command: "bash src/runtimes/liboliphaunt/native/tools/test-generation-lifecycle.sh"
-    inputs:
-      - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_platform.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_backup_state.c"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c"
-      - "/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_generation_lifecycle.c"
-      - "/src/runtimes/liboliphaunt/native/tools/test-generation-lifecycle.sh"
-    options:
-      cache: true
-      internal: true
-      runFromWorkspaceRoot: true
-  ios-extension-packager-test:
-    command: "bash src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.test.sh"
-    inputs:
-      - "/src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.test.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/common.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/mobile-static-extensions.sh"
-      - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-    options:
-      cache: true
-      internal: true
-      runFromWorkspaceRoot: true
-  postgis-reproducible-time-test:
-    script: |
-      set -e
-      bash src/runtimes/liboliphaunt/native/bin/postgis-reproducible-time.test.sh
-    inputs:
-      - "/src/extensions/external/postgis/source.toml"
-      - "/src/extensions/external/postgis/tools/build_wasix.sh"
-      - "/src/extensions/external/postgis/tools/reproducible-bin/date"
-      - "/src/extensions/external/postgis/tools/reproducible-time.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/build-macos-extension-archives.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-device.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1"
-      - "/src/runtimes/liboliphaunt/native/bin/mobile-postgis-extensions.sh"
-      - "/src/runtimes/liboliphaunt/native/bin/postgis-reproducible-time.test.sh"
-      - "/tools/xtask/src/asset_checks.rs"
-      - "/tools/xtask/src/asset_manifest.rs"
-      - "/tools/xtask/src/asset_pipeline.rs"
-      - "/tools/xtask/src/source_spine.rs"
-    options:
-      cache: true
-      internal: true
-      runFromWorkspaceRoot: true
-  module-dir-resolver-test:
-    command: "bash src/runtimes/liboliphaunt/native/tools/test-module-dir-resolver.sh"
-    inputs:
-      - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_platform.h"
-      - "/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_module_dir_resolver.c"
-      - "/src/runtimes/liboliphaunt/native/tools/test-module-dir-resolver.sh"
-    options:
-      cache: true
-      internal: true
-      runFromWorkspaceRoot: true
-  static-extension-registry-test:
-    command: "bash src/runtimes/liboliphaunt/native/tools/test-static-extension-registry.sh"
-    inputs:
-      - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_platform.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_static_extensions.c"
-      - "/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_static_extension_registry.c"
-      - "/src/runtimes/liboliphaunt/native/tools/test-static-extension-registry.sh"
-    options:
-      cache: true
-      internal: true
-      runFromWorkspaceRoot: true
-  symbol-scope-test:
-    command: "bash src/runtimes/liboliphaunt/native/tools/test-symbol-scope.sh"
-    inputs:
-      - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_internal.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_platform.h"
-      - "/src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c"
-      - "/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_symbol_scope_consumer.c"
-      - "/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_symbol_scope_host.c"
-      - "/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_symbol_scope_provider.c"
-      - "/src/runtimes/liboliphaunt/native/tools/audit-macos-module-nm.awk"
-      - "/src/runtimes/liboliphaunt/native/tools/audit-macos-provider-collisions.awk"
-      - "/src/runtimes/liboliphaunt/native/tools/test-symbol-scope.sh"
-    options:
-      cache: true
-      internal: true
-      runFromWorkspaceRoot: true
-  host-smoke:
-    tags: ["runtime", "smoke"]
-    script: |
-      set -e
-      . src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh
-      oliphaunt_runtime_native_host_require basic
-      node src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs
-    deps:
-      - "liboliphaunt-native:build-runtime-desktop-target"
-    inputs:
-      - "**/*"
-      - project: "postgres18"
-        group: "source"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "third-party-native"
-        group: "sources"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: skip
-  build-runtime-desktop-target:
-    tags: ["runtime", "build"]
-    deps:
-      - "source-inputs:source-fetch-native-runtime"
-    command: "node src/runtimes/liboliphaunt/native/tools/build-release-runtime.mjs"
-    inputs:
-      - "$OLIPHAUNT_CI_TARGET"
-      - project: "postgres18"
-        group: "source"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "third-party-native"
-        group: "sources"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "**/*"
-      - "/tools/native-packaging/**/*"
-      - "/tools/xtask/**/*"
-      - "@group(cargo-workspace)"
-    outputs:
-      - "/target/liboliphaunt-pg18/**/*"
-      - "/target/liboliphaunt-pg18-linux-*/**/*"
-      - "/target/liboliphaunt-pg18-windows-*/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  package-runtime-desktop-target:
-    tags: ["runtime", "release", "artifact-package", "ci-liboliphaunt-native-desktop"]
-    command: "node src/runtimes/liboliphaunt/native/tools/package-release-runtime.mjs"
-    deps:
-      - "liboliphaunt-native:build-runtime-desktop-target"
-    inputs:
-      - "$OLIPHAUNT_CI_TARGET"
-      - "@group(legal-files)"
-      - "/src/runtimes/liboliphaunt/native/include/**/*"
-      - "/src/runtimes/liboliphaunt/native/tools/package-release-runtime.mjs"
-      - "/tools/release/package-liboliphaunt-icu-data.sh"
-      - "/tools/release/package-liboliphaunt-linux-assets.sh"
-      - "/tools/release/package-liboliphaunt-macos-assets.sh"
-      - "/tools/release/package-liboliphaunt-windows-assets.ps1"
-      - "/tools/release/liboliphaunt-extension-guard.sh"
-      - "/tools/release/release-notices.mjs"
-      - "/tools/release/strip_native_release_binaries.mjs"
-      - "/tools/release/platform-binary-contract.mjs"
-      - project: "artifact-packaging"
-        group: "source"
-    outputs:
-      - "/target/liboliphaunt/desktop-release-assets/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  build-runtime-android-arm64-v8a:
-    tags: ["runtime", "build"]
-    deps:
-      - "source-inputs:source-fetch-native-runtime"
-    command: "bun src/runtimes/liboliphaunt/native/tools/build-ci-target.mjs android-arm64-v8a"
-    inputs:
-      - "@group(legal-files)"
-      - project: "postgres18"
-        group: "source"
-      - "/src/runtimes/liboliphaunt/licenses/**/*"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "third-party-native"
-        group: "sources"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "**/*"
-      - "/tools/native-packaging/**/*"
-      - "/tools/release/native-mobile-abi-contract.mjs"
-      - "/tools/xtask/**/*"
-      - "@group(cargo-workspace)"
-    outputs:
-      - "/target/liboliphaunt-native-ci/android-arm64-v8a/**/*"
-      - "/target/liboliphaunt-pg18-android-arm64/**/*"
-      - "/target/liboliphaunt-mobile-host/android-arm64-v8a/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  package-runtime-android-arm64-v8a:
-    tags: ["runtime", "release", "artifact-package", "ci-liboliphaunt-native-android"]
-    command: >-
-      env OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS="target/liboliphaunt/mobile-release-assets/android-arm64-v8a"
-      OLIPHAUNT_LINUX_X64_ROOT="$PWD/target/liboliphaunt-mobile-host/android-arm64-v8a"
-      bash tools/release/package-liboliphaunt-mobile-assets.sh android-arm64-v8a
-    deps:
-      - "liboliphaunt-native:build-runtime-android-arm64-v8a"
-    inputs:
-      - "@group(legal-files)"
-      - "/src/runtimes/liboliphaunt/native/include/**/*"
-      - "/tools/release/package-liboliphaunt-mobile-assets.sh"
-      - "/tools/release/liboliphaunt-extension-guard.sh"
-      - "/tools/release/native-mobile-abi-contract.mjs"
-      - "/tools/release/stage-native-cluster-seed.mjs"
-      - "/tools/release/finalize-native-runtime-carrier.mjs"
-      - "/tools/release/strip_native_release_binaries.mjs"
-      - "/tools/release/platform-binary-contract.mjs"
-      - "@group(release-archive-contract)"
-    outputs:
-      - "/target/liboliphaunt/mobile-release-assets/android-arm64-v8a/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  build-runtime-android-x86_64:
-    tags: ["runtime", "build"]
-    deps:
-      - "source-inputs:source-fetch-native-runtime"
-    command: "bun src/runtimes/liboliphaunt/native/tools/build-ci-target.mjs android-x86_64"
-    inputs:
-      - "@group(legal-files)"
-      - project: "postgres18"
-        group: "source"
-      - "/src/runtimes/liboliphaunt/licenses/**/*"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "third-party-native"
-        group: "sources"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "**/*"
-      - "/tools/native-packaging/**/*"
-      - "/tools/release/native-mobile-abi-contract.mjs"
-      - "/tools/xtask/**/*"
-      - "@group(cargo-workspace)"
-    outputs:
-      - "/target/liboliphaunt-native-ci/android-x86_64/**/*"
-      - "/target/liboliphaunt-pg18-android-x86_64/**/*"
-      - "/target/liboliphaunt-mobile-host/android-x86_64/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  package-runtime-android-x86_64:
-    tags: ["runtime", "release", "artifact-package", "ci-liboliphaunt-native-android"]
-    command: >-
-      env OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS="target/liboliphaunt/mobile-release-assets/android-x86_64"
-      OLIPHAUNT_LINUX_X64_ROOT="$PWD/target/liboliphaunt-mobile-host/android-x86_64"
-      bash tools/release/package-liboliphaunt-mobile-assets.sh android-x86_64
-    deps:
-      - "liboliphaunt-native:build-runtime-android-x86_64"
-    inputs:
-      - "@group(legal-files)"
-      - "/src/runtimes/liboliphaunt/native/include/**/*"
-      - "/tools/release/package-liboliphaunt-mobile-assets.sh"
-      - "/tools/release/liboliphaunt-extension-guard.sh"
-      - "/tools/release/native-mobile-abi-contract.mjs"
-      - "/tools/release/stage-native-cluster-seed.mjs"
-      - "/tools/release/finalize-native-runtime-carrier.mjs"
-      - "/tools/release/strip_native_release_binaries.mjs"
-      - "/tools/release/platform-binary-contract.mjs"
-      - "@group(release-archive-contract)"
-    outputs:
-      - "/target/liboliphaunt/mobile-release-assets/android-x86_64/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  build-runtime-ios-xcframework:
-    tags: ["runtime", "build"]
-    deps:
-      - "source-inputs:source-fetch-native-runtime"
-    command: "bun src/runtimes/liboliphaunt/native/tools/build-ci-target.mjs ios-xcframework"
-    inputs:
-      - "@group(legal-files)"
-      - project: "postgres18"
-        group: "source"
-      - "/src/runtimes/liboliphaunt/licenses/**/*"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "third-party-native"
-        group: "sources"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "**/*"
-      - "/tools/native-packaging/**/*"
-      - "/tools/release/native-mobile-abi-contract.mjs"
-      - "/tools/xtask/**/*"
-      - "@group(cargo-workspace)"
-    outputs:
-      - "/target/liboliphaunt-native-ci/ios-xcframework/**/*"
-      - "/target/liboliphaunt-ios-device/**/*"
-      - "/target/liboliphaunt-ios-simulator/**/*"
-      - "/target/liboliphaunt-ios-xcframework/**/*"
-      - "/target/liboliphaunt-mobile-host/ios-xcframework/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  package-runtime-ios-xcframework:
-    tags: ["runtime", "release", "artifact-package", "ci-liboliphaunt-native-ios"]
-    script: |
-      set -e
-      export OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS="target/liboliphaunt/mobile-release-assets/ios-xcframework"
-      export OLIPHAUNT_WORK_ROOT="$PWD/target/liboliphaunt-mobile-host/ios-xcframework"
-      tools/release/package-liboliphaunt-mobile-assets.sh ios-xcframework
-      node tools/release/validate-ios-carrier-zips.mjs --root "$OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS"
-    deps:
-      - "liboliphaunt-native:build-runtime-ios-xcframework"
-    inputs:
-      - "@group(legal-files)"
-      - "/src/runtimes/liboliphaunt/native/include/**/*"
-      - "/tools/release/package-liboliphaunt-mobile-assets.sh"
-      - "/tools/release/liboliphaunt-extension-guard.sh"
-      - "/tools/release/native-mobile-abi-contract.mjs"
-      - "/tools/release/stage-native-cluster-seed.mjs"
-      - "/tools/release/finalize-native-runtime-carrier.mjs"
-      - "/tools/release/strip_native_release_binaries.mjs"
-      - "/tools/release/platform-binary-contract.mjs"
-      - "/tools/release/validate-ios-carrier-zips.mjs"
-      - "/src/runtimes/liboliphaunt/native/bin/build-ios-xcframework.sh"
-      - "@group(release-archive-contract)"
-    outputs:
-      - "/target/liboliphaunt/mobile-release-assets/ios-xcframework/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  finalize-runtime-android-abi:
-    tags: ["runtime", "artifact-package"]
-    command: >-
-      tools/dev/bun.sh tools/release/finalize-native-mobile-abi-proofs.mjs
-      --domain android-datum64
-      --asset-dir target/liboliphaunt/mobile-release-assets/android-x86_64
-      --receipt-root target/liboliphaunt-native-ci
-      --output-dir target/liboliphaunt/abi-compatible-release-assets/android-datum64
-    deps:
-      - "liboliphaunt-native:package-runtime-android-arm64-v8a"
-      - "liboliphaunt-native:package-runtime-android-x86_64"
-    inputs:
-      - "/tools/release/finalize-native-mobile-abi-proofs.mjs"
-      - "/tools/release/native-mobile-abi-contract.mjs"
-      - "/target/liboliphaunt/mobile-release-assets/android-x86_64/**/*"
-      - "/target/liboliphaunt-native-ci/android-*/**/*"
-    outputs:
-      - "/target/liboliphaunt/abi-compatible-release-assets/android-datum64/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  finalize-runtime-ios-abi:
-    tags: ["runtime", "artifact-package"]
-    command: >-
-      tools/dev/bun.sh tools/release/finalize-native-mobile-abi-proofs.mjs
-      --domain ios-datum64
-      --asset-dir target/liboliphaunt/mobile-release-assets/ios-xcframework
-      --receipt-root target/liboliphaunt-native-ci/ios-xcframework
-      --output-dir target/liboliphaunt/abi-compatible-release-assets/ios-datum64
-    deps:
-      - "liboliphaunt-native:package-runtime-ios-xcframework"
-    inputs:
-      - "/tools/release/finalize-native-mobile-abi-proofs.mjs"
-      - "/tools/release/native-mobile-abi-contract.mjs"
-      - "/target/liboliphaunt/mobile-release-assets/ios-xcframework/**/*"
-      - "/target/liboliphaunt-native-ci/ios-xcframework/**/*"
-    outputs:
-      - "/target/liboliphaunt/abi-compatible-release-assets/ios-datum64/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-  release-assets:
-    tags: ["runtime", "release", "artifact-package", "ci-liboliphaunt-native-release-assets"]
-    command: "bash tools/release/package-liboliphaunt-aggregate-assets.sh"
-    deps:
-      - "liboliphaunt-native:package-runtime-desktop-target"
-      - "liboliphaunt-native:package-runtime-android-arm64-v8a"
-      - "liboliphaunt-native:package-runtime-android-x86_64"
-      - "liboliphaunt-native:package-runtime-ios-xcframework"
-      - "liboliphaunt-native:finalize-runtime-android-abi"
-      - "liboliphaunt-native:finalize-runtime-ios-abi"
-    inputs:
-      - "/release-please-config.json"
-      - project: "extensions"
-        group: "sdk-metadata"
-      - "/src/runtimes/liboliphaunt/native/moon.yml"
-      - project: "artifact-packaging"
-        group: "source"
-      - "/tools/release/check-liboliphaunt-release-assets.mjs"
-      - "/tools/release/package-liboliphaunt-aggregate-assets.sh"
-      - "@group(release-target-contract)"
-      - "/tools/release/platform-compatibility-policy.test.mjs"
-      - "/tools/release/platform-binary-contract.mjs"
-      - "/tools/release/platform-binary-contract.test.mjs"
-      - "/tools/release/release-graph.mjs"
-      - "/tools/release/release_graph_query.mjs"
-      - "/target/liboliphaunt/release-assets/**/*"
-    outputs:
-      - "/target/liboliphaunt/release-assets/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
-  qualify:
-    tags: ["release", "package"]
-    command: "true"
-    deps:
-      - "liboliphaunt-native:lint"
-      - "liboliphaunt-native:unit"
-      - "liboliphaunt-native:host-smoke"
-    inputs: []
diff --git a/src/runtimes/liboliphaunt/native/packages/darwin-arm64/package.json b/src/runtimes/liboliphaunt/native/packages/darwin-arm64/package.json
deleted file mode 100644
index e08352ec0..000000000
--- a/src/runtimes/liboliphaunt/native/packages/darwin-arm64/package.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
-  "name": "@oliphaunt/liboliphaunt-darwin-arm64",
-  "version": "0.2.0",
-  "description": "macOS arm64 liboliphaunt native library for Oliphaunt.",
-  "license": "MIT AND PostgreSQL AND Unicode-3.0",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/packages/darwin-arm64"
-  },
-  "os": [
-    "darwin"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "macos-arm64",
-    "clusterSeedTarget": "macos-arm64",
-    "libraryRelativePath": "lib/liboliphaunt.dylib",
-    "runtimeRelativePath": "runtime",
-    "clusterSeedRelativePath": "cluster-seed",
-    "icuClusterSeedRelativePath": "cluster-seed-icu"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./runtime/bin/initdb",
-      "./runtime/bin/pg_ctl",
-      "./runtime/bin/postgres"
-    ]
-  },
-  "files": [
-    "lib",
-    "runtime",
-    "cluster-seed",
-    "cluster-seed-icu",
-    "manifest.properties",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "THIRD_PARTY_LICENSES/ICU-LICENSE"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/packages/linux-arm64-gnu/package.json b/src/runtimes/liboliphaunt/native/packages/linux-arm64-gnu/package.json
deleted file mode 100644
index 8cc20b12f..000000000
--- a/src/runtimes/liboliphaunt/native/packages/linux-arm64-gnu/package.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
-  "name": "@oliphaunt/liboliphaunt-linux-arm64-gnu",
-  "version": "0.2.0",
-  "description": "Linux arm64 glibc liboliphaunt native library for Oliphaunt.",
-  "license": "MIT AND PostgreSQL AND Unicode-3.0",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/packages/linux-arm64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "linux-arm64-gnu",
-    "clusterSeedTarget": "linux-arm64-gnu",
-    "libraryRelativePath": "lib/liboliphaunt.so",
-    "runtimeRelativePath": "runtime",
-    "clusterSeedRelativePath": "cluster-seed",
-    "icuClusterSeedRelativePath": "cluster-seed-icu"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./runtime/bin/initdb",
-      "./runtime/bin/pg_ctl",
-      "./runtime/bin/postgres"
-    ]
-  },
-  "files": [
-    "lib",
-    "runtime",
-    "cluster-seed",
-    "cluster-seed-icu",
-    "manifest.properties",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "THIRD_PARTY_LICENSES/ICU-LICENSE"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/packages/linux-x64-gnu/package.json b/src/runtimes/liboliphaunt/native/packages/linux-x64-gnu/package.json
deleted file mode 100644
index fb1f483f4..000000000
--- a/src/runtimes/liboliphaunt/native/packages/linux-x64-gnu/package.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
-  "name": "@oliphaunt/liboliphaunt-linux-x64-gnu",
-  "version": "0.2.0",
-  "description": "Linux x64 glibc liboliphaunt native library for Oliphaunt.",
-  "license": "MIT AND PostgreSQL AND Unicode-3.0",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/packages/linux-x64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "linux-x64-gnu",
-    "clusterSeedTarget": "linux-x64-gnu",
-    "libraryRelativePath": "lib/liboliphaunt.so",
-    "runtimeRelativePath": "runtime",
-    "clusterSeedRelativePath": "cluster-seed",
-    "icuClusterSeedRelativePath": "cluster-seed-icu"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./runtime/bin/initdb",
-      "./runtime/bin/pg_ctl",
-      "./runtime/bin/postgres"
-    ]
-  },
-  "files": [
-    "lib",
-    "runtime",
-    "cluster-seed",
-    "cluster-seed-icu",
-    "manifest.properties",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "THIRD_PARTY_LICENSES/ICU-LICENSE"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/packages/win32-x64-msvc/package.json b/src/runtimes/liboliphaunt/native/packages/win32-x64-msvc/package.json
deleted file mode 100644
index 337609de5..000000000
--- a/src/runtimes/liboliphaunt/native/packages/win32-x64-msvc/package.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
-  "name": "@oliphaunt/liboliphaunt-win32-x64-msvc",
-  "version": "0.2.0",
-  "description": "Windows x64 MSVC liboliphaunt native library for Oliphaunt.",
-  "license": "MIT AND PostgreSQL AND Unicode-3.0",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/packages/win32-x64-msvc"
-  },
-  "os": [
-    "win32"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "windows-x64-msvc",
-    "clusterSeedTarget": "windows-x64-msvc",
-    "libraryRelativePath": "bin/oliphaunt.dll",
-    "runtimeRelativePath": "runtime",
-    "clusterSeedRelativePath": "cluster-seed",
-    "icuClusterSeedRelativePath": "cluster-seed-icu"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./runtime/bin/initdb.exe",
-      "./runtime/bin/pg_ctl.exe",
-      "./runtime/bin/postgres.exe"
-    ]
-  },
-  "files": [
-    "bin",
-    "lib",
-    "runtime",
-    "cluster-seed",
-    "cluster-seed-icu",
-    "manifest.properties",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "THIRD_PARTY_LICENSES/ICU-LICENSE"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/postgres18/external-extensions.toml b/src/runtimes/liboliphaunt/native/postgres18/external-extensions.toml
deleted file mode 100644
index 37532354e..000000000
--- a/src/runtimes/liboliphaunt/native/postgres18/external-extensions.toml
+++ /dev/null
@@ -1,36 +0,0 @@
-schema = "liboliphaunt-external-extensions-v2"
-pg_major = 18
-
-[[extensions]]
-id = "pggraph"
-sql_name = "graph"
-module_stem = "graph"
-source_kind = "pgrx"
-upstream = "https://github.com/evokoa/pggraph.git"
-source_ref = "main"
-commit = "4ea3c3206811deda03de136b4f465a2cf9bc8e72"
-checkout = "target/oliphaunt-sources/checkouts/pggraph"
-source_subdir = "graph"
-license = "Apache-2.0"
-redistribution = "allowed"
-pgrx_version = "0.18.0"
-pg_feature = "pg18"
-requires_shared_preload = false
-release_state = "candidate"
-
-[[extensions]]
-id = "paradedb-pg-search"
-sql_name = "pg_search"
-module_stem = "pg_search"
-source_kind = "pgrx"
-upstream = "https://github.com/paradedb/paradedb.git"
-source_ref = "v0.23.4"
-commit = "c07921a78f3d24cbb0251b31a1150a7db600af5a"
-checkout = "target/oliphaunt-sources/checkouts/paradedb"
-source_subdir = "pg_search"
-license = "AGPL-3.0"
-redistribution = "requires-commercial-license"
-pgrx_version = "0.18.0"
-pg_feature = "pg18"
-requires_shared_preload = true
-release_state = "candidate"
diff --git a/src/runtimes/liboliphaunt/native/postgres18/source.toml b/src/runtimes/liboliphaunt/native/postgres18/source.toml
deleted file mode 100644
index 400ea510a..000000000
--- a/src/runtimes/liboliphaunt/native/postgres18/source.toml
+++ /dev/null
@@ -1,29 +0,0 @@
-[postgresql]
-version = "18.4"
-url = "https://ftp.postgresql.org/pub/source/v18.4/postgresql-18.4.tar.bz2"
-sha256 = "81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094"
-
-[patches]
-directory = "../patches/postgresql-18.4"
-series = [
-  "0001-liboliphaunt-add-backend-host-io.patch",
-  "0002-liboliphaunt-add-embedded-entrypoint.patch",
-  "0003-liboliphaunt-return-from-embedded-frontend-terminate.patch",
-  "0004-liboliphaunt-run-embedded-exit-cleanup.patch",
-  "0005-liboliphaunt-restore-host-cwd.patch",
-  "0006-liboliphaunt-add-static-extension-loader.patch",
-  "0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch",
-  "0008-liboliphaunt-clean-embedded-symbols.patch",
-  "0009-liboliphaunt-guard-embedded-proc-exit.patch",
-  "0010-liboliphaunt-use-host-runtime-paths.patch",
-  "0011-liboliphaunt-add-android-embedded-shared-memory.patch",
-  "0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch",
-  "0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch",
-  "0014-liboliphaunt-use-portable-embedded-socketpair.patch",
-  "0015-liboliphaunt-add-embedded-meson-option.patch",
-  "0016-liboliphaunt-control-initdb-collation-discovery.patch",
-  "0017-liboliphaunt-namespace-dynahash-host-collisions.patch",
-  "0018-liboliphaunt-contain-embedded-proc-signals.patch",
-  "0019-liboliphaunt-link-windows-embedded-modules-to-host.patch",
-  "0020-liboliphaunt-enforce-embedded-signal-boundary.patch",
-]
diff --git a/src/runtimes/liboliphaunt/native/release.toml b/src/runtimes/liboliphaunt/native/release.toml
deleted file mode 100644
index f4d0bf043..000000000
--- a/src/runtimes/liboliphaunt/native/release.toml
+++ /dev/null
@@ -1,40 +0,0 @@
-id = "liboliphaunt-native"
-owner = "@oliphaunt/core"
-kind = "native-core"
-publish_targets = ["github-release-assets", "npm", "maven-central", "crates-io"]
-registry_packages = [
-  "crates:liboliphaunt-native-linux-arm64-gnu",
-  "crates:liboliphaunt-native-linux-x64-gnu",
-  "crates:liboliphaunt-native-macos-arm64",
-  "crates:liboliphaunt-native-windows-x64-msvc",
-  "crates:oliphaunt-tools",
-  "crates:oliphaunt-tools-linux-arm64-gnu",
-  "crates:oliphaunt-tools-linux-x64-gnu",
-  "crates:oliphaunt-tools-macos-arm64",
-  "crates:oliphaunt-tools-windows-x64-msvc",
-  "npm:@oliphaunt/icu",
-  "npm:@oliphaunt/liboliphaunt-darwin-arm64",
-  "npm:@oliphaunt/liboliphaunt-linux-x64-gnu",
-  "npm:@oliphaunt/liboliphaunt-linux-arm64-gnu",
-  "npm:@oliphaunt/liboliphaunt-win32-x64-msvc",
-  "npm:@oliphaunt/tools-darwin-arm64",
-  "npm:@oliphaunt/tools-linux-x64-gnu",
-  "npm:@oliphaunt/tools-linux-arm64-gnu",
-  "npm:@oliphaunt/tools-win32-x64-msvc",
-  "npm:@oliphaunt/tools",
-  "maven:dev.oliphaunt.runtime:oliphaunt-icu",
-  "maven:dev.oliphaunt.runtime:liboliphaunt-runtime-resources-android-datum64",
-  "maven:dev.oliphaunt.runtime:liboliphaunt-android-arm64-v8a",
-  "maven:dev.oliphaunt.runtime:liboliphaunt-android-x86_64",
-]
-release_artifacts = [
-  "c-headers",
-  "macos-dylib",
-  "linux-shared-library",
-  "windows-dll",
-  "ios-xcframework",
-  "android-shared-library",
-  "runtime-resources-ios-datum64",
-  "runtime-resources-android-datum64",
-  "icu-data",
-]
diff --git a/src/runtimes/liboliphaunt/native/tools-npm/package.json b/src/runtimes/liboliphaunt/native/tools-npm/package.json
deleted file mode 100644
index d2b57251b..000000000
--- a/src/runtimes/liboliphaunt/native/tools-npm/package.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
-  "name": "@oliphaunt/tools",
-  "version": "0.2.0",
-  "description": "Optional PostgreSQL pg_dump and psql runners for Oliphaunt native endpoints.",
-  "license": "MIT",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/tools-npm"
-  },
-  "bugs": {
-    "url": "https://github.com/f0rr0/oliphaunt/issues"
-  },
-  "homepage": "https://oliphaunt.dev",
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "exports": {
-    ".": {
-      "types": "./index.d.ts",
-      "default": "./index.js"
-    },
-    "./package.json": "./package.json"
-  },
-  "main": "index.js",
-  "types": "index.d.ts",
-  "files": [
-    "index.d.ts",
-    "index.js",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md"
-  ],
-  "optionalDependencies": {
-    "@oliphaunt/tools-darwin-arm64": "workspace:0.2.0",
-    "@oliphaunt/tools-linux-arm64-gnu": "workspace:0.2.0",
-    "@oliphaunt/tools-linux-x64-gnu": "workspace:0.2.0",
-    "@oliphaunt/tools-win32-x64-msvc": "workspace:0.2.0"
-  },
-  "engines": {
-    "node": ">=22.13 <25",
-    "bun": ">=1.3.14",
-    "deno": ">=2.8.1"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/tools-packages/darwin-arm64/package.json b/src/runtimes/liboliphaunt/native/tools-packages/darwin-arm64/package.json
deleted file mode 100644
index 4fcdfd7a6..000000000
--- a/src/runtimes/liboliphaunt/native/tools-packages/darwin-arm64/package.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
-  "name": "@oliphaunt/tools-darwin-arm64",
-  "version": "0.2.0",
-  "description": "macOS arm64 PostgreSQL client tools for Oliphaunt.",
-  "license": "MIT AND PostgreSQL",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/tools-packages/darwin-arm64"
-  },
-  "os": [
-    "darwin"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "product": "oliphaunt-tools",
-    "kind": "native-tools",
-    "target": "macos-arm64",
-    "runtimeRelativePath": "runtime"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./runtime/bin/pg_basebackup",
-      "./runtime/bin/pg_dump",
-      "./runtime/bin/psql"
-    ]
-  },
-  "files": [
-    "runtime",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/tools-packages/linux-arm64-gnu/package.json b/src/runtimes/liboliphaunt/native/tools-packages/linux-arm64-gnu/package.json
deleted file mode 100644
index 046477619..000000000
--- a/src/runtimes/liboliphaunt/native/tools-packages/linux-arm64-gnu/package.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-  "name": "@oliphaunt/tools-linux-arm64-gnu",
-  "version": "0.2.0",
-  "description": "Linux arm64 glibc PostgreSQL client tools for Oliphaunt.",
-  "license": "MIT AND PostgreSQL",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/tools-packages/linux-arm64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "product": "oliphaunt-tools",
-    "kind": "native-tools",
-    "target": "linux-arm64-gnu",
-    "runtimeRelativePath": "runtime"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./runtime/bin/pg_basebackup",
-      "./runtime/bin/pg_dump",
-      "./runtime/bin/psql"
-    ]
-  },
-  "files": [
-    "runtime",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/tools-packages/linux-x64-gnu/package.json b/src/runtimes/liboliphaunt/native/tools-packages/linux-x64-gnu/package.json
deleted file mode 100644
index 587c109c2..000000000
--- a/src/runtimes/liboliphaunt/native/tools-packages/linux-x64-gnu/package.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-  "name": "@oliphaunt/tools-linux-x64-gnu",
-  "version": "0.2.0",
-  "description": "Linux x64 glibc PostgreSQL client tools for Oliphaunt.",
-  "license": "MIT AND PostgreSQL",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/tools-packages/linux-x64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "product": "oliphaunt-tools",
-    "kind": "native-tools",
-    "target": "linux-x64-gnu",
-    "runtimeRelativePath": "runtime"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./runtime/bin/pg_basebackup",
-      "./runtime/bin/pg_dump",
-      "./runtime/bin/psql"
-    ]
-  },
-  "files": [
-    "runtime",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/tools-packages/win32-x64-msvc/package.json b/src/runtimes/liboliphaunt/native/tools-packages/win32-x64-msvc/package.json
deleted file mode 100644
index 486e2c97d..000000000
--- a/src/runtimes/liboliphaunt/native/tools-packages/win32-x64-msvc/package.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
-  "name": "@oliphaunt/tools-win32-x64-msvc",
-  "version": "0.2.0",
-  "description": "Windows x64 MSVC PostgreSQL client tools for Oliphaunt.",
-  "license": "MIT AND PostgreSQL",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/liboliphaunt/native/tools-packages/win32-x64-msvc"
-  },
-  "os": [
-    "win32"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "product": "oliphaunt-tools",
-    "kind": "native-tools",
-    "target": "windows-x64-msvc",
-    "runtimeRelativePath": "runtime"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true,
-    "executableFiles": [
-      "./runtime/bin/pg_basebackup.exe",
-      "./runtime/bin/pg_dump.exe",
-      "./runtime/bin/psql.exe"
-    ]
-  },
-  "files": [
-    "runtime",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"
-  ],
-  "exports": {
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/tools/build-ci-target.mjs b/src/runtimes/liboliphaunt/native/tools/build-ci-target.mjs
deleted file mode 100755
index 5461a98c2..000000000
--- a/src/runtimes/liboliphaunt/native/tools/build-ci-target.mjs
+++ /dev/null
@@ -1,184 +0,0 @@
-#!/usr/bin/env bun
-import { spawnSync } from "node:child_process";
-import { existsSync, mkdirSync, rmSync } from "node:fs";
-import path from "node:path";
-import process from "node:process";
-
-const PREFIX = "build-ci-target.mjs";
-const TARGETS = new Set(["android-arm64-v8a", "android-x86_64", "ios-xcframework"]);
-
-function fail(message, code = 1) {
-  console.error(message);
-  process.exit(code);
-}
-
-function formatArg(arg) {
-  return /^[A-Za-z0-9_./:=+-]+$/.test(arg) ? arg : JSON.stringify(arg);
-}
-
-function run(command, args = [], { env = {} } = {}) {
-  const envArgs = Object.entries(env).map(([key, value]) => `${key}=${formatArg(value)}`);
-  console.log(`\n==> ${[...envArgs, command, ...args].map(formatArg).join(" ")}`);
-  const result = spawnSync(command, args, {
-    stdio: "inherit",
-    env: { ...process.env, ...env },
-  });
-  if (result.error) {
-    fail(`${PREFIX}: ${result.error.message}`);
-  }
-  if (result.status !== 0) {
-    process.exit(result.status ?? 1);
-  }
-}
-
-function stagePath(root, stageRoot, source) {
-  const absoluteSource = path.resolve(source);
-  const relative = path.relative(root, absoluteSource);
-  if (relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) {
-    fail(`refusing to stage path outside repository: ${source}`);
-  }
-  if (!existsSync(absoluteSource)) {
-    fail(`missing CI target artifact input: ${absoluteSource}`);
-  }
-  const destination = path.join(stageRoot, relative);
-  mkdirSync(path.dirname(destination), { recursive: true });
-  run("rsync", ["-a", "--delete", `${absoluteSource}/`, `${destination}/`]);
-}
-
-function buildLinuxRuntimeAssets(workRoot) {
-  run("src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh", ["--runtime-only"], {
-    env: { OLIPHAUNT_LINUX_WORK_ROOT: workRoot },
-  });
-}
-
-function buildLinuxDirectRuntimeAssets(workRoot) {
-  run("src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh", [], {
-    env: { OLIPHAUNT_LINUX_WORK_ROOT: workRoot },
-  });
-}
-
-function buildMacosRuntimeAssets(workRoot) {
-  run("src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh", ["--runtime-only"], {
-    env: {
-      OLIPHAUNT_BUILD_EXTENSIONS: process.env.OLIPHAUNT_BUILD_EXTENSIONS ?? "0",
-      OLIPHAUNT_WORK_ROOT: workRoot,
-    },
-  });
-}
-
-function writeMobileAbiReceipt(buildRoot, target, output) {
-  run("bun", [
-    "tools/release/native-mobile-abi-contract.mjs",
-    "write",
-    "--build-root", buildRoot,
-    "--target", target,
-    "--output", output,
-  ]);
-}
-
-const root = path.resolve(import.meta.dir, "../../../../..");
-process.chdir(root);
-
-const target = process.argv[2] ?? "";
-if (!TARGETS.has(target)) {
-  fail(
-    "usage: src/runtimes/liboliphaunt/native/tools/build-ci-target.mjs [android-arm64-v8a|android-x86_64|ios-xcframework]",
-    2,
-  );
-}
-
-const mobileExtensions =
-  process.env.OLIPHAUNT_CI_MOBILE_EXTENSIONS ?? process.env.OLIPHAUNT_MOBILE_STATIC_EXTENSIONS ?? "";
-if (mobileExtensions !== "") {
-  fail(
-    "base liboliphaunt CI target builds do not accept selected extensions; publish exact extension artifacts through the extension artifact lane",
-    2,
-  );
-}
-
-const stageRoot = path.join(root, "target/liboliphaunt-native-ci", target);
-const hostWorkRoot = path.join(root, "target/liboliphaunt-mobile-host", target);
-rmSync(stageRoot, { recursive: true, force: true });
-mkdirSync(stageRoot, { recursive: true });
-
-if (target === "android-arm64-v8a") {
-  run("src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh", [], {
-    env: {
-      OLIPHAUNT_ANDROID_ABI: "arm64-v8a",
-      OLIPHAUNT_ANDROID_ARM64_ROOT: path.join(root, "target/liboliphaunt-pg18-android-arm64"),
-    },
-  });
-  buildLinuxRuntimeAssets(hostWorkRoot);
-  writeMobileAbiReceipt(
-    path.join(hostWorkRoot, "postgresql-18.4"),
-    "linux-x64-gnu",
-    path.join(root, "target/liboliphaunt-pg18-android-arm64/out/native-mobile-abi-producer.properties"),
-  );
-  writeMobileAbiReceipt(
-    path.join(root, "target/liboliphaunt-pg18-android-arm64/postgresql-18.4"),
-    "android-arm64-v8a",
-    path.join(root, "target/liboliphaunt-pg18-android-arm64/out/native-mobile-abi.properties"),
-  );
-  stagePath(root, stageRoot, path.join(root, "target/liboliphaunt-pg18-android-arm64/out"));
-  stagePath(root, stageRoot, path.join(hostWorkRoot, "install"));
-  stagePath(root, stageRoot, path.join(hostWorkRoot, "icu/share/icu"));
-} else if (target === "android-x86_64") {
-  run("src/runtimes/liboliphaunt/native/bin/build-postgres18-android-x86_64.sh", [], {
-    env: {
-      OLIPHAUNT_ANDROID_ABI: "x86_64",
-      OLIPHAUNT_ANDROID_X86_64_ROOT: path.join(root, "target/liboliphaunt-pg18-android-x86_64"),
-    },
-  });
-  buildLinuxDirectRuntimeAssets(hostWorkRoot);
-  writeMobileAbiReceipt(
-    path.join(hostWorkRoot, "postgresql-18.4"),
-    "linux-x64-gnu",
-    path.join(root, "target/liboliphaunt-pg18-android-x86_64/out/native-mobile-abi-producer.properties"),
-  );
-  writeMobileAbiReceipt(
-    path.join(root, "target/liboliphaunt-pg18-android-x86_64/postgresql-18.4"),
-    "android-x86_64",
-    path.join(root, "target/liboliphaunt-pg18-android-x86_64/out/native-mobile-abi.properties"),
-  );
-  stagePath(root, stageRoot, path.join(root, "target/liboliphaunt-pg18-android-x86_64/out"));
-  stagePath(root, stageRoot, path.join(hostWorkRoot, "install"));
-  stagePath(root, stageRoot, path.join(hostWorkRoot, "out/modules"));
-  stagePath(root, stageRoot, path.join(hostWorkRoot, "icu/share/icu"));
-} else if (target === "ios-xcframework") {
-  run("src/runtimes/liboliphaunt/native/bin/build-ios-xcframework.sh", [], {
-    env: { OLIPHAUNT_WORK_ROOT: hostWorkRoot },
-  });
-  buildMacosRuntimeAssets(hostWorkRoot);
-  const iosDeviceReceipt = path.join(root, "target/liboliphaunt-ios-device/out/native-mobile-abi.properties");
-  const iosSimulatorReceipt = path.join(root, "target/liboliphaunt-ios-simulator/out/native-mobile-abi.properties");
-  const macosProducerReceipt = path.join(root, "target/liboliphaunt-ios-xcframework/out/native-mobile-abi-producer.properties");
-  writeMobileAbiReceipt(
-    path.join(hostWorkRoot, "postgresql-18.4"),
-    "macos-arm64",
-    macosProducerReceipt,
-  );
-  writeMobileAbiReceipt(
-    path.join(root, "target/liboliphaunt-ios-device/postgresql-18.4"),
-    "ios-arm64",
-    iosDeviceReceipt,
-  );
-  writeMobileAbiReceipt(
-    path.join(root, "target/liboliphaunt-ios-simulator/postgresql-18.4"),
-    "ios-arm64-simulator",
-    iosSimulatorReceipt,
-  );
-  run("bun", [
-    "tools/release/native-mobile-abi-contract.mjs",
-    "compare",
-    "--domain", "ios-datum64",
-    "--receipt", iosDeviceReceipt,
-    "--receipt", iosSimulatorReceipt,
-    "--receipt", macosProducerReceipt,
-  ]);
-  stagePath(root, stageRoot, path.join(root, "target/liboliphaunt-ios-xcframework/out"));
-  stagePath(root, stageRoot, path.join(root, "target/liboliphaunt-ios-simulator/out"));
-  stagePath(root, stageRoot, path.join(root, "target/liboliphaunt-ios-device/out"));
-  stagePath(root, stageRoot, path.join(hostWorkRoot, "install"));
-}
-
-console.log(`\nStaged liboliphaunt CI target artifact: ${stageRoot}`);
diff --git a/src/runtimes/liboliphaunt/native/tools/build-release-runtime.mjs b/src/runtimes/liboliphaunt/native/tools/build-release-runtime.mjs
deleted file mode 100755
index a2e21fef2..000000000
--- a/src/runtimes/liboliphaunt/native/tools/build-release-runtime.mjs
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env node
-import { spawnSync } from 'node:child_process';
-import process from 'node:process';
-
-const env = { ...process.env };
-const ciTarget = env.OLIPHAUNT_CI_TARGET;
-const hostTargets = {
-  darwin: ['macos-arm64'],
-  linux: ['linux-arm64-gnu', 'linux-x64-gnu'],
-  win32: ['windows-x64-msvc'],
-};
-if (ciTarget && !hostTargets[process.platform]?.includes(ciTarget)) {
-  console.error(`cannot build native runtime target ${JSON.stringify(ciTarget)} on ${process.platform}`);
-  process.exit(2);
-}
-let command;
-let args;
-
-if (process.platform === 'darwin') {
-  env.OLIPHAUNT_BUILD_EXTENSIONS ??= '0';
-  command = 'bash';
-  args = ['src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh'];
-} else if (process.platform === 'linux') {
-  command = 'bash';
-  args = ['src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh'];
-} else if (process.platform === 'win32') {
-  command = 'pwsh';
-  args = [
-    '-NoProfile',
-    '-ExecutionPolicy',
-    'Bypass',
-    '-File',
-    'src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1',
-  ];
-} else {
-  console.error(`unsupported liboliphaunt release runtime host: ${process.platform}`);
-  process.exit(2);
-}
-
-const result = spawnSync(command, args, { stdio: 'inherit', env });
-if (result.error !== undefined) {
-  console.error(result.error.message);
-  process.exit(1);
-}
-process.exit(result.status ?? 1);
diff --git a/src/runtimes/liboliphaunt/native/tools/check-patch-stack.mjs b/src/runtimes/liboliphaunt/native/tools/check-patch-stack.mjs
deleted file mode 100755
index ed4a0328d..000000000
--- a/src/runtimes/liboliphaunt/native/tools/check-patch-stack.mjs
+++ /dev/null
@@ -1,541 +0,0 @@
-#!/usr/bin/env node
-import {execFileSync, spawnSync} from 'node:child_process';
-import {existsSync, readdirSync, readFileSync, writeFileSync} from 'node:fs';
-import path from 'node:path';
-
-const root = execFileSync('git', ['rev-parse', '--show-toplevel'], {
-  encoding: 'utf8',
-}).trim();
-const mode = process.argv[2] ?? '--check';
-const outputPath = path.join(root, 'docs/internal/OLIPHAUNT_PATCH_STACK.md');
-const sourceManifestPath = path.join(root, 'src/runtimes/liboliphaunt/native/postgres18/source.toml');
-const PATCH_CONSUMERS = [
-  'src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh',
-  'src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-device.sh',
-  'src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh',
-  'src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh',
-  'src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh',
-  'src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1',
-  'src/runtimes/liboliphaunt/native/bin/check-postgres18-ios-simulator.sh',
-];
-
-const REQUIRED_AUDIT_CHECKS = [
-  {
-    id: 'host-io-vtable',
-    requirement: 'Host-owned protocol I/O vtable',
-    patches: ['0001-liboliphaunt-add-backend-host-io.patch'],
-    evidence: ['OliphauntEmbeddedIO', 'secure_raw_read', 'secure_raw_write'],
-    posture: 'Generic libpq backend hook; normal socket I/O remains untouched.',
-  },
-  {
-    id: 'postmaster-waitset-guard',
-    requirement: 'Standalone backend waitset guard',
-    patches: ['0001-liboliphaunt-add-backend-host-io.patch'],
-    evidence: ['WL_POSTMASTER_DEATH', 'if (IsUnderPostmaster)'],
-    posture: 'Embedded standalone sessions avoid a postmaster-death wait handle that cannot exist.',
-  },
-  {
-    id: 'embedded-entrypoint',
-    requirement: 'Explicit embedded backend entrypoint',
-    patches: ['0002-liboliphaunt-add-embedded-entrypoint.patch'],
-    evidence: ['oliphaunt_embedded_main', 'pq_init(&client_sock)', 'PostgresMain(dbname, username)'],
-    posture: 'Uses PostgreSQL backend initialization and FE/BE protocol instead of single-user query transport.',
-  },
-  {
-    id: 'embedded-backend-return-contract',
-    requirement: 'Embedded BackendMain may return without violating its declaration',
-    patches: ['0013-liboliphaunt-fix-embedded-backend-main-return-contract.patch'],
-    evidence: ['#ifdef OLIPHAUNT_EMBEDDED', 'extern void BackendMain', 'pg_noreturn extern void BackendMain'],
-    posture: 'Only embedded builds drop pg_noreturn; normal PostgreSQL server builds retain the upstream non-returning contract.',
-  },
-  {
-    id: 'frontend-terminate-return',
-    requirement: 'Frontend Terminate returns to host owner',
-    patches: ['0003-liboliphaunt-return-from-embedded-frontend-terminate.patch'],
-    evidence: ['frontend sends Terminate', 'return;', 'proc_exit(0)'],
-    posture: 'Only OLIPHAUNT_EMBEDDED changes backend termination into a returning thread lifecycle.',
-  },
-  {
-    id: 'embedded-exit-cleanup',
-    requirement: 'PostgreSQL exit callbacks still run',
-    patches: ['0004-liboliphaunt-run-embedded-exit-cleanup.patch'],
-    evidence: ['oliphaunt_embedded_proc_exit', 'proc_exit_prepare(code)'],
-    posture: 'Keeps upstream cleanup ordering for shmem, locks, callbacks, and backend-local state.',
-  },
-  {
-    id: 'fatal-startup-guard',
-    requirement: 'Startup FATAL does not exit the host process',
-    patches: ['0009-liboliphaunt-guard-embedded-proc-exit.patch'],
-    evidence: ['oliphaunt_embedded_set_proc_exit_handler', 'siglongjmp', 'proc_exit_handler'],
-    posture: 'Embedded startup failures unwind to liboliphaunt after PostgreSQL cleanup callbacks run.',
-  },
-  {
-    id: 'fatal-startup-cleanup-label',
-    requirement: 'Embedded proc_exit guard is cleared before returning to host',
-    patches: ['0009-liboliphaunt-guard-embedded-proc-exit.patch'],
-    evidence: ['embedded_cleanup:', 'oliphaunt_embedded_set_proc_exit_handler(NULL, NULL)', 'chdir(original_cwd)'],
-    posture: 'Normal and FATAL startup paths share one cleanup label so thread-local exit guards and host cwd are restored before returning.',
-  },
-  {
-    id: 'cwd-restore',
-    requirement: 'Host working directory is restored',
-    patches: ['0005-liboliphaunt-restore-host-cwd.patch'],
-    evidence: ['original_cwd', 'getcwd(original_cwd', 'chdir(original_cwd)'],
-    posture: 'Contains PostgreSQL standalone ChangeToDataDir side effects inside the backend lifetime.',
-  },
-  {
-    id: 'static-extension-loader',
-    requirement: 'Static extension registry uses PostgreSQL dfmgr path',
-    patches: ['0006-liboliphaunt-add-static-extension-loader.patch'],
-    evidence: ['oliphaunt_static_extension_lookup', 'lookup_library_symbol', 'oliphaunt_static_extension_symbol'],
-    posture: 'CREATE EXTENSION/LOAD semantics stay in PostgreSQL; hosts only provide module symbols.',
-  },
-  {
-    id: 'msvc-static-extension-loader-defaults',
-    requirement: 'MSVC PostgreSQL tools link without static extension providers',
-    patches: ['0006-liboliphaunt-add-static-extension-loader.patch'],
-    evidence: [
-      'defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))',
-      '/alternatename:oliphaunt_static_extension_lookup=oliphaunt_static_extension_lookup_default',
-      'oliphaunt_static_extension_symbol_default',
-    ],
-    posture: 'Meson-built PostgreSQL tools get no-op static extension hooks on MSVC; liboliphaunt still overrides them by linking the real registry provider.',
-  },
-  {
-    id: 'portable-static-extension-loader-defaults',
-    requirement: 'Portable PostgreSQL tools link without static extension providers',
-    patches: ['0006-liboliphaunt-add-static-extension-loader.patch'],
-    evidence: [
-      '#define OLIPHAUNT_OPTIONAL_HOOK __attribute__((weak))',
-      'oliphaunt_static_extension_lookup(const char *filename)',
-      'oliphaunt_static_extension_init(const OliphauntStaticExtension *extension)',
-    ],
-    posture: 'Non-MSVC embedded PostgreSQL tool links get weak no-op static extension hooks; liboliphaunt overrides them by linking the real registry provider.',
-  },
-  {
-    id: 'static-extension-magic',
-    requirement: 'Static extension ABI magic is validated',
-    patches: [
-      '0006-liboliphaunt-add-static-extension-loader.patch',
-      '0008-liboliphaunt-clean-embedded-symbols.patch',
-    ],
-    evidence: ['oliphaunt_static_extension_magic', 'Pg_magic_struct', 'memcmp(&magic_data_ptr->abi_fields'],
-    posture: 'Static modules still pass PostgreSQL ABI checks before symbols are used.',
-  },
-  {
-    id: 'host-runtime-paths',
-    requirement: 'Runtime paths come from host-packaged resources',
-    patches: ['0010-liboliphaunt-use-host-runtime-paths.patch'],
-    evidence: ['oliphaunt_embedded_set_runtime_paths', 'OLIPHAUNT_EMBEDDED_MODULE_DIR', 'my_exec_path', 'PGSYSCONFDIR'],
-    posture: 'Avoids executable-bit assumptions for mobile resources while preserving runtime path derivation and using host-packaged embedded modules for pkglib_path.',
-  },
-  {
-    id: 'apple-mobile-shell-exclusion',
-    requirement: 'Apple mobile builds do not call system(3)',
-    patches: ['0007-liboliphaunt-disable-shell-commands-on-apple-mobile.patch'],
-    evidence: ['OLIPHAUNT_EMBEDDED_NO_SHELL_COMMANDS', 'TARGET_OS_IPHONE', 'archive_command cannot be executed'],
-    posture: 'Mobile direct mode fails optional shell archive/restore hooks explicitly instead of compiling unavailable APIs.',
-  },
-  {
-    id: 'embedded-mobile-shared-memory',
-    requirement: 'Embedded mobile shared memory and semaphores are process-local',
-    patches: ['0011-liboliphaunt-add-android-embedded-shared-memory.patch'],
-    evidence: ['oliphaunt_embedded_shmem.c', 'oliphaunt_embedded_sema.c', 'OLIPHAUNT_EMBEDDED_MOBILE_SHMEM'],
-    posture: 'Android and Apple mobile builds avoid unavailable SysV shared memory and semaphores while direct mode remains one backend per process.',
-  },
-  {
-    id: 'event-trigger-policy',
-    requirement: 'Event triggers run in embedded protocol sessions',
-    patches: ['0012-liboliphaunt-enable-event-triggers-in-embedded-backend.patch'],
-    evidence: ['EventTriggersHaveRunnableBackend', 'OLIPHAUNT_EMBEDDED', 'event_triggers'],
-    posture: 'Keeps upstream single-user escape hatch outside OLIPHAUNT_EMBEDDED but treats embedded protocol sessions as runnable backends.',
-  },
-  {
-    id: 'embedded-meson-option',
-    requirement: 'Meson builds expose an explicit embedded backend option',
-    patches: ['0015-liboliphaunt-add-embedded-meson-option.patch'],
-    evidence: ['oliphaunt_embedded', 'add_project_arguments', '-DOLIPHAUNT_EMBEDDED'],
-    posture: 'Windows and other Meson-hosted embedded builds enable the backend entrypoint through PostgreSQL build configuration while default server builds remain unchanged.',
-  },
-  {
-    id: 'optional-icu-initdb',
-    requirement: 'Optional ICU data stays optional during initdb',
-    patches: ['0016-liboliphaunt-control-initdb-collation-discovery.patch'],
-    evidence: ['OLIPHAUNT_INTERNAL_ICU_READY', 'OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY', 'OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY', 'strcmp', 'pg_collation_actual_version', 'pg_import_system_collations'],
-    posture: 'Ordinary initdb and public collation import retain PostgreSQL host discovery. Distributed standard seeds suppress OS and ICU discovery; ICU seeds suppress only OS discovery and verify ICU readiness for initdb\'s unicode-version probe.',
-  },
-  {
-    id: 'apple-dynahash-namespace',
-    requirement: 'Apple builds namespace PostgreSQL dynahash symbols that collide with libSystem',
-    patches: ['0017-liboliphaunt-namespace-dynahash-host-collisions.patch'],
-    evidence: ['#ifdef __APPLE__', 'oliphaunt_pg_hash_create', 'oliphaunt_pg_hash_destroy', 'oliphaunt_pg_hash_search'],
-    posture: 'Apple backend and extension objects share collision-free dynahash names; non-Apple PostgreSQL binary names remain unchanged.',
-  },
-  {
-    id: 'embedded-procsignal-containment',
-    requirement: 'Embedded ProcSignal delivery cannot escape into the host process',
-    patches: ['0018-liboliphaunt-contain-embedded-proc-signals.patch'],
-    evidence: ['oliphaunt_send_proc_signal', 'pid != MyProcPid', 'procsignal_sigusr1_handler(SIGUSR1)', 'host owns SIGUSR1'],
-    posture: 'The one-backend embedded runtime dispatches ProcSignal flags synchronously, rejects foreign PIDs, and leaves the host SIGUSR1 disposition untouched; normal PostgreSQL server builds retain upstream signal delivery.',
-  },
-  {
-    id: 'windows-embedded-module-provider',
-    requirement: 'Windows embedded extension modules link to the host DLL provider',
-    patches: ['0019-liboliphaunt-link-windows-embedded-modules-to-host.patch'],
-    evidence: [
-      'oliphaunt_embedded_module_provider',
-      "requires an embedded MSVC Windows build",
-      'pg_mod_link_args += oliphaunt_embedded_module_provider',
-      "oliphaunt_embedded_module_provider == ''",
-    ],
-    posture: 'Embedded MSVC extension modules resolve PostgreSQL backend symbols from the oliphaunt host import library; ordinary PostgreSQL modules retain the upstream postgres executable link contract.',
-  },
-  {
-    id: 'embedded-host-signal-boundary',
-    requirement: 'Embedded backend and extension signal calls preserve host SIGUSR1 ownership',
-    patches: ['0020-liboliphaunt-enforce-embedded-signal-boundary.patch'],
-    evidence: [
-      'oliphaunt_embedded_kill',
-      'oliphaunt_embedded_raise',
-      '!defined(FRONTEND)',
-      'if (signo == SIGUSR1)',
-    ],
-    posture: 'Embedded backend and extension calls cannot replace or emit host-owned SIGUSR1; other signals delegate to the platform implementation, while frontend tools and normal PostgreSQL builds retain upstream behavior.',
-  },
-];
-
-const EXPECTED_UPSTREAM_TOUCHPOINTS = new Map([
-  ['meson.build', 'Meson-hosted embedded builds enable OLIPHAUNT_EMBEDDED through an explicit opt-in build option.'],
-  ['meson_options.txt', 'Meson-hosted embedded builds declare opt-in backend and Windows module-provider options without changing default PostgreSQL builds.'],
-  ['src/backend/access/transam/xlogarchive.c', 'Apple mobile embedded builds compile out optional archive shell commands.'],
-  ['src/backend/archive/shell_archive.c', 'Apple mobile embedded builds compile out optional archive shell commands.'],
-  ['src/backend/commands/event_trigger.c', 'Embedded FE/BE protocol sessions can run event triggers without changing standalone recovery behavior.'],
-  ['src/backend/commands/collationcmds.c', 'System-collation import preserves host providers except during deliberate deterministic distributed-seed production; verified ICU readiness independently gates only the ICU provider.'],
-  ['src/backend/libpq/be-secure.c', 'Backend secure read/write path delegates to a host I/O vtable only when OLIPHAUNT_EMBEDDED is set.'],
-  ['src/backend/libpq/pqcomm.c', 'Standalone embedded sessions avoid waiting on a non-existent postmaster death latch.'],
-  ['src/backend/port/Makefile', 'Embedded mobile builds swap unavailable SysV shared memory and semaphores for process-local implementations.'],
-  ['src/backend/port/meson.build', 'Android embedded builds swap unavailable SysV shared memory and semaphores for process-local implementations.'],
-  ['src/backend/port/oliphaunt_embedded_sema.c', 'Embedded mobile semaphore implementation for one backend in one process.'],
-  ['src/backend/port/oliphaunt_embedded_shmem.c', 'Embedded mobile shared memory implementation for one backend in one process.'],
-  ['src/backend/meson.build', 'Embedded MSVC extension modules link to the oliphaunt host import library instead of the standalone postgres executable.'],
-  ['src/backend/storage/ipc/ipc.c', 'Embedded backend cleanup and proc_exit unwinding stay at PostgreSQL lifecycle boundaries.'],
-  ['src/backend/storage/ipc/procsignal.c', 'The one-backend embedded runtime dispatches ProcSignal flags without sending process-directed host signals.'],
-  ['src/backend/tcop/postgres.c', 'Embedded backend entrypoint, protocol lifecycle, cwd restoration, host runtime paths, and host-owned SIGUSR1 disposition.'],
-  ['src/backend/utils/fmgr/dfmgr.c', 'Static extension lookup reuses PostgreSQL dynamic function manager semantics.'],
-  [
-    'src/bin/initdb/initdb.c',
-    'Controlled seed production selects standard or verified ICU collation discovery without changing ordinary initdb semantics.',
-  ],
-  ['src/include/libpq/libpq-be.h', 'Host I/O vtable is attached to PostgreSQL Port state under OLIPHAUNT_EMBEDDED.'],
-  ['src/include/tcop/backend_startup.h', 'Embedded BackendMain may return after its returning PostgresMain call without retaining an invalid pg_noreturn declaration.'],
-  ['src/include/port.h', 'Embedded mobile builds avoid POSIX shared memory declarations and route embedded backend signal calls through the host-safe provider boundary.'],
-  ['src/include/storage/dsm_impl.h', 'Embedded mobile builds keep DSM on mmap instead of POSIX or SysV shared memory.'],
-  ['src/include/storage/ipc.h', 'Embedded cleanup and proc_exit guard declarations.'],
-  ['src/include/tcop/tcopprot.h', 'Embedded entrypoint and returning PostgresMain declarations.'],
-  ['src/include/utils/hsearch.h', 'Apple builds namespace PostgreSQL dynahash symbols that otherwise bind to unrelated libSystem exports.'],
-  ['src/port/chklocale.c', 'Android embedded builds avoid unsupported locale-environment mutation.'],
-  ['src/port/pqsignal.c', 'Embedded backend signal registration and emission preserve the host-owned SIGUSR1 disposition while delegating other signals.'],
-]);
-
-if (!['--check', '--write'].includes(mode)) {
-  console.error('usage: src/runtimes/liboliphaunt/native/tools/check-patch-stack.mjs [--check|--write]');
-  process.exit(2);
-}
-
-function read(relativePath) {
-  return readFileSync(path.join(root, relativePath), 'utf8');
-}
-
-function parseSourceManifest() {
-  const text = readFileSync(sourceManifestPath, 'utf8');
-  const version = matchRequired(text, /version\s*=\s*"([^"]+)"/u, 'postgresql.version');
-  const url = matchRequired(text, /url\s*=\s*"([^"]+)"/u, 'postgresql.url');
-  const sha256 = matchRequired(text, /sha256\s*=\s*"([^"]+)"/u, 'postgresql.sha256');
-  const directory = matchRequired(text, /directory\s*=\s*"([^"]+)"/u, 'patches.directory');
-  const seriesBlock = matchRequired(text, /series\s*=\s*\[([\s\S]*?)\]/u, 'patches.series');
-  const series = Array.from(seriesBlock.matchAll(/"([^"]+\.patch)"/gu), match => match[1]);
-  if (series.length === 0) {
-    throw new Error('src/runtimes/liboliphaunt/native/postgres18/source.toml patch series is empty');
-  }
-  const patchDir = path.resolve(path.dirname(sourceManifestPath), directory);
-  return {version, url, sha256, directory, patchDir, series};
-}
-
-function matchRequired(text, pattern, label) {
-  const match = text.match(pattern);
-  if (!match) {
-    throw new Error(`missing ${label} in src/runtimes/liboliphaunt/native/postgres18/source.toml`);
-  }
-  return match[1];
-}
-
-function patchFiles(patchDir) {
-  return readdirSync(patchDir)
-    .filter(name => name.endsWith('.patch'))
-    .sort();
-}
-
-function parsePatch(fileName, patchDir) {
-  const relativePath = `src/runtimes/liboliphaunt/native/patches/${path.basename(patchDir)}/${fileName}`;
-  const text = read(relativePath);
-  const trailingWhitespaceLine = text
-    .split(/\r?\n/u)
-    .findIndex(line => /[\t ]+$/u.test(line));
-  if (trailingWhitespaceLine !== -1) {
-    throw new Error(
-      `${relativePath}:${trailingWhitespaceLine + 1} contains trailing whitespace`,
-    );
-  }
-  if (/\r?\n-- ?\r?\n[0-9]+(?:[.][0-9]+){1,2}\r?\n?$/u.test(text)) {
-    throw new Error(`${relativePath} must not include a format-patch tool signature footer`);
-  }
-  const syntax = spawnSync('git', ['apply', '--numstat', '--whitespace=error-all', relativePath], {
-    cwd: root,
-    encoding: 'utf8',
-  });
-  if (syntax.error !== undefined || syntax.status !== 0 || syntax.stderr.trim() !== '') {
-    const detail = syntax.error?.message ?? (syntax.stderr.trim() || `git apply exited ${syntax.status}`);
-    throw new Error(`${relativePath} is not a warning-free strict Git patch: ${detail}`);
-  }
-  const author = text.match(/^From:\s+(.+)$/mu)?.[1];
-  if (!author) {
-    throw new Error(`${relativePath} must have a deterministic From: header`);
-  }
-  if (author !== 'liboliphaunt ') {
-    throw new Error(
-      `${relativePath} From: header must be "liboliphaunt ", got ${author}`,
-    );
-  }
-  const subjectHeader = text.match(/^Subject:[ \t]+(.+(?:\r?\n[ \t]+.+)*)/mu)?.[1]
-    ?.replace(/\r?\n[ \t]+/gu, ' ');
-  const subject = subjectHeader?.match(/^\[PATCH\][ \t]+(.+)$/u)?.[1];
-  if (!subject) {
-    throw new Error(`${relativePath} must have a deterministic Subject: [PATCH] header`);
-  }
-  if (!subject.startsWith('liboliphaunt: ')) {
-    throw new Error(`${relativePath} subject must start with "liboliphaunt: "`);
-  }
-
-  const changedFiles = Array.from(
-    text.matchAll(/^diff --git a\/(.+?) b\/(.+)$/gmu),
-    match => match[2],
-  );
-  if (changedFiles.length === 0) {
-    throw new Error(`${relativePath} does not contain any diff --git file entries`);
-  }
-
-  const forbidden = [];
-  const whitespaceProblems = [];
-  const symbols = new Set();
-  for (const [index, line] of text.split('\n').entries()) {
-    if (!line.startsWith('+') || line.startsWith('+++')) {
-      continue;
-    }
-    if (line !== '+' && /[ \t]$/u.test(line)) {
-      whitespaceProblems.push(`${index + 1}: ${line}`);
-    }
-    if (/^\+ \t/u.test(line)) {
-      whitespaceProblems.push(`${index + 1}: ${line}`);
-    }
-    if (/\b(Swift|Kotlin|React|JavaScript|TypeScript|wasix|wasmer|wasm|oliphaunt-wasix)\b/iu.test(line)) {
-      forbidden.push(line);
-    }
-    if (/\b(extern|PGDLLIMPORT|oliphaunt_embedded_main|oliphaunt_embedded_proc_exit)\b/u.test(line)) {
-      for (const symbol of line.matchAll(/\b(oliphaunt_[A-Za-z0-9_]+)\b/gu)) {
-        symbols.add(symbol[1]);
-      }
-    }
-  }
-  if (forbidden.length > 0) {
-    throw new Error(
-      `${relativePath} contains product-specific terms in added PostgreSQL code:\n${forbidden.join('\n')}`,
-    );
-  }
-  if (whitespaceProblems.length > 0) {
-    throw new Error(
-      `${relativePath} contains whitespace problems in added PostgreSQL code:\n${whitespaceProblems.join('\n')}`,
-    );
-  }
-
-  return {
-    fileName,
-    relativePath,
-    author,
-    subject,
-    changedFiles,
-    symbols: Array.from(symbols).sort(),
-  };
-}
-
-function validateSeries(manifest, actualFiles) {
-  const expected = manifest.series;
-  if (JSON.stringify(expected) !== JSON.stringify(actualFiles)) {
-    const expectedText = expected.map(name => `  ${name}`).join('\n');
-    const actualText = actualFiles.map(name => `  ${name}`).join('\n');
-    throw new Error(
-      `source.toml patch series must exactly match patch directory files\nexpected:\n${expectedText}\nactual:\n${actualText}`,
-    );
-  }
-}
-
-function validatePatchConsumers() {
-  for (const consumer of PATCH_CONSUMERS) {
-    const text = read(consumer);
-    if (text.includes('--recount') || text.includes('--whitespace=nowarn')) {
-      throw new Error(`${consumer} must not relax PostgreSQL patch parsing with --recount or --whitespace=nowarn`);
-    }
-    if (!text.includes('git apply --whitespace=error-all')) {
-      throw new Error(`${consumer} must apply PostgreSQL patches with git apply --whitespace=error-all`);
-    }
-  }
-}
-
-function render() {
-  const manifest = parseSourceManifest();
-  const actualFiles = patchFiles(manifest.patchDir);
-  validateSeries(manifest, actualFiles);
-  validatePatchConsumers();
-  const patches = actualFiles.map(fileName => parsePatch(fileName, manifest.patchDir));
-  const patchesByName = new Map(patches.map(patch => [patch.fileName, patch]));
-
-  const changedFiles = new Map();
-  const symbols = new Map();
-  for (const patch of patches) {
-    for (const file of patch.changedFiles) {
-      if (!changedFiles.has(file)) {
-        changedFiles.set(file, []);
-      }
-      changedFiles.get(file).push(patch.fileName);
-    }
-    for (const symbol of patch.symbols) {
-      if (!symbols.has(symbol)) {
-        symbols.set(symbol, []);
-      }
-      symbols.get(symbol).push(patch.fileName);
-    }
-  }
-
-  for (const file of changedFiles.keys()) {
-    if (!EXPECTED_UPSTREAM_TOUCHPOINTS.has(file)) {
-      throw new Error(
-        `patch-stack audit found unexpected upstream touchpoint ${file}; add an explicit rationale before changing it`,
-      );
-    }
-  }
-  for (const file of EXPECTED_UPSTREAM_TOUCHPOINTS.keys()) {
-    if (!changedFiles.has(file)) {
-      throw new Error(`patch-stack audit expected upstream touchpoint ${file} is no longer changed`);
-    }
-  }
-
-  for (const check of REQUIRED_AUDIT_CHECKS) {
-    for (const patchName of check.patches) {
-      if (!patchesByName.has(patchName)) {
-        throw new Error(`patch-stack audit check ${check.id} references missing patch ${patchName}`);
-      }
-    }
-    const checkText = check.patches
-      .map(patchName => read(patchesByName.get(patchName).relativePath))
-      .join('\n');
-    const missing = check.evidence.filter(fragment => !checkText.includes(fragment));
-    if (missing.length > 0) {
-      throw new Error(
-        `patch-stack audit check ${check.id} is missing evidence in ${check.patches.join(', ')}: ${missing.join(', ')}`,
-      );
-    }
-  }
-
-  const lines = [];
-  lines.push('');
-  lines.push('# liboliphaunt PostgreSQL 18 Patch Stack Review');
-  lines.push('');
-  lines.push('This source-only review artifact keeps the native PostgreSQL patch stack deterministic and reviewable without rebuilding PostgreSQL.');
-  lines.push('');
-  lines.push('Regenerate with:');
-  lines.push('');
-  lines.push('```sh');
-  lines.push('src/runtimes/liboliphaunt/native/tools/check-patch-stack.mjs --write');
-  lines.push('```');
-  lines.push('');
-  lines.push('## Source Pin');
-  lines.push('');
-  lines.push(`- PostgreSQL: \`${manifest.version}\``);
-  lines.push(`- URL: \`${manifest.url}\``);
-  lines.push(`- SHA-256: \`${manifest.sha256}\``);
-  lines.push(`- Patch directory: \`${manifest.directory}\``);
-  lines.push('');
-  lines.push('## Patch Series');
-  lines.push('');
-  lines.push('| Order | Patch | Author | Subject |');
-  lines.push('| --- | --- | --- | --- |');
-  patches.forEach((patch, index) => {
-    lines.push(`| ${index + 1} | \`${patch.fileName}\` | ${patch.author} | ${patch.subject} |`);
-  });
-  lines.push('');
-  lines.push('## Changed Upstream Files');
-  lines.push('');
-  for (const [file, owners] of Array.from(changedFiles.entries()).sort()) {
-    lines.push(`- \`${file}\` (${owners.map(owner => `\`${owner}\``).join(', ')})`);
-  }
-  lines.push('');
-  lines.push('## Expected Upstream Touchpoints');
-  lines.push('');
-  lines.push('| File | Rationale |');
-  lines.push('| --- | --- |');
-  for (const [file, rationale] of Array.from(EXPECTED_UPSTREAM_TOUCHPOINTS.entries()).sort()) {
-    lines.push(`| \`${file}\` | ${rationale} |`);
-  }
-  lines.push('');
-  lines.push('## PostgreSQL Patch Symbols');
-  lines.push('');
-  if (symbols.size === 0) {
-    lines.push('- none');
-  } else {
-    for (const [symbol, owners] of Array.from(symbols.entries()).sort()) {
-      lines.push(`- \`${symbol}\` (${owners.map(owner => `\`${owner}\``).join(', ')})`);
-    }
-  }
-  lines.push('');
-  lines.push('## Audit Checklist');
-  lines.push('');
-  lines.push('| Requirement | Owning Patch | Required Evidence | Review Posture |');
-  lines.push('| --- | --- | --- | --- |');
-  for (const check of REQUIRED_AUDIT_CHECKS) {
-    lines.push(
-      `| ${check.requirement} | ${check.patches.map(patch => `\`${patch}\``).join(', ')} | ${check.evidence.map(fragment => `\`${fragment}\``).join(', ')} | ${check.posture} |`,
-    );
-  }
-  lines.push('');
-  lines.push('## Guardrails');
-  lines.push('');
-  lines.push('- `source.toml` patch series exactly matches the patch directory.');
-  lines.push('- Every patch has a deterministic `From: liboliphaunt ` header.');
-  lines.push('- Every patch has a deterministic `Subject: [PATCH] liboliphaunt: ...` header.');
-  lines.push('- Entire patch files are checked for trailing whitespace; added PostgreSQL lines are also checked for space-before-tab indentation and SDK/runtime/product-specific terms that belong above PostgreSQL.');
-  lines.push('- Changed upstream files must exactly match the expected touchpoint table above; new upstream touchpoints need an explicit rationale before landing.');
-  lines.push('- Required audit checks prove their evidence in the named owning patch or patches, keeping host I/O, embedded lifecycle, cleanup, cwd restore, runtime paths, static extensions, host-signal containment, Windows module linkage, mobile shell exclusion, embedded mobile shared memory, and event triggers reviewable independently.');
-  lines.push('- Changed upstream files and patch-introduced `oliphaunt_*` symbols are listed here for release review.');
-  lines.push('');
-
-  return `${lines.join('\n')}`;
-}
-
-function normalizeGeneratedMarkdown(text) {
-  return text.replace(/\r\n/gu, '\n').replace(/\r/gu, '\n').trimEnd();
-}
-
-try {
-  const generated = render();
-  if (mode === '--write') {
-    writeFileSync(outputPath, generated, 'utf8');
-  } else {
-    const current = existsSync(outputPath) ? readFileSync(outputPath, 'utf8') : '';
-    if (normalizeGeneratedMarkdown(current) !== normalizeGeneratedMarkdown(generated)) {
-      console.error('docs/internal/OLIPHAUNT_PATCH_STACK.md is stale; run src/runtimes/liboliphaunt/native/tools/check-patch-stack.mjs --write');
-      process.exit(1);
-    }
-  }
-} catch (error) {
-  console.error(error instanceof Error ? error.message : String(error));
-  process.exit(1);
-}
diff --git a/src/runtimes/liboliphaunt/native/tools/package-release-runtime.mjs b/src/runtimes/liboliphaunt/native/tools/package-release-runtime.mjs
deleted file mode 100644
index 9f0285ca6..000000000
--- a/src/runtimes/liboliphaunt/native/tools/package-release-runtime.mjs
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env node
-import {spawnSync} from 'node:child_process';
-import process from 'node:process';
-
-const target = process.env.OLIPHAUNT_CI_TARGET ?? '';
-const targets = {
-  darwin: {allowed: ['macos-arm64'], command: 'bash', args: ['tools/release/package-liboliphaunt-macos-assets.sh']},
-  linux: {allowed: ['linux-arm64-gnu', 'linux-x64-gnu'], command: 'bash', args: ['tools/release/package-liboliphaunt-linux-assets.sh']},
-  win32: {
-    allowed: ['windows-x64-msvc'],
-    command: 'pwsh',
-    args: ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', 'tools/release/package-liboliphaunt-windows-assets.ps1'],
-  },
-};
-const plan = targets[process.platform];
-if (!plan?.allowed.includes(target)) {
-  console.error(`cannot package native runtime target ${JSON.stringify(target)} on ${process.platform}`);
-  process.exit(2);
-}
-const result = spawnSync(plan.command, plan.args, {
-  stdio: 'inherit',
-  env: {
-    ...process.env,
-    OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS: `target/liboliphaunt/desktop-release-assets/${target}`,
-    OLIPHAUNT_RELEASE_BUILD_RUNTIME: '0',
-    OLIPHAUNT_RELEASE_FETCH_ASSETS: '0',
-  },
-});
-if (result.error) console.error(result.error.message);
-process.exit(result.status ?? 1);
diff --git a/src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs b/src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs
deleted file mode 100755
index 0823827a7..000000000
--- a/src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs
+++ /dev/null
@@ -1,604 +0,0 @@
-#!/usr/bin/env node
-import childProcess from 'node:child_process';
-import fs from 'node:fs';
-import os from 'node:os';
-import path from 'node:path';
-
-const PG_VERSION = '18.4';
-
-function usage() {
-  console.error(`usage: src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs [--abi-only|--smoke-only] [--cluster-seeds] [--root ]
-
-Compiles and runs the host liboliphaunt C ABI smoke against the current native
-runtime artifacts for macOS, Linux, or Windows.
-
-Set LIBOLIPHAUNT_PATH and OLIPHAUNT_INSTALL_DIR to smoke a staged release
-layout. Set OLIPHAUNT_SMOKE_BIN_DIR to keep compiled smoke binaries out of that
-layout. Set OLIPHAUNT_SMOKE_ROOT to run database scratch roots outside the
-build work root.`);
-}
-
-function parseArgs(argv) {
-  const args = {
-    abiOnly: false,
-    smokeOnly: false,
-    clusterSeeds: false,
-    root: '',
-  };
-  for (let index = 0; index < argv.length; index++) {
-    const arg = argv[index];
-    if (arg === '--abi-only') {
-      args.abiOnly = true;
-    } else if (arg === '--smoke-only') {
-      args.smokeOnly = true;
-    } else if (arg === '--cluster-seeds') {
-      args.clusterSeeds = true;
-    } else if (arg === '--root') {
-      index++;
-      if (index >= argv.length) {
-        throw new Error('--root requires a directory');
-      }
-      args.root = argv[index];
-    } else if (arg === '--help' || arg === '-h') {
-      usage();
-      process.exit(0);
-    } else if (!arg.startsWith('-') && !args.root) {
-      args.root = arg;
-    } else {
-      throw new Error(`unknown argument: ${arg}`);
-    }
-  }
-  if (args.abiOnly && args.smokeOnly) {
-    throw new Error('--abi-only and --smoke-only are mutually exclusive');
-  }
-  if (args.abiOnly && args.clusterSeeds) {
-    throw new Error('--abi-only and --cluster-seeds are mutually exclusive');
-  }
-  return args;
-}
-
-function run(command, args, options = {}) {
-  const rendered = [command, ...args].join(' ');
-  console.error(`\n==> ${rendered}`);
-  const result = childProcess.spawnSync(command, args, {
-    cwd: options.cwd,
-    env: options.env ?? process.env,
-    encoding: 'utf8',
-    shell: false,
-    stdio: options.capture ? ['ignore', 'pipe', 'pipe'] : 'inherit',
-    windowsVerbatimArguments: options.windowsVerbatimArguments ?? false,
-  });
-  if (result.error) {
-    throw result.error;
-  }
-  if (result.status !== 0) {
-    if (options.capture) {
-      process.stderr.write(result.stderr ?? '');
-      process.stderr.write(result.stdout ?? '');
-    }
-    throw new Error(`${rendered} exited with status ${result.status}`);
-  }
-  return result.stdout ?? '';
-}
-
-function commandExists(command, env = process.env) {
-  const result = process.platform === 'win32'
-    ? childProcess.spawnSync('where.exe', [command], { env, stdio: 'ignore' })
-    : childProcess.spawnSync('sh', ['-c', 'command -v "$1" >/dev/null 2>&1', 'sh', command], {
-      env,
-      stdio: 'ignore',
-    });
-  return result.status === 0;
-}
-
-function executableExists(file) {
-  if (!fs.existsSync(file)) {
-    return false;
-  }
-  if (process.platform === 'win32') {
-    return true;
-  }
-  try {
-    fs.accessSync(file, fs.constants.X_OK);
-    return true;
-  } catch {
-    return false;
-  }
-}
-
-function requireExecutable(file, label) {
-  if (!executableExists(file)) {
-    throw new Error(`missing ${label}: ${file}`);
-  }
-}
-
-function repoRoot() {
-  const output = childProcess.spawnSync('git', ['rev-parse', '--show-toplevel'], {
-    encoding: 'utf8',
-    stdio: ['ignore', 'pipe', 'ignore'],
-  });
-  if (output.status === 0 && output.stdout.trim()) {
-    return output.stdout.trim();
-  }
-  return path.resolve(new URL('../../..', import.meta.url).pathname);
-}
-
-function hostTarget() {
-  if (process.platform === 'darwin') {
-    return process.arch === 'x64' ? 'macos-x64' : 'macos-arm64';
-  }
-  if (process.platform === 'linux') {
-    if (process.arch === 'x64') {
-      return 'linux-x64-gnu';
-    }
-    if (process.arch === 'arm64') {
-      return 'linux-arm64-gnu';
-    }
-  }
-  if (process.platform === 'win32' && process.arch === 'x64') {
-    return 'windows-x64-msvc';
-  }
-  throw new Error(`unsupported liboliphaunt host target: ${process.platform}/${process.arch}`);
-}
-
-function defaultWorkRoot(root, target) {
-  if (process.env.OLIPHAUNT_WORK_ROOT) {
-    return path.resolve(process.env.OLIPHAUNT_WORK_ROOT);
-  }
-  if (process.platform === 'darwin') {
-    return path.join(root, 'target/liboliphaunt-pg18');
-  }
-  return path.join(root, `target/liboliphaunt-pg18-${target}`);
-}
-
-function executableName(name) {
-  return process.platform === 'win32' ? `${name}.exe` : name;
-}
-
-function artifactPaths(root) {
-  const target = hostTarget();
-  const workRoot = defaultWorkRoot(root, target);
-  const installDir = path.resolve(process.env.OLIPHAUNT_INSTALL_DIR ?? path.join(workRoot, 'install'));
-  const libPath = path.resolve(
-    process.env.LIBOLIPHAUNT_PATH ??
-      (process.platform === 'win32'
-        ? path.join(workRoot, 'out/bin/oliphaunt.dll')
-        : path.join(workRoot, `out/${process.platform === 'darwin' ? 'liboliphaunt.dylib' : 'liboliphaunt.so'}`)),
-  );
-  const outDir = process.platform === 'win32'
-    ? path.dirname(path.dirname(libPath))
-    : path.dirname(libPath);
-  const binDir = path.resolve(
-    process.env.OLIPHAUNT_SMOKE_BIN_DIR ??
-      (process.platform === 'win32' ? path.dirname(libPath) : outDir),
-  );
-  return {
-    root,
-    target,
-    workRoot,
-    outDir,
-    binDir,
-    installDir,
-    buildDir: path.join(workRoot, `postgresql-${PG_VERSION}`),
-    embeddedBuildDir: path.join(workRoot, 'meson-embedded'),
-    libPath,
-    importLib: path.join(outDir, 'lib/oliphaunt.lib'),
-    initdb: path.resolve(process.env.OLIPHAUNT_INITDB ?? path.join(installDir, 'bin', executableName('initdb'))),
-    postgres: path.resolve(process.env.OLIPHAUNT_POSTGRES ?? path.join(installDir, 'bin', executableName('postgres'))),
-  };
-}
-
-function requireFile(file, label) {
-  if (!fs.existsSync(file)) {
-    throw new Error(`missing ${label}: ${file}`);
-  }
-}
-
-function normalizeForC(value) {
-  return process.platform === 'win32' ? value.replaceAll('\\', '/') : value;
-}
-
-function splitCommand(value, fallback) {
-  return (value ?? fallback).trim().split(/\s+/).filter(Boolean);
-}
-
-function ccachePrefix() {
-  const mode = process.env.OLIPHAUNT_CCACHE ?? 'auto';
-  if (mode === '0' || mode === 'off' || process.platform === 'win32') {
-    return [];
-  }
-  if (mode !== 'auto') {
-    return [mode];
-  }
-  return commandExists('ccache') ? ['ccache'] : [];
-}
-
-function compileUnix(paths, kind, source, output, extraArgs) {
-  const envName = kind === 'abi' ? 'OLIPHAUNT_ABI_CC' : 'OLIPHAUNT_SMOKE_CC';
-  const compiler = splitCommand(process.env[envName], 'cc');
-  const command = [...ccachePrefix(), ...compiler];
-  const exe = command[0];
-  const args = [
-    ...command.slice(1),
-    '-std=c11',
-    '-Wall',
-    '-Wextra',
-    '-Werror',
-    '-O0',
-    '-g',
-    '-I',
-    path.join(paths.root, 'src/runtimes/liboliphaunt/native/include'),
-    ...extraArgs,
-    source,
-    '-L',
-    path.dirname(paths.libPath),
-    `-Wl,-rpath,${path.dirname(paths.libPath)}`,
-    '-pthread',
-    '-loliphaunt',
-    '-o',
-    output,
-  ];
-  run(exe, args, { cwd: paths.root });
-}
-
-function msvcEnvironment() {
-  if (commandExists('cl.exe')) {
-    return process.env;
-  }
-  const programFilesX86 = process.env['ProgramFiles(x86)'];
-  if (!programFilesX86) {
-    throw new Error('ProgramFiles(x86) is not set; cannot locate Visual Studio Build Tools');
-  }
-  const vswhere = path.join(programFilesX86, 'Microsoft Visual Studio/Installer/vswhere.exe');
-  requireFile(vswhere, 'vswhere.exe');
-  const vsRoot = run(
-    vswhere,
-    [
-      '-latest',
-      '-products',
-      '*',
-      '-requires',
-      'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
-      '-property',
-      'installationPath',
-    ],
-    { capture: true },
-  ).trim();
-  if (!vsRoot) {
-    throw new Error('Visual Studio Build Tools with MSVC x64 tools were not found');
-  }
-  const vsDevCmd = path.join(vsRoot, 'Common7/Tools/VsDevCmd.bat');
-  requireFile(vsDevCmd, 'VsDevCmd.bat');
-  const envOutput = run(
-    'cmd.exe',
-    ['/d', '/s', '/c', `call "${vsDevCmd}" -arch=x64 -host_arch=x64 >nul && set`],
-    { capture: true, windowsVerbatimArguments: true },
-  );
-  const env = { ...process.env };
-  for (const line of envOutput.split(/\r?\n/)) {
-    const match = /^(.*?)=(.*)$/.exec(line);
-    if (match) {
-      env[match[1]] = match[2];
-    }
-  }
-  return env;
-}
-
-function compileWindows(paths, source, output, extraIncludes) {
-  requireFile(paths.importLib, 'Windows import library');
-  const env = msvcEnvironment();
-  fs.mkdirSync(path.dirname(output), { recursive: true });
-  run(
-    'cl.exe',
-    [
-      '/nologo',
-      '/std:c11',
-      '/Zi',
-      '/MD',
-      '/D_CRT_SECURE_NO_WARNINGS',
-      '/DWIN32_LEAN_AND_MEAN',
-      `/I${path.join(paths.root, 'src/runtimes/liboliphaunt/native/include')}`,
-      ...extraIncludes.map((include) => `/I${include}`),
-      source,
-      '/link',
-      `/LIBPATH:${path.dirname(paths.importLib)}`,
-      'oliphaunt.lib',
-      `/OUT:${output}`,
-    ],
-    { cwd: paths.root, env },
-  );
-}
-
-function compileAbi(paths) {
-  requireFile(paths.libPath, 'liboliphaunt library');
-  const source = path.join(paths.root, 'src/runtimes/liboliphaunt/native/smoke/liboliphaunt_abi_conformance.c');
-  const output = path.join(paths.binDir, executableName('liboliphaunt_abi_conformance'));
-  fs.mkdirSync(path.dirname(output), { recursive: true });
-  if (process.platform === 'win32') {
-    compileWindows(paths, source, output, []);
-  } else {
-    compileUnix(paths, 'abi', source, output, ['-pedantic']);
-  }
-  run(output, [], { env: smokeEnv(paths) });
-}
-
-function smokeIncludes(paths) {
-  const includes = [
-    path.join(paths.root, 'src/runtimes/liboliphaunt/native/src'),
-    path.join(paths.buildDir, 'src/include'),
-    path.join(paths.embeddedBuildDir, 'src/include'),
-    path.join(paths.installDir, 'include'),
-  ];
-  if (process.platform === 'win32') {
-    includes.push(path.join(paths.buildDir, 'src/include/port/win32'));
-  }
-  return includes;
-}
-
-function compileSmoke(paths) {
-  requireFile(paths.libPath, 'liboliphaunt library');
-  requireExecutable(paths.initdb, 'initdb');
-  requireExecutable(paths.postgres, 'postgres');
-  const source = path.join(paths.root, 'src/runtimes/liboliphaunt/native/smoke/liboliphaunt_smoke.c');
-  const output = path.join(paths.binDir, executableName('liboliphaunt_smoke'));
-  fs.mkdirSync(path.dirname(output), { recursive: true });
-  if (process.platform === 'win32') {
-    compileWindows(paths, source, output, smokeIncludes(paths));
-  } else {
-    const includeArgs = smokeIncludes(paths).flatMap((include) => ['-I', include]);
-    compileUnix(paths, 'smoke', source, output, includeArgs);
-  }
-  return output;
-}
-
-function compileClusterSeedSmoke(paths) {
-  const source = path.join(paths.root, 'src/runtimes/liboliphaunt/native/smoke/liboliphaunt_cluster_seed_smoke.c');
-  const output = path.join(paths.binDir, executableName('liboliphaunt_cluster_seed_smoke'));
-  fs.mkdirSync(path.dirname(output), { recursive: true });
-  if (process.platform === 'win32') {
-    compileWindows(paths, source, output, []);
-  } else {
-    compileUnix(paths, 'smoke', source, output, []);
-  }
-  return output;
-}
-
-function smokeEnv(paths) {
-  const sharedPathEnv = process.platform === 'win32'
-    ? { PATH: [path.dirname(paths.libPath), path.join(paths.installDir, 'bin'), process.env.PATH ?? ''].join(path.delimiter) }
-    : process.platform === 'darwin'
-      ? { DYLD_LIBRARY_PATH: [path.dirname(paths.libPath), path.join(paths.installDir, 'lib'), process.env.DYLD_LIBRARY_PATH ?? ''].join(path.delimiter) }
-      : { LD_LIBRARY_PATH: [path.dirname(paths.libPath), path.join(paths.installDir, 'lib'), process.env.LD_LIBRARY_PATH ?? ''].join(path.delimiter) };
-  return {
-    ...process.env,
-    ...sharedPathEnv,
-    LIBOLIPHAUNT_PATH: paths.libPath,
-    OLIPHAUNT_POSTGRES: paths.postgres,
-    OLIPHAUNT_INSTALL_DIR: paths.installDir,
-    OLIPHAUNT_STREAM_QUEUE_MAX_BYTES: process.env.OLIPHAUNT_STREAM_QUEUE_MAX_BYTES ?? '4096',
-  };
-}
-
-function prepareSmokeManagedRoot(paths, root, pgdata, env) {
-  const descriptor = path.join(root, '.oliphaunt.json');
-  if (fs.existsSync(descriptor)) {
-    return;
-  }
-  if (fs.readdirSync(root).length !== 0) {
-    throw new Error(`native smoke root is nonempty but unmanaged: ${root}`);
-  }
-  const initdbEnv = {
-    ...env,
-    OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY: '1',
-    OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY: '1',
-  };
-  run(paths.initdb, [
-    '-D',
-    pgdata,
-    '-U',
-    'postgres',
-    '--auth=trust',
-    '--no-sync',
-    '--locale-provider=libc',
-    '--locale=C',
-    '--encoding=UTF8',
-  ], { env: initdbEnv });
-  publishSmokeManagedRootDescriptor(root);
-}
-
-function publishSmokeManagedRootDescriptor(root) {
-  const descriptor = path.join(root, '.oliphaunt.json');
-  const staging = `${descriptor}.tmp`;
-  fs.writeFileSync(
-    staging,
-    '{"schema":"oliphaunt-database-root-v1","engineFamily":"native","pgdata":"pgdata","postgresMajor":18,"physicalFormat":"native-pg18-v1"}\n',
-    { encoding: 'utf8', flag: 'wx', mode: 0o600 },
-  );
-  fs.renameSync(staging, descriptor);
-}
-
-function runSmoke(paths, smokeBin, rootArg) {
-  const smokeRoot = process.env.OLIPHAUNT_SMOKE_ROOT
-    ? path.resolve(process.env.OLIPHAUNT_SMOKE_ROOT)
-    : paths.workRoot;
-  if (!rootArg) {
-    fs.mkdirSync(smokeRoot, { recursive: true });
-  }
-  const root = rootArg
-    ? path.resolve(rootArg)
-    : fs.mkdtempSync(path.join(smokeRoot, 'smoke.'));
-  const keepRoot = Boolean(rootArg);
-  const pgdata = path.join(root, 'pgdata');
-  const archiveManifestFixture = path.join(
-    paths.root,
-    'src/shared/fixtures/storage/physical-archive-native-v1.properties',
-  );
-  requireFile(archiveManifestFixture, 'shared native archive manifest fixture');
-  const args = [
-    normalizeForC(pgdata),
-    normalizeForC(paths.installDir),
-    normalizeForC(archiveManifestFixture),
-  ];
-  const env = smokeEnv(paths);
-  try {
-    prepareSmokeManagedRoot(paths, root, pgdata, env);
-    run(smokeBin, args, { env });
-    run(smokeBin, args, { env });
-    if (!keepRoot) {
-      fs.rmSync(root, { recursive: true, force: true });
-    }
-  } catch (error) {
-    console.error(`native smoke root: ${root}`);
-    throw error;
-  }
-}
-
-function runClusterSeedSmoke(paths, smokeBin) {
-  const standardSeed = process.env.OLIPHAUNT_STANDARD_CLUSTER_SEED;
-  const icuSeed = process.env.OLIPHAUNT_ICU_CLUSTER_SEED;
-  const icuData = process.env.OLIPHAUNT_ICU_DATA_DIR;
-  if (!standardSeed || !icuSeed || !icuData) {
-    throw new Error('cluster-seed qualification requires OLIPHAUNT_STANDARD_CLUSTER_SEED, OLIPHAUNT_ICU_CLUSTER_SEED, and OLIPHAUNT_ICU_DATA_DIR');
-  }
-  const fixturePath = path.join(paths.root, 'src/shared/cluster-seed-contract/profile-probe.json');
-  const fixture = JSON.parse(fs.readFileSync(fixturePath, 'utf8'));
-  if (fixture.schema !== 'oliphaunt-cluster-seed-profile-probe-v1') {
-    throw new Error(`unsupported cluster-seed profile probe: ${fixturePath}`);
-  }
-  const scratchRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-cluster-seed-smoke.'));
-  const runtimeIcuData = path.join(paths.installDir, 'share/icu');
-  const removeRuntimeIcuData = !fs.existsSync(runtimeIcuData);
-  try {
-    if (removeRuntimeIcuData) {
-      fs.mkdirSync(path.dirname(runtimeIcuData), { recursive: true });
-      fs.cpSync(icuData, runtimeIcuData, { recursive: true, errorOnExist: true });
-    }
-    for (const [profile, seed] of [['standard', standardSeed], ['icu', icuSeed]]) {
-      const root = path.join(scratchRoot, profile);
-      const pgdata = path.join(root, 'pgdata');
-      fs.cpSync(path.join(seed, 'files'), pgdata, { recursive: true, errorOnExist: true });
-      fs.chmodSync(pgdata, 0o700);
-      publishSmokeManagedRootDescriptor(root);
-      const probe = fixture.profiles?.[profile];
-      if (typeof probe?.sql !== 'string' || typeof probe?.expected !== 'string') {
-        throw new Error(`cluster-seed fixture is missing ${profile}`);
-      }
-      const env = smokeEnv(paths);
-      delete env.OLIPHAUNT_ICU_DATA_DIR;
-      env.ICU_DATA = '/ambient/unverified-icu';
-      const args = [normalizeForC(pgdata), normalizeForC(paths.installDir), probe.sql, probe.expected];
-      run(smokeBin, args, { env });
-      run(smokeBin, args, { env });
-    }
-
-    const importRoot = path.join(scratchRoot, 'standard-icu-import');
-    const importPgdata = path.join(importRoot, 'pgdata');
-    fs.cpSync(path.join(standardSeed, 'files'), importPgdata, { recursive: true, errorOnExist: true });
-    fs.chmodSync(importPgdata, 0o700);
-    publishSmokeManagedRootDescriptor(importRoot);
-    const importSql = [
-      "SELECT pg_import_system_collations('pg_catalog')",
-      "SELECT CASE WHEN EXISTS (SELECT 1 FROM pg_collation WHERE collname LIKE '%-x-icu') THEN 'OLIPHAUNT_ICU_IMPORT_OK' ELSE 'OLIPHAUNT_ICU_IMPORT_MISSING' END",
-    ].join('; ');
-    const importEnv = smokeEnv(paths);
-    importEnv.ICU_DATA = '/ambient/unverified-icu';
-    importEnv.OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY = '1';
-    const importArgs = [
-      normalizeForC(importPgdata),
-      normalizeForC(paths.installDir),
-      importSql,
-      'OLIPHAUNT_ICU_IMPORT_OK',
-    ];
-    run(smokeBin, importArgs, { env: importEnv });
-    run(smokeBin, importArgs, { env: importEnv });
-  } finally {
-    if (removeRuntimeIcuData) {
-      fs.rmSync(runtimeIcuData, { recursive: true, force: true });
-    }
-    fs.rmSync(scratchRoot, { recursive: true, force: true });
-  }
-  console.error('native standard and ICU cluster seeds passed open, catalog, close, and reopen qualification');
-}
-
-function checkIosCSourceSyntax(paths) {
-  if (process.platform !== 'darwin') {
-    return;
-  }
-  const sdkPath = childProcess.spawnSync('xcrun', ['--sdk', 'iphonesimulator', '--show-sdk-path'], {
-    encoding: 'utf8',
-    stdio: ['ignore', 'pipe', 'ignore'],
-  }).stdout?.trim();
-  const clang = childProcess.spawnSync('xcrun', ['--sdk', 'iphonesimulator', '--find', 'clang'], {
-    encoding: 'utf8',
-    stdio: ['ignore', 'pipe', 'ignore'],
-  }).stdout?.trim();
-  if (!sdkPath || !clang) {
-    console.error('skipping iOS C source syntax check: iPhoneSimulator SDK is unavailable');
-    return;
-  }
-
-  const sources = [
-    'liboliphaunt_native.c',
-    'liboliphaunt_error.c',
-    'liboliphaunt_runtime.c',
-    'liboliphaunt_protocol.c',
-    'liboliphaunt_config.c',
-    'liboliphaunt_process.c',
-    'liboliphaunt_trace.c',
-    'liboliphaunt_fs.c',
-    'liboliphaunt_backup_state.c',
-    'liboliphaunt_archive.c',
-    'liboliphaunt_archive_tar.c',
-    'liboliphaunt_static_extensions.c',
-    'liboliphaunt_builtin_extensions.c',
-  ];
-  for (const source of sources) {
-    run(clang, [
-      '-std=c11',
-      '-Wall',
-      '-Wextra',
-      '-Werror',
-      '-Wpedantic',
-      '-Werror=unguarded-availability-new',
-      '-fsyntax-only',
-      '-target',
-      'arm64-apple-ios17.0-simulator',
-      '-mios-simulator-version-min=17.0',
-      '-isysroot',
-      sdkPath,
-      '-I',
-      path.join(paths.root, 'src/runtimes/liboliphaunt/native/include'),
-      '-I',
-      path.join(paths.root, 'src/runtimes/liboliphaunt/native/src'),
-      path.join(paths.root, 'src/runtimes/liboliphaunt/native/src', source),
-    ]);
-  }
-  console.error('iOS liboliphaunt C source syntax check passed');
-}
-
-function main() {
-  const args = parseArgs(process.argv.slice(2));
-  const root = repoRoot();
-  const paths = artifactPaths(root);
-  console.error(`liboliphaunt host target: ${paths.target}`);
-  console.error(`liboliphaunt work root: ${paths.workRoot}`);
-
-  if (!args.smokeOnly) {
-    compileAbi(paths);
-    checkIosCSourceSyntax(paths);
-  }
-  if (!args.abiOnly) {
-    const smokeBin = compileSmoke(paths);
-    runSmoke(paths, smokeBin, args.root);
-    if (args.clusterSeeds) {
-      runClusterSeedSmoke(paths, compileClusterSeedSmoke(paths));
-    }
-  }
-}
-
-try {
-  main();
-} catch (error) {
-  console.error(error instanceof Error ? error.message : String(error));
-  process.exit(1);
-}
diff --git a/src/runtimes/liboliphaunt/native/tools/smoke-packed-tools-npm.mjs b/src/runtimes/liboliphaunt/native/tools/smoke-packed-tools-npm.mjs
deleted file mode 100644
index 1a1b542c8..000000000
--- a/src/runtimes/liboliphaunt/native/tools/smoke-packed-tools-npm.mjs
+++ /dev/null
@@ -1,221 +0,0 @@
-#!/usr/bin/env node
-
-import { execFile } from 'node:child_process';
-import { copyFile, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import path from 'node:path';
-import process from 'node:process';
-import { fileURLToPath, pathToFileURL } from 'node:url';
-import { promisify } from 'node:util';
-
-const execFileAsync = promisify(execFile);
-const TOOL = 'smoke-packed-tools-npm.mjs';
-const ENGINE_FLAG = '--engine';
-
-if (process.argv.includes(ENGINE_FLAG)) {
-  await runConsumer(readEngine(process.argv.slice(2)));
-} else {
-  await runOrchestrator(readAssetDirectory(process.argv.slice(2)));
-}
-
-async function runOrchestrator(assetDir) {
-  const connectionString = requiredEnvironment('OLIPHAUNT_NATIVE_TOOLS_CONNECTION_STRING');
-  const repositoryRoot = path.resolve(
-    path.dirname(fileURLToPath(import.meta.url)),
-    '../../../../..',
-  );
-  const { currentProductVersionSync } = await import(
-    pathToFileURL(path.join(repositoryRoot, 'tools/release/release-artifact-targets.mjs')).href
-  );
-  const { liboliphauntToolsNpmTarballs } = await import(
-    pathToFileURL(path.join(repositoryRoot, 'tools/release/package-release-carriers.mjs')).href
-  );
-  const version = currentProductVersionSync('liboliphaunt-native', TOOL);
-  const packages = liboliphauntToolsNpmTarballs(version, {
-    assetDir,
-    targetIds: ['linux-x64-gnu'],
-  });
-  const packageFiles = new Map(packages);
-  const facade = requiredPackage(packageFiles, '@oliphaunt/tools');
-  const carrier = requiredPackage(packageFiles, '@oliphaunt/tools-linux-x64-gnu');
-  if (packages.length !== 2 || packageFiles.size !== 2) {
-    throw new Error(`${TOOL}: expected exactly the facade and Linux x64 carrier`);
-  }
-
-  const scratch = await mkdtemp(path.join(tmpdir(), 'oliphaunt-native-tools-npm-'));
-  try {
-    await writeFile(
-      path.join(scratch, 'package.json'),
-      `${JSON.stringify(
-        {
-          name: 'oliphaunt-native-tools-smoke-consumer',
-          version: '0.0.0',
-          private: true,
-          type: 'module',
-          dependencies: {
-            '@oliphaunt/tools': version,
-            '@oliphaunt/tools-linux-x64-gnu': version,
-          },
-        },
-        null,
-        2,
-      )}\n`,
-    );
-    await copyFile(fileURLToPath(import.meta.url), path.join(scratch, 'smoke.mjs'));
-    // The facade advertises every supported optional platform carrier. This
-    // Linux-only lane materializes the two already-validated tarballs directly
-    // so the smoke remains offline without manufacturing other-platform stubs.
-    for (const [tarball, directory] of [
-      [facade, path.join(scratch, 'node_modules/@oliphaunt/tools')],
-      [carrier, path.join(scratch, 'node_modules/@oliphaunt/tools-linux-x64-gnu')],
-    ]) {
-      await mkdir(directory, { recursive: true });
-      await run('tar', ['-xzf', tarball, '--strip-components=1', '-C', directory]);
-    }
-
-    const fixtureRoot = path.join(repositoryRoot, 'src/shared/fixtures/postgres');
-    const environment = {
-      ...process.env,
-      OLIPHAUNT_NATIVE_TOOLS_CONNECTION_STRING: connectionString,
-      OLIPHAUNT_LOGICAL_TOOLS_CONTRACT: path.join(fixtureRoot, 'logical-tools.json'),
-      OLIPHAUNT_LOGICAL_TOOLS_SEED: path.join(fixtureRoot, 'logical-tools-seed.sql'),
-      OLIPHAUNT_LOGICAL_TOOLS_VERIFY: path.join(fixtureRoot, 'logical-tools-verify.sql'),
-    };
-    const smoke = path.join(scratch, 'smoke.mjs');
-    for (const [engine, command, args] of [
-      ['node', 'node', [smoke, ENGINE_FLAG, 'node']],
-      ['bun', path.join(repositoryRoot, 'tools/dev/bun.sh'), [smoke, ENGINE_FLAG, 'bun']],
-      [
-        'deno',
-        path.join(repositoryRoot, 'tools/dev/deno.sh'),
-        ['run', '--allow-all', smoke, ENGINE_FLAG, 'deno'],
-      ],
-    ]) {
-      await run(command, args, { cwd: scratch, env: environment });
-      console.log(`${TOOL}: ${engine} packed tools smoke passed`);
-    }
-  } finally {
-    await rm(scratch, { force: true, recursive: true });
-  }
-}
-
-async function runConsumer(engine) {
-  const connectionString = requiredEnvironment('OLIPHAUNT_NATIVE_TOOLS_CONNECTION_STRING');
-  const contract = JSON.parse(
-    await readFile(requiredEnvironment('OLIPHAUNT_LOGICAL_TOOLS_CONTRACT'), 'utf8'),
-  );
-  const seed = await readFile(requiredEnvironment('OLIPHAUNT_LOGICAL_TOOLS_SEED'), 'utf8');
-  const verify = await readFile(requiredEnvironment('OLIPHAUNT_LOGICAL_TOOLS_VERIFY'), 'utf8');
-  const { pgDump, psql } = await import('@oliphaunt/tools');
-  const suffix = `${engine}_${process.pid}`.replaceAll(/[^a-z0-9_]/gu, '_');
-  const sourceDatabase = `oliphaunt_tools_${suffix}_source`;
-  const restoredDatabase = `oliphaunt_tools_${suffix}_restored`;
-  const sourceConnection = databaseConnectionString(connectionString, sourceDatabase);
-  const restoredConnection = databaseConnectionString(connectionString, restoredDatabase);
-  try {
-    await psql(connectionString, { command: `CREATE DATABASE ${quoteIdentifier(sourceDatabase)}` });
-    await psql(connectionString, {
-      command: `CREATE DATABASE ${quoteIdentifier(restoredDatabase)}`,
-    });
-    await psql(sourceConnection, { script: seed });
-    const dump = await pgDump(sourceConnection);
-    if (
-      !dump.includes('COPY public.logical_items') ||
-      dump.includes('INSERT INTO public.logical_items')
-    ) {
-      throw new Error(`${engine}: pg_dump did not preserve PostgreSQL's ordinary COPY output`);
-    }
-    await psql(restoredConnection, { script: dump });
-    const actual = (await psql(restoredConnection, { args: ['-tA'], script: verify })).trim();
-    const expected = expectedLogicalToolsRow(contract);
-    if (actual !== expected) {
-      throw new Error(
-        `${engine}: logical tools round trip returned ${JSON.stringify(actual)}, ` +
-          `expected ${JSON.stringify(expected)}`,
-      );
-    }
-    console.log(`OLIPHAUNT_NATIVE_TOOLS_NPM_SMOKE_PASS engine=${engine}`);
-  } finally {
-    for (const database of [restoredDatabase, sourceDatabase]) {
-      try {
-        await psql(connectionString, {
-          command: `DROP DATABASE IF EXISTS ${quoteIdentifier(database)} WITH (FORCE)`,
-        });
-      } catch (error) {
-        console.error(`${TOOL}: failed to drop ${database}: ${error?.stack ?? error}`);
-      }
-    }
-  }
-}
-
-function readAssetDirectory(arguments_) {
-  if (arguments_.length !== 2 || arguments_[0] !== '--asset-dir') {
-    throw new Error(`usage: ${TOOL} --asset-dir DIRECTORY`);
-  }
-  return path.resolve(arguments_[1]);
-}
-
-function readEngine(arguments_) {
-  if (arguments_.length !== 2 || arguments_[0] !== ENGINE_FLAG) {
-    throw new Error(`usage: ${TOOL} ${ENGINE_FLAG} node|bun|deno`);
-  }
-  if (!new Set(['node', 'bun', 'deno']).has(arguments_[1])) {
-    throw new Error(`${TOOL}: unsupported engine ${JSON.stringify(arguments_[1])}`);
-  }
-  return arguments_[1];
-}
-
-function requiredPackage(packages, name) {
-  const file = packages.get(name);
-  if (typeof file !== 'string' || file.length === 0) {
-    throw new Error(`${TOOL}: packed package ${name} is missing`);
-  }
-  return file;
-}
-
-function requiredEnvironment(name) {
-  const value = process.env[name];
-  if (typeof value !== 'string' || value.length === 0) {
-    throw new Error(`${TOOL}: ${name} is required`);
-  }
-  return value;
-}
-
-function databaseConnectionString(connectionString, database) {
-  const url = new URL(connectionString);
-  url.pathname = `/${database}`;
-  return url.href;
-}
-
-function quoteIdentifier(identifier) {
-  return `"${identifier.replaceAll('"', '""')}"`;
-}
-
-function expectedLogicalToolsRow(contract) {
-  const expected = contract.expected;
-  return [
-    expected.rows,
-    expected.sum,
-    expected.sequenceLastValue,
-    expected.quotedValue,
-    expected.normalizedMatches,
-    expected.extensionLoaded ? 't' : 'f',
-  ].join('|');
-}
-
-async function run(command, args, { cwd, env = process.env } = {}) {
-  try {
-    const result = await execFileAsync(command, args, {
-      cwd,
-      env,
-      maxBuffer: 64 * 1024 * 1024,
-      timeout: 300_000,
-    });
-    if (result.stdout) process.stdout.write(result.stdout);
-    if (result.stderr) process.stderr.write(result.stderr);
-  } catch (error) {
-    if (error?.stdout) process.stdout.write(error.stdout);
-    if (error?.stderr) process.stderr.write(error.stderr);
-    throw error;
-  }
-}
diff --git a/src/runtimes/liboliphaunt/native/tools/test-module-dir-resolver.sh b/src/runtimes/liboliphaunt/native/tools/test-module-dir-resolver.sh
deleted file mode 100644
index 6ef11ba05..000000000
--- a/src/runtimes/liboliphaunt/native/tools/test-module-dir-resolver.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-root=$(git rev-parse --show-toplevel)
-case "$(uname -s)" in
-  MINGW*|MSYS*|CYGWIN*)
-    echo "liboliphaunt module-dir resolver test is covered by the Linux/macOS C lanes"
-    exit 0
-    ;;
-esac
-
-scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-module-dir-test.XXXXXX")
-trap 'rm -rf "$scratch"' EXIT
-
-compiler=${CC:-cc}
-linker_arg=
-if [[ "$(uname -s)" == Linux ]]; then
-  linker_arg=-ldl
-fi
-
-"$compiler" \
-  -std=c11 \
-  -Wall \
-  -Wextra \
-  -Werror \
-  -I "$root/src/runtimes/liboliphaunt/native/include" \
-  -I "$root/src/runtimes/liboliphaunt/native/src" \
-  "$root/src/runtimes/liboliphaunt/native/smoke/liboliphaunt_module_dir_resolver.c" \
-  "$root/src/runtimes/liboliphaunt/native/src/liboliphaunt_fs.c" \
-  ${linker_arg:+"$linker_arg"} \
-  -o "$scratch/liboliphaunt_module_dir_resolver"
-
-mkdir "$scratch/fixture"
-"$scratch/liboliphaunt_module_dir_resolver" "$scratch/fixture"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/.gitignore b/src/runtimes/liboliphaunt/wasix-postmaster/.gitignore
deleted file mode 100644
index b8aead570..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/.gitignore
+++ /dev/null
@@ -1,16 +0,0 @@
-/build/
-/builds/
-/install/
-/reports/
-/run/
-/sources/
-/tools/*
-!/tools/sealed-export-closure/
-/tools/sealed-export-closure/target/
-/work/
-*.a
-*.dylib
-*.log
-*.o
-*.so
-*.wasm
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/CHANGELOG.md b/src/runtimes/liboliphaunt/wasix-postmaster/CHANGELOG.md
deleted file mode 100644
index 74e8b8444..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/CHANGELOG.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Changelog
-
-## 0.1.0 (2026-09-05)
-
-
-### ⚠ BREAKING CHANGES
-
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
-
-### Features
-
-* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
-
-
-### Code Refactoring
-
-* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
-* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/README.md b/src/runtimes/liboliphaunt/wasix-postmaster/README.md
deleted file mode 100644
index 2b8d8eef9..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/README.md
+++ /dev/null
@@ -1,127 +0,0 @@
-# liboliphaunt WASIX Postmaster
-
-`liboliphaunt-wasix-postmaster` is the concurrent PostgreSQL 18 runtime for
-WASIX. One PostgreSQL postmaster accepts connections and starts isolated WASIX
-backend processes that coordinate through PostgreSQL shared memory.
-
-This is a release product. Its release identity, version, source pins, build,
-sealed carrier, verification, and qualification tasks are owned by this
-directory. The existing `liboliphaunt-wasix` runtime remains the lightweight
-single-backend product; applications select the topology that fits their
-workload without changing PostgreSQL protocol semantics.
-
-## Release targets
-
-Release carriers are published as level-19 Zstandard `.tar.zst` archives for
-`linux-arm64-gnu`, `linux-x64-gnu`, and `macos-arm64`, matching the normal
-WASIX carrier format. Each published carrier contains:
-
-- the compiler-free postmaster executor;
-- `initdb`, `postgres`, and every side module declared by
-  `runtime/policies/sealed-side-modules.v1.tsv`;
-- receipt-bound AOT artifacts for every admitted executable module;
-- PostgreSQL support files, build receipts, a complete payload inventory, and
-  the sealed manifest.
-
-Each carrier is fail-closed: the verifier rejects missing, unexpected, renamed,
-symlinked, special, or modified payloads, an incompatible runtime ABI, a
-mismatched producer recipe, and undeclared modules. Platform support is a
-release target claim, not an inference from Wasmer portability. Additional
-targets are added only with an artifact target, CI builder, and consumer smoke.
-
-## Run the release carrier
-
-Download and extract the release archive matching the host, then start a local
-cluster through its supported launcher:
-
-```sh
-./bin/oliphaunt-wasix-postmaster start --data-dir "$PWD/pgdata"
-```
-
-The launcher initializes an empty directory with the `postgres` superuser,
-prints `postgresql://postgres@127.0.0.1:5432/postgres`, and keeps PostgreSQL in
-the foreground. It binds only to loopback unless `--allow-remote` is explicit.
-Use `--port`, repeated `--guc name=value`, and `--username` to configure the
-cluster without depending on the repository's build scripts. Send SIGTERM for
-a clean shutdown. The archive is self-contained; it does not compile or fetch
-code when it starts.
-
-## Build and verify
-
-Run the focused source and product checks:
-
-```sh
-moon run liboliphaunt-wasix-postmaster:lint
-```
-
-Build the pinned runtime and PostgreSQL guest, then construct the sealed
-carrier:
-
-```sh
-moon run liboliphaunt-wasix-postmaster:runtime-build
-moon run liboliphaunt-wasix-postmaster:postgres-build
-moon run liboliphaunt-wasix-postmaster:carrier
-```
-
-Verify an existing carrier independently:
-
-```sh
-src/runtimes/liboliphaunt/wasix-postmaster/bin/verify-sealed-headless-carrier.sh \
-  target/oliphaunt-wasix-postmaster/carriers/
-```
-
-Build outputs, fetched sources, caches, and qualification results stay under
-`target/oliphaunt-wasix-postmaster/`. Nothing generated is admitted as a
-release asset unless it was built from the exact release commit and passes the
-product verifier and lifecycle qualification.
-
-Linux release qualification additionally requires immutable-inode activation
-and cgroup-v2 memory controls. macOS uses runtime-owned private AOT and memory
-image copies because Linux immutable-inode and cgroup primitives do not exist
-there; qualification proves the copy/hash byte accounting, forbids carrier
-source writes and sync calls, and runs the same backend-wave and crash-recovery
-campaign.
-
-## Architecture boundary
-
-The launcher's `--data-dir` is a raw PostgreSQL PGDATA directory. It is not an
-Oliphaunt SDK managed root and does not participate in the single-backend
-WASIX root or physical-backup contracts.
-
-PostgreSQL is built with `EXEC_BACKEND`. The postmaster uses the WASIX process
-and exec syscalls to create a fresh Wasmer instance for each backend. The child
-restores PostgreSQL's serialized backend parameters and reattaches the
-postmaster's shared-memory segment at the original guest address.
-
-```text
-native supervisor and compiler-free WASIX executor
-  PostgreSQL postmaster.wasm
-    TCP listener + PostgreSQL shared memory
-      |
-      +-- vfork + execv --> isolated backend.wasm instance
-      +-- vfork + execv --> isolated backend.wasm instance
-```
-
-The postmaster guest deliberately does not consume the single-backend patches
-that remove concurrent observers, workers, process creation, or PostgreSQL's
-normal spinlock/atomic behavior. Compatible PostgreSQL optimizations are
-referenced from the canonical WASIX product where possible; postmaster-only
-concurrency patches remain local and are justified in
-`postgres/product-patch-provenance.toml`.
-
-Maintainer architecture, failure semantics, performance interpretation, and
-the durable conclusions from product development are documented in
-`docs/maintainers/wasix-postmaster.md`. Product source contains only build,
-runtime, packaging, verification, and qualification machinery.
-
-## Release contract
-
-- Product id and tag prefix: `liboliphaunt-wasix-postmaster` and
-  `liboliphaunt-wasix-postmaster-v`.
-- The source version remains `0.0.0` until the first generated release PR.
-- `release.toml`, Moon release metadata, Release Please, and the release asset
-  task describe the same product.
-- A release is valid only when the exact release commit produced and verified
-  the carrier later attached to its GitHub release.
-- The checksum manifest uses the same canonical release-asset contract as the
-  single-backend WASIX product and covers every published carrier exactly.
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-sealed-headless-carrier.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-sealed-headless-carrier.sh
deleted file mode 100755
index 203acaa19..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-sealed-headless-carrier.sh
+++ /dev/null
@@ -1,1025 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-wasix_core_profile_explicit=0
-if [ "${WASIX_CORE_PROFILE+x}" = x ] && [ -n "$WASIX_CORE_PROFILE" ]; then
-  wasix_core_profile_explicit=1
-fi
-source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/common.sh"
-source "$FRESH_ROOT/lib/sealed-carrier.sh"
-
-usage() {
-  cat <<'EOF'
-Usage: build-sealed-headless-carrier.sh [options]
-
-Build an atomic, compiler-free WASIX PostgreSQL carrier from an already
-validated runtime receipt and precompiled AOT cache.
-
-Options:
-  --output DIR              Final carrier directory (must not already exist).
-                            By default, publish below the work-root carriers
-                            directory under the exact payload-inventory digest.
-  --install-dir DIR         WASIX PostgreSQL prefix (default: WASIX_INSTALL_DIR)
-  --postmaster-compiler FILE
-                            Receipt-bound bounded-memory LLVM producer
-  --postmaster-executor FILE
-                            Product-specific sealed-postmaster executor
-  --postmaster-executor-receipt FILE
-                            Exact product executor build receipt
-  --cache-bucket DIR        Exact precompiled AOT bucket
-  --receipt FILE            Canonical Wasmer build receipt
-  -h, --help                Show this help
-
-The builder never compiles implicitly and never accepts host-native CPU AOT.
-EOF
-}
-
-fail() {
-  printf 'sealed carrier build: %s\n' "$*" >&2
-  exit 2
-}
-
-output=""
-install_dir="$WASIX_INSTALL_DIR"
-postmaster_compiler="$FRESH_POSTMASTER_COMPILER_BIN"
-postmaster_executor="$FRESH_POSTMASTER_EXECUTOR_BIN"
-postmaster_executor_receipt="$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
-receipt="${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}"
-cache_bucket=""
-
-while [ "$#" -gt 0 ]; do
-  case "$1" in
-    --output|--install-dir|--postmaster-compiler|--postmaster-executor|--postmaster-executor-receipt|--cache-bucket|--receipt)
-      option="$1"
-      shift
-      [ "$#" -gt 0 ] || fail "$option requires a value"
-      case "$option" in
-        --output) output="$1" ;;
-        --install-dir) install_dir="$1" ;;
-        --postmaster-compiler) postmaster_compiler="$1" ;;
-        --postmaster-executor) postmaster_executor="$1" ;;
-        --postmaster-executor-receipt) postmaster_executor_receipt="$1" ;;
-        --cache-bucket) cache_bucket="$1" ;;
-        --receipt) receipt="$1" ;;
-      esac
-      ;;
-    -h|--help)
-      usage
-      exit 0
-      ;;
-    *)
-      fail "unknown argument: $1"
-      ;;
-  esac
-  shift
-done
-
-selected_executor="$postmaster_executor"
-
-fresh_require_command python3
-fresh_require_command cp
-fresh_require_command find
-fresh_require_command flock
-fresh_require_command sort
-
-[ "$wasix_core_profile_explicit" -eq 1 ] || {
-  fail 'WASIX_CORE_PROFILE must be explicit for a sealed qualification carrier'
-}
-core_profile="$(fresh_normalize_wasix_core_profile "$WASIX_CORE_PROFILE")" || exit
-case "$core_profile" in
-  release-o3) ;;
-  *)
-    fail "sealed qualification carriers require a release-o3 guest with a qualified final fence inventory, got: $core_profile"
-    ;;
-esac
-
-fresh_require_patched_postmaster_compiler \
-  "$postmaster_compiler" \
-  "$postmaster_executor_receipt" \
-  "$receipt" \
-  "$postmaster_executor"
-fresh_require_patched_postmaster_executor \
-  "$selected_executor" "$postmaster_executor_receipt" "$receipt"
-
-runtime_abi_id="$(fresh_manifest_value "$receipt" runtime_abi_id)"
-output_is_explicit=1
-if [ -n "$output" ]; then
-  case "$output" in
-    */.|*/..|.|..|/) fail "unsafe output directory: $output" ;;
-  esac
-  output_parent_input="$(dirname "$output")"
-  output_name="$(basename "$output")"
-  [ -n "$output_name" ] || fail "output directory has no basename: $output"
-  case "$output_name" in
-    *$'\n'*|*$'\r'*|*$'\t'*) fail "output directory basename contains a control delimiter" ;;
-  esac
-else
-  # The complete payload identity is unavailable until manifest.json and the
-  # exact inventory have been generated.  Keep unpublished construction in a
-  # generic, private staging name and resolve the public path immediately
-  # before the atomic rename.  This prevents two PostgreSQL build profiles
-  # with the same runtime ABI from colliding at the old default path.
-  output_is_explicit=0
-  output_parent_input="$FRESH_WORK_ROOT/carriers"
-  output_name="wasix-postmaster-$POSTGRES_VERSION-${runtime_abi_id:0:16}-unpublished"
-fi
-mkdir -p "$output_parent_input"
-output_parent="$(cd "$output_parent_input" && pwd -P)"
-if [ "$output_is_explicit" -eq 1 ]; then
-  output="$output_parent/$output_name"
-  [ ! -e "$output" ] && [ ! -L "$output" ] || fail "output already exists: $output"
-fi
-
-[ -d "$install_dir" ] && [ ! -L "$install_dir" ] || fail "missing regular WASIX install prefix: $install_dir"
-install_dir="$(cd "$install_dir" && pwd -P)"
-guest_build_receipt_source="$install_dir/guest-build.receipt"
-[ -f "$guest_build_receipt_source" ] && [ ! -L "$guest_build_receipt_source" ] || {
-  fail "missing regular guest build receipt: $guest_build_receipt_source"
-}
-python3 - "$guest_build_receipt_source" "$core_profile" "$POSTGRES_TAG" \
-  "$POSTGRES_VERSION" "$WASIXCC_SYSROOT_VARIANT" <<'PY'
-import re
-import sys
-
-path, expected_profile, postgres_tag, postgres_version, sysroot_variant = sys.argv[1:]
-keys = (
-    "schema",
-    "core_profile",
-    "guest_source_signature_sha256",
-    "docker_image_id",
-    "installed_closure_sha256",
-    "child_backend",
-    "effective_cflags",
-    "effective_ldflags",
-    "effective_wasm_opt",
-    "effective_wasm_opt_flags",
-    "effective_wasm_opt_suppress_default",
-    "atomic_fence_total",
-    "atomic_fence_set_latch",
-    "atomic_fence_reset_latch",
-    "atomic_fence_wait_event_set_wait",
-    "latch_state_contract",
-    "final_wasm_concurrency_receipt_sha256",
-    "linear_memory_profile_id",
-    "linear_memory_install_receipt_sha256",
-    "postgres_tag",
-    "postgres_version",
-    "sysroot_variant",
-)
-with open(path, encoding="utf-8", newline="") as stream:
-    text = stream.read()
-if not text.endswith("\n") or "\r" in text:
-    raise SystemExit("guest build receipt is not canonical newline text")
-lines = text.splitlines()
-if len(lines) != len(keys):
-    raise SystemExit("guest build receipt field count differs")
-values = {}
-for expected, line in zip(keys, lines, strict=True):
-    if "=" not in line:
-        raise SystemExit(f"guest build receipt field has no separator: {expected}")
-    key, value = line.split("=", 1)
-    if key != expected or not value:
-        raise SystemExit(f"guest build receipt field differs: {expected}")
-    values[key] = value
-if values["schema"] != "oliphaunt.wasix-postmaster.guest-build.v5":
-    raise SystemExit("guest build receipt schema differs")
-if values["core_profile"] != expected_profile:
-    raise SystemExit("guest build receipt profile differs from explicit carrier profile")
-if re.fullmatch(r"[0-9a-f]{64}", values["guest_source_signature_sha256"]) is None:
-    raise SystemExit("guest build source signature is not a SHA-256")
-if re.fullmatch(r"sha256:[0-9a-f]{64}", values["docker_image_id"]) is None:
-    raise SystemExit("guest build Docker image ID is not immutable")
-if re.fullmatch(r"[0-9a-f]{64}", values["installed_closure_sha256"]) is None:
-    raise SystemExit("guest build installed closure identity is not a SHA-256")
-if values["child_backend"] != "exec":
-    raise SystemExit("sealed postmaster carrier requires the exec child backend")
-if values["effective_wasm_opt"] not in {"yes", "no"}:
-    raise SystemExit("guest build receipt wasm-opt mode differs")
-if values["effective_wasm_opt_suppress_default"] != "yes":
-    raise SystemExit("guest build receipt must suppress implicit wasm-opt defaults")
-expected_fences = {
-    "atomic_fence_set_latch": "2",
-    "atomic_fence_reset_latch": "1",
-    "atomic_fence_wait_event_set_wait": "1",
-}
-for key, expected in expected_fences.items():
-    if values[key] != expected:
-        raise SystemExit(f"guest build receipt concurrency fence contract differs: {key}")
-if re.fullmatch(r"[1-9][0-9]*", values["atomic_fence_total"]) is None:
-    raise SystemExit("guest build receipt atomic fence total is not canonical")
-if values["latch_state_contract"] != "packed-atomic-v1":
-    raise SystemExit("guest build receipt latch-state contract differs")
-if re.fullmatch(
-    r"[0-9a-f]{64}", values["final_wasm_concurrency_receipt_sha256"]
-) is None:
-    raise SystemExit("guest build final Wasm concurrency receipt identity differs")
-if values["linear_memory_profile_id"] != "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1":
-    raise SystemExit("guest build linear-memory profile differs")
-if re.fullmatch(
-    r"[0-9a-f]{64}", values["linear_memory_install_receipt_sha256"]
-) is None:
-    raise SystemExit("guest build linear-memory install receipt identity differs")
-if values["postgres_tag"] != postgres_tag or values["postgres_version"] != postgres_version:
-    raise SystemExit("guest build receipt PostgreSQL version differs")
-if values["sysroot_variant"] != sysroot_variant:
-    raise SystemExit("guest build receipt sysroot variant differs")
-PY
-final_wasm_concurrency_receipt_source="$install_dir/share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt"
-[ -f "$final_wasm_concurrency_receipt_source" ] && \
-  [ ! -L "$final_wasm_concurrency_receipt_source" ] || {
-  fail "missing regular final Wasm concurrency receipt: $final_wasm_concurrency_receipt_source"
-}
-expected_final_wasm_concurrency_receipt_sha256="$(
-  fresh_manifest_value "$guest_build_receipt_source" \
-    final_wasm_concurrency_receipt_sha256
-)"
-actual_final_wasm_concurrency_receipt_sha256="$(
-  fresh_wasmer_bin_hash "$final_wasm_concurrency_receipt_source"
-)"
-[ "$actual_final_wasm_concurrency_receipt_sha256" = \
-  "$expected_final_wasm_concurrency_receipt_sha256" ] || {
-  fail 'final Wasm concurrency receipt differs from guest build receipt'
-}
-linear_memory_receipt_relative="share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
-linear_memory_receipt_source="$install_dir/$linear_memory_receipt_relative"
-[ -f "$linear_memory_receipt_source" ] && [ ! -L "$linear_memory_receipt_source" ] || {
-  fail "missing regular linear-memory install receipt: $linear_memory_receipt_source"
-}
-linear_memory_install_receipt_sha256="$(fresh_wasmer_bin_hash "$linear_memory_receipt_source")"
-fresh_is_sha256 "$linear_memory_install_receipt_sha256" ||
-  fail 'linear-memory install receipt identity is invalid'
-[ "$(fresh_manifest_value "$guest_build_receipt_source" linear_memory_profile_id)" = \
-  "$FRESH_LINEAR_MEMORY_PROFILE_ID" ] || {
-  fail 'guest build receipt linear-memory profile differs'
-}
-[ "$(fresh_manifest_value "$guest_build_receipt_source" linear_memory_install_receipt_sha256)" = \
-  "$linear_memory_install_receipt_sha256" ] || {
-  fail 'linear-memory install receipt differs from guest build receipt'
-}
-expected_atomic_fence_total="$(
-  fresh_manifest_value "$guest_build_receipt_source" atomic_fence_total
-)"
-python3 "$FRESH_ROOT/runtime/bin/verify-postmaster-concurrency-contract.py" \
-  --expected-total "$expected_atomic_fence_total" \
-  --latch-state-contract packed-atomic-v1 \
-  --verified-receipt "$final_wasm_concurrency_receipt_source" \
-  --receipt-only \
-  "$install_dir/bin/postgres" >/dev/null || {
-  fail 'final Wasm concurrency receipt contract validation failed'
-}
-guest_build_recipe_sha256="$(fresh_wasmer_bin_hash "$guest_build_receipt_source")"
-fresh_is_sha256 "$guest_build_recipe_sha256" || fail 'invalid guest build recipe identity'
-guest_installed_closure_sha256="$(
-  fresh_manifest_value "$guest_build_receipt_source" installed_closure_sha256
-)"
-fresh_is_sha256 "$guest_installed_closure_sha256" || {
-  fail 'invalid guest installed closure identity'
-}
-actual_guest_installed_closure_sha256="$(
-  python3 "$FRESH_ROOT/lib/guest_build_provenance.py" identity "$install_dir"
-)" || exit
-[ "$actual_guest_installed_closure_sha256" = \
-  "$guest_installed_closure_sha256" ] || {
-  fail 'guest install bytes differ from their build receipt'
-}
-share_source="$install_dir/share/postgresql"
-[ -d "$share_source" ] && [ ! -L "$share_source" ] || fail "missing PostgreSQL support tree: $share_source"
-
-compiler="$(fresh_wasmer_compiler)"
-llvm_opt_level=aggressive
-runtime_stack_size="${WASMER_STACK_SIZE:-33554432}"
-case "$runtime_stack_size" in
-  ''|*[!0-9]*) fail "WASMER_STACK_SIZE must be a positive integer" ;;
-esac
-[ "$runtime_stack_size" -gt 0 ] || fail "WASMER_STACK_SIZE must be greater than zero"
-compiler_config="$(fresh_wasmer_compiler_cache_bucket \
-  "$compiler" "$llvm_opt_level" "$FRESH_WASMER_ARTIFACT_ABI_VERSION")"
-[ -z "${FRESH_PINNED_WASMER_CACHE_DIR:-}" ] || {
-  fail "sealed product carriers refuse pinned or foreign AOT cache roots: $FRESH_PINNED_WASMER_CACHE_DIR"
-}
-expected_cache_bucket="$(fresh_wasmer_cache_dir "$postmaster_compiler")/compiled/$compiler_config"
-if [ -z "$cache_bucket" ]; then
-  cache_bucket="$expected_cache_bucket"
-fi
-[ -d "$cache_bucket" ] && [ ! -L "$cache_bucket" ] || fail "missing regular AOT cache bucket: $cache_bucket"
-cache_bucket="$(cd "$cache_bucket" && pwd -P)"
-[ -d "$expected_cache_bucket" ] && [ ! -L "$expected_cache_bucket" ] || {
-  fail "missing receipt-bound AOT cache bucket: $expected_cache_bucket"
-}
-expected_cache_bucket="$(cd "$expected_cache_bucket" && pwd -P)"
-[ "$cache_bucket" = "$expected_cache_bucket" ] || {
-  fail "AOT cache bucket is not bound to the selected producer: expected $expected_cache_bucket, got $cache_bucket"
-}
-
-side_module_policy="$FRESH_ROOT/runtime/policies/sealed-side-modules.v1.tsv"
-[ -f "$side_module_policy" ] && [ ! -L "$side_module_policy" ] || {
-  fail "missing regular sealed side-module policy: $side_module_policy"
-}
-
-required_modules=(
-  bin/initdb
-  bin/postgres
-)
-while IFS=$'\t' read -r relative aliases abi_policy extra; do
-  case "$relative" in
-    ""|'#'*) continue ;;
-  esac
-  [ -z "${extra:-}" ] && [ -n "${aliases:-}" ] && [ -n "${abi_policy:-}" ] || {
-    fail "invalid sealed side-module policy row: $relative"
-  }
-  case "$relative" in
-    lib/*.so|lib/*.so.*|lib/postgresql/*.so) ;;
-    *) fail "invalid sealed side-module path: $relative" ;;
-  esac
-  required_modules+=("$relative")
-done <"$side_module_policy"
-[ "${#required_modules[@]}" -gt 2 ] || fail "sealed side-module policy is empty"
-for relative in "${required_modules[@]}"; do
-  source_path="$install_dir/$relative"
-  [ -f "$source_path" ] && [ ! -L "$source_path" ] || fail "missing regular runtime-closure module: $source_path"
-done
-if find "$share_source" -type l -print -quit | grep -q .; then
-  fail "PostgreSQL support tree contains a symbolic link: $share_source"
-fi
-if find "$share_source" ! -type d ! -type f -print -quit | grep -q .; then
-  fail "PostgreSQL support tree contains a special file: $share_source"
-fi
-
-staging="$(mktemp -d "$output_parent/.${output_name}.tmp.XXXXXX")"
-validation_root=""
-chmod 0755 "$staging"
-cleanup_validation_root() {
-  if [ -n "${validation_root:-}" ] && [ -d "$validation_root" ]; then
-    chmod -R u+w "$validation_root" 2>/dev/null || true
-    rm -rf -- "$validation_root"
-  fi
-  validation_root=""
-}
-cleanup() {
-  cleanup_validation_root
-  if [ -n "${staging:-}" ] && [ -d "$staging" ]; then
-    chmod -R u+w "$staging" 2>/dev/null || true
-    rm -rf -- "$staging"
-  fi
-}
-handle_signal() {
-  local status="$1"
-  trap - EXIT HUP INT TERM
-  cleanup
-  exit "$status"
-}
-trap cleanup EXIT
-trap 'handle_signal 129' HUP
-trap 'handle_signal 130' INT
-trap 'handle_signal 143' TERM
-
-mkdir -p \
-  "$staging/bin" \
-  "$staging/lib/postgresql" \
-  "$staging/share/postgresql" \
-  "$staging/aot"
-cp -p "$selected_executor" "$staging/bin/wasmer-headless"
-chmod 0555 "$staging/bin/wasmer-headless"
-cp -pR "$share_source/." "$staging/share/postgresql/"
-
-artifact_rows="$staging/.artifact-rows.tsv"
-: >"$artifact_rows"
-
-copy_artifact() {
-  local name="$1"
-  local kind="$2"
-  local relative="$3"
-  local alias="$4"
-  local module_source="$install_dir/$relative"
-  local module_sha256
-  local module_hash
-  local artifact_source
-  local artifact_relative
-  local artifact_sha256
-  local module_size
-  local artifact_size
-
-  module_sha256="$(fresh_wasmer_bin_hash "$module_source")"
-  fresh_is_sha256 "$module_sha256" || fail "invalid module digest: $module_source"
-  module_hash="${module_sha256^^}"
-  artifact_source="$cache_bucket/$module_hash.bin"
-  [ -f "$artifact_source" ] && [ ! -L "$artifact_source" ] && [ -s "$artifact_source" ] || {
-    fail "missing regular precompiled AOT artifact for $relative: $artifact_source"
-  }
-
-  mkdir -p "$staging/$(dirname "$relative")"
-  cp -p "$module_source" "$staging/$relative"
-  artifact_relative="aot/$module_hash.bin"
-  cp -p "$artifact_source" "$staging/$artifact_relative"
-  chmod 0444 "$staging/$artifact_relative"
-  "$postmaster_compiler" verify-aot \
-    "$staging/$relative" "$staging/$artifact_relative" >/dev/null || {
-    fail "AOT artifact failed product compiler admission: $relative"
-  }
-
-  artifact_sha256="$(fresh_wasmer_bin_hash "$staging/$artifact_relative")"
-  module_size="$(wc -c <"$staging/$relative" | tr -d '[:space:]')"
-  artifact_size="$(wc -c <"$staging/$artifact_relative" | tr -d '[:space:]')"
-  [ "$module_sha256" = "$(fresh_wasmer_bin_hash "$staging/$relative")" ] || {
-    fail "module changed while copying: $module_source"
-  }
-  [ "$artifact_sha256" = "$(fresh_wasmer_bin_hash "$artifact_source")" ] || {
-    fail "AOT artifact changed while copying: $artifact_source"
-  }
-
-  printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
-    "$name" "$kind" "$artifact_relative" "$relative" "$artifact_sha256" \
-    "$artifact_size" "$module_sha256" "$module_size" "$alias" >>"$artifact_rows"
-}
-
-copy_artifact runtime:initdb executable bin/initdb /bin/initdb
-copy_artifact runtime:postgres executable bin/postgres /bin/postgres
-while IFS=$'\t' read -r relative aliases abi_policy extra; do
-  case "$relative" in
-    ""|'#'*) continue ;;
-  esac
-  artifact_name="runtime:${relative##*/}"
-  copy_artifact "$artifact_name" side-module "$relative" ""
-
-  # Dynamic-loader aliases are policy, not ad-hoc carrier knowledge. Keep each
-  # alias as a regular byte-identical file because sealed paths reject symlinks.
-  if [ "$aliases" != - ]; then
-    old_ifs="$IFS"
-    IFS=','
-    for alias_relative in $aliases; do
-      IFS="$old_ifs"
-      case "$alias_relative" in
-        lib/*.so|lib/*.so.*|lib/postgresql/*.so) ;;
-        *) fail "invalid sealed side-module alias: $alias_relative" ;;
-      esac
-      [ ! -e "$staging/$alias_relative" ] || {
-        fail "duplicate sealed side-module alias: $alias_relative"
-      }
-      mkdir -p "$staging/$(dirname "$alias_relative")"
-      cp -p "$staging/$relative" "$staging/$alias_relative"
-      IFS=','
-    done
-    IFS="$old_ifs"
-  fi
-done <"$side_module_policy"
-
-if find "$staging" -type l -print -quit | grep -q .; then
-  fail "staged carrier contains a symbolic link"
-fi
-if find "$staging" ! -type d ! -type f -print -quit | grep -q .; then
-  fail "staged carrier contains a special file"
-fi
-
-sealed_receipt="$staging/wasmer-build.receipt"
-cp -p "$receipt" "$sealed_receipt"
-chmod 0444 "$sealed_receipt"
-sealed_postmaster_executor_receipt="$staging/postmaster-executor.receipt"
-cp -p "$postmaster_executor_receipt" "$sealed_postmaster_executor_receipt"
-chmod 0444 "$sealed_postmaster_executor_receipt"
-sealed_product_build_receipt="$sealed_postmaster_executor_receipt"
-guest_build_receipt="$staging/guest-build.receipt"
-cp -p "$guest_build_receipt_source" "$guest_build_receipt"
-chmod 0444 "$guest_build_receipt"
-[ "$(fresh_wasmer_bin_hash "$guest_build_receipt")" = \
-  "$guest_build_recipe_sha256" ] || {
-  fail 'guest build receipt changed while packaging the carrier'
-}
-staged_guest_installed_closure_sha256="$(
-  python3 "$FRESH_ROOT/lib/guest_build_provenance.py" identity "$staging"
-)" || exit
-[ "$staged_guest_installed_closure_sha256" = \
-  "$guest_installed_closure_sha256" ] || {
-  fail 'staged guest bytes differ from their build receipt'
-}
-actual_guest_installed_closure_sha256="$(
-  python3 "$FRESH_ROOT/lib/guest_build_provenance.py" identity "$install_dir"
-)" || exit
-[ "$actual_guest_installed_closure_sha256" = \
-  "$guest_installed_closure_sha256" ] || {
-  fail 'guest install changed while the carrier was staged'
-}
-
-# From this point onward, derive every manifest identity from the immutable
-# carrier snapshot, not from a mutable external pathname. Revalidating both
-# binaries against that snapshot also closes the receipt/executor copy window.
-fresh_require_patched_postmaster_compiler \
-  "$postmaster_compiler" \
-  "$sealed_product_build_receipt" \
-  "$sealed_receipt" \
-  "$postmaster_executor"
-fresh_require_patched_postmaster_executor \
-  "$staging/bin/wasmer-headless" \
-  "$sealed_postmaster_executor_receipt" \
-  "$sealed_receipt"
-snapshot_runtime_abi_id="$(fresh_manifest_value "$sealed_receipt" runtime_abi_id)"
-[ "$snapshot_runtime_abi_id" = "$runtime_abi_id" ] || {
-  fail "runtime ABI changed while snapshotting the build receipt"
-}
-receipt="$sealed_receipt"
-
-source_fingerprint="$(python3 - "$staging" <<'PY'
-import hashlib
-import os
-import stat
-import sys
-
-root = os.path.realpath(sys.argv[1])
-hasher = hashlib.sha256()
-for subtree in ("bin", "lib", "share"):
-    for current, dirs, files in os.walk(os.path.join(root, subtree), followlinks=False):
-        dirs.sort()
-        files.sort()
-        for name in files:
-            path = os.path.join(current, name)
-            info = os.lstat(path)
-            if not stat.S_ISREG(info.st_mode):
-                raise SystemExit(f"non-regular carrier input: {path}")
-            relative = os.path.relpath(path, root)
-            if relative == "bin/wasmer-headless":
-                continue
-            digest = hashlib.sha256()
-            with open(path, "rb", buffering=0) as stream:
-                for chunk in iter(lambda: stream.read(1024 * 1024), b""):
-                    digest.update(chunk)
-            for value in (relative, str(info.st_size), digest.hexdigest()):
-                encoded = value.encode("utf-8")
-                hasher.update(len(encoded).to_bytes(8, "big"))
-                hasher.update(encoded)
-print(hasher.hexdigest())
-PY
-)"
-fresh_is_sha256 "$source_fingerprint" || fail "failed to compute PostgreSQL carrier fingerprint"
-
-executor_sha256="$(fresh_wasmer_bin_hash "$staging/bin/wasmer-headless")"
-executor_size="$(wc -c <"$staging/bin/wasmer-headless" | tr -d '[:space:]')"
-target_triple="$(fresh_manifest_value "$receipt" rustc_host)"
-host_abi="$(fresh_manifest_value "$receipt" host_abi)"
-wasmer_source_commit="$(fresh_manifest_value "$receipt" wasmer_source_commit)"
-wasmer_patch_sha256="$(fresh_manifest_value "$receipt" wasmer_patch_sha256)"
-wasmer_cargo_lock_sha256="$(fresh_manifest_value "$receipt" wasmer_cargo_lock_sha256)"
-producer_recipe_sha256="$(fresh_aot_producer_recipe_sha256 \
-  "$receipt" "$sealed_product_build_receipt" "$compiler_config" \
-  "$target_triple" "$source_fingerprint")"
-fresh_is_sha256 "$producer_recipe_sha256" || fail "failed to compute AOT producer recipe identity"
-
-write_sealed_manifest() {
-  local output_path="$1"
-
-  python3 - \
-    "$artifact_rows" \
-    "$staging" \
-    "$output_path" \
-    "$source_fingerprint" \
-    "$core_profile" \
-    "$guest_build_recipe_sha256" \
-    "$target_triple" \
-    "$host_abi" \
-    "$compiler_config" \
-    "$wasmer_source_commit" \
-    "$wasmer_patch_sha256" \
-    "$wasmer_cargo_lock_sha256" \
-    "$runtime_abi_id" \
-    "$producer_recipe_sha256" \
-    "$executor_sha256" \
-    "$executor_size" \
-    "$POSTGRES_VERSION" \
-    "$FRESH_WASMER_VERSION" \
-    "$FRESH_WASMER_WASIX_VERSION" \
-    "$FRESH_WASMER_ARTIFACT_ABI_VERSION" \
-    "$linear_memory_receipt_relative" \
-    "$linear_memory_install_receipt_sha256" <<'PY'
-import hashlib
-import json
-import os
-import sys
-
-(
-    rows_path,
-    carrier_root,
-    output_path,
-    source_fingerprint,
-    core_profile,
-    guest_build_recipe_sha256,
-    target_triple,
-    host_abi,
-    compiler_config,
-    wasmer_source_commit,
-    wasmer_patch_sha256,
-    wasmer_cargo_lock_sha256,
-    runtime_abi_id,
-    producer_recipe_sha256,
-    executor_sha256,
-    executor_size,
-    postgres_version,
-    wasmer_version,
-    wasmer_wasix_version,
-    artifact_abi_version,
-    linear_memory_receipt_path,
-    linear_memory_receipt_sha256,
-) = sys.argv[1:]
-
-with open(os.path.join(carrier_root, linear_memory_receipt_path), "r", encoding="utf-8") as stream:
-    linear_memory_receipt = json.load(stream)
-if linear_memory_receipt.get("schema") != "oliphaunt.wasix-postmaster.linear-memory-install.v1":
-    raise SystemExit("linear-memory install receipt schema differs")
-profile_id = linear_memory_receipt.get("profile-id")
-expected_profile = {
-    "profile-id": "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1",
-    "address-width": "wasm32",
-    "supported-host-pointer-width": "u64",
-    "maximum-pages": 4096,
-    "maximum-bytes": 268435456,
-    "static-bound-pages": 65536,
-    "static-offset-guard-bytes": 2147483648,
-    "static-access-lowering": "wasmer-llvm-unchecked-reservation-and-guard-v1",
-}
-for key, expected in expected_profile.items():
-    if linear_memory_receipt.get(key) != expected:
-        raise SystemExit(f"linear-memory install receipt profile differs: {key}")
-linear_memory_modules = {}
-for record in linear_memory_receipt.get("modules", []):
-    path = record.get("path")
-    if not isinstance(path, str) or path in linear_memory_modules:
-        raise SystemExit("linear-memory install receipt has invalid module paths")
-    linear_memory_modules[path] = record
-
-artifacts = []
-with open(rows_path, "r", encoding="utf-8", newline="") as rows:
-    for line_number, line in enumerate(rows, 1):
-        fields = line.rstrip("\n").split("\t")
-        if len(fields) != 9:
-            raise SystemExit(f"invalid artifact metadata row {line_number}")
-        name, kind, path, module_path, artifact_hash, artifact_size, module_hash, module_size, alias = fields
-        try:
-            linear_memory_record = linear_memory_modules[module_path]
-        except KeyError:
-            raise SystemExit(f"linear-memory receipt has no record for {module_path}")
-        if linear_memory_record.get("module-sha256") != module_hash.lower():
-            raise SystemExit(f"linear-memory receipt module digest differs for {module_path}")
-        artifact = {
-            "name": name,
-            "kind": kind,
-            "path": path,
-            "module-path": module_path,
-            "sha256": artifact_hash,
-            "raw-sha256": artifact_hash,
-            "raw-size": int(artifact_size),
-            "module-sha256": module_hash,
-            "module-size": int(module_size),
-            "linear-memory": {
-                "profile-id": profile_id,
-                "source-module-sha256": linear_memory_record["source-module-sha256"],
-                "install-receipt-sha256": linear_memory_receipt_sha256,
-            },
-            "compressed": False,
-            "exec-aliases": [alias] if alias else [],
-        }
-        artifacts.append(artifact)
-
-manifest = {
-    "format-version": 6,
-    "schema": "oliphaunt.wasix-postmaster.sealed-aot.v5",
-    "source-lane": "wasix-postmaster",
-    "source-fingerprint": source_fingerprint,
-    "core-profile": core_profile,
-    "guest-build-recipe-sha256": guest_build_recipe_sha256,
-    "postgres-version": postgres_version,
-    "target-triple": target_triple,
-    "host-abi": host_abi,
-    "engine": "llvm-opta",
-    "compiler-config": compiler_config,
-    "cpu-policy": "generic-baseline",
-    "cpu-features": [],
-    "wasmer-version": wasmer_version,
-    "wasmer-wasix-version": wasmer_wasix_version,
-    "wasmer-source-commit": wasmer_source_commit,
-    "wasmer-patch-sha256": wasmer_patch_sha256,
-    "wasmer-cargo-lock-sha256": wasmer_cargo_lock_sha256,
-    "artifact-abi-version": int(artifact_abi_version),
-    "runtime-abi-id": runtime_abi_id,
-    "producer-recipe-sha256": producer_recipe_sha256,
-    "executor-engine": "engine-headless",
-    "executor-sha256": executor_sha256,
-    "executor-size": int(executor_size),
-    "linear-memory-profile": {
-        "id": profile_id,
-        "address-width": linear_memory_receipt["address-width"],
-        "supported-host-pointer-width": linear_memory_receipt["supported-host-pointer-width"],
-        "maximum-pages": linear_memory_receipt["maximum-pages"],
-        "maximum-bytes": linear_memory_receipt["maximum-bytes"],
-        "static-bound-pages": linear_memory_receipt["static-bound-pages"],
-        "static-offset-guard-bytes": linear_memory_receipt["static-offset-guard-bytes"],
-        "static-access-lowering": linear_memory_receipt["static-access-lowering"],
-        "install-receipt-path": linear_memory_receipt_path,
-        "install-receipt-sha256": linear_memory_receipt_sha256,
-    },
-    "wasm-features": ["exceptions", "threads"],
-    "entrypoint": "runtime:postgres",
-    "artifacts": artifacts,
-}
-with open(output_path, "x", encoding="utf-8", newline="\n") as output:
-    json.dump(manifest, output, ensure_ascii=False, indent=2)
-    output.write("\n")
-PY
-}
-
-write_sealed_manifest "$staging/manifest.json"
-rm "$artifact_rows"
-chmod 0444 "$staging/manifest.json"
-
-# Exercise the final sealed carrier before publication. A
-# version probe is sufficient for the postgres entrypoint, but initdb must run
-# its real bootstrap lifecycle: it reads the packaged share tree, loads libpq,
-# creates writable relation files, and EXEC_BACKEND-spawns the sealed postgres
-# alias.  Keep every writable path outside staging and remove it through the
-# same signal-safe cleanup path as the unpublished carrier.
-validation_root="$(mktemp -d "$output_parent/.${output_name}.validate.XXXXXX")"
-mkdir -p \
-  "$validation_root/home" \
-  "$validation_root/cache" \
-  "$validation_root/pgdata" \
-  "$validation_root/dev-shm"
-chmod 0700 "$validation_root/pgdata"
-chmod 1777 "$validation_root/dev-shm"
-
-# HostFS volumes are writable mappings.  Remove write permission from every
-# staged payload before exposing it to the guest, and verify its complete
-# content-and-mode fingerprint afterwards.  Only the disposable PGDATA and
-# /dev/shm mappings are intentionally writable.
-carrier_mode_snapshot="$validation_root/carrier-modes.json"
-python3 - "$staging" "$carrier_mode_snapshot" <<'PY'
-import json
-import os
-import stat
-import sys
-
-root = os.path.realpath(sys.argv[1])
-modes = {}
-for current, dirs, files in os.walk(root, followlinks=False):
-    dirs.sort()
-    files.sort()
-    for name in [*dirs, *files]:
-        path = os.path.join(current, name)
-        modes[os.path.relpath(path, root)] = stat.S_IMODE(os.lstat(path).st_mode)
-modes["."] = stat.S_IMODE(os.lstat(root).st_mode)
-with open(sys.argv[2], "x", encoding="utf-8", newline="\n") as stream:
-    json.dump(modes, stream, sort_keys=True)
-    stream.write("\n")
-PY
-chmod -R a-w "$staging"
-carrier_validation_fingerprint() {
-  python3 - "$staging" <<'PY'
-import hashlib
-import os
-import stat
-import sys
-
-root = os.path.realpath(sys.argv[1])
-digest = hashlib.sha256()
-for current, dirs, files in os.walk(root, followlinks=False):
-    dirs.sort()
-    files.sort()
-    relative_directory = os.path.relpath(current, root)
-    directory_mode = stat.S_IMODE(os.lstat(current).st_mode)
-    digest.update(f"d\0{relative_directory}\0{directory_mode:o}\0".encode())
-    for name in files:
-        path = os.path.join(current, name)
-        info = os.lstat(path)
-        if not stat.S_ISREG(info.st_mode):
-            raise SystemExit(f"carrier validation input is not regular: {path}")
-        relative = os.path.relpath(path, root)
-        file_digest = hashlib.sha256()
-        with open(path, "rb", buffering=0) as stream:
-            for chunk in iter(lambda: stream.read(1024 * 1024), b""):
-                file_digest.update(chunk)
-        digest.update(
-            f"f\0{relative}\0{stat.S_IMODE(info.st_mode):o}\0{info.st_size}\0{file_digest.hexdigest()}\0".encode()
-        )
-print(digest.hexdigest())
-PY
-}
-validation_fingerprint="$(carrier_validation_fingerprint)"
-fresh_is_sha256 "$validation_fingerprint" || fail "failed to fingerprint carrier before validation"
-
-validation_common_args=(
-  run
-  --disable-cache
-  --stack-size "$runtime_stack_size"
-  --sealed-module-manifest "$staging/manifest.json"
-  --enable-exceptions
-  --enable-threads
-  --net
-  --volume "$staging:$staging"
-  --volume "$staging/share:/share"
-  --volume "$staging/lib:/lib"
-  --volume "$validation_root/pgdata:/pgdata"
-  --volume "$validation_root/dev-shm:/dev/shm"
-)
-
-postgres_validation_log="$validation_root/postgres.log"
-set +e
-env \
-  WASMER_DIR="$validation_root/home" \
-  WASMER_CACHE_DIR="$validation_root/cache" \
-  "$staging/bin/wasmer-headless" "${validation_common_args[@]}" \
-    "$staging/bin/postgres" -- --version >"$postgres_validation_log" 2>&1
-postgres_validation_status=$?
-set -e
-if [ "$postgres_validation_status" -ne 0 ]; then
-  sed 's/^/sealed postgres load check: /' "$postgres_validation_log" >&2
-  fail "headless executor rejected sealed postgres"
-fi
-
-initdb_validation_log="$validation_root/initdb.log"
-set +e
-env \
-  WASMER_DIR="$validation_root/home" \
-  WASMER_CACHE_DIR="$validation_root/cache" \
-  "$staging/bin/wasmer-headless" "${validation_common_args[@]}" \
-    "$staging/bin/initdb" -- \
-      -D /pgdata \
-      -A trust \
-      --no-locale \
-      --encoding=UTF8 \
-      --no-instructions >"$initdb_validation_log" 2>&1
-initdb_validation_status=$?
-set -e
-if [ "$initdb_validation_status" -ne 0 ]; then
-  sed 's/^/sealed initdb lifecycle check: /' "$initdb_validation_log" >&2
-  fail "headless executor failed the sealed initdb lifecycle"
-fi
-for initialized_path in PG_VERSION global/pg_control; do
-  if ! { [ -f "$validation_root/pgdata/$initialized_path" ] \
-    && [ ! -L "$validation_root/pgdata/$initialized_path" ] \
-    && [ -s "$validation_root/pgdata/$initialized_path" ]; }
-  then
-    fail "sealed initdb lifecycle did not create regular non-empty $initialized_path"
-  fi
-done
-
-[ "$(carrier_validation_fingerprint)" = "$validation_fingerprint" ] || {
-  fail "sealed validation mutated the staged carrier"
-}
-python3 - "$staging" "$carrier_mode_snapshot" <<'PY'
-import json
-import os
-import sys
-
-root = os.path.realpath(sys.argv[1])
-with open(sys.argv[2], encoding="utf-8") as stream:
-    modes = json.load(stream)
-for relative, mode in modes.items():
-    path = root if relative == "." else os.path.join(root, relative)
-    os.chmod(path, mode, follow_symlinks=False)
-PY
-cleanup_validation_root
-
-# The payload inventory covers every published regular file except itself.
-# It also provides a portable verification surface for support files that are
-# intentionally outside the strict AOT loader schema.
-python3 - "$staging" "$staging/payload.files" <<'PY'
-import hashlib
-import os
-import stat
-import sys
-
-root = os.path.realpath(sys.argv[1])
-inventory = os.path.realpath(sys.argv[2])
-rows = []
-for current, dirs, files in os.walk(root, followlinks=False):
-    dirs.sort()
-    files.sort()
-    for name in files:
-        path = os.path.join(current, name)
-        if os.path.realpath(path) == inventory:
-            continue
-        info = os.lstat(path)
-        if not stat.S_ISREG(info.st_mode):
-            raise SystemExit(f"carrier contains non-regular file: {path}")
-        relative = os.path.relpath(path, root)
-        if any(character in relative for character in ("\n", "\r", "\t")):
-            raise SystemExit(f"carrier path contains a control delimiter: {relative!r}")
-        digest = hashlib.sha256()
-        with open(path, "rb", buffering=0) as stream:
-            for chunk in iter(lambda: stream.read(1024 * 1024), b""):
-                digest.update(chunk)
-        rows.append((relative, info.st_size, digest.hexdigest()))
-with open(inventory, "x", encoding="utf-8", newline="\n") as output:
-    output.write("schema=oliphaunt.wasix-postmaster.payload-files.v1\n")
-    for relative, size, digest in sorted(rows):
-        output.write(f"{digest}\t{size}\t{relative}\n")
-PY
-chmod 0444 "$staging/payload.files"
-
-# A sealed carrier is an immutable deployment input, not a runtime cache or a
-# scratch directory.  Normalize the published mode surface after the complete
-# payload has been assembled: every directory is traversable/read-only and
-# every regular file is read-only, while preserving whether a file was meant
-# to be directly executable by the host.  The loader must place any ephemeral
-# AOT snapshot in its separate scratch tier.  The cleanup trap deliberately
-# restores owner write permission if a later publication check fails.
-python3 - "$staging" <<'PY'
-import os
-import stat
-import sys
-
-root = os.path.realpath(sys.argv[1])
-for current, directories, files in os.walk(root, topdown=False, followlinks=False):
-    for name in files:
-        path = os.path.join(current, name)
-        info = os.lstat(path)
-        if not stat.S_ISREG(info.st_mode):
-            raise SystemExit(f"sealed carrier contains a non-regular file: {path}")
-        executable = bool(stat.S_IMODE(info.st_mode) & 0o111)
-        os.chmod(path, 0o555 if executable else 0o444, follow_symlinks=False)
-    for name in directories:
-        path = os.path.join(current, name)
-        info = os.lstat(path)
-        if not stat.S_ISDIR(info.st_mode) or stat.S_ISLNK(info.st_mode):
-            raise SystemExit(f"sealed carrier contains a non-directory: {path}")
-        os.chmod(path, 0o555, follow_symlinks=False)
-os.chmod(root, 0o555, follow_symlinks=False)
-PY
-
-# Reconsume the finished staging tree through the same verifier used by every
-# sealed runtime entrypoint. This proves that the inventory is exact and that
-# its manifest, receipt, executor, modules, and AOT artifacts form one
-# internally consistent closure before any path is published.
-fresh_verify_sealed_headless_carrier "$staging" || {
-  fail "finished sealed carrier failed complete payload verification"
-}
-
-payload_inventory_sha256="$(fresh_wasmer_bin_hash "$staging/payload.files")"
-fresh_is_sha256 "$payload_inventory_sha256" || {
-  fail "failed to compute sealed carrier payload identity"
-}
-if [ "$output_is_explicit" -eq 0 ]; then
-  output_name="wasix-postmaster-$POSTGRES_VERSION-${runtime_abi_id:0:16}-$payload_inventory_sha256"
-  output="$output_parent/$output_name"
-  [ ! -e "$output" ] && [ ! -L "$output" ] || {
-    fail "content-addressed output already exists: $output"
-  }
-fi
-
-# Durability is scoped to the carrier: flush each regular file, then each
-# directory bottom-up.  This avoids a global sync while ensuring rename never
-# publishes a directory whose verified bytes only lived in page cache.
-python3 - "$staging" <<'PY'
-import os
-import stat
-import sys
-
-root = os.path.realpath(sys.argv[1])
-directories = []
-for current, dirs, files in os.walk(root, topdown=True, followlinks=False):
-    directories.append(current)
-    for name in files:
-        path = os.path.join(current, name)
-        info = os.lstat(path)
-        if not stat.S_ISREG(info.st_mode):
-            raise SystemExit(f"carrier contains non-regular file: {path}")
-        flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
-        descriptor = os.open(path, flags)
-        try:
-            os.fsync(descriptor)
-        finally:
-            os.close(descriptor)
-for directory in reversed(directories):
-    flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_DIRECTORY", 0)
-    descriptor = os.open(directory, flags)
-    try:
-        os.fsync(descriptor)
-    finally:
-        os.close(descriptor)
-PY
-
-publication_lock_path="$output_parent/.${output_name}.publish.lock"
-exec {publication_lock_fd}>"$publication_lock_path"
-chmod 0600 "$publication_lock_path"
-flock -n "$publication_lock_fd" ||
-  fail "another process is publishing the same carrier output: $output"
-[ ! -e "$output" ] && [ ! -L "$output" ] ||
-  fail "carrier output appeared before atomic publication: $output"
-fresh_atomic_publish_directory_noreplace "$staging" "$output" ||
-  fail "could not atomically publish sealed carrier: $output"
-staging=""
-python3 - "$output_parent" <<'PY'
-import os
-import sys
-
-flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_DIRECTORY", 0)
-descriptor = os.open(sys.argv[1], flags)
-try:
-    os.fsync(descriptor)
-finally:
-    os.close(descriptor)
-PY
-trap - EXIT HUP INT TERM
-
-printf 'built sealed headless WASIX PostgreSQL carrier: %s\n' "$output"
-printf 'executor role: postmaster-product\n'
-printf 'runtime ABI ID: %s\n' "$runtime_abi_id"
-printf 'source fingerprint: %s\n' "$source_fingerprint"
-printf 'payload inventory SHA-256: %s\n' "$payload_inventory_sha256"
-printf 'payload inventory: %s\n' "$output/payload.files"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-sealed-headless-carrier.test.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-sealed-headless-carrier.test.sh
deleted file mode 100755
index 5b7886b15..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-sealed-headless-carrier.test.sh
+++ /dev/null
@@ -1,950 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-sealed-carrier.XXXXXX")"
-test_root="$(cd "$test_root" && pwd -P)"
-cleanup_test_root() {
-  chmod -R u+w "$test_root" 2>/dev/null || true
-  rm -rf -- "$test_root"
-}
-trap cleanup_test_root EXIT
-
-export FRESH_WORK_ROOT="$test_root/work"
-export FRESH_UPSTREAM_WASMER_BIN="$test_root/wasmer"
-export FRESH_UPSTREAM_WASMER_HEADLESS_BIN="$test_root/wasmer-headless"
-export FRESH_POSTMASTER_EXECUTOR_BIN="$test_root/postmaster-executor"
-export FRESH_START_PROOF_BIN="$test_root/start-proof"
-export FRESH_POSTMASTER_COMPILER_BIN="$test_root/postmaster-compiler"
-export FRESH_WASMER_BUILD_RECEIPT="$test_root/wasmer-build.receipt"
-export FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT="$test_root/postmaster-executor-build.receipt"
-export WASIX_INSTALL_DIR="$test_root/install"
-export WASIX_CORE_PROFILE=release-o3
-export FAKE_WASMER_CAPTURE_LOG="$test_root/memory-captures.log"
-export FAKE_WASMER_VALIDATION_LOG="$test_root/final-validations.log"
-unset FRESH_PINNED_WASMER_CACHE_DIR FRESH_ALLOW_PINNED_CACHE_WRITE
-
-source "$project_root/lib/common.sh"
-source "$project_root/lib/sealed-carrier.sh"
-
-atomic_parent="$test_root/atomic-publication"
-mkdir -p "$atomic_parent/source" "$atomic_parent/competitor"
-printf 'owned-by-competitor\n' >"$atomic_parent/competitor/sentinel"
-if fresh_atomic_publish_directory_noreplace \
-  "$atomic_parent/source" "$atomic_parent/competitor" >/dev/null 2>&1; then
-  printf 'atomic carrier publication replaced a competitor unexpectedly\n' >&2
-  exit 1
-fi
-[ -d "$atomic_parent/source" ] && \
-  [ "$(cat "$atomic_parent/competitor/sentinel")" = owned-by-competitor ] || {
-  printf 'failed atomic publication mutated source or competitor output\n' >&2
-  exit 1
-}
-mkdir "$atomic_parent/publishable"
-printf 'published\n' >"$atomic_parent/publishable/payload"
-fresh_atomic_publish_directory_noreplace \
-  "$atomic_parent/publishable" "$atomic_parent/published"
-[ ! -e "$atomic_parent/publishable" ] && \
-  [ "$(cat "$atomic_parent/published/payload")" = published ] || {
-  printf 'atomic carrier publication did not rename the exact source directory\n' >&2
-  exit 1
-}
-
-mkdir -p \
-  "$WASIX_INSTALL_DIR/bin" \
-  "$WASIX_INSTALL_DIR/lib/postgresql" \
-  "$WASIX_INSTALL_DIR/share/postgresql"
-cp "$project_root/testdata/fake-sealed-wasmer.py" "$FRESH_UPSTREAM_WASMER_BIN"
-cp "$project_root/testdata/fake-sealed-wasmer.py" "$FRESH_UPSTREAM_WASMER_HEADLESS_BIN"
-cp "$project_root/testdata/fake-sealed-wasmer.py" "$FRESH_POSTMASTER_EXECUTOR_BIN"
-printf '# product-executor-fixture\n' >>"$FRESH_POSTMASTER_EXECUTOR_BIN"
-cp "$project_root/testdata/fake-start-proof.py" "$FRESH_START_PROOF_BIN"
-cp "$project_root/testdata/fake-postmaster-compiler.py" "$FRESH_POSTMASTER_COMPILER_BIN"
-chmod +x "$FRESH_UPSTREAM_WASMER_BIN" "$FRESH_UPSTREAM_WASMER_HEADLESS_BIN" \
-  "$FRESH_POSTMASTER_EXECUTOR_BIN" "$FRESH_START_PROOF_BIN" \
-  "$FRESH_POSTMASTER_COMPILER_BIN"
-printf 'initdb-wasm\n' >"$WASIX_INSTALL_DIR/bin/initdb"
-printf 'postgres-wasm\n' >"$WASIX_INSTALL_DIR/bin/postgres"
-printf 'libpq-wasm\n' >"$WASIX_INSTALL_DIR/lib/libpq.so.5.18"
-printf 'snowball-wasm\n' >"$WASIX_INSTALL_DIR/lib/postgresql/dict_snowball.so"
-printf 'plpgsql-wasm\n' >"$WASIX_INSTALL_DIR/lib/postgresql/plpgsql.so"
-printf 'sample-config\n' >"$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample"
-python3 "$project_root/testdata/make-sealed-export-fixture.py" \
-  --install-root "$WASIX_INSTALL_DIR" \
-  --project-root "$project_root"
-chmod 0644 "$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample"
-postgres_sha256="$(fresh_wasmer_bin_hash "$WASIX_INSTALL_DIR/bin/postgres")"
-final_wasm_concurrency_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt"
-{
-  printf 'schema=oliphaunt.wasix-postmaster.final-wasm-concurrency.v1\n'
-  printf 'postgres_sha256=%s\n' "$postgres_sha256"
-  printf 'wasm_dis_sha256=%064d\n' 2
-  printf 'wasm_dis_version=fake-wasm-dis version 130\n'
-  printf 'latch_state_contract=packed-atomic-v1\n'
-  printf 'atomic_fence_total=995\n'
-  printf 'atomic_fence_set_latch=2\n'
-  printf 'atomic_fence_reset_latch=1\n'
-  printf 'atomic_fence_wait_event_set_wait=1\n'
-  printf 'i32_atomic_load_total=2\n'
-  printf 'i32_atomic_load_wait_event_set_wait=2\n'
-  printf 'i32_atomic_rmw_and_total=7\n'
-  printf 'i32_atomic_rmw_and_reset_latch=1\n'
-  printf 'i32_atomic_rmw_and_wait_event_set_wait=2\n'
-  printf 'i32_atomic_rmw_or_total=117\n'
-  printf 'i32_atomic_rmw_or_set_latch=1\n'
-  printf 'i32_atomic_rmw_or_wait_event_set_wait=1\n'
-} >"$final_wasm_concurrency_receipt"
-chmod 0444 "$final_wasm_concurrency_receipt"
-final_wasm_concurrency_receipt_sha256="$(
-  fresh_wasmer_bin_hash "$final_wasm_concurrency_receipt"
-)"
-
-sealed_export_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
-linear_memory_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
-python3 - "$WASIX_INSTALL_DIR" "$sealed_export_receipt" "$linear_memory_receipt" "$project_root" <<'PY'
-import hashlib
-import json
-import sys
-from pathlib import Path
-
-root = Path(sys.argv[1])
-predecessor = Path(sys.argv[2])
-output = Path(sys.argv[3])
-project_root = Path(sys.argv[4])
-side_manifest = project_root / "runtime/policies/sealed-side-modules.v1.tsv"
-side_paths = [
-    line.split("\t", 1)[0]
-    for line in side_manifest.read_text(encoding="utf-8").splitlines()
-    if line and not line.startswith("#")
-]
-module_paths = ("bin/initdb", "bin/postgres", *side_paths)
-records = []
-for relative in module_paths:
-    data = (root / relative).read_bytes()
-    records.append(
-        {
-            "path": relative,
-            "source-module-sha256": hashlib.sha256(data).hexdigest(),
-            "module-sha256": hashlib.sha256(data).hexdigest(),
-            "initial-pages": 1,
-            "maximum-pages": 4096,
-            "maximum-bytes": 268435456,
-            "shared": True,
-            "import-module": "env",
-            "import-name": "memory",
-            "transformation": "pinned-wasixcc-65536-to-embedded-4096-reversible-v1",
-        }
-    )
-records.sort(key=lambda record: record["path"])
-
-def closure_hash(field):
-    digest = hashlib.sha256()
-    for value in (
-        "oliphaunt.wasix-postmaster.linear-memory-install-closure.v1",
-        field,
-    ):
-        encoded = value.encode()
-        digest.update(len(encoded).to_bytes(8, "big"))
-        digest.update(encoded)
-    for record in records:
-        for value in (record["path"], record[field]):
-            encoded = value.encode()
-            digest.update(len(encoded).to_bytes(8, "big"))
-            digest.update(encoded)
-    return digest.hexdigest()
-
-receipt = {
-    "schema": "oliphaunt.wasix-postmaster.linear-memory-install.v1",
-    "profile-id": "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1",
-    "address-width": "wasm32",
-    "supported-host-pointer-width": "u64",
-    "maximum-pages": 4096,
-    "maximum-bytes": 268435456,
-    "static-bound-pages": 65536,
-    "static-offset-guard-bytes": 2147483648,
-    "static-access-lowering": "wasmer-llvm-unchecked-reservation-and-guard-v1",
-    "requires-shared": True,
-    "requires-import": "env.memory",
-    "excludes-wasm32-end-wrap": True,
-    "predecessor-export-closure-receipt": predecessor.relative_to(root).as_posix(),
-    "predecessor-export-closure-receipt-sha256": hashlib.sha256(predecessor.read_bytes()).hexdigest(),
-    "source-module-closure-sha256": closure_hash("source-module-sha256"),
-    "module-closure-sha256": closure_hash("module-sha256"),
-    "module-count": len(records),
-    "modules": records,
-}
-with output.open("x", encoding="utf-8", newline="\n") as stream:
-    json.dump(receipt, stream, indent=2, sort_keys=True)
-    stream.write("\n")
-PY
-chmod 0444 "$sealed_export_receipt" "$linear_memory_receipt"
-linear_memory_install_receipt_sha256="$(fresh_wasmer_bin_hash "$linear_memory_receipt")"
-
-installed_closure_sha256="$(
-  python3 "$project_root/lib/guest_build_provenance.py" \
-    identity "$WASIX_INSTALL_DIR"
-)"
-{
-  printf 'schema=oliphaunt.wasix-postmaster.guest-build.v5\n'
-  printf 'core_profile=release-o3\n'
-  printf 'guest_source_signature_sha256=%064d\n' 1
-  printf 'docker_image_id=sha256:%064d\n' 2
-  printf 'installed_closure_sha256=%s\n' "$installed_closure_sha256"
-  printf 'child_backend=exec\n'
-  printf 'effective_cflags=-O3 -g0 -flto=thin\n'
-  printf 'effective_ldflags=-flto=thin\n'
-  printf 'effective_wasm_opt=yes\n'
-  printf 'effective_wasm_opt_flags=--converge:--strip-debug:--strip-producers\n'
-  printf 'effective_wasm_opt_suppress_default=yes\n'
-  printf 'atomic_fence_total=995\n'
-  printf 'atomic_fence_set_latch=2\n'
-  printf 'atomic_fence_reset_latch=1\n'
-  printf 'atomic_fence_wait_event_set_wait=1\n'
-  printf 'latch_state_contract=packed-atomic-v1\n'
-  printf 'final_wasm_concurrency_receipt_sha256=%s\n' \
-    "$final_wasm_concurrency_receipt_sha256"
-  printf 'linear_memory_profile_id=%s\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
-  printf 'linear_memory_install_receipt_sha256=%s\n' \
-    "$linear_memory_install_receipt_sha256"
-  printf 'postgres_tag=%s\n' "$POSTGRES_TAG"
-  printf 'postgres_version=%s\n' "$POSTGRES_VERSION"
-  printf 'sysroot_variant=%s\n' "$WASIXCC_SYSROOT_VARIANT"
-} >"$WASIX_INSTALL_DIR/guest-build.receipt"
-
-cargo_lock_sha256="$(printf test-cargo-lock | fresh_sha256_stream)"
-runtime_abi_id="$(fresh_runtime_abi_id \
-  "$cargo_lock_sha256" "$(fresh_host_arch | sed 's/linux-amd64/x86_64-unknown-linux-gnu/; s/linux-arm64/aarch64-unknown-linux-gnu/; s/darwin-amd64/x86_64-apple-darwin/; s/darwin-arm64/aarch64-apple-darwin/')" \
-  "$(fresh_host_arch)" "$(fresh_host_abi)")"
-target_triple="$(fresh_host_arch | sed 's/linux-amd64/x86_64-unknown-linux-gnu/; s/linux-arm64/aarch64-unknown-linux-gnu/; s/darwin-amd64/x86_64-apple-darwin/; s/darwin-arm64/aarch64-apple-darwin/')"
-
-{
-  printf 'schema=oliphaunt.wasix-postmaster.wasmer-build.v2\n'
-  printf 'build_recipe_sha256=%s\n' "$(fresh_runtime_build_recipe_sha256)"
-  printf 'wasmer_source_commit=%s\n' "$FRESH_WASMER_SOURCE_COMMIT"
-  printf 'wasmer_napi_commit=%s\n' "$FRESH_WASMER_NAPI_COMMIT"
-  printf 'wasmer_test_files_commit=%s\n' "$FRESH_WASMER_TEST_FILES_COMMIT"
-  printf 'wasmer_spec_commit=%s\n' "$FRESH_WASMER_SPEC_COMMIT"
-  printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch")"
-  printf 'wasmer_prepared_signature_sha256=%064d\n' 0
-  printf 'wasmer_cargo_lock_sha256=%s\n' "$cargo_lock_sha256"
-  printf 'wasmer_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_UPSTREAM_WASMER_BIN")"
-  printf 'wasmer_features=%s\n' "$FRESH_WASMER_COMPILER_FEATURES"
-  printf 'wasmer_headless_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_UPSTREAM_WASMER_HEADLESS_BIN")"
-  printf 'wasmer_headless_features=%s\n' "$FRESH_WASMER_HEADLESS_FEATURES"
-  printf 'runtime_abi_id=%s\n' "$runtime_abi_id"
-  printf 'artifact_abi_version=%s\n' "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
-  printf 'wasix_libc_source_commit=%s\n' "$FRESH_WASIX_LIBC_SOURCE_COMMIT"
-  printf 'wasix_libc_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$project_root/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch")"
-  printf 'wasix_libc_prepared_signature_sha256=%064d\n' 0
-  printf 'sysroot_carrier_manifest_sha256=%064d\n' 0
-  printf 'sysroot_variant=%s\n' "$WASIXCC_SYSROOT_VARIANT"
-  printf 'sysroot_variant_manifest_sha256=%064d\n' 0
-  printf 'host_platform=%s\n' "$(fresh_host_arch)"
-  printf 'host_abi=%s\n' "$(fresh_host_abi)"
-  printf 'rustc_host=%s\n' "$target_triple"
-  printf 'rustc_version=test-rustc\n'
-  printf 'llvm_version=22.1.0\n'
-} >"$FRESH_WASMER_BUILD_RECEIPT"
-
-{
-  printf 'schema=oliphaunt.wasix-postmaster.postmaster-executor-build.v3\n'
-  printf 'build_recipe_sha256=%s\n' "$(fresh_runtime_build_recipe_sha256)"
-  printf 'wasmer_build_receipt_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_WASMER_BUILD_RECEIPT")"
-  printf 'wasmer_source_commit=%s\n' "$FRESH_WASMER_SOURCE_COMMIT"
-  printf 'wasmer_patch_sha256=%s\n' "$(fresh_manifest_value "$FRESH_WASMER_BUILD_RECEIPT" wasmer_patch_sha256)"
-  printf 'wasmer_prepared_signature_sha256=%s\n' "$(fresh_manifest_value "$FRESH_WASMER_BUILD_RECEIPT" wasmer_prepared_signature_sha256)"
-  printf 'wasmer_cargo_lock_sha256=%s\n' "$cargo_lock_sha256"
-  printf 'runtime_abi_id=%s\n' "$runtime_abi_id"
-  printf 'artifact_abi_version=%s\n' "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
-  printf 'executor_package=%s\n' "$FRESH_POSTMASTER_EXECUTOR_PACKAGE"
-  printf 'executor_binary=%s\n' "$FRESH_POSTMASTER_EXECUTOR_BINARY"
-  printf 'executor_features=%s\n' "$FRESH_POSTMASTER_EXECUTOR_FEATURES"
-  printf 'executor_role=%s\n' "$FRESH_POSTMASTER_EXECUTOR_ROLE"
-  printf 'runtime_policy_id=%s\n' "$FRESH_POSTMASTER_EXECUTOR_RUNTIME_POLICY_ID"
-  printf 'cli_contract=%s\n' "$FRESH_POSTMASTER_EXECUTOR_CLI_CONTRACT"
-  printf 'executor_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_POSTMASTER_EXECUTOR_BIN")"
-  printf 'start_proof_binary=%s\n' "$FRESH_START_PROOF_BINARY"
-  printf 'start_proof_features=%s\n' "$FRESH_START_PROOF_FEATURES"
-  printf 'start_proof_policy=%s\n' "$FRESH_START_PROOF_POLICY"
-  printf 'start_proof_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$FRESH_START_PROOF_BIN")"
-  printf 'memory_profile_binary=%s\n' "$FRESH_MEMORY_PROFILE_BINARY"
-  printf 'memory_profile_features=%s\n' "$FRESH_MEMORY_PROFILE_FEATURES"
-  printf 'linear_memory_profile_id=%s\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
-  printf 'memory_profile_binary_sha256=%064d\n' 9
-  printf 'postmaster_compiler_binary=%s\n' "$FRESH_POSTMASTER_COMPILER_BINARY"
-  printf 'postmaster_compiler_features=%s\n' "$FRESH_POSTMASTER_COMPILER_FEATURES"
-  printf 'compiler_cpu_policy=generic-baseline\n'
-  printf 'compiler_cpu_features=none\n'
-  printf 'postmaster_compiler_binary_sha256=%s\n' \
-    "$(fresh_wasmer_bin_hash "$FRESH_POSTMASTER_COMPILER_BIN")"
-  printf 'host_platform=%s\n' "$(fresh_host_arch)"
-  printf 'host_abi=%s\n' "$(fresh_host_abi)"
-  printf 'rustc_host=%s\n' "$target_triple"
-  printf 'rustc_version=test-rustc\n'
-} >"$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
-
-cache_bucket="$(fresh_wasmer_cache_dir "$FRESH_POSTMASTER_COMPILER_BIN")/compiled/$(fresh_wasmer_compiler_cache_bucket llvm aggressive "$FRESH_WASMER_ARTIFACT_ABI_VERSION")"
-mkdir -p "$cache_bucket"
-required_modules=(bin/initdb bin/postgres)
-while IFS=$'\t' read -r relative _aliases _abi_policy; do
-  case "$relative" in
-    ""|'#'*) continue ;;
-  esac
-  required_modules+=("$relative")
-done <"$project_root/runtime/policies/sealed-side-modules.v1.tsv"
-for relative in "${required_modules[@]}"; do
-  module="$WASIX_INSTALL_DIR/$relative"
-  module_hash="$(fresh_wasmer_module_hash "$module")"
-  "$FRESH_POSTMASTER_COMPILER_BIN" \
-    --llvm --llvm-opt-level aggressive --compiler-threads 1 \
-    --enable-exceptions --enable-threads \
-    -o "$cache_bucket/$module_hash.bin" "$module"
-done
-
-cp "$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample" \
-  "$test_root/postgresql.conf.sample.saved"
-printf 'stale-install-mutation\n' \
-  >>"$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample"
-if "$project_root/bin/build-sealed-headless-carrier.sh" \
-  --output "$test_root/stale-guest-receipt-carrier" \
-  --cache-bucket "$cache_bucket" >/dev/null 2>&1
-then
-  printf 'carrier builder accepted guest bytes differing from their build receipt\n' >&2
-  exit 1
-fi
-mv "$test_root/postgresql.conf.sample.saved" \
-  "$WASIX_INSTALL_DIR/share/postgresql/postgresql.conf.sample"
-
-postgres_hash="$(fresh_wasmer_module_hash "$WASIX_INSTALL_DIR/bin/postgres")"
-mv "$cache_bucket/$postgres_hash.bin" "$test_root/postgres-aot.saved"
-if "$project_root/bin/build-sealed-headless-carrier.sh" \
-  --output "$test_root/missing-artifact-carrier" \
-  --cache-bucket "$cache_bucket" >/dev/null 2>&1
-then
-  printf 'carrier builder compiled or ignored a missing AOT artifact\n' >&2
-  exit 1
-fi
-mv "$test_root/postgres-aot.saved" "$cache_bucket/$postgres_hash.bin"
-
-plpgsql_hash="$(fresh_wasmer_module_hash "$WASIX_INSTALL_DIR/lib/postgresql/plpgsql.so")"
-mv "$cache_bucket/$plpgsql_hash.bin" "$test_root/plpgsql-aot.saved"
-printf 'wrong-plan-or-module-fixture\n' >"$cache_bucket/$plpgsql_hash.bin"
-if "$project_root/bin/build-sealed-headless-carrier.sh" \
-  --output "$test_root/invalid-inactive-aot-carrier" \
-  --cache-bucket "$cache_bucket" >/dev/null 2>&1
-then
-  printf 'carrier builder accepted an invalid inactive side-module AOT artifact\n' >&2
-  exit 1
-fi
-mv "$test_root/plpgsql-aot.saved" "$cache_bucket/$plpgsql_hash.bin"
-
-: >"$FAKE_WASMER_VALIDATION_LOG"
-failed_validation_output="$test_root/failed-initdb-carrier"
-if FAKE_WASMER_FAIL_FINAL_INITDB=1 \
-  "$project_root/bin/build-sealed-headless-carrier.sh" \
-    --output "$failed_validation_output" \
-    --cache-bucket "$cache_bucket" >/dev/null 2>&1
-then
-  printf 'carrier builder published after the final initdb lifecycle failed\n' >&2
-  exit 1
-fi
-[ ! -e "$failed_validation_output" ]
-if find "$test_root" -maxdepth 1 -type d \
-  \( -name '.failed-initdb-carrier.tmp.*' -o -name '.failed-initdb-carrier.validate.*' \) \
-  -print -quit | grep -q .
-then
-  printf 'carrier builder left staging or validation state after initdb failure\n' >&2
-  exit 1
-fi
-python3 - "$FAKE_WASMER_VALIDATION_LOG" <<'PY'
-import json
-import os
-import sys
-
-with open(sys.argv[1], encoding="utf-8") as stream:
-    records = [json.loads(line) for line in stream]
-assert [record["program"] for record in records] == ["postgres", "initdb"]
-assert records[0]["arguments"] == ["--version"]
-assert records[1]["arguments"] != ["--version"]
-for record in records:
-    for volume in record["volumes"]:
-        host, guest = volume.rsplit(":", 1)
-        if guest in {"/pgdata", "/dev/shm"}:
-            assert not os.path.exists(host), (guest, host)
-PY
-
-: >"$FAKE_WASMER_CAPTURE_LOG"
-: >"$FAKE_WASMER_VALIDATION_LOG"
-
-if FRESH_PINNED_WASMER_CACHE_DIR="$test_root/foreign-pinned-cache" \
-  "$project_root/bin/build-sealed-headless-carrier.sh" \
-    --output "$test_root/pinned-cache-carrier" \
-    --cache-bucket "$cache_bucket" >/dev/null 2>&1
-then
-  printf 'carrier builder admitted a pinned or foreign AOT cache root\n' >&2
-  exit 1
-fi
-[ ! -e "$test_root/pinned-cache-carrier" ]
-
-output="$test_root/carrier"
-"$project_root/bin/build-sealed-headless-carrier.sh" \
-  --output "$output" \
-  --cache-bucket "$cache_bucket"
-
-for required in \
-  bin/wasmer-headless \
-  bin/initdb \
-  bin/postgres \
-  lib/libpq.so \
-  lib/libpq.so.5 \
-  lib/libpq.so.5.18 \
-  lib/postgresql/dict_snowball.so \
-  lib/postgresql/plpgsql.so \
-  share/postgresql/postgresql.conf.sample \
-  share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json \
-  share/postgresql/wasix-postmaster.sealed-export.structure.receipt \
-  guest-build.receipt \
-  manifest.json \
-  payload.files \
-  postmaster-executor.receipt \
-  wasmer-build.receipt
-do
-  [ -f "$output/$required" ] && [ ! -L "$output/$required" ] || {
-    printf 'missing regular carrier test output: %s\n' "$required" >&2
-    exit 1
-  }
-done
-while IFS=$'\t' read -r relative aliases _abi_policy; do
-  case "$relative" in
-    ""|'#'*) continue ;;
-  esac
-  [ -f "$output/$relative" ] && [ ! -L "$output/$relative" ] || {
-    printf 'missing regular carrier side module: %s\n' "$relative" >&2
-    exit 1
-  }
-  if [ "$aliases" != - ]; then
-    old_ifs="$IFS"
-    IFS=','
-    for alias_relative in $aliases; do
-      IFS="$old_ifs"
-      cmp -s "$output/$relative" "$output/$alias_relative" || {
-        printf 'carrier side-module alias differs from canonical module: %s\n' \
-          "$alias_relative" >&2
-        exit 1
-      }
-      IFS=','
-    done
-    IFS="$old_ifs"
-  fi
-done <"$project_root/runtime/policies/sealed-side-modules.v1.tsv"
-side_module_count="$(awk -F '\t' '!/^#/ && NF { count += 1 } END { print count + 0 }' \
-  "$project_root/runtime/policies/sealed-side-modules.v1.tsv")"
-[ "$(find "$output/aot" -type f -name '*.bin' | wc -l | tr -d '[:space:]')" -eq "$((side_module_count + 2))" ]
-[ "$(wc -l <"$FAKE_WASMER_VALIDATION_LOG" | tr -d '[:space:]')" -eq 2 ]
-[ "$(stat -c %a "$output" 2>/dev/null || stat -f %Lp "$output")" = 555 ]
-[ "$(stat -c %a "$output/share/postgresql/postgresql.conf.sample" 2>/dev/null || stat -f %Lp "$output/share/postgresql/postgresql.conf.sample")" = 444 ]
-
-python3 - "$output" "$project_root/runtime/policies/sealed-side-modules.v1.tsv" <<'PY'
-import hashlib
-import json
-import os
-import sys
-
-root = sys.argv[1]
-side_module_policy = sys.argv[2]
-with open(os.path.join(root, "manifest.json"), encoding="utf-8") as stream:
-    manifest = json.load(stream)
-assert manifest["format-version"] == 6
-assert manifest["schema"] == "oliphaunt.wasix-postmaster.sealed-aot.v5"
-assert manifest["core-profile"] == "release-o3"
-with open(os.path.join(root, "guest-build.receipt"), "rb") as stream:
-    guest_build_receipt = stream.read()
-assert manifest["guest-build-recipe-sha256"] == hashlib.sha256(
-    guest_build_receipt
-).hexdigest()
-assert manifest["entrypoint"] == "runtime:postgres"
-linear_profile = manifest["linear-memory-profile"]
-assert linear_profile == {
-    "id": "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1",
-    "address-width": "wasm32",
-    "supported-host-pointer-width": "u64",
-    "maximum-pages": 4096,
-    "maximum-bytes": 268435456,
-    "static-bound-pages": 65536,
-    "static-offset-guard-bytes": 2147483648,
-    "static-access-lowering": "wasmer-llvm-unchecked-reservation-and-guard-v1",
-    "install-receipt-path": "share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json",
-    "install-receipt-sha256": hashlib.sha256(
-        open(
-            os.path.join(
-                root,
-                "share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json",
-            ),
-            "rb",
-        ).read()
-    ).hexdigest(),
-}
-with open(os.path.join(root, "postmaster-executor.receipt"), encoding="utf-8") as stream:
-    executor_receipt = dict(line.rstrip("\n").split("=", 1) for line in stream)
-assert executor_receipt["schema"] == "oliphaunt.wasix-postmaster.postmaster-executor-build.v3"
-assert executor_receipt["linear_memory_profile_id"] == linear_profile["id"]
-assert executor_receipt["executor_role"] == "postmaster-product"
-assert executor_receipt["executor_binary_sha256"] == manifest["executor-sha256"]
-with open(side_module_policy, encoding="utf-8") as stream:
-    side_modules = {
-        line.split("\t", 1)[0]
-        for line in stream
-        if line.strip() and not line.startswith("#")
-    }
-assert len(manifest["artifacts"]) == len(side_modules) + 2
-assert {
-    item["module-path"]
-    for item in manifest["artifacts"]
-    if item["kind"] == "side-module"
-} == side_modules
-assert {tuple(item["exec-aliases"]) for item in manifest["artifacts"] if item["kind"] == "executable"} == {
-    ("/bin/initdb",),
-    ("/bin/postgres",),
-}
-for artifact in manifest["artifacts"]:
-    assert "preinitialized-memory" not in artifact
-with open(os.path.join(root, "payload.files"), encoding="utf-8") as stream:
-    assert stream.readline().strip() == "schema=oliphaunt.wasix-postmaster.payload-files.v1"
-    listed_payloads = set()
-    for line in stream:
-        digest, size, relative = line.rstrip("\n").split("\t")
-        assert relative not in listed_payloads
-        listed_payloads.add(relative)
-        path = os.path.join(root, relative)
-        assert os.path.getsize(path) == int(size)
-        with open(path, "rb") as payload:
-            assert hashlib.sha256(payload.read()).hexdigest() == digest
-expected_payloads = set()
-for current, dirs, files in os.walk(root):
-    dirs.sort()
-    files.sort()
-    for name in files:
-        relative = os.path.relpath(os.path.join(current, name), root)
-        if relative != "payload.files":
-            expected_payloads.add(relative)
-assert listed_payloads == expected_payloads
-assert not any(path.startswith(".") for path in listed_payloads)
-PY
-
-python3 - "$FAKE_WASMER_VALIDATION_LOG" <<'PY'
-import json
-import os
-import sys
-
-with open(sys.argv[1], encoding="utf-8") as stream:
-    records = [json.loads(line) for line in stream]
-assert [record["program"] for record in records] == ["postgres", "initdb"]
-assert records[0]["arguments"] == ["--version"]
-assert records[1]["arguments"] == [
-    "-D",
-    "/pgdata",
-    "-A",
-    "trust",
-    "--no-locale",
-    "--encoding=UTF8",
-    "--no-instructions",
-]
-for record in records:
-    guest_volumes = {}
-    for volume in record["volumes"]:
-        host, guest = volume.rsplit(":", 1)
-        assert guest not in guest_volumes
-        guest_volumes[guest] = host
-    carrier_root = next(host for guest, host in guest_volumes.items() if guest == host)
-    assert guest_volumes["/lib"] == os.path.join(carrier_root, "lib")
-    assert guest_volumes["/share"] == os.path.join(carrier_root, "share")
-    for guest in ("/pgdata", "/dev/shm"):
-        assert not os.path.exists(guest_volumes[guest]), (guest, guest_volumes[guest])
-PY
-
-if find "$test_root" -maxdepth 1 -type d \
-  \( -name '.carrier.tmp.*' -o -name '.carrier.validate.*' \) \
-  -print -quit | grep -q .
-then
-  printf 'carrier builder left staging or validation state after success\n' >&2
-  exit 1
-fi
-
-manifest_source_fingerprint="$(python3 - "$output/manifest.json" <<'PY'
-import json
-import sys
-with open(sys.argv[1], encoding="utf-8") as stream:
-    print(json.load(stream)["source-fingerprint"])
-PY
-)"
-manifest_producer_recipe="$(python3 - "$output/manifest.json" <<'PY'
-import json
-import sys
-with open(sys.argv[1], encoding="utf-8") as stream:
-    print(json.load(stream)["producer-recipe-sha256"])
-PY
-)"
-compiler_config="$(fresh_wasmer_compiler_cache_bucket \
-  llvm aggressive "$FRESH_WASMER_ARTIFACT_ABI_VERSION")"
-expected_producer_recipe="$(fresh_aot_producer_recipe_sha256 \
-  "$output/wasmer-build.receipt" \
-  "$output/postmaster-executor.receipt" \
-  "$compiler_config" \
-  "$target_triple" \
-  "$manifest_source_fingerprint")"
-[ "$manifest_producer_recipe" = "$expected_producer_recipe" ] || {
-  printf 'manifest AOT producer recipe is not reproducible from packaged inputs\n' >&2
-  exit 1
-}
-recipe_fixture="$test_root/producer-recipe-fixture"
-mkdir -p "$recipe_fixture/bin" "$recipe_fixture/lib"
-cp "$project_root/bin/precompile-wasix-core.sh" "$recipe_fixture/bin/"
-cp "$project_root/bin/build-sealed-headless-carrier.sh" "$recipe_fixture/bin/"
-cp "$project_root/lib/sealed-carrier.sh" "$recipe_fixture/lib/"
-cp "$project_root/lib/verify-sealed-carrier.py" "$recipe_fixture/lib/"
-cp "$project_root/lib/sealed_export_chain.py" "$recipe_fixture/lib/"
-fixture_producer_recipe="$(FRESH_ROOT="$recipe_fixture" \
-  fresh_aot_producer_recipe_sha256 \
-    "$output/wasmer-build.receipt" \
-    "$output/postmaster-executor.receipt" \
-    "$compiler_config" \
-    "$target_triple" \
-    "$manifest_source_fingerprint")"
-[ "$manifest_producer_recipe" = "$fixture_producer_recipe" ] || {
-  printf 'AOT producer recipe depends on paths outside its declared inputs\n' >&2
-  exit 1
-}
-printf '# verifier policy mutation\n' >>"$recipe_fixture/lib/verify-sealed-carrier.py"
-[ "$manifest_producer_recipe" != "$(FRESH_ROOT="$recipe_fixture" \
-  fresh_aot_producer_recipe_sha256 \
-    "$output/wasmer-build.receipt" \
-    "$output/postmaster-executor.receipt" \
-    "$compiler_config" \
-    "$target_triple" \
-    "$manifest_source_fingerprint")" ] || {
-  printf 'AOT producer recipe does not bind the carrier verifier policy\n' >&2
-  exit 1
-}
-cp "$project_root/lib/verify-sealed-carrier.py" "$recipe_fixture/lib/"
-printf '# export chain policy mutation\n' >>"$recipe_fixture/lib/sealed_export_chain.py"
-[ "$manifest_producer_recipe" != "$(FRESH_ROOT="$recipe_fixture" \
-  fresh_aot_producer_recipe_sha256 \
-    "$output/wasmer-build.receipt" \
-    "$output/postmaster-executor.receipt" \
-    "$compiler_config" \
-    "$target_triple" \
-    "$manifest_source_fingerprint")" ] || {
-  printf 'AOT producer recipe does not bind sealed export lineage policy\n' >&2
-  exit 1
-}
-[ "$manifest_producer_recipe" != "$(fresh_manifest_value "$output/wasmer-build.receipt" build_recipe_sha256)" ] || {
-  printf 'AOT producer recipe collapsed to the runtime build recipe\n' >&2
-  exit 1
-}
-different_source_fingerprint="$(printf different-source | fresh_sha256_stream)"
-[ "$manifest_producer_recipe" != "$(fresh_aot_producer_recipe_sha256 \
-  "$output/wasmer-build.receipt" \
-  "$output/postmaster-executor.receipt" \
-  "$compiler_config" \
-  "$target_triple" \
-  "$different_source_fingerprint")" ] || {
-  printf 'AOT producer recipe does not bind the guest source fingerprint\n' >&2
-  exit 1
-}
-sed 's/^rustc_version=.*/rustc_version=alternate-test-rustc/' \
-  "$output/wasmer-build.receipt" >"$test_root/alternate-wasmer-build.receipt"
-[ "$manifest_producer_recipe" != "$(fresh_aot_producer_recipe_sha256 \
-  "$test_root/alternate-wasmer-build.receipt" \
-  "$output/postmaster-executor.receipt" \
-  "$compiler_config" \
-  "$target_triple" \
-  "$manifest_source_fingerprint")" ] || {
-  printf 'AOT producer recipe does not bind the canonical build receipt\n' >&2
-  exit 1
-}
-[ "$manifest_producer_recipe" != "$(fresh_aot_producer_recipe_sha256 \
-  "$output/wasmer-build.receipt" \
-  "$output/postmaster-executor.receipt" \
-  "${compiler_config}-different" \
-  "$target_triple" \
-  "$manifest_source_fingerprint")" ] || {
-  printf 'AOT producer recipe does not bind the compiler configuration\n' >&2
-  exit 1
-}
-[ "$manifest_producer_recipe" != "$(WASMER_STACK_SIZE=16777216 \
-  fresh_aot_producer_recipe_sha256 \
-    "$output/wasmer-build.receipt" \
-    "$output/postmaster-executor.receipt" \
-    "$compiler_config" \
-    "$target_triple" \
-    "$manifest_source_fingerprint")" ] || {
-  printf 'AOT producer recipe does not bind the runtime stack size\n' >&2
-  exit 1
-}
-if fresh_aot_producer_recipe_sha256 \
-  "$output/wasmer-build.receipt" \
-  "$output/postmaster-executor.receipt" \
-  "$compiler_config" \
-  different-target \
-  "$manifest_source_fingerprint" >/dev/null 2>&1
-then
-  printf 'AOT producer recipe accepted a target inconsistent with its receipt\n' >&2
-  exit 1
-fi
-
-if "$project_root/bin/build-sealed-headless-carrier.sh" \
-  --output "$output" \
-  --cache-bucket "$cache_bucket" >/dev/null 2>&1
-then
-  printf 'carrier builder replaced an existing output unexpectedly\n' >&2
-  exit 1
-fi
-
-"$project_root/bin/verify-sealed-headless-carrier.sh" "$output" >/dev/null
-[ "$(python3 "$project_root/lib/verify-sealed-carrier.py" executor-selection "$output")" = \
-  $'postmaster-product\tpostmaster-executor.receipt\t'"$(fresh_wasmer_bin_hash "$output/postmaster-executor.receipt")"$'\t'"$(fresh_wasmer_bin_hash "$output/bin/wasmer-headless")" ]
-
-# The implicit publication path is derived from the finished exact payload
-# inventory, not merely from the runtime ABI.  This keeps distinct PostgreSQL
-# build profiles from racing for or aliasing one default directory.
-default_build_log="$test_root/default-build.log"
-"$project_root/bin/build-sealed-headless-carrier.sh" \
-  --cache-bucket "$cache_bucket" >"$default_build_log"
-default_output="$(sed -n 's/^built sealed headless WASIX PostgreSQL carrier: //p' "$default_build_log")"
-[ -n "$default_output" ] && [ -d "$default_output" ] || {
-  printf 'default carrier output was not published\n' >&2
-  exit 1
-}
-default_payload_sha256="$(fresh_wasmer_bin_hash "$default_output/payload.files")"
-expected_default_output="$FRESH_WORK_ROOT/carriers/wasix-postmaster-$POSTGRES_VERSION-${runtime_abi_id:0:16}-$default_payload_sha256"
-[ "$default_output" = "$expected_default_output" ] || {
-  printf 'default carrier output is not content-addressed: expected %s, got %s\n' \
-    "$expected_default_output" "$default_output" >&2
-  exit 1
-}
-grep -Fx "payload inventory SHA-256: $default_payload_sha256" "$default_build_log" >/dev/null
-"$project_root/bin/verify-sealed-headless-carrier.sh" "$default_output" >/dev/null
-[ "$(fresh_select_current_sealed_carrier)" = "$default_output" ] || {
-  printf 'current carrier selection did not resolve the receipt-bound output\n' >&2
-  exit 1
-}
-if "$project_root/bin/build-sealed-headless-carrier.sh" \
-  --cache-bucket "$cache_bucket" >/dev/null 2>&1
-then
-  printf 'default carrier builder replaced an existing content identity\n' >&2
-  exit 1
-fi
-
-expect_verifier_failure() {
-  local label="$1"
-  local carrier="$2"
-
-  if "$project_root/bin/verify-sealed-headless-carrier.sh" "$carrier" \
-    >"$test_root/$label.stdout" 2>"$test_root/$label.stderr"
-  then
-    printf 'sealed carrier verifier accepted %s\n' "$label" >&2
-    exit 1
-  fi
-}
-
-reindex_carrier() {
-  local carrier="$1"
-
-  chmod u+w "$carrier/payload.files"
-  python3 - "$carrier" <<'PY'
-import hashlib
-import os
-import stat
-import sys
-
-root = os.path.realpath(sys.argv[1])
-inventory = os.path.join(root, "payload.files")
-rows = []
-for current, dirs, files in os.walk(root, followlinks=False):
-    dirs.sort()
-    files.sort()
-    for name in files:
-        path = os.path.join(current, name)
-        if os.path.realpath(path) == inventory:
-            continue
-        info = os.lstat(path)
-        if not stat.S_ISREG(info.st_mode):
-            continue
-        digest = hashlib.sha256()
-        with open(path, "rb", buffering=0) as stream:
-            for chunk in iter(lambda: stream.read(1024 * 1024), b""):
-                digest.update(chunk)
-        rows.append((os.path.relpath(path, root), info.st_size, digest.hexdigest()))
-with open(inventory, "w", encoding="utf-8", newline="\n") as output:
-    output.write("schema=oliphaunt.wasix-postmaster.payload-files.v1\n")
-    for relative, size, digest in sorted(rows):
-        output.write(f"{digest}\t{size}\t{relative}\n")
-PY
-  chmod 0444 "$carrier/payload.files"
-}
-
-legacy_manifest="$test_root/verifier-legacy-manifest-v4"
-cp -a "$output" "$legacy_manifest"
-chmod u+w "$legacy_manifest/manifest.json"
-python3 - "$legacy_manifest/manifest.json" <<'PY'
-import json
-import sys
-
-path = sys.argv[1]
-with open(path, encoding="utf-8") as stream:
-    manifest = json.load(stream)
-manifest["schema"] = "oliphaunt.wasix-postmaster.sealed-aot.v4"
-manifest["format-version"] = 5
-with open(path, "w", encoding="utf-8", newline="\n") as stream:
-    json.dump(manifest, stream, ensure_ascii=False, indent=2)
-    stream.write("\n")
-PY
-chmod 0444 "$legacy_manifest/manifest.json"
-reindex_carrier "$legacy_manifest"
-expect_verifier_failure legacy-manifest-v4 "$legacy_manifest"
-
-legacy_guest="$test_root/verifier-legacy-guest-v4"
-cp -a "$output" "$legacy_guest"
-chmod u+w "$legacy_guest/guest-build.receipt" "$legacy_guest/manifest.json"
-sed 's/^schema=oliphaunt.wasix-postmaster.guest-build.v5$/schema=oliphaunt.wasix-postmaster.guest-build.v4/' \
-  "$output/guest-build.receipt" >"$legacy_guest/guest-build.receipt"
-python3 - "$legacy_guest" <<'PY'
-import hashlib
-import json
-import os
-import sys
-
-root = sys.argv[1]
-guest = os.path.join(root, "guest-build.receipt")
-manifest_path = os.path.join(root, "manifest.json")
-with open(guest, "rb") as stream:
-    digest = hashlib.sha256(stream.read()).hexdigest()
-with open(manifest_path, encoding="utf-8") as stream:
-    manifest = json.load(stream)
-manifest["guest-build-recipe-sha256"] = digest
-with open(manifest_path, "w", encoding="utf-8", newline="\n") as stream:
-    json.dump(manifest, stream, ensure_ascii=False, indent=2)
-    stream.write("\n")
-PY
-chmod 0444 "$legacy_guest/guest-build.receipt" "$legacy_guest/manifest.json"
-reindex_carrier "$legacy_guest"
-expect_verifier_failure legacy-guest-v4 "$legacy_guest"
-
-tampered="$test_root/verifier-tampered"
-cp -a "$output" "$tampered"
-chmod u+w "$tampered/bin/postgres"
-printf 'tampered\n' >>"$tampered/bin/postgres"
-chmod 0555 "$tampered/bin/postgres"
-expect_verifier_failure tampered-payload "$tampered"
-
-missing="$test_root/verifier-missing"
-cp -a "$output" "$missing"
-chmod u+w "$missing/share/postgresql"
-mv "$missing/share/postgresql/postgresql.conf.sample" \
-  "$test_root/missing-postgresql.conf.sample"
-chmod 0555 "$missing/share/postgresql"
-expect_verifier_failure missing-payload "$missing"
-
-unexpected="$test_root/verifier-unexpected"
-cp -a "$output" "$unexpected"
-chmod u+w "$unexpected"
-printf 'unexpected\n' >"$unexpected/unexpected.txt"
-chmod 0444 "$unexpected/unexpected.txt"
-chmod 0555 "$unexpected"
-expect_verifier_failure unexpected-payload "$unexpected"
-
-symlinked="$test_root/verifier-symlink"
-cp -a "$output" "$symlinked"
-chmod u+w "$symlinked"
-ln -s bin/postgres "$symlinked/postgres-link"
-chmod 0555 "$symlinked"
-expect_verifier_failure symlink-entry "$symlinked"
-
-special="$test_root/verifier-special"
-cp -a "$output" "$special"
-chmod u+w "$special"
-mkfifo "$special/unexpected.fifo"
-chmod 0555 "$special"
-expect_verifier_failure special-entry "$special"
-
-empty_directory="$test_root/verifier-empty-directory"
-cp -a "$output" "$empty_directory"
-chmod u+w "$empty_directory"
-mkdir "$empty_directory/unrepresented-directory"
-chmod 0555 "$empty_directory/unrepresented-directory" "$empty_directory"
-expect_verifier_failure unrepresented-directory "$empty_directory"
-
-writable_file="$test_root/verifier-writable-file"
-cp -a "$output" "$writable_file"
-chmod u+w "$writable_file/bin/postgres"
-expect_verifier_failure writable-file "$writable_file"
-
-writable_directory="$test_root/verifier-writable-directory"
-cp -a "$output" "$writable_directory"
-chmod u+w "$writable_directory/aot"
-expect_verifier_failure writable-directory "$writable_directory"
-
-unsafe_inventory="$test_root/verifier-unsafe-inventory"
-cp -a "$output" "$unsafe_inventory"
-chmod u+w "$unsafe_inventory/payload.files"
-printf '%064d\t0\t../outside\n' 0 >>"$unsafe_inventory/payload.files"
-chmod 0444 "$unsafe_inventory/payload.files"
-expect_verifier_failure unsafe-inventory-path "$unsafe_inventory"
-
-wrong_executor="$test_root/verifier-wrong-executor"
-cp -a "$output" "$wrong_executor"
-chmod u+w "$wrong_executor/bin/wasmer-headless"
-printf 'different executor\n' >>"$wrong_executor/bin/wasmer-headless"
-chmod 0555 "$wrong_executor/bin/wasmer-headless"
-reindex_carrier "$wrong_executor"
-expect_verifier_failure headless-receipt-identity "$wrong_executor"
-
-wrong_manifest="$test_root/verifier-wrong-manifest"
-cp -a "$output" "$wrong_manifest"
-chmod u+w "$wrong_manifest/manifest.json"
-python3 - "$wrong_manifest/manifest.json" <<'PY'
-import json
-import sys
-
-path = sys.argv[1]
-with open(path, encoding="utf-8") as stream:
-    manifest = json.load(stream)
-manifest["executor-sha256"] = "0" * 64
-with open(path, "w", encoding="utf-8", newline="\n") as stream:
-    json.dump(manifest, stream, ensure_ascii=False, indent=2)
-    stream.write("\n")
-PY
-chmod 0444 "$wrong_manifest/manifest.json"
-reindex_carrier "$wrong_manifest"
-expect_verifier_failure manifest-executor-identity "$wrong_manifest"
-
-wrong_receipt="$test_root/verifier-wrong-receipt"
-cp -a "$output" "$wrong_receipt"
-chmod u+w "$wrong_receipt/wasmer-build.receipt"
-sed 's/^wasmer_headless_binary_sha256=.*/wasmer_headless_binary_sha256=0000000000000000000000000000000000000000000000000000000000000000/' \
-  "$output/wasmer-build.receipt" >"$wrong_receipt/wasmer-build.receipt"
-chmod 0444 "$wrong_receipt/wasmer-build.receipt"
-reindex_carrier "$wrong_receipt"
-expect_verifier_failure receipt-headless-identity "$wrong_receipt"
-
-wrong_product_receipt="$test_root/verifier-wrong-product-receipt"
-cp -a "$output" "$wrong_product_receipt"
-chmod u+w "$wrong_product_receipt/postmaster-executor.receipt"
-sed 's/^executor_binary_sha256=.*/executor_binary_sha256=0000000000000000000000000000000000000000000000000000000000000000/' \
-  "$output/postmaster-executor.receipt" \
-  >"$wrong_product_receipt/postmaster-executor.receipt"
-chmod 0444 "$wrong_product_receipt/postmaster-executor.receipt"
-reindex_carrier "$wrong_product_receipt"
-expect_verifier_failure product-receipt-executor-identity "$wrong_product_receipt"
-
-missing_product_receipt="$test_root/verifier-missing-product-receipt"
-cp -a "$output" "$missing_product_receipt"
-chmod u+w "$missing_product_receipt"
-mv "$missing_product_receipt/postmaster-executor.receipt" \
-  "$test_root/missing-postmaster-executor.receipt"
-chmod 0555 "$missing_product_receipt"
-reindex_carrier "$missing_product_receipt"
-expect_verifier_failure missing-product-role-sidecar "$missing_product_receipt"
-
-printf 'sealed headless carrier packaging tests passed\n'
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.backend.test.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.backend.test.sh
deleted file mode 100755
index b9a469be5..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.backend.test.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-builder="$project_root/bin/build-wasix-core.sh"
-
-for unsupported in copied-fork fork typo; do
-  set +e
-  output="$(WASIX_CORE_CHILD_BACKEND="$unsupported" "$builder" --configure-only 2>&1)"
-  status=$?
-  set -e
-
-  [ "$status" -eq 2 ] || {
-    printf 'unsupported backend %s exited %s instead of 2\n' \
-      "$unsupported" "$status" >&2
-    exit 1
-  }
-  [ "$output" = "unsupported WASIX_CORE_CHILD_BACKEND=$unsupported; expected exec" ] || {
-    printf 'unexpected unsupported-backend diagnostic for %s: %s\n' \
-      "$unsupported" "$output" >&2
-    exit 1
-  }
-done
-
-test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-build-identity.XXXXXX")"
-trap 'rm -rf -- "$test_root"' EXIT
-signature_function="$test_root/compute-source-signature.sh"
-sed -n '/^compute_source_signature() {$/,/^}$/p' \
-  "$builder" >"$signature_function"
-[ -s "$signature_function" ] || {
-  echo 'could not extract compute_source_signature from builder' >&2
-  exit 1
-}
-# shellcheck source=/dev/null
-source "$signature_function"
-
-# Keep every source input fixed while varying only the immutable builder ID.
-# File hashing is replaced with stable fixture records; the final pipeline hash
-# still processes the complete framed source-signature stream.
-shasum() {
-  [ "${1-}" = -a ] && [ "${2-}" = 256 ] || return 2
-  shift 2
-  if [ "$#" -gt 0 ]; then
-    local path
-    for path in "$@"; do
-      printf '%064d  %s\n' 0 "$path"
-    done
-    return
-  fi
-  python3 -c 'import hashlib, sys; print(hashlib.sha256(sys.stdin.buffer.read()).hexdigest(), " -")'
-}
-
-postgres_worktree_signature="$test_root/postgres-worktree.signature"
-printf 'schema=fixture\nworktree_state_sha256=%064d\n' 0 \
-  >"$postgres_worktree_signature"
-FRESH_ROOT="$project_root"
-durable_publication="$project_root/lib/durable_publication.py"
-WASIXCC_SYSROOT_PREFIX=""
-WASIXCC_SYSROOT=""
-WASIX_CORE_PROFILE=release-o3
-wasix_core_child_backend=exec
-wasix_core_latch_state_contract=packed-atomic-v1
-wasix_core_cflags='-O3 -g0 -flto=thin'
-wasix_core_ldflags='-flto=thin'
-wasixcc_run_wasm_opt=yes
-wasixcc_wasm_opt_flags='--converge --strip-debug --strip-producers'
-wasixcc_wasm_opt_suppress_default=yes
-expected_atomic_fence_total=1111
-expected_final_atomic_fence_total=995
-FRESH_LINEAR_MEMORY_PROFILE_ID=fixture-linear-memory
-FRESH_LINEAR_MEMORY_MAXIMUM_PAGES=4096
-FRESH_LINEAR_MEMORY_STATIC_BOUND_PAGES=65536
-FRESH_LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES=2147483648
-worktree_state="$(printf '1%.0s' {1..64})"
-first_image_id="sha256:$(printf 'a%.0s' {1..64})"
-second_image_id="sha256:$(printf 'b%.0s' {1..64})"
-first_signature="$(compute_source_signature "$worktree_state" "$first_image_id")"
-replayed_signature="$(compute_source_signature "$worktree_state" "$first_image_id")"
-second_signature="$(compute_source_signature "$worktree_state" "$second_image_id")"
-case "$first_signature$replayed_signature$second_signature" in
-  *[!0-9a-f]*|'') echo 'source signature fixture did not emit canonical SHA-256 values' >&2; exit 1 ;;
-esac
-[ "${#first_signature}" -eq 64 ] && \
-  [ "${#replayed_signature}" -eq 64 ] && \
-  [ "${#second_signature}" -eq 64 ] || {
-  echo 'source signature fixture emitted a non-SHA-256 length' >&2
-  exit 1
-}
-[ "$first_signature" = "$replayed_signature" ] || {
-  echo 'identical immutable builder IDs produced different source signatures' >&2
-  exit 1
-}
-[ "$first_signature" != "$second_signature" ] || {
-  echo 'an immutable builder image ID-only change did not invalidate the source signature' >&2
-  exit 1
-}
-
-printf 'WASIX core backend validation tests passed\n'
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.sh
deleted file mode 100755
index 85d94c717..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.sh
+++ /dev/null
@@ -1,786 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/common.sh"
-source "$FRESH_ROOT/lib/wasix-build-lock.sh"
-
-configure_only=0
-force_clean=0
-portable_inputs="${OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS:-0}"
-case "$portable_inputs" in
-  0|1) ;;
-  *)
-    echo 'OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS must be 0 or 1' >&2
-    exit 2
-    ;;
-esac
-while [ "$#" -gt 0 ]; do
-  case "$1" in
-    --configure-only)
-      configure_only=1
-      ;;
-    --clean)
-      force_clean=1
-      ;;
-    *)
-      printf 'unknown argument: %s\n' "$1" >&2
-      exit 2
-      ;;
-  esac
-  shift
-done
-
-case "${WASIX_CORE_CHILD_BACKEND:-exec}" in
-  exec|exec-backend)
-    wasix_core_child_backend="exec"
-    ;;
-  *)
-    printf 'unsupported WASIX_CORE_CHILD_BACKEND=%s; expected exec\n' \
-      "$WASIX_CORE_CHILD_BACKEND" >&2
-    exit 2
-    ;;
-esac
-
-if [ "$portable_inputs" -eq 1 ]; then
-  [ "$force_clean" -eq 0 ] || {
-    echo '--clean is incompatible with portable PostgreSQL build inputs' >&2
-    exit 2
-  }
-  guest_receipt="$WASIX_INSTALL_DIR/guest-build.receipt"
-  [ -f "$guest_receipt" ] && [ ! -L "$guest_receipt" ] || {
-    printf 'missing portable PostgreSQL guest receipt: %s\n' "$guest_receipt" >&2
-    exit 2
-  }
-  expected_guest_identity="$(
-    fresh_manifest_value "$guest_receipt" installed_closure_sha256
-  )"
-  actual_guest_identity="$(
-    python3 "$FRESH_ROOT/lib/guest_build_provenance.py" identity \
-      "$WASIX_INSTALL_DIR"
-  )"
-  [ "$actual_guest_identity" = "$expected_guest_identity" ] || {
-    echo 'portable PostgreSQL guest differs from its build receipt' >&2
-    exit 2
-  }
-  [ "$(fresh_manifest_value "$guest_receipt" core_profile)" = \
-    "$WASIX_CORE_PROFILE" ] || {
-    echo 'portable PostgreSQL guest profile differs from the selected product profile' >&2
-    exit 2
-  }
-  printf 'validated portable PostgreSQL guest: %s\n' "$WASIX_INSTALL_DIR"
-  exit 0
-fi
-
-managed_work_probe="$FRESH_WORK_ROOT/.managed-path-boundary"
-fresh_require_managed_generated_path "$managed_work_probe" FRESH_WORK_ROOT
-fresh_require_managed_generated_path "$WASIX_BUILD_DIR" WASIX_BUILD_DIR
-fresh_require_managed_generated_path "$WASIX_INSTALL_DIR" WASIX_INSTALL_DIR
-fresh_require_managed_generated_path "$REPORT_DIR" REPORT_DIR
-fresh_require_managed_generated_path "$RUN_DIR" RUN_DIR
-
-fresh_ensure_dirs
-fresh_require_command git
-fresh_require_command python3
-
-durable_publication="$FRESH_ROOT/lib/durable_publication.py"
-[ -f "$durable_publication" ] && [ ! -L "$durable_publication" ] || {
-  printf 'missing regular durable-publication helper: %s\n' "$durable_publication" >&2
-  exit 2
-}
-
-if [ -n "${FRESH_PINNED_WASIX_INSTALL_DIR:-}" ] && [ "$WASIX_INSTALL_DIR" = "$FRESH_PINNED_WASIX_INSTALL_DIR" ] && [ "${FRESH_ALLOW_PINNED_INSTALL_WRITE:-0}" != "1" ]; then
-  {
-    printf 'refusing to build into pinned WASIX install: %s\n' "$FRESH_PINNED_WASIX_INSTALL_DIR"
-    printf 'Unset FRESH_PINNED_WASIX_INSTALL_DIR or set FRESH_ALLOW_PINNED_INSTALL_WRITE=1 if you are intentionally replacing the pin.\n'
-  } >&2
-  exit 2
-fi
-
-# Serialize the complete producer, including configuration, sealing, and
-# receipt publication.  Every profile and wasix-make.sh acquires this same
-# product-wide lock because the default profiles share one mutable source tree.
-fresh_lock_wasix_core_build "$WASIX_INSTALL_DIR"
-
-jobs="${JOBS:-$(fresh_jobs)}"
-docker_bin="$(fresh_docker_bin)"
-fresh_resolve_wasix_core_profile
-wasix_core_cflags="$FRESH_WASIX_CORE_EFFECTIVE_CFLAGS"
-wasix_core_ldflags="$FRESH_WASIX_CORE_EFFECTIVE_LDFLAGS"
-wasix_core_latch_state_contract="packed-atomic-v1"
-wasixcc_run_wasm_opt="$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT"
-wasixcc_wasm_opt_flags="$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_FLAGS"
-wasixcc_wasm_opt_suppress_default="$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT"
-expected_atomic_fence_total="$FRESH_WASIX_CORE_EXPECTED_ATOMIC_FENCE_TOTAL"
-expected_final_atomic_fence_total="$FRESH_WASIX_CORE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL"
-
-wasix_core_cflags="$wasix_core_cflags -DPG_WASIX_ATOMIC_LATCH_STATE=1"
-
-"$FRESH_ROOT/bin/apply-wasix-core-overlay.sh" >/dev/null
-postgres_worktree_signature="$WASIX_SRC_DIR/.fresh-wasix-core-signature"
-postgres_worktree_state="$(
-  fresh_git_worktree_state_sha256 "$WASIX_SRC_DIR" ".fresh-wasix-core-signature"
-)" || exit
-fresh_require_manifest_value "$postgres_worktree_signature" \
-  worktree_state_sha256 "$postgres_worktree_state" || exit
-
-compute_source_signature() {
-  local worktree_state="$1"
-  local builder_image_id="$2"
-
-  {
-    cat "$postgres_worktree_signature"
-    shasum -a 256 "$0"
-    shasum -a 256 \
-      "$FRESH_ROOT/bin/apply-wasix-core-overlay.sh" \
-      "$FRESH_ROOT/lib/common.sh" \
-      "$FRESH_ROOT/lib/wasix-build-lock.sh" \
-      "$FRESH_ROOT/runtime/bin/verify-postmaster-wasm-import.py" \
-      "$FRESH_ROOT/runtime/bin/verify-postmaster-concurrency-contract.py" \
-      "$FRESH_ROOT/bin/seal-wasix-core-exports.sh" \
-      "$FRESH_ROOT/bin/seal-wasix-linear-memory.sh" \
-      "$FRESH_ROOT/lib/guest_build_provenance.py" \
-      "$FRESH_ROOT/lib/linear_memory_transaction.py" \
-      "$FRESH_ROOT/lib/sealed_export_chain.py" \
-      "$FRESH_ROOT/runtime/policies/sealed-main-runtime-exports.v1.txt" \
-      "$FRESH_ROOT/runtime/policies/sealed-main-dlsym-exports.v1.txt" \
-      "$FRESH_ROOT/runtime/policies/sealed-side-modules.v1.tsv" \
-      "$FRESH_ROOT/tools/sealed-export-closure/Cargo.toml" \
-      "$FRESH_ROOT/tools/sealed-export-closure/Cargo.lock" \
-      "$FRESH_ROOT/tools/sealed-export-closure/src/main.rs" \
-      "$durable_publication"
-    printf 'WASIXCC_SYSROOT_PREFIX=%s\n' "${WASIXCC_SYSROOT_PREFIX:-}"
-    printf 'WASIXCC_SYSROOT=%s\n' "${WASIXCC_SYSROOT:-}"
-    if [ -n "${WASIXCC_SYSROOT_PREFIX:-}" ] && [ -f "$WASIXCC_SYSROOT_PREFIX/.fresh-sysroot-signature" ]; then
-      printf 'WASIXCC_SYSROOT_PREFIX_SIGNATURE='
-      cat "$WASIXCC_SYSROOT_PREFIX/.fresh-sysroot-signature"
-    fi
-    if [ -n "${WASIXCC_SYSROOT:-}" ] && [ -f "$WASIXCC_SYSROOT/.fresh-sysroot-signature" ]; then
-      printf 'WASIXCC_SYSROOT_SIGNATURE='
-      cat "$WASIXCC_SYSROOT/.fresh-sysroot-signature"
-    fi
-    printf 'WASIX_CORE_PROFILE=%s\n' "$WASIX_CORE_PROFILE"
-    printf 'WASIX_CORE_CHILD_BACKEND=%s\n' "$wasix_core_child_backend"
-    printf 'WASIX_CORE_LATCH_STATE_CONTRACT=%s\n' "$wasix_core_latch_state_contract"
-    printf 'WASIX_CORE_CFLAGS=%s\n' "$wasix_core_cflags"
-    printf 'WASIX_CORE_LDFLAGS=%s\n' "$wasix_core_ldflags"
-    printf 'WASIXCC_RUN_WASM_OPT=%s\n' "$wasixcc_run_wasm_opt"
-    printf 'WASIXCC_WASM_OPT_FLAGS=%s\n' "$wasixcc_wasm_opt_flags"
-    printf 'WASIXCC_WASM_OPT_SUPPRESS_DEFAULT=%s\n' "$wasixcc_wasm_opt_suppress_default"
-    printf 'EXPECTED_ATOMIC_FENCE_TOTAL=%s\n' "${expected_atomic_fence_total:-profile-unlocked}"
-    printf 'EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=%s\n' \
-      "${expected_final_atomic_fence_total:-profile-unlocked}"
-    printf 'LINEAR_MEMORY_PROFILE_ID=%s\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
-    printf 'LINEAR_MEMORY_MAXIMUM_PAGES=%s\n' "$FRESH_LINEAR_MEMORY_MAXIMUM_PAGES"
-    printf 'LINEAR_MEMORY_STATIC_BOUND_PAGES=%s\n' "$FRESH_LINEAR_MEMORY_STATIC_BOUND_PAGES"
-    printf 'LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES=%s\n' \
-      "$FRESH_LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES"
-    printf 'DOCKER_IMAGE_ID=%s\n' "$builder_image_id"
-    printf 'POSTGRES_WORKTREE_STATE=%s\n' "$worktree_state"
-  } | shasum -a 256 | awk '{print $1}'
-}
-
-build_signature_file="$WASIX_BUILD_DIR/.fresh-wasix-core-build-signature"
-fresh_require_managed_generated_path "$build_signature_file" wasix-core-build-signature
-
-require_build_inputs_unchanged() {
-  local context="$1"
-  local current_source_signature
-  local current_postgres_worktree_state
-
-  [ -f "$build_signature_file" ] && [ ! -L "$build_signature_file" ] &&
-    [ "$(cat "$build_signature_file")" = "$source_signature" ] || {
-    printf 'WASIX core build signature changed %s\n' "$context" >&2
-    return 125
-  }
-  current_postgres_worktree_state="$(
-    fresh_git_worktree_state_sha256 \
-      "$WASIX_SRC_DIR" ".fresh-wasix-core-signature"
-  )" || return 125
-  [ "$current_postgres_worktree_state" = "$postgres_worktree_state" ] || {
-    printf 'WASIX core PostgreSQL source changed %s\n' "$context" >&2
-    return 125
-  }
-  current_source_signature="$(
-    compute_source_signature "$current_postgres_worktree_state" "$docker_image_id"
-  )" || return 125
-  fresh_is_sha256 "$current_source_signature" || return 125
-  [ "$current_source_signature" = "$source_signature" ] || {
-    printf 'WASIX core build input changed %s\n' "$context" >&2
-    return 125
-  }
-}
-
-report="$REPORT_DIR/wasix-core-build.md"
-log="$REPORT_DIR/wasix-core-build.log"
-fresh_require_managed_generated_path "$report" wasix-core-build-report
-fresh_require_managed_generated_path "$log" wasix-core-build-log
-fresh_write_report_header "$report" "WASIX Core PostgreSQL Build"
-
-{
-  printf '## Scope\n\n'
-  printf -- '- Source: clean PostgreSQL `%s` plus `postgres/overlays/wasix-core` and the explicit patch series.\n' "$POSTGRES_TAG"
-  printf -- '- Template: `--with-template=wasix-core`.\n'
-  printf -- '- Build profile: `%s`.\n' "$WASIX_CORE_PROFILE"
-  printf -- '- Profile description: `%s`.\n' "$FRESH_WASIX_CORE_PROFILE_DESCRIPTION"
-  printf -- '- Child backend: `%s`.\n' "$wasix_core_child_backend"
-  printf -- '- Shared latch state contract: `%s`.\n' "$wasix_core_latch_state_contract"
-  printf -- '- Build lane: optimized core server/tools, PL/pgSQL, snowball dictionary, and core encoding conversion modules; no contrib or regression test binaries.\n'
-  printf -- '- wasixcc sysroot prefix: `%s`.\n' "${WASIXCC_SYSROOT_PREFIX:-}"
-  printf -- '- wasixcc sysroot: `%s`.\n' "${WASIXCC_SYSROOT:-}"
-  printf -- '- Build directory: `%s`.\n' "$WASIX_BUILD_DIR"
-  printf -- '- Install directory: `%s`.\n' "$WASIX_INSTALL_DIR"
-  printf -- '- CFLAGS: `%s`.\n' "$wasix_core_cflags"
-  printf -- '- LDFLAGS: `%s`.\n' "$wasix_core_ldflags"
-  printf -- '- wasixcc wasm-opt: `%s`.\n' "$wasixcc_run_wasm_opt"
-  printf -- '- wasixcc wasm-opt flags: `%s`.\n' "$wasixcc_wasm_opt_flags"
-  printf -- '- wasixcc suppress implicit wasm-opt defaults: `%s`.\n' "$wasixcc_wasm_opt_suppress_default"
-  printf -- '- Final-module critical fence contract: `SetLatch=2`, `ResetLatch=1`, and `WaitEventSetWait=1`.\n'
-  printf -- '- Main export policy: exact typed packaged-side closure, followed only by Binaryen module-element reachability DCE and final proof replay.\n'
-  printf -- '- Linear-memory ABI: `%s` (bounded 256 MiB guest maximum; 64-bit-host static lowering only).\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
-  printf -- '- Profile-locked pre-seal fence inventory: `%s`.\n' "${expected_atomic_fence_total:-critical-functions-only}"
-  printf -- '- Profile-locked final sealed-module fence inventory: `%s`.\n' \
-    "${expected_final_atomic_fence_total:-critical-functions-only}"
-  printf -- '- Configure wasm-opt: `no`.\n'
-  printf -- '- Largefile support: not disabled.\n'
-  printf -- '- Spinlocks: not disabled.\n'
-  printf -- '- Single-user compatibility macros: not used.\n\n'
-  printf '## Build Log\n\n'
-  printf 'See `%s`.\n' "$log"
-} >>"$report"
-
-mode="build"
-if [ "$configure_only" -eq 1 ]; then
-  mode="configure-only"
-fi
-
-: >"$log"
-if ! "$docker_bin" info >>"$log" 2>&1; then
-  {
-    printf '\n## Result\n\n'
-    printf -- '- Status: `blocked`\n'
-    printf -- '- Mode: `%s`\n' "$mode"
-    printf -- '- Blocker: Docker daemon is not reachable.\n\n'
-    printf 'Start Docker or run this script inside an environment with the pinned WASIX toolchain already available.\n'
-  } >>"$report"
-  printf 'blocked: Docker daemon is not reachable; see %s\n' "$log" >&2
-  exit 2
-fi
-
-set +e
-fresh_ensure_docker_image >>"$log" 2>&1
-image_status=$?
-set -e
-if [ "$image_status" -ne 0 ]; then
-  {
-    printf '\n## Result\n\n'
-    printf -- '- Status: `fail`\n'
-    printf -- '- Mode: `%s`\n' "$mode"
-    printf -- '- Exit code: `%s`\n' "$image_status"
-    printf -- '- Failure: could not prepare Docker image `%s`.\n' "$FRESH_WASIX_DOCKER_IMAGE"
-  } >>"$report"
-  printf 'WASIX Docker image preparation failed; see %s\n' "$log" >&2
-  exit "$image_status"
-fi
-docker_image_id="$(fresh_wasix_builder_image_id)" || {
-  printf 'WASIX Docker image identity lookup failed; see %s\n' "$log" >&2
-  exit 2
-}
-{
-  printf '\n## Immutable Builder\n\n'
-  printf -- '- Image reference: `%s`\n' "$FRESH_WASIX_DOCKER_IMAGE"
-  printf -- '- Image ID: `%s`\n' "$docker_image_id"
-} >>"$report"
-
-# The immutable builder is an input, not merely the transport used to execute
-# the build. Resolve it before deciding whether an existing build directory is
-# reusable, and bind that exact identity into every later provenance record.
-source_signature="$(
-  compute_source_signature "$postgres_worktree_state" "$docker_image_id"
-)"
-fresh_is_sha256 "$source_signature" || {
-  printf 'could not derive WASIX core source signature\n' >&2
-  exit 125
-}
-if [ "$force_clean" -eq 0 ] && [ -f "$build_signature_file" ] && \
-  [ "$(cat "$build_signature_file")" = "$source_signature" ]; then
-  mkdir -p "$WASIX_BUILD_DIR" "$WASIX_INSTALL_DIR"
-else
-  fresh_require_managed_generated_path "$WASIX_BUILD_DIR" WASIX_BUILD_DIR
-  fresh_require_managed_generated_path "$WASIX_INSTALL_DIR" WASIX_INSTALL_DIR
-  rm -rf "$WASIX_BUILD_DIR" "$WASIX_INSTALL_DIR"
-  mkdir -p "$WASIX_BUILD_DIR" "$WASIX_INSTALL_DIR"
-  printf '%s' "$source_signature" >"$build_signature_file"
-fi
-
-if ! DOCKER_IMAGE="$FRESH_WASIX_DOCKER_IMAGE" \
-  "$FRESH_ROOT/runtime/bin/validate-runtime-capabilities.sh" --validate-sysroot-only >>"$log" 2>&1; then
-  {
-    printf '\n## Result\n\n'
-    printf -- '- Status: `fail`\n'
-    printf -- '- Mode: `%s`\n' "$mode"
-    printf -- '- Failure: exact patched WASIX libc carrier validation failed.\n'
-  } >>"$report"
-  printf 'WASIX libc carrier validation failed; see %s\n' "$log" >&2
-  exit 2
-fi
-
-fresh_require_managed_generated_path "$WASIX_BUILD_DIR" WASIX_BUILD_DIR
-fresh_require_managed_generated_path "$WASIX_INSTALL_DIR" WASIX_INSTALL_DIR
-set +e
-printf '\n## docker run\n\n' >>"$log"
-docker_env=()
-if [ -n "${WASIXCC_SYSROOT_PREFIX:-}" ]; then
-  docker_env+=(-e "WASIXCC_SYSROOT_PREFIX=$(fresh_docker_path_for "$WASIXCC_SYSROOT_PREFIX")")
-fi
-if [ -n "${WASIXCC_SYSROOT:-}" ]; then
-  docker_env+=(-e "WASIXCC_SYSROOT=$(fresh_docker_path_for "$WASIXCC_SYSROOT")")
-fi
-"$docker_bin" run --rm \
-  -v "$REPO_ROOT:/work" \
-  -w /work \
-  -e JOBS="$jobs" \
-  -e PGSRC="${WASIX_SRC_DIR#$REPO_ROOT/}" \
-  -e BUILD_DIR="${WASIX_BUILD_DIR#$REPO_ROOT/}" \
-  -e INSTALL_DIR="${WASIX_INSTALL_DIR#$REPO_ROOT/}" \
-  -e MODE="$mode" \
-  -e WASIX_CORE_CFLAGS="$wasix_core_cflags" \
-  -e WASIX_CORE_LDFLAGS="$wasix_core_ldflags" \
-  -e WASIXCC_RUN_WASM_OPT="$wasixcc_run_wasm_opt" \
-  -e WASIXCC_WASM_OPT_FLAGS="$wasixcc_wasm_opt_flags" \
-  -e WASIXCC_WASM_OPT_SUPPRESS_DEFAULT="$wasixcc_wasm_opt_suppress_default" \
-  -e EXPECTED_ATOMIC_FENCE_TOTAL="$expected_atomic_fence_total" \
-  -e WASIX_CORE_LATCH_STATE_CONTRACT="$wasix_core_latch_state_contract" \
-  -e "HOST_UID=$(id -u)" \
-  -e "HOST_GID=$(id -g)" \
-  "${docker_env[@]}" \
-  "$docker_image_id" \
-  bash -lc '
-    set -euo pipefail
-    source ./src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh
-    cd /work
-
-    restore_host_ownership() {
-      local command_status="$?"
-      local ownership_failed=0
-      local output_path
-
-      trap - EXIT
-      for output_path in "/work/$BUILD_DIR" "/work/$INSTALL_DIR"; do
-        if [ -e "$output_path" ] && ! chown -R "$HOST_UID:$HOST_GID" "$output_path"; then
-          printf "failed to restore host ownership for %s\n" "$output_path" >&2
-          ownership_failed=1
-        fi
-      done
-      if [ "$command_status" -eq 0 ] && [ "$ownership_failed" -ne 0 ]; then
-        command_status="$ownership_failed"
-      fi
-      exit "$command_status"
-    }
-    trap restore_host_ownership EXIT
-
-    mkdir -p "$BUILD_DIR" "$INSTALL_DIR"
-    cd "$BUILD_DIR"
-    configure_args=(
-      "--prefix=/"
-      "--bindir=/bin"
-      "--libdir=/lib"
-      "--datadir=/share/postgresql"
-      "--host=wasm32-wasix"
-      "--with-template=wasix-core"
-      "--without-readline"
-      "--without-icu"
-      "--without-zlib"
-      "--without-llvm"
-      "--without-pam"
-      "--with-openssl=no"
-    )
-    if [ ! -f config.status ]; then
-      WASIXCC_RUN_WASM_OPT=no \
-      CC=wasixcc \
-      AR=wasixar \
-      RANLIB=wasixranlib \
-      NM=wasixnm \
-      CPPFLAGS="-D_GNU_SOURCE" \
-      CFLAGS="$WASIX_CORE_CFLAGS" \
-      LDFLAGS="$WASIX_CORE_LDFLAGS" \
-      "/work/$PGSRC/configure" "${configure_args[@]}"
-    fi
-    if ! grep -Fxq "#define HAVE_SYNC_FILE_RANGE 1" src/include/pg_config.h; then
-      printf "configured PostgreSQL does not define HAVE_SYNC_FILE_RANGE=1; refuse the fallback build\n" >&2
-      exit 2
-    fi
-    if [ "$MODE" = "configure-only" ]; then
-      exit 0
-    fi
-    core_dirs=(
-      src/port
-      src/common
-      src/include
-      src/interfaces/libpq
-      src/backend
-      src/backend/snowball
-      src/backend/utils/mb/conversion_procs
-      src/pl/plpgsql/src
-      src/bin/initdb
-      src/bin/pg_ctl
-      src/bin/psql
-      src/bin/pg_dump
-      src/bin/pg_config
-      src/timezone
-    )
-    make -C src/backend -j "$JOBS" generated-headers
-    rm -f \
-      src/backend/postgres \
-      src/bin/initdb/initdb \
-      src/bin/pg_ctl/pg_ctl \
-      src/bin/psql/psql \
-      src/bin/pg_dump/pg_dump \
-      src/bin/pg_dump/pg_restore \
-      src/bin/pg_dump/pg_dumpall \
-      src/bin/pg_config/pg_config
-    for dir in "${core_dirs[@]}"; do
-      make -C "$dir" -j "$JOBS" all
-    done
-    rm -rf "/work/$INSTALL_DIR"
-    mkdir -p "/work/$INSTALL_DIR"
-    for dir in "${core_dirs[@]}"; do
-      make -C "$dir" -j "$JOBS" install DESTDIR="/work/$INSTALL_DIR"
-    done
-    python3 \
-      /work/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-wasm-import.py \
-      "/work/$INSTALL_DIR/bin/postgres"
-    concurrency_args=()
-    if [ -n "$EXPECTED_ATOMIC_FENCE_TOTAL" ]; then
-      concurrency_args+=(--expected-total "$EXPECTED_ATOMIC_FENCE_TOTAL")
-    fi
-    if [ "$WASIX_CORE_LATCH_STATE_CONTRACT" = packed-atomic-v1 ]; then
-      concurrency_args+=(
-        --latch-state-contract packed-atomic-v1
-        --wasm-dis /opt/wasixcc-home/.wasixcc/binaryen/bin/wasm-dis
-      )
-    fi
-    python3 \
-      /work/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.py \
-      "${concurrency_args[@]}" \
-      "/work/$INSTALL_DIR/bin/postgres"
-  ' >>"$log" 2>&1
-status=$?
-set -e
-
-if [ "$status" -eq 0 ] && [ "$mode" = build ] && \
-  [ "$wasix_core_latch_state_contract" = packed-atomic-v1 ]
-then
-  if [ -z "$expected_atomic_fence_total" ] || \
-    [ -z "$expected_final_atomic_fence_total" ]; then
-    printf 'sealed export closure requires profile-locked pre-seal and final atomic fence totals\n' >>"$log"
-    status=2
-  else
-    set +e
-    (
-      set -euo pipefail
-
-      "$FRESH_ROOT/bin/seal-wasix-core-exports.sh" \
-        --install-dir "$WASIX_INSTALL_DIR" \
-        --expected-total "$expected_final_atomic_fence_total"
-
-      sealed_export_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
-      "$FRESH_ROOT/bin/seal-wasix-linear-memory.sh" \
-        --install-dir "$WASIX_INSTALL_DIR" \
-        --predecessor-receipt "$sealed_export_receipt"
-
-      python3 "$FRESH_ROOT/runtime/bin/verify-postmaster-wasm-import.py" \
-        "$WASIX_INSTALL_DIR/bin/postgres"
-      fresh_require_start_proof_tool \
-        "$FRESH_START_PROOF_BIN" \
-        "$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
-
-      proof_dir="$WASIX_INSTALL_DIR/share/postgresql"
-      final_start_proof="$proof_dir/wasix-postmaster.start-proof.json"
-      final_start_proof_pending="$proof_dir/.wasix-postmaster.start-proof.pending"
-      final_concurrency_receipt="$proof_dir/wasix-postmaster.final-wasm-concurrency.receipt"
-      final_concurrency_receipt_pending="$proof_dir/.wasix-postmaster.final-wasm-concurrency.pending"
-      [ -d "$proof_dir" ] && [ ! -L "$proof_dir" ] || {
-        printf 'unsafe final-proof directory: %s\n' "$proof_dir" >&2
-        exit 2
-      }
-      python3 "$durable_publication" discard-private "$final_start_proof_pending"
-      python3 "$durable_publication" discard-private "$final_concurrency_receipt_pending"
-      cleanup_final_proof_stage() {
-        status=$?
-        trap - EXIT
-        python3 "$durable_publication" discard-private \
-          "$final_start_proof_pending" || status=2
-        python3 "$durable_publication" discard-private \
-          "$final_concurrency_receipt_pending" || status=2
-        exit "$status"
-      }
-      trap cleanup_final_proof_stage EXIT
-
-      docker_install_dir="$(fresh_docker_path_for "$WASIX_INSTALL_DIR")"
-
-      validate_final_proof_generation() {
-        "$FRESH_START_PROOF_BIN" "$WASIX_INSTALL_DIR/bin/postgres" \
-          | python3 "$durable_publication" write-stdin \
-            "$final_start_proof_pending"
-        [ -s "$final_start_proof_pending" ] && \
-          [ ! -L "$final_start_proof_pending" ] || {
-          printf 'deterministic-start analyzer did not produce a regular proof\n' >&2
-          return 2
-        }
-        python3 "$durable_publication" require-equal \
-          "$final_start_proof_pending" "$final_start_proof"
-        python3 "$durable_publication" discard-private "$final_start_proof_pending"
-        python3 \
-          "$FRESH_ROOT/runtime/bin/verify-postmaster-concurrency-contract.py" \
-          --expected-total "$expected_final_atomic_fence_total" \
-          --latch-state-contract packed-atomic-v1 \
-          --verified-receipt "$final_concurrency_receipt" \
-          --receipt-only \
-          "$WASIX_INSTALL_DIR/bin/postgres"
-      }
-
-      if [ -e "$final_concurrency_receipt" ] || \
-        [ -L "$final_concurrency_receipt" ]
-      then
-        [ -f "$final_concurrency_receipt" ] && \
-          [ ! -L "$final_concurrency_receipt" ] || {
-          printf 'final concurrency admission is not regular: %s\n' \
-            "$final_concurrency_receipt" >&2
-          exit 2
-        }
-        [ -f "$final_start_proof" ] && [ ! -L "$final_start_proof" ] || {
-          printf 'admitted final generation has no regular start proof: %s\n' \
-            "$final_start_proof" >&2
-          exit 2
-        }
-        validate_final_proof_generation
-      else
-        final_start_proof_identity="$(
-          "$FRESH_START_PROOF_BIN" "$WASIX_INSTALL_DIR/bin/postgres" |
-            python3 "$durable_publication" write-stdin-identified \
-              "$final_start_proof_pending"
-        )"
-        IFS=$'\t' read -r final_start_proof_dev final_start_proof_ino \
-          final_start_proof_size final_start_proof_sha \
-          <<<"$final_start_proof_identity"
-        [ -s "$final_start_proof_pending" ] && \
-          [ ! -L "$final_start_proof_pending" ] || {
-          printf 'deterministic-start analyzer did not produce a regular proof\n' >&2
-          exit 2
-        }
-        if [ -e "$final_start_proof" ] || [ -L "$final_start_proof" ]; then
-          [ -f "$final_start_proof" ] && [ ! -L "$final_start_proof" ] || {
-            printf 'partial final start proof is not regular: %s\n' \
-              "$final_start_proof" >&2
-            exit 2
-          }
-          python3 "$durable_publication" require-equal \
-            "$final_start_proof_pending" "$final_start_proof"
-          python3 "$durable_publication" discard-private "$final_start_proof_pending"
-        else
-          python3 "$durable_publication" publish-identified \
-            "$final_start_proof_pending" "$final_start_proof" \
-            "$final_start_proof_dev" "$final_start_proof_ino" \
-            "$final_start_proof_size" "$final_start_proof_sha"
-        fi
-
-        "$docker_bin" run --rm \
-          --user "$(id -u):$(id -g)" \
-          -v "$REPO_ROOT:/work" \
-          -w /work \
-          "$docker_image_id" \
-          python3 \
-          /work/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.py \
-          --expected-total "$expected_final_atomic_fence_total" \
-          --latch-state-contract packed-atomic-v1 \
-          --wasm-dis /opt/wasixcc-home/.wasixcc/binaryen/bin/wasm-dis \
-          --receipt "$docker_install_dir/share/postgresql/$(basename "$final_concurrency_receipt_pending")" \
-          "$docker_install_dir/bin/postgres"
-        [ -f "$final_concurrency_receipt_pending" ] && \
-          [ ! -L "$final_concurrency_receipt_pending" ] || {
-          printf 'concurrency analyzer did not produce a regular receipt\n' >&2
-          exit 2
-          }
-        final_concurrency_identity="$(
-          python3 "$durable_publication" identify-source \
-            "$final_concurrency_receipt_pending"
-        )"
-        IFS=$'\t' read -r final_concurrency_dev final_concurrency_ino \
-          final_concurrency_size final_concurrency_sha \
-          <<<"$final_concurrency_identity"
-        python3 \
-          "$FRESH_ROOT/runtime/bin/verify-postmaster-concurrency-contract.py" \
-          --expected-total "$expected_final_atomic_fence_total" \
-          --latch-state-contract packed-atomic-v1 \
-          --verified-receipt "$final_concurrency_receipt_pending" \
-          --receipt-only \
-          "$WASIX_INSTALL_DIR/bin/postgres"
-        # This receipt is the admission record for the pair and is therefore
-        # published last, without replacement, only after the start proof is
-        # durable at its public name.
-        python3 "$durable_publication" publish-identified \
-          "$final_concurrency_receipt_pending" "$final_concurrency_receipt" \
-          "$final_concurrency_dev" "$final_concurrency_ino" \
-          "$final_concurrency_size" "$final_concurrency_sha"
-        validate_final_proof_generation
-      fi
-      trap - EXIT
-    ) >>"$log" 2>&1
-    status=$?
-    set -e
-  fi
-fi
-
-if [ "$status" -eq 0 ]; then
-  if [ "$mode" = build ]; then
-    guest_build_receipt="$WASIX_INSTALL_DIR/guest-build.receipt"
-    guest_build_receipt_pending="$WASIX_INSTALL_DIR/.guest-build.receipt.pending"
-    concurrency_args=()
-    if [ -n "$expected_final_atomic_fence_total" ]; then
-      concurrency_args+=(--expected-total "$expected_final_atomic_fence_total")
-    fi
-    final_wasm_concurrency_receipt_sha256="none"
-    if [ "$wasix_core_latch_state_contract" = packed-atomic-v1 ]; then
-      final_wasm_concurrency_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt"
-      [ -f "$final_wasm_concurrency_receipt" ] && [ ! -L "$final_wasm_concurrency_receipt" ] || {
-        echo 'missing final Wasm concurrency receipt' >&2
-        exit 125
-      }
-      concurrency_args+=(
-        --latch-state-contract packed-atomic-v1
-        --verified-receipt "$final_wasm_concurrency_receipt"
-      )
-      final_wasm_concurrency_receipt_sha256="$(
-        fresh_wasmer_bin_hash "$final_wasm_concurrency_receipt"
-      )" || exit
-      fresh_is_sha256 "$final_wasm_concurrency_receipt_sha256" || {
-        echo 'final Wasm concurrency receipt identity is not a SHA-256' >&2
-        exit 125
-      }
-    fi
-    concurrency_contract_output="$(
-      python3 "$FRESH_ROOT/runtime/bin/verify-postmaster-concurrency-contract.py" \
-        "${concurrency_args[@]}" "$WASIX_INSTALL_DIR/bin/postgres"
-    )" || exit
-    atomic_fence_total="$(
-      printf '%s\n' "$concurrency_contract_output" |
-        sed -n 's/^verified PostgreSQL Wasm concurrency contract: total=\([0-9][0-9]*\) .*/\1/p'
-    )"
-    case "$atomic_fence_total" in
-      ''|*[!0-9]*) echo 'could not parse verified atomic fence total' >&2; exit 125 ;;
-    esac
-    linear_memory_profile_id="$FRESH_LINEAR_MEMORY_PROFILE_ID"
-    linear_memory_install_receipt="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
-    [ -f "$linear_memory_install_receipt" ] && \
-      [ ! -L "$linear_memory_install_receipt" ] || {
-      echo 'missing regular linear-memory install receipt' >&2
-      exit 125
-    }
-    python3 - "$linear_memory_install_receipt" "$linear_memory_profile_id" <<'PY'
-import json
-import sys
-
-path, expected_profile = sys.argv[1:]
-with open(path, encoding="utf-8") as stream:
-    receipt = json.load(stream)
-if receipt.get("schema") != "oliphaunt.wasix-postmaster.linear-memory-install.v1":
-    raise SystemExit("linear-memory install receipt schema differs")
-if receipt.get("profile-id") != expected_profile:
-    raise SystemExit("linear-memory install receipt profile differs")
-PY
-    linear_memory_install_receipt_sha256="$(
-      fresh_wasmer_bin_hash "$linear_memory_install_receipt"
-    )" || exit
-    fresh_is_sha256 "$linear_memory_install_receipt_sha256" || {
-      echo 'linear-memory install receipt identity is not a SHA-256' >&2
-      exit 125
-    }
-    require_build_inputs_unchanged 'before guest receipt publication' || exit
-    installed_closure_sha256="$(
-      python3 "$FRESH_ROOT/lib/guest_build_provenance.py" \
-        seal-identity "$WASIX_INSTALL_DIR"
-    )" || exit
-    fresh_is_sha256 "$installed_closure_sha256" || {
-      echo 'WASIX core installed closure identity is not a SHA-256' >&2
-      exit 125
-    }
-    require_build_inputs_unchanged 'while installed outputs were hashed' || exit
-    case "$wasix_core_cflags$wasix_core_ldflags$wasixcc_run_wasm_opt$wasixcc_wasm_opt_flags$wasixcc_wasm_opt_suppress_default" in
-      *$'\n'*|*$'\r'*)
-        echo 'WASIX core effective build flags contain a line break' >&2
-        exit 2
-        ;;
-    esac
-    python3 "$durable_publication" discard-private "$guest_build_receipt_pending"
-    guest_build_receipt_identity="$({
-      printf 'schema=oliphaunt.wasix-postmaster.guest-build.v5\n'
-      printf 'core_profile=%s\n' "$WASIX_CORE_PROFILE"
-      printf 'guest_source_signature_sha256=%s\n' "$source_signature"
-      printf 'docker_image_id=%s\n' "$docker_image_id"
-      printf 'installed_closure_sha256=%s\n' "$installed_closure_sha256"
-      printf 'child_backend=%s\n' "$wasix_core_child_backend"
-      printf 'effective_cflags=%s\n' "$wasix_core_cflags"
-      printf 'effective_ldflags=%s\n' "$wasix_core_ldflags"
-      printf 'effective_wasm_opt=%s\n' "$wasixcc_run_wasm_opt"
-      printf 'effective_wasm_opt_flags=%s\n' "${wasixcc_wasm_opt_flags:-none}"
-      printf 'effective_wasm_opt_suppress_default=%s\n' "$wasixcc_wasm_opt_suppress_default"
-      printf 'atomic_fence_total=%s\n' "$atomic_fence_total"
-      printf 'atomic_fence_set_latch=2\n'
-      printf 'atomic_fence_reset_latch=1\n'
-      printf 'atomic_fence_wait_event_set_wait=1\n'
-      printf 'latch_state_contract=%s\n' "$wasix_core_latch_state_contract"
-      printf 'final_wasm_concurrency_receipt_sha256=%s\n' \
-        "$final_wasm_concurrency_receipt_sha256"
-      printf 'linear_memory_profile_id=%s\n' "$linear_memory_profile_id"
-      printf 'linear_memory_install_receipt_sha256=%s\n' \
-        "$linear_memory_install_receipt_sha256"
-      printf 'postgres_tag=%s\n' "$POSTGRES_TAG"
-      printf 'postgres_version=%s\n' "$POSTGRES_VERSION"
-      printf 'sysroot_variant=%s\n' "$WASIXCC_SYSROOT_VARIANT"
-    } | python3 "$durable_publication" write-stdin-identified \
-      "$guest_build_receipt_pending")"
-    IFS=$'\t' read -r guest_build_receipt_dev guest_build_receipt_ino \
-      guest_build_receipt_size guest_build_receipt_sha \
-      <<<"$guest_build_receipt_identity"
-    require_build_inputs_unchanged 'before final guest receipt publication' || exit
-    if [ -e "$guest_build_receipt" ] || [ -L "$guest_build_receipt" ]; then
-      [ -f "$guest_build_receipt" ] && [ ! -L "$guest_build_receipt" ] || {
-        printf 'guest build admission is not regular: %s\n' \
-          "$guest_build_receipt" >&2
-        exit 125
-      }
-      python3 "$durable_publication" require-equal \
-        "$guest_build_receipt_pending" "$guest_build_receipt" || exit 125
-      python3 "$durable_publication" discard-private \
-        "$guest_build_receipt_pending" || exit 125
-    else
-      # The guest receipt admits the complete installed closure.  It is
-      # synchronized and published without replacement only after every
-      # predecessor proof above has been replayed against that closure.
-      python3 "$durable_publication" publish-identified \
-        "$guest_build_receipt_pending" "$guest_build_receipt" \
-        "$guest_build_receipt_dev" "$guest_build_receipt_ino" \
-        "$guest_build_receipt_size" "$guest_build_receipt_sha" || exit 125
-    fi
-  fi
-  {
-    printf '\n## Result\n\n'
-    printf -- '- Status: `pass`\n'
-    printf -- '- Mode: `%s`\n' "$mode"
-    printf -- '- Build directory: `%s`\n' "$WASIX_BUILD_DIR"
-    printf -- '- Install directory: `%s`\n' "$WASIX_INSTALL_DIR"
-  } >>"$report"
-  printf 'built WASIX core PostgreSQL lane at %s\n' "$WASIX_INSTALL_DIR"
-else
-  {
-    printf '\n## Result\n\n'
-    printf -- '- Status: `fail`\n'
-    printf -- '- Mode: `%s`\n' "$mode"
-    printf -- '- Exit code: `%s`\n\n' "$status"
-    printf '## Blocker Policy\n\n'
-    printf 'Treat this as a PostgreSQL/WASIX/toolchain compatibility blocker. Do not add fake PostgreSQL success shims to make this pass.\n'
-  } >>"$report"
-  printf 'WASIX core build failed; see %s\n' "$log" >&2
-  exit "$status"
-fi
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-release-carrier.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-release-carrier.sh
deleted file mode 100755
index 6bc5acce7..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-release-carrier.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
-source "$project_root/lib/common.sh"
-source "$project_root/lib/sealed-carrier.sh"
-
-carrier="$(fresh_select_current_sealed_carrier)"
-target="$(fresh_release_target)"
-
-bash "$project_root/bin/build-native-client-tools.sh"
-if [ "$target" = macos-arm64 ]; then
-  exec bash "$project_root/bin/qualify-wasix-immediate-recovery.sh" \
-    --target "$target" \
-    --sealed-carrier "$carrier"
-fi
-
-receipt_dir="$FRESH_WORK_ROOT/immutable-receipts"
-mkdir -p "$receipt_dir"
-receipt="$receipt_dir/$(basename "$carrier").json"
-cleanup() {
-  status=$?
-  trap - EXIT
-  if [ -f "$receipt" ]; then
-    sudo bash "$project_root/bin/deploy-immutable-sealed-carrier.sh" \
-      --sealed-carrier "$carrier" \
-      --receipt "$receipt" \
-      --remove || {
-        cleanup_status=$?
-        [ "$status" -ne 0 ] || status=$cleanup_status
-      }
-  fi
-  exit "$status"
-}
-trap cleanup EXIT
-sudo bash "$project_root/bin/deploy-immutable-sealed-carrier.sh" \
-  --sealed-carrier "$carrier" \
-  --receipt "$receipt"
-bash "$project_root/bin/qualify-wasix-immediate-recovery.sh" \
-  --target "$target" \
-  --sealed-carrier "$carrier" \
-  --immutable-carrier-receipt "$receipt" \
-  --cgroup-memory-max 4G \
-  --cgroup-memory-high 3G \
-  --cgroup-swap-max 0
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-wasix-immediate-recovery.test.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-wasix-immediate-recovery.test.sh
deleted file mode 100755
index 9f7610ab1..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-wasix-immediate-recovery.test.sh
+++ /dev/null
@@ -1,187 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-qualifier="$root/bin/qualify-wasix-immediate-recovery.sh"
-test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-immediate-recovery-test.XXXXXX")"
-trap 'rm -rf -- "$test_root"' EXIT HUP INT TERM
-
-help_output="$("$qualifier" --help)"
-for option in \
-  '--target TARGET' \
-  '--immutable-carrier-receipt FILE' \
-  '--cgroup-memory-max SIZE' \
-  '--cgroup-memory-high SIZE' \
-  '--cgroup-swap-max SIZE'
-do
-  grep -Fq -- "$option" <<<"$help_output"
-done
-grep -Fq -- '--immutable-carrier-receipt is required on Linux' "$qualifier"
-grep -Fq 'Linux immediate-recovery qualification requires finite --cgroup-memory-max' "$qualifier"
-grep -Fq 'required_snapshot_policy=portable-copy' "$qualifier"
-if grep -Fq -- '--mode MODE' <<<"$help_output"; then
-  echo 'recovery qualifier still exposes a research/diagnostic mode' >&2
-  exit 1
-fi
-grep -Fq -- '--expected-initdb-executions 1' "$qualifier"
-grep -Fq -- '--expected-postgres-executions 3' "$qualifier"
-grep -Fq 'expected_outer_initdb_invocations' "$qualifier"
-grep -Fq 'expected_outer_postgres_invocations' "$qualifier"
-grep -Fq 'postgres and dynamic modules' <<<"$help_output"
-grep -Fq 'immediate-recovery-evidence.v5' "$qualifier"
-grep -Fq "WHERE source = 'command line'" "$qualifier"
-if grep -Eq 'adaptive|cache-offers|CACHE_OFFER' "$qualifier"; then
-  echo 'recovery qualifier still contains cache experiment machinery' >&2
-  exit 1
-fi
-
-for function_name in validate_cgroup_size cgroup_size_to_bytes configure_server_cgroup; do
-  awk -v signature="${function_name}() {" '
-    $0 == signature { capture = 1 }
-    capture { print }
-    capture && /^}$/ { exit }
-  ' "$qualifier" >>"$test_root/cgroup-functions.sh"
-done
-# shellcheck source=/dev/null
-source "$test_root/cgroup-functions.sh"
-
-validate_cgroup_size 256M
-validate_cgroup_size 224MiB
-validate_cgroup_size 0
-! validate_cgroup_size infinity
-! validate_cgroup_size -1
-[ "$(cgroup_size_to_bytes 256M)" = 268435456 ]
-[ "$(cgroup_size_to_bytes 224MiB)" = 234881024 ]
-[ "$(cgroup_size_to_bytes 0)" = 0 ]
-! cgroup_size_to_bytes 9223372036854775808 >/dev/null 2>&1
-
-cgroup_enabled=1
-cgroup_memory_max=256M
-cgroup_memory_high=224M
-cgroup_swap_max=0
-active_cgroup_unit=""
-server_command_prefix=()
-configure_server_cgroup baseline
-[ "$active_cgroup_unit" = "oliphaunt-recovery-$$-baseline" ]
-prefix_text="$(printf '%s\n' "${server_command_prefix[@]}")"
-grep -Fxq -- '--property=MemoryAccounting=yes' <<<"$prefix_text"
-grep -Fxq -- '--property=MemoryMax=256M' <<<"$prefix_text"
-grep -Fxq -- '--property=MemoryHigh=224M' <<<"$prefix_text"
-grep -Fxq -- '--property=MemorySwapMax=0' <<<"$prefix_text"
-cgroup_enabled=0
-configure_server_cgroup recovery
-[ -z "$active_cgroup_unit" ]
-[ "${#server_command_prefix[@]}" -eq 0 ]
-
-awk '
-  /^wait_for_unassisted_exit\(\) \{$/ { capture = 1 }
-  capture { print }
-  capture && /^}$/ { exit }
-' "$qualifier" >"$test_root/wait-for-unassisted-exit.sh"
-grep -Fq 'wait_for_unassisted_exit() {' \
-  "$test_root/wait-for-unassisted-exit.sh"
-# shellcheck source=/dev/null
-source "$test_root/wait-for-unassisted-exit.sh"
-
-fresh_supervision_now_ms() {
-  printf '1000\n'
-}
-
-fresh_supervision_pid_running() {
-  return 1
-}
-
-fresh_pid_matches_birth_identity() {
-  return 0
-}
-
-fresh_reap_process_group_leader() {
-  FRESH_PROCESS_GROUP_WAIT_STATUS="$fixture_wait_status"
-}
-
-fresh_process_group_exists() {
-  return 1
-}
-
-fresh_wait_tcp_port_closed() {
-  return 0
-}
-
-reset_fixture() {
-  fixture_wait_status="$1"
-  active_pid=4242
-  active_pgid=4242
-  active_identity=linux-starttime:303
-  active_phase=fixture-shutdown
-}
-
-timeout_seconds=1
-port=15432
-dev_shm="$test_root/dev-shm"
-active_cgroup_unit=""
-active_cgroup_dir=""
-active_cgroup_identity=""
-mkdir -p "$dev_shm"
-
-reset_fixture 17
-set +e
-wait_for_unassisted_exit "$test_root/nonzero-exit.tsv" \
-  >"$test_root/nonzero.out" 2>"$test_root/nonzero.err"
-status=$?
-set -e
-[ "$status" -eq 1 ] || {
-  printf 'expected nonzero leader status to reject recovery evidence, got %s\n' \
-    "$status" >&2
-  exit 1
-}
-[ ! -e "$test_root/nonzero-exit.tsv" ] || {
-  printf 'nonzero leader status produced successful recovery evidence\n' >&2
-  exit 1
-}
-grep -Fqx \
-  'server leader exited nonzero after unassisted guest shutdown: phase=fixture-shutdown status=17' \
-  "$test_root/nonzero.err"
-[ "$active_pid" = 4242 ]
-[ "$active_pgid" = 4242 ]
-[ "$active_identity" = linux-starttime:303 ]
-[ "$active_phase" = fixture-shutdown ]
-
-reset_fixture 0
-wait_for_unassisted_exit "$test_root/zero-exit.tsv"
-awk -F '\t' '
-  NR == 1 {
-    valid = ($1 == "phase" && $2 == "wait_status" &&
-      $3 == "process_group_empty" && $4 == "cgroup_empty" &&
-      $5 == "port_closed" && $6 == "shared_objects_empty" &&
-      $7 == "escalation_used")
-  }
-  NR == 2 {
-    valid = valid && ($1 == "fixture-shutdown" && $2 == "0" &&
-      $3 == "true" && $4 == "not-requested" && $5 == "true" &&
-      $6 == "true" && $7 == "false")
-  }
-  END { exit !(valid && NR == 2) }
-' "$test_root/zero-exit.tsv"
-[ -z "$active_pid" ]
-[ -z "$active_pgid" ]
-[ -z "$active_identity" ]
-[ -z "$active_phase" ]
-
-fresh_wait_cgroup_empty() {
-  [ "$1" = "$test_root/fake-cgroup" ]
-  [ "$2" = 42:99 ]
-  [ "$3" = 1000 ]
-  cgroup_wait_called=1
-}
-reset_fixture 0
-active_cgroup_unit=oliphaunt-recovery-fixture
-active_cgroup_dir="$test_root/fake-cgroup"
-active_cgroup_identity=42:99
-cgroup_wait_called=0
-wait_for_unassisted_exit "$test_root/cgroup-exit.tsv"
-[ "$cgroup_wait_called" -eq 1 ]
-awk -F '\t' 'NR == 2 { exit !($4 == "true") }' \
-  "$test_root/cgroup-exit.tsv"
-
-printf 'immediate recovery exit tests passed\n'
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-core-exports.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-core-exports.sh
deleted file mode 100755
index a6102253c..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-core-exports.sh
+++ /dev/null
@@ -1,709 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/common.sh"
-
-usage() {
-  cat <<'EOF'
-Usage: seal-wasix-core-exports.sh [options]
-
-Derive the exact typed PostgreSQL main-module export closure from the packaged
-side modules, remove unreachable definitions with one pinned Binaryen pass,
-re-run the start/import/fence proofs, and publish the module plus receipts.
-
-Options:
-  --install-dir DIR       WASIX PostgreSQL prefix (default: WASIX_INSTALL_DIR)
-  --expected-total COUNT  Exact final atomic.fence count for the packed latch proof
-  -h, --help              Show this help
-EOF
-}
-
-fail() {
-  printf 'sealed export closure: %s\n' "$*" >&2
-  exit 2
-}
-
-install_dir="$WASIX_INSTALL_DIR"
-expected_total=""
-while [ "$#" -gt 0 ]; do
-  case "$1" in
-    --install-dir|--expected-total)
-      option="$1"
-      shift
-      [ "$#" -gt 0 ] || fail "$option requires a value"
-      case "$option" in
-        --install-dir) install_dir="$1" ;;
-        --expected-total) expected_total="$1" ;;
-      esac
-      ;;
-    -h|--help)
-      usage
-      exit 0
-      ;;
-    *) fail "unknown argument: $1" ;;
-  esac
-  shift
-done
-
-case "$expected_total" in
-  ''|*[!0-9]*) fail '--expected-total must be a nonnegative integer' ;;
-esac
-
-fresh_require_command cargo
-fresh_require_command cmp
-fresh_require_command cp
-fresh_require_command find
-fresh_require_command flock
-fresh_require_command grep
-fresh_require_command python3
-fresh_require_command sha256sum
-fresh_require_command sort
-
-[ -d "$install_dir" ] && [ ! -L "$install_dir" ] || fail "missing regular install prefix: $install_dir"
-install_dir="$(cd "$install_dir" && pwd -P)"
-postgres="$install_dir/bin/postgres"
-[ -f "$postgres" ] && [ ! -L "$postgres" ] || fail "missing regular PostgreSQL module: $postgres"
-fresh_require_managed_generated_path "$postgres" sealed-postgres-module
-
-readonly publication_schema=oliphaunt.wasix-postmaster.sealed-export-publication.v1
-readonly structure_relative=share/postgresql/wasix-postmaster.sealed-export.structure.receipt
-declare -ar publication_relatives=(
-  bin/postgres
-  share/postgresql/wasix-postmaster.sealed-export.seed-proof.json
-  share/postgresql/wasix-postmaster.sealed-export.final-proof.json
-  share/postgresql/wasix-postmaster.sealed-export.allowlist
-  share/postgresql/wasix-postmaster.sealed-export.start-proof.intermediate.json
-  share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt
-  "$structure_relative"
-)
-
-stage="$install_dir/.oliphaunt-sealed-export-closure.pending"
-stage_initializing="$install_dir/.oliphaunt-sealed-export-closure.initializing"
-stage_discarded="$install_dir/.oliphaunt-sealed-export-closure.discarded"
-fresh_require_managed_generated_path "$stage" sealed-export-closure-stage
-fresh_require_managed_generated_path "$stage_initializing" sealed-export-closure-initializer
-fresh_require_managed_generated_path "$stage_discarded" sealed-export-closure-discarded
-
-publication_lock_dir="$FRESH_WORK_ROOT/runtime/publication-locks"
-fresh_require_managed_generated_path "$publication_lock_dir" sealed-export-publication-locks
-mkdir -p "$publication_lock_dir"
-[ -d "$publication_lock_dir" ] && [ ! -L "$publication_lock_dir" ] ||
-  fail "unsafe publication lock directory: $publication_lock_dir"
-publication_lock_subject="$(python3 - "$install_dir" <<'PY'
-import os
-import stat
-import sys
-
-path = sys.argv[1]
-before = os.lstat(path)
-if not stat.S_ISDIR(before.st_mode) or stat.S_ISLNK(before.st_mode):
-    raise SystemExit("install prefix is not a non-symlink directory")
-flags = (
-    os.O_RDONLY
-    | getattr(os, "O_CLOEXEC", 0)
-    | getattr(os, "O_DIRECTORY", 0)
-    | getattr(os, "O_NOFOLLOW", 0)
-)
-descriptor = os.open(path, flags)
-try:
-    opened = os.fstat(descriptor)
-    if (before.st_dev, before.st_ino) != (opened.st_dev, opened.st_ino):
-        raise SystemExit("install prefix changed while deriving lock identity")
-    print(f"{opened.st_dev}:{opened.st_ino}")
-finally:
-    os.close(descriptor)
-PY
-)" || fail 'could not derive publication lock subject'
-publication_lock_key="$(printf '%s' "$publication_lock_subject" | sha256sum)" ||
-  fail 'could not derive publication lock identity'
-publication_lock_key="${publication_lock_key%% *}"
-fresh_is_sha256 "$publication_lock_key" || fail 'invalid publication lock identity'
-publication_lock="$publication_lock_dir/$publication_lock_key.lock"
-[ ! -L "$publication_lock" ] || fail "unsafe publication lock: $publication_lock"
-exec {publication_lock_fd}>"$publication_lock"
-[ -f "$publication_lock" ] && [ ! -L "$publication_lock" ] ||
-  fail "publication lock changed while opening: $publication_lock"
-flock -x "$publication_lock_fd" || fail "could not lock export publication for $install_dir"
-readonly completion_schema=oliphaunt.wasix-postmaster.sealed-export-completion.v2
-publication_completion="$publication_lock_dir/$publication_lock_key.completed"
-publication_completion_pending="$publication_lock_dir/$publication_lock_key.completed.pending"
-
-fsync_paths() {
-  python3 - "$@" <<'PY'
-import os
-import stat
-import sys
-
-for raw in sys.argv[1:]:
-    flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
-    fd = os.open(raw, flags)
-    try:
-        mode = os.fstat(fd).st_mode
-        if not (stat.S_ISREG(mode) or stat.S_ISDIR(mode)):
-            raise SystemExit(f"refusing to fsync non-file path: {raw}")
-        os.fsync(fd)
-    finally:
-        os.close(fd)
-PY
-}
-
-fsync_tree_directories() {
-  python3 - "$1" <<'PY'
-import os
-import stat
-import sys
-
-root = os.path.realpath(sys.argv[1])
-directories = []
-for current, names, _files in os.walk(root, topdown=True, followlinks=False):
-    names.sort()
-    for name in names:
-        candidate = os.path.join(current, name)
-        mode = os.lstat(candidate).st_mode
-        if stat.S_ISLNK(mode):
-            raise SystemExit(f"refusing symlink directory in publication tree: {candidate}")
-        if not stat.S_ISDIR(mode):
-            raise SystemExit(f"refusing non-directory in publication tree: {candidate}")
-    directories.append(current)
-for current in reversed(directories):
-    flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
-    fd = os.open(current, flags)
-    try:
-        if not stat.S_ISDIR(os.fstat(fd).st_mode):
-            raise SystemExit(f"publication path changed type: {current}")
-        os.fsync(fd)
-    finally:
-        os.close(fd)
-PY
-}
-
-remove_pending_path() {
-  local path="$1"
-  if [ -e "$path" ] || [ -L "$path" ]; then
-    [ -f "$path" ] && [ ! -L "$path" ] || fail "unsafe pending publication path: $path"
-    rm -f -- "$path"
-  fi
-}
-
-remove_disposable_tree() {
-  local path="$1"
-  if [ -e "$path" ] || [ -L "$path" ]; then
-    [ -d "$path" ] && [ ! -L "$path" ] || fail "unsafe disposable transaction path: $path"
-    rm -rf -- "$path"
-    fsync_paths "$install_dir"
-  fi
-}
-
-discard_canonical_stage() {
-  [ -d "$stage" ] && [ ! -L "$stage" ] || fail "unsafe canonical transaction stage: $stage"
-  remove_disposable_tree "$stage_discarded"
-  mv -- "$stage" "$stage_discarded"
-  fsync_paths "$install_dir"
-  remove_disposable_tree "$stage_discarded"
-}
-
-remove_completion_path() {
-  local path="$1"
-  if [ -e "$path" ] || [ -L "$path" ]; then
-    [ -f "$path" ] && [ ! -L "$path" ] || fail "unsafe completion path: $path"
-    rm -f -- "$path"
-    fsync_paths "$publication_lock_dir"
-  fi
-}
-
-completion_matches_live() {
-  [ -f "$publication_completion" ] && [ ! -L "$publication_completion" ] || return 1
-  python3 - \
-    "$publication_completion" \
-    "$completion_schema" \
-    "$install_dir" \
-    "${publication_relatives[@]}" <<'PY'
-import hashlib
-import os
-import stat
-import sys
-from pathlib import Path, PurePosixPath
-
-receipt = Path(sys.argv[1])
-schema = sys.argv[2]
-install = Path(sys.argv[3])
-relatives = sys.argv[4:]
-
-def digest(path: Path) -> str:
-    value = hashlib.sha256()
-    flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
-    descriptor = os.open(path, flags)
-    info = os.fstat(descriptor)
-    if not stat.S_ISREG(info.st_mode):
-        os.close(descriptor)
-        raise SystemExit(1)
-    with os.fdopen(descriptor, "rb", closefd=True) as stream:
-        for chunk in iter(lambda: stream.read(1024 * 1024), b""):
-            value.update(chunk)
-    return value.hexdigest()
-
-identity = os.stat(install, follow_symlinks=False)
-lines = [f"schema={schema}", f"install_identity={identity.st_dev}:{identity.st_ino}"]
-for relative in relatives:
-    pure = PurePosixPath(relative)
-    if pure.is_absolute() or any(part in ("", ".", "..") for part in pure.parts):
-        raise SystemExit(1)
-    lines.append(f"file_sha256.{relative}={digest(install.joinpath(*pure.parts))}")
-expected = ("\n".join(lines) + "\n").encode("ascii")
-if receipt.read_bytes() != expected:
-    raise SystemExit(1)
-PY
-}
-
-publish_completion() {
-  remove_completion_path "$publication_completion_pending"
-  python3 - \
-    "$completion_schema" \
-    "$install_dir" \
-    "${publication_relatives[@]}" >"$publication_completion_pending" <<'PY'
-import hashlib
-import os
-import stat
-import sys
-from pathlib import Path, PurePosixPath
-
-schema = sys.argv[1]
-install = Path(sys.argv[2])
-relatives = sys.argv[3:]
-
-def digest(path: Path) -> str:
-    value = hashlib.sha256()
-    flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
-    descriptor = os.open(path, flags)
-    info = os.fstat(descriptor)
-    if not stat.S_ISREG(info.st_mode):
-        os.close(descriptor)
-        raise SystemExit(f"completion input is not regular: {path}")
-    with os.fdopen(descriptor, "rb", closefd=True) as stream:
-        for chunk in iter(lambda: stream.read(1024 * 1024), b""):
-            value.update(chunk)
-    return value.hexdigest()
-
-identity = os.stat(install, follow_symlinks=False)
-lines = [f"schema={schema}", f"install_identity={identity.st_dev}:{identity.st_ino}"]
-for relative in relatives:
-    pure = PurePosixPath(relative)
-    if pure.is_absolute() or any(part in ("", ".", "..") for part in pure.parts):
-        raise SystemExit(f"unsafe completion path: {relative}")
-    lines.append(f"file_sha256.{relative}={digest(install.joinpath(*pure.parts))}")
-sys.stdout.write("\n".join(lines) + "\n")
-PY
-  fsync_paths "$publication_completion_pending"
-  mv -f -- "$publication_completion_pending" "$publication_completion"
-  fsync_paths "$publication_lock_dir"
-}
-
-validate_existing_export_generation() {
-  local relative
-  local start_validation_pending
-  local installed_start_proof="$install_dir/share/postgresql/wasix-postmaster.sealed-export.start-proof.intermediate.json"
-  local installed_concurrency_receipt="$install_dir/share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt"
-
-  for relative in "${publication_relatives[@]}"; do
-    [ -f "$install_dir/$relative" ] && [ ! -L "$install_dir/$relative" ] ||
-      fail "sealed export generation is missing a regular member: $relative"
-  done
-  python3 "$FRESH_ROOT/lib/sealed_export_chain.py" \
-    --install-root "$install_dir" \
-    --project-root "$FRESH_ROOT" ||
-    fail 'installed sealed export proof chain is invalid'
-  python3 "$FRESH_ROOT/runtime/bin/verify-postmaster-wasm-import.py" "$postgres" >/dev/null ||
-    fail 'installed sealed export module import contract is invalid'
-  fresh_require_start_proof_tool \
-    "$FRESH_START_PROOF_BIN" \
-    "$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
-  start_validation_pending="$publication_lock_dir/$publication_lock_key.start-proof.validation.pending"
-  remove_completion_path "$start_validation_pending"
-  "$FRESH_START_PROOF_BIN" "$postgres" >"$start_validation_pending"
-  cmp -s "$start_validation_pending" "$installed_start_proof" || {
-    remove_completion_path "$start_validation_pending"
-    fail 'installed sealed export deterministic-start proof differs'
-  }
-  remove_completion_path "$start_validation_pending"
-  python3 "$FRESH_ROOT/runtime/bin/verify-postmaster-concurrency-contract.py" \
-    --expected-total "$expected_total" \
-    --latch-state-contract packed-atomic-v1 \
-    --verified-receipt "$installed_concurrency_receipt" \
-    --receipt-only \
-    "$postgres" >/dev/null ||
-    fail 'installed sealed export concurrency receipt differs'
-}
-
-remove_publication_temporary() {
-  local relative="$1"
-  local destination="$install_dir/$relative"
-  remove_pending_path "$(dirname "$destination")/.$(basename "$destination").oliphaunt-sealed-export.pending"
-}
-
-atomic_publish_file() {
-  local source="$1"
-  local relative="$2"
-  local destination="$install_dir/$relative"
-  local parent
-  local temporary
-  parent="$(dirname "$destination")"
-  [ -d "$parent" ] && [ ! -L "$parent" ] || fail "unsafe publication directory: $parent"
-  [ -f "$source" ] && [ ! -L "$source" ] || fail "missing regular publication source: $source"
-  temporary="$parent/.$(basename "$destination").oliphaunt-sealed-export.pending"
-  remove_pending_path "$temporary"
-  cp -p -- "$source" "$temporary"
-  fsync_paths "$temporary"
-  mv -f -- "$temporary" "$destination"
-  fsync_paths "$parent"
-}
-
-remove_live_file() {
-  local relative="$1"
-  local destination="$install_dir/$relative"
-  local parent
-  parent="$(dirname "$destination")"
-  if [ -e "$destination" ] || [ -L "$destination" ]; then
-    [ -f "$destination" ] && [ ! -L "$destination" ] ||
-      fail "unsafe live publication path: $destination"
-    rm -f -- "$destination"
-    fsync_paths "$parent"
-  fi
-}
-
-rollback_publication() {
-  local relative backup absent destination parent temporary
-
-  # The structural receipt is the sole admission point. Remove a possibly new
-  # receipt before restoring any payload so no mixed generation is admissible.
-  for relative in "${publication_relatives[@]}"; do
-    remove_publication_temporary "$relative"
-  done
-  remove_live_file "$structure_relative"
-  for relative in "${publication_relatives[@]}"; do
-    [ "$relative" != "$structure_relative" ] || continue
-    backup="$stage/originals/$relative"
-    absent="$stage/originals/$relative.absent"
-    if [ -f "$backup" ] && [ ! -L "$backup" ] && [ ! -e "$absent" ]; then
-      atomic_publish_file "$backup" "$relative"
-    elif [ -f "$absent" ] && [ ! -L "$absent" ] && [ ! -e "$backup" ]; then
-      remove_live_file "$relative"
-    else
-      fail "incomplete rollback identity for $relative"
-    fi
-  done
-
-  backup="$stage/originals/$structure_relative"
-  absent="$stage/originals/$structure_relative.absent"
-  if [ -f "$backup" ] && [ ! -L "$backup" ] && [ ! -e "$absent" ]; then
-    atomic_publish_file "$backup" "$structure_relative"
-  elif [ -f "$absent" ] && [ ! -L "$absent" ] && [ ! -e "$backup" ]; then
-    :
-  else
-    fail "incomplete rollback identity for $structure_relative"
-  fi
-}
-
-recover_stale_publication() {
-  local schema_path="$stage/TRANSACTION_SCHEMA"
-  local ready="$stage/READY_TO_ADMIT"
-  local staged_receipt="$stage/$structure_relative"
-  local live_receipt="$install_dir/$structure_relative"
-
-  [ -d "$stage" ] && [ ! -L "$stage" ] || fail "unsafe stale closure staging path: $stage"
-  [ -f "$schema_path" ] && [ ! -L "$schema_path" ] ||
-    fail "stale closure transaction has no regular schema: $stage"
-  [ "$(cat "$schema_path")" = "$publication_schema" ] ||
-    fail "stale closure transaction schema differs: $stage"
-
-  # READY is durable only after every non-admission file and directory is
-  # durable. A matching live structural receipt therefore proves the new
-  # generation reached its atomic admission point before interruption.
-  if [ -f "$ready" ] && [ ! -L "$ready" ] &&
-    [ -f "$staged_receipt" ] && [ ! -L "$staged_receipt" ] &&
-    [ -f "$live_receipt" ] && [ ! -L "$live_receipt" ] &&
-    cmp -s "$staged_receipt" "$live_receipt"; then
-    recovery_committed=1
-    return 0
-  fi
-  if [ -f "$stage/BACKUPS_COMPLETE" ] && [ ! -L "$stage/BACKUPS_COMPLETE" ]; then
-    rollback_publication
-  fi
-}
-
-recovery_committed=0
-remove_disposable_tree "$stage_initializing"
-remove_disposable_tree "$stage_discarded"
-remove_completion_path "$publication_completion_pending"
-if [ -e "$stage" ] || [ -L "$stage" ]; then
-  recover_stale_publication
-  if [ "$recovery_committed" -eq 1 ]; then
-    validate_existing_export_generation
-    publish_completion
-    discard_canonical_stage
-    printf 'recovered committed sealed export closure: module=%s receipt=%s\n' \
-      "$postgres" "$install_dir/$structure_relative"
-    exit 0
-  fi
-  discard_canonical_stage
-fi
-linear_memory_descendant="$install_dir/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
-if [ -e "$linear_memory_descendant" ] || [ -L "$linear_memory_descendant" ]; then
-  [ -f "$linear_memory_descendant" ] && [ ! -L "$linear_memory_descendant" ] ||
-    fail "unsafe linear-memory descendant receipt: $linear_memory_descendant"
-  python3 "$FRESH_ROOT/lib/sealed_export_chain.py" \
-    --install-root "$install_dir" \
-    --project-root "$FRESH_ROOT" \
-    --allow-linear-memory-descendant ||
-    fail 'installed linear-memory descendant does not validate against the sealed export generation'
-  printf 'sealed export closure already has a validated linear-memory descendant: module=%s receipt=%s\n' \
-    "$postgres" "$install_dir/$structure_relative"
-  exit 0
-fi
-if [ -e "$install_dir/$structure_relative" ] || [ -L "$install_dir/$structure_relative" ]; then
-  validate_existing_export_generation
-  publish_completion
-  printf 'validated existing sealed export closure: module=%s receipt=%s\n' \
-    "$postgres" "$install_dir/$structure_relative"
-  exit 0
-fi
-remove_completion_path "$publication_completion"
-mkdir -p "$stage_initializing/bin" "$stage_initializing/share/postgresql"
-printf '%s\n' "$publication_schema" >"$stage_initializing/TRANSACTION_SCHEMA"
-fsync_paths "$stage_initializing/TRANSACTION_SCHEMA"
-fsync_tree_directories "$stage_initializing"
-mv -- "$stage_initializing" "$stage"
-fsync_paths "$install_dir"
-
-publish_complete=0
-cleanup() {
-  status=$?
-  trap - EXIT HUP INT TERM
-  if completion_matches_live; then
-    status=0
-  fi
-  if [ -d "$stage" ] && [ ! -L "$stage" ]; then
-    if [ "$publish_complete" -eq 0 ]; then
-      recovery_committed=0
-      recover_stale_publication
-      if [ "$recovery_committed" -eq 1 ]; then
-        publish_completion
-        status=0
-      fi
-    fi
-    discard_canonical_stage
-  fi
-  remove_disposable_tree "$stage_initializing"
-  remove_disposable_tree "$stage_discarded"
-  exit "$status"
-}
-trap cleanup EXIT
-trap 'exit 129' HUP
-trap 'exit 130' INT
-trap 'exit 143' TERM
-
-readonly tool_manifest="$FRESH_ROOT/tools/sealed-export-closure/Cargo.toml"
-readonly mandatory_policy="$FRESH_ROOT/runtime/policies/sealed-main-runtime-exports.v1.txt"
-readonly dlsym_policy="$FRESH_ROOT/runtime/policies/sealed-main-dlsym-exports.v1.txt"
-readonly side_manifest="$FRESH_ROOT/runtime/policies/sealed-side-modules.v1.tsv"
-for required in "$tool_manifest" "$mandatory_policy" "$dlsym_policy" "$side_manifest"; do
-  [ -f "$required" ] && [ ! -L "$required" ] || fail "missing regular closure input: $required"
-done
-grep -Fxq '# schema=oliphaunt.wasix-postmaster.sealed-side-modules.v1' "$side_manifest" ||
-  fail 'side-module manifest schema differs'
-
-declare -a side_modules=()
-declare -A admitted_side_paths=()
-manifest_records=0
-while IFS=$'\t' read -r canonical aliases abi_policy extra; do
-  case "$canonical" in
-    ''|'#'*) continue ;;
-  esac
-  [ -z "${extra:-}" ] || fail "side-module manifest has extra columns: $canonical"
-  [ -n "$aliases" ] && [ -n "$abi_policy" ] || fail "incomplete side-module record: $canonical"
-  case "$canonical" in
-    /*|*/../*|../*|*/./*|./*|*//*|*[$'\n\r']*) fail "unsafe canonical side path: $canonical" ;;
-  esac
-  [ -z "${admitted_side_paths[$canonical]+x}" ] || fail "duplicate side path: $canonical"
-  canonical_file="$install_dir/$canonical"
-  [ -f "$canonical_file" ] && [ ! -L "$canonical_file" ] ||
-    fail "missing regular canonical side module: $canonical"
-  admitted_side_paths[$canonical]=1
-  side_modules+=("$canonical")
-  manifest_records=$((manifest_records + 1))
-  if [ "$aliases" != - ]; then
-    IFS=',' read -r -a alias_paths <<<"$aliases"
-    [ "${#alias_paths[@]}" -gt 0 ] || fail "empty alias set: $canonical"
-    for alias_path in "${alias_paths[@]}"; do
-      case "$alias_path" in
-        ''|/*|*/../*|../*|*/./*|./*|*//*|*[$'\n\r']*) fail "unsafe side alias: $alias_path" ;;
-      esac
-      [ -z "${admitted_side_paths[$alias_path]+x}" ] || fail "duplicate side alias: $alias_path"
-      alias_file="$install_dir/$alias_path"
-      [ -f "$alias_file" ] || fail "missing side alias: $alias_path"
-      cmp -s "$canonical_file" "$alias_file" ||
-        fail "side alias bytes differ from $canonical: $alias_path"
-      admitted_side_paths[$alias_path]=1
-    done
-  fi
-done <"$side_manifest"
-[ "$manifest_records" -gt 0 ] || fail 'side-module manifest has no records'
-
-find "$install_dir/lib" \( -type f -o -type l \) \
-  \( -name '*.so' -o -name '*.so.*' \) -printf '%P\0' >"$stage/discovered-side-modules.unsorted"
-LC_ALL=C sort -z "$stage/discovered-side-modules.unsorted" >"$stage/discovered-side-modules.sorted"
-while IFS= read -r -d '' discovered; do
-  relative="lib/$discovered"
-  [ -n "${admitted_side_paths[$relative]+x}" ] ||
-    fail "installed side module is absent from the sealed graph: $relative"
-done <"$stage/discovered-side-modules.sorted"
-
-tool_target="$FRESH_WORK_ROOT/runtime/sealed-export-closure-target"
-fresh_require_managed_generated_path "$tool_target" sealed-export-closure-tool-target
-CARGO_TARGET_DIR="$tool_target" cargo build --locked --release --manifest-path "$tool_manifest"
-closure_tool="$tool_target/release/oliphaunt-wasix-sealed-export-closure"
-[ -x "$closure_tool" ] && [ ! -L "$closure_tool" ] || fail "missing built closure analyzer: $closure_tool"
-
-docker_bin="$(fresh_docker_bin)"
-fresh_ensure_docker_image
-docker_image_id="$(fresh_wasix_builder_image_id)" ||
-  fail 'could not resolve pinned WASIX builder image identity'
-readonly container_wasm_opt=/opt/wasixcc-home/.wasixcc/binaryen/bin/wasm-opt
-dce_identity="$($docker_bin run --rm "$docker_image_id" sha256sum "$container_wasm_opt")" ||
-  fail 'could not hash pinned wasm-opt'
-dce_sha256="${dce_identity%% *}"
-fresh_is_sha256 "$dce_sha256" || fail "invalid wasm-opt SHA-256: $dce_sha256"
-dce_version="$($docker_bin run --rm "$docker_image_id" "$container_wasm_opt" --version)" ||
-  fail 'could not read pinned wasm-opt version'
-[ "$(printf '%s\n' "$dce_version" | wc -l | tr -d ' ')" -eq 1 ] || fail 'wasm-opt version is multiline'
-
-cp -p "$postgres" "$stage/bin/postgres.seed"
-seed_proof="$stage/share/postgresql/wasix-postmaster.sealed-export.seed-proof.json"
-final_proof="$stage/share/postgresql/wasix-postmaster.sealed-export.final-proof.json"
-allowlist="$stage/share/postgresql/wasix-postmaster.sealed-export.allowlist"
-structure_receipt="$stage/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
-start_proof="$stage/share/postgresql/wasix-postmaster.sealed-export.start-proof.intermediate.json"
-concurrency_receipt="$stage/share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt"
-
-side_manifest_sha256="$(sha256sum "$side_manifest" | awk '{print $1}')"
-
-(
-  cd "$install_dir"
-  "$closure_tool" seal \
-    bin/postgres \
-    "$mandatory_policy" \
-    "$dlsym_policy" \
-    "$seed_proof" \
-    "$allowlist" \
-    "${side_modules[@]}"
-  "$closure_tool" rewrite \
-    bin/postgres \
-    "$allowlist" \
-    .oliphaunt-sealed-export-closure.pending/bin/postgres.stripped
-)
-
-docker_stage="$(fresh_docker_path_for "$stage")"
-"$docker_bin" run --rm \
-  --user "$(id -u):$(id -g)" \
-  -v "$REPO_ROOT:/work" \
-  -w /work \
-  "$docker_image_id" \
-  "$container_wasm_opt" \
-  "$docker_stage/bin/postgres.stripped" \
-  --remove-unused-module-elements \
-  --enable-bulk-memory \
-  --enable-threads \
-  --enable-mutable-globals \
-  --enable-exception-handling \
-  --enable-extended-const \
-  -o "$docker_stage/bin/postgres"
-chmod --reference="$postgres" "$stage/bin/postgres"
-
-(
-  cd "$install_dir"
-  "$closure_tool" attest-final \
-    bin/postgres \
-    .oliphaunt-sealed-export-closure.pending/bin/postgres \
-    "$mandatory_policy" \
-    "$dlsym_policy" \
-    "$allowlist" \
-    "$seed_proof" \
-    "$final_proof" \
-    "$structure_receipt" \
-    "$dce_sha256" \
-    "$dce_version" \
-    "$side_manifest_sha256" \
-    "${side_modules[@]}"
-)
-
-python3 "$FRESH_ROOT/runtime/bin/verify-postmaster-wasm-import.py" "$stage/bin/postgres"
-fresh_require_start_proof_tool "$FRESH_START_PROOF_BIN" "$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
-"$FRESH_START_PROOF_BIN" "$stage/bin/postgres" >"$start_proof"
-
-"$docker_bin" run --rm \
-  --user "$(id -u):$(id -g)" \
-  -v "$REPO_ROOT:/work" \
-  -w /work \
-  "$docker_image_id" \
-  python3 \
-  /work/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.py \
-  --expected-total "$expected_total" \
-  --latch-state-contract packed-atomic-v1 \
-  --wasm-dis /opt/wasixcc-home/.wasixcc/binaryen/bin/wasm-dis \
-  --receipt "$docker_stage/share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt" \
-  "$docker_stage/bin/postgres"
-
-for artifact in \
-  "$seed_proof" \
-  "$final_proof" \
-  "$allowlist" \
-  "$structure_receipt" \
-  "$start_proof" \
-  "$concurrency_receipt"
-do
-  [ -f "$artifact" ] && [ ! -L "$artifact" ] || fail "missing staged receipt: $artifact"
-done
-
-share_dir="$install_dir/share/postgresql"
-mkdir -p "$share_dir"
-[ ! -L "$share_dir" ] || fail "unsafe publication directory: $share_dir"
-
-# Copy every predecessor before changing the live prefix. BACKUPS_COMPLETE is a
-# durable write-ahead boundary: before it, cleanup may discard the stage;
-# after it, cleanup can restore the exact predecessor generation.
-for relative in "${publication_relatives[@]}"; do
-  destination="$install_dir/$relative"
-  backup="$stage/originals/$relative"
-  absent="$stage/originals/$relative.absent"
-  mkdir -p "$(dirname "$backup")"
-  if [ -e "$destination" ] || [ -L "$destination" ]; then
-    [ -f "$destination" ] && [ ! -L "$destination" ] ||
-      fail "unsafe predecessor publication path: $destination"
-    cp -p -- "$destination" "$backup"
-    fsync_paths "$backup" "$(dirname "$backup")"
-  else
-    : >"$absent"
-    fsync_paths "$absent" "$(dirname "$absent")"
-  fi
-done
-fsync_tree_directories "$stage/originals"
-: >"$stage/BACKUPS_COMPLETE"
-fsync_paths "$stage/BACKUPS_COMPLETE" "$stage/originals" "$stage"
-
-# De-admit the predecessor first. Publish the rewritten module and auxiliary
-# proofs, make them durable, mark READY, and only then atomically publish the
-# structural receipt that admits the new generation.
-remove_live_file "$structure_relative"
-for relative in "${publication_relatives[@]}"; do
-  [ "$relative" != "$structure_relative" ] || continue
-  atomic_publish_file "$stage/$relative" "$relative"
-done
-fsync_paths "$stage/$structure_relative" "$(dirname "$stage/$structure_relative")"
-: >"$stage/READY_TO_ADMIT"
-fsync_paths "$stage/READY_TO_ADMIT" "$stage"
-atomic_publish_file "$stage/$structure_relative" "$structure_relative"
-publish_completion
-publish_complete=1
-
-printf 'sealed exact main-module export closure: module=%s receipt=%s\n' \
-  "$postgres" "$share_dir/wasix-postmaster.sealed-export.structure.receipt"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-core-exports.test.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-core-exports.test.sh
deleted file mode 100755
index d41ba9bc1..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-core-exports.test.sh
+++ /dev/null
@@ -1,142 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
-wrapper="$project_root/bin/seal-wasix-core-exports.sh"
-build_script="$project_root/bin/build-wasix-core.sh"
-tool_manifest="$project_root/tools/sealed-export-closure/Cargo.toml"
-runtime_roots="$project_root/runtime/policies/sealed-main-runtime-exports.v1.txt"
-dlsym_roots="$project_root/runtime/policies/sealed-main-dlsym-exports.v1.txt"
-side_manifest="$project_root/runtime/policies/sealed-side-modules.v1.tsv"
-
-bash -n "$wrapper"
-bash -n "$build_script"
-"$wrapper" --help >/dev/null
-
-test_target="$(mktemp -d)"
-cleanup() {
-  status=$?
-  trap - EXIT
-  rm -rf -- "$test_target"
-  exit "$status"
-}
-trap cleanup EXIT
-CARGO_TARGET_DIR="$test_target" cargo test --locked --manifest-path "$tool_manifest"
-
-python3 - "$runtime_roots" "$dlsym_roots" "$side_manifest" "$build_script" "$wrapper" <<'PY'
-import pathlib
-import sys
-
-runtime_path, dlsym_path, side_path, build_path, wrapper_path = map(pathlib.Path, sys.argv[1:])
-
-
-def names(path: pathlib.Path) -> list[str]:
-    raw = path.read_bytes()
-    assert raw.endswith(b"\n") and b"\r" not in raw
-    values = []
-    for line in raw.decode().splitlines():
-        value = line.split("#", 1)[0].strip()
-        if value:
-            assert not any(char.isspace() for char in value)
-            values.append(value)
-    assert len(values) == len(set(values))
-    return values
-
-
-runtime = set(names(runtime_path))
-assert runtime == {
-    "__data_end",
-    "__tls_align",
-    "__tls_base",
-    "__tls_size",
-    "__wasm_apply_data_relocs",
-    "__wasm_call_ctors",
-    "__wasm_init_memory",
-    "__wasm_init_tls",
-    "__wasm_signal",
-    "_start",
-    "wasi_thread_start",
-    "ResetLatch",
-    "SetLatch",
-    "WaitEventSetWait",
-}
-assert names(dlsym_path) == []
-
-raw = side_path.read_bytes()
-assert raw.endswith(b"\n") and b"\r" not in raw
-lines = [
-    line
-    for line in raw.decode().splitlines()
-    if line and not line.startswith("#")
-]
-assert lines == [
-    "lib/libpq.so.5.18\tlib/libpq.so,lib/libpq.so.5\tpublic-libpq-abi",
-    "lib/postgresql/cyrillic_and_mic.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/dict_snowball.so\t-\tpostgresql-server-extension",
-    "lib/postgresql/euc2004_sjis2004.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/euc_cn_and_mic.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/euc_jp_and_sjis.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/euc_kr_and_mic.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/euc_tw_and_big5.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/latin2_and_win1250.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/latin_and_mic.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/plpgsql.so\t-\tpostgresql-server-extension",
-    "lib/postgresql/utf8_and_big5.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_cyrillic.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_euc2004.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_euc_cn.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_euc_jp.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_euc_kr.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_euc_tw.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_gb18030.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_gbk.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_iso8859.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_iso8859_1.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_johab.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_sjis.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_sjis2004.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_uhc.so\t-\tpostgresql-encoding-conversion",
-    "lib/postgresql/utf8_and_win.so\t-\tpostgresql-encoding-conversion",
-]
-
-build = build_path.read_text(encoding="utf-8")
-pipeline_markers = [
-    '"$FRESH_ROOT/bin/seal-wasix-core-exports.sh"',
-    '"$FRESH_ROOT/bin/seal-wasix-linear-memory.sh"',
-    'final_start_proof="$proof_dir/wasix-postmaster.start-proof.json"',
-    'final_concurrency_receipt="$proof_dir/wasix-postmaster.final-wasm-concurrency.receipt"',
-]
-positions = [build.rindex(marker) for marker in pipeline_markers]
-assert positions == sorted(positions), positions
-assert "schema=oliphaunt.wasix-postmaster.guest-build.v5" in build
-guest_fields = [
-    "docker_image_id",
-    "final_wasm_concurrency_receipt_sha256",
-    "linear_memory_profile_id",
-    "linear_memory_install_receipt_sha256",
-    "postgres_tag",
-]
-guest_positions = [build.rindex(f"printf '{field}=") for field in guest_fields]
-assert guest_positions == sorted(guest_positions), guest_positions
-
-wrapper = wrapper_path.read_text(encoding="utf-8")
-assert 'sealed-export-publication.v1' in wrapper
-assert 'READY_TO_ADMIT' in wrapper
-assert 'BACKUPS_COMPLETE' in wrapper
-assert 'cmp -s "$staged_receipt" "$live_receipt"' in wrapper
-assert 'done < <(' not in wrapper
-assert '>"$stage/discovered-side-modules.unsorted"' in wrapper
-assert 'sort -z "$stage/discovered-side-modules.unsorted"' in wrapper
-publication_markers = [
-    ': >"$stage/BACKUPS_COMPLETE"',
-    'remove_live_file "$structure_relative"',
-    'atomic_publish_file "$stage/$relative" "$relative"',
-    ': >"$stage/READY_TO_ADMIT"',
-    'atomic_publish_file "$stage/$structure_relative" "$structure_relative"',
-]
-positions = [wrapper.rindex(marker) for marker in publication_markers]
-assert positions == sorted(positions), positions
-PY
-
-printf 'sealed export closure policy and analyzer tests passed\n'
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-core-exports.transaction.test.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-core-exports.transaction.test.sh
deleted file mode 100755
index 92a711260..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-core-exports.transaction.test.sh
+++ /dev/null
@@ -1,1038 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-# Exercise the real publication transaction with tiny deterministic producer
-# fixtures.  The command shims do not replace transaction operations: they
-# only make the expensive Cargo/Docker analyzers local and inject SIGKILL at
-# externally observable filesystem boundaries.
-
-project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
-repo_root="$(cd "$project_root/../../../.." && pwd -P)"
-wrapper="$project_root/bin/seal-wasix-core-exports.sh"
-side_manifest="$project_root/runtime/policies/sealed-side-modules.v1.tsv"
-managed_root="$repo_root/target/oliphaunt-wasix-postmaster"
-
-fail() {
-  printf 'sealed export transaction test: %s\n' "$*" >&2
-  exit 1
-}
-
-for command in bash cmp cp find flock grep mktemp python3 sha256sum sort; do
-  command -v "$command" >/dev/null 2>&1 || fail "missing test command: $command"
-done
-[ -x "$wrapper" ] || fail "missing executable wrapper: $wrapper"
-[ -f "$side_manifest" ] && [ ! -L "$side_manifest" ] ||
-  fail "missing regular side-module manifest: $side_manifest"
-
-real_cp="$(command -v cp)"
-real_mv="$(command -v mv)"
-real_rm="$(command -v rm)"
-real_python3="$(command -v python3)"
-real_sha256sum="$(command -v sha256sum)"
-tx_docker_recipe_sha256="$(
-  bash -c 'source "$1/lib/common.sh"; fresh_wasix_builder_recipe_sha256' \
-    bash "$project_root"
-)" || fail 'could not derive fixture WASIX builder recipe identity'
-
-mkdir -p "$managed_root"
-[ -d "$managed_root" ] && [ ! -L "$managed_root" ] ||
-  fail "unsafe managed test root: $managed_root"
-test_root="$(mktemp -d "$managed_root/sealed-export-transaction-test.XXXXXX")"
-fake_bin="$test_root/fake-bin"
-mkdir -p "$fake_bin"
-active_pids=""
-
-cleanup() {
-  status=$?
-  trap - EXIT HUP INT TERM
-  find "$test_root" -type f -name '*.gate-release' -exec touch {} + 2>/dev/null || :
-  for pid in $active_pids; do
-    kill -TERM "$pid" 2>/dev/null || :
-  done
-  for pid in $active_pids; do
-    wait "$pid" 2>/dev/null || :
-  done
-  "$real_rm" -rf -- "$test_root"
-  exit "$status"
-}
-trap cleanup EXIT
-trap 'exit 129' HUP
-trap 'exit 130' INT
-trap 'exit 143' TERM
-
-fake_closure_tool="$test_root/fake-sealed-export-closure"
-fake_closure_attest="$test_root/fake-sealed-export-attest.py"
-fake_start_proof="$test_root/fake-start-proof"
-executor_receipt="$test_root/postmaster-executor-build.receipt"
-
-cat >"$fake_closure_attest" <<'PY'
-#!/usr/bin/env python3
-import json
-import pathlib
-import runpy
-import sys
-
-(
-    fixture_helper,
-    install_raw,
-    staged_raw,
-    mandatory_raw,
-    dlsym_raw,
-    seed_raw,
-    final_raw,
-    allowlist_raw,
-    structure_raw,
-    dce_sha256,
-    dce_version,
-    side_manifest_sha256,
-    *side_paths,
-) = sys.argv[1:]
-fixture = runpy.run_path(fixture_helper)
-digest = fixture["digest"]
-json_bytes = fixture["json_bytes"]
-module_summary = fixture["module_summary"]
-proof = fixture["proof"]
-snapshot = fixture["snapshot"]
-
-install = pathlib.Path(install_raw)
-staged = pathlib.Path(staged_raw)
-mandatory = digest(pathlib.Path(mandatory_raw).read_bytes())
-dlsym = digest(pathlib.Path(dlsym_raw).read_bytes())
-sides = [
-    module_summary(
-        relative,
-        digest((install / relative).read_bytes()),
-        (install / relative).stat().st_size,
-    )
-    for relative in side_paths
-]
-final_data = staged.read_bytes()
-final_sha256 = digest(final_data)
-final_main = module_summary("bin/postgres", final_sha256, len(final_data))
-seed_sha256 = digest(b"pre-dce-fixture\0" + final_data)
-seed_main = module_summary("bin/postgres", seed_sha256, len(final_data) + 16)
-seed_data = json_bytes(proof(seed_main, sides, mandatory, dlsym))
-final_proof_data = json_bytes(proof(final_main, sides, mandatory, dlsym))
-pathlib.Path(seed_raw).write_bytes(seed_data)
-pathlib.Path(final_raw).write_bytes(final_proof_data)
-allowlist = pathlib.Path(allowlist_raw)
-receipt = {
-    "schema": "oliphaunt.wasix-postmaster.sealed-export-structure.v1",
-    "policy-id": "oliphaunt.wasix-postmaster.sealed-export-closure.v1",
-    "analyzer-version": "fixture",
-    "analyzer-binary-sha256": "0" * 64,
-    "dce-tool-sha256": dce_sha256,
-    "dce-tool-version": dce_version,
-    "dce-passes": ["--remove-unused-module-elements"],
-    "mandatory-policy-sha256": mandatory,
-    "declared-main-dlsym-policy-sha256": dlsym,
-    "side-manifest-sha256": side_manifest_sha256,
-    "allowlist-sha256": digest(allowlist.read_bytes()),
-    "seed-proof-sha256": digest(seed_data),
-    "final-proof-sha256": digest(final_proof_data),
-    "seed": snapshot(seed_sha256, len(final_data) + 16),
-    "final-module": snapshot(final_sha256, len(final_data)),
-    "sides": [
-        {"path": side["path"], "sha256": side["sha256"]} for side in sides
-    ],
-}
-pathlib.Path(structure_raw).write_text(
-    json.dumps(receipt, indent=2, sort_keys=True) + "\n", encoding="utf-8"
-)
-PY
-chmod 755 "$fake_closure_attest"
-
-cat >"$fake_closure_tool" <<'EOF'
-#!/usr/bin/env bash
-set -euo pipefail
-
-command="$1"
-shift
-case "$command" in
-  seal)
-    seed_proof="$4"
-    allowlist="$5"
-    printf '{"schema":"fixture-seed-proof-v1"}\n' >"$seed_proof"
-    printf 'fixture-export\n' >"$allowlist"
-    ;;
-  rewrite)
-    main_module="$1"
-    output="$3"
-    "$TX_REAL_CP" -p -- "$main_module" "$output"
-    # A valid empty-name custom section makes the successor byte-distinct.
-    printf '\000\001\000' >>"$output"
-    ;;
-  attest-final)
-    install="$PWD"
-    staged_module="$2"
-    mandatory_policy="$3"
-    dlsym_policy="$4"
-    allowlist="$5"
-    seed_proof="$6"
-    final_proof="$7"
-    structure_receipt="$8"
-    dce_sha256="$9"
-    dce_version="${10}"
-    side_manifest_sha256="${11}"
-    shift 11
-    "$TX_REAL_PYTHON3" "$TX_FAKE_CLOSURE_ATTEST" \
-      "$TX_EXPORT_FIXTURE_HELPER" \
-      "$install" "$staged_module" "$mandatory_policy" "$dlsym_policy" \
-      "$seed_proof" "$final_proof" "$allowlist" "$structure_receipt" \
-      "$dce_sha256" "$dce_version" "$side_manifest_sha256" "$@"
-    ;;
-  *)
-    printf 'unexpected fake closure command: %s\n' "$command" >&2
-    exit 2
-    ;;
-esac
-EOF
-chmod 755 "$fake_closure_tool"
-
-cat >"$fake_start_proof" <<'EOF'
-#!/usr/bin/env bash
-set -euo pipefail
-
-if [ "$#" -eq 1 ] && [ "$1" = --policy-id ]; then
-  printf '%s\n' llvm-shared-memory-init-restricted-effects.v1
-  exit 0
-fi
-[ "$#" -eq 1 ] || exit 2
-module_sha256="$("$TX_REAL_SHA256SUM" "$1")"
-module_sha256="${module_sha256%% *}"
-printf '{"schema":"fixture-start-proof-v1","module-sha256":"%s"}\n' \
-  "$module_sha256"
-EOF
-chmod 755 "$fake_start_proof"
-
-zero_sha=0000000000000000000000000000000000000000000000000000000000000000
-start_proof_sha256="$("$real_sha256sum" "$fake_start_proof")"
-start_proof_sha256="${start_proof_sha256%% *}"
-cat >"$executor_receipt" <"$fake_bin/cargo" <<'EOF'
-#!/usr/bin/env bash
-set -euo pipefail
-
-printf '%s\n' "$$" >>"$TX_CARGO_LOG"
-if [ "${TX_FAIL_BUILD:-0}" = 1 ]; then
-  exit 23
-fi
-if [ -n "${TX_GATE_READY:-}" ]; then
-  : >"$TX_GATE_READY"
-  while [ ! -e "$TX_GATE_RELEASE" ]; do
-    sleep 0.02
-  done
-fi
-mkdir -p "$CARGO_TARGET_DIR/release"
-"$TX_REAL_CP" -p -- \
-  "$TX_FAKE_CLOSURE_TOOL" \
-  "$CARGO_TARGET_DIR/release/oliphaunt-wasix-sealed-export-closure"
-chmod 755 "$CARGO_TARGET_DIR/release/oliphaunt-wasix-sealed-export-closure"
-EOF
-chmod 755 "$fake_bin/cargo"
-
-cat >"$fake_bin/docker" <<'EOF'
-#!/usr/bin/env bash
-set -euo pipefail
-
-map_path() {
-  case "$1" in
-    /work) printf '%s\n' "$TX_REPO_ROOT" ;;
-    /work/*) printf '%s/%s\n' "$TX_REPO_ROOT" "${1#/work/}" ;;
-    *) printf '%s\n' "$1" ;;
-  esac
-}
-
-case "${1:-}" in
-  image)
-    [ "${2:-}" = inspect ] || exit 2
-    case "${4:-}" in
-      *'.Id'*)
-        printf 'sha256:%s|%s\n' \
-          "$TX_DOCKER_IMAGE_SHA256" "$TX_DOCKER_RECIPE_SHA256"
-        ;;
-      *) printf '%s\n' "$TX_DOCKER_RECIPE_SHA256" ;;
-    esac
-    exit 0
-    ;;
-  run)
-    shift
-    while [ "$#" -gt 0 ]; do
-      case "$1" in
-        --rm) shift ;;
-        --user|-v|-w) shift 2 ;;
-        *) image="$1"; shift; break ;;
-      esac
-    done
-    [ -n "${image:-}" ] && [ "$#" -gt 0 ] || exit 2
-    command="$1"
-    shift
-    case "$command" in
-      sha256sum)
-        printf '%s  %s\n' \
-          1111111111111111111111111111111111111111111111111111111111111111 \
-          "${1:-/opt/fake-wasm-opt}"
-        ;;
-      */wasm-opt)
-        if [ "${1:-}" = --version ]; then
-          printf 'fixture-wasm-opt 1\n'
-          exit 0
-        fi
-        input="$(map_path "$1")"
-        output=""
-        while [ "$#" -gt 0 ]; do
-          if [ "$1" = -o ]; then
-            shift
-            output="$(map_path "$1")"
-            break
-          fi
-          shift
-        done
-        [ -n "$output" ] || exit 2
-        "$TX_REAL_CP" -p -- "$input" "$output"
-        ;;
-      python3)
-        receipt=""
-        postgres=""
-        while [ "$#" -gt 0 ]; do
-          if [ "$1" = --receipt ]; then
-            shift
-            receipt="$(map_path "$1")"
-          fi
-          postgres="$1"
-          shift
-        done
-        postgres="$(map_path "$postgres")"
-        [ -n "$receipt" ] && [ -f "$postgres" ] || exit 2
-        postgres_sha256="$("$TX_REAL_SHA256SUM" "$postgres")"
-        postgres_sha256="${postgres_sha256%% *}"
-        cat >"$receipt" <&2
-        exit 2
-        ;;
-    esac
-    ;;
-  *)
-    exit 2
-    ;;
-esac
-EOF
-chmod 755 "$fake_bin/docker"
-
-cat >"$fake_bin/cp" <<'EOF'
-#!/usr/bin/env bash
-set -euo pipefail
-
-previous=""
-last=""
-for argument in "$@"; do
-  previous="$last"
-  last="$argument"
-done
-source_path="$previous"
-destination="$last"
-stage="$WASIX_INSTALL_DIR/.oliphaunt-sealed-export-closure.pending"
-share="$WASIX_INSTALL_DIR/share/postgresql"
-trip=0
-case "${TX_KILL_AT:-}" in
-  de-admit)
-    [ "$source_path" = "$stage/bin/postgres" ] &&
-      [ "$destination" = "$WASIX_INSTALL_DIR/bin/.postgres.oliphaunt-sealed-export.pending" ] &&
-      trip=1
-    ;;
-  READY)
-    [ "$source_path" = "$stage/share/postgresql/wasix-postmaster.sealed-export.structure.receipt" ] &&
-      [ "$destination" = "$share/.wasix-postmaster.sealed-export.structure.receipt.oliphaunt-sealed-export.pending" ] &&
-      trip=1
-    ;;
-esac
-if [ "$trip" -eq 1 ]; then
-  printf '%s\n' "$TX_KILL_AT" >>"$TX_HOOK_LOG"
-  kill -KILL "$PPID"
-  exit 137
-fi
-exec "$TX_REAL_CP" "$@"
-EOF
-chmod 755 "$fake_bin/cp"
-
-cat >"$fake_bin/mv" <<'EOF'
-#!/usr/bin/env bash
-set -euo pipefail
-
-previous=""
-last=""
-for argument in "$@"; do
-  previous="$last"
-  last="$argument"
-done
-source_path="$previous"
-destination="$last"
-stage="$WASIX_INSTALL_DIR/.oliphaunt-sealed-export-closure.pending"
-initializing="$WASIX_INSTALL_DIR/.oliphaunt-sealed-export-closure.initializing"
-discarded="$WASIX_INSTALL_DIR/.oliphaunt-sealed-export-closure.discarded"
-
-trip_before=0
-trip_after=0
-case "${TX_KILL_AT:-}" in
-  init)
-    [ "$source_path" = "$initializing" ] && [ "$destination" = "$stage" ] && trip_before=1
-    ;;
-  payload:*)
-    relative="${TX_KILL_AT#payload:}"
-    live="$WASIX_INSTALL_DIR/$relative"
-    temporary="$(dirname "$live")/.$(basename "$live").oliphaunt-sealed-export.pending"
-    [ "$source_path" = "$temporary" ] && [ "$destination" = "$live" ] && trip_after=1
-    ;;
-  rollback:*)
-    relative="${TX_KILL_AT#rollback:}"
-    live="$WASIX_INSTALL_DIR/$relative"
-    temporary="$(dirname "$live")/.$(basename "$live").oliphaunt-sealed-export.pending"
-    [ "$source_path" = "$temporary" ] && [ "$destination" = "$live" ] && trip_after=1
-    ;;
-  completion)
-    case "$source_path:$destination" in
-      *.completed.pending:*.completed) trip_after=1 ;;
-    esac
-    ;;
-  tombstone)
-    [ "$source_path" = "$stage" ] && [ "$destination" = "$discarded" ] && trip_after=1
-    ;;
-esac
-
-if [ "$trip_before" -eq 1 ]; then
-  printf '%s\n' "$TX_KILL_AT" >>"$TX_HOOK_LOG"
-  kill -KILL "$PPID"
-  exit 137
-fi
-if [ "$trip_after" -eq 1 ]; then
-  "$TX_REAL_MV" "$@"
-  printf '%s\n' "$TX_KILL_AT" >>"$TX_HOOK_LOG"
-  kill -KILL "$PPID"
-  exit 137
-fi
-exec "$TX_REAL_MV" "$@"
-EOF
-chmod 755 "$fake_bin/mv"
-
-cat >"$fake_bin/rm" <<'EOF'
-#!/usr/bin/env bash
-set -euo pipefail
-
-last=""
-for argument in "$@"; do
-  last="$argument"
-done
-structure="$WASIX_INSTALL_DIR/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
-if [ "${TX_KILL_AT:-}" = backup ] && [ "$last" = "$structure" ]; then
-  printf '%s\n' "$TX_KILL_AT" >>"$TX_HOOK_LOG"
-  kill -KILL "$PPID"
-  exit 137
-fi
-exec "$TX_REAL_RM" "$@"
-EOF
-chmod 755 "$fake_bin/rm"
-
-cat >"$fake_bin/python3" <<'EOF'
-#!/usr/bin/env bash
-set -euo pipefail
-
-stage="$WASIX_INSTALL_DIR/.oliphaunt-sealed-export-closure.pending"
-backups_complete="$stage/BACKUPS_COMPLETE"
-partial_backup="$stage/originals/share/postgresql/wasix-postmaster.sealed-export.final-proof.json"
-if [ "${TX_KILL_AT:-}" = backup ] &&
-  [ "${1:-}" = - ] && [ "${2:-}" = "$backups_complete" ]; then
-  "$TX_REAL_PYTHON3" "$@"
-  printf '%s\n' "$TX_KILL_AT" >>"$TX_HOOK_LOG"
-  kill -KILL "$PPID"
-  exit 137
-fi
-if [ "${TX_KILL_AT:-}" = backup-partial ] &&
-  [ "${1:-}" = - ] && [ "${2:-}" = "$partial_backup" ]; then
-  "$TX_REAL_PYTHON3" "$@"
-  printf '%s\n' "$TX_KILL_AT" >>"$TX_HOOK_LOG"
-  kill -KILL "$PPID"
-  exit 137
-fi
-if [ "${TX_KILL_AT:-}" = admission ] &&
-  [ "${1:-}" = - ] &&
-  [ "${2:-}" = oliphaunt.wasix-postmaster.sealed-export-completion.v2 ]; then
-  printf '%s\n' "$TX_KILL_AT" >>"$TX_HOOK_LOG"
-  kill -KILL "$PPID"
-  exit 137
-fi
-exec "$TX_REAL_PYTHON3" "$@"
-EOF
-chmod 755 "$fake_bin/python3"
-
-publication_relatives=(
-  bin/postgres
-  share/postgresql/wasix-postmaster.sealed-export.seed-proof.json
-  share/postgresql/wasix-postmaster.sealed-export.final-proof.json
-  share/postgresql/wasix-postmaster.sealed-export.allowlist
-  share/postgresql/wasix-postmaster.sealed-export.start-proof.intermediate.json
-  share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt
-  share/postgresql/wasix-postmaster.sealed-export.structure.receipt
-)
-structure_relative=share/postgresql/wasix-postmaster.sealed-export.structure.receipt
-
-write_minimal_postmaster() {
-  "$real_python3" - "$1" <<'PY'
-import pathlib
-import sys
-
-def uleb(value: int) -> bytes:
-    out = bytearray()
-    while True:
-        byte = value & 0x7f
-        value >>= 7
-        out.append(byte | (0x80 if value else 0))
-        if not value:
-            return bytes(out)
-
-def vector(items: list[bytes]) -> bytes:
-    return uleb(len(items)) + b"".join(items)
-
-def name(value: str) -> bytes:
-    raw = value.encode("utf-8")
-    return uleb(len(raw)) + raw
-
-def function_type(parameters: tuple[int, ...]) -> bytes:
-    return b"\x60" + vector([bytes([value]) for value in parameters]) + vector([b"\x7f"])
-
-types = [function_type((0x7f, 0x7e, 0x7e, 0x7f))]
-imports = [name("oliphaunt_postmaster_v1") + name("fd_sync_range") + b"\x00" + uleb(0)]
-
-def section(identifier: int, payload: bytes) -> bytes:
-    return bytes([identifier]) + uleb(len(payload)) + payload
-
-module = b"\x00asm\x01\x00\x00\x00" + section(1, vector(types)) + section(2, vector(imports))
-path = pathlib.Path(sys.argv[1])
-path.write_bytes(module)
-PY
-}
-
-create_fixture() {
-  case_root="$1"
-  install="$case_root/install"
-  mkdir -p "$install/bin" "$install/lib/postgresql" "$install/share/postgresql" "$case_root/work"
-  write_minimal_postmaster "$install/bin/postgres"
-  chmod 755 "$install/bin/postgres"
-
-  while IFS=$'\t' read -r canonical aliases _abi extra; do
-    case "$canonical" in
-      ''|'#'*) continue ;;
-    esac
-    [ -z "${extra:-}" ] || fail "unexpected side-manifest column: $canonical"
-    mkdir -p "$(dirname "$install/$canonical")"
-    printf 'fixture-side-module-v1\n' >"$install/$canonical"
-    if [ "$aliases" != - ]; then
-      IFS=',' read -r -a alias_paths <<<"$aliases"
-      for alias_path in "${alias_paths[@]}"; do
-        mkdir -p "$(dirname "$install/$alias_path")"
-        "$real_cp" -p -- "$install/$canonical" "$install/$alias_path"
-      done
-    fi
-  done <"$side_manifest"
-
-  printf 'old-seed-proof\n' >"$install/share/postgresql/wasix-postmaster.sealed-export.seed-proof.json"
-  printf 'old-final-proof\n' >"$install/share/postgresql/wasix-postmaster.sealed-export.final-proof.json"
-  printf 'old-allowlist\n' >"$install/share/postgresql/wasix-postmaster.sealed-export.allowlist"
-  printf 'old-start-proof\n' >"$install/share/postgresql/wasix-postmaster.sealed-export.start-proof.intermediate.json"
-  printf 'old-concurrency-receipt\n' >"$install/share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt"
-}
-
-make_linear_memory_descendant() {
-  "$real_python3" - "$1/install" "$side_manifest" <<'PY'
-import hashlib
-import json
-import pathlib
-import sys
-
-install = pathlib.Path(sys.argv[1])
-side_manifest = pathlib.Path(sys.argv[2])
-side_paths = [
-    line.split("\t", 1)[0]
-    for line in side_manifest.read_text(encoding="utf-8").splitlines()
-    if line and not line.startswith("#")
-]
-paths = sorted(["bin/postgres", *side_paths])
-
-def digest(data: bytes) -> str:
-    return hashlib.sha256(data).hexdigest()
-
-records = []
-for relative in paths:
-    path = install / relative
-    source = path.read_bytes()
-    sealed = source + b"\x00\x01\x00"
-    path.write_bytes(sealed)
-    records.append(
-        {
-            "path": relative,
-            "source-module-sha256": digest(source),
-            "module-sha256": digest(sealed),
-            "initial-pages": 1,
-            "maximum-pages": 4096,
-            "maximum-bytes": 268435456,
-            "shared": True,
-            "import-module": "env",
-            "import-name": "memory",
-            "transformation": "pinned-wasixcc-65536-to-embedded-4096-reversible-v1",
-        }
-    )
-
-def closure_hash(field: str) -> str:
-    value = hashlib.sha256()
-    for item in (
-        "oliphaunt.wasix-postmaster.linear-memory-install-closure.v1",
-        field,
-    ):
-        encoded = item.encode()
-        value.update(len(encoded).to_bytes(8, "big"))
-        value.update(encoded)
-    for record in records:
-        for item in (record["path"], record[field]):
-            encoded = item.encode()
-            value.update(len(encoded).to_bytes(8, "big"))
-            value.update(encoded)
-    return value.hexdigest()
-
-predecessor_relative = "share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
-predecessor = (install / predecessor_relative).read_bytes()
-receipt = {
-    "schema": "oliphaunt.wasix-postmaster.linear-memory-install.v1",
-    "profile-id": "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1",
-    "address-width": "wasm32",
-    "supported-host-pointer-width": "u64",
-    "maximum-pages": 4096,
-    "maximum-bytes": 268435456,
-    "static-bound-pages": 65536,
-    "static-offset-guard-bytes": 2147483648,
-    "static-access-lowering": "wasmer-llvm-unchecked-reservation-and-guard-v1",
-    "requires-shared": True,
-    "requires-import": "env.memory",
-    "excludes-wasm32-end-wrap": True,
-    "predecessor-export-closure-receipt": predecessor_relative,
-    "predecessor-export-closure-receipt-sha256": digest(predecessor),
-    "source-module-closure-sha256": closure_hash("source-module-sha256"),
-    "module-closure-sha256": closure_hash("module-sha256"),
-    "module-count": len(records),
-    "modules": records,
-}
-output = install / "share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
-output.write_text(json.dumps(receipt, indent=2, sort_keys=True) + "\n", encoding="utf-8")
-PY
-}
-
-write_snapshot() {
-  install="$1"
-  output="$2"
-  : >"$output"
-  for relative in "${publication_relatives[@]}"; do
-    if [ -f "$install/$relative" ] && [ ! -L "$install/$relative" ]; then
-      value="$("$real_sha256sum" "$install/$relative")"
-      printf '%s\t%s\n' "${value%% *}" "$relative" >>"$output"
-    elif [ ! -e "$install/$relative" ] && [ ! -L "$install/$relative" ]; then
-      printf 'absent\t%s\n' "$relative" >>"$output"
-    else
-      fail "snapshot source is neither regular nor absent: $install/$relative"
-    fi
-  done
-}
-
-snapshot_hash() {
-  snapshot="$1"
-  relative="$2"
-  awk -F '\t' -v expected="$relative" '$2 == expected { count += 1; value = $1 } END { if (count != 1) exit 2; print value }' "$snapshot"
-}
-
-assert_matches() {
-  install="$1"
-  snapshot="$2"
-  relative="$3"
-  expected="$(snapshot_hash "$snapshot" "$relative")"
-  if [ "$expected" = absent ]; then
-    assert_absent "$install/$relative"
-    return
-  fi
-  [ -f "$install/$relative" ] && [ ! -L "$install/$relative" ] ||
-    fail "missing regular publication file: $install/$relative"
-  actual="$("$real_sha256sum" "$install/$relative")"
-  actual="${actual%% *}"
-  [ "$actual" = "$expected" ] ||
-    fail "$relative does not match $(basename "$snapshot")"
-}
-
-assert_snapshot() {
-  install="$1"
-  snapshot="$2"
-  for relative in "${publication_relatives[@]}"; do
-    assert_matches "$install" "$snapshot" "$relative"
-  done
-}
-
-assert_absent() {
-  path="$1"
-  [ ! -e "$path" ] && [ ! -L "$path" ] || fail "expected absent path: $path"
-}
-
-assert_transaction_clean() {
-  case_root="$1"
-  install="$case_root/install"
-  for suffix in pending initializing discarded; do
-    assert_absent "$install/.oliphaunt-sealed-export-closure.$suffix"
-  done
-  if find "$install" -type f -name '*.oliphaunt-sealed-export.pending' -print -quit | grep -q .; then
-    fail "publication temporary survived under $install"
-  fi
-  if find "$case_root/work/runtime/publication-locks" -type f -name '*.completed.pending' -print -quit 2>/dev/null | grep -q .; then
-    fail "completion temporary survived under $case_root/work"
-  fi
-}
-
-invoke_wrapper() {
-  case_root="$1"
-  kill_at="$2"
-  fail_build="$3"
-  gate_ready="$4"
-  gate_release="$5"
-  install="$case_root/install"
-  mkdir -p "$case_root/work"
-  env \
-    PATH="$fake_bin:$PATH" \
-    FRESH_WORK_ROOT="$case_root/work" \
-    FRESH_START_PROOF_BIN="$fake_start_proof" \
-    FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT="$executor_receipt" \
-    FRESH_WASIX_DOCKER_IMAGE=fixture-wasix-image \
-    WASIX_INSTALL_DIR="$install" \
-    TX_CARGO_LOG="$case_root/cargo.log" \
-    TX_DOCKER_IMAGE_SHA256=1111111111111111111111111111111111111111111111111111111111111111 \
-    TX_DOCKER_RECIPE_SHA256="$tx_docker_recipe_sha256" \
-    TX_FAIL_BUILD="$fail_build" \
-    TX_GATE_READY="$gate_ready" \
-    TX_GATE_RELEASE="$gate_release" \
-    TX_HOOK_LOG="$case_root/hook.log" \
-    TX_KILL_AT="$kill_at" \
-    TX_EXPORT_FIXTURE_HELPER="$project_root/testdata/make-sealed-export-fixture.py" \
-    TX_FAKE_CLOSURE_ATTEST="$fake_closure_attest" \
-    TX_FAKE_CLOSURE_TOOL="$fake_closure_tool" \
-    TX_REAL_CP="$real_cp" \
-    TX_REAL_MV="$real_mv" \
-    TX_REAL_RM="$real_rm" \
-    TX_REAL_PYTHON3="$real_python3" \
-    TX_REAL_SHA256SUM="$real_sha256sum" \
-    TX_REPO_ROOT="$repo_root" \
-    "$wrapper" --install-dir "$install" --expected-total 7
-}
-
-run_crash() {
-  case_root="$1"
-  boundary="$2"
-  set +e
-  invoke_wrapper "$case_root" "$boundary" 0 '' '' >"$case_root/crash.out" 2>&1
-  status=$?
-  set -e
-  [ "$status" -ne 0 ] || fail "$boundary fault unexpectedly committed"
-  [ -f "$case_root/hook.log" ] || fail "$boundary fault hook was not reached"
-  [ "$(cat "$case_root/hook.log")" = "$boundary" ] ||
-    fail "$boundary fault hook was reached more than once or at the wrong boundary"
-}
-
-recover_rollback() {
-  case_root="$1"
-  set +e
-  invoke_wrapper "$case_root" '' 1 '' '' >"$case_root/recover.out" 2>&1
-  status=$?
-  set -e
-  [ "$status" -ne 0 ] || fail "rollback recovery unexpectedly reached a new commit"
-  assert_snapshot "$case_root/install" "$old_snapshot"
-  assert_transaction_clean "$case_root"
-}
-
-recover_committed() {
-  case_root="$1"
-  cargo_count_before=0
-  if [ -f "$case_root/cargo.log" ]; then
-    cargo_count_before="$(wc -l <"$case_root/cargo.log" | tr -d ' ')"
-  fi
-  invoke_wrapper "$case_root" '' 1 '' '' >"$case_root/recover.out" 2>&1 ||
-    fail "admitted generation recovery failed"
-  assert_snapshot "$case_root/install" "$new_snapshot"
-  assert_transaction_clean "$case_root"
-  completed_count="$(find "$case_root/work/runtime/publication-locks" -type f -name '*.completed' | wc -l | tr -d ' ')"
-  [ "$completed_count" -eq 1 ] || fail "admission recovery did not publish one completion record"
-  cargo_count_after="$(wc -l <"$case_root/cargo.log" | tr -d ' ')"
-  [ "$cargo_count_after" -eq "$cargo_count_before" ] ||
-    fail "admission recovery unexpectedly rebuilt the generation"
-}
-
-wait_for_path() {
-  path="$1"
-  attempts=0
-  while [ ! -e "$path" ]; do
-    attempts=$((attempts + 1))
-    [ "$attempts" -lt 500 ] || fail "timed out waiting for $path"
-    sleep 0.02
-  done
-}
-
-# Establish exact old and new byte generations once.  Every crash fixture is
-# separately created and compared against these deterministic snapshots.
-golden="$test_root/golden"
-create_fixture "$golden"
-old_snapshot="$test_root/old.snapshot"
-new_snapshot="$test_root/new.snapshot"
-write_snapshot "$golden/install" "$old_snapshot"
-invoke_wrapper "$golden" '' 0 '' '' >"$golden/commit.out" 2>&1 ||
-  fail "golden transaction failed"
-write_snapshot "$golden/install" "$new_snapshot"
-assert_transaction_clean "$golden"
-
-init_case="$test_root/crash-init"
-create_fixture "$init_case"
-run_crash "$init_case" init
-[ -d "$init_case/install/.oliphaunt-sealed-export-closure.initializing" ] ||
-  fail "initialization crash lacks the durable initializing tree"
-assert_absent "$init_case/install/.oliphaunt-sealed-export-closure.pending"
-assert_snapshot "$init_case/install" "$old_snapshot"
-recover_rollback "$init_case"
-
-partial_backup_case="$test_root/crash-partial-backup"
-create_fixture "$partial_backup_case"
-run_crash "$partial_backup_case" backup-partial
-[ -f "$partial_backup_case/install/.oliphaunt-sealed-export-closure.pending/originals/share/postgresql/wasix-postmaster.sealed-export.final-proof.json" ] ||
-  fail "partial-backup crash did not reach the selected durable backup"
-assert_absent "$partial_backup_case/install/.oliphaunt-sealed-export-closure.pending/BACKUPS_COMPLETE"
-assert_snapshot "$partial_backup_case/install" "$old_snapshot"
-recover_rollback "$partial_backup_case"
-
-backup_case="$test_root/crash-backup"
-create_fixture "$backup_case"
-run_crash "$backup_case" backup
-[ -f "$backup_case/install/.oliphaunt-sealed-export-closure.pending/BACKUPS_COMPLETE" ] ||
-  fail "backup crash lacks durable BACKUPS_COMPLETE"
-assert_snapshot "$backup_case/install" "$old_snapshot"
-recover_rollback "$backup_case"
-
-deadmit_case="$test_root/crash-de-admit"
-create_fixture "$deadmit_case"
-run_crash "$deadmit_case" de-admit
-assert_absent "$deadmit_case/install/$structure_relative"
-for relative in "${publication_relatives[@]}"; do
-  [ "$relative" = "$structure_relative" ] ||
-    assert_matches "$deadmit_case/install" "$old_snapshot" "$relative"
-done
-recover_rollback "$deadmit_case"
-
-payload_relatives=(
-  bin/postgres
-  share/postgresql/wasix-postmaster.sealed-export.seed-proof.json
-  share/postgresql/wasix-postmaster.sealed-export.final-proof.json
-  share/postgresql/wasix-postmaster.sealed-export.allowlist
-  share/postgresql/wasix-postmaster.sealed-export.start-proof.intermediate.json
-  share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt
-)
-payload_index=0
-for crashed_payload in "${payload_relatives[@]}"; do
-  payload_case="$test_root/crash-payload-$payload_index"
-  create_fixture "$payload_case"
-  run_crash "$payload_case" "payload:$crashed_payload"
-  assert_absent "$payload_case/install/$structure_relative"
-  check_index=0
-  for relative in "${payload_relatives[@]}"; do
-    if [ "$check_index" -le "$payload_index" ]; then
-      assert_matches "$payload_case/install" "$new_snapshot" "$relative"
-    else
-      assert_matches "$payload_case/install" "$old_snapshot" "$relative"
-    fi
-    check_index=$((check_index + 1))
-  done
-  recover_rollback "$payload_case"
-  payload_index=$((payload_index + 1))
-done
-
-ready_case="$test_root/crash-READY"
-create_fixture "$ready_case"
-run_crash "$ready_case" READY
-[ -f "$ready_case/install/.oliphaunt-sealed-export-closure.pending/READY_TO_ADMIT" ] ||
-  fail "READY crash lacks durable READY_TO_ADMIT"
-assert_absent "$ready_case/install/$structure_relative"
-for relative in "${publication_relatives[@]}"; do
-  [ "$relative" = "$structure_relative" ] ||
-    assert_matches "$ready_case/install" "$new_snapshot" "$relative"
-done
-recover_rollback "$ready_case"
-
-# Interrupt rollback itself after restoring a middle payload.  A third
-# invocation must safely repeat the rollback from its beginning and recover
-# the exact predecessor generation.
-rollback_case="$test_root/crash-rollback"
-create_fixture "$rollback_case"
-run_crash "$rollback_case" READY
-: >"$rollback_case/hook.log"
-rollback_relative=share/postgresql/wasix-postmaster.sealed-export.final-proof.json
-set +e
-invoke_wrapper "$rollback_case" "rollback:$rollback_relative" 1 '' '' \
-  >"$rollback_case/rollback-crash.out" 2>&1
-status=$?
-set -e
-[ "$status" -ne 0 ] || fail "rollback interruption unexpectedly completed"
-[ "$(cat "$rollback_case/hook.log")" = "rollback:$rollback_relative" ] ||
-  fail "rollback interruption did not reach the selected payload"
-assert_absent "$rollback_case/install/$structure_relative"
-for relative in \
-  bin/postgres \
-  share/postgresql/wasix-postmaster.sealed-export.seed-proof.json \
-  share/postgresql/wasix-postmaster.sealed-export.final-proof.json
-do
-  assert_matches "$rollback_case/install" "$old_snapshot" "$relative"
-done
-for relative in \
-  share/postgresql/wasix-postmaster.sealed-export.allowlist \
-  share/postgresql/wasix-postmaster.sealed-export.start-proof.intermediate.json \
-  share/postgresql/wasix-postmaster.sealed-export.concurrency.intermediate.receipt
-do
-  assert_matches "$rollback_case/install" "$new_snapshot" "$relative"
-done
-recover_rollback "$rollback_case"
-
-admission_case="$test_root/crash-admission"
-create_fixture "$admission_case"
-run_crash "$admission_case" admission
-[ -f "$admission_case/install/.oliphaunt-sealed-export-closure.pending/READY_TO_ADMIT" ] ||
-  fail "admission crash lacks durable READY_TO_ADMIT"
-assert_snapshot "$admission_case/install" "$new_snapshot"
-if find "$admission_case/work/runtime/publication-locks" -type f -name '*.completed' -print -quit 2>/dev/null | grep -q .; then
-  fail "admission fault occurred after completion publication"
-fi
-recover_committed "$admission_case"
-
-completion_case="$test_root/crash-completion"
-create_fixture "$completion_case"
-run_crash "$completion_case" completion
-assert_snapshot "$completion_case/install" "$new_snapshot"
-[ -d "$completion_case/install/.oliphaunt-sealed-export-closure.pending" ] ||
-  fail "completion crash unexpectedly discarded the recovery journal"
-completed_count="$(find "$completion_case/work/runtime/publication-locks" -type f -name '*.completed' | wc -l | tr -d ' ')"
-[ "$completed_count" -eq 1 ] || fail "completion crash did not reach the completion rename"
-recover_committed "$completion_case"
-
-tombstone_case="$test_root/crash-tombstone"
-create_fixture "$tombstone_case"
-run_crash "$tombstone_case" tombstone
-assert_snapshot "$tombstone_case/install" "$new_snapshot"
-assert_absent "$tombstone_case/install/.oliphaunt-sealed-export-closure.pending"
-[ -d "$tombstone_case/install/.oliphaunt-sealed-export-closure.discarded" ] ||
-  fail "tombstone crash did not preserve the renamed transaction journal"
-recover_committed "$tombstone_case"
-
-# A linear-memory successor intentionally makes the export completion record
-# stale because the module bytes changed.  The wrapper must validate that
-# descendant chain and return without trying to reseal its predecessor.
-descendant_case="$test_root/linear-memory-descendant"
-create_fixture "$descendant_case"
-invoke_wrapper "$descendant_case" '' 0 '' '' >"$descendant_case/seal.out" 2>&1 ||
-  fail "descendant predecessor seal failed"
-make_linear_memory_descendant "$descendant_case"
-descendant_snapshot="$test_root/descendant.snapshot"
-write_snapshot "$descendant_case/install" "$descendant_snapshot"
-cargo_count_before="$(wc -l <"$descendant_case/cargo.log" | tr -d ' ')"
-invoke_wrapper "$descendant_case" '' 1 '' '' >"$descendant_case/recheck.out" 2>&1 ||
-  fail "valid linear-memory descendant was not accepted"
-cargo_count_after="$(wc -l <"$descendant_case/cargo.log" | tr -d ' ')"
-[ "$cargo_count_after" -eq "$cargo_count_before" ] ||
-  fail "linear-memory descendant caused its export predecessor to be resealed"
-grep -Fq 'validated linear-memory descendant' "$descendant_case/recheck.out" ||
-  fail "linear-memory descendant did not use the strict successor path"
-assert_snapshot "$descendant_case/install" "$descendant_snapshot"
-assert_transaction_clean "$descendant_case"
-
-# Hold the first invocation inside the producer after it owns the publication
-# lock.  A second invocation must neither run Cargo nor mutate the prefix; once
-# released, it must observe the first invocation's durable completion.
-concurrent_case="$test_root/concurrent"
-create_fixture "$concurrent_case"
-gate_ready="$concurrent_case/producer.gate-ready"
-gate_release="$concurrent_case/producer.gate-release"
-invoke_wrapper "$concurrent_case" '' 0 "$gate_ready" "$gate_release" \
-  >"$concurrent_case/first.out" 2>&1 &
-first_pid=$!
-active_pids="$active_pids $first_pid"
-wait_for_path "$gate_ready"
-invoke_wrapper "$concurrent_case" '' 0 '' '' \
-  >"$concurrent_case/second.out" 2>&1 &
-second_pid=$!
-active_pids="$active_pids $second_pid"
-sleep 0.2
-kill -0 "$second_pid" 2>/dev/null || fail "second invocation did not wait for the publication lock"
-cargo_count="$(wc -l <"$concurrent_case/cargo.log" | tr -d ' ')"
-[ "$cargo_count" -eq 1 ] || fail "concurrent invocation entered the producer while the lock was held"
-assert_snapshot "$concurrent_case/install" "$old_snapshot"
-: >"$gate_release"
-wait "$first_pid" || fail "first concurrent invocation failed"
-wait "$second_pid" || fail "second concurrent invocation failed"
-active_pids=""
-cargo_count="$(wc -l <"$concurrent_case/cargo.log" | tr -d ' ')"
-[ "$cargo_count" -eq 1 ] || fail "second concurrent invocation rebuilt an already committed generation"
-grep -Fq 'validated existing sealed export closure' "$concurrent_case/second.out" ||
-  fail "second concurrent invocation did not validate the committed generation"
-assert_snapshot "$concurrent_case/install" "$new_snapshot"
-assert_transaction_clean "$concurrent_case"
-
-printf 'sealed export transaction crash-recovery and exclusion tests passed\n'
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-linear-memory.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-linear-memory.sh
deleted file mode 100755
index 4f8fd0074..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-linear-memory.sh
+++ /dev/null
@@ -1,296 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/common.sh"
-
-usage() {
-  cat <<'EOF'
-Usage: seal-wasix-linear-memory.sh [options]
-
-Seal every installed WASIX WebAssembly module to the versioned product memory
-ABI after all code-rewriting passes have completed.
-
-Options:
-  --install-dir DIR          WASIX PostgreSQL prefix (default: WASIX_INSTALL_DIR)
-  --predecessor-receipt FILE Exact sealed-export structural receipt
-  -h, --help                 Show this help
-EOF
-}
-
-fail() {
-  printf 'WASIX linear-memory sealer: %s\n' "$*" >&2
-  exit 2
-}
-
-install_dir="$WASIX_INSTALL_DIR"
-predecessor_receipt=""
-while [ "$#" -gt 0 ]; do
-  case "$1" in
-    --install-dir|--predecessor-receipt)
-      option="$1"
-      shift
-      [ "$#" -gt 0 ] || fail "$option requires a value"
-      case "$option" in
-        --install-dir) install_dir="$1" ;;
-        --predecessor-receipt) predecessor_receipt="$1" ;;
-      esac
-      ;;
-    -h|--help)
-      usage
-      exit 0
-      ;;
-    *) fail "unknown argument: $1" ;;
-  esac
-  shift
-done
-
-[ -n "$predecessor_receipt" ] || fail '--predecessor-receipt is required'
-for command in find flock od python3 sha256sum sort; do
-  fresh_require_command "$command"
-done
-[ -d "$install_dir" ] && [ ! -L "$install_dir" ] ||
-  fail "missing non-symlink install prefix: $install_dir"
-install_dir="$(cd "$install_dir" && pwd -P)"
-fresh_require_managed_generated_path "$install_dir" WASIX_INSTALL_DIR
-
-stage="$install_dir/.oliphaunt-linear-memory.pending"
-fresh_require_managed_generated_path "$stage" linear-memory-stage
-transaction_tool="$FRESH_ROOT/lib/linear_memory_transaction.py"
-[ -f "$transaction_tool" ] && [ ! -L "$transaction_tool" ] ||
-  fail "missing regular linear-memory transaction helper: $transaction_tool"
-lock_path="$install_dir/.oliphaunt-linear-memory.lock"
-exec {linear_memory_lock_fd}>"$lock_path"
-chmod 0600 "$lock_path"
-flock -n "$linear_memory_lock_fd" ||
-  fail "another linear-memory transaction holds the install-prefix lock: $lock_path"
-python3 "$transaction_tool" recover \
-  --install-root "$install_dir" \
-  --stage "$stage" >/dev/null ||
-  fail 'could not recover an interrupted linear-memory transaction'
-
-[ -f "$predecessor_receipt" ] && [ ! -L "$predecessor_receipt" ] ||
-  fail "missing regular predecessor receipt: $predecessor_receipt"
-predecessor_receipt="$(cd "$(dirname "$predecessor_receipt")" && pwd -P)/$(basename "$predecessor_receipt")"
-expected_predecessor="$install_dir/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
-[ "$predecessor_receipt" = "$expected_predecessor" ] ||
-  fail "predecessor receipt must be the canonical sealed-export receipt: $expected_predecessor"
-
-memory_tool="$FRESH_MEMORY_PROFILE_BIN"
-fresh_require_memory_profile_tool "$memory_tool" "$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT"
-aggregate_destination="$install_dir/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
-if [ -e "$aggregate_destination" ] || [ -L "$aggregate_destination" ]; then
-  [ -f "$aggregate_destination" ] && [ ! -L "$aggregate_destination" ] ||
-    fail "existing linear-memory receipt is not a regular file: $aggregate_destination"
-  python3 "$FRESH_ROOT/lib/sealed_export_chain.py" \
-    --install-root "$install_dir" \
-    --project-root "$FRESH_ROOT" \
-    --allow-linear-memory-descendant ||
-    fail 'existing linear-memory descendant proof chain is invalid'
-  python3 - "$aggregate_destination" "$install_dir" "$memory_tool" <<'PY'
-import json
-from pathlib import Path, PurePosixPath
-import subprocess
-import sys
-
-receipt_path, install_root, tool = sys.argv[1:]
-with open(receipt_path, encoding="utf-8") as stream:
-    receipt = json.load(stream)
-for module in receipt["modules"]:
-    relative = module["path"]
-    pure = PurePosixPath(relative)
-    if pure.is_absolute() or any(part in ("", ".", "..") for part in pure.parts):
-        raise SystemExit(f"unsafe existing linear-memory module path: {relative!r}")
-    subprocess.run(
-        [tool, "verify", str(Path(install_root).joinpath(*pure.parts))],
-        check=True,
-        stdout=subprocess.DEVNULL,
-    )
-PY
-  printf 'WASIX linear-memory profile already sealed: receipt=%s\n' \
-    "$aggregate_destination"
-  exit 0
-fi
-
-python3 "$FRESH_ROOT/lib/sealed_export_chain.py" \
-  --install-root "$install_dir" \
-  --project-root "$FRESH_ROOT" ||
-  fail 'sealed-export predecessor proof chain is invalid'
-profile_json="$($memory_tool --profile-json)" || fail 'could not read memory-tool profile'
-predecessor_sha256="$(sha256sum "$predecessor_receipt" | awk '{print $1}')"
-fresh_is_sha256 "$predecessor_sha256" || fail 'predecessor receipt hash is invalid'
-predecessor_relative="${predecessor_receipt#"$install_dir"/}"
-
-python3 "$transaction_tool" init \
-  --install-root "$install_dir" \
-  --stage "$stage" ||
-  fail 'could not initialize the linear-memory transaction'
-index="$stage/modules.tsv"
-: >"$index"
-transaction_active=1
-cleanup() {
-  local status=$?
-  trap - EXIT
-  if [ "${transaction_active:-0}" -eq 1 ] && \
-    { [ -e "$stage" ] || [ -L "$stage" ]; }; then
-    if ! python3 "$transaction_tool" recover \
-      --install-root "$install_dir" \
-      --stage "$stage" >/dev/null; then
-      printf 'WASIX linear-memory sealer: automatic transaction recovery failed: %s\n' \
-        "$stage" >&2
-      status=2
-    fi
-  fi
-  exit "$status"
-}
-trap cleanup EXIT
-
-module_count=0
-module_paths="$stage/module-paths.nul"
-find "$install_dir/bin" "$install_dir/lib" -type f -print0 | \
-  LC_ALL=C sort -z >"$module_paths" ||
-  fail 'could not enumerate the installed WebAssembly module closure'
-while IFS= read -r -d '' module; do
-  magic="$(od -An -tx1 -N4 "$module" | tr -d ' \n')"
-  [ "$magic" = 0061736d ] || continue
-  relative="${module#"$install_dir"/}"
-  case "$relative" in
-    ''|/*|*/../*|../*|*/./*|./*|*//*|*$'\t'*|*$'\n'*|*$'\r'*)
-      fail "unsafe installed module path: $relative"
-      ;;
-  esac
-  output="$stage/modules/$relative"
-  receipt="$stage/receipts/$relative.json"
-  mkdir -p "$(dirname "$output")" "$(dirname "$receipt")"
-  "$memory_tool" seal --output "$output" --receipt "$receipt" "$module"
-  chmod --reference="$module" "$output"
-  printf '%s\t%s\n' "$relative" "${receipt#"$stage"/}" >>"$index"
-  module_count=$((module_count + 1))
-done <"$module_paths"
-[ "$module_count" -gt 0 ] || fail 'no installed WebAssembly modules were found'
-
-for required in \
-  bin/initdb \
-  bin/postgres \
-  lib/libpq.so.5.18 \
-  lib/postgresql/dict_snowball.so \
-  lib/postgresql/plpgsql.so
-do
-  awk -F '\t' -v expected="$required" '$1 == expected { count += 1 } END { exit count == 1 ? 0 : 1 }' "$index" ||
-    fail "required carrier module was not sealed exactly once: $required"
-done
-
-aggregate="$stage/wasix-postmaster.linear-memory-profile.receipt.json"
-PROFILE_JSON="$profile_json" python3 - \
-  "$stage" "$index" "$predecessor_relative" "$predecessor_sha256" "$aggregate" <<'PY'
-import hashlib
-import json
-import os
-import sys
-from pathlib import Path
-
-stage = Path(sys.argv[1])
-index = Path(sys.argv[2])
-predecessor_path = sys.argv[3]
-predecessor_sha256 = sys.argv[4]
-output = Path(sys.argv[5])
-profile = json.loads(os.environ["PROFILE_JSON"])
-expected_profile = {
-    "address-width": "wasm32",
-    "supported-host-pointer-width": "u64",
-    "maximum-pages": 4096,
-    "maximum-bytes": 268435456,
-    "static-bound-pages": 65536,
-    "static-offset-guard-bytes": 2147483648,
-    "requires-shared": True,
-    "requires-import": "env.memory",
-    "excludes-wasm32-end-wrap": True,
-    "static-access-lowering": "wasmer-llvm-unchecked-reservation-and-guard-v1",
-}
-for key, expected in expected_profile.items():
-    if profile.get(key) != expected:
-        raise SystemExit(f"memory-tool profile mismatch for {key}: {profile.get(key)!r}")
-profile_id = profile.get("id")
-if profile_id != "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1":
-    raise SystemExit(f"memory-tool profile id mismatch: {profile_id!r}")
-
-records = []
-for line in index.read_text(encoding="utf-8").splitlines():
-    relative, receipt_relative = line.split("\t")
-    receipt_bytes = (stage / receipt_relative).read_bytes()
-    receipt = json.loads(receipt_bytes)
-    if receipt.get("schema") != "oliphaunt.wasix-postmaster.linear-memory-module.v1":
-        raise SystemExit(f"module receipt schema mismatch: {relative}")
-    if receipt.get("profile-id") != profile_id:
-        raise SystemExit(f"module profile mismatch: {relative}")
-    if receipt.get("source-module-sha256") is None:
-        raise SystemExit(f"module receipt has no predecessor hash: {relative}")
-    records.append({
-        "path": relative,
-        "source-module-sha256": receipt["source-module-sha256"],
-        "module-sha256": receipt["module-sha256"],
-        "initial-pages": receipt["initial-pages"],
-        "maximum-pages": receipt["maximum-pages"],
-        "maximum-bytes": receipt["maximum-bytes"],
-        "shared": receipt["shared"],
-        "import-module": receipt["import-module"],
-        "import-name": receipt["import-name"],
-        "transformation": receipt["transformation"],
-    })
-records.sort(key=lambda record: record["path"])
-if len(records) != len({record["path"] for record in records}):
-    raise SystemExit("duplicate installed module paths")
-
-def closure_hash(hash_field):
-    digest = hashlib.sha256()
-    for value in ("oliphaunt.wasix-postmaster.linear-memory-install-closure.v1", hash_field):
-        encoded = value.encode()
-        digest.update(len(encoded).to_bytes(8, "big"))
-        digest.update(encoded)
-    for record in records:
-        for value in (record["path"], record[hash_field]):
-            encoded = value.encode()
-            digest.update(len(encoded).to_bytes(8, "big"))
-            digest.update(encoded)
-    return digest.hexdigest()
-
-aggregate = {
-    "schema": "oliphaunt.wasix-postmaster.linear-memory-install.v1",
-    "profile-id": profile_id,
-    **expected_profile,
-    "predecessor-export-closure-receipt": predecessor_path,
-    "predecessor-export-closure-receipt-sha256": predecessor_sha256,
-    "source-module-closure-sha256": closure_hash("source-module-sha256"),
-    "module-closure-sha256": closure_hash("module-sha256"),
-    "module-count": len(records),
-    "modules": records,
-}
-with output.open("x", encoding="utf-8", newline="\n") as stream:
-    json.dump(aggregate, stream, indent=2, sort_keys=True)
-    stream.write("\n")
-    stream.flush()
-    os.fsync(stream.fileno())
-PY
-
-[ "$(sha256sum "$predecessor_receipt" | awk '{print $1}')" = "$predecessor_sha256" ] ||
-  fail 'predecessor export receipt changed while modules were sealed'
-while IFS=$'\t' read -r relative receipt_relative; do
-  "$memory_tool" verify "$stage/modules/$relative" >/dev/null
-done <"$index"
-
-[ "$(sha256sum "$predecessor_receipt" | awk '{print $1}')" = "$predecessor_sha256" ] ||
-  fail 'predecessor export receipt changed before transaction preparation'
-
-python3 "$transaction_tool" prepare \
-  --install-root "$install_dir" \
-  --stage "$stage" \
-  --aggregate "$aggregate" ||
-  fail 'could not prepare durable linear-memory rollback state'
-python3 "$transaction_tool" publish \
-  --install-root "$install_dir" \
-  --stage "$stage" ||
-  fail 'could not publish the linear-memory transaction'
-transaction_active=0
-trap - EXIT
-printf 'sealed WASIX linear-memory profile: modules=%s receipt=%s\n' \
-  "$module_count" "$aggregate_destination"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-linear-memory.test.sh b/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-linear-memory.test.sh
deleted file mode 100755
index 20e4a0b99..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-linear-memory.test.sh
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
-source "$project_root/lib/common.sh"
-memory_tool="$FRESH_MEMORY_PROFILE_BIN"
-[ -f "$memory_tool" ] && [ -x "$memory_tool" ] || {
-  printf 'missing executable memory-profile tool: %s\n' "$memory_tool" >&2
-  exit 2
-}
-repo_root="$(cd "$project_root/../../../.." && pwd -P)"
-mkdir -p "$repo_root/target/oliphaunt-wasix-postmaster"
-test_root="$(mktemp -d "$repo_root/target/oliphaunt-wasix-postmaster/linear-memory-test.XXXXXX")"
-cleanup() {
-  chmod -R u+w "$test_root" 2>/dev/null || true
-  rm -rf -- "$test_root"
-}
-trap cleanup EXIT
-
-make_fixture() {
-  local name="$1"
-  local root="$test_root/$name"
-  local receipt="$root/executor.receipt"
-  mkdir -p \
-    "$root/install/bin" \
-    "$root/install/lib/postgresql" \
-    "$root/install/share/postgresql"
-  python3 - "$root" <<'PY'
-import os
-import sys
-from pathlib import Path
-
-root = Path(sys.argv[1])
-module = bytes.fromhex(
-    "0061736d01000000"
-    "0212"
-    "01"
-    "03656e76"
-    "066d656d6f7279"
-    "02"
-    "03"
-    "01"
-    "808004"
-)
-for relative in (
-    "bin/initdb",
-    "bin/postgres",
-    "lib/libpq.so.5.18",
-    "lib/postgresql/dict_snowball.so",
-    "lib/postgresql/plpgsql.so",
-):
-    path = root / "install" / relative
-    path.write_bytes(module)
-    os.chmod(path, 0o755)
-PY
-  python3 "$project_root/testdata/make-sealed-export-fixture.py" \
-    --install-root "$root/install" \
-    --project-root "$project_root"
-  memory_hash="$(sha256sum "$memory_tool" | awk '{print $1}')"
-  python3 - "$receipt" "$memory_hash" <<'PY'
-import sys
-
-path, memory_hash = sys.argv[1:]
-fields = [
-    ("schema", "oliphaunt.wasix-postmaster.postmaster-executor-build.v3"),
-    ("build_recipe_sha256", "1" * 64),
-    ("wasmer_build_receipt_sha256", "2" * 64),
-    ("wasmer_source_commit", "3" * 40),
-    ("wasmer_patch_sha256", "4" * 64),
-    ("wasmer_prepared_signature_sha256", "5" * 64),
-    ("wasmer_cargo_lock_sha256", "6" * 64),
-    ("runtime_abi_id", "7" * 64),
-    ("artifact_abi_version", "21"),
-    ("executor_package", "oliphaunt-wasix-postmaster-executor"),
-    ("executor_binary", "oliphaunt-wasix-postmaster-executor"),
-    ("executor_features", "product-executor"),
-    ("executor_role", "postmaster-product"),
-    ("runtime_policy_id", "fixture"),
-    ("cli_contract", "fixture"),
-    ("executor_binary_sha256", "8" * 64),
-    ("start_proof_binary", "oliphaunt-wasix-start-proof"),
-    ("start_proof_features", "start-proof-tool"),
-    ("start_proof_policy", "fixture"),
-    ("start_proof_binary_sha256", "9" * 64),
-    ("memory_profile_binary", "oliphaunt-wasix-memory-profile"),
-    ("memory_profile_features", "memory-profile-tool"),
-    ("linear_memory_profile_id", "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1"),
-    ("memory_profile_binary_sha256", memory_hash),
-    ("postmaster_compiler_binary", "oliphaunt-wasix-postmaster-compiler"),
-    ("postmaster_compiler_features", "product-compiler"),
-    ("compiler_cpu_policy", "generic-baseline"),
-    ("compiler_cpu_features", "none"),
-    ("postmaster_compiler_binary_sha256", "a" * 64),
-    ("host_platform", "fixture"),
-    ("host_abi", "fixture"),
-    ("rustc_host", "fixture"),
-    ("rustc_version", "fixture"),
-]
-with open(path, "x", encoding="utf-8", newline="\n") as stream:
-    for key, value in fields:
-        stream.write(f"{key}={value}\n")
-PY
-  printf '%s\n' "$root"
-}
-
-invoke() {
-  local root="$1"
-  FRESH_WORK_ROOT="$test_root/work" \
-  WASIX_INSTALL_DIR="$root/install" \
-  FRESH_MEMORY_PROFILE_BIN="$memory_tool" \
-  FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT="$root/executor.receipt" \
-    "$project_root/bin/seal-wasix-linear-memory.sh" \
-      --install-dir "$root/install" \
-      --predecessor-receipt \
-        "$root/install/share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
-}
-
-success_root="$(make_fixture success)"
-invoke "$success_root"
-python3 - "$success_root/install" "$memory_tool" <<'PY'
-import json
-import subprocess
-import sys
-from pathlib import Path
-
-root = Path(sys.argv[1])
-tool = sys.argv[2]
-receipt = json.loads(
-    (root / "share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json").read_text()
-)
-assert receipt["module-count"] == 29
-assert [record["path"] for record in receipt["modules"]] == sorted(
-    record["path"] for record in receipt["modules"]
-)
-for record in receipt["modules"]:
-    assert record["source-module-sha256"] != record["module-sha256"]
-    subprocess.run([tool, "verify", root / record["path"]], check=True, stdout=subprocess.DEVNULL)
-PY
-receipt_before="$(sha256sum "$success_root/install/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json" | awk '{print $1}')"
-invoke "$success_root" >/dev/null
-receipt_after="$(sha256sum "$success_root/install/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json" | awk '{print $1}')"
-[ "$receipt_before" = "$receipt_after" ] || {
-  echo 'idempotent linear-memory sealing changed the aggregate receipt' >&2
-  exit 1
-}
-
-exec {held_lock_fd}>"$success_root/install/.oliphaunt-linear-memory.lock"
-flock -n "$held_lock_fd"
-if invoke "$success_root" >/dev/null 2>&1; then
-  echo 'linear-memory sealer ignored its install-prefix lock' >&2
-  exit 1
-fi
-flock -u "$held_lock_fd"
-exec {held_lock_fd}>&-
-
-stale_root="$(make_fixture stale-staging)"
-python3 "$project_root/lib/linear_memory_transaction.py" init \
-  --install-root "$stale_root/install" \
-  --stage "$stale_root/install/.oliphaunt-linear-memory.pending"
-invoke "$stale_root" >/dev/null
-[ ! -e "$stale_root/install/.oliphaunt-linear-memory.pending" ] || {
-  echo 'linear-memory sealer did not recover an abandoned construction stage' >&2
-  exit 1
-}
-
-rollback_root="$(make_fixture rollback)"
-before="$(sha256sum "$rollback_root/install/bin/initdb" | awk '{print $1}')"
-chmod 0555 "$rollback_root/install/lib"
-if invoke "$rollback_root" >/dev/null 2>&1; then
-  echo 'expected publication failure with a read-only later module directory' >&2
-  exit 1
-fi
-chmod 0755 "$rollback_root/install/lib"
-after="$(sha256sum "$rollback_root/install/bin/initdb" | awk '{print $1}')"
-[ "$after" = "$before" ] || {
-  echo 'publication rollback did not restore an earlier module' >&2
-  exit 1
-}
-[ ! -e "$rollback_root/install/share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json" ] || {
-  echo 'failed publication exposed an aggregate receipt' >&2
-  exit 1
-}
-[ ! -e "$rollback_root/install/.oliphaunt-linear-memory.pending" ] || {
-  echo 'failed publication left recoverable transaction state after rollback' >&2
-  exit 1
-}
-
-printf 'WASIX linear-memory sealer tests passed\n'
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/validate-sealed-loader-audit.py b/src/runtimes/liboliphaunt/wasix-postmaster/bin/validate-sealed-loader-audit.py
deleted file mode 100755
index 4f23b632e..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/validate-sealed-loader-audit.py
+++ /dev/null
@@ -1,693 +0,0 @@
-#!/usr/bin/env python3
-
-"""Validate sealed Wasmer activation evidence for a release platform."""
-
-from __future__ import annotations
-
-import argparse
-import hashlib
-import json
-import os
-import re
-import secrets
-import stat
-import sys
-from pathlib import Path
-from typing import Any
-
-sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "lib"))
-from durable_publication import (  # noqa: E402
-    PublicationError,
-    PublicationSource,
-    publish_identified,
-    remove_private,
-    stable_regular_bytes,
-    write_bytes,
-)
-
-
-SCHEMA = "oliphaunt.wasix-postmaster.sealed-loader-receipt.v2"
-SUMMARY_SCHEMA = "oliphaunt.wasix-postmaster.attested-start-runtime-summary.v1"
-MEMORY_IMAGE_SCHEMA = "oliphaunt.wasix-postmaster.memory-image.v2"
-DETERMINISTIC_START_PROOF_SCHEMA = (
-    "oliphaunt.wasix-postmaster.deterministic-start-proof.v1"
-)
-RESULT_SCHEMA = "oliphaunt.wasix-postmaster.sealed-loader-audit-validation.v4"
-MAX_U64 = (1 << 64) - 1
-SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
-FIELDS = {
-    "schema",
-    "pid",
-    "artifact_kind",
-    "module_sha256",
-    "snapshot_mode",
-    "logical_bytes",
-    "source_bytes_read",
-    "source_bytes_written",
-    "snapshot_bytes_written",
-    "mapping_bytes_hashed",
-    "sync_calls",
-    "read_advice_applicable",
-    "read_advice_supported",
-    "read_advice_calls",
-    "read_advice_successes",
-    "read_advice_first_errno",
-    "source_cache_eviction_applicable",
-    "source_cache_eviction_supported",
-    "source_cache_eviction_calls",
-    "source_cache_eviction_successes",
-    "source_cache_eviction_errno",
-    "snapshot_cache_eviction_applicable",
-    "snapshot_cache_eviction_supported",
-    "snapshot_cache_eviction_calls",
-    "snapshot_cache_eviction_successes",
-    "snapshot_cache_eviction_errno",
-    "mapping_cache_eviction_applicable",
-    "mapping_cache_eviction_supported",
-    "mapping_cache_eviction_calls",
-    "mapping_cache_eviction_successes",
-    "mapping_cache_eviction_errno",
-    "residency_after_hash_inspect",
-    "residency_after_archive_release",
-    "source_residency_before_eviction",
-    "source_residency_after_eviction",
-    "residency_after_eviction",
-    "write_policy",
-}
-SUMMARY_FIELDS = {
-    "schema",
-    "pid",
-    "artifact_kind",
-    "terminal",
-    "module_sha256",
-    "memory_image_schema",
-    "proof_sha256",
-    "proof_output_sha256",
-    "mapped_size",
-    "ordinary_start_completed_instances",
-    "fresh_zeroed_instances",
-    "nonfresh_instances",
-    "validation_attempts",
-    "full_compare_attempts",
-    "full_compare_successes",
-    "full_compare_failures",
-    "compared_bytes",
-    "reuse_successes",
-    "reuse_failures",
-    "skipped_bytes",
-    "remap_successes",
-    "remap_failures",
-    "counter_overflow",
-}
-SUMMARY_COUNTER_FIELDS = (
-    "ordinary_start_completed_instances",
-    "fresh_zeroed_instances",
-    "nonfresh_instances",
-    "validation_attempts",
-    "full_compare_attempts",
-    "full_compare_successes",
-    "full_compare_failures",
-    "compared_bytes",
-    "reuse_successes",
-    "reuse_failures",
-    "skipped_bytes",
-    "remap_successes",
-    "remap_failures",
-)
-RESIDENCY_FIELDS = {
-    "state",
-    "page_size",
-    "total_pages",
-    "resident_pages",
-    "resident_bytes",
-    "errno",
-}
-DIRECT_MODES = {"direct-immutable-inode", "direct-read-only-filesystem"}
-PORTABLE_MODES = {
-    "aot": "streamed-copy",
-    "preinitialized-memory": "streamed-copy-sealed-backing",
-}
-SNAPSHOT_POLICIES = {"direct", "direct-immutable", "portable-copy"}
-EXECUTABLE_NAMES = ("runtime:initdb", "runtime:postgres")
-
-
-class ValidationError(Exception):
-    pass
-
-
-def require(condition: bool, message: str) -> None:
-    if not condition:
-        raise ValidationError(message)
-
-
-def duplicate_keys(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
-    result: dict[str, Any] = {}
-    for key, value in pairs:
-        require(key not in result, f"duplicate JSON field: {key}")
-        result[key] = value
-    return result
-
-
-def read_regular(path: Path, label: str) -> bytes:
-    try:
-        return stable_regular_bytes(path)
-    except PublicationError as error:
-        raise ValidationError(f"invalid {label}: {error}") from error
-
-
-def manifest_module_evidence(
-    manifest_data: bytes,
-) -> tuple[dict[str, str], dict[str, dict[str, Any]]]:
-    try:
-        manifest = json.loads(manifest_data.decode("utf-8"), object_pairs_hook=duplicate_keys)
-    except (UnicodeDecodeError, json.JSONDecodeError, ValidationError) as error:
-        raise ValidationError(f"invalid sealed manifest: {error}") from error
-    require(isinstance(manifest, dict), "sealed manifest must be an object")
-    artifacts = manifest.get("artifacts")
-    require(
-        isinstance(artifacts, list) and len(artifacts) >= len(EXECUTABLE_NAMES),
-        "sealed manifest artifact closure is incomplete",
-    )
-    modules: dict[str, str] = {}
-    for artifact in artifacts:
-        require(isinstance(artifact, dict), "sealed manifest artifact must be an object")
-        name = artifact.get("name")
-        require(
-            isinstance(name, str) and name.startswith("runtime:") and len(name) > 8,
-            "sealed manifest artifact name is invalid",
-        )
-        module_hash = artifact.get("module-sha256")
-        require(isinstance(module_hash, str) and SHA256_RE.fullmatch(module_hash), f"invalid module SHA-256 for {name}")
-        require(name not in modules, f"duplicate manifest artifact: {name}")
-        require(module_hash not in modules.values(), f"duplicate manifest module hash: {module_hash}")
-        modules[name] = module_hash
-    require(
-        all(name in modules for name in EXECUTABLE_NAMES),
-        "sealed manifest executable closure differs",
-    )
-    return modules, {}
-
-
-def exact_nonnegative(value: Any, label: str) -> int:
-    require(type(value) is int and value >= 0, f"{label} must be a nonnegative integer")
-    return value
-
-
-def exact_u64(value: Any, label: str) -> int:
-    require(
-        type(value) is int and 0 <= value <= MAX_U64,
-        f"{label} must be an unsigned 64-bit integer",
-    )
-    return value
-
-
-def exact_bool(value: Any, label: str) -> bool:
-    require(type(value) is bool, f"{label} must be a boolean")
-    return value
-
-
-def validate_advice(
-    record: dict[str, Any],
-    *,
-    prefix: str,
-    errno_field: str,
-    expected_applicable: bool,
-    expected_calls: int,
-    allow_unsupported: bool,
-    line_number: int,
-) -> tuple[int, int]:
-    label = f"{prefix} line {line_number}"
-    applicable = exact_bool(record[f"{prefix}_applicable"], f"{label} applicable")
-    supported = exact_bool(record[f"{prefix}_supported"], f"{label} supported")
-    calls = exact_nonnegative(record[f"{prefix}_calls"], f"{label} calls")
-    successes = exact_nonnegative(record[f"{prefix}_successes"], f"{label} successes")
-    errno = record[errno_field]
-    require(applicable is expected_applicable, f"{label} applicability differs")
-    require(successes <= calls, f"{label} successes exceed calls")
-    if not applicable:
-        require(calls == 0 and successes == 0 and errno is None, f"{label} issued an inapplicable call")
-        return calls, successes
-    if not supported:
-        require(allow_unsupported, f"{label} is unsupported")
-        require(
-            calls == 0 and successes == 0 and errno is None,
-            f"{label} unsupported shape differs",
-        )
-        return calls, successes
-    require(calls == expected_calls, f"{label} call count differs")
-    require(successes == calls, f"{label} advisory call failed")
-    require(errno is None, f"{label} success unexpectedly carries errno")
-    return calls, successes
-
-
-def validate_residency(
-    value: Any,
-    *,
-    label: str,
-    logical_bytes: int,
-    expected_states: set[str],
-) -> int:
-    require(isinstance(value, dict) and set(value) == RESIDENCY_FIELDS, f"{label} fields differ")
-    state = value["state"]
-    require(
-        state in expected_states,
-        f"{label} state differs: expected {sorted(expected_states)!r}, got {state!r}",
-    )
-    if state in {"not-applicable", "unsupported-platform"}:
-        for field in RESIDENCY_FIELDS - {"state"}:
-            require(value[field] is None, f"{label} not-applicable field {field} must be null")
-        return 0
-
-    page_size = exact_nonnegative(value["page_size"], f"{label} page_size")
-    total_pages = exact_nonnegative(value["total_pages"], f"{label} total_pages")
-    resident_pages = exact_nonnegative(value["resident_pages"], f"{label} resident_pages")
-    resident_bytes = exact_nonnegative(value["resident_bytes"], f"{label} resident_bytes")
-    require(value["errno"] is None, f"{label} measured checkpoint carries errno")
-    require(page_size >= 512 and page_size & (page_size - 1) == 0, f"{label} page_size is invalid")
-    expected_pages = (logical_bytes + page_size - 1) // page_size
-    require(total_pages == expected_pages, f"{label} total_pages differs")
-    require(resident_pages <= total_pages, f"{label} resident_pages exceed total_pages")
-    if resident_pages == 0:
-        possible_bytes = {0}
-    else:
-        tail_bytes = logical_bytes - (total_pages - 1) * page_size
-        possible_bytes = {
-            min(logical_bytes, resident_pages * page_size),
-            (resident_pages - 1) * page_size + tail_bytes,
-        }
-    require(resident_bytes in possible_bytes, f"{label} resident byte/page accounting differs")
-    return resident_bytes
-
-
-def parse_audit(
-    data: bytes,
-    *,
-    snapshot_policy: str = "direct",
-) -> tuple[list[tuple[int, dict[str, Any]]], list[tuple[int, dict[str, Any]]]]:
-    require(snapshot_policy in SNAPSHOT_POLICIES, "unknown snapshot policy")
-    portable = snapshot_policy == "portable-copy"
-    require(data and data.endswith(b"\n"), "sealed loader audit must be nonempty and newline-terminated")
-    require(b"\r" not in data, "sealed loader audit contains a carriage return")
-    records: list[tuple[int, dict[str, Any]]] = []
-    summaries: list[tuple[int, dict[str, Any]]] = []
-    for line_number, raw in enumerate(data.splitlines(), 1):
-        try:
-            record = json.loads(raw.decode("utf-8"), object_pairs_hook=duplicate_keys)
-        except (UnicodeDecodeError, json.JSONDecodeError, ValidationError) as error:
-            raise ValidationError(f"invalid audit JSON on line {line_number}: {error}") from error
-        require(isinstance(record, dict), f"audit record must be an object on line {line_number}")
-        schema = record.get("schema")
-        require(isinstance(schema, str), f"audit schema is missing on line {line_number}")
-        require(schema == SCHEMA, f"unknown audit schema on line {line_number}: {schema!r}")
-        require(set(record) == FIELDS, f"loader audit fields differ on line {line_number}")
-        require(type(record["pid"]) is int and record["pid"] > 0, f"invalid audit pid on line {line_number}")
-        require(record["artifact_kind"] == "aot", f"invalid artifact kind on line {line_number}")
-        require(isinstance(record["module_sha256"], str) and SHA256_RE.fullmatch(record["module_sha256"]), f"invalid module SHA-256 on line {line_number}")
-        if portable:
-            expected_mode = PORTABLE_MODES[record["artifact_kind"]]
-            require(
-                record["snapshot_mode"] == expected_mode,
-                f"snapshot mode differs from portable-copy policy on line {line_number}",
-            )
-        else:
-            require(record["snapshot_mode"] in DIRECT_MODES, f"non-direct snapshot mode on line {line_number}")
-            if snapshot_policy == "direct-immutable":
-                require(
-                    record["snapshot_mode"] == "direct-immutable-inode",
-                    f"snapshot mode differs from direct-immutable policy on line {line_number}",
-                )
-        logical = exact_nonnegative(record["logical_bytes"], f"logical_bytes line {line_number}")
-        require(logical > 0, f"logical_bytes must be positive on line {line_number}")
-        source_read = exact_nonnegative(record["source_bytes_read"], f"source_bytes_read line {line_number}")
-        if portable:
-            require(source_read == logical, f"source_bytes_read differs from portable-copy contract on line {line_number}")
-        else:
-            require(source_read in (0, logical), f"source_bytes_read differs from direct-mode contract on line {line_number}")
-        require(exact_nonnegative(record["source_bytes_written"], f"source_bytes_written line {line_number}") == 0, f"source bytes were written on line {line_number}")
-        expected_snapshot_writes = logical if portable else 0
-        require(
-            exact_nonnegative(record["snapshot_bytes_written"], f"snapshot_bytes_written line {line_number}") == expected_snapshot_writes,
-            f"snapshot byte accounting differs on line {line_number}",
-        )
-        require(exact_nonnegative(record["mapping_bytes_hashed"], f"mapping_bytes_hashed line {line_number}") == logical, f"mapping hash coverage differs on line {line_number}")
-        require(exact_nonnegative(record["sync_calls"], f"sync_calls line {line_number}") == 0, f"loader issued sync calls on line {line_number}")
-        validate_advice(
-            record,
-            prefix="read_advice",
-            errno_field="read_advice_first_errno",
-            expected_applicable=True,
-            expected_calls=2,
-            allow_unsupported=portable,
-            line_number=line_number,
-        )
-        validate_advice(
-            record,
-            prefix="source_cache_eviction",
-            errno_field="source_cache_eviction_errno",
-            expected_applicable=True,
-            expected_calls=1,
-            allow_unsupported=portable,
-            line_number=line_number,
-        )
-        validate_advice(
-            record,
-            prefix="snapshot_cache_eviction",
-            errno_field="snapshot_cache_eviction_errno",
-            expected_applicable=portable and record["artifact_kind"] == "aot",
-            expected_calls=1,
-            allow_unsupported=portable,
-            line_number=line_number,
-        )
-        validate_advice(
-            record,
-            prefix="mapping_cache_eviction",
-            errno_field="mapping_cache_eviction_errno",
-            expected_applicable=False,
-            expected_calls=1,
-            allow_unsupported=portable,
-            line_number=line_number,
-        )
-        validate_residency(
-            record["residency_after_hash_inspect"],
-            label=f"residency_after_hash_inspect line {line_number}",
-            logical_bytes=logical,
-            expected_states={"unsupported-platform"} if portable else {"measured"},
-        )
-        validate_residency(
-            record["residency_after_archive_release"],
-            label=f"residency_after_archive_release line {line_number}",
-            logical_bytes=logical,
-            expected_states=(
-                {"unsupported-platform"}
-                if portable and record["artifact_kind"] == "aot"
-                else {"measured"}
-                if record["artifact_kind"] == "aot"
-                else {"not-applicable"}
-            ),
-        )
-        validate_residency(
-            record["source_residency_before_eviction"],
-            label=f"source_residency_before_eviction line {line_number}",
-            logical_bytes=logical,
-            expected_states={"unsupported-platform"} if portable else {"measured"},
-        )
-        validate_residency(
-            record["source_residency_after_eviction"],
-            label=f"source_residency_after_eviction line {line_number}",
-            logical_bytes=logical,
-            expected_states={"unsupported-platform"} if portable else {"measured"},
-        )
-        validate_residency(
-            record["residency_after_eviction"],
-            label=f"residency_after_eviction line {line_number}",
-            logical_bytes=logical,
-            expected_states={"unsupported-platform"} if portable else {"measured"},
-        )
-        expected_write_policy = (
-            "private-streamed-copy-no-sync"
-            if portable and record["artifact_kind"] == "aot"
-            else "private-sealed-backing-no-sync"
-            if portable
-            else "none-immutable-source"
-        )
-        require(record["write_policy"] == expected_write_policy, f"write policy differs on line {line_number}")
-        records.append((line_number, record))
-    require(records, "sealed loader audit contains no loader receipts")
-    return records, summaries
-
-
-def validate_attested_start_summary(
-    record: dict[str, Any],
-    expected: dict[str, Any],
-    *,
-    line_number: int,
-) -> None:
-    label = f"attested-start summary line {line_number}"
-    for field in (
-        "memory_image_schema",
-        "proof_sha256",
-        "proof_output_sha256",
-        "mapped_size",
-    ):
-        require(record[field] == expected[field], f"{label} {field} differs from sealed manifest")
-
-    require(not record["counter_overflow"], f"{label} reports counter overflow")
-    ordinary_starts = record["ordinary_start_completed_instances"]
-    fresh_instances = record["fresh_zeroed_instances"]
-    nonfresh_instances = record["nonfresh_instances"]
-    validations = record["validation_attempts"]
-    compare_attempts = record["full_compare_attempts"]
-    compare_successes = record["full_compare_successes"]
-    compare_failures = record["full_compare_failures"]
-    reuse_successes = record["reuse_successes"]
-    reuse_failures = record["reuse_failures"]
-    remap_successes = record["remap_successes"]
-    remap_failures = record["remap_failures"]
-    mapped_size = record["mapped_size"]
-
-    require(ordinary_starts > 0, f"{label} has no ordinary start completions")
-    require(
-        ordinary_starts == fresh_instances + nonfresh_instances,
-        f"{label} ordinary-start/fresh-memory conservation differs",
-    )
-    require(nonfresh_instances == 0, f"{label} observed a non-fresh memory instance")
-    require(
-        validations == ordinary_starts,
-        f"{label} ordinary-start/validation conservation differs",
-    )
-    require(
-        compare_attempts == compare_successes + compare_failures,
-        f"{label} full-compare conservation differs",
-    )
-    require(
-        validations == compare_attempts + reuse_successes + reuse_failures,
-        f"{label} validation compare/reuse conservation differs",
-    )
-    require(compare_attempts == 1, f"{label} did not perform exactly one full comparison")
-    require(compare_failures == 0, f"{label} reports a full comparison failure")
-    require(compare_successes == 1, f"{label} did not complete the first full comparison")
-    require(reuse_failures == 0, f"{label} reports a cached-validation failure")
-    require(
-        reuse_successes == ordinary_starts - 1,
-        f"{label} validation reuse count differs",
-    )
-
-    expected_compared_bytes = mapped_size * compare_successes
-    expected_skipped_bytes = mapped_size * reuse_successes
-    require(
-        expected_compared_bytes <= MAX_U64 and expected_skipped_bytes <= MAX_U64,
-        f"{label} byte-accounting product overflows u64",
-    )
-    require(
-        record["compared_bytes"] == expected_compared_bytes,
-        f"{label} compared byte accounting differs",
-    )
-    require(
-        record["skipped_bytes"] == expected_skipped_bytes,
-        f"{label} skipped byte accounting differs",
-    )
-
-    successful_validations = compare_successes + reuse_successes
-    require(
-        remap_successes + remap_failures == successful_validations,
-        f"{label} validation/remap conservation differs",
-    )
-    require(remap_failures == 0, f"{label} reports a memory-image remap failure")
-    require(
-        remap_successes == ordinary_starts,
-        f"{label} successful remap count differs from ordinary starts",
-    )
-
-
-def validate(
-    audit: Path,
-    manifest: Path,
-    output: Path,
-    *,
-    snapshot_policy: str = "direct",
-    expected_initdb_executions: int = 1,
-    expected_postgres_executions: int = 1,
-) -> None:
-    require(not os.path.lexists(output), f"validation output already exists: {output}")
-    require(snapshot_policy in SNAPSHOT_POLICIES, "unknown snapshot policy")
-    require(expected_initdb_executions > 0, "expected initdb executions must be positive")
-    require(expected_postgres_executions > 0, "expected postgres executions must be positive")
-    audit_data = read_regular(audit, "sealed loader audit")
-    manifest_data = read_regular(manifest, "sealed manifest")
-    validator_data = read_regular(Path(__file__), "validator")
-    manifest_modules, manifest_attested_memory = manifest_module_evidence(manifest_data)
-    expected = {name: manifest_modules[name] for name in EXECUTABLE_NAMES}
-    parsed_records, parsed_summaries = parse_audit(
-        audit_data,
-        snapshot_policy=snapshot_policy,
-    )
-    records = [record for _, record in parsed_records]
-    summaries = [record for _, record in parsed_summaries]
-    allowed_module_hashes = set(manifest_modules.values())
-    for line_number, record in parsed_records:
-        require(
-            record["module_sha256"] in allowed_module_hashes,
-            f"audit module SHA-256 is not in sealed manifest on line {line_number}",
-        )
-    by_key: dict[tuple[str, str], list[dict[str, Any]]] = {}
-    for record in records:
-        by_key.setdefault((record["module_sha256"], record["artifact_kind"]), []).append(record)
-    # An outer initdb invocation necessarily execs the sealed postgres module
-    # for bootstrap/single-user initialization in the same native executor
-    # process.  The loader receipt records module activations, not merely outer
-    # CLI invocations, so a valid initdb+postmaster lifecycle contains one
-    # postgres activation on every initdb pid plus one on every outer postgres
-    # pid.  Classify the outer invocation by the presence of the initdb module;
-    # the product CLI admits only these two outer executables.  This preserves
-    # exact population accounting without misreporting bootstrap activations as
-    # additional postmasters.
-    activation_pids: dict[str, set[int]] = {}
-    for name, module_hash in expected.items():
-        aot = by_key.get((module_hash, "aot"), [])
-        aot_pids = [record["pid"] for record in aot]
-        require(len(set(aot_pids)) == len(aot_pids), f"{name} AOT audit pids are not unique")
-        activation_pids[name] = set(aot_pids)
-
-    initdb_pids = activation_pids["runtime:initdb"]
-    postgres_activation_pids = activation_pids["runtime:postgres"]
-    require(
-        len(initdb_pids) == expected_initdb_executions,
-        f"runtime:initdb must have exactly {expected_initdb_executions} outer execution pids",
-    )
-    require(
-        initdb_pids <= postgres_activation_pids,
-        "every initdb execution must activate bootstrap postgres on the same pid",
-    )
-    outer_postgres_pids = postgres_activation_pids - initdb_pids
-    require(
-        len(outer_postgres_pids) == expected_postgres_executions,
-        f"runtime:postgres must have exactly {expected_postgres_executions} outer execution pids",
-    )
-    expected_postgres_activations = expected_initdb_executions + expected_postgres_executions
-    require(
-        len(postgres_activation_pids) == expected_postgres_activations,
-        "runtime:postgres activation population differs from initdb bootstrap plus outer executions",
-    )
-
-    executable_pids = {
-        "runtime:initdb": sorted(initdb_pids),
-        "runtime:postgres": sorted(outer_postgres_pids),
-    }
-    output.parent.mkdir(parents=True, exist_ok=True)
-    audit_sha = hashlib.sha256(audit_data).hexdigest()
-    manifest_sha = hashlib.sha256(manifest_data).hexdigest()
-    validator_sha = hashlib.sha256(validator_data).hexdigest()
-    summary_totals = {
-        field: sum(summary[field] for summary in summaries)
-        for field in SUMMARY_COUNTER_FIELDS
-    }
-    overflow_summaries = sum(summary["counter_overflow"] for summary in summaries)
-    read_calls = sum(record["read_advice_calls"] for record in records)
-    read_successes = sum(record["read_advice_successes"] for record in records)
-    source_eviction_calls = sum(
-        record["source_cache_eviction_calls"] for record in records
-    )
-    source_eviction_successes = sum(
-        record["source_cache_eviction_successes"] for record in records
-    )
-    snapshot_eviction_calls = sum(
-        record["snapshot_cache_eviction_calls"] for record in records
-    )
-    snapshot_eviction_successes = sum(
-        record["snapshot_cache_eviction_successes"] for record in records
-    )
-    mapping_eviction_calls = sum(
-        record["mapping_cache_eviction_calls"] for record in records
-    )
-    mapping_eviction_successes = sum(
-        record["mapping_cache_eviction_successes"] for record in records
-    )
-    hash_resident_bytes = sum(
-        record["residency_after_hash_inspect"]["resident_bytes"] or 0
-        for record in records
-    )
-    archive_resident_bytes = sum(
-        record["residency_after_archive_release"]["resident_bytes"] or 0
-        for record in records
-    )
-    source_before_eviction_bytes = sum(
-        record["source_residency_before_eviction"]["resident_bytes"] or 0
-        for record in records
-    )
-    source_after_eviction_bytes = sum(
-        record["source_residency_after_eviction"]["resident_bytes"] or 0
-        for record in records
-    )
-    eviction_resident_bytes = sum(
-        record["residency_after_eviction"]["resident_bytes"] or 0
-        for record in records
-    )
-    payload = (
-        "schema_version\tstatus\trecords\taot_records\tmemory_records\t"
-        "initdb_executions\tpostgres_executions\tinitdb_pids\tpostgres_pids\t"
-        "snapshot_policy\taudit_sha256\tmanifest_sha256\tvalidator_sha256\t"
-        "read_advice_calls\tread_advice_successes\tsource_cache_eviction_calls\t"
-        "source_cache_eviction_successes\tsnapshot_cache_eviction_calls\t"
-        "snapshot_cache_eviction_successes\tmapping_cache_eviction_calls\t"
-        "mapping_cache_eviction_successes\tresidency_after_hash_inspect_bytes\t"
-        "residency_after_archive_release_bytes\tsource_residency_before_eviction_bytes\t"
-        "source_residency_after_eviction_bytes\tresidency_after_eviction_bytes\t"
-        "attested_summary_records\t"
-        + "\t".join(SUMMARY_COUNTER_FIELDS)
-        + "\tcounter_overflow_records\n"
-        + f"{RESULT_SCHEMA}\tpassed\t{len(records)}\t"
-        f"{sum(record['artifact_kind'] == 'aot' for record in records)}\t"
-        f"{sum(record['artifact_kind'] == 'preinitialized-memory' for record in records)}\t"
-        f"{expected_initdb_executions}\t{expected_postgres_executions}\t"
-        f"{','.join(str(pid) for pid in executable_pids['runtime:initdb'])}\t"
-        f"{','.join(str(pid) for pid in executable_pids['runtime:postgres'])}\t"
-        f"{snapshot_policy}\t"
-        f"{audit_sha}\t{manifest_sha}\t{validator_sha}\t"
-        f"{read_calls}\t{read_successes}\t"
-        f"{source_eviction_calls}\t{source_eviction_successes}\t"
-        f"{snapshot_eviction_calls}\t{snapshot_eviction_successes}\t"
-        f"{mapping_eviction_calls}\t{mapping_eviction_successes}\t"
-        f"{hash_resident_bytes}\t{archive_resident_bytes}\t"
-        f"{source_before_eviction_bytes}\t{source_after_eviction_bytes}\t"
-        f"{eviction_resident_bytes}\t{len(summaries)}\t"
-        + "\t".join(str(summary_totals[field]) for field in SUMMARY_COUNTER_FIELDS)
-        + f"\t{overflow_summaries}\n"
-    ).encode("utf-8")
-    pending = output.with_name(
-        f".{output.name}.pending.{os.getpid()}.{secrets.token_hex(16)}"
-    )
-    pending_identity: PublicationSource | None = None
-    try:
-        pending_identity = write_bytes(pending, payload)
-        publish_identified(pending, output, pending_identity)
-    finally:
-        if pending_identity is not None:
-            remove_private(pending, pending_identity)
-
-
-def main(argv: list[str]) -> int:
-    parser = argparse.ArgumentParser(description=__doc__)
-    parser.add_argument("--audit", type=Path, required=True)
-    parser.add_argument("--manifest", type=Path, required=True)
-    parser.add_argument("--output", type=Path, required=True)
-    parser.add_argument("--snapshot-policy", choices=sorted(SNAPSHOT_POLICIES), default="direct")
-    parser.add_argument("--expected-initdb-executions", type=int, default=1)
-    parser.add_argument("--expected-postgres-executions", type=int, default=1)
-    arguments = parser.parse_args(argv)
-    try:
-        validate(
-            arguments.audit,
-            arguments.manifest,
-            arguments.output,
-            snapshot_policy=arguments.snapshot_policy,
-            expected_initdb_executions=arguments.expected_initdb_executions,
-            expected_postgres_executions=arguments.expected_postgres_executions,
-        )
-        return 0
-    except (OSError, PublicationError, ValidationError) as error:
-        print(f"sealed loader audit validation failed: {error}", file=sys.stderr)
-        return 2
-
-
-if __name__ == "__main__":
-    raise SystemExit(main(sys.argv[1:]))
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/bin/validate-sealed-loader-audit.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/bin/validate-sealed-loader-audit.test.py
deleted file mode 100644
index aa368064b..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/bin/validate-sealed-loader-audit.test.py
+++ /dev/null
@@ -1,209 +0,0 @@
-#!/usr/bin/env python3
-
-from __future__ import annotations
-
-import importlib.util
-import json
-import sys
-import tempfile
-import unittest
-from pathlib import Path
-
-
-SCRIPT = Path(__file__).with_name("validate-sealed-loader-audit.py")
-SPEC = importlib.util.spec_from_file_location("validate_sealed_loader_audit", SCRIPT)
-assert SPEC is not None and SPEC.loader is not None
-MODULE = importlib.util.module_from_spec(SPEC)
-sys.modules[SPEC.name] = MODULE
-SPEC.loader.exec_module(MODULE)
-
-INITDB = "1" * 64
-POSTGRES = "2" * 64
-SIDE_MODULE = "3" * 64
-LOGICAL_BYTES = 4096
-
-
-def manifest() -> dict[str, object]:
-    return {
-        "artifacts": [
-            {"name": "runtime:initdb", "module-sha256": INITDB},
-            {"name": "runtime:postgres", "module-sha256": POSTGRES},
-            {"name": "runtime:libpq.so.5.18", "module-sha256": SIDE_MODULE},
-        ]
-    }
-
-
-def residency(state: str, *, resident: bool = True) -> dict[str, object]:
-    if state == "unsupported-platform":
-        return {
-            "state": state,
-            "page_size": None,
-            "total_pages": None,
-            "resident_pages": None,
-            "resident_bytes": None,
-            "errno": None,
-        }
-    return {
-        "state": state,
-        "page_size": 4096,
-        "total_pages": 1,
-        "resident_pages": 1 if resident else 0,
-        "resident_bytes": LOGICAL_BYTES if resident else 0,
-        "errno": None,
-    }
-
-
-def record(module_hash: str, pid: int, *, portable: bool = False) -> dict[str, object]:
-    observed = residency("unsupported-platform") if portable else residency("measured")
-    evicted = residency("unsupported-platform") if portable else residency("measured", resident=False)
-    return {
-        "schema": MODULE.SCHEMA,
-        "pid": pid,
-        "artifact_kind": "aot",
-        "module_sha256": module_hash,
-        "snapshot_mode": "streamed-copy" if portable else "direct-immutable-inode",
-        "logical_bytes": LOGICAL_BYTES,
-        "source_bytes_read": LOGICAL_BYTES if portable else 0,
-        "source_bytes_written": 0,
-        "snapshot_bytes_written": LOGICAL_BYTES if portable else 0,
-        "mapping_bytes_hashed": LOGICAL_BYTES,
-        "sync_calls": 0,
-        "read_advice_applicable": True,
-        "read_advice_supported": not portable,
-        "read_advice_calls": 0 if portable else 2,
-        "read_advice_successes": 0 if portable else 2,
-        "read_advice_first_errno": None,
-        "source_cache_eviction_applicable": True,
-        "source_cache_eviction_supported": not portable,
-        "source_cache_eviction_calls": 0 if portable else 1,
-        "source_cache_eviction_successes": 0 if portable else 1,
-        "source_cache_eviction_errno": None,
-        "snapshot_cache_eviction_applicable": portable,
-        "snapshot_cache_eviction_supported": not portable,
-        "snapshot_cache_eviction_calls": 0,
-        "snapshot_cache_eviction_successes": 0,
-        "snapshot_cache_eviction_errno": None,
-        "mapping_cache_eviction_applicable": False,
-        "mapping_cache_eviction_supported": True,
-        "mapping_cache_eviction_calls": 0,
-        "mapping_cache_eviction_successes": 0,
-        "mapping_cache_eviction_errno": None,
-        "residency_after_hash_inspect": dict(observed),
-        "residency_after_archive_release": dict(observed),
-        "source_residency_before_eviction": dict(observed),
-        "source_residency_after_eviction": dict(evicted),
-        "residency_after_eviction": dict(evicted),
-        "write_policy": "private-streamed-copy-no-sync" if portable else "none-immutable-source",
-    }
-
-
-def lifecycle_records(*, portable: bool = False) -> list[dict[str, object]]:
-    return [
-        record(INITDB, 101, portable=portable),
-        record(POSTGRES, 101, portable=portable),
-        record(POSTGRES, 202, portable=portable),
-    ]
-
-
-class LoaderAuditTests(unittest.TestCase):
-    def write_fixture(
-        self,
-        root: Path,
-        records: list[dict[str, object]],
-        manifest_value: dict[str, object] | None = None,
-    ) -> tuple[Path, Path]:
-        manifest_path = root / "manifest.json"
-        manifest_path.write_text(
-            json.dumps(manifest_value or manifest(), sort_keys=True) + "\n",
-            encoding="utf-8",
-        )
-        audit_path = root / "audit.jsonl"
-        audit_path.write_text(
-            "".join(json.dumps(item, sort_keys=True) + "\n" for item in records),
-            encoding="utf-8",
-        )
-        return manifest_path, audit_path
-
-    def validate(
-        self,
-        records: list[dict[str, object]],
-        *,
-        snapshot_policy: str = "direct-immutable",
-    ) -> list[str]:
-        with tempfile.TemporaryDirectory() as temporary:
-            root = Path(temporary)
-            manifest_path, audit_path = self.write_fixture(root, records)
-            output = root / "validation.tsv"
-            MODULE.validate(
-                audit_path,
-                manifest_path,
-                output,
-                snapshot_policy=snapshot_policy,
-            )
-            return output.read_text(encoding="utf-8").splitlines()
-
-    def test_exact_aot_lifecycle_passes(self) -> None:
-        header, values = self.validate(lifecycle_records())
-        columns = dict(zip(header.split("\t"), values.split("\t"), strict=True))
-        self.assertEqual(columns["status"], "passed")
-        self.assertEqual(columns["records"], "3")
-        self.assertEqual(columns["aot_records"], "3")
-        self.assertEqual(columns["memory_records"], "0")
-        self.assertEqual(columns["attested_summary_records"], "0")
-        self.assertEqual(columns["initdb_pids"], "101")
-        self.assertEqual(columns["postgres_pids"], "202")
-
-    def test_portable_aot_lifecycle_passes(self) -> None:
-        header, values = self.validate(
-            lifecycle_records(portable=True),
-            snapshot_policy="portable-copy",
-        )
-        columns = dict(zip(header.split("\t"), values.split("\t"), strict=True))
-        self.assertEqual(columns["snapshot_policy"], "portable-copy")
-        self.assertEqual(columns["snapshot_cache_eviction_calls"], "0")
-
-    def test_preinitialized_memory_receipt_is_rejected(self) -> None:
-        records = lifecycle_records()
-        records.insert(1, {**records[0], "artifact_kind": "preinitialized-memory"})
-        with self.assertRaisesRegex(MODULE.ValidationError, "invalid artifact kind"):
-            self.validate(records)
-
-    def test_missing_bootstrap_postgres_activation_is_rejected(self) -> None:
-        records = [record(INITDB, 101), record(POSTGRES, 202)]
-        with self.assertRaisesRegex(
-            MODULE.ValidationError,
-            "every initdb execution must activate bootstrap postgres",
-        ):
-            self.validate(records)
-
-    def test_unknown_module_and_duplicate_pid_are_rejected(self) -> None:
-        with self.assertRaisesRegex(MODULE.ValidationError, "not in sealed manifest"):
-            self.validate([*lifecycle_records(), record("f" * 64, 303)])
-        duplicate = lifecycle_records()
-        duplicate.append(dict(duplicate[-1]))
-        with self.assertRaisesRegex(MODULE.ValidationError, "AOT audit pids are not unique"):
-            self.validate(duplicate)
-
-    def test_loader_fields_and_modes_fail_closed(self) -> None:
-        records = lifecycle_records()
-        records[0]["unknown"] = True
-        with self.assertRaisesRegex(MODULE.ValidationError, "loader audit fields differ"):
-            self.validate(records)
-        records = lifecycle_records()
-        records[0]["snapshot_mode"] = "reflink"
-        with self.assertRaisesRegex(MODULE.ValidationError, "non-direct snapshot mode"):
-            self.validate(records)
-
-    def test_existing_output_is_not_replaced(self) -> None:
-        with tempfile.TemporaryDirectory() as temporary:
-            root = Path(temporary)
-            manifest_path, audit_path = self.write_fixture(root, lifecycle_records())
-            output = root / "validation.tsv"
-            output.write_text("existing\n", encoding="utf-8")
-            with self.assertRaisesRegex(MODULE.ValidationError, "already exists"):
-                MODULE.validate(audit_path, manifest_path, output)
-            self.assertEqual(output.read_text(encoding="utf-8"), "existing\n")
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh b/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh
deleted file mode 100644
index f8891565f..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh
+++ /dev/null
@@ -1,1780 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-_fresh_common_source="${BASH_SOURCE[0]}"
-_fresh_source_root="$(cd -P "$(dirname "$_fresh_common_source")/.." && pwd -P)"
-_fresh_source_repo_root="$(cd -P "$_fresh_source_root/../../../.." && pwd -P)"
-export FRESH_ROOT="${FRESH_ROOT:-$_fresh_source_root}"
-export REPO_ROOT="${REPO_ROOT:-$_fresh_source_repo_root}"
-_fresh_project_source_id_prefix="src/runtimes/liboliphaunt/wasix-postmaster"
-if [ "${FRESH_PROJECT_SOURCE_ID_PREFIX+x}" = x ]; then
-  if [ "$FRESH_PROJECT_SOURCE_ID_PREFIX" != "$_fresh_project_source_id_prefix" ]; then
-    printf 'FRESH_PROJECT_SOURCE_ID_PREFIX must be %s\n' \
-      "$_fresh_project_source_id_prefix" >&2
-    return 2 2>/dev/null || exit 2
-  fi
-else
-  FRESH_PROJECT_SOURCE_ID_PREFIX="$_fresh_project_source_id_prefix"
-fi
-readonly FRESH_PROJECT_SOURCE_ID_PREFIX
-export FRESH_PROJECT_SOURCE_ID_PREFIX
-export WASIX_TOOLCHAIN_ROOT="${WASIX_TOOLCHAIN_ROOT:-$REPO_ROOT/src/runtimes/liboliphaunt/wasix/assets/build}"
-export FRESH_WORK_ROOT="${FRESH_WORK_ROOT:-$REPO_ROOT/target/oliphaunt-wasix-postmaster}"
-
-export POSTGRES_TAG="${POSTGRES_TAG:-REL_18_4}"
-export POSTGRES_VERSION="${POSTGRES_VERSION:-18.4}"
-export POSTGRES_SOURCE_TOML="${POSTGRES_SOURCE_TOML:-$REPO_ROOT/src/postgres/versions/18/source.toml}"
-export BASELINE_DIR="${BASELINE_DIR:-$FRESH_WORK_ROOT/sources/postgresql-$POSTGRES_VERSION}"
-export WASIX_SRC_DIR="${WASIX_SRC_DIR:-$FRESH_WORK_ROOT/work/postgres-wasix-core-src}"
-export CLIENT_TOOLS_BUILD_DIR="${CLIENT_TOOLS_BUILD_DIR:-$FRESH_WORK_ROOT/builds/native-client-tools}"
-export CLIENT_TOOLS_INSTALL_DIR="${CLIENT_TOOLS_INSTALL_DIR:-$FRESH_WORK_ROOT/install/native-client-tools}"
-export FRESH_WASIX_DOCKER_IMAGE="${FRESH_WASIX_DOCKER_IMAGE:-oliphaunt-wasix-wasix-build:local}"
-export FRESH_WASMER_VERSION="${FRESH_WASMER_VERSION:-7.2.0-alpha.2}"
-export FRESH_WASMER_WASIX_VERSION="${FRESH_WASMER_WASIX_VERSION:-0.702.0-alpha.2}"
-export FRESH_WASMER_COMPILER_FEATURES="${FRESH_WASMER_COMPILER_FEATURES:-llvm,wat}"
-export FRESH_WASMER_HEADLESS_FEATURES="${FRESH_WASMER_HEADLESS_FEATURES:-headless-minimal}"
-export FRESH_POSTMASTER_EXECUTOR_PACKAGE="oliphaunt-wasix-postmaster-executor"
-export FRESH_POSTMASTER_EXECUTOR_BINARY="oliphaunt-wasix-postmaster-executor"
-export FRESH_POSTMASTER_EXECUTOR_FEATURES="product-executor"
-export FRESH_START_PROOF_BINARY="oliphaunt-wasix-start-proof"
-export FRESH_START_PROOF_FEATURES="start-proof-tool"
-export FRESH_START_PROOF_POLICY="llvm-shared-memory-init-restricted-effects.v1"
-export FRESH_MEMORY_PROFILE_BINARY="oliphaunt-wasix-memory-profile"
-export FRESH_MEMORY_PROFILE_FEATURES="memory-profile-tool"
-export FRESH_LINEAR_MEMORY_PROFILE_ID="oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1"
-export FRESH_LINEAR_MEMORY_MAXIMUM_PAGES="4096"
-export FRESH_LINEAR_MEMORY_STATIC_BOUND_PAGES="65536"
-export FRESH_LINEAR_MEMORY_STATIC_OFFSET_GUARD_BYTES="2147483648"
-export FRESH_POSTMASTER_COMPILER_BINARY="oliphaunt-wasix-postmaster-compiler"
-export FRESH_POSTMASTER_COMPILER_FEATURES="product-compiler"
-export FRESH_POSTMASTER_EXECUTOR_ROLE="postmaster-product"
-export FRESH_POSTMASTER_TASK_BUDGET_PROFILE="$FRESH_ROOT/profiles/runtime-task-budgets/embedded-postmaster-v1.tsv"
-export FRESH_POSTMASTER_RUNTIME_FOOTPRINT_PROFILE="$FRESH_ROOT/profiles/runtime-footprints/embedded-concurrent-v1.gucs"
-export FRESH_POSTMASTER_TASK_BUDGET_PROFILE_ID="embedded-postmaster-v1"
-export FRESH_POSTMASTER_HOST_TASK_BUDGET="96"
-export FRESH_POSTMASTER_BLOCKING_CORE_THREADS="1"
-export FRESH_POSTMASTER_BLOCKING_WORKER_IDLE_TIMEOUT_MS="1000"
-export FRESH_POSTMASTER_EXECUTOR_RUNTIME_POLICY_ID="oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2"
-export FRESH_POSTMASTER_EXECUTOR_CLI_CONTRACT="sealed-postmaster-run-v1"
-export FRESH_WASMER_ARTIFACT_ABI_VERSION="${FRESH_WASMER_ARTIFACT_ABI_VERSION:-21}"
-export FRESH_WASMER_SOURCE_COMMIT="${FRESH_WASMER_SOURCE_COMMIT:-1d1b3420beef28550afbb4692b664bd7f6bc2581}"
-export FRESH_WASMER_NAPI_COMMIT="${FRESH_WASMER_NAPI_COMMIT:-706383f42391cb4e4e82e5fd5e63a0ebf81ae19d}"
-export FRESH_WASMER_TEST_FILES_COMMIT="${FRESH_WASMER_TEST_FILES_COMMIT:-7f27e84c69af3b772f751d6c4a733d9f448b2c70}"
-export FRESH_WASMER_SPEC_COMMIT="${FRESH_WASMER_SPEC_COMMIT:-7e0b83aba9dbbb6e0623c9334b0f73b3bb584b90}"
-export FRESH_WASIX_LIBC_SOURCE_COMMIT="${FRESH_WASIX_LIBC_SOURCE_COMMIT:-34178a6272804f90448b5bd08dc7bcf0d85438e3}"
-export FRESH_UPSTREAM_WASMER_BIN="${FRESH_UPSTREAM_WASMER_BIN:-$FRESH_WORK_ROOT/runtime/wasmer/target/release/wasmer}"
-export FRESH_UPSTREAM_WASMER_HEADLESS_BIN="${FRESH_UPSTREAM_WASMER_HEADLESS_BIN:-$FRESH_WORK_ROOT/runtime/wasmer/target/release/wasmer-headless}"
-export FRESH_WASMER_BUILD_RECEIPT="${FRESH_WASMER_BUILD_RECEIPT:-$FRESH_WORK_ROOT/runtime/build/wasmer-build.receipt}"
-export FRESH_POSTMASTER_EXECUTOR_TARGET_DIR="${FRESH_POSTMASTER_EXECUTOR_TARGET_DIR:-$FRESH_WORK_ROOT/runtime/postmaster-executor-target}"
-export FRESH_POSTMASTER_EXECUTOR_BIN="${FRESH_POSTMASTER_EXECUTOR_BIN:-$FRESH_POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_POSTMASTER_EXECUTOR_BINARY}"
-export FRESH_START_PROOF_BIN="${FRESH_START_PROOF_BIN:-$FRESH_POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_START_PROOF_BINARY}"
-export FRESH_MEMORY_PROFILE_BIN="${FRESH_MEMORY_PROFILE_BIN:-$FRESH_POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_MEMORY_PROFILE_BINARY}"
-export FRESH_POSTMASTER_COMPILER_TARGET_DIR="${FRESH_POSTMASTER_COMPILER_TARGET_DIR:-$FRESH_WORK_ROOT/runtime/postmaster-compiler-target}"
-export FRESH_POSTMASTER_COMPILER_BIN="${FRESH_POSTMASTER_COMPILER_BIN:-$FRESH_POSTMASTER_COMPILER_TARGET_DIR/release/$FRESH_POSTMASTER_COMPILER_BINARY}"
-export FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT="${FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT:-$FRESH_WORK_ROOT/runtime/build/postmaster-executor-build.receipt}"
-export FRESH_PATCHED_WASIXCC_SYSROOT_PREFIX="${FRESH_PATCHED_WASIXCC_SYSROOT_PREFIX:-$FRESH_WORK_ROOT/runtime/build/patched-wasixcc-sysroot}"
-export WASIXCC_SYSROOT_VARIANT="${WASIXCC_SYSROOT_VARIANT:-sysroot-exnref-ehpic}"
-export WASIXCC_SYSROOT_PREFIX="${WASIXCC_SYSROOT_PREFIX:-$FRESH_PATCHED_WASIXCC_SYSROOT_PREFIX}"
-export WASIXCC_SYSROOT="${WASIXCC_SYSROOT:-$WASIXCC_SYSROOT_PREFIX/$WASIXCC_SYSROOT_VARIANT}"
-
-fresh_validate_postmaster_task_budget_profile() {
-  local profile="${1:-$FRESH_POSTMASTER_TASK_BUDGET_PROFILE}"
-  local footprint="${2:-$FRESH_POSTMASTER_RUNTIME_FOOTPRINT_PROFILE}"
-  local max_connections
-  local max_wal_senders
-  local autovacuum_worker_slots
-  local max_worker_processes
-  local io_method
-  local profile_key
-  local profile_value
-
-  [ -f "$profile" ] && [ ! -L "$profile" ] || {
-    printf 'missing regular postmaster task-budget profile: %s\n' "$profile" >&2
-    return 2
-  }
-  [ -f "$footprint" ] && [ ! -L "$footprint" ] || {
-    printf 'missing regular postmaster runtime-footprint profile: %s\n' "$footprint" >&2
-    return 2
-  }
-  for profile_key in \
-    max_connections max_wal_senders autovacuum_worker_slots max_worker_processes io_method
-  do
-    profile_value="$(awk -F= -v expected="$profile_key" '
-      $1 == expected { count += 1; value = substr($0, index($0, "=") + 1) }
-      END { if (count != 1 || value == "") exit 2; print value }
-    ' "$footprint")" || {
-      printf 'runtime-footprint profile must contain one %s: %s\n' \
-        "$profile_key" "$footprint" >&2
-      return 2
-    }
-    case "$profile_key" in
-      max_connections) max_connections="$profile_value" ;;
-      max_wal_senders) max_wal_senders="$profile_value" ;;
-      autovacuum_worker_slots) autovacuum_worker_slots="$profile_value" ;;
-      max_worker_processes) max_worker_processes="$profile_value" ;;
-      io_method) io_method="$profile_value" ;;
-    esac
-  done
-  [ "$max_connections" = 8 ] && [ "$max_wal_senders" = 10 ] && \
-    [ "$autovacuum_worker_slots" = 4 ] && [ "$max_worker_processes" = 8 ] && \
-    [ "$io_method" = sync ] || {
-    printf 'postmaster task budget does not match runtime-footprint GUC capacity: %s\n' \
-      "$footprint" >&2
-    return 2
-  }
-  awk -F '\t' \
-    -v expected_id="$FRESH_POSTMASTER_TASK_BUDGET_PROFILE_ID" \
-    -v expected_budget="$FRESH_POSTMASTER_HOST_TASK_BUDGET" \
-    -v expected_core="$FRESH_POSTMASTER_BLOCKING_CORE_THREADS" \
-    -v expected_idle_ms="$FRESH_POSTMASTER_BLOCKING_WORKER_IDLE_TIMEOUT_MS" '
-    BEGIN {
-      header = "schema_version\tprofile_id\tstatus\tpostgres_major\truntime_footprint\tmax_backends\tbackend_authentication_overlap\tmax_io_worker_slots\tfixed_non_max_backends_pmchild_roles\ttracked_child_capacity\tpostmaster_tasks\treserve_tasks\thost_task_budget\tblocking_core_threads\tblocking_worker_idle_timeout_ms"
-    }
-    NR == 1 {
-      if ($0 != header) exit 2
-      next
-    }
-    NR == 2 {
-      if (NF != 15 ||
-          $1 != "oliphaunt.wasix-postmaster.runtime-task-budget.v1" ||
-          $2 != expected_id ||
-          $3 != "supported" ||
-          $4 != "18" ||
-          $5 != "embedded-concurrent") exit 2
-      for (i = 6; i <= 15; i++)
-        if ($i !~ /^(0|[1-9][0-9]*)$/) exit 2
-      if ($6 != 32 || $7 != 18 || $8 != 32 || $9 != 8) exit 2
-      if ($10 != $6 + $7 + $8 + $9) exit 2
-      if ($13 != $10 + $11 + $12) exit 2
-      if ($13 != expected_budget || $14 != expected_core ||
-          $15 != expected_idle_ms || $14 < 1 || $14 > $13 || $15 < 1) exit 2
-      next
-    }
-    { exit 2 }
-    END { if (NR != 2) exit 2 }
-  ' "$profile" || {
-    printf 'invalid or non-canonical postmaster task-budget profile: %s\n' "$profile" >&2
-    return 2
-  }
-}
-
-fresh_normalize_wasix_core_profile() {
-  case "${1:-safe-o2}" in
-    current|baseline|safe|safe-o2) echo "safe-o2" ;;
-    o3) echo "o3" ;;
-    o3-wasmopt|o3-wasm-opt) echo "o3-wasmopt" ;;
-    o3-thinlto) echo "o3-thinlto" ;;
-    release-o3|perf|production) echo "release-o3" ;;
-    release-o3-symbols|perf-symbols|profile-o3) echo "release-o3-symbols" ;;
-    *)
-      echo "unknown WASIX_CORE_PROFILE=$1; expected safe-o2, o3, o3-wasmopt, o3-thinlto, release-o3, or release-o3-symbols" >&2
-      return 2
-      ;;
-  esac
-}
-
-WASIX_CORE_PROFILE="$(fresh_normalize_wasix_core_profile "${WASIX_CORE_PROFILE:-release-o3}")"
-export WASIX_CORE_PROFILE
-
-fresh_wasix_core_profile_suffix_for() {
-  case "$(fresh_normalize_wasix_core_profile "$1")" in
-    safe-o2) printf '' ;;
-    *) printf -- '-%s' "$(fresh_normalize_wasix_core_profile "$1")" ;;
-  esac
-}
-
-fresh_wasix_core_build_dir_for() {
-  printf '%s/builds/wasix-core%s\n' "$FRESH_WORK_ROOT" "$(fresh_wasix_core_profile_suffix_for "$1")"
-}
-
-fresh_wasix_core_install_dir_for() {
-  printf '%s/install/wasix-core%s\n' "$FRESH_WORK_ROOT" "$(fresh_wasix_core_profile_suffix_for "$1")"
-}
-
-fresh_wasix_core_report_dir_for() {
-  case "$(fresh_normalize_wasix_core_profile "$1")" in
-    safe-o2) printf '%s/reports\n' "$FRESH_WORK_ROOT" ;;
-    *) printf '%s/reports/%s\n' "$FRESH_WORK_ROOT" "$(fresh_normalize_wasix_core_profile "$1")" ;;
-  esac
-}
-
-fresh_wasix_core_run_dir_for() {
-  case "$(fresh_normalize_wasix_core_profile "$1")" in
-    safe-o2) printf '%s/run\n' "$FRESH_WORK_ROOT" ;;
-    *) printf '%s/run/%s\n' "$FRESH_WORK_ROOT" "$(fresh_normalize_wasix_core_profile "$1")" ;;
-  esac
-}
-
-export WASIX_BUILD_DIR="${WASIX_BUILD_DIR:-$(fresh_wasix_core_build_dir_for "$WASIX_CORE_PROFILE")}"
-export WASIX_INSTALL_DIR="${WASIX_INSTALL_DIR:-$(fresh_wasix_core_install_dir_for "$WASIX_CORE_PROFILE")}"
-export REPORT_DIR="${REPORT_DIR:-$(fresh_wasix_core_report_dir_for "$WASIX_CORE_PROFILE")}"
-export RUN_DIR="${RUN_DIR:-$(fresh_wasix_core_run_dir_for "$WASIX_CORE_PROFILE")}"
-
-fresh_resolve_wasix_core_profile() {
-  local profile="${1:-$WASIX_CORE_PROFILE}"
-  profile="$(fresh_normalize_wasix_core_profile "$profile")"
-
-  case "$profile" in
-    safe-o2)
-      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="current conservative bring-up profile: O2, no wasm-opt, SIMD/vectorizers disabled"
-      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O2 -g0 -mno-simd128 -fno-vectorize -fno-slp-vectorize -fno-inline-functions-called-once -fno-unroll-loops -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
-      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-fPIC -pthread -sWASM_EXCEPTIONS=yes"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT="no"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS=""
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL="275"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL="233"
-      ;;
-    o3)
-      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="O3 codegen profile without LTO or Binaryen post-link optimization"
-      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
-      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-fPIC -pthread -sWASM_EXCEPTIONS=yes"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT="no"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS=""
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL=""
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=""
-      ;;
-    o3-wasmopt)
-      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="O3 plus Binaryen post-link converge/strip, without ThinLTO"
-      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
-      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-fPIC -pthread -sWASM_EXCEPTIONS=yes"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT="yes"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS="--converge:--strip-debug:--strip-producers"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL=""
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=""
-      ;;
-    o3-thinlto)
-      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="O3 plus ThinLTO, without Binaryen post-link optimization"
-      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
-      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT="no"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS=""
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL="1111"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=""
-      ;;
-    release-o3)
-      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="release-lane performance profile: O3, ThinLTO, and Binaryen converge/strip"
-      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
-      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT="yes"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS="--converge:--strip-debug:--strip-producers"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL="1111"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL="995"
-      ;;
-    release-o3-symbols)
-      FRESH_WASIX_CORE_PROFILE_DESCRIPTION="release-lane profiling profile: O3, ThinLTO, and Binaryen converge while retaining Wasm symbol names"
-      FRESH_WASIX_CORE_PROFILE_CFLAGS="-O3 -g0 -flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes -Wno-unused-command-line-argument"
-      FRESH_WASIX_CORE_PROFILE_LDFLAGS="-flto=thin -fPIC -pthread -sWASM_EXCEPTIONS=yes"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT="yes"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS="--converge:--debuginfo"
-      FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT="yes"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL="1111"
-      FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL=""
-      ;;
-  esac
-
-  FRESH_WASIX_CORE_EFFECTIVE_CFLAGS="${WASIX_CORE_CFLAGS:-$FRESH_WASIX_CORE_PROFILE_CFLAGS}"
-  FRESH_WASIX_CORE_EFFECTIVE_LDFLAGS="${WASIX_CORE_LDFLAGS:-$FRESH_WASIX_CORE_PROFILE_LDFLAGS}"
-  FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT="${WASIXCC_RUN_WASM_OPT:-$FRESH_WASIX_CORE_PROFILE_WASM_OPT}"
-  FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_FLAGS="${WASIXCC_WASM_OPT_FLAGS:-$FRESH_WASIX_CORE_PROFILE_WASM_OPT_FLAGS}"
-  FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT="${WASIXCC_WASM_OPT_SUPPRESS_DEFAULT:-$FRESH_WASIX_CORE_PROFILE_WASM_OPT_SUPPRESS_DEFAULT}"
-  FRESH_WASIX_CORE_EXPECTED_ATOMIC_FENCE_TOTAL="$FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL"
-  FRESH_WASIX_CORE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL="$FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL"
-
-  case "$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT" in
-    yes|true|1) FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT="yes" ;;
-    no|false|0) FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT="no" ;;
-    *)
-      printf 'invalid WASIXCC_WASM_OPT_SUPPRESS_DEFAULT=%s; expected yes or no\n' \
-        "$FRESH_WASIX_CORE_EFFECTIVE_WASM_OPT_SUPPRESS_DEFAULT" >&2
-      return 2
-      ;;
-  esac
-}
-
-fresh_jobs() {
-  if command -v sysctl >/dev/null 2>&1; then
-    sysctl -n hw.ncpu 2>/dev/null && return
-  fi
-  if command -v nproc >/dev/null 2>&1; then
-    nproc 2>/dev/null && return
-  fi
-  echo 4
-}
-
-fresh_timestamp() {
-  date -u +"%Y-%m-%dT%H:%M:%SZ"
-}
-
-fresh_require_command() {
-  local name="$1"
-  if ! command -v "$name" >/dev/null 2>&1; then
-    echo "missing required command: $name" >&2
-    return 127
-  fi
-}
-
-# Return the stable repository identity for a file in this product source
-# tree.  Measurement tools may execute from a content-addressed physical copy
-# under target/, but build receipts must continue naming the canonical source
-# location.  Mixing those two identities makes byte-identical frozen tools
-# reject artifacts produced from the ordinary checkout.
-fresh_project_source_identity_path() {
-  local path="${1-}"
-  local relative
-
-  [ "$#" -eq 1 ] && [ -n "$path" ] && [ "${path#/}" != "$path" ] || {
-    printf 'fresh_project_source_identity_path requires one absolute path\n' >&2
-    return 2
-  }
-  case "$path" in
-    "$FRESH_ROOT"/*)
-      relative="${path#"$FRESH_ROOT"/}"
-      ;;
-    *)
-      printf 'source path is outside FRESH_ROOT: %s\n' "$path" >&2
-      return 2
-      ;;
-  esac
-  case "$relative" in
-    ""|/*|.|..|*/../*|../*|*/..|*/./*|./*|*/.)
-      printf 'source path is not canonical beneath FRESH_ROOT: %s\n' "$path" >&2
-      return 2
-      ;;
-  esac
-  printf '%s/%s\n' "$FRESH_PROJECT_SOURCE_ID_PREFIX" "$relative"
-}
-
-fresh_require_patched_wasixcc_sysroot() {
-  local carrier_manifest="$WASIXCC_SYSROOT_PREFIX/.oliphaunt-patched-sysroots.manifest"
-  local variant_manifest="$WASIXCC_SYSROOT/.oliphaunt-patched-sysroot.manifest"
-  local validator="$FRESH_ROOT/runtime/bin/validate-runtime-capabilities.sh"
-
-  if [ ! -f "$carrier_manifest" ] || [ ! -f "$variant_manifest" ]; then
-    {
-      printf 'missing exact patched WASIX libc carrier: %s\n' "$WASIXCC_SYSROOT"
-      printf 'Run %s/runtime/bin/build-patched-wasix-libc-sysroot.sh after preparing the pinned runtime sources.\n' "$FRESH_ROOT"
-    } >&2
-    return 2
-  fi
-
-  [ -x "$validator" ] || {
-    printf 'missing exact patched WASIX libc validator: %s\n' "$validator" >&2
-    return 2
-  }
-  UPSTREAM_WORK_ROOT="$FRESH_WORK_ROOT/runtime" \
-    WASIXCC_SYSROOT_PREFIX="$WASIXCC_SYSROOT_PREFIX" \
-    WASIXCC_SYSROOT_VARIANT="$WASIXCC_SYSROOT_VARIANT" \
-    WASIXCC_SYSROOT="$WASIXCC_SYSROOT" \
-    "$validator" --validate-sysroot-only >/dev/null
-}
-
-fresh_docker_bin() {
-  if command -v docker >/dev/null 2>&1; then
-    command -v docker
-    return
-  fi
-  echo "missing required command: docker" >&2
-  return 127
-}
-
-fresh_docker_path_for() {
-  local path="$1"
-
-  case "$path" in
-    "$REPO_ROOT")
-      printf '/work\n'
-      ;;
-    "$REPO_ROOT"/*)
-      printf '/work/%s\n' "${path#$REPO_ROOT/}"
-      ;;
-    *)
-      printf '%s\n' "$path"
-      ;;
-  esac
-}
-
-fresh_managed_generated_root() {
-  printf '%s/target/oliphaunt-wasix-postmaster\n' "$_fresh_source_repo_root"
-}
-
-# Fail closed before a builder removes or replaces generated output.  The
-# trust root is derived physically from this file, rather than from the
-# overridable REPO_ROOT or FRESH_WORK_ROOT variables. Rejecting every existing
-# symlink component is deliberately stricter than resolving and following it.
-fresh_require_managed_generated_path() {
-  local candidate="${1-}"
-  local label="${2:-generated path}"
-  local managed_root
-  local remainder
-  local component
-  local current=""
-  local has_more
-
-  if [ "$#" -lt 1 ] || [ "$#" -gt 2 ]; then
-    printf 'fresh_require_managed_generated_path expects a path and optional label\n' >&2
-    return 2
-  fi
-
-  managed_root="$(fresh_managed_generated_root)"
-  if [ -z "$candidate" ]; then
-    printf 'refusing empty %s\n' "$label" >&2
-    return 2
-  fi
-  case "$candidate" in
-    /*) ;;
-    *)
-      printf 'refusing non-absolute %s: %s\n' "$label" "$candidate" >&2
-      return 2
-      ;;
-  esac
-  if [ "$candidate" = "/" ] || [ "$candidate" = "$managed_root" ]; then
-    printf 'refusing unsafe %s root: %s\n' "$label" "$candidate" >&2
-    return 2
-  fi
-  case "$candidate" in
-    "$managed_root"/*) ;;
-    *)
-      printf 'refusing %s outside managed generated root %s: %s\n' \
-        "$label" "$managed_root" "$candidate" >&2
-      return 2
-      ;;
-  esac
-
-  remainder="${candidate#/}"
-  while :; do
-    case "$remainder" in
-      */*)
-        component="${remainder%%/*}"
-        remainder="${remainder#*/}"
-        has_more=1
-        ;;
-      *)
-        component="$remainder"
-        remainder=""
-        has_more=0
-        ;;
-    esac
-
-    case "$component" in
-      ""|.|..)
-        printf 'refusing non-canonical %s component in: %s\n' "$label" "$candidate" >&2
-        return 2
-        ;;
-    esac
-
-    current="$current/$component"
-    if [ -L "$current" ]; then
-      printf 'refusing symlink component in %s: %s\n' "$label" "$current" >&2
-      return 2
-    fi
-    if [ "$has_more" -eq 1 ] && [ -e "$current" ] && [ ! -d "$current" ]; then
-      printf 'refusing non-directory component in %s: %s\n' "$label" "$current" >&2
-      return 2
-    fi
-    [ "$has_more" -eq 1 ] || break
-  done
-}
-
-# Reserve one or more generated leaf directories without replacement. Parents
-# may be shared, but each requested leaf is claimed with plain mkdir so two
-# equal qualification labels cannot enter the same evidence namespace. No
-# caller writes until every leaf is held; a partial claim is rolled back only
-# while it remains empty.
-fresh_claim_generated_directories() {
-  local -a requested=("$@")
-  local -a claimed=()
-  local path other parent
-  local index
-
-  [ "${#requested[@]}" -gt 0 ] || {
-    printf 'fresh_claim_generated_directories requires at least one path\n' >&2
-    return 2
-  }
-  for path in "${requested[@]}"; do
-    fresh_require_managed_generated_path "$path" "generated directory claim" ||
-      return
-    for other in "${claimed[@]}"; do
-      [ "$path" != "$other" ] || {
-        printf 'duplicate generated directory claim: %s\n' "$path" >&2
-        return 2
-      }
-    done
-    claimed+=("$path")
-  done
-
-  claimed=()
-  for path in "${requested[@]}"; do
-    parent="$(dirname "$path")"
-    fresh_require_managed_generated_path "$parent" "generated claim parent" ||
-      return
-    mkdir -p "$parent" || return
-    fresh_require_managed_generated_path "$path" "generated directory claim" ||
-      return
-  done
-  for path in "${requested[@]}"; do
-    if ! mkdir -- "$path"; then
-      printf 'generated directory is already claimed: %s\n' "$path" >&2
-      for ((index = ${#claimed[@]} - 1; index >= 0; index--)); do
-        rmdir -- "${claimed[$index]}" 2>/dev/null || true
-      done
-      return 2
-    fi
-    claimed+=("$path")
-  done
-}
-
-fresh_ensure_dirs() {
-  mkdir -p "$REPORT_DIR" "$RUN_DIR" "$FRESH_WORK_ROOT/sources" "$FRESH_WORK_ROOT/work" \
-    "$FRESH_WORK_ROOT/builds" "$FRESH_WORK_ROOT/install" "$FRESH_WORK_ROOT/tools"
-}
-
-# Serialize publication and consumption of the canonical PostgreSQL baseline.
-# Callers keep the descriptor open for the complete interval in which they read
-# BASELINE_DIR. The permanent lock file lives outside that replaceable directory,
-# so staged publication cannot change the synchronization object.
-fresh_lock_postgres_baseline() {
-  local mode="${1-}"
-  local lock_dir="$FRESH_WORK_ROOT/baseline-locks"
-  local lock_path
-
-  [ "$#" -eq 1 ] || {
-    printf 'fresh_lock_postgres_baseline expects shared or exclusive\n' >&2
-    return 2
-  }
-  case "$mode" in
-    shared) mode=-s ;;
-    exclusive) mode=-x ;;
-    *)
-      printf 'invalid PostgreSQL baseline lock mode: %s\n' "$mode" >&2
-      return 2
-      ;;
-  esac
-  [ -z "${FRESH_POSTGRES_BASELINE_LOCK_FD:-}" ] || {
-    printf 'PostgreSQL baseline lock is already held by this shell\n' >&2
-    return 2
-  }
-  fresh_require_command flock || return
-  fresh_require_managed_generated_path "$BASELINE_DIR" BASELINE_DIR || return
-  fresh_require_managed_generated_path "$lock_dir" postgres-baseline-locks || return
-  mkdir -p "$lock_dir"
-  [ -d "$lock_dir" ] && [ ! -L "$lock_dir" ] || {
-    printf 'unsafe PostgreSQL baseline lock directory: %s\n' "$lock_dir" >&2
-    return 2
-  }
-  lock_path="$lock_dir/postgres-baseline.lock"
-  fresh_require_managed_generated_path "$lock_path" postgres-baseline-lock || return
-  [ ! -L "$lock_path" ] || {
-    printf 'unsafe PostgreSQL baseline lock: %s\n' "$lock_path" >&2
-    return 2
-  }
-  exec {FRESH_POSTGRES_BASELINE_LOCK_FD}>"$lock_path"
-  [ -f "$lock_path" ] && [ ! -L "$lock_path" ] || {
-    printf 'PostgreSQL baseline lock changed while opening: %s\n' "$lock_path" >&2
-    exec {FRESH_POSTGRES_BASELINE_LOCK_FD}>&-
-    unset FRESH_POSTGRES_BASELINE_LOCK_FD
-    return 2
-  }
-  flock "$mode" "$FRESH_POSTGRES_BASELINE_LOCK_FD" || {
-    printf 'could not acquire PostgreSQL baseline lock: %s\n' "$lock_path" >&2
-    exec {FRESH_POSTGRES_BASELINE_LOCK_FD}>&-
-    unset FRESH_POSTGRES_BASELINE_LOCK_FD
-    return 2
-  }
-  FRESH_POSTGRES_BASELINE_LOCK_PATH="$lock_path"
-}
-
-fresh_unlock_postgres_baseline() {
-  if [ -n "${FRESH_POSTGRES_BASELINE_LOCK_FD:-}" ]; then
-    exec {FRESH_POSTGRES_BASELINE_LOCK_FD}>&-
-  fi
-  unset FRESH_POSTGRES_BASELINE_LOCK_FD
-  unset FRESH_POSTGRES_BASELINE_LOCK_PATH
-}
-
-fresh_postgres_baseline_fingerprint() {
-  local version
-  local archive_sha256
-
-  [ -f "$POSTGRES_SOURCE_TOML" ] && [ ! -L "$POSTGRES_SOURCE_TOML" ] || {
-    printf 'missing regular PostgreSQL source manifest: %s\n' "$POSTGRES_SOURCE_TOML" >&2
-    return 2
-  }
-  version="$(awk -F= '
-    $1 ~ /^[[:space:]]*version[[:space:]]*$/ {
-      count += 1
-      value = $2
-      gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
-      gsub(/^"|"$/, "", value)
-    }
-    END { if (count != 1 || value == "") exit 2; print value }
-  ' "$POSTGRES_SOURCE_TOML")" || {
-    printf 'PostgreSQL source manifest must contain one version: %s\n' \
-      "$POSTGRES_SOURCE_TOML" >&2
-    return 2
-  }
-  archive_sha256="$(awk -F= '
-    $1 ~ /^[[:space:]]*sha256[[:space:]]*$/ {
-      count += 1
-      value = $2
-      gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
-      gsub(/^"|"$/, "", value)
-    }
-    END { if (count != 1 || value == "") exit 2; print value }
-  ' "$POSTGRES_SOURCE_TOML")" || {
-    printf 'PostgreSQL source manifest must contain one SHA-256: %s\n' \
-      "$POSTGRES_SOURCE_TOML" >&2
-    return 2
-  }
-  [ "$version" = "$POSTGRES_VERSION" ] && fresh_is_sha256 "$archive_sha256" || {
-    printf 'invalid PostgreSQL baseline source identity in %s\n' \
-      "$POSTGRES_SOURCE_TOML" >&2
-    return 2
-  }
-  printf '%s:%s\n' "$version" "$archive_sha256"
-}
-
-# Validate that BASELINE_DIR is the exact clean Git tree materialized from the
-# pinned PostgreSQL archive.  The manifest lives inside the checkout so an
-# overridden BASELINE_DIR cannot accidentally inherit another checkout's
-# global fingerprint.
-fresh_require_postgres_baseline() {
-  local expected_fingerprint="${1-}"
-  local manifest="$BASELINE_DIR/.git/oliphaunt-baseline.manifest"
-  local head
-  local tree
-
-  [ "$#" -eq 1 ] && [ -n "$expected_fingerprint" ] || {
-    printf 'fresh_require_postgres_baseline requires an expected fingerprint\n' >&2
-    return 2
-  }
-  [ -d "$BASELINE_DIR" ] && [ ! -L "$BASELINE_DIR" ] &&
-    [ -d "$BASELINE_DIR/.git" ] && [ ! -L "$BASELINE_DIR/.git" ] &&
-    [ -f "$manifest" ] && [ ! -L "$manifest" ] || return 1
-  fresh_require_manifest_value "$manifest" schema \
-    oliphaunt.wasix-postmaster.postgres-baseline.v1 >/dev/null 2>&1 || return 1
-  fresh_require_manifest_value "$manifest" fingerprint \
-    "$expected_fingerprint" >/dev/null 2>&1 || return 1
-  head="$(git -C "$BASELINE_DIR" rev-parse --verify 'HEAD^{commit}' 2>/dev/null)" || return 1
-  tree="$(git -C "$BASELINE_DIR" rev-parse --verify 'HEAD^{tree}' 2>/dev/null)" || return 1
-  fresh_require_manifest_value "$manifest" head "$head" >/dev/null 2>&1 || return 1
-  fresh_require_manifest_value "$manifest" tree "$tree" >/dev/null 2>&1 || return 1
-  [ -z "$(git -C "$BASELINE_DIR" status --porcelain=v1 --untracked-files=all --ignored 2>/dev/null)" ] || return 1
-  FRESH_POSTGRES_BASELINE_HEAD="$head"
-  FRESH_POSTGRES_BASELINE_TREE="$tree"
-}
-
-fresh_host_arch() {
-  case "$(uname -s)-$(uname -m)" in
-    Darwin-arm64) echo "darwin-arm64" ;;
-    Darwin-x86_64) echo "darwin-amd64" ;;
-    Linux-x86_64) echo "linux-amd64" ;;
-    Linux-aarch64|Linux-arm64) echo "linux-arm64" ;;
-    *)
-      echo "unsupported host for patched Wasmer runtime: $(uname -s)-$(uname -m)" >&2
-      return 2
-      ;;
-  esac
-}
-
-fresh_host_abi() {
-  local ldd_version
-  local glibc_version
-
-  case "$(uname -s)" in
-    Darwin) echo "darwin" ;;
-    Linux)
-      glibc_version="$(getconf GNU_LIBC_VERSION 2>/dev/null || true)"
-      if [ -n "$glibc_version" ]; then
-        echo "linux-gnu"
-        return
-      fi
-      if command -v ldd >/dev/null 2>&1; then
-        ldd_version="$(ldd --version 2>&1 | head -1 || true)"
-        case "$ldd_version" in
-          *musl*|*Musl*) echo "linux-musl"; return ;;
-          *GLIBC*|*glibc*|*GNU*) echo "linux-gnu"; return ;;
-        esac
-      fi
-      echo "unable to identify Linux libc ABI for patched Wasmer receipt" >&2
-      return 2
-      ;;
-    MINGW*|MSYS*|CYGWIN*) echo "windows-gnu" ;;
-    *)
-      echo "unsupported host ABI for patched Wasmer receipt: $(uname -s)" >&2
-      return 2
-      ;;
-  esac
-}
-
-fresh_release_target_for_host_arch() {
-  case "$1" in
-    darwin-arm64) echo "macos-arm64" ;;
-    linux-arm64) echo "linux-arm64-gnu" ;;
-    linux-amd64) echo "linux-x64-gnu" ;;
-    *)
-      printf 'unsupported WASIX postmaster release host: %s\n' "$1" >&2
-      return 2
-      ;;
-  esac
-}
-
-fresh_release_target() {
-  local host_arch
-  host_arch="$(fresh_host_arch)" || return
-  fresh_release_target_for_host_arch "$host_arch"
-}
-
-fresh_release_target_triple() {
-  case "$1" in
-    linux-arm64-gnu) echo "aarch64-unknown-linux-gnu" ;;
-    linux-x64-gnu) echo "x86_64-unknown-linux-gnu" ;;
-    macos-arm64) echo "aarch64-apple-darwin" ;;
-    *)
-      printf 'unsupported WASIX postmaster release target: %s\n' "$1" >&2
-      return 2
-      ;;
-  esac
-}
-
-fresh_manifest_value() {
-  local manifest="$1"
-  local key="$2"
-
-  awk -v expected_key="$key" '
-    {
-      separator = index($0, "=")
-      if (separator > 0 && substr($0, 1, separator - 1) == expected_key) {
-        count += 1
-        value = substr($0, separator + 1)
-      }
-    }
-    END {
-      if (count != 1) exit 2
-      print value
-    }
-  ' "$manifest"
-}
-
-fresh_require_manifest_value() {
-  local manifest="$1"
-  local key="$2"
-  local expected="$3"
-  local actual
-
-  if ! actual="$(fresh_manifest_value "$manifest" "$key")"; then
-    printf 'manifest must contain exactly one %s field: %s\n' "$key" "$manifest" >&2
-    return 2
-  fi
-  if [ "$actual" != "$expected" ]; then
-    printf 'manifest %s mismatch: expected %s, got %s\n' \
-      "$key" "$expected" "${actual:-}" >&2
-    return 2
-  fi
-}
-
-fresh_validate_wasmer_build_receipt_shape() {
-  local receipt="$1"
-
-  awk -F= '
-    BEGIN {
-      split("schema build_recipe_sha256 wasmer_source_commit wasmer_napi_commit wasmer_test_files_commit wasmer_spec_commit wasmer_patch_sha256 wasmer_prepared_signature_sha256 wasmer_cargo_lock_sha256 wasmer_binary_sha256 wasmer_features wasmer_headless_binary_sha256 wasmer_headless_features runtime_abi_id artifact_abi_version wasix_libc_source_commit wasix_libc_patch_sha256 wasix_libc_prepared_signature_sha256 sysroot_carrier_manifest_sha256 sysroot_variant sysroot_variant_manifest_sha256 host_platform host_abi rustc_host rustc_version llvm_version", fields, " ")
-      for (i in fields) allowed[fields[i]] = 1
-    }
-    index($0, "\r") || NF != 2 || $1 == "" || $2 == "" || !($1 in allowed) || seen[$1]++ || $1 != fields[NR] { exit 2 }
-    END {
-      if (NR != 26) exit 2
-      for (key in allowed) if (seen[key] != 1) exit 2
-    }
-  ' "$receipt" || {
-    printf 'invalid or non-canonical Wasmer build receipt: %s\n' "$receipt" >&2
-    return 2
-  }
-}
-
-fresh_validate_postmaster_executor_build_receipt_shape() {
-  local receipt="$1"
-
-  awk -F= '
-    BEGIN {
-      split("schema build_recipe_sha256 wasmer_build_receipt_sha256 wasmer_source_commit wasmer_patch_sha256 wasmer_prepared_signature_sha256 wasmer_cargo_lock_sha256 runtime_abi_id artifact_abi_version executor_package executor_binary executor_features executor_role runtime_policy_id cli_contract executor_binary_sha256 start_proof_binary start_proof_features start_proof_policy start_proof_binary_sha256 memory_profile_binary memory_profile_features linear_memory_profile_id memory_profile_binary_sha256 postmaster_compiler_binary postmaster_compiler_features compiler_cpu_policy compiler_cpu_features postmaster_compiler_binary_sha256 host_platform host_abi rustc_host rustc_version", fields, " ")
-      for (i in fields) allowed[fields[i]] = 1
-    }
-    index($0, "\r") || NF != 2 || $1 == "" || $2 == "" || !($1 in allowed) || seen[$1]++ || $1 != fields[NR] { exit 2 }
-    END {
-      if (NR != 33) exit 2
-      for (key in allowed) if (seen[key] != 1) exit 2
-    }
-  ' "$receipt" || {
-    printf 'invalid or non-canonical postmaster executor build receipt: %s\n' "$receipt" >&2
-    return 2
-  }
-}
-
-fresh_is_sha256() {
-  [ "${#1}" -eq 64 ] || return 1
-  case "$1" in
-    *[!0-9a-f]*) return 1 ;;
-    *) return 0 ;;
-  esac
-}
-
-fresh_require_receipt_sha256() {
-  local receipt="$1"
-  local key="$2"
-  local value
-
-  value="$(fresh_manifest_value "$receipt" "$key")" || {
-    printf 'Wasmer build receipt must contain exactly one %s field: %s\n' "$key" "$receipt" >&2
-    return 2
-  }
-  fresh_is_sha256 "$value" || {
-    printf 'Wasmer build receipt %s is not a lowercase SHA-256: %s\n' "$key" "$receipt" >&2
-    return 2
-  }
-}
-
-fresh_sha256_stream() {
-  if command -v sha256sum >/dev/null 2>&1; then
-    sha256sum | awk '{print $1}'
-  else
-    shasum -a 256 | awk '{print $1}'
-  fi
-}
-
-fresh_require_canonical_directory() {
-  local label="${1-}"
-  local path="${2-}"
-  local resolved
-
-  [ "$#" -eq 2 ] && [ -n "$label" ] && [ -n "$path" ] && [ "${path#/}" != "$path" ] || {
-    printf 'canonical directory validation requires a label and absolute path\n' >&2
-    return 2
-  }
-  resolved="$(cd -P -- "$path" 2>/dev/null && pwd -P)" || {
-    printf '%s is not an existing directory: %s\n' "$label" "$path" >&2
-    return 2
-  }
-  [ "$resolved" = "$path" ] || {
-    printf '%s is not an absolute canonical directory: %s (resolved %s)\n' \
-      "$label" "$path" "$resolved" >&2
-    return 2
-  }
-}
-
-fresh_wasix_builder_recipe_sha256() {
-  local file_sha256
-  local identity_mode
-  local path
-  local recipe_paths=(
-    "$WASIX_TOOLCHAIN_ROOT/docker/Dockerfile"
-    "$WASIX_TOOLCHAIN_ROOT/docker/isrg-root-x1.pem"
-    "$WASIX_TOOLCHAIN_ROOT/docker/install-pinned-apt-packages.sh"
-    "$WASIX_TOOLCHAIN_ROOT/docker/install-pinned-wasixcc.sh"
-    "$WASIX_TOOLCHAIN_ROOT/docker/pinned-wasixcc-assets.tsv"
-  )
-
-  fresh_require_canonical_directory REPO_ROOT "$REPO_ROOT" || return
-  fresh_require_canonical_directory WASIX_TOOLCHAIN_ROOT "$WASIX_TOOLCHAIN_ROOT" || return
-  {
-    printf '%s\0%s\0' schema oliphaunt.wasix-builder-recipe.v1
-    for path in "${recipe_paths[@]}"; do
-      [ -f "$path" ] && [ ! -L "$path" ] || {
-        printf 'missing regular WASIX builder-recipe input: %s\n' "$path" >&2
-        return 2
-      }
-      file_sha256="$(fresh_wasmer_bin_hash "$path")" || return
-      fresh_is_sha256 "$file_sha256" || {
-        printf 'failed to hash WASIX builder-recipe input: %s\n' "$path" >&2
-        return 2
-      }
-      if [ -x "$path" ]; then
-        identity_mode=executable
-      else
-        identity_mode=data
-      fi
-      printf '%s\0%s\0%s\0' "${path#"$WASIX_TOOLCHAIN_ROOT"/}" "$file_sha256" "$identity_mode"
-    done
-  } | fresh_sha256_stream
-}
-
-fresh_runtime_build_recipe_sha256() {
-  local builder_recipe_sha256
-  local file_sha256
-  local identity_path
-  local identity_mode
-  local path
-  local recipe_paths=(
-    "$FRESH_ROOT/lib/common.sh"
-    "$FRESH_ROOT/sources.lock.toml"
-    "$FRESH_ROOT/runtime/capabilities.tsv"
-    "$FRESH_POSTMASTER_TASK_BUDGET_PROFILE"
-    "$FRESH_POSTMASTER_RUNTIME_FOOTPRINT_PROFILE"
-    "$FRESH_ROOT/runtime/bin/prepare-upstream-checkouts.sh"
-    "$FRESH_ROOT/runtime/bin/build-runtime.sh"
-    "$FRESH_ROOT/runtime/bin/build-patched-wasix-libc-sysroot.sh"
-    "$FRESH_ROOT/runtime/bin/validate-runtime-capabilities.sh"
-    "$FRESH_ROOT/runtime/bin/verify-source-lock.py"
-    "$WASIX_TOOLCHAIN_ROOT/docker_wasix_env.sh"
-  )
-
-  fresh_require_canonical_directory FRESH_ROOT "$FRESH_ROOT" || return
-  fresh_require_canonical_directory REPO_ROOT "$REPO_ROOT" || return
-  fresh_require_canonical_directory WASIX_TOOLCHAIN_ROOT "$WASIX_TOOLCHAIN_ROOT" || return
-
-  for path in "${recipe_paths[@]}"; do
-    [ -f "$path" ] && [ ! -L "$path" ] || {
-      printf 'missing regular runtime build-recipe input: %s\n' "$path" >&2
-      return 2
-    }
-  done
-  builder_recipe_sha256="$(fresh_wasix_builder_recipe_sha256)" || return
-  fresh_is_sha256 "$builder_recipe_sha256" || {
-    printf 'failed to derive WASIX builder-recipe identity\n' >&2
-    return 2
-  }
-  {
-    printf '%s\0%s\0' schema oliphaunt.wasix-postmaster.runtime-build-recipe.v3
-    printf '%s\0%s\0' wasix-builder-recipe-sha256 "$builder_recipe_sha256"
-    for path in "${recipe_paths[@]}"; do
-      case "$path" in
-        "$FRESH_ROOT"/*)
-          identity_path="$(fresh_project_source_identity_path "$path")" || return
-          ;;
-        "$REPO_ROOT"/*)
-          identity_path="${path#"$REPO_ROOT"/}"
-          ;;
-        *)
-          # An explicitly overridden external toolchain remains bound to its
-          # absolute location. Product-local sources must always use the
-          # canonical repository identity above so a byte-identical frozen
-          # measurement closure validates the same receipt.
-          identity_path="$path"
-          ;;
-      esac
-      file_sha256="$(fresh_wasmer_bin_hash "$path")" || return
-      fresh_is_sha256 "$file_sha256" || {
-        printf 'failed to hash runtime build-recipe input: %s\n' "$path" >&2
-        return 2
-      }
-      if [ -x "$path" ]; then
-        identity_mode=executable
-      else
-        identity_mode=data
-      fi
-      printf '%s\0%s\0%s\0' "$identity_path" "$file_sha256" "$identity_mode"
-    done
-  } | fresh_sha256_stream
-}
-
-# This identity is embedded into both native executors at compile time and into
-# every sealed AOT carrier.  Keep the serialization explicit and
-# length-unambiguous: changing a source pin, patch, Cargo resolution, native
-# target/ABI, feature set, artifact ABI, or tracked build recipe changes the
-# identity and makes old compiler output fail closed under the new executor.
-fresh_runtime_abi_id() {
-  local cargo_lock_sha256="$1"
-  local target_triple="$2"
-  local host_platform="$3"
-  local host_abi="$4"
-  local wasmer_patch="$FRESH_ROOT/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch"
-  local wasix_libc_patch="$FRESH_ROOT/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
-
-  fresh_is_sha256 "$cargo_lock_sha256" || {
-    printf 'runtime ABI Cargo.lock identity is not a lowercase SHA-256\n' >&2
-    return 2
-  }
-  [ -n "$target_triple" ] && [ -n "$host_platform" ] && [ -n "$host_abi" ] || {
-    printf 'runtime ABI target and host identity fields must be nonempty\n' >&2
-    return 2
-  }
-  [ -f "$wasmer_patch" ] && [ ! -L "$wasmer_patch" ] || return 2
-  [ -f "$wasix_libc_patch" ] && [ ! -L "$wasix_libc_patch" ] || return 2
-
-  {
-    printf '%s\0%s\0' schema oliphaunt.wasix-postmaster.runtime-abi.v1
-    printf '%s\0%s\0' wasmer-source-commit "$FRESH_WASMER_SOURCE_COMMIT"
-    printf '%s\0%s\0' wasmer-napi-commit "$FRESH_WASMER_NAPI_COMMIT"
-    printf '%s\0%s\0' wasmer-test-files-commit "$FRESH_WASMER_TEST_FILES_COMMIT"
-    printf '%s\0%s\0' wasmer-spec-commit "$FRESH_WASMER_SPEC_COMMIT"
-    printf '%s\0%s\0' wasmer-patch-sha256 "$(fresh_wasmer_bin_hash "$wasmer_patch")"
-    printf '%s\0%s\0' wasmer-cargo-lock-sha256 "$cargo_lock_sha256"
-    printf '%s\0%s\0' wasix-libc-source-commit "$FRESH_WASIX_LIBC_SOURCE_COMMIT"
-    printf '%s\0%s\0' wasix-libc-patch-sha256 "$(fresh_wasmer_bin_hash "$wasix_libc_patch")"
-    printf '%s\0%s\0' sysroot-variant "$WASIXCC_SYSROOT_VARIANT"
-    printf '%s\0%s\0' target-triple "$target_triple"
-    printf '%s\0%s\0' host-platform "$host_platform"
-    printf '%s\0%s\0' host-abi "$host_abi"
-    printf '%s\0%s\0' wasmer-version "$FRESH_WASMER_VERSION"
-    printf '%s\0%s\0' wasmer-wasix-version "$FRESH_WASMER_WASIX_VERSION"
-    printf '%s\0%s\0' compiler-features "$FRESH_WASMER_COMPILER_FEATURES"
-    printf '%s\0%s\0' headless-features "$FRESH_WASMER_HEADLESS_FEATURES"
-    printf '%s\0%s\0' artifact-abi-version "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
-    printf '%s\0%s\0' build-recipe-sha256 "$(fresh_runtime_build_recipe_sha256)"
-  } | fresh_sha256_stream
-}
-
-fresh_runtime_worktree_state_hash() {
-  local root="$1"
-  local path
-
-  {
-    git -C "$root" diff --binary HEAD
-    git -C "$root" ls-files --others --exclude-standard -z |
-      while IFS= read -r -d '' path; do
-        printf 'untracked:%s\n' "$path"
-        fresh_wasmer_bin_hash "$root/$path"
-      done
-  } | fresh_sha256_stream
-}
-
-fresh_require_prepared_worktree() {
-  local label="$1"
-  local root="$2"
-  local source_commit="$3"
-  local patch_hash="$4"
-  local extra_signature="$5"
-  local signature_file="$6"
-  local expected_signature
-
-  [ -d "$root/.git" ] && [ ! -L "$root" ] || {
-    printf 'missing prepared %s worktree: %s\n' "$label" "$root" >&2
-    return 2
-  }
-  [ -f "$signature_file" ] && [ ! -L "$signature_file" ] || {
-    printf 'missing regular prepared %s signature: %s\n' "$label" "$signature_file" >&2
-    return 2
-  }
-  [ "$(git -C "$root" rev-parse HEAD)" = "$source_commit" ] || {
-    printf 'prepared %s worktree is not at %s: %s\n' "$label" "$source_commit" "$root" >&2
-    return 2
-  }
-  expected_signature="$source_commit:$patch_hash:$extra_signature:$(fresh_runtime_worktree_state_hash "$root")"
-  [ "$(cat "$signature_file")" = "$expected_signature" ] || {
-    printf 'prepared %s worktree no longer matches its source-and-patch signature: %s\n' "$label" "$root" >&2
-    return 2
-  }
-}
-
-# Builder-only provenance verification. Runtime selection does not depend on
-# disposable source worktrees or the compilation sysroot being present.
-fresh_require_local_wasmer_build_state() {
-  local receipt="$1"
-  local runtime_root="$FRESH_WORK_ROOT/runtime"
-  local wasmer_root="$runtime_root/wasmer"
-  local wasix_libc_root="$runtime_root/wasix-libc"
-  local wasmer_signature="$runtime_root/.prepared/wasmer.signature"
-  local wasix_libc_signature="$runtime_root/.prepared/wasix-libc.signature"
-  local carrier_manifest="$WASIXCC_SYSROOT_PREFIX/.oliphaunt-patched-sysroots.manifest"
-  local variant_manifest="$WASIXCC_SYSROOT/.oliphaunt-patched-sysroot.manifest"
-  local wasmer_patch="$FRESH_ROOT/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch"
-  local wasix_libc_patch="$FRESH_ROOT/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
-  local wasmer_patch_hash
-  local wasix_libc_patch_hash
-
-  fresh_require_command git || return
-  wasmer_patch_hash="$(fresh_wasmer_bin_hash "$wasmer_patch")"
-  wasix_libc_patch_hash="$(fresh_wasmer_bin_hash "$wasix_libc_patch")"
-  fresh_require_prepared_worktree \
-    Wasmer "$wasmer_root" "$FRESH_WASMER_SOURCE_COMMIT" "$wasmer_patch_hash" \
-    "$FRESH_WASMER_NAPI_COMMIT:$FRESH_WASMER_TEST_FILES_COMMIT:$FRESH_WASMER_SPEC_COMMIT" \
-    "$wasmer_signature" || return
-  fresh_require_prepared_worktree \
-    wasix-libc "$wasix_libc_root" "$FRESH_WASIX_LIBC_SOURCE_COMMIT" "$wasix_libc_patch_hash" \
-    "" "$wasix_libc_signature" || return
-  [ -f "$wasmer_root/Cargo.lock" ] && [ ! -L "$wasmer_root/Cargo.lock" ] || {
-    printf 'missing regular Wasmer Cargo.lock: %s\n' "$wasmer_root/Cargo.lock" >&2
-    return 2
-  }
-  fresh_require_patched_wasixcc_sysroot || return
-  fresh_require_manifest_value \
-    "$receipt" wasmer_prepared_signature_sha256 "$(fresh_wasmer_bin_hash "$wasmer_signature")" || return
-  fresh_require_manifest_value \
-    "$receipt" build_recipe_sha256 "$(fresh_runtime_build_recipe_sha256)" || return
-  fresh_require_manifest_value \
-    "$receipt" wasmer_cargo_lock_sha256 "$(fresh_wasmer_bin_hash "$wasmer_root/Cargo.lock")" || return
-  fresh_require_manifest_value \
-    "$receipt" wasix_libc_prepared_signature_sha256 "$(fresh_wasmer_bin_hash "$wasix_libc_signature")" || return
-  fresh_require_manifest_value \
-    "$receipt" sysroot_carrier_manifest_sha256 "$(fresh_wasmer_bin_hash "$carrier_manifest")" || return
-  fresh_require_manifest_value \
-    "$receipt" sysroot_variant_manifest_sha256 "$(fresh_wasmer_bin_hash "$variant_manifest")" || return
-}
-
-fresh_require_patched_wasmer_receipt() {
-  local manifest="${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}"
-  local wasmer_patch="$FRESH_ROOT/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch"
-  local wasix_libc_patch="$FRESH_ROOT/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
-
-  [ -f "$manifest" ] && [ ! -L "$manifest" ] || {
-    printf 'missing regular Wasmer build receipt: %s\n' "$manifest" >&2
-    printf 'Run %s/runtime/bin/build-runtime.sh, or provide a matching WASMER_BUILD_RECEIPT.\n' "$FRESH_ROOT" >&2
-    return 2
-  }
-  [ -f "$wasmer_patch" ] && [ ! -L "$wasmer_patch" ] || return 2
-  [ -f "$wasix_libc_patch" ] && [ ! -L "$wasix_libc_patch" ] || return 2
-
-  fresh_validate_wasmer_build_receipt_shape "$manifest" || return
-  fresh_require_manifest_value \
-    "$manifest" schema oliphaunt.wasix-postmaster.wasmer-build.v2 || return
-  fresh_require_manifest_value \
-    "$manifest" build_recipe_sha256 "$(fresh_runtime_build_recipe_sha256)" || return
-  fresh_require_manifest_value \
-    "$manifest" wasmer_source_commit "$FRESH_WASMER_SOURCE_COMMIT" || return
-  fresh_require_manifest_value \
-    "$manifest" wasmer_napi_commit "$FRESH_WASMER_NAPI_COMMIT" || return
-  fresh_require_manifest_value \
-    "$manifest" wasmer_test_files_commit "$FRESH_WASMER_TEST_FILES_COMMIT" || return
-  fresh_require_manifest_value \
-    "$manifest" wasmer_spec_commit "$FRESH_WASMER_SPEC_COMMIT" || return
-  fresh_require_manifest_value \
-    "$manifest" wasix_libc_source_commit "$FRESH_WASIX_LIBC_SOURCE_COMMIT" || return
-  fresh_require_manifest_value \
-    "$manifest" wasmer_patch_sha256 "$(fresh_wasmer_bin_hash "$wasmer_patch")" || return
-  fresh_require_manifest_value \
-    "$manifest" wasix_libc_patch_sha256 "$(fresh_wasmer_bin_hash "$wasix_libc_patch")" || return
-  fresh_require_manifest_value \
-    "$manifest" wasmer_features "$FRESH_WASMER_COMPILER_FEATURES" || return
-  fresh_require_manifest_value \
-    "$manifest" wasmer_headless_features "$FRESH_WASMER_HEADLESS_FEATURES" || return
-  fresh_require_manifest_value \
-    "$manifest" artifact_abi_version "$FRESH_WASMER_ARTIFACT_ABI_VERSION" || return
-  fresh_require_manifest_value \
-    "$manifest" host_platform "$(fresh_host_arch)" || return
-  fresh_require_manifest_value \
-    "$manifest" host_abi "$(fresh_host_abi)" || return
-  fresh_require_manifest_value \
-    "$manifest" runtime_abi_id "$(fresh_runtime_abi_id \
-      "$(fresh_manifest_value "$manifest" wasmer_cargo_lock_sha256)" \
-      "$(fresh_manifest_value "$manifest" rustc_host)" \
-      "$(fresh_manifest_value "$manifest" host_platform)" \
-      "$(fresh_manifest_value "$manifest" host_abi)")" || return
-
-  local hash_field
-  for hash_field in \
-    build_recipe_sha256 \
-    wasmer_patch_sha256 \
-    wasmer_prepared_signature_sha256 \
-    wasmer_cargo_lock_sha256 \
-    wasmer_binary_sha256 \
-    wasmer_headless_binary_sha256 \
-    runtime_abi_id \
-    wasix_libc_patch_sha256 \
-    wasix_libc_prepared_signature_sha256 \
-    sysroot_carrier_manifest_sha256 \
-    sysroot_variant_manifest_sha256
-  do
-    fresh_require_receipt_sha256 "$manifest" "$hash_field" || return
-  done
-}
-
-fresh_require_patched_wasmer() {
-  local wasmer_bin="$1"
-  local manifest="${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}"
-
-  [ -f "$wasmer_bin" ] && [ ! -L "$wasmer_bin" ] && [ -x "$wasmer_bin" ] || {
-    printf 'missing executable patched Wasmer binary: %s\n' "$wasmer_bin" >&2
-    return 2
-  }
-  fresh_require_patched_wasmer_receipt || return
-  fresh_require_manifest_value \
-    "$manifest" wasmer_binary_sha256 "$(fresh_wasmer_bin_hash "$wasmer_bin")"
-}
-
-fresh_require_patched_wasmer_headless() {
-  local wasmer_bin="$1"
-  local manifest="${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}"
-
-  [ -f "$wasmer_bin" ] && [ ! -L "$wasmer_bin" ] && [ -x "$wasmer_bin" ] || {
-    printf 'missing executable patched headless Wasmer binary: %s\n' "$wasmer_bin" >&2
-    return 2
-  }
-  fresh_require_patched_wasmer_receipt || return
-  fresh_require_manifest_value \
-    "$manifest" wasmer_headless_binary_sha256 "$(fresh_wasmer_bin_hash "$wasmer_bin")"
-}
-
-# Select the product-specific sealed-postmaster executor independently from the
-# general compiler-free Wasmer CLI.  Its receipt binds the exact parent runtime
-# receipt as well as the isolated Cargo feature/package build, so a carrier can
-# retain the established AOT manifest format without treating two native
-# executors as interchangeable.
-fresh_require_patched_postmaster_executor() {
-  local executor_bin="$1"
-  local executor_receipt="${2:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
-  local wasmer_receipt="${3:-${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}}"
-  local hash_field
-
-  [ -f "$executor_bin" ] && [ ! -L "$executor_bin" ] && [ -x "$executor_bin" ] || {
-    printf 'missing executable postmaster executor binary: %s\n' "$executor_bin" >&2
-    return 2
-  }
-  [ -f "$executor_receipt" ] && [ ! -L "$executor_receipt" ] || {
-    printf 'missing regular postmaster executor build receipt: %s\n' "$executor_receipt" >&2
-    return 2
-  }
-  [ -f "$wasmer_receipt" ] && [ ! -L "$wasmer_receipt" ] || {
-    printf 'missing regular parent Wasmer build receipt: %s\n' "$wasmer_receipt" >&2
-    return 2
-  }
-
-  WASMER_BUILD_RECEIPT="$wasmer_receipt" fresh_require_patched_wasmer_receipt || return
-  fresh_validate_postmaster_executor_build_receipt_shape "$executor_receipt" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" schema \
-    oliphaunt.wasix-postmaster.postmaster-executor-build.v3 || return
-  fresh_require_manifest_value \
-    "$executor_receipt" build_recipe_sha256 \
-    "$(fresh_runtime_build_recipe_sha256)" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" wasmer_build_receipt_sha256 \
-    "$(fresh_wasmer_bin_hash "$wasmer_receipt")" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" wasmer_source_commit "$FRESH_WASMER_SOURCE_COMMIT" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" wasmer_patch_sha256 \
-    "$(fresh_wasmer_bin_hash "$FRESH_ROOT/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch")" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" wasmer_prepared_signature_sha256 \
-    "$(fresh_manifest_value "$wasmer_receipt" wasmer_prepared_signature_sha256)" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" wasmer_cargo_lock_sha256 \
-    "$(fresh_manifest_value "$wasmer_receipt" wasmer_cargo_lock_sha256)" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" runtime_abi_id \
-    "$(fresh_manifest_value "$wasmer_receipt" runtime_abi_id)" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" artifact_abi_version "$FRESH_WASMER_ARTIFACT_ABI_VERSION" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" executor_package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" executor_binary "$FRESH_POSTMASTER_EXECUTOR_BINARY" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" executor_features "$FRESH_POSTMASTER_EXECUTOR_FEATURES" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" executor_role "$FRESH_POSTMASTER_EXECUTOR_ROLE" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" runtime_policy_id \
-    "$FRESH_POSTMASTER_EXECUTOR_RUNTIME_POLICY_ID" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" cli_contract "$FRESH_POSTMASTER_EXECUTOR_CLI_CONTRACT" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" executor_binary_sha256 \
-    "$(fresh_wasmer_bin_hash "$executor_bin")" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" start_proof_binary "$FRESH_START_PROOF_BINARY" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" start_proof_features "$FRESH_START_PROOF_FEATURES" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" start_proof_policy "$FRESH_START_PROOF_POLICY" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" memory_profile_binary "$FRESH_MEMORY_PROFILE_BINARY" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" memory_profile_features "$FRESH_MEMORY_PROFILE_FEATURES" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" linear_memory_profile_id "$FRESH_LINEAR_MEMORY_PROFILE_ID" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" postmaster_compiler_binary "$FRESH_POSTMASTER_COMPILER_BINARY" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" postmaster_compiler_features "$FRESH_POSTMASTER_COMPILER_FEATURES" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" compiler_cpu_policy generic-baseline || return
-  fresh_require_manifest_value \
-    "$executor_receipt" compiler_cpu_features none || return
-  fresh_require_manifest_value \
-    "$executor_receipt" host_platform "$(fresh_host_arch)" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" host_abi "$(fresh_host_abi)" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" rustc_host \
-    "$(fresh_manifest_value "$wasmer_receipt" rustc_host)" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" rustc_version \
-    "$(fresh_manifest_value "$wasmer_receipt" rustc_version)" || return
-
-  for hash_field in \
-    build_recipe_sha256 \
-    wasmer_build_receipt_sha256 \
-    wasmer_patch_sha256 \
-    wasmer_prepared_signature_sha256 \
-    wasmer_cargo_lock_sha256 \
-    runtime_abi_id \
-    executor_binary_sha256 \
-    start_proof_binary_sha256 \
-    memory_profile_binary_sha256 \
-    postmaster_compiler_binary_sha256
-  do
-    fresh_require_receipt_sha256 "$executor_receipt" "$hash_field" || return
-  done
-}
-
-fresh_require_memory_profile_tool() {
-  local profile_bin="${1:-$FRESH_MEMORY_PROFILE_BIN}"
-  local executor_receipt="${2:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
-  local actual_id
-
-  [ -f "$profile_bin" ] && [ ! -L "$profile_bin" ] && [ -x "$profile_bin" ] || {
-    printf 'missing executable linear-memory profile tool: %s\n' "$profile_bin" >&2
-    return 2
-  }
-  fresh_validate_postmaster_executor_build_receipt_shape "$executor_receipt" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" schema \
-    oliphaunt.wasix-postmaster.postmaster-executor-build.v3 || return
-  fresh_require_manifest_value \
-    "$executor_receipt" memory_profile_binary "$FRESH_MEMORY_PROFILE_BINARY" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" memory_profile_features "$FRESH_MEMORY_PROFILE_FEATURES" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" linear_memory_profile_id "$FRESH_LINEAR_MEMORY_PROFILE_ID" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" memory_profile_binary_sha256 \
-    "$(fresh_wasmer_bin_hash "$profile_bin")" || return
-  actual_id="$("$profile_bin" --profile-json | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')" || {
-    printf 'could not read linear-memory profile identity from %s\n' "$profile_bin" >&2
-    return 2
-  }
-  [ "$actual_id" = "$FRESH_LINEAR_MEMORY_PROFILE_ID" ] || {
-    printf 'linear-memory profile tool identity mismatch: expected %s, got %s\n' \
-      "$FRESH_LINEAR_MEMORY_PROFILE_ID" "$actual_id" >&2
-    return 2
-  }
-}
-
-fresh_require_patched_postmaster_compiler() {
-  local compiler_bin="${1:-$FRESH_POSTMASTER_COMPILER_BIN}"
-  local executor_receipt="${2:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
-  local wasmer_receipt="${3:-${WASMER_BUILD_RECEIPT:-$FRESH_WASMER_BUILD_RECEIPT}}"
-  local executor_bin="${4:-$FRESH_POSTMASTER_EXECUTOR_BIN}"
-  local version profile_id
-
-  [ -f "$compiler_bin" ] && [ ! -L "$compiler_bin" ] && [ -x "$compiler_bin" ] || {
-    printf 'missing executable postmaster product compiler: %s\n' "$compiler_bin" >&2
-    return 2
-  }
-  fresh_require_patched_postmaster_executor \
-    "$executor_bin" "$executor_receipt" "$wasmer_receipt" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" postmaster_compiler_binary \
-    "$FRESH_POSTMASTER_COMPILER_BINARY" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" postmaster_compiler_features \
-    "$FRESH_POSTMASTER_COMPILER_FEATURES" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" compiler_cpu_policy generic-baseline || return
-  fresh_require_manifest_value \
-    "$executor_receipt" compiler_cpu_features none || return
-  fresh_require_manifest_value \
-    "$executor_receipt" postmaster_compiler_binary_sha256 \
-    "$(fresh_wasmer_bin_hash "$compiler_bin")" || return
-  version="$("$compiler_bin" --version)" || {
-    printf 'could not read postmaster product compiler identity: %s\n' \
-      "$compiler_bin" >&2
-    return 2
-  }
-  profile_id="${version##* }"
-  [ "${version%% *}" = "$FRESH_POSTMASTER_COMPILER_BINARY" ] && \
-    [ "$profile_id" = "$FRESH_LINEAR_MEMORY_PROFILE_ID" ] || {
-    printf 'postmaster product compiler profile identity differs: %s\n' \
-      "${version:-}" >&2
-    return 2
-  }
-}
-
-fresh_require_start_proof_tool() {
-  local proof_bin="${1:-$FRESH_START_PROOF_BIN}"
-  local executor_receipt="${2:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
-  local actual_policy
-
-  [ -f "$proof_bin" ] && [ ! -L "$proof_bin" ] && [ -x "$proof_bin" ] || {
-    printf 'missing executable deterministic-start proof tool: %s\n' "$proof_bin" >&2
-    return 2
-  }
-  fresh_validate_postmaster_executor_build_receipt_shape "$executor_receipt" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" start_proof_binary "$FRESH_START_PROOF_BINARY" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" start_proof_features "$FRESH_START_PROOF_FEATURES" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" start_proof_policy "$FRESH_START_PROOF_POLICY" || return
-  fresh_require_manifest_value \
-    "$executor_receipt" start_proof_binary_sha256 \
-    "$(fresh_wasmer_bin_hash "$proof_bin")" || return
-  actual_policy="$("$proof_bin" --policy-id)" || return
-  [ "$actual_policy" = "$FRESH_START_PROOF_POLICY" ] || {
-    printf 'deterministic-start proof policy mismatch: expected %s, got %s\n' \
-      "$FRESH_START_PROOF_POLICY" "${actual_policy:-}" >&2
-    return 2
-  }
-}
-
-fresh_wasmer_bin() {
-  local candidate
-
-  if [ -n "${WASMER_BIN:-}" ]; then
-    if command -v "$WASMER_BIN" >/dev/null 2>&1; then
-      candidate="$(command -v "$WASMER_BIN")"
-    elif [ -x "$WASMER_BIN" ]; then
-      candidate="$WASMER_BIN"
-    else
-      echo "WASMER_BIN is set but not executable: $WASMER_BIN" >&2
-      return 127
-    fi
-  else
-    candidate="$FRESH_UPSTREAM_WASMER_BIN"
-  fi
-
-  fresh_require_patched_wasmer "$candidate" || return
-  printf '%s\n' "$candidate"
-}
-
-fresh_wasmer_bin_hash() {
-  local wasmer_bin="$1"
-  if command -v sha256sum >/dev/null 2>&1; then
-    sha256sum "$wasmer_bin" | awk '{print $1}'
-  else
-    shasum -a 256 "$wasmer_bin" | awk '{print $1}'
-  fi
-}
-
-fresh_wasmer_metadata_dir() {
-  printf '%s/tools/wasmer-home\n' "$FRESH_WORK_ROOT"
-}
-
-fresh_wasmer_metadata_cache_dir() {
-  printf '%s/tools/wasmer-cache/metadata\n' "$FRESH_WORK_ROOT"
-}
-
-fresh_wasmer_version() {
-  local wasmer_bin="$1"
-  local metadata_dir
-  local metadata_cache_dir
-
-  metadata_dir="$(fresh_wasmer_metadata_dir)"
-  metadata_cache_dir="$(fresh_wasmer_metadata_cache_dir)"
-  mkdir -p "$metadata_dir" "$metadata_cache_dir"
-  env \
-    WASMER_DIR="$metadata_dir" \
-    WASMER_CACHE_DIR="$metadata_cache_dir" \
-    "$wasmer_bin" --version
-}
-
-fresh_wasmer_cache_dir() {
-  local wasmer_bin="$1"
-  if [ -n "${FRESH_PINNED_WASMER_CACHE_DIR:-}" ]; then
-    printf '%s\n' "$FRESH_PINNED_WASMER_CACHE_DIR"
-    return
-  fi
-  printf '%s/tools/wasmer-cache/%s\n' "$FRESH_WORK_ROOT" "$(fresh_wasmer_bin_hash "$wasmer_bin")"
-}
-
-fresh_wasmer_llvm_opt_suffix() {
-  [ "${1:-aggressive}" = aggressive ] || {
-    echo "the postmaster product compiler is fixed to aggressive LLVM optimization" >&2
-    return 2
-  }
-  echo opta
-}
-
-fresh_normalize_wasmer_compiler() {
-  [ "${1:-llvm}" = llvm ] || {
-    echo "the postmaster product compiler is fixed to llvm" >&2
-    return 2
-  }
-  echo llvm
-}
-
-fresh_wasmer_compiler() {
-  printf '%s\n' llvm
-}
-
-fresh_wasmer_compiler_cli_flag() {
-  fresh_normalize_wasmer_compiler "$1" >/dev/null || return
-  printf '%s\n' --llvm
-}
-
-fresh_wasmer_cli_has_option() {
-  local wasmer_bin="$1"
-  local subcommand="$2"
-  local option="$3"
-
-  local metadata_dir
-  local metadata_cache_dir
-
-  metadata_dir="$(fresh_wasmer_metadata_dir)"
-  metadata_cache_dir="$(fresh_wasmer_metadata_cache_dir)"
-  mkdir -p "$metadata_dir" "$metadata_cache_dir"
-
-  env \
-    WASMER_DIR="$metadata_dir" \
-    WASMER_CACHE_DIR="$metadata_cache_dir" \
-    "$wasmer_bin" "$subcommand" --help 2>/dev/null |
-    grep -Eq "(^|[[:space:]])${option//-/\\-}([[:space:],]|$)"
-}
-
-fresh_require_wasmer_compiler_cli() {
-  local wasmer_bin="$1"
-  local compiler="$2"
-  shift 2
-
-  local flag
-  flag="$(fresh_wasmer_compiler_cli_flag "$compiler")"
-
-  local subcommand
-  for subcommand in "$@"; do
-    if ! fresh_wasmer_cli_has_option "$wasmer_bin" "$subcommand" "$flag"; then
-      {
-        printf 'the postmaster LLVM compiler requires `%s %s`, but `%s %s --help` does not expose that option.\n' \
-          "$(basename "$wasmer_bin")" "$flag" "$wasmer_bin" "$subcommand"
-        printf 'Build or select the receipt-bound postmaster compiler.\n'
-      } >&2
-      return 2
-    fi
-  done
-}
-
-fresh_wasmer_compiler_args_for() {
-  local wasmer_bin="$1"
-  local subcommand="$2"
-  shift 2
-  local compiler="$1"
-  local llvm_opt_level="$2"
-  local compiler_threads="$3"
-  [ "$llvm_opt_level" = aggressive ] || {
-    echo "the postmaster product compiler is fixed to aggressive LLVM optimization" >&2
-    return 2
-  }
-
-  case "$(fresh_normalize_wasmer_compiler "$compiler")" in
-    llvm)
-      printf '%s\n' --llvm
-      if [ -n "$wasmer_bin" ] &&
-        [ -n "$subcommand" ] &&
-        fresh_wasmer_cli_has_option "$wasmer_bin" "$subcommand" "--llvm-opt-level"; then
-        printf '%s\n' --llvm-opt-level "$llvm_opt_level"
-      fi
-      ;;
-  esac
-  if [ -n "$compiler_threads" ]; then
-    printf '%s\n' --compiler-threads "$compiler_threads"
-  fi
-}
-
-fresh_wasmer_compiler_cache_bucket() {
-  local compiler="$1"
-  local llvm_opt_level="$2"
-  local artifact_version="$3"
-  [ "$llvm_opt_level" = aggressive ] || {
-    echo "the postmaster product compiler is fixed to aggressive LLVM optimization" >&2
-    return 2
-  }
-
-  case "$(fresh_normalize_wasmer_compiler "$compiler")" in
-    llvm)
-      printf 'llvm-%s-v%s\n' "$(fresh_wasmer_llvm_opt_suffix "$llvm_opt_level")" "$artifact_version"
-      ;;
-  esac
-}
-
-fresh_wasmer_module_hash() {
-  local wasm_path="$1"
-  shasum -a 256 "$wasm_path" | awk '{print toupper($1)}'
-}
-
-fresh_git_worktree_state_sha256() {
-  local excluded_path="${2:-}"
-  local file_sha256
-  local identity_mode
-  local path
-  local root="$1"
-  local source
-  local source_head
-  local symlink_target
-
-  source_head="$(git -C "$root" rev-parse --verify 'HEAD^{commit}')" || {
-    printf 'not a Git worktree: %s\n' "$root" >&2
-    return 2
-  }
-  {
-    printf '%s\0%s\0%s\0' \
-      schema oliphaunt.git-worktree-state.v1 "$source_head"
-    git -C "$root" diff --binary --full-index --no-ext-diff HEAD -- || return
-    git -C "$root" ls-files --others --exclude-standard -z |
-      LC_ALL=C sort -z |
-      while IFS= read -r -d '' path; do
-        [ -n "$excluded_path" ] && [ "$path" = "$excluded_path" ] && continue
-        source="$root/$path"
-        if [ -L "$source" ]; then
-          symlink_target="$(readlink "$source")" || return
-          printf 'untracked-symlink\0%s\0%s\0' "$path" "$symlink_target"
-        elif [ -f "$source" ]; then
-          file_sha256="$(fresh_wasmer_bin_hash "$source")" || return
-          fresh_is_sha256 "$file_sha256" || {
-            printf 'failed to hash untracked worktree input: %s\n' "$source" >&2
-            return 2
-          }
-          if [ -x "$source" ]; then
-            identity_mode=executable
-          else
-            identity_mode=data
-          fi
-          printf 'untracked-file\0%s\0%s\0%s\0' \
-            "$path" "$file_sha256" "$identity_mode"
-        else
-          printf 'unsupported untracked worktree entry: %s\n' "$source" >&2
-          return 2
-        fi
-      done || return
-  } | fresh_sha256_stream
-}
-
-fresh_overlay_digest() {
-  local overlay_dir="$FRESH_ROOT/postgres/overlays/wasix-core"
-  local optimization_patches_dir="$REPO_ROOT/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches"
-  local optimization_series="$FRESH_ROOT/postgres/main-optimizations.series"
-  local patch_name
-  local patches_dir="$FRESH_ROOT/postgres/patches"
-  local path
-
-  [ -f "$patches_dir/series" ] && [ ! -L "$patches_dir/series" ] || {
-    printf 'missing regular PostgreSQL patch series: %s\n' "$patches_dir/series" >&2
-    return 2
-  }
-  [ -f "$optimization_series" ] && [ ! -L "$optimization_series" ] || {
-    printf 'missing regular main-optimization series: %s\n' "$optimization_series" >&2
-    return 2
-  }
-  while IFS= read -r patch_name || [ -n "$patch_name" ]; do
-    case "$patch_name" in
-      ''|'#'*) continue ;;
-      */*)
-        printf 'unsafe main-optimization patch entry: %s\n' "$patch_name" >&2
-        return 2
-        ;;
-    esac
-    path="$optimization_patches_dir/$patch_name"
-    [ -f "$path" ] && [ ! -L "$path" ] || {
-      printf 'missing regular main-optimization patch: %s\n' "$path" >&2
-      return 2
-    }
-  done <"$optimization_series"
-
-  {
-    printf '%s\0%s\0' schema oliphaunt.wasix-postmaster.overlay.v2
-    if [ -d "$overlay_dir" ]; then
-      while IFS= read -r -d '' path; do
-        printf 'overlay\0%s\0%s\0' \
-          "${path#"$overlay_dir"/}" "$(fresh_wasmer_bin_hash "$path")"
-      done < <(find "$overlay_dir" -type f -print0 | LC_ALL=C sort -z)
-    fi
-    printf 'series\0local\0%s\0' "$(fresh_wasmer_bin_hash "$patches_dir/series")"
-    if [ -d "$patches_dir" ]; then
-      while IFS= read -r -d '' path; do
-        printf 'patch\0local/%s\0%s\0' \
-          "${path#"$patches_dir"/}" "$(fresh_wasmer_bin_hash "$path")"
-      done < <(find "$patches_dir" -type f -name '*.patch' -print0 | LC_ALL=C sort -z)
-    fi
-    printf 'series\0main-optimizations\0%s\0' \
-      "$(fresh_wasmer_bin_hash "$optimization_series")"
-    while IFS= read -r patch_name || [ -n "$patch_name" ]; do
-      case "$patch_name" in
-        ''|'#'*) continue ;;
-      esac
-      path="$optimization_patches_dir/$patch_name"
-      printf 'patch\0main-optimizations/%s\0%s\0' \
-        "$patch_name" "$(fresh_wasmer_bin_hash "$path")"
-    done <"$optimization_series"
-  } | fresh_sha256_stream
-}
-
-fresh_write_report_header() {
-  local report="$1"
-  local title="$2"
-  mkdir -p "$(dirname "$report")"
-  {
-    printf '# %s\n\n' "$title"
-    printf -- '- Generated: `%s`\n' "$(fresh_timestamp)"
-    printf -- '- Repository: `%s`\n' "$REPO_ROOT"
-    printf -- '- Project source root: `%s`\n' "$FRESH_ROOT"
-    printf -- '- Generated work root: `%s`\n' "$FRESH_WORK_ROOT"
-    printf -- '- PostgreSQL tag: `%s`\n\n' "$POSTGRES_TAG"
-  } >"$report"
-}
-
-fresh_ensure_docker_image() {
-  local docker_bin
-  local actual_recipe
-  local expected_recipe
-  local image="${1:-$FRESH_WASIX_DOCKER_IMAGE}"
-  local label=dev.oliphaunt.wasix-builder.recipe-sha256
-  local context="$WASIX_TOOLCHAIN_ROOT/docker"
-  docker_bin="$(fresh_docker_bin)"
-  expected_recipe="$(fresh_wasix_builder_recipe_sha256)" || return
-  actual_recipe="$("$docker_bin" image inspect \
-    --format "{{ index .Config.Labels \"$label\" }}" "$image" 2>/dev/null || true)"
-  if [ "$actual_recipe" = "$expected_recipe" ]; then
-    return
-  fi
-  "$docker_bin" build \
-    --label "$label=$expected_recipe" \
-    -f "$context/Dockerfile" \
-    -t "$image" \
-    "$context" || return
-  actual_recipe="$("$docker_bin" image inspect \
-    --format "{{ index .Config.Labels \"$label\" }}" "$image" 2>/dev/null || true)"
-  [ "$actual_recipe" = "$expected_recipe" ] || {
-    printf 'WASIX builder image recipe label mismatch after build: %s\n' "$image" >&2
-    return 2
-  }
-}
-
-fresh_wasix_builder_image_id() {
-  local actual_recipe
-  local docker_bin
-  local expected_recipe
-  local image="${1:-$FRESH_WASIX_DOCKER_IMAGE}"
-  local image_id
-  local label=dev.oliphaunt.wasix-builder.recipe-sha256
-  local record
-
-  docker_bin="$(fresh_docker_bin)" || return
-  expected_recipe="$(fresh_wasix_builder_recipe_sha256)" || return
-  record="$("$docker_bin" image inspect \
-    --format "{{.Id}}|{{ index .Config.Labels \"$label\" }}" \
-    "$image" 2>/dev/null)" || {
-    printf 'WASIX builder image is unavailable: %s\n' "$image" >&2
-    return 2
-  }
-  case "$record" in
-    *'|'*)
-      image_id="${record%%|*}"
-      actual_recipe="${record#*|}"
-      ;;
-    *)
-      printf 'WASIX builder image inspection returned an invalid record: %s\n' "$image" >&2
-      return 2
-      ;;
-  esac
-  [ "$actual_recipe" = "$expected_recipe" ] || {
-    printf 'WASIX builder image recipe label mismatch: %s\n' "$image" >&2
-    return 2
-  }
-  case "$image_id" in
-    sha256:*)
-      fresh_is_sha256 "${image_id#sha256:}" || {
-        printf 'WASIX builder image has an invalid immutable identity: %s\n' "$image" >&2
-        return 2
-      }
-      ;;
-    *)
-      printf 'WASIX builder image has an invalid immutable identity: %s\n' "$image" >&2
-      return 2
-      ;;
-  esac
-  printf '%s\n' "$image_id"
-}
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/durable_publication.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/durable_publication.py
deleted file mode 100644
index 2cf536f4f..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/durable_publication.py
+++ /dev/null
@@ -1,738 +0,0 @@
-#!/usr/bin/env python3
-
-"""Publish bounded evidence files with an admission-last durability contract.
-
-The source and destination of ``publish`` must be regular files in the same
-non-symlink directory.  The source is synchronized before an atomic hard-link
-creates the destination without replacement.  The directory is synchronized
-while both names exist, then the private source name is removed and the
-directory is synchronized again.  A crash can therefore leave either no
-admission name, the admitted destination, or the destination plus a harmless
-private source name; it cannot replace an existing admission record.
-"""
-
-from __future__ import annotations
-
-import hashlib
-import io
-import os
-import re
-import stat
-import sys
-from pathlib import Path
-from typing import BinaryIO, NamedTuple, Sequence
-
-
-MAX_COMPARISON_BYTES = 16 * 1024 * 1024
-MAX_PUBLICATION_BYTES = 256 * 1024 * 1024
-FileIdentity = tuple[int, int]
-OPEN_REGULAR_FLAGS = (
-    os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
-)
-OPEN_DIRECTORY_FLAGS = (
-    os.O_RDONLY
-    | getattr(os, "O_CLOEXEC", 0)
-    | getattr(os, "O_DIRECTORY", 0)
-    | getattr(os, "O_NOFOLLOW", 0)
-)
-
-
-class PublicationError(Exception):
-    pass
-
-
-class PublicationSource(NamedTuple):
-    """Exact sealed private generation intended for public admission."""
-
-    device: int
-    inode: int
-    size: int
-    sha256: str
-
-    @property
-    def file_identity(self) -> FileIdentity:
-        return self.device, self.inode
-
-    def token(self) -> str:
-        return f"{self.device}\t{self.inode}\t{self.size}\t{self.sha256}"
-
-
-def parse_source_token(values: Sequence[str]) -> PublicationSource:
-    require(len(values) == 4, "identified publication requires four source fields")
-    device_text, inode_text, size_text, digest = values
-    for label, value in (
-        ("device", device_text),
-        ("inode", inode_text),
-        ("size", size_text),
-    ):
-        require(
-            value.isascii()
-            and value.isdecimal()
-            and (len(value) == 1 or not value.startswith("0")),
-            f"identified publication {label} is not canonical unsigned decimal",
-        )
-    device = int(device_text)
-    inode = int(inode_text)
-    size = int(size_text)
-    require(device > 0, "identified publication device must be positive")
-    require(inode > 0, "identified publication inode must be positive")
-    require(
-        0 <= size <= MAX_PUBLICATION_BYTES,
-        "identified publication size is outside the supported range",
-    )
-    require(
-        re.fullmatch(r"[0-9a-f]{64}", digest) is not None,
-        "identified publication SHA-256 is malformed",
-    )
-    return PublicationSource(device, inode, size, digest)
-
-
-def require(condition: bool, message: str) -> None:
-    if not condition:
-        raise PublicationError(message)
-
-
-def identity(metadata: os.stat_result) -> tuple[int, ...]:
-    return (
-        metadata.st_dev,
-        metadata.st_ino,
-        metadata.st_mode,
-        metadata.st_size,
-        metadata.st_mtime_ns,
-        metadata.st_ctime_ns,
-    )
-
-
-class AnchoredDirectory:
-    def __init__(self, path: Path) -> None:
-        self.path = Path(os.path.abspath(path))
-        before = os.lstat(self.path)
-        require(
-            stat.S_ISDIR(before.st_mode) and not stat.S_ISLNK(before.st_mode),
-            f"publication parent is not a non-symlink directory: {self.path}",
-        )
-        self.fd = os.open(self.path, OPEN_DIRECTORY_FLAGS)
-        try:
-            opened = os.fstat(self.fd)
-            require(
-                stat.S_ISDIR(opened.st_mode)
-                and (before.st_dev, before.st_ino) == (opened.st_dev, opened.st_ino),
-                f"publication parent changed while opening: {self.path}",
-            )
-        except BaseException:
-            os.close(self.fd)
-            raise
-
-    def close(self) -> None:
-        os.close(self.fd)
-
-    def __enter__(self) -> "AnchoredDirectory":
-        return self
-
-    def __exit__(self, *_: object) -> None:
-        self.close()
-
-    def fsync(self) -> None:
-        os.fsync(self.fd)
-
-    def lstat(self, name: str) -> os.stat_result | None:
-        try:
-            return os.stat(name, dir_fd=self.fd, follow_symlinks=False)
-        except FileNotFoundError:
-            return None
-
-    def open_regular(self, name: str) -> tuple[int, os.stat_result]:
-        before = self.lstat(name)
-        require(before is not None, f"publication source is missing: {self.path / name}")
-        require(
-            stat.S_ISREG(before.st_mode),
-            f"publication source is not regular: {self.path / name}",
-        )
-        descriptor = os.open(name, OPEN_REGULAR_FLAGS, dir_fd=self.fd)
-        opened = os.fstat(descriptor)
-        current = self.lstat(name)
-        if not (
-            stat.S_ISREG(opened.st_mode)
-            and identity(before) == identity(opened)
-            and current is not None
-            and identity(current) == identity(opened)
-        ):
-            os.close(descriptor)
-            raise PublicationError(
-                f"publication source changed while opening: {self.path / name}"
-            )
-        return descriptor, opened
-
-
-def split_same_parent(source: Path, destination: Path) -> tuple[Path, str, str]:
-    source = Path(os.path.abspath(source))
-    destination = Path(os.path.abspath(destination))
-    require(source != destination, "publication source and destination must differ")
-    require(
-        source.parent == destination.parent,
-        "publication source and destination must share one directory",
-    )
-    require(source.name not in {"", ".", ".."}, "invalid publication source name")
-    require(
-        destination.name not in {"", ".", ".."},
-        "invalid publication destination name",
-    )
-    return source.parent, source.name, destination.name
-
-
-def descriptor_sha256(descriptor: int, expected_size: int) -> str:
-    require(
-        expected_size <= MAX_PUBLICATION_BYTES,
-        f"publication source exceeds {MAX_PUBLICATION_BYTES} bytes",
-    )
-    os.lseek(descriptor, 0, os.SEEK_SET)
-    digest = hashlib.sha256()
-    remaining = expected_size
-    while remaining:
-        chunk = os.read(descriptor, min(remaining, 1024 * 1024))
-        require(chunk != b"", "publication source was truncated while hashing")
-        digest.update(chunk)
-        remaining -= len(chunk)
-    require(os.read(descriptor, 1) == b"", "publication source grew while hashing")
-    os.lseek(descriptor, 0, os.SEEK_SET)
-    return digest.hexdigest()
-
-
-def publish_identified(
-    source: Path,
-    destination: Path,
-    expected: PublicationSource,
-) -> None:
-    """Admit only the exact private generation described by ``expected``."""
-
-    parent, source_name, destination_name = split_same_parent(source, destination)
-    with AnchoredDirectory(parent) as directory:
-        require(
-            directory.lstat(destination_name) is None,
-            f"publication destination already exists: {destination}",
-        )
-        source_descriptor, source_metadata = directory.open_regular(source_name)
-        require(
-            stat.S_IMODE(source_metadata.st_mode) == 0o444,
-            f"publication source is not sealed read-only: {source}",
-        )
-        require(
-            (source_metadata.st_dev, source_metadata.st_ino)
-            == expected.file_identity
-            and source_metadata.st_size == expected.size,
-            f"publication source generation differs from intended source: {source}",
-        )
-        linked = False
-        linked_destination_identity: tuple[int, int] | None = None
-        committed = False
-        try:
-            source_digest = descriptor_sha256(
-                source_descriptor, source_metadata.st_size
-            )
-            require(
-                source_digest == expected.sha256,
-                f"publication source contents differ from intended source: {source}",
-            )
-            os.fsync(source_descriptor)
-            os.link(
-                source_name,
-                destination_name,
-                src_dir_fd=directory.fd,
-                dst_dir_fd=directory.fd,
-                follow_symlinks=False,
-            )
-            linked = True
-            linked_destination_metadata = directory.lstat(destination_name)
-            require(
-                linked_destination_metadata is not None,
-                f"published destination disappeared: {destination}",
-            )
-            linked_destination_identity = (
-                linked_destination_metadata.st_dev,
-                linked_destination_metadata.st_ino,
-            )
-            destination_descriptor, destination_metadata = directory.open_regular(
-                destination_name
-            )
-            try:
-                require(
-                    (source_metadata.st_dev, source_metadata.st_ino)
-                    == (destination_metadata.st_dev, destination_metadata.st_ino),
-                    f"published destination identity differs: {destination}",
-                )
-                current_source = os.fstat(source_descriptor)
-                require(
-                    (
-                        current_source.st_dev,
-                        current_source.st_ino,
-                        current_source.st_mode,
-                        current_source.st_size,
-                        current_source.st_mtime_ns,
-                    )
-                    == (
-                        source_metadata.st_dev,
-                        source_metadata.st_ino,
-                        source_metadata.st_mode,
-                        source_metadata.st_size,
-                        source_metadata.st_mtime_ns,
-                    ),
-                    f"publication source changed before commit: {source}",
-                )
-                require(
-                    descriptor_sha256(source_descriptor, current_source.st_size)
-                    == source_digest,
-                    f"publication source contents changed before commit: {source}",
-                )
-                os.fsync(destination_descriptor)
-            finally:
-                os.close(destination_descriptor)
-
-            # This is the commit point.  Once the directory synchronization
-            # completes, the public admission name durably identifies the
-            # exact fsynced inode even if cleanup is interrupted.
-            directory.fsync()
-            committed = True
-        except FileExistsError as error:
-            raise PublicationError(
-                f"publication destination appeared concurrently: {destination}"
-            ) from error
-        finally:
-            os.close(source_descriptor)
-            if linked and not committed:
-                current_destination = directory.lstat(destination_name)
-                if (
-                    current_destination is not None
-                    and linked_destination_identity is not None
-                    and (
-                        current_destination.st_dev,
-                        current_destination.st_ino,
-                    )
-                    == linked_destination_identity
-                ):
-                    os.unlink(destination_name, dir_fd=directory.fd)
-                    directory.fsync()
-
-        current_source = directory.lstat(source_name)
-        require(
-            current_source is not None
-            and stat.S_ISREG(current_source.st_mode)
-            and (current_source.st_dev, current_source.st_ino)
-            == (source_metadata.st_dev, source_metadata.st_ino),
-            f"private source changed after publication commit: {source}",
-        )
-        os.unlink(source_name, dir_fd=directory.fd)
-        directory.fsync()
-
-
-def publication_source(path: Path) -> PublicationSource:
-    """Capture the exact current sealed source generation for admission."""
-
-    metadata, digest = stable_regular_digest(path)
-    require(
-        stat.S_IMODE(metadata.st_mode) == 0o444,
-        f"publication source is not sealed read-only: {path}",
-    )
-    return PublicationSource(
-        device=metadata.st_dev,
-        inode=metadata.st_ino,
-        size=metadata.st_size,
-        sha256=digest,
-    )
-
-
-def publish(source: Path, destination: Path) -> None:
-    """Capture and admit the source generation current at function entry."""
-
-    publish_identified(source, destination, publication_source(source))
-
-
-def _require_existing_destination(
-    destination: Path,
-    expected: PublicationSource,
-) -> None:
-    destination = Path(os.path.abspath(destination))
-    with AnchoredDirectory(destination.parent) as directory:
-        descriptor, metadata = directory.open_regular(destination.name)
-        try:
-            require(
-                stat.S_IMODE(metadata.st_mode) == 0o444,
-                f"publication set destination is not sealed read-only: {destination}",
-            )
-            require(
-                metadata.st_size == expected.size
-                and descriptor_sha256(descriptor, metadata.st_size)
-                == expected.sha256,
-                f"publication set destination differs: {destination}",
-            )
-            os.fsync(descriptor)
-            directory.fsync()
-        finally:
-            os.close(descriptor)
-
-
-def publish_set(
-    paths: Sequence[Path],
-    expected_sources: Sequence[PublicationSource] | None = None,
-) -> None:
-    """Idempotently admit a same-directory set without replacing any member.
-
-    Each destination is independently admission-last and readers must require
-    the complete set.  If a process stops between members, replay with the same
-    sealed sources verifies already-admitted members and completes the set;
-    different content fails closed.
-    """
-
-    require(
-        len(paths) >= 4 and len(paths) % 2 == 0,
-        "publication set requires at least two SOURCE DESTINATION pairs",
-    )
-    pairs = [
-        (Path(paths[index]), Path(paths[index + 1]))
-        for index in range(0, len(paths), 2)
-    ]
-    parents: set[Path] = set()
-    source_paths: set[Path] = set()
-    destination_paths: set[Path] = set()
-    for source, destination in pairs:
-        parent, _, _ = split_same_parent(source, destination)
-        absolute_source = Path(os.path.abspath(source))
-        absolute_destination = Path(os.path.abspath(destination))
-        parents.add(parent)
-        require(
-            absolute_source not in source_paths,
-            f"duplicate publication source: {source}",
-        )
-        require(
-            absolute_destination not in destination_paths,
-            f"duplicate publication destination: {destination}",
-        )
-        source_paths.add(absolute_source)
-        destination_paths.add(absolute_destination)
-    require(len(parents) == 1, "publication set must share one directory")
-    require(
-        source_paths.isdisjoint(destination_paths),
-        "publication set source and destination names must be disjoint",
-    )
-
-    if expected_sources is None:
-        sources = [publication_source(source) for source, _ in pairs]
-    else:
-        require(
-            len(expected_sources) == len(pairs),
-            "identified publication set source count differs",
-        )
-        sources = list(expected_sources)
-        for (source, _), expected in zip(pairs, sources, strict=True):
-            require(
-                publication_source(source) == expected,
-                f"publication set source generation differs: {source}",
-            )
-
-    # Reject every conflicting existing member before admitting any missing
-    # one. A bad later destination must not create a new partial set.
-    for (_, destination), expected in zip(pairs, sources, strict=True):
-        try:
-            os.lstat(destination)
-        except FileNotFoundError:
-            continue
-        _require_existing_destination(destination, expected)
-
-    for (source, destination), expected in zip(pairs, sources, strict=True):
-        try:
-            publish_identified(source, destination, expected)
-        except (OSError, PublicationError):
-            # A prior replay or a concurrent identical publisher may already
-            # own this admission name. Accept it only byte-for-byte, then
-            # remove our private replay source before advancing the set.
-            _require_existing_destination(destination, expected)
-            absolute_source = Path(os.path.abspath(source))
-            try:
-                os.lstat(absolute_source)
-            except FileNotFoundError:
-                pass
-            else:
-                remove_private(
-                    absolute_source,
-                    expected,
-                )
-
-
-def _write_stream(path: Path, source: BinaryIO) -> PublicationSource:
-    """Create one private, fsynced, read-only file without following links."""
-
-    path = Path(os.path.abspath(path))
-    with AnchoredDirectory(path.parent) as directory:
-        require(
-            directory.lstat(path.name) is None,
-            f"private publication path already exists: {path}",
-        )
-        flags = (
-            os.O_WRONLY
-            | os.O_CREAT
-            | os.O_EXCL
-            | getattr(os, "O_CLOEXEC", 0)
-            | getattr(os, "O_NOFOLLOW", 0)
-        )
-        descriptor = os.open(path.name, flags, 0o600, dir_fd=directory.fd)
-        opened = os.fstat(descriptor)
-        try:
-            total = 0
-            digest = hashlib.sha256()
-            while True:
-                chunk = source.read(1024 * 1024)
-                if not chunk:
-                    break
-                total += len(chunk)
-                require(
-                    total <= MAX_PUBLICATION_BYTES,
-                    f"private publication input exceeds {MAX_PUBLICATION_BYTES} bytes",
-                )
-                digest.update(chunk)
-                view = memoryview(chunk)
-                while view:
-                    written = os.write(descriptor, view)
-                    require(written > 0, f"short write to private publication: {path}")
-                    view = view[written:]
-            os.fchmod(descriptor, 0o444)
-            os.fsync(descriptor)
-            final = os.fstat(descriptor)
-            require(
-                stat.S_ISREG(final.st_mode)
-                and (opened.st_dev, opened.st_ino) == (final.st_dev, final.st_ino)
-                and final.st_size == total,
-                f"private publication changed while writing: {path}",
-            )
-            current = directory.lstat(path.name)
-            require(
-                current is not None
-                and stat.S_ISREG(current.st_mode)
-                and (current.st_dev, current.st_ino) == (final.st_dev, final.st_ino),
-                f"private publication path changed while writing: {path}",
-            )
-        except BaseException:
-            try:
-                current = directory.lstat(path.name)
-                if current is not None and (
-                    current.st_dev,
-                    current.st_ino,
-                ) == (opened.st_dev, opened.st_ino):
-                    os.unlink(path.name, dir_fd=directory.fd)
-                    directory.fsync()
-            finally:
-                os.close(descriptor)
-            raise
-        os.close(descriptor)
-        return PublicationSource(
-            device=final.st_dev,
-            inode=final.st_ino,
-            size=final.st_size,
-            sha256=digest.hexdigest(),
-        )
-
-
-def write_bytes(path: Path, payload: bytes) -> PublicationSource:
-    """Create one private durable publication from bounded in-memory bytes."""
-
-    require(
-        len(payload) <= MAX_PUBLICATION_BYTES,
-        f"private publication input exceeds {MAX_PUBLICATION_BYTES} bytes",
-    )
-    return _write_stream(path, io.BytesIO(payload))
-
-
-def write_stdin(path: Path) -> PublicationSource:
-    """Create one private durable publication from standard input."""
-
-    return _write_stream(path, sys.stdin.buffer)
-
-
-def stable_regular_bytes(path: Path) -> bytes:
-    path = Path(os.path.abspath(path))
-    before = os.lstat(path)
-    require(stat.S_ISREG(before.st_mode), f"comparison input is not regular: {path}")
-    require(
-        before.st_size <= MAX_COMPARISON_BYTES,
-        f"comparison input exceeds {MAX_COMPARISON_BYTES} bytes: {path}",
-    )
-    descriptor = os.open(path, OPEN_REGULAR_FLAGS)
-    try:
-        opened = os.fstat(descriptor)
-        current_after_open = os.lstat(path)
-        require(
-            stat.S_ISREG(opened.st_mode)
-            and identity(before) == identity(opened)
-            and identity(current_after_open) == identity(opened),
-            f"comparison input changed while opening: {path}",
-        )
-        require(
-            opened.st_size <= MAX_COMPARISON_BYTES,
-            f"comparison input exceeds {MAX_COMPARISON_BYTES} bytes: {path}",
-        )
-        chunks: list[bytes] = []
-        remaining = opened.st_size
-        while remaining:
-            chunk = os.read(descriptor, min(remaining, 1024 * 1024))
-            require(chunk != b"", f"comparison input was truncated: {path}")
-            chunks.append(chunk)
-            remaining -= len(chunk)
-        require(os.read(descriptor, 1) == b"", f"comparison input grew: {path}")
-        after = os.fstat(descriptor)
-        require(identity(opened) == identity(after), f"comparison input changed: {path}")
-    finally:
-        os.close(descriptor)
-    current = os.lstat(path)
-    require(
-        stat.S_ISREG(current.st_mode)
-        and identity(current) == identity(after),
-        f"comparison input was replaced: {path}",
-    )
-    return b"".join(chunks)
-
-
-def stable_regular_digest(path: Path) -> tuple[os.stat_result, str]:
-    """Hash one stable regular file without retaining its contents in memory."""
-
-    path = Path(os.path.abspath(path))
-    before = os.lstat(path)
-    require(stat.S_ISREG(before.st_mode), f"digest input is not regular: {path}")
-    require(
-        before.st_size <= MAX_PUBLICATION_BYTES,
-        f"digest input exceeds {MAX_PUBLICATION_BYTES} bytes: {path}",
-    )
-    descriptor = os.open(path, OPEN_REGULAR_FLAGS)
-    try:
-        opened = os.fstat(descriptor)
-        current_after_open = os.lstat(path)
-        require(
-            stat.S_ISREG(opened.st_mode)
-            and identity(before) == identity(opened)
-            and identity(current_after_open) == identity(opened),
-            f"digest input changed while opening: {path}",
-        )
-        digest = descriptor_sha256(descriptor, opened.st_size)
-        after = os.fstat(descriptor)
-        require(identity(opened) == identity(after), f"digest input changed: {path}")
-    finally:
-        os.close(descriptor)
-    current = os.lstat(path)
-    require(
-        stat.S_ISREG(current.st_mode) and identity(current) == identity(after),
-        f"digest input was replaced: {path}",
-    )
-    return after, digest
-
-
-def require_equal(left: Path, right: Path) -> None:
-    require(
-        stable_regular_bytes(left) == stable_regular_bytes(right),
-        f"regular files differ: {left} != {right}",
-    )
-
-
-def remove_private(
-    path: Path,
-    expected_identity: FileIdentity | PublicationSource,
-) -> None:
-    """Remove only the private generation identified by ``expected_identity``."""
-
-    path = Path(os.path.abspath(path))
-    with AnchoredDirectory(path.parent) as directory:
-        metadata = directory.lstat(path.name)
-        if metadata is None:
-            return
-        require(
-            stat.S_ISREG(metadata.st_mode),
-            f"private publication path is not regular: {path}",
-        )
-        wanted = (
-            expected_identity.file_identity
-            if isinstance(expected_identity, PublicationSource)
-            else expected_identity
-        )
-        require(
-            (metadata.st_dev, metadata.st_ino) == wanted,
-            f"private publication generation changed: {path}",
-        )
-        os.unlink(path.name, dir_fd=directory.fd)
-        directory.fsync()
-
-
-def discard_private(path: Path) -> None:
-    """Discard a private name in a caller-owned, exclusively held namespace."""
-
-    path = Path(os.path.abspath(path))
-    try:
-        metadata = os.lstat(path)
-    except FileNotFoundError:
-        return
-    remove_private(path, (metadata.st_dev, metadata.st_ino))
-
-
-def fsync_directory(path: Path) -> None:
-    with AnchoredDirectory(path) as directory:
-        directory.fsync()
-
-
-def main(arguments: list[str]) -> int:
-    try:
-        if len(arguments) == 3 and arguments[0] == "publish":
-            publish(Path(arguments[1]), Path(arguments[2]))
-        elif len(arguments) == 7 and arguments[0] == "publish-identified":
-            publish_identified(
-                Path(arguments[1]),
-                Path(arguments[2]),
-                parse_source_token(arguments[3:]),
-            )
-        elif (
-            len(arguments) >= 5
-            and len(arguments) % 2 == 1
-            and arguments[0] == "publish-set"
-        ):
-            publish_set(tuple(Path(argument) for argument in arguments[1:]))
-        elif (
-            len(arguments) >= 13
-            and (len(arguments) - 1) % 6 == 0
-            and arguments[0] == "publish-set-identified"
-        ):
-            paths: list[Path] = []
-            sources: list[PublicationSource] = []
-            for index in range(1, len(arguments), 6):
-                paths.extend((Path(arguments[index]), Path(arguments[index + 1])))
-                sources.append(parse_source_token(arguments[index + 2 : index + 6]))
-            publish_set(paths, sources)
-        elif len(arguments) == 2 and arguments[0] == "write-stdin":
-            write_stdin(Path(arguments[1]))
-        elif len(arguments) == 2 and arguments[0] == "write-stdin-identified":
-            print(write_stdin(Path(arguments[1])).token())
-        elif len(arguments) == 2 and arguments[0] == "identify-source":
-            print(publication_source(Path(arguments[1])).token())
-        elif len(arguments) == 3 and arguments[0] == "require-equal":
-            require_equal(Path(arguments[1]), Path(arguments[2]))
-        elif len(arguments) == 2 and arguments[0] == "discard-private":
-            discard_private(Path(arguments[1]))
-        elif len(arguments) == 6 and arguments[0] == "remove-private-identified":
-            remove_private(
-                Path(arguments[1]), parse_source_token(arguments[2:])
-            )
-        elif len(arguments) == 2 and arguments[0] == "fsync-directory":
-            fsync_directory(Path(arguments[1]))
-        else:
-            raise PublicationError(
-                "usage: durable_publication.py "
-                "{publish SOURCE DESTINATION|"
-                "publish-identified SOURCE DESTINATION DEVICE INODE SIZE SHA256|"
-                "publish-set SOURCE DESTINATION SOURCE DESTINATION [...]|"
-                "publish-set-identified SOURCE DESTINATION DEVICE INODE SIZE SHA256 [...]|"
-                "require-equal LEFT RIGHT|"
-                "write-stdin PATH|write-stdin-identified PATH|identify-source PATH|"
-                "discard-private PATH|remove-private-identified PATH DEVICE INODE SIZE SHA256|"
-                "fsync-directory DIRECTORY}"
-            )
-        return 0
-    except (OSError, PublicationError) as error:
-        print(f"durable publication failed: {error}", file=sys.stderr)
-        return 2
-
-
-if __name__ == "__main__":
-    raise SystemExit(main(sys.argv[1:]))
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/durable_publication.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/durable_publication.test.py
deleted file mode 100644
index a489a10f8..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/durable_publication.test.py
+++ /dev/null
@@ -1,433 +0,0 @@
-#!/usr/bin/env python3
-
-from __future__ import annotations
-
-import importlib.util
-import os
-import stat
-import subprocess
-import sys
-import tempfile
-import time
-import unittest
-from pathlib import Path
-from unittest import mock
-
-
-MODULE_PATH = Path(__file__).with_name("durable_publication.py")
-SPEC = importlib.util.spec_from_file_location("durable_publication", MODULE_PATH)
-assert SPEC is not None and SPEC.loader is not None
-PUBLICATION = importlib.util.module_from_spec(SPEC)
-SPEC.loader.exec_module(PUBLICATION)
-
-
-class DurablePublicationTests(unittest.TestCase):
-    def setUp(self) -> None:
-        self.temporary = tempfile.TemporaryDirectory()
-        self.root = Path(self.temporary.name)
-
-    def tearDown(self) -> None:
-        self.temporary.cleanup()
-
-    def write(self, name: str, payload: bytes = b"receipt\n") -> Path:
-        path = self.root / name
-        path.write_bytes(payload)
-        return path
-
-    def test_publish_is_no_replace_and_removes_private_name(self) -> None:
-        pending = self.write(".receipt.pending")
-        os.chmod(pending, 0o444)
-        destination = self.root / "receipt"
-        PUBLICATION.publish(pending, destination)
-        self.assertFalse(pending.exists())
-        self.assertEqual(destination.read_bytes(), b"receipt\n")
-        self.assertEqual(stat.S_IMODE(destination.stat().st_mode), 0o444)
-        self.assertEqual(destination.stat().st_nlink, 1)
-
-    def test_existing_destination_is_never_replaced(self) -> None:
-        pending = self.write(".receipt.pending", b"new\n")
-        destination = self.write("receipt", b"old\n")
-        with self.assertRaises(PUBLICATION.PublicationError):
-            PUBLICATION.publish(pending, destination)
-        self.assertEqual(pending.read_bytes(), b"new\n")
-        self.assertEqual(destination.read_bytes(), b"old\n")
-
-    def test_symlink_source_is_rejected(self) -> None:
-        real = self.write("real")
-        pending = self.root / ".receipt.pending"
-        pending.symlink_to(real.name)
-        with self.assertRaises(PUBLICATION.PublicationError):
-            PUBLICATION.publish(pending, self.root / "receipt")
-
-    def test_require_equal_rejects_mismatch_and_symlink(self) -> None:
-        left = self.write("left", b"same\n")
-        right = self.write("right", b"same\n")
-        PUBLICATION.require_equal(left, right)
-        right.write_bytes(b"different\n")
-        with self.assertRaises(PUBLICATION.PublicationError):
-            PUBLICATION.require_equal(left, right)
-        right.unlink()
-        right.symlink_to(left.name)
-        with self.assertRaises(PUBLICATION.PublicationError):
-            PUBLICATION.require_equal(left, right)
-
-    def test_stable_read_and_digest_reject_mutation_during_open(self) -> None:
-        for operation in (
-            PUBLICATION.stable_regular_bytes,
-            PUBLICATION.stable_regular_digest,
-        ):
-            with self.subTest(operation=operation.__name__):
-                path = self.write(f"{operation.__name__}.input", b"trusted!")
-                real_open = PUBLICATION.os.open
-                injected = False
-
-                def mutate_then_open(target, *args, **kwargs):
-                    nonlocal injected
-                    if not injected and Path(os.path.abspath(target)) == path:
-                        injected = True
-                        time.sleep(0.002)
-                        with path.open("r+b") as handle:
-                            handle.write(b"attack!!")
-                    return real_open(target, *args, **kwargs)
-
-                with mock.patch.object(
-                    PUBLICATION.os, "open", side_effect=mutate_then_open
-                ):
-                    with self.assertRaisesRegex(
-                        PUBLICATION.PublicationError,
-                        "changed while opening",
-                    ):
-                        operation(path)
-
-    def test_anchored_open_rejects_mutation_during_open(self) -> None:
-        path = self.write("anchored.input", b"trusted!")
-        real_open = PUBLICATION.os.open
-        injected = False
-
-        def mutate_then_open(target, *args, **kwargs):
-            nonlocal injected
-            if not injected and target == path.name and kwargs.get("dir_fd") is not None:
-                injected = True
-                time.sleep(0.002)
-                with path.open("r+b") as handle:
-                    handle.write(b"attack!!")
-            return real_open(target, *args, **kwargs)
-
-        with PUBLICATION.AnchoredDirectory(self.root) as directory:
-            with mock.patch.object(PUBLICATION.os, "open", side_effect=mutate_then_open):
-                with self.assertRaisesRegex(
-                    PUBLICATION.PublicationError,
-                    "changed while opening",
-                ):
-                    directory.open_regular(path.name)
-    def test_discard_private_is_idempotent_and_rejects_symlink(self) -> None:
-        pending = self.write(".receipt.pending")
-        PUBLICATION.discard_private(pending)
-        PUBLICATION.discard_private(pending)
-        pending.symlink_to(self.write("real").name)
-        with self.assertRaises(PUBLICATION.PublicationError):
-            PUBLICATION.discard_private(pending)
-
-    def test_write_stdin_creates_fsynced_publication_source(self) -> None:
-        pending = self.root / ".receipt.pending"
-        result = subprocess.run(
-            [sys.executable, str(MODULE_PATH), "write-stdin", str(pending)],
-            input=b"captured receipt\n",
-            check=False,
-        )
-        self.assertEqual(result.returncode, 0)
-        self.assertEqual(pending.read_bytes(), b"captured receipt\n")
-        self.assertEqual(stat.S_IMODE(pending.stat().st_mode), 0o444)
-        second = subprocess.run(
-            [sys.executable, str(MODULE_PATH), "write-stdin", str(pending)],
-            input=b"replacement\n",
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            check=False,
-        )
-        self.assertEqual(second.returncode, 2)
-        self.assertEqual(pending.read_bytes(), b"captured receipt\n")
-
-    def test_cli_identified_handoff_rejects_replaced_source(self) -> None:
-        pending = self.root / ".receipt.pending"
-        destination = self.root / "receipt"
-        written = subprocess.run(
-            [
-                sys.executable,
-                str(MODULE_PATH),
-                "write-stdin-identified",
-                str(pending),
-            ],
-            input=b"intended\n",
-            stdout=subprocess.PIPE,
-            check=True,
-        )
-        fields = written.stdout.decode("ascii").strip().split("\t")
-        self.assertEqual(len(fields), 4)
-
-        replacement = self.root / ".replacement"
-        replacement.write_bytes(b"attacker\n")
-        os.chmod(replacement, 0o444)
-        os.replace(replacement, pending)
-        rejected = subprocess.run(
-            [
-                sys.executable,
-                str(MODULE_PATH),
-                "publish-identified",
-                str(pending),
-                str(destination),
-                *fields,
-            ],
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            check=False,
-        )
-        self.assertEqual(rejected.returncode, 2)
-        self.assertFalse(destination.exists())
-        self.assertEqual(pending.read_bytes(), b"attacker\n")
-
-    def test_cli_identified_handoff_publishes_exact_source(self) -> None:
-        pending = self.root / ".receipt.pending"
-        destination = self.root / "receipt"
-        written = subprocess.run(
-            [
-                sys.executable,
-                str(MODULE_PATH),
-                "write-stdin-identified",
-                str(pending),
-            ],
-            input=b"intended\n",
-            stdout=subprocess.PIPE,
-            check=True,
-        )
-        fields = written.stdout.decode("ascii").strip().split("\t")
-        published = subprocess.run(
-            [
-                sys.executable,
-                str(MODULE_PATH),
-                "publish-identified",
-                str(pending),
-                str(destination),
-                *fields,
-            ],
-            check=False,
-        )
-        self.assertEqual(published.returncode, 0)
-        self.assertEqual(destination.read_bytes(), b"intended\n")
-        self.assertFalse(pending.exists())
-
-    def test_parent_symlink_is_rejected(self) -> None:
-        actual = self.root / "actual"
-        actual.mkdir()
-        alias = self.root / "alias"
-        alias.symlink_to(actual.name)
-        pending = actual / ".receipt.pending"
-        pending.write_bytes(b"receipt\n")
-        with self.assertRaises(PUBLICATION.PublicationError):
-            PUBLICATION.publish(pending, alias / "receipt")
-
-    def test_publish_set_recovers_an_identical_partial_admission(self) -> None:
-        first_source = self.write(".first.pending", b"first\n")
-        second_source = self.write(".second.pending", b"second\n")
-        first_destination = self.root / "first"
-        second_destination = self.root / "second"
-        os.chmod(first_source, 0o444)
-        os.chmod(second_source, 0o444)
-        PUBLICATION.publish(first_source, first_destination)
-
-        first_replay = self.write(".first.replay", b"first\n")
-        os.chmod(first_replay, 0o444)
-        PUBLICATION.publish_set(
-            (first_replay, first_destination, second_source, second_destination)
-        )
-        self.assertFalse(first_replay.exists())
-        self.assertFalse(second_source.exists())
-        self.assertEqual(first_destination.read_bytes(), b"first\n")
-        self.assertEqual(second_destination.read_bytes(), b"second\n")
-
-    def test_publish_set_rejects_a_different_partial_admission(self) -> None:
-        first_destination = self.write("first", b"other\n")
-        os.chmod(first_destination, 0o444)
-        first_source = self.write(".first.pending", b"first\n")
-        second_source = self.write(".second.pending", b"second\n")
-        os.chmod(first_source, 0o444)
-        os.chmod(second_source, 0o444)
-        with self.assertRaises(PUBLICATION.PublicationError):
-            PUBLICATION.publish_set(
-                (
-                    first_source,
-                    first_destination,
-                    second_source,
-                    self.root / "second",
-                )
-            )
-        self.assertEqual(first_destination.read_bytes(), b"other\n")
-        self.assertFalse((self.root / "second").exists())
-
-    def test_publish_set_rejects_an_unsealed_partial_admission(self) -> None:
-        first_destination = self.write("first", b"first\n")
-        first_source = self.write(".first.pending", b"first\n")
-        second_source = self.write(".second.pending", b"second\n")
-        os.chmod(first_source, 0o444)
-        os.chmod(second_source, 0o444)
-        with self.assertRaises(PUBLICATION.PublicationError):
-            PUBLICATION.publish_set(
-                (
-                    first_source,
-                    first_destination,
-                    second_source,
-                    self.root / "second",
-                )
-            )
-        self.assertFalse((self.root / "second").exists())
-
-    def test_publish_set_preserves_a_replaced_private_generation(self) -> None:
-        first_source = self.write(".first.pending", b"first\n")
-        second_source = self.write(".second.pending", b"second\n")
-        first_destination = self.root / "first"
-        os.chmod(first_source, 0o444)
-        os.chmod(second_source, 0o444)
-        replacement_identity: tuple[int, int] | None = None
-
-        def concurrent_identical_publish(
-            source: Path,
-            destination: Path,
-            expected: object,
-        ) -> None:
-            nonlocal replacement_identity
-            replacement = source.with_name(f"{source.name}.replacement")
-            replacement.write_bytes(b"first\n")
-            os.chmod(replacement, 0o444)
-            os.replace(replacement, source)
-            replacement_identity = (source.stat().st_dev, source.stat().st_ino)
-            destination.write_bytes(b"first\n")
-            os.chmod(destination, 0o444)
-            raise PUBLICATION.PublicationError("concurrent identical publisher")
-
-        with mock.patch.object(
-            PUBLICATION, "publish_identified", concurrent_identical_publish
-        ):
-            with self.assertRaisesRegex(
-                PUBLICATION.PublicationError,
-                "private publication generation changed",
-            ):
-                PUBLICATION.publish_set(
-                    (
-                        first_source,
-                        first_destination,
-                        second_source,
-                        self.root / "second",
-                    )
-                )
-
-        self.assertEqual(
-            replacement_identity,
-            (first_source.stat().st_dev, first_source.stat().st_ino),
-        )
-        self.assertEqual(first_source.read_bytes(), b"first\n")
-        self.assertFalse((self.root / "second").exists())
-
-    def test_identified_publish_rejects_replaced_private_generation(self) -> None:
-        source = self.root / ".receipt.pending"
-        intended = PUBLICATION.write_bytes(source, b"intended\n")
-        replacement = self.root / ".replacement"
-        replacement.write_bytes(b"attacker\n")
-        os.chmod(replacement, 0o444)
-        os.replace(replacement, source)
-        destination = self.root / "receipt"
-
-        with self.assertRaisesRegex(
-            PUBLICATION.PublicationError,
-            "generation differs from intended source",
-        ):
-            PUBLICATION.publish_identified(source, destination, intended)
-
-        self.assertFalse(destination.exists())
-        self.assertEqual(source.read_bytes(), b"attacker\n")
-
-    def test_publish_set_rejects_source_swap_without_admitting_swapped_bytes(self) -> None:
-        first_source = self.root / ".first.pending"
-        second_source = self.root / ".second.pending"
-        PUBLICATION.write_bytes(first_source, b"first\n")
-        PUBLICATION.write_bytes(second_source, b"second\n")
-        first_destination = self.root / "first"
-        second_destination = self.root / "second"
-        real_publish = PUBLICATION.publish_identified
-        injected = False
-
-        def replace_before_publish(source, destination, expected):
-            nonlocal injected
-            if not injected:
-                injected = True
-                replacement = source.with_name(f"{source.name}.replacement")
-                replacement.write_bytes(b"ATTACKER\n")
-                os.chmod(replacement, 0o444)
-                os.replace(replacement, source)
-            return real_publish(source, destination, expected)
-
-        with mock.patch.object(
-            PUBLICATION, "publish_identified", replace_before_publish
-        ):
-            with self.assertRaises(PUBLICATION.PublicationError):
-                PUBLICATION.publish_set(
-                    (
-                        first_source,
-                        first_destination,
-                        second_source,
-                        second_destination,
-                    )
-                )
-
-        self.assertFalse(first_destination.exists())
-        self.assertFalse(second_destination.exists())
-        self.assertEqual(first_source.read_bytes(), b"ATTACKER\n")
-
-    def test_publish_set_preflights_later_conflict_before_any_admission(self) -> None:
-        first_source = self.root / ".first.pending"
-        second_source = self.root / ".second.pending"
-        PUBLICATION.write_bytes(first_source, b"first\n")
-        PUBLICATION.write_bytes(second_source, b"second\n")
-        first_destination = self.root / "first"
-        second_destination = self.write("second", b"conflict\n")
-        os.chmod(second_destination, 0o444)
-
-        with self.assertRaisesRegex(
-            PUBLICATION.PublicationError,
-            "publication set destination differs",
-        ):
-            PUBLICATION.publish_set(
-                (
-                    first_source,
-                    first_destination,
-                    second_source,
-                    second_destination,
-                )
-            )
-
-        self.assertFalse(first_destination.exists())
-        self.assertEqual(second_destination.read_bytes(), b"conflict\n")
-
-    def test_publish_set_streams_members_larger_than_the_comparison_limit(self) -> None:
-        large_payload = b"x" * (PUBLICATION.MAX_COMPARISON_BYTES + 1)
-        large_source = self.root / ".large.pending"
-        small_source = self.root / ".small.pending"
-        PUBLICATION.write_bytes(large_source, large_payload)
-        PUBLICATION.write_bytes(small_source, b"small\n")
-        large_destination = self.root / "large"
-        small_destination = self.root / "small"
-
-        PUBLICATION.publish_set(
-            (
-                large_source,
-                large_destination,
-                small_source,
-                small_destination,
-            )
-        )
-
-        self.assertEqual(large_destination.stat().st_size, len(large_payload))
-        self.assertEqual(small_destination.read_bytes(), b"small\n")
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/durable_publication_crash.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/durable_publication_crash.test.py
deleted file mode 100644
index e8ee30ebe..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/durable_publication_crash.test.py
+++ /dev/null
@@ -1,235 +0,0 @@
-#!/usr/bin/env python3
-
-"""Fault-model tests for receipt admission and recovery.
-
-These tests deliberately stop a forked publisher immediately after each
-namespace/durability operation.  The child uses ``os._exit`` so Python
-``finally`` blocks do not turn the simulated crash into an orderly rollback.
-"""
-
-from __future__ import annotations
-
-import importlib.util
-import io
-import os
-import stat
-import tempfile
-import unittest
-from pathlib import Path
-from unittest import mock
-
-
-MODULE_PATH = Path(__file__).with_name("durable_publication.py")
-SPEC = importlib.util.spec_from_file_location("durable_publication", MODULE_PATH)
-assert SPEC is not None and SPEC.loader is not None
-PUBLICATION = importlib.util.module_from_spec(SPEC)
-SPEC.loader.exec_module(PUBLICATION)
-
-PAYLOAD = b"schema=receipt.v1\nidentity=exact\n"
-
-
-class _BinaryStdin:
-    def __init__(self, payload: bytes) -> None:
-        self.buffer = io.BytesIO(payload)
-
-
-class DurablePublicationCrashTests(unittest.TestCase):
-    def setUp(self) -> None:
-        self.temporary = tempfile.TemporaryDirectory()
-        self.root = Path(self.temporary.name)
-        self.pending = self.root / ".receipt.pending"
-        self.destination = self.root / "receipt"
-        self.expected = self.root / "expected"
-        self.expected.write_bytes(PAYLOAD)
-        os.chmod(self.expected, 0o444)
-
-    def tearDown(self) -> None:
-        self.temporary.cleanup()
-
-    def create_pending(self) -> None:
-        self.assertFalse(self.pending.exists())
-        with mock.patch.object(PUBLICATION.sys, "stdin", _BinaryStdin(PAYLOAD)):
-            PUBLICATION.write_stdin(self.pending)
-
-    def assert_exact_admission(self) -> None:
-        self.assertTrue(self.destination.is_file())
-        self.assertFalse(self.destination.is_symlink())
-        self.assertEqual(self.destination.read_bytes(), PAYLOAD)
-        self.assertEqual(stat.S_IMODE(self.destination.stat().st_mode), 0o444)
-
-    def recover(self) -> None:
-        # This is the caller protocol in build-wasix-core.sh: discard a stale
-        # private name first, replay an admitted generation, or regenerate and
-        # publish when no admission name survived.
-        if self.pending.exists() or self.pending.is_symlink():
-            PUBLICATION.discard_private(self.pending)
-        if self.destination.exists() or self.destination.is_symlink():
-            PUBLICATION.require_equal(self.expected, self.destination)
-        else:
-            self.create_pending()
-            PUBLICATION.publish(self.pending, self.destination)
-
-    def crash_publish(self, point: str) -> None:
-        self.create_pending()
-        pid = os.fork()
-        if pid == 0:
-            real_fsync = PUBLICATION.os.fsync
-            real_link = PUBLICATION.os.link
-            real_unlink = PUBLICATION.os.unlink
-            fsync_calls = 0
-            unlink_calls = 0
-
-            def crash_after_fsync(descriptor: int) -> None:
-                nonlocal fsync_calls
-                real_fsync(descriptor)
-                fsync_calls += 1
-                fsync_points = {
-                    1: "source-fsync",
-                    2: "destination-fsync",
-                    3: "commit-directory-fsync",
-                    4: "cleanup-directory-fsync",
-                }
-                if fsync_points.get(fsync_calls) == point:
-                    os._exit(91)
-
-            def crash_after_link(*args: object, **kwargs: object) -> None:
-                real_link(*args, **kwargs)
-                if point == "link":
-                    os._exit(92)
-
-            def crash_after_unlink(*args: object, **kwargs: object) -> None:
-                nonlocal unlink_calls
-                real_unlink(*args, **kwargs)
-                unlink_calls += 1
-                if point == "source-unlink" and unlink_calls == 1:
-                    os._exit(93)
-
-            try:
-                with (
-                    mock.patch.object(PUBLICATION.os, "fsync", crash_after_fsync),
-                    mock.patch.object(PUBLICATION.os, "link", crash_after_link),
-                    mock.patch.object(PUBLICATION.os, "unlink", crash_after_unlink),
-                ):
-                    PUBLICATION.publish(self.pending, self.destination)
-            except BaseException:
-                os._exit(94)
-            os._exit(95)
-
-        waited, wait_status = os.waitpid(pid, 0)
-        self.assertEqual(waited, pid)
-        self.assertTrue(os.WIFEXITED(wait_status))
-        self.assertIn(os.WEXITSTATUS(wait_status), {91, 92, 93})
-
-    @unittest.skipUnless(hasattr(os, "fork"), "requires POSIX fork semantics")
-    def test_each_publish_crash_boundary_recovers_exactly_and_idempotently(self) -> None:
-        points = (
-            "source-fsync",
-            "link",
-            "destination-fsync",
-            "commit-directory-fsync",
-            "source-unlink",
-            "cleanup-directory-fsync",
-        )
-        for point in points:
-            with self.subTest(point=point):
-                if self.pending.exists() or self.pending.is_symlink():
-                    self.pending.unlink()
-                if self.destination.exists() or self.destination.is_symlink():
-                    self.destination.unlink()
-
-                self.crash_publish(point)
-                if self.destination.exists():
-                    self.assert_exact_admission()
-
-                self.recover()
-                self.assert_exact_admission()
-                self.assertFalse(self.pending.exists())
-
-                # A second replay must preserve the admitted inode and bytes.
-                admitted_identity = (
-                    self.destination.stat().st_dev,
-                    self.destination.stat().st_ino,
-                )
-                self.recover()
-                self.assertEqual(
-                    admitted_identity,
-                    (self.destination.stat().st_dev, self.destination.stat().st_ino),
-                )
-                self.assert_exact_admission()
-
-    def test_post_link_identity_failure_rolls_back_created_destination(self) -> None:
-        self.create_pending()
-        real_link = PUBLICATION.os.link
-        real_unlink = PUBLICATION.os.unlink
-
-        def replace_source_then_link(*args: object, **kwargs: object) -> None:
-            real_unlink(self.pending)
-            self.pending.write_bytes(b"wrong generation\n")
-            os.chmod(self.pending, 0o444)
-            real_link(*args, **kwargs)
-
-        with mock.patch.object(PUBLICATION.os, "link", replace_source_then_link):
-            with self.assertRaises(PUBLICATION.PublicationError):
-                PUBLICATION.publish(self.pending, self.destination)
-
-        self.assertFalse(
-            self.destination.exists(),
-            "a helper-created destination survived pre-commit identity failure",
-        )
-
-    def test_post_link_fsync_failure_rolls_back_exact_destination(self) -> None:
-        self.create_pending()
-        real_fsync = PUBLICATION.os.fsync
-        calls = 0
-
-        def fail_destination_fsync(descriptor: int) -> None:
-            nonlocal calls
-            calls += 1
-            if calls == 2:
-                raise OSError("injected destination fsync failure")
-            real_fsync(descriptor)
-
-        with mock.patch.object(PUBLICATION.os, "fsync", fail_destination_fsync):
-            with self.assertRaises(OSError):
-                PUBLICATION.publish(self.pending, self.destination)
-
-        self.assertFalse(self.destination.exists())
-        self.assertEqual(self.pending.read_bytes(), PAYLOAD)
-        self.recover()
-        self.assert_exact_admission()
-
-    def test_rollback_does_not_remove_concurrent_destination(self) -> None:
-        self.create_pending()
-        real_fsync = PUBLICATION.os.fsync
-        real_unlink = PUBLICATION.os.unlink
-        calls = 0
-        competitor = b"concurrent owner\n"
-
-        def replace_destination_then_fail(descriptor: int) -> None:
-            nonlocal calls
-            calls += 1
-            if calls == 2:
-                real_unlink(self.destination)
-                self.destination.write_bytes(competitor)
-                raise OSError("injected destination replacement")
-            real_fsync(descriptor)
-
-        with mock.patch.object(PUBLICATION.os, "fsync", replace_destination_then_fail):
-            with self.assertRaises(OSError):
-                PUBLICATION.publish(self.pending, self.destination)
-
-        self.assertEqual(self.destination.read_bytes(), competitor)
-
-    def test_write_stdin_rejects_symlink_without_touching_target(self) -> None:
-        target = self.root / "unrelated"
-        target.write_bytes(b"do not touch\n")
-        self.pending.symlink_to(target.name)
-        with mock.patch.object(PUBLICATION.sys, "stdin", _BinaryStdin(PAYLOAD)):
-            with self.assertRaises(PUBLICATION.PublicationError):
-                PUBLICATION.write_stdin(self.pending)
-        self.assertTrue(self.pending.is_symlink())
-        self.assertEqual(target.read_bytes(), b"do not touch\n")
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/guest_build_provenance.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/guest_build_provenance.py
deleted file mode 100644
index 22883d1fd..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/guest_build_provenance.py
+++ /dev/null
@@ -1,369 +0,0 @@
-#!/usr/bin/env python3
-
-"""Compute the exact installed guest closure identity used by a carrier."""
-
-from __future__ import annotations
-
-import hashlib
-import os
-import re
-import stat
-import sys
-from pathlib import Path
-from typing import TypeAlias
-
-
-SCHEMA = "oliphaunt.wasix-postmaster.guest-installed-closure.v1"
-SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
-
-
-def load_side_module_policy() -> tuple[tuple[str, tuple[str, ...]], ...]:
-    def policy_require(condition: bool, message: str) -> None:
-        if not condition:
-            raise RuntimeError(message)
-
-    policy = (
-        Path(__file__).resolve().parent.parent
-        / "runtime"
-        / "policies"
-        / "sealed-side-modules.v1.tsv"
-    )
-    rows: list[tuple[str, tuple[str, ...]]] = []
-    occupied: set[str] = set()
-    for line_number, line in enumerate(
-        policy.read_text(encoding="utf-8").splitlines(), start=1
-    ):
-        if not line or line.startswith("#"):
-            continue
-        fields = line.split("\t")
-        policy_require(len(fields) == 3, f"invalid side-module policy row {line_number}")
-        relative, raw_aliases, abi_policy = fields
-        policy_require(
-            relative.startswith("lib/") and relative.endswith((".so", ".so.5.18")),
-            f"invalid side-module policy path: {relative}",
-        )
-        policy_require(bool(abi_policy), f"empty side-module ABI policy: {relative}")
-        aliases = () if raw_aliases == "-" else tuple(raw_aliases.split(","))
-        for candidate in (relative, *aliases):
-            policy_require(
-                candidate.startswith("lib/") and candidate not in occupied,
-                f"duplicate or invalid side-module path: {candidate}",
-            )
-            occupied.add(candidate)
-        rows.append((relative, aliases))
-    policy_require(bool(rows), "sealed side-module policy is empty")
-    return tuple(rows)
-
-
-SIDE_MODULE_POLICY = load_side_module_policy()
-REQUIRED_MODULES = (
-    "bin/initdb",
-    "bin/postgres",
-    *(relative for relative, _aliases in SIDE_MODULE_POLICY),
-)
-REGULAR_OPEN_FLAGS = (
-    os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
-)
-DIRECTORY_OPEN_FLAGS = (
-    REGULAR_OPEN_FLAGS | getattr(os, "O_DIRECTORY", 0)
-)
-FileIdentity: TypeAlias = tuple[int, int, int, int, int, int]
-FileRecord: TypeAlias = tuple[str, int, str, FileIdentity]
-
-
-class ProvenanceError(Exception):
-    pass
-
-
-def require(condition: bool, message: str) -> None:
-    if not condition:
-        raise ProvenanceError(message)
-
-
-def file_identity(metadata: os.stat_result) -> FileIdentity:
-    return (
-        metadata.st_dev,
-        metadata.st_ino,
-        metadata.st_mode,
-        metadata.st_size,
-        metadata.st_mtime_ns,
-        metadata.st_ctime_ns,
-    )
-
-
-def read_regular(path: Path, *, synchronize: bool = False) -> tuple[int, str, FileIdentity]:
-    before = os.lstat(path)
-    require(stat.S_ISREG(before.st_mode), f"guest closure entry is not regular: {path}")
-    descriptor = os.open(path, REGULAR_OPEN_FLAGS)
-    try:
-        opened = os.fstat(descriptor)
-        require(
-            stat.S_ISREG(opened.st_mode)
-            and (before.st_dev, before.st_ino) == (opened.st_dev, opened.st_ino),
-            f"guest closure entry changed while opening: {path}",
-        )
-        digest = hashlib.sha256()
-        size = 0
-        while True:
-            chunk = os.read(descriptor, 1024 * 1024)
-            if not chunk:
-                break
-            digest.update(chunk)
-            size += len(chunk)
-        if synchronize:
-            os.fsync(descriptor)
-        after = os.fstat(descriptor)
-        require(
-            file_identity(opened) == file_identity(after)
-            and size == opened.st_size,
-            f"guest closure entry changed while hashing: {path}",
-        )
-        current = os.lstat(path)
-        require(
-            stat.S_ISREG(current.st_mode)
-            and file_identity(current) == file_identity(after),
-            f"guest closure entry was replaced while hashing: {path}",
-        )
-        return size, digest.hexdigest(), file_identity(after)
-    finally:
-        os.close(descriptor)
-
-
-def closure_files(root: Path) -> list[str]:
-    info = os.lstat(root)
-    require(
-        stat.S_ISDIR(info.st_mode) and not stat.S_ISLNK(info.st_mode),
-        f"guest install root is not a non-symlink directory: {root}",
-    )
-    files = list(REQUIRED_MODULES)
-    for relative in REQUIRED_MODULES:
-        require(
-            relative.encode("utf-8").decode("utf-8") == relative,
-            f"guest module path is not canonical UTF-8: {relative!r}",
-        )
-        module_info = os.lstat(root / relative)
-        require(
-            stat.S_ISREG(module_info.st_mode),
-            f"required guest module is not regular: {root / relative}",
-        )
-
-    share_root = root / "share/postgresql"
-    share_info = os.lstat(share_root)
-    require(
-        stat.S_ISDIR(share_info.st_mode) and not stat.S_ISLNK(share_info.st_mode),
-        f"PostgreSQL share root is not a non-symlink directory: {share_root}",
-    )
-    share_files = 0
-    for current, directories, names in os.walk(share_root, followlinks=False):
-        directories.sort()
-        names.sort()
-        for name in directories:
-            path = Path(current, name)
-            entry = os.lstat(path)
-            require(
-                stat.S_ISDIR(entry.st_mode) and not stat.S_ISLNK(entry.st_mode),
-                f"PostgreSQL share closure contains a non-directory: {path}",
-            )
-        for name in names:
-            path = Path(current, name)
-            entry = os.lstat(path)
-            require(
-                stat.S_ISREG(entry.st_mode),
-                f"PostgreSQL share closure contains a non-regular file: {path}",
-            )
-            files.append(path.relative_to(root).as_posix())
-            share_files += 1
-    require(share_files > 0, "PostgreSQL share closure is empty")
-    require(len(files) == len(set(files)), "guest closure contains duplicate paths")
-    return sorted(files)
-
-
-def frame(digest: "hashlib._Hash", value: str) -> None:
-    encoded = value.encode("utf-8")
-    digest.update(len(encoded).to_bytes(8, "big"))
-    digest.update(encoded)
-
-
-def installed_closure_identity_from_records(
-    records: list[tuple[str, int, str]],
-) -> str:
-    require(records, "guest installed closure records are empty")
-    paths = [relative for relative, _, _ in records]
-    require(paths == sorted(paths), "guest installed closure records are not sorted")
-    require(len(paths) == len(set(paths)), "guest installed closure records are duplicated")
-    require(
-        all(type(size) is int and size >= 0 for _, size, _ in records),
-        "guest installed closure record has an invalid size",
-    )
-    require(
-        all(SHA256_RE.fullmatch(file_digest) is not None for _, _, file_digest in records),
-        "guest installed closure record has an invalid SHA-256",
-    )
-    digest = hashlib.sha256()
-    frame(digest, SCHEMA)
-    for relative, size, file_digest in records:
-        for value in (relative, str(size), file_digest):
-            frame(digest, value)
-    return digest.hexdigest()
-
-
-def installed_closure_identity(root: Path) -> str:
-    root = Path(os.path.realpath(root))
-    records: list[tuple[str, int, str]] = []
-    for relative in closure_files(root):
-        size, file_digest, _ = read_regular(root / relative)
-        records.append((relative, size, file_digest))
-    return installed_closure_identity_from_records(records)
-
-
-def directory_closure(files: list[str]) -> list[str]:
-    directories = {"."}
-    for relative in files:
-        parent = Path(relative).parent
-        while parent != Path("."):
-            directories.add(parent.as_posix())
-            parent = parent.parent
-    return sorted(directories, key=lambda value: (-len(Path(value).parts), value))
-
-
-def synchronize_directories(root: Path, directories: list[str]) -> dict[str, FileIdentity]:
-    synchronized: dict[str, FileIdentity] = {}
-    for relative in directories:
-        path = root if relative == "." else root / relative
-        before = os.lstat(path)
-        require(
-            stat.S_ISDIR(before.st_mode) and not stat.S_ISLNK(before.st_mode),
-            f"guest closure parent is not a non-symlink directory: {path}",
-        )
-        descriptor = os.open(path, DIRECTORY_OPEN_FLAGS)
-        try:
-            opened = os.fstat(descriptor)
-            require(
-                stat.S_ISDIR(opened.st_mode)
-                and (before.st_dev, before.st_ino) == (opened.st_dev, opened.st_ino),
-                f"guest closure parent changed while opening: {path}",
-            )
-            os.fsync(descriptor)
-            after = os.fstat(descriptor)
-            require(
-                file_identity(opened) == file_identity(after),
-                f"guest closure parent changed while synchronizing: {path}",
-            )
-            current = os.lstat(path)
-            require(
-                stat.S_ISDIR(current.st_mode)
-                and file_identity(current) == file_identity(after),
-                f"guest closure parent was replaced while synchronizing: {path}",
-            )
-            synchronized[relative] = file_identity(after)
-        finally:
-            os.close(descriptor)
-    return synchronized
-
-
-def synchronize_root_entry(root: Path, expected_root: FileIdentity) -> None:
-    """Make a freshly recreated install-root entry durable in its parent."""
-
-    parent = root.parent
-    before_parent = os.lstat(parent)
-    require(
-        stat.S_ISDIR(before_parent.st_mode) and not stat.S_ISLNK(before_parent.st_mode),
-        f"guest install parent is not a non-symlink directory: {parent}",
-    )
-    descriptor = os.open(parent, DIRECTORY_OPEN_FLAGS)
-    try:
-        opened_parent = os.fstat(descriptor)
-        require(
-            stat.S_ISDIR(opened_parent.st_mode)
-            and (before_parent.st_dev, before_parent.st_ino)
-            == (opened_parent.st_dev, opened_parent.st_ino),
-            f"guest install parent changed while opening: {parent}",
-        )
-        current_root = os.lstat(root)
-        require(
-            stat.S_ISDIR(current_root.st_mode)
-            and file_identity(current_root) == expected_root,
-            f"guest install root changed before parent synchronization: {root}",
-        )
-        os.fsync(descriptor)
-        after_parent = os.fstat(descriptor)
-        require(
-            file_identity(opened_parent) == file_identity(after_parent),
-            f"guest install parent changed while synchronizing: {parent}",
-        )
-        current_root = os.lstat(root)
-        require(
-            stat.S_ISDIR(current_root.st_mode)
-            and file_identity(current_root) == expected_root,
-            f"guest install root changed during parent synchronization: {root}",
-        )
-    finally:
-        os.close(descriptor)
-
-
-def seal_installed_closure(root: Path) -> str:
-    """Synchronize and replay the exact closure before its receipt is admitted."""
-
-    root = Path(os.path.realpath(root))
-    files = closure_files(root)
-    directories = directory_closure(files)
-    sealed_records: list[FileRecord] = []
-    for relative in files:
-        size, file_digest, entry_identity = read_regular(
-            root / relative, synchronize=True
-        )
-        sealed_records.append((relative, size, file_digest, entry_identity))
-
-    directory_identities = synchronize_directories(root, directories)
-    synchronize_root_entry(root, directory_identities["."])
-
-    # Replay both namespace and inode/content identity after the durability
-    # barriers.  This rejects a file replacement that happens to preserve the
-    # same bytes but whose new directory entry was never synchronized.
-    require(
-        closure_files(root) == files,
-        "guest installed closure inventory changed while synchronizing",
-    )
-    replayed_records: list[FileRecord] = []
-    for relative in files:
-        size, file_digest, entry_identity = read_regular(root / relative)
-        replayed_records.append((relative, size, file_digest, entry_identity))
-    require(
-        replayed_records == sealed_records,
-        "guest installed closure changed after synchronization",
-    )
-    for relative, expected_identity in directory_identities.items():
-        path = root if relative == "." else root / relative
-        current = os.lstat(path)
-        require(
-            stat.S_ISDIR(current.st_mode)
-            and file_identity(current) == expected_identity,
-            f"guest closure parent changed after synchronization: {path}",
-        )
-
-    identity_records = [
-        (relative, size, file_digest)
-        for relative, size, file_digest, _ in sealed_records
-    ]
-    return installed_closure_identity_from_records(identity_records)
-
-
-def main(arguments: list[str]) -> int:
-    try:
-        if len(arguments) != 2 or arguments[0] not in {"identity", "seal-identity"}:
-            raise ProvenanceError(
-                "usage: guest-build-provenance.py {identity|seal-identity} INSTALL_ROOT"
-            )
-        root = Path(arguments[1])
-        if arguments[0] == "seal-identity":
-            print(seal_installed_closure(root))
-        else:
-            print(installed_closure_identity(root))
-        return 0
-    except (OSError, ProvenanceError) as error:
-        print(f"guest build provenance failed: {error}", file=sys.stderr)
-        return 2
-
-
-if __name__ == "__main__":
-    raise SystemExit(main(sys.argv[1:]))
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/guest_build_provenance.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/guest_build_provenance.test.py
deleted file mode 100644
index 2cb17a9df..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/guest_build_provenance.test.py
+++ /dev/null
@@ -1,98 +0,0 @@
-#!/usr/bin/env python3
-
-from __future__ import annotations
-
-import importlib.util
-import contextlib
-import io
-import os
-import re
-import tempfile
-import unittest
-from pathlib import Path
-from unittest import mock
-
-
-MODULE_PATH = Path(__file__).with_name("guest_build_provenance.py")
-SPEC = importlib.util.spec_from_file_location("guest_build_provenance", MODULE_PATH)
-assert SPEC is not None and SPEC.loader is not None
-PROVENANCE = importlib.util.module_from_spec(SPEC)
-SPEC.loader.exec_module(PROVENANCE)
-
-
-class GuestBuildProvenanceTests(unittest.TestCase):
-    def setUp(self) -> None:
-        self.temporary = tempfile.TemporaryDirectory()
-        self.root = Path(self.temporary.name)
-        for relative in PROVENANCE.REQUIRED_MODULES:
-            path = self.root / relative
-            path.parent.mkdir(parents=True, exist_ok=True)
-            path.write_bytes(f"module:{relative}\n".encode())
-        share = self.root / "share/postgresql"
-        (share / "nested").mkdir(parents=True)
-        (share / "postgres.bki").write_bytes(b"bootstrap\n")
-        (share / "nested/data.txt").write_bytes(b"nested\n")
-
-    def tearDown(self) -> None:
-        self.temporary.cleanup()
-
-    def test_seal_identity_matches_read_only_identity_and_fsyncs_topology(self) -> None:
-        expected = PROVENANCE.installed_closure_identity(self.root)
-        with mock.patch.object(
-            PROVENANCE.os, "fsync", wraps=os.fsync
-        ) as synchronized:
-            actual = PROVENANCE.seal_installed_closure(self.root)
-        self.assertEqual(actual, expected)
-        files = PROVENANCE.closure_files(self.root)
-        directories = PROVENANCE.directory_closure(files)
-        self.assertGreaterEqual(synchronized.call_count, len(files) + len(directories))
-
-    def test_directory_closure_is_bottom_up_and_includes_root(self) -> None:
-        directories = PROVENANCE.directory_closure(
-            ["bin/postgres", "share/postgresql/nested/data.txt"]
-        )
-        self.assertEqual(directories[-1], ".")
-        depths = [len(Path(relative).parts) for relative in directories]
-        self.assertEqual(depths, sorted(depths, reverse=True))
-
-    def test_seal_rejects_symlinked_intermediate_directory(self) -> None:
-        postgresql = self.root / "lib/postgresql"
-        actual = self.root / "lib/postgresql.actual"
-        postgresql.rename(actual)
-        postgresql.symlink_to(actual.name)
-        with self.assertRaises(PROVENANCE.ProvenanceError):
-            PROVENANCE.seal_installed_closure(self.root)
-
-    def test_unsynchronized_replacement_after_directory_fsync_is_rejected(self) -> None:
-        original = PROVENANCE.synchronize_directories
-
-        def replace_after_sync(
-            root: Path, directories: list[str]
-        ) -> dict[str, PROVENANCE.FileIdentity]:
-            identities = original(root, directories)
-            postgres = root / "bin/postgres"
-            replacement = root / "bin/.postgres.replacement"
-            replacement.write_bytes(postgres.read_bytes())
-            os.replace(replacement, postgres)
-            return identities
-
-        with mock.patch.object(
-            PROVENANCE,
-            "synchronize_directories",
-            side_effect=replace_after_sync,
-        ):
-            with self.assertRaises(PROVENANCE.ProvenanceError):
-                PROVENANCE.seal_installed_closure(self.root)
-
-    def test_seal_cli_emits_canonical_sha256(self) -> None:
-        output = io.StringIO()
-        with contextlib.redirect_stdout(output):
-            self.assertEqual(
-                PROVENANCE.main(["seal-identity", str(self.root)]),
-                0,
-            )
-        self.assertIsNotNone(re.fullmatch(r"[0-9a-f]{64}\n", output.getvalue()))
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/immutable-carrier.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/immutable-carrier.py
deleted file mode 100644
index 6e28d4966..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/immutable-carrier.py
+++ /dev/null
@@ -1,1336 +0,0 @@
-#!/usr/bin/env python3
-
-"""Deploy and attest an immutable sealed-carrier closure on ext filesystems."""
-
-from __future__ import annotations
-
-import argparse
-import array
-import ctypes
-import fcntl
-import hashlib
-import json
-import os
-import re
-import stat
-import sys
-import time
-from dataclasses import dataclass
-from pathlib import Path, PurePosixPath
-from typing import Any, Callable, Iterable
-
-
-SCHEMA = "oliphaunt.wasix-postmaster.immutable-carrier-deployment.v2"
-POLICY = "linux-ext-fs-immutable-sealed-closure-v2"
-PAYLOAD_SCHEMA = "oliphaunt.wasix-postmaster.payload-files.v1"
-MANIFEST_SCHEMA = "oliphaunt.wasix-postmaster.sealed-aot.v5"
-EXT_SUPER_MAGIC = 0xEF53
-FS_IOC_GETFLAGS = 0x80086601
-FS_IOC_SETFLAGS = 0x40086602
-FS_IMMUTABLE_FL = 0x00000010
-CAP_LINUX_IMMUTABLE = 9
-SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
-AOT_RE = re.compile(r"aot/[0-9A-F]{64}\.bin\Z")
-MEMORY_RE = re.compile(r"memory/[0-9A-F]{64}\.bin\Z")
-SIDE_MODULE_POLICY_PATH = (
-    Path(__file__).resolve().parent.parent
-    / "runtime"
-    / "policies"
-    / "sealed-side-modules.v1.tsv"
-)
-
-
-class DeploymentError(Exception):
-    pass
-
-
-def require(condition: bool, message: str) -> None:
-    if not condition:
-        raise DeploymentError(message)
-
-
-def expected_aot_count() -> int:
-    rows = [
-        line
-        for line in SIDE_MODULE_POLICY_PATH.read_text(encoding="utf-8").splitlines()
-        if line and not line.startswith("#")
-    ]
-    require(bool(rows), "sealed side-module policy is empty")
-    require(
-        all(len(line.split("\t")) == 3 for line in rows),
-        "sealed side-module policy contains a malformed row",
-    )
-    return 2 + len(rows)
-
-
-EXPECTED_AOT_COUNT = expected_aot_count()
-
-
-def canonical_json(value: Any) -> bytes:
-    return (
-        json.dumps(value, ensure_ascii=True, separators=(",", ":"), sort_keys=True)
-        + "\n"
-    ).encode("ascii")
-
-
-def reject_duplicate_keys(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
-    result: dict[str, Any] = {}
-    for key, value in pairs:
-        require(key not in result, f"duplicate JSON field: {key}")
-        result[key] = value
-    return result
-
-
-def decode_json(data: bytes, label: str) -> Any:
-    try:
-        text = data.decode("utf-8")
-    except UnicodeDecodeError as error:
-        raise DeploymentError(f"{label} is not UTF-8: {error}") from error
-    require("\r" not in text, f"{label} contains a carriage return")
-    try:
-        return json.loads(text, object_pairs_hook=reject_duplicate_keys)
-    except (json.JSONDecodeError, DeploymentError) as error:
-        raise DeploymentError(f"invalid {label}: {error}") from error
-
-
-def checked_relative(value: Any, label: str) -> str:
-    require(isinstance(value, str) and value, f"{label} must be a nonempty string")
-    require(
-        not any(character in value for character in ("\0", "\n", "\r", "\t", "\\")),
-        f"{label} contains a control character or backslash",
-    )
-    path = PurePosixPath(value)
-    require(not path.is_absolute(), f"{label} must be relative: {value!r}")
-    require(
-        all(part not in ("", ".", "..") for part in path.parts),
-        f"unsafe {label}: {value!r}",
-    )
-    require(str(path) == value, f"non-canonical {label}: {value!r}")
-    return value
-
-
-def sha256_fd(descriptor: int) -> str:
-    digest = hashlib.sha256()
-    os.lseek(descriptor, 0, os.SEEK_SET)
-    while True:
-        chunk = os.read(descriptor, 1024 * 1024)
-        if not chunk:
-            break
-        digest.update(chunk)
-    os.lseek(descriptor, 0, os.SEEK_SET)
-    return digest.hexdigest()
-
-
-def read_fd(descriptor: int) -> bytes:
-    chunks: list[bytes] = []
-    os.lseek(descriptor, 0, os.SEEK_SET)
-    while True:
-        chunk = os.read(descriptor, 1024 * 1024)
-        if not chunk:
-            break
-        chunks.append(chunk)
-    os.lseek(descriptor, 0, os.SEEK_SET)
-    return b"".join(chunks)
-
-
-def open_beneath(root_fd: int, relative: str) -> int:
-    checked_relative(relative, "carrier path")
-    parts = PurePosixPath(relative).parts
-    directory_fd = os.dup(root_fd)
-    try:
-        for part in parts[:-1]:
-            next_fd = os.open(
-                part,
-                os.O_RDONLY
-                | os.O_DIRECTORY
-                | getattr(os, "O_CLOEXEC", 0)
-                | getattr(os, "O_NOFOLLOW", 0),
-                dir_fd=directory_fd,
-            )
-            os.close(directory_fd)
-            directory_fd = next_fd
-        descriptor = os.open(
-            parts[-1],
-            os.O_RDONLY
-            | getattr(os, "O_CLOEXEC", 0)
-            | getattr(os, "O_NOFOLLOW", 0),
-            dir_fd=directory_fd,
-        )
-        info = os.fstat(descriptor)
-        require(stat.S_ISREG(info.st_mode), f"carrier path is not regular: {relative}")
-        return descriptor
-    finally:
-        os.close(directory_fd)
-
-
-def open_beneath_entry(root_fd: int, relative: str, entry_type: str) -> int:
-    require(entry_type in {"file", "directory"}, "invalid carrier entry type")
-    if relative == ".":
-        require(entry_type == "directory", "carrier root receipt entry is not a directory")
-        return os.dup(root_fd)
-    checked_relative(relative, "carrier receipt path")
-    parts = PurePosixPath(relative).parts
-    directory_fd = os.dup(root_fd)
-    try:
-        for part in parts[:-1]:
-            next_fd = os.open(
-                part,
-                os.O_RDONLY
-                | os.O_DIRECTORY
-                | getattr(os, "O_CLOEXEC", 0)
-                | getattr(os, "O_NOFOLLOW", 0),
-                dir_fd=directory_fd,
-            )
-            os.close(directory_fd)
-            directory_fd = next_fd
-        flags = (
-            os.O_RDONLY
-            | getattr(os, "O_CLOEXEC", 0)
-            | getattr(os, "O_NOFOLLOW", 0)
-        )
-        if entry_type == "directory":
-            flags |= os.O_DIRECTORY
-        descriptor = os.open(parts[-1], flags, dir_fd=directory_fd)
-        info = os.fstat(descriptor)
-        expected = stat.S_ISREG(info.st_mode) if entry_type == "file" else stat.S_ISDIR(info.st_mode)
-        require(expected, f"carrier receipt entry type changed: {relative}")
-        return descriptor
-    finally:
-        os.close(directory_fd)
-
-
-class StatFs(ctypes.Structure):
-    _fields_ = [
-        ("f_type", ctypes.c_long),
-        ("f_bsize", ctypes.c_long),
-        ("f_blocks", ctypes.c_ulong),
-        ("f_bfree", ctypes.c_ulong),
-        ("f_bavail", ctypes.c_ulong),
-        ("f_files", ctypes.c_ulong),
-        ("f_ffree", ctypes.c_ulong),
-        ("f_fsid", ctypes.c_int * 2),
-        ("f_namelen", ctypes.c_long),
-        ("f_frsize", ctypes.c_long),
-        ("f_flags", ctypes.c_long),
-        ("f_spare", ctypes.c_long * 4),
-    ]
-
-
-class KernelOps:
-    def __init__(self) -> None:
-        self._libc = ctypes.CDLL(None, use_errno=True)
-
-    def filesystem_magic(self, descriptor: int) -> int:
-        result = StatFs()
-        if self._libc.fstatfs(descriptor, ctypes.byref(result)) != 0:
-            error = ctypes.get_errno()
-            raise OSError(error, os.strerror(error))
-        return int(result.f_type) & 0xFFFFFFFFFFFFFFFF
-
-    def get_flags(self, descriptor: int) -> int:
-        value = array.array("I", [0])
-        fcntl.ioctl(descriptor, FS_IOC_GETFLAGS, value, True)
-        return int(value[0])
-
-    def set_flags(self, descriptor: int, flags: int) -> None:
-        value = array.array("I", [flags])
-        fcntl.ioctl(descriptor, FS_IOC_SETFLAGS, value, True)
-
-
-@dataclass
-class OpenCarrierEntry:
-    path: str
-    entry_type: str
-    direct_loader_kind: str
-    descriptor: int
-    expected_sha256: str | None
-    info: os.stat_result
-    actual_sha256: str | None
-    pre_flags: int
-    post_flags: int
-
-    def close(self) -> None:
-        os.close(self.descriptor)
-
-
-def require_linux() -> None:
-    require(sys.platform.startswith("linux"), "immutable deployment requires Linux")
-
-
-def effective_capabilities() -> int:
-    try:
-        lines = Path("/proc/self/status").read_text(encoding="ascii").splitlines()
-    except OSError as error:
-        raise DeploymentError(f"cannot read effective Linux capabilities: {error}") from error
-    for line in lines:
-        if line.startswith("CapEff:\t"):
-            try:
-                return int(line.split("\t", 1)[1], 16)
-            except ValueError as error:
-                raise DeploymentError("malformed CapEff in /proc/self/status") from error
-    raise DeploymentError("/proc/self/status does not expose CapEff")
-
-
-def require_root_immutable_capability() -> None:
-    require(os.geteuid() == 0, "immutable deployment/removal requires effective UID 0")
-    capabilities = effective_capabilities()
-    require(
-        capabilities & (1 << CAP_LINUX_IMMUTABLE) != 0,
-        "immutable deployment/removal requires effective CAP_LINUX_IMMUTABLE",
-    )
-
-
-def parse_expected_hash(value: str, label: str) -> str:
-    require(SHA256_RE.fullmatch(value) is not None, f"{label} must be a SHA-256")
-    return value
-
-
-def carrier_closure_identity(identity_hashes: dict[str, str]) -> str:
-    digest = hashlib.sha256()
-    for value in (
-        "oliphaunt.wasix-postmaster.qualification-carrier.v1",
-        identity_hashes["manifest.json"],
-        identity_hashes["wasmer-build.receipt"],
-        identity_hashes["payload.files"],
-        identity_hashes["bin/wasmer-headless"],
-    ):
-        digest.update(value.encode("ascii"))
-        digest.update(b"\0")
-    return digest.hexdigest()
-
-
-def direct_loader_paths(manifest: dict[str, Any]) -> list[tuple[str, str, str]]:
-    artifacts = manifest.get("artifacts")
-    require(
-        isinstance(artifacts, list) and len(artifacts) == EXPECTED_AOT_COUNT,
-        f"manifest must contain exactly {EXPECTED_AOT_COUNT} artifacts",
-    )
-    selected: list[tuple[str, str, str]] = []
-    for index, artifact in enumerate(artifacts):
-        require(isinstance(artifact, dict), f"manifest artifact {index} is not an object")
-        path = checked_relative(artifact.get("path"), f"manifest artifact {index} path")
-        digest = parse_expected_hash(artifact.get("sha256"), f"manifest artifact {index} SHA-256")
-        require(AOT_RE.fullmatch(path) is not None, f"non-canonical AOT path: {path}")
-        selected.append((path, "aot", digest))
-    selected.sort()
-    paths = [item[0] for item in selected]
-    require(len(paths) == len(set(paths)), "manifest direct-loader paths are not unique")
-    require(
-        sum(kind == "aot" for _, kind, _ in selected) == EXPECTED_AOT_COUNT,
-        "immutable policy requires the complete AOT closure",
-    )
-    return selected
-
-
-def manifest_provenance(manifest_data: bytes) -> tuple[str, str]:
-    manifest = decode_json(manifest_data, "sealed carrier manifest")
-    require(isinstance(manifest, dict), "sealed carrier manifest must be an object")
-    require(
-        manifest.get("format-version") == 6
-        and manifest.get("schema") == MANIFEST_SCHEMA,
-        "sealed carrier manifest provenance schema differs",
-    )
-    core_profile = manifest.get("core-profile")
-    require(
-        core_profile in {"release-o3", "safe-o2"},
-        "sealed carrier core profile is not candidate/control",
-    )
-    guest_recipe = manifest.get("guest-build-recipe-sha256")
-    parse_expected_hash(guest_recipe, "sealed carrier guest build recipe")
-    return core_profile, guest_recipe
-
-
-def open_carrier_root(carrier: Path) -> tuple[Path, int, os.stat_result]:
-    require_linux()
-    require(carrier.is_absolute(), "carrier path must be absolute")
-    before = os.lstat(carrier)
-    require(stat.S_ISDIR(before.st_mode) and not stat.S_ISLNK(before.st_mode), "carrier root must be a non-symlink directory")
-    descriptor = os.open(
-        carrier,
-        os.O_RDONLY
-        | os.O_DIRECTORY
-        | getattr(os, "O_CLOEXEC", 0)
-        | getattr(os, "O_NOFOLLOW", 0),
-    )
-    opened = os.fstat(descriptor)
-    require(
-        (before.st_dev, before.st_ino) == (opened.st_dev, opened.st_ino),
-        "carrier root changed while opening",
-    )
-    canonical = Path(os.path.realpath(carrier))
-    require(canonical == carrier, "carrier path must already be canonical")
-    return canonical, descriptor, opened
-
-
-def identity_files(root_fd: int) -> tuple[dict[str, str], dict[str, bytes]]:
-    hashes: dict[str, str] = {}
-    contents: dict[str, bytes] = {}
-    for relative in (
-        "manifest.json",
-        "wasmer-build.receipt",
-        "payload.files",
-        "bin/wasmer-headless",
-    ):
-        descriptor = open_beneath(root_fd, relative)
-        try:
-            data = read_fd(descriptor)
-            hashes[relative] = hashlib.sha256(data).hexdigest()
-            contents[relative] = data
-        finally:
-            os.close(descriptor)
-    return hashes, contents
-
-
-def require_expected_identity(hashes: dict[str, str], expected: dict[str, str]) -> None:
-    for key, digest in expected.items():
-        parse_expected_hash(digest, f"expected {key} identity")
-        require(hashes[key] == digest, f"carrier identity changed for {key}")
-
-
-def parse_inventory(data: bytes) -> dict[str, tuple[int, str]]:
-    try:
-        text = data.decode("utf-8")
-    except UnicodeDecodeError as error:
-        raise DeploymentError(f"payload inventory is not UTF-8: {error}") from error
-    require("\r" not in text and text.endswith("\n"), "payload inventory is not canonical text")
-    lines = text.splitlines()
-    require(lines and lines[0] == f"schema={PAYLOAD_SCHEMA}", "payload inventory schema differs")
-    inventory: dict[str, tuple[int, str]] = {}
-    previous = ""
-    for line_number, line in enumerate(lines[1:], 2):
-        fields = line.split("\t")
-        require(len(fields) == 3, f"payload inventory line {line_number} must have three fields")
-        digest, size_text, relative_value = fields
-        parse_expected_hash(digest, f"payload inventory line {line_number} SHA-256")
-        require(
-            re.fullmatch(r"0|[1-9][0-9]*", size_text) is not None,
-            f"payload inventory line {line_number} has a non-canonical size",
-        )
-        relative = checked_relative(relative_value, f"payload inventory line {line_number} path")
-        require(relative != "payload.files", "payload inventory must not inventory itself")
-        require(relative > previous, "payload inventory paths must be unique and strictly sorted")
-        previous = relative
-        inventory[relative] = (int(size_text), digest)
-    require(inventory, "payload inventory is empty")
-    return inventory
-
-
-def entry_order_key(item: OpenCarrierEntry) -> tuple[int, int, str]:
-    if item.entry_type == "file":
-        return (0, 0, item.path)
-    if item.path == ".":
-        return (2, 0, item.path)
-    return (1, -len(PurePosixPath(item.path).parts), item.path)
-
-
-def transition_order(entries: Iterable[OpenCarrierEntry]) -> list[OpenCarrierEntry]:
-    # Files first; then deepest directories; carrier root last. This keeps the
-    # namespace traversable until every leaf has been protected.
-    return sorted(entries, key=entry_order_key)
-
-
-def open_exact_carrier_closure(
-    root_fd: int,
-    manifest_data: bytes,
-    payload_data: bytes,
-    ops: KernelOps,
-) -> list[OpenCarrierEntry]:
-    manifest = decode_json(manifest_data, "carrier manifest")
-    require(isinstance(manifest, dict), "carrier manifest must be an object")
-    direct = {
-        path: (kind, digest)
-        for path, kind, digest in direct_loader_paths(manifest)
-    }
-    inventory = parse_inventory(payload_data)
-    expected_files = set(inventory) | {"payload.files"}
-    opened: list[OpenCarrierEntry] = []
-
-    def capture(
-        descriptor: int,
-        relative: str,
-        entry_type: str,
-        info: os.stat_result,
-    ) -> None:
-        mode = stat.S_IMODE(info.st_mode)
-        if entry_type == "file":
-            require(mode in (0o444, 0o555), f"sealed carrier file mode differs: {relative}")
-        else:
-            require(mode == 0o555, f"sealed carrier directory mode differs: {relative}")
-        magic = ops.filesystem_magic(descriptor)
-        require(
-            magic == EXT_SUPER_MAGIC,
-            f"sealed carrier entry is not on an ext-family filesystem: {relative}: 0x{magic:x}",
-        )
-        actual_digest = sha256_fd(descriptor) if entry_type == "file" else None
-        expected_digest: str | None = None
-        direct_kind = "none"
-        if entry_type == "file":
-            require(relative in expected_files, f"carrier contains an unlisted file: {relative}")
-            if relative == "payload.files":
-                expected_digest = hashlib.sha256(payload_data).hexdigest()
-                require(actual_digest == expected_digest, "payload inventory changed during closure scan")
-            else:
-                expected_size, expected_digest = inventory[relative]
-                require(info.st_size == expected_size, f"payload size mismatch: {relative}")
-                require(actual_digest == expected_digest, f"payload SHA-256 mismatch: {relative}")
-            if relative in direct:
-                direct_kind, direct_digest = direct[relative]
-                require(actual_digest == direct_digest, f"direct-loader SHA-256 mismatch: {relative}")
-        pre_flags = ops.get_flags(descriptor)
-        opened.append(
-            OpenCarrierEntry(
-                path=relative,
-                entry_type=entry_type,
-                direct_loader_kind=direct_kind,
-                descriptor=descriptor,
-                expected_sha256=expected_digest,
-                info=info,
-                actual_sha256=actual_digest,
-                pre_flags=pre_flags,
-                post_flags=pre_flags | FS_IMMUTABLE_FL,
-            )
-        )
-
-    def walk(directory_fd: int, prefix: str) -> None:
-        try:
-            names = sorted(os.listdir(directory_fd))
-        except OSError as error:
-            raise DeploymentError(f"cannot enumerate sealed carrier directory {prefix or '.'}: {error}") from error
-        for name in names:
-            require(name not in ("", ".", "..") and "/" not in name, "unsafe carrier directory entry")
-            relative = f"{prefix}/{name}" if prefix else name
-            checked_relative(relative, "carrier closure path")
-            before = os.stat(name, dir_fd=directory_fd, follow_symlinks=False)
-            if stat.S_ISDIR(before.st_mode):
-                descriptor = os.open(
-                    name,
-                    os.O_RDONLY
-                    | os.O_DIRECTORY
-                    | getattr(os, "O_CLOEXEC", 0)
-                    | getattr(os, "O_NOFOLLOW", 0),
-                    dir_fd=directory_fd,
-                )
-                after = os.fstat(descriptor)
-                require(
-                    (before.st_dev, before.st_ino) == (after.st_dev, after.st_ino),
-                    f"carrier directory changed while opening: {relative}",
-                )
-                capture(descriptor, relative, "directory", after)
-                walk(descriptor, relative)
-            elif stat.S_ISREG(before.st_mode):
-                descriptor = os.open(
-                    name,
-                    os.O_RDONLY
-                    | getattr(os, "O_CLOEXEC", 0)
-                    | getattr(os, "O_NOFOLLOW", 0),
-                    dir_fd=directory_fd,
-                )
-                after = os.fstat(descriptor)
-                require(
-                    (before.st_dev, before.st_ino) == (after.st_dev, after.st_ino),
-                    f"carrier file changed while opening: {relative}",
-                )
-                capture(descriptor, relative, "file", after)
-            else:
-                raise DeploymentError(f"carrier contains a symlink or special entry: {relative}")
-
-    try:
-        root_descriptor = os.dup(root_fd)
-        root_info = os.fstat(root_descriptor)
-        capture(root_descriptor, ".", "directory", root_info)
-        walk(root_fd, "")
-        actual_files = {entry.path for entry in opened if entry.entry_type == "file"}
-        require(actual_files == expected_files, "carrier file closure differs from payload inventory")
-        actual_direct = {
-            entry.path
-            for entry in opened
-            if entry.direct_loader_kind != "none"
-        }
-        require(actual_direct == set(direct), "carrier direct-loader subset differs from manifest")
-    except BaseException:
-        for item in opened:
-            item.close()
-        raise
-    return opened
-
-
-def receipt_path_checks(receipt: Path, carrier: Path) -> tuple[Path, str]:
-    require(receipt.is_absolute(), "receipt path must be absolute")
-    parent = Path(os.path.realpath(receipt.parent))
-    require(parent == receipt.parent, "receipt parent must already be canonical")
-    info = os.lstat(parent)
-    require(stat.S_ISDIR(info.st_mode) and not stat.S_ISLNK(info.st_mode), "receipt parent must be a non-symlink directory")
-    require(receipt.parent != carrier and carrier not in receipt.parents, "receipt must be outside the sealed carrier")
-    require(receipt.name not in ("", ".", "..") and "/" not in receipt.name, "invalid receipt filename")
-    return parent, receipt.name
-
-
-def write_atomic_new(
-    path: Path,
-    data: bytes,
-    ops: KernelOps,
-    *,
-    expected_owner_uid: int = 0,
-) -> tuple[int, int, str]:
-    parent, name = receipt_path_checks(path, Path("/nonexistent-carrier-placeholder"))
-    directory_fd = os.open(parent, os.O_RDONLY | os.O_DIRECTORY | getattr(os, "O_CLOEXEC", 0))
-    temporary = f".{name}.pending.{os.getpid()}.{time.monotonic_ns()}"
-    descriptor = -1
-    published = False
-    info: os.stat_result | None = None
-    try:
-        descriptor = os.open(
-            temporary,
-            os.O_RDWR | os.O_CREAT | os.O_EXCL | getattr(os, "O_CLOEXEC", 0),
-            0o600,
-            dir_fd=directory_fd,
-        )
-        view = memoryview(data)
-        while view:
-            written = os.write(descriptor, view)
-            require(written > 0, "short write while creating immutable deployment receipt")
-            view = view[written:]
-        os.fsync(descriptor)
-        os.fchmod(descriptor, 0o444)
-        info = os.fstat(descriptor)
-        require(info.st_uid == expected_owner_uid, "deployment receipt is not owned by the required root identity")
-        # linkat is the portable no-replace publication primitive available
-        # through Python. The fully written inode becomes visible in one step,
-        # and an existing receipt can never be overwritten.
-        os.link(
-            temporary,
-            name,
-            src_dir_fd=directory_fd,
-            dst_dir_fd=directory_fd,
-            follow_symlinks=False,
-        )
-        published = True
-        os.unlink(temporary, dir_fd=directory_fd)
-        os.fsync(directory_fd)
-        receipt_flags = ops.get_flags(descriptor)
-        require(
-            receipt_flags & FS_IMMUTABLE_FL == 0,
-            "new deployment receipt unexpectedly begins immutable",
-        )
-        ops.set_flags(descriptor, receipt_flags | FS_IMMUTABLE_FL)
-        require(
-            ops.get_flags(descriptor) == receipt_flags | FS_IMMUTABLE_FL,
-            "deployment receipt immutable flag did not stick",
-        )
-        os.fsync(descriptor)
-        os.fsync(directory_fd)
-        os.close(descriptor)
-        descriptor = -1
-        return info.st_dev, info.st_ino, hashlib.sha256(data).hexdigest()
-    except BaseException:
-        if published and info is not None and descriptor >= 0:
-            try:
-                current_flags = ops.get_flags(descriptor)
-                if current_flags & FS_IMMUTABLE_FL:
-                    ops.set_flags(descriptor, current_flags & ~FS_IMMUTABLE_FL)
-                current = os.stat(name, dir_fd=directory_fd, follow_symlinks=False)
-                if (current.st_dev, current.st_ino) == (info.st_dev, info.st_ino):
-                    os.unlink(name, dir_fd=directory_fd)
-                    os.fsync(directory_fd)
-            except OSError:
-                pass
-        if descriptor >= 0:
-            os.close(descriptor)
-        try:
-            os.unlink(temporary, dir_fd=directory_fd)
-        except FileNotFoundError:
-            pass
-        raise
-    finally:
-        os.close(directory_fd)
-
-
-def unlink_exact_receipt(
-    path: Path,
-    expected_dev: int,
-    expected_ino: int,
-    expected_sha: str,
-    ops: KernelOps,
-) -> None:
-    parent, name = receipt_path_checks(path, Path("/nonexistent-carrier-placeholder"))
-    directory_fd = os.open(parent, os.O_RDONLY | os.O_DIRECTORY | getattr(os, "O_CLOEXEC", 0))
-    descriptor = -1
-    try:
-        descriptor = os.open(
-            name,
-            os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0),
-            dir_fd=directory_fd,
-        )
-        info = os.fstat(descriptor)
-        require(
-            stat.S_ISREG(info.st_mode)
-            and (info.st_dev, info.st_ino) == (expected_dev, expected_ino),
-            "deployment receipt identity changed before removal",
-        )
-        require(sha256_fd(descriptor) == expected_sha, "deployment receipt content changed before removal")
-        current_flags = ops.get_flags(descriptor)
-        if current_flags & FS_IMMUTABLE_FL:
-            ops.set_flags(descriptor, current_flags & ~FS_IMMUTABLE_FL)
-        require(
-            ops.get_flags(descriptor) == current_flags & ~FS_IMMUTABLE_FL,
-            "deployment receipt immutable flag could not be cleared",
-        )
-        current = os.stat(name, dir_fd=directory_fd, follow_symlinks=False)
-        require(
-            (current.st_dev, current.st_ino) == (expected_dev, expected_ino),
-            "deployment receipt path changed after clearing its immutable flag",
-        )
-        os.unlink(name, dir_fd=directory_fd)
-        os.fsync(directory_fd)
-    finally:
-        if descriptor >= 0:
-            os.close(descriptor)
-        os.close(directory_fd)
-
-
-def make_receipt(
-    carrier: Path,
-    root_info: os.stat_result,
-    identity_hashes: dict[str, str],
-    manifest_data: bytes,
-    entries: Iterable[OpenCarrierEntry],
-) -> dict[str, Any]:
-    ordered = sorted(entries, key=lambda item: (item.path != ".", item.path))
-    core_profile, guest_build_recipe_sha256 = manifest_provenance(manifest_data)
-    return {
-        "carrier": {
-            "closure-identity": carrier_closure_identity(identity_hashes),
-            "device": root_info.st_dev,
-            "headless-sha256": identity_hashes["bin/wasmer-headless"],
-            "inode": root_info.st_ino,
-            "manifest-sha256": identity_hashes["manifest.json"],
-            "path": str(carrier),
-            "payload-inventory-sha256": identity_hashes["payload.files"],
-            "wasmer-build-receipt-sha256": identity_hashes["wasmer-build.receipt"],
-        },
-        "filesystem": {"magic": f"0x{EXT_SUPER_MAGIC:x}", "type": "ext-family"},
-        "direct-loader-paths": [
-            item.path
-            for item in ordered
-            if item.direct_loader_kind != "none"
-        ],
-        "core_profile": core_profile,
-        "entries": [
-            {
-                "device": item.info.st_dev,
-                "direct-loader-kind": item.direct_loader_kind,
-                "entry-type": item.entry_type,
-                "gid": item.info.st_gid,
-                "inode": item.info.st_ino,
-                "mode": f"{stat.S_IMODE(item.info.st_mode):04o}",
-                "path": item.path,
-                "post-flags": f"0x{item.post_flags:08x}",
-                "pre-flags": f"0x{item.pre_flags:08x}",
-                "sha256": item.actual_sha256,
-                "size": item.info.st_size,
-                "uid": item.info.st_uid,
-            }
-            for item in ordered
-        ],
-        "guest_build_recipe_sha256": guest_build_recipe_sha256,
-        "policy": POLICY,
-        "schema": SCHEMA,
-    }
-
-
-def close_all(entries: Iterable[OpenCarrierEntry]) -> None:
-    for item in entries:
-        item.close()
-
-
-def transition_flags(
-    entries: Iterable[OpenCarrierEntry],
-    ops: KernelOps,
-    target: Callable[[OpenCarrierEntry], int],
-) -> None:
-    errors: list[str] = []
-    for item in entries:
-        try:
-            current = ops.get_flags(item.descriptor)
-            desired = target(item)
-            require(
-                current in (item.pre_flags, item.post_flags),
-                f"inode flags diverged from the deployment transition: {item.path}",
-            )
-            if current != desired:
-                ops.set_flags(item.descriptor, desired)
-            require(ops.get_flags(item.descriptor) == desired, f"flag restore did not stick: {item.path}")
-        except (OSError, DeploymentError) as error:
-            errors.append(f"{item.path}: {error}")
-    require(not errors, "failed to restore inode flags: " + "; ".join(errors))
-
-
-def deploy(
-    carrier: Path,
-    receipt_path: Path,
-    expected_identity: dict[str, str],
-    ops: KernelOps,
-    *,
-    check_capability: Callable[[], None] = require_root_immutable_capability,
-    receipt_owner_uid: int = 0,
-) -> dict[str, Any]:
-    check_capability()
-    receipt_path_checks(receipt_path, carrier)
-    require(not os.path.lexists(receipt_path), f"deployment receipt already exists: {receipt_path}")
-    canonical, root_fd, root_info = open_carrier_root(carrier)
-    entries: list[OpenCarrierEntry] = []
-    receipt_dev = receipt_ino = -1
-    receipt_sha = ""
-    receipt_written = False
-    try:
-        identity_hashes, identity_contents = identity_files(root_fd)
-        require_expected_identity(identity_hashes, expected_identity)
-        entries = open_exact_carrier_closure(
-            root_fd,
-            identity_contents["manifest.json"],
-            identity_contents["payload.files"],
-            ops,
-        )
-        receipt = make_receipt(
-            canonical,
-            root_info,
-            identity_hashes,
-            identity_contents["manifest.json"],
-            entries,
-        )
-        receipt_data = canonical_json(receipt)
-        receipt_dev, receipt_ino, receipt_sha = write_atomic_new(
-            receipt_path,
-            receipt_data,
-            ops,
-            expected_owner_uid=receipt_owner_uid,
-        )
-        receipt_written = True
-        try:
-            transition_flags(
-                transition_order(entries),
-                ops,
-                lambda item: item.post_flags,
-            )
-            after_hashes, _ = identity_files(root_fd)
-            require(after_hashes == identity_hashes, "carrier identity changed during immutable deployment")
-        except BaseException:
-            transition_flags(
-                reversed(transition_order(entries)),
-                ops,
-                lambda item: item.pre_flags,
-            )
-            unlink_exact_receipt(
-                receipt_path,
-                receipt_dev,
-                receipt_ino,
-                receipt_sha,
-                ops,
-            )
-            receipt_written = False
-            raise
-        return receipt
-    finally:
-        close_all(entries)
-        os.close(root_fd)
-        if receipt_written:
-            # Retained intentionally: it is the recovery journal and active policy receipt.
-            pass
-
-
-def load_receipt(
-    path: Path,
-    carrier: Path,
-    ops: KernelOps,
-    *,
-    expected_owner_uid: int = 0,
-    require_immutable: bool = True,
-) -> tuple[dict[str, Any], os.stat_result, str]:
-    receipt_path_checks(path, carrier)
-    flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
-    before = os.lstat(path)
-    require(stat.S_ISREG(before.st_mode) and not stat.S_ISLNK(before.st_mode), "deployment receipt must be a regular non-symlink file")
-    descriptor = os.open(path, flags)
-    try:
-        opened = os.fstat(descriptor)
-        require((before.st_dev, before.st_ino) == (opened.st_dev, opened.st_ino), "deployment receipt changed while opening")
-        data = read_fd(descriptor)
-        after = os.fstat(descriptor)
-        require(
-            (opened.st_dev, opened.st_ino, opened.st_size, opened.st_mtime_ns)
-            == (after.st_dev, after.st_ino, after.st_size, after.st_mtime_ns),
-            "deployment receipt changed while reading",
-        )
-        require(opened.st_uid == expected_owner_uid, "deployment receipt is not root-owned")
-        require(stat.S_IMODE(opened.st_mode) == 0o444, "deployment receipt mode must be 0444")
-        require(
-            ops.filesystem_magic(descriptor) == EXT_SUPER_MAGIC,
-            "deployment receipt must reside on an ext-family filesystem",
-        )
-        if require_immutable:
-            require(
-                ops.get_flags(descriptor) & FS_IMMUTABLE_FL != 0,
-                "deployment receipt inode is not immutable",
-            )
-    finally:
-        os.close(descriptor)
-    receipt = decode_json(data, "immutable deployment receipt")
-    require(isinstance(receipt, dict), "immutable deployment receipt must be an object")
-    require(canonical_json(receipt) == data, "immutable deployment receipt is not canonical JSON")
-    require(
-        set(receipt)
-        == {
-            "carrier",
-            "core_profile",
-            "direct-loader-paths",
-            "entries",
-            "filesystem",
-            "guest_build_recipe_sha256",
-            "policy",
-            "schema",
-        },
-        "immutable deployment receipt fields differ",
-    )
-    require(receipt["schema"] == SCHEMA and receipt["policy"] == POLICY, "immutable deployment receipt policy differs")
-    require(
-        receipt["core_profile"] in {"release-o3", "safe-o2"},
-        "immutable deployment receipt core profile differs",
-    )
-    parse_expected_hash(
-        receipt["guest_build_recipe_sha256"],
-        "immutable deployment receipt guest build recipe",
-    )
-    return receipt, opened, hashlib.sha256(data).hexdigest()
-
-
-def receipt_identity(
-    receipt: dict[str, Any],
-    carrier: Path,
-    root_info: os.stat_result,
-    hashes: dict[str, str],
-    manifest_data: bytes,
-) -> None:
-    expected_carrier = {
-        "closure-identity": carrier_closure_identity(hashes),
-        "device": root_info.st_dev,
-        "headless-sha256": hashes["bin/wasmer-headless"],
-        "inode": root_info.st_ino,
-        "manifest-sha256": hashes["manifest.json"],
-        "path": str(carrier),
-        "payload-inventory-sha256": hashes["payload.files"],
-        "wasmer-build-receipt-sha256": hashes["wasmer-build.receipt"],
-    }
-    require(receipt["carrier"] == expected_carrier, "deployment receipt carrier identity differs")
-    require(receipt["filesystem"] == {"magic": f"0x{EXT_SUPER_MAGIC:x}", "type": "ext-family"}, "deployment receipt filesystem differs")
-    core_profile, guest_build_recipe_sha256 = manifest_provenance(manifest_data)
-    require(
-        receipt["core_profile"] == core_profile
-        and receipt["guest_build_recipe_sha256"] == guest_build_recipe_sha256,
-        "deployment receipt guest build provenance differs",
-    )
-
-
-def parse_receipt_entries(
-    receipt: dict[str, Any], *, allow_legacy_ownership_for_remove: bool = False
-) -> list[dict[str, Any]]:
-    entries = receipt["entries"]
-    require(isinstance(entries, list) and entries, "deployment receipt closure is empty")
-    previous: str | None = None
-    result: list[dict[str, Any]] = []
-    for entry in entries:
-        require(isinstance(entry, dict), "deployment receipt entry must be an object")
-        current_fields = {
-            "device",
-            "direct-loader-kind",
-            "entry-type",
-            "gid",
-            "inode",
-            "mode",
-            "path",
-            "post-flags",
-            "pre-flags",
-            "sha256",
-            "size",
-            "uid",
-        }
-        legacy_fields = current_fields - {"gid", "uid"}
-        require(
-            set(entry) == current_fields
-            or (
-                allow_legacy_ownership_for_remove
-                and set(entry) == legacy_fields
-            ),
-            "deployment receipt entry fields differ",
-        )
-        if entry["path"] == ".":
-            path = "."
-        else:
-            path = checked_relative(entry["path"], "deployment receipt entry path")
-        require(
-            previous is None
-            or (previous == "." and path != ".")
-            or (previous != "." and path > previous),
-            "deployment receipt entries must be strictly sorted with root first",
-        )
-        previous = path
-        require(entry["entry-type"] in ("file", "directory"), f"invalid entry type: {path}")
-        require(
-            entry["direct-loader-kind"] in ("none", "aot"),
-            f"invalid direct-loader kind: {path}",
-        )
-        if entry["direct-loader-kind"] != "none":
-            require(entry["entry-type"] == "file", f"direct-loader entry is not a file: {path}")
-        require(type(entry["device"]) is int and entry["device"] >= 0, f"invalid device: {path}")
-        require(type(entry["inode"]) is int and entry["inode"] > 0, f"invalid inode: {path}")
-        require(type(entry["size"]) is int and entry["size"] >= 0, f"invalid size: {path}")
-        if "uid" in entry:
-            require(type(entry["uid"]) is int and entry["uid"] >= 0, f"invalid uid: {path}")
-            require(type(entry["gid"]) is int and entry["gid"] >= 0, f"invalid gid: {path}")
-        if entry["entry-type"] == "file":
-            parse_expected_hash(entry["sha256"], f"deployment receipt SHA-256: {path}")
-            require(entry["mode"] in ("0444", "0555"), f"sealed carrier file mode differs: {path}")
-        else:
-            require(entry["sha256"] is None, f"directory receipt must not contain a SHA-256: {path}")
-            require(entry["mode"] == "0555", f"sealed carrier directory mode must be 0555: {path}")
-        for field in ("pre-flags", "post-flags"):
-            require(re.fullmatch(r"0x[0-9a-f]{8}", entry[field]) is not None, f"invalid {field}: {path}")
-        pre = int(entry["pre-flags"], 16)
-        post = int(entry["post-flags"], 16)
-        require(post == pre | FS_IMMUTABLE_FL, f"invalid immutable flag transition: {path}")
-        result.append(entry)
-    require(result[0]["path"] == "." and result[0]["entry-type"] == "directory", "receipt does not begin with carrier root")
-    direct_paths = [
-        entry["path"]
-        for entry in result
-        if entry["direct-loader-kind"] != "none"
-    ]
-    require(receipt["direct-loader-paths"] == direct_paths, "receipt direct-loader subset differs")
-    require(
-        sum(entry["direct-loader-kind"] == "aot" for entry in result)
-        == EXPECTED_AOT_COUNT,
-        "receipt AOT file count differs",
-    )
-    return result
-
-
-def fast_receipt_identity(
-    receipt: dict[str, Any], carrier: Path, root_info: os.stat_result
-) -> None:
-    identity = receipt["carrier"]
-    require(isinstance(identity, dict), "deployment receipt carrier identity is not an object")
-    require(
-        set(identity)
-        == {
-            "closure-identity",
-            "device",
-            "headless-sha256",
-            "inode",
-            "manifest-sha256",
-            "path",
-            "payload-inventory-sha256",
-            "wasmer-build-receipt-sha256",
-        },
-        "deployment receipt carrier identity fields differ",
-    )
-    hashes = {
-        "manifest.json": identity["manifest-sha256"],
-        "wasmer-build.receipt": identity["wasmer-build-receipt-sha256"],
-        "payload.files": identity["payload-inventory-sha256"],
-        "bin/wasmer-headless": identity["headless-sha256"],
-    }
-    for relative, digest in hashes.items():
-        parse_expected_hash(digest, f"deployment receipt {relative} identity")
-    parse_expected_hash(identity["closure-identity"], "deployment receipt closure identity")
-    require(
-        identity["closure-identity"] == carrier_closure_identity(hashes),
-        "deployment receipt closure identity is internally inconsistent",
-    )
-    require(
-        identity["path"] == str(carrier)
-        and identity["device"] == root_info.st_dev
-        and identity["inode"] == root_info.st_ino,
-        "deployment receipt carrier root identity differs",
-    )
-    require(
-        receipt["filesystem"]
-        == {"magic": f"0x{EXT_SUPER_MAGIC:x}", "type": "ext-family"},
-        "deployment receipt filesystem differs",
-    )
-
-
-def verify_fast(
-    carrier: Path,
-    receipt_path: Path,
-    ops: KernelOps,
-    *,
-    expected_identity: dict[str, str] | None = None,
-    receipt_owner_uid: int = 0,
-) -> dict[str, Any]:
-    """Verify immutable inode identity without rereading payload contents."""
-
-    receipt, _, _ = load_receipt(
-        receipt_path,
-        carrier,
-        ops,
-        expected_owner_uid=receipt_owner_uid,
-        require_immutable=True,
-    )
-    canonical, root_fd, root_info = open_carrier_root(carrier)
-    descriptors: list[int] = []
-    try:
-        require(
-            ops.filesystem_magic(root_fd) == EXT_SUPER_MAGIC,
-            "carrier root must reside on an ext-family filesystem",
-        )
-        fast_receipt_identity(receipt, canonical, root_info)
-        if expected_identity is not None:
-            identity = receipt["carrier"]
-            actual_identity = {
-                "manifest.json": identity["manifest-sha256"],
-                "wasmer-build.receipt": identity["wasmer-build-receipt-sha256"],
-                "payload.files": identity["payload-inventory-sha256"],
-                "bin/wasmer-headless": identity["headless-sha256"],
-            }
-            require_expected_identity(actual_identity, expected_identity)
-        for entry in parse_receipt_entries(receipt):
-            descriptor = open_beneath_entry(
-                root_fd, entry["path"], entry["entry-type"]
-            )
-            descriptors.append(descriptor)
-            info = os.fstat(descriptor)
-            require(
-                (info.st_dev, info.st_ino, info.st_size)
-                == (entry["device"], entry["inode"], entry["size"]),
-                f"deployment inode identity differs: {entry['path']}",
-            )
-            require(
-                stat.S_IMODE(info.st_mode) == int(entry["mode"], 8),
-                f"deployment entry mode differs: {entry['path']}",
-            )
-            require(
-                (info.st_uid, info.st_gid) == (entry["uid"], entry["gid"]),
-                f"deployment entry ownership differs: {entry['path']}",
-            )
-            post_flags = int(entry["post-flags"], 16)
-            current_flags = ops.get_flags(descriptor)
-            require(
-                current_flags == post_flags
-                and current_flags & FS_IMMUTABLE_FL != 0,
-                f"deployment inode is not immutable: {entry['path']}",
-            )
-        return receipt
-    finally:
-        for descriptor in descriptors:
-            os.close(descriptor)
-        os.close(root_fd)
-
-
-def verify_or_remove(
-    carrier: Path,
-    receipt_path: Path,
-    expected_identity: dict[str, str],
-    ops: KernelOps,
-    *,
-    remove: bool,
-    check_capability: Callable[[], None] = require_root_immutable_capability,
-    receipt_owner_uid: int = 0,
-) -> dict[str, Any]:
-    if remove:
-        check_capability()
-    receipt, receipt_info, receipt_sha = load_receipt(
-        receipt_path,
-        carrier,
-        ops,
-        expected_owner_uid=receipt_owner_uid,
-        require_immutable=not remove,
-    )
-    canonical, root_fd, root_info = open_carrier_root(carrier)
-    opened: list[OpenCarrierEntry] = []
-    live_entries: list[OpenCarrierEntry] = []
-    try:
-        hashes, contents = identity_files(root_fd)
-        require_expected_identity(hashes, expected_identity)
-        receipt_identity(
-            receipt,
-            canonical,
-            root_info,
-            hashes,
-            contents["manifest.json"],
-        )
-        live_entries = open_exact_carrier_closure(
-            root_fd,
-            contents["manifest.json"],
-            contents["payload.files"],
-            ops,
-        )
-        receipt_entries = parse_receipt_entries(
-            receipt, allow_legacy_ownership_for_remove=remove
-        )
-        require(
-            [entry.path for entry in sorted(live_entries, key=lambda item: (item.path != ".", item.path))]
-            == [entry["path"] for entry in receipt_entries],
-            "deployment receipt carrier closure differs",
-        )
-        live_by_path = {entry.path: entry for entry in live_entries}
-        for entry in receipt_entries:
-            live = live_by_path[entry["path"]]
-            info = live.info
-            actual_digest = live.actual_sha256
-            require(
-                (info.st_dev, info.st_ino, info.st_size)
-                == (entry["device"], entry["inode"], entry["size"]),
-                f"deployment inode identity differs: {entry['path']}",
-            )
-            require(stat.S_IMODE(info.st_mode) == int(entry["mode"], 8), f"deployment entry mode differs: {entry['path']}")
-            if "uid" in entry:
-                require(
-                    (info.st_uid, info.st_gid) == (entry["uid"], entry["gid"]),
-                    f"deployment entry ownership differs: {entry['path']}",
-                )
-            else:
-                require(
-                    remove,
-                    f"deployment entry ownership is not receipt-bound: {entry['path']}",
-                )
-            require(live.entry_type == entry["entry-type"], f"deployment entry type differs: {entry['path']}")
-            require(live.direct_loader_kind == entry["direct-loader-kind"], f"deployment direct-loader kind differs: {entry['path']}")
-            require(actual_digest == entry["sha256"], f"deployment entry content differs: {entry['path']}")
-            pre_flags = int(entry["pre-flags"], 16)
-            post_flags = int(entry["post-flags"], 16)
-            current = ops.get_flags(live.descriptor)
-            if remove:
-                require(current in (pre_flags, post_flags), f"deployment inode flags differ from receipt: {entry['path']}")
-            else:
-                require(current == post_flags and current & FS_IMMUTABLE_FL, f"deployment inode is not immutable: {entry['path']}")
-            live.expected_sha256 = entry["sha256"]
-            live.pre_flags = pre_flags
-            live.post_flags = post_flags
-        # Ownership of every live descriptor moves to opened for one close path.
-        opened = live_entries
-        live_entries = []
-        if not remove:
-            return receipt
-        try:
-            transition_flags(
-                reversed(transition_order(opened)),
-                ops,
-                lambda item: item.pre_flags,
-            )
-        except BaseException:
-            # Preserve an active, receipt-verifiable deployment if removal fails.
-            transition_flags(
-                transition_order(opened),
-                ops,
-                lambda item: item.post_flags,
-            )
-            raise
-        unlink_exact_receipt(
-            receipt_path,
-            receipt_info.st_dev,
-            receipt_info.st_ino,
-            receipt_sha,
-            ops,
-        )
-        return receipt
-    finally:
-        close_all(opened)
-        close_all(live_entries)
-        os.close(root_fd)
-
-
-def expected_identity_from_args(arguments: argparse.Namespace) -> dict[str, str]:
-    require(
-        all(
-            value is not None
-            for value in (
-                arguments.manifest_sha256,
-                arguments.wasmer_build_receipt_sha256,
-                arguments.payload_inventory_sha256,
-                arguments.headless_sha256,
-            )
-        ),
-        "full immutable deployment operations require all carrier identity hashes",
-    )
-    return {
-        "manifest.json": arguments.manifest_sha256,
-        "wasmer-build.receipt": arguments.wasmer_build_receipt_sha256,
-        "payload.files": arguments.payload_inventory_sha256,
-        "bin/wasmer-headless": arguments.headless_sha256,
-    }
-
-
-def parse_arguments(argv: list[str]) -> argparse.Namespace:
-    parser = argparse.ArgumentParser(description=__doc__)
-    action = parser.add_mutually_exclusive_group(required=True)
-    action.add_argument("--deploy", action="store_true")
-    action.add_argument("--verify", action="store_true")
-    action.add_argument("--verify-fast", action="store_true")
-    action.add_argument("--remove", action="store_true")
-    parser.add_argument("--carrier", type=Path, required=True)
-    parser.add_argument("--receipt", type=Path, required=True)
-    parser.add_argument("--manifest-sha256")
-    parser.add_argument("--wasmer-build-receipt-sha256")
-    parser.add_argument("--payload-inventory-sha256")
-    parser.add_argument("--headless-sha256")
-    return parser.parse_args(argv)
-
-
-def main(argv: list[str]) -> int:
-    try:
-        arguments = parse_arguments(argv)
-        ops = KernelOps()
-        if arguments.verify_fast:
-            optional_identity = (
-                arguments.manifest_sha256,
-                arguments.wasmer_build_receipt_sha256,
-                arguments.payload_inventory_sha256,
-                arguments.headless_sha256,
-            )
-            require(
-                all(value is None for value in optional_identity)
-                or all(value is not None for value in optional_identity),
-                "fast immutable verification identity hashes must be all present or all absent",
-            )
-            expected = (
-                None
-                if all(value is None for value in optional_identity)
-                else expected_identity_from_args(arguments)
-            )
-            verify_fast(
-                arguments.carrier,
-                arguments.receipt,
-                ops,
-                expected_identity=expected,
-            )
-            print(f"fast-verified immutable sealed carrier closure: {arguments.carrier}")
-            return 0
-        expected = expected_identity_from_args(arguments)
-        if arguments.deploy:
-            deploy(arguments.carrier, arguments.receipt, expected, ops)
-            print(f"deployed immutable sealed carrier closure: {arguments.carrier}")
-        elif arguments.verify:
-            verify_or_remove(
-                arguments.carrier,
-                arguments.receipt,
-                expected,
-                ops,
-                remove=False,
-            )
-            print(f"verified immutable sealed carrier closure: {arguments.carrier}")
-        else:
-            verify_or_remove(
-                arguments.carrier,
-                arguments.receipt,
-                expected,
-                ops,
-                remove=True,
-            )
-            print(f"removed immutable sealed carrier closure deployment: {arguments.carrier}")
-        return 0
-    except (DeploymentError, OSError) as error:
-        print(f"immutable carrier deployment failed: {error}", file=sys.stderr)
-        return 2
-
-
-if __name__ == "__main__":
-    raise SystemExit(main(sys.argv[1:]))
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/immutable-carrier.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/immutable-carrier.test.py
deleted file mode 100644
index 3800a212b..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/immutable-carrier.test.py
+++ /dev/null
@@ -1,360 +0,0 @@
-#!/usr/bin/env python3
-
-from __future__ import annotations
-
-import hashlib
-import importlib.util
-import json
-import os
-import stat
-import sys
-import tempfile
-import unittest
-from pathlib import Path
-from unittest import mock
-
-
-SCRIPT = Path(__file__).with_name("immutable-carrier.py")
-SPEC = importlib.util.spec_from_file_location("immutable_carrier", SCRIPT)
-assert SPEC is not None and SPEC.loader is not None
-MODULE = importlib.util.module_from_spec(SPEC)
-sys.modules[SPEC.name] = MODULE
-SPEC.loader.exec_module(MODULE)
-
-
-def digest(data: bytes) -> str:
-    return hashlib.sha256(data).hexdigest()
-
-
-class FakeOps:
-    def __init__(self, *, fail_set_number: int | None = None) -> None:
-        self.flags: dict[tuple[int, int], int] = {}
-        self.set_count = 0
-        self.fail_set_number = fail_set_number
-
-    @staticmethod
-    def key(descriptor: int) -> tuple[int, int]:
-        info = os.fstat(descriptor)
-        return info.st_dev, info.st_ino
-
-    def filesystem_magic(self, descriptor: int) -> int:
-        del descriptor
-        return MODULE.EXT_SUPER_MAGIC
-
-    def get_flags(self, descriptor: int) -> int:
-        return self.flags.setdefault(self.key(descriptor), 0x00080000)
-
-    def set_flags(self, descriptor: int, flags: int) -> None:
-        self.set_count += 1
-        if self.fail_set_number == self.set_count:
-            raise OSError("injected flag transition failure")
-        self.flags[self.key(descriptor)] = flags
-
-
-def make_carrier(parent: Path) -> tuple[Path, dict[str, str]]:
-    root = parent / "carrier"
-    for directory in ("aot", "bin"):
-        (root / directory).mkdir(parents=True, exist_ok=True)
-    artifacts = []
-    for index in range(MODULE.EXPECTED_AOT_COUNT):
-        module_digest = f"{index + 1:064X}"
-        artifact_path = f"aot/{module_digest}.bin"
-        artifact_data = f"artifact-{index}\n".encode()
-        (root / artifact_path).write_bytes(artifact_data)
-        artifact: dict[str, object] = {
-            "path": artifact_path,
-            "sha256": digest(artifact_data),
-        }
-        artifacts.append(artifact)
-    manifest_data = (
-        json.dumps(
-            {
-                "artifacts": artifacts,
-                "core-profile": "release-o3",
-                "format-version": 6,
-                "guest-build-recipe-sha256": "9" * 64,
-                "schema": MODULE.MANIFEST_SCHEMA,
-            },
-            separators=(",", ":"),
-            sort_keys=True,
-        )
-        + "\n"
-    ).encode()
-    identity_data: dict[str, bytes] = {
-        "manifest.json": manifest_data,
-        "wasmer-build.receipt": b"schema=fake\n",
-        "bin/wasmer-headless": b"fake-headless\n",
-    }
-    for relative, data in identity_data.items():
-        path = root / relative
-        path.parent.mkdir(parents=True, exist_ok=True)
-        path.write_bytes(data)
-    inventory_lines = [f"schema={MODULE.PAYLOAD_SCHEMA}"]
-    for path in sorted(candidate for candidate in root.rglob("*") if candidate.is_file()):
-        relative = path.relative_to(root).as_posix()
-        data = path.read_bytes()
-        inventory_lines.append(f"{digest(data)}\t{len(data)}\t{relative}")
-    payload_data = ("\n".join(inventory_lines) + "\n").encode()
-    (root / "payload.files").write_bytes(payload_data)
-    identity_data["payload.files"] = payload_data
-    for path in root.rglob("*"):
-        if path.is_file():
-            path.chmod(0o444)
-    for path in sorted((path for path in root.rglob("*") if path.is_dir()), reverse=True):
-        path.chmod(0o555)
-    root.chmod(0o555)
-    expected = {relative: digest(data) for relative, data in identity_data.items()}
-    return root.resolve(), expected
-
-
-class ImmutableCarrierPlatformTests(unittest.TestCase):
-    def test_non_linux_platform_is_rejected(self) -> None:
-        with mock.patch.object(sys, "platform", "darwin"):
-            with self.assertRaisesRegex(
-                MODULE.DeploymentError, "immutable deployment requires Linux"
-            ):
-                MODULE.require_linux()
-
-
-class ImmutableCarrierTests(unittest.TestCase):
-    def setUp(self) -> None:
-        if not sys.platform.startswith("linux"):
-            linux_guard = mock.patch.object(MODULE, "require_linux", return_value=None)
-            linux_guard.start()
-            self.addCleanup(linux_guard.stop)
-
-    def test_deploy_verify_and_exact_remove_round_trip(self) -> None:
-        with tempfile.TemporaryDirectory() as temporary:
-            parent = Path(temporary)
-            carrier, expected = make_carrier(parent)
-            receipt = (parent / "deployment.json").resolve()
-            ops = FakeOps()
-            result = MODULE.deploy(
-                carrier,
-                receipt,
-                expected,
-                ops,
-                check_capability=lambda: None,
-                receipt_owner_uid=os.geteuid(),
-            )
-            self.assertEqual(result["schema"], MODULE.SCHEMA)
-            self.assertEqual(result["core_profile"], "release-o3")
-            self.assertEqual(result["guest_build_recipe_sha256"], "9" * 64)
-            self.assertGreater(len(result["entries"]), 7)
-            self.assertEqual(
-                len(result["direct-loader-paths"]), MODULE.EXPECTED_AOT_COUNT
-            )
-            self.assertTrue(
-                all(
-                    entry["uid"] == os.geteuid() and entry["gid"] == os.getegid()
-                    for entry in result["entries"]
-                )
-            )
-            self.assertEqual(receipt.stat().st_mode & 0o777, 0o444)
-            self.assertEqual(receipt.read_bytes(), MODULE.canonical_json(result))
-            for entry in result["entries"]:
-                key = (entry["device"], entry["inode"])
-                self.assertTrue(ops.flags[key] & MODULE.FS_IMMUTABLE_FL)
-
-            verified = MODULE.verify_or_remove(
-                carrier,
-                receipt,
-                expected,
-                ops,
-                remove=False,
-                receipt_owner_uid=os.geteuid(),
-            )
-            self.assertEqual(verified, result)
-            with mock.patch.object(
-                MODULE,
-                "open_exact_carrier_closure",
-                side_effect=AssertionError("fast verification read the payload closure"),
-            ):
-                fast_verified = MODULE.verify_fast(
-                    carrier,
-                    receipt,
-                    ops,
-                    receipt_owner_uid=os.geteuid(),
-                )
-            self.assertEqual(fast_verified, result)
-            MODULE.verify_or_remove(
-                carrier,
-                receipt,
-                expected,
-                ops,
-                remove=True,
-                check_capability=lambda: None,
-                receipt_owner_uid=os.geteuid(),
-            )
-            self.assertFalse(receipt.exists())
-            for entry in result["entries"]:
-                key = (entry["device"], entry["inode"])
-                self.assertEqual(ops.flags[key], int(entry["pre-flags"], 16))
-
-    def test_fast_verification_rejects_ownership_drift(self) -> None:
-        with tempfile.TemporaryDirectory() as temporary:
-            parent = Path(temporary)
-            carrier, expected = make_carrier(parent)
-            receipt = (parent / "deployment.json").resolve()
-            ops = FakeOps()
-            result = MODULE.deploy(
-                carrier,
-                receipt,
-                expected,
-                ops,
-                check_capability=lambda: None,
-                receipt_owner_uid=os.geteuid(),
-            )
-            result["entries"][0]["uid"] += 1
-            receipt.chmod(0o644)
-            receipt.write_bytes(MODULE.canonical_json(result))
-            receipt.chmod(0o444)
-            with self.assertRaisesRegex(
-                MODULE.DeploymentError, "entry ownership differs"
-            ):
-                MODULE.verify_fast(
-                    carrier,
-                    receipt,
-                    ops,
-                    receipt_owner_uid=os.geteuid(),
-                )
-
-    def test_remove_accepts_pre_ownership_binding_recovery_receipt(self) -> None:
-        with tempfile.TemporaryDirectory() as temporary:
-            parent = Path(temporary)
-            carrier, expected = make_carrier(parent)
-            receipt = (parent / "deployment.json").resolve()
-            ops = FakeOps()
-            result = MODULE.deploy(
-                carrier,
-                receipt,
-                expected,
-                ops,
-                check_capability=lambda: None,
-                receipt_owner_uid=os.geteuid(),
-            )
-            for entry in result["entries"]:
-                del entry["uid"]
-                del entry["gid"]
-            receipt.chmod(0o644)
-            receipt.write_bytes(MODULE.canonical_json(result))
-            receipt.chmod(0o444)
-            MODULE.verify_or_remove(
-                carrier,
-                receipt,
-                expected,
-                ops,
-                remove=True,
-                check_capability=lambda: None,
-                receipt_owner_uid=os.geteuid(),
-            )
-            self.assertFalse(receipt.exists())
-
-    def test_failed_deployment_rolls_back_and_removes_journal(self) -> None:
-        with tempfile.TemporaryDirectory() as temporary:
-            parent = Path(temporary)
-            carrier, expected = make_carrier(parent)
-            receipt = (parent / "deployment.json").resolve()
-            ops = FakeOps(fail_set_number=4)
-            with self.assertRaises(MODULE.DeploymentError):
-                MODULE.deploy(
-                    carrier,
-                    receipt,
-                    expected,
-                    ops,
-                    check_capability=lambda: None,
-                    receipt_owner_uid=os.geteuid(),
-                )
-            self.assertFalse(receipt.exists())
-            self.assertTrue(ops.flags)
-            self.assertEqual(set(ops.flags.values()), {0x00080000})
-
-    def test_remove_repairs_receipt_bound_partial_transition(self) -> None:
-        with tempfile.TemporaryDirectory() as temporary:
-            parent = Path(temporary)
-            carrier, expected = make_carrier(parent)
-            receipt = (parent / "deployment.json").resolve()
-            ops = FakeOps()
-            result = MODULE.deploy(
-                carrier,
-                receipt,
-                expected,
-                ops,
-                check_capability=lambda: None,
-                receipt_owner_uid=os.geteuid(),
-            )
-            first = result["entries"][0]
-            ops.flags[(first["device"], first["inode"])] = int(first["pre-flags"], 16)
-            receipt_info = receipt.stat()
-            receipt_key = (receipt_info.st_dev, receipt_info.st_ino)
-            ops.flags[receipt_key] &= ~MODULE.FS_IMMUTABLE_FL
-            MODULE.verify_or_remove(
-                carrier,
-                receipt,
-                expected,
-                ops,
-                remove=True,
-                check_capability=lambda: None,
-                receipt_owner_uid=os.geteuid(),
-            )
-            self.assertFalse(receipt.exists())
-            self.assertEqual(set(ops.flags.values()), {0x00080000})
-
-    def test_replaced_inode_is_rejected_even_with_identical_bytes(self) -> None:
-        with tempfile.TemporaryDirectory() as temporary:
-            parent = Path(temporary)
-            carrier, expected = make_carrier(parent)
-            receipt = (parent / "deployment.json").resolve()
-            ops = FakeOps()
-            result = MODULE.deploy(
-                carrier,
-                receipt,
-                expected,
-                ops,
-                check_capability=lambda: None,
-                receipt_owner_uid=os.geteuid(),
-            )
-            entry = next(
-                candidate
-                for candidate in result["entries"]
-                if candidate["entry-type"] == "file"
-            )
-            path = carrier / entry["path"]
-            data = path.read_bytes()
-            path.parent.chmod(0o755)
-            replacement = path.with_name(path.name + ".replacement")
-            replacement.write_bytes(data)
-            os.replace(replacement, path)
-            path.chmod(0o444)
-            path.parent.chmod(0o555)
-            with self.assertRaisesRegex(MODULE.DeploymentError, "inode identity differs"):
-                MODULE.verify_or_remove(
-                    carrier,
-                    receipt,
-                    expected,
-                    ops,
-                    remove=False,
-                    receipt_owner_uid=os.geteuid(),
-                )
-
-    def test_root_and_effective_capability_are_both_required(self) -> None:
-        with mock.patch.object(os, "geteuid", return_value=1000):
-            with self.assertRaisesRegex(MODULE.DeploymentError, "effective UID 0"):
-                MODULE.require_root_immutable_capability()
-        with mock.patch.object(os, "geteuid", return_value=0), mock.patch.object(
-            MODULE, "effective_capabilities", return_value=0
-        ):
-            with self.assertRaisesRegex(MODULE.DeploymentError, "CAP_LINUX_IMMUTABLE"):
-                MODULE.require_root_immutable_capability()
-
-    @unittest.skipUnless(sys.platform.startswith("linux"), "Linux ioctl contract")
-    def test_real_filesystem_flag_query_is_read_only(self) -> None:
-        with tempfile.NamedTemporaryFile() as candidate:
-            ops = MODULE.KernelOps()
-            self.assertEqual(ops.filesystem_magic(candidate.fileno()), MODULE.EXT_SUPER_MAGIC)
-            flags = ops.get_flags(candidate.fileno())
-            self.assertIsInstance(flags, int)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/linear_memory_transaction.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/linear_memory_transaction.py
deleted file mode 100644
index 09f2bebbe..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/linear_memory_transaction.py
+++ /dev/null
@@ -1,453 +0,0 @@
-#!/usr/bin/env python3
-
-"""Crash-recoverable publication for the installed WASIX memory ABI seal.
-
-The transaction keeps durable copies of every predecessor before replacing a
-live module.  The aggregate receipt is linked into place only after every
-module replacement and containing directory have reached stable storage.  A
-restart either recognizes that receipt as a complete commit or restores every
-predecessor from the still-durable copies.
-"""
-
-from __future__ import annotations
-
-import argparse
-import hashlib
-import json
-import os
-from pathlib import Path, PurePosixPath
-import shutil
-import stat
-import tempfile
-from typing import Any
-
-
-SCHEMA = "oliphaunt.wasix-postmaster.linear-memory-transaction.v1"
-AGGREGATE_SCHEMA = "oliphaunt.wasix-postmaster.linear-memory-install.v1"
-AGGREGATE_RELATIVE = (
-    "share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
-)
-STATE_NAME = "transaction.json"
-SHA256_LENGTH = 64
-
-
-class TransactionError(ValueError):
-    pass
-
-
-def require(condition: bool, message: str) -> None:
-    if not condition:
-        raise TransactionError(message)
-
-
-def digest_path(path: Path) -> str:
-    descriptor = os.open(
-        path,
-        os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0),
-    )
-    try:
-        info = os.fstat(descriptor)
-        require(stat.S_ISREG(info.st_mode), f"transaction input is not regular: {path}")
-        digest = hashlib.sha256()
-        while chunk := os.read(descriptor, 1024 * 1024):
-            digest.update(chunk)
-        after = os.fstat(descriptor)
-        require(
-            (info.st_dev, info.st_ino, info.st_size, info.st_mtime_ns, info.st_ctime_ns)
-            == (
-                after.st_dev,
-                after.st_ino,
-                after.st_size,
-                after.st_mtime_ns,
-                after.st_ctime_ns,
-            ),
-            f"transaction input changed while hashing: {path}",
-        )
-        return digest.hexdigest()
-    finally:
-        os.close(descriptor)
-
-
-def safe_relative(value: Any) -> str:
-    require(isinstance(value, str) and value, "transaction module path is empty")
-    pure = PurePosixPath(value)
-    require(
-        not pure.is_absolute()
-        and all(part not in ("", ".", "..") for part in pure.parts)
-        and not any(character in value for character in ("\0", "\n", "\r", "\t")),
-        f"unsafe transaction module path: {value!r}",
-    )
-    return value
-
-
-def resolve(root: Path, relative: str) -> Path:
-    return root.joinpath(*PurePosixPath(safe_relative(relative)).parts)
-
-
-def fsync_file(path: Path) -> None:
-    descriptor = os.open(
-        path,
-        os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0),
-    )
-    try:
-        require(stat.S_ISREG(os.fstat(descriptor).st_mode), f"not a regular file: {path}")
-        os.fsync(descriptor)
-    finally:
-        os.close(descriptor)
-
-
-def fsync_directory(path: Path) -> None:
-    descriptor = os.open(
-        path,
-        os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_DIRECTORY", 0),
-    )
-    try:
-        os.fsync(descriptor)
-    finally:
-        os.close(descriptor)
-
-
-def fsync_tree(root: Path) -> None:
-    directories: list[Path] = []
-    for current, names, files in os.walk(root, topdown=True, followlinks=False):
-        names.sort()
-        files.sort()
-        current_path = Path(current)
-        directories.append(current_path)
-        for name in files:
-            path = current_path / name
-            info = os.lstat(path)
-            require(stat.S_ISREG(info.st_mode), f"transaction stage contains a special file: {path}")
-            fsync_file(path)
-    for directory in reversed(directories):
-        fsync_directory(directory)
-
-
-def exact_json(path: Path, label: str) -> dict[str, Any]:
-    descriptor = os.open(
-        path,
-        os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0),
-    )
-    try:
-        info = os.fstat(descriptor)
-        require(stat.S_ISREG(info.st_mode), f"{label} is not regular")
-        require(info.st_size <= 16 * 1024 * 1024, f"{label} is unexpectedly large")
-        data = bytearray()
-        while len(data) <= info.st_size:
-            chunk = os.read(descriptor, min(1024 * 1024, info.st_size + 1 - len(data)))
-            if not chunk:
-                break
-            data.extend(chunk)
-        require(len(data) == info.st_size, f"{label} changed while reading")
-        after = os.fstat(descriptor)
-        require(
-            (info.st_dev, info.st_ino, info.st_size, info.st_mtime_ns, info.st_ctime_ns)
-            == (
-                after.st_dev,
-                after.st_ino,
-                after.st_size,
-                after.st_mtime_ns,
-                after.st_ctime_ns,
-            ),
-            f"{label} changed while reading",
-        )
-    finally:
-        os.close(descriptor)
-    try:
-        value = json.loads(bytes(data), object_pairs_hook=reject_duplicates)
-    except (UnicodeDecodeError, json.JSONDecodeError) as error:
-        raise TransactionError(f"invalid {label}: {error}") from error
-    require(isinstance(value, dict), f"{label} must be an object")
-    return value
-
-
-def reject_duplicates(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
-    value: dict[str, Any] = {}
-    for key, item in pairs:
-        require(key not in value, f"duplicate transaction JSON field: {key}")
-        value[key] = item
-    return value
-
-
-def atomic_json(path: Path, value: dict[str, Any], *, exclusive: bool = False) -> None:
-    path.parent.mkdir(parents=True, exist_ok=True)
-    descriptor, temporary_name = tempfile.mkstemp(
-        prefix=f".{path.name}.tmp.", dir=path.parent
-    )
-    temporary = Path(temporary_name)
-    try:
-        with os.fdopen(descriptor, "w", encoding="utf-8", newline="\n") as stream:
-            json.dump(value, stream, indent=2, sort_keys=True)
-            stream.write("\n")
-            stream.flush()
-            os.fsync(stream.fileno())
-        if exclusive:
-            os.link(temporary, path, follow_symlinks=False)
-            temporary.unlink()
-        else:
-            os.replace(temporary, path)
-        fsync_directory(path.parent)
-    finally:
-        if temporary.exists():
-            temporary.unlink()
-
-
-def remove_stage(stage: Path, install: Path) -> None:
-    if stage.exists():
-        require(stage.is_dir() and not stage.is_symlink(), "transaction stage is not a directory")
-        shutil.rmtree(stage)
-        fsync_directory(install)
-
-
-def state_path(stage: Path) -> Path:
-    return stage / STATE_NAME
-
-
-def initial_state() -> dict[str, Any]:
-    return {"phase": "staging", "schema": SCHEMA}
-
-
-def load_state(stage: Path) -> dict[str, Any] | None:
-    path = state_path(stage)
-    if not path.exists():
-        return None
-    state = exact_json(path, "linear-memory transaction state")
-    require(state.get("schema") == SCHEMA, "linear-memory transaction schema differs")
-    return state
-
-
-def parse_aggregate(path: Path) -> tuple[dict[str, Any], list[dict[str, str]]]:
-    aggregate = exact_json(path, "linear-memory aggregate receipt")
-    require(aggregate.get("schema") == AGGREGATE_SCHEMA, "linear-memory aggregate schema differs")
-    modules = aggregate.get("modules")
-    require(isinstance(modules, list) and modules, "linear-memory aggregate has no modules")
-    records: list[dict[str, str]] = []
-    seen: set[str] = set()
-    for module in modules:
-        require(isinstance(module, dict), "linear-memory aggregate module is not an object")
-        relative = safe_relative(module.get("path"))
-        source = module.get("source-module-sha256")
-        sealed = module.get("module-sha256")
-        require(
-            isinstance(source, str)
-            and len(source) == SHA256_LENGTH
-            and all(character in "0123456789abcdef" for character in source)
-            and isinstance(sealed, str)
-            and len(sealed) == SHA256_LENGTH
-            and all(character in "0123456789abcdef" for character in sealed),
-            f"linear-memory aggregate module digest differs: {relative}",
-        )
-        require(relative not in seen, f"duplicate linear-memory aggregate path: {relative}")
-        seen.add(relative)
-        records.append({"path": relative, "sealed-sha256": sealed, "source-sha256": source})
-    require(
-        [record["path"] for record in records]
-        == sorted(record["path"] for record in records),
-        "linear-memory aggregate modules are not sorted",
-    )
-    require(aggregate.get("module-count") == len(records), "linear-memory aggregate count differs")
-    return aggregate, records
-
-
-def validate_prepared_state(state: dict[str, Any]) -> tuple[str, str, list[dict[str, str]]]:
-    require(
-        set(state) == {"aggregate-path", "aggregate-sha256", "modules", "phase", "schema"},
-        "prepared linear-memory transaction fields differ",
-    )
-    require(state["phase"] == "prepared", "linear-memory transaction is not prepared")
-    aggregate_relative = safe_relative(state["aggregate-path"])
-    require(aggregate_relative == AGGREGATE_RELATIVE, "transaction aggregate path differs")
-    aggregate_sha = state["aggregate-sha256"]
-    require(
-        isinstance(aggregate_sha, str)
-        and len(aggregate_sha) == SHA256_LENGTH
-        and all(character in "0123456789abcdef" for character in aggregate_sha),
-        "transaction aggregate digest differs",
-    )
-    modules = state["modules"]
-    require(isinstance(modules, list) and modules, "prepared transaction has no modules")
-    expected_keys = {"path", "sealed-sha256", "source-sha256"}
-    for module in modules:
-        require(isinstance(module, dict) and set(module) == expected_keys, "transaction module fields differ")
-        safe_relative(module["path"])
-    require(
-        [module["path"] for module in modules] == sorted(module["path"] for module in modules),
-        "transaction modules are not sorted",
-    )
-    return aggregate_relative, aggregate_sha, modules
-
-
-def copy_durable(source: Path, destination: Path) -> None:
-    info = os.lstat(source)
-    require(stat.S_ISREG(info.st_mode) and not stat.S_ISLNK(info.st_mode), f"source is not regular: {source}")
-    destination.parent.mkdir(parents=True, exist_ok=True)
-    descriptor, temporary_name = tempfile.mkstemp(
-        prefix=f".{destination.name}.copy.", dir=destination.parent
-    )
-    temporary = Path(temporary_name)
-    try:
-        with source.open("rb", buffering=0) as input_stream, os.fdopen(
-            descriptor, "wb", buffering=0
-        ) as output_stream:
-            shutil.copyfileobj(input_stream, output_stream, 1024 * 1024)
-            os.fchmod(output_stream.fileno(), stat.S_IMODE(info.st_mode))
-            os.fsync(output_stream.fileno())
-        os.utime(temporary, ns=(info.st_atime_ns, info.st_mtime_ns), follow_symlinks=False)
-        os.replace(temporary, destination)
-        fsync_directory(destination.parent)
-    finally:
-        if temporary.exists():
-            temporary.unlink()
-
-
-def init_transaction(install: Path, stage: Path) -> None:
-    require(not stage.exists() and not stage.is_symlink(), f"transaction stage already exists: {stage}")
-    stage.mkdir(mode=0o700)
-    (stage / "modules").mkdir()
-    (stage / "receipts").mkdir()
-    atomic_json(state_path(stage), initial_state(), exclusive=True)
-    fsync_tree(stage)
-    fsync_directory(install)
-
-
-def prepare_transaction(install: Path, stage: Path, aggregate_path: Path) -> None:
-    state = load_state(stage)
-    require(state == initial_state(), "transaction stage is not in its initial state")
-    _, records = parse_aggregate(aggregate_path)
-    originals = stage / "originals"
-    originals.mkdir()
-    for record in records:
-        relative = record["path"]
-        live = resolve(install, relative)
-        staged = resolve(stage / "modules", relative)
-        require(digest_path(live) == record["source-sha256"], f"live predecessor differs: {relative}")
-        require(digest_path(staged) == record["sealed-sha256"], f"staged sealed module differs: {relative}")
-        backup = resolve(originals, relative)
-        copy_durable(live, backup)
-        require(digest_path(backup) == record["source-sha256"], f"durable backup differs: {relative}")
-    fsync_tree(stage)
-    prepared = {
-        "aggregate-path": AGGREGATE_RELATIVE,
-        "aggregate-sha256": digest_path(aggregate_path),
-        "modules": records,
-        "phase": "prepared",
-        "schema": SCHEMA,
-    }
-    atomic_json(state_path(stage), prepared)
-    fsync_tree(stage)
-    fsync_directory(install)
-
-
-def committed(install: Path, aggregate_relative: str, aggregate_sha: str, modules: list[dict[str, str]]) -> bool:
-    destination = resolve(install, aggregate_relative)
-    try:
-        if digest_path(destination) != aggregate_sha:
-            return False
-        return all(
-            digest_path(resolve(install, module["path"])) == module["sealed-sha256"]
-            for module in modules
-        )
-    except (FileNotFoundError, OSError, TransactionError):
-        return False
-
-
-def restore_prepared(install: Path, stage: Path, state: dict[str, Any]) -> str:
-    aggregate_relative, aggregate_sha, modules = validate_prepared_state(state)
-    if committed(install, aggregate_relative, aggregate_sha, modules):
-        remove_stage(stage, install)
-        return "committed"
-    destination = resolve(install, aggregate_relative)
-    if destination.exists() or destination.is_symlink():
-        info = os.lstat(destination)
-        require(stat.S_ISREG(info.st_mode), "incomplete transaction aggregate is not regular")
-        destination.unlink()
-        fsync_directory(destination.parent)
-    for module in modules:
-        relative = module["path"]
-        backup = resolve(stage / "originals", relative)
-        require(digest_path(backup) == module["source-sha256"], f"transaction backup differs: {relative}")
-        live = resolve(install, relative)
-        if digest_path(live) != module["source-sha256"]:
-            copy_durable(backup, live)
-    for module in modules:
-        require(
-            digest_path(resolve(install, module["path"])) == module["source-sha256"],
-            f"transaction rollback verification failed: {module['path']}",
-        )
-    remove_stage(stage, install)
-    return "rolled-back"
-
-
-def recover_transaction(install: Path, stage: Path) -> str:
-    if not stage.exists() and not stage.is_symlink():
-        return "none"
-    require(stage.is_dir() and not stage.is_symlink(), "linear-memory transaction stage is unsafe")
-    state = load_state(stage)
-    if state is None or state == initial_state():
-        # The protocol performs no live mutation until the prepared state is
-        # durable, so an interrupted construction stage is safe to discard.
-        remove_stage(stage, install)
-        return "discarded-staging"
-    return restore_prepared(install, stage, state)
-
-
-def publish_transaction(install: Path, stage: Path) -> None:
-    state = load_state(stage)
-    require(state is not None, "linear-memory transaction state is missing")
-    aggregate_relative, aggregate_sha, modules = validate_prepared_state(state)
-    aggregate_source = stage / "wasix-postmaster.linear-memory-profile.receipt.json"
-    require(digest_path(aggregate_source) == aggregate_sha, "staged aggregate receipt differs")
-    aggregate_destination = resolve(install, aggregate_relative)
-    require(
-        not aggregate_destination.exists() and not aggregate_destination.is_symlink(),
-        f"aggregate receipt destination already exists: {aggregate_destination}",
-    )
-    for module in modules:
-        relative = module["path"]
-        live = resolve(install, relative)
-        staged = resolve(stage / "modules", relative)
-        require(digest_path(live) == module["source-sha256"], f"live module changed before publication: {relative}")
-        require(digest_path(staged) == module["sealed-sha256"], f"staged module changed before publication: {relative}")
-        os.replace(staged, live)
-        fsync_directory(live.parent)
-        require(digest_path(live) == module["sealed-sha256"], f"published module differs: {relative}")
-    require(
-        all(digest_path(resolve(install, module["path"])) == module["sealed-sha256"] for module in modules),
-        "published linear-memory closure differs before receipt commit",
-    )
-    # Hard-link publication is atomic and fails rather than replacing a
-    # concurrently created receipt.  The staged inode remains available to
-    # recovery until the parent directory has also been flushed.
-    os.link(aggregate_source, aggregate_destination, follow_symlinks=False)
-    fsync_directory(aggregate_destination.parent)
-    require(committed(install, aggregate_relative, aggregate_sha, modules), "committed transaction verification failed")
-    remove_stage(stage, install)
-
-
-def main() -> int:
-    parser = argparse.ArgumentParser()
-    parser.add_argument("command", choices=("init", "prepare", "publish", "recover"))
-    parser.add_argument("--install-root", type=Path, required=True)
-    parser.add_argument("--stage", type=Path, required=True)
-    parser.add_argument("--aggregate", type=Path)
-    arguments = parser.parse_args()
-    install = arguments.install_root.resolve(strict=True)
-    stage = arguments.stage
-    require(stage.parent.resolve(strict=True) == install, "transaction stage is not directly below install root")
-    if arguments.command == "init":
-        init_transaction(install, stage)
-    elif arguments.command == "prepare":
-        require(arguments.aggregate is not None, "prepare requires --aggregate")
-        prepare_transaction(install, stage, arguments.aggregate)
-    elif arguments.command == "publish":
-        publish_transaction(install, stage)
-    else:
-        print(recover_transaction(install, stage))
-    return 0
-
-
-if __name__ == "__main__":
-    try:
-        raise SystemExit(main())
-    except (OSError, TransactionError) as error:
-        raise SystemExit(f"linear-memory transaction: {error}") from error
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/linear_memory_transaction.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/linear_memory_transaction.test.py
deleted file mode 100644
index 6b15391d4..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/linear_memory_transaction.test.py
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/usr/bin/env python3
-
-"""Crash-boundary tests for durable linear-memory publication."""
-
-from __future__ import annotations
-
-import hashlib
-import json
-import os
-from pathlib import Path
-import shutil
-import tempfile
-
-from linear_memory_transaction import (
-    AGGREGATE_RELATIVE,
-    init_transaction,
-    prepare_transaction,
-    publish_transaction,
-    recover_transaction,
-)
-
-
-def digest(data: bytes) -> str:
-    return hashlib.sha256(data).hexdigest()
-
-
-def write_fixture(root: Path, suffix: str) -> tuple[Path, Path, dict[str, bytes]]:
-    install = root / suffix / "install"
-    stage = install / ".oliphaunt-linear-memory.pending"
-    originals = {"bin/a.wasm": b"original-a", "lib/b.wasm": b"original-b"}
-    sealed = {"bin/a.wasm": b"sealed-a", "lib/b.wasm": b"sealed-b"}
-    for relative, data in originals.items():
-        path = install / relative
-        path.parent.mkdir(parents=True, exist_ok=True)
-        path.write_bytes(data)
-    (install / "share/postgresql").mkdir(parents=True)
-    init_transaction(install, stage)
-    modules = []
-    for relative in sorted(originals):
-        path = stage / "modules" / relative
-        path.parent.mkdir(parents=True, exist_ok=True)
-        path.write_bytes(sealed[relative])
-        modules.append(
-            {
-                "path": relative,
-                "source-module-sha256": digest(originals[relative]),
-                "module-sha256": digest(sealed[relative]),
-            }
-        )
-    aggregate = {
-        "schema": "oliphaunt.wasix-postmaster.linear-memory-install.v1",
-        "module-count": len(modules),
-        "modules": modules,
-    }
-    aggregate_path = stage / "wasix-postmaster.linear-memory-profile.receipt.json"
-    aggregate_path.write_text(
-        json.dumps(aggregate, indent=2, sort_keys=True) + "\n", encoding="utf-8"
-    )
-    prepare_transaction(install, stage, aggregate_path)
-    return install, stage, originals
-
-
-def assert_originals(install: Path, originals: dict[str, bytes]) -> None:
-    for relative, data in originals.items():
-        assert (install / relative).read_bytes() == data
-
-
-def main() -> int:
-    root = Path(tempfile.mkdtemp(prefix="linear-memory-transaction-test."))
-    try:
-        install, stage, originals = write_fixture(root, "interrupted-modules")
-        os.replace(stage / "modules/bin/a.wasm", install / "bin/a.wasm")
-        assert recover_transaction(install, stage) == "rolled-back"
-        assert_originals(install, originals)
-        assert not stage.exists()
-
-        install, stage, originals = write_fixture(root, "premature-receipt")
-        os.replace(stage / "modules/bin/a.wasm", install / "bin/a.wasm")
-        os.link(
-            stage / "wasix-postmaster.linear-memory-profile.receipt.json",
-            install / AGGREGATE_RELATIVE,
-        )
-        assert recover_transaction(install, stage) == "rolled-back"
-        assert_originals(install, originals)
-        assert not (install / AGGREGATE_RELATIVE).exists()
-
-        install, stage, _ = write_fixture(root, "commit")
-        publish_transaction(install, stage)
-        assert not stage.exists()
-        assert (install / AGGREGATE_RELATIVE).is_file()
-        assert recover_transaction(install, stage) == "none"
-
-        install = root / "abandoned-staging" / "install"
-        install.mkdir(parents=True)
-        stage = install / ".oliphaunt-linear-memory.pending"
-        init_transaction(install, stage)
-        (stage / "modules" / "partial").write_bytes(b"partial")
-        assert recover_transaction(install, stage) == "discarded-staging"
-        assert not stage.exists()
-    finally:
-        shutil.rmtree(root)
-    print("linear-memory transaction tests passed")
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/qualification-identities.sh b/src/runtimes/liboliphaunt/wasix-postmaster/lib/qualification-identities.sh
deleted file mode 100644
index 5fc6b3269..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/qualification-identities.sh
+++ /dev/null
@@ -1,141 +0,0 @@
-#!/usr/bin/env bash
-
-# Shared, fail-closed identity capture for qualification runners.  Callers must
-# source common.sh and sealed-carrier.sh first.
-
-fresh_capture_stable_regular_file_identity() {
-  local path="$1"
-  local identity
-
-  identity="$(python3 - "$path" <<'PY'
-import hashlib
-import os
-import stat
-import sys
-
-path = sys.argv[1]
-
-
-def identity(info: os.stat_result) -> tuple[int, ...]:
-    return (
-        info.st_dev,
-        info.st_ino,
-        info.st_mode,
-        info.st_uid,
-        info.st_gid,
-        info.st_size,
-        info.st_mtime_ns,
-        info.st_ctime_ns,
-    )
-
-
-before = os.lstat(path)
-if not stat.S_ISREG(before.st_mode) or stat.S_ISLNK(before.st_mode):
-    raise SystemExit("identity input must be a regular non-symlink file")
-descriptor = os.open(
-    path,
-    os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0),
-)
-try:
-    opened = os.fstat(descriptor)
-    if identity(before) != identity(opened):
-        raise SystemExit("identity input changed while opening")
-    digest = hashlib.sha256()
-    while True:
-        chunk = os.read(descriptor, 1024 * 1024)
-        if not chunk:
-            break
-        digest.update(chunk)
-    after = os.fstat(descriptor)
-    if identity(opened) != identity(after):
-        raise SystemExit("identity input changed while reading")
-    pathname_after = os.lstat(path)
-    if identity(after) != identity(pathname_after):
-        raise SystemExit("identity input pathname changed while reading")
-finally:
-    os.close(descriptor)
-
-print(digest.hexdigest(), opened.st_dev, opened.st_ino, sep="\t")
-PY
-  )" || return
-  IFS=$'\t' read -r FRESH_QUALIFICATION_REGULAR_FILE_SHA256 \
-    FRESH_QUALIFICATION_REGULAR_FILE_DEVICE \
-    FRESH_QUALIFICATION_REGULAR_FILE_INODE <<<"$identity"
-  [ "${#FRESH_QUALIFICATION_REGULAR_FILE_SHA256}" -eq 64 ] || return 2
-  case "$FRESH_QUALIFICATION_REGULAR_FILE_SHA256" in
-    *[!0-9a-f]*) return 2 ;;
-  esac
-  case "$FRESH_QUALIFICATION_REGULAR_FILE_DEVICE:$FRESH_QUALIFICATION_REGULAR_FILE_INODE" in
-    *[!0-9:]*) return 2 ;;
-    :*|*:|*:*:*) return 2 ;;
-  esac
-  export FRESH_QUALIFICATION_REGULAR_FILE_SHA256
-  export FRESH_QUALIFICATION_REGULAR_FILE_DEVICE
-  export FRESH_QUALIFICATION_REGULAR_FILE_INODE
-}
-fresh_capture_qualification_carrier_identity() {
-  local carrier="$1"
-  local manifest receipt payload headless identities provenance digest
-
-  manifest="$carrier/manifest.json"
-  receipt="$carrier/wasmer-build.receipt"
-  payload="$carrier/payload.files"
-  headless="$carrier/bin/wasmer-headless"
-  fresh_verify_sealed_headless_carrier "$carrier" || return
-  identities="$(
-    printf '%s\t%s\t%s\t%s\n' \
-      "$(fresh_wasmer_bin_hash "$manifest")" \
-      "$(fresh_wasmer_bin_hash "$receipt")" \
-      "$(fresh_wasmer_bin_hash "$payload")" \
-      "$(fresh_wasmer_bin_hash "$headless")"
-  )" || return
-  IFS=$'\t' read -r FRESH_QUALIFICATION_CARRIER_MANIFEST_SHA256 \
-    FRESH_QUALIFICATION_CARRIER_RECEIPT_SHA256 \
-    FRESH_QUALIFICATION_CARRIER_PAYLOAD_SHA256 \
-    FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256 <<<"$identities"
-  for digest in \
-    "$FRESH_QUALIFICATION_CARRIER_MANIFEST_SHA256" \
-    "$FRESH_QUALIFICATION_CARRIER_RECEIPT_SHA256" \
-    "$FRESH_QUALIFICATION_CARRIER_PAYLOAD_SHA256" \
-    "$FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256"
-  do
-    [ "${#digest}" -eq 64 ] || return 2
-    case "$digest" in
-      *[!0-9a-f]*) return 2 ;;
-    esac
-  done
-  provenance="$(python3 - "$manifest" <<'PY'
-import json
-import re
-import sys
-
-with open(sys.argv[1], encoding="utf-8") as stream:
-    manifest = json.load(stream)
-profile = manifest.get("core-profile")
-recipe = manifest.get("guest-build-recipe-sha256")
-if profile not in {"release-o3", "safe-o2"}:
-    raise SystemExit("sealed carrier core profile differs")
-if not isinstance(recipe, str) or re.fullmatch(r"[0-9a-f]{64}", recipe) is None:
-    raise SystemExit("sealed carrier guest build recipe differs")
-print(profile, recipe, sep="\t")
-PY
-  )" || return
-  IFS=$'\t' read -r FRESH_QUALIFICATION_CORE_PROFILE \
-    FRESH_QUALIFICATION_GUEST_BUILD_RECIPE_SHA256 <<<"$provenance"
-  FRESH_QUALIFICATION_CARRIER_CLOSURE_IDENTITY="$(
-    {
-      printf '%s\0' oliphaunt.wasix-postmaster.qualification-carrier.v1
-      printf '%s\0' "$FRESH_QUALIFICATION_CARRIER_MANIFEST_SHA256"
-      printf '%s\0' "$FRESH_QUALIFICATION_CARRIER_RECEIPT_SHA256"
-      printf '%s\0' "$FRESH_QUALIFICATION_CARRIER_PAYLOAD_SHA256"
-      printf '%s\0' "$FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256"
-    } | fresh_sha256_stream
-  )" || return
-  export FRESH_QUALIFICATION_CARRIER_CLOSURE_IDENTITY
-  export FRESH_QUALIFICATION_CARRIER_MANIFEST_SHA256
-  export FRESH_QUALIFICATION_CARRIER_RECEIPT_SHA256
-  export FRESH_QUALIFICATION_CARRIER_PAYLOAD_SHA256
-  export FRESH_QUALIFICATION_CARRIER_HEADLESS_SHA256
-  export FRESH_QUALIFICATION_CORE_PROFILE
-  export FRESH_QUALIFICATION_GUEST_BUILD_RECIPE_SHA256
-}
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/sealed_export_chain.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/sealed_export_chain.py
deleted file mode 100644
index fb78be533..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/sealed_export_chain.py
+++ /dev/null
@@ -1,547 +0,0 @@
-#!/usr/bin/env python3
-
-"""Strictly verify the sealed-export predecessor of the memory-ABI seal."""
-
-from __future__ import annotations
-
-import hashlib
-import json
-import os
-from pathlib import Path, PurePosixPath
-import re
-import stat
-from typing import Any, Mapping
-
-
-RECEIPT_RELATIVE = (
-    "share/postgresql/wasix-postmaster.sealed-export.structure.receipt"
-)
-SEED_PROOF_RELATIVE = (
-    "share/postgresql/wasix-postmaster.sealed-export.seed-proof.json"
-)
-FINAL_PROOF_RELATIVE = (
-    "share/postgresql/wasix-postmaster.sealed-export.final-proof.json"
-)
-ALLOWLIST_RELATIVE = (
-    "share/postgresql/wasix-postmaster.sealed-export.allowlist"
-)
-RECEIPT_SCHEMA = "oliphaunt.wasix-postmaster.sealed-export-structure.v1"
-PROOF_SCHEMA = "oliphaunt.wasix-postmaster.sealed-export-closure-proof.v2"
-POLICY_ID = "oliphaunt.wasix-postmaster.sealed-export-closure.v1"
-SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
-LINEAR_RECEIPT_RELATIVE = (
-    "share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json"
-)
-LINEAR_RECEIPT_SCHEMA = "oliphaunt.wasix-postmaster.linear-memory-install.v1"
-LINEAR_PROFILE_ID = (
-    "oliphaunt.wasix-postmaster.linear-memory."
-    "wasm32-max256m-u64-static4g-guard2g.v1"
-)
-MAX_UNINVENTORIED_INPUT_BYTES = 512 * 1024 * 1024
-
-RECEIPT_KEYS = {
-    "schema",
-    "policy-id",
-    "analyzer-version",
-    "analyzer-binary-sha256",
-    "dce-tool-sha256",
-    "dce-tool-version",
-    "dce-passes",
-    "mandatory-policy-sha256",
-    "declared-main-dlsym-policy-sha256",
-    "side-manifest-sha256",
-    "allowlist-sha256",
-    "seed-proof-sha256",
-    "final-proof-sha256",
-    "seed",
-    "final-module",
-    "sides",
-}
-SNAPSHOT_KEYS = {
-    "sha256",
-    "bytes",
-    "exports",
-    "local-functions",
-    "local-globals",
-    "element-function-entries",
-    "element-unique-function-indices",
-    "start-function-index",
-}
-SIDE_KEYS = {"path", "sha256"}
-PROOF_KEYS = {
-    "schema",
-    "policy-id",
-    "analyzer-version",
-    "mandatory-policy-sha256",
-    "declared-main-dlsym-policy-sha256",
-    "main",
-    "sides",
-    "mandatory-runtime-exports",
-    "declared-main-dlsym-exports",
-    "side-dynamic-imports",
-    "retained-main-exports",
-    "retained-main-export-descriptors",
-    "removed-main-export-count",
-    "removed-main-export-names-sha256",
-    "unresolved-main-requirements",
-    "mismatched-main-requirements",
-    "unresolved-side-dependencies",
-    "retained-counts",
-    "removed-counts",
-}
-MODULE_KEYS = {
-    "path",
-    "sha256",
-    "bytes",
-    "non-export-sections-sha256",
-    "dylink-needed",
-    "imported-functions",
-    "local-functions",
-    "imported-globals",
-    "local-globals",
-    "imported-tables",
-    "local-tables",
-    "element-function-entries",
-    "element-unique-function-indices",
-    "element-max-function-index",
-    "start-function-index",
-    "imports",
-    "export-counts",
-    "exported-global-type-counts",
-    "exported-immutable-i32-globals",
-    "exported-local-functions",
-    "exported-imported-functions",
-}
-LINEAR_RECEIPT_KEYS = {
-    "schema",
-    "profile-id",
-    "address-width",
-    "supported-host-pointer-width",
-    "maximum-pages",
-    "maximum-bytes",
-    "static-bound-pages",
-    "static-offset-guard-bytes",
-    "static-access-lowering",
-    "requires-shared",
-    "requires-import",
-    "excludes-wasm32-end-wrap",
-    "predecessor-export-closure-receipt",
-    "predecessor-export-closure-receipt-sha256",
-    "source-module-closure-sha256",
-    "module-closure-sha256",
-    "module-count",
-    "modules",
-}
-LINEAR_MODULE_KEYS = {
-    "path",
-    "source-module-sha256",
-    "module-sha256",
-    "initial-pages",
-    "maximum-pages",
-    "maximum-bytes",
-    "shared",
-    "import-module",
-    "import-name",
-    "transformation",
-}
-
-
-class ExportChainError(ValueError):
-    pass
-
-
-def require(condition: bool, message: str) -> None:
-    if not condition:
-        raise ExportChainError(message)
-
-
-def sha256(data: bytes) -> str:
-    return hashlib.sha256(data).hexdigest()
-
-
-def duplicate_rejecting_object(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
-    result: dict[str, Any] = {}
-    for key, value in pairs:
-        require(key not in result, f"duplicate sealed-export JSON field: {key}")
-        result[key] = value
-    return result
-
-
-def parse_json(data: bytes, label: str) -> dict[str, Any]:
-    try:
-        text = data.decode("utf-8")
-    except UnicodeDecodeError as error:
-        raise ExportChainError(f"{label} is not UTF-8: {error}") from error
-    require("\0" not in text and "\r" not in text, f"{label} is not canonical text")
-    try:
-        value = json.loads(text, object_pairs_hook=duplicate_rejecting_object)
-    except json.JSONDecodeError as error:
-        raise ExportChainError(f"invalid {label}: {error}") from error
-    require(isinstance(value, dict), f"{label} must be an object")
-    return value
-
-
-def safe_relative(value: Any, label: str) -> str:
-    require(isinstance(value, str) and value, f"{label} must be nonempty")
-    pure = PurePosixPath(value)
-    require(
-        not pure.is_absolute()
-        and all(part not in ("", ".", "..") for part in pure.parts),
-        f"unsafe {label}: {value!r}",
-    )
-    return value
-
-
-def read_regular(
-    root: Path,
-    relative: str,
-    expected_identities: Mapping[str, tuple[int, str]] | None,
-) -> bytes:
-    safe_relative(relative, "sealed-export path")
-    path = root.joinpath(*PurePosixPath(relative).parts)
-    expected: tuple[int, str] | None = None
-    if expected_identities is not None:
-        require(relative in expected_identities, f"sealed-export input is not inventoried: {relative}")
-        expected = expected_identities[relative]
-        require(
-            type(expected[0]) is int and 0 <= expected[0] <= MAX_UNINVENTORIED_INPUT_BYTES,
-            f"sealed-export inventory size is invalid: {relative}",
-        )
-    descriptor = os.open(
-        path,
-        os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0),
-    )
-    try:
-        before = os.fstat(descriptor)
-        require(
-            stat.S_ISREG(before.st_mode),
-            f"sealed-export input is not a regular file: {relative}",
-        )
-        bound = expected[0] if expected is not None else MAX_UNINVENTORIED_INPUT_BYTES
-        if expected is not None:
-            require(
-                before.st_size == expected[0],
-                f"sealed-export input size differs from inventory: {relative}",
-            )
-        require(
-            0 <= before.st_size <= bound,
-            f"sealed-export input exceeds its read bound: {relative}",
-        )
-        data = bytearray()
-        while len(data) <= bound:
-            chunk = os.read(descriptor, min(1024 * 1024, bound + 1 - len(data)))
-            if not chunk:
-                break
-            data.extend(chunk)
-        require(
-            len(data) == before.st_size and len(data) <= bound,
-            f"sealed-export input changed size while reading: {relative}",
-        )
-        after = os.fstat(descriptor)
-        require(
-            (
-                before.st_dev,
-                before.st_ino,
-                before.st_size,
-                before.st_mtime_ns,
-                before.st_ctime_ns,
-            )
-            == (
-                after.st_dev,
-                after.st_ino,
-                after.st_size,
-                after.st_mtime_ns,
-                after.st_ctime_ns,
-            ),
-            f"sealed-export input changed while reading: {relative}",
-        )
-    finally:
-        os.close(descriptor)
-    result = bytes(data)
-    if expected is not None:
-        require(
-            expected == (len(result), sha256(result)),
-            f"sealed-export input differs from inventory: {relative}",
-        )
-    return result
-
-
-def tracked_hash(path: Path, label: str) -> str:
-    info = os.lstat(path)
-    require(
-        stat.S_ISREG(info.st_mode) and not stat.S_ISLNK(info.st_mode),
-        f"tracked {label} is not a regular file: {path}",
-    )
-    return sha256(path.read_bytes())
-
-
-def require_sha(value: Any, label: str) -> str:
-    require(isinstance(value, str) and SHA256_RE.fullmatch(value) is not None, f"{label} is not a SHA-256")
-    return value
-
-
-def side_manifest_paths(path: Path) -> list[str]:
-    lines = path.read_text(encoding="utf-8").splitlines()
-    require(
-        lines and lines[0] == "# schema=oliphaunt.wasix-postmaster.sealed-side-modules.v1",
-        "sealed side-module manifest schema differs",
-    )
-    result: list[str] = []
-    for line in lines:
-        if not line or line.startswith("#"):
-            continue
-        fields = line.split("\t")
-        require(len(fields) == 3, "sealed side-module manifest row differs")
-        result.append(safe_relative(fields[0], "sealed side-module path"))
-    require(len(result) == 27 and len(set(result)) == 27, "sealed side-module manifest must contain exactly 27 canonical paths")
-    return result
-
-
-def validate_proof(
-    proof: dict[str, Any],
-    label: str,
-    receipt: dict[str, Any],
-    expected_main_sha256: str,
-    expected_sides: list[dict[str, str]],
-) -> None:
-    require(set(proof) == PROOF_KEYS, f"{label} fields differ")
-    require(proof["schema"] == PROOF_SCHEMA, f"{label} schema differs")
-    require(proof["policy-id"] == POLICY_ID, f"{label} policy differs")
-    require(
-        proof["analyzer-version"] == receipt["analyzer-version"],
-        f"{label} analyzer version differs from structural receipt",
-    )
-    require(
-        proof["mandatory-policy-sha256"] == receipt["mandatory-policy-sha256"]
-        and proof["declared-main-dlsym-policy-sha256"]
-        == receipt["declared-main-dlsym-policy-sha256"],
-        f"{label} policy hashes differ from structural receipt",
-    )
-    main = proof["main"]
-    require(isinstance(main, dict) and set(main) == MODULE_KEYS, f"{label} main fields differ")
-    require(
-        main["path"] == "bin/postgres" and main["sha256"] == expected_main_sha256,
-        f"{label} main module identity differs",
-    )
-    sides = proof["sides"]
-    require(isinstance(sides, list) and len(sides) == len(expected_sides), f"{label} side closure differs")
-    for module, expected in zip(sides, expected_sides, strict=True):
-        require(isinstance(module, dict) and set(module) == MODULE_KEYS, f"{label} side fields differ")
-        require(
-            (module["path"], module["sha256"])
-            == (expected["path"], expected["sha256"]),
-            f"{label} side identity differs: {expected['path']}",
-        )
-    for field in (
-        "unresolved-main-requirements",
-        "mismatched-main-requirements",
-        "unresolved-side-dependencies",
-    ):
-        require(proof[field] == [], f"{label} is not a closed export graph: {field}")
-
-
-def validate_export_chain(
-    root: Path,
-    project_root: Path,
-    source_module_hashes: Mapping[str, str],
-    expected_identities: Mapping[str, tuple[int, str]] | None = None,
-) -> dict[str, Any]:
-    receipt_data = read_regular(root, RECEIPT_RELATIVE, expected_identities)
-    receipt = parse_json(receipt_data, "sealed-export structural receipt")
-    require(set(receipt) == RECEIPT_KEYS, "sealed-export structural receipt fields differ")
-    require(receipt["schema"] == RECEIPT_SCHEMA, "sealed-export structural receipt schema differs")
-    require(receipt["policy-id"] == POLICY_ID, "sealed-export structural receipt policy differs")
-    require(receipt["dce-passes"] == ["--remove-unused-module-elements"], "sealed-export DCE pass differs")
-    for field in (
-        "analyzer-binary-sha256",
-        "dce-tool-sha256",
-        "mandatory-policy-sha256",
-        "declared-main-dlsym-policy-sha256",
-        "side-manifest-sha256",
-        "allowlist-sha256",
-        "seed-proof-sha256",
-        "final-proof-sha256",
-    ):
-        require_sha(receipt[field], f"sealed-export receipt {field}")
-    require(
-        isinstance(receipt["analyzer-version"], str)
-        and receipt["analyzer-version"]
-        and isinstance(receipt["dce-tool-version"], str)
-        and receipt["dce-tool-version"]
-        and "\n" not in receipt["dce-tool-version"],
-        "sealed-export tool version identity differs",
-    )
-
-    policy_root = project_root / "runtime" / "policies"
-    mandatory = policy_root / "sealed-main-runtime-exports.v1.txt"
-    dlsym = policy_root / "sealed-main-dlsym-exports.v1.txt"
-    side_manifest = policy_root / "sealed-side-modules.v1.tsv"
-    require(
-        receipt["mandatory-policy-sha256"] == tracked_hash(mandatory, "mandatory export policy")
-        and receipt["declared-main-dlsym-policy-sha256"] == tracked_hash(dlsym, "dlsym export policy")
-        and receipt["side-manifest-sha256"] == tracked_hash(side_manifest, "side-module manifest"),
-        "sealed-export tracked policy identity differs",
-    )
-    side_paths = side_manifest_paths(side_manifest)
-
-    seed = receipt["seed"]
-    final_module = receipt["final-module"]
-    require(isinstance(seed, dict) and set(seed) == SNAPSHOT_KEYS, "sealed-export seed snapshot fields differ")
-    require(isinstance(final_module, dict) and set(final_module) == SNAPSHOT_KEYS, "sealed-export final snapshot fields differ")
-    seed_sha = require_sha(seed["sha256"], "sealed-export seed module")
-    final_sha = require_sha(final_module["sha256"], "sealed-export final module")
-    require(
-        source_module_hashes.get("bin/postgres") == final_sha,
-        "sealed-export final module is not the linear-memory predecessor of bin/postgres",
-    )
-
-    sides = receipt["sides"]
-    require(isinstance(sides, list) and len(sides) == len(side_paths), "sealed-export side count differs")
-    expected_sides: list[dict[str, str]] = []
-    for side, expected_path in zip(sides, side_paths, strict=True):
-        require(isinstance(side, dict) and set(side) == SIDE_KEYS, "sealed-export side receipt fields differ")
-        side_path = safe_relative(side["path"], "sealed-export side path")
-        side_sha = require_sha(side["sha256"], f"sealed-export side {side_path}")
-        require(side_path == expected_path, f"sealed-export side order/path differs: {expected_path}")
-        require(
-            source_module_hashes.get(side_path) == side_sha,
-            f"sealed-export side is not the linear-memory predecessor: {side_path}",
-        )
-        expected_sides.append({"path": side_path, "sha256": side_sha})
-
-    allowlist = read_regular(root, ALLOWLIST_RELATIVE, expected_identities)
-    seed_proof_data = read_regular(root, SEED_PROOF_RELATIVE, expected_identities)
-    final_proof_data = read_regular(root, FINAL_PROOF_RELATIVE, expected_identities)
-    require(
-        sha256(allowlist) == receipt["allowlist-sha256"]
-        and sha256(seed_proof_data) == receipt["seed-proof-sha256"]
-        and sha256(final_proof_data) == receipt["final-proof-sha256"],
-        "sealed-export installed proof bytes differ from structural receipt",
-    )
-    seed_proof = parse_json(seed_proof_data, "sealed-export seed proof")
-    final_proof = parse_json(final_proof_data, "sealed-export final proof")
-    validate_proof(seed_proof, "sealed-export seed proof", receipt, seed_sha, expected_sides)
-    validate_proof(final_proof, "sealed-export final proof", receipt, final_sha, expected_sides)
-    return receipt
-
-
-def linear_closure_hash(modules: list[dict[str, Any]], field: str) -> str:
-    digest = hashlib.sha256()
-    for value in (
-        "oliphaunt.wasix-postmaster.linear-memory-install-closure.v1",
-        field,
-    ):
-        encoded = value.encode()
-        digest.update(len(encoded).to_bytes(8, "big"))
-        digest.update(encoded)
-    for module in modules:
-        for value in (module["path"], module[field]):
-            encoded = value.encode()
-            digest.update(len(encoded).to_bytes(8, "big"))
-            digest.update(encoded)
-    return digest.hexdigest()
-
-
-def linear_memory_descendant_source_hashes(root: Path) -> dict[str, str]:
-    data = read_regular(root, LINEAR_RECEIPT_RELATIVE, None)
-    receipt = parse_json(data, "linear-memory install receipt")
-    require(set(receipt) == LINEAR_RECEIPT_KEYS, "linear-memory install receipt fields differ")
-    require(
-        receipt["schema"] == LINEAR_RECEIPT_SCHEMA
-        and receipt["profile-id"] == LINEAR_PROFILE_ID
-        and receipt["address-width"] == "wasm32"
-        and receipt["supported-host-pointer-width"] == "u64"
-        and receipt["maximum-pages"] == 4096
-        and receipt["maximum-bytes"] == 268435456
-        and receipt["static-bound-pages"] == 65536
-        and receipt["static-offset-guard-bytes"] == 2147483648
-        and receipt["static-access-lowering"]
-        == "wasmer-llvm-unchecked-reservation-and-guard-v1"
-        and receipt["requires-shared"] is True
-        and receipt["requires-import"] == "env.memory"
-        and receipt["excludes-wasm32-end-wrap"] is True,
-        "linear-memory descendant profile differs",
-    )
-    require(
-        receipt["predecessor-export-closure-receipt"] == RECEIPT_RELATIVE,
-        "linear-memory descendant predecessor path differs",
-    )
-    predecessor = read_regular(root, RECEIPT_RELATIVE, None)
-    require(
-        sha256(predecessor)
-        == receipt["predecessor-export-closure-receipt-sha256"],
-        "linear-memory descendant predecessor digest differs",
-    )
-    modules = receipt["modules"]
-    require(
-        isinstance(modules, list)
-        and type(receipt["module-count"]) is int
-        and receipt["module-count"] == len(modules)
-        and len(modules) > 0,
-        "linear-memory descendant module count differs",
-    )
-    paths: list[str] = []
-    source_hashes: dict[str, str] = {}
-    for module in modules:
-        require(isinstance(module, dict) and set(module) == LINEAR_MODULE_KEYS, "linear-memory descendant module fields differ")
-        path = safe_relative(module["path"], "linear-memory descendant module path")
-        source = require_sha(module["source-module-sha256"], f"linear-memory source {path}")
-        sealed = require_sha(module["module-sha256"], f"linear-memory module {path}")
-        require(
-            type(module["initial-pages"]) is int
-            and 0 <= module["initial-pages"] <= 4096
-            and module["maximum-pages"] == 4096
-            and module["maximum-bytes"] == 268435456
-            and module["shared"] is True
-            and module["import-module"] == "env"
-            and module["import-name"] == "memory"
-            and module["transformation"]
-            == "pinned-wasixcc-65536-to-embedded-4096-reversible-v1",
-            f"linear-memory descendant module contract differs: {path}",
-        )
-        current = read_regular(root, path, None)
-        require(sha256(current) == sealed, f"linear-memory descendant bytes differ: {path}")
-        paths.append(path)
-        require(path not in source_hashes, f"duplicate linear-memory descendant path: {path}")
-        source_hashes[path] = source
-    require(paths == sorted(paths), "linear-memory descendant modules are not path-sorted")
-    require(
-        linear_closure_hash(modules, "source-module-sha256")
-        == receipt["source-module-closure-sha256"]
-        and linear_closure_hash(modules, "module-sha256")
-        == receipt["module-closure-sha256"],
-        "linear-memory descendant closure digest differs",
-    )
-    return source_hashes
-
-
-def main() -> int:
-    import argparse
-
-    parser = argparse.ArgumentParser()
-    parser.add_argument("--install-root", type=Path, required=True)
-    parser.add_argument("--project-root", type=Path, required=True)
-    parser.add_argument("--allow-linear-memory-descendant", action="store_true")
-    arguments = parser.parse_args()
-    side_manifest = (
-        arguments.project_root / "runtime" / "policies" / "sealed-side-modules.v1.tsv"
-    )
-    linear_receipt = arguments.install_root / LINEAR_RECEIPT_RELATIVE
-    if arguments.allow_linear_memory_descendant and linear_receipt.is_file():
-        source_hashes = linear_memory_descendant_source_hashes(arguments.install_root)
-    else:
-        paths = ["bin/postgres", *side_manifest_paths(side_manifest)]
-        source_hashes = {
-            relative: sha256(read_regular(arguments.install_root, relative, None))
-            for relative in paths
-        }
-    validate_export_chain(
-        arguments.install_root,
-        arguments.project_root,
-        source_hashes,
-    )
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/sealed_export_chain.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/sealed_export_chain.test.py
deleted file mode 100644
index 6083fff76..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/sealed_export_chain.test.py
+++ /dev/null
@@ -1,194 +0,0 @@
-#!/usr/bin/env python3
-
-"""Focused adversarial tests for the sealed-export predecessor verifier."""
-
-from __future__ import annotations
-
-import hashlib
-import json
-import os
-from pathlib import Path
-import shutil
-import subprocess
-import sys
-import tempfile
-
-
-PROJECT_ROOT = Path(__file__).resolve().parent.parent
-sys.path.insert(0, str(PROJECT_ROOT / "lib"))
-
-from sealed_export_chain import (  # noqa: E402
-    ExportChainError,
-    LINEAR_PROFILE_ID,
-    LINEAR_RECEIPT_RELATIVE,
-    RECEIPT_RELATIVE,
-    SEED_PROOF_RELATIVE,
-    linear_closure_hash,
-    read_regular,
-)
-
-
-def sha256(path: Path) -> str:
-    return hashlib.sha256(path.read_bytes()).hexdigest()
-
-
-def run_chain(install: Path, *, descendant: bool = False, succeeds: bool = True) -> None:
-    command = [
-        sys.executable,
-        str(PROJECT_ROOT / "lib" / "sealed_export_chain.py"),
-        "--install-root",
-        str(install),
-        "--project-root",
-        str(PROJECT_ROOT),
-    ]
-    if descendant:
-        command.append("--allow-linear-memory-descendant")
-    result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
-    if (result.returncode == 0) != succeeds:
-        raise AssertionError(
-            f"sealed-export verifier outcome differs: command={command!r}\n{result.stderr}"
-        )
-
-
-def write_json(path: Path, value: object) -> None:
-    temporary = path.with_name(f".{path.name}.test.tmp")
-    with temporary.open("w", encoding="utf-8", newline="\n") as stream:
-        json.dump(value, stream, indent=2, sort_keys=True)
-        stream.write("\n")
-        stream.flush()
-        os.fsync(stream.fileno())
-    os.replace(temporary, path)
-
-
-def make_linear_receipt(install: Path) -> dict[str, object]:
-    modules: list[dict[str, object]] = []
-    for subtree in (install / "bin", install / "lib"):
-        for path in sorted(item for item in subtree.rglob("*") if item.is_file()):
-            if path.read_bytes()[:4] != b"\0asm":
-                continue
-            relative = path.relative_to(install).as_posix()
-            digest = sha256(path)
-            modules.append(
-                {
-                    "import-module": "env",
-                    "import-name": "memory",
-                    "initial-pages": 1,
-                    "maximum-bytes": 268435456,
-                    "maximum-pages": 4096,
-                    "module-sha256": digest,
-                    "path": relative,
-                    "shared": True,
-                    "source-module-sha256": digest,
-                    "transformation": "pinned-wasixcc-65536-to-embedded-4096-reversible-v1",
-                }
-            )
-    modules.sort(key=lambda module: str(module["path"]))
-    return {
-        "address-width": "wasm32",
-        "excludes-wasm32-end-wrap": True,
-        "maximum-bytes": 268435456,
-        "maximum-pages": 4096,
-        "module-closure-sha256": linear_closure_hash(modules, "module-sha256"),
-        "module-count": len(modules),
-        "modules": modules,
-        "predecessor-export-closure-receipt": RECEIPT_RELATIVE,
-        "predecessor-export-closure-receipt-sha256": sha256(install / RECEIPT_RELATIVE),
-        "profile-id": LINEAR_PROFILE_ID,
-        "requires-import": "env.memory",
-        "requires-shared": True,
-        "schema": "oliphaunt.wasix-postmaster.linear-memory-install.v1",
-        "source-module-closure-sha256": linear_closure_hash(modules, "source-module-sha256"),
-        "static-access-lowering": "wasmer-llvm-unchecked-reservation-and-guard-v1",
-        "static-bound-pages": 65536,
-        "static-offset-guard-bytes": 2147483648,
-        "supported-host-pointer-width": "u64",
-    }
-
-
-def main() -> int:
-    target = PROJECT_ROOT.parents[3] / "target" / "oliphaunt-wasix-postmaster"
-    target.mkdir(parents=True, exist_ok=True)
-    root = Path(tempfile.mkdtemp(prefix="sealed-export-chain-test.", dir=target))
-    try:
-        install = root / "install"
-        module = bytes.fromhex(
-            "0061736d01000000"
-            "0212"
-            "01"
-            "03656e76"
-            "066d656d6f7279"
-            "02"
-            "03"
-            "01"
-            "808004"
-        )
-        for relative in (
-            "bin/initdb",
-            "bin/postgres",
-            "lib/libpq.so.5.18",
-            "lib/postgresql/dict_snowball.so",
-            "lib/postgresql/plpgsql.so",
-        ):
-            path = install / relative
-            path.parent.mkdir(parents=True, exist_ok=True)
-            path.write_bytes(module)
-        subprocess.run(
-            [
-                sys.executable,
-                str(PROJECT_ROOT / "testdata" / "make-sealed-export-fixture.py"),
-                "--install-root",
-                str(install),
-                "--project-root",
-                str(PROJECT_ROOT),
-            ],
-            check=True,
-        )
-        run_chain(install)
-
-        linear_receipt = make_linear_receipt(install)
-        linear_path = install / LINEAR_RECEIPT_RELATIVE
-        write_json(linear_path, linear_receipt)
-        run_chain(install, descendant=True)
-
-        linear_receipt["modules"][0]["initial-pages"] = True  # type: ignore[index]
-        write_json(linear_path, linear_receipt)
-        run_chain(install, descendant=True, succeeds=False)
-        linear_receipt["modules"][0]["initial-pages"] = 4097  # type: ignore[index]
-        write_json(linear_path, linear_receipt)
-        run_chain(install, descendant=True, succeeds=False)
-        linear_path.unlink()
-
-        seed_path = install / SEED_PROOF_RELATIVE
-        seed = json.loads(seed_path.read_text(encoding="utf-8"))
-        seed["analyzer-version"] = "mismatched-analyzer"
-        write_json(seed_path, seed)
-        structural_path = install / RECEIPT_RELATIVE
-        structural = json.loads(structural_path.read_text(encoding="utf-8"))
-        structural["seed-proof-sha256"] = sha256(seed_path)
-        write_json(structural_path, structural)
-        run_chain(install, succeeds=False)
-
-        regular = install / "regular"
-        regular.write_bytes(b"bounded")
-        symlink = install / "symlink"
-        symlink.symlink_to(regular.name)
-        try:
-            read_regular(install, "symlink", None)
-        except (ExportChainError, OSError):
-            pass
-        else:
-            raise AssertionError("sealed-export verifier followed a final-component symlink")
-        try:
-            read_regular(install, "regular", {"regular": (1, "0" * 64)})
-        except ExportChainError:
-            pass
-        else:
-            raise AssertionError("sealed-export verifier ignored inventoried size precheck")
-    finally:
-        shutil.rmtree(root)
-    print("sealed export chain tests passed")
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/server-lifecycle.sh b/src/runtimes/liboliphaunt/wasix-postmaster/lib/server-lifecycle.sh
deleted file mode 100644
index d758c2682..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/server-lifecycle.sh
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env bash
-
-# Requires process-supervision.sh.
-
-fresh_path_identity() {
-  local path="$1"
-  if stat -Lc '%d:%i' "$path" >/dev/null 2>&1; then
-    stat -Lc '%d:%i' "$path"
-  elif stat -f '%d:%i' "$path" >/dev/null 2>&1; then
-    stat -f '%d:%i' "$path"
-  else
-    return 1
-  fi
-}
-
-fresh_wait_cgroup_empty() {
-  local cgroup_dir="$1"
-  local expected_identity="$2"
-  local timeout_ms="$3"
-  local deadline actual_identity members
-
-  [ -n "$cgroup_dir" ] || return 0
-  case "$timeout_ms" in ""|*[!0-9]*) return 125 ;; esac
-  deadline=$(( $(fresh_supervision_now_ms) + timeout_ms ))
-  while :; do
-    [ -e "$cgroup_dir" ] || return 0
-    actual_identity="$(fresh_path_identity "$cgroup_dir" 2>/dev/null)" || return 125
-    if [ "$actual_identity" != "$expected_identity" ]; then
-      printf 'refusing reused cgroup identity: path=%s expected=%s actual=%s\n' \
-        "$cgroup_dir" "$expected_identity" "$actual_identity" >&2
-      return 125
-    fi
-    [ -r "$cgroup_dir/cgroup.procs" ] || {
-      printf 'tracked cgroup.procs became unreadable: %s\n' "$cgroup_dir" >&2
-      return 125
-    }
-    members="$(tr -d '[:space:]' <"$cgroup_dir/cgroup.procs")"
-    [ -z "$members" ] && return 0
-    [ "$(fresh_supervision_now_ms)" -lt "$deadline" ] || {
-      printf 'tracked cgroup retained processes after shutdown: %s (%s)\n' \
-        "$cgroup_dir" "$members" >&2
-      return 125
-    }
-    sleep 0.05
-  done
-}
-
-fresh_tcp_port_open() {
-  local host="$1"
-  local port="$2"
-  perl -MIO::Socket::INET -e '
-    my ($host, $port) = @ARGV;
-    my $socket = IO::Socket::INET->new(
-      PeerAddr => $host,
-      PeerPort => $port,
-      Proto => "tcp",
-      Timeout => 0.2,
-    );
-    exit($socket ? 0 : 1);
-  ' "$host" "$port"
-}
-
-fresh_wait_tcp_port_closed() {
-  local host="$1"
-  local port="$2"
-  local timeout_ms="$3"
-  local deadline
-
-  case "$port:$timeout_ms" in *[!0-9:]*|:*|*:) return 125 ;; esac
-  deadline=$(( $(fresh_supervision_now_ms) + timeout_ms ))
-  while fresh_tcp_port_open "$host" "$port"; do
-    [ "$(fresh_supervision_now_ms)" -lt "$deadline" ] || {
-      printf 'TCP listener survived shutdown: %s:%s\n' "$host" "$port" >&2
-      return 125
-    }
-    sleep 0.05
-  done
-}
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/signal-owned-pid.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/signal-owned-pid.py
deleted file mode 100644
index 993e09d05..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/signal-owned-pid.py
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/env python3
-
-from __future__ import annotations
-
-import argparse
-import ctypes
-import errno
-import os
-from pathlib import Path
-import re
-import select
-import signal
-import sys
-
-
-IDENTITY = re.compile(r"linux-starttime:([1-9][0-9]*)")
-
-
-def process_starttime(pid: int) -> int | None:
-    try:
-        record = Path(f"/proc/{pid}/stat").read_text(encoding="ascii")
-    except (FileNotFoundError, ProcessLookupError):
-        return None
-    except OSError as error:
-        raise RuntimeError(f"could not read /proc/{pid}/stat: {error}") from error
-    closing = record.rfind(") ")
-    if closing < 0:
-        raise RuntimeError(f"malformed /proc/{pid}/stat")
-    fields = record[closing + 2 :].split()
-    if len(fields) < 20 or not fields[19].isdigit():
-        raise RuntimeError(f"malformed starttime in /proc/{pid}/stat")
-    return int(fields[19])
-
-
-def parse_signal(value: str) -> int:
-    normalized = value.removeprefix("SIG").upper()
-    try:
-        number = int(normalized)
-    except ValueError:
-        try:
-            return int(signal.Signals[f"SIG{normalized}"])
-        except KeyError as error:
-            raise argparse.ArgumentTypeError(f"unsupported signal: {value}") from error
-    try:
-        return int(signal.Signals(number))
-    except ValueError as error:
-        raise argparse.ArgumentTypeError(f"unsupported signal: {value}") from error
-
-
-def pidfd_is_exited(pidfd: int) -> bool:
-    poller = select.poll()
-    poller.register(pidfd, select.POLLIN)
-    return bool(poller.poll(0))
-
-
-def signal_owned_pid(pid: int, expected_starttime: int, signum: int) -> int:
-    libc = ctypes.CDLL(None, use_errno=True)
-    if not hasattr(libc, "pidfd_open") or not hasattr(libc, "pidfd_send_signal"):
-        print("libc does not expose Linux pidfd APIs", file=sys.stderr)
-        return 125
-    libc.pidfd_open.argtypes = (ctypes.c_int, ctypes.c_uint)
-    libc.pidfd_open.restype = ctypes.c_int
-    libc.pidfd_send_signal.argtypes = (
-        ctypes.c_int,
-        ctypes.c_int,
-        ctypes.c_void_p,
-        ctypes.c_uint,
-    )
-    libc.pidfd_send_signal.restype = ctypes.c_int
-
-    pidfd = libc.pidfd_open(pid, 0)
-    if pidfd < 0:
-        error = ctypes.get_errno()
-        if error == errno.ESRCH:
-            return 0
-        print(f"pidfd_open({pid}) failed: {os.strerror(error)}", file=sys.stderr)
-        return 125
-    try:
-        try:
-            actual_starttime = process_starttime(pid)
-        except RuntimeError as error:
-            if pidfd_is_exited(pidfd):
-                return 0
-            print(error, file=sys.stderr)
-            return 125
-        if actual_starttime is None:
-            return 0 if pidfd_is_exited(pidfd) else 125
-        if actual_starttime != expected_starttime:
-            if pidfd_is_exited(pidfd):
-                return 0
-            print(
-                "refusing to signal reused process identity: "
-                f"pid={pid} expected=linux-starttime:{expected_starttime} "
-                f"actual=linux-starttime:{actual_starttime}",
-                file=sys.stderr,
-            )
-            return 125
-        if libc.pidfd_send_signal(pidfd, signum, None, 0) < 0:
-            error = ctypes.get_errno()
-            if error == errno.ESRCH:
-                return 0
-            print(f"pidfd_send_signal({pid}) failed: {os.strerror(error)}", file=sys.stderr)
-            return 125
-        return 0
-    finally:
-        os.close(pidfd)
-
-
-def main() -> int:
-    parser = argparse.ArgumentParser()
-    parser.add_argument("--pid", type=int, required=True)
-    parser.add_argument("--identity", required=True)
-    parser.add_argument("--signal", type=parse_signal, required=True)
-    args = parser.parse_args()
-    if args.pid <= 0:
-        parser.error("--pid must be positive")
-    match = IDENTITY.fullmatch(args.identity)
-    if match is None:
-        parser.error("--identity must be linux-starttime:")
-    return signal_owned_pid(args.pid, int(match.group(1)), args.signal)
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/signal-owned-pid.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/signal-owned-pid.test.py
deleted file mode 100644
index b678a4526..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/signal-owned-pid.test.py
+++ /dev/null
@@ -1,261 +0,0 @@
-#!/usr/bin/env python3
-
-from __future__ import annotations
-
-from contextlib import redirect_stderr
-import importlib.util
-import io
-from pathlib import Path
-import subprocess
-import sys
-import time
-import unittest
-from unittest import mock
-
-
-SCRIPT = Path(__file__).with_name("signal-owned-pid.py")
-
-
-def load_helper():
-    spec = importlib.util.spec_from_file_location("signal_owned_pid", SCRIPT)
-    if spec is None or spec.loader is None:
-        raise RuntimeError(f"could not load {SCRIPT}")
-    module = importlib.util.module_from_spec(spec)
-    spec.loader.exec_module(module)
-    return module
-
-
-HELPER = load_helper()
-
-
-class FakeCFunction:
-    def __init__(self, implementation):
-        self.implementation = implementation
-        self.argtypes = None
-        self.restype = None
-
-    def __call__(self, *args):
-        return self.implementation(*args)
-
-
-class FakeLibc:
-    def __init__(self, pidfd_open, pidfd_send_signal):
-        self.pidfd_open = FakeCFunction(pidfd_open)
-        self.pidfd_send_signal = FakeCFunction(pidfd_send_signal)
-
-
-def starttime(pid: int) -> int:
-    record = Path(f"/proc/{pid}/stat").read_text(encoding="ascii")
-    fields = record[record.rfind(") ") + 2 :].split()
-    return int(fields[19])
-
-
-class SignalOwnedPidTests(unittest.TestCase):
-    def test_pidfd_is_opened_before_identity_is_read_and_signal_uses_that_fd(
-        self,
-    ) -> None:
-        events: list[tuple[object, ...]] = []
-
-        def pidfd_open(pid: int, flags: int) -> int:
-            events.append(("open", pid, flags))
-            return 71
-
-        def read_starttime(pid: int) -> int:
-            events.append(("read-starttime", pid))
-            return 303
-
-        def pidfd_send_signal(
-            pidfd: int, signum: int, siginfo: object, flags: int
-        ) -> int:
-            events.append(("send", pidfd, signum, siginfo, flags))
-            return 0
-
-        libc = FakeLibc(pidfd_open, pidfd_send_signal)
-        with (
-            mock.patch.object(HELPER.ctypes, "CDLL", return_value=libc),
-            mock.patch.object(HELPER, "process_starttime", side_effect=read_starttime),
-            mock.patch.object(
-                HELPER,
-                "pidfd_is_exited",
-                side_effect=AssertionError("matching identity must not poll the pidfd"),
-            ),
-            mock.patch.object(
-                HELPER.os,
-                "close",
-                side_effect=lambda fd: events.append(("close", fd)),
-            ),
-        ):
-            status = HELPER.signal_owned_pid(41, 303, 15)
-
-        self.assertEqual(status, 0)
-        self.assertEqual(
-            events,
-            [
-                ("open", 41, 0),
-                ("read-starttime", 41),
-                ("send", 71, 15, None, 0),
-                ("close", 71),
-            ],
-        )
-
-    def test_live_pidfd_rejects_starttime_mismatch_without_signalling(self) -> None:
-        events: list[tuple[object, ...]] = []
-        libc = FakeLibc(
-            lambda pid, flags: events.append(("open", pid, flags)) or 72,
-            lambda *args: events.append(("send", *args)) or 0,
-        )
-        stderr = io.StringIO()
-        with (
-            mock.patch.object(HELPER.ctypes, "CDLL", return_value=libc),
-            mock.patch.object(HELPER, "process_starttime", return_value=404),
-            mock.patch.object(
-                HELPER,
-                "pidfd_is_exited",
-                side_effect=lambda fd: events.append(("poll", fd)) or False,
-            ),
-            mock.patch.object(
-                HELPER.os,
-                "close",
-                side_effect=lambda fd: events.append(("close", fd)),
-            ),
-            redirect_stderr(stderr),
-        ):
-            status = HELPER.signal_owned_pid(42, 303, 15)
-
-        self.assertEqual(status, 125)
-        self.assertEqual(events, [("open", 42, 0), ("poll", 72), ("close", 72)])
-        self.assertIn(
-            "pid=42 expected=linux-starttime:303 actual=linux-starttime:404",
-            stderr.getvalue(),
-        )
-
-    def test_exited_pidfd_turns_starttime_mismatch_into_noop(self) -> None:
-        events: list[tuple[object, ...]] = []
-        libc = FakeLibc(
-            lambda pid, flags: events.append(("open", pid, flags)) or 73,
-            lambda *args: events.append(("send", *args)) or 0,
-        )
-        with (
-            mock.patch.object(HELPER.ctypes, "CDLL", return_value=libc),
-            mock.patch.object(HELPER, "process_starttime", return_value=404),
-            mock.patch.object(
-                HELPER,
-                "pidfd_is_exited",
-                side_effect=lambda fd: events.append(("poll", fd)) or True,
-            ),
-            mock.patch.object(
-                HELPER.os,
-                "close",
-                side_effect=lambda fd: events.append(("close", fd)),
-            ),
-        ):
-            status = HELPER.signal_owned_pid(43, 303, 15)
-
-        self.assertEqual(status, 0)
-        self.assertEqual(events, [("open", 43, 0), ("poll", 73), ("close", 73)])
-
-    def test_proc_disappearance_is_accepted_only_after_pidfd_exit(self) -> None:
-        for pidfd_exited, expected_status in ((False, 125), (True, 0)):
-            with self.subTest(pidfd_exited=pidfd_exited):
-                events: list[tuple[object, ...]] = []
-                libc = FakeLibc(
-                    lambda pid, flags: events.append(("open", pid, flags)) or 74,
-                    lambda *args: events.append(("send", *args)) or 0,
-                )
-                with (
-                    mock.patch.object(HELPER.ctypes, "CDLL", return_value=libc),
-                    mock.patch.object(HELPER, "process_starttime", return_value=None),
-                    mock.patch.object(
-                        HELPER,
-                        "pidfd_is_exited",
-                        side_effect=lambda fd: events.append(("poll", fd))
-                        or pidfd_exited,
-                    ),
-                    mock.patch.object(
-                        HELPER.os,
-                        "close",
-                        side_effect=lambda fd: events.append(("close", fd)),
-                    ),
-                ):
-                    status = HELPER.signal_owned_pid(44, 303, 15)
-
-                self.assertEqual(status, expected_status)
-                self.assertEqual(
-                    events, [("open", 44, 0), ("poll", 74), ("close", 74)]
-                )
-
-    @unittest.skipUnless(sys.platform.startswith("linux"), "Linux pidfd contract")
-    def test_pidfd_rejects_wrong_birth_and_signals_exact_process(self) -> None:
-        process = subprocess.Popen(["sleep", "30"])
-        try:
-            identity = f"linux-starttime:{starttime(process.pid)}"
-            wrong = subprocess.run(
-                [
-                    sys.executable,
-                    str(SCRIPT),
-                    "--pid",
-                    str(process.pid),
-                    "--identity",
-                    "linux-starttime:1",
-                    "--signal",
-                    "TERM",
-                ],
-                check=False,
-                text=True,
-                capture_output=True,
-            )
-            self.assertEqual(wrong.returncode, 125, wrong.stderr)
-            self.assertIsNone(process.poll())
-
-            sent = subprocess.run(
-                [
-                    sys.executable,
-                    str(SCRIPT),
-                    "--pid",
-                    str(process.pid),
-                    "--identity",
-                    identity,
-                    "--signal",
-                    "TERM",
-                ],
-                check=False,
-                text=True,
-                capture_output=True,
-            )
-            self.assertEqual(sent.returncode, 0, sent.stderr)
-            process.wait(timeout=2)
-            self.assertEqual(process.returncode, -15)
-        finally:
-            if process.poll() is None:
-                process.kill()
-                process.wait()
-
-    @unittest.skipUnless(sys.platform.startswith("linux"), "Linux pidfd contract")
-    def test_already_exited_process_is_a_noop(self) -> None:
-        # Keep the fixture alive long enough to capture a real birth identity,
-        # then reap it before invoking the helper.  A `true` process can exit
-        # before /proc is read and makes this race test the fixture, not pidfd.
-        process = subprocess.Popen(["sleep", "30"])
-        identity = f"linux-starttime:{starttime(process.pid)}"
-        process.terminate()
-        process.wait(timeout=2)
-        result = subprocess.run(
-            [
-                sys.executable,
-                str(SCRIPT),
-                "--pid",
-                str(process.pid),
-                "--identity",
-                identity,
-                "--signal",
-                "TERM",
-            ],
-            check=False,
-            text=True,
-            capture_output=True,
-        )
-        self.assertEqual(result.returncode, 0, result.stderr)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/verify-sealed-carrier.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/verify-sealed-carrier.py
deleted file mode 100644
index 704060302..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/verify-sealed-carrier.py
+++ /dev/null
@@ -1,1469 +0,0 @@
-#!/usr/bin/env python3
-
-"""Verify the complete local sealed WASIX PostgreSQL carrier closure."""
-
-from __future__ import annotations
-
-import hashlib
-import json
-import os
-import re
-import stat
-import sys
-from pathlib import Path, PurePosixPath
-from typing import Any
-
-from guest_build_provenance import (
-    ProvenanceError,
-    REQUIRED_MODULES,
-    SIDE_MODULE_POLICY,
-    installed_closure_identity_from_records,
-)
-from sealed_export_chain import (
-    ExportChainError,
-    RECEIPT_RELATIVE as SEALED_EXPORT_RECEIPT_RELATIVE,
-    validate_export_chain,
-)
-
-
-PAYLOAD_SCHEMA = "oliphaunt.wasix-postmaster.payload-files.v1"
-MANIFEST_SCHEMA = "oliphaunt.wasix-postmaster.sealed-aot.v5"
-LINEAR_MEMORY_INSTALL_SCHEMA = "oliphaunt.wasix-postmaster.linear-memory-install.v1"
-LINEAR_MEMORY_PROFILE_ID = "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1"
-MEMORY_SCHEMA = "oliphaunt.wasix-postmaster.memory-image.v2"
-MEMORY_PHASE = "post-module-start-pre-link-relocations-v1"
-DETERMINISTIC_START_PROOF_SCHEMA = (
-    "oliphaunt.wasix-postmaster.deterministic-start-proof.v1"
-)
-DETERMINISTIC_START_ANALYZER_POLICY = (
-    "llvm-shared-memory-init-restricted-effects.v1"
-)
-DETERMINISTIC_START_MEMORY_READS = "fresh-zero-atomic-guard-only"
-DETERMINISTIC_START_MEMORY_EFFECTS = (
-    "passive-data-init-zero-fill-atomic-guard-only"
-)
-DETERMINISTIC_START_GLOBAL_EFFECTS = "local-numeric-relocations-only"
-DETERMINISTIC_START_TABLE_EFFECTS = "none"
-DETERMINISTIC_START_PROOF_KEYS = {
-    "schema",
-    "analyzer-policy",
-    "module-sha256",
-    "proof-sha256",
-    "start-function-index",
-    "start-function-export",
-    "transitive-function-indices",
-    "imported-function-calls",
-    "memory-reads",
-    "memory-effects",
-    "global-effects",
-    "table-effects",
-    "requires-fresh-zeroed-memory",
-    "ordinary-start-execution-per-instance",
-    "first-instance-full-byte-validation",
-}
-SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
-SIZE_RE = re.compile(r"(?:0|[1-9][0-9]*)\Z")
-
-TOP_LEVEL_MANIFEST_KEYS = {
-    "format-version",
-    "schema",
-    "source-lane",
-    "source-fingerprint",
-    "core-profile",
-    "guest-build-recipe-sha256",
-    "postgres-version",
-    "target-triple",
-    "host-abi",
-    "engine",
-    "compiler-config",
-    "cpu-policy",
-    "cpu-features",
-    "wasmer-version",
-    "wasmer-wasix-version",
-    "wasmer-source-commit",
-    "wasmer-patch-sha256",
-    "wasmer-cargo-lock-sha256",
-    "artifact-abi-version",
-    "runtime-abi-id",
-    "producer-recipe-sha256",
-    "executor-engine",
-    "executor-sha256",
-    "executor-size",
-    "linear-memory-profile",
-    "wasm-features",
-    "entrypoint",
-    "artifacts",
-}
-LINEAR_MEMORY_PROFILE_KEYS = {
-    "id",
-    "address-width",
-    "supported-host-pointer-width",
-    "maximum-pages",
-    "maximum-bytes",
-    "static-bound-pages",
-    "static-offset-guard-bytes",
-    "static-access-lowering",
-    "install-receipt-path",
-    "install-receipt-sha256",
-}
-ARTIFACT_KEYS = {
-    "name",
-    "kind",
-    "path",
-    "module-path",
-    "sha256",
-    "raw-sha256",
-    "raw-size",
-    "module-sha256",
-    "module-size",
-    "linear-memory",
-    "compressed",
-    "exec-aliases",
-}
-ARTIFACT_LINEAR_MEMORY_KEYS = {
-    "profile-id",
-    "source-module-sha256",
-    "install-receipt-sha256",
-}
-LINEAR_MEMORY_INSTALL_KEYS = {
-    "schema",
-    "profile-id",
-    "address-width",
-    "supported-host-pointer-width",
-    "maximum-pages",
-    "maximum-bytes",
-    "static-bound-pages",
-    "static-offset-guard-bytes",
-    "static-access-lowering",
-    "requires-shared",
-    "requires-import",
-    "excludes-wasm32-end-wrap",
-    "predecessor-export-closure-receipt",
-    "predecessor-export-closure-receipt-sha256",
-    "source-module-closure-sha256",
-    "module-closure-sha256",
-    "module-count",
-    "modules",
-}
-LINEAR_MEMORY_INSTALL_MODULE_KEYS = {
-    "path",
-    "source-module-sha256",
-    "module-sha256",
-    "initial-pages",
-    "maximum-pages",
-    "maximum-bytes",
-    "shared",
-    "import-module",
-    "import-name",
-    "transformation",
-}
-MEMORY_KEYS = {
-    "path",
-    "size",
-    "sha256",
-    "schema",
-    "module-sha256",
-    "runtime-abi-id",
-    "phase",
-    "mapping-alignment",
-    "mapped-size",
-    "memory-minimum-pages",
-    "memory-maximum-pages",
-    "memory-shared",
-    "memory-base",
-    "dylink-memory-size",
-    "dylink-memory-alignment",
-    "stack-low",
-    "deterministic-start-proof",
-    "deterministic-start-proof-output-sha256",
-}
-MEMORY_RECEIPT_KEYS = MEMORY_KEYS - {"path", "size", "sha256"}
-RECEIPT_KEYS = (
-    "schema",
-    "build_recipe_sha256",
-    "wasmer_source_commit",
-    "wasmer_napi_commit",
-    "wasmer_test_files_commit",
-    "wasmer_spec_commit",
-    "wasmer_patch_sha256",
-    "wasmer_prepared_signature_sha256",
-    "wasmer_cargo_lock_sha256",
-    "wasmer_binary_sha256",
-    "wasmer_features",
-    "wasmer_headless_binary_sha256",
-    "wasmer_headless_features",
-    "runtime_abi_id",
-    "artifact_abi_version",
-    "wasix_libc_source_commit",
-    "wasix_libc_patch_sha256",
-    "wasix_libc_prepared_signature_sha256",
-    "sysroot_carrier_manifest_sha256",
-    "sysroot_variant",
-    "sysroot_variant_manifest_sha256",
-    "host_platform",
-    "host_abi",
-    "rustc_host",
-    "rustc_version",
-    "llvm_version",
-)
-POSTMASTER_EXECUTOR_RECEIPT_PATH = "postmaster-executor.receipt"
-POSTMASTER_EXECUTOR_RECEIPT_KEYS = (
-    "schema",
-    "build_recipe_sha256",
-    "wasmer_build_receipt_sha256",
-    "wasmer_source_commit",
-    "wasmer_patch_sha256",
-    "wasmer_prepared_signature_sha256",
-    "wasmer_cargo_lock_sha256",
-    "runtime_abi_id",
-    "artifact_abi_version",
-    "executor_package",
-    "executor_binary",
-    "executor_features",
-    "executor_role",
-    "runtime_policy_id",
-    "cli_contract",
-    "executor_binary_sha256",
-    "start_proof_binary",
-    "start_proof_features",
-    "start_proof_policy",
-    "start_proof_binary_sha256",
-    "memory_profile_binary",
-    "memory_profile_features",
-    "linear_memory_profile_id",
-    "memory_profile_binary_sha256",
-    "postmaster_compiler_binary",
-    "postmaster_compiler_features",
-    "compiler_cpu_policy",
-    "compiler_cpu_features",
-    "postmaster_compiler_binary_sha256",
-    "host_platform",
-    "host_abi",
-    "rustc_host",
-    "rustc_version",
-)
-GUEST_BUILD_RECEIPT_KEYS = (
-    "schema",
-    "core_profile",
-    "guest_source_signature_sha256",
-    "docker_image_id",
-    "installed_closure_sha256",
-    "child_backend",
-    "effective_cflags",
-    "effective_ldflags",
-    "effective_wasm_opt",
-    "effective_wasm_opt_flags",
-    "effective_wasm_opt_suppress_default",
-    "atomic_fence_total",
-    "atomic_fence_set_latch",
-    "atomic_fence_reset_latch",
-    "atomic_fence_wait_event_set_wait",
-    "latch_state_contract",
-    "final_wasm_concurrency_receipt_sha256",
-    "linear_memory_profile_id",
-    "linear_memory_install_receipt_sha256",
-    "postgres_tag",
-    "postgres_version",
-    "sysroot_variant",
-)
-FINAL_CONCURRENCY_RECEIPT_PATH = (
-    "share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt"
-)
-FINAL_CONCURRENCY_RECEIPT_KEYS = (
-    "schema",
-    "postgres_sha256",
-    "wasm_dis_sha256",
-    "wasm_dis_version",
-    "latch_state_contract",
-    "atomic_fence_total",
-    "atomic_fence_set_latch",
-    "atomic_fence_reset_latch",
-    "atomic_fence_wait_event_set_wait",
-    "i32_atomic_load_total",
-    "i32_atomic_load_wait_event_set_wait",
-    "i32_atomic_rmw_and_total",
-    "i32_atomic_rmw_and_reset_latch",
-    "i32_atomic_rmw_and_wait_event_set_wait",
-    "i32_atomic_rmw_or_total",
-    "i32_atomic_rmw_or_set_latch",
-    "i32_atomic_rmw_or_wait_event_set_wait",
-)
-EXPECTED_ARTIFACTS = (
-    ("runtime:initdb", "executable", "bin/initdb", ["/bin/initdb"]),
-    ("runtime:postgres", "executable", "bin/postgres", ["/bin/postgres"]),
-    *(
-        (f"runtime:{PurePosixPath(relative).name}", "side-module", relative, [])
-        for relative, _aliases in SIDE_MODULE_POLICY
-    ),
-)
-
-
-class VerificationError(Exception):
-    pass
-
-
-def fail(message: str) -> None:
-    raise VerificationError(message)
-
-
-def require(condition: bool, message: str) -> None:
-    if not condition:
-        fail(message)
-
-
-def sha256_bytes(data: bytes) -> str:
-    return hashlib.sha256(data).hexdigest()
-
-
-def linear_memory_closure_sha256(modules: list[dict[str, Any]], hash_field: str) -> str:
-    digest = hashlib.sha256()
-    for value in (
-        "oliphaunt.wasix-postmaster.linear-memory-install-closure.v1",
-        hash_field,
-    ):
-        encoded = value.encode("utf-8")
-        digest.update(len(encoded).to_bytes(8, "big"))
-        digest.update(encoded)
-    for module in modules:
-        for value in (module["path"], module[hash_field]):
-            encoded = value.encode("utf-8")
-            digest.update(len(encoded).to_bytes(8, "big"))
-            digest.update(encoded)
-    return digest.hexdigest()
-
-
-def checked_relative(value: Any, label: str) -> str:
-    require(isinstance(value, str) and value != "", f"{label} must be a nonempty string")
-    require(
-        not any(character in value for character in ("\0", "\n", "\r", "\t", "\\")),
-        f"{label} contains a control character or backslash: {value!r}",
-    )
-    path = PurePosixPath(value)
-    require(not path.is_absolute(), f"{label} must be relative: {value!r}")
-    require(all(part not in ("", ".", "..") for part in path.parts), f"unsafe {label}: {value!r}")
-    require(str(path) == value, f"non-canonical {label}: {value!r}")
-    return value
-
-
-def reject_duplicate_keys(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
-    result: dict[str, Any] = {}
-    for key, value in pairs:
-        if key in result:
-            fail(f"duplicate JSON field: {key}")
-        result[key] = value
-    return result
-
-
-def decode_json(data: bytes, label: str) -> Any:
-    try:
-        text = data.decode("utf-8")
-    except UnicodeDecodeError as error:
-        fail(f"{label} is not UTF-8: {error}")
-    require("\r" not in text, f"{label} contains a carriage return")
-    try:
-        return json.loads(text, object_pairs_hook=reject_duplicate_keys)
-    except (json.JSONDecodeError, VerificationError) as error:
-        fail(f"invalid {label}: {error}")
-
-
-def consume_regular(
-    path: Path, *, capture: bool
-) -> tuple[bytes | None, os.stat_result, str]:
-    flags = os.O_RDONLY | getattr(os, "O_CLOEXEC", 0) | getattr(os, "O_NOFOLLOW", 0)
-    before = os.lstat(path)
-    require(stat.S_ISREG(before.st_mode), f"carrier entry is not a regular file: {path}")
-    descriptor = os.open(path, flags)
-    try:
-        opened = os.fstat(descriptor)
-        require(stat.S_ISREG(opened.st_mode), f"opened carrier entry is not regular: {path}")
-        require(
-            (before.st_dev, before.st_ino) == (opened.st_dev, opened.st_ino),
-            f"carrier entry changed identity while opening: {path}",
-        )
-        chunks: list[bytes] | None = [] if capture else None
-        digest = hashlib.sha256()
-        size = 0
-        while True:
-            chunk = os.read(descriptor, 1024 * 1024)
-            if not chunk:
-                break
-            digest.update(chunk)
-            size += len(chunk)
-            if chunks is not None:
-                chunks.append(chunk)
-        after = os.fstat(descriptor)
-        require(
-            (
-                opened.st_dev,
-                opened.st_ino,
-                opened.st_size,
-                opened.st_mtime_ns,
-                opened.st_ctime_ns,
-            )
-            == (
-                after.st_dev,
-                after.st_ino,
-                after.st_size,
-                after.st_mtime_ns,
-                after.st_ctime_ns,
-            ),
-            f"carrier entry changed while reading: {path}",
-        )
-        require(size == opened.st_size, f"short read while verifying carrier entry: {path}")
-        data = b"".join(chunks) if chunks is not None else None
-        return data, opened, digest.hexdigest()
-    finally:
-        os.close(descriptor)
-
-
-def read_regular(path: Path) -> tuple[bytes, os.stat_result]:
-    data, info, _ = consume_regular(path, capture=True)
-    require(data is not None, f"internal read failed to capture carrier entry: {path}")
-    return data, info
-
-
-def hash_regular(path: Path) -> tuple[os.stat_result, str]:
-    _, info, digest = consume_regular(path, capture=False)
-    return info, digest
-
-
-def scan_carrier(root: Path) -> tuple[set[str], set[str]]:
-    root_info = os.lstat(root)
-    require(stat.S_ISDIR(root_info.st_mode), f"carrier root is not a directory: {root}")
-    require(not stat.S_ISLNK(root_info.st_mode), f"carrier root must not be a symlink: {root}")
-    require(
-        stat.S_IMODE(root_info.st_mode) == 0o555,
-        f"carrier root mode must be 0555: {stat.S_IMODE(root_info.st_mode):04o}",
-    )
-    files: set[str] = set()
-    directories: set[str] = set()
-    for current, names, filenames in os.walk(root, topdown=True, followlinks=False):
-        names.sort()
-        filenames.sort()
-        for name in names:
-            path = Path(current, name)
-            info = os.lstat(path)
-            relative = path.relative_to(root).as_posix()
-            require(not stat.S_ISLNK(info.st_mode), f"carrier contains a symlink: {relative}")
-            require(stat.S_ISDIR(info.st_mode), f"carrier contains a special entry: {relative}")
-            require(
-                stat.S_IMODE(info.st_mode) == 0o555,
-                f"carrier directory mode must be 0555: {relative}: {stat.S_IMODE(info.st_mode):04o}",
-            )
-            directories.add(relative)
-        for name in filenames:
-            path = Path(current, name)
-            info = os.lstat(path)
-            relative = path.relative_to(root).as_posix()
-            require(not stat.S_ISLNK(info.st_mode), f"carrier contains a symlink: {relative}")
-            require(stat.S_ISREG(info.st_mode), f"carrier contains a special entry: {relative}")
-            mode = stat.S_IMODE(info.st_mode)
-            require(
-                mode in (0o444, 0o555),
-                f"carrier file mode must be 0444 or 0555: {relative}: {mode:04o}",
-            )
-            files.add(relative)
-    return files, directories
-
-
-def parse_inventory(root: Path) -> tuple[dict[str, tuple[int, str]], bytes]:
-    inventory_path = root / "payload.files"
-    data, _ = read_regular(inventory_path)
-    try:
-        text = data.decode("utf-8")
-    except UnicodeDecodeError as error:
-        fail(f"payload.files is not UTF-8: {error}")
-    require("\r" not in text, "payload.files contains a carriage return")
-    lines = text.splitlines()
-    require(lines and lines[0] == f"schema={PAYLOAD_SCHEMA}", "payload.files schema mismatch")
-    require(text.endswith("\n"), "payload.files must end in a newline")
-    inventory: dict[str, tuple[int, str]] = {}
-    previous = ""
-    for line_number, line in enumerate(lines[1:], 2):
-        fields = line.split("\t")
-        require(len(fields) == 3, f"payload.files line {line_number} must have three tab-separated fields")
-        digest, size_text, relative_value = fields
-        require(SHA256_RE.fullmatch(digest) is not None, f"invalid SHA-256 on payload.files line {line_number}")
-        require(SIZE_RE.fullmatch(size_text) is not None, f"invalid size on payload.files line {line_number}")
-        relative = checked_relative(relative_value, f"payload.files path on line {line_number}")
-        require(relative != "payload.files", "payload.files must not inventory itself")
-        require(relative > previous, "payload.files paths must be unique and strictly sorted")
-        previous = relative
-        inventory[relative] = (int(size_text), digest)
-    require(inventory, "payload.files contains no carrier entries")
-    return inventory, data
-
-
-def verify_inventory(
-    root: Path,
-    inventory: dict[str, tuple[int, str]],
-    actual_files: set[str],
-    actual_directories: set[str],
-) -> dict[str, tuple[int, str]]:
-    expected_files = set(inventory) | {"payload.files"}
-    missing = sorted(expected_files - actual_files)
-    unexpected = sorted(actual_files - expected_files)
-    require(not missing, f"carrier is missing inventoried files: {missing}")
-    require(not unexpected, f"carrier contains unlisted files: {unexpected}")
-
-    expected_directories: set[str] = set()
-    for relative in expected_files:
-        parent = PurePosixPath(relative).parent
-        while str(parent) != ".":
-            expected_directories.add(str(parent))
-            parent = parent.parent
-    missing_directories = sorted(expected_directories - actual_directories)
-    unexpected_directories = sorted(actual_directories - expected_directories)
-    require(not missing_directories, f"carrier is missing inventory parent directories: {missing_directories}")
-    require(not unexpected_directories, f"carrier contains unrepresented directories: {unexpected_directories}")
-
-    verified: dict[str, tuple[int, str]] = {}
-    for relative in sorted(inventory):
-        info, actual_digest = hash_regular(root.joinpath(*PurePosixPath(relative).parts))
-        expected_size, expected_digest = inventory[relative]
-        require(info.st_size == expected_size, f"payload size mismatch for {relative}")
-        require(actual_digest == expected_digest, f"payload SHA-256 mismatch for {relative}")
-        verified[relative] = (info.st_size, actual_digest)
-    return verified
-
-
-def verified_json(
-    root: Path,
-    relative: str,
-    verified: dict[str, tuple[int, str]],
-    label: str,
-) -> Any:
-    require(relative in verified, f"{label} is not inventoried: {relative}")
-    data, info = read_regular(root.joinpath(*PurePosixPath(relative).parts))
-    require((info.st_size, sha256_bytes(data)) == verified[relative], f"{label} changed after inventory verification")
-    return decode_json(data, label)
-
-
-def parse_receipt(root: Path, verified: dict[str, tuple[int, str]]) -> dict[str, str]:
-    relative = "wasmer-build.receipt"
-    data, info = read_regular(root / relative)
-    require((info.st_size, sha256_bytes(data)) == verified[relative], "Wasmer receipt changed after inventory verification")
-    try:
-        text = data.decode("utf-8")
-    except UnicodeDecodeError as error:
-        fail(f"Wasmer receipt is not UTF-8: {error}")
-    require("\r" not in text and text.endswith("\n"), "Wasmer receipt is not canonical text")
-    lines = text.splitlines()
-    require(len(lines) == len(RECEIPT_KEYS), "Wasmer receipt field count mismatch")
-    receipt: dict[str, str] = {}
-    for expected_key, line in zip(RECEIPT_KEYS, lines, strict=True):
-        require(line.count("=") == 1, f"invalid Wasmer receipt field: {line!r}")
-        key, value = line.split("=", 1)
-        require(key == expected_key and value != "", f"non-canonical Wasmer receipt field: expected {expected_key}")
-        receipt[key] = value
-    return receipt
-
-
-def parse_postmaster_executor_receipt(
-    root: Path,
-    verified: dict[str, tuple[int, str]],
-    wasmer_receipt: dict[str, str],
-) -> dict[str, str]:
-    require(
-        POSTMASTER_EXECUTOR_RECEIPT_PATH in verified,
-        "carrier must contain the postmaster product executor receipt",
-    )
-    relative = POSTMASTER_EXECUTOR_RECEIPT_PATH
-    data, info = read_regular(root / relative)
-    require(
-        (info.st_size, sha256_bytes(data)) == verified[relative],
-        "postmaster executor receipt changed after inventory verification",
-    )
-    try:
-        text = data.decode("utf-8")
-    except UnicodeDecodeError as error:
-        fail(f"postmaster executor receipt is not UTF-8: {error}")
-    require(
-        "\r" not in text and text.endswith("\n"),
-        "postmaster executor receipt is not canonical text",
-    )
-    lines = text.splitlines()
-    require(
-        len(lines) == len(POSTMASTER_EXECUTOR_RECEIPT_KEYS),
-        "postmaster executor receipt field count mismatch",
-    )
-    receipt: dict[str, str] = {}
-    for expected_key, line in zip(
-        POSTMASTER_EXECUTOR_RECEIPT_KEYS, lines, strict=True
-    ):
-        require(line.count("=") == 1, f"invalid postmaster executor receipt field: {line!r}")
-        key, value = line.split("=", 1)
-        require(
-            key == expected_key and value != "",
-            f"non-canonical postmaster executor receipt field: expected {expected_key}",
-        )
-        receipt[key] = value
-
-    require(
-        receipt["schema"]
-        == "oliphaunt.wasix-postmaster.postmaster-executor-build.v3",
-        "postmaster executor receipt schema mismatch",
-    )
-    for key in (
-        "build_recipe_sha256",
-        "wasmer_build_receipt_sha256",
-        "wasmer_patch_sha256",
-        "wasmer_prepared_signature_sha256",
-        "wasmer_cargo_lock_sha256",
-        "runtime_abi_id",
-        "executor_binary_sha256",
-        "start_proof_binary_sha256",
-        "memory_profile_binary_sha256",
-        "postmaster_compiler_binary_sha256",
-    ):
-        require(
-            SHA256_RE.fullmatch(receipt[key]) is not None,
-            f"postmaster executor receipt {key} is not a SHA-256",
-        )
-    require(
-        receipt["wasmer_build_receipt_sha256"]
-        == verified["wasmer-build.receipt"][1],
-        "postmaster executor receipt does not bind the packaged Wasmer receipt",
-    )
-    for executor_key, wasmer_key in (
-        ("build_recipe_sha256", "build_recipe_sha256"),
-        ("wasmer_source_commit", "wasmer_source_commit"),
-        ("wasmer_patch_sha256", "wasmer_patch_sha256"),
-        ("wasmer_prepared_signature_sha256", "wasmer_prepared_signature_sha256"),
-        ("wasmer_cargo_lock_sha256", "wasmer_cargo_lock_sha256"),
-        ("runtime_abi_id", "runtime_abi_id"),
-        ("artifact_abi_version", "artifact_abi_version"),
-        ("host_platform", "host_platform"),
-        ("host_abi", "host_abi"),
-        ("rustc_host", "rustc_host"),
-        ("rustc_version", "rustc_version"),
-    ):
-        require(
-            receipt[executor_key] == wasmer_receipt[wasmer_key],
-            f"postmaster executor receipt differs from Wasmer receipt: {executor_key}",
-        )
-    require(
-        receipt["executor_package"] == "oliphaunt-wasix-postmaster-executor"
-        and receipt["executor_binary"] == "oliphaunt-wasix-postmaster-executor"
-        and receipt["executor_features"] == "product-executor",
-        "postmaster executor Cargo product identity mismatch",
-    )
-    require(
-        receipt["executor_role"] == "postmaster-product",
-        "postmaster executor role mismatch",
-    )
-    require(
-        receipt["runtime_policy_id"]
-        == "oliphaunt.wasix-postmaster.tokio.2-async.embedded-postmaster-v1-budget96.v2",
-        "postmaster executor runtime policy mismatch",
-    )
-    require(
-        receipt["cli_contract"] == "sealed-postmaster-run-v1",
-        "postmaster executor CLI contract mismatch",
-    )
-    require(
-        receipt["executor_binary_sha256"] == verified["bin/wasmer-headless"][1],
-        "postmaster executor receipt does not identify bin/wasmer-headless",
-    )
-    require(
-        receipt["start_proof_binary"] == "oliphaunt-wasix-start-proof"
-        and receipt["start_proof_features"] == "start-proof-tool"
-        and receipt["start_proof_policy"]
-        == DETERMINISTIC_START_ANALYZER_POLICY,
-        "postmaster executor deterministic-start analyzer identity mismatch",
-    )
-    require(
-        receipt["memory_profile_binary"] == "oliphaunt-wasix-memory-profile"
-        and receipt["memory_profile_features"] == "memory-profile-tool"
-        and receipt["linear_memory_profile_id"] == LINEAR_MEMORY_PROFILE_ID,
-        "postmaster executor linear-memory tool identity mismatch",
-    )
-    require(
-        receipt["postmaster_compiler_binary"]
-        == "oliphaunt-wasix-postmaster-compiler"
-        and receipt["postmaster_compiler_features"] == "product-compiler"
-        and receipt["compiler_cpu_policy"] == "generic-baseline"
-        and receipt["compiler_cpu_features"] == "none",
-        "postmaster product compiler identity mismatch",
-    )
-    return receipt
-
-
-def parse_guest_build_receipt(
-    root: Path, verified: dict[str, tuple[int, str]]
-) -> dict[str, str]:
-    relative = "guest-build.receipt"
-    data, info = read_regular(root / relative)
-    require(
-        (info.st_size, sha256_bytes(data)) == verified[relative],
-        "guest build receipt changed after inventory verification",
-    )
-    try:
-        text = data.decode("utf-8")
-    except UnicodeDecodeError as error:
-        fail(f"guest build receipt is not UTF-8: {error}")
-    require(
-        "\r" not in text and text.endswith("\n"),
-        "guest build receipt is not canonical text",
-    )
-    lines = text.splitlines()
-    require(
-        len(lines) == len(GUEST_BUILD_RECEIPT_KEYS),
-        "guest build receipt field count mismatch",
-    )
-    receipt: dict[str, str] = {}
-    for expected_key, line in zip(GUEST_BUILD_RECEIPT_KEYS, lines, strict=True):
-        require("=" in line, f"invalid guest build receipt field: {line!r}")
-        key, value = line.split("=", 1)
-        require(
-            key == expected_key and value != "",
-            f"non-canonical guest build receipt field: expected {expected_key}",
-        )
-        receipt[key] = value
-    require(
-        receipt["schema"] == "oliphaunt.wasix-postmaster.guest-build.v5",
-        "guest build receipt schema mismatch",
-    )
-    require(
-        receipt["core_profile"] == "release-o3",
-        "guest build receipt core profile lacks a qualified final fence inventory",
-    )
-    require(
-        SHA256_RE.fullmatch(receipt["guest_source_signature_sha256"]) is not None,
-        "guest build source signature is not a SHA-256",
-    )
-    require(
-        receipt["docker_image_id"].startswith("sha256:")
-        and SHA256_RE.fullmatch(receipt["docker_image_id"][len("sha256:") :])
-        is not None,
-        "guest build Docker image ID is not an immutable SHA-256 identity",
-    )
-    require(
-        SHA256_RE.fullmatch(receipt["installed_closure_sha256"]) is not None,
-        "guest build installed closure identity is not a SHA-256",
-    )
-    require(
-        receipt["child_backend"] == "exec",
-        "guest build receipt child backend must be exec",
-    )
-    require(
-        receipt["effective_wasm_opt"] in {"yes", "no"},
-        "guest build receipt wasm-opt mode mismatch",
-    )
-    require(
-        receipt["effective_wasm_opt_suppress_default"] == "yes",
-        "guest build receipt must suppress implicit wasm-opt defaults",
-    )
-    expected_fences = {
-        "atomic_fence_set_latch": "2",
-        "atomic_fence_reset_latch": "1",
-        "atomic_fence_wait_event_set_wait": "1",
-    }
-    for key, expected in expected_fences.items():
-        require(
-            receipt[key] == expected,
-            f"guest build receipt concurrency fence contract mismatch: {key}",
-        )
-    require(
-        re.fullmatch(r"[1-9][0-9]*", receipt["atomic_fence_total"]) is not None,
-        "guest build receipt atomic fence total is not canonical",
-    )
-    require(
-        receipt["latch_state_contract"] == "packed-atomic-v1",
-        "guest build receipt latch-state contract mismatch",
-    )
-    require(
-        SHA256_RE.fullmatch(receipt["final_wasm_concurrency_receipt_sha256"])
-        is not None,
-        "guest build final Wasm concurrency receipt is not a SHA-256",
-    )
-    require(
-        receipt["linear_memory_profile_id"] == LINEAR_MEMORY_PROFILE_ID,
-        "guest build linear-memory profile mismatch",
-    )
-    require(
-        SHA256_RE.fullmatch(receipt["linear_memory_install_receipt_sha256"])
-        is not None,
-        "guest build linear-memory install receipt is not a SHA-256",
-    )
-    return receipt
-
-
-def parse_final_concurrency_receipt(
-    root: Path,
-    verified: dict[str, tuple[int, str]],
-    guest_build_receipt: dict[str, str],
-) -> None:
-    relative = FINAL_CONCURRENCY_RECEIPT_PATH
-    require(
-        relative in verified,
-        "carrier lacks final Wasm concurrency receipt",
-    )
-    data, info = read_regular(root / relative)
-    require(
-        (info.st_size, sha256_bytes(data)) == verified[relative],
-        "final Wasm concurrency receipt changed after inventory verification",
-    )
-    require(
-        verified[relative][1]
-        == guest_build_receipt["final_wasm_concurrency_receipt_sha256"],
-        "final Wasm concurrency receipt differs from guest build receipt",
-    )
-    try:
-        text = data.decode("utf-8")
-    except UnicodeDecodeError as error:
-        fail(f"final Wasm concurrency receipt is not UTF-8: {error}")
-    require(
-        "\r" not in text and text.endswith("\n"),
-        "final Wasm concurrency receipt is not canonical text",
-    )
-    lines = text.splitlines()
-    require(
-        len(lines) == len(FINAL_CONCURRENCY_RECEIPT_KEYS),
-        "final Wasm concurrency receipt field count mismatch",
-    )
-    values: dict[str, str] = {}
-    for expected_key, line in zip(
-        FINAL_CONCURRENCY_RECEIPT_KEYS, lines, strict=True
-    ):
-        require("=" in line, f"invalid final Wasm concurrency field: {line!r}")
-        key, value = line.split("=", 1)
-        require(
-            key == expected_key and value != "",
-            f"non-canonical final Wasm concurrency field: expected {expected_key}",
-        )
-        values[key] = value
-
-    require(
-        values["schema"]
-        == "oliphaunt.wasix-postmaster.final-wasm-concurrency.v1",
-        "final Wasm concurrency receipt schema mismatch",
-    )
-    require(
-        values["postgres_sha256"] == verified["bin/postgres"][1],
-        "final Wasm concurrency receipt does not identify PostgreSQL module",
-    )
-    require(
-        SHA256_RE.fullmatch(values["wasm_dis_sha256"]) is not None,
-        "final Wasm concurrency receipt disassembler identity is not a SHA-256",
-    )
-    require(
-        values["latch_state_contract"] == "packed-atomic-v1",
-        "final Wasm concurrency receipt latch-state contract mismatch",
-    )
-
-    integer_keys = FINAL_CONCURRENCY_RECEIPT_KEYS[5:]
-    integers: dict[str, int] = {}
-    for key in integer_keys:
-        value = values[key]
-        require(
-            value.isascii()
-            and value.isdecimal()
-            and (len(value) == 1 or value[0] != "0"),
-            f"final Wasm concurrency receipt {key} is not a canonical integer",
-        )
-        integers[key] = int(value)
-    require(
-        integers["atomic_fence_total"]
-        == int(guest_build_receipt["atomic_fence_total"]),
-        "final Wasm concurrency receipt fence total mismatch",
-    )
-    expected_exact = {
-        "atomic_fence_set_latch": 2,
-        "atomic_fence_reset_latch": 1,
-        "atomic_fence_wait_event_set_wait": 1,
-        "i32_atomic_rmw_and_reset_latch": 1,
-        "i32_atomic_rmw_and_wait_event_set_wait": 2,
-        "i32_atomic_rmw_or_set_latch": 1,
-        "i32_atomic_rmw_or_wait_event_set_wait": 1,
-    }
-    for key, expected in expected_exact.items():
-        require(
-            integers[key] == expected,
-            f"final Wasm concurrency receipt contract mismatch: {key}",
-        )
-    require(
-        integers["i32_atomic_load_wait_event_set_wait"] >= 1,
-        "final Wasm concurrency receipt waiter has no atomic load",
-    )
-    require(
-        integers["i32_atomic_load_total"]
-        >= integers["i32_atomic_load_wait_event_set_wait"],
-        "final Wasm concurrency receipt atomic load total is inconsistent",
-    )
-    require(
-        integers["i32_atomic_rmw_and_total"] >= 3
-        and integers["i32_atomic_rmw_or_total"] >= 2,
-        "final Wasm concurrency receipt RMW totals are inconsistent",
-    )
-
-
-def exact_int(value: Any, label: str, *, minimum: int = 0) -> int:
-    require(type(value) is int and value >= minimum, f"{label} must be an integer >= {minimum}")
-    return value
-
-
-def validate_deterministic_start_proof(
-    proof: Any, output_sha256: Any, module_sha256: str, label: str
-) -> None:
-    require(
-        isinstance(proof, dict) and set(proof) == DETERMINISTIC_START_PROOF_KEYS,
-        f"{label} fields differ",
-    )
-    require(
-        proof["schema"] == DETERMINISTIC_START_PROOF_SCHEMA,
-        f"{label} schema mismatch",
-    )
-    require(
-        proof["analyzer-policy"] == DETERMINISTIC_START_ANALYZER_POLICY,
-        f"{label} analyzer policy mismatch",
-    )
-    require(
-        proof["module-sha256"] == module_sha256,
-        f"{label} module SHA-256 mismatch",
-    )
-    require(
-        isinstance(proof["proof-sha256"], str)
-        and SHA256_RE.fullmatch(proof["proof-sha256"]) is not None,
-        f"{label} digest is not a lowercase SHA-256",
-    )
-    start_index = exact_int(
-        proof["start-function-index"], f"{label} start function index"
-    )
-    require(start_index <= 0xFFFFFFFF, f"{label} start function index exceeds u32")
-    require(
-        proof["start-function-export"] == "__wasm_init_memory",
-        f"{label} start function export mismatch",
-    )
-    closure = proof["transitive-function-indices"]
-    require(
-        isinstance(closure, list)
-        and len(closure) > 0
-        and all(
-            type(index) is int and 0 <= index <= 0xFFFFFFFF for index in closure
-        )
-        and closure == sorted(set(closure))
-        and start_index in closure,
-        f"{label} transitive function closure is invalid",
-    )
-    require(
-        type(proof["imported-function-calls"]) is int
-        and proof["imported-function-calls"] == 0,
-        f"{label} admits imported function calls",
-    )
-    for field, expected in (
-        ("memory-reads", DETERMINISTIC_START_MEMORY_READS),
-        ("memory-effects", DETERMINISTIC_START_MEMORY_EFFECTS),
-        ("global-effects", DETERMINISTIC_START_GLOBAL_EFFECTS),
-        ("table-effects", DETERMINISTIC_START_TABLE_EFFECTS),
-    ):
-        require(proof[field] == expected, f"{label} {field} policy mismatch")
-    for field in (
-        "requires-fresh-zeroed-memory",
-        "ordinary-start-execution-per-instance",
-        "first-instance-full-byte-validation",
-    ):
-        require(proof[field] is True, f"{label} requires {field}=true")
-    canonical_proof = json.dumps(
-        proof,
-        ensure_ascii=False,
-        sort_keys=True,
-        separators=(",", ":"),
-    ).encode("utf-8")
-    require(
-        isinstance(output_sha256, str)
-        and SHA256_RE.fullmatch(output_sha256) is not None
-        and output_sha256 == sha256_bytes(canonical_proof),
-        f"{label} canonical analyzer output digest mismatch",
-    )
-
-
-def inventory_identity(
-    verified: dict[str, tuple[int, str]], relative: str, label: str
-) -> tuple[int, str]:
-    checked_relative(relative, label)
-    require(relative in verified, f"{label} is not inventoried: {relative}")
-    return verified[relative]
-
-
-def source_fingerprint(root: Path, verified: dict[str, tuple[int, str]]) -> str:
-    digest = hashlib.sha256()
-    for subtree in ("bin", "lib", "share"):
-        subtree_root = root / subtree
-        for current, directories, files in os.walk(subtree_root, followlinks=False):
-            directories.sort()
-            files.sort()
-            for name in files:
-                relative = Path(current, name).relative_to(root).as_posix()
-                if relative == "bin/wasmer-headless":
-                    continue
-                size, file_digest = verified[relative]
-                for value in (relative, str(size), file_digest):
-                    encoded = value.encode("utf-8")
-                    digest.update(len(encoded).to_bytes(8, "big"))
-                    digest.update(encoded)
-    return digest.hexdigest()
-
-
-def guest_installed_closure_identity(
-    verified: dict[str, tuple[int, str]],
-) -> str:
-    selected = sorted(
-        set(REQUIRED_MODULES)
-        | {path for path in verified if path.startswith("share/postgresql/")}
-    )
-    try:
-        return installed_closure_identity_from_records(
-            [(path, verified[path][0], verified[path][1]) for path in selected]
-        )
-    except (KeyError, ProvenanceError) as error:
-        fail(f"cannot derive guest installed closure identity: {error}")
-
-
-def verify_layout(verified: dict[str, tuple[int, str]]) -> None:
-    require(
-        {path for path in verified if "/" not in path}
-        == {
-            "guest-build.receipt",
-            "manifest.json",
-            "postmaster-executor.receipt",
-            "wasmer-build.receipt",
-        },
-        "carrier root contains an unexpected inventoried file",
-    )
-    require(
-        {path for path in verified if path.startswith("bin/")}
-        == {"bin/initdb", "bin/postgres", "bin/wasmer-headless"},
-        "carrier bin/ closure differs",
-    )
-    require(
-        {path for path in verified if path.startswith("lib/")}
-        == {
-            path
-            for relative, aliases in SIDE_MODULE_POLICY
-            for path in (relative, *aliases)
-        },
-        "carrier lib/ closure differs",
-    )
-    require(any(path.startswith("share/postgresql/") for path in verified), "carrier PostgreSQL share tree is empty")
-    require(
-        all(
-            path.startswith(("bin/", "lib/", "share/postgresql/", "aot/", "memory/"))
-            or path in {
-                "guest-build.receipt",
-                "manifest.json",
-                "postmaster-executor.receipt",
-                "wasmer-build.receipt",
-            }
-            for path in verified
-        ),
-        "carrier inventory contains a file outside the supported closure",
-    )
-    for relative, aliases in SIDE_MODULE_POLICY:
-        identities = {verified[path] for path in (relative, *aliases)}
-        require(
-            len(identities) == 1,
-            f"carrier aliases do not contain bytes identical to {relative}",
-        )
-
-
-def verify_manifest(
-    root: Path,
-    verified: dict[str, tuple[int, str]],
-    receipt: dict[str, str],
-    postmaster_executor_receipt: dict[str, str],
-    guest_build_receipt: dict[str, str],
-    expected_producer_recipe: str,
-    postgres_version: str,
-    wasmer_version: str,
-    wasmer_wasix_version: str,
-    artifact_abi_version: int,
-) -> None:
-    manifest = verified_json(root, "manifest.json", verified, "sealed manifest")
-    require(isinstance(manifest, dict), "sealed manifest must be a JSON object")
-    require(set(manifest) == TOP_LEVEL_MANIFEST_KEYS, "sealed manifest top-level fields differ")
-    require(manifest["format-version"] == 6, "sealed manifest format version mismatch")
-    require(manifest["schema"] == MANIFEST_SCHEMA, "sealed manifest schema mismatch")
-    require(manifest["source-lane"] == "wasix-postmaster", "sealed manifest source lane mismatch")
-    require(
-        manifest["core-profile"] == "release-o3",
-        "sealed manifest core profile lacks a qualified final fence inventory",
-    )
-    require(
-        manifest["core-profile"] == guest_build_receipt["core_profile"],
-        "sealed manifest core profile differs from the guest build receipt",
-    )
-    require(
-        isinstance(manifest["guest-build-recipe-sha256"], str)
-        and SHA256_RE.fullmatch(manifest["guest-build-recipe-sha256"]) is not None,
-        "sealed manifest guest build recipe is not a SHA-256",
-    )
-    require(
-        manifest["guest-build-recipe-sha256"]
-        == verified["guest-build.receipt"][1],
-        "sealed manifest guest build recipe differs from its inventoried receipt",
-    )
-    require(manifest["postgres-version"] == postgres_version, "sealed manifest PostgreSQL version mismatch")
-    require(
-        guest_build_receipt["postgres_version"] == postgres_version,
-        "guest build receipt PostgreSQL version mismatch",
-    )
-    require(
-        guest_build_receipt["sysroot_variant"] == receipt["sysroot_variant"],
-        "guest build receipt sysroot differs from the Wasmer build receipt",
-    )
-    require(manifest["target-triple"] == receipt["rustc_host"], "sealed manifest target differs from receipt")
-    require(manifest["host-abi"] == receipt["host_abi"], "sealed manifest host ABI differs from receipt")
-    require(manifest["engine"] == "llvm-opta", "sealed manifest producer engine mismatch")
-    require(isinstance(manifest["compiler-config"], str) and manifest["compiler-config"], "sealed compiler config is empty")
-    require(manifest["cpu-policy"] == "generic-baseline", "sealed CPU policy mismatch")
-    require(manifest["cpu-features"] == [], "sealed CPU feature list must be empty")
-    require(manifest["wasmer-version"] == wasmer_version, "sealed Wasmer version mismatch")
-    require(manifest["wasmer-wasix-version"] == wasmer_wasix_version, "sealed Wasmer-WASIX version mismatch")
-    require(manifest["wasmer-source-commit"] == receipt["wasmer_source_commit"], "sealed Wasmer source differs from receipt")
-    require(manifest["wasmer-patch-sha256"] == receipt["wasmer_patch_sha256"], "sealed Wasmer patch differs from receipt")
-    require(manifest["wasmer-cargo-lock-sha256"] == receipt["wasmer_cargo_lock_sha256"], "sealed Cargo.lock differs from receipt")
-    require(exact_int(manifest["artifact-abi-version"], "artifact ABI version") == artifact_abi_version, "sealed artifact ABI mismatch")
-    require(str(artifact_abi_version) == receipt["artifact_abi_version"], "receipt artifact ABI mismatch")
-    require(manifest["runtime-abi-id"] == receipt["runtime_abi_id"], "sealed runtime ABI differs from receipt")
-    require(manifest["producer-recipe-sha256"] == expected_producer_recipe, "sealed AOT producer recipe mismatch")
-    require(manifest["executor-engine"] == "engine-headless", "sealed executor engine mismatch")
-    headless_size, headless_digest = verified["bin/wasmer-headless"]
-    require(manifest["executor-sha256"] == headless_digest, "sealed executor SHA-256 mismatch")
-    expected_executor_digest = postmaster_executor_receipt["executor_binary_sha256"]
-    require(
-        manifest["executor-sha256"] == expected_executor_digest,
-        "sealed executor differs from its role-selected receipt",
-    )
-    require(exact_int(manifest["executor-size"], "executor size", minimum=1) == headless_size, "sealed executor size mismatch")
-    linear_profile = manifest["linear-memory-profile"]
-    require(
-        isinstance(linear_profile, dict)
-        and set(linear_profile) == LINEAR_MEMORY_PROFILE_KEYS,
-        "sealed linear-memory profile fields differ",
-    )
-    expected_linear_profile = {
-        "id": LINEAR_MEMORY_PROFILE_ID,
-        "address-width": "wasm32",
-        "supported-host-pointer-width": "u64",
-        "maximum-pages": 4096,
-        "maximum-bytes": 268435456,
-        "static-bound-pages": 65536,
-        "static-offset-guard-bytes": 2147483648,
-        "static-access-lowering": "wasmer-llvm-unchecked-reservation-and-guard-v1",
-    }
-    for key, expected in expected_linear_profile.items():
-        require(
-            linear_profile[key] == expected,
-            f"sealed linear-memory profile differs: {key}",
-        )
-    linear_receipt_path = linear_profile["install-receipt-path"]
-    require(
-        isinstance(linear_receipt_path, str)
-        and linear_receipt_path
-        == "share/postgresql/wasix-postmaster.linear-memory-profile.receipt.json",
-        "sealed linear-memory install receipt path differs",
-    )
-    linear_receipt_size, linear_receipt_digest = inventory_identity(
-        verified, linear_receipt_path, "linear-memory install receipt"
-    )
-    require(linear_receipt_size > 0, "linear-memory install receipt is empty")
-    require(
-        linear_profile["install-receipt-sha256"] == linear_receipt_digest,
-        "sealed linear-memory install receipt SHA-256 differs",
-    )
-    require(
-        guest_build_receipt["linear_memory_profile_id"] == LINEAR_MEMORY_PROFILE_ID
-        and guest_build_receipt["linear_memory_install_receipt_sha256"]
-        == linear_receipt_digest,
-        "guest build receipt linear-memory binding differs",
-    )
-    linear_receipt = verified_json(
-        root, linear_receipt_path, verified, "linear-memory install receipt"
-    )
-    require(
-        isinstance(linear_receipt, dict)
-        and set(linear_receipt) == LINEAR_MEMORY_INSTALL_KEYS,
-        "linear-memory install receipt fields differ",
-    )
-    receipt_profile_keys = {
-        "profile-id": LINEAR_MEMORY_PROFILE_ID,
-        "address-width": "wasm32",
-        "supported-host-pointer-width": "u64",
-        "maximum-pages": 4096,
-        "maximum-bytes": 268435456,
-        "static-bound-pages": 65536,
-        "static-offset-guard-bytes": 2147483648,
-        "static-access-lowering": "wasmer-llvm-unchecked-reservation-and-guard-v1",
-        "requires-shared": True,
-        "requires-import": "env.memory",
-        "excludes-wasm32-end-wrap": True,
-    }
-    require(
-        linear_receipt["schema"] == LINEAR_MEMORY_INSTALL_SCHEMA,
-        "linear-memory install receipt schema differs",
-    )
-    for key, expected in receipt_profile_keys.items():
-        require(
-            linear_receipt[key] == expected,
-            f"linear-memory install receipt profile differs: {key}",
-        )
-    for key in (
-        "predecessor-export-closure-receipt-sha256",
-        "source-module-closure-sha256",
-        "module-closure-sha256",
-    ):
-        require(
-            isinstance(linear_receipt[key], str)
-            and SHA256_RE.fullmatch(linear_receipt[key]) is not None,
-            f"linear-memory install receipt {key} is not a SHA-256",
-        )
-    linear_modules = linear_receipt["modules"]
-    require(
-        isinstance(linear_modules, list)
-        and exact_int(linear_receipt["module-count"], "linear-memory module count", minimum=1)
-        == len(linear_modules),
-        "linear-memory install receipt module count differs",
-    )
-    linear_modules_by_path: dict[str, dict[str, Any]] = {}
-    for module in linear_modules:
-        require(
-            isinstance(module, dict)
-            and set(module) == LINEAR_MEMORY_INSTALL_MODULE_KEYS,
-            "linear-memory install module fields differ",
-        )
-        path = module["path"]
-        require(
-            isinstance(path, str) and path not in linear_modules_by_path,
-            "linear-memory install module path is invalid or duplicated",
-        )
-        require(
-            SHA256_RE.fullmatch(module["source-module-sha256"]) is not None
-            and SHA256_RE.fullmatch(module["module-sha256"]) is not None,
-            f"linear-memory install module hash differs for {path}",
-        )
-        require(
-            type(module["initial-pages"]) is int
-            and 0 <= module["initial-pages"] <= 4096
-            and module["maximum-pages"] == 4096
-            and module["maximum-bytes"] == 268435456
-            and module["shared"] is True
-            and module["import-module"] == "env"
-            and module["import-name"] == "memory"
-            and module["transformation"]
-            == "pinned-wasixcc-65536-to-embedded-4096-reversible-v1",
-            f"linear-memory install module contract differs for {path}",
-        )
-        linear_modules_by_path[path] = module
-    require(
-        [module["path"] for module in linear_modules]
-        == sorted(linear_modules_by_path),
-        "linear-memory install modules are not path-sorted",
-    )
-    require(
-        linear_memory_closure_sha256(linear_modules, "source-module-sha256")
-        == linear_receipt["source-module-closure-sha256"]
-        and linear_memory_closure_sha256(linear_modules, "module-sha256")
-        == linear_receipt["module-closure-sha256"],
-        "linear-memory install closure SHA-256 differs",
-    )
-    require(
-        linear_receipt["predecessor-export-closure-receipt"]
-        == SEALED_EXPORT_RECEIPT_RELATIVE,
-        "linear-memory predecessor path is not the canonical sealed-export receipt",
-    )
-    _, predecessor_digest = inventory_identity(
-        verified,
-        SEALED_EXPORT_RECEIPT_RELATIVE,
-        "sealed-export predecessor receipt",
-    )
-    require(
-        predecessor_digest
-        == linear_receipt["predecessor-export-closure-receipt-sha256"],
-        "linear-memory predecessor receipt digest differs",
-    )
-    try:
-        validate_export_chain(
-            root,
-            Path(__file__).resolve().parent.parent,
-            {
-                module["path"]: module["source-module-sha256"]
-                for module in linear_modules
-            },
-            verified,
-        )
-    except ExportChainError as error:
-        fail(f"sealed-export predecessor chain differs: {error}")
-    require(manifest["wasm-features"] == ["exceptions", "threads"], "sealed Wasm features mismatch")
-    require(manifest["entrypoint"] == "runtime:postgres", "sealed entrypoint mismatch")
-    require(manifest["source-fingerprint"] == source_fingerprint(root, verified), "sealed source fingerprint mismatch")
-    require(
-        guest_build_receipt["installed_closure_sha256"]
-        == guest_installed_closure_identity(verified),
-        "guest build receipt installed closure differs from the carrier bytes",
-    )
-
-    artifacts = manifest["artifacts"]
-    require(isinstance(artifacts, list) and len(artifacts) == len(EXPECTED_ARTIFACTS), "sealed artifact closure size mismatch")
-    expected_aot: set[str] = set()
-    seen_module_hashes: set[str] = set()
-    for artifact, expected in zip(artifacts, EXPECTED_ARTIFACTS, strict=True):
-        expected_name, expected_kind, expected_module_path, expected_aliases = expected
-        require(isinstance(artifact, dict), f"sealed artifact {expected_name} must be an object")
-        require(set(artifact) == ARTIFACT_KEYS, f"sealed artifact fields differ for {expected_name}")
-        require(artifact["name"] == expected_name, f"sealed artifact name/order mismatch for {expected_name}")
-        require(artifact["kind"] == expected_kind, f"sealed artifact kind mismatch for {expected_name}")
-        require(artifact["module-path"] == expected_module_path, f"sealed module path mismatch for {expected_name}")
-        require(artifact["exec-aliases"] == expected_aliases, f"sealed aliases mismatch for {expected_name}")
-        require(artifact["compressed"] is False, f"sealed artifact must be uncompressed for {expected_name}")
-        module_digest = artifact["module-sha256"]
-        require(isinstance(module_digest, str) and SHA256_RE.fullmatch(module_digest), f"invalid module SHA-256 for {expected_name}")
-        artifact_linear_memory = artifact["linear-memory"]
-        require(
-            isinstance(artifact_linear_memory, dict)
-            and set(artifact_linear_memory) == ARTIFACT_LINEAR_MEMORY_KEYS,
-            f"sealed artifact linear-memory fields differ for {expected_name}",
-        )
-        try:
-            install_record = linear_modules_by_path[expected_module_path]
-        except KeyError:
-            fail(f"linear-memory install receipt has no record for {expected_name}")
-        require(
-            artifact_linear_memory["profile-id"] == LINEAR_MEMORY_PROFILE_ID
-            and artifact_linear_memory["install-receipt-sha256"]
-            == linear_receipt_digest
-            and artifact_linear_memory["source-module-sha256"]
-            == install_record["source-module-sha256"]
-            and install_record["module-sha256"] == module_digest,
-            f"sealed artifact linear-memory binding differs for {expected_name}",
-        )
-        require(module_digest not in seen_module_hashes, f"duplicate module digest for {expected_name}")
-        seen_module_hashes.add(module_digest)
-        expected_artifact_path = f"aot/{module_digest.upper()}.bin"
-        require(artifact["path"] == expected_artifact_path, f"sealed AOT path mismatch for {expected_name}")
-        expected_aot.add(expected_artifact_path)
-        module_size, actual_module_digest = inventory_identity(verified, expected_module_path, f"module path for {expected_name}")
-        artifact_size, actual_artifact_digest = inventory_identity(verified, expected_artifact_path, f"AOT path for {expected_name}")
-        require(actual_module_digest == module_digest, f"module SHA-256 mismatch for {expected_name}")
-        require(exact_int(artifact["module-size"], f"module size for {expected_name}") == module_size, f"module size mismatch for {expected_name}")
-        require(artifact["sha256"] == actual_artifact_digest, f"AOT SHA-256 mismatch for {expected_name}")
-        require(artifact["raw-sha256"] == actual_artifact_digest, f"raw AOT SHA-256 mismatch for {expected_name}")
-        require(exact_int(artifact["raw-size"], f"raw AOT size for {expected_name}") == artifact_size, f"raw AOT size mismatch for {expected_name}")
-
-    require(
-        {path for path in verified if path.startswith("aot/")} == expected_aot,
-        "carrier AOT directory differs from the manifest closure",
-    )
-    require(
-        not any(path.startswith("memory/") for path in verified),
-        "carrier contains unsupported preinitialized-memory payloads",
-    )
-
-
-def recipe_inputs(root: Path) -> None:
-    info = os.lstat(root)
-    require(stat.S_ISDIR(info.st_mode) and not stat.S_ISLNK(info.st_mode), f"carrier root must be a non-symlink directory: {root}")
-    manifest_data, _ = read_regular(root / "manifest.json")
-    manifest = decode_json(manifest_data, "sealed manifest")
-    require(isinstance(manifest, dict), "sealed manifest must be an object")
-    values = (
-        manifest.get("compiler-config"),
-        manifest.get("target-triple"),
-        manifest.get("source-fingerprint"),
-    )
-    for label, value in zip(("compiler-config", "target-triple", "source-fingerprint"), values, strict=True):
-        require(isinstance(value, str) and value and "\n" not in value and "\r" not in value, f"invalid sealed manifest {label}")
-    require(SHA256_RE.fullmatch(values[2]) is not None, "invalid sealed source fingerprint")
-    print(*values, sep="\n")
-
-
-def executor_selection(root: Path) -> None:
-    actual_files, actual_directories = scan_carrier(root)
-    inventory, _ = parse_inventory(root)
-    verified = verify_inventory(
-        root, inventory, actual_files, actual_directories
-    )
-    verify_layout(verified)
-    wasmer_receipt = parse_receipt(root, verified)
-    postmaster_receipt = parse_postmaster_executor_receipt(
-        root, verified, wasmer_receipt
-    )
-    manifest = verified_json(root, "manifest.json", verified, "sealed manifest")
-    require(isinstance(manifest, dict), "sealed manifest must be a JSON object")
-    executor_size, executor_digest = verified["bin/wasmer-headless"]
-    require(
-        manifest.get("executor-sha256") == executor_digest,
-        "sealed manifest does not identify the selected executor",
-    )
-    require(
-        manifest.get("executor-size") == executor_size,
-        "sealed manifest selected executor size differs",
-    )
-    role = "postmaster-product"
-    receipt_path = POSTMASTER_EXECUTOR_RECEIPT_PATH
-    print(
-        role,
-        receipt_path,
-        verified[receipt_path][1],
-        executor_digest,
-        sep="\t",
-    )
-
-
-def verify(arguments: list[str]) -> None:
-    require(len(arguments) == 7, "internal verifier invocation has the wrong argument count")
-    root = Path(arguments[0])
-    expected_producer_recipe = arguments[1]
-    postgres_version = arguments[2]
-    wasmer_version = arguments[3]
-    wasmer_wasix_version = arguments[4]
-    try:
-        artifact_abi_version = int(arguments[5])
-    except ValueError:
-        fail("expected artifact ABI version is not an integer")
-    expected_root = Path(arguments[6])
-    require(root == expected_root, "carrier root changed while canonicalizing")
-    require(SHA256_RE.fullmatch(expected_producer_recipe) is not None, "expected producer recipe is not a SHA-256")
-    actual_files, actual_directories = scan_carrier(root)
-    inventory, _ = parse_inventory(root)
-    verified = verify_inventory(root, inventory, actual_files, actual_directories)
-    verify_layout(verified)
-    receipt = parse_receipt(root, verified)
-    postmaster_executor_receipt = parse_postmaster_executor_receipt(
-        root, verified, receipt
-    )
-    guest_build_receipt = parse_guest_build_receipt(root, verified)
-    parse_final_concurrency_receipt(root, verified, guest_build_receipt)
-    verify_manifest(
-        root,
-        verified,
-        receipt,
-        postmaster_executor_receipt,
-        guest_build_receipt,
-        expected_producer_recipe,
-        postgres_version,
-        wasmer_version,
-        wasmer_wasix_version,
-        artifact_abi_version,
-    )
-
-
-def main() -> int:
-    try:
-        if len(sys.argv) == 3 and sys.argv[1] == "recipe-inputs":
-            recipe_inputs(Path(sys.argv[2]))
-            return 0
-        if len(sys.argv) == 3 and sys.argv[1] == "executor-selection":
-            executor_selection(Path(sys.argv[2]))
-            return 0
-        if len(sys.argv) >= 2 and sys.argv[1] == "verify":
-            verify(sys.argv[2:])
-            return 0
-        fail("usage: verify-sealed-carrier.py recipe-inputs ROOT | executor-selection ROOT | verify ROOT PRODUCER PG WASMER WASIX ABI CANONICAL_ROOT")
-    except (OSError, VerificationError) as error:
-        print(f"sealed carrier verification failed: {error}", file=sys.stderr)
-        return 2
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/lib/verify-sealed-carrier.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/lib/verify-sealed-carrier.test.py
deleted file mode 100644
index ab7741682..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/lib/verify-sealed-carrier.test.py
+++ /dev/null
@@ -1,323 +0,0 @@
-#!/usr/bin/env python3
-
-from __future__ import annotations
-
-import copy
-import hashlib
-import importlib.util
-import json
-import sys
-import tempfile
-import unittest
-from pathlib import Path
-
-
-SCRIPT = Path(__file__).with_name("verify-sealed-carrier.py")
-SPEC = importlib.util.spec_from_file_location("verify_sealed_carrier", SCRIPT)
-assert SPEC is not None and SPEC.loader is not None
-MODULE = importlib.util.module_from_spec(SPEC)
-sys.modules[SPEC.name] = MODULE
-SPEC.loader.exec_module(MODULE)
-
-def sha256(payload: bytes) -> str:
-    return hashlib.sha256(payload).hexdigest()
-
-
-def valid_proof(module_sha256: str = "a" * 64) -> dict[str, object]:
-    return {
-        "schema": MODULE.DETERMINISTIC_START_PROOF_SCHEMA,
-        "analyzer-policy": MODULE.DETERMINISTIC_START_ANALYZER_POLICY,
-        "module-sha256": module_sha256,
-        "proof-sha256": "b" * 64,
-        "start-function-index": 147,
-        "start-function-export": "__wasm_init_memory",
-        "transitive-function-indices": [147, 148],
-        "imported-function-calls": 0,
-        "memory-reads": MODULE.DETERMINISTIC_START_MEMORY_READS,
-        "memory-effects": MODULE.DETERMINISTIC_START_MEMORY_EFFECTS,
-        "global-effects": MODULE.DETERMINISTIC_START_GLOBAL_EFFECTS,
-        "table-effects": MODULE.DETERMINISTIC_START_TABLE_EFFECTS,
-        "requires-fresh-zeroed-memory": True,
-        "ordinary-start-execution-per-instance": True,
-        "first-instance-full-byte-validation": True,
-    }
-
-
-def proof_output_sha256(proof: dict[str, object]) -> str:
-    return sha256(
-        json.dumps(
-            proof,
-            ensure_ascii=False,
-            sort_keys=True,
-            separators=(",", ":"),
-        ).encode("utf-8")
-    )
-
-
-def valid_executor_receipt_values() -> dict[str, str]:
-    return {
-        "schema": "oliphaunt.wasix-postmaster.postmaster-executor-build.v3",
-        "build_recipe_sha256": "1" * 64,
-        "wasmer_build_receipt_sha256": "2" * 64,
-        "wasmer_source_commit": "3" * 40,
-        "wasmer_patch_sha256": "4" * 64,
-        "wasmer_prepared_signature_sha256": "5" * 64,
-        "wasmer_cargo_lock_sha256": "6" * 64,
-        "runtime_abi_id": "7" * 64,
-        "artifact_abi_version": "21",
-        "executor_package": "oliphaunt-wasix-postmaster-executor",
-        "executor_binary": "oliphaunt-wasix-postmaster-executor",
-        "executor_features": "product-executor",
-        "executor_role": "postmaster-product",
-        "runtime_policy_id": (
-            "oliphaunt.wasix-postmaster.tokio.2-async."
-            "embedded-postmaster-v1-budget96.v2"
-        ),
-        "cli_contract": "sealed-postmaster-run-v1",
-        "executor_binary_sha256": "8" * 64,
-        "start_proof_binary": "oliphaunt-wasix-start-proof",
-        "start_proof_features": "start-proof-tool",
-        "start_proof_policy": MODULE.DETERMINISTIC_START_ANALYZER_POLICY,
-        "start_proof_binary_sha256": "9" * 64,
-        "memory_profile_binary": "oliphaunt-wasix-memory-profile",
-        "memory_profile_features": "memory-profile-tool",
-        "linear_memory_profile_id": MODULE.LINEAR_MEMORY_PROFILE_ID,
-        "memory_profile_binary_sha256": "a" * 64,
-        "postmaster_compiler_binary": "oliphaunt-wasix-postmaster-compiler",
-        "postmaster_compiler_features": "product-compiler",
-        "compiler_cpu_policy": "generic-baseline",
-        "compiler_cpu_features": "none",
-        "postmaster_compiler_binary_sha256": "b" * 64,
-        "host_platform": "x86_64-linux",
-        "host_abi": "glibc-2.39",
-        "rustc_host": "x86_64-unknown-linux-gnu",
-        "rustc_version": "rustc 1.90.0",
-    }
-
-
-def render_executor_receipt(values: dict[str, str], keys: tuple[str, ...]) -> bytes:
-    return "".join(f"{key}={values[key]}\n" for key in keys).encode("utf-8")
-
-
-def valid_guest_build_receipt_values() -> dict[str, str]:
-    return {
-        "schema": "oliphaunt.wasix-postmaster.guest-build.v5",
-        "core_profile": "release-o3",
-        "guest_source_signature_sha256": "1" * 64,
-        "docker_image_id": f"sha256:{'2' * 64}",
-        "installed_closure_sha256": "3" * 64,
-        "child_backend": "exec",
-        "effective_cflags": "-O3",
-        "effective_ldflags": "-Wl,--gc-sections",
-        "effective_wasm_opt": "yes",
-        "effective_wasm_opt_flags": "-O3",
-        "effective_wasm_opt_suppress_default": "yes",
-        "atomic_fence_total": "995",
-        "atomic_fence_set_latch": "2",
-        "atomic_fence_reset_latch": "1",
-        "atomic_fence_wait_event_set_wait": "1",
-        "latch_state_contract": "packed-atomic-v1",
-        "final_wasm_concurrency_receipt_sha256": "4" * 64,
-        "linear_memory_profile_id": MODULE.LINEAR_MEMORY_PROFILE_ID,
-        "linear_memory_install_receipt_sha256": "5" * 64,
-        "postgres_tag": "REL_18_1",
-        "postgres_version": "18.1",
-        "sysroot_variant": "upstream-patched",
-    }
-
-
-def render_guest_build_receipt(
-    values: dict[str, str], keys: tuple[str, ...] = MODULE.GUEST_BUILD_RECEIPT_KEYS
-) -> bytes:
-    return "".join(f"{key}={values[key]}\n" for key in keys).encode("utf-8")
-
-
-class DeterministicStartProofTests(unittest.TestCase):
-    def test_accepts_exact_ordinary_start_preserving_contract(self) -> None:
-        proof = valid_proof()
-        MODULE.validate_deterministic_start_proof(
-            proof, proof_output_sha256(proof), "a" * 64, "test proof"
-        )
-
-    def test_rejects_weakened_or_ambiguous_contracts(self) -> None:
-        mutations = (
-            lambda proof: proof.__setitem__("unknown", True),
-            lambda proof: proof.__setitem__("schema", "wrong"),
-            lambda proof: proof.__setitem__("module-sha256", "c" * 64),
-            lambda proof: proof.__setitem__("proof-sha256", "B" * 64),
-            lambda proof: proof.__setitem__("start-function-index", True),
-            lambda proof: proof.__setitem__("start-function-index", 1 << 32),
-            lambda proof: proof.__setitem__(
-                "transitive-function-indices", [148, 147]
-            ),
-            lambda proof: proof.__setitem__("imported-function-calls", False),
-            lambda proof: proof.__setitem__("memory-reads", "none"),
-            lambda proof: proof.__setitem__("table-effects", "table.init"),
-            lambda proof: proof.__setitem__(
-                "ordinary-start-execution-per-instance", False
-            ),
-            lambda proof: proof.__setitem__(
-                "first-instance-full-byte-validation", False
-            ),
-        )
-        for mutate in mutations:
-            with self.subTest(mutation=mutate):
-                proof = copy.deepcopy(valid_proof())
-                mutate(proof)
-                with self.assertRaises(MODULE.VerificationError):
-                    MODULE.validate_deterministic_start_proof(
-                        proof,
-                        proof_output_sha256(proof),
-                        "a" * 64,
-                        "test proof",
-                    )
-
-    def test_rejects_proof_that_differs_from_bound_analyzer_output(self) -> None:
-        proof = valid_proof()
-        with self.assertRaises(MODULE.VerificationError):
-            MODULE.validate_deterministic_start_proof(
-                proof, "c" * 64, "a" * 64, "test proof"
-            )
-
-
-class GuestBuildReceiptV5Tests(unittest.TestCase):
-    def parse(self, payload: bytes) -> dict[str, str]:
-        with tempfile.TemporaryDirectory() as temporary:
-            root = Path(temporary)
-            receipt = root / "guest-build.receipt"
-            receipt.write_bytes(payload)
-            verified = {
-                "guest-build.receipt": (receipt.stat().st_size, sha256(payload))
-            }
-            return MODULE.parse_guest_build_receipt(root, verified)
-
-    def test_accepts_immutable_builder_identity(self) -> None:
-        values = valid_guest_build_receipt_values()
-        self.assertEqual(self.parse(render_guest_build_receipt(values)), values)
-
-    def test_rejects_legacy_schema_and_invalid_builder_identities(self) -> None:
-        for docker_image_id in (
-            "2" * 64,
-            f"sha256:{'A' * 64}",
-            "sha256:short",
-            "sha512:" + "2" * 64,
-        ):
-            with self.subTest(docker_image_id=docker_image_id):
-                values = valid_guest_build_receipt_values()
-                values["docker_image_id"] = docker_image_id
-                with self.assertRaises(MODULE.VerificationError):
-                    self.parse(render_guest_build_receipt(values))
-
-        values = valid_guest_build_receipt_values()
-        values["schema"] = "oliphaunt.wasix-postmaster.guest-build.v4"
-        with self.assertRaises(MODULE.VerificationError):
-            self.parse(render_guest_build_receipt(values))
-
-    def test_rejects_missing_or_reordered_builder_identity(self) -> None:
-        values = valid_guest_build_receipt_values()
-        without_image_id = tuple(
-            key for key in MODULE.GUEST_BUILD_RECEIPT_KEYS if key != "docker_image_id"
-        )
-        with self.assertRaises(MODULE.VerificationError):
-            self.parse(render_guest_build_receipt(values, without_image_id))
-
-        reordered = list(MODULE.GUEST_BUILD_RECEIPT_KEYS)
-        image_index = reordered.index("docker_image_id")
-        reordered[image_index - 1], reordered[image_index] = (
-            reordered[image_index],
-            reordered[image_index - 1],
-        )
-        with self.assertRaises(MODULE.VerificationError):
-            self.parse(render_guest_build_receipt(values, tuple(reordered)))
-
-
-class ExecutorReceiptV3Tests(unittest.TestCase):
-    def verifier_fixture(
-        self, root: Path, values: dict[str, str]
-    ) -> tuple[dict[str, tuple[int, str]], dict[str, str]]:
-        (root / "bin").mkdir()
-        executor = root / "bin" / "wasmer-headless"
-        executor.write_bytes(b"executor\n")
-        values["executor_binary_sha256"] = sha256(executor.read_bytes())
-        wasmer_build = root / "wasmer-build.receipt"
-        wasmer_build.write_bytes(b"wasmer receipt\n")
-        values["wasmer_build_receipt_sha256"] = sha256(wasmer_build.read_bytes())
-        receipt_data = render_executor_receipt(
-            values, MODULE.POSTMASTER_EXECUTOR_RECEIPT_KEYS
-        )
-        receipt = root / MODULE.POSTMASTER_EXECUTOR_RECEIPT_PATH
-        receipt.write_bytes(receipt_data)
-        verified = {
-            "bin/wasmer-headless": (executor.stat().st_size, values["executor_binary_sha256"]),
-            "wasmer-build.receipt": (
-                wasmer_build.stat().st_size,
-                values["wasmer_build_receipt_sha256"],
-            ),
-            MODULE.POSTMASTER_EXECUTOR_RECEIPT_PATH: (
-                receipt.stat().st_size,
-                sha256(receipt_data),
-            ),
-        }
-        wasmer_receipt = {
-            "build_recipe_sha256": values["build_recipe_sha256"],
-            "wasmer_source_commit": values["wasmer_source_commit"],
-            "wasmer_patch_sha256": values["wasmer_patch_sha256"],
-            "wasmer_prepared_signature_sha256": values[
-                "wasmer_prepared_signature_sha256"
-            ],
-            "wasmer_cargo_lock_sha256": values["wasmer_cargo_lock_sha256"],
-            "runtime_abi_id": values["runtime_abi_id"],
-            "artifact_abi_version": values["artifact_abi_version"],
-            "host_platform": values["host_platform"],
-            "host_abi": values["host_abi"],
-            "rustc_host": values["rustc_host"],
-            "rustc_version": values["rustc_version"],
-        }
-        return verified, wasmer_receipt
-
-    def test_verifier_accepts_exact_analyzer_provenance(self) -> None:
-        values = valid_executor_receipt_values()
-        with tempfile.TemporaryDirectory() as temporary:
-            root = Path(temporary)
-            verified, wasmer_receipt = self.verifier_fixture(root, values)
-            self.assertEqual(
-                MODULE.parse_postmaster_executor_receipt(
-                    root, verified, wasmer_receipt
-                ),
-                values,
-            )
-
-    def test_verifier_rejects_legacy_v2_schema_and_weakened_tools(self) -> None:
-        for field, value in (
-            (
-                "schema",
-                "oliphaunt.wasix-postmaster.postmaster-executor-build.v2",
-            ),
-            ("start_proof_binary", "another-tool"),
-            ("start_proof_features", ""),
-            ("start_proof_policy", "unrestricted"),
-            ("start_proof_binary_sha256", "not-a-digest"),
-            ("memory_profile_binary", "another-tool"),
-            ("memory_profile_features", ""),
-            ("linear_memory_profile_id", "unbounded"),
-            ("memory_profile_binary_sha256", "not-a-digest"),
-            ("postmaster_compiler_binary", "another-tool"),
-            ("postmaster_compiler_features", ""),
-            ("compiler_cpu_policy", "host-native"),
-            ("compiler_cpu_features", "avx2"),
-            ("postmaster_compiler_binary_sha256", "not-a-digest"),
-        ):
-            with self.subTest(field=field):
-                values = valid_executor_receipt_values()
-                values[field] = value
-                with tempfile.TemporaryDirectory() as temporary:
-                    root = Path(temporary)
-                    verified, wasmer_receipt = self.verifier_fixture(root, values)
-                    with self.assertRaises(MODULE.VerificationError):
-                        MODULE.parse_postmaster_executor_receipt(
-                            root, verified, wasmer_receipt
-                        )
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/moon.yml b/src/runtimes/liboliphaunt/wasix-postmaster/moon.yml
deleted file mode 100644
index 61704e3df..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/moon.yml
+++ /dev/null
@@ -1,400 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "liboliphaunt-wasix-postmaster"
-language: "c"
-layer: "library"
-stack: "systems"
-tags: ["runtime", "wasix", "wasm", "postgres", "release-product"]
-dependsOn:
-  - id: "artifact-packaging"
-    scope: "build"
-  - id: "postgres18"
-    scope: "build"
-  - id: "source-toolchains"
-    scope: "build"
-  - id: "third-party-shared"
-    scope: "build"
-  - id: "third-party-wasix-postmaster"
-    scope: "build"
-  - id: "liboliphaunt-wasix"
-    scope: "build"
-
-project:
-  title: "liboliphaunt WASIX Postmaster"
-  description: "Concurrent PostgreSQL 18 postmaster runtime with isolated WASIX backends."
-  owner: "oliphaunt"
-  release:
-    component: "liboliphaunt-wasix-postmaster"
-    packagePath: "src/runtimes/liboliphaunt/wasix-postmaster"
-    artifactTargets:
-      preset: "liboliphaunt-wasix-postmaster"
-      targets:
-        - "linux-arm64-gnu"
-        - "linux-x64-gnu"
-        - "macos-arm64"
-
-owners:
-  defaultOwner: "@oliphaunt/wasix"
-  paths:
-    "**/*": ["@oliphaunt/wasix"]
-
-fileGroups:
-  runtime-source:
-    - "runtime/**/*"
-    - "!runtime/**/*.md"
-    - "!runtime/**/*.test.py"
-
-tasks:
-  lint:
-    tags: ["quality", "static", "requires-rust"]
-    script: |
-      set -e
-      python3 src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-source-lock.py
-      while IFS= read -r script; do bash -n "$script"; done < <(find src/runtimes/liboliphaunt/wasix-postmaster -type f -name '*.sh' | LC_ALL=C sort)
-      PYTHONPYCACHEPREFIX=target/moon/liboliphaunt-wasix-postmaster/pycache python3 -m compileall -q src/runtimes/liboliphaunt/wasix-postmaster
-    inputs:
-      - "/rust-toolchain.toml"
-      - "/src/postgres/versions/18/source.toml"
-      - "/src/sources/toolchains/wasix.toml"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "third-party-wasix-postmaster"
-        group: "sources"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/**/*"
-      - "**/*"
-      - "/docs/maintainers/wasix-postmaster.md"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-
-  unit:
-    tags: ["quality", "unit", "requires-rust"]
-    script: |
-      set -e
-      while IFS= read -r test_file; do python3 "$test_file"; done < <(find src/runtimes/liboliphaunt/wasix-postmaster -type f -name '*.test.py' | LC_ALL=C sort)
-      while IFS= read -r test_file; do bash "$test_file"; done < <(find src/runtimes/liboliphaunt/wasix-postmaster -type f -name '*.test.sh' ! -name 'seal-wasix-linear-memory.test.sh' | LC_ALL=C sort)
-    inputs:
-      - "**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-
-  qualify:
-    tags: ["release", "package"]
-    command: "true"
-    deps:
-      - "liboliphaunt-wasix-postmaster:lint"
-      - "liboliphaunt-wasix-postmaster:unit"
-      - "liboliphaunt-wasix-postmaster:runtime-patch-tests"
-      - "liboliphaunt-wasix-postmaster:regression"
-      - "liboliphaunt-wasix-postmaster:release-assets"
-      - "liboliphaunt-wasix-postmaster:immediate-recovery"
-      - "liboliphaunt-wasix-postmaster:linear-memory-integration"
-    inputs: []
-
-  prepare-postgres:
-    tags: ["runtime", "source"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/apply-wasix-core-overlay.sh"
-    deps:
-      - "source-inputs:source-fetch-wasix-postmaster-runtime"
-    inputs:
-      - "/src/postgres/versions/18/source.toml"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/**/*"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/postgres/**/*"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/bin/prepare-baseline.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/bin/apply-wasix-core-overlay.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  prepare-runtime:
-    tags: ["runtime", "source", "rust"]
-    command: "UPSTREAM_WORK_ROOT=$PWD/target/oliphaunt-wasix-postmaster/runtime bash src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/prepare-upstream-checkouts.sh"
-    deps:
-      - "source-inputs:source-fetch-wasix-postmaster-runtime"
-    inputs:
-      - "@group(runtime-source)"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/sources.lock.toml"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  runtime-build:
-    tags: ["runtime", "wasix", "rust", "build"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/build-runtime.sh --build-only"
-    deps:
-      - "liboliphaunt-wasix-postmaster:prepare-runtime"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh"
-      - "@group(runtime-source)"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/sources.lock.toml"
-    outputs:
-      - "/target/oliphaunt-wasix-postmaster/runtime/build/**/*"
-      - "/target/oliphaunt-wasix-postmaster/runtime/wasmer/target/release/wasmer"
-      - "/target/oliphaunt-wasix-postmaster/runtime/wasmer/target/release/wasmer-headless"
-      - "/target/oliphaunt-wasix-postmaster/runtime/postmaster-executor-target/release/oliphaunt-wasix-postmaster-executor"
-      - "/target/oliphaunt-wasix-postmaster/runtime/postmaster-executor-target/release/oliphaunt-wasix-start-proof"
-      - "/target/oliphaunt-wasix-postmaster/runtime/postmaster-executor-target/release/oliphaunt-wasix-memory-profile"
-      - "/target/oliphaunt-wasix-postmaster/runtime/postmaster-compiler-target/release/oliphaunt-wasix-postmaster-compiler"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  runtime-patch-tests:
-    tags: ["runtime", "wasix", "test", "requires-rust"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/build-runtime.sh --tests-only"
-    deps:
-      - "liboliphaunt-wasix-postmaster:prepare-runtime"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh"
-      - "@group(runtime-source)"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/sources.lock.toml"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  configure:
-    tags: ["runtime", "wasix"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.sh --configure-only"
-    deps:
-      - "liboliphaunt-wasix-postmaster:prepare-postgres"
-      - "liboliphaunt-wasix-postmaster:runtime-build"
-    inputs:
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  postgres-build:
-    tags: ["runtime", "wasix", "postgres"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.sh"
-    deps:
-      - "liboliphaunt-wasix-postmaster:configure"
-    inputs:
-      - "/src/postgres/versions/18/source.toml"
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/**/*"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/postgres/**/*"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/bin/build-wasix-core.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-wasm-import.py"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.py"
-    outputs:
-      - "/target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3/**/*"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  runtime-capabilities:
-    tags: ["runtime", "wasix", "rust"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/qualify-runtime-capabilities.sh"
-    deps:
-      - "liboliphaunt-wasix-postmaster:runtime-build"
-    inputs:
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh"
-      - "@group(runtime-source)"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  linear-memory-integration:
-    tags: ["runtime", "wasix", "test"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-linear-memory.test.sh"
-    deps:
-      - "liboliphaunt-wasix-postmaster:runtime-build"
-    inputs:
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-linear-memory.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/bin/seal-wasix-linear-memory.test.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/linear_memory_transaction.py"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/testdata/make-sealed-export-fixture.py"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  initdb-smoke:
-    tags: ["runtime", "wasix", "postgres"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-core.sh"
-    deps:
-      - "liboliphaunt-wasix-postmaster:runtime-capabilities"
-      - "liboliphaunt-wasix-postmaster:postgres-build"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  initdb-stress:
-    tags: ["runtime", "wasix", "postgres", "reliability"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/stress-wasix-initdb.sh --iterations 20"
-    deps:
-      - "liboliphaunt-wasix-postmaster:initdb-smoke"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  smoke:
-    tags: ["runtime", "wasix", "postgres"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/smoke-wasix-concurrent-connections.sh"
-    deps:
-      - "liboliphaunt-wasix-postmaster:initdb-stress"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  regression:
-    tags: ["runtime", "wasix", "postgres", "regression"]
-    command: "WASIX_SKIP_PRECOMPILE=1 WASIX_REGRESS_SUITE_NAME=wasix-regress-acceptance bash src/runtimes/liboliphaunt/wasix-postmaster/bin/run-wasix-regress-subset.sh boolean case copy"
-    deps:
-      - "liboliphaunt-wasix-postmaster:smoke"
-    inputs:
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/bin/run-wasix-regress-subset.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/bin/wasix-make.sh"
-      - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  carrier:
-    tags: ["runtime", "artifact"]
-    script: |
-      set -e
-      export WASIX_CORE_PROFILE=release-o3
-      bash src/runtimes/liboliphaunt/wasix-postmaster/bin/precompile-wasix-core.sh
-      bash src/runtimes/liboliphaunt/wasix-postmaster/bin/build-sealed-headless-carrier.sh
-    deps:
-      - "liboliphaunt-wasix-postmaster:postgres-build"
-      - "liboliphaunt-wasix-postmaster:runtime-capabilities"
-    inputs:
-      - "@group(legal-files)"
-      - "@group(cargo-workspace)"
-      - "**/*"
-      - project: "third-party-wasix-postmaster"
-        group: "sources"
-      - "/src/sources/toolchains/wasix.toml"
-      - project: "artifact-packaging"
-        group: "source"
-    outputs:
-      - "/target/oliphaunt-wasix-postmaster/carriers/**/*"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  release-assets:
-    tags: ["release", "artifact", "in-place-finalizer-input", "ci-wasix-postmaster"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/package-release-assets.sh"
-    deps:
-      - "liboliphaunt-wasix-postmaster:carrier"
-    inputs:
-      - "@group(legal-files)"
-      - "**/*"
-      - project: "third-party-wasix-postmaster"
-        group: "sources"
-      - project: "artifact-packaging"
-        group: "source"
-      - "/target/oliphaunt-wasix-postmaster/carriers/**/*"
-    outputs:
-      - "/target/oliphaunt-wasix-postmaster/release-assets/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  backend-wave-stress:
-    tags: ["runtime", "wasix", "postgres", "reliability"]
-    script: |
-      set -e
-      source src/runtimes/liboliphaunt/wasix-postmaster/lib/common.sh
-      source "$FRESH_ROOT/lib/sealed-carrier.sh"
-      carrier="$(fresh_select_current_sealed_carrier)"
-      bash src/runtimes/liboliphaunt/wasix-postmaster/bin/stress-wasix-backend-waves.sh \
-        --sealed-carrier "$carrier" \
-        --attempts 10
-    deps:
-      - "liboliphaunt-wasix-postmaster:carrier"
-      - "liboliphaunt-wasix-postmaster:regression"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  immediate-recovery:
-    tags: ["runtime", "wasix", "postgres", "recovery"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/qualify-release-carrier.sh"
-    deps:
-      - "liboliphaunt-wasix-postmaster:carrier"
-      - "liboliphaunt-wasix-postmaster:backend-wave-stress"
-    inputs:
-      - "**/*"
-      - "/target/oliphaunt-wasix-postmaster/carriers/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  portable-inputs:
-    tags: ["runtime", "artifact", "ci-wasix-postmaster"]
-    command: "bash src/runtimes/liboliphaunt/wasix-postmaster/bin/package-portable-build-inputs.sh"
-    deps:
-      - "liboliphaunt-wasix-postmaster:postgres-build"
-      - "liboliphaunt-wasix-postmaster:runtime-capabilities"
-    inputs:
-      - "**/*"
-      - project: "third-party-wasix-postmaster"
-        group: "sources"
-      - project: "artifact-packaging"
-        group: "source"
-      - "/target/oliphaunt-wasix-postmaster/install/wasix-core-release-o3/**/*"
-      - "/target/oliphaunt-wasix-postmaster/runtime/build/patched-wasixcc-sysroot/**/*"
-      - "/target/oliphaunt-wasix-postmaster/runtime/build/probes/**/*"
-    outputs:
-      - "/target/oliphaunt-wasix-postmaster/portable-inputs/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/main-optimizations.series b/src/runtimes/liboliphaunt/wasix-postmaster/postgres/main-optimizations.series
deleted file mode 100644
index 53ad692b2..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/main-optimizations.series
+++ /dev/null
@@ -1,15 +0,0 @@
-# Compatible PostgreSQL optimizations owned by the main WASIX runtime.
-#
-# Deliberately excluded from this multi-backend lane:
-# - 0035 and 0036 specialize spinlocks and atomics for the canonical guest
-#   shared by Rust and TypeScript bindings, whose hosts enforce one PostgreSQL
-#   backend execution context per isolated instance.
-# The postmaster and its backends coordinate concurrently through shared
-# memory, so this lane retains PostgreSQL's normal spinlock and atomic paths.
-0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch
-0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch
-0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch
-0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch
-0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch
-0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch
-0037-oliphaunt-wasix-buffer-strong-random.patch
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0008-wasix-packed-atomic-latch-state.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0008-wasix-packed-atomic-latch-state.test.py
deleted file mode 100755
index c2a2ecac8..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/0008-wasix-packed-atomic-latch-state.test.py
+++ /dev/null
@@ -1,277 +0,0 @@
-#!/usr/bin/env python3
-
-"""Static and optional REL_18_4 apply checks for the packed latch state."""
-
-from __future__ import annotations
-
-import argparse
-import re
-import subprocess
-import tempfile
-import tomllib
-from pathlib import Path
-
-
-PATCH_DIR = Path(__file__).resolve().parent
-PROJECT_ROOT = PATCH_DIR.parents[1]
-PATCH_NAME = "0008-wasix-packed-atomic-latch-state.patch"
-PATCH_PATH = PATCH_DIR / PATCH_NAME
-FEATURE = "PG_WASIX_ATOMIC_LATCH_STATE"
-
-
-def require(condition: bool, message: str) -> None:
-    if not condition:
-        raise AssertionError(message)
-
-
-def require_text(contents: str, expected: str) -> None:
-    require(expected in contents, f"patch lacks required text: {expected}")
-
-
-def function_body(contents: str, start: str, end: str) -> str:
-    start_offset = contents.index(start)
-    end_offset = contents.index(end, start_offset + len(start))
-    return contents[start_offset:end_offset]
-
-
-def assert_order(contents: str, *needles: str) -> None:
-    cursor = 0
-    for needle in needles:
-        offset = contents.find(needle, cursor)
-        require(offset >= 0, f"wrong or missing operation order: {needles}")
-        cursor = offset + len(needle)
-
-
-def run_git_apply_check(source: Path, patches: list[Path], label: str) -> None:
-    result = subprocess.run(
-        ["git", "-C", str(source), "apply", "--check", *map(str, patches)],
-        check=False,
-        capture_output=True,
-        text=True,
-    )
-    require(
-        result.returncode == 0,
-        f"{label} does not apply to {source}: {result.stdout}{result.stderr}",
-    )
-
-
-def run_full_series_apply_check(source: Path, patches: list[Path]) -> None:
-    with tempfile.TemporaryDirectory(prefix="pg-packed-latch-series-") as temporary:
-        checkout = Path(temporary) / "postgres"
-        added = subprocess.run(
-            ["git", "-C", str(source), "worktree", "add", "--detach", str(checkout), "HEAD"],
-            check=False,
-            capture_output=True,
-            text=True,
-        )
-        require(
-            added.returncode == 0,
-            f"could not create isolated series worktree: {added.stdout}{added.stderr}",
-        )
-        try:
-            for patch in patches:
-                applied = subprocess.run(
-                    ["git", "-C", str(checkout), "apply", str(patch)],
-                    check=False,
-                    capture_output=True,
-                    text=True,
-                )
-                require(
-                    applied.returncode == 0,
-                    f"ordered full series failed at {patch.name}: "
-                    f"{applied.stdout}{applied.stderr}",
-                )
-        finally:
-            subprocess.run(
-                ["git", "-C", str(source), "worktree", "remove", "--force", str(checkout)],
-                check=False,
-                capture_output=True,
-                text=True,
-            )
-
-
-def main() -> None:
-    parser = argparse.ArgumentParser(description=__doc__)
-    parser.add_argument(
-        "--postgres-source",
-        type=Path,
-        help="optional clean PostgreSQL 18.4 git worktree for apply checks",
-    )
-    options = parser.parse_args()
-
-    patch = PATCH_PATH.read_text(encoding="utf-8")
-    series = [
-        line
-        for line in (PATCH_DIR / "series").read_text(encoding="utf-8").splitlines()
-        if line and not line.startswith("#")
-    ]
-    require(series.count(PATCH_NAME) == 1, "packed-latch patch must occur once")
-    provenance_path = PROJECT_ROOT / "postgres/product-patch-provenance.toml"
-    with provenance_path.open("rb") as handle:
-        provenance = tomllib.load(handle)
-    records = provenance.get("patch", [])
-    record = next(
-        (
-            item
-            for item in records
-            if item.get("path") == f"postgres/patches/{PATCH_NAME}"
-        ),
-        None,
-    )
-    require(record is not None, "packed-latch patch provenance is missing")
-    require(record.get("base_tag") == "REL_18_4", "provenance base tag changed")
-    require(record.get("status") == "guest-correctness-seam", "status changed")
-    require(record.get("feature_macro") == FEATURE, "feature macro changed")
-    require(record.get("native_behavior_preserved") is True, "native guard changed")
-
-    changed_paths = set(re.findall(r"^diff --git a/(\S+) b/(\S+)$", patch, re.MULTILINE))
-    expected_paths = {
-        ("src/backend/storage/ipc/latch.c", "src/backend/storage/ipc/latch.c"),
-        (
-            "src/backend/storage/ipc/waiteventset.c",
-            "src/backend/storage/ipc/waiteventset.c",
-        ),
-        ("src/include/storage/latch.h", "src/include/storage/latch.h"),
-    }
-    require(changed_paths == expected_paths, f"unexpected patch paths: {changed_paths}")
-
-    removed_lines = [
-        line
-        for line in patch.splitlines()
-        if line.startswith("-") and not line.startswith("--- ")
-    ]
-    require(
-        not removed_lines,
-        "the patch must retain every upstream native source line under #else",
-    )
-
-    for expected in (
-        "#ifdef PG_WASIX_ATOMIC_LATCH_STATE",
-        '#error "PG_WASIX_ATOMIC_LATCH_STATE is only supported by the WASIX port"',
-        '#error "PG_WASIX_ATOMIC_LATCH_STATE requires native SC uint32 atomics"',
-        "!defined(HAVE_GCC__SYNC_INT32_CAS)",
-        "pg_atomic_uint32 state;",
-        "uint32\t\tstate_reserved;",
-        "PG_WASIX_LATCH_STATE_SET\t\t((uint32) 1)",
-        "PG_WASIX_LATCH_STATE_SLEEPING\t((uint32) 2)",
-        "sizeof(Latch) == sizeof(PGWasixUpstreamLatchLayout)",
-        "offsetof(Latch, state_reserved) ==",
-        "offsetof(Latch, owner_pid) ==",
-        "__atomic_always_lock_free(sizeof(uint32), 0)",
-        "__atomic_load_n(&latch->state.value, __ATOMIC_SEQ_CST)",
-        "pg_atomic_fetch_or_u32(&latch->state",
-        "pg_atomic_fetch_and_u32(&latch->state",
-        "pg_atomic_fetch_or_u32(&set->latch->state",
-        "pg_atomic_fetch_and_u32(&set->latch->state",
-        "pg_wasix_latch_state_is_set_and_sleeping(set->latch)",
-    ):
-        require_text(patch, expected)
-
-    require(
-        "return pg_atomic_read_u32" not in patch,
-        "the latch predicate must not use PostgreSQL's non-SC read fallback",
-    )
-    require(
-        patch.count("pg_wasix_latch_state_is_set_and_sleeping(set->latch)") == 4,
-        "every epoll, kqueue, poll, and Win32 fallback must use the atomic state",
-    )
-    require(
-        patch.count("set->latch->maybe_sleeping && set->latch->is_set") == 4,
-        "all four upstream platform checks must remain in native #else branches",
-    )
-
-    set_latch = function_body(patch, "SetLatch(Latch *latch)", "ResetLatch(Latch *latch)")
-    assert_order(
-        set_latch,
-        "pg_memory_barrier();",
-        "old_state = pg_atomic_fetch_or_u32",
-        "if (old_state & PG_WASIX_LATCH_STATE_SET)",
-        "pg_memory_barrier();",
-        "if (!(old_state & PG_WASIX_LATCH_STATE_SLEEPING))",
-    )
-    require(
-        set_latch.count("pg_atomic_fetch_or_u32") == 1,
-        "SetLatch must publish and test the packed state once",
-    )
-
-    reset_latch = patch[patch.index("ResetLatch(Latch *latch)") :]
-    assert_order(
-        reset_latch,
-        "Assert(latch->owner_pid == MyProcPid);",
-        "Assert(!pg_wasix_latch_state_is_sleeping(latch));",
-        "pg_atomic_fetch_and_u32(&latch->state",
-        "pg_memory_barrier();",
-    )
-    require(
-        "~PG_WASIX_LATCH_STATE_SET" in reset_latch,
-        "ResetLatch must preserve SLEEPING while clearing SET",
-    )
-
-    wait = function_body(
-        patch,
-        "WaitEventSetWait(WaitEventSet *set, long timeout,",
-        "WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,",
-    )
-    assert_order(
-        wait,
-        "pg_atomic_fetch_or_u32(&set->latch->state",
-        "pg_memory_barrier();",
-        "pg_wasix_latch_state_is_set(set->latch)",
-        "pg_atomic_fetch_and_u32(&set->latch->state",
-        "WaitEventSetWaitBlock(set, cur_timeout",
-        "pg_atomic_fetch_and_u32(&set->latch->state",
-    )
-    require(
-        wait.count("pg_atomic_fetch_or_u32(&set->latch->state") == 1,
-        "the waiter must publish SLEEPING exactly once per wait-loop iteration",
-    )
-    require(
-        wait.count("pg_atomic_fetch_and_u32(&set->latch->state") == 2,
-        "the waiter must retract SLEEPING on the already-set and wake paths",
-    )
-
-    added_lines = [line[1:] for line in patch.splitlines() if line.startswith("+")]
-    added_text = "\n".join(added_lines)
-    for forbidden in ("errno =", "WakeupMyProc(", "WakeupOtherProc(", "kill(", "SetEvent("):
-        require(
-            forbidden not in added_text,
-            f"packed-state code must not alter signal/errno behavior: {forbidden}",
-        )
-
-    if options.postgres_source is not None:
-        source = options.postgres_source.resolve()
-        require((source / ".git").exists() or (source / ".git").is_file(), "not a git worktree")
-        status = subprocess.run(
-            ["git", "-C", str(source), "status", "--porcelain"],
-            check=True,
-            capture_output=True,
-            text=True,
-        ).stdout
-        require(status == "", "PostgreSQL apply-check source must be clean")
-        configure_ac = (source / "configure.ac").read_text(encoding="utf-8")
-        require("AC_INIT([PostgreSQL], [18.4]" in configure_ac, "source is not 18.4")
-
-        run_git_apply_check(source, [PATCH_PATH], "standalone packed-latch patch")
-        run_full_series_apply_check(source, [PATCH_DIR / name for name in series])
-
-        direct_access_paths: set[str] = set()
-        for candidate in (source / "src").rglob("*"):
-            if candidate.suffix not in {".c", ".h"} or not candidate.is_file():
-                continue
-            contents = candidate.read_text(encoding="utf-8", errors="ignore")
-            if "->maybe_sleeping" in contents:
-                direct_access_paths.add(candidate.relative_to(source).as_posix())
-        require(
-            direct_access_paths
-            == {
-                "src/backend/storage/ipc/latch.c",
-                "src/backend/storage/ipc/waiteventset.c",
-            },
-            f"unreviewed direct latch-state access paths: {direct_access_paths}",
-        )
-
-    print("packed atomic latch-state patch checks passed")
-
-
-if __name__ == "__main__":
-    main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/series b/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/series
deleted file mode 100644
index dcb992257..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/postgres/patches/series
+++ /dev/null
@@ -1,5 +0,0 @@
-0001-wasix-use-posix-dsm-not-sysv.patch
-0003-wasix-libpq-static-encoding-shim.patch
-0004-wasix-core-execbackend-initdb-runtime.patch
-0006-wasix-retry-proc-join-on-eintr.patch
-0008-wasix-packed-atomic-latch-state.patch
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/README.md b/src/runtimes/liboliphaunt/wasix-postmaster/runtime/README.md
deleted file mode 100644
index 69bb709e4..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/README.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# Patched WASIX postmaster runtime
-
-This subtree builds the host runtime for
-`liboliphaunt-wasix-postmaster`. Repository-pinned Wasmer and wasix-libc inputs
-are copied into disposable worktrees, patched, tested, and built into a
-compiler-bearing producer plus a compiler-free product executor.
-
-Tracked product inputs are:
-
-- `patches/wasmer/0001-postgres-wasix-blockers.patch`;
-- `patches/wasix-libc/0001-postgres-wasix-blockers.patch`;
-- the current contract inventory in `capabilities.tsv`;
-- focused capability fixtures under `probes/`;
-- preparation, build, verification, and qualification entrypoints under `bin/`.
-
-Immutable upstream checkouts live under
-`target/oliphaunt-sources/checkouts/`. Patched worktrees, sysroots, build
-outputs, caches, and reports live under
-`target/oliphaunt-wasix-postmaster/runtime/` and are never patched into the
-source checkout.
-
-`build-runtime.sh` produces a Wasmer build receipt and a separate product
-executor receipt. Together they bind source pins, patch digests, prepared-tree
-identities, Cargo.lock, sysroot manifests, compiler/executor features, host ABI,
-Rust and LLVM versions, artifact ABI, runtime ABI, CPU policy, and binary
-hashes. Runtime selection never falls back to a stock or `PATH` Wasmer.
-
-The product executor accepts only an independently verified sealed carrier. It
-does not expose the general Wasmer package, registry, network, or compilation
-command graph. AOT production uses an explicit generic CPU baseline; native CPU
-tuning is rejected for release carriers.
-
-From the repository root:
-
-```sh
-moon run source-inputs:source-fetch-wasix-postmaster-runtime
-moon run liboliphaunt-wasix-postmaster:prepare-runtime
-moon run liboliphaunt-wasix-postmaster:runtime-build
-moon run liboliphaunt-wasix-postmaster:runtime-patch-tests
-moon run liboliphaunt-wasix-postmaster:runtime-capabilities
-```
-
-The architectural and operational rationale is maintained in
-`docs/maintainers/wasix-postmaster.md`.
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/build-runtime.sh b/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/build-runtime.sh
deleted file mode 100755
index 2414e7638..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/build-runtime.sh
+++ /dev/null
@@ -1,1285 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-FRESH_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
-source "$FRESH_ROOT/lib/common.sh"
-
-mode="all"
-case "${1:-}" in
-	"") ;;
-	--build-only) mode="build"; shift ;;
-	--tests-only) mode="tests"; shift ;;
-	*) printf 'unknown argument: %s\n' "$1" >&2; exit 2 ;;
-esac
-[ "$#" -eq 0 ] || {
-	printf 'unexpected argument: %s\n' "$1" >&2
-	exit 2
-}
-
-UPSTREAM_WORK_ROOT="${UPSTREAM_WORK_ROOT:-$FRESH_WORK_ROOT/runtime}"
-WASMER_ROOT="${WASMER_ROOT:-$UPSTREAM_WORK_ROOT/wasmer}"
-LLVM_MAJOR=22
-WASMER_PATCH="$FRESH_ROOT/runtime/patches/wasmer/0001-postgres-wasix-blockers.patch"
-WASIX_LIBC_PATCH="$FRESH_ROOT/runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
-WASMER_BUILD_RECEIPT_OUT="${WASMER_BUILD_RECEIPT_OUT:-$FRESH_WASMER_BUILD_RECEIPT}"
-POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT="${POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT:-$FRESH_POSTMASTER_EXECUTOR_BUILD_RECEIPT}"
-WASMER_TARGET_DIR="$WASMER_ROOT/target"
-POSTMASTER_EXECUTOR_TARGET_DIR="$FRESH_POSTMASTER_EXECUTOR_TARGET_DIR"
-POSTMASTER_COMPILER_TARGET_DIR="$FRESH_POSTMASTER_COMPILER_TARGET_DIR"
-PORTABLE_INPUTS="${OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS:-0}"
-
-case "$PORTABLE_INPUTS" in
-	0|1) ;;
-	*)
-		printf 'OLIPHAUNT_WASIX_POSTMASTER_PORTABLE_INPUTS must be 0 or 1\n' >&2
-		exit 2
-		;;
-esac
-
-if [ -n "${CARGO_TARGET_DIR:-}" ] || [ -n "${CARGO_BUILD_TARGET:-}" ] ||
-	{ [ -n "${CARGO_INCREMENTAL:-}" ] && [ "$CARGO_INCREMENTAL" != 0 ]; }; then
-	printf 'build-runtime.sh owns Cargo target selection and disables incremental compilation; unset CARGO_TARGET_DIR/CARGO_BUILD_TARGET and use CARGO_INCREMENTAL=0\n' >&2
-	exit 2
-fi
-export CARGO_INCREMENTAL=0
-
-find_llvm_prefix() {
-	local candidate
-	local version
-
-	if [ -n "${LLVM_SYS_221_PREFIX:-}" ]; then
-		printf '%s\n' "$LLVM_SYS_221_PREFIX"
-		return
-	fi
-
-	for candidate in llvm-config-22 llvm-config; do
-		if ! command -v "$candidate" >/dev/null 2>&1; then
-			continue
-		fi
-		version="$("$candidate" --version 2>/dev/null || true)"
-		case "$version" in
-			22|22.*)
-				"$candidate" --prefix
-				return
-				;;
-		esac
-	done
-
-	printf 'Wasmer LLVM builds require LLVM %s. Set LLVM_SYS_221_PREFIX or install llvm-config-%s.\n' \
-		"$LLVM_MAJOR" "$LLVM_MAJOR" >&2
-	return 2
-}
-
-require_listed_test() {
-	local listing="$1"
-	local expected="$2"
-
-	case "$listing" in
-		*"$expected: test"*) ;;
-		*)
-			printf 'required focused test filter did not list %s\n' "$expected" >&2
-			exit 2
-			;;
-	esac
-}
-
-require_listed_tests() {
-	local listing="$1"
-	shift
-	local expected
-	for expected in "$@"; do
-		require_listed_test "$listing" "$expected"
-	done
-}
-
-fresh_require_command cargo
-fresh_require_command git
-fresh_require_command python3
-fresh_validate_postmaster_task_budget_profile
-
-python3 "$FRESH_ROOT/runtime/bin/verify-source-lock.py"
-
-LLVM_SYS_221_PREFIX="$(find_llvm_prefix)"
-export LLVM_SYS_221_PREFIX
-
-UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
-	"$FRESH_ROOT/runtime/bin/prepare-upstream-checkouts.sh"
-[ -f "$WASMER_ROOT/lib/cli/Cargo.toml" ] || {
-	printf 'missing prepared Wasmer checkout: %s\n' "$WASMER_ROOT" >&2
-	exit 2
-}
-while IFS=$'\t' read -r capability _owner _basis source_paths _rest; do
-	case "${capability:-}" in ''|'#'*) continue ;; esac
-	IFS=';' read -r -a source_refs <<<"$source_paths"
-	for source_ref in "${source_refs[@]}"; do
-		case "$source_ref" in
-			project:*) source_path="$FRESH_ROOT/${source_ref#project:}" ;;
-			wasmer:*) source_path="$WASMER_ROOT/${source_ref#wasmer:}" ;;
-			wasix-libc:*) source_path="$WASIX_LIBC_ROOT/${source_ref#wasix-libc:}" ;;
-			*) printf 'unknown capability source reference: %s\n' "$source_ref" >&2; exit 2 ;;
-		esac
-		[ -e "$source_path" ] || {
-			printf 'missing source for capability %s: %s\n' "$capability" "$source_ref" >&2
-			exit 2
-		}
-	done
-done <"$FRESH_ROOT/runtime/capabilities.tsv"
-wasmer_cargo_lock="$WASMER_ROOT/Cargo.lock"
-[ -f "$wasmer_cargo_lock" ] && [ ! -L "$wasmer_cargo_lock" ] || {
-	printf 'missing regular Wasmer Cargo.lock: %s\n' "$wasmer_cargo_lock" >&2
-	exit 2
-}
-rustc_host="$(rustc -vV | awk '/^host:/ {print $2}')"
-[ -n "$rustc_host" ] || {
-	printf 'rustc did not report a host target\n' >&2
-	exit 2
-}
-runtime_abi_id="$(fresh_runtime_abi_id \
-	"$(fresh_wasmer_bin_hash "$wasmer_cargo_lock")" \
-	"$rustc_host" \
-	"$(fresh_host_arch)" \
-	"$(fresh_host_abi)")"
-export OLIPHAUNT_WASIX_RUNTIME_ABI_ID="$runtime_abi_id"
-
-source_wasmer_version="$(awk '
-	$0 == "[workspace.package]" { in_package = 1; next }
-	in_package && /^\[/ { exit }
-	in_package && $1 == "version" { gsub(/"/, "", $3); print $3; exit }
-' "$WASMER_ROOT/Cargo.toml")"
-source_wasmer_wasix_version="$(awk '
-	$0 == "[package]" { in_package = 1; next }
-	in_package && /^\[/ { exit }
-	in_package && $1 == "version" { gsub(/"/, "", $3); print $3; exit }
-' "$WASMER_ROOT/lib/wasix/Cargo.toml")"
-[ "$source_wasmer_version" = "$FRESH_WASMER_VERSION" ] || {
-	printf 'prepared Wasmer version mismatch: expected %s, got %s\n' \
-		"$FRESH_WASMER_VERSION" "${source_wasmer_version:-}" >&2
-	exit 2
-}
-[ "$source_wasmer_wasix_version" = "$FRESH_WASMER_WASIX_VERSION" ] || {
-	printf 'prepared wasmer-wasix version mismatch: expected %s, got %s\n' \
-		"$FRESH_WASMER_WASIX_VERSION" "${source_wasmer_wasix_version:-}" >&2
-	exit 2
-}
-
-if [ "$mode" != build ]; then
-"$WASMER_ROOT/lib/oliphaunt-wasix-postmaster-executor/tests/check-dependency-policy.sh"
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	state::preinitialized_memory_image::tests \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'state::preinitialized_memory_image::tests::attested_runtime_validation_is_single_flight' \
-	'state::preinitialized_memory_image::tests::attested_runtime_audit_has_exact_terminal_conservation' \
-	'state::preinitialized_memory_image::tests::attested_runtime_audit_reports_counter_overflow_without_wrapping'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/vm/Cargo.toml" \
-	remap_shared_file_fixed_replaces_only_requested_pages
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/vm/Cargo.toml" \
-	remap_shared_file_fixed_accepts_a_partial_final_file_page
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/vm/Cargo.toml" \
-	remap_private_file_fixed_shares_clean_bytes_but_isolates_writes
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/vm/Cargo.toml" \
-	immutable_function_tables_are_shared_by_two_instances
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/vm/Cargo.toml" \
-	shared_function_tables_outlive_artifact_owner_and_peer_instance
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/vm/Cargo.toml" \
-	instance::allocator::tests::cached_offsets_produce_the_same_allocator_layout \
-	-- \
-	--exact
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/vm/Cargo.toml" \
-	trap::traphandlers::tests::tls_stack_reuses_mapping_without_global_queue \
-	-- \
-	--exact
-if [ "$(uname -s)-$(uname -m)" = Linux-x86_64 ]; then
-	cargo test \
-		--locked \
-		--target-dir "$WASMER_TARGET_DIR" \
-		--manifest-path "$WASMER_ROOT/lib/compiler/Cargo.toml" \
-		engine::code_memory::tests::strict_linux_x86_64::relocated_regular_file_preserves_base_bytes_permissions_and_execution \
-		-- \
-		--exact
-fi
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/compiler/Cargo.toml" \
-	engine::trap::frame_info::tests \
-	--lib
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	shared_memory_mapping \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	state::linker::dynamic_instance_export_tests
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	state::linker::single_slot_broadcast_tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,host-fs,wasmer/cranelift \
-	fs::tests::host_file_size_refresh_observes_another_process_extension \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" \
-	'fs::tests::host_file_size_refresh_observes_another_process_extension'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,host-fs,wasmer/cranelift \
-	fs::tests::host_file_size_refresh_observes_another_process_extension \
-	-- \
-	--exact
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	runtime::sealed_loader_audit::tests
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	state::preinitialized_memory_image::tests
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	syscalls::wasix::path_open2::tests
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
-	host_file_defers_async_descriptor_until_async_io_is_requested
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
-	file_advice
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
-	shared_positioned_read \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'advice_tests::virtual_file_shared_positioned_read_defaults_to_unsupported' \
-	'host_fs::tests::host_file_shared_positioned_reads_are_concurrent_and_cursor_invariant'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
-	shared_positioned_read
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--features wasmer/cranelift \
-	live_shared_mapping_registry_blocks_backing_file_shrink \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" \
-	'state::tests::live_shared_mapping_registry_blocks_backing_file_shrink'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--features wasmer/cranelift \
-	state::tests::live_shared_mapping_registry_blocks_backing_file_shrink \
-	-- \
-	--exact
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--features wasmer/cranelift \
-	utils::store::tests \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'utils::store::tests::sparse_snapshot_restores_imported_main_and_side_module_globals_to_fresh_store' \
-	'utils::store::tests::sparse_snapshot_rejects_shape_mismatch_before_changing_any_global' \
-	'utils::store::tests::const_heavy_store_allocation_scales_with_mutable_globals_only' \
-	'utils::store::tests::persisted_unversioned_dense_snapshot_still_decodes_and_restores' \
-	'utils::store::tests::capture_rejects_mutable_reference_global_before_raw_read' \
-	'utils::store::tests::dense_restore_rejects_reference_shape_before_any_write'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--features wasmer/cranelift \
-	utils::store::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
-	file_writeback \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'advice_tests::file_writeback_flags_preserve_the_linux_abi_bits'
-require_listed_test "$listed_tests" 'advice_tests::virtual_file_writeback_defaults_to_unsupported'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
-	file_writeback
-if [ "$(uname -s)" = Linux ]; then
-	listed_tests="$(cargo test \
-		--locked \
-		--target-dir "$WASMER_TARGET_DIR" \
-		--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
-		host_file_range_writeback \
-		-- \
-		--list)"
-	require_listed_test "$listed_tests" 'host_fs::tests::host_file_range_writeback_uses_existing_descriptor_without_async_clone'
-	require_listed_test "$listed_tests" 'host_fs::tests::host_file_range_writeback_rejects_unrepresentable_ranges'
-	require_listed_test "$listed_tests" 'host_fs::tests::host_file_range_writeback_accepts_maximum_finite_boundary'
-	cargo test \
-		--locked \
-		--target-dir "$WASMER_TARGET_DIR" \
-		--manifest-path "$WASMER_ROOT/lib/virtual-fs/Cargo.toml" \
-		host_file_range_writeback
-fi
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	syscalls::wasi::fd_advise::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	syscalls::wasix::fd_sync_range::tests \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'syscalls::wasix::fd_sync_range::tests::fd_sync_range_read_only_advice_right_is_accepted'
-require_listed_test "$listed_tests" 'syscalls::wasix::fd_sync_range::tests::fd_sync_range_directory_is_badf'
-require_listed_tests "$listed_tests" \
-	'syscalls::wasix::fd_sync_range::tests::fd_sync_range_maps_all_exact_flag_combinations' \
-	'syscalls::wasix::fd_sync_range::tests::fd_sync_range_rejects_negative_overflowing_and_unknown_ranges' \
-	'syscalls::wasix::fd_sync_range::tests::fd_sync_range_preserves_zero_length_and_maximum_finite_range' \
-	'syscalls::wasix::fd_sync_range::tests::fd_sync_range_maps_unsupported_backends_to_nosys'
-if [ "$(uname -s)" = Linux ]; then
-	require_listed_test "$listed_tests" \
-		'syscalls::wasix::fd_sync_range::tests::fd_sync_range_preserves_linux_writeback_errnos'
-fi
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	syscalls::wasix::fd_sync_range::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	required_import_tests \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'required_import_tests::oliphaunt_postmaster_fd_sync_range_has_exact_versioned_abi'
-require_listed_test "$listed_tests" 'required_import_tests::explicit_wasi_import_object_includes_versioned_postmaster_namespace'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	required_import_tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	os::task::control_plane::tests \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::concurrent_parent_waiters_return_one_child_status'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::concurrent_task_reservations_never_oversubscribe_limit'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::duplicate_live_tid_is_rejected_without_count_or_slot_corruption'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::main_thread_admission_failure_cannot_leave_published_process'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::process_wait_status_has_exactly_one_concurrent_consumer'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::public_process_construction_never_publishes_without_a_main_thread'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::retirement_and_child_publication_linearize_without_leaking_permit'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::retirement_seals_a_finished_process_against_new_threads'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::tentative_process_is_invisible_and_abort_releases_last_object'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::unpublished_process_guard_rolls_back_registry_and_parent_link'
-require_listed_test "$listed_tests" 'os::task::control_plane::tests::child_adoption_rejects_a_permit_for_a_different_parent_without_panic'
-require_listed_tests "$listed_tests" \
-	'os::task::control_plane::tests::child_execution_admission_requires_exact_publication' \
-	'os::task::control_plane::tests::failed_launch_rollback_waits_for_real_execution_quiescence' \
-	'os::task::control_plane::tests::process_tree_barrier_waits_for_late_descendant_execution_quiescence' \
-	'os::task::control_plane::tests::process_join_waits_for_pending_child_publication_ownership' \
-	'os::task::control_plane::tests::execution_guard_publishes_terminal_before_quiescence' \
-	'os::task::control_plane::tests::abandoned_host_execution_fails_closed_only_after_last_guard_clone' \
-	'os::task::control_plane::tests::supplemental_parent_guard_requires_an_accepted_successor' \
-	'os::task::control_plane::tests::repeated_parent_switch_guards_remain_bounded_without_a_task_successor' \
-	'os::task::control_plane::tests::unrelated_task_or_thread_cannot_authorize_parent_guard_handoff' \
-	'os::task::control_plane::tests::concurrent_guard_clones_have_one_linearizable_handoff_winner' \
-	'os::task::control_plane::tests::abandoned_non_main_vfork_owner_terminalizes_whole_process_before_quiescence' \
-	'os::task::control_plane::tests::vfork_parent_and_child_ownership_coexist_across_deep_sleep_handoffs' \
-	'os::task::control_plane::tests::panicking_monitor_manager_terminates_and_reaps_before_quiescence'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	os::task::control_plane::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	state::env::tests \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'state::env::tests::reinit_rejects_a_running_epoch_without_mutation'
-require_listed_test "$listed_tests" 'state::env::tests::reinit_rejects_live_background_thread_without_mutating_epoch'
-require_listed_test "$listed_tests" 'state::env::tests::reinit_rejects_live_child_then_reaps_finished_child_exactly'
-require_listed_test "$listed_tests" 'state::env::tests::reinit_cannot_cross_inflight_child_publication'
-require_listed_test "$listed_tests" 'state::env::tests::repeated_reinit_uses_fresh_registered_epoch_and_plateaus_counts'
-require_listed_test "$listed_tests" 'state::env::tests::sealed_epoch_is_terminal_after_later_reset_failure'
-require_listed_test "$listed_tests" 'state::env::tests::public_fork_publishes_and_adopts_before_releasing_parent_permit'
-require_listed_test "$listed_tests" 'state::env::tests::reinit_recursively_retires_finished_grandchildren'
-require_listed_test "$listed_tests" 'state::env::tests::stale_environment_cannot_fork_or_start_threads_after_reinit'
-require_listed_test "$listed_tests" 'state::env::tests::post_seal_main_thread_admission_failure_is_terminal_and_leak_free'
-require_listed_tests "$listed_tests" \
-	'state::env::tests::reinit_requires_terminal_status_and_execution_quiescence' \
-	'state::env::tests::descendant_validation_failure_seals_no_process_in_tree' \
-	'state::env::tests::repeated_child_construction_keeps_main_handle_owned_by_child' \
-	'state::env::tests::retargeted_thread_clone_drops_calling_thread_execution_ownership' \
-	'state::env::tests::swap_inner_uses_exact_physical_owner_for_immediate_and_deferred_restore'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	state::env::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	runtime::task_manager::lifecycle_tests \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'runtime::task_manager::lifecycle_tests::canceled_task_wasm_terminalizes_exact_thread_before_quiescence' \
-	'runtime::task_manager::lifecycle_tests::closed_worker_queue_drops_pending_execution_fail_closed' \
-	'runtime::task_manager::lifecycle_tests::accepted_callback_conversion_is_the_only_successful_disarm' \
-	'runtime::task_manager::lifecycle_tests::accepted_callback_panic_terminalizes_before_quiescence' \
-	'runtime::task_manager::lifecycle_tests::rejected_successor_keeps_predecessor_until_fail_closed_drop' \
-	'runtime::task_manager::lifecycle_tests::deep_sleep_handoff_keeps_thread_live_until_successor_guard_finishes'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	runtime::task_manager::lifecycle_tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	runtime::task_manager::tokio::tests \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'runtime::task_manager::tokio::tests::non_core_workers_retire_after_the_idle_timeout' \
-	'runtime::task_manager::tokio::tests::memory_construction_failure_terminalizes_before_releasing_lease' \
-	'runtime::task_manager::tokio::tests::instantiation_failure_terminalizes_before_releasing_lease' \
-	'runtime::task_manager::tokio::tests::panicking_custom_task_wasm_callback_terminalizes_before_quiescence' \
-	'runtime::task_manager::tokio::tests::accepted_restored_process_adopts_its_single_deferred_parent_guard' \
-	'runtime::task_manager::tokio::tests::task_wasm_constructor_binds_owner_before_manager_instantiation' \
-	'runtime::task_manager::tokio::tests::foreign_pending_token_cannot_accept_same_guest_thread' \
-	'runtime::task_manager::tokio::tests::pending_task_drop_with_deferred_owner_is_fail_closed_and_bounded' \
-	'runtime::task_manager::tokio::tests::module_start_observes_child_parent_after_exact_publication'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	runtime::task_manager::tokio::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	bin_factory::exec::lifecycle_tests \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" \
-	'bin_factory::exec::lifecycle_tests::run_exec_panic_terminalizes_before_releasing_accepted_guard'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	bin_factory::exec::lifecycle_tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	syscalls::wasix::proc_signal::tests \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'syscalls::wasix::proc_signal::tests::absent_pid_returns_srch_for_liveness_probe' \
-	'syscalls::wasix::proc_signal::tests::signal_zero_observes_existing_pid_without_delivery' \
-	'syscalls::wasix::proc_signal::tests::real_signal_delivery_is_unchanged'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	syscalls::wasix::proc_signal::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	state::tests \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'state::tests::shared_memory_mapping_splits_reuse_futex_registry' \
-	'state::tests::shared_futex_registry_uses_containing_mapping_only' \
-	'state::tests::shared_file_identity_survives_file_clone' \
-	'state::tests::shared_futex_registry_reuses_same_live_file' \
-	'state::tests::shared_futex_registry_pins_file_identity_until_last_live_reference' \
-	'state::tests::shared_futex_registry_replaces_entry_after_last_live_drop' \
-	'state::tests::shared_futex_registry_last_drop_racing_lookup_keeps_exact_replacement' \
-	'state::tests::forked_states_share_mapping_registry_and_return_to_zero_plateau' \
-	'state::tests::repeated_shared_futex_registry_churn_returns_to_slot_and_fd_plateau' \
-	'state::tests::shared_futex_registry_old_generation_cannot_remove_replacement' \
-	'state::tests::shared_futex_registry_prunes_stale_slots_in_bounded_order'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	state::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift,ctrlc \
-	os::task::task_join_handle::tests \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" \
-	'os::task::task_join_handle::tests::direct_signal_controller_is_platform_neutral_and_rejects_finished_tasks'
-if [ "$(uname -s)" = Linux ]; then
-	require_listed_test "$listed_tests" \
-		'os::task::task_join_handle::tests::unix_supervisor_real_signals_restore_and_route_exclusively'
-fi
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift,ctrlc \
-	os::task::task_join_handle::tests \
-	-- \
-	--test-threads=1
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift,ctrlc \
-		runners::wasi:: \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'runners::wasi::host_lifecycle_tests::wasi_runner_never_owns_host_lifecycle_by_default' \
-	'runners::wasi::host_lifecycle_tests::lifecycle_bind_failure_kills_and_reaps_spawned_root' \
-	'runners::wasi::host_lifecycle_tests::bind_panic_terminates_and_reaps_spawned_root' \
-	'runners::wasi::host_lifecycle_tests::dropping_admitted_watcher_terminates_and_reaps_spawned_root' \
-	'runners::wasi::tests::direct_root_spawn_has_no_effect_before_watcher_admission'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift,ctrlc \
-		runners::wasi::
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	syscalls::wasix::proc_join::tests \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'syscalls::wasix::proc_join::tests::any_child_blocking_wait_returns_one_serializable_claim'
-require_listed_test "$listed_tests" 'syscalls::wasix::proc_join::tests::blocking_join_payload_survives_beyond_the_deep_sleep_threshold'
-require_listed_test "$listed_tests" 'syscalls::wasix::proc_join::tests::explicit_blocking_wait_claims_and_reaps_before_serialization'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	syscalls::wasix::proc_join::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	fs::fd_list::tests::renumber \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'fs::fd_list::tests::renumber_is_an_atomic_move_and_preserves_source_descriptor_ownership'
-require_listed_test "$listed_tests" 'fs::fd_list::tests::renumber_keeps_epoll_watch_until_moved_descriptor_final_close'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	fs::fd_list::tests::renumber
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	epoll \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'os::epoll::tests::failed_older_mod_cannot_rollback_over_later_subscription'
-require_listed_test "$listed_tests" 'os::epoll::tests::ofd_aware_keys_allow_dup_backed_old_watch_and_reused_numeric_fd'
-require_listed_test "$listed_tests" 'syscalls::wasix::epoll_ctl::tests::failed_mod_rebuilds_active_old_subscription_with_fresh_identity'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/wasix/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features sys-minimal,wasmer/cranelift \
-	epoll
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
-	--test memory \
-	--no-default-features \
-	--features sys,headless \
-	private_file_remap_preserves_memory_base_growth_and_mapping_lifetime \
-	-- \
-	--exact
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--test compilers \
-	--features test-llvm \
-	issues::llvm_rotates_and_atomic_fence_emit_expected_ir \
-	-- \
-	--exact
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--test compilers \
-	--features test-llvm \
-	wast::spec::data_drop0::llvm::llvm \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'wast::spec::data_drop0::llvm::llvm'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--test compilers \
-	--features test-llvm \
-	wast::spec::data_drop0::llvm::llvm \
-	-- \
-	--exact
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--test compilers \
-	--features test-llvm \
-	wast::spec::memory_init::llvm::llvm \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'wast::spec::memory_init::llvm::llvm'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--test compilers \
-	--features test-llvm \
-	wast::spec::memory_init::llvm::llvm \
-	-- \
-	--exact
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/oliphaunt-wasix-postmaster-executor/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features "$FRESH_POSTMASTER_EXECUTOR_FEATURES" \
-	sealed::tests::runtime_policy_identity_ \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'sealed::tests::runtime_policy_identity_requires_the_exact_postmaster_closure' \
-	'sealed::tests::runtime_policy_identity_parser_rejects_unknown_manifest_fields' \
-	'sealed::tests::runtime_policy_identity_selects_only_product_executables'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/oliphaunt-wasix-postmaster-executor/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features "$FRESH_POSTMASTER_EXECUTOR_FEATURES" \
-	sealed::tests::runtime_policy_identity_
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/oliphaunt-wasix-postmaster-executor/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features cranelift,wat \
-	sealed::tests::selected_only_activation_and_success_are_single_flight \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" \
-	'sealed::tests::selected_only_activation_and_success_are_single_flight'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/oliphaunt-wasix-postmaster-executor/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features cranelift,wat \
-	sealed::tests::selected_only_activation_and_success_are_single_flight \
-	-- \
-	--exact
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/oliphaunt-wasix-postmaster-executor/Cargo.toml" \
-	--bin "$FRESH_START_PROOF_BINARY" \
-	--no-default-features \
-	--features "$FRESH_START_PROOF_FEATURES"
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/cli/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features "$FRESH_WASMER_HEADLESS_FEATURES" \
-	commands::run::runtime::tests \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'commands::run::runtime::tests::sealed_postmaster_policy_id_and_worker_configuration_are_stable' \
-	'commands::run::runtime::tests::sealed_postmaster_runtime_has_exactly_two_tokio_workers' \
-	'commands::run::runtime::tests::generic_runtime_policy_retains_tokio_default_worker_selection'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/cli/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features "$FRESH_WASMER_HEADLESS_FEATURES" \
-	commands::run::runtime::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/cli/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features "$FRESH_WASMER_HEADLESS_FEATURES" \
-	commands::run::tests \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'commands::run::tests::headless_stack_size_sets_vm_and_guest_limit'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/cli/Cargo.toml" \
-	--lib \
-	--no-default-features \
-	--features "$FRESH_WASMER_HEADLESS_FEATURES" \
-	commands::run::tests
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
-	--no-default-features \
-	--features "$FRESH_POSTMASTER_EXECUTOR_FEATURES" \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'args::tests::parses_the_complete_closed_product_contract' \
-	'args::tests::denies_unknown_generic_wasmer_options' \
-	'args::tests::required_abi_and_cache_assertions_fail_closed' \
-	'execute::tests::product_runtime_policy_is_declared_at_the_execution_boundary' \
-	'execute::tests::product_runner_applies_the_same_guest_and_host_task_budget' \
-	'runtime::tests::blocking_worker_growth_is_bounded_by_the_host_task_budget' \
-	'runtime::tests::runtime_policy_identity_is_stable' \
-	'runtime::tests::runtime_has_exactly_two_tokio_workers'
-cargo test \
-	--locked \
-	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
-	--no-default-features \
-	--features "$FRESH_POSTMASTER_EXECUTOR_FEATURES"
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
-	--test module \
-	serialized_artifact_inspector
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
-	--test module \
-	detached_module_executes_from_strict_relocated_regular_file_code_memory \
-	-- \
-	--exact
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
-	--test instance \
-	selectively_materialized_exports_remain_available_by_module_identity \
-	-- \
-	--exact
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
-	--test instance \
-	--no-default-features \
-	--features sys,llvm,wat \
-	passive_data_ \
-	-- \
-	--list)"
-require_listed_test "$listed_tests" 'passive_data_drop_is_local_to_each_instance'
-require_listed_test "$listed_tests" 'passive_data_memory_init_preserves_contents_and_bounds'
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
-	--test instance \
-	--no-default-features \
-	--features sys,llvm,wat \
-	passive_data_drop_is_local_to_each_instance \
-	-- \
-	--exact
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
-	--test instance \
-	--no-default-features \
-	--features sys,llvm,wat \
-	passive_data_memory_init_preserves_contents_and_bounds \
-	-- \
-	--exact
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
-	--test module \
-	--no-default-features \
-	--features sys,llvm,wat \
-	detached_artifact_passive_data_has_instance_local_drop_state \
-	-- \
-	--exact
-cargo test \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/api/Cargo.toml" \
-	--test module \
-	detached_mmapped_module_executes_without_retaining_serializable_state \
-	-- \
-	--exact
-listed_tests="$(cargo test \
-	--locked \
-	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
-	--lib \
-	--no-default-features \
-	--features "$FRESH_MEMORY_PROFILE_FEATURES" \
-	memory_profile::wasm_tool::tests \
-	-- \
-	--list)"
-require_listed_tests "$listed_tests" \
-	'memory_profile::wasm_tool::tests::exact_width_u32_leb_encoding_fails_closed' \
-	'memory_profile::wasm_tool::tests::invalid_memory_import_shapes_fail_closed' \
-	'memory_profile::wasm_tool::tests::sealer_changes_only_the_explicit_memory_maximum' \
-	'memory_profile::wasm_tool::tests::sealer_preserves_relocation_width_immediates' \
-	'memory_profile::wasm_tool::tests::selected_profile_is_strictly_below_wasm32_end_wrap'
-cargo test \
-	--locked \
-	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
-	--lib \
-	--no-default-features \
-	--features "$FRESH_MEMORY_PROFILE_FEATURES" \
-	memory_profile::wasm_tool::tests
-fi
-
-if [ "$mode" = tests ]; then
-	printf 'patched Wasmer and Postmaster runtime tests passed\n'
-	exit 0
-fi
-
-cargo build \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/cli/Cargo.toml" \
-	--bin wasmer \
-	--release \
-	--no-default-features \
-	--features "$FRESH_WASMER_COMPILER_FEATURES"
-cargo build \
-	--locked \
-	--target-dir "$WASMER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/lib/cli/Cargo.toml" \
-	--bin wasmer-headless \
-	--release \
-	--no-default-features \
-	--features "$FRESH_WASMER_HEADLESS_FEATURES"
-cargo build \
-	--locked \
-	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
-	--bin "$FRESH_POSTMASTER_EXECUTOR_BINARY" \
-	--release \
-	--no-default-features \
-	--features "$FRESH_POSTMASTER_EXECUTOR_FEATURES"
-cargo build \
-	--locked \
-	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
-	--bin "$FRESH_START_PROOF_BINARY" \
-	--release \
-	--no-default-features \
-	--features "$FRESH_START_PROOF_FEATURES"
-cargo build \
-	--locked \
-	--target-dir "$POSTMASTER_EXECUTOR_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
-	--bin "$FRESH_MEMORY_PROFILE_BINARY" \
-	--release \
-	--no-default-features \
-	--features "$FRESH_MEMORY_PROFILE_FEATURES"
-cargo build \
-	--locked \
-	--target-dir "$POSTMASTER_COMPILER_TARGET_DIR" \
-	--manifest-path "$WASMER_ROOT/Cargo.toml" \
-	--package "$FRESH_POSTMASTER_EXECUTOR_PACKAGE" \
-	--bin "$FRESH_POSTMASTER_COMPILER_BINARY" \
-	--release \
-	--no-default-features \
-	--features "$FRESH_POSTMASTER_COMPILER_FEATURES"
-if [ "$PORTABLE_INPUTS" -eq 1 ]; then
-	UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
-		"$FRESH_ROOT/runtime/bin/build-patched-wasix-libc-sysroot.sh" \
-		--no-build --portable-inputs
-elif [ -f "$WASIXCC_SYSROOT_PREFIX/.oliphaunt-patched-sysroots.manifest" ] && \
-	UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
-	"$FRESH_ROOT/runtime/bin/build-patched-wasix-libc-sysroot.sh" --no-build; then
-	:
-else
-	UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
-	"$FRESH_ROOT/runtime/bin/build-patched-wasix-libc-sysroot.sh"
-fi
-
-UPSTREAM_WORK_ROOT="$UPSTREAM_WORK_ROOT" \
-	"$FRESH_ROOT/runtime/bin/prepare-upstream-checkouts.sh"
-
-wasmer_bin="$WASMER_TARGET_DIR/release/wasmer"
-wasmer_headless_bin="$WASMER_TARGET_DIR/release/wasmer-headless"
-postmaster_executor_bin="$POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_POSTMASTER_EXECUTOR_BINARY"
-start_proof_bin="$POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_START_PROOF_BINARY"
-memory_profile_bin="$POSTMASTER_EXECUTOR_TARGET_DIR/release/$FRESH_MEMORY_PROFILE_BINARY"
-postmaster_compiler_bin="$POSTMASTER_COMPILER_TARGET_DIR/release/$FRESH_POSTMASTER_COMPILER_BINARY"
-carrier_manifest="$WASIXCC_SYSROOT_PREFIX/.oliphaunt-patched-sysroots.manifest"
-variant_manifest="$WASIXCC_SYSROOT/.oliphaunt-patched-sysroot.manifest"
-prepared_signature="$UPSTREAM_WORK_ROOT/.prepared/wasmer.signature"
-libc_prepared_signature="$UPSTREAM_WORK_ROOT/.prepared/wasix-libc.signature"
-for required in \
-	"$wasmer_bin" \
-	"$wasmer_headless_bin" \
-	"$postmaster_executor_bin" \
-	"$start_proof_bin" \
-	"$memory_profile_bin" \
-	"$postmaster_compiler_bin" \
-	"$WASMER_PATCH" \
-	"$WASIX_LIBC_PATCH" \
-	"$carrier_manifest" \
-	"$variant_manifest" \
-	"$prepared_signature" \
-	"$libc_prepared_signature" \
-	"$WASMER_ROOT/Cargo.lock"
-do
-	[ -f "$required" ] || {
-		printf 'missing Wasmer build-receipt input: %s\n' "$required" >&2
-		exit 2
-	}
-done
-
-mkdir -p "$(dirname "$WASMER_BUILD_RECEIPT_OUT")"
-temporary_manifest="$WASMER_BUILD_RECEIPT_OUT.tmp.$$"
-trap 'rm -f "$temporary_manifest"' EXIT
-{
-	printf 'schema=oliphaunt.wasix-postmaster.wasmer-build.v2\n'
-	printf 'build_recipe_sha256=%s\n' "$(fresh_runtime_build_recipe_sha256)"
-	printf 'wasmer_source_commit=%s\n' "$(git -C "$WASMER_ROOT" rev-parse HEAD)"
-	printf 'wasmer_napi_commit=%s\n' "$(git -C "$WASMER_ROOT/lib/napi" rev-parse HEAD)"
-	printf 'wasmer_test_files_commit=%s\n' "$(git -C "$WASMER_ROOT/wasmer-test-files" rev-parse HEAD)"
-	printf 'wasmer_spec_commit=%s\n' "$(git -C "$WASMER_ROOT/tests/wast/spec" rev-parse HEAD)"
-	printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_PATCH")"
-	printf 'wasmer_prepared_signature_sha256=%s\n' "$(fresh_wasmer_bin_hash "$prepared_signature")"
-	printf 'wasmer_cargo_lock_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_ROOT/Cargo.lock")"
-	printf 'wasmer_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$wasmer_bin")"
-	printf 'wasmer_features=%s\n' "$FRESH_WASMER_COMPILER_FEATURES"
-	printf 'wasmer_headless_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$wasmer_headless_bin")"
-	printf 'wasmer_headless_features=%s\n' "$FRESH_WASMER_HEADLESS_FEATURES"
-	printf 'runtime_abi_id=%s\n' "$runtime_abi_id"
-	printf 'artifact_abi_version=%s\n' "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
-	printf 'wasix_libc_source_commit=%s\n' "$(git -C "$UPSTREAM_WORK_ROOT/wasix-libc" rev-parse HEAD)"
-	printf 'wasix_libc_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASIX_LIBC_PATCH")"
-	printf 'wasix_libc_prepared_signature_sha256=%s\n' "$(fresh_wasmer_bin_hash "$libc_prepared_signature")"
-	printf 'sysroot_carrier_manifest_sha256=%s\n' "$(fresh_wasmer_bin_hash "$carrier_manifest")"
-	printf 'sysroot_variant=%s\n' "$WASIXCC_SYSROOT_VARIANT"
-	printf 'sysroot_variant_manifest_sha256=%s\n' "$(fresh_wasmer_bin_hash "$variant_manifest")"
-	printf 'host_platform=%s\n' "$(fresh_host_arch)"
-	printf 'host_abi=%s\n' "$(fresh_host_abi)"
-	printf 'rustc_host=%s\n' "$rustc_host"
-	printf 'rustc_version=%s\n' "$(rustc --version)"
-	printf 'llvm_version=%s\n' "$("$LLVM_SYS_221_PREFIX/bin/llvm-config" --version)"
-} >"$temporary_manifest"
-fresh_validate_wasmer_build_receipt_shape "$temporary_manifest"
-fresh_require_local_wasmer_build_state "$temporary_manifest"
-WASMER_BUILD_RECEIPT="$temporary_manifest" fresh_require_patched_wasmer "$wasmer_bin"
-WASMER_BUILD_RECEIPT="$temporary_manifest" fresh_require_patched_wasmer_headless "$wasmer_headless_bin"
-mv "$temporary_manifest" "$WASMER_BUILD_RECEIPT_OUT"
-trap - EXIT
-WASMER_BUILD_RECEIPT="$WASMER_BUILD_RECEIPT_OUT" fresh_require_patched_wasmer "$wasmer_bin"
-WASMER_BUILD_RECEIPT="$WASMER_BUILD_RECEIPT_OUT" fresh_require_patched_wasmer_headless "$wasmer_headless_bin"
-
-mkdir -p "$(dirname "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT")"
-temporary_executor_receipt="$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT.tmp.$$"
-trap 'rm -f "$temporary_executor_receipt"' EXIT
-{
-	printf 'schema=oliphaunt.wasix-postmaster.postmaster-executor-build.v3\n'
-	printf 'build_recipe_sha256=%s\n' "$(fresh_runtime_build_recipe_sha256)"
-	printf 'wasmer_build_receipt_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_BUILD_RECEIPT_OUT")"
-	printf 'wasmer_source_commit=%s\n' "$(git -C "$WASMER_ROOT" rev-parse HEAD)"
-	printf 'wasmer_patch_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_PATCH")"
-	printf 'wasmer_prepared_signature_sha256=%s\n' "$(fresh_wasmer_bin_hash "$prepared_signature")"
-	printf 'wasmer_cargo_lock_sha256=%s\n' "$(fresh_wasmer_bin_hash "$WASMER_ROOT/Cargo.lock")"
-	printf 'runtime_abi_id=%s\n' "$runtime_abi_id"
-	printf 'artifact_abi_version=%s\n' "$FRESH_WASMER_ARTIFACT_ABI_VERSION"
-	printf 'executor_package=%s\n' "$FRESH_POSTMASTER_EXECUTOR_PACKAGE"
-	printf 'executor_binary=%s\n' "$FRESH_POSTMASTER_EXECUTOR_BINARY"
-	printf 'executor_features=%s\n' "$FRESH_POSTMASTER_EXECUTOR_FEATURES"
-	printf 'executor_role=%s\n' "$FRESH_POSTMASTER_EXECUTOR_ROLE"
-	printf 'runtime_policy_id=%s\n' "$FRESH_POSTMASTER_EXECUTOR_RUNTIME_POLICY_ID"
-	printf 'cli_contract=%s\n' "$FRESH_POSTMASTER_EXECUTOR_CLI_CONTRACT"
-	printf 'executor_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$postmaster_executor_bin")"
-	printf 'start_proof_binary=%s\n' "$FRESH_START_PROOF_BINARY"
-	printf 'start_proof_features=%s\n' "$FRESH_START_PROOF_FEATURES"
-	printf 'start_proof_policy=%s\n' "$FRESH_START_PROOF_POLICY"
-	printf 'start_proof_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$start_proof_bin")"
-	printf 'memory_profile_binary=%s\n' "$FRESH_MEMORY_PROFILE_BINARY"
-	printf 'memory_profile_features=%s\n' "$FRESH_MEMORY_PROFILE_FEATURES"
-	printf 'linear_memory_profile_id=%s\n' "$FRESH_LINEAR_MEMORY_PROFILE_ID"
-	printf 'memory_profile_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$memory_profile_bin")"
-	printf 'postmaster_compiler_binary=%s\n' "$FRESH_POSTMASTER_COMPILER_BINARY"
-	printf 'postmaster_compiler_features=%s\n' "$FRESH_POSTMASTER_COMPILER_FEATURES"
-	printf 'compiler_cpu_policy=generic-baseline\n'
-	printf 'compiler_cpu_features=none\n'
-	printf 'postmaster_compiler_binary_sha256=%s\n' "$(fresh_wasmer_bin_hash "$postmaster_compiler_bin")"
-	printf 'host_platform=%s\n' "$(fresh_host_arch)"
-	printf 'host_abi=%s\n' "$(fresh_host_abi)"
-	printf 'rustc_host=%s\n' "$rustc_host"
-	printf 'rustc_version=%s\n' "$(rustc --version)"
-} >"$temporary_executor_receipt"
-fresh_validate_postmaster_executor_build_receipt_shape "$temporary_executor_receipt"
-fresh_require_patched_postmaster_executor \
-	"$postmaster_executor_bin" \
-	"$temporary_executor_receipt" \
-	"$WASMER_BUILD_RECEIPT_OUT"
-fresh_require_start_proof_tool \
-	"$start_proof_bin" \
-	"$temporary_executor_receipt"
-fresh_require_memory_profile_tool \
-	"$memory_profile_bin" \
-	"$temporary_executor_receipt"
-fresh_require_patched_postmaster_compiler \
-	"$postmaster_compiler_bin" \
-	"$temporary_executor_receipt" \
-	"$WASMER_BUILD_RECEIPT_OUT" \
-	"$postmaster_executor_bin"
-mv "$temporary_executor_receipt" "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
-trap - EXIT
-fresh_require_patched_postmaster_executor \
-	"$postmaster_executor_bin" \
-	"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT" \
-	"$WASMER_BUILD_RECEIPT_OUT"
-fresh_require_start_proof_tool \
-	"$start_proof_bin" \
-	"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
-fresh_require_memory_profile_tool \
-	"$memory_profile_bin" \
-	"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
-fresh_require_patched_postmaster_compiler \
-	"$postmaster_compiler_bin" \
-	"$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT" \
-	"$WASMER_BUILD_RECEIPT_OUT" \
-	"$postmaster_executor_bin"
-
-printf 'built patched Wasmer: %s\n' "$wasmer_bin"
-printf 'Wasmer sha256: %s\n' "$(fresh_wasmer_bin_hash "$wasmer_bin")"
-printf 'built patched headless Wasmer: %s\n' "$wasmer_headless_bin"
-printf 'Headless Wasmer sha256: %s\n' "$(fresh_wasmer_bin_hash "$wasmer_headless_bin")"
-printf 'built postmaster product executor: %s\n' "$postmaster_executor_bin"
-printf 'Postmaster executor sha256: %s\n' "$(fresh_wasmer_bin_hash "$postmaster_executor_bin")"
-printf 'built deterministic-start proof tool: %s\n' "$start_proof_bin"
-printf 'Start proof tool sha256: %s\n' "$(fresh_wasmer_bin_hash "$start_proof_bin")"
-printf 'built linear-memory profile tool: %s\n' "$memory_profile_bin"
-printf 'Linear-memory profile tool sha256: %s\n' "$(fresh_wasmer_bin_hash "$memory_profile_bin")"
-printf 'built postmaster product compiler: %s\n' "$postmaster_compiler_bin"
-printf 'Postmaster product compiler sha256: %s\n' "$(fresh_wasmer_bin_hash "$postmaster_compiler_bin")"
-printf 'Runtime ABI ID: %s\n' "$runtime_abi_id"
-printf 'WASIX libc carrier: %s\n' "$WASIXCC_SYSROOT_PREFIX"
-printf 'Wasmer build receipt: %s\n' "$WASMER_BUILD_RECEIPT_OUT"
-printf 'Receipt sha256: %s\n' "$(fresh_wasmer_bin_hash "$WASMER_BUILD_RECEIPT_OUT")"
-printf 'Postmaster executor build receipt: %s\n' "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT"
-printf 'Postmaster executor receipt sha256: %s\n' \
-	"$(fresh_wasmer_bin_hash "$POSTMASTER_EXECUTOR_BUILD_RECEIPT_OUT")"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.py b/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.py
deleted file mode 100755
index b55acab81..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.py
+++ /dev/null
@@ -1,768 +0,0 @@
-#!/usr/bin/env python3
-
-"""Verify the final PostgreSQL module's latch synchronization instructions.
-
-The PostgreSQL latch fields are ordinary shared-memory fields ordered by
-pg_memory_barrier().  In a Wasm build those barriers are encoded as
-``atomic.fence``.  This verifier deliberately inspects the *final* linked and
-post-processed module: checking C sources, LLVM objects, or an intermediate
-module cannot detect a post-link optimizer that erased the barriers.
-
-For the packed WASIX latch contract, the verifier also streams the final module
-through the pinned Binaryen ``wasm-dis`` and checks that the three critical
-exported functions contain real WebAssembly atomic loads and read/modify/write
-operations.  Text decoding is delegated to Binaryen so instruction bytes in an
-immediate cannot be mistaken for an opcode.
-"""
-
-from __future__ import annotations
-
-import argparse
-import hashlib
-import os
-import pathlib
-import re
-import subprocess
-import sys
-import tempfile
-from collections.abc import Iterable
-
-
-EXPECTED_FUNCTION_FENCES = {
-    "SetLatch": 2,
-    "ResetLatch": 1,
-    "WaitEventSetWait": 1,
-}
-ATOMIC_FENCE_ENCODING = b"\xfe\x03\x00"
-PACKED_LATCH_CONTRACT = "packed-atomic-v1"
-UPSTREAM_LATCH_CONTRACT = "upstream-sig-atomic-v1"
-FINAL_CONTRACT_SCHEMA = "oliphaunt.wasix-postmaster.final-wasm-concurrency.v1"
-FINAL_CONTRACT_RECEIPT = "share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt"
-FINAL_CONTRACT_KEYS = (
-    "schema",
-    "postgres_sha256",
-    "wasm_dis_sha256",
-    "wasm_dis_version",
-    "latch_state_contract",
-    "atomic_fence_total",
-    "atomic_fence_set_latch",
-    "atomic_fence_reset_latch",
-    "atomic_fence_wait_event_set_wait",
-    "i32_atomic_load_total",
-    "i32_atomic_load_wait_event_set_wait",
-    "i32_atomic_rmw_and_total",
-    "i32_atomic_rmw_and_reset_latch",
-    "i32_atomic_rmw_and_wait_event_set_wait",
-    "i32_atomic_rmw_or_total",
-    "i32_atomic_rmw_or_set_latch",
-    "i32_atomic_rmw_or_wait_event_set_wait",
-)
-SHA256_RE = re.compile(r"[0-9a-f]{64}\Z")
-
-WAT_OPCODES = (
-    "atomic.fence",
-    "i32.atomic.load",
-    "i32.atomic.rmw.and",
-    "i32.atomic.rmw.or",
-)
-PACKED_FUNCTION_ATOMICS = {
-    "SetLatch": {
-        "atomic.fence": 2,
-        "i32.atomic.rmw.or": 1,
-    },
-    "ResetLatch": {
-        "atomic.fence": 1,
-        "i32.atomic.rmw.and": 1,
-    },
-    "WaitEventSetWait": {
-        "atomic.fence": 1,
-        "i32.atomic.rmw.and": 2,
-        "i32.atomic.rmw.or": 1,
-    },
-}
-PACKED_FUNCTION_ATOMIC_MINIMUMS = {
-    "WaitEventSetWait": {
-        "i32.atomic.load": 1,
-    },
-}
-
-EXPORT_RE = re.compile(r'^ \(export "([^"]+)" \(func (\$[^ ()]+)\)\)$')
-FUNCTION_RE = re.compile(r"^ \(func (\$[^ ()]+)(?:[ ()]|$)")
-OPCODE_RE = re.compile(
-    r"^ +\((atomic\.fence|i32\.atomic\.load|i32\.atomic\.rmw\.and|"
-    r"i32\.atomic\.rmw\.or)\b"
-)
-
-
-class DecodeError(ValueError):
-    pass
-
-
-def empty_opcode_counts() -> dict[str, int]:
-    return {opcode: 0 for opcode in WAT_OPCODES}
-
-
-def parse_wat_instruction_inventory(
-    lines: Iterable[str],
-) -> tuple[dict[str, int], dict[str, dict[str, int]]]:
-    """Parse the stable, one-expression-per-line format emitted by wasm-dis."""
-
-    target_exports: dict[str, str] = {}
-    target_by_identifier: dict[str, str] = {}
-    function_counts = {
-        name: empty_opcode_counts() for name in EXPECTED_FUNCTION_FENCES
-    }
-    total_counts = empty_opcode_counts()
-    seen_functions: set[str] = set()
-    current_target: str | None = None
-
-    for raw_line in lines:
-        line = raw_line.rstrip("\n")
-        if "\r" in line:
-            raise DecodeError("wasm-dis emitted non-canonical CR text")
-
-        export = EXPORT_RE.fullmatch(line)
-        if export and export.group(1) in EXPECTED_FUNCTION_FENCES:
-            name, identifier = export.groups()
-            if name in target_exports:
-                raise DecodeError(f"wasm-dis emitted duplicate export {name}")
-            if identifier in target_by_identifier:
-                raise DecodeError(
-                    f"critical exports share one function identifier: {identifier}"
-                )
-            target_exports[name] = identifier
-            target_by_identifier[identifier] = name
-
-        function = FUNCTION_RE.match(line)
-        if function:
-            identifier = function.group(1)
-            current_target = target_by_identifier.get(identifier)
-            if current_target is not None:
-                if current_target in seen_functions:
-                    raise DecodeError(
-                        f"wasm-dis emitted duplicate function body for {current_target}"
-                    )
-                seen_functions.add(current_target)
-
-        for opcode in OPCODE_RE.findall(line):
-            total_counts[opcode] += 1
-            if current_target is not None:
-                function_counts[current_target][opcode] += 1
-
-        # Binaryen prints the function's closing parenthesis at indentation 1;
-        # nested expressions are indented further.
-        if line == " )":
-            current_target = None
-
-    missing_exports = set(EXPECTED_FUNCTION_FENCES) - set(target_exports)
-    if missing_exports:
-        raise DecodeError(
-            "wasm-dis lacks critical exports: " + ", ".join(sorted(missing_exports))
-        )
-    missing_bodies = set(EXPECTED_FUNCTION_FENCES) - seen_functions
-    if missing_bodies:
-        raise DecodeError(
-            "wasm-dis lacks critical function bodies: "
-            + ", ".join(sorted(missing_bodies))
-        )
-    return total_counts, function_counts
-
-
-def inspect_with_wasm_dis(
-    path: pathlib.Path, wasm_dis: pathlib.Path
-) -> tuple[dict[str, int], dict[str, dict[str, int]], str, str]:
-    if not wasm_dis.is_file() or not os.access(wasm_dis, os.X_OK):
-        raise DecodeError(f"wasm-dis is not an executable regular file: {wasm_dis}")
-
-    wasm_dis_sha256 = hashlib.sha256(wasm_dis.read_bytes()).hexdigest()
-    try:
-        version_process = subprocess.run(
-            [str(wasm_dis), "--version"],
-            check=False,
-            capture_output=True,
-            text=True,
-            timeout=30,
-        )
-    except (OSError, subprocess.SubprocessError) as error:
-        raise DecodeError(f"could not identify wasm-dis: {error}") from error
-    version = (version_process.stdout + version_process.stderr).strip()
-    if version_process.returncode != 0 or not version or "\n" in version or "\r" in version:
-        raise DecodeError("wasm-dis did not provide one canonical version line")
-
-    try:
-        with tempfile.TemporaryFile(mode="w+t", encoding="utf-8") as error_file:
-            process = subprocess.Popen(
-                [str(wasm_dis), str(path)],
-                stdout=subprocess.PIPE,
-                stderr=error_file,
-                text=True,
-                encoding="utf-8",
-                errors="strict",
-            )
-            assert process.stdout is not None
-            with process.stdout:
-                try:
-                    total_counts, function_counts = parse_wat_instruction_inventory(
-                        process.stdout
-                    )
-                except BaseException:
-                    process.kill()
-                    process.wait()
-                    raise
-            returncode = process.wait()
-            if returncode != 0:
-                error_file.seek(0)
-                detail = error_file.read().strip()
-                raise DecodeError(
-                    f"wasm-dis failed with status {returncode}: {detail or 'no detail'}"
-                )
-    except (OSError, UnicodeError, subprocess.SubprocessError) as error:
-        raise DecodeError(f"could not disassemble final PostgreSQL module: {error}") from error
-
-    return total_counts, function_counts, wasm_dis_sha256, version
-
-
-def verify_packed_atomic_contract(
-    total_counts: dict[str, int],
-    function_counts: dict[str, dict[str, int]],
-) -> None:
-    for name, expected_counts in PACKED_FUNCTION_ATOMICS.items():
-        for opcode, expected in expected_counts.items():
-            actual = function_counts[name][opcode]
-            if actual != expected:
-                raise DecodeError(
-                    f"{name} contains {actual} {opcode} instructions, expected {expected}"
-                )
-    for name, minimum_counts in PACKED_FUNCTION_ATOMIC_MINIMUMS.items():
-        for opcode, minimum in minimum_counts.items():
-            actual = function_counts[name][opcode]
-            if actual < minimum:
-                raise DecodeError(
-                    f"{name} contains {actual} {opcode} instructions, "
-                    f"expected at least {minimum}"
-                )
-
-
-def canonical_receipt(
-    postgres_sha256: str,
-    binary_fence_total: int,
-    total_counts: dict[str, int],
-    function_counts: dict[str, dict[str, int]],
-    wasm_dis_sha256: str,
-    wasm_dis_version: str,
-) -> str:
-    fields = (
-        ("schema", FINAL_CONTRACT_SCHEMA),
-        ("postgres_sha256", postgres_sha256),
-        ("wasm_dis_sha256", wasm_dis_sha256),
-        ("wasm_dis_version", wasm_dis_version),
-        ("latch_state_contract", PACKED_LATCH_CONTRACT),
-        ("atomic_fence_total", str(binary_fence_total)),
-        ("atomic_fence_set_latch", str(function_counts["SetLatch"]["atomic.fence"])),
-        ("atomic_fence_reset_latch", str(function_counts["ResetLatch"]["atomic.fence"])),
-        (
-            "atomic_fence_wait_event_set_wait",
-            str(function_counts["WaitEventSetWait"]["atomic.fence"]),
-        ),
-        ("i32_atomic_load_total", str(total_counts["i32.atomic.load"])),
-        (
-            "i32_atomic_load_wait_event_set_wait",
-            str(function_counts["WaitEventSetWait"]["i32.atomic.load"]),
-        ),
-        ("i32_atomic_rmw_and_total", str(total_counts["i32.atomic.rmw.and"])),
-        (
-            "i32_atomic_rmw_and_reset_latch",
-            str(function_counts["ResetLatch"]["i32.atomic.rmw.and"]),
-        ),
-        (
-            "i32_atomic_rmw_and_wait_event_set_wait",
-            str(function_counts["WaitEventSetWait"]["i32.atomic.rmw.and"]),
-        ),
-        ("i32_atomic_rmw_or_total", str(total_counts["i32.atomic.rmw.or"])),
-        (
-            "i32_atomic_rmw_or_set_latch",
-            str(function_counts["SetLatch"]["i32.atomic.rmw.or"]),
-        ),
-        (
-            "i32_atomic_rmw_or_wait_event_set_wait",
-            str(function_counts["WaitEventSetWait"]["i32.atomic.rmw.or"]),
-        ),
-    )
-    if tuple(key for key, _ in fields) != FINAL_CONTRACT_KEYS:
-        raise DecodeError("internal final concurrency receipt field order differs")
-    for key, value in fields:
-        if not value or "\n" in value or "\r" in value or "=" in key:
-            raise DecodeError(f"non-canonical final contract receipt field: {key}")
-    return "".join(f"{key}={value}\n" for key, value in fields)
-
-
-def read_receipt(path: pathlib.Path) -> dict[str, str]:
-    contents = path.read_text(encoding="utf-8")
-    if not contents.endswith("\n") or "\r" in contents:
-        raise DecodeError("final concurrency receipt is not canonical newline text")
-    lines = contents.splitlines()
-    if len(lines) != len(FINAL_CONTRACT_KEYS):
-        raise DecodeError("final concurrency receipt field count differs")
-    values: dict[str, str] = {}
-    for expected_key, line in zip(FINAL_CONTRACT_KEYS, lines, strict=True):
-        if "=" not in line:
-            raise DecodeError(
-                f"final concurrency receipt field has no separator: {expected_key}"
-            )
-        key, value = line.split("=", 1)
-        if key != expected_key or not value:
-            raise DecodeError(
-                f"non-canonical final concurrency receipt field: {expected_key}"
-            )
-        values[key] = value
-    return values
-
-
-def exact_receipt_integer(values: dict[str, str], key: str) -> int:
-    value = values[key]
-    if not value.isascii() or not value.isdecimal() or (len(value) > 1 and value[0] == "0"):
-        raise DecodeError(f"final concurrency receipt {key} is not a canonical integer")
-    return int(value)
-
-
-def verify_receipt(
-    receipt_path: pathlib.Path,
-    postgres_path: pathlib.Path,
-    expected_fence_total: int,
-) -> dict[str, str]:
-    values = read_receipt(receipt_path)
-    if values["schema"] != FINAL_CONTRACT_SCHEMA:
-        raise DecodeError("final concurrency receipt schema differs")
-    if values["latch_state_contract"] != PACKED_LATCH_CONTRACT:
-        raise DecodeError("final concurrency receipt latch-state contract differs")
-    for key in ("postgres_sha256", "wasm_dis_sha256"):
-        if SHA256_RE.fullmatch(values[key]) is None:
-            raise DecodeError(f"final concurrency receipt {key} is not a SHA-256")
-    actual_postgres_sha256 = hashlib.sha256(postgres_path.read_bytes()).hexdigest()
-    if values["postgres_sha256"] != actual_postgres_sha256:
-        raise DecodeError("final concurrency receipt does not identify PostgreSQL module")
-    if "\n" in values["wasm_dis_version"] or "\r" in values["wasm_dis_version"]:
-        raise DecodeError("final concurrency receipt wasm-dis version is not canonical")
-
-    integers = {
-        key: exact_receipt_integer(values, key)
-        for key in FINAL_CONTRACT_KEYS
-        if key.startswith("atomic_") or key.startswith("i32_atomic_")
-    }
-    if integers["atomic_fence_total"] != expected_fence_total:
-        raise DecodeError("final concurrency receipt fence total differs from contract")
-    expected_exact = {
-        "atomic_fence_set_latch": 2,
-        "atomic_fence_reset_latch": 1,
-        "atomic_fence_wait_event_set_wait": 1,
-        "i32_atomic_rmw_and_reset_latch": 1,
-        "i32_atomic_rmw_and_wait_event_set_wait": 2,
-        "i32_atomic_rmw_or_set_latch": 1,
-        "i32_atomic_rmw_or_wait_event_set_wait": 1,
-    }
-    for key, expected in expected_exact.items():
-        if integers[key] != expected:
-            raise DecodeError(f"final concurrency receipt contract differs: {key}")
-    if integers["i32_atomic_load_wait_event_set_wait"] < 1:
-        raise DecodeError("final concurrency receipt waiter has no atomic load")
-    if (
-        integers["i32_atomic_load_total"]
-        < integers["i32_atomic_load_wait_event_set_wait"]
-    ):
-        raise DecodeError("final concurrency receipt atomic load total is inconsistent")
-    if integers["i32_atomic_rmw_and_total"] < 3:
-        raise DecodeError("final concurrency receipt has too few atomic AND operations")
-    if integers["i32_atomic_rmw_or_total"] < 2:
-        raise DecodeError("final concurrency receipt has too few atomic OR operations")
-    return values
-
-
-def write_receipt(path: pathlib.Path, contents: str) -> None:
-    path.parent.mkdir(parents=True, exist_ok=True)
-    descriptor, temporary_name = tempfile.mkstemp(
-        prefix=f".{path.name}.", dir=path.parent
-    )
-    temporary = pathlib.Path(temporary_name)
-    try:
-        with os.fdopen(descriptor, "w", encoding="utf-8", newline="") as stream:
-            stream.write(contents)
-            stream.flush()
-            os.fsync(stream.fileno())
-        os.chmod(temporary, 0o444)
-        os.replace(temporary, path)
-    finally:
-        if temporary.exists():
-            temporary.unlink()
-
-
-class Reader:
-    def __init__(self, data: bytes, context: str) -> None:
-        self.data = data
-        self.offset = 0
-        self.context = context
-
-    def eof(self) -> bool:
-        return self.offset == len(self.data)
-
-    def byte(self) -> int:
-        if self.offset >= len(self.data):
-            raise DecodeError(f"truncated {self.context}")
-        value = self.data[self.offset]
-        self.offset += 1
-        return value
-
-    def uleb(self, bits: int = 32) -> int:
-        value = 0
-        shift = 0
-        while True:
-            byte = self.byte()
-            value |= (byte & 0x7F) << shift
-            if byte & 0x80 == 0:
-                if value >= 1 << bits:
-                    raise DecodeError(
-                        f"out-of-range unsigned LEB in {self.context}"
-                    )
-                return value
-            shift += 7
-            if shift >= bits + 7:
-                raise DecodeError(f"oversized unsigned LEB in {self.context}")
-
-    def take(self, size: int) -> bytes:
-        end = self.offset + size
-        if end > len(self.data):
-            raise DecodeError(f"truncated {self.context}")
-        value = self.data[self.offset:end]
-        self.offset = end
-        return value
-
-    def name(self) -> str:
-        raw = self.take(self.uleb())
-        try:
-            return raw.decode("utf-8")
-        except UnicodeDecodeError as error:
-            raise DecodeError(f"invalid UTF-8 name in {self.context}") from error
-
-
-def skip_limits(reader: Reader) -> bool:
-    flags = reader.uleb()
-    if flags & ~0x07:
-        raise DecodeError(f"unsupported limits flags 0x{flags:x} in {reader.context}")
-    reader.uleb(64 if flags & 0x04 else 32)
-    if flags & 0x01:
-        reader.uleb(64 if flags & 0x04 else 32)
-    return bool(flags & 0x02)
-
-
-def read_sections(data: bytes) -> dict[int, bytes]:
-    if data[:8] != b"\x00asm\x01\x00\x00\x00":
-        raise DecodeError("not a core WebAssembly version-1 module")
-
-    reader = Reader(data[8:], "module")
-    sections: dict[int, bytes] = {}
-    while not reader.eof():
-        section_id = reader.byte()
-        payload = reader.take(reader.uleb())
-        if section_id != 0:
-            if section_id in sections:
-                raise DecodeError(f"duplicate section {section_id}")
-            sections[section_id] = payload
-    return sections
-
-
-def read_imported_function_count(payload: bytes) -> tuple[int, bool]:
-    reader = Reader(payload, "import section")
-    function_count = 0
-    shared_memories = []
-    for _ in range(reader.uleb()):
-        module = reader.name()
-        name = reader.name()
-        kind = reader.byte()
-        if kind == 0:  # function
-            reader.uleb()
-            function_count += 1
-        elif kind == 1:  # table
-            reader.byte()
-            skip_limits(reader)
-        elif kind == 2:  # memory
-            shared_memories.append((module, name, skip_limits(reader)))
-        elif kind == 3:  # global
-            reader.byte()
-            reader.byte()
-        elif kind == 4:  # exception tag
-            reader.byte()
-            reader.uleb()
-        else:
-            raise DecodeError(f"unknown import kind {kind}")
-    if not reader.eof():
-        raise DecodeError("trailing bytes in import section")
-
-    exact_memories = [
-        shared for module, name, shared in shared_memories
-        if module == "env" and name == "memory"
-    ]
-    if len(exact_memories) != 1:
-        raise DecodeError(
-            f"expected exactly one env.memory import, found {len(exact_memories)}"
-        )
-    return function_count, exact_memories[0]
-
-
-def read_defined_function_count(payload: bytes) -> int:
-    reader = Reader(payload, "function section")
-    count = reader.uleb()
-    for _ in range(count):
-        reader.uleb()
-    if not reader.eof():
-        raise DecodeError("trailing bytes in function section")
-    return count
-
-
-def read_function_exports(payload: bytes) -> dict[str, int]:
-    reader = Reader(payload, "export section")
-    exports = {}
-    for _ in range(reader.uleb()):
-        name = reader.name()
-        kind = reader.byte()
-        index = reader.uleb()
-        if kind == 0:
-            if name in exports:
-                raise DecodeError(f"duplicate function export {name}")
-            exports[name] = index
-    if not reader.eof():
-        raise DecodeError("trailing bytes in export section")
-    return exports
-
-
-def read_code_bodies(payload: bytes) -> tuple[bytes, ...]:
-    reader = Reader(payload, "code section")
-    bodies = tuple(reader.take(reader.uleb()) for _ in range(reader.uleb()))
-    if not reader.eof():
-        raise DecodeError("trailing bytes in code section")
-    return bodies
-
-
-def verify_module_structure(
-    path: pathlib.Path,
-) -> tuple[int, dict[str, int], tuple[bytes, ...]]:
-    sections = read_sections(path.read_bytes())
-    for section_id, name in ((2, "import"), (3, "function"), (7, "export"), (10, "code")):
-        if section_id not in sections:
-            raise DecodeError(f"missing {name} section")
-
-    imported_functions, memory_is_shared = read_imported_function_count(sections[2])
-    if not memory_is_shared:
-        raise DecodeError("env.memory is not declared shared")
-
-    defined_functions = read_defined_function_count(sections[3])
-    exports = read_function_exports(sections[7])
-    bodies = read_code_bodies(sections[10])
-    if len(bodies) != defined_functions:
-        raise DecodeError(
-            f"function/code count mismatch: {defined_functions} definitions, "
-            f"{len(bodies)} bodies"
-        )
-
-    for name in EXPECTED_FUNCTION_FENCES:
-        if name not in exports:
-            raise DecodeError(f"missing required function export {name}")
-        defined_index = exports[name] - imported_functions
-        if defined_index < 0 or defined_index >= len(bodies):
-            raise DecodeError(f"{name} does not refer to a defined function")
-    return imported_functions, exports, bodies
-
-
-def verify(
-    path: pathlib.Path, *, expected_total: int | None = None
-) -> tuple[int, dict[str, int]]:
-    imported_functions, exports, bodies = verify_module_structure(path)
-
-    function_counts = {}
-    for name, expected in EXPECTED_FUNCTION_FENCES.items():
-        defined_index = exports[name] - imported_functions
-        actual = bodies[defined_index].count(ATOMIC_FENCE_ENCODING)
-        function_counts[name] = actual
-        if actual != expected:
-            raise DecodeError(
-                f"{name} contains {actual} atomic.fence instructions, expected {expected}"
-            )
-
-    total = sum(body.count(ATOMIC_FENCE_ENCODING) for body in bodies)
-    if expected_total is not None and total != expected_total:
-        raise DecodeError(
-            f"module contains {total} atomic.fence instructions, "
-            f"expected {expected_total}"
-        )
-    if total < sum(EXPECTED_FUNCTION_FENCES.values()):
-        raise DecodeError(f"module contains implausibly few atomic.fence instructions: {total}")
-    return total, function_counts
-
-
-def main(argv: list[str]) -> int:
-    parser = argparse.ArgumentParser(description=__doc__)
-    parser.add_argument("--expected-total", type=int)
-    parser.add_argument(
-        "--latch-state-contract",
-        choices=(UPSTREAM_LATCH_CONTRACT, PACKED_LATCH_CONTRACT),
-        default=UPSTREAM_LATCH_CONTRACT,
-    )
-    parser.add_argument(
-        "--wasm-dis",
-        type=pathlib.Path,
-        help="exact Binaryen wasm-dis executable used to validate atomic opcodes",
-    )
-    parser.add_argument(
-        "--receipt",
-        type=pathlib.Path,
-        help="write a sealed final-module instruction receipt",
-    )
-    parser.add_argument(
-        "--verified-receipt",
-        type=pathlib.Path,
-        help="validate a build-time instruction receipt against the final module",
-    )
-    parser.add_argument(
-        "--receipt-only",
-        action="store_true",
-        help="validate a sealed receipt and module identity without decoding Wasm",
-    )
-    parser.add_argument("postgres_wasm", type=pathlib.Path)
-    options = parser.parse_args(argv[1:])
-    if options.expected_total is not None and options.expected_total < 4:
-        parser.error("--expected-total must be at least 4")
-    if (
-        options.latch_state_contract == PACKED_LATCH_CONTRACT
-        and options.wasm_dis is None
-        and options.verified_receipt is None
-    ):
-        parser.error("the packed latch contract requires --wasm-dis or --verified-receipt")
-    if options.receipt is not None and options.latch_state_contract != PACKED_LATCH_CONTRACT:
-        parser.error("--receipt requires the packed latch contract")
-    if options.receipt is not None and options.wasm_dis is None:
-        parser.error("--receipt requires --wasm-dis")
-    if options.receipt is not None and options.verified_receipt is not None:
-        parser.error("--receipt and --verified-receipt are mutually exclusive")
-    if options.receipt_only and (
-        options.verified_receipt is None
-        or options.expected_total is None
-        or options.latch_state_contract != PACKED_LATCH_CONTRACT
-    ):
-        parser.error(
-            "--receipt-only requires --verified-receipt, --expected-total, and "
-            "the packed latch contract"
-        )
-    if options.receipt_only and (options.wasm_dis is not None or options.receipt is not None):
-        parser.error("--receipt-only cannot disassemble or create a receipt")
-    try:
-        atomic_summary = ""
-        if options.receipt_only:
-            assert options.expected_total is not None
-            total = options.expected_total
-            receipt_values = verify_receipt(
-                options.verified_receipt,
-                options.postgres_wasm,
-                total,
-            )
-            counts = {
-                "SetLatch": int(receipt_values["atomic_fence_set_latch"]),
-                "ResetLatch": int(receipt_values["atomic_fence_reset_latch"]),
-                "WaitEventSetWait": int(
-                    receipt_values["atomic_fence_wait_event_set_wait"]
-                ),
-            }
-            atomic_summary = (
-                " atomics="
-                f"SetLatch:or={receipt_values['i32_atomic_rmw_or_set_latch']} "
-                f"ResetLatch:and={receipt_values['i32_atomic_rmw_and_reset_latch']} "
-                "WaitEventSetWait:"
-                f"load={receipt_values['i32_atomic_load_wait_event_set_wait']},"
-                f"and={receipt_values['i32_atomic_rmw_and_wait_event_set_wait']},"
-                f"or={receipt_values['i32_atomic_rmw_or_wait_event_set_wait']}"
-            )
-        elif options.wasm_dis is not None:
-            verify_module_structure(options.postgres_wasm)
-            (
-                total_opcodes,
-                function_opcodes,
-                wasm_dis_sha256,
-                wasm_dis_version,
-            ) = inspect_with_wasm_dis(options.postgres_wasm, options.wasm_dis)
-            total = total_opcodes["atomic.fence"]
-            counts = {
-                name: function_opcodes[name]["atomic.fence"]
-                for name in EXPECTED_FUNCTION_FENCES
-            }
-            if options.expected_total is not None and total != options.expected_total:
-                raise DecodeError(
-                    f"module contains {total} atomic.fence instructions, "
-                    f"expected {options.expected_total}"
-                )
-            if options.latch_state_contract == PACKED_LATCH_CONTRACT:
-                verify_packed_atomic_contract(total_opcodes, function_opcodes)
-                atomic_summary = (
-                    " atomics="
-                    f"SetLatch:or={function_opcodes['SetLatch']['i32.atomic.rmw.or']} "
-                    f"ResetLatch:and={function_opcodes['ResetLatch']['i32.atomic.rmw.and']} "
-                    "WaitEventSetWait:"
-                    f"load={function_opcodes['WaitEventSetWait']['i32.atomic.load']},"
-                    f"and={function_opcodes['WaitEventSetWait']['i32.atomic.rmw.and']},"
-                    f"or={function_opcodes['WaitEventSetWait']['i32.atomic.rmw.or']}"
-                )
-                if options.receipt is not None:
-                    postgres_sha256 = hashlib.sha256(
-                        options.postgres_wasm.read_bytes()
-                    ).hexdigest()
-                    receipt = canonical_receipt(
-                        postgres_sha256,
-                        total,
-                        total_opcodes,
-                        function_opcodes,
-                        wasm_dis_sha256,
-                        wasm_dis_version,
-                    )
-                    write_receipt(options.receipt, receipt)
-        elif options.verified_receipt is not None:
-            verify_module_structure(options.postgres_wasm)
-            receipt_values = read_receipt(options.verified_receipt)
-            receipt_total = exact_receipt_integer(
-                receipt_values, "atomic_fence_total"
-            )
-            total = options.expected_total or receipt_total
-            receipt_values = verify_receipt(
-                options.verified_receipt,
-                options.postgres_wasm,
-                total,
-            )
-            counts = {
-                name: int(receipt_values[f"atomic_fence_{key}"])
-                for name, key in (
-                    ("SetLatch", "set_latch"),
-                    ("ResetLatch", "reset_latch"),
-                    ("WaitEventSetWait", "wait_event_set_wait"),
-                )
-            }
-            atomic_summary = (
-                " atomics="
-                f"SetLatch:or={receipt_values['i32_atomic_rmw_or_set_latch']} "
-                f"ResetLatch:and={receipt_values['i32_atomic_rmw_and_reset_latch']} "
-                "WaitEventSetWait:"
-                f"load={receipt_values['i32_atomic_load_wait_event_set_wait']},"
-                f"and={receipt_values['i32_atomic_rmw_and_wait_event_set_wait']},"
-                f"or={receipt_values['i32_atomic_rmw_or_wait_event_set_wait']}"
-            )
-        else:
-            total, counts = verify(
-                options.postgres_wasm, expected_total=options.expected_total
-            )
-    except (DecodeError, OSError, UnicodeError) as error:
-        print(f"verify-postmaster-concurrency-contract: {error}", file=sys.stderr)
-        return 1
-    rendered = " ".join(f"{name}={counts[name]}" for name in EXPECTED_FUNCTION_FENCES)
-    print(
-        f"verified PostgreSQL Wasm concurrency contract: total={total} "
-        f"{rendered}{atomic_summary}"
-    )
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main(sys.argv))
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.test.py
deleted file mode 100755
index 5a66c2c1d..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-concurrency-contract.test.py
+++ /dev/null
@@ -1,260 +0,0 @@
-#!/usr/bin/env python3
-
-"""Unit tests for the final-module PostgreSQL concurrency contract verifier."""
-
-from __future__ import annotations
-
-import importlib.util
-import hashlib
-import io
-import pathlib
-import tempfile
-import unittest
-from contextlib import redirect_stdout
-
-
-SCRIPT = pathlib.Path(__file__).with_name("verify-postmaster-concurrency-contract.py")
-SPEC = importlib.util.spec_from_file_location("concurrency_contract", SCRIPT)
-assert SPEC is not None and SPEC.loader is not None
-MODULE = importlib.util.module_from_spec(SPEC)
-SPEC.loader.exec_module(MODULE)
-
-
-def uleb(value: int) -> bytes:
-    output = bytearray()
-    while True:
-        byte = value & 0x7F
-        value >>= 7
-        if value:
-            byte |= 0x80
-        output.append(byte)
-        if not value:
-            return bytes(output)
-
-
-def name(value: str) -> bytes:
-    encoded = value.encode("utf-8")
-    return uleb(len(encoded)) + encoded
-
-
-def vector(items: list[bytes]) -> bytes:
-    return uleb(len(items)) + b"".join(items)
-
-
-def section(section_id: int, payload: bytes) -> bytes:
-    return bytes((section_id,)) + uleb(len(payload)) + payload
-
-
-def module_bytes(
-    *, shared: bool = True, function_fences: dict[str, int] | None = None,
-    extra_fences: int = 271, immediate_fence_lookalike: bool = False,
-) -> bytes:
-    counts = dict(MODULE.EXPECTED_FUNCTION_FENCES)
-    if function_fences is not None:
-        counts.update(function_fences)
-    type_section = section(1, vector([b"\x60\x00\x00"]))
-    limits = (b"\x03" if shared else b"\x01") + uleb(1) + uleb(2)
-    memory_import = name("env") + name("memory") + b"\x02" + limits
-    import_section = section(2, vector([memory_import]))
-
-    function_names = list(MODULE.EXPECTED_FUNCTION_FENCES) + ["other"]
-    function_section = section(3, vector([b"\x00" for _ in function_names]))
-    exports = [
-        name(function_name) + b"\x00" + uleb(index)
-        for index, function_name in enumerate(function_names)
-        if function_name != "other"
-    ]
-    export_section = section(7, vector(exports))
-
-    bodies = []
-    for function_name in function_names:
-        fence_count = extra_fences if function_name == "other" else counts[function_name]
-        instructions = MODULE.ATOMIC_FENCE_ENCODING * fence_count
-        if function_name == "other" and immediate_fence_lookalike:
-            # i32.const 510 followed by unreachable contains fe 03 00, but no fence.
-            instructions += b"\x41\xfe\x03\x00"
-        instructions += b"\x0b"
-        body = b"\x00" + instructions  # zero local declaration groups
-        bodies.append(uleb(len(body)) + body)
-    code_section = section(10, uleb(len(bodies)) + b"".join(bodies))
-    return b"\x00asm\x01\x00\x00\x00" + type_section + import_section + function_section + export_section + code_section
-
-
-def packed_wat(*, wait_loads: int = 1, wait_ands: int = 2) -> list[str]:
-    lines = [
-        ' (export "ResetLatch" (func $20))\n',
-        ' (export "SetLatch" (func $19))\n',
-        ' (export "WaitEventSetWait" (func $21))\n',
-        ' (data $0 (i32.const 0) "(atomic.fence) is data, not code")\n',
-        ' (func $19 (param $0 i32)\n',
-        '  (atomic.fence)\n',
-        '  (i32.atomic.rmw.or\n',
-        '   (local.get $0)\n',
-        '   (i32.const 1)\n',
-        '  )\n',
-        '  (atomic.fence)\n',
-        ' )\n',
-        ' (func $20 (param $0 i32)\n',
-        '  (i32.atomic.rmw.and\n',
-        '   (local.get $0)\n',
-        '   (i32.const -2)\n',
-        '  )\n',
-        '  (atomic.fence)\n',
-        ' )\n',
-        ' (func $21 (param $0 i32)\n',
-        '  (i32.atomic.rmw.or\n',
-        '   (local.get $0)\n',
-        '   (i32.const 2)\n',
-        '  )\n',
-    ]
-    lines.extend('  (i32.atomic.load (local.get $0))\n' for _ in range(wait_loads))
-    lines.extend('  (i32.atomic.rmw.and (local.get $0) (i32.const -3))\n' for _ in range(wait_ands))
-    lines.extend(['  (atomic.fence)\n', ' )\n'])
-    return lines
-
-
-class ConcurrencyContractTests(unittest.TestCase):
-    def verify_bytes(self, contents: bytes):
-        with tempfile.TemporaryDirectory() as directory:
-            path = pathlib.Path(directory) / "postgres.wasm"
-            path.write_bytes(contents)
-            return MODULE.verify(path)
-
-    def test_exact_contract_passes(self) -> None:
-        total, functions = self.verify_bytes(module_bytes())
-        self.assertEqual(total, 275)
-        self.assertEqual(functions, MODULE.EXPECTED_FUNCTION_FENCES)
-
-    def test_missing_critical_fence_fails(self) -> None:
-        with self.assertRaisesRegex(MODULE.DecodeError, "SetLatch contains 1"):
-            self.verify_bytes(module_bytes(function_fences={"SetLatch": 1}))
-
-    def test_total_fence_drift_fails(self) -> None:
-        with self.assertRaisesRegex(MODULE.DecodeError, "module contains 274"):
-            with tempfile.TemporaryDirectory() as directory:
-                path = pathlib.Path(directory) / "postgres.wasm"
-                path.write_bytes(module_bytes(extra_fences=270))
-                MODULE.verify(path, expected_total=275)
-
-    def test_unshared_memory_fails(self) -> None:
-        with self.assertRaisesRegex(MODULE.DecodeError, "not declared shared"):
-            self.verify_bytes(module_bytes(shared=False))
-
-    def test_truncated_module_fails(self) -> None:
-        with self.assertRaisesRegex(MODULE.DecodeError, "truncated"):
-            self.verify_bytes(module_bytes()[:-1])
-
-    def test_packed_wat_contract_passes_and_ignores_data_text(self) -> None:
-        totals, functions = MODULE.parse_wat_instruction_inventory(packed_wat())
-        self.assertEqual(totals["atomic.fence"], 4)
-        self.assertEqual(totals["i32.atomic.load"], 1)
-        MODULE.verify_packed_atomic_contract(totals, functions)
-
-    def test_packed_contract_ignores_fence_encoding_inside_immediate(self) -> None:
-        contents = module_bytes(extra_fences=0, immediate_fence_lookalike=True)
-        with tempfile.TemporaryDirectory() as directory:
-            root = pathlib.Path(directory)
-            postgres = root / "postgres.wasm"
-            wasm_dis = root / "wasm-dis"
-            postgres.write_bytes(contents)
-            wasm_dis.write_text(
-                "#!/usr/bin/env python3\n"
-                "import sys\n"
-                "if '--version' in sys.argv:\n"
-                "    print('wasm-dis version 130')\n"
-                "else:\n"
-                f"    print({''.join(packed_wat())!r}, end='')\n",
-                encoding="utf-8",
-            )
-            wasm_dis.chmod(0o755)
-
-            # The legacy byte substring inventory sees a false fifth fence.
-            self.assertEqual(MODULE.verify(postgres)[0], 5)
-            with redirect_stdout(io.StringIO()):
-                status = MODULE.main(
-                    [
-                        str(SCRIPT),
-                        "--expected-total",
-                        "4",
-                        "--latch-state-contract",
-                        MODULE.PACKED_LATCH_CONTRACT,
-                        "--wasm-dis",
-                        str(wasm_dis),
-                        str(postgres),
-                    ]
-                )
-            self.assertEqual(status, 0)
-
-    def test_packed_wat_missing_waiter_retraction_fails(self) -> None:
-        totals, functions = MODULE.parse_wat_instruction_inventory(
-            packed_wat(wait_ands=1)
-        )
-        with self.assertRaisesRegex(
-            MODULE.DecodeError,
-            "WaitEventSetWait contains 1 i32.atomic.rmw.and",
-        ):
-            MODULE.verify_packed_atomic_contract(totals, functions)
-
-    def test_packed_wat_missing_atomic_load_fails(self) -> None:
-        totals, functions = MODULE.parse_wat_instruction_inventory(
-            packed_wat(wait_loads=0)
-        )
-        with self.assertRaisesRegex(MODULE.DecodeError, "expected at least 1"):
-            MODULE.verify_packed_atomic_contract(totals, functions)
-
-    def test_packed_wat_duplicate_critical_alias_fails(self) -> None:
-        lines = packed_wat()
-        lines[1] = ' (export "SetLatch" (func $20))\n'
-        with self.assertRaisesRegex(MODULE.DecodeError, "share one function"):
-            MODULE.parse_wat_instruction_inventory(lines)
-
-    def test_final_contract_receipt_is_canonical(self) -> None:
-        totals, functions = MODULE.parse_wat_instruction_inventory(packed_wat())
-        receipt = MODULE.canonical_receipt(
-            "1" * 64,
-            4,
-            totals,
-            functions,
-            "2" * 64,
-            "wasm-dis version 130",
-        )
-        self.assertTrue(receipt.endswith("\n"))
-        self.assertIn(
-            "schema=oliphaunt.wasix-postmaster.final-wasm-concurrency.v1\n",
-            receipt,
-        )
-        self.assertIn("i32_atomic_rmw_and_wait_event_set_wait=2\n", receipt)
-
-    def test_final_contract_receipt_binds_module(self) -> None:
-        contents = module_bytes()
-        totals, functions = MODULE.parse_wat_instruction_inventory(packed_wat())
-        receipt = MODULE.canonical_receipt(
-            hashlib.sha256(contents).hexdigest(),
-            275,
-            totals,
-            functions,
-            "2" * 64,
-            "wasm-dis version 130",
-        )
-        with tempfile.TemporaryDirectory() as directory:
-            root = pathlib.Path(directory)
-            postgres = root / "postgres.wasm"
-            receipt_path = root / "contract.receipt"
-            postgres.write_bytes(contents)
-            receipt_path.write_text(receipt, encoding="utf-8")
-            values = MODULE.verify_receipt(receipt_path, postgres, 275)
-            self.assertEqual(values["postgres_sha256"], hashlib.sha256(contents).hexdigest())
-
-            receipt_path.write_text(
-                receipt.replace(
-                    "i32_atomic_rmw_or_set_latch=1",
-                    "i32_atomic_rmw_or_set_latch=0",
-                ),
-                encoding="utf-8",
-            )
-            with self.assertRaisesRegex(MODULE.DecodeError, "contract differs"):
-                MODULE.verify_receipt(receipt_path, postgres, 275)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-wasm-import.py b/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-wasm-import.py
deleted file mode 100755
index f170df31e..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-wasm-import.py
+++ /dev/null
@@ -1,215 +0,0 @@
-#!/usr/bin/env python3
-
-"""Fail closed unless a postmaster module has every exact product import."""
-
-from __future__ import annotations
-
-import pathlib
-import sys
-
-
-EXPECTED_MODULE = "oliphaunt_postmaster_v1"
-EXPECTED_IMPORTS = {
-    "fd_sync_range": (
-        (0x7F, 0x7E, 0x7E, 0x7F),  # i32, i64, i64, i32
-        (0x7F,),  # i32 errno
-    ),
-}
-VALUE_TYPE_NAMES = {
-    0x7F: "i32",
-    0x7E: "i64",
-    0x7D: "f32",
-    0x7C: "f64",
-    0x7B: "v128",
-    0x70: "funcref",
-    0x6F: "externref",
-    0x69: "exnref",
-}
-
-
-class DecodeError(ValueError):
-    pass
-
-
-class Reader:
-    def __init__(self, data: bytes, context: str) -> None:
-        self.data = data
-        self.offset = 0
-        self.context = context
-
-    def eof(self) -> bool:
-        return self.offset == len(self.data)
-
-    def byte(self) -> int:
-        if self.offset >= len(self.data):
-            raise DecodeError(f"truncated {self.context}")
-        value = self.data[self.offset]
-        self.offset += 1
-        return value
-
-    def uleb(self, bits: int = 32) -> int:
-        value = 0
-        shift = 0
-        while True:
-            byte = self.byte()
-            value |= (byte & 0x7F) << shift
-            if byte & 0x80 == 0:
-                if value >= 1 << bits:
-                    raise DecodeError(f"out-of-range unsigned LEB in {self.context}")
-                return value
-            shift += 7
-            if shift >= bits + 7:
-                raise DecodeError(f"oversized unsigned LEB in {self.context}")
-
-    def take(self, size: int) -> bytes:
-        end = self.offset + size
-        if end > len(self.data):
-            raise DecodeError(f"truncated {self.context}")
-        value = self.data[self.offset:end]
-        self.offset = end
-        return value
-
-    def name(self) -> str:
-        raw = self.take(self.uleb())
-        try:
-            return raw.decode("utf-8")
-        except UnicodeDecodeError as error:
-            raise DecodeError(f"invalid UTF-8 name in {self.context}") from error
-
-
-def read_vector(reader: Reader, item) -> tuple:
-    return tuple(item(reader) for _ in range(reader.uleb()))
-
-
-def read_value_type(reader: Reader) -> int:
-    value = reader.byte()
-    if value not in VALUE_TYPE_NAMES:
-        raise DecodeError(f"unsupported value type 0x{value:02x} in {reader.context}")
-    return value
-
-
-def read_types(payload: bytes) -> tuple[tuple[tuple[int, ...], tuple[int, ...]], ...]:
-    reader = Reader(payload, "type section")
-    types = []
-    for _ in range(reader.uleb()):
-        if reader.byte() != 0x60:
-            raise DecodeError("non-function type in the postmaster core Wasm module")
-        params = read_vector(reader, read_value_type)
-        results = read_vector(reader, read_value_type)
-        types.append((params, results))
-    if not reader.eof():
-        raise DecodeError("trailing bytes in type section")
-    return tuple(types)
-
-
-def skip_limits(reader: Reader) -> None:
-    flags = reader.uleb()
-    if flags & ~0x07:
-        raise DecodeError(f"unsupported limits flags 0x{flags:x} in import section")
-    reader.uleb(64 if flags & 0x04 else 32)
-    if flags & 0x01:
-        reader.uleb(64 if flags & 0x04 else 32)
-
-
-def read_imports(payload: bytes) -> tuple[tuple[str, str, int | None], ...]:
-    reader = Reader(payload, "import section")
-    imports = []
-    for _ in range(reader.uleb()):
-        module = reader.name()
-        name = reader.name()
-        kind = reader.byte()
-        type_index = None
-        if kind == 0:  # function
-            type_index = reader.uleb()
-        elif kind == 1:  # table
-            read_value_type(reader)
-            skip_limits(reader)
-        elif kind == 2:  # memory
-            skip_limits(reader)
-        elif kind == 3:  # global
-            read_value_type(reader)
-            reader.byte()
-        elif kind == 4:  # exception tag
-            reader.byte()
-            reader.uleb()
-        else:
-            raise DecodeError(f"unknown import kind {kind}")
-        imports.append((module, name, type_index))
-    if not reader.eof():
-        raise DecodeError("trailing bytes in import section")
-    return tuple(imports)
-
-
-def decode_module(data: bytes):
-    if data[:8] != b"\x00asm\x01\x00\x00\x00":
-        raise DecodeError("not a core WebAssembly version-1 module")
-    reader = Reader(data[8:], "module")
-    types = ()
-    imports = ()
-    seen = set()
-    while not reader.eof():
-        section_id = reader.byte()
-        payload = reader.take(reader.uleb())
-        if section_id in (1, 2):
-            if section_id in seen:
-                raise DecodeError(f"duplicate section {section_id}")
-            seen.add(section_id)
-        if section_id == 1:
-            types = read_types(payload)
-        elif section_id == 2:
-            imports = read_imports(payload)
-    return types, imports
-
-
-def signature_text(signature) -> str:
-    params, results = signature
-    left = ",".join(VALUE_TYPE_NAMES[value] for value in params)
-    right = ",".join(VALUE_TYPE_NAMES[value] for value in results)
-    return f"({left})->({right})"
-
-
-def verify(path: pathlib.Path) -> None:
-    types, imports = decode_module(path.read_bytes())
-    for expected_name, expected_signature in EXPECTED_IMPORTS.items():
-        named = [entry for entry in imports if entry[1] == expected_name]
-        exact = [entry for entry in named if entry[0] == EXPECTED_MODULE]
-        aliases = [entry for entry in named if entry[0] != EXPECTED_MODULE]
-        if aliases:
-            rendered = ", ".join(f"{module}.{name}" for module, name, _ in aliases)
-            raise DecodeError(f"forbidden {expected_name} import alias(es): {rendered}")
-        if len(exact) != 1:
-            raise DecodeError(
-                f"expected exactly one {EXPECTED_MODULE}.{expected_name} import, "
-                f"found {len(exact)}"
-            )
-        type_index = exact[0][2]
-        if type_index is None or type_index >= len(types):
-            raise DecodeError(f"{expected_name} import has an invalid function type index")
-        signature = types[type_index]
-        if signature != expected_signature:
-            raise DecodeError(
-                f"{expected_name} signature is {signature_text(signature)}, "
-                f"expected {signature_text(expected_signature)}"
-            )
-
-
-def main(argv: list[str]) -> int:
-    if len(argv) != 2:
-        print(f"usage: {argv[0]} POSTGRES_WASM", file=sys.stderr)
-        return 2
-    path = pathlib.Path(argv[1])
-    try:
-        verify(path)
-    except (DecodeError, OSError) as error:
-        print(f"verify-postmaster-wasm-import: {error}", file=sys.stderr)
-        return 1
-    rendered = ", ".join(
-        f"{EXPECTED_MODULE}.{name}{signature_text(signature)}"
-        for name, signature in EXPECTED_IMPORTS.items()
-    )
-    print(f"verified required postmaster imports: {rendered}")
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main(sys.argv))
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-wasm-import.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-wasm-import.test.py
deleted file mode 100755
index b41492cf8..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-postmaster-wasm-import.test.py
+++ /dev/null
@@ -1,96 +0,0 @@
-#!/usr/bin/env python3
-
-import pathlib
-import subprocess
-import sys
-import tempfile
-import unittest
-
-
-SCRIPT = pathlib.Path(__file__).with_name("verify-postmaster-wasm-import.py")
-SIGNATURE = (b"\x7f\x7e\x7e\x7f", b"\x7f")
-
-
-def uleb(value):
-    encoded = bytearray()
-    while True:
-        byte = value & 0x7F
-        value >>= 7
-        encoded.append(byte | (0x80 if value else 0))
-        if not value:
-            return bytes(encoded)
-
-
-def vector(*values):
-    return uleb(len(values)) + b"".join(values)
-
-
-def name(value):
-    encoded = value.encode("utf-8")
-    return uleb(len(encoded)) + encoded
-
-
-def section(section_id, payload):
-    return bytes([section_id]) + uleb(len(payload)) + payload
-
-
-def module(imports=None):
-    imports = imports or [("oliphaunt_postmaster_v1", "fd_sync_range", SIGNATURE)]
-    function_types = []
-    import_entries = []
-    for type_index, (module_name, field, signature) in enumerate(imports):
-        params, results = signature
-        function_types.append(
-            b"\x60"
-            + vector(*(bytes([item]) for item in params))
-            + vector(*(bytes([item]) for item in results))
-        )
-        import_entries.append(name(module_name) + name(field) + b"\x00" + uleb(type_index))
-    return (
-        b"\x00asm\x01\x00\x00\x00"
-        + section(1, vector(*function_types))
-        + section(2, vector(*import_entries))
-    )
-
-
-class VerifyPostmasterImportTests(unittest.TestCase):
-    def run_verifier(self, contents):
-        with tempfile.TemporaryDirectory() as directory:
-            wasm = pathlib.Path(directory) / "postgres.wasm"
-            wasm.write_bytes(contents)
-            return subprocess.run(
-                [sys.executable, str(SCRIPT), str(wasm)],
-                text=True,
-                stdout=subprocess.PIPE,
-                stderr=subprocess.PIPE,
-                check=False,
-            )
-
-    def test_accepts_exact_product_import_and_signature(self):
-        result = self.run_verifier(module())
-        self.assertEqual(result.returncode, 0, result.stderr)
-        self.assertIn("(i32,i64,i64,i32)->(i32)", result.stdout)
-
-    def test_rejects_legacy_namespace_alias(self):
-        result = self.run_verifier(module([("wasix_32v1", "fd_sync_range", SIGNATURE)]))
-        self.assertNotEqual(result.returncode, 0)
-        self.assertIn("forbidden fd_sync_range import alias", result.stderr)
-
-    def test_rejects_wrong_signature(self):
-        result = self.run_verifier(
-            module([("oliphaunt_postmaster_v1", "fd_sync_range", (b"\x7f", b"\x7f"))])
-        )
-        self.assertNotEqual(result.returncode, 0)
-        self.assertIn("fd_sync_range signature is", result.stderr)
-
-    def test_rejects_missing_product_import(self):
-        result = self.run_verifier(module([("wasi_snapshot_preview1", "fd_sync", (b"\x7f", b"\x7f"))]))
-        self.assertNotEqual(result.returncode, 0)
-        self.assertIn(
-            "expected exactly one oliphaunt_postmaster_v1.fd_sync_range",
-            result.stderr,
-        )
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-source-lock.py b/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-source-lock.py
deleted file mode 100755
index 90d78357c..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-source-lock.py
+++ /dev/null
@@ -1,302 +0,0 @@
-#!/usr/bin/env python3
-"""Reconcile every wasix-postmaster source and runtime-patch trust input."""
-
-from __future__ import annotations
-
-import argparse
-import hashlib
-import re
-import sys
-import tomllib
-from pathlib import Path
-from typing import Any
-
-
-class VerificationError(RuntimeError):
-    pass
-
-
-COMMON_KEYS = {
-    "POSTGRES_TAG",
-    "POSTGRES_VERSION",
-    "FRESH_WASMER_VERSION",
-    "FRESH_WASMER_WASIX_VERSION",
-    "FRESH_WASMER_SOURCE_COMMIT",
-    "FRESH_WASMER_NAPI_COMMIT",
-    "FRESH_WASMER_TEST_FILES_COMMIT",
-    "FRESH_WASMER_SPEC_COMMIT",
-    "FRESH_WASIX_LIBC_SOURCE_COMMIT",
-}
-
-SOURCE_MANIFESTS = {
-    "wasmer": {
-        "path": "src/sources/third-party/wasix-postmaster/wasmer.toml",
-        "name": "wasmer-postmaster",
-        "commit_key": "commit",
-        "remote_key": "remote",
-        "branch_key": "tag",
-    },
-    "wasmer_napi": {
-        "path": "src/sources/third-party/wasix-postmaster/wasmer-napi.toml",
-        "name": "wasmer-postmaster-napi",
-        "commit_key": "napi_commit",
-        "remote_key": "napi_remote",
-        "branch": "main",
-    },
-    "wasmer_test_files": {
-        "path": "src/sources/third-party/wasix-postmaster/wasmer-test-files.toml",
-        "name": "wasmer-postmaster-test-files",
-        "commit_key": "test_files_commit",
-        "remote_key": "test_files_remote",
-        "branch": "main",
-    },
-    "wasmer_spec": {
-        "path": "src/sources/third-party/wasix-postmaster/webassembly-testsuite.toml",
-        "name": "wasmer-postmaster-webassembly-testsuite",
-        "commit_key": "webassembly_testsuite_commit",
-        "remote_key": "webassembly_testsuite_remote",
-        "branch": "main",
-    },
-}
-
-
-def load_toml(path: Path) -> dict[str, Any]:
-    try:
-        with path.open("rb") as handle:
-            return tomllib.load(handle)
-    except (OSError, tomllib.TOMLDecodeError) as error:
-        raise VerificationError(f"cannot read TOML {path}: {error}") from error
-
-
-def require_equal(label: str, actual: Any, expected: Any) -> None:
-    if actual != expected:
-        raise VerificationError(f"{label}: expected {expected!r}, got {actual!r}")
-
-
-def require_table(table: dict[str, Any], key: str, source: str) -> dict[str, Any]:
-    value = table.get(key)
-    if not isinstance(value, dict):
-        raise VerificationError(f"{source} must define table [{key}]")
-    return value
-
-
-def parse_common_constants(path: Path) -> dict[str, str]:
-    assignment = re.compile(
-        r'^export\s+([A-Z0-9_]+)="\$\{\1:-([^"}]*)\}"\s*$'
-    )
-    constants: dict[str, str] = {}
-    try:
-        lines = path.read_text(encoding="utf-8").splitlines()
-    except OSError as error:
-        raise VerificationError(f"cannot read {path}: {error}") from error
-    for line in lines:
-        match = assignment.match(line)
-        if match and match.group(1) in COMMON_KEYS:
-            constants[match.group(1)] = match.group(2)
-    missing = sorted(COMMON_KEYS - constants.keys())
-    if missing:
-        raise VerificationError(
-            f"{path} lacks canonical default assignments for: {', '.join(missing)}"
-        )
-    return constants
-
-
-def regular_project_file(project_root: Path, relative: str, label: str) -> Path:
-    candidate = Path(relative)
-    if candidate.is_absolute() or ".." in candidate.parts or "." in candidate.parts:
-        raise VerificationError(f"{label} has unsafe relative path: {relative!r}")
-    path = project_root / candidate
-    if path.is_symlink() or not path.is_file():
-        raise VerificationError(f"{label} must be a regular non-symlink file: {path}")
-    return path
-
-
-def verify_patch(
-    project_root: Path,
-    record: dict[str, Any],
-    *,
-    label: str,
-    expected_path: str,
-    expected_base: str,
-) -> None:
-    require_equal(f"{label}.path", record.get("path"), expected_path)
-    require_equal(f"{label}.base_commit", record.get("base_commit"), expected_base)
-    path = regular_project_file(project_root, expected_path, label)
-    contents = path.read_bytes()
-    require_equal(f"{label}.bytes", record.get("bytes"), len(contents))
-    require_equal(
-        f"{label}.sha256", record.get("sha256"), hashlib.sha256(contents).hexdigest()
-    )
-
-
-def verify_postgresql_product_inputs(
-    project_root: Path, record: dict[str, Any]
-) -> None:
-    label = "current_postgresql_product_inputs"
-    files = record.get("file")
-    if not isinstance(files, list) or not all(isinstance(item, dict) for item in files):
-        raise VerificationError(f"{label}.file must be an array of tables")
-    series_path = regular_project_file(
-        project_root, "postgres/patches/series", f"{label}.series"
-    )
-    expected_paths = {
-        "postgres/patches/series",
-        "postgres/product-patch-provenance.toml",
-        *{
-            f"postgres/patches/{line}"
-            for line in series_path.read_text(encoding="utf-8").splitlines()
-            if line and not line.startswith("#")
-        },
-    }
-    actual_paths = [item.get("path") for item in files]
-    if len(actual_paths) != len(set(actual_paths)):
-        raise VerificationError(f"{label}.file contains duplicate paths")
-    require_equal(f"{label}.paths", set(actual_paths), expected_paths)
-    for index, item in enumerate(files):
-        item_label = f"{label}.file[{index}]"
-        relative = item.get("path")
-        if not isinstance(relative, str):
-            raise VerificationError(f"{item_label}.path must be a string")
-        contents = regular_project_file(project_root, relative, item_label).read_bytes()
-        require_equal(f"{item_label}.bytes", item.get("bytes"), len(contents))
-        require_equal(
-            f"{item_label}.sha256",
-            item.get("sha256"),
-            hashlib.sha256(contents).hexdigest(),
-        )
-
-
-def verify_postgresql_packed_latch_patch(
-    project_root: Path, record: dict[str, Any], *, postgres_tag: str
-) -> None:
-    label = "current_postgresql_patches.packed_atomic_latch_state"
-    expected_path = "postgres/patches/0008-wasix-packed-atomic-latch-state.patch"
-    require_equal(f"{label}.path", record.get("path"), expected_path)
-    require_equal(f"{label}.base_tag", record.get("base_tag"), postgres_tag)
-    require_equal(
-        f"{label}.feature_macro",
-        record.get("feature_macro"),
-        "PG_WASIX_ATOMIC_LATCH_STATE",
-    )
-    require_equal(
-        f"{label}.native_behavior_preserved",
-        record.get("native_behavior_preserved"),
-        True,
-    )
-    path = regular_project_file(project_root, expected_path, label)
-    contents = path.read_bytes()
-    require_equal(f"{label}.bytes", record.get("bytes"), len(contents))
-    require_equal(
-        f"{label}.sha256", record.get("sha256"), hashlib.sha256(contents).hexdigest()
-    )
-
-
-def verify(project_root: Path, repo_root: Path) -> None:
-    project_root = project_root.resolve()
-    repo_root = repo_root.resolve()
-    lock_path = project_root / "sources.lock.toml"
-    lock = load_toml(lock_path)
-    common = parse_common_constants(project_root / "lib/common.sh")
-
-    postgres = require_table(lock, "postgresql", str(lock_path))
-    postgres_source_path = repo_root / "src/postgres/versions/18/source.toml"
-    postgres_source = require_table(
-        load_toml(postgres_source_path), "postgresql", str(postgres_source_path)
-    )
-    require_equal("PostgreSQL version vs source manifest", postgres.get("version"), postgres_source.get("version"))
-    require_equal("PostgreSQL archive digest vs source manifest", postgres.get("archive_sha256"), postgres_source.get("sha256"))
-    require_equal("PostgreSQL version vs common.sh", postgres.get("version"), common["POSTGRES_VERSION"])
-    require_equal("PostgreSQL tag vs common.sh", postgres.get("tag"), common["POSTGRES_TAG"])
-
-    postgresql_patches = require_table(
-        lock, "current_postgresql_patches", str(lock_path)
-    )
-    verify_postgresql_product_inputs(
-        project_root,
-        require_table(lock, "current_postgresql_product_inputs", str(lock_path)),
-    )
-    verify_postgresql_packed_latch_patch(
-        project_root,
-        require_table(
-            postgresql_patches, "packed_atomic_latch_state", str(lock_path)
-        ),
-        postgres_tag=postgres["tag"],
-    )
-    wasmer = require_table(lock, "wasmer", str(lock_path))
-    require_equal("Wasmer version vs common.sh", wasmer.get("version"), common["FRESH_WASMER_VERSION"])
-    require_equal("wasmer-wasix version vs common.sh", wasmer.get("wasix_version"), common["FRESH_WASMER_WASIX_VERSION"])
-    common_commit_keys = {
-        "commit": "FRESH_WASMER_SOURCE_COMMIT",
-        "napi_commit": "FRESH_WASMER_NAPI_COMMIT",
-        "test_files_commit": "FRESH_WASMER_TEST_FILES_COMMIT",
-        "webassembly_testsuite_commit": "FRESH_WASMER_SPEC_COMMIT",
-    }
-    for lock_key, common_key in common_commit_keys.items():
-        require_equal(f"wasmer.{lock_key} vs common.sh", wasmer.get(lock_key), common[common_key])
-
-    for label, specification in SOURCE_MANIFESTS.items():
-        manifest_path = repo_root / specification["path"]
-        manifest = load_toml(manifest_path)
-        require_equal(f"{label} source name", manifest.get("name"), specification["name"])
-        require_equal(
-            f"{label} source commit",
-            manifest.get("commit"),
-            wasmer.get(specification["commit_key"]),
-        )
-        require_equal(
-            f"{label} source remote",
-            manifest.get("url"),
-            wasmer.get(specification["remote_key"]),
-        )
-        expected_branch = (
-            wasmer.get(specification["branch_key"])
-            if "branch_key" in specification
-            else specification["branch"]
-        )
-        require_equal(f"{label} source branch", manifest.get("branch"), expected_branch)
-
-    wasix_libc = require_table(lock, "wasix_libc", str(lock_path))
-    libc_manifest_path = repo_root / "src/sources/third-party/wasix-postmaster/wasix-libc.toml"
-    libc_manifest = load_toml(libc_manifest_path)
-    require_equal("wasix-libc source name", libc_manifest.get("name"), "wasix-libc-postmaster")
-    require_equal("wasix-libc source branch", libc_manifest.get("branch"), "main")
-    require_equal("wasix-libc source commit", libc_manifest.get("commit"), wasix_libc.get("commit"))
-    require_equal("wasix-libc source remote", libc_manifest.get("url"), wasix_libc.get("remote"))
-    require_equal("wasix-libc commit vs common.sh", wasix_libc.get("commit"), common["FRESH_WASIX_LIBC_SOURCE_COMMIT"])
-
-    runtime_patches = require_table(lock, "current_runtime_patches", str(lock_path))
-    verify_patch(
-        project_root,
-        require_table(runtime_patches, "wasmer", str(lock_path)),
-        label="current_runtime_patches.wasmer",
-        expected_path="runtime/patches/wasmer/0001-postgres-wasix-blockers.patch",
-        expected_base=wasmer["commit"],
-    )
-    verify_patch(
-        project_root,
-        require_table(runtime_patches, "wasix_libc", str(lock_path)),
-        label="current_runtime_patches.wasix_libc",
-        expected_path="runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch",
-        expected_base=wasix_libc["commit"],
-    )
-
-
-def main() -> int:
-    parser = argparse.ArgumentParser(description=__doc__)
-    script_project_root = Path(__file__).resolve().parents[2]
-    parser.add_argument("--project-root", type=Path, default=script_project_root)
-    parser.add_argument("--repo-root", type=Path)
-    options = parser.parse_args()
-    project_root = options.project_root
-    repo_root = options.repo_root or project_root.parents[3]
-    try:
-        verify(project_root, repo_root)
-    except (KeyError, VerificationError) as error:
-        print(f"wasix-postmaster source-lock verification failed: {error}", file=sys.stderr)
-        return 1
-    print("wasix-postmaster source lock verified")
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-source-lock.test.py b/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-source-lock.test.py
deleted file mode 100755
index c188d3521..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-source-lock.test.py
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/env python3
-
-from __future__ import annotations
-
-import shutil
-import subprocess
-import tempfile
-from pathlib import Path
-
-
-PROJECT_ROOT = Path(__file__).resolve().parents[2]
-REPO_ROOT = PROJECT_ROOT.parents[3]
-VERIFIER = PROJECT_ROOT / "runtime/bin/verify-source-lock.py"
-
-
-def copy_file(source: Path, destination: Path) -> None:
-    destination.parent.mkdir(parents=True, exist_ok=True)
-    shutil.copy2(source, destination)
-
-
-def fixture(root: Path) -> tuple[Path, Path]:
-    repo = root / "repo"
-    project = repo / "src/runtimes/liboliphaunt/wasix-postmaster"
-    copy_file(PROJECT_ROOT / "sources.lock.toml", project / "sources.lock.toml")
-    copy_file(PROJECT_ROOT / "lib/common.sh", project / "lib/common.sh")
-    for patch in (
-        "postgres/patches/series",
-        "postgres/product-patch-provenance.toml",
-        "postgres/patches/0001-wasix-use-posix-dsm-not-sysv.patch",
-        "postgres/patches/0003-wasix-libpq-static-encoding-shim.patch",
-        "postgres/patches/0004-wasix-core-execbackend-initdb-runtime.patch",
-        "postgres/patches/0006-wasix-retry-proc-join-on-eintr.patch",
-        "postgres/patches/0008-wasix-packed-atomic-latch-state.patch",
-        "runtime/patches/wasmer/0001-postgres-wasix-blockers.patch",
-        "runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch",
-    ):
-        copy_file(PROJECT_ROOT / patch, project / patch)
-    shutil.copytree(
-        REPO_ROOT / "src/sources/third-party/wasix-postmaster",
-        repo / "src/sources/third-party/wasix-postmaster",
-    )
-    copy_file(
-        REPO_ROOT / "src/postgres/versions/18/source.toml",
-        repo / "src/postgres/versions/18/source.toml",
-    )
-    return project, repo
-
-
-def run(project: Path, repo: Path, *, succeeds: bool, marker: str = "") -> None:
-    result = subprocess.run(
-        [
-            "python3",
-            str(VERIFIER),
-            "--project-root",
-            str(project),
-            "--repo-root",
-            str(repo),
-        ],
-        check=False,
-        capture_output=True,
-        text=True,
-    )
-    if (result.returncode == 0) != succeeds:
-        raise AssertionError(
-            f"unexpected verifier status {result.returncode}\nstdout={result.stdout}\nstderr={result.stderr}"
-        )
-    combined = result.stdout + result.stderr
-    if marker and marker not in combined:
-        raise AssertionError(f"missing {marker!r} in verifier output: {combined}")
-
-
-def replace(path: Path, old: str, new: str) -> None:
-    contents = path.read_text(encoding="utf-8")
-    if old not in contents:
-        raise AssertionError(f"fixture marker missing from {path}: {old}")
-    path.write_text(contents.replace(old, new, 1), encoding="utf-8")
-
-
-def main() -> None:
-    run(PROJECT_ROOT, REPO_ROOT, succeeds=True, marker="source lock verified")
-
-    with tempfile.TemporaryDirectory(prefix="wasix-source-lock-test-") as temporary:
-        project, repo = fixture(Path(temporary))
-        run(project, repo, succeeds=True)
-        manifest = repo / "src/sources/third-party/wasix-postmaster/wasmer-test-files.toml"
-        replace(
-            manifest,
-            "7f27e84c69af3b772f751d6c4a733d9f448b2c70",
-            "0000000000000000000000000000000000000000",
-        )
-        run(project, repo, succeeds=False, marker="wasmer_test_files source commit")
-
-    with tempfile.TemporaryDirectory(prefix="wasix-source-lock-test-") as temporary:
-        project, repo = fixture(Path(temporary))
-        patch = project / "postgres/patches/0008-wasix-packed-atomic-latch-state.patch"
-        with patch.open("ab") as handle:
-            handle.write(b"\n")
-        run(
-            project,
-            repo,
-            succeeds=False,
-            marker="current_postgresql_product_inputs.file",
-        )
-
-    with tempfile.TemporaryDirectory(prefix="wasix-source-lock-test-") as temporary:
-        project, repo = fixture(Path(temporary))
-        lock = project / "sources.lock.toml"
-        replace(
-            lock,
-            'feature_macro = "PG_WASIX_ATOMIC_LATCH_STATE"',
-            'feature_macro = "PG_WASIX_UNSAFE_LATCH_STATE"',
-        )
-        run(
-            project,
-            repo,
-            succeeds=False,
-            marker="current_postgresql_patches.packed_atomic_latch_state.feature_macro",
-        )
-
-    with tempfile.TemporaryDirectory(prefix="wasix-source-lock-test-") as temporary:
-        project, repo = fixture(Path(temporary))
-        patch = project / "runtime/patches/wasmer/0001-postgres-wasix-blockers.patch"
-        with patch.open("ab") as handle:
-            handle.write(b"\n")
-        run(project, repo, succeeds=False, marker="current_runtime_patches.wasmer.bytes")
-
-    with tempfile.TemporaryDirectory(prefix="wasix-source-lock-test-") as temporary:
-        project, repo = fixture(Path(temporary))
-        patch = project / "runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
-        with patch.open("ab") as handle:
-            handle.write(b"\n")
-        run(
-            project,
-            repo,
-            succeeds=False,
-            marker="current_runtime_patches.wasix_libc.bytes",
-        )
-
-    with tempfile.TemporaryDirectory(prefix="wasix-source-lock-test-") as temporary:
-        project, repo = fixture(Path(temporary))
-        patch = project / "postgres/patches/0001-wasix-use-posix-dsm-not-sysv.patch"
-        with patch.open("ab") as handle:
-            handle.write(b"\n")
-        run(
-            project,
-            repo,
-            succeeds=False,
-            marker="current_postgresql_product_inputs.file",
-        )
-
-    print("source lock verifier tests passed")
-
-
-if __name__ == "__main__":
-    main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/sources.lock.toml b/src/runtimes/liboliphaunt/wasix-postmaster/sources.lock.toml
deleted file mode 100644
index 6139bf6e6..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/sources.lock.toml
+++ /dev/null
@@ -1,79 +0,0 @@
-[current_postgresql_product_inputs]
-
-[[current_postgresql_product_inputs.file]]
-path = "postgres/patches/series"
-sha256 = "3842f934e69d47a85c13e6ad37fb6d095b512bca56c3c0bdfac9e159ded26f22"
-bytes = 218
-
-[[current_postgresql_product_inputs.file]]
-path = "postgres/product-patch-provenance.toml"
-sha256 = "26e2b2e54bfe4c99b2007593e0eb34071030970fecca4b79a4056098dc81121e"
-bytes = 3445
-
-[[current_postgresql_product_inputs.file]]
-path = "postgres/patches/0001-wasix-use-posix-dsm-not-sysv.patch"
-sha256 = "17435fd5261a641837053728ed3314a2145307ab25bea473d5529b62a6a5aa3b"
-bytes = 883
-
-[[current_postgresql_product_inputs.file]]
-path = "postgres/patches/0003-wasix-libpq-static-encoding-shim.patch"
-sha256 = "a7eb6c9bd4366938fd40de1e8bdeaba600f4d9a42f5d2935677a795c3fcefc43"
-bytes = 501
-
-[[current_postgresql_product_inputs.file]]
-path = "postgres/patches/0004-wasix-core-execbackend-initdb-runtime.patch"
-sha256 = "acf40abd1498a92d122f939857086003e66962e51a2501b927391939981de502"
-bytes = 28650
-
-[[current_postgresql_product_inputs.file]]
-path = "postgres/patches/0006-wasix-retry-proc-join-on-eintr.patch"
-sha256 = "329fb6d098240b96d504165043f5b9f41f67439032b7dbf672367bffa4c78c14"
-bytes = 1751
-
-[[current_postgresql_product_inputs.file]]
-path = "postgres/patches/0008-wasix-packed-atomic-latch-state.patch"
-sha256 = "419eb45d4ee33aac428bc21a819409e4cd5fac5a227562c3e2c60a1a697fef43"
-bytes = 10236
-
-[current_postgresql_patches.packed_atomic_latch_state]
-path = "postgres/patches/0008-wasix-packed-atomic-latch-state.patch"
-base_tag = "REL_18_4"
-sha256 = "419eb45d4ee33aac428bc21a819409e4cd5fac5a227562c3e2c60a1a697fef43"
-bytes = 10236
-feature_macro = "PG_WASIX_ATOMIC_LATCH_STATE"
-native_behavior_preserved = true
-
-[current_runtime_patches.wasmer]
-path = "runtime/patches/wasmer/0001-postgres-wasix-blockers.patch"
-base_commit = "1d1b3420beef28550afbb4692b664bd7f6bc2581"
-sha256 = "dc08e0449829f42c23fbf822e87d61da5a500d5ced39bef2e501e7eec070d510"
-bytes = 1726836
-
-[current_runtime_patches.wasix_libc]
-path = "runtime/patches/wasix-libc/0001-postgres-wasix-blockers.patch"
-base_commit = "34178a6272804f90448b5bd08dc7bcf0d85438e3"
-sha256 = "116f0728a06e7b2e8e4189b0af6a7d22f40fb0fdda597a6170b5b6e712ddc3dc"
-bytes = 57623
-
-[postgresql]
-version = "18.4"
-tag = "REL_18_4"
-remote = "https://github.com/postgres/postgres.git"
-archive_sha256 = "81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094"
-
-[wasmer]
-version = "7.2.0-alpha.2"
-wasix_version = "0.702.0-alpha.2"
-tag = "v7.2.0-alpha.2"
-commit = "1d1b3420beef28550afbb4692b664bd7f6bc2581"
-napi_commit = "706383f42391cb4e4e82e5fd5e63a0ebf81ae19d"
-test_files_commit = "7f27e84c69af3b772f751d6c4a733d9f448b2c70"
-webassembly_testsuite_commit = "7e0b83aba9dbbb6e0623c9334b0f73b3bb584b90"
-remote = "https://github.com/wasmerio/wasmer.git"
-napi_remote = "https://github.com/wasmerio/napi.git"
-test_files_remote = "https://github.com/wasmerio/wasmer-test-files.git"
-webassembly_testsuite_remote = "https://github.com/WebAssembly/testsuite.git"
-
-[wasix_libc]
-commit = "34178a6272804f90448b5bd08dc7bcf0d85438e3"
-remote = "https://github.com/wasix-org/wasix-libc.git"
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/testdata/fake-postmaster-compiler.py b/src/runtimes/liboliphaunt/wasix-postmaster/testdata/fake-postmaster-compiler.py
deleted file mode 100755
index e32b1a0c1..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/testdata/fake-postmaster-compiler.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python3
-
-"""Minimal receipt-aware product-compiler fixture."""
-
-from __future__ import annotations
-
-import hashlib
-import pathlib
-import sys
-
-
-PROFILE = "oliphaunt.wasix-postmaster.linear-memory.wasm32-max256m-u64-static4g-guard2g.v1"
-
-
-def main() -> int:
-    arguments = sys.argv[1:]
-    if arguments == ["--version"]:
-        print(f"oliphaunt-wasix-postmaster-compiler fixture {PROFILE}")
-        return 0
-    if len(arguments) == 3 and arguments[0] == "verify-aot":
-        module = pathlib.Path(arguments[1])
-        artifact = pathlib.Path(arguments[2])
-        expected = b"fake-product-aot\0" + hashlib.sha256(module.read_bytes()).digest()
-        if artifact.read_bytes() != expected:
-            raise SystemExit("fake product AOT identity differs")
-        print(hashlib.sha256(module.read_bytes()).hexdigest())
-        return 0
-    try:
-        output_index = arguments.index("-o")
-        output = pathlib.Path(arguments[output_index + 1])
-        module = pathlib.Path(arguments[-1])
-    except (ValueError, IndexError):
-        raise SystemExit("fake product compiler requires -o OUTPUT MODULE")
-    if "--llvm" not in arguments or "--enable-exceptions" not in arguments or "--enable-threads" not in arguments:
-        raise SystemExit("fake product compiler requires LLVM, exceptions, and threads")
-    payload = module.read_bytes()
-    output.write_bytes(b"fake-product-aot\0" + hashlib.sha256(payload).digest())
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/testdata/fake-sealed-wasmer.py b/src/runtimes/liboliphaunt/wasix-postmaster/testdata/fake-sealed-wasmer.py
deleted file mode 100755
index 438455ed9..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/testdata/fake-sealed-wasmer.py
+++ /dev/null
@@ -1,251 +0,0 @@
-#!/usr/bin/env python3
-
-"""Behavioral fake for the sealed carrier shell test.
-
-It validates the provisional/final manifest transition and emits deterministic
-memory-image capture artifacts. It is not installed or used by product code.
-"""
-
-import hashlib
-import json
-import os
-import pathlib
-import sys
-
-
-
-def fail(message):
-    raise SystemExit(f"fake sealed Wasmer: {message}")
-
-
-def parse_run(arguments):
-    if not arguments or arguments[0] != "run":
-        return {}, pathlib.Path(), [], []
-    values = {}
-    value_options = {
-        "--stack-size",
-        "--sealed-module-manifest",
-        "--emit-preinitialized-memory-image",
-        "--emit-preinitialized-memory-receipt",
-    }
-    flag_options = {
-        "--disable-cache",
-        "--enable-exceptions",
-        "--enable-threads",
-        "--net",
-        "--quiet",
-    }
-    seen_flags = set()
-    volumes = []
-    guest_arguments = []
-    index = 1
-    input_path = None
-    while index < len(arguments):
-        argument = arguments[index]
-        if argument == "--":
-            guest_arguments = arguments[index + 1 :]
-            break
-        if argument == "--volume":
-            index += 1
-            if index >= len(arguments):
-                fail(f"{argument} has no value")
-            volumes.append(arguments[index])
-        elif argument in value_options:
-            if argument in values:
-                fail(f"duplicate option: {argument}")
-            index += 1
-            if index >= len(arguments):
-                fail(f"{argument} has no value")
-            values[argument] = arguments[index]
-        elif argument in flag_options:
-            if argument in seen_flags:
-                fail(f"duplicate option: {argument}")
-            seen_flags.add(argument)
-        elif argument.startswith("-"):
-            fail(f"unknown option: {argument}")
-        elif input_path is None:
-            input_path = pathlib.Path(argument)
-        index += 1
-    if input_path is None:
-        fail("run has no input module")
-    required_flags = {
-        "--disable-cache",
-        "--enable-exceptions",
-        "--enable-threads",
-        "--net",
-    }
-    if not required_flags.issubset(seen_flags):
-        fail(f"run lacks required flags: {sorted(required_flags - seen_flags)}")
-    if not volumes:
-        fail("run has no volume")
-    return values, input_path, volumes, guest_arguments
-
-
-def file_sha256(path):
-    digest = hashlib.sha256()
-    with path.open("rb", buffering=0) as stream:
-        for chunk in iter(lambda: stream.read(1024 * 1024), b""):
-            digest.update(chunk)
-    return digest.hexdigest()
-
-
-def volume_for_guest(volumes, guest):
-    matches = []
-    for volume in volumes:
-        if ":" not in volume:
-            continue
-        host, mounted_at = volume.rsplit(":", 1)
-        if mounted_at == guest:
-            matches.append(pathlib.Path(host))
-    if len(matches) != 1:
-        fail(f"expected exactly one volume mounted at {guest}, got {len(matches)}")
-    return matches[0]
-
-
-def append_validation_log(program, guest_arguments, volumes):
-    validation_log = os.environ.get("FAKE_WASMER_VALIDATION_LOG")
-    if not validation_log:
-        return
-    record = {
-        "program": program,
-        "arguments": guest_arguments,
-        "volumes": volumes,
-    }
-    with open(validation_log, "a", encoding="utf-8", newline="\n") as stream:
-        json.dump(record, stream, sort_keys=True)
-        stream.write("\n")
-
-
-def main():
-    values, module_path, volumes, guest_arguments = parse_run(sys.argv[1:])
-    if not values:
-        return
-    manifest_path = pathlib.Path(values.get("--sealed-module-manifest", ""))
-    if not manifest_path.is_file():
-        fail("run did not receive a sealed manifest")
-    carrier_root = manifest_path.resolve().parent
-    expected_lib_volume = f"{carrier_root / 'lib'}:/lib"
-    if volumes.count(expected_lib_volume) != 1:
-        fail(
-            "run did not mount the exact staged library closure at /lib: "
-            f"expected {expected_lib_volume!r}, got {volumes!r}"
-        )
-    volume_for_guest(volumes, "/lib")
-    with manifest_path.open(encoding="utf-8") as stream:
-        manifest = json.load(stream)
-    image_value = values.get("--emit-preinitialized-memory-image")
-    receipt_value = values.get("--emit-preinitialized-memory-receipt")
-    if bool(image_value) != bool(receipt_value):
-        fail("capture image and receipt were not paired")
-
-    if image_value:
-        if guest_arguments != ["--version"]:
-            fail("memory capture did not use a side-effect-free version probe")
-        if manifest.get("format-version") != 4:
-            fail("capture did not use manifest format 4")
-        if manifest.get("schema") != "oliphaunt.wasix-postmaster.sealed-aot.v3":
-            fail("capture did not use sealed-aot.v3")
-        if any("preinitialized-memory" in artifact for artifact in manifest["artifacts"]):
-            fail("capture manifest already contains a memory image")
-
-        module_sha256 = file_sha256(module_path)
-        image_path = pathlib.Path(image_value)
-        receipt_path = pathlib.Path(receipt_value)
-        image_size = 65536
-        seed = bytes.fromhex(module_sha256)
-        image = bytearray((seed * (image_size // len(seed) + 1))[:image_size])
-        if os.environ.get("FAKE_WASMER_NONDETERMINISTIC") == "1" and image_path.parent.name == "2":
-            image[-1] ^= 0xFF
-        image_path.write_bytes(image)
-
-        receipt = {
-            "schema": "oliphaunt.wasix-postmaster.memory-image.v1",
-            "module-sha256": module_sha256,
-            "runtime-abi-id": manifest["runtime-abi-id"],
-            "phase": "post-module-start-pre-link-relocations-v1",
-            "mapping-alignment": 65536,
-            "mapped-size": image_size,
-            "memory-minimum-pages": 1,
-            "memory-maximum-pages": 4096,
-            "memory-shared": True,
-            "memory-base": 4096,
-            "dylink-memory-size": 61440,
-            "dylink-memory-alignment": 12,
-            "stack-low": 65536,
-        }
-        if os.environ.get("FAKE_WASMER_RECEIPT_MISMATCH") == "1" and receipt_path.parent.name == "2":
-            receipt["phase"] = "different-phase"
-        if os.environ.get("FAKE_WASMER_INVALID_RECEIPT") == "1":
-            receipt["mapped-size"] = image_size + 1
-        with receipt_path.open("x", encoding="utf-8", newline="\n") as stream:
-            json.dump(receipt, stream, indent=2)
-            stream.write("\n")
-
-        capture_log = os.environ.get("FAKE_WASMER_CAPTURE_LOG")
-        if capture_log:
-            with open(capture_log, "a", encoding="utf-8", newline="\n") as stream:
-                stream.write(f"{module_path.name}\t{module_sha256}\n")
-        return
-
-    if manifest.get("format-version") != 6:
-        fail("validation did not use manifest format 6")
-    if manifest.get("schema") != "oliphaunt.wasix-postmaster.sealed-aot.v5":
-        fail("validation did not use sealed-aot.v5")
-    for artifact in manifest["artifacts"]:
-        if "preinitialized-memory" in artifact:
-            fail(f"final artifact {artifact['name']} has a preinitialized memory image")
-    expected_carrier_volume = f"{carrier_root}:{carrier_root}"
-    expected_share_volume = f"{carrier_root / 'share'}:/share"
-    if volumes.count(expected_carrier_volume) != 1:
-        fail("final validation did not mount the exact staged carrier path")
-    if volumes.count(expected_share_volume) != 1:
-        fail("final validation did not mount the exact staged share tree at /share")
-    volume_for_guest(volumes, str(carrier_root))
-    volume_for_guest(volumes, "/share")
-
-    expected_module = carrier_root / "bin" / module_path.name
-    if module_path.resolve() != expected_module:
-        fail("final validation did not execute the module from the staged carrier")
-    append_validation_log(module_path.name, guest_arguments, volumes)
-
-    if module_path.name == "postgres":
-        if guest_arguments != ["--version"]:
-            fail("final postgres validation was not a version probe")
-        return
-    if module_path.name != "initdb":
-        fail(f"unexpected final executable validation: {module_path.name}")
-
-    expected_initdb_arguments = [
-        "-D",
-        "/pgdata",
-        "-A",
-        "trust",
-        "--no-locale",
-        "--encoding=UTF8",
-        "--no-instructions",
-    ]
-    if guest_arguments != expected_initdb_arguments:
-        fail(
-            "final initdb validation did not run the real bootstrap lifecycle: "
-            f"got {guest_arguments!r}"
-        )
-    pgdata = volume_for_guest(volumes, "/pgdata").resolve()
-    dev_shm = volume_for_guest(volumes, "/dev/shm").resolve()
-    if not pgdata.is_dir() or not os.access(pgdata, os.W_OK):
-        fail("final initdb validation PGDATA is not a writable host directory")
-    if not dev_shm.is_dir() or not os.access(dev_shm, os.W_OK):
-        fail("final initdb validation /dev/shm is not a writable host directory")
-    if pgdata == carrier_root or carrier_root in pgdata.parents:
-        fail("final initdb validation PGDATA overlaps the staged carrier")
-    if dev_shm == carrier_root or carrier_root in dev_shm.parents:
-        fail("final initdb validation /dev/shm overlaps the staged carrier")
-    if os.environ.get("FAKE_WASMER_FAIL_FINAL_INITDB") == "1":
-        fail("requested final initdb lifecycle failure")
-    if os.environ.get("FAKE_WASMER_SKIP_INITDB_OUTPUT") != "1":
-        (pgdata / "global").mkdir()
-        (pgdata / "PG_VERSION").write_text("18\n", encoding="utf-8")
-        (pgdata / "global" / "pg_control").write_bytes(b"fake-pg-control\n")
-
-
-if __name__ == "__main__":
-    main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/testdata/fake-start-proof.py b/src/runtimes/liboliphaunt/wasix-postmaster/testdata/fake-start-proof.py
deleted file mode 100755
index 1c549aa6f..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/testdata/fake-start-proof.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python3
-
-"""Receipt-bound deterministic-start analyzer fixture for carrier tests."""
-
-import hashlib
-import json
-import os
-import pathlib
-import sys
-
-
-POLICY = "llvm-shared-memory-init-restricted-effects.v1"
-
-
-def file_sha256(path: pathlib.Path) -> str:
-    digest = hashlib.sha256()
-    with path.open("rb", buffering=0) as stream:
-        for chunk in iter(lambda: stream.read(1024 * 1024), b""):
-            digest.update(chunk)
-    return digest.hexdigest()
-
-
-def main() -> None:
-    if sys.argv[1:] == ["--policy-id"]:
-        print(POLICY)
-        return
-    if len(sys.argv) != 2:
-        raise SystemExit("usage: fake-start-proof.py MODULE | --policy-id")
-
-    module = pathlib.Path(sys.argv[1])
-    if not module.is_file() or module.is_symlink():
-        raise SystemExit(f"not a regular module: {module}")
-    module_sha256 = file_sha256(module)
-    if os.environ.get("FAKE_START_PROOF_WRONG_MODULE") == "1":
-        module_sha256 = "ff" * 32
-    proof_seed = (
-        POLICY.encode("ascii")
-        + b"\0"
-        + module_sha256.encode("ascii")
-        + b"\0fake-restricted-start-closure"
-    )
-    proof = {
-        "schema": "oliphaunt.wasix-postmaster.deterministic-start-proof.v1",
-        "analyzer-policy": POLICY,
-        "module-sha256": module_sha256,
-        "proof-sha256": hashlib.sha256(proof_seed).hexdigest(),
-        "start-function-index": 147,
-        "start-function-export": "__wasm_init_memory",
-        "transitive-function-indices": [147, 148],
-        "imported-function-calls": 0,
-        "memory-reads": "fresh-zero-atomic-guard-only",
-        "memory-effects": "passive-data-init-zero-fill-atomic-guard-only",
-        "global-effects": "local-numeric-relocations-only",
-        "table-effects": "none",
-        "requires-fresh-zeroed-memory": True,
-        "ordinary-start-execution-per-instance": True,
-        "first-instance-full-byte-validation": True,
-    }
-    if os.environ.get("FAKE_START_PROOF_INVALID") == "1":
-        proof["imported-function-calls"] = 1
-    json.dump(proof, sys.stdout, ensure_ascii=False, indent=2)
-    sys.stdout.write("\n")
-
-
-if __name__ == "__main__":
-    main()
diff --git a/src/runtimes/liboliphaunt/wasix-postmaster/testdata/make-sealed-export-fixture.py b/src/runtimes/liboliphaunt/wasix-postmaster/testdata/make-sealed-export-fixture.py
deleted file mode 100755
index ca7017d2a..000000000
--- a/src/runtimes/liboliphaunt/wasix-postmaster/testdata/make-sealed-export-fixture.py
+++ /dev/null
@@ -1,166 +0,0 @@
-#!/usr/bin/env python3
-
-"""Create a strict synthetic sealed-export predecessor for product tests."""
-
-from __future__ import annotations
-
-import argparse
-import hashlib
-import json
-from pathlib import Path
-
-
-def digest(data: bytes) -> str:
-    return hashlib.sha256(data).hexdigest()
-
-
-def json_bytes(value: object) -> bytes:
-    return (json.dumps(value, indent=2, sort_keys=True) + "\n").encode()
-
-
-def uleb128(value: int) -> bytes:
-    encoded = bytearray()
-    while True:
-        byte = value & 0x7F
-        value >>= 7
-        encoded.append(byte | (0x80 if value else 0))
-        if not value:
-            return bytes(encoded)
-
-
-def fixture_module(template: bytes, identity: str) -> bytes:
-    name = b"oliphaunt.fixture"
-    payload = uleb128(len(name)) + name + identity.encode()
-    return template + b"\0" + uleb128(len(payload)) + payload
-
-
-def module_summary(path: str, sha256: str, size: int) -> dict[str, object]:
-    return {
-        "path": path,
-        "sha256": sha256,
-        "bytes": size,
-        "non-export-sections-sha256": digest(f"sections:{path}".encode()),
-        "dylink-needed": [],
-        "imported-functions": 0,
-        "local-functions": 1,
-        "imported-globals": 0,
-        "local-globals": 0,
-        "imported-tables": 0,
-        "local-tables": 1,
-        "element-function-entries": 1,
-        "element-unique-function-indices": 1,
-        "element-max-function-index": 0,
-        "start-function-index": 0,
-        "imports": [],
-        "export-counts": {},
-        "exported-global-type-counts": {},
-        "exported-immutable-i32-globals": 0,
-        "exported-local-functions": 0,
-        "exported-imported-functions": 0,
-    }
-
-
-def proof(main: dict[str, object], sides: list[dict[str, object]], mandatory: str, dlsym: str) -> dict[str, object]:
-    return {
-        "schema": "oliphaunt.wasix-postmaster.sealed-export-closure-proof.v2",
-        "policy-id": "oliphaunt.wasix-postmaster.sealed-export-closure.v1",
-        "analyzer-version": "fixture",
-        "mandatory-policy-sha256": mandatory,
-        "declared-main-dlsym-policy-sha256": dlsym,
-        "main": main,
-        "sides": sides,
-        "mandatory-runtime-exports": [],
-        "declared-main-dlsym-exports": [],
-        "side-dynamic-imports": [],
-        "retained-main-exports": [],
-        "retained-main-export-descriptors": [],
-        "removed-main-export-count": 1,
-        "removed-main-export-names-sha256": digest(b"fixture-removed"),
-        "unresolved-main-requirements": [],
-        "mismatched-main-requirements": [],
-        "unresolved-side-dependencies": [],
-        "retained-counts": {},
-        "removed-counts": {"function": 1},
-    }
-
-
-def snapshot(module_sha256: str, size: int) -> dict[str, object]:
-    return {
-        "sha256": module_sha256,
-        "bytes": size,
-        "exports": 0,
-        "local-functions": 1,
-        "local-globals": 0,
-        "element-function-entries": 1,
-        "element-unique-function-indices": 1,
-        "start-function-index": 0,
-    }
-
-
-def main() -> int:
-    parser = argparse.ArgumentParser()
-    parser.add_argument("--install-root", type=Path, required=True)
-    parser.add_argument("--project-root", type=Path, required=True)
-    arguments = parser.parse_args()
-    root = arguments.install_root
-    policy_root = arguments.project_root / "runtime" / "policies"
-    side_manifest = policy_root / "sealed-side-modules.v1.tsv"
-    side_paths = [
-        line.split("\t", 1)[0]
-        for line in side_manifest.read_text(encoding="utf-8").splitlines()
-        if line and not line.startswith("#")
-    ]
-    assert len(side_paths) == 27
-    template = (root / "lib/libpq.so.5.18").read_bytes()
-    for relative in side_paths:
-        path = root / relative
-        path.parent.mkdir(parents=True, exist_ok=True)
-        if not path.exists():
-            # Keep fixture modules distinct so the carrier test also exercises
-            # one AOT identity per declared side module.
-            path.write_bytes(fixture_module(template, relative))
-
-    mandatory_hash = digest((policy_root / "sealed-main-runtime-exports.v1.txt").read_bytes())
-    dlsym_hash = digest((policy_root / "sealed-main-dlsym-exports.v1.txt").read_bytes())
-    sides = [
-        module_summary(relative, digest((root / relative).read_bytes()), (root / relative).stat().st_size)
-        for relative in side_paths
-    ]
-    postgres = (root / "bin/postgres").read_bytes()
-    final_main = module_summary("bin/postgres", digest(postgres), len(postgres))
-    seed_sha = digest(b"pre-dce-fixture\0" + postgres)
-    seed_main = module_summary("bin/postgres", seed_sha, len(postgres) + 16)
-    seed_proof_data = json_bytes(proof(seed_main, sides, mandatory_hash, dlsym_hash))
-    final_proof_data = json_bytes(proof(final_main, sides, mandatory_hash, dlsym_hash))
-    share = root / "share/postgresql"
-    share.mkdir(parents=True, exist_ok=True)
-    seed_path = share / "wasix-postmaster.sealed-export.seed-proof.json"
-    final_path = share / "wasix-postmaster.sealed-export.final-proof.json"
-    allowlist_path = share / "wasix-postmaster.sealed-export.allowlist"
-    seed_path.write_bytes(seed_proof_data)
-    final_path.write_bytes(final_proof_data)
-    allowlist_path.write_bytes(b"fixture-export\n")
-    receipt = {
-        "schema": "oliphaunt.wasix-postmaster.sealed-export-structure.v1",
-        "policy-id": "oliphaunt.wasix-postmaster.sealed-export-closure.v1",
-        "analyzer-version": "fixture",
-        "analyzer-binary-sha256": "0" * 64,
-        "dce-tool-sha256": "1" * 64,
-        "dce-tool-version": "fixture-wasm-opt",
-        "dce-passes": ["--remove-unused-module-elements"],
-        "mandatory-policy-sha256": mandatory_hash,
-        "declared-main-dlsym-policy-sha256": dlsym_hash,
-        "side-manifest-sha256": digest(side_manifest.read_bytes()),
-        "allowlist-sha256": digest(allowlist_path.read_bytes()),
-        "seed-proof-sha256": digest(seed_proof_data),
-        "final-proof-sha256": digest(final_proof_data),
-        "seed": snapshot(seed_sha, len(postgres) + 16),
-        "final-module": snapshot(digest(postgres), len(postgres)),
-        "sides": [{"path": side["path"], "sha256": side["sha256"]} for side in sides],
-    }
-    (share / "wasix-postmaster.sealed-export.structure.receipt").write_bytes(json_bytes(receipt))
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/runtimes/liboliphaunt/wasix/CHANGELOG.md b/src/runtimes/liboliphaunt/wasix/CHANGELOG.md
deleted file mode 100644
index c9f630ea5..000000000
--- a/src/runtimes/liboliphaunt/wasix/CHANGELOG.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# Changelog
-
-## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-wasix-v0.1.1...liboliphaunt-wasix-v0.2.0) (2026-09-05)
-
-
-### ⚠ BREAKING CHANGES
-
-* **wasix-ts:** run host runtimes through Rust Node-API ([#156](https://github.com/f0rr0/oliphaunt/issues/156))
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
-
-### Features
-
-* **contrib:** shared contrib carrier source: simplify releases and make contrib runtime-owned (#127) (c45082dc)
-* **contrib:** shared contrib carrier source: unify native and WASIX runtimes and SDKs (#129) (fae2bd7b)
-* **contrib:** shared contrib carrier source: model independent product dependencies (#173) (2d5f90c8)
-* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
-* **wasix-ts:** run host runtimes through Rust Node-API ([#156](https://github.com/f0rr0/oliphaunt/issues/156)) ([28e07be](https://github.com/f0rr0/oliphaunt/commit/28e07be782388915b28ad3fd30e3e78143710d28))
-
-
-### Bug Fixes
-
-* **wasix:** align WAL sync patch identity ([#163](https://github.com/f0rr0/oliphaunt/issues/163)) ([1708ef4](https://github.com/f0rr0/oliphaunt/commit/1708ef43aa092645cac57564c20bbd40e89d3894))
-* **wasix:** reject unsupported WAL open-sync modes ([#159](https://github.com/f0rr0/oliphaunt/issues/159)) ([6e9f903](https://github.com/f0rr0/oliphaunt/commit/6e9f9032ef802a970dc1d763e29b66b8e5d17f2f))
-
-
-### Performance Improvements
-
-* **wasix:** cache JSONB constructor metadata ([#164](https://github.com/f0rr0/oliphaunt/issues/164)) ([31bb5e1](https://github.com/f0rr0/oliphaunt/commit/31bb5e19b13ea002b311dfb57f110dfc54cf563e))
-
-
-### Code Refactoring
-
-* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
-* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
-
-## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/liboliphaunt-wasix-v0.1.0...liboliphaunt-wasix-v0.1.1) (2026-08-08)
-
-
-### Bug Fixes
-
-* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))
-
-## 0.1.0 (2026-07-28)
-
-
-### Features
-
-* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_geos.sh b/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_geos.sh
deleted file mode 100755
index 5e83cc7a6..000000000
--- a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_geos.sh
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-. "$ROOT/wasix_third_party.sh"
-
-REPO_ROOT="$(oliphaunt_wasix_repo_root "$ROOT")"
-GEOS_SOURCE_DIR="${GEOS_SOURCE_DIR:-$REPO_ROOT/target/oliphaunt-sources/checkouts/geos}"
-GENERATED_ROOT="$(oliphaunt_wasix_generated_root "$REPO_ROOT")"
-GEOS_PREFIX="${GEOS_PREFIX:-$GENERATED_ROOT/work/geos-wasix}"
-GEOS_BUILD_DIR="${GEOS_BUILD_DIR:-$GENERATED_ROOT/work/geos-wasix-build}"
-JOBS="${JOBS:-4}"
-
-if [ ! -f "$GEOS_SOURCE_DIR/CMakeLists.txt" ]; then
-  echo "missing GEOS source checkout at $GEOS_SOURCE_DIR; run assets fetch/source-spine first" >&2
-  exit 1
-fi
-
-. "$ROOT/docker_wasix_env.sh"
-. "$ROOT/profile_flags.sh"
-oliphaunt_wasix_apply_wasix_profile build
-
-source_commit="$(oliphaunt_wasix_source_commit "$GEOS_SOURCE_DIR")"
-script_sha256="$(oliphaunt_wasix_script_sha256 "$0")"
-helper_sha256="$(oliphaunt_wasix_script_sha256 "$ROOT/wasix_third_party.sh")"
-wasixcc_version="$(wasixcc --version 2>/dev/null)"
-wasixcc_version="${wasixcc_version%%$'\n'*}"
-stamp="source=$source_commit
-script=$script_sha256
-helper=$helper_sha256
-profile=$(oliphaunt_wasix_wasix_profile_signature)
-wasixcc=$wasixcc_version
-cmake=static-libs-only-no-tests"
-
-if [ -f "$GEOS_PREFIX/.oliphaunt-wasix-geos-build" ] &&
-   [ -f "$GEOS_PREFIX/include/geos_c.h" ] &&
-   [ -f "$GEOS_PREFIX/lib/libgeos_c.a" ] &&
-   [ -f "$GEOS_PREFIX/lib/libgeos.a" ] &&
-   [ "$(cat "$GEOS_PREFIX/.oliphaunt-wasix-geos-build")" = "$stamp" ]; then
-  echo "$GEOS_PREFIX"
-  exit 0
-fi
-
-{
-  rm -rf "$GEOS_BUILD_DIR" "$GEOS_PREFIX"
-  mkdir -p "$GEOS_BUILD_DIR" "$(dirname "$GEOS_PREFIX")"
-  oliphaunt_wasix_static_cmake_build \
-    "$GEOS_SOURCE_DIR" \
-    "$GEOS_BUILD_DIR" \
-    "$GEOS_PREFIX" \
-    -DBUILD_TESTING=OFF \
-    -DBUILD_BENCHMARKS=OFF \
-    -DBUILD_GEOSOP=OFF \
-    -DGEOS_BUILD_DEVELOPER=OFF
-} >&2
-
-test -f "$GEOS_PREFIX/include/geos_c.h"
-test -f "$GEOS_PREFIX/lib/libgeos_c.a"
-test -f "$GEOS_PREFIX/lib/libgeos.a"
-printf '%s\n' "$stamp" > "$GEOS_PREFIX/.oliphaunt-wasix-geos-build"
-echo "$GEOS_PREFIX"
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_proj.sh b/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_proj.sh
deleted file mode 100755
index 684bf8f9b..000000000
--- a/src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_proj.sh
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-. "$ROOT/wasix_third_party.sh"
-
-REPO_ROOT="$(oliphaunt_wasix_repo_root "$ROOT")"
-PROJ_SOURCE_DIR="${PROJ_SOURCE_DIR:-$REPO_ROOT/target/oliphaunt-sources/checkouts/proj}"
-GENERATED_ROOT="$(oliphaunt_wasix_generated_root "$REPO_ROOT")"
-PROJ_PREFIX="${PROJ_PREFIX:-$GENERATED_ROOT/work/proj-wasix}"
-PROJ_BUILD_DIR="${PROJ_BUILD_DIR:-$GENERATED_ROOT/work/proj-wasix-build}"
-SQLITE_PREFIX="${SQLITE_PREFIX:-$("$ROOT/build_wasix_sqlite.sh")}"
-JOBS="${JOBS:-4}"
-
-if [ ! -f "$PROJ_SOURCE_DIR/CMakeLists.txt" ]; then
-  echo "missing PROJ source checkout at $PROJ_SOURCE_DIR; run assets fetch/source-spine first" >&2
-  exit 1
-fi
-
-. "$ROOT/docker_wasix_env.sh"
-. "$ROOT/profile_flags.sh"
-oliphaunt_wasix_apply_wasix_profile build
-
-source_commit="$(oliphaunt_wasix_source_commit "$PROJ_SOURCE_DIR")"
-sqlite_stamp="$(cat "$SQLITE_PREFIX/.oliphaunt-wasix-sqlite-build")"
-script_sha256="$(oliphaunt_wasix_script_sha256 "$0")"
-helper_sha256="$(oliphaunt_wasix_script_sha256 "$ROOT/wasix_third_party.sh")"
-sqlite_script_sha256="$(oliphaunt_wasix_script_sha256 "$ROOT/build_wasix_sqlite.sh")"
-wasixcc_version="$(wasixcc --version 2>/dev/null)"
-wasixcc_version="${wasixcc_version%%$'\n'*}"
-stamp="source=$source_commit
-sqlite=$sqlite_stamp
-script=$script_sha256
-sqlite_script=$sqlite_script_sha256
-helper=$helper_sha256
-profile=$(oliphaunt_wasix_wasix_profile_signature)
-wasixcc=$wasixcc_version
-cmake=static-libs-only-no-tiff-no-curl-no-libdl-embedded-projdb-install-projdb"
-
-if [ -f "$PROJ_PREFIX/.oliphaunt-wasix-proj-build" ] &&
-   [ -f "$PROJ_PREFIX/include/proj.h" ] &&
-   [ -f "$PROJ_PREFIX/lib/libproj.a" ] &&
-   [ -f "$PROJ_PREFIX/share/proj/proj.db" ] &&
-   [ "$(cat "$PROJ_PREFIX/.oliphaunt-wasix-proj-build")" = "$stamp" ]; then
-  echo "$PROJ_PREFIX"
-  exit 0
-fi
-
-{
-  rm -rf "$PROJ_BUILD_DIR" "$PROJ_PREFIX"
-  mkdir -p "$PROJ_BUILD_DIR" "$(dirname "$PROJ_PREFIX")"
-  oliphaunt_wasix_static_cmake_build \
-    "$PROJ_SOURCE_DIR" \
-    "$PROJ_BUILD_DIR" \
-    "$PROJ_PREFIX" \
-    -DSQLite3_INCLUDE_DIR="$SQLITE_PREFIX/include" \
-    -DSQLite3_LIBRARY="$SQLITE_PREFIX/lib/libsqlite3.a" \
-    -DEXE_SQLITE3="$(command -v sqlite3)" \
-    -DENABLE_TIFF=OFF \
-    -DENABLE_CURL=OFF \
-    -DENABLE_EMSCRIPTEN_FETCH=OFF \
-    -DHAVE_LIBDL=OFF \
-    -DBUILD_APPS=OFF \
-    -DBUILD_TESTING=OFF \
-    -DBUILD_EXAMPLES=OFF \
-    -DEMBED_RESOURCE_FILES=ON \
-    -DUSE_ONLY_EMBEDDED_RESOURCE_FILES=ON
-  mkdir -p "$PROJ_PREFIX/share/proj"
-  cp "$PROJ_BUILD_DIR/data/proj.db" "$PROJ_PREFIX/share/proj/proj.db"
-} >&2
-
-test -f "$PROJ_PREFIX/include/proj.h"
-test -f "$PROJ_PREFIX/lib/libproj.a"
-test -f "$PROJ_PREFIX/share/proj/proj.db"
-printf '%s\n' "$stamp" > "$PROJ_PREFIX/.oliphaunt-wasix-proj-build"
-echo "$PROJ_PREFIX"
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/experiment-patch-disposition.toml b/src/runtimes/liboliphaunt/wasix/assets/build/postgres/experiment-patch-disposition.toml
deleted file mode 100644
index 66ae1cb09..000000000
--- a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/experiment-patch-disposition.toml
+++ /dev/null
@@ -1,78 +0,0 @@
-# Disposition of PostgreSQL-source patches from:
-# f0rr0/wasix-pg18-experiment.
-#
-# This file is intentionally separate from the applied patch series.  It records
-# which experiment patches were ported into the PG18 WASIX runtime, which
-# were replaced by narrower patches, and which remain deferred or rejected.
-
-[metadata]
-source_repository = "f0rr0/wasix-pg18-experiment"
-source_branch = "f0rr0/wasix-pg18-experiment"
-source_path = "assets/wasix-build/experiments/fresh-wasix-postgres/patches"
-policy = "do-not-port-experiment-patches-without-a-recorded-wasix-runtime-rationale"
-
-[[patch]]
-experiment = "0001-wasix-use-posix-dsm-not-sysv.patch"
-status = "not-carried"
-wasix_runtime_decision = "replaced where relevant by 0010 and 0011"
-rationale = "The experiment patch changes full-concurrent PostgreSQL dynamic shared memory selection. The embedded WASIX runtime does not take postmaster DSM as a product constraint; it instead routes SysV shmem through the wasix-dl port header and explicitly selects POSIX semaphores."
-
-[[patch]]
-experiment = "0003-wasix-libpq-static-encoding-shim.patch"
-status = "covered-by-build-spine"
-wasix_runtime_decision = "covered by the WASIX bridge aliases and standalone pg_dump build path"
-rationale = "The released-lane bridge already provides weak pg_char_to_encoding and pg_encoding_to_char aliases for static pg_dump/libpq linkage. No PG18 source patch is needed unless a future configured build proves a tool-specific gap."
-
-[[patch]]
-experiment = "0004-wasix-core-execbackend-initdb-runtime.patch"
-status = "not-carried"
-wasix_runtime_decision = "full-concurrent runtime blocker patch, not embedded product shape"
-rationale = "The patch addresses EXEC_BACKEND, fork/exec, root checks, locale command probing, and directory fsync behavior for proper concurrent PostgreSQL under WASIX. The embedded WASIX runtime avoids the postmaster/fork lifecycle; any tool blocker found later should become a smaller tool-specific patch."
-
-[[patch]]
-experiment = "0005-pg-dump-avoid-lto-executequery-collision.patch"
-status = "ported"
-wasix_runtime_decision = "ported as 0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch"
-rationale = "This is a narrow pg_dump source hygiene patch that supports standalone WASIX tool builds under thin LTO without changing query behavior."
-
-[[patch]]
-experiment = "0006-like-literal-substring-fast-path.patch"
-status = "ported-with-tighter-guards"
-wasix_runtime_decision = "ported as 0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch"
-rationale = "The PG18 patch narrows the experiment shortcut to deterministic, case-sensitive LIKE matching for the simple %literal% shape and rejects escapes, _, inner %, lower/case-insensitive variants, and nondeterministic collations before using memchr/memcmp."
-
-[[patch]]
-experiment = "0007-top-xid-current-transaction-fast-path.patch"
-status = "ported"
-wasix_runtime_decision = "ported as 0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch"
-rationale = "The final PG18 patch keeps the upstream parallel and subtransaction paths and only short-circuits the ordinary top-level case after all alternate current-XID sources are absent."
-
-[[patch]]
-experiment = "0008-btree-int4-compare-fast-path.patch"
-status = "ported-with-tighter-guards"
-wasix_runtime_decision = "ported as 0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch"
-rationale = "The PG18 patch keeps index_getattr(), requires the built-in integer btree family, int4 input type, int4 or InvalidOid subtype, and InvalidOid collation. It does not assume every int4 opclass has the built-in ordering."
-
-[[patch]]
-experiment = "0009-btree-delete-stack-state.patch"
-status = "ported-with-single-user-gate"
-wasix_runtime_decision = "ported as 0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch"
-rationale = "The PG18 patch is restricted to __wasi__ and OLIPHAUNT_WASM_SINGLE_USER. It keeps deletion policy and tableam behavior unchanged while avoiding page-local allocator churn."
-
-[[patch]]
-experiment = "0010-btree-bottomup-delete-runtime-toggle.patch"
-status = "rejected-for-default-lane"
-wasix_runtime_decision = "diagnostic toggle was tested with Oliphaunt env names but not kept in the patch stack"
-rationale = "Disabling bottom-up deletion changes PostgreSQL's index maintenance behavior. A local PG18 WASIX port of the diagnostic hook made the default release-profile 9/10 run much slower before any override was enabled, so it is not a defensible carried patch."
-
-[[patch]]
-experiment = "0011-btree-first-int4-compare-fast-path.patch"
-status = "ported-with-tighter-guards"
-wasix_runtime_decision = "ported as 0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch"
-rationale = "The PG18 patch keeps the direct tuple-data read only for embedded WASIX, leaf pages, one-key non-null non-posting non-pivot tuples, built-in int4 btree family, int4 input type, InvalidOid collation, and non-DESC scan keys. Equal values still fall through to PostgreSQL's existing heap-TID and truncated-key tie-break logic."
-
-[[patch]]
-experiment = "0012-hash-bytes-unaligned-load-fast-path.patch"
-status = "ported"
-wasix_runtime_decision = "ported as 0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch"
-rationale = "The PG18 patch uses memcpy-based little-endian 32-bit loads under __wasi__ only, preserving defined C behavior while giving LLVM a wasm-load lowering opportunity."
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0033-oliphaunt-wasix-control-initdb-collation-discovery.patch b/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0033-oliphaunt-wasix-control-initdb-collation-discovery.patch
deleted file mode 100644
index cb9f93415..000000000
--- a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0033-oliphaunt-wasix-control-initdb-collation-discovery.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From 0000000000000000000000000000000000000033 Mon Sep 17 00:00:00 2001
-From: Oliphaunt Maintainers 
-Date: Mon, 22 Jun 2026 00:00:00 +0000
-Subject: [PATCH] oliphaunt-wasix: control initdb collation discovery
-
-Oliphaunt packages ICU data as an optional runtime resource. PostgreSQL 18
-refreshes the built-in unicode collation version and imports ICU collations
-during initdb. Both paths can open ICU data before the embedded WASIX runtime
-has a database to start.
-
-Keep the public import function at PostgreSQL semantics unless a controlled
-seed producer explicitly suppresses host discovery. Distributed standard seeds
-suppress both OS and ICU discovery; distributed ICU seeds suppress only OS
-discovery and use verified ICU data. The readiness signal gates only initdb's
-unicode-version probe, where optional ICU data might otherwise be opened too
-early.
----
- src/backend/commands/collationcmds.c | 17 ++++++++++++++---
- src/bin/initdb/initdb.c              |  9 ++++++++-
- 2 files changed, 22 insertions(+), 4 deletions(-)
-
-diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
---- a/src/backend/commands/collationcmds.c
-+++ b/src/backend/commands/collationcmds.c
-@@ -841,4 +841,11 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
-+	bool		oliphaunt_skip_system_collation_discovery =
-+		getenv("OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY") != NULL &&
-+		strcmp(getenv("OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY"),
-+			   "1") == 0;
-+	bool		oliphaunt_skip_icu_collation_discovery =
-+		getenv("OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY") != NULL &&
-+		strcmp(getenv("OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY"), "1") == 0;
- 	if (!superuser())
- 		ereport(ERROR,
- 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- 				 errmsg("must be superuser to import system collations")));
-@@ -851,6 +858,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
- 	/* Load collations known to libc, using "locale -a" to enumerate them */
- #ifdef READ_LOCALE_A_OUTPUT
--	{
-+	if (!oliphaunt_skip_system_collation_discovery)
-+	{
- 		FILE	   *locale_a_handle;
- 		char		localebuf[LOCALE_NAME_BUFLEN];
- 		int			nvalid = 0;
-@@ -976,7 +985,8 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
- 	 * confusing.
- 	 */
- #ifdef USE_ICU
--	{
-+	if (!oliphaunt_skip_icu_collation_discovery)
-+	{
- 		int			i;
- 
- 		/*
-@@ -1027,7 +1037,8 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
- 
- 	/* Load collations known to WIN32 */
- #ifdef ENUM_SYSTEM_LOCALE
--	{
-+	if (!oliphaunt_skip_system_collation_discovery)
-+	{
- 		int			nvalid = 0;
- 		CollParam	param;
- 
-diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
---- a/src/bin/initdb/initdb.c
-+++ b/src/bin/initdb/initdb.c
-@@ -1778,4 +1778,11 @@ setup_collation(FILE *cmdfd)
--	PG_CMD_PUTS("UPDATE pg_collation SET collversion = pg_collation_actual_version(oid) WHERE collname = 'unicode';\n\n");
--
-+	/*
-+	 * Oliphaunt standard seeds intentionally omit optional ICU data. Only the
-+	 * internal readiness signal is allowed to select the ICU catalog profile;
-+	 * inherited or user-authored ICU_DATA must not silently change initdb output.
-+	 */
-+	if (getenv("OLIPHAUNT_INTERNAL_ICU_READY") != NULL &&
-+		strcmp(getenv("OLIPHAUNT_INTERNAL_ICU_READY"), "1") == 0)
-+		PG_CMD_PUTS("UPDATE pg_collation SET collversion = pg_collation_actual_version(oid) WHERE collname = 'unicode';\n\n");
-+
- 	/* Import all collations we can find in the operating system */
- 	PG_CMD_PUTS("SELECT pg_import_system_collations('pg_catalog');\n\n");
---
-2.39.5
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/series b/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/series
deleted file mode 100644
index 6fd916aa6..000000000
--- a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/series
+++ /dev/null
@@ -1,43 +0,0 @@
-0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch
-0002-oliphaunt-wasix-add-backend-host-io-hooks.patch
-0003-oliphaunt-wasix-export-startup-packet-parser.patch
-0004-oliphaunt-wasix-add-host-lifecycle-exports.patch
-0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch
-0006-oliphaunt-wasix-report-copy-protocol-state.patch
-0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch
-0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch
-0009-oliphaunt-wasix-route-process-identity-through-port.patch
-0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch
-0011-oliphaunt-wasix-prefer-posix-semaphores.patch
-0012-oliphaunt-wasix-capture-startup-errors.patch
-0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch
-0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch
-0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch
-0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch
-0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch
-0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch
-0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch
-0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch
-0021-oliphaunt-wasix-declare-wasix-fork.patch
-0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch
-0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch
-0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch
-0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch
-0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch
-0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch
-0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch
-0029-oliphaunt-wasix-set-embedded-postmaster-environment.patch
-0030-oliphaunt-wasix-avoid-xlogwrite-prevseg-division.patch
-0031-oliphaunt-wasix-skip-activity-id-reporting.patch
-0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch
-0033-oliphaunt-wasix-control-initdb-collation-discovery.patch
-0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch
-0035-oliphaunt-wasix-use-single-backend-spinlocks.patch
-0036-oliphaunt-wasix-specialize-single-backend-atomics.patch
-0037-oliphaunt-wasix-buffer-strong-random.patch
-0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch
-0039-oliphaunt-wasix-inline-sigsetjmp.patch
-0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch
-0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch
-0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch
-0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/source.toml b/src/runtimes/liboliphaunt/wasix/assets/build/postgres/source.toml
deleted file mode 100644
index 8893e03ef..000000000
--- a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/source.toml
+++ /dev/null
@@ -1,46 +0,0 @@
-[patches]
-series = [
-  "0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch",
-  "0002-oliphaunt-wasix-add-backend-host-io-hooks.patch",
-  "0003-oliphaunt-wasix-export-startup-packet-parser.patch",
-  "0004-oliphaunt-wasix-add-host-lifecycle-exports.patch",
-  "0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch",
-  "0006-oliphaunt-wasix-report-copy-protocol-state.patch",
-  "0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch",
-  "0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch",
-  "0009-oliphaunt-wasix-route-process-identity-through-port.patch",
-  "0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch",
-  "0011-oliphaunt-wasix-prefer-posix-semaphores.patch",
-  "0012-oliphaunt-wasix-capture-startup-errors.patch",
-  "0013-oliphaunt-wasix-fail-active-portals-on-host-recovery.patch",
-  "0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch",
-  "0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch",
-  "0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch",
-  "0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch",
-  "0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch",
-  "0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch",
-  "0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch",
-  "0021-oliphaunt-wasix-declare-wasix-fork.patch",
-  "0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch",
-  "0023-oliphaunt-wasix-skip-data-dir-ownership-check-under-embedded-wasix.patch",
-  "0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch",
-  "0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch",
-  "0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch",
-  "0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch",
-  "0028-oliphaunt-wasix-use-lightweight-embedded-runtime-paths.patch",
-  "0029-oliphaunt-wasix-set-embedded-postmaster-environment.patch",
-  "0030-oliphaunt-wasix-avoid-xlogwrite-prevseg-division.patch",
-  "0031-oliphaunt-wasix-skip-activity-id-reporting.patch",
-  "0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch",
-  "0033-oliphaunt-wasix-control-initdb-collation-discovery.patch",
-  "0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch",
-  "0035-oliphaunt-wasix-use-single-backend-spinlocks.patch",
-  "0036-oliphaunt-wasix-specialize-single-backend-atomics.patch",
-  "0037-oliphaunt-wasix-buffer-strong-random.patch",
-  "0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch",
-  "0039-oliphaunt-wasix-inline-sigsetjmp.patch",
-  "0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch",
-  "0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch",
-  "0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch",
-  "0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch",
-]
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/wasix-toml-value.mjs b/src/runtimes/liboliphaunt/wasix/assets/build/wasix-toml-value.mjs
deleted file mode 100644
index 40b5aafcc..000000000
--- a/src/runtimes/liboliphaunt/wasix/assets/build/wasix-toml-value.mjs
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env bun
-
-function fail(message) {
-  console.error(message);
-  process.exit(2);
-}
-
-function usage() {
-  fail("usage: wasix-toml-value.mjs string|string-list  ");
-}
-
-function isObject(value) {
-  return value !== null && typeof value === "object" && !Array.isArray(value);
-}
-
-const [mode, file, key] = Bun.argv.slice(2);
-if ((mode !== "string" && mode !== "string-list") || !file || !key) {
-  usage();
-}
-
-let data;
-try {
-  data = Bun.TOML.parse(await Bun.file(file).text());
-} catch (error) {
-  fail(`could not read TOML file ${file}: ${error.message}`);
-}
-
-if (!isObject(data)) {
-  fail(`${file} must contain a TOML table`);
-}
-
-if (mode === "string-list") {
-  const values = Object.hasOwn(data, key) ? data[key] : [];
-  if (!Array.isArray(values) || !values.every((value) => typeof value === "string")) {
-    fail(`${file} field ${key} must be an array of strings`);
-  }
-  for (const value of values) {
-    console.log(value);
-  }
-} else {
-  const value = data[key];
-  if (typeof value !== "string" || value.length === 0) {
-    fail(`${file} field ${key} must be a non-empty string`);
-  }
-  console.log(value);
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/Cargo.toml
deleted file mode 100644
index f61e6a0fc..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "liboliphaunt-wasix-aot-aarch64-apple-darwin"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Wasmer AOT runtime artifacts for oliphaunt-wasix on aarch64-apple-darwin"
-repository = "https://github.com/f0rr0/oliphaunt"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_liboliphaunt_wasix_aot_macos_arm64"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-serde_json = "1"
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/build.rs b/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/build.rs
deleted file mode 100644
index f20c08e9f..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-apple-darwin/build.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
-const ARTIFACT_KIND: &str = "wasix-aot";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
-
-    let target = env::var("CARGO_PKG_NAME")
-        .expect("CARGO_PKG_NAME is set by Cargo")
-        .strip_prefix("liboliphaunt-wasix-aot-")
-        .expect("AOT crate name starts with liboliphaunt-wasix-aot-")
-        .to_owned();
-    emit_expected_artifact_inputs(&target);
-
-    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
-        .join("generated_aot.rs");
-    if let Some(artifact_dir) = find_artifact_dir(&target) {
-        emit_rerun_directives(&artifact_dir);
-        write_generated_aot(&out, &target, &artifact_dir);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX AOT artifacts for {target}");
-    } else {
-        write_source_only_aot(&out, &target);
-    }
-}
-
-fn emit_expected_artifact_inputs(target: &str) {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        emit_manifest_probe(&candidate);
-    }
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
-    }
-    emit_manifest_probe(&manifest_dir.join("artifacts"));
-}
-
-fn emit_manifest_probe(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("manifest.json").display()
-    );
-}
-
-fn find_artifact_dir(target: &str) -> Option {
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let package_artifacts = manifest_dir.join("artifacts");
-    if package_artifacts.join("manifest.json").is_file() {
-        return Some(package_artifacts);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        if candidate.join("manifest.json").is_file() {
-            return Some(candidate);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
-        if target_artifacts.join("manifest.json").is_file() {
-            return Some(target_artifacts);
-        }
-    }
-
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
-    manifest_dir.ancestors().find(|candidate| {
-        candidate.join("Cargo.toml").is_file()
-            && candidate
-                .join("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml")
-                .is_file()
-    })
-}
-
-fn emit_rerun_directives(artifact_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", artifact_dir.display());
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.is_file() {
-                println!("cargo:rerun-if-changed={}", path.display());
-            }
-        }
-    }
-}
-
-fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
-    let manifest = artifact_dir.join("manifest.json");
-    let generated_manifest = out
-        .parent()
-        .expect("generated AOT output has parent")
-        .join("manifest.json");
-    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
-    let mut cases = String::new();
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        let mut files = entries
-            .flatten()
-            .map(|entry| entry.path())
-            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
-            .collect::>();
-        files.sort();
-        for file in files {
-            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
-                continue;
-            };
-            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
-                continue;
-            };
-            let artifact_name = artifact_name_from_file_stem(stem);
-            if !artifact_belongs_to_crate(&artifact_name) {
-                continue;
-            }
-            cases.push_str(&format!(
-                "        {:?} => Some(include_bytes!({})),\n",
-                artifact_name,
-                rust_string_literal(&file)
-            ));
-        }
-    }
-    cases.push_str("        _ => None,\n");
-
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = true;\n\
-         pub const MANIFEST_JSON: &str = include_str!({});\n\
-         #[rustfmt::skip]\n\
-         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
-             match name {{\n\
-         {cases}    }}\n\
-         }}\n",
-        target,
-        rust_string_literal(&generated_manifest)
-    );
-    fs::write(out, text).expect("write generated AOT include module");
-    let mut manifest_files = vec![generated_manifest];
-    for relative in retained_paths {
-        manifest_files.push(artifact_dir.join(relative));
-    }
-    emit_artifact_manifest(
-        out.parent().expect("generated AOT output has parent"),
-        target,
-        artifact_dir,
-        &manifest_files,
-    );
-}
-
-fn write_source_only_aot(out: &Path, target: &str) {
-    let manifest = format!(
-        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
-    );
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {target:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = false;\n\
-         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
-         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
-    );
-    fs::write(out, text).expect("write source-only AOT include module");
-}
-
-fn artifact_name_from_file_stem(stem: &str) -> String {
-    match stem {
-        "oliphaunt" => "runtime:oliphaunt".to_owned(),
-        "pg_dump" => "tool:pg_dump".to_owned(),
-        "psql" => "tool:psql".to_owned(),
-        "initdb" => "tool:initdb".to_owned(),
-        "plpgsql" => "runtime-support:plpgsql".to_owned(),
-        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
-        extension_support if extension_support.ends_with("_deps") => {
-            let sql_name = extension_support.trim_end_matches("_deps");
-            format!("extension:{sql_name}:{extension_support}")
-        }
-        extension => format!("extension:{extension}"),
-    }
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn artifact_belongs_to_crate(name: &str) -> bool {
-    match ARTIFACT_KIND {
-        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
-        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
-    }
-}
-
-fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
-    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
-    let mut manifest: serde_json::Value =
-        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
-    let artifacts = manifest
-        .get_mut("artifacts")
-        .and_then(|value| value.as_array_mut())
-        .expect("generated WASIX AOT manifest has artifacts array");
-    let mut retained = Vec::new();
-    let mut paths = Vec::new();
-    for artifact in artifacts.drain(..) {
-        let name = artifact
-            .get("name")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has name")
-            .to_owned();
-        if !artifact_belongs_to_crate(&name) {
-            continue;
-        }
-        let path = artifact
-            .get("path")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has path")
-            .to_owned();
-        paths.push(path);
-        retained.push(artifact);
-    }
-    *artifacts = retained;
-    let rendered =
-        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
-    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
-    paths
-}
-
-fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
-    );
-    for file in files {
-        if !file.is_file() {
-            continue;
-        }
-        let relative = file
-            .strip_prefix(artifact_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| "manifest.json".to_owned());
-        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/Cargo.toml
deleted file mode 100644
index 9138276f7..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Wasmer AOT runtime artifacts for oliphaunt-wasix on aarch64-unknown-linux-gnu"
-repository = "https://github.com/f0rr0/oliphaunt"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_liboliphaunt_wasix_aot_linux_arm64_gnu"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-serde_json = "1"
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/build.rs b/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/build.rs
deleted file mode 100644
index f20c08e9f..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/aot/aarch64-unknown-linux-gnu/build.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
-const ARTIFACT_KIND: &str = "wasix-aot";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
-
-    let target = env::var("CARGO_PKG_NAME")
-        .expect("CARGO_PKG_NAME is set by Cargo")
-        .strip_prefix("liboliphaunt-wasix-aot-")
-        .expect("AOT crate name starts with liboliphaunt-wasix-aot-")
-        .to_owned();
-    emit_expected_artifact_inputs(&target);
-
-    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
-        .join("generated_aot.rs");
-    if let Some(artifact_dir) = find_artifact_dir(&target) {
-        emit_rerun_directives(&artifact_dir);
-        write_generated_aot(&out, &target, &artifact_dir);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX AOT artifacts for {target}");
-    } else {
-        write_source_only_aot(&out, &target);
-    }
-}
-
-fn emit_expected_artifact_inputs(target: &str) {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        emit_manifest_probe(&candidate);
-    }
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
-    }
-    emit_manifest_probe(&manifest_dir.join("artifacts"));
-}
-
-fn emit_manifest_probe(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("manifest.json").display()
-    );
-}
-
-fn find_artifact_dir(target: &str) -> Option {
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let package_artifacts = manifest_dir.join("artifacts");
-    if package_artifacts.join("manifest.json").is_file() {
-        return Some(package_artifacts);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        if candidate.join("manifest.json").is_file() {
-            return Some(candidate);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
-        if target_artifacts.join("manifest.json").is_file() {
-            return Some(target_artifacts);
-        }
-    }
-
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
-    manifest_dir.ancestors().find(|candidate| {
-        candidate.join("Cargo.toml").is_file()
-            && candidate
-                .join("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml")
-                .is_file()
-    })
-}
-
-fn emit_rerun_directives(artifact_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", artifact_dir.display());
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.is_file() {
-                println!("cargo:rerun-if-changed={}", path.display());
-            }
-        }
-    }
-}
-
-fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
-    let manifest = artifact_dir.join("manifest.json");
-    let generated_manifest = out
-        .parent()
-        .expect("generated AOT output has parent")
-        .join("manifest.json");
-    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
-    let mut cases = String::new();
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        let mut files = entries
-            .flatten()
-            .map(|entry| entry.path())
-            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
-            .collect::>();
-        files.sort();
-        for file in files {
-            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
-                continue;
-            };
-            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
-                continue;
-            };
-            let artifact_name = artifact_name_from_file_stem(stem);
-            if !artifact_belongs_to_crate(&artifact_name) {
-                continue;
-            }
-            cases.push_str(&format!(
-                "        {:?} => Some(include_bytes!({})),\n",
-                artifact_name,
-                rust_string_literal(&file)
-            ));
-        }
-    }
-    cases.push_str("        _ => None,\n");
-
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = true;\n\
-         pub const MANIFEST_JSON: &str = include_str!({});\n\
-         #[rustfmt::skip]\n\
-         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
-             match name {{\n\
-         {cases}    }}\n\
-         }}\n",
-        target,
-        rust_string_literal(&generated_manifest)
-    );
-    fs::write(out, text).expect("write generated AOT include module");
-    let mut manifest_files = vec![generated_manifest];
-    for relative in retained_paths {
-        manifest_files.push(artifact_dir.join(relative));
-    }
-    emit_artifact_manifest(
-        out.parent().expect("generated AOT output has parent"),
-        target,
-        artifact_dir,
-        &manifest_files,
-    );
-}
-
-fn write_source_only_aot(out: &Path, target: &str) {
-    let manifest = format!(
-        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
-    );
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {target:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = false;\n\
-         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
-         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
-    );
-    fs::write(out, text).expect("write source-only AOT include module");
-}
-
-fn artifact_name_from_file_stem(stem: &str) -> String {
-    match stem {
-        "oliphaunt" => "runtime:oliphaunt".to_owned(),
-        "pg_dump" => "tool:pg_dump".to_owned(),
-        "psql" => "tool:psql".to_owned(),
-        "initdb" => "tool:initdb".to_owned(),
-        "plpgsql" => "runtime-support:plpgsql".to_owned(),
-        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
-        extension_support if extension_support.ends_with("_deps") => {
-            let sql_name = extension_support.trim_end_matches("_deps");
-            format!("extension:{sql_name}:{extension_support}")
-        }
-        extension => format!("extension:{extension}"),
-    }
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn artifact_belongs_to_crate(name: &str) -> bool {
-    match ARTIFACT_KIND {
-        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
-        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
-    }
-}
-
-fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
-    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
-    let mut manifest: serde_json::Value =
-        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
-    let artifacts = manifest
-        .get_mut("artifacts")
-        .and_then(|value| value.as_array_mut())
-        .expect("generated WASIX AOT manifest has artifacts array");
-    let mut retained = Vec::new();
-    let mut paths = Vec::new();
-    for artifact in artifacts.drain(..) {
-        let name = artifact
-            .get("name")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has name")
-            .to_owned();
-        if !artifact_belongs_to_crate(&name) {
-            continue;
-        }
-        let path = artifact
-            .get("path")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has path")
-            .to_owned();
-        paths.push(path);
-        retained.push(artifact);
-    }
-    *artifacts = retained;
-    let rendered =
-        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
-    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
-    paths
-}
-
-fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
-    );
-    for file in files {
-        if !file.is_file() {
-            continue;
-        }
-        let relative = file
-            .strip_prefix(artifact_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| "manifest.json".to_owned());
-        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/Cargo.toml
deleted file mode 100644
index 05079e549..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Wasmer AOT runtime artifacts for oliphaunt-wasix on x86_64-pc-windows-msvc"
-repository = "https://github.com/f0rr0/oliphaunt"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_liboliphaunt_wasix_aot_windows_x64_msvc"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-serde_json = "1"
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/build.rs b/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/build.rs
deleted file mode 100644
index f20c08e9f..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-pc-windows-msvc/build.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
-const ARTIFACT_KIND: &str = "wasix-aot";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
-
-    let target = env::var("CARGO_PKG_NAME")
-        .expect("CARGO_PKG_NAME is set by Cargo")
-        .strip_prefix("liboliphaunt-wasix-aot-")
-        .expect("AOT crate name starts with liboliphaunt-wasix-aot-")
-        .to_owned();
-    emit_expected_artifact_inputs(&target);
-
-    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
-        .join("generated_aot.rs");
-    if let Some(artifact_dir) = find_artifact_dir(&target) {
-        emit_rerun_directives(&artifact_dir);
-        write_generated_aot(&out, &target, &artifact_dir);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX AOT artifacts for {target}");
-    } else {
-        write_source_only_aot(&out, &target);
-    }
-}
-
-fn emit_expected_artifact_inputs(target: &str) {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        emit_manifest_probe(&candidate);
-    }
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
-    }
-    emit_manifest_probe(&manifest_dir.join("artifacts"));
-}
-
-fn emit_manifest_probe(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("manifest.json").display()
-    );
-}
-
-fn find_artifact_dir(target: &str) -> Option {
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let package_artifacts = manifest_dir.join("artifacts");
-    if package_artifacts.join("manifest.json").is_file() {
-        return Some(package_artifacts);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        if candidate.join("manifest.json").is_file() {
-            return Some(candidate);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
-        if target_artifacts.join("manifest.json").is_file() {
-            return Some(target_artifacts);
-        }
-    }
-
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
-    manifest_dir.ancestors().find(|candidate| {
-        candidate.join("Cargo.toml").is_file()
-            && candidate
-                .join("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml")
-                .is_file()
-    })
-}
-
-fn emit_rerun_directives(artifact_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", artifact_dir.display());
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.is_file() {
-                println!("cargo:rerun-if-changed={}", path.display());
-            }
-        }
-    }
-}
-
-fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
-    let manifest = artifact_dir.join("manifest.json");
-    let generated_manifest = out
-        .parent()
-        .expect("generated AOT output has parent")
-        .join("manifest.json");
-    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
-    let mut cases = String::new();
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        let mut files = entries
-            .flatten()
-            .map(|entry| entry.path())
-            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
-            .collect::>();
-        files.sort();
-        for file in files {
-            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
-                continue;
-            };
-            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
-                continue;
-            };
-            let artifact_name = artifact_name_from_file_stem(stem);
-            if !artifact_belongs_to_crate(&artifact_name) {
-                continue;
-            }
-            cases.push_str(&format!(
-                "        {:?} => Some(include_bytes!({})),\n",
-                artifact_name,
-                rust_string_literal(&file)
-            ));
-        }
-    }
-    cases.push_str("        _ => None,\n");
-
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = true;\n\
-         pub const MANIFEST_JSON: &str = include_str!({});\n\
-         #[rustfmt::skip]\n\
-         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
-             match name {{\n\
-         {cases}    }}\n\
-         }}\n",
-        target,
-        rust_string_literal(&generated_manifest)
-    );
-    fs::write(out, text).expect("write generated AOT include module");
-    let mut manifest_files = vec![generated_manifest];
-    for relative in retained_paths {
-        manifest_files.push(artifact_dir.join(relative));
-    }
-    emit_artifact_manifest(
-        out.parent().expect("generated AOT output has parent"),
-        target,
-        artifact_dir,
-        &manifest_files,
-    );
-}
-
-fn write_source_only_aot(out: &Path, target: &str) {
-    let manifest = format!(
-        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
-    );
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {target:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = false;\n\
-         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
-         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
-    );
-    fs::write(out, text).expect("write source-only AOT include module");
-}
-
-fn artifact_name_from_file_stem(stem: &str) -> String {
-    match stem {
-        "oliphaunt" => "runtime:oliphaunt".to_owned(),
-        "pg_dump" => "tool:pg_dump".to_owned(),
-        "psql" => "tool:psql".to_owned(),
-        "initdb" => "tool:initdb".to_owned(),
-        "plpgsql" => "runtime-support:plpgsql".to_owned(),
-        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
-        extension_support if extension_support.ends_with("_deps") => {
-            let sql_name = extension_support.trim_end_matches("_deps");
-            format!("extension:{sql_name}:{extension_support}")
-        }
-        extension => format!("extension:{extension}"),
-    }
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn artifact_belongs_to_crate(name: &str) -> bool {
-    match ARTIFACT_KIND {
-        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
-        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
-    }
-}
-
-fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
-    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
-    let mut manifest: serde_json::Value =
-        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
-    let artifacts = manifest
-        .get_mut("artifacts")
-        .and_then(|value| value.as_array_mut())
-        .expect("generated WASIX AOT manifest has artifacts array");
-    let mut retained = Vec::new();
-    let mut paths = Vec::new();
-    for artifact in artifacts.drain(..) {
-        let name = artifact
-            .get("name")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has name")
-            .to_owned();
-        if !artifact_belongs_to_crate(&name) {
-            continue;
-        }
-        let path = artifact
-            .get("path")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has path")
-            .to_owned();
-        paths.push(path);
-        retained.push(artifact);
-    }
-    *artifacts = retained;
-    let rendered =
-        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
-    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
-    paths
-}
-
-fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
-    );
-    for file in files {
-        if !file.is_file() {
-            continue;
-        }
-        let relative = file
-            .strip_prefix(artifact_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| "manifest.json".to_owned());
-        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/Cargo.toml
deleted file mode 100644
index 8a6a8b06b..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Wasmer AOT runtime artifacts for oliphaunt-wasix on x86_64-unknown-linux-gnu"
-repository = "https://github.com/f0rr0/oliphaunt"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_liboliphaunt_wasix_aot_linux_x64_gnu"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-serde_json = "1"
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/build.rs b/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/build.rs
deleted file mode 100644
index f20c08e9f..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/aot/x86_64-unknown-linux-gnu/build.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
-const ARTIFACT_KIND: &str = "wasix-aot";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
-
-    let target = env::var("CARGO_PKG_NAME")
-        .expect("CARGO_PKG_NAME is set by Cargo")
-        .strip_prefix("liboliphaunt-wasix-aot-")
-        .expect("AOT crate name starts with liboliphaunt-wasix-aot-")
-        .to_owned();
-    emit_expected_artifact_inputs(&target);
-
-    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
-        .join("generated_aot.rs");
-    if let Some(artifact_dir) = find_artifact_dir(&target) {
-        emit_rerun_directives(&artifact_dir);
-        write_generated_aot(&out, &target, &artifact_dir);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX AOT artifacts for {target}");
-    } else {
-        write_source_only_aot(&out, &target);
-    }
-}
-
-fn emit_expected_artifact_inputs(target: &str) {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        emit_manifest_probe(&candidate);
-    }
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
-    }
-    emit_manifest_probe(&manifest_dir.join("artifacts"));
-}
-
-fn emit_manifest_probe(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("manifest.json").display()
-    );
-}
-
-fn find_artifact_dir(target: &str) -> Option {
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let package_artifacts = manifest_dir.join("artifacts");
-    if package_artifacts.join("manifest.json").is_file() {
-        return Some(package_artifacts);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        if candidate.join("manifest.json").is_file() {
-            return Some(candidate);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
-        if target_artifacts.join("manifest.json").is_file() {
-            return Some(target_artifacts);
-        }
-    }
-
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
-    manifest_dir.ancestors().find(|candidate| {
-        candidate.join("Cargo.toml").is_file()
-            && candidate
-                .join("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml")
-                .is_file()
-    })
-}
-
-fn emit_rerun_directives(artifact_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", artifact_dir.display());
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.is_file() {
-                println!("cargo:rerun-if-changed={}", path.display());
-            }
-        }
-    }
-}
-
-fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
-    let manifest = artifact_dir.join("manifest.json");
-    let generated_manifest = out
-        .parent()
-        .expect("generated AOT output has parent")
-        .join("manifest.json");
-    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
-    let mut cases = String::new();
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        let mut files = entries
-            .flatten()
-            .map(|entry| entry.path())
-            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
-            .collect::>();
-        files.sort();
-        for file in files {
-            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
-                continue;
-            };
-            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
-                continue;
-            };
-            let artifact_name = artifact_name_from_file_stem(stem);
-            if !artifact_belongs_to_crate(&artifact_name) {
-                continue;
-            }
-            cases.push_str(&format!(
-                "        {:?} => Some(include_bytes!({})),\n",
-                artifact_name,
-                rust_string_literal(&file)
-            ));
-        }
-    }
-    cases.push_str("        _ => None,\n");
-
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = true;\n\
-         pub const MANIFEST_JSON: &str = include_str!({});\n\
-         #[rustfmt::skip]\n\
-         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
-             match name {{\n\
-         {cases}    }}\n\
-         }}\n",
-        target,
-        rust_string_literal(&generated_manifest)
-    );
-    fs::write(out, text).expect("write generated AOT include module");
-    let mut manifest_files = vec![generated_manifest];
-    for relative in retained_paths {
-        manifest_files.push(artifact_dir.join(relative));
-    }
-    emit_artifact_manifest(
-        out.parent().expect("generated AOT output has parent"),
-        target,
-        artifact_dir,
-        &manifest_files,
-    );
-}
-
-fn write_source_only_aot(out: &Path, target: &str) {
-    let manifest = format!(
-        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
-    );
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {target:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = false;\n\
-         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
-         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
-    );
-    fs::write(out, text).expect("write source-only AOT include module");
-}
-
-fn artifact_name_from_file_stem(stem: &str) -> String {
-    match stem {
-        "oliphaunt" => "runtime:oliphaunt".to_owned(),
-        "pg_dump" => "tool:pg_dump".to_owned(),
-        "psql" => "tool:psql".to_owned(),
-        "initdb" => "tool:initdb".to_owned(),
-        "plpgsql" => "runtime-support:plpgsql".to_owned(),
-        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
-        extension_support if extension_support.ends_with("_deps") => {
-            let sql_name = extension_support.trim_end_matches("_deps");
-            format!("extension:{sql_name}:{extension_support}")
-        }
-        extension => format!("extension:{extension}"),
-    }
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn artifact_belongs_to_crate(name: &str) -> bool {
-    match ARTIFACT_KIND {
-        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
-        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
-    }
-}
-
-fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
-    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
-    let mut manifest: serde_json::Value =
-        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
-    let artifacts = manifest
-        .get_mut("artifacts")
-        .and_then(|value| value.as_array_mut())
-        .expect("generated WASIX AOT manifest has artifacts array");
-    let mut retained = Vec::new();
-    let mut paths = Vec::new();
-    for artifact in artifacts.drain(..) {
-        let name = artifact
-            .get("name")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has name")
-            .to_owned();
-        if !artifact_belongs_to_crate(&name) {
-            continue;
-        }
-        let path = artifact
-            .get("path")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has path")
-            .to_owned();
-        paths.push(path);
-        retained.push(artifact);
-    }
-    *artifacts = retained;
-    let rendered =
-        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
-    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
-    paths
-}
-
-fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
-    );
-    for file in files {
-        if !file.is_file() {
-            continue;
-        }
-        let relative = file
-            .strip_prefix(artifact_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| "manifest.json".to_owned());
-        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml
deleted file mode 100644
index 2ea3b51be..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml
+++ /dev/null
@@ -1,76 +0,0 @@
-[package]
-name = "liboliphaunt-wasix-portable"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Portable WASIX runtime assets for oliphaunt-wasix"
-repository = "https://github.com/f0rr0/oliphaunt"
-homepage = "https://oliphaunt.dev"
-documentation = "https://docs.rs/liboliphaunt-wasix-portable"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_liboliphaunt_wasix_runtime"
-include = [
-  "Cargo.toml",
-  "build.rs",
-  "README.md",
-  "src/**",
-  "payload/**",
-  "LICENSE",
-  "THIRD_PARTY_NOTICES.md",
-  "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
-  "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-  "THIRD_PARTY_LICENSES/ICU-LICENSE",
-]
-
-[features]
-extension-amcheck = []
-extension-auto-explain = []
-extension-bloom = []
-extension-btree-gin = []
-extension-btree-gist = []
-extension-citext = []
-extension-cube = []
-extension-dict-int = []
-extension-dict-xsyn = []
-extension-earthdistance = ["extension-cube"]
-extension-file-fdw = []
-extension-fuzzystrmatch = []
-extension-hstore = []
-extension-intarray = []
-extension-isn = []
-extension-lo = []
-extension-ltree = []
-extension-pageinspect = []
-extension-pg-buffercache = []
-extension-pg-freespacemap = []
-extension-pg-hashids = []
-extension-pg-ivm = []
-extension-pg-surgery = []
-extension-pg-textsearch = []
-extension-pg-trgm = []
-extension-pg-uuidv7 = []
-extension-pg-visibility = []
-extension-pg-walinspect = []
-extension-pgcrypto = []
-extension-pgtap = []
-extension-postgis = []
-extension-seg = []
-extension-tablefunc = []
-extension-tcn = []
-extension-tsm-system-rows = []
-extension-tsm-system-time = []
-extension-unaccent = []
-extension-uuid-ossp = []
-extension-vector = []
-
-[lib]
-path = "src/lib.rs"
-
-[dependencies]
-serde = { version = "1", features = ["derive"] }
-serde_json = "1"
-
-[build-dependencies]
-serde_json = "1"
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/assets/build.rs b/src/runtimes/liboliphaunt/wasix/crates/assets/build.rs
deleted file mode 100644
index 3953fc9b1..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/assets/build.rs
+++ /dev/null
@@ -1,1198 +0,0 @@
-use std::collections::BTreeSet;
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Component, Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";
-const ARTIFACT_KIND: &str = "wasix-runtime";
-const ARTIFACT_TARGET: &str = "portable";
-
-#[derive(Debug, Clone, Copy)]
-struct ExtensionPackage {
-    #[allow(dead_code)]
-    feature: &'static str,
-    env: &'static str,
-    product: &'static str,
-    sql_name: &'static str,
-    crate_ident: &'static str,
-}
-
-#[derive(Debug)]
-struct SelectedExtension {
-    package: ExtensionPackage,
-    archive: ExtensionArchiveSource,
-    aot_packages: Vec,
-}
-
-#[derive(Debug)]
-enum ExtensionArchiveSource {
-    Crate,
-    Local {
-        path: PathBuf,
-        sha256: String,
-        size: u64,
-    },
-    Missing,
-}
-
-#[derive(Debug, Clone, Copy)]
-struct ExtensionAotTarget {
-    id: &'static str,
-    target: &'static str,
-    cfg: &'static str,
-}
-
-#[derive(Debug)]
-struct SelectedExtensionAotPackage {
-    target: ExtensionAotTarget,
-    source: ExtensionAotSource,
-}
-
-#[derive(Debug)]
-enum ExtensionAotSource {
-    Crate {
-        crate_ident: String,
-    },
-    Local {
-        manifest: PathBuf,
-        artifacts: Vec,
-    },
-}
-
-#[derive(Debug)]
-struct LocalExtensionAotArtifact {
-    name: String,
-    path: PathBuf,
-}
-
-const EXTENSION_AOT_TARGETS: &[ExtensionAotTarget] = &[
-    ExtensionAotTarget {
-        id: "macos-arm64",
-        target: "aarch64-apple-darwin",
-        cfg: r#"all(target_os = "macos", target_arch = "aarch64")"#,
-    },
-    ExtensionAotTarget {
-        id: "linux-arm64-gnu",
-        target: "aarch64-unknown-linux-gnu",
-        cfg: r#"all(target_os = "linux", target_arch = "aarch64", target_env = "gnu")"#,
-    },
-    ExtensionAotTarget {
-        id: "linux-x64-gnu",
-        target: "x86_64-unknown-linux-gnu",
-        cfg: r#"all(target_os = "linux", target_arch = "x86_64", target_env = "gnu")"#,
-    },
-    ExtensionAotTarget {
-        id: "windows-x64-msvc",
-        target: "x86_64-pc-windows-msvc",
-        cfg: r#"all(target_os = "windows", target_arch = "x86_64", target_env = "msvc")"#,
-    },
-];
-
-const EXTENSION_PACKAGES: &[ExtensionPackage] = &[
-    ExtensionPackage {
-        feature: "extension-amcheck",
-        env: "CARGO_FEATURE_EXTENSION_AMCHECK",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "amcheck",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-auto-explain",
-        env: "CARGO_FEATURE_EXTENSION_AUTO_EXPLAIN",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "auto_explain",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-bloom",
-        env: "CARGO_FEATURE_EXTENSION_BLOOM",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "bloom",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-btree-gin",
-        env: "CARGO_FEATURE_EXTENSION_BTREE_GIN",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "btree_gin",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-btree-gist",
-        env: "CARGO_FEATURE_EXTENSION_BTREE_GIST",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "btree_gist",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-citext",
-        env: "CARGO_FEATURE_EXTENSION_CITEXT",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "citext",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-cube",
-        env: "CARGO_FEATURE_EXTENSION_CUBE",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "cube",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-dict-int",
-        env: "CARGO_FEATURE_EXTENSION_DICT_INT",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "dict_int",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-dict-xsyn",
-        env: "CARGO_FEATURE_EXTENSION_DICT_XSYN",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "dict_xsyn",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-earthdistance",
-        env: "CARGO_FEATURE_EXTENSION_EARTHDISTANCE",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "earthdistance",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-file-fdw",
-        env: "CARGO_FEATURE_EXTENSION_FILE_FDW",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "file_fdw",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-fuzzystrmatch",
-        env: "CARGO_FEATURE_EXTENSION_FUZZYSTRMATCH",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "fuzzystrmatch",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-hstore",
-        env: "CARGO_FEATURE_EXTENSION_HSTORE",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "hstore",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-intarray",
-        env: "CARGO_FEATURE_EXTENSION_INTARRAY",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "intarray",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-isn",
-        env: "CARGO_FEATURE_EXTENSION_ISN",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "isn",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-lo",
-        env: "CARGO_FEATURE_EXTENSION_LO",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "lo",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-ltree",
-        env: "CARGO_FEATURE_EXTENSION_LTREE",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "ltree",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-pageinspect",
-        env: "CARGO_FEATURE_EXTENSION_PAGEINSPECT",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "pageinspect",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-buffercache",
-        env: "CARGO_FEATURE_EXTENSION_PG_BUFFERCACHE",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "pg_buffercache",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-freespacemap",
-        env: "CARGO_FEATURE_EXTENSION_PG_FREESPACEMAP",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "pg_freespacemap",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-surgery",
-        env: "CARGO_FEATURE_EXTENSION_PG_SURGERY",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "pg_surgery",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-trgm",
-        env: "CARGO_FEATURE_EXTENSION_PG_TRGM",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "pg_trgm",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-visibility",
-        env: "CARGO_FEATURE_EXTENSION_PG_VISIBILITY",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "pg_visibility",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-walinspect",
-        env: "CARGO_FEATURE_EXTENSION_PG_WALINSPECT",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "pg_walinspect",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-pgcrypto",
-        env: "CARGO_FEATURE_EXTENSION_PGCRYPTO",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "pgcrypto",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-seg",
-        env: "CARGO_FEATURE_EXTENSION_SEG",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "seg",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-tablefunc",
-        env: "CARGO_FEATURE_EXTENSION_TABLEFUNC",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "tablefunc",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-tcn",
-        env: "CARGO_FEATURE_EXTENSION_TCN",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "tcn",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-tsm-system-rows",
-        env: "CARGO_FEATURE_EXTENSION_TSM_SYSTEM_ROWS",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "tsm_system_rows",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-tsm-system-time",
-        env: "CARGO_FEATURE_EXTENSION_TSM_SYSTEM_TIME",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "tsm_system_time",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-unaccent",
-        env: "CARGO_FEATURE_EXTENSION_UNACCENT",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "unaccent",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-uuid-ossp",
-        env: "CARGO_FEATURE_EXTENSION_UUID_OSSP",
-        product: "oliphaunt-extension-contrib-pg18",
-        sql_name: "uuid-ossp",
-        crate_ident: "oliphaunt_extension_contrib_pg18",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-hashids",
-        env: "CARGO_FEATURE_EXTENSION_PG_HASHIDS",
-        product: "oliphaunt-extension-pg-hashids",
-        sql_name: "pg_hashids",
-        crate_ident: "oliphaunt_extension_pg_hashids",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-ivm",
-        env: "CARGO_FEATURE_EXTENSION_PG_IVM",
-        product: "oliphaunt-extension-pg-ivm",
-        sql_name: "pg_ivm",
-        crate_ident: "oliphaunt_extension_pg_ivm",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-textsearch",
-        env: "CARGO_FEATURE_EXTENSION_PG_TEXTSEARCH",
-        product: "oliphaunt-extension-pg-textsearch",
-        sql_name: "pg_textsearch",
-        crate_ident: "oliphaunt_extension_pg_textsearch",
-    },
-    ExtensionPackage {
-        feature: "extension-pg-uuidv7",
-        env: "CARGO_FEATURE_EXTENSION_PG_UUIDV7",
-        product: "oliphaunt-extension-pg-uuidv7",
-        sql_name: "pg_uuidv7",
-        crate_ident: "oliphaunt_extension_pg_uuidv7",
-    },
-    ExtensionPackage {
-        feature: "extension-pgtap",
-        env: "CARGO_FEATURE_EXTENSION_PGTAP",
-        product: "oliphaunt-extension-pgtap",
-        sql_name: "pgtap",
-        crate_ident: "oliphaunt_extension_pgtap",
-    },
-    ExtensionPackage {
-        feature: "extension-postgis",
-        env: "CARGO_FEATURE_EXTENSION_POSTGIS",
-        product: "oliphaunt-extension-postgis",
-        sql_name: "postgis",
-        crate_ident: "oliphaunt_extension_postgis",
-    },
-    ExtensionPackage {
-        feature: "extension-vector",
-        env: "CARGO_FEATURE_EXTENSION_VECTOR",
-        product: "oliphaunt-extension-vector",
-        sql_name: "vector",
-        crate_ident: "oliphaunt_extension_vector",
-    },
-];
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR");
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT");
-    for package in EXTENSION_PACKAGES {
-        println!("cargo:rerun-if-env-changed={}", package.env);
-    }
-    emit_expected_asset_inputs();
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"));
-    let out = out_dir.join("generated_assets.rs");
-    let manifest_text =
-        fs::read_to_string(manifest_dir.join("Cargo.toml")).expect("read Cargo.toml");
-    let selected_extensions = selected_extensions(&manifest_dir, &manifest_text);
-
-    if let Some(asset_dir) = find_asset_dir() {
-        emit_rerun_directives(&asset_dir);
-        write_generated_assets(&out, &asset_dir, &selected_extensions);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX runtime payload");
-    } else {
-        write_source_only_assets(&out, &selected_extensions);
-    }
-}
-
-fn emit_expected_asset_inputs() {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR") {
-        emit_manifest_probe(&PathBuf::from(path));
-    }
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/assets"));
-    }
-    emit_manifest_probe(&manifest_dir.join("payload"));
-}
-
-fn emit_manifest_probe(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("manifest.json").display()
-    );
-}
-
-fn find_asset_dir() -> Option {
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let package_payload = manifest_dir.join("payload");
-    if package_payload.join("manifest.json").is_file() {
-        return Some(package_payload);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR") {
-        let path = PathBuf::from(path);
-        if path.join("manifest.json").is_file() {
-            return Some(path);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_assets = repo_root.join("target/oliphaunt-wasix/assets");
-        if target_assets.join("manifest.json").is_file() {
-            return Some(target_assets);
-        }
-    }
-
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
-    manifest_dir.ancestors().find(|candidate| {
-        candidate.join("Cargo.toml").is_file()
-            && candidate
-                .join("src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml")
-                .is_file()
-    })
-}
-
-fn emit_rerun_directives(asset_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", asset_dir.display());
-    visit_files(asset_dir, &mut |path| {
-        println!("cargo:rerun-if-changed={}", path.display());
-    });
-}
-
-fn visit_files(path: &Path, f: &mut impl FnMut(&Path)) {
-    let Ok(entries) = fs::read_dir(path) else {
-        return;
-    };
-    for entry in entries.flatten() {
-        let path = entry.path();
-        if path.is_dir() {
-            visit_files(&path, f);
-        } else if path.is_file() {
-            f(&path);
-        }
-    }
-}
-
-fn write_generated_assets(out: &Path, asset_dir: &Path, selected_extensions: &[SelectedExtension]) {
-    let manifest = asset_dir.join("manifest.json");
-    let generated_manifest = out
-        .parent()
-        .expect("generated asset output has parent")
-        .join("manifest.json");
-    write_core_manifest(&manifest, &generated_manifest, selected_extensions);
-    let runtime = asset_dir.join("oliphaunt.wasix.tar.zst");
-    let standard_seed_archive = asset_dir.join("cluster-seeds/standard.tar.zst");
-    let standard_seed_manifest = asset_dir.join("cluster-seeds/standard.json");
-    let icu_seed_archive = asset_dir.join("cluster-seeds/icu.tar.zst");
-    let icu_seed_manifest = asset_dir.join("cluster-seeds/icu.json");
-    let initdb = asset_dir.join("bin/initdb.wasix.wasm");
-
-    for required in [&manifest, &runtime, &initdb] {
-        assert!(
-            required.is_file(),
-            "generated asset directory {} is missing required file {}",
-            asset_dir.display(),
-            required.display()
-        );
-    }
-    for (profile, archive, seed_manifest) in [
-        ("standard", &standard_seed_archive, &standard_seed_manifest),
-        ("icu", &icu_seed_archive, &icu_seed_manifest),
-    ] {
-        assert!(
-            archive.is_file() && seed_manifest.is_file(),
-            "generated asset directory {} is missing the required {profile} cluster seed; expected both {} and {}",
-            asset_dir.display(),
-            archive.display(),
-            seed_manifest.display()
-        );
-    }
-
-    let standard_seed_archive_body = optional_include_bytes_body(&standard_seed_archive);
-    let standard_seed_manifest_body = optional_include_bytes_body(&standard_seed_manifest);
-    let icu_seed_archive_body = optional_include_bytes_body(&icu_seed_archive);
-    let icu_seed_manifest_body = optional_include_bytes_body(&icu_seed_manifest);
-    let extension_sql_names = selected_extension_sql_names_body(selected_extensions);
-    let extension_aot_sql_names = selected_extension_aot_sql_names_body(selected_extensions);
-    let extension_archive_body = extension_archive_body(selected_extensions);
-    let extension_sha256_body = expected_extension_archive_sha256_body(selected_extensions);
-    let extension_aot_manifest_body = extension_aot_manifest_json_body(selected_extensions);
-    let extension_aot_bytes_body = extension_aot_artifact_bytes_body(selected_extensions);
-
-    let text = format!(
-        "pub const HAS_EMBEDDED_ASSETS: bool = true;\n\
-         pub const SELECTED_EXTENSION_SQL_NAMES: &[&str] = {extension_sql_names};\n\
-         pub const SELECTED_EXTENSION_AOT_SQL_NAMES: &[&str] = {extension_aot_sql_names};\n\
-         pub const MANIFEST_JSON: &str = include_str!({manifest});\n\
-         pub fn runtime_archive() -> Option<&'static [u8]> {{ Some(include_bytes!({runtime})) }}\n\
-         pub fn standard_cluster_seed_archive() -> Option<&'static [u8]> {{ {standard_seed_archive_body} }}\n\
-         pub fn standard_cluster_seed_manifest() -> Option<&'static [u8]> {{ {standard_seed_manifest_body} }}\n\
-         pub fn icu_cluster_seed_archive() -> Option<&'static [u8]> {{ {icu_seed_archive_body} }}\n\
-         pub fn icu_cluster_seed_manifest() -> Option<&'static [u8]> {{ {icu_seed_manifest_body} }}\n\
-         pub fn initdb_wasm() -> Option<&'static [u8]> {{ Some(include_bytes!({initdb})) }}\n\
-         pub fn extension_archive(name: &str) -> Option<&'static [u8]> {{\n{extension_archive_body}         }}\n\
-         pub fn expected_extension_archive_sha256(name: &str) -> Option<&'static str> {{\n{extension_sha256_body}         }}\n\
-         #[allow(clippy::match_single_binding)] // Target cfgs can remove every generated match arm.\n\
-         pub fn extension_aot_manifest_json(target: &str, sql_name: &str) -> Option<&'static str> {{\n{extension_aot_manifest_body}         }}\n\
-         pub fn extension_aot_artifact_bytes(target: &str, name: &str) -> Option<&'static [u8]> {{\n{extension_aot_bytes_body}         }}\n",
-        manifest = rust_string_literal(&generated_manifest),
-        runtime = rust_string_literal(&runtime),
-        standard_seed_archive_body = standard_seed_archive_body,
-        standard_seed_manifest_body = standard_seed_manifest_body,
-        icu_seed_archive_body = icu_seed_archive_body,
-        icu_seed_manifest_body = icu_seed_manifest_body,
-        initdb = rust_string_literal(&initdb),
-        extension_sql_names = extension_sql_names,
-        extension_aot_sql_names = extension_aot_sql_names,
-        extension_archive_body = extension_archive_body,
-        extension_sha256_body = extension_sha256_body,
-        extension_aot_manifest_body = extension_aot_manifest_body,
-        extension_aot_bytes_body = extension_aot_bytes_body,
-    );
-    fs::write(out, text).expect("write generated asset include module");
-    emit_artifact_manifest(
-        out.parent().expect("generated asset output has parent"),
-        asset_dir,
-        &[
-            &generated_manifest,
-            &runtime,
-            &standard_seed_archive,
-            &standard_seed_manifest,
-            &icu_seed_archive,
-            &icu_seed_manifest,
-            &initdb,
-        ],
-    );
-}
-
-fn write_source_only_assets(out: &Path, selected_extensions: &[SelectedExtension]) {
-    let extension_sql_names = selected_extension_sql_names_body(selected_extensions);
-    let extension_aot_sql_names = selected_extension_aot_sql_names_body(selected_extensions);
-    let extension_archive_body = extension_archive_body(selected_extensions);
-    let extension_sha256_body = expected_extension_archive_sha256_body(selected_extensions);
-    let extension_aot_manifest_body = extension_aot_manifest_json_body(selected_extensions);
-    let extension_aot_bytes_body = extension_aot_artifact_bytes_body(selected_extensions);
-    let mut text = format!(
-        "pub const HAS_EMBEDDED_ASSETS: bool = false;\n\
-         pub const SELECTED_EXTENSION_SQL_NAMES: &[&str] = {extension_sql_names};\n\
-         pub const SELECTED_EXTENSION_AOT_SQL_NAMES: &[&str] = {extension_aot_sql_names};\n"
-    );
-    text.push_str(
-        r##"pub const MANIFEST_JSON: &str = r#"{"format-version":2,"runtime":{"archive":"","sha256":"","module-sha256":"","postgres-version":"","runtime-kind":"source-only-template"},"runtime-support":[],"cluster-seeds":{},"extensions":[],"sources":[]}"#;
-pub fn runtime_archive() -> Option<&'static [u8]> { None }
-pub fn standard_cluster_seed_archive() -> Option<&'static [u8]> { None }
-pub fn standard_cluster_seed_manifest() -> Option<&'static [u8]> { None }
-pub fn icu_cluster_seed_archive() -> Option<&'static [u8]> { None }
-pub fn icu_cluster_seed_manifest() -> Option<&'static [u8]> { None }
-pub fn initdb_wasm() -> Option<&'static [u8]> { None }
-"##,
-    );
-    text.push_str(&format!(
-        "pub fn extension_archive(name: &str) -> Option<&'static [u8]> {{\n\
-{extension_archive_body}}}\n\
-         pub fn expected_extension_archive_sha256(name: &str) -> Option<&'static str> {{\n\
-{extension_sha256_body}}}\n\
-         #[allow(clippy::match_single_binding)] // Target cfgs can remove every generated match arm.\n\
-         pub fn extension_aot_manifest_json(target: &str, sql_name: &str) -> Option<&'static str> {{\n\
-{extension_aot_manifest_body}}}\n\
-         pub fn extension_aot_artifact_bytes(target: &str, name: &str) -> Option<&'static [u8]> {{\n\
-{extension_aot_bytes_body}}}\n"
-    ));
-    fs::write(out, text).expect("write source-only asset include module");
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn optional_include_bytes_body(path: &Path) -> String {
-    if path.is_file() {
-        format!("Some(include_bytes!({}))", rust_string_literal(path))
-    } else {
-        "None".to_owned()
-    }
-}
-
-fn write_core_manifest(
-    source: &Path,
-    destination: &Path,
-    selected_extensions: &[SelectedExtension],
-) {
-    let text = fs::read_to_string(source).expect("read generated WASIX asset manifest");
-    let mut manifest: serde_json::Value =
-        serde_json::from_str(&text).expect("parse generated WASIX asset manifest");
-    manifest["extensions"] = serde_json::Value::Array(
-        selected_extensions
-            .iter()
-            .filter_map(extension_manifest_entry)
-            .collect(),
-    );
-    let object = manifest
-        .as_object_mut()
-        .expect("generated WASIX asset manifest is an object");
-    object.remove("pg-dump");
-    object.remove("psql");
-    let rendered =
-        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX asset manifest");
-    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX asset manifest");
-}
-
-fn selected_extensions(manifest_dir: &Path, manifest_text: &str) -> Vec {
-    let repo_root = repo_root_from_manifest_dir(manifest_dir).map(Path::to_path_buf);
-    EXTENSION_PACKAGES
-        .iter()
-        .copied()
-        .filter_map(|package| {
-            env::var_os(package.env)?;
-            let archive_package = extension_wasix_package_name(package);
-            let archive = if manifest_declares_dependency(manifest_text, &archive_package) {
-                ExtensionArchiveSource::Crate
-            } else if let Some(path) =
-                find_local_extension_archive(manifest_dir, repo_root.as_deref(), package)
-            {
-                println!("cargo:rerun-if-changed={}", path.display());
-                let sha256 =
-                    sha256_file(&path).expect("hash selected local WASIX extension archive");
-                let size = path
-                    .metadata()
-                    .expect("stat selected local WASIX extension archive")
-                    .len();
-                ExtensionArchiveSource::Local { path, sha256, size }
-            } else {
-                if let Some(root) = env::var_os("OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT") {
-                    panic!(
-                        "explicit local extension artifact root {} is missing the canonical WASIX archive for selected extension {}",
-                        Path::new(&root).display(),
-                        package.sql_name,
-                    );
-                }
-                ExtensionArchiveSource::Missing
-            };
-            let aot_packages = selected_extension_aot_packages(manifest_text, package);
-            Some(SelectedExtension {
-                package,
-                archive,
-                aot_packages,
-            })
-        })
-        .collect()
-}
-
-fn selected_extension_aot_packages(
-    manifest_text: &str,
-    package: ExtensionPackage,
-) -> Vec {
-    let dependencies = EXTENSION_AOT_TARGETS
-        .iter()
-        .copied()
-        .filter_map(|target| {
-            let package_name = extension_aot_package_name(package, target);
-            manifest_declares_dependency(manifest_text, &package_name).then(|| {
-                SelectedExtensionAotPackage {
-                    target,
-                    source: ExtensionAotSource::Crate {
-                        crate_ident: crate_ident(&package_name),
-                    },
-                }
-            })
-        })
-        .collect::>();
-    if !dependencies.is_empty() {
-        return dependencies;
-    }
-    local_extension_aot_package(package).into_iter().collect()
-}
-
-fn local_extension_product_roots(root: &Path, product: &str) -> [PathBuf; 4] {
-    let packaged = root.join("oliphaunt-extension-package-artifacts");
-    [
-        root.join(ARTIFACT_PRODUCT).join(product),
-        root.join(product),
-        packaged.join(ARTIFACT_PRODUCT).join(product),
-        packaged.join(product),
-    ]
-}
-
-fn find_local_extension_product_root(root: &Path, package: ExtensionPackage) -> Option {
-    local_extension_product_roots(root, package.product)
-        .into_iter()
-        .find(|candidate| candidate.join("extension-artifacts.json").is_file())
-}
-
-fn local_extension_aot_package(package: ExtensionPackage) -> Option {
-    let root = PathBuf::from(env::var_os("OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT")?);
-    let product_root = find_local_extension_product_root(&root, package).unwrap_or_else(|| {
-        panic!(
-            "local extension artifact root {} has no manifest for {}",
-            root.display(),
-            package.product,
-        )
-    });
-    let product_manifest = product_root.join("extension-artifacts.json");
-    let product_value: serde_json::Value = serde_json::from_str(
-        &fs::read_to_string(&product_manifest).unwrap_or_else(|error| {
-            panic!(
-                "read local extension artifact manifest {}: {error}",
-                product_manifest.display()
-            )
-        }),
-    )
-    .unwrap_or_else(|error| {
-        panic!(
-            "parse local extension artifact manifest {}: {error}",
-            product_manifest.display()
-        )
-    });
-    assert_eq!(
-        product_value
-            .get("product")
-            .and_then(serde_json::Value::as_str),
-        Some(package.product),
-        "local extension artifact manifest {} has the wrong product",
-        product_manifest.display(),
-    );
-    let schema = product_value
-        .get("schema")
-        .and_then(serde_json::Value::as_str)
-        .unwrap_or_else(|| {
-            panic!(
-                "local extension artifact manifest {} has no schema",
-                product_manifest.display()
-            )
-        });
-    let member = match schema {
-        "oliphaunt-extension-ci-artifacts-v1" => {
-            assert_eq!(
-                product_value
-                    .get("sqlName")
-                    .and_then(serde_json::Value::as_str),
-                Some(package.sql_name),
-                "local extension artifact manifest {} has the wrong SQL name",
-                product_manifest.display(),
-            );
-            &product_value
-        }
-        "oliphaunt-extension-ci-artifacts-v2" => product_value
-            .get("extensions")
-            .and_then(serde_json::Value::as_array)
-            .and_then(|rows| {
-                rows.iter().find(|row| {
-                    row.get("sqlName").and_then(serde_json::Value::as_str) == Some(package.sql_name)
-                })
-            })
-            .unwrap_or_else(|| {
-                panic!(
-                    "local extension artifact manifest {} lacks bundle member {}",
-                    product_manifest.display(),
-                    package.sql_name
-                )
-            }),
-        other => panic!(
-            "local extension artifact manifest {} has unsupported schema {other}",
-            product_manifest.display()
-        ),
-    };
-    let requires_aot = match member.get("nativeModuleStem") {
-        Some(serde_json::Value::String(value)) if !value.is_empty() => true,
-        Some(serde_json::Value::Null) => false,
-        other => panic!(
-            "local extension artifact manifest {} has invalid nativeModuleStem {other:?}",
-            product_manifest.display(),
-        ),
-    };
-    if !requires_aot {
-        return None;
-    }
-
-    let build_target = env::var("TARGET").expect("Cargo sets TARGET for build scripts");
-    let target = EXTENSION_AOT_TARGETS
-        .iter()
-        .copied()
-        .find(|target| target.target == build_target)
-        .unwrap_or_else(|| panic!("unsupported local extension AOT build target {build_target}"));
-    let target_root = product_root.join("wasix-aot").join(target.id);
-    let aot_dir = if schema == "oliphaunt-extension-ci-artifacts-v2" {
-        target_root.join(package.sql_name)
-    } else {
-        target_root
-    };
-    let manifest = aot_dir.join("manifest.json");
-    let manifest_value: serde_json::Value =
-        serde_json::from_str(&fs::read_to_string(&manifest).unwrap_or_else(|error| {
-            panic!(
-                "read local extension AOT manifest {}: {error}",
-                manifest.display()
-            )
-        }))
-        .unwrap_or_else(|error| {
-            panic!(
-                "parse local extension AOT manifest {}: {error}",
-                manifest.display()
-            )
-        });
-    assert_eq!(
-        manifest_value
-            .get("format-version")
-            .and_then(serde_json::Value::as_u64),
-        Some(1),
-        "local extension AOT manifest {} has an unsupported format",
-        manifest.display(),
-    );
-    assert_eq!(
-        manifest_value
-            .get("target-triple")
-            .and_then(serde_json::Value::as_str),
-        Some(target.target),
-        "local extension AOT manifest {} targets the wrong platform",
-        manifest.display(),
-    );
-    let rows = manifest_value
-        .get("artifacts")
-        .and_then(serde_json::Value::as_array)
-        .filter(|rows| !rows.is_empty())
-        .unwrap_or_else(|| {
-            panic!(
-                "local extension AOT manifest {} has no artifacts",
-                manifest.display()
-            )
-        });
-    let mut names = BTreeSet::new();
-    let mut artifacts = Vec::new();
-    for row in rows {
-        let name = row
-            .get("name")
-            .and_then(serde_json::Value::as_str)
-            .unwrap_or_else(|| {
-                panic!(
-                    "local extension AOT manifest {} has an artifact without a name",
-                    manifest.display()
-                )
-            });
-        let expected_prefix = format!("extension:{}", package.sql_name);
-        assert!(
-            name == expected_prefix || name.starts_with(&format!("{expected_prefix}:")),
-            "local extension AOT manifest {} contains foreign artifact {name}",
-            manifest.display(),
-        );
-        assert!(
-            names.insert(name.to_owned()),
-            "local extension AOT manifest {} repeats artifact {name}",
-            manifest.display()
-        );
-        let relative = row
-            .get("path")
-            .and_then(serde_json::Value::as_str)
-            .map(Path::new)
-            .unwrap_or_else(|| {
-                panic!(
-                    "local extension AOT manifest {} has an artifact without a path",
-                    manifest.display()
-                )
-            });
-        assert!(
-            !relative.is_absolute()
-                && relative
-                    .components()
-                    .all(|component| matches!(component, Component::Normal(_))),
-            "local extension AOT manifest {} contains unsafe path {}",
-            manifest.display(),
-            relative.display(),
-        );
-        let artifact = aot_dir.join(relative);
-        assert!(
-            artifact.is_file(),
-            "local extension AOT manifest {} references missing {}",
-            manifest.display(),
-            artifact.display()
-        );
-        let expected_sha256 = row
-            .get("sha256")
-            .and_then(serde_json::Value::as_str)
-            .filter(|value| value.len() == 64 && value.bytes().all(|byte| byte.is_ascii_hexdigit()))
-            .unwrap_or_else(|| {
-                panic!(
-                    "local extension AOT manifest {} has an invalid artifact sha256",
-                    manifest.display()
-                )
-            });
-        let actual_sha256 = sha256_file(&artifact).unwrap_or_else(|error| {
-            panic!(
-                "hash local extension AOT artifact {}: {error}",
-                artifact.display()
-            )
-        });
-        assert_eq!(
-            actual_sha256,
-            expected_sha256,
-            "local extension AOT artifact {} does not match its manifest",
-            artifact.display()
-        );
-        println!("cargo:rerun-if-changed={}", artifact.display());
-        artifacts.push(LocalExtensionAotArtifact {
-            name: name.to_owned(),
-            path: artifact,
-        });
-    }
-    println!("cargo:rerun-if-changed={}", product_manifest.display());
-    println!("cargo:rerun-if-changed={}", manifest.display());
-    Some(SelectedExtensionAotPackage {
-        target,
-        source: ExtensionAotSource::Local {
-            manifest,
-            artifacts,
-        },
-    })
-}
-
-fn extension_aot_package_name(package: ExtensionPackage, target: ExtensionAotTarget) -> String {
-    let suffix = match target.id {
-        "macos-arm64" => "macos-arm64",
-        "linux-arm64-gnu" => "linux-arm64",
-        "linux-x64-gnu" => "linux-x64",
-        "windows-x64-msvc" => "windows-x64",
-        other => panic!("unsupported extension AOT target id {other}"),
-    };
-    format!("{}-aot-{suffix}", package.product)
-}
-
-fn extension_wasix_package_name(package: ExtensionPackage) -> String {
-    format!("{}-wasix", package.product)
-}
-
-fn crate_ident(package_name: &str) -> String {
-    package_name.replace('-', "_")
-}
-
-fn manifest_declares_dependency(manifest_text: &str, package_name: &str) -> bool {
-    manifest_text
-        .lines()
-        .any(|line| line.trim_start().starts_with(&format!("{package_name} =")))
-}
-
-fn find_local_extension_archive(
-    manifest_dir: &Path,
-    repo_root: Option<&Path>,
-    package: ExtensionPackage,
-) -> Option {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let archive_name = format!("{}-{version}-wasix-portable.tar.zst", package.product);
-    let roots = if let Some(path) = env::var_os("OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT") {
-        // An explicit root takes precedence over workspace and package assets.
-        vec![PathBuf::from(path)]
-    } else {
-        let mut roots = Vec::new();
-        if let Some(repo_root) = repo_root {
-            roots.push(repo_root.join("target/extension-artifacts"));
-        }
-        roots.push(manifest_dir.join("extension-artifacts"));
-        roots
-    };
-
-    for root in roots {
-        for product_root in local_extension_product_roots(&root, package.product) {
-            for candidate in [
-                product_root
-                    .join("member-assets")
-                    .join(package.sql_name)
-                    .join(&archive_name),
-                product_root.join("release-assets").join(&archive_name),
-            ] {
-                if candidate.is_file() {
-                    return Some(candidate);
-                }
-            }
-        }
-    }
-    None
-}
-
-fn selected_extension_sql_names_body(selected_extensions: &[SelectedExtension]) -> String {
-    let sql_names = selected_extensions
-        .iter()
-        .map(|extension| format!("{:?}", extension.package.sql_name))
-        .collect::>()
-        .join(", ");
-    format!("&[{sql_names}]")
-}
-
-fn selected_extension_aot_sql_names_body(selected_extensions: &[SelectedExtension]) -> String {
-    let sql_names = selected_extensions
-        .iter()
-        .filter(|extension| !extension.aot_packages.is_empty())
-        .map(|extension| format!("{:?}", extension.package.sql_name))
-        .collect::>()
-        .join(", ");
-    format!("&[{sql_names}]")
-}
-
-fn extension_archive_body(selected_extensions: &[SelectedExtension]) -> String {
-    if selected_extensions.is_empty() {
-        return "            let _ = name;\n            None\n".to_owned();
-    }
-    let mut body = String::from("            match name {\n");
-    for extension in selected_extensions {
-        let sql_name = extension.package.sql_name;
-        let expression = match &extension.archive {
-            ExtensionArchiveSource::Crate => {
-                format!(
-                    "{}::archive({sql_name:?})",
-                    extension_wasix_crate_ident(extension.package),
-                )
-            }
-            ExtensionArchiveSource::Local { path, .. } => {
-                format!("Some(include_bytes!({}))", rust_string_literal(path))
-            }
-            ExtensionArchiveSource::Missing => "None".to_owned(),
-        };
-        body.push_str(&format!("                {sql_name:?} => {expression},\n"));
-    }
-    body.push_str("                _ => None,\n            }\n");
-    body
-}
-
-fn expected_extension_archive_sha256_body(selected_extensions: &[SelectedExtension]) -> String {
-    if selected_extensions.is_empty() {
-        return "            let _ = name;\n            None\n".to_owned();
-    }
-    let mut body = String::from("            match name {\n");
-    for extension in selected_extensions {
-        let sql_name = extension.package.sql_name;
-        let expression = match &extension.archive {
-            ExtensionArchiveSource::Crate => {
-                format!(
-                    "{}::archive_sha256({sql_name:?})",
-                    extension_wasix_crate_ident(extension.package),
-                )
-            }
-            ExtensionArchiveSource::Local { sha256, .. } => {
-                format!("Some({sha256:?})")
-            }
-            ExtensionArchiveSource::Missing => "None".to_owned(),
-        };
-        body.push_str(&format!("                {sql_name:?} => {expression},\n"));
-    }
-    body.push_str("                _ => None,\n            }\n");
-    body
-}
-
-fn extension_aot_manifest_json_body(selected_extensions: &[SelectedExtension]) -> String {
-    let mut body = String::from("            match (target, sql_name) {\n");
-    for extension in selected_extensions {
-        let sql_name = extension.package.sql_name;
-        for aot in &extension.aot_packages {
-            let expression = match &aot.source {
-                ExtensionAotSource::Crate { crate_ident } => {
-                    format!("{crate_ident}::aot_manifest_json({sql_name:?})")
-                }
-                ExtensionAotSource::Local { manifest, .. } => {
-                    format!("Some(include_str!({}))", rust_string_literal(manifest))
-                }
-            };
-            body.push_str(&format!(
-                "                #[cfg({})]\n                ({:?}, {:?}) => {expression},\n",
-                aot.target.cfg, aot.target.target, sql_name,
-            ));
-        }
-    }
-    body.push_str("                _ => None,\n            }\n");
-    body
-}
-
-fn extension_aot_artifact_bytes_body(selected_extensions: &[SelectedExtension]) -> String {
-    let mut body = String::from("            let _ = (target, name);\n");
-    let mut emitted_crates = BTreeSet::new();
-    for extension in selected_extensions {
-        for aot in &extension.aot_packages {
-            match &aot.source {
-                ExtensionAotSource::Crate { crate_ident } => {
-                    if !emitted_crates.insert((aot.target.target, crate_ident.as_str())) {
-                        continue;
-                    }
-                    body.push_str(&format!(
-                        "            #[cfg({})]\n            if target == {:?} {{\n                if let Some(bytes) = {}::aot_artifact_bytes(name) {{\n                    return Some(bytes);\n                }}\n            }}\n",
-                        aot.target.cfg,
-                        aot.target.target,
-                        crate_ident,
-                    ));
-                }
-                ExtensionAotSource::Local { artifacts, .. } => {
-                    body.push_str(&format!(
-                        "            #[cfg({})]\n            if target == {:?} {{\n                match name {{\n",
-                        aot.target.cfg,
-                        aot.target.target,
-                    ));
-                    for artifact in artifacts {
-                        body.push_str(&format!(
-                            "                    {:?} => return Some(include_bytes!({})),\n",
-                            artifact.name,
-                            rust_string_literal(&artifact.path),
-                        ));
-                    }
-                    body.push_str(
-                        "                    _ => {}\n                }\n            }\n",
-                    );
-                }
-            }
-        }
-    }
-    body.push_str("            None\n");
-    body
-}
-
-fn extension_manifest_entry(extension: &SelectedExtension) -> Option {
-    match &extension.archive {
-        ExtensionArchiveSource::Local { sha256, size, .. } => Some(serde_json::json!({
-            "name": extension.package.sql_name,
-            "sql-name": extension.package.sql_name,
-            "archive": format!("extensions/{}.tar.zst", extension.package.sql_name),
-            "sha256": sha256,
-            "size": size,
-        })),
-        ExtensionArchiveSource::Crate | ExtensionArchiveSource::Missing => None,
-    }
-}
-
-fn extension_wasix_crate_ident(package: ExtensionPackage) -> String {
-    format!("{}_wasix", package.crate_ident)
-}
-
-fn emit_artifact_manifest(out_dir: &Path, asset_dir: &Path, files: &[&Path]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {ARTIFACT_TARGET:?}\n"
-    );
-    for file in files {
-        if !file.is_file() {
-            continue;
-        }
-        let relative = file
-            .strip_prefix(asset_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| "manifest.json".to_owned());
-        let sha256 = sha256_file(file).expect("hash WASIX runtime artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX runtime Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/assets/src/lib.rs b/src/runtimes/liboliphaunt/wasix/crates/assets/src/lib.rs
deleted file mode 100644
index f57d08c53..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/assets/src/lib.rs
+++ /dev/null
@@ -1,300 +0,0 @@
-#![deny(unsafe_code)]
-
-use serde::{Deserialize, Serialize};
-
-include!(concat!(env!("OUT_DIR"), "/generated_assets.rs"));
-
-/// PostgreSQL major whose on-disk layout is carried by this runtime family.
-pub const POSTGRES_MAJOR: u32 = 18;
-/// Version of the runtime payload selected by Cargo.
-#[doc(hidden)]
-pub const PACKAGE_VERSION: &str = env!("CARGO_PKG_VERSION");
-/// Stable WASIX physical-storage compatibility identity.
-pub const PHYSICAL_FORMAT: &str = "wasix-pg18-v1";
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct AssetManifest {
-    pub format_version: u32,
-    #[serde(default)]
-    pub source_lane: Option,
-    #[serde(default)]
-    pub source_fingerprint: Option,
-    pub runtime: RuntimeAsset,
-    #[serde(default)]
-    pub runtime_support: Vec,
-    #[serde(default)]
-    pub initdb: Option,
-    #[serde(default)]
-    pub cluster_seeds: std::collections::BTreeMap,
-    #[serde(default)]
-    pub extensions: Vec,
-    #[serde(default)]
-    pub sources: Vec,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct RuntimeAsset {
-    pub archive: String,
-    pub sha256: String,
-    #[serde(default)]
-    pub module_sha256: String,
-    pub postgres_version: String,
-    pub runtime_kind: String,
-    #[serde(default)]
-    pub link: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct BinaryAsset {
-    pub name: String,
-    pub path: String,
-    pub sha256: String,
-    #[serde(default)]
-    pub module_sha256: String,
-    #[serde(default)]
-    pub native_module: Option,
-    pub size: u64,
-    #[serde(default)]
-    pub link: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct ClusterSeedAsset {
-    pub artifact_role: String,
-    pub catalog_profile: String,
-    pub archive: String,
-    pub manifest: String,
-    pub sha256: String,
-    pub size: u64,
-    pub runtime_module_sha256: String,
-    pub initdb_module_sha256: String,
-    pub source_pins_sha256: String,
-    #[serde(default)]
-    pub source_lane: Option,
-    #[serde(default)]
-    pub source_fingerprint: Option,
-    pub postgres_version: String,
-    pub catalog_version: String,
-    pub init_profile: String,
-    pub wasmer_version: String,
-    pub physical_format: String,
-    pub compatibility_key: String,
-    #[serde(default)]
-    pub icu_data_tree_sha256: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct ExtensionAsset {
-    pub name: String,
-    pub sql_name: String,
-    #[serde(default)]
-    pub source_kind: String,
-    pub archive: String,
-    pub sha256: String,
-    #[serde(default)]
-    pub module_sha256: String,
-    #[serde(default)]
-    pub native_modules: Vec,
-    pub size: u64,
-    #[serde(default)]
-    pub control_files: Vec,
-    #[serde(default)]
-    pub dependencies: Vec,
-    #[serde(default)]
-    pub load_order: Vec,
-    #[serde(default)]
-    pub lifecycle: Option,
-    #[serde(default)]
-    pub extension_imports: Vec,
-    #[serde(default)]
-    pub core_exports_required: Vec,
-    #[serde(default)]
-    pub unresolved_imports: Vec,
-    #[serde(default)]
-    pub installed_files: Vec,
-    #[serde(default)]
-    pub link: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct ExtensionLifecycle {
-    pub create_extension: bool,
-    #[serde(default)]
-    pub create_schema: Option,
-    #[serde(default)]
-    pub load_sql: Vec,
-    #[serde(default)]
-    pub post_create_sql: Vec,
-    #[serde(default)]
-    pub startup_config: Vec,
-    #[serde(default)]
-    pub preload_required: bool,
-    #[serde(default)]
-    pub restart_required: bool,
-    #[serde(default)]
-    pub shared_memory_required: bool,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct WasmLinkMetadata {
-    pub has_dylink0: bool,
-    #[serde(default)]
-    pub dylink_needed: Vec,
-    #[serde(default)]
-    pub dylink_runtime_paths: Vec,
-    #[serde(default)]
-    pub dylink_memory: Option,
-    #[serde(default)]
-    pub dylink_imports: Vec,
-    #[serde(default)]
-    pub dylink_exports: Vec,
-    #[serde(default)]
-    pub imports: Vec,
-    #[serde(default)]
-    pub exports: Vec,
-    #[serde(default)]
-    pub memories: Vec,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct WasmDylinkMemory {
-    pub memory_size: u32,
-    pub memory_alignment: u32,
-    pub table_size: u32,
-    pub table_alignment: u32,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct WasmDylinkSymbol {
-    pub module: Option,
-    pub name: String,
-    pub flags: u32,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct WasmImport {
-    pub module: String,
-    pub name: String,
-    pub kind: String,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct WasmExport {
-    pub name: String,
-    pub kind: String,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct WasmMemory {
-    pub initial_pages: u64,
-    pub maximum_pages: Option,
-    pub memory64: bool,
-    pub shared: bool,
-    pub page_size_log2: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(rename_all = "kebab-case")]
-pub struct SourcePin {
-    pub name: String,
-    pub url: String,
-    pub branch: String,
-    pub commit: String,
-}
-
-pub fn manifest() -> Result {
-    serde_json::from_str(MANIFEST_JSON)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn manifest_parses_and_keeps_core_payload_extension_free() {
-        let manifest = manifest().expect("asset manifest should parse");
-        if !HAS_EMBEDDED_ASSETS {
-            assert_eq!(manifest.runtime.runtime_kind, "source-only-template");
-            if SELECTED_EXTENSION_SQL_NAMES.is_empty() {
-                assert!(manifest.extensions.is_empty());
-            }
-            return;
-        }
-        assert_eq!(manifest.runtime.postgres_version, "18.4");
-        assert_eq!(manifest.runtime.runtime_kind, "wasix-dynamic-main");
-        if SELECTED_EXTENSION_SQL_NAMES.is_empty() {
-            assert!(manifest.extensions.is_empty());
-        }
-    }
-
-    #[test]
-    fn pg18_manifest_metadata_round_trips() {
-        let manifest: AssetManifest = serde_json::from_str(
-            r#"{
-              "format-version": 2,
-              "source-lane": "stable",
-              "source-fingerprint": "postgresql-18.4:patch-stack",
-              "runtime": {
-                "archive": "oliphaunt.wasix.tar.zst",
-                "sha256": "runtime-archive",
-                "module-sha256": "runtime-module",
-                "postgres-version": "18.4",
-                "runtime-kind": "wasix-dynamic-main"
-              },
-              "runtime-support": [],
-              "cluster-seeds": {
-                "standard": {
-                  "artifact-role": "cluster-seed-standard",
-                  "catalog-profile": "standard",
-                  "archive": "cluster-seeds/standard.tar.zst",
-                  "manifest": "cluster-seeds/standard.json",
-                  "sha256": "seed-archive",
-                  "size": 1,
-                  "runtime-module-sha256": "runtime-module",
-                  "initdb-module-sha256": "initdb-module",
-                  "source-pins-sha256": "source-pins",
-                  "source-lane": "stable",
-                  "source-fingerprint": "postgresql-18.4:patch-stack",
-                  "postgres-version": "18",
-                  "catalog-version": "202505281",
-                  "init-profile": "default",
-                  "wasmer-version": "6.0.0",
-                  "physical-format": "wasix-pg18-v1",
-                  "compatibility-key": "wasix-pg18-datum32-v1"
-                }
-              },
-              "extensions": [],
-              "sources": []
-            }"#,
-        )
-        .expect("PG18 asset manifest metadata should parse");
-
-        assert_eq!(manifest.source_lane.as_deref(), Some("stable"));
-        assert_eq!(
-            manifest.source_fingerprint.as_deref(),
-            Some("postgresql-18.4:patch-stack")
-        );
-        let seed = manifest
-            .cluster_seeds
-            .get("standard")
-            .expect("standard cluster seed asset");
-        assert_eq!(seed.catalog_profile, "standard");
-        assert_eq!(seed.source_lane.as_deref(), Some("stable"));
-        assert_eq!(
-            seed.source_fingerprint.as_deref(),
-            Some("postgresql-18.4:patch-stack")
-        );
-    }
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/Cargo.toml
deleted file mode 100644
index 2db4c4cbc..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "oliphaunt-wasix-tools-aot-aarch64-apple-darwin"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Wasmer AOT pg_dump and psql artifacts for oliphaunt-wasix on aarch64-apple-darwin"
-repository = "https://github.com/f0rr0/oliphaunt"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_oliphaunt_wasix_tools_aot_macos_arm64"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-serde_json = "1"
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/build.rs b/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/build.rs
deleted file mode 100644
index 127906ae8..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-apple-darwin/build.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
-const ARTIFACT_KIND: &str = "wasix-tools-aot";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
-
-    let target = env::var("CARGO_PKG_NAME")
-        .expect("CARGO_PKG_NAME is set by Cargo")
-        .strip_prefix("oliphaunt-wasix-tools-aot-")
-        .expect("AOT crate name starts with oliphaunt-wasix-tools-aot-")
-        .to_owned();
-    emit_expected_artifact_inputs(&target);
-
-    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
-        .join("generated_aot.rs");
-    if let Some(artifact_dir) = find_artifact_dir(&target) {
-        emit_rerun_directives(&artifact_dir);
-        write_generated_aot(&out, &target, &artifact_dir);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX tools AOT artifacts for {target}");
-    } else {
-        write_source_only_aot(&out, &target);
-    }
-}
-
-fn emit_expected_artifact_inputs(target: &str) {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        emit_manifest_probe(&candidate);
-    }
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
-    }
-    emit_manifest_probe(&manifest_dir.join("artifacts"));
-}
-
-fn emit_manifest_probe(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("manifest.json").display()
-    );
-}
-
-fn find_artifact_dir(target: &str) -> Option {
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let package_artifacts = manifest_dir.join("artifacts");
-    if package_artifacts.join("manifest.json").is_file() {
-        return Some(package_artifacts);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        if candidate.join("manifest.json").is_file() {
-            return Some(candidate);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
-        if target_artifacts.join("manifest.json").is_file() {
-            return Some(target_artifacts);
-        }
-    }
-
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
-    manifest_dir.ancestors().find(|candidate| {
-        candidate.join("Cargo.toml").is_file()
-            && candidate
-                .join("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml")
-                .is_file()
-    })
-}
-
-fn emit_rerun_directives(artifact_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", artifact_dir.display());
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.is_file() {
-                println!("cargo:rerun-if-changed={}", path.display());
-            }
-        }
-    }
-}
-
-fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
-    let manifest = artifact_dir.join("manifest.json");
-    let generated_manifest = out
-        .parent()
-        .expect("generated AOT output has parent")
-        .join("manifest.json");
-    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
-    let mut cases = String::new();
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        let mut files = entries
-            .flatten()
-            .map(|entry| entry.path())
-            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
-            .collect::>();
-        files.sort();
-        for file in files {
-            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
-                continue;
-            };
-            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
-                continue;
-            };
-            let artifact_name = artifact_name_from_file_stem(stem);
-            if !artifact_belongs_to_crate(&artifact_name) {
-                continue;
-            }
-            cases.push_str(&format!(
-                "        {:?} => Some(include_bytes!({})),\n",
-                artifact_name,
-                rust_string_literal(&file)
-            ));
-        }
-    }
-    cases.push_str("        _ => None,\n");
-
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = true;\n\
-         pub const MANIFEST_JSON: &str = include_str!({});\n\
-         #[rustfmt::skip]\n\
-         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
-             match name {{\n\
-         {cases}    }}\n\
-         }}\n",
-        target,
-        rust_string_literal(&generated_manifest)
-    );
-    fs::write(out, text).expect("write generated AOT include module");
-    let mut manifest_files = vec![generated_manifest];
-    for relative in retained_paths {
-        manifest_files.push(artifact_dir.join(relative));
-    }
-    emit_artifact_manifest(
-        out.parent().expect("generated AOT output has parent"),
-        target,
-        artifact_dir,
-        &manifest_files,
-    );
-}
-
-fn write_source_only_aot(out: &Path, target: &str) {
-    let manifest = format!(
-        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
-    );
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {target:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = false;\n\
-         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
-         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
-    );
-    fs::write(out, text).expect("write source-only AOT include module");
-}
-
-fn artifact_name_from_file_stem(stem: &str) -> String {
-    match stem {
-        "oliphaunt" => "runtime:oliphaunt".to_owned(),
-        "pg_dump" => "tool:pg_dump".to_owned(),
-        "psql" => "tool:psql".to_owned(),
-        "initdb" => "tool:initdb".to_owned(),
-        "plpgsql" => "runtime-support:plpgsql".to_owned(),
-        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
-        extension_support if extension_support.ends_with("_deps") => {
-            let sql_name = extension_support.trim_end_matches("_deps");
-            format!("extension:{sql_name}:{extension_support}")
-        }
-        extension => format!("extension:{extension}"),
-    }
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn artifact_belongs_to_crate(name: &str) -> bool {
-    match ARTIFACT_KIND {
-        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
-        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
-    }
-}
-
-fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
-    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
-    let mut manifest: serde_json::Value =
-        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
-    let artifacts = manifest
-        .get_mut("artifacts")
-        .and_then(|value| value.as_array_mut())
-        .expect("generated WASIX AOT manifest has artifacts array");
-    let mut retained = Vec::new();
-    let mut paths = Vec::new();
-    for artifact in artifacts.drain(..) {
-        let name = artifact
-            .get("name")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has name")
-            .to_owned();
-        if !artifact_belongs_to_crate(&name) {
-            continue;
-        }
-        let path = artifact
-            .get("path")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has path")
-            .to_owned();
-        paths.push(path);
-        retained.push(artifact);
-    }
-    *artifacts = retained;
-    let rendered =
-        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
-    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
-    paths
-}
-
-fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
-    );
-    for file in files {
-        if !file.is_file() {
-            continue;
-        }
-        let relative = file
-            .strip_prefix(artifact_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| "manifest.json".to_owned());
-        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/Cargo.toml
deleted file mode 100644
index 81fda9a39..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Wasmer AOT pg_dump and psql artifacts for oliphaunt-wasix on aarch64-unknown-linux-gnu"
-repository = "https://github.com/f0rr0/oliphaunt"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_oliphaunt_wasix_tools_aot_linux_arm64_gnu"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-serde_json = "1"
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/build.rs b/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/build.rs
deleted file mode 100644
index 127906ae8..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/aarch64-unknown-linux-gnu/build.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
-const ARTIFACT_KIND: &str = "wasix-tools-aot";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
-
-    let target = env::var("CARGO_PKG_NAME")
-        .expect("CARGO_PKG_NAME is set by Cargo")
-        .strip_prefix("oliphaunt-wasix-tools-aot-")
-        .expect("AOT crate name starts with oliphaunt-wasix-tools-aot-")
-        .to_owned();
-    emit_expected_artifact_inputs(&target);
-
-    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
-        .join("generated_aot.rs");
-    if let Some(artifact_dir) = find_artifact_dir(&target) {
-        emit_rerun_directives(&artifact_dir);
-        write_generated_aot(&out, &target, &artifact_dir);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX tools AOT artifacts for {target}");
-    } else {
-        write_source_only_aot(&out, &target);
-    }
-}
-
-fn emit_expected_artifact_inputs(target: &str) {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        emit_manifest_probe(&candidate);
-    }
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
-    }
-    emit_manifest_probe(&manifest_dir.join("artifacts"));
-}
-
-fn emit_manifest_probe(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("manifest.json").display()
-    );
-}
-
-fn find_artifact_dir(target: &str) -> Option {
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let package_artifacts = manifest_dir.join("artifacts");
-    if package_artifacts.join("manifest.json").is_file() {
-        return Some(package_artifacts);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        if candidate.join("manifest.json").is_file() {
-            return Some(candidate);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
-        if target_artifacts.join("manifest.json").is_file() {
-            return Some(target_artifacts);
-        }
-    }
-
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
-    manifest_dir.ancestors().find(|candidate| {
-        candidate.join("Cargo.toml").is_file()
-            && candidate
-                .join("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml")
-                .is_file()
-    })
-}
-
-fn emit_rerun_directives(artifact_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", artifact_dir.display());
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.is_file() {
-                println!("cargo:rerun-if-changed={}", path.display());
-            }
-        }
-    }
-}
-
-fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
-    let manifest = artifact_dir.join("manifest.json");
-    let generated_manifest = out
-        .parent()
-        .expect("generated AOT output has parent")
-        .join("manifest.json");
-    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
-    let mut cases = String::new();
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        let mut files = entries
-            .flatten()
-            .map(|entry| entry.path())
-            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
-            .collect::>();
-        files.sort();
-        for file in files {
-            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
-                continue;
-            };
-            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
-                continue;
-            };
-            let artifact_name = artifact_name_from_file_stem(stem);
-            if !artifact_belongs_to_crate(&artifact_name) {
-                continue;
-            }
-            cases.push_str(&format!(
-                "        {:?} => Some(include_bytes!({})),\n",
-                artifact_name,
-                rust_string_literal(&file)
-            ));
-        }
-    }
-    cases.push_str("        _ => None,\n");
-
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = true;\n\
-         pub const MANIFEST_JSON: &str = include_str!({});\n\
-         #[rustfmt::skip]\n\
-         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
-             match name {{\n\
-         {cases}    }}\n\
-         }}\n",
-        target,
-        rust_string_literal(&generated_manifest)
-    );
-    fs::write(out, text).expect("write generated AOT include module");
-    let mut manifest_files = vec![generated_manifest];
-    for relative in retained_paths {
-        manifest_files.push(artifact_dir.join(relative));
-    }
-    emit_artifact_manifest(
-        out.parent().expect("generated AOT output has parent"),
-        target,
-        artifact_dir,
-        &manifest_files,
-    );
-}
-
-fn write_source_only_aot(out: &Path, target: &str) {
-    let manifest = format!(
-        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
-    );
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {target:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = false;\n\
-         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
-         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
-    );
-    fs::write(out, text).expect("write source-only AOT include module");
-}
-
-fn artifact_name_from_file_stem(stem: &str) -> String {
-    match stem {
-        "oliphaunt" => "runtime:oliphaunt".to_owned(),
-        "pg_dump" => "tool:pg_dump".to_owned(),
-        "psql" => "tool:psql".to_owned(),
-        "initdb" => "tool:initdb".to_owned(),
-        "plpgsql" => "runtime-support:plpgsql".to_owned(),
-        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
-        extension_support if extension_support.ends_with("_deps") => {
-            let sql_name = extension_support.trim_end_matches("_deps");
-            format!("extension:{sql_name}:{extension_support}")
-        }
-        extension => format!("extension:{extension}"),
-    }
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn artifact_belongs_to_crate(name: &str) -> bool {
-    match ARTIFACT_KIND {
-        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
-        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
-    }
-}
-
-fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
-    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
-    let mut manifest: serde_json::Value =
-        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
-    let artifacts = manifest
-        .get_mut("artifacts")
-        .and_then(|value| value.as_array_mut())
-        .expect("generated WASIX AOT manifest has artifacts array");
-    let mut retained = Vec::new();
-    let mut paths = Vec::new();
-    for artifact in artifacts.drain(..) {
-        let name = artifact
-            .get("name")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has name")
-            .to_owned();
-        if !artifact_belongs_to_crate(&name) {
-            continue;
-        }
-        let path = artifact
-            .get("path")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has path")
-            .to_owned();
-        paths.push(path);
-        retained.push(artifact);
-    }
-    *artifacts = retained;
-    let rendered =
-        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
-    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
-    paths
-}
-
-fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
-    );
-    for file in files {
-        if !file.is_file() {
-            continue;
-        }
-        let relative = file
-            .strip_prefix(artifact_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| "manifest.json".to_owned());
-        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/Cargo.toml
deleted file mode 100644
index 8f90dc31e..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Wasmer AOT pg_dump and psql artifacts for oliphaunt-wasix on x86_64-pc-windows-msvc"
-repository = "https://github.com/f0rr0/oliphaunt"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_oliphaunt_wasix_tools_aot_windows_x64_msvc"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-serde_json = "1"
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/build.rs b/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/build.rs
deleted file mode 100644
index 127906ae8..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-pc-windows-msvc/build.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
-const ARTIFACT_KIND: &str = "wasix-tools-aot";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
-
-    let target = env::var("CARGO_PKG_NAME")
-        .expect("CARGO_PKG_NAME is set by Cargo")
-        .strip_prefix("oliphaunt-wasix-tools-aot-")
-        .expect("AOT crate name starts with oliphaunt-wasix-tools-aot-")
-        .to_owned();
-    emit_expected_artifact_inputs(&target);
-
-    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
-        .join("generated_aot.rs");
-    if let Some(artifact_dir) = find_artifact_dir(&target) {
-        emit_rerun_directives(&artifact_dir);
-        write_generated_aot(&out, &target, &artifact_dir);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX tools AOT artifacts for {target}");
-    } else {
-        write_source_only_aot(&out, &target);
-    }
-}
-
-fn emit_expected_artifact_inputs(target: &str) {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        emit_manifest_probe(&candidate);
-    }
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
-    }
-    emit_manifest_probe(&manifest_dir.join("artifacts"));
-}
-
-fn emit_manifest_probe(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("manifest.json").display()
-    );
-}
-
-fn find_artifact_dir(target: &str) -> Option {
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let package_artifacts = manifest_dir.join("artifacts");
-    if package_artifacts.join("manifest.json").is_file() {
-        return Some(package_artifacts);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        if candidate.join("manifest.json").is_file() {
-            return Some(candidate);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
-        if target_artifacts.join("manifest.json").is_file() {
-            return Some(target_artifacts);
-        }
-    }
-
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
-    manifest_dir.ancestors().find(|candidate| {
-        candidate.join("Cargo.toml").is_file()
-            && candidate
-                .join("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml")
-                .is_file()
-    })
-}
-
-fn emit_rerun_directives(artifact_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", artifact_dir.display());
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.is_file() {
-                println!("cargo:rerun-if-changed={}", path.display());
-            }
-        }
-    }
-}
-
-fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
-    let manifest = artifact_dir.join("manifest.json");
-    let generated_manifest = out
-        .parent()
-        .expect("generated AOT output has parent")
-        .join("manifest.json");
-    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
-    let mut cases = String::new();
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        let mut files = entries
-            .flatten()
-            .map(|entry| entry.path())
-            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
-            .collect::>();
-        files.sort();
-        for file in files {
-            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
-                continue;
-            };
-            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
-                continue;
-            };
-            let artifact_name = artifact_name_from_file_stem(stem);
-            if !artifact_belongs_to_crate(&artifact_name) {
-                continue;
-            }
-            cases.push_str(&format!(
-                "        {:?} => Some(include_bytes!({})),\n",
-                artifact_name,
-                rust_string_literal(&file)
-            ));
-        }
-    }
-    cases.push_str("        _ => None,\n");
-
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = true;\n\
-         pub const MANIFEST_JSON: &str = include_str!({});\n\
-         #[rustfmt::skip]\n\
-         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
-             match name {{\n\
-         {cases}    }}\n\
-         }}\n",
-        target,
-        rust_string_literal(&generated_manifest)
-    );
-    fs::write(out, text).expect("write generated AOT include module");
-    let mut manifest_files = vec![generated_manifest];
-    for relative in retained_paths {
-        manifest_files.push(artifact_dir.join(relative));
-    }
-    emit_artifact_manifest(
-        out.parent().expect("generated AOT output has parent"),
-        target,
-        artifact_dir,
-        &manifest_files,
-    );
-}
-
-fn write_source_only_aot(out: &Path, target: &str) {
-    let manifest = format!(
-        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
-    );
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {target:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = false;\n\
-         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
-         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
-    );
-    fs::write(out, text).expect("write source-only AOT include module");
-}
-
-fn artifact_name_from_file_stem(stem: &str) -> String {
-    match stem {
-        "oliphaunt" => "runtime:oliphaunt".to_owned(),
-        "pg_dump" => "tool:pg_dump".to_owned(),
-        "psql" => "tool:psql".to_owned(),
-        "initdb" => "tool:initdb".to_owned(),
-        "plpgsql" => "runtime-support:plpgsql".to_owned(),
-        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
-        extension_support if extension_support.ends_with("_deps") => {
-            let sql_name = extension_support.trim_end_matches("_deps");
-            format!("extension:{sql_name}:{extension_support}")
-        }
-        extension => format!("extension:{extension}"),
-    }
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn artifact_belongs_to_crate(name: &str) -> bool {
-    match ARTIFACT_KIND {
-        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
-        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
-    }
-}
-
-fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
-    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
-    let mut manifest: serde_json::Value =
-        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
-    let artifacts = manifest
-        .get_mut("artifacts")
-        .and_then(|value| value.as_array_mut())
-        .expect("generated WASIX AOT manifest has artifacts array");
-    let mut retained = Vec::new();
-    let mut paths = Vec::new();
-    for artifact in artifacts.drain(..) {
-        let name = artifact
-            .get("name")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has name")
-            .to_owned();
-        if !artifact_belongs_to_crate(&name) {
-            continue;
-        }
-        let path = artifact
-            .get("path")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has path")
-            .to_owned();
-        paths.push(path);
-        retained.push(artifact);
-    }
-    *artifacts = retained;
-    let rendered =
-        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
-    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
-    paths
-}
-
-fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
-    );
-    for file in files {
-        if !file.is_file() {
-            continue;
-        }
-        let relative = file
-            .strip_prefix(artifact_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| "manifest.json".to_owned());
-        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/Cargo.toml
deleted file mode 100644
index e7ec7c065..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-name = "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Wasmer AOT pg_dump and psql artifacts for oliphaunt-wasix on x86_64-unknown-linux-gnu"
-repository = "https://github.com/f0rr0/oliphaunt"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_oliphaunt_wasix_tools_aot_linux_x64_gnu"
-include = ["Cargo.toml", "README.md", "build.rs", "src/**", "artifacts/**", "LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", "THIRD_PARTY_LICENSES/ICU-LICENSE"]
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-serde_json = "1"
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/build.rs b/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/build.rs
deleted file mode 100644
index 127906ae8..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools-aot/x86_64-unknown-linux-gnu/build.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
-const ARTIFACT_KIND: &str = "wasix-tools-aot";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASM_GENERATED_AOT_DIR");
-
-    let target = env::var("CARGO_PKG_NAME")
-        .expect("CARGO_PKG_NAME is set by Cargo")
-        .strip_prefix("oliphaunt-wasix-tools-aot-")
-        .expect("AOT crate name starts with oliphaunt-wasix-tools-aot-")
-        .to_owned();
-    emit_expected_artifact_inputs(&target);
-
-    let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"))
-        .join("generated_aot.rs");
-    if let Some(artifact_dir) = find_artifact_dir(&target) {
-        emit_rerun_directives(&artifact_dir);
-        write_generated_aot(&out, &target, &artifact_dir);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX tools AOT artifacts for {target}");
-    } else {
-        write_source_only_aot(&out, &target);
-    }
-}
-
-fn emit_expected_artifact_inputs(target: &str) {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        emit_manifest_probe(&candidate);
-    }
-
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_manifest_probe(&repo_root.join("target/oliphaunt-wasix/aot").join(target));
-    }
-    emit_manifest_probe(&manifest_dir.join("artifacts"));
-}
-
-fn emit_manifest_probe(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("manifest.json").display()
-    );
-}
-
-fn find_artifact_dir(target: &str) -> Option {
-    let manifest_dir = PathBuf::from(
-        env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"),
-    );
-    let package_artifacts = manifest_dir.join("artifacts");
-    if package_artifacts.join("manifest.json").is_file() {
-        return Some(package_artifacts);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASM_GENERATED_AOT_DIR") {
-        let path = PathBuf::from(path);
-        let candidate = if path.ends_with(target) {
-            path
-        } else {
-            path.join(target)
-        };
-        if candidate.join("manifest.json").is_file() {
-            return Some(candidate);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_artifacts = repo_root.join("target/oliphaunt-wasix/aot").join(target);
-        if target_artifacts.join("manifest.json").is_file() {
-            return Some(target_artifacts);
-        }
-    }
-
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option<&Path> {
-    manifest_dir.ancestors().find(|candidate| {
-        candidate.join("Cargo.toml").is_file()
-            && candidate
-                .join("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml")
-                .is_file()
-    })
-}
-
-fn emit_rerun_directives(artifact_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", artifact_dir.display());
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.is_file() {
-                println!("cargo:rerun-if-changed={}", path.display());
-            }
-        }
-    }
-}
-
-fn write_generated_aot(out: &Path, target: &str, artifact_dir: &Path) {
-    let manifest = artifact_dir.join("manifest.json");
-    let generated_manifest = out
-        .parent()
-        .expect("generated AOT output has parent")
-        .join("manifest.json");
-    let retained_paths = write_core_aot_manifest(&manifest, &generated_manifest);
-    let mut cases = String::new();
-    if let Ok(entries) = fs::read_dir(artifact_dir) {
-        let mut files = entries
-            .flatten()
-            .map(|entry| entry.path())
-            .filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("zst"))
-            .collect::>();
-        files.sort();
-        for file in files {
-            let Some(file_name) = file.file_name().and_then(|name| name.to_str()) else {
-                continue;
-            };
-            let Some(stem) = file_name.strip_suffix("-llvm-opta.bin.zst") else {
-                continue;
-            };
-            let artifact_name = artifact_name_from_file_stem(stem);
-            if !artifact_belongs_to_crate(&artifact_name) {
-                continue;
-            }
-            cases.push_str(&format!(
-                "        {:?} => Some(include_bytes!({})),\n",
-                artifact_name,
-                rust_string_literal(&file)
-            ));
-        }
-    }
-    cases.push_str("        _ => None,\n");
-
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = true;\n\
-         pub const MANIFEST_JSON: &str = include_str!({});\n\
-         #[rustfmt::skip]\n\
-         pub fn artifact_bytes(name: &str) -> Option<&'static [u8]> {{\n\
-             match name {{\n\
-         {cases}    }}\n\
-         }}\n",
-        target,
-        rust_string_literal(&generated_manifest)
-    );
-    fs::write(out, text).expect("write generated AOT include module");
-    let mut manifest_files = vec![generated_manifest];
-    for relative in retained_paths {
-        manifest_files.push(artifact_dir.join(relative));
-    }
-    emit_artifact_manifest(
-        out.parent().expect("generated AOT output has parent"),
-        target,
-        artifact_dir,
-        &manifest_files,
-    );
-}
-
-fn write_source_only_aot(out: &Path, target: &str) {
-    let manifest = format!(
-        "{{\"format-version\":1,\"target-triple\":{target:?},\"engine\":\"llvm-opta\",\"wasmer-version\":\"7.2.1\",\"wasmer-wasix-version\":\"0.702.1\",\"artifacts\":[]}}"
-    );
-    let text = format!(
-        "pub const TARGET_TRIPLE: &str = {target:?};\n\
-         pub const ENGINE: &str = \"llvm-opta\";\n\
-         pub const HAS_EMBEDDED_AOT: bool = false;\n\
-         pub const MANIFEST_JSON: &str = r#\"{manifest}\"#;\n\
-         pub fn artifact_bytes(_name: &str) -> Option<&'static [u8]> {{ None }}\n"
-    );
-    fs::write(out, text).expect("write source-only AOT include module");
-}
-
-fn artifact_name_from_file_stem(stem: &str) -> String {
-    match stem {
-        "oliphaunt" => "runtime:oliphaunt".to_owned(),
-        "pg_dump" => "tool:pg_dump".to_owned(),
-        "psql" => "tool:psql".to_owned(),
-        "initdb" => "tool:initdb".to_owned(),
-        "plpgsql" => "runtime-support:plpgsql".to_owned(),
-        "dict_snowball" => "runtime-support:dict_snowball".to_owned(),
-        extension_support if extension_support.ends_with("_deps") => {
-            let sql_name = extension_support.trim_end_matches("_deps");
-            format!("extension:{sql_name}:{extension_support}")
-        }
-        extension => format!("extension:{extension}"),
-    }
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn artifact_belongs_to_crate(name: &str) -> bool {
-    match ARTIFACT_KIND {
-        "wasix-tools-aot" => matches!(name, "tool:pg_dump" | "tool:psql"),
-        _ => !name.starts_with("extension:") && !matches!(name, "tool:pg_dump" | "tool:psql"),
-    }
-}
-
-fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec {
-    let text = fs::read_to_string(source).expect("read generated WASIX AOT manifest");
-    let mut manifest: serde_json::Value =
-        serde_json::from_str(&text).expect("parse generated WASIX AOT manifest");
-    let artifacts = manifest
-        .get_mut("artifacts")
-        .and_then(|value| value.as_array_mut())
-        .expect("generated WASIX AOT manifest has artifacts array");
-    let mut retained = Vec::new();
-    let mut paths = Vec::new();
-    for artifact in artifacts.drain(..) {
-        let name = artifact
-            .get("name")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has name")
-            .to_owned();
-        if !artifact_belongs_to_crate(&name) {
-            continue;
-        }
-        let path = artifact
-            .get("path")
-            .and_then(|value| value.as_str())
-            .expect("AOT artifact has path")
-            .to_owned();
-        paths.push(path);
-        retained.push(artifact);
-    }
-    *artifacts = retained;
-    let rendered =
-        serde_json::to_string_pretty(&manifest).expect("serialize core WASIX AOT manifest");
-    fs::write(destination, format!("{rendered}\n")).expect("write core WASIX AOT manifest");
-    paths
-}
-
-fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {target:?}\n"
-    );
-    for file in files {
-        if !file.is_file() {
-            continue;
-        }
-        let relative = file
-            .strip_prefix(artifact_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| "manifest.json".to_owned());
-        let sha256 = sha256_file(file).expect("hash WASIX AOT artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX AOT Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools/Cargo.toml b/src/runtimes/liboliphaunt/wasix/crates/tools/Cargo.toml
deleted file mode 100644
index 9f110a89d..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools/Cargo.toml
+++ /dev/null
@@ -1,34 +0,0 @@
-[package]
-name = "oliphaunt-wasix-tools"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "WASIX pg_dump and psql assets for oliphaunt-wasix"
-repository = "https://github.com/f0rr0/oliphaunt"
-homepage = "https://oliphaunt.dev"
-documentation = "https://docs.rs/oliphaunt-wasix-tools"
-license = "MIT AND PostgreSQL AND Unicode-3.0"
-publish = false
-links = "oliphaunt_artifact_oliphaunt_wasix_tools"
-include = [
-  "Cargo.toml",
-  "build.rs",
-  "README.md",
-  "src/**",
-  "payload/**",
-  "LICENSE",
-  "THIRD_PARTY_NOTICES.md",
-  "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
-  "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-  "THIRD_PARTY_LICENSES/ICU-LICENSE",
-]
-
-[package.metadata.oliphaunt-wasix-tools.assets]
-pg-dump-wasix-sha256 = "90180532a2d4ccd68405f9ecc3057607e84fb5a033ae51541bc36535a8311909"
-psql-wasix-sha256 = "894aeb0d846c249e4697a4795184b2e6a470ca53daa4819f61c204f05baf9c8d"
-
-[lib]
-path = "src/lib.rs"
-
-[build-dependencies]
-sha2 = "0.10"
diff --git a/src/runtimes/liboliphaunt/wasix/crates/tools/build.rs b/src/runtimes/liboliphaunt/wasix/crates/tools/build.rs
deleted file mode 100644
index 11fa02bd0..000000000
--- a/src/runtimes/liboliphaunt/wasix/crates/tools/build.rs
+++ /dev/null
@@ -1,195 +0,0 @@
-use std::env;
-use std::fs;
-use std::io::{self, Read};
-use std::path::{Path, PathBuf};
-
-use sha2::{Digest, Sha256};
-
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";
-const ARTIFACT_KIND: &str = "wasix-tools";
-const ARTIFACT_TARGET: &str = "portable";
-
-fn main() {
-    println!("cargo:rerun-if-env-changed=OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR");
-    emit_expected_asset_inputs();
-
-    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"));
-    let out = out_dir.join("generated_tools.rs");
-    if let Some(asset_dir) = find_asset_dir() {
-        emit_rerun_directives(&asset_dir);
-        write_generated_tools(&out, &asset_dir);
-    } else if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() {
-        panic!("release packaging requires package-local WASIX tools payload");
-    } else {
-        write_source_only_tools(&out);
-    }
-}
-
-fn emit_expected_asset_inputs() {
-    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR") {
-        emit_tool_probes(&PathBuf::from(path));
-    }
-
-    let manifest_dir =
-        PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set"));
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        emit_tool_probes(&repo_root.join("target/oliphaunt-wasix/assets"));
-    }
-    emit_tool_probes(&manifest_dir.join("payload"));
-}
-
-fn emit_tool_probes(dir: &Path) {
-    println!("cargo:rerun-if-changed={}", dir.display());
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("bin/pg_dump.wasix.wasm").display()
-    );
-    println!(
-        "cargo:rerun-if-changed={}",
-        dir.join("bin/psql.wasix.wasm").display()
-    );
-}
-
-fn find_asset_dir() -> Option {
-    let manifest_dir =
-        PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set"));
-    let package_payload = manifest_dir.join("payload");
-    if package_payload.join("bin/pg_dump.wasix.wasm").is_file()
-        && package_payload.join("bin/psql.wasix.wasm").is_file()
-    {
-        return Some(package_payload);
-    }
-
-    if let Some(path) = env::var_os("OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR") {
-        let path = PathBuf::from(path);
-        if path.join("bin/pg_dump.wasix.wasm").is_file()
-            && path.join("bin/psql.wasix.wasm").is_file()
-        {
-            return Some(path);
-        }
-    }
-
-    if let Some(repo_root) = repo_root_from_manifest_dir(&manifest_dir) {
-        let target_assets = repo_root.join("target/oliphaunt-wasix/assets");
-        if target_assets.join("bin/pg_dump.wasix.wasm").is_file()
-            && target_assets.join("bin/psql.wasix.wasm").is_file()
-        {
-            return Some(target_assets);
-        }
-    }
-    None
-}
-
-fn repo_root_from_manifest_dir(manifest_dir: &Path) -> Option {
-    for ancestor in manifest_dir.ancestors() {
-        if ancestor.join(".git").exists() && ancestor.join("Cargo.toml").is_file() {
-            return Some(ancestor.to_path_buf());
-        }
-    }
-    None
-}
-
-fn emit_rerun_directives(asset_dir: &Path) {
-    println!("cargo:rerun-if-changed={}", asset_dir.display());
-    visit_files(asset_dir, &mut |path| {
-        println!("cargo:rerun-if-changed={}", path.display());
-    });
-}
-
-fn visit_files(path: &Path, f: &mut impl FnMut(&Path)) {
-    let Ok(entries) = fs::read_dir(path) else {
-        return;
-    };
-    for entry in entries.flatten() {
-        let path = entry.path();
-        if path.is_dir() {
-            visit_files(&path, f);
-        } else if path.is_file() {
-            f(&path);
-        }
-    }
-}
-
-fn write_generated_tools(out: &Path, asset_dir: &Path) {
-    let pg_dump = asset_dir.join("bin/pg_dump.wasix.wasm");
-    let psql = asset_dir.join("bin/psql.wasix.wasm");
-    for required in [&pg_dump, &psql] {
-        assert!(
-            required.is_file(),
-            "generated WASIX tools directory {} is missing required file {}",
-            asset_dir.display(),
-            required.display()
-        );
-    }
-    let text = format!(
-        "pub const HAS_EMBEDDED_TOOLS: bool = true;\n\
-         pub fn pg_dump_wasm() -> Option<&'static [u8]> {{ Some(include_bytes!({pg_dump})) }}\n\
-         pub fn psql_wasm() -> Option<&'static [u8]> {{ Some(include_bytes!({psql})) }}\n",
-        pg_dump = rust_string_literal(&pg_dump),
-        psql = rust_string_literal(&psql),
-    );
-    fs::write(out, text).expect("write generated WASIX tool include module");
-    emit_artifact_manifest(
-        out.parent().expect("generated tool output has parent"),
-        asset_dir,
-        &[&pg_dump, &psql],
-    );
-}
-
-fn write_source_only_tools(out: &Path) {
-    fs::write(
-        out,
-        "pub const HAS_EMBEDDED_TOOLS: bool = false;\n\
-         pub fn pg_dump_wasm() -> Option<&'static [u8]> { None }\n\
-         pub fn psql_wasm() -> Option<&'static [u8]> { None }\n",
-    )
-    .expect("write source-only WASIX tool include module");
-}
-
-fn rust_string_literal(path: &Path) -> String {
-    format!("{:?}", path.to_string_lossy())
-}
-
-fn emit_artifact_manifest(out_dir: &Path, asset_dir: &Path, files: &[&Path]) {
-    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
-    let manifest_path = out_dir.join("oliphaunt-artifact.toml");
-    let mut text = format!(
-        "schema = {ARTIFACT_SCHEMA:?}\nproduct = {ARTIFACT_PRODUCT:?}\nversion = {version:?}\nkind = {ARTIFACT_KIND:?}\ntarget = {ARTIFACT_TARGET:?}\n"
-    );
-    for file in files {
-        let relative = file
-            .strip_prefix(asset_dir)
-            .ok()
-            .map(|path| path.to_string_lossy().replace('\\', "/"))
-            .unwrap_or_else(|| {
-                file.file_name()
-                    .unwrap_or_default()
-                    .to_string_lossy()
-                    .into_owned()
-            });
-        let sha256 = sha256_file(file).expect("hash WASIX tools artifact file");
-        text.push_str(&format!(
-            "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n",
-            file.display().to_string(),
-            relative,
-            sha256,
-        ));
-    }
-    fs::write(&manifest_path, text).expect("write WASIX tools Cargo artifact manifest");
-    println!("cargo::metadata=manifest={}", manifest_path.display());
-}
-
-fn sha256_file(path: &Path) -> io::Result {
-    let mut file = fs::File::open(path)?;
-    let mut hasher = Sha256::new();
-    let mut buffer = [0u8; 128 * 1024];
-    loop {
-        let read = file.read(&mut buffer)?;
-        if read == 0 {
-            break;
-        }
-        hasher.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", hasher.finalize()))
-}
diff --git a/src/runtimes/liboliphaunt/wasix/moon.yml b/src/runtimes/liboliphaunt/wasix/moon.yml
deleted file mode 100644
index 53ad8bbf0..000000000
--- a/src/runtimes/liboliphaunt/wasix/moon.yml
+++ /dev/null
@@ -1,290 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "liboliphaunt-wasix"
-language: "rust"
-layer: "library"
-stack: "systems"
-tags: ["runtime", "wasix", "wasm", "postgres", "release-product"]
-dependsOn:
-  - id: "postgres18"
-    scope: "build"
-  - id: "source-toolchains"
-    scope: "build"
-  - id: "third-party-shared"
-    scope: "build"
-  - id: "extensions"
-    scope: "build"
-  - id: "extension-runtime-contract"
-    scope: "build"
-  - id: "oliphaunt-extension-contrib-pg18"
-    scope: "build"
-
-project:
-  title: "liboliphaunt WASIX"
-  description: "WASIX PostgreSQL runtime, portable assets, and AOT artifact carriers."
-  owner: "oliphaunt"
-  release:
-    component: "liboliphaunt-wasix"
-    packagePath: "src/runtimes/liboliphaunt/wasix"
-    artifactTargets:
-      preset: "liboliphaunt-wasix"
-      targets:
-        - "portable"
-        - "linux-arm64-gnu"
-        - "linux-x64-gnu"
-        - "macos-arm64"
-        - "windows-x64-msvc"
-
-owners:
-  defaultOwner: "@oliphaunt/wasix"
-  paths:
-    "assets/**": ["@oliphaunt/wasix"]
-    "crates/**": ["@oliphaunt/wasix"]
-    "tools/**": ["@oliphaunt/wasix"]
-
-fileGroups:
-  version:
-    - "VERSION"
-  release-metadata:
-    - "VERSION"
-    - "release.toml"
-  crates:
-    - "crates/**/*"
-
-tasks:
-  unit:
-    tags: ["quality", "unit"]
-    script: |
-      set -e
-      bash src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.test.sh
-      bash src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-wasixcc.test.sh
-    inputs:
-      - "assets/build/docker/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-
-  lint:
-    tags: ["quality", "static"]
-    command: "src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs"
-    inputs:
-      - "assets/build/postgres/**/*"
-      - "tools/check-patch-stack.mjs"
-      - "/src/postgres/versions/18/source.toml"
-      - "/docs/internal/WASIX_PATCH_STACK.md"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-
-  assets-verify:
-    tags: ["quality", "static", "requires-rust"]
-    command: "bash src/runtimes/liboliphaunt/wasix/tools/verify-committed-assets.sh"
-    inputs:
-      - "@group(cargo-workspace)"
-      - project: "postgres18"
-        group: "source"
-      - project: "source-toolchains"
-        group: "wasix"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "extensions"
-        group: "build"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "assets/build/**/*"
-      - "assets/generated/**/*"
-      - "crates/**/*"
-      - "tools/verify-committed-assets.sh"
-      - "/src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"
-      - "/tools/xtask/**/*"
-      - "/src/sources/tools/verify-source-tree.py"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-
-  runtime-portable:
-    tags: ["runtime", "artifact", "ci-liboliphaunt-wasix-runtime"]
-    command: "bash src/runtimes/liboliphaunt/wasix/tools/build-runtime-portable.sh"
-    deps:
-      - "source-inputs:source-fetch-wasix-runtime"
-    inputs:
-      - "@group(legal-files)"
-      - "@group(cargo-workspace)"
-      - "/src/bindings/wasix-rust/THIRD_PARTY_NOTICES.md"
-      - "/src/runtimes/liboliphaunt/licenses/**/*"
-      - project: "postgres18"
-        group: "source"
-      - project: "source-toolchains"
-        group: "wasix"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "extensions"
-        group: "build"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "assets/build/**/*"
-      - "crates/**/*"
-      - "tools/build-runtime-portable.sh"
-      - "!assets/generated"
-      - "!assets/generated/**"
-      - "/src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"
-      - "/tools/xtask/**/*"
-      - "@group(release-archive-contract)"
-      - "/src/sources/tools/verify-source-tree.py"
-    outputs:
-      - "/target/oliphaunt-wasix/wasix-build/build/**/*"
-      - "/target/oliphaunt-wasix/wasix-build/work/icu-wasix/share/icu/**/*"
-      - "/target/oliphaunt-wasix/assets/**/*"
-      - "/src/extensions/generated/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/assets/generated/**/*"
-    options:
-      cache: local
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  runtime-aot:
-    tags: ["runtime", "artifact", "ci-liboliphaunt-wasix-aot"]
-    command: "bash src/runtimes/liboliphaunt/wasix/tools/build-aot-target.sh"
-    deps:
-      - "liboliphaunt-wasix:runtime-portable"
-    inputs:
-      - "@group(legal-files)"
-      - "@group(cargo-workspace)"
-      - "/src/bindings/wasix-rust/THIRD_PARTY_NOTICES.md"
-      - "/src/runtimes/liboliphaunt/licenses/**/*"
-      - project: "postgres18"
-        group: "source"
-      - project: "source-toolchains"
-        group: "wasix"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "extensions"
-        group: "build"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - "crates/**/*"
-      - "tools/build-aot-target.sh"
-      - "tools/cargo-test-filter.sh"
-      - "/src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"
-      - "/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh"
-      - "/tools/xtask/**/*"
-      - "@group(release-archive-contract)"
-      - "/src/sources/tools/verify-source-tree.py"
-    outputs:
-      - "/target/oliphaunt-wasix/aot/**/*"
-      - "/target/extensions/wasix/aot-artifacts/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/crates/aot/*/artifacts/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/crates/tools-aot/*/artifacts/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  release-assets:
-    tags: ["release", "artifact", "ci-liboliphaunt-wasix-release-assets"]
-    command: "cargo run -p xtask -- release package-assets"
-    env:
-      CARGO_TARGET_DIR: "target/moon/liboliphaunt-wasix/release-assets"
-    deps:
-      - "liboliphaunt-wasix:runtime-portable"
-      - "liboliphaunt-wasix:runtime-aot"
-    inputs:
-      - "@group(legal-files)"
-      - "@group(cargo-workspace)"
-      - "/src/bindings/wasix-rust/THIRD_PARTY_NOTICES.md"
-      - "/src/postgres/versions/18/source.toml"
-      - "/src/runtimes/liboliphaunt/licenses/**/*"
-      - "assets/generated/**/*"
-      - "crates/**/*"
-      - "/src/sources/third-party/shared/icu.toml"
-      - "/src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"
-      - "/src/runtimes/liboliphaunt/wasix/crates/assets/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/crates/aot/**/*"
-      - "/tools/xtask/**/*"
-      - "/tools/release/check-liboliphaunt-wasix-release-assets.mjs"
-      - "@group(release-archive-contract)"
-      - "/src/sources/tools/verify-source-tree.py"
-      - "/target/oliphaunt-wasix/wasix-build/build/**/*"
-      - "/target/oliphaunt-wasix/wasix-build/work/icu-wasix/share/icu/**/*"
-      - "/target/oliphaunt-wasix/assets/**/*"
-      - "/target/oliphaunt-wasix/aot/**/*"
-    outputs:
-      - "/target/oliphaunt-wasix/release-assets/**/*"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
-
-  smoke:
-    tags: ["runtime", "smoke"]
-    command: "bash src/runtimes/liboliphaunt/wasix/tools/runtime-smoke.sh"
-    deps:
-      - "liboliphaunt-wasix:runtime-aot"
-    inputs:
-      - "@group(cargo-workspace)"
-      - project: "postgres18"
-        group: "source"
-      - project: "source-toolchains"
-        group: "wasix"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "extensions"
-        group: "build"
-      - "tools/cargo-test-filter.sh"
-      - "tools/runtime-preflight.sh"
-      - "tools/runtime-smoke.sh"
-      - "/src/bindings/wasix-rust/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh"
-      - "/tools/xtask/**/*"
-      - "/src/sources/tools/verify-source-tree.py"
-    options:
-      cache: local
-      runFromWorkspaceRoot: true
-      runInCI: false
-
-  regression:
-    tags: ["regression", "runtime"]
-    command: "bash src/runtimes/liboliphaunt/wasix/tools/runtime-smoke.sh regression"
-    deps:
-      - "liboliphaunt-wasix:runtime-aot"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "@group(legal-files)"
-      - "@group(pnpm-workspace)"
-      - project: "postgres18"
-        group: "source"
-      - project: "source-toolchains"
-        group: "wasix"
-      - project: "third-party-shared"
-        group: "sources"
-      - project: "extensions"
-        group: "build"
-      - "tools/cargo-test-filter.sh"
-      - "tools/runtime-preflight.sh"
-      - "tools/runtime-smoke.sh"
-      - "/src/bindings/wasix-rust/**/*"
-      - "/src/bindings/wasix-ts/**/*"
-      - "/src/shared/js-core/**/*"
-      - "/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh"
-      - "/tools/release/wasix-runtime-npm-*.mjs"
-      - "/tools/release/wasix-tools-npm-carrier.mjs"
-      - "/tools/release/wasix-typescript-package.mjs"
-      - "@group(release-archive-contract)"
-      - "/tools/xtask/**/*"
-      - "/src/sources/tools/verify-source-tree.py"
-    options:
-      cache: local
-      runFromWorkspaceRoot: true
-
-  qualify:
-    tags: ["release", "package"]
-    command: "true"
-    deps:
-      - "liboliphaunt-wasix:lint"
-      - "liboliphaunt-wasix:assets-verify"
-      - "liboliphaunt-wasix:release-assets"
-      - "liboliphaunt-wasix:smoke"
-      - "liboliphaunt-wasix:regression"
-    inputs: []
-    options:
-      runInCI: false
diff --git a/src/runtimes/liboliphaunt/wasix/release.toml b/src/runtimes/liboliphaunt/wasix/release.toml
deleted file mode 100644
index c0c5225b2..000000000
--- a/src/runtimes/liboliphaunt/wasix/release.toml
+++ /dev/null
@@ -1,30 +0,0 @@
-id = "liboliphaunt-wasix"
-owner = "@oliphaunt/wasix"
-kind = "wasm-runtime"
-publish_targets = ["github-release-assets", "crates-io", "npm"]
-registry_packages = [
-  "crates:oliphaunt-icu",
-  "crates:liboliphaunt-wasix-portable",
-  "crates:oliphaunt-wasix-tools",
-  "crates:liboliphaunt-wasix-aot-aarch64-apple-darwin",
-  "crates:liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu",
-  "crates:liboliphaunt-wasix-aot-x86_64-pc-windows-msvc",
-  "crates:liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu",
-  "crates:oliphaunt-wasix-tools-aot-aarch64-apple-darwin",
-  "crates:oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu",
-  "crates:oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc",
-  "crates:oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu",
-  "npm:@oliphaunt/liboliphaunt-wasix",
-  "npm:@oliphaunt/liboliphaunt-wasix-tools",
-  "npm:@oliphaunt/wasix-icu",
-]
-release_artifacts = [
-  "release-assets",
-]
-derived_version_files = ["src/runtimes/liboliphaunt/icu/Cargo.toml"]
-shared_source_paths = ["src/runtimes/liboliphaunt/icu"]
-
-[compatibility_versions.liboliphaunt-wasix-icu]
-source_product = "liboliphaunt-wasix"
-path = "src/runtimes/liboliphaunt/icu/Cargo.toml"
-parser = "toml:package.version"
diff --git a/src/runtimes/liboliphaunt/wasix/tools-npm/index.js b/src/runtimes/liboliphaunt/wasix/tools-npm/index.js
deleted file mode 100644
index 1c6175499..000000000
--- a/src/runtimes/liboliphaunt/wasix/tools-npm/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import manifest from './package.json' with { type: 'json' };
-
-// Source-workspace descriptor. Release packaging emits the same shape with
-// package-local assets and removes the private marker.
-export default Object.freeze({
-  schema: 'oliphaunt-wasix-tools-v1',
-  product: 'oliphaunt-wasix-tools',
-  version: manifest.version,
-  runtimeProduct: 'liboliphaunt-wasix',
-  runtimeVersion: manifest.version,
-  pgDump: Object.freeze({
-    name: 'pg_dump',
-    sha256: '90180532a2d4ccd68405f9ecc3057607e84fb5a033ae51541bc36535a8311909',
-    size: 1324956,
-    source: new URL('../../../../../target/oliphaunt-wasix/assets/bin/pg_dump.wasix.wasm', import.meta.url).href,
-  }),
-  psql: Object.freeze({
-    name: 'psql',
-    sha256: '894aeb0d846c249e4697a4795184b2e6a470ca53daa4819f61c204f05baf9c8d',
-    size: 1419164,
-    source: new URL('../../../../../target/oliphaunt-wasix/assets/bin/psql.wasix.wasm', import.meta.url).href,
-  }),
-});
diff --git a/src/runtimes/liboliphaunt/wasix/tools-npm/package.json b/src/runtimes/liboliphaunt/wasix/tools-npm/package.json
deleted file mode 100644
index 70377d99d..000000000
--- a/src/runtimes/liboliphaunt/wasix/tools-npm/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "name": "@oliphaunt/liboliphaunt-wasix-tools",
-  "version": "0.2.0",
-  "description": "Portable WASIX pg_dump and psql modules for Oliphaunt hosts.",
-  "license": "MIT AND PostgreSQL AND Unicode-3.0",
-  "type": "module",
-  "sideEffects": false,
-  "private": true,
-  "exports": {
-    ".": {
-      "types": "./index.d.ts",
-      "default": "./index.js"
-    },
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/liboliphaunt/wasix/tools/build-aot-target.sh b/src/runtimes/liboliphaunt/wasix/tools/build-aot-target.sh
deleted file mode 100755
index d09c9f1ad..000000000
--- a/src/runtimes/liboliphaunt/wasix/tools/build-aot-target.sh
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
-root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "unable to determine repository root from $script_dir; run this script from a Git checkout" >&2
-  exit 1
-}
-[ -f "$root/package.json" ] && [ -d "$root/src/runtimes/liboliphaunt/wasix" ] || {
-  echo "must run inside the Oliphaunt workspace" >&2
-  exit 1
-}
-cd "$root"
-
-. "$root/src/runtimes/liboliphaunt/wasix/tools/cargo-test-filter.sh"
-
-target="${AOT_TARGET:-${1:-}}"
-if [ -z "$target" ]; then
-  target="$(rustc -vV | awk '/^host:/{print $2}')"
-fi
-package="${AOT_PACKAGE:-liboliphaunt-wasix-aot-${target}}"
-host="$(rustc -vV | awk '/^host:/{print $2}')"
-if [ "$target" != "$host" ]; then
-  echo "target AOT execution requires the builder host $host to match AOT target $target" >&2
-  exit 1
-fi
-
-cargo run -p xtask -- assets aot --target-triple "$target"
-cargo run -p xtask -- assets package-aot --target-triple "$target"
-cargo run -p xtask -- assets package-extension-aot --target-triple "$target"
-cargo run -p xtask -- assets check-aot --target-triple "$target"
-cargo check -p "$package" --locked
-cargo run -p xtask -- assets smoke --core-only
-
-# The portable/Linux regression exercises every catalogued extension. Each host
-# must also deserialize and execute machine code produced for that exact host,
-# including a side module and the split pg_dump/psql tool artifacts.  Keep this
-# bounded representative lane on all four AOT builders so cross-host coverage
-# does not multiply the exhaustive 39-extension lifecycle suite by four.
-proof_root="$root/target/wasix-target-aot-smoke"
-rm -rf "$proof_root"
-OLIPHAUNT_WASIX_GENERATED_ASSET_ROOT="$root/target/oliphaunt-wasix/assets" \
-OLIPHAUNT_WASIX_EXTENSION_AOT_ARTIFACT_ROOT="$root/target/extensions/wasix/aot-artifacts" \
-  tools/dev/bun.sh tools/release/build-extension-ci-artifacts.mjs \
-    --output-root "$proof_root/extension-artifacts" \
-    --family wasix \
-    --require-wasix \
-    oliphaunt-extension-contrib-pg18
-aot_test_filter="extension_tests::uuid_ossp_aot_"
-aot_test_command=(
-  env
-  OLIPHAUNT_WASM_AOT_VERIFY=full
-  OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="$proof_root/extension-artifacts"
-  cargo test -p oliphaunt-wasix --locked --no-default-features
-  --features extension-uuid-ossp,tools
-  --lib "$aot_test_filter"
-)
-oliphaunt_assert_cargo_test_filter_count 4 "$aot_test_filter" "${aot_test_command[@]}"
-"${aot_test_command[@]}" -- --nocapture --test-threads=1
diff --git a/src/runtimes/liboliphaunt/wasix/tools/build-runtime-portable.sh b/src/runtimes/liboliphaunt/wasix/tools/build-runtime-portable.sh
deleted file mode 100755
index 4e634d9c2..000000000
--- a/src/runtimes/liboliphaunt/wasix/tools/build-runtime-portable.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
-root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "unable to determine repository root from $script_dir; run this script from a Git checkout" >&2
-  exit 1
-}
-[ -f "$root/package.json" ] && [ -d "$root/src/runtimes/liboliphaunt/wasix" ] || {
-  echo "must run inside the Oliphaunt workspace" >&2
-  exit 1
-}
-cd "$root"
-
-asset_profile="${ASSET_PROFILE:-release}"
-image="${IMAGE:-oliphaunt-wasix-wasix-build:ci}"
-export IMAGE="$image"
-if [ -z "${DOCKER_CONFIG:-}" ]; then
-  docker_config="$root/target/docker/public-config"
-  mkdir -p "$docker_config"
-  [ -f "$docker_config/config.json" ] || printf '{}\n' >"$docker_config/config.json"
-  if [ -d "$HOME/.docker/cli-plugins" ]; then
-    mkdir -p "$docker_config/cli-plugins"
-    for plugin in "$HOME/.docker/cli-plugins/"*; do
-      [ -e "$plugin" ] || continue
-      ln -sf "$plugin" "$docker_config/cli-plugins/$(basename "$plugin")"
-    done
-  fi
-  export DOCKER_CONFIG="$docker_config"
-fi
-export DOCKER_BUILDKIT="${DOCKER_BUILDKIT:-1}"
-
-cargo run -p xtask --features cluster-seed-runner -- assets release-build \
-  --profile "$asset_profile" \
-  --target-triple x86_64-unknown-linux-gnu \
-  --skip-aot
-
-cargo run -p xtask -- assets check --strict-generated
diff --git a/src/runtimes/liboliphaunt/wasix/tools/cargo-test-filter.sh b/src/runtimes/liboliphaunt/wasix/tools/cargo-test-filter.sh
deleted file mode 100755
index eabc51d07..000000000
--- a/src/runtimes/liboliphaunt/wasix/tools/cargo-test-filter.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-# Cargo treats a test-name filter that matches nothing as success. Runtime
-# smoke lanes must state how many tests they intend to select first.
-oliphaunt_assert_cargo_test_filter_count() {
-  local expected="$1"
-  local filter="$2"
-  shift 2
-
-  local listed_tests
-  local test_count
-  listed_tests="$("$@" -- --list)"
-  test_count="$(awk -v filter="$filter" '
-    index($0, filter) && /: test$/ { count += 1 }
-    END { print count + 0 }
-  ' <<<"$listed_tests")"
-  if [ "$test_count" -ne "$expected" ]; then
-    printf '%s\n' "$listed_tests" >&2
-    echo "expected exactly $expected tests matching $filter, found $test_count" >&2
-    return 1
-  fi
-}
diff --git a/src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs b/src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs
deleted file mode 100755
index 9a421bcac..000000000
--- a/src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs
+++ /dev/null
@@ -1,595 +0,0 @@
-#!/usr/bin/env node
-import {execFileSync} from 'node:child_process';
-import {existsSync, readdirSync, readFileSync, writeFileSync} from 'node:fs';
-import path from 'node:path';
-
-const root = execFileSync('git', ['rev-parse', '--show-toplevel'], {
-  encoding: 'utf8',
-}).trim();
-const mode = process.argv[2] ?? '--check';
-const outputPath = path.join(root, 'docs/internal/WASIX_PATCH_STACK.md');
-const postgresSourceManifestPath = path.join(root, 'src/postgres/versions/18/source.toml');
-const patchSeriesManifestPath = path.join(
-  root,
-  'src/runtimes/liboliphaunt/wasix/assets/build/postgres/source.toml',
-);
-const patchDir = path.join(root, 'src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches');
-const dispositionPath = path.join(
-  root,
-  'src/runtimes/liboliphaunt/wasix/assets/build/postgres/experiment-patch-disposition.toml',
-);
-
-const EXPECTED_AUTHOR = 'Oliphaunt Maintainers ';
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-const EXPECTED_TOUCHPOINTS = new Map([
-  ['src/Makefile.shlib', 'Defines the WASIX dynamic-link shared-library shape.'],
-  ['src/backend/Makefile', 'Builds the dynamic-main backend module without changing other ports.'],
-  ['src/backend/common.mk', 'Scopes scalar atomics to PostgreSQL backend objects instead of PGXS side modules.'],
-  ['src/backend/access/nbtree/nbtdedup.c', 'Keeps btree delete scratch storage on stack under embedded WASIX.'],
-  ['src/backend/access/nbtree/nbtinsert.c', 'Adds the guarded int4 insert fast path.'],
-  ['src/backend/access/nbtree/nbtsearch.c', 'Adds guarded int4 leaf fast paths.'],
-  ['src/backend/access/transam/xact.c', 'Adds top-level current-transaction shortcut for embedded WASIX.'],
-  ['src/backend/access/transam/xlog.c', 'Keeps checkpoint work local, avoids expensive segment division, and exposes only explicit WAL sync operations under embedded WASIX.'],
-  ['src/backend/commands/copyfromparse.c', 'Reports COPY protocol state to the host.'],
-  ['src/backend/commands/copyto.c', 'Reports COPY protocol state to the host.'],
-  ['src/backend/commands/collationcmds.c', 'System-collation import preserves PostgreSQL semantics unless a controlled seed producer suppresses discovery.'],
-  ['src/backend/libpq/be-secure.c', 'Routes embedded protocol reads and writes through host-owned callbacks.'],
-  ['src/backend/libpq/pqcomm.c', 'Skips unavailable postmaster-death wait handles in embedded WASIX.'],
-  ['src/backend/main/main.c', 'Rejects concurrent postmaster and fork-child dispatch in the scalar-atomic runtime.'],
-  ['src/backend/optimizer/plan/planner.c', 'Suppresses activity identifier reporting in embedded WASIX.'],
-  ['src/backend/port/posix_sema.c', 'Uses POSIX semaphore behavior selected by the WASIX template.'],
-  ['src/backend/postmaster/checkpointer.c', 'Keeps checkpoint requests local to embedded WASIX.'],
-  ['src/backend/postmaster/fork_process.c', 'Declares the WASIX fork boundary without enabling postmaster concurrency.'],
-  ['src/backend/replication/walsender.c', 'Suppresses activity identifier reporting in embedded WASIX.'],
-  ['src/backend/storage/file/fd.c', 'Keeps real fsync while narrowing unsupported WASIX directory and writeback-hint behavior.'],
-  ['src/backend/tcop/backend_startup.c', 'Exports the startup packet parser for host-driven startup.'],
-  ['src/backend/tcop/postgres.c', 'Owns embedded lifecycle, protocol loop, and error recovery.'],
-  ['src/backend/utils/adt/like.c', 'Adds guarded LIKE literal fast path for embedded WASIX.'],
-  ['src/backend/utils/adt/like_match.c', 'Adds guarded LIKE literal fast path for embedded WASIX.'],
-  ['src/backend/utils/adt/jsonb.c', 'Caches immutable jsonb_build_object expression metadata while preserving PostgreSQL cast and VARIADIC semantics.'],
-  ['src/backend/utils/init/miscinit.c', 'Routes process identity through the WASIX port layer.'],
-  ['src/backend/utils/init/postinit.c', 'Skips data-directory ownership checks under embedded WASIX.'],
-  ['src/backend/utils/misc/guc.c', 'Uses the embedded WASIX postmaster-style environment.'],
-  ['src/backend/utils/mmgr/portalmem.c', 'Fails active portals on host-forced recovery.'],
-  ['src/bin/initdb/initdb.c', 'Controlled seed producers may suppress host discovery while verified ICU readiness gates the unicode-version probe.'],
-  ['src/bin/pg_dump/connectdb.c', 'Avoids pg_dump LTO symbol collisions.'],
-  ['src/bin/pg_dump/connectdb.h', 'Avoids pg_dump LTO symbol collisions.'],
-  ['src/bin/pg_dump/parallel.c', 'Stubs unavailable pg_dump parallel fork behavior under WASIX.'],
-  ['src/bin/pg_dump/pg_dumpall.c', 'Avoids pg_dump LTO symbol collisions.'],
-  ['src/common/file_utils.c', 'Keeps real fsync while narrowing unsupported WASIX directory and writeback-hint behavior.'],
-  ['src/common/hashfn.c', 'Uses defined unaligned load fast path under WASIX.'],
-  ['src/port/pg_strong_random.c', 'Uses checked direct WASI entropy reads and batches them only for the single-backend runtime.'],
-  ['src/include/libpq/libpq-be.h', 'Adds the host I/O callback table to Port only for embedded WASIX.'],
-  ['src/include/access/xlog.h', 'Exposes the embedded idle-boundary checkpoint handoff within PostgreSQL.'],
-  ['src/include/port/atomics.h', 'Selects scalar atomics only for the explicitly single-backend WASIX build.'],
-  ['src/include/port/atomics/arch-wasix-single.h', 'Preserves PostgreSQL atomic layouts and contracts without guest atomic instructions.'],
-  ['src/include/port/wasix-dl.h', 'Defines the embedded WASIX port header, durability default, ABI redirects, and call-site SJLJ contract.'],
-  ['src/include/port/wasix-dl/sys/ipc.h', 'Provides the WASIX SysV IPC shim surface.'],
-  ['src/include/port/wasix-dl/sys/shm.h', 'Provides the WASIX SysV shared-memory shim surface.'],
-  ['src/include/storage/s_lock.h', 'Specializes spinlocks only for the enforced single-backend WASIX runtime.'],
-  ['src/bin/psql/startup.c', 'Keeps captured Oliphaunt psql invocations noninteractive despite WASIX virtual descriptor types.'],
-  ['src/interfaces/libpq/fe-connect.c', 'Makes libpq socket nonblocking state explicit where WASIX socket creation ignores type flags.'],
-  ['src/makefiles/Makefile.wasix-dl', 'Builds side modules and PGXS artifacts for WASIX dynamic linking.'],
-  ['src/makefiles/pgxs.mk', 'Installs PGXS extension artifacts for WASIX packaging.'],
-  ['src/template/wasix-dl', 'Keeps the WASIX template and atomics invariants source-controlled.'],
-  ['src/test/regress/expected/jsonb.out', 'Records fixed, VARIADIC, Param, null, error, and mutable user-cast JSONB constructor semantics.'],
-  ['src/test/regress/sql/jsonb.sql', 'Covers fixed, VARIADIC, Param, null, error, and mutable user-cast JSONB constructor semantics.'],
-]);
-
-const REQUIRED_AUDIT_CHECKS = [
-  {
-    requirement: 'WASIX dynamic-main build spine is isolated',
-    patches: ['0001-oliphaunt-wasix-add-wasix-dl-build-spine.patch'],
-    evidence: ['PORTNAME), wasix-dl', 'oliphaunt: $(OBJS)'],
-    posture: 'Build plumbing lands before lifecycle behavior, so linker changes are reviewable alone.',
-  },
-  {
-    requirement: 'Backend protocol I/O is host-owned without touching normal sockets',
-    patches: ['0002-oliphaunt-wasix-add-backend-host-io-hooks.patch'],
-    evidence: ['OliphauntWasmHostIO', 'secure_raw_read', 'secure_raw_write'],
-    posture: 'Only OLIPHAUNT_WASM_SINGLE_USER installs the callback table.',
-  },
-  {
-    requirement: 'Startup packet parsing remains PostgreSQL-owned',
-    patches: ['0003-oliphaunt-wasix-export-startup-packet-parser.patch'],
-    evidence: ['ProcessStartupPacket', 'OLIPHAUNT_WASM_HOST_EXPORT("ProcessStartupPacket")'],
-    posture: 'The host can call the parser, but PostgreSQL still validates the startup packet.',
-  },
-  {
-    requirement: 'Host lifecycle exports stay explicit',
-    patches: ['0004-oliphaunt-wasix-add-host-lifecycle-exports.patch'],
-    evidence: ['oliphaunt_wasix_start', 'oliphaunt_wasix_pq_flush', 'oliphaunt_wasix_get_proc_port'],
-    posture: 'Host-visible entry points are named exports instead of broad syscall remaps.',
-  },
-  {
-    requirement: 'Protocol loop recovery remains at the PostgresMain boundary',
-    patches: [
-      '0005-oliphaunt-wasix-add-loop-pumped-protocol-exports.patch',
-      '0019-oliphaunt-wasix-schedule-ready-after-host-recovery.patch',
-      '0020-oliphaunt-wasix-rearm-exception-stack-after-host-recovery.patch',
-    ],
-    evidence: ['PostgresMainLoopOnce', 'PostgresMainLongJmp', 'send_ready_for_query = true'],
-    posture: 'The host pumps PostgreSQL one loop at a time and recovery re-enters the upstream exception stack.',
-  },
-  {
-    requirement: 'COPY protocol state is host-observable',
-    patches: [
-      '0006-oliphaunt-wasix-report-copy-protocol-state.patch',
-      '0008-oliphaunt-wasix-reset-copy-state-on-error-recovery.patch',
-    ],
-    evidence: ['oliphaunt_wasix_protocol_report_copy_response', 'OLIPHAUNT_WASIX_PROTOCOL_COPY_NONE'],
-    posture: 'COPY state is reported and cleared around PostgreSQL error recovery.',
-  },
-  {
-    requirement: 'PGXS side modules use the WASIX dynamic-link contract',
-    patches: [
-      '0007-oliphaunt-wasix-add-wasix-pgxs-side-module-support.patch',
-      '0022-oliphaunt-wasix-use-wasm-ld-for-backend-core.patch',
-    ],
-    evidence: ['PGXS', 'WASM_LD ?= $(shell $(CC) -print-prog-name=wasm-ld)'],
-    posture: 'Extension and backend side-module behavior is source-reviewed with the linker path.',
-  },
-  {
-    requirement: 'Process identity and shared memory stay behind the port header',
-    patches: [
-      '0009-oliphaunt-wasix-route-process-identity-through-port.patch',
-      '0010-oliphaunt-wasix-route-sysv-shmem-through-port.patch',
-      '0011-oliphaunt-wasix-prefer-posix-semaphores.patch',
-    ],
-    evidence: ['oliphaunt_wasix_geteuid', 'oliphaunt_wasix_shmget', 'PREFERRED_SEMAPHORES=UNNAMED_POSIX'],
-    posture: 'WASIX platform gaps are explicit port-layer dependencies, not scattered runtime guesses.',
-  },
-  {
-    requirement: 'Tool/runtime platform stubs fail closed',
-    patches: [
-      '0021-oliphaunt-wasix-declare-wasix-fork.patch',
-      '0025-oliphaunt-wasix-stub-pg-dump-parallel-fork.patch',
-      '0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch',
-    ],
-    evidence: ['fork_process', 'oliphaunt_wasix_pgdump_fork', 'errno == EISDIR'],
-    posture: 'Unavailable WASIX behavior is explicit and narrow instead of silently emulated.',
-  },
-  {
-    requirement: 'Controlled initdb collation discovery',
-    patches: ['0033-oliphaunt-wasix-control-initdb-collation-discovery.patch'],
-    evidence: ['OLIPHAUNT_INTERNAL_ICU_READY', 'OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY', 'OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY', 'strcmp', 'pg_collation_actual_version', 'pg_import_system_collations'],
-    posture: 'Public collation import retains PostgreSQL semantics. Distributed standard seeds suppress OS and ICU discovery; ICU seeds suppress only OS discovery and verify ICU readiness for initdb\'s unicode-version probe.',
-  },
-  {
-    requirement: 'COPY streaming keeps an explicit hybrid transport ABI',
-    patches: ['0034-oliphaunt-wasix-declare-hybrid-protocol-transport.patch'],
-    evidence: [
-      'oliphaunt_wasix_set_protocol_transport(int mode)',
-      'oliphaunt_wasix_protocol_stream_active(void)',
-    ],
-    posture: 'Only COPY switches an embedded host from buffered protocol I/O to its attached stream; Rust and TypeScript provide language-native bounded stream adapters over the same guest ABI.',
-  },
-  {
-    requirement: 'Single-backend WASIX spinlocks preserve their ABI and scope',
-    patches: ['0035-oliphaunt-wasix-use-single-backend-spinlocks.patch'],
-    evidence: [
-      'defined(__wasi__) && defined(OLIPHAUNT_WASM_SINGLE_USER)',
-      'OLIPHAUNT_WASM_SINGLE_BACKEND_ATOMICS',
-      'typedef int slock_t;',
-      'oliphaunt_wasix_single_user_tas',
-    ],
-    posture: 'The shared guest lets Rust AOT and every TypeScript placement replace atomic exchange; all concurrent PostgreSQL builds retain upstream spinlocks.',
-  },
-  {
-    requirement: 'Single-backend WASIX atomics preserve ABI and operation contracts',
-    patches: ['0036-oliphaunt-wasix-specialize-single-backend-atomics.patch'],
-    evidence: [
-      'override CPPFLAGS += -DOLIPHAUNT_WASM_SINGLE_BACKEND_ATOMICS',
-      'postmaster mode is unavailable in the single-backend WASIX runtime',
-      'PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY',
-      'volatile uint64 value pg_attribute_aligned(8)',
-      '*expected = current',
-    ],
-    posture: 'Shared guest backend objects use scalar operations for Rust and TypeScript hosts; frontends, extensions, and every concurrent PostgreSQL build retain normal atomics.',
-  },
-  {
-    requirement: 'WASIX strong randomness avoids descriptor pressure and forked state',
-    patches: ['0037-oliphaunt-wasix-buffer-strong-random.patch'],
-    evidence: [
-      '#elif defined(__wasi__)',
-      'wasix_strong_random_fill(void *buf, size_t len)',
-      '#if defined(OLIPHAUNT_WASM_SINGLE_USER)',
-      'wasix_strong_random_fill(wasix_strong_random_pool',
-      'if (errno == EINTR)',
-      'wasix_strong_random_used += copy_len',
-      'No guest-side state in a process that may fork.',
-    ],
-    posture: 'Every WASIX backend bypasses the virtual random device. The embedded backend amortizes host calls, while fork-capable backends keep no duplicable random state.',
-  },
-  {
-    requirement: 'Unsupported writeback hints stay separate from real durability',
-    patches: ['0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch'],
-    evidence: [
-      '#if defined(OLIPHAUNT_WASM_SINGLE_USER)',
-      'Actual fsync/fdatasync durability remains enabled.',
-      '#elif defined(HAVE_SYNC_FILE_RANGE)',
-    ],
-    posture: 'The single-backend guest omits only pg_flush_data hints that WASIX rejects on read-only descriptors; PostgreSQL fsync and fdatasync remain active.',
-  },
-  {
-    requirement: 'WASIX WAL durability exposes only explicit sync operations',
-    patches: ['0042-oliphaunt-wasix-use-explicit-wal-sync-operations.patch'],
-    evidence: [
-      'PLATFORM_DEFAULT_WAL_SYNC_METHOD',
-      'WAL_SYNC_METHOD_FDATASYNC',
-      'OLIPHAUNT_WASM_EXPLICIT_WAL_SYNC_ONLY',
-      'explicit fd_datasync operation',
-    ],
-    posture: 'The shared PostgreSQL port selects fdatasync and removes open_sync/open_datasync from the WASIX GUC choices because Wasmer does not honor their open flags.',
-  },
-  {
-    requirement: 'Fixed JSONB constructor metadata preserves PostgreSQL semantics',
-    patches: ['0043-oliphaunt-wasix-cache-jsonb-build-object-metadata.patch'],
-    evidence: [
-      'JsonbBuildObjectState',
-      'get_fn_expr_variadic',
-      'FirstNormalObjectId',
-      'jsonb_build_object_cache_drop_cast',
-    ],
-    posture: 'Ordinary calls reuse immutable expression metadata; explicit VARIADIC arrays keep the generic path and user-defined types are recategorized so cast DDL remains visible.',
-  },
-  {
-    requirement: 'PostgreSQL side modules own their SJLJ catch frames',
-    patches: ['0039-oliphaunt-wasix-inline-sigsetjmp.patch'],
-    evidence: [
-      '-DOLIPHAUNT_WASM_SIDE_MODULE',
-      'WebAssembly SJLJ requires setjmp to be visible at the protected call site.',
-      'defined(__wasm_exception_handling__) && defined(OLIPHAUNT_WASM_SIDE_MODULE)',
-      '#undef sigsetjmp',
-      '#define sigsetjmp(env, savesigs) ((void) (savesigs), setjmp(env))',
-    ],
-    posture: 'PG_TRY expands to a compiler-recognized setjmp in every PostgreSQL side module, so nested errors unwind to the live module-local handler.',
-  },
-  {
-    requirement: 'Standalone WASIX libpq sockets are actually nonblocking',
-    patches: ['0040-oliphaunt-wasix-set-libpq-sockets-nonblocking.patch'],
-    evidence: [
-      'defined(SOCK_NONBLOCK) && !defined(__wasi__)',
-      '!defined(SOCK_NONBLOCK) || defined(__wasi__)',
-      'pg_set_noblock(conn->sock)',
-    ],
-    posture: 'WASIX uses PostgreSQL\'s existing fcntl fallback because Wasmer ignores socket type flags; native platforms retain upstream atomic socket creation.',
-  },
-  {
-    requirement: 'Captured Oliphaunt psql scripts remain noninteractive',
-    patches: ['0041-oliphaunt-wasix-honor-noninteractive-psql-invocations.patch'],
-    evidence: [
-      'OLIPHAUNT_PSQL_NONINTERACTIVE',
-      'strcmp(oliphaunt_noninteractive, "1") == 0',
-      '!isatty(fileno(stdin)) || !isatty(fileno(stdout))',
-    ],
-    posture: 'Only the private exact-value marker overrides virtual terminal detection; ordinary WASIX psql retains upstream isatty semantics.',
-  },
-];
-
-if (!['--check', '--write'].includes(mode)) {
-  console.error('usage: src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs [--check|--write]');
-  process.exit(2);
-}
-
-function read(relativePath) {
-  return readFileSync(path.join(root, relativePath), 'utf8');
-}
-
-function matchRequired(text, pattern, label) {
-  const match = text.match(pattern);
-  if (!match) {
-    throw new Error(`missing ${label}`);
-  }
-  return match[1];
-}
-
-function parseSourceManifest() {
-  const postgresText = readFileSync(postgresSourceManifestPath, 'utf8');
-  const seriesText = readFileSync(patchSeriesManifestPath, 'utf8');
-  const version = matchRequired(postgresText, /version\s*=\s*"([^"]+)"/u, 'postgresql.version');
-  const url = matchRequired(postgresText, /url\s*=\s*"([^"]+)"/u, 'postgresql.url');
-  const sha256 = matchRequired(postgresText, /sha256\s*=\s*"([^"]+)"/u, 'postgresql.sha256');
-  const seriesBlock = matchRequired(seriesText, /series\s*=\s*\[([\s\S]*?)\]/u, 'patches.series');
-  const series = Array.from(seriesBlock.matchAll(/"([^"]+\.patch)"/gu), match => match[1]);
-  if (series.length === 0) {
-    throw new Error('WASIX source.toml patch series is empty');
-  }
-  return {version, url, sha256, series};
-}
-
-function patchFiles() {
-  return readdirSync(patchDir)
-    .filter(name => name.endsWith('.patch'))
-    .sort(compareText);
-}
-
-function parsePatch(fileName) {
-  const relativePath = `src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/${fileName}`;
-  const text = read(relativePath);
-  const author = text.match(/^From:\s+(.+)$/mu)?.[1];
-  if (author !== EXPECTED_AUTHOR) {
-    throw new Error(`${relativePath} From: header must be "${EXPECTED_AUTHOR}", got ${author ?? ''}`);
-  }
-  const subject = text.match(/^Subject:\s+\[PATCH\]\s+(.+)$/mu)?.[1];
-  if (!subject?.startsWith('oliphaunt-wasix: ')) {
-    throw new Error(`${relativePath} subject must start with "oliphaunt-wasix: "`);
-  }
-  const changedFiles = Array.from(
-    text.matchAll(/^diff --git a\/(.+?) b\/(.+)$/gmu),
-    match => match[2],
-  );
-  if (changedFiles.length === 0) {
-    throw new Error(`${relativePath} does not contain any diff --git file entries`);
-  }
-  const prefix = `${String(Number(fileName.slice(0, 4))).padStart(4, '0')}-oliphaunt-wasix-`;
-  if (!fileName.startsWith(prefix)) {
-    throw new Error(`${relativePath} must use sequential prefix ${prefix}`);
-  }
-  if (/\b(TODO|FIXME)\b/u.test(text)) {
-    throw new Error(`${relativePath} must not carry TODO/FIXME placeholders`);
-  }
-
-  const diffStart = text
-    .indexOf('\ndiff --git ');
-  if (diffStart === -1) {
-    throw new Error(`${relativePath} is missing a diff body`);
-  }
-  const rationaleCount = countRationaleLines(text.slice(0, diffStart));
-  if (rationaleCount < 2) {
-    throw new Error(`${relativePath} must include a short rationale before the diff`);
-  }
-
-  const whitespaceProblems = [];
-  const symbols = new Set();
-  for (const [index, line] of text.split('\n').entries()) {
-    if (!line.startsWith('+') || line.startsWith('+++')) {
-      continue;
-    }
-    if (line !== '+' && /[ \t]$/u.test(line)) {
-      whitespaceProblems.push(`${index + 1}: ${line}`);
-    }
-    if (/^\+ \t/u.test(line)) {
-      whitespaceProblems.push(`${index + 1}: ${line}`);
-    }
-    for (const symbol of line.matchAll(/\b(oliphaunt_wasix_[A-Za-z0-9_]+|OLIPHAUNT_WASM_[A-Za-z0-9_]+|PostgresMainLoopOnce|PostgresMainLongJmp|ProcessStartupPacket)\b/gu)) {
-      symbols.add(symbol[1]);
-    }
-  }
-  if (whitespaceProblems.length > 0) {
-    throw new Error(
-      `${relativePath} contains whitespace problems in added PostgreSQL code:\n${whitespaceProblems.join('\n')}`,
-    );
-  }
-
-  return {
-    fileName,
-    relativePath,
-    text,
-    author,
-    subject,
-    changedFiles,
-    symbols: Array.from(symbols).sort(compareText),
-  };
-}
-
-function countRationaleLines(headerText) {
-  return headerText
-    .split('\n')
-    .slice(headerText.split('\n').findIndex(line => line.startsWith('Subject: ')) + 1)
-    .filter(line => {
-      const trimmed = line.trim();
-      return trimmed !== '' && !trimmed.startsWith('---') && !trimmed.startsWith('From:') && !trimmed.startsWith('Date:');
-    })
-    .length;
-}
-
-function parseDisposition() {
-  const text = readFileSync(dispositionPath, 'utf8');
-  const policy = matchRequired(text, /policy\s*=\s*"([^"]+)"/u, 'experiment disposition policy');
-  const entries = text
-    .split(/\n\[\[patch\]\]\n/u)
-    .slice(1)
-    .map(block => ({
-      experiment: matchRequired(block, /experiment\s*=\s*"([^"]+)"/u, 'experiment'),
-      status: matchRequired(block, /status\s*=\s*"([^"]+)"/u, 'status'),
-      decision: matchRequired(block, /wasix_runtime_decision\s*=\s*"([^"]+)"/u, 'wasix_runtime_decision'),
-      rationale: matchRequired(block, /rationale\s*=\s*"([^"]+)"/u, 'rationale'),
-    }));
-  if (policy !== 'do-not-port-experiment-patches-without-a-recorded-wasix-runtime-rationale') {
-    throw new Error(`unexpected experiment disposition policy: ${policy}`);
-  }
-  if (entries.length === 0) {
-    throw new Error('experiment disposition must record at least one patch');
-  }
-  const seen = new Set();
-  for (const entry of entries) {
-    if (seen.has(entry.experiment)) {
-      throw new Error(`duplicate experiment disposition for ${entry.experiment}`);
-    }
-    seen.add(entry.experiment);
-    for (const field of ['decision', 'rationale']) {
-      if (entry[field].trim().length < 8) {
-        throw new Error(`experiment ${entry.experiment} has an under-specified ${field}`);
-      }
-    }
-  }
-  return {policy, entries};
-}
-
-function validateSeries(manifest, actualFiles) {
-  if (JSON.stringify(manifest.series) !== JSON.stringify(actualFiles)) {
-    throw new Error(
-      `WASIX source.toml patch series must exactly match patch directory files\nexpected:\n${manifest.series.join('\n')}\nactual:\n${actualFiles.join('\n')}`,
-    );
-  }
-  manifest.series.forEach((fileName, index) => {
-    const expectedPrefix = `${String(index + 1).padStart(4, '0')}-oliphaunt-wasix-`;
-    if (!fileName.startsWith(expectedPrefix)) {
-      throw new Error(`${fileName} must use sequential prefix ${expectedPrefix}`);
-    }
-  });
-}
-
-function validateTouchpoints(patches) {
-  const actual = new Set(patches.flatMap(patch => patch.changedFiles));
-  const expected = new Set(EXPECTED_TOUCHPOINTS.keys());
-  const missing = [...expected].filter(file => !actual.has(file));
-  const extra = [...actual].filter(file => !expected.has(file));
-  if (missing.length > 0 || extra.length > 0) {
-    throw new Error(
-      `WASIX patch touchpoints changed; update ${path.relative(root, outputPath)} and src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs\nmissing:\n${missing.join('\n') || ''}\nextra:\n${extra.join('\n') || ''}`,
-    );
-  }
-}
-
-function validateAuditChecks(patches) {
-  const byName = new Map(patches.map(patch => [patch.fileName, patch]));
-  for (const check of REQUIRED_AUDIT_CHECKS) {
-    const text = check.patches
-      .map(fileName => {
-        const patch = byName.get(fileName);
-        if (!patch) {
-          throw new Error(`audit check "${check.requirement}" references missing patch ${fileName}`);
-        }
-        return patch.text;
-      })
-      .join('\n');
-    for (const evidence of check.evidence) {
-      if (!text.includes(evidence)) {
-        throw new Error(`audit check "${check.requirement}" is missing evidence ${evidence}`);
-      }
-    }
-  }
-}
-
-function render() {
-  const manifest = parseSourceManifest();
-  const actualFiles = patchFiles();
-  validateSeries(manifest, actualFiles);
-  const patches = actualFiles.map(parsePatch);
-  validateTouchpoints(patches);
-  validateAuditChecks(patches);
-  const disposition = parseDisposition();
-
-  const changedFiles = new Map();
-  for (const patch of patches) {
-    for (const changed of patch.changedFiles) {
-      if (!changedFiles.has(changed)) {
-        changedFiles.set(changed, []);
-      }
-      changedFiles.get(changed).push(patch.fileName);
-    }
-  }
-
-  const symbols = new Map();
-  for (const patch of patches) {
-    for (const symbol of patch.symbols) {
-      if (!symbols.has(symbol)) {
-        symbols.set(symbol, []);
-      }
-      symbols.get(symbol).push(patch.fileName);
-    }
-  }
-
-  const lines = [];
-  lines.push('');
-  lines.push('# oliphaunt-wasix PostgreSQL 18 WASIX Patch Stack Review');
-  lines.push('');
-  lines.push('This source-only review artifact keeps the WASIX PostgreSQL patch stack deterministic and reviewable without rebuilding PostgreSQL.');
-  lines.push('');
-  lines.push('Regenerate with:');
-  lines.push('');
-  lines.push('```sh');
-  lines.push('src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs --write');
-  lines.push('```');
-  lines.push('');
-  lines.push('## Source Pin');
-  lines.push('');
-  lines.push(`- PostgreSQL: \`${manifest.version}\``);
-  lines.push(`- URL: \`${manifest.url}\``);
-  lines.push(`- SHA-256: \`${manifest.sha256}\``);
-  lines.push(`- Patch directory: \`src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches\``);
-  lines.push(`- Experiment disposition policy: \`${disposition.policy}\``);
-  lines.push('');
-  lines.push('## Patch Series');
-  lines.push('');
-  lines.push('| Order | Patch | Author | Subject |');
-  lines.push('| --- | --- | --- | --- |');
-  patches.forEach((patch, index) => {
-    lines.push(`| ${index + 1} | \`${patch.fileName}\` | ${patch.author} | ${patch.subject} |`);
-  });
-  lines.push('');
-  lines.push('## Changed Upstream Files');
-  lines.push('');
-  lines.push('| File | Owning Patch(es) | Rationale |');
-  lines.push('| --- | --- | --- |');
-  for (const [file, patchNames] of [...changedFiles.entries()].sort((a, b) => compareText(a[0], b[0]))) {
-    lines.push(
-      `| \`${file}\` | ${patchNames.map(name => `\`${name}\``).join(', ')} | ${EXPECTED_TOUCHPOINTS.get(file)} |`,
-    );
-  }
-  lines.push('');
-  lines.push('## Audit Checklist');
-  lines.push('');
-  lines.push('| Requirement | Owning Patch(es) | Required Evidence | Review Posture |');
-  lines.push('| --- | --- | --- | --- |');
-  for (const check of REQUIRED_AUDIT_CHECKS) {
-    lines.push(
-      `| ${check.requirement} | ${check.patches.map(name => `\`${name}\``).join(', ')} | ${check.evidence.map(evidence => `\`${evidence}\``).join(', ')} | ${check.posture} |`,
-    );
-  }
-  lines.push('');
-  lines.push('## PostgreSQL Patch Symbols');
-  lines.push('');
-  for (const [symbol, patchNames] of [...symbols.entries()].sort((a, b) => compareText(a[0], b[0]))) {
-    lines.push(`- \`${symbol}\` (${patchNames.map(name => `\`${name}\``).join(', ')})`);
-  }
-  lines.push('');
-  lines.push('## Experiment Patch Disposition');
-  lines.push('');
-  lines.push('| Experiment Patch | Status | WASIX Runtime Decision | Rationale |');
-  lines.push('| --- | --- | --- | --- |');
-  for (const entry of disposition.entries) {
-    lines.push(`| \`${entry.experiment}\` | \`${entry.status}\` | ${entry.decision} | ${entry.rationale} |`);
-  }
-  lines.push('');
-  lines.push('## Guardrails');
-  lines.push('');
-  lines.push('- `source.toml` patch series exactly matches the patch directory.');
-  lines.push('- Every patch has a deterministic `From: Oliphaunt Maintainers ` header.');
-  lines.push('- Every patch has a deterministic `Subject: [PATCH] oliphaunt-wasix: ...` header and a rationale before the diff.');
-  lines.push('- Added PostgreSQL lines are checked for trailing whitespace and space-before-tab indentation.');
-  lines.push('- Changed upstream files must exactly match the expected touchpoint table above; new upstream touchpoints need an explicit rationale before landing.');
-  lines.push('- Required audit checks prove their evidence in the named owning patch or patches.');
-  lines.push('- Experiment patches can only be ported, rejected, or replaced with a recorded WASIX runtime decision and rationale.');
-  lines.push('');
-  return lines.join('\n');
-}
-
-function normalizeGeneratedMarkdown(text) {
-  return text.replace(/\r\n/gu, '\n').replace(/\r/gu, '\n').trimEnd();
-}
-
-try {
-  const rendered = render();
-  if (mode === '--write') {
-    writeFileSync(outputPath, rendered, 'utf8');
-  } else {
-    if (!existsSync(outputPath)) {
-      throw new Error(`${path.relative(root, outputPath)} is missing; run src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs --write`);
-    }
-    const actual = readFileSync(outputPath, 'utf8');
-    if (normalizeGeneratedMarkdown(actual) !== normalizeGeneratedMarkdown(rendered)) {
-      throw new Error(`${path.relative(root, outputPath)} is stale; run src/runtimes/liboliphaunt/wasix/tools/check-patch-stack.mjs --write`);
-    }
-  }
-  console.log('WASIX patch stack review artifact is current');
-} catch (error) {
-  console.error(error instanceof Error ? error.message : error);
-  process.exit(1);
-}
diff --git a/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh b/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh
deleted file mode 100644
index 720b2cea9..000000000
--- a/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env sh
-
-oliphaunt_runtime_wasm_host_triple() {
-  rustc -vV | awk '/^host:/{print $2}'
-}
-
-oliphaunt_runtime_wasm_asset_mode() {
-  command -v bun >/dev/null 2>&1 || {
-    echo "Bun is required to inspect target/oliphaunt-wasix/assets/manifest.json" >&2
-    return 1
-  }
-  bun --eval '
-const manifest = await Bun.file("target/oliphaunt-wasix/assets/manifest.json").json();
-const present = (value) => value !== null && value !== undefined && value !== false
-  && (!Array.isArray(value) || value.length > 0)
-  && (typeof value !== "string" || value.length > 0)
-  && (typeof value !== "number" || value !== 0)
-  && (typeof value !== "object" || Array.isArray(value) || Object.keys(value).length > 0);
-console.log(present(manifest.extensions) && present(manifest["pg-dump"]) && present(manifest.psql) ? "full" : "core");
-'
-}
-
-oliphaunt_runtime_wasm_require() {
-  oliphaunt_runtime_mode="${1:-smoke}"
-  oliphaunt_runtime_host="$(oliphaunt_runtime_wasm_host_triple)"
-  [ -f "target/oliphaunt-wasix/assets/manifest.json" ] || {
-    echo "missing generated portable WASIX assets at target/oliphaunt-wasix/assets" >&2
-    return 1
-  }
-  [ -f "target/oliphaunt-wasix/aot/$oliphaunt_runtime_host/manifest.json" ] ||
-    [ -f "src/runtimes/liboliphaunt/wasix/crates/aot/$oliphaunt_runtime_host/artifacts/manifest.json" ] || {
-      echo "missing host WASIX AOT artifacts for $oliphaunt_runtime_host" >&2
-      return 1
-    }
-  oliphaunt_runtime_asset_mode="$(oliphaunt_runtime_wasm_asset_mode)"
-  if [ "$oliphaunt_runtime_asset_mode" = "core" ]; then
-    [ "$oliphaunt_runtime_mode" != "regression" ] || {
-      echo "full WASIX assets are required for liboliphaunt-wasix:regression" >&2
-      return 1
-    }
-    export OLIPHAUNT_WASM_SKIP_EXTENSIONS_FOR_PERF=1
-  fi
-  export OLIPHAUNT_RUNTIME_WASM_ASSET_MODE="$oliphaunt_runtime_asset_mode"
-}
diff --git a/src/runtimes/liboliphaunt/wasix/tools/runtime-smoke.sh b/src/runtimes/liboliphaunt/wasix/tools/runtime-smoke.sh
deleted file mode 100755
index ee4ffa15b..000000000
--- a/src/runtimes/liboliphaunt/wasix/tools/runtime-smoke.sh
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
-root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "unable to determine repository root from $script_dir; run this script from a Git checkout" >&2
-  exit 1
-}
-[ -f "$root/package.json" ] && [ -d "$root/src/runtimes/liboliphaunt/wasix" ] || {
-  echo "must run inside the Oliphaunt workspace" >&2
-  exit 1
-}
-cd "$root"
-
-. "$root/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh"
-. "$root/src/runtimes/liboliphaunt/wasix/tools/cargo-test-filter.sh"
-
-mode="${1:-smoke}"
-case "$mode" in
-  smoke|regression|core-smoke)
-    ;;
-  *)
-    echo "usage: src/runtimes/liboliphaunt/wasix/tools/runtime-smoke.sh [smoke|regression|core-smoke]" >&2
-    exit 2
-    ;;
-esac
-
-host="$(oliphaunt_runtime_wasm_host_triple)"
-preflight_mode="$mode"
-if [ "$mode" = "core-smoke" ]; then
-  preflight_mode="smoke"
-fi
-oliphaunt_runtime_wasm_require "$preflight_mode"
-if [ "$mode" = "core-smoke" ]; then
-  export OLIPHAUNT_RUNTIME_WASM_ASSET_MODE="core"
-fi
-asset_mode="$OLIPHAUNT_RUNTIME_WASM_ASSET_MODE"
-full_evidence_features=""
-if [ "$asset_mode" = "full" ]; then
-  full_evidence_features="$(
-    tools/dev/bun.sh tools/release/wasix-extension-features.mjs \
-      "$root/target/oliphaunt-wasix/assets/manifest.json"
-  )"
-fi
-
-oliphaunt_wasix_cargo_test() {
-  if [ "$asset_mode" = "full" ]; then
-    # Full evidence enables every catalogued extension plus the tool features
-    # needed by the separate extension and logical dump/restore proofs below.
-    cargo test -p oliphaunt-wasix --locked --no-default-features \
-      --features "$full_evidence_features" "$@"
-  else
-    cargo test -p oliphaunt-wasix --locked --no-default-features "$@"
-  fi
-}
-
-oliphaunt_wasix_counted_library_tests() {
-  local expected="$1"
-  local filter="$2"
-  local command=(oliphaunt_wasix_cargo_test --lib "$filter")
-  oliphaunt_assert_cargo_test_filter_count "$expected" "$filter" "${command[@]}"
-  "${command[@]}" -- --nocapture --test-threads=1
-}
-
-cargo run -p xtask -- assets install-local --target-triple "$host"
-if [ "$mode" = "core-smoke" ]; then
-  # Validate the installed AOT manifest against the asset set that actually
-  # produced it, then narrow only the smoke workload. A full manifest still
-  # contains the split pg_dump/psql tools even when this run skips their tests.
-  export OLIPHAUNT_WASM_SKIP_EXTENSIONS_FOR_PERF=1
-fi
-export OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR="$root/target/oliphaunt-wasix/assets"
-export OLIPHAUNT_WASM_GENERATED_AOT_DIR="$root/target/oliphaunt-wasix/aot"
-export RUST_BACKTRACE="${RUST_BACKTRACE:-full}"
-
-oliphaunt_wasix_cargo_test \
-  --test runtime_smoke \
-  --test proxy_smoke \
-  --test cli_smoke \
-  --test extensions_smoke \
-  --test postgres_regression \
-  -- --nocapture --test-threads=1
-if [ "$asset_mode" = "full" ]; then
-  # The three exhaustive tests cover every catalogued extension through direct,
-  # restart, server, and materialization paths. Logical dump/restore is a
-  # separate shared-fixture proof below; it does not claim every extension.
-  oliphaunt_wasix_counted_library_tests 3 extension_tests::public_extensions
-  if [ "$mode" = "regression" ]; then
-    oliphaunt_wasix_cargo_test --test client_compat -- --nocapture --test-threads=1
-  fi
-  tools_filter="oliphaunt::tools::tests::public_tools_round_trip_shared_logical_fixture"
-  tools_command=(oliphaunt_wasix_cargo_test --lib "$tools_filter")
-  oliphaunt_assert_cargo_test_filter_count 1 "$tools_filter" "${tools_command[@]}"
-  "${tools_command[@]}" -- --exact --nocapture --test-threads=1
-else
-  echo "core-only WASIX assets detected; skipping extension and frontend-tool smoke tests"
-fi
diff --git a/src/runtimes/liboliphaunt/wasix/tools/verify-committed-assets.sh b/src/runtimes/liboliphaunt/wasix/tools/verify-committed-assets.sh
deleted file mode 100755
index 63852e37b..000000000
--- a/src/runtimes/liboliphaunt/wasix/tools/verify-committed-assets.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "verify-committed-assets.sh: must run inside the Oliphaunt checkout" >&2
-  exit 1
-}
-cd "$root"
-
-if [ "${CI:-}" = "true" ]; then
-  cargo run -p xtask -- assets fetch
-fi
-src/runtimes/liboliphaunt/wasix/assets/build/prepare_postgres_source.sh >/dev/null
-cargo run -p xtask -- assets verify-committed
diff --git a/src/runtimes/node-direct/CHANGELOG.md b/src/runtimes/node-direct/CHANGELOG.md
deleted file mode 100644
index b53f02ca7..000000000
--- a/src/runtimes/node-direct/CHANGELOG.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# Changelog
-
-## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-node-direct-v0.1.1...oliphaunt-node-direct-v0.2.0) (2026-09-05)
-
-
-### ⚠ BREAKING CHANGES
-
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
-
-### Features
-
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))
-* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
-
-
-### Code Refactoring
-
-* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
-* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
-
-## 0.1.1
-
-### Dependencies
-
-* **dependencies:** align with `liboliphaunt-native` 0.1.1 (release compatibility field `oliphaunt-node-direct-liboliphaunt`)
-* **dependencies:** align with `liboliphaunt-native` 0.1.1 (Moon production dependency: `liboliphaunt-native` -> `oliphaunt-node-direct`)
-
-## 0.1.0 (2026-07-28)
-
-
-### Features
-
-* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/runtimes/node-direct/README.md b/src/runtimes/node-direct/README.md
deleted file mode 100644
index 0c2a2e015..000000000
--- a/src/runtimes/node-direct/README.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Oliphaunt Node Direct Runtime
-
-`oliphaunt-node-direct` owns the Node-API adapter that lets the TypeScript SDK
-call the native `liboliphaunt` runtime without compiling native code during a
-normal application install.
-
-Published consumer packages are platform-specific optional npm packages:
-
-- `@oliphaunt/node-direct-darwin-arm64`
-- `@oliphaunt/node-direct-linux-x64-gnu`
-- `@oliphaunt/node-direct-linux-arm64-gnu`
-- `@oliphaunt/node-direct-win32-x64-msvc`
-
-The TypeScript SDK selects the matching optional package. Missing packages fail
-with an install-time action instead of downloading runtime assets.
-
-Native database calls run on addon-owned background threads and return to
-JavaScript through bounded Node-API thread-safe-function bridges. Environment
-cleanup first aborts those JavaScript delivery bridges and waits only for a
-producer already inside Node-API to observe that abort. An asynchronous reaper
-then cancels the resident backend, waits for every registered native call
-(including one whose thread has not started yet), and terminally closes only
-the generation owned by that environment. It marshals final cleanup-hook
-removal back to Node's event-loop thread. Cleanup never waits for a promise
-completion or runs PostgreSQL teardown on Node's environment thread.
diff --git a/src/runtimes/node-direct/moon.yml b/src/runtimes/node-direct/moon.yml
deleted file mode 100644
index 46411de3e..000000000
--- a/src/runtimes/node-direct/moon.yml
+++ /dev/null
@@ -1,63 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "oliphaunt-node-direct"
-language: "typescript"
-layer: "library"
-stack: "systems"
-tags: ["runtime", "node", "native", "node-api", "release-product"]
-dependsOn:
-  - "liboliphaunt-native"
-
-project:
-  title: "Oliphaunt Node Direct Runtime"
-  description: "Node-API native direct addon runtime consumed by the TypeScript SDK."
-  owner: "oliphaunt"
-  release:
-    component: "oliphaunt-node-direct"
-    packagePath: "src/runtimes/node-direct"
-    artifactTargets:
-      preset: "node-direct-addon"
-      targets:
-        - "linux-arm64-gnu"
-        - "linux-x64-gnu"
-        - "macos-arm64"
-        - "windows-x64-msvc"
-
-owners:
-  defaultOwner: "@oliphaunt/node-direct"
-
-fileGroups:
-  code:
-    - "native/**/*"
-    - "tools/**/*"
-    - "package.json"
-
-tasks:
-  compile:
-    tags: ["quality", "static"]
-    command: "bash tools/check-native-source.sh"
-    inputs:
-      - "native/**/*"
-      - "tools/check-native-source.sh"
-      - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
-      - "@group(pnpm-workspace)"
-    options:
-      cache: true
-
-  unit:
-    tags: ["quality", "unit"]
-    command: "bash tools/test-node-addon-cleanup-lifecycle.sh --test-path-classifier"
-    inputs:
-      - "tools/test-node-addon-cleanup-lifecycle.sh"
-    options:
-      cache: true
-
-  qualify:
-    tags: ["release"]
-    command: "true"
-    deps:
-      - "oliphaunt-node-direct:compile"
-      - "oliphaunt-node-direct:unit"
-    inputs: []
-    options:
-      cache: true
diff --git a/src/runtimes/node-direct/native/node-addon/oliphaunt_node.cc b/src/runtimes/node-direct/native/node-addon/oliphaunt_node.cc
deleted file mode 100644
index 5db307e29..000000000
--- a/src/runtimes/node-direct/native/node-addon/oliphaunt_node.cc
+++ /dev/null
@@ -1,2444 +0,0 @@
-#include 
-#include "oliphaunt.h"
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-#include 
-#include 
-#endif
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#if defined(_WIN32)
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif
-#include 
-#else
-#include 
-#endif
-
-namespace {
-
-using InitFn = int32_t (*)(const OliphauntConfig *, OliphauntHandle **);
-using ExecProtocolFn = int32_t (*)(OliphauntHandle *, const uint8_t *, size_t, OliphauntResponse *);
-using ExecSimpleQueryFn = int32_t (*)(OliphauntHandle *, const char *, size_t, OliphauntResponse *);
-using ExecProtocolRawStreamFn = decltype(&oliphaunt_exec_protocol_raw_stream);
-using BackupFn = decltype(&oliphaunt_backup);
-using RestoreFn = int32_t (*)(const OliphauntRestoreOptions *);
-using CancelFn = int32_t (*)(OliphauntHandle *);
-using DetachFn = int32_t (*)(OliphauntHandle *);
-using LogicalGenerationFn = uint64_t (*)(OliphauntHandle *);
-using CloseIfGenerationFn = int32_t (*)(uint64_t);
-using CopyLastErrorFn = size_t (*)(OliphauntHandle *, char *, size_t);
-using VersionFn = const char *(*)();
-using FreeResponseFn = void (*)(OliphauntResponse *);
-
-struct DynamicLibrary {
-#if defined(_WIN32)
-  HMODULE handle = nullptr;
-#else
-  void *handle = nullptr;
-#endif
-};
-
-struct NativeLibrary {
-  DynamicLibrary library;
-  InitFn init = nullptr;
-  ExecProtocolFn exec_protocol = nullptr;
-  ExecSimpleQueryFn exec_simple_query = nullptr;
-  ExecProtocolRawStreamFn exec_protocol_raw_stream = nullptr;
-  BackupFn backup = nullptr;
-  RestoreFn restore = nullptr;
-  CancelFn cancel = nullptr;
-  DetachFn detach = nullptr;
-  LogicalGenerationFn logical_generation = nullptr;
-  CloseIfGenerationFn close_if_generation = nullptr;
-  CopyLastErrorFn copy_last_error = nullptr;
-  VersionFn version = nullptr;
-  FreeResponseFn free_response = nullptr;
-  // JavaScript close is intentionally a logical detach so a direct backend can
-  // be reopened. Keep its process-resident handle until the owning Node
-  // environment performs the one terminal close.
-  std::mutex lifecycle_mutex;
-  OliphauntHandle *resident_handle = nullptr;
-  uint64_t resident_generation = 0;
-  napi_env owner_env = nullptr;
-  bool detach_pending = false;
-  bool terminally_closed = false;
-};
-
-struct NativeHandleBox {
-  std::shared_ptr library;
-  OliphauntHandle *handle = nullptr;
-  uint64_t generation = 0;
-  bool detached = false;
-};
-
-constexpr uint64_t kForgottenHandleRecoveryTokenMagic =
-    UINT64_C(0x4f4c495048524543);
-
-struct ForgottenHandleRecoveryToken {
-  uint64_t magic = kForgottenHandleRecoveryTokenMagic;
-  std::shared_ptr library;
-  uint64_t generation = 0;
-};
-
-std::mutex g_libraries_mutex;
-std::map> g_libraries;
-
-struct EnvironmentOperation;
-
-struct AddonEnvironment {
-  napi_env env = nullptr;
-  std::mutex mutex;
-  std::condition_variable condition;
-  size_t pending_operations = 0;
-  size_t pending_native_call_entries = 0;
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-  size_t cleanup_cancel_attempts = 0;
-#endif
-  bool shutting_down = false;
-  bool quiesce_hook_registered = false;
-  napi_async_cleanup_hook_handle async_cleanup_handle = nullptr;
-  // Created by the async cleanup hook itself, after ordinary environment
-  // resources have quiesced. The reaper uses it solely to finish cleanup on
-  // Node's event-loop thread.
-  napi_threadsafe_function cleanup_completion = nullptr;
-  bool cleanup_completion_call_returned = false;
-};
-
-struct EnvironmentOperation {
-  AddonEnvironment *environment = nullptr;
-  std::atomic registered = false;
-  std::atomic started = false;
-  // Guarded by AddonEnvironment::mutex. Once set, cleanup must not issue its
-  // cancellation attempt until this worker has crossed the native-call entry
-  // boundary or retired the operation.
-  bool native_call_entry_pending = false;
-};
-
-struct ThreadsafeBridge {
-  napi_threadsafe_function function = nullptr;
-  std::mutex release_mutex;
-  std::condition_variable release_condition;
-  size_t active_calls = 0;
-  bool acquisition_released = false;
-  std::atomic aborted = false;
-};
-
-std::mutex g_environments_mutex;
-std::map g_environments;
-std::mutex g_threadsafe_bridges_mutex;
-std::map>>
-    g_threadsafe_bridges;
-
-void Throw(napi_env env, const std::string &message);
-void QuiesceEnvironment(void *data);
-void CompleteEnvironmentCleanup(
-    napi_env env,
-    napi_value callback,
-    void *context,
-    void *data);
-
-AddonEnvironment *LookupEnvironment(napi_env env) {
-  std::lock_guard guard(g_environments_mutex);
-  auto entry = g_environments.find(env);
-  return entry == g_environments.end() ? nullptr : entry->second;
-}
-
-bool RegisterEnvironmentOperation(
-    napi_env env,
-    EnvironmentOperation *operation) {
-  AddonEnvironment *environment = LookupEnvironment(env);
-  if (environment == nullptr) {
-    Throw(env, "Oliphaunt native environment is unavailable");
-    return false;
-  }
-  std::lock_guard guard(environment->mutex);
-  if (environment->shutting_down) {
-    Throw(env, "Oliphaunt native environment is shutting down");
-    return false;
-  }
-  environment->pending_operations++;
-  operation->environment = environment;
-  operation->registered.store(true);
-  return true;
-}
-
-void FinishEnvironmentOperation(EnvironmentOperation *operation) {
-  if (operation == nullptr || !operation->registered.exchange(false)) {
-    return;
-  }
-  AddonEnvironment *environment = operation->environment;
-  std::lock_guard guard(environment->mutex);
-  if (operation->native_call_entry_pending) {
-    operation->native_call_entry_pending = false;
-    if (environment->pending_native_call_entries > 0) {
-      environment->pending_native_call_entries--;
-    }
-  }
-  if (environment->pending_operations > 0) {
-    environment->pending_operations--;
-  }
-  environment->condition.notify_all();
-}
-
-void StartEnvironmentOperation(EnvironmentOperation *operation) {
-  operation->started.store(true);
-}
-
-bool EnvironmentIsShuttingDown(const EnvironmentOperation *operation) {
-  AddonEnvironment *environment = operation->environment;
-  if (environment == nullptr) {
-    return true;
-  }
-  std::lock_guard guard(environment->mutex);
-  return environment->shutting_down;
-}
-
-bool AdmitEnvironmentNativeCall(EnvironmentOperation *operation) {
-  AddonEnvironment *environment = operation->environment;
-  if (environment == nullptr) {
-    return false;
-  }
-  std::lock_guard guard(environment->mutex);
-  if (environment->shutting_down) {
-    return false;
-  }
-  operation->native_call_entry_pending = true;
-  environment->pending_native_call_entries++;
-  environment->condition.notify_all();
-  return true;
-}
-
-void MarkEnvironmentNativeCallEntered(EnvironmentOperation *operation) {
-  AddonEnvironment *environment = operation->environment;
-  if (environment == nullptr) {
-    return;
-  }
-  std::lock_guard guard(environment->mutex);
-  if (!operation->native_call_entry_pending) {
-    return;
-  }
-  operation->native_call_entry_pending = false;
-  if (environment->pending_native_call_entries > 0) {
-    environment->pending_native_call_entries--;
-  }
-  environment->condition.notify_all();
-}
-
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-void PauseNativeCallEntryForCleanupTest(
-    EnvironmentOperation *operation) {
-  const char *pause =
-      std::getenv("OLIPHAUNT_NODE_CLEANUP_TEST_PAUSE_NATIVE_CALL_ENTRY");
-  if (pause == nullptr || std::strcmp(pause, "1") != 0) {
-    return;
-  }
-  AddonEnvironment *environment = operation->environment;
-  std::unique_lock lock(environment->mutex);
-  environment->condition.notify_all();
-  environment->condition.wait(
-      lock,
-      [environment]() { return environment->shutting_down; });
-}
-
-void WaitForNativeCallEntryPauseForCleanupTest(
-    EnvironmentOperation *operation) {
-  const char *pause =
-      std::getenv("OLIPHAUNT_NODE_CLEANUP_TEST_PAUSE_NATIVE_CALL_ENTRY");
-  if (pause == nullptr || std::strcmp(pause, "1") != 0) {
-    return;
-  }
-  AddonEnvironment *environment = operation->environment;
-  std::unique_lock lock(environment->mutex);
-  environment->condition.wait(
-      lock,
-      [operation]() {
-        return operation->native_call_entry_pending ||
-            !operation->registered.load();
-      });
-}
-
-void WaitForFirstCleanupCancelForTest(
-    EnvironmentOperation *operation) {
-  const char *pause =
-      std::getenv("OLIPHAUNT_NODE_CLEANUP_TEST_PAUSE_NATIVE_CALL_ENTRY");
-  if (pause == nullptr || std::strcmp(pause, "1") != 0) {
-    return;
-  }
-  AddonEnvironment *environment = operation->environment;
-  std::unique_lock lock(environment->mutex);
-  environment->condition.wait(
-      lock,
-      [environment, operation]() {
-        return environment->cleanup_cancel_attempts > 0 ||
-            !operation->registered.load();
-      });
-}
-#endif
-
-class EnvironmentOperationFinish {
- public:
-  explicit EnvironmentOperationFinish(EnvironmentOperation *operation)
-      : operation_(operation) {}
-  ~EnvironmentOperationFinish() { FinishEnvironmentOperation(operation_); }
-
- private:
-  EnvironmentOperation *operation_;
-};
-
-void RegisterThreadsafeBridge(
-    AddonEnvironment *environment,
-    const std::shared_ptr &bridge) {
-  std::lock_guard guard(g_threadsafe_bridges_mutex);
-  auto &bridges = g_threadsafe_bridges[environment];
-  bridges.erase(
-      std::remove_if(
-          bridges.begin(), bridges.end(),
-          [](const auto &candidate) { return candidate.expired(); }),
-      bridges.end());
-  bridges.emplace_back(bridge);
-}
-
-void ReleaseThreadsafeAcquisition(
-    const std::shared_ptr &bridge,
-    napi_threadsafe_function_release_mode mode) {
-  if (bridge == nullptr) {
-    return;
-  }
-  std::unique_lock lock(bridge->release_mutex);
-  if (mode == napi_tsfn_abort) {
-    bridge->aborted.store(true);
-    bridge->release_condition.notify_all();
-  }
-  if (!bridge->acquisition_released && bridge->function != nullptr) {
-    bridge->acquisition_released = true;
-    // Keep bridge ownership serialized until Node-API has consumed the
-    // acquisition. Otherwise environment cleanup could observe the flag,
-    // destroy the Node 22 TSFN, and race this still-pending release call.
-    (void)napi_release_threadsafe_function(bridge->function, mode);
-  }
-  if (mode == napi_tsfn_abort) {
-    // Node 22 destroys TSFNs from its environment cleanup hook even when a
-    // producer thread is still alive. Keep our earlier quiesce hook on the
-    // event-loop stack until every producer has returned from Node-API, and
-    // make shutdown the bridge's sole acquisition release. The worker observes
-    // `aborted` and never touches the TSFN afterward.
-    bridge->release_condition.wait(
-        lock,
-        [bridge]() { return bridge->active_calls == 0; });
-  }
-}
-
-napi_status CallThreadsafeBridge(
-    const std::shared_ptr &bridge,
-    void *data,
-    napi_threadsafe_function_call_mode mode) {
-  if (bridge == nullptr) {
-    return napi_closing;
-  }
-  napi_threadsafe_function function = nullptr;
-  {
-    std::lock_guard guard(bridge->release_mutex);
-    if (bridge->aborted.load() || bridge->function == nullptr) {
-      return napi_closing;
-    }
-    bridge->active_calls++;
-    function = bridge->function;
-  }
-  const napi_status status =
-      napi_call_threadsafe_function(function, data, mode);
-  {
-    std::lock_guard guard(bridge->release_mutex);
-    if (status == napi_closing) {
-      // Node-API consumes one thread acquisition when Push observes a closing
-      // TSFN. Record that ownership transfer so the producer cannot release an
-      // already-destroyed Node 22 bridge later in environment teardown.
-      bridge->acquisition_released = true;
-      bridge->aborted.store(true);
-    }
-    if (bridge->active_calls > 0) {
-      bridge->active_calls--;
-    }
-    if (bridge->active_calls == 0) {
-      bridge->release_condition.notify_all();
-    }
-  }
-  return status;
-}
-
-using BackgroundOperation = void (*)(void *);
-using BackgroundContextRelease = void (*)(void *);
-
-template 
-void ReleaseBackgroundContext(void *data) {
-  auto *context = static_cast(data);
-  if (context->lifetime_references.fetch_sub(1) == 1) {
-    delete context;
-  }
-}
-
-bool StartBackgroundOperation(
-    napi_env env,
-    EnvironmentOperation *operation,
-    const std::shared_ptr &bridge,
-    BackgroundOperation execute,
-    BackgroundContextRelease release_context,
-  void *data) {
-  try {
-    std::thread([operation, bridge, execute, release_context, data]() {
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-      // The cleanup fixture holds this narrow internal seam long enough to
-      // deterministically terminate an environment after registration but
-      // before Execute begins. It is not a public scheduling option.
-      const char *delay_start =
-          std::getenv("OLIPHAUNT_NODE_CLEANUP_TEST_DELAY_OPERATION_START");
-      if (delay_start != nullptr && std::strcmp(delay_start, "1") == 0) {
-        std::this_thread::sleep_for(std::chrono::seconds(1));
-      }
-#endif
-      StartEnvironmentOperation(operation);
-      {
-        EnvironmentOperationFinish finish(operation);
-        execute(data);
-      }
-      // Releasing the TSFN acquisition schedules its finalizer on the Node
-      // thread. Environment teardown may already have retired that
-      // acquisition; this helper retires it exactly once and no environment
-      // state is touched after the operation lease is retired above.
-      ReleaseThreadsafeAcquisition(bridge, napi_tsfn_release);
-      release_context(data);
-    }).detach();
-    return true;
-  } catch (const std::exception &error) {
-    Throw(env, std::string("start native background operation: ") + error.what());
-  } catch (...) {
-    Throw(env, "start native background operation failed");
-  }
-  return false;
-}
-
-void AbortBackgroundOperationSetup(
-    EnvironmentOperation *operation,
-    const std::shared_ptr &bridge) {
-  FinishEnvironmentOperation(operation);
-  ReleaseThreadsafeAcquisition(bridge, napi_tsfn_abort);
-}
-
-bool CanDeliverBackgroundCompletion(
-    napi_env env,
-    const EnvironmentOperation &operation,
-    const std::shared_ptr &bridge) {
-  return env != nullptr && operation.started.load() && bridge != nullptr &&
-      !bridge->aborted.load();
-}
-
-void IgnoreBackgroundCompletion(napi_env, napi_value, void *, void *) {}
-
-void Throw(napi_env env, const std::string &message) { napi_throw_error(env, nullptr, message.c_str()); }
-
-#if defined(_WIN32)
-bool Utf8ToWidePath(
-    const std::string &path,
-    std::wstring *wide_path,
-    std::string *error) {
-  if (path.size() > static_cast(std::numeric_limits::max())) {
-    *error = "liboliphaunt path is too long to load on Windows";
-    return false;
-  }
-
-  const int source_length = static_cast(path.size());
-  const int required_length =
-      MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path.data(), source_length, nullptr, 0);
-  if (required_length <= 0) {
-    *error = "liboliphaunt path is not valid UTF-8";
-    return false;
-  }
-
-  wide_path->resize(static_cast(required_length));
-  const int converted_length = MultiByteToWideChar(
-      CP_UTF8, MB_ERR_INVALID_CHARS, path.data(), source_length, wide_path->data(), required_length);
-  if (converted_length != required_length) {
-    wide_path->clear();
-    *error = "liboliphaunt path could not be converted for the Windows loader";
-    return false;
-  }
-  return true;
-}
-#endif
-
-bool Check(napi_env env, napi_status status, const char *message) {
-  if (status == napi_ok) {
-    return true;
-  }
-  Throw(env, message);
-  return false;
-}
-
-bool RefreshEnvironmentQuiesceHook(
-    napi_env env,
-    AddonEnvironment *environment) {
-  if (environment->quiesce_hook_registered) {
-    if (!Check(
-            env,
-            napi_remove_env_cleanup_hook(
-                env, QuiesceEnvironment, environment),
-            "refresh native environment quiesce hook")) {
-      return false;
-    }
-    environment->quiesce_hook_registered = false;
-  }
-  if (!Check(
-          env,
-          napi_add_env_cleanup_hook(env, QuiesceEnvironment, environment),
-          "register native environment quiesce hook")) {
-    return false;
-  }
-  environment->quiesce_hook_registered = true;
-  return true;
-}
-
-bool ExceptionPending(napi_env env) {
-  bool pending = false;
-  return napi_is_exception_pending(env, &pending) == napi_ok && pending;
-}
-
-std::string LastError(NativeLibrary *library, OliphauntHandle *handle) {
-  if (library == nullptr || library->copy_last_error == nullptr) {
-    return "unknown error";
-  }
-  std::vector message(1024, '\0');
-  for (;;) {
-    const size_t length =
-        library->copy_last_error(handle, message.data(), message.size());
-    if (length == 0 || message[0] == '\0') {
-      return "unknown error";
-    }
-    if (length < message.size()) {
-      return std::string(message.data(), length);
-    }
-    if (length == std::numeric_limits::max()) {
-      return "native liboliphaunt returned an invalid error length";
-    }
-    message.assign(length + 1, '\0');
-  }
-}
-
-void *LoadSymbol(DynamicLibrary library, const char *name, std::string *error) {
-#if defined(_WIN32)
-  void *symbol = reinterpret_cast(GetProcAddress(library.handle, name));
-#else
-  void *symbol = dlsym(library.handle, name);
-#endif
-  if (symbol == nullptr) {
-    if (error->empty()) {
-      *error = std::string("liboliphaunt is missing required symbol ") + name;
-    }
-  }
-  return symbol;
-}
-
-bool SameLoadedImage(DynamicLibrary left, DynamicLibrary right) {
-  return left.handle != nullptr && left.handle == right.handle;
-}
-
-void ReleaseDynamicLibraryReference(DynamicLibrary library) {
-  if (library.handle == nullptr) {
-    return;
-  }
-#if defined(_WIN32)
-  (void)FreeLibrary(library.handle);
-#else
-  (void)dlclose(library.handle);
-#endif
-}
-
-std::shared_ptr LoadNativeLibrary(
-    const std::string &path,
-    std::string *error) {
-  if (path.empty()) {
-    *error = "liboliphaunt path must not be empty";
-    return nullptr;
-  }
-  if (path.find('\0') != std::string::npos) {
-    *error = "liboliphaunt path must not contain a null byte";
-    return nullptr;
-  }
-
-  std::lock_guard guard(g_libraries_mutex);
-  auto existing = g_libraries.find(path);
-  if (existing != g_libraries.end()) {
-    return existing->second;
-  }
-
-  DynamicLibrary dynamic;
-#if defined(_WIN32)
-  std::wstring wide_path;
-  if (!Utf8ToWidePath(path, &wide_path, error)) {
-    return nullptr;
-  }
-  dynamic.handle = LoadLibraryW(wide_path.c_str());
-#else
-  // liboliphaunt embeds PostgreSQL. PostgreSQL loads extension DSOs after the
-  // engine starts, and those DSOs resolve backend globals from liboliphaunt.
-  // Keep the engine's symbols in the process-global lookup scope just as the
-  // Rust native loader does; RTLD_LOCAL makes contrib modules such as amcheck
-  // fail with unresolved PostgreSQL symbols.
-  dynamic.handle = dlopen(path.c_str(), RTLD_NOW | RTLD_GLOBAL);
-#endif
-  if (dynamic.handle == nullptr) {
-#if defined(_WIN32)
-    *error = "load liboliphaunt failed";
-#else
-    const char *message = dlerror();
-    *error =
-        std::string("load liboliphaunt failed: ") + (message == nullptr ? path : message);
-#endif
-    return nullptr;
-  }
-
-  // Equivalent path aliases can return the same loader image. They must share
-  // one lifecycle record or environment cleanup could terminally close the
-  // same resident OliphauntHandle more than once.
-  for (const auto &entry : g_libraries) {
-    if (SameLoadedImage(entry.second->library, dynamic)) {
-      ReleaseDynamicLibraryReference(dynamic);
-      g_libraries[path] = entry.second;
-      return entry.second;
-    }
-  }
-
-  auto library = std::make_shared();
-  library->library = dynamic;
-  library->init = reinterpret_cast(LoadSymbol(dynamic, "oliphaunt_init", error));
-  library->exec_protocol =
-      reinterpret_cast(LoadSymbol(dynamic, "oliphaunt_exec_protocol", error));
-  library->exec_simple_query =
-      reinterpret_cast(
-          LoadSymbol(dynamic, "oliphaunt_exec_simple_query", error));
-  library->exec_protocol_raw_stream = reinterpret_cast(
-      LoadSymbol(dynamic, "oliphaunt_exec_protocol_raw_stream", error));
-  library->backup =
-      reinterpret_cast(LoadSymbol(dynamic, "oliphaunt_backup", error));
-  library->restore =
-      reinterpret_cast(LoadSymbol(dynamic, "oliphaunt_restore", error));
-  library->cancel =
-      reinterpret_cast(LoadSymbol(dynamic, "oliphaunt_cancel", error));
-  library->detach =
-      reinterpret_cast(LoadSymbol(dynamic, "oliphaunt_detach", error));
-  library->logical_generation = reinterpret_cast(
-      LoadSymbol(dynamic, "oliphaunt_logical_generation", error));
-  library->close_if_generation = reinterpret_cast(
-      LoadSymbol(dynamic, "oliphaunt_close_if_generation", error));
-  library->copy_last_error = reinterpret_cast(
-      LoadSymbol(dynamic, "oliphaunt_copy_last_error", error));
-  library->version =
-      reinterpret_cast(LoadSymbol(dynamic, "oliphaunt_version", error));
-  library->free_response =
-      reinterpret_cast(LoadSymbol(dynamic, "oliphaunt_free_response", error));
-
-  if (!error->empty()) {
-    ReleaseDynamicLibraryReference(dynamic);
-    return nullptr;
-  }
-  g_libraries[path] = library;
-  return library;
-}
-
-std::vector> SnapshotLibraries() {
-  std::vector> libraries;
-  {
-    std::lock_guard guard(g_libraries_mutex);
-    libraries.reserve(g_libraries.size());
-    for (const auto &entry : g_libraries) {
-      libraries.push_back(entry.second);
-    }
-  }
-  // Equivalent loader paths intentionally share one NativeLibrary record.
-  // Collapse those aliases before lifecycle work so cancellation is invoked
-  // exactly once for the resident backend rather than once per spelling.
-  std::sort(libraries.begin(), libraries.end());
-  libraries.erase(
-      std::unique(libraries.begin(), libraries.end()), libraries.end());
-  return libraries;
-}
-
-void CancelEnvironmentWork(AddonEnvironment *environment) {
-  for (const auto &library : SnapshotLibraries()) {
-    std::lock_guard guard(library->lifecycle_mutex);
-    if (library->owner_env == environment->env &&
-        library->resident_handle != nullptr && !library->terminally_closed &&
-        library->cancel != nullptr) {
-      /* Cancellation is the supported cross-thread operation. It wakes a
-       * query before the reaper waits for its background call to release the raw
-       * handle, and is harmless when the operation already completed. */
-      (void)library->cancel(library->resident_handle);
-    }
-  }
-}
-
-void CancelAndDrainEnvironmentWork(AddonEnvironment *environment) {
-  {
-    std::unique_lock lock(environment->mutex);
-    environment->condition.wait(
-        lock,
-        [environment]() {
-          return environment->pending_native_call_entries == 0;
-        });
-    if (environment->pending_operations == 0) {
-      return;
-    }
-  }
-
-  // Cancellation can be consumed while PostgreSQL is still between commands,
-  // immediately before an admitted worker enters its blocking native call.
-  // Retry outside the environment lock until every admitted operation retires.
-  // A standalone restore has no resident owner to cancel; the timed waits still
-  // let it drain normally without spinning.
-  while (true) {
-    CancelEnvironmentWork(environment);
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-    {
-      std::lock_guard guard(environment->mutex);
-      environment->cleanup_cancel_attempts++;
-      environment->condition.notify_all();
-    }
-#endif
-    std::unique_lock lock(environment->mutex);
-    if (environment->condition.wait_for(
-            lock,
-            std::chrono::milliseconds(10),
-            [environment]() {
-              return environment->pending_operations == 0;
-            })) {
-      return;
-    }
-  }
-}
-
-void CloseEnvironmentLibraries(AddonEnvironment *environment) {
-  for (const auto &library : SnapshotLibraries()) {
-    std::lock_guard guard(library->lifecycle_mutex);
-    if (library->owner_env != environment->env || library->resident_handle == nullptr ||
-        library->terminally_closed) {
-      continue;
-    }
-
-    const uint64_t generation = library->resident_generation;
-    // Node runs environment cleanup hooks before external finalizers. Publish
-    // the local terminal state first so a later NativeHandleBox finalizer
-    // cannot detach the generation being closed. A copied addon image has an
-    // independent lifecycle map, so liboliphaunt must decide atomically whether
-    // this image still owns the process-resident generation.
-    library->terminally_closed = true;
-    library->resident_handle = nullptr;
-    library->resident_generation = 0;
-    library->owner_env = nullptr;
-    library->detach_pending = false;
-    int32_t close_result = -1;
-    if (library->close_if_generation != nullptr) {
-      close_result = library->close_if_generation(generation);
-    }
-    if (close_result > 0) {
-      // This cleanup record was stale. The current generation belongs to
-      // another addon image/environment, so this image may be reused later.
-      // Its old finalizers remain harmless because their generation no longer
-      // matches any resident lifecycle recorded here.
-      library->terminally_closed = false;
-    }
-  }
-}
-
-void BeginEnvironmentShutdown(AddonEnvironment *environment) {
-  std::vector> bridges;
-  {
-    std::lock_guard guard(environment->mutex);
-    environment->shutting_down = true;
-    environment->quiesce_hook_registered = false;
-    environment->condition.notify_all();
-  }
-  {
-    std::lock_guard guard(g_environments_mutex);
-    auto entry = g_environments.find(environment->env);
-    if (entry != g_environments.end() && entry->second == environment) {
-      g_environments.erase(entry);
-    }
-  }
-  {
-    std::lock_guard guard(g_threadsafe_bridges_mutex);
-    auto entry = g_threadsafe_bridges.find(environment);
-    if (entry != g_threadsafe_bridges.end()) {
-      bridges.reserve(entry->second.size());
-      for (const auto &candidate : entry->second) {
-        if (auto bridge = candidate.lock()) {
-          bridges.push_back(std::move(bridge));
-        }
-      }
-      g_threadsafe_bridges.erase(entry);
-    }
-  }
-  for (const auto &bridge : bridges) {
-    /* A blocking TSFN producer cannot depend on an event loop that is already
-     * tearing down. Aborting the bridge's sole acquisition wakes it and makes
-     * shutdown, rather than the producer, own the final Node-API operation. */
-    ReleaseThreadsafeAcquisition(bridge, napi_tsfn_abort);
-  }
-}
-
-void QuiesceEnvironment(void *data) {
-  auto *environment = static_cast(data);
-  if (environment == nullptr) {
-    return;
-  }
-  BeginEnvironmentShutdown(environment);
-  /* This synchronous hook only closes JS delivery bridges. Potentially
-   * blocking cancellation and terminal close are owned by the asynchronous
-   * reaper below, never by Node's environment teardown thread. */
-}
-
-void CleanupEnvironment(
-    napi_async_cleanup_hook_handle cleanup_handle,
-    void *data) {
-  auto *environment = static_cast(data);
-  if (environment == nullptr) {
-    (void)napi_remove_async_cleanup_hook(cleanup_handle);
-    return;
-  }
-
-  BeginEnvironmentShutdown(environment);
-
-  napi_handle_scope cleanup_scope = nullptr;
-  napi_value cleanup_resource_name = nullptr;
-  if (napi_open_handle_scope(environment->env, &cleanup_scope) != napi_ok ||
-      napi_create_string_utf8(
-          environment->env,
-          "oliphaunt:environment-cleanup",
-          NAPI_AUTO_LENGTH,
-          &cleanup_resource_name) != napi_ok ||
-      napi_create_threadsafe_function(
-          environment->env,
-          nullptr,
-          nullptr,
-          cleanup_resource_name,
-          1,
-          1,
-          nullptr,
-          nullptr,
-          environment,
-          CompleteEnvironmentCleanup,
-          &environment->cleanup_completion) != napi_ok) {
-    napi_fatal_error(
-        "oliphaunt", NAPI_AUTO_LENGTH,
-        "could not create asynchronous environment cleanup completion",
-        NAPI_AUTO_LENGTH);
-    return;
-  }
-  (void)napi_close_handle_scope(environment->env, cleanup_scope);
-
-  try {
-    std::thread([environment, cleanup_handle]() {
-      CancelAndDrainEnvironmentWork(environment);
-      CloseEnvironmentLibraries(environment);
-      // napi_remove_async_cleanup_hook mutates Node environment state and must
-      // run on its event-loop thread. Calling this freshly-created TSFN is the
-      // only Node-API operation the background reaper performs.
-      napi_threadsafe_function completion = environment->cleanup_completion;
-      const napi_status status = napi_call_threadsafe_function(
-          completion, cleanup_handle, napi_tsfn_nonblocking);
-      {
-        std::lock_guard guard(environment->mutex);
-        environment->cleanup_completion_call_returned = true;
-        environment->condition.notify_all();
-      }
-      if (status != napi_ok) {
-        // The async hook owns this referenced TSFN until the callback below, so
-        // failure indicates an internal lifecycle violation. Removing the hook
-        // from this reaper thread would race Node environment state, while
-        // leaving it pending deadlocks teardown. Fail closed instead of silently
-        // hanging worker.terminate() or process shutdown forever.
-        napi_fatal_error(
-            "oliphaunt", NAPI_AUTO_LENGTH,
-            "could not queue asynchronous environment cleanup completion",
-            NAPI_AUTO_LENGTH);
-      }
-    }).detach();
-  } catch (...) {
-    // There is no recoverable completion path once an async cleanup hook owns
-    // the environment barrier. Never let a C++ thread-construction exception
-    // escape across the Node-API callback boundary.
-    napi_fatal_error(
-        "oliphaunt", NAPI_AUTO_LENGTH,
-        "could not start asynchronous environment cleanup reaper",
-        NAPI_AUTO_LENGTH);
-  }
-}
-
-void CompleteEnvironmentCleanup(
-    napi_env,
-    napi_value,
-    void *context,
-    void *data) {
-  auto *environment = static_cast(context);
-  auto cleanup_handle =
-      static_cast(data);
-  if (environment == nullptr || cleanup_handle == nullptr) {
-    return;
-  }
-  {
-    // A TSFN callback may overtake the producing thread immediately after its
-    // queue insertion. Wait until the producer has returned from the Node-API
-    // call before releasing the TSFN or deleting its context.
-    std::unique_lock lock(environment->mutex);
-    environment->condition.wait(
-        lock,
-        [environment]() {
-          return environment->cleanup_completion_call_returned;
-        });
-  }
-  // This callback is dispatched by the environment's TSFN and therefore runs
-  // on the owning event-loop thread, including when Node is tearing a Worker
-  // down. Release the TSFN's producer reference before removing the hook: hook
-  // removal lets teardown close TSFN resources immediately, so a later reaper-
-  // thread release would race their destruction.
-  (void)napi_release_threadsafe_function(
-      environment->cleanup_completion, napi_tsfn_release);
-  (void)napi_remove_async_cleanup_hook(cleanup_handle);
-  delete environment;
-}
-
-bool HasNamedProperty(napi_env env, napi_value object, const char *name) {
-  bool has_property = false;
-  return napi_has_named_property(env, object, name, &has_property) == napi_ok && has_property;
-}
-
-napi_value GetNamed(napi_env env, napi_value object, const char *name) {
-  napi_value value = nullptr;
-  if (!Check(env, napi_get_named_property(env, object, name, &value), "read object property")) {
-    return nullptr;
-  }
-  return value;
-}
-
-std::string ValueToString(napi_env env, napi_value value, const char *label) {
-  size_t length = 0;
-  if (!Check(env, napi_get_value_string_utf8(env, value, nullptr, 0, &length), label)) {
-    return {};
-  }
-  std::vector buffer(length + 1);
-  if (!Check(env, napi_get_value_string_utf8(env, value, buffer.data(), buffer.size(), &length),
-             label)) {
-    return {};
-  }
-  return std::string(buffer.data(), length);
-}
-
-std::string GetString(napi_env env, napi_value object, const char *name, bool required = true) {
-  if (!HasNamedProperty(env, object, name)) {
-    if (required) {
-      Throw(env, std::string("missing required string property ") + name);
-    }
-    return {};
-  }
-  napi_value value = GetNamed(env, object, name);
-  napi_valuetype type = napi_undefined;
-  napi_typeof(env, value, &type);
-  if (type == napi_null || type == napi_undefined) {
-    return {};
-  }
-  std::string out = ValueToString(env, value, "read string value");
-  if (required && out.empty()) {
-    Throw(env, std::string("string property must not be empty: ") + name);
-  }
-  return out;
-}
-
-std::vector GetStringArray(napi_env env, napi_value object, const char *name) {
-  std::vector out;
-  if (!HasNamedProperty(env, object, name)) {
-    return out;
-  }
-  napi_value value = GetNamed(env, object, name);
-  bool is_array = false;
-  if (!Check(env, napi_is_array(env, value, &is_array), "check string array")) {
-    return out;
-  }
-  if (!is_array) {
-    Throw(env, std::string("property must be a string array: ") + name);
-    return out;
-  }
-  uint32_t length = 0;
-  Check(env, napi_get_array_length(env, value, &length), "read string array length");
-  out.reserve(length);
-  for (uint32_t index = 0; index < length; ++index) {
-    napi_value item = nullptr;
-    Check(env, napi_get_element(env, value, index, &item), "read string array item");
-    out.push_back(ValueToString(env, item, "read string item"));
-  }
-  return out;
-}
-
-std::vector GetBytes(napi_env env, napi_value value) {
-  bool is_typed_array = false;
-  Check(env, napi_is_typedarray(env, value, &is_typed_array), "check typed array");
-  if (!is_typed_array) {
-    Throw(env, "expected Uint8Array");
-    return {};
-  }
-  napi_typedarray_type type;
-  size_t length = 0;
-  void *data = nullptr;
-  napi_value array_buffer = nullptr;
-  size_t byte_offset = 0;
-  Check(env,
-        napi_get_typedarray_info(env, value, &type, &length, &data, &array_buffer, &byte_offset),
-        "read typed array");
-  if (type != napi_uint8_array) {
-    Throw(env, "expected Uint8Array");
-    return {};
-  }
-  const auto *bytes = static_cast(data);
-  return std::vector(bytes, bytes + length);
-}
-
-napi_value MakeBytes(napi_env env, const uint8_t *data, size_t length) {
-  void *out = nullptr;
-  napi_value buffer = nullptr;
-  if (!Check(env, napi_create_buffer_copy(env, length, data, &out, &buffer), "create response buffer")) {
-    return nullptr;
-  }
-  return buffer;
-}
-
-napi_value MakeResponse(napi_env env, NativeLibrary *library, OliphauntResponse *response) {
-  napi_value value = MakeBytes(env, response->data, response->len);
-  library->free_response(response);
-  response->data = nullptr;
-  response->len = 0;
-  return value;
-}
-
-napi_value MakeError(napi_env env, const std::string &message) {
-  napi_value text = nullptr;
-  napi_value error = nullptr;
-  if (napi_create_string_utf8(env, message.c_str(), message.size(), &text) != napi_ok ||
-      napi_create_error(env, nullptr, text, &error) != napi_ok) {
-    return nullptr;
-  }
-  return error;
-}
-
-bool RejectPendingException(napi_env env, napi_deferred deferred) {
-  if (!ExceptionPending(env)) {
-    return false;
-  }
-  napi_value exception = nullptr;
-  return napi_get_and_clear_last_exception(env, &exception) == napi_ok &&
-      exception != nullptr &&
-      napi_reject_deferred(env, deferred, exception) == napi_ok;
-}
-
-void RejectDeferred(napi_env env, napi_deferred deferred, const std::string &message) {
-  napi_value error = MakeError(env, message);
-  if (error != nullptr) {
-    (void)napi_reject_deferred(env, deferred, error);
-    return;
-  }
-  if (!RejectPendingException(env, deferred)) {
-    Throw(env, message);
-  }
-}
-
-void RejectResponseCreation(napi_env env, napi_deferred deferred) {
-  if (!RejectPendingException(env, deferred)) {
-    RejectDeferred(env, deferred, "native liboliphaunt could not create the JavaScript response");
-  }
-}
-
-NativeHandleBox *GetHandleBox(napi_env env, napi_value value) {
-  void *data = nullptr;
-  if (!Check(env, napi_get_value_external(env, value, &data), "read native handle")) {
-    return nullptr;
-  }
-  auto *box = static_cast(data);
-  if (box == nullptr || box->handle == nullptr || box->detached) {
-    Throw(env, "Oliphaunt native handle is closed");
-    return nullptr;
-  }
-  return box;
-}
-
-void FinalizeHandle(napi_env, void *data, void *) {
-  auto *box = static_cast(data);
-  if (box != nullptr) {
-    if (box->library != nullptr) {
-      std::lock_guard guard(box->library->lifecycle_mutex);
-      if (!box->library->terminally_closed && !box->detached && box->handle != nullptr &&
-          box->library->resident_handle == box->handle &&
-          box->library->resident_generation == box->generation) {
-        // A finalizer must never run DISCARD ALL or ROLLBACK on the JavaScript
-        // thread. Preserve the resident owner for the next async open to
-        // detach, or for environment cleanup to close terminally.
-        box->library->detach_pending = true;
-      }
-    }
-    delete box;
-  }
-}
-
-void FinalizeForgottenHandleRecoveryToken(napi_env, void *data, void *) {
-  delete static_cast(data);
-}
-
-std::vector Args(napi_env env, napi_callback_info info, size_t expected) {
-  size_t argc = expected;
-  std::vector args(expected);
-  napi_value this_arg = nullptr;
-  if (!Check(env, napi_get_cb_info(env, info, &argc, args.data(), &this_arg, nullptr), "read arguments")) {
-    return {};
-  }
-  if (argc < expected) {
-    Throw(env, "missing required argument");
-  }
-  return args;
-}
-
-napi_value CreateForgottenHandleRecoveryToken(
-    napi_env env,
-    napi_callback_info info) {
-  auto args = Args(env, info, 1);
-  if (args.empty()) return nullptr;
-  NativeHandleBox *box = GetHandleBox(env, args[0]);
-  if (box == nullptr) return nullptr;
-
-  auto token = std::make_unique();
-  token->library = box->library;
-  token->generation = box->generation;
-  napi_value external = nullptr;
-  if (!Check(
-          env,
-          napi_create_external(
-              env,
-              token.get(),
-              FinalizeForgottenHandleRecoveryToken,
-              nullptr,
-              &external),
-          "create forgotten-handle recovery token")) {
-    return nullptr;
-  }
-  (void)token.release();
-  return external;
-}
-
-napi_value QueueForgottenHandleRecovery(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 1);
-  if (args.empty()) return nullptr;
-  void *data = nullptr;
-  if (!Check(
-          env,
-          napi_get_value_external(env, args[0], &data),
-          "read forgotten-handle recovery token")) {
-    return nullptr;
-  }
-  auto *token = static_cast(data);
-  if (token == nullptr || token->magic != kForgottenHandleRecoveryTokenMagic ||
-      token->library == nullptr || token->generation == 0) {
-    Throw(env, "Oliphaunt forgotten-handle recovery token is invalid");
-    return nullptr;
-  }
-
-  bool queued = false;
-  {
-    std::lock_guard guard(token->library->lifecycle_mutex);
-    if (!token->library->terminally_closed &&
-        token->library->resident_handle != nullptr &&
-        token->library->resident_generation == token->generation) {
-      // This only records native work for the next asynchronous open. It does
-      // not run PostgreSQL teardown on the JavaScript finalizer thread.
-      token->library->detach_pending = true;
-      queued = true;
-    }
-  }
-
-  napi_value result = nullptr;
-  if (!Check(env, napi_get_boolean(env, queued, &result),
-             "create forgotten-handle recovery result")) {
-    return nullptr;
-  }
-  return result;
-}
-
-napi_value Version(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 1);
-  if (args.empty()) return nullptr;
-  std::string library_path = ValueToString(env, args[0], "read library path");
-  std::string error;
-  auto library = LoadNativeLibrary(library_path, &error);
-  if (library == nullptr) {
-    Throw(env, error);
-    return nullptr;
-  }
-  const char *version = library->version();
-  napi_value out = nullptr;
-  Check(env, napi_create_string_utf8(env, version == nullptr ? "unknown" : version, NAPI_AUTO_LENGTH, &out),
-        "create version string");
-  return out;
-}
-
-struct AsyncOpenContext {
-  std::atomic lifetime_references = 2;
-  EnvironmentOperation environment_operation;
-  std::shared_ptr completion_bridge;
-  napi_deferred deferred = nullptr;
-  napi_ref handle_ref = nullptr;
-  NativeHandleBox *box = nullptr;
-  std::shared_ptr library;
-  napi_env owner_env = nullptr;
-  std::string library_path;
-  std::string pgdata;
-  std::string runtime_dir;
-  std::string module_dir;
-  std::string username;
-  std::string database;
-  std::vector startup_args;
-  OliphauntHandle *handle = nullptr;
-  uint64_t generation = 0;
-  std::string error;
-  bool succeeded = false;
-};
-
-void ExecuteAsyncOpen(void *data) {
-  auto *context = static_cast(data);
-  if (EnvironmentIsShuttingDown(&context->environment_operation)) {
-    context->error = "native liboliphaunt environment is shutting down";
-    return;
-  }
-  context->library = LoadNativeLibrary(context->library_path, &context->error);
-  if (context->library == nullptr) {
-    return;
-  }
-  std::vector startup_ptrs;
-  startup_ptrs.reserve(context->startup_args.size());
-  for (const auto &arg : context->startup_args) {
-    startup_ptrs.push_back(arg.c_str());
-  }
-
-  OliphauntConfig native_config = {};
-  native_config.abi_version = OLIPHAUNT_ABI_VERSION;
-  native_config.pgdata = context->pgdata.c_str();
-  native_config.runtime_dir = context->runtime_dir.empty() ? nullptr : context->runtime_dir.c_str();
-  native_config.module_dir = context->module_dir.empty() ? nullptr : context->module_dir.c_str();
-  native_config.username = context->username.c_str();
-  native_config.database = context->database.c_str();
-  native_config.flags = 0;
-  native_config.startup_args = startup_ptrs.empty() ? nullptr : startup_ptrs.data();
-  native_config.startup_arg_count = startup_ptrs.size();
-
-  std::lock_guard guard(context->library->lifecycle_mutex);
-  if (context->library->terminally_closed) {
-    context->error = "native liboliphaunt environment has already shut down";
-    return;
-  }
-  if (context->library->detach_pending) {
-    if (context->library->resident_handle == nullptr ||
-        context->library->resident_generation == 0 || context->library->detach == nullptr) {
-      context->error = "native liboliphaunt has an invalid pending detach owner";
-      return;
-    }
-    const int32_t detach_rc = context->library->detach(context->library->resident_handle);
-    if (detach_rc != 0) {
-      context->error =
-          "native liboliphaunt could not recover the previous logical handle: " +
-          LastError(context->library.get(), context->library->resident_handle);
-      return;
-    }
-    context->library->detach_pending = false;
-  }
-
-  const int32_t rc = context->library->init(&native_config, &context->handle);
-  if (rc != 0) {
-    context->error =
-        "native liboliphaunt init failed: " + LastError(context->library.get(), nullptr);
-    return;
-  }
-  if (context->handle == nullptr) {
-    context->error = "native liboliphaunt init returned a null handle";
-    return;
-  }
-  context->generation = context->library->logical_generation(context->handle);
-  if (context->generation == 0) {
-    // A zero generation means another cleanup owner invalidated the opaque
-    // pointer. Do not pass that potentially stale pointer to any other ABI.
-    context->library->terminally_closed = true;
-    context->library->resident_handle = nullptr;
-    context->library->resident_generation = 0;
-    context->library->owner_env = nullptr;
-    context->handle = nullptr;
-    context->error = "native liboliphaunt init returned an invalid logical generation";
-    return;
-  }
-  context->library->resident_handle = context->handle;
-  context->library->resident_generation = context->generation;
-  context->library->owner_env = context->owner_env;
-  context->library->detach_pending = false;
-  context->succeeded = true;
-}
-
-void FinalizeAsyncOpen(napi_env env, void *data, void *) {
-  auto *context = static_cast(data);
-  if (CanDeliverBackgroundCompletion(
-          env, context->environment_operation, context->completion_bridge) &&
-      !context->succeeded) {
-    RejectDeferred(
-        env,
-        context->deferred,
-        context->error);
-  } else if (CanDeliverBackgroundCompletion(
-                 env, context->environment_operation, context->completion_bridge)) {
-    context->box->library = context->library;
-    context->box->handle = context->handle;
-    context->box->generation = context->generation;
-    napi_value external = nullptr;
-    if (napi_get_reference_value(env, context->handle_ref, &external) == napi_ok &&
-        external != nullptr) {
-      (void)napi_resolve_deferred(env, context->deferred, external);
-    } else {
-      RejectDeferred(env, context->deferred, "native liboliphaunt could not publish its handle");
-    }
-  }
-  if (env != nullptr && context->handle_ref != nullptr) {
-    (void)napi_delete_reference(env, context->handle_ref);
-    context->handle_ref = nullptr;
-  }
-  ReleaseBackgroundContext(context);
-}
-
-napi_value Open(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 1);
-  if (args.empty()) return nullptr;
-  napi_value config = args[0];
-  auto context = std::make_unique();
-  context->library_path = GetString(env, config, "libraryPath");
-  context->pgdata = GetString(env, config, "pgdata");
-  context->runtime_dir = GetString(env, config, "runtimeDirectory", false);
-  context->module_dir = GetString(env, config, "moduleDirectory", false);
-  context->username = GetString(env, config, "username");
-  context->database = GetString(env, config, "database");
-  context->startup_args = GetStringArray(env, config, "startupArgs");
-  if (ExceptionPending(env)) return nullptr;
-  context->owner_env = env;
-  context->box = new NativeHandleBox();
-  context->completion_bridge = std::make_shared();
-
-  napi_value promise = nullptr;
-  napi_value external = nullptr;
-  napi_value resource_name = nullptr;
-  if (!Check(env, napi_create_promise(env, &context->deferred, &promise), "create open promise") ||
-      !Check(env,
-             napi_create_external(env, context->box, FinalizeHandle, nullptr, &external),
-             "create native handle") ||
-      !Check(env, napi_create_reference(env, external, 1, &context->handle_ref),
-             "retain native handle during open") ||
-      !Check(env,
-             napi_create_string_utf8(
-                 env, "oliphaunt.open", NAPI_AUTO_LENGTH, &resource_name),
-             "create open resource name") ||
-      !Check(env,
-             napi_create_threadsafe_function(
-                 env,
-                 nullptr,
-                 nullptr,
-                 resource_name,
-                 1,
-                 1,
-                 context.get(),
-                 FinalizeAsyncOpen,
-                 context.get(),
-                 IgnoreBackgroundCompletion,
-                 &context->completion_bridge->function),
-             "create native open completion")) {
-    if (context->handle_ref != nullptr) {
-      (void)napi_delete_reference(env, context->handle_ref);
-    } else if (external == nullptr) {
-      delete context->box;
-    }
-    return nullptr;
-  }
-  AsyncOpenContext *raw_context = context.release();
-  if (!RegisterEnvironmentOperation(env, &raw_context->environment_operation)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->completion_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-  RegisterThreadsafeBridge(
-      raw_context->environment_operation.environment, raw_context->completion_bridge);
-  if (!RefreshEnvironmentQuiesceHook(
-          env, raw_context->environment_operation.environment) ||
-      !StartBackgroundOperation(
-          env,
-          &raw_context->environment_operation,
-          raw_context->completion_bridge,
-          ExecuteAsyncOpen,
-          ReleaseBackgroundContext,
-          raw_context)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->completion_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-  return promise;
-}
-
-enum class AsyncQueryKind { Protocol, Simple };
-
-struct AsyncQueryContext {
-  std::atomic lifetime_references = 2;
-  EnvironmentOperation environment_operation;
-  std::shared_ptr completion_bridge;
-  napi_deferred deferred = nullptr;
-  napi_ref handle_ref = nullptr;
-  std::shared_ptr library;
-  OliphauntHandle *handle = nullptr;
-  AsyncQueryKind kind = AsyncQueryKind::Protocol;
-  std::vector request;
-  std::string sql;
-  OliphauntResponse response = {};
-  int32_t result = -1;
-  std::string error;
-
-  ~AsyncQueryContext() {
-    if (library != nullptr && (response.data != nullptr || response.len != 0)) {
-      library->free_response(&response);
-    }
-  }
-};
-
-void ExecuteAsyncQuery(void *data) {
-  auto *context = static_cast(data);
-  if (!AdmitEnvironmentNativeCall(&context->environment_operation)) {
-    context->error = "native liboliphaunt environment is shutting down";
-    return;
-  }
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-  PauseNativeCallEntryForCleanupTest(&context->environment_operation);
-#endif
-  MarkEnvironmentNativeCallEntered(&context->environment_operation);
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-  WaitForFirstCleanupCancelForTest(&context->environment_operation);
-#endif
-  if (context->kind == AsyncQueryKind::Protocol) {
-    context->result = context->library->exec_protocol(
-        context->handle,
-        context->request.empty() ? nullptr : context->request.data(),
-        context->request.size(),
-        &context->response);
-  } else {
-    context->result = context->library->exec_simple_query(
-        context->handle, context->sql.data(), context->sql.size(), &context->response);
-  }
-  if (context->result != 0) {
-    context->error = LastError(context->library.get(), context->handle);
-  }
-}
-
-void FinalizeAsyncQuery(napi_env env, void *data, void *) {
-  auto *context = static_cast(data);
-  const bool deliver = CanDeliverBackgroundCompletion(
-      env, context->environment_operation, context->completion_bridge);
-  if (env != nullptr && context->handle_ref != nullptr) {
-    (void)napi_delete_reference(env, context->handle_ref);
-    context->handle_ref = nullptr;
-  }
-
-  if (deliver && context->result != 0) {
-    context->library->free_response(&context->response);
-    context->response.data = nullptr;
-    context->response.len = 0;
-    const char *operation =
-        context->kind == AsyncQueryKind::Protocol ? "protocol execution" : "simple query";
-    RejectDeferred(
-        env,
-        context->deferred,
-        std::string("native liboliphaunt ") + operation + " failed: " + context->error);
-  } else if (deliver) {
-    napi_value response = MakeResponse(env, context->library.get(), &context->response);
-    if (response != nullptr) {
-      (void)napi_resolve_deferred(env, context->deferred, response);
-    } else {
-      RejectResponseCreation(env, context->deferred);
-    }
-  }
-  ReleaseBackgroundContext(context);
-}
-
-napi_value QueueAsyncQuery(
-    napi_env env,
-    napi_value handle_value,
-    NativeHandleBox *box,
-    AsyncQueryKind kind,
-    std::vector request,
-  std::string sql) {
-  auto context = std::make_unique();
-  context->library = box->library;
-  context->handle = box->handle;
-  context->kind = kind;
-  context->request = std::move(request);
-  context->sql = std::move(sql);
-  context->completion_bridge = std::make_shared();
-
-  napi_value promise = nullptr;
-  napi_value resource_name = nullptr;
-  const char *resource = kind == AsyncQueryKind::Protocol
-      ? "oliphaunt.execProtocolRaw"
-      : "oliphaunt.execSimpleQuery";
-  if (!Check(env, napi_create_promise(env, &context->deferred, &promise), "create query promise") ||
-      !Check(env, napi_create_reference(env, handle_value, 1, &context->handle_ref),
-             "retain native handle for query") ||
-      !Check(env, napi_create_string_utf8(env, resource, NAPI_AUTO_LENGTH, &resource_name),
-             "create query resource name") ||
-      !Check(env,
-             napi_create_threadsafe_function(
-                 env,
-                 nullptr,
-                 nullptr,
-                 resource_name,
-                 1,
-                 1,
-                 context.get(),
-                 FinalizeAsyncQuery,
-                 context.get(),
-                 IgnoreBackgroundCompletion,
-                 &context->completion_bridge->function),
-             "create native query completion")) {
-    if (context->handle_ref != nullptr) {
-      (void)napi_delete_reference(env, context->handle_ref);
-    }
-    return nullptr;
-  }
-  AsyncQueryContext *raw_context = context.release();
-  if (!RegisterEnvironmentOperation(env, &raw_context->environment_operation)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->completion_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-  RegisterThreadsafeBridge(
-      raw_context->environment_operation.environment, raw_context->completion_bridge);
-  if (!RefreshEnvironmentQuiesceHook(
-          env, raw_context->environment_operation.environment) ||
-      !StartBackgroundOperation(
-          env,
-          &raw_context->environment_operation,
-          raw_context->completion_bridge,
-          ExecuteAsyncQuery,
-          ReleaseBackgroundContext,
-          raw_context)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->completion_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-  WaitForNativeCallEntryPauseForCleanupTest(&raw_context->environment_operation);
-#endif
-  return promise;
-}
-
-napi_value ExecProtocolRaw(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 2);
-  if (args.empty()) return nullptr;
-  NativeHandleBox *box = GetHandleBox(env, args[0]);
-  if (box == nullptr) return nullptr;
-  std::vector request = GetBytes(env, args[1]);
-  if (ExceptionPending(env)) return nullptr;
-  return QueueAsyncQuery(
-      env, args[0], box, AsyncQueryKind::Protocol, std::move(request), std::string());
-}
-
-napi_value ExecSimpleQuery(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 2);
-  if (args.empty()) return nullptr;
-  NativeHandleBox *box = GetHandleBox(env, args[0]);
-  if (box == nullptr) return nullptr;
-  std::string sql = ValueToString(env, args[1], "read SQL");
-  if (ExceptionPending(env)) return nullptr;
-  return QueueAsyncQuery(
-      env, args[0], box, AsyncQueryKind::Simple, std::vector(), std::move(sql));
-}
-
-struct AsyncStreamContext {
-  std::atomic lifetime_references = 2;
-  EnvironmentOperation environment_operation;
-  std::shared_ptr callback_bridge;
-  napi_deferred deferred = nullptr;
-  napi_ref handle_ref = nullptr;
-  // Node-API versions before 10 cannot reference arbitrary primitive values.
-  // Retain an Array holder so every JavaScript throw value, including
-  // undefined and NaN, can be recovered without changing its identity.
-  napi_ref callback_exception_holder = nullptr;
-  std::shared_ptr library;
-  OliphauntHandle *handle = nullptr;
-  std::vector request;
-  int32_t result = -1;
-  std::atomic callback_failed = false;
-  std::mutex error_mutex;
-  std::string error;
-};
-
-struct StreamChunkDelivery {
-  std::vector bytes;
-  std::shared_ptr bridge;
-  std::atomic completed = false;
-};
-
-class StreamChunkDeliveryCompletion {
- public:
-  explicit StreamChunkDeliveryCompletion(
-      std::shared_ptr delivery)
-      : delivery_(std::move(delivery)) {}
-
-  ~StreamChunkDeliveryCompletion() {
-    delivery_->completed.store(true, std::memory_order_release);
-    delivery_->bridge->release_condition.notify_all();
-  }
-
- private:
-  std::shared_ptr delivery_;
-};
-
-void RecordStreamError(AsyncStreamContext *context, std::string error) {
-  std::lock_guard guard(context->error_mutex);
-  if (context->error.empty()) {
-    context->error = std::move(error);
-  }
-  context->callback_failed.store(true);
-}
-
-void RecordStreamException(
-    napi_env env,
-    AsyncStreamContext *context,
-    napi_value exception,
-    const char *fallback) {
-  if (context->callback_exception_holder == nullptr && exception != nullptr) {
-    napi_value holder = nullptr;
-    if (napi_create_array_with_length(env, 1, &holder) == napi_ok &&
-        napi_set_element(env, holder, 0, exception) == napi_ok &&
-        napi_create_reference(
-            env, holder, 1, &context->callback_exception_holder) == napi_ok) {
-      context->callback_failed.store(true);
-      return;
-    }
-  }
-  RecordStreamError(context, fallback);
-}
-
-void RecordPendingStreamException(
-    napi_env env,
-    AsyncStreamContext *context,
-    const char *fallback) {
-  napi_value exception = nullptr;
-  if (ExceptionPending(env) && napi_get_and_clear_last_exception(env, &exception) == napi_ok) {
-    RecordStreamException(env, context, exception, fallback);
-  } else {
-    RecordStreamError(context, fallback);
-  }
-}
-
-void CallStreamChunk(napi_env env, napi_value callback, void *data, void *chunk_data) {
-  std::unique_ptr> queued_delivery(
-      static_cast *>(chunk_data));
-  if (queued_delivery == nullptr || *queued_delivery == nullptr) {
-    return;
-  }
-  auto delivery = std::move(*queued_delivery);
-  StreamChunkDeliveryCompletion completion(delivery);
-  auto *context = static_cast(data);
-  if (env == nullptr || callback == nullptr || context->callback_failed.load()) {
-    return;
-  }
-  napi_handle_scope scope = nullptr;
-  if (napi_open_handle_scope(env, &scope) != napi_ok) {
-    RecordPendingStreamException(env, context, "open stream callback scope failed");
-    return;
-  }
-  napi_value global = nullptr;
-  napi_value chunk = nullptr;
-  napi_value result = nullptr;
-  napi_status status = napi_get_global(env, &global);
-  if (status == napi_ok) {
-    chunk = MakeBytes(env, delivery->bytes.data(), delivery->bytes.size());
-    status = chunk == nullptr ? napi_generic_failure : napi_ok;
-  }
-  if (status == napi_ok) {
-    status = napi_call_function(env, global, callback, 1, &chunk, &result);
-  }
-  if (status != napi_ok) {
-    RecordPendingStreamException(env, context, "stream callback failed");
-    (void)napi_close_handle_scope(env, scope);
-    return;
-  }
-
-  napi_valuetype result_type = napi_undefined;
-  if (napi_typeof(env, result, &result_type) != napi_ok) {
-    RecordPendingStreamException(env, context, "inspect stream callback result failed");
-  } else if (result_type == napi_object || result_type == napi_function) {
-    bool has_then = false;
-    napi_value then_value = nullptr;
-    napi_valuetype then_type = napi_undefined;
-    if (napi_has_named_property(env, result, "then", &has_then) != napi_ok ||
-        (has_then && napi_get_named_property(env, result, "then", &then_value) != napi_ok) ||
-        (has_then && napi_typeof(env, then_value, &then_type) != napi_ok)) {
-      RecordPendingStreamException(env, context, "inspect stream callback thenable failed");
-    } else if (has_then && then_type == napi_function) {
-      constexpr const char *message =
-          "raw protocol stream callback must complete synchronously and must not return a "
-          "Promise or thenable";
-      napi_value message_value = nullptr;
-      napi_value exception = nullptr;
-      if (napi_create_string_utf8(env, message, NAPI_AUTO_LENGTH, &message_value) == napi_ok &&
-          napi_create_type_error(env, nullptr, message_value, &exception) == napi_ok) {
-        RecordStreamException(env, context, exception, message);
-      } else {
-        RecordPendingStreamException(env, context, message);
-      }
-    }
-  }
-  (void)napi_close_handle_scope(env, scope);
-}
-
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-bool PrefillStreamQueueForCleanupTest(
-    napi_env env,
-    AsyncStreamContext *context) {
-  const char *prefill =
-      std::getenv("OLIPHAUNT_NODE_CLEANUP_TEST_PREFILL_STREAM_QUEUE");
-  if (prefill == nullptr || std::strcmp(prefill, "1") != 0) {
-    return true;
-  }
-
-  // Keep one delivery queued while the fixture blocks its Worker event loop.
-  // The real stream producer then blocks inside napi_call_threadsafe_function,
-  // giving teardown a deterministic in-flight producer to abort.
-  auto delivery = std::make_shared();
-  delivery->bridge = context->callback_bridge;
-  auto queued_delivery =
-      std::make_unique>(delivery);
-  const napi_status status = CallThreadsafeBridge(
-      context->callback_bridge, queued_delivery.get(), napi_tsfn_nonblocking);
-  if (status != napi_ok) {
-    Throw(env, "prefill native stream callback queue for cleanup test");
-    return false;
-  }
-  (void)queued_delivery.release();
-  return true;
-}
-#endif
-
-int32_t StreamChunk(void *data, const uint8_t *bytes, size_t length) {
-  auto *context = static_cast(data);
-  if (context->callback_failed.load()) {
-    return 1;
-  }
-  if (bytes == nullptr && length != 0) {
-    RecordStreamError(context, "native liboliphaunt stream returned null bytes");
-    return 1;
-  }
-  auto delivery = std::make_shared();
-  delivery->bridge = context->callback_bridge;
-  if (length != 0) {
-    delivery->bytes.assign(bytes, bytes + length);
-  }
-  auto queued_delivery =
-      std::make_unique>(delivery);
-  const napi_status status = CallThreadsafeBridge(
-      context->callback_bridge, queued_delivery.get(), napi_tsfn_blocking);
-  if (status != napi_ok) {
-    RecordStreamError(context, "queue stream callback failed");
-    return 1;
-  }
-  (void)queued_delivery.release();
-
-  // `napi_tsfn_blocking` waits only for queue admission, not for the JavaScript
-  // callback to finish. The native stream callback must return the actual
-  // synchronous consumer result so liboliphaunt can stop delivery and drain to
-  // ReadyForQuery. Environment abort wakes this wait even if Node can no longer
-  // invoke JavaScript; the queued shared owner keeps the delivery alive until
-  // Node calls `CallStreamChunk` with a null environment to discard it.
-  bool aborted = false;
-  {
-    std::unique_lock lock(context->callback_bridge->release_mutex);
-    context->callback_bridge->release_condition.wait(
-        lock,
-        [&]() {
-          return delivery->completed.load(std::memory_order_acquire) ||
-              context->callback_bridge->aborted.load();
-        });
-    aborted = context->callback_bridge->aborted.load();
-  }
-  return aborted || context->callback_failed.load() ? 1 : 0;
-}
-
-enum class AsyncStreamCompletion {
-  Success,
-  RecoveredCallbackFailure,
-  NativeFailure,
-  AdapterMismatch,
-};
-
-AsyncStreamCompletion ClassifyAsyncStreamCompletion(
-    int32_t result,
-    bool callback_failed) {
-  // This is the complete native-result/callback-state truth table:
-  //
-  //   result == 0                         false -> success
-  //   result == 0                         true  -> adapter/ABI mismatch
-  //   result == CALLBACK_ABORTED          true  -> recovered callback failure
-  //   result == CALLBACK_ABORTED          false -> native/ABI failure
-  //   every negative or unknown positive  either -> native/recovery failure
-  //
-  // Only the exact recovered-abort status is allowed to preserve a callback
-  // throw. Every other non-success result is authoritative native state.
-  if (result == 0) {
-    return callback_failed ? AsyncStreamCompletion::AdapterMismatch
-                           : AsyncStreamCompletion::Success;
-  }
-  if (result == OLIPHAUNT_STREAM_CALLBACK_ABORTED && callback_failed) {
-    return AsyncStreamCompletion::RecoveredCallbackFailure;
-  }
-  return AsyncStreamCompletion::NativeFailure;
-}
-
-void ReleaseStreamEnvironmentReferences(
-    napi_env env,
-    AsyncStreamContext *context) {
-  if (env == nullptr) {
-    return;
-  }
-  if (context->callback_exception_holder != nullptr) {
-    (void)napi_delete_reference(env, context->callback_exception_holder);
-    context->callback_exception_holder = nullptr;
-  }
-  if (context->handle_ref != nullptr) {
-    (void)napi_delete_reference(env, context->handle_ref);
-    context->handle_ref = nullptr;
-  }
-}
-
-bool RejectRecordedStreamException(
-    napi_env env,
-    AsyncStreamContext *context) {
-  if (context->callback_exception_holder == nullptr) {
-    return false;
-  }
-  napi_value holder = nullptr;
-  napi_value exception = nullptr;
-  return napi_get_reference_value(
-             env, context->callback_exception_holder, &holder) == napi_ok &&
-      holder != nullptr &&
-      napi_get_element(env, holder, 0, &exception) == napi_ok &&
-      exception != nullptr &&
-      napi_reject_deferred(env, context->deferred, exception) == napi_ok;
-}
-
-void FinishAsyncStream(napi_env env, AsyncStreamContext *context) {
-  const AsyncStreamCompletion completion = ClassifyAsyncStreamCompletion(
-      context->result, context->callback_failed.load());
-  switch (completion) {
-    case AsyncStreamCompletion::Success: {
-      napi_value out = nullptr;
-      if (napi_get_undefined(env, &out) == napi_ok) {
-        (void)napi_resolve_deferred(env, context->deferred, out);
-      } else {
-        RejectDeferred(
-            env,
-            context->deferred,
-            "native liboliphaunt could not complete streaming");
-      }
-      break;
-    }
-    case AsyncStreamCompletion::RecoveredCallbackFailure: {
-      if (!RejectRecordedStreamException(env, context)) {
-        std::lock_guard guard(context->error_mutex);
-        RejectDeferred(
-            env,
-            context->deferred,
-            context->error.empty() ? "stream callback failed" : context->error);
-      }
-      break;
-    }
-    case AsyncStreamCompletion::NativeFailure:
-      RejectDeferred(
-          env,
-          context->deferred,
-          "native liboliphaunt protocol streaming failed: " + context->error);
-      break;
-    case AsyncStreamCompletion::AdapterMismatch:
-      RejectDeferred(
-          env,
-          context->deferred,
-          "native liboliphaunt protocol streaming reported success after the callback failed");
-      break;
-  }
-  ReleaseStreamEnvironmentReferences(env, context);
-}
-
-void FinalizeStreamCallback(napi_env env, void *data, void *) {
-  auto *context = static_cast(data);
-  if (CanDeliverBackgroundCompletion(
-          env, context->environment_operation, context->callback_bridge)) {
-    FinishAsyncStream(env, context);
-  } else if (env != nullptr) {
-    ReleaseStreamEnvironmentReferences(env, context);
-  }
-  ReleaseBackgroundContext(context);
-}
-
-void ExecuteAsyncStream(void *data) {
-  auto *context = static_cast(data);
-  if (!AdmitEnvironmentNativeCall(&context->environment_operation)) {
-    context->error = "native liboliphaunt environment is shutting down";
-    return;
-  }
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-  PauseNativeCallEntryForCleanupTest(&context->environment_operation);
-#endif
-  MarkEnvironmentNativeCallEntered(&context->environment_operation);
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-  WaitForFirstCleanupCancelForTest(&context->environment_operation);
-#endif
-  context->result = context->library->exec_protocol_raw_stream(
-      context->handle,
-      context->request.empty() ? nullptr : context->request.data(),
-      context->request.size(),
-      StreamChunk,
-      context);
-  if (ClassifyAsyncStreamCompletion(
-          context->result,
-          context->callback_failed.load()) == AsyncStreamCompletion::NativeFailure) {
-    std::lock_guard guard(context->error_mutex);
-    context->error = LastError(context->library.get(), context->handle);
-  }
-}
-
-napi_value ExecProtocolRawStream(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 3);
-  if (args.empty()) return nullptr;
-  NativeHandleBox *box = GetHandleBox(env, args[0]);
-  if (box == nullptr) return nullptr;
-  auto context = std::make_unique();
-  context->library = box->library;
-  context->handle = box->handle;
-  context->callback_bridge = std::make_shared();
-  context->request = GetBytes(env, args[1]);
-  if (ExceptionPending(env)) return nullptr;
-
-  napi_value promise = nullptr;
-  napi_value resource_name = nullptr;
-  bool setup_ok =
-      Check(env, napi_create_promise(env, &context->deferred, &promise), "create stream promise") &&
-      Check(env, napi_create_reference(env, args[0], 1, &context->handle_ref),
-            "retain native handle for stream") &&
-      Check(env,
-            napi_create_string_utf8(
-                env, "oliphaunt.execProtocolRawStream", NAPI_AUTO_LENGTH, &resource_name),
-            "create stream resource name") &&
-      Check(env,
-            napi_create_threadsafe_function(
-                env,
-                args[2],
-                nullptr,
-                resource_name,
-                1,
-                1,
-                context.get(),
-                FinalizeStreamCallback,
-                context.get(),
-                CallStreamChunk,
-                &context->callback_bridge->function),
-            "create stream callback bridge");
-  if (!setup_ok) {
-    if (context->handle_ref != nullptr) {
-      (void)napi_delete_reference(env, context->handle_ref);
-    }
-    return nullptr;
-  }
-  AsyncStreamContext *raw_context = context.release();
-  if (!RegisterEnvironmentOperation(env, &raw_context->environment_operation)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->callback_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-  RegisterThreadsafeBridge(
-      raw_context->environment_operation.environment,
-      raw_context->callback_bridge);
-  if (!RefreshEnvironmentQuiesceHook(
-          env, raw_context->environment_operation.environment) ||
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-      !PrefillStreamQueueForCleanupTest(env, raw_context) ||
-#endif
-      !StartBackgroundOperation(
-          env,
-          &raw_context->environment_operation,
-          raw_context->callback_bridge,
-          ExecuteAsyncStream,
-          ReleaseBackgroundContext,
-          raw_context)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->callback_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-  return promise;
-}
-
-enum class AsyncArchiveKind { Backup, Restore };
-
-struct AsyncArchiveContext {
-  std::atomic lifetime_references = 2;
-  EnvironmentOperation environment_operation;
-  std::shared_ptr completion_bridge;
-  napi_deferred deferred = nullptr;
-  napi_ref handle_ref = nullptr;
-  std::shared_ptr library;
-  std::string library_path;
-  OliphauntHandle *handle = nullptr;
-  AsyncArchiveKind kind = AsyncArchiveKind::Backup;
-  std::string destination;
-  std::vector bytes;
-  OliphauntResponse response = {};
-  int32_t result = -1;
-  std::string error;
-
-  ~AsyncArchiveContext() {
-    if (kind == AsyncArchiveKind::Backup && library != nullptr &&
-        (response.data != nullptr || response.len != 0)) {
-      library->free_response(&response);
-    }
-  }
-};
-
-void ExecuteAsyncArchive(void *data) {
-  auto *context = static_cast(data);
-  if (EnvironmentIsShuttingDown(&context->environment_operation)) {
-    context->error = "native liboliphaunt environment is shutting down";
-    return;
-  }
-  if (context->library == nullptr) {
-    context->library = LoadNativeLibrary(context->library_path, &context->error);
-    if (context->library == nullptr) {
-      return;
-    }
-  }
-  if (!AdmitEnvironmentNativeCall(&context->environment_operation)) {
-    context->error = "native liboliphaunt environment is shutting down";
-    return;
-  }
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-  PauseNativeCallEntryForCleanupTest(&context->environment_operation);
-#endif
-  MarkEnvironmentNativeCallEntered(&context->environment_operation);
-#if defined(OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING) && \
-    OLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING
-  WaitForFirstCleanupCancelForTest(&context->environment_operation);
-#endif
-  if (context->kind == AsyncArchiveKind::Backup) {
-    context->result = context->library->backup(context->handle, &context->response);
-  } else {
-    OliphauntRestoreOptions options = {};
-    options.abi_version = OLIPHAUNT_ABI_VERSION;
-    options.destination = context->destination.c_str();
-    options.data = context->bytes.empty() ? nullptr : context->bytes.data();
-    options.len = context->bytes.size();
-    context->result = context->library->restore(&options);
-  }
-  if (context->result != 0) {
-    context->error = LastError(context->library.get(), context->handle);
-  }
-}
-
-void FinalizeAsyncArchive(napi_env env, void *data, void *) {
-  auto *context = static_cast(data);
-  const bool deliver = CanDeliverBackgroundCompletion(
-      env, context->environment_operation, context->completion_bridge);
-  if (env != nullptr && context->handle_ref != nullptr) {
-    (void)napi_delete_reference(env, context->handle_ref);
-    context->handle_ref = nullptr;
-  }
-
-  if (deliver && context->result != 0) {
-    if (context->kind == AsyncArchiveKind::Backup) {
-      context->library->free_response(&context->response);
-      context->response.data = nullptr;
-      context->response.len = 0;
-    }
-    const char *operation = context->kind == AsyncArchiveKind::Backup ? "backup" : "restore";
-    RejectDeferred(
-        env,
-        context->deferred,
-        std::string("native liboliphaunt ") + operation + " failed: " + context->error);
-  } else if (deliver && context->kind == AsyncArchiveKind::Backup) {
-    napi_value response = MakeResponse(env, context->library.get(), &context->response);
-    if (response != nullptr) {
-      (void)napi_resolve_deferred(env, context->deferred, response);
-    } else {
-      RejectResponseCreation(env, context->deferred);
-    }
-  } else if (deliver) {
-    napi_value out = nullptr;
-    if (napi_get_undefined(env, &out) == napi_ok) {
-      (void)napi_resolve_deferred(env, context->deferred, out);
-    } else {
-      RejectDeferred(env, context->deferred, "native liboliphaunt could not complete restore");
-    }
-  }
-  ReleaseBackgroundContext(context);
-}
-
-napi_value QueueAsyncArchive(
-    napi_env env,
-    AsyncArchiveKind kind,
-    std::shared_ptr library,
-    std::string library_path,
-    OliphauntHandle *handle,
-    napi_value handle_value,
-    std::string destination,
-    std::vector bytes) {
-  auto context = std::make_unique();
-  context->library = std::move(library);
-  context->library_path = std::move(library_path);
-  context->handle = handle;
-  context->kind = kind;
-  context->destination = std::move(destination);
-  context->bytes = std::move(bytes);
-  context->completion_bridge = std::make_shared();
-
-  napi_value promise = nullptr;
-  napi_value resource_name = nullptr;
-  const char *resource = kind == AsyncArchiveKind::Backup
-      ? "oliphaunt.backup"
-      : "oliphaunt.restore";
-  if (!Check(env, napi_create_promise(env, &context->deferred, &promise), "create archive promise")) {
-    return nullptr;
-  }
-  if (handle_value != nullptr &&
-      !Check(env, napi_create_reference(env, handle_value, 1, &context->handle_ref),
-             "retain native handle for archive operation")) {
-    return nullptr;
-  }
-  if (!Check(env, napi_create_string_utf8(env, resource, NAPI_AUTO_LENGTH, &resource_name),
-             "create archive resource name") ||
-      !Check(env,
-             napi_create_threadsafe_function(
-                 env,
-                 nullptr,
-                 nullptr,
-                 resource_name,
-                 1,
-                 1,
-                 context.get(),
-                 FinalizeAsyncArchive,
-                 context.get(),
-                 IgnoreBackgroundCompletion,
-                 &context->completion_bridge->function),
-             "create native archive completion")) {
-    if (context->handle_ref != nullptr) {
-      (void)napi_delete_reference(env, context->handle_ref);
-    }
-    return nullptr;
-  }
-  AsyncArchiveContext *raw_context = context.release();
-  if (!RegisterEnvironmentOperation(env, &raw_context->environment_operation)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->completion_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-  RegisterThreadsafeBridge(
-      raw_context->environment_operation.environment, raw_context->completion_bridge);
-  if (!RefreshEnvironmentQuiesceHook(
-          env, raw_context->environment_operation.environment) ||
-      !StartBackgroundOperation(
-          env,
-          &raw_context->environment_operation,
-          raw_context->completion_bridge,
-          ExecuteAsyncArchive,
-          ReleaseBackgroundContext,
-          raw_context)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->completion_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-  return promise;
-}
-
-napi_value Backup(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 1);
-  if (args.empty()) return nullptr;
-  NativeHandleBox *box = GetHandleBox(env, args[0]);
-  if (box == nullptr) return nullptr;
-  return QueueAsyncArchive(
-      env,
-      AsyncArchiveKind::Backup,
-      box->library,
-      std::string(),
-      box->handle,
-      args[0],
-      std::string(),
-      std::vector());
-}
-
-napi_value Restore(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 1);
-  if (args.empty()) return nullptr;
-  napi_value options = args[0];
-  std::string library_path = GetString(env, options, "libraryPath");
-  std::string destination = GetString(env, options, "destination");
-  std::vector bytes = GetBytes(env, GetNamed(env, options, "bytes"));
-  if (ExceptionPending(env)) return nullptr;
-  return QueueAsyncArchive(
-      env,
-      AsyncArchiveKind::Restore,
-      nullptr,
-      std::move(library_path),
-      nullptr,
-      nullptr,
-      std::move(destination),
-      std::move(bytes));
-}
-
-napi_value Cancel(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 1);
-  if (args.empty()) return nullptr;
-  NativeHandleBox *box = GetHandleBox(env, args[0]);
-  if (box == nullptr) return nullptr;
-  int32_t rc = box->library->cancel(box->handle);
-  if (rc != 0) {
-    Throw(env, "native liboliphaunt cancel failed: " + LastError(box->library.get(), box->handle));
-    return nullptr;
-  }
-  napi_value out = nullptr;
-  Check(env, napi_get_undefined(env, &out), "create undefined");
-  return out;
-}
-
-struct AsyncDetachContext {
-  std::atomic lifetime_references = 2;
-  EnvironmentOperation environment_operation;
-  std::shared_ptr completion_bridge;
-  napi_deferred deferred = nullptr;
-  napi_ref handle_ref = nullptr;
-  NativeHandleBox *box = nullptr;
-  std::shared_ptr library;
-  OliphauntHandle *handle = nullptr;
-  uint64_t generation = 0;
-  int32_t result = -1;
-  bool stale = false;
-  std::string error;
-};
-
-void ExecuteAsyncDetach(void *data) {
-  auto *context = static_cast(data);
-  if (EnvironmentIsShuttingDown(&context->environment_operation)) {
-    context->stale = true;
-    context->error = "native liboliphaunt environment is shutting down";
-    return;
-  }
-  std::lock_guard guard(context->library->lifecycle_mutex);
-  if (context->library->terminally_closed ||
-      context->library->resident_handle != context->handle ||
-      context->library->resident_generation != context->generation) {
-    context->stale = true;
-    context->error = "native liboliphaunt environment has already shut down";
-    return;
-  }
-  context->result = context->library->detach(context->handle);
-  if (context->result != 0) {
-    context->library->detach_pending = true;
-    context->error =
-        "native liboliphaunt detach failed: " +
-        LastError(context->library.get(), context->handle);
-    return;
-  }
-  context->library->detach_pending = false;
-}
-
-void FinalizeAsyncDetach(napi_env env, void *data, void *) {
-  auto *context = static_cast(data);
-  const bool deliver = CanDeliverBackgroundCompletion(
-      env, context->environment_operation, context->completion_bridge);
-  if (deliver && (context->result == 0 || context->stale)) {
-    // From the logical owner's perspective an exact-generation handle that is
-    // already terminally unavailable is closed, not retryable. NativeBinding
-    // reserves detach rejection for failures that leave this handle active.
-    context->box->handle = nullptr;
-    napi_value out = nullptr;
-    if (napi_get_undefined(env, &out) == napi_ok) {
-      (void)napi_resolve_deferred(env, context->deferred, out);
-    }
-    // Logical detach already succeeded. Failure to materialize its JavaScript
-    // completion cannot safely be reported as a retryable native rejection.
-  } else if (deliver) {
-    // A failed logical detach remains retryable through Database.close().
-    context->box->detached = false;
-    RejectDeferred(
-        env,
-        context->deferred,
-        context->error);
-  }
-  if (env != nullptr && context->handle_ref != nullptr) {
-    (void)napi_delete_reference(env, context->handle_ref);
-    context->handle_ref = nullptr;
-  }
-  ReleaseBackgroundContext(context);
-}
-
-napi_value Detach(napi_env env, napi_callback_info info) {
-  auto args = Args(env, info, 1);
-  if (args.empty()) return nullptr;
-  NativeHandleBox *box = GetHandleBox(env, args[0]);
-  if (box == nullptr) return nullptr;
-  auto context = std::make_unique();
-  context->box = box;
-  context->library = box->library;
-  context->handle = box->handle;
-  context->generation = box->generation;
-  context->completion_bridge = std::make_shared();
-
-  napi_value promise = nullptr;
-  napi_value resource_name = nullptr;
-  if (!Check(env, napi_create_promise(env, &context->deferred, &promise), "create detach promise") ||
-      !Check(env, napi_create_reference(env, args[0], 1, &context->handle_ref),
-             "retain native handle during detach") ||
-      !Check(env,
-             napi_create_string_utf8(
-                 env, "oliphaunt.detach", NAPI_AUTO_LENGTH, &resource_name),
-             "create detach resource name") ||
-      !Check(env,
-             napi_create_threadsafe_function(
-                 env,
-                 nullptr,
-                 nullptr,
-                 resource_name,
-                 1,
-                 1,
-                 context.get(),
-                 FinalizeAsyncDetach,
-                 context.get(),
-                 IgnoreBackgroundCompletion,
-                 &context->completion_bridge->function),
-             "create native detach completion")) {
-    if (context->handle_ref != nullptr) {
-      (void)napi_delete_reference(env, context->handle_ref);
-    }
-    return nullptr;
-  }
-  AsyncDetachContext *raw_context = context.release();
-  if (!RegisterEnvironmentOperation(env, &raw_context->environment_operation)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->completion_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-  RegisterThreadsafeBridge(
-      raw_context->environment_operation.environment, raw_context->completion_bridge);
-  if (!RefreshEnvironmentQuiesceHook(
-          env, raw_context->environment_operation.environment) ||
-      !StartBackgroundOperation(
-          env,
-          &raw_context->environment_operation,
-          raw_context->completion_bridge,
-          ExecuteAsyncDetach,
-          ReleaseBackgroundContext,
-          raw_context)) {
-    AbortBackgroundOperationSetup(
-        &raw_context->environment_operation, raw_context->completion_bridge);
-    ReleaseBackgroundContext(raw_context);
-    return nullptr;
-  }
-  // Reject new work immediately while the native detach runs. On failure the
-  // completion callback restores the retryable logical handle.
-  box->detached = true;
-  return promise;
-}
-
-napi_value Init(napi_env env, napi_value exports) {
-  auto *environment = new AddonEnvironment{env};
-  // Node-API 8 pairs asynchronous registration with removal through the
-  // returned opaque handle. Retain that handle explicitly; the addon never
-  // relies on a null output pointer being accepted by a particular Node build.
-  if (!Check(
-          env,
-          napi_add_async_cleanup_hook(
-              env,
-              CleanupEnvironment,
-              environment,
-              &environment->async_cleanup_handle),
-          "register asynchronous native environment cleanup")) {
-    delete environment;
-    return nullptr;
-  }
-  {
-    std::lock_guard guard(g_environments_mutex);
-    g_environments[env] = environment;
-  }
-  if (!RefreshEnvironmentQuiesceHook(env, environment)) {
-    (void)napi_remove_async_cleanup_hook(environment->async_cleanup_handle);
-    {
-      std::lock_guard guard(g_environments_mutex);
-      g_environments.erase(env);
-    }
-    delete environment;
-    return nullptr;
-  }
-  const napi_property_descriptor descriptors[] = {
-      {"version", nullptr, Version, nullptr, nullptr, nullptr, napi_default, nullptr},
-      {"open", nullptr, Open, nullptr, nullptr, nullptr, napi_default, nullptr},
-      {"execProtocolRaw", nullptr, ExecProtocolRaw, nullptr, nullptr, nullptr, napi_default, nullptr},
-      {"execSimpleQuery", nullptr, ExecSimpleQuery, nullptr, nullptr, nullptr, napi_default, nullptr},
-      {"execProtocolRawStream", nullptr, ExecProtocolRawStream, nullptr, nullptr, nullptr, napi_default, nullptr},
-      {"backup", nullptr, Backup, nullptr, nullptr, nullptr, napi_default, nullptr},
-      {"restore", nullptr, Restore, nullptr, nullptr, nullptr, napi_default, nullptr},
-      {"cancel", nullptr, Cancel, nullptr, nullptr, nullptr, napi_default, nullptr},
-      {"detach", nullptr, Detach, nullptr, nullptr, nullptr, napi_default, nullptr},
-      {"createForgottenHandleRecoveryToken", nullptr,
-       CreateForgottenHandleRecoveryToken, nullptr, nullptr, nullptr,
-       napi_default, nullptr},
-      {"queueForgottenHandleRecovery", nullptr, QueueForgottenHandleRecovery,
-       nullptr, nullptr, nullptr, napi_default, nullptr},
-  };
-  Check(env, napi_define_properties(env, exports, sizeof(descriptors) / sizeof(descriptors[0]), descriptors),
-        "define exports");
-  return exports;
-}
-
-}  // namespace
-
-NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
diff --git a/src/runtimes/node-direct/package.json b/src/runtimes/node-direct/package.json
deleted file mode 100644
index 85b3dc29f..000000000
--- a/src/runtimes/node-direct/package.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
-  "name": "@oliphaunt/node-direct",
-  "version": "0.2.0",
-  "description": "Node-API native direct adapter for Oliphaunt.",
-  "license": "MIT",
-  "private": true,
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/node-direct"
-  },
-  "oliphaunt": {
-    "liboliphauntVersion": "0.2.0"
-  },
-  "files": [
-    "native",
-    "packages",
-    "tools",
-    "README.md",
-    "CHANGELOG.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md"
-  ],
-  "engines": {
-    "node": ">=22.13 <25"
-  },
-  "devDependencies": {
-    "node-api-headers": "1.9.0"
-  }
-}
diff --git a/src/runtimes/node-direct/packages/darwin-arm64/package.json b/src/runtimes/node-direct/packages/darwin-arm64/package.json
deleted file mode 100644
index 8cd2ac3a7..000000000
--- a/src/runtimes/node-direct/packages/darwin-arm64/package.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
-  "name": "@oliphaunt/node-direct-darwin-arm64",
-  "version": "0.2.0",
-  "description": "macOS arm64 prebuilt Node-API native direct adapter for Oliphaunt.",
-  "license": "MIT",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/node-direct/packages/darwin-arm64"
-  },
-  "os": [
-    "darwin"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "macos-arm64"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "files": [
-    "prebuilds",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md"
-  ],
-  "exports": {
-    "./oliphaunt_node.node": "./prebuilds/oliphaunt_node.node",
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/node-direct/packages/linux-arm64-gnu/package.json b/src/runtimes/node-direct/packages/linux-arm64-gnu/package.json
deleted file mode 100644
index 2c8b1d626..000000000
--- a/src/runtimes/node-direct/packages/linux-arm64-gnu/package.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "@oliphaunt/node-direct-linux-arm64-gnu",
-  "version": "0.2.0",
-  "description": "Linux arm64 glibc prebuilt Node-API native direct adapter for Oliphaunt.",
-  "license": "MIT",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/node-direct/packages/linux-arm64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "linux-arm64-gnu"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "files": [
-    "prebuilds",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md"
-  ],
-  "exports": {
-    "./oliphaunt_node.node": "./prebuilds/oliphaunt_node.node",
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/node-direct/packages/linux-x64-gnu/package.json b/src/runtimes/node-direct/packages/linux-x64-gnu/package.json
deleted file mode 100644
index 5b1a437f1..000000000
--- a/src/runtimes/node-direct/packages/linux-x64-gnu/package.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-  "name": "@oliphaunt/node-direct-linux-x64-gnu",
-  "version": "0.2.0",
-  "description": "Linux x64 glibc prebuilt Node-API native direct adapter for Oliphaunt.",
-  "license": "MIT",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/node-direct/packages/linux-x64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "linux-x64-gnu"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "files": [
-    "prebuilds",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md"
-  ],
-  "exports": {
-    "./oliphaunt_node.node": "./prebuilds/oliphaunt_node.node",
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/node-direct/packages/win32-x64-msvc/package.json b/src/runtimes/node-direct/packages/win32-x64-msvc/package.json
deleted file mode 100644
index d93370baa..000000000
--- a/src/runtimes/node-direct/packages/win32-x64-msvc/package.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
-  "name": "@oliphaunt/node-direct-win32-x64-msvc",
-  "version": "0.2.0",
-  "description": "Windows x64 MSVC prebuilt Node-API native direct adapter for Oliphaunt.",
-  "license": "MIT",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/node-direct/packages/win32-x64-msvc"
-  },
-  "os": [
-    "win32"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "windows-x64-msvc"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "files": [
-    "prebuilds",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md"
-  ],
-  "exports": {
-    "./oliphaunt_node.node": "./prebuilds/oliphaunt_node.node",
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/node-direct/release.toml b/src/runtimes/node-direct/release.toml
deleted file mode 100644
index 134447a2a..000000000
--- a/src/runtimes/node-direct/release.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-id = "oliphaunt-node-direct"
-owner = "@oliphaunt/node-direct"
-kind = "runtime"
-publish_targets = ["npm", "github-release-assets"]
-registry_packages = [
-  "npm:@oliphaunt/node-direct-darwin-arm64",
-  "npm:@oliphaunt/node-direct-linux-x64-gnu",
-  "npm:@oliphaunt/node-direct-linux-arm64-gnu",
-  "npm:@oliphaunt/node-direct-win32-x64-msvc",
-]
-release_artifacts = ["node-api-prebuilds", "npm-optional-platform-packages"]
-
-[compatibility_versions.oliphaunt-node-direct-liboliphaunt]
-source_product = "liboliphaunt-native"
-path = "src/runtimes/node-direct/package.json"
-parser = "json:oliphaunt.liboliphauntVersion"
diff --git a/src/runtimes/node-direct/tools/check-native-source.sh b/src/runtimes/node-direct/tools/check-native-source.sh
deleted file mode 100755
index 361e95173..000000000
--- a/src/runtimes/node-direct/tools/check-native-source.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-root="$(git rev-parse --show-toplevel)"
-cd "$root"
-
-command -v c++ >/dev/null || { echo "Node Direct compile requires c++" >&2; exit 1; }
-node_include="$(node -e '
-const path = require("node:path");
-const fs = require("node:fs");
-const adjacent = path.resolve(process.execPath, "../../include/node");
-process.stdout.write(fs.existsSync(path.join(adjacent, "node_api.h"))
-  ? adjacent
-  : path.dirname(require.resolve("node-api-headers/include/node_api.h", {
-      paths: [process.cwd(), path.join(process.cwd(), "src/runtimes/node-direct")]
-    })));
-')"
-test -f "$node_include/node_api.h" || { echo "Node-API headers not found" >&2; exit 1; }
-
-source=src/runtimes/node-direct/native/node-addon/oliphaunt_node.cc
-include=src/runtimes/liboliphaunt/native/include
-c++ -std=c++17 -DNAPI_VERSION=8 -DNODE_GYP_MODULE_NAME=oliphaunt_node \
-  -I"$node_include" -I"$include" -fsyntax-only "$source"
-c++ -std=c++17 -DNAPI_VERSION=8 -DNODE_GYP_MODULE_NAME=oliphaunt_node \
-  -DOLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING=1 \
-  -I"$node_include" -I"$include" -fsyntax-only "$source"
-c++ -std=c++17 -DOLIPHAUNT_BUILDING_DLL -I"$include" -fsyntax-only \
-  src/runtimes/node-direct/native/node-addon/fixtures/fake_liboliphaunt.cc
diff --git a/src/runtimes/node-direct/tools/node-addon-cleanup-lifecycle.test.mjs b/src/runtimes/node-direct/tools/node-addon-cleanup-lifecycle.test.mjs
deleted file mode 100644
index bc9033745..000000000
--- a/src/runtimes/node-direct/tools/node-addon-cleanup-lifecycle.test.mjs
+++ /dev/null
@@ -1,1228 +0,0 @@
-import assert from "node:assert/strict";
-import { existsSync, readFileSync } from "node:fs";
-import { copyFile, mkdir, mkdtemp, rm } from "node:fs/promises";
-import { tmpdir } from "node:os";
-import path from "node:path";
-import { createRequire } from "node:module";
-import { fileURLToPath } from "node:url";
-import { spawnSync } from "node:child_process";
-import {
-  Worker,
-  isMainThread,
-  parentPort,
-  workerData,
-} from "node:worker_threads";
-
-const scriptPath = fileURLToPath(import.meta.url);
-const workspaceRoot = path.resolve(path.dirname(scriptPath), "../../../..");
-const require = createRequire(import.meta.url);
-const streamFixtureRequest = Object.freeze({
-  normal: 0x01,
-  failRecovery: 0xf1,
-  unknownAfterCallback: 0xf2,
-  successAfterCallback: 0xf3,
-  abortWithoutCallback: 0xf4,
-  failureWithoutCallback: 0xf5,
-  unknownWithoutCallback: 0xf6,
-});
-
-function parseArgs(argv) {
-  const parsed = {};
-  for (let index = 0; index < argv.length; index += 2) {
-    const key = argv[index];
-    const value = argv[index + 1];
-    if (!key?.startsWith("--") || value === undefined) {
-      throw new Error(`invalid cleanup lifecycle argument: ${key ?? ""}`);
-    }
-    const name = key
-      .slice(2)
-      .replace(/-([a-z])/gu, (_match, letter) => letter.toUpperCase());
-    parsed[name] = value;
-  }
-  return parsed;
-}
-
-function loadAddon(addonPath) {
-  return require(addonPath);
-}
-
-async function openFake(addon, libraryPath, root) {
-  return addon.open({
-    libraryPath,
-    pgdata: path.join(root, "pgdata"),
-    runtimeDirectory: path.join(root, "runtime"),
-    username: "postgres",
-    database: "postgres",
-    startupArgs: [],
-  });
-}
-
-function eventsFrom(logPath) {
-  if (!existsSync(logPath)) {
-    return [];
-  }
-  return readFileSync(logPath, "utf8")
-    .split(/\r?\n/u)
-    .filter((entry) => entry.length > 0);
-}
-
-function waitForWorkerMessage(worker, expectedMessage) {
-  return new Promise((resolve, reject) => {
-    const cleanup = () => {
-      worker.off("message", onMessage);
-      worker.off("messageerror", onMessageError);
-      worker.off("error", onError);
-      worker.off("exit", onExit);
-    };
-    const fail = (error, terminate = true) => {
-      cleanup();
-      reject(error);
-      if (terminate) {
-        void worker.terminate();
-      }
-    };
-    const onMessage = (received) => {
-      try {
-        assert.equal(received, expectedMessage);
-        cleanup();
-        resolve(received);
-      } catch (error) {
-        fail(error);
-      }
-    };
-    const onMessageError = (error) => {
-      fail(error instanceof Error ? error : new Error("cleanup lifecycle worker message failed"));
-    };
-    const onError = (error) => {
-      fail(error);
-    };
-    const onExit = (code) => {
-      fail(
-        new Error(
-          `cleanup lifecycle worker exited with status ${code} before ${expectedMessage}`,
-        ),
-        false,
-      );
-    };
-    worker.once("message", onMessage);
-    worker.once("messageerror", onMessageError);
-    worker.once("error", onError);
-    worker.once("exit", onExit);
-  });
-}
-
-function observeWorkerExit(worker) {
-  return new Promise((resolve) => {
-    let workerError;
-    worker.once("error", (error) => {
-      workerError = error;
-    });
-    worker.once("exit", (code) => {
-      resolve({ code, error: workerError });
-    });
-  });
-}
-
-async function requireWorkerExit(exitObservation, expectedCode) {
-  const { code, error } = await exitObservation;
-  if (error !== undefined) {
-    throw error;
-  }
-  assert.equal(code, expectedCode, "cleanup lifecycle worker exit status");
-}
-
-async function runWorker() {
-  const { role, addonPath, libraryPath, root } = workerData;
-  const addon = loadAddon(addonPath);
-  if (role === "load-only") {
-    parentPort.postMessage("loaded");
-    parentPort.close();
-    return;
-  }
-  if (role === "open-and-detach") {
-    const handle = await openFake(addon, libraryPath, root);
-    await addon.detach(handle);
-    parentPort.postMessage("detached");
-    await new Promise((resolve) => {
-      parentPort.once("message", (message) => {
-        assert.equal(message, "finish");
-        resolve();
-      });
-    });
-    parentPort.close();
-    return;
-  }
-  if (role === "open-and-wait") {
-    globalThis.__oliphauntCleanupLifecycleWorkerHandle = await openFake(
-      addon,
-      libraryPath,
-      root,
-    );
-    parentPort.postMessage("opened");
-    await new Promise((resolve) => {
-      parentPort.once("message", resolve);
-    });
-    return;
-  }
-  if (role === "open-with-active-query") {
-    const handle = await openFake(addon, libraryPath, root);
-    globalThis.__oliphauntCleanupRaceHandle = handle;
-    globalThis.__oliphauntCleanupRaceOperation = addon
-      .execProtocolRaw(handle, new Uint8Array([1]))
-      .catch(() => undefined);
-    parentPort.postMessage("queued");
-    return;
-  }
-  if (role === "open-with-queued-query") {
-    const handle = await openFake(addon, libraryPath, root);
-    globalThis.__oliphauntCleanupRaceHandle = handle;
-    globalThis.__oliphauntCleanupRaceOperation = addon
-      .execProtocolRaw(handle, new Uint8Array([1]))
-      .catch(() => undefined);
-    parentPort.postMessage("queued");
-    return;
-  }
-  if (role === "open-with-active-stream") {
-    const handle = await openFake(addon, libraryPath, root);
-    globalThis.__oliphauntCleanupRaceHandle = handle;
-    globalThis.__oliphauntCleanupRaceOperation = addon
-      .execProtocolRawStream(handle, new Uint8Array([1]), () => undefined)
-      .catch(() => undefined);
-    parentPort.postMessage("queued");
-    return;
-  }
-  if (role === "open-with-stream-call-blocked") {
-    const handle = await openFake(addon, libraryPath, root);
-    globalThis.__oliphauntCleanupRaceHandle = handle;
-    globalThis.__oliphauntCleanupRaceOperation = addon
-      .execProtocolRawStream(handle, new Uint8Array([1]), () => {
-        assert.fail("the prefilled callback queue must not drain before Worker teardown");
-      })
-      .catch(() => undefined);
-    parentPort.postMessage("queued");
-    Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 60_000);
-    return;
-  }
-  if (role === "open-with-stream-delivery-wait") {
-    const handle = await openFake(addon, libraryPath, root);
-    globalThis.__oliphauntCleanupRaceHandle = handle;
-    globalThis.__oliphauntCleanupRaceOperation = addon
-      .execProtocolRawStream(handle, new Uint8Array([1]), () => {
-        assert.fail("the admitted callback must remain queued until Worker teardown");
-      })
-      .catch(() => undefined);
-    parentPort.postMessage("queued");
-    Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 60_000);
-    return;
-  }
-  if (role === "open-with-active-backup") {
-    const handle = await openFake(addon, libraryPath, root);
-    globalThis.__oliphauntCleanupRaceHandle = handle;
-    globalThis.__oliphauntCleanupRaceOperation = addon.backup(handle).catch(() => undefined);
-    parentPort.postMessage("queued");
-    return;
-  }
-  throw new Error(`unknown cleanup lifecycle worker role: ${role}`);
-}
-
-async function collectGarbageUntilCollected(signal) {
-  assert.equal(typeof globalThis.gc, "function", "GC lifecycle child must run with --expose-gc");
-  for (let attempt = 0; attempt < 200; attempt += 1) {
-    globalThis.gc();
-    await new Promise((resolve) => setImmediate(resolve));
-    if (signal.collected) {
-      return;
-    }
-  }
-  throw new Error("Node did not collect the unreachable native handle after 200 forced GC cycles");
-}
-
-function observeCollection(value) {
-  const signal = { collected: false, registry: undefined };
-  signal.registry = new FinalizationRegistry(() => {
-    signal.collected = true;
-  });
-  signal.registry.register(value, undefined);
-  return signal;
-}
-
-async function waitForEvent(logPath, expectedEvent) {
-  const deadline = Date.now() + 5_000;
-  while (Date.now() < deadline) {
-    if (eventsFrom(logPath).includes(expectedEvent)) {
-      return;
-    }
-    await new Promise((resolve) => setTimeout(resolve, 1));
-  }
-  throw new Error(`native lifecycle event did not arrive: ${expectedEvent}`);
-}
-
-async function runChild(options) {
-  const copiedImageScenario = options.scenario.startsWith("copied-image-");
-  const addon = copiedImageScenario ? undefined : loadAddon(options.addon);
-  switch (options.scenario) {
-    case "invalid-library-path": {
-      assert.throws(
-        () => addon.version(""),
-        /liboliphaunt path must not be empty/u,
-      );
-      assert.throws(
-        () => addon.version(`${options.library}\0ignored-suffix`),
-        /liboliphaunt path must not contain a null byte/u,
-      );
-      return;
-    }
-    case "explicit-detach":
-    case "unicode-library-path": {
-      const handle = await openFake(addon, options.library, options.root);
-      await addon.detach(handle);
-      return;
-    }
-    case "active-exit": {
-      globalThis.__oliphauntCleanupLifecycleHandle = await openFake(
-        addon,
-        options.library,
-        options.root,
-      );
-      return;
-    }
-    case "forced-process-exit-active": {
-      globalThis.__oliphauntCleanupLifecycleHandle = await openFake(
-        addon,
-        options.library,
-        options.root,
-      );
-      // Node intentionally bypasses N-API environment cleanup hooks here.
-      // The real liboliphaunt process-level atexit handler owns this abrupt
-      // process teardown; this addon fixture must not claim otherwise.
-      process.exit(0);
-    }
-    case "gc-finalizer": {
-      let handle = await openFake(addon, options.library, options.root);
-      const collection = observeCollection(handle);
-      handle = undefined;
-      assert.equal(handle, undefined);
-      await collectGarbageUntilCollected(collection);
-      const reopened = await openFake(addon, options.library, options.root);
-      await addon.detach(reopened);
-      return;
-    }
-    case "gc-detach-recovery": {
-      let handle = await openFake(addon, options.library, options.root);
-      const collection = observeCollection(handle);
-      handle = undefined;
-      assert.equal(handle, undefined);
-      await collectGarbageUntilCollected(collection);
-      await assert.rejects(
-        openFake(addon, options.library, options.root),
-        /could not recover the previous logical handle/u,
-      );
-      const recovered = await openFake(addon, options.library, options.root);
-      await addon.detach(recovered);
-      assert.equal(
-        eventsFrom(options.log).includes("init-while-active"),
-        false,
-        "reopen must recover the retained failed-detach owner before init",
-      );
-      return;
-    }
-    case "forgotten-token-generation-guard": {
-      const staleHandle = await openFake(addon, options.library, options.root);
-      const staleToken = addon.createForgottenHandleRecoveryToken(staleHandle);
-      await addon.detach(staleHandle);
-
-      let currentHandle = await openFake(addon, options.library, options.root);
-      const currentToken = addon.createForgottenHandleRecoveryToken(currentHandle);
-      assert.equal(
-        addon.queueForgottenHandleRecovery(staleToken),
-        false,
-        "a recovery token from an older logical generation must not mark the current owner",
-      );
-      assert.equal(
-        addon.queueForgottenHandleRecovery(currentToken),
-        true,
-        "the current logical generation must be marked for next-open recovery",
-      );
-      currentHandle = undefined;
-      const recovered = await openFake(addon, options.library, options.root);
-      await addon.detach(recovered);
-      return;
-    }
-    case "async-query-cancel": {
-      const handle = await openFake(addon, options.library, options.root);
-      const query = addon.execProtocolRaw(handle, new Uint8Array([1]));
-      assert.equal(query instanceof Promise, true, "native query must return a Promise");
-      await waitForEvent(options.log, "query-started");
-      addon.cancel(handle);
-      await assert.rejects(query, /fake query was cancelled/u);
-      await addon.detach(handle);
-      return;
-    }
-    case "async-archive-timers": {
-      const handle = await openFake(addon, options.library, options.root);
-      let backupSettled = false;
-      const backup = addon.backup(handle).finally(() => {
-        backupSettled = true;
-      });
-      await new Promise((resolve) => setTimeout(resolve, 0));
-      assert.equal(backupSettled, false, "backup must not block the Node.js event loop");
-      assert.deepEqual([...await backup], [1, 2, 3]);
-
-      let restoreSettled = false;
-      const restore = addon.restore({
-        libraryPath: options.library,
-        destination: path.join(options.root, "restored"),
-        bytes: new Uint8Array([1, 2, 3]),
-      }).finally(() => {
-        restoreSettled = true;
-      });
-      await new Promise((resolve) => setTimeout(resolve, 0));
-      assert.equal(restoreSettled, false, "restore must not block the Node.js event loop");
-      await restore;
-      await addon.detach(handle);
-      return;
-    }
-    case "async-open-stream-detach-timers": {
-      let openSettled = false;
-      const opening = openFake(addon, options.library, options.root).finally(() => {
-        openSettled = true;
-      });
-      assert.equal(opening instanceof Promise, true, "native open must return a Promise");
-      await new Promise((resolve) => setTimeout(resolve, 0));
-      assert.equal(openSettled, false, "open must not block the Node.js event loop");
-      const handle = await opening;
-
-      const chunks = [];
-      let streamSettled = false;
-      const streaming = addon
-        .execProtocolRawStream(handle, new Uint8Array([1]), (chunk) => {
-          chunks.push([...chunk]);
-        })
-        .finally(() => {
-          streamSettled = true;
-        });
-      assert.equal(streaming instanceof Promise, true, "native stream must return a Promise");
-      await new Promise((resolve) => setTimeout(resolve, 0));
-      assert.equal(streamSettled, false, "streaming must not block the Node.js event loop");
-      await streaming;
-      assert.deepEqual(chunks, [[1, 2], [3, 4], [5, 6]]);
-
-      let detachSettled = false;
-      const detaching = addon.detach(handle).finally(() => {
-        detachSettled = true;
-      });
-      assert.equal(detaching instanceof Promise, true, "native detach must return a Promise");
-      await new Promise((resolve) => setTimeout(resolve, 0));
-      assert.equal(detachSettled, false, "detach must not block the Node.js event loop");
-      await detaching;
-      return;
-    }
-    case "async-stream-callback-contract": {
-      const handle = await openFake(addon, options.library, options.root);
-      await assert.rejects(
-        addon.execProtocolRawStream(
-          handle,
-          new Uint8Array([streamFixtureRequest.normal]),
-          () => Promise.resolve(),
-        ),
-        /must complete synchronously.*Promise or thenable/u,
-      );
-      await assert.rejects(
-        addon.execProtocolRawStream(handle, new Uint8Array([streamFixtureRequest.normal]), () => {
-          throw new Error("stream consumer failed");
-        }),
-        /stream consumer failed/u,
-      );
-      const callbackObject = { kind: "stream callback object identity" };
-      for (const callbackFailure of [
-        "stream callback string",
-        73,
-        Number.NaN,
-        undefined,
-        callbackObject,
-      ]) {
-        const outcome = await addon
-          .execProtocolRawStream(handle, new Uint8Array([streamFixtureRequest.normal]), () => {
-            throw callbackFailure;
-          })
-          .then(
-            () => ({ rejected: false, error: undefined }),
-            (error) => ({ rejected: true, error }),
-          );
-        assert.equal(outcome.rejected, true, "a failed stream callback must reject");
-        assert.equal(
-          Object.is(outcome.error, callbackFailure),
-          true,
-          "a recovered callback abort must preserve the exact JavaScript throw value",
-        );
-      }
-      await assert.rejects(
-        addon.execProtocolRawStream(
-          handle,
-          new Uint8Array([streamFixtureRequest.failRecovery]),
-          () => {
-            throw new Error("secondary stream consumer failure");
-          },
-        ),
-        /native liboliphaunt protocol streaming failed: fake stream recovery failed/u,
-        "an unconfirmed native recovery must take precedence over the callback exception",
-      );
-      await assert.rejects(
-        addon.execProtocolRawStream(
-          handle,
-          new Uint8Array([streamFixtureRequest.unknownAfterCallback]),
-          () => {
-            throw new Error("tertiary stream consumer failure");
-          },
-        ),
-        /native liboliphaunt protocol streaming failed: fake stream returned an unknown positive status/u,
-        "an unknown positive native status must take precedence over the callback exception",
-      );
-      const successMismatchCallback = new Error(
-        "a success mismatch must not escape as a recovered callback failure",
-      );
-      await assert.rejects(
-        addon.execProtocolRawStream(
-          handle,
-          new Uint8Array([streamFixtureRequest.successAfterCallback]),
-          () => {
-            throw successMismatchCallback;
-          },
-        ),
-        (error) => {
-          assert.notStrictEqual(
-            error,
-            successMismatchCallback,
-            "native success after callback failure is authoritative adapter failure",
-          );
-          assert.match(String(error), /reported success after the callback failed/u);
-          return true;
-        },
-      );
-      let callbackCalled = false;
-      await assert.rejects(
-        addon.execProtocolRawStream(
-          handle,
-          new Uint8Array([streamFixtureRequest.abortWithoutCallback]),
-          () => {
-            callbackCalled = true;
-          },
-        ),
-        /native liboliphaunt protocol streaming failed: fake stream reported callback abort without callback failure/u,
-        "CALLBACK_ABORTED without a recorded callback failure is native/ABI failure",
-      );
-      assert.equal(callbackCalled, false);
-      await assert.rejects(
-        addon.execProtocolRawStream(
-          handle,
-          new Uint8Array([streamFixtureRequest.failureWithoutCallback]),
-          () => {
-            assert.fail("native failure before delivery must not call the stream callback");
-          },
-        ),
-        /native liboliphaunt protocol streaming failed: fake stream failed before callback delivery/u,
-      );
-      await assert.rejects(
-        addon.execProtocolRawStream(
-          handle,
-          new Uint8Array([streamFixtureRequest.unknownWithoutCallback]),
-          () => {
-            assert.fail("unknown native status before delivery must not call the stream callback");
-          },
-        ),
-        /native liboliphaunt protocol streaming failed: fake stream returned an unknown status before callback delivery/u,
-      );
-      await addon.detach(handle);
-      return;
-    }
-    case "generation-acquisition-race": {
-      await assert.rejects(
-        () => openFake(addon, options.library, options.root),
-        /native liboliphaunt init returned an invalid logical generation/u,
-        "open must fail closed when the resident handle closes before generation acquisition",
-      );
-      return;
-    }
-    case "alias-path": {
-      const first = await openFake(addon, options.library, options.root);
-      await addon.detach(first);
-      const aliasPath = `${path.dirname(options.library)}${path.sep}.${path.sep}${path.basename(options.library)}`;
-      assert.notEqual(aliasPath, options.library);
-      const second = await openFake(addon, aliasPath, options.root);
-      await addon.detach(second);
-      return;
-    }
-    case "load-only-worker": {
-      const handle = await openFake(addon, options.library, options.root);
-      const worker = new Worker(scriptPath, {
-        workerData: {
-          role: "load-only",
-          addonPath: options.addon,
-          libraryPath: options.library,
-          root: path.join(options.root, "worker"),
-        },
-      });
-      const workerExit = observeWorkerExit(worker);
-      await waitForWorkerMessage(worker, "loaded");
-      await requireWorkerExit(workerExit, 0);
-      assert.deepEqual(
-        eventsFrom(options.log),
-        ["init"],
-        "an environment that only loads the addon must not close another environment's runtime",
-      );
-      await addon.detach(handle);
-      return;
-    }
-    case "ownership-transfer": {
-      const worker = new Worker(scriptPath, {
-        workerData: {
-          role: "open-and-detach",
-          addonPath: options.addon,
-          libraryPath: options.library,
-          root: path.join(options.root, "worker"),
-        },
-      });
-      const workerExit = observeWorkerExit(worker);
-      await waitForWorkerMessage(worker, "detached");
-      const handle = await openFake(addon, options.library, options.root);
-      worker.postMessage("finish");
-      await requireWorkerExit(workerExit, 0);
-      assert.deepEqual(
-        eventsFrom(options.log),
-        ["init", "detach", "init"],
-        "the previous owner environment must not close a runtime after ownership transfers",
-      );
-      await addon.detach(handle);
-      return;
-    }
-    case "worker-terminate-active": {
-      const worker = new Worker(scriptPath, {
-        workerData: {
-          role: "open-and-wait",
-          addonPath: options.addon,
-          libraryPath: options.library,
-          root: path.join(options.root, "worker"),
-        },
-      });
-      const workerExit = observeWorkerExit(worker);
-      await waitForWorkerMessage(worker, "opened");
-      assert.equal(await worker.terminate(), 1);
-      await requireWorkerExit(workerExit, 1);
-      assert.deepEqual(
-        eventsFrom(options.log),
-        ["init", "close"],
-        "worker.terminate() must run the owning Node environment cleanup hook",
-      );
-      return;
-    }
-    case "worker-terminate-query":
-    case "worker-terminate-query-entry-race":
-    case "worker-terminate-backup": {
-      const entryRace = options.scenario === "worker-terminate-query-entry-race";
-      const operation = entryRace
-        ? "query"
-        : options.scenario.slice("worker-terminate-".length);
-      const worker = new Worker(scriptPath, {
-        workerData: {
-          role: `open-with-active-${operation}`,
-          addonPath: options.addon,
-          libraryPath: options.library,
-          root: path.join(options.root, "worker"),
-        },
-      });
-      const workerExit = observeWorkerExit(worker);
-      await waitForWorkerMessage(worker, "queued");
-      if (!entryRace) {
-        await waitForEvent(options.log, `${operation}-started`);
-      }
-      assert.equal(await worker.terminate(), 1);
-      await requireWorkerExit(workerExit, 1);
-      return;
-    }
-    case "worker-terminate-query-alias": {
-      const aliasPath = `${path.dirname(options.library)}${path.sep}.${path.sep}${path.basename(options.library)}`;
-      addon.version(aliasPath);
-      const worker = new Worker(scriptPath, {
-        workerData: {
-          role: "open-with-active-query",
-          addonPath: options.addon,
-          libraryPath: options.library,
-          root: path.join(options.root, "worker"),
-        },
-      });
-      const workerExit = observeWorkerExit(worker);
-      await waitForWorkerMessage(worker, "queued");
-      await waitForEvent(options.log, "query-started");
-      assert.equal(await worker.terminate(), 1);
-      await requireWorkerExit(workerExit, 1);
-      return;
-    }
-    case "worker-terminate-stream-call-blocked":
-    case "worker-terminate-stream-delivery-wait": {
-      const deliveryWait = options.scenario.endsWith("delivery-wait");
-      const worker = new Worker(scriptPath, {
-        workerData: {
-          role: deliveryWait
-            ? "open-with-stream-delivery-wait"
-            : "open-with-stream-call-blocked",
-          addonPath: options.addon,
-          libraryPath: options.library,
-          root: path.join(options.root, "worker"),
-        },
-      });
-      const workerExit = observeWorkerExit(worker);
-      await waitForWorkerMessage(worker, "queued");
-      // The fake runtime emits this only when its call into StreamChunk remains
-      // blocked for 50ms. The call-blocked case prefills the max-one queue, so
-      // the producer is inside blocking Push. The delivery-wait case leaves the
-      // queue empty but blocks the Worker event loop, so Push admits the chunk
-      // and StreamChunk can wake only from the teardown abort.
-      await waitForEvent(options.log, "stream-callback-blocked");
-      assert.equal(await worker.terminate(), 1);
-      await requireWorkerExit(workerExit, 1);
-      return;
-    }
-    case "worker-terminate-queued-query": {
-      const worker = new Worker(scriptPath, {
-        workerData: {
-          role: "open-with-queued-query",
-          addonPath: options.addon,
-          libraryPath: options.library,
-          root: path.join(options.root, "worker"),
-        },
-      });
-      const workerExit = observeWorkerExit(worker);
-      await waitForWorkerMessage(worker, "queued");
-      // The addon fixture delays the dedicated native thread before Execute,
-      // so cleanup must retire the registered pending count without relying on
-      // a JS Complete callback that can no longer run.
-      assert.equal(await worker.terminate(), 1);
-      await requireWorkerExit(workerExit, 1);
-      return;
-    }
-    case "copied-image-same-env-active":
-    case "copied-image-same-env-detached": {
-      const firstAddon = loadAddon(options.addonCopyA);
-      const secondAddon = loadAddon(options.addonCopyB);
-      const firstHandle = await openFake(
-        firstAddon,
-        options.library,
-        path.join(options.root, "first"),
-      );
-      await firstAddon.detach(firstHandle);
-      const secondHandle = await openFake(
-        secondAddon,
-        options.library,
-        path.join(options.root, "second"),
-      );
-      if (options.scenario.endsWith("-detached")) {
-        await secondAddon.detach(secondHandle);
-      } else {
-        globalThis.__oliphauntCopiedImageCurrentHandle = secondHandle;
-      }
-      return;
-    }
-    case "copied-image-worker-main-active":
-    case "copied-image-worker-main-detached": {
-      const worker = new Worker(scriptPath, {
-        workerData: {
-          role: "open-and-detach",
-          addonPath: options.addonCopyA,
-          libraryPath: options.library,
-          root: path.join(options.root, "worker"),
-        },
-      });
-      const workerExit = observeWorkerExit(worker);
-      await waitForWorkerMessage(worker, "detached");
-      const mainAddon = loadAddon(options.addonCopyB);
-      const mainHandle = await openFake(
-        mainAddon,
-        options.library,
-        path.join(options.root, "main"),
-      );
-      const currentOwnerDetached = options.scenario.endsWith("-detached");
-      if (currentOwnerDetached) {
-        await mainAddon.detach(mainHandle);
-      } else {
-        globalThis.__oliphauntCopiedImageCurrentHandle = mainHandle;
-      }
-      worker.postMessage("finish");
-      await requireWorkerExit(workerExit, 0);
-      assert.deepEqual(
-        eventsFrom(options.log),
-        [
-          "init",
-          "detach",
-          "init",
-          ...(currentOwnerDetached ? ["detach"] : []),
-          "close-stale",
-        ],
-        "cleanup from the copied worker image must not close the main image's current generation",
-      );
-      return;
-    }
-    case "copied-image-worker-terminate-stale": {
-      const worker = new Worker(scriptPath, {
-        workerData: {
-          role: "open-and-detach",
-          addonPath: options.addonCopyA,
-          libraryPath: options.library,
-          root: path.join(options.root, "worker"),
-        },
-      });
-      const workerExit = observeWorkerExit(worker);
-      await waitForWorkerMessage(worker, "detached");
-      const mainAddon = loadAddon(options.addonCopyB);
-      globalThis.__oliphauntCopiedImageCurrentHandle = await openFake(
-        mainAddon,
-        options.library,
-        path.join(options.root, "main"),
-      );
-      assert.equal(await worker.terminate(), 1);
-      await requireWorkerExit(workerExit, 1);
-      assert.deepEqual(
-        eventsFrom(options.log),
-        ["init", "detach", "init", "close-stale"],
-        "terminated stale addon cleanup must not close the current copied-image generation",
-      );
-      return;
-    }
-    default:
-      throw new Error(`unknown cleanup lifecycle scenario: ${options.scenario}`);
-  }
-}
-
-function assertTerminalLifecycle(scenario, events, expectedBeforeClose) {
-  assert.deepEqual(
-    events,
-    [...expectedBeforeClose, "close"],
-    `${scenario} must terminally close exactly once during Node environment cleanup`,
-  );
-  assert.equal(events.includes("close-after-close"), false);
-  assert.equal(events.includes("detach-after-close"), false);
-  assert.equal(events.includes("close-unguarded"), false);
-  assert.equal(events.includes("close-guard-invalid"), false);
-}
-
-function assertCopiedImageLifecycle(
-  scenario,
-  events,
-  expectedBeforeCleanup,
-  expectStaleCleanup,
-) {
-  assert.deepEqual(
-    events.slice(0, expectedBeforeCleanup.length),
-    expectedBeforeCleanup,
-    `${scenario} must complete its logical ownership transfer before cleanup`,
-  );
-  const cleanupEvents = events.slice(expectedBeforeCleanup.length).toSorted();
-  if (expectStaleCleanup) {
-    assert.deepEqual(
-      cleanupEvents,
-      ["close", "close-stale"],
-      `${scenario} must close the current generation once and reject one stale cleanup`,
-    );
-  } else {
-    assert.deepEqual(
-      cleanupEvents,
-      cleanupEvents.includes("close-stale")
-        ? ["close", "close-stale"]
-        : ["close"],
-      `${scenario} must close exactly once; an older token may observe the already-spent process`,
-    );
-  }
-  assert.equal(events.includes("close-unguarded"), false);
-  assert.equal(events.includes("close-guard-invalid"), false);
-  assert.equal(events.includes("close-after-close"), false);
-  assert.equal(events.includes("detach-after-close"), false);
-}
-
-function assertGenerationAcquisitionRace(scenario, events) {
-  assert.deepEqual(
-    events,
-    ["init", "close-before-generation"],
-    `${scenario} must not dereference a handle after generation acquisition reports it stale`,
-  );
-  assert.equal(events.includes("close-unguarded"), false);
-  assert.equal(events.includes("close-guard-invalid"), false);
-  assert.equal(events.includes("close-after-close"), false);
-  assert.equal(events.includes("detach-after-close"), false);
-}
-
-async function runParent(options) {
-  for (const candidate of [options.addon, options.instrumentedAddon, options.library]) {
-    assert.ok(path.isAbsolute(candidate), `cleanup lifecycle input must be absolute: ${candidate}`);
-    assert.ok(existsSync(candidate), `cleanup lifecycle input does not exist: ${candidate}`);
-  }
-
-  const temporaryRoot = await mkdtemp(path.join(tmpdir(), "oliphaunt-node-cleanup-"));
-  let singleImageCases = 0;
-  let copiedImageCases = 0;
-  let staleAcquisitionCases = 0;
-  try {
-    const copiedAddonA = path.join(temporaryRoot, "oliphaunt-node-copy-a.node");
-    const copiedAddonB = path.join(temporaryRoot, "oliphaunt-node-copy-b.node");
-    const unicodeLibraryDirectory = path.join(temporaryRoot, "unicode-λ-路径");
-    const unicodeLibrary = path.join(
-      unicodeLibraryDirectory,
-      path.basename(options.library),
-    );
-    await mkdir(unicodeLibraryDirectory, { recursive: true });
-    await Promise.all([
-      copyFile(options.addon, copiedAddonA),
-      copyFile(options.addon, copiedAddonB),
-      copyFile(options.library, unicodeLibrary),
-    ]);
-    const scenarios = [
-      {
-        name: "explicit-detach",
-        expectedBeforeClose: ["init", "detach"],
-        iterations: 12,
-      },
-      {
-        name: "active-exit",
-        expectedBeforeClose: ["init"],
-        iterations: 12,
-      },
-      {
-        name: "forced-process-exit-active",
-        expectedAbruptExit: ["init"],
-      },
-      {
-        name: "unicode-library-path",
-        expectedBeforeClose: ["init", "detach"],
-        library: unicodeLibrary,
-      },
-      {
-        name: "invalid-library-path",
-        expectedNoEvents: true,
-      },
-      {
-        name: "gc-finalizer",
-        expectedBeforeClose: ["init", "detach", "init", "detach"],
-        exposeGc: true,
-      },
-      {
-        name: "gc-detach-recovery",
-        expectedBeforeClose: ["init", "detach-failed", "detach", "init", "detach"],
-        exposeGc: true,
-        failDetachOnce: true,
-      },
-      {
-        name: "forgotten-token-generation-guard",
-        expectedBeforeClose: ["init", "detach", "init", "detach", "init", "detach"],
-      },
-      {
-        name: "async-query-cancel",
-        expectedBeforeClose: ["init", "query-started", "cancel", "query-cancelled", "detach"],
-        blockQuery: true,
-      },
-      {
-        name: "async-archive-timers",
-        expectedBeforeClose: [
-          "init",
-          "backup-started",
-          "backup-finished",
-          "restore-started",
-          "restore-finished",
-          "detach",
-        ],
-        blockArchive: true,
-      },
-      {
-        name: "async-open-stream-detach-timers",
-        expectedBeforeClose: [
-          "open-started",
-          "open-finished",
-          "init",
-          "stream-started",
-          "stream-finished",
-          "detach-started",
-          "detach-finished",
-          "detach",
-        ],
-        blockOpen: true,
-        blockStream: true,
-        blockDetach: true,
-      },
-      {
-        name: "async-stream-callback-contract",
-        expectedBeforeClose: [
-          "init",
-          ...Array.from(
-            { length: 7 },
-            () => ["stream-started", "stream-aborted"],
-          ).flat(),
-          "stream-started",
-          "stream-aborted",
-          "stream-recovery-failed",
-          "stream-started",
-          "stream-aborted",
-          "stream-unknown-status",
-          "stream-started",
-          "stream-aborted",
-          "stream-success-after-callback-abort",
-          "stream-started",
-          "stream-abort-without-callback",
-          "stream-started",
-          "stream-failure-without-callback",
-          "stream-started",
-          "stream-unknown-without-callback",
-          "detach",
-        ],
-        blockStream: true,
-      },
-      {
-        name: "generation-acquisition-race",
-        generationAcquisitionRace: true,
-      },
-      {
-        name: "alias-path",
-        expectedBeforeClose: ["init", "detach", "init", "detach"],
-      },
-      {
-        name: "load-only-worker",
-        expectedBeforeClose: ["init", "detach"],
-      },
-      {
-        name: "ownership-transfer",
-        expectedBeforeClose: ["init", "detach", "init", "detach"],
-      },
-      {
-        name: "worker-terminate-active",
-        expectedBeforeClose: ["init"],
-      },
-      {
-        name: "worker-terminate-query",
-        expectedBeforeClose: ["init", "query-started", "cancel", "query-cancelled"],
-        blockQuery: true,
-        iterations: 3,
-      },
-      {
-        name: "worker-terminate-query-entry-race",
-        expectedBeforeClose: [
-          "init",
-          "cancel-early-ignored",
-          "query-started",
-          "cancel",
-          "query-cancelled",
-        ],
-        blockQuery: true,
-        ignoreEarlyCancel: true,
-        pauseNativeCallEntry: true,
-        usesAddonTestHooks: true,
-        iterations: 3,
-      },
-      {
-        name: "worker-terminate-query-alias",
-        expectedBeforeClose: ["init", "query-started", "cancel", "query-cancelled"],
-        blockQuery: true,
-        recordRepeatCancel: true,
-      },
-      {
-        name: "worker-terminate-queued-query",
-        expectedBeforeClose: ["init"],
-        delayOperationStart: true,
-        usesAddonTestHooks: true,
-        iterations: 3,
-      },
-      {
-        name: "worker-terminate-stream-call-blocked",
-        expectedBeforeClose: [
-          "init",
-          "stream-started",
-          "stream-callback-blocked",
-          "stream-aborted",
-        ],
-        blockStream: true,
-        prefillStreamQueue: true,
-        observeBlockedStreamCallback: true,
-        usesAddonTestHooks: true,
-        iterations: 3,
-      },
-      {
-        name: "worker-terminate-stream-delivery-wait",
-        expectedBeforeClose: [
-          "init",
-          "stream-started",
-          "stream-callback-blocked",
-          "stream-aborted",
-        ],
-        blockStream: true,
-        observeBlockedStreamCallback: true,
-        iterations: 3,
-      },
-      {
-        name: "worker-terminate-backup",
-        expectedBeforeClose: ["init", "backup-started", "backup-finished"],
-        blockArchive: true,
-        iterations: 3,
-      },
-      {
-        name: "copied-image-same-env-active",
-        expectedBeforeCleanup: ["init", "detach", "init"],
-      },
-      {
-        name: "copied-image-same-env-detached",
-        expectedBeforeCleanup: ["init", "detach", "init", "detach"],
-      },
-      {
-        name: "copied-image-worker-main-active",
-        expectedBeforeCleanup: ["init", "detach", "init"],
-        expectStaleCleanup: true,
-      },
-      {
-        name: "copied-image-worker-main-detached",
-        expectedBeforeCleanup: ["init", "detach", "init", "detach"],
-        expectStaleCleanup: true,
-      },
-      {
-        name: "copied-image-worker-terminate-stale",
-        expectedBeforeClose: ["init", "detach", "init", "close-stale"],
-      },
-    ];
-
-    for (const scenario of scenarios) {
-      const iterations = scenario.iterations ?? 1;
-      for (let iteration = 1; iteration <= iterations; iteration += 1) {
-        if (scenario.generationAcquisitionRace) {
-          staleAcquisitionCases += 1;
-        } else if (scenario.name.startsWith("copied-image-")) {
-          copiedImageCases += 1;
-        } else {
-          singleImageCases += 1;
-        }
-        const executionName = iterations === 1
-          ? scenario.name
-          : `${scenario.name}-${iteration}-of-${iterations}`;
-        const scenarioAddon = scenario.usesAddonTestHooks
-          ? options.instrumentedAddon
-          : options.addon;
-        const scenarioRoot = path.join(temporaryRoot, executionName);
-        const logPath = path.join(temporaryRoot, `${executionName}.log`);
-        const childArgs = [
-          ...(scenario.exposeGc ? ["--expose-gc"] : []),
-          scriptPath,
-          "--scenario",
-          scenario.name,
-          "--addon",
-          scenarioAddon,
-          "--addon-copy-a",
-          copiedAddonA,
-          "--addon-copy-b",
-          copiedAddonB,
-          "--library",
-          scenario.library ?? options.library,
-          "--root",
-          scenarioRoot,
-          "--log",
-          logPath,
-        ];
-        const child = spawnSync(process.execPath, childArgs, {
-          encoding: "utf8",
-          env: {
-            ...process.env,
-            OLIPHAUNT_NODE_CLEANUP_TEST_LOG: logPath,
-            ...(scenario.generationAcquisitionRace
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_CLOSE_BEFORE_GENERATION: "1" }
-              : {}),
-            ...(scenario.failDetachOnce
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_FAIL_DETACH_ONCE: "1" }
-              : {}),
-            ...(scenario.blockQuery
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_QUERY: "1" }
-              : {}),
-            ...(scenario.blockArchive
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_ARCHIVE: "1" }
-              : {}),
-            ...(scenario.blockOpen
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_OPEN: "1" }
-              : {}),
-            ...(scenario.blockStream
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_STREAM: "1" }
-              : {}),
-            ...(scenario.blockDetach
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_DETACH: "1" }
-              : {}),
-            ...(scenario.delayOperationStart
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_DELAY_OPERATION_START: "1" }
-              : {}),
-            ...(scenario.pauseNativeCallEntry
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_PAUSE_NATIVE_CALL_ENTRY: "1" }
-              : {}),
-            ...(scenario.ignoreEarlyCancel
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_IGNORE_EARLY_CANCEL: "1" }
-              : {}),
-            ...(scenario.prefillStreamQueue
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_PREFILL_STREAM_QUEUE: "1" }
-              : {}),
-            ...(scenario.observeBlockedStreamCallback
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_OBSERVE_BLOCKED_STREAM_CALLBACK: "1" }
-              : {}),
-            ...(scenario.recordRepeatCancel
-              ? { OLIPHAUNT_NODE_CLEANUP_TEST_RECORD_REPEAT_CANCEL: "1" }
-              : {}),
-          },
-          timeout: 30_000,
-        });
-        assert.equal(
-          child.error,
-          undefined,
-          `${executionName} child could not run: ${child.error?.message ?? "unknown error"}`,
-        );
-        assert.equal(
-          child.signal,
-          null,
-          `${executionName} child terminated by ${child.signal}\n${child.stderr}`,
-        );
-        assert.equal(
-          child.status,
-          0,
-          `${executionName} child failed\nstdout:\n${child.stdout}\nstderr:\n${child.stderr}`,
-        );
-        const events = eventsFrom(logPath);
-        if (scenario.expectedNoEvents) {
-          assert.deepEqual(events, [], `${executionName} must not load a library image`);
-        } else if (scenario.expectedAbruptExit !== undefined) {
-          assert.deepEqual(
-            events,
-            scenario.expectedAbruptExit,
-            `${executionName} must defer cleanup to process teardown`,
-          );
-        } else if (scenario.generationAcquisitionRace) {
-          assertGenerationAcquisitionRace(executionName, events);
-        } else if (scenario.expectedBeforeCleanup !== undefined) {
-          assertCopiedImageLifecycle(
-            executionName,
-            events,
-            scenario.expectedBeforeCleanup,
-            scenario.expectStaleCleanup ?? false,
-          );
-        } else {
-          const assertedEvents = scenario.ignoreEarlyCancel
-            ? events.filter((event, index) =>
-                event !== "cancel-early-ignored" || index === events.indexOf(event))
-            : events;
-          assertTerminalLifecycle(executionName, assertedEvents, scenario.expectedBeforeClose);
-        }
-      }
-    }
-  } finally {
-    await rm(temporaryRoot, { recursive: true, force: true });
-  }
-
-  console.log(
-    `Node direct environment cleanup lifecycle passed (${singleImageCases} single-image + ${copiedImageCases} copied-image + ${staleAcquisitionCases} stale-acquisition cases)`,
-  );
-}
-
-if (!isMainThread) {
-  await runWorker();
-} else {
-  const options = parseArgs(process.argv.slice(2));
-  if (options.scenario !== undefined) {
-    await runChild(options);
-  } else {
-    await runParent(options);
-  }
-}
diff --git a/src/runtimes/node-direct/tools/test-node-addon-cleanup-lifecycle.sh b/src/runtimes/node-direct/tools/test-node-addon-cleanup-lifecycle.sh
deleted file mode 100755
index ac1312f03..000000000
--- a/src/runtimes/node-direct/tools/test-node-addon-cleanup-lifecycle.sh
+++ /dev/null
@@ -1,157 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-is_absolute_path() {
-  case "$1" in
-    /*|[A-Za-z]:/*|[A-Za-z]:\\*|\\\\*) return 0 ;;
-    *) return 1 ;;
-  esac
-}
-
-test_absolute_path_classifier() {
-  local candidate
-  for candidate in \
-    "/tmp/oliphaunt.node" \
-    "D:/oliphaunt.node" \
-    'D:\oliphaunt.node' \
-    "//server/share/oliphaunt.node" \
-    '\\server\share\oliphaunt.node' \
-    '\\?\D:\oliphaunt.node'; do
-    if ! is_absolute_path "$candidate"; then
-      echo "absolute cleanup lifecycle path was misclassified: $candidate" >&2
-      return 1
-    fi
-  done
-  for candidate in \
-    "relative/oliphaunt.node" \
-    "./oliphaunt.node" \
-    "../oliphaunt.node" \
-    "D:relative.node"; do
-    if is_absolute_path "$candidate"; then
-      echo "relative cleanup lifecycle path was misclassified: $candidate" >&2
-      return 1
-    fi
-  done
-}
-
-if [[ "${1:-}" == "--test-path-classifier" ]]; then
-  test_absolute_path_classifier
-  echo "Node cleanup lifecycle path classifier passed"
-  exit 0
-fi
-
-root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "must run inside the Oliphaunt git checkout" >&2
-  exit 1
-}
-cd "$root"
-
-addon="${1:-}"
-instrumented_addon="${2:-}"
-if [[ -z "$addon" || -z "$instrumented_addon" ]]; then
-  echo "usage: $0  " >&2
-  exit 2
-fi
-if ! is_absolute_path "$addon"; then
-  addon="$root/$addon"
-fi
-if [[ ! -f "$addon" ]]; then
-  echo "compiled production Node direct addon does not exist: $addon" >&2
-  exit 2
-fi
-if ! is_absolute_path "$instrumented_addon"; then
-  instrumented_addon="$root/$instrumented_addon"
-fi
-if [[ ! -f "$instrumented_addon" ]]; then
-  echo "compiled instrumented Node direct addon does not exist: $instrumented_addon" >&2
-  exit 2
-fi
-
-case "$(uname -s)" in
-  Darwin)
-    platform="macos"
-    library_name="libfake_oliphaunt.dylib"
-    ;;
-  Linux)
-    platform="linux"
-    library_name="libfake_oliphaunt.so"
-    ;;
-  MINGW*|MSYS*|CYGWIN*)
-    platform="windows"
-    library_name="fake_oliphaunt.dll"
-    ;;
-  *)
-    echo "unsupported Node cleanup lifecycle platform: $(uname -s)" >&2
-    exit 2
-    ;;
-esac
-
-out_root="${OLIPHAUNT_NODE_CLEANUP_TEST_OUT_DIR:-$root/target/oliphaunt-node-direct/cleanup-lifecycle/$platform}"
-if ! is_absolute_path "$out_root"; then
-  out_root="$root/$out_root"
-fi
-rm -rf "$out_root"
-mkdir -p "$out_root"
-
-source_path="$root/src/runtimes/node-direct/native/node-addon/fixtures/fake_liboliphaunt.cc"
-include_path="$root/src/runtimes/liboliphaunt/native/include"
-library_path="$out_root/$library_name"
-cxx="${CXX:-c++}"
-
-case "$platform" in
-  macos)
-    "$cxx" \
-      -std=c++17 \
-      -O2 \
-      -fPIC \
-      -dynamiclib \
-      -DOLIPHAUNT_BUILDING_DLL \
-      "-I$include_path" \
-      "$source_path" \
-      -o "$library_path"
-    ;;
-  linux)
-    "$cxx" \
-      -std=c++17 \
-      -O2 \
-      -fPIC \
-      -shared \
-      -DOLIPHAUNT_BUILDING_DLL \
-      "-I$include_path" \
-      "$source_path" \
-      -o "$library_path"
-    ;;
-  windows)
-    cxx="${CXX:-cl}"
-    object_path="$out_root/fake_liboliphaunt.obj"
-    import_library_path="$out_root/fake_liboliphaunt.lib"
-    if command -v cygpath >/dev/null 2>&1; then
-      source_path="$(cygpath -w "$source_path")"
-      include_path="$(cygpath -w "$include_path")"
-      library_path="$(cygpath -w "$library_path")"
-      object_path="$(cygpath -w "$object_path")"
-      import_library_path="$(cygpath -w "$import_library_path")"
-      addon="$(cygpath -w "$addon")"
-      instrumented_addon="$(cygpath -w "$instrumented_addon")"
-    fi
-    "$cxx" \
-      //nologo \
-      //std:c++17 \
-      //O2 \
-      //EHsc \
-      //LD \
-      //DOLIPHAUNT_BUILDING_DLL \
-      "-I$include_path" \
-      "$source_path" \
-      //Fo:"$object_path" \
-      //link \
-      //OUT:"$library_path" \
-      //IMPLIB:"$import_library_path"
-    ;;
-esac
-
-node \
-  src/runtimes/node-direct/tools/node-addon-cleanup-lifecycle.test.mjs \
-  --addon "$addon" \
-  --instrumented-addon "$instrumented_addon" \
-  --library "$library_path"
diff --git a/src/runtimes/wasix-browser-host/build-provenance.mts b/src/runtimes/wasix-browser-host/build-provenance.mts
new file mode 100644
index 000000000..c6115e1a6
--- /dev/null
+++ b/src/runtimes/wasix-browser-host/build-provenance.mts
@@ -0,0 +1,118 @@
+import { createHash } from 'node:crypto';
+import { readFile } from 'node:fs/promises';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const hostDirectory = dirname(fileURLToPath(import.meta.url));
+const repositoryRoot = resolve(hostDirectory, '../../..');
+const sourceManifestPath = 'src/runtimes/wasix-browser-host/source.toml';
+const buildScriptPath = 'src/runtimes/wasix-browser-host/build-sdk.sh';
+const provenanceScriptPath = 'src/runtimes/wasix-browser-host/build-provenance.mts';
+const safePatchName = /^\d{4}-wasmer-(?:(?:js|wasix)-)?[a-z0-9-]+\.patch$/u;
+
+export async function loadHostBuildContract() {
+  const source = await readFile(resolve(repositoryRoot, sourceManifestPath), 'utf8');
+  const patchSeries = tomlStringArray(source, 'patches', 'series');
+  if (patchSeries.length === 0 || new Set(patchSeries).size !== patchSeries.length) {
+    throw new Error('WASIX host patch series must be non-empty and unique');
+  }
+  for (const patch of patchSeries) {
+    if (!safePatchName.test(patch)) {
+      throw new Error(`WASIX host patch name is unsafe: ${JSON.stringify(patch)}`);
+    }
+  }
+
+  const inputs = Object.freeze([
+    sourceManifestPath,
+    ...patchSeries.map((patch) => `src/runtimes/wasix-browser-host/patches/${patch}`),
+    buildScriptPath,
+    provenanceScriptPath,
+  ]);
+  const digests = [];
+  for (const input of inputs) {
+    const bytes = await readFile(resolve(repositoryRoot, input));
+    digests.push(`${sha256(bytes)}\n`);
+  }
+
+  const provenance = deepFreeze({
+    wasmerJsCommit: tomlString(source, 'wasmer-js', 'commit'),
+    wasmerWasixVersion: tomlString(source, 'wasmer-wasix', 'version'),
+    inputsSha256: sha256(digests.join('')),
+    guestConcurrency: 'denied-for-oliphaunt-single-backend',
+    optimization: {
+      cargoProfile: 'release',
+      rustOptLevel: 3,
+      lto: true,
+      wasmOpt: ['--enable-threads', '--enable-bulk-memory', '-O3'],
+    },
+  });
+  return Object.freeze({ inputs, patchSeries: Object.freeze(patchSeries), provenance });
+}
+
+function tomlString(source, section, key) {
+  const body = tomlSection(source, section);
+  const match = body.match(new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*"([^"]+)"\\s*$`, 'mu'));
+  if (match === null) {
+    throw new Error(`WASIX host source manifest is missing [${section}].${key}`);
+  }
+  return match[1];
+}
+
+function tomlStringArray(source, section, key) {
+  const body = tomlSection(source, section);
+  const match = body.match(
+    new RegExp(`^\\s*${escapeRegExp(key)}\\s*=\\s*\\[([\\s\\S]*?)\\]\\s*$`, 'mu'),
+  );
+  if (match === null) {
+    throw new Error(`WASIX host source manifest is missing [${section}].${key}`);
+  }
+  const values = [];
+  const item = /"([^"]+)"\s*,?/gu;
+  for (const entry of match[1].matchAll(item)) values.push(entry[1]);
+  const residue = match[1]
+    .replace(item, '')
+    .replace(/#[^\n]*/gu, '')
+    .trim();
+  if (residue !== '') {
+    throw new Error(`WASIX host source manifest has malformed [${section}].${key}`);
+  }
+  return values;
+}
+
+function tomlSection(source, section) {
+  const escaped = escapeRegExp(section);
+  const match = source.match(
+    new RegExp(`^\\[${escaped}\\][ \\t]*\\r?\\n([\\s\\S]*?)(?=^\\[|(?![\\s\\S]))`, 'mu'),
+  );
+  if (match === null) throw new Error(`WASIX host source manifest is missing [${section}]`);
+  return match[1];
+}
+
+function escapeRegExp(value) {
+  return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
+}
+
+function sha256(value) {
+  return createHash('sha256').update(value).digest('hex');
+}
+
+function deepFreeze(value) {
+  Object.freeze(value);
+  for (const child of Object.values(value)) {
+    if (child !== null && typeof child === 'object' && !Object.isFrozen(child)) deepFreeze(child);
+  }
+  return value;
+}
+
+if (process.argv[1] !== undefined && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
+  const contract = await loadHostBuildContract();
+  if (process.argv[2] === '--inputs-sha256') {
+    console.log(contract.provenance.inputsSha256);
+  } else if (process.argv[2] === '--patch-series') {
+    console.log(contract.patchSeries.join('\n'));
+  } else if (process.argv[2] === '--json') {
+    console.log(JSON.stringify(contract.provenance, null, 2));
+  } else {
+    throw new Error('usage: build-provenance.mts --inputs-sha256|--patch-series|--json');
+  }
+}
diff --git a/src/bindings/wasix-ts/host/build-sdk.sh b/src/runtimes/wasix-browser-host/build-sdk.sh
similarity index 89%
rename from src/bindings/wasix-ts/host/build-sdk.sh
rename to src/runtimes/wasix-browser-host/build-sdk.sh
index d7291e63f..0db80d0c0 100755
--- a/src/bindings/wasix-ts/host/build-sdk.sh
+++ b/src/runtimes/wasix-browser-host/build-sdk.sh
@@ -2,10 +2,9 @@
 set -euo pipefail
 
 host_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-binding_dir="$(cd "$host_dir/.." && pwd)"
-repo_root="$(cd "$binding_dir/../../.." && pwd)"
+repo_root="$(cd "$host_dir/../../.." && pwd)"
 source_manifest="$host_dir/source.toml"
-provenance_script="$host_dir/build-provenance.mjs"
+provenance_script="$host_dir/build-provenance.mts"
 target_parent="$repo_root/target/oliphaunt-wasix-ts/host"
 target_dir="$target_parent/wasmer-sdk"
 cargo_target_dir="$target_parent/cargo"
@@ -45,12 +44,12 @@ for value in "$wasmer_js_url" "$wasmer_js_version" "$wasmer_js_commit" "$wasmer_
   fi
 done
 
-if ! command -v node >/dev/null 2>&1; then
-  echo "wasix-ts host build: required command not found: node" >&2
+if ! command -v bun >/dev/null 2>&1; then
+  echo "wasix-ts host build: required command not found: bun" >&2
   exit 1
 fi
-mapfile -t patch_series < <(node "$provenance_script" --patch-series)
-input_hash="$(node "$provenance_script" --inputs-sha256)"
+mapfile -t patch_series < <(bun "$provenance_script" --patch-series)
+input_hash="$(bun "$provenance_script" --inputs-sha256)"
 
 patch_command="patch"
 sha256sum_command="sha256sum"
@@ -72,7 +71,7 @@ fi
 
 mkdir -p "$target_parent"
 
-for command_name in awk curl git node npm "$patch_command" "$sha256sum_command" tar wasm-pack; do
+for command_name in awk bun curl git node npm "$patch_command" "$sha256sum_command" tar wasm-pack; do
   if ! command -v "$command_name" >/dev/null 2>&1; then
     echo "wasix-ts host build: required command not found: $command_name" >&2
     exit 1
@@ -103,7 +102,7 @@ if [[ "$(git -C "$wasmer_js_dir" rev-parse HEAD)" != "$wasmer_js_commit" ]]; the
   echo "wasix-ts host build: Wasmer JS checkout did not resolve the pinned commit" >&2
   exit 1
 fi
-actual_wasmer_js_version="$(node -p "require(process.argv[1]).version" "$wasmer_js_dir/package.json")"
+actual_wasmer_js_version="$(bun "$repo_root/tools/dev/node-info.mts" package-version "$wasmer_js_dir/package.json")"
 if [[ "$actual_wasmer_js_version" != "$wasmer_js_version" ]]; then
   echo "wasix-ts host build: pinned Wasmer JS version is $actual_wasmer_js_version, expected $wasmer_js_version" >&2
   exit 1
@@ -167,7 +166,7 @@ mkdir -p "$staging_dir"
 cp -R "$wasmer_js_dir/dist" "$staging_dir/dist"
 cp "$wasmer_js_dir/LICENSE" "$staging_dir/LICENSE"
 printf '%s\n' "$input_hash" > "$staging_dir/.oliphaunt-input-sha256"
-node "$provenance_script" --json > "$staging_dir/provenance.json"
+bun "$provenance_script" --json > "$staging_dir/provenance.json"
 chmod -R u+rwX,go+rX "$staging_dir"
 
 previous_dir="$target_parent/.wasmer-sdk-previous"
diff --git a/src/runtimes/wasix-browser-host/moon.yml b/src/runtimes/wasix-browser-host/moon.yml
new file mode 100644
index 000000000..62757ad8e
--- /dev/null
+++ b/src/runtimes/wasix-browser-host/moon.yml
@@ -0,0 +1,22 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "wasix-browser-host"
+language: "rust"
+layer: "library"
+stack: "frontend"
+
+tasks:
+  build:
+    tags: ["artifact", "build", "requires-rust"]
+    command: "bash src/runtimes/wasix-browser-host/build-sdk.sh"
+    env:
+      WASM_PACK_VERSION: "0.15.0"
+    inputs:
+      - "**/*"
+      - "/tools/dev/node-info.mts"
+      - "@group(cargo-workspace)"
+    outputs:
+      - "/target/oliphaunt-wasix-ts/host/wasmer-sdk/**/*"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/bindings/wasix-ts/host/patches/0001-wasmer-js-run-configured-wasix-process.patch b/src/runtimes/wasix-browser-host/patches/0001-wasmer-js-run-configured-wasix-process.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0001-wasmer-js-run-configured-wasix-process.patch
rename to src/runtimes/wasix-browser-host/patches/0001-wasmer-js-run-configured-wasix-process.patch
diff --git a/src/bindings/wasix-ts/host/patches/0002-wasmer-wasix-add-0702-compatibility-imports.patch b/src/runtimes/wasix-browser-host/patches/0002-wasmer-wasix-add-0702-compatibility-imports.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0002-wasmer-wasix-add-0702-compatibility-imports.patch
rename to src/runtimes/wasix-browser-host/patches/0002-wasmer-wasix-add-0702-compatibility-imports.patch
diff --git a/src/bindings/wasix-ts/host/patches/0003-wasmer-js-install-browser-runtime-devices.patch b/src/runtimes/wasix-browser-host/patches/0003-wasmer-js-install-browser-runtime-devices.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0003-wasmer-js-install-browser-runtime-devices.patch
rename to src/runtimes/wasix-browser-host/patches/0003-wasmer-js-install-browser-runtime-devices.patch
diff --git a/src/bindings/wasix-ts/host/patches/0005-wasmer-js-use-object-wasm-init.patch b/src/runtimes/wasix-browser-host/patches/0005-wasmer-js-use-object-wasm-init.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0005-wasmer-js-use-object-wasm-init.patch
rename to src/runtimes/wasix-browser-host/patches/0005-wasmer-js-use-object-wasm-init.patch
diff --git a/src/bindings/wasix-ts/host/patches/0006-wasmer-js-reuse-precompiled-wasix-module.patch b/src/runtimes/wasix-browser-host/patches/0006-wasmer-js-reuse-precompiled-wasix-module.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0006-wasmer-js-reuse-precompiled-wasix-module.patch
rename to src/runtimes/wasix-browser-host/patches/0006-wasmer-js-reuse-precompiled-wasix-module.patch
diff --git a/src/bindings/wasix-ts/host/patches/0007-wasmer-js-run-oliphaunt-direct.patch b/src/runtimes/wasix-browser-host/patches/0007-wasmer-js-run-oliphaunt-direct.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0007-wasmer-js-run-oliphaunt-direct.patch
rename to src/runtimes/wasix-browser-host/patches/0007-wasmer-js-run-oliphaunt-direct.patch
diff --git a/src/bindings/wasix-ts/host/patches/0008-wasmer-instantiate-js-modules-async.patch b/src/runtimes/wasix-browser-host/patches/0008-wasmer-instantiate-js-modules-async.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0008-wasmer-instantiate-js-modules-async.patch
rename to src/runtimes/wasix-browser-host/patches/0008-wasmer-instantiate-js-modules-async.patch
diff --git a/src/bindings/wasix-ts/host/patches/0009-wasmer-wasix-instantiate-main-module-async.patch b/src/runtimes/wasix-browser-host/patches/0009-wasmer-wasix-instantiate-main-module-async.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0009-wasmer-wasix-instantiate-main-module-async.patch
rename to src/runtimes/wasix-browser-host/patches/0009-wasmer-wasix-instantiate-main-module-async.patch
diff --git a/src/bindings/wasix-ts/host/patches/0010-wasmer-js-refresh-npm-lock.patch b/src/runtimes/wasix-browser-host/patches/0010-wasmer-js-refresh-npm-lock.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0010-wasmer-js-refresh-npm-lock.patch
rename to src/runtimes/wasix-browser-host/patches/0010-wasmer-js-refresh-npm-lock.patch
diff --git a/src/bindings/wasix-ts/host/patches/0011-wasmer-wasix-deny-single-backend-guest-spawn.patch b/src/runtimes/wasix-browser-host/patches/0011-wasmer-wasix-deny-single-backend-guest-spawn.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0011-wasmer-wasix-deny-single-backend-guest-spawn.patch
rename to src/runtimes/wasix-browser-host/patches/0011-wasmer-wasix-deny-single-backend-guest-spawn.patch
diff --git a/src/bindings/wasix-ts/host/patches/0012-wasmer-js-remove-retired-wasm32-wasi-target.patch b/src/runtimes/wasix-browser-host/patches/0012-wasmer-js-remove-retired-wasm32-wasi-target.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0012-wasmer-js-remove-retired-wasm32-wasi-target.patch
rename to src/runtimes/wasix-browser-host/patches/0012-wasmer-js-remove-retired-wasm32-wasi-target.patch
diff --git a/src/bindings/wasix-ts/host/patches/0013-wasmer-wasix-fast-single-backend-clock.patch b/src/runtimes/wasix-browser-host/patches/0013-wasmer-wasix-fast-single-backend-clock.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0013-wasmer-wasix-fast-single-backend-clock.patch
rename to src/runtimes/wasix-browser-host/patches/0013-wasmer-wasix-fast-single-backend-clock.patch
diff --git a/src/bindings/wasix-ts/host/patches/0014-wasmer-js-track-directory-mutations.patch b/src/runtimes/wasix-browser-host/patches/0014-wasmer-js-track-directory-mutations.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0014-wasmer-js-track-directory-mutations.patch
rename to src/runtimes/wasix-browser-host/patches/0014-wasmer-js-track-directory-mutations.patch
diff --git a/src/bindings/wasix-ts/host/patches/0015-wasmer-js-add-sync-filesystem-bridge.patch b/src/runtimes/wasix-browser-host/patches/0015-wasmer-js-add-sync-filesystem-bridge.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0015-wasmer-js-add-sync-filesystem-bridge.patch
rename to src/runtimes/wasix-browser-host/patches/0015-wasmer-js-add-sync-filesystem-bridge.patch
diff --git a/src/bindings/wasix-ts/host/patches/0016-wasmer-wasix-direct-single-backend-clock.patch b/src/runtimes/wasix-browser-host/patches/0016-wasmer-wasix-direct-single-backend-clock.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0016-wasmer-wasix-direct-single-backend-clock.patch
rename to src/runtimes/wasix-browser-host/patches/0016-wasmer-wasix-direct-single-backend-clock.patch
diff --git a/src/bindings/wasix-ts/host/patches/0017-wasmer-js-direct-pgwire-memory-bridge.patch b/src/runtimes/wasix-browser-host/patches/0017-wasmer-js-direct-pgwire-memory-bridge.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0017-wasmer-js-direct-pgwire-memory-bridge.patch
rename to src/runtimes/wasix-browser-host/patches/0017-wasmer-js-direct-pgwire-memory-bridge.patch
diff --git a/src/bindings/wasix-ts/host/patches/0018-wasmer-js-bound-direct-stderr.patch b/src/runtimes/wasix-browser-host/patches/0018-wasmer-js-bound-direct-stderr.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0018-wasmer-js-bound-direct-stderr.patch
rename to src/runtimes/wasix-browser-host/patches/0018-wasmer-js-bound-direct-stderr.patch
diff --git a/src/bindings/wasix-ts/host/patches/0019-wasmer-parse-exception-reference-types.patch b/src/runtimes/wasix-browser-host/patches/0019-wasmer-parse-exception-reference-types.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0019-wasmer-parse-exception-reference-types.patch
rename to src/runtimes/wasix-browser-host/patches/0019-wasmer-parse-exception-reference-types.patch
diff --git a/src/bindings/wasix-ts/host/patches/0020-wasmer-wasix-preserve-posix-close-durability.patch b/src/runtimes/wasix-browser-host/patches/0020-wasmer-wasix-preserve-posix-close-durability.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0020-wasmer-wasix-preserve-posix-close-durability.patch
rename to src/runtimes/wasix-browser-host/patches/0020-wasmer-wasix-preserve-posix-close-durability.patch
diff --git a/src/bindings/wasix-ts/host/patches/0021-wasmer-js-stream-direct-pgwire.patch b/src/runtimes/wasix-browser-host/patches/0021-wasmer-js-stream-direct-pgwire.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0021-wasmer-js-stream-direct-pgwire.patch
rename to src/runtimes/wasix-browser-host/patches/0021-wasmer-js-stream-direct-pgwire.patch
diff --git a/src/bindings/wasix-ts/host/patches/0033-wasmer-wasix-poll-ready-asyncify-work.patch b/src/runtimes/wasix-browser-host/patches/0033-wasmer-wasix-poll-ready-asyncify-work.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0033-wasmer-wasix-poll-ready-asyncify-work.patch
rename to src/runtimes/wasix-browser-host/patches/0033-wasmer-wasix-poll-ready-asyncify-work.patch
diff --git a/src/bindings/wasix-ts/host/patches/0034-wasmer-js-preserve-seek-end-errors.patch b/src/runtimes/wasix-browser-host/patches/0034-wasmer-js-preserve-seek-end-errors.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0034-wasmer-js-preserve-seek-end-errors.patch
rename to src/runtimes/wasix-browser-host/patches/0034-wasmer-js-preserve-seek-end-errors.patch
diff --git a/src/bindings/wasix-ts/host/patches/0035-wasmer-wasix-preserve-shared-seek-offset.patch b/src/runtimes/wasix-browser-host/patches/0035-wasmer-wasix-preserve-shared-seek-offset.patch
similarity index 100%
rename from src/bindings/wasix-ts/host/patches/0035-wasmer-wasix-preserve-shared-seek-offset.patch
rename to src/runtimes/wasix-browser-host/patches/0035-wasmer-wasix-preserve-shared-seek-offset.patch
diff --git a/src/bindings/wasix-ts/host/source.toml b/src/runtimes/wasix-browser-host/source.toml
similarity index 100%
rename from src/bindings/wasix-ts/host/source.toml
rename to src/runtimes/wasix-browser-host/source.toml
diff --git a/src/runtimes/wasix-napi/Cargo.toml b/src/runtimes/wasix-napi/Cargo.toml
deleted file mode 100644
index 63dcce0b9..000000000
--- a/src/runtimes/wasix-napi/Cargo.toml
+++ /dev/null
@@ -1,116 +0,0 @@
-[package]
-name = "oliphaunt-wasix-napi"
-version = "0.1.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Node-API adapter for the Oliphaunt WASIX Rust runtime."
-repository = "https://github.com/f0rr0/oliphaunt"
-homepage = "https://oliphaunt.dev"
-license = "MIT"
-publish = false
-build = "build.rs"
-
-[lib]
-crate-type = ["cdylib"]
-
-[features]
-default = []
-extensions = ["oliphaunt-wasix/extensions"]
-tools = ["oliphaunt-wasix/tools", "dep:oliphaunt-wasix-tools"]
-test-noop = ["napi/noop"]
-release = [
-  "tools",
-  "extension-amcheck",
-  "extension-auto-explain",
-  "extension-bloom",
-  "extension-btree-gin",
-  "extension-btree-gist",
-  "extension-citext",
-  "extension-cube",
-  "extension-dict-int",
-  "extension-dict-xsyn",
-  "extension-earthdistance",
-  "extension-file-fdw",
-  "extension-fuzzystrmatch",
-  "extension-hstore",
-  "extension-intarray",
-  "extension-isn",
-  "extension-lo",
-  "extension-ltree",
-  "extension-pageinspect",
-  "extension-pg-buffercache",
-  "extension-pg-freespacemap",
-  "extension-pg-hashids",
-  "extension-pg-ivm",
-  "extension-pg-surgery",
-  "extension-pg-textsearch",
-  "extension-pg-trgm",
-  "extension-pg-uuidv7",
-  "extension-pg-visibility",
-  "extension-pg-walinspect",
-  "extension-pgcrypto",
-  "extension-pgtap",
-  "extension-postgis",
-  "extension-seg",
-  "extension-tablefunc",
-  "extension-tcn",
-  "extension-tsm-system-rows",
-  "extension-tsm-system-time",
-  "extension-unaccent",
-  "extension-uuid-ossp",
-  "extension-vector",
-]
-extension-amcheck = ["extensions", "oliphaunt-wasix/extension-amcheck"]
-extension-auto-explain = ["extensions", "oliphaunt-wasix/extension-auto-explain"]
-extension-bloom = ["extensions", "oliphaunt-wasix/extension-bloom"]
-extension-btree-gin = ["extensions", "oliphaunt-wasix/extension-btree-gin"]
-extension-btree-gist = ["extensions", "oliphaunt-wasix/extension-btree-gist"]
-extension-citext = ["extensions", "oliphaunt-wasix/extension-citext"]
-extension-cube = ["extensions", "oliphaunt-wasix/extension-cube"]
-extension-dict-int = ["extensions", "oliphaunt-wasix/extension-dict-int"]
-extension-dict-xsyn = ["extensions", "oliphaunt-wasix/extension-dict-xsyn"]
-extension-earthdistance = ["extensions", "oliphaunt-wasix/extension-earthdistance"]
-extension-file-fdw = ["extensions", "oliphaunt-wasix/extension-file-fdw"]
-extension-fuzzystrmatch = ["extensions", "oliphaunt-wasix/extension-fuzzystrmatch"]
-extension-hstore = ["extensions", "oliphaunt-wasix/extension-hstore"]
-extension-intarray = ["extensions", "oliphaunt-wasix/extension-intarray"]
-extension-isn = ["extensions", "oliphaunt-wasix/extension-isn"]
-extension-lo = ["extensions", "oliphaunt-wasix/extension-lo"]
-extension-ltree = ["extensions", "oliphaunt-wasix/extension-ltree"]
-extension-pageinspect = ["extensions", "oliphaunt-wasix/extension-pageinspect"]
-extension-pg-buffercache = ["extensions", "oliphaunt-wasix/extension-pg-buffercache"]
-extension-pg-freespacemap = ["extensions", "oliphaunt-wasix/extension-pg-freespacemap"]
-extension-pg-hashids = ["extensions", "oliphaunt-wasix/extension-pg-hashids"]
-extension-pg-ivm = ["extensions", "oliphaunt-wasix/extension-pg-ivm"]
-extension-pg-surgery = ["extensions", "oliphaunt-wasix/extension-pg-surgery"]
-extension-pg-textsearch = ["extensions", "oliphaunt-wasix/extension-pg-textsearch"]
-extension-pg-trgm = ["extensions", "oliphaunt-wasix/extension-pg-trgm"]
-extension-pg-uuidv7 = ["extensions", "oliphaunt-wasix/extension-pg-uuidv7"]
-extension-pg-visibility = ["extensions", "oliphaunt-wasix/extension-pg-visibility"]
-extension-pg-walinspect = ["extensions", "oliphaunt-wasix/extension-pg-walinspect"]
-extension-pgcrypto = ["extensions", "oliphaunt-wasix/extension-pgcrypto"]
-extension-pgtap = ["extensions", "oliphaunt-wasix/extension-pgtap"]
-extension-postgis = ["extensions", "oliphaunt-wasix/extension-postgis"]
-extension-seg = ["extensions", "oliphaunt-wasix/extension-seg"]
-extension-tablefunc = ["extensions", "oliphaunt-wasix/extension-tablefunc"]
-extension-tcn = ["extensions", "oliphaunt-wasix/extension-tcn"]
-extension-tsm-system-rows = ["extensions", "oliphaunt-wasix/extension-tsm-system-rows"]
-extension-tsm-system-time = ["extensions", "oliphaunt-wasix/extension-tsm-system-time"]
-extension-unaccent = ["extensions", "oliphaunt-wasix/extension-unaccent"]
-extension-uuid-ossp = ["extensions", "oliphaunt-wasix/extension-uuid-ossp"]
-extension-vector = ["extensions", "oliphaunt-wasix/extension-vector"]
-
-[dependencies]
-napi = { version = "=3.12.2", default-features = false, features = ["napi8"] }
-napi-derive = { version = "=3.6.3", default-features = false, features = ["strict", "type-def"] }
-liboliphaunt-wasix-portable = { version = "*", path = "../liboliphaunt/wasix/crates/assets" }
-oliphaunt-icu = { version = "*", path = "../liboliphaunt/icu" }
-oliphaunt-wasix = { version = "*", path = "../../bindings/wasix-rust/crates/oliphaunt-wasix", features = ["__internal-napi", "icu"] }
-oliphaunt-wasix-tools = { version = "*", path = "../liboliphaunt/wasix/crates/tools", optional = true }
-sha2 = "0.10"
-
-[target.'cfg(unix)'.dependencies]
-rustix = { version = "=1.1.4", features = ["fs"] }
-
-[build-dependencies]
-napi-build = "=2.4.1"
diff --git a/src/runtimes/wasix-napi/README.md b/src/runtimes/wasix-napi/README.md
deleted file mode 100644
index 681abaa76..000000000
--- a/src/runtimes/wasix-napi/README.md
+++ /dev/null
@@ -1,160 +0,0 @@
-# Oliphaunt WASIX Node-API Runtime
-
-This private product builds the Node-API boundary used by `@oliphaunt/wasix-ts`
-on Node.js, Bun, Deno, and Electron. Browser export conditions do not load this product;
-they continue to use the patched Wasmer JavaScript host.
-
-The addon supports four purpose-specific TypeScript placement paths:
-
-- the direct TypeScript entry point opens and runs the database on its caller's
-  JavaScript thread;
-- the default native-host entry point uses one Rust database-owner actor so
-  synchronous guest work does not block the importing event loop;
-- the `/worker` entry point loads the direct class inside a real package-owned
-  JavaScript Worker; and
-- `/server` wraps the Rust listener owner directly.
-
-Direct handles reject use from a thread other than their creator. The actor and
-server surfaces instead expose Promise-facing Rust owners and do not publish a
-movable native handle to JavaScript.
-
-This makes the lowest-hop path explicit without making it the event-loop-blocking
-default. Calls on `/direct` are synchronous at the native boundary; the root
-settles promises from the Rust actor, and `/worker` adds only its requested
-JavaScript Worker hop. The TypeScript facade retains one promise-shaped public
-API and serialization contract.
-
-## Binary boundary
-
-`execProtocolRaw`, `backup`, and tool output return ordinary V8-owned
-`Uint8Array` values. This keeps their lifetime and detach behavior predictable
-across Node-API implementations. Direct requests borrow JavaScript input only
-for the synchronous call; actor requests copy into Rust-owned admission data
-before the caller returns. The `/worker` transport transfers eligible V8-owned
-`ArrayBuffer` values instead of cloning them again.
-
-`execProtocolRawStream` uses the Rust runtime's synchronous protocol callback.
-It verifies that every callback remains on the creator thread before entering
-Node-API, copies each chunk into V8-owned memory, and returns
-`callbackAborted` only after PostgreSQL recovers to `ReadyForQuery`. An
-unexpected off-thread callback is stopped without touching the JavaScript
-environment.
-
-`pgDump` and `psql` return structured `{ status, stdout, stderr }` results
-whose output fields retain their exact bytes, including invalid UTF-8.
-Ordinary frontend nonzero exits therefore retain stdout and stderr. A
-`PostgresToolError` is still thrown with its structured diagnostics even if it
-reports exit code zero; unrelated runtime failures remain thrown errors.
-
-`extensionIdentity(sqlName)` and `toolIdentity(name)` expose each embedded
-archive/module as canonical `sha256:size`. The TypeScript adapter compares
-these identities with its validated public descriptors, so a same-name but
-different payload fails before database startup or tool execution.
-
-`payloadIdentity(component)` exposes the same identity form for the runtime,
-standard seed, ICU data, and ICU seed payloads embedded in the single addon.
-
-## Standard and ICU profiles
-
-Each platform carrier contains one stable addon subpath,
-`oliphaunt_wasix_napi.node`. The release feature embeds both the standard and
-ICU payloads in that binary, and database open options select the requested
-profile. `supportedProfiles()` reports the exact `['standard', 'icu']` contract.
-
-The existing TypeScript `icu` option therefore changes the selected database
-profile, not the package or binary that gets loaded. The default remains the
-standard profile.
-
-Release builds enable the `release` Cargo feature, which includes packaged
-PostgreSQL tools and all extension features supported by the WASIX catalog.
-The TypeScript API continues to accept extension descriptors, but the addon
-receives the validated SQL names and resolves them against this compile-time
-catalog. It never loads arbitrary extension bytes from JavaScript. A new or
-updated server extension, or a changed frontend tool, therefore needs a new
-N-API carrier release. This makes each carrier larger, but removes portable
-archive expansion, WebAssembly compilation, and dynamic side-module linking
-from server startup.
-
-Source-only `cargo check` intentionally leaves those payload features disabled.
-The artifact build validates every staged runtime, tool, extension, cluster
-seed, and AOT payload before embedding it.
-
-`tools/build-native.sh` fails closed unless the same-run producer outputs are
-available through the dependency build-script contract:
-
-- `OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR` points at the portable runtime and
-  split `pg_dump`/`psql` payload root;
-- `OLIPHAUNT_WASM_GENERATED_AOT_DIR` points at the root containing the current
-  Rust target triple's core and tool AOT manifest;
-- `OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT` points at the exact portable and
-  per-target AOT extension inventory;
-- `OLIPHAUNT_ICU_DATA_DIR` points at the portable ICU data tree; and
-- `OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD=1` prevents every dependency crate
-  from selecting its source-only fallback.
-
-The build records and rechecks a deterministic inventory before packaging.
-Its portable manifest, split tools, host AOT manifest, every selected extension
-manifest/archive/AOT manifest, and ICU tree digest are embedded under
-`artifact-provenance.json.buildInputs` in both distribution forms. Its `build`
-object also records the release Cargo profile, disabled incremental compilation,
-single codegen unit, thin LTO, symbol stripping, exact `release` feature, and
-Rust target triple.
-The addon's `runtimeVersion()` identity comes directly from the selected
-`liboliphaunt-wasix-portable` crate. Workspace builds therefore report the
-local runtime while released carriers retain exact product compatibility pins.
-Product metadata tracks the runtime and `oliphaunt-wasix` Rust binding as
-separate compatibility versions; they are not assumed to advance together.
-
-## Distribution
-
-The canonical build package is private. `@oliphaunt/wasix-ts` declares public
-platform carriers as optional dependencies, allowing npm-compatible package
-managers to install only the matching target:
-
-- `@oliphaunt/wasix-napi-darwin-arm64`
-- `@oliphaunt/wasix-napi-linux-arm64-gnu`
-- `@oliphaunt/wasix-napi-linux-x64-gnu`
-- `@oliphaunt/wasix-napi-win32-x64-msvc`
-
-Carrier packages have no install scripts and never download executable code.
-`tools/build-native.sh` creates the single profile-complete addon and
-`tools/package-platform.mjs` stages the matching carrier and portable release
-archive with source/artifact provenance before `pnpm pack`. Per-target jobs do
-not write the shared checksum filename; the aggregate release-assets task
-writes one canonical checksum manifest after all four target outputs merge.
-
-The supported target set is intentionally closed: macOS arm64, Linux arm64 or
-x64 with glibc, and Windows x64 with MSVC. macOS x64, Linux musl, and Windows
-arm64 do not have carriers. The native builder detects its Linux libc and
-rejects musl or an unidentifiable libc before compiling a GNU carrier. The
-Linux release addons are then compiled inside the pinned Rust 1.93.1 Debian
-Bookworm image (glibc 2.36), with exact payload paths mounted read-only and the
-actual build run without network access. This keeps them below the published
-glibc 2.38 ceiling; release staging also validates their ELF shape and resolves
-their dynamic dependencies in the pinned Fedora 39 glibc 2.38 consumer
-fixture. The runtime loader performs the same libc check before resolving even
-an explicit addon override. An unsupported target or
-missing optional package fails explicitly; the server export never falls back
-to the browser Wasmer implementation.
-
-Release staging pins every carrier to the exact N-API product version. Before
-loading native code, the TypeScript adapter checks the package identity,
-version, target, WASIX runtime version, addon ABI, Node-API level, and presence
-of both profiles. It then checks the addon's self-reported runtime and supported
-profiles. Artifact provenance records the exact source and embedded input
-identities used for the binary.
-
-Deno requires a local `node_modules` directory plus `--allow-ffi`,
-`--allow-read`, and `--allow-env`; directory databases need the corresponding
-filesystem permissions. Its `/worker` path uses the Node-compatible Worker
-implementation and does not require process-spawn permission. Managed Deno
-Deploy is not a qualified distribution target. Node.js, Bun, Deno, and Electron
-load the same Node-API 8 binary for their platform.
-
-Electron applications should configure their packager to leave
-`**/prebuilds/**` unpacked and ship `app.asar.unpacked` beside `app.asar`. This
-keeps the addon and any platform loader companions, including the Windows
-app-local VC runtime, in one loadable directory. Electron can otherwise extract
-native modules to a temporary file, which adds startup work and can interact
-poorly with antivirus scanners. Each carrier job exercises the ASAR-unpacked
-layout and its missing-companion failure mode.
diff --git a/src/runtimes/wasix-napi/build.rs b/src/runtimes/wasix-napi/build.rs
deleted file mode 100644
index f8f669cc8..000000000
--- a/src/runtimes/wasix-napi/build.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-use std::path::{Path, PathBuf};
-
-const RELEASE_INPUT_ENVS: &[&str] = &[
-    "OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD",
-    "OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR",
-    "OLIPHAUNT_WASM_GENERATED_AOT_DIR",
-    "OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT",
-    "OLIPHAUNT_ICU_DATA_DIR",
-    "OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS",
-];
-
-fn main() {
-    napi_build::setup();
-    for name in RELEASE_INPUT_ENVS {
-        println!("cargo::rerun-if-env-changed={name}");
-    }
-    println!("cargo::rustc-env=OLIPHAUNT_WASIX_NAPI_ABI_VERSION=1");
-    validate_release_inputs();
-}
-
-fn validate_release_inputs() {
-    if std::env::var_os("CARGO_FEATURE_RELEASE").is_none() {
-        return;
-    }
-    assert!(
-        matches!(
-            std::env::var("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").as_deref(),
-            Ok("1")
-        ),
-        "WASIX N-API release builds must set OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD=1",
-    );
-
-    let portable = required_directory("OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR");
-    for relative in [
-        "manifest.json",
-        "oliphaunt.wasix.tar.zst",
-        "bin/initdb.wasix.wasm",
-        "bin/pg_dump.wasix.wasm",
-        "bin/psql.wasix.wasm",
-        "cluster-seeds/standard.tar.zst",
-        "cluster-seeds/standard.json",
-        "cluster-seeds/icu.tar.zst",
-        "cluster-seeds/icu.json",
-    ] {
-        required_file(&portable.join(relative), "portable WASIX release payload");
-    }
-
-    let target = std::env::var("TARGET").expect("Cargo provides TARGET");
-    let aot_root = required_directory("OLIPHAUNT_WASM_GENERATED_AOT_DIR");
-    let target_aot = if aot_root.ends_with(&target) {
-        aot_root
-    } else {
-        aot_root.join(&target)
-    };
-    required_file(
-        &target_aot.join("manifest.json"),
-        "target WASIX core/tools AOT manifest",
-    );
-
-    let extension_root = required_directory("OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT");
-    assert!(
-        std::fs::read_dir(&extension_root)
-            .expect("read exact WASIX extension artifact root")
-            .next()
-            .is_some(),
-        "exact WASIX extension artifact root {} must not be empty",
-        extension_root.display(),
-    );
-    let icu_root = required_directory("OLIPHAUNT_ICU_DATA_DIR");
-    assert!(
-        std::fs::read_dir(&icu_root)
-            .expect("read ICU data root")
-            .next()
-            .is_some(),
-        "ICU data root {} must not be empty",
-        icu_root.display(),
-    );
-
-    let inventory = required_path("OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS");
-    required_file(&inventory, "validated WASIX N-API build-input inventory");
-    println!("cargo::rerun-if-changed={}", inventory.display());
-
-    // `oliphaunt-wasix` relays the manifests emitted by the exact payload
-    // crates it compiled. Requiring all four proves Cargo selected embedded
-    // portable/core-AOT/tool/tool-AOT inputs, not only that similarly named
-    // files happened to exist in the workspace.
-    let target_suffix = match target.as_str() {
-        "aarch64-apple-darwin" => "MACOS_ARM64",
-        "aarch64-unknown-linux-gnu" => "LINUX_ARM64_GNU",
-        "x86_64-unknown-linux-gnu" => "LINUX_X64_GNU",
-        "x86_64-pc-windows-msvc" => "WINDOWS_X64_MSVC",
-        other => panic!("unsupported WASIX N-API release target {other}"),
-    };
-    for name in [
-        "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_LIBOLIPHAUNT_WASIX_RUNTIME_MANIFEST".to_owned(),
-        "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_OLIPHAUNT_WASIX_TOOLS_MANIFEST".to_owned(),
-        format!(
-            "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_LIBOLIPHAUNT_WASIX_AOT_{target_suffix}_MANIFEST"
-        ),
-        format!(
-            "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_OLIPHAUNT_WASIX_TOOLS_AOT_{target_suffix}_MANIFEST"
-        ),
-    ] {
-        required_env_file(&name, "relayed WASIX Cargo artifact manifest");
-    }
-    if std::env::var_os("CARGO_FEATURE_ICU").is_some() {
-        required_env_file(
-            "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_OLIPHAUNT_ICU_MANIFEST",
-            "relayed ICU Cargo artifact manifest",
-        );
-    }
-}
-
-fn required_path(name: &str) -> PathBuf {
-    std::env::var_os(name)
-        .filter(|value| !value.is_empty())
-        .map(PathBuf::from)
-        .unwrap_or_else(|| panic!("WASIX N-API release builds require {name}"))
-}
-
-fn required_directory(name: &str) -> PathBuf {
-    let path = required_path(name);
-    let metadata = std::fs::symlink_metadata(&path)
-        .unwrap_or_else(|error| panic!("inspect {name} {}: {error}", path.display()));
-    assert!(
-        metadata.is_dir() && !metadata.file_type().is_symlink(),
-        "{name} must be a regular non-symlink directory: {}",
-        path.display(),
-    );
-    path
-}
-
-fn required_file(path: &Path, label: &str) {
-    let metadata = std::fs::symlink_metadata(path)
-        .unwrap_or_else(|error| panic!("inspect {label} {}: {error}", path.display()));
-    assert!(
-        metadata.is_file() && !metadata.file_type().is_symlink() && metadata.len() > 0,
-        "{label} must be a non-empty regular non-symlink file: {}",
-        path.display(),
-    );
-}
-
-fn required_env_file(name: &str, label: &str) {
-    println!("cargo::rerun-if-env-changed={name}");
-    let path = required_path(name);
-    required_file(&path, label);
-    println!("cargo::rerun-if-changed={}", path.display());
-}
diff --git a/src/runtimes/wasix-napi/moon.yml b/src/runtimes/wasix-napi/moon.yml
deleted file mode 100644
index 286be71bf..000000000
--- a/src/runtimes/wasix-napi/moon.yml
+++ /dev/null
@@ -1,95 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "oliphaunt-wasix-napi"
-language: "rust"
-layer: "library"
-stack: "systems"
-tags: ["runtime", "wasix", "native", "node-api", "release-product"]
-dependsOn:
-  - id: "liboliphaunt-wasix"
-    scope: "production"
-  - id: "oliphaunt-wasix-rust"
-    scope: "production"
-
-project:
-  title: "Oliphaunt WASIX Node-API Runtime"
-  description: "Node-API adapter over the Oliphaunt WASIX Rust binding."
-  owner: "oliphaunt"
-  release:
-    component: "oliphaunt-wasix-napi"
-    packagePath: "src/runtimes/wasix-napi"
-    artifactTargets:
-      preset: "wasix-napi-addon"
-      targets:
-        - "linux-arm64-gnu"
-        - "linux-x64-gnu"
-        - "macos-arm64"
-        - "windows-x64-msvc"
-
-owners:
-  defaultOwner: "@oliphaunt/wasix-napi"
-
-fileGroups:
-  code:
-    - "**/*"
-    - "!**/*.md"
-    - "!moon.yml"
-    - "!release.toml"
-
-tasks:
-  format-check:
-    tags: ["quality", "format", "requires-rust"]
-    command: "cargo fmt --manifest-path Cargo.toml --check"
-    inputs:
-      - "Cargo.toml"
-      - "build.rs"
-      - "src/**/*.rs"
-    options:
-      cache: true
-
-  compile:
-    tags: ["quality", "static", "requires-rust"]
-    script: |
-      set -e
-      node --check tools/smoke-packaged-addon.mjs
-      cargo check --manifest-path Cargo.toml --locked --no-default-features
-    env:
-      CARGO_TARGET_DIR: "../../../target/moon/oliphaunt-wasix-napi/compile"
-    inputs:
-      - "@group(cargo-workspace)"
-      - project: "oliphaunt-wasix-rust"
-        group: "code"
-      - project: "liboliphaunt-wasix"
-        group: "crates"
-      - "/src/runtimes/liboliphaunt/icu/**/*"
-      - "Cargo.toml"
-      - "build.rs"
-      - "src/**/*"
-      - "tools/smoke-packaged-addon.mjs"
-    options:
-      cache: true
-
-  unit:
-    tags: ["quality", "unit", "requires-rust"]
-    script: |
-      set -e
-      bun test tools/detect-linux-libc.test.mjs tools/portable-command.test.mjs
-      cargo test --manifest-path Cargo.toml --locked --no-default-features --features test-noop --lib
-    env:
-      CARGO_TARGET_DIR: "../../../target/moon/oliphaunt-wasix-napi/unit"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "@group(code)"
-    options:
-      cache: true
-
-  qualify:
-    tags: ["release"]
-    command: "true"
-    deps:
-      - "oliphaunt-wasix-napi:format-check"
-      - "oliphaunt-wasix-napi:compile"
-      - "oliphaunt-wasix-napi:unit"
-    inputs: []
-    options:
-      cache: true
diff --git a/src/runtimes/wasix-napi/package.json b/src/runtimes/wasix-napi/package.json
deleted file mode 100644
index 6507473dc..000000000
--- a/src/runtimes/wasix-napi/package.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
-  "name": "@oliphaunt/wasix-napi",
-  "version": "0.1.0",
-  "description": "Private build package for the Oliphaunt WASIX Node-API runtime.",
-  "license": "MIT",
-  "private": true,
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/wasix-napi"
-  },
-  "oliphaunt": {
-    "runtimeProduct": "liboliphaunt-wasix",
-    "runtimeVersion": "0.2.0",
-    "rustBindingProduct": "oliphaunt-wasix-rust",
-    "rustBindingVersion": "0.2.0",
-    "addonAbiVersion": 1,
-    "nodeApiVersion": 8,
-    "profiles": [
-      "standard",
-      "icu"
-    ]
-  },
-  "files": [
-    "src",
-    "packages",
-    "tools",
-    "Cargo.toml",
-    "build.rs",
-    "README.md",
-    "CHANGELOG.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md"
-  ],
-  "scripts": {
-    "build": "bash tools/build-native.sh",
-    "package": "node tools/package-platform.mjs"
-  },
-  "engines": {
-    "node": ">=22.13 <25",
-    "bun": ">=1.3.14",
-    "deno": ">=2.8.1"
-  }
-}
diff --git a/src/runtimes/wasix-napi/packages/darwin-arm64/package.json b/src/runtimes/wasix-napi/packages/darwin-arm64/package.json
deleted file mode 100644
index 016dbcb32..000000000
--- a/src/runtimes/wasix-napi/packages/darwin-arm64/package.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-  "name": "@oliphaunt/wasix-napi-darwin-arm64",
-  "version": "0.1.0",
-  "description": "macOS arm64 prebuilt Oliphaunt WASIX Node-API runtime.",
-  "license": "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0",
-  "type": "commonjs",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/wasix-napi/packages/darwin-arm64"
-  },
-  "os": [
-    "darwin"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "macos-arm64",
-    "runtimeProduct": "liboliphaunt-wasix",
-    "runtimeVersion": "0.2.0",
-    "addonAbiVersion": 1,
-    "nodeApiVersion": 8,
-    "profiles": [
-      "standard",
-      "icu"
-    ]
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "files": [
-    "prebuilds",
-    "artifact-provenance.json",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
-    "THIRD_PARTY_LICENSES"
-  ],
-  "exports": {
-    "./oliphaunt_wasix_napi.node": "./prebuilds/oliphaunt_wasix_napi.node",
-    "./artifact-provenance.json": "./artifact-provenance.json",
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/wasix-napi/packages/linux-arm64-gnu/package.json b/src/runtimes/wasix-napi/packages/linux-arm64-gnu/package.json
deleted file mode 100644
index cc4c13f41..000000000
--- a/src/runtimes/wasix-napi/packages/linux-arm64-gnu/package.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
-  "name": "@oliphaunt/wasix-napi-linux-arm64-gnu",
-  "version": "0.1.0",
-  "description": "Linux arm64 glibc prebuilt Oliphaunt WASIX Node-API runtime.",
-  "license": "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0",
-  "type": "commonjs",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/wasix-napi/packages/linux-arm64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "arm64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "linux-arm64-gnu",
-    "runtimeProduct": "liboliphaunt-wasix",
-    "runtimeVersion": "0.2.0",
-    "addonAbiVersion": 1,
-    "nodeApiVersion": 8,
-    "profiles": [
-      "standard",
-      "icu"
-    ]
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "files": [
-    "prebuilds",
-    "artifact-provenance.json",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
-    "THIRD_PARTY_LICENSES"
-  ],
-  "exports": {
-    "./oliphaunt_wasix_napi.node": "./prebuilds/oliphaunt_wasix_napi.node",
-    "./artifact-provenance.json": "./artifact-provenance.json",
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/wasix-napi/packages/linux-x64-gnu/package.json b/src/runtimes/wasix-napi/packages/linux-x64-gnu/package.json
deleted file mode 100644
index f81d8df46..000000000
--- a/src/runtimes/wasix-napi/packages/linux-x64-gnu/package.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
-  "name": "@oliphaunt/wasix-napi-linux-x64-gnu",
-  "version": "0.1.0",
-  "description": "Linux x64 glibc prebuilt Oliphaunt WASIX Node-API runtime.",
-  "license": "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0",
-  "type": "commonjs",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/wasix-napi/packages/linux-x64-gnu"
-  },
-  "os": [
-    "linux"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "libc": [
-    "glibc"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "linux-x64-gnu",
-    "runtimeProduct": "liboliphaunt-wasix",
-    "runtimeVersion": "0.2.0",
-    "addonAbiVersion": 1,
-    "nodeApiVersion": 8,
-    "profiles": [
-      "standard",
-      "icu"
-    ]
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "files": [
-    "prebuilds",
-    "artifact-provenance.json",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
-    "THIRD_PARTY_LICENSES"
-  ],
-  "exports": {
-    "./oliphaunt_wasix_napi.node": "./prebuilds/oliphaunt_wasix_napi.node",
-    "./artifact-provenance.json": "./artifact-provenance.json",
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/wasix-napi/packages/win32-x64-msvc/package.json b/src/runtimes/wasix-napi/packages/win32-x64-msvc/package.json
deleted file mode 100644
index 9437c884f..000000000
--- a/src/runtimes/wasix-napi/packages/win32-x64-msvc/package.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-  "name": "@oliphaunt/wasix-napi-win32-x64-msvc",
-  "version": "0.1.0",
-  "description": "Windows x64 MSVC prebuilt Oliphaunt WASIX Node-API runtime.",
-  "license": "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0",
-  "type": "commonjs",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/runtimes/wasix-napi/packages/win32-x64-msvc"
-  },
-  "os": [
-    "win32"
-  ],
-  "cpu": [
-    "x64"
-  ],
-  "optional": true,
-  "oliphaunt": {
-    "target": "windows-x64-msvc",
-    "runtimeProduct": "liboliphaunt-wasix",
-    "runtimeVersion": "0.2.0",
-    "addonAbiVersion": 1,
-    "nodeApiVersion": 8,
-    "profiles": [
-      "standard",
-      "icu"
-    ]
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "files": [
-    "prebuilds",
-    "artifact-provenance.json",
-    "README.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
-    "THIRD_PARTY_LICENSES"
-  ],
-  "exports": {
-    "./oliphaunt_wasix_napi.node": "./prebuilds/oliphaunt_wasix_napi.node",
-    "./artifact-provenance.json": "./artifact-provenance.json",
-    "./package.json": "./package.json"
-  }
-}
diff --git a/src/runtimes/wasix-napi/release.toml b/src/runtimes/wasix-napi/release.toml
deleted file mode 100644
index 915c6e346..000000000
--- a/src/runtimes/wasix-napi/release.toml
+++ /dev/null
@@ -1,41 +0,0 @@
-id = "oliphaunt-wasix-napi"
-owner = "@oliphaunt/wasix-napi"
-kind = "runtime"
-publish_targets = ["npm", "github-release-assets"]
-registry_packages = [
-  "npm:@oliphaunt/wasix-napi-darwin-arm64",
-  "npm:@oliphaunt/wasix-napi-linux-arm64-gnu",
-  "npm:@oliphaunt/wasix-napi-linux-x64-gnu",
-  "npm:@oliphaunt/wasix-napi-win32-x64-msvc",
-]
-release_artifacts = ["node-api-prebuilds", "npm-optional-platform-packages"]
-
-[compatibility_versions.oliphaunt-wasix-napi-runtime]
-source_product = "liboliphaunt-wasix"
-path = "src/runtimes/wasix-napi/package.json"
-parser = "json:oliphaunt.runtimeVersion"
-
-[compatibility_versions.oliphaunt-wasix-napi-runtime-darwin-arm64]
-source_product = "liboliphaunt-wasix"
-path = "src/runtimes/wasix-napi/packages/darwin-arm64/package.json"
-parser = "json:oliphaunt.runtimeVersion"
-
-[compatibility_versions.oliphaunt-wasix-napi-runtime-linux-arm64-gnu]
-source_product = "liboliphaunt-wasix"
-path = "src/runtimes/wasix-napi/packages/linux-arm64-gnu/package.json"
-parser = "json:oliphaunt.runtimeVersion"
-
-[compatibility_versions.oliphaunt-wasix-napi-runtime-linux-x64-gnu]
-source_product = "liboliphaunt-wasix"
-path = "src/runtimes/wasix-napi/packages/linux-x64-gnu/package.json"
-parser = "json:oliphaunt.runtimeVersion"
-
-[compatibility_versions.oliphaunt-wasix-napi-runtime-win32-x64-msvc]
-source_product = "liboliphaunt-wasix"
-path = "src/runtimes/wasix-napi/packages/win32-x64-msvc/package.json"
-parser = "json:oliphaunt.runtimeVersion"
-
-[compatibility_versions.oliphaunt-wasix-napi-wasix-rust]
-source_product = "oliphaunt-wasix-rust"
-path = "src/runtimes/wasix-napi/package.json"
-parser = "json:oliphaunt.rustBindingVersion"
diff --git a/src/runtimes/wasix-napi/src/lib.rs b/src/runtimes/wasix-napi/src/lib.rs
deleted file mode 100644
index 634134823..000000000
--- a/src/runtimes/wasix-napi/src/lib.rs
+++ /dev/null
@@ -1,1446 +0,0 @@
-//! Node-API boundary for the Oliphaunt WASIX Rust runtime.
-//!
-//! `NativeWasixActorDatabase` and `NativeWasixServer` reuse the Rust async
-//! owners directly. Promise settlement is the only owner-to-JavaScript hop;
-//! no Tokio runtime or Node async-work queue participates in database work.
-
-use std::collections::BTreeMap;
-use std::mem;
-use std::panic::{AssertUnwindSafe, catch_unwind};
-use std::path::PathBuf;
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Condvar, Mutex, OnceLock};
-use std::thread::{self, ThreadId};
-
-use napi::Env;
-use napi::bindgen_prelude::{
-    Function, JsObjectValue, JsValue, Object, ObjectFinalize, ToNapiValue, Uint8Array,
-    Uint8ArraySlice,
-};
-use napi::threadsafe_function::{ThreadsafeCallContext, ThreadsafeFunctionCallMode};
-use napi::{Error, Result, Status};
-use napi_derive::napi;
-#[cfg(feature = "extensions")]
-use oliphaunt_wasix::Extension;
-#[cfg(feature = "tools")]
-use oliphaunt_wasix::tools::{PgDumpOptions, PostgresToolOutput, PsqlOptions};
-use oliphaunt_wasix::{
-    AsyncOliphaunt, AsyncOliphauntBuilder, AsyncOliphauntServer, AsyncOliphauntServerBuilder,
-    CatalogProfile, DatabaseStorage, ErrorKind, Oliphaunt, OliphauntBuilder, RawStreamError,
-    ServerListen, StorageCommitState, StorageErrorCode, StorageErrorPhase,
-};
-use sha2::{Digest, Sha256};
-
-const ADDON_ABI_VERSION: u32 = 1;
-const NODE_API_VERSION: u32 = 8;
-const RUNTIME_VERSION: &str = liboliphaunt_wasix_portable::PACKAGE_VERSION;
-
-/// Keep the native image mapped after a JavaScript Worker environment exits.
-///
-/// The synchronous `/direct` placement can initialize Wasmer/WASIX's
-/// process-wide Tokio runtime without first creating a Node-API deferred or
-/// threadsafe function. Those napi-rs values normally request this same pin,
-/// but a direct-only Worker has neither. The runtime's native threads can
-/// outlive that Worker environment, so Windows must not `FreeLibrary` (and
-/// Unix hosts must not `dlclose`) the code containing their wakers. napi-rs
-/// implements this as a process-once loader reference and leaves the event
-/// loop unreferenced.
-#[inline]
-fn retain_addon_image_for_process_runtime() {
-    #[cfg(not(feature = "test-noop"))]
-    napi::bindgen_prelude::retain_current_module_for_unload_safety();
-}
-
-#[napi(object)]
-pub struct NativeStorageOptions {
-    pub kind: String,
-    pub path: Option,
-}
-
-#[napi(object)]
-pub struct NativeOpenOptions {
-    pub profile: String,
-    pub storage: NativeStorageOptions,
-    pub username: String,
-    pub database: String,
-    #[napi(js_name = "startupGucs")]
-    pub startup_gucs: BTreeMap,
-    pub extensions: Vec,
-}
-
-#[napi(object)]
-pub struct NativeListenOptions {
-    pub transport: String,
-    pub port: Option,
-    pub directory: Option,
-}
-
-#[napi(object)]
-pub struct NativeServerOpenOptions {
-    pub profile: String,
-    pub storage: NativeStorageOptions,
-    pub username: String,
-    pub database: String,
-    #[napi(js_name = "startupGucs")]
-    pub startup_gucs: BTreeMap,
-    pub extensions: Vec,
-    pub listen: NativeListenOptions,
-}
-
-#[napi(object)]
-pub struct NativeToolResult {
-    pub status: i32,
-    pub stdout: Uint8Array,
-    pub stderr: Uint8Array,
-}
-
-#[derive(Debug)]
-struct CreatorThread {
-    id: ThreadId,
-}
-
-impl CreatorThread {
-    fn current() -> Self {
-        Self {
-            id: thread::current().id(),
-        }
-    }
-
-    fn require(&self, owner: &'static str) -> Result<()> {
-        if thread::current().id() == self.id {
-            return Ok(());
-        }
-        Err(Error::new(
-            Status::GenericFailure,
-            format!(
-                "{owner} is bound to the JavaScript thread that created it; open and use it in the same Node.js, Bun, Deno, or Electron isolate"
-            ),
-        ))
-    }
-}
-
-/// Synchronous database owner for the `/direct` placement and for a real
-/// JavaScript Worker placement which loads `/direct` in its own isolate.
-#[napi(custom_finalize)]
-pub struct NativeWasixDatabase {
-    owner: CreatorThread,
-    database: Option,
-}
-
-impl NativeWasixDatabase {
-    fn invoke_result(
-        &mut self,
-        env: &Env,
-        operation: &'static str,
-        action: impl FnOnce(&mut Oliphaunt) -> std::result::Result,
-    ) -> Result> {
-        self.owner.require("WASIX direct database")?;
-        let Some(mut database) = self.database.take() else {
-            return Err(native_lifecycle_error(
-                env,
-                operation,
-                "WASIX direct database is closed",
-            ));
-        };
-        match catch_unwind(AssertUnwindSafe(|| action(&mut database))) {
-            Ok(result) => {
-                self.database = Some(database);
-                Ok(result)
-            }
-            Err(payload) => {
-                // The Wasmer store cannot be trusted after an unwind. Retire
-                // and quarantine it instead of allowing a second entry or Drop.
-                mem::forget(payload);
-                mem::forget(database);
-                Err(native_lifecycle_error(
-                    env,
-                    operation,
-                    "WASIX direct database panicked and was permanently retired",
-                ))
-            }
-        }
-    }
-
-    fn invoke_core(
-        &mut self,
-        env: &Env,
-        operation: &'static str,
-        action: impl FnOnce(&mut Oliphaunt) -> oliphaunt_wasix::Result,
-    ) -> Result> {
-        self.invoke_result(env, operation, action)
-    }
-
-    fn invoke(
-        &mut self,
-        env: &Env,
-        operation: &'static str,
-        action: impl FnOnce(&mut Oliphaunt) -> oliphaunt_wasix::Result,
-    ) -> Result {
-        self.invoke_core(env, operation, action)?
-            .map_err(|error| native_runtime_error(env, operation, error))
-    }
-}
-
-impl Drop for NativeWasixDatabase {
-    fn drop(&mut self) {
-        let Some(mut database) = self.database.take() else {
-            return;
-        };
-        if thread::current().id() != self.owner.id {
-            mem::forget(database);
-            return;
-        }
-        if let Err(payload) = catch_unwind(AssertUnwindSafe(|| {
-            let _ = database.close();
-        })) {
-            mem::forget(payload);
-            mem::forget(database);
-        }
-    }
-}
-
-impl ObjectFinalize for NativeWasixDatabase {
-    fn finalize(mut self, _env: Env) -> Result<()> {
-        // A V8/N-API finalizer is an environment-teardown callback, not an
-        // explicit lifecycle operation. Synchronous PostgreSQL shutdown could
-        // hang teardown indefinitely, so quarantine the still-open creator-
-        // thread-affine store. An already closed store is safe to drop and
-        // release normally; explicit `close()` therefore does not leak its
-        // Wasmer allocation. Drop sees `None` after this method.
-        drop_if_closed_or_quarantine(&mut self.database, Oliphaunt::is_closed);
-        Ok(())
-    }
-}
-
-fn drop_if_closed_or_quarantine(value: &mut Option, is_closed: impl FnOnce(&T) -> bool) {
-    if let Some(value) = value.take() {
-        if is_closed(&value) {
-            drop(value);
-        } else {
-            mem::forget(value);
-        }
-    }
-}
-
-#[napi]
-impl NativeWasixDatabase {
-    #[napi(factory, catch_unwind)]
-    pub fn open(env: Env, options: NativeOpenOptions) -> Result {
-        retain_addon_image_for_process_runtime();
-        let database = configure_direct_database(options)?
-            .open()
-            .map_err(|error| native_runtime_error(&env, "open WASIX direct database", error))?;
-        Ok(Self {
-            owner: CreatorThread::current(),
-            database: Some(database),
-        })
-    }
-
-    #[napi(getter, catch_unwind)]
-    pub fn closed(&self) -> Result {
-        self.owner.require("WASIX direct database")?;
-        Ok(self.database.as_ref().is_none_or(Oliphaunt::is_closed))
-    }
-
-    #[napi(js_name = "execProtocolRaw", catch_unwind)]
-    pub fn exec_protocol_raw(
-        &mut self,
-        env: Env,
-        request: Uint8ArraySlice<'_>,
-    ) -> Result {
-        let response = self.invoke(&env, "execute PostgreSQL protocol request", |database| {
-            database.exec_protocol_raw(request.as_ref())
-        })?;
-        v8_owned_bytes(&env, &response)
-    }
-
-    #[napi(js_name = "execProtocolRawStream", catch_unwind)]
-    pub fn exec_protocol_raw_stream(
-        &mut self,
-        env: Env,
-        request: Uint8ArraySlice<'_>,
-        on_chunk: Function<'_, Uint8Array, ()>,
-    ) -> Result<&'static str> {
-        let callback = on_chunk.create_ref()?;
-        let raw_env = env.raw() as usize;
-        let owner_thread = self.owner.id;
-        let result =
-            self.invoke_result(&env, "stream PostgreSQL protocol response", |database| {
-                database.exec_protocol_raw_stream(request.as_ref(), move |chunk| {
-                    if thread::current().id() != owner_thread {
-                        return Err(Error::new(
-                            Status::GenericFailure,
-                            "WASIX protocol callback left its JavaScript owner thread",
-                        ));
-                    }
-                    let callback_env = Env::from_raw(raw_env as napi::sys::napi_env);
-                    let output = v8_owned_bytes(&callback_env, chunk)?;
-                    callback.borrow_back(&callback_env)?.call(output)
-                })
-            })?;
-        match result {
-            Ok(()) => Ok("complete"),
-            Err(RawStreamError::Callback(_)) => Ok("callbackAborted"),
-            Err(RawStreamError::Database(error)) => Err(native_runtime_error(
-                &env,
-                "stream PostgreSQL protocol response",
-                error,
-            )),
-            Err(RawStreamError::CallbackPanicked(error)) => Err(native_runtime_error(
-                &env,
-                "stream PostgreSQL protocol callback",
-                error,
-            )),
-            Err(_) => Err(Error::new(
-                Status::GenericFailure,
-                "stream PostgreSQL protocol response: unknown stream error",
-            )),
-        }
-    }
-
-    #[napi(catch_unwind)]
-    pub fn backup(&mut self, env: Env) -> Result {
-        let backup = self.invoke(&env, "back up WASIX database", Oliphaunt::backup)?;
-        v8_owned_bytes(&env, &backup)
-    }
-
-    #[napi(js_name = "pgDump", catch_unwind)]
-    pub fn pg_dump(&mut self, env: Env, args: Vec) -> Result {
-        #[cfg(feature = "tools")]
-        {
-            let output = self.invoke_core(&env, "run WASIX pg_dump", |database| {
-                database.pg_dump_output(PgDumpOptions::new().args(args))
-            })?;
-            native_tool_result(&env, "run WASIX pg_dump", output)
-        }
-        #[cfg(not(feature = "tools"))]
-        {
-            let _ = (env, args);
-            Err(missing_release_feature("tools", "pgDump"))
-        }
-    }
-
-    #[napi(catch_unwind)]
-    pub fn psql(
-        &mut self,
-        env: Env,
-        args: Vec,
-        command: Option,
-        script: Option,
-    ) -> Result {
-        if command.is_some() && script.is_some() {
-            return Err(invalid_argument(
-                "psql accepts either command or script, not both",
-            ));
-        }
-        #[cfg(feature = "tools")]
-        {
-            let options = psql_options(args, command, script);
-            let output = self.invoke_core(&env, "run WASIX psql", |database| {
-                database.psql_output(options)
-            })?;
-            native_tool_result(&env, "run WASIX psql", output)
-        }
-        #[cfg(not(feature = "tools"))]
-        {
-            let _ = (env, args, command, script);
-            Err(missing_release_feature("tools", "psql"))
-        }
-    }
-
-    #[napi(catch_unwind)]
-    pub fn close(&mut self, env: Env) -> Result<()> {
-        self.invoke(&env, "close WASIX direct database", Oliphaunt::close)
-    }
-}
-
-#[derive(Default)]
-struct StreamEnvironment {
-    alive: AtomicBool,
-    active: Mutex>>,
-}
-
-impl StreamEnvironment {
-    fn new() -> Self {
-        Self {
-            alive: AtomicBool::new(true),
-            active: Mutex::new(None),
-        }
-    }
-
-    fn activate(&self, ack: Arc) -> Result<()> {
-        let mut active = self
-            .active
-            .lock()
-            .map_err(|_| Error::new(Status::GenericFailure, "stream state lock poisoned"))?;
-        if !self.alive.load(Ordering::Acquire) {
-            return Err(Error::new(
-                Status::Closing,
-                "JavaScript environment is closing",
-            ));
-        }
-        *active = Some(ack);
-        Ok(())
-    }
-
-    fn deactivate(&self, ack: &Arc) {
-        let Ok(mut active) = self.active.lock() else {
-            return;
-        };
-        if active
-            .as_ref()
-            .is_some_and(|current| Arc::ptr_eq(current, ack))
-        {
-            active.take();
-        }
-    }
-
-    fn shutdown(&self) {
-        let active = {
-            let mut active = self
-                .active
-                .lock()
-                .unwrap_or_else(|error| error.into_inner());
-            self.alive.store(false, Ordering::Release);
-            active.take()
-        };
-        if let Some(active) = active {
-            active.complete(Err(Error::new(
-                Status::Closing,
-                "JavaScript environment closed during protocol streaming",
-            )));
-        }
-    }
-}
-
-#[derive(Default)]
-struct StreamAck {
-    result: Mutex>>,
-    ready: Condvar,
-}
-
-impl StreamAck {
-    fn complete(&self, result: Result<()>) {
-        let mut slot = self
-            .result
-            .lock()
-            .unwrap_or_else(|error| error.into_inner());
-        if slot.is_none() {
-            *slot = Some(result);
-            self.ready.notify_one();
-        }
-    }
-
-    fn wait(&self) -> Result<()> {
-        let mut slot = self.result.lock().map_err(|_| {
-            Error::new(
-                Status::GenericFailure,
-                "stream acknowledgement lock poisoned",
-            )
-        })?;
-        while slot.is_none() {
-            slot = self.ready.wait(slot).map_err(|_| {
-                Error::new(
-                    Status::GenericFailure,
-                    "stream acknowledgement lock poisoned",
-                )
-            })?;
-        }
-        slot.take().expect("stream acknowledgement is present")
-    }
-}
-
-/// Promise-facing database which directly owns one `AsyncOliphaunt` actor.
-#[napi(custom_finalize)]
-pub struct NativeWasixActorDatabase {
-    database: AsyncOliphaunt,
-    stream_environment: Arc,
-}
-
-impl NativeWasixActorDatabase {
-    fn attach(env: &Env, database: AsyncOliphaunt) -> Result {
-        let stream_environment = Arc::new(StreamEnvironment::new());
-        let cleanup_environment = Arc::clone(&stream_environment);
-        let _cleanup = env.add_env_cleanup_hook(cleanup_environment, |environment| {
-            environment.shutdown();
-        })?;
-        Ok(Self {
-            database,
-            stream_environment,
-        })
-    }
-}
-
-/// Promise-facing local wire server backed by the existing Rust server owner.
-#[napi(custom_finalize)]
-pub struct NativeWasixServer {
-    server: AsyncOliphauntServer,
-}
-
-impl ObjectFinalize for NativeWasixServer {}
-
-#[napi]
-impl NativeWasixServer {
-    #[napi(catch_unwind, ts_return_type = "Promise")]
-    pub fn open(env: Env, options: NativeServerOpenOptions) -> Result> {
-        let builder = configure_async_server(options)?;
-        let (deferred, promise) = env.create_deferred()?;
-        builder.start_with_completion(move |result| {
-            deferred.resolve(move |env| {
-                result
-                    .map(|server| Self { server })
-                    .map_err(|error| native_runtime_error(&env, "open WASIX server", error))
-            });
-        });
-        Ok(static_object(&env, promise))
-    }
-
-    #[napi(getter, js_name = "connectionString", catch_unwind)]
-    pub fn connection_string(&self) -> String {
-        self.server.connection_string().to_owned()
-    }
-
-    #[napi(getter, catch_unwind)]
-    pub fn closed(&self) -> bool {
-        self.server.is_closed()
-    }
-
-    #[napi(catch_unwind, ts_return_type = "Promise")]
-    pub fn close(&self, env: Env) -> Result> {
-        let server = self.server.clone();
-        let (deferred, promise) = env.create_deferred()?;
-        server.close_with_completion(move |result| {
-            deferred.resolve(move |env| {
-                result.map_err(|error| native_runtime_error(&env, "close WASIX server", error))
-            });
-        });
-        Ok(static_object(&env, promise))
-    }
-}
-
-#[napi(js_name = "restore", catch_unwind, ts_return_type = "Promise")]
-pub fn restore_database(
-    env: Env,
-    destination: String,
-    backup: Uint8ArraySlice<'_>,
-) -> Result> {
-    let destination = PathBuf::from(destination);
-    let backup = backup.as_ref().to_vec();
-    let (deferred, promise) = env.create_deferred()?;
-    AsyncOliphaunt::restore_with_completion(destination, backup, move |result| {
-        deferred.resolve(move |env| {
-            result.map_err(|error| native_runtime_error(&env, "restore WASIX database", error))
-        });
-    });
-    Ok(static_object(&env, promise))
-}
-
-#[napi(js_name = "restoreDirect", catch_unwind)]
-pub fn restore_database_direct(
-    env: Env,
-    destination: String,
-    backup: Uint8ArraySlice<'_>,
-) -> Result<()> {
-    retain_addon_image_for_process_runtime();
-    Oliphaunt::restore(PathBuf::from(destination), backup.as_ref())
-        .map_err(|error| native_runtime_error(&env, "restore WASIX database", error))
-}
-
-#[napi(js_name = "addonAbiVersion", catch_unwind)]
-pub fn addon_abi_version() -> u32 {
-    ADDON_ABI_VERSION
-}
-
-#[napi(js_name = "nodeApiVersion", catch_unwind)]
-pub fn node_api_version() -> u32 {
-    NODE_API_VERSION
-}
-
-#[napi(js_name = "runtimeVersion", catch_unwind)]
-pub fn runtime_version() -> &'static str {
-    RUNTIME_VERSION
-}
-
-#[napi(js_name = "supportedProfiles", catch_unwind)]
-pub fn supported_profiles() -> Vec<&'static str> {
-    vec!["standard", "icu"]
-}
-
-#[napi(js_name = "payloadIdentity", catch_unwind)]
-pub fn payload_identity(component: String) -> Result {
-    static STANDARD_SEED_MANIFEST: OnceLock = OnceLock::new();
-    static ICU_SEED_MANIFEST: OnceLock = OnceLock::new();
-    let manifest = embedded_portable_manifest()?;
-    match component.as_str() {
-        "runtimeArchive" => embedded_identity(
-            "runtime archive",
-            liboliphaunt_wasix_portable::runtime_archive(),
-            &manifest.runtime.sha256,
-        ),
-        "standardSeedArchive" => {
-            let seed = embedded_seed(manifest, "standard")?;
-            embedded_identity(
-                "standard cluster seed archive",
-                liboliphaunt_wasix_portable::standard_cluster_seed_archive(),
-                &seed.sha256,
-            )
-        }
-        "standardSeedManifest" => hashed_embedded_identity(
-            "standard cluster seed manifest",
-            liboliphaunt_wasix_portable::standard_cluster_seed_manifest(),
-            &STANDARD_SEED_MANIFEST,
-        ),
-        "icuDataArchive" => embedded_identity(
-            "ICU data archive",
-            oliphaunt_icu::icu_data_archive(),
-            oliphaunt_icu::ICU_DATA_ARCHIVE_SHA256.ok_or_else(|| {
-                Error::new(
-                    Status::GenericFailure,
-                    "WASIX ICU data archive has no embedded SHA-256 identity".to_owned(),
-                )
-            })?,
-        ),
-        "icuSeedArchive" => {
-            let seed = embedded_seed(manifest, "icu")?;
-            embedded_identity(
-                "ICU cluster seed archive",
-                liboliphaunt_wasix_portable::icu_cluster_seed_archive(),
-                &seed.sha256,
-            )
-        }
-        "icuSeedManifest" => hashed_embedded_identity(
-            "ICU cluster seed manifest",
-            liboliphaunt_wasix_portable::icu_cluster_seed_manifest(),
-            &ICU_SEED_MANIFEST,
-        ),
-        _ => Err(invalid_argument(format!(
-            "unsupported WASIX payload component {component:?}"
-        ))),
-    }
-}
-
-#[napi(js_name = "extensionIdentity", catch_unwind)]
-pub fn extension_identity(sql_name: String) -> Result {
-    #[cfg(feature = "extensions")]
-    {
-        let bytes = liboliphaunt_wasix_portable::extension_archive(&sql_name).ok_or_else(|| {
-            invalid_argument(format!(
-                "WASIX extension {sql_name:?} is not embedded in this addon"
-            ))
-        })?;
-        let sha256 = liboliphaunt_wasix_portable::expected_extension_archive_sha256(&sql_name)
-            .ok_or_else(|| {
-                Error::new(
-                    Status::GenericFailure,
-                    format!("WASIX extension {sql_name:?} has no embedded SHA-256 identity"),
-                )
-            })?;
-        Ok(format!("{sha256}:{}", bytes.len()))
-    }
-    #[cfg(not(feature = "extensions"))]
-    {
-        let _ = sql_name;
-        Err(missing_release_feature("extensions", "extensionIdentity"))
-    }
-}
-
-#[napi(js_name = "toolIdentity", catch_unwind)]
-pub fn tool_identity(name: String) -> Result {
-    #[cfg(feature = "tools")]
-    {
-        static PG_DUMP: OnceLock = OnceLock::new();
-        static PSQL: OnceLock = OnceLock::new();
-        let (bytes, identity) = match name.as_str() {
-            "pg_dump" => (oliphaunt_wasix_tools::pg_dump_wasm(), &PG_DUMP),
-            "psql" => (oliphaunt_wasix_tools::psql_wasm(), &PSQL),
-            _ => {
-                return Err(invalid_argument(format!(
-                    "unsupported WASIX tool {name:?}; expected \"pg_dump\" or \"psql\""
-                )));
-            }
-        };
-        hashed_embedded_identity(&format!("tool {name}"), bytes, identity)
-    }
-    #[cfg(not(feature = "tools"))]
-    {
-        let _ = name;
-        Err(missing_release_feature("tools", "toolIdentity"))
-    }
-}
-
-fn configure_direct_database(options: NativeOpenOptions) -> Result {
-    let NativeOpenOptions {
-        profile,
-        storage,
-        username,
-        database,
-        startup_gucs,
-        extensions,
-    } = options;
-    let mut builder = Oliphaunt::builder()
-        .storage(resolve_storage(storage)?)
-        .catalog_profile(resolve_profile(&profile)?)
-        .username(username)
-        .database(database)
-        .startup_gucs(startup_gucs);
-    builder = apply_direct_extensions(builder, extensions)?;
-    Ok(builder)
-}
-
-fn configure_actor_database(options: NativeOpenOptions) -> Result {
-    let NativeOpenOptions {
-        profile,
-        storage,
-        username,
-        database,
-        startup_gucs,
-        extensions,
-    } = options;
-    let mut builder = AsyncOliphaunt::builder()
-        .storage(resolve_storage(storage)?)
-        .catalog_profile(resolve_profile(&profile)?)
-        .username(username)
-        .database(database)
-        .startup_gucs(startup_gucs);
-    builder = apply_async_extensions(builder, extensions)?;
-    Ok(builder)
-}
-
-fn configure_async_server(options: NativeServerOpenOptions) -> Result {
-    let NativeServerOpenOptions {
-        profile,
-        storage,
-        username,
-        database,
-        startup_gucs,
-        extensions,
-        listen,
-    } = options;
-    let mut builder = AsyncOliphauntServer::builder()
-        .storage(resolve_storage(storage)?)
-        .catalog_profile(resolve_profile(&profile)?)
-        .username(username)
-        .database(database)
-        .startup_gucs(startup_gucs)
-        .listen(resolve_listen(listen)?);
-    builder = apply_server_extensions(builder, extensions)?;
-    Ok(builder)
-}
-
-fn resolve_profile(profile: &str) -> Result {
-    match profile {
-        "standard" => Ok(CatalogProfile::Standard),
-        "icu" => Ok(CatalogProfile::Icu),
-        value => Err(invalid_argument(format!(
-            "unsupported WASIX profile {value:?}; expected \"standard\" or \"icu\""
-        ))),
-    }
-}
-
-fn resolve_storage(storage: NativeStorageOptions) -> Result {
-    match storage.kind.as_str() {
-        "memory" => {
-            if storage.path.is_some() {
-                return Err(invalid_argument("memory storage must not include path"));
-            }
-            Ok(DatabaseStorage::Memory)
-        }
-        "directory" => {
-            let path = storage
-                .path
-                .filter(|path| !path.is_empty())
-                .ok_or_else(|| invalid_argument("directory storage requires a non-empty path"))?;
-            Ok(DatabaseStorage::Directory(PathBuf::from(path)))
-        }
-        kind => Err(invalid_argument(format!(
-            "unsupported WASIX storage kind {kind:?}; expected \"memory\" or \"directory\""
-        ))),
-    }
-}
-
-fn resolve_listen(listen: NativeListenOptions) -> Result {
-    let port = listen.port.map(resolve_port).transpose()?;
-    match listen.transport.as_str() {
-        "tcp" => {
-            if listen.directory.is_some() {
-                return Err(invalid_argument(
-                    "TCP listen options must not include directory",
-                ));
-            }
-            Ok(port.map_or_else(ServerListen::tcp, ServerListen::tcp_port))
-        }
-        "unix" => {
-            #[cfg(unix)]
-            {
-                let path = listen
-                    .directory
-                    .filter(|path| !path.is_empty())
-                    .ok_or_else(|| {
-                        invalid_argument("Unix listen options require a non-empty directory")
-                    })?;
-                Ok(match port {
-                    Some(port) => ServerListen::unix_port(path, port),
-                    None => ServerListen::unix(path),
-                })
-            }
-            #[cfg(not(unix))]
-            {
-                let _ = (listen.directory, port);
-                Err(invalid_argument(
-                    "Unix-domain WASIX server listeners are not supported on Windows",
-                ))
-            }
-        }
-        kind => Err(invalid_argument(format!(
-            "unsupported WASIX server transport {kind:?}; expected \"tcp\" or \"unix\""
-        ))),
-    }
-}
-
-fn resolve_port(port: u32) -> Result {
-    u16::try_from(port)
-        .ok()
-        .filter(|port| *port != 0)
-        .ok_or_else(|| invalid_argument("server port must be in the range 1..=65535"))
-}
-
-#[cfg(feature = "extensions")]
-fn resolve_extensions(names: Vec) -> Result> {
-    names
-        .into_iter()
-        .map(|name| {
-            Extension::by_sql_name(&name).ok_or_else(|| {
-                invalid_argument(format!(
-                    "WASIX extension {name:?} is unknown or unavailable in this runtime"
-                ))
-            })
-        })
-        .collect()
-}
-
-fn apply_direct_extensions(
-    builder: OliphauntBuilder,
-    names: Vec,
-) -> Result {
-    #[cfg(feature = "extensions")]
-    {
-        Ok(builder.extensions(resolve_extensions(names)?))
-    }
-    #[cfg(not(feature = "extensions"))]
-    {
-        if names.is_empty() {
-            Ok(builder)
-        } else {
-            Err(missing_release_feature("extensions", "open"))
-        }
-    }
-}
-
-fn apply_async_extensions(
-    builder: AsyncOliphauntBuilder,
-    names: Vec,
-) -> Result {
-    #[cfg(feature = "extensions")]
-    {
-        Ok(builder.extensions(resolve_extensions(names)?))
-    }
-    #[cfg(not(feature = "extensions"))]
-    {
-        if names.is_empty() {
-            Ok(builder)
-        } else {
-            Err(missing_release_feature("extensions", "open"))
-        }
-    }
-}
-
-fn apply_server_extensions(
-    builder: AsyncOliphauntServerBuilder,
-    names: Vec,
-) -> Result {
-    #[cfg(feature = "extensions")]
-    {
-        Ok(builder.extensions(resolve_extensions(names)?))
-    }
-    #[cfg(not(feature = "extensions"))]
-    {
-        if names.is_empty() {
-            Ok(builder)
-        } else {
-            Err(missing_release_feature("extensions", "server open"))
-        }
-    }
-}
-
-#[cfg(feature = "tools")]
-fn psql_options(args: Vec, command: Option, script: Option) -> PsqlOptions {
-    let mut options = PsqlOptions::new().args(args);
-    if let Some(command) = command {
-        options = options.command(command);
-    }
-    if let Some(script) = script {
-        options = options.script(script);
-    }
-    options
-}
-
-fn static_object(env: &Env, object: Object<'_>) -> Object<'static> {
-    // `Object` is a copyable local N-API handle; its Rust lifetime only ties it
-    // to the current handle scope. The value is returned immediately to N-API
-    // and is never retained in Rust under this widened marker lifetime.
-    Object::from_raw(env.raw(), object.raw())
-}
-
-fn v8_owned_bytes(env: &Env, bytes: &[u8]) -> Result {
-    // napi-rs 3.12.2 allocates here but does not initialize the new
-    // ArrayBuffer from `bytes`; fill the V8-owned allocation explicitly.
-    let mut output = Uint8ArraySlice::copy_from(env, bytes)?;
-    // SAFETY: the new ArrayBuffer is not observable by JavaScript until this
-    // function returns, and its allocation has exactly `bytes.len()` elements.
-    unsafe { output.as_mut() }.copy_from_slice(bytes);
-    output.into_typed_array(env)
-}
-
-#[cfg(feature = "tools")]
-fn native_tool_result(
-    env: &Env,
-    operation: &'static str,
-    result: oliphaunt_wasix::Result,
-) -> Result {
-    match result {
-        Ok(output) => {
-            let (stdout, stderr) = output.into_parts();
-            Ok(NativeToolResult {
-                status: 0,
-                stdout: v8_owned_bytes(env, &stdout)?,
-                stderr: v8_owned_bytes(env, &stderr)?,
-            })
-        }
-        Err(error) => {
-            if let Some(tool) = error.tool_error()
-                && let Some(status) = tool.exit_code()
-            {
-                if status == 0 {
-                    return Err(native_tool_error(env, operation, tool));
-                }
-                return Ok(NativeToolResult {
-                    status,
-                    stdout: v8_owned_bytes(env, tool.stdout_bytes())?,
-                    stderr: v8_owned_bytes(env, tool.stderr_bytes())?,
-                });
-            }
-            Err(native_runtime_error(env, operation, error))
-        }
-    }
-}
-
-fn invalid_argument(reason: impl Into) -> Error {
-    Error::new(Status::InvalidArg, reason.into())
-}
-
-#[cfg(any(not(feature = "tools"), not(feature = "extensions")))]
-fn missing_release_feature(feature: &str, operation: &str) -> Error {
-    Error::new(
-        Status::GenericFailure,
-        format!("WASIX N-API {operation} requires an addon built with the {feature} feature"),
-    )
-}
-
-fn native_runtime_error(
-    env: &Env,
-    operation: &'static str,
-    error: oliphaunt_wasix::Error,
-) -> Error {
-    if error.kind() == ErrorKind::Storage
-        && let Some(details) = error.storage_error()
-    {
-        return native_storage_error(
-            env,
-            operation,
-            &error,
-            details.code(),
-            details.commit_state(),
-            details.phase(),
-        );
-    }
-    let (marker, code) = match error.kind() {
-        ErrorKind::InvalidConfiguration => ("configuration", "invalid-configuration"),
-        ErrorKind::Lifecycle => ("lifecycle", "lifecycle"),
-        ErrorKind::TransactionActive => ("transaction", "transaction-active"),
-        ErrorKind::Postgres => ("postgres", "postgres-error"),
-        ErrorKind::Storage => ("runtime", "unclassified-storage-error"),
-        ErrorKind::Other => ("runtime", "runtime-error"),
-        _ => ("runtime", "runtime-error"),
-    };
-    native_tagged_error(
-        env,
-        "OliphauntWasixError",
-        marker,
-        code,
-        operation,
-        format!("{operation}: {error}"),
-    )
-}
-
-fn native_lifecycle_error(env: &Env, operation: &'static str, reason: &'static str) -> Error {
-    native_tagged_error(
-        env,
-        "OliphauntWasixError",
-        "lifecycle",
-        "lifecycle",
-        operation,
-        format!("{operation}: {reason}"),
-    )
-}
-
-fn native_tagged_error(
-    env: &Env,
-    name: &'static str,
-    marker: &'static str,
-    code: &'static str,
-    operation: &'static str,
-    reason: String,
-) -> Error {
-    let tagged = (|| -> Result {
-        let mut object = env.create_error(Error::new(Status::GenericFailure, reason.clone()))?;
-        object.set_named_property("name", name)?;
-        object.set_named_property("oliphauntWasixError", marker)?;
-        object.set_named_property("oliphauntWasixAddonAbi", ADDON_ABI_VERSION)?;
-        object.set_named_property("code", code)?;
-        object.set_named_property("operation", operation)?;
-        Ok(Error::from_unknown_without_coercion(
-            object.into_unknown(env)?,
-        ))
-    })();
-    tagged.unwrap_or_else(|tag_error| {
-        Error::new(
-            Status::GenericFailure,
-            format!("{reason}; construct structured native error: {tag_error}"),
-        )
-    })
-}
-
-fn native_storage_error(
-    env: &Env,
-    operation: &'static str,
-    error: &oliphaunt_wasix::Error,
-    code: StorageErrorCode,
-    commit_state: StorageCommitState,
-    phase: StorageErrorPhase,
-) -> Error {
-    let reason = format!("{operation}: {error}");
-    let tagged = (|| -> Result {
-        let mut object = env.create_error(Error::new(Status::GenericFailure, reason.clone()))?;
-        object.set_named_property("name", "OliphauntWasixStorageError")?;
-        object.set_named_property("oliphauntWasixError", "storage")?;
-        object.set_named_property("oliphauntWasixAddonAbi", ADDON_ABI_VERSION)?;
-        object.set_named_property("code", storage_code(code))?;
-        object.set_named_property("commitState", storage_commit_state(commit_state))?;
-        object.set_named_property("phase", storage_phase(phase))?;
-        object.set_named_property("operation", operation)?;
-        Ok(Error::from_unknown_without_coercion(
-            object.into_unknown(env)?,
-        ))
-    })();
-    tagged.unwrap_or_else(|tag_error| {
-        Error::new(
-            Status::GenericFailure,
-            format!("{reason}; construct structured storage error: {tag_error}"),
-        )
-    })
-}
-
-#[cfg(feature = "tools")]
-fn native_tool_error(
-    env: &Env,
-    operation: &'static str,
-    tool: &oliphaunt_wasix::tools::PostgresToolError,
-) -> Error {
-    let reason = format!("{operation}: {tool}");
-    let tagged = (|| -> Result {
-        let mut object = env.create_error(Error::new(Status::GenericFailure, reason.clone()))?;
-        object.set_named_property("name", "OliphauntWasixToolError")?;
-        object.set_named_property("oliphauntWasixError", "tool")?;
-        object.set_named_property("oliphauntWasixAddonAbi", ADDON_ABI_VERSION)?;
-        object.set_named_property("code", "tool-error")?;
-        object.set_named_property("operation", operation)?;
-        object.set_named_property("tool", tool.tool())?;
-        object.set_named_property("exitCode", tool.exit_code())?;
-        object.set_named_property("stdout", v8_owned_bytes(env, tool.stdout_bytes())?)?;
-        object.set_named_property("stderr", v8_owned_bytes(env, tool.stderr_bytes())?)?;
-        Ok(Error::from_unknown_without_coercion(
-            object.into_unknown(env)?,
-        ))
-    })();
-    tagged.unwrap_or_else(|tag_error| {
-        Error::new(
-            Status::GenericFailure,
-            format!("{reason}; construct structured tool error: {tag_error}"),
-        )
-    })
-}
-
-fn storage_code(code: StorageErrorCode) -> &'static str {
-    match code {
-        StorageErrorCode::Busy => "busy",
-        StorageErrorCode::Corrupt => "corrupt",
-        StorageErrorCode::Incomplete => "incomplete",
-        StorageErrorCode::Incompatible => "incompatible",
-        StorageErrorCode::PublicationFailed => "publication-failed",
-        StorageErrorCode::Unavailable => "unavailable",
-        _ => "unavailable",
-    }
-}
-
-fn storage_commit_state(state: StorageCommitState) -> &'static str {
-    match state {
-        StorageCommitState::NotPersisted => "not-persisted",
-        StorageCommitState::Persisted => "persisted",
-        StorageCommitState::Unchanged => "unchanged",
-        StorageCommitState::Unknown => "unknown",
-        _ => "unknown",
-    }
-}
-
-fn storage_phase(phase: StorageErrorPhase) -> &'static str {
-    match phase {
-        StorageErrorPhase::Ownership => "ownership",
-        StorageErrorPhase::Open => "open",
-        StorageErrorPhase::OpenPublication => "open-publication",
-        StorageErrorPhase::Operation => "operation",
-        StorageErrorPhase::Backup => "backup",
-        StorageErrorPhase::Close => "close",
-        StorageErrorPhase::RestoreValidation => "restore-validation",
-        StorageErrorPhase::RestoreStaging => "restore-staging",
-        StorageErrorPhase::RestorePublication => "restore-publication",
-        StorageErrorPhase::RestoreDurability => "restore-durability",
-        _ => "operation",
-    }
-}
-
-fn embedded_portable_manifest() -> Result<&'static liboliphaunt_wasix_portable::AssetManifest> {
-    static MANIFEST: OnceLock<
-        std::result::Result,
-    > = OnceLock::new();
-    match MANIFEST
-        .get_or_init(|| liboliphaunt_wasix_portable::manifest().map_err(|error| error.to_string()))
-    {
-        Ok(manifest) => Ok(manifest),
-        Err(error) => Err(Error::new(
-            Status::GenericFailure,
-            format!("parse embedded WASIX payload manifest: {error}"),
-        )),
-    }
-}
-
-fn embedded_seed<'a>(
-    manifest: &'a liboliphaunt_wasix_portable::AssetManifest,
-    profile: &str,
-) -> Result<&'a liboliphaunt_wasix_portable::ClusterSeedAsset> {
-    manifest.cluster_seeds.get(profile).ok_or_else(|| {
-        Error::new(
-            Status::GenericFailure,
-            format!("WASIX {profile} cluster seed is not embedded in this addon"),
-        )
-    })
-}
-
-fn embedded_identity(label: &str, bytes: Option<&[u8]>, sha256: &str) -> Result {
-    let bytes = bytes.ok_or_else(|| {
-        Error::new(
-            Status::GenericFailure,
-            format!("WASIX {label} is not embedded in this addon"),
-        )
-    })?;
-    Ok(format!("{sha256}:{}", bytes.len()))
-}
-
-fn hashed_embedded_identity(
-    label: &str,
-    bytes: Option<&[u8]>,
-    identity: &'static OnceLock,
-) -> Result {
-    let bytes = bytes.ok_or_else(|| {
-        Error::new(
-            Status::GenericFailure,
-            format!("WASIX {label} is not embedded in this addon"),
-        )
-    })?;
-    Ok(identity
-        .get_or_init(|| {
-            let sha256 = format!("{:x}", Sha256::digest(bytes));
-            format!("{sha256}:{}", bytes.len())
-        })
-        .clone())
-}
-
-#[cfg(test)]
-mod tests {
-    use std::sync::atomic::AtomicUsize;
-
-    use super::*;
-
-    struct DropCounter {
-        drops: Arc,
-        closed: bool,
-    }
-
-    impl Drop for DropCounter {
-        fn drop(&mut self) {
-            self.drops.fetch_add(1, Ordering::SeqCst);
-        }
-    }
-
-    #[test]
-    fn environment_finalizer_drops_closed_and_quarantines_open_owners() {
-        let drops = Arc::new(AtomicUsize::new(0));
-        let mut open = Some(DropCounter {
-            drops: Arc::clone(&drops),
-            closed: false,
-        });
-        drop_if_closed_or_quarantine(&mut open, |value| value.closed);
-        assert!(open.is_none());
-        assert_eq!(drops.load(Ordering::SeqCst), 0);
-
-        let mut closed = Some(DropCounter {
-            drops: Arc::clone(&drops),
-            closed: true,
-        });
-        drop_if_closed_or_quarantine(&mut closed, |value| value.closed);
-        assert!(closed.is_none());
-        assert_eq!(drops.load(Ordering::SeqCst), 1);
-    }
-
-    #[test]
-    fn profile_selection_is_explicit() {
-        assert_eq!(
-            resolve_profile("standard").unwrap(),
-            CatalogProfile::Standard
-        );
-        assert_eq!(resolve_profile("icu").unwrap(), CatalogProfile::Icu);
-        assert!(resolve_profile("default").is_err());
-    }
-
-    #[test]
-    fn directory_storage_requires_path() {
-        let error = resolve_storage(NativeStorageOptions {
-            kind: "directory".to_owned(),
-            path: None,
-        })
-        .unwrap_err();
-        assert!(error.reason.contains("requires a non-empty path"));
-    }
-
-    #[test]
-    fn explicit_zero_port_is_rejected() {
-        let error = resolve_port(0).unwrap_err();
-        assert!(error.reason.contains("1..=65535"));
-    }
-}
-
-// Dropping these fields never joins the owner thread. AsyncOliphaunt's final
-// Arc sends its existing best-effort Shutdown control and returns immediately.
-impl ObjectFinalize for NativeWasixActorDatabase {}
-
-#[napi]
-impl NativeWasixActorDatabase {
-    #[napi(catch_unwind, ts_return_type = "Promise")]
-    pub fn open(env: Env, options: NativeOpenOptions) -> Result> {
-        let builder = configure_actor_database(options)?;
-        let (deferred, promise) = env.create_deferred()?;
-        builder.open_with_completion(move |result| {
-            deferred.resolve(move |env| {
-                let database = result.map_err(|error| {
-                    native_runtime_error(&env, "open WASIX actor database", error)
-                })?;
-                Self::attach(&env, database)
-            });
-        });
-        Ok(static_object(&env, promise))
-    }
-
-    #[napi(getter, catch_unwind)]
-    pub fn closed(&self) -> bool {
-        self.database.is_closed()
-    }
-
-    #[napi(
-        js_name = "execProtocolRaw",
-        catch_unwind,
-        ts_return_type = "Promise"
-    )]
-    pub fn exec_protocol_raw(
-        &self,
-        env: Env,
-        request: Uint8ArraySlice<'_>,
-    ) -> Result> {
-        let request = request.as_ref().to_vec();
-        let database = self.database.clone();
-        let (deferred, promise) = env.create_deferred()?;
-        database.exec_protocol_raw_with_completion(request, move |result| {
-            deferred.resolve(move |env| {
-                let response = result.map_err(|error| {
-                    native_runtime_error(&env, "execute PostgreSQL protocol request", error)
-                })?;
-                v8_owned_bytes(&env, &response)
-            });
-        });
-        Ok(static_object(&env, promise))
-    }
-
-    #[napi(
-        js_name = "execProtocolRawStream",
-        catch_unwind,
-        ts_return_type = "Promise<'complete' | 'callbackAborted'>"
-    )]
-    pub fn exec_protocol_raw_stream(
-        &self,
-        env: Env,
-        request: Uint8ArraySlice<'_>,
-        on_chunk: Function<'_, Uint8Array, ()>,
-    ) -> Result> {
-        let request = request.as_ref().to_vec();
-        let stream_environment = Arc::clone(&self.stream_environment);
-        let callback_environment = Arc::clone(&stream_environment);
-        let threadsafe = on_chunk
-            .build_threadsafe_function::>()
-            .max_queue_size::<1>()
-            .build_callback(|context: ThreadsafeCallContext>| {
-                v8_owned_bytes(&context.env, &context.value)
-            })?;
-        let database = self.database.clone();
-        let (deferred, promise) = env.create_deferred()?;
-        database.exec_protocol_raw_stream_with_completion(
-            request,
-            move |chunk| {
-                let ack = Arc::new(StreamAck::default());
-                callback_environment.activate(Arc::clone(&ack))?;
-                let callback_ack = Arc::clone(&ack);
-                let status = threadsafe.call_with_return_value(
-                    chunk.to_vec(),
-                    ThreadsafeFunctionCallMode::Blocking,
-                    move |result, _env| {
-                        callback_ack.complete(result.map(|_| ()));
-                        Ok(())
-                    },
-                );
-                if status != Status::Ok {
-                    ack.complete(Err(Error::new(
-                        status,
-                        "queue protocol chunk on the JavaScript thread",
-                    )));
-                }
-                let result = ack.wait();
-                callback_environment.deactivate(&ack);
-                result
-            },
-            move |result| {
-                deferred.resolve(move |env| match result {
-                    Ok(()) => Ok("complete"),
-                    Err(RawStreamError::Callback(_)) => Ok("callbackAborted"),
-                    Err(RawStreamError::Database(error)) => Err(native_runtime_error(
-                        &env,
-                        "stream PostgreSQL protocol response",
-                        error,
-                    )),
-                    Err(RawStreamError::CallbackPanicked(error)) => Err(native_runtime_error(
-                        &env,
-                        "stream PostgreSQL protocol callback",
-                        error,
-                    )),
-                    Err(_) => Err(Error::new(
-                        Status::GenericFailure,
-                        "stream PostgreSQL protocol response: unknown stream error",
-                    )),
-                });
-            },
-        );
-        Ok(static_object(&env, promise))
-    }
-
-    #[napi(catch_unwind, ts_return_type = "Promise")]
-    pub fn backup(&self, env: Env) -> Result> {
-        let database = self.database.clone();
-        let (deferred, promise) = env.create_deferred()?;
-        database.backup_with_completion(move |result| {
-            deferred.resolve(move |env| {
-                let backup = result
-                    .map_err(|error| native_runtime_error(&env, "back up WASIX database", error))?;
-                v8_owned_bytes(&env, &backup)
-            });
-        });
-        Ok(static_object(&env, promise))
-    }
-
-    #[napi(
-        js_name = "pgDump",
-        catch_unwind,
-        ts_return_type = "Promise"
-    )]
-    pub fn pg_dump(&self, env: Env, args: Vec) -> Result> {
-        #[cfg(feature = "tools")]
-        {
-            let database = self.database.clone();
-            let (deferred, promise) = env.create_deferred()?;
-            database.pg_dump_output_with_completion(
-                PgDumpOptions::new().args(args),
-                move |result| {
-                    deferred
-                        .resolve(move |env| native_tool_result(&env, "run WASIX pg_dump", result));
-                },
-            );
-            Ok(static_object(&env, promise))
-        }
-        #[cfg(not(feature = "tools"))]
-        {
-            let _ = (env, args);
-            Err(missing_release_feature("tools", "pgDump"))
-        }
-    }
-
-    #[napi(catch_unwind, ts_return_type = "Promise")]
-    pub fn psql(
-        &self,
-        env: Env,
-        args: Vec,
-        command: Option,
-        script: Option,
-    ) -> Result> {
-        if command.is_some() && script.is_some() {
-            return Err(invalid_argument(
-                "psql accepts either command or script, not both",
-            ));
-        }
-        #[cfg(feature = "tools")]
-        {
-            let database = self.database.clone();
-            let (deferred, promise) = env.create_deferred()?;
-            database.psql_output_with_completion(
-                psql_options(args, command, script),
-                move |result| {
-                    deferred.resolve(move |env| native_tool_result(&env, "run WASIX psql", result));
-                },
-            );
-            Ok(static_object(&env, promise))
-        }
-        #[cfg(not(feature = "tools"))]
-        {
-            let _ = (env, args, command, script);
-            Err(missing_release_feature("tools", "psql"))
-        }
-    }
-
-    #[napi(catch_unwind, ts_return_type = "Promise")]
-    pub fn close(&self, env: Env) -> Result> {
-        let database = self.database.clone();
-        let (deferred, promise) = env.create_deferred()?;
-        database.close_with_completion(move |result| {
-            deferred.resolve(move |env| {
-                result.map_err(|error| {
-                    native_runtime_error(&env, "close WASIX actor database", error)
-                })
-            });
-        });
-        Ok(static_object(&env, promise))
-    }
-}
diff --git a/src/runtimes/wasix-napi/tests/native.integration.mjs b/src/runtimes/wasix-napi/tests/native.integration.mjs
deleted file mode 100644
index 62bbd6f01..000000000
--- a/src/runtimes/wasix-napi/tests/native.integration.mjs
+++ /dev/null
@@ -1,220 +0,0 @@
-import assert from 'node:assert/strict';
-import { mkdtempSync, rmSync } from 'node:fs';
-import { createRequire } from 'node:module';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
-import { Worker } from 'node:worker_threads';
-
-const addonPath = process.argv[2];
-if (addonPath === undefined) {
-  throw new Error('usage: node native.integration.mjs /absolute/path/to/addon.node [--tools]');
-}
-
-const addon = createRequire(import.meta.url)(addonPath);
-const expectedExports = [
-  'NativeWasixActorDatabase',
-  'NativeWasixDatabase',
-  'NativeWasixServer',
-  'addonAbiVersion',
-  'extensionIdentity',
-  'nodeApiVersion',
-  'payloadIdentity',
-  'restore',
-  'restoreDirect',
-  'runtimeVersion',
-  'supportedProfiles',
-  'toolIdentity',
-];
-assert.deepEqual(Object.keys(addon).sort(), expectedExports);
-assert.equal(addon.addonAbiVersion(), 1);
-assert.equal(addon.nodeApiVersion(), 8);
-assert.deepEqual(addon.supportedProfiles(), ['standard', 'icu']);
-
-const openOptions = (profile = 'standard', storage = { kind: 'memory' }) => ({
-  profile,
-  storage,
-  username: 'postgres',
-  database: 'postgres',
-  startupGucs: {},
-  extensions: [],
-});
-
-const queryMessage = (sql) => {
-  const text = Buffer.from(`${sql}\0`);
-  const request = Buffer.alloc(5 + text.length);
-  request[0] = 0x51;
-  request.writeUInt32BE(4 + text.length, 1);
-  text.copy(request, 5);
-  return request;
-};
-
-const assertResponse = (response, value) => {
-  assert(response instanceof Uint8Array);
-  assert(Buffer.from(response).includes(Buffer.from(String(value))));
-};
-
-const assertTransferable = (bytes) => {
-  assert(bytes instanceof Uint8Array);
-  const expected = Uint8Array.from(bytes);
-  const moved = structuredClone(bytes, { transfer: [bytes.buffer] });
-  assert.equal(bytes.byteLength, 0, 'V8 must detach the source ArrayBuffer');
-  assert.deepEqual(moved, expected, 'transfer must preserve every output byte');
-  return moved;
-};
-
-const direct = addon.NativeWasixDatabase.open(openOptions());
-const directResponse = direct.execProtocolRaw(queryMessage('select 4101'));
-assertResponse(directResponse, 4101);
-assertTransferable(directResponse);
-const directChunks = [];
-assert.equal(
-  direct.execProtocolRawStream(queryMessage('select 4102'), (chunk) => {
-    assertResponse(chunk, 4102);
-    directChunks.push(assertTransferable(chunk));
-  }),
-  'complete',
-);
-assert(Buffer.concat(directChunks.map(Buffer.from)).includes(Buffer.from('4102')));
-let directReentryError;
-assert.equal(
-  direct.execProtocolRawStream(queryMessage('select 4103'), () => {
-    try {
-      direct.close();
-    } catch (error) {
-      directReentryError = error;
-    }
-  }),
-  'complete',
-);
-assert(
-  directReentryError instanceof Error,
-  'napi-rs must reject a synchronous mutable reentry while the stream callback is active',
-);
-assert.match(directReentryError.message, /borrow(?:ed|ing)|mutabl/iu);
-assertResponse(direct.execProtocolRaw(queryMessage('select 4104')), 4104);
-const directBackup = direct.backup();
-const restoreBackup = Uint8Array.from(directBackup);
-assert(directBackup.byteLength > 0);
-assertTransferable(directBackup);
-direct.close();
-assert.equal(direct.closed, true);
-
-const actor = await addon.NativeWasixActorDatabase.open(openOptions());
-const actorResponse = await actor.execProtocolRaw(queryMessage('select 4201'));
-assertResponse(actorResponse, 4201);
-assertTransferable(actorResponse);
-const actorChunks = [];
-assert.equal(
-  await actor.execProtocolRawStream(queryMessage('select 4202'), (chunk) => {
-    actorChunks.push(assertTransferable(chunk));
-  }),
-  'complete',
-);
-assert(Buffer.concat(actorChunks.map(Buffer.from)).includes(Buffer.from('4202')));
-assert.equal(
-  await actor.execProtocolRawStream(queryMessage('select 4203'), () => {
-    throw new Error('intentional stream stop');
-  }),
-  'callbackAborted',
-);
-assertResponse(await actor.execProtocolRaw(queryMessage('select 4204')), 4204);
-
-if (process.argv.includes('--tools')) {
-  const dump = await actor.pgDump([]);
-  assert.equal(dump.status, 0);
-  assert(dump.stdout.byteLength > 0);
-  assertTransferable(dump.stdout);
-  assertTransferable(dump.stderr);
-}
-
-await Promise.all([actor.close(), actor.close()]);
-assert.equal(actor.closed, true);
-await assert.rejects(actor.execProtocolRaw(queryMessage('select 1')), (error) => {
-  assert.equal(error.oliphauntWasixError, 'lifecycle');
-  assert.equal(error.oliphauntWasixAddonAbi, 1);
-  return true;
-});
-
-const server = await addon.NativeWasixServer.open({
-  ...openOptions(),
-  listen: { transport: 'tcp' },
-});
-assert.match(server.connectionString, /^postgresql:\/\//u);
-await Promise.all([server.close(), server.close()]);
-assert.equal(server.closed, true);
-
-assert.match(addon.payloadIdentity('icuDataArchive'), /^[0-9a-f]{64}:\d+$/u);
-const icu = await addon.NativeWasixActorDatabase.open(openOptions('icu'));
-assertResponse(await icu.execProtocolRaw(queryMessage('select 4301')), 4301);
-await icu.close();
-
-const temporaryRoot = mkdtempSync(join(tmpdir(), 'oliphaunt-wasix-napi-'));
-try {
-  const restored = join(temporaryRoot, 'restored-actor');
-  await addon.restore(restored, restoreBackup);
-  const restoredActor = await addon.NativeWasixActorDatabase.open(
-    openOptions('standard', { kind: 'directory', path: restored }),
-  );
-  assertResponse(await restoredActor.execProtocolRaw(queryMessage('select 4401')), 4401);
-  await assert.rejects(
-    addon.NativeWasixActorDatabase.open(
-      openOptions('standard', { kind: 'directory', path: restored }),
-    ),
-    (error) => {
-      assert.equal(error.name, 'OliphauntWasixStorageError');
-      assert.equal(error.oliphauntWasixError, 'storage');
-      assert.equal(error.oliphauntWasixAddonAbi, 1);
-      assert.equal(error.code, 'busy');
-      assert.equal(error.commitState, 'unchanged');
-      assert.equal(error.phase, 'ownership');
-      return true;
-    },
-  );
-  await restoredActor.close();
-
-  const restoredDirectPath = join(temporaryRoot, 'restored-direct');
-  addon.restoreDirect(restoredDirectPath, restoreBackup);
-  const restoredDirect = addon.NativeWasixDatabase.open(
-    openOptions('standard', { kind: 'directory', path: restoredDirectPath }),
-  );
-  assertResponse(restoredDirect.execProtocolRaw(queryMessage('select 4402')), 4402);
-  restoredDirect.close();
-} finally {
-  rmSync(temporaryRoot, { recursive: true, force: true });
-}
-
-const worker = new Worker(
-  `
-    const { parentPort, workerData } = require('node:worker_threads');
-    const addon = require(workerData.addonPath);
-    const options = ${JSON.stringify(openOptions())};
-    addon.NativeWasixActorDatabase.open(options).then((database) => {
-      globalThis.database = database;
-      const text = Buffer.from('select 4501\\0');
-      const request = Buffer.alloc(5 + text.length);
-      request[0] = 0x51;
-      request.writeUInt32BE(4 + text.length, 1);
-      text.copy(request, 5);
-      void database.execProtocolRawStream(request, () => {
-        parentPort.postMessage('stream-entered');
-        Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 60_000);
-      }).catch(() => undefined);
-    }, (error) => { throw error; });
-  `,
-  { eval: true, workerData: { addonPath } },
-);
-await new Promise((resolve, reject) => {
-  worker.once('message', resolve);
-  worker.once('error', reject);
-});
-await Promise.race([
-  worker.terminate(),
-  new Promise((_, reject) => {
-    setTimeout(
-      () => reject(new Error('worker teardown blocked on actor stream')),
-      10_000,
-    ).unref();
-  }),
-]);
-
-console.log('WASIX N-API native integration passed');
diff --git a/src/runtimes/wasix-napi/tools/build-native.sh b/src/runtimes/wasix-napi/tools/build-native.sh
deleted file mode 100755
index dc0ac4644..000000000
--- a/src/runtimes/wasix-napi/tools/build-native.sh
+++ /dev/null
@@ -1,339 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-workspace_root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "must run inside the Oliphaunt git checkout" >&2
-  exit 1
-}
-cd "$workspace_root"
-
-require_command() {
-  if ! command -v "$1" >/dev/null 2>&1; then
-    echo "missing required command: $1" >&2
-    exit 1
-  fi
-}
-
-require_command cargo
-require_command git
-require_command node
-require_command pnpm
-
-host_system="$(uname -s)"
-host_machine="$(uname -m)"
-if [[ "$host_system" == "Linux" ]]; then
-  linux_libc="$(node src/runtimes/wasix-napi/tools/detect-linux-libc.mjs)"
-  case "$linux_libc" in
-    glibc) ;;
-    musl)
-      echo "WASIX N-API native addons do not support Linux musl; use a glibc build host" >&2
-      exit 2
-      ;;
-    *)
-      echo "WASIX N-API could not verify that this Linux build host uses glibc" >&2
-      exit 2
-      ;;
-  esac
-fi
-
-target_id="${1:-${OLIPHAUNT_WASIX_NAPI_TARGET:-}}"
-if [[ -z "$target_id" ]]; then
-  case "$host_system:$host_machine" in
-    Darwin:arm64|Darwin:aarch64) target_id="macos-arm64" ;;
-    Linux:x86_64|Linux:amd64) target_id="linux-x64-gnu" ;;
-    Linux:arm64|Linux:aarch64) target_id="linux-arm64-gnu" ;;
-    MINGW*:x86_64|MSYS*:x86_64|CYGWIN*:x86_64) target_id="windows-x64-msvc" ;;
-    *)
-      echo "unsupported WASIX N-API host: $(uname -s)/$(uname -m)" >&2
-      exit 2
-      ;;
-  esac
-fi
-
-case "$target_id" in
-  macos-arm64)
-    cargo_target="aarch64-apple-darwin"
-    library_name="liboliphaunt_wasix_napi.dylib"
-    ;;
-  linux-arm64-gnu)
-    cargo_target="aarch64-unknown-linux-gnu"
-    library_name="liboliphaunt_wasix_napi.so"
-    ;;
-  linux-x64-gnu)
-    cargo_target="x86_64-unknown-linux-gnu"
-    library_name="liboliphaunt_wasix_napi.so"
-    ;;
-  windows-x64-msvc)
-    cargo_target="x86_64-pc-windows-msvc"
-    library_name="oliphaunt_wasix_napi.dll"
-    ;;
-  *)
-    echo "unsupported WASIX N-API target: $target_id" >&2
-    exit 2
-    ;;
-esac
-
-source_sha="$(git rev-parse HEAD)"
-artifact_source_sha="${OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA:-$source_sha}"
-if [[ ! "$artifact_source_sha" =~ ^[0-9a-f]{40}$ ]]; then
-  echo "OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA must be a lowercase 40-character Git SHA" >&2
-  exit 2
-fi
-
-manifest="src/runtimes/wasix-napi/Cargo.toml"
-package_manifest="src/runtimes/wasix-napi/package.json"
-metadata_contract="$(node - "$package_manifest" <<'JS'
-const manifest = JSON.parse(require("node:fs").readFileSync(process.argv[2], "utf8"));
-const values = [
-  manifest.oliphaunt?.runtimeVersion,
-  manifest.oliphaunt?.addonAbiVersion,
-  manifest.oliphaunt?.nodeApiVersion,
-];
-if (
-  !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/.test(values[0] ?? "")
-  || !Number.isSafeInteger(values[1])
-  || !Number.isSafeInteger(values[2])
-) {
-  throw new Error("WASIX N-API package metadata has an invalid runtime/ABI contract");
-}
-process.stdout.write(values.join("\t"));
-JS
-)"
-IFS=$'\t' read -r expected_runtime_version expected_addon_abi expected_node_api <<< "$metadata_contract"
-product_target_root="${OLIPHAUNT_WASIX_NAPI_BUILD_ROOT:-$workspace_root/target/oliphaunt-wasix-napi}"
-prebuild_dir="$product_target_root/prebuilds/$target_id"
-cargo_target_dir="$product_target_root/cargo-release"
-build_inputs_file="$product_target_root/build-inputs/$target_id.json"
-mkdir -p "$prebuild_dir"
-
-# Release addons must consume the exact portable runtime, target AOT, exact
-# extension, and ICU payloads staged by the same CI run. Export the canonical
-# dependency build-script variables explicitly so no source-only fallback can
-# be selected through a package-local or stale workspace probe.
-export OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR="${OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR:-$workspace_root/target/oliphaunt-wasix/assets}"
-export OLIPHAUNT_WASM_GENERATED_AOT_DIR="${OLIPHAUNT_WASM_GENERATED_AOT_DIR:-$workspace_root/target/oliphaunt-wasix/aot}"
-export OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="${OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT:-$workspace_root/target/extension-artifacts}"
-export OLIPHAUNT_ICU_DATA_DIR="${OLIPHAUNT_ICU_DATA_DIR:-$workspace_root/target/oliphaunt-wasix/wasix-build/work/icu-wasix/share/icu}"
-export OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD=1
-export OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS="$build_inputs_file"
-
-build_input_args=(
-  --target "$target_id"
-  --target-triple "$cargo_target"
-  --portable-root "$OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR"
-  --aot-root "$OLIPHAUNT_WASM_GENERATED_AOT_DIR"
-  --extension-root "$OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT"
-  --icu-root "$OLIPHAUNT_ICU_DATA_DIR"
-)
-tools/dev/bun.sh src/runtimes/wasix-napi/tools/check-build-inputs.mjs \
-  "${build_input_args[@]}" \
-  --output "$build_inputs_file"
-
-# Release profile environment variables work whether the crate is built as a
-# workspace member or through its manifest directly.
-export CARGO_INCREMENTAL=0
-export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1
-export CARGO_PROFILE_RELEASE_LTO=thin
-export CARGO_PROFILE_RELEASE_STRIP=symbols
-
-build_addon() {
-  local output="$1"
-
-  echo "building WASIX N-API addon for $target_id ($cargo_target)"
-  if [[ "$target_id" == linux-*-gnu ]]; then
-    tools/release/build-linux-wasix-napi-baseline.sh \
-      "$cargo_target_dir" \
-      "$cargo_target" \
-      release
-  else
-    CARGO_TARGET_DIR="$cargo_target_dir" cargo build \
-      --locked \
-      --manifest-path "$manifest" \
-      --target "$cargo_target" \
-      --release \
-      --no-default-features \
-      --features release
-  fi
-
-  local library="$cargo_target_dir/$cargo_target/release/$library_name"
-  if [[ ! -f "$library" ]]; then
-    echo "Cargo did not produce expected addon library: $library" >&2
-    exit 1
-  fi
-  cp "$library" "$output"
-}
-
-addon="$prebuild_dir/oliphaunt_wasix_napi.node"
-build_addon "$addon"
-
-# Recompute the complete input inventory after compilation so packaging
-# cannot attest to payloads that changed during compilation.
-tools/dev/bun.sh src/runtimes/wasix-napi/tools/check-build-inputs.mjs \
-  "${build_input_args[@]}" \
-  --check "$build_inputs_file"
-
-# Loading a foreign-target addon is impossible. For a host build, validate the
-# complete stable N-API contract before it can be packaged.
-host_target=""
-case "$host_system:$host_machine" in
-  Darwin:arm64|Darwin:aarch64) host_target="macos-arm64" ;;
-  Linux:x86_64|Linux:amd64) host_target="linux-x64-gnu" ;;
-  Linux:arm64|Linux:aarch64) host_target="linux-arm64-gnu" ;;
-  MINGW*:x86_64|MSYS*:x86_64|CYGWIN*:x86_64) host_target="windows-x64-msvc" ;;
-esac
-if [[ "$target_id" == "$host_target" ]]; then
-  node - \
-    "$addon" \
-    "$expected_runtime_version" \
-    "$expected_addon_abi" \
-    "$expected_node_api" \
-    "$build_inputs_file" <<'JS'
-const { readFileSync, statSync } = require("node:fs");
-const { resolve } = require("node:path");
-
-const [addonPath, expectedRuntime, expectedAbiRaw, expectedNodeApiRaw, buildInputsPath] =
-  process.argv.slice(2);
-const expectedAbi = Number(expectedAbiRaw);
-const expectedNodeApi = Number(expectedNodeApiRaw);
-const buildInputs = JSON.parse(readFileSync(buildInputsPath, "utf8"));
-const expectedFunctions = [
-  "addonAbiVersion",
-  "extensionIdentity",
-  "nodeApiVersion",
-  "payloadIdentity",
-  "restore",
-  "restoreDirect",
-  "runtimeVersion",
-  "supportedProfiles",
-  "toolIdentity",
-];
-const expectedDatabaseMethods = [
-  "backup",
-  "close",
-  "execProtocolRaw",
-  "execProtocolRawStream",
-  "pgDump",
-  "psql",
-];
-const expectedServerMethods = ["close"];
-const addon = require(addonPath);
-for (const name of expectedFunctions) {
-  if (typeof addon[name] !== "function") {
-    throw new Error(`${addonPath} is missing function export ${name}`);
-  }
-}
-if (
-  addon.addonAbiVersion() !== expectedAbi
-  || addon.nodeApiVersion() !== expectedNodeApi
-  || addon.runtimeVersion() !== expectedRuntime
-  || JSON.stringify(addon.supportedProfiles()) !== JSON.stringify(["standard", "icu"])
-) {
-  throw new Error(`${addonPath} reports an incompatible ABI/runtime/profile contract`);
-}
-
-function expectedIdentity(record, kind) {
-  if (
-    typeof record?.path !== "string"
-    || !/^[0-9a-f]{64}$/.test(record?.sha256 ?? "")
-  ) {
-    throw new Error(`${buildInputsPath} has an invalid ${kind} record`);
-  }
-  const size = statSync(resolve(record.path)).size;
-  if (!Number.isSafeInteger(size) || size < 1) {
-    throw new Error(`${record.path} has an invalid ${kind} size: ${size}`);
-  }
-  return `${record.sha256}:${size}`;
-}
-
-const portableTools = buildInputs.inputs?.portableTools;
-if (
-  buildInputs.schema !== "oliphaunt-wasix-napi-build-inputs-v1"
-  || JSON.stringify(portableTools?.map(({ name }) => name)) !== JSON.stringify(["pg_dump", "psql"])
-) {
-  throw new Error(`${buildInputsPath} has an incompatible portable tool inventory`);
-}
-for (const tool of portableTools) {
-  const actual = addon.toolIdentity(tool.name);
-  const expected = expectedIdentity(tool, `${tool.name} tool`);
-  if (actual !== expected) {
-    throw new Error(`${addonPath} reports ${tool.name} tool identity ${actual}; expected ${expected}`);
-  }
-}
-
-const portableExtensions = (buildInputs.inputs?.extensionArtifacts ?? [])
-  .flatMap(({ portableArchives = [] }) => portableArchives);
-const extensionNames = portableExtensions.map(({ sqlName }) => sqlName);
-if (
-  extensionNames.length === 0
-  || extensionNames.some((name) => typeof name !== "string" || name.length === 0)
-  || new Set(extensionNames).size !== extensionNames.length
-) {
-  throw new Error(`${buildInputsPath} has an invalid portable extension inventory`);
-}
-for (const extension of portableExtensions) {
-  const actual = addon.extensionIdentity(extension.sqlName);
-  const expected = expectedIdentity(extension, `${extension.sqlName} extension`);
-  if (actual !== expected) {
-    throw new Error(
-      `${addonPath} reports ${extension.sqlName} extension identity ${actual}; expected ${expected}`,
-    );
-  }
-}
-for (const component of [
-  "runtimeArchive",
-  "standardSeedArchive",
-  "standardSeedManifest",
-  "icuDataArchive",
-  "icuSeedArchive",
-  "icuSeedManifest",
-]) {
-  const identity = addon.payloadIdentity(component);
-  if (!/^[0-9a-f]{64}:[1-9][0-9]*$/.test(identity)) {
-    throw new Error(`${addonPath} reports an invalid ${component} identity: ${identity}`);
-  }
-}
-for (const constructor of ["NativeWasixActorDatabase", "NativeWasixDatabase"]) {
-  if (typeof addon[constructor]?.open !== "function") {
-    throw new Error(`${addonPath} is missing ${constructor}.open`);
-  }
-  for (const name of expectedDatabaseMethods) {
-    if (typeof addon[constructor].prototype[name] !== "function") {
-      throw new Error(`${addonPath} is missing ${constructor}.prototype.${name}`);
-    }
-  }
-}
-if (typeof addon.NativeWasixServer?.open !== "function") {
-  throw new Error(`${addonPath} is missing NativeWasixServer.open`);
-}
-for (const name of expectedServerMethods) {
-  if (typeof addon.NativeWasixServer.prototype[name] !== "function") {
-    throw new Error(`${addonPath} is missing NativeWasixServer.prototype.${name}`);
-  }
-}
-JS
-fi
-
-OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA="$artifact_source_sha" \
-  node src/runtimes/wasix-napi/tools/package-platform.mjs \
-  --target "$target_id" \
-  --prebuild-dir "$prebuild_dir" \
-  --build-inputs "$build_inputs_file"
-
-# Exercise the packed carrier, never the build directory. Node covers both
-# supported clean-install clients; every host then loads the same target addon
-# through its own Node-API implementation. Electron also exercises the
-# production ASAR-unpacked layout while remaining display-server-independent.
-for runtime_and_manager in \
-  "node npm" \
-  "node pnpm" \
-  "bun pnpm" \
-  "deno pnpm" \
-  "electron pnpm"; do
-  read -r smoke_runtime smoke_package_manager <<< "$runtime_and_manager"
-  node src/runtimes/wasix-napi/tools/smoke-packaged-addon.mjs \
-    --target "$target_id" \
-    --runtime "$smoke_runtime" \
-    --package-manager "$smoke_package_manager"
-done
-
-printf 'WASIX N-API addon: %s\n' "$addon"
diff --git a/src/runtimes/wasix-napi/tools/check-build-inputs.mjs b/src/runtimes/wasix-napi/tools/check-build-inputs.mjs
deleted file mode 100755
index f8b117275..000000000
--- a/src/runtimes/wasix-napi/tools/check-build-inputs.mjs
+++ /dev/null
@@ -1,387 +0,0 @@
-#!/usr/bin/env bun
-
-import { createHash } from "node:crypto";
-import {
-  lstatSync,
-  mkdirSync,
-  readFileSync,
-  readdirSync,
-  writeFileSync,
-} from "node:fs";
-import path from "node:path";
-import { fileURLToPath } from "node:url";
-
-import {
-  compareText,
-  exactExtensionProducts,
-  extensionArtifactProductRoot,
-  extensionSqlNames,
-  extensionWasixAotMemberSqlNames,
-} from "../../../../tools/release/release-artifact-targets.mjs";
-import { assertCanonicalWasixAotManifest } from "../../../../tools/release/wasix-aot-manifest.mjs";
-
-const PREFIX = "check-wasix-napi-build-inputs.mjs";
-const WORKSPACE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../..");
-const SHA256 = /^[0-9a-f]{64}$/u;
-
-function fail(message) {
-  throw new Error(message);
-}
-
-function parseArguments(argv) {
-  const options = {};
-  for (let index = 0; index < argv.length; index += 1) {
-    const argument = argv[index];
-    if (!argument.startsWith("--")) fail(`unexpected argument ${argument}`);
-    const value = argv[index + 1];
-    if (!value || value.startsWith("--")) fail(`${argument} requires a value`);
-    options[argument.slice(2)] = value;
-    index += 1;
-  }
-  for (const required of [
-    "target",
-    "target-triple",
-    "portable-root",
-    "aot-root",
-    "extension-root",
-    "icu-root",
-  ]) {
-    if (!options[required]) fail(`--${required} is required`);
-  }
-  if (Boolean(options.output) === Boolean(options.check)) {
-    fail("exactly one of --output or --check is required");
-  }
-  return options;
-}
-
-function repoPath(file, label) {
-  const resolved = path.resolve(file);
-  const relative = path.relative(WORKSPACE_ROOT, resolved);
-  if (!relative || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
-    fail(`${label} must be inside the repository: ${resolved}`);
-  }
-  return relative.split(path.sep).join("/");
-}
-
-function regularFile(file, label) {
-  let metadata;
-  try {
-    metadata = lstatSync(file);
-  } catch (error) {
-    fail(`${label} is missing: ${repoPath(file, label)} (${error.message})`);
-  }
-  if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) {
-    fail(`${label} must be a non-empty regular non-symlink file: ${repoPath(file, label)}`);
-  }
-  return metadata;
-}
-
-function directory(root, label) {
-  let metadata;
-  try {
-    metadata = lstatSync(root);
-  } catch (error) {
-    fail(`${label} is missing: ${repoPath(root, label)} (${error.message})`);
-  }
-  if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
-    fail(`${label} must be a regular non-symlink directory: ${repoPath(root, label)}`);
-  }
-}
-
-function readJson(file, label) {
-  regularFile(file, label);
-  try {
-    return JSON.parse(readFileSync(file, "utf8"));
-  } catch (error) {
-    fail(`${label} is not valid JSON: ${error.message}`);
-  }
-}
-
-function sha256Bytes(bytes) {
-  return createHash("sha256").update(bytes).digest("hex");
-}
-
-function sha256(file) {
-  return sha256Bytes(readFileSync(file));
-}
-
-function safeMember(value, label) {
-  if (typeof value !== "string" || value.length === 0 || path.isAbsolute(value)) {
-    fail(`${label} must be a non-empty relative path`);
-  }
-  const normalized = value.replaceAll("\\", "/");
-  if (
-    normalized !== value
-    || normalized.split("/").some((part) => !part || part === "." || part === "..")
-  ) {
-    fail(`${label} is not a canonical portable path: ${JSON.stringify(value)}`);
-  }
-  return value;
-}
-
-function validateDigestFile(file, expected, label) {
-  const metadata = regularFile(file, label);
-  if (!SHA256.test(expected ?? "")) fail(`${label} manifest digest is not lowercase SHA-256`);
-  const actual = sha256(file);
-  if (actual !== expected) fail(`${label} digest mismatch: expected ${expected}, got ${actual}`);
-  return metadata;
-}
-
-function portableInputs(portableRoot) {
-  directory(portableRoot, "portable WASIX artifact root");
-  const manifestFile = path.join(portableRoot, "manifest.json");
-  const manifest = readJson(manifestFile, "portable WASIX manifest");
-  if (manifest?.["format-version"] !== 2) fail("portable WASIX manifest must use format-version 2");
-  if (typeof manifest["source-fingerprint"] !== "string" || !manifest["source-fingerprint"]) {
-    fail("portable WASIX manifest must contain a source-fingerprint");
-  }
-  const runtimeArchive = safeMember(manifest.runtime?.archive, "portable runtime archive");
-  validateDigestFile(
-    path.join(portableRoot, runtimeArchive),
-    manifest.runtime?.sha256,
-    "portable WASIX runtime archive",
-  );
-  regularFile(path.join(portableRoot, "bin/initdb.wasix.wasm"), "portable WASIX initdb module");
-
-  for (const profile of ["standard", "icu"]) {
-    const seed = manifest["cluster-seeds"]?.[profile];
-    if (!seed || typeof seed !== "object" || Array.isArray(seed)) {
-      fail(`portable WASIX manifest is missing ${profile} cluster seed metadata`);
-    }
-    const archive = safeMember(seed.archive, `${profile} cluster seed archive`);
-    const seedManifest = safeMember(seed.manifest, `${profile} cluster seed manifest`);
-    validateDigestFile(
-      path.join(portableRoot, archive),
-      seed.sha256,
-      `${profile} cluster seed archive`,
-    );
-    regularFile(path.join(portableRoot, seedManifest), `${profile} cluster seed manifest`);
-  }
-
-  const portableTools = [
-    ["pg_dump", "bin/pg_dump.wasix.wasm"],
-    ["psql", "bin/psql.wasix.wasm"],
-  ].map(([name, relative]) => {
-    const file = path.join(portableRoot, relative);
-    regularFile(file, `portable WASIX ${name} module`);
-    return { name, path: repoPath(file, `portable WASIX ${name} module`), sha256: sha256(file) };
-  });
-
-  return {
-    manifest,
-    provenance: {
-      portableManifest: {
-        path: repoPath(manifestFile, "portable WASIX manifest"),
-        sha256: sha256(manifestFile),
-      },
-      portableTools,
-    },
-  };
-}
-
-function validateAotManifest(file, targetTriple, sourceFingerprint, label, namePredicate) {
-  const manifest = readJson(file, label);
-  try {
-    assertCanonicalWasixAotManifest(manifest, {
-      context: repoPath(file, label),
-      expectedTarget: targetTriple,
-    });
-  } catch (error) {
-    fail(error.message);
-  }
-  if (manifest["source-fingerprint"] !== sourceFingerprint) {
-    fail(`${label} source-fingerprint does not match the portable WASIX runtime`);
-  }
-  const names = new Set();
-  for (const [index, artifact] of manifest.artifacts.entries()) {
-    const name = artifact?.name;
-    if (typeof name !== "string" || !namePredicate(name)) {
-      fail(`${label} artifact ${index} has an unexpected name ${JSON.stringify(name)}`);
-    }
-    if (names.has(name)) fail(`${label} repeats artifact ${name}`);
-    names.add(name);
-    const relative = safeMember(artifact.path, `${label} artifact ${name}`);
-    validateDigestFile(path.join(path.dirname(file), relative), artifact.sha256, `${label} artifact ${name}`);
-  }
-  return { manifest, names };
-}
-
-function runtimeAotInputs(aotRoot, targetTriple, sourceFingerprint) {
-  directory(aotRoot, "WASIX AOT artifact root");
-  const targetRoot = path.basename(path.resolve(aotRoot)) === targetTriple
-    ? path.resolve(aotRoot)
-    : path.join(aotRoot, targetTriple);
-  const manifestFile = path.join(targetRoot, "manifest.json");
-  const { names } = validateAotManifest(
-    manifestFile,
-    targetTriple,
-    sourceFingerprint,
-    "host WASIX AOT manifest",
-    (name) => !name.startsWith("extension:"),
-  );
-  for (const tool of ["tool:pg_dump", "tool:psql"]) {
-    if (!names.has(tool)) fail(`host WASIX AOT manifest is missing ${tool}`);
-  }
-  if (![...names].some((name) => !name.startsWith("tool:"))) {
-    fail("host WASIX AOT manifest contains tools but no core runtime artifacts");
-  }
-  return {
-    targetTriple,
-    path: repoPath(manifestFile, "host WASIX AOT manifest"),
-    sha256: sha256(manifestFile),
-  };
-}
-
-function manifestMembers(manifest, product) {
-  if (manifest.schema === "oliphaunt-extension-ci-artifacts-v1") return [manifest];
-  if (manifest.schema === "oliphaunt-extension-ci-artifacts-v2" && Array.isArray(manifest.extensions)) {
-    return manifest.extensions;
-  }
-  fail(`${product} has an unsupported extension-artifacts schema ${JSON.stringify(manifest.schema)}`);
-}
-
-function extensionInputs(extensionRoot, target, targetTriple, sourceFingerprint) {
-  directory(extensionRoot, "WASIX extension artifact root");
-  return exactExtensionProducts(PREFIX).map((product) => {
-    const productRoot = extensionArtifactProductRoot(product, "wasix", extensionRoot, PREFIX);
-    const manifestFile = path.join(productRoot, "extension-artifacts.json");
-    const manifest = readJson(manifestFile, `${product} extension artifact manifest`);
-    if (manifest.product !== product) fail(`${repoPath(manifestFile, product)} identifies ${manifest.product}`);
-    const members = manifestMembers(manifest, product);
-    const expectedSqlNames = extensionSqlNames(product, PREFIX).sort(compareText);
-    const actualSqlNames = members.map((member) => member?.sqlName).sort(compareText);
-    if (JSON.stringify(actualSqlNames) !== JSON.stringify(expectedSqlNames)) {
-      fail(`${product} extension member inventory is not exact`);
-    }
-    const portableArchives = members.map((member) => {
-      const matches = Array.isArray(member.assets)
-        ? member.assets.filter((asset) =>
-            asset?.family === "wasix"
-            && asset.target === "wasix-portable"
-            && asset.kind === "wasix-runtime"
-          )
-        : [];
-      if (matches.length !== 1) fail(`${product}/${member.sqlName} must have one portable WASIX asset`);
-      const asset = matches[0];
-      const file = manifest.schema === "oliphaunt-extension-ci-artifacts-v2"
-        ? path.join(productRoot, "member-assets", member.sqlName, asset.name)
-        : path.join(productRoot, "release-assets", asset.name);
-      const metadata = validateDigestFile(file, asset.sha256, `${product}/${member.sqlName} portable archive`);
-      if (metadata.size !== asset.bytes) fail(`${product}/${member.sqlName} portable archive size changed`);
-      return {
-        sqlName: member.sqlName,
-        path: repoPath(file, `${product}/${member.sqlName} portable archive`),
-        sha256: asset.sha256,
-      };
-    }).sort((left, right) => compareText(left.sqlName, right.sqlName));
-
-    const aotManifests = extensionWasixAotMemberSqlNames(product, PREFIX).map((sqlName) => {
-      const targetRoot = path.join(productRoot, "wasix-aot", target);
-      const file = manifest.schema === "oliphaunt-extension-ci-artifacts-v2"
-        ? path.join(targetRoot, sqlName, "manifest.json")
-        : path.join(targetRoot, "manifest.json");
-      const { names } = validateAotManifest(
-        file,
-        targetTriple,
-        sourceFingerprint,
-        `${product}/${sqlName} AOT manifest`,
-        (name) => name === `extension:${sqlName}` || name.startsWith(`extension:${sqlName}:`),
-      );
-      if (names.size === 0) fail(`${product}/${sqlName} AOT manifest has no artifacts`);
-      return {
-        sqlName,
-        targetTriple,
-        path: repoPath(file, `${product}/${sqlName} AOT manifest`),
-        sha256: sha256(file),
-      };
-    }).sort((left, right) => compareText(left.sqlName, right.sqlName));
-
-    return {
-      product,
-      manifest: {
-        path: repoPath(manifestFile, `${product} extension artifact manifest`),
-        sha256: sha256(manifestFile),
-      },
-      portableArchives,
-      aotManifests,
-    };
-  }).sort((left, right) => compareText(left.product, right.product));
-}
-
-function visitRegularFiles(root, files = []) {
-  for (const entry of readdirSync(root, { withFileTypes: true }).sort((left, right) => compareText(left.name, right.name))) {
-    const file = path.join(root, entry.name);
-    if (entry.isSymbolicLink()) fail(`ICU input contains a symlink: ${repoPath(file, "ICU input")}`);
-    if (entry.isDirectory()) visitRegularFiles(file, files);
-    else if (entry.isFile()) files.push(file);
-    else fail(`ICU input contains a non-regular entry: ${repoPath(file, "ICU input")}`);
-  }
-  return files;
-}
-
-function icuInput(icuRoot) {
-  directory(icuRoot, "ICU data root");
-  const files = visitRegularFiles(icuRoot);
-  if (files.length === 0) fail("ICU data root must not be empty");
-  const records = files.map((file) => {
-    const relative = path.relative(icuRoot, file).split(path.sep).join("/");
-    return `${sha256(file)}  ${relative}\n`;
-  });
-  return {
-    path: repoPath(icuRoot, "ICU data root"),
-    sha256: sha256Bytes(Buffer.from(records.join(""), "utf8")),
-    fileCount: files.length,
-  };
-}
-
-function buildInventory(options) {
-  const portableRoot = path.resolve(options["portable-root"]);
-  const aotRoot = path.resolve(options["aot-root"]);
-  const extensionRoot = path.resolve(options["extension-root"]);
-  const icuRoot = path.resolve(options["icu-root"]);
-  const portable = portableInputs(portableRoot);
-  return {
-    schema: "oliphaunt-wasix-napi-build-inputs-v1",
-    target: options.target,
-    targetTriple: options["target-triple"],
-    inputs: {
-      ...portable.provenance,
-      runtimeAotManifest: runtimeAotInputs(
-        aotRoot,
-        options["target-triple"],
-        portable.manifest["source-fingerprint"],
-      ),
-      extensionArtifacts: extensionInputs(
-        extensionRoot,
-        options.target,
-        options["target-triple"],
-        portable.manifest["source-fingerprint"],
-      ),
-      icuData: icuInput(icuRoot),
-    },
-  };
-}
-
-function main() {
-  const options = parseArguments(Bun.argv.slice(2));
-  const rendered = `${JSON.stringify(buildInventory(options), null, 2)}\n`;
-  const destination = path.resolve(options.output ?? options.check);
-  repoPath(destination, options.output ? "build input inventory output" : "build input inventory check");
-  if (options.output) {
-    mkdirSync(path.dirname(destination), { recursive: true });
-    writeFileSync(destination, rendered, { encoding: "utf8", mode: 0o600 });
-  } else {
-    regularFile(destination, "recorded build input inventory");
-    if (readFileSync(destination, "utf8") !== rendered) {
-      fail("WASIX build inputs changed while compiling the Node-API addon");
-    }
-  }
-  console.log(`WASIX Node-API build inputs validated: ${repoPath(destination, "build input inventory")}`);
-}
-
-try {
-  main();
-} catch (error) {
-  console.error(`${PREFIX}: ${error instanceof Error ? error.message : String(error)}`);
-  process.exitCode = 1;
-}
diff --git a/src/runtimes/wasix-napi/tools/detect-linux-libc.mjs b/src/runtimes/wasix-napi/tools/detect-linux-libc.mjs
deleted file mode 100644
index 9fecd40d1..000000000
--- a/src/runtimes/wasix-napi/tools/detect-linux-libc.mjs
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env node
-
-import path from "node:path";
-import { fileURLToPath } from "node:url";
-
-const MUSL_LOADER = /(?:^|[/\\])(?:ld-musl-[^/\\]+[.]so[.]1|libc[.]musl-[^/\\]+[.]so[.]1)$/iu;
-
-export function detectLinuxLibc({ report, versions } = {}) {
-  const runtimeVersions = versions ?? process.versions;
-  if (typeof runtimeVersions?.musl === "string" && runtimeVersions.musl.length > 0) {
-    return "musl";
-  }
-
-  const diagnostic = report ?? process.report?.getReport?.();
-  if (
-    Array.isArray(diagnostic?.sharedObjects)
-    && diagnostic.sharedObjects.some((member) =>
-      typeof member === "string" && (MUSL_LOADER.test(member) || /(?:^|[/\\])ld-musl-/iu.test(member))
-    )
-  ) {
-    return "musl";
-  }
-  if (
-    typeof diagnostic?.header?.glibcVersionRuntime === "string"
-    && diagnostic.header.glibcVersionRuntime.length > 0
-  ) {
-    return "glibc";
-  }
-  return "unknown";
-}
-
-function main() {
-  process.stdout.write(`${detectLinuxLibc()}\n`);
-}
-
-if (path.resolve(process.argv[1] ?? "") === fileURLToPath(import.meta.url)) main();
diff --git a/src/runtimes/wasix-napi/tools/detect-linux-libc.test.mjs b/src/runtimes/wasix-napi/tools/detect-linux-libc.test.mjs
deleted file mode 100644
index b54f2a59a..000000000
--- a/src/runtimes/wasix-napi/tools/detect-linux-libc.test.mjs
+++ /dev/null
@@ -1,25 +0,0 @@
-import { describe, expect, test } from "bun:test";
-
-import { detectLinuxLibc } from "./detect-linux-libc.mjs";
-
-describe("WASIX Node-API Linux libc detection", () => {
-  test("recognizes glibc from the runtime diagnostic header", () => {
-    expect(detectLinuxLibc({
-      report: { header: { glibcVersionRuntime: "2.38" }, sharedObjects: [] },
-      versions: {},
-    })).toBe("glibc");
-  });
-
-  test("recognizes musl from an explicit runtime version or loader", () => {
-    expect(detectLinuxLibc({ report: {}, versions: { musl: "1.2.5" } })).toBe("musl");
-    expect(detectLinuxLibc({
-      report: { header: {}, sharedObjects: ["/lib/ld-musl-x86_64.so.1"] },
-      versions: {},
-    })).toBe("musl");
-  });
-
-  test("does not guess when diagnostics identify neither libc", () => {
-    expect(detectLinuxLibc({ report: { header: {}, sharedObjects: [] }, versions: {} }))
-      .toBe("unknown");
-  });
-});
diff --git a/src/runtimes/wasix-napi/tools/package-platform.mjs b/src/runtimes/wasix-napi/tools/package-platform.mjs
deleted file mode 100755
index 1f2c12f94..000000000
--- a/src/runtimes/wasix-napi/tools/package-platform.mjs
+++ /dev/null
@@ -1,296 +0,0 @@
-#!/usr/bin/env node
-
-import { createHash } from "node:crypto";
-import {
-  cpSync,
-  existsSync,
-  mkdirSync,
-  readFileSync,
-  rmSync,
-  writeFileSync,
-} from "node:fs";
-import { execFileSync } from "node:child_process";
-import path from "node:path";
-import { fileURLToPath } from "node:url";
-
-import { localWindowsTarInvocation } from "../../../../tools/release/tar-command.mjs";
-import {
-  WINDOWS_VC_RUNTIME_RECEIPT,
-  stageWindowsVcRuntime,
-} from "../../../../tools/release/windows-vc-runtime-closure.mjs";
-import { portableCommand } from "./portable-command.mjs";
-
-const WORKSPACE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../..");
-const PRODUCT_ROOT = path.join(WORKSPACE_ROOT, "src/runtimes/wasix-napi");
-const BUN_WRAPPER = path.join(WORKSPACE_ROOT, "tools/dev/bun.sh");
-const RELEASE_NOTICES = path.join(WORKSPACE_ROOT, "tools/release/release-notices.mjs");
-const ARCHIVE_DIRECTORY = path.join(WORKSPACE_ROOT, "src/shared/artifact-packaging/archive-directory.mjs");
-const PLATFORM_BINARY_CONTRACT = path.join(
-  WORKSPACE_ROOT,
-  "tools/release/platform-binary-contract.mjs",
-);
-const CHECK_LINUX_CONSUMER_BASELINE = path.join(
-  WORKSPACE_ROOT,
-  "tools/release/check-linux-consumer-baseline.sh",
-);
-const TARGETS = Object.freeze({
-  "macos-arm64": "darwin-arm64",
-  "linux-arm64-gnu": "linux-arm64-gnu",
-  "linux-x64-gnu": "linux-x64-gnu",
-  "windows-x64-msvc": "win32-x64-msvc",
-});
-const BINARY = "oliphaunt_wasix_napi.node";
-
-function parseArguments(argv) {
-  const options = {};
-  for (let index = 0; index < argv.length; index += 1) {
-    const argument = argv[index];
-    if (!argument.startsWith("--")) {
-      throw new Error(`unexpected argument ${argument}`);
-    }
-    const value = argv[index + 1];
-    if (!value || value.startsWith("--")) {
-      throw new Error(`${argument} requires a value`);
-    }
-    options[argument.slice(2)] = value;
-    index += 1;
-  }
-  return options;
-}
-
-function sha256(file) {
-  return createHash("sha256").update(readFileSync(file)).digest("hex");
-}
-
-function readJson(file) {
-  return JSON.parse(readFileSync(file, "utf8"));
-}
-
-function requireFile(file) {
-  if (!existsSync(file)) {
-    throw new Error(`missing required file: ${path.relative(WORKSPACE_ROOT, file)}`);
-  }
-}
-
-function stageReleaseNotices(directory) {
-  const invocation = portableCommand(BUN_WRAPPER, [
-    RELEASE_NOTICES,
-    "stage",
-    directory,
-    "--profile",
-    "wasix-napi-addon",
-  ]);
-  execFileSync(
-    invocation.command,
-    invocation.args,
-    { cwd: WORKSPACE_ROOT, stdio: "inherit" },
-  );
-}
-
-function main() {
-  const options = parseArguments(process.argv.slice(2));
-  const target = options.target;
-  const carrierDirectory = TARGETS[target];
-  if (!carrierDirectory) {
-    throw new Error(`--target must be one of ${Object.keys(TARGETS).join(", ")}`);
-  }
-  if (!options["build-inputs"]) {
-    throw new Error("--build-inputs is required");
-  }
-  const buildInputsFile = path.resolve(options["build-inputs"]);
-  requireFile(buildInputsFile);
-  const buildInputs = readJson(buildInputsFile);
-  if (
-    buildInputs.schema !== "oliphaunt-wasix-napi-build-inputs-v1"
-    || buildInputs.target !== target
-    || typeof buildInputs.targetTriple !== "string"
-    || buildInputs.targetTriple.length === 0
-    || !Array.isArray(buildInputs.inputs?.extensionArtifacts)
-    || buildInputs.inputs.extensionArtifacts.length === 0
-  ) {
-    throw new Error(`${path.basename(buildInputsFile)} has incompatible WASIX N-API build inputs`);
-  }
-  const prebuildDirectory = path.resolve(
-    options["prebuild-dir"]
-      ?? path.join(WORKSPACE_ROOT, "target/oliphaunt-wasix-napi/prebuilds", target),
-  );
-  requireFile(path.join(prebuildDirectory, BINARY));
-
-  const sourcePackage = path.join(PRODUCT_ROOT, "packages", carrierDirectory);
-  const packageWork = path.join(
-    WORKSPACE_ROOT,
-    "target/oliphaunt-wasix-napi/npm-package-work",
-    carrierDirectory,
-  );
-  const packageOutput = path.join(WORKSPACE_ROOT, "target/oliphaunt-wasix-napi/npm-packages");
-  rmSync(packageWork, { recursive: true, force: true });
-  mkdirSync(path.join(packageWork, "prebuilds"), { recursive: true });
-  mkdirSync(packageOutput, { recursive: true });
-  cpSync(sourcePackage, packageWork, { recursive: true });
-  const packagePrebuilds = path.join(packageWork, "prebuilds");
-  mkdirSync(packagePrebuilds, { recursive: true });
-  cpSync(path.join(prebuildDirectory, BINARY), path.join(packagePrebuilds, BINARY));
-  stageReleaseNotices(packageWork);
-  const windowsRuntimeNames = target === "windows-x64-msvc"
-    ? stageWindowsVcRuntime({
-      root: packageWork,
-      destinations: [packagePrebuilds],
-    }).required
-    : [];
-
-  const sourceSha = execFileSync("git", ["rev-parse", "HEAD"], {
-    cwd: WORKSPACE_ROOT,
-    encoding: "utf8",
-  }).trim();
-  const artifactSourceSha = process.env.OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA ?? sourceSha;
-  if (!/^[0-9a-f]{40}$/.test(artifactSourceSha)) {
-    throw new Error("OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA must be a lowercase Git SHA");
-  }
-  const provenance = {
-    schema: "oliphaunt-wasix-napi-provenance-v1",
-    product: "oliphaunt-wasix-napi",
-    target,
-    sourceSha,
-    artifactSourceSha,
-    build: {
-      cargoProfile: "release",
-      incremental: false,
-      codegenUnits: 1,
-      lto: "thin",
-      strip: "symbols",
-      features: ["release"],
-      targetTriple: buildInputs.targetTriple,
-    },
-    buildInputs,
-    binary: {
-      filename: BINARY,
-      sha256: sha256(path.join(packageWork, "prebuilds", BINARY)),
-    },
-  };
-  writeFileSync(
-    path.join(packageWork, "artifact-provenance.json"),
-    `${JSON.stringify(provenance, null, 2)}\n`,
-  );
-
-  const rootManifest = readJson(path.join(PRODUCT_ROOT, "package.json"));
-  const releaseStage = path.join(
-    WORKSPACE_ROOT,
-    "target/oliphaunt-wasix-napi/release-stage",
-    target,
-  );
-  const releaseAssets = path.join(WORKSPACE_ROOT, "target/oliphaunt-wasix-napi/release-assets");
-  rmSync(releaseStage, { recursive: true, force: true });
-  mkdirSync(releaseStage, { recursive: true });
-  mkdirSync(releaseAssets, { recursive: true });
-  cpSync(path.join(prebuildDirectory, BINARY), path.join(releaseStage, BINARY));
-  stageReleaseNotices(releaseStage);
-  cpSync(
-    path.join(packageWork, "artifact-provenance.json"),
-    path.join(releaseStage, "artifact-provenance.json"),
-  );
-  if (target === "windows-x64-msvc") {
-    const releaseRuntimeNames = stageWindowsVcRuntime({
-      root: releaseStage,
-      sourceDirectory: packagePrebuilds,
-      destinations: [releaseStage],
-    }).required;
-    if (JSON.stringify(releaseRuntimeNames) !== JSON.stringify(windowsRuntimeNames)) {
-      throw new Error("release and npm carriers derived different Windows VC runtime closures");
-    }
-  }
-  const platformCheck = portableCommand(BUN_WRAPPER, [
-    PLATFORM_BINARY_CONTRACT,
-    "--target",
-    target,
-    "--root",
-    releaseStage,
-  ]);
-  execFileSync(
-    platformCheck.command,
-    platformCheck.args,
-    { cwd: WORKSPACE_ROOT, stdio: "inherit" },
-  );
-  if (target.startsWith("linux-")) {
-    execFileSync(
-      "bash",
-      [CHECK_LINUX_CONSUMER_BASELINE, "--target", target, "--root", releaseStage],
-      { cwd: WORKSPACE_ROOT, stdio: "inherit" },
-    );
-  }
-  const archiveExtension = target === "windows-x64-msvc" ? "zip" : "tar.gz";
-  const releaseArchive = path.join(
-    releaseAssets,
-    `oliphaunt-wasix-napi-${rootManifest.version}-${target}.${archiveExtension}`,
-  );
-  const archiveCommand = portableCommand(BUN_WRAPPER, [
-    ARCHIVE_DIRECTORY,
-    releaseStage,
-    releaseArchive,
-  ]);
-  execFileSync(archiveCommand.command, archiveCommand.args, {
-    cwd: WORKSPACE_ROOT,
-    stdio: "inherit",
-  });
-
-  const packCommand = portableCommand("pnpm", [
-    "--dir",
-    packageWork,
-    "pack",
-    "--pack-destination",
-    packageOutput,
-    "--json",
-  ]);
-  const output = execFileSync(
-    packCommand.command,
-    packCommand.args,
-    { cwd: WORKSPACE_ROOT, encoding: "utf8" },
-  );
-  const parsed = JSON.parse(output);
-  const entry = Array.isArray(parsed) ? parsed[0] : parsed;
-  if (!entry || typeof entry.filename !== "string" || !entry.filename.endsWith(".tgz")) {
-    throw new Error("pnpm pack did not report a .tgz filename");
-  }
-  const tarball = path.isAbsolute(entry.filename)
-    ? entry.filename
-    : path.join(packageOutput, entry.filename);
-  requireFile(tarball);
-
-  const tarInvocation = localWindowsTarInvocation(["-tzf", tarball], {
-    cwd: WORKSPACE_ROOT,
-  });
-  const listing = execFileSync("tar", tarInvocation.args, {
-    cwd: tarInvocation.cwd,
-    encoding: "utf8",
-  })
-    .trim()
-    .split(/\r?\n/u);
-  const requiredMembers = [
-    `package/prebuilds/${BINARY}`,
-    "package/artifact-provenance.json",
-    "package/LICENSE",
-    "package/THIRD_PARTY_NOTICES.md",
-    "package/THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
-    "package/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "package/THIRD_PARTY_LICENSES/ICU-LICENSE",
-    "package/THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt",
-  ];
-  if (windowsRuntimeNames.length > 0) {
-    requiredMembers.push(
-      ...windowsRuntimeNames.map((name) => `package/prebuilds/${name}`),
-      `package/prebuilds/${WINDOWS_VC_RUNTIME_RECEIPT}`,
-    );
-  }
-  for (const member of requiredMembers) {
-    if (!listing.includes(member)) {
-      throw new Error(`${path.basename(tarball)} is missing ${member}`);
-    }
-  }
-  process.stdout.write(`${tarball}\n${releaseArchive}\n`);
-}
-
-try {
-  main();
-} catch (error) {
-  console.error(`package-wasix-napi-platform: ${error instanceof Error ? error.message : String(error)}`);
-  process.exitCode = 1;
-}
diff --git a/src/runtimes/wasix-napi/tools/portable-command.mjs b/src/runtimes/wasix-napi/tools/portable-command.mjs
deleted file mode 100644
index 6281458da..000000000
--- a/src/runtimes/wasix-napi/tools/portable-command.mjs
+++ /dev/null
@@ -1,22 +0,0 @@
-import path from "node:path";
-
-const WINDOWS_PACKAGE_MANAGERS = new Set(["npm", "pnpm"]);
-
-/** Resolve script and package-manager shims without asking Node to execute them directly. */
-export function portableCommand(
-  command,
-  args,
-  { platform = process.platform, comspec = process.env.ComSpec } = {},
-) {
-  if (path.extname(command).toLowerCase() === ".sh") {
-    const script = platform === "win32" ? command.replaceAll("\\", "/") : command;
-    return { command: "bash", args: [script, ...args] };
-  }
-  if (platform === "win32" && WINDOWS_PACKAGE_MANAGERS.has(command)) {
-    return {
-      command: comspec || "cmd.exe",
-      args: ["/d", "/s", "/c", `${command}.cmd`, ...args],
-    };
-  }
-  return { command, args };
-}
diff --git a/src/runtimes/wasix-napi/tools/portable-command.test.mjs b/src/runtimes/wasix-napi/tools/portable-command.test.mjs
deleted file mode 100644
index 9ca46cbe7..000000000
--- a/src/runtimes/wasix-napi/tools/portable-command.test.mjs
+++ /dev/null
@@ -1,43 +0,0 @@
-import { describe, expect, test } from "bun:test";
-
-import { portableCommand } from "./portable-command.mjs";
-
-describe("WASIX Node-API portable subprocess commands", () => {
-  test("always invokes repository shell wrappers through bash", () => {
-    expect(portableCommand("tools/dev/bun.sh", ["script.mjs"], { platform: "linux" })).toEqual({
-      command: "bash",
-      args: ["tools/dev/bun.sh", "script.mjs"],
-    });
-    expect(portableCommand("C:\\repo\\tools\\dev\\deno.sh", ["run"], { platform: "win32" })).toEqual({
-      command: "bash",
-      args: ["C:/repo/tools/dev/deno.sh", "run"],
-    });
-  });
-
-  test("invokes Windows npm and pnpm command shims through ComSpec", () => {
-    expect(
-      portableCommand("pnpm", ["install", "--ignore-scripts"], {
-        platform: "win32",
-        comspec: "C:\\Windows\\System32\\cmd.exe",
-      }),
-    ).toEqual({
-      command: "C:\\Windows\\System32\\cmd.exe",
-      args: ["/d", "/s", "/c", "pnpm.cmd", "install", "--ignore-scripts"],
-    });
-    expect(portableCommand("npm", ["exec"], { platform: "win32" })).toEqual({
-      command: "cmd.exe",
-      args: ["/d", "/s", "/c", "npm.cmd", "exec"],
-    });
-  });
-
-  test("leaves native executables and Unix package managers unchanged", () => {
-    expect(portableCommand("node", ["verify.mjs"], { platform: "win32" })).toEqual({
-      command: "node",
-      args: ["verify.mjs"],
-    });
-    expect(portableCommand("pnpm", ["pack"], { platform: "linux" })).toEqual({
-      command: "pnpm",
-      args: ["pack"],
-    });
-  });
-});
diff --git a/src/runtimes/wasix-napi/tools/smoke-packaged-addon.mjs b/src/runtimes/wasix-napi/tools/smoke-packaged-addon.mjs
deleted file mode 100644
index a01f346d9..000000000
--- a/src/runtimes/wasix-napi/tools/smoke-packaged-addon.mjs
+++ /dev/null
@@ -1,542 +0,0 @@
-#!/usr/bin/env node
-
-import { execFile } from "node:child_process";
-import { access, cp, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
-import { createRequire } from "node:module";
-import { tmpdir } from "node:os";
-import path from "node:path";
-import { fileURLToPath, pathToFileURL } from "node:url";
-import { promisify } from "node:util";
-
-import { portableCommand } from "./portable-command.mjs";
-
-const execFileAsync = promisify(execFile);
-const WORKSPACE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../..");
-const PACKAGE_ROOT = path.join(WORKSPACE_ROOT, "src/runtimes/wasix-napi");
-const PACKAGE_OUTPUT = path.join(WORKSPACE_ROOT, "target/oliphaunt-wasix-napi/npm-packages");
-const BINARY = "oliphaunt_wasix_napi.node";
-const PGWIRE_CLIENT = pathToFileURL(
-  path.join(WORKSPACE_ROOT, "src/bindings/wasix-ts/tools/pgwire-client.mjs"),
-).href;
-const ELECTRON_ASAR_VERSION = "3.4.1";
-const ELECTRON_VERSION = "39.2.5";
-const TARGET_PACKAGES = Object.freeze({
-  "linux-arm64-gnu": "linux-arm64-gnu",
-  "linux-x64-gnu": "linux-x64-gnu",
-  "macos-arm64": "darwin-arm64",
-  "windows-x64-msvc": "win32-x64-msvc",
-});
-
-function parseArguments(argv) {
-  const options = { packageManager: "pnpm" };
-  for (let index = 0; index < argv.length; index += 1) {
-    const argument = argv[index];
-    const value = argv[index + 1];
-    if (!["--package-manager", "--runtime", "--target"].includes(argument) || !value) {
-      throw new Error(
-        "usage: smoke-packaged-addon.mjs --target TARGET --runtime node|bun|deno|electron [--package-manager npm|pnpm]",
-      );
-    }
-    options[argument.slice(2).replace(/-([a-z])/gu, (_match, letter) => letter.toUpperCase())] = value;
-    index += 1;
-  }
-  if (!Object.hasOwn(TARGET_PACKAGES, options.target)) {
-    throw new Error(`unsupported WASIX Node-API smoke target ${options.target}`);
-  }
-  if (!["bun", "deno", "electron", "node"].includes(options.runtime)) {
-    throw new Error(`unsupported WASIX Node-API smoke runtime ${options.runtime}`);
-  }
-  if (!["npm", "pnpm"].includes(options.packageManager)) {
-    throw new Error(`unsupported WASIX Node-API smoke package manager ${options.packageManager}`);
-  }
-  return options;
-}
-
-async function run(command, args, cwd, extraEnv = {}) {
-  const invocation = portableCommand(command, args);
-  return execFileAsync(invocation.command, invocation.args, {
-    cwd,
-    env: {
-      ...process.env,
-      NPM_CONFIG_AUDIT: "false",
-      NPM_CONFIG_FUND: "false",
-      NPM_CONFIG_IGNORE_SCRIPTS: "true",
-      PNPM_CONFIG_IGNORE_SCRIPTS: "true",
-      ...extraEnv,
-    },
-    maxBuffer: 64 * 1024 * 1024,
-    timeout: 300_000,
-  });
-}
-
-function tarballName(manifest) {
-  return `${manifest.name.slice(1).replace("/", "-")}-${manifest.version}.tgz`;
-}
-
-function runtimeCommand(runtime, verification) {
-  if (runtime === "node") return [process.execPath, [verification], {}];
-  if (runtime === "bun") {
-    return [path.join(WORKSPACE_ROOT, "tools/dev/bun.sh"), [verification], {}];
-  }
-  if (runtime === "deno") {
-    return [
-      path.join(WORKSPACE_ROOT, "tools/dev/deno.sh"),
-      [
-        "run",
-        "--allow-env",
-        "--allow-ffi",
-        "--allow-net=127.0.0.1",
-        "--allow-read",
-        verification,
-      ],
-      {},
-    ];
-  }
-  return [
-    "npm",
-    ["exec", "--yes", `--package=electron@${ELECTRON_VERSION}`, "--", "electron", verification],
-    {
-      ELECTRON_RUN_AS_NODE: "1",
-      NPM_CONFIG_IGNORE_SCRIPTS: "false",
-      PNPM_CONFIG_IGNORE_SCRIPTS: "false",
-    },
-  ];
-}
-
-async function runElectronAsarSmoke(scratch, carrierManifest) {
-  const require = createRequire(path.join(scratch, "package.json"));
-  const installedManifest = require.resolve(`${carrierManifest.name}/package.json`);
-  const installedCarrier = await realpath(path.dirname(installedManifest));
-  const source = path.join(scratch, "asar-source");
-  const archive = path.join(scratch, "app.asar");
-  const scopedDirectory = carrierManifest.name;
-  const archivedCarrier = path.join(source, "node_modules", scopedDirectory);
-  await mkdir(path.dirname(archivedCarrier), { recursive: true });
-  await cp(installedCarrier, archivedCarrier, { recursive: true });
-  await writeFile(
-    path.join(source, "package.json"),
-    `${JSON.stringify({ name: "oliphaunt-wasix-napi-asar-smoke", main: "main.cjs" }, null, 2)}\n`,
-  );
-  await writeFile(
-    path.join(source, "main.cjs"),
-    `const addonPath = require.resolve(${JSON.stringify(`${carrierManifest.name}/${BINARY}`)});
-if (!addonPath.includes('app.asar')) {
-  throw new Error('ASAR smoke resolved the addon outside app.asar: ' + addonPath);
-}
-const addon = require(addonPath);
-if (
-  addon.addonAbiVersion() !== 1 ||
-  addon.nodeApiVersion() !== 8 ||
-  JSON.stringify(addon.supportedProfiles()) !== JSON.stringify(['standard', 'icu'])
-) {
-  throw new Error('ASAR-unpacked addon reports incompatible metadata');
-}
-console.log('oliphaunt-wasix-napi-asar-unpacked:PASS');
-`,
-  );
-  await run(
-    "npm",
-    [
-      "exec",
-      "--yes",
-      `--package=@electron/asar@${ELECTRON_ASAR_VERSION}`,
-      "--",
-      "asar",
-      "pack",
-      source,
-      archive,
-      "--unpack",
-      "**/prebuilds/**",
-    ],
-    scratch,
-  );
-
-  const unpackedBinary = path.join(
-    `${archive}.unpacked`,
-    "node_modules",
-    scopedDirectory,
-    "prebuilds",
-    BINARY,
-  );
-  const installedPrebuilds = path.join(installedCarrier, "prebuilds");
-  const unpackedPrebuilds = path.dirname(unpackedBinary);
-  const packagedCompanions = await readdir(installedPrebuilds);
-  await Promise.all(
-    packagedCompanions.map((name) => access(path.join(unpackedPrebuilds, name))),
-  );
-  const heldBinary = `${unpackedBinary}.missing`;
-  const verification = path.join(archive, "main.cjs");
-  const [command, args, env] = runtimeCommand("electron", verification);
-  await rename(unpackedBinary, heldBinary);
-  let missingCompanionRejected = false;
-  try {
-    await run(command, args, scratch, env);
-  } catch {
-    missingCompanionRejected = true;
-  } finally {
-    await rename(heldBinary, unpackedBinary);
-  }
-  if (!missingCompanionRejected) {
-    throw new Error("Electron loaded an ASAR-unpacked addon without its unpacked .node companion");
-  }
-
-  const { stdout } = await run(command, args, scratch, env);
-  if (!stdout.includes("oliphaunt-wasix-napi-asar-unpacked:PASS")) {
-    throw new Error(`Electron ASAR-unpacked smoke returned unexpected output: ${stdout.trim()}`);
-  }
-}
-
-async function runWorkerUnloadSmoke(scratch, carrierManifest, runtime) {
-  const verification = path.join(scratch, "worker-unload.mjs");
-  await writeFile(
-    verification,
-    `import { createRequire } from 'node:module';
-import { Worker } from 'node:worker_threads';
-
-const require = createRequire(import.meta.url);
-const addonPath = require.resolve(${JSON.stringify(`${carrierManifest.name}/${BINARY}`)});
-const openOptions = ${JSON.stringify({
-  profile: "standard",
-  storage: { kind: "memory" },
-  username: "postgres",
-  database: "postgres",
-  startupGucs: {},
-  extensions: [],
-})};
-const naturalExitSource = [
-  "import { createRequire } from 'node:module';",
-  "import { parentPort, workerData } from 'node:worker_threads';",
-  "const addon = createRequire(workerData.addonPath)(workerData.addonPath);",
-  "const database = addon.NativeWasixDatabase.open(workerData.openOptions);",
-  "try {",
-  "  const query = new TextEncoder().encode('SELECT 42::text\\0');",
-  "  const request = new Uint8Array(5 + query.length);",
-  "  request[0] = 0x51;",
-  "  new DataView(request.buffer).setUint32(1, 4 + query.length, false);",
-  "  request.set(query, 5);",
-  "  const response = database.execProtocolRaw(request);",
-  "  if (!new TextDecoder().decode(response).includes('42')) throw new Error('worker query omitted 42');",
-  "} finally {",
-  "  database.close();",
-  "}",
-  "if (!database.closed) throw new Error('worker direct database did not close');",
-  "parentPort.postMessage('closed');",
-  "if (workerData.runtime === 'bun') process.exit(0);",
-  "else {",
-  "  parentPort.close?.();",
-  "  parentPort.unref();",
-  "}",
-].join('\\n');
-const terminateSource = [
-  "import { createRequire } from 'node:module';",
-  "import { parentPort, workerData } from 'node:worker_threads';",
-  "const addon = createRequire(workerData.addonPath)(workerData.addonPath);",
-  "globalThis.database = addon.NativeWasixDatabase.open(workerData.openOptions);",
-  "parentPort.postMessage('opened');",
-  "setInterval(() => undefined, 60_000);",
-].join('\\n');
-
-function spawn(source, name) {
-  return new Worker(new URL('data:text/javascript,' + encodeURIComponent(source)), {
-    name,
-    workerData: { addonPath, openOptions, runtime: ${JSON.stringify(runtime)} },
-  });
-}
-
-async function awaitNaturalExit(iteration) {
-  const worker = spawn(naturalExitSource, 'oliphaunt-wasix-direct-unload-' + iteration);
-  let exitObserved = false;
-  try {
-    await new Promise((resolve, reject) => {
-      let message;
-      worker.once('message', (value) => {
-        message = value;
-      });
-      worker.once('error', reject);
-      worker.once('exit', (code) => {
-        exitObserved = true;
-        if (code !== 0) reject(new Error('direct worker exited with code ' + code));
-        else if (message !== 'closed') reject(new Error('direct worker omitted close acknowledgement'));
-        else resolve();
-      });
-    });
-  } finally {
-    // Forced termination is only failure cleanup. Bun does not settle a
-    // redundant terminate() after a Worker has emitted its exit event.
-    if (!exitObserved) await worker.terminate();
-  }
-}
-
-for (let iteration = 1; iteration <= 20; iteration += 1) {
-  await awaitNaturalExit(iteration);
-}
-
-const terminated = spawn(terminateSource, 'oliphaunt-wasix-direct-terminate-after-open');
-await new Promise((resolve, reject) => {
-  terminated.once('message', (message) => {
-    if (message !== 'opened') {
-      reject(new Error('terminate-after-open worker returned an unexpected message'));
-      return;
-    }
-    void terminated.terminate().then(resolve, reject);
-  });
-  terminated.once('error', reject);
-});
-
-console.log(${JSON.stringify(`oliphaunt-wasix-napi-worker-unload-${runtime}:PASS`)});
-`,
-  );
-  const [command, args, env] = runtimeCommand(runtime, verification);
-  const { stdout } = await run(command, args, scratch, env);
-  const marker = `oliphaunt-wasix-napi-worker-unload-${runtime}:PASS`;
-  if (!stdout.includes(marker)) {
-    throw new Error(`${runtime} Worker unload smoke returned unexpected output: ${stdout.trim()}`);
-  }
-}
-
-async function main() {
-  const options = parseArguments(process.argv.slice(2));
-  const carrierDirectory = TARGET_PACKAGES[options.target];
-  const carrierManifest = JSON.parse(
-    await readFile(path.join(PACKAGE_ROOT, "packages", carrierDirectory, "package.json"), "utf8"),
-  );
-  const tarball = path.join(PACKAGE_OUTPUT, tarballName(carrierManifest));
-  await readFile(tarball);
-
-  const scratch = await mkdtemp(path.join(tmpdir(), `oliphaunt-wasix-napi-${options.runtime}-`));
-  try {
-    await writeFile(
-      path.join(scratch, "package.json"),
-      `${JSON.stringify({
-        name: "oliphaunt-wasix-napi-smoke",
-        version: "0.0.0",
-        private: true,
-        type: "module",
-        dependencies: { [carrierManifest.name]: pathToFileURL(tarball).href },
-      }, null, 2)}\n`,
-    );
-    if (options.packageManager === "pnpm") {
-      await writeFile(
-        path.join(scratch, "pnpm-workspace.yaml"),
-        "packages:\n  - .\nminimumReleaseAge: 0\nallowBuilds: {}\n",
-      );
-      await run("pnpm", ["install", "--ignore-scripts", "--no-frozen-lockfile"], scratch);
-    } else {
-      await run(
-        "npm",
-        ["install", "--ignore-scripts", "--no-audit", "--no-fund", "--package-lock=false"],
-        scratch,
-      );
-    }
-
-    await runWorkerUnloadSmoke(scratch, carrierManifest, options.runtime);
-
-    const verification = path.join(scratch, "verify.mjs");
-    await writeFile(
-      verification,
-      `import { readdirSync, readFileSync } from 'node:fs';
-import { createRequire } from 'node:module';
-import { dirname, join } from 'node:path';
-
-const {
-  connect,
-  onceClosed,
-  onceConnected,
-  readExchange,
-  simpleQuery: wireSimpleQuery,
-  startupPacket,
-} = await import(${JSON.stringify(PGWIRE_CLIENT)});
-
-const require = createRequire(import.meta.url);
-const packageName = ${JSON.stringify(carrierManifest.name)};
-const expectedTarget = ${JSON.stringify(options.target)};
-const expectedElectron = ${JSON.stringify(ELECTRON_VERSION)};
-const manifestPath = require.resolve(packageName + '/package.json');
-const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
-const prebuilds = join(dirname(manifestPath), 'prebuilds');
-const nativeFiles = readdirSync(prebuilds).filter((name) => name.endsWith('.node'));
-if (
-  manifest.name !== packageName ||
-  manifest.oliphaunt?.target !== expectedTarget ||
-  manifest.oliphaunt?.addonAbiVersion !== 1 ||
-  manifest.oliphaunt?.nodeApiVersion !== 8 ||
-  JSON.stringify(manifest.oliphaunt?.profiles) !== JSON.stringify(['standard', 'icu']) ||
-  JSON.stringify(nativeFiles) !== JSON.stringify([${JSON.stringify(BINARY)}])
-) {
-  throw new Error('installed WASIX Node-API carrier has incompatible metadata or binary inventory');
-}
-const addon = require(packageName + '/${BINARY}');
-for (const name of [
-  'addonAbiVersion',
-  'extensionIdentity',
-  'nodeApiVersion',
-  'payloadIdentity',
-  'restore',
-  'restoreDirect',
-  'runtimeVersion',
-  'supportedProfiles',
-  'toolIdentity',
-]) {
-  if (typeof addon[name] !== 'function') throw new Error('addon is missing function ' + name);
-}
-if (
-  addon.addonAbiVersion() !== manifest.oliphaunt.addonAbiVersion ||
-  addon.nodeApiVersion() !== manifest.oliphaunt.nodeApiVersion ||
-  addon.runtimeVersion() !== manifest.oliphaunt.runtimeVersion ||
-  JSON.stringify(addon.supportedProfiles()) !== JSON.stringify(manifest.oliphaunt.profiles)
-) {
-  throw new Error('addon self-reported metadata differs from its carrier');
-}
-for (const constructor of ['NativeWasixActorDatabase', 'NativeWasixDatabase']) {
-  if (typeof addon[constructor]?.open !== 'function') {
-    throw new Error('addon is missing ' + constructor + '.open');
-  }
-  for (const method of ['backup', 'close', 'execProtocolRaw', 'execProtocolRawStream', 'pgDump', 'psql']) {
-    if (typeof addon[constructor].prototype[method] !== 'function') {
-      throw new Error('addon is missing ' + constructor + '.prototype.' + method);
-    }
-  }
-}
-if (typeof addon.NativeWasixServer?.open !== 'function' || typeof addon.NativeWasixServer.prototype.close !== 'function') {
-  throw new Error('addon is missing NativeWasixServer');
-}
-if (process.versions.electron !== undefined && process.versions.electron !== expectedElectron) {
-  throw new Error('unexpected Electron version ' + process.versions.electron);
-}
-
-const runtime = ${JSON.stringify(options.runtime)};
-const decoder = new TextDecoder();
-const openOptions = {
-  profile: 'standard',
-  storage: { kind: 'memory' },
-  username: 'postgres',
-  database: 'postgres',
-  startupGucs: {},
-  extensions: [],
-};
-
-function simpleQuery(sql) {
-  const query = new TextEncoder().encode(sql);
-  const message = new Uint8Array(1 + 4 + query.byteLength + 1);
-  message[0] = 'Q'.charCodeAt(0);
-  new DataView(message.buffer).setUint32(1, 4 + query.byteLength + 1, false);
-  message.set(query, 5);
-  return message;
-}
-
-function verifySimpleQuery(response, owner) {
-  let answer = false;
-  let ready = false;
-  for (let offset = 0; offset < response.byteLength;) {
-    if (offset + 5 > response.byteLength) throw new Error(owner + ' returned a truncated frame');
-    const tag = String.fromCharCode(response[offset]);
-    const length = new DataView(
-      response.buffer,
-      response.byteOffset + offset + 1,
-      4,
-    ).getUint32(0, false);
-    const end = offset + 1 + length;
-    if (length < 4 || end > response.byteLength) throw new Error(owner + ' returned an invalid frame');
-    if (tag === 'D') {
-      const view = new DataView(response.buffer, response.byteOffset + offset + 5, length - 4);
-      const fields = view.getUint16(0, false);
-      const valueLength = view.getInt32(2, false);
-      if (fields === 1 && valueLength === 2) {
-        const value = response.subarray(offset + 11, offset + 13);
-        answer = decoder.decode(value) === '42';
-      }
-    }
-    if (tag === 'Z') ready = true;
-    offset = end;
-  }
-  if (!answer || !ready) throw new Error(owner + ' failed the PostgreSQL Simple Query roundtrip');
-}
-
-function transferResponse(response, owner) {
-  if (!(response instanceof Uint8Array) || !(response.buffer instanceof ArrayBuffer)) {
-    throw new Error(owner + ' did not return a V8-owned Uint8Array');
-  }
-  const transferred = structuredClone(response, { transfer: [response.buffer] });
-  if (response.byteLength !== 0 || !(transferred instanceof Uint8Array)) {
-    throw new Error(owner + ' response ArrayBuffer was not transferable');
-  }
-  return transferred;
-}
-
-async function exerciseDatabase(constructor, owner) {
-  const database = await constructor.open(openOptions);
-  try {
-    const response = await database.execProtocolRaw(simpleQuery('SELECT 42::text AS answer'));
-    verifySimpleQuery(transferResponse(response, owner), owner);
-  } finally {
-    await database.close();
-  }
-  if (!database.closed) throw new Error(owner + ' did not reach its closed state');
-}
-
-await exerciseDatabase(addon.NativeWasixActorDatabase, runtime + '-actor');
-await exerciseDatabase(addon.NativeWasixDatabase, runtime + '-direct');
-
-async function exerciseServer() {
-  const server = await addon.NativeWasixServer.open({
-    ...openOptions,
-    listen: { transport: 'tcp' },
-  });
-  if (
-    server.closed ||
-    typeof server.connectionString !== 'string' ||
-    server.connectionString.length === 0
-  ) {
-    throw new Error(runtime + ' server did not expose a live connection string');
-  }
-  const socket = connect(server.connectionString);
-  let startup;
-  let query;
-  try {
-    await onceConnected(socket);
-    const startupResponse = readExchange(socket);
-    socket.write(startupPacket('postgres', 'postgres'));
-    startup = await startupResponse;
-    const queryResponse = readExchange(socket);
-    socket.write(wireSimpleQuery('SELECT 42::int AS answer'));
-    query = await queryResponse;
-  } finally {
-    socket.end();
-    await onceClosed(socket);
-    await server.close();
-  }
-  if (!server.closed || startup.messages < 1 || query.messages < 3 || query.totalBytes < 6) {
-    throw new Error(
-      runtime + ' server wire roundtrip failed: ' +
-        JSON.stringify({ closed: server.closed, startup, query }),
-    );
-  }
-}
-await exerciseServer();
-console.log(JSON.stringify({
-  addonAbiVersion: addon.addonAbiVersion(),
-  nodeApiVersion: addon.nodeApiVersion(),
-  profiles: addon.supportedProfiles(),
-  runtime,
-  roundtrip: 'actor+direct+server-wire',
-  target: expectedTarget,
-}));
-`,
-    );
-    const [command, args, env] = runtimeCommand(options.runtime, verification);
-    const { stdout } = await run(command, args, scratch, env);
-    if (options.runtime === "electron") {
-      await runElectronAsarSmoke(scratch, carrierManifest);
-    }
-    process.stdout.write(
-      `WASIX Node-API packaged ${options.runtime}/${options.packageManager} smoke passed: ${stdout.trim()}\n`,
-    );
-  } finally {
-    await rm(scratch, { recursive: true, force: true });
-  }
-}
-
-main().catch((error) => {
-  console.error(`smoke-packaged-addon: ${error instanceof Error ? error.message : String(error)}`);
-  process.exitCode = 1;
-});
diff --git a/src/sdks/js/ARCHITECTURE.md b/src/sdks/js/ARCHITECTURE.md
deleted file mode 100644
index 72521ca7d..000000000
--- a/src/sdks/js/ARCHITECTURE.md
+++ /dev/null
@@ -1,137 +0,0 @@
-# TypeScript SDK architecture
-
-The TypeScript SDK is a thin native binding with one public entrypoint. It keeps
-JavaScript ergonomics at the API boundary and delegates PostgreSQL lifecycle and
-physical backup to `liboliphaunt`.
-
-## Public shape
-
-The default `Oliphaunt` client exposes `open`, `openServer`, and static
-`restore`. `open` returns the direct/broker database interface. `openServer`
-returns a distinct handle with a required connection string and no backup
-or database-connection methods.
-
-Typed execute/query results, callback transactions, cancellation, buffered and
-callback-streamed raw protocol, and close are common where meaningful. Backup
-is one byte format and only belongs to direct/broker databases. Runtime modes,
-capability objects, archive formats, parsers, stream primitives, packaging
-reports, and resource profiles are internal or absent.
-
-## Adapter boundaries
-
-- Native direct uses the platform Node addon on Node/Bun and the Deno FFI
-  adapter on Deno.
-- Native broker owns one authenticated helper process per database. Helper or
-  IPC failure permanently fails that database handle; recovery is an explicit
-  close plus new open, never transparent session replacement or request replay.
-- Native server starts PostgreSQL, closes its private readiness probe before
-  publication, and exposes a connection string for caller-owned ORMs, drivers,
-  and tools.
-
-All three adapters implement the internal runtime binding. Its server adapter
-uses only open/connection-string/close/finalizer slots; required database slots
-reject internally and never appear on the public server facade. The Node addon and C ABI
-may have lower-level symbols for other consumers; the SDK does not mirror unused
-symbols into its own interface.
-
-The private close boundary returns a discriminated `closed`, `retryable`, or
-`terminal` outcome. Direct adapters may report retryable only when logical
-deactivation did not occur. Broker and server adapters cross a destructive
-cutoff before fallible process/filesystem cleanup and therefore classify those
-failures as terminal without inspecting error text.
-
-The public database contract is promise-based in every JavaScript runtime, and
-PostgreSQL open, query, backup, restore, and detach work runs through async native
-work (Node/Bun addon jobs or Deno `nonblocking` FFI). Loading the native module is
-the narrow exception: Node/Bun `require()` and Deno `dlopen()` are synchronous
-platform operations during first adapter resolution. They do not run a database
-operation or create an alternate synchronous database surface.
-
-Direct and broker databases have the same public methods. Server differs
-structurally instead of returning runtime-dependent failures: it exposes only
-`connectionString`, `closed`, `close`, and async disposal. External connections
-own SQL, transactions, raw protocol, cancellation, and backup. Standard
-PostgreSQL tools own server backup and logical import/export; applications
-provide those tools through their ordinary environment.
-
-## Lifecycle and concurrency
-
-Direct runtime admission prevents two active direct owners in one process.
-Broker supervision prevents duplicate roots and uses a separate cancellation
-endpoint so cancellation is not queued behind query output. The server handle
-does not control independent external connections.
-
-The database handle tracks close and active transaction state. A transaction
-pins the one SDK connection. Body failure rolls back; failed rollback poisons.
-COMMIT transport/protocol uncertainty poisons without a later ROLLBACK. An
-explicit PostgreSQL `ROLLBACK` command tag returned for COMMIT is the known-idle
-exception. Close waits for admitted operations. A pre-teardown direct failure
-may be retried; after success or a destructive broker/server failure, the one
-terminal close attempt is retained and later calls replay its exact outcome.
-The read-only `closed` state becomes true for either terminal result.
-
-Managed transaction handles expose structured SQL only. They reject ownership
-escape based on exact `CommandComplete` tags and the terminal `ReadyForQuery`
-frame before high-level parsing, then make the database close-only without a
-speculative SDK control command. Manual transaction lifecycle SQL and `AND
-CHAIN` are unsupported; `SAVEPOINT` and `ROLLBACK TO` remain supported.
-Closing stops ordinary session admission immediately, but keeps out-of-band
-cancel admission open while already-admitted work drains. Runtime teardown
-closes that cancel gate only after every admitted cancellation request settles.
-
-Raw-stream callbacks provide synchronous backpressure. While a callback runs,
-same-handle database work, transaction work, backup, close, and nested streams
-are rejected at admission rather than silently queued. Out-of-band `cancel()`
-remains available.
-
-Explicit close unregisters forgotten-handle cleanup before releasing the
-JavaScript direct owner. Node/Bun register the public object with a
-`FinalizationRegistry` whose held record contains an opaque, exact-generation
-addon token. The registry only releases the matching JavaScript admission lease
-if the addon safely marks that generation for recovery by the next asynchronous
-open. Deno registers the public database object with a `FinalizationRegistry`
-whose held record contains only the logical generation and an idempotent ownership-release
-callback, never the object or opaque pointer. The finalizer only starts a
-`nonblocking` generation-guarded terminal FFI close and swallows its unobservable
-outcome. This makes stale cleanup harmless without running PostgreSQL teardown
-on the JavaScript finalizer job. Broker and server registries likewise hold only
-an exact private runtime handle and private lease generation, never the public
-facade or its release callback. Their finalizers schedule asynchronous teardown;
-explicitly unregistered and superseded generations are no-ops. Registration is
-the last step of facade publication: if it throws, the opened handle is retired,
-any partial registration is unregistered, and the exact JavaScript ownership
-lease is released before `open()` rejects. None of these guards make garbage
-collection a supported replacement for explicit close.
-
-## Storage
-
-Storage resolution maps temporary or caller-owned roots to `pgdata/`. Root
-preparation and restore validate before mutation. Initialization creates PGDATA
-first and publishes the exact shared `.oliphaunt.json` descriptor last. Symlink
-roots and structural directories are rejected.
-
-Direct and broker share the native C sibling lease. The server provider prevents
-duplicate server ownership separately. Neither mechanism coordinates across
-providers, so simultaneous direct/broker/server mutation of one root is
-application error. The descriptor records the root schema, family/format pair,
-PGDATA directory name, and PostgreSQL major; it does not record JavaScript or
-Node ownership and does not reject another valid runtime family merely because
-cross-family reuse is undocumented.
-
-Direct/broker backup bytes contain the PostgreSQL physical initialization
-payload. Restore stages those bytes in a sibling directory, validates PGDATA,
-and creates the outer receiving identity. Existing nonempty destinations are
-rejected. No replacement mode exists.
-
-## Packaging
-
-Optional platform packages carry the native library/runtime, Node addon, broker
-helper, and ICU data. Resolution validates package versions and target identity
-before loading. Split native client-tool packages are independent products, not
-dependencies or locators of `@oliphaunt/ts`. Development path overrides are
-normalized internally but do not create alternate public runtime profiles.
-
-Extension selection uses the generated exact-name PostgreSQL 18 catalog. The
-adapter resolves only selected artifacts and required preload libraries. Package
-metadata, resource manifests, and materialization details remain outside the
-public SDK contract.
diff --git a/src/sdks/js/CHANGELOG.md b/src/sdks/js/CHANGELOG.md
deleted file mode 100644
index d991df1d0..000000000
--- a/src/sdks/js/CHANGELOG.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# Changelog
-
-## Unreleased
-
-- Fail broker database objects permanently after helper or IPC failure. Close
-  and explicitly open a new object for PostgreSQL WAL recovery; the SDK never
-  substitutes a new session or replays uncertain work under the old object.
-
-## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-js-v0.1.1...oliphaunt-js-v0.2.0) (2026-09-05)
-
-
-### ⚠ BREAKING CHANGES
-
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
-
-### Features
-
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))
-* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
-
-
-### Performance Improvements
-
-* **js:** streamline exec response handling ([#158](https://github.com/f0rr0/oliphaunt/issues/158)) ([5eaf05b](https://github.com/f0rr0/oliphaunt/commit/5eaf05b8a8d21bd974b9fcb6d618103be5689151))
-
-
-### Code Refactoring
-
-* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
-* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
-
-## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-js-v0.1.0...oliphaunt-js-v0.1.1) (2026-08-08)
-
-
-### Bug Fixes
-
-* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))
-
-## 0.1.0 (2026-07-28)
-
-
-### Features
-
-* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/sdks/js/README.md b/src/sdks/js/README.md
deleted file mode 100644
index b273ff7a9..000000000
--- a/src/sdks/js/README.md
+++ /dev/null
@@ -1,213 +0,0 @@
-# Oliphaunt TypeScript SDK
-
-`@oliphaunt/ts` embeds PostgreSQL 18 on Node.js, Bun, and Deno through the native
-`liboliphaunt` runtime. It is the native TypeScript SDK; browser and WASIX hosts
-use the separate WASIX TypeScript package.
-
-## Open and query
-
-```ts
-import Oliphaunt from '@oliphaunt/ts';
-
-const db = await Oliphaunt.open({
-  storage: { kind: 'directory', path: '.oliphaunt' },
-  startupGUCs: { application_name: 'my-app' },
-});
-
-await db.execute('CREATE TABLE events(value text)');
-await db.execute('INSERT INTO events(value) VALUES ($1)', ['ready']);
-const result = await db.query('SELECT value FROM events');
-console.log(result.rows[0]?.value);
-await db.close();
-```
-
-Direct topology is the default. Set `topology: 'broker'` to place the embedded
-backend in a helper process while keeping the same database API. If that helper
-fails, the database object fails permanently; close it and explicitly open a new
-object on persistent storage for PostgreSQL WAL recovery. The SDK never swaps a
-new session under an existing object or replays uncertain work.
-
-The database API is promise-based on Node.js, Bun, and Deno. Native PostgreSQL
-work runs in addon jobs or Deno nonblocking FFI rather than on the JavaScript
-event loop. First adapter resolution still performs the platform's synchronous
-native-module load (`require()` on Node/Bun or `dlopen()` on Deno); that narrow
-startup step is not a synchronous database execution mode.
-
-The deliberate public vocabulary is:
-
-- `Oliphaunt.open(config)` for direct or broker databases.
-- `execute`, decoded `query`, byte-preserving `queryRaw`, ordered `exec`,
-  non-executing `describe`, callback `transaction`, `cancel`, and `close`.
-- `execProtocolRaw` as the buffered escape hatch for protocol flows the typed
-  helpers cannot represent.
-- `execProtocolRawStream` for callback delivery of raw backend protocol chunks,
-  including COPY responses, without buffering the complete response.
-- `backup()` returning the one physical backup format as `Uint8Array`.
-- `Oliphaunt.restore(destination, bytes)` for an absent or empty destination.
-- `Oliphaunt.openServer(config)` for the distinct local-server handle.
-
-`execute` asserts one command with no rows. `query` accepts command-only or
-row-producing SQL and defaults to decoded object rows; use `rowMode: 'array'`
-for positional rows or duplicate column names, `valueMode: 'text'` for
-text-format strings, or per-query OID decoders. Object mode rejects duplicate
-names rather than discarding a value. `queryRaw` retains ordered nullable bytes
-and complete field metadata. `exec` returns each simple-query statement in wire order, and
-`describe` returns resolved parameter OIDs and optional result fields without
-executing. All structured results preserve notices and command metadata.
-
-Safe scalar parameters are inferred inside one owned Parse/Describe/Bind
-operation. Use the exported `text`, `binary`, `typedNull`, `json`, and `array`
-helpers with `postgresOids` when the type must be deterministic, and immutable
-per-query encoders for extension OIDs. Unsupported or mismatched values fail
-instead of being guessed or stringified; `undefined` is never a SQL null.
-PostgreSQL errors are structured `PostgresError` instances with query notices.
-
-The read-only `closed` property becomes true whenever the owner is terminally
-retired, including after a broker/server teardown error that occurs past its
-destructive cutoff. Transactions pin the session and mirror query/raw query, execute, exec,
-and describe. One-shot `rollback()` closes the transaction and lets the callback
-return without committing. Failed rollback or COMMIT uncertainty poisons the
-database and never triggers a misleading second control command.
-
-When a callback throws, Oliphaunt waits for a successful automatic rollback and
-then rethrows the original value unchanged. If the callback and rollback both
-fail, the transaction rejects with an `AggregateError` whose `errors` are the
-callback failure followed by the rollback failure. If an earlier independent
-database or protocol failure has already poisoned or expired transaction
-ownership and the callback then throws a different value, an `AggregateError`
-preserves the callback failure followed by that database failure; the database
-is close-only. An ordinary PostgreSQL statement error that remains safely
-rollbackable uses the first rule and is not automatically aggregated.
-
-Raw protocol is intentionally database-only and absent from callback transaction
-handles. Inside a transaction callback, do not issue manual `BEGIN`, `START
-TRANSACTION`, `COMMIT`, `END`, `ABORT`, `PREPARE TRANSACTION`, or `AND CHAIN`;
-return/throw from the callback or call `rollback()` instead. `SAVEPOINT` and
-`ROLLBACK TO` remain ordinary supported SQL. `ROLLBACK AND CHAIN` is unsupported
-contract misuse and cannot be distinguished from `ROLLBACK TO` by PostgreSQL's
-wire tag and readiness status, so Oliphaunt rejects `ROLLBACK`/`ABORT ... AND
-CHAIN` before dispatch and still validates every actual protocol boundary. A
-proven ownership escape makes the database close-only and the SDK sends no
-follow-up `COMMIT` or `ROLLBACK`.
-
-Always `await db.close()` or use `await using` for deterministic lifecycle.
-Garbage collection is only a best-effort leak guard: on Node/Bun a
-`FinalizationRegistry` gives the addon an opaque exact-generation token and only
-releases JavaScript admission after the addon queues recovery for the next
-asynchronous open. Deno's registry enqueues nonblocking generation-guarded
-terminal cleanup. Broker and server registries retain only their exact private
-runtime handle plus a private lease generation; finalizers schedule
-asynchronous teardown and an unregistered or superseded generation is a no-op.
-A stale cleanup
-cannot close a newer logical lease, but finalizer timing and errors are not
-observable and an executed fallback spends the native database process
-lifetime. Explicit close remains the path that resets the logical session for
-reuse and reports failures.
-
-A direct logical-detach failure is retryable only while the native owner proves
-it remains active. Broker/server teardown failures are terminal: later work is
-rejected and every repeated `close()` observes the same original outcome.
-Raw-stream callbacks are synchronous, cannot reenter database or transaction
-work on the same handle, and may only use `cancel()` out of band. Once `close()`
-stops ordinary admission, `cancel()` remains available while previously
-admitted work drains; runtime teardown begins only after admitted cancellation
-requests settle. A thrown callback is returned unchanged only after the runtime
-confirms that it recovered the PostgreSQL protocol boundary. An execution,
-transport, or recovery failure is authoritative instead and poisons the
-session when its state is unknown.
-
-## Backup and restore
-
-```ts
-const source = await Oliphaunt.open({
-  storage: { kind: 'directory', path: '.oliphaunt-source' },
-});
-const bytes = await source.backup();
-await source.close();
-
-await Oliphaunt.restore('.oliphaunt-restored', bytes);
-```
-
-Backup bytes are a PostgreSQL physical initialization payload containing PGDATA
-and backup metadata. They do not contain the outer `.oliphaunt.json` descriptor.
-Restore stages and validates PGDATA, then creates the receiving root identity.
-There is no archive selector and no replace-existing option.
-
-## Local server
-
-```ts
-const server = await Oliphaunt.openServer({
-  storage: { kind: 'directory', path: '.oliphaunt-server' },
-  listen: { transport: 'tcp' },
-});
-console.log(server.connectionString);
-await server.close();
-```
-
-The server handle owns only the PostgreSQL process/listener lifecycle and exposes
-its `connectionString`, `closed`, and `close`. Connect an ORM, PostgreSQL driver,
-or tool with that URI; the resulting connections own their own queries,
-transactions, raw protocol, and cancellation. The server handle cannot cancel
-or otherwise control work on external clients. TCP is fixed to IPv4 loopback;
-omit `port` for automatic assignment. Unix hosts may
-instead pass `{ transport: 'unix', directory, port? }`, which uses
-`.s.PGSQL.` and never removes the caller's directory.
-
-Use `pg_basebackup` for a standard server physical backup. Plain `pg_dump` and
-non-interactive `psql` are available from the optional endpoint-oriented
-`@oliphaunt/tools` package. `@oliphaunt/ts` does not depend on or install client
-tools.
-
-```js
-import { pgDump, psql } from '@oliphaunt/tools';
-
-const sql = await pgDump(server.connectionString, {
-  args: ['--schema-only'],
-});
-await psql(server.connectionString, { script: sql });
-```
-
-Pass the server's `connectionString` to the standard PostgreSQL tool:
-
-```sh
-pg_basebackup --dbname "$CONNECTION_STRING" --pgdata ./server-backup --wal-method=stream
-```
-
-## Storage contract
-
-A persistent managed root contains:
-
-```text
-.oliphaunt.json
-pgdata/
-```
-
-The descriptor's exact five fields record its schema, engine family, PGDATA
-directory name, PostgreSQL major, and physical format. It is shared contract
-vocabulary, not a TypeScript or Node marker. Root validation occurs before
-mutation, rejects symlink structural directories, requires complete PostgreSQL
-18 PGDATA, and publishes the descriptor last.
-
-Direct and broker coordinate through the same native sibling-lock identity. The
-server provider prevents duplicate server ownership separately. These are
-provider-local lifecycle safeguards, not a public cross-provider lock protocol.
-Simultaneous direct/broker/server mutation of one root is application error.
-
-If server open reports an existing sibling owner directory, first confirm that
-no native server owns the root. Only then remove the exact reported directory;
-the SDK deliberately does not guess that an owner is stale.
-
-## Runtime and extensions
-
-Platform native runtime, Node addon, broker, and ICU packages are optional
-dependencies selected for the installed host. Explicit library, runtime, addon,
-broker, or server paths exist for packaging and development scenarios. Native
-client-tool packages remain separate products and are not SDK dependencies.
-
-Extensions are selected by exact PostgreSQL SQL name through `extensions`.
-Runtime artifact discovery remains internal. The package intentionally does not
-publish capability profiles, supported-mode introspection, package-size reports,
-generic streams, protocol parsers, or backup format helpers.
-
-The package has one public code entrypoint, `@oliphaunt/ts`, plus
-`@oliphaunt/ts/package.json` for package metadata.
diff --git a/src/sdks/js/moon.yml b/src/sdks/js/moon.yml
deleted file mode 100644
index 46e8078de..000000000
--- a/src/sdks/js/moon.yml
+++ /dev/null
@@ -1,117 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "oliphaunt-js"
-language: "typescript"
-layer: "library"
-stack: "backend"
-tags: ["sdk", "typescript", "node", "bun", "deno", "release-product"]
-dependsOn:
-  - id: "cluster-seed-contract"
-    scope: "development"
-  - id: "shared-test-fixtures"
-    scope: "development"
-  - "liboliphaunt-native"
-  - "oliphaunt-broker"
-  - "oliphaunt-node-direct"
-
-project:
-  title: "Oliphaunt TypeScript SDK"
-  description: "TypeScript SDK with native direct topology defaults for Node.js, Bun, and Deno."
-  owner: "oliphaunt"
-  release:
-    component: "oliphaunt-js"
-    packagePath: "src/sdks/js"
-
-owners:
-  defaultOwner: "@oliphaunt/sdk-js"
-  paths:
-    "**/*.ts": ["@oliphaunt/sdk-js"]
-    "tools/**": ["@oliphaunt/sdk-js"]
-
-fileGroups:
-  code:
-    - "**/*"
-    - "!**/*.md"
-    - "!moon.yml"
-    - "!release.toml"
-
-tasks:
-  compile:
-    tags: ["quality", "static"]
-    command: "pnpm run build"
-    deps:
-      - "shared-js-core:build"
-    inputs:
-      - project: "shared-js-core"
-        group: "sources"
-      - "@group(pnpm-workspace)"
-      - "@group(code)"
-    outputs:
-      - "lib/**/*"
-    options:
-      cache: true
-  typecheck:
-    tags: ["quality", "static"]
-    command: "pnpm run typecheck"
-    deps:
-      - "shared-js-core:build"
-    inputs:
-      - project: "shared-js-core"
-        group: "sources"
-      - "@group(pnpm-workspace)"
-      - "@group(code)"
-    options:
-      cache: true
-  unit:
-    tags: ["quality", "unit"]
-    command: "pnpm test"
-    deps:
-      - "shared-js-core:build"
-    inputs:
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - project: "cluster-seed-contract"
-        group: "contract"
-      - project: "shared-js-core"
-        group: "sources"
-      - "@group(pnpm-workspace)"
-      - "@group(code)"
-    options:
-      cache: true
-      runInCI: false
-  package:
-    tags: ["package"]
-    script: |
-      set -e
-      rm -rf target/liboliphaunt-sdk-check/oliphaunt-js/package-shape
-      mkdir -p target/liboliphaunt-sdk-check/oliphaunt-js/package-shape/src/sdks/js
-      rsync -a --exclude node_modules src/sdks/js/ target/liboliphaunt-sdk-check/oliphaunt-js/package-shape/src/sdks/js/
-      cp LICENSE THIRD_PARTY_NOTICES.md target/liboliphaunt-sdk-check/oliphaunt-js/package-shape/src/sdks/js/
-      node src/shared/js-core/tools/stage-package.mjs target/liboliphaunt-sdk-check/oliphaunt-js/package-shape/src/sdks/js src/shared/js-core
-    deps:
-      - "oliphaunt-js:compile"
-    inputs:
-      - "@group(legal-files)"
-      - project: "shared-js-core"
-        group: "sources"
-      - "@group(pnpm-workspace)"
-      - "/src/shared/js-core/tools/stage-package.mjs"
-      - "**/*"
-    outputs:
-      - "/target/liboliphaunt-sdk-check/oliphaunt-js/package-shape/src/sdks/js/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  qualify:
-    tags: ["release", "package"]
-    command: "true"
-    deps:
-      - "oliphaunt-js:compile"
-      - "oliphaunt-js:typecheck"
-      - "oliphaunt-js:unit"
-      - "oliphaunt-js:package"
-    inputs: []
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-      runInCI: false
diff --git a/src/sdks/js/package.json b/src/sdks/js/package.json
deleted file mode 100644
index 33bc208fa..000000000
--- a/src/sdks/js/package.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
-  "name": "@oliphaunt/ts",
-  "version": "0.2.0",
-  "description": "TypeScript SDK for Oliphaunt on Node.js, Bun, and Deno.",
-  "license": "MIT",
-  "type": "module",
-  "repository": {
-    "type": "git",
-    "url": "git+https://github.com/f0rr0/oliphaunt.git",
-    "directory": "src/sdks/js"
-  },
-  "bugs": {
-    "url": "https://github.com/f0rr0/oliphaunt/issues"
-  },
-  "homepage": "https://oliphaunt.dev",
-  "oliphaunt": {
-    "liboliphauntVersion": "0.2.0",
-    "icuPackage": "@oliphaunt/icu",
-    "icuVersion": "0.2.0",
-    "brokerVersion": "0.2.0",
-    "nodeDirectAddonVersion": "0.2.0",
-    "nodeDirectAddon": "oliphaunt-node-direct",
-    "brokerHelper": "oliphaunt-broker"
-  },
-  "dependencies": {
-    "@oliphaunt/js-core": "workspace:*"
-  },
-  "bundledDependencies": [
-    "@oliphaunt/js-core"
-  ],
-  "optionalDependencies": {
-    "@oliphaunt/broker-darwin-arm64": "workspace:*",
-    "@oliphaunt/broker-linux-arm64-gnu": "workspace:*",
-    "@oliphaunt/broker-linux-x64-gnu": "workspace:*",
-    "@oliphaunt/broker-win32-x64-msvc": "workspace:*",
-    "@oliphaunt/liboliphaunt-darwin-arm64": "workspace:*",
-    "@oliphaunt/liboliphaunt-linux-arm64-gnu": "workspace:*",
-    "@oliphaunt/liboliphaunt-linux-x64-gnu": "workspace:*",
-    "@oliphaunt/liboliphaunt-win32-x64-msvc": "workspace:*",
-    "@oliphaunt/node-direct-darwin-arm64": "workspace:*",
-    "@oliphaunt/node-direct-linux-arm64-gnu": "workspace:*",
-    "@oliphaunt/node-direct-linux-x64-gnu": "workspace:*",
-    "@oliphaunt/node-direct-win32-x64-msvc": "workspace:*"
-  },
-  "publishConfig": {
-    "access": "public",
-    "provenance": true
-  },
-  "exports": {
-    ".": {
-      "types": "./lib/index.d.ts",
-      "default": "./lib/index.js"
-    },
-    "./package.json": {
-      "default": "./package.json"
-    }
-  },
-  "main": "lib/index.js",
-  "module": "lib/index.js",
-  "types": "lib/index.d.ts",
-  "files": [
-    "lib",
-    "src",
-    "README.md",
-    "ARCHITECTURE.md",
-    "CHANGELOG.md",
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-    "!src/__tests__"
-  ],
-  "scripts": {
-    "build": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
-    "docs:api": "typedoc --options typedoc.json",
-    "test": "vitest run --pool=forks --fileParallelism=false --dir=src/__tests__",
-    "typecheck": "tsc --noEmit",
-    "clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\""
-  },
-  "engines": {
-    "node": ">=22.13 <25"
-  },
-  "devDependencies": {
-    "@types/node": "^24.10.1",
-    "@vitest/coverage-v8": "catalog:",
-    "tsx": "catalog:",
-    "typedoc": "catalog:",
-    "typescript": "catalog:",
-    "vitest": "catalog:"
-  }
-}
diff --git a/src/sdks/js/release.toml b/src/sdks/js/release.toml
deleted file mode 100644
index 816a5d428..000000000
--- a/src/sdks/js/release.toml
+++ /dev/null
@@ -1,30 +0,0 @@
-id = "oliphaunt-js"
-owner = "@oliphaunt/sdk-js"
-kind = "sdk"
-publish_targets = ["npm"]
-registry_packages = ["npm:@oliphaunt/ts"]
-release_artifacts = [
-  "npm-package",
-  "node-bun-deno-direct",
-  "rust-broker-helper-compatibility",
-]
-
-[compatibility_versions.oliphaunt-js-liboliphaunt]
-source_product = "liboliphaunt-native"
-path = "src/sdks/js/package.json"
-parser = "json:oliphaunt.liboliphauntVersion"
-
-[compatibility_versions.oliphaunt-js-icu]
-source_product = "liboliphaunt-native"
-path = "src/sdks/js/package.json"
-parser = "json:oliphaunt.icuVersion"
-
-[compatibility_versions.oliphaunt-js-broker]
-source_product = "oliphaunt-broker"
-path = "src/sdks/js/package.json"
-parser = "json:oliphaunt.brokerVersion"
-
-[compatibility_versions.oliphaunt-js-node-direct-runtime]
-source_product = "oliphaunt-node-direct"
-path = "src/sdks/js/package.json"
-parser = "json:oliphaunt.nodeDirectAddonVersion"
diff --git a/src/sdks/js/src/__tests__/broker-frames.test.ts b/src/sdks/js/src/__tests__/broker-frames.test.ts
deleted file mode 100644
index 07ee1ba26..000000000
--- a/src/sdks/js/src/__tests__/broker-frames.test.ts
+++ /dev/null
@@ -1,169 +0,0 @@
-import assert from 'node:assert/strict';
-import { test } from 'vitest';
-
-import {
-  decodeBrokerRequest,
-  decodeBrokerResponse,
-  encodeBrokerRequest,
-  encodeBrokerResponse,
-  readBrokerRequest,
-  readBrokerResponse,
-  writeBrokerRequest,
-  writeBrokerResponse,
-} from '../runtime/broker-frames.js';
-import { MemoryDuplexStream } from '../runtime/byte-stream.js';
-import { resolveBrokerStreamCompletion } from '../runtime/broker.js';
-
-async function main(): Promise {
-  await requestFramesRoundTrip();
-  await responseFramesRoundTrip();
-  rejectsMalformedFrames();
-  streamCompletionUsesRecoveryAwareErrorPrecedence();
-  await streamHelpersUseBinaryFrames();
-}
-
-async function requestFramesRoundTrip(): Promise {
-  assert.deepEqual(decodeBrokerRequest(6, new TextEncoder().encode('secret')), {
-    kind: 'authenticate',
-    token: 'secret',
-  });
-  assert.deepEqual(decodeBrokerRequest(1, new Uint8Array([1, 2])), {
-    kind: 'execProtocol',
-    bytes: new Uint8Array([1, 2]),
-  });
-  assert.deepEqual(decodeBrokerRequest(4, new Uint8Array([3, 4])), {
-    kind: 'execProtocolStream',
-    bytes: new Uint8Array([3, 4]),
-  });
-  assert.deepEqual(decodeBrokerRequest(8, new TextEncoder().encode('SELECT 1')), {
-    kind: 'execSimpleQuery',
-    sql: 'SELECT 1',
-  });
-  assert.deepEqual(decodeBrokerRequest(3, new Uint8Array()), { kind: 'close' });
-  assert.deepEqual(decodeBrokerRequest(5, new Uint8Array()), {
-    kind: 'backup',
-  });
-  assert.deepEqual(decodeBrokerRequest(7, new Uint8Array()), {
-    kind: 'cancel',
-  });
-}
-
-async function responseFramesRoundTrip(): Promise {
-  const ok = encodeBrokerResponse({ kind: 'ok', bytes: new Uint8Array([9]) });
-  assert.deepEqual(await readBrokerResponse(new MemoryDuplexStream([ok])), {
-    kind: 'ok',
-    bytes: new Uint8Array([9]),
-  });
-
-  const error = encodeBrokerResponse({ kind: 'error', message: 'boom' });
-  assert.deepEqual(await readBrokerResponse(new MemoryDuplexStream([error])), {
-    kind: 'error',
-    message: 'boom',
-  });
-
-  const chunk = encodeBrokerResponse({ kind: 'chunk', bytes: new Uint8Array([7, 8]) });
-  assert.deepEqual(await readBrokerResponse(new MemoryDuplexStream([chunk])), {
-    kind: 'chunk',
-    bytes: new Uint8Array([7, 8]),
-  });
-
-  const callbackAborted = encodeBrokerResponse({
-    kind: 'streamCallbackAborted',
-    message: 'callback rejected; stream recovered to ReadyForQuery',
-  });
-  assert.deepEqual(await readBrokerResponse(new MemoryDuplexStream([callbackAborted])), {
-    kind: 'streamCallbackAborted',
-    message: 'callback rejected; stream recovered to ReadyForQuery',
-  });
-}
-
-function rejectsMalformedFrames(): void {
-  assert.throws(() => decodeBrokerRequest(999, new Uint8Array()), /unknown broker request/);
-  assert.throws(() => decodeBrokerResponse(999, new Uint8Array()), /unknown broker response/);
-  assert.throws(() => decodeBrokerRequest(5, new Uint8Array([99])), /unexpectedly had a payload/);
-  assert.throws(
-    () => decodeBrokerResponse(104, new Uint8Array([0xff])),
-    /stream callback-aborted frame is not UTF-8/,
-  );
-}
-
-function streamCompletionUsesRecoveryAwareErrorPrecedence(): void {
-  const callbackError = new Error('client callback failed');
-  assert.throws(
-    () =>
-      resolveBrokerStreamCompletion(
-        { kind: 'streamCallbackAborted', message: 'stream recovered' },
-        true,
-        callbackError,
-      ),
-    (error) => error === callbackError,
-  );
-  assert.throws(
-    () =>
-      resolveBrokerStreamCompletion(
-        { kind: 'error', message: 'transport recovery failed' },
-        true,
-        callbackError,
-      ),
-    (error) => error instanceof Error && error.message === 'transport recovery failed',
-  );
-  assert.throws(
-    () =>
-      resolveBrokerStreamCompletion(
-        { kind: 'streamCallbackAborted', message: 'stream recovered' },
-        false,
-        undefined,
-      ),
-    /without a stored client callback error: stream recovered/,
-  );
-  assert.throws(
-    () =>
-      resolveBrokerStreamCompletion({ kind: 'ok', bytes: new Uint8Array() }, true, callbackError),
-    (error) => error === callbackError,
-  );
-  assert.doesNotThrow(() =>
-    resolveBrokerStreamCompletion({ kind: 'ok', bytes: new Uint8Array() }, false, undefined),
-  );
-}
-
-async function streamHelpersUseBinaryFrames(): Promise {
-  const requestStream = new MemoryDuplexStream();
-  await writeBrokerRequest(requestStream, {
-    kind: 'execProtocol',
-    bytes: new Uint8Array([0x51, 0, 0, 0, 4]),
-  });
-  assert.deepEqual(await readBrokerRequest(new MemoryDuplexStream(requestStream.output)), {
-    kind: 'execProtocol',
-    bytes: new Uint8Array([0x51, 0, 0, 0, 4]),
-  });
-
-  const streamingRequest = new MemoryDuplexStream();
-  await writeBrokerRequest(streamingRequest, {
-    kind: 'execProtocolStream',
-    bytes: new Uint8Array([0x51]),
-  });
-  assert.deepEqual(await readBrokerRequest(new MemoryDuplexStream(streamingRequest.output)), {
-    kind: 'execProtocolStream',
-    bytes: new Uint8Array([0x51]),
-  });
-
-  const responseStream = new MemoryDuplexStream();
-  await writeBrokerResponse(responseStream, {
-    kind: 'ok',
-    bytes: new Uint8Array([0x5a]),
-  });
-  assert.deepEqual(await readBrokerResponse(new MemoryDuplexStream(responseStream.output)), {
-    kind: 'ok',
-    bytes: new Uint8Array([0x5a]),
-  });
-
-  const raw = encodeBrokerRequest({ kind: 'backup' });
-  assert.equal(raw[0], 0x50);
-  assert.equal(raw[1], 0x47);
-  assert.equal(raw[2], 0x4f);
-  assert.equal(raw[3], 0x42);
-}
-
-test('broker frames', async () => {
-  await main();
-});
diff --git a/src/sdks/js/src/__tests__/client.test.ts b/src/sdks/js/src/__tests__/client.test.ts
deleted file mode 100644
index aec45e84b..000000000
--- a/src/sdks/js/src/__tests__/client.test.ts
+++ /dev/null
@@ -1,1548 +0,0 @@
-import assert from 'node:assert/strict';
-import { mkdtemp, rm, stat } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
-import { test } from 'vitest';
-
-import { createOliphauntClient } from '../client.js';
-import type {
-  NativeBinding,
-  NativeBindingOptions,
-  NativeHandle,
-  NativeOpenConfig,
-  NativeRestoreOptions,
-} from '../native/types.js';
-import type { CommandResult } from '../query.js';
-import type {
-  OliphauntDatabase,
-  OliphauntTransaction,
-  OpenConfig,
-  ServerOpenConfig,
-} from '../types.js';
-import type { RuntimeBinding } from '../runtime/types.js';
-
-// OLIPHAUNT_DOCS_SNIPPET typescript-quickstart
-test('exposes the minimal database lifecycle and byte backup contract', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-client-'));
-  const binding = new FakeBinding();
-  const bindingOptions: NativeBindingOptions[] = [];
-  const client = createOliphauntClient((options = {}) => {
-    bindingOptions.push(options);
-    return binding;
-  });
-  try {
-    const db = await client.open({
-      storage: { kind: 'directory', path: root },
-      startupGUCs: { work_mem: '16MB' },
-      username: 'app',
-      database: 'appdb',
-    });
-    assert.deepEqual(binding.openCalls[0], {
-      pgdata: join(root, 'pgdata'),
-      runtimeDirectory: undefined,
-      username: 'app',
-      database: 'appdb',
-      extensions: [],
-      startupArgs: ['-c', 'work_mem=16MB'],
-    });
-    assert.deepEqual(await db.execute('UPDATE things SET value = 1'), {
-      commandTag: 'UPDATE 3',
-      rowCount: 3,
-      notices: [],
-    });
-    assert.equal(binding.requestTags.at(-1), 'P');
-    const result = await db.query('SELECT value FROM things');
-    assert.equal(binding.requestTags.at(-1), 'P');
-    assert.equal(result.commandTag, 'SELECT 1');
-    assert.equal(result.rowCount, 1);
-    assert.deepEqual(result.rows, [{ value: 'ok' }]);
-    const streamed: Uint8Array[] = [];
-    await db.execProtocolRawStream(new Uint8Array([0x51]), (chunk) => {
-      streamed.push(chunk);
-    });
-    assert.equal(streamed.length, 1);
-    assert.deepEqual(await db.backup(), new Uint8Array([1, 2, 3]));
-    await db.execute('CHECKPOINT');
-    await db.cancel();
-    await db.close();
-    assert.equal(binding.cancelCalls, 1);
-    assert.equal(binding.detachCalls, 1);
-    await assert.rejects(() => db.execute('SELECT 1'), /closed/);
-
-    await client.restore(join(root, 'restored'), new Uint8Array([7, 8]), {
-      libraryPath: '/opt/oliphaunt/liboliphaunt.so',
-    });
-    assert.deepEqual(binding.restoreCalls, [
-      { destination: join(root, 'restored'), bytes: new Uint8Array([7, 8]) },
-    ]);
-    assert.deepEqual(bindingOptions, [
-      { libraryPath: undefined },
-      { libraryPath: '/opt/oliphaunt/liboliphaunt.so' },
-    ]);
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('snapshots open configuration before asynchronous storage work', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-open-snapshot-'));
-  const direct = new FakeBinding();
-  const broker = new FakeBinding();
-  const brokerRuntime = broker as unknown as RuntimeBinding;
-  brokerRuntime.close = async (handle) => {
-    await broker.detach(handle);
-    return { state: 'closed' };
-  };
-  const startupGUCs: Record = { work_mem: '8MB' };
-  const extensions: string[] = [];
-  const config: OpenConfig = {
-    topology: 'broker',
-    storage: { kind: 'directory', path: root },
-    startupGUCs,
-    username: 'before',
-    database: 'before',
-    extensions,
-  };
-  const client = createOliphauntClient(() => direct, { broker: brokerRuntime });
-
-  try {
-    const opening = client.open(config);
-    config.topology = 'direct';
-    config.username = 'after';
-    config.database = 'after';
-    startupGUCs.work_mem = '64MB';
-    extensions.push('vector');
-
-    const database = await opening;
-    assert.equal(direct.openCalls.length, 0);
-    assert.equal(broker.openCalls.length, 1);
-    assert.deepEqual(broker.openCalls[0], {
-      topology: 'broker',
-      instanceDirectory: root,
-      pgdata: join(root, 'pgdata'),
-      temporaryDirectory: false,
-      startupArgs: ['-c', 'work_mem=8MB'],
-      username: 'before',
-      database: 'before',
-      extensions: [],
-      libraryPath: undefined,
-      runtimeDirectory: undefined,
-      brokerExecutable: undefined,
-      serverExecutable: undefined,
-      serverListen: undefined,
-    });
-    await database.close();
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('rejects an unknown current topology before materializing storage', async () => {
-  const scratch = await mkdtemp(join(tmpdir(), 'oliphaunt-js-invalid-topology-'));
-  const instanceDirectory = join(scratch, 'must-not-exist');
-  const binding = new FakeBinding();
-  const client = createOliphauntClient(() => binding);
-
-  try {
-    await assert.rejects(
-      client.open({
-        topology: 'worker',
-        storage: { kind: 'directory', path: instanceDirectory },
-      } as unknown as OpenConfig),
-      /topology must be "direct" or "broker"/,
-    );
-    assert.equal(binding.openCalls.length, 0);
-    await assert.rejects(stat(instanceDirectory), { code: 'ENOENT' });
-  } finally {
-    await rm(scratch, { recursive: true, force: true });
-  }
-});
-
-test('rejects storage-owned startup GUCs before materializing storage', async () => {
-  const scratch = await mkdtemp(join(tmpdir(), 'oliphaunt-js-owned-guc-'));
-  const instanceDirectory = join(scratch, 'must-not-exist');
-  const binding = new FakeBinding();
-  const client = createOliphauntClient(() => binding);
-
-  try {
-    await assert.rejects(
-      client.open({
-        storage: { kind: 'directory', path: instanceDirectory },
-        startupGUCs: { CONFIG_FILE: '/tmp/redirect.conf' },
-      }),
-      /Oliphaunt owns PostgreSQL startup GUC 'config_file'/,
-    );
-    assert.equal(binding.openCalls.length, 0);
-    await assert.rejects(stat(instanceDirectory), { code: 'ENOENT' });
-  } finally {
-    await rm(scratch, { recursive: true, force: true });
-  }
-});
-
-test('snapshots server storage and nested configuration before asynchronous work', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-server-snapshot-'));
-  const movedRoot = join(root, 'mutated');
-  const server = new FakeBinding();
-  const serverRuntime = server as unknown as RuntimeBinding;
-  serverRuntime.close = async (handle) => {
-    await server.detach(handle);
-    return { state: 'closed' };
-  };
-  serverRuntime.connectionString = () => 'postgresql://postgres@127.0.0.1:15432/postgres';
-  const storage = { kind: 'directory' as const, path: root };
-  const listen = { transport: 'tcp' as const, port: 15432 };
-  const startupGUCs: Record = { work_mem: '8MB' };
-  const extensions: string[] = [];
-  const config: ServerOpenConfig = { storage, listen, startupGUCs, extensions };
-  const client = createOliphauntClient(() => new FakeBinding(), { server: serverRuntime });
-
-  try {
-    const opening = client.openServer(config);
-    storage.path = movedRoot;
-    listen.port = 25432;
-    startupGUCs.work_mem = '64MB';
-    extensions.push('vector');
-
-    const database = await opening;
-    assert.equal(database.connectionString, 'postgresql://postgres@127.0.0.1:15432/postgres');
-    for (const operation of [
-      'execute',
-      'query',
-      'queryRaw',
-      'exec',
-      'describe',
-      'execProtocolRaw',
-      'execProtocolRawStream',
-      'backup',
-      'cancel',
-      'transaction',
-    ]) {
-      assert.equal(operation in database, false, `${operation} must not leak from server facade`);
-    }
-    assert.equal(server.openCalls.length, 1);
-    assert.deepEqual(server.openCalls[0], {
-      topology: 'server',
-      instanceDirectory: root,
-      pgdata: join(root, 'pgdata'),
-      temporaryDirectory: false,
-      startupArgs: ['-c', 'work_mem=8MB'],
-      username: 'postgres',
-      database: 'postgres',
-      extensions: [],
-      libraryPath: undefined,
-      runtimeDirectory: undefined,
-      brokerExecutable: undefined,
-      serverExecutable: undefined,
-      serverListen: { transport: 'tcp', port: 15432 },
-    });
-    await database.close();
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('server open preserves both a missing endpoint and handle cleanup failure', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-server-open-failure-'));
-  const binding = new FakeBinding();
-  const cleanupFailure = new Error('server handle cleanup failed');
-  let closeCalls = 0;
-  const runtime = binding as unknown as RuntimeBinding;
-  runtime.close = async () => {
-    closeCalls += 1;
-    return { state: 'terminal', error: cleanupFailure };
-  };
-  const client = createOliphauntClient(() => new FakeBinding(), { server: runtime });
-
-  try {
-    const failure = await client
-      .openServer({ storage: { kind: 'directory', path: root } })
-      .catch((error: unknown) => error);
-    assert.ok(failure instanceof AggregateError);
-    assert.equal(failure.errors[0]?.message, 'native server did not expose its connection string');
-    assert.equal(failure.errors[1], cleanupFailure);
-    assert.equal(closeCalls, 1);
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('copies restore bytes before asynchronous binding resolution', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-restore-snapshot-'));
-  const binding = new FakeBinding();
-  const releaseBinding = deferred();
-  const client = createOliphauntClient(async () => {
-    await releaseBinding.promise;
-    return binding;
-  });
-  const backup = new Uint8Array([7, 8]);
-
-  try {
-    const restoring = client.restore(join(root, 'restored'), backup);
-    backup.fill(0);
-    releaseBinding.resolve();
-    await restoring;
-    assert.deepEqual(binding.restoreCalls, [
-      { destination: join(root, 'restored'), bytes: new Uint8Array([7, 8]) },
-    ]);
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('transactions commit, roll back body failures, and never roll back a failed commit', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-transaction-'));
-  try {
-    const successful = new FakeBinding();
-    const db = await createOliphauntClient(() => successful).open({
-      storage: { kind: 'directory', path: join(root, 'success') },
-    });
-    const value = await db.transaction(async (transaction) => {
-      await transaction.execute('UPDATE things SET value = 2');
-      return 42;
-    });
-    assert.equal(value, 42);
-    assert.deepEqual(successful.sqlCalls.slice(-3), [
-      'BEGIN',
-      'UPDATE things SET value = 2',
-      'COMMIT',
-    ]);
-    await db.close();
-
-    const bodyFailure = new FakeBinding();
-    const rollingBack = await createOliphauntClient(() => bodyFailure).open({
-      storage: { kind: 'directory', path: join(root, 'rollback') },
-    });
-    await assert.rejects(
-      () =>
-        rollingBack.transaction(() => {
-          throw new Error('body failed');
-        }),
-      /body failed/,
-    );
-    assert.deepEqual(bodyFailure.sqlCalls.slice(-2), ['BEGIN', 'ROLLBACK']);
-    await rollingBack.close();
-
-    const commitFailure = new FakeBinding();
-    commitFailure.failSql = 'COMMIT';
-    const uncertain = await createOliphauntClient(() => commitFailure).open({
-      storage: { kind: 'directory', path: join(root, 'commit') },
-    });
-    await assert.rejects(() => uncertain.transaction(() => 'done'), /commit failed/);
-    assert.deepEqual(commitFailure.sqlCalls.slice(-2), ['BEGIN', 'COMMIT']);
-    assert.equal(commitFailure.sqlCalls.includes('ROLLBACK'), false);
-    await assert.rejects(() => uncertain.execute('SELECT 1'), /state is unknown/);
-    await uncertain.close();
-
-    const poisonedCallback = new FakeBinding();
-    poisonedCallback.failSql = 'UPDATE transport_unknown';
-    const poisonedCallbackDb = await createOliphauntClient(() => poisonedCallback).open({
-      storage: { kind: 'directory', path: join(root, 'poisoned-callback') },
-    });
-    const businessFailure = new Error('business callback failed');
-    let databaseFailure: unknown;
-    const combinedFailure = await poisonedCallbackDb
-      .transaction(async (transaction) => {
-        try {
-          await transaction.execute('UPDATE transport_unknown');
-        } catch (error) {
-          databaseFailure = error;
-        }
-        throw businessFailure;
-      })
-      .catch((error: unknown) => error);
-    assert.ok(combinedFailure instanceof AggregateError);
-    assert.deepEqual(combinedFailure.errors, [businessFailure, databaseFailure]);
-    assert.match(combinedFailure.message, /independent database failure/);
-    assert.deepEqual(poisonedCallback.sqlCalls.slice(-2), ['BEGIN', 'UPDATE transport_unknown']);
-    const poisonedRequestCount = poisonedCallback.requests.length;
-    await assert.rejects(() => poisonedCallbackDb.execute('SELECT 1'), /state is unknown/);
-    assert.equal(poisonedCallback.requests.length, poisonedRequestCount);
-    await poisonedCallbackDb.close();
-
-    const malformedCommit = new FakeBinding();
-    malformedCommit.responseForSql.set('COMMIT', Uint8Array.from(backendMessage(0x5a, [0x49])));
-    const malformed = await createOliphauntClient(() => malformedCommit).open({
-      storage: { kind: 'directory', path: join(root, 'malformed-commit') },
-    });
-    await assert.rejects(
-      () => malformed.transaction(() => 'done'),
-      /omitted CommandComplete or EmptyQueryResponse/,
-    );
-    assert.deepEqual(malformedCommit.sqlCalls.slice(-2), ['BEGIN', 'COMMIT']);
-    assert.equal(malformedCommit.sqlCalls.includes('ROLLBACK'), false);
-    await assert.rejects(() => malformed.execute('SELECT 1'), /state is unknown/);
-    await malformed.close();
-
-    const rollbackFailure = new FakeBinding();
-    rollbackFailure.failSql = 'ROLLBACK';
-    const rollbackUncertain = await createOliphauntClient(() => rollbackFailure).open({
-      storage: { kind: 'directory', path: join(root, 'rollback-failure') },
-    });
-    const bodyError = new Error('body and rollback failed');
-    const aggregate = await rollbackUncertain
-      .transaction(() => {
-        throw bodyError;
-      })
-      .catch((error: unknown) => error);
-    assert.ok(aggregate instanceof AggregateError);
-    assert.equal(aggregate.errors[0], bodyError);
-    assert.match(String(aggregate.errors[1]), /commit failed/);
-    assert.deepEqual(rollbackFailure.sqlCalls.slice(-2), ['BEGIN', 'ROLLBACK']);
-    await assert.rejects(() => rollbackUncertain.execute('SELECT 1'), /state is unknown/);
-    await rollbackUncertain.close();
-
-    const aborted = new FakeBinding();
-    aborted.responseForSql.set(
-      'UPDATE rejected',
-      Uint8Array.from([
-        ...backendMessage(0x45, diagnostic('ERROR', 'XX000', 'queued operation failed')),
-        ...backendMessage(0x5a, [0x45]),
-      ]),
-    );
-    aborted.tagForSql.set('COMMIT', 'ROLLBACK');
-    const abortedDb = await createOliphauntClient(() => aborted).open({
-      storage: { kind: 'directory', path: join(root, 'aborted-transaction') },
-    });
-    let ignored: Promise | undefined;
-    const originalFailure = await abortedDb
-      .transaction((transaction) => {
-        ignored = transaction.execute('UPDATE rejected');
-        void ignored.catch(() => undefined);
-        return 'done';
-      })
-      .catch((error: unknown) => error);
-    assert.equal((originalFailure as { sqlstate?: string }).sqlstate, 'XX000');
-    assert.equal((originalFailure as Error).message, 'queued operation failed');
-    assert.ok(ignored);
-    await assert.rejects(ignored, (error: unknown) => error === originalFailure);
-    assert.deepEqual(aborted.sqlCalls.slice(-3), ['BEGIN', 'UPDATE rejected', 'COMMIT']);
-    await abortedDb.close();
-
-    const postgresRollback = new FakeBinding();
-    postgresRollback.tagForSql.set('COMMIT', 'ROLLBACK');
-    const idle = await createOliphauntClient(() => postgresRollback).open({
-      storage: { kind: 'directory', path: join(root, 'postgres-rollback') },
-    });
-    await assert.rejects(() => idle.transaction(() => 'done'), /expected COMMIT, got ROLLBACK/);
-    assert.deepEqual(await idle.execute('UPDATE things SET value = 3'), {
-      commandTag: 'UPDATE 3',
-      rowCount: 3,
-      notices: [],
-    });
-    await idle.close();
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('transaction Promise methods never leak admission or planning failures synchronously', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-transaction-promises-'));
-  const binding = new FakeBinding();
-  const db = await createOliphauntClient(() => binding).open({
-    storage: { kind: 'directory', path: root },
-  });
-  let expired!: OliphauntTransaction;
-  try {
-    await db.transaction(async (transaction) => {
-      expired = transaction;
-      for (const call of [
-        () => transaction.execute('SELECT\0invalid'),
-        () => transaction.query('SELECT\0invalid'),
-        () => transaction.queryRaw('SELECT\0invalid'),
-        () => transaction.exec('SELECT\0invalid'),
-        () => transaction.describe('SELECT\0invalid'),
-      ]) {
-        assert.match(String(await catchPromiseWithoutSynchronousThrow(call)), /NUL bytes/);
-      }
-      for (const call of [
-        () => transaction.execute('ROLLBACK AND CHAIN'),
-        () => transaction.query('ABORT WORK AND CHAIN'),
-        () => transaction.queryRaw('ROLLBACK TRANSACTION /* keep ownership */ AND CHAIN'),
-        () => transaction.exec('SELECT 1; RoLlBaCk AND /* nested /* comment */ */ CHAIN'),
-      ]) {
-        assert.match(
-          String(await catchPromiseWithoutSynchronousThrow(call)),
-          /do not support ROLLBACK\/ABORT .* AND CHAIN/,
-        );
-      }
-      assert.deepEqual(binding.sqlCalls, ['BEGIN']);
-      // Planning failures never enter the transaction queue or poison it.
-      assert.deepEqual(await transaction.execute('UPDATE things SET value = 22'), {
-        commandTag: 'UPDATE 3',
-        rowCount: 3,
-        notices: [],
-      });
-    });
-
-    assert.match(
-      String(
-        await catchPromiseWithoutSynchronousThrow(() =>
-          expired.execute('UPDATE things SET value = 23'),
-        ),
-      ),
-      /transaction is no longer active/,
-    );
-    assert.match(
-      String(await catchPromiseWithoutSynchronousThrow(() => expired.rollback())),
-      /transaction is no longer active/,
-    );
-  } finally {
-    await db.close();
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('serializes physical-session work in FIFO order and pins transactions', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-session-queue-'));
-  const binding = new FakeBinding();
-  const firstStarted = deferred();
-  const releaseFirst = deferred();
-  binding.protocolStarted = () => firstStarted.resolve();
-  binding.protocolGate = releaseFirst.promise;
-  const db = await createOliphauntClient(() => binding).open({
-    storage: { kind: 'directory', path: root },
-  });
-  try {
-    const first = db.execute('UPDATE things SET value = 10');
-    await firstStarted.promise;
-    const backup = db.backup();
-    const checkpoint = db.execute('CHECKPOINT');
-    await new Promise((resolve) => setImmediate(resolve));
-    assert.deepEqual(binding.operationEvents, ['raw:UPDATE things SET value = 10']);
-
-    binding.protocolGate = undefined;
-    releaseFirst.resolve();
-    await Promise.all([first, backup, checkpoint]);
-    assert.deepEqual(binding.operationEvents, [
-      'raw:UPDATE things SET value = 10',
-      'backup',
-      'raw:CHECKPOINT',
-    ]);
-
-    binding.queryValues.set("SELECT 'first'", 'first');
-    binding.queryValues.set("SELECT 'second'", 'second');
-    const [firstResult, secondResult] = await Promise.all([
-      db.query("SELECT 'first'"),
-      db.query("SELECT 'second'"),
-    ]);
-    assert.deepEqual(firstResult.rows, [{ value: 'first' }]);
-    assert.deepEqual(secondResult.rows, [{ value: 'second' }]);
-
-    const transactionBodyStarted = deferred();
-    const releaseTransactionBody = deferred();
-    let completedTransactionHandle!: OliphauntTransaction;
-    const transaction = db.transaction(async (owned) => {
-      completedTransactionHandle = owned;
-      await owned.execute('UPDATE things SET value = 11');
-      transactionBodyStarted.resolve();
-      await releaseTransactionBody.promise;
-      await Promise.all([
-        owned.execute('UPDATE things SET value = 12'),
-        owned.execute('UPDATE things SET value = 13'),
-      ]);
-    });
-    await transactionBodyStarted.promise;
-    await assert.rejects(() => db.query('SELECT 1'), /physical session is pinned/);
-    releaseTransactionBody.resolve();
-    await transaction;
-    assert.deepEqual(binding.sqlCalls.slice(-5), [
-      'BEGIN',
-      'UPDATE things SET value = 11',
-      'UPDATE things SET value = 12',
-      'UPDATE things SET value = 13',
-      'COMMIT',
-    ]);
-    assert.equal(binding.maxConcurrentProtocolOperations, 1);
-    await assert.rejects(
-      () => completedTransactionHandle.execute('SELECT 1'),
-      /transaction is no longer active/,
-    );
-
-    const acceptedOperationStarted = deferred();
-    const releaseAcceptedOperation = deferred();
-    let acceptedOperation!: Promise;
-    let sealedTransactionHandle!: OliphauntTransaction;
-    const drainingTransaction = db.transaction(async (owned) => {
-      sealedTransactionHandle = owned;
-      binding.protocolStarted = () => acceptedOperationStarted.resolve();
-      binding.protocolGate = releaseAcceptedOperation.promise;
-      acceptedOperation = owned.execute('UPDATE things SET value = 15');
-      await acceptedOperationStarted.promise;
-    });
-    await acceptedOperationStarted.promise;
-    await new Promise((resolve) => setImmediate(resolve));
-    assert.notEqual(binding.sqlCalls.at(-1), 'COMMIT');
-    await assert.rejects(
-      () => sealedTransactionHandle.execute('UPDATE things SET value = 16'),
-      /transaction is finishing|transaction is no longer active/,
-    );
-    binding.protocolGate = undefined;
-    releaseAcceptedOperation.resolve();
-    await acceptedOperation;
-    await drainingTransaction;
-    assert.deepEqual(binding.sqlCalls.slice(-3), [
-      'BEGIN',
-      'UPDATE things SET value = 15',
-      'COMMIT',
-    ]);
-
-    await assert.rejects(
-      () =>
-        db.execProtocolRawStream(new Uint8Array([0x51]), () => {
-          throw new Error('stream consumer failed');
-        }),
-      /stream consumer failed/,
-    );
-    const nanCallbackOutcome = await db
-      .execProtocolRawStream(new Uint8Array([0x51]), () => {
-        throw Number.NaN;
-      })
-      .then(
-        () => ({ fulfilled: true as const, error: undefined }),
-        (error: unknown) => ({ fulfilled: false as const, error }),
-      );
-    assert.equal(nanCallbackOutcome.fulfilled, false);
-    assert.ok(Object.is(nanCallbackOutcome.error, Number.NaN));
-    const dynamicallyTypedAsyncCallback: (chunk: Uint8Array) => unknown = async () => {};
-    await assert.rejects(
-      db.execProtocolRawStream(
-        new Uint8Array([0x51]),
-        dynamicallyTypedAsyncCallback as unknown as (chunk: Uint8Array) => undefined,
-      ),
-      /must complete synchronously.*Promise or thenable/,
-    );
-    assert.deepEqual(await db.execute('UPDATE things SET value = 14'), {
-      commandTag: 'UPDATE 3',
-      rowCount: 3,
-      notices: [],
-    });
-  } finally {
-    await db.close();
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('keeps cancellation out of band and close drains accepted work exactly once', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-session-close-'));
-  const binding = new FakeBinding();
-  const operationStarted = deferred();
-  const releaseOperation = deferred();
-  const cancellationStarted = deferred();
-  const releaseCancellation = deferred();
-  const teardownStarted = deferred();
-  const releaseTeardown = deferred();
-  binding.protocolStarted = () => operationStarted.resolve();
-  binding.protocolGate = releaseOperation.promise;
-  binding.cancelStarted = () => cancellationStarted.resolve();
-  binding.cancelGate = releaseCancellation.promise;
-  binding.detachStarted = () => teardownStarted.resolve();
-  binding.detachGate = releaseTeardown.promise;
-  const db = await createOliphauntClient(() => binding).open({
-    storage: { kind: 'directory', path: root },
-  });
-  try {
-    // Deterministic query->immediate close->cancel admission regression.
-    const operation = db.execute('UPDATE things SET value = 12');
-    const firstClose = db.close();
-    const secondClose = db.close();
-    const cancellation = db.cancel();
-    assert.equal(firstClose, secondClose);
-    await Promise.all([operationStarted.promise, cancellationStarted.promise]);
-    assert.deepEqual(binding.operationEvents, ['cancel', 'raw:UPDATE things SET value = 12']);
-    await assert.rejects(() => db.backup(), /closing/);
-    assert.equal(binding.detachCalls, 0);
-
-    binding.protocolGate = undefined;
-    releaseOperation.resolve();
-    await operation;
-    await new Promise((resolve) => setImmediate(resolve));
-    assert.equal(
-      binding.detachCalls,
-      0,
-      'close must wait for the out-of-band cancellation it admitted',
-    );
-    binding.cancelGate = undefined;
-    releaseCancellation.resolve();
-    await cancellation;
-    await teardownStarted.promise;
-    await assert.rejects(() => db.cancel(), /closing/);
-    binding.detachGate = undefined;
-    releaseTeardown.resolve();
-    await Promise.all([firstClose, secondClose]);
-    assert.equal(binding.detachCalls, 1);
-    assert.equal(db.close(), firstClose);
-    await db.close();
-    assert.equal(binding.detachCalls, 1);
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('keeps direct pre-deactivation close failures retryable', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-retryable-close-'));
-  const binding = new FakeBinding();
-  const closeError = new Error('logical detach did not complete');
-  binding.detachFailures.push(closeError);
-  const db = await createOliphauntClient(() => binding).open({
-    storage: { kind: 'directory', path: root },
-  });
-  try {
-    const first = db.close();
-    assert.equal(await first.catch((error: unknown) => error), closeError);
-    assert.equal(db.closed, false);
-    assert.deepEqual(await db.execute('UPDATE things SET value = 18'), {
-      commandTag: 'UPDATE 3',
-      rowCount: 3,
-      notices: [],
-    });
-
-    const retry = db.close();
-    assert.notEqual(retry, first);
-    await retry;
-    assert.equal(db.closed, true);
-    assert.equal(db.close(), retry);
-    assert.equal(binding.detachCalls, 2);
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('terminal broker and server close failures retire the facade and replay exactly', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-terminal-close-'));
-  try {
-    for (const topology of ['broker', 'server'] as const) {
-      const binding = new FakeBinding();
-      const closeError = new Error(`${topology} teardown failed`);
-      let closeCalls = 0;
-      const runtime = binding as unknown as RuntimeBinding;
-      runtime.close = async () => {
-        closeCalls += 1;
-        return { state: 'terminal', error: closeError };
-      };
-      runtime.connectionString = () => 'postgresql://postgres@127.0.0.1:5432/postgres';
-      const client = createOliphauntClient(() => binding, {
-        broker: runtime,
-        server: runtime,
-      });
-      const database =
-        topology === 'broker'
-          ? await client.open({
-              topology,
-              storage: { kind: 'directory', path: join(root, topology) },
-            })
-          : await client.openServer({
-              storage: { kind: 'directory', path: join(root, topology) },
-            });
-
-      const first = database.close();
-      const concurrent = database.close();
-      assert.equal(concurrent, first);
-      assert.equal(await first.catch((error: unknown) => error), closeError);
-      assert.equal(database.closed, true);
-      assert.equal(closeCalls, 1);
-      assert.equal(database.close(), first);
-      assert.equal(await database.close().catch((error: unknown) => error), closeError);
-      if (topology === 'broker') {
-        const brokerDatabase = database as OliphauntDatabase;
-        await assert.rejects(() => brokerDatabase.query('SELECT 1'), /closed/);
-        await assert.rejects(() => brokerDatabase.cancel(), /closed/);
-      } else {
-        assert.equal('query' in database, false);
-        assert.equal('cancel' in database, false);
-      }
-      assert.equal(closeCalls, 1);
-    }
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('database raw stream callbacks cannot queue same-handle work while cancel stays out of band', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-stream-reentry-'));
-  const binding = new FakeBinding();
-  const db = await createOliphauntClient(() => binding).open({
-    storage: { kind: 'directory', path: root },
-  });
-  try {
-    let databaseAttempts: Promise[] = [];
-    let cancellation!: Promise;
-    const beforeDatabaseStream = binding.requests.length;
-    await db.execProtocolRawStream(new Uint8Array([0x51]), () => {
-      databaseAttempts = [
-        db.query('SELECT callback_reentry'),
-        db.backup(),
-        db.close(),
-        db.execProtocolRawStream(new Uint8Array([0x51]), () => undefined),
-      ];
-      for (const attempt of databaseAttempts) void attempt.catch(() => undefined);
-      cancellation = db.cancel();
-      void cancellation.catch(() => undefined);
-    });
-    for (const attempt of databaseAttempts) {
-      await assert.rejects(attempt, /must not re-enter the same Oliphaunt handle/);
-    }
-    await cancellation;
-    assert.equal(binding.requests.length, beforeDatabaseStream + 1);
-    assert.equal(binding.detachCalls, 0);
-    assert.equal(binding.cancelCalls, 1);
-  } finally {
-    await db.close();
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('raw stream native recovery failure outranks an earlier callback failure', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-stream-error-precedence-'));
-  const binding = new FakeBinding();
-  const nativeFailure = new Error('native protocol stream recovery failed');
-  const callbackFailure = new Error('protocol stream callback failed');
-  binding.streamCompletionFailure = nativeFailure;
-  const db = await createOliphauntClient(() => binding).open({
-    storage: { kind: 'directory', path: root },
-  });
-  try {
-    await assert.rejects(
-      () =>
-        db.execProtocolRawStream(new Uint8Array([0x51]), () => {
-          throw callbackFailure;
-        }),
-      (error) => error === nativeFailure,
-    );
-    const requestsAfterFailure = binding.requests.length;
-    await assert.rejects(() => db.query('SELECT 1'), /session state is unknown/);
-    assert.equal(binding.requests.length, requestsAfterFailure);
-  } finally {
-    await db.close();
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('registers forgotten direct cleanup and releases only the collected owner', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-finalizer-'));
-  const binding = new FinalizingFakeBinding();
-  const client = createOliphauntClient(() => binding);
-  try {
-    const explicit = await client.open({
-      storage: { kind: 'directory', path: join(root, 'explicit') },
-    });
-    assert.equal(binding.registeredOwner, explicit);
-    await explicit.close();
-    assert.deepEqual(binding.unregisteredOwners, [explicit]);
-
-    const current = await client.open({
-      storage: { kind: 'directory', path: join(root, 'current') },
-    });
-    await binding.runStaleFinalizer(explicit);
-    await assert.rejects(
-      () =>
-        client.open({
-          storage: { kind: 'directory', path: join(root, 'stale-must-not-release-current') },
-        }),
-      /active process-wide instance/,
-    );
-    await current.close();
-
-    const forgotten = await client.open({
-      storage: { kind: 'directory', path: join(root, 'forgotten') },
-    });
-    assert.equal(binding.registeredOwner, forgotten);
-    await binding.finalizeRegisteredOwner();
-    assert.equal(binding.forgottenCleanupCalls, 1);
-
-    // The cleanup record carries the exact direct-owner release callback. The
-    // next open reaches the runtime instead of failing the stale JS ownership
-    // guard; Deno's generation cleanup is terminal for this process lifetime.
-    await assert.rejects(
-      () =>
-        client.open({
-          storage: { kind: 'directory', path: join(root, 'after-finalizer') },
-        }),
-      /process lifetime has already been used/,
-    );
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('cleans an opened owner before rejecting failed facade publication', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-publication-cleanup-'));
-  try {
-    for (const topology of ['direct', 'broker', 'server'] as const) {
-      const binding = new PublicationFailingFakeBinding();
-      const registrationError = new Error(`${topology} registry rejected owner`);
-      binding.registrationFailure = registrationError;
-      const runtime = binding as unknown as RuntimeBinding;
-      runtime.close = async (handle) => {
-        await binding.detach(handle);
-        return { state: 'closed' };
-      };
-      runtime.connectionString = () => 'postgresql://postgres@127.0.0.1:5432/postgres';
-      const client = createOliphauntClient(() => binding, {
-        broker: runtime,
-        server: runtime,
-      });
-      const config = {
-        storage: { kind: 'directory' as const, path: join(root, topology) },
-      };
-      const firstOpen =
-        topology === 'server'
-          ? client.openServer(config)
-          : client.open({
-              ...config,
-              topology,
-            });
-      assert.equal(await firstOpen.catch((error: unknown) => error), registrationError);
-      assert.equal(binding.detachCalls, 1);
-      assert.equal(binding.registeredOwners.length, 1);
-      assert.deepEqual(binding.unregisteredOwners, binding.registeredOwners);
-
-      // In particular, direct publication failure must release only its exact
-      // process-wide JavaScript admission lease so a later owner can open.
-      const database =
-        topology === 'server'
-          ? await client.openServer(config)
-          : await client.open({ ...config, topology });
-      await database.close();
-      assert.equal(binding.detachCalls, 2);
-      assert.equal(binding.registeredOwners.length, 2);
-      assert.deepEqual(binding.unregisteredOwners, binding.registeredOwners);
-    }
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('broker facade preserves FIFO session ownership', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-runtime-queue-'));
-  try {
-    const binding = new FakeBinding();
-    const started = deferred();
-    const release = deferred();
-    binding.protocolStarted = () => started.resolve();
-    binding.protocolGate = release.promise;
-    const runtime = binding as unknown as RuntimeBinding;
-    runtime.close = async (handle) => {
-      await binding.detach(handle);
-      return { state: 'closed' };
-    };
-    const client = createOliphauntClient(() => binding, { broker: runtime });
-    const database = await client.open({
-      topology: 'broker',
-      storage: { kind: 'directory', path: join(root, 'broker') },
-    });
-    const first = database.execute('UPDATE things SET value = 20');
-    await started.promise;
-    const second = database.execute('UPDATE things SET value = 21');
-    await new Promise((resolve) => setImmediate(resolve));
-    assert.deepEqual(binding.operationEvents, ['raw:UPDATE things SET value = 20']);
-    binding.protocolGate = undefined;
-    release.resolve();
-    await Promise.all([first, second]);
-    assert.deepEqual(binding.operationEvents, [
-      'raw:UPDATE things SET value = 20',
-      'raw:UPDATE things SET value = 21',
-    ]);
-    await database.close();
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('exposes decoded, raw, exec, describe, and immutable inferred-codec operations', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-structured-api-'));
-  const binding = new FakeBinding();
-  const firstStarted = deferred();
-  const releaseFirst = deferred();
-  binding.protocolStarted = () => firstStarted.resolve();
-  binding.protocolGate = releaseFirst.promise;
-  const db = await createOliphauntClient(() => binding).open({
-    storage: { kind: 'directory', path: root },
-  });
-  try {
-    assert.equal(db.closed, false);
-    const object = { version: 1 };
-    const decoders: Record unknown> = {
-      3802: (value) => `first:${value}`,
-    };
-    const inferred = db.query<{ value: string }>('SELECT $1::jsonb AS value', [object], {
-      decoders,
-    });
-    await firstStarted.promise;
-    const queued = db.execute('UPDATE things SET value = 22');
-    object.version = 2;
-    decoders[3802] = (value) => `second:${value}`;
-    await new Promise((resolve) => setImmediate(resolve));
-    assert.deepEqual(binding.requestTags, ['P']);
-
-    binding.protocolGate = undefined;
-    releaseFirst.resolve();
-    const [decoded] = await Promise.all([inferred, queued]);
-    assert.deepEqual(decoded.rows, [{ value: 'first:{"version":1}' }]);
-    assert.deepEqual(binding.requestTags.slice(0, 3), ['P', 'P', 'P']);
-    const bindRequest = binding.requests.find((request) =>
-      frontendMessageTags(request).includes('B'),
-    );
-    assert.ok(bindRequest);
-    assert.equal(firstBindTextParameter(bindRequest), '{"version":1}');
-    assert.equal(binding.maxConcurrentProtocolOperations, 1);
-
-    const raw = await db.queryRaw('SELECT $1::text AS value', ['raw']);
-    assert.equal(raw.getText(0, 'value'), 'raw');
-    assert.equal(raw.kind, 'rows');
-
-    const description = await db.describe('SELECT $1::int4 AS value');
-    assert.deepEqual(description.parameterTypeOids, [23]);
-    assert.equal(description.fields?.[0]?.typeOid, 23);
-
-    const multiSql = 'UPDATE things SET value = 30; SELECT value FROM things';
-    binding.responseForSql.set(multiSql, multiExecResponse());
-    const execution = await db.exec(multiSql);
-    assert.deepEqual(
-      execution.statements.map((statement) => statement.kind),
-      ['command', 'rows'],
-    );
-    assert.deepEqual(execution.statements[1]?.rows, [{ value: 'multi' }]);
-
-    const requestCount = binding.requests.length;
-    await assert.rejects(() => db.exec('COPY things FROM STDIN'), /does not support COPY/);
-    assert.equal(binding.requests.length, requestCount);
-  } finally {
-    await db.close();
-    assert.equal(db.closed, true);
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('recovers database-level transaction leakage and poisons unknown wire boundaries', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-recovery-'));
-  try {
-    const recoverableBinding = new FakeBinding();
-    const recoverable = await createOliphauntClient(() => recoverableBinding).open({
-      storage: { kind: 'directory', path: join(root, 'recoverable') },
-    });
-    await assert.rejects(
-      () => recoverable.execute('BEGIN'),
-      /ended with PostgreSQL transaction status transaction/,
-    );
-    assert.deepEqual(recoverableBinding.sqlCalls.slice(-2), ['BEGIN', 'ROLLBACK']);
-    await assert.doesNotReject(() => recoverable.execute('UPDATE things SET value = 31'));
-    await recoverable.close();
-
-    const malformedBinding = new FakeBinding();
-    malformedBinding.responseForSql.set(
-      'SELECT malformed',
-      Uint8Array.from(backendMessage(0x43, cstring('SELECT 0'))),
-    );
-    const malformed = await createOliphauntClient(() => malformedBinding).open({
-      storage: { kind: 'directory', path: join(root, 'malformed') },
-    });
-    await assert.rejects(() => malformed.query('SELECT malformed'), /before ReadyForQuery/);
-    await assert.rejects(() => malformed.query('SELECT 1'), /session state is unknown/);
-    await malformed.close();
-
-    const rawFailureBinding = new FakeBinding();
-    const rawTransportFailure = new Error('raw transport failed');
-    rawFailureBinding.protocolFailure = rawTransportFailure;
-    const rawFailure = await createOliphauntClient(() => rawFailureBinding).open({
-      storage: { kind: 'directory', path: join(root, 'raw-failure') },
-    });
-    await assert.rejects(
-      () => rawFailure.execProtocolRaw(new Uint8Array([0x51])),
-      (error) => error === rawTransportFailure,
-    );
-    const requestsAfterFailure = rawFailureBinding.requests.length;
-    await assert.rejects(() => rawFailure.query('SELECT 1'), /session state is unknown/);
-    assert.equal(rawFailureBinding.requests.length, requestsAfterFailure);
-    await rawFailure.close();
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('supports one-shot explicit transaction rollback and expires the handle', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-explicit-rollback-'));
-  const binding = new FakeBinding();
-  const db = await createOliphauntClient(() => binding).open({
-    storage: { kind: 'directory', path: root },
-  });
-  let completed!: OliphauntTransaction;
-  try {
-    const value = await db.transaction(async (transaction) => {
-      completed = transaction;
-      assert.equal(transaction.closed, false);
-      assert.equal('execProtocolRaw' in transaction, false);
-      assert.equal('execProtocolRawStream' in transaction, false);
-      await transaction.execute('UPDATE things SET value = 40');
-      await transaction.rollback();
-      assert.equal(transaction.closed, true);
-      await assert.rejects(() => transaction.rollback(), /no longer active/);
-      await assert.rejects(() => transaction.query('SELECT 1'), /no longer active/);
-      return 40;
-    });
-    assert.equal(value, 40);
-    assert.equal(completed.closed, true);
-    assert.deepEqual(binding.sqlCalls.slice(-3), [
-      'BEGIN',
-      'UPDATE things SET value = 40',
-      'ROLLBACK',
-    ]);
-    assert.equal(binding.sqlCalls.includes('COMMIT'), false);
-    await assert.doesNotReject(() => db.execute('UPDATE things SET value = 41'));
-  } finally {
-    await db.close();
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-test('transaction ownership is enforced from complete protocol responses before parsing', async () => {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-transaction-ownership-'));
-  try {
-    const escapedResponses = [
-      {
-        sql: 'SELECT hidden_commit_then_begin',
-        response: Uint8Array.from([
-          ...backendMessage(0x43, cstring('COMMIT')),
-          ...backendMessage(0x43, cstring('BEGIN')),
-          ...backendMessage(0x45, diagnostic('ERROR', 'XX000', 'later failure')),
-          ...backendMessage(0x5a, [0x54]),
-        ]),
-        expected: /command tag COMMIT/,
-      },
-      {
-        sql: 'SELECT hidden_rollback_then_begin',
-        response: Uint8Array.from([
-          ...backendMessage(0x43, cstring('ROLLBACK')),
-          ...backendMessage(0x43, cstring('BEGIN')),
-          ...backendMessage(0x5a, [0x54]),
-        ]),
-        expected: /command tag BEGIN/,
-      },
-    ];
-
-    for (const [index, escaped] of escapedResponses.entries()) {
-      const binding = new FakeBinding();
-      binding.responseForSql.set(escaped.sql, escaped.response);
-      const db = await createOliphauntClient(() => binding).open({
-        storage: { kind: 'directory', path: join(root, `escaped-${index}`) },
-      });
-      const failure = await db
-        .transaction((transaction) => {
-          const ignored = transaction.exec(escaped.sql);
-          void ignored.catch(() => undefined);
-        })
-        .catch((error: unknown) => error);
-      assert.match(String(failure), escaped.expected);
-      assert.deepEqual(binding.sqlCalls, ['BEGIN', escaped.sql]);
-      const requestCount = binding.requests.length;
-      await assert.rejects(() => db.query('SELECT 1'), /session state is unknown/);
-      assert.equal(binding.requests.length, requestCount);
-      await db.close();
-    }
-
-    const savepointBinding = new FakeBinding();
-    const rollbackToSavepoint = 'ROLLBACK TO SAVEPOINT nested';
-    savepointBinding.responseForSql.set(rollbackToSavepoint, commandResponse('ROLLBACK', 0x54));
-    const reusable = await createOliphauntClient(() => savepointBinding).open({
-      storage: { kind: 'directory', path: join(root, 'savepoint') },
-    });
-    await reusable.transaction(async (transaction) => {
-      await transaction.exec(rollbackToSavepoint);
-    });
-    assert.deepEqual(savepointBinding.sqlCalls.slice(-3), ['BEGIN', rollbackToSavepoint, 'COMMIT']);
-    await reusable.close();
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-});
-
-class FakeBinding implements NativeBinding {
-  readonly openCalls: NativeOpenConfig[] = [];
-  readonly restoreCalls: NativeRestoreOptions[] = [];
-  readonly sqlCalls: string[] = [];
-  readonly requestTags: string[] = [];
-  readonly requests: Uint8Array[] = [];
-  readonly operationEvents: string[] = [];
-  cancelCalls = 0;
-  detachCalls = 0;
-  readonly detachFailures: unknown[] = [];
-  failSql?: string;
-  protocolGate?: Promise;
-  protocolStarted?: () => void;
-  protocolFailure?: unknown;
-  streamCompletionFailure?: unknown;
-  cancelGate?: Promise;
-  cancelStarted?: () => void;
-  detachGate?: Promise;
-  detachStarted?: () => void;
-  activeProtocolOperations = 0;
-  maxConcurrentProtocolOperations = 0;
-  readonly tagForSql = new Map();
-  readonly queryValues = new Map();
-  readonly responseForSql = new Map();
-  #transactionStatus = 0x49;
-  #pendingSql?: string;
-
-  async open(config: NativeOpenConfig): Promise {
-    this.openCalls.push(config);
-    return { id: 1 };
-  }
-
-  async execProtocolRaw(_handle: NativeHandle, request: Uint8Array): Promise {
-    this.requestTags.push(String.fromCharCode(request[0] ?? 0));
-    this.requests.push(request.slice());
-    const tags = frontendMessageTags(request);
-    const parsedSql = decodeSimpleQuery(request) ?? decodeExtendedQuery(request);
-    const describeOnly = tags.includes('P') && tags.includes('D') && !tags.includes('B');
-    if (describeOnly && parsedSql !== undefined) this.#pendingSql = parsedSql;
-    const sql =
-      parsedSql ?? (tags[0] === 'B' ? this.#pendingSql : undefined) ?? 'SELECT value FROM things';
-    this.operationEvents.push(`raw:${sql}`);
-    this.protocolStarted?.();
-    this.activeProtocolOperations += 1;
-    this.maxConcurrentProtocolOperations = Math.max(
-      this.maxConcurrentProtocolOperations,
-      this.activeProtocolOperations,
-    );
-    try {
-      await this.protocolGate;
-      if (this.protocolFailure !== undefined) throw this.protocolFailure;
-      if (describeOnly) {
-        return describeResponse(sql, inferredParameterOids(sql), this.#transactionStatus);
-      }
-      if (tags.includes('B')) this.#pendingSql = undefined;
-      return this.respond(
-        sql,
-        tags.includes('B') ? firstBindTextParameter(request) : undefined,
-        tags.includes('B'),
-      );
-    } finally {
-      this.activeProtocolOperations -= 1;
-    }
-  }
-
-  async execProtocolStream(
-    handle: NativeHandle,
-    request: Uint8Array,
-    onChunk: (chunk: Uint8Array) => void,
-  ): Promise {
-    try {
-      onChunk(await this.execProtocolRaw(handle, request));
-    } catch (callbackError) {
-      if (this.streamCompletionFailure !== undefined) {
-        throw this.streamCompletionFailure;
-      }
-      throw callbackError;
-    }
-    if (this.streamCompletionFailure !== undefined) {
-      throw this.streamCompletionFailure;
-    }
-  }
-
-  async execSimpleQuery(_handle: NativeHandle, sql: string): Promise {
-    this.operationEvents.push(`simple:${sql}`);
-    return this.respond(sql);
-  }
-
-  async backup(_handle: NativeHandle): Promise {
-    this.operationEvents.push('backup');
-    return new Uint8Array([1, 2, 3]);
-  }
-
-  async restore(options: NativeRestoreOptions): Promise {
-    this.restoreCalls.push(options);
-  }
-
-  async cancel(_handle: NativeHandle): Promise {
-    this.cancelCalls += 1;
-    this.operationEvents.push('cancel');
-    this.cancelStarted?.();
-    await this.cancelGate;
-  }
-
-  async detach(_handle: NativeHandle): Promise {
-    this.detachCalls += 1;
-    this.detachStarted?.();
-    await this.detachGate;
-    if (this.detachFailures.length > 0) {
-      throw this.detachFailures.shift();
-    }
-  }
-
-  private respond(sql: string, boundValue?: string, extended = false): Uint8Array {
-    this.sqlCalls.push(sql);
-    if (sql === this.failSql) throw new Error('commit failed');
-    const configured = this.responseForSql.get(sql);
-    if (configured !== undefined) return configured;
-    if (sql === 'BEGIN') {
-      this.#transactionStatus = 0x54;
-      return commandResponse(this.tagForSql.get(sql) ?? sql, this.#transactionStatus, extended);
-    }
-    if (sql === 'COMMIT' || sql === 'ROLLBACK') {
-      this.#transactionStatus = 0x49;
-      return commandResponse(this.tagForSql.get(sql) ?? sql, this.#transactionStatus, extended);
-    }
-    if (sql === 'CHECKPOINT') return commandResponse(sql, this.#transactionStatus, extended);
-    if (sql.startsWith('UPDATE'))
-      return commandResponse('UPDATE 3', this.#transactionStatus, extended);
-    return queryResponse(
-      this.queryValues.get(sql) ?? boundValue ?? 'ok',
-      this.#transactionStatus,
-      inferredResultOid(sql),
-      extended,
-    );
-  }
-}
-
-class FinalizingFakeBinding extends FakeBinding {
-  registeredOwner?: object;
-  readonly unregisteredOwners: object[] = [];
-  forgottenCleanupCalls = 0;
-  terminallyClosed = false;
-  #releaseOwnership?: () => void;
-  readonly #releaseByOwner = new WeakMap void>();
-
-  override async open(config: NativeOpenConfig): Promise {
-    if (this.terminallyClosed) {
-      throw new Error('native process lifetime has already been used');
-    }
-    return super.open(config);
-  }
-
-  registerForgottenHandleCleanup(
-    owner: object,
-    _handle: NativeHandle,
-    releaseOwnership: () => void,
-  ): void {
-    this.registeredOwner = owner;
-    this.#releaseOwnership = releaseOwnership;
-    this.#releaseByOwner.set(owner, releaseOwnership);
-  }
-
-  unregisterForgottenHandleCleanup(owner: object): void {
-    this.unregisteredOwners.push(owner);
-    if (this.registeredOwner === owner) {
-      this.registeredOwner = undefined;
-      this.#releaseOwnership = undefined;
-    }
-  }
-
-  async finalizeRegisteredOwner(): Promise {
-    const releaseOwnership = this.#releaseOwnership;
-    assert.ok(releaseOwnership);
-    this.forgottenCleanupCalls += 1;
-    await Promise.resolve();
-    this.terminallyClosed = true;
-    releaseOwnership();
-    this.registeredOwner = undefined;
-    this.#releaseOwnership = undefined;
-  }
-
-  async runStaleFinalizer(owner: object): Promise {
-    const releaseOwnership = this.#releaseByOwner.get(owner);
-    assert.ok(releaseOwnership);
-    await Promise.resolve();
-    releaseOwnership();
-  }
-}
-
-class PublicationFailingFakeBinding extends FakeBinding {
-  registrationFailure?: Error;
-  readonly registeredOwners: object[] = [];
-  readonly unregisteredOwners: object[] = [];
-
-  registerForgottenHandleCleanup(
-    owner: object,
-    _handle: NativeHandle,
-    _releaseOwnership: () => void,
-  ): void {
-    this.registeredOwners.push(owner);
-    const error = this.registrationFailure;
-    this.registrationFailure = undefined;
-    if (error !== undefined) throw error;
-  }
-
-  unregisterForgottenHandleCleanup(owner: object): void {
-    this.unregisteredOwners.push(owner);
-  }
-}
-
-async function catchPromiseWithoutSynchronousThrow(call: () => Promise): Promise {
-  let caught!: Promise;
-  assert.doesNotThrow(() => {
-    caught = call().catch((error: unknown) => error);
-  });
-  return caught;
-}
-
-function deferred(): {
-  promise: Promise;
-  resolve(value?: T): void;
-} {
-  let resolvePromise!: (value: T | PromiseLike) => void;
-  const promise = new Promise((resolve) => {
-    resolvePromise = resolve;
-  });
-  return {
-    promise,
-    resolve: (value) => resolvePromise(value as T),
-  };
-}
-
-function commandResponse(tag: string, status = 0x49, extended = false): Uint8Array {
-  return Uint8Array.from([
-    ...(extended
-      ? [...backendMessage(0x31, []), ...backendMessage(0x32, []), ...backendMessage(0x6e, [])]
-      : []),
-    ...backendMessage(0x43, cstring(tag)),
-    ...backendMessage(0x5a, [status]),
-  ]);
-}
-
-function queryResponse(value: string, status = 0x49, typeOid = 25, extended = false): Uint8Array {
-  const bytes = [...new TextEncoder().encode(value)];
-  return Uint8Array.from([
-    ...(extended ? [...backendMessage(0x31, []), ...backendMessage(0x32, [])] : []),
-    ...backendMessage(0x54, rowDescriptionBody(typeOid)),
-    ...backendMessage(0x44, [...i16(1), ...i32(bytes.length), ...bytes]),
-    ...backendMessage(0x43, cstring('SELECT 1')),
-    ...backendMessage(0x5a, [status]),
-  ]);
-}
-
-function multiExecResponse(): Uint8Array {
-  const value = [...new TextEncoder().encode('multi')];
-  return Uint8Array.from([
-    ...backendMessage(0x43, cstring('UPDATE 2')),
-    ...backendMessage(0x54, rowDescriptionBody(25)),
-    ...backendMessage(0x44, [...i16(1), ...i32(value.length), ...value]),
-    ...backendMessage(0x43, cstring('SELECT 1')),
-    ...backendMessage(0x5a, [0x49]),
-  ]);
-}
-
-function describeResponse(sql: string, parameterTypeOids: number[], status: number): Uint8Array {
-  return Uint8Array.from([
-    ...backendMessage(0x31, []),
-    ...backendMessage(0x74, [...i16(parameterTypeOids.length), ...parameterTypeOids.flatMap(i32)]),
-    ...(sql.trimStart().toUpperCase().startsWith('SELECT')
-      ? backendMessage(0x54, rowDescriptionBody(inferredResultOid(sql)))
-      : backendMessage(0x6e, [])),
-    ...backendMessage(0x5a, [status]),
-  ]);
-}
-
-function rowDescriptionBody(typeOid: number): number[] {
-  return [
-    ...i16(1),
-    ...cstring('value'),
-    ...i32(0),
-    ...i16(0),
-    ...i32(typeOid),
-    ...i16(-1),
-    ...i32(-1),
-    ...i16(0),
-  ];
-}
-
-function inferredParameterOids(sql: string): number[] {
-  const indexes = [...sql.matchAll(/\$([1-9][0-9]*)/g)].map((match) => Number(match[1]));
-  const count = Math.max(0, ...indexes);
-  return Array.from({ length: count }, (_, offset) => {
-    const index = offset + 1;
-    const cast = new RegExp(`\\$${index}\\s*::\\s*([a-z0-9_]+)`, 'i').exec(sql)?.[1]?.toLowerCase();
-    if (cast === 'jsonb') return 3802;
-    if (cast === 'json') return 114;
-    if (cast === 'int4' || cast === 'integer') return 23;
-    return 25;
-  });
-}
-
-function inferredResultOid(sql: string): number {
-  if (/::\s*jsonb\b/i.test(sql)) return 3802;
-  if (/::\s*json\b/i.test(sql)) return 114;
-  if (/::\s*(?:int4|integer)\b/i.test(sql)) return 23;
-  return 25;
-}
-
-function backendMessage(tag: number, body: number[]): number[] {
-  return [tag, ...i32(body.length + 4), ...body];
-}
-
-function cstring(value: string): number[] {
-  return [...new TextEncoder().encode(value), 0];
-}
-
-function diagnostic(severity: string, sqlstate: string, message: string): number[] {
-  return [0x53, ...cstring(severity), 0x43, ...cstring(sqlstate), 0x4d, ...cstring(message), 0];
-}
-
-function i16(value: number): number[] {
-  const bits = value & 0xffff;
-  return [(bits >>> 8) & 0xff, bits & 0xff];
-}
-
-function i32(value: number): number[] {
-  const bits = value >>> 0;
-  return [(bits >>> 24) & 0xff, (bits >>> 16) & 0xff, (bits >>> 8) & 0xff, bits & 0xff];
-}
-
-function decodeSimpleQuery(request: Uint8Array): string | undefined {
-  return request[0] === 0x51
-    ? new TextDecoder().decode(request.subarray(5, request.length - 1))
-    : undefined;
-}
-
-function decodeExtendedQuery(request: Uint8Array): string | undefined {
-  if (request[0] !== 0x50 || request[5] !== 0) return undefined;
-  const terminator = request.indexOf(0, 6);
-  return terminator < 0 ? undefined : new TextDecoder().decode(request.subarray(6, terminator));
-}
-
-function frontendMessageTags(request: Uint8Array): string[] {
-  const tags: string[] = [];
-  let offset = 0;
-  while (offset + 5 <= request.length) {
-    const length = readU32(request, offset + 1);
-    if (length < 4 || offset + length + 1 > request.length) break;
-    tags.push(String.fromCharCode(request[offset]!));
-    offset += length + 1;
-  }
-  if (tags.length === 0 && request.length > 0) tags.push(String.fromCharCode(request[0]!));
-  return tags;
-}
-
-function firstBindTextParameter(request: Uint8Array): string | undefined {
-  let messageOffset = 0;
-  while (messageOffset + 5 <= request.length && request[messageOffset] !== 0x42) {
-    messageOffset += readU32(request, messageOffset + 1) + 1;
-  }
-  if (request[messageOffset] !== 0x42) return undefined;
-  let offset = messageOffset + 5;
-  while (offset < request.length && request[offset] !== 0) offset += 1;
-  offset += 1;
-  while (offset < request.length && request[offset] !== 0) offset += 1;
-  offset += 1;
-  const formatCount = readU16(request, offset);
-  offset += 2 + formatCount * 2;
-  const parameterCount = readU16(request, offset);
-  offset += 2;
-  if (parameterCount === 0) return undefined;
-  const length = readU32(request, offset);
-  if (length === 0xffffffff) return undefined;
-  offset += 4;
-  return new TextDecoder().decode(request.subarray(offset, offset + length));
-}
-
-function readU16(bytes: Uint8Array, offset: number): number {
-  return ((bytes[offset] ?? 0) << 8) | (bytes[offset + 1] ?? 0);
-}
-
-function readU32(bytes: Uint8Array, offset: number): number {
-  return (
-    ((bytes[offset] ?? 0) * 0x1000000 +
-      ((bytes[offset + 1] ?? 0) << 16) +
-      ((bytes[offset + 2] ?? 0) << 8) +
-      (bytes[offset + 3] ?? 0)) >>>
-    0
-  );
-}
diff --git a/src/sdks/js/src/__tests__/deno-native-smoke.mjs b/src/sdks/js/src/__tests__/deno-native-smoke.mjs
deleted file mode 100644
index 7ba635b97..000000000
--- a/src/sdks/js/src/__tests__/deno-native-smoke.mjs
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Oliphaunt } from '../../lib/index.js';
-import { assertNativeDatabaseContract } from './native-direct-contract.mjs';
-
-const libraryPath = Deno.env.get('LIBOLIPHAUNT_PATH');
-if (!libraryPath) {
-  throw new Error('LIBOLIPHAUNT_PATH is required for the TypeScript SDK Deno smoke check');
-}
-
-await assertNativeDatabaseContract(Oliphaunt, { topology: 'direct', libraryPath }, 'deno-direct');
diff --git a/src/sdks/js/src/__tests__/native-bindings.test.ts b/src/sdks/js/src/__tests__/native-bindings.test.ts
deleted file mode 100644
index 93efb21d9..000000000
--- a/src/sdks/js/src/__tests__/native-bindings.test.ts
+++ /dev/null
@@ -1,1254 +0,0 @@
-import assert from 'node:assert/strict';
-import {
-  mkdir as fsMkdir,
-  stat as fsStat,
-  mkdtemp,
-  readdir,
-  readFile,
-  rm,
-  rmdir,
-  writeFile,
-} from 'node:fs/promises';
-import { createRequire } from 'node:module';
-import { tmpdir } from 'node:os';
-import { dirname, join, resolve } from 'node:path';
-import { fileURLToPath } from 'node:url';
-import { test, vi } from 'vitest';
-import * as publicEntrypoint from '../index.js';
-import Oliphaunt, { type OliphauntClient } from '../index.js';
-import { resolveDenoNativeInstall } from '../native/assets-deno.js';
-import {
-  ABI_VERSION,
-  liboliphauntPackageTarget,
-  nativeRuntimeLibraryEnvironment,
-} from '../native/common.js';
-import { createDenoNativeBinding } from '../native/deno.js';
-import { nativeModuleSuffixForTarget } from '../native/extension-runtime.js';
-import {
-  cString,
-  errorCaptureBuffer,
-  OLIPHAUNT_CONFIG_SIZE,
-  OLIPHAUNT_ERROR_CAPTURE_CAPACITY,
-  OLIPHAUNT_ERROR_CAPTURE_SIZE,
-  OLIPHAUNT_RESPONSE_SIZE,
-  packConfigPointers,
-  packPointerArray,
-  packRestoreOptionsPointers,
-  readResponseLength,
-  readResponsePointer,
-  readErrorCapture,
-  responseBuffer,
-  writePointer,
-} from '../native/ffi-layout.js';
-import { createNodeNativeBinding } from '../native/node.js';
-import { publishNativeDescriptor } from '../root-descriptor.js';
-import { directRuntimeBinding } from '../runtime/direct.js';
-import { readTypeScriptPackageVersions } from './package-metadata.js';
-
-async function main(): Promise {
-  testIndexExportsDefaultClient();
-  testFfiLayoutPackingAndBounds();
-  testPackagedRuntimeLibraryEnvironment();
-  await testNodeNativeBindingUsesExplicitAssetsAndAddon();
-  await testDenoAssetResolverHonorsExplicitPaths();
-  await testDenoPackageManagedResolverUsesStandardCarrierRuntime();
-  await testDenoNativeBindingRejectsPackageManagedExtensions();
-  await testDenoNativeBindingUsesSeparateModuleDirectoryWithoutAmbientMutation();
-}
-
-function testPackagedRuntimeLibraryEnvironment(): void {
-  const previous = Object.fromEntries(
-    ['LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'PATH'].map((name) => [name, process.env[name]]),
-  );
-  try {
-    process.env.LD_LIBRARY_PATH = '/existing/lib';
-    assert.deepEqual(nativeRuntimeLibraryEnvironment('/candidate/runtime', 'linux'), {
-      LD_LIBRARY_PATH: '/candidate/runtime/lib:/existing/lib',
-    });
-    process.env.LD_LIBRARY_PATH = '/candidate/runtime/lib:/existing/lib';
-    assert.deepEqual(nativeRuntimeLibraryEnvironment('/candidate/runtime', 'linux'), {
-      LD_LIBRARY_PATH: '/candidate/runtime/lib:/existing/lib',
-    });
-
-    process.env.DYLD_LIBRARY_PATH = '/candidate/runtime/lib:/existing/macos/lib';
-    assert.deepEqual(nativeRuntimeLibraryEnvironment('/candidate/runtime', 'darwin'), {
-      DYLD_LIBRARY_PATH: '/candidate/runtime/lib:/existing/macos/lib',
-    });
-
-    process.env.PATH = 'C:\\candidate\\runtime\\lib;C:\\existing\\bin;C:\\candidate\\runtime\\bin';
-    assert.deepEqual(nativeRuntimeLibraryEnvironment('C:\\candidate\\runtime', 'win32'), {
-      PATH: 'C:\\candidate\\runtime\\bin;C:\\candidate\\runtime\\lib;C:\\existing\\bin',
-    });
-
-    assert.deepEqual(nativeRuntimeLibraryEnvironment('   ', 'linux'), {});
-    assert.throws(
-      () => nativeRuntimeLibraryEnvironment('/candidate\0runtime', 'linux'),
-      /NUL bytes/,
-    );
-  } finally {
-    for (const [name, value] of Object.entries(previous)) {
-      if (value === undefined) delete process.env[name];
-      else process.env[name] = value;
-    }
-  }
-}
-
-function testIndexExportsDefaultClient(): void {
-  assert.equal(typeof (Oliphaunt as OliphauntClient).open, 'function');
-  assert.equal(typeof (Oliphaunt as OliphauntClient).openServer, 'function');
-  assert.equal(typeof (Oliphaunt as OliphauntClient).restore, 'function');
-  for (const internalName of [
-    'createOliphauntClient',
-    'OliphauntDatabase',
-    'nativeDirectCapabilities',
-    'createDefaultNativeBinding',
-    'createNodeNativeBinding',
-    'createDenoNativeBinding',
-  ]) {
-    assert.equal(internalName in publicEntrypoint, false, `${internalName} must remain internal`);
-  }
-}
-
-function testFfiLayoutPackingAndBounds(): void {
-  assert.deepEqual([...cString('pgdata')], [112, 103, 100, 97, 116, 97, 0]);
-  assert.throws(() => cString('bad\0value'), /NUL bytes/);
-
-  const pointers = packPointerArray([1n, 2n, 3n]);
-  const pointerView = new DataView(pointers.buffer);
-  assert.equal(pointerView.getBigUint64(0, true), 1n);
-  assert.equal(pointerView.getBigUint64(8, true), 2n);
-  assert.equal(pointerView.getBigUint64(16, true), 3n);
-  assert.equal(packPointerArray([]).byteLength, 8);
-
-  const emptyCapture = errorCaptureBuffer();
-  assert.equal(emptyCapture.byteLength, OLIPHAUNT_ERROR_CAPTURE_SIZE);
-  assert.equal(OLIPHAUNT_ERROR_CAPTURE_CAPACITY, 1024);
-  assert.equal(readErrorCapture(emptyCapture), null);
-  const capturedText = new TextEncoder().encode('operation-local failure');
-  new DataView(emptyCapture.buffer).setUint32(0, capturedText.byteLength, true);
-  emptyCapture.set(capturedText, 4);
-  assert.equal(readErrorCapture(emptyCapture), 'operation-local failure');
-  emptyCapture[4 + capturedText.byteLength] = 1;
-  assert.match(readErrorCapture(emptyCapture) ?? '', /invalid error capture/);
-  const invalidLengthCapture = errorCaptureBuffer();
-  new DataView(invalidLengthCapture.buffer).setUint32(0, OLIPHAUNT_ERROR_CAPTURE_CAPACITY, true);
-  assert.match(readErrorCapture(invalidLengthCapture) ?? '', /invalid error capture/);
-  const embeddedNulCapture = errorCaptureBuffer();
-  new DataView(embeddedNulCapture.buffer).setUint32(0, 3, true);
-  embeddedNulCapture.set([0x61, 0, 0x62], 4);
-  assert.match(readErrorCapture(embeddedNulCapture) ?? '', /invalid error capture/);
-  assert.match(readErrorCapture(new Uint8Array(4)) ?? '', /invalid error capture/);
-
-  let nextPointer = 16n;
-  const seenStrings: string[] = [];
-  const pointerOf = (value: Uint8Array): bigint => {
-    const decoded = new TextDecoder().decode(value.slice(0, Math.max(0, value.byteLength - 1)));
-    seenStrings.push(decoded);
-    nextPointer += 16n;
-    return nextPointer;
-  };
-  const packed = packConfigPointers(
-    {
-      pgdata: '/tmp/pgdata',
-      runtimeDirectory: '/tmp/runtime',
-      moduleDirectory: '/tmp/modules',
-      username: 'postgres',
-      database: 'app',
-      extensions: [],
-      startupArgs: ['-c', 'work_mem=8MB'],
-    },
-    pointerOf,
-  );
-  assert.equal(packed.config.byteLength, OLIPHAUNT_CONFIG_SIZE);
-  assert.ok(seenStrings.includes('/tmp/pgdata'));
-  assert.ok(seenStrings.includes('/tmp/runtime'));
-  assert.ok(seenStrings.includes('/tmp/modules'));
-  assert.ok(seenStrings.includes('work_mem=8MB'));
-  assert.equal(packed.keepAlive.length, 8);
-  const configView = new DataView(packed.config.buffer);
-  assert.equal(configView.getUint32(0, true), ABI_VERSION);
-  assert.notEqual(configView.getBigUint64(24, true), 0n);
-
-  const restore = packRestoreOptionsPointers(
-    {
-      destination: '/tmp/root',
-      bytes: new Uint8Array([1, 2, 3]),
-    },
-    pointerOf,
-  );
-  assert.equal(restore.options.byteLength, 32);
-  assert.equal(restore.keepAlive.length, 2);
-
-  const response = responseBuffer();
-  assert.equal(response.byteLength, OLIPHAUNT_RESPONSE_SIZE);
-  const responseView = new DataView(response.buffer);
-  writePointer(responseView, 0, 0x1234n);
-  writePointer(responseView, 8, 3n);
-  assert.equal(readResponsePointer(response), 0x1234n);
-  assert.equal(readResponseLength(response), 3);
-  writePointer(responseView, 8, BigInt(Number.MAX_SAFE_INTEGER) + 1n);
-  assert.throws(() => readResponseLength(response), /safe integer/);
-}
-
-async function testNodeNativeBindingUsesExplicitAssetsAndAddon(): Promise {
-  const previousFinalizationRegistry = globalThis.FinalizationRegistry;
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-node-binding-'));
-  const addonPath = join(root, 'mock-addon.cjs');
-  const databaseRoot = join(root, 'database');
-  const runtimeDirectory = join(root, 'runtime');
-  const moduleDirectory = join(runtimeDirectory, 'lib/modules');
-  const extensionDirectory = join(runtimeDirectory, 'share/postgresql/extension');
-  const target = liboliphauntPackageTarget(process.platform, process.arch);
-  await fsMkdir(moduleDirectory, { recursive: true });
-  await fsMkdir(extensionDirectory, { recursive: true });
-  await fsMkdir(join(databaseRoot, 'pgdata', 'global'), { recursive: true });
-  await fsMkdir(join(databaseRoot, 'pgdata', 'pg_wal'));
-  await writeFile(join(databaseRoot, 'pgdata', 'PG_VERSION'), '18\n');
-  await writeFile(join(databaseRoot, 'pgdata', 'global', 'pg_control'), 'control');
-  await publishNativeDescriptor(databaseRoot);
-  await writeFile(join(extensionDirectory, 'hstore.control'), "default_version = '1.0'\n");
-  await writeFile(join(extensionDirectory, 'hstore--1.0.sql'), 'SELECT 1;\n');
-  await writeFile(
-    join(moduleDirectory, `hstore${nativeModuleSuffixForTarget(target.id)}`),
-    'native-module',
-  );
-  await writeFile(
-    join(moduleDirectory, `dict_snowball${nativeModuleSuffixForTarget(target.id)}`),
-    'native-module',
-  );
-  await writeFile(
-    join(moduleDirectory, `plpgsql${nativeModuleSuffixForTarget(target.id)}`),
-    'native-module',
-  );
-  await writeFile(
-    addonPath,
-    `
-let nextHandle = 40n;
-module.exports = {
-  default: {
-    async open(config) {
-      globalThis.__oliphauntNodeAddonCalls.push(['open', config]);
-      nextHandle += 1n;
-      return nextHandle;
-    },
-    execProtocolRaw(handle, request) {
-      globalThis.__oliphauntNodeAddonCalls.push(['execProtocolRaw', handle, Array.from(request)]);
-      return request.buffer.slice(request.byteOffset, request.byteOffset + request.byteLength);
-    },
-    async execProtocolRawStream(handle, request, onChunk) {
-      globalThis.__oliphauntNodeAddonCalls.push(['execProtocolRawStream', handle, Array.from(request)]);
-      onChunk(request.slice());
-    },
-    execSimpleQuery(handle, sql) {
-      globalThis.__oliphauntNodeAddonCalls.push(['execSimpleQuery', handle, sql]);
-      return new Uint8Array([90, 0, 0, 0, 5, 73]);
-    },
-    async backup(handle) {
-      globalThis.__oliphauntNodeAddonCalls.push(['backup', handle]);
-      return new Uint8Array([4, 5, 6]).buffer;
-    },
-    async restore(options) {
-      globalThis.__oliphauntNodeAddonCalls.push(['restore', options]);
-    },
-    cancel(handle) {
-      globalThis.__oliphauntNodeAddonCalls.push(['cancel', handle]);
-    },
-    async detach(handle) {
-      globalThis.__oliphauntNodeAddonCalls.push(['detach', handle]);
-    },
-    createForgottenHandleRecoveryToken(handle) {
-      const token = 'recovery-token:' + handle;
-      globalThis.__oliphauntNodeAddonCalls.push(['createForgottenHandleRecoveryToken', handle, token]);
-      return token;
-    },
-    queueForgottenHandleRecovery(token) {
-      globalThis.__oliphauntNodeAddonCalls.push(['queueForgottenHandleRecovery', token]);
-      return token !== 'stale-recovery-token';
-    },
-  },
-};
-`,
-    'utf8',
-  );
-  const calls: unknown[][] = [];
-  (globalThis as { __oliphauntNodeAddonCalls?: unknown[][] }).__oliphauntNodeAddonCalls = calls;
-  const previousRuntime = process.env.OLIPHAUNT_RUNTIME_DIR;
-  const previousModuleDirectory = process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR;
-  const callerModuleDirectory = join(root, 'caller-owned-modules');
-  type NodeForgottenHandle = {
-    readonly recoveryToken: unknown;
-    readonly releaseOwnership: () => void;
-  };
-  let finalizer: ((held: NodeForgottenHandle) => void) | undefined;
-  let registered: { target: object; held: NodeForgottenHandle; token?: object } | undefined;
-  const unregistered: object[] = [];
-  process.env.OLIPHAUNT_RUNTIME_DIR = runtimeDirectory;
-  process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR = callerModuleDirectory;
-  try {
-    (globalThis as { FinalizationRegistry: unknown }).FinalizationRegistry = class {
-      constructor(callback: (held: NodeForgottenHandle) => void) {
-        finalizer = callback;
-      }
-
-      register(target: object, held: NodeForgottenHandle, token?: object): void {
-        registered = { target, held, token };
-      }
-
-      unregister(token: object): boolean {
-        unregistered.push(token);
-        return true;
-      }
-    };
-    const binding = await createNodeNativeBinding({
-      libraryPath: join(root, 'liboliphaunt.dylib'),
-      nodeAddonPath: addonPath,
-    });
-    const handle = await binding.open({
-      pgdata: join(databaseRoot, 'pgdata'),
-      username: 'postgres',
-      database: 'postgres',
-      extensions: ['hstore'],
-      startupArgs: [],
-    });
-    assert.equal(handle, 41n);
-    const openConfig = calls.find(([name]) => name === 'open')?.[1] as
-      | { moduleDirectory?: string; runtimeDirectory?: string }
-      | undefined;
-    assert.equal(openConfig?.runtimeDirectory, runtimeDirectory);
-    assert.equal(openConfig?.moduleDirectory, moduleDirectory);
-    assert.equal(process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR, callerModuleDirectory);
-    assert.deepEqual([...(await binding.execProtocolRaw(handle, new Uint8Array([7, 8])))], [7, 8]);
-    const chunks: Uint8Array[] = [];
-    await binding.execProtocolStream(handle, new Uint8Array([9, 10]), (chunk) =>
-      chunks.push(chunk),
-    );
-    assert.deepEqual(
-      chunks.map((chunk) => [...chunk]),
-      [[9, 10]],
-    );
-    const execSimpleQuery = binding.execSimpleQuery;
-    assert.ok(execSimpleQuery !== undefined);
-    assert.deepEqual([...(await execSimpleQuery(handle, 'SELECT 1'))], [90, 0, 0, 0, 5, 73]);
-    assert.deepEqual([...(await binding.backup(handle))], [4, 5, 6]);
-    await binding.restore({
-      destination: join(root, 'restore'),
-      bytes: new Uint8Array([1]),
-    });
-    await binding.cancel(handle);
-
-    const forgottenOwner = {};
-    let released = 0;
-    binding.registerForgottenHandleCleanup?.(forgottenOwner, handle, () => {
-      released += 1;
-    });
-    assert.equal(registered?.target, forgottenOwner);
-    assert.equal(registered?.token, forgottenOwner);
-    assert.equal(registered?.held.recoveryToken, 'recovery-token:41');
-    finalizer?.(registered!.held);
-    assert.equal(released, 1);
-    let unsafeRelease = 0;
-    finalizer?.({
-      recoveryToken: 'stale-recovery-token',
-      releaseOwnership: () => {
-        unsafeRelease += 1;
-      },
-    });
-    assert.equal(unsafeRelease, 0, 'native recovery rejection must keep admission closed');
-
-    const explicitlyClosedOwner = {};
-    binding.registerForgottenHandleCleanup?.(explicitlyClosedOwner, handle, () => {});
-    await binding.detach(handle);
-    binding.unregisterForgottenHandleCleanup?.(explicitlyClosedOwner);
-    assert.deepEqual(unregistered, [explicitlyClosedOwner]);
-    assert.deepEqual(
-      calls.map((entry) => entry[0]),
-      [
-        'open',
-        'execProtocolRaw',
-        'execProtocolRawStream',
-        'execSimpleQuery',
-        'backup',
-        'restore',
-        'cancel',
-        'createForgottenHandleRecoveryToken',
-        'queueForgottenHandleRecovery',
-        'queueForgottenHandleRecovery',
-        'createForgottenHandleRecoveryToken',
-        'detach',
-      ],
-    );
-  } finally {
-    if (previousRuntime === undefined) {
-      delete process.env.OLIPHAUNT_RUNTIME_DIR;
-    } else {
-      process.env.OLIPHAUNT_RUNTIME_DIR = previousRuntime;
-    }
-    (globalThis as { FinalizationRegistry: unknown }).FinalizationRegistry =
-      previousFinalizationRegistry;
-    restoreEnv('OLIPHAUNT_EMBEDDED_MODULE_DIR', previousModuleDirectory);
-    delete (globalThis as { __oliphauntNodeAddonCalls?: unknown[][] }).__oliphauntNodeAddonCalls;
-    await rm(root, { recursive: true, force: true });
-  }
-}
-
-async function testDenoAssetResolverHonorsExplicitPaths(): Promise {
-  const previousRuntime = process.env.OLIPHAUNT_RUNTIME_DIR;
-  process.env.OLIPHAUNT_RUNTIME_DIR = '/tmp/oliphaunt-deno-runtime';
-  try {
-    assert.deepEqual(await resolveDenoNativeInstall('/tmp/liboliphaunt.dylib'), {
-      libraryPath: '/tmp/liboliphaunt.dylib',
-      runtimeDirectory: '/tmp/oliphaunt-deno-runtime',
-      icuDataDirectory: undefined,
-      catalogProfile: 'standard',
-      packageManaged: false,
-    });
-    await assert.rejects(async () => resolveDenoNativeInstall(), /only be used inside Deno/);
-  } finally {
-    if (previousRuntime === undefined) {
-      delete process.env.OLIPHAUNT_RUNTIME_DIR;
-    } else {
-      process.env.OLIPHAUNT_RUNTIME_DIR = previousRuntime;
-    }
-  }
-}
-
-async function testDenoNativeBindingRejectsPackageManagedExtensions(): Promise {
-  const previousDeno = (globalThis as { Deno?: unknown }).Deno;
-  const previousLibrary = process.env.LIBOLIPHAUNT_PATH;
-  const previousRuntime = process.env.OLIPHAUNT_RUNTIME_DIR;
-  const { liboliphauntVersion, icuVersion } = await readTypeScriptPackageVersions();
-  const calls: string[] = [];
-  try {
-    process.env.LIBOLIPHAUNT_PATH = '/tmp/liboliphaunt-deno-test.so';
-    delete process.env.OLIPHAUNT_RUNTIME_DIR;
-    (globalThis as { Deno?: unknown }).Deno = {
-      build: { os: 'linux', arch: 'x86_64' },
-      async readTextFile(path: string | URL) {
-        const text = String(path);
-        if (text.endsWith('/OliphauntICU.bundle/manifest.properties')) {
-          return `schema=oliphaunt-icu-data-v1\nartifactRole=icu-data\nicuDataVersion=76.1\nicuDataForm=files-le\nicuDataTreeSha256=${'a'.repeat(64)}\n`;
-        }
-        if (text.includes('@oliphaunt/icu')) {
-          return JSON.stringify({
-            name: '@oliphaunt/icu',
-            version: icuVersion,
-            oliphaunt: {
-              product: 'oliphaunt-icu',
-              kind: 'icu-data',
-              target: 'portable',
-              dataRelativePath: 'OliphauntICU.bundle/share/icu',
-              manifestRelativePath: 'OliphauntICU.bundle/manifest.properties',
-              icuDataTreeSha256: 'a'.repeat(64),
-            },
-          });
-        }
-        return JSON.stringify({
-          name: '@oliphaunt/ts',
-          oliphaunt: {
-            liboliphauntVersion,
-            icuPackage: '@oliphaunt/icu',
-            icuVersion,
-          },
-        });
-      },
-      async stat(path: string | URL) {
-        return String(path).endsWith('/manifest.properties')
-          ? { isFile: true, isDirectory: false }
-          : { isFile: false, isDirectory: true };
-      },
-      async *readDir() {
-        yield { name: 'icudt76l.dat', isFile: true };
-      },
-      dlopen(path: string, definitions: Record) {
-        calls.push(`dlopen:${path}`);
-        assert.deepEqual(definitions.oliphaunt_init_with_error, {
-          parameters: ['buffer', 'buffer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_exec_protocol_with_error, {
-          parameters: ['pointer', 'buffer', 'usize', 'buffer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_exec_simple_query_with_error, {
-          parameters: ['pointer', 'buffer', 'usize', 'buffer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_exec_protocol_raw_stream_with_error, {
-          parameters: ['pointer', 'buffer', 'usize', 'function', 'pointer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_detach_with_error, {
-          parameters: ['pointer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_logical_generation, {
-          parameters: ['pointer'],
-          result: 'u64',
-        });
-        assert.deepEqual(definitions.oliphaunt_close_if_generation, {
-          parameters: ['u64'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_copy_last_error, {
-          parameters: ['pointer', 'buffer', 'usize'],
-          result: 'usize',
-        });
-        assert.deepEqual(definitions.oliphaunt_backup_with_error, {
-          parameters: ['pointer', 'buffer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_restore_with_error, {
-          parameters: ['buffer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        return {
-          symbols: {
-            oliphaunt_init_with_error() {
-              calls.push('init');
-              return 0;
-            },
-            oliphaunt_exec_protocol_with_error() {
-              return 0;
-            },
-            oliphaunt_exec_simple_query_with_error() {
-              return 0;
-            },
-            oliphaunt_backup_with_error() {
-              return 0;
-            },
-            oliphaunt_restore_with_error() {
-              return 0;
-            },
-            oliphaunt_cancel() {
-              return 0;
-            },
-            oliphaunt_detach_with_error() {
-              return 0;
-            },
-            oliphaunt_logical_generation() {
-              return 1n;
-            },
-            oliphaunt_close_if_generation() {
-              return 1;
-            },
-            oliphaunt_copy_last_error(_handle: unknown, output: Uint8Array) {
-              output.fill(0);
-              return 0n;
-            },
-            oliphaunt_free_response() {},
-          },
-        };
-      },
-      UnsafePointer: {
-        of() {
-          throw new Error('Deno extension guard should run before pointer packing');
-        },
-        value() {
-          return 0n;
-        },
-        create() {
-          return null;
-        },
-      },
-      UnsafePointerView: class {},
-    };
-
-    const binding = await createDenoNativeBinding();
-    await assert.rejects(
-      () =>
-        Promise.resolve(
-          binding.open({
-            pgdata: '/tmp/deno-pgdata',
-            runtimeDirectory: undefined,
-            username: 'postgres',
-            database: 'postgres',
-            extensions: ['hstore'],
-            startupArgs: [],
-          }),
-        ),
-      /Deno direct execution does not automatically materialize extension packages/,
-    );
-    await assert.rejects(
-      () =>
-        Promise.resolve(
-          binding.open({
-            pgdata: '/tmp/deno-pgdata',
-            runtimeDirectory: '/tmp/deno-prepared-runtime',
-            username: 'postgres',
-            database: 'postgres',
-            extensions: ['hstore'],
-            startupArgs: [],
-          }),
-        ),
-      /Deno direct explicit runtimeDirectory is missing hstore.control/,
-    );
-    assert.deepEqual(calls, ['dlopen:/tmp/liboliphaunt-deno-test.so']);
-  } finally {
-    if (previousDeno === undefined) {
-      delete (globalThis as { Deno?: unknown }).Deno;
-    } else {
-      (globalThis as { Deno?: unknown }).Deno = previousDeno;
-    }
-    if (previousLibrary === undefined) {
-      delete process.env.LIBOLIPHAUNT_PATH;
-    } else {
-      process.env.LIBOLIPHAUNT_PATH = previousLibrary;
-    }
-    if (previousRuntime === undefined) {
-      delete process.env.OLIPHAUNT_RUNTIME_DIR;
-    } else {
-      process.env.OLIPHAUNT_RUNTIME_DIR = previousRuntime;
-    }
-  }
-}
-
-async function testDenoNativeBindingUsesSeparateModuleDirectoryWithoutAmbientMutation(): Promise {
-  const previousDeno = (globalThis as { Deno?: unknown }).Deno;
-  const previousFinalizationRegistry = globalThis.FinalizationRegistry;
-  const previousModuleDirectory = process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR;
-  const previousRuntime = process.env.OLIPHAUNT_RUNTIME_DIR;
-  const previousLibraryPath = process.env.LIBOLIPHAUNT_PATH;
-  const previousLibrarySearchPath = process.env.LD_LIBRARY_PATH;
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-deno-config-'));
-  const databaseRoot = join(root, 'database');
-  const runtime = join(root, 'runtime');
-  const embeddedModules = join(runtime, 'lib/modules');
-  const pointerStrings = new Map();
-  let nextPointer = 0x1000n;
-  const calls: string[] = [];
-  let copyLastErrorCalls = 0;
-  let restoreCallsStartedResolve: (() => void) | undefined;
-  let releaseRestoreCalls: (() => void) | undefined;
-  let restoreCallCount = 0;
-  let rejectInit = false;
-  let initFailure: unknown;
-  let initStatus = 0;
-  let initHandleAddress = 0x99n;
-  let logicalGeneration = 23n;
-  let rejectDetach = false;
-  let detachFailure: unknown;
-  let generationCleanupStatus = 1;
-  const restoreCallsStarted = new Promise((resolve) => {
-    restoreCallsStartedResolve = resolve;
-  });
-  const restoreCallsMayFinish = new Promise((resolve) => {
-    releaseRestoreCalls = resolve;
-  });
-  let finalizer: ((held: { generation: bigint; releaseOwnership: () => void }) => void) | undefined;
-  let registered:
-    | {
-        target: object;
-        held: { generation: bigint; releaseOwnership: () => void };
-        token?: object;
-      }
-    | undefined;
-  const unregistered: object[] = [];
-  try {
-    (globalThis as { FinalizationRegistry: unknown }).FinalizationRegistry = class {
-      constructor(callback: (held: { generation: bigint; releaseOwnership: () => void }) => void) {
-        finalizer = callback;
-      }
-
-      register(
-        target: object,
-        held: { generation: bigint; releaseOwnership: () => void },
-        token?: object,
-      ): void {
-        registered = { target, held, token };
-      }
-
-      unregister(token: object): boolean {
-        unregistered.push(token);
-        return true;
-      }
-    };
-    delete process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR;
-    delete process.env.OLIPHAUNT_RUNTIME_DIR;
-    delete process.env.LIBOLIPHAUNT_PATH;
-    await fsMkdir(join(databaseRoot, 'pgdata', 'global'), { recursive: true });
-    await fsMkdir(join(databaseRoot, 'pgdata', 'pg_wal'));
-    await writeFile(join(databaseRoot, 'pgdata', 'PG_VERSION'), '18\n');
-    await writeFile(join(databaseRoot, 'pgdata', 'global', 'pg_control'), 'control');
-    await publishNativeDescriptor(databaseRoot);
-    await fsMkdir(join(runtime, 'share/postgresql/extension'), {
-      recursive: true,
-    });
-    await fsMkdir(join(runtime, 'lib/postgresql'), { recursive: true });
-    await fsMkdir(embeddedModules, { recursive: true });
-    await writeFile(join(runtime, 'share/postgresql/extension/hstore.control'), 'extension');
-    await writeFile(join(runtime, 'share/postgresql/extension/hstore--1.0.sql'), 'install');
-    await writeFile(join(runtime, 'lib/postgresql/hstore.so'), 'subprocess hstore');
-    await writeFile(join(runtime, 'lib/postgresql/dict_snowball.so'), 'subprocess dict_snowball');
-    await writeFile(join(runtime, 'lib/postgresql/plpgsql.so'), 'subprocess plpgsql');
-    await writeFile(join(embeddedModules, 'hstore.so'), 'embedded hstore');
-    await writeFile(join(embeddedModules, 'dict_snowball.so'), 'embedded dict_snowball');
-    await writeFile(join(embeddedModules, 'plpgsql.so'), 'embedded plpgsql');
-
-    const deno = fsBackedDenoRuntime(root) as Record;
-    (globalThis as { Deno?: unknown }).Deno = {
-      ...deno,
-      dlopen(_path: string, definitions: Record) {
-        assert.deepEqual(definitions.oliphaunt_init_with_error, {
-          parameters: ['buffer', 'buffer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_exec_protocol_raw_stream_with_error, {
-          parameters: ['pointer', 'buffer', 'usize', 'function', 'pointer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_detach_with_error, {
-          parameters: ['pointer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_logical_generation, {
-          parameters: ['pointer'],
-          result: 'u64',
-        });
-        assert.deepEqual(definitions.oliphaunt_close_if_generation, {
-          parameters: ['u64'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_copy_last_error, {
-          parameters: ['pointer', 'buffer', 'usize'],
-          result: 'usize',
-        });
-        assert.deepEqual(definitions.oliphaunt_backup_with_error, {
-          parameters: ['pointer', 'buffer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        assert.deepEqual(definitions.oliphaunt_restore_with_error, {
-          parameters: ['buffer', 'buffer'],
-          result: 'i32',
-          nonblocking: true,
-        });
-        return {
-          symbols: {
-            async oliphaunt_init_with_error(config: Uint8Array, out: Uint8Array) {
-              calls.push('init');
-              if (rejectInit) throw initFailure;
-              assert.equal(process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR, undefined);
-              const view = new DataView(config.buffer, config.byteOffset, config.byteLength);
-              assert.equal(view.getUint32(0, true), ABI_VERSION);
-              assert.equal(pointerStrings.get(view.getBigUint64(24, true)), embeddedModules);
-              new DataView(out.buffer, out.byteOffset, out.byteLength).setBigUint64(
-                0,
-                initHandleAddress,
-                true,
-              );
-              return initStatus;
-            },
-            oliphaunt_exec_protocol_with_error() {
-              return 0;
-            },
-            oliphaunt_exec_protocol_raw_stream_with_error(
-              _handle: unknown,
-              request: Uint8Array,
-              _requestLength: bigint,
-              callback: (context: unknown, bytes: unknown, length: bigint) => number,
-              context: unknown,
-              captured: Uint8Array,
-            ) {
-              const callbackStatus = callback(context, null, 0n);
-              if (request[0] === 4) {
-                assert.equal(callbackStatus, 0);
-                return 1;
-              }
-              assert.equal(callbackStatus, 1);
-              if (request[0] === 3) return 0;
-              if (request[0] === 1) {
-                writeErrorCapture(captured, 'stream callback aborted after confirmed recovery');
-                return 1;
-              }
-              writeErrorCapture(captured, 'stream transport recovery failed');
-              return -1;
-            },
-            oliphaunt_exec_simple_query_with_error() {
-              return 0;
-            },
-            oliphaunt_backup_with_error() {
-              return 0;
-            },
-            async oliphaunt_restore_with_error(options: Uint8Array, captured: Uint8Array) {
-              const view = new DataView(options.buffer, options.byteOffset, options.byteLength);
-              const destination = pointerStrings.get(view.getBigUint64(8, true));
-              assert.ok(destination);
-              restoreCallCount += 1;
-              if (restoreCallCount === 2) restoreCallsStartedResolve?.();
-              await restoreCallsMayFinish;
-              writeErrorCapture(captured, `${destination} failed on its native worker`);
-              return -1;
-            },
-            oliphaunt_cancel() {
-              return 0;
-            },
-            async oliphaunt_detach_with_error(_handle: unknown, _captured: Uint8Array) {
-              calls.push('detach');
-              if (rejectDetach) throw detachFailure;
-              return 0;
-            },
-            oliphaunt_logical_generation() {
-              calls.push('logical-generation');
-              return logicalGeneration;
-            },
-            oliphaunt_close_if_generation(generation: bigint) {
-              calls.push(`close-generation:${generation}`);
-              return generationCleanupStatus;
-            },
-            oliphaunt_copy_last_error(_handle: unknown, output: Uint8Array) {
-              copyLastErrorCalls += 1;
-              output.fill(0);
-              return 0n;
-            },
-            oliphaunt_free_response() {},
-          },
-        };
-      },
-      UnsafePointer: {
-        of(value: Uint8Array) {
-          nextPointer += 0x10n;
-          pointerStrings.set(
-            nextPointer,
-            new TextDecoder().decode(value.subarray(0, Math.max(0, value.byteLength - 1))),
-          );
-          return { address: nextPointer };
-        },
-        value(pointer: { address: bigint }) {
-          return pointer.address;
-        },
-        create(address: bigint) {
-          return { address };
-        },
-      },
-      UnsafePointerView: class {},
-      UnsafeCallback: {
-        threadSafe(_definition: unknown, callback: unknown) {
-          return {
-            pointer: callback,
-            close() {},
-          };
-        },
-      },
-    };
-
-    const binding = await createDenoNativeBinding({
-      libraryPath: join(root, 'liboliphaunt.so'),
-    });
-    const handle = await binding.open({
-      pgdata: join(databaseRoot, 'pgdata'),
-      runtimeDirectory: runtime,
-      username: 'postgres',
-      database: 'postgres',
-      extensions: ['hstore'],
-      startupArgs: [],
-    });
-    assert.deepEqual(handle, { address: 0x99n });
-    assert.deepEqual(calls, ['init', 'logical-generation']);
-
-    await assert.rejects(
-      () =>
-        binding.execProtocolStream(handle, new Uint8Array([1]), () => {
-          throw new Error('Deno stream callback failed');
-        }),
-      /Deno stream callback failed/,
-    );
-    const undefinedCallbackFailure = await binding
-      .execProtocolStream(handle, new Uint8Array([1]), () => {
-        throw undefined;
-      })
-      .then(
-        () => ({ fulfilled: true as const, error: undefined }),
-        (error: unknown) => ({ fulfilled: false as const, error }),
-      );
-    assert.equal(undefinedCallbackFailure.fulfilled, false);
-    assert.equal(
-      undefinedCallbackFailure.error,
-      undefined,
-      'a recovered Deno callback abort must preserve even an undefined rejection reason',
-    );
-    await assert.rejects(
-      () =>
-        binding.execProtocolStream(handle, new Uint8Array([3]), () => {
-          throw undefined;
-        }),
-      /reported success after the callback failed/,
-    );
-    await assert.rejects(
-      () => binding.execProtocolStream(handle, new Uint8Array([4]), () => undefined),
-      /reported a recovered callback abort without a callback failure/,
-    );
-    await assert.rejects(
-      () =>
-        binding.execProtocolStream(handle, new Uint8Array([2]), () => {
-          throw new Error('this callback failure must not mask native recovery');
-        }),
-      /stream transport recovery failed/,
-    );
-
-    const firstRestore = binding.restore({
-      destination: '/tmp/first-restore',
-      bytes: new Uint8Array([1]),
-    });
-    const secondRestore = binding.restore({
-      destination: '/tmp/second-restore',
-      bytes: new Uint8Array([2]),
-    });
-    await restoreCallsStarted;
-    releaseRestoreCalls?.();
-    const restoreResults = await Promise.allSettled([firstRestore, secondRestore]);
-    assert.equal(restoreResults[0]?.status, 'rejected');
-    assert.equal(restoreResults[1]?.status, 'rejected');
-    assert.match(
-      String((restoreResults[0] as PromiseRejectedResult).reason),
-      /\/tmp\/first-restore failed on its native worker/,
-    );
-    assert.match(
-      String((restoreResults[1] as PromiseRejectedResult).reason),
-      /\/tmp\/second-restore failed on its native worker/,
-    );
-    assert.equal(
-      copyLastErrorCalls,
-      0,
-      'nonblocking Deno failures must not read worker-local errors later on the JS thread',
-    );
-
-    const forgottenOwner = {};
-    let released = 0;
-    binding.registerForgottenHandleCleanup?.(forgottenOwner, handle, () => {
-      released += 1;
-    });
-    assert.equal(registered?.target, forgottenOwner);
-    assert.equal(registered?.token, forgottenOwner);
-    assert.equal(registered?.held.generation, 23n);
-    finalizer?.(registered!.held);
-    assert.equal(released, 0, 'the finalizer must return before native cleanup settles');
-    await new Promise((resolve) => setImmediate(resolve));
-    assert.equal(released, 1);
-    assert.deepEqual(calls, ['init', 'logical-generation', 'close-generation:23']);
-
-    const failedCleanupOwner = {};
-    let releasedAfterFailedCleanup = 0;
-    generationCleanupStatus = -1;
-    binding.registerForgottenHandleCleanup?.(failedCleanupOwner, handle, () => {
-      releasedAfterFailedCleanup += 1;
-    });
-    finalizer?.(registered!.held);
-    await new Promise((resolve) => setImmediate(resolve));
-    assert.equal(
-      releasedAfterFailedCleanup,
-      0,
-      'failed native generation cleanup must keep direct admission closed',
-    );
-    assert.equal(calls.at(-1), 'close-generation:23');
-
-    const explicitlyClosedOwner = {};
-    binding.registerForgottenHandleCleanup?.(explicitlyClosedOwner, handle, () => {});
-    await binding.detach(handle);
-    binding.unregisterForgottenHandleCleanup?.(explicitlyClosedOwner);
-    assert.deepEqual(unregistered, [explicitlyClosedOwner]);
-    assert.equal(calls.at(-1), 'detach');
-
-    calls.length = 0;
-    const openConfig = {
-      pgdata: join(databaseRoot, 'pgdata'),
-      runtimeDirectory: runtime,
-      username: 'postgres',
-      database: 'postgres',
-      extensions: ['hstore'],
-      startupArgs: [],
-    };
-
-    const uncertainHandle = await binding.open(openConfig);
-    rejectDetach = true;
-    detachFailure = new Error('Deno detach worker delivery rejected');
-    const uncertainClose = await directRuntimeBinding(binding).close(uncertainHandle);
-    assert.equal(uncertainClose.state, 'terminal');
-    assert.match(
-      String(uncertainClose.error),
-      /detach delivery failed after its outcome became unknown/,
-    );
-    assert.equal((uncertainClose.error as Error).cause, detachFailure);
-    await assert.rejects(
-      () => binding.detach(uncertainHandle),
-      (error: unknown) => error === uncertainClose.error,
-    );
-    await assert.rejects(
-      () => binding.open(openConfig),
-      /prior native lifecycle outcome left ownership unknown/,
-    );
-    assert.deepEqual(
-      calls,
-      ['init', 'logical-generation', 'detach'],
-      'an outcome-unknown detach is terminal, cannot be retried, and closes admission before another init',
-    );
-
-    const createFreshBinding = async () => {
-      vi.resetModules();
-      const freshDeno = await import('../native/deno.js');
-      return freshDeno.createDenoNativeBinding({
-        libraryPath: join(root, 'liboliphaunt.so'),
-      });
-    };
-
-    calls.length = 0;
-    rejectInit = false;
-    initStatus = -1;
-    initHandleAddress = 0x99n;
-    logicalGeneration = 23n;
-    rejectDetach = false;
-    detachFailure = undefined;
-    let freshBinding = await createFreshBinding();
-    await assert.rejects(() => freshBinding.open(openConfig), /native liboliphaunt init failed/);
-    initStatus = 0;
-    const retryHandle = await freshBinding.open(openConfig);
-    await freshBinding.detach(retryHandle);
-    assert.deepEqual(
-      calls,
-      ['init', 'init', 'logical-generation', 'detach'],
-      'a confirmed nonzero init status remains retryable',
-    );
-
-    calls.length = 0;
-    rejectInit = true;
-    initStatus = 0;
-    initFailure = new Error('Deno init worker delivery rejected');
-    rejectDetach = false;
-    detachFailure = undefined;
-    initHandleAddress = 0x99n;
-    logicalGeneration = 23n;
-    freshBinding = await createFreshBinding();
-    await assert.rejects(
-      () => freshBinding.open(openConfig),
-      (error) => error === initFailure,
-    );
-    await assert.rejects(
-      () => freshBinding.open(openConfig),
-      /prior native lifecycle outcome left ownership unknown/,
-    );
-    assert.deepEqual(calls, ['init'], 'a rejected init worker must close admission immediately');
-
-    calls.length = 0;
-    rejectInit = false;
-    initHandleAddress = 0n;
-    freshBinding = await createFreshBinding();
-    await assert.rejects(() => freshBinding.open(openConfig), /init returned a null handle/);
-    await assert.rejects(
-      () => freshBinding.open(openConfig),
-      /prior native lifecycle outcome left ownership unknown/,
-    );
-    assert.deepEqual(calls, ['init'], 'a null successful init must close admission immediately');
-
-    calls.length = 0;
-    initHandleAddress = 0x99n;
-    logicalGeneration = 0n;
-    freshBinding = await createFreshBinding();
-    await assert.rejects(() => freshBinding.open(openConfig), /invalid logical generation/);
-    await assert.rejects(
-      () => freshBinding.open(openConfig),
-      /prior native lifecycle outcome left ownership unknown/,
-    );
-    assert.deepEqual(
-      calls,
-      ['init', 'logical-generation'],
-      'an invalid generation must close admission without dereferencing the handle',
-    );
-  } finally {
-    if (previousDeno === undefined) {
-      delete (globalThis as { Deno?: unknown }).Deno;
-    } else {
-      (globalThis as { Deno?: unknown }).Deno = previousDeno;
-    }
-    (globalThis as { FinalizationRegistry: unknown }).FinalizationRegistry =
-      previousFinalizationRegistry;
-    restoreEnv('OLIPHAUNT_EMBEDDED_MODULE_DIR', previousModuleDirectory);
-    restoreEnv('OLIPHAUNT_RUNTIME_DIR', previousRuntime);
-    restoreEnv('LIBOLIPHAUNT_PATH', previousLibraryPath);
-    restoreEnv('LD_LIBRARY_PATH', previousLibrarySearchPath);
-    await rm(root, { recursive: true, force: true });
-  }
-}
-
-async function testDenoPackageManagedResolverUsesStandardCarrierRuntime(): Promise {
-  const previousDeno = (globalThis as { Deno?: unknown }).Deno;
-  const previousLibraryPath = process.env.LIBOLIPHAUNT_PATH;
-  const previousRuntimeDir = process.env.OLIPHAUNT_RUNTIME_DIR;
-  const target = liboliphauntPackageTarget('linux', 'x86_64');
-  const runtimePackageRoot = packageRoot(target.packageName);
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-deno-runtime-'));
-  const createdFiles: string[] = [];
-  try {
-    delete process.env.LIBOLIPHAUNT_PATH;
-    delete process.env.OLIPHAUNT_RUNTIME_DIR;
-    (globalThis as { Deno?: unknown }).Deno = fsBackedDenoRuntime(root);
-
-    await writeFixtureFile(
-      join(runtimePackageRoot, target.libraryRelativePath),
-      'liboliphaunt-test',
-      createdFiles,
-    );
-    const runtimeBin = join(runtimePackageRoot, target.runtimeRelativePath, 'bin');
-    for (const tool of nativeRuntimeToolsForTarget(target.id)) {
-      await writeFixtureFile(join(runtimeBin, tool), `runtime:${tool}`, createdFiles);
-    }
-    await writeClusterSeedFixture(
-      join(runtimePackageRoot, 'cluster-seed'),
-      'standard',
-      target.id,
-      createdFiles,
-    );
-    const install = await resolveDenoNativeInstall();
-    assert.equal(install.libraryPath, join(runtimePackageRoot, target.libraryRelativePath));
-    assert.equal(install.packageManaged, true);
-    assert.equal(install.runtimeDirectory, join(runtimePackageRoot, target.runtimeRelativePath));
-  } finally {
-    if (previousDeno === undefined) {
-      delete (globalThis as { Deno?: unknown }).Deno;
-    } else {
-      (globalThis as { Deno?: unknown }).Deno = previousDeno;
-    }
-    restoreEnv('LIBOLIPHAUNT_PATH', previousLibraryPath);
-    restoreEnv('OLIPHAUNT_RUNTIME_DIR', previousRuntimeDir);
-    await rm(root, { recursive: true, force: true });
-    await removeFixtureFiles(createdFiles, [runtimePackageRoot]);
-  }
-}
-
-function fsBackedDenoRuntime(tempRoot: string): unknown {
-  return {
-    build: { os: 'linux', arch: 'x86_64' },
-    env: {
-      get(name: string) {
-        return name === 'TMPDIR' ? tempRoot : undefined;
-      },
-    },
-    async readTextFile(path: string | URL) {
-      return readFile(fsPath(path), 'utf8');
-    },
-    async *readDir(path: string | URL) {
-      for (const entry of await readdir(fsPath(path), {
-        withFileTypes: true,
-      })) {
-        yield {
-          name: entry.name,
-          isFile: entry.isFile(),
-          isDirectory: entry.isDirectory(),
-        };
-      }
-    },
-    async stat(path: string | URL) {
-      const metadata = await fsStat(fsPath(path));
-      return {
-        isFile: metadata.isFile(),
-        isDirectory: metadata.isDirectory(),
-      };
-    },
-  };
-}
-
-function writeErrorCapture(capture: Uint8Array, message: string): void {
-  capture.fill(0);
-  const bytes = new TextEncoder().encode(message);
-  assert.ok(bytes.byteLength < OLIPHAUNT_ERROR_CAPTURE_CAPACITY);
-  new DataView(capture.buffer, capture.byteOffset, capture.byteLength).setUint32(
-    0,
-    bytes.byteLength,
-    true,
-  );
-  capture.set(bytes, 4);
-}
-
-function fsPath(path: string | URL): string {
-  return path instanceof URL ? fileURLToPath(path) : path;
-}
-
-const require = createRequire(import.meta.url);
-
-function packageRoot(packageName: string): string {
-  return dirname(require.resolve(`${packageName}/package.json`));
-}
-
-async function writeFixtureFile(
-  path: string,
-  contents: string,
-  createdFiles: string[],
-): Promise {
-  try {
-    await readFile(path);
-    return;
-  } catch {}
-  await fsMkdir(dirname(path), { recursive: true });
-  await writeFile(path, contents, 'utf8');
-  createdFiles.push(path);
-}
-
-async function writeClusterSeedFixture(
-  root: string,
-  profile: 'standard' | 'icu',
-  target: string,
-  createdFiles: string[],
-): Promise {
-  if (profile === 'standard') {
-    await writeFixtureFile(
-      join(dirname(root), 'manifest.properties'),
-      `schema=oliphaunt-native-runtime-carrier-v1\nclusterSeedTarget=${target}\nclusterSeedRelativePath=cluster-seed\nicuClusterSeedRelativePath=cluster-seed-icu\n`,
-      createdFiles,
-    );
-  }
-  await writeFixtureFile(join(root, 'files', 'PG_VERSION'), '18\n', createdFiles);
-  await writeFixtureFile(join(root, 'files', 'global', 'pg_control'), 'control', createdFiles);
-  await writeFixtureFile(
-    join(root, 'manifest.properties'),
-    `schema=oliphaunt-runtime-resources-v1\nlayout=oliphaunt-cluster-seed-v1\nartifactRole=cluster-seed-${profile}\ncatalogProfile=${profile}\ntarget=${target}\npostgresMajor=18\nphysicalFormat=native-pg18-v1\ncompatibilityKey=native-pg18-${target}-v1\ninitialSuperuser=postgres\nicuDataVersion=${profile === 'icu' ? '76.1' : ''}\nicuDataForm=${profile === 'icu' ? 'files-le' : ''}\nicuDataTreeSha256=${profile === 'icu' ? 'a'.repeat(64) : ''}\nruntimeFeatures=${profile === 'icu' ? 'icu' : ''}\ncacheKey=fixture-seed\n`,
-    createdFiles,
-  );
-}
-
-async function removeFixtureFiles(files: string[], stopRoots: string[]): Promise {
-  for (const file of files.reverse()) {
-    await rm(file, { force: true });
-    await removeEmptyParents(dirname(file), stopRoots);
-  }
-}
-
-async function removeEmptyParents(directory: string, stopRoots: string[]): Promise {
-  const stops = new Set(stopRoots.map((stopRoot) => resolve(stopRoot)));
-  let current = resolve(directory);
-  while (!stops.has(current)) {
-    try {
-      await rmdir(current);
-    } catch {
-      return;
-    }
-    current = dirname(current);
-  }
-}
-
-function nativeRuntimeToolsForTarget(target: string): string[] {
-  return target === 'windows-x64-msvc'
-    ? ['initdb.exe', 'pg_ctl.exe', 'postgres.exe']
-    : ['initdb', 'pg_ctl', 'postgres'];
-}
-
-function restoreEnv(name: string, value: string | undefined): void {
-  if (value === undefined) {
-    delete process.env[name];
-  } else {
-    process.env[name] = value;
-  }
-}
-
-test('native bindings', async () => {
-  await main();
-});
diff --git a/src/sdks/js/src/__tests__/native-cluster-seed-contract.test.ts b/src/sdks/js/src/__tests__/native-cluster-seed-contract.test.ts
deleted file mode 100644
index 7cff04327..000000000
--- a/src/sdks/js/src/__tests__/native-cluster-seed-contract.test.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import { readFile } from 'node:fs/promises';
-import { describe, expect, test } from 'vitest';
-
-import { validateNativeClusterSeedManifest } from '../native/cluster-seed.js';
-
-const FIXTURE_ROOT = new URL('../../../../shared/cluster-seed-contract/fixtures/', import.meta.url);
-
-async function fixture(name: string): Promise {
-  return readFile(new URL(name, FIXTURE_ROOT), 'utf8');
-}
-
-describe('shared native cluster seed contract fixtures', () => {
-  test('accepts the canonical standard and ICU manifests', async () => {
-    expect(
-      validateNativeClusterSeedManifest(
-        await fixture('native-standard.valid.properties'),
-        'standard',
-        'linux-x64-gnu',
-        'shared standard fixture',
-      ),
-    ).toBeUndefined();
-    expect(
-      validateNativeClusterSeedManifest(
-        await fixture('native-icu.valid.properties'),
-        'icu',
-        'linux-x64-gnu',
-        'shared ICU fixture',
-      ),
-    ).toBe('a'.repeat(64));
-  });
-
-  test('rejects the canonical invalid vectors', async () => {
-    for (const name of [
-      'native-malformed.invalid.properties',
-      'native-whitespace.invalid.properties',
-      'native-cache-key.invalid.properties',
-      'native-dot-cache-key.invalid.properties',
-      'native-dotdot-cache-key.invalid.properties',
-      'native-extra-field.invalid.properties',
-      'native-target-mismatch.invalid.properties',
-      'native-profile-mismatch.invalid.properties',
-    ]) {
-      const manifest = await fixture(name);
-      expect(
-        () => validateNativeClusterSeedManifest(manifest, 'standard', 'linux-x64-gnu', name),
-        name,
-      ).toThrow();
-    }
-  });
-});
diff --git a/src/sdks/js/src/__tests__/native-direct-contract.mjs b/src/sdks/js/src/__tests__/native-direct-contract.mjs
deleted file mode 100644
index 36232e978..000000000
--- a/src/sdks/js/src/__tests__/native-direct-contract.mjs
+++ /dev/null
@@ -1,83 +0,0 @@
-import assert from 'node:assert/strict';
-import { mkdtemp, readFile, rm } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
-
-export async function assertNativeDatabaseContract(Oliphaunt, config, label) {
-  const root = await mkdtemp(join(tmpdir(), `oliphaunt-js-${label}-`));
-  let database;
-  try {
-    database = await Oliphaunt.open({
-      ...config,
-      storage: { kind: 'directory', path: root },
-    });
-    await assertStructuredQueryContract(database, label);
-    await assertOrmSurfaceContract(database, label);
-    const backup = await database.backup();
-    assert.ok(backup.byteLength > 0);
-    await assertStructuredQueryContract(database, label);
-    await database.close();
-    database = undefined;
-
-    const restoredRoot = join(root, 'restored');
-    await Oliphaunt.restore(restoredRoot, backup);
-    assert.match(await readFile(join(restoredRoot, 'pgdata', 'PG_VERSION'), 'utf8'), /^18\s*$/u);
-    database = await Oliphaunt.open({
-      ...config,
-      storage: { kind: 'directory', path: restoredRoot },
-    });
-    await assertStructuredQueryContract(database, label);
-    await database.close();
-    database = undefined;
-
-    await assert.rejects(
-      Oliphaunt.restore(join(root, 'invalid'), backup.subarray(0, 8)),
-      (error) => error instanceof Error && error.message.length > 0,
-    );
-  } finally {
-    await database?.close().catch(() => {});
-    await rm(root, { recursive: true, force: true });
-  }
-}
-
-async function assertStructuredQueryContract(database, label) {
-  const sql = `SELECT '${label}'::text AS value`;
-  const decoded = await database.query(sql);
-  assert.deepEqual(decoded.rows, [{ value: label }]);
-
-  const positional = await database.query(sql, [], { rowMode: 'array' });
-  assert.deepEqual(positional.rows, [[label]]);
-
-  const raw = await database.queryRaw(sql);
-  assert.equal(raw.getText(0, 'value'), label);
-}
-
-async function assertOrmSurfaceContract(database, label) {
-  const decoded = await database.query(
-    'SELECT $1::text AS label, $2::int8 AS wide, $3::jsonb AS document, $4::int4[] AS numbers',
-    [label, 9007199254740993n, { ok: true }, [1, 2, 3]],
-  );
-  assert.deepEqual(decoded.rows, [
-    {
-      label,
-      wide: '9007199254740993',
-      document: { ok: true },
-      numbers: [1, 2, 3],
-    },
-  ]);
-
-  const custom = await database.query('SELECT 42::int4 AS answer', [], {
-    decoders: { 23: (value, field) => `custom:${value}:${field.typeOid}` },
-  });
-  assert.deepEqual(custom.rows, [{ answer: 'custom:42:23' }]);
-
-  const description = await database.describe('SELECT $1::int4 AS answer');
-  assert.deepEqual(description.parameterTypeOids, [23]);
-  assert.equal(description.fields?.[0]?.typeOid, 23);
-
-  const execution = await database.exec('SELECT 1::int4 AS first; SELECT 2::int4 AS second');
-  assert.deepEqual(
-    execution.statements.map((statement) => statement.rows),
-    [[{ first: 1 }], [{ second: 2 }]],
-  );
-}
diff --git a/src/sdks/js/src/__tests__/native-smoke.ts b/src/sdks/js/src/__tests__/native-smoke.ts
deleted file mode 100644
index 48d4fe77f..000000000
--- a/src/sdks/js/src/__tests__/native-smoke.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import assert from 'node:assert/strict';
-import { mkdtemp, rm } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { dirname, join } from 'node:path';
-
-import { Oliphaunt } from '../index.js';
-import { simpleQuery } from '../protocol.js';
-import { parseSimpleQueryRawResponse } from '../query.js';
-import { PostgresWireClient } from '../runtime/pgwire.js';
-import { assertNativeDatabaseContract } from './native-direct-contract.mjs';
-
-async function main(): Promise {
-  const libraryPath = requiredEnv('LIBOLIPHAUNT_PATH');
-  await assertNativeDatabaseContract(Oliphaunt, { topology: 'direct', libraryPath }, 'node-direct');
-  const brokerExecutable = process.env.OLIPHAUNT_BROKER;
-  if (brokerExecutable) {
-    await assertNativeDatabaseContract(
-      Oliphaunt,
-      { topology: 'broker', libraryPath, brokerExecutable },
-      'broker',
-    );
-  }
-  const serverExecutable = process.env.OLIPHAUNT_POSTGRES;
-  if (serverExecutable) {
-    const roots = await Promise.all([
-      mkdtemp(join(tmpdir(), 'oliphaunt-js-native-server-first-')),
-      mkdtemp(join(tmpdir(), 'oliphaunt-js-native-server-second-')),
-    ]);
-    try {
-      const systemIdentifiers: string[] = [];
-      for (const [index, root] of roots.entries()) {
-        const server = await Oliphaunt.openServer({
-          storage: { kind: 'directory', path: root },
-          serverExecutable,
-          runtimeDirectory: process.env.OLIPHAUNT_POSTGRES_TOOL_DIR ?? dirname(serverExecutable),
-        });
-        try {
-          assert.match(server.connectionString, /^postgresql:\/\//u);
-          assert.equal('query' in server, false);
-          assert.equal('cancel' in server, false);
-          assert.equal('backup' in server, false);
-          const connection = await connectToServer(server.connectionString);
-          let identifier: string | null;
-          try {
-            if (index === 0) {
-              const one = parseSimpleQueryRawResponse(
-                await connection.execProtocolRaw(simpleQuery('SELECT 1 AS value')),
-              );
-              assert.equal(one.getText(0, 'value'), '1');
-            }
-            identifier = parseSimpleQueryRawResponse(
-              await connection.execProtocolRaw(
-                simpleQuery(
-                  'SELECT system_identifier::text AS system_identifier FROM pg_control_system()',
-                ),
-              ),
-            ).getText(0, 'system_identifier');
-          } finally {
-            await connection.terminate();
-          }
-          assert.match(identifier ?? '', /^\d+$/u);
-          assert.ok(identifier !== null);
-          systemIdentifiers.push(identifier);
-        } finally {
-          await server.close();
-        }
-      }
-      assert.notEqual(
-        systemIdentifiers[0],
-        systemIdentifiers[1],
-        'independent fresh server roots must not clone one PostgreSQL system identifier',
-      );
-    } finally {
-      await Promise.all(roots.map((root) => rm(root, { recursive: true, force: true })));
-    }
-  }
-}
-
-async function connectToServer(connectionString: string): Promise {
-  const endpoint = new URL(connectionString);
-  if (endpoint.hostname.length === 0) {
-    throw new Error('native server smoke requires a TCP connection string');
-  }
-  return PostgresWireClient.connect(
-    {
-      kind: 'tcp',
-      host: endpoint.hostname,
-      port: Number.parseInt(endpoint.port, 10),
-    },
-    decodeURIComponent(endpoint.username),
-    decodeURIComponent(endpoint.pathname.slice(1)),
-  );
-}
-
-function requiredEnv(name: string): string {
-  const value = process.env[name];
-  if (!value) throw new Error(`${name} is required for the TypeScript SDK native smoke check`);
-  return value;
-}
-
-await main();
diff --git a/src/sdks/js/src/__tests__/public-api.test.ts b/src/sdks/js/src/__tests__/public-api.test.ts
deleted file mode 100644
index 260518ef6..000000000
--- a/src/sdks/js/src/__tests__/public-api.test.ts
+++ /dev/null
@@ -1,156 +0,0 @@
-import assert from 'node:assert/strict';
-import { test } from 'vitest';
-
-import {
-  array,
-  binary,
-  json,
-  Oliphaunt,
-  PostgresError,
-  postgresOids,
-  text,
-  typedNull,
-  type BinaryQueryParameter,
-  type DescribeResult,
-  type EncodedQueryParameter,
-  type ExecResult,
-  type NullQueryParameter,
-  type OliphauntDatabase,
-  type OliphauntServer,
-  type OliphauntTransaction,
-  type OpenConfig,
-  type QueryArrayRow,
-  type QueryObjectRow,
-  type QueryResult,
-  type QueryParam,
-  type QueryValue,
-  type RawQueryResult,
-  type RestoreOptions,
-  type TextQueryParameter,
-} from '../index.js';
-
-test('root entrypoint publishes the ORM-facing values', () => {
-  assert.equal(typeof Oliphaunt.open, 'function');
-  assert.equal(typeof PostgresError, 'function');
-  assert.equal(postgresOids.jsonb, 3802);
-  assert.equal(text('value', postgresOids.text).format, 'text');
-  assert.equal(binary(Uint8Array.of(1), postgresOids.bytea).format, 'binary');
-  assert.equal(json({ ok: true }).typeOid, postgresOids.jsonb);
-  assert.equal(array([1, 2], postgresOids.int4Array).typeOid, postgresOids.int4Array);
-  assert.equal(typedNull(postgresOids.uuid).format, 'null');
-});
-
-const canonicalPostgresError = new PostgresError([
-  { code: 0x43, value: '22000' },
-  { code: 0x4d, value: 'invalid value' },
-]);
-const canonicalSqlstate: string | undefined = canonicalPostgresError.sqlstate;
-const canonicalMessage: string = canonicalPostgresError.message;
-void [canonicalSqlstate, canonicalMessage];
-
-// Compile-time proof from the external root surface. Keeping this function
-// uncalled verifies declarations without needing a native runtime in the test.
-function assertPublicDatabaseTypes(
-  database: OliphauntDatabase,
-  server: OliphauntServer,
-  transaction: OliphauntTransaction,
-): void {
-  const decoded: Promise> = database.query<{
-    value: number;
-  }>('SELECT $1::int4 AS value', [1], { rowMode: 'object' });
-  const raw: Promise = database.queryRaw('SELECT $1::bytea', [
-    binary(Uint8Array.of(1), postgresOids.bytea),
-  ]);
-  const execution: Promise> = database.exec(
-    'SELECT 1',
-    { rowMode: 'array' },
-  );
-  const inferredArrays: Promise> = database.query('SELECT 1', [], {
-    rowMode: 'array',
-  });
-  const inferredDecoder: Promise>> = database.query(
-    'SELECT now()',
-    [],
-    { decoders: { [postgresOids.timestamptz]: (value) => new Date(value) } },
-  );
-  const description: Promise = database.describe('SELECT $1', [postgresOids.int4]);
-  const streamed: Promise = database.execProtocolRawStream(
-    Uint8Array.of(0x51),
-    () => undefined,
-  );
-  // @ts-expect-error Stream callbacks are synchronous backpressure acknowledgements.
-  const asyncStreamed = database.execProtocolRawStream(Uint8Array.of(0x51), async () => {});
-  const widenedAsyncCallback: (chunk: Uint8Array) => unknown = async () => {};
-  const widenedAsyncStreamed = database.execProtocolRawStream(
-    Uint8Array.of(0x51),
-    // @ts-expect-error Widening an async callback must not bypass the synchronous contract.
-    widenedAsyncCallback,
-  );
-  // @ts-expect-error Raw protocol is database/root-only; it bypasses callback transaction ownership.
-  const transactionBuffered = transaction.execProtocolRaw(Uint8Array.of(0x51));
-  // @ts-expect-error Raw protocol is database/root-only; it bypasses callback transaction ownership.
-  const transactionStreamed = transaction.execProtocolRawStream(
-    Uint8Array.of(0x51),
-    () => undefined,
-  );
-  const rollback: Promise = transaction.rollback();
-  const serverConnectionString: string = server.connectionString;
-  const serverClose: Promise = server.close();
-  // @ts-expect-error Server handles own lifecycle, not a privileged database connection.
-  const serverQuery = server.query('SELECT 1');
-  // @ts-expect-error External driver connections own their own cancellation.
-  const serverCancel = server.cancel();
-  // @ts-expect-error Server handles do not expose the embedded database backup format.
-  const serverBackup = server.backup();
-  // @ts-expect-error Raw protocol belongs to database connections, not listener ownership.
-  const serverRaw = server.execProtocolRaw(Uint8Array.of(0x51));
-  // @ts-expect-error Transactions belong to caller-owned database connections.
-  const serverTransaction = server.transaction(() => undefined);
-  const closed: boolean = database.closed || server.closed || transaction.closed;
-  void [
-    decoded,
-    raw,
-    execution,
-    inferredArrays,
-    inferredDecoder,
-    description,
-    streamed,
-    asyncStreamed,
-    widenedAsyncStreamed,
-    transactionBuffered,
-    transactionStreamed,
-    rollback,
-    serverConnectionString,
-    serverClose,
-    serverQuery,
-    serverCancel,
-    serverBackup,
-    serverRaw,
-    serverTransaction,
-    closed,
-  ];
-}
-
-void assertPublicDatabaseTypes;
-
-const publicHelperTypes: [TextQueryParameter, BinaryQueryParameter, NullQueryParameter] = [
-  text('value'),
-  binary(Uint8Array.of(1)),
-  typedNull(postgresOids.text),
-];
-void publicHelperTypes;
-
-const publicRestoreOptions: RestoreOptions = { libraryPath: '/opt/liboliphaunt.so' };
-const publicTopology: OpenConfig = { topology: 'broker' };
-void [publicRestoreOptions, publicTopology];
-
-const plainJsonParameter: QueryParam = {
-  format: 'text',
-  value: 'plain JSON data',
-};
-// @ts-expect-error Encoded parameters must be created by an exported helper.
-const forgedEncodedParameter: EncodedQueryParameter = {
-  format: 'text',
-  value: 'forged',
-};
-void [plainJsonParameter, forgedEncodedParameter];
diff --git a/src/sdks/js/src/__tests__/query.test.ts b/src/sdks/js/src/__tests__/query.test.ts
deleted file mode 100644
index dff6cfacd..000000000
--- a/src/sdks/js/src/__tests__/query.test.ts
+++ /dev/null
@@ -1,309 +0,0 @@
-import assert from 'node:assert/strict';
-import { test } from 'vitest';
-
-import {
-  PostgresError,
-  assertSuccessfulQueryResponse,
-  binary,
-  extendedQuery,
-  parseDescribeResponse,
-  parseExecResponse,
-  parseQueryRawResponse,
-  parseSimpleQueryRawResponse,
-  postgresOids,
-  text,
-  toUint8Array,
-  typedNull,
-} from '../query.js';
-
-test('extendedQuery serializes text, binary, and null parameters', () => {
-  const bytes = extendedQuery('SELECT $1, $2, $3', [
-    text('text', postgresOids.text),
-    typedNull(postgresOids.text),
-    binary(new Uint8Array([1, 2, 3]), postgresOids.bytea),
-  ]);
-  const messages = splitFrontendMessages(bytes);
-
-  assert.deepEqual(
-    messages.map((message) => message.tag),
-    [0x50, 0x42, 0x44, 0x45, 0x53],
-  );
-  assert.equal(new TextDecoder().decode(messages[0]!.body).includes('SELECT $1, $2, $3'), true);
-
-  const bind = messages[1]!.body;
-  assert.deepEqual([...bind.slice(0, 2)], [0, 0], 'portal and statement names are empty');
-  assert.equal(readI16(bind, 2), 3, 'three parameter format codes');
-  assert.deepEqual([readI16(bind, 4), readI16(bind, 6), readI16(bind, 8)], [0, 0, 1]);
-  assert.equal(readI16(bind, 10), 3, 'three parameter values');
-  assert.equal(readI32(bind, 12), 4);
-  assert.equal(new TextDecoder().decode(bind.slice(16, 20)), 'text');
-  assert.equal(readI32(bind, 20), -1);
-  assert.equal(readI32(bind, 24), 3);
-  assert.deepEqual([...bind.slice(28, 31)], [1, 2, 3]);
-});
-
-test('extendedQuery rejects invalid frontend inputs', () => {
-  assert.throws(() => extendedQuery('SELECT \0', []), /SQL must not contain NUL/);
-  assert.throws(
-    () => extendedQuery('SELECT 1', new Array(0x8000).fill(null)),
-    /at most 32767 parameters/,
-  );
-
-  const view = new DataView(new Uint8Array([9, 8, 7, 6]).buffer, 1, 2);
-  assert.deepEqual([...toUint8Array(view)], [8, 7]);
-  assert.deepEqual([...toUint8Array([4, 5, 6])], [4, 5, 6]);
-});
-
-test('parseSimpleQueryRawResponse validates result ordering and accessors', () => {
-  const result = parseSimpleQueryRawResponse(
-    Uint8Array.from([
-      ...backend(0x53, [...cstring('server_version'), ...cstring('18.4')]),
-      ...backend(0x54, rowDescription([{ name: 'value', format: 0 }])),
-      ...backend(0x44, dataRow(['hello'])),
-      ...backend(0x43, cstring('SELECT 1')),
-      ...backend(0x5a, [0x49]),
-    ]),
-  );
-
-  assert.equal(result.rowCount, 1);
-  assert.equal(result.commandTag, 'SELECT 1');
-  assert.equal(result.getText(0, 'value'), 'hello');
-  assert.throws(() => result.getText(0, 'missing'), /no column/);
-  assert.throws(() => result.getText(3, 'value'), /no row/);
-  assert.throws(() => result.rows[0]!.text(99), /no column/);
-});
-
-test('parseSimpleQueryRawResponse surfaces PostgreSQL errors and malformed backend traffic', () => {
-  const error = thrownBy(() =>
-    parseSimpleQueryRawResponse(
-      Uint8Array.from([
-        ...backend(0x45, [
-          0x53,
-          ...cstring('ERROR'),
-          0x43,
-          ...cstring('42601'),
-          0x4d,
-          ...cstring('syntax error'),
-          0,
-        ]),
-      ]),
-    ),
-  );
-  assert.ok(error instanceof PostgresError);
-  assert.equal(error.severity, 'ERROR');
-  assert.equal(error.sqlstate, '42601');
-  assert.equal(error.message, 'syntax error');
-
-  assert.throws(() => parseSimpleQueryRawResponse(Uint8Array.from([0x5a, 0, 0, 0, 3])), /length 3/);
-  assert.throws(
-    () => parseSimpleQueryRawResponse(Uint8Array.from([...backend(0x44, dataRow(['orphan']))])),
-    /before RowDescription/,
-  );
-  assert.throws(
-    () =>
-      parseSimpleQueryRawResponse(
-        Uint8Array.from([
-          ...backend(0x54, rowDescription([{ name: 'one', format: 0 }])),
-          ...backend(0x54, rowDescription([{ name: 'two', format: 0 }])),
-          ...backend(0x5a, [0x49]),
-        ]),
-      ),
-    /two RowDescriptions/,
-  );
-  assert.throws(() => parseSimpleQueryRawResponse(Uint8Array.from([...backend(0x47, [])])), /COPY/);
-  assert.throws(() => parseSimpleQueryRawResponse(Uint8Array.from([...backend(0x99, [])])), /0x99/);
-  assert.throws(
-    () => parseSimpleQueryRawResponse(Uint8Array.from([...backend(0x5a, [0x00])])),
-    /invalid transaction status/,
-  );
-  assert.throws(
-    () =>
-      parseSimpleQueryRawResponse(
-        Uint8Array.from([...backend(0x5a, [0x49]), ...backend(0x49, [])]),
-      ),
-    /bytes after ReadyForQuery/,
-  );
-  assert.throws(
-    () => parseSimpleQueryRawResponse(Uint8Array.from([...backend(0x49, [])])),
-    /before ReadyForQuery/,
-  );
-});
-
-test('assertSuccessfulQueryResponse and row decoding reject invalid payloads', () => {
-  assertSuccessfulQueryResponse(
-    Uint8Array.from([...backend(0x43, cstring('CREATE 1')), ...backend(0x5a, [0x49])]),
-  );
-  assert.throws(
-    () => assertSuccessfulQueryResponse(Uint8Array.from([...backend(0x5a, [0x49, 0])])),
-    /ReadyForQuery contained 2 bytes/,
-  );
-  assert.throws(
-    () =>
-      assertSuccessfulQueryResponse(
-        Uint8Array.from([...backend(0x45, [0x4d, ...cstring('boom'), 0])]),
-      ),
-    PostgresError,
-  );
-
-  const result = parseSimpleQueryRawResponse(
-    Uint8Array.from([
-      ...backend(0x54, rowDescription([{ name: 'bad', format: 0 }])),
-      ...backend(0x44, dataRow([new Uint8Array([0xff])])),
-      ...backend(0x43, cstring('SELECT 1')),
-      ...backend(0x5a, [0x49]),
-    ]),
-  );
-  assert.throws(() => result.getText(0, 'bad'), /not valid UTF-8/);
-});
-
-test('rejects incomplete and out-of-order structured completions', () => {
-  assert.throws(
-    () => parseSimpleQueryRawResponse(Uint8Array.from(backend(0x5a, [0x49]))),
-    /omitted CommandComplete or EmptyQueryResponse/,
-  );
-  assert.throws(
-    () =>
-      parseSimpleQueryRawResponse(
-        Uint8Array.from([
-          ...backend(0x43, cstring('SELECT 1')),
-          ...backend(0x44, dataRow(['late'])),
-          ...backend(0x5a, [0x49]),
-        ]),
-      ),
-    /DataRow arrived after statement completion/,
-  );
-  assert.throws(
-    () =>
-      parseDescribeResponse(
-        Uint8Array.from([...backend(0x74, i16(0)), ...backend(0x6e, []), ...backend(0x5a, [0x49])]),
-      ),
-    /before ParseComplete|omitted ParseComplete/,
-  );
-  assert.equal(
-    parseExecResponse(
-      Uint8Array.from([
-        ...backend(0x43, cstring('UPDATE 1')),
-        ...backend(0x49, []),
-        ...backend(0x43, cstring('DELETE 2')),
-        ...backend(0x5a, [0x49]),
-      ]),
-    ).statements.length,
-    2,
-  );
-  for (const completion of [backend(0x43, cstring('UPDATE 1')), backend(0x49, [])]) {
-    assert.throws(
-      () => parseQueryRawResponse(Uint8Array.from([...completion, ...backend(0x5a, [0x49])])),
-      /before the extended-query result description/,
-    );
-  }
-  assert.throws(
-    () =>
-      parseQueryRawResponse(
-        Uint8Array.from([
-          ...backend(0x32, []),
-          ...backend(0x6e, []),
-          ...backend(0x43, cstring('UPDATE 1')),
-          ...backend(0x5a, [0x49]),
-        ]),
-      ),
-    /BindComplete arrived before ParseComplete/,
-  );
-  assert.throws(
-    () =>
-      parseExecResponse(
-        Uint8Array.from([
-          ...backend(0x31, []),
-          ...backend(0x43, cstring('UPDATE 1')),
-          ...backend(0x5a, [0x49]),
-        ]),
-      ),
-    /simple-query response contained ParseComplete/,
-  );
-});
-
-type FrontendMessage = {
-  tag: number;
-  body: Uint8Array;
-};
-
-function splitFrontendMessages(bytes: Uint8Array): FrontendMessage[] {
-  const messages: FrontendMessage[] = [];
-  let offset = 0;
-  while (offset < bytes.length) {
-    const tag = bytes[offset]!;
-    const length = readI32(bytes, offset + 1);
-    messages.push({ tag, body: bytes.slice(offset + 5, offset + 1 + length) });
-    offset += 1 + length;
-  }
-  return messages;
-}
-
-function backend(tag: number, body: number[] | Uint8Array): number[] {
-  return [tag, ...i32(body.length + 4), ...body];
-}
-
-function rowDescription(fields: Array<{ name: string; format: number }>): number[] {
-  return [
-    ...i16(fields.length),
-    ...fields.flatMap((field) => [
-      ...cstring(field.name),
-      ...i32(0),
-      ...i16(0),
-      ...i32(25),
-      ...i16(-1),
-      ...i32(-1),
-      ...i16(field.format),
-    ]),
-  ];
-}
-
-function dataRow(values: Array): number[] {
-  return [
-    ...i16(values.length),
-    ...values.flatMap((value) => {
-      if (value === null) {
-        return i32(-1);
-      }
-      const bytes = typeof value === 'string' ? new TextEncoder().encode(value) : value;
-      return [...i32(bytes.byteLength), ...bytes];
-    }),
-  ];
-}
-
-function cstring(value: string): number[] {
-  return [...new TextEncoder().encode(value), 0];
-}
-
-function i16(value: number): number[] {
-  const bits = value & 0xffff;
-  return [(bits >>> 8) & 0xff, bits & 0xff];
-}
-
-function i32(value: number): number[] {
-  const bits = value >>> 0;
-  return [(bits >>> 24) & 0xff, (bits >>> 16) & 0xff, (bits >>> 8) & 0xff, bits & 0xff];
-}
-
-function readI16(bytes: Uint8Array, offset: number): number {
-  const value = (bytes[offset]! << 8) | bytes[offset + 1]!;
-  return value > 0x7fff ? value - 0x10000 : value;
-}
-
-function readI32(bytes: Uint8Array, offset: number): number {
-  const value =
-    (bytes[offset]! * 0x1000000 +
-      (bytes[offset + 1]! << 16) +
-      (bytes[offset + 2]! << 8) +
-      bytes[offset + 3]!) >>>
-    0;
-  return value > 0x7fffffff ? value - 0x100000000 : value;
-}
-
-function thrownBy(fn: () => unknown): unknown {
-  try {
-    fn();
-  } catch (error) {
-    return error;
-  }
-  assert.fail('expected function to throw');
-}
diff --git a/src/sdks/js/src/client.ts b/src/sdks/js/src/client.ts
deleted file mode 100644
index 00b64641f..000000000
--- a/src/sdks/js/src/client.ts
+++ /dev/null
@@ -1,1279 +0,0 @@
-import { mkdir, mkdtemp, rm } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { join } from 'node:path';
-
-import {
-  normalizeDatabaseTopology,
-  normalizeOpenConfig,
-  validateDirectoryPath,
-  validateNativeStartupGUCs,
-} from './config.js';
-import { createDefaultNativeBinding } from './native/default.js';
-import type { NativeBinding, NativeBindingOptions } from './native/types.js';
-import {
-  assertNoTransactionChain,
-  decodeQueryResult,
-  describeQuery,
-  errorWithNotices,
-  extendedQuery,
-  inspectManagedTransactionResponse,
-  inspectReadyForQuery,
-  parseCommandResponse,
-  parseDescribeResponse,
-  parseExecResponse,
-  parseQueryRawResponse,
-  planQuery,
-  structuredSimpleQuery,
-  type CommandResult,
-  type DescribeResult,
-  type ExecResult,
-  type InferQueryRow,
-  type ParameterOptions,
-  type PostgresNotice,
-  type QueryParam,
-  type QueryOptions,
-  type QueryPlan,
-  type QueryResult,
-  type RawQueryResult,
-  type TransactionStatus,
-  toUint8Array,
-} from './query.js';
-import { createBrokerRuntimeBinding } from './runtime/broker.js';
-import { directRuntimeBinding } from './runtime/direct.js';
-import { createServerRuntimeBinding } from './runtime/server.js';
-import type { RuntimeBinding, RuntimeHandle } from './runtime/types.js';
-import type {
-  BinaryInput,
-  DatabaseStorage,
-  OliphauntClient,
-  OliphauntDatabase,
-  OliphauntTransaction,
-  OliphauntServer,
-  OpenConfig,
-  ServerListen,
-  ServerOpenConfig,
-  ProtocolChunkCallback,
-  RestoreOptions,
-} from './types.js';
-
-export type NativeBindingFactory = (
-  options?: NativeBindingOptions,
-) => NativeBinding | Promise;
-
-type RuntimeBindingOverrides = {
-  readonly broker?: RuntimeBinding;
-  readonly server?: RuntimeBinding;
-};
-
-type QueryReadOptions = Omit;
-
-class OliphauntDatabaseBase {
-  protected readonly binding: RuntimeBinding;
-  protected readonly handle: RuntimeHandle;
-  readonly #releaseOwnership?: () => void;
-  #closed = false;
-  #closing = false;
-  #closeAttempt?: Promise;
-  #operationTail = Promise.resolve();
-  readonly #cancellationOperations = new Set>();
-  #runtimeCloseActive = false;
-  #activeTransaction = false;
-  #streamCallbackActive = false;
-  #sessionFailure?: Error;
-
-  static async publish(
-    database: Database,
-  ): Promise {
-    try {
-      database.#initializeForgottenHandleCleanup();
-      return database;
-    } catch (publicationError) {
-      const cleanupFailure = await database.#discardUnpublishedOwner();
-      if (cleanupFailure === undefined) throw publicationError;
-      throw new AggregateError(
-        [publicationError, cleanupFailure],
-        'Oliphaunt opened a runtime owner but could not publish its JavaScript facade',
-      );
-    }
-  }
-
-  constructor(binding: RuntimeBinding, handle: RuntimeHandle, releaseOwnership?: () => void) {
-    this.binding = binding;
-    this.handle = handle;
-    if (releaseOwnership !== undefined) {
-      let released = false;
-      this.#releaseOwnership = () => {
-        if (released) return;
-        released = true;
-        releaseOwnership();
-      };
-    }
-  }
-
-  /** Complete owner publication after the facade itself is reachable locally. */
-  #initializeForgottenHandleCleanup(): void {
-    this.binding.registerForgottenHandleCleanup?.(
-      this,
-      this.handle,
-      this.#releaseOwnership ?? noop,
-    );
-  }
-
-  /**
-   * Retire an opened handle whose public facade could not be published.
-   * Registration is unregistered even when the registry threw after partially
-   * accepting it, and the exact JavaScript ownership lease is always released.
-   */
-  async #discardUnpublishedOwner(): Promise {
-    const failures: unknown[] = [];
-    const closeFailure = await closeRuntimeHandleFailure(this.binding, this.handle);
-    if (closeFailure !== undefined) failures.push(closeFailure);
-    const retirementFailure = this.#retire();
-    if (retirementFailure !== undefined) failures.push(retirementFailure);
-    return collapseFailures(failures, 'unpublished Oliphaunt owner cleanup failed');
-  }
-
-  get closed(): boolean {
-    return this.#closed;
-  }
-
-  async execute(
-    sql: string,
-    parameters: ReadonlyArray = [],
-    options: ParameterOptions = {},
-  ): Promise {
-    this.assertNoActiveTransaction();
-    const plan = planQuery(sql, parameters, snapshotParameterOptions(options));
-    return this.withSessionOperation(() =>
-      this.#runPlannedUnlocked(plan, 'database', parseCommandResponse),
-    );
-  }
-
-  async query(
-    sql: string,
-    parameters: ReadonlyArray = [],
-    options: Options & QueryOptions = {} as Options & QueryOptions,
-  ): Promise>> {
-    this.assertNoActiveTransaction();
-    const stableOptions = snapshotQueryOptions(options);
-    const plan = planQuery(sql, parameters, stableOptions);
-    return this.withSessionOperation(async () =>
-      decodeQueryResult(
-        await this.#runPlannedUnlocked(plan, 'database', parseQueryRawResponse),
-        stableOptions,
-      ),
-    );
-  }
-
-  async queryRaw(
-    sql: string,
-    parameters: ReadonlyArray = [],
-    options: ParameterOptions = {},
-  ): Promise {
-    this.assertNoActiveTransaction();
-    const plan = planQuery(sql, parameters, snapshotParameterOptions(options));
-    return this.withSessionOperation(() =>
-      this.#runPlannedUnlocked(plan, 'database', parseQueryRawResponse),
-    );
-  }
-
-  async exec(
-    sql: string,
-    options: Options & QueryReadOptions = {} as Options & QueryReadOptions,
-  ): Promise>> {
-    this.assertNoActiveTransaction();
-    const input = structuredSimpleQuery(sql);
-    const stableOptions = snapshotReadOptions(options);
-    return this.withSessionOperation(() =>
-      this.#runStructuredUnlocked(input, 'database', (response) =>
-        parseExecResponse(response, stableOptions),
-      ),
-    );
-  }
-
-  async describe(
-    sql: string,
-    parameterTypeOids: ReadonlyArray = [],
-  ): Promise {
-    this.assertNoActiveTransaction();
-    const input = describeQuery(sql, [...parameterTypeOids]);
-    return this.withSessionOperation(() =>
-      this.#runStructuredUnlocked(input, 'database', parseDescribeResponse),
-    );
-  }
-
-  async execProtocolRaw(input: BinaryInput): Promise {
-    this.assertNoActiveTransaction();
-    const bytes = toUint8Array(input).slice();
-    return this.withSessionOperation(() => this.#runRawProtocolUnlocked(bytes));
-  }
-
-  async execProtocolRawStream(input: BinaryInput, onChunk: ProtocolChunkCallback): Promise {
-    this.assertNoActiveTransaction();
-    if (typeof onChunk !== 'function') {
-      return Promise.reject(new TypeError('protocol stream callback must be a function'));
-    }
-    const bytes = toUint8Array(input).slice();
-    return this.withSessionOperation(() => this.#execProtocolStreamUnlocked(bytes, onChunk));
-  }
-
-  cancel(): Promise {
-    if (this.#closed) {
-      return Promise.reject(new Error('Oliphaunt database is closed'));
-    }
-    if (this.#runtimeCloseActive) {
-      return Promise.reject(new Error('Oliphaunt database is closing'));
-    }
-    // Cancellation must remain independent of the physical-session queue so
-    // it can interrupt an admitted operation even after close() has stopped
-    // ordinary admission. Runtime teardown waits for every admitted cancel.
-    const operation = this.#runNativeVoidOperation(() => this.binding.cancel(this.handle));
-    this.#cancellationOperations.add(operation);
-    void operation.then(
-      () => this.#cancellationOperations.delete(operation),
-      () => this.#cancellationOperations.delete(operation),
-    );
-    return operation;
-  }
-
-  async transaction(body: (transaction: OliphauntTransaction) => Promise | T): Promise {
-    this.assertNoActiveTransaction();
-    if (typeof body !== 'function') {
-      return Promise.reject(new TypeError('Oliphaunt transaction body must be a function'));
-    }
-    // Pin immediately at admission. Calls made after transaction() returns may
-    // not slip into the physical-session queue before BEGIN starts.
-    this.#activeTransaction = true;
-    let attempt: Promise;
-    try {
-      attempt = this.withSessionOperation(async () => {
-        const transaction = new OliphauntTransactionHandle(
-          (plan, decode) => this.#runPlannedUnlocked(plan, 'transaction', decode),
-          (input, decode) => this.#runStructuredUnlocked(input, 'transaction', decode),
-          () => this.#executeTransactionControlUnlocked('ROLLBACK').then(() => undefined),
-        );
-        try {
-          await this.#executeTransactionControlUnlocked('BEGIN');
-
-          let result: T;
-          try {
-            result = await body(transaction);
-            await transaction.sealAndDrain();
-          } catch (error) {
-            transaction.seal();
-            await transaction.drain().catch(() => undefined);
-            let rollbackFailure: unknown;
-            if (transaction.rollbackStarted) {
-              try {
-                await transaction.waitForRollback();
-              } catch (rollbackError) {
-                rollbackFailure = rollbackError;
-              }
-            } else if (this.#sessionFailure === undefined) {
-              try {
-                await this.#executeTransactionControlUnlocked('ROLLBACK');
-              } catch (rollbackError) {
-                rollbackFailure = rollbackError;
-              }
-            }
-            if (rollbackFailure !== undefined && rollbackFailure !== error) {
-              throw transactionCallbackAggregate(
-                error,
-                rollbackFailure,
-                'transaction callback and rollback both failed',
-              );
-            }
-            const databaseFailure =
-              this.#sessionFailure === undefined
-                ? undefined
-                : (transaction.firstFailure ?? this.#sessionFailure);
-            if (databaseFailure !== undefined && databaseFailure !== error) {
-              throw transactionCallbackAggregate(
-                error,
-                databaseFailure,
-                'transaction callback and an independent database failure both occurred',
-              );
-            }
-            throw error;
-          }
-
-          if (transaction.rolledBack) {
-            return result;
-          }
-          if (this.#sessionFailure !== undefined && transaction.firstFailure !== undefined) {
-            throw transaction.firstFailure;
-          }
-          const outcome = await this.#executeTransactionControlUnlocked('COMMIT');
-          if (outcome === 'rolledBack') {
-            throw transaction.firstFailure ?? transactionTagError('COMMIT', 'ROLLBACK');
-          }
-          return result;
-        } finally {
-          transaction.deactivate();
-        }
-      });
-    } catch (error) {
-      this.#activeTransaction = false;
-      throw error;
-    }
-    return attempt.finally(() => {
-      this.#activeTransaction = false;
-    });
-  }
-
-  close(): Promise {
-    if (this.#streamCallbackActive) {
-      return Promise.reject(streamCallbackReentryError());
-    }
-    if (this.#closeAttempt !== undefined) {
-      return this.#closeAttempt;
-    }
-    if (this.#closed) {
-      return Promise.resolve();
-    }
-    if (this.#activeTransaction) {
-      return Promise.reject(new Error('cannot close Oliphaunt while a transaction is active'));
-    }
-
-    this.#closing = true;
-    let terminal = false;
-    const attempt = this.#operationTail
-      .then(async () => {
-        // Cancellation remains out-of-band while admitted session work drains.
-        // Close the cancellation admission gate only in the same job that
-        // starts runtime teardown, after every already-admitted cancel settles.
-        while (this.#cancellationOperations.size > 0) {
-          await Promise.allSettled([...this.#cancellationOperations]);
-        }
-        this.#runtimeCloseActive = true;
-        let outcome: Awaited>;
-        try {
-          outcome = await this.binding.close(this.handle);
-        } catch (error) {
-          // A runtime adapter violated the private no-rejection contract. Its
-          // teardown state is unknowable, so retiring the public owner is the
-          // only safe result.
-          outcome = { state: 'terminal' as const, error };
-        }
-        if (outcome.state === 'retryable') {
-          throw outcome.error;
-        }
-
-        terminal = true;
-        const cleanupFailure = this.#retire();
-        if (outcome.state === 'terminal') {
-          throw outcome.error;
-        }
-        if (cleanupFailure !== undefined) {
-          throw cleanupFailure;
-        }
-      })
-      .finally(() => {
-        this.#closing = false;
-        if (!terminal && this.#closeAttempt === attempt) {
-          this.#runtimeCloseActive = false;
-          this.#closeAttempt = undefined;
-        }
-      });
-    this.#closeAttempt = attempt;
-    return attempt;
-  }
-
-  async [Symbol.asyncDispose](): Promise {
-    await this.close();
-  }
-
-  async #executeTransactionControlUnlocked(
-    sql: 'BEGIN' | 'COMMIT' | 'ROLLBACK',
-  ): Promise<'committed' | 'rolledBack' | undefined> {
-    this.#assertHealthy();
-    let response: Uint8Array;
-    try {
-      response = await this.#execProtocolRawUnlocked(extendedQuery(sql, []));
-    } catch (error) {
-      this.#poison(error, `${sql} transport outcome is unknown`);
-      throw error;
-    }
-
-    let status: TransactionStatus;
-    try {
-      status = inspectReadyForQuery(response);
-    } catch (error) {
-      this.#poison(error, `${sql} did not reach a valid ReadyForQuery boundary`);
-      throw error;
-    }
-
-    let result: CommandResult;
-    try {
-      result = parseCommandResponse(response);
-    } catch (error) {
-      if (sql === 'BEGIN' && status !== 'idle') {
-        await this.#recoverDatabaseBoundaryUnlocked().catch(() => undefined);
-      } else if (sql === 'ROLLBACK') {
-        this.#poison(error, 'ROLLBACK did not return its exact command boundary');
-      } else if (sql === 'COMMIT') {
-        this.#poison(error, 'COMMIT did not return its exact command boundary');
-      }
-      throw error;
-    }
-
-    if (sql === 'BEGIN') {
-      if (result.commandTag === 'BEGIN' && status === 'transaction') return undefined;
-      const error = transactionBoundaryError(sql, result.commandTag, status);
-      if (status !== 'idle') {
-        await this.#recoverDatabaseBoundaryUnlocked();
-      }
-      throw error;
-    }
-
-    if (sql === 'COMMIT' && result.commandTag === 'ROLLBACK' && status === 'idle') {
-      return 'rolledBack';
-    }
-    if (result.commandTag === sql && status === 'idle') {
-      return sql === 'COMMIT' ? 'committed' : undefined;
-    }
-
-    const error = transactionBoundaryError(sql, result.commandTag, status);
-    this.#poison(error, `${sql} returned an unrecognized transaction boundary`);
-    throw error;
-  }
-
-  async #runPlannedUnlocked(
-    plan: QueryPlan,
-    scope: StructuredScope,
-    decode: (response: Uint8Array) => Result,
-  ): Promise {
-    if (plan.kind === 'complete') {
-      return this.#runStructuredUnlocked(plan.input, scope, decode);
-    }
-    const description = await this.#runStructuredUnlocked(plan.input, scope, parseDescribeResponse);
-    // plan.bind() may invoke a caller codec. It runs only after a proven Ready
-    // boundary and therefore cannot poison the wire session if it throws.
-    let input: Uint8Array;
-    try {
-      input = plan.bind(description.parameterTypeOids);
-    } catch (error) {
-      throw errorWithNotices(error, description.notices);
-    }
-    try {
-      return prependNotices(
-        await this.#runStructuredUnlocked(input, scope, decode),
-        description.notices,
-      );
-    } catch (error) {
-      throw errorWithNotices(error, description.notices);
-    }
-  }
-
-  async #runStructuredUnlocked(
-    input: Uint8Array,
-    scope: StructuredScope,
-    decode: (response: Uint8Array) => Result,
-  ): Promise {
-    let response: Uint8Array;
-    try {
-      response = await this.#execProtocolRawUnlocked(input);
-    } catch (error) {
-      this.#poison(error, 'structured PostgreSQL transport outcome is unknown');
-      throw error;
-    }
-
-    let status: TransactionStatus;
-    try {
-      status =
-        scope === 'transaction'
-          ? inspectManagedTransactionResponse(response)
-          : inspectReadyForQuery(response);
-    } catch (error) {
-      this.#poison(
-        error,
-        scope === 'transaction'
-          ? 'callback transaction ownership escaped or its response boundary was invalid'
-          : 'structured PostgreSQL response has no valid readiness boundary',
-      );
-      throw error;
-    }
-
-    if (scope === 'database' && status !== 'idle') {
-      await this.#recoverDatabaseBoundaryUnlocked();
-      // Preserve a PostgreSQL/parser error after proven recovery, but never
-      // report a successful structured call whose transaction was discarded.
-      const result = decode(response);
-      const error = new Error(
-        `structured database operation ended with PostgreSQL transaction status ${status}; Oliphaunt rolled it back`,
-      );
-      throw isNoticeCarrier(result) ? errorWithNotices(error, result.notices) : error;
-    }
-    return decode(response);
-  }
-
-  async #recoverDatabaseBoundaryUnlocked(): Promise {
-    try {
-      await this.#executeTransactionControlUnlocked('ROLLBACK');
-    } catch (error) {
-      this.#poison(error, 'PostgreSQL automatic rollback did not prove recovery');
-      throw new Error('PostgreSQL session could not be recovered to idle; close the database', {
-        cause: error,
-      });
-    }
-  }
-
-  async #execProtocolRawUnlocked(input: BinaryInput): Promise {
-    const requestBytes = toUint8Array(input);
-    return this.runNativeOperation(() => this.binding.execProtocolRaw(this.handle, requestBytes));
-  }
-
-  async #runRawProtocolUnlocked(input: BinaryInput): Promise {
-    try {
-      return await this.#execProtocolRawUnlocked(input);
-    } catch (error) {
-      // Raw protocol bypasses Oliphaunt's response-boundary parser. If the
-      // adapter rejects, neither the caller nor this layer can prove where the
-      // physical PostgreSQL session stopped, so subsequent work is unsafe.
-      this.#poison(error, 'raw PostgreSQL transport outcome is unknown');
-      throw error;
-    }
-  }
-
-  async #execProtocolStreamUnlocked(
-    input: BinaryInput,
-    onChunk: ProtocolChunkCallback,
-  ): Promise {
-    if (typeof onChunk !== 'function') {
-      throw new TypeError('protocol stream callback must be a function');
-    }
-    const requestBytes = toUint8Array(input);
-    const consumer = synchronousProtocolChunkConsumer((chunk) => {
-      this.#streamCallbackActive = true;
-      try {
-        return (onChunk as (chunk: Uint8Array) => unknown)(chunk);
-      } finally {
-        this.#streamCallbackActive = false;
-      }
-    });
-    try {
-      await this.binding.execProtocolStream(this.handle, requestBytes, consumer.callback);
-    } catch (error) {
-      // Adapters only preserve callback identity when they have positively
-      // confirmed recovery (for example broker ReadyForQuery frame 104). Any
-      // other rejection is the authoritative execution/recovery outcome.
-      if (consumer.failure === undefined || !Object.is(error, consumer.failure.error)) {
-        this.#poison(error, 'streaming raw PostgreSQL recovery was not proven');
-      }
-      throw error;
-    }
-    if (consumer.failure !== undefined) {
-      throw consumer.failure.error;
-    }
-  }
-
-  #assertOpen(): void {
-    this.#assertNoStreamCallbackReentry();
-    if (this.#closed) {
-      throw new Error('Oliphaunt database is closed');
-    }
-    if (this.#closing) {
-      throw new Error('Oliphaunt database is closing');
-    }
-    this.#assertHealthy();
-  }
-
-  #assertHealthy(): void {
-    if (this.#sessionFailure !== undefined) {
-      throw new Error('Oliphaunt session state is unknown; close the database', {
-        cause: this.#sessionFailure,
-      });
-    }
-  }
-
-  protected assertNoActiveTransaction(): void {
-    this.#assertNoStreamCallbackReentry();
-    if (this.#activeTransaction) {
-      throw new Error(transactionPinnedMessage);
-    }
-  }
-
-  #assertNoStreamCallbackReentry(): void {
-    if (this.#streamCallbackActive) {
-      throw streamCallbackReentryError();
-    }
-  }
-
-  #retire(): unknown | undefined {
-    this.#closed = true;
-    const failures: unknown[] = [];
-    try {
-      this.binding.unregisterForgottenHandleCleanup?.(this);
-    } catch (error) {
-      failures.push(error);
-    }
-    try {
-      this.#releaseOwnership?.();
-    } catch (error) {
-      failures.push(error);
-    }
-    if (failures.length === 0) return undefined;
-    if (failures.length === 1) return failures[0];
-    return new AggregateError(failures, 'Oliphaunt owner retirement failed');
-  }
-
-  protected withSessionOperation(body: () => T | Promise): Promise {
-    this.#assertOpen();
-    const operation = this.#operationTail.then(async () => {
-      this.#assertHealthy();
-      return await body();
-    });
-    this.#operationTail = operation.then(
-      () => undefined,
-      () => undefined,
-    );
-    return operation;
-  }
-
-  protected async runNativeOperation(
-    body: () => T | undefined | Promise,
-  ): Promise {
-    const result = await body();
-    if (result === undefined) {
-      throw new Error('native oliphaunt runtime operation returned no result');
-    }
-    return result;
-  }
-
-  async #runNativeVoidOperation(body: () => void | Promise): Promise {
-    await body();
-  }
-
-  #poison(error: unknown, message: string): void {
-    this.#sessionFailure ??= new Error(message, { cause: error });
-  }
-}
-
-class OliphauntDatabaseImpl extends OliphauntDatabaseBase implements OliphauntDatabase {
-  async backup(): Promise {
-    this.assertNoActiveTransaction();
-    return this.withSessionOperation(async () => {
-      const backup = this.binding.backup;
-      if (backup === undefined) {
-        throw new Error('database runtime binding does not implement backup');
-      }
-      return this.runNativeOperation(() => backup(this.handle));
-    });
-  }
-}
-
-class OliphauntServerOwner extends OliphauntDatabaseBase {}
-
-class OliphauntServerImpl implements OliphauntServer {
-  readonly #owner: OliphauntServerOwner;
-
-  constructor(
-    owner: OliphauntServerOwner,
-    readonly connectionString: string,
-  ) {
-    this.#owner = owner;
-  }
-
-  get closed(): boolean {
-    return this.#owner.closed;
-  }
-
-  close(): Promise {
-    return this.#owner.close();
-  }
-
-  async [Symbol.asyncDispose](): Promise {
-    await this.close();
-  }
-}
-
-class OliphauntTransactionHandle implements OliphauntTransaction {
-  readonly #runPlan: (
-    plan: QueryPlan,
-    decode: (response: Uint8Array) => Result,
-  ) => Promise;
-  readonly #runStructured: (
-    input: Uint8Array,
-    decode: (response: Uint8Array) => Result,
-  ) => Promise;
-  readonly #rollbackControl: () => Promise;
-  #state: 'active' | 'finishing' | 'closed' = 'active';
-  #tail = Promise.resolve();
-  #rollbackAttempt?: Promise;
-  #rolledBack = false;
-  #firstFailure: unknown;
-
-  constructor(
-    runPlan: (
-      plan: QueryPlan,
-      decode: (response: Uint8Array) => Result,
-    ) => Promise,
-    runStructured: (
-      input: Uint8Array,
-      decode: (response: Uint8Array) => Result,
-    ) => Promise,
-    rollbackControl: () => Promise,
-  ) {
-    this.#runPlan = runPlan;
-    this.#runStructured = runStructured;
-    this.#rollbackControl = rollbackControl;
-  }
-
-  get closed(): boolean {
-    return this.#state === 'closed';
-  }
-
-  get rollbackStarted(): boolean {
-    return this.#rollbackAttempt !== undefined;
-  }
-
-  get rolledBack(): boolean {
-    return this.#rolledBack;
-  }
-
-  get firstFailure(): unknown {
-    return this.#firstFailure;
-  }
-
-  execute(
-    sql: string,
-    parameters: ReadonlyArray = [],
-    options: ParameterOptions = {},
-  ): Promise {
-    return promiseFromSynchronousCall(() => {
-      assertNoTransactionChain(sql);
-      const plan = planQuery(sql, parameters, snapshotParameterOptions(options));
-      return this.#enqueue(() => this.#runPlan(plan, parseCommandResponse));
-    });
-  }
-
-  query(
-    sql: string,
-    parameters: ReadonlyArray = [],
-    options: Options & QueryOptions = {} as Options & QueryOptions,
-  ): Promise>> {
-    return promiseFromSynchronousCall(() => {
-      assertNoTransactionChain(sql);
-      const stableOptions = snapshotQueryOptions(options);
-      const plan = planQuery(sql, parameters, stableOptions);
-      return this.#enqueue(async () => {
-        return decodeQueryResult(
-          await this.#runPlan(plan, parseQueryRawResponse),
-          stableOptions,
-        );
-      });
-    });
-  }
-
-  queryRaw(
-    sql: string,
-    parameters: ReadonlyArray = [],
-    options: ParameterOptions = {},
-  ): Promise {
-    return promiseFromSynchronousCall(() => {
-      assertNoTransactionChain(sql);
-      const plan = planQuery(sql, parameters, snapshotParameterOptions(options));
-      return this.#enqueue(() => this.#runPlan(plan, parseQueryRawResponse));
-    });
-  }
-
-  exec(
-    sql: string,
-    options: Options & QueryReadOptions = {} as Options & QueryReadOptions,
-  ): Promise>> {
-    return promiseFromSynchronousCall(() => {
-      assertNoTransactionChain(sql);
-      const input = structuredSimpleQuery(sql);
-      const stableOptions = snapshotReadOptions(options);
-      return this.#enqueue(() =>
-        this.#runStructured(input, (response) =>
-          parseExecResponse(response, stableOptions),
-        ),
-      );
-    });
-  }
-
-  describe(sql: string, parameterTypeOids: ReadonlyArray = []): Promise {
-    return promiseFromSynchronousCall(() => {
-      const input = describeQuery(sql, [...parameterTypeOids]);
-      return this.#enqueue(() => this.#runStructured(input, parseDescribeResponse));
-    });
-  }
-
-  rollback(): Promise {
-    return promiseFromSynchronousCall(() => {
-      this.#assertActive();
-      this.#state = 'finishing';
-      const operation = this.#enqueueFinishing(this.#rollbackControl);
-      const attempt = operation.then(
-        () => {
-          this.#rolledBack = true;
-          this.#state = 'closed';
-        },
-        (error: unknown) => {
-          this.#state = 'closed';
-          throw error;
-        },
-      );
-      this.#rollbackAttempt = attempt;
-      return attempt;
-    });
-  }
-
-  deactivate(): void {
-    this.#state = 'closed';
-  }
-
-  seal(): void {
-    if (this.#state === 'active') this.#state = 'finishing';
-  }
-
-  async drain(): Promise {
-    await this.#tail;
-  }
-
-  async sealAndDrain(): Promise {
-    this.seal();
-    await this.#tail;
-    await this.#rollbackAttempt;
-  }
-
-  async waitForRollback(): Promise {
-    await this.#rollbackAttempt;
-  }
-
-  #assertActive(): void {
-    if (this.#state === 'finishing') throw new Error('transaction is finishing');
-    if (this.#state === 'closed') throw new Error('transaction is no longer active');
-  }
-
-  #enqueue(body: () => Promise): Promise {
-    try {
-      this.#assertActive();
-    } catch (error) {
-      return Promise.reject(error);
-    }
-    return this.#enqueueFinishing(body);
-  }
-
-  #enqueueFinishing(body: () => Promise): Promise {
-    const operation = this.#tail.then(body);
-    this.#tail = operation.then(
-      () => undefined,
-      (error: unknown) => {
-        this.#firstFailure ??= error;
-      },
-    );
-    return operation;
-  }
-}
-
-const transactionPinnedMessage = 'physical session is pinned; use the active OliphauntTransaction';
-
-type StructuredScope = 'database' | 'transaction';
-type NoticeCarrier = { notices: PostgresNotice[] };
-
-function promiseFromSynchronousCall(body: () => Promise): Promise {
-  try {
-    return body();
-  } catch (error) {
-    return Promise.reject(error);
-  }
-}
-
-function snapshotParameterOptions(options: ParameterOptions): ParameterOptions {
-  return Object.freeze({
-    ...(options.encoders === undefined ? {} : { encoders: Object.freeze({ ...options.encoders }) }),
-  });
-}
-
-function snapshotReadOptions(options: Options): Options {
-  return Object.freeze({
-    rowMode: options.rowMode,
-    valueMode: options.valueMode,
-    ...(options.decoders === undefined ? {} : { decoders: Object.freeze({ ...options.decoders }) }),
-  }) as Options;
-}
-
-function snapshotQueryOptions(options: Options): Options {
-  return Object.freeze({
-    ...snapshotReadOptions(options),
-    ...snapshotParameterOptions(options),
-  }) as Options;
-}
-
-function prependNotices(
-  result: Result,
-  notices: ReadonlyArray,
-): Result {
-  if (notices.length > 0) result.notices.unshift(...notices);
-  return result;
-}
-
-function isNoticeCarrier(value: unknown): value is NoticeCarrier {
-  return (
-    value !== null &&
-    typeof value === 'object' &&
-    Array.isArray((value as { notices?: unknown }).notices)
-  );
-}
-
-function transactionTagError(expected: string, actual: string | undefined): Error {
-  return new Error(
-    `PostgreSQL transaction command expected ${expected}, got ${actual ?? 'no command tag'}`,
-  );
-}
-
-function transactionBoundaryError(
-  expected: 'BEGIN' | 'COMMIT' | 'ROLLBACK',
-  actual: string | undefined,
-  status: TransactionStatus,
-): Error {
-  return new Error(
-    `PostgreSQL transaction command expected ${expected} with its matching readiness status, got ${actual ?? 'no command tag'} with ${status}`,
-  );
-}
-
-function collapseFailures(failures: readonly unknown[], message: string): unknown | undefined {
-  if (failures.length === 0) return undefined;
-  if (failures.length === 1) return failures[0];
-  return new AggregateError(failures, message);
-}
-
-function transactionCallbackAggregate(
-  callback: unknown,
-  secondary: unknown,
-  message: string,
-): AggregateError {
-  return new AggregateError([callback, secondary], message);
-}
-
-function noop(): void {}
-
-export function createOliphauntClient(
-  bindingFactory: NativeBindingFactory = createDefaultNativeBinding,
-  runtimeOverrides: RuntimeBindingOverrides = {},
-): OliphauntClient {
-  const bindings = new Map>();
-  const brokerBindings = new Map();
-  const serverBinding = runtimeOverrides.server ?? createServerRuntimeBinding();
-  const directResident = {
-    temporaryDirectory: undefined as string | undefined,
-    activeOwner: undefined as symbol | undefined,
-    openQueue: Promise.resolve() as Promise,
-  };
-
-  function bindingFor(options: NativeBindingOptions = {}): Promise {
-    const key = options.libraryPath ?? '';
-    const cached = bindings.get(key);
-    if (cached !== undefined) {
-      return cached;
-    }
-    const created = Promise.resolve()
-      .then(() => bindingFactory(options))
-      .catch((error) => {
-        bindings.delete(key);
-        throw error;
-      });
-    bindings.set(key, created);
-    return created;
-  }
-
-  function brokerBindingFor(config: { brokerExecutable?: string }): RuntimeBinding {
-    if (runtimeOverrides.broker !== undefined) {
-      return runtimeOverrides.broker;
-    }
-    const key = config.brokerExecutable ?? '';
-    const cached = brokerBindings.get(key);
-    if (cached !== undefined) {
-      return cached;
-    }
-    const created = createBrokerRuntimeBinding({
-      executable: config.brokerExecutable,
-    });
-    brokerBindings.set(key, created);
-    return created;
-  }
-
-  function serializeDirectOpen(body: () => Promise): Promise {
-    const result = directResident.openQueue.then(body, body);
-    directResident.openQueue = result.then(
-      () => {},
-      () => {},
-    );
-    return result;
-  }
-
-  async function openDatabase(
-    effectiveConfig: OpenConfig | (ServerOpenConfig & { topology: 'server' }),
-  ): Promise {
-    const direct = effectiveConfig.topology === 'direct';
-    if (direct && directResident.activeOwner !== undefined) {
-      throw new Error('native direct already has an active process-wide instance');
-    }
-
-    const reusableTemporaryDirectory = direct ? directResident.temporaryDirectory : undefined;
-    const resolvedStorage = await materializeStorage(
-      effectiveConfig.storage,
-      reusableTemporaryDirectory,
-    );
-    let runtimeOpenAttempted = false;
-    try {
-      const normalized = normalizeOpenConfig(effectiveConfig, resolvedStorage);
-      let binding: RuntimeBinding;
-      if (normalized.topology === 'direct') {
-        binding = directRuntimeBinding(await bindingFor({ libraryPath: normalized.libraryPath }));
-      } else if (normalized.topology === 'broker') {
-        binding = brokerBindingFor({
-          brokerExecutable: normalized.brokerExecutable,
-        });
-      } else {
-        binding = serverBinding;
-      }
-
-      runtimeOpenAttempted = true;
-      const handle = await binding.open(normalized);
-      if (normalized.topology === 'server') {
-        const connectionString = binding.connectionString?.(handle);
-        if (connectionString === undefined) {
-          const mismatch = new Error('native server did not expose its connection string');
-          const cleanupFailure = await closeRuntimeHandleFailure(binding, handle);
-          if (cleanupFailure !== undefined) {
-            throw new AggregateError(
-              [mismatch, cleanupFailure],
-              'native server omitted its connection string and cleanup also failed',
-            );
-          }
-          throw mismatch;
-        }
-        const owner = await OliphauntDatabaseBase.publish(
-          new OliphauntServerOwner(binding, handle),
-        );
-        return new OliphauntServerImpl(owner, connectionString);
-      }
-      if (!direct) {
-        return await OliphauntDatabaseBase.publish(new OliphauntDatabaseImpl(binding, handle));
-      }
-
-      if (resolvedStorage.temporaryDirectory) {
-        directResident.temporaryDirectory ??= resolvedStorage.instanceDirectory;
-      }
-      const owner = Symbol('native-direct-owner');
-      directResident.activeOwner = owner;
-      return await OliphauntDatabaseBase.publish(
-        new OliphauntDatabaseImpl(binding, handle, () => {
-          if (directResident.activeOwner === owner) {
-            directResident.activeOwner = undefined;
-          }
-        }),
-      );
-    } catch (error) {
-      if (resolvedStorage.createdTemporaryDirectory) {
-        if (direct && runtimeOpenAttempted) {
-          // A native adapter can surface an error after liboliphaunt has claimed
-          // its process-resident PGDATA. Retain the candidate for a coherent
-          // retry, but do not publish it before the native open is entered.
-          directResident.temporaryDirectory ??= resolvedStorage.instanceDirectory;
-        } else if (!runtimeOpenAttempted) {
-          await removeDirectory(resolvedStorage.instanceDirectory);
-        }
-      }
-      throw error;
-    }
-  }
-
-  return {
-    async open(config: OpenConfig = {}): Promise {
-      const effectiveConfig = snapshotOpenConfig(config);
-      const database = await (effectiveConfig.topology === 'direct'
-        ? serializeDirectOpen(() => openDatabase(effectiveConfig))
-        : openDatabase(effectiveConfig));
-      if (database instanceof OliphauntServerImpl) {
-        return rejectUnexpectedFacade(
-          database,
-          new Error('generic database opener returned a native server'),
-        );
-      }
-      return database;
-    },
-
-    async openServer(config: ServerOpenConfig = {}): Promise {
-      const database = await openDatabase(snapshotServerOpenConfig(config));
-      if (!(database instanceof OliphauntServerImpl)) {
-        return rejectUnexpectedFacade(
-          database,
-          new Error('native server opener returned a non-server database'),
-        );
-      }
-      return database;
-    },
-
-    async restore(
-      destination: string,
-      backup: BinaryInput,
-      options: RestoreOptions = {},
-    ): Promise {
-      validateDirectoryPath(destination, 'restore destination');
-      const bytes = toUint8Array(backup).slice();
-      const binding = await bindingFor({ libraryPath: options.libraryPath });
-      await binding.restore({
-        destination,
-        bytes,
-      });
-    },
-  };
-}
-
-function snapshotOpenConfig(config: OpenConfig): OpenConfig & { topology: 'direct' | 'broker' } {
-  const topology = normalizeDatabaseTopology(config.topology);
-  validateNativeStartupGUCs(topology, config.startupGUCs ?? {});
-  return {
-    ...snapshotCommonOpenConfig(config),
-    topology,
-    libraryPath: config.libraryPath,
-    brokerExecutable: config.brokerExecutable,
-  };
-}
-
-async function rejectUnexpectedFacade(
-  facade: OliphauntDatabaseImpl | OliphauntServerImpl,
-  mismatch: Error,
-): Promise {
-  try {
-    await facade.close();
-  } catch (cleanupFailure) {
-    throw new AggregateError(
-      [mismatch, cleanupFailure],
-      'native runtime returned the wrong facade and cleanup also failed',
-    );
-  }
-  throw mismatch;
-}
-
-async function closeRuntimeHandleFailure(
-  binding: RuntimeBinding,
-  handle: RuntimeHandle,
-): Promise {
-  try {
-    const outcome = await binding.close(handle);
-    return outcome.state === 'closed' ? undefined : outcome.error;
-  } catch (error) {
-    return error;
-  }
-}
-
-function snapshotServerOpenConfig(
-  config: ServerOpenConfig,
-): ServerOpenConfig & { topology: 'server' } {
-  validateNativeStartupGUCs('server', config.startupGUCs ?? {});
-  return {
-    ...snapshotCommonOpenConfig(config),
-    topology: 'server',
-    serverExecutable: config.serverExecutable,
-    listen: snapshotServerListen(config.listen),
-  };
-}
-
-function snapshotCommonOpenConfig(config: OpenConfig | ServerOpenConfig) {
-  return {
-    storage: snapshotStorage(config.storage),
-    startupGUCs: config.startupGUCs === undefined ? undefined : { ...config.startupGUCs },
-    username: config.username,
-    database: config.database,
-    extensions: config.extensions === undefined ? undefined : [...config.extensions],
-    runtimeDirectory: config.runtimeDirectory,
-  };
-}
-
-function snapshotStorage(storage: DatabaseStorage | undefined): DatabaseStorage | undefined {
-  if (storage === undefined) return undefined;
-  return storage.kind === 'directory'
-    ? { kind: 'directory', path: storage.path }
-    : { kind: storage.kind };
-}
-
-function snapshotServerListen(listen: ServerListen | undefined): ServerListen | undefined {
-  if (listen === undefined) return undefined;
-  return listen.transport === 'tcp'
-    ? { transport: 'tcp', port: listen.port }
-    : { transport: 'unix', directory: listen.directory, port: listen.port };
-}
-
-async function materializeStorage(
-  storage: DatabaseStorage | undefined,
-  reusableTemporaryDirectory?: string,
-): Promise<{
-  instanceDirectory: string;
-  temporaryDirectory: boolean;
-  createdTemporaryDirectory: boolean;
-}> {
-  if (storage === undefined || storage.kind === 'temporaryDirectory') {
-    if (reusableTemporaryDirectory !== undefined) {
-      return {
-        instanceDirectory: reusableTemporaryDirectory,
-        temporaryDirectory: true,
-        createdTemporaryDirectory: false,
-      };
-    }
-    return {
-      instanceDirectory: await mkdtemp(join(tmpdir(), 'liboliphaunt-js-')),
-      temporaryDirectory: true,
-      createdTemporaryDirectory: true,
-    };
-  }
-  if (storage.kind === 'directory') {
-    await mkdir(storage.path, { recursive: true });
-    return {
-      instanceDirectory: storage.path,
-      temporaryDirectory: false,
-      createdTemporaryDirectory: false,
-    };
-  }
-  throw new Error(
-    `unknown native database storage kind '${String((storage as { kind?: unknown }).kind)}'`,
-  );
-}
-
-async function removeDirectory(path: string): Promise {
-  await rm(path, { recursive: true, force: true }).catch(() => {});
-}
-
-function synchronousProtocolChunkConsumer(callback: (chunk: Uint8Array) => unknown): {
-  callback: ProtocolChunkCallback;
-  failure?: { error: unknown };
-} {
-  const consumer: {
-    callback: ProtocolChunkCallback;
-    failure?: { error: unknown };
-  } = {
-    callback(chunk) {
-      try {
-        const result = (callback as (chunk: Uint8Array) => unknown)(chunk);
-        if (!isThenable(result)) return;
-        // A synchronous chunk boundary cannot await caller work. Observe any
-        // eventual rejection before reporting the contract violation.
-        void Promise.resolve(result).catch(() => undefined);
-        throw new TypeError(
-          'raw protocol stream callback must complete synchronously and must not return a Promise or thenable',
-        );
-      } catch (error) {
-        consumer.failure ??= { error };
-        throw error;
-      }
-    },
-  };
-  return consumer;
-}
-
-function streamCallbackReentryError(): Error {
-  return new Error(
-    'raw protocol stream callback must not re-enter the same Oliphaunt handle; cancel remains available',
-  );
-}
-
-function isThenable(value: unknown): value is PromiseLike {
-  return (
-    ((typeof value === 'object' && value !== null) || typeof value === 'function') &&
-    typeof (value as { then?: unknown }).then === 'function'
-  );
-}
diff --git a/src/sdks/js/src/generated/extensions.ts b/src/sdks/js/src/generated/extensions.ts
deleted file mode 100644
index d4fc5a6b6..000000000
--- a/src/sdks/js/src/generated/extensions.ts
+++ /dev/null
@@ -1,966 +0,0 @@
-// This file is generated by src/extensions/tools/check-extension-model.mjs.
-// Do not edit by hand.
-
-export type GeneratedExtensionMetadata = {
-  readonly id: string;
-  readonly sqlName: string;
-  readonly displayName: string;
-  readonly postgresMajor: number;
-  readonly artifactProduct: string;
-  readonly releaseProduct: string;
-  readonly cargoPackage: string;
-  readonly npmPackage: string;
-  readonly mavenGroup: string;
-  readonly mavenArtifact: string;
-  readonly runtimeBound: boolean;
-  readonly createsExtension: boolean;
-  readonly nativeModuleStem: string | null;
-  readonly dependencies: readonly string[];
-  readonly selectedExtensionDependencies: readonly string[];
-  readonly sharedPreloadLibraries: readonly string[];
-  readonly dataFiles: readonly string[];
-  readonly runtimeShareDataFiles: readonly string[];
-  readonly extensionSqlFilePrefixes: readonly string[];
-  readonly extensionSqlFileNames: readonly string[];
-  readonly sourceKind: string;
-};
-
-export const GENERATED_EXTENSION_METADATA_SHA256 =
-  'c1d2e09905d7ecc0172173b34b9e4104dad58987503dd3dab7af4ae78890d9f3' as const;
-
-export const GENERATED_EXTENSION_METADATA = [
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'amcheck',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'amcheck',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'amcheck',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'amcheck',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: false,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'auto_explain',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'auto_explain',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'auto_explain',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'auto_explain',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'bloom',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'bloom',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'bloom',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'bloom',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'btree_gin',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'btree_gin',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'btree_gin',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'btree_gin',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'btree_gist',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'btree_gist',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'btree_gist',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'btree_gist',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'citext',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'citext',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'citext',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'citext',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'cube',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'cube',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'cube',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'cube',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'dict_int',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'dict_int',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'dict_int',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'dict_int',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: ['share/postgresql/tsearch_data/xsyn_sample.rules'],
-    dependencies: [],
-    displayName: 'dict_xsyn',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'dict_xsyn',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'dict_xsyn',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: ['tsearch_data/xsyn_sample.rules'],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'dict_xsyn',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: ['cube'],
-    displayName: 'earthdistance',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'earthdistance',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'earthdistance',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: ['cube'],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'earthdistance',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'file_fdw',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'file_fdw',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'file_fdw',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'file_fdw',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'fuzzystrmatch',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'fuzzystrmatch',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'fuzzystrmatch',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'fuzzystrmatch',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'hstore',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'hstore',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'hstore',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'hstore',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'intarray',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'intarray',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: '_int',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'intarray',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'isn',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'isn',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'isn',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'isn',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'lo',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'lo',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'lo',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'lo',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'ltree',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'ltree',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'ltree',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'ltree',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pageinspect',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pageinspect',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pageinspect',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pageinspect',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_buffercache',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_buffercache',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_buffercache',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_buffercache',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_freespacemap',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_freespacemap',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_freespacemap',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_freespacemap',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pg-hashids',
-    cargoPackage: 'oliphaunt-extension-pg-hashids',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_hashids',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_hashids',
-    mavenArtifact: 'oliphaunt-extension-pg-hashids',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_hashids',
-    npmPackage: '@oliphaunt/extension-pg-hashids',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pg-hashids',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pg_hashids',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pg-ivm',
-    cargoPackage: 'oliphaunt-extension-pg-ivm',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_ivm',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_ivm',
-    mavenArtifact: 'oliphaunt-extension-pg-ivm',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_ivm',
-    npmPackage: '@oliphaunt/extension-pg-ivm',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pg-ivm',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pg_ivm',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_surgery',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_surgery',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_surgery',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_surgery',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pg-textsearch',
-    cargoPackage: 'oliphaunt-extension-pg-textsearch',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_textsearch',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_textsearch',
-    mavenArtifact: 'oliphaunt-extension-pg-textsearch',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_textsearch',
-    npmPackage: '@oliphaunt/extension-pg-textsearch',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pg-textsearch',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: ['pg_textsearch'],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pg_textsearch',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_trgm',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_trgm',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_trgm',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_trgm',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pg-uuidv7',
-    cargoPackage: 'oliphaunt-extension-pg-uuidv7',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_uuidv7',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_uuidv7',
-    mavenArtifact: 'oliphaunt-extension-pg-uuidv7',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_uuidv7',
-    npmPackage: '@oliphaunt/extension-pg-uuidv7',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pg-uuidv7',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pg_uuidv7',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_visibility',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_visibility',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_visibility',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_visibility',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_walinspect',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_walinspect',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_walinspect',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_walinspect',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pgcrypto',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pgcrypto',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pgcrypto',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pgcrypto',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pgtap',
-    cargoPackage: 'oliphaunt-extension-pgtap',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: ['plpgsql'],
-    displayName: 'pgtap',
-    extensionSqlFileNames: ['uninstall_pgtap.sql'],
-    extensionSqlFilePrefixes: ['pgtap-core', 'pgtap-schema'],
-    id: 'pgtap',
-    mavenArtifact: 'oliphaunt-extension-pgtap',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: null,
-    npmPackage: '@oliphaunt/extension-pgtap',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pgtap',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pgtap',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-postgis',
-    cargoPackage: 'oliphaunt-extension-postgis',
-    createsExtension: true,
-    dataFiles: [
-      'share/postgresql/contrib/postgis-3.6/legacy.sql',
-      'share/postgresql/contrib/postgis-3.6/legacy_gist.sql',
-      'share/postgresql/contrib/postgis-3.6/legacy_minimal.sql',
-      'share/postgresql/contrib/postgis-3.6/postgis.sql',
-      'share/postgresql/contrib/postgis-3.6/postgis_upgrade.sql',
-      'share/postgresql/contrib/postgis-3.6/spatial_ref_sys.sql',
-      'share/postgresql/contrib/postgis-3.6/uninstall_legacy.sql',
-      'share/postgresql/contrib/postgis-3.6/uninstall_postgis.sql',
-      'share/postgresql/proj/proj.db',
-    ],
-    dependencies: [],
-    displayName: 'PostGIS',
-    extensionSqlFileNames: ['uninstall_postgis.sql'],
-    extensionSqlFilePrefixes: ['postgis_comments', 'postgis_proc_set_search_path', 'rtpostgis'],
-    id: 'postgis',
-    mavenArtifact: 'oliphaunt-extension-postgis',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'postgis-3',
-    npmPackage: '@oliphaunt/extension-postgis',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-postgis',
-    runtimeBound: false,
-    runtimeShareDataFiles: [
-      'contrib/postgis-3.6/legacy.sql',
-      'contrib/postgis-3.6/legacy_gist.sql',
-      'contrib/postgis-3.6/legacy_minimal.sql',
-      'contrib/postgis-3.6/postgis.sql',
-      'contrib/postgis-3.6/postgis_upgrade.sql',
-      'contrib/postgis-3.6/spatial_ref_sys.sql',
-      'contrib/postgis-3.6/uninstall_legacy.sql',
-      'contrib/postgis-3.6/uninstall_postgis.sql',
-      'proj/proj.db',
-    ],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgis',
-    sqlName: 'postgis',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'seg',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'seg',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'seg',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'seg',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'tablefunc',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'tablefunc',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'tablefunc',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'tablefunc',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'tcn',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'tcn',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'tcn',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'tcn',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'tsm_system_rows',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'tsm_system_rows',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'tsm_system_rows',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'tsm_system_rows',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'tsm_system_time',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'tsm_system_time',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'tsm_system_time',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'tsm_system_time',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: ['share/postgresql/tsearch_data/unaccent.rules'],
-    dependencies: [],
-    displayName: 'unaccent',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'unaccent',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'unaccent',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: ['tsearch_data/unaccent.rules'],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'unaccent',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'uuid-ossp',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'uuid_ossp',
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'uuid-ossp',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'uuid-ossp',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-vector',
-    cargoPackage: 'oliphaunt-extension-vector',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pgvector',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'vector',
-    mavenArtifact: 'oliphaunt-extension-vector',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'vector',
-    npmPackage: '@oliphaunt/extension-vector',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-vector',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'vector',
-  },
-] as const satisfies readonly GeneratedExtensionMetadata[];
-
-export function generatedExtensionBySqlName(
-  sqlName: string,
-): GeneratedExtensionMetadata | undefined {
-  return GENERATED_EXTENSION_METADATA.find((extension) => extension.sqlName === sqlName);
-}
-
-export function generatedSharedPreloadLibraries(extensionSqlNames: readonly string[]): string[] {
-  const libraries = new Set();
-  for (const sqlName of extensionSqlNames) {
-    const extension = generatedExtensionBySqlName(sqlName);
-    for (const library of extension?.sharedPreloadLibraries ?? []) {
-      libraries.add(library);
-    }
-  }
-  return [...libraries].sort();
-}
diff --git a/src/sdks/js/src/index.ts b/src/sdks/js/src/index.ts
deleted file mode 100644
index ae8698e85..000000000
--- a/src/sdks/js/src/index.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-export {
-  array,
-  binary,
-  json,
-  postgresOids,
-  text,
-  typedNull,
-  type BinaryQueryParameter,
-  type CommandResult,
-  type DescribeResult,
-  type EncodedQueryParameter,
-  type ExecResult,
-  type InferQueryRow,
-  type NullQueryParameter,
-  type ParameterOptions,
-  PostgresError,
-  type PostgresErrorField,
-  type PostgresNotice,
-  type QueryArrayRow,
-  type QueryBinaryInput,
-  type QueryDecoderMap,
-  type QueryField,
-  type QueryFormat,
-  type QueryObjectRow,
-  type QueryOptions,
-  type QueryParam,
-  type QueryParameterEncoder,
-  type QueryResult,
-  type QueryRowMode,
-  type QueryValue,
-  type QueryValueDecoder,
-  type RawQueryResult,
-  type RawQueryRow,
-  type TextQueryParameter,
-  type TransactionStatus,
-} from './query.js';
-export type {
-  BinaryInput,
-  DatabaseStorage,
-  OliphauntClient,
-  OliphauntDatabase,
-  OliphauntTransaction,
-  OliphauntServer,
-  OpenConfig,
-  RestoreOptions,
-  ServerListen,
-  ServerOpenConfig,
-} from './types.js';
-
-import { createOliphauntClient } from './client.js';
-import type { OliphauntClient } from './types.js';
-
-export const Oliphaunt: OliphauntClient = createOliphauntClient();
-
-export default Oliphaunt;
diff --git a/src/sdks/js/src/native/assets-deno.ts b/src/sdks/js/src/native/assets-deno.ts
deleted file mode 100644
index 45b1dce90..000000000
--- a/src/sdks/js/src/native/assets-deno.ts
+++ /dev/null
@@ -1,534 +0,0 @@
-import { createRequire } from 'node:module';
-import { join } from 'node:path';
-import { fileURLToPath, pathToFileURL } from 'node:url';
-
-import {
-  liboliphauntPackageTarget,
-  type NativePackageTarget,
-  resolveExplicitLibraryPath,
-  resolveExplicitRuntimeDirectory,
-} from './common.js';
-import { type RuntimeFileHost, validatePreparedRuntimeExtensions } from './extension-runtime.js';
-import {
-  requireIcuDataTreeSha256,
-  requireIcuManifestRelativePath,
-  requireNativeClusterSeedPath,
-  requireNativeClusterSeedTarget,
-  validateNativeClusterSeedManifest,
-  validateNativeIcuDataReceipt,
-  validateNativeRuntimeCarrierReceipt,
-  type NativeCatalogProfile,
-} from './cluster-seed.js';
-
-export type ResolvedDenoNativeInstall = {
-  libraryPath: string;
-  runtimeDirectory?: string;
-  icuDataDirectory?: string;
-  clusterSeedDirectory?: string;
-  catalogProfile?: NativeCatalogProfile;
-  packageManaged: boolean;
-};
-
-export type DenoRuntime = {
-  build: { os: string; arch: string };
-  env?: { get(name: string): string | undefined };
-  readTextFile(path: string | URL): Promise;
-  readDir(
-    path: string | URL,
-  ): AsyncIterable<{ name: string; isFile?: boolean; isDirectory?: boolean }>;
-  stat(path: string | URL): Promise<{ isFile?: boolean; isDirectory?: boolean }>;
-};
-const require = createRequire(import.meta.url);
-
-type PackageMetadata = {
-  name: string;
-  oliphaunt?: {
-    liboliphauntVersion?: string;
-    icuPackage?: string;
-    icuVersion?: string;
-  };
-};
-
-type LiboliphauntPackageMetadata = {
-  name?: string;
-  version?: string;
-  oliphaunt?: {
-    target?: string;
-    libraryRelativePath?: string;
-    runtimeRelativePath?: string;
-    clusterSeedRelativePath?: string;
-    icuClusterSeedRelativePath?: string;
-    clusterSeedTarget?: string;
-  };
-};
-
-type IcuPackageMetadata = {
-  name?: string;
-  version?: string;
-  oliphaunt?: {
-    product?: string;
-    kind?: string;
-    target?: string;
-    dataRelativePath?: string;
-    manifestRelativePath?: string;
-    icuDataTreeSha256?: string;
-  };
-};
-
-type ResolvedDenoIcuResources = {
-  dataDirectory: string;
-  dataTreeSha256: string;
-};
-
-export async function resolveDenoNativeInstall(
-  libraryPath?: string,
-): Promise {
-  const explicit = resolveExplicitLibraryPath(libraryPath);
-  if (explicit !== undefined) {
-    const deno = optionalDenoRuntime();
-    const versions = deno === undefined ? undefined : await packageVersions(deno);
-    const icuDataDirectory =
-      deno === undefined || versions === undefined
-        ? undefined
-        : (await resolveDenoIcuResources(deno, versions.icuVersion, versions.icuPackage))
-            ?.dataDirectory;
-    return {
-      libraryPath: explicit,
-      runtimeDirectory: resolveExplicitRuntimeDirectory(),
-      icuDataDirectory,
-      catalogProfile: icuDataDirectory === undefined ? 'standard' : 'icu',
-      packageManaged: false,
-    };
-  }
-
-  const deno = denoRuntime();
-  const versions = await packageVersions(deno);
-  const icu = await resolveDenoIcuResources(deno, versions.icuVersion, versions.icuPackage);
-  const target = liboliphauntPackageTarget(deno.build.os, deno.build.arch);
-  return resolvePackageNativeInstall(deno, target, versions.liboliphauntVersion, icu);
-}
-
-export async function validatePreparedDenoRuntimeExtensions(config: {
-  deno: DenoRuntime;
-  runtimeDirectory?: string;
-  extensions: ReadonlyArray;
-  source: string;
-}): Promise<{ runtimeDirectory: string; moduleDirectory?: string }> {
-  const target = liboliphauntPackageTarget(config.deno.build.os, config.deno.build.arch);
-  return validatePreparedRuntimeExtensions({
-    runtimeDirectory: config.runtimeDirectory,
-    extensions: config.extensions,
-    target: target.id,
-    source: config.source,
-    host: denoRuntimeFileHost(config.deno),
-  });
-}
-
-async function packageVersions(deno: DenoRuntime): Promise<{
-  liboliphauntVersion: string;
-  icuPackage: string;
-  icuVersion: string;
-}> {
-  const packageUrl = new URL('../../package.json', import.meta.url);
-  const packageJson = JSON.parse(await deno.readTextFile(packageUrl)) as PackageMetadata;
-  const liboliphauntVersion = packageJson.oliphaunt?.liboliphauntVersion;
-  const icuPackage = packageJson.oliphaunt?.icuPackage;
-  const icuVersion = packageJson.oliphaunt?.icuVersion;
-  if (
-    packageJson.name !== '@oliphaunt/ts' ||
-    liboliphauntVersion === undefined ||
-    liboliphauntVersion.length === 0
-  ) {
-    throw new Error('@oliphaunt/ts package metadata does not pin liboliphauntVersion');
-  }
-  if (icuPackage !== '@oliphaunt/icu' || icuVersion === undefined || icuVersion.length === 0) {
-    throw new Error('@oliphaunt/ts package metadata does not pin @oliphaunt/icu');
-  }
-  return { liboliphauntVersion, icuPackage, icuVersion };
-}
-
-async function resolvePackageNativeInstall(
-  deno: DenoRuntime,
-  target: NativePackageTarget,
-  expectedVersion: string,
-  icu: ResolvedDenoIcuResources | undefined,
-): Promise {
-  const packageJsonUrl = resolvePackageJsonUrl(target.packageName);
-  const packageJson = JSON.parse(
-    await deno.readTextFile(packageJsonUrl),
-  ) as LiboliphauntPackageMetadata;
-  if (packageJson.name !== target.packageName) {
-    throw new Error(
-      `${target.packageName} package metadata has name ${packageJson.name ?? ''}`,
-    );
-  }
-  if (packageJson.version !== expectedVersion) {
-    throw new Error(
-      `${target.packageName} version ${packageJson.version ?? ''} does not match @oliphaunt/ts liboliphauntVersion ${expectedVersion}`,
-    );
-  }
-  if (packageJson.oliphaunt?.target !== target.id) {
-    throw new Error(`${target.packageName} package metadata does not target ${target.id}`);
-  }
-  const clusterSeedTarget = requireNativeClusterSeedTarget(
-    packageJson.oliphaunt.clusterSeedTarget,
-    target.id,
-    `${target.packageName} package metadata`,
-  );
-  const standardClusterSeedRelativePath = requireNativeClusterSeedPath(
-    packageJson.oliphaunt.clusterSeedRelativePath,
-    'cluster-seed',
-    `${target.packageName} clusterSeedRelativePath`,
-  );
-  const icuClusterSeedRelativePath = requireNativeClusterSeedPath(
-    packageJson.oliphaunt.icuClusterSeedRelativePath,
-    'cluster-seed-icu',
-    `${target.packageName} icuClusterSeedRelativePath`,
-  );
-  const packageRoot = new URL('.', packageJsonUrl);
-  const carrierManifestUrl = new URL('manifest.properties', packageRoot);
-  await requireFile(deno, carrierManifestUrl, `${target.packageName} runtime carrier receipt`);
-  validateNativeRuntimeCarrierReceipt(
-    await deno.readTextFile(carrierManifestUrl),
-    clusterSeedTarget,
-    `${target.packageName} runtime carrier receipt`,
-  );
-  const libraryUrl = resolvePackageRelativeUrl(
-    packageRoot,
-    packageJson.oliphaunt?.libraryRelativePath ?? target.libraryRelativePath,
-    `${target.packageName} liboliphaunt library metadata`,
-  );
-  await requireFile(deno, libraryUrl, `${target.packageName} liboliphaunt library`);
-  const runtimeUrl = resolvePackageRelativeUrl(
-    packageRoot,
-    packageJson.oliphaunt?.runtimeRelativePath ?? target.runtimeRelativePath,
-    `${target.packageName} runtime directory metadata`,
-  );
-  await requireDirectory(deno, runtimeUrl, `${target.packageName} runtime directory`);
-  for (const tool of nativeRuntimeToolsForTarget(target.id)) {
-    await requireFile(
-      deno,
-      new URL(`bin/${tool}`, directoryUrl(runtimeUrl)),
-      `${target.packageName} runtime tool bin/${tool}`,
-    );
-  }
-  const standardClusterSeedUrl = resolvePackageRelativeUrl(
-    packageRoot,
-    standardClusterSeedRelativePath,
-    `${target.packageName} standard cluster seed metadata`,
-  );
-  await requireClusterSeedDirectory(
-    deno,
-    standardClusterSeedUrl,
-    'standard',
-    clusterSeedTarget,
-    `${target.packageName} standard cluster seed`,
-  );
-  const selectedClusterSeedUrl =
-    icu === undefined
-      ? standardClusterSeedUrl
-      : resolvePackageRelativeUrl(
-          packageRoot,
-          icuClusterSeedRelativePath,
-          `${target.packageName} ICU cluster seed metadata`,
-        );
-  let icuDataTreeSha256: string | undefined;
-  if (icu !== undefined) {
-    icuDataTreeSha256 = await requireClusterSeedDirectory(
-      deno,
-      selectedClusterSeedUrl,
-      'icu',
-      clusterSeedTarget,
-      `${target.packageName} ICU cluster seed`,
-    );
-    if (icuDataTreeSha256 !== icu.dataTreeSha256) {
-      throw new Error(
-        `${target.packageName} ICU cluster seed and the selected ICU data package identify different logical trees`,
-      );
-    }
-  }
-  const libraryPath = fileURLToPath(libraryUrl);
-  return {
-    libraryPath,
-    runtimeDirectory: fileURLToPath(runtimeUrl),
-    icuDataDirectory: icu?.dataDirectory,
-    clusterSeedDirectory: fileURLToPath(selectedClusterSeedUrl),
-    catalogProfile: icu === undefined ? 'standard' : 'icu',
-    packageManaged: true,
-  };
-}
-
-async function resolveDenoIcuResources(
-  deno: DenoRuntime,
-  expectedVersion: string,
-  packageName: string,
-): Promise {
-  const packageJsonUrl = optionalResolvePackageJsonUrl(packageName);
-  if (packageJsonUrl === undefined) {
-    return undefined;
-  }
-  const packageJson = JSON.parse(await deno.readTextFile(packageJsonUrl)) as IcuPackageMetadata;
-  validateDenoIcuPackageMetadata(packageJson, packageName, expectedVersion);
-  const metadata = packageJson.oliphaunt!;
-  const dataUrl = resolvePackageRelativeUrl(
-    new URL('.', packageJsonUrl),
-    metadata.dataRelativePath ?? 'share/icu',
-    `${packageName} ICU data directory metadata`,
-  );
-  await requireIcuDataDirectory(deno, dataUrl, `${packageName} ICU data directory`);
-  const manifestRelativePath = requireIcuManifestRelativePath(
-    metadata.dataRelativePath,
-    metadata.manifestRelativePath,
-    `${packageName} package metadata`,
-  );
-  const manifestUrl = resolvePackageRelativeUrl(
-    new URL('.', packageJsonUrl),
-    manifestRelativePath,
-    `${packageName} ICU data manifest metadata`,
-  );
-  await requireFile(deno, manifestUrl, `${packageName} ICU data manifest`);
-  const dataTreeSha256 = requireIcuDataTreeSha256(
-    metadata.icuDataTreeSha256,
-    `${packageName} package metadata`,
-  );
-  const receiptDigest = validateNativeIcuDataReceipt(
-    await deno.readTextFile(manifestUrl),
-    `${packageName} ICU data manifest`,
-  );
-  if (receiptDigest !== dataTreeSha256) {
-    throw new Error(`${packageName} ICU data receipt does not match package metadata`);
-  }
-  return {
-    dataDirectory: fileURLToPath(dataUrl),
-    dataTreeSha256,
-  };
-}
-
-function validateDenoIcuPackageMetadata(
-  packageJson: IcuPackageMetadata,
-  packageName: string,
-  expectedVersion: string,
-): void {
-  if (packageJson.name !== packageName) {
-    throw new Error(`${packageName} package metadata has name ${packageJson.name ?? ''}`);
-  }
-  if (packageJson.version !== expectedVersion) {
-    throw new Error(
-      `${packageName} version ${packageJson.version ?? ''} does not match @oliphaunt/ts icuVersion ${expectedVersion}`,
-    );
-  }
-  if (packageJson.oliphaunt?.product !== 'oliphaunt-icu') {
-    throw new Error(`${packageName} package metadata does not declare oliphaunt-icu`);
-  }
-  if (packageJson.oliphaunt?.kind !== 'icu-data') {
-    throw new Error(`${packageName} package metadata does not declare ICU data`);
-  }
-  if (packageJson.oliphaunt?.target !== 'portable') {
-    throw new Error(`${packageName} package metadata must target portable ICU data`);
-  }
-}
-
-export function resolvePackageRelativeUrl(
-  packageRoot: URL,
-  metadataPath: string,
-  source: string,
-): URL {
-  const relativePath = safePackageRelativePath(metadataPath, source);
-  const resolved = new URL(relativePath, packageRoot);
-  const rootHref = packageRoot.href.endsWith('/') ? packageRoot.href : `${packageRoot.href}/`;
-  if (resolved.protocol !== packageRoot.protocol || !resolved.href.startsWith(rootHref)) {
-    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
-  }
-  return resolved;
-}
-
-function safePackageRelativePath(metadataPath: string, source: string): string {
-  if (metadataPath.length === 0) {
-    throw new Error(`${source} contains unsafe package metadata path: `);
-  }
-  if (metadataPath.includes('\0')) {
-    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
-  }
-  let decoded: string;
-  try {
-    decoded = decodeURIComponent(metadataPath);
-  } catch {
-    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
-  }
-  const normalized = decoded.replaceAll('\\', '/');
-  if (
-    normalized.startsWith('/') ||
-    /^[A-Za-z][A-Za-z0-9+.-]*:/.test(normalized) ||
-    normalized.split('/').includes('..')
-  ) {
-    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
-  }
-  return normalized;
-}
-
-function nativeRuntimeToolsForTarget(target: string): string[] {
-  return target === 'windows-x64-msvc'
-    ? ['initdb.exe', 'pg_ctl.exe', 'postgres.exe']
-    : ['initdb', 'pg_ctl', 'postgres'];
-}
-
-function directoryUrl(url: URL): URL {
-  return url.href.endsWith('/') ? url : new URL(`${url.href}/`);
-}
-
-function resolvePackageJsonUrl(packageName: string): URL {
-  const specifier = `${packageName}/package.json`;
-  const resolver = (import.meta as ImportMeta & { resolve?: (specifier: string) => string })
-    .resolve;
-  if (resolver === undefined) {
-    return resolvePackageJsonUrlWithRequire(packageName, specifier);
-  }
-  try {
-    return new URL(resolver(specifier));
-  } catch (error) {
-    if (importMetaResolveUnsupported(error)) {
-      return resolvePackageJsonUrlWithRequire(packageName, specifier);
-    }
-    throw new Error(
-      `${packageName} is not installed; import Oliphaunt from npm:@oliphaunt/ts with optional dependencies enabled`,
-      { cause: error },
-    );
-  }
-}
-
-function optionalResolvePackageJsonUrl(packageName: string): URL | undefined {
-  const specifier = `${packageName}/package.json`;
-  const resolver = (import.meta as ImportMeta & { resolve?: (specifier: string) => string })
-    .resolve;
-  if (resolver === undefined) {
-    return optionalResolvePackageJsonUrlWithRequire(specifier);
-  }
-  try {
-    return new URL(resolver(specifier));
-  } catch (error) {
-    if (importMetaResolveUnsupported(error)) {
-      return optionalResolvePackageJsonUrlWithRequire(specifier);
-    }
-    return undefined;
-  }
-}
-
-function resolvePackageJsonUrlWithRequire(packageName: string, specifier: string): URL {
-  const resolved = optionalResolvePackageJsonUrlWithRequire(specifier);
-  if (resolved !== undefined) {
-    return resolved;
-  }
-  throw new Error(
-    `${packageName} is not installed; import Oliphaunt from npm:@oliphaunt/ts with optional dependencies enabled`,
-  );
-}
-
-function optionalResolvePackageJsonUrlWithRequire(specifier: string): URL | undefined {
-  try {
-    return pathToFileURL(require.resolve(specifier));
-  } catch {
-    return undefined;
-  }
-}
-
-function importMetaResolveUnsupported(error: unknown): boolean {
-  return error instanceof Error && error.message.includes('import.meta.resolve');
-}
-
-async function requireFile(deno: DenoRuntime, path: URL, source: string): Promise {
-  try {
-    const info = await deno.stat(path);
-    if (info.isFile === true) {
-      return;
-    }
-  } catch {}
-  throw new Error(
-    `${source} does not point to an existing file: ${decodeURIComponent(path.pathname)}`,
-  );
-}
-
-async function requireDirectory(deno: DenoRuntime, path: URL, source: string): Promise {
-  try {
-    const info = await deno.stat(path);
-    if (info.isDirectory === true) {
-      return;
-    }
-  } catch {}
-  throw new Error(
-    `${source} does not point to an existing directory: ${decodeURIComponent(path.pathname)}`,
-  );
-}
-
-async function requireIcuDataDirectory(
-  deno: DenoRuntime,
-  path: URL,
-  source: string,
-): Promise {
-  await requireDirectory(deno, path, source);
-  for await (const entry of deno.readDir(path)) {
-    if (entry.isFile === true && entry.name.startsWith('icudt') && entry.name.endsWith('.dat')) {
-      return;
-    }
-    if (entry.isDirectory === true && entry.name.startsWith('icudt')) {
-      return;
-    }
-  }
-  throw new Error(
-    `${source} does not contain ICU icudt data files: ${decodeURIComponent(path.pathname)}`,
-  );
-}
-
-async function requireClusterSeedDirectory(
-  deno: DenoRuntime,
-  path: URL,
-  profile: NativeCatalogProfile,
-  target: string,
-  source: string,
-): Promise {
-  await requireDirectory(deno, path, source);
-  const root = directoryUrl(path);
-  await requireFile(deno, new URL('files/PG_VERSION', root), `${source} PG_VERSION`);
-  await requireFile(deno, new URL('files/global/pg_control', root), `${source} pg_control`);
-  const manifest = await deno.readTextFile(new URL('manifest.properties', root)).catch(() => '');
-  return validateNativeClusterSeedManifest(manifest, profile, target, source);
-}
-
-function denoRuntime(): DenoRuntime {
-  const deno = optionalDenoRuntime();
-  if (deno === undefined) {
-    throw new Error('Deno native binding can only be used inside Deno');
-  }
-  return deno;
-}
-
-function optionalDenoRuntime(): DenoRuntime | undefined {
-  const deno = (globalThis as { Deno?: DenoRuntime }).Deno;
-  return deno;
-}
-
-function denoRuntimeFileHost(deno: DenoRuntime): RuntimeFileHost {
-  return {
-    join,
-    async readDir(path: string) {
-      const entries: Array<{ name: string; isFile?: boolean }> = [];
-      for await (const entry of deno.readDir(path)) {
-        entries.push({ name: entry.name, isFile: entry.isFile });
-      }
-      return entries;
-    },
-    async isDirectory(path: string) {
-      try {
-        return (await deno.stat(path)).isDirectory === true;
-      } catch {
-        return false;
-      }
-    },
-    async isFile(path: string) {
-      try {
-        return (await deno.stat(path)).isFile === true;
-      } catch {
-        return false;
-      }
-    },
-  };
-}
diff --git a/src/sdks/js/src/native/assets-node.ts b/src/sdks/js/src/native/assets-node.ts
deleted file mode 100644
index 32991de3c..000000000
--- a/src/sdks/js/src/native/assets-node.ts
+++ /dev/null
@@ -1,1765 +0,0 @@
-import { createHash, randomUUID } from 'node:crypto';
-import { createReadStream } from 'node:fs';
-import { cp, lstat, mkdir, readdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
-import { createRequire } from 'node:module';
-import { arch, platform, tmpdir } from 'node:os';
-import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
-import { setTimeout as delay } from 'node:timers/promises';
-import {
-  GENERATED_EXTENSION_METADATA,
-  generatedExtensionBySqlName,
-  type GeneratedExtensionMetadata,
-} from '../generated/extensions.js';
-import {
-  liboliphauntPackageTarget,
-  type NativePackageTarget,
-  resolveExplicitLibraryPath,
-  resolveExplicitRuntimeDirectory,
-} from './common.js';
-import {
-  parseNpmExtensionLicenseFiles,
-  type NpmExtensionLicenseFileContract,
-} from './extension-contract.js';
-import {
-  nativeModuleSuffixForTarget,
-  selectedExtensionClosure,
-  type RuntimeFileHost,
-  validatePreparedRuntimeExtensions,
-} from './extension-runtime.js';
-import { syncDirectory, syncRuntimeDirectoryTree } from './filesystem-durability.js';
-import {
-  requireIcuDataTreeSha256,
-  requireIcuManifestRelativePath,
-  requireNativeClusterSeedPath,
-  requireNativeClusterSeedTarget,
-  validateNativeClusterSeedManifest,
-  validateNativeIcuDataReceipt,
-  validateNativeRuntimeCarrierReceipt,
-  type NativeCatalogProfile,
-} from './cluster-seed.js';
-
-export type ResolvedNativeInstall = {
-  libraryPath: string;
-  runtimeDirectory?: string;
-  icuDataDirectory?: string;
-  clusterSeedDirectory?: string;
-  catalogProfile?: NativeCatalogProfile;
-  moduleDirectory?: string;
-  packageManaged?: boolean;
-};
-
-type PackageMetadata = {
-  name: string;
-  oliphaunt?: {
-    liboliphauntVersion?: string;
-    icuPackage?: string;
-    icuVersion?: string;
-  };
-};
-
-type LiboliphauntPackageMetadata = {
-  name?: string;
-  version?: string;
-  oliphaunt?: {
-    target?: string;
-    libraryRelativePath?: string;
-    runtimeRelativePath?: string;
-    clusterSeedRelativePath?: string;
-    icuClusterSeedRelativePath?: string;
-    clusterSeedTarget?: string;
-  };
-};
-
-type IcuPackageMetadata = {
-  name?: string;
-  version?: string;
-  oliphaunt?: {
-    product?: string;
-    kind?: string;
-    target?: string;
-    dataRelativePath?: string;
-    manifestRelativePath?: string;
-    icuDataTreeSha256?: string;
-  };
-};
-
-type ResolvedNodeIcuResources = {
-  dataDirectory: string;
-  dataTreeSha256: string;
-};
-
-type ExtensionPackageMetadata = {
-  name?: string;
-  version?: string;
-  oliphaunt?: {
-    product?: string;
-    kind?: string;
-    sqlName?: string;
-    target?: string;
-    runtimeRelativePath?: string;
-    moduleRelativePath?: string;
-    liboliphauntVersion?: string;
-    bundleManifest?: string;
-    extensionContract?: string;
-    members?: string[];
-    memberRuntimeRelativePaths?: Record;
-    memberModuleRelativePaths?: Record;
-    targetPackageNames?: Record;
-  };
-};
-
-type NpmExtensionRuntimeBundleMember = {
-  sqlName: string;
-  kind: 'runtime';
-  identity: null;
-  path: string;
-  sha256: string;
-  bytes: number;
-  runtimeRelativePath: string;
-  moduleRelativePath?: string;
-};
-
-type NpmExtensionMemberContract = {
-  sqlName: string;
-  createsExtension: boolean;
-  nativeModuleStem: string | null;
-  dependencies: string[];
-  dataFiles: string[];
-  extensionSqlFileNames: string[];
-  extensionSqlFilePrefixes: string[];
-  licenseFiles: NpmExtensionLicenseFileContract[];
-  sharedPreloadLibraries: string[];
-};
-
-type NpmExtensionContractManifest = {
-  schema?: string;
-  product?: string;
-  version?: string;
-  family?: string;
-  target?: string;
-  members?: unknown[];
-};
-
-type NpmExtensionBundleManifest = {
-  schema?: string;
-  product?: string;
-  version?: string;
-  family?: string;
-  target?: string;
-  members?: unknown[];
-};
-
-const require = createRequire(import.meta.url);
-const CACHE_LOCK_POLL_MS = 25;
-const CACHE_LOCK_TIMEOUT_MS = 30_000;
-const CACHE_LOCK_STALE_MS = 5 * 60_000;
-const MAX_EXTENSION_RUNTIME_FILES = 4096;
-const MAX_EXTENSION_RUNTIME_FILE_BYTES = 48 * 1024 * 1024;
-const MAX_EXTENSION_RUNTIME_BYTES = 256 * 1024 * 1024;
-const NPM_EXTENSION_CONTRACT_SCHEMA = 'oliphaunt-npm-extension-contract-v1';
-const NPM_EXTENSION_CONTRACT_MEMBER_FIELDS = [
-  'createsExtension',
-  'dataFiles',
-  'dependencies',
-  'extensionSqlFileNames',
-  'extensionSqlFilePrefixes',
-  'licenseFiles',
-  'nativeModuleStem',
-  'sharedPreloadLibraries',
-  'sqlName',
-] as const;
-
-export async function resolveNodeNativeInstall(
-  libraryPath?: string,
-): Promise {
-  const versions = await packageVersions();
-  const explicit = resolveExplicitLibraryPath(libraryPath);
-  if (explicit !== undefined) {
-    const icuDataDirectory = await resolveNodeIcuDataDirectory(
-      versions.icuVersion,
-      versions.icuPackage,
-    );
-    return {
-      libraryPath: explicit,
-      runtimeDirectory: resolveExplicitRuntimeDirectory(),
-      icuDataDirectory,
-      catalogProfile: icuDataDirectory === undefined ? 'standard' : 'icu',
-      packageManaged: false,
-    };
-  }
-
-  const icu = await resolveNodeIcuResources(versions.icuVersion, versions.icuPackage);
-  const target = liboliphauntPackageTarget(platform(), arch());
-  return resolvePackageNativeInstall(target, versions.liboliphauntVersion, icu);
-}
-
-export async function prepareNodeExtensionInstall(
-  install: ResolvedNativeInstall,
-  extensions: ReadonlyArray = [],
-  options: { explicitRuntimeDirectory?: boolean } = {},
-): Promise {
-  if (options.explicitRuntimeDirectory === true && extensions.length > 0) {
-    return validatePreparedNodeRuntimeExtensions(install, extensions);
-  }
-  return materializeNodeExtensionInstall(install, extensions);
-}
-
-export async function validatePreparedNodeRuntimeExtensions(
-  install: ResolvedNativeInstall,
-  extensions: ReadonlyArray = [],
-): Promise {
-  const target = liboliphauntPackageTarget(platform(), arch());
-  const validated = await validatePreparedRuntimeExtensions({
-    runtimeDirectory: install.runtimeDirectory,
-    extensions,
-    target: target.id,
-    source: 'explicit native runtimeDirectory',
-    host: nodeRuntimeFileHost,
-  });
-  return {
-    ...install,
-    runtimeDirectory: validated.runtimeDirectory,
-    moduleDirectory: validated.moduleDirectory,
-  };
-}
-
-export async function materializeNodeExtensionInstall(
-  install: ResolvedNativeInstall,
-  extensions: ReadonlyArray = [],
-): Promise {
-  const selected = selectedExtensionClosure(extensions);
-  if (selected.length === 0) {
-    return install;
-  }
-  if (install.runtimeDirectory === undefined) {
-    throw new Error(
-      `native extension packages require a package-managed runtime directory; selected extensions: ${selected.join(', ')}`,
-    );
-  }
-  const installRuntimeDirectory = install.runtimeDirectory;
-
-  const versions = await packageVersions();
-  const target = liboliphauntPackageTarget(platform(), arch());
-  const packages = await Promise.all(
-    selected.map((sqlName) =>
-      resolveExtensionPackage(sqlName, target.id, versions.liboliphauntVersion),
-    ),
-  );
-  const cacheKey = runtimeCacheKey({
-    libraryPath: install.libraryPath,
-    runtimeDirectory: installRuntimeDirectory,
-    target: target.id,
-    packages: packages.map((entry) => ({
-      name: entry.name,
-      version: entry.version,
-      contract: entry.contract,
-      runtimeDirectories: entry.runtimeDirectories,
-      moduleDirectories: entry.moduleDirectories,
-    })),
-  });
-  const root = join(tmpdir(), 'oliphaunt-js-runtime-cache', cacheKey);
-  const runtimeDirectory = join(root, 'runtime');
-  const moduleDirectory = join(root, 'modules');
-  const marker = join(root, 'manifest.json');
-  const manifest = JSON.stringify(
-    {
-      runtimeDirectory: installRuntimeDirectory,
-      libraryPath: install.libraryPath,
-      target: target.id,
-      packages: packages.map((entry) => ({
-        name: entry.name,
-        version: entry.version,
-        sqlName: entry.sqlName,
-        contract: entry.contract,
-      })),
-    },
-    null,
-    2,
-  );
-  if ((await optionalRead(marker)) === manifest) {
-    return { ...install, runtimeDirectory, moduleDirectory };
-  }
-
-  await publishRuntimeCache(root, manifest, async (stageRoot) => {
-    const stageRuntimeDirectory = join(stageRoot, 'runtime');
-    const stageModuleDirectory = join(stageRoot, 'modules');
-    await cp(installRuntimeDirectory, stageRuntimeDirectory, {
-      recursive: true,
-    });
-    await mkdir(stageModuleDirectory, { recursive: true });
-    for (const source of nativeModuleDirectoryCandidates(install.libraryPath)) {
-      if (await isDirectory(source)) {
-        await cp(source, stageModuleDirectory, {
-          force: true,
-          recursive: true,
-        });
-      }
-    }
-    for (const entry of packages) {
-      for (const source of entry.runtimeDirectories) {
-        await cp(source, stageRuntimeDirectory, {
-          force: true,
-          recursive: true,
-        });
-      }
-      for (const source of entry.moduleDirectories) {
-        if (await isDirectory(source)) {
-          await cp(source, stageModuleDirectory, {
-            force: true,
-            recursive: true,
-          });
-        }
-      }
-    }
-  });
-  return { ...install, runtimeDirectory, moduleDirectory };
-}
-
-export async function resolveNodeIcuDataDirectory(
-  expectedVersion?: string,
-  packageName?: string,
-): Promise {
-  return (await resolveNodeIcuResources(expectedVersion, packageName))?.dataDirectory;
-}
-
-async function resolveNodeIcuResources(
-  expectedVersion?: string,
-  packageName?: string,
-): Promise {
-  const versions =
-    expectedVersion === undefined || packageName === undefined
-      ? await packageVersions()
-      : undefined;
-  const expected = expectedVersion ?? versions?.icuVersion;
-  const name = packageName ?? versions?.icuPackage ?? '@oliphaunt/icu';
-  const packageJsonPath = optionalResolvePackageJson(name);
-  if (packageJsonPath === undefined) {
-    return undefined;
-  }
-  const packageRoot = dirname(packageJsonPath);
-  const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as IcuPackageMetadata;
-  if (packageJson.name !== name) {
-    throw new Error(`${name} package metadata has name ${packageJson.name ?? ''}`);
-  }
-  if (expected !== undefined && packageJson.version !== expected) {
-    throw new Error(
-      `${name} version ${packageJson.version ?? ''} does not match @oliphaunt/ts icuVersion ${expected}`,
-    );
-  }
-  if (packageJson.oliphaunt?.product !== 'oliphaunt-icu') {
-    throw new Error(`${name} package metadata does not declare oliphaunt-icu`);
-  }
-  if (packageJson.oliphaunt?.kind !== 'icu-data') {
-    throw new Error(`${name} package metadata does not declare ICU data`);
-  }
-  if (packageJson.oliphaunt?.target !== 'portable') {
-    throw new Error(`${name} package metadata must target portable ICU data`);
-  }
-  const dataDirectory = resolvePackageRelativePath(
-    packageRoot,
-    packageJson.oliphaunt.dataRelativePath ?? 'share/icu',
-    `${name} ICU data directory metadata`,
-  );
-  await requireIcuDataDirectory(dataDirectory, `${name} ICU data directory`);
-  const manifestRelativePath = requireIcuManifestRelativePath(
-    packageJson.oliphaunt.dataRelativePath,
-    packageJson.oliphaunt.manifestRelativePath,
-    `${name} package metadata`,
-  );
-  const manifestPath = resolvePackageRelativePath(
-    packageRoot,
-    manifestRelativePath,
-    `${name} ICU data manifest metadata`,
-  );
-  await requireFile(manifestPath, `${name} ICU data manifest`);
-  const dataTreeSha256 = requireIcuDataTreeSha256(
-    packageJson.oliphaunt.icuDataTreeSha256,
-    `${name} package metadata`,
-  );
-  const receiptDigest = validateNativeIcuDataReceipt(
-    await readFile(manifestPath, 'utf8'),
-    `${name} ICU data manifest`,
-  );
-  if (receiptDigest !== dataTreeSha256) {
-    throw new Error(`${name} ICU data receipt does not match package metadata`);
-  }
-  return { dataDirectory, dataTreeSha256 };
-}
-
-async function packageVersions(): Promise<{
-  liboliphauntVersion: string;
-  icuPackage: string;
-  icuVersion: string;
-}> {
-  const packageJson = JSON.parse(
-    await readFile(require.resolve('@oliphaunt/ts/package.json'), 'utf8'),
-  ) as PackageMetadata;
-  const liboliphauntVersion = packageJson.oliphaunt?.liboliphauntVersion;
-  const icuPackage = packageJson.oliphaunt?.icuPackage;
-  const icuVersion = packageJson.oliphaunt?.icuVersion;
-  if (
-    packageJson.name !== '@oliphaunt/ts' ||
-    liboliphauntVersion === undefined ||
-    liboliphauntVersion.length === 0
-  ) {
-    throw new Error('@oliphaunt/ts package metadata does not pin liboliphauntVersion');
-  }
-  if (icuPackage !== '@oliphaunt/icu' || icuVersion === undefined || icuVersion.length === 0) {
-    throw new Error('@oliphaunt/ts package metadata does not pin @oliphaunt/icu');
-  }
-  return { liboliphauntVersion, icuPackage, icuVersion };
-}
-
-type ResolvedExtensionPackage = {
-  name: string;
-  version: string;
-  sqlName: string;
-  contract: NpmExtensionMemberContract;
-  runtimeDirectories: string[];
-  moduleDirectories: string[];
-};
-
-async function resolveExtensionPackage(
-  sqlName: string,
-  target: string,
-  liboliphauntVersion: string,
-): Promise {
-  const extension = generatedExtensionBySqlName(sqlName);
-  if (extension === undefined) {
-    throw new Error(`unknown Oliphaunt extension id '${sqlName}'`);
-  }
-  const packageName = extension.npmPackage;
-  const targetPackageName = extensionTargetPackageName(extension, target);
-  const resolvedTarget = await resolveExtensionTargetPackageJson(
-    extension,
-    targetPackageName,
-    target,
-  );
-  const packageJsonPath = resolvedTarget.packageJsonPath;
-  const packageRoot = dirname(packageJsonPath);
-  const packageJson = JSON.parse(
-    await readFile(packageJsonPath, 'utf8'),
-  ) as ExtensionPackageMetadata;
-  const expectedProduct = extension.artifactProduct;
-  const expectedMembers = extensionOwnerMembers(extension);
-  const isBundle = expectedMembers.length > 1;
-  if (packageJson.name !== targetPackageName) {
-    throw new Error(
-      `${targetPackageName} package metadata has name ${packageJson.name ?? ''}`,
-    );
-  }
-  const expectedKind = isBundle ? 'exact-extension-bundle-target' : 'exact-extension-target';
-  if (packageJson.oliphaunt?.kind !== expectedKind) {
-    throw new Error(`${targetPackageName} package metadata does not declare ${expectedKind}`);
-  }
-  if (packageJson.oliphaunt?.product !== expectedProduct) {
-    throw new Error(`${targetPackageName} package metadata does not declare ${expectedProduct}`);
-  }
-  requireExtensionPackageMembers(packageJson, expectedMembers, targetPackageName);
-  if (packageJson.oliphaunt?.target !== target) {
-    throw new Error(`${targetPackageName} package metadata does not target ${target}`);
-  }
-  if (packageJson.oliphaunt?.liboliphauntVersion !== liboliphauntVersion) {
-    throw new Error(
-      `${targetPackageName} liboliphauntVersion ${packageJson.oliphaunt?.liboliphauntVersion ?? ''} does not match @oliphaunt/ts liboliphauntVersion ${liboliphauntVersion}`,
-    );
-  }
-  if (packageJson.version === undefined || packageJson.version.length === 0) {
-    throw new Error(`${targetPackageName} package metadata is missing version`);
-  }
-  if (packageJson.version !== resolvedTarget.ownerVersion) {
-    throw new Error(
-      `${targetPackageName} version ${packageJson.version} does not match ${packageName} version ${resolvedTarget.ownerVersion}`,
-    );
-  }
-  const memberContracts = await loadExtensionPackageContract({
-    extension,
-    expectedMembers,
-    packageJson,
-    packageRoot,
-    packageName: targetPackageName,
-    target,
-  });
-  const selectedContract = memberContracts.get(sqlName);
-  if (selectedContract === undefined) {
-    throw new Error(
-      `${targetPackageName} extension contract is missing selected member ${sqlName}`,
-    );
-  }
-  const runtimeDirectories: string[] = [];
-  const moduleDirectories: string[] = [];
-  if (isBundle) {
-    const payload = await resolveExtensionBundleMember({
-      extension,
-      expectedMembers,
-      packageJson,
-      packageRoot,
-      packageName: targetPackageName,
-      target,
-      memberContracts,
-    });
-    runtimeDirectories.push(payload.runtimeDirectory);
-    if (payload.moduleDirectory !== undefined) {
-      moduleDirectories.push(payload.moduleDirectory);
-    }
-  } else {
-    const runtimeRelativePath = packageJson.oliphaunt.runtimeRelativePath;
-    if (runtimeRelativePath !== 'runtime') {
-      throw new Error(`${targetPackageName} extension runtime path must be exactly runtime`);
-    }
-    const runtimeDirectory = resolvePackageRelativePath(
-      packageRoot,
-      runtimeRelativePath,
-      `${targetPackageName} extension runtime directory metadata`,
-    );
-    await requireDirectory(runtimeDirectory, `${targetPackageName} extension runtime directory`);
-    await requireExactExtensionRuntimeInventory({
-      contract: selectedContract,
-      runtimeDirectory,
-      target,
-      source: `${targetPackageName} extension runtime directory`,
-    });
-    runtimeDirectories.push(runtimeDirectory);
-    const moduleRelativePath = packageJson.oliphaunt.moduleRelativePath;
-    const expectedModuleRelativePath =
-      selectedContract.nativeModuleStem === null ? undefined : 'runtime/lib/modules';
-    if (moduleRelativePath !== expectedModuleRelativePath) {
-      throw new Error(
-        `${targetPackageName} extension module path must be ${expectedModuleRelativePath ?? ''}`,
-      );
-    }
-    const moduleDirectory =
-      moduleRelativePath === undefined
-        ? undefined
-        : resolvePackageRelativePath(
-            packageRoot,
-            moduleRelativePath,
-            `${targetPackageName} extension module directory metadata`,
-          );
-    if (moduleDirectory !== undefined) {
-      await requireDirectory(moduleDirectory, `${targetPackageName} extension module directory`);
-      moduleDirectories.push(moduleDirectory);
-    }
-  }
-  return {
-    name: targetPackageName,
-    version: packageJson.version,
-    sqlName,
-    contract: selectedContract,
-    runtimeDirectories,
-    moduleDirectories,
-  };
-}
-
-function extensionOwnerMembers(extension: GeneratedExtensionMetadata): string[] {
-  const rows = GENERATED_EXTENSION_METADATA.filter(
-    (candidate) =>
-      candidate.artifactProduct === extension.artifactProduct &&
-      candidate.npmPackage === extension.npmPackage,
-  );
-  if (
-    rows.length === 0 ||
-    rows.some(
-      (candidate) =>
-        candidate.cargoPackage !== extension.cargoPackage ||
-        candidate.mavenGroup !== extension.mavenGroup ||
-        candidate.mavenArtifact !== extension.mavenArtifact ||
-        candidate.runtimeBound !== extension.runtimeBound,
-    )
-  ) {
-    throw new Error(
-      `generated extension metadata has inconsistent release ownership for ${extension.sqlName}`,
-    );
-  }
-  return rows.map((candidate) => candidate.sqlName).sort();
-}
-
-function requireExtensionPackageMembers(
-  packageJson: ExtensionPackageMetadata,
-  expectedMembers: readonly string[],
-  packageName: string,
-): void {
-  if (expectedMembers.length === 1) {
-    if (packageJson.oliphaunt?.sqlName !== expectedMembers[0]) {
-      throw new Error(
-        `${packageName} package metadata does not declare SQL extension ${expectedMembers[0]}`,
-      );
-    }
-    return;
-  }
-  const members = packageJson.oliphaunt?.members;
-  if (
-    !Array.isArray(members) ||
-    members.some((member) => typeof member !== 'string') ||
-    JSON.stringify(members) !== JSON.stringify(expectedMembers)
-  ) {
-    throw new Error(
-      `${packageName} package metadata members must exactly match ${expectedMembers.join(', ')}`,
-    );
-  }
-}
-
-function compareText(left: string, right: string): number {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function parseExtensionContractStringList(value: unknown, field: string, label: string): string[] {
-  if (
-    !Array.isArray(value) ||
-    value.some((item) => typeof item !== 'string' || item.length === 0)
-  ) {
-    throw new Error(`${label}.${field} must be a string array`);
-  }
-  const rows = value as string[];
-  const canonical = [...new Set(rows)].sort(compareText);
-  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
-    throw new Error(`${label}.${field} must be sorted and unique`);
-  }
-  return rows;
-}
-
-function requirePortableExtensionContractPath(value: string, field: string, label: string): void {
-  const parts = value.split('/');
-  let decoded: string;
-  try {
-    decoded = decodeURIComponent(value);
-  } catch {
-    throw new Error(`${label}.${field} contains unsafe relative path ${value}`);
-  }
-  if (
-    value.includes('\\') ||
-    value !== value.normalize('NFC') ||
-    decoded !== value ||
-    value.startsWith('/') ||
-    /^[A-Za-z]:/u.test(value) ||
-    // biome-ignore lint/suspicious/noControlCharactersInRegex: Control characters make archive paths unsafe.
-    /[\u0000-\u001f\u007f]/u.test(value) ||
-    Buffer.byteLength(value, 'utf8') > 4096 ||
-    parts.some(
-      (part) =>
-        part === '' ||
-        part === '.' ||
-        part === '..' ||
-        Buffer.byteLength(part, 'utf8') > 255 ||
-        /[<>:"|?*]/u.test(part) ||
-        /[ .]$/u.test(part) ||
-        /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(part),
-    )
-  ) {
-    throw new Error(`${label}.${field} contains unsafe relative path ${value}`);
-  }
-}
-
-function requirePortableExtensionContractPaths(
-  values: readonly string[],
-  field: string,
-  label: string,
-): void {
-  const portable = new Map();
-  for (const value of values) {
-    requirePortableExtensionContractPath(value, field, label);
-    const key = value.toLowerCase();
-    const prior = portable.get(key);
-    if (prior !== undefined && prior !== value) {
-      throw new Error(`${label}.${field} contains case/NFC-colliding paths ${prior} and ${value}`);
-    }
-    portable.set(key, value);
-  }
-}
-
-function parseExtensionMemberContract(value: unknown, label: string): NpmExtensionMemberContract {
-  if (value === null || typeof value !== 'object' || Array.isArray(value)) {
-    throw new Error(`${label} must be a JSON object`);
-  }
-  const row = value as Record;
-  if (
-    JSON.stringify(Object.keys(row).sort(compareText)) !==
-    JSON.stringify(NPM_EXTENSION_CONTRACT_MEMBER_FIELDS)
-  ) {
-    throw new Error(
-      `${label} fields must be exactly ${NPM_EXTENSION_CONTRACT_MEMBER_FIELDS.join(', ')}`,
-    );
-  }
-  if (typeof row.sqlName !== 'string' || !/^[A-Za-z0-9._-]{1,128}$/u.test(row.sqlName)) {
-    throw new Error(`${label}.sqlName must be a portable identifier`);
-  }
-  if (typeof row.createsExtension !== 'boolean') {
-    throw new Error(`${label}.createsExtension must be a boolean`);
-  }
-  if (
-    row.nativeModuleStem !== null &&
-    (typeof row.nativeModuleStem !== 'string' ||
-      !/^[A-Za-z0-9._-]{1,128}$/u.test(row.nativeModuleStem))
-  ) {
-    throw new Error(`${label}.nativeModuleStem must be null or a portable identifier`);
-  }
-  const dependencies = parseExtensionContractStringList(row.dependencies, 'dependencies', label);
-  if (
-    dependencies.includes(row.sqlName) ||
-    dependencies.some((item) => !/^[A-Za-z0-9._-]{1,128}$/u.test(item))
-  ) {
-    throw new Error(`${label}.dependencies contains an invalid or self dependency`);
-  }
-  const dataFiles = parseExtensionContractStringList(row.dataFiles, 'dataFiles', label);
-  requirePortableExtensionContractPaths(dataFiles, 'dataFiles', label);
-  const extensionSqlFileNames = parseExtensionContractStringList(
-    row.extensionSqlFileNames,
-    'extensionSqlFileNames',
-    label,
-  );
-  if (
-    extensionSqlFileNames.some(
-      (file) => !/^[A-Za-z0-9._-]+\.sql$/u.test(file) || file.includes('/') || file.includes('\\'),
-    )
-  ) {
-    throw new Error(`${label}.extensionSqlFileNames must contain portable .sql basenames`);
-  }
-  const extensionSqlFilePrefixes = parseExtensionContractStringList(
-    row.extensionSqlFilePrefixes,
-    'extensionSqlFilePrefixes',
-    label,
-  );
-  if (extensionSqlFilePrefixes.some((prefix) => !/^[A-Za-z0-9_-]{1,128}$/u.test(prefix))) {
-    throw new Error(`${label}.extensionSqlFilePrefixes must contain portable dot-free prefixes`);
-  }
-  const licenseFiles = parseNpmExtensionLicenseFiles(row.licenseFiles, `${label}.licenseFiles`);
-  const sharedPreloadLibraries = parseExtensionContractStringList(
-    row.sharedPreloadLibraries,
-    'sharedPreloadLibraries',
-    label,
-  );
-  if (sharedPreloadLibraries.some((library) => !/^[A-Za-z0-9._-]{1,128}$/u.test(library))) {
-    throw new Error(`${label}.sharedPreloadLibraries contains an invalid identifier`);
-  }
-  return {
-    sqlName: row.sqlName,
-    createsExtension: row.createsExtension,
-    nativeModuleStem: row.nativeModuleStem as string | null,
-    dependencies,
-    dataFiles,
-    extensionSqlFileNames,
-    extensionSqlFilePrefixes,
-    licenseFiles,
-    sharedPreloadLibraries,
-  };
-}
-
-async function loadExtensionPackageContract(config: {
-  extension: GeneratedExtensionMetadata;
-  expectedMembers: readonly string[];
-  packageJson: ExtensionPackageMetadata;
-  packageRoot: string;
-  packageName: string;
-  target: string;
-}): Promise> {
-  const pointer = config.packageJson.oliphaunt?.extensionContract;
-  if (pointer !== 'extension-contract.json') {
-    throw new Error(
-      `${config.packageName} target must declare oliphaunt.extensionContract=extension-contract.json`,
-    );
-  }
-  const contractPath = resolvePackageRelativePath(
-    config.packageRoot,
-    pointer,
-    `${config.packageName} extension contract metadata`,
-  );
-  await requireFile(contractPath, `${config.packageName} extension contract`);
-  let parsed: unknown;
-  try {
-    parsed = JSON.parse(await readFile(contractPath, 'utf8')) as unknown;
-  } catch (error) {
-    throw new Error(`${config.packageName} extension contract is not valid JSON`, { cause: error });
-  }
-  if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
-    throw new Error(`${config.packageName} extension contract must be a JSON object`);
-  }
-  const manifest = parsed as NpmExtensionContractManifest;
-  const expectedFields = ['family', 'members', 'product', 'schema', 'target', 'version'];
-  if (JSON.stringify(Object.keys(manifest).sort(compareText)) !== JSON.stringify(expectedFields)) {
-    throw new Error(
-      `${config.packageName} extension contract fields must be exactly ${expectedFields.join(', ')}`,
-    );
-  }
-  if (manifest.schema !== NPM_EXTENSION_CONTRACT_SCHEMA) {
-    throw new Error(`${config.packageName} extension contract has unsupported schema`);
-  }
-  if (
-    manifest.product !== config.extension.artifactProduct ||
-    manifest.version !== config.packageJson.version ||
-    manifest.family !== 'native' ||
-    manifest.target !== config.target
-  ) {
-    throw new Error(
-      `${config.packageName} extension contract does not match its product, version, family, and target`,
-    );
-  }
-  if (!Array.isArray(manifest.members)) {
-    throw new Error(`${config.packageName} extension contract is missing members`);
-  }
-  const members = manifest.members.map((member, index) =>
-    parseExtensionMemberContract(
-      member,
-      `${config.packageName} extension contract members[${index}]`,
-    ),
-  );
-  if (
-    JSON.stringify(members.map(({ sqlName }) => sqlName)) !== JSON.stringify(config.expectedMembers)
-  ) {
-    throw new Error(
-      `${config.packageName} extension contract members must exactly match ${config.expectedMembers.join(', ')}`,
-    );
-  }
-  for (const member of members) {
-    const current = generatedExtensionBySqlName(member.sqlName);
-    if (
-      current === undefined ||
-      current.artifactProduct !== config.extension.artifactProduct ||
-      JSON.stringify(current.selectedExtensionDependencies) !== JSON.stringify(member.dependencies)
-    ) {
-      throw new Error(
-        `${config.packageName} extension contract member ${member.sqlName} is incompatible with the SDK dependency contract`,
-      );
-    }
-  }
-  return new Map(members.map((member) => [member.sqlName, member]));
-}
-
-async function resolveExtensionBundleMember(config: {
-  extension: GeneratedExtensionMetadata;
-  expectedMembers: readonly string[];
-  packageJson: ExtensionPackageMetadata;
-  packageRoot: string;
-  packageName: string;
-  target: string;
-  memberContracts: ReadonlyMap;
-}): Promise<{ runtimeDirectory: string; moduleDirectory?: string }> {
-  const pointer = config.packageJson.oliphaunt?.bundleManifest;
-  if (pointer !== 'bundle-manifest.json') {
-    throw new Error(
-      `${config.packageName} bundle target must declare oliphaunt.bundleManifest=bundle-manifest.json`,
-    );
-  }
-  const manifestPath = resolvePackageRelativePath(
-    config.packageRoot,
-    pointer,
-    `${config.packageName} bundle manifest metadata`,
-  );
-  await requireFile(manifestPath, `${config.packageName} bundle manifest`);
-  let parsedManifest: unknown;
-  try {
-    parsedManifest = JSON.parse(await readFile(manifestPath, 'utf8')) as unknown;
-  } catch (error) {
-    throw new Error(`${config.packageName} bundle manifest is not valid JSON`, {
-      cause: error,
-    });
-  }
-  if (
-    parsedManifest === null ||
-    typeof parsedManifest !== 'object' ||
-    Array.isArray(parsedManifest)
-  ) {
-    throw new Error(`${config.packageName} bundle manifest must be a JSON object`);
-  }
-  const manifest = parsedManifest as NpmExtensionBundleManifest;
-  if (manifest.schema === 'oliphaunt-extension-bundle-v1') {
-    throw new Error(
-      `${config.packageName} bundle manifest uses the physical carrier schema; expected oliphaunt-npm-extension-bundle-v1`,
-    );
-  }
-  if (manifest.schema !== 'oliphaunt-npm-extension-bundle-v1') {
-    throw new Error(`${config.packageName} bundle manifest has unsupported schema`);
-  }
-  const manifestFields = Object.keys(manifest).sort();
-  const expectedManifestFields = ['family', 'members', 'product', 'schema', 'target', 'version'];
-  if (JSON.stringify(manifestFields) !== JSON.stringify(expectedManifestFields)) {
-    throw new Error(
-      `${config.packageName} npm bundle manifest fields must be exactly ${expectedManifestFields.join(', ')}`,
-    );
-  }
-  if (manifest.product !== config.extension.artifactProduct) {
-    throw new Error(
-      `${config.packageName} bundle manifest does not declare ${config.extension.artifactProduct}`,
-    );
-  }
-  if (manifest.version !== config.packageJson.version) {
-    throw new Error(
-      `${config.packageName} bundle manifest version ${manifest.version ?? ''} does not match package version ${config.packageJson.version ?? ''}`,
-    );
-  }
-  if (manifest.family !== 'native' || manifest.target !== config.target) {
-    throw new Error(
-      `${config.packageName} bundle manifest must declare native target ${config.target}`,
-    );
-  }
-  if (!Array.isArray(manifest.members)) {
-    throw new Error(`${config.packageName} bundle manifest is missing members`);
-  }
-  const expectedRuntimeRelativePaths = Object.fromEntries(
-    config.expectedMembers.map((sqlName) => [sqlName, `extensions/${sqlName}/runtime`]),
-  );
-  const memberRuntimeRelativePaths = config.packageJson.oliphaunt?.memberRuntimeRelativePaths;
-  if (
-    memberRuntimeRelativePaths === undefined ||
-    memberRuntimeRelativePaths === null ||
-    typeof memberRuntimeRelativePaths !== 'object' ||
-    Array.isArray(memberRuntimeRelativePaths) ||
-    Object.values(memberRuntimeRelativePaths).some(
-      (value) => typeof value !== 'string' || value.length === 0,
-    ) ||
-    JSON.stringify(Object.keys(memberRuntimeRelativePaths).sort()) !==
-      JSON.stringify([...config.expectedMembers].sort()) ||
-    JSON.stringify(memberRuntimeRelativePaths) !== JSON.stringify(expectedRuntimeRelativePaths)
-  ) {
-    throw new Error(
-      `${config.packageName} bundle target must declare one runtime path for every exact member`,
-    );
-  }
-  const rawMemberModuleRelativePaths = config.packageJson.oliphaunt?.memberModuleRelativePaths;
-  const expectedMemberModuleRelativePaths = Object.fromEntries(
-    config.expectedMembers.flatMap((sqlName) =>
-      config.memberContracts.get(sqlName)?.nativeModuleStem === null
-        ? []
-        : [[sqlName, `extensions/${sqlName}/runtime/lib/modules`]],
-    ),
-  );
-  if (
-    rawMemberModuleRelativePaths === undefined
-      ? Object.keys(expectedMemberModuleRelativePaths).length !== 0
-      : rawMemberModuleRelativePaths === null ||
-        typeof rawMemberModuleRelativePaths !== 'object' ||
-        Array.isArray(rawMemberModuleRelativePaths) ||
-        Object.values(rawMemberModuleRelativePaths).some(
-          (value) => typeof value !== 'string' || value.length === 0,
-        ) ||
-        JSON.stringify(rawMemberModuleRelativePaths) !==
-          JSON.stringify(expectedMemberModuleRelativePaths)
-  ) {
-    throw new Error(`${config.packageName} bundle target has invalid member module paths`);
-  }
-  const memberModuleRelativePaths = rawMemberModuleRelativePaths ?? {};
-  const validatedMembers: NpmExtensionRuntimeBundleMember[] = [];
-  const canonicalMembers = new Set();
-  const memberPaths = new Set();
-  const memberArchivePaths = new Map();
-  for (const [index, rawMember] of manifest.members.entries()) {
-    if (rawMember === null || typeof rawMember !== 'object' || Array.isArray(rawMember)) {
-      throw new Error(`${config.packageName} bundle manifest members[${index}] must be an object`);
-    }
-    const member = rawMember as Record;
-    if (typeof member.sqlName !== 'string' || !/^[A-Za-z0-9._-]{1,128}$/.test(member.sqlName)) {
-      throw new Error(
-        `${config.packageName} bundle manifest members[${index}] has invalid sqlName`,
-      );
-    }
-    if (member.kind !== 'runtime') {
-      throw new Error(
-        `${config.packageName} bundle manifest member ${member.sqlName} must declare kind=runtime`,
-      );
-    }
-    if (!Object.prototype.hasOwnProperty.call(member, 'identity') || member.identity !== null) {
-      throw new Error(
-        `${config.packageName} bundle manifest runtime member ${member.sqlName} must declare identity=null`,
-      );
-    }
-    if (
-      typeof member.path !== 'string' ||
-      !new RegExp(
-        `^extensions/${member.sqlName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/[A-Za-z0-9][A-Za-z0-9._-]*\\.(?:tar\\.gz|tgz)$`,
-      ).test(member.path) ||
-      member.path !== member.path.normalize('NFC') ||
-      decodeURIComponent(member.path) !== member.path
-    ) {
-      throw new Error(
-        `${config.packageName} bundle manifest member ${member.sqlName} has invalid archive path`,
-      );
-    }
-    const archive = resolvePackageRelativePath(
-      config.packageRoot,
-      member.path,
-      `${config.packageName} bundle member ${member.sqlName}`,
-    );
-    await requireFile(archive, `${config.packageName} bundle member ${member.sqlName}`);
-    if (typeof member.sha256 !== 'string' || !/^[0-9a-f]{64}$/.test(member.sha256)) {
-      throw new Error(
-        `${config.packageName} bundle manifest member ${member.sqlName} has invalid sha256`,
-      );
-    }
-    if (
-      typeof member.bytes !== 'number' ||
-      !Number.isSafeInteger(member.bytes) ||
-      member.bytes <= 0
-    ) {
-      throw new Error(
-        `${config.packageName} bundle manifest member ${member.sqlName} has invalid bytes`,
-      );
-    }
-    const archiveIdentity = await fileSha256AndBytes(archive);
-    if (archiveIdentity.bytes !== member.bytes || archiveIdentity.sha256 !== member.sha256) {
-      throw new Error(
-        `${config.packageName} bundle member ${member.sqlName} does not match its exact bytes and sha256`,
-      );
-    }
-    if (
-      typeof member.runtimeRelativePath !== 'string' ||
-      member.runtimeRelativePath.length === 0 ||
-      member.runtimeRelativePath !== memberRuntimeRelativePaths[member.sqlName] ||
-      member.runtimeRelativePath !== `extensions/${member.sqlName}/runtime`
-    ) {
-      throw new Error(
-        `${config.packageName} bundle manifest member ${member.sqlName} runtime path disagrees with package metadata`,
-      );
-    }
-    const runtimeDirectory = resolvePackageRelativePath(
-      config.packageRoot,
-      member.runtimeRelativePath,
-      `${config.packageName} bundle member ${member.sqlName} runtime directory metadata`,
-    );
-    await requireDirectory(
-      runtimeDirectory,
-      `${config.packageName} bundle member ${member.sqlName} runtime directory`,
-    );
-    const memberContract = config.memberContracts.get(member.sqlName);
-    if (memberContract === undefined) {
-      throw new Error(
-        `${config.packageName} bundle member ${member.sqlName} has no frozen package contract`,
-      );
-    }
-    await requireExactExtensionRuntimeInventory({
-      contract: memberContract,
-      runtimeDirectory,
-      target: config.target,
-      source: `${config.packageName} bundle member ${member.sqlName} runtime directory`,
-    });
-    if (
-      member.moduleRelativePath !== undefined &&
-      (typeof member.moduleRelativePath !== 'string' || member.moduleRelativePath.length === 0)
-    ) {
-      throw new Error(
-        `${config.packageName} bundle manifest member ${member.sqlName} has invalid moduleRelativePath`,
-      );
-    }
-    if (member.moduleRelativePath !== memberModuleRelativePaths[member.sqlName]) {
-      throw new Error(
-        `${config.packageName} bundle manifest member ${member.sqlName} module path disagrees with package metadata`,
-      );
-    }
-    const expectedModuleRelativePath =
-      memberContract.nativeModuleStem === null
-        ? undefined
-        : `extensions/${member.sqlName}/runtime/lib/modules`;
-    if (member.moduleRelativePath !== expectedModuleRelativePath) {
-      throw new Error(
-        `${config.packageName} bundle manifest member ${member.sqlName} module path is not canonical`,
-      );
-    }
-    if (member.moduleRelativePath !== undefined) {
-      const moduleDirectory = resolvePackageRelativePath(
-        config.packageRoot,
-        member.moduleRelativePath,
-        `${config.packageName} bundle member ${member.sqlName} module directory metadata`,
-      );
-      await requireDirectory(
-        moduleDirectory,
-        `${config.packageName} bundle member ${member.sqlName} module directory`,
-      );
-    }
-    const expectedMemberFields = [
-      'bytes',
-      'identity',
-      'kind',
-      ...(member.moduleRelativePath === undefined ? [] : ['moduleRelativePath']),
-      'path',
-      'runtimeRelativePath',
-      'sha256',
-      'sqlName',
-    ].sort();
-    if (JSON.stringify(Object.keys(member).sort()) !== JSON.stringify(expectedMemberFields)) {
-      throw new Error(
-        `${config.packageName} bundle manifest member ${member.sqlName} has unexpected or missing fields`,
-      );
-    }
-    const canonicalMember = `${member.sqlName}\u0000${member.kind}\u0000${member.path}`;
-    if (canonicalMembers.has(canonicalMember) || memberPaths.has(member.path)) {
-      throw new Error(
-        `${config.packageName} bundle manifest repeats a canonical member or archive path`,
-      );
-    }
-    canonicalMembers.add(canonicalMember);
-    memberPaths.add(member.path);
-    memberArchivePaths.set(member.sqlName, archive);
-    validatedMembers.push({
-      sqlName: member.sqlName,
-      kind: 'runtime',
-      identity: null,
-      path: member.path,
-      sha256: member.sha256,
-      bytes: member.bytes,
-      runtimeRelativePath: member.runtimeRelativePath,
-      ...(member.moduleRelativePath === undefined
-        ? {}
-        : { moduleRelativePath: member.moduleRelativePath }),
-    });
-  }
-  const sqlNames = validatedMembers.map((member) => member.sqlName);
-  if (JSON.stringify(sqlNames) !== JSON.stringify(config.expectedMembers)) {
-    throw new Error(
-      `${config.packageName} bundle manifest members must exactly match ${config.expectedMembers.join(', ')}`,
-    );
-  }
-  const member = validatedMembers.find(
-    (candidate) => candidate.sqlName === config.extension.sqlName,
-  );
-  if (member === undefined) {
-    throw new Error(
-      `${config.packageName} bundle manifest is missing selected member ${config.extension.sqlName}`,
-    );
-  }
-  const archive = memberArchivePaths.get(config.extension.sqlName);
-  if (archive === undefined) {
-    throw new Error(
-      `${config.packageName} bundle manifest did not resolve selected member ${config.extension.sqlName}`,
-    );
-  }
-
-  const runtimeRelativePath = member.runtimeRelativePath;
-  const runtimeDirectory = resolvePackageRelativePath(
-    config.packageRoot,
-    runtimeRelativePath,
-    `${config.packageName} bundle member ${config.extension.sqlName} runtime directory metadata`,
-  );
-  const moduleRelativePath = member.moduleRelativePath;
-  const moduleDirectory =
-    moduleRelativePath === undefined
-      ? undefined
-      : resolvePackageRelativePath(
-          config.packageRoot,
-          moduleRelativePath,
-          `${config.packageName} bundle member ${config.extension.sqlName} module directory metadata`,
-        );
-  return { runtimeDirectory, moduleDirectory };
-}
-
-function extensionRuntimeSqlFileOwned(
-  extension: NpmExtensionMemberContract,
-  fileName: string,
-): boolean {
-  return (
-    (extension.createsExtension && fileName === `${extension.sqlName}.control`) ||
-    (extension.createsExtension && fileName === `${extension.sqlName}.sql`) ||
-    (extension.createsExtension &&
-      fileName.startsWith(`${extension.sqlName}--`) &&
-      fileName.endsWith('.sql')) ||
-    extension.extensionSqlFileNames.includes(fileName) ||
-    (fileName.endsWith('.sql') &&
-      extension.extensionSqlFilePrefixes.some((prefix) => fileName.startsWith(prefix)))
-  );
-}
-
-function isCanonicalExtensionInstallSql(fileName: string, sqlName: string): boolean {
-  if (fileName === `${sqlName}.sql`) return true;
-  const prefix = `${sqlName}--`;
-  if (!fileName.startsWith(prefix) || !fileName.endsWith('.sql')) return false;
-  const version = fileName.slice(prefix.length, -'.sql'.length);
-  return /^[0-9][A-Za-z0-9._-]*$/u.test(version) && !version.includes('--');
-}
-
-async function exactRuntimeLeafPaths(root: string, source: string): Promise {
-  const rows: string[] = [];
-  const collisionPaths = new Map();
-  let totalBytes = 0;
-  const visit = async (current: string, relativePath: string): Promise => {
-    if (relativePath !== '') {
-      if (
-        relativePath.includes('\\') ||
-        relativePath !== relativePath.normalize('NFC') ||
-        // biome-ignore lint/suspicious/noControlCharactersInRegex: Control characters make archive paths unsafe.
-        /[\u0000-\u001f\u007f]/u.test(relativePath)
-      ) {
-        throw new Error(`${source} contains a noncanonical runtime path ${relativePath}`);
-      }
-      const collisionKey = relativePath.toLowerCase();
-      const collision = collisionPaths.get(collisionKey);
-      if (collision !== undefined && collision !== relativePath) {
-        throw new Error(
-          `${source} contains case/NFC-colliding paths ${collision} and ${relativePath}`,
-        );
-      }
-      collisionPaths.set(collisionKey, relativePath);
-    }
-    const metadata = await lstat(current);
-    if (metadata.isSymbolicLink()) {
-      throw new Error(`${source} contains symbolic link ${relativePath || '.'}`);
-    }
-    if (metadata.isDirectory()) {
-      const entries = (await readdir(current)).sort();
-      for (const entry of entries) {
-        await visit(join(current, entry), relativePath === '' ? entry : `${relativePath}/${entry}`);
-      }
-      return;
-    }
-    if (!metadata.isFile()) {
-      throw new Error(`${source} contains unsupported filesystem entry ${relativePath}`);
-    }
-    if (metadata.size > MAX_EXTENSION_RUNTIME_FILE_BYTES) {
-      throw new Error(`${source} runtime file ${relativePath} exceeds the bounded member size`);
-    }
-    totalBytes += metadata.size;
-    if (totalBytes > MAX_EXTENSION_RUNTIME_BYTES) {
-      throw new Error(`${source} exceeds the bounded expanded runtime size`);
-    }
-    rows.push(relativePath);
-    if (rows.length > MAX_EXTENSION_RUNTIME_FILES) {
-      throw new Error(`${source} contains too many runtime files`);
-    }
-  };
-  await visit(root, '');
-  return rows;
-}
-
-async function requireExactExtensionRuntimeInventory(config: {
-  contract: NpmExtensionMemberContract;
-  runtimeDirectory: string;
-  target: string;
-  source: string;
-}): Promise {
-  const files = await exactRuntimeLeafPaths(config.runtimeDirectory, config.source);
-  const dataFiles = new Set(config.contract.dataFiles.map((file) => `share/postgresql/${file}`));
-  const licenseFiles = new Map(config.contract.licenseFiles.map((file) => [file.path, file]));
-  const moduleFile =
-    config.contract.nativeModuleStem === null
-      ? undefined
-      : `lib/postgresql/${config.contract.nativeModuleStem}${nativeModuleSuffixForTarget(config.target)}`;
-  const embeddedModuleFile =
-    config.contract.nativeModuleStem === null
-      ? undefined
-      : `lib/modules/${config.contract.nativeModuleStem}${nativeModuleSuffixForTarget(config.target)}`;
-  let hasControl = false;
-  let hasSql = false;
-  for (const file of files) {
-    const extensionPrefix = 'share/postgresql/extension/';
-    if (file.startsWith(extensionPrefix)) {
-      const fileName = file.slice(extensionPrefix.length);
-      if (fileName.includes('/') || !extensionRuntimeSqlFileOwned(config.contract, fileName)) {
-        throw new Error(`${config.source} contains undeclared extension SQL/control file ${file}`);
-      }
-      if (fileName === `${config.contract.sqlName}.control`) hasControl = true;
-      if (isCanonicalExtensionInstallSql(fileName, config.contract.sqlName)) hasSql = true;
-      continue;
-    }
-    if (
-      dataFiles.has(file) ||
-      licenseFiles.has(file) ||
-      file === moduleFile ||
-      file === embeddedModuleFile
-    ) {
-      continue;
-    }
-    throw new Error(`${config.source} contains undeclared runtime file ${file}`);
-  }
-  const missingDataFiles = [...dataFiles].filter((file) => !files.includes(file));
-  if (missingDataFiles.length > 0) {
-    throw new Error(
-      `${config.source} is missing declared data file(s): ${missingDataFiles.join(', ')}`,
-    );
-  }
-  const missingLicenseFiles = [...licenseFiles.keys()].filter((file) => !files.includes(file));
-  if (missingLicenseFiles.length > 0) {
-    throw new Error(
-      `${config.source} is missing declared license file(s): ${missingLicenseFiles.join(', ')}`,
-    );
-  }
-  for (const licenseFile of licenseFiles.values()) {
-    const licensePath = resolvePackageRelativePath(
-      config.runtimeDirectory,
-      licenseFile.path,
-      `${config.source} declared license file`,
-    );
-    const metadata = await lstat(licensePath);
-    const observedMode = metadata.mode & 0o7777;
-    const declaredMode = Number.parseInt(licenseFile.mode, 8);
-    if (
-      (platform() === 'win32' && (observedMode & 0o111) !== 0) ||
-      (platform() !== 'win32' &&
-        ((observedMode & ~declaredMode) !== 0 || (observedMode & 0o400) === 0))
-    ) {
-      throw new Error(
-        `${config.source} license file ${licenseFile.path} mode is not a safe installed representation of declared ${licenseFile.mode}`,
-      );
-    }
-    const identity = await fileSha256AndBytes(licensePath);
-    if (identity.sha256 !== licenseFile.sha256) {
-      throw new Error(
-        `${config.source} license file ${licenseFile.path} does not match declared SHA-256 ${licenseFile.sha256}`,
-      );
-    }
-  }
-  if (moduleFile !== undefined && !files.includes(moduleFile)) {
-    throw new Error(`${config.source} is missing declared native module ${moduleFile}`);
-  }
-  if (embeddedModuleFile !== undefined && !files.includes(embeddedModuleFile)) {
-    throw new Error(
-      `${config.source} is missing declared embedded native module ${embeddedModuleFile}`,
-    );
-  }
-  if (config.contract.createsExtension && (!hasControl || !hasSql)) {
-    throw new Error(
-      `${config.source} must contain ${config.contract.sqlName}.control and canonical base installation SQL`,
-    );
-  }
-}
-
-async function resolvePackageNativeInstall(
-  target: NativePackageTarget,
-  expectedVersion: string,
-  icu: ResolvedNodeIcuResources | undefined,
-): Promise {
-  const packageJsonPath = resolvePackageJson(target.packageName);
-  const packageRoot = dirname(packageJsonPath);
-  const packageJson = JSON.parse(
-    await readFile(packageJsonPath, 'utf8'),
-  ) as LiboliphauntPackageMetadata;
-  if (packageJson.name !== target.packageName) {
-    throw new Error(
-      `${target.packageName} package metadata has name ${packageJson.name ?? ''}`,
-    );
-  }
-  if (packageJson.version !== expectedVersion) {
-    throw new Error(
-      `${target.packageName} version ${packageJson.version ?? ''} does not match @oliphaunt/ts liboliphauntVersion ${expectedVersion}`,
-    );
-  }
-  if (packageJson.oliphaunt?.target !== target.id) {
-    throw new Error(`${target.packageName} package metadata does not target ${target.id}`);
-  }
-  const clusterSeedTarget = requireNativeClusterSeedTarget(
-    packageJson.oliphaunt.clusterSeedTarget,
-    target.id,
-    `${target.packageName} package metadata`,
-  );
-  const standardClusterSeedRelativePath = requireNativeClusterSeedPath(
-    packageJson.oliphaunt.clusterSeedRelativePath,
-    'cluster-seed',
-    `${target.packageName} clusterSeedRelativePath`,
-  );
-  const icuClusterSeedRelativePath = requireNativeClusterSeedPath(
-    packageJson.oliphaunt.icuClusterSeedRelativePath,
-    'cluster-seed-icu',
-    `${target.packageName} icuClusterSeedRelativePath`,
-  );
-  const carrierManifestPath = join(packageRoot, 'manifest.properties');
-  await requireFile(carrierManifestPath, `${target.packageName} runtime carrier receipt`);
-  validateNativeRuntimeCarrierReceipt(
-    await readFile(carrierManifestPath, 'utf8'),
-    clusterSeedTarget,
-    `${target.packageName} runtime carrier receipt`,
-  );
-  const libraryPath = resolvePackageRelativePath(
-    packageRoot,
-    packageJson.oliphaunt?.libraryRelativePath ?? target.libraryRelativePath,
-    `${target.packageName} liboliphaunt library metadata`,
-  );
-  await requireFile(libraryPath, `${target.packageName} liboliphaunt library`);
-  const runtimeDirectory = resolvePackageRelativePath(
-    packageRoot,
-    packageJson.oliphaunt?.runtimeRelativePath ?? target.runtimeRelativePath,
-    `${target.packageName} runtime directory metadata`,
-  );
-  await requireDirectory(runtimeDirectory, `${target.packageName} runtime directory`);
-  for (const tool of nativeRuntimeToolsForTarget(target.id)) {
-    await requireFile(
-      join(runtimeDirectory, 'bin', tool),
-      `${target.packageName} runtime tool bin/${tool}`,
-    );
-  }
-  const standardClusterSeedDirectory = resolvePackageRelativePath(
-    packageRoot,
-    standardClusterSeedRelativePath,
-    `${target.packageName} standard cluster seed metadata`,
-  );
-  await requireClusterSeedDirectory(
-    standardClusterSeedDirectory,
-    'standard',
-    clusterSeedTarget,
-    `${target.packageName} standard cluster seed`,
-  );
-  const selectedClusterSeedDirectory =
-    icu === undefined
-      ? standardClusterSeedDirectory
-      : resolvePackageRelativePath(
-          packageRoot,
-          icuClusterSeedRelativePath,
-          `${target.packageName} ICU cluster seed metadata`,
-        );
-  let icuDataTreeSha256: string | undefined;
-  if (icu !== undefined) {
-    icuDataTreeSha256 = await requireClusterSeedDirectory(
-      selectedClusterSeedDirectory,
-      'icu',
-      clusterSeedTarget,
-      `${target.packageName} ICU cluster seed`,
-    );
-    if (icuDataTreeSha256 !== icu.dataTreeSha256) {
-      throw new Error(
-        `${target.packageName} ICU cluster seed and the selected ICU data package identify different logical trees`,
-      );
-    }
-  }
-  return {
-    libraryPath,
-    runtimeDirectory,
-    icuDataDirectory: icu?.dataDirectory,
-    clusterSeedDirectory: selectedClusterSeedDirectory,
-    catalogProfile: icu === undefined ? 'standard' : 'icu',
-    packageManaged: true,
-  };
-}
-
-async function publishRuntimeCache(
-  root: string,
-  manifest: string,
-  build: (stageRoot: string) => Promise,
-): Promise {
-  const marker = join(root, 'manifest.json');
-  if ((await optionalRead(marker)) === manifest) {
-    return;
-  }
-  await mkdir(dirname(root), { recursive: true });
-  await withRuntimeCacheLock(root, async () => {
-    if ((await optionalRead(marker)) === manifest) {
-      return;
-    }
-    const unique = `${process.pid}-${randomUUID()}`;
-    const stageRoot = `${root}.build-${unique}`;
-    const oldRoot = `${root}.old-${unique}`;
-    await rm(stageRoot, { force: true, recursive: true });
-    await rm(oldRoot, { force: true, recursive: true });
-    let movedExistingRoot = false;
-    let publishedRoot = false;
-    try {
-      await mkdir(stageRoot, { recursive: true });
-      await build(stageRoot);
-      await writeFile(join(stageRoot, 'manifest.json'), manifest, 'utf8');
-      await syncRuntimeDirectoryTree(stageRoot);
-      try {
-        await rename(root, oldRoot);
-        movedExistingRoot = true;
-      } catch (error) {
-        if (!isErrorCode(error, 'ENOENT')) {
-          throw error;
-        }
-      }
-      try {
-        await rename(stageRoot, root);
-        publishedRoot = true;
-      } catch (error) {
-        if (movedExistingRoot) {
-          await rename(oldRoot, root).catch(() => undefined);
-          movedExistingRoot = false;
-        }
-        throw error;
-      }
-      await syncDirectory(dirname(root));
-      if (movedExistingRoot) {
-        await rm(oldRoot, { force: true, recursive: true }).catch(() => undefined);
-      }
-    } catch (error) {
-      await rm(stageRoot, { force: true, recursive: true });
-      if (!publishedRoot) {
-        await rm(oldRoot, { force: true, recursive: true });
-      }
-      throw error;
-    }
-  });
-}
-
-async function withRuntimeCacheLock(root: string, callback: () => Promise): Promise {
-  const lock = `${root}.lock`;
-  const deadline = Date.now() + CACHE_LOCK_TIMEOUT_MS;
-  while (true) {
-    try {
-      await mkdir(lock);
-      break;
-    } catch (error) {
-      if (!isErrorCode(error, 'EEXIST')) {
-        throw error;
-      }
-      if (await runtimeCacheLockIsStale(lock)) {
-        await rm(lock, { force: true, recursive: true });
-        continue;
-      }
-      if (Date.now() >= deadline) {
-        throw new Error(`timed out waiting for Oliphaunt runtime cache lock: ${lock}`);
-      }
-      await delay(CACHE_LOCK_POLL_MS);
-    }
-  }
-
-  try {
-    return await callback();
-  } finally {
-    await rm(lock, { force: true, recursive: true });
-  }
-}
-
-async function runtimeCacheLockIsStale(lock: string): Promise {
-  try {
-    const metadata = await stat(lock);
-    return Date.now() - metadata.mtimeMs > CACHE_LOCK_STALE_MS;
-  } catch {
-    return true;
-  }
-}
-
-function resolvePackageJson(packageName: string): string {
-  try {
-    return require.resolve(`${packageName}/package.json`);
-  } catch (error) {
-    throw new Error(
-      `${packageName} is not installed; reinstall @oliphaunt/ts with optional dependencies enabled`,
-      { cause: error },
-    );
-  }
-}
-
-async function resolveExtensionTargetPackageJson(
-  extension: GeneratedExtensionMetadata,
-  targetPackageName: string,
-  target: string,
-): Promise<{ packageJsonPath: string; ownerVersion: string }> {
-  const packageName = extension.npmPackage;
-  const expectedMembers = extensionOwnerMembers(extension);
-  const isBundle = expectedMembers.length > 1;
-  const packageJsonPath = optionalResolvePackageJson(packageName);
-  if (packageJsonPath === undefined) {
-    if (isBundle) {
-      throw new Error(
-        `${packageName} is not installed; add it to the application dependencies for CREATE EXTENSION support`,
-      );
-    }
-    const targetPath = resolveExtensionPackageJson(targetPackageName, packageName);
-    const targetMetadata = JSON.parse(
-      await readFile(targetPath, 'utf8'),
-    ) as ExtensionPackageMetadata;
-    if (typeof targetMetadata.version !== 'string' || targetMetadata.version.length === 0) {
-      throw new Error(`${targetPackageName} package metadata is missing version`);
-    }
-    return {
-      packageJsonPath: targetPath,
-      ownerVersion: targetMetadata.version,
-    };
-  }
-
-  const packageJson = JSON.parse(
-    await readFile(packageJsonPath, 'utf8'),
-  ) as ExtensionPackageMetadata;
-  if (packageJson.name !== packageName) {
-    throw new Error(`${packageName} package metadata has name ${packageJson.name ?? ''}`);
-  }
-  const expectedKind = isBundle ? 'exact-extension-bundle' : 'exact-extension';
-  if (packageJson.oliphaunt?.kind !== expectedKind) {
-    throw new Error(`${packageName} package metadata does not declare ${expectedKind}`);
-  }
-  if (packageJson.oliphaunt?.product !== extension.artifactProduct) {
-    throw new Error(
-      `${packageName} package metadata does not declare ${extension.artifactProduct}`,
-    );
-  }
-  requireExtensionPackageMembers(packageJson, expectedMembers, packageName);
-  if (typeof packageJson.version !== 'string' || packageJson.version.length === 0) {
-    throw new Error(`${packageName} package metadata is missing version`);
-  }
-  const resolvedTargetPackageName =
-    packageJson.oliphaunt.targetPackageNames?.[target] ?? targetPackageName;
-  if (resolvedTargetPackageName !== targetPackageName) {
-    throw new Error(
-      `${packageName} target package for ${target} must be ${targetPackageName}, got ${resolvedTargetPackageName}`,
-    );
-  }
-  try {
-    return {
-      packageJsonPath: createRequire(packageJsonPath).resolve(
-        `${resolvedTargetPackageName}/package.json`,
-      ),
-      ownerVersion: packageJson.version,
-    };
-  } catch (error) {
-    throw new Error(
-      `${resolvedTargetPackageName} is not installed; reinstall ${packageName} with optional dependencies enabled`,
-      { cause: error },
-    );
-  }
-}
-
-function resolveExtensionPackageJson(packageName: string, installPackageName: string): string {
-  try {
-    return require.resolve(`${packageName}/package.json`);
-  } catch (error) {
-    throw new Error(
-      `${installPackageName} is not installed; add it to the application dependencies for CREATE EXTENSION support`,
-      { cause: error },
-    );
-  }
-}
-
-function optionalResolvePackageJson(packageName: string): string | undefined {
-  try {
-    return require.resolve(`${packageName}/package.json`);
-  } catch {
-    return undefined;
-  }
-}
-
-export function resolvePackageRelativePath(
-  packageRoot: string,
-  metadataPath: string,
-  source: string,
-): string {
-  const relativePath = safePackageRelativePath(metadataPath, source);
-  const root = resolve(packageRoot);
-  const resolved = resolve(root, relativePath);
-  const fromRoot = relative(root, resolved);
-  if (fromRoot.startsWith('..') || isAbsolute(fromRoot)) {
-    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
-  }
-  return resolved;
-}
-
-function safePackageRelativePath(metadataPath: string, source: string): string {
-  if (metadataPath.length === 0) {
-    throw new Error(`${source} contains unsafe package metadata path: `);
-  }
-  if (metadataPath.includes('\0')) {
-    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
-  }
-  let decoded: string;
-  try {
-    decoded = decodeURIComponent(metadataPath);
-  } catch {
-    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
-  }
-  const normalized = decoded.replaceAll('\\', '/');
-  if (
-    normalized.startsWith('/') ||
-    /^[A-Za-z][A-Za-z0-9+.-]*:/.test(normalized) ||
-    normalized.split('/').includes('..')
-  ) {
-    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
-  }
-  return normalized;
-}
-
-async function requireFile(path: string, source: string): Promise {
-  try {
-    const metadata = await lstat(path);
-    if (metadata.isFile() && !metadata.isSymbolicLink()) {
-      return;
-    }
-  } catch {}
-  throw new Error(`${source} does not point to an existing file: ${path}`);
-}
-
-async function fileSha256AndBytes(path: string): Promise<{ sha256: string; bytes: number }> {
-  const digest = createHash('sha256');
-  let bytes = 0;
-  for await (const chunk of createReadStream(path)) {
-    const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
-    bytes += buffer.byteLength;
-    digest.update(buffer);
-  }
-  return { sha256: digest.digest('hex'), bytes };
-}
-
-async function requireDirectory(path: string, source: string): Promise {
-  try {
-    const metadata = await lstat(path);
-    if (metadata.isDirectory() && !metadata.isSymbolicLink()) {
-      return;
-    }
-  } catch {}
-  throw new Error(`${source} does not point to an existing directory: ${path}`);
-}
-
-async function isDirectory(path: string): Promise {
-  try {
-    return (await stat(path)).isDirectory();
-  } catch {
-    return false;
-  }
-}
-
-async function requireIcuDataDirectory(path: string, source: string): Promise {
-  await requireDirectory(path, source);
-  for (const entry of await readdir(path, { withFileTypes: true })) {
-    if (entry.isFile() && entry.name.startsWith('icudt') && entry.name.endsWith('.dat')) {
-      return;
-    }
-    if (entry.isDirectory() && entry.name.startsWith('icudt')) {
-      return;
-    }
-  }
-  throw new Error(`${source} does not contain ICU icudt data files: ${path}`);
-}
-
-async function requireClusterSeedDirectory(
-  path: string,
-  profile: NativeCatalogProfile,
-  target: string,
-  source: string,
-): Promise {
-  await requireDirectory(path, source);
-  await requireFile(join(path, 'files', 'PG_VERSION'), `${source} PG_VERSION`);
-  await requireFile(join(path, 'files', 'global', 'pg_control'), `${source} pg_control`);
-  const manifest = await readFile(join(path, 'manifest.properties'), 'utf8').catch(() => '');
-  return validateNativeClusterSeedManifest(manifest, profile, target, source);
-}
-
-async function optionalRead(path: string): Promise {
-  try {
-    return await readFile(path, 'utf8');
-  } catch {
-    return undefined;
-  }
-}
-
-function isErrorCode(error: unknown, code: string): boolean {
-  return typeof error === 'object' && error !== null && 'code' in error && error.code === code;
-}
-
-function extensionTargetPackageName(extension: GeneratedExtensionMetadata, target: string): string {
-  return `${extension.npmPackage}-${target}`;
-}
-
-function nativeModuleDirectoryCandidates(libraryPath: string): string[] {
-  const libraryDir = dirname(libraryPath);
-  return [join(libraryDir, 'modules'), join(dirname(libraryDir), 'lib', 'modules')];
-}
-
-function nativeRuntimeToolsForTarget(target: string): string[] {
-  return target === 'windows-x64-msvc'
-    ? ['initdb.exe', 'pg_ctl.exe', 'postgres.exe']
-    : ['initdb', 'pg_ctl', 'postgres'];
-}
-
-function runtimeCacheKey(value: unknown): string {
-  return createHash('sha256').update(JSON.stringify(value)).digest('hex').slice(0, 32);
-}
-
-const nodeRuntimeFileHost: RuntimeFileHost = {
-  join,
-  async readDir(path: string) {
-    return (await readdir(path, { withFileTypes: true })).map((entry) => ({
-      name: entry.name,
-      isFile: entry.isFile(),
-    }));
-  },
-  async isDirectory(path: string) {
-    return isDirectory(path);
-  },
-  async isFile(path: string) {
-    try {
-      return (await stat(path)).isFile();
-    } catch {
-      return false;
-    }
-  },
-};
diff --git a/src/sdks/js/src/native/cluster-seed.ts b/src/sdks/js/src/native/cluster-seed.ts
deleted file mode 100644
index 9058707e7..000000000
--- a/src/sdks/js/src/native/cluster-seed.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-export type NativeCatalogProfile = 'standard' | 'icu';
-
-const SHA256 = /^[0-9a-f]{64}$/u;
-const PORTABLE_ID = /^[A-Za-z0-9._-]{1,128}$/u;
-const DISALLOWED_CACHE_KEYS = new Set(['.', '..']);
-
-function isPortableCacheKey(value: string): boolean {
-  return PORTABLE_ID.test(value) && !DISALLOWED_CACHE_KEYS.has(value);
-}
-const CLUSTER_SEED_FIELDS = [
-  'schema',
-  'layout',
-  'artifactRole',
-  'catalogProfile',
-  'target',
-  'postgresMajor',
-  'physicalFormat',
-  'compatibilityKey',
-  'initialSuperuser',
-  'icuDataVersion',
-  'icuDataForm',
-  'icuDataTreeSha256',
-  'runtimeFeatures',
-  'cacheKey',
-] as const;
-const ICU_DATA_FIELDS = [
-  'schema',
-  'artifactRole',
-  'icuDataVersion',
-  'icuDataForm',
-  'icuDataTreeSha256',
-] as const;
-const RUNTIME_CARRIER_FIELDS = [
-  'schema',
-  'clusterSeedTarget',
-  'clusterSeedRelativePath',
-  'icuClusterSeedRelativePath',
-] as const;
-
-function parseProperties(manifest: string, source: string): Map {
-  const fields = new Map();
-  for (const line of manifest.split(/\r?\n/u)) {
-    if (line.length === 0) continue;
-    const separator = line.indexOf('=');
-    if (separator <= 0) {
-      throw new Error(`${source} manifest contains a malformed property`);
-    }
-    const key = line.slice(0, separator);
-    if (fields.has(key)) {
-      throw new Error(`${source} manifest repeats property ${key}`);
-    }
-    fields.set(key, line.slice(separator + 1));
-  }
-  return fields;
-}
-
-function requireExactFields(
-  fields: ReadonlyMap,
-  expected: ReadonlyArray,
-  source: string,
-): void {
-  if (fields.size !== expected.length || expected.some((key) => !fields.has(key))) {
-    throw new Error(`${source} manifest fields must be exactly ${expected.join(',')}`);
-  }
-}
-
-export function requireNativeClusterSeedTarget(
-  value: string | undefined,
-  expected: string,
-  source: string,
-): string {
-  if (value !== expected) {
-    throw new Error(`${source} clusterSeedTarget must be ${expected}`);
-  }
-  return value;
-}
-
-export function requireNativeClusterSeedPath(
-  value: string | undefined,
-  expected: 'cluster-seed' | 'cluster-seed-icu',
-  source: string,
-): string {
-  if (value !== expected) {
-    throw new Error(`${source} must be ${expected}`);
-  }
-  return value;
-}
-
-export function requireIcuDataTreeSha256(value: string | undefined, source: string): string {
-  if (value === undefined || !SHA256.test(value)) {
-    throw new Error(`${source} does not declare canonical ICU data identity`);
-  }
-  return value;
-}
-
-export function requireIcuManifestRelativePath(
-  dataRelativePath: string | undefined,
-  manifestRelativePath: string | undefined,
-  source: string,
-): string {
-  const data = dataRelativePath ?? 'share/icu';
-  const suffix = 'share/icu';
-  if (data !== suffix && !data.endsWith(`/${suffix}`)) {
-    throw new Error(`${source} dataRelativePath must end in ${suffix}`);
-  }
-  const expected = `${data.slice(0, -suffix.length)}manifest.properties`;
-  if (manifestRelativePath !== expected) {
-    throw new Error(`${source} manifestRelativePath must be ${expected}`);
-  }
-  return manifestRelativePath;
-}
-
-export function validateNativeClusterSeedManifest(
-  manifest: string,
-  profile: NativeCatalogProfile,
-  target: string,
-  source: string,
-): string | undefined {
-  const fields = parseProperties(manifest, source);
-  requireExactFields(fields, CLUSTER_SEED_FIELDS, source);
-  const expectedFeatures = profile === 'icu' ? 'icu' : '';
-  if (
-    fields.get('schema') !== 'oliphaunt-runtime-resources-v1' ||
-    fields.get('layout') !== 'oliphaunt-cluster-seed-v1' ||
-    fields.get('artifactRole') !== `cluster-seed-${profile}` ||
-    fields.get('catalogProfile') !== profile ||
-    fields.get('target') !== target ||
-    fields.get('postgresMajor') !== '18' ||
-    fields.get('physicalFormat') !== 'native-pg18-v1' ||
-    fields.get('compatibilityKey') !== `native-pg18-${target}-v1` ||
-    fields.get('initialSuperuser') !== 'postgres' ||
-    fields.get('runtimeFeatures') !== expectedFeatures ||
-    !isPortableCacheKey(fields.get('cacheKey') ?? '')
-  ) {
-    throw new Error(`${source} manifest does not declare the ${profile} cluster seed contract`);
-  }
-  if (profile === 'icu') {
-    if (
-      fields.get('icuDataVersion') !== '76.1' ||
-      fields.get('icuDataForm') !== 'files-le' ||
-      !SHA256.test(fields.get('icuDataTreeSha256') ?? '')
-    ) {
-      throw new Error(`${source} manifest does not bind the canonical ICU data tree`);
-    }
-  } else if (
-    fields.get('icuDataVersion') !== '' ||
-    fields.get('icuDataForm') !== '' ||
-    fields.get('icuDataTreeSha256') !== ''
-  ) {
-    throw new Error(`${source} standard manifest must not select ICU data`);
-  }
-  return fields.get('icuDataTreeSha256') || undefined;
-}
-
-export function validateNativeIcuDataReceipt(manifest: string, source: string): string {
-  const fields = parseProperties(manifest, source);
-  requireExactFields(fields, ICU_DATA_FIELDS, source);
-  if (
-    fields.get('schema') !== 'oliphaunt-icu-data-v1' ||
-    fields.get('artifactRole') !== 'icu-data' ||
-    fields.get('icuDataVersion') !== '76.1' ||
-    fields.get('icuDataForm') !== 'files-le'
-  ) {
-    throw new Error(`${source} manifest does not declare canonical ICU data`);
-  }
-  return requireIcuDataTreeSha256(fields.get('icuDataTreeSha256'), source);
-}
-
-export function validateNativeRuntimeCarrierReceipt(
-  manifest: string,
-  target: string,
-  source: string,
-): void {
-  const fields = parseProperties(manifest, source);
-  requireExactFields(fields, RUNTIME_CARRIER_FIELDS, source);
-  if (
-    fields.get('schema') !== 'oliphaunt-native-runtime-carrier-v1' ||
-    fields.get('clusterSeedTarget') !== target ||
-    fields.get('clusterSeedRelativePath') !== 'cluster-seed' ||
-    fields.get('icuClusterSeedRelativePath') !== 'cluster-seed-icu'
-  ) {
-    throw new Error(`${source} manifest does not declare the ${target} runtime carrier`);
-  }
-}
diff --git a/src/sdks/js/src/native/default.ts b/src/sdks/js/src/native/default.ts
deleted file mode 100644
index f957562c3..000000000
--- a/src/sdks/js/src/native/default.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import type { NativeBinding, NativeBindingOptions } from './types.js';
-
-export async function createDefaultNativeBinding(
-  options: NativeBindingOptions = {},
-): Promise {
-  if (isDeno()) {
-    const { createDenoNativeBinding } = await import('./deno.js');
-    return createDenoNativeBinding(options);
-  }
-  if (isBun()) {
-    // Bun recommends Node-API for production native integrations. The addon
-    // also runs blocking database work off the JavaScript thread, which keeps
-    // cancel() and timers live while a query is executing.
-    const { createNodeNativeBinding } = await import('./node.js');
-    return createNodeNativeBinding(options);
-  }
-  const { createNodeNativeBinding } = await import('./node.js');
-  return createNodeNativeBinding(options);
-}
-
-function isDeno(): boolean {
-  return (
-    typeof (globalThis as { Deno?: { version?: { deno?: string } } }).Deno?.version?.deno ===
-    'string'
-  );
-}
-
-function isBun(): boolean {
-  return typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined';
-}
diff --git a/src/sdks/js/src/native/node.ts b/src/sdks/js/src/native/node.ts
deleted file mode 100644
index fefbfb578..000000000
--- a/src/sdks/js/src/native/node.ts
+++ /dev/null
@@ -1,189 +0,0 @@
-import {
-  applyNativeIcuDataEnvironment,
-  applyNativeRuntimeLibraryEnvironment,
-  replaceNativeIcuDataEnvironment,
-} from './common.js';
-import { loadNodeDirectAddon } from './node-addon.js';
-import { prepareNodeExtensionInstall, resolveNodeNativeInstall } from './assets-node.js';
-import {
-  copyNativeClusterSeed,
-  initializeNativePgdata,
-  nativeInitdbArgs,
-  nativePostgresChildEnvironment,
-} from './initialize.js';
-import { spawn } from 'node:child_process';
-import { dirname, join } from 'node:path';
-import { resolveExactNativeRuntimeProfile } from './runtime-profile.js';
-import type {
-  NativeBinding,
-  NativeBindingOptions,
-  NativeHandle,
-  NativeOpenConfig,
-  NativeRestoreOptions,
-} from './types.js';
-
-export async function createNodeNativeBinding(
-  options: NativeBindingOptions = {},
-): Promise {
-  const install = await resolveNodeNativeInstall(options.libraryPath);
-  applyNativeIcuDataEnvironment(install.icuDataDirectory);
-  applyNativeRuntimeLibraryEnvironment(install.runtimeDirectory);
-  const addon = await loadNodeDirectAddon(options.nodeAddonPath);
-  const forgottenHandles = new FinalizationRegistry<{
-    readonly recoveryToken: unknown;
-    readonly releaseOwnership: () => void;
-  }>(({ recoveryToken, releaseOwnership }) => {
-    try {
-      // The addon only marks this exact logical generation for recovery. The
-      // actual PostgreSQL detach remains on the next open's async worker.
-      if (addon.queueForgottenHandleRecovery(recoveryToken)) {
-        releaseOwnership();
-      }
-    } catch {
-      // Finalizer failures are unobservable. Keep the JavaScript admission
-      // lease closed if native recovery could not be queued safely.
-    }
-  });
-
-  return {
-    async open(config: NativeOpenConfig): Promise {
-      const explicitRuntimeDirectory =
-        config.runtimeDirectory !== undefined || install.packageManaged === false;
-      let extensionInstall = await prepareNodeExtensionInstall(
-        {
-          ...install,
-          runtimeDirectory: config.runtimeDirectory ?? install.runtimeDirectory,
-          clusterSeedDirectory:
-            config.runtimeDirectory === undefined ? install.clusterSeedDirectory : undefined,
-        },
-        config.extensions,
-        {
-          explicitRuntimeDirectory,
-        },
-      );
-      if (explicitRuntimeDirectory && extensionInstall.runtimeDirectory !== undefined) {
-        extensionInstall = {
-          ...extensionInstall,
-          ...(await resolveExactNativeRuntimeProfile(extensionInstall.runtimeDirectory)),
-          clusterSeedDirectory: undefined,
-        };
-        replaceNativeIcuDataEnvironment(extensionInstall.icuDataDirectory);
-      }
-      applyNativeRuntimeLibraryEnvironment(extensionInstall.runtimeDirectory);
-      await prepareNodePgdata(
-        config.pgdata,
-        config.username,
-        extensionInstall.runtimeDirectory,
-        extensionInstall.clusterSeedDirectory,
-        extensionInstall.icuDataDirectory,
-        extensionInstall.catalogProfile,
-      );
-      return await addon.open({
-        ...config,
-        libraryPath: extensionInstall.libraryPath,
-        runtimeDirectory: extensionInstall.runtimeDirectory,
-        moduleDirectory: extensionInstall.moduleDirectory,
-      });
-    },
-    async execProtocolRaw(handle: NativeHandle, request: Uint8Array): Promise {
-      return toUint8Array(await addon.execProtocolRaw(handle, request));
-    },
-    async execProtocolStream(
-      handle: NativeHandle,
-      request: Uint8Array,
-      onChunk: (chunk: Uint8Array) => void,
-    ): Promise {
-      await addon.execProtocolRawStream(handle, request, onChunk);
-    },
-    async execSimpleQuery(handle: NativeHandle, sql: string): Promise {
-      return toUint8Array(await addon.execSimpleQuery(handle, sql));
-    },
-    async backup(handle: NativeHandle): Promise {
-      return toUint8Array(await addon.backup(handle));
-    },
-    async restore(options: NativeRestoreOptions): Promise {
-      await addon.restore({
-        libraryPath: install.libraryPath,
-        destination: options.destination,
-        bytes: options.bytes,
-      });
-    },
-    async cancel(handle: NativeHandle): Promise {
-      addon.cancel(handle);
-    },
-    async detach(handle: NativeHandle): Promise {
-      await addon.detach(handle);
-    },
-    registerForgottenHandleCleanup(
-      owner: object,
-      handle: NativeHandle,
-      releaseOwnership: () => void,
-    ): void {
-      forgottenHandles.register(
-        owner,
-        Object.freeze({
-          recoveryToken: addon.createForgottenHandleRecoveryToken(handle),
-          releaseOwnership,
-        }),
-        owner,
-      );
-    },
-    unregisterForgottenHandleCleanup(owner: object): void {
-      forgottenHandles.unregister(owner);
-    },
-  };
-}
-
-async function prepareNodePgdata(
-  pgdata: string,
-  username: string,
-  runtimeDirectory?: string,
-  clusterSeedDirectory?: string,
-  icuDataDirectory?: string,
-  catalogProfile: 'standard' | 'icu' = 'standard',
-): Promise {
-  if (runtimeDirectory === undefined) {
-    throw new Error('initializing a native database requires runtimeDirectory with initdb');
-  }
-  const executable = join(
-    runtimeDirectory,
-    'bin',
-    process.platform === 'win32' ? 'initdb.exe' : 'initdb',
-  );
-  await initializeNativePgdata({
-    root: dirname(pgdata),
-    pgdata,
-    username,
-    populatePgdata: (staging) => {
-      if (clusterSeedDirectory !== undefined) {
-        return copyNativeClusterSeed(clusterSeedDirectory, staging);
-      }
-      return new Promise((resolve, reject) => {
-        const env = nativePostgresChildEnvironment(process.env, {
-          icuDataDirectory,
-          initdbCatalogProfile: catalogProfile,
-        });
-        const child = spawn(executable, nativeInitdbArgs(staging), {
-          env,
-          stdio: ['ignore', 'ignore', 'pipe'],
-        });
-        const errors: Buffer[] = [];
-        child.stderr.on('data', (chunk: Buffer) => errors.push(chunk));
-        child.once('error', reject);
-        child.once('exit', (code) =>
-          code === 0
-            ? resolve()
-            : reject(
-                new Error(
-                  `initdb failed with exit code ${code ?? 'unknown'}: ${Buffer.concat(errors).toString('utf8').trim()}`,
-                ),
-              ),
-        );
-      });
-    },
-  });
-}
-
-function toUint8Array(value: Uint8Array | ArrayBuffer): Uint8Array {
-  return value instanceof Uint8Array ? value : new Uint8Array(value);
-}
diff --git a/src/sdks/js/src/native/types.ts b/src/sdks/js/src/native/types.ts
deleted file mode 100644
index ff7ce0da7..000000000
--- a/src/sdks/js/src/native/types.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-export type NativeBindingOptions = {
-  libraryPath?: string;
-  nodeAddonPath?: string;
-};
-
-export type NativeOpenConfig = {
-  pgdata: string;
-  runtimeDirectory?: string;
-  username: string;
-  database: string;
-  extensions: string[];
-  startupArgs: string[];
-};
-
-export type NativeRestoreOptions = {
-  destination: string;
-  bytes: Uint8Array;
-};
-
-export type NativeHandle = unknown;
-
-/** @internal The adapter cannot prove whether a logical detach took effect. */
-export class NativeDetachOutcomeUnknownError extends Error {
-  constructor(message: string, options?: ErrorOptions) {
-    super(message, options);
-    this.name = 'NativeDetachOutcomeUnknownError';
-  }
-}
-
-export type NativeBinding = {
-  open(config: NativeOpenConfig): Promise;
-  execProtocolRaw(handle: NativeHandle, request: Uint8Array): Promise;
-  execProtocolStream(
-    handle: NativeHandle,
-    request: Uint8Array,
-    onChunk: (chunk: Uint8Array) => void,
-  ): Promise;
-  execSimpleQuery?(handle: NativeHandle, sql: string): Promise;
-  backup(handle: NativeHandle): Promise;
-  restore(options: NativeRestoreOptions): Promise;
-  cancel(handle: NativeHandle): Promise;
-  /**
-   * Deactivate the logical handle. An ordinary rejection guarantees that
-   * deactivation did not occur and the same handle remains valid for a later
-   * retry. NativeDetachOutcomeUnknownError is terminal. A handle that is
-   * already terminally unavailable is a successful detach.
-   */
-  detach(handle: NativeHandle): Promise;
-  /**
-   * Register a public owner for best-effort cleanup when that owner becomes
-   * unreachable. Native adapters omit this unless they can make stale cleanup
-   * ownership-safe and keep native teardown off the JavaScript thread.
-   */
-  registerForgottenHandleCleanup?(
-    owner: object,
-    handle: NativeHandle,
-    releaseOwnership: () => void,
-  ): void;
-  unregisterForgottenHandleCleanup?(owner: object): void;
-};
diff --git a/src/sdks/js/src/protocol.ts b/src/sdks/js/src/protocol.ts
deleted file mode 100644
index f23f4bdb1..000000000
--- a/src/sdks/js/src/protocol.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from '@oliphaunt/js-core/protocol';
diff --git a/src/sdks/js/src/query.ts b/src/sdks/js/src/query.ts
deleted file mode 100644
index a297830c0..000000000
--- a/src/sdks/js/src/query.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from '@oliphaunt/js-core/query';
diff --git a/src/sdks/js/src/runtime/broker.ts b/src/sdks/js/src/runtime/broker.ts
deleted file mode 100644
index bbe3f2cab..000000000
--- a/src/sdks/js/src/runtime/broker.ts
+++ /dev/null
@@ -1,952 +0,0 @@
-import { createRequire } from 'node:module';
-import { dirname, join, resolve } from 'node:path';
-import { fileURLToPath } from 'node:url';
-import { arch, platform } from 'node:os';
-import { readFile, stat } from 'node:fs/promises';
-
-import type { NormalizedOpenConfig } from '../config.js';
-import type { DenoRuntime } from '../native/assets-deno.js';
-import {
-  ICU_DATA_ENV,
-  envVar,
-  LIBOLIPHAUNT_RUNTIME_DIR_ENV,
-  nativeRuntimeLibraryEnvironment,
-  OLIPHAUNT_EMBEDDED_MODULE_DIR_ENV,
-  OLIPHAUNT_ICU_DATA_DIR_ENV,
-} from '../native/common.js';
-import {
-  readBrokerResponse,
-  writeBrokerRequest,
-  type BrokerResponseFrame,
-} from './broker-frames.js';
-import type { ByteStream } from './byte-stream.js';
-import {
-  connectEndpoint,
-  cleanupFailedManagedLaunch,
-  createTempDir,
-  parseReadyEndpoint,
-  randomHexToken,
-  readReadyLine,
-  removeTree,
-  spawnManagedChild,
-  unixSocketPathsFit,
-  waitForManagedChild,
-  type ManagedChild,
-  type FailedManagedLaunch,
-} from './node-adapter.js';
-import type { RuntimeBinding, RuntimeHandle } from './types.js';
-import { throwCollectedCloseFailures } from './close.js';
-import { createForgottenRuntimeHandleCleanup } from './forgotten-handle.js';
-import { resolveExactNativeRuntimeProfile } from '../native/runtime-profile.js';
-
-const READY_PREFIX = 'OLIPHAUNT_BROKER_READY ';
-const ERROR_PREFIX = 'OLIPHAUNT_BROKER_ERROR ';
-const LIBOLIPHAUNT_PATH_ENV = 'LIBOLIPHAUNT_PATH';
-const OLIPHAUNT_INSTALL_DIR_ENV = 'OLIPHAUNT_INSTALL_DIR';
-const OLIPHAUNT_BROKER_ENV = 'OLIPHAUNT_BROKER';
-const OLIPHAUNT_BROKER_STARTUP_TIMEOUT_MS_ENV = 'OLIPHAUNT_BROKER_STARTUP_TIMEOUT_MS';
-const DEFAULT_STARTUP_TIMEOUT_MS = 60_000;
-const SHUTDOWN_TIMEOUT_MS = 5_000;
-const require = createRequire(import.meta.url);
-
-export type BrokerRuntimeBindingOptions = {
-  executable?: string;
-};
-
-export function createBrokerRuntimeBinding(
-  options: BrokerRuntimeBindingOptions = {},
-): RuntimeBinding {
-  const forgottenHandles = createForgottenRuntimeHandleCleanup((handle) =>
-    handle.detach(),
-  );
-  return {
-    async open(config: NormalizedOpenConfig): Promise {
-      return openBrokerHandle(config.brokerExecutable ?? options.executable, config);
-    },
-    execProtocolRaw(handle: RuntimeHandle, request: Uint8Array): Promise {
-      return asBrokerHandle(handle).requestOk({
-        kind: 'execProtocol',
-        bytes: request,
-      });
-    },
-    execProtocolStream(
-      handle: RuntimeHandle,
-      request: Uint8Array,
-      onChunk: (chunk: Uint8Array) => void,
-    ): Promise {
-      return asBrokerHandle(handle).execProtocolStream(request, onChunk);
-    },
-    execSimpleQuery(handle: RuntimeHandle, sql: string): Promise {
-      return asBrokerHandle(handle).requestOk({ kind: 'execSimpleQuery', sql });
-    },
-    backup(handle: RuntimeHandle): Promise {
-      return asBrokerHandle(handle).requestOk({ kind: 'backup' });
-    },
-    cancel(handle: RuntimeHandle): Promise {
-      return asBrokerHandle(handle).cancel();
-    },
-    async close(handle: RuntimeHandle) {
-      try {
-        await asBrokerHandle(handle).detach();
-        return { state: 'closed' };
-      } catch (error) {
-        // BrokerHandle.detach() crosses its destructive cutoff before any
-        // fallible teardown. The public owner must be retired even when later
-        // process or filesystem cleanup reports an error.
-        return { state: 'terminal', error };
-      }
-    },
-    registerForgottenHandleCleanup(
-      owner: object,
-      handle: RuntimeHandle,
-      _releaseOwnership: () => void,
-    ): void {
-      forgottenHandles.register(owner, asBrokerHandle(handle));
-    },
-    unregisterForgottenHandleCleanup(owner: object): void {
-      forgottenHandles.unregister(owner);
-    },
-  };
-}
-
-/** @internal Runtime-owned handle; exported only for package-internal contract tests. */
-export class BrokerHandle {
-  #child: ManagedChild | undefined;
-  #stream: ByteStream | undefined;
-  #cancelEndpoint: string | undefined;
-  #ipcDir: string | undefined;
-  #temporaryInstanceDirectory: string | undefined;
-  #authToken: string | undefined;
-  #failed = false;
-  #failure: unknown;
-  #closed = false;
-
-  constructor(
-    readonly config: NormalizedOpenConfig,
-    launch: BrokerLaunch,
-    authToken: string,
-    private readonly shutdownTimeoutMs = SHUTDOWN_TIMEOUT_MS,
-  ) {
-    this.#child = launch.child;
-    this.#stream = launch.stream;
-    this.#cancelEndpoint = launch.cancelEndpoint;
-    this.#ipcDir = launch.ipcDir;
-    this.#temporaryInstanceDirectory = config.temporaryDirectory
-      ? config.instanceDirectory
-      : undefined;
-    this.#authToken = authToken;
-  }
-
-  async requestOk(frame: Parameters[1]): Promise {
-    const response = await this.request(frame);
-    switch (response.kind) {
-      case 'ok':
-        return response.bytes;
-      case 'error':
-        throw new Error(response.message);
-      case 'chunk':
-        throw new Error('native broker returned a stream chunk for a buffered request');
-      case 'streamCallbackAborted':
-        throw new Error(
-          `native broker returned a stream callback-aborted frame for a buffered request: ${response.message}`,
-        );
-    }
-  }
-
-  async execProtocolStream(
-    request: Uint8Array,
-    onChunk: (chunk: Uint8Array) => void,
-  ): Promise {
-    const stream = await this.ensureStream();
-    let callbackFailed = false;
-    let callbackError: unknown;
-    try {
-      await writeBrokerRequest(stream, {
-        kind: 'execProtocolStream',
-        bytes: request,
-      });
-    } catch (error) {
-      await this.markFailed(error);
-      throw error;
-    }
-    for (;;) {
-      let response: BrokerResponseFrame;
-      try {
-        response = await readBrokerResponse(stream);
-      } catch (error) {
-        await this.markFailed(error);
-        throw error;
-      }
-      switch (response.kind) {
-        case 'chunk':
-          if (!callbackFailed) {
-            try {
-              onChunk(response.bytes);
-            } catch (error) {
-              callbackFailed = true;
-              callbackError = error;
-            }
-          }
-          break;
-        case 'ok':
-          resolveBrokerStreamCompletion(response, callbackFailed, callbackError);
-          return;
-        case 'error':
-        case 'streamCallbackAborted':
-          resolveBrokerStreamCompletion(response, callbackFailed, callbackError);
-          return;
-      }
-    }
-  }
-
-  async cancel(): Promise {
-    const endpoint = this.#cancelEndpoint;
-    if (endpoint === undefined) {
-      throw new Error('native broker cancel endpoint is unavailable');
-    }
-    const authToken = this.#authToken;
-    if (authToken === undefined) {
-      throw new Error('native broker auth token is unavailable');
-    }
-    const stream = await connectEndpoint(parseReadyEndpoint(endpoint));
-    await cancelBrokerStream(stream, authToken);
-  }
-
-  async detach(): Promise {
-    const firstAttempt = !this.#closed;
-    this.#closed = true;
-    this.#cancelEndpoint = undefined;
-    this.#authToken = undefined;
-    const failures: unknown[] = [];
-    const stream = this.#stream;
-    if (stream !== undefined) {
-      if (firstAttempt && !this.#failed) {
-        try {
-          await writeBrokerRequest(stream, { kind: 'close' });
-          const response = await readBrokerResponse(stream);
-          if (response.kind === 'error') {
-            throw new Error(`native broker close failed: ${response.message}`);
-          }
-          if (response.kind === 'chunk') {
-            throw new Error('native broker close returned a stream chunk');
-          }
-          if (response.kind === 'streamCallbackAborted') {
-            throw new Error(
-              `native broker close returned a stream callback-aborted frame: ${response.message}`,
-            );
-          }
-        } catch (error) {
-          failures.push(error);
-        }
-      }
-      try {
-        await stream.close();
-        if (this.#stream === stream) {
-          this.#stream = undefined;
-        }
-      } catch (error) {
-        // Retain the exact stream so a later internal cleanup attempt can
-        // retry releasing it. Public close still memoizes this first terminal
-        // result and never presents the handle as usable again.
-        failures.push(error);
-      }
-    }
-    const child = this.#child;
-    if (child !== undefined) {
-      try {
-        let exited = await waitForManagedChild(child, this.shutdownTimeoutMs);
-        if (!exited) {
-          failures.push(new Error(`native broker did not stop within ${this.shutdownTimeoutMs}ms`));
-          child.kill('SIGKILL');
-          exited = await waitForManagedChild(child, this.shutdownTimeoutMs);
-          if (!exited) {
-            failures.push(
-              new Error(
-                `native broker was not reaped within ${this.shutdownTimeoutMs}ms after SIGKILL`,
-              ),
-            );
-          }
-        }
-        if (exited && this.#child === child) {
-          this.#child = undefined;
-        }
-      } catch (error) {
-        // An unconfirmed reap remains owned by this terminal handle. Never
-        // discard the only child handle merely because wait/kill failed.
-        failures.push(error);
-      }
-    }
-    // A process whose reap is unconfirmed may still have its IPC endpoint and
-    // PGDATA open. Never remove either tree underneath it; retain the exact
-    // paths until a later internal cleanup attempt confirms the reap.
-    if (this.#child === undefined) {
-      const ipcDir = this.#ipcDir;
-      try {
-        await removeTree(ipcDir);
-        if (this.#ipcDir === ipcDir) {
-          this.#ipcDir = undefined;
-        }
-      } catch (error) {
-        // Retain the path so later best-effort cleanup can retry it.
-        failures.push(error);
-      }
-      const temporaryInstanceDirectory = this.#temporaryInstanceDirectory;
-      if (temporaryInstanceDirectory !== undefined) {
-        try {
-          await removeTree(temporaryInstanceDirectory);
-          if (this.#temporaryInstanceDirectory === temporaryInstanceDirectory) {
-            this.#temporaryInstanceDirectory = undefined;
-          }
-        } catch (error) {
-          // Retain the managed-root cleanup identity after a failed removal.
-          failures.push(error);
-        }
-      }
-    }
-    if (
-      this.#stream !== undefined ||
-      this.#child !== undefined ||
-      this.#ipcDir !== undefined ||
-      this.#temporaryInstanceDirectory !== undefined
-    ) {
-      // Public close is terminal after the first destructive attempt, so no
-      // later facade call is available to own these uncertain resources. Keep
-      // the exact private handle alive through process exit instead of letting
-      // GC discard the only stream/child/path cleanup identity.
-      retainedFailedBrokerHandles.add(this);
-    } else {
-      retainedFailedBrokerHandles.delete(this);
-    }
-    throwCollectedCloseFailures(failures, 'native broker teardown failed');
-  }
-
-  async request(frame: Parameters[1]): Promise {
-    const stream = await this.ensureStream();
-    try {
-      await writeBrokerRequest(stream, frame);
-      return await readBrokerResponse(stream);
-    } catch (error) {
-      await this.markFailed(error);
-      throw error;
-    }
-  }
-
-  async ensureStream(): Promise {
-    if (this.#closed) {
-      throw new Error('native broker session is closed');
-    }
-    if (this.#failed) {
-      throw new Error(
-        'native broker helper failed; close and reopen the database before running more work',
-        { cause: this.#failure },
-      );
-    }
-    if (this.#stream === undefined) {
-      throw new Error(
-        'native broker stream is unavailable; close and reopen the database before running more work',
-      );
-    }
-    return this.#stream;
-  }
-
-  async markFailed(error: unknown): Promise {
-    if (!this.#failed) {
-      this.#failed = true;
-      this.#failure = error;
-    }
-    const stream = this.#stream;
-    try {
-      await stream?.close();
-      if (this.#stream === stream) {
-        this.#stream = undefined;
-      }
-    } catch {
-      // Preserve the operation/transport failure that made session state
-      // unknown. Keep cleanup ownership so explicit close can retry it.
-    }
-    const child = this.#child;
-    if (child !== undefined) {
-      try {
-        child.kill('SIGKILL');
-        const reaped = await waitForManagedChild(child, this.shutdownTimeoutMs);
-        if (reaped && this.#child === child) {
-          this.#child = undefined;
-        }
-      } catch {
-        // Retain the child handle so explicit close can retry reaping it.
-      }
-    }
-    if (this.#child === undefined) {
-      const ipcDir = this.#ipcDir;
-      try {
-        await removeTree(ipcDir);
-        if (this.#ipcDir === ipcDir) {
-          this.#ipcDir = undefined;
-        }
-      } catch {
-        // Retain the path so explicit close retries filesystem cleanup.
-      }
-    }
-    this.#cancelEndpoint = undefined;
-    this.#authToken = undefined;
-  }
-}
-
-/** @internal Execute one out-of-band cancellation and always release its control stream. */
-export async function cancelBrokerStream(stream: ByteStream, authToken: string): Promise {
-  try {
-    await authenticateBroker(stream, authToken);
-    await writeBrokerRequest(stream, { kind: 'cancel' });
-    const response = await readBrokerResponse(stream);
-    if (response.kind === 'error') {
-      throw new Error(`native broker cancel failed: ${response.message}`);
-    }
-    if (response.kind === 'chunk') {
-      throw new Error('native broker cancel endpoint returned a stream chunk');
-    }
-    if (response.kind === 'streamCallbackAborted') {
-      throw new Error(
-        `native broker cancel endpoint returned a stream callback-aborted frame: ${response.message}`,
-      );
-    }
-  } catch (primaryFailure) {
-    try {
-      await stream.close();
-    } catch (closeFailure) {
-      throw new AggregateError(
-        [primaryFailure, closeFailure],
-        'native broker cancel and control-stream close both failed',
-      );
-    }
-    throw primaryFailure;
-  }
-  await stream.close();
-}
-
-// Intentionally process-lifetime ownership for resources whose destructive
-// cleanup did not complete. Entries are removed only if a package-internal
-// best-effort retry later releases every exact resource.
-const retainedFailedBrokerHandles = new Set();
-
-async function openBrokerHandle(
-  executable: string | undefined,
-  config: NormalizedOpenConfig,
-): Promise {
-  const authToken = randomHexToken();
-  const launch = await launchBroker(executable, config, authToken);
-  return new BrokerHandle(config, launch, authToken);
-}
-
-type BrokerLaunch = {
-  child: ManagedChild;
-  stream: ByteStream;
-  cancelEndpoint: string;
-  ipcDir?: string;
-};
-
-async function launchBroker(
-  executable: string | undefined,
-  config: NormalizedOpenConfig,
-  authToken: string,
-): Promise {
-  const failedLaunch: FailedManagedLaunch = {
-    paths: [undefined, config.temporaryDirectory ? config.instanceDirectory : undefined],
-  };
-  try {
-    const startupTimeoutMs = brokerStartupTimeoutMs();
-    const resolvedExecutable = await resolveBrokerExecutable(executable);
-    const endpoint = await allocateBrokerEndpoint(config);
-    failedLaunch.paths[0] = endpoint.ipcDir;
-    const nativeInstall = await resolveBrokerNativeInstall(config);
-    const child = spawnManagedChild({
-      executable: resolvedExecutable,
-      args: brokerSpawnArgs(config, endpoint),
-      env: brokerSpawnEnv(authToken, nativeInstall),
-      replaceEnv: true,
-    });
-    failedLaunch.child = child;
-    const readiness = new AbortController();
-    const line = await Promise.race([
-      readReadyLine(child.stdout, startupTimeoutMs, 'native broker', readiness.signal),
-      child.exited().then((code) => {
-        throw new Error(`native broker exited before readiness with code ${code ?? 'signal'}`);
-      }),
-    ]).finally(() => readiness.abort());
-    const ready = parseBrokerReadyLine(line);
-    const stream = await connectEndpoint(parseReadyEndpoint(ready.primary));
-    failedLaunch.stream = stream;
-    await authenticateBroker(stream, authToken);
-    return {
-      child,
-      stream,
-      cancelEndpoint: ready.cancel,
-      ipcDir: endpoint.ipcDir,
-    };
-  } catch (error) {
-    const cleanupFailures = await cleanupFailedManagedLaunch(
-      failedLaunch,
-      SHUTDOWN_TIMEOUT_MS,
-      'native broker startup child',
-    );
-    throwCollectedCloseFailures(
-      [error, ...cleanupFailures],
-      'native broker startup and cleanup failed',
-    );
-    throw error;
-  }
-}
-
-function brokerStartupTimeoutMs(): number {
-  return positiveIntegerEnvMs(OLIPHAUNT_BROKER_STARTUP_TIMEOUT_MS_ENV, DEFAULT_STARTUP_TIMEOUT_MS);
-}
-
-function positiveIntegerEnvMs(name: string, fallback: number): number {
-  const value = envVar(name);
-  if (value === undefined || value.length === 0) {
-    return fallback;
-  }
-  const parsed = Number.parseInt(value, 10);
-  if (!Number.isFinite(parsed) || parsed <= 0 || parsed.toString() !== value.trim()) {
-    throw new Error(`${name} must be a positive integer number of milliseconds`);
-  }
-  return parsed;
-}
-
-type BrokerNativeInstall = {
-  libraryPath: string;
-  runtimeDirectory?: string;
-  icuDataDirectory?: string;
-  catalogProfile: 'standard' | 'icu';
-  moduleDirectory?: string;
-};
-
-async function resolveBrokerNativeInstall(config: {
-  libraryPath?: string;
-  runtimeDirectory?: string;
-  extensions?: readonly string[];
-}): Promise {
-  const extensions = config.extensions ?? [];
-  if (runtimeName() === 'deno') {
-    if (
-      extensions.length > 0 &&
-      config.runtimeDirectory === undefined &&
-      envVar(LIBOLIPHAUNT_RUNTIME_DIR_ENV) === undefined
-    ) {
-      throw new Error(
-        `Deno broker execution does not automatically materialize extension packages; pass runtimeDirectory with the selected extension assets or use Node/Bun broker execution. Selected extensions: ${extensions.join(', ')}`,
-      );
-    }
-    const assets = await import('../native/assets-deno.js');
-    const deno = (globalThis as { Deno?: unknown }).Deno;
-    const install = await assets.resolveDenoNativeInstall(config.libraryPath);
-    const runtimeDirectory = config.runtimeDirectory ?? install.runtimeDirectory;
-    if (
-      extensions.length > 0 &&
-      (runtimeDirectory === undefined ||
-        (install.packageManaged && config.runtimeDirectory === undefined))
-    ) {
-      throw new Error(
-        `Deno broker execution does not automatically materialize extension packages; pass runtimeDirectory with the selected extension assets or use Node/Bun broker execution. Selected extensions: ${extensions.join(', ')}`,
-      );
-    }
-    const validated =
-      extensions.length === 0
-        ? { runtimeDirectory, moduleDirectory: undefined }
-        : await assets.validatePreparedDenoRuntimeExtensions({
-            deno: deno as DenoRuntime,
-            runtimeDirectory,
-            extensions,
-            source: 'Deno broker explicit runtimeDirectory',
-          });
-    const explicitRuntimeDirectory =
-      config.runtimeDirectory !== undefined || install.packageManaged === false;
-    const profile =
-      explicitRuntimeDirectory && validated.runtimeDirectory !== undefined
-        ? await resolveExactNativeRuntimeProfile(validated.runtimeDirectory)
-        : {
-            icuDataDirectory: install.icuDataDirectory,
-            catalogProfile: install.catalogProfile ?? ('standard' as const),
-          };
-    return {
-      libraryPath: install.libraryPath,
-      runtimeDirectory: validated.runtimeDirectory,
-      ...profile,
-      moduleDirectory: validated.moduleDirectory,
-    };
-  }
-
-  const assets = await import('../native/assets-node.js');
-  const install = await assets.resolveNodeNativeInstall(config.libraryPath);
-  const explicitRuntimeDirectory =
-    config.runtimeDirectory !== undefined || install.packageManaged === false;
-  const resolved = {
-    libraryPath: install.libraryPath,
-    runtimeDirectory: config.runtimeDirectory ?? install.runtimeDirectory,
-    icuDataDirectory: install.icuDataDirectory,
-    catalogProfile: install.catalogProfile ?? ('standard' as const),
-  };
-  const prepared = await assets.prepareNodeExtensionInstall(resolved, extensions, {
-    explicitRuntimeDirectory,
-  });
-  if (!explicitRuntimeDirectory || prepared.runtimeDirectory === undefined) {
-    return {
-      ...prepared,
-      catalogProfile: prepared.catalogProfile ?? 'standard',
-    };
-  }
-  return {
-    ...prepared,
-    ...(await resolveExactNativeRuntimeProfile(prepared.runtimeDirectory)),
-  };
-}
-
-function brokerSpawnEnv(
-  authToken: string,
-  nativeInstall: BrokerNativeInstall,
-): Record {
-  const env = Object.fromEntries(
-    Object.entries(process.env).filter(
-      (entry): entry is [string, string] => entry[1] !== undefined,
-    ),
-  );
-  delete env[OLIPHAUNT_ICU_DATA_DIR_ENV];
-  delete env[ICU_DATA_ENV];
-  return {
-    ...env,
-    OLIPHAUNT_BROKER_AUTH_TOKEN: authToken,
-    ...brokerNativeInstallEnv(nativeInstall),
-  };
-}
-
-function brokerNativeInstallEnv(nativeInstall: BrokerNativeInstall): Record {
-  const env: Record = {
-    [LIBOLIPHAUNT_PATH_ENV]: nativeInstall.libraryPath,
-  };
-  if (nativeInstall.runtimeDirectory !== undefined) {
-    env[OLIPHAUNT_INSTALL_DIR_ENV] = nativeInstall.runtimeDirectory;
-    env[LIBOLIPHAUNT_RUNTIME_DIR_ENV] = nativeInstall.runtimeDirectory;
-    Object.assign(env, nativeRuntimeLibraryEnvironment(nativeInstall.runtimeDirectory, platform()));
-  }
-  if (nativeInstall.icuDataDirectory !== undefined) {
-    env[OLIPHAUNT_ICU_DATA_DIR_ENV] = nativeInstall.icuDataDirectory;
-    env[ICU_DATA_ENV] = nativeInstall.icuDataDirectory;
-  }
-  if (nativeInstall.moduleDirectory !== undefined) {
-    env[OLIPHAUNT_EMBEDDED_MODULE_DIR_ENV] = nativeInstall.moduleDirectory;
-  }
-  return env;
-}
-
-async function authenticateBroker(stream: ByteStream, authToken: string): Promise {
-  await writeBrokerRequest(stream, { kind: 'authenticate', token: authToken });
-  const response = await readBrokerResponse(stream);
-  if (response.kind === 'error') {
-    throw new Error(`native broker authentication failed: ${response.message}`);
-  }
-  if (response.kind === 'chunk') {
-    throw new Error('native broker authentication returned a stream chunk');
-  }
-  if (response.kind === 'streamCallbackAborted') {
-    throw new Error(
-      `native broker authentication returned a stream callback-aborted frame: ${response.message}`,
-    );
-  }
-}
-
-type BrokerStreamCompletionFrame = Exclude;
-
-/** @internal */
-export function resolveBrokerStreamCompletion(
-  response: BrokerStreamCompletionFrame,
-  callbackFailed: boolean,
-  callbackError: unknown,
-): void {
-  switch (response.kind) {
-    case 'ok':
-      if (callbackFailed) throw callbackError;
-      return;
-    case 'error':
-      // A generic error means the broker did not confirm recovery to
-      // ReadyForQuery. That native failure is authoritative even when the
-      // client callback also failed earlier in the stream.
-      throw new Error(response.message);
-    case 'streamCallbackAborted':
-      if (callbackFailed) throw callbackError;
-      throw new Error(
-        `native broker reported a recovered stream callback abort without a stored client callback error: ${response.message}`,
-      );
-  }
-}
-
-type BrokerEndpointPlan =
-  | { kind: 'unix'; socket: string; cancelSocket: string; ipcDir: string }
-  | { kind: 'tcp'; listen: string; cancelListen: string; ipcDir?: undefined };
-
-async function allocateBrokerEndpoint(config: NormalizedOpenConfig): Promise {
-  const canUseUnix = process.platform !== 'win32';
-  if (canUseUnix) {
-    const ipcDir = await createTempDir('lpgo-');
-    const endpoint = {
-      kind: 'unix',
-      socket: join(ipcDir, 's'),
-      cancelSocket: join(ipcDir, 'c'),
-      ipcDir,
-    } as const;
-    if (unixSocketPathsFit(endpoint.socket, endpoint.cancelSocket)) return endpoint;
-    await removeTree(ipcDir);
-  }
-  return { kind: 'tcp', listen: '127.0.0.1:0', cancelListen: '127.0.0.1:0' };
-}
-
-function brokerSpawnArgs(config: NormalizedOpenConfig, endpoint: BrokerEndpointPlan): string[] {
-  const args = [
-    '--root',
-    config.instanceDirectory,
-    '--username',
-    config.username,
-    '--database',
-    config.database,
-  ];
-  if (endpoint.kind === 'unix') {
-    args.push('--socket', endpoint.socket, '--cancel-socket', endpoint.cancelSocket);
-  } else {
-    args.push('--listen', endpoint.listen, '--cancel-listen', endpoint.cancelListen);
-  }
-  for (const extension of config.extensions) {
-    args.push('--extension', extension);
-  }
-  for (const assignment of startupAssignments(config.startupArgs)) {
-    args.push('--startup-guc', assignment);
-  }
-  return args;
-}
-
-function parseBrokerReadyLine(line: string): {
-  primary: string;
-  cancel: string;
-} {
-  if (line.startsWith(ERROR_PREFIX)) {
-    throw new Error(`native broker failed to start: ${line.slice(ERROR_PREFIX.length)}`);
-  }
-  if (!line.startsWith(READY_PREFIX)) {
-    throw new Error(`native broker did not print a ready line: ${line}`);
-  }
-  const parts = line.slice(READY_PREFIX.length).trim().split(/\s+/);
-  const primary = parts[0];
-  const cancel = parts[1]?.startsWith('cancel=') ? parts[1].slice('cancel='.length) : undefined;
-  if (primary === undefined || cancel === undefined) {
-    throw new Error('native broker ready line did not include primary and cancel endpoints');
-  }
-  return { primary, cancel };
-}
-
-async function resolveBrokerExecutable(explicit: string | undefined): Promise {
-  if (explicit !== undefined) {
-    return requireExecutableFile(explicit, 'brokerExecutable');
-  }
-
-  const configured = envVar(OLIPHAUNT_BROKER_ENV);
-  if (configured !== undefined && configured.trim().length > 0) {
-    if (configured.includes('\0')) {
-      throw new Error(`${OLIPHAUNT_BROKER_ENV} must not contain NUL bytes`);
-    }
-    return requireExecutableFile(configured, OLIPHAUNT_BROKER_ENV);
-  }
-
-  for (const candidate of packageAdjacentExecutables('oliphaunt-broker')) {
-    if (await isFile(candidate)) {
-      return candidate;
-    }
-  }
-  const version = await packageBrokerVersion();
-  const target = brokerPackageTarget(platform(), arch());
-  const installed = await packageBrokerExecutable(target, version);
-  if (installed !== undefined) {
-    return installed;
-  }
-  throw new Error(
-    `${target.packageName} ${version} is not installed; reinstall @oliphaunt/ts with optional dependencies enabled`,
-  );
-}
-
-async function requireExecutableFile(path: string, source: string): Promise {
-  if (!(await isFile(path))) {
-    throw new Error(`${source} does not point to an existing file: ${path}`);
-  }
-  return path;
-}
-
-function packageAdjacentExecutables(base: string): string[] {
-  const here = dirname(fileURLToPath(import.meta.url));
-  return [
-    join(here, base),
-    join(here, `${base}.exe`),
-    join(here, '..', base),
-    join(here, '..', `${base}.exe`),
-    resolve(process.cwd(), base),
-    resolve(process.cwd(), `${base}.exe`),
-  ];
-}
-
-type BrokerPackageTarget = {
-  id: string;
-  packageName: string;
-  executableRelativePath: string;
-};
-
-async function packageBrokerVersion(): Promise {
-  type PackageMetadata = {
-    name?: string;
-    version?: string;
-    oliphaunt?: { brokerVersion?: string };
-  };
-  const packageJson = JSON.parse(
-    await readFile(new URL('../../package.json', import.meta.url), 'utf8'),
-  ) as PackageMetadata;
-  const version = packageJson.oliphaunt?.brokerVersion;
-  if (packageJson.name !== '@oliphaunt/ts' || version === undefined || version.length === 0) {
-    throw new Error('@oliphaunt/ts package metadata does not pin brokerVersion');
-  }
-  return version;
-}
-
-function brokerPackageTarget(currentPlatform: string, currentArch: string): BrokerPackageTarget {
-  const normalizedPlatform = normalizeBrokerPlatform(currentPlatform);
-  const normalizedArch = normalizeBrokerArchitecture(currentArch);
-  if (normalizedPlatform === 'darwin' && normalizedArch === 'arm64') {
-    return {
-      id: 'macos-arm64',
-      packageName: '@oliphaunt/broker-darwin-arm64',
-      executableRelativePath: 'bin/oliphaunt-broker',
-    };
-  }
-  if (normalizedPlatform === 'linux' && normalizedArch === 'x64') {
-    return {
-      id: 'linux-x64-gnu',
-      packageName: '@oliphaunt/broker-linux-x64-gnu',
-      executableRelativePath: 'bin/oliphaunt-broker',
-    };
-  }
-  if (normalizedPlatform === 'linux' && normalizedArch === 'arm64') {
-    return {
-      id: 'linux-arm64-gnu',
-      packageName: '@oliphaunt/broker-linux-arm64-gnu',
-      executableRelativePath: 'bin/oliphaunt-broker',
-    };
-  }
-  if (normalizedPlatform === 'windows' && normalizedArch === 'x64') {
-    return {
-      id: 'windows-x64-msvc',
-      packageName: '@oliphaunt/broker-win32-x64-msvc',
-      executableRelativePath: 'bin/oliphaunt-broker.exe',
-    };
-  }
-  throw new Error(
-    `no oliphaunt-broker package is defined for ${currentPlatform}/${currentArch}; pass brokerExecutable explicitly for this platform`,
-  );
-}
-
-async function packageBrokerExecutable(
-  target: BrokerPackageTarget,
-  expectedVersion: string,
-): Promise {
-  let packageJsonPath: string;
-  try {
-    packageJsonPath = require.resolve(`${target.packageName}/package.json`);
-  } catch {
-    return undefined;
-  }
-  type BrokerPackageMetadata = {
-    name?: string;
-    version?: string;
-    oliphaunt?: {
-      brokerHelper?: string;
-      target?: string;
-      executableRelativePath?: string;
-    };
-  };
-  const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as BrokerPackageMetadata;
-  if (packageJson.name !== target.packageName) {
-    throw new Error(
-      `${target.packageName} package metadata has name ${packageJson.name ?? ''}`,
-    );
-  }
-  if (packageJson.version !== expectedVersion) {
-    throw new Error(
-      `${target.packageName} version ${packageJson.version ?? ''} does not match @oliphaunt/ts brokerVersion ${expectedVersion}`,
-    );
-  }
-  if (packageJson.oliphaunt?.brokerHelper !== 'oliphaunt-broker') {
-    throw new Error(`${target.packageName} package metadata does not declare oliphaunt-broker`);
-  }
-  if (packageJson.oliphaunt?.target !== target.id) {
-    throw new Error(`${target.packageName} package metadata does not target ${target.id}`);
-  }
-  const executable = join(
-    dirname(packageJsonPath),
-    packageJson.oliphaunt.executableRelativePath ?? target.executableRelativePath,
-  );
-  return requireExecutableFile(executable, `${target.packageName} broker helper`);
-}
-
-async function isFile(path: string): Promise {
-  try {
-    return (await stat(path)).isFile();
-  } catch {
-    return false;
-  }
-}
-
-function startupAssignments(startupArgs: string[]): string[] {
-  const assignments: string[] = [];
-  for (let i = 0; i < startupArgs.length; i += 2) {
-    const assignment = startupArgs[i + 1];
-    if (startupArgs[i] === '-c' && assignment !== undefined) {
-      assignments.push(assignment);
-    }
-  }
-  return assignments;
-}
-
-function asBrokerHandle(handle: RuntimeHandle): BrokerHandle {
-  if (handle instanceof BrokerHandle) {
-    return handle;
-  }
-  throw new Error('invalid native broker handle');
-}
-
-function runtimeName(): 'node' | 'bun' | 'deno' {
-  if (typeof (globalThis as { Deno?: unknown }).Deno !== 'undefined') {
-    return 'deno';
-  }
-  if (typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined') {
-    return 'bun';
-  }
-  return 'node';
-}
-
-function normalizeBrokerPlatform(value: string): string {
-  switch (value) {
-    case 'darwin':
-    case 'macos':
-      return 'darwin';
-    case 'win32':
-    case 'windows':
-      return 'windows';
-    default:
-      return value;
-  }
-}
-
-function normalizeBrokerArchitecture(value: string): string {
-  switch (value) {
-    case 'arm64':
-    case 'aarch64':
-      return 'arm64';
-    case 'x64':
-    case 'x86_64':
-      return 'x64';
-    default:
-      return value;
-  }
-}
diff --git a/src/sdks/js/src/runtime/direct.ts b/src/sdks/js/src/runtime/direct.ts
deleted file mode 100644
index 82fb242fd..000000000
--- a/src/sdks/js/src/runtime/direct.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-import type { NormalizedOpenConfig } from '../config.js';
-import {
-  NativeDetachOutcomeUnknownError,
-  type NativeBinding,
-  type NativeHandle,
-} from '../native/types.js';
-import type { RuntimeBinding, RuntimeHandle } from './types.js';
-
-export function directRuntimeBinding(binding: NativeBinding): RuntimeBinding {
-  const runtimeBinding: RuntimeBinding = {
-    open(config: NormalizedOpenConfig): Promise {
-      return binding.open({
-        pgdata: config.pgdata,
-        // Undefined is provenance: Node and Bun may materialize package-managed
-        // extension assets, while a caller-supplied directory must be validated as-is.
-        runtimeDirectory: config.runtimeDirectory,
-        username: config.username,
-        database: config.database,
-        extensions: config.extensions,
-        startupArgs: config.startupArgs,
-      });
-    },
-    execProtocolRaw(handle: RuntimeHandle, request: Uint8Array): Promise {
-      return binding.execProtocolRaw(handle, request);
-    },
-    execProtocolStream(
-      handle: RuntimeHandle,
-      request: Uint8Array,
-      onChunk: (chunk: Uint8Array) => void,
-    ): Promise {
-      return binding.execProtocolStream(handle, request, onChunk);
-    },
-    backup(handle: RuntimeHandle): Promise {
-      return binding.backup(handle);
-    },
-    cancel(handle: RuntimeHandle): Promise {
-      return binding.cancel(handle);
-    },
-    async close(handle: RuntimeHandle) {
-      try {
-        await binding.detach(handle);
-        return { state: 'closed' };
-      } catch (error) {
-        if (error instanceof NativeDetachOutcomeUnknownError) {
-          return { state: 'terminal', error };
-        }
-        // Every other NativeBinding.detach() rejection is required to precede
-        // logical deactivation. Keeping this owner live is therefore safe and
-        // lets a caller retry an interrupted DISCARD ALL / ROLLBACK boundary.
-        return { state: 'retryable', error };
-      }
-    },
-  };
-  if (binding.registerForgottenHandleCleanup !== undefined) {
-    runtimeBinding.registerForgottenHandleCleanup = (
-      owner: object,
-      handle: RuntimeHandle,
-      releaseOwnership: () => void,
-    ) => binding.registerForgottenHandleCleanup?.(owner, handle, releaseOwnership);
-  }
-  if (binding.unregisterForgottenHandleCleanup !== undefined) {
-    runtimeBinding.unregisterForgottenHandleCleanup = (owner: object) =>
-      binding.unregisterForgottenHandleCleanup?.(owner);
-  }
-  if (binding.execSimpleQuery !== undefined) {
-    runtimeBinding.execSimpleQuery = (handle: RuntimeHandle, sql: string) =>
-      binding.execSimpleQuery?.(handle, sql).then(assertDefined) ??
-      Promise.reject(new Error('direct simple query operation is unavailable'));
-  }
-  return runtimeBinding;
-}
-
-function assertDefined(value: T): T {
-  return value;
-}
diff --git a/src/sdks/js/src/runtime/pgwire.ts b/src/sdks/js/src/runtime/pgwire.ts
deleted file mode 100644
index 5041208fd..000000000
--- a/src/sdks/js/src/runtime/pgwire.ts
+++ /dev/null
@@ -1,188 +0,0 @@
-import type { ByteStream } from './byte-stream.js';
-import { connectEndpoint, type LocalEndpoint } from './node-adapter.js';
-import { throwCollectedCloseFailures } from './close.js';
-
-const PROTOCOL_VERSION_3 = 196_608;
-
-export class PostgresWireClient {
-  readonly #stream: ByteStream;
-  #terminateRequested = false;
-  #streamClosed = false;
-
-  private constructor(stream: ByteStream) {
-    this.#stream = stream;
-  }
-
-  static async connect(
-    endpoint: LocalEndpoint,
-    username: string,
-    database: string,
-  ): Promise {
-    const stream = await connectEndpoint(endpoint);
-    try {
-      await stream.writeAll(encodeStartupMessage(username, database));
-      await readUntilReady(stream, {
-        includeMessages: false,
-        errorIsFatal: true,
-      });
-      return new PostgresWireClient(stream);
-    } catch (error) {
-      const failures: unknown[] = [error];
-      try {
-        await stream.close();
-      } catch (closeError) {
-        failures.push(closeError);
-      }
-      throwCollectedCloseFailures(failures, 'native server startup connection cleanup failed');
-      throw error;
-    }
-  }
-
-  async execProtocolRaw(request: Uint8Array): Promise {
-    await this.#stream.writeAll(request);
-    return readUntilReady(this.#stream, {
-      includeMessages: true,
-      errorIsFatal: false,
-    });
-  }
-
-  async terminate(): Promise {
-    const failures: unknown[] = [];
-    if (!this.#terminateRequested) {
-      this.#terminateRequested = true;
-      try {
-        await this.#stream.writeAll(new Uint8Array([0x58, 0, 0, 0, 4]));
-      } catch (error) {
-        failures.push(error);
-      }
-    }
-    if (!this.#streamClosed) {
-      try {
-        await this.#stream.close();
-        this.#streamClosed = true;
-      } catch (error) {
-        failures.push(error);
-      }
-    }
-    throwCollectedCloseFailures(failures, 'native server client termination failed');
-  }
-
-  /** @internal Whether the exact client stream has been released. */
-  get isTerminated(): boolean {
-    return this.#streamClosed;
-  }
-}
-
-export function encodeStartupMessage(username: string, database: string): Uint8Array {
-  const body: number[] = [];
-  pushI32(body, PROTOCOL_VERSION_3);
-  pushCString(body, 'user');
-  pushCString(body, username);
-  pushCString(body, 'database');
-  pushCString(body, database);
-  pushCString(body, 'client_encoding');
-  pushCString(body, 'UTF8');
-  body.push(0);
-  const out: number[] = [];
-  pushI32(out, body.length + 4);
-  out.push(...body);
-  return Uint8Array.from(out);
-}
-
-async function readUntilReady(
-  stream: ByteStream,
-  options: {
-    includeMessages: boolean;
-    errorIsFatal: boolean;
-  },
-): Promise {
-  const chunks: Uint8Array[] = [];
-  for (;;) {
-    const header = await stream.readExactly(5);
-    const tag = header[0];
-    if (tag === undefined) {
-      throw new Error('native server returned an empty backend frame header');
-    }
-    const length = readI32(header, 1);
-    if (length < 4) {
-      throw new Error(`native server returned invalid message length ${length}`);
-    }
-    const body = await stream.readExactly(length - 4);
-    const frame = new Uint8Array(5 + body.length);
-    frame.set(header, 0);
-    frame.set(body, 5);
-    if (options.includeMessages) {
-      chunks.push(frame);
-    }
-    switch (tag) {
-      case 0x52:
-        handleAuthentication(body);
-        break;
-      case 0x45:
-        if (options.errorIsFatal) {
-          throw new Error(parseErrorResponse(body));
-        }
-        break;
-      case 0x5a:
-        return concat(chunks);
-      default:
-        break;
-    }
-  }
-}
-
-function handleAuthentication(body: Uint8Array): void {
-  if (body.length < 4) {
-    throw new Error('native server returned truncated authentication message');
-  }
-  const method = readI32(body, 0);
-  if (method !== 0) {
-    throw new Error(`native server requested unsupported authentication method ${method}`);
-  }
-}
-
-function parseErrorResponse(body: Uint8Array): string {
-  let offset = 0;
-  while (offset < body.length && body[offset] !== 0) {
-    const code = body[offset];
-    offset += 1;
-    const end = body.indexOf(0, offset);
-    if (end < 0) {
-      break;
-    }
-    if (code === 0x4d) {
-      return strictUtf8.decode(body.subarray(offset, end));
-    }
-    offset = end + 1;
-  }
-  return 'native server returned an error response';
-}
-
-function concat(chunks: Uint8Array[]): Uint8Array {
-  const total = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
-  const out = new Uint8Array(total);
-  let offset = 0;
-  for (const chunk of chunks) {
-    out.set(chunk, offset);
-    offset += chunk.length;
-  }
-  return out;
-}
-
-function pushCString(out: number[], value: string): void {
-  if (value.includes('\0')) {
-    throw new Error('PostgreSQL startup string must not contain NUL bytes');
-  }
-  out.push(...new TextEncoder().encode(value), 0);
-}
-
-function pushI32(out: number[], value: number): void {
-  const bits = value >>> 0;
-  out.push((bits >>> 24) & 0xff, (bits >>> 16) & 0xff, (bits >>> 8) & 0xff, bits & 0xff);
-}
-
-function readI32(bytes: Uint8Array, offset: number): number {
-  return new DataView(bytes.buffer, bytes.byteOffset + offset, 4).getInt32(0);
-}
-
-const strictUtf8 = new TextDecoder('utf-8', { fatal: true });
diff --git a/src/sdks/js/src/types.ts b/src/sdks/js/src/types.ts
deleted file mode 100644
index 4f4a1615f..000000000
--- a/src/sdks/js/src/types.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-export type DatabaseStorage =
-  | { readonly kind: 'temporaryDirectory' }
-  | { readonly kind: 'directory'; readonly path: string };
-
-export type BinaryInput = ArrayBuffer | ArrayBufferView | Uint8Array | ReadonlyArray;
-
-type QueryReadOptions = Omit;
-/** A synchronous, serial raw-protocol consumer used as the backpressure acknowledgement. */
-export type ProtocolChunkCallback = (chunk: Uint8Array) => undefined;
-
-export type OpenConfig = {
-  /**
-   * Runtime placement topology. `direct` is in-process; it does not mean that
-   * PostgreSQL work runs synchronously on the JavaScript caller thread.
-   * Server ownership is selected explicitly with `Oliphaunt.openServer()`.
-   */
-  topology?: 'direct' | 'broker';
-  storage?: DatabaseStorage;
-  startupGUCs?: Readonly>;
-  username?: string;
-  database?: string;
-  extensions?: ReadonlyArray;
-  libraryPath?: string;
-  runtimeDirectory?: string;
-  brokerExecutable?: string;
-};
-
-export type ServerOpenConfig = Omit & {
-  serverExecutable?: string;
-  listen?: ServerListen;
-};
-
-export type ServerListen =
-  | { readonly transport: 'tcp'; readonly port?: number }
-  | {
-      readonly transport: 'unix';
-      readonly directory: string;
-      readonly port?: number;
-    };
-
-export type OliphauntTransaction = {
-  readonly closed: boolean;
-  execute(
-    sql: string,
-    parameters?: ReadonlyArray,
-    options?: import('./query.js').ParameterOptions,
-  ): Promise;
-  query(
-    sql: string,
-    parameters?: ReadonlyArray,
-    options?: Options & import('./query.js').QueryOptions,
-  ): Promise>>;
-  queryRaw(
-    sql: string,
-    parameters?: ReadonlyArray,
-    options?: import('./query.js').ParameterOptions,
-  ): Promise;
-  exec(
-    sql: string,
-    options?: Options & QueryReadOptions,
-  ): Promise>>;
-  describe(
-    sql: string,
-    parameterTypeOids?: ReadonlyArray,
-  ): Promise;
-  rollback(): Promise;
-};
-
-export type OliphauntDatabase = {
-  readonly closed: boolean;
-  execute(
-    sql: string,
-    parameters?: ReadonlyArray,
-    options?: import('./query.js').ParameterOptions,
-  ): Promise;
-  query(
-    sql: string,
-    parameters?: ReadonlyArray,
-    options?: Options & import('./query.js').QueryOptions,
-  ): Promise>>;
-  queryRaw(
-    sql: string,
-    parameters?: ReadonlyArray,
-    options?: import('./query.js').ParameterOptions,
-  ): Promise;
-  exec(
-    sql: string,
-    options?: Options & QueryReadOptions,
-  ): Promise>>;
-  describe(
-    sql: string,
-    parameterTypeOids?: ReadonlyArray,
-  ): Promise;
-  execProtocolRaw(input: BinaryInput): Promise;
-  execProtocolRawStream(input: BinaryInput, onChunk: ProtocolChunkCallback): Promise;
-  backup(): Promise;
-  cancel(): Promise;
-  /**
-   * Own the session for one callback. Use callback return/throw or rollback()
-   * for lifecycle; manual BEGIN/START/COMMIT/END/ABORT/PREPARE TRANSACTION and
-   * AND CHAIN are unsupported. SAVEPOINT and ROLLBACK TO are allowed.
-   */
-  transaction(body: (transaction: OliphauntTransaction) => Promise | T): Promise;
-  close(): Promise;
-  [Symbol.asyncDispose](): Promise;
-};
-
-export type OliphauntServer = {
-  readonly closed: boolean;
-  /** Endpoint for caller-owned ORM, driver, or tool connections. */
-  readonly connectionString: string;
-  close(): Promise;
-  [Symbol.asyncDispose](): Promise;
-};
-
-export type RestoreOptions = {
-  libraryPath?: string;
-};
-
-export type OliphauntClient = {
-  open(config?: OpenConfig): Promise;
-  openServer(config?: ServerOpenConfig): Promise;
-  restore(destination: string, backup: BinaryInput, options?: RestoreOptions): Promise;
-};
diff --git a/src/sdks/js/tsconfig.json b/src/sdks/js/tsconfig.json
deleted file mode 100644
index d105afcb4..000000000
--- a/src/sdks/js/tsconfig.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-  "compilerOptions": {
-    "declaration": true,
-    "declarationMap": true,
-    "lib": ["ES2023", "DOM"],
-    "module": "NodeNext",
-    "moduleResolution": "NodeNext",
-    "noEmit": true,
-    "noUncheckedIndexedAccess": true,
-    "outDir": "lib",
-    "rootDir": "src",
-    "skipLibCheck": true,
-    "strict": true,
-    "target": "ES2022",
-    "types": ["node"]
-  },
-  "include": ["src/**/*.ts"],
-  "exclude": ["lib", "node_modules"]
-}
diff --git a/src/sdks/js/typedoc.json b/src/sdks/js/typedoc.json
deleted file mode 100644
index 94456d321..000000000
--- a/src/sdks/js/typedoc.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "$schema": "https://typedoc.org/schema.json",
-  "entryPoints": ["src/index.ts"],
-  "exclude": ["src/__tests__/**"],
-  "excludePrivate": true,
-  "excludeProtected": true,
-  "gitRevision": "main",
-  "json": "../../target/docs/generated/api/typescript/typedoc.json",
-  "name": "Oliphaunt TypeScript SDK",
-  "out": "../../target/docs/generated/api/typescript/html",
-  "plugin": [],
-  "readme": "README.md",
-  "tsconfig": "tsconfig.build.json"
-}
diff --git a/src/sdks/kotlin/CHANGELOG.md b/src/sdks/kotlin/CHANGELOG.md
index d4d98960e..626bcc188 100644
--- a/src/sdks/kotlin/CHANGELOG.md
+++ b/src/sdks/kotlin/CHANGELOG.md
@@ -6,7 +6,6 @@
 ### ⚠ BREAKING CHANGES
 
 * **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/sdks/kotlin/README.md b/src/sdks/kotlin/README.md
index 213c0aefb..b7b7d85b5 100644
--- a/src/sdks/kotlin/README.md
+++ b/src/sdks/kotlin/README.md
@@ -22,6 +22,7 @@ dependencies {
 
 oliphaunt {
     icu.set(true) // Omit unless PostgreSQL ICU collations are required.
+    seedProfile.set("icu") // Select "standard" or "icu" only for first-open initialization.
 }
 ```
 
@@ -90,6 +91,12 @@ recovery, so the session remains reusable. A buffered or streaming transport or
 recovery failure is authoritative and poisons the database; close it instead of
 assuming a later operation can recover the physical session.
 
+Java callers can use `OliphauntJava.open(context)` or
+`OliphauntJava.open(context, config)` on an application worker thread. The
+returned `BlockingOliphauntDatabase` supports `execute`, `query`, `exec`,
+`backup`, `cancel`, and `close`, and implements `AutoCloseable` for
+try-with-resources. These methods block the calling thread.
+
 Suspending calls never execute embedded PostgreSQL or storage preparation on
 the Android UI thread. One single-thread owner dispatcher performs open,
 protocol calls, backup, and close in admission order. A transaction or close
@@ -157,3 +164,30 @@ size reports remain internal build concerns.
 Run `./gradlew :oliphaunt:jvmTest :oliphaunt:testDebugUnitTest` with
 `ANDROID_HOME` configured. Android runtime smoke tests use explicitly packaged
 runtime resources and JNI libraries.
+
+The native execution bridge is generated by UniFFI from `src/sdks/rust/mobile-bindings`.
+Gradle builds its Rust dependencies and packages the selected Android libraries;
+use the repository-pinned Bun and Rust, and install `aarch64-linux-android` and
+`x86_64-linux-android` Rust targets before assembling both published AAR slices.
+Application consumers use the AAR and its JNA dependency without a Rust toolchain.
+`test` runs the Gradle suites; `package-maven` produces local Maven artifacts and
+`package` stages their release distribution.
+
+From this directory, use the same Gradle tasks with their binding prerequisites:
+
+```sh
+moon run oliphaunt-kotlin:build
+moon run oliphaunt-kotlin:test
+moon run oliphaunt-kotlin:lint
+moon run oliphaunt-kotlin:package
+```
+
+These commands generate the Rust bindings first. Source checks and AAR
+assembly run on Linux with Android SDK/NDK, Java, Rust and Bun installed;
+device execution is a separate qualification step. `format-check` checks
+formatting without compiling the native runtime.
+
+`bash tools/test-native-bindings.sh` (or `moon run oliphaunt-kotlin:test-native-bindings`)
+uses the host runtime to test the generated facade, query cancellation and recovery,
+streaming callback errors, transactions and backup. It creates and cleans its own
+database. This portable check complements Android device qualification.
diff --git a/src/sdks/kotlin/build.gradle.kts b/src/sdks/kotlin/build.gradle.kts
index c0ee48a84..dd149cc01 100644
--- a/src/sdks/kotlin/build.gradle.kts
+++ b/src/sdks/kotlin/build.gradle.kts
@@ -1,7 +1,6 @@
 plugins {
     alias(libs.plugins.android.library) apply false
     alias(libs.plugins.detekt) apply false
-    alias(libs.plugins.dokka) apply false
     alias(libs.plugins.kotlin.jvm) apply false
     alias(libs.plugins.kotlin.multiplatform) apply false
     alias(libs.plugins.maven.publish) apply false
diff --git a/src/sdks/kotlin/gradle/libs.versions.toml b/src/sdks/kotlin/gradle/libs.versions.toml
index 0f198a399..60b1d5c09 100644
--- a/src/sdks/kotlin/gradle/libs.versions.toml
+++ b/src/sdks/kotlin/gradle/libs.versions.toml
@@ -6,7 +6,6 @@ kotlinx-serialization = "1.8.1"
 maven-publish = "0.34.0"
 spotless = "8.5.1"
 detekt = "2.0.0-alpha.3"
-dokka = "2.2.0"
 kover = "0.9.8"
 
 [libraries]
@@ -22,5 +21,4 @@ kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref
 maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "maven-publish" }
 spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
 detekt = { id = "dev.detekt", version.ref = "detekt" }
-dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
 kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
diff --git a/src/sdks/kotlin/moon.yml b/src/sdks/kotlin/moon.yml
index fa4e6abb9..9f21ba229 100644
--- a/src/sdks/kotlin/moon.yml
+++ b/src/sdks/kotlin/moon.yml
@@ -4,8 +4,12 @@ id: "oliphaunt-kotlin"
 language: "kotlin"
 layer: "library"
 stack: "systems"
-tags: ["sdk", "kotlin", "android", "native", "release-product"]
+tags: ["javascript-quality", "sdk", "kotlin", "android", "native", "release-product"]
 dependsOn:
+  - id: "oliphaunt-mobile-bindings"
+    scope: "build"
+  - id: "database-resources"
+    scope: "build"
   - id: "extensions"
     scope: "build"
   - id: "cluster-seed-contract"
@@ -38,22 +42,46 @@ fileGroups:
     - "!release.toml"
 
 tasks:
-  check:
-    tags: ["quality", "static", "requires-android-sdk"]
+  format-check:
+    tags: ["quality", "static", "format", "requires-android-sdk"]
+    command: "./gradlew :oliphaunt:spotlessCheck --configuration-cache"
     env:
-      OLIPHAUNT_GRADLE_BUILD_ROOT: "../../../target/moon/oliphaunt-kotlin/check"
+      OLIPHAUNT_GRADLE_BUILD_ROOT: "../../../target"
+    inputs: ["@group(code)"]
+  lint:
+    tags: ["quality", "static", "requires-android-sdk", "requires-rust"]
+    deps:
+      - "oliphaunt-mobile-bindings:generate"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    env:
+      OLIPHAUNT_GRADLE_BUILD_ROOT: "../../../target"
     command: >-
       ./gradlew
-      :oliphaunt:spotlessCheck
       :oliphaunt:detekt
       :oliphaunt:lintDebug
-      :oliphaunt:checkMavenPublicationContract
+      --configuration-cache
+    inputs:
+      - "@group(code)"
+      - project: "extensions"
+        group: "sdk-metadata"
+      - project: "extension-runtime-contract"
+        group: "contract"
+  build:
+    tags: ["build", "requires-android-sdk", "requires-rust"]
+    deps:
+      - "oliphaunt-mobile-bindings:generate"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    env:
+      OLIPHAUNT_GRADLE_BUILD_ROOT: "../../../target"
+    command: >-
+      ./gradlew
       :oliphaunt:compileKotlinJvm
       :oliphaunt:compileDebugKotlinAndroid
       :oliphaunt:compileReleaseKotlinAndroid
       :oliphaunt-android-gradle-plugin:classes
       --configuration-cache
     inputs:
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
       - project: "extensions"
         group: "sdk-metadata"
       - "@group(code)"
@@ -61,15 +89,18 @@ tasks:
         group: "contract"
     options:
       cache: true
-  unit:
-    tags: ["quality", "unit", "requires-android-sdk"]
+  test:
+    tags: ["quality", "unit", "requires-android-sdk", "requires-rust"]
+    deps:
+      - "oliphaunt-mobile-bindings:generate"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
     env:
-      OLIPHAUNT_GRADLE_BUILD_ROOT: "../../../target/moon/oliphaunt-kotlin/unit"
+      OLIPHAUNT_GRADLE_BUILD_ROOT: "../../../target"
     script: |
       set -e
-      sh tools/test-cpp-bridge.sh
       ./gradlew :oliphaunt:jvmTest :oliphaunt:testDebugUnitTest :oliphaunt:testReleaseUnitTest :oliphaunt-android-gradle-plugin:check -x :oliphaunt:koverVerify --configuration-cache
     inputs:
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
       - project: "extensions"
         group: "sdk-metadata"
       - project: "shared-test-fixtures"
@@ -81,11 +112,24 @@ tasks:
         group: "contract"
     options:
       cache: true
-  package:
-    tags: ["package"]
+  test-native-bindings:
+    tags: ["integration", "requires-android-sdk", "requires-rust"]
+    command: "bash tools/test-native-bindings.sh"
+    deps:
+      - "liboliphaunt-native:build-runtime-desktop-target"
+      - "oliphaunt-mobile-bindings:generate"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    options:
+      cache: false
+  package-maven:
+    tags: ["package", "requires-android-sdk", "requires-rust"]
+    deps:
+      - "oliphaunt-mobile-bindings:generate"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
     script: |
       set -e
       ./gradlew \
+        :oliphaunt:checkMavenPublicationContract \
         :oliphaunt:publishAndroidReleasePublicationToMavenLocal \
         :oliphaunt-android-gradle-plugin:publishToMavenLocal \
         "-Dmaven.repo.local=$MOON_WORKSPACE_ROOT/target/moon/oliphaunt-kotlin/package/maven" \
@@ -96,7 +140,7 @@ tasks:
     inputs:
       - project: "extensions"
         group: "sdk-metadata"
-      - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h"
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
       - "@group(code)"
       - project: "extension-runtime-contract"
         group: "contract"
@@ -104,13 +148,72 @@ tasks:
       - "/target/moon/oliphaunt-kotlin/package/maven/**/*"
     options:
       cache: true
-  qualify:
-    tags: ["release", "package"]
-    command: "true"
+  coverage:
+    tags: ["coverage", "requires-android-sdk", "requires-rust"]
+    deps:
+      - "oliphaunt-mobile-bindings:generate"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    command: "./gradlew :oliphaunt:koverXmlReport --configuration-cache"
+    env:
+      OLIPHAUNT_GRADLE_BUILD_ROOT: "../../../target/coverage/oliphaunt-kotlin"
+    inputs:
+      - "@group(code)"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+    outputs: ["/target/coverage/oliphaunt-kotlin/**/*"]
+    options:
+      cache: false
+      runInCI: false
+
+  package:
+    tags: ["release", "artifact-package", "ci-kotlin-sdk-package"]
+    script: |
+      set -eu
+      bash tools/dev/bun.sh src/sdks/kotlin/tools/stage-release-artifacts.mts
+      bash tools/dev/bun.sh src/sdks/kotlin/tools/check-package.mts
+    deps:
+      - "oliphaunt-kotlin:package-maven"
+    inputs:
+      - "@group(legal-files)"
+      - "@group(release-archive-contract)"
+      - "/src/sdks/kotlin/tools/check-package.mts"
+      - "/src/sdks/kotlin/tools/stage-release-artifacts.mts"
+      - "/tools/packaging/staging.mts"
+      - "/tools/dev/bun.sh"
+      - "/src/third-party/tools/source-fetch-core.mts"
+    outputs:
+      - "/target/sdk-artifacts/oliphaunt-kotlin/**/*"
+    options:
+      cache: local
+      runFromWorkspaceRoot: true
+
+  maven-staging:
+    tags: ["release", "artifact-package", "ci-kotlin-maven-staging"]
+    command: "tools/dev/bun.sh src/sdks/kotlin/tools/kotlin-maven-staging.mts"
     deps:
-      - "oliphaunt-kotlin:check"
-      - "oliphaunt-kotlin:unit"
       - "oliphaunt-kotlin:package"
-    inputs: []
+    inputs:
+      - "/src/sdks/kotlin/gradle.properties"
+      - "/src/sdks/kotlin/tools/kotlin-maven-staging.mts"
+      - "/tools/packaging/maven-central-contract.mts"
+      - "/target/sdk-artifacts/oliphaunt-kotlin/maven/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+
+  test-packaging:
+    tags: ["quality", "unit"]
+    command: "bun test --timeout=30000 ./src/sdks/kotlin/tools/kotlin-maven-staging.test.mts"
+    inputs:
+      - "@group(legal-files)"
+      - "@group(release-target-contract)"
+      - "@group(package-test-metadata)"
+      - "**/*.{mjs,mts}"
+      - "/tools/packaging/testdata/**/*"
+      - "/tools/dev/bun.sh"
+      - "/tools/packaging/*.{mts,sh}"
+      - "/tools/release/*.{mjs,mts}"
     options:
       cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/build.gradle.kts b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/build.gradle.kts
index d9723821b..4033489ed 100644
--- a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/build.gradle.kts
+++ b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/build.gradle.kts
@@ -36,10 +36,14 @@ java {
 }
 
 tasks.processResources {
-    from(file("../../../runtimes/liboliphaunt/native/include/oliphaunt.h")) {
+    from(file("../../../database-resources/VERSION")) {
         into("dev/oliphaunt/android")
+        rename { "database-resources.version" }
     }
-    from(file("../../../shared/extension-runtime-contract/extension-artifact-archive-policy.properties")) {
+    from(file("../../../runtimes/liboliphaunt-native/include/oliphaunt.h")) {
+        into("dev/oliphaunt/android")
+    }
+    from(file("../../../extensions/contracts/extension-artifact-archive-policy.properties")) {
         into("dev/oliphaunt/android")
     }
 }
diff --git a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidExtension.java b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidExtension.java
index d18746731..137a06bc1 100644
--- a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidExtension.java
+++ b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidExtension.java
@@ -18,6 +18,11 @@ public OliphauntAndroidExtension(ObjectFactory objects) {
 
   public abstract Property getIcu();
 
+  /** Optional fresh-database seed profile: empty, standard or icu. */
+  public abstract Property getSeedProfile();
+
+  public abstract Property getDatabaseResourcesVersion();
+
   /** Extension SQL names selected for exact runtime and native packaging. */
   public abstract ListProperty getSelectedExtensions();
 
diff --git a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidPlugin.java b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidPlugin.java
index 99d4590ef..8b5ad0b1e 100644
--- a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidPlugin.java
+++ b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidPlugin.java
@@ -19,6 +19,8 @@ public void apply(Project project) {
     OliphauntAndroidExtension extension =
         project.getExtensions().create("oliphaunt", OliphauntAndroidExtension.class);
     String defaultVersion = defaultLiboliphauntVersion();
+    extension.getSeedProfile().convention(project.getProviders().gradleProperty("oliphauntSeedProfile").orElse(""));
+    extension.getDatabaseResourcesVersion().convention(project.getProviders().gradleProperty("oliphauntDatabaseResourcesVersion").orElse(defaultDatabaseResourcesVersion()));
     extension
         .getLiboliphauntVersion()
         .convention(
@@ -107,7 +109,12 @@ public void apply(Project project) {
                   configuration.setDescription("Optional Oliphaunt Android ICU data artifact resolved from Maven.");
                 });
 
-    project.afterEvaluate(ignored -> addDefaultArtifactDependencies(project, extension, runtimeArtifacts, extensionArtifacts, icuArtifacts));
+    Configuration seedArtifacts = project.getConfigurations().create("oliphauntAndroidSeedArtifacts", configuration -> {
+      configuration.setCanBeConsumed(false);
+      configuration.setCanBeResolved(true);
+      configuration.setDescription("Optional selected native PostgreSQL cluster seed.");
+    });
+    project.afterEvaluate(ignored -> addDefaultArtifactDependencies(project, extension, runtimeArtifacts, extensionArtifacts, icuArtifacts, seedArtifacts));
 
     TaskProvider resolve =
         project
@@ -131,6 +138,8 @@ public void apply(Project project) {
                   task.getRuntimeArtifacts().from(runtimeArtifacts);
                   task.getExtensionArtifacts().from(extensionArtifacts);
                   task.getIcuArtifacts().from(icuArtifacts);
+                  task.getSeedArtifacts().from(seedArtifacts);
+                  task.getDatabaseResourcesVersion().set(extension.getDatabaseResourcesVersion());
                   task.getRuntimeResourcesDir().set(resolvedRoot.map(dir -> dir.dir("runtime-resources")));
                   task.getJniLibsDir().set(resolvedRoot.map(dir -> dir.dir("jniLibs")));
                   task.getExtensionArchivesDir().set(resolvedRoot.map(dir -> dir.dir("extensionArchives")));
@@ -276,7 +285,8 @@ private static void addDefaultArtifactDependencies(
       OliphauntAndroidExtension extension,
       Configuration runtimeArtifacts,
       Configuration extensionArtifacts,
-      Configuration icuArtifacts) {
+      Configuration icuArtifacts,
+      Configuration seedArtifacts) {
     String runtimeVersion = extension.getLiboliphauntVersion().get();
     project
         .getDependencies()
@@ -293,10 +303,16 @@ private static void addDefaultArtifactDependencies(
       };
       project.getDependencies().add(runtimeArtifacts.getName(), "dev.oliphaunt.runtime:" + artifact + ":" + runtimeVersion + "@tar.gz");
     }
-    if (extension.getIcu().get()) {
+    String resourceVersion = extension.getDatabaseResourcesVersion().get();
+    String seedProfile = extension.getSeedProfile().get();
+    if (!List.of("", "standard", "icu").contains(seedProfile)) throw new GradleException("seedProfile must be empty, standard or icu");
+    if (!seedProfile.isEmpty()) {
+      project.getDependencies().add(seedArtifacts.getName(), "dev.oliphaunt.runtime:oliphaunt-seed-native-android-datum64-" + seedProfile + ":" + resourceVersion + "@tar.gz");
+    }
+    if (extension.getIcu().get() || seedProfile.equals("icu")) {
       project
           .getDependencies()
-          .add(icuArtifacts.getName(), "dev.oliphaunt.runtime:oliphaunt-icu:" + runtimeVersion + "@tar.gz");
+          .add(icuArtifacts.getName(), "dev.oliphaunt.runtime:oliphaunt-icu:" + resourceVersion + "@tar.gz");
     }
     List extensionOwners =
         OliphauntExtensionCatalog.resolveOwners(
@@ -395,10 +411,18 @@ private static String androidTarget(String abi) {
   }
 
   private static String defaultLiboliphauntVersion() {
+    return embeddedVersion("liboliphaunt.version");
+  }
+
+  private static String defaultDatabaseResourcesVersion() {
+    return embeddedVersion("database-resources.version");
+  }
+
+  private static String embeddedVersion(String name) {
     try (java.io.InputStream stream =
-        OliphauntAndroidPlugin.class.getResourceAsStream("/dev/oliphaunt/android/liboliphaunt.version")) {
+        OliphauntAndroidPlugin.class.getResourceAsStream("/dev/oliphaunt/android/" + name)) {
       if (stream == null) {
-        throw new GradleException("Oliphaunt Android plugin is missing liboliphaunt.version");
+        throw new GradleException("Oliphaunt Android plugin is missing " + name);
       }
       return new String(stream.readAllBytes(), java.nio.charset.StandardCharsets.UTF_8).trim();
     } catch (java.io.IOException error) {
diff --git a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/ResolveOliphauntAndroidAssetsTask.java b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/ResolveOliphauntAndroidAssetsTask.java
index 54419f333..b356bb704 100644
--- a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/ResolveOliphauntAndroidAssetsTask.java
+++ b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/ResolveOliphauntAndroidAssetsTask.java
@@ -47,7 +47,6 @@ public abstract class ResolveOliphauntAndroidAssetsTask extends DefaultTask {
   private static final String ANDROID_CLUSTER_SEED_COMPATIBILITY_KEY =
       "native-pg18-android-datum64-v1";
   private static final String ICU_DATA_SCHEMA = "oliphaunt-icu-data-v1";
-  private static final String RUNTIME_CARRIER_SCHEMA = "oliphaunt-native-runtime-carrier-v1";
   private static final Set RUNTIME_RESOURCE_MANIFEST_KEYS =
       Set.of(
           "schema",
@@ -157,6 +156,9 @@ public ResolveOliphauntAndroidAssetsTask(
   @Input
   public abstract Property getIcu();
 
+  @Input
+  public abstract Property getDatabaseResourcesVersion();
+
   @InputFiles
   @PathSensitive(PathSensitivity.RELATIVE)
   public abstract ConfigurableFileCollection getRuntimeArtifacts();
@@ -169,6 +171,10 @@ public ResolveOliphauntAndroidAssetsTask(
   @PathSensitive(PathSensitivity.RELATIVE)
   public abstract ConfigurableFileCollection getIcuArtifacts();
 
+  @InputFiles
+  @PathSensitive(PathSensitivity.RELATIVE)
+  public abstract ConfigurableFileCollection getSeedArtifacts();
+
   @OutputDirectory
   public abstract DirectoryProperty getRuntimeResourcesDir();
 
@@ -195,10 +201,11 @@ public void resolve() {
     List> selectedRows = selectedExtensionRows(extensionArtifacts, selectedExtensionFiles, abis);
     List icuArtifacts = sortedFiles(getIcuArtifacts().getFiles());
     boolean includeIcu = Boolean.TRUE.equals(getIcu().get()) || !icuArtifacts.isEmpty();
-    File icuArtifact = includeIcu ? findIcuDataArtifact(icuArtifacts, releaseVersion) : null;
+    File icuArtifact = includeIcu ? findIcuDataArtifact(icuArtifacts, getDatabaseResourcesVersion().get()) : null;
 
     unpackRuntimeResources(runtimeResources);
     File resourceRoot = runtimeResourcesRoot(getRuntimeResourcesDir().get().getAsFile());
+    mergeSeedArtifact(resourceRoot);
     validateAndroidRuntimeClosure(resourceRoot);
     if (icuArtifact != null) {
       mergeIcuDataArtifact(icuArtifact);
@@ -259,7 +266,7 @@ private static File findAndroidRuntimeArtifact(List artifacts, String vers
   private static File findIcuDataArtifact(List artifacts, String version) {
     return findArtifact(
         artifacts,
-        List.of("liboliphaunt-" + version + "-icu-data.tar.gz", "oliphaunt-icu-" + version + ".tar.gz"),
+        List.of("database-resources-" + version + "-icu-data.tar.gz", "oliphaunt-icu-" + version + ".tar.gz"),
         List.of("icu"),
         "Oliphaunt ICU data");
   }
@@ -955,7 +962,7 @@ static void validateBundleCompatibility(
         compatibility,
         "extensionRuntimeContract",
         source,
-        "src/shared/extension-runtime-contract/contract.toml");
+        "extensions/contracts/contract.toml");
     requireJsonString(compatibility, "nativeRuntimeProduct", source, "liboliphaunt-native");
     String runtimeVersion =
         requireJsonString(compatibility, "nativeRuntimeVersion", source, null);
@@ -2046,6 +2053,25 @@ private void unpackRuntimeResources(File archive) {
         });
   }
 
+  private void mergeSeedArtifact(File root) {
+    List seeds = sortedFiles(getSeedArtifacts().getFiles());
+    if (seeds.size() > 1) throw new GradleException("Select at most one native cluster seed profile");
+    if (seeds.isEmpty()) return;
+    File archive = validatedTarGzSnapshot(seeds.get(0));
+    File extracted = new File(getTemporaryDir(), "selected-seed");
+    fileSystemOperations.delete(spec -> spec.delete(extracted));
+    fileSystemOperations.copy(spec -> { spec.from(archiveOperations.tarTree(archiveOperations.gzip(archive))); spec.into(extracted); });
+    boolean standard = new File(extracted, "cluster-seed").isDirectory();
+    boolean icu = new File(extracted, "cluster-seed-icu").isDirectory();
+    if (standard == icu) throw new GradleException("A seed carrier must contain exactly one selected profile");
+    String name = standard ? "cluster-seed" : "cluster-seed-icu";
+    File source = new File(extracted, name);
+    validateClusterSeed(source, standard ? "standard" : "icu", standard ? "" : null);
+    File destination = new File(root, name);
+    fileSystemOperations.delete(spec -> spec.delete(destination));
+    copyTree(source.toPath(), destination.toPath());
+  }
+
   private void mergeIcuDataArtifact(File archive) {
     File validatedArchive = validatedTarGzSnapshot(archive);
     File extractRoot = new File(getTemporaryDir(), "icu-artifact-" + archive.getName());
@@ -2071,13 +2097,7 @@ private void mergeIcuDataArtifact(File archive) {
     copyTree(icuRoot.toPath(), destination.toPath());
     File icuClusterSeed = new File(root, "cluster-seed-icu");
     File icuClusterSeedManifest = new File(icuClusterSeed, "manifest.properties");
-    if (!new File(icuClusterSeed, "files/PG_VERSION").isFile()
-        || !new File(icuClusterSeed, "files/global/pg_control").isFile()
-        || !icuClusterSeedManifest.isFile()) {
-      throw new GradleException(
-          "liboliphaunt Android runtime resources do not contain the ICU cluster seed");
-    }
-    validateClusterSeed(icuClusterSeed, "icu", icuDigest);
+    if (icuClusterSeedManifest.exists()) validateClusterSeed(icuClusterSeed, "icu", icuDigest);
     updateRuntimeIcu(new File(runtimePackage, "manifest.properties"), icuDigest);
   }
 
@@ -2376,22 +2396,6 @@ private static File runtimeResourcesRoot(File root) {
   }
 
   private static void validateAndroidRuntimeClosure(File root) {
-    File receiptFile = new File(root, "manifest.properties");
-    Properties receipt = readProperties(receiptFile);
-    Set receiptKeys =
-        Set.of(
-            "schema",
-            "clusterSeedTarget",
-            "clusterSeedRelativePath",
-            "icuClusterSeedRelativePath");
-    if (!receipt.stringPropertyNames().equals(receiptKeys)
-        || !RUNTIME_CARRIER_SCHEMA.equals(receipt.getProperty("schema"))
-        || !ANDROID_CLUSTER_SEED_TARGET.equals(receipt.getProperty("clusterSeedTarget"))
-        || !"cluster-seed".equals(receipt.getProperty("clusterSeedRelativePath"))
-        || !"cluster-seed-icu".equals(receipt.getProperty("icuClusterSeedRelativePath"))) {
-      throw new GradleException(
-          "liboliphaunt Android runtime carrier must contain the exact target seed receipt");
-    }
     File runtimeManifest = new File(root, "runtime/manifest.properties");
     if (!runtimeManifest.isFile() || !new File(root, "runtime/files").isDirectory()) {
       throw new GradleException(
@@ -2421,14 +2425,8 @@ private static void validateAndroidRuntimeClosure(File root) {
       throw new GradleException(
           "liboliphaunt Android runtime resources have inconsistent mobileStaticRegistrySource");
     }
-    validateClusterSeed(new File(root, "cluster-seed"), "standard", "");
-    Properties icuSeed =
-        validateClusterSeed(new File(root, "cluster-seed-icu"), "icu", null);
-    String icuDigest = icuSeed.getProperty("icuDataTreeSha256", "");
-    if (!icuDigest.matches("[0-9a-f]{64}")) {
-      throw new GradleException(
-          "liboliphaunt Android ICU cluster seed must bind a lowercase ICU data tree SHA-256");
-    }
+    if (new File(root, "cluster-seed").exists()) validateClusterSeed(new File(root, "cluster-seed"), "standard", "");
+    if (new File(root, "cluster-seed-icu").exists()) validateClusterSeed(new File(root, "cluster-seed-icu"), "icu", null);
   }
 
   static void validateAndroidRuntimeClosureForContractTest(File root) {
diff --git a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json
index a515c05ed..4585f6ba7 100644
--- a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json
+++ b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extension-legal-catalog.json
@@ -30,8 +30,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -64,8 +64,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -88,8 +88,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -118,8 +118,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -148,8 +148,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -178,8 +178,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -209,8 +209,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -246,8 +246,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -282,8 +282,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -312,8 +312,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -342,8 +342,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -372,8 +372,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -417,8 +417,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -552,8 +552,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -672,8 +672,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -702,8 +702,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -736,8 +736,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -764,8 +764,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -792,8 +792,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -820,8 +820,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -848,8 +848,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -876,8 +876,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -904,8 +904,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -932,8 +932,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -960,8 +960,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -988,8 +988,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1016,8 +1016,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1044,8 +1044,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1072,8 +1072,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1100,8 +1100,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1128,8 +1128,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1156,8 +1156,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1184,8 +1184,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1212,8 +1212,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1240,8 +1240,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1268,8 +1268,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1296,8 +1296,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1324,8 +1324,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1352,8 +1352,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1380,8 +1380,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1408,8 +1408,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1436,8 +1436,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1464,8 +1464,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1492,8 +1492,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1520,8 +1520,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1548,8 +1548,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1576,8 +1576,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1604,8 +1604,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1632,8 +1632,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1660,8 +1660,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1688,8 +1688,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1716,8 +1716,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1744,8 +1744,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1772,8 +1772,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1800,8 +1800,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1828,8 +1828,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -1852,8 +1852,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -1882,8 +1882,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -1912,8 +1912,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -1942,8 +1942,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -1976,8 +1976,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2004,8 +2004,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2029,8 +2029,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -2066,8 +2066,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -2106,8 +2106,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2134,8 +2134,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2158,8 +2158,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -2188,8 +2188,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -2222,8 +2222,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2250,8 +2250,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2278,8 +2278,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2306,8 +2306,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2340,8 +2340,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2374,8 +2374,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2398,8 +2398,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -2428,8 +2428,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -2473,8 +2473,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -2608,8 +2608,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -2732,8 +2732,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2760,8 +2760,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2788,8 +2788,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2816,8 +2816,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2844,8 +2844,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2872,8 +2872,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2900,8 +2900,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2928,8 +2928,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2956,8 +2956,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -2984,8 +2984,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -3012,8 +3012,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -3040,8 +3040,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -3068,8 +3068,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -3096,8 +3096,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         }
       ]
@@ -3120,8 +3120,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
@@ -3150,8 +3150,8 @@
         },
         {
           "path": "THIRD_PARTY_NOTICES.md",
-          "bytes": 864,
-          "sha256": "81765aa852ba082089aceef23be857f36cdf98543c480bf67b764ff011b50619",
+          "bytes": 835,
+          "sha256": "6654a883df21f8dffc2138429db4109b9a462b45e331f469bc0ab0008d22d7bf",
           "mode": "0644"
         },
         {
diff --git a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties
index 657f8a645..e7fcddbbd 100644
--- a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties
+++ b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties
@@ -1,4 +1,4 @@
-# This file is generated by src/extensions/tools/check-extension-model.mjs.
+# This file is generated by src/extensions/tools/check-extension-model.sh.
 # Do not edit by hand.
 schema=oliphaunt-android-extension-catalog-v2
 catalogSha256=c1d2e09905d7ecc0172173b34b9e4104dad58987503dd3dab7af4ae78890d9f3
diff --git a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/test/java/dev/oliphaunt/android/OliphauntExtensionCatalogContractTest.java b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/test/java/dev/oliphaunt/android/OliphauntExtensionCatalogContractTest.java
index c064d054d..6668ac813 100644
--- a/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/test/java/dev/oliphaunt/android/OliphauntExtensionCatalogContractTest.java
+++ b/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/test/java/dev/oliphaunt/android/OliphauntExtensionCatalogContractTest.java
@@ -127,33 +127,9 @@ private static void validatesExactAndroidRuntimeManifestContract() throws Except
 
   private static void writeAndroidRuntimeClosure(Path root, String runtimeManifest)
       throws Exception {
-    writeInventoryFile(
-        root,
-        "manifest.properties",
-        "schema=oliphaunt-native-runtime-carrier-v1\n"
-            + "clusterSeedTarget=android-datum64\n"
-            + "clusterSeedRelativePath=cluster-seed\n"
-            + "icuClusterSeedRelativePath=cluster-seed-icu\n");
     writeInventoryFile(root, "runtime/manifest.properties", runtimeManifest);
     writeInventoryFile(root, "runtime/files/README", "runtime\n");
-    writeInventoryFile(
-        root,
-        "cluster-seed/manifest.properties",
-        androidClusterSeedManifest("cluster-seed-standard", "standard", "", "", "", ""));
-    writeInventoryFile(root, "cluster-seed/files/PG_VERSION", "18\n");
-    writeInventoryFile(root, "cluster-seed/files/global/pg_control", "control\n");
-    writeInventoryFile(
-        root,
-        "cluster-seed-icu/manifest.properties",
-        androidClusterSeedManifest(
-            "cluster-seed-icu",
-            "icu",
-            "icu",
-            "76.1",
-            "files-le",
-            "a".repeat(64)));
-    writeInventoryFile(root, "cluster-seed-icu/files/PG_VERSION", "18\n");
-    writeInventoryFile(root, "cluster-seed-icu/files/global/pg_control", "control\n");
+
   }
 
   private static void validatesPublicTarGzArchivePreflight() throws Exception {
@@ -374,55 +350,6 @@ private static TarFixtureEntry tarFile(String path, String contents) {
     return new TarFixtureEntry(path, '0', contents.getBytes(StandardCharsets.UTF_8));
   }
 
-  private static TarFixtureEntry standardAndroidClusterSeedManifestTarFile() {
-    return tarFile(
-        "oliphaunt/cluster-seed/manifest.properties",
-        androidClusterSeedManifest("cluster-seed-standard", "standard", "", "", "", ""));
-  }
-
-  private static TarFixtureEntry androidRuntimeCarrierReceiptTarFile() {
-    return tarFile(
-        "oliphaunt/manifest.properties",
-        "schema=oliphaunt-native-runtime-carrier-v1\n"
-            + "clusterSeedTarget=android-datum64\n"
-            + "clusterSeedRelativePath=cluster-seed\n"
-            + "icuClusterSeedRelativePath=cluster-seed-icu\n");
-  }
-
-  private static TarFixtureEntry icuAndroidClusterSeedManifestTarFile() {
-    return tarFile(
-        "oliphaunt/cluster-seed-icu/manifest.properties",
-        androidClusterSeedManifest(
-            "cluster-seed-icu",
-            "icu",
-            "icu",
-            "76.1",
-            "files-le",
-            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
-  }
-
-  private static String androidClusterSeedManifest(
-      String artifactRole,
-      String profile,
-      String runtimeFeatures,
-      String icuVersion,
-      String icuForm,
-      String icuDigest) {
-    return "schema=oliphaunt-runtime-resources-v1\n"
-        + "layout=oliphaunt-cluster-seed-v1\n"
-        + "artifactRole=" + artifactRole + "\n"
-        + "catalogProfile=" + profile + "\n"
-        + "postgresMajor=18\n"
-        + "physicalFormat=native-pg18-v1\n"
-        + "target=android-datum64\n"
-        + "compatibilityKey=native-pg18-android-datum64-v1\n"
-        + "initialSuperuser=postgres\n"
-        + "cacheKey=fixture-" + profile + "-cluster-seed\n"
-        + "runtimeFeatures=" + runtimeFeatures + "\n"
-        + "icuDataVersion=" + icuVersion + "\n"
-        + "icuDataForm=" + icuForm + "\n"
-        + "icuDataTreeSha256=" + icuDigest + "\n";
-  }
 
   private static String androidRuntimeManifest(String cacheKey) {
     return "schema=oliphaunt-runtime-resources-v1\n"
@@ -1342,17 +1269,14 @@ private static RuntimeCarrierSet writeCanonicalRuntimeCarrierSet(Path carriers)
             carriers.resolve("liboliphaunt-1.2.3-runtime-resources-android-datum64.tar.gz"),
             tarBytes(
                 List.of(
-                    androidRuntimeCarrierReceiptTarFile(),
                     tarFile(
                         "oliphaunt/runtime/manifest.properties",
                         androidRuntimeManifest("canonical-runtime-fixture")),
                     tarFile("oliphaunt/runtime/files/README.fixture", "runtime\n"),
-                    standardAndroidClusterSeedManifestTarFile(),
-                    tarFile("oliphaunt/cluster-seed/files/PG_VERSION", "18\n"),
-                    tarFile("oliphaunt/cluster-seed/files/global/pg_control", "control\n"),
-                    icuAndroidClusterSeedManifestTarFile(),
-                    tarFile("oliphaunt/cluster-seed-icu/files/PG_VERSION", "18\n"),
-                    tarFile("oliphaunt/cluster-seed-icu/files/global/pg_control", "control\n"),
+
+
+
+
                     tarFile(
                         "oliphaunt/static-registry/manifest.properties",
                         canonicalEmptyStaticRegistryManifest()))));
@@ -1380,17 +1304,14 @@ private static void resolvesExternalAggregateWithoutStaticDependenciesEndToEnd()
               carriers.resolve("liboliphaunt-1.2.3-runtime-resources-android-datum64.tar.gz"),
               tarBytes(
                   List.of(
-                      androidRuntimeCarrierReceiptTarFile(),
                       tarFile(
                           "oliphaunt/runtime/manifest.properties",
                           androidRuntimeManifest("aggregate-resolve-fixture")),
                       tarFile("oliphaunt/runtime/files/README.fixture", "runtime\n"),
-                      standardAndroidClusterSeedManifestTarFile(),
-                      tarFile("oliphaunt/cluster-seed/files/PG_VERSION", "18\n"),
-                      tarFile("oliphaunt/cluster-seed/files/global/pg_control", "control\n"),
-                      icuAndroidClusterSeedManifestTarFile(),
-                      tarFile("oliphaunt/cluster-seed-icu/files/PG_VERSION", "18\n"),
-                      tarFile("oliphaunt/cluster-seed-icu/files/global/pg_control", "control\n"),
+
+
+
+
                       tarFile(
                           "oliphaunt/static-registry/manifest.properties",
                           canonicalEmptyStaticRegistryManifest()))));
@@ -1947,7 +1868,7 @@ private static Path writeSingleMemberAggregateCarrierFromBytes(
 
     Map compatibility = new LinkedHashMap<>();
     compatibility.put(
-        "extensionRuntimeContract", "src/shared/extension-runtime-contract/contract.toml");
+        "extensionRuntimeContract", "extensions/contracts/contract.toml");
     compatibility.put("nativeRuntimeProduct", "liboliphaunt-native");
     compatibility.put("nativeRuntimeVersion", "1.2.3");
     compatibility.put("postgresMajor", "18");
@@ -2919,11 +2840,11 @@ private static byte[] canonicalLegalBytes(
       case "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT" ->
           Files.readAllBytes(
               repository.resolve(
-                  "src/runtimes/liboliphaunt/licenses/postgresql-18.4-COPYRIGHT"));
+                  "src/third-party/postgres/COPYRIGHT"));
       case "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt" ->
           Files.readAllBytes(
               repository.resolve(
-                  "src/runtimes/liboliphaunt/licenses/openssl-3.5.6-LICENSE.txt"));
+                  "src/third-party/openssl/LICENSE.txt"));
       default -> canonicalUpstreamLegalBytes(repository, contract.product(), logicalPath);
     };
   }
@@ -3206,7 +3127,7 @@ private static Map runtimeBundleManifest(
       String target, List> members) {
     Map compatibility = new LinkedHashMap<>();
     compatibility.put(
-        "extensionRuntimeContract", "src/shared/extension-runtime-contract/contract.toml");
+        "extensionRuntimeContract", "extensions/contracts/contract.toml");
     compatibility.put("nativeRuntimeProduct", "liboliphaunt-native");
     compatibility.put("nativeRuntimeVersion", "1.2.3");
     compatibility.put("postgresMajor", "18");
@@ -3368,7 +3289,7 @@ private static void rejectsIncompatibleExternalAndroidCarrier() {
     Map compatible =
         Map.of(
             "extensionRuntimeContract",
-            "src/shared/extension-runtime-contract/contract.toml",
+            "extensions/contracts/contract.toml",
             "nativeRuntimeProduct",
             "liboliphaunt-native",
             "nativeRuntimeVersion",
diff --git a/src/sdks/kotlin/oliphaunt/build.gradle.kts b/src/sdks/kotlin/oliphaunt/build.gradle.kts
index dcb6a1a25..ef5fa6271 100644
--- a/src/sdks/kotlin/oliphaunt/build.gradle.kts
+++ b/src/sdks/kotlin/oliphaunt/build.gradle.kts
@@ -13,7 +13,6 @@ import org.gradle.api.tasks.PathSensitive
 import org.gradle.api.tasks.PathSensitivity
 import org.gradle.api.tasks.TaskAction
 import org.gradle.api.tasks.bundling.AbstractArchiveTask
-import org.jetbrains.dokka.gradle.engine.parameters.VisibilityModifier
 import java.nio.file.Files
 import java.nio.file.Path
 import java.nio.file.StandardCopyOption
@@ -62,7 +61,6 @@ abstract class CheckMavenPublicationContractTask : DefaultTask() {
 plugins {
     id("com.android.library")
     alias(libs.plugins.detekt)
-    alias(libs.plugins.dokka)
     id("org.jetbrains.kotlin.multiplatform")
     alias(libs.plugins.kover)
     alias(libs.plugins.maven.publish)
@@ -112,27 +110,6 @@ kover {
     }
 }
 
-dokka {
-    dokkaPublications.html {
-        moduleName.set("Oliphaunt Kotlin SDK")
-        moduleVersion.set(project.version.toString())
-        outputDirectory.set(rootProject.layout.projectDirectory.dir("../../target/docs/generated/api/kotlin/html"))
-        failOnWarning.set(false)
-        suppressObviousFunctions.set(true)
-    }
-    dokkaSourceSets.configureEach {
-        documentedVisibilities.set(setOf(VisibilityModifier.Public))
-        reportUndocumented.set(false)
-        skipEmptyPackages.set(true)
-        suppressGeneratedFiles.set(true)
-        sourceLink {
-            localDirectory.set(project.layout.projectDirectory.dir("src"))
-            remoteUrl("https://github.com/f0rr0/oliphaunt/tree/main/src/sdks/kotlin/oliphaunt/src")
-            remoteLineSuffix.set("#L")
-        }
-    }
-}
-
 val mavenCentralPublishRequested =
     gradle.startParameter.taskNames.any {
         it.contains("MavenCentral", ignoreCase = true)
@@ -183,6 +160,14 @@ mavenPublishing {
 
 val generatedAndroidAssetsDir = layout.buildDirectory.dir("generated/oliphaunt-android-assets")
 val generatedAndroidJniLibsDir = layout.buildDirectory.dir("generated/oliphaunt-android-jniLibs")
+val mobileBindingsRoot = rootProject.layout.projectDirectory.dir("../../../target/mobile-bindings")
+val generateNativeBindings by tasks.registering(Exec::class) {
+    workingDir(rootProject.layout.projectDirectory.dir("../../.."))
+    commandLine("bash", "src/sdks/rust/mobile-bindings/tools/generate.sh")
+    // Cargo tracks the complete Rust dependency graph, including local crates.
+    outputs.upToDateWhen { false }
+    outputs.dir(mobileBindingsRoot.dir("generated"))
+}
 val configuredCxxBuildRoot =
     (
         oliphauntProperty("oliphauntCxxBuildRoot")
@@ -747,6 +732,12 @@ kotlin {
     jvm()
 
     sourceSets {
+        androidMain {
+            kotlin.srcDir(generateNativeBindings.map { mobileBindingsRoot.dir("generated/dev") })
+            dependencies {
+                implementation("net.java.dev.jna:jna:5.14.0@aar")
+            }
+        }
         commonMain.dependencies {
             implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
         }
@@ -756,6 +747,7 @@ kotlin {
             implementation(libs.kotlinx.serialization.json)
         }
         androidUnitTest.dependencies {
+            implementation("net.java.dev.jna:jna:5.14.0")
             // Android's SDK jar contains only throwing org.json stubs on the host JVM.
             implementation("org.json:json:20240303")
         }
@@ -771,7 +763,7 @@ val baseReleaseNoticeFiles =
     )
 val publishedArchiveTaskNames =
     setOf(
-        "androidReleaseDokkaJavadocJar",
+        "androidReleaseEmptyJavadocJar",
         "androidReleaseSourcesJar",
         "bundleReleaseAar",
     )
@@ -876,31 +868,16 @@ gradle.projectsEvaluated {
 }
 
 val sharedFixturesDirectory =
-    listOf(
-        rootProject.layout.projectDirectory
-            .dir("../../shared/fixtures")
-            .asFile,
-        project.layout.projectDirectory
-            .dir("../../../shared/fixtures")
-            .asFile,
-    ).firstOrNull { it.isDirectory }
-        ?: rootProject.layout.projectDirectory
-            .dir("../../shared/fixtures")
-            .asFile
+    rootProject.layout.projectDirectory
+        .dir("../../test-fixtures")
+        .asFile
 val sharedClusterSeedFixturesDirectory =
-    listOf(
-        rootProject.layout.projectDirectory
-            .dir("../../shared/cluster-seed-contract/fixtures")
-            .asFile,
-        project.layout.projectDirectory
-            .dir("../../../shared/cluster-seed-contract/fixtures")
-            .asFile,
-    ).firstOrNull { it.isDirectory }
-        ?: rootProject.layout.projectDirectory
-            .dir("../../shared/cluster-seed-contract/fixtures")
-            .asFile
+    rootProject.layout.projectDirectory
+        .dir("../../database-resources/contracts/fixtures")
+        .asFile
 
 tasks.withType().configureEach {
+    inputs.property("nativeBindingsPgdata", providers.environmentVariable("OLIPHAUNT_MOBILE_TEST_PGDATA").orElse(""))
     systemProperty(
         "oliphaunt.sharedFixturesDir",
         sharedFixturesDirectory.absolutePath,
@@ -917,6 +894,7 @@ android {
 
     defaultConfig {
         minSdk = 24
+        consumerProguardFiles("consumer-rules.pro")
         if (androidAbiFilters.isNotEmpty()) {
             ndk {
                 abiFilters.addAll(androidAbiFilters)
@@ -958,9 +936,54 @@ android {
 
     sourceSets["main"].assets.srcDir(generatedAndroidAssetsDir)
     sourceSets["main"].jniLibs.srcDir(generatedAndroidJniLibsDir)
+    sourceSets["main"].jniLibs.srcDir(layout.buildDirectory.dir("generated/oliphaunt-rust-jniLibs"))
+    sourceSets["main"].assets.srcDir(layout.buildDirectory.dir("generated/oliphaunt-rust-assets"))
 }
 
+val mobileNdkDirectory = androidComponents.sdkComponents.ndkDirectory
+val buildNativeBindings =
+    (androidAbiFilters.ifEmpty { listOf("arm64-v8a", "x86_64") }).map { abi ->
+        tasks.register("buildNativeBindings${abi.replace("-", "").replace("_", "")}") {
+            val output = layout.buildDirectory.dir("generated/oliphaunt-rust-jniLibs")
+            workingDir(rootProject.layout.projectDirectory.dir("../../.."))
+            commandLine(
+                "bash",
+                "src/sdks/rust/mobile-bindings/tools/build-android.sh",
+                abi,
+                output.get().asFile.absolutePath,
+                layout.buildDirectory
+                    .dir("generated/oliphaunt-rust-assets")
+                    .get()
+                    .asFile.absolutePath,
+            )
+            val ndkDirectory = mobileNdkDirectory
+            doFirst {
+                (this as Exec).environment("ANDROID_NDK_HOME", ndkDirectory.get().asFile.absolutePath)
+            }
+            // Cargo owns the transitive source fingerprint and incremental rebuild.
+            // Do not invent a second handwritten list of Rust dependency inputs.
+        }
+    }
+
 tasks.named("preBuild") {
+    dependsOn(generateNativeBindings)
     dependsOn(prepareOliphauntAndroidAssets)
     dependsOn(prepareOliphauntAndroidJniLibs)
 }
+
+tasks.matching { it.name.startsWith("merge") && (it.name.endsWith("JniLibFolders") || it.name.endsWith("Assets")) }.configureEach {
+    // Source checks also merge resources. Only an AAR needs the Rust payload;
+    // when packaging, generate it before Gradle snapshots the merge inputs.
+    mustRunAfter(buildNativeBindings)
+}
+
+androidComponents.onVariants { variant ->
+    val bundleTask = "bundle${variant.name.replaceFirstChar { it.uppercaseChar() }}Aar"
+    tasks.matching { it.name == bundleTask }.configureEach {
+        dependsOn(buildNativeBindings)
+    }
+}
+
+tasks.matching { it.name.startsWith("compile") && it.name.contains("KotlinAndroid") }.configureEach {
+    dependsOn(generateNativeBindings)
+}
diff --git a/src/sdks/kotlin/oliphaunt/consumer-rules.pro b/src/sdks/kotlin/oliphaunt/consumer-rules.pro
new file mode 100644
index 000000000..e32a3b89c
--- /dev/null
+++ b/src/sdks/kotlin/oliphaunt/consumer-rules.pro
@@ -0,0 +1,3 @@
+# UniFFI's generated JNA ABI uses reflection for native entry points and fields.
+-keep class dev.oliphaunt.bindings.** { *; }
+-keep class com.sun.jna.** { *; }
diff --git a/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/CMakeLists.txt b/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/CMakeLists.txt
index 386c7a123..4817a0052 100644
--- a/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/CMakeLists.txt
+++ b/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/CMakeLists.txt
@@ -2,24 +2,11 @@ cmake_minimum_required(VERSION 3.22.1)
 
 project(liboliphaunt_kotlin_android LANGUAGES C CXX)
 
-add_library(oliphaunt_kotlin_android SHARED
-  oliphaunt_android_bridge.cpp
-)
-
-target_compile_features(oliphaunt_kotlin_android PRIVATE cxx_std_17)
-
-target_include_directories(oliphaunt_kotlin_android PRIVATE
-  "${CMAKE_CURRENT_SOURCE_DIR}/include"
-)
-
-target_link_libraries(oliphaunt_kotlin_android PRIVATE
-  dl
-  log
-)
-
-target_link_options(oliphaunt_kotlin_android PRIVATE
-  "-Wl,-z,max-page-size=16384"
-)
+# Checkout builds use the runtime owner; source distributions carry this header.
+set(OLIPHAUNT_NATIVE_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../runtimes/liboliphaunt-native/include")
+if(NOT EXISTS "${OLIPHAUNT_NATIVE_INCLUDE}/oliphaunt.h")
+  set(OLIPHAUNT_NATIVE_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include")
+endif()
 
 function(oliphaunt_find_file out_var)
   foreach(candidate IN LISTS ARGN)
@@ -74,7 +61,7 @@ if(DEFINED OLIPHAUNT_MOBILE_STATIC_MODULES AND NOT "${OLIPHAUNT_MOBILE_STATIC_MO
     LINKER_LANGUAGE CXX
   )
   target_include_directories(oliphaunt_extensions PRIVATE
-    "${CMAKE_CURRENT_SOURCE_DIR}/include"
+    "${OLIPHAUNT_NATIVE_INCLUDE}"
   )
   target_link_libraries(oliphaunt_extensions PRIVATE
     oliphaunt_imported
diff --git a/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/include/oliphaunt.h b/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/include/oliphaunt.h
deleted file mode 100644
index d96facff7..000000000
--- a/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/include/oliphaunt.h
+++ /dev/null
@@ -1,257 +0,0 @@
-#ifndef OLIPHAUNT_H
-#define OLIPHAUNT_H
-
-#include 
-#include 
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define OLIPHAUNT_ABI_VERSION 10u
-#define OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION 1u
-#define OLIPHAUNT_ERROR_CAPTURE_CAPACITY 1024u
-#define OLIPHAUNT_STREAM_CALLBACK_ABORTED 1
-/* The caller already owns liboliphaunt's stable sibling root lease. */
-#define OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK (1ull << 0)
-
-#if defined(_WIN32) && defined(OLIPHAUNT_BUILDING_DLL)
-#define OLIPHAUNT_API __declspec(dllexport)
-#elif defined(_WIN32)
-#define OLIPHAUNT_API __declspec(dllimport)
-#else
-#define OLIPHAUNT_API
-#endif
-
-typedef struct OliphauntHandle OliphauntHandle;
-
-typedef struct OliphauntStaticExtensionSymbol {
-    const char *name;
-    void *address;
-} OliphauntStaticExtensionSymbol;
-
-typedef struct OliphauntStaticExtension {
-    uint32_t abi_version;
-    const char *name;
-    const void *(*magic)(void);
-    void (*init)(void);
-    const OliphauntStaticExtensionSymbol *symbols;
-    size_t symbol_count;
-    uint64_t reserved_flags;
-} OliphauntStaticExtension;
-
-/*
- * Direct-mode extension compatibility contract:
- *
- * oliphaunt_init sets the process PGDATA environment variable to this config's
- * pgdata path while the embedded backend is active, because PostgreSQL
- * extensions may read PGDATA through standard process APIs. oliphaunt_detach
- * releases a logical direct-mode lease but keeps the resident backend alive;
- * oliphaunt_close is terminal for the process lifetime and restores the caller's
- * previous PGDATA value, or unsets it if it was unset.
- *
- * Every successful oliphaunt_init establishes a current
- * logical lease generation. Hosts with independent cleanup owners must capture
- * its non-zero value immediately with oliphaunt_logical_generation and use
- * oliphaunt_close_if_generation: a stale owner then cannot terminate a newer
- * logical lease on the same resident handle.
- *
- * Callers that require process environment isolation should use broker/server
- * mode through the Rust SDK instead of keeping multiple direct-mode backends in
- * one process.
- */
-typedef struct OliphauntConfig {
-    uint32_t abi_version;
-    /* The pgdata child of an already-prepared managed root. Init does not create it. */
-    const char *pgdata;
-    const char *runtime_dir;
-    /*
-     * Exact PostgreSQL $libdir for the embedded handle. It must name an
-     * existing directory. Pass NULL to use OLIPHAUNT_EMBEDDED_MODULE_DIR and
-     * release-layout discovery.
-     */
-    const char *module_dir;
-    const char *username;
-    const char *database;
-    /* OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK or zero. */
-    uint64_t flags;
-    /* Zero or more `-c`, `name=value` pairs. Storage-routing GUCs are rejected. */
-    const char *const *startup_args;
-    size_t startup_arg_count;
-} OliphauntConfig;
-
-typedef struct OliphauntResponse {
-    uint8_t *data;
-    size_t len;
-} OliphauntResponse;
-
-/*
- * Operation-owned error storage for hosts whose FFI scheduler resumes the
- * caller on a different thread. The `_with_error` entry points below execute
- * the operation and capture its thread-local failure before that native
- * invocation returns. `length` excludes the trailing NUL and is at most
- * OLIPHAUNT_ERROR_CAPTURE_CAPACITY - 1; `message` is always NUL-terminated
- * and is empty on success. The entire capture is zeroed on success. Native
- * error sources use the same bound, so a valid runtime error is not
- * additionally truncated during capture.
- */
-typedef struct OliphauntErrorCapture {
-    uint32_t length;
-    char message[OLIPHAUNT_ERROR_CAPTURE_CAPACITY];
-} OliphauntErrorCapture;
-
-typedef struct OliphauntRestoreOptions {
-    uint32_t abi_version;
-    /* New or existing-empty managed-root path; this is not a PGDATA path. */
-    const char *destination;
-    /* Bytes in the single native physical archive format returned by oliphaunt_backup. */
-    const uint8_t *data;
-    size_t len;
-} OliphauntRestoreOptions;
-
-/*
- * Same-handle ownership and streaming contract:
- *
- * Hosts serialize ordinary non-cancel operations on one logical handle.
- * oliphaunt_cancel is the deliberate cross-thread exception and may interrupt
- * the active PostgreSQL operation. A successful detach ends that logical
- * lease; a successful close terminally invalidates the opaque handle, which
- * must never be dereferenced again.
- *
- * A raw-stream callback borrows data only for that callback invocation. It may
- * copy the bytes, inspect errors, or call oliphaunt_cancel. It must not call
- * query, backup, detach, close, or another raw-stream operation on the same
- * handle. Those calls fail with a busy error while streaming is active,
- * including from another thread, so the callback cannot corrupt protocol
- * ordering or free its own handle. A non-zero callback result stops later
- * callback delivery and drains the backend to ReadyForQuery. The stream then
- * returns OLIPHAUNT_STREAM_CALLBACK_ABORTED; negative results identify
- * validation, transport, backend, or recovery failures for which reuse may be
- * unsafe.
- */
-typedef int32_t (*OliphauntStreamCallback)(void *context, const uint8_t *data, size_t len);
-
-OLIPHAUNT_API int32_t oliphaunt_init(const OliphauntConfig *config, OliphauntHandle **out);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_exec_simple_query(
-    OliphauntHandle *handle,
-    const char *sql,
-    size_t sql_len,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context);
-/*
- * Creates a session-preserving online physical archive. If an error says that
- * backup-mode exit is unconfirmed, no later query is safe: detach/close the
- * handle and restart the process before reopening PostgreSQL.
- */
-OLIPHAUNT_API int32_t oliphaunt_backup(
-    OliphauntHandle *handle,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_restore(const OliphauntRestoreOptions *options);
-/*
- * Scheduler-safe variants for asynchronous FFI hosts. These preserve the
- * return code and response ownership of their corresponding operation while
- * filling a required caller-owned capture before returning.
- */
-OLIPHAUNT_API int32_t oliphaunt_init_with_error(
-    const OliphauntConfig *config,
-    OliphauntHandle **out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_with_error(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_simple_query_with_error(
-    OliphauntHandle *handle,
-    const char *sql,
-    size_t sql_len,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream_with_error(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_backup_with_error(
-    OliphauntHandle *handle,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_restore_with_error(
-    const OliphauntRestoreOptions *options,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_detach_with_error(
-    OliphauntHandle *handle,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_cancel(OliphauntHandle *handle);
-/* A poisoned backup session is terminally closed instead of retained. */
-OLIPHAUNT_API int32_t oliphaunt_detach(OliphauntHandle *handle);
-/*
- * Returns the non-zero generation of the currently published logical lease.
- * Returns zero for NULL, stale, terminally closed, or otherwise non-current
- * handles. The registry is validated before the opaque handle is dereferenced.
- */
-OLIPHAUNT_API uint64_t oliphaunt_logical_generation(OliphauntHandle *handle);
-/*
- * Terminally closes the process-wide resident handle only when generation
- * still owns its current logical lease. Returns 0 when terminal close completes
- * or had already completed, 1 for an active stale/non-owner generation no-op,
- * and -1 for generation zero or an internal failure.
- */
-OLIPHAUNT_API int32_t oliphaunt_close_if_generation(
-    uint64_t generation);
-/*
- * Unconditionally performs process-terminal close for the current published
- * resident handle. Hosts with multiple cleanup owners should use
- * oliphaunt_close_if_generation and retain only its generation token.
- */
-OLIPHAUNT_API int32_t oliphaunt_close(OliphauntHandle *handle);
-/*
- * Registers statically linked PostgreSQL extension modules for the embedded
- * backend's normal LOAD path.
- *
- * Call this before oliphaunt_init in processes that link extension code directly
- * into the application or SDK library. The registry is process-wide and becomes
- * immutable once backend startup begins. Each extension name is the module stem
- * used by SQL, for example AS 'vector', and each symbol row exposes the C
- * symbols PostgreSQL would otherwise resolve with dlsym().
- */
-OLIPHAUNT_API int32_t oliphaunt_register_static_extensions(const OliphauntStaticExtension *extensions, size_t count);
-/*
- * Copies an error into caller-owned storage. Immediately after a fallible C
- * operation returns failure, calls on that same thread read the operation's
- * owned snapshot. It takes precedence over the shared handle/global error and
- * remains stable across a size probe and repeated copies until the thread
- * begins another fallible C operation, even if another thread updates the
- * shared error. With no operation snapshot, this atomically reads the latest
- * handle error, or the process-global error when handle is NULL.
- *
- * The return value is the full UTF-8 byte length excluding the trailing NUL.
- * When capacity is non-zero, out must be non-NULL and is always
- * NUL-terminated; content is truncated when capacity is smaller than length +
- * 1.
- */
-OLIPHAUNT_API size_t oliphaunt_copy_last_error(
-    OliphauntHandle *handle,
-    char *out,
-    size_t capacity);
-OLIPHAUNT_API const char *oliphaunt_version(void);
-OLIPHAUNT_API void oliphaunt_free_response(OliphauntResponse *response);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/oliphaunt_android_bridge.cpp b/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/oliphaunt_android_bridge.cpp
deleted file mode 100644
index 85901e88a..000000000
--- a/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/oliphaunt_android_bridge.cpp
+++ /dev/null
@@ -1,663 +0,0 @@
-#include "oliphaunt.h"
-#include "stream_completion.h"
-
-#include 
-#include 
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-namespace {
-
-using OliphauntInitFn = int32_t (*)(const OliphauntConfig *, OliphauntHandle **);
-using OliphauntExecProtocolFn = int32_t (*)(
-    OliphauntHandle *,
-    const uint8_t *,
-    size_t,
-    OliphauntResponse *);
-using OliphauntExecProtocolRawStreamFn = int32_t (*)(
-    OliphauntHandle *,
-    const uint8_t *,
-    size_t,
-    OliphauntStreamCallback,
-    void *);
-using OliphauntCancelFn = int32_t (*)(OliphauntHandle *);
-using OliphauntDetachFn = int32_t (*)(OliphauntHandle *);
-using OliphauntCloseFn = int32_t (*)(OliphauntHandle *);
-using OliphauntRegisterStaticExtensionsFn = int32_t (*)(const OliphauntStaticExtension *, size_t);
-using OliphauntSelectedStaticExtensionsFn = const OliphauntStaticExtension *(*)(size_t *);
-using OliphauntCopyLastErrorFn = size_t (*)(OliphauntHandle *, char *, size_t);
-using OliphauntFreeResponseFn = void (*)(OliphauntResponse *);
-using OliphauntBackupFn = int32_t (*)(OliphauntHandle *, OliphauntResponse *);
-using OliphauntRestoreFn = int32_t (*)(const OliphauntRestoreOptions *);
-
-struct Symbols {
-  void *library = nullptr;
-  bool ownsLibrary = false;
-  OliphauntInitFn init = nullptr;
-  OliphauntExecProtocolFn execProtocol = nullptr;
-  OliphauntExecProtocolRawStreamFn execProtocolRawStream = nullptr;
-  OliphauntCancelFn cancel = nullptr;
-  OliphauntDetachFn detach = nullptr;
-  OliphauntCloseFn close = nullptr;
-  OliphauntRegisterStaticExtensionsFn registerStaticExtensions = nullptr;
-  OliphauntCopyLastErrorFn copyLastError = nullptr;
-  OliphauntFreeResponseFn freeResponse = nullptr;
-  OliphauntBackupFn backup = nullptr;
-  OliphauntRestoreFn restore = nullptr;
-};
-
-struct Session {
-  Symbols symbols;
-  OliphauntHandle *handle = nullptr;
-};
-
-struct StreamContext {
-  JNIEnv *env = nullptr;
-  jobject sink = nullptr;
-  jmethodID onChunk = nullptr;
-  bool failed = false;
-};
-
-std::string jniString(JNIEnv *env, jstring value) {
-  if (value == nullptr) {
-    return {};
-  }
-  const char *chars = env->GetStringUTFChars(value, nullptr);
-  if (chars == nullptr) {
-    return {};
-  }
-  std::string out(chars);
-  env->ReleaseStringUTFChars(value, chars);
-  return out;
-}
-
-std::vector jniStringArray(JNIEnv *env, jobjectArray values) {
-  std::vector out;
-  if (values == nullptr) {
-    return out;
-  }
-  const jsize count = env->GetArrayLength(values);
-  out.reserve(static_cast(count));
-  for (jsize index = 0; index < count; index += 1) {
-    auto item = static_cast(env->GetObjectArrayElement(values, index));
-    out.push_back(jniString(env, item));
-    env->DeleteLocalRef(item);
-  }
-  return out;
-}
-
-void throwException(JNIEnv *env, const char *className, const std::string &message) {
-  jclass cls = env->FindClass(className);
-  if (cls == nullptr) {
-    return;
-  }
-  env->ThrowNew(cls, message.c_str());
-  env->DeleteLocalRef(cls);
-}
-
-void throwIllegalState(JNIEnv *env, const std::string &message) {
-  throwException(env, "java/lang/IllegalStateException", message);
-}
-
-void throwRuntime(JNIEnv *env, const std::string &message) {
-  throwException(env, "java/lang/RuntimeException", message);
-}
-
-const char *envPath(const char *name) {
-  const char *value = std::getenv(name);
-  return value != nullptr && value[0] != '\0' ? value : nullptr;
-}
-
-std::string defaultLibraryPath() {
-  const char *path = envPath("OLIPHAUNT_KOTLIN_ANDROID_LIBRARY");
-  if (path == nullptr) {
-    path = envPath("LIBOLIPHAUNT_PATH");
-  }
-  if (path == nullptr) {
-    path = envPath("OLIPHAUNT_LIBRARY");
-  }
-  return path != nullptr ? std::string(path) : std::string("liboliphaunt.so");
-}
-
-void unloadSymbols(Symbols *symbols) {
-  // liboliphaunt embeds PostgreSQL, which installs process-global runtime state
-  // while a backend session is active. Ordinary SDK close calls oliphaunt_detach;
-  // oliphaunt_close is terminal for the process lifetime. Unloading the code image
-  // can leave host-process callbacks or handlers pointing at unmapped addresses.
-  // Keep the native engine resident once it has been loaded.
-  *symbols = Symbols{};
-}
-
-bool loadSymbol(Symbols *symbols, const char *name, void **out, std::string *error) {
-  dlerror();
-  void *lookupHandle = symbols->library != nullptr ? symbols->library : RTLD_DEFAULT;
-  *out = dlsym(lookupHandle, name);
-  const char *dlError = dlerror();
-  if (dlError != nullptr || *out == nullptr) {
-    *error = "liboliphaunt symbol ";
-    *error += name;
-    *error += " is unavailable: ";
-    *error += dlError != nullptr ? dlError : "symbol not found";
-    return false;
-  }
-  return true;
-}
-
-bool loadSymbols(const std::string &configuredLibraryPath, Symbols *symbols, std::string *error) {
-  *symbols = Symbols{};
-  std::string libraryPath = configuredLibraryPath.empty()
-      ? defaultLibraryPath()
-      : configuredLibraryPath;
-
-  if (!libraryPath.empty()) {
-    symbols->library = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_GLOBAL);
-    if (symbols->library == nullptr && configuredLibraryPath.empty()) {
-      libraryPath.clear();
-    } else if (symbols->library == nullptr) {
-      *error = "failed to load liboliphaunt at ";
-      *error += configuredLibraryPath;
-      *error += ": ";
-      *error += dlerror();
-      return false;
-    } else {
-      symbols->ownsLibrary = true;
-    }
-  }
-
-  if (!loadSymbol(symbols, "oliphaunt_init", reinterpret_cast(&symbols->init), error) ||
-      !loadSymbol(symbols, "oliphaunt_exec_protocol", reinterpret_cast(&symbols->execProtocol), error) ||
-      !loadSymbol(symbols, "oliphaunt_exec_protocol_raw_stream", reinterpret_cast(&symbols->execProtocolRawStream), error) ||
-      !loadSymbol(symbols, "oliphaunt_cancel", reinterpret_cast(&symbols->cancel), error) ||
-      !loadSymbol(symbols, "oliphaunt_detach", reinterpret_cast(&symbols->detach), error) ||
-      !loadSymbol(symbols, "oliphaunt_close", reinterpret_cast(&symbols->close), error) ||
-      !loadSymbol(symbols, "oliphaunt_register_static_extensions", reinterpret_cast(&symbols->registerStaticExtensions), error) ||
-      !loadSymbol(symbols, "oliphaunt_copy_last_error", reinterpret_cast(&symbols->copyLastError), error) ||
-      !loadSymbol(symbols, "oliphaunt_free_response", reinterpret_cast(&symbols->freeResponse), error) ||
-      !loadSymbol(symbols, "oliphaunt_backup", reinterpret_cast(&symbols->backup), error) ||
-      !loadSymbol(symbols, "oliphaunt_restore", reinterpret_cast(&symbols->restore), error)) {
-    unloadSymbols(symbols);
-    if (libraryPath.empty()) {
-      *error += "; package liboliphaunt.so with the app or pass libraryPath";
-    }
-    return false;
-  }
-  return true;
-}
-
-bool registerSelectedStaticExtensions(Symbols *symbols, std::string *error) {
-  dlerror();
-  OliphauntSelectedStaticExtensionsFn selected = nullptr;
-  static void *extensionLibrary = nullptr;
-  if (symbols->library != nullptr) {
-    selected = reinterpret_cast(
-        dlsym(symbols->library, "liboliphaunt_selected_static_extensions"));
-    const char *libraryError = dlerror();
-    if (libraryError != nullptr) {
-      selected = nullptr;
-    }
-    dlerror();
-  }
-  if (selected == nullptr && extensionLibrary == nullptr) {
-    extensionLibrary = dlopen("liboliphaunt_extensions.so", RTLD_NOW | RTLD_GLOBAL);
-    dlerror();
-  }
-  if (selected == nullptr && extensionLibrary != nullptr) {
-    selected = reinterpret_cast(
-        dlsym(extensionLibrary, "liboliphaunt_selected_static_extensions"));
-    const char *extensionError = dlerror();
-    if (extensionError != nullptr) {
-      selected = nullptr;
-    }
-    dlerror();
-  }
-  if (selected == nullptr) {
-    selected = reinterpret_cast(
-        dlsym(RTLD_DEFAULT, "liboliphaunt_selected_static_extensions"));
-  }
-  const char *dlError = dlerror();
-  if (dlError != nullptr || selected == nullptr) {
-    return true;
-  }
-  size_t count = 0;
-  const OliphauntStaticExtension *extensions = selected(&count);
-  if (count == 0) {
-    return true;
-  }
-  if (extensions == nullptr) {
-    *error = "selected liboliphaunt static extension registry returned null extensions";
-    return false;
-  }
-  if (symbols->registerStaticExtensions(extensions, count) != 0) {
-    const char *fallback = "liboliphaunt static extension registration failed";
-    size_t required = symbols->copyLastError(nullptr, nullptr, 0);
-    if (required == 0 || required == std::numeric_limits::max()) {
-      *error = fallback;
-    } else {
-      std::vector message(required + 1, '\0');
-      size_t currentRequired = symbols->copyLastError(nullptr, message.data(), message.size());
-      if (currentRequired >= message.size() && currentRequired != std::numeric_limits::max()) {
-        message.assign(currentRequired + 1, '\0');
-        symbols->copyLastError(nullptr, message.data(), message.size());
-      }
-      *error = message[0] != '\0' ? std::string(message.data()) : fallback;
-    }
-    return false;
-  }
-  return true;
-}
-
-Session *sessionFromHandle(jlong handle) {
-  return reinterpret_cast(static_cast(handle));
-}
-
-int32_t streamCallback(void *context, const uint8_t *data, size_t len) {
-  auto *stream = static_cast(context);
-  if (stream == nullptr || stream->env == nullptr || stream->sink == nullptr || stream->onChunk == nullptr) {
-    return -1;
-  }
-  jbyteArray chunk = stream->env->NewByteArray(static_cast(len));
-  if (chunk == nullptr) {
-    stream->failed = true;
-    return -1;
-  }
-  if (len > 0 && data != nullptr) {
-    stream->env->SetByteArrayRegion(
-        chunk,
-        0,
-        static_cast(len),
-        reinterpret_cast(data));
-    if (stream->env->ExceptionCheck()) {
-      stream->failed = true;
-      stream->env->DeleteLocalRef(chunk);
-      return -1;
-    }
-  }
-  jint rc = stream->env->CallIntMethod(stream->sink, stream->onChunk, chunk);
-  stream->env->DeleteLocalRef(chunk);
-  if (stream->env->ExceptionCheck()) {
-    stream->failed = true;
-    return -1;
-  }
-  if (rc != 0) {
-    stream->failed = true;
-    return -1;
-  }
-  return 0;
-}
-
-std::string lastError(Session *session) {
-  if (session == nullptr) {
-    return "invalid liboliphaunt Android session";
-  }
-  const char *fallback = "unknown liboliphaunt Android runtime error";
-  if (session->symbols.copyLastError == nullptr) {
-    return fallback;
-  }
-  size_t required = session->symbols.copyLastError(session->handle, nullptr, 0);
-  if (required == 0 || required == std::numeric_limits::max()) {
-    return fallback;
-  }
-  std::vector message(required + 1, '\0');
-  size_t currentRequired = session->symbols.copyLastError(
-      session->handle,
-      message.data(),
-      message.size());
-  if (currentRequired >= message.size() && currentRequired != std::numeric_limits::max()) {
-    message.assign(currentRequired + 1, '\0');
-    session->symbols.copyLastError(session->handle, message.data(), message.size());
-  }
-  return message[0] != '\0' ? std::string(message.data()) : fallback;
-}
-
-}  // namespace
-
-extern "C" JNIEXPORT jlong JNICALL
-Java_dev_oliphaunt_OliphauntAndroidNativeBridge_openNative(
-    JNIEnv *env,
-    jobject,
-    jstring libraryPath,
-    jstring pgdata,
-    jstring runtimeDirectory,
-    jstring username,
-    jstring database,
-    jobjectArray startupArgs) {
-  auto session = new Session();
-  std::string error;
-  if (!loadSymbols(jniString(env, libraryPath), &session->symbols, &error)) {
-    delete session;
-    throwRuntime(env, error);
-    return 0;
-  }
-  if (!registerSelectedStaticExtensions(&session->symbols, &error)) {
-    unloadSymbols(&session->symbols);
-    delete session;
-    throwRuntime(env, error);
-    return 0;
-  }
-
-  std::vector args = jniStringArray(env, startupArgs);
-  std::vector argPointers;
-  argPointers.reserve(args.size());
-  for (const auto &arg : args) {
-    argPointers.push_back(arg.c_str());
-  }
-
-  std::string pgdataPath = jniString(env, pgdata);
-  std::string runtimePath = jniString(env, runtimeDirectory);
-  std::string usernameString = jniString(env, username);
-  std::string databaseString = jniString(env, database);
-  OliphauntConfig config = {
-      .abi_version = OLIPHAUNT_ABI_VERSION,
-      .pgdata = pgdataPath.c_str(),
-      .runtime_dir = runtimePath.c_str(),
-      .module_dir = nullptr,
-      .username = usernameString.c_str(),
-      .database = databaseString.c_str(),
-      .flags = 0,
-      .startup_args = argPointers.data(),
-      .startup_arg_count = argPointers.size(),
-  };
-
-  int32_t rc = session->symbols.init(&config, &session->handle);
-  if (rc != 0 || session->handle == nullptr) {
-    error = lastError(session);
-    unloadSymbols(&session->symbols);
-    delete session;
-    throwRuntime(env, error);
-    return 0;
-  }
-
-  return static_cast(reinterpret_cast(session));
-}
-
-extern "C" JNIEXPORT jbyteArray JNICALL
-Java_dev_oliphaunt_OliphauntAndroidNativeBridge_execProtocolRawNative(
-    JNIEnv *env,
-    jobject,
-    jlong handle,
-    jbyteArray request) {
-  Session *session = sessionFromHandle(handle);
-  if (session == nullptr || session->handle == nullptr) {
-    throwIllegalState(env, "Oliphaunt database is closed");
-    return nullptr;
-  }
-  if (request == nullptr) {
-    throwRuntime(env, "request must not be null");
-    return nullptr;
-  }
-
-  const jsize requestLength = env->GetArrayLength(request);
-  std::vector requestBytes(static_cast(requestLength));
-  if (requestLength > 0) {
-    env->GetByteArrayRegion(
-        request,
-        0,
-        requestLength,
-        reinterpret_cast(requestBytes.data()));
-    if (env->ExceptionCheck()) {
-      return nullptr;
-    }
-  }
-
-  OliphauntResponse response = {nullptr, 0};
-  int32_t rc = session->symbols.execProtocol(
-      session->handle,
-      requestBytes.empty() ? nullptr : requestBytes.data(),
-      requestBytes.size(),
-      &response);
-  if (rc != 0) {
-    std::string error = lastError(session);
-    if (session->symbols.freeResponse != nullptr) {
-      session->symbols.freeResponse(&response);
-    }
-    throwRuntime(env, error);
-    return nullptr;
-  }
-
-  jbyteArray out = env->NewByteArray(static_cast(response.len));
-  if (out != nullptr && response.len > 0) {
-    env->SetByteArrayRegion(
-        out,
-        0,
-        static_cast(response.len),
-        reinterpret_cast(response.data));
-  }
-  session->symbols.freeResponse(&response);
-  return out;
-}
-
-extern "C" JNIEXPORT jboolean JNICALL
-Java_dev_oliphaunt_OliphauntAndroidNativeBridge_execProtocolRawStreamNative(
-    JNIEnv *env,
-    jobject,
-    jlong handle,
-    jbyteArray request,
-    jobject sink) {
-  Session *session = sessionFromHandle(handle);
-  if (session == nullptr || session->handle == nullptr) {
-    throwIllegalState(env, "Oliphaunt database is closed");
-    return JNI_FALSE;
-  }
-  if (request == nullptr) {
-    throwRuntime(env, "request must not be null");
-    return JNI_FALSE;
-  }
-  if (sink == nullptr) {
-    throwRuntime(env, "stream sink must not be null");
-    return JNI_FALSE;
-  }
-
-  const jsize requestLength = env->GetArrayLength(request);
-  std::vector requestBytes(static_cast(requestLength));
-  if (requestLength > 0) {
-    env->GetByteArrayRegion(
-        request,
-        0,
-        requestLength,
-        reinterpret_cast(requestBytes.data()));
-    if (env->ExceptionCheck()) {
-      return JNI_FALSE;
-    }
-  }
-
-  jclass sinkClass = env->GetObjectClass(sink);
-  if (sinkClass == nullptr) {
-    return JNI_FALSE;
-  }
-  jmethodID onChunk = env->GetMethodID(sinkClass, "onChunk", "([B)I");
-  env->DeleteLocalRef(sinkClass);
-  if (onChunk == nullptr) {
-    throwRuntime(env, "stream sink is missing onChunk(byte[])");
-    return JNI_FALSE;
-  }
-
-  StreamContext stream;
-  stream.env = env;
-  stream.sink = sink;
-  stream.onChunk = onChunk;
-  int32_t rc = session->symbols.execProtocolRawStream(
-      session->handle,
-      requestBytes.empty() ? nullptr : requestBytes.data(),
-      requestBytes.size(),
-      streamCallback,
-      &stream);
-  using oliphaunt::android_bridge::StreamCompletion;
-  switch (oliphaunt::android_bridge::classifyStreamCompletion(rc, stream.failed)) {
-    case StreamCompletion::Success:
-      return JNI_FALSE;
-    case StreamCompletion::CallbackAborted:
-      // Expected Kotlin callback failures are captured by the sink. Any
-      // unexpected pending JNI exception remains pending when JNI returns.
-      return JNI_TRUE;
-    case StreamCompletion::NativeFailure: {
-      // Capture the same-thread native diagnostic before touching JNI state.
-      // Transport or recovery failure is authoritative over a callback error.
-      std::string nativeError = lastError(session);
-      if (env->ExceptionCheck()) {
-        env->ExceptionClear();
-      }
-      throwRuntime(env, nativeError);
-      return JNI_FALSE;
-    }
-    case StreamCompletion::ProtocolInconsistency:
-      if (env->ExceptionCheck()) {
-        env->ExceptionClear();
-      }
-      if (rc == 0) {
-        throwRuntime(
-            env,
-            "liboliphaunt returned protocol stream success after the callback failed");
-      } else if (rc == OLIPHAUNT_STREAM_CALLBACK_ABORTED) {
-        throwRuntime(
-            env,
-            "liboliphaunt reported a recovered callback abort without a callback failure");
-      } else {
-        throwRuntime(
-            env,
-            "liboliphaunt returned an unknown positive protocol stream result");
-      }
-      return JNI_FALSE;
-  }
-  throwRuntime(env, "unreachable protocol stream completion state");
-  return JNI_FALSE;
-}
-
-extern "C" JNIEXPORT jbyteArray JNICALL
-Java_dev_oliphaunt_OliphauntAndroidNativeBridge_backupNative(
-    JNIEnv *env,
-    jobject,
-    jlong handle) {
-  Session *session = sessionFromHandle(handle);
-  if (session == nullptr || session->handle == nullptr) {
-    throwIllegalState(env, "Oliphaunt database is closed");
-    return nullptr;
-  }
-  OliphauntResponse response = {nullptr, 0};
-  int32_t rc = session->symbols.backup(session->handle, &response);
-  if (rc != 0) {
-    std::string error = lastError(session);
-    if (session->symbols.freeResponse != nullptr) {
-      session->symbols.freeResponse(&response);
-    }
-    throwRuntime(env, error);
-    return nullptr;
-  }
-
-  jbyteArray out = env->NewByteArray(static_cast(response.len));
-  if (out != nullptr && response.len > 0) {
-    env->SetByteArrayRegion(
-        out,
-        0,
-        static_cast(response.len),
-        reinterpret_cast(response.data));
-  }
-  session->symbols.freeResponse(&response);
-  return out;
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_dev_oliphaunt_OliphauntAndroidNativeBridge_restoreNative(
-    JNIEnv *env,
-    jobject,
-    jstring destination,
-    jbyteArray bytes,
-    jstring libraryPath) {
-  if (bytes == nullptr) {
-    throwRuntime(env, "backup bytes must not be null");
-    return;
-  }
-
-  Symbols symbols;
-  std::string error;
-  if (!loadSymbols(jniString(env, libraryPath), &symbols, &error)) {
-    throwRuntime(env, error);
-    return;
-  }
-
-  std::string destinationPath = jniString(env, destination);
-  const jsize byteLength = env->GetArrayLength(bytes);
-  std::vector backupBytes(static_cast(byteLength));
-  if (byteLength > 0) {
-    env->GetByteArrayRegion(
-        bytes,
-        0,
-        byteLength,
-        reinterpret_cast(backupBytes.data()));
-    if (env->ExceptionCheck()) {
-      unloadSymbols(&symbols);
-      return;
-    }
-  }
-
-  OliphauntRestoreOptions options = {
-      .abi_version = OLIPHAUNT_ABI_VERSION,
-      .destination = destinationPath.c_str(),
-      .data = backupBytes.empty() ? nullptr : backupBytes.data(),
-      .len = backupBytes.size(),
-  };
-  int32_t rc = symbols.restore(&options);
-  if (rc != 0) {
-    const char *fallback = "liboliphaunt restore failed";
-    size_t required = symbols.copyLastError(nullptr, nullptr, 0);
-    if (required == 0 || required == std::numeric_limits::max()) {
-      error = fallback;
-    } else {
-      std::vector message(required + 1, '\0');
-      size_t currentRequired = symbols.copyLastError(nullptr, message.data(), message.size());
-      if (currentRequired >= message.size() && currentRequired != std::numeric_limits::max()) {
-        message.assign(currentRequired + 1, '\0');
-        symbols.copyLastError(nullptr, message.data(), message.size());
-      }
-      error = message[0] != '\0' ? std::string(message.data()) : fallback;
-    }
-    unloadSymbols(&symbols);
-    throwRuntime(env, error);
-    return;
-  }
-  unloadSymbols(&symbols);
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_dev_oliphaunt_OliphauntAndroidNativeBridge_cancelNative(
-    JNIEnv *env,
-    jobject,
-    jlong handle) {
-  Session *session = sessionFromHandle(handle);
-  if (session == nullptr || session->handle == nullptr) {
-    throwIllegalState(env, "Oliphaunt database is closed");
-    return;
-  }
-  int32_t rc = session->symbols.cancel(session->handle);
-  if (rc != 0) {
-    throwRuntime(env, lastError(session));
-  }
-}
-
-extern "C" JNIEXPORT void JNICALL
-Java_dev_oliphaunt_OliphauntAndroidNativeBridge_closeNative(
-    JNIEnv *env,
-    jobject,
-    jlong handle) {
-  Session *session = sessionFromHandle(handle);
-  if (session == nullptr) {
-    return;
-  }
-  int32_t rc = 0;
-  std::string error;
-  if (session->handle != nullptr) {
-    rc = session->symbols.detach(session->handle);
-    if (rc != 0) {
-      error = lastError(session);
-      throwRuntime(env, error.empty() ? "liboliphaunt close failed" : error);
-      return;
-    }
-    session->handle = nullptr;
-  }
-  unloadSymbols(&session->symbols);
-  delete session;
-}
diff --git a/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/stream_completion.h b/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/stream_completion.h
deleted file mode 100644
index c4d5b459d..000000000
--- a/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/stream_completion.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef OLIPHAUNT_KOTLIN_ANDROID_STREAM_COMPLETION_H
-#define OLIPHAUNT_KOTLIN_ANDROID_STREAM_COMPLETION_H
-
-#include "oliphaunt.h"
-
-#include 
-
-namespace oliphaunt::android_bridge {
-
-enum class StreamCompletion {
-  Success,
-  CallbackAborted,
-  NativeFailure,
-  ProtocolInconsistency,
-};
-
-constexpr StreamCompletion classifyStreamCompletion(
-    int32_t result,
-    bool callbackFailed) {
-  if (result < 0) {
-    return StreamCompletion::NativeFailure;
-  }
-  if (result == OLIPHAUNT_STREAM_CALLBACK_ABORTED) {
-    return callbackFailed
-        ? StreamCompletion::CallbackAborted
-        : StreamCompletion::ProtocolInconsistency;
-  }
-  if (result == 0) {
-    return callbackFailed
-        ? StreamCompletion::ProtocolInconsistency
-        : StreamCompletion::Success;
-  }
-  return StreamCompletion::ProtocolInconsistency;
-}
-
-}  // namespace oliphaunt::android_bridge
-
-#endif
diff --git a/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/AndroidNativeDirectEngine.kt b/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/AndroidNativeDirectEngine.kt
index 580b11552..526c39af0 100644
--- a/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/AndroidNativeDirectEngine.kt
+++ b/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/AndroidNativeDirectEngine.kt
@@ -6,19 +6,20 @@ import android.os.Process
 import android.system.ErrnoException
 import android.system.Os
 import android.system.OsConstants
-import kotlinx.coroutines.ExecutorCoroutineDispatcher
-import kotlinx.coroutines.asCoroutineDispatcher
+import dev.oliphaunt.bindings.ChunkSink
+import dev.oliphaunt.bindings.NativeDatabase
+import dev.oliphaunt.bindings.NativeException
+import dev.oliphaunt.bindings.OpenOptions
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.NonCancellable
+import kotlinx.coroutines.currentCoroutineContext
+import kotlinx.coroutines.withContext
 import java.io.File
 import java.io.FileOutputStream
-import java.lang.ref.PhantomReference
-import java.lang.ref.ReferenceQueue
 import java.util.UUID
-import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.Executors
-import java.util.concurrent.atomic.AtomicBoolean
-import java.util.concurrent.locks.ReentrantLock
+import java.util.concurrent.atomic.AtomicReference
 import java.util.zip.ZipFile
-import kotlin.coroutines.suspendCoroutine
 
 private const val OWNER_READ_WRITE_MODE = 384 // 0600
 
@@ -30,124 +31,115 @@ internal class AndroidNativeDirectEngine(
 ) : OliphauntEngine {
     private val appContext = context.applicationContext
 
-    override suspend fun open(config: EngineConfig): OliphauntSession {
-        val executionDispatcher =
-            newAndroidNativeOwnerDispatcher("oliphaunt-android-direct")
-        return try {
-            runOnAndroidNativeOwner(executionDispatcher) {
-                validateDatabaseStorage(config.storage)
-                validateStartupIdentity(config.username, "username")
-                validateStartupIdentity(config.database, "database")
-                validateStartupGucs(config.startupGucs)
-                val runtime =
-                    OliphauntAndroidRuntimeAssets.resolve(
-                        context = appContext,
-                        explicitRuntimeDirectory =
-                        runtimeDirectory
-                            ?: env("OLIPHAUNT_INSTALL_DIR")
-                            ?: env("OLIPHAUNT_RUNTIME_DIR"),
-                        requestedExtensions = config.extensions,
-                        resourceRoot = resourceRoot,
-                    )
-                val storageDirectory =
-                    when (val storage = config.storage) {
-                        EngineStorage.TemporaryDirectory -> AndroidDirectTemporaryStorage.resolve(appContext)
-                        is EngineStorage.Directory -> File(storage.path)
-                    }
-                var nativeOpenAttempted = false
-                try {
-                    if (isAndroidSymbolicLink(storageDirectory)) {
-                        throw OliphauntException(
-                            "database storage directory must be a real directory: ${storageDirectory.absolutePath}",
-                        )
-                    }
-                    if (!storageDirectory.mkdirs() && !storageDirectory.isDirectory) {
-                        throw OliphauntException(
-                            "failed to create database storage directory at ${storageDirectory.absolutePath}",
-                        )
-                    }
-                    val pgdata = File(storageDirectory, "pgdata")
-                    val rootState = classifyAndroidManagedRoot(storageDirectory)
-                    val effectiveUsername = config.username ?: "postgres"
-                    val effectiveDatabase = config.database ?: "postgres"
-                    when (rootState) {
-                        AndroidManagedRootState.Managed -> {
-                            validateCompleteAndroidPgdata(pgdata)
-                        }
+    override suspend fun open(config: EngineConfig): OliphauntSession = withContext(Dispatchers.IO) {
+        validateDatabaseStorage(config.storage)
+        validateStartupIdentity(config.username, "username")
+        validateStartupIdentity(config.database, "database")
+        validateStartupGucs(config.startupGucs)
+        val runtime =
+            OliphauntAndroidRuntimeAssets.resolve(
+                context = appContext,
+                explicitRuntimeDirectory =
+                runtimeDirectory
+                    ?: env("OLIPHAUNT_INSTALL_DIR")
+                    ?: env("OLIPHAUNT_RUNTIME_DIR"),
+                requestedExtensions = config.extensions,
+                resourceRoot = resourceRoot,
+            )
+        val storageDirectory =
+            when (val storage = config.storage) {
+                EngineStorage.TemporaryDirectory -> AndroidDirectTemporaryStorage.resolve(appContext)
+                is EngineStorage.Directory -> File(storage.path)
+            }
+        var nativeOpenAttempted = false
+        try {
+            if (isAndroidSymbolicLink(storageDirectory)) {
+                throw OliphauntException(
+                    "database storage directory must be a real directory: ${storageDirectory.absolutePath}",
+                )
+            }
+            if (!storageDirectory.mkdirs() && !storageDirectory.isDirectory) {
+                throw OliphauntException(
+                    "failed to create database storage directory at ${storageDirectory.absolutePath}",
+                )
+            }
+            val pgdata = File(storageDirectory, "pgdata")
+            val rootState = classifyAndroidManagedRoot(storageDirectory)
+            val effectiveUsername = config.username ?: "postgres"
+            val effectiveDatabase = config.database ?: "postgres"
+            when (rootState) {
+                AndroidManagedRootState.Managed -> {
+                    validateCompleteAndroidPgdata(pgdata)
+                }
 
-                        AndroidManagedRootState.Empty -> {
-                            requireAndroidFreshRootRole(effectiveUsername)
-                            var ownsPublishedPgdata = false
-                            try {
-                                OliphauntAndroidRuntimeAssets.preparePgdata(
-                                    assetManager = appContext.assets,
-                                    pgdata = pgdata,
-                                    clusterSeed = runtime.clusterSeed,
-                                    didPublishDestination = { ownsPublishedPgdata = true },
-                                )
-                                validateCompleteAndroidPgdata(pgdata)
-                                writeAndroidManagedRootDescriptor(storageDirectory)
-                            } catch (publicationError: Throwable) {
-                                recoverAndroidManagedRootPublicationFailure(
-                                    publicationError = publicationError,
-                                    ownsPublishedPgdata = ownsPublishedPgdata,
-                                    descriptorDefinitelyAbsent = {
-                                        isAndroidPathDefinitelyAbsent(
-                                            File(storageDirectory, ".oliphaunt.json"),
-                                        )
-                                    },
-                                    removePublishedPgdata = {
-                                        if (
-                                            !isAndroidPathDefinitelyAbsent(pgdata) &&
-                                            !pgdata.deleteRecursively()
-                                        ) {
-                                            throw OliphauntException(
-                                                "failed to remove uncommitted PGDATA at ${pgdata.absolutePath}",
-                                            )
-                                        }
-                                    },
-                                    syncRoot = {
-                                        OliphauntAndroidRuntimeAssets.syncAndroidDirectory(storageDirectory)
-                                    },
-                                )
-                            }
-                        }
-                    }
-                    val effectiveLibraryPath =
-                        resolveAndroidLiboliphauntLibraryPath(
-                            explicitLibraryPath = libraryPath,
-                            nativeLibraryDirectory = appContext.applicationInfo.nativeLibraryDir,
-                            sourceArchivePaths = appContext.applicationInfo.liboliphauntSourceArchivePaths(),
-                            supportedAbis = Build.SUPPORTED_ABIS.asList(),
+                AndroidManagedRootState.Empty -> {
+                    requireAndroidFreshRootRole(effectiveUsername)
+                    var ownsPublishedPgdata = false
+                    try {
+                        OliphauntAndroidRuntimeAssets.preparePgdata(
+                            assetManager = appContext.assets,
+                            pgdata = pgdata,
+                            clusterSeed = runtime.clusterSeed,
+                            didPublishDestination = { ownsPublishedPgdata = true },
                         )
-                    nativeOpenAttempted = true
-                    val nativeHandle =
-                        OliphauntAndroidNativeBridge.openNative(
-                            effectiveLibraryPath,
-                            pgdata.absolutePath,
-                            runtime.runtimeDirectory,
-                            effectiveUsername,
-                            effectiveDatabase,
-                            config.postgresStartupArgs(runtime.sharedPreloadLibraries).toTypedArray(),
+                        validateCompleteAndroidPgdata(pgdata)
+                        writeAndroidManagedRootDescriptor(storageDirectory)
+                    } catch (publicationError: Throwable) {
+                        recoverAndroidManagedRootPublicationFailure(
+                            publicationError = publicationError,
+                            ownsPublishedPgdata = ownsPublishedPgdata,
+                            descriptorDefinitelyAbsent = {
+                                isAndroidPathDefinitelyAbsent(
+                                    File(storageDirectory, ".oliphaunt.json"),
+                                )
+                            },
+                            removePublishedPgdata = {
+                                if (
+                                    !isAndroidPathDefinitelyAbsent(pgdata) &&
+                                    !pgdata.deleteRecursively()
+                                ) {
+                                    throw OliphauntException(
+                                        "failed to remove uncommitted PGDATA at ${pgdata.absolutePath}",
+                                    )
+                                }
+                            },
+                            syncRoot = {
+                                OliphauntAndroidRuntimeAssets.syncAndroidDirectory(storageDirectory)
+                            },
                         )
-                    AndroidNativeDirectSession(
-                        nativeHandle = nativeHandle,
-                        executionDispatcher = executionDispatcher,
-                    )
-                } catch (error: Throwable) {
-                    executionDispatcher.close()
-                    // Preparation failures are safe to clean. Once control reaches the
-                    // process-resident runtime, a rejected logical reopen may leave it
-                    // owning the same directory.
-                    if (config.storage == EngineStorage.TemporaryDirectory && !nativeOpenAttempted) {
-                        storageDirectory.deleteRecursively()
                     }
-                    throw error
                 }
             }
+            val effectiveLibraryPath =
+                resolveAndroidLiboliphauntLibraryPath(
+                    explicitLibraryPath = libraryPath,
+                    nativeLibraryDirectory = appContext.applicationInfo.nativeLibraryDir,
+                    sourceArchivePaths = appContext.applicationInfo.liboliphauntSourceArchivePaths(),
+                    supportedAbis = Build.SUPPORTED_ABIS.asList(),
+                )
+            nativeOpenAttempted = true
+            val database = NativeDatabase.open(
+                OpenOptions(
+                    libraryPath = effectiveLibraryPath,
+                    pgdata = pgdata.absolutePath,
+                    runtimeDirectory = runtime.runtimeDirectory,
+                    moduleDirectory = null,
+                    icuDataDirectory = File(runtime.runtimeDirectory, "share/icu")
+                        .takeIf { it.isDirectory }?.absolutePath,
+                    username = effectiveUsername,
+                    database = effectiveDatabase,
+                    startupArgs = config.postgresStartupArgs(runtime.sharedPreloadLibraries),
+                ),
+            )
+            AndroidNativeDirectSession(database)
         } catch (error: Throwable) {
-            executionDispatcher.close()
-            throw error
+            // Preparation failures are safe to clean. Once control reaches the
+            // process-resident runtime, a rejected logical reopen may leave it
+            // owning the same directory.
+            if (config.storage == EngineStorage.TemporaryDirectory && !nativeOpenAttempted) {
+                storageDirectory.deleteRecursively()
+            }
+            throw if (error is NativeException.Database) OliphauntException(error.detail) else error
         }
     }
 
@@ -155,24 +147,18 @@ internal class AndroidNativeDirectEngine(
         destination: String,
         bytes: ByteArray,
     ) {
-        val owner = newAndroidNativeOwnerDispatcher("oliphaunt-android-direct-restore")
-        runOnAndroidNativeOwner(owner) {
-            try {
-                validateDirectoryPath(destination, "restore destination")
-                OliphauntAndroidNativeBridge.restoreNative(
-                    destination = destination,
-                    bytes = bytes,
-                    libraryPath =
-                    resolveAndroidLiboliphauntLibraryPath(
-                        explicitLibraryPath = libraryPath,
-                        nativeLibraryDirectory = appContext.applicationInfo.nativeLibraryDir,
-                        sourceArchivePaths = appContext.applicationInfo.liboliphauntSourceArchivePaths(),
-                        supportedAbis = Build.SUPPORTED_ABIS.asList(),
-                    ),
-                )
-            } finally {
-                owner.close()
-            }
+        validateDirectoryPath(destination, "restore destination")
+        nativeOperation {
+            dev.oliphaunt.bindings.restore(
+                destination = destination,
+                bytes = bytes,
+                libraryPath = resolveAndroidLiboliphauntLibraryPath(
+                    explicitLibraryPath = libraryPath,
+                    nativeLibraryDirectory = appContext.applicationInfo.nativeLibraryDir,
+                    sourceArchivePaths = appContext.applicationInfo.liboliphauntSourceArchivePaths(),
+                    supportedAbis = Build.SUPPORTED_ABIS.asList(),
+                ),
+            )
         }
     }
 }
@@ -527,320 +513,73 @@ private object AndroidDirectTemporaryStorage {
     }
 }
 
-internal fun newAndroidNativeOwnerDispatcher(name: String): ExecutorCoroutineDispatcher = Executors
-    .newSingleThreadExecutor { runnable ->
-        Thread(runnable, name).apply { isDaemon = true }
-    }.asCoroutineDispatcher()
-
-/**
- * Dispatches work without linking native ownership to caller cancellation.
- * Once admitted, a native operation reaches a definite result before its
- * continuation resumes, so handle transitions are never half-applied.
- */
-internal suspend fun  runOnAndroidNativeOwner(
-    dispatcher: ExecutorCoroutineDispatcher,
-    operation: () -> T,
-): T = suspendCoroutine { continuation ->
-    val task = Runnable { continuation.resumeWith(runCatching(operation)) }
-    try {
-        dispatcher.executor.execute(task)
-    } catch (error: Throwable) {
-        continuation.resumeWith(Result.failure(error))
-    }
-}
-
-internal fun interface AndroidNativeCleanable {
-    fun clean()
-}
-
-/**
- * Android's supported API floor predates `java.lang.ref.Cleaner`. This small
- * phantom-reference registry provides the same one-shot reachability signal
- * without finalizers. Cleanup actions must only enqueue work: its daemon must
- * never perform a blocking native close itself.
- */
-internal object AndroidNativeCleaner {
-    private val queue = ReferenceQueue()
-    private val references = ConcurrentHashMap()
-
-    init {
-        Thread(
-            cleanerLoop@{
-                while (true) {
-                    try {
-                        (queue.remove() as CleanupReference).clean()
-                    } catch (_: InterruptedException) {
-                        Thread.currentThread().interrupt()
-                        return@cleanerLoop
-                    } catch (_: Throwable) {
-                        // Best-effort forgotten-handle cleanup must not stop
-                        // cleanup for later unreachable sessions.
-                    }
-                }
-            },
-            "oliphaunt-android-cleaner",
-        ).apply {
-            isDaemon = true
-            start()
-        }
-    }
-
-    fun register(
-        owner: Any,
-        cleanup: () -> Unit,
-    ): AndroidNativeCleanable = CleanupReference(owner, cleanup).also { references[it] = Unit }
-
-    private class CleanupReference(
-        owner: Any,
-        cleanup: () -> Unit,
-    ) : PhantomReference(owner, queue),
-        AndroidNativeCleanable {
-        private val claimed = AtomicBoolean()
-        private var cleanup: (() -> Unit)? = cleanup
-
-        override fun clean() {
-            if (!claimed.compareAndSet(false, true)) return
-            references.remove(this)
-            clear()
-            val action = cleanup
-            cleanup = null
-            action?.invoke()
-        }
-    }
-}
-
-private object AndroidNativeCleanerFallbackOwner {
-    private val executor =
-        Executors.newSingleThreadExecutor { runnable ->
-            Thread(runnable, "oliphaunt-android-cleaner-fallback").apply { isDaemon = true }
-        }
-
-    fun execute(task: Runnable) {
-        executor.execute(task)
-    }
-}
-
-private class AndroidNativeDirectSession(
-    nativeHandle: Long,
-    executionDispatcher: ExecutorCoroutineDispatcher,
+internal class AndroidNativeDirectSession(
+    private val database: NativeDatabase,
 ) : OliphauntSession {
-    private val cancellationDispatcher =
-        newAndroidNativeOwnerDispatcher("oliphaunt-android-direct-cancel")
-    private val state =
-        AndroidNativeSessionState(
-            nativeHandle = nativeHandle,
-            executionDispatcher = executionDispatcher,
-            cancellationDispatcher = cancellationDispatcher,
-            closeNative = OliphauntAndroidNativeBridge::closeNative,
-        )
-    private val cleanable = AndroidNativeCleaner.register(this, state::scheduleForgottenClose)
-
-    override suspend fun execProtocolRaw(request: ByteArray): ByteArray = state.runOnExecutionOwner { current ->
-        OliphauntAndroidNativeBridge.execProtocolRawNative(current, request)
-    }
-
-    override suspend fun execProtocolRawStream(
-        request: ByteArray,
-        onChunk: (ByteArray) -> Unit,
-    ): ProtocolStreamOutcome = state.runOnExecutionOwner { current ->
-        var callbackError: Throwable? = null
-        val callbackAborted =
-            OliphauntAndroidNativeBridge.execProtocolRawStreamNative(
-                current,
-                request,
-                OliphauntAndroidProtocolStreamSink { chunk ->
-                    try {
-                        onChunk(chunk)
-                        0
-                    } catch (error: Throwable) {
-                        callbackError = error
-                        -1
-                    }
-                },
-            )
-        when {
-            !callbackAborted && callbackError == null -> ProtocolStreamOutcome.Complete
-
-            callbackAborted && callbackError != null ->
-                ProtocolStreamOutcome.CallbackAborted(requireNotNull(callbackError))
-
-            callbackAborted ->
-                throw OliphauntException(
-                    "liboliphaunt reported a recovered callback abort without a callback failure",
-                )
-
-            else ->
-                throw OliphauntException(
-                    "liboliphaunt returned protocol stream success after the callback failed",
-                )
+    private suspend fun  runRequest(block: suspend (dev.oliphaunt.bindings.NativeRequest) -> T): T {
+        val request = database.request()
+        // A child Job observes cancellation immediately, while the native
+        // future remains alive until its confirmed protocol outcome arrives.
+        val context = currentCoroutineContext()
+        val cancellation = Job(context[OliphauntOperationCancellation]?.caller ?: context[Job])
+        val cancellationFailure = AtomicReference()
+        val observer = cancellation.invokeOnCompletion { cause ->
+            if (cause != null) runCatching { request.cancel() }.exceptionOrNull()?.let(cancellationFailure::set)
         }
-    }
-
-    override suspend fun backup(): ByteArray = state.runOnExecutionOwner { current ->
-        OliphauntAndroidNativeBridge.backupNative(current)
-    }
-
-    override suspend fun cancel() {
-        state.runOnCancellationOwner { current ->
-            OliphauntAndroidNativeBridge.cancelNative(current)
-        }
-    }
-
-    override suspend fun close() {
-        state.close()
-        cleanable.clean()
-    }
-}
-
-internal class AndroidNativeSessionState(
-    nativeHandle: Long,
-    private val executionDispatcher: ExecutorCoroutineDispatcher,
-    private val cancellationDispatcher: ExecutorCoroutineDispatcher,
-    private val closeNative: (Long) -> Unit,
-) {
-    private val lock = ReentrantLock()
-    private val noActiveCalls = lock.newCondition()
-    private var handle: Long = nativeHandle
-    private var closing = false
-    private var closed = false
-    private var activeCalls = 0
-    private val forgottenCloseScheduled = AtomicBoolean()
-
-    suspend fun  runOnExecutionOwner(operation: (Long) -> T): T = runOnAndroidNativeOwner(executionDispatcher) {
-        val current = beginCall()
         try {
-            operation(current)
+            val result = withContext(NonCancellable) { block(request) }
+            cancellationFailure.get()?.let { throw OliphauntException("native cancellation failed", it) }
+            return result
+        } catch (_: NativeException.NotSubmitted) {
+            throw OliphauntRequestNotSubmitted()
+        } catch (error: NativeException.Database) {
+            throw OliphauntException(error.detail)
         } finally {
-            endCall()
+            observer.dispose()
+            cancellation.complete()
+            request.destroy()
         }
     }
 
-    suspend fun  runOnCancellationOwner(operation: (Long) -> T): T = runOnAndroidNativeOwner(cancellationDispatcher) {
-        val current = beginCall()
-        try {
-            operation(current)
-        } finally {
-            endCall()
-        }
-    }
-
-    suspend fun close() {
-        runOnAndroidNativeOwner(executionDispatcher) {
-            val current = beginClose() ?: return@runOnAndroidNativeOwner
-            try {
-                closeNative(current)
-                finishClose(detached = true)
-                cancellationDispatcher.close()
-                executionDispatcher.close()
-            } catch (error: Throwable) {
-                finishClose(detached = false)
-                throw error
-            }
-        }
-    }
-
-    /** Schedules best-effort close behind every operation already on the owner. */
-    fun scheduleForgottenClose() {
-        if (!forgottenCloseScheduled.compareAndSet(false, true)) return
-        val task = Runnable { closeForgottenBestEffort() }
-        try {
-            executionDispatcher.executor.execute(task)
-        } catch (_: Throwable) {
-            if (!isClosed()) AndroidNativeCleanerFallbackOwner.execute(task)
-        }
-    }
+    override suspend fun execProtocolRaw(request: ByteArray): ByteArray = runRequest { it.execute(request) }
 
-    private fun closeForgottenBestEffort() {
-        try {
-            val current = beginClose() ?: return
+    override suspend fun execProtocolRawStream(
+        request: ByteArray,
+        onChunk: (ByteArray) -> Unit,
+    ): ProtocolStreamOutcome {
+        val callbackError = AtomicReference()
+        val deliver = onChunk
+        return runRequest { operation ->
             try {
-                closeNative(current)
-                finishClose(detached = true)
-            } catch (_: Throwable) {
-                finishClose(detached = false)
-            }
-        } finally {
-            cancellationDispatcher.close()
-            executionDispatcher.close()
-        }
-    }
-
-    private fun isClosed(): Boolean {
-        lock.lock()
-        return try {
-            closed || handle == 0L
-        } finally {
-            lock.unlock()
-        }
-    }
-
-    private fun beginCall(): Long {
-        lock.lock()
-        try {
-            checkOpen()
-            activeCalls += 1
-            return handle
-        } finally {
-            lock.unlock()
-        }
-    }
-
-    private fun endCall() {
-        lock.lock()
-        try {
-            activeCalls -= 1
-            noActiveCalls.signalAll()
-        } finally {
-            lock.unlock()
-        }
-    }
-
-    private fun beginClose(): Long? {
-        lock.lock()
-        try {
-            if (closed) {
-                return null
-            }
-            if (closing) {
-                throw OliphauntException("database close is already in progress")
-            }
-            closing = true
-            val current = handle.takeIf { it != 0L }
-            while (activeCalls > 0) {
-                try {
-                    noActiveCalls.await()
-                } catch (error: InterruptedException) {
-                    closing = false
-                    noActiveCalls.signalAll()
-                    Thread.currentThread().interrupt()
-                    throw OliphauntException("interrupted while closing database")
-                }
+                operation.stream(
+                    request,
+                    object : ChunkSink {
+                        override fun onChunk(bytes: ByteArray): Boolean = try {
+                            deliver(bytes)
+                            true
+                        } catch (error: Throwable) {
+                            callbackError.set(error)
+                            false
+                        }
+                    },
+                )
+                ProtocolStreamOutcome.Complete
+            } catch (error: NativeException.Callback) {
+                // Rust only returns Callback after recovery reaches ReadyForQuery.
+                ProtocolStreamOutcome.CallbackAborted(callbackError.get() ?: throw error)
             }
-            return current
-        } finally {
-            lock.unlock()
         }
     }
 
-    private fun finishClose(detached: Boolean) {
-        lock.lock()
-        try {
-            if (detached) {
-                handle = 0
-                closed = true
-            }
-            closing = false
-            noActiveCalls.signalAll()
-        } finally {
-            lock.unlock()
-        }
-    }
+    override suspend fun backup(): ByteArray = nativeOperation { database.backup() }
+    override suspend fun cancel() = nativeOperation { database.cancel() }
+    override suspend fun close() = nativeOperation { database.detach() }
+}
 
-    private fun checkOpen() {
-        if (closing || closed || handle == 0L) {
-            throw OliphauntException("database is closed")
-        }
-    }
+private suspend fun  nativeOperation(block: suspend () -> T): T = try {
+    block()
+} catch (error: NativeException.Database) {
+    throw OliphauntException(error.detail)
 }
 
 internal fun resolveAndroidLiboliphauntLibraryPath(
diff --git a/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroidNativeBridge.kt b/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroidNativeBridge.kt
deleted file mode 100644
index 862021887..000000000
--- a/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroidNativeBridge.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package dev.oliphaunt
-
-internal object OliphauntAndroidNativeBridge {
-    init {
-        System.loadLibrary("oliphaunt_kotlin_android")
-    }
-
-    external fun openNative(
-        libraryPath: String?,
-        pgdata: String,
-        runtimeDirectory: String,
-        username: String,
-        database: String,
-        startupArgs: Array,
-    ): Long
-
-    external fun execProtocolRawNative(
-        handle: Long,
-        request: ByteArray,
-    ): ByteArray
-
-    external fun execProtocolRawStreamNative(
-        handle: Long,
-        request: ByteArray,
-        sink: OliphauntAndroidProtocolStreamSink,
-    ): Boolean
-
-    external fun backupNative(handle: Long): ByteArray
-
-    external fun restoreNative(
-        destination: String,
-        bytes: ByteArray,
-        libraryPath: String?,
-    )
-
-    external fun cancelNative(handle: Long)
-
-    external fun closeNative(handle: Long)
-}
-
-internal fun interface OliphauntAndroidProtocolStreamSink {
-    fun onChunk(chunk: ByteArray): Int
-}
diff --git a/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssets.kt b/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssets.kt
index 9f3875549..dc1101ab5 100644
--- a/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssets.kt
+++ b/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssets.kt
@@ -99,8 +99,6 @@ internal fun removeAndroidStagingIfPresent(staging: File) {
 
 internal object OliphauntAndroidRuntimeAssets {
     private const val RUNTIME_ASSET_ROOT = "oliphaunt/runtime"
-    private const val CARRIER_MANIFEST_ASSET = "oliphaunt/manifest.properties"
-    private const val CARRIER_SCHEMA = "oliphaunt-native-runtime-carrier-v1"
     private const val CLUSTER_SEED_TARGET = "android-datum64"
     private const val CLUSTER_SEED_COMPATIBILITY_KEY = "native-pg18-android-datum64-v1"
     private const val STANDARD_CLUSTER_SEED_ASSET_ROOT = "oliphaunt/cluster-seed"
@@ -190,18 +188,6 @@ internal object OliphauntAndroidRuntimeAssets {
             )
         }
 
-        if (resourceRoot == null) {
-            validateCarrierReceipt(
-                context.assets
-                    .open(CARRIER_MANIFEST_ASSET)
-                    .bufferedReader()
-                    .use { it.readText() },
-                CARRIER_MANIFEST_ASSET,
-            )
-        } else {
-            val receipt = File(resourceRoot, CARRIER_MANIFEST_ASSET)
-            validateCarrierReceipt(receipt.readText(), receipt.absolutePath)
-        }
         val standardClusterSeed =
             if (resourceRoot == null) {
                 packageManifestOrNull(context.assets, STANDARD_CLUSTER_SEED_ASSET_ROOT)
@@ -268,7 +254,7 @@ internal object OliphauntAndroidRuntimeAssets {
         runtime: OliphauntAndroidAssetPackage?,
         standard: OliphauntAndroidAssetPackage?,
         icu: OliphauntAndroidAssetPackage?,
-    ): OliphauntAndroidAssetPackage {
+    ): OliphauntAndroidAssetPackage? {
         val resolvedRuntime =
             runtime
                 ?: throw OliphauntException("Kotlin Android Oliphaunt runtime resources are not present")
@@ -280,9 +266,7 @@ internal object OliphauntAndroidRuntimeAssets {
         val profile = if ("icu" in resolvedRuntime.runtimeFeatures) "icu" else "standard"
         val selected =
             (if (profile == "icu") icu else standard)
-                ?: throw OliphauntException(
-                    "Kotlin Android Oliphaunt runtime resources are missing the $profile cluster seed for $CLUSTER_SEED_TARGET",
-                )
+                ?: return null
         if (profile == "icu" && resolvedRuntime.icuDataTreeSha256 != selected.icuDataTreeSha256) {
             throw OliphauntException(
                 "Kotlin Android Oliphaunt ICU data does not match the $CLUSTER_SEED_TARGET ICU cluster seed",
@@ -291,7 +275,7 @@ internal object OliphauntAndroidRuntimeAssets {
         return selected
     }
 
-    private fun matchingReleaseShapedClusterSeed(runtime: OliphauntAndroidAssetPackage): OliphauntAndroidAssetPackage {
+    private fun matchingReleaseShapedClusterSeed(runtime: OliphauntAndroidAssetPackage): OliphauntAndroidAssetPackage? {
         val resourceRoot =
             runtime.resourceRoot
                 ?: throw OliphauntException("release-shaped Android runtime resources have no resource root")
@@ -373,6 +357,15 @@ internal object OliphauntAndroidRuntimeAssets {
     ): AndroidPgdataPublication {
         validateCompleteAndroidPgdata(staging)
         if (isCompleteAndroidPgdata(destination)) return AndroidPgdataPublication.Existing
+        if (!staging.setReadable(false, false) ||
+            !staging.setWritable(false, false) ||
+            !staging.setExecutable(false, false) ||
+            !staging.setReadable(true, true) ||
+            !staging.setWritable(true, true) ||
+            !staging.setExecutable(true, true)
+        ) {
+            throw OliphauntException("failed to make PGDATA private at ${staging.absolutePath}")
+        }
         syncPublicationTree(staging)
 
         if (destination.exists()) {
@@ -515,30 +508,6 @@ internal object OliphauntAndroidRuntimeAssets {
         return properties
     }
 
-    private fun validateCarrierReceipt(
-        text: String,
-        source: String,
-    ) {
-        val properties = parseManifestText(text, source)
-        val expected =
-            setOf(
-                "schema",
-                "clusterSeedTarget",
-                "clusterSeedRelativePath",
-                "icuClusterSeedRelativePath",
-            )
-        if (properties.stringPropertyNames() != expected ||
-            properties.getProperty("schema") != CARRIER_SCHEMA ||
-            properties.getProperty("clusterSeedTarget") != CLUSTER_SEED_TARGET ||
-            properties.getProperty("clusterSeedRelativePath") != "cluster-seed" ||
-            properties.getProperty("icuClusterSeedRelativePath") != "cluster-seed-icu"
-        ) {
-            throw OliphauntException(
-                "Oliphaunt runtime carrier $source does not contain the exact $CLUSTER_SEED_TARGET seed receipt",
-            )
-        }
-    }
-
     internal fun parseManifestProperties(
         assetRoot: String,
         properties: Properties,
@@ -1133,9 +1102,6 @@ internal object OliphauntAndroidRuntimeAssets {
         if (filesDir.canonicalPathOrAbsolute() != expectedFiles.canonicalPathOrAbsolute()) {
             return null
         }
-        val receipt = File(resourceRoot, CARRIER_MANIFEST_ASSET)
-        if (!receipt.isFile) return null
-        validateCarrierReceipt(receipt.readText(), receipt.absolutePath)
         return filePackageManifestOrNull(resourceRoot, RUNTIME_ASSET_ROOT)
     }
 
diff --git a/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntJava.kt b/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntJava.kt
new file mode 100644
index 000000000..2825f5fbd
--- /dev/null
+++ b/src/sdks/kotlin/oliphaunt/src/androidMain/kotlin/dev/oliphaunt/OliphauntJava.kt
@@ -0,0 +1,28 @@
+package dev.oliphaunt
+
+import android.content.Context
+import kotlinx.coroutines.runBlocking
+
+/** Blocking Java access to the Kotlin SDK. Invoke on application worker threads. */
+public object OliphauntJava {
+    @JvmStatic
+    @JvmOverloads
+    public fun open(context: Context, config: OliphauntConfig = OliphauntConfig()): BlockingOliphauntDatabase = BlockingOliphauntDatabase(runBlocking { Oliphaunt.open(context, config) })
+}
+
+/** Owns the same native session as [OliphauntDatabase] and supports try-with-resources. */
+public class BlockingOliphauntDatabase internal constructor(private val database: OliphauntDatabase) : AutoCloseable {
+    @JvmOverloads
+    public fun execute(sql: String, parameters: List = emptyList()): CommandResult = runBlocking { database.execute(sql, parameters) }
+
+    @JvmOverloads
+    public fun query(sql: String, parameters: List = emptyList()): QueryResult = runBlocking { database.query(sql, parameters) }
+
+    public fun exec(sql: String): ExecResult = runBlocking { database.exec(sql) }
+
+    public fun backup(): ByteArray = runBlocking { database.backup() }
+
+    public fun cancel(): Unit = runBlocking { database.cancel() }
+
+    override fun close(): Unit = runBlocking { database.close() }
+}
diff --git a/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/AndroidNativeOwnerTest.kt b/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/AndroidNativeOwnerTest.kt
deleted file mode 100644
index 157cf089c..000000000
--- a/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/AndroidNativeOwnerTest.kt
+++ /dev/null
@@ -1,138 +0,0 @@
-package dev.oliphaunt
-
-import kotlinx.coroutines.CoroutineStart
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.atomic.AtomicInteger
-import java.util.concurrent.atomic.AtomicReference
-import kotlin.test.Test
-import kotlin.test.assertEquals
-import kotlin.test.assertNotEquals
-import kotlin.test.assertTrue
-
-class AndroidNativeOwnerTest {
-    @Test
-    fun ownerUsesOneDedicatedThreadInsteadOfTheCallerThread() = runBlocking {
-        val caller = Thread.currentThread()
-        val owner = newAndroidNativeOwnerDispatcher("oliphaunt-owner-test")
-        try {
-            val threads =
-                List(8) {
-                    async { runOnAndroidNativeOwner(owner) { Thread.currentThread() } }
-                }.awaitAll()
-
-            assertEquals(1, threads.toSet().size)
-            assertNotEquals(caller, threads.first())
-        } finally {
-            owner.close()
-        }
-    }
-
-    @Test
-    fun admittedOwnerWorkFinishesAfterCallerCancellation() = runBlocking {
-        val owner = newAndroidNativeOwnerDispatcher("oliphaunt-owner-cancel-test")
-        val started = CountDownLatch(1)
-        val release = CountDownLatch(1)
-        val finished = CountDownLatch(1)
-        try {
-            val caller =
-                launch(start = CoroutineStart.UNDISPATCHED) {
-                    runOnAndroidNativeOwner(owner) {
-                        started.countDown()
-                        release.await()
-                        finished.countDown()
-                    }
-                }
-
-            assertTrue(started.await(5, TimeUnit.SECONDS))
-            caller.cancel()
-            release.countDown()
-            assertTrue(finished.await(5, TimeUnit.SECONDS))
-            caller.join()
-        } finally {
-            owner.close()
-        }
-    }
-
-    @Test
-    fun forgottenHandleCleanupIsOneShotAndRunsOnTheOwner() {
-        val executionOwner = newAndroidNativeOwnerDispatcher("oliphaunt-owner-cleaner-test")
-        val cancellationOwner = newAndroidNativeOwnerDispatcher("oliphaunt-owner-cleaner-cancel-test")
-        val callerThread = Thread.currentThread().name
-        val closeThread = AtomicReference()
-        val closeCount = AtomicInteger()
-        val closed = CountDownLatch(1)
-        val state =
-            AndroidNativeSessionState(
-                nativeHandle = 42,
-                executionDispatcher = executionOwner,
-                cancellationDispatcher = cancellationOwner,
-                closeNative = {
-                    closeThread.set(Thread.currentThread().name)
-                    closeCount.incrementAndGet()
-                    closed.countDown()
-                },
-            )
-
-        state.scheduleForgottenClose()
-        state.scheduleForgottenClose()
-
-        assertTrue(closed.await(5, TimeUnit.SECONDS))
-        assertEquals(1, closeCount.get())
-        assertNotEquals(callerThread, closeThread.get())
-    }
-
-    @Test
-    fun cleanerRegistrationClaimsItsActionOnlyOnce() {
-        val calls = AtomicInteger()
-        val cleanable = AndroidNativeCleaner.register(Any()) { calls.incrementAndGet() }
-
-        cleanable.clean()
-        cleanable.clean()
-
-        assertEquals(1, calls.get())
-    }
-
-    @Test
-    fun forgottenHandleCleanupDrainsPreviouslyAdmittedOwnerWork() = runBlocking {
-        val executionOwner = newAndroidNativeOwnerDispatcher("oliphaunt-owner-cleaner-order-test")
-        val cancellationOwner = newAndroidNativeOwnerDispatcher("oliphaunt-owner-cleaner-order-cancel-test")
-        val operationStarted = CountDownLatch(1)
-        val operationRelease = CountDownLatch(1)
-        val closed = CountDownLatch(1)
-        val events = mutableListOf()
-        val state =
-            AndroidNativeSessionState(
-                nativeHandle = 42,
-                executionDispatcher = executionOwner,
-                cancellationDispatcher = cancellationOwner,
-                closeNative = {
-                    events += "close"
-                    closed.countDown()
-                },
-            )
-
-        val operation =
-            launch(start = CoroutineStart.UNDISPATCHED) {
-                state.runOnExecutionOwner {
-                    events += "operation"
-                    operationStarted.countDown()
-                    operationRelease.await()
-                    events += "operation-finished"
-                }
-            }
-        assertTrue(operationStarted.await(5, TimeUnit.SECONDS))
-
-        state.scheduleForgottenClose()
-        assertEquals(1L, closed.count)
-        operationRelease.countDown()
-
-        operation.join()
-        assertTrue(closed.await(5, TimeUnit.SECONDS))
-        assertEquals(listOf("operation", "operation-finished", "close"), events)
-    }
-}
diff --git a/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/NativeBindingsTest.kt b/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/NativeBindingsTest.kt
new file mode 100644
index 000000000..027b41023
--- /dev/null
+++ b/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/NativeBindingsTest.kt
@@ -0,0 +1,80 @@
+package dev.oliphaunt
+
+import dev.oliphaunt.bindings.NativeDatabase
+import dev.oliphaunt.bindings.OpenOptions
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.json.JSONObject
+import org.junit.Assume.assumeTrue
+import java.io.File
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+class NativeBindingsTest {
+    @Test
+    fun generatedBridgePreservesTypedQueriesCancellationAndRecovery() = runBlocking {
+        val pgdata = System.getenv("OLIPHAUNT_MOBILE_TEST_PGDATA")
+        assumeTrue("requires a prepared native database", pgdata != null)
+        val descriptor = File(File(requireNotNull(pgdata)).parentFile, ".oliphaunt.json")
+        if (!descriptor.exists()) {
+            val fixture = JSONObject(File(System.getProperty("oliphaunt.sharedFixturesDir"), "storage/database-root.json").readText())
+            val descriptors = fixture.getJSONArray("validDescriptors")
+            val native = (0 until descriptors.length()).map(descriptors::getJSONObject)
+                .first { it.getString("engineFamily") == "native" }
+            descriptor.writeText("$native\n")
+        }
+        System.setProperty("jna.library.path", System.getenv("OLIPHAUNT_MOBILE_BINDINGS_DIR"))
+        val native = NativeDatabase.open(
+            OpenOptions(
+                System.getenv("LIBOLIPHAUNT_PATH"),
+                requireNotNull(pgdata),
+                System.getenv("OLIPHAUNT_INSTALL_DIR"),
+                System.getenv("OLIPHAUNT_EMBEDDED_MODULE_DIR"),
+                null,
+                "postgres",
+                "postgres",
+                emptyList(),
+            ),
+        )
+        val database = OliphauntDatabase.open(
+            EngineConfig(),
+            object : OliphauntEngine {
+                override suspend fun open(config: EngineConfig): OliphauntSession = AndroidNativeDirectSession(native)
+                override suspend fun restore(destination: String, bytes: ByteArray) = dev.oliphaunt.bindings.restore(System.getenv("LIBOLIPHAUNT_PATH"), destination, bytes)
+            },
+        )
+        try {
+            assertEquals("42", database.query("SELECT 42").rows.single().text(0))
+            val sleeping = launch { runCatching { database.query("SELECT pg_sleep(60)") } }
+            delay(100)
+            val start = System.nanoTime()
+            sleeping.cancelAndJoin()
+            assertTrue(System.nanoTime() - start < 3_000_000_000)
+            assertEquals("7", database.query("SELECT 7").rows.single().text(0))
+            val transaction = launch {
+                runCatching { database.transaction { it.query("SELECT pg_sleep(60)") } }
+            }
+            delay(100)
+            transaction.cancelAndJoin()
+            assertEquals("7", database.query("SELECT 7").rows.single().text(0))
+            // Coroutine debug stack recovery may copy standard exception types.
+            // An application exception with state must retain its identity.
+            class CallbackFailure(val marker: Any) : RuntimeException("stop rows")
+            val callbackFailure = CallbackFailure(Any())
+            val failure = runCatching {
+                database.execProtocolRawStream(simpleQueryProtocol("SELECT generate_series(1, 1000)")) {
+                    throw callbackFailure
+                }
+            }.exceptionOrNull()
+            assertTrue(failure === callbackFailure, "callback failure changed to $failure")
+            assertEquals("8", database.query("SELECT 8").rows.single().text(0))
+            assertTrue(database.backup().isNotEmpty())
+        } finally {
+            database.close()
+            native.destroy()
+        }
+    }
+}
diff --git a/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssetsTest.kt b/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssetsTest.kt
index 6810e8319..a93fe4ace 100644
--- a/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssetsTest.kt
+++ b/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssetsTest.kt
@@ -510,6 +510,10 @@ class OliphauntAndroidRuntimeAssetsTest {
             assertEquals(AndroidPgdataPublication.Published, publication)
             assertTrue(didPublish)
             assertFalse(staging.exists())
+            assertEquals(
+                java.nio.file.attribute.PosixFilePermissions.fromString("rwx------"),
+                Files.getPosixFilePermissions(destination.toPath()),
+            )
             validateCompleteAndroidPgdata(destination)
         } finally {
             parent.deleteRecursively()
@@ -1167,20 +1171,11 @@ class OliphauntAndroidRuntimeAssetsTest {
 }
 
 private fun databaseRootFixture(): JSONObject {
-    val configured =
-        System
-            .getProperty("oliphaunt.sharedFixturesDir")
-            ?.takeIf(String::isNotBlank)
-            ?.let { Path.of(it, "storage", "database-root.json") }
-    val cwd = Path.of("").toAbsolutePath()
-    val fixture =
-        listOfNotNull(
-            configured,
-            cwd.resolve("src/shared/fixtures/storage/database-root.json").normalize(),
-            cwd.resolve("../../shared/fixtures/storage/database-root.json").normalize(),
-        ).firstOrNull(Files::isRegularFile)
-    checkNotNull(fixture) { "shared database-root fixture was not found from the repository checkout" }
-    return JSONObject(fixture.toFile().readText())
+    val directory =
+        checkNotNull(System.getProperty("oliphaunt.sharedFixturesDir")?.takeIf(String::isNotBlank)) {
+            "Run fixture tests through Gradle to configure oliphaunt.sharedFixturesDir"
+        }
+    return JSONObject(Path.of(directory, "storage", "database-root.json").toFile().readText())
 }
 
 private fun manifestProperties(vararg entries: Pair): Properties = Properties().apply {
@@ -1264,12 +1259,6 @@ private fun writeReleaseShapedRuntime(
 ): java.io.File {
     val oliphauntRoot = resourceRoot.resolve("oliphaunt")
     oliphauntRoot.mkdirs()
-    oliphauntRoot.resolve("manifest.properties").writeText(
-        "schema=oliphaunt-native-runtime-carrier-v1\n" +
-            "clusterSeedTarget=android-datum64\n" +
-            "clusterSeedRelativePath=cluster-seed\n" +
-            "icuClusterSeedRelativePath=cluster-seed-icu\n",
-    )
     writeTestClusterSeed(oliphauntRoot.resolve("cluster-seed"), "standard", "")
     writeTestClusterSeed(oliphauntRoot.resolve("cluster-seed-icu"), "icu", "a".repeat(64))
     val runtimeRoot = oliphauntRoot.resolve("runtime")
diff --git a/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntJavaTest.kt b/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntJavaTest.kt
new file mode 100644
index 000000000..c6a9f9318
--- /dev/null
+++ b/src/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntJavaTest.kt
@@ -0,0 +1,36 @@
+package dev.oliphaunt
+
+import kotlinx.coroutines.runBlocking
+import kotlin.test.Test
+import kotlin.test.assertContentEquals
+import kotlin.test.assertEquals
+
+class OliphauntJavaTest {
+    @Test
+    fun blockingFacadeOwnsTheSessionAndSupportsUse() {
+        var closed = 0
+        var cancelled = 0
+        val session = object : OliphauntSession {
+            override suspend fun execProtocolRaw(request: ByteArray): ByteArray = error("unused")
+            override suspend fun execProtocolRawStream(request: ByteArray, onChunk: (ByteArray) -> Unit): ProtocolStreamOutcome = error("unused")
+            override suspend fun backup(): ByteArray = byteArrayOf(1, 2, 3)
+            override suspend fun cancel() {
+                cancelled++
+            }
+            override suspend fun close() {
+                closed++
+            }
+        }
+        val engine = object : OliphauntEngine {
+            override suspend fun open(config: EngineConfig): OliphauntSession = session
+            override suspend fun restore(destination: String, bytes: ByteArray): Unit = error("unused")
+        }
+        val database = runBlocking { OliphauntDatabase.open(EngineConfig(), engine) }
+        BlockingOliphauntDatabase(database).use {
+            assertContentEquals(byteArrayOf(1, 2, 3), it.backup())
+            it.cancel()
+        }
+        assertEquals(1, cancelled)
+        assertEquals(1, closed)
+    }
+}
diff --git a/src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt b/src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt
index f4823459c..929af8cae 100644
--- a/src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt
+++ b/src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt
@@ -1,4 +1,4 @@
-// This file is generated by src/extensions/tools/check-extension-model.mjs.
+// This file is generated by src/extensions/tools/check-extension-model.sh.
 // Do not edit by hand.
 
 package dev.oliphaunt
diff --git a/src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/Oliphaunt.kt b/src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/Oliphaunt.kt
index 197f2357c..4048f0804 100644
--- a/src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/Oliphaunt.kt
+++ b/src/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/Oliphaunt.kt
@@ -138,6 +138,12 @@ internal interface OliphauntEngine {
     )
 }
 
+internal class OliphauntRequestNotSubmitted : kotlinx.coroutines.CancellationException("request was not submitted")
+
+internal class OliphauntOperationCancellation(val caller: kotlinx.coroutines.Job?) : kotlin.coroutines.AbstractCoroutineContextElement(Key) {
+    companion object Key : kotlin.coroutines.CoroutineContext.Key
+}
+
 internal interface OliphauntSession {
     suspend fun execProtocolRaw(request: ByteArray): ByteArray
 
@@ -848,6 +854,7 @@ public class OliphauntDatabase private constructor(
         transactionToken: Long?,
         error: Throwable,
     ) {
+        if (error is OliphauntRequestNotSubmitted) return
         val message =
             "typed operation outcome is unknown before a complete ReadyForQuery boundary; close and reopen the database: $error"
         stateMutex.withLock {
@@ -1007,6 +1014,7 @@ public class OliphauntDatabase private constructor(
     private suspend fun poisonUnknownRawProtocolOperation(
         error: Throwable,
     ) {
+        if (error is OliphauntRequestNotSubmitted) return
         val message =
             "raw protocol operation outcome is unknown before confirmed recovery; " +
                 "close and reopen the database: $error"
@@ -1091,8 +1099,9 @@ public class OliphauntDatabase private constructor(
             throw error
         }
 
+        val cancellation = OliphauntOperationCancellation(currentCoroutineContext()[kotlinx.coroutines.Job])
         val result =
-            withContext(NonCancellable) {
+            withContext(NonCancellable + cancellation) {
                 try {
                     operation()
                 } finally {
diff --git a/src/sdks/kotlin/oliphaunt/src/jvmTest/kotlin/dev/oliphaunt/SharedProtocolFixtureTest.kt b/src/sdks/kotlin/oliphaunt/src/jvmTest/kotlin/dev/oliphaunt/SharedProtocolFixtureTest.kt
index ed2d07911..f2c602dd9 100644
--- a/src/sdks/kotlin/oliphaunt/src/jvmTest/kotlin/dev/oliphaunt/SharedProtocolFixtureTest.kt
+++ b/src/sdks/kotlin/oliphaunt/src/jvmTest/kotlin/dev/oliphaunt/SharedProtocolFixtureTest.kt
@@ -20,7 +20,7 @@ import kotlin.test.assertTrue
 class SharedProtocolFixtureTest {
     @Test
     fun structuredSqlScannerMatchesSharedFixtures() {
-        val path = sharedStructuredSqlFixturePath() ?: return
+        val path = sharedProtocolFixturePath("structured-sql-cases.json")
         val corpus = Json.parseToJsonElement(Files.readString(path)).jsonObject
         assertEquals(2, corpus.requiredInt("schemaVersion"))
         assertEquals("postgres-structured-sql-preflight", corpus.requiredString("kind"))
@@ -45,7 +45,7 @@ class SharedProtocolFixtureTest {
 
     @Test
     fun queryParserMatchesSharedProtocolFixtures() {
-        val path = sharedProtocolFixturePath() ?: return
+        val path = sharedProtocolFixturePath("query-response-cases.json")
         val corpus = Json.parseToJsonElement(Files.readString(path)).jsonObject
         assertEquals(1, corpus.requiredInt("schemaVersion"))
         assertEquals("postgres-backend-query-response", corpus.requiredString("kind"))
@@ -146,34 +146,12 @@ class SharedProtocolFixtureTest {
     }
 }
 
-private fun sharedProtocolFixturePath(): Path? {
-    val configured =
-        System
-            .getProperty("oliphaunt.sharedFixturesDir")
-            ?.takeIf(String::isNotBlank)
-            ?.let { Path.of(it, "protocol", "query-response-cases.json") }
-    val cwdCandidate =
-        Path
-            .of("")
-            .toAbsolutePath()
-            .resolve("../../shared/fixtures/protocol/query-response-cases.json")
-            .normalize()
-    return listOfNotNull(configured, cwdCandidate).firstOrNull(Files::isRegularFile)
-}
-
-private fun sharedStructuredSqlFixturePath(): Path? {
-    val configured =
-        System
-            .getProperty("oliphaunt.sharedFixturesDir")
-            ?.takeIf(String::isNotBlank)
-            ?.let { Path.of(it, "protocol", "structured-sql-cases.json") }
-    val cwdCandidate =
-        Path
-            .of("")
-            .toAbsolutePath()
-            .resolve("../../shared/fixtures/protocol/structured-sql-cases.json")
-            .normalize()
-    return listOfNotNull(configured, cwdCandidate).firstOrNull(Files::isRegularFile)
+private fun sharedProtocolFixturePath(name: String): Path {
+    val directory =
+        checkNotNull(System.getProperty("oliphaunt.sharedFixturesDir")?.takeIf(String::isNotBlank)) {
+            "Run fixture tests through Gradle to configure oliphaunt.sharedFixturesDir"
+        }
+    return Path.of(directory, "protocol", name)
 }
 
 private fun parseFixtures(cases: JsonArray): List = cases.map { element ->
diff --git a/src/sdks/kotlin/release.toml b/src/sdks/kotlin/release.toml
index 1957fde0d..42b5d3986 100644
--- a/src/sdks/kotlin/release.toml
+++ b/src/sdks/kotlin/release.toml
@@ -15,7 +15,6 @@ release_artifacts = [
   "maven-publication",
   "runtime-assets-external",
 ]
-derived_version_files = ["src/sdks/kotlin/oliphaunt/build.gradle.kts", "src/sdks/kotlin/oliphaunt-android-gradle-plugin/build.gradle.kts"]
 
 [compatibility_versions.oliphaunt-kotlin-liboliphaunt]
 source_product = "liboliphaunt-native"
diff --git a/src/sdks/kotlin/tests/public-api-consumer/src/main/java/dev/oliphaunt/consumer/JavaPublicApiConsumer.java b/src/sdks/kotlin/tests/public-api-consumer/src/main/java/dev/oliphaunt/consumer/JavaPublicApiConsumer.java
new file mode 100644
index 000000000..a8d7e2a0b
--- /dev/null
+++ b/src/sdks/kotlin/tests/public-api-consumer/src/main/java/dev/oliphaunt/consumer/JavaPublicApiConsumer.java
@@ -0,0 +1,17 @@
+package dev.oliphaunt.consumer;
+
+import android.content.Context;
+import dev.oliphaunt.OliphauntJava;
+
+/** Compile-only proof of Java overloads and ownership against the packaged AAR. */
+public final class JavaPublicApiConsumer {
+    public static void useDatabase(Context context) {
+        try (var database = OliphauntJava.open(context)) {
+            database.execute("CREATE TABLE items(value text)");
+            database.query("SELECT value FROM items");
+            database.exec("SELECT 1");
+            database.backup();
+            database.cancel();
+        }
+    }
+}
diff --git a/src/sdks/kotlin/tools/android-stream-completion-test.cpp b/src/sdks/kotlin/tools/android-stream-completion-test.cpp
deleted file mode 100644
index 40c2f9245..000000000
--- a/src/sdks/kotlin/tools/android-stream-completion-test.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "stream_completion.h"
-
-#include 
-
-using oliphaunt::android_bridge::StreamCompletion;
-using oliphaunt::android_bridge::classifyStreamCompletion;
-
-static_assert(classifyStreamCompletion(0, false) == StreamCompletion::Success);
-static_assert(
-    classifyStreamCompletion(OLIPHAUNT_STREAM_CALLBACK_ABORTED, true) ==
-    StreamCompletion::CallbackAborted);
-static_assert(
-    classifyStreamCompletion(-1, true) == StreamCompletion::NativeFailure);
-static_assert(
-    classifyStreamCompletion(-1, false) == StreamCompletion::NativeFailure);
-static_assert(
-    classifyStreamCompletion(0, true) ==
-    StreamCompletion::ProtocolInconsistency);
-static_assert(
-    classifyStreamCompletion(OLIPHAUNT_STREAM_CALLBACK_ABORTED, false) ==
-    StreamCompletion::ProtocolInconsistency);
-static_assert(
-    classifyStreamCompletion(2, true) ==
-    StreamCompletion::ProtocolInconsistency);
-
-int main() {
-  std::cout << "Kotlin Android stream completion precedence passed\n";
-  return 0;
-}
diff --git a/src/sdks/kotlin/tools/check-package.mts b/src/sdks/kotlin/tools/check-package.mts
new file mode 100644
index 000000000..39b35dd29
--- /dev/null
+++ b/src/sdks/kotlin/tools/check-package.mts
@@ -0,0 +1,71 @@
+#!/usr/bin/env bun
+import {
+  archiveZipNames,
+  fail,
+  inspectSdkProduct,
+  isDirectory,
+  rejectSdkRuntimePayload,
+  rel,
+  walkFiles,
+} from '../../../../tools/packaging/release-carrier.mts';
+import { compareText } from '../../../../tools/release/release-artifact-targets.mts';
+import path from 'node:path';
+import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts';
+import { assertRustDependencyLicensesInEntries } from '../../rust/mobile-bindings/tools/dependency-license-contract.mts';
+
+const KOTLIN_RELEASE_ABIS = new Set(['arm64-v8a', 'x86_64']);
+
+function validateKotlinAndroidAar(artifact, names) {
+  const presentAbis = new Set(
+    names
+      .map((name) => name.split('/'))
+      .filter(
+        (parts) =>
+          parts.length === 3 &&
+          parts[0] === 'jni' &&
+          parts[2] === 'liboliphaunt_mobile_bindings.so',
+      )
+      .map((parts) => parts[1]),
+  );
+  if (
+    presentAbis.size !== KOTLIN_RELEASE_ABIS.size ||
+    [...presentAbis].some((abi) => !KOTLIN_RELEASE_ABIS.has(abi))
+  ) {
+    fail(
+      `Kotlin Android release AAR ${rel(artifact)} must contain generated native bindings for ` +
+        `${[...KOTLIN_RELEASE_ABIS].sort(compareText).join(', ')}; got ${[...presentAbis].sort(compareText).join(', ') || '(none)'}`,
+    );
+  }
+}
+
+export async function checkKotlinPackage(root) {
+  const product = 'oliphaunt-kotlin';
+  let checked = false;
+
+  const mavenRoot = path.join(root, 'maven');
+  if (!isDirectory(mavenRoot)) {
+    fail(`${product} must stage a Maven repository under ${rel(mavenRoot)}`);
+  }
+  for (const archive of walkFiles(root)
+    .filter((file) => file.endsWith('.aar') || file.endsWith('.jar'))
+    .sort(compareText)) {
+    const names = archiveZipNames(archive);
+    rejectSdkRuntimePayload(product, archive, names);
+    if (archive.endsWith('.aar')) {
+      validateKotlinAndroidAar(archive, names);
+      const entries = readPortableArchiveEntries(archive, { format: 'zip' });
+      for (const target of ['android-arm64', 'android-x86_64']) {
+        assertRustDependencyLicensesInEntries(entries, {
+          target,
+          prefix: `assets/oliphaunt-native-bindings/${target}`,
+          label: archive,
+        });
+      }
+    }
+    checked = true;
+  }
+
+  return checked;
+}
+
+if (import.meta.main) await inspectSdkProduct('oliphaunt-kotlin', checkKotlinPackage);
diff --git a/src/sdks/kotlin/tools/kotlin-maven-staging.mts b/src/sdks/kotlin/tools/kotlin-maven-staging.mts
new file mode 100644
index 000000000..af366449a
--- /dev/null
+++ b/src/sdks/kotlin/tools/kotlin-maven-staging.mts
@@ -0,0 +1,223 @@
+#!/usr/bin/env bun
+
+import { lstatSync, readdirSync, readFileSync, statSync } from 'node:fs';
+import path from 'node:path';
+
+import { validateMavenCentralPublication } from '../../../../tools/packaging/maven-central-contract.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../../../..');
+const TOOL = 'kotlin-maven-staging.mts';
+const PRODUCT = 'oliphaunt-kotlin';
+const DEFAULT_STAGING_ROOT = path.join(ROOT, 'target/sdk-artifacts/oliphaunt-kotlin/maven');
+const VERSION_TOKEN = /^[A-Za-z0-9_.-]+$/u;
+
+function error(message) {
+  return new Error(`${TOOL}: ${message}`);
+}
+
+function ordinalCompare(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function normalizedRelative(root, file) {
+  return path.relative(root, file).split(path.sep).join('/');
+}
+
+function repositoryRelative(file) {
+  const relative = path.relative(ROOT, file);
+  return relative.startsWith('..') ? file : relative.split(path.sep).join('/');
+}
+
+function requireDirectory(directory, label) {
+  let stat;
+  try {
+    stat = lstatSync(directory);
+  } catch (cause) {
+    throw error(`${label} is missing: ${cause.message}`);
+  }
+  if (!stat.isDirectory() || stat.isSymbolicLink()) {
+    throw error(`${label} must be a real non-symlink directory`);
+  }
+}
+
+function walkRegularFiles(root) {
+  const files = [];
+  const visit = (directory) => {
+    for (const entry of readdirSync(directory, { withFileTypes: true })) {
+      const file = path.join(directory, entry.name);
+      if (entry.isSymbolicLink()) {
+        throw error(`staged Maven repository must not contain symlink ${repositoryRelative(file)}`);
+      }
+      if (entry.isDirectory()) {
+        visit(file);
+      } else if (entry.isFile()) {
+        files.push(file);
+      } else {
+        throw error(
+          `staged Maven repository must contain only regular files and directories: ${repositoryRelative(file)}`,
+        );
+      }
+    }
+  };
+  visit(root);
+  return files.sort((left, right) =>
+    ordinalCompare(normalizedRelative(root, left), normalizedRelative(root, right)),
+  );
+}
+
+function coordinate(groupId, artifactId, version, packaging, companions) {
+  const directory = `${groupId.replaceAll('.', '/')}/${artifactId}/${version}`;
+  const prefix = `${artifactId}-${version}`;
+  return Object.freeze({
+    artifactId,
+    directory,
+    files: Object.freeze(companions.map((suffix) => `${directory}/${prefix}${suffix}`)),
+    groupId,
+    packaging,
+    version,
+  });
+}
+
+export function kotlinMavenCentralCoordinates(version) {
+  if (typeof version !== 'string' || !VERSION_TOKEN.test(version)) {
+    throw error(
+      `Kotlin product version must be a safe Maven token, got ${JSON.stringify(version)}`,
+    );
+  }
+  return Object.freeze([
+    coordinate('dev.oliphaunt', 'oliphaunt-android', version, 'aar', [
+      '.aar',
+      '.pom',
+      '-sources.jar',
+      '-javadoc.jar',
+    ]),
+    coordinate('dev.oliphaunt', 'oliphaunt-android-gradle-plugin', version, 'jar', [
+      '.jar',
+      '.pom',
+      '.module',
+      '-sources.jar',
+      '-javadoc.jar',
+    ]),
+    coordinate('dev.oliphaunt.android', 'dev.oliphaunt.android.gradle.plugin', version, 'pom', [
+      '.pom',
+    ]),
+  ]);
+}
+
+export function kotlinMavenCentralRelativeFiles(version) {
+  return kotlinMavenCentralCoordinates(version)
+    .flatMap(({ files }) => files)
+    .sort();
+}
+
+function localMetadataRelativeFiles(version) {
+  return kotlinMavenCentralCoordinates(version)
+    .map(({ directory }) => `${path.posix.dirname(directory)}/maven-metadata-local.xml`)
+    .sort();
+}
+
+export function currentKotlinProductVersion() {
+  const file = path.join(ROOT, 'src/sdks/kotlin/gradle.properties');
+  const versions = readFileSync(file, 'utf8')
+    .split(/\r?\n/u)
+    .map((line) => line.match(/^VERSION_NAME=(.+)$/u)?.[1]?.trim())
+    .filter(Boolean);
+  if (versions.length !== 1 || !VERSION_TOKEN.test(versions[0])) {
+    throw error(`${repositoryRelative(file)} must declare exactly one safe VERSION_NAME`);
+  }
+  return versions[0];
+}
+
+/**
+ * Validate the complete unsigned Maven Central input staged by the Kotlin SDK.
+ * Gradle's three maven-metadata-local.xml files are permitted because the
+ * producer uses publishToMavenLocal, but they are explicitly excluded from the
+ * immutable ten-file Central closure returned by this function.
+ */
+export function validateKotlinMavenStagingClosure(
+  root,
+  version,
+  { allowLocalMetadata = true, label = repositoryRelative(root) } = {},
+) {
+  const stagingRoot = path.resolve(root);
+  requireDirectory(stagingRoot, `${label} staged Maven repository`);
+
+  const coordinates = kotlinMavenCentralCoordinates(version);
+  const expected = new Set(kotlinMavenCentralRelativeFiles(version));
+  const permittedMetadata = new Set(allowLocalMetadata ? localMetadataRelativeFiles(version) : []);
+  const files = walkRegularFiles(stagingRoot);
+  const actual = new Map(files.map((file) => [normalizedRelative(stagingRoot, file), file]));
+  const missing = [...expected].filter((file) => !actual.has(file)).sort();
+  const unexpected = [...actual.keys()]
+    .filter((file) => !expected.has(file) && !permittedMetadata.has(file))
+    .sort();
+  if (missing.length > 0 || unexpected.length > 0) {
+    throw error(
+      `${label} must contain the exact ${expected.size}-file Maven Central companion closure; ` +
+        `missing=${JSON.stringify(missing)}, unexpected=${JSON.stringify(unexpected)}`,
+    );
+  }
+
+  for (const [relative, file] of actual) {
+    if (statSync(file).size <= 0) {
+      throw error(`${label} contains empty file ${relative}`);
+    }
+  }
+
+  for (const expectedCoordinate of coordinates) {
+    const pomRelative = expectedCoordinate.files.find((file) => file.endsWith('.pom'));
+    const pom = actual.get(pomRelative);
+    const publicationFiles = expectedCoordinate.files.map((relative) => {
+      const file = actual.get(relative);
+      return { name: path.basename(file), size: statSync(file).size };
+    });
+    const validated = validateMavenCentralPublication({
+      context: `${label}/${pomRelative}`,
+      files: publicationFiles,
+      pomText: readFileSync(pom, 'utf8'),
+    });
+    for (const field of ['artifactId', 'groupId', 'packaging', 'version']) {
+      if (validated[field] !== expectedCoordinate[field]) {
+        throw error(
+          `${label}/${pomRelative} ${field} must be ${expectedCoordinate[field]}, got ${validated[field]}`,
+        );
+      }
+    }
+  }
+
+  return Object.freeze({
+    coordinates: coordinates.map(({ artifactId, groupId, packaging }) => ({
+      artifactId,
+      groupId,
+      packaging,
+    })),
+    localMetadataFiles: [...actual.keys()].filter((file) => permittedMetadata.has(file)).sort(),
+    publicationFiles: [...expected].sort(),
+    root: stagingRoot,
+    version,
+  });
+}
+
+export function stagedKotlinMavenRepo({
+  root = DEFAULT_STAGING_ROOT,
+  version = currentKotlinProductVersion(),
+} = {}) {
+  const result = validateKotlinMavenStagingClosure(root, version);
+  console.log(
+    `validated exact ${result.publicationFiles.length}-file Kotlin Maven Central staging closure: ${repositoryRelative(result.root)}`,
+  );
+  return result.root;
+}
+
+if (import.meta.main) {
+  if (Bun.argv.length !== 2) {
+    console.error(`usage: ${TOOL}`);
+    process.exit(2);
+  }
+  try {
+    stagedKotlinMavenRepo();
+  } catch (cause) {
+    console.error(cause instanceof Error ? cause.message : String(cause));
+    process.exit(1);
+  }
+}
diff --git a/src/sdks/kotlin/tools/kotlin-maven-staging.test.mts b/src/sdks/kotlin/tools/kotlin-maven-staging.test.mts
new file mode 100644
index 000000000..81e65d178
--- /dev/null
+++ b/src/sdks/kotlin/tools/kotlin-maven-staging.test.mts
@@ -0,0 +1,125 @@
+import { afterEach, expect, test } from 'bun:test';
+import { mkdirSync, mkdtempSync, rmSync, unlinkSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+
+import {
+  kotlinMavenCentralCoordinates,
+  kotlinMavenCentralRelativeFiles,
+  validateKotlinMavenStagingClosure,
+} from './kotlin-maven-staging.mts';
+
+const VERSION = '1.2.3';
+const temporaryDirectories = [];
+
+function pom({ artifactId, groupId, packaging, version = VERSION }) {
+  return `
+
+  4.0.0
+  ${groupId}
+  ${artifactId}
+  ${version}
+  ${packaging}
+  Oliphaunt ${artifactId}
+  Exact Kotlin Maven staging fixture.
+  https://github.com/f0rr0/oliphaunt
+  MIThttps://opensource.org/license/mit
+  Oliphaunt Maintainershttps://github.com/f0rr0
+  
+    scm:git:https://github.com/f0rr0/oliphaunt.git
+    scm:git:ssh://git@github.com/f0rr0/oliphaunt.git
+    https://github.com/f0rr0/oliphaunt
+  
+
+`;
+}
+
+function write(relative, bytes, root) {
+  const file = path.join(root, ...relative.split('/'));
+  mkdirSync(path.dirname(file), { recursive: true });
+  writeFileSync(file, bytes);
+  return file;
+}
+
+function fixture({ localMetadata = true } = {}) {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-kotlin-maven-staging-'));
+  temporaryDirectories.push(root);
+  for (const coordinate of kotlinMavenCentralCoordinates(VERSION)) {
+    for (const relative of coordinate.files) {
+      write(
+        relative,
+        relative.endsWith('.pom') ? pom(coordinate) : `fixture ${path.basename(relative)}\n`,
+        root,
+      );
+    }
+    if (localMetadata) {
+      write(
+        `${path.posix.dirname(coordinate.directory)}/maven-metadata-local.xml`,
+        '\n',
+        root,
+      );
+    }
+  }
+  return root;
+}
+
+afterEach(() => {
+  while (temporaryDirectories.length > 0) {
+    rmSync(temporaryDirectories.pop(), { force: true, recursive: true });
+  }
+});
+
+test('validates the exact ten-file Kotlin Maven Central companion closure', () => {
+  const result = validateKotlinMavenStagingClosure(fixture(), VERSION);
+  expect(result.publicationFiles).toEqual(kotlinMavenCentralRelativeFiles(VERSION));
+  expect(result.publicationFiles).toHaveLength(10);
+  expect(result.coordinates).toEqual([
+    { artifactId: 'oliphaunt-android', groupId: 'dev.oliphaunt', packaging: 'aar' },
+    { artifactId: 'oliphaunt-android-gradle-plugin', groupId: 'dev.oliphaunt', packaging: 'jar' },
+    {
+      artifactId: 'dev.oliphaunt.android.gradle.plugin',
+      groupId: 'dev.oliphaunt.android',
+      packaging: 'pom',
+    },
+  ]);
+  expect(result.localMetadataFiles).toHaveLength(3);
+});
+
+test('rejects missing companions and undeclared staging files', () => {
+  const missing = fixture();
+  unlinkSync(path.join(missing, kotlinMavenCentralRelativeFiles(VERSION)[0]));
+  expect(() => validateKotlinMavenStagingClosure(missing, VERSION)).toThrow(
+    /exact 10-file.*missing=/u,
+  );
+
+  const unexpected = fixture();
+  write('dev/oliphaunt/oliphaunt-android/1.2.3/resolver.lock', 'forbidden\n', unexpected);
+  expect(() => validateKotlinMavenStagingClosure(unexpected, VERSION)).toThrow(
+    /unexpected=.*resolver[.]lock/u,
+  );
+});
+
+test('permits only the known local metadata outside the Central closure', () => {
+  const root = fixture();
+  expect(() =>
+    validateKotlinMavenStagingClosure(root, VERSION, { allowLocalMetadata: false }),
+  ).toThrow(/unexpected=.*maven-metadata-local[.]xml/u);
+
+  const withoutMetadata = fixture({ localMetadata: false });
+  expect(validateKotlinMavenStagingClosure(withoutMetadata, VERSION).localMetadataFiles).toEqual(
+    [],
+  );
+});
+
+test('validates each staged POM against the canonical Maven Central contract', () => {
+  const root = fixture();
+  const coordinate = kotlinMavenCentralCoordinates(VERSION)[0];
+  const pomFile = path.join(
+    root,
+    coordinate.files.find((file) => file.endsWith('.pom')),
+  );
+  writeFileSync(pomFile, pom(coordinate).replace(/\s*[\s\S]*?<\/developers>/u, ''));
+  expect(() => validateKotlinMavenStagingClosure(root, VERSION)).toThrow(
+    /maven-central-contract:.*must define /u,
+  );
+});
diff --git a/src/sdks/kotlin/tools/stage-release-artifacts.mts b/src/sdks/kotlin/tools/stage-release-artifacts.mts
new file mode 100644
index 000000000..6faf70979
--- /dev/null
+++ b/src/sdks/kotlin/tools/stage-release-artifacts.mts
@@ -0,0 +1,59 @@
+import path from 'node:path';
+import { readFileSync } from 'node:fs';
+
+import { assertReleaseNoticesInArchive } from '../../../../tools/packaging/release-notices.mts';
+import {
+  ROOT,
+  copyDirContents,
+  fail,
+  filesUnder,
+  rel,
+  requireFile,
+} from '../../../../tools/packaging/staging.mts';
+
+function kotlinVersion() {
+  const gradleProperties = readFileSync(
+    path.join(ROOT, 'src/sdks/kotlin/gradle.properties'),
+    'utf8',
+  );
+  const versions = gradleProperties
+    .split(/\r?\n/u)
+    .map((line) => line.match(/^VERSION_NAME=(.+)$/u)?.[1]?.trim())
+    .filter(Boolean);
+  const version = versions.at(-1);
+  if (!version) {
+    fail('missing VERSION_NAME in src/sdks/kotlin/gradle.properties');
+  }
+  return version;
+}
+
+export function stageArtifacts(artifactRoot) {
+  const mavenRepo = path.join(ROOT, 'target/moon/oliphaunt-kotlin/package/maven');
+  const version = kotlinVersion();
+  requireFile(
+    path.join(
+      mavenRepo,
+      `dev/oliphaunt/oliphaunt-android/${version}/oliphaunt-android-${version}.aar`,
+    ),
+  );
+  requireFile(
+    path.join(
+      mavenRepo,
+      `dev/oliphaunt/oliphaunt-android-gradle-plugin/${version}/oliphaunt-android-gradle-plugin-${version}.jar`,
+    ),
+  );
+  const publishedArchives = filesUnder(mavenRepo).filter(
+    (file) => file.endsWith('.aar') || file.endsWith('.jar'),
+  );
+  if (publishedArchives.length === 0) {
+    fail(`Kotlin SDK Maven repository contains no AAR or JAR artifacts: ${rel(mavenRepo)}`);
+  }
+  for (const archive of publishedArchives) {
+    assertReleaseNoticesInArchive(archive, { prefix: 'META-INF' });
+  }
+  const destination = path.join(artifactRoot, 'maven');
+  copyDirContents(mavenRepo, destination);
+}
+
+import { stageSdkArtifacts } from '../../../../tools/packaging/staging.mts';
+if (import.meta.main) await stageSdkArtifacts('oliphaunt-kotlin', stageArtifacts);
diff --git a/src/sdks/kotlin/tools/test-cpp-bridge.sh b/src/sdks/kotlin/tools/test-cpp-bridge.sh
deleted file mode 100755
index 6c3529256..000000000
--- a/src/sdks/kotlin/tools/test-cpp-bridge.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env sh
-set -eu
-
-root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "must run inside the Oliphaunt git checkout" >&2
-  exit 1
-}
-cxx="${CXX:-c++}"
-if ! command -v "$cxx" >/dev/null 2>&1; then
-  echo "missing required C++ compiler: $cxx" >&2
-  exit 1
-fi
-
-scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-kotlin-cpp-bridge.XXXXXX")"
-trap 'rm -rf "$scratch"' EXIT
-
-"$cxx" \
-  -std=c++17 \
-  -Wall \
-  -Wextra \
-  -Werror \
-  -Wpedantic \
-  -I "$root/src/sdks/kotlin/oliphaunt/src/androidMain/cpp" \
-  -I "$root/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/include" \
-  "$root/src/sdks/kotlin/tools/android-stream-completion-test.cpp" \
-  -o "$scratch/android-stream-completion-test"
-
-"$scratch/android-stream-completion-test"
diff --git a/src/sdks/kotlin/tools/test-native-bindings.sh b/src/sdks/kotlin/tools/test-native-bindings.sh
new file mode 100644
index 000000000..f6532fe61
--- /dev/null
+++ b/src/sdks/kotlin/tools/test-native-bindings.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+cd "$root"
+. src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+oliphaunt_runtime_native_host_require basic
+scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-kotlin-native.XXXXXX")"
+trap 'rm -rf "$scratch"' EXIT
+export LIBOLIPHAUNT_PATH="$(oliphaunt_runtime_native_host_lib)"
+export OLIPHAUNT_INSTALL_DIR="$(oliphaunt_runtime_native_host_install_dir)"
+export OLIPHAUNT_EMBEDDED_MODULE_DIR="${OLIPHAUNT_EMBEDDED_MODULE_DIR:-$(oliphaunt_runtime_native_host_work_root)/out/modules}"
+export OLIPHAUNT_MOBILE_BINDINGS_DIR="${CARGO_TARGET_DIR:-$root/target}/debug"
+export OLIPHAUNT_MOBILE_TEST_PGDATA="$scratch/pgdata"
+OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY=1 "$(oliphaunt_runtime_native_host_initdb)" \
+  -D "$OLIPHAUNT_MOBILE_TEST_PGDATA" -U postgres --locale=C --encoding=UTF8 --auth=trust
+cd src/sdks/kotlin
+./gradlew :oliphaunt:testDebugUnitTest --tests dev.oliphaunt.NativeBindingsTest --console=plain
diff --git a/src/sdks/react-native/CHANGELOG.md b/src/sdks/react-native/CHANGELOG.md
index e83d150cd..74f087acc 100644
--- a/src/sdks/react-native/CHANGELOG.md
+++ b/src/sdks/react-native/CHANGELOG.md
@@ -6,7 +6,6 @@
 ### ⚠ BREAKING CHANGES
 
 * **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/sdks/react-native/OliphauntReactNative.podspec b/src/sdks/react-native/OliphauntReactNative.podspec
index 74597ad7d..bb21d61ff 100644
--- a/src/sdks/react-native/OliphauntReactNative.podspec
+++ b/src/sdks/react-native/OliphauntReactNative.podspec
@@ -15,7 +15,9 @@ Pod::Spec.new do |s|
   s.source = { :git => "https://github.com/f0rr0/oliphaunt.git", :tag => "oliphaunt-react-native-v#{s.version}" }
   s.platforms = { :ios => "17.0" }
   s.swift_version = "6.0"
-  s.source_files = "ios/*.{h,m,mm,swift}"
+  s.source_files = "ios/*.{h,m,mm,swift}", "cpp/*.{h,cpp}"
+  s.private_header_files = "cpp/*.h", "ios/OliphauntReactNative.h"
+  s.exclude_files = "cpp/*.test.cpp"
   s.requires_arc = true
   s.dependency "Oliphaunt", native_sdk_version
 
diff --git a/src/sdks/react-native/README.md b/src/sdks/react-native/README.md
index ffd83023e..ea7cb66d3 100644
--- a/src/sdks/react-native/README.md
+++ b/src/sdks/react-native/README.md
@@ -17,13 +17,22 @@ them:
 ```json
 {
   "expo": {
-    "plugins": [["@oliphaunt/react-native", { "icu": true }]]
+    "plugins": [["@oliphaunt/react-native", { "seedProfile": "icu", "icu": true }]]
   }
 }
 ```
 
-The plugin packages ICU data with the matching platform cluster seed; this is a
-build-time choice and does not add a database-open option.
+Initialization seeds are optional dependencies owned by `database-resources`.
+On Android, `seedProfile` selects the standard or ICU Maven seed; omit it when
+opening an existing database or supplying application-owned seed resources.
+On iOS, install exactly one `@oliphaunt/seed-native-ios-datum64-standard` or
+`@oliphaunt/seed-native-ios-datum64-icu` npm package. Its resource-only CocoaPod
+is autolinked into the application. `seedProfile` declares the selected resource
+dependency in the app-owned podspec; omit it when using an existing database or
+application-owned resources. An ICU profile also requires the separately installed
+`@oliphaunt/icu` package. Its data bundle stays separate from the runtime payload;
+the Swift initializer validates and uses it with the selected seed.
+These are build-time choices and do not add a database-open option.
 
 ```typescript
 import Oliphaunt from '@oliphaunt/react-native';
@@ -101,6 +110,11 @@ speculative SDK `COMMIT` or `ROLLBACK`.
 
 ## Backup and storage
 
+`directory` from `@oliphaunt/react-native/storage` converts an absolute native
+path or a local `file:` URI into a directory storage descriptor for open or
+restore. For example, `directory('file:///data/my%20database')` selects
+`/data/my database`. It performs no filesystem operations.
+
 Backup has one representation: PostgreSQL physical initialization bytes.
 Restore requires an absent or empty destination and never replaces an existing
 root. The payload contains PGDATA and backup metadata, not the outer
@@ -147,6 +161,28 @@ facade. Both use exact generated PostgreSQL extension names and selected package
 artifacts. Runtime manifests, static registries, package reports, and link
 evidence remain internal packaging concerns.
 
-Run `pnpm typecheck`, `pnpm test`, and the platform package checks before
-publishing. The Expo example is an executable smoke application, not an
-additional public API layer.
+## Working on this package
+
+After installing the workspace's pinned tools and workspace dependencies, run
+from this directory:
+
+```sh
+moon run oliphaunt-react-native:build
+bun run format-check
+bun run lint
+bun run typecheck
+bun run codegen:check
+bun run test
+```
+
+Moon builds the independently versioned query dependency before the SDK.
+`moon run oliphaunt-react-native:package` assembles its distributable archive
+and requires Apple carrier inputs. `moon run oliphaunt-react-native:test-consumer`
+separately verifies packaged ICU autolinking. Neither is a prerequisite for
+TypeScript tests. `bun run package` runs assembly against already built inputs.
+Installed Android/iOS app tests live in the Expo example and require their
+platform tools and runtime artifacts.
+
+The platform bridges share JSI marshalling, promise settlement and stream acknowledgement code in `cpp/`. An installed runtime owns its pending callbacks and waits; invalidating or replacing that runtime releases blocked producers and prevents queued callbacks from touching its JavaScript objects. JNI and Objective-C conversions, storage, and platform process isolation stay in their respective adapters.
+
+`bun run test-cpp` checks acknowledgement delivery and teardown races with a local C++17 compiler. `bun run typecheck`, `bun run test`, and `bun run build` cover the source package. These checks do not replace the installed Android/iOS Hermes and lifecycle tests; final release packaging also requires the prepared iOS carrier assets declared by its Moon task.
diff --git a/src/sdks/react-native/android/build.gradle b/src/sdks/react-native/android/build.gradle
index b190c1c60..89658be03 100644
--- a/src/sdks/react-native/android/build.gradle
+++ b/src/sdks/react-native/android/build.gradle
@@ -63,7 +63,7 @@ def reactNativeCodegenDir = findNodeModuleDir("@react-native/codegen")
 if (reactNativeDir == null || reactNativeCodegenDir == null) {
   throw new GradleException(
     "Could not resolve react-native and @react-native/codegen from node_modules. " +
-    "Run pnpm install for @oliphaunt/react-native before building the Android package."
+    "Run bun install for @oliphaunt/react-native before building the Android package."
   )
 }
 def nodeExecutable = (project.findProperty("nodeExecutable") ?: System.getenv("NODE_BINARY") ?: "node").toString()
@@ -354,21 +354,14 @@ abstract class PrepareOliphauntAndroidAssetsTask extends DefaultTask {
       "target", "compatibilityKey", "initialSuperuser", "runtimeFeatures", "icuDataVersion",
       "icuDataForm", "icuDataTreeSha256", "cacheKey",
     ] as Set
-    File receiptFile = new File(root, "manifest.properties")
-    Map receipt = readStrictManifest(receiptFile)
-    Map expectedReceipt = [
-      schema: "oliphaunt-native-runtime-carrier-v1",
-      clusterSeedTarget: "android-datum64",
-      clusterSeedRelativePath: "cluster-seed",
-      icuClusterSeedRelativePath: "cluster-seed-icu",
-    ]
-    if (receipt != expectedReceipt) {
-      throw new GradleException("Oliphaunt React Native Android runtime resources have an invalid target seed receipt")
-    }
     String runtimeIcuDigest = ""
     boolean runtimeUsesIcu = false
     String icuSeedDigest = ""
-    ["runtime", "cluster-seed", "cluster-seed-icu"].each { name ->
+    // Mobile apps carry only the seed selected by runtimeFeatures.
+    ["runtime", "cluster-seed"].each { name ->
+      if (name == "cluster-seed" && runtimeUsesIcu) {
+        name = "cluster-seed-icu"
+      }
       File manifest = new File(new File(root, name), "manifest.properties")
       if (!manifest.isFile()) {
         throw new GradleException("Oliphaunt React Native Android runtime resources are missing ${name}/manifest.properties under ${root.absolutePath}")
@@ -926,6 +919,8 @@ dependencies {
     // the staged AAR directly so an already-published artifact with the same
     // coordinate cannot win through another Gradle repository or cache.
     implementation files(kotlinSdkAar)
+    // File dependencies have no Maven metadata; supply the Kotlin SDK's JNA runtime.
+    implementation "net.java.dev.jna:jna:5.14.0@aar"
   } else {
     implementation kotlinSdkDependency
   }
diff --git a/src/sdks/react-native/android/src/main/cpp/CMakeLists.txt b/src/sdks/react-native/android/src/main/cpp/CMakeLists.txt
index 7d0ff38e5..1c16d30e6 100644
--- a/src/sdks/react-native/android/src/main/cpp/CMakeLists.txt
+++ b/src/sdks/react-native/android/src/main/cpp/CMakeLists.txt
@@ -2,6 +2,12 @@ cmake_minimum_required(VERSION 3.22.1)
 
 project(liboliphaunt_reactnative LANGUAGES C CXX)
 
+# Checkout builds use the runtime owner; source distributions carry this header.
+set(OLIPHAUNT_NATIVE_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../runtimes/liboliphaunt-native/include")
+if(NOT EXISTS "${OLIPHAUNT_NATIVE_INCLUDE}/oliphaunt.h")
+  set(OLIPHAUNT_NATIVE_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include")
+endif()
+
 find_package(fbjni REQUIRED CONFIG)
 find_package(ReactAndroid REQUIRED CONFIG)
 
@@ -73,7 +79,7 @@ if(DEFINED OLIPHAUNT_MOBILE_STATIC_MODULES AND NOT "${OLIPHAUNT_MOBILE_STATIC_MO
     LINKER_LANGUAGE CXX
   )
   target_include_directories(oliphaunt_extensions PRIVATE
-    "${CMAKE_CURRENT_SOURCE_DIR}/include"
+    "${OLIPHAUNT_NATIVE_INCLUDE}"
   )
   target_link_libraries(oliphaunt_extensions PRIVATE
     oliphaunt_imported
diff --git a/src/sdks/react-native/android/src/main/cpp/OliphauntJsiBindings.cpp b/src/sdks/react-native/android/src/main/cpp/OliphauntJsiBindings.cpp
index f4e5441b8..fa72e2191 100644
--- a/src/sdks/react-native/android/src/main/cpp/OliphauntJsiBindings.cpp
+++ b/src/sdks/react-native/android/src/main/cpp/OliphauntJsiBindings.cpp
@@ -1,3 +1,4 @@
+#include "../../../../cpp/Jsi.h"
 #include 
 #include 
 #include 
@@ -20,304 +21,82 @@
 
 namespace facebook::react {
 namespace {
-
-class OliphauntMutableBuffer final : public jsi::MutableBuffer {
- public:
-  explicit OliphauntMutableBuffer(std::vector bytes)
-      : bytes_(std::move(bytes)) {}
-
-  size_t size() const override
-  {
-    return bytes_.size();
-  }
-
-  uint8_t *data() override
-  {
-    return bytes_.data();
-  }
-
- private:
-  std::vector bytes_;
-};
-
-struct PendingPromise final {
-  std::shared_ptr> resolve;
-  std::shared_ptr> reject;
-};
-
-class ChunkAcknowledgement final {
- public:
-  void resolve()
-  {
-    finish(std::nullopt);
-  }
-
-  void reject(std::string message)
-  {
-    finish(std::move(message));
-  }
-
-  std::optional wait()
-  {
-    std::unique_lock lock(mutex_);
-    condition_.wait(lock, [this]() { return complete_; });
-    return error_;
-  }
-
- private:
-  void finish(std::optional error)
-  {
-    {
-      std::lock_guard lock(mutex_);
-      if (complete_) {
-        return;
-      }
-      error_ = std::move(error);
-      complete_ = true;
-    }
-    condition_.notify_one();
-  }
-
-  std::mutex mutex_;
-  std::condition_variable condition_;
-  bool complete_ = false;
-  std::optional error_;
+using namespace oliphaunt::reactnative;
+
+struct PendingStream final : PendingPromise {
+  PendingStream(std::shared_ptr chunk, PendingPromise promise,
+      std::shared_ptr owner)
+      : PendingPromise(std::move(promise)), onChunk(std::move(chunk)), lifetime(std::move(owner)) {}
+  std::shared_ptr onChunk;
+  std::shared_ptr lifetime;
 };
 
-struct PendingStream final {
-  PendingStream(
-      std::shared_ptr> onChunk,
-      std::shared_ptr> resolve,
-      std::shared_ptr> reject)
-      : onChunk(std::move(onChunk)),
-        resolve(std::move(resolve)),
-        reject(std::move(reject)) {}
-
-  void acknowledgeWith(std::shared_ptr next)
-  {
-    std::lock_guard lock(mutex);
-    acknowledgement = std::move(next);
-  }
-
-  void clearAcknowledgement(const std::shared_ptr ¤t)
-  {
-    std::lock_guard lock(mutex);
-    if (acknowledgement == current) {
-      acknowledgement.reset();
-    }
-  }
-
-  void abort()
-  {
-    std::shared_ptr current;
-    {
-      std::lock_guard lock(mutex);
-      invalidated = true;
-      current = acknowledgement;
-    }
-    if (current != nullptr) {
-      current->reject("React Native Oliphaunt module has been invalidated");
-    }
-  }
-
-  bool settle()
-  {
-    std::lock_guard lock(mutex);
-    if (invalidated || settled) {
-      return false;
-    }
-    settled = true;
-    return true;
-  }
-
-  std::shared_ptr> onChunk;
-  std::shared_ptr> resolve;
-  std::shared_ptr> reject;
-
- private:
+struct RuntimeState final : RuntimeLifetime {
+  int64_t id;
   std::mutex mutex;
-  std::shared_ptr acknowledgement;
-  bool invalidated = false;
-  bool settled = false;
-};
-
-std::mutex gPendingMutex;
-std::unordered_map gPendingPromises;
-std::unordered_map> gPendingStreams;
-std::atomic gNextToken{1};
-std::atomic gBindingsInvalidated{false};
-
-jsi::ArrayBuffer arrayBufferFromBytes(jsi::Runtime &runtime, std::vector bytes)
-{
-  return jsi::ArrayBuffer(
-      runtime,
-      std::make_shared(std::move(bytes)));
-}
-
-jsi::Value createError(jsi::Runtime &runtime, const std::string &message)
-{
-  return runtime.global()
-      .getPropertyAsFunction(runtime, "Error")
-      .callAsConstructor(runtime, jsi::String::createFromUtf8(runtime, message));
-}
-
-jsi::Value createProtocolCallbackAbortedError(
-    jsi::Runtime &runtime,
-    const std::string &message)
-{
-  auto value = createError(runtime, message);
-  auto object = value.asObject(runtime);
-  object.setProperty(runtime, "__oliphauntProtocolCallbackAborted", true);
-  return object;
-}
-
-size_t copySizeArgument(jsi::Runtime &runtime, double value, const char *name)
-{
-  constexpr double kMaxSafeInteger = 9007199254740991.0;
-  if (!std::isfinite(value) ||
-      value < 0 ||
-      std::trunc(value) != value ||
-      value > kMaxSafeInteger ||
-      value > static_cast(std::numeric_limits::max())) {
-    throw jsi::JSError(
-        runtime,
-        std::string("liboliphaunt JSI ") + name + " must be a non-negative integer");
-  }
-  return static_cast(value);
-}
-
-int64_t copyHandleArgument(jsi::Runtime &runtime, const jsi::Value &value)
-{
-  constexpr double kMaxSafeInteger = 9007199254740991.0;
-  if (!value.isNumber()) {
-    throw jsi::JSError(runtime, "liboliphaunt JSI handle must be a number");
-  }
-  double handle = value.asNumber();
-  if (!std::isfinite(handle) ||
-      handle <= 0 ||
-      std::trunc(handle) != handle ||
-      handle > kMaxSafeInteger ||
-      handle > static_cast(std::numeric_limits::max())) {
-    throw jsi::JSError(runtime, "liboliphaunt JSI handle must be a positive safe integer");
-  }
-  return static_cast(handle);
-}
-
-std::vector copyBinaryArgument(jsi::Runtime &runtime, const jsi::Value &value)
-{
-  if (!value.isObject()) {
-    throw jsi::JSError(runtime, "liboliphaunt JSI request must be an ArrayBuffer or typed array");
-  }
-
-  auto object = value.asObject(runtime);
-  size_t byteOffset = 0;
-  size_t byteLength = 0;
-  jsi::ArrayBuffer buffer = [&]() {
-    if (object.isArrayBuffer(runtime)) {
-      auto arrayBuffer = object.getArrayBuffer(runtime);
-      byteLength = arrayBuffer.size(runtime);
-      return arrayBuffer;
-    }
-
-    auto bufferValue = object.getProperty(runtime, "buffer");
-    if (!bufferValue.isObject() || !bufferValue.asObject(runtime).isArrayBuffer(runtime)) {
-      throw jsi::JSError(runtime, "liboliphaunt JSI request must be an ArrayBuffer or typed array");
-    }
-    auto offsetValue = object.getProperty(runtime, "byteOffset");
-    auto lengthValue = object.getProperty(runtime, "byteLength");
-    if (!offsetValue.isNumber() || !lengthValue.isNumber()) {
-      throw jsi::JSError(runtime, "liboliphaunt JSI typed-array request is missing byteOffset/byteLength");
-    }
-    byteOffset = copySizeArgument(runtime, offsetValue.asNumber(), "typed-array byteOffset");
-    byteLength = copySizeArgument(runtime, lengthValue.asNumber(), "typed-array byteLength");
-    return bufferValue.asObject(runtime).getArrayBuffer(runtime);
-  }();
-
-  if (byteOffset > buffer.size(runtime) || byteLength > buffer.size(runtime) - byteOffset) {
-    throw jsi::JSError(runtime, "liboliphaunt JSI typed-array request is out of bounds");
-  }
-
-  const uint8_t *begin = buffer.data(runtime) + byteOffset;
-  return std::vector(begin, begin + byteLength);
-}
-
-std::string copyStringArgument(jsi::Runtime &runtime, const jsi::Value &value, const char *name)
-{
-  if (!value.isString()) {
-    throw jsi::JSError(runtime, std::string("liboliphaunt JSI ") + name + " must be a string");
-  }
-  return value.asString(runtime).utf8(runtime);
-}
-
-std::optional copyOptionalStringArgument(
-    jsi::Runtime &runtime,
-    const jsi::Value &value,
-    const char *name)
-{
-  if (value.isNull() || value.isUndefined()) {
-    return std::nullopt;
-  }
-  return copyStringArgument(runtime, value, name);
-}
-
+  std::unordered_map promises;
+  std::unordered_map> streams;
+  explicit RuntimeState(int64_t id) : id(id) {}
 void storePendingPromise(int64_t token, PendingPromise promise)
 {
-  std::lock_guard lock(gPendingMutex);
-  gPendingPromises.emplace(token, std::move(promise));
+  std::lock_guard lock(mutex);
+  if (active()) promises.emplace(token, std::move(promise));
 }
 
 std::optional takePendingPromise(int64_t token)
 {
-  std::lock_guard lock(gPendingMutex);
-  auto iter = gPendingPromises.find(token);
-  if (iter == gPendingPromises.end()) {
+  std::lock_guard lock(mutex);
+  auto iter = promises.find(token);
+  if (iter == promises.end()) {
     return std::nullopt;
   }
   auto promise = std::move(iter->second);
-  gPendingPromises.erase(iter);
+  promises.erase(iter);
   return promise;
 }
 
 void storePendingStream(int64_t token, std::shared_ptr stream)
 {
-  std::lock_guard lock(gPendingMutex);
-  gPendingStreams.emplace(token, std::move(stream));
+  std::lock_guard lock(mutex);
+  if (active()) streams.emplace(token, std::move(stream));
 }
 
 std::shared_ptr findPendingStream(int64_t token)
 {
-  std::lock_guard lock(gPendingMutex);
-  auto iter = gPendingStreams.find(token);
-  return iter == gPendingStreams.end() ? nullptr : iter->second;
+  std::lock_guard lock(mutex);
+  auto iter = streams.find(token);
+  return iter == streams.end() ? nullptr : iter->second;
 }
 
 std::shared_ptr takePendingStream(int64_t token)
 {
-  std::lock_guard lock(gPendingMutex);
-  auto iter = gPendingStreams.find(token);
-  if (iter == gPendingStreams.end()) {
+  std::lock_guard lock(mutex);
+  auto iter = streams.find(token);
+  if (iter == streams.end()) {
     return nullptr;
   }
   auto stream = std::move(iter->second);
-  gPendingStreams.erase(iter);
+  streams.erase(iter);
   return stream;
 }
 
-void invalidatePendingCallbacks()
-{
-  std::vector> streams;
-  {
-    std::lock_guard lock(gPendingMutex);
-    streams.reserve(gPendingStreams.size());
-    for (auto &[_, stream] : gPendingStreams) {
-      streams.push_back(stream);
-    }
-    gPendingStreams.clear();
-    gPendingPromises.clear();
-  }
-  for (const auto &stream : streams) {
-    stream->abort();
+
+  void close() {
+    invalidate();
+    std::lock_guard lock(mutex);
+    promises.clear();
+    streams.clear();
   }
+};
+// JNI callbacks carry the module owner ID; the routing table holds no callback
+// from a different runtime and is erased by that module's invalidate hook.
+std::mutex gOwnersMutex;
+std::unordered_map> gOwners;
+std::atomic gNextToken{1};
+std::shared_ptr findOwner(int64_t id) {
+  std::lock_guard lock(gOwnersMutex);
+  auto found = gOwners.find(id);
+  return found == gOwners.end() ? nullptr : found->second;
 }
 
 jni::local_ref makeByteArray(const std::vector &bytes)
@@ -374,10 +153,12 @@ class OliphauntJsiPromiseCallback
  private:
   static void nativeResolveBytes(
       jni::alias_ref,
+      jlong ownerId,
       jlong token,
       jni::alias_ref response)
   {
-    auto promise = takePendingPromise(static_cast(token));
+    auto owner = findOwner(ownerId);
+    auto promise = owner ? owner->takePendingPromise(static_cast(token)) : std::nullopt;
     if (!promise) {
       return;
     }
@@ -391,10 +172,12 @@ class OliphauntJsiPromiseCallback
 
   static void nativeResolveString(
       jni::alias_ref,
+      jlong ownerId,
       jlong token,
       jni::alias_ref value)
   {
-    auto promise = takePendingPromise(static_cast(token));
+    auto owner = findOwner(ownerId);
+    auto promise = owner ? owner->takePendingPromise(static_cast(token)) : std::nullopt;
     if (!promise) {
       return;
     }
@@ -408,9 +191,11 @@ class OliphauntJsiPromiseCallback
 
   static void nativeResolveUnit(
       jni::alias_ref,
+      jlong ownerId,
       jlong token)
   {
-    auto promise = takePendingPromise(static_cast(token));
+    auto owner = findOwner(ownerId);
+    auto promise = owner ? owner->takePendingPromise(static_cast(token)) : std::nullopt;
     if (!promise) {
       return;
     }
@@ -423,10 +208,12 @@ class OliphauntJsiPromiseCallback
 
   static void nativeReject(
       jni::alias_ref,
+      jlong ownerId,
       jlong token,
       jni::alias_ref message)
   {
-    auto promise = takePendingPromise(static_cast(token));
+    auto owner = findOwner(ownerId);
+    auto promise = owner ? owner->takePendingPromise(static_cast(token)) : std::nullopt;
     if (!promise) {
       return;
     }
@@ -458,46 +245,26 @@ class OliphauntJsiStreamCallback
  private:
   static jni::local_ref nativeEmitChunk(
       jni::alias_ref,
+      jlong ownerId,
       jlong token,
       jni::alias_ref chunk)
   {
-    auto stream = findPendingStream(static_cast(token));
+    auto owner = findOwner(ownerId);
+    auto stream = owner ? owner->findPendingStream(static_cast(token)) : nullptr;
     if (stream == nullptr) {
       return jni::make_jstring("liboliphaunt protocol stream is no longer active");
     }
     std::vector bytes = copyByteArray(chunk);
-    auto acknowledgement = std::make_shared();
-    stream->acknowledgeWith(acknowledgement);
+    auto acknowledgement = stream->lifetime->acknowledge();
     try {
-      stream->onChunk->call([bytes = std::move(bytes), acknowledgement](
+      stream->onChunk->call([bytes = std::move(bytes), acknowledgement, lifetime = stream->lifetime](
                                 jsi::Runtime &runtime,
                                 jsi::Function &chunkFunction) mutable {
-        if (gBindingsInvalidated.load()) {
+        if (!lifetime->active()) {
           acknowledgement->reject("React Native Oliphaunt module has been invalidated");
           return;
         }
-        try {
-          auto result = chunkFunction.call(
-              runtime,
-              arrayBufferFromBytes(runtime, std::move(bytes)));
-          if (result.isObject()) {
-            auto resultObject = result.asObject(runtime);
-            auto failureMarker = resultObject.getProperty(
-                runtime,
-                "__oliphauntProtocolChunkFailure");
-            if (failureMarker.isBool() && failureMarker.getBool()) {
-              acknowledgement->reject("protocol stream callback failed");
-              return;
-            }
-          }
-          acknowledgement->resolve();
-        } catch (const jsi::JSError &error) {
-          acknowledgement->reject(error.what());
-        } catch (const std::exception &error) {
-          acknowledgement->reject(error.what());
-        } catch (...) {
-          acknowledgement->reject("protocol stream callback failed");
-        }
+        deliverChunk(runtime, chunkFunction, std::move(bytes), acknowledgement);
       });
     } catch (const std::exception &error) {
       acknowledgement->reject(error.what());
@@ -505,19 +272,20 @@ class OliphauntJsiStreamCallback
       acknowledgement->reject("failed to schedule protocol stream callback");
     }
     auto error = acknowledgement->wait();
-    stream->clearAcknowledgement(acknowledgement);
     return error ? jni::make_jstring(*error) : jni::local_ref();
   }
 
   static void nativeResolveUnit(
       jni::alias_ref,
+      jlong ownerId,
       jlong token)
   {
-    auto stream = takePendingStream(static_cast(token));
+    auto owner = findOwner(ownerId);
+    auto stream = owner ? owner->takePendingStream(static_cast(token)) : nullptr;
     if (stream == nullptr) {
       return;
     }
-    if (gBindingsInvalidated.load() || !stream->settle()) {
+    if (!stream->lifetime->active()) {
       return;
     }
     stream->resolve->call([](jsi::Runtime &runtime, jsi::Function &resolveFunction) {
@@ -527,14 +295,16 @@ class OliphauntJsiStreamCallback
 
   static void nativeRejectCallbackAborted(
       jni::alias_ref,
+      jlong ownerId,
       jlong token,
       jni::alias_ref message)
   {
-    auto stream = takePendingStream(static_cast(token));
+    auto owner = findOwner(ownerId);
+    auto stream = owner ? owner->takePendingStream(static_cast(token)) : nullptr;
     if (stream == nullptr) {
       return;
     }
-    if (gBindingsInvalidated.load() || !stream->settle()) {
+    if (!stream->lifetime->active()) {
       return;
     }
     std::string errorMessage =
@@ -552,14 +322,16 @@ class OliphauntJsiStreamCallback
 
   static void nativeReject(
       jni::alias_ref,
+      jlong ownerId,
       jlong token,
       jni::alias_ref message)
   {
-    auto stream = takePendingStream(static_cast(token));
+    auto owner = findOwner(ownerId);
+    auto stream = owner ? owner->takePendingStream(static_cast(token)) : nullptr;
     if (stream == nullptr) {
       return;
     }
-    if (gBindingsInvalidated.load() || !stream->settle()) {
+    if (!stream->lifetime->active()) {
       return;
     }
     std::string errorMessage = message != nullptr ? message->toStdString() : "liboliphaunt stream failed";
@@ -590,11 +362,23 @@ class OliphauntModuleJSIBindings
       jni::alias_ref module)
   {
     auto moduleGlobal = jni::make_global(module);
+    static const auto ownerField = javaClassStatic()->getField("jsiOwnerId");
+    auto owner = std::make_shared(gNextToken.fetch_add(1));
+    {
+      std::lock_guard lock(gOwnersMutex);
+      const auto previous = module->getFieldValue(ownerField);
+      if (previous == -1) owner->invalidate();
+      if (auto found = gOwners.find(previous); found != gOwners.end()) {
+        found->second->close();
+        gOwners.erase(found);
+      }
+      gOwners.emplace(owner->id, owner);
+      module->setFieldValue(ownerField, static_cast(owner->id));
+    }
     return BindingsInstallerHolder::newObjectCxxArgs(
-        [moduleGlobal](
+        [owner, moduleGlobal](
             jsi::Runtime &runtime,
             const std::shared_ptr &callInvoker) {
-          gBindingsInvalidated.store(false);
           auto transport = jsi::Object(runtime);
           transport.setProperty(runtime, "version", 1);
           transport.setProperty(
@@ -604,7 +388,7 @@ class OliphauntModuleJSIBindings
                   runtime,
                   jsi::PropNameID::forAscii(runtime, "liboliphauntCloseIfGeneration"),
                   1,
-                  [moduleGlobal](
+                  [owner, moduleGlobal](
                       jsi::Runtime &runtime,
                       const jsi::Value &,
                       const jsi::Value *args,
@@ -615,7 +399,7 @@ class OliphauntModuleJSIBindings
                           "liboliphaunt JSI closeIfGeneration expects a generation");
                     }
                     int64_t generation = copyHandleArgument(runtime, args[0]);
-                    if (gBindingsInvalidated.load()) {
+                    if (!owner->active()) {
                       return jsi::Value::undefined();
                     }
                     static const auto closeIfGeneration =
@@ -631,7 +415,7 @@ class OliphauntModuleJSIBindings
                   runtime,
                   jsi::PropNameID::forAscii(runtime, "liboliphauntExecProtocolRaw"),
                   1,
-                  [moduleGlobal, callInvoker](
+                  [owner, moduleGlobal, callInvoker](
                       jsi::Runtime &runtime,
                       const jsi::Value &,
                       const jsi::Value *args,
@@ -647,43 +431,24 @@ class OliphauntModuleJSIBindings
                         runtime,
                         jsi::PropNameID::forAscii(runtime, "liboliphauntExecProtocolRawExecutor"),
                         2,
-                        [moduleGlobal, callInvoker, handle, request = std::move(request)](
+                        [owner, moduleGlobal, callInvoker, handle, request = std::move(request)](
                             jsi::Runtime &runtime,
                             const jsi::Value &,
                             const jsi::Value *promiseArgs,
                             size_t promiseArgCount) mutable -> jsi::Value {
-                          if (promiseArgCount < 2 ||
-                              !promiseArgs[0].isObject() ||
-                              !promiseArgs[0].asObject(runtime).isFunction(runtime) ||
-                              !promiseArgs[1].isObject() ||
-                              !promiseArgs[1].asObject(runtime).isFunction(runtime)) {
-                            throw jsi::JSError(
-                                runtime,
-                                "liboliphaunt JSI Promise executor received invalid callbacks");
-                          }
-
                           int64_t token = gNextToken.fetch_add(1);
-                          PendingPromise pending{
-                              std::make_shared>(
-                                  runtime,
-                                  promiseArgs[0].asObject(runtime).getFunction(runtime),
-                                  callInvoker),
-                              std::make_shared>(
-                                  runtime,
-                                  promiseArgs[1].asObject(runtime).getFunction(runtime),
-                                  callInvoker),
-                          };
+                          auto pending = promiseCallbacks(runtime, promiseArgs, promiseArgCount, callInvoker, owner);
                           auto reject = pending.reject;
-                          storePendingPromise(token, std::move(pending));
+                          owner->storePendingPromise(token, std::move(pending));
 
                           try {
                             auto requestArray = makeByteArray(request);
                             static const auto callbackConstructor =
                                 OliphauntJsiPromiseCallback::javaClassStatic()
-                                    ->getConstructor();
+                                    ->getConstructor();
                             auto callback =
                                 OliphauntJsiPromiseCallback::javaClassStatic()
-                                    ->newObject(callbackConstructor, static_cast(token));
+                                    ->newObject(callbackConstructor, static_cast(owner->id), static_cast(token));
                             static const auto execProtocolRawBytes =
                                 OliphauntModuleJSIBindings::javaClassStatic()
                                     ->getMethod(
@@ -694,7 +459,7 @@ class OliphauntModuleJSIBindings
                                 requestArray.get(),
                                 callback.get());
                           } catch (const std::exception &error) {
-                            takePendingPromise(token);
+                            owner->takePendingPromise(token);
                             std::string message = error.what();
                             reject->call([message](
                                              jsi::Runtime &runtime,
@@ -713,7 +478,7 @@ class OliphauntModuleJSIBindings
                   runtime,
                   jsi::PropNameID::forAscii(runtime, "liboliphauntExecProtocolStream"),
                   3,
-                  [moduleGlobal, callInvoker](
+                  [owner, moduleGlobal, callInvoker](
                       jsi::Runtime &runtime,
                       const jsi::Value &,
                       const jsi::Value *args,
@@ -728,16 +493,16 @@ class OliphauntModuleJSIBindings
 
                     int64_t handle = copyHandleArgument(runtime, args[0]);
                     std::vector request = copyBinaryArgument(runtime, args[1]);
-                    auto onChunk = std::make_shared>(
+                    auto onChunk = std::make_shared(
                         runtime,
                         args[2].asObject(runtime).getFunction(runtime),
-                        callInvoker);
+                        callInvoker, owner);
                     auto promiseConstructor = runtime.global().getPropertyAsFunction(runtime, "Promise");
                     auto executor = jsi::Function::createFromHostFunction(
                         runtime,
                         jsi::PropNameID::forAscii(runtime, "liboliphauntExecProtocolStreamExecutor"),
                         2,
-                        [moduleGlobal,
+                        [owner, moduleGlobal,
                          callInvoker,
                          handle,
                          request = std::move(request),
@@ -746,38 +511,20 @@ class OliphauntModuleJSIBindings
                             const jsi::Value &,
                             const jsi::Value *promiseArgs,
                             size_t promiseArgCount) mutable -> jsi::Value {
-                          if (promiseArgCount < 2 ||
-                              !promiseArgs[0].isObject() ||
-                              !promiseArgs[0].asObject(runtime).isFunction(runtime) ||
-                              !promiseArgs[1].isObject() ||
-                              !promiseArgs[1].asObject(runtime).isFunction(runtime)) {
-                            throw jsi::JSError(
-                                runtime,
-                                "liboliphaunt JSI Promise executor received invalid callbacks");
-                          }
-
                           int64_t token = gNextToken.fetch_add(1);
-                          auto stream = std::make_shared(
-                              onChunk,
-                              std::make_shared>(
-                                  runtime,
-                                  promiseArgs[0].asObject(runtime).getFunction(runtime),
-                                  callInvoker),
-                              std::make_shared>(
-                                  runtime,
-                                  promiseArgs[1].asObject(runtime).getFunction(runtime),
-                                  callInvoker));
+                          auto stream = std::make_shared(onChunk,
+                              promiseCallbacks(runtime, promiseArgs, promiseArgCount, callInvoker, owner), owner);
                           auto reject = stream->reject;
-                          storePendingStream(token, stream);
+                          owner->storePendingStream(token, stream);
 
                           try {
                             auto requestArray = makeByteArray(request);
                             static const auto callbackConstructor =
                                 OliphauntJsiStreamCallback::javaClassStatic()
-                                    ->getConstructor();
+                                    ->getConstructor();
                             auto callback =
                                 OliphauntJsiStreamCallback::javaClassStatic()
-                                    ->newObject(callbackConstructor, static_cast(token));
+                                    ->newObject(callbackConstructor, static_cast(owner->id), static_cast(token));
                             static const auto execProtocolStreamBytes =
                                 OliphauntModuleJSIBindings::javaClassStatic()
                                     ->getMethod(
@@ -788,7 +535,7 @@ class OliphauntModuleJSIBindings
                                 requestArray.get(),
                                 callback.get());
                           } catch (const std::exception &error) {
-                            takePendingStream(token);
+                            owner->takePendingStream(token);
                             std::string message = error.what();
                             reject->call([message](
                                              jsi::Runtime &runtime,
@@ -807,7 +554,7 @@ class OliphauntModuleJSIBindings
                   runtime,
                   jsi::PropNameID::forAscii(runtime, "liboliphauntBackup"),
                   2,
-                  [moduleGlobal, callInvoker](
+                  [owner, moduleGlobal, callInvoker](
                       jsi::Runtime &runtime,
                       const jsi::Value &,
                       const jsi::Value *args,
@@ -822,42 +569,23 @@ class OliphauntModuleJSIBindings
                         runtime,
                         jsi::PropNameID::forAscii(runtime, "liboliphauntBackupExecutor"),
                         2,
-                        [moduleGlobal, callInvoker, handle](
+                        [owner, moduleGlobal, callInvoker, handle](
                             jsi::Runtime &runtime,
                             const jsi::Value &,
                             const jsi::Value *promiseArgs,
                             size_t promiseArgCount) -> jsi::Value {
-                          if (promiseArgCount < 2 ||
-                              !promiseArgs[0].isObject() ||
-                              !promiseArgs[0].asObject(runtime).isFunction(runtime) ||
-                              !promiseArgs[1].isObject() ||
-                              !promiseArgs[1].asObject(runtime).isFunction(runtime)) {
-                            throw jsi::JSError(
-                                runtime,
-                                "liboliphaunt JSI Promise executor received invalid callbacks");
-                          }
-
                           int64_t token = gNextToken.fetch_add(1);
-                          PendingPromise pending{
-                              std::make_shared>(
-                                  runtime,
-                                  promiseArgs[0].asObject(runtime).getFunction(runtime),
-                                  callInvoker),
-                              std::make_shared>(
-                                  runtime,
-                                  promiseArgs[1].asObject(runtime).getFunction(runtime),
-                                  callInvoker),
-                          };
+                          auto pending = promiseCallbacks(runtime, promiseArgs, promiseArgCount, callInvoker, owner);
                           auto reject = pending.reject;
-                          storePendingPromise(token, std::move(pending));
+                          owner->storePendingPromise(token, std::move(pending));
 
                           try {
                             static const auto callbackConstructor =
                                 OliphauntJsiPromiseCallback::javaClassStatic()
-                                    ->getConstructor();
+                                    ->getConstructor();
                             auto callback =
                                 OliphauntJsiPromiseCallback::javaClassStatic()
-                                    ->newObject(callbackConstructor, static_cast(token));
+                                    ->newObject(callbackConstructor, static_cast(owner->id), static_cast(token));
                             static const auto backupBytes =
                                 OliphauntModuleJSIBindings::javaClassStatic()
                                     ->getMethod(
@@ -867,7 +595,7 @@ class OliphauntModuleJSIBindings
                                 static_cast(handle),
                                 callback.get());
                           } catch (const std::exception &error) {
-                            takePendingPromise(token);
+                            owner->takePendingPromise(token);
                             std::string message = error.what();
                             reject->call([message](
                                              jsi::Runtime &runtime,
@@ -886,7 +614,7 @@ class OliphauntModuleJSIBindings
                   runtime,
                   jsi::PropNameID::forAscii(runtime, "liboliphauntRestore"),
                   2,
-                  [moduleGlobal, callInvoker](
+                  [owner, moduleGlobal, callInvoker](
                       jsi::Runtime &runtime,
                       const jsi::Value &,
                       const jsi::Value *args,
@@ -919,7 +647,7 @@ class OliphauntModuleJSIBindings
                         runtime,
                         jsi::PropNameID::forAscii(runtime, "liboliphauntRestoreExecutor"),
                         2,
-                        [moduleGlobal,
+                        [owner, moduleGlobal,
                          callInvoker,
                          storageKind = std::move(storageKind),
                          storagePath = std::move(storagePath),
@@ -929,29 +657,10 @@ class OliphauntModuleJSIBindings
                             const jsi::Value &,
                             const jsi::Value *promiseArgs,
                             size_t promiseArgCount) mutable -> jsi::Value {
-                          if (promiseArgCount < 2 ||
-                              !promiseArgs[0].isObject() ||
-                              !promiseArgs[0].asObject(runtime).isFunction(runtime) ||
-                              !promiseArgs[1].isObject() ||
-                              !promiseArgs[1].asObject(runtime).isFunction(runtime)) {
-                            throw jsi::JSError(
-                                runtime,
-                                "liboliphaunt JSI Promise executor received invalid callbacks");
-                          }
-
                           int64_t token = gNextToken.fetch_add(1);
-                          PendingPromise pending{
-                              std::make_shared>(
-                                  runtime,
-                                  promiseArgs[0].asObject(runtime).getFunction(runtime),
-                                  callInvoker),
-                              std::make_shared>(
-                                  runtime,
-                                  promiseArgs[1].asObject(runtime).getFunction(runtime),
-                                  callInvoker),
-                          };
+                          auto pending = promiseCallbacks(runtime, promiseArgs, promiseArgCount, callInvoker, owner);
                           auto reject = pending.reject;
-                          storePendingPromise(token, std::move(pending));
+                          owner->storePendingPromise(token, std::move(pending));
 
                           try {
                             auto storageKindString = jni::make_jstring(storageKind);
@@ -960,10 +669,10 @@ class OliphauntModuleJSIBindings
                             auto artifactArray = makeByteArray(artifact);
                             static const auto callbackConstructor =
                                 OliphauntJsiPromiseCallback::javaClassStatic()
-                                    ->getConstructor();
+                                    ->getConstructor();
                             auto callback =
                                 OliphauntJsiPromiseCallback::javaClassStatic()
-                                    ->newObject(callbackConstructor, static_cast(token));
+                                    ->newObject(callbackConstructor, static_cast(owner->id), static_cast(token));
                             static const auto restoreBytes =
                                 OliphauntModuleJSIBindings::javaClassStatic()
                                     ->getMethodtakePendingPromise(token);
                             std::string message = error.what();
                             reject->call([message](
                                              jsi::Runtime &runtime,
@@ -996,10 +705,19 @@ class OliphauntModuleJSIBindings
         });
   }
 
-  static void invalidateJsiBindings(jni::alias_ref)
+  static void invalidateJsiBindings(jni::alias_ref module)
   {
-    gBindingsInvalidated.store(true);
-    invalidatePendingCallbacks();
+    static const auto ownerField = javaClassStatic()->getField("jsiOwnerId");
+    std::shared_ptr owner;
+    {
+      std::lock_guard lock(gOwnersMutex);
+      auto found = gOwners.find(module->getFieldValue(ownerField));
+      module->setFieldValue(ownerField, static_cast(-1));
+      if (found == gOwners.end()) return;
+      owner = std::move(found->second);
+      gOwners.erase(found);
+    }
+    owner->close();
   }
 };
 
diff --git a/src/sdks/react-native/android/src/main/cpp/include/oliphaunt.h b/src/sdks/react-native/android/src/main/cpp/include/oliphaunt.h
deleted file mode 100644
index d96facff7..000000000
--- a/src/sdks/react-native/android/src/main/cpp/include/oliphaunt.h
+++ /dev/null
@@ -1,257 +0,0 @@
-#ifndef OLIPHAUNT_H
-#define OLIPHAUNT_H
-
-#include 
-#include 
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define OLIPHAUNT_ABI_VERSION 10u
-#define OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION 1u
-#define OLIPHAUNT_ERROR_CAPTURE_CAPACITY 1024u
-#define OLIPHAUNT_STREAM_CALLBACK_ABORTED 1
-/* The caller already owns liboliphaunt's stable sibling root lease. */
-#define OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK (1ull << 0)
-
-#if defined(_WIN32) && defined(OLIPHAUNT_BUILDING_DLL)
-#define OLIPHAUNT_API __declspec(dllexport)
-#elif defined(_WIN32)
-#define OLIPHAUNT_API __declspec(dllimport)
-#else
-#define OLIPHAUNT_API
-#endif
-
-typedef struct OliphauntHandle OliphauntHandle;
-
-typedef struct OliphauntStaticExtensionSymbol {
-    const char *name;
-    void *address;
-} OliphauntStaticExtensionSymbol;
-
-typedef struct OliphauntStaticExtension {
-    uint32_t abi_version;
-    const char *name;
-    const void *(*magic)(void);
-    void (*init)(void);
-    const OliphauntStaticExtensionSymbol *symbols;
-    size_t symbol_count;
-    uint64_t reserved_flags;
-} OliphauntStaticExtension;
-
-/*
- * Direct-mode extension compatibility contract:
- *
- * oliphaunt_init sets the process PGDATA environment variable to this config's
- * pgdata path while the embedded backend is active, because PostgreSQL
- * extensions may read PGDATA through standard process APIs. oliphaunt_detach
- * releases a logical direct-mode lease but keeps the resident backend alive;
- * oliphaunt_close is terminal for the process lifetime and restores the caller's
- * previous PGDATA value, or unsets it if it was unset.
- *
- * Every successful oliphaunt_init establishes a current
- * logical lease generation. Hosts with independent cleanup owners must capture
- * its non-zero value immediately with oliphaunt_logical_generation and use
- * oliphaunt_close_if_generation: a stale owner then cannot terminate a newer
- * logical lease on the same resident handle.
- *
- * Callers that require process environment isolation should use broker/server
- * mode through the Rust SDK instead of keeping multiple direct-mode backends in
- * one process.
- */
-typedef struct OliphauntConfig {
-    uint32_t abi_version;
-    /* The pgdata child of an already-prepared managed root. Init does not create it. */
-    const char *pgdata;
-    const char *runtime_dir;
-    /*
-     * Exact PostgreSQL $libdir for the embedded handle. It must name an
-     * existing directory. Pass NULL to use OLIPHAUNT_EMBEDDED_MODULE_DIR and
-     * release-layout discovery.
-     */
-    const char *module_dir;
-    const char *username;
-    const char *database;
-    /* OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK or zero. */
-    uint64_t flags;
-    /* Zero or more `-c`, `name=value` pairs. Storage-routing GUCs are rejected. */
-    const char *const *startup_args;
-    size_t startup_arg_count;
-} OliphauntConfig;
-
-typedef struct OliphauntResponse {
-    uint8_t *data;
-    size_t len;
-} OliphauntResponse;
-
-/*
- * Operation-owned error storage for hosts whose FFI scheduler resumes the
- * caller on a different thread. The `_with_error` entry points below execute
- * the operation and capture its thread-local failure before that native
- * invocation returns. `length` excludes the trailing NUL and is at most
- * OLIPHAUNT_ERROR_CAPTURE_CAPACITY - 1; `message` is always NUL-terminated
- * and is empty on success. The entire capture is zeroed on success. Native
- * error sources use the same bound, so a valid runtime error is not
- * additionally truncated during capture.
- */
-typedef struct OliphauntErrorCapture {
-    uint32_t length;
-    char message[OLIPHAUNT_ERROR_CAPTURE_CAPACITY];
-} OliphauntErrorCapture;
-
-typedef struct OliphauntRestoreOptions {
-    uint32_t abi_version;
-    /* New or existing-empty managed-root path; this is not a PGDATA path. */
-    const char *destination;
-    /* Bytes in the single native physical archive format returned by oliphaunt_backup. */
-    const uint8_t *data;
-    size_t len;
-} OliphauntRestoreOptions;
-
-/*
- * Same-handle ownership and streaming contract:
- *
- * Hosts serialize ordinary non-cancel operations on one logical handle.
- * oliphaunt_cancel is the deliberate cross-thread exception and may interrupt
- * the active PostgreSQL operation. A successful detach ends that logical
- * lease; a successful close terminally invalidates the opaque handle, which
- * must never be dereferenced again.
- *
- * A raw-stream callback borrows data only for that callback invocation. It may
- * copy the bytes, inspect errors, or call oliphaunt_cancel. It must not call
- * query, backup, detach, close, or another raw-stream operation on the same
- * handle. Those calls fail with a busy error while streaming is active,
- * including from another thread, so the callback cannot corrupt protocol
- * ordering or free its own handle. A non-zero callback result stops later
- * callback delivery and drains the backend to ReadyForQuery. The stream then
- * returns OLIPHAUNT_STREAM_CALLBACK_ABORTED; negative results identify
- * validation, transport, backend, or recovery failures for which reuse may be
- * unsafe.
- */
-typedef int32_t (*OliphauntStreamCallback)(void *context, const uint8_t *data, size_t len);
-
-OLIPHAUNT_API int32_t oliphaunt_init(const OliphauntConfig *config, OliphauntHandle **out);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_exec_simple_query(
-    OliphauntHandle *handle,
-    const char *sql,
-    size_t sql_len,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context);
-/*
- * Creates a session-preserving online physical archive. If an error says that
- * backup-mode exit is unconfirmed, no later query is safe: detach/close the
- * handle and restart the process before reopening PostgreSQL.
- */
-OLIPHAUNT_API int32_t oliphaunt_backup(
-    OliphauntHandle *handle,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_restore(const OliphauntRestoreOptions *options);
-/*
- * Scheduler-safe variants for asynchronous FFI hosts. These preserve the
- * return code and response ownership of their corresponding operation while
- * filling a required caller-owned capture before returning.
- */
-OLIPHAUNT_API int32_t oliphaunt_init_with_error(
-    const OliphauntConfig *config,
-    OliphauntHandle **out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_with_error(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_simple_query_with_error(
-    OliphauntHandle *handle,
-    const char *sql,
-    size_t sql_len,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream_with_error(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_backup_with_error(
-    OliphauntHandle *handle,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_restore_with_error(
-    const OliphauntRestoreOptions *options,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_detach_with_error(
-    OliphauntHandle *handle,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_cancel(OliphauntHandle *handle);
-/* A poisoned backup session is terminally closed instead of retained. */
-OLIPHAUNT_API int32_t oliphaunt_detach(OliphauntHandle *handle);
-/*
- * Returns the non-zero generation of the currently published logical lease.
- * Returns zero for NULL, stale, terminally closed, or otherwise non-current
- * handles. The registry is validated before the opaque handle is dereferenced.
- */
-OLIPHAUNT_API uint64_t oliphaunt_logical_generation(OliphauntHandle *handle);
-/*
- * Terminally closes the process-wide resident handle only when generation
- * still owns its current logical lease. Returns 0 when terminal close completes
- * or had already completed, 1 for an active stale/non-owner generation no-op,
- * and -1 for generation zero or an internal failure.
- */
-OLIPHAUNT_API int32_t oliphaunt_close_if_generation(
-    uint64_t generation);
-/*
- * Unconditionally performs process-terminal close for the current published
- * resident handle. Hosts with multiple cleanup owners should use
- * oliphaunt_close_if_generation and retain only its generation token.
- */
-OLIPHAUNT_API int32_t oliphaunt_close(OliphauntHandle *handle);
-/*
- * Registers statically linked PostgreSQL extension modules for the embedded
- * backend's normal LOAD path.
- *
- * Call this before oliphaunt_init in processes that link extension code directly
- * into the application or SDK library. The registry is process-wide and becomes
- * immutable once backend startup begins. Each extension name is the module stem
- * used by SQL, for example AS 'vector', and each symbol row exposes the C
- * symbols PostgreSQL would otherwise resolve with dlsym().
- */
-OLIPHAUNT_API int32_t oliphaunt_register_static_extensions(const OliphauntStaticExtension *extensions, size_t count);
-/*
- * Copies an error into caller-owned storage. Immediately after a fallible C
- * operation returns failure, calls on that same thread read the operation's
- * owned snapshot. It takes precedence over the shared handle/global error and
- * remains stable across a size probe and repeated copies until the thread
- * begins another fallible C operation, even if another thread updates the
- * shared error. With no operation snapshot, this atomically reads the latest
- * handle error, or the process-global error when handle is NULL.
- *
- * The return value is the full UTF-8 byte length excluding the trailing NUL.
- * When capacity is non-zero, out must be non-NULL and is always
- * NUL-terminated; content is truncated when capacity is smaller than length +
- * 1.
- */
-OLIPHAUNT_API size_t oliphaunt_copy_last_error(
-    OliphauntHandle *handle,
-    char *out,
-    size_t capacity);
-OLIPHAUNT_API const char *oliphaunt_version(void);
-OLIPHAUNT_API void oliphaunt_free_response(OliphauntResponse *response);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntJsiPromiseCallback.kt b/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntJsiPromiseCallback.kt
index 15a967143..ba48713f8 100644
--- a/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntJsiPromiseCallback.kt
+++ b/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntJsiPromiseCallback.kt
@@ -4,29 +4,30 @@ import com.facebook.proguard.annotations.DoNotStrip
 
 @DoNotStrip
 class OliphauntJsiPromiseCallback @DoNotStrip constructor(
+  private val ownerId: Long,
   private val token: Long,
 ) : OliphauntJsiCallback {
   override fun resolveBytes(response: ByteArray) {
-    nativeResolveBytes(token, response)
+    nativeResolveBytes(ownerId, token, response)
   }
 
   override fun resolveString(value: String) {
-    nativeResolveString(token, value)
+    nativeResolveString(ownerId, token, value)
   }
 
   override fun resolveUnit() {
-    nativeResolveUnit(token)
+    nativeResolveUnit(ownerId, token)
   }
 
   override fun reject(code: String, message: String?) {
-    nativeReject(token, if (message.isNullOrBlank()) code else "$code: $message")
+    nativeReject(ownerId, token, if (message.isNullOrBlank()) code else "$code: $message")
   }
 
-  private external fun nativeResolveBytes(token: Long, response: ByteArray)
+  private external fun nativeResolveBytes(ownerId: Long, token: Long, response: ByteArray)
 
-  private external fun nativeResolveString(token: Long, value: String)
+  private external fun nativeResolveString(ownerId: Long, token: Long, value: String)
 
-  private external fun nativeResolveUnit(token: Long)
+  private external fun nativeResolveUnit(ownerId: Long, token: Long)
 
-  private external fun nativeReject(token: Long, message: String)
+  private external fun nativeReject(ownerId: Long, token: Long, message: String)
 }
diff --git a/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntJsiStreamCallback.kt b/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntJsiStreamCallback.kt
index 88b7a9d80..b8091e188 100644
--- a/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntJsiStreamCallback.kt
+++ b/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntJsiStreamCallback.kt
@@ -4,34 +4,36 @@ import com.facebook.proguard.annotations.DoNotStrip
 
 @DoNotStrip
 class OliphauntJsiStreamCallback @DoNotStrip constructor(
+  private val ownerId: Long,
   private val token: Long,
 ) {
   fun emitChunk(chunk: ByteArray) {
-    nativeEmitChunk(token, chunk)?.let { error ->
+    nativeEmitChunk(ownerId, token, chunk)?.let { error ->
       throw IllegalStateException(error)
     }
   }
 
   fun resolveUnit() {
-    nativeResolveUnit(token)
+    nativeResolveUnit(ownerId, token)
   }
 
   fun rejectCallbackAborted(message: String?) {
     nativeRejectCallbackAborted(
+      ownerId,
       token,
       message ?: "protocol stream callback aborted after recovery to ReadyForQuery",
     )
   }
 
   fun reject(code: String, message: String?) {
-    nativeReject(token, if (message.isNullOrBlank()) code else "$code: $message")
+    nativeReject(ownerId, token, if (message.isNullOrBlank()) code else "$code: $message")
   }
 
-  private external fun nativeEmitChunk(token: Long, chunk: ByteArray): String?
+  private external fun nativeEmitChunk(ownerId: Long, token: Long, chunk: ByteArray): String?
 
-  private external fun nativeResolveUnit(token: Long)
+  private external fun nativeResolveUnit(ownerId: Long, token: Long)
 
-  private external fun nativeRejectCallbackAborted(token: Long, message: String)
+  private external fun nativeRejectCallbackAborted(ownerId: Long, token: Long, message: String)
 
-  private external fun nativeReject(token: Long, message: String)
+  private external fun nativeReject(ownerId: Long, token: Long, message: String)
 }
diff --git a/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntModule.kt b/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntModule.kt
index 90f44c557..7cfb628b9 100644
--- a/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntModule.kt
+++ b/src/sdks/react-native/android/src/main/java/dev/oliphaunt/reactnative/OliphauntModule.kt
@@ -59,6 +59,9 @@ internal fun requireReactNativeHandle(handle: Long): Long {
 class OliphauntModule(
   private val reactContext: ReactApplicationContext,
 ) : NativeOliphauntSpec(reactContext), TurboModuleWithJSIBindings {
+  @DoNotStrip
+  private var jsiOwnerId: Long = 0
+
   private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
   private val sessions = ConcurrentHashMap()
   private val sessionMutex = Mutex()
diff --git a/src/sdks/react-native/android/src/test/java/dev/oliphaunt/reactnative/OliphauntAndroidBoundaryTest.kt b/src/sdks/react-native/android/src/test/java/dev/oliphaunt/reactnative/OliphauntAndroidBoundaryTest.kt
index 12c77cece..fccab283e 100644
--- a/src/sdks/react-native/android/src/test/java/dev/oliphaunt/reactnative/OliphauntAndroidBoundaryTest.kt
+++ b/src/sdks/react-native/android/src/test/java/dev/oliphaunt/reactnative/OliphauntAndroidBoundaryTest.kt
@@ -134,23 +134,6 @@ class OliphauntAndroidBoundaryTest {
   fun reactNativeAndroidDelegatesRuntimeToKotlinSdk() {
     assertEquals("dev.oliphaunt.Oliphaunt", Oliphaunt::class.java.name)
 
-    val nativeSourceDir = File(System.getProperty("user.dir"), "src/main/cpp")
-    val nativeSources = nativeSourceDir
-      .takeIf(File::isDirectory)
-      ?.walkTopDown()
-      ?.filter(File::isFile)
-      ?.toList()
-      ?: emptyList()
-
-    val nativeSourceNames = nativeSources
-      .map { it.relativeTo(nativeSourceDir).invariantSeparatorsPath }
-      .sorted()
-    assertEquals(
-      "React Native Android should only carry the JSI installer and must not duplicate the native C++ runtime",
-      listOf("CMakeLists.txt", "OliphauntJsiBindings.cpp", "include/oliphaunt.h"),
-      nativeSourceNames,
-    )
-
     val moduleSource = File(
       System.getProperty("user.dir"),
       "src/main/java/dev/oliphaunt/reactnative/OliphauntModule.kt",
diff --git a/src/sdks/react-native/app.plugin.cts b/src/sdks/react-native/app.plugin.cts
new file mode 100644
index 000000000..8f2a105e2
--- /dev/null
+++ b/src/sdks/react-native/app.plugin.cts
@@ -0,0 +1,1053 @@
+const fs = require('node:fs');
+const path = require('node:path');
+const { pathToFileURL } = require('node:url');
+
+const EXTENSION_NAME_RE = /^[A-Za-z0-9._-]{1,128}$/;
+const packageMetadata = require('./package.json');
+const packagedExtensionMetadata = path.join(__dirname, 'src/generated/extensions.json');
+const repositoryExtensionMetadata = path.join(
+  __dirname,
+  '../../extensions/generated/sdk/extensions.json',
+);
+const extensionMetadata = require(
+  fs.existsSync(packagedExtensionMetadata)
+    ? packagedExtensionMetadata
+    : repositoryExtensionMetadata,
+);
+const IOS_PODFILE_START = '# @oliphaunt/react-native begin';
+const IOS_PODFILE_END = '# @oliphaunt/react-native end';
+const IOS_MINIMUM_DEPLOYMENT_TARGET = '17.0';
+const IOS_CARRIER_SCHEMA = 'oliphaunt-react-native-ios-carrier-v1';
+const IOS_CARRIER_FILENAME = 'oliphaunt-react-native-ios-carriers.json';
+const IOS_BASE_CARRIER_ENV = 'OLIPHAUNT_REACT_NATIVE_IOS_BASE_CARRIER';
+const IOS_EXTENSION_CARRIERS_ENV = 'OLIPHAUNT_REACT_NATIVE_IOS_EXTENSION_CARRIERS';
+const IOS_CARRIER_CACHE_ENV = 'OLIPHAUNT_REACT_NATIVE_IOS_CACHE_DIR';
+const IOS_ALLOW_FILE_URLS_ENV = 'OLIPHAUNT_REACT_NATIVE_IOS_ALLOW_FILE_URLS';
+const ANDROID_APP_PLUGIN_RE = /id\s*(?:\(\s*)?['"]dev\.oliphaunt\.android['"]/;
+const STABLE_SEMVER_RE = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/;
+const KNOWN_EXTENSION_SQL_NAMES = new Set(
+  extensionMetadata.extensions.map((extension) => extension['sql-name']),
+);
+const EXTENSION_METADATA_BY_SQL_NAME = new Map(
+  extensionMetadata.extensions.map((extension) => [extension['sql-name'], extension]),
+);
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function normalizeOptions(options = {}) {
+  const extensions = Array.isArray(options.extensions) ? options.extensions : [];
+  const selected = [
+    ...new Set(extensions.map((value) => String(value).trim()).filter(Boolean)),
+  ].sort();
+  for (const extension of selected) {
+    if (!EXTENSION_NAME_RE.test(extension)) {
+      throw new Error(
+        `@oliphaunt/react-native extension '${extension}' must be an exact PostgreSQL extension name`,
+      );
+    }
+    if (!KNOWN_EXTENSION_SQL_NAMES.has(extension)) {
+      throw new Error(
+        `@oliphaunt/react-native extension '${extension}' is not in the generated exact-extension catalog`,
+      );
+    }
+  }
+  const seedProfile = optionalString(options.seedProfile);
+  if (seedProfile !== undefined && !['standard', 'icu'].includes(seedProfile)) {
+    throw new Error('@oliphaunt/react-native seedProfile must be standard or icu');
+  }
+  return {
+    extensions: selected,
+    icu: Boolean(options.icu) || seedProfile === 'icu',
+    seedProfile,
+    databaseResourcesVersion: optionalString(options.databaseResourcesVersion),
+    liboliphauntVersion: optionalString(options.liboliphauntVersion),
+    assetBaseUrl: optionalString(options.assetBaseUrl),
+    kotlinPluginVersion:
+      optionalString(options.kotlinPluginVersion) ?? packageMetadata.oliphaunt?.kotlinSdkVersion,
+  };
+}
+
+function optionalString(value) {
+  if (value == null) {
+    return undefined;
+  }
+  const stringValue = String(value).trim();
+  return stringValue.length > 0 ? stringValue : undefined;
+}
+
+function extensionPackageName(sqlName) {
+  const extension = EXTENSION_METADATA_BY_SQL_NAME.get(sqlName);
+  if (!extension) {
+    throw new Error(`unknown Oliphaunt extension SQL name ${sqlName}`);
+  }
+  return extension['npm-package'];
+}
+
+function selectedExtensionClosure(extensions) {
+  const selected = new Set();
+  const visiting = new Set();
+  function visit(sqlName) {
+    if (selected.has(sqlName)) {
+      return;
+    }
+    if (visiting.has(sqlName)) {
+      throw new Error(`generated extension dependency cycle includes ${sqlName}`);
+    }
+    const extension = EXTENSION_METADATA_BY_SQL_NAME.get(sqlName);
+    if (!extension) {
+      throw new Error(`unknown Oliphaunt extension SQL name ${sqlName}`);
+    }
+    visiting.add(sqlName);
+    for (const dependency of extension['selected-extension-dependencies'] ?? []) {
+      visit(dependency);
+    }
+    visiting.delete(sqlName);
+    selected.add(sqlName);
+  }
+  for (const sqlName of extensions) {
+    visit(sqlName);
+  }
+  return [...selected].sort();
+}
+
+function releaseOwnerForSqlName(sqlName) {
+  const extension = EXTENSION_METADATA_BY_SQL_NAME.get(sqlName);
+  if (!extension) {
+    throw new Error(`unknown Oliphaunt extension SQL name ${sqlName}`);
+  }
+  const members = extensionMetadata.extensions
+    .filter(
+      (candidate) =>
+        candidate['artifact-product'] === extension['artifact-product'] &&
+        candidate['npm-package'] === extension['npm-package'],
+    )
+    .map((candidate) => candidate['sql-name'])
+    .sort();
+  if (
+    members.length === 0 ||
+    extensionMetadata.extensions
+      .filter((candidate) => members.includes(candidate['sql-name']))
+      .some(
+        (candidate) =>
+          candidate['maven-group'] !== extension['maven-group'] ||
+          candidate['maven-artifact'] !== extension['maven-artifact'] ||
+          candidate['runtime-bound'] !== extension['runtime-bound'],
+      )
+  ) {
+    throw new Error(`generated extension ownership metadata is inconsistent for ${sqlName}`);
+  }
+  return {
+    artifactProduct: extension['artifact-product'],
+    members,
+    mavenArtifact: extension['maven-artifact'],
+    mavenGroup: extension['maven-group'],
+    npmPackage: extension['npm-package'],
+    releaseProduct: extension['release-product'],
+    runtimeBound: extension['runtime-bound'] === true,
+  };
+}
+
+function absoluteFromProject(projectRoot, value, label) {
+  if (typeof value !== 'string' || value.trim() === '') {
+    throw new Error(`${label} must be a non-empty path`);
+  }
+  return path.resolve(projectRoot, value);
+}
+
+function readJsonObject(file, label) {
+  let value;
+  try {
+    value = JSON.parse(fs.readFileSync(file, 'utf8'));
+  } catch (error) {
+    throw new Error(`${label} could not be read from ${file}: ${error.message}`);
+  }
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    throw new Error(`${label} at ${file} must be a JSON object`);
+  }
+  return value;
+}
+
+function readCarrierSummary(file, label = 'iOS carrier manifest') {
+  const manifest = readJsonObject(file, label);
+  if (manifest.schema !== IOS_CARRIER_SCHEMA) {
+    throw new Error(`${label} at ${file} must declare schema=${IOS_CARRIER_SCHEMA}`);
+  }
+  if (manifest.base === null || Array.isArray(manifest.base) || typeof manifest.base !== 'object') {
+    throw new Error(`${label} at ${file} must contain a base carrier object`);
+  }
+  if (
+    manifest.base.product !== 'liboliphaunt-native' ||
+    typeof manifest.base.version !== 'string' ||
+    !STABLE_SEMVER_RE.test(manifest.base.version) ||
+    manifest.base.tag !== `liboliphaunt-native-v${manifest.base.version}`
+  ) {
+    throw new Error(`${label} at ${file} contains an invalid base release identity`);
+  }
+  if (!Array.isArray(manifest.carriers)) {
+    throw new Error(`${label} at ${file} must contain a carriers array`);
+  }
+  const carrierNames = new Set();
+  for (const [index, carrier] of manifest.carriers.entries()) {
+    if (carrier === null || Array.isArray(carrier) || typeof carrier !== 'object') {
+      throw new Error(`${label} at ${file} carriers[${index}] must be an object`);
+    }
+    if (
+      typeof carrier.name !== 'string' ||
+      carrier.name.length === 0 ||
+      typeof carrier.url !== 'string' ||
+      carrier.url.length === 0 ||
+      typeof carrier.sha256 !== 'string' ||
+      !/^[0-9a-f]{64}$/.test(carrier.sha256) ||
+      !Number.isSafeInteger(carrier.bytes) ||
+      carrier.bytes <= 0 ||
+      !['zip', 'tar.gz'].includes(carrier.format)
+    ) {
+      throw new Error(`${label} at ${file} carriers[${index}] is invalid`);
+    }
+    if (carrierNames.has(carrier.name)) {
+      throw new Error(`${label} at ${file} repeats carrier ${carrier.name}`);
+    }
+    carrierNames.add(carrier.name);
+  }
+  if (!Array.isArray(manifest.extensions)) {
+    throw new Error(`${label} at ${file} must contain an extensions array`);
+  }
+  const releasesByOwner = new Map();
+  const extensions = manifest.extensions.map((row, index) => {
+    if (row === null || Array.isArray(row) || typeof row !== 'object') {
+      throw new Error(`${label} at ${file} extensions[${index}] must be an object`);
+    }
+    if (typeof row.sqlName !== 'string' || !EXTENSION_NAME_RE.test(row.sqlName)) {
+      throw new Error(`${label} at ${file} extensions[${index}].sqlName is invalid`);
+    }
+    if (
+      !Array.isArray(row.dependencies) ||
+      row.dependencies.some(
+        (dependency) => typeof dependency !== 'string' || !EXTENSION_NAME_RE.test(dependency),
+      )
+    ) {
+      throw new Error(`${label} at ${file} extension ${row.sqlName} has invalid dependencies`);
+    }
+    const dependencies = [...new Set(row.dependencies)].sort();
+    if (dependencies.length !== row.dependencies.length) {
+      throw new Error(`${label} at ${file} extension ${row.sqlName} repeats a dependency`);
+    }
+    const owner = releaseOwnerForSqlName(row.sqlName);
+    if (row.product !== owner.artifactProduct) {
+      throw new Error(
+        `${label} at ${file} extension ${row.sqlName} must belong to ${owner.artifactProduct}`,
+      );
+    }
+    if (row.releaseProduct !== owner.releaseProduct) {
+      throw new Error(
+        `${label} at ${file} extension ${row.sqlName} must be owned by ${owner.releaseProduct}`,
+      );
+    }
+    if (typeof row.version !== 'string' || !STABLE_SEMVER_RE.test(row.version)) {
+      throw new Error(
+        `${label} at ${file} extension ${row.sqlName} has an invalid stable SemVer version`,
+      );
+    }
+    const expectedTag = `${owner.releaseProduct}-v${row.version}`;
+    if (row.tag !== expectedTag) {
+      throw new Error(`${label} at ${file} extension ${row.sqlName}.tag must be ${expectedTag}`);
+    }
+    const generatedDependencies = [
+      ...(EXTENSION_METADATA_BY_SQL_NAME.get(row.sqlName)?.['selected-extension-dependencies'] ??
+        []),
+    ].sort();
+    if (JSON.stringify(dependencies) !== JSON.stringify(generatedDependencies)) {
+      throw new Error(
+        `${label} at ${file} extension ${row.sqlName} dependencies do not match generated metadata`,
+      );
+    }
+    const release = `${row.version}\0${row.tag}`;
+    const previousRelease = releasesByOwner.get(row.releaseProduct);
+    if (previousRelease !== undefined && previousRelease !== release) {
+      throw new Error(
+        `${label} at ${file} contains conflicting releases for owner ${owner.releaseProduct}`,
+      );
+    }
+    releasesByOwner.set(row.releaseProduct, release);
+    if (owner.runtimeBound && row.version !== manifest.base.version) {
+      throw new Error(
+        `${label} at ${file} runtime-bound owner ${owner.releaseProduct} version ${row.version} ` +
+          `must match base ${manifest.base.version}`,
+      );
+    }
+    return {
+      dependencies,
+      product: owner.artifactProduct,
+      releaseProduct: owner.releaseProduct,
+      sqlName: row.sqlName,
+      tag: row.tag,
+      version: row.version,
+    };
+  });
+  if (new Set(extensions.map(({ sqlName }) => sqlName)).size !== extensions.length) {
+    throw new Error(`${label} at ${file} repeats an extension row`);
+  }
+  return {
+    base: {
+      product: manifest.base.product,
+      tag: manifest.base.tag,
+      version: manifest.base.version,
+    },
+    carriers: manifest.carriers,
+    extensions,
+    file: path.resolve(file),
+  };
+}
+
+function carrierPointerFromPackage(packageJsonFile, expectedPackageName, owner) {
+  const installedOwner = owner
+    ? validateInstalledExtensionOwner(packageJsonFile, owner)
+    : undefined;
+  const packageJson =
+    installedOwner?.packageJson ??
+    readJsonObject(packageJsonFile, `${expectedPackageName} package metadata`);
+  if (packageJson.name !== expectedPackageName) {
+    throw new Error(
+      `${expectedPackageName} resolved to package metadata for ${String(packageJson.name)}`,
+    );
+  }
+  const pointer = packageJson.oliphaunt?.iosCarrierManifest;
+  if (typeof pointer !== 'string' || pointer.trim() === '') {
+    throw new Error(
+      `${expectedPackageName} must declare package.json.oliphaunt.iosCarrierManifest`,
+    );
+  }
+  const packageRoot = path.dirname(packageJsonFile);
+  const carrier = path.resolve(packageRoot, pointer);
+  const relative = path.relative(packageRoot, carrier);
+  if (relative.startsWith('..') || path.isAbsolute(relative)) {
+    throw new Error(`${expectedPackageName} iOS carrier manifest must stay inside its package`);
+  }
+  if (
+    path.basename(carrier) !== IOS_CARRIER_FILENAME ||
+    !fs.statSync(carrier, { throwIfNoEntry: false })?.isFile()
+  ) {
+    throw new Error(
+      `${expectedPackageName} iOS carrier manifest must be the packaged ${IOS_CARRIER_FILENAME}`,
+    );
+  }
+  return {
+    carrier,
+    ownerLiboliphauntVersion: installedOwner?.liboliphauntVersion,
+    ownerVersion: installedOwner?.version,
+    packageRoot,
+  };
+}
+
+function resolvePackageJson(packageName, searchPaths) {
+  try {
+    return require.resolve(`${packageName}/package.json`, { paths: searchPaths });
+  } catch (error) {
+    throw new Error(
+      `selected extension requires installed package ${packageName}: ${error.message}`,
+    );
+  }
+}
+
+function validateInstalledExtensionOwner(packageJsonFile, owner) {
+  const packageJson = readJsonObject(packageJsonFile, `${owner.npmPackage} package metadata`);
+  if (packageJson.name !== owner.npmPackage) {
+    throw new Error(
+      `${owner.npmPackage} resolved to package metadata for ${String(packageJson.name)}`,
+    );
+  }
+  if (
+    typeof packageJson.version !== 'string' ||
+    packageJson.version.length === 0 ||
+    !STABLE_SEMVER_RE.test(packageJson.version)
+  ) {
+    throw new Error(`${owner.npmPackage} package metadata has an invalid version`);
+  }
+  if (packageJson.oliphaunt?.product !== owner.artifactProduct) {
+    throw new Error(
+      `${owner.npmPackage} package metadata does not declare ${owner.artifactProduct}`,
+    );
+  }
+  const expectedKind = owner.members.length > 1 ? 'exact-extension-bundle' : 'exact-extension';
+  if (packageJson.oliphaunt?.kind !== expectedKind) {
+    throw new Error(`${owner.npmPackage} package metadata does not declare ${expectedKind}`);
+  }
+  if (owner.members.length > 1) {
+    if (JSON.stringify(packageJson.oliphaunt?.members) !== JSON.stringify(owner.members)) {
+      throw new Error(
+        `${owner.npmPackage} package metadata members do not match its generated release ownership`,
+      );
+    }
+  } else if (packageJson.oliphaunt?.sqlName !== owner.members[0]) {
+    throw new Error(
+      `${owner.npmPackage} package metadata does not declare SQL extension ${owner.members[0]}`,
+    );
+  }
+  const liboliphauntVersion = packageJson.oliphaunt?.liboliphauntVersion;
+  if (
+    typeof liboliphauntVersion !== 'string' ||
+    liboliphauntVersion.length === 0 ||
+    !STABLE_SEMVER_RE.test(liboliphauntVersion)
+  ) {
+    throw new Error(`${owner.npmPackage} package metadata does not pin liboliphauntVersion`);
+  }
+  if (owner.runtimeBound && packageJson.version !== liboliphauntVersion) {
+    throw new Error(
+      `${owner.npmPackage} is runtime-bound but version ${packageJson.version} does not match liboliphauntVersion ${liboliphauntVersion}`,
+    );
+  }
+  return {
+    liboliphauntVersion,
+    packageJson,
+    packageJsonFile: path.resolve(packageJsonFile),
+    packageRoot: path.dirname(packageJsonFile),
+    version: packageJson.version,
+  };
+}
+
+function resolveInstalledExtensionOwners(
+  projectRoot,
+  extensions,
+  { liboliphauntVersion, packageJsonResolver = resolvePackageJson } = {},
+) {
+  const closure = selectedExtensionClosure(extensions);
+  const ownersByPackage = new Map();
+  for (const sqlName of closure) {
+    const owner = releaseOwnerForSqlName(sqlName);
+    const previous = ownersByPackage.get(owner.npmPackage);
+    if (previous) {
+      if (
+        previous.artifactProduct !== owner.artifactProduct ||
+        previous.releaseProduct !== owner.releaseProduct ||
+        previous.mavenGroup !== owner.mavenGroup ||
+        previous.mavenArtifact !== owner.mavenArtifact ||
+        previous.runtimeBound !== owner.runtimeBound ||
+        JSON.stringify(previous.members) !== JSON.stringify(owner.members)
+      ) {
+        throw new Error(`selected SQL members disagree about release owner ${owner.npmPackage}`);
+      }
+      continue;
+    }
+    ownersByPackage.set(owner.npmPackage, owner);
+  }
+
+  const resolved = [];
+  const versionsByMavenCoordinate = new Map();
+  const extensionVersions = {};
+  let compatibleRuntimeVersion = optionalString(liboliphauntVersion);
+  for (const owner of [...ownersByPackage.values()].sort((left, right) =>
+    compareText(left.npmPackage, right.npmPackage),
+  )) {
+    const packageJsonFile = packageJsonResolver(owner.npmPackage, [projectRoot]);
+    const installed = validateInstalledExtensionOwner(packageJsonFile, owner);
+    if (
+      compatibleRuntimeVersion !== undefined &&
+      compatibleRuntimeVersion !== installed.liboliphauntVersion
+    ) {
+      throw new Error(
+        `${owner.npmPackage} requires liboliphaunt ${installed.liboliphauntVersion}, but the app selected ${compatibleRuntimeVersion}`,
+      );
+    }
+    compatibleRuntimeVersion ??= installed.liboliphauntVersion;
+    const coordinate = `${owner.mavenGroup}:${owner.mavenArtifact}`;
+    const previousVersion = versionsByMavenCoordinate.get(coordinate);
+    if (previousVersion !== undefined && previousVersion !== installed.version) {
+      throw new Error(
+        `selected extension packages require conflicting versions ${previousVersion} and ${installed.version} for ${coordinate}`,
+      );
+    }
+    versionsByMavenCoordinate.set(coordinate, installed.version);
+    const previousOwnerVersion = extensionVersions[owner.releaseProduct];
+    if (previousOwnerVersion !== undefined && previousOwnerVersion !== installed.version) {
+      throw new Error(
+        `selected extension packages require conflicting versions for ${owner.releaseProduct}`,
+      );
+    }
+    extensionVersions[owner.releaseProduct] = installed.version;
+    resolved.push({ ...owner, ...installed });
+  }
+  return {
+    closure,
+    extensionVersions,
+    liboliphauntVersion: compatibleRuntimeVersion,
+    owners: resolved,
+  };
+}
+
+function serializeExtensionVersions(extensionVersions) {
+  return Object.entries(extensionVersions)
+    .sort(([left], [right]) => compareText(left, right))
+    .map(([owner, version]) => `${owner}=${version}`)
+    .join(',');
+}
+
+function parseExtensionCarrierOverrides(projectRoot, value) {
+  if (value == null || String(value).trim() === '') {
+    return new Map();
+  }
+  let parsed;
+  try {
+    parsed = JSON.parse(String(value));
+  } catch (error) {
+    throw new Error(`${IOS_EXTENSION_CARRIERS_ENV} must be a JSON object: ${error.message}`);
+  }
+  if (parsed === null || Array.isArray(parsed) || typeof parsed !== 'object') {
+    throw new Error(`${IOS_EXTENSION_CARRIERS_ENV} must be a JSON object keyed by SQL name`);
+  }
+  const result = new Map();
+  for (const [sqlName, file] of Object.entries(parsed)) {
+    if (!EXTENSION_NAME_RE.test(sqlName)) {
+      throw new Error(`${IOS_EXTENSION_CARRIERS_ENV} contains invalid SQL name ${sqlName}`);
+    }
+    result.set(
+      sqlName,
+      absoluteFromProject(projectRoot, file, `${IOS_EXTENSION_CARRIERS_ENV}.${sqlName}`),
+    );
+  }
+  return result;
+}
+
+function validateAggregateCarrierClosure(summary, selected) {
+  const bySqlName = new Map(summary.extensions.map((row) => [row.sqlName, row]));
+  const visited = new Set();
+  const visiting = new Set();
+
+  function visit(sqlName, requiredBy) {
+    if (visited.has(sqlName)) {
+      return;
+    }
+    if (visiting.has(sqlName)) {
+      throw new Error(`aggregate iOS carrier dependency cycle includes ${sqlName}`);
+    }
+    const row = bySqlName.get(sqlName);
+    if (!row) {
+      throw new Error(
+        `aggregate iOS carrier is missing ${sqlName}${requiredBy ? ` required by ${requiredBy}` : ''}`,
+      );
+    }
+    visiting.add(sqlName);
+    for (const dependency of row.dependencies) {
+      visit(dependency, sqlName);
+    }
+    visiting.delete(sqlName);
+    visited.add(sqlName);
+  }
+
+  for (const sqlName of selected) {
+    visit(sqlName, undefined);
+  }
+}
+
+function resolveIosCarrierManifests(
+  projectRoot,
+  extensions,
+  { basePackageRoot = __dirname, env = process.env, packageJsonResolver = resolvePackageJson } = {},
+) {
+  const selected = [...new Set(extensions)].sort();
+  const baseCarrierOverride = optionalString(env[IOS_BASE_CARRIER_ENV]);
+  let baseCarrier;
+  if (baseCarrierOverride) {
+    baseCarrier = absoluteFromProject(projectRoot, baseCarrierOverride, IOS_BASE_CARRIER_ENV);
+  } else {
+    baseCarrier = carrierPointerFromPackage(
+      path.join(basePackageRoot, 'package.json'),
+      '@oliphaunt/react-native',
+    ).carrier;
+  }
+  const baseSummary = readCarrierSummary(baseCarrier, 'React Native base iOS carrier manifest');
+  const overrides = parseExtensionCarrierOverrides(projectRoot, env[IOS_EXTENSION_CARRIERS_ENV]);
+  if (baseCarrierOverride && baseSummary.extensions.length > 0) {
+    if (overrides.size > 0) {
+      throw new Error(
+        `${IOS_EXTENSION_CARRIERS_ENV} cannot be combined with an aggregate ${IOS_BASE_CARRIER_ENV}`,
+      );
+    }
+    validateAggregateCarrierClosure(baseSummary, selected);
+    return [baseSummary.file];
+  }
+  if (baseSummary.extensions.length !== 0) {
+    throw new Error(
+      'the installed @oliphaunt/react-native base iOS carrier manifest must be extension-free',
+    );
+  }
+
+  const visited = new Set();
+  const visiting = new Set();
+  const extensionCarriers = [];
+  const extensionCarrierFiles = new Set();
+  const installedOwnerCarriers = new Map();
+  const releasesByOwner = new Map();
+
+  function registerOwnerReleases(summary) {
+    for (const row of summary.extensions) {
+      const release = `${row.version}\0${row.tag}`;
+      const previous = releasesByOwner.get(row.releaseProduct);
+      if (previous !== undefined && previous !== release) {
+        throw new Error(
+          `iOS carrier manifests require conflicting releases for owner ${row.releaseProduct}`,
+        );
+      }
+      releasesByOwner.set(row.releaseProduct, release);
+    }
+  }
+
+  function visit(sqlName, searchPaths, requiredBy) {
+    if (visited.has(sqlName)) {
+      return;
+    }
+    if (visiting.has(sqlName)) {
+      throw new Error(`iOS carrier dependency cycle includes ${sqlName}`);
+    }
+    visiting.add(sqlName);
+    const owner = releaseOwnerForSqlName(sqlName);
+    const packageName = owner.npmPackage;
+    let carrier;
+    let dependencySearchPaths = searchPaths;
+    let installedOwnerLiboliphauntVersion;
+    let installedOwnerVersion;
+    let summary;
+    if (overrides.has(sqlName)) {
+      carrier = overrides.get(sqlName);
+    } else {
+      const cached = installedOwnerCarriers.get(packageName);
+      if (cached) {
+        carrier = cached.carrier;
+        dependencySearchPaths = cached.dependencySearchPaths;
+        installedOwnerLiboliphauntVersion = cached.installedOwnerLiboliphauntVersion;
+        installedOwnerVersion = cached.installedOwnerVersion;
+        summary = cached.summary;
+      } else {
+        let packageJsonFile;
+        try {
+          packageJsonFile = packageJsonResolver(packageName, searchPaths);
+        } catch (error) {
+          const suffix = requiredBy ? ` required by ${requiredBy}` : '';
+          throw new Error(`missing ${packageName}${suffix}: ${error.message}`);
+        }
+        const resolved = carrierPointerFromPackage(packageJsonFile, packageName, owner);
+        carrier = resolved.carrier;
+        installedOwnerLiboliphauntVersion = resolved.ownerLiboliphauntVersion;
+        installedOwnerVersion = resolved.ownerVersion;
+        dependencySearchPaths = [resolved.packageRoot, ...searchPaths];
+        summary = readCarrierSummary(carrier, `${packageName} iOS carrier manifest`);
+        const carrierMembers = summary.extensions.map((row) => row.sqlName).sort();
+        if (JSON.stringify(carrierMembers) !== JSON.stringify(owner.members)) {
+          throw new Error(
+            `${packageName} iOS carrier members do not match its generated release ownership`,
+          );
+        }
+        installedOwnerCarriers.set(packageName, {
+          carrier,
+          dependencySearchPaths,
+          installedOwnerLiboliphauntVersion,
+          installedOwnerVersion,
+          summary,
+        });
+      }
+    }
+    summary ??= readCarrierSummary(carrier, `${packageName} iOS carrier manifest`);
+    if (JSON.stringify(summary.base) !== JSON.stringify(baseSummary.base)) {
+      throw new Error(
+        `${packageName} iOS carrier pins ${summary.base.tag}, but the selected base carrier ` +
+          `pins ${baseSummary.base.tag}`,
+      );
+    }
+    if (
+      installedOwnerLiboliphauntVersion !== undefined &&
+      summary.base.version !== installedOwnerLiboliphauntVersion
+    ) {
+      throw new Error(
+        `${packageName} iOS carrier base ${summary.base.version} does not match installed package ` +
+          `liboliphauntVersion ${installedOwnerLiboliphauntVersion}`,
+      );
+    }
+    registerOwnerReleases(summary);
+    const extensionRow = summary.extensions.find((row) => row.sqlName === sqlName);
+    if (!extensionRow) {
+      throw new Error(
+        `${packageName} iOS carrier manifest does not contain the ${sqlName} extension row`,
+      );
+    }
+    if (installedOwnerVersion !== undefined && extensionRow.version !== installedOwnerVersion) {
+      throw new Error(
+        `${packageName} iOS carrier version ${extensionRow.version} does not match installed package ` +
+          `version ${installedOwnerVersion}`,
+      );
+    }
+    for (const dependency of extensionRow.dependencies) {
+      visit(dependency, dependencySearchPaths, sqlName);
+    }
+    visiting.delete(sqlName);
+    visited.add(sqlName);
+    if (!extensionCarrierFiles.has(summary.file)) {
+      extensionCarrierFiles.add(summary.file);
+      extensionCarriers.push(summary.file);
+    }
+  }
+
+  for (const sqlName of selected) {
+    visit(sqlName, [projectRoot], undefined);
+  }
+  return [baseSummary.file, ...extensionCarriers];
+}
+
+function explicitBooleanEnv(env, name) {
+  const value = optionalString(env[name]);
+  if (value === undefined || value === '0' || value === 'false') {
+    return false;
+  }
+  if (value === '1' || value === 'true') {
+    return true;
+  }
+  throw new Error(`${name} must be one of 1, 0, true, or false`);
+}
+
+function iosStageOptions(
+  projectRoot,
+  iosRoot,
+  normalized,
+  { basePackageRoot = __dirname, env = process.env, packageJsonResolver = resolvePackageJson } = {},
+) {
+  const cacheDir = optionalString(env[IOS_CARRIER_CACHE_ENV]);
+  return {
+    carriers: resolveIosCarrierManifests(projectRoot, normalized.extensions, {
+      basePackageRoot,
+      env,
+      packageJsonResolver,
+    }),
+    outputDir: path.join(iosRoot, 'oliphaunt'),
+    extensions: normalized.extensions,
+    icu: normalized.icu,
+    seedProfile: normalized.seedProfile,
+    cacheDir: cacheDir
+      ? absoluteFromProject(projectRoot, cacheDir, IOS_CARRIER_CACHE_ENV)
+      : undefined,
+    allowFileUrls: explicitBooleanEnv(env, IOS_ALLOW_FILE_URLS_ENV),
+  };
+}
+
+async function stageIosAppPayload(projectRoot, iosRoot, normalized, options = {}) {
+  const staging = iosStageOptions(projectRoot, iosRoot, normalized, options);
+  const helper = path.join(__dirname, 'tools', 'stage-ios-app.mjs');
+  const stageIosApp =
+    options.stageIosAppImpl ??
+    (
+      await import(
+        pathToFileURL(
+          fs.existsSync(helper) ? helper : path.join(__dirname, 'tools', 'stage-ios-app.mts'),
+        ).href
+      )
+    ).stageIosApp;
+  const result = await stageIosApp(staging);
+  const podspec = path.join(staging.outputDir, 'OliphauntReactNativePayload.podspec');
+  if (!fs.statSync(podspec, { throwIfNoEntry: false })?.isFile()) {
+    throw new Error(`iOS carrier resolver did not produce ${podspec}`);
+  }
+  return result;
+}
+
+function ensureDir(dir) {
+  fs.mkdirSync(dir, { recursive: true });
+}
+
+function writeJson(file, value) {
+  ensureDir(path.dirname(file));
+  fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
+}
+
+function compareAppleDeploymentTargets(left, right) {
+  const parse = (value) => {
+    if (typeof value !== 'string' || !/^[0-9]+(?:\.[0-9]+){0,2}$/.test(value)) {
+      throw new Error(
+        `iOS deployment target must be a numeric dotted version, got ${JSON.stringify(value)}`,
+      );
+    }
+    return value.split('.').map((part) => Number(part));
+  };
+  const leftParts = parse(left);
+  const rightParts = parse(right);
+  const count = Math.max(leftParts.length, rightParts.length);
+  for (let index = 0; index < count; index += 1) {
+    const delta = (leftParts[index] ?? 0) - (rightParts[index] ?? 0);
+    if (delta !== 0) return delta < 0 ? -1 : 1;
+  }
+  return 0;
+}
+
+function ensureIosDeploymentTarget(properties) {
+  if (properties === null || Array.isArray(properties) || typeof properties !== 'object') {
+    throw new Error('ios/Podfile.properties.json must contain a JSON object');
+  }
+  const current = properties['ios.deploymentTarget'];
+  if (
+    current !== undefined &&
+    compareAppleDeploymentTargets(current, IOS_MINIMUM_DEPLOYMENT_TARGET) >= 0
+  ) {
+    return { ...properties };
+  }
+  return { ...properties, 'ios.deploymentTarget': IOS_MINIMUM_DEPLOYMENT_TARGET };
+}
+
+function ensureIosConfigDeploymentTarget(config) {
+  if (config === null || Array.isArray(config) || typeof config !== 'object') {
+    throw new Error('Expo config must be an object');
+  }
+  const ios = config.ios ?? {};
+  const normalized = ensureIosDeploymentTarget(
+    ios.deploymentTarget === undefined ? {} : { 'ios.deploymentTarget': ios.deploymentTarget },
+  );
+  return {
+    ...config,
+    ios: {
+      ...ios,
+      deploymentTarget: normalized['ios.deploymentTarget'],
+    },
+  };
+}
+
+function ensureIosDeploymentTargetFile(file) {
+  const before = fs.existsSync(file) ? readJsonObject(file, 'ios/Podfile.properties.json') : {};
+  const after = ensureIosDeploymentTarget(before);
+  if (JSON.stringify(after) !== JSON.stringify(before)) writeJson(file, after);
+}
+
+function mergeProperties(file, entries) {
+  let lines = [];
+  if (fs.existsSync(file)) {
+    lines = fs.readFileSync(file, 'utf8').split(/\r?\n/);
+  }
+  const keys = new Set(Object.keys(entries));
+  const kept = lines.filter((line) => {
+    const trimmed = line.trim();
+    if (!trimmed || trimmed.startsWith('#') || !trimmed.includes('=')) {
+      return true;
+    }
+    const key = trimmed.slice(0, trimmed.indexOf('=')).trim();
+    return !keys.has(key);
+  });
+  for (const [key, value] of Object.entries(entries)) {
+    if (value != null && String(value).trim() !== '') {
+      kept.push(`${key}=${value}`);
+    }
+  }
+  fs.writeFileSync(file, `${kept.join('\n').replace(/\n+$/, '')}\n`);
+}
+
+function iosPodfileBlock(options = {}) {
+  const lines = [
+    IOS_PODFILE_START,
+    "oliphaunt_podspecs_path = File.expand_path('../node_modules/@oliphaunt/react-native/ios/podspecs', __dir__)",
+    "pod 'COliphaunt', :podspec => File.join(oliphaunt_podspecs_path, 'COliphaunt.podspec'), :modular_headers => true",
+    "pod 'OliphauntNativeBindings', :podspec => File.join(oliphaunt_podspecs_path, 'OliphauntNativeBindings.podspec')",
+    "pod 'Oliphaunt', :podspec => File.join(oliphaunt_podspecs_path, 'Oliphaunt.podspec')",
+    "oliphaunt_payload_path = File.expand_path('oliphaunt', __dir__)",
+    "oliphaunt_payload_podspec = File.join(oliphaunt_payload_path, 'OliphauntReactNativePayload.podspec')",
+    "raise 'Oliphaunt iOS payload is missing; rerun Expo prebuild' unless File.file?(oliphaunt_payload_podspec)",
+    "pod 'OliphauntReactNativePayload', :path => oliphaunt_payload_path",
+  ];
+  const resources = [];
+  if (options.seedProfile) {
+    resources.push([
+      `@oliphaunt/seed-native-ios-datum64-${options.seedProfile}`,
+      `OliphauntSeedNativeIOS${options.seedProfile === 'icu' ? 'ICU' : 'Standard'}`,
+    ]);
+  }
+  if (options.icu) resources.push(['@oliphaunt/icu', 'OliphauntICU']);
+  for (const [packageName, podName] of resources) {
+    const projectRoot = options.projectRoot ?? process.cwd();
+    const packageRoot = path.dirname(resolvePackageJson(packageName, [projectRoot]));
+    if (!fs.existsSync(path.join(packageRoot, `${podName}.podspec`))) {
+      throw new Error(`${packageName} is missing ${podName}.podspec`);
+    }
+    const relative = path
+      .relative(path.join(projectRoot, 'ios'), packageRoot)
+      .split(path.sep)
+      .join('/');
+    const rubyPath = relative.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
+    lines.push(`pod '${podName}', :path => File.expand_path('${rubyPath}', __dir__)`);
+  }
+  lines.push(IOS_PODFILE_END);
+  return lines.join('\n');
+}
+
+function replaceMarkedBlock(contents, block) {
+  const start = contents.indexOf(IOS_PODFILE_START);
+  const end = contents.indexOf(IOS_PODFILE_END);
+  if (start === -1 && end === -1) {
+    return undefined;
+  }
+  if (start === -1 || end === -1 || end < start) {
+    throw new Error('ios/Podfile has a partial @oliphaunt/react-native managed block');
+  }
+  const lineStart = contents.lastIndexOf('\n', start) + 1;
+  const indent = contents.slice(lineStart, start).match(/^[ \t]*/)?.[0] ?? '';
+  const indentedBlock = block
+    .split('\n')
+    .map((line) => `${indent}${line}`)
+    .join('\n');
+  const afterEnd = end + IOS_PODFILE_END.length;
+  return `${contents.slice(0, lineStart)}${indentedBlock}${contents.slice(afterEnd)}`;
+}
+
+function insertIosPodfileBlock(contents, options = {}) {
+  const block = iosPodfileBlock(options);
+  const replaced = replaceMarkedBlock(contents, block);
+  if (replaced !== undefined) {
+    return `${replaced.replace(/\n+$/, '')}\n`;
+  }
+
+  const lines = contents.split(/\r?\n/);
+  const anchorIndex = lines.findIndex((line) => /config\s*=\s*use_native_modules!\s*/.test(line));
+  const fallbackIndex = lines.findIndex((line) => /^\s*use_expo_modules!\s*$/.test(line));
+  const insertAfter = anchorIndex >= 0 ? anchorIndex : fallbackIndex;
+  if (insertAfter < 0) {
+    throw new Error(
+      'ios/Podfile must call use_native_modules! or use_expo_modules! before Oliphaunt can add Swift SDK podspecs',
+    );
+  }
+  const indent = lines[insertAfter].match(/^\s*/)?.[0] ?? '';
+  const indentedBlock = block
+    .split('\n')
+    .map((line) => `${indent}${line}`)
+    .join('\n');
+  lines.splice(insertAfter + 1, 0, indentedBlock);
+  return `${lines.join('\n').replace(/\n+$/, '')}\n`;
+}
+
+function patchIosPodfile(file, options = {}) {
+  if (!fs.existsSync(file)) {
+    return false;
+  }
+  const before = fs.readFileSync(file, 'utf8');
+  const after = insertIosPodfileBlock(before, {
+    ...options,
+    projectRoot: path.dirname(path.dirname(file)),
+  });
+  if (after !== before) {
+    fs.writeFileSync(file, after);
+  }
+  return true;
+}
+
+function androidPluginVersion(options) {
+  return optionalString(options.kotlinPluginVersion) ?? packageMetadata.oliphaunt?.kotlinSdkVersion;
+}
+
+function androidAppPluginLine(version) {
+  return `    id 'dev.oliphaunt.android' version '${version}'`;
+}
+
+function insertAppGradlePlugin(contents, version) {
+  if (ANDROID_APP_PLUGIN_RE.test(contents)) {
+    return `${contents.replace(/\n+$/, '')}\n`;
+  }
+  const lines = contents.split(/\r?\n/);
+  const pluginsIndex = lines.findIndex((line) => /^\s*plugins\s*\{\s*$/.test(line));
+  if (pluginsIndex < 0) {
+    return `plugins {\n${androidAppPluginLine(version)}\n}\n\n${contents.replace(/\n+$/, '')}\n`;
+  }
+  let insertAt = pluginsIndex + 1;
+  while (insertAt < lines.length && lines[insertAt].trim().startsWith('//')) {
+    insertAt += 1;
+  }
+  lines.splice(insertAt, 0, androidAppPluginLine(version));
+  return `${lines.join('\n').replace(/\n+$/, '')}\n`;
+}
+
+function patchAndroidGradle(androidRoot, normalized) {
+  const version = androidPluginVersion(normalized);
+  if (!version) {
+    throw new Error(
+      '@oliphaunt/react-native requires oliphaunt.kotlinSdkVersion metadata or kotlinPluginVersion',
+    );
+  }
+  const appBuildGradle = path.join(androidRoot, 'app', 'build.gradle');
+  if (fs.existsSync(appBuildGradle)) {
+    const before = fs.readFileSync(appBuildGradle, 'utf8');
+    const after = insertAppGradlePlugin(before, version);
+    if (after !== before) {
+      fs.writeFileSync(appBuildGradle, after);
+    }
+  }
+}
+
+function withOliphaunt(config, options = {}) {
+  const plugin = require('expo/config-plugins');
+  const normalized = normalizeOptions(options);
+  // Expo's built-in iOS mods consume this synchronously and propagate it to
+  // both the Xcode project and Podfile.properties.json during prebuild.
+  config = ensureIosConfigDeploymentTarget(config);
+
+  config = plugin.withDangerousMod(config, [
+    'android',
+    (modConfig) => {
+      const projectRoot = modConfig.modRequest.projectRoot;
+      const androidRoot = path.join(projectRoot, 'android');
+      const installedExtensions = resolveInstalledExtensionOwners(
+        projectRoot,
+        normalized.extensions,
+        { liboliphauntVersion: normalized.liboliphauntVersion },
+      );
+      const androidOptions = {
+        ...normalized,
+        extensionVersions: installedExtensions.extensionVersions,
+        liboliphauntVersion: installedExtensions.liboliphauntVersion,
+      };
+      writeJson(path.join(androidRoot, 'oliphaunt.json'), androidOptions);
+      mergeProperties(path.join(androidRoot, 'gradle.properties'), {
+        oliphauntExtensions: normalized.extensions.join(','),
+        oliphauntExtensionVersions: serializeExtensionVersions(
+          installedExtensions.extensionVersions,
+        ),
+        oliphauntIcu: normalized.icu ? 'true' : undefined,
+        oliphauntSeedProfile: normalized.seedProfile,
+        oliphauntDatabaseResourcesVersion: normalized.databaseResourcesVersion,
+        oliphauntLiboliphauntVersion: installedExtensions.liboliphauntVersion,
+        oliphauntAssetBaseUrl: normalized.assetBaseUrl,
+      });
+      patchAndroidGradle(androidRoot, androidOptions);
+      return modConfig;
+    },
+  ]);
+
+  config = plugin.withDangerousMod(config, [
+    'ios',
+    async (modConfig) => {
+      const projectRoot = modConfig.modRequest.projectRoot;
+      const iosRoot = path.join(projectRoot, 'ios');
+      await stageIosAppPayload(projectRoot, iosRoot, normalized);
+      writeJson(path.join(iosRoot, 'oliphaunt.json'), normalized);
+      writeJson(path.join(iosRoot, 'OliphauntExtensions.json'), {
+        extensions: normalized.extensions,
+        icu: normalized.icu,
+        liboliphauntVersion: normalized.liboliphauntVersion,
+        assetBaseUrl: normalized.assetBaseUrl,
+      });
+      ensureIosDeploymentTargetFile(path.join(iosRoot, 'Podfile.properties.json'));
+      patchIosPodfile(path.join(iosRoot, 'Podfile'), normalized);
+      return modConfig;
+    },
+  ]);
+
+  return config;
+}
+
+module.exports = withOliphaunt;
+module.exports.withOliphaunt = withOliphaunt;
+module.exports.normalizeOptions = normalizeOptions;
+module.exports.extensionPackageName = extensionPackageName;
+module.exports.selectedExtensionClosure = selectedExtensionClosure;
+module.exports.releaseOwnerForSqlName = releaseOwnerForSqlName;
+module.exports.resolveInstalledExtensionOwners = resolveInstalledExtensionOwners;
+module.exports.serializeExtensionVersions = serializeExtensionVersions;
+module.exports.readCarrierSummary = readCarrierSummary;
+module.exports.resolveIosCarrierManifests = resolveIosCarrierManifests;
+module.exports.iosStageOptions = iosStageOptions;
+module.exports.stageIosAppPayload = stageIosAppPayload;
+module.exports.insertIosPodfileBlock = insertIosPodfileBlock;
+module.exports.iosPodfileBlock = iosPodfileBlock;
+module.exports.ensureIosDeploymentTarget = ensureIosDeploymentTarget;
+module.exports.ensureIosConfigDeploymentTarget = ensureIosConfigDeploymentTarget;
+module.exports.insertAppGradlePlugin = insertAppGradlePlugin;
diff --git a/src/sdks/react-native/app.plugin.js b/src/sdks/react-native/app.plugin.js
deleted file mode 100644
index 0b12f5c6e..000000000
--- a/src/sdks/react-native/app.plugin.js
+++ /dev/null
@@ -1,1085 +0,0 @@
-const fs = require('node:fs');
-const os = require('node:os');
-const path = require('node:path');
-const { spawnSync } = require('node:child_process');
-
-const EXTENSION_NAME_RE = /^[A-Za-z0-9._-]{1,128}$/;
-const packageMetadata = require('./package.json');
-const packagedExtensionMetadata = path.join(__dirname, 'src/generated/extensions.json');
-const repositoryExtensionMetadata = path.join(
-  __dirname,
-  '../../extensions/generated/sdk/extensions.json',
-);
-const extensionMetadata = require(
-  fs.existsSync(packagedExtensionMetadata) ? packagedExtensionMetadata : repositoryExtensionMetadata,
-);
-const IOS_PODFILE_START = '# @oliphaunt/react-native begin';
-const IOS_PODFILE_END = '# @oliphaunt/react-native end';
-const IOS_MINIMUM_DEPLOYMENT_TARGET = '17.0';
-const IOS_CARRIER_SCHEMA = 'oliphaunt-react-native-ios-carrier-v1';
-const IOS_CARRIER_FILENAME = 'oliphaunt-react-native-ios-carriers.json';
-const IOS_BASE_CARRIER_ENV = 'OLIPHAUNT_REACT_NATIVE_IOS_BASE_CARRIER';
-const IOS_EXTENSION_CARRIERS_ENV = 'OLIPHAUNT_REACT_NATIVE_IOS_EXTENSION_CARRIERS';
-const IOS_CARRIER_CACHE_ENV = 'OLIPHAUNT_REACT_NATIVE_IOS_CACHE_DIR';
-const IOS_ALLOW_FILE_URLS_ENV = 'OLIPHAUNT_REACT_NATIVE_IOS_ALLOW_FILE_URLS';
-const ANDROID_APP_PLUGIN_RE = /id\s*(?:\(\s*)?['"]dev\.oliphaunt\.android['"]/;
-const STABLE_SEMVER_RE = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/;
-const KNOWN_EXTENSION_SQL_NAMES = new Set(
-  extensionMetadata.extensions.map((extension) => extension['sql-name']),
-);
-const EXTENSION_METADATA_BY_SQL_NAME = new Map(
-  extensionMetadata.extensions.map((extension) => [extension['sql-name'], extension]),
-);
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function normalizeOptions(options = {}) {
-  const extensions = Array.isArray(options.extensions) ? options.extensions : [];
-  const selected = [...new Set(extensions.map((value) => String(value).trim()).filter(Boolean))].sort();
-  for (const extension of selected) {
-    if (!EXTENSION_NAME_RE.test(extension)) {
-      throw new Error(
-        `@oliphaunt/react-native extension '${extension}' must be an exact PostgreSQL extension name`,
-      );
-    }
-    if (!KNOWN_EXTENSION_SQL_NAMES.has(extension)) {
-      throw new Error(
-        `@oliphaunt/react-native extension '${extension}' is not in the generated exact-extension catalog`,
-      );
-    }
-  }
-  return {
-    extensions: selected,
-    icu: Boolean(options.icu),
-    liboliphauntVersion: optionalString(options.liboliphauntVersion),
-    assetBaseUrl: optionalString(options.assetBaseUrl),
-    kotlinPluginVersion: optionalString(options.kotlinPluginVersion) ?? packageMetadata.oliphaunt?.kotlinSdkVersion,
-  };
-}
-
-function optionalString(value) {
-  if (value == null) {
-    return undefined;
-  }
-  const stringValue = String(value).trim();
-  return stringValue.length > 0 ? stringValue : undefined;
-}
-
-function extensionPackageName(sqlName) {
-  const extension = EXTENSION_METADATA_BY_SQL_NAME.get(sqlName);
-  if (!extension) {
-    throw new Error(`unknown Oliphaunt extension SQL name ${sqlName}`);
-  }
-  return extension['npm-package'];
-}
-
-function selectedExtensionClosure(extensions) {
-  const selected = new Set();
-  const visiting = new Set();
-  function visit(sqlName) {
-    if (selected.has(sqlName)) {
-      return;
-    }
-    if (visiting.has(sqlName)) {
-      throw new Error(`generated extension dependency cycle includes ${sqlName}`);
-    }
-    const extension = EXTENSION_METADATA_BY_SQL_NAME.get(sqlName);
-    if (!extension) {
-      throw new Error(`unknown Oliphaunt extension SQL name ${sqlName}`);
-    }
-    visiting.add(sqlName);
-    for (const dependency of extension['selected-extension-dependencies'] ?? []) {
-      visit(dependency);
-    }
-    visiting.delete(sqlName);
-    selected.add(sqlName);
-  }
-  for (const sqlName of extensions) {
-    visit(sqlName);
-  }
-  return [...selected].sort();
-}
-
-function releaseOwnerForSqlName(sqlName) {
-  const extension = EXTENSION_METADATA_BY_SQL_NAME.get(sqlName);
-  if (!extension) {
-    throw new Error(`unknown Oliphaunt extension SQL name ${sqlName}`);
-  }
-  const members = extensionMetadata.extensions
-    .filter(
-      (candidate) =>
-        candidate['artifact-product'] === extension['artifact-product'] &&
-        candidate['npm-package'] === extension['npm-package'],
-    )
-    .map((candidate) => candidate['sql-name'])
-    .sort();
-  if (
-    members.length === 0 ||
-    extensionMetadata.extensions
-      .filter((candidate) => members.includes(candidate['sql-name']))
-      .some(
-        (candidate) =>
-          candidate['maven-group'] !== extension['maven-group'] ||
-          candidate['maven-artifact'] !== extension['maven-artifact'] ||
-          candidate['runtime-bound'] !== extension['runtime-bound'],
-      )
-  ) {
-    throw new Error(`generated extension ownership metadata is inconsistent for ${sqlName}`);
-  }
-  return {
-    artifactProduct: extension['artifact-product'],
-    members,
-    mavenArtifact: extension['maven-artifact'],
-    mavenGroup: extension['maven-group'],
-    npmPackage: extension['npm-package'],
-    releaseProduct: extension['release-product'],
-    runtimeBound: extension['runtime-bound'] === true,
-  };
-}
-
-function absoluteFromProject(projectRoot, value, label) {
-  if (typeof value !== 'string' || value.trim() === '') {
-    throw new Error(`${label} must be a non-empty path`);
-  }
-  return path.resolve(projectRoot, value);
-}
-
-function readJsonObject(file, label) {
-  let value;
-  try {
-    value = JSON.parse(fs.readFileSync(file, 'utf8'));
-  } catch (error) {
-    throw new Error(`${label} could not be read from ${file}: ${error.message}`);
-  }
-  if (value === null || Array.isArray(value) || typeof value !== 'object') {
-    throw new Error(`${label} at ${file} must be a JSON object`);
-  }
-  return value;
-}
-
-function readCarrierSummary(file, label = 'iOS carrier manifest') {
-  const manifest = readJsonObject(file, label);
-  if (manifest.schema !== IOS_CARRIER_SCHEMA) {
-    throw new Error(`${label} at ${file} must declare schema=${IOS_CARRIER_SCHEMA}`);
-  }
-  if (manifest.base === null || Array.isArray(manifest.base) || typeof manifest.base !== 'object') {
-    throw new Error(`${label} at ${file} must contain a base carrier object`);
-  }
-  if (
-    manifest.base.product !== 'liboliphaunt-native' ||
-    typeof manifest.base.version !== 'string' ||
-    !STABLE_SEMVER_RE.test(manifest.base.version) ||
-    manifest.base.tag !== `liboliphaunt-native-v${manifest.base.version}`
-  ) {
-    throw new Error(`${label} at ${file} contains an invalid base release identity`);
-  }
-  if (!Array.isArray(manifest.carriers)) {
-    throw new Error(`${label} at ${file} must contain a carriers array`);
-  }
-  const carrierNames = new Set();
-  for (const [index, carrier] of manifest.carriers.entries()) {
-    if (carrier === null || Array.isArray(carrier) || typeof carrier !== 'object') {
-      throw new Error(`${label} at ${file} carriers[${index}] must be an object`);
-    }
-    if (
-      typeof carrier.name !== 'string' ||
-      carrier.name.length === 0 ||
-      typeof carrier.url !== 'string' ||
-      carrier.url.length === 0 ||
-      typeof carrier.sha256 !== 'string' ||
-      !/^[0-9a-f]{64}$/.test(carrier.sha256) ||
-      !Number.isSafeInteger(carrier.bytes) ||
-      carrier.bytes <= 0 ||
-      !['zip', 'tar.gz'].includes(carrier.format)
-    ) {
-      throw new Error(`${label} at ${file} carriers[${index}] is invalid`);
-    }
-    if (carrierNames.has(carrier.name)) {
-      throw new Error(`${label} at ${file} repeats carrier ${carrier.name}`);
-    }
-    carrierNames.add(carrier.name);
-  }
-  if (!Array.isArray(manifest.extensions)) {
-    throw new Error(`${label} at ${file} must contain an extensions array`);
-  }
-  const releasesByOwner = new Map();
-  const extensions = manifest.extensions.map((row, index) => {
-    if (row === null || Array.isArray(row) || typeof row !== 'object') {
-      throw new Error(`${label} at ${file} extensions[${index}] must be an object`);
-    }
-    if (typeof row.sqlName !== 'string' || !EXTENSION_NAME_RE.test(row.sqlName)) {
-      throw new Error(`${label} at ${file} extensions[${index}].sqlName is invalid`);
-    }
-    if (
-      !Array.isArray(row.dependencies) ||
-      row.dependencies.some((dependency) => typeof dependency !== 'string' || !EXTENSION_NAME_RE.test(dependency))
-    ) {
-      throw new Error(`${label} at ${file} extension ${row.sqlName} has invalid dependencies`);
-    }
-    const dependencies = [...new Set(row.dependencies)].sort();
-    if (dependencies.length !== row.dependencies.length) {
-      throw new Error(`${label} at ${file} extension ${row.sqlName} repeats a dependency`);
-    }
-    const owner = releaseOwnerForSqlName(row.sqlName);
-    if (row.product !== owner.artifactProduct) {
-      throw new Error(
-        `${label} at ${file} extension ${row.sqlName} must belong to ${owner.artifactProduct}`,
-      );
-    }
-    if (row.releaseProduct !== owner.releaseProduct) {
-      throw new Error(
-        `${label} at ${file} extension ${row.sqlName} must be owned by ${owner.releaseProduct}`,
-      );
-    }
-    if (typeof row.version !== 'string' || !STABLE_SEMVER_RE.test(row.version)) {
-      throw new Error(
-        `${label} at ${file} extension ${row.sqlName} has an invalid stable SemVer version`,
-      );
-    }
-    const expectedTag = `${owner.releaseProduct}-v${row.version}`;
-    if (row.tag !== expectedTag) {
-      throw new Error(`${label} at ${file} extension ${row.sqlName}.tag must be ${expectedTag}`);
-    }
-    const generatedDependencies = [
-      ...(EXTENSION_METADATA_BY_SQL_NAME.get(row.sqlName)?.['selected-extension-dependencies'] ?? []),
-    ].sort();
-    if (JSON.stringify(dependencies) !== JSON.stringify(generatedDependencies)) {
-      throw new Error(
-        `${label} at ${file} extension ${row.sqlName} dependencies do not match generated metadata`,
-      );
-    }
-    const release = `${row.version}\0${row.tag}`;
-    const previousRelease = releasesByOwner.get(row.releaseProduct);
-    if (previousRelease !== undefined && previousRelease !== release) {
-      throw new Error(
-        `${label} at ${file} contains conflicting releases for owner ${owner.releaseProduct}`,
-      );
-    }
-    releasesByOwner.set(row.releaseProduct, release);
-    if (owner.runtimeBound && row.version !== manifest.base.version) {
-      throw new Error(
-        `${label} at ${file} runtime-bound owner ${owner.releaseProduct} version ${row.version} ` +
-          `must match base ${manifest.base.version}`,
-      );
-    }
-    return {
-      dependencies,
-      product: owner.artifactProduct,
-      releaseProduct: owner.releaseProduct,
-      sqlName: row.sqlName,
-      tag: row.tag,
-      version: row.version,
-    };
-  });
-  if (new Set(extensions.map(({ sqlName }) => sqlName)).size !== extensions.length) {
-    throw new Error(`${label} at ${file} repeats an extension row`);
-  }
-  return {
-    base: {
-      product: manifest.base.product,
-      tag: manifest.base.tag,
-      version: manifest.base.version,
-    },
-    carriers: manifest.carriers,
-    extensions,
-    file: path.resolve(file),
-  };
-}
-
-function carrierPointerFromPackage(packageJsonFile, expectedPackageName, owner) {
-  const installedOwner = owner ? validateInstalledExtensionOwner(packageJsonFile, owner) : undefined;
-  const packageJson = installedOwner?.packageJson ??
-    readJsonObject(packageJsonFile, `${expectedPackageName} package metadata`);
-  if (packageJson.name !== expectedPackageName) {
-    throw new Error(
-      `${expectedPackageName} resolved to package metadata for ${String(packageJson.name)}`,
-    );
-  }
-  const pointer = packageJson.oliphaunt?.iosCarrierManifest;
-  if (typeof pointer !== 'string' || pointer.trim() === '') {
-    throw new Error(
-      `${expectedPackageName} must declare package.json.oliphaunt.iosCarrierManifest`,
-    );
-  }
-  const packageRoot = path.dirname(packageJsonFile);
-  const carrier = path.resolve(packageRoot, pointer);
-  const relative = path.relative(packageRoot, carrier);
-  if (relative.startsWith('..') || path.isAbsolute(relative)) {
-    throw new Error(`${expectedPackageName} iOS carrier manifest must stay inside its package`);
-  }
-  if (path.basename(carrier) !== IOS_CARRIER_FILENAME || !fs.statSync(carrier, { throwIfNoEntry: false })?.isFile()) {
-    throw new Error(
-      `${expectedPackageName} iOS carrier manifest must be the packaged ${IOS_CARRIER_FILENAME}`,
-    );
-  }
-  return {
-    carrier,
-    ownerLiboliphauntVersion: installedOwner?.liboliphauntVersion,
-    ownerVersion: installedOwner?.version,
-    packageRoot,
-  };
-}
-
-function resolvePackageJson(packageName, searchPaths) {
-  try {
-    return require.resolve(`${packageName}/package.json`, { paths: searchPaths });
-  } catch (error) {
-    throw new Error(
-      `selected extension requires installed package ${packageName}: ${error.message}`,
-    );
-  }
-}
-
-function validateInstalledExtensionOwner(packageJsonFile, owner) {
-  const packageJson = readJsonObject(packageJsonFile, `${owner.npmPackage} package metadata`);
-  if (packageJson.name !== owner.npmPackage) {
-    throw new Error(
-      `${owner.npmPackage} resolved to package metadata for ${String(packageJson.name)}`,
-    );
-  }
-  if (
-    typeof packageJson.version !== 'string' ||
-    packageJson.version.length === 0 ||
-    !STABLE_SEMVER_RE.test(packageJson.version)
-  ) {
-    throw new Error(`${owner.npmPackage} package metadata has an invalid version`);
-  }
-  if (packageJson.oliphaunt?.product !== owner.artifactProduct) {
-    throw new Error(`${owner.npmPackage} package metadata does not declare ${owner.artifactProduct}`);
-  }
-  const expectedKind = owner.members.length > 1 ? 'exact-extension-bundle' : 'exact-extension';
-  if (packageJson.oliphaunt?.kind !== expectedKind) {
-    throw new Error(`${owner.npmPackage} package metadata does not declare ${expectedKind}`);
-  }
-  if (owner.members.length > 1) {
-    if (JSON.stringify(packageJson.oliphaunt?.members) !== JSON.stringify(owner.members)) {
-      throw new Error(
-        `${owner.npmPackage} package metadata members do not match its generated release ownership`,
-      );
-    }
-  } else if (packageJson.oliphaunt?.sqlName !== owner.members[0]) {
-    throw new Error(
-      `${owner.npmPackage} package metadata does not declare SQL extension ${owner.members[0]}`,
-    );
-  }
-  const liboliphauntVersion = packageJson.oliphaunt?.liboliphauntVersion;
-  if (
-    typeof liboliphauntVersion !== 'string' ||
-    liboliphauntVersion.length === 0 ||
-    !STABLE_SEMVER_RE.test(liboliphauntVersion)
-  ) {
-    throw new Error(`${owner.npmPackage} package metadata does not pin liboliphauntVersion`);
-  }
-  if (owner.runtimeBound && packageJson.version !== liboliphauntVersion) {
-    throw new Error(
-      `${owner.npmPackage} is runtime-bound but version ${packageJson.version} does not match liboliphauntVersion ${liboliphauntVersion}`,
-    );
-  }
-  return {
-    liboliphauntVersion,
-    packageJson,
-    packageJsonFile: path.resolve(packageJsonFile),
-    packageRoot: path.dirname(packageJsonFile),
-    version: packageJson.version,
-  };
-}
-
-function resolveInstalledExtensionOwners(
-  projectRoot,
-  extensions,
-  {
-    liboliphauntVersion,
-    packageJsonResolver = resolvePackageJson,
-  } = {},
-) {
-  const closure = selectedExtensionClosure(extensions);
-  const ownersByPackage = new Map();
-  for (const sqlName of closure) {
-    const owner = releaseOwnerForSqlName(sqlName);
-    const previous = ownersByPackage.get(owner.npmPackage);
-    if (previous) {
-      if (
-        previous.artifactProduct !== owner.artifactProduct ||
-        previous.releaseProduct !== owner.releaseProduct ||
-        previous.mavenGroup !== owner.mavenGroup ||
-        previous.mavenArtifact !== owner.mavenArtifact ||
-        previous.runtimeBound !== owner.runtimeBound ||
-        JSON.stringify(previous.members) !== JSON.stringify(owner.members)
-      ) {
-        throw new Error(`selected SQL members disagree about release owner ${owner.npmPackage}`);
-      }
-      continue;
-    }
-    ownersByPackage.set(owner.npmPackage, owner);
-  }
-
-  const resolved = [];
-  const versionsByMavenCoordinate = new Map();
-  const extensionVersions = {};
-  let compatibleRuntimeVersion = optionalString(liboliphauntVersion);
-  for (const owner of [...ownersByPackage.values()].sort((left, right) =>
-    compareText(left.npmPackage, right.npmPackage),
-  )) {
-    const packageJsonFile = packageJsonResolver(owner.npmPackage, [projectRoot]);
-    const installed = validateInstalledExtensionOwner(packageJsonFile, owner);
-    if (
-      compatibleRuntimeVersion !== undefined &&
-      compatibleRuntimeVersion !== installed.liboliphauntVersion
-    ) {
-      throw new Error(
-        `${owner.npmPackage} requires liboliphaunt ${installed.liboliphauntVersion}, but the app selected ${compatibleRuntimeVersion}`,
-      );
-    }
-    compatibleRuntimeVersion ??= installed.liboliphauntVersion;
-    const coordinate = `${owner.mavenGroup}:${owner.mavenArtifact}`;
-    const previousVersion = versionsByMavenCoordinate.get(coordinate);
-    if (previousVersion !== undefined && previousVersion !== installed.version) {
-      throw new Error(
-        `selected extension packages require conflicting versions ${previousVersion} and ${installed.version} for ${coordinate}`,
-      );
-    }
-    versionsByMavenCoordinate.set(coordinate, installed.version);
-    const previousOwnerVersion = extensionVersions[owner.releaseProduct];
-    if (previousOwnerVersion !== undefined && previousOwnerVersion !== installed.version) {
-      throw new Error(
-        `selected extension packages require conflicting versions for ${owner.releaseProduct}`,
-      );
-    }
-    extensionVersions[owner.releaseProduct] = installed.version;
-    resolved.push({ ...owner, ...installed });
-  }
-  return {
-    closure,
-    extensionVersions,
-    liboliphauntVersion: compatibleRuntimeVersion,
-    owners: resolved,
-  };
-}
-
-function serializeExtensionVersions(extensionVersions) {
-  return Object.entries(extensionVersions)
-    .sort(([left], [right]) => compareText(left, right))
-    .map(([owner, version]) => `${owner}=${version}`)
-    .join(',');
-}
-
-function parseExtensionCarrierOverrides(projectRoot, value) {
-  if (value == null || String(value).trim() === '') {
-    return new Map();
-  }
-  let parsed;
-  try {
-    parsed = JSON.parse(String(value));
-  } catch (error) {
-    throw new Error(`${IOS_EXTENSION_CARRIERS_ENV} must be a JSON object: ${error.message}`);
-  }
-  if (parsed === null || Array.isArray(parsed) || typeof parsed !== 'object') {
-    throw new Error(`${IOS_EXTENSION_CARRIERS_ENV} must be a JSON object keyed by SQL name`);
-  }
-  const result = new Map();
-  for (const [sqlName, file] of Object.entries(parsed)) {
-    if (!EXTENSION_NAME_RE.test(sqlName)) {
-      throw new Error(`${IOS_EXTENSION_CARRIERS_ENV} contains invalid SQL name ${sqlName}`);
-    }
-    result.set(
-      sqlName,
-      absoluteFromProject(projectRoot, file, `${IOS_EXTENSION_CARRIERS_ENV}.${sqlName}`),
-    );
-  }
-  return result;
-}
-
-function validateAggregateCarrierClosure(summary, selected) {
-  const bySqlName = new Map(summary.extensions.map((row) => [row.sqlName, row]));
-  const visited = new Set();
-  const visiting = new Set();
-
-  function visit(sqlName, requiredBy) {
-    if (visited.has(sqlName)) {
-      return;
-    }
-    if (visiting.has(sqlName)) {
-      throw new Error(`aggregate iOS carrier dependency cycle includes ${sqlName}`);
-    }
-    const row = bySqlName.get(sqlName);
-    if (!row) {
-      throw new Error(
-        `aggregate iOS carrier is missing ${sqlName}${requiredBy ? ` required by ${requiredBy}` : ''}`,
-      );
-    }
-    visiting.add(sqlName);
-    for (const dependency of row.dependencies) {
-      visit(dependency, sqlName);
-    }
-    visiting.delete(sqlName);
-    visited.add(sqlName);
-  }
-
-  for (const sqlName of selected) {
-    visit(sqlName, undefined);
-  }
-}
-
-function resolveIosCarrierManifests(
-  projectRoot,
-  extensions,
-  {
-    basePackageRoot = __dirname,
-    env = process.env,
-    packageJsonResolver = resolvePackageJson,
-  } = {},
-) {
-  const selected = [...new Set(extensions)].sort();
-  const baseCarrierOverride = optionalString(env[IOS_BASE_CARRIER_ENV]);
-  let baseCarrier;
-  if (baseCarrierOverride) {
-    baseCarrier = absoluteFromProject(projectRoot, baseCarrierOverride, IOS_BASE_CARRIER_ENV);
-  } else {
-    baseCarrier = carrierPointerFromPackage(
-      path.join(basePackageRoot, 'package.json'),
-      '@oliphaunt/react-native',
-    ).carrier;
-  }
-  const baseSummary = readCarrierSummary(baseCarrier, 'React Native base iOS carrier manifest');
-  const overrides = parseExtensionCarrierOverrides(
-    projectRoot,
-    env[IOS_EXTENSION_CARRIERS_ENV],
-  );
-  if (baseCarrierOverride && baseSummary.extensions.length > 0) {
-    if (overrides.size > 0) {
-      throw new Error(
-        `${IOS_EXTENSION_CARRIERS_ENV} cannot be combined with an aggregate ${IOS_BASE_CARRIER_ENV}`,
-      );
-    }
-    validateAggregateCarrierClosure(baseSummary, selected);
-    return [baseSummary.file];
-  }
-  if (baseSummary.extensions.length !== 0) {
-    throw new Error('the installed @oliphaunt/react-native base iOS carrier manifest must be extension-free');
-  }
-
-  const visited = new Set();
-  const visiting = new Set();
-  const extensionCarriers = [];
-  const extensionCarrierFiles = new Set();
-  const installedOwnerCarriers = new Map();
-  const releasesByOwner = new Map();
-
-  function registerOwnerReleases(summary) {
-    for (const row of summary.extensions) {
-      const release = `${row.version}\0${row.tag}`;
-      const previous = releasesByOwner.get(row.releaseProduct);
-      if (previous !== undefined && previous !== release) {
-        throw new Error(`iOS carrier manifests require conflicting releases for owner ${row.releaseProduct}`);
-      }
-      releasesByOwner.set(row.releaseProduct, release);
-    }
-  }
-
-  function visit(sqlName, searchPaths, requiredBy) {
-    if (visited.has(sqlName)) {
-      return;
-    }
-    if (visiting.has(sqlName)) {
-      throw new Error(`iOS carrier dependency cycle includes ${sqlName}`);
-    }
-    visiting.add(sqlName);
-    const owner = releaseOwnerForSqlName(sqlName);
-    const packageName = owner.npmPackage;
-    let carrier;
-    let dependencySearchPaths = searchPaths;
-    let installedOwnerLiboliphauntVersion;
-    let installedOwnerVersion;
-    let summary;
-    if (overrides.has(sqlName)) {
-      carrier = overrides.get(sqlName);
-    } else {
-      const cached = installedOwnerCarriers.get(packageName);
-      if (cached) {
-        carrier = cached.carrier;
-        dependencySearchPaths = cached.dependencySearchPaths;
-        installedOwnerLiboliphauntVersion = cached.installedOwnerLiboliphauntVersion;
-        installedOwnerVersion = cached.installedOwnerVersion;
-        summary = cached.summary;
-      } else {
-        let packageJsonFile;
-        try {
-          packageJsonFile = packageJsonResolver(packageName, searchPaths);
-        } catch (error) {
-          const suffix = requiredBy ? ` required by ${requiredBy}` : '';
-          throw new Error(`missing ${packageName}${suffix}: ${error.message}`);
-        }
-        const resolved = carrierPointerFromPackage(packageJsonFile, packageName, owner);
-        carrier = resolved.carrier;
-        installedOwnerLiboliphauntVersion = resolved.ownerLiboliphauntVersion;
-        installedOwnerVersion = resolved.ownerVersion;
-        dependencySearchPaths = [resolved.packageRoot, ...searchPaths];
-        summary = readCarrierSummary(carrier, `${packageName} iOS carrier manifest`);
-        const carrierMembers = summary.extensions.map((row) => row.sqlName).sort();
-        if (JSON.stringify(carrierMembers) !== JSON.stringify(owner.members)) {
-          throw new Error(
-            `${packageName} iOS carrier members do not match its generated release ownership`,
-          );
-        }
-        installedOwnerCarriers.set(packageName, {
-            carrier,
-            dependencySearchPaths,
-            installedOwnerLiboliphauntVersion,
-            installedOwnerVersion,
-            summary,
-          });
-      }
-    }
-    summary ??= readCarrierSummary(carrier, `${packageName} iOS carrier manifest`);
-    if (JSON.stringify(summary.base) !== JSON.stringify(baseSummary.base)) {
-      throw new Error(
-        `${packageName} iOS carrier pins ${summary.base.tag}, but the selected base carrier ` +
-          `pins ${baseSummary.base.tag}`,
-      );
-    }
-    if (
-      installedOwnerLiboliphauntVersion !== undefined &&
-      summary.base.version !== installedOwnerLiboliphauntVersion
-    ) {
-      throw new Error(
-        `${packageName} iOS carrier base ${summary.base.version} does not match installed package ` +
-          `liboliphauntVersion ${installedOwnerLiboliphauntVersion}`,
-      );
-    }
-    registerOwnerReleases(summary);
-    const extensionRow = summary.extensions.find((row) => row.sqlName === sqlName);
-    if (!extensionRow) {
-      throw new Error(
-        `${packageName} iOS carrier manifest does not contain the ${sqlName} extension row`,
-      );
-    }
-    if (installedOwnerVersion !== undefined && extensionRow.version !== installedOwnerVersion) {
-      throw new Error(
-        `${packageName} iOS carrier version ${extensionRow.version} does not match installed package ` +
-          `version ${installedOwnerVersion}`,
-      );
-    }
-    for (const dependency of extensionRow.dependencies) {
-      visit(dependency, dependencySearchPaths, sqlName);
-    }
-    visiting.delete(sqlName);
-    visited.add(sqlName);
-    if (!extensionCarrierFiles.has(summary.file)) {
-      extensionCarrierFiles.add(summary.file);
-      extensionCarriers.push(summary.file);
-    }
-  }
-
-  for (const sqlName of selected) {
-    visit(sqlName, [projectRoot], undefined);
-  }
-  return [baseSummary.file, ...extensionCarriers];
-}
-
-function explicitBooleanEnv(env, name) {
-  const value = optionalString(env[name]);
-  if (value === undefined || value === '0' || value === 'false') {
-    return false;
-  }
-  if (value === '1' || value === 'true') {
-    return true;
-  }
-  throw new Error(`${name} must be one of 1, 0, true, or false`);
-}
-
-function iosStageCommand(
-  projectRoot,
-  iosRoot,
-  normalized,
-  { basePackageRoot = __dirname, env = process.env, packageJsonResolver = resolvePackageJson } = {},
-) {
-  const outputDir = path.join(iosRoot, 'oliphaunt');
-  const carrierManifests = resolveIosCarrierManifests(projectRoot, normalized.extensions, {
-    basePackageRoot,
-    env,
-    packageJsonResolver,
-  });
-  const args = [path.join(__dirname, 'tools', 'stage-ios-app.mjs')];
-  for (const carrier of carrierManifests) {
-    args.push('--carrier', carrier);
-  }
-  args.push('--output-dir', outputDir);
-  if (normalized.extensions.length > 0) {
-    args.push('--extensions', normalized.extensions.join(','));
-  }
-  if (normalized.icu) {
-    args.push('--icu');
-  }
-  const cacheDir = optionalString(env[IOS_CARRIER_CACHE_ENV]);
-  if (cacheDir) {
-    args.push('--cache-dir', absoluteFromProject(projectRoot, cacheDir, IOS_CARRIER_CACHE_ENV));
-  }
-  if (explicitBooleanEnv(env, IOS_ALLOW_FILE_URLS_ENV)) {
-    args.push('--allow-file-urls');
-  }
-  return {
-    args,
-    carrierManifests,
-    command: process.execPath,
-    outputDir,
-  };
-}
-
-// The published config plugin cannot depend on repository tooling. Keep this
-// regular-file capture local so Bun never has to drain synchronous child pipes.
-function captureCommandOutputSync(command, args, { cwd, env, label }) {
-  const maximum = 64 * 1024 * 1024;
-  const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-react-native-command-'));
-  const stdoutFile = path.join(directory, 'stdout');
-  const stderrFile = path.join(directory, 'stderr');
-  let stdoutDescriptor;
-  let stderrDescriptor;
-  try {
-    stdoutDescriptor = fs.openSync(stdoutFile, 'wx', 0o600);
-    stderrDescriptor = fs.openSync(stderrFile, 'wx', 0o600);
-    const result = spawnSync(command, args, {
-      cwd,
-      env,
-      stdio: ['ignore', stdoutDescriptor, stderrDescriptor],
-    });
-    fs.closeSync(stdoutDescriptor);
-    stdoutDescriptor = undefined;
-    fs.closeSync(stderrDescriptor);
-    stderrDescriptor = undefined;
-    for (const [file, stream] of [[stdoutFile, 'stdout'], [stderrFile, 'stderr']]) {
-      const bytes = fs.statSync(file).size;
-      if (bytes > maximum) {
-        throw new Error(`${label} ${stream} exceeded the ${maximum}-byte capture limit`);
-      }
-    }
-    return {
-      ...result,
-      stderr: fs.readFileSync(stderrFile, 'utf8'),
-      stdout: fs.readFileSync(stdoutFile, 'utf8'),
-    };
-  } finally {
-    if (stdoutDescriptor !== undefined) fs.closeSync(stdoutDescriptor);
-    if (stderrDescriptor !== undefined) fs.closeSync(stderrDescriptor);
-    fs.rmSync(directory, { force: true, recursive: true });
-  }
-}
-
-function stageIosAppPayload(
-  projectRoot,
-  iosRoot,
-  normalized,
-  {
-    basePackageRoot = __dirname,
-    env = process.env,
-    packageJsonResolver = resolvePackageJson,
-    spawnSyncImpl = undefined,
-  } = {},
-) {
-  const command = iosStageCommand(projectRoot, iosRoot, normalized, {
-    basePackageRoot,
-    env,
-    packageJsonResolver,
-  });
-  const result = spawnSyncImpl === undefined
-    ? captureCommandOutputSync(command.command, command.args, {
-        cwd: projectRoot,
-        env,
-        label: 'iOS carrier resolver',
-      })
-    : spawnSyncImpl(command.command, command.args, {
-        cwd: projectRoot,
-        encoding: 'utf8',
-        env,
-        maxBuffer: 64 * 1024 * 1024,
-        stdio: ['ignore', 'pipe', 'pipe'],
-      });
-  if (result.error) {
-    throw new Error(`failed to start the iOS carrier resolver: ${result.error.message}`);
-  }
-  if (result.status !== 0) {
-    const detail = String(result.stderr || result.stdout || '').trim();
-    throw new Error(
-      `iOS carrier resolver failed${result.status == null ? '' : ` with exit code ${result.status}`}: ${detail || 'no diagnostic output'}`,
-    );
-  }
-  const podspec = path.join(command.outputDir, 'OliphauntReactNativePayload.podspec');
-  if (!fs.statSync(podspec, { throwIfNoEntry: false })?.isFile()) {
-    throw new Error(`iOS carrier resolver did not produce ${podspec}`);
-  }
-  return command;
-}
-
-function ensureDir(dir) {
-  fs.mkdirSync(dir, { recursive: true });
-}
-
-function writeJson(file, value) {
-  ensureDir(path.dirname(file));
-  fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
-}
-
-function compareAppleDeploymentTargets(left, right) {
-  const parse = (value) => {
-    if (typeof value !== 'string' || !/^[0-9]+(?:\.[0-9]+){0,2}$/.test(value)) {
-      throw new Error(`iOS deployment target must be a numeric dotted version, got ${JSON.stringify(value)}`);
-    }
-    return value.split('.').map((part) => Number(part));
-  };
-  const leftParts = parse(left);
-  const rightParts = parse(right);
-  const count = Math.max(leftParts.length, rightParts.length);
-  for (let index = 0; index < count; index += 1) {
-    const delta = (leftParts[index] ?? 0) - (rightParts[index] ?? 0);
-    if (delta !== 0) return delta < 0 ? -1 : 1;
-  }
-  return 0;
-}
-
-function ensureIosDeploymentTarget(properties) {
-  if (properties === null || Array.isArray(properties) || typeof properties !== 'object') {
-    throw new Error('ios/Podfile.properties.json must contain a JSON object');
-  }
-  const current = properties['ios.deploymentTarget'];
-  if (
-    current !== undefined &&
-    compareAppleDeploymentTargets(current, IOS_MINIMUM_DEPLOYMENT_TARGET) >= 0
-  ) {
-    return { ...properties };
-  }
-  return { ...properties, 'ios.deploymentTarget': IOS_MINIMUM_DEPLOYMENT_TARGET };
-}
-
-function ensureIosConfigDeploymentTarget(config) {
-  if (config === null || Array.isArray(config) || typeof config !== 'object') {
-    throw new Error('Expo config must be an object');
-  }
-  const ios = config.ios ?? {};
-  const normalized = ensureIosDeploymentTarget(
-    ios.deploymentTarget === undefined
-      ? {}
-      : { 'ios.deploymentTarget': ios.deploymentTarget },
-  );
-  return {
-    ...config,
-    ios: {
-      ...ios,
-      deploymentTarget: normalized['ios.deploymentTarget'],
-    },
-  };
-}
-
-function ensureIosDeploymentTargetFile(file) {
-  const before = fs.existsSync(file) ? readJsonObject(file, 'ios/Podfile.properties.json') : {};
-  const after = ensureIosDeploymentTarget(before);
-  if (JSON.stringify(after) !== JSON.stringify(before)) writeJson(file, after);
-}
-
-function mergeProperties(file, entries) {
-  let lines = [];
-  if (fs.existsSync(file)) {
-    lines = fs.readFileSync(file, 'utf8').split(/\r?\n/);
-  }
-  const keys = new Set(Object.keys(entries));
-  const kept = lines.filter((line) => {
-    const trimmed = line.trim();
-    if (!trimmed || trimmed.startsWith('#') || !trimmed.includes('=')) {
-      return true;
-    }
-    const key = trimmed.slice(0, trimmed.indexOf('=')).trim();
-    return !keys.has(key);
-  });
-  for (const [key, value] of Object.entries(entries)) {
-    if (value != null && String(value).trim() !== '') {
-      kept.push(`${key}=${value}`);
-    }
-  }
-  fs.writeFileSync(file, `${kept.join('\n').replace(/\n+$/, '')}\n`);
-}
-
-function iosPodfileBlock(options = {}) {
-  const lines = [
-    IOS_PODFILE_START,
-    "oliphaunt_podspecs_path = File.expand_path('../node_modules/@oliphaunt/react-native/ios/podspecs', __dir__)",
-    "pod 'COliphaunt', :podspec => File.join(oliphaunt_podspecs_path, 'COliphaunt.podspec'), :modular_headers => true",
-    "pod 'Oliphaunt', :podspec => File.join(oliphaunt_podspecs_path, 'Oliphaunt.podspec')",
-    "oliphaunt_payload_path = File.expand_path('oliphaunt', __dir__)",
-    "oliphaunt_payload_podspec = File.join(oliphaunt_payload_path, 'OliphauntReactNativePayload.podspec')",
-    "raise 'Oliphaunt iOS payload is missing; rerun Expo prebuild' unless File.file?(oliphaunt_payload_podspec)",
-    "pod 'OliphauntReactNativePayload', :path => oliphaunt_payload_path",
-  ];
-  lines.push(IOS_PODFILE_END);
-  return lines.join('\n');
-}
-
-function replaceMarkedBlock(contents, block) {
-  const start = contents.indexOf(IOS_PODFILE_START);
-  const end = contents.indexOf(IOS_PODFILE_END);
-  if (start === -1 && end === -1) {
-    return undefined;
-  }
-  if (start === -1 || end === -1 || end < start) {
-    throw new Error('ios/Podfile has a partial @oliphaunt/react-native managed block');
-  }
-  const lineStart = contents.lastIndexOf('\n', start) + 1;
-  const indent = contents.slice(lineStart, start).match(/^[ \t]*/)?.[0] ?? '';
-  const indentedBlock = block
-    .split('\n')
-    .map((line) => `${indent}${line}`)
-    .join('\n');
-  const afterEnd = end + IOS_PODFILE_END.length;
-  return `${contents.slice(0, lineStart)}${indentedBlock}${contents.slice(afterEnd)}`;
-}
-
-function insertIosPodfileBlock(contents, options = {}) {
-  const block = iosPodfileBlock(options);
-  const replaced = replaceMarkedBlock(contents, block);
-  if (replaced !== undefined) {
-    return `${replaced.replace(/\n+$/, '')}\n`;
-  }
-
-  const lines = contents.split(/\r?\n/);
-  const anchorIndex = lines.findIndex((line) => /config\s*=\s*use_native_modules!\s*/.test(line));
-  const fallbackIndex = lines.findIndex((line) => /^\s*use_expo_modules!\s*$/.test(line));
-  const insertAfter = anchorIndex >= 0 ? anchorIndex : fallbackIndex;
-  if (insertAfter < 0) {
-    throw new Error('ios/Podfile must call use_native_modules! or use_expo_modules! before Oliphaunt can add Swift SDK podspecs');
-  }
-  const indent = lines[insertAfter].match(/^\s*/)?.[0] ?? '';
-  const indentedBlock = block
-    .split('\n')
-    .map((line) => `${indent}${line}`)
-    .join('\n');
-  lines.splice(insertAfter + 1, 0, indentedBlock);
-  return `${lines.join('\n').replace(/\n+$/, '')}\n`;
-}
-
-function patchIosPodfile(file, options = {}) {
-  if (!fs.existsSync(file)) {
-    return false;
-  }
-  const before = fs.readFileSync(file, 'utf8');
-  const after = insertIosPodfileBlock(before, options);
-  if (after !== before) {
-    fs.writeFileSync(file, after);
-  }
-  return true;
-}
-
-function androidPluginVersion(options) {
-  return optionalString(options.kotlinPluginVersion) ?? packageMetadata.oliphaunt?.kotlinSdkVersion;
-}
-
-function androidAppPluginLine(version) {
-  return `    id 'dev.oliphaunt.android' version '${version}'`;
-}
-
-function insertAppGradlePlugin(contents, version) {
-  if (ANDROID_APP_PLUGIN_RE.test(contents)) {
-    return `${contents.replace(/\n+$/, '')}\n`;
-  }
-  const lines = contents.split(/\r?\n/);
-  const pluginsIndex = lines.findIndex((line) => /^\s*plugins\s*\{\s*$/.test(line));
-  if (pluginsIndex < 0) {
-    return `plugins {\n${androidAppPluginLine(version)}\n}\n\n${contents.replace(/\n+$/, '')}\n`;
-  }
-  let insertAt = pluginsIndex + 1;
-  while (insertAt < lines.length && lines[insertAt].trim().startsWith('//')) {
-    insertAt += 1;
-  }
-  lines.splice(insertAt, 0, androidAppPluginLine(version));
-  return `${lines.join('\n').replace(/\n+$/, '')}\n`;
-}
-
-function patchAndroidGradle(androidRoot, normalized) {
-  const version = androidPluginVersion(normalized);
-  if (!version) {
-    throw new Error('@oliphaunt/react-native requires oliphaunt.kotlinSdkVersion metadata or kotlinPluginVersion');
-  }
-  const appBuildGradle = path.join(androidRoot, 'app', 'build.gradle');
-  if (fs.existsSync(appBuildGradle)) {
-    const before = fs.readFileSync(appBuildGradle, 'utf8');
-    const after = insertAppGradlePlugin(before, version);
-    if (after !== before) {
-      fs.writeFileSync(appBuildGradle, after);
-    }
-  }
-}
-
-function withOliphaunt(config, options = {}) {
-  const plugin = require('expo/config-plugins');
-  const normalized = normalizeOptions(options);
-  // Expo's built-in iOS mods consume this synchronously and propagate it to
-  // both the Xcode project and Podfile.properties.json during prebuild.
-  config = ensureIosConfigDeploymentTarget(config);
-
-  config = plugin.withDangerousMod(config, [
-    'android',
-    (modConfig) => {
-      const projectRoot = modConfig.modRequest.projectRoot;
-      const androidRoot = path.join(projectRoot, 'android');
-      const installedExtensions = resolveInstalledExtensionOwners(
-        projectRoot,
-        normalized.extensions,
-        { liboliphauntVersion: normalized.liboliphauntVersion },
-      );
-      const androidOptions = {
-        ...normalized,
-        extensionVersions: installedExtensions.extensionVersions,
-        liboliphauntVersion: installedExtensions.liboliphauntVersion,
-      };
-      writeJson(path.join(androidRoot, 'oliphaunt.json'), androidOptions);
-      mergeProperties(path.join(androidRoot, 'gradle.properties'), {
-        oliphauntExtensions: normalized.extensions.join(','),
-        oliphauntExtensionVersions: serializeExtensionVersions(
-          installedExtensions.extensionVersions,
-        ),
-        oliphauntIcu: normalized.icu ? 'true' : undefined,
-        oliphauntLiboliphauntVersion: installedExtensions.liboliphauntVersion,
-        oliphauntAssetBaseUrl: normalized.assetBaseUrl,
-      });
-      patchAndroidGradle(androidRoot, androidOptions);
-      return modConfig;
-    },
-  ]);
-
-  config = plugin.withDangerousMod(config, [
-    'ios',
-    (modConfig) => {
-      const projectRoot = modConfig.modRequest.projectRoot;
-      const iosRoot = path.join(projectRoot, 'ios');
-      stageIosAppPayload(projectRoot, iosRoot, normalized);
-      writeJson(path.join(iosRoot, 'oliphaunt.json'), normalized);
-      writeJson(path.join(iosRoot, 'OliphauntExtensions.json'), {
-        extensions: normalized.extensions,
-        icu: normalized.icu,
-        liboliphauntVersion: normalized.liboliphauntVersion,
-        assetBaseUrl: normalized.assetBaseUrl,
-      });
-      ensureIosDeploymentTargetFile(path.join(iosRoot, 'Podfile.properties.json'));
-      patchIosPodfile(path.join(iosRoot, 'Podfile'), normalized);
-      return modConfig;
-    },
-  ]);
-
-  return config;
-}
-
-module.exports = withOliphaunt;
-module.exports.withOliphaunt = withOliphaunt;
-module.exports.normalizeOptions = normalizeOptions;
-module.exports.extensionPackageName = extensionPackageName;
-module.exports.selectedExtensionClosure = selectedExtensionClosure;
-module.exports.releaseOwnerForSqlName = releaseOwnerForSqlName;
-module.exports.resolveInstalledExtensionOwners = resolveInstalledExtensionOwners;
-module.exports.serializeExtensionVersions = serializeExtensionVersions;
-module.exports.readCarrierSummary = readCarrierSummary;
-module.exports.resolveIosCarrierManifests = resolveIosCarrierManifests;
-module.exports.iosStageCommand = iosStageCommand;
-module.exports.stageIosAppPayload = stageIosAppPayload;
-module.exports.insertIosPodfileBlock = insertIosPodfileBlock;
-module.exports.iosPodfileBlock = iosPodfileBlock;
-module.exports.ensureIosDeploymentTarget = ensureIosDeploymentTarget;
-module.exports.ensureIosConfigDeploymentTarget = ensureIosConfigDeploymentTarget;
-module.exports.insertAppGradlePlugin = insertAppGradlePlugin;
diff --git a/src/sdks/react-native/cpp/Jsi.h b/src/sdks/react-native/cpp/Jsi.h
new file mode 100644
index 000000000..f69c07a94
--- /dev/null
+++ b/src/sdks/react-native/cpp/Jsi.h
@@ -0,0 +1,222 @@
+#pragma once
+#include "Lifecycle.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace oliphaunt::reactnative {
+namespace jsi = facebook::jsi;
+
+class RuntimeCallback final {
+ public:
+  RuntimeCallback(jsi::Runtime &runtime, jsi::Function function,
+      const std::shared_ptr &invoker,
+      std::shared_ptr lifetime,
+      std::shared_ptr> settled = nullptr)
+      : callback_(runtime, std::move(function), invoker),
+        lifetime_(std::move(lifetime)), settled_(std::move(settled)) {}
+
+  template  void call(F action)
+  {
+    if (!lifetime_->active() || (settled_ && settled_->exchange(true))) return;
+    callback_.call([lifetime = lifetime_, action = std::move(action)](
+        jsi::Runtime &runtime, jsi::Function &function) mutable {
+      if (lifetime->active()) action(runtime, function);
+    });
+  }
+
+ private:
+  facebook::react::AsyncCallback<> callback_;
+  std::shared_ptr lifetime_;
+  std::shared_ptr> settled_;
+};
+
+struct PendingPromise {
+  std::shared_ptr resolve;
+  std::shared_ptr reject;
+};
+
+inline PendingPromise promiseCallbacks(jsi::Runtime &runtime,
+    const jsi::Value *args, size_t count,
+    const std::shared_ptr &invoker,
+    const std::shared_ptr &lifetime)
+{
+  if (!lifetime->active()) throw jsi::JSError(runtime, invalidatedMessage);
+  if (count < 2 || !args[0].isObject() ||
+      !args[0].asObject(runtime).isFunction(runtime) || !args[1].isObject() ||
+      !args[1].asObject(runtime).isFunction(runtime))
+    throw jsi::JSError(runtime, "liboliphaunt JSI Promise executor received invalid callbacks");
+  auto settled = std::make_shared>(false);
+  return {
+    std::make_shared(runtime,
+        args[0].asObject(runtime).getFunction(runtime), invoker, lifetime, settled),
+    std::make_shared(runtime,
+        args[1].asObject(runtime).getFunction(runtime), invoker, lifetime, settled),
+  };
+}
+class OliphauntMutableBuffer final : public jsi::MutableBuffer {
+ public:
+  explicit OliphauntMutableBuffer(std::vector bytes)
+      : bytes_(std::move(bytes)) {}
+
+  size_t size() const override
+  {
+    return bytes_.size();
+  }
+
+  uint8_t *data() override
+  {
+    return bytes_.data();
+  }
+
+ private:
+  std::vector bytes_;
+};
+
+inline jsi::ArrayBuffer arrayBufferFromBytes(jsi::Runtime &runtime, std::vector bytes)
+{
+  return jsi::ArrayBuffer(
+      runtime,
+      std::make_shared(std::move(bytes)));
+}
+
+inline jsi::Value createError(jsi::Runtime &runtime, const std::string &message)
+{
+  return runtime.global()
+      .getPropertyAsFunction(runtime, "Error")
+      .callAsConstructor(runtime, jsi::String::createFromUtf8(runtime, message));
+}
+
+inline jsi::Value createProtocolCallbackAbortedError(
+    jsi::Runtime &runtime,
+    const std::string &message)
+{
+  auto value = createError(runtime, message);
+  auto object = value.asObject(runtime);
+  object.setProperty(runtime, "__oliphauntProtocolCallbackAborted", true);
+  return object;
+}
+
+inline size_t copySizeArgument(jsi::Runtime &runtime, double value, const char *name)
+{
+  constexpr double kMaxSafeInteger = 9007199254740991.0;
+  if (!std::isfinite(value) ||
+      value < 0 ||
+      std::trunc(value) != value ||
+      value > kMaxSafeInteger ||
+      value > static_cast(std::numeric_limits::max())) {
+    throw jsi::JSError(
+        runtime,
+        std::string("liboliphaunt JSI ") + name + " must be a non-negative integer");
+  }
+  return static_cast(value);
+}
+
+inline int64_t copyHandleArgument(jsi::Runtime &runtime, const jsi::Value &value)
+{
+  constexpr double kMaxSafeInteger = 9007199254740991.0;
+  if (!value.isNumber()) {
+    throw jsi::JSError(runtime, "liboliphaunt JSI handle must be a number");
+  }
+  double handle = value.asNumber();
+  if (!std::isfinite(handle) ||
+      handle <= 0 ||
+      std::trunc(handle) != handle ||
+      handle > kMaxSafeInteger ||
+      handle > static_cast(std::numeric_limits::max())) {
+    throw jsi::JSError(runtime, "liboliphaunt JSI handle must be a positive safe integer");
+  }
+  return static_cast(handle);
+}
+
+inline std::vector copyBinaryArgument(jsi::Runtime &runtime, const jsi::Value &value)
+{
+  if (!value.isObject()) {
+    throw jsi::JSError(runtime, "liboliphaunt JSI request must be an ArrayBuffer or typed array");
+  }
+
+  auto object = value.asObject(runtime);
+  size_t byteOffset = 0;
+  size_t byteLength = 0;
+  jsi::ArrayBuffer buffer = [&]() {
+    if (object.isArrayBuffer(runtime)) {
+      auto arrayBuffer = object.getArrayBuffer(runtime);
+      byteLength = arrayBuffer.size(runtime);
+      return arrayBuffer;
+    }
+
+    auto bufferValue = object.getProperty(runtime, "buffer");
+    if (!bufferValue.isObject() || !bufferValue.asObject(runtime).isArrayBuffer(runtime)) {
+      throw jsi::JSError(runtime, "liboliphaunt JSI request must be an ArrayBuffer or typed array");
+    }
+    auto offsetValue = object.getProperty(runtime, "byteOffset");
+    auto lengthValue = object.getProperty(runtime, "byteLength");
+    if (!offsetValue.isNumber() || !lengthValue.isNumber()) {
+      throw jsi::JSError(runtime, "liboliphaunt JSI typed-array request is missing byteOffset/byteLength");
+    }
+    byteOffset = copySizeArgument(runtime, offsetValue.asNumber(), "typed-array byteOffset");
+    byteLength = copySizeArgument(runtime, lengthValue.asNumber(), "typed-array byteLength");
+    return bufferValue.asObject(runtime).getArrayBuffer(runtime);
+  }();
+
+  if (byteOffset > buffer.size(runtime) || byteLength > buffer.size(runtime) - byteOffset) {
+    throw jsi::JSError(runtime, "liboliphaunt JSI typed-array request is out of bounds");
+  }
+
+  if (byteLength == 0) return {};
+  const uint8_t *begin = buffer.data(runtime) + byteOffset;
+  return std::vector(begin, begin + byteLength);
+}
+
+inline std::string copyStringArgument(jsi::Runtime &runtime, const jsi::Value &value, const char *name)
+{
+  if (!value.isString()) {
+    throw jsi::JSError(runtime, std::string("liboliphaunt JSI ") + name + " must be a string");
+  }
+  return value.asString(runtime).utf8(runtime);
+}
+
+inline std::optional copyOptionalStringArgument(
+    jsi::Runtime &runtime,
+    const jsi::Value &value,
+    const char *name)
+{
+  if (value.isNull() || value.isUndefined()) {
+    return std::nullopt;
+  }
+  return copyStringArgument(runtime, value, name);
+}
+
+
+inline void deliverChunk(jsi::Runtime &runtime, jsi::Function &chunkFunction,
+    std::vector bytes, const std::shared_ptr &acknowledgement)
+{
+        try {
+          auto result = chunkFunction.call(
+              runtime,
+              arrayBufferFromBytes(runtime, std::move(bytes)));
+          if (result.isObject()) {
+            auto resultObject = result.asObject(runtime);
+            auto failureMarker = resultObject.getProperty(
+                runtime,
+                "__oliphauntProtocolChunkFailure");
+            if (failureMarker.isBool() && failureMarker.getBool()) {
+              acknowledgement->reject("protocol stream callback failed");
+              return;
+            }
+          }
+          acknowledgement->resolve();
+        } catch (const jsi::JSError &error) {
+          acknowledgement->reject(error.what());
+        } catch (const std::exception &error) {
+          acknowledgement->reject(error.what());
+        } catch (...) {
+          acknowledgement->reject("protocol stream callback failed");
+        }
+}
+
+} // namespace oliphaunt::reactnative
diff --git a/src/sdks/react-native/cpp/Lifecycle.h b/src/sdks/react-native/cpp/Lifecycle.h
new file mode 100644
index 000000000..b2b31e17c
--- /dev/null
+++ b/src/sdks/react-native/cpp/Lifecycle.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+namespace oliphaunt::reactnative {
+
+inline constexpr const char *invalidatedMessage =
+    "React Native Oliphaunt module has been invalidated";
+
+class ChunkAcknowledgement final {
+ public:
+  void resolve() { finish(std::nullopt); }
+  void reject(std::string message) { finish(std::move(message)); }
+  std::optional wait()
+  {
+    std::unique_lock lock(mutex_);
+    condition_.wait(lock, [this] { return complete_; });
+    return error_;
+  }
+
+ private:
+  void finish(std::optional error)
+  {
+    {
+      std::lock_guard lock(mutex_);
+      if (complete_) return;
+      error_ = std::move(error);
+      complete_ = true;
+    }
+    condition_.notify_all();
+  }
+  std::mutex mutex_;
+  std::condition_variable condition_;
+  bool complete_ = false;
+  std::optional error_;
+};
+
+// One instance belongs to one installed RN runtime. Registering a wait and
+// invalidating the owner share a lock, so teardown cannot miss a new waiter.
+class RuntimeLifetime {
+ public:
+  bool active() const { return active_.load(); }
+  std::shared_ptr acknowledge()
+  {
+    auto result = std::make_shared();
+    std::lock_guard lock(mutex_);
+    if (!active_) {
+      result->reject(invalidatedMessage);
+      return result;
+    }
+    waits_.erase(std::remove_if(waits_.begin(), waits_.end(),
+        [](const auto &entry) { return entry.expired(); }), waits_.end());
+    waits_.emplace_back(result);
+    return result;
+  }
+  void invalidate()
+  {
+    std::lock_guard lock(mutex_);
+    active_ = false;
+    for (const auto &entry : waits_)
+      if (auto wait = entry.lock()) wait->reject(invalidatedMessage);
+    waits_.clear();
+  }
+  ~RuntimeLifetime() { invalidate(); }
+
+ private:
+  std::atomic active_{true};
+  std::mutex mutex_;
+  std::vector> waits_;
+};
+
+} // namespace oliphaunt::reactnative
diff --git a/src/sdks/react-native/cpp/Lifecycle.test.cpp b/src/sdks/react-native/cpp/Lifecycle.test.cpp
new file mode 100644
index 000000000..810b7d5d9
--- /dev/null
+++ b/src/sdks/react-native/cpp/Lifecycle.test.cpp
@@ -0,0 +1,42 @@
+#include "Lifecycle.h"
+#include 
+#include 
+#include 
+#include 
+
+using namespace oliphaunt::reactnative;
+using namespace std::chrono_literals;
+
+int main()
+{
+  auto first = std::make_shared();
+  auto second = std::make_shared();
+  auto firstWait = first->acknowledge();
+  auto secondWait = second->acknowledge();
+  auto blocked = std::async(std::launch::async, [firstWait] { return firstWait->wait(); });
+  first->invalidate();
+  assert(blocked.wait_for(2s) == std::future_status::ready);
+  assert(blocked.get() == invalidatedMessage);
+  assert(second->active());
+  secondWait->resolve();
+  secondWait->reject("late rejection must not replace successful delivery");
+  assert(!secondWait->wait());
+  assert(first->acknowledge()->wait() == invalidatedMessage);
+
+  // A producer racing teardown must either be registered before invalidation
+  // or immediately rejected. Neither outcome leaves a blocked native worker.
+  for (int i = 0; i < 1000; ++i) {
+    auto owner = std::make_shared();
+    auto work = std::async(std::launch::async, [owner] {
+      return owner->acknowledge()->wait();
+    });
+    owner->invalidate();
+    assert(work.wait_for(2s) == std::future_status::ready);
+    assert(work.get() == invalidatedMessage);
+  }
+
+  auto abandonedOwner = std::make_shared();
+  auto abandonedWait = abandonedOwner->acknowledge();
+  abandonedOwner.reset();
+  assert(abandonedWait->wait() == invalidatedMessage);
+}
diff --git a/src/sdks/react-native/ios/Oliphaunt.mm b/src/sdks/react-native/ios/Oliphaunt.mm
index 966d649d5..47ee54e3b 100644
--- a/src/sdks/react-native/ios/Oliphaunt.mm
+++ b/src/sdks/react-native/ios/Oliphaunt.mm
@@ -4,6 +4,7 @@
 #import 
 
 #ifdef RCT_NEW_ARCH_ENABLED
+#include "../cpp/Jsi.h"
 #include 
 #include 
 #include 
@@ -25,93 +26,7 @@
     @"dev.oliphaunt.reactnative.ios.protocolStreamCallbackAborted";
 
 #ifdef RCT_NEW_ARCH_ENABLED
-class OliphauntChunkAcknowledgement final {
- public:
-  void resolve()
-  {
-    finish(std::nullopt);
-  }
-
-  void reject(std::string message)
-  {
-    finish(std::move(message));
-  }
-
-  std::optional wait()
-  {
-    std::unique_lock lock(mutex_);
-    condition_.wait(lock, [this]() { return complete_; });
-    return error_;
-  }
-
- private:
-  void finish(std::optional error)
-  {
-    {
-      std::lock_guard lock(mutex_);
-      if (complete_) {
-        return;
-      }
-      error_ = std::move(error);
-      complete_ = true;
-    }
-    condition_.notify_one();
-  }
-
-  std::mutex mutex_;
-  std::condition_variable condition_;
-  bool complete_ = false;
-  std::optional error_;
-};
-
-static std::mutex gOliphauntChunkAcknowledgementsMutex;
-static std::vector> gOliphauntChunkAcknowledgements;
-
-static void OliphauntRegisterChunkAcknowledgement(
-    const std::shared_ptr &acknowledgement)
-{
-  std::lock_guard lock(gOliphauntChunkAcknowledgementsMutex);
-  gOliphauntChunkAcknowledgements.erase(
-      std::remove_if(
-          gOliphauntChunkAcknowledgements.begin(),
-          gOliphauntChunkAcknowledgements.end(),
-          [](const auto &entry) { return entry.expired(); }),
-      gOliphauntChunkAcknowledgements.end());
-  gOliphauntChunkAcknowledgements.emplace_back(acknowledgement);
-}
-
-static void OliphauntUnregisterChunkAcknowledgement(
-    const std::shared_ptr &acknowledgement)
-{
-  std::lock_guard lock(gOliphauntChunkAcknowledgementsMutex);
-  gOliphauntChunkAcknowledgements.erase(
-      std::remove_if(
-          gOliphauntChunkAcknowledgements.begin(),
-          gOliphauntChunkAcknowledgements.end(),
-          [&acknowledgement](const auto &entry) {
-            auto current = entry.lock();
-            return current == nullptr || current == acknowledgement;
-          }),
-      gOliphauntChunkAcknowledgements.end());
-}
-
-static void OliphauntAbortChunkAcknowledgements(void)
-{
-  std::vector> acknowledgements;
-  {
-    std::lock_guard lock(gOliphauntChunkAcknowledgementsMutex);
-    acknowledgements.reserve(gOliphauntChunkAcknowledgements.size());
-    for (const auto &entry : gOliphauntChunkAcknowledgements) {
-      if (auto acknowledgement = entry.lock()) {
-        acknowledgements.push_back(std::move(acknowledgement));
-      }
-    }
-    gOliphauntChunkAcknowledgements.clear();
-  }
-  for (const auto &acknowledgement : acknowledgements) {
-    acknowledgement->reject("React Native Oliphaunt module has been invalidated");
-  }
-}
+using namespace oliphaunt::reactnative;
 
 static NSError *OliphauntProtocolStreamCallbackError(const std::string &message)
 {
@@ -343,34 +258,6 @@ static void OliphauntSetIfPresent(NSMutableDictionary *dictionary, NSString *key
   return dictionary;
 }
 
-class OliphauntMutableBuffer final : public facebook::jsi::MutableBuffer {
- public:
-  explicit OliphauntMutableBuffer(std::vector bytes)
-      : bytes_(std::move(bytes)) {}
-
-  size_t size() const override
-  {
-    return bytes_.size();
-  }
-
-  uint8_t *data() override
-  {
-    return bytes_.data();
-  }
-
- private:
-  std::vector bytes_;
-};
-
-static facebook::jsi::ArrayBuffer OliphauntArrayBufferFromBytes(
-    facebook::jsi::Runtime &runtime,
-    std::vector bytes)
-{
-  return facebook::jsi::ArrayBuffer(
-      runtime,
-      std::make_shared(std::move(bytes)));
-}
-
 static std::vector OliphauntBytesFromNSData(NSData *_Nullable data)
 {
   std::vector bytes;
@@ -381,95 +268,6 @@ size_t size() const override
   return bytes;
 }
 
-static size_t OliphauntCopySizeArgument(
-    facebook::jsi::Runtime &runtime,
-    double value,
-    const char *name)
-{
-  constexpr double kMaxSafeInteger = 9007199254740991.0;
-  if (!std::isfinite(value) ||
-      value < 0 ||
-      std::trunc(value) != value ||
-      value > kMaxSafeInteger ||
-      value > static_cast(std::numeric_limits::max())) {
-    throw facebook::jsi::JSError(
-        runtime,
-        std::string("liboliphaunt JSI ") + name + " must be a non-negative integer");
-  }
-  return static_cast(value);
-}
-
-static double OliphauntCopyHandleArgument(
-    facebook::jsi::Runtime &runtime,
-    const facebook::jsi::Value &value)
-{
-  if (!value.isNumber()) {
-    throw facebook::jsi::JSError(runtime, "liboliphaunt JSI handle must be a number");
-  }
-  double handle = value.asNumber();
-  if (!OliphauntIsValidHandle(handle)) {
-    throw facebook::jsi::JSError(runtime, "liboliphaunt JSI handle must be a positive safe integer");
-  }
-  return handle;
-}
-
-static std::vector OliphauntCopyBinaryArgument(
-    facebook::jsi::Runtime &runtime,
-    const facebook::jsi::Value &value)
-{
-  if (!value.isObject()) {
-    throw facebook::jsi::JSError(runtime, "liboliphaunt JSI request must be an ArrayBuffer or typed array");
-  }
-
-  auto object = value.asObject(runtime);
-  size_t byteOffset = 0;
-  size_t byteLength = 0;
-  facebook::jsi::ArrayBuffer buffer = [&]() {
-    if (object.isArrayBuffer(runtime)) {
-      auto arrayBuffer = object.getArrayBuffer(runtime);
-      byteLength = arrayBuffer.size(runtime);
-      return arrayBuffer;
-    }
-
-    auto bufferValue = object.getProperty(runtime, "buffer");
-    if (!bufferValue.isObject() || !bufferValue.asObject(runtime).isArrayBuffer(runtime)) {
-      throw facebook::jsi::JSError(runtime, "liboliphaunt JSI request must be an ArrayBuffer or typed array");
-    }
-    auto offsetValue = object.getProperty(runtime, "byteOffset");
-    auto lengthValue = object.getProperty(runtime, "byteLength");
-    if (!offsetValue.isNumber() || !lengthValue.isNumber()) {
-      throw facebook::jsi::JSError(runtime, "liboliphaunt JSI typed-array request is missing byteOffset/byteLength");
-    }
-    byteOffset = OliphauntCopySizeArgument(
-        runtime,
-        offsetValue.asNumber(),
-        "typed-array byteOffset");
-    byteLength = OliphauntCopySizeArgument(
-        runtime,
-        lengthValue.asNumber(),
-        "typed-array byteLength");
-    return bufferValue.asObject(runtime).getArrayBuffer(runtime);
-  }();
-
-  if (byteOffset > buffer.size(runtime) || byteLength > buffer.size(runtime) - byteOffset) {
-    throw facebook::jsi::JSError(runtime, "liboliphaunt JSI typed-array request is out of bounds");
-  }
-
-  const uint8_t *begin = buffer.data(runtime) + byteOffset;
-  return std::vector(begin, begin + byteLength);
-}
-
-static std::string OliphauntCopyStringArgument(
-    facebook::jsi::Runtime &runtime,
-    const facebook::jsi::Value &value,
-    const char *name)
-{
-  if (!value.isString()) {
-    throw facebook::jsi::JSError(runtime, std::string("liboliphaunt JSI ") + name + " must be a string");
-  }
-  return value.asString(runtime).utf8(runtime);
-}
-
 static NSString *OliphauntNSStringFromString(const std::string &value)
 {
   return [NSString stringWithUTF8String:value.c_str()] ?: @"";
@@ -483,27 +281,9 @@ static double OliphauntCopyHandleArgument(
   if (value.isNull() || value.isUndefined()) {
     return nil;
   }
-  return OliphauntNSStringFromString(OliphauntCopyStringArgument(runtime, value, name));
-}
-
-static facebook::jsi::Value OliphauntCreateError(
-    facebook::jsi::Runtime &runtime,
-    const std::string &message)
-{
-  return runtime.global()
-      .getPropertyAsFunction(runtime, "Error")
-      .callAsConstructor(runtime, facebook::jsi::String::createFromUtf8(runtime, message));
+  return OliphauntNSStringFromString(copyStringArgument(runtime, value, name));
 }
 
-static facebook::jsi::Value OliphauntCreateProtocolCallbackAbortedError(
-    facebook::jsi::Runtime &runtime,
-    const std::string &message)
-{
-  auto value = OliphauntCreateError(runtime, message);
-  auto object = value.asObject(runtime);
-  object.setProperty(runtime, "__oliphauntProtocolCallbackAborted", true);
-  return object;
-}
 #endif
 
 @interface Oliphaunt ()
@@ -515,6 +295,9 @@ @implementation Oliphaunt {
   dispatch_queue_t _methodQueue;
   uint64_t _nativeDirectClaim;
   BOOL _invalidated;
+#ifdef RCT_NEW_ARCH_ENABLED
+  std::shared_ptr _jsiLifetime;
+#endif
 }
 
 RCT_EXPORT_MODULE(Oliphaunt)
@@ -528,6 +311,9 @@ - (instancetype)init
 {
   if (self = [super init]) {
     _sessions = [NSMutableDictionary new];
+#ifdef RCT_NEW_ARCH_ENABLED
+    _jsiLifetime = std::make_shared();
+#endif
     _methodQueue = dispatch_queue_create("dev.oliphaunt.reactnative.ios.module", DISPATCH_QUEUE_SERIAL);
   }
   return self;
@@ -741,6 +527,13 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                           callInvoker:(const std::shared_ptr &)callInvoker
 {
   __weak Oliphaunt *weakSelf = self;
+  std::shared_ptr lifetime;
+  @synchronized (self) {
+    _jsiLifetime->invalidate();
+    lifetime = std::make_shared();
+    if (_invalidated) lifetime->invalidate();
+    _jsiLifetime = lifetime;
+  }
   auto transport = facebook::jsi::Object(runtime);
   transport.setProperty(runtime, "version", 1);
   transport.setProperty(
@@ -760,7 +553,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                   runtime,
                   "liboliphaunt JSI closeIfGeneration expects a generation");
             }
-            double generation = OliphauntCopyHandleArgument(runtime, args[0]);
+            double generation = copyHandleArgument(runtime, args[0]);
             Oliphaunt *strongSelf = weakSelf;
             if (strongSelf != nil) {
               [strongSelf closeIfGeneration:generation];
@@ -774,7 +567,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
           runtime,
           facebook::jsi::PropNameID::forAscii(runtime, "liboliphauntExecProtocolRaw"),
           1,
-          [weakSelf, callInvoker](
+          [lifetime, weakSelf, callInvoker](
               facebook::jsi::Runtime &runtime,
               const facebook::jsi::Value &,
               const facebook::jsi::Value *args,
@@ -783,39 +576,26 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
               throw facebook::jsi::JSError(runtime, "liboliphaunt JSI execProtocolRaw expects handle and request");
             }
 
-            double handle = OliphauntCopyHandleArgument(runtime, args[0]);
-            std::vector request = OliphauntCopyBinaryArgument(runtime, args[1]);
+            double handle = copyHandleArgument(runtime, args[0]);
+            std::vector request = copyBinaryArgument(runtime, args[1]);
             auto requestData = [NSData dataWithBytes:request.data() length:request.size()];
             auto promiseConstructor = runtime.global().getPropertyAsFunction(runtime, "Promise");
             auto executor = facebook::jsi::Function::createFromHostFunction(
                 runtime,
                 facebook::jsi::PropNameID::forAscii(runtime, "liboliphauntExecProtocolRawExecutor"),
                 2,
-                [weakSelf, callInvoker, handle, requestData](
+                [lifetime, weakSelf, callInvoker, handle, requestData](
                     facebook::jsi::Runtime &runtime,
                     const facebook::jsi::Value &,
                     const facebook::jsi::Value *promiseArgs,
                     size_t promiseArgCount) -> facebook::jsi::Value {
-                  if (promiseArgCount < 2 ||
-                      !promiseArgs[0].isObject() ||
-                      !promiseArgs[0].asObject(runtime).isFunction(runtime) ||
-                      !promiseArgs[1].isObject() ||
-                      !promiseArgs[1].asObject(runtime).isFunction(runtime)) {
-                    throw facebook::jsi::JSError(runtime, "liboliphaunt JSI Promise executor received invalid callbacks");
-                  }
-
-                  auto resolve = std::make_shared>(
-                      runtime,
-                      promiseArgs[0].asObject(runtime).getFunction(runtime),
-                      callInvoker);
-                  auto reject = std::make_shared>(
-                      runtime,
-                      promiseArgs[1].asObject(runtime).getFunction(runtime),
-                      callInvoker);
+                  auto pending = promiseCallbacks(runtime, promiseArgs, promiseArgCount, callInvoker, lifetime);
+                  auto resolve = pending.resolve;
+                  auto reject = pending.reject;
                   Oliphaunt *strongSelf = weakSelf;
                   if (strongSelf == nil) {
                     reject->call([](facebook::jsi::Runtime &runtime, facebook::jsi::Function &rejectFunction) {
-                      rejectFunction.call(runtime, OliphauntCreateError(runtime, "liboliphaunt native module is unavailable"));
+                      rejectFunction.call(runtime, createError(runtime, "liboliphaunt native module is unavailable"));
                     });
                     return facebook::jsi::Value::undefined();
                   }
@@ -827,7 +607,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                       const char *errorMessage = error.localizedDescription.UTF8String;
                       std::string message = errorMessage != nullptr ? errorMessage : "liboliphaunt exec failed";
                       reject->call([message](facebook::jsi::Runtime &runtime, facebook::jsi::Function &rejectFunction) {
-                        rejectFunction.call(runtime, OliphauntCreateError(runtime, message));
+                        rejectFunction.call(runtime, createError(runtime, message));
                       });
                       return;
                     }
@@ -835,7 +615,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                     resolve->call([bytes = std::move(bytes)](
                                       facebook::jsi::Runtime &runtime,
                                       facebook::jsi::Function &resolveFunction) mutable {
-                      resolveFunction.call(runtime, OliphauntArrayBufferFromBytes(runtime, std::move(bytes)));
+                      resolveFunction.call(runtime, arrayBufferFromBytes(runtime, std::move(bytes)));
                     });
                   }];
                   return facebook::jsi::Value::undefined();
@@ -849,7 +629,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
           runtime,
           facebook::jsi::PropNameID::forAscii(runtime, "liboliphauntExecProtocolStream"),
           3,
-          [weakSelf, callInvoker](
+          [lifetime, weakSelf, callInvoker](
               facebook::jsi::Runtime &runtime,
               const facebook::jsi::Value &,
               const facebook::jsi::Value *args,
@@ -858,44 +638,30 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
               throw facebook::jsi::JSError(runtime, "liboliphaunt JSI execProtocolStream expects handle, request, and onChunk");
             }
 
-            double handle = OliphauntCopyHandleArgument(runtime, args[0]);
-            std::vector request = OliphauntCopyBinaryArgument(runtime, args[1]);
+            double handle = copyHandleArgument(runtime, args[0]);
+            std::vector request = copyBinaryArgument(runtime, args[1]);
             auto requestData = [NSData dataWithBytes:request.data() length:request.size()];
-            auto chunkCallback = std::make_shared>(
+            auto chunkCallback = std::make_shared(
                 runtime,
                 args[2].asObject(runtime).getFunction(runtime),
-                callInvoker);
+                callInvoker, lifetime);
             auto promiseConstructor = runtime.global().getPropertyAsFunction(runtime, "Promise");
             auto executor = facebook::jsi::Function::createFromHostFunction(
                 runtime,
                 facebook::jsi::PropNameID::forAscii(runtime, "liboliphauntExecProtocolStreamExecutor"),
                 2,
-                [weakSelf, callInvoker, handle, requestData, chunkCallback](
+                [lifetime, weakSelf, callInvoker, handle, requestData, chunkCallback](
                     facebook::jsi::Runtime &runtime,
                     const facebook::jsi::Value &,
                     const facebook::jsi::Value *promiseArgs,
                     size_t promiseArgCount) -> facebook::jsi::Value {
-                  if (promiseArgCount < 2 ||
-                      !promiseArgs[0].isObject() ||
-                      !promiseArgs[0].asObject(runtime).isFunction(runtime) ||
-                      !promiseArgs[1].isObject() ||
-                      !promiseArgs[1].asObject(runtime).isFunction(runtime)) {
-                    throw facebook::jsi::JSError(runtime, "liboliphaunt JSI Promise executor received invalid callbacks");
-                  }
-
-                  auto resolve = std::make_shared>(
-                      runtime,
-                      promiseArgs[0].asObject(runtime).getFunction(runtime),
-                      callInvoker);
-                  auto reject = std::make_shared>(
-                      runtime,
-                      promiseArgs[1].asObject(runtime).getFunction(runtime),
-                      callInvoker);
-                  auto settled = std::make_shared>(false);
+                  auto pending = promiseCallbacks(runtime, promiseArgs, promiseArgCount, callInvoker, lifetime);
+                  auto resolve = pending.resolve;
+                  auto reject = pending.reject;
                   Oliphaunt *strongSelf = weakSelf;
                   if (strongSelf == nil) {
                     reject->call([](facebook::jsi::Runtime &runtime, facebook::jsi::Function &rejectFunction) {
-                      rejectFunction.call(runtime, OliphauntCreateError(runtime, "liboliphaunt native module is unavailable"));
+                      rejectFunction.call(runtime, createError(runtime, "liboliphaunt native module is unavailable"));
                     });
                     return facebook::jsi::Value::undefined();
                   }
@@ -911,8 +677,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                       }
                     }
                     std::vector bytes = OliphauntBytesFromNSData(chunk);
-                    auto acknowledgement = std::make_shared();
-                    OliphauntRegisterChunkAcknowledgement(acknowledgement);
+                    auto acknowledgement = lifetime->acknowledge();
                     try {
                       chunkCallback->call([strongSelf, bytes = std::move(bytes), acknowledgement](
                                               facebook::jsi::Runtime &runtime,
@@ -923,28 +688,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                             return;
                           }
                         }
-                        try {
-                          auto result = chunkFunction.call(
-                              runtime,
-                              OliphauntArrayBufferFromBytes(runtime, std::move(bytes)));
-                          if (result.isObject()) {
-                            auto resultObject = result.asObject(runtime);
-                            auto failureMarker = resultObject.getProperty(
-                                runtime,
-                                "__oliphauntProtocolChunkFailure");
-                            if (failureMarker.isBool() && failureMarker.getBool()) {
-                              acknowledgement->reject("protocol stream callback failed");
-                              return;
-                            }
-                          }
-                          acknowledgement->resolve();
-                        } catch (const facebook::jsi::JSError &error) {
-                          acknowledgement->reject(error.what());
-                        } catch (const std::exception &error) {
-                          acknowledgement->reject(error.what());
-                        } catch (...) {
-                          acknowledgement->reject("protocol stream callback failed");
-                        }
+                        deliverChunk(runtime, chunkFunction, std::move(bytes), acknowledgement);
                       });
                     } catch (const std::exception &error) {
                       acknowledgement->reject(error.what());
@@ -952,7 +696,6 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                       acknowledgement->reject("failed to schedule protocol stream callback");
                     }
                     auto error = acknowledgement->wait();
-                    OliphauntUnregisterChunkAcknowledgement(acknowledgement);
                     return error ? OliphauntProtocolStreamCallbackError(*error) : nil;
                   }
                                                 completion:^(NSError *_Nullable error) {
@@ -961,9 +704,6 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                         return;
                       }
                     }
-                    if (settled->exchange(true)) {
-                      return;
-                    }
                     if (error != nil) {
                       const char *errorMessage = error.localizedDescription.UTF8String;
                       std::string message = errorMessage != nullptr ? errorMessage : "liboliphaunt stream failed";
@@ -973,8 +713,8 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                         rejectFunction.call(
                             runtime,
                             callbackAborted
-                                ? OliphauntCreateProtocolCallbackAbortedError(runtime, message)
-                                : OliphauntCreateError(runtime, message));
+                                ? createProtocolCallbackAbortedError(runtime, message)
+                                : createError(runtime, message));
                       });
                       return;
                     }
@@ -993,7 +733,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
           runtime,
           facebook::jsi::PropNameID::forAscii(runtime, "liboliphauntBackup"),
           2,
-          [weakSelf, callInvoker](
+          [lifetime, weakSelf, callInvoker](
               facebook::jsi::Runtime &runtime,
               const facebook::jsi::Value &,
               const facebook::jsi::Value *args,
@@ -1002,37 +742,24 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
               throw facebook::jsi::JSError(runtime, "liboliphaunt JSI backup expects a handle");
             }
 
-            double handle = OliphauntCopyHandleArgument(runtime, args[0]);
+            double handle = copyHandleArgument(runtime, args[0]);
             auto promiseConstructor = runtime.global().getPropertyAsFunction(runtime, "Promise");
             auto executor = facebook::jsi::Function::createFromHostFunction(
                 runtime,
                 facebook::jsi::PropNameID::forAscii(runtime, "liboliphauntBackupExecutor"),
                 2,
-                [weakSelf, callInvoker, handle](
+                [lifetime, weakSelf, callInvoker, handle](
                     facebook::jsi::Runtime &runtime,
                     const facebook::jsi::Value &,
                     const facebook::jsi::Value *promiseArgs,
                     size_t promiseArgCount) -> facebook::jsi::Value {
-                  if (promiseArgCount < 2 ||
-                      !promiseArgs[0].isObject() ||
-                      !promiseArgs[0].asObject(runtime).isFunction(runtime) ||
-                      !promiseArgs[1].isObject() ||
-                      !promiseArgs[1].asObject(runtime).isFunction(runtime)) {
-                    throw facebook::jsi::JSError(runtime, "liboliphaunt JSI Promise executor received invalid callbacks");
-                  }
-
-                  auto resolve = std::make_shared>(
-                      runtime,
-                      promiseArgs[0].asObject(runtime).getFunction(runtime),
-                      callInvoker);
-                  auto reject = std::make_shared>(
-                      runtime,
-                      promiseArgs[1].asObject(runtime).getFunction(runtime),
-                      callInvoker);
+                  auto pending = promiseCallbacks(runtime, promiseArgs, promiseArgCount, callInvoker, lifetime);
+                  auto resolve = pending.resolve;
+                  auto reject = pending.reject;
                   Oliphaunt *strongSelf = weakSelf;
                   if (strongSelf == nil) {
                     reject->call([](facebook::jsi::Runtime &runtime, facebook::jsi::Function &rejectFunction) {
-                      rejectFunction.call(runtime, OliphauntCreateError(runtime, "liboliphaunt native module is unavailable"));
+                      rejectFunction.call(runtime, createError(runtime, "liboliphaunt native module is unavailable"));
                     });
                     return facebook::jsi::Value::undefined();
                   }
@@ -1043,7 +770,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                       const char *errorMessage = error.localizedDescription.UTF8String;
                       std::string message = errorMessage != nullptr ? errorMessage : "liboliphaunt backup failed";
                       reject->call([message](facebook::jsi::Runtime &runtime, facebook::jsi::Function &rejectFunction) {
-                        rejectFunction.call(runtime, OliphauntCreateError(runtime, message));
+                        rejectFunction.call(runtime, createError(runtime, message));
                       });
                       return;
                     }
@@ -1051,7 +778,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                     resolve->call([bytes = std::move(bytes)](
                                       facebook::jsi::Runtime &runtime,
                                       facebook::jsi::Function &resolveFunction) mutable {
-                      resolveFunction.call(runtime, OliphauntArrayBufferFromBytes(runtime, std::move(bytes)));
+                      resolveFunction.call(runtime, arrayBufferFromBytes(runtime, std::move(bytes)));
                     });
                   }];
                   return facebook::jsi::Value::undefined();
@@ -1065,7 +792,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
           runtime,
           facebook::jsi::PropNameID::forAscii(runtime, "liboliphauntRestore"),
           2,
-          [weakSelf, callInvoker](
+          [lifetime, weakSelf, callInvoker](
               facebook::jsi::Runtime &runtime,
               const facebook::jsi::Value &,
               const facebook::jsi::Value *args,
@@ -1079,7 +806,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
             }
             auto destination = args[0].asObject(runtime);
             NSString *storageKind = OliphauntNSStringFromString(
-                OliphauntCopyStringArgument(
+                copyStringArgument(
                     runtime,
                     destination.getProperty(runtime, "storageKind"),
                     "restore storageKind"));
@@ -1091,38 +818,25 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                 runtime,
                 destination.getProperty(runtime, "storageName"),
                 "restore storageName");
-            std::vector artifact = OliphauntCopyBinaryArgument(runtime, args[1]);
+            std::vector artifact = copyBinaryArgument(runtime, args[1]);
             auto artifactData = [NSData dataWithBytes:artifact.data() length:artifact.size()];
             auto promiseConstructor = runtime.global().getPropertyAsFunction(runtime, "Promise");
             auto executor = facebook::jsi::Function::createFromHostFunction(
                 runtime,
                 facebook::jsi::PropNameID::forAscii(runtime, "liboliphauntRestoreExecutor"),
                 2,
-                [weakSelf, callInvoker, storageKind, storagePath, storageName, artifactData](
+                [lifetime, weakSelf, callInvoker, storageKind, storagePath, storageName, artifactData](
                     facebook::jsi::Runtime &runtime,
                     const facebook::jsi::Value &,
                     const facebook::jsi::Value *promiseArgs,
                     size_t promiseArgCount) -> facebook::jsi::Value {
-                  if (promiseArgCount < 2 ||
-                      !promiseArgs[0].isObject() ||
-                      !promiseArgs[0].asObject(runtime).isFunction(runtime) ||
-                      !promiseArgs[1].isObject() ||
-                      !promiseArgs[1].asObject(runtime).isFunction(runtime)) {
-                    throw facebook::jsi::JSError(runtime, "liboliphaunt JSI Promise executor received invalid callbacks");
-                  }
-
-                  auto resolve = std::make_shared>(
-                      runtime,
-                      promiseArgs[0].asObject(runtime).getFunction(runtime),
-                      callInvoker);
-                  auto reject = std::make_shared>(
-                      runtime,
-                      promiseArgs[1].asObject(runtime).getFunction(runtime),
-                      callInvoker);
+                  auto pending = promiseCallbacks(runtime, promiseArgs, promiseArgCount, callInvoker, lifetime);
+                  auto resolve = pending.resolve;
+                  auto reject = pending.reject;
                   Oliphaunt *strongSelf = weakSelf;
                   if (strongSelf == nil) {
                     reject->call([](facebook::jsi::Runtime &runtime, facebook::jsi::Function &rejectFunction) {
-                      rejectFunction.call(runtime, OliphauntCreateError(runtime, "liboliphaunt native module is unavailable"));
+                      rejectFunction.call(runtime, createError(runtime, "liboliphaunt native module is unavailable"));
                     });
                     return facebook::jsi::Value::undefined();
                   }
@@ -1136,7 +850,7 @@ - (void)installJSIBindingsWithRuntime:(facebook::jsi::Runtime &)runtime
                       const char *errorMessage = error.localizedDescription.UTF8String;
                       std::string message = errorMessage != nullptr ? errorMessage : "liboliphaunt restore failed";
                       reject->call([message](facebook::jsi::Runtime &runtime, facebook::jsi::Function &rejectFunction) {
-                        rejectFunction.call(runtime, OliphauntCreateError(runtime, message));
+                        rejectFunction.call(runtime, createError(runtime, message));
                       });
                       return;
                     }
@@ -1299,7 +1013,7 @@ - (void)invalidate
     _nativeDirectClaim = 0;
   }
 #ifdef RCT_NEW_ARCH_ENABLED
-  OliphauntAbortChunkAcknowledgements();
+  _jsiLifetime->invalidate();
 #endif
   [sessionsToClose enumerateKeysAndObjectsUsingBlock:^(
       NSNumber *key,
diff --git a/src/sdks/react-native/ios/podspecs/COliphaunt.podspec b/src/sdks/react-native/ios/podspecs/COliphaunt.podspec
index 7e82d181a..e8a3fbc0e 100644
--- a/src/sdks/react-native/ios/podspecs/COliphaunt.podspec
+++ b/src/sdks/react-native/ios/podspecs/COliphaunt.podspec
@@ -5,7 +5,7 @@ swift_sdk_version = ENV.fetch("OLIPHAUNT_REACT_NATIVE_SWIFT_SDK_VERSION") do
   package.fetch("oliphaunt", {}).fetch("swiftSdkVersion", package["version"])
 end
 swift_sdk_git = ENV.fetch("OLIPHAUNT_SWIFT_SDK_GIT_URL", "https://github.com/f0rr0/oliphaunt.git")
-swift_sdk_tag = ENV.fetch("OLIPHAUNT_SWIFT_SDK_TAG", "oliphaunt-swift-v#{swift_sdk_version}")
+swift_sdk_tag = ENV.fetch("OLIPHAUNT_SWIFT_SDK_TAG", swift_sdk_version)
 swift_sdk_commit = ENV["OLIPHAUNT_SWIFT_SDK_COMMIT"]
 swift_sdk_branch = ENV["OLIPHAUNT_SWIFT_SDK_BRANCH"]
 swift_sdk_source = { :git => swift_sdk_git }
@@ -25,6 +25,9 @@ Pod::Spec.new do |s|
   s.homepage = "https://oliphaunt.dev"
   s.authors = { "Oliphaunt" => "opensource@oliphaunt.dev" }
   s.source = swift_sdk_source
+  # CocoaPods exports flattened public headers, so materialize the runtime ABI
+  # in the downloaded source before it copies the bridge headers.
+  s.prepare_command = "if test -f src/runtimes/liboliphaunt-native/include/oliphaunt.h; then cp src/runtimes/liboliphaunt-native/include/oliphaunt.h src/sdks/swift/Sources/COliphaunt/include/oliphaunt.h; fi; test -s src/sdks/swift/Sources/COliphaunt/include/oliphaunt.h"
   s.platforms = { :ios => "17.0" }
   s.source_files = "src/sdks/swift/Sources/COliphaunt/**/*.{c,h}"
   s.public_header_files = "src/sdks/swift/Sources/COliphaunt/include/COliphaunt.h", "src/sdks/swift/Sources/COliphaunt/include/oliphaunt.h"
diff --git a/src/sdks/react-native/ios/podspecs/Oliphaunt.podspec b/src/sdks/react-native/ios/podspecs/Oliphaunt.podspec
index e6d7d61c6..9e040b9ce 100644
--- a/src/sdks/react-native/ios/podspecs/Oliphaunt.podspec
+++ b/src/sdks/react-native/ios/podspecs/Oliphaunt.podspec
@@ -5,7 +5,7 @@ swift_sdk_version = ENV.fetch("OLIPHAUNT_REACT_NATIVE_SWIFT_SDK_VERSION") do
   package.fetch("oliphaunt", {}).fetch("swiftSdkVersion", package["version"])
 end
 swift_sdk_git = ENV.fetch("OLIPHAUNT_SWIFT_SDK_GIT_URL", "https://github.com/f0rr0/oliphaunt.git")
-swift_sdk_tag = ENV.fetch("OLIPHAUNT_SWIFT_SDK_TAG", "oliphaunt-swift-v#{swift_sdk_version}")
+swift_sdk_tag = ENV.fetch("OLIPHAUNT_SWIFT_SDK_TAG", swift_sdk_version)
 swift_sdk_commit = ENV["OLIPHAUNT_SWIFT_SDK_COMMIT"]
 swift_sdk_branch = ENV["OLIPHAUNT_SWIFT_SDK_BRANCH"]
 swift_sdk_source = { :git => swift_sdk_git }
@@ -30,4 +30,5 @@ Pod::Spec.new do |s|
   s.source_files = "src/sdks/swift/Sources/Oliphaunt/**/*.swift"
   s.requires_arc = true
   s.dependency "COliphaunt", swift_sdk_version
+  s.dependency "OliphauntNativeBindings", swift_sdk_version
 end
diff --git a/src/sdks/react-native/ios/podspecs/OliphauntNativeBindings.podspec b/src/sdks/react-native/ios/podspecs/OliphauntNativeBindings.podspec
new file mode 100644
index 000000000..67851a96c
--- /dev/null
+++ b/src/sdks/react-native/ios/podspecs/OliphauntNativeBindings.podspec
@@ -0,0 +1,35 @@
+require "json"
+require "shellwords"
+
+package = JSON.parse(File.read(File.expand_path("../../package.json", __dir__)))
+swift_sdk_version = ENV.fetch("OLIPHAUNT_REACT_NATIVE_SWIFT_SDK_VERSION") do
+  package.fetch("oliphaunt", {}).fetch("swiftSdkVersion", package["version"])
+end
+swift_sdk_git = ENV.fetch("OLIPHAUNT_SWIFT_SDK_GIT_URL", "https://github.com/f0rr0/oliphaunt.git")
+swift_sdk_tag = ENV.fetch("OLIPHAUNT_SWIFT_SDK_TAG", swift_sdk_version)
+swift_sdk_commit = ENV["OLIPHAUNT_SWIFT_SDK_COMMIT"]
+swift_sdk_branch = ENV["OLIPHAUNT_SWIFT_SDK_BRANCH"]
+swift_sdk_source = { :git => swift_sdk_git }
+if swift_sdk_commit && !swift_sdk_commit.empty?
+  swift_sdk_source[:commit] = swift_sdk_commit
+elsif swift_sdk_branch && !swift_sdk_branch.empty?
+  swift_sdk_source[:branch] = swift_sdk_branch
+else
+  swift_sdk_source[:tag] = swift_sdk_tag
+end
+
+Pod::Spec.new do |s|
+  s.name = "OliphauntNativeBindings"
+  s.version = swift_sdk_version
+  s.summary = "Generated native bindings for the Oliphaunt Swift SDK."
+  s.license = package["license"]
+  s.homepage = "https://oliphaunt.dev"
+  s.authors = { "Oliphaunt" => "opensource@oliphaunt.dev" }
+  s.source = swift_sdk_source
+  s.platforms = { :ios => "17.0" }
+  s.swift_version = "6.0"
+  s.source_files = "src/sdks/swift/Sources/OliphauntNativeBindings/**/*.swift"
+  s.vendored_frameworks = "Artifacts/OliphauntNativeBindingsFFI.xcframework"
+  s.requires_arc = true
+  s.prepare_command = "set -- #{Shellwords.escape(swift_sdk_version)}\n" + File.read(File.join(__dir__, "prepare-native-bindings.sh"))
+end
diff --git a/src/sdks/react-native/ios/podspecs/prepare-native-bindings.sh b/src/sdks/react-native/ios/podspecs/prepare-native-bindings.sh
new file mode 100644
index 000000000..f30777255
--- /dev/null
+++ b/src/sdks/react-native/ios/podspecs/prepare-native-bindings.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+set -eu
+version="$1"
+bindings_asset="oliphaunt-swift-$version-bindings.xcframework.zip"
+expected_url="https://github.com/f0rr0/oliphaunt/releases/download/oliphaunt-swift-v$version/$bindings_asset"
+target="$(sed -n '/name: "OliphauntNativeBindingsFFI"/,/)/p' Package.swift)"
+url="$(printf '%s\n' "$target" | sed -n 's/.*url: "\([^"]*\)".*/\1/p')"
+checksum="$(printf '%s\n' "$target" | sed -n 's/.*checksum: "\([0-9a-f]*\)".*/\1/p')"
+[ "$url" = "$expected_url" ] && [ "${#checksum}" -eq 64 ] || {
+  echo 'Swift source must contain the checksum-pinned bindings target for the selected SDK version' >&2
+  exit 1
+}
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+archive="$PWD/Artifacts/$bindings_asset"
+if [ ! -f "$archive" ]; then
+  archive="$scratch/$bindings_asset"
+  curl --fail --location --silent --show-error "$url" --output "$archive"
+fi
+printf '%s  %s\n' "$checksum" "$archive" | shasum -a 256 -c -
+unzip -q "$archive" -d "$scratch"
+test -s "$scratch/OliphauntNativeBindingsFFI.xcframework/Info.plist"
+mkdir -p Artifacts
+rm -rf Artifacts/OliphauntNativeBindingsFFI.xcframework
+mv "$scratch/OliphauntNativeBindingsFFI.xcframework" Artifacts/
diff --git a/src/sdks/react-native/moon.yml b/src/sdks/react-native/moon.yml
index 7ffed856e..4edfcb766 100644
--- a/src/sdks/react-native/moon.yml
+++ b/src/sdks/react-native/moon.yml
@@ -1,57 +1,71 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "oliphaunt-react-native"
-language: "typescript"
-layer: "library"
-stack: "frontend"
-tags: ["sdk", "react-native", "typescript", "ios", "android", "release-product"]
+$schema: https://moonrepo.dev/schemas/project.json
+id: oliphaunt-react-native
+language: typescript
+layer: library
+stack: frontend
+tags:
+  - javascript-quality
+  - sdk
+  - react-native
+  - typescript
+  - ios
+  - android
+  - release-product
 dependsOn:
-  - id: "extensions"
-    scope: "build"
-  - id: "cluster-seed-contract"
-    scope: "development"
-  - "oliphaunt-swift"
-  - "oliphaunt-kotlin"
-  - id: "extension-runtime-contract"
-    scope: "build"
-
+  - id: oliphaunt-query-ts
+    scope: build
+  - id: shared-test-fixtures
+    scope: development
+  - id: extensions
+    scope: build
+  - id: cluster-seed-contract
+    scope: development
+  - oliphaunt-swift
+  - oliphaunt-kotlin
+  - id: extension-runtime-contract
+    scope: build
 project:
-  title: "Oliphaunt React Native SDK"
-  description: "React Native New Architecture SDK over the Swift and Kotlin Oliphaunt SDKs."
-  owner: "oliphaunt"
+  title: Oliphaunt React Native SDK
+  description: React Native New Architecture SDK over the Swift and Kotlin Oliphaunt SDKs.
+  owner: oliphaunt
   release:
-    component: "oliphaunt-react-native"
-    packagePath: "src/sdks/react-native"
-
+    component: oliphaunt-react-native
+    packagePath: src/sdks/react-native
 owners:
   defaultOwner: "@oliphaunt/sdk-react-native"
   paths:
-    "**/*.ts": ["@oliphaunt/sdk-react-native"]
-    "**/*.tsx": ["@oliphaunt/sdk-react-native"]
-    "ios/**": ["@oliphaunt/sdk-react-native", "@oliphaunt/sdk-swift"]
-    "android/**": ["@oliphaunt/sdk-react-native", "@oliphaunt/sdk-android"]
-
+    "**/*.ts":
+      - "@oliphaunt/sdk-react-native"
+    "**/*.tsx":
+      - "@oliphaunt/sdk-react-native"
+    ios/**:
+      - "@oliphaunt/sdk-react-native"
+      - "@oliphaunt/sdk-swift"
+    android/**:
+      - "@oliphaunt/sdk-react-native"
+      - "@oliphaunt/sdk-android"
 fileGroups:
   code:
     - "**/*"
     - "!**/*.md"
     - "!moon.yml"
     - "!release.toml"
-
 tasks:
-  compile:
-    tags: ["quality", "static"]
-    script: |
-      set -e
-      pnpm run build
-      pnpm run typecheck
-      pnpm run codegen:check
+  test-cpp:
+    tags: [quality, unit]
+    command: "bash tools/test-cpp.sh"
+    inputs: ["cpp/**/*", "tools/test-cpp.sh"]
+  build:
+    tags:
+      - build
+    command: bun run build
     deps:
-      - "shared-js-core:build"
+      - oliphaunt-query-ts:build
     inputs:
-      - project: "shared-js-core"
-        group: "sources"
-      - "@group(pnpm-workspace)"
+      - /tools/packaging/portable-archive.mts
+      - project: oliphaunt-query-ts
+        group: sources
+      - "@group(bun-workspace)"
       - "@group(code)"
       - "!/src/sdks/react-native/**/node_modules"
       - "!/src/sdks/react-native/**/node_modules/**"
@@ -63,27 +77,69 @@ tasks:
       - "!/src/sdks/react-native/**/lib/**"
       - "!/src/sdks/react-native/ios/vendor/**"
     outputs:
-      - "lib/**/*"
+      - lib/**/*
+      - app.plugin.js
+      - react-native.config.js
+      - tools/codegen-check.cjs
+      - tools/native-resource-closure.mjs
+      - tools/stage-ios-app.mjs
+      - tools/verify-ios-package.mjs
     options:
       cache: true
-  unit-distinct:
-    tags: ["quality", "unit"]
-    script: |
-      set -e
-      bash tools/verify-android-apk.test.sh
-      bun test tools/validate-android-link-evidence.test.mjs
-      node tools/stage-ios-app.test.mjs
+  typecheck:
+    tags:
+      - quality
+      - static
+    command: bun run typecheck
     deps:
-      - "shared-js-core:build"
+      - oliphaunt-query-ts:build
     inputs:
-      - project: "shared-js-core"
-        group: "sources"
-      - "@group(pnpm-workspace)"
-      - project: "cluster-seed-contract"
-        group: "contract"
-      - project: "extensions"
-        group: "sdk-metadata"
       - "@group(code)"
+      - "@group(bun-workspace)"
+      - project: oliphaunt-query-ts
+        group: sources
+  package:
+    tags:
+      - package
+      - release
+      - artifact-package
+      - ci-react-native-sdk-package
+    script: bun run --cwd src/sdks/react-native package
+    env:
+      OLIPHAUNT_REACT_NATIVE_IOS_RELEASE_ASSET_DIR: target/liboliphaunt/abi-compatible-release-assets/ios-datum64
+    deps:
+      - oliphaunt-react-native:build
+      - liboliphaunt-native:finalize-runtime-ios-abi
+    inputs:
+      - /src/runtimes/liboliphaunt-native/include/oliphaunt.h
+      - "@group(legal-files)"
+      - "@group(bun-workspace)"
+      - "@group(release-archive-contract)"
+      - "@group(release-target-contract)"
+      - /src/sdks/react-native/tools/check-package.mts
+      - /src/extensions/artifacts/packages/tools/contrib-carriers.mts
+      - /src/sdks/swift/tools/ios-carrier-manifest.mts
+      - /tools/release/release-graph.mts
+      - /tools/packaging/npm-package.mts
+      - /src/sdks/react-native/tools/stage-release-artifacts.mts
+      - /src/sdks/react-native/tools/stage-release-artifacts.sh
+      - /tools/packaging/staging.mts
+      - /tools/packaging/source-only-sdk-package.mts
+      - /src/database-resources/icu/npm/**/*
+      - /src/examples/react-native-expo/package.json
+      - /src/sdks/react-native/tools/icu-autolinking-fixture.mts
+      - /src/sdks/react-native/tools/check-icu-autolinking.sh
+      - /tools/packaging/portable-archive.mts
+      - /target/liboliphaunt/abi-compatible-release-assets/ios-datum64/**/*
+      - /tools/dev/bun.sh
+      - /src/third-party/tools/source-fetch-core.mts
+      - "@group(legal-files)"
+      - project: oliphaunt-query-ts
+        group: sources
+      - project: extensions
+        group: sdk-metadata
+      - "@group(bun-workspace)"
+      - "**/*"
       - "!/src/sdks/react-native/**/node_modules"
       - "!/src/sdks/react-native/**/node_modules/**"
       - "!/src/sdks/react-native/**/.build"
@@ -93,53 +149,48 @@ tasks:
       - "!/src/sdks/react-native/**/build/**"
       - "!/src/sdks/react-native/**/lib/**"
       - "!/src/sdks/react-native/ios/vendor/**"
+    outputs:
+      - /target/sdk-artifacts/oliphaunt-react-native/**/*
     options:
       cache: true
-  unit-shared:
-    command: "pnpm test"
+      runFromWorkspaceRoot: true
+  coverage:
+    tags:
+      - coverage
+    command: bun run coverage
     deps:
-      - "shared-js-core:build"
+      - oliphaunt-query-ts:build
     inputs:
-      - project: "shared-js-core"
-        group: "sources"
-      - "@group(pnpm-workspace)"
       - "@group(code)"
-      - "!/src/sdks/react-native/**/node_modules/**"
-      - "!/src/sdks/react-native/**/lib/**"
-    options:
-      cache: true
-      runInCI: false
-  unit:
-    command: "true"
-    deps:
-      - "oliphaunt-react-native:unit-distinct"
-      - "oliphaunt-react-native:unit-shared"
-    inputs: []
+      - "@group(bun-workspace)"
+      - project: oliphaunt-query-ts
+        group: sources
+      - project: shared-test-fixtures
+        group: fixtures
+    outputs:
+      - /target/coverage/oliphaunt-react-native/**/*
     options:
       cache: false
       runInCI: false
-  package:
-    tags: ["package"]
-    script: |
-      set -e
-      rm -rf target/liboliphaunt-sdk-check/oliphaunt-react-native/package-shape
-      mkdir -p target/liboliphaunt-sdk-check/oliphaunt-react-native/package-shape/src/sdks/react-native
-      rsync -a --exclude node_modules --exclude .build --exclude android/.gradle --exclude android/.cxx --exclude android/build --exclude ios/vendor src/sdks/react-native/ target/liboliphaunt-sdk-check/oliphaunt-react-native/package-shape/src/sdks/react-native/
-      mkdir -p target/liboliphaunt-sdk-check/oliphaunt-react-native/package-shape/src/sdks/react-native/src/generated
-      cp src/extensions/generated/sdk/extensions.json src/extensions/generated/sdk/ios-static-dependencies.json target/liboliphaunt-sdk-check/oliphaunt-react-native/package-shape/src/sdks/react-native/src/generated/
-      cp LICENSE THIRD_PARTY_NOTICES.md target/liboliphaunt-sdk-check/oliphaunt-react-native/package-shape/src/sdks/react-native/
-      node src/shared/js-core/tools/stage-package.mjs target/liboliphaunt-sdk-check/oliphaunt-react-native/package-shape/src/sdks/react-native src/shared/js-core
+  test:
+    tags:
+      - quality
+      - unit
     deps:
-      - "oliphaunt-react-native:compile"
+      - oliphaunt-query-ts:build
     inputs:
-      - "@group(legal-files)"
-      - project: "shared-js-core"
-        group: "sources"
-      - project: "extensions"
-        group: "sdk-metadata"
-      - "@group(pnpm-workspace)"
-      - "/src/shared/js-core/tools/stage-package.mjs"
-      - "**/*"
+      - /tools/packaging/portable-archive.mts
+      - project: oliphaunt-query-ts
+        group: sources
+      - "@group(bun-workspace)"
+      - project: cluster-seed-contract
+        group: contract
+      - project: extensions
+        group: sdk-metadata
+      - project: extensions
+        group: mobile-metadata
+      - /src/runtimes/liboliphaunt-native/bin/mobile-static-extensions.sh
+      - "@group(code)"
       - "!/src/sdks/react-native/**/node_modules"
       - "!/src/sdks/react-native/**/node_modules/**"
       - "!/src/sdks/react-native/**/.build"
@@ -149,18 +200,41 @@ tasks:
       - "!/src/sdks/react-native/**/build/**"
       - "!/src/sdks/react-native/**/lib/**"
       - "!/src/sdks/react-native/ios/vendor/**"
-    outputs:
-      - "/target/liboliphaunt-sdk-check/oliphaunt-react-native/package-shape/src/sdks/react-native/**/*"
     options:
       cache: true
-      runFromWorkspaceRoot: true
-  qualify:
-    tags: ["release", "package"]
-    command: "true"
+    command: bun run test
+  check-codegen:
+    tags:
+      - quality
+      - static
+    command: bun run codegen:check
+    inputs:
+      - package.json
+      - tools/codegen-check.cts
+      - src/specs/**/*.ts
+      - "@group(bun-workspace)"
+  lint:
+    deps:
+      - oliphaunt-react-native:check-codegen
+  test-consumer:
+    command: bun run test-consumer
+    tags:
+      - integration
+      - consumer
+      - ci-react-native-sdk-package
     deps:
-      - "oliphaunt-react-native:compile"
-      - "oliphaunt-react-native:unit-distinct"
-      - "oliphaunt-react-native:package"
-    inputs: []
+      - oliphaunt-react-native:package
+    inputs:
+      - tools/check-icu-autolinking.sh
+      - tools/icu-autolinking-fixture.mts
+      - /src/examples/react-native-expo/package.json
+      - /src/database-resources/icu/npm/**/*
+      - "@group(bun-workspace)"
     options:
-      cache: true
+      cache: false
+workspace:
+  inheritedTasks:
+    rename:
+      js-format: format
+      js-format-check: format-check
+      js-lint: lint
diff --git a/src/sdks/react-native/package.json b/src/sdks/react-native/package.json
index bfb6c0fd9..cbff1f62b 100644
--- a/src/sdks/react-native/package.json
+++ b/src/sdks/react-native/package.json
@@ -28,7 +28,13 @@
       "require": "./lib/commonjs/index.js",
       "default": "./lib/module/index.js"
     },
-    "./package.json": "./package.json"
+    "./package.json": "./package.json",
+    "./storage": {
+      "types": "./lib/typescript/storage.d.ts",
+      "import": "./lib/module/storage.js",
+      "require": "./lib/commonjs/storage.js",
+      "default": "./lib/module/storage.js"
+    }
   },
   "oliphaunt": {
     "swiftSdkVersion": "0.7.0",
@@ -64,17 +70,25 @@
     "!android/src/main/jniLibs",
     "!android/src/main/jniLibs/**",
     "!android/src/test",
-    "!src/__tests__"
+    "!src/__tests__",
+    "cpp",
+    "!cpp/*.test.cpp"
   ],
   "scripts": {
-    "build": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\" && tsc -p tsconfig.build.types.json && tsc -p tsconfig.build.module.json && tsc -p tsconfig.build.commonjs.json",
-    "codegen:check": "node ./tools/codegen-check.cjs /tmp/oliphaunt-react-native-schema.json src/specs/NativeOliphaunt.ts",
-    "docs:api": "typedoc --options typedoc.json",
+    "build": "bash tools/build.sh",
+    "codegen:check": "node ./tools/codegen-check.cts /tmp/oliphaunt-react-native-schema.json src/specs/NativeOliphaunt.ts",
     "package:verify-ios": "node ./tools/verify-ios-package.mjs --package-dir .",
     "prepack": "node ./tools/verify-ios-package.mjs --package-dir .",
-    "test": "vitest run --pool=forks --fileParallelism=false --dir=src/__tests__",
+    "test": "bash tools/test.sh",
     "typecheck": "tsc --noEmit",
-    "clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\""
+    "clean": "rm -rf lib",
+    "coverage": "bun test --isolate --timeout=30000 ./src/__tests__ --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=../../../target/coverage/oliphaunt-react-native",
+    "format": "bun x --no-install biome format --write --no-errors-on-unmatched .",
+    "format-check": "bun x --no-install biome format --no-errors-on-unmatched .",
+    "lint": "bun x --no-install biome lint --diagnostic-level=error --no-errors-on-unmatched . && bun run codegen:check",
+    "test-consumer": "bash tools/test-consumer.sh",
+    "package": "bash tools/package.sh",
+    "test-cpp": "bash tools/test-cpp.sh"
   },
   "peerDependencies": {
     "expo": ">=56.0.0",
@@ -87,22 +101,16 @@
     }
   },
   "dependencies": {
-    "@oliphaunt/js-core": "workspace:*"
+    "@oliphaunt/ts-query": "0.1.0"
   },
-  "bundledDependencies": [
-    "@oliphaunt/js-core"
-  ],
   "devDependencies": {
     "@react-native/codegen": "^0.85.3",
     "@react-native/typescript-config": "^0.85.0",
     "@types/node": "^24.10.1",
-    "@vitest/coverage-v8": "catalog:",
     "react": "^19.2.0",
     "react-native": "^0.85.0",
-    "tsx": "catalog:",
-    "typedoc": "catalog:",
     "typescript": "catalog:",
-    "vitest": "catalog:"
+    "@types/bun": "catalog:"
   },
   "codegenConfig": {
     "name": "OliphauntReactNativeSpec",
diff --git a/src/sdks/react-native/react-native.config.js b/src/sdks/react-native/react-native.config.cts
similarity index 100%
rename from src/sdks/react-native/react-native.config.js
rename to src/sdks/react-native/react-native.config.cts
diff --git a/src/sdks/react-native/release.toml b/src/sdks/react-native/release.toml
index 11583790e..241eb4655 100644
--- a/src/sdks/react-native/release.toml
+++ b/src/sdks/react-native/release.toml
@@ -8,7 +8,6 @@ release_artifacts = [
   "react-native-podspec",
   "expo-dev-client-example",
 ]
-derived_version_files = ["src/sdks/react-native/OliphauntReactNative.podspec"]
 
 [compatibility_versions.oliphaunt-react-native-swift-sdk]
 source_product = "oliphaunt-swift"
@@ -19,3 +18,8 @@ parser = "json:oliphaunt.swiftSdkVersion"
 source_product = "oliphaunt-kotlin"
 path = "src/sdks/react-native/package.json"
 parser = "json:oliphaunt.kotlinSdkVersion"
+
+[compatibility_versions.oliphaunt-react-native-query]
+source_product = "oliphaunt-query-ts"
+path = "src/sdks/react-native/package.json"
+parser = "json:dependencies.@oliphaunt/ts-query"
diff --git a/src/sdks/react-native/src/__tests__/client.test.ts b/src/sdks/react-native/src/__tests__/client.test.ts
index 6244e24cc..2fbbbe3aa 100644
--- a/src/sdks/react-native/src/__tests__/client.test.ts
+++ b/src/sdks/react-native/src/__tests__/client.test.ts
@@ -1,5 +1,5 @@
+import { test, vi } from 'bun:test';
 import assert from 'node:assert/strict';
-import { test, vi } from 'vitest';
 
 import {
   createOliphauntClient,
@@ -20,7 +20,7 @@ import type {
 } from '../index';
 import type { JsiProtocolChunkResult } from '../jsiTransport';
 import { parseCommandResponse, text } from '../query';
-import type { Spec } from '../specs/NativeOliphaunt';
+import type { NativeOpenConfig, Spec } from '../specs/NativeOliphaunt';
 
 // OLIPHAUNT_DOCS_SNIPPET react-native-quickstart
 
@@ -65,7 +65,7 @@ const forgedEncodedParameter: EncodedQueryParameter = {
 void [plainJsonParameter, forgedEncodedParameter];
 
 async function main(): Promise {
-  await testPublicEntrypointIsMinimal();
+  await testPublicEntrypointOpensDirectoryStorage();
   await testStartupGUCValidation();
   await testOpenUsesNativeDirectDefaults();
   await testExecuteReturnsPostgresCommandMetadata();
@@ -157,34 +157,27 @@ async function testStartupGUCValidation(): Promise {
   }
 }
 
-async function testPublicEntrypointIsMinimal(): Promise {
-  vi.resetModules();
-  vi.doMock('react-native', () => ({
+async function testPublicEntrypointOpensDirectoryStorage(): Promise {
+  const native = new MockNative();
+  vi.mock('react-native', () => ({
     TurboModuleRegistry: {
       getEnforcing(name: string) {
         assert.equal(name, 'Oliphaunt');
-        return new MockNative();
+        return native;
       },
     },
   }));
-  try {
-    const entrypoint = await import('../index');
-    assert.deepEqual(Object.keys(entrypoint).sort(), [
-      'Oliphaunt',
-      'PostgresError',
-      'array',
-      'binary',
-      'default',
-      'json',
-      'postgresOids',
-      'text',
-      'typedNull',
-    ]);
-    assert.equal(entrypoint.default, entrypoint.Oliphaunt);
-  } finally {
-    vi.doUnmock('react-native');
-    vi.resetModules();
-  }
+  const entrypoint = await import('../index');
+  assert.equal(entrypoint.default, entrypoint.Oliphaunt);
+  const database = await entrypoint.Oliphaunt.open({
+    storage: entrypoint.directory('file:///data/my%20database'),
+  });
+  assert.equal(native.openCalls.length, 1);
+  assert.equal((native.openCalls[0] as NativeOpenConfig).storageKind, 'directory');
+  assert.equal((native.openCalls[0] as NativeOpenConfig).storagePath, '/data/my database');
+  await database.close();
+  assert.equal(database.closed, true);
+  assert.deepEqual(native.closedHandles, [1]);
 }
 
 async function testOpenUsesNativeDirectDefaults(): Promise {
diff --git a/src/sdks/react-native/src/__tests__/config-plugin.test.ts b/src/sdks/react-native/src/__tests__/config-plugin.test.ts
index 79bdc0fe1..51aa8e309 100644
--- a/src/sdks/react-native/src/__tests__/config-plugin.test.ts
+++ b/src/sdks/react-native/src/__tests__/config-plugin.test.ts
@@ -1,10 +1,10 @@
+import { test } from 'bun:test';
 import assert from 'node:assert/strict';
 import fs from 'node:fs';
+import { createRequire } from 'node:module';
 import os from 'node:os';
 import path from 'node:path';
-import { createRequire } from 'node:module';
 import { fileURLToPath } from 'node:url';
-import { test } from 'vitest';
 
 const require = createRequire(import.meta.url);
 const {
@@ -13,7 +13,7 @@ const {
   ensureIosConfigDeploymentTarget,
   insertAppGradlePlugin,
   insertIosPodfileBlock,
-  iosStageCommand,
+  iosStageOptions,
   normalizeOptions,
   readCarrierSummary,
   releaseOwnerForSqlName,
@@ -22,7 +22,7 @@ const {
   selectedExtensionClosure,
   serializeExtensionVersions,
   stageIosAppPayload,
-} = require('../../app.plugin.js');
+} = require('../../app.plugin.cts');
 const packageJson = require('../../package.json');
 const sdkRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
 
@@ -124,6 +124,8 @@ test('normalizes exact extension selection', () => {
   });
 
   assert.deepEqual(normalized, {
+    seedProfile: undefined,
+    databaseResourcesVersion: undefined,
     extensions: ['pg_trgm', 'vector'],
     icu: true,
     liboliphauntVersion: '0.1.0',
@@ -139,6 +141,8 @@ test('normalizes exact extension selection', () => {
     /not in the generated exact-extension catalog/,
   );
   assert.deepEqual(normalizeOptions({ extensions: ['postgis'] }).extensions, ['postgis']);
+  assert.equal(normalizeOptions({ seedProfile: 'icu' }).icu, true);
+  assert.throws(() => normalizeOptions({ seedProfile: 'both' }), /seedProfile/);
   assert.equal(extensionPackageName('uuid-ossp'), '@oliphaunt/extension-contrib-pg18');
   assert.equal(extensionPackageName('vector'), '@oliphaunt/extension-vector');
   assert.deepEqual(selectedExtensionClosure(['earthdistance']), ['cube', 'earthdistance']);
@@ -154,49 +158,86 @@ test('normalizes exact extension selection', () => {
 });
 
 test('Podfile patch is app-owned, fail-closed, and idempotent', () => {
-  const podfile = [
-    "target 'OliphauntExample' do",
-    '  use_expo_modules!',
-    '  config = use_native_modules!',
-    'end',
-    '',
-  ].join('\n');
-
-  const patchedPodfile = insertIosPodfileBlock(podfile, { icu: true });
-  assert.match(patchedPodfile, /# @oliphaunt\/react-native begin/);
-  assert.match(
-    patchedPodfile,
-    /pod 'COliphaunt', :podspec => File\.join\(oliphaunt_podspecs_path, 'COliphaunt\.podspec'\), :modular_headers => true/,
-  );
-  assert.match(
-    patchedPodfile,
-    /pod 'Oliphaunt', :podspec => File\.join\(oliphaunt_podspecs_path, 'Oliphaunt\.podspec'\)/,
-  );
-  assert.match(
-    patchedPodfile,
-    /oliphaunt_payload_path = File\.expand_path\('oliphaunt', __dir__\)/,
-  );
-  assert.match(
-    patchedPodfile,
-    /oliphaunt_payload_podspec = File\.join\(oliphaunt_payload_path, 'OliphauntReactNativePayload\.podspec'\)/,
-  );
-  assert.match(patchedPodfile, /raise 'Oliphaunt iOS payload is missing/);
-  assert.match(
-    patchedPodfile,
-    /pod 'OliphauntReactNativePayload', :path => oliphaunt_payload_path/,
-  );
-  assert.doesNotMatch(patchedPodfile, /pod 'OliphauntReactNativePayload', :podspec/);
-  assert.doesNotMatch(patchedPodfile, /OliphauntICU/);
-  assert.equal(insertIosPodfileBlock(patchedPodfile, { icu: true }), patchedPodfile);
+  const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-pod-resources-'));
+  try {
+    for (const [name, pod] of [
+      ['@oliphaunt/icu', 'OliphauntICU'],
+      ['@oliphaunt/seed-native-ios-datum64-icu', 'OliphauntSeedNativeIOSICU'],
+      ['@oliphaunt/seed-native-ios-datum64-standard', 'OliphauntSeedNativeIOSStandard'],
+    ] as const) {
+      const packageRoot = path.join(projectRoot, 'node_modules', name);
+      writeJson(path.join(packageRoot, 'package.json'), { name, version: '1.2.3' });
+      fs.writeFileSync(path.join(packageRoot, `${pod}.podspec`), 'Pod::Spec.new {}');
+    }
+    const options = { icu: true, seedProfile: 'icu', projectRoot };
+    const podfile = [
+      "target 'OliphauntExample' do",
+      '  use_expo_modules!',
+      '  config = use_native_modules!',
+      'end',
+      '',
+    ].join('\n');
+
+    const patchedPodfile = insertIosPodfileBlock(podfile, options);
+    assert.match(patchedPodfile, /# @oliphaunt\/react-native begin/);
+    assert.match(
+      patchedPodfile,
+      /pod 'COliphaunt', :podspec => File\.join\(oliphaunt_podspecs_path, 'COliphaunt\.podspec'\), :modular_headers => true/,
+    );
+    assert.match(
+      patchedPodfile,
+      /pod 'OliphauntNativeBindings', :podspec => File\.join\(oliphaunt_podspecs_path, 'OliphauntNativeBindings\.podspec'\)/,
+    );
+    assert.match(
+      patchedPodfile,
+      /pod 'Oliphaunt', :podspec => File\.join\(oliphaunt_podspecs_path, 'Oliphaunt\.podspec'\)/,
+    );
+    assert.match(
+      patchedPodfile,
+      /oliphaunt_payload_path = File\.expand_path\('oliphaunt', __dir__\)/,
+    );
+    assert.match(
+      patchedPodfile,
+      /oliphaunt_payload_podspec = File\.join\(oliphaunt_payload_path, 'OliphauntReactNativePayload\.podspec'\)/,
+    );
+    assert.match(patchedPodfile, /raise 'Oliphaunt iOS payload is missing/);
+    assert.match(
+      patchedPodfile,
+      /pod 'OliphauntReactNativePayload', :path => oliphaunt_payload_path/,
+    );
+    assert.doesNotMatch(patchedPodfile, /pod 'OliphauntReactNativePayload', :podspec/);
+    assert.ok(
+      patchedPodfile.includes(
+        "pod 'OliphauntICU', :path => File.expand_path('../node_modules/@oliphaunt/icu', __dir__)",
+      ),
+    );
+    assert.ok(
+      patchedPodfile.includes(
+        "pod 'OliphauntSeedNativeIOSICU', :path => File.expand_path('../node_modules/@oliphaunt/seed-native-ios-datum64-icu', __dir__)",
+      ),
+    );
+    assert.equal(insertIosPodfileBlock(patchedPodfile, options), patchedPodfile);
+    const standard = insertIosPodfileBlock(patchedPodfile, {
+      icu: false,
+      seedProfile: 'standard',
+      projectRoot,
+    });
+    assert.match(standard, /pod 'OliphauntSeedNativeIOSStandard'/);
+    assert.doesNotMatch(standard, /OliphauntICU|OliphauntSeedNativeIOSICU/);
+    fs.unlinkSync(path.join(projectRoot, 'node_modules/@oliphaunt/icu/OliphauntICU.podspec'));
+    assert.throws(() => insertIosPodfileBlock(podfile, options), /missing OliphauntICU.podspec/);
 
-  assert.throws(
-    () => insertIosPodfileBlock("target 'App' do\nend\n"),
-    /use_native_modules! or use_expo_modules!/,
-  );
-  assert.throws(
-    () => insertIosPodfileBlock('# @oliphaunt/react-native begin\n'),
-    /partial @oliphaunt\/react-native managed block/,
-  );
+    assert.throws(
+      () => insertIosPodfileBlock("target 'App' do\nend\n"),
+      /use_native_modules! or use_expo_modules!/,
+    );
+    assert.throws(
+      () => insertIosPodfileBlock('# @oliphaunt/react-native begin\n'),
+      /partial @oliphaunt\/react-native managed block/,
+    );
+  } finally {
+    fs.rmSync(projectRoot, { recursive: true, force: true });
+  }
 });
 
 test('Expo iOS deployment target meets the packaged pod minimum without lowering newer apps', () => {
@@ -363,7 +404,7 @@ test('Android package discovery passes exact owner versions and rejects compatib
   }
 });
 
-test('carrier env overrides are exact and stage only into the app ios tree', () => {
+test('carrier env overrides are exact and stage only into the app ios tree', async () => {
   const root = fs.mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-plugin-stage-'));
   try {
     const projectRoot = path.join(root, 'app');
@@ -389,43 +430,31 @@ test('carrier env overrides are exact and stage only into the app ios tree', ()
       icu: true,
     };
 
-    const command = iosStageCommand(projectRoot, iosRoot, normalized, { env });
-    assert.deepEqual(command.carrierManifests, [baseCarrier, cubeCarrier, earthdistanceCarrier]);
-    assert.equal(command.outputDir, path.join(iosRoot, 'oliphaunt'));
-    assert.equal(command.args.filter((arg: string) => arg === '--carrier').length, 3);
-    assert.deepEqual(command.args.slice(-8), [
-      '--output-dir',
-      path.join(iosRoot, 'oliphaunt'),
-      '--extensions',
-      'earthdistance',
-      '--icu',
-      '--cache-dir',
-      path.join(projectRoot, '.oliphaunt-cache'),
-      '--allow-file-urls',
-    ]);
-    assert.ok(command.args.includes('--allow-file-urls'));
-    assert.ok(!command.outputDir.includes('node_modules'));
-
-    let spawned = false;
-    stageIosAppPayload(projectRoot, iosRoot, normalized, {
+    const staging = iosStageOptions(projectRoot, iosRoot, normalized, { env });
+    assert.deepEqual(staging, {
+      carriers: [baseCarrier, cubeCarrier, earthdistanceCarrier],
+      outputDir: path.join(iosRoot, 'oliphaunt'),
+      extensions: ['earthdistance'],
+      icu: true,
+      seedProfile: undefined,
+      cacheDir: path.join(projectRoot, '.oliphaunt-cache'),
+      allowFileUrls: true,
+    });
+    let staged = false;
+    await stageIosAppPayload(projectRoot, iosRoot, normalized, {
       env,
-      spawnSyncImpl: (_executable: string, args: string[], options: { cwd: string }) => {
-        spawned = true;
-        assert.equal(options.cwd, projectRoot);
-        const outputIndex = args.indexOf('--output-dir');
-        const outputDir = args[outputIndex + 1];
-        if (outputIndex < 0 || outputDir === undefined) {
-          throw new Error('stage command omitted --output-dir');
-        }
-        fs.mkdirSync(outputDir, { recursive: true });
+      stageIosAppImpl: async (options: typeof staging) => {
+        assert.deepEqual(options, staging);
+        await Promise.resolve();
+        fs.mkdirSync(options.outputDir, { recursive: true });
         fs.writeFileSync(
-          path.join(outputDir, 'OliphauntReactNativePayload.podspec'),
+          path.join(options.outputDir, 'OliphauntReactNativePayload.podspec'),
           'Pod::Spec.new\n',
         );
-        return { error: undefined, status: 0, stderr: '', stdout: '' };
+        staged = true;
       },
     });
-    assert.equal(spawned, true);
+    assert.equal(staged, true);
     assert.equal(fs.existsSync(path.join(projectRoot, 'node_modules')), false);
   } finally {
     fs.rmSync(root, { force: true, recursive: true });
@@ -456,14 +485,13 @@ test('aggregate CI carrier override supplies base and dependency closure exactly
       }),
       [aggregateCarrier],
     );
-    const command = iosStageCommand(
+    const command = iosStageOptions(
       projectRoot,
       path.join(projectRoot, 'ios'),
       { extensions: ['earthdistance'], icu: false },
       { env, packageJsonResolver },
     );
-    assert.equal(command.args.filter((arg: string) => arg === '--carrier').length, 1);
-    assert.deepEqual(command.carrierManifests, [aggregateCarrier]);
+    assert.deepEqual(command.carriers, [aggregateCarrier]);
     assert.throws(
       () =>
         resolveIosCarrierManifests(projectRoot, ['earthdistance'], {
@@ -487,7 +515,7 @@ test('aggregate CI carrier override supplies base and dependency closure exactly
   }
 });
 
-test('carrier discovery and staging fail closed', () => {
+test('carrier discovery and staging fail closed', async () => {
   const root = fs.mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-plugin-failure-'));
   try {
     const fakeOwner = path.join(root, 'fake-owner.json');
@@ -576,7 +604,7 @@ test('carrier discovery and staging fail closed', () => {
         vector: vectorCarrier,
       }),
     };
-    assert.throws(
+    await assert.rejects(
       () =>
         stageIosAppPayload(
           root,
@@ -584,15 +612,12 @@ test('carrier discovery and staging fail closed', () => {
           { extensions: ['vector'], icu: false },
           {
             env: stageEnv,
-            spawnSyncImpl: () => ({
-              error: undefined,
-              status: 12,
-              stderr: 'checksum mismatch',
-              stdout: '',
-            }),
+            stageIosAppImpl: async () => {
+              throw new Error('checksum mismatch');
+            },
           },
         ),
-      /exit code 12: checksum mismatch/,
+      /checksum mismatch/,
     );
   } finally {
     fs.rmSync(root, { force: true, recursive: true });
diff --git a/src/sdks/react-native/src/__tests__/storage.test.ts b/src/sdks/react-native/src/__tests__/storage.test.ts
new file mode 100644
index 000000000..c5480c60a
--- /dev/null
+++ b/src/sdks/react-native/src/__tests__/storage.test.ts
@@ -0,0 +1,31 @@
+import { expect, test } from 'bun:test';
+import { directory } from '../storage';
+
+test('directory accepts native paths and decodes local filesystem URIs once', () => {
+  expect(directory('/data/my db')).toEqual({ kind: 'directory', path: '/data/my db' });
+  expect(directory('file:///data/my%20db')).toEqual(directory('/data/my db'));
+  expect(directory('file:///data/a%2520b').path).toBe('/data/a%20b');
+  expect(Object.isFrozen(directory('/data/db'))).toBe(true);
+});
+
+test('directory rejects non-local resources and malformed file URIs', () => {
+  for (const input of [
+    '',
+    ' ',
+    'relative/db',
+    './db',
+    '../db',
+    '/data/\0db',
+    'file:///data/%00db',
+    'file://remote/db',
+    'https://example.com/db',
+    'content://files/db',
+    'file:///db?q=1',
+    'file:///db#fragment',
+    'file:///data%2fdb',
+    'file:///data%5cdb',
+    'file:///bad%',
+  ]) {
+    expect(() => directory(input), input).toThrow();
+  }
+});
diff --git a/src/sdks/react-native/src/generated/extensions.ts b/src/sdks/react-native/src/generated/extensions.ts
index 7f6106a9d..a510a3679 100644
--- a/src/sdks/react-native/src/generated/extensions.ts
+++ b/src/sdks/react-native/src/generated/extensions.ts
@@ -1,4 +1,4 @@
-// This file is generated by src/extensions/tools/check-extension-model.mjs.
+// This file is generated by src/extensions/tools/check-extension-model.sh.
 // Do not edit by hand.
 
 export type GeneratedExtensionMetadata = {
@@ -26,971 +26,1006 @@ export type GeneratedExtensionMetadata = {
   readonly sourceKind: string;
 };
 
-export const GENERATED_EXTENSION_METADATA_SHA256 =
-  'c1d2e09905d7ecc0172173b34b9e4104dad58987503dd3dab7af4ae78890d9f3' as const;
+export const GENERATED_EXTENSION_METADATA_SHA256 = "c1d2e09905d7ecc0172173b34b9e4104dad58987503dd3dab7af4ae78890d9f3" as const;
 
 export const GENERATED_EXTENSION_METADATA = [
   {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'amcheck',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'amcheck',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'amcheck',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'amcheck',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: false,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'auto_explain',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'auto_explain',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'auto_explain',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'auto_explain',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'bloom',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'bloom',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'bloom',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'bloom',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'btree_gin',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'btree_gin',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'btree_gin',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'btree_gin',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'btree_gist',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'btree_gist',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'btree_gist',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'btree_gist',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'citext',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'citext',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'citext',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'citext',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'cube',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'cube',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'cube',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'cube',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'dict_int',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'dict_int',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'dict_int',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'dict_int',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: ['share/postgresql/tsearch_data/xsyn_sample.rules'],
-    dependencies: [],
-    displayName: 'dict_xsyn',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'dict_xsyn',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'dict_xsyn',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: ['tsearch_data/xsyn_sample.rules'],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'dict_xsyn',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: ['cube'],
-    displayName: 'earthdistance',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'earthdistance',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'earthdistance',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: ['cube'],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'earthdistance',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'file_fdw',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'file_fdw',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'file_fdw',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'file_fdw',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'fuzzystrmatch',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'fuzzystrmatch',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'fuzzystrmatch',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'fuzzystrmatch',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'hstore',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'hstore',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'hstore',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'hstore',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'intarray',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'intarray',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: '_int',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'intarray',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'isn',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'isn',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'isn',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'isn',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'lo',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'lo',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'lo',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'lo',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'ltree',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'ltree',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'ltree',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'ltree',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pageinspect',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pageinspect',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pageinspect',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pageinspect',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_buffercache',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_buffercache',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_buffercache',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_buffercache',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_freespacemap',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_freespacemap',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_freespacemap',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_freespacemap',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pg-hashids',
-    cargoPackage: 'oliphaunt-extension-pg-hashids',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_hashids',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_hashids',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-pg-hashids',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_hashids',
-    npmPackage: '@oliphaunt/extension-pg-hashids',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pg-hashids',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pg_hashids',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pg-ivm',
-    cargoPackage: 'oliphaunt-extension-pg-ivm',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_ivm',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_ivm',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-pg-ivm',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_ivm',
-    npmPackage: '@oliphaunt/extension-pg-ivm',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pg-ivm',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pg_ivm',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_surgery',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_surgery',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_surgery',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_surgery',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pg-textsearch',
-    cargoPackage: 'oliphaunt-extension-pg-textsearch',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_textsearch',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_textsearch',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-pg-textsearch',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_textsearch',
-    npmPackage: '@oliphaunt/extension-pg-textsearch',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pg-textsearch',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: ['pg_textsearch'],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pg_textsearch',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_trgm',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_trgm',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_trgm',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_trgm',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pg-uuidv7',
-    cargoPackage: 'oliphaunt-extension-pg-uuidv7',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_uuidv7',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_uuidv7',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-pg-uuidv7',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_uuidv7',
-    npmPackage: '@oliphaunt/extension-pg-uuidv7',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pg-uuidv7',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pg_uuidv7',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_visibility',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_visibility',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_visibility',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_visibility',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pg_walinspect',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pg_walinspect',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pg_walinspect',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pg_walinspect',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pgcrypto',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'pgcrypto',
-    iosStaticDependencies: ['openssl'],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'pgcrypto',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'pgcrypto',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-pgtap',
-    cargoPackage: 'oliphaunt-extension-pgtap',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: ['plpgsql'],
-    displayName: 'pgtap',
-    extensionSqlFileNames: ['uninstall_pgtap.sql'],
-    extensionSqlFilePrefixes: ['pgtap-core', 'pgtap-schema'],
-    id: 'pgtap',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-pgtap',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: null,
-    npmPackage: '@oliphaunt/extension-pgtap',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-pgtap',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'pgtap',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-postgis',
-    cargoPackage: 'oliphaunt-extension-postgis',
-    createsExtension: true,
-    dataFiles: [
-      'share/postgresql/contrib/postgis-3.6/legacy.sql',
-      'share/postgresql/contrib/postgis-3.6/legacy_gist.sql',
-      'share/postgresql/contrib/postgis-3.6/legacy_minimal.sql',
-      'share/postgresql/contrib/postgis-3.6/postgis.sql',
-      'share/postgresql/contrib/postgis-3.6/postgis_upgrade.sql',
-      'share/postgresql/contrib/postgis-3.6/spatial_ref_sys.sql',
-      'share/postgresql/contrib/postgis-3.6/uninstall_legacy.sql',
-      'share/postgresql/contrib/postgis-3.6/uninstall_postgis.sql',
-      'share/postgresql/proj/proj.db',
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "amcheck",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "amcheck",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "amcheck",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "amcheck"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": false,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "auto_explain",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "auto_explain",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "auto_explain",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "auto_explain"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "bloom",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "bloom",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "bloom",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "bloom"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "btree_gin",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "btree_gin",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "btree_gin",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "btree_gin"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "btree_gist",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "btree_gist",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "btree_gist",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "btree_gist"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "citext",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "citext",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "citext",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "citext"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "cube",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "cube",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "cube",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "cube"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "dict_int",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "dict_int",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "dict_int",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "dict_int"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [
+      "share/postgresql/tsearch_data/xsyn_sample.rules"
     ],
-    dependencies: [],
-    displayName: 'PostGIS',
-    extensionSqlFileNames: ['uninstall_postgis.sql'],
-    extensionSqlFilePrefixes: ['postgis_comments', 'postgis_proc_set_search_path', 'rtpostgis'],
-    id: 'postgis',
-    iosStaticDependencies: ['geos', 'geos-c', 'json-c', 'libxml2', 'proj', 'sqlite'],
-    mavenArtifact: 'oliphaunt-extension-postgis',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'postgis-3',
-    npmPackage: '@oliphaunt/extension-postgis',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-postgis',
-    runtimeBound: false,
-    runtimeShareDataFiles: [
-      'contrib/postgis-3.6/legacy.sql',
-      'contrib/postgis-3.6/legacy_gist.sql',
-      'contrib/postgis-3.6/legacy_minimal.sql',
-      'contrib/postgis-3.6/postgis.sql',
-      'contrib/postgis-3.6/postgis_upgrade.sql',
-      'contrib/postgis-3.6/spatial_ref_sys.sql',
-      'contrib/postgis-3.6/uninstall_legacy.sql',
-      'contrib/postgis-3.6/uninstall_postgis.sql',
-      'proj/proj.db',
+    "dependencies": [],
+    "displayName": "dict_xsyn",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "dict_xsyn",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "dict_xsyn",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [
+      "tsearch_data/xsyn_sample.rules"
     ],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgis',
-    sqlName: 'postgis',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'seg',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'seg',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'seg',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'seg',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'tablefunc',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'tablefunc',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'tablefunc',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'tablefunc',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'tcn',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'tcn',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'tcn',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'tcn',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'tsm_system_rows',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'tsm_system_rows',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'tsm_system_rows',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'tsm_system_rows',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'tsm_system_time',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'tsm_system_time',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'tsm_system_time',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'tsm_system_time',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: ['share/postgresql/tsearch_data/unaccent.rules'],
-    dependencies: [],
-    displayName: 'unaccent',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'unaccent',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'unaccent',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: ['tsearch_data/unaccent.rules'],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'unaccent',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-contrib-pg18',
-    cargoPackage: 'oliphaunt-extension-contrib-pg18',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'uuid-ossp',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'uuid_ossp',
-    iosStaticDependencies: ['uuid'],
-    mavenArtifact: 'oliphaunt-extension-contrib-pg18',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'uuid-ossp',
-    npmPackage: '@oliphaunt/extension-contrib-pg18',
-    postgresMajor: 18,
-    releaseProduct: 'liboliphaunt-native',
-    runtimeBound: true,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'postgres-contrib',
-    sqlName: 'uuid-ossp',
-  },
-  {
-    artifactProduct: 'oliphaunt-extension-vector',
-    cargoPackage: 'oliphaunt-extension-vector',
-    createsExtension: true,
-    dataFiles: [],
-    dependencies: [],
-    displayName: 'pgvector',
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-    id: 'vector',
-    iosStaticDependencies: [],
-    mavenArtifact: 'oliphaunt-extension-vector',
-    mavenGroup: 'dev.oliphaunt.extensions',
-    nativeModuleStem: 'vector',
-    npmPackage: '@oliphaunt/extension-vector',
-    postgresMajor: 18,
-    releaseProduct: 'oliphaunt-extension-vector',
-    runtimeBound: false,
-    runtimeShareDataFiles: [],
-    selectedExtensionDependencies: [],
-    sharedPreloadLibraries: [],
-    sourceKind: 'oliphaunt-other-extension',
-    sqlName: 'vector',
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "dict_xsyn"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [
+      "cube"
+    ],
+    "displayName": "earthdistance",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "earthdistance",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "earthdistance",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [
+      "cube"
+    ],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "earthdistance"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "file_fdw",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "file_fdw",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "file_fdw",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "file_fdw"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "fuzzystrmatch",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "fuzzystrmatch",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "fuzzystrmatch",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "fuzzystrmatch"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "hstore",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "hstore",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "hstore",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "hstore"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "intarray",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "intarray",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "_int",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "intarray"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "isn",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "isn",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "isn",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "isn"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "lo",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "lo",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "lo",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "lo"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "ltree",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "ltree",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "ltree",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "ltree"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pageinspect",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pageinspect",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pageinspect",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pageinspect"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_buffercache",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_buffercache",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_buffercache",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_buffercache"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_freespacemap",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_freespacemap",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_freespacemap",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_freespacemap"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-pg-hashids",
+    "cargoPackage": "oliphaunt-extension-pg-hashids",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_hashids",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_hashids",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-pg-hashids",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_hashids",
+    "npmPackage": "@oliphaunt/extension-pg-hashids",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pg-hashids",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pg_hashids"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-pg-ivm",
+    "cargoPackage": "oliphaunt-extension-pg-ivm",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_ivm",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_ivm",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-pg-ivm",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_ivm",
+    "npmPackage": "@oliphaunt/extension-pg-ivm",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pg-ivm",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pg_ivm"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_surgery",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_surgery",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_surgery",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_surgery"
   },
+  {
+    "artifactProduct": "oliphaunt-extension-pg-textsearch",
+    "cargoPackage": "oliphaunt-extension-pg-textsearch",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_textsearch",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_textsearch",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-pg-textsearch",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_textsearch",
+    "npmPackage": "@oliphaunt/extension-pg-textsearch",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pg-textsearch",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [
+      "pg_textsearch"
+    ],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pg_textsearch"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_trgm",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_trgm",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_trgm",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_trgm"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-pg-uuidv7",
+    "cargoPackage": "oliphaunt-extension-pg-uuidv7",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_uuidv7",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_uuidv7",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-pg-uuidv7",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_uuidv7",
+    "npmPackage": "@oliphaunt/extension-pg-uuidv7",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pg-uuidv7",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pg_uuidv7"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_visibility",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_visibility",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_visibility",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_visibility"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_walinspect",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_walinspect",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_walinspect",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_walinspect"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pgcrypto",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pgcrypto",
+    "iosStaticDependencies": [
+      "openssl"
+    ],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pgcrypto",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pgcrypto"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-pgtap",
+    "cargoPackage": "oliphaunt-extension-pgtap",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [
+      "plpgsql"
+    ],
+    "displayName": "pgtap",
+    "extensionSqlFileNames": [
+      "uninstall_pgtap.sql"
+    ],
+    "extensionSqlFilePrefixes": [
+      "pgtap-core",
+      "pgtap-schema"
+    ],
+    "id": "pgtap",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-pgtap",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": null,
+    "npmPackage": "@oliphaunt/extension-pgtap",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pgtap",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pgtap"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-postgis",
+    "cargoPackage": "oliphaunt-extension-postgis",
+    "createsExtension": true,
+    "dataFiles": [
+      "share/postgresql/contrib/postgis-3.6/legacy.sql",
+      "share/postgresql/contrib/postgis-3.6/legacy_gist.sql",
+      "share/postgresql/contrib/postgis-3.6/legacy_minimal.sql",
+      "share/postgresql/contrib/postgis-3.6/postgis.sql",
+      "share/postgresql/contrib/postgis-3.6/postgis_upgrade.sql",
+      "share/postgresql/contrib/postgis-3.6/spatial_ref_sys.sql",
+      "share/postgresql/contrib/postgis-3.6/uninstall_legacy.sql",
+      "share/postgresql/contrib/postgis-3.6/uninstall_postgis.sql",
+      "share/postgresql/proj/proj.db"
+    ],
+    "dependencies": [],
+    "displayName": "PostGIS",
+    "extensionSqlFileNames": [
+      "uninstall_postgis.sql"
+    ],
+    "extensionSqlFilePrefixes": [
+      "postgis_comments",
+      "postgis_proc_set_search_path",
+      "rtpostgis"
+    ],
+    "id": "postgis",
+    "iosStaticDependencies": [
+      "geos",
+      "geos-c",
+      "json-c",
+      "libxml2",
+      "proj",
+      "sqlite"
+    ],
+    "mavenArtifact": "oliphaunt-extension-postgis",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "postgis-3",
+    "npmPackage": "@oliphaunt/extension-postgis",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-postgis",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [
+      "contrib/postgis-3.6/legacy.sql",
+      "contrib/postgis-3.6/legacy_gist.sql",
+      "contrib/postgis-3.6/legacy_minimal.sql",
+      "contrib/postgis-3.6/postgis.sql",
+      "contrib/postgis-3.6/postgis_upgrade.sql",
+      "contrib/postgis-3.6/spatial_ref_sys.sql",
+      "contrib/postgis-3.6/uninstall_legacy.sql",
+      "contrib/postgis-3.6/uninstall_postgis.sql",
+      "proj/proj.db"
+    ],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgis",
+    "sqlName": "postgis"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "seg",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "seg",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "seg",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "seg"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "tablefunc",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "tablefunc",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "tablefunc",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "tablefunc"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "tcn",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "tcn",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "tcn",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "tcn"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "tsm_system_rows",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "tsm_system_rows",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "tsm_system_rows",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "tsm_system_rows"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "tsm_system_time",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "tsm_system_time",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "tsm_system_time",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "tsm_system_time"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [
+      "share/postgresql/tsearch_data/unaccent.rules"
+    ],
+    "dependencies": [],
+    "displayName": "unaccent",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "unaccent",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "unaccent",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [
+      "tsearch_data/unaccent.rules"
+    ],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "unaccent"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "uuid-ossp",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "uuid_ossp",
+    "iosStaticDependencies": [
+      "uuid"
+    ],
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "uuid-ossp",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "uuid-ossp"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-vector",
+    "cargoPackage": "oliphaunt-extension-vector",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pgvector",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "vector",
+    "iosStaticDependencies": [],
+    "mavenArtifact": "oliphaunt-extension-vector",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "vector",
+    "npmPackage": "@oliphaunt/extension-vector",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-vector",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "vector"
+  }
 ] as const satisfies readonly GeneratedExtensionMetadata[];
 
-export function generatedExtensionBySqlName(
-  sqlName: string,
-): GeneratedExtensionMetadata | undefined {
+export function generatedExtensionBySqlName(sqlName: string): GeneratedExtensionMetadata | undefined {
   return GENERATED_EXTENSION_METADATA.find((extension) => extension.sqlName === sqlName);
 }
 
diff --git a/src/sdks/react-native/src/index.ts b/src/sdks/react-native/src/index.ts
index c34ae433a..40d3bed1f 100644
--- a/src/sdks/react-native/src/index.ts
+++ b/src/sdks/react-native/src/index.ts
@@ -1,5 +1,6 @@
 import NativeOliphaunt from './specs/NativeOliphaunt';
 import { createOliphauntClient } from './client';
+export { directory } from './storage';
 
 export type {
   BinaryInput,
diff --git a/src/sdks/react-native/src/protocol.ts b/src/sdks/react-native/src/protocol.ts
index f23f4bdb1..0fdfe840b 100644
--- a/src/sdks/react-native/src/protocol.ts
+++ b/src/sdks/react-native/src/protocol.ts
@@ -1 +1 @@
-export * from '@oliphaunt/js-core/protocol';
+export * from '@oliphaunt/ts-query/protocol';
diff --git a/src/sdks/react-native/src/query.ts b/src/sdks/react-native/src/query.ts
index a297830c0..d4b53542b 100644
--- a/src/sdks/react-native/src/query.ts
+++ b/src/sdks/react-native/src/query.ts
@@ -1 +1 @@
-export * from '@oliphaunt/js-core/query';
+export * from '@oliphaunt/ts-query/query';
diff --git a/src/sdks/react-native/src/storage.ts b/src/sdks/react-native/src/storage.ts
new file mode 100644
index 000000000..e9152c39b
--- /dev/null
+++ b/src/sdks/react-native/src/storage.ts
@@ -0,0 +1,31 @@
+import type { DatabaseStorage } from './client';
+
+/**
+ * Persist a database in a native directory. Accepts a filesystem path or the
+ * local file URI returned by a mobile filesystem API; performs no file IO.
+ */
+export function directory(location: string): Extract {
+  let path = location;
+  if (/^file:/i.test(location)) {
+    const url = new URL(location);
+    if (url.hostname !== '' && url.hostname !== 'localhost') {
+      throw new TypeError('database storage directory must be a local file URI');
+    }
+    if (url.search || url.hash || /%2f|%5c/i.test(url.pathname)) {
+      throw new TypeError(
+        'database storage file URI must not contain a query, fragment, or encoded separator',
+      );
+    }
+    path = decodeURIComponent(url.pathname);
+  } else if (/^[a-z][a-z0-9+.-]*:/i.test(location)) {
+    throw new TypeError('database storage directory must be a filesystem path or local file URI');
+  }
+  if (!path.startsWith('/') || path.includes('\0')) {
+    throw new TypeError(
+      'database storage directory must be an absolute native path without NUL bytes',
+    );
+  }
+  return Object.freeze({ kind: 'directory', path });
+}
+
+export default directory;
diff --git a/src/sdks/react-native/tools/android-apk-resources.test.sh b/src/sdks/react-native/tools/android-apk-resources.test.sh
new file mode 100644
index 000000000..2aca2ecf8
--- /dev/null
+++ b/src/sdks/react-native/tools/android-apk-resources.test.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(cd "$(dirname "$0")/../../../.." && pwd)"
+# shellcheck source=src/sdks/react-native/tools/expo-runner-reporting.sh
+source "$root/src/sdks/react-native/tools/expo-runner-reporting.sh"
+scratch=$(mktemp -d)
+trap 'rm -rf "$scratch"' EXIT
+fixture="$scratch/apk"
+resources="$fixture/assets/oliphaunt"
+pack() {
+  rm -f "$scratch/app.apk"
+  (cd "$fixture" && zip -qr "$scratch/app.apk" assets)
+}
+for profile in standard icu; do
+  rm -rf "$fixture"
+  mkdir -p "$resources/runtime"
+  features=''
+  seed=cluster-seed
+  if [[ "$profile" == icu ]]; then features=icu; seed=cluster-seed-icu; fi
+  printf 'runtimeFeatures=%s\n' "$features" >"$resources/runtime/manifest.properties"
+  # Existing storage requires no seed dependency, with or without ICU data.
+  pack
+  export_mobile_e2e_icu_expectation_from_android_apk "$scratch/app.apk" fixture
+  [[ "$OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE" == "$profile" ]]
+  [[ "$OLIPHAUNT_MOBILE_E2E_EXPECT_ICU" == "$([[ "$profile" == icu ]] && echo 1 || echo 0)" ]]
+  mkdir -p "$resources/$seed"
+  printf 'catalogProfile=%s\n' "$profile" >"$resources/$seed/manifest.properties"
+  pack
+  export_mobile_e2e_icu_expectation_from_android_apk "$scratch/app.apk" fixture
+  printf 'catalogProfile=invalid\n' >"$resources/$seed/manifest.properties"
+  pack
+  if export_mobile_e2e_icu_expectation_from_android_apk "$scratch/app.apk" fixture 2>"$scratch/error"; then
+    echo 'accepted an incompatible selected seed' >&2; exit 1
+  fi
+  grep -q 'does not declare catalogProfile' "$scratch/error"
+done
+# A carrier cannot silently select both profiles or the opposite profile.
+printf 'catalogProfile=icu\n' >"$resources/cluster-seed-icu/manifest.properties"
+mkdir -p "$resources/cluster-seed"
+printf 'catalogProfile=standard\n' >"$resources/cluster-seed/manifest.properties"
+pack
+if export_mobile_e2e_icu_expectation_from_android_apk "$scratch/app.apk" fixture 2>"$scratch/error"; then exit 1; fi
+grep -q 'incompatible with catalogProfile' "$scratch/error"
+rm "$resources/runtime/manifest.properties"
+pack
+if export_mobile_e2e_icu_expectation_from_android_apk "$scratch/app.apk" fixture 2>"$scratch/error"; then exit 1; fi
+grep -q 'could not be read' "$scratch/error"
diff --git a/src/sdks/react-native/tools/build.sh b/src/sdks/react-native/tools/build.sh
new file mode 100644
index 000000000..18d13ae1c
--- /dev/null
+++ b/src/sdks/react-native/tools/build.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
+rm -rf lib .generated-tools
+tsc --ignoreConfig --noCheck --target ES2022 --module nodenext --rewriteRelativeImportExtensions \
+  --rootDir . --outDir .generated-tools \
+  app.plugin.cts react-native.config.cts tools/codegen-check.cts \
+  tools/native-resource-closure.mts tools/verify-ios-package.mts
+mv .generated-tools/app.plugin.cjs app.plugin.js
+mv .generated-tools/react-native.config.cjs react-native.config.js
+mv .generated-tools/tools/* tools/
+rm -rf .generated-tools
+bun build tools/stage-ios-app.mts --target=node --format=esm --outfile=tools/stage-ios-app.mjs
+tsc -p tsconfig.build.types.json
+tsc -p tsconfig.build.module.json
+tsc -p tsconfig.build.commonjs.json
diff --git a/src/sdks/react-native/tools/check-icu-autolinking.sh b/src/sdks/react-native/tools/check-icu-autolinking.sh
new file mode 100644
index 000000000..4e7a79f90
--- /dev/null
+++ b/src/sdks/react-native/tools/check-icu-autolinking.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+set -euo pipefail
+[ "$#" -eq 3 ] || { echo 'usage: check-icu-autolinking.sh REACT_NATIVE_TARBALL ICU_SOURCE EXPO_PROJECT' >&2; exit 2; }
+root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-autolinking.XXXXXX")"
+trap 'rm -rf "$root"' EXIT
+helper="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/icu-autolinking-fixture.mts"
+expo_project="$(cd "$3" && pwd)"
+bun "$helper" prepare "$root" "$1" "$2" "$expo_project"
+mkdir "$root/packed"
+bun pm --cwd "$root/icu-source" pack --ignore-scripts --destination "$root/packed" > /dev/null
+archives=("$root/packed/"*.tgz)
+[ "${#archives[@]}" -eq 1 ] && [ -f "${archives[0]}" ]
+bun "$helper" extract "$root" "${archives[0]}"
+consumer="$root/consumer"
+cli="$(cat "$root/cli")"
+for kind in candidate control; do
+  if [ "$kind" = control ]; then bun "$helper" control "$root"; platforms=(ios); else platforms=(ios android); fi
+  for platform in "${platforms[@]}"; do
+    (cd "$expo_project" && bun x --no-install expo-modules-autolinking react-native-config "$consumer/node_modules" \
+      --project-root "$consumer" --platform "$platform" --json) > "$root/expo.json"
+    bun "$helper" check "$root" "$kind" "$platform" "$root/expo.json"
+    (cd "$consumer" && node "$cli" config --platform "$platform") > "$root/bare.json"
+    bun "$helper" check "$root" "$kind" "$platform" "$root/bare.json"
+  done
+done
+printf 'Packed React Native and ICU Expo/bare autolinking passed\n'
diff --git a/src/sdks/react-native/tools/check-mobile-artifacts.mts b/src/sdks/react-native/tools/check-mobile-artifacts.mts
new file mode 100644
index 000000000..a46a40162
--- /dev/null
+++ b/src/sdks/react-native/tools/check-mobile-artifacts.mts
@@ -0,0 +1,1034 @@
+#!/usr/bin/env bun
+import path from 'node:path';
+import {
+  ROOT,
+  compareText,
+  exactExtensionProducts,
+  extensionArtifactProductRoot,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
+import {
+  ARCHIVE_ENTRY_CACHE,
+  ARCHIVE_ENTRY_CACHE_LIMIT,
+  PREFIX,
+  directoryNames,
+  fail,
+  isDirectory,
+  isFile,
+  readJson,
+  readPropertiesText,
+  rel,
+  sha256File,
+  walkFiles,
+} from '../../../../tools/packaging/release-carrier.mts';
+import { readAndroidApkEntries } from '../../../../tools/packaging/portable-archive.mts';
+import { validateMobileRuntimeFiles } from './validate-mobile-runtime-files.mts';
+import { EXTENSION_ROOT } from '../../../extensions/artifacts/packages/tools/check-carriers.mts';
+
+const MOBILE_ROOT = path.join(ROOT, 'target/mobile-build/react-native');
+
+const REACT_NATIVE_EXTENSION_METADATA = path.join(
+  ROOT,
+  'src/extensions/generated/sdk/extensions.json',
+);
+
+const MOBILE_STATIC_REGISTRY = path.join(
+  ROOT,
+  'src/extensions/generated/mobile/static-registry.json',
+);
+
+const IOS_EXTENSION_LINK_PREFIX = 'liboliphaunt_extension_';
+
+const IOS_EXTENSION_LINK_STEM = /^[a-z_][a-z0-9_-]{0,127}$/u;
+
+function csvValues(value) {
+  if (!value) {
+    return [];
+  }
+  return String(value)
+    .split(',')
+    .map((item) => item.trim())
+    .filter(Boolean);
+}
+
+function strictAndroidApkEntries(file) {
+  const fileStat = statSync(file, { bigint: true });
+  const cacheKey = [
+    'android-apk',
+    path.resolve(file),
+    fileStat.dev,
+    fileStat.ino,
+    fileStat.size,
+    fileStat.mtimeNs,
+    fileStat.ctimeNs,
+  ].join('\0');
+  const cached = ARCHIVE_ENTRY_CACHE.get(cacheKey);
+  if (cached !== undefined) {
+    ARCHIVE_ENTRY_CACHE.delete(cacheKey);
+    ARCHIVE_ENTRY_CACHE.set(cacheKey, cached);
+    return cached;
+  }
+  let entries;
+  try {
+    entries = readAndroidApkEntries(file);
+  } catch (error) {
+    fail(`${rel(file)} is not a strict Android APK archive: ${error.message}`);
+  }
+  ARCHIVE_ENTRY_CACHE.set(cacheKey, entries);
+  while (ARCHIVE_ENTRY_CACHE.size > ARCHIVE_ENTRY_CACHE_LIMIT) {
+    ARCHIVE_ENTRY_CACHE.delete(ARCHIVE_ENTRY_CACHE.keys().next().value);
+  }
+  return entries;
+}
+
+function archiveAndroidApkNames(file) {
+  return [...strictAndroidApkEntries(file)]
+    .filter(([, entry]) => entry.isFile)
+    .map(([name]) => name)
+    .sort(compareText);
+}
+
+function androidApkReadText(file, name) {
+  const entry = strictAndroidApkEntries(file).get(name);
+  if (!entry || !entry.isFile) {
+    fail(`${rel(file)} is missing ${name}`);
+  }
+  try {
+    return Buffer.from(entry.data()).toString('utf8');
+  } catch (error) {
+    fail(`${rel(file)} member ${name} is not readable UTF-8: ${error.message}`);
+  }
+}
+
+function pathBytes(file) {
+  if (isFile(file)) {
+    return statSync(file).size;
+  }
+  if (isDirectory(file)) {
+    let total = 0;
+    for (const name of directoryNames(file)) {
+      total += statSync(path.join(file, ...name.split('/'))).size;
+    }
+    return total;
+  }
+  fail(`missing path while measuring bytes: ${rel(file)}`);
+}
+
+function dirReadText(root, name) {
+  const file = path.join(root, ...name.split('/'));
+  if (!isFile(file)) {
+    fail(`${rel(root)} is missing ${name}`);
+  }
+  return readFileSync(file, 'utf8');
+}
+
+function generatedExtensionRows() {
+  const data = readJson(REACT_NATIVE_EXTENSION_METADATA);
+  const rows = data.extensions;
+  if (!Array.isArray(rows)) {
+    fail(`${rel(REACT_NATIVE_EXTENSION_METADATA)} must contain an extensions array`);
+  }
+  const result = new Map();
+  for (const row of rows) {
+    if (row && typeof row === 'object' && !Array.isArray(row)) {
+      const sqlName = row['sql-name'];
+      if (typeof sqlName === 'string' && sqlName) {
+        result.set(sqlName, row);
+      }
+    }
+  }
+  return result;
+}
+
+function canonicalMobileDomain(values, label) {
+  const canonical = [...new Set(values)].sort(compareText);
+  if (canonical.length !== values.length || JSON.stringify(canonical) !== JSON.stringify(values)) {
+    throw new Error(
+      `${label} must be a sorted, duplicate-free CSV domain; got ${JSON.stringify(values)}`,
+    );
+  }
+  return canonical;
+}
+
+function requireSameMobileDomain(actual, expected, label) {
+  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+    throw new Error(`${label}=${JSON.stringify(actual)}, expected ${JSON.stringify(expected)}`);
+  }
+}
+
+export function validateMobileExtensionManifestDomains({
+  runtime,
+  staticRegistry,
+  rows,
+  label = 'mobile runtime manifest',
+}) {
+  for (const key of [
+    'selectedExtensions',
+    'extensions',
+    'mobileStaticRegistryState',
+    'mobileStaticRegistryRegistered',
+    'mobileStaticRegistryPending',
+    'nativeModuleStems',
+  ]) {
+    if (!Object.hasOwn(runtime, key)) {
+      throw new Error(
+        key === 'selectedExtensions'
+          ? `${label} must define the full selectedExtensions domain`
+          : `${label} must define ${key}`,
+      );
+    }
+  }
+  for (const key of [
+    'state',
+    'registeredExtensions',
+    'pendingExtensions',
+    'nativeModuleStems',
+    'modules',
+  ]) {
+    if (!Object.hasOwn(staticRegistry, key)) {
+      throw new Error(`${label} static-registry manifest must define ${key}`);
+    }
+  }
+  const selectedExtensions = canonicalMobileDomain(
+    csvValues(runtime.selectedExtensions),
+    `${label} selectedExtensions`,
+  );
+  const createableExtensions = [];
+  const nativeExtensions = [];
+  const nativeModuleStems = [];
+  for (const extension of selectedExtensions) {
+    const row = rows.get(extension);
+    if (!row) {
+      throw new Error(
+        `${label} selected extension ${JSON.stringify(extension)} is missing from generated extension metadata`,
+      );
+    }
+    if (row['creates-extension'] === true) {
+      createableExtensions.push(extension);
+    }
+    const stem = row['native-module-stem'];
+    if (typeof stem === 'string' && stem && stem !== '-') {
+      nativeExtensions.push(extension);
+      nativeModuleStems.push(stem);
+    }
+  }
+  nativeModuleStems.sort(compareText);
+
+  requireSameMobileDomain(
+    canonicalMobileDomain(csvValues(runtime.extensions), `${label} extensions`),
+    createableExtensions,
+    `${label} createable extensions`,
+  );
+  requireSameMobileDomain(
+    canonicalMobileDomain(
+      csvValues(runtime.mobileStaticRegistryRegistered),
+      `${label} mobileStaticRegistryRegistered`,
+    ),
+    nativeExtensions,
+    `${label} registered native extensions`,
+  );
+  requireSameMobileDomain(
+    canonicalMobileDomain(csvValues(runtime.nativeModuleStems), `${label} nativeModuleStems`),
+    nativeModuleStems,
+    `${label} native module stems`,
+  );
+  requireSameMobileDomain(
+    canonicalMobileDomain(
+      csvValues(staticRegistry.registeredExtensions),
+      `${label} static-registry registeredExtensions`,
+    ),
+    nativeExtensions,
+    `${label} static-registry registered native extensions`,
+  );
+  requireSameMobileDomain(
+    canonicalMobileDomain(
+      csvValues(staticRegistry.nativeModuleStems),
+      `${label} static-registry nativeModuleStems`,
+    ),
+    nativeModuleStems,
+    `${label} static-registry native module stems`,
+  );
+  requireSameMobileDomain(
+    canonicalMobileDomain(
+      csvValues(runtime.mobileStaticRegistryPending),
+      `${label} mobileStaticRegistryPending`,
+    ),
+    [],
+    `${label} pending native extensions`,
+  );
+  requireSameMobileDomain(
+    canonicalMobileDomain(
+      csvValues(staticRegistry.pendingExtensions),
+      `${label} static-registry pendingExtensions`,
+    ),
+    [],
+    `${label} static-registry pending native extensions`,
+  );
+  requireSameMobileDomain(
+    canonicalMobileDomain(csvValues(staticRegistry.modules), `${label} static-registry modules`),
+    nativeModuleStems,
+    `${label} static-registry modules`,
+  );
+  const expectedRegistryState = nativeExtensions.length > 0 ? 'complete' : 'not-required';
+  if (runtime.mobileStaticRegistryState !== expectedRegistryState) {
+    throw new Error(
+      `${label} mobileStaticRegistryState=${JSON.stringify(runtime.mobileStaticRegistryState)}, ` +
+        `expected ${JSON.stringify(expectedRegistryState)}`,
+    );
+  }
+  if (staticRegistry.state !== expectedRegistryState) {
+    throw new Error(
+      `${label} static-registry state=${JSON.stringify(staticRegistry.state)}, ` +
+        `expected ${JSON.stringify(expectedRegistryState)}`,
+    );
+  }
+
+  return {
+    createableExtensions,
+    nativeExtensions,
+    nativeModuleStems,
+    selectedExtensions,
+  };
+}
+
+function discoverMobileArtifacts(platform) {
+  if (platform === 'android') {
+    const root = path.join(MOBILE_ROOT, 'android');
+    return existsSync(root)
+      ? readdirSync(root)
+          .filter((name) => name.endsWith('.apk'))
+          .map((name) => {
+            const file = path.join(root, name);
+            return {
+              platform: 'android',
+              path: file,
+              names: archiveAndroidApkNames(file),
+              readText: (member) => androidApkReadText(file, member),
+            };
+          })
+          .sort((left, right) => compareText(left.path, right.path))
+      : [];
+  }
+  if (platform === 'ios') {
+    const root = path.join(MOBILE_ROOT, 'ios');
+    return existsSync(root)
+      ? readdirSync(root)
+          .filter((name) => name.endsWith('.app') && isDirectory(path.join(root, name)))
+          .map((name) => {
+            const app = path.join(root, name);
+            return {
+              platform: 'ios',
+              path: app,
+              names: directoryNames(app),
+              readText: (member) => dirReadText(app, member),
+            };
+          })
+          .sort((left, right) => compareText(left.path, right.path))
+      : [];
+  }
+  fail(`unsupported mobile platform ${platform}`);
+}
+
+function mobilePrefix(platform) {
+  if (platform === 'android') {
+    return 'assets/oliphaunt/';
+  }
+  if (platform === 'ios') {
+    return 'OliphauntReactNativeResources.bundle/oliphaunt/';
+  }
+  fail(`unsupported mobile platform ${platform}`);
+}
+
+function mobileTargetForArtifact(artifact) {
+  if (artifact.platform === 'ios') {
+    return 'ios-xcframework';
+  }
+  const abis = artifact.names
+    .map((name) => name.split('/'))
+    .filter((parts) => parts.length === 3 && parts[0] === 'lib' && parts[2] === 'liboliphaunt.so')
+    .map((parts) => parts[1])
+    .sort(compareText);
+  if (abis.length !== 1) {
+    fail(
+      `${rel(artifact.path)} must contain exactly one Android liboliphaunt ABI, got ${JSON.stringify(abis)}`,
+    );
+  }
+  if (abis[0] === 'arm64-v8a') {
+    return 'android-arm64-v8a';
+  }
+  if (abis[0] === 'x86_64') {
+    return 'android-x86_64';
+  }
+  fail(`${rel(artifact.path)} contains unsupported Android ABI ${abis[0]}`);
+}
+
+export function validatePackagedMobileRuntimeFiles({
+  artifactNames,
+  metadata,
+  platform,
+  prefix,
+  registry,
+  selected,
+}) {
+  const runtimePrefix = `${prefix}runtime/files/`;
+  const runtimePaths = new Set(
+    artifactNames
+      .filter((name) => name.startsWith(runtimePrefix) && !name.endsWith('/'))
+      .map((name) => name.slice(runtimePrefix.length)),
+  );
+  validateMobileRuntimeFiles({
+    metadata,
+    metadataLabel: rel(REACT_NATIVE_EXTENSION_METADATA),
+    platform,
+    registry,
+    registryLabel: rel(MOBILE_STATIC_REGISTRY),
+    runtimePaths,
+    selected: selected.join(','),
+  });
+}
+
+function mobileBuildReport(platform) {
+  const report = path.join(MOBILE_ROOT, platform, 'build-report.json');
+  if (!isFile(report)) {
+    return null;
+  }
+  const data = readJson(report);
+  if (data.schema !== 'oliphaunt-react-native-mobile-build-v1') {
+    fail(`${rel(report)} has invalid mobile build report schema`);
+  }
+  if (data.platform !== platform) {
+    fail(
+      `${rel(report)} has platform=${JSON.stringify(data.platform)}, expected ${JSON.stringify(platform)}`,
+    );
+  }
+  return data;
+}
+
+function resolveReportPath(value, reportPath, field) {
+  if (typeof value !== 'string' || !value) {
+    fail(`${rel(reportPath)} must declare ${field}`);
+  }
+  return path.isAbsolute(value) ? value : path.join(ROOT, value);
+}
+
+function checkExtensionPackageHasMobileTarget(sqlName, target) {
+  for (const product of exactExtensionProducts(PREFIX)) {
+    const manifest = path.join(
+      extensionArtifactProductRoot(product, 'native', EXTENSION_ROOT, PREFIX),
+      'extension-artifacts.json',
+    );
+    if (!isFile(manifest)) {
+      continue;
+    }
+    const data = readJson(manifest);
+    const member =
+      data.schema === 'oliphaunt-extension-ci-artifacts-v2'
+        ? data.extensions?.find((row) => row?.sqlName === sqlName)
+        : data.sqlName === sqlName
+          ? data
+          : null;
+    if (member === null || member === undefined) {
+      continue;
+    }
+    const assets = member.assets;
+    if (!Array.isArray(assets)) {
+      fail(`${rel(manifest)} must declare assets`);
+    }
+    const runtimeMatches = assets.filter(
+      (asset) =>
+        asset && asset.family === 'native' && asset.target === target && asset.kind === 'runtime',
+    );
+    if (runtimeMatches.length !== 1) {
+      fail(
+        `${sqlName} exact-extension package must contain one native runtime asset for ${target}`,
+      );
+    }
+    if (target === 'ios-xcframework') {
+      const frameworkMatches = assets.filter(
+        (asset) =>
+          asset &&
+          asset.family === 'native' &&
+          asset.target === target &&
+          asset.kind === 'ios-xcframework',
+      );
+      const dependencyMatches = assets.filter(
+        (asset) =>
+          asset &&
+          asset.family === 'native' &&
+          asset.target === target &&
+          asset.kind === 'ios-dependency-xcframework',
+      );
+      const hasNativeModule =
+        typeof member.nativeModuleStem === 'string' && member.nativeModuleStem.length > 0;
+      if (frameworkMatches.length !== (hasNativeModule ? 1 : 0)) {
+        fail(
+          `${sqlName} exact-extension package has the wrong iOS XCFramework role count for ${hasNativeModule ? 'native' : 'SQL-only'} metadata`,
+        );
+      }
+      const expectedDependencies =
+        hasNativeModule && Array.isArray(member.iosNativeDependencies)
+          ? member.iosNativeDependencies
+          : [];
+      if (
+        JSON.stringify(dependencyMatches.map((asset) => asset.identity).sort(compareText)) !==
+        JSON.stringify(expectedDependencies)
+      ) {
+        fail(
+          `${sqlName} exact-extension package iOS dependency XCFrameworks do not match its frozen dependency closure`,
+        );
+      }
+    }
+    return;
+  }
+  fail(`no exact-extension package found for selected mobile extension ${sqlName}`);
+}
+
+export function iosPayloadCocoaPodsFileListPaths(scratchPath) {
+  const podName = 'OliphauntReactNativePayload';
+  const supportRoot = path.join(
+    scratchPath,
+    'src/examples/react-native-expo/ios/Pods/Target Support Files',
+    podName,
+  );
+  return {
+    inputFile: path.join(supportRoot, `${podName}-xcframeworks-input-files.xcfilelist`),
+    outputFile: path.join(supportRoot, `${podName}-xcframeworks-output-files.xcfilelist`),
+    podName,
+    supportRoot,
+  };
+}
+
+function canonicalIosExtensionLinkStems(stems) {
+  if (!Array.isArray(stems)) {
+    throw new Error('expected iOS extension native-module stems must be an array');
+  }
+  const raw = new Set();
+  const symbols = new Map();
+  for (const stem of stems) {
+    if (typeof stem !== 'string' || !IOS_EXTENSION_LINK_STEM.test(stem)) {
+      throw new Error(`invalid iOS extension native-module stem ${JSON.stringify(stem)}`);
+    }
+    if (raw.has(stem)) {
+      throw new Error(`duplicate iOS extension native-module stem ${JSON.stringify(stem)}`);
+    }
+    raw.add(stem);
+    const symbolStem = stem.replaceAll('-', '_');
+    const prior = symbols.get(symbolStem);
+    if (prior !== undefined) {
+      throw new Error(
+        `iOS extension native-module stems ${JSON.stringify(prior)} and ${JSON.stringify(stem)} ` +
+          `collide after registration-symbol normalization to ${JSON.stringify(symbolStem)}`,
+      );
+    }
+    symbols.set(symbolStem, stem);
+  }
+  return [...raw].sort(compareText);
+}
+
+function iosCocoaPodsExtensionArtifacts(text, kind) {
+  if (typeof text !== 'string') {
+    throw new Error(`CocoaPods ${kind} file list must be text`);
+  }
+  const suffixes =
+    kind === 'input' ? ['.xcframework'] : kind === 'output' ? ['.framework', '.a'] : null;
+  if (suffixes === null) {
+    throw new Error(`unsupported CocoaPods file-list kind ${JSON.stringify(kind)}`);
+  }
+  const artifacts = new Set();
+  for (const [index, raw] of text.split(/\r?\n/u).entries()) {
+    if (raw.includes('\0')) {
+      throw new Error(`CocoaPods ${kind} file list line ${index + 1} contains NUL`);
+    }
+    const record = raw.trim();
+    if (!record) {
+      continue;
+    }
+    const components = record.split('/');
+    const candidates = kind === 'input' ? components : [components.at(-1)];
+    for (const component of candidates) {
+      if (!component.startsWith(IOS_EXTENSION_LINK_PREFIX)) {
+        continue;
+      }
+      const suffix = suffixes.find((value) => component.endsWith(value));
+      if (suffix === undefined) {
+        throw new Error(
+          `CocoaPods ${kind} file list line ${index + 1} has unsupported ` +
+            `Oliphaunt extension artifact component ${JSON.stringify(component)}`,
+        );
+      }
+      const stem = component.slice(IOS_EXTENSION_LINK_PREFIX.length, -suffix.length);
+      if (!IOS_EXTENSION_LINK_STEM.test(stem)) {
+        throw new Error(
+          `CocoaPods ${kind} file list line ${index + 1} has invalid ` +
+            `Oliphaunt extension native-module stem ${JSON.stringify(stem)}`,
+        );
+      }
+      const artifact = `${IOS_EXTENSION_LINK_PREFIX}${stem}`;
+      if (artifacts.has(artifact)) {
+        throw new Error(
+          `CocoaPods ${kind} file list repeats Oliphaunt extension artifact ${JSON.stringify(artifact)}`,
+        );
+      }
+      artifacts.add(artifact);
+    }
+  }
+  return [...artifacts].sort(compareText);
+}
+
+export function iosCocoaPodsExtensionLinkEvidence({ expectedStems, inputText, outputText }) {
+  const expectedArtifacts = canonicalIosExtensionLinkStems(expectedStems).map(
+    (stem) => `${IOS_EXTENSION_LINK_PREFIX}${stem}`,
+  );
+  const inputArtifacts = iosCocoaPodsExtensionArtifacts(inputText, 'input');
+  const outputArtifacts = iosCocoaPodsExtensionArtifacts(outputText, 'output');
+  const expected = new Set(expectedArtifacts);
+  const input = new Set(inputArtifacts);
+  const output = new Set(outputArtifacts);
+  return {
+    expectedArtifacts,
+    inputArtifacts,
+    missingInput: expectedArtifacts.filter((artifact) => !input.has(artifact)),
+    missingOutput: expectedArtifacts.filter((artifact) => !output.has(artifact)),
+    outputArtifacts,
+    unexpectedInput: inputArtifacts.filter((artifact) => !expected.has(artifact)),
+    unexpectedOutput: outputArtifacts.filter((artifact) => !expected.has(artifact)),
+  };
+}
+
+function checkIosPrebuiltExtensionLinkage(artifact, stems) {
+  if (stems.length === 0) {
+    return;
+  }
+  const sourceLeaks = artifact.names
+    .filter(
+      (name) =>
+        name.includes('/static-registry/oliphaunt_static_registry.c') ||
+        name.includes('/extension-frameworks/') ||
+        name.endsWith('.xcframework'),
+    )
+    .sort(compareText);
+  if (sourceLeaks.length > 0) {
+    fail(
+      `${rel(artifact.path)} includes build-only iOS static-extension inputs as app resources: ${sourceLeaks.slice(0, 10).join(', ')}`,
+    );
+  }
+  const report = mobileBuildReport('ios');
+  if (report === null) {
+    fail(
+      `${rel(artifact.path)} requires ${rel(path.join(MOBILE_ROOT, 'ios/build-report.json'))} for iOS extension link evidence`,
+    );
+  }
+  const scratchRoot = report.scratchRoot;
+  if (typeof scratchRoot !== 'string' || !scratchRoot) {
+    fail(
+      `${rel(path.join(MOBILE_ROOT, 'ios/build-report.json'))} must declare scratchRoot for iOS extension link evidence`,
+    );
+  }
+  const scratchPath = scratchRoot;
+  const xcodeLog = path.join(scratchPath, 'xcodebuild.log');
+  if (!isFile(xcodeLog)) {
+    fail(`iOS extension link evidence is missing xcodebuild log: ${rel(xcodeLog)}`);
+  }
+  const logText = readFileSync(xcodeLog, 'utf8');
+  if (!logText.includes('** BUILD SUCCEEDED **')) {
+    fail(`iOS extension link evidence requires a successful xcodebuild log: ${rel(xcodeLog)}`);
+  }
+  const { inputFile, outputFile } = iosPayloadCocoaPodsFileListPaths(scratchPath);
+  if (!isFile(inputFile)) {
+    fail(
+      `iOS extension link evidence is missing CocoaPods XCFramework input file list: ${rel(inputFile)}`,
+    );
+  }
+  if (!isFile(outputFile)) {
+    fail(
+      `iOS extension link evidence is missing CocoaPods XCFramework output file list: ${rel(outputFile)}`,
+    );
+  }
+  let podEvidence;
+  try {
+    podEvidence = iosCocoaPodsExtensionLinkEvidence({
+      expectedStems: stems,
+      inputText: readFileSync(inputFile, 'utf8'),
+      outputText: readFileSync(outputFile, 'utf8'),
+    });
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+  const expectedFrameworks = new Set(podEvidence.expectedArtifacts);
+  const productsRoot = path.join(scratchPath, 'DerivedData/Build/Products');
+  if (!isDirectory(productsRoot)) {
+    fail(`iOS extension link evidence is missing Xcode build products: ${rel(productsRoot)}`);
+  }
+  const builtFrameworks = new Set(
+    walkFiles(productsRoot)
+      .map((file) => path.basename(file))
+      .filter((name) => /^liboliphaunt_extension_.*(\.a|\.framework)$/u.test(name))
+      .map((name) => name.replace(/\.a$/u, '').replace(/\.framework$/u, '')),
+  );
+  if (podEvidence.missingInput.length > 0) {
+    fail(
+      `CocoaPods input file list does not include selected iOS extension XCFramework(s): ${podEvidence.missingInput.join(', ')}`,
+    );
+  }
+  if (podEvidence.missingOutput.length > 0) {
+    fail(
+      `CocoaPods output file list does not include selected iOS extension linked artifact(s): ${podEvidence.missingOutput.join(', ')}`,
+    );
+  }
+  const missingBuilt = [...expectedFrameworks]
+    .filter((item) => !builtFrameworks.has(item))
+    .sort(compareText);
+  if (missingBuilt.length > 0) {
+    fail(
+      `Xcode build products do not include selected iOS extension linked artifact(s): ${missingBuilt.join(', ')}`,
+    );
+  }
+  if (podEvidence.unexpectedInput.length > 0) {
+    fail(
+      `CocoaPods input file list includes unselected iOS extension XCFramework(s): ${podEvidence.unexpectedInput.join(', ')}`,
+    );
+  }
+  if (podEvidence.unexpectedOutput.length > 0) {
+    fail(
+      `CocoaPods output file list includes unselected iOS extension linked artifact(s): ${podEvidence.unexpectedOutput.join(', ')}`,
+    );
+  }
+  const unexpectedBuilt = [...builtFrameworks]
+    .filter((item) => !expectedFrameworks.has(item))
+    .sort(compareText);
+  if (unexpectedBuilt.length > 0) {
+    fail(
+      `Xcode build products include unselected iOS extension linked artifact(s): ${unexpectedBuilt.join(', ')}`,
+    );
+  }
+}
+
+function checkAndroidPrebuiltExtensionLinkage(
+  artifact,
+  stems,
+  report,
+  reportPath,
+  expectedAbi,
+  staticRegistry,
+  target,
+) {
+  if (stems.length === 0) {
+    return;
+  }
+  const evidencePath = resolveReportPath(
+    report.androidLinkEvidence,
+    reportPath,
+    'androidLinkEvidence',
+  );
+  if (!isFile(evidencePath)) {
+    fail(`Android extension link evidence is missing: ${rel(evidencePath)}`);
+  }
+  if (!/^[0-9a-f]{64}$/u.test(report.androidLinkEvidenceSha256 ?? '')) {
+    fail(`${rel(reportPath)} androidLinkEvidenceSha256 must be a lowercase SHA-256 digest`);
+  }
+  const evidenceSha256 = sha256File(evidencePath);
+  if (evidenceSha256 !== report.androidLinkEvidenceSha256) {
+    fail(`${rel(reportPath)} androidLinkEvidenceSha256 does not match ${rel(evidencePath)}`);
+  }
+  const linkedStems = new Set();
+  const linkedDependencies = new Set();
+  let evidenceAbi = '';
+  let runtimePath = '';
+  let schemaRows = 0;
+  let abiRows = 0;
+  const requireExistingPath = (rawPath, lineNumber, rowKind) => {
+    const resolved = path.isAbsolute(rawPath)
+      ? rawPath
+      : path.join(path.dirname(evidencePath), rawPath);
+    if (!isFile(resolved)) {
+      fail(`${rel(evidencePath)}:${lineNumber} ${rowKind} path does not exist: ${resolved}`);
+    }
+    return resolved;
+  };
+  const lines = readFileSync(evidencePath, 'utf8').split(/\r?\n/u);
+  for (let index = 0; index < lines.length; index += 1) {
+    const parts = lines[index].split('\t');
+    if (!parts.length || !parts[0]) {
+      continue;
+    }
+    const lineNumber = index + 1;
+    const kind = parts[0];
+    if (kind === 'schema') {
+      if (
+        JSON.stringify(parts) !==
+        JSON.stringify(['schema', 'oliphaunt-android-static-extension-link-v1'])
+      ) {
+        fail(`${rel(evidencePath)}:${lineNumber} has invalid schema row`);
+      }
+      schemaRows += 1;
+    } else if (kind === 'abi') {
+      if (parts.length !== 2) {
+        fail(`${rel(evidencePath)}:${lineNumber} has invalid abi row`);
+      }
+      evidenceAbi = parts[1];
+      abiRows += 1;
+    } else if (kind === 'runtime') {
+      if (parts.length !== 3 || parts[1] !== 'liboliphaunt') {
+        fail(`${rel(evidencePath)}:${lineNumber} has invalid runtime row`);
+      }
+      const runtime = requireExistingPath(parts[2], lineNumber, 'runtime');
+      if (path.basename(runtime) !== 'liboliphaunt.so') {
+        fail(`${rel(evidencePath)}:${lineNumber} runtime path must end in liboliphaunt.so`);
+      }
+      if (runtimePath) {
+        fail(`${rel(evidencePath)} contains duplicate runtime rows`);
+      }
+      runtimePath = runtime;
+    } else if (kind === 'extension') {
+      if (parts.length !== 3) {
+        fail(`${rel(evidencePath)}:${lineNumber} has invalid extension row`);
+      }
+      const [stem, archive] = [parts[1], parts[2]];
+      const expectedName = `liboliphaunt_extension_${stem}.a`;
+      const archivePath = requireExistingPath(archive, lineNumber, 'extension');
+      const expectedRelative = staticRegistry[`module.${stem}.archive.${target}`];
+      if (!expectedRelative) {
+        fail(
+          `${rel(artifact.path)} static registry manifest has no module.${stem}.archive.${target} entry`,
+        );
+      }
+      if (path.basename(archivePath) !== expectedName) {
+        fail(
+          `${rel(evidencePath)}:${lineNumber} archive ${JSON.stringify(archive)} does not match stem ${JSON.stringify(stem)}`,
+        );
+      }
+      if (!archivePath.split(path.sep).join('/').endsWith(expectedRelative)) {
+        fail(
+          `${rel(evidencePath)}:${lineNumber} archive ${JSON.stringify(archive)} does not match static-registry path ${JSON.stringify(expectedRelative)}`,
+        );
+      }
+      linkedStems.add(stem);
+    } else if (kind === 'dependency') {
+      if (parts.length !== 3 || !parts[1]) {
+        fail(`${rel(evidencePath)}:${lineNumber} has invalid dependency row`);
+      }
+      const dependencyName = parts[1];
+      const dependencyPath = requireExistingPath(parts[2], lineNumber, 'dependency');
+      const expectedRelative = staticRegistry[`dependency.${dependencyName}.archive.${target}`];
+      if (!expectedRelative) {
+        fail(
+          `${rel(evidencePath)}:${lineNumber} dependency ${JSON.stringify(dependencyName)} is not declared by the static-registry manifest for ${target}`,
+        );
+      }
+      if (!dependencyPath.split(path.sep).join('/').endsWith(expectedRelative)) {
+        fail(
+          `${rel(evidencePath)}:${lineNumber} dependency path ${JSON.stringify(parts[2])} does not match static-registry path ${JSON.stringify(expectedRelative)}`,
+        );
+      }
+      linkedDependencies.add(dependencyName);
+    } else {
+      fail(`${rel(evidencePath)}:${lineNumber} has unknown row kind ${JSON.stringify(kind)}`);
+    }
+  }
+  if (schemaRows !== 1) {
+    fail(`${rel(evidencePath)} must contain exactly one schema row`);
+  }
+  if (abiRows !== 1) {
+    fail(`${rel(evidencePath)} must contain exactly one abi row`);
+  }
+  if (evidenceAbi !== expectedAbi) {
+    fail(
+      `${rel(evidencePath)} declares abi=${JSON.stringify(evidenceAbi)}, expected ${JSON.stringify(expectedAbi)}`,
+    );
+  }
+  if (!runtimePath) {
+    fail(`${rel(evidencePath)} does not show liboliphaunt runtime link input`);
+  }
+  const expectedStems = new Set(stems);
+  const missing = [...expectedStems].filter((stem) => !linkedStems.has(stem)).sort(compareText);
+  if (missing.length > 0) {
+    fail(
+      `${rel(evidencePath)} does not show selected Android extension archive link input(s): ${missing.join(', ')}`,
+    );
+  }
+  const unexpected = [...linkedStems].filter((stem) => !expectedStems.has(stem)).sort(compareText);
+  if (unexpected.length > 0) {
+    fail(
+      `${rel(evidencePath)} shows unselected Android extension archive link input(s): ${unexpected.join(', ')}`,
+    );
+  }
+  const expectedDependencies = new Set(csvValues(staticRegistry.dependencyArchives));
+  const missingDependencies = [...expectedDependencies]
+    .filter((dependency) => !linkedDependencies.has(dependency))
+    .sort(compareText);
+  if (missingDependencies.length > 0) {
+    fail(
+      `${rel(evidencePath)} does not show required Android extension dependency archive link input(s): ${missingDependencies.join(', ')}`,
+    );
+  }
+  const unexpectedDependencies = [...linkedDependencies]
+    .filter((dependency) => !expectedDependencies.has(dependency))
+    .sort(compareText);
+  if (unexpectedDependencies.length > 0) {
+    fail(
+      `${rel(evidencePath)} shows unselected Android extension dependency archive link input(s): ${unexpectedDependencies.join(', ')}`,
+    );
+  }
+}
+
+export function validatePackagedMobileRuntimeManifest(runtime, source = 'mobile runtime manifest') {
+  if (runtime.schema !== 'oliphaunt-runtime-resources-v1') {
+    throw new Error(`${source} has invalid runtime resource manifest schema`);
+  }
+  if (runtime.mode !== 'native-direct') {
+    throw new Error(`${source} must declare mode=native-direct`);
+  }
+}
+
+function checkMobileArtifact(artifact, { requirePrebuiltExtensions }) {
+  const prefix = mobilePrefix(artifact.platform);
+  const runtimeManifestName = `${prefix}runtime/manifest.properties`;
+  const staticRegistryManifestName = `${prefix}static-registry/manifest.properties`;
+  const packageSizeName = `${prefix}package-size.tsv`;
+  const runtime = readPropertiesText(artifact.readText(runtimeManifestName));
+  try {
+    validatePackagedMobileRuntimeManifest(
+      runtime,
+      `${rel(artifact.path)} runtime resource manifest`,
+    );
+  } catch (error) {
+    fail(error.message);
+  }
+  const rows = generatedExtensionRows();
+  const staticRegistry = readPropertiesText(artifact.readText(staticRegistryManifestName));
+  let domains;
+  try {
+    domains = validateMobileExtensionManifestDomains({
+      label: `${rel(artifact.path)} runtime manifest`,
+      rows,
+      runtime,
+      staticRegistry,
+    });
+  } catch (error) {
+    fail(error.message);
+  }
+  const selected = domains.selectedExtensions;
+  const target = mobileTargetForArtifact(artifact);
+  const reportPath = path.join(MOBILE_ROOT, artifact.platform, 'build-report.json');
+  const report = mobileBuildReport(artifact.platform);
+  if (report === null) {
+    fail(`${rel(artifact.path)} requires mobile build report ${rel(reportPath)}`);
+  }
+  const reportArtifact = resolveReportPath(report.appArtifact, reportPath, 'appArtifact');
+  if (path.resolve(reportArtifact) !== path.resolve(artifact.path)) {
+    fail(
+      `${rel(reportPath)} appArtifact=${reportArtifact} does not match inspected artifact ${artifact.path}`,
+    );
+  }
+  if (report.appArtifactBytes !== pathBytes(artifact.path)) {
+    fail(`${rel(reportPath)} appArtifactBytes does not match inspected artifact size`);
+  }
+  if (!Array.isArray(report.selectedExtensions)) {
+    fail(`${rel(reportPath)} selectedExtensions must be an array`);
+  }
+  const reportSelected = report.selectedExtensions
+    .map((value) => String(value))
+    .filter(Boolean)
+    .sort(compareText);
+  if (JSON.stringify(reportSelected) !== JSON.stringify([...selected].sort(compareText))) {
+    fail(
+      `${rel(reportPath)} selectedExtensions=${JSON.stringify(reportSelected)} must match runtime manifest ${JSON.stringify([...selected].sort(compareText))}`,
+    );
+  }
+  let expectedAbi = '';
+  if (artifact.platform === 'android') {
+    expectedAbi = target === 'android-arm64-v8a' ? 'arm64-v8a' : 'x86_64';
+    if (report.abi !== expectedAbi) {
+      fail(
+        `${rel(reportPath)} abi=${JSON.stringify(report.abi)}, expected ${JSON.stringify(expectedAbi)}`,
+      );
+    }
+  }
+  try {
+    validatePackagedMobileRuntimeFiles({
+      artifactNames: artifact.names,
+      metadata: readJson(REACT_NATIVE_EXTENSION_METADATA),
+      platform: artifact.platform === 'android' ? 'Android' : 'iOS',
+      prefix,
+      registry: readJson(MOBILE_STATIC_REGISTRY),
+      selected,
+    });
+  } catch (error) {
+    fail(`${rel(artifact.path)} failed mobile runtime inventory validation: ${error.message}`);
+  }
+  for (const extension of selected) {
+    if (requirePrebuiltExtensions) {
+      checkExtensionPackageHasMobileTarget(extension, target);
+    }
+  }
+  const stems = domains.nativeModuleStems;
+  if (stems.length > 0) {
+    if (runtime.mobileStaticRegistryState !== 'complete') {
+      fail(
+        `${rel(artifact.path)} must mark mobile static registry complete for native-module extensions`,
+      );
+    }
+    if (
+      artifact.platform === 'android' &&
+      !artifact.names.some((name) => name.endsWith('/liboliphaunt_extensions.so'))
+    ) {
+      fail(`${rel(artifact.path)} Android app is missing liboliphaunt_extensions.so`);
+    }
+    if (artifact.platform === 'android' && requirePrebuiltExtensions) {
+      checkAndroidPrebuiltExtensionLinkage(
+        artifact,
+        stems,
+        report,
+        reportPath,
+        expectedAbi,
+        staticRegistry,
+        target,
+      );
+    }
+    if (artifact.platform === 'ios' && requirePrebuiltExtensions) {
+      checkIosPrebuiltExtensionLinkage(artifact, stems);
+    }
+    if (artifact.names.some((name) => name.includes('static-registry/archives/'))) {
+      fail(`${rel(artifact.path)} must not ship build-only static-registry archives`);
+    }
+  } else if (![undefined, '', 'not-required'].includes(runtime.mobileStaticRegistryState)) {
+    fail(`${rel(artifact.path)} must not claim a static registry for SQL-only extensions`);
+  }
+  const packageSize = artifact.readText(packageSizeName);
+  const packageSizeExtensions = packageSize
+    .split(/\r?\n/u)
+    .filter((line) => line.startsWith('extension\t'))
+    .map((line) => line.split('\t')[1])
+    .filter(Boolean)
+    .sort(compareText);
+  if (JSON.stringify(packageSizeExtensions) !== JSON.stringify([...selected].sort(compareText))) {
+    fail(
+      `${rel(artifact.path)} package-size extension rows ${JSON.stringify(packageSizeExtensions)} must exactly match selected extensions ${JSON.stringify([...selected].sort(compareText))}`,
+    );
+  }
+  console.log(
+    `validated mobile app extension contents: ${artifact.platform} ${rel(artifact.path)}`,
+  );
+}
+
+export function checkMobilePlatform(platform, { require, requirePrebuiltExtensions }) {
+  const artifacts = discoverMobileArtifacts(platform);
+  if (artifacts.length === 0) {
+    if (require) {
+      fail(
+        `missing staged React Native ${platform} mobile app artifacts under ${rel(path.join(MOBILE_ROOT, platform))}`,
+      );
+    }
+    return false;
+  }
+  for (const artifact of artifacts) {
+    checkMobileArtifact(artifact, { requirePrebuiltExtensions });
+  }
+  return true;
+}
+
+if (import.meta.main) {
+  const [platform] = process.argv.slice(2);
+  if (!['android', 'ios'].includes(platform)) fail('usage: check-mobile-artifacts.mts android|ios');
+  checkMobilePlatform(platform, { require: true, requirePrebuiltExtensions: true });
+}
diff --git a/src/sdks/react-native/tools/check-mobile-artifacts.test.mts b/src/sdks/react-native/tools/check-mobile-artifacts.test.mts
new file mode 100644
index 000000000..48126639d
--- /dev/null
+++ b/src/sdks/react-native/tools/check-mobile-artifacts.test.mts
@@ -0,0 +1,320 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import {
+  iosCocoaPodsExtensionLinkEvidence,
+  validateMobileExtensionManifestDomains,
+  validatePackagedMobileRuntimeFiles,
+  validatePackagedMobileRuntimeManifest,
+} from './check-mobile-artifacts.mts';
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+import { CORE_SNOWBALL_RUNTIME_DATA_FILES } from './validate-mobile-runtime-files.mts';
+
+const REACT_NATIVE_METADATA = JSON.parse(
+  readFileSync(
+    path.join(import.meta.dir, '../../../extensions/generated/sdk/extensions.json'),
+    'utf8',
+  ),
+);
+
+const MOBILE_STATIC_REGISTRY = JSON.parse(
+  readFileSync(
+    path.join(import.meta.dir, '../../../extensions/generated/mobile/static-registry.json'),
+    'utf8',
+  ),
+);
+
+function packagedMobileRuntimeNames(prefix, extensionAssets) {
+  return [
+    ...CORE_SNOWBALL_RUNTIME_DATA_FILES.map((name) => `${prefix}runtime/files/${name}`),
+    ...extensionAssets.map((name) => `${prefix}runtime/files/share/postgresql/extension/${name}`),
+  ];
+}
+
+test('packaged mobile apps require the native-direct runtime contract', () => {
+  assert.doesNotThrow(() =>
+    validatePackagedMobileRuntimeManifest({
+      schema: 'oliphaunt-runtime-resources-v1',
+      mode: 'native-direct',
+    }),
+  );
+  assert.throws(
+    () =>
+      validatePackagedMobileRuntimeManifest({
+        schema: 'oliphaunt-runtime-resources-v1',
+        mode: 'native-server',
+      }),
+    /mode=native-direct/u,
+  );
+});
+
+test('matches CocoaPods iOS link inputs exactly for all generated extension identities', () => {
+  const bySqlName = new Map(
+    REACT_NATIVE_METADATA.extensions.map((row) => [row['sql-name'], row['native-module-stem']]),
+  );
+  assert.equal(bySqlName.get('intarray'), '_int');
+  assert.equal(bySqlName.get('pgtap'), null);
+  assert.equal(bySqlName.get('postgis'), 'postgis-3');
+  assert.equal(bySqlName.get('uuid-ossp'), 'uuid-ossp');
+
+  const expectedStems = [...bySqlName.values()].filter((stem) => stem !== null).sort();
+  assert.equal(expectedStems.length, 38);
+  const evidence = iosCocoaPodsExtensionLinkEvidence({
+    expectedStems,
+    inputText: expectedStems
+      .map(
+        (stem) =>
+          `\${PODS_ROOT}/../oliphaunt/frameworks/extensions/liboliphaunt_extension_${stem}.xcframework`,
+      )
+      .join('\r\n'),
+    outputText: expectedStems
+      .map(
+        (stem, index) =>
+          `\${PODS_XCFRAMEWORKS_BUILD_DIR}/OliphauntReactNativePayload/liboliphaunt_extension_${stem}${index === 0 ? '.framework' : '.a'}`,
+      )
+      .join('\n'),
+  });
+  const expectedArtifacts = expectedStems.map((stem) => `liboliphaunt_extension_${stem}`).sort();
+
+  assert.deepEqual(evidence, {
+    expectedArtifacts,
+    inputArtifacts: expectedArtifacts,
+    missingInput: [],
+    missingOutput: [],
+    outputArtifacts: expectedArtifacts,
+    unexpectedInput: [],
+    unexpectedOutput: [],
+  });
+});
+
+test('does not let prefix collisions or free-text fragments satisfy iOS link identities', () => {
+  const evidence = iosCocoaPodsExtensionLinkEvidence({
+    expectedStems: ['postgis-3', 'uuid-ossp'],
+    inputText: [
+      'note: liboliphaunt_extension_postgis-3.xcframework is not a path component',
+      '${PODS_ROOT}/liboliphaunt_extension_postgis-30.xcframework',
+      '${PODS_ROOT}/liboliphaunt_extension_uuid-ossp-extra.xcframework',
+    ].join('\n'),
+    outputText: [
+      '${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-30.a',
+      '${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_uuid-ossp-extra.a',
+    ].join('\n'),
+  });
+
+  assert.deepEqual(evidence.missingInput, [
+    'liboliphaunt_extension_postgis-3',
+    'liboliphaunt_extension_uuid-ossp',
+  ]);
+  assert.deepEqual(evidence.unexpectedInput, [
+    'liboliphaunt_extension_postgis-30',
+    'liboliphaunt_extension_uuid-ossp-extra',
+  ]);
+  assert.deepEqual(evidence.missingOutput, evidence.missingInput);
+  assert.deepEqual(evidence.unexpectedOutput, evidence.unexpectedInput);
+
+  const inputOnly = iosCocoaPodsExtensionLinkEvidence({
+    expectedStems: ['postgis-3'],
+    inputText: '${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework',
+    outputText: '',
+  });
+  assert.deepEqual(inputOnly.missingInput, []);
+  assert.deepEqual(inputOnly.missingOutput, ['liboliphaunt_extension_postgis-3']);
+
+  const outputOnly = iosCocoaPodsExtensionLinkEvidence({
+    expectedStems: ['postgis-3'],
+    inputText: '',
+    outputText: '${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-3.a',
+  });
+  assert.deepEqual(outputOnly.missingInput, ['liboliphaunt_extension_postgis-3']);
+  assert.deepEqual(outputOnly.missingOutput, []);
+
+  assert.throws(
+    () =>
+      iosCocoaPodsExtensionLinkEvidence({
+        expectedStems: ['postgis-3'],
+        inputText: '${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework.attacker',
+        outputText: '${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-3.a',
+      }),
+    /unsupported Oliphaunt extension artifact component/u,
+  );
+  assert.throws(
+    () =>
+      iosCocoaPodsExtensionLinkEvidence({
+        expectedStems: ['postgis-3'],
+        inputText: [
+          '${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework',
+          '${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework',
+        ].join('\n'),
+        outputText: '${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-3.a',
+      }),
+    /input file list repeats Oliphaunt extension artifact/u,
+  );
+  assert.throws(
+    () =>
+      iosCocoaPodsExtensionLinkEvidence({
+        expectedStems: ['postgis-3'],
+        inputText: '${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework\0',
+        outputText: '${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-3.a',
+      }),
+    /input file list line 1 contains NUL/u,
+  );
+  assert.throws(
+    () =>
+      iosCocoaPodsExtensionLinkEvidence({
+        expectedStems: ['future-name', 'future_name'],
+        inputText: '',
+        outputText: '',
+      }),
+    /collide after registration-symbol normalization/u,
+  );
+});
+
+test('mobile artifact gate uses generated ownership for ancillary extension SQL', () => {
+  for (const [platform, prefix] of [
+    ['Android', 'assets/oliphaunt/'],
+    ['iOS', 'OliphauntReactNativeResources.bundle/oliphaunt/'],
+  ]) {
+    const artifactNames = packagedMobileRuntimeNames(prefix, [
+      'pgtap.control',
+      'pgtap--1.3.5.sql',
+      'pgtap-core--1.3.5.sql',
+      'pgtap-schema.sql',
+      'uninstall_pgtap.sql',
+      'plpgsql.control',
+      'plpgsql--1.0.sql',
+    ]);
+
+    assert.doesNotThrow(() =>
+      validatePackagedMobileRuntimeFiles({
+        artifactNames,
+        metadata: REACT_NATIVE_METADATA,
+        platform,
+        prefix,
+        registry: MOBILE_STATIC_REGISTRY,
+        selected: ['pgtap'],
+      }),
+    );
+    assert.throws(
+      () =>
+        validatePackagedMobileRuntimeFiles({
+          artifactNames: artifactNames.filter((name) => !name.endsWith('/english.stop')),
+          metadata: REACT_NATIVE_METADATA,
+          platform,
+          prefix,
+          registry: MOBILE_STATIC_REGISTRY,
+          selected: ['pgtap'],
+        }),
+      /missing PostgreSQL core Snowball runtime data: .*english[.]stop/u,
+    );
+    assert.throws(
+      () =>
+        validatePackagedMobileRuntimeFiles({
+          artifactNames,
+          metadata: REACT_NATIVE_METADATA,
+          platform,
+          prefix,
+          registry: MOBILE_STATIC_REGISTRY,
+          selected: [],
+        }),
+      /unselected PostgreSQL extension asset/u,
+    );
+  }
+});
+
+test('mobile manifests keep full, createable, and native extension domains distinct', () => {
+  const rows = new Map([
+    [
+      'auto_explain',
+      {
+        'creates-extension': false,
+        'native-module-stem': 'auto_explain',
+        'sql-name': 'auto_explain',
+      },
+    ],
+    [
+      'future_hook',
+      {
+        'creates-extension': false,
+        'native-module-stem': '-',
+        'sql-name': 'future_hook',
+      },
+    ],
+    [
+      'pgtap',
+      {
+        'creates-extension': true,
+        'native-module-stem': '-',
+        'sql-name': 'pgtap',
+      },
+    ],
+  ]);
+  const runtime = {
+    extensions: 'pgtap',
+    mobileStaticRegistryRegistered: 'auto_explain',
+    mobileStaticRegistryPending: '',
+    mobileStaticRegistryState: 'complete',
+    nativeModuleStems: 'auto_explain',
+    selectedExtensions: 'auto_explain,future_hook,pgtap',
+  };
+  const staticRegistry = {
+    modules: 'auto_explain',
+    nativeModuleStems: 'auto_explain',
+    pendingExtensions: '',
+    registeredExtensions: 'auto_explain',
+    state: 'complete',
+  };
+
+  assert.deepEqual(validateMobileExtensionManifestDomains({ runtime, staticRegistry, rows }), {
+    createableExtensions: ['pgtap'],
+    nativeExtensions: ['auto_explain'],
+    nativeModuleStems: ['auto_explain'],
+    selectedExtensions: ['auto_explain', 'future_hook', 'pgtap'],
+  });
+  assert.throws(
+    () =>
+      validateMobileExtensionManifestDomains({
+        runtime: Object.fromEntries(
+          Object.entries(runtime).filter(([key]) => key !== 'selectedExtensions'),
+        ),
+        staticRegistry,
+        rows,
+      }),
+    /must define the full selectedExtensions domain/u,
+  );
+  assert.throws(
+    () =>
+      validateMobileExtensionManifestDomains({
+        runtime: { ...runtime, extensions: 'auto_explain,pgtap' },
+        staticRegistry,
+        rows,
+      }),
+    /createable extensions/u,
+  );
+  assert.throws(
+    () =>
+      validateMobileExtensionManifestDomains({
+        runtime: { ...runtime, mobileStaticRegistryRegistered: 'pgtap' },
+        staticRegistry,
+        rows,
+      }),
+    /registered native extensions/u,
+  );
+  assert.throws(
+    () =>
+      validateMobileExtensionManifestDomains({
+        runtime: { ...runtime, mobileStaticRegistryState: 'not-required' },
+        staticRegistry,
+        rows,
+      }),
+    /mobileStaticRegistryState/u,
+  );
+  assert.throws(
+    () =>
+      validateMobileExtensionManifestDomains({
+        runtime,
+        staticRegistry: { ...staticRegistry, modules: '' },
+        rows,
+      }),
+    /static-registry modules/u,
+  );
+});
diff --git a/src/sdks/react-native/tools/check-package.mts b/src/sdks/react-native/tools/check-package.mts
new file mode 100644
index 000000000..115d9dabd
--- /dev/null
+++ b/src/sdks/react-native/tools/check-package.mts
@@ -0,0 +1,113 @@
+#!/usr/bin/env bun
+import { IOS_CARRIER_FILENAME } from '../../swift/tools/ios-carrier-manifest.mts';
+import {
+  PREFIX,
+  archiveTarNames,
+  fail,
+  inspectSdkProduct,
+  isFile,
+  rejectSdkRuntimePayload,
+  rel,
+  tarReadBytes,
+} from '../../../../tools/packaging/release-carrier.mts';
+import { validateSelectionNeutralSwiftCarrierIdentity } from '../../swift/tools/swift-source-carrier-contract.mts';
+import { readFileSync, readdirSync } from 'node:fs';
+import path from 'node:path';
+import { compareText } from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  SOURCE_ONLY_NPM_PROFILES,
+  assertSourceOnlyNpmArchive,
+} from '../../../../tools/packaging/source-only-sdk-package.mts';
+import { productCompatibilityVersion } from '../../../../tools/release/release-graph.mts';
+
+/**
+ * Prove that the selection-neutral Apple carrier users receive in the React
+ * Native npm package is the exact carrier staged as release evidence.
+ */
+export function validateReactNativePackagedCarrier({
+  artifact,
+  evidence,
+  expectedNativeVersion,
+  memberBytes,
+  names,
+}) {
+  const member = `package/${IOS_CARRIER_FILENAME}`;
+  const matches = names.filter((name) => name === member);
+  if (matches.length !== 1) {
+    throw new Error(`${rel(artifact)} must contain exactly one ${member}; found ${matches.length}`);
+  }
+  if (!Buffer.isBuffer(memberBytes) || !Buffer.isBuffer(evidence)) {
+    throw new TypeError('React Native carrier inputs must be byte buffers');
+  }
+  if (!memberBytes.equals(evidence)) {
+    throw new Error(
+      `${rel(artifact)} ${member} must byte-for-byte match its staged carrier evidence`,
+    );
+  }
+  let carrier;
+  try {
+    carrier = JSON.parse(memberBytes.toString('utf8'));
+  } catch (error) {
+    throw new Error(`${rel(artifact)} ${member} is not valid JSON: ${error.message}`);
+  }
+  return validateSelectionNeutralSwiftCarrierIdentity({
+    carrier,
+    expectedNativeVersion,
+    label: `${rel(artifact)} packaged React Native Apple carrier`,
+  });
+}
+
+export async function checkReactNativePackage(root) {
+  const product = 'oliphaunt-react-native';
+  let checked = false;
+
+  const tarballs = readdirSync(root)
+    .filter((name) => name.endsWith('.tgz'))
+    .map((name) => path.join(root, name))
+    .sort(compareText);
+  if (tarballs.length === 0) {
+    fail(`${product} must stage an npm tarball under ${rel(root)}`);
+  }
+  for (const tarball of tarballs) {
+    const names = archiveTarNames(tarball);
+    rejectSdkRuntimePayload(product, tarball, names);
+    try {
+      assertSourceOnlyNpmArchive(tarball, SOURCE_ONLY_NPM_PROFILES['react-native']);
+    } catch (error) {
+      fail(error instanceof Error ? error.message : String(error));
+    }
+    {
+      const carrierEvidence = path.join(root, 'ios-carriers', IOS_CARRIER_FILENAME);
+      const carrierMember = `package/${IOS_CARRIER_FILENAME}`;
+      if (!isFile(carrierEvidence)) {
+        fail(`${product} must stage selection-neutral carrier evidence at ${rel(carrierEvidence)}`);
+      }
+      if (names.filter((name) => name === carrierMember).length !== 1) {
+        fail(
+          `${rel(tarball)} must contain exactly one ${carrierMember}; found ` +
+            names.filter((name) => name === carrierMember).length,
+        );
+      }
+      try {
+        validateReactNativePackagedCarrier({
+          artifact: tarball,
+          evidence: readFileSync(carrierEvidence),
+          expectedNativeVersion: productCompatibilityVersion(
+            'oliphaunt-swift',
+            'liboliphaunt-native',
+            PREFIX,
+          ),
+          memberBytes: tarReadBytes(tarball, carrierMember),
+          names,
+        });
+      } catch (error) {
+        fail(error instanceof Error ? error.message : String(error));
+      }
+    }
+    checked = true;
+  }
+
+  return checked;
+}
+
+if (import.meta.main) await inspectSdkProduct('oliphaunt-react-native', checkReactNativePackage);
diff --git a/src/sdks/react-native/tools/check-package.test.mts b/src/sdks/react-native/tools/check-package.test.mts
new file mode 100644
index 000000000..1127eb836
--- /dev/null
+++ b/src/sdks/react-native/tools/check-package.test.mts
@@ -0,0 +1,89 @@
+import test from 'node:test';
+import { iosBaseLegalMetadata } from '../../swift/tools/ios-carrier-manifest.mts';
+import assert from 'node:assert/strict';
+import { validateReactNativePackagedCarrier } from './check-package.mts';
+
+function selectionNeutralCarrier(version = '1.2.3') {
+  const product = 'liboliphaunt-native';
+  const tag = `${product}-v${version}`;
+  const assets = [
+    [
+      'base-xcframework',
+      `liboliphaunt-${version}-apple-spm-xcframework.zip`,
+      'zip',
+      'liboliphaunt.xcframework',
+      'a',
+    ],
+    [
+      'runtime-resources',
+      `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`,
+      'tar.gz',
+      'oliphaunt',
+      'b',
+    ],
+  ].map(([role, name, format, member, digit], index) => ({
+    bytes: index + 1,
+    format,
+    member,
+    name,
+    role,
+    sha256: digit.repeat(64),
+    url: `https://github.com/f0rr0/oliphaunt/releases/download/${tag}/${name}`,
+  }));
+  return {
+    base: { assets, product, tag, version },
+    carriers: [],
+    extensions: [],
+    legal: { base: iosBaseLegalMetadata(), extensions: [] },
+    schema: 'oliphaunt-react-native-ios-carrier-v1',
+  };
+}
+
+test('binds the React Native npm carrier bytes to selection-neutral staged evidence', () => {
+  const member = 'package/oliphaunt-react-native-ios-carriers.json';
+  const bytes = Buffer.from(`${JSON.stringify(selectionNeutralCarrier(), null, 2)}\n`);
+  assert.deepEqual(
+    validateReactNativePackagedCarrier({
+      artifact: 'oliphaunt-react-native.tgz',
+      evidence: bytes,
+      expectedNativeVersion: '1.2.3',
+      memberBytes: bytes,
+      names: [member],
+    }),
+    selectionNeutralCarrier(),
+  );
+
+  assert.throws(
+    () =>
+      validateReactNativePackagedCarrier({
+        artifact: 'missing.tgz',
+        evidence: bytes,
+        expectedNativeVersion: '1.2.3',
+        memberBytes: Buffer.alloc(0),
+        names: [],
+      }),
+    /must contain exactly one/u,
+  );
+  assert.throws(
+    () =>
+      validateReactNativePackagedCarrier({
+        artifact: 'skewed.tgz',
+        evidence: bytes,
+        expectedNativeVersion: '1.2.3',
+        memberBytes: Buffer.from(`${JSON.stringify(selectionNeutralCarrier('1.2.4'))}\n`),
+        names: [member],
+      }),
+    /byte-for-byte match/u,
+  );
+  assert.throws(
+    () =>
+      validateReactNativePackagedCarrier({
+        artifact: 'wrong-version.tgz',
+        evidence: Buffer.from(`${JSON.stringify(selectionNeutralCarrier('1.2.4'))}\n`),
+        expectedNativeVersion: '1.2.3',
+        memberBytes: Buffer.from(`${JSON.stringify(selectionNeutralCarrier('1.2.4'))}\n`),
+        names: [member],
+      }),
+    /must match liboliphaunt-native 1\.2\.3/u,
+  );
+});
diff --git a/src/sdks/react-native/tools/codegen-check.cjs b/src/sdks/react-native/tools/codegen-check.cjs
deleted file mode 100644
index ff362ba1c..000000000
--- a/src/sdks/react-native/tools/codegen-check.cjs
+++ /dev/null
@@ -1,13 +0,0 @@
-const path = require("node:path");
-const { createRequire } = require("node:module");
-
-const requireFromPackage = createRequire(path.join(process.cwd(), "package.json"));
-const codegenPackageJson = requireFromPackage.resolve("@react-native/codegen/package.json");
-const codegenRoot = path.dirname(codegenPackageJson);
-const cliPath = path.join(
-  codegenRoot,
-  "lib/cli/combine/combine-js-to-schema-cli.js",
-);
-
-process.argv = [process.execPath, cliPath, ...process.argv.slice(2)];
-require(cliPath);
diff --git a/src/sdks/react-native/tools/codegen-check.cts b/src/sdks/react-native/tools/codegen-check.cts
new file mode 100644
index 000000000..15e09b9d2
--- /dev/null
+++ b/src/sdks/react-native/tools/codegen-check.cts
@@ -0,0 +1,10 @@
+const path = require('node:path');
+const { createRequire } = require('node:module');
+
+const requireFromPackage = createRequire(path.join(process.cwd(), 'package.json'));
+const codegenPackageJson = requireFromPackage.resolve('@react-native/codegen/package.json');
+const codegenRoot = path.dirname(codegenPackageJson);
+const cliPath = path.join(codegenRoot, 'lib/cli/combine/combine-js-to-schema-cli.js');
+
+process.argv = [process.execPath, cliPath, ...process.argv.slice(2)];
+require(cliPath);
diff --git a/tools/integration/react-native/expo-android-gradle-limits.test.sh b/src/sdks/react-native/tools/expo-android-gradle-limits.test.sh
similarity index 100%
rename from tools/integration/react-native/expo-android-gradle-limits.test.sh
rename to src/sdks/react-native/tools/expo-android-gradle-limits.test.sh
diff --git a/src/sdks/react-native/tools/expo-android-runner.sh b/src/sdks/react-native/tools/expo-android-runner.sh
index 0a1f08945..16b08e912 100755
--- a/src/sdks/react-native/tools/expo-android-runner.sh
+++ b/src/sdks/react-native/tools/expo-android-runner.sh
@@ -7,7 +7,7 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
   exit 1
 }
 cd "$root"
-. "$root/src/runtimes/liboliphaunt/native/bin/build-output.bash"
+. "$root/src/runtimes/liboliphaunt-native/bin/build-output.bash"
 . "$root/src/sdks/react-native/tools/expo-runner-common.sh"
 . "$root/src/sdks/react-native/tools/expo-android-gradle-limits.sh"
 . "$root/src/sdks/react-native/tools/expo-runner-metro.sh"
@@ -17,7 +17,7 @@ cd "$root"
 . "$root/src/sdks/react-native/tools/expo-runner-runtime-resources.sh"
 . "$root/src/sdks/react-native/tools/expo-runner-android-device.sh"
 
-source_example_dir="$root/examples/react-native-expo"
+source_example_dir="$root/src/examples/react-native-expo"
 rn_dir="$root/src/sdks/react-native"
 mobile_platform="android"
 scratch_workspace_name="oliphaunt-react-native-expo-android-workspace"
@@ -40,7 +40,7 @@ elif [ "$runner" = "crash" ]; then
   failure_tag="OLIPHAUNT_EXPO_CRASH_RECOVERY_FAIL"
 fi
 scratch_root="${OLIPHAUNT_EXPO_ANDROID_SCRATCH:-$root/target/oliphaunt-expo-android-$runner}"
-example_dir="${OLIPHAUNT_EXPO_ANDROID_EXAMPLE_DIR:-$scratch_root/examples/react-native-expo}"
+example_dir="${OLIPHAUNT_EXPO_ANDROID_EXAMPLE_DIR:-$scratch_root/src/examples/react-native-expo}"
 package_work="$scratch_root/src/sdks/react-native"
 crash_storage_suffix="$(printf '%s' "$(basename "$scratch_root")" | LC_ALL=C tr -c 'A-Za-z0-9_.-' '-')"
 [ -n "$crash_storage_suffix" ] || crash_storage_suffix="run"
@@ -105,7 +105,6 @@ startup_gucs="${OLIPHAUNT_EXPO_ANDROID_STARTUP_GUCS:-${OLIPHAUNT_EXPO_MOBILE_STA
 benchmark_preset="${OLIPHAUNT_EXPO_ANDROID_BENCHMARK_PRESET:-${OLIPHAUNT_EXPO_MOBILE_BENCHMARK_PRESET:-full}}"
 crash_storage_override="${OLIPHAUNT_EXPO_ANDROID_CRASH_STORAGE:-}"
 crash_storage="${crash_storage_override:-/data/data/$app_id/files/oliphaunt-crash-recovery-storage-$crash_storage_suffix}"
-mobile_packaging_initdb="${OLIPHAUNT_EXPO_ANDROID_INITDB:-}"
 case "${OLIPHAUNT_EXPO_ANDROID_ICU:-0}" in
   1|true|TRUE|yes|YES|on|ON) android_icu_enabled=1 ;;
   0|false|FALSE|no|NO|off|OFF) android_icu_enabled=0 ;;
@@ -214,8 +213,8 @@ android_build_root_for_abi() {
 
 android_build_script_for_abi() {
   case "$android_abi" in
-    arm64-v8a) printf '%s\n' "$root/src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh" ;;
-    x86_64) printf '%s\n' "$root/src/runtimes/liboliphaunt/native/bin/build-postgres18-android-x86_64.sh" ;;
+    arm64-v8a) printf '%s\n' "$root/src/runtimes/liboliphaunt-native/bin/build-postgres18-android-arm64.sh" ;;
+    x86_64) printf '%s\n' "$root/src/runtimes/liboliphaunt-native/bin/build-postgres18-android-x86_64.sh" ;;
     *) fail "unsupported Android ABI: $android_abi" ;;
   esac
 }
@@ -265,7 +264,7 @@ pack_react_native_sdk_if_needed() {
     return
   fi
 
-  need_cmd pnpm
+  need_cmd bun
   mkdir -p "$pack_dir"
 
   local package_stamp="$pack_dir/.android-package-inputs.sha256"
@@ -280,12 +279,12 @@ pack_react_native_sdk_if_needed() {
 
   if [ "$needs_pack" -eq 1 ]; then
     prepare_react_native_package_worktree
-    run pnpm --dir "$package_work" run build
+    run bun run --cwd "$package_work" build
     echo
-    echo "==> (cd $package_work && pnpm pack --pack-destination $pack_dir)"
+    echo "==> (cd $package_work && bun pm pack --destination $pack_dir)"
     (
       cd "$package_work"
-      pnpm pack --pack-destination "$pack_dir"
+      bun pm pack --destination "$pack_dir"
     )
     printf '%s\n' "$package_fingerprint" >"$package_stamp"
   else
@@ -315,7 +314,7 @@ ensure_android_project() {
   echo "Generating Expo Android project for smoke validation"
   (
     cd "$example_dir"
-    CI=1 EXPO_NO_TELEMETRY=1 pnpm exec expo prebuild --platform android
+    CI=1 EXPO_NO_TELEMETRY=1 bun x --no-install expo prebuild --platform android
   )
 }
 
@@ -345,8 +344,8 @@ find_android_liboliphaunt_so() {
       "$scratch_root/logs/build-android-$android_abi.log" \
       env ANDROID_HOME="$ANDROID_HOME" OLIPHAUNT_ANDROID_ABI="$android_abi" OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$static_extensions" "$(android_build_script_for_abi)")"
   fi
-  if [ -z "$source_so" ] && [ -f "$root/target/liboliphaunt-android-jni-smoke/$android_abi/liboliphaunt.so" ]; then
-    source_so="$root/target/liboliphaunt-android-jni-smoke/$android_abi/liboliphaunt.so"
+  if [ -z "$source_so" ] && [ -f "$root/target/liboliphaunt-android-jni-smoke$android_abi/liboliphaunt.so" ]; then
+    source_so="$root/target/liboliphaunt-android-jni-smoke$android_abi/liboliphaunt.so"
   fi
   if [ -z "$source_so" ] && [ -x "$(android_build_script_for_abi)" ]; then
     expo_allows_native_builds ||
@@ -421,23 +420,22 @@ prepare_runtime_resources() {
     android_runtime_source="$(android_build_root_for_abi)/install"
     if [ -f "$root/target/liboliphaunt-android-runtime-smoke/share/postgresql/postgres.bki" ]; then
       runtime_source="$root/target/liboliphaunt-android-runtime-smoke"
-    elif [ -f "$android_runtime_source/share/postgresql/postgres.bki" ]; then
-      runtime_source="$android_runtime_source"
     else
-      runtime_source="$(ensure_host_runtime_assets)"
+      runtime_source="$android_runtime_source"
     fi
   fi
-  [ -f "$runtime_source/share/postgresql/postgres.bki" ] ||
-    fail "runtime assets are missing postgres.bki: $runtime_source"
-  ensure_mobile_runtime_tool_permissions "$runtime_source"
-  ensure_mobile_tool_executable "$mobile_packaging_initdb"
+  require_mobile_runtime_data "$runtime_source" OLIPHAUNT_EXPO_ANDROID_RUNTIME_DIR \
+    "liboliphaunt-native:build-runtime-android-$android_abi"
 
-  local seed_closure
-  seed_closure="$(
-    require_mobile_runtime_seed_closure \
+  local seed seed_profile=standard
+  [ "$android_icu_enabled" != 1 ] || seed_profile=icu
+  seed="$(
+    require_mobile_seed \
       Android \
-      "${OLIPHAUNT_EXPO_ANDROID_SEED_CLOSURE_DIR:-}" \
-      OLIPHAUNT_EXPO_ANDROID_SEED_CLOSURE_DIR
+      "${OLIPHAUNT_EXPO_ANDROID_SEED_DIR:-}" \
+      OLIPHAUNT_EXPO_ANDROID_SEED_DIR \
+      "$seed_profile" \
+      "$android_icu_data_dir"
   )"
   local selected_extensions
   selected_extensions="$(normalize_mobile_extensions)"
@@ -452,13 +450,12 @@ prepare_runtime_resources() {
   if prepared_package="$(oliphaunt_dev_prepare_prebuilt_mobile_runtime_resource_package \
     Android \
     "$runtime_source" \
-    "$mobile_packaging_initdb" \
     "$selected_extensions" \
     "$package_root" \
     "$android_icu_enabled" \
     "$android_icu_data_dir")"; then
-    install_mobile_runtime_seed_closure "$prepared_package" "$seed_closure"
-    bind_mobile_runtime_manifest_to_seed_closure "$prepared_package" "$seed_closure"
+    install_mobile_seed "$prepared_package" "$seed"
+    bind_mobile_runtime_manifest_to_seed "$prepared_package" "$seed"
     assert_android_icu_payload \
       "$prepared_package/oliphaunt/runtime/manifest.properties" \
       "$prepared_package/oliphaunt/runtime/files/share/icu" \
@@ -472,7 +469,7 @@ prepare_runtime_resources() {
   prepared_package="$(prepare_mobile_runtime_resource_package \
     Android \
     "$runtime_source" \
-    "$seed_closure" \
+    "$seed" \
     "$static_registry_source" \
     "$selected_extensions" \
     "${OLIPHAUNT_EXPO_ANDROID_REPACKAGE_ASSETS:-0}" \
@@ -566,7 +563,7 @@ build_apk() {
     local gradle_jvmargs gradle_max_workers node_binary
     gradle_jvmargs="$(oliphaunt_android_gradle_jvmargs)"
     gradle_max_workers="$(oliphaunt_android_gradle_max_workers)"
-    node_binary="$(node -p 'process.execPath')"
+    node_binary="$(node "$root/tools/dev/node-info.mts" executable)"
     local selected_extensions extension_archives_root kotlin_sdk_aar android_link_evidence module_stems
     selected_extensions="$(normalize_mobile_extensions)"
     module_stems="$(oliphaunt_dev_mobile_module_stems_for_selection "$selected_extensions")"
@@ -614,7 +611,7 @@ build_apk() {
       fail "Android build did not emit static extension link evidence: $android_link_evidence"
     fi
     if [ -n "$module_stems" ]; then
-      run node "$root/src/sdks/react-native/tools/validate-android-link-evidence.mjs" \
+      run bun "$root/src/sdks/react-native/tools/validate-android-link-evidence.mts" \
         --evidence "$android_link_evidence" \
         --abi "$android_abi" \
         --module-stems "$module_stems" \
@@ -631,10 +628,10 @@ build_apk() {
     fail "APK is missing lib/$android_abi/liboliphaunt.so"
   grep -Fxq "assets/oliphaunt/runtime/manifest.properties" "$apk_files" ||
     fail "APK is missing Oliphaunt runtime manifest"
-  grep -Fxq "assets/oliphaunt/cluster-seed/manifest.properties" "$apk_files" ||
+  local selected_seed=cluster-seed
+  [ "$android_icu_enabled" != 1 ] || selected_seed=cluster-seed-icu
+  grep -Fxq "assets/oliphaunt/$selected_seed/manifest.properties" "$apk_files" ||
     fail "APK is missing liboliphaunt template manifest"
-  grep -Fxq "assets/oliphaunt/package-size.tsv" "$apk_files" ||
-    fail "APK is missing Oliphaunt package-size report"
   local selected_extensions
   selected_extensions="$(normalize_mobile_extensions)"
   oliphaunt_dev_assert_runtime_file_list "$selected_extensions" "Android" <"$apk_files"
@@ -685,7 +682,7 @@ start_metro_if_needed() {
       EXPO_PUBLIC_OLIPHAUNT_BENCHMARK_PRESET="$benchmark_preset" \
       EXPO_PUBLIC_OLIPHAUNT_STARTUP_GUCS="$startup_gucs" \
       EXPO_PUBLIC_OLIPHAUNT_STORAGE_DIRECTORY="$bundle_storage" \
-      pnpm exec expo start --dev-client --port "$metro_port" --clear \
+      bun x --no-install expo start --dev-client --port "$metro_port" --clear \
       >"$scratch_root/metro.log" 2>&1
   ) &
   metro_pid="$!"
diff --git a/src/sdks/react-native/tools/expo-ios-runner.mts b/src/sdks/react-native/tools/expo-ios-runner.mts
new file mode 100644
index 000000000..6ee133542
--- /dev/null
+++ b/src/sdks/react-native/tools/expo-ios-runner.mts
@@ -0,0 +1,116 @@
+import * as fs from 'node:fs';
+import * as path from 'node:path';
+
+const [command, ...args] = process.argv.slice(2);
+switch (command) {
+  case 'configure-resource-dependencies': {
+    const [workspaceFile, exampleFile, ...archives] = args;
+    const { readPortableArchiveEntries } = await import(
+      '../../../../tools/packaging/portable-archive.mts'
+    );
+    const candidates = archives.map((archive) => {
+      const entry = readPortableArchiveEntries(archive).get('package/package.json');
+      if (!entry?.isFile || entry.isSymbolicLink)
+        throw new Error(`missing package manifest: ${archive}`);
+      return {
+        ...JSON.parse(Buffer.from(entry.data()).toString('utf8')),
+        archive: path.resolve(archive),
+      };
+    });
+    const [seed, icu] = candidates;
+    if (
+      !/^@oliphaunt\/seed-native-ios-datum64-(standard|icu)$/.test(seed?.name ?? '') ||
+      candidates.length !== (seed.name.endsWith('-icu') ? 2 : 1)
+    ) {
+      throw new Error('iOS requires exactly the selected seed and its optional ICU carrier');
+    }
+    if (
+      icu &&
+      (icu.name !== '@oliphaunt/icu' ||
+        !Bun.semver.satisfies(icu.version, seed.dependencies?.['@oliphaunt/icu'] ?? ''))
+    ) {
+      throw new Error('ICU candidate does not satisfy the selected seed dependency');
+    }
+    const workspace = JSON.parse(fs.readFileSync(workspaceFile, 'utf8'));
+    const example =
+      path.resolve(workspaceFile) === path.resolve(exampleFile)
+        ? workspace
+        : JSON.parse(fs.readFileSync(exampleFile, 'utf8'));
+    workspace.overrides ??= {};
+    example.dependencies ??= {};
+    for (const name of [
+      '@oliphaunt/icu',
+      '@oliphaunt/seed-native-ios-datum64-standard',
+      '@oliphaunt/seed-native-ios-datum64-icu',
+    ]) {
+      delete workspace.overrides[name];
+      delete example.dependencies[name];
+    }
+    for (const candidate of candidates) {
+      const spec = `file:${candidate.archive}`;
+      workspace.overrides[candidate.name] = spec;
+      example.dependencies[candidate.name] = spec;
+    }
+    fs.writeFileSync(workspaceFile, `${JSON.stringify(workspace, null, 2)}\n`);
+    fs.writeFileSync(exampleFile, `${JSON.stringify(example, null, 2)}\n`);
+    break;
+  }
+  case 'configure-plugin': {
+    const file = args[0];
+    const extensions = args[1]
+      .split(',')
+      .map((value) => value.trim())
+      .filter(Boolean);
+    const icu = ['1', 'true', 'yes'].includes(args[2].toLowerCase());
+    const value = JSON.parse(fs.readFileSync(file, 'utf8'));
+    const plugins = Array.isArray(value.expo?.plugins) ? value.expo.plugins : [];
+    value.expo.plugins = plugins.filter((entry) => {
+      const name = Array.isArray(entry) ? entry[0] : entry;
+      return name !== '@oliphaunt/react-native';
+    });
+    value.expo.plugins.push([
+      '@oliphaunt/react-native',
+      { extensions, icu, seedProfile: icu ? 'icu' : 'standard' },
+    ]);
+    fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
+    break;
+  }
+  case 'validate-pod-source': {
+    const [lockfile, expectedRoot] = args;
+    const document = Bun.YAML.parse(fs.readFileSync(lockfile, 'utf8'));
+    const sources = document?.['EXTERNAL SOURCES'];
+    const payload = sources?.OliphauntReactNativePayload;
+    if (
+      !payload ||
+      typeof payload !== 'object' ||
+      Array.isArray(payload) ||
+      typeof payload[':path'] !== 'string' ||
+      !payload[':path']
+    )
+      throw new Error('OliphauntReactNativePayload must be an app-owned path pod');
+    if (
+      [':git', ':http', ':tag', ':branch', ':commit', ':podspec'].some((key) =>
+        Object.hasOwn(payload, key),
+      )
+    )
+      throw new Error('app-owned payload must not declare a remote or podspec source');
+    if (path.resolve(path.dirname(lockfile), payload[':path']) !== path.resolve(expectedRoot))
+      throw new Error('app-owned payload resolved to the wrong directory');
+    break;
+  }
+  case 'patch-weak-references': {
+    for (const entry of fs.readdirSync(args[0], { recursive: true, withFileTypes: true })) {
+      if (!entry.isFile() || !entry.name.endsWith('.swift')) continue;
+      const file = path.join(entry.parentPath, entry.name);
+      const before = fs.readFileSync(file, 'utf8');
+      const after = before.replace(
+        /\b(nonisolated\(unsafe\)\s+)?weak\s+(let|var)\b/g,
+        'nonisolated(unsafe) weak var',
+      );
+      if (after !== before) fs.writeFileSync(file, after);
+    }
+    break;
+  }
+  default:
+    throw Error('unknown iOS runner data command: ' + command);
+}
diff --git a/src/sdks/react-native/tools/expo-ios-runner.sh b/src/sdks/react-native/tools/expo-ios-runner.sh
index 5762518f0..129a6b450 100755
--- a/src/sdks/react-native/tools/expo-ios-runner.sh
+++ b/src/sdks/react-native/tools/expo-ios-runner.sh
@@ -7,7 +7,7 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
   exit 1
 }
 cd "$root"
-. "$root/src/runtimes/liboliphaunt/native/bin/build-output.bash"
+. "$root/src/runtimes/liboliphaunt-native/bin/build-output.bash"
 . "$root/src/sdks/react-native/tools/expo-runner-common.sh"
 . "$root/src/sdks/react-native/tools/expo-runner-metro.sh"
 . "$root/src/sdks/react-native/tools/expo-runner-reporting.sh"
@@ -17,14 +17,13 @@ cd "$root"
 . "$root/src/sdks/react-native/tools/expo-runner-ios-device.sh"
 . "$root/src/sdks/react-native/tools/expo-runner-ios-installed-app.sh"
 
-source_example_dir="$root/examples/react-native-expo"
+source_example_dir="$root/src/examples/react-native-expo"
 rn_dir="$root/src/sdks/react-native"
 mobile_platform="ios"
 scratch_workspace_name="oliphaunt-react-native-expo-ios-workspace"
 runner="${OLIPHAUNT_EXPO_IOS_RUNNER:-smoke}"
 case "$runner" in
-  smoke|benchmark|crash)
-    ;;
+  smoke | benchmark | crash) ;;
   *)
     echo "error: OLIPHAUNT_EXPO_IOS_RUNNER must be smoke, benchmark, or crash, got $runner" >&2
     exit 1
@@ -40,7 +39,7 @@ elif [ "$runner" = "crash" ]; then
   failure_tag="OLIPHAUNT_EXPO_CRASH_RECOVERY_FAIL"
 fi
 scratch_root="${OLIPHAUNT_EXPO_IOS_SCRATCH:-$root/target/oliphaunt-expo-ios-$runner}"
-example_dir="${OLIPHAUNT_EXPO_IOS_EXAMPLE_DIR:-$scratch_root/examples/react-native-expo}"
+example_dir="${OLIPHAUNT_EXPO_IOS_EXAMPLE_DIR:-$scratch_root/src/examples/react-native-expo}"
 crash_storage_suffix="$(printf '%s' "$(basename "$scratch_root")" | LC_ALL=C tr -c 'A-Za-z0-9_.-' '-')"
 [ -n "$crash_storage_suffix" ] || crash_storage_suffix="run"
 package_work="$scratch_root/src/sdks/react-native"
@@ -71,8 +70,7 @@ clean_simulator_install="${OLIPHAUNT_EXPO_IOS_CLEAN_INSTALL:-1}"
 e2e_only="${OLIPHAUNT_EXPO_IOS_E2E_ONLY:-0}"
 e2e_assertion_runner="${OLIPHAUNT_EXPO_IOS_E2E_ASSERTION_RUNNER:-${OLIPHAUNT_MOBILE_E2E_ASSERTION_RUNNER:-log}}"
 case "$e2e_assertion_runner" in
-  auto|log|maestro)
-    ;;
+  auto | log | maestro) ;;
   *)
     echo "error: OLIPHAUNT_EXPO_IOS_E2E_ASSERTION_RUNNER must be auto, log, or maestro, got $e2e_assertion_runner" >&2
     exit 1
@@ -110,7 +108,6 @@ fi
 startup_gucs="${OLIPHAUNT_EXPO_IOS_STARTUP_GUCS:-${OLIPHAUNT_EXPO_MOBILE_STARTUP_GUCS:-}}"
 benchmark_preset="${OLIPHAUNT_EXPO_IOS_BENCHMARK_PRESET:-${OLIPHAUNT_EXPO_MOBILE_BENCHMARK_PRESET:-full}}"
 crash_storage_override="${OLIPHAUNT_EXPO_IOS_CRASH_STORAGE:-}"
-mobile_packaging_initdb="${OLIPHAUNT_EXPO_IOS_INITDB:-}"
 if is_truthy "${OLIPHAUNT_EXPO_IOS_ICU:-0}"; then
   configure_mobile_catalog_profile_probe icu
 else
@@ -132,7 +129,7 @@ is_physical_ios_launch() {
 
 is_ios_debug_configuration() {
   case "$configuration" in
-    Debug|debug|DEBUG)
+    Debug | debug | DEBUG)
       return 0
       ;;
     *)
@@ -189,23 +186,22 @@ prepare_runtime_resources() {
   if [ -z "$runtime_source" ]; then
     if [ -f "$root/target/liboliphaunt-ios-runtime-smoke/share/postgresql/postgres.bki" ]; then
       runtime_source="$root/target/liboliphaunt-ios-runtime-smoke"
-    elif [ -f "$root/target/liboliphaunt-ios-simulator/install/share/postgresql/postgres.bki" ]; then
-      runtime_source="$root/target/liboliphaunt-ios-simulator/install"
     else
-      runtime_source="$(ensure_host_runtime_assets)"
+      runtime_source="$root/target/liboliphaunt-ios-simulator/install"
     fi
   fi
-  [ -f "$runtime_source/share/postgresql/postgres.bki" ] ||
-    fail "runtime assets are missing postgres.bki: $runtime_source"
-  ensure_mobile_runtime_tool_permissions "$runtime_source"
-  ensure_mobile_tool_executable "$mobile_packaging_initdb"
+  require_mobile_runtime_data "$runtime_source" OLIPHAUNT_EXPO_IOS_RUNTIME_DIR \
+    liboliphaunt-native:build-runtime-ios-xcframework
 
-  local seed_closure
-  seed_closure="$(
-    require_mobile_runtime_seed_closure \
+  local seed seed_profile=standard
+  [ "${OLIPHAUNT_EXPO_IOS_ICU:-0}" != 1 ] || seed_profile=icu
+  seed="$(
+    require_mobile_seed \
       iOS \
-      "${OLIPHAUNT_EXPO_IOS_SEED_CLOSURE_DIR:-}" \
-      OLIPHAUNT_EXPO_IOS_SEED_CLOSURE_DIR
+      "${OLIPHAUNT_EXPO_IOS_SEED_DIR:-}" \
+      OLIPHAUNT_EXPO_IOS_SEED_DIR \
+      "$seed_profile" \
+      "${OLIPHAUNT_IOS_ICU_DATA_DIR:-}"
   )"
   local selected_extensions
   selected_extensions="$(normalize_mobile_extensions)"
@@ -213,17 +209,19 @@ prepare_runtime_resources() {
   if oliphaunt_dev_prepare_prebuilt_mobile_runtime_resource_package \
     iOS \
     "$runtime_source" \
-    "$mobile_packaging_initdb" \
     "$selected_extensions" \
-    "$package_root"; then
-    install_mobile_runtime_seed_closure "$package_root" "$seed_closure"
-    bind_mobile_runtime_manifest_to_seed_closure "$package_root" "$seed_closure"
+    "$package_root" \
+    "${OLIPHAUNT_EXPO_IOS_ICU:-0}" \
+    "${OLIPHAUNT_IOS_ICU_DATA_DIR:-}"; then
+    install_mobile_seed "$package_root" "$seed"
+    bind_mobile_runtime_manifest_to_seed "$package_root" "$seed"
     return 0
   fi
+  [ "$seed_profile" != icu ] || fail "selected iOS ICU data could not be staged by the runtime resource packager"
   prepare_mobile_runtime_resource_package \
     iOS \
     "$runtime_source" \
-    "$seed_closure" \
+    "$seed" \
     "$static_registry_source" \
     "$selected_extensions" \
     "${OLIPHAUNT_EXPO_IOS_REPACKAGE_ASSETS:-0}" \
@@ -243,7 +241,7 @@ find_ios_library_artifact() {
     artifact="$(oliphaunt_capture_build_artifact_path \
       "iOS simulator liboliphaunt build" \
       "$scratch_root/logs/build-ios-simulator.log" \
-      env OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$static_extensions" src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh)"
+      env OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$static_extensions" src/runtimes/liboliphaunt-native/bin/build-postgres18-ios-simulator.sh)"
   fi
   [ -n "$artifact" ] ||
     fail "missing iOS liboliphaunt artifact; set OLIPHAUNT_EXPO_IOS_OLIPHAUNT_XCFRAMEWORK, OLIPHAUNT_EXPO_IOS_OLIPHAUNT_FRAMEWORK, or OLIPHAUNT_EXPO_IOS_OLIPHAUNT_DYLIB. macOS dylibs are not accepted."
@@ -273,8 +271,7 @@ validate_ios_library_artifact() {
       local platform
       platform="$(xcrun vtool -show-build "$artifact" 2>/dev/null | awk '/platform /{print $2; exit}')"
       case "$sdk:$platform" in
-        iphonesimulator:IOSSIMULATOR|iphoneos:IOS)
-          ;;
+        iphonesimulator:IOSSIMULATOR | iphoneos:IOS) ;;
         *:MACOS)
           fail "refusing macOS liboliphaunt.dylib for iOS smoke: $artifact"
           ;;
@@ -353,6 +350,29 @@ validate_ios_static_extension_linkage() {
   fi
 }
 
+install_ios_resource_carriers() {
+  local profile=standard version seed_archive icu_archive
+  if is_truthy "${OLIPHAUNT_EXPO_IOS_ICU:-0}"; then profile=icu; fi
+  version="$(tr -d '\r\n' <"$root/src/database-resources/VERSION")"
+  seed_archive="$root/target/database-resources/seed-carriers/npm/oliphaunt-seed-native-ios-datum64-$profile/oliphaunt-seed-native-ios-datum64-$profile-$version.tgz"
+  [ -f "$seed_archive" ] ||
+    fail "missing iOS $profile seed npm carrier; run moon run database-resources:package-ios"
+  local packages=("$seed_archive")
+  if [ "$profile" = icu ]; then
+    icu_archive="$root/target/release/npm-packages/oliphaunt-icu/oliphaunt-icu-$version.tgz"
+    [ -f "$icu_archive" ] ||
+      fail "missing ICU npm carrier; run moon run database-resources:package-icu"
+    packages+=("$icu_archive")
+  fi
+  local workspace_manifest="$example_dir/package.json"
+  if [ "$example_dir" = "$scratch_root/src/examples/react-native-expo" ]; then
+    workspace_manifest="$scratch_root/package.json"
+  fi
+  bun "$root/src/sdks/react-native/tools/expo-ios-runner.mts" configure-resource-dependencies \
+    "$workspace_manifest" "$example_dir/package.json" "${packages[@]}"
+  install_expo_example_dependencies
+}
+
 install_react_native_sdk_tarball() {
   patch_expo_example_react_native_dependency "file:$tarball"
   rm -rf "$example_dir/node_modules/@oliphaunt/react-native"
@@ -360,7 +380,7 @@ install_react_native_sdk_tarball() {
 }
 
 install_react_native_sdk_from_source_for_reuse() {
-  need_cmd pnpm
+  need_cmd bun
   patch_expo_example_react_native_dependency "file:$rn_dir"
   rm -rf "$example_dir/node_modules/@oliphaunt/react-native"
   install_expo_example_dependencies
@@ -384,7 +404,7 @@ verify_installed_ios_package() {
 }
 
 pack_react_native_sdk() {
-  need_cmd pnpm
+  need_cmd bun
   mkdir -p "$pack_dir" "$scratch_root"
 
   if expo_requires_sdk_artifacts; then
@@ -412,12 +432,12 @@ pack_react_native_sdk() {
   fi
 
   prepare_react_native_package_worktree
-  run pnpm --dir "$package_work" run build
+  run bun run --cwd "$package_work" build
   echo
-  echo "==> (cd $package_work && pnpm pack --pack-destination $pack_dir)"
+  echo "==> (cd $package_work && bun pm pack --destination $pack_dir)"
   (
     cd "$package_work"
-    pnpm pack --pack-destination "$pack_dir"
+    bun pm pack --destination "$pack_dir"
   )
   install_react_native_sdk_tarball
   local installed_package="$example_dir/node_modules/@oliphaunt/react-native"
@@ -440,7 +460,7 @@ prepare_swift_sdk_artifact_git_repo_if_required() {
   source_root="$artifact_repo/src/sdks/swift"
   rm -rf "$artifact_repo" "$extract_root"
   mkdir -p "$source_root"
-  node "$root/src/sdks/swift/tools/extract-verified-zip.mjs" \
+  bun "$root/src/sdks/swift/tools/extract-verified-zip.mts" \
     --archive "$archive" \
     --destination "$extract_root"
   package_archive_root="$extract_root"
@@ -462,9 +482,15 @@ prepare_swift_sdk_artifact_git_repo_if_required() {
   cp -R "$package_archive_root/." "$source_root/"
   [ -f "$source_root/Sources/Oliphaunt/Oliphaunt.swift" ] ||
     fail "Swift SDK source artifact did not unpack to Sources/Oliphaunt/Oliphaunt.swift: $archive"
-  if [ -f "$(expo_sdk_artifact_product_root oliphaunt-swift)/Package.swift.release" ]; then
-    cp "$(expo_sdk_artifact_product_root oliphaunt-swift)/Package.swift.release" "$artifact_repo/Package.swift"
-  fi
+  local swift_version bindings_archive
+  swift_version="$(cat "$source_root/VERSION")"
+  bindings_archive="$(expo_sdk_artifact_product_root oliphaunt-swift)/release-assets/oliphaunt-swift-$swift_version-bindings.xcframework.zip"
+  [ -s "$bindings_archive" ] || fail "Swift SDK bindings artifact is missing: $bindings_archive"
+  mkdir -p "$artifact_repo/Artifacts"
+  cp "$bindings_archive" "$artifact_repo/Artifacts/"
+  cp "$(expo_sdk_artifact_product_root oliphaunt-swift)/Package.swift.release" "$artifact_repo/Package.swift"
+  [ -s "$source_root/Sources/OliphauntNativeBindings/OliphauntNativeBindings.swift" ] ||
+    fail "Swift SDK source artifact is missing generated native bindings"
   (
     cd "$artifact_repo"
     git init -q
@@ -481,6 +507,7 @@ prepare_swift_sdk_artifact_git_repo_if_required() {
 }
 
 configure_ios_carrier_inputs() {
+  install_ios_resource_carriers
   local carrier_manifest="${OLIPHAUNT_REACT_NATIVE_IOS_BASE_CARRIER:-}"
   if [ -z "$carrier_manifest" ]; then
     local candidate="$root/target/release/ios-carriers/oliphaunt-react-native-ios-carriers.json"
@@ -506,27 +533,14 @@ configure_ios_carrier_inputs() {
   local selected_extensions icu_enabled
   selected_extensions="$(normalize_mobile_extensions)"
   icu_enabled="${OLIPHAUNT_EXPO_IOS_ICU:-0}"
-  node - "$example_dir/app.json" "$selected_extensions" "$icu_enabled" <<'NODE'
-const fs = require("node:fs");
-const file = process.argv[2];
-const extensions = process.argv[3].split(",").map((value) => value.trim()).filter(Boolean);
-const icu = ["1", "true", "yes"].includes(process.argv[4].toLowerCase());
-const value = JSON.parse(fs.readFileSync(file, "utf8"));
-const plugins = Array.isArray(value.expo?.plugins) ? value.expo.plugins : [];
-value.expo.plugins = plugins.filter((entry) => {
-  const name = Array.isArray(entry) ? entry[0] : entry;
-  return name !== "@oliphaunt/react-native";
-});
-value.expo.plugins.push(["@oliphaunt/react-native", { extensions, icu }]);
-fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-ios-runner.mts" configure-plugin "$example_dir/app.json" "$selected_extensions" "$icu_enabled"
 }
 
 ensure_ios_project() {
   echo "Generating Expo iOS project and app-owned carrier payload for smoke validation"
   (
     cd "$example_dir"
-    CI=1 EXPO_NO_TELEMETRY=1 pnpm exec expo prebuild --platform ios --no-install
+    CI=1 EXPO_NO_TELEMETRY=1 bun x --no-install expo prebuild --platform ios --no-install
   )
 }
 
@@ -562,95 +576,10 @@ install_pods() {
 validate_app_owned_payload_pod_source() {
   local lockfile="$example_dir/ios/Podfile.lock"
   local expected_root="$example_dir/ios/oliphaunt"
-  local require_icu=0
   [ -f "$lockfile" ] || fail "CocoaPods did not produce $lockfile"
   [ -f "$expected_root/OliphauntReactNativePayload.podspec" ] ||
     fail "app-owned iOS payload podspec is missing from $expected_root"
-  if is_truthy "${OLIPHAUNT_EXPO_IOS_ICU:-0}"; then
-    require_icu=1
-    node - \
-      "$expected_root/selection.json" \
-      "$expected_root/resources/OliphauntReactNativeResources.bundle/oliphaunt/runtime/files/share/icu" <<'NODE'
-const fs = require("node:fs");
-const path = require("node:path");
-
-const [selectionFile, icuRoot] = process.argv.slice(2);
-const selection = JSON.parse(fs.readFileSync(selectionFile, "utf8"));
-if (selection.icu !== true) {
-  throw new Error(`app-owned iOS selection did not record ICU: ${selectionFile}`);
-}
-if (!fs.statSync(icuRoot).isDirectory()) {
-  throw new Error(`app-owned iOS ICU payload is not a directory: ${icuRoot}`);
-}
-
-const files = [];
-const pending = [icuRoot];
-while (pending.length > 0) {
-  const directory = pending.pop();
-  for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
-    const candidate = path.join(directory, entry.name);
-    if (entry.isDirectory()) pending.push(candidate);
-    else if (entry.isFile()) files.push(path.relative(icuRoot, candidate));
-  }
-}
-if (files.length === 0) {
-  throw new Error(`app-owned iOS ICU payload is empty: ${icuRoot}`);
-}
-if (!files.some((file) => file.split(path.sep).length > 1)) {
-  throw new Error(`app-owned iOS ICU payload lost its directory structure: ${icuRoot}`);
-}
-NODE
-  fi
-
-  ruby - "$lockfile" "$expected_root" "$require_icu" <<'RUBY'
-require "yaml"
-
-lockfile, expected_root, require_icu = ARGV
-# CocoaPods serializes external-source keys as Ruby symbols. Keep object
-# loading closed to every other class and to symbols outside this exact source
-# contract so Ruby/Psych upgrades cannot turn lockfile validation into either
-# an unsafe load or a version-dependent failure.
-source_symbols = %i[path git http tag branch commit podspec]
-document = YAML.safe_load(
-  File.read(lockfile),
-  permitted_classes: [Symbol],
-  permitted_symbols: source_symbols,
-  aliases: false,
-)
-sources = document.fetch("EXTERNAL SOURCES")
-payload = sources.fetch("OliphauntReactNativePayload")
-unless payload.is_a?(Hash)
-  abort "OliphauntReactNativePayload external source is not a mapping"
-end
-
-path = payload[":path"] || payload[:path]
-unless path.is_a?(String) && !path.empty?
-  abort "OliphauntReactNativePayload must be installed as an app-owned :path pod"
-end
-
-forbidden = %w[:git :http :tag :branch :commit :podspec].select do |key|
-  payload.key?(key) || payload.key?(key.to_sym)
-end
-unless forbidden.empty?
-  abort "OliphauntReactNativePayload unexpectedly declares remote/podspec source keys: #{forbidden.join(", ")}"
-end
-
-resolved = File.expand_path(path, File.dirname(lockfile))
-expected = File.expand_path(expected_root)
-unless resolved == expected
-  abort "OliphauntReactNativePayload path resolved to #{resolved}, expected #{expected}"
-end
-
-if require_icu == "1"
-  pod_names = document.fetch("PODS", []).map do |entry|
-    entry.is_a?(Hash) ? entry.keys.first : entry
-  end.compact.map { |entry| entry.to_s.split(/[\s(]/, 2).first }
-  checksums = document.fetch("SPEC CHECKSUMS", {})
-  if pod_names.include?("OliphauntICU") || checksums.key?("OliphauntICU") || sources.key?("OliphauntICU")
-    abort "OliphauntICU must not be linked separately from the app-owned ICU payload"
-  end
-end
-RUBY
+  "$root/tools/dev/bun.sh" "$root/src/sdks/react-native/tools/expo-ios-runner.mts" validate-pod-source "$lockfile" "$expected_root"
 }
 
 patch_expo_modules_jsi_for_host_toolchain() {
@@ -659,8 +588,7 @@ patch_expo_modules_jsi_for_host_toolchain() {
   local swift_version package_dir
   swift_version="$(xcrun swiftc -version 2>/dev/null || true)"
   case "$swift_version" in
-    *"Swift version 6.2"*)
-      ;;
+    *"Swift version 6.2"*) ;;
     *)
       return 0
       ;;
@@ -668,8 +596,7 @@ patch_expo_modules_jsi_for_host_toolchain() {
 
   package_dir="$example_dir/node_modules/expo-modules-jsi/apple/Sources/ExpoModulesJSI"
   [ -d "$package_dir" ] || return 0
-  find "$package_dir" -name '*.swift' -print0 |
-    xargs -0 perl -pi -e 's/\b(nonisolated\(unsafe\)\s+)?weak\s+(let|var)\b/nonisolated(unsafe) weak var/g'
+  "$root/tools/dev/bun.sh" "$root/src/sdks/react-native/tools/expo-ios-runner.mts" patch-weak-references "$package_dir"
   echo "Patched ExpoModulesJSI weak references for local Swift 6.2 source builds" >&2
 }
 
@@ -812,25 +739,13 @@ build_ios_app() {
   [ -d "$resource_root" ] ||
     fail "iOS app is missing OliphauntReactNativeResources.bundle/oliphaunt resource root"
   echo "bundled: $resource_root ($(directory_files "$resource_root") files, $(directory_bytes "$resource_root") bytes)" >&2
-  for required in \
-    "$resource_root/cluster-seed/files/PG_VERSION" \
-    "$resource_root/runtime/files/share/postgresql/postgres.bki"; do
-    [ -e "$required" ] || fail "iOS app is missing packaged Oliphaunt resource: $required"
-    echo "bundled: $required" >&2
-  done
-  if is_truthy "${OLIPHAUNT_EXPO_IOS_ICU:-0}"; then
-    local built_icu_root="$resource_root/runtime/files/share/icu"
-    local built_icu_file built_nested_icu_file
-    [ -d "$built_icu_root" ] ||
-      fail "iOS app is missing selected ICU data: $built_icu_root"
-    built_icu_file="$(find "$built_icu_root" -type f -print -quit)"
-    [ -n "$built_icu_file" ] ||
-      fail "iOS app contains an empty selected ICU data directory: $built_icu_root"
-    built_nested_icu_file="$(find "$built_icu_root" -mindepth 2 -type f -print -quit)"
-    [ -n "$built_nested_icu_file" ] ||
-      fail "iOS app ICU data lost its directory structure: $built_icu_root"
-    echo "bundled ICU: $built_icu_root ($(directory_files "$built_icu_root") files, $(directory_bytes "$built_icu_root") bytes)" >&2
-  fi
+  [ -s "$resource_root/runtime/files/share/postgresql/postgres.bki" ] ||
+    fail "iOS app is missing packaged PostgreSQL runtime data"
+  export_mobile_e2e_icu_expectation_from_ios_app "$app" || return 1
+  local expected_icu=0
+  if is_truthy "${OLIPHAUNT_EXPO_IOS_ICU:-0}"; then expected_icu=1; fi
+  [ "$OLIPHAUNT_MOBILE_E2E_EXPECT_ICU" = "$expected_icu" ] ||
+    fail "iOS app resource carriers do not match the requested ICU selection"
   if [ -e "$resource_root/lib/liboliphaunt.dylib" ]; then
     echo "bundled: $resource_root/lib/liboliphaunt.dylib" >&2
   fi
@@ -866,12 +781,12 @@ start_metro_if_needed() {
     (
       cd "$example_dir"
       CI=1 EXPO_NO_TELEMETRY=1 EXPO_UNSTABLE_MCP_SERVER=1 \
-      EXPO_PUBLIC_OLIPHAUNT_RUNNER="$bundle_runner" \
-      EXPO_PUBLIC_OLIPHAUNT_LIFECYCLE_SMOKE="$lifecycle_smoke" \
-      EXPO_PUBLIC_OLIPHAUNT_BENCHMARK_PRESET="$benchmark_preset" \
-      EXPO_PUBLIC_OLIPHAUNT_STARTUP_GUCS="$startup_gucs" \
-      EXPO_PUBLIC_OLIPHAUNT_STORAGE_DIRECTORY="$bundle_storage" \
-      pnpm exec expo start --dev-client --port "$metro_port" --host lan --clear \
+        EXPO_PUBLIC_OLIPHAUNT_RUNNER="$bundle_runner" \
+        EXPO_PUBLIC_OLIPHAUNT_LIFECYCLE_SMOKE="$lifecycle_smoke" \
+        EXPO_PUBLIC_OLIPHAUNT_BENCHMARK_PRESET="$benchmark_preset" \
+        EXPO_PUBLIC_OLIPHAUNT_STARTUP_GUCS="$startup_gucs" \
+        EXPO_PUBLIC_OLIPHAUNT_STORAGE_DIRECTORY="$bundle_storage" \
+        bun x --no-install expo start --dev-client --port "$metro_port" --host lan --clear \
         >"$scratch_root/metro.log" 2>&1
     ) &
     metro_pid="$!"
@@ -954,9 +869,7 @@ main() {
   if is_truthy "$e2e_only"; then
     local app
     app="$(resolve_prebuilt_ios_app)"
-    export_mobile_e2e_icu_expectation_from_manifest \
-      "$app/OliphauntReactNativeResources.bundle/oliphaunt/runtime/manifest.properties" \
-      "iOS app"
+    export_mobile_e2e_icu_expectation_from_ios_app "$app"
     install_and_launch "$app"
     local ios_app_bytes rn_package_bytes
     ios_app_bytes="$(directory_bytes "$app")"
@@ -965,7 +878,6 @@ main() {
     exit 0
   fi
   need_cmd rg
-  need_cmd ruby
   need_cmd rsync
   need_cmd pgrep
   need_cmd lsof
@@ -1006,9 +918,7 @@ main() {
   validate_app_owned_payload_pod_source
   stamp_expo_modules_jsi_prebuilt
   app="$(build_ios_app)"
-  export_mobile_e2e_icu_expectation_from_manifest \
-    "$app/OliphauntReactNativeResources.bundle/oliphaunt/runtime/manifest.properties" \
-    "iOS app"
+  export_mobile_e2e_icu_expectation_from_ios_app "$app"
   local selected_extensions
   selected_extensions="$(normalize_mobile_extensions)"
   write_ios_build_artifact_report "$app" "$selected_extensions"
diff --git a/src/sdks/react-native/tools/expo-ios-runner.test.mts b/src/sdks/react-native/tools/expo-ios-runner.test.mts
new file mode 100644
index 000000000..95ac203b5
--- /dev/null
+++ b/src/sdks/react-native/tools/expo-ios-runner.test.mts
@@ -0,0 +1,35 @@
+import assert from 'node:assert/strict';
+import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { gzipSync } from 'node:zlib';
+import { createDeterministicTar } from '../../../../tools/packaging/archive-directory.mts';
+
+const [phase, root] = process.argv.slice(2);
+const seedName = (profile) => `@oliphaunt/seed-native-ios-datum64-${profile}`;
+const read = (name) => JSON.parse(readFileSync(path.join(root, name), 'utf8'));
+if (phase === 'prepare') {
+  for (const [name, metadata] of Object.entries({
+    standard: { name: seedName('standard'), version: '1.2.3' },
+    icu: { name: seedName('icu'), version: '1.2.3', dependencies: { '@oliphaunt/icu': '1.2.3' } },
+    data: { name: '@oliphaunt/icu', version: '1.2.3' },
+    wrong: { name: '@oliphaunt/icu', version: '9.9.9' },
+  })) {
+    const source = path.join(root, name);
+    mkdirSync(path.join(source, 'package'), { recursive: true });
+    writeFileSync(path.join(source, 'package/package.json'), JSON.stringify(metadata));
+    writeFileSync(path.join(root, `${name}.tgz`), gzipSync(await createDeterministicTar(source)));
+  }
+  for (const name of ['workspace.json', 'example.json', 'single.json']) {
+    writeFileSync(path.join(root, name), JSON.stringify({ dependencies: { unrelated: '1.0.0' } }));
+  }
+} else {
+  const profile = phase === 'standard' ? 'standard' : 'icu';
+  const example = read(phase === 'single' ? 'single.json' : 'example.json');
+  const workspace = read(phase === 'single' ? 'single.json' : 'workspace.json');
+  const expected = {
+    [seedName(profile)]: `file:${path.join(root, `${profile}.tgz`)}`,
+    ...(profile === 'icu' ? { '@oliphaunt/icu': `file:${path.join(root, 'data.tgz')}` } : {}),
+  };
+  assert.deepEqual(workspace.overrides, expected);
+  assert.deepEqual(example.dependencies, { unrelated: '1.0.0', ...expected });
+}
diff --git a/src/sdks/react-native/tools/expo-ios-runner.test.sh b/src/sdks/react-native/tools/expo-ios-runner.test.sh
new file mode 100644
index 000000000..c36bf6915
--- /dev/null
+++ b/src/sdks/react-native/tools/expo-ios-runner.test.sh
@@ -0,0 +1,96 @@
+#!/usr/bin/env bash
+set -euo pipefail
+tool="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/expo-ios-runner.mts"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+fixture="${tool%.mts}.test.mts"
+bun "$fixture" prepare "$scratch"
+bun "$tool" configure-resource-dependencies "$scratch/workspace.json" "$scratch/example.json" "$scratch/icu.tgz" "$scratch/data.tgz"
+bun "$fixture" icu "$scratch"
+for invalid in "$scratch/wrong.tgz" "$scratch/standard.tgz"; do
+  if bun "$tool" configure-resource-dependencies "$scratch/workspace.json" "$scratch/example.json" "$scratch/icu.tgz" "$invalid" > "$scratch/resource-failure.log" 2>&1; then
+    echo 'incompatible ICU resource carrier was accepted' >&2
+    exit 1
+  fi
+  bun "$fixture" icu "$scratch"
+done
+bun "$tool" configure-resource-dependencies "$scratch/workspace.json" "$scratch/example.json" "$scratch/standard.tgz"
+bun "$fixture" standard "$scratch"
+bun "$tool" configure-resource-dependencies "$scratch/single.json" "$scratch/single.json" "$scratch/icu.tgz" "$scratch/data.tgz"
+bun "$fixture" single "$scratch"
+valid='EXTERNAL SOURCES:
+  OliphauntReactNativePayload:
+    :path: oliphaunt'
+printf '%s\n' "$valid" > "$scratch/Podfile.lock"
+bun "$tool" validate-pod-source "$scratch/Podfile.lock" "$scratch/oliphaunt" 1
+printf '%s\n' "$valid"$'\nPODS:\n  - OliphauntICU (1.0)\n  - OliphauntSeedNativeIOSICU (1.0)' > "$scratch/Podfile.lock"
+bun "$tool" validate-pod-source "$scratch/Podfile.lock" "$scratch/oliphaunt"
+for value in \
+  "${valid/:path: oliphaunt/:path: ../elsewhere}" \
+  "$valid"$'\n    :git: https://example.invalid/payload.git'; do
+  printf '%s\n' "$value" > "$scratch/Podfile.lock"
+  if bun "$tool" validate-pod-source "$scratch/Podfile.lock" "$scratch/oliphaunt" 1 > "$scratch/failure.log" 2>&1; then
+    echo 'invalid CocoaPods source unexpectedly accepted' >&2
+    exit 1
+  fi
+done
+mkdir "$scratch/nested"
+printf '%s\n' 'weak let first: Object?' 'nonisolated(unsafe) weak var second: Object?' 'let third: Object?' > "$scratch/nested/Refs.swift"
+printf '%s\n' 'nonisolated(unsafe) weak var first: Object?' 'nonisolated(unsafe) weak var second: Object?' 'let third: Object?' > "$scratch/expected"
+bun "$tool" patch-weak-references "$scratch"
+cmp "$scratch/expected" "$scratch/nested/Refs.swift"
+bun "$tool" patch-weak-references "$scratch"
+cmp "$scratch/expected" "$scratch/nested/Refs.swift"
+
+# Exercise the exact CocoaPods prepare command against a local bindings archive.
+root="$(cd "$(dirname "$tool")/../../../.." && pwd)"
+prepare="$root/src/sdks/react-native/ios/podspecs/prepare-native-bindings.sh"
+version=1.2.3
+asset="oliphaunt-swift-$version-bindings.xcframework.zip"
+url="https://github.com/f0rr0/oliphaunt/releases/download/oliphaunt-swift-v$version/$asset"
+mkdir -p "$scratch/input/OliphauntNativeBindingsFFI.xcframework" "$scratch/pod/Artifacts"
+printf '%s\n' fixture-plist > "$scratch/input/OliphauntNativeBindingsFFI.xcframework/Info.plist"
+bun "$root/tools/packaging/archive-directory.mts" --keep-parent \
+  "$scratch/input/OliphauntNativeBindingsFFI.xcframework" "$scratch/pod/Artifacts/$asset"
+checksum="$(shasum -a 256 "$scratch/pod/Artifacts/$asset" | cut -d ' ' -f 1)"
+cat > "$scratch/pod/Package.swift" < "$scratch/bin/curl" <<'CURL'
+#!/usr/bin/env bash
+set -eu
+test "$5" = "$EXPECTED_BINDINGS_URL"
+printf '%s\n' "$5" > "$DOWNLOAD_LOG"
+cp "$DOWNLOAD_ARCHIVE" "$7"
+CURL
+  chmod +x "$scratch/bin/curl"
+  rm "Artifacts/$asset"
+  PATH="$scratch/bin:$PATH" EXPECTED_BINDINGS_URL="$url" \
+    DOWNLOAD_LOG="$scratch/download.log" DOWNLOAD_ARCHIVE="$scratch/download.zip" \
+    bash "$prepare" "$version"
+  test "$(cat "$scratch/download.log")" = "$url"
+  cmp "$scratch/input/OliphauntNativeBindingsFFI.xcframework/Info.plist" Artifacts/OliphauntNativeBindingsFFI.xcframework/Info.plist
+  cp "$scratch/download.zip" "Artifacts/$asset"
+  printf tampered >> "Artifacts/$asset"
+  if bash "$prepare" "$version" > "$scratch/checksum-failure.log" 2>&1; then
+    echo 'CocoaPods accepted a corrupt bindings archive' >&2
+    exit 1
+  fi
+  cmp "$scratch/input/OliphauntNativeBindingsFFI.xcframework/Info.plist" Artifacts/OliphauntNativeBindingsFFI.xcframework/Info.plist
+  if bash "$prepare" 9.9.9 > "$scratch/version-failure.log" 2>&1; then
+    echo 'CocoaPods accepted another SDK version bindings target' >&2
+    exit 1
+  fi
+)
diff --git a/src/sdks/react-native/tools/expo-packed-workspace.test.sh b/src/sdks/react-native/tools/expo-packed-workspace.test.sh
new file mode 100644
index 000000000..719fe9d82
--- /dev/null
+++ b/src/sdks/react-native/tools/expo-packed-workspace.test.sh
@@ -0,0 +1,98 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+fixture="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-expo-packed.XXXXXX")"
+trap 'rm -rf "$fixture"' EXIT
+# shellcheck source=src/sdks/react-native/tools/expo-runner-common.sh
+. "$root/src/sdks/react-native/tools/expo-runner-common.sh"
+# shellcheck source=src/sdks/react-native/tools/expo-runner-workspace.sh
+. "$root/src/sdks/react-native/tools/expo-runner-workspace.sh"
+export OLIPHAUNT_EXPO_REQUIRE_SDK_ARTIFACTS=1
+export OLIPHAUNT_EXPO_SDK_ARTIFACT_ROOT="$fixture/artifacts"
+scratch_root="$fixture/consumer"
+query_artifacts="$OLIPHAUNT_EXPO_SDK_ARTIFACT_ROOT/oliphaunt-query-ts"
+mkdir -p "$query_artifacts" "$fixture/query" "$fixture/rn"
+if (write_scratch_bun_workspace) >"$fixture/missing.log" 2>&1; then
+  echo 'missing candidate query artifact unexpectedly accepted' >&2
+  exit 1
+fi
+grep -Fq 'required SDK artifact for oliphaunt-query-ts' "$fixture/missing.log"
+cat >"$fixture/query/package.json" <<'JSON'
+{"name":"@oliphaunt/ts-query","version":"0.0.1","type":"module","exports":"./index.js"}
+JSON
+printf 'export const candidate = "packed-query";\n' >"$fixture/query/index.js"
+bun pm pack --cwd "$fixture/query" --filename "$query_artifacts/query.tgz" >/dev/null
+cat >"$fixture/rn/package.json" <<'JSON'
+{"name":"@oliphaunt/react-native","version":"0.0.1","type":"module","exports":"./index.js","dependencies":{"@oliphaunt/ts-query":"0.0.1"}}
+JSON
+printf 'export { candidate } from "@oliphaunt/ts-query";\n' >"$fixture/rn/index.js"
+bun pm pack --cwd "$fixture/rn" --filename "$fixture/rn.tgz" >/dev/null
+write_scratch_bun_workspace
+[ ! -e "$scratch_root/src/sdks/ts-query" ]
+example_dir="$scratch_root/src/examples/react-native-expo"
+mkdir -p "$example_dir"
+printf '{"name":"react-native-oliphaunt-expo","private":true,"dependencies":{"picocolors":"^1.0.0"}}\n' >"$example_dir/package.json"
+patch_expo_example_react_native_dependency "file:$fixture/rn.tgz"
+install_expo_example_dependencies 2>&1 | tee -a "$fixture/install.log"
+bun -e '
+  const source = Bun.JSONC.parse(await Bun.file(process.argv[1]).text());
+  const consumer = Bun.JSONC.parse(await Bun.file(process.argv[2]).text());
+  if (JSON.stringify(source.packages.picocolors) !== JSON.stringify(consumer.packages.picocolors))
+    throw new Error("locked registry version or integrity changed");
+' "$root/bun.lock" "$scratch_root/bun.lock"
+bun --cwd "$example_dir" -e '
+  const { dirname, join } = await import("node:path");
+  const { candidate } = await import("@oliphaunt/react-native");
+  if (candidate !== "packed-query") throw new Error("did not load the query candidate");
+  const rn = dirname(Bun.resolveSync("@oliphaunt/react-native", process.cwd()));
+  const query = dirname(Bun.resolveSync("@oliphaunt/ts-query", rn));
+  const declared = (await Bun.file(join(rn, "package.json")).json()).dependencies["@oliphaunt/ts-query"];
+  if ((await Bun.file(join(query, "package.json")).json()).version !== declared)
+    throw new Error("installed query version differs from the packed RN dependency");
+'
+cp "$scratch_root/bun.lock" "$fixture/first-consumer.lock"
+write_scratch_bun_workspace
+install_expo_example_dependencies 2>&1 | tee -a "$fixture/install.log"
+cmp "$fixture/first-consumer.lock" "$scratch_root/bun.lock"
+# Exercise the real Expo peer graph without compiling or running native apps.
+scratch_root="$fixture/full-example-consumer"
+write_scratch_bun_workspace
+example_dir="$scratch_root/src/examples/react-native-expo"
+mkdir -p "$example_dir"
+cp "$root/src/examples/react-native-expo/package.json" "$example_dir/package.json"
+patch_expo_example_react_native_dependency "file:$fixture/rn.tgz"
+bun install --cwd "$scratch_root" --ignore-scripts --lockfile-only 2>&1 | tee -a "$fixture/install.log"
+bun -e '
+  const source = Bun.JSONC.parse(await Bun.file(process.argv[1]).text());
+  const consumer = Bun.JSONC.parse(await Bun.file(process.argv[2]).text());
+  const identity = row => JSON.stringify([row[0], row.at(-1)]);
+  const pinned = new Set(Object.values(source.packages).map(identity));
+  for (const row of Object.values(consumer.packages)) {
+    if (typeof row[1] === "string" && typeof row.at(-1) === "string" && row.at(-1).startsWith("sha") && !pinned.has(identity(row)))
+      throw new Error(`Expo registry version or integrity changed: ${row[0]}`);
+  }
+' "$root/bun.lock" "$scratch_root/bun.lock"
+cp "$scratch_root/bun.lock" "$fixture/first-example.lock"
+write_scratch_bun_workspace
+bun install --cwd "$scratch_root" --ignore-scripts --lockfile-only 2>&1 | tee -a "$fixture/install.log"
+cmp "$fixture/first-example.lock" "$scratch_root/bun.lock"
+# The consumer must not acquire query merely because it exists in the checkout.
+printf '{"name":"@oliphaunt/react-native","version":"0.0.1","type":"module","exports":"./index.js"}\n' >"$fixture/rn/package.json"
+bun pm pack --cwd "$fixture/rn" --filename "$fixture/rn-missing-dependency.tgz" >/dev/null
+if patch_expo_example_react_native_dependency "file:$fixture/rn-missing-dependency.tgz" >"$fixture/undeclared.log" 2>&1; then
+  echo 'undeclared query dependency unexpectedly accepted' >&2
+  exit 1
+fi
+grep -Fq 'does not satisfy packed RN dependency' "$fixture/undeclared.log"
+printf '{"name":"@oliphaunt/react-native","version":"0.0.1","type":"module","exports":"./index.js","dependencies":{"@oliphaunt/ts-query":"0.0.2"}}\n' >"$fixture/rn/package.json"
+bun pm pack --cwd "$fixture/rn" --filename "$fixture/rn-wrong-query.tgz" >/dev/null
+if patch_expo_example_react_native_dependency "file:$fixture/rn-wrong-query.tgz" >"$fixture/mismatch.log" 2>&1; then
+  echo 'mismatched query candidate unexpectedly accepted' >&2
+  exit 1
+fi
+grep -Fq 'query candidate 0.0.1 does not satisfy packed RN dependency 0.0.2' "$fixture/mismatch.log"
+if grep -Eq 'InvalidLockfile|Ignoring lockfile' "$fixture/install.log"; then
+  echo 'consumer installation discarded its pinned registry lock' >&2
+  exit 1
+fi
+echo 'Packed Expo consumer resolves declared candidate dependencies and rejects missing inputs'
diff --git a/tools/integration/react-native/expo-runner-android-device.test.sh b/src/sdks/react-native/tools/expo-runner-android-device.test.sh
similarity index 100%
rename from tools/integration/react-native/expo-runner-android-device.test.sh
rename to src/sdks/react-native/tools/expo-runner-android-device.test.sh
diff --git a/src/sdks/react-native/tools/expo-runner-common.mts b/src/sdks/react-native/tools/expo-runner-common.mts
new file mode 100644
index 000000000..e0738956b
--- /dev/null
+++ b/src/sdks/react-native/tools/expo-runner-common.mts
@@ -0,0 +1,132 @@
+import * as fs from 'node:fs';
+import * as path from 'node:path';
+
+const [command, ...args] = process.argv.slice(2);
+switch (command) {
+  case 'check-query-dependency': {
+    const { readPortableArchiveEntries } = await import(
+      '../../../../tools/packaging/portable-archive.mts'
+    );
+    const manifests = args.map((archive) => {
+      const entry = readPortableArchiveEntries(archive).get('package/package.json');
+      if (!entry?.isFile || entry.isSymbolicLink)
+        throw new Error(`missing regular package/package.json in ${archive}`);
+      return JSON.parse(Buffer.from(entry.data()).toString('utf8'));
+    });
+    const [rn, query] = manifests;
+    const requirement = rn.dependencies?.['@oliphaunt/ts-query'];
+    if (rn.name !== '@oliphaunt/react-native' || query.name !== '@oliphaunt/ts-query')
+      throw new Error('packed Expo consumer requires React Native and query package artifacts');
+    if (typeof requirement !== 'string' || !Bun.semver.satisfies(query.version, requirement))
+      throw new Error(
+        `query candidate ${query.version} does not satisfy packed RN dependency ${requirement}`,
+      );
+    break;
+  }
+  case 'workspace': {
+    const [root, scratch, name, queryArtifact] = args;
+    if (path.resolve(root) === path.resolve(scratch))
+      throw new Error('Expo scratch workspace must be outside the source root');
+    const source = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
+    if (queryArtifact && !fs.statSync(queryArtifact).isFile())
+      throw new Error(`query package artifact is not a file: ${queryArtifact}`);
+    if (queryArtifact && !fs.existsSync(path.join(root, 'bun.lock')))
+      throw new Error('packed Expo consumer requires the repository Bun lockfile');
+    const packages = queryArtifact
+      ? ['src/examples/react-native-expo']
+      : ['src/sdks/react-native', 'src/examples/react-native-expo', 'src/sdks/ts-query'];
+    fs.mkdirSync(scratch, { recursive: true });
+    fs.writeFileSync(
+      path.join(scratch, 'package.json'),
+      JSON.stringify(
+        {
+          name,
+          private: true,
+          packageManager: source.packageManager,
+          workspaces: { ...source.workspaces, packages },
+          overrides: {
+            ...source.overrides,
+            ...(queryArtifact
+              ? { '@oliphaunt/ts-query': `file:${path.resolve(queryArtifact)}` }
+              : {}),
+          },
+          trustedDependencies: source.trustedDependencies,
+        },
+        null,
+        2,
+      ) + '\n',
+    );
+    if (queryArtifact) {
+      fs.rmSync(path.join(scratch, 'src/sdks/ts-query'), { recursive: true, force: true });
+    } else {
+      fs.cpSync(path.join(root, 'src/sdks/ts-query'), path.join(scratch, 'src/sdks/ts-query'), {
+        recursive: true,
+        filter: (file) => path.basename(file) !== 'node_modules',
+      });
+    }
+    // This derived workspace changes the source package to a packed consumer.
+    // Reuse resolved versions, allowing Bun to update its own ordinary lockfile.
+    if (root !== scratch && fs.existsSync(path.join(root, 'bun.lock'))) {
+      if (queryArtifact) {
+        // Bun cannot reconcile absent checkout workspace locators. Retain the
+        // locked registry resolutions; Bun owns the candidate file dependency
+        // records and the resulting consumer lockfile.
+        const lock = Bun.JSONC.parse(fs.readFileSync(path.join(root, 'bun.lock'), 'utf8'));
+        const checkoutPackages = new Set(
+          Object.entries(lock.packages)
+            .filter(([, row]) => (row as string[])[0].includes('@workspace:'))
+            .map(([name]) => name),
+        );
+        lock.workspaces = Object.fromEntries(
+          Object.entries(lock.workspaces).filter(
+            ([directory]) => directory === '' || packages.includes(directory),
+          ),
+        );
+        for (const workspace of Object.values(lock.workspaces)) {
+          for (const kind of ['dependencies', 'devDependencies', 'optionalDependencies']) {
+            if (!workspace[kind]) continue;
+            workspace[kind] = Object.fromEntries(
+              Object.entries(workspace[kind]).filter(([name]) => !checkoutPackages.has(name)),
+            );
+          }
+        }
+        lock.packages = Object.fromEntries(
+          Object.entries(lock.packages).filter(
+            ([, row]) => !(row as string[])[0].includes('@workspace:'),
+          ),
+        );
+        fs.writeFileSync(path.join(scratch, 'bun.lock'), `${JSON.stringify(lock, null, 2)}\n`);
+      } else {
+        fs.copyFileSync(path.join(root, 'bun.lock'), path.join(scratch, 'bun.lock'));
+      }
+    }
+    break;
+  }
+  case 'tarball-name': {
+    const packageJson = args[0];
+    const pkg = JSON.parse(fs.readFileSync(packageJson, 'utf8'));
+    const name = String(pkg.name || '')
+      .replace(/^@/, '')
+      .replace(/\//g, '-');
+    const version = String(pkg.version || '');
+    if (!name || !version) {
+      throw new Error(`package name/version is missing from ${packageJson}`);
+    }
+    process.stdout.write(`${name}-${version}.tgz`);
+    break;
+  }
+  case 'urlencode': {
+    process.stdout.write(encodeURIComponent(args[0]));
+    break;
+  }
+  case 'patch-dependency': {
+    const [packageJson, dependencySpec] = args;
+    const pkg = JSON.parse(fs.readFileSync(packageJson, 'utf8'));
+    pkg.dependencies ??= {};
+    pkg.dependencies['@oliphaunt/react-native'] = dependencySpec;
+    fs.writeFileSync(packageJson, `${JSON.stringify(pkg, null, 2)}\n`);
+    break;
+  }
+  default:
+    throw new Error('unknown expo-runner-common command: ' + command);
+}
diff --git a/src/sdks/react-native/tools/expo-runner-common.sh b/src/sdks/react-native/tools/expo-runner-common.sh
index b1c43bbba..592a77521 100644
--- a/src/sdks/react-native/tools/expo-runner-common.sh
+++ b/src/sdks/react-native/tools/expo-runner-common.sh
@@ -15,7 +15,7 @@ fail() {
 
 is_truthy() {
   case "${1:-}" in
-    1|true|TRUE|yes|YES|on|ON)
+    1 | true | TRUE | yes | YES | on | ON)
       return 0
       ;;
     *)
@@ -26,7 +26,7 @@ is_truthy() {
 
 is_falsey() {
   case "${1:-}" in
-    0|false|FALSE|no|NO|off|OFF)
+    0 | false | FALSE | no | NO | off | OFF)
       return 0
       ;;
     *)
@@ -117,19 +117,9 @@ file_from_offset() {
 }
 
 urlencode() {
-  node -e 'process.stdout.write(encodeURIComponent(process.argv[1]))' "$1"
+  bun "$root/src/sdks/react-native/tools/expo-runner-common.mts" urlencode "$1"
 }
 
 react_native_package_tarball_name() {
-  node - "$1/package.json" <<'NODE'
-const fs = require('node:fs');
-const packageJson = process.argv[2];
-const pkg = JSON.parse(fs.readFileSync(packageJson, 'utf8'));
-const name = String(pkg.name || '').replace(/^@/, '').replace(/\//g, '-');
-const version = String(pkg.version || '');
-if (!name || !version) {
-  throw new Error(`package name/version is missing from ${packageJson}`);
-}
-process.stdout.write(`${name}-${version}.tgz`);
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-runner-common.mts" tarball-name "$1/package.json"
 }
diff --git a/src/sdks/react-native/tools/expo-runner-ios-device.mts b/src/sdks/react-native/tools/expo-runner-ios-device.mts
new file mode 100644
index 000000000..754ec08b8
--- /dev/null
+++ b/src/sdks/react-native/tools/expo-runner-ios-device.mts
@@ -0,0 +1,135 @@
+import * as fs from 'node:fs';
+
+const [command, ...args] = process.argv.slice(2);
+switch (command) {
+  case 'physical-device': {
+    const file = args[0];
+    const data = JSON.parse(fs.readFileSync(file, 'utf8'));
+    const devices = data?.result?.devices ?? [];
+    const candidates = devices.filter((device) => {
+      const hardware = device.hardwareProperties ?? {};
+      const connection = device.connectionProperties ?? {};
+      return (
+        hardware.platform === 'iOS' &&
+        hardware.reality === 'physical' &&
+        connection.pairingState === 'paired'
+      );
+    });
+    candidates.sort((left, right) => {
+      const leftLocal = left.connectionProperties?.transportType === 'localNetwork' ? 1 : 0;
+      const rightLocal = right.connectionProperties?.transportType === 'localNetwork' ? 1 : 0;
+      const leftName = String(left.deviceProperties?.name ?? '');
+      const rightName = String(right.deviceProperties?.name ?? '');
+      return rightLocal - leftLocal || (leftName < rightName ? -1 : leftName > rightName ? 1 : 0);
+    });
+    if (!candidates.length) {
+      process.exit(1);
+    }
+    process.stdout.write(candidates[0].identifier || candidates[0].hardwareProperties?.udid);
+    break;
+  }
+  case 'preflight': {
+    const file = args[0];
+    const data = JSON.parse(fs.readFileSync(file, 'utf8'));
+    const result = data.result ?? {};
+    const props = result.deviceProperties ?? {};
+    const hardware = result.hardwareProperties ?? {};
+    const name = props.name ?? 'physical iOS device';
+    const os = props.osVersionNumber ?? 'unknown iOS';
+    const devMode = props.developerModeStatus ?? 'unknown';
+    if (devMode !== 'enabled') {
+      console.error(
+        `error: physical iOS runs require Developer Mode enabled on ${name}; current developerModeStatus=${devMode}, os=${os}`,
+      );
+      process.exit(1);
+    }
+    if (props.ddiServicesAvailable === false) {
+      const product = hardware.productType ?? 'unknown product';
+      console.error(
+        `error: physical iOS runs require Developer Disk Image services on ${name}; ddiServicesAvailable=false, product=${product}, os=${os}`,
+      );
+      process.exit(1);
+    }
+    break;
+  }
+  case 'booted-simulator': {
+    const data = JSON.parse(fs.readFileSync(0, 'utf8'));
+    for (const devices of Object.values(data.devices || {})) {
+      const found = devices.find((device) => device.isAvailable && device.state === 'Booted');
+      if (found) {
+        process.stdout.write(found.udid);
+        process.exit(0);
+      }
+    }
+
+    break;
+  }
+  case 'available-simulator': {
+    const preferredName = process.env.OLIPHAUNT_EXPO_IOS_DEVICE_NAME || 'iPhone 15 Pro';
+    const preferredRuntime = process.env.OLIPHAUNT_EXPO_IOS_RUNTIME || '';
+    const data = JSON.parse(fs.readFileSync(0, 'utf8'));
+    const candidates = [];
+    for (const [runtime, devices] of Object.entries(data.devices || {})) {
+      if (!runtime.includes('iOS')) {
+        continue;
+      }
+      const versionMatch = runtime.match(/iOS-(\d+)-(\d+)/);
+      const major = versionMatch ? Number(versionMatch[1]) : 0;
+      const minor = versionMatch ? Number(versionMatch[2]) : 0;
+      for (const device of devices) {
+        if (!device.isAvailable) {
+          continue;
+        }
+        const exactName = device.name === preferredName ? 1 : 0;
+        const iphone = device.name.startsWith('iPhone') ? 1 : 0;
+        const runtimeMatch = preferredRuntime && runtime.includes(preferredRuntime) ? 1 : 0;
+        candidates.push({ device, exactName, iphone, runtimeMatch, major, minor });
+      }
+    }
+    candidates.sort(
+      (left, right) =>
+        right.runtimeMatch - left.runtimeMatch ||
+        right.exactName - left.exactName ||
+        right.iphone - left.iphone ||
+        right.major - left.major ||
+        right.minor - left.minor ||
+        (left.device.name < right.device.name ? -1 : left.device.name > right.device.name ? 1 : 0),
+    );
+    if (!candidates.length) {
+      process.exit(1);
+    }
+    process.stdout.write(candidates[0].device.udid);
+
+    break;
+  }
+  case 'process-id': {
+    const data = JSON.parse(fs.readFileSync(args[0], 'utf8'));
+    const seen = new Set();
+    function visit(value) {
+      if (value == null || typeof value !== 'object' || seen.has(value)) {
+        return undefined;
+      }
+      seen.add(value);
+      for (const key of ['processIdentifier', 'pid']) {
+        if (Number.isInteger(value[key]) && value[key] > 0) {
+          return value[key];
+        }
+      }
+      for (const child of Object.values(value)) {
+        const found = visit(child);
+        if (found !== undefined) {
+          return found;
+        }
+      }
+      return undefined;
+    }
+    const pid = visit(data);
+    if (!pid) {
+      process.exit(1);
+    }
+    process.stdout.write(String(pid));
+    break;
+  }
+  default:
+    throw new Error('unknown expo-runner-ios-device command: ' + command);
+}
diff --git a/src/sdks/react-native/tools/expo-runner-ios-device.sh b/src/sdks/react-native/tools/expo-runner-ios-device.sh
index 704d20efd..d71f76f54 100755
--- a/src/sdks/react-native/tools/expo-runner-ios-device.sh
+++ b/src/sdks/react-native/tools/expo-runner-ios-device.sh
@@ -11,17 +11,7 @@ select_ios_simulator_udid() {
   local booted
   booted="$(
     xcrun simctl list devices booted -j |
-      node -e '
-const fs = require("fs");
-const data = JSON.parse(fs.readFileSync(0, "utf8"));
-for (const devices of Object.values(data.devices || {})) {
-  const found = devices.find(device => device.isAvailable && device.state === "Booted");
-  if (found) {
-    process.stdout.write(found.udid);
-    process.exit(0);
-  }
-}
-'
+      bun "$root/src/sdks/react-native/tools/expo-runner-ios-device.mts" booted-simulator
   )"
   if [ -n "$booted" ]; then
     printf '%s\n' "$booted"
@@ -29,42 +19,7 @@ for (const devices of Object.values(data.devices || {})) {
   fi
 
   xcrun simctl list devices available -j |
-    OLIPHAUNT_EXPO_IOS_DEVICE_NAME="$simulator_name" node -e '
-const fs = require("fs");
-const preferredName = process.env.OLIPHAUNT_EXPO_IOS_DEVICE_NAME || "iPhone 15 Pro";
-const preferredRuntime = process.env.OLIPHAUNT_EXPO_IOS_RUNTIME || "";
-const data = JSON.parse(fs.readFileSync(0, "utf8"));
-const candidates = [];
-for (const [runtime, devices] of Object.entries(data.devices || {})) {
-  if (!runtime.includes("iOS")) {
-    continue;
-  }
-  const versionMatch = runtime.match(/iOS-(\d+)-(\d+)/);
-  const major = versionMatch ? Number(versionMatch[1]) : 0;
-  const minor = versionMatch ? Number(versionMatch[2]) : 0;
-  for (const device of devices) {
-    if (!device.isAvailable) {
-      continue;
-    }
-    const exactName = device.name === preferredName ? 1 : 0;
-    const iphone = device.name.startsWith("iPhone") ? 1 : 0;
-    const runtimeMatch = preferredRuntime && runtime.includes(preferredRuntime) ? 1 : 0;
-    candidates.push({device, exactName, iphone, runtimeMatch, major, minor});
-  }
-}
-candidates.sort((left, right) =>
-  right.runtimeMatch - left.runtimeMatch ||
-  right.exactName - left.exactName ||
-  right.iphone - left.iphone ||
-  right.major - left.major ||
-  right.minor - left.minor ||
-  (left.device.name < right.device.name ? -1 : left.device.name > right.device.name ? 1 : 0)
-);
-if (!candidates.length) {
-  process.exit(1);
-}
-process.stdout.write(candidates[0].device.udid);
-'
+    OLIPHAUNT_EXPO_IOS_DEVICE_NAME="$simulator_name" bun "$root/src/sdks/react-native/tools/expo-runner-ios-device.mts" available-simulator
 }
 
 select_ios_physical_device_id() {
@@ -77,31 +32,7 @@ select_ios_physical_device_id() {
   local json="$scratch_root/devicectl-devices.json"
   xcrun devicectl list devices --timeout 10 --json-output "$json" >/dev/null 2>&1 ||
     return 1
-  node - "$json" <<'NODE'
-const fs = require('fs');
-const file = process.argv[2];
-const data = JSON.parse(fs.readFileSync(file, 'utf8'));
-const devices = data?.result?.devices ?? [];
-const candidates = devices.filter(device => {
-  const hardware = device.hardwareProperties ?? {};
-  const connection = device.connectionProperties ?? {};
-  return hardware.platform === 'iOS' &&
-    hardware.reality === 'physical' &&
-    connection.pairingState === 'paired';
-});
-candidates.sort((left, right) => {
-  const leftLocal = left.connectionProperties?.transportType === 'localNetwork' ? 1 : 0;
-  const rightLocal = right.connectionProperties?.transportType === 'localNetwork' ? 1 : 0;
-  const leftName = String(left.deviceProperties?.name ?? '');
-  const rightName = String(right.deviceProperties?.name ?? '');
-  return rightLocal - leftLocal ||
-    (leftName < rightName ? -1 : leftName > rightName ? 1 : 0);
-});
-if (!candidates.length) {
-  process.exit(1);
-}
-process.stdout.write(candidates[0].identifier || candidates[0].hardwareProperties?.udid);
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-runner-ios-device.mts" physical-device "$json"
 }
 
 select_xcode_development_team() {
@@ -174,26 +105,7 @@ preflight_physical_ios_device() {
     --json-output "$json" >/dev/null 2>&1 ||
     fail "failed to inspect physical iOS device with devicectl; device may be locked, untrusted, or unavailable"
 
-  node - "$json" <<'NODE' || exit $?
-const fs = require('fs');
-const file = process.argv[2];
-const data = JSON.parse(fs.readFileSync(file, 'utf8'));
-const result = data.result ?? {};
-const props = result.deviceProperties ?? {};
-const hardware = result.hardwareProperties ?? {};
-const name = props.name ?? 'physical iOS device';
-const os = props.osVersionNumber ?? 'unknown iOS';
-const devMode = props.developerModeStatus ?? 'unknown';
-if (devMode !== 'enabled') {
-  console.error(`error: physical iOS runs require Developer Mode enabled on ${name}; current developerModeStatus=${devMode}, os=${os}`);
-  process.exit(1);
-}
-if (props.ddiServicesAvailable === false) {
-  const product = hardware.productType ?? 'unknown product';
-  console.error(`error: physical iOS runs require Developer Disk Image services on ${name}; ddiServicesAvailable=false, product=${product}, os=${os}`);
-  process.exit(1);
-}
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-runner-ios-device.mts" preflight "$json" || exit $?
 }
 
 resolve_xcode_destination() {
diff --git a/src/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts b/src/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts
new file mode 100644
index 000000000..1537f4546
--- /dev/null
+++ b/src/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts
@@ -0,0 +1,32 @@
+import * as fs from 'node:fs';
+const [command, ...args] = process.argv.slice(2);
+switch (command) {
+  case 'receipt': {
+    const metadata = JSON.parse(fs.readFileSync(args[0], 'utf8'));
+    const extensions = (metadata.extensions ?? []).map((row) => row['sql-name']).sort();
+    process.stdout.write(
+      JSON.stringify({
+        schema: 'oliphaunt-expo-smoke-pass-v4',
+        runner: 'smoke',
+        platform: 'ios',
+        extensionCount: extensions.length,
+        allExtensionsActivated: true,
+        extensionCatalogComplete: true,
+        pgTextsearchEnglishBm25: extensions.includes('pg_textsearch'),
+        extensionCatalogSha256: metadata['extension-catalog-sha256'],
+        catalogProfile: 'standard',
+        icuRuntimeProof: false,
+      }),
+    );
+    break;
+  }
+  case 'tamper': {
+    const file = args[0];
+    const receipt = JSON.parse(fs.readFileSync(file, 'utf8'));
+    receipt.candidateTree = '0'.repeat(40);
+    fs.writeFileSync(file, `${JSON.stringify(receipt)}\n`);
+    break;
+  }
+  default:
+    throw Error('unknown mobile runner fixture command');
+}
diff --git a/src/sdks/react-native/tools/expo-runner-ios-installed-app.sh b/src/sdks/react-native/tools/expo-runner-ios-installed-app.sh
index e99671ba4..19a9c64e9 100644
--- a/src/sdks/react-native/tools/expo-runner-ios-installed-app.sh
+++ b/src/sdks/react-native/tools/expo-runner-ios-installed-app.sh
@@ -59,10 +59,10 @@ run_maestro_installed_smoke() {
   MAESTRO_CLI_NO_ANALYTICS=true \
     MAESTRO_CLI_ANALYSIS_NOTIFICATION_DISABLED=true \
     "$maestro" --device "$device_udid" test \
-      -e APP_ID="$app_id" \
-      -e SMOKE_TIMEOUT_MS="$((timeout_seconds * 1000))" \
-      "$maestro_flow" \
-      >"$reports_dir/maestro.log" 2>&1 &
+    -e APP_ID="$app_id" \
+    -e SMOKE_TIMEOUT_MS="$((timeout_seconds * 1000))" \
+    "$maestro_flow" \
+    >"$reports_dir/maestro.log" 2>&1 &
   local maestro_pid=$!
   local failure_receipt=""
   local capture_failed=0
@@ -136,7 +136,7 @@ resolve_ios_app_process_name() {
     return 1
   }
   case "$process_name" in
-    ''|*[!A-Za-z0-9._-]*)
+    '' | *[!A-Za-z0-9._-]*)
       echo "iOS app has an unsafe CFBundleExecutable for unified-log capture: $process_name" >&2
       return 1
       ;;
@@ -160,7 +160,7 @@ start_ios_simulator_log_capture() {
     return 1
   }
   case "$process_name" in
-    ''|*[!A-Za-z0-9._-]*)
+    '' | *[!A-Za-z0-9._-]*)
       echo "unsafe iOS process name for unified-log predicate: $process_name" >&2
       return 1
       ;;
@@ -225,7 +225,7 @@ latest_ios_simulator_capture_tag() {
 wait_for_ios_simulator_maestro_receipt() {
   local grace_seconds="${OLIPHAUNT_EXPO_IOS_RECEIPT_GRACE_SECONDS:-15}"
   case "$grace_seconds" in
-    ''|*[!0-9]*)
+    '' | *[!0-9]*)
       echo "OLIPHAUNT_EXPO_IOS_RECEIPT_GRACE_SECONDS must be a nonnegative integer, got $grace_seconds" >&2
       return 4
       ;;
@@ -313,34 +313,7 @@ resolve_prebuilt_ios_app() {
 extract_devicectl_pid() {
   local json="$1"
   [ -s "$json" ] || return 1
-  node - "$json" <<'NODE'
-const fs = require('fs');
-const data = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
-const seen = new Set();
-function visit(value) {
-  if (value == null || typeof value !== 'object' || seen.has(value)) {
-    return undefined;
-  }
-  seen.add(value);
-  for (const key of ['processIdentifier', 'pid']) {
-    if (Number.isInteger(value[key]) && value[key] > 0) {
-      return value[key];
-    }
-  }
-  for (const child of Object.values(value)) {
-    const found = visit(child);
-    if (found !== undefined) {
-      return found;
-    }
-  }
-  return undefined;
-}
-const pid = visit(data);
-if (!pid) {
-  process.exit(1);
-}
-process.stdout.write(String(pid));
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-runner-ios-device.mts" process-id "$json"
 }
 
 write_ios_device_process_metrics() {
@@ -354,144 +327,7 @@ write_ios_device_process_metrics() {
     --timeout 30 \
     --json-output "$json" >/dev/null 2>&1 || true
   [ -s "$json" ] || return 0
-  node - "$json" "$app_id" <<'NODE' >"$reports_dir/$runner-process.tsv" || true
-const fs = require('node:fs');
-const [file, bundleId] = process.argv.slice(2);
-const processName = bundleId.split('.').slice(-1)[0]?.toLowerCase() ?? '';
-const data = JSON.parse(fs.readFileSync(file, 'utf8'));
-const rows = [];
-const seen = new Set();
-
-function visit(value) {
-  if (value == null || typeof value !== 'object' || seen.has(value)) {
-    return;
-  }
-  seen.add(value);
-  if (!Array.isArray(value)) {
-    const pid = integerFor(value, [
-      'processIdentifier',
-      'processID',
-      'pid',
-      'identifier',
-    ]);
-    if (pid != null && matchesProcess(value)) {
-      rows.push({
-        pid,
-        rssKb: memoryKbFor(value),
-        cpuPercent: numberFor(value, [
-          'cpuPercent',
-          'cpuPercentage',
-          'cpuUsage',
-          'percentCPU',
-        ]),
-        command: commandFor(value),
-      });
-    }
-  }
-  for (const child of Object.values(value)) {
-    visit(child);
-  }
-}
-
-function integerFor(record, names) {
-  for (const name of names) {
-    const value = valueFor(record, name);
-    if (Number.isInteger(value) && value > 0) {
-      return value;
-    }
-  }
-  return null;
-}
-
-function numberFor(record, names) {
-  for (const name of names) {
-    const value = valueFor(record, name);
-    if (typeof value === 'number' && Number.isFinite(value)) {
-      return value;
-    }
-  }
-  return null;
-}
-
-function valueFor(record, wanted) {
-  const normalizedWanted = normalizeKey(wanted);
-  for (const [key, value] of Object.entries(record)) {
-    if (normalizeKey(key) === normalizedWanted) {
-      if (typeof value === 'object' && value != null && typeof value.value === 'number') {
-        return value.value;
-      }
-      return value;
-    }
-  }
-  return undefined;
-}
-
-function normalizeKey(key) {
-  return String(key).replace(/[^a-z0-9]/gi, '').toLowerCase();
-}
-
-function matchesProcess(record) {
-  const haystack = Object.values(record)
-    .filter(value => typeof value === 'string')
-    .join('\n')
-    .toLowerCase();
-  return haystack.includes(bundleId.toLowerCase()) ||
-    (processName.length > 0 && haystack.includes(processName)) ||
-    haystack.includes('reactnativeoliphaunt');
-}
-
-function memoryKbFor(record) {
-  for (const [key, value] of Object.entries(record)) {
-    const normalized = normalizeKey(key);
-    if (!/(rss|resident|memory)/.test(normalized)) {
-      continue;
-    }
-    const number = typeof value === 'number'
-      ? value
-      : (typeof value === 'object' && value != null && typeof value.value === 'number'
-        ? value.value
-        : null);
-    if (number == null || !Number.isFinite(number)) {
-      continue;
-    }
-    const unit = typeof value === 'object' && value != null && typeof value.unit === 'string'
-      ? value.unit.toLowerCase()
-      : '';
-    if (unit.includes('byte')) {
-      return Math.round(number / 1024);
-    }
-    if (unit.includes('mb') || unit.includes('mib')) {
-      return Math.round(number * 1024);
-    }
-    return Math.round(number);
-  }
-  return null;
-}
-
-function commandFor(record) {
-  for (const name of ['executableName', 'name', 'command', 'bundleIdentifier', 'bundleID']) {
-    const value = valueFor(record, name);
-    if (typeof value === 'string' && value.length > 0) {
-      return value;
-    }
-  }
-  return bundleId;
-}
-
-visit(data);
-process.stdout.write('pid\trss_kb\tcpu_percent\tcommand\n');
-for (const row of rows.slice(0, 1)) {
-  process.stdout.write([
-    row.pid,
-    row.rssKb ?? '',
-    row.cpuPercent ?? '',
-    String(row.command).replace(/\t/g, ' '),
-  ].join('\t') + '\n');
-}
-NODE
-  if [ -s "$reports_dir/$runner-process.tsv" ]; then
-    cat "$reports_dir/$runner-process.tsv" >&2
-  fi
+  echo "iOS device process report: $json" >&2
 }
 
 logs_have_lifecycle_ready() {
@@ -618,8 +454,7 @@ exercise_ios_crash_recovery() {
 
   if [ -z "$crash_storage_override" ]; then
     case "$crash_storage" in
-      app-data:*)
-        ;;
+      app-data:*) ;;
       /*)
         rm -rf "$crash_storage"
         ;;
@@ -746,8 +581,7 @@ exercise_ios_device_crash_recovery() {
 
   if [ -z "$crash_storage_override" ]; then
     case "$crash_storage" in
-      app-data:*)
-        ;;
+      app-data:*) ;;
       /*)
         rm -rf "$crash_storage"
         ;;
diff --git a/src/sdks/react-native/tools/expo-runner-ios-installed-app.test.sh b/src/sdks/react-native/tools/expo-runner-ios-installed-app.test.sh
new file mode 100644
index 000000000..83e48d5f9
--- /dev/null
+++ b/src/sdks/react-native/tools/expo-runner-ios-installed-app.test.sh
@@ -0,0 +1,121 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+. "$root/src/sdks/react-native/tools/expo-runner-ios-installed-app.sh"
+. "$root/src/sdks/react-native/tools/expo-runner-reporting.sh"
+
+test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-ios-runner-test.XXXXXX")"
+trap 'rm -rf "$test_root"' EXIT
+app="$test_root/fixture.app"
+for profile in standard icu; do
+  rm -rf "$app"
+  seed_name=Standard
+  seed_resource=cluster-seed
+  expected_icu=0
+  if [ "$profile" = icu ]; then
+    seed_name=ICU
+    seed_resource=cluster-seed-icu
+    expected_icu=1
+    mkdir -p "$app/OliphauntICU.bundle/share/icu"
+    printf data >"$app/OliphauntICU.bundle/share/icu/icudt.dat"
+    printf receipt >"$app/OliphauntICU.bundle/manifest.properties"
+  fi
+  seed="$app/OliphauntSeedNativeIOS$seed_name.bundle/$seed_resource"
+  mkdir -p "$seed/files"
+  printf '18\n' >"$seed/files/PG_VERSION"
+  printf 'catalogProfile=%s\n' "$profile" >"$seed/manifest.properties"
+  export_mobile_e2e_icu_expectation_from_ios_app "$app"
+  [ "$OLIPHAUNT_MOBILE_E2E_EXPECT_ICU" = "$expected_icu" ]
+  [ "$OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE" = "$profile" ]
+  other=ICU
+  [ "$seed_name" != ICU ] || other=Standard
+  mkdir "$app/OliphauntSeedNativeIOS$other.bundle"
+  if export_mobile_e2e_icu_expectation_from_ios_app "$app" >/dev/null 2>&1; then
+    echo "iOS app accepted two seed carriers" >&2
+    exit 1
+  fi
+  rmdir "$app/OliphauntSeedNativeIOS$other.bundle"
+  printf 'catalogProfile=wrong\n' >"$seed/manifest.properties"
+  if export_mobile_e2e_icu_expectation_from_ios_app "$app" >/dev/null 2>&1; then
+    echo "iOS app accepted a mismatched seed profile" >&2
+    exit 1
+  fi
+  printf 'catalogProfile=%s\n' "$profile" >"$seed/manifest.properties"
+  rm "$seed/files/PG_VERSION"
+  if export_mobile_e2e_icu_expectation_from_ios_app "$app" >/dev/null 2>&1; then
+    echo "iOS app accepted missing seed data" >&2
+    exit 1
+  fi
+  if [ "$profile" = icu ]; then
+    printf '18\n' >"$seed/files/PG_VERSION"
+    rm "$app/OliphauntICU.bundle/share/icu/icudt.dat"
+    if export_mobile_e2e_icu_expectation_from_ios_app "$app" >/dev/null 2>&1; then
+      echo "iOS app accepted empty ICU data" >&2
+      exit 1
+    fi
+  fi
+done
+scratch_root="$test_root/scratch"
+maestro_flow="$test_root/installed-smoke.yaml"
+app_id="dev.oliphaunt.test"
+runner="smoke"
+mobile_platform="ios"
+timeout_seconds=600
+success_tag="OLIPHAUNT_EXPO_SMOKE_PASS"
+failure_tag="OLIPHAUNT_EXPO_SMOKE_FAIL"
+ios_simulator_log_pid=""
+ios_simulator_log_file="$test_root/simulator.log"
+export CI_HEAD_SHA="$(git rev-parse HEAD)"
+export OLIPHAUNT_MOBILE_E2E_EXPECT_ICU=0
+export OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE=standard
+export FAKE_MAESTRO_STARTED="$test_root/maestro-started"
+export FAKE_MAESTRO_TERMINATED="$test_root/maestro-terminated"
+
+mkdir -p "$scratch_root/reports"
+printf 'appId: dev.oliphaunt.test\n---\n- assertVisible: smoke\n' >"$maestro_flow"
+fake_maestro="$test_root/maestro"
+cat >"$fake_maestro" <<'SH'
+#!/usr/bin/env bash
+trap 'printf "terminated\n" >"$FAKE_MAESTRO_TERMINATED"; exit 143' TERM INT
+printf 'started\n' >"$FAKE_MAESTRO_STARTED"
+while :; do sleep 0.1; done
+SH
+chmod +x "$fake_maestro"
+
+maestro_binary() { printf '%s\n' "$fake_maestro"; }
+ios_simulator_log_capture_is_alive() { return 0; }
+latest_ios_simulator_capture_tag() {
+  [ "$1" = "$failure_tag" ] || return 0
+  local attempts=100
+  while [ "$attempts" -gt 0 ] && [ ! -f "$FAKE_MAESTRO_STARTED" ]; do
+    command sleep 0.01
+    attempts=$((attempts - 1))
+  done
+  printf '%s fixture\n' "$failure_tag"
+}
+
+set +e
+run_maestro_installed_smoke simulator-1 >"$test_root/fail.stdout" 2>"$test_root/fail.stderr"
+status=$?
+set -e
+[ "$status" -eq 2 ]
+[ -f "$FAKE_MAESTRO_TERMINATED" ]
+grep -Fq "$failure_tag" "$scratch_root/reports/maestro-authoritative-failure.txt"
+
+receipt_json="$(
+  bun "$root/src/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts" receipt "$root/src/extensions/generated/sdk/extensions.json"
+)"
+write_runner_report "$success_tag $receipt_json"
+verify_mobile_e2e_smoke_receipt ios "$scratch_root"
+
+bun "$root/src/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts" tamper "$scratch_root/reports/smoke-extension-receipt.json"
+if verify_mobile_e2e_smoke_receipt ios "$scratch_root" >/dev/null 2>&1; then
+  echo "tampered mobile receipt was accepted" >&2
+  exit 1
+fi
+
+echo "iOS runner failure and receipt checks passed"
diff --git a/src/sdks/react-native/tools/expo-runner-reporting.mts b/src/sdks/react-native/tools/expo-runner-reporting.mts
new file mode 100644
index 000000000..16b04a416
--- /dev/null
+++ b/src/sdks/react-native/tools/expo-runner-reporting.mts
@@ -0,0 +1,251 @@
+import * as fs from 'node:fs';
+import * as crypto from 'node:crypto';
+import assert from 'node:assert/strict';
+function extensionReceipt(reportFile, metadataFile, platform, candidateSha, candidateTree) {
+  const payload = JSON.parse(fs.readFileSync(reportFile, 'utf8'));
+  const metadata = JSON.parse(fs.readFileSync(metadataFile, 'utf8'));
+  if (!/^[0-9a-f]{40}$/.test(candidateSha) || !/^[0-9a-f]{40}$/.test(candidateTree)) {
+    throw new Error(
+      `${platform} installed-app receipt requires full candidate commit and tree IDs`,
+    );
+  }
+  if (payload === null || typeof payload !== 'object' || Array.isArray(payload)) {
+    throw new Error(`${platform} app PASS receipt must be a JSON object`);
+  }
+  const expectedKeys = [
+    'allExtensionsActivated',
+    'catalogProfile',
+    'extensionCatalogSha256',
+    'extensionCatalogComplete',
+    'extensionCount',
+    'icuRuntimeProof',
+    'pgTextsearchEnglishBm25',
+    'platform',
+    'runner',
+    'schema',
+  ].sort();
+  const actualKeys = Object.keys(payload).sort();
+  if (JSON.stringify(actualKeys) !== JSON.stringify(expectedKeys)) {
+    throw new Error(
+      `${platform} app PASS receipt keys mismatch: expected=${expectedKeys.join(',')}; actual=${actualKeys.join(',')}`,
+    );
+  }
+  if (
+    payload.schema !== 'oliphaunt-expo-smoke-pass-v4' ||
+    payload.runner !== 'smoke' ||
+    payload.platform !== platform
+  ) {
+    throw new Error(`${platform} app PASS receipt schema, runner, or platform identity mismatch`);
+  }
+  const expectedIcu = process.env.OLIPHAUNT_MOBILE_E2E_EXPECT_ICU;
+  const expectedCatalogProfile = process.env.OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE;
+  if (expectedIcu !== '0' && expectedIcu !== '1') {
+    throw new Error(`${platform} app PASS receipt requires an exact artifact ICU expectation`);
+  }
+  if (payload.icuRuntimeProof !== (expectedIcu === '1')) {
+    throw new Error(
+      `${platform} app PASS ICU runtime proof does not match the exact artifact selection`,
+    );
+  }
+  if (
+    (expectedCatalogProfile !== 'standard' && expectedCatalogProfile !== 'icu') ||
+    payload.catalogProfile !== expectedCatalogProfile
+  ) {
+    throw new Error(
+      `${platform} app PASS catalog profile does not match the selected packaged cluster seed`,
+    );
+  }
+  const passEventBytes = Buffer.byteLength(`OLIPHAUNT_EXPO_SMOKE_PASS ${JSON.stringify(payload)}`);
+  if (passEventBytes > 768) {
+    throw new Error(
+      `${platform} app PASS receipt exceeds the 768-byte unified-log-safe event budget: ${passEventBytes}`,
+    );
+  }
+  const expected = (metadata.extensions ?? []).map((row) => row['sql-name']).sort();
+  if (expected.length === 0 || new Set(expected).size !== expected.length) {
+    throw new Error(
+      `${platform} generated mobile catalog must contain a nonempty unique release extension set`,
+    );
+  }
+  if (
+    payload.extensionCount !== expected.length ||
+    payload.allExtensionsActivated !== true ||
+    payload.extensionCatalogComplete !== true ||
+    payload.pgTextsearchEnglishBm25 !== expected.includes('pg_textsearch')
+  ) {
+    throw new Error(
+      `${platform} app PASS receipt must prove exact activation, catalog completeness, and required functional checks`,
+    );
+  }
+  const catalogSha256 = metadata['extension-catalog-sha256'];
+  if (!/^[0-9a-f]{64}$/.test(catalogSha256) || payload.extensionCatalogSha256 !== catalogSha256) {
+    throw new Error(`${platform} app PASS receipt generated-catalog digest mismatch`);
+  }
+  const receipt = {
+    schema: 'oliphaunt-mobile-installed-extension-proof-v1',
+    platform,
+    catalogProfile: expectedCatalogProfile,
+    candidateSha,
+    candidateTree,
+    extensionCount: expected.length,
+    extensions: expected,
+    extensionCatalogSha256: catalogSha256,
+    appPassPayloadSha256: crypto.createHash('sha256').update(JSON.stringify(payload)).digest('hex'),
+  };
+  return receipt;
+}
+
+const [command, ...args] = process.argv.slice(2);
+switch (command) {
+  case 'json-object': {
+    const file = args[0];
+    const value = JSON.parse(fs.readFileSync(file, 'utf8'));
+    if (value === null || typeof value !== 'object' || Array.isArray(value)) {
+      throw new Error(`${file} must contain a JSON object`);
+    }
+    break;
+  }
+  case 'parse-pass': {
+    const input = process.env.OLIPHAUNT_EXPO_LOG_LINE || fs.readFileSync(0, 'utf8').trim();
+    const tag = process.env.OLIPHAUNT_EXPO_LOG_TAG;
+    let payload;
+
+    function escapeRegExp(value) {
+      return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+    }
+
+    try {
+      const jsonStart = input.indexOf('{');
+      if (jsonStart >= 0) {
+        const event = JSON.parse(input.slice(jsonStart));
+        if (Array.isArray(event.data)) {
+          const index = event.data.indexOf(tag);
+          if (index >= 0) {
+            payload = event.data[index + 1];
+          }
+        }
+      }
+    } catch {}
+
+    if (payload === undefined) {
+      const tagIndex = input.indexOf(tag);
+      if (tagIndex >= 0) {
+        const rest = input.slice(tagIndex + tag.length);
+        const jsonStart = rest.indexOf('{');
+        if (jsonStart >= 0) {
+          payload = rest.slice(jsonStart).trim();
+        }
+      }
+    }
+
+    if (payload === undefined) {
+      const reactNativeMatch = input.match(
+        new RegExp(`ReactNativeJS:\\s*'${escapeRegExp(tag)}',\\s*'([\\s\\S]*)'\\s*$`),
+      );
+      if (reactNativeMatch) {
+        payload = reactNativeMatch[1];
+      }
+    }
+
+    if (typeof payload === 'string') {
+      payload = payload.trim();
+      if (payload.startsWith("'") && payload.endsWith("'")) {
+        payload = payload.slice(1, -1);
+      } else if (payload.endsWith("'")) {
+        payload = payload.slice(0, -1);
+      }
+      payload = JSON.parse(payload);
+    }
+    if (payload === undefined) {
+      process.exit(1);
+    }
+    process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
+    break;
+  }
+  case 'extension-receipt': {
+    process.stdout.write(JSON.stringify(extensionReceipt(...args), null, 2) + '\n');
+    break;
+  }
+  case 'verify-receipt': {
+    const [report, receipt, ...identity] = args;
+    assert.deepEqual(
+      JSON.parse(fs.readFileSync(receipt, 'utf8')),
+      extensionReceipt(report, ...identity),
+      'mobile E2E receipt does not match the current report, catalog and candidate',
+    );
+    break;
+  }
+  case 'maestro-report': {
+    const report = {
+      runner: 'maestro',
+      platform: process.env.OLIPHAUNT_MAESTRO_PLATFORM,
+      appId: process.env.OLIPHAUNT_MAESTRO_APP_ID,
+      flow: process.env.OLIPHAUNT_MAESTRO_FLOW,
+      passedAt: new Date().toISOString(),
+    };
+    process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
+    break;
+  }
+  case 'maestro-pass': {
+    const report = {
+      runner: 'maestro',
+      platform: process.env.OLIPHAUNT_MAESTRO_PLATFORM,
+      appId: process.env.OLIPHAUNT_MAESTRO_APP_ID,
+      flow: process.env.OLIPHAUNT_MAESTRO_FLOW,
+    };
+    process.stdout.write(`OLIPHAUNT_EXPO_MAESTRO_PASS ${JSON.stringify(report)}\n`);
+    break;
+  }
+  case 'package-sizes': {
+    const [report, artifactSizeKey, artifactBytes, rnPackageBytes] = args;
+    const payload = {
+      [artifactSizeKey]: Number(artifactBytes),
+      rnPackageBytes: Number(rnPackageBytes),
+    };
+    fs.writeFileSync(report, `${JSON.stringify(payload, null, 2)}\n`);
+    break;
+  }
+  case 'build-artifact': {
+    const [
+      report,
+      platform,
+      appArtifact,
+      appArtifactBytes,
+      rnPackage,
+      rnPackageBytes,
+      extensions,
+      scratchRoot,
+      ...metadataArgs
+    ] = args;
+
+    if (metadataArgs.length % 2 !== 0) {
+      throw new Error('metadata arguments must be key/value pairs');
+    }
+
+    const metadata = {};
+    for (let index = 0; index < metadataArgs.length; index += 2) {
+      metadata[metadataArgs[index]] = metadataArgs[index + 1];
+    }
+
+    const payload = {
+      schema: 'oliphaunt-react-native-mobile-build-v1',
+      platform,
+      ...metadata,
+      appArtifact,
+      appArtifactBytes: Number(appArtifactBytes),
+      reactNativePackage: rnPackage,
+      reactNativePackageBytes: Number(rnPackageBytes),
+      selectedExtensions: extensions ? extensions.split(',').filter(Boolean) : [],
+      scratchRoot,
+    };
+    fs.writeFileSync(report, `${JSON.stringify(payload, null, 2)}\n`);
+    break;
+  }
+  case 'profile': {
+    const [file, profile, field] = args;
+    process.stdout.write(JSON.parse(fs.readFileSync(file, 'utf8')).profiles[profile][field]);
+    break;
+  }
+  default:
+    throw new Error('unknown expo-runner-reporting command: ' + command);
+}
diff --git a/src/sdks/react-native/tools/expo-runner-reporting.sh b/src/sdks/react-native/tools/expo-runner-reporting.sh
index 148b13802..c5f81ea42 100644
--- a/src/sdks/react-native/tools/expo-runner-reporting.sh
+++ b/src/sdks/react-native/tools/expo-runner-reporting.sh
@@ -6,10 +6,13 @@
 
 configure_mobile_catalog_profile_probe() {
   local profile="$1"
-  local fixture="$root/src/shared/cluster-seed-contract/profile-probe.json"
+  local fixture="$root/src/database-resources/contracts/profile-probe.json"
   case "$profile" in
-    standard|icu) ;;
-    *) echo "unsupported mobile catalog profile: $profile" >&2; return 1 ;;
+    standard | icu) ;;
+    *)
+      echo "unsupported mobile catalog profile: $profile" >&2
+      return 1
+      ;;
   esac
   [ -s "$fixture" ] || {
     echo "mobile catalog profile probe is missing: $fixture" >&2
@@ -17,10 +20,10 @@ configure_mobile_catalog_profile_probe() {
   }
   export EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE="$profile"
   export EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_SQL="$({
-    node -e 'const fs=require("node:fs"); const [file, profile]=process.argv.slice(1); process.stdout.write(JSON.parse(fs.readFileSync(file, "utf8")).profiles[profile].sql);' "$fixture" "$profile"
+    bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" profile "$fixture" "$profile" sql
   })"
   export EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_EXPECTED="$({
-    node -e 'const fs=require("node:fs"); const [file, profile]=process.argv.slice(1); process.stdout.write(JSON.parse(fs.readFileSync(file, "utf8")).profiles[profile].expected);' "$fixture" "$profile"
+    bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" profile "$fixture" "$profile" expected
   })"
 }
 
@@ -32,24 +35,48 @@ require_nonempty_json_file() {
     return 1
   fi
   local json_status=0
-  node - "$file" <<'NODE' >/dev/null || json_status=$?
-const fs = require('node:fs');
-const file = process.argv[2];
-const value = JSON.parse(fs.readFileSync(file, 'utf8'));
-if (value === null || typeof value !== 'object' || Array.isArray(value)) {
-  throw new Error(`${file} must contain a JSON object`);
-}
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" json-object "$file" >/dev/null || json_status=$?
   if [ "$json_status" -ne 0 ]; then
     echo "$label is not valid JSON: $file" >&2
     return 1
   fi
 }
 
+export_mobile_e2e_icu_expectation_from_ios_app() {
+  # iOS keeps the base runtime selection-neutral; CocoaPods installs the
+  # selected ICU and seed carriers as sibling resource bundles.
+  local app="$1"
+  local profile=standard seed_name=Standard seed_resource=cluster-seed
+  local icu="$app/OliphauntICU.bundle"
+  if [ -d "$icu" ]; then
+    profile=icu
+    seed_name=ICU
+    seed_resource=cluster-seed-icu
+    [ -s "$icu/manifest.properties" ] &&
+      [ -n "$(find "$icu/share/icu" -type f -print -quit 2>/dev/null)" ] || {
+      echo "iOS app has an incomplete ICU resource carrier: $icu" >&2
+      return 1
+    }
+  fi
+  local seed="$app/OliphauntSeedNativeIOS$seed_name.bundle/$seed_resource"
+  local other=ICU
+  [ "$seed_name" != ICU ] || other=Standard
+  [ ! -e "$app/OliphauntSeedNativeIOS$other.bundle" ] &&
+    [ -s "$seed/files/PG_VERSION" ] &&
+    [ "$(grep -c '^catalogProfile=' "$seed/manifest.properties" 2>/dev/null || true)" = 1 ] &&
+    grep -Fxq "catalogProfile=$profile" "$seed/manifest.properties" || {
+    echo "iOS app must contain exactly its selected $profile cluster seed carrier: $seed" >&2
+    return 1
+  }
+  export OLIPHAUNT_MOBILE_E2E_EXPECT_ICU=0
+  [ "$profile" != icu ] || export OLIPHAUNT_MOBILE_E2E_EXPECT_ICU=1
+  export OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE="$profile"
+}
+
 export_mobile_e2e_icu_expectation_from_manifest() {
   local manifest="$1"
   local label="$2"
-  local runtime_feature_rows runtime_features seed_manifest catalog_profile
+  local runtime_feature_rows runtime_features seed_manifest other_seed_manifest catalog_profile
   [ -s "$manifest" ] || {
     echo "$label runtime manifest is missing or empty: $manifest" >&2
     return 1
@@ -67,27 +94,34 @@ export_mobile_e2e_icu_expectation_from_manifest() {
     export OLIPHAUNT_MOBILE_E2E_EXPECT_ICU=1
     catalog_profile=icu
     seed_manifest="$(dirname "$(dirname "$manifest")")/cluster-seed-icu/manifest.properties"
+    other_seed_manifest="$(dirname "$(dirname "$manifest")")/cluster-seed/manifest.properties"
   else
     export OLIPHAUNT_MOBILE_E2E_EXPECT_ICU=0
     catalog_profile=standard
     seed_manifest="$(dirname "$(dirname "$manifest")")/cluster-seed/manifest.properties"
+    other_seed_manifest="$(dirname "$(dirname "$manifest")")/cluster-seed-icu/manifest.properties"
   fi
-  [ -s "$seed_manifest" ] || {
-    echo "$label selected cluster-seed manifest is missing or empty: $seed_manifest" >&2
+  [ ! -e "$other_seed_manifest" ] || {
+    echo "$label includes a cluster seed incompatible with catalogProfile=$catalog_profile" >&2
     return 1
   }
-  [ "$(grep -c '^catalogProfile=' "$seed_manifest" || true)" = "1" ] &&
-    grep -Fxq "catalogProfile=$catalog_profile" "$seed_manifest" || {
+  # This is the assembled app's resource manifest. ICU selection determines the
+  # expected catalog, but reopening an existing database does not require a seed.
+  # Runners creating a new database separately require their requested seed.
+  if [ -e "$seed_manifest" ]; then
+    if [ "$(grep -c '^catalogProfile=' "$seed_manifest" || true)" != "1" ] ||
+      ! grep -Fxq "catalogProfile=$catalog_profile" "$seed_manifest"; then
       echo "$label selected cluster seed does not declare catalogProfile=$catalog_profile" >&2
       return 1
-    }
+    fi
+  fi
   export OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE="$catalog_profile"
 }
 
 export_mobile_e2e_icu_expectation_from_android_apk() {
   local apk="$1"
   local label="$2"
-  local extracted manifest
+  local extracted manifest member
   [ -f "$apk" ] || {
     echo "$label is missing: $apk" >&2
     return 1
@@ -97,17 +131,20 @@ export_mobile_e2e_icu_expectation_from_android_apk() {
     return 1
   }
   manifest="$extracted/runtime/manifest.properties"
-  mkdir -p "$extracted/runtime" "$extracted/cluster-seed" "$extracted/cluster-seed-icu"
+  mkdir -p "$extracted/runtime"
   local extract_status=0
   unzip -p "$apk" "assets/oliphaunt/runtime/manifest.properties" >"$manifest" ||
     extract_status=$?
-  unzip -p "$apk" "assets/oliphaunt/cluster-seed/manifest.properties" >"$extracted/cluster-seed/manifest.properties" ||
-    extract_status=$?
-  unzip -p "$apk" "assets/oliphaunt/cluster-seed-icu/manifest.properties" >"$extracted/cluster-seed-icu/manifest.properties" ||
-    extract_status=$?
+  zipinfo -1 "$apk" >"$extracted/members" || extract_status=$?
+  for member in cluster-seed cluster-seed-icu; do
+    if grep -Fxq "assets/oliphaunt/$member/manifest.properties" "$extracted/members"; then
+      mkdir -p "$extracted/$member"
+      unzip -p "$apk" "assets/oliphaunt/$member/manifest.properties" >"$extracted/$member/manifest.properties" || extract_status=$?
+    fi
+  done
   if [ "$extract_status" -ne 0 ]; then
     rm -rf "$extracted"
-    echo "$label is missing its runtime or cluster-seed manifest: $apk" >&2
+    echo "$label resource manifests could not be read: $apk" >&2
     return 1
   fi
   local expectation_status=0
@@ -151,63 +188,7 @@ write_runner_report() {
   local parse_status=0
   OLIPHAUNT_EXPO_LOG_TAG="$success_tag" \
     OLIPHAUNT_EXPO_LOG_LINE="$line" \
-    node <<'NODE' >"$report_tmp" || parse_status=$?
-const fs = require('fs');
-const input = process.env.OLIPHAUNT_EXPO_LOG_LINE || fs.readFileSync(0, 'utf8').trim();
-const tag = process.env.OLIPHAUNT_EXPO_LOG_TAG;
-let payload;
-
-function escapeRegExp(value) {
-  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
-}
-
-try {
-  const jsonStart = input.indexOf('{');
-  if (jsonStart >= 0) {
-    const event = JSON.parse(input.slice(jsonStart));
-    if (Array.isArray(event.data)) {
-      const index = event.data.indexOf(tag);
-      if (index >= 0) {
-        payload = event.data[index + 1];
-      }
-    }
-  }
-} catch {}
-
-if (payload === undefined) {
-  const tagIndex = input.indexOf(tag);
-  if (tagIndex >= 0) {
-    const rest = input.slice(tagIndex + tag.length);
-    const jsonStart = rest.indexOf('{');
-    if (jsonStart >= 0) {
-      payload = rest.slice(jsonStart).trim();
-    }
-  }
-}
-
-if (payload === undefined) {
-  const reactNativeMatch = input.match(
-    new RegExp(`ReactNativeJS:\\s*'${escapeRegExp(tag)}',\\s*'([\\s\\S]*)'\\s*$`),
-  );
-  if (reactNativeMatch) {
-    payload = reactNativeMatch[1];
-  }
-}
-
-if (typeof payload === 'string') {
-  payload = payload.trim();
-  if (payload.startsWith("'") && payload.endsWith("'")) {
-    payload = payload.slice(1, -1);
-  } else if (payload.endsWith("'")) {
-    payload = payload.slice(0, -1);
-  }
-  payload = JSON.parse(payload);
-}
-if (payload === undefined) {
-  process.exit(1);
-}
-process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
-NODE
+    bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" parse-pass >"$report_tmp" || parse_status=$?
   if [ "$parse_status" -ne 0 ]; then
     rm -f "$pass_tmp" "$report_tmp" "$report" "$receipt" || true
     echo "failed to parse the authoritative $runner PASS payload" >&2
@@ -276,83 +257,7 @@ verify_mobile_extension_smoke_receipt() {
     return 1
   fi
   local receipt_status=0
-  node - "$report" "$metadata" "$platform" "$candidate_sha" "$candidate_tree" <<'NODE' >"$receipt_tmp" || receipt_status=$?
-const fs = require('node:fs');
-const crypto = require('node:crypto');
-const [reportFile, metadataFile, platform, candidateSha, candidateTree] = process.argv.slice(2);
-const payload = JSON.parse(fs.readFileSync(reportFile, 'utf8'));
-const metadata = JSON.parse(fs.readFileSync(metadataFile, 'utf8'));
-if (!/^[0-9a-f]{40}$/.test(candidateSha) || !/^[0-9a-f]{40}$/.test(candidateTree)) {
-  throw new Error(`${platform} installed-app receipt requires full candidate commit and tree IDs`);
-}
-if (payload === null || typeof payload !== 'object' || Array.isArray(payload)) {
-  throw new Error(`${platform} app PASS receipt must be a JSON object`);
-}
-const expectedKeys = [
-  'allExtensionsActivated',
-  'catalogProfile',
-  'extensionCatalogSha256',
-  'extensionCatalogComplete',
-  'extensionCount',
-  'icuRuntimeProof',
-  'pgTextsearchEnglishBm25',
-  'platform',
-  'runner',
-  'schema',
-].sort();
-const actualKeys = Object.keys(payload).sort();
-if (JSON.stringify(actualKeys) !== JSON.stringify(expectedKeys)) {
-  throw new Error(`${platform} app PASS receipt keys mismatch: expected=${expectedKeys.join(',')}; actual=${actualKeys.join(',')}`);
-}
-if (payload.schema !== 'oliphaunt-expo-smoke-pass-v4' || payload.runner !== 'smoke' || payload.platform !== platform) {
-  throw new Error(`${platform} app PASS receipt schema, runner, or platform identity mismatch`);
-}
-const expectedIcu = process.env.OLIPHAUNT_MOBILE_E2E_EXPECT_ICU;
-const expectedCatalogProfile = process.env.OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE;
-if (expectedIcu !== '0' && expectedIcu !== '1') {
-  throw new Error(`${platform} app PASS receipt requires an exact artifact ICU expectation`);
-}
-if (payload.icuRuntimeProof !== (expectedIcu === '1')) {
-  throw new Error(`${platform} app PASS ICU runtime proof does not match the exact artifact selection`);
-}
-if ((expectedCatalogProfile !== 'standard' && expectedCatalogProfile !== 'icu') || payload.catalogProfile !== expectedCatalogProfile) {
-  throw new Error(`${platform} app PASS catalog profile does not match the selected packaged cluster seed`);
-}
-const passEventBytes = Buffer.byteLength(`OLIPHAUNT_EXPO_SMOKE_PASS ${JSON.stringify(payload)}`);
-if (passEventBytes > 768) {
-  throw new Error(`${platform} app PASS receipt exceeds the 768-byte unified-log-safe event budget: ${passEventBytes}`);
-}
-const expected = (metadata.extensions ?? [])
-  .map(row => row['sql-name'])
-  .sort();
-if (expected.length === 0 || new Set(expected).size !== expected.length) {
-  throw new Error(`${platform} generated mobile catalog must contain a nonempty unique release extension set`);
-}
-if (
-  payload.extensionCount !== expected.length ||
-  payload.allExtensionsActivated !== true ||
-  payload.extensionCatalogComplete !== true ||
-  payload.pgTextsearchEnglishBm25 !== expected.includes('pg_textsearch')
-) {
-  throw new Error(`${platform} app PASS receipt must prove exact activation, catalog completeness, and required functional checks`);
-}
-const catalogSha256 = metadata['extension-catalog-sha256'];
-if (!/^[0-9a-f]{64}$/.test(catalogSha256) || payload.extensionCatalogSha256 !== catalogSha256) {
-  throw new Error(`${platform} app PASS receipt generated-catalog digest mismatch`);
-}
-const receipt = {
-  schema: 'oliphaunt-mobile-installed-extension-proof-v1',
-  platform,
-  catalogProfile: expectedCatalogProfile,
-  candidateSha,
-  candidateTree,
-  extensionCount: expected.length,
-  extensions: expected,
-  extensionCatalogSha256: catalogSha256,
-  appPassPayloadSha256: crypto.createHash('sha256').update(JSON.stringify(payload)).digest('hex'),
-};
-process.stdout.write(`${JSON.stringify(receipt, null, 2)}\n`);
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" extension-receipt "$report" "$metadata" "$platform" "$candidate_sha" "$candidate_tree" >"$receipt_tmp" || receipt_status=$?
   if [ "$receipt_status" -ne 0 ]; then
     rm -f "$receipt_tmp" "$receipt" || true
     echo "$platform installed-app extension receipt verification failed" >&2
@@ -394,95 +299,7 @@ verify_mobile_e2e_smoke_receipt() {
   fi
 
   local verify_status=0
-  node - "$report" "$receipt" "$metadata" "$platform" "$candidate_sha" "$candidate_tree" <<'NODE' >/dev/null || verify_status=$?
-const fs = require('node:fs');
-const crypto = require('node:crypto');
-const [reportFile, receiptFile, metadataFile, platform, candidateSha, candidateTree] = process.argv.slice(2);
-const report = JSON.parse(fs.readFileSync(reportFile, 'utf8'));
-const receipt = JSON.parse(fs.readFileSync(receiptFile, 'utf8'));
-const metadata = JSON.parse(fs.readFileSync(metadataFile, 'utf8'));
-const expectedReportKeys = [
-  'allExtensionsActivated',
-  'catalogProfile',
-  'extensionCatalogSha256',
-  'extensionCatalogComplete',
-  'extensionCount',
-  'icuRuntimeProof',
-  'pgTextsearchEnglishBm25',
-  'platform',
-  'runner',
-  'schema',
-].sort();
-const actualReportKeys = Object.keys(report).sort();
-if (JSON.stringify(actualReportKeys) !== JSON.stringify(expectedReportKeys)) {
-  throw new Error(`${platform} mobile E2E PASS report keys mismatch`);
-}
-const expectedIcu = process.env.OLIPHAUNT_MOBILE_E2E_EXPECT_ICU;
-const expectedCatalogProfile = process.env.OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE;
-if (expectedIcu !== '0' && expectedIcu !== '1') {
-  throw new Error(`${platform} mobile E2E PASS report requires an exact artifact ICU expectation`);
-}
-if (report.icuRuntimeProof !== (expectedIcu === '1')) {
-  throw new Error(`${platform} mobile E2E ICU runtime proof does not match the exact artifact selection`);
-}
-if ((expectedCatalogProfile !== 'standard' && expectedCatalogProfile !== 'icu') || report.catalogProfile !== expectedCatalogProfile) {
-  throw new Error(`${platform} mobile E2E catalog profile does not match the selected packaged cluster seed`);
-}
-const expectedKeys = [
-  'appPassPayloadSha256',
-  'candidateSha',
-  'candidateTree',
-  'catalogProfile',
-  'extensionCatalogSha256',
-  'extensionCount',
-  'extensions',
-  'platform',
-  'schema',
-].sort();
-const actualKeys = Object.keys(receipt).sort();
-if (JSON.stringify(actualKeys) !== JSON.stringify(expectedKeys)) {
-  throw new Error(`${platform} mobile E2E extension receipt keys mismatch`);
-}
-if (
-  receipt.schema !== 'oliphaunt-mobile-installed-extension-proof-v1' ||
-  receipt.platform !== platform ||
-  receipt.candidateSha !== candidateSha ||
-  receipt.candidateTree !== candidateTree
-) {
-  throw new Error(`${platform} mobile E2E receipt is not bound to the current commit and tree`);
-}
-if (receipt.catalogProfile !== expectedCatalogProfile) {
-  throw new Error(`${platform} mobile E2E receipt catalog profile mismatch`);
-}
-const expected = (metadata.extensions ?? [])
-  .map(row => row['sql-name'])
-  .sort();
-if (
-  expected.length === 0 ||
-  report.schema !== 'oliphaunt-expo-smoke-pass-v4' ||
-  report.runner !== 'smoke' ||
-  report.platform !== platform ||
-  report.extensionCount !== expected.length ||
-  report.allExtensionsActivated !== true ||
-  report.extensionCatalogComplete !== true ||
-  report.pgTextsearchEnglishBm25 !== expected.includes('pg_textsearch') ||
-  report.extensionCatalogSha256 !== metadata['extension-catalog-sha256'] ||
-  Buffer.byteLength(`OLIPHAUNT_EXPO_SMOKE_PASS ${JSON.stringify(report)}`) > 768 ||
-  receipt.extensionCount !== expected.length ||
-  !Array.isArray(receipt.extensions) ||
-  JSON.stringify(receipt.extensions) !== JSON.stringify(expected)
-) {
-  throw new Error(`${platform} mobile E2E receipt does not prove the exact generated extension set`);
-}
-if (
-  !/^[0-9a-f]{64}$/.test(receipt.extensionCatalogSha256) ||
-  receipt.extensionCatalogSha256 !== metadata['extension-catalog-sha256'] ||
-  !/^[0-9a-f]{64}$/.test(receipt.appPassPayloadSha256) ||
-  receipt.appPassPayloadSha256 !== crypto.createHash('sha256').update(JSON.stringify(report)).digest('hex')
-) {
-  throw new Error(`${platform} mobile E2E report/receipt digest mismatch`);
-}
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" verify-receipt "$report" "$receipt" "$metadata" "$platform" "$candidate_sha" "$candidate_tree" >/dev/null || verify_status=$?
   if [ "$verify_status" -ne 0 ]; then
     echo "$platform mobile E2E extension receipt failed its outer postcondition: $receipt" >&2
     return 1
@@ -497,28 +314,11 @@ write_maestro_runner_report() {
   OLIPHAUNT_MAESTRO_PLATFORM="$platform" \
     OLIPHAUNT_MAESTRO_APP_ID="$app_id" \
     OLIPHAUNT_MAESTRO_FLOW="$maestro_flow" \
-    node <<'NODE' >"$reports_dir/$runner-report.json"
-const report = {
-  runner: 'maestro',
-  platform: process.env.OLIPHAUNT_MAESTRO_PLATFORM,
-  appId: process.env.OLIPHAUNT_MAESTRO_APP_ID,
-  flow: process.env.OLIPHAUNT_MAESTRO_FLOW,
-  passedAt: new Date().toISOString(),
-};
-process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
-NODE
+    bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" maestro-report >"$reports_dir/$runner-report.json"
   OLIPHAUNT_MAESTRO_PLATFORM="$platform" \
     OLIPHAUNT_MAESTRO_APP_ID="$app_id" \
     OLIPHAUNT_MAESTRO_FLOW="$maestro_flow" \
-    node <<'NODE' >"$reports_dir/$runner-pass.log"
-const report = {
-  runner: 'maestro',
-  platform: process.env.OLIPHAUNT_MAESTRO_PLATFORM,
-  appId: process.env.OLIPHAUNT_MAESTRO_APP_ID,
-  flow: process.env.OLIPHAUNT_MAESTRO_FLOW,
-};
-process.stdout.write(`OLIPHAUNT_EXPO_MAESTRO_PASS ${JSON.stringify(report)}\n`);
-NODE
+    bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" maestro-pass >"$reports_dir/$runner-pass.log"
 }
 
 write_mobile_package_size_report() {
@@ -527,15 +327,7 @@ write_mobile_package_size_report() {
   local rn_package_bytes="$3"
   local reports_dir="$scratch_root/reports"
   mkdir -p "$reports_dir"
-  node - "$reports_dir/$runner-package-sizes.json" "$artifact_size_key" "$artifact_bytes" "$rn_package_bytes" <<'NODE'
-const fs = require('node:fs');
-const [report, artifactSizeKey, artifactBytes, rnPackageBytes] = process.argv.slice(2);
-const payload = {
-  [artifactSizeKey]: Number(artifactBytes),
-  rnPackageBytes: Number(rnPackageBytes),
-};
-fs.writeFileSync(report, `${JSON.stringify(payload, null, 2)}\n`);
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" package-sizes "$reports_dir/$runner-package-sizes.json" "$artifact_size_key" "$artifact_bytes" "$rn_package_bytes"
 }
 
 write_mobile_build_artifact_report_json() {
@@ -548,40 +340,5 @@ write_mobile_build_artifact_report_json() {
   local selected_extensions="$7"
   local report_scratch_root="$8"
   shift 8
-  node - "$report" "$platform" "$artifact" "$artifact_bytes" "$rn_package" "$rn_package_bytes" "$selected_extensions" "$report_scratch_root" "$@" <<'NODE'
-const fs = require('node:fs');
-const [
-  report,
-  platform,
-  appArtifact,
-  appArtifactBytes,
-  rnPackage,
-  rnPackageBytes,
-  extensions,
-  scratchRoot,
-  ...metadataArgs
-] = process.argv.slice(2);
-
-if (metadataArgs.length % 2 !== 0) {
-  throw new Error('metadata arguments must be key/value pairs');
-}
-
-const metadata = {};
-for (let index = 0; index < metadataArgs.length; index += 2) {
-  metadata[metadataArgs[index]] = metadataArgs[index + 1];
-}
-
-const payload = {
-  schema: 'oliphaunt-react-native-mobile-build-v1',
-  platform,
-  ...metadata,
-  appArtifact,
-  appArtifactBytes: Number(appArtifactBytes),
-  reactNativePackage: rnPackage,
-  reactNativePackageBytes: Number(rnPackageBytes),
-  selectedExtensions: extensions ? extensions.split(',').filter(Boolean) : [],
-  scratchRoot,
-};
-fs.writeFileSync(report, `${JSON.stringify(payload, null, 2)}\n`);
-NODE
+  bun "$root/src/sdks/react-native/tools/expo-runner-reporting.mts" build-artifact "$report" "$platform" "$artifact" "$artifact_bytes" "$rn_package" "$rn_package_bytes" "$selected_extensions" "$report_scratch_root" "$@"
 }
diff --git a/src/sdks/react-native/tools/expo-runner-runtime-resources.sh b/src/sdks/react-native/tools/expo-runner-runtime-resources.sh
index 26aa95498..97a9f28b9 100644
--- a/src/sdks/react-native/tools/expo-runner-runtime-resources.sh
+++ b/src/sdks/react-native/tools/expo-runner-runtime-resources.sh
@@ -7,6 +7,12 @@
 
 expo_runner_runtime_resources_script="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
 
+require_mobile_runtime_data() {
+  local runtime_source="$1" configured_env="$2" producer="$3"
+  [ -f "$runtime_source/share/postgresql/postgres.bki" ] ||
+    fail "mobile runtime data is missing at $runtime_source; run moon run $producer or set $configured_env to its prepared install directory"
+}
+
 mobile_cluster_seed_target() {
   case "$1" in
     iOS) printf '%s\n' ios-datum64 ;;
@@ -15,85 +21,35 @@ mobile_cluster_seed_target() {
   esac
 }
 
-require_exact_cluster_seed_manifest_keys() {
-  local manifest="$1" actual expected
-  actual="$(sed '/^$/d;/^#/d' "$manifest" | sed -n '/^[^=][^=]*=/s/=.*//p' | LC_ALL=C sort)"
-  expected="$(printf '%s\n' artifactRole cacheKey catalogProfile compatibilityKey icuDataForm icuDataTreeSha256 icuDataVersion initialSuperuser layout physicalFormat postgresMajor runtimeFeatures schema target | LC_ALL=C sort)"
-  [ "$actual" = "$expected" ] &&
-    [ "$(sed '/^$/d;/^#/d' "$manifest" | wc -l | tr -d ' ')" = 14 ] ||
-    fail "$manifest does not contain the exact canonical cluster-seed fields"
-}
-
-require_mobile_runtime_seed_closure() {
-  local platform="$1" configured="$2" configured_env="$3" target root receipt expected
+require_mobile_seed() {
+  local platform="$1" configured="$2" configured_env="$3" profile="$4" icu_data="$5" target
   target="$(mobile_cluster_seed_target "$platform")"
-  [ -n "$configured" ] ||
-    fail "$configured_env must name a target-qualified $target runtime-resource closure; arbitrary host PGDATA is not a supported seed for $platform"
-  root="$configured"
-  [ -d "$root/oliphaunt" ] && root="$root/oliphaunt"
-  receipt="$root/manifest.properties"
-  [ -f "$receipt" ] || fail "$configured_env is missing the runtime-carrier receipt: $receipt"
-  expected="$(printf 'schema=oliphaunt-native-runtime-carrier-v1\nclusterSeedTarget=%s\nclusterSeedRelativePath=cluster-seed\nicuClusterSeedRelativePath=cluster-seed-icu\n' "$target")"
-  [ "$(cat "$receipt")" = "$expected" ] ||
-    fail "$configured_env does not contain the exact $target runtime-carrier receipt"
-  local name profile role manifest
-  for name in cluster-seed cluster-seed-icu; do
-    [ "$name" = cluster-seed ] && profile=standard || profile=icu
-    role="cluster-seed-$profile"
-    manifest="$root/$name/manifest.properties"
-    [ -f "$root/$name/files/PG_VERSION" ] && [ -f "$root/$name/files/global/pg_control" ] ||
-      fail "$configured_env is missing the complete $name payload"
-    require_exact_cluster_seed_manifest_keys "$manifest"
-    grep -Fxq "schema=oliphaunt-runtime-resources-v1" "$manifest" &&
-      grep -Fxq "layout=oliphaunt-cluster-seed-v1" "$manifest" &&
-      grep -Fxq "artifactRole=$role" "$manifest" &&
-      grep -Fxq "catalogProfile=$profile" "$manifest" &&
-      grep -Fxq "postgresMajor=18" "$manifest" &&
-      grep -Fxq "physicalFormat=native-pg18-v1" "$manifest" &&
-      grep -Fxq "target=$target" "$manifest" &&
-      grep -Fxq "compatibilityKey=native-pg18-$target-v1" "$manifest" &&
-    grep -Fxq "initialSuperuser=postgres" "$manifest" ||
-      fail "$configured_env contains an incompatible $name manifest"
-    grep -Eq '^cacheKey=[A-Za-z0-9._-]{1,128}$' "$manifest" ||
-      fail "$configured_env contains an invalid $name cache key"
-    ! grep -Eq '^cacheKey=\.{1,2}$' "$manifest" ||
-      fail "$configured_env contains an invalid $name cache key"
-    if [ "$profile" = icu ]; then
-      grep -Fxq runtimeFeatures=icu "$manifest" &&
-        grep -Fxq icuDataVersion=76.1 "$manifest" &&
-        grep -Fxq icuDataForm=files-le "$manifest" &&
-        grep -Eq '^icuDataTreeSha256=[0-9a-f]{64}$' "$manifest" ||
-        fail "$configured_env contains an incompatible ICU cluster seed"
-    else
-      grep -Fxq runtimeFeatures= "$manifest" &&
-        grep -Fxq icuDataVersion= "$manifest" &&
-        grep -Fxq icuDataForm= "$manifest" &&
-        grep -Fxq icuDataTreeSha256= "$manifest" ||
-        fail "$configured_env contains an incompatible standard cluster seed"
-    fi
-  done
-  printf '%s\n' "$root"
+  [ -n "$configured" ] || fail "$configured_env must name the selected database-resources seed directory for $target"
+  local -a args=(--profile "$profile" --target "$target" --seed "$configured")
+  [ "$profile" != icu ] || args+=(--icu-data "$icu_data")
+  bun "$root/src/database-resources/contracts/native-manifest.mts" "${args[@]}" >/dev/null
+  printf '%s\n' "$configured"
 }
 
-install_mobile_runtime_seed_closure() {
-  local package_root="$1" closure="$2"
+install_mobile_seed() {
+  local package_root="$1" seed="$2" profile name
+  profile="$(sed -n 's/^catalogProfile=//p' "$seed/manifest.properties")"
+  [ "$profile" = icu ] && name=cluster-seed-icu || name=cluster-seed
   rm -rf "$package_root/oliphaunt/cluster-seed" "$package_root/oliphaunt/cluster-seed-icu"
-  cp "$closure/manifest.properties" "$package_root/oliphaunt/manifest.properties"
-  cp -R "$closure/cluster-seed" "$package_root/oliphaunt/cluster-seed"
-  cp -R "$closure/cluster-seed-icu" "$package_root/oliphaunt/cluster-seed-icu"
+  cp -R "$seed" "$package_root/oliphaunt/$name"
 }
 
-bind_mobile_runtime_manifest_to_seed_closure() {
-  local package_root="$1" closure="$2" manifest target features digest seed_digest temporary
+bind_mobile_runtime_manifest_to_seed() {
+  local package_root="$1" seed="$2" manifest target features digest seed_digest temporary
   manifest="$package_root/oliphaunt/runtime/manifest.properties"
-  target="$(sed -n 's/^clusterSeedTarget=//p' "$closure/manifest.properties")"
+  target="$(sed -n 's/^target=//p' "$seed/manifest.properties")"
   features="$(sed -n 's/^runtimeFeatures=//p' "$manifest")"
   digest="$(sed -n 's/^icuDataTreeSha256=//p' "$manifest")"
-  seed_digest="$(sed -n 's/^icuDataTreeSha256=//p' "$closure/cluster-seed-icu/manifest.properties")"
+  seed_digest="$(sed -n 's/^icuDataTreeSha256=//p' "$seed/manifest.properties")"
   if [ "$features" = icu ]; then
-    [ -n "$digest" ] && [ "$digest" = "$seed_digest" ] ||
-      fail "staged mobile ICU runtime does not match the canonical $target ICU cluster seed"
+    [ -n "$digest" ] && [ "$digest" = "$seed_digest" ] || fail "staged mobile ICU runtime does not match its selected seed"
   else
+    [ -z "$seed_digest" ] || fail "ICU seed requires ICU runtime data"
     digest=""
   fi
   temporary="$manifest.tmp.$$"
@@ -132,7 +88,7 @@ copy_mobile_runtime_files() {
 prepare_mobile_runtime_resource_package() {
   local platform="$1"
   local runtime_source="$2"
-  local seed_closure="$3"
+  local seed="$3"
   local static_registry_source="$4"
   local selected_extensions="$5"
   local repackage_assets="$6"
@@ -151,7 +107,7 @@ prepare_mobile_runtime_resource_package() {
   local prepared_stamp="$package_root/.prepared"
   local current_sources
   current_sources="$(
-    printf '%s\n%s\nruntime-layout=mobile-minimal-v1\nextensions=%s\n' "$runtime_source" "$seed_closure" "$selected_extensions"
+    printf '%s\n%s\nruntime-layout=mobile-minimal-v1\nextensions=%s\n' "$runtime_source" "$seed" "$selected_extensions"
     [ -n "$static_registry_source" ] && shasum -a 256 "$static_registry_source"
     shasum -a 256 "$root/src/extensions/generated/mobile/static-registry.json"
     oliphaunt_dev_hash_mobile_runtime_extension_assets "$runtime_source" "$selected_extensions"
@@ -159,13 +115,13 @@ prepare_mobile_runtime_resource_package() {
       "$script_path" \
       "$expo_runner_runtime_resources_script" \
       "$root/src/sdks/react-native/tools/mobile-extension-runtime.sh" \
-      "$root/src/sdks/react-native/tools/validate-mobile-runtime-files.mjs"
+      "$root/src/sdks/react-native/tools/validate-mobile-runtime-files.mts"
   )"
   if [ "$repackage_assets" != "1" ] &&
     [ -f "$prepared_stamp" ] &&
     [ -f "$source_stamp" ] &&
     [ "$current_sources" = "$(cat "$source_stamp")" ] &&
-    [ -z "$(find "$runtime_source" "$seed_closure" -type f -newer "$prepared_stamp" -print)" ]; then
+    [ -z "$(find "$runtime_source" "$seed" -type f -newer "$prepared_stamp" -print)" ]; then
     echo "Reusing $platform runtime resources: $package_root" >&2
     printf '%s\n' "$package_root"
     return
@@ -175,7 +131,7 @@ prepare_mobile_runtime_resource_package() {
   local static_registry_dest="$package_root/oliphaunt/static-registry"
   rm -rf "$package_root"
   mkdir -p "$runtime_dest" "$static_registry_dest" "$package_root/oliphaunt"
-  install_mobile_runtime_seed_closure "$package_root" "$seed_closure"
+  install_mobile_seed "$package_root" "$seed"
 
   copy_mobile_runtime_files "$runtime_source" "$runtime_dest"
   oliphaunt_dev_copy_mobile_runtime_extension_assets "$runtime_source" "$runtime_dest" "$selected_extensions"
@@ -218,19 +174,23 @@ prepare_mobile_runtime_resource_package() {
 
   local runtime_bytes standard_seed_bytes icu_seed_bytes total_bytes runtime_files standard_seed_files icu_seed_files total_files
   runtime_bytes="$(directory_bytes "$runtime_dest")"
-  standard_seed_bytes="$(directory_bytes "$package_root/oliphaunt/cluster-seed/files")"
-  icu_seed_bytes="$(directory_bytes "$package_root/oliphaunt/cluster-seed-icu/files")"
+  standard_seed_bytes=0
+  [ ! -d "$package_root/oliphaunt/cluster-seed/files" ] || standard_seed_bytes="$(directory_bytes "$package_root/oliphaunt/cluster-seed/files")"
+  icu_seed_bytes=0
+  [ ! -d "$package_root/oliphaunt/cluster-seed-icu/files" ] || icu_seed_bytes="$(directory_bytes "$package_root/oliphaunt/cluster-seed-icu/files")"
   static_registry_bytes="$(directory_bytes "$static_registry_dest")"
   total_bytes=$((runtime_bytes + standard_seed_bytes + icu_seed_bytes + static_registry_bytes))
   runtime_files="$(directory_files "$runtime_dest")"
-  standard_seed_files="$(directory_files "$package_root/oliphaunt/cluster-seed/files")"
-  icu_seed_files="$(directory_files "$package_root/oliphaunt/cluster-seed-icu/files")"
+  standard_seed_files=0
+  [ ! -d "$package_root/oliphaunt/cluster-seed/files" ] || standard_seed_files="$(directory_files "$package_root/oliphaunt/cluster-seed/files")"
+  icu_seed_files=0
+  [ ! -d "$package_root/oliphaunt/cluster-seed-icu/files" ] || icu_seed_files="$(directory_files "$package_root/oliphaunt/cluster-seed-icu/files")"
   static_registry_files="$(directory_files "$static_registry_dest")"
   total_files=$((runtime_files + standard_seed_files + icu_seed_files + static_registry_files))
 
   local runtime_key cluster_seed_target
   runtime_key="$(directory_fingerprint "$runtime_dest")"
-  cluster_seed_target="$(sed -n 's/^clusterSeedTarget=//p' "$seed_closure/manifest.properties")"
+  cluster_seed_target="$(sed -n 's/^target=//p' "$seed/manifest.properties")"
 
   mkdir -p "$package_root/oliphaunt/runtime"
   cat >"$package_root/oliphaunt/runtime/manifest.properties" <"$log" 2>&1; then
-    tail -120 "$log" >&2 || true
-    fail "failed to build host PostgreSQL runtime assets for mobile packaging; see $log"
-  fi
-  if ! host_runtime_ready "$runtime_source"; then
-    tail -120 "$log" >&2 || true
-    fail "host PostgreSQL runtime assets are incomplete after build: $runtime_source"
-  fi
-  printf '%s\n' "$runtime_source"
-}
-
-normalize_cluster_seed() {
-  local pgdata="$1"
-  local conf="$pgdata/postgresql.conf"
-  [ -f "$conf" ] || return 0
-
-  local tmp="$conf.liboliphaunt-normalized"
-  awk '
-    /^[[:space:]]*dynamic_shared_memory_type[[:space:]]*=/ {
-      print "dynamic_shared_memory_type = mmap"
-      next
-    }
-    /^[[:space:]]*log_timezone[[:space:]]*=/ {
-      print "log_timezone = '\''UTC'\''"
-      next
-    }
-    /^[[:space:]]*timezone[[:space:]]*=/ {
-      print "timezone = '\''UTC'\''"
-      next
-    }
-    /^[[:space:]]*lc_messages[[:space:]]*=/ {
-      print "lc_messages = '\''C'\''"
-      next
-    }
-    /^[[:space:]]*lc_monetary[[:space:]]*=/ {
-      print "lc_monetary = '\''C'\''"
-      next
-    }
-    /^[[:space:]]*lc_numeric[[:space:]]*=/ {
-      print "lc_numeric = '\''C'\''"
-      next
-    }
-    /^[[:space:]]*lc_time[[:space:]]*=/ {
-      print "lc_time = '\''C'\''"
-      next
-    }
-    { print }
-  ' "$conf" > "$tmp"
-  mv "$tmp" "$conf"
-}
-
-ensure_mobile_tool_executable() {
-  local tool="$1"
-  [ -n "$tool" ] || return 0
-  [ -f "$tool" ] || return 0
-  [ -x "$tool" ] && return 0
-  chmod u+x "$tool" ||
-    fail "mobile runtime tool is not executable and could not be repaired: $tool"
-}
-
-ensure_mobile_runtime_tool_permissions() {
-  local runtime_source="$1"
-  local tool
-  for tool in postgres initdb pg_ctl pg_dump psql; do
-    ensure_mobile_tool_executable "$runtime_source/bin/$tool"
-  done
-}
-
 directory_fingerprint() {
   local dir="$1"
   (
@@ -147,55 +26,47 @@ directory_fingerprint() {
 
 patch_expo_example_react_native_dependency() {
   local dependency_spec="$1"
-  node - "$example_dir/package.json" "$dependency_spec" <<'NODE'
-const fs = require('node:fs');
-const [packageJson, dependencySpec] = process.argv.slice(2);
-const pkg = JSON.parse(fs.readFileSync(packageJson, 'utf8'));
-pkg.dependencies ??= {};
-pkg.dependencies['@oliphaunt/react-native'] = dependencySpec;
-fs.writeFileSync(packageJson, `${JSON.stringify(pkg, null, 2)}\n`);
-NODE
+  if expo_requires_sdk_artifacts; then
+    local query_artifact
+    query_artifact="$(expo_single_sdk_artifact_file oliphaunt-query-ts '*.tgz')" || return
+    bun "$root/src/sdks/react-native/tools/expo-runner-common.mts" check-query-dependency \
+      "${dependency_spec#file:}" "$query_artifact" || return
+  fi
+  bun "$root/src/sdks/react-native/tools/expo-runner-common.mts" patch-dependency "$example_dir/package.json" "$dependency_spec"
 }
 
-write_scratch_pnpm_workspace() {
-  mkdir -p "$scratch_root"
-  cat >"$scratch_root/package.json" <&2
+  exit 1
+}
+product_tools="$root/src/sdks/react-native/tools"
+fixture="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-rn-package-inputs.XXXXXX")"
+trap 'rm -rf "$fixture"' EXIT
+
+fixture_root="$fixture/repo"
+rn_dir="$fixture_root/src/sdks/react-native"
+source_example_dir="$fixture_root/src/examples/react-native-expo"
+scratch_root="$fixture/scratch"
+package_work="$scratch_root/src/sdks/react-native"
+mkdir -p \
+  "$rn_dir/src" \
+  "$rn_dir/node_modules" \
+  "$source_example_dir" \
+  "$fixture_root/src/extensions/generated/sdk"
+printf '{"name":"fixture"}\n' >"$rn_dir/package.json"
+printf 'export const fixture = 1;\n' >"$rn_dir/src/index.ts"
+printf '{"name":"example"}\n' >"$source_example_dir/package.json"
+printf '{"extensions":[]}\n' >"$fixture_root/src/extensions/generated/sdk/extensions.json"
+printf '{"extensions":[]}\n' >"$fixture_root/src/extensions/generated/sdk/ios-static-dependencies.json"
+
+# shellcheck source=src/sdks/react-native/tools/expo-runner-workspace.sh
+. "$product_tools/expo-runner-workspace.sh"
+root="$fixture_root"
+need_cmd() { command -v "$1" >/dev/null; }
+write_scratch_bun_workspace() { mkdir -p "$scratch_root"; }
+
+prepare_react_native_package_worktree
+cmp "$root/src/extensions/generated/sdk/extensions.json" "$package_work/src/generated/extensions.json"
+cmp "$root/src/extensions/generated/sdk/ios-static-dependencies.json" "$package_work/src/generated/ios-static-dependencies.json"
+[ -L "$package_work/node_modules" ]
+
+fingerprint() {
+  bun "$product_tools/react-native-package-inputs.mts" \
+    --root "$root" \
+    --rn-dir "$rn_dir" \
+    --example-package "$source_example_dir/package.json"
+}
+
+assert_fingerprint_changes() {
+  local file="$1"
+  local before after
+  before="$(fingerprint)"
+  printf '\nmutation\n' >>"$file"
+  touch -t 200001010000 "$file"
+  after="$(fingerprint)"
+  [ "$before" != "$after" ] || {
+    echo "package fingerprint ignored changed input: $file" >&2
+    exit 1
+  }
+}
+
+assert_fingerprint_changes "$rn_dir/src/index.ts"
+assert_fingerprint_changes "$root/src/extensions/generated/sdk/extensions.json"
+assert_fingerprint_changes "$root/src/extensions/generated/sdk/ios-static-dependencies.json"
+assert_fingerprint_changes "$source_example_dir/package.json"
+
+first="$(fingerprint)"
+second="$(fingerprint)"
+[ "$first" = "$second" ] || {
+  echo "package fingerprint is nondeterministic" >&2
+  exit 1
+}
+
+echo "React Native source-package staging and content fingerprint tests passed"
+
+# Resource assembly consumes data without executing or repairing source tools.
+root="$(cd "$product_tools/../../../.." && pwd)"
+script_path="$product_tools/expo-android-runner.sh"
+# shellcheck source=src/sdks/react-native/tools/expo-runner-common.sh
+. "$product_tools/expo-runner-common.sh"
+# shellcheck source=src/sdks/react-native/tools/mobile-extension-runtime.sh
+. "$product_tools/mobile-extension-runtime.sh"
+# shellcheck source=src/sdks/react-native/tools/expo-runner-runtime-resources.sh
+. "$product_tools/expo-runner-runtime-resources.sh"
+runtime_source="$fixture/runtime"
+seed="$fixture/seed"
+mkdir -p "$runtime_source/share/postgresql" "$runtime_source/bin" "$seed/files"
+printf 'fixture catalog\n' >"$runtime_source/share/postgresql/postgres.bki"
+printf 'fixture settings\n' >"$runtime_source/share/postgresql/postgresql.conf.sample"
+bun -e '
+  const [module, runtime] = process.argv.splice(1);
+  const { CORE_SNOWBALL_RUNTIME_DATA_FILES } = await import(module);
+  for (const file of CORE_SNOWBALL_RUNTIME_DATA_FILES) {
+    await Bun.write(`${runtime}/${file}`, "fixture Snowball data\n");
+  }
+' "$product_tools/validate-mobile-runtime-files.mts" "$runtime_source"
+printf 'must never execute\n' >"$runtime_source/bin/initdb"
+chmod 0444 "$runtime_source/bin/initdb"
+printf 'catalogProfile=standard\ntarget=android-datum64\n' >"$seed/manifest.properties"
+printf '18\n' >"$seed/files/PG_VERSION"
+before="$(directory_fingerprint "$runtime_source")"
+require_mobile_runtime_data "$runtime_source" OLIPHAUNT_EXPO_ANDROID_RUNTIME_DIR \
+  liboliphaunt-native:build-runtime-android-x86_64
+package_root="$fixture/mobile-package"
+prepare_mobile_runtime_resource_package Android "$runtime_source" "$seed" '' '' 1 "$package_root"
+cmp "$runtime_source/share/postgresql/postgres.bki" "$package_root/oliphaunt/runtime/files/share/postgresql/postgres.bki"
+cmp "$seed/files/PG_VERSION" "$package_root/oliphaunt/cluster-seed/files/PG_VERSION"
+[ ! -e "$package_root/oliphaunt/runtime/files/bin/initdb" ]
+[ ! -x "$runtime_source/bin/initdb" ]
+[ "$before" = "$(directory_fingerprint "$runtime_source")" ]
+if (require_mobile_runtime_data "$fixture/missing" OLIPHAUNT_EXPO_ANDROID_RUNTIME_DIR \
+  liboliphaunt-native:build-runtime-android-x86_64) >"$fixture/missing.log" 2>&1; then
+  echo 'missing mobile runtime data unexpectedly accepted' >&2
+  exit 1
+fi
+grep -Fq 'moon run liboliphaunt-native:build-runtime-android-x86_64' "$fixture/missing.log"
+echo "Mobile resource assembly preserves producer inputs and rejects missing data"
diff --git a/src/sdks/react-native/tools/icu-autolinking-fixture.mts b/src/sdks/react-native/tools/icu-autolinking-fixture.mts
new file mode 100644
index 000000000..654a9473e
--- /dev/null
+++ b/src/sdks/react-native/tools/icu-autolinking-fixture.mts
@@ -0,0 +1,88 @@
+import assert from 'node:assert/strict';
+import { cpSync, mkdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
+import { createRequire } from 'node:module';
+import path from 'node:path';
+import { extractPortableArchiveTree } from '../../../../tools/packaging/portable-archive.mts';
+
+const [phase, root, ...args] = process.argv.slice(2);
+const consumer = path.join(root, 'consumer');
+const icuRoot = path.join(consumer, 'node_modules/@oliphaunt/icu');
+const readJson = (file) => JSON.parse(readFileSync(file, 'utf8'));
+const writeJson = (file, value) => writeFileSync(file, JSON.stringify(value));
+
+if (phase === 'prepare') {
+  const [reactNativeTarball, icuSource, expoProject] = args;
+  const resolver = createRequire(path.join(expoProject, 'package.json'));
+  const dependencies = {};
+  for (const name of [
+    'react-native',
+    '@react-native-community/cli',
+    '@react-native-community/cli-platform-android',
+    '@react-native-community/cli-platform-ios',
+  ]) {
+    const manifestPath = resolver.resolve(name + '/package.json');
+    const manifest = readJson(manifestPath);
+    dependencies[name] = manifest.version;
+    const destination = path.join(consumer, 'node_modules', name);
+    mkdirSync(path.dirname(destination), { recursive: true });
+    symlinkSync(
+      path.dirname(manifestPath),
+      destination,
+      process.platform === 'win32' ? 'junction' : 'dir',
+    );
+    if (name === '@react-native-community/cli') {
+      const bin = typeof manifest.bin === 'string' ? manifest.bin : manifest.bin['rnc-cli'];
+      writeFileSync(path.join(root, 'cli'), path.join(path.dirname(manifestPath), bin));
+    }
+  }
+  writeJson(path.join(consumer, 'package.json'), {
+    name: 'oliphaunt-autolinking-consumer',
+    private: true,
+    dependencies: {
+      ...dependencies,
+      '@oliphaunt/react-native': '0.0.0',
+      '@oliphaunt/icu': '0.0.0',
+    },
+  });
+  extractPortableArchiveTree(
+    reactNativeTarball,
+    path.join(consumer, 'node_modules/@oliphaunt/react-native'),
+    'package',
+  );
+  const source = path.join(root, 'icu-source');
+  mkdirSync(source);
+  for (const file of ['package.json', 'OliphauntICU.podspec'])
+    cpSync(path.join(icuSource, file), path.join(source, file));
+  cpSync(
+    path.join(icuSource, 'react-native.config.cts'),
+    path.join(source, 'react-native.config.js'),
+  );
+} else if (phase === 'extract') {
+  extractPortableArchiveTree(args[0], icuRoot, 'package');
+} else if (phase === 'control') {
+  // Discovery must work when the opt-out is removed; an empty autolinker result cannot pass.
+  rmSync(path.join(icuRoot, 'react-native.config.js'));
+} else if (phase === 'check') {
+  const [kind, platform, result] = args;
+  const config = readJson(result);
+  assert.ok(
+    config.dependencies?.['@oliphaunt/react-native']?.platforms?.[platform],
+    'React Native carrier must be discoverable',
+  );
+  const icu = config.dependencies?.['@oliphaunt/icu'];
+  if (kind === 'candidate') {
+    assert.equal(icu, undefined, 'ICU data package must opt out of native autolinking');
+    const resolver = createRequire(path.join(consumer, 'package.json'));
+    assert.equal(
+      resolver.resolve('@oliphaunt/icu/package.json'),
+      path.join(icuRoot, 'package.json'),
+    );
+  } else {
+    assert.ok(
+      icu?.platforms?.ios?.podspecPath,
+      'ICU control without its opt-out must be discoverable',
+    );
+  }
+} else {
+  throw new Error('unknown autolinking fixture phase: ' + phase);
+}
diff --git a/src/sdks/react-native/tools/ios-app-transport.mjs b/src/sdks/react-native/tools/ios-app-transport.mjs
deleted file mode 100755
index 260505b66..000000000
--- a/src/sdks/react-native/tools/ios-app-transport.mjs
+++ /dev/null
@@ -1,1339 +0,0 @@
-#!/usr/bin/env node
-
-import { createHash, randomUUID } from "node:crypto";
-import { createReadStream } from "node:fs";
-import fs from "node:fs/promises";
-import path from "node:path";
-import { fileURLToPath } from "node:url";
-import { inflateRawSync } from "node:zlib";
-
-import { captureCommandOutput } from "../../../../tools/dev/capture-command-output.mjs";
-
-const PREFIX = "ios-app-transport.mjs";
-export const TRANSPORT_SCHEMA = "oliphaunt-react-native-ios-app-transport-v1";
-export const ARCHIVE_NAME = "react-native-mobile-ios-app.zip";
-export const MANIFEST_NAME = "react-native-mobile-ios-app.manifest.json";
-export const BUILD_REPORT_NAME = "build-report.json";
-const ZIP_EOCD_SIGNATURE = 0x06054b50;
-const ZIP64_EOCD_SIGNATURE = 0x06064b50;
-const ZIP64_LOCATOR_SIGNATURE = 0x07064b50;
-const ZIP_CENTRAL_SIGNATURE = 0x02014b50;
-const ZIP_LOCAL_SIGNATURE = 0x04034b50;
-const ZIP64_EXTRA_ID = 0x0001;
-const ZIP_EOCD_MAX_BYTES = 22 + 0xffff;
-const ZIP_MAX_CENTRAL_BYTES = 256 * 1024 * 1024;
-const ZIP_MAX_ENTRIES = 1_000_000;
-const ZIP_MAX_MEMBER_NAME_BYTES = 4096;
-const ZIP_MAX_SYMLINK_TARGET_BYTES = 64 * 1024;
-const UTF8 = new TextDecoder("utf-8", { fatal: true });
-const ARCHIVE_TIMESTAMP = new Date("2000-01-01T00:00:00.000Z");
-
-function fail(message) {
-  throw new Error(`${PREFIX}: ${message}`);
-}
-
-function usage() {
-  return `usage:
-  ${PREFIX} pack --app-dir DIR --transport-dir DIR [--build-report FILE]
-  ${PREFIX} verify-extract --transport-dir DIR --output-dir DIR`;
-}
-
-function parseFlags(argv) {
-  const values = new Map();
-  for (let index = 0; index < argv.length; index += 1) {
-    const flag = argv[index];
-    if (!flag.startsWith("--") || flag === "--help") {
-      fail(`unknown argument ${JSON.stringify(flag)}\n${usage()}`);
-    }
-    if (values.has(flag)) {
-      fail(`argument ${flag} must not be repeated`);
-    }
-    const value = argv[index + 1];
-    if (!value || value.startsWith("--")) {
-      fail(`${flag} requires a value`);
-    }
-    values.set(flag, value);
-    index += 1;
-  }
-  return values;
-}
-
-function requireOnlyFlags(values, allowed) {
-  for (const flag of values.keys()) {
-    if (!allowed.has(flag)) {
-      fail(`unknown argument ${flag}\n${usage()}`);
-    }
-  }
-}
-
-function requiredFlag(values, flag) {
-  const value = values.get(flag);
-  if (!value) {
-    fail(`${flag} is required\n${usage()}`);
-  }
-  return path.resolve(value);
-}
-
-function parseArgs(argv) {
-  const command = argv[0];
-  if (command === "--help" || command === "-h") {
-    process.stdout.write(`${usage()}\n`);
-    process.exit(0);
-  }
-  if (!new Set(["pack", "verify-extract"]).has(command)) {
-    fail(`expected pack or verify-extract\n${usage()}`);
-  }
-  const values = parseFlags(argv.slice(1));
-  if (command === "pack") {
-    requireOnlyFlags(values, new Set(["--app-dir", "--transport-dir", "--build-report"]));
-    return {
-      command,
-      appDir: requiredFlag(values, "--app-dir"),
-      transportDir: requiredFlag(values, "--transport-dir"),
-      buildReport: values.has("--build-report")
-        ? path.resolve(values.get("--build-report"))
-        : undefined,
-    };
-  }
-  requireOnlyFlags(values, new Set(["--transport-dir", "--output-dir"]));
-  return {
-    command,
-    transportDir: requiredFlag(values, "--transport-dir"),
-    outputDir: requiredFlag(values, "--output-dir"),
-  };
-}
-
-async function statOrUndefined(file, { follow = true } = {}) {
-  try {
-    return follow ? await fs.stat(file) : await fs.lstat(file);
-  } catch (error) {
-    if (error?.code === "ENOENT") return undefined;
-    throw error;
-  }
-}
-
-async function requireDirectory(directory, label) {
-  if ((await statOrUndefined(directory, { follow: false }))?.isDirectory() !== true) {
-    fail(`${label} is not a directory: ${directory}`);
-  }
-}
-
-async function requireRegularFile(file, label) {
-  const stat = await statOrUndefined(file, { follow: false });
-  if (stat?.isFile() !== true || stat.size === 0) {
-    fail(`${label} is missing, empty, or not a regular file: ${file}`);
-  }
-  return stat;
-}
-
-async function findCommand(name) {
-  for (const directory of (process.env.PATH ?? "").split(path.delimiter).filter(Boolean)) {
-    const candidate = path.join(directory, name);
-    try {
-      await fs.access(candidate, fs.constants.X_OK);
-      if ((await fs.stat(candidate)).isFile()) return candidate;
-    } catch {
-      // Continue through PATH.
-    }
-  }
-  fail(
-    `required Apple command ${name} was not found; ` +
-      "run this operation on macOS with ditto and plutil available",
-  );
-}
-
-async function appleTools() {
-  return {
-    ditto: await findCommand("ditto"),
-    plutil: await findCommand("plutil"),
-  };
-}
-
-function run(command, args, { cwd = undefined, label = command } = {}) {
-  const result = captureCommandOutput(command, args, {
-    cwd,
-    env: { ...process.env, TZ: "UTC" },
-    label,
-    maxOutputBytes: 16 * 1024 * 1024,
-  });
-  if (result.error) {
-    fail(`${label} could not start: ${result.error.message}`);
-  }
-  if (result.status !== 0) {
-    const detail = [result.stderr, result.stdout]
-      .map((value) => value?.trim())
-      .filter(Boolean)
-      .join("\n");
-    fail(`${label} failed with exit code ${result.status}${detail ? `: ${detail}` : ""}`);
-  }
-  return result.stdout;
-}
-
-function safeLeaf(value, label, suffix = undefined) {
-  if (
-    typeof value !== "string" ||
-    value.length === 0 ||
-    value === "." ||
-    value === ".." ||
-    value.includes("/") ||
-    value.includes("\\") ||
-    /[\u0000-\u001f\u007f]/u.test(value) ||
-    path.basename(value) !== value
-  ) {
-    fail(`${label} must be a safe filename; got ${JSON.stringify(value)}`);
-  }
-  if (suffix !== undefined && !value.endsWith(suffix)) {
-    fail(`${label} must end in ${suffix}; got ${JSON.stringify(value)}`);
-  }
-  return value;
-}
-
-async function sha256File(file) {
-  const hash = createHash("sha256");
-  await new Promise((resolve, reject) => {
-    const input = createReadStream(file);
-    input.on("data", (chunk) => hash.update(chunk));
-    input.on("error", reject);
-    input.on("end", resolve);
-  });
-  return hash.digest("hex");
-}
-
-function compareNames(left, right) {
-  return Buffer.compare(Buffer.from(left, "utf8"), Buffer.from(right, "utf8"));
-}
-
-function inside(root, candidate) {
-  const relative = path.relative(root, candidate);
-  return relative === "" || (!relative.startsWith(`..${path.sep}`) && relative !== ".." && !path.isAbsolute(relative));
-}
-
-async function payloadIdentity(app) {
-  const hash = createHash("sha256");
-  let entries = 0;
-
-  async function visit(file, relative) {
-    const stat = await fs.lstat(file);
-    const mode = (stat.mode & 0o7777).toString(8).padStart(4, "0");
-    let row;
-    if (stat.isSymbolicLink()) {
-      const target = await fs.readlink(file);
-      if (path.isAbsolute(target) || !inside(app, path.resolve(path.dirname(file), target))) {
-        fail(`app bundle contains unsafe symlink ${relative} -> ${target}`);
-      }
-      row = { mode, path: relative, target, type: "symlink" };
-    } else if (stat.isDirectory()) {
-      row = { mode, path: relative, type: "directory" };
-    } else if (stat.isFile()) {
-      row = {
-        bytes: stat.size,
-        mode,
-        path: relative,
-        sha256: await sha256File(file),
-        type: "file",
-      };
-    } else {
-      fail(`app bundle contains unsupported special entry: ${relative}`);
-    }
-    hash.update(`${JSON.stringify(row)}\n`);
-    entries += 1;
-
-    if (stat.isDirectory()) {
-      const children = await fs.readdir(file);
-      children.sort(compareNames);
-      for (const child of children) {
-        const childRelative = relative === "." ? child : `${relative}/${child}`;
-        await visit(path.join(file, child), childRelative);
-      }
-    }
-  }
-
-  await visit(app, ".");
-  return { entries, sha256: hash.digest("hex") };
-}
-
-async function directApps(directory) {
-  const entries = await fs.readdir(directory, { withFileTypes: true });
-  return entries
-    .filter((entry) => entry.isDirectory() && entry.name.endsWith(".app"))
-    .map((entry) => ({ name: entry.name, path: path.join(directory, entry.name) }))
-    .sort((left, right) => compareNames(left.name, right.name));
-}
-
-async function exactlyOneApp(directory, expectedName = undefined) {
-  const apps = await directApps(directory);
-  if (apps.length !== 1) {
-    fail(
-      `${directory} must contain exactly one direct .app directory; ` +
-        `found ${apps.length}${apps.length > 0 ? `: ${apps.map(({ name }) => name).join(", ")}` : ""}`,
-    );
-  }
-  if (expectedName !== undefined && apps[0].name !== expectedName) {
-    fail(`${directory} contains ${apps[0].name}, but the manifest requires ${expectedName}`);
-  }
-  return apps[0];
-}
-
-async function requireExactDirectEntries(directory, expected, label) {
-  const actual = (await fs.readdir(directory)).sort(compareNames);
-  const wanted = [...expected].sort(compareNames);
-  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
-    fail(`${label} entries must be ${JSON.stringify(wanted)}; got ${JSON.stringify(actual)}`);
-  }
-}
-
-async function appIdentity(app, plutil) {
-  const appName = safeLeaf(path.basename(app), "app bundle name", ".app");
-  const infoPlist = path.join(app, "Info.plist");
-  await requireRegularFile(infoPlist, `${appName} Info.plist`);
-  const executable = safeLeaf(
-    run(
-      plutil,
-      ["-extract", "CFBundleExecutable", "raw", "-o", "-", infoPlist],
-      { label: `${appName} CFBundleExecutable lookup` },
-    ).trim(),
-    `${appName} CFBundleExecutable`,
-  );
-  const executableFile = path.join(app, executable);
-  const executableStat = await requireRegularFile(executableFile, `${appName} executable`);
-  try {
-    await fs.access(executableFile, fs.constants.X_OK);
-  } catch {
-    fail(`${appName} executable is not executable: ${executableFile}`);
-  }
-  return {
-    executable,
-    executableMode: (executableStat.mode & 0o7777).toString(8).padStart(4, "0"),
-    infoPlistSha256: await sha256File(infoPlist),
-    name: appName,
-    payload: await payloadIdentity(app),
-  };
-}
-
-function object(value) {
-  return value !== null && typeof value === "object" && !Array.isArray(value);
-}
-
-function exactKeys(value, expected, label) {
-  if (!object(value)) fail(`${label} must be a JSON object`);
-  const actual = Object.keys(value).sort(compareNames);
-  const wanted = [...expected].sort(compareNames);
-  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
-    fail(`${label} keys must be ${JSON.stringify(wanted)}; got ${JSON.stringify(actual)}`);
-  }
-}
-
-function sha256Value(value, label) {
-  if (typeof value !== "string" || !/^[0-9a-f]{64}$/u.test(value)) {
-    fail(`${label} must be a lowercase SHA-256 digest`);
-  }
-  return value;
-}
-
-function safeInteger(value, label, { positive = false } = {}) {
-  if (!Number.isSafeInteger(value) || value < (positive ? 1 : 0)) {
-    fail(`${label} must be a ${positive ? "positive " : "non-negative "}safe integer`);
-  }
-  return value;
-}
-
-async function readJson(file, label) {
-  await requireRegularFile(file, label);
-  try {
-    return JSON.parse(await fs.readFile(file, "utf8"));
-  } catch (error) {
-    fail(`${label} is not valid JSON: ${error.message}`);
-  }
-}
-
-function reportIdentity(data, { appName, bytes, sha256 }) {
-  if (!object(data)) fail(`${BUILD_REPORT_NAME} must contain a JSON object`);
-  if (data.schema !== "oliphaunt-react-native-mobile-build-v1") {
-    fail(`${BUILD_REPORT_NAME} has invalid schema ${JSON.stringify(data.schema)}`);
-  }
-  if (data.platform !== "ios") {
-    fail(`${BUILD_REPORT_NAME} must declare platform=ios`);
-  }
-  if (typeof data.appArtifact !== "string" || path.basename(data.appArtifact) !== appName) {
-    fail(`${BUILD_REPORT_NAME} appArtifact must identify ${appName}`);
-  }
-  safeInteger(data.appArtifactBytes, `${BUILD_REPORT_NAME} appArtifactBytes`);
-  for (const key of ["configuration", "sdk"]) {
-    if (data[key] !== undefined && typeof data[key] !== "string") {
-      fail(`${BUILD_REPORT_NAME} ${key} must be a string when present`);
-    }
-  }
-  return {
-    appArtifactBytes: data.appArtifactBytes,
-    appArtifactName: appName,
-    bytes,
-    configuration: data.configuration ?? null,
-    name: BUILD_REPORT_NAME,
-    platform: data.platform,
-    schema: data.schema,
-    sdk: data.sdk ?? null,
-    sha256,
-  };
-}
-
-async function loadBuildReport(file, appName) {
-  const stat = await requireRegularFile(file, "iOS mobile build report");
-  const sha256 = await sha256File(file);
-  const data = await readJson(file, "iOS mobile build report");
-  return { identity: reportIdentity(data, { appName, bytes: stat.size, sha256 }) };
-}
-
-function validateReportIdentity(value) {
-  exactKeys(
-    value,
-    [
-      "appArtifactBytes",
-      "appArtifactName",
-      "bytes",
-      "configuration",
-      "name",
-      "platform",
-      "schema",
-      "sdk",
-      "sha256",
-    ],
-    "transport manifest buildReport",
-  );
-  if (value.name !== BUILD_REPORT_NAME) fail(`transport build report name must be ${BUILD_REPORT_NAME}`);
-  if (value.schema !== "oliphaunt-react-native-mobile-build-v1" || value.platform !== "ios") {
-    fail("transport build report identity must describe an iOS mobile build report");
-  }
-  safeLeaf(value.appArtifactName, "transport build report appArtifactName", ".app");
-  safeInteger(value.appArtifactBytes, "transport build report appArtifactBytes");
-  safeInteger(value.bytes, "transport build report bytes", { positive: true });
-  sha256Value(value.sha256, "transport build report sha256");
-  for (const key of ["configuration", "sdk"]) {
-    if (value[key] !== null && typeof value[key] !== "string") {
-      fail(`transport build report ${key} must be a string or null`);
-    }
-  }
-}
-
-function validateManifest(data) {
-  exactKeys(data, ["app", "archive", "buildReport", "schema"], "transport manifest");
-  if (data.schema !== TRANSPORT_SCHEMA) {
-    fail(`transport manifest schema must be ${TRANSPORT_SCHEMA}; got ${JSON.stringify(data.schema)}`);
-  }
-  exactKeys(data.archive, ["bytes", "format", "name", "sha256"], "transport manifest archive");
-  if (data.archive.name !== ARCHIVE_NAME || data.archive.format !== "ditto-zip") {
-    fail(`transport archive must be ${ARCHIVE_NAME} in ditto-zip format`);
-  }
-  safeInteger(data.archive.bytes, "transport archive bytes", { positive: true });
-  sha256Value(data.archive.sha256, "transport archive sha256");
-
-  exactKeys(
-    data.app,
-    ["executable", "executableMode", "infoPlistSha256", "name", "payload"],
-    "transport manifest app",
-  );
-  safeLeaf(data.app.name, "transport app name", ".app");
-  safeLeaf(data.app.executable, "transport app executable");
-  if (typeof data.app.executableMode !== "string" || !/^[0-7]{4}$/u.test(data.app.executableMode)) {
-    fail("transport app executableMode must be a four-digit octal mode");
-  }
-  if ((Number.parseInt(data.app.executableMode, 8) & 0o111) === 0) {
-    fail("transport app executableMode must include an executable bit");
-  }
-  sha256Value(data.app.infoPlistSha256, "transport app Info.plist sha256");
-  exactKeys(data.app.payload, ["entries", "sha256"], "transport manifest app payload");
-  safeInteger(data.app.payload.entries, "transport app payload entries", { positive: true });
-  sha256Value(data.app.payload.sha256, "transport app payload sha256");
-
-  if (data.buildReport !== null) {
-    validateReportIdentity(data.buildReport);
-    if (data.buildReport.appArtifactName !== data.app.name) {
-      fail("transport build report and app names do not match");
-    }
-  }
-  return data;
-}
-
-async function readAt(handle, offset, length, label) {
-  if (
-    !Number.isSafeInteger(offset) ||
-    offset < 0 ||
-    !Number.isSafeInteger(length) ||
-    length < 0
-  ) {
-    fail(`${label} has an invalid byte range`);
-  }
-  const buffer = Buffer.alloc(length);
-  let consumed = 0;
-  while (consumed < length) {
-    const { bytesRead } = await handle.read(
-      buffer,
-      consumed,
-      length - consumed,
-      offset + consumed,
-    );
-    if (bytesRead === 0) {
-      fail(`${label} is truncated at byte ${offset + consumed}`);
-    }
-    consumed += bytesRead;
-  }
-  return buffer;
-}
-
-function safeZipNumber(value, label) {
-  if (typeof value === "bigint") {
-    if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
-      fail(`${label} exceeds the JavaScript safe-integer range`);
-    }
-    value = Number(value);
-  }
-  if (!Number.isSafeInteger(value) || value < 0) {
-    fail(`${label} must be a non-negative safe integer`);
-  }
-  return value;
-}
-
-function extraFields(buffer, label) {
-  const fields = new Map();
-  let cursor = 0;
-  while (cursor < buffer.length) {
-    if (cursor + 4 > buffer.length) fail(`${label} has a truncated extra-field header`);
-    const id = buffer.readUInt16LE(cursor);
-    const size = buffer.readUInt16LE(cursor + 2);
-    cursor += 4;
-    if (cursor + size > buffer.length) fail(`${label} has a truncated 0x${id.toString(16)} extra field`);
-    if (fields.has(id)) fail(`${label} repeats extra field 0x${id.toString(16)}`);
-    fields.set(id, buffer.subarray(cursor, cursor + size));
-    cursor += size;
-  }
-  return fields;
-}
-
-function zip64EntryValues({
-  compressedSize,
-  diskStart,
-  extra,
-  localOffset,
-  uncompressedSize,
-  label,
-}) {
-  const needed =
-    uncompressedSize === 0xffffffff ||
-    compressedSize === 0xffffffff ||
-    localOffset === 0xffffffff ||
-    diskStart === 0xffff;
-  if (!needed) {
-    return { compressedSize, diskStart, localOffset, uncompressedSize };
-  }
-  const zip64 = extraFields(extra, label).get(ZIP64_EXTRA_ID);
-  if (zip64 === undefined) fail(`${label} requires a ZIP64 extra field`);
-  let cursor = 0;
-  const read64 = (field) => {
-    if (cursor + 8 > zip64.length) fail(`${label} ZIP64 ${field} is truncated`);
-    const value = safeZipNumber(zip64.readBigUInt64LE(cursor), `${label} ZIP64 ${field}`);
-    cursor += 8;
-    return value;
-  };
-  const read32 = (field) => {
-    if (cursor + 4 > zip64.length) fail(`${label} ZIP64 ${field} is truncated`);
-    const value = zip64.readUInt32LE(cursor);
-    cursor += 4;
-    return value;
-  };
-  if (uncompressedSize === 0xffffffff) uncompressedSize = read64("uncompressed size");
-  if (compressedSize === 0xffffffff) compressedSize = read64("compressed size");
-  if (localOffset === 0xffffffff) localOffset = read64("local-header offset");
-  if (diskStart === 0xffff) diskStart = read32("disk start");
-  return { compressedSize, diskStart, localOffset, uncompressedSize };
-}
-
-async function zipDirectory(handle, archiveSize) {
-  if (archiveSize < 22) fail("iOS app ZIP is too short to contain an end-of-central-directory record");
-  const tailSize = Math.min(archiveSize, ZIP_EOCD_MAX_BYTES);
-  const tailOffset = archiveSize - tailSize;
-  const tail = await readAt(handle, tailOffset, tailSize, "iOS app ZIP tail");
-  let eocdIndex = -1;
-  for (let index = tail.length - 22; index >= 0; index -= 1) {
-    if (tail.readUInt32LE(index) !== ZIP_EOCD_SIGNATURE) continue;
-    const commentBytes = tail.readUInt16LE(index + 20);
-    if (index + 22 + commentBytes === tail.length) {
-      eocdIndex = index;
-      break;
-    }
-  }
-  if (eocdIndex < 0) fail("iOS app ZIP has no well-formed end-of-central-directory record");
-
-  const eocdOffset = tailOffset + eocdIndex;
-  const disk = tail.readUInt16LE(eocdIndex + 4);
-  const centralDisk = tail.readUInt16LE(eocdIndex + 6);
-  let diskEntries = tail.readUInt16LE(eocdIndex + 8);
-  let entries = tail.readUInt16LE(eocdIndex + 10);
-  let centralSize = tail.readUInt32LE(eocdIndex + 12);
-  let centralOffset = tail.readUInt32LE(eocdIndex + 16);
-  let centralBoundary = eocdOffset;
-  const zip64 =
-    disk === 0xffff ||
-    centralDisk === 0xffff ||
-    diskEntries === 0xffff ||
-    entries === 0xffff ||
-    centralSize === 0xffffffff ||
-    centralOffset === 0xffffffff;
-
-  if (zip64) {
-    if (eocdOffset < 20) fail("iOS app ZIP64 locator is missing");
-    const locator = await readAt(handle, eocdOffset - 20, 20, "iOS app ZIP64 locator");
-    if (locator.readUInt32LE(0) !== ZIP64_LOCATOR_SIGNATURE) {
-      fail("iOS app ZIP64 locator has an invalid signature");
-    }
-    const zip64Disk = locator.readUInt32LE(4);
-    const zip64Offset = safeZipNumber(locator.readBigUInt64LE(8), "iOS app ZIP64 record offset");
-    const totalDisks = locator.readUInt32LE(16);
-    if (zip64Disk !== 0 || totalDisks !== 1) fail("multi-disk iOS app ZIP64 archives are not supported");
-    const record = await readAt(handle, zip64Offset, 56, "iOS app ZIP64 end record");
-    if (record.readUInt32LE(0) !== ZIP64_EOCD_SIGNATURE) {
-      fail("iOS app ZIP64 end record has an invalid signature");
-    }
-    const recordBytes = safeZipNumber(record.readBigUInt64LE(4), "iOS app ZIP64 record size");
-    const locatorOffset = eocdOffset - 20;
-    if (
-      recordBytes < 44 ||
-      zip64Offset > locatorOffset ||
-      locatorOffset - zip64Offset < 12 ||
-      recordBytes !== locatorOffset - zip64Offset - 12
-    ) {
-      fail("iOS app ZIP64 end record has an invalid extent");
-    }
-    if (record.readUInt32LE(16) !== 0 || record.readUInt32LE(20) !== 0) {
-      fail("multi-disk iOS app ZIP64 archives are not supported");
-    }
-    diskEntries = safeZipNumber(record.readBigUInt64LE(24), "iOS app ZIP64 disk entry count");
-    entries = safeZipNumber(record.readBigUInt64LE(32), "iOS app ZIP64 entry count");
-    centralSize = safeZipNumber(record.readBigUInt64LE(40), "iOS app ZIP64 central size");
-    centralOffset = safeZipNumber(record.readBigUInt64LE(48), "iOS app ZIP64 central offset");
-    centralBoundary = zip64Offset;
-  } else if (disk !== 0 || centralDisk !== 0) {
-    fail("multi-disk iOS app ZIP archives are not supported");
-  }
-
-  if (diskEntries !== entries) fail("iOS app ZIP central-directory entry counts do not match");
-  if (entries === 0 || entries > ZIP_MAX_ENTRIES) {
-    fail(`iOS app ZIP entry count must be between 1 and ${ZIP_MAX_ENTRIES}`);
-  }
-  if (centralSize === 0 || centralSize > ZIP_MAX_CENTRAL_BYTES) {
-    fail(`iOS app ZIP central directory must be between 1 and ${ZIP_MAX_CENTRAL_BYTES} bytes`);
-  }
-  if (
-    centralBoundary > archiveSize ||
-    centralOffset > centralBoundary ||
-    centralSize !== centralBoundary - centralOffset
-  ) {
-    fail("iOS app ZIP central directory has an invalid or ambiguous extent");
-  }
-  return { centralOffset, centralSize, entries, zip64 };
-}
-
-function decodeZipName(buffer, label) {
-  if (buffer.length === 0 || buffer.length > ZIP_MAX_MEMBER_NAME_BYTES) {
-    fail(`${label} must contain between 1 and ${ZIP_MAX_MEMBER_NAME_BYTES} filename bytes`);
-  }
-  try {
-    return UTF8.decode(buffer);
-  } catch {
-    fail(`${label} is not valid UTF-8`);
-  }
-}
-
-function zipMemberPath(name, appName) {
-  if (
-    name.startsWith("/") ||
-    name.includes("\\") ||
-    /^[A-Za-z]:/u.test(name) ||
-    /[\u0000-\u001f\u007f]/u.test(name)
-  ) {
-    fail(`iOS app ZIP contains unsafe member path ${JSON.stringify(name)}`);
-  }
-  const directory = name.endsWith("/");
-  const components = name.split("/");
-  if (directory) components.pop();
-  if (
-    components.length === 0 ||
-    components.some(
-      (component) =>
-        component === "" ||
-        component === "." ||
-        component === ".." ||
-        Buffer.byteLength(component, "utf8") > 255,
-    )
-  ) {
-    fail(`iOS app ZIP contains unsafe member path ${JSON.stringify(name)}`);
-  }
-  const metadata = components[0] === "__MACOSX";
-  if (!metadata && components[0] !== appName) {
-    fail(`iOS app ZIP member is outside ${appName}: ${JSON.stringify(name)}`);
-  }
-  if (metadata) {
-    if (components.length === 1 && !directory) {
-      fail("iOS app ZIP __MACOSX root must be a directory");
-    }
-    if (
-      components.length > 1 &&
-      components[1] !== appName &&
-      components[1] !== `._${appName}`
-    ) {
-      fail(`iOS app ZIP metadata member is unrelated to ${appName}: ${JSON.stringify(name)}`);
-    }
-  }
-  return {
-    canonical: components.join("/"),
-    directory,
-    metadata,
-    normalized: components.join("/").normalize("NFC"),
-  };
-}
-
-function portableCaseFold(value) {
-  // NFKC expands compatibility characters and the upper/lower round-trip
-  // catches multi-code-point folds such as sharp-s. This is deliberately
-  // conservative across the case-insensitive filesystems a macOS runner may
-  // use during extraction.
-  return value.normalize("NFKC").toUpperCase().toLowerCase().normalize("NFC");
-}
-
-function zipMemberType(versionMadeBy, externalAttributes, directoryHint, name) {
-  const host = versionMadeBy >>> 8;
-  const mode = externalAttributes >>> 16;
-  const unixType = mode & 0o170000;
-  let type;
-  if (unixType !== 0) {
-    type = new Map([
-      [0o040000, "directory"],
-      [0o100000, "file"],
-      [0o120000, "symlink"],
-    ]).get(unixType);
-    if (type === undefined) {
-      fail(
-        `iOS app ZIP member ${JSON.stringify(name)} uses unsupported special mode ` +
-          `0${unixType.toString(8)} from host ${host}`,
-      );
-    }
-  } else {
-    type = (externalAttributes & 0x10) !== 0 || directoryHint ? "directory" : "file";
-  }
-  if ((type === "directory") !== directoryHint) {
-    fail(`iOS app ZIP member ${JSON.stringify(name)} has inconsistent directory metadata`);
-  }
-  return type;
-}
-
-const CRC32_TABLE = (() => {
-  const table = new Uint32Array(256);
-  for (let index = 0; index < table.length; index += 1) {
-    let value = index;
-    for (let bit = 0; bit < 8; bit += 1) {
-      value = (value & 1) === 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;
-    }
-    table[index] = value >>> 0;
-  }
-  return table;
-})();
-
-function crc32(buffer) {
-  let value = 0xffffffff;
-  for (const byte of buffer) value = CRC32_TABLE[(value ^ byte) & 0xff] ^ (value >>> 8);
-  return (value ^ 0xffffffff) >>> 0;
-}
-
-async function validateZipLocalEntry(handle, entry, centralOffset) {
-  if (entry.localOffset > centralOffset || centralOffset - entry.localOffset < 30) {
-    fail(`iOS app ZIP local header for ${JSON.stringify(entry.name)} is outside the payload region`);
-  }
-  const header = await readAt(
-    handle,
-    entry.localOffset,
-    30,
-    `iOS app ZIP local header for ${entry.name}`,
-  );
-  if (header.readUInt32LE(0) !== ZIP_LOCAL_SIGNATURE) {
-    fail(`iOS app ZIP local header for ${JSON.stringify(entry.name)} has an invalid signature`);
-  }
-  const flags = header.readUInt16LE(6);
-  const method = header.readUInt16LE(8);
-  const checksum = header.readUInt32LE(14);
-  const compressed32 = header.readUInt32LE(18);
-  const uncompressed32 = header.readUInt32LE(22);
-  const nameBytes = header.readUInt16LE(26);
-  const extraBytes = header.readUInt16LE(28);
-  if (flags !== entry.flags || method !== entry.method) {
-    fail(`iOS app ZIP local header metadata does not match ${JSON.stringify(entry.name)}`);
-  }
-  const localName = await readAt(
-    handle,
-    entry.localOffset + 30,
-    nameBytes,
-    `iOS app ZIP local filename for ${entry.name}`,
-  );
-  if (!localName.equals(entry.rawName)) {
-    fail(`iOS app ZIP local header filename does not match central member ${JSON.stringify(entry.name)}`);
-  }
-  const localExtra = await readAt(
-    handle,
-    entry.localOffset + 30 + nameBytes,
-    extraBytes,
-    `iOS app ZIP local extra fields for ${entry.name}`,
-  );
-  const localSizes = zip64EntryValues({
-    compressedSize: compressed32,
-    diskStart: 0,
-    extra: localExtra,
-    label: `iOS app ZIP local header ${JSON.stringify(entry.name)}`,
-    localOffset: 0,
-    uncompressedSize: uncompressed32,
-  });
-  const descriptor = (flags & 0x0008) !== 0;
-  if (descriptor) {
-    if (checksum !== 0 && checksum !== entry.crc32) {
-      fail(`iOS app ZIP local CRC disagrees with central member ${JSON.stringify(entry.name)}`);
-    }
-    for (const [label, raw, resolved, expected] of [
-      ["compressed size", compressed32, localSizes.compressedSize, entry.compressedSize],
-      ["uncompressed size", uncompressed32, localSizes.uncompressedSize, entry.uncompressedSize],
-    ]) {
-      if (raw !== 0 && resolved !== 0 && resolved !== expected) {
-        fail(`iOS app ZIP local ${label} disagrees with central member ${JSON.stringify(entry.name)}`);
-      }
-    }
-  } else if (
-    checksum !== entry.crc32 ||
-    localSizes.compressedSize !== entry.compressedSize ||
-    localSizes.uncompressedSize !== entry.uncompressedSize
-  ) {
-    fail(`iOS app ZIP local CRC or sizes disagree with central member ${JSON.stringify(entry.name)}`);
-  }
-  const headerBytes = 30 + nameBytes + extraBytes;
-  if (entry.localOffset > centralOffset || headerBytes > centralOffset - entry.localOffset) {
-    fail(`iOS app ZIP local header for ${JSON.stringify(entry.name)} overlaps the central directory`);
-  }
-  const dataOffset = entry.localOffset + headerBytes;
-  if (dataOffset > centralOffset || entry.compressedSize > centralOffset - dataOffset) {
-    fail(`iOS app ZIP data for ${JSON.stringify(entry.name)} overlaps the central directory`);
-  }
-  const dataEnd = dataOffset + entry.compressedSize;
-  entry.dataOffset = dataOffset;
-  entry.dataEnd = dataEnd;
-  entry.usesDataDescriptor = descriptor;
-}
-
-async function validateZipDataDescriptor(handle, entry, offset, length) {
-  const zip64Sizes = entry.zip64Sizes;
-  const unsignedBytes = zip64Sizes ? 20 : 12;
-  const signedBytes = unsignedBytes + 4;
-  if (length !== unsignedBytes && length !== signedBytes) {
-    fail(
-      `iOS app ZIP has an unreferenced or ambiguous ${length}-byte gap after ` +
-        JSON.stringify(entry.name),
-    );
-  }
-  const descriptor = await readAt(
-    handle,
-    offset,
-    length,
-    `iOS app ZIP data descriptor for ${entry.name}`,
-  );
-  let cursor = 0;
-  if (length === signedBytes) {
-    if (descriptor.readUInt32LE(0) !== 0x08074b50) {
-      fail(`iOS app ZIP data descriptor for ${JSON.stringify(entry.name)} has an invalid signature`);
-    }
-    cursor = 4;
-  }
-  const checksum = descriptor.readUInt32LE(cursor);
-  cursor += 4;
-  const compressedSize = zip64Sizes
-    ? safeZipNumber(descriptor.readBigUInt64LE(cursor), `ZIP64 descriptor compressed size for ${entry.name}`)
-    : descriptor.readUInt32LE(cursor);
-  cursor += zip64Sizes ? 8 : 4;
-  const uncompressedSize = zip64Sizes
-    ? safeZipNumber(descriptor.readBigUInt64LE(cursor), `ZIP64 descriptor uncompressed size for ${entry.name}`)
-    : descriptor.readUInt32LE(cursor);
-  if (
-    checksum !== entry.crc32 ||
-    compressedSize !== entry.compressedSize ||
-    uncompressedSize !== entry.uncompressedSize
-  ) {
-    fail(`iOS app ZIP data descriptor disagrees with central member ${JSON.stringify(entry.name)}`);
-  }
-}
-
-async function validateZipSymlink(handle, entry, appName) {
-  if (entry.metadata) fail(`iOS app ZIP metadata member ${JSON.stringify(entry.name)} must not be a symlink`);
-  if (
-    entry.uncompressedSize === 0 ||
-    entry.uncompressedSize > ZIP_MAX_SYMLINK_TARGET_BYTES ||
-    entry.compressedSize > ZIP_MAX_SYMLINK_TARGET_BYTES
-  ) {
-    fail(`iOS app ZIP symlink ${JSON.stringify(entry.name)} has an invalid target size`);
-  }
-  const compressed = await readAt(
-    handle,
-    entry.dataOffset,
-    entry.compressedSize,
-    `iOS app ZIP symlink data for ${entry.name}`,
-  );
-  let payload;
-  try {
-    payload = entry.method === 0
-      ? compressed
-      : inflateRawSync(compressed, { maxOutputLength: ZIP_MAX_SYMLINK_TARGET_BYTES });
-  } catch (error) {
-    fail(`iOS app ZIP symlink ${JSON.stringify(entry.name)} could not be decompressed: ${error.message}`);
-  }
-  if (payload.length !== entry.uncompressedSize || crc32(payload) !== entry.crc32) {
-    fail(`iOS app ZIP symlink ${JSON.stringify(entry.name)} fails size or CRC validation`);
-  }
-  let target;
-  try {
-    target = UTF8.decode(payload);
-  } catch {
-    fail(`iOS app ZIP symlink ${JSON.stringify(entry.name)} target is not valid UTF-8`);
-  }
-  if (
-    target.length === 0 ||
-    path.posix.isAbsolute(target) ||
-    target.includes("\\") ||
-    /^[A-Za-z]:/u.test(target) ||
-    /[\u0000-\u001f\u007f]/u.test(target)
-  ) {
-    fail(`iOS app ZIP symlink ${JSON.stringify(entry.name)} has unsafe target ${JSON.stringify(target)}`);
-  }
-  const resolved = path.posix.normalize(path.posix.join(path.posix.dirname(entry.canonical), target));
-  if (resolved !== appName && !resolved.startsWith(`${appName}/`)) {
-    fail(`iOS app ZIP symlink ${JSON.stringify(entry.name)} escapes ${appName}: ${JSON.stringify(target)}`);
-  }
-}
-
-export async function validateIosAppZipArchive(archive, expectedAppName) {
-  const appName = safeLeaf(expectedAppName, "ZIP app bundle name", ".app");
-  const stat = await requireRegularFile(archive, "iOS app ZIP archive");
-  const handle = await fs.open(archive, "r");
-  try {
-    const directory = await zipDirectory(handle, stat.size);
-    const central = await readAt(
-      handle,
-      directory.centralOffset,
-      directory.centralSize,
-      "iOS app ZIP central directory",
-    );
-    const entries = [];
-    const paths = new Map();
-    const normalizedPaths = new Map();
-    const foldedPaths = new Map();
-    let cursor = 0;
-    for (let index = 0; index < directory.entries; index += 1) {
-      if (cursor + 46 > central.length || central.readUInt32LE(cursor) !== ZIP_CENTRAL_SIGNATURE) {
-        fail(`iOS app ZIP central entry ${index + 1} is missing or malformed`);
-      }
-      const versionMadeBy = central.readUInt16LE(cursor + 4);
-      const flags = central.readUInt16LE(cursor + 8);
-      const method = central.readUInt16LE(cursor + 10);
-      const checksum = central.readUInt32LE(cursor + 16);
-      const compressed32 = central.readUInt32LE(cursor + 20);
-      const uncompressed32 = central.readUInt32LE(cursor + 24);
-      const nameBytes = central.readUInt16LE(cursor + 28);
-      const extraBytes = central.readUInt16LE(cursor + 30);
-      const commentBytes = central.readUInt16LE(cursor + 32);
-      const diskStart16 = central.readUInt16LE(cursor + 34);
-      const externalAttributes = central.readUInt32LE(cursor + 38);
-      const localOffset32 = central.readUInt32LE(cursor + 42);
-      const end = cursor + 46 + nameBytes + extraBytes + commentBytes;
-      if (end > central.length) fail(`iOS app ZIP central entry ${index + 1} is truncated`);
-      if ((flags & 0x0001) !== 0 || (flags & 0x0040) !== 0) {
-        fail(`iOS app ZIP central entry ${index + 1} is encrypted`);
-      }
-      if (method !== 0 && method !== 8) {
-        fail(`iOS app ZIP central entry ${index + 1} uses unsupported compression method ${method}`);
-      }
-      const rawName = central.subarray(cursor + 46, cursor + 46 + nameBytes);
-      const name = decodeZipName(rawName, `iOS app ZIP central entry ${index + 1}`);
-      const member = zipMemberPath(name, appName);
-      const extra = central.subarray(
-        cursor + 46 + nameBytes,
-        cursor + 46 + nameBytes + extraBytes,
-      );
-      const sizes = zip64EntryValues({
-        compressedSize: compressed32,
-        diskStart: diskStart16,
-        extra,
-        label: `iOS app ZIP central entry ${JSON.stringify(name)}`,
-        localOffset: localOffset32,
-        uncompressedSize: uncompressed32,
-      });
-      if (sizes.diskStart !== 0) fail("multi-disk iOS app ZIP entries are not supported");
-      const type = zipMemberType(versionMadeBy, externalAttributes, member.directory, name);
-      if (type === "directory" && (sizes.compressedSize !== 0 || sizes.uncompressedSize !== 0)) {
-        fail(`iOS app ZIP directory ${JSON.stringify(name)} must have an empty payload`);
-      }
-      const prior = paths.get(member.canonical);
-      if (prior !== undefined) {
-        fail(`iOS app ZIP repeats member path ${JSON.stringify(member.canonical)}`);
-      }
-      const normalizedPrior = normalizedPaths.get(member.normalized);
-      if (normalizedPrior !== undefined) {
-        fail(
-          `iOS app ZIP has Unicode-normalization-colliding members ` +
-            `${JSON.stringify(normalizedPrior)} and ${JSON.stringify(name)}`,
-        );
-      }
-      const entry = {
-        ...member,
-        compressedSize: sizes.compressedSize,
-        crc32: checksum,
-        flags,
-        localOffset: sizes.localOffset,
-        method,
-        name,
-        rawName: Buffer.from(rawName),
-        type,
-        uncompressedSize: sizes.uncompressedSize,
-        zip64Sizes: compressed32 === 0xffffffff || uncompressed32 === 0xffffffff,
-      };
-      paths.set(member.canonical, entry);
-      normalizedPaths.set(member.normalized, name);
-      const folded = portableCaseFold(member.normalized);
-      const foldedEntries = foldedPaths.get(folded) ?? [];
-      foldedEntries.push(entry);
-      foldedPaths.set(folded, foldedEntries);
-      entries.push(entry);
-      cursor = end;
-    }
-    if (cursor !== central.length) fail("iOS app ZIP central directory contains trailing records");
-
-    const root = paths.get(appName);
-    if (root?.type !== "directory") {
-      fail(`iOS app ZIP must contain the direct app root ${appName}/`);
-    }
-    for (const entry of entries) {
-      await validateZipLocalEntry(handle, entry, directory.centralOffset);
-    }
-    const extents = entries
-      .map((entry) => ({ end: entry.dataEnd, entry, name: entry.name, start: entry.localOffset }))
-      .sort((left, right) => left.start - right.start || left.end - right.end);
-    if (extents[0].start !== 0) {
-      fail("iOS app ZIP must not contain an executable prefix or unreferenced bytes before its first local record");
-    }
-    for (let index = 1; index < extents.length; index += 1) {
-      if (extents[index].start < extents[index - 1].end) {
-        fail(
-          `iOS app ZIP local records overlap: ${JSON.stringify(extents[index - 1].name)} and ` +
-            JSON.stringify(extents[index].name),
-        );
-      }
-    }
-    // A ditto ZIP may place the standard data descriptor after a local
-    // payload. No other local-record gaps are accepted: that prevents an
-    // extractor that scans local records from seeing content omitted from the
-    // manifest-bound central directory.
-    for (let index = 0; index < extents.length; index += 1) {
-      const extent = extents[index];
-      const nextStart = extents[index + 1]?.start ?? directory.centralOffset;
-      const gap = nextStart - extent.end;
-      if (extent.entry.usesDataDescriptor) {
-        await validateZipDataDescriptor(handle, extent.entry, extent.end, gap);
-      } else if (gap !== 0) {
-        fail(
-          `iOS app ZIP has an unreferenced or ambiguous ${gap}-byte gap after ` +
-            JSON.stringify(extent.name),
-        );
-      }
-    }
-    for (const foldedEntries of foldedPaths.values()) {
-      if (
-        foldedEntries.length > 1 &&
-        foldedEntries.some(({ type }) => type !== "file")
-      ) {
-        fail(
-          `iOS app ZIP has case-ambiguous non-file members: ` +
-            foldedEntries.map(({ name }) => JSON.stringify(name)).join(", "),
-        );
-      }
-    }
-    for (const entry of entries) {
-      let parent = path.posix.dirname(entry.canonical);
-      while (parent !== ".") {
-        const declaredParent = paths.get(parent);
-        if (declaredParent !== undefined && declaredParent.type !== "directory") {
-          fail(
-            `iOS app ZIP member ${JSON.stringify(entry.name)} descends through non-directory ` +
-              JSON.stringify(declaredParent.name),
-          );
-        }
-        const foldedParents = foldedPaths.get(portableCaseFold(parent)) ?? [];
-        const foldedNonDirectory = foldedParents.find(({ type }) => type !== "directory");
-        if (foldedNonDirectory !== undefined) {
-          fail(
-            `iOS app ZIP member ${JSON.stringify(entry.name)} has a case-ambiguous ` +
-              `non-directory ancestor ${JSON.stringify(foldedNonDirectory.name)}`,
-          );
-        }
-        parent = path.posix.dirname(parent);
-      }
-      if (entry.type === "symlink") await validateZipSymlink(handle, entry, appName);
-    }
-    return { entries: entries.length, zip64: directory.zip64 };
-  } finally {
-    await handle.close();
-  }
-}
-
-function regexEscape(value) {
-  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
-}
-
-const OWNED_TEMPORARY_NAMES = [
-  new RegExp(
-    `^\\.${regexEscape(ARCHIVE_NAME)}\\.[0-9]+(?:\\.[0-9a-f-]+)?\\.tmp\\.zip$`,
-    "u",
-  ),
-  new RegExp(
-    `^\\.?${regexEscape(MANIFEST_NAME)}\\.[0-9]+(?:\\.[0-9a-f-]+)?\\.tmp$`,
-    "u",
-  ),
-];
-
-async function removeOwnedStaleTransportTemps(directory) {
-  for (const entry of await fs.readdir(directory, { withFileTypes: true })) {
-    if (!OWNED_TEMPORARY_NAMES.some((pattern) => pattern.test(entry.name))) continue;
-    if (!entry.isFile() && !entry.isSymbolicLink()) continue;
-    await fs.rm(path.join(directory, entry.name), { force: true });
-  }
-}
-
-async function ensureTransportDirectory(directory) {
-  await fs.mkdir(directory, { recursive: true });
-  const stat = await fs.lstat(directory);
-  if (!stat.isDirectory()) fail(`transport output is not a directory: ${directory}`);
-  await removeOwnedStaleTransportTemps(directory);
-  const allowed = new Set([ARCHIVE_NAME, MANIFEST_NAME, BUILD_REPORT_NAME]);
-  const unexpected = (await fs.readdir(directory)).filter((name) => !allowed.has(name)).sort(compareNames);
-  if (unexpected.length > 0) {
-    fail(`transport directory contains unexpected entries: ${unexpected.join(", ")}`);
-  }
-}
-
-async function validateTransportFiles(directory, manifest) {
-  const expected = new Set([ARCHIVE_NAME, MANIFEST_NAME]);
-  if (manifest.buildReport !== null) expected.add(BUILD_REPORT_NAME);
-  const actual = (await fs.readdir(directory)).sort(compareNames);
-  const wanted = [...expected].sort(compareNames);
-  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
-    fail(`transport directory entries must be ${JSON.stringify(wanted)}; got ${JSON.stringify(actual)}`);
-  }
-  for (const name of wanted) {
-    await requireRegularFile(path.join(directory, name), `transport ${name}`);
-  }
-}
-
-async function writeJsonAtomic(file, value) {
-  const temporary = path.join(
-    path.dirname(file),
-    `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`,
-  );
-  try {
-    await fs.writeFile(temporary, `${JSON.stringify(value, null, 2)}\n`, { flag: "wx" });
-    await fs.rename(temporary, file);
-  } finally {
-    await fs.rm(temporary, { force: true });
-  }
-}
-
-async function normalizeTreeTimes(file) {
-  const stat = await fs.lstat(file);
-  if (stat.isDirectory()) {
-    const children = await fs.readdir(file);
-    children.sort(compareNames);
-    for (const child of children) await normalizeTreeTimes(path.join(file, child));
-  }
-  if (stat.isSymbolicLink()) {
-    await fs.lutimes(file, ARCHIVE_TIMESTAMP, ARCHIVE_TIMESTAMP);
-  } else {
-    await fs.utimes(file, ARCHIVE_TIMESTAMP, ARCHIVE_TIMESTAMP);
-  }
-}
-
-export async function packIosAppTransport({ appDir, transportDir, buildReport = undefined }) {
-  const tools = await appleTools();
-  await requireDirectory(appDir, "iOS app artifact directory");
-  if (path.resolve(appDir) === path.resolve(transportDir)) {
-    fail("--app-dir and --transport-dir must be different directories");
-  }
-  const app = await exactlyOneApp(appDir);
-  const appData = await appIdentity(app.path, tools.plutil);
-
-  let report;
-  const automaticReport = path.join(appDir, BUILD_REPORT_NAME);
-  const reportFile = buildReport ?? ((await statOrUndefined(automaticReport)) !== undefined ? automaticReport : undefined);
-  if (reportFile !== undefined) report = await loadBuildReport(reportFile, appData.name);
-
-  await ensureTransportDirectory(transportDir);
-  const archive = path.join(transportDir, ARCHIVE_NAME);
-  const manifestFile = path.join(transportDir, MANIFEST_NAME);
-  const copiedReport = path.join(transportDir, BUILD_REPORT_NAME);
-  for (const file of [archive, manifestFile, copiedReport]) await fs.rm(file, { force: true });
-
-  const temporaryArchive = path.join(
-    transportDir,
-    `.${ARCHIVE_NAME}.${process.pid}.${randomUUID()}.tmp.zip`,
-  );
-  const archiveStage = path.join(
-    transportDir,
-    `.archive-stage.${process.pid}.${randomUUID()}`,
-  );
-  const stagedApp = path.join(archiveStage, appData.name);
-  try {
-    await fs.mkdir(archiveStage);
-    run(tools.ditto, [appData.name, stagedApp], {
-      cwd: appDir,
-      label: "iOS app deterministic archive staging",
-    });
-    await normalizeTreeTimes(stagedApp);
-    run(
-      tools.ditto,
-      ["-c", "-k", "--sequesterRsrc", "--keepParent", appData.name, temporaryArchive],
-      { cwd: archiveStage, label: "iOS app ditto archive" },
-    );
-    await requireRegularFile(temporaryArchive, "iOS app ditto archive");
-    await fs.rename(temporaryArchive, archive);
-    const archiveStat = await requireRegularFile(archive, "iOS app transport archive");
-    const archiveSha256 = await sha256File(archive);
-    await validateIosAppZipArchive(archive, appData.name);
-
-    if (report !== undefined) {
-      await fs.copyFile(reportFile, copiedReport);
-      const copied = await loadBuildReport(copiedReport, appData.name);
-      if (JSON.stringify(copied.identity) !== JSON.stringify(report.identity)) {
-        fail("copied iOS mobile build report does not match its manifest identity");
-      }
-    }
-    const manifest = {
-      schema: TRANSPORT_SCHEMA,
-      archive: {
-        bytes: archiveStat.size,
-        format: "ditto-zip",
-        name: ARCHIVE_NAME,
-        sha256: archiveSha256,
-      },
-      app: appData,
-      buildReport: report?.identity ?? null,
-    };
-    await writeJsonAtomic(manifestFile, manifest);
-    process.stdout.write(
-      `${JSON.stringify({ archive, buildReport: report === undefined ? null : copiedReport, manifest: manifestFile })}\n`,
-    );
-    return { archive, buildReport: report === undefined ? null : copiedReport, manifest: manifestFile };
-  } finally {
-    await fs.rm(temporaryArchive, { force: true });
-    await fs.rm(archiveStage, { force: true, recursive: true });
-  }
-}
-
-export async function verifyExtractIosAppTransport({ transportDir, outputDir }) {
-  const tools = await appleTools();
-  await requireDirectory(transportDir, "iOS app transport directory");
-  if (inside(transportDir, outputDir)) {
-    fail("--output-dir must not be inside --transport-dir");
-  }
-  if ((await statOrUndefined(outputDir, { follow: false })) !== undefined) {
-    fail(`iOS app extraction output already exists: ${outputDir}`);
-  }
-
-  const manifestFile = path.join(transportDir, MANIFEST_NAME);
-  const manifest = validateManifest(await readJson(manifestFile, "iOS app transport manifest"));
-  await validateTransportFiles(transportDir, manifest);
-
-  const archive = path.join(transportDir, ARCHIVE_NAME);
-  const archiveStat = await requireRegularFile(archive, "iOS app transport archive");
-  if (archiveStat.size !== manifest.archive.bytes) {
-    fail(`transport archive byte count mismatch: expected ${manifest.archive.bytes}, got ${archiveStat.size}`);
-  }
-  const archiveSha256 = await sha256File(archive);
-  if (archiveSha256 !== manifest.archive.sha256) {
-    fail(`transport archive checksum mismatch: expected ${manifest.archive.sha256}, got ${archiveSha256}`);
-  }
-  await validateIosAppZipArchive(archive, manifest.app.name);
-
-  let reportFile;
-  if (manifest.buildReport !== null) {
-    reportFile = path.join(transportDir, BUILD_REPORT_NAME);
-    const report = await loadBuildReport(reportFile, manifest.app.name);
-    if (JSON.stringify(report.identity) !== JSON.stringify(manifest.buildReport)) {
-      fail("transport build report identity does not match its manifest binding");
-    }
-  }
-
-  await fs.mkdir(path.dirname(outputDir), { recursive: true });
-  const temporary = await fs.mkdtemp(path.join(path.dirname(outputDir), ".ios-app-extract-"));
-  try {
-    run(tools.ditto, ["-x", "-k", archive, temporary], { label: "iOS app ditto extraction" });
-    await requireExactDirectEntries(
-      temporary,
-      [manifest.app.name],
-      "extracted iOS app transport root",
-    );
-    const app = await exactlyOneApp(temporary, manifest.app.name);
-    const extracted = await appIdentity(app.path, tools.plutil);
-    for (const key of ["name", "executable", "executableMode", "infoPlistSha256"]) {
-      if (extracted[key] !== manifest.app[key]) {
-        fail(
-          `extracted app ${key} mismatch: expected ${JSON.stringify(manifest.app[key])}, ` +
-            `got ${JSON.stringify(extracted[key])}`,
-        );
-      }
-    }
-    if (
-      extracted.payload.entries !== manifest.app.payload.entries ||
-      extracted.payload.sha256 !== manifest.app.payload.sha256
-    ) {
-      fail(
-        `extracted app payload mismatch: expected ${JSON.stringify(manifest.app.payload)}, ` +
-        `got ${JSON.stringify(extracted.payload)}`,
-      );
-    }
-    if (reportFile !== undefined) {
-      const copiedReport = path.join(temporary, BUILD_REPORT_NAME);
-      await fs.copyFile(reportFile, copiedReport);
-      const copied = await loadBuildReport(copiedReport, manifest.app.name);
-      if (JSON.stringify(copied.identity) !== JSON.stringify(manifest.buildReport)) {
-        fail("extracted build report does not match its manifest binding");
-      }
-    }
-    await fs.rename(temporary, outputDir);
-    const extractedApp = path.join(outputDir, manifest.app.name);
-    const extractedReport = reportFile === undefined ? null : path.join(outputDir, BUILD_REPORT_NAME);
-    const result = {
-      app: extractedApp,
-      buildReport: extractedReport,
-      executable: manifest.app.executable,
-    };
-    process.stdout.write(`${JSON.stringify(result)}\n`);
-    return result;
-  } catch (error) {
-    await fs.rm(temporary, { force: true, recursive: true });
-    throw error;
-  }
-}
-
-async function main(argv) {
-  const args = parseArgs(argv);
-  if (args.command === "pack") {
-    await packIosAppTransport(args);
-  } else {
-    await verifyExtractIosAppTransport(args);
-  }
-}
-
-if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
-  try {
-    await main(process.argv.slice(2));
-  } catch (error) {
-    console.error(error instanceof Error ? error.message : `${PREFIX}: ${String(error)}`);
-    process.exit(1);
-  }
-}
diff --git a/src/sdks/react-native/tools/ios-app-transport.mts b/src/sdks/react-native/tools/ios-app-transport.mts
new file mode 100755
index 000000000..b07259808
--- /dev/null
+++ b/src/sdks/react-native/tools/ios-app-transport.mts
@@ -0,0 +1,1341 @@
+#!/usr/bin/env bun
+
+import { createHash, randomUUID } from 'node:crypto';
+import { createReadStream } from 'node:fs';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { inflateRawSync } from 'node:zlib';
+
+const PREFIX = 'ios-app-transport.mts';
+export const TRANSPORT_SCHEMA = 'oliphaunt-react-native-ios-app-transport-v1';
+export const ARCHIVE_NAME = 'react-native-mobile-ios-app.zip';
+export const MANIFEST_NAME = 'react-native-mobile-ios-app.manifest.json';
+export const BUILD_REPORT_NAME = 'build-report.json';
+const ZIP_EOCD_SIGNATURE = 0x06054b50;
+const ZIP64_EOCD_SIGNATURE = 0x06064b50;
+const ZIP64_LOCATOR_SIGNATURE = 0x07064b50;
+const ZIP_CENTRAL_SIGNATURE = 0x02014b50;
+const ZIP_LOCAL_SIGNATURE = 0x04034b50;
+const ZIP64_EXTRA_ID = 0x0001;
+const ZIP_EOCD_MAX_BYTES = 22 + 0xffff;
+const ZIP_MAX_CENTRAL_BYTES = 256 * 1024 * 1024;
+const ZIP_MAX_ENTRIES = 1_000_000;
+const ZIP_MAX_MEMBER_NAME_BYTES = 4096;
+const ZIP_MAX_SYMLINK_TARGET_BYTES = 64 * 1024;
+const UTF8 = new TextDecoder('utf-8', { fatal: true });
+const ARCHIVE_TIMESTAMP = new Date('2000-01-01T00:00:00.000Z');
+
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+
+function usage() {
+  return `usage:
+  ${PREFIX} pack --app-dir DIR --transport-dir DIR [--build-report FILE]
+  ${PREFIX} verify-extract --transport-dir DIR --output-dir DIR`;
+}
+
+function parseFlags(argv) {
+  const values = new Map();
+  for (let index = 0; index < argv.length; index += 1) {
+    const flag = argv[index];
+    if (!flag.startsWith('--') || flag === '--help') {
+      fail(`unknown argument ${JSON.stringify(flag)}\n${usage()}`);
+    }
+    if (values.has(flag)) {
+      fail(`argument ${flag} must not be repeated`);
+    }
+    const value = argv[index + 1];
+    if (!value || value.startsWith('--')) {
+      fail(`${flag} requires a value`);
+    }
+    values.set(flag, value);
+    index += 1;
+  }
+  return values;
+}
+
+function requireOnlyFlags(values, allowed) {
+  for (const flag of values.keys()) {
+    if (!allowed.has(flag)) {
+      fail(`unknown argument ${flag}\n${usage()}`);
+    }
+  }
+}
+
+function requiredFlag(values, flag) {
+  const value = values.get(flag);
+  if (!value) {
+    fail(`${flag} is required\n${usage()}`);
+  }
+  return path.resolve(value);
+}
+
+function parseArgs(argv) {
+  const command = argv[0];
+  if (command === '--help' || command === '-h') {
+    process.stdout.write(`${usage()}\n`);
+    process.exit(0);
+  }
+  if (!new Set(['pack', 'verify-extract']).has(command)) {
+    fail(`expected pack or verify-extract\n${usage()}`);
+  }
+  const values = parseFlags(argv.slice(1));
+  if (command === 'pack') {
+    requireOnlyFlags(values, new Set(['--app-dir', '--transport-dir', '--build-report']));
+    return {
+      command,
+      appDir: requiredFlag(values, '--app-dir'),
+      transportDir: requiredFlag(values, '--transport-dir'),
+      buildReport: values.has('--build-report')
+        ? path.resolve(values.get('--build-report'))
+        : undefined,
+    };
+  }
+  requireOnlyFlags(values, new Set(['--transport-dir', '--output-dir']));
+  return {
+    command,
+    transportDir: requiredFlag(values, '--transport-dir'),
+    outputDir: requiredFlag(values, '--output-dir'),
+  };
+}
+
+async function statOrUndefined(file, { follow = true } = {}) {
+  try {
+    return follow ? await fs.stat(file) : await fs.lstat(file);
+  } catch (error) {
+    if (error?.code === 'ENOENT') return undefined;
+    throw error;
+  }
+}
+
+async function requireDirectory(directory, label) {
+  if ((await statOrUndefined(directory, { follow: false }))?.isDirectory() !== true) {
+    fail(`${label} is not a directory: ${directory}`);
+  }
+}
+
+async function requireRegularFile(file, label) {
+  const stat = await statOrUndefined(file, { follow: false });
+  if (stat?.isFile() !== true || stat.size === 0) {
+    fail(`${label} is missing, empty, or not a regular file: ${file}`);
+  }
+  return stat;
+}
+
+function safeLeaf(value, label, suffix = undefined) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value === '.' ||
+    value === '..' ||
+    value.includes('/') ||
+    value.includes('\\') ||
+    /[\u0000-\u001f\u007f]/u.test(value) ||
+    path.basename(value) !== value
+  ) {
+    fail(`${label} must be a safe filename; got ${JSON.stringify(value)}`);
+  }
+  if (suffix !== undefined && !value.endsWith(suffix)) {
+    fail(`${label} must end in ${suffix}; got ${JSON.stringify(value)}`);
+  }
+  return value;
+}
+
+async function sha256File(file) {
+  const hash = createHash('sha256');
+  await new Promise((resolve, reject) => {
+    const input = createReadStream(file);
+    input.on('data', (chunk) => hash.update(chunk));
+    input.on('error', reject);
+    input.on('end', resolve);
+  });
+  return hash.digest('hex');
+}
+
+function compareNames(left, right) {
+  return Buffer.compare(Buffer.from(left, 'utf8'), Buffer.from(right, 'utf8'));
+}
+
+function inside(root, candidate) {
+  const relative = path.relative(root, candidate);
+  return (
+    relative === '' ||
+    (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative))
+  );
+}
+
+async function payloadIdentity(app) {
+  const hash = createHash('sha256');
+  let entries = 0;
+
+  async function visit(file, relative) {
+    const stat = await fs.lstat(file);
+    const mode = (stat.mode & 0o7777).toString(8).padStart(4, '0');
+    let row;
+    if (stat.isSymbolicLink()) {
+      const target = await fs.readlink(file);
+      if (path.isAbsolute(target) || !inside(app, path.resolve(path.dirname(file), target))) {
+        fail(`app bundle contains unsafe symlink ${relative} -> ${target}`);
+      }
+      row = { mode, path: relative, target, type: 'symlink' };
+    } else if (stat.isDirectory()) {
+      row = { mode, path: relative, type: 'directory' };
+    } else if (stat.isFile()) {
+      row = {
+        bytes: stat.size,
+        mode,
+        path: relative,
+        sha256: await sha256File(file),
+        type: 'file',
+      };
+    } else {
+      fail(`app bundle contains unsupported special entry: ${relative}`);
+    }
+    hash.update(`${JSON.stringify(row)}\n`);
+    entries += 1;
+
+    if (stat.isDirectory()) {
+      const children = await fs.readdir(file);
+      children.sort(compareNames);
+      for (const child of children) {
+        const childRelative = relative === '.' ? child : `${relative}/${child}`;
+        await visit(path.join(file, child), childRelative);
+      }
+    }
+  }
+
+  await visit(app, '.');
+  return { entries, sha256: hash.digest('hex') };
+}
+
+async function directApps(directory) {
+  const entries = await fs.readdir(directory, { withFileTypes: true });
+  return entries
+    .filter((entry) => entry.isDirectory() && entry.name.endsWith('.app'))
+    .map((entry) => ({ name: entry.name, path: path.join(directory, entry.name) }))
+    .sort((left, right) => compareNames(left.name, right.name));
+}
+
+async function exactlyOneApp(directory, expectedName = undefined) {
+  const apps = await directApps(directory);
+  if (apps.length !== 1) {
+    fail(
+      `${directory} must contain exactly one direct .app directory; ` +
+        `found ${apps.length}${apps.length > 0 ? `: ${apps.map(({ name }) => name).join(', ')}` : ''}`,
+    );
+  }
+  if (expectedName !== undefined && apps[0].name !== expectedName) {
+    fail(`${directory} contains ${apps[0].name}, but the manifest requires ${expectedName}`);
+  }
+  return apps[0];
+}
+
+async function requireExactDirectEntries(directory, expected, label) {
+  const actual = (await fs.readdir(directory)).sort(compareNames);
+  const wanted = [...expected].sort(compareNames);
+  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
+    fail(`${label} entries must be ${JSON.stringify(wanted)}; got ${JSON.stringify(actual)}`);
+  }
+}
+
+async function appIdentity(app, executableText) {
+  const appName = safeLeaf(path.basename(app), 'app bundle name', '.app');
+  const infoPlist = path.join(app, 'Info.plist');
+  await requireRegularFile(infoPlist, `${appName} Info.plist`);
+  const executable = safeLeaf(executableText.trim(), `${appName} CFBundleExecutable`);
+  const executableFile = path.join(app, executable);
+  const executableStat = await requireRegularFile(executableFile, `${appName} executable`);
+  try {
+    await fs.access(executableFile, fs.constants.X_OK);
+  } catch {
+    fail(`${appName} executable is not executable: ${executableFile}`);
+  }
+  return {
+    executable,
+    executableMode: (executableStat.mode & 0o7777).toString(8).padStart(4, '0'),
+    infoPlistSha256: await sha256File(infoPlist),
+    name: appName,
+    payload: await payloadIdentity(app),
+  };
+}
+
+function object(value) {
+  return value !== null && typeof value === 'object' && !Array.isArray(value);
+}
+
+function exactKeys(value, expected, label) {
+  if (!object(value)) fail(`${label} must be a JSON object`);
+  const actual = Object.keys(value).sort(compareNames);
+  const wanted = [...expected].sort(compareNames);
+  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
+    fail(`${label} keys must be ${JSON.stringify(wanted)}; got ${JSON.stringify(actual)}`);
+  }
+}
+
+function sha256Value(value, label) {
+  if (typeof value !== 'string' || !/^[0-9a-f]{64}$/u.test(value)) {
+    fail(`${label} must be a lowercase SHA-256 digest`);
+  }
+  return value;
+}
+
+function safeInteger(value, label, { positive = false } = {}) {
+  if (!Number.isSafeInteger(value) || value < (positive ? 1 : 0)) {
+    fail(`${label} must be a ${positive ? 'positive ' : 'non-negative '}safe integer`);
+  }
+  return value;
+}
+
+async function readJson(file, label) {
+  await requireRegularFile(file, label);
+  try {
+    return JSON.parse(await fs.readFile(file, 'utf8'));
+  } catch (error) {
+    fail(`${label} is not valid JSON: ${error.message}`);
+  }
+}
+
+function reportIdentity(data, { appName, bytes, sha256 }) {
+  if (!object(data)) fail(`${BUILD_REPORT_NAME} must contain a JSON object`);
+  if (data.schema !== 'oliphaunt-react-native-mobile-build-v1') {
+    fail(`${BUILD_REPORT_NAME} has invalid schema ${JSON.stringify(data.schema)}`);
+  }
+  if (data.platform !== 'ios') {
+    fail(`${BUILD_REPORT_NAME} must declare platform=ios`);
+  }
+  if (typeof data.appArtifact !== 'string' || path.basename(data.appArtifact) !== appName) {
+    fail(`${BUILD_REPORT_NAME} appArtifact must identify ${appName}`);
+  }
+  safeInteger(data.appArtifactBytes, `${BUILD_REPORT_NAME} appArtifactBytes`);
+  for (const key of ['configuration', 'sdk']) {
+    if (data[key] !== undefined && typeof data[key] !== 'string') {
+      fail(`${BUILD_REPORT_NAME} ${key} must be a string when present`);
+    }
+  }
+  return {
+    appArtifactBytes: data.appArtifactBytes,
+    appArtifactName: appName,
+    bytes,
+    configuration: data.configuration ?? null,
+    name: BUILD_REPORT_NAME,
+    platform: data.platform,
+    schema: data.schema,
+    sdk: data.sdk ?? null,
+    sha256,
+  };
+}
+
+async function loadBuildReport(file, appName) {
+  const stat = await requireRegularFile(file, 'iOS mobile build report');
+  const sha256 = await sha256File(file);
+  const data = await readJson(file, 'iOS mobile build report');
+  return { identity: reportIdentity(data, { appName, bytes: stat.size, sha256 }) };
+}
+
+function validateReportIdentity(value) {
+  exactKeys(
+    value,
+    [
+      'appArtifactBytes',
+      'appArtifactName',
+      'bytes',
+      'configuration',
+      'name',
+      'platform',
+      'schema',
+      'sdk',
+      'sha256',
+    ],
+    'transport manifest buildReport',
+  );
+  if (value.name !== BUILD_REPORT_NAME)
+    fail(`transport build report name must be ${BUILD_REPORT_NAME}`);
+  if (value.schema !== 'oliphaunt-react-native-mobile-build-v1' || value.platform !== 'ios') {
+    fail('transport build report identity must describe an iOS mobile build report');
+  }
+  safeLeaf(value.appArtifactName, 'transport build report appArtifactName', '.app');
+  safeInteger(value.appArtifactBytes, 'transport build report appArtifactBytes');
+  safeInteger(value.bytes, 'transport build report bytes', { positive: true });
+  sha256Value(value.sha256, 'transport build report sha256');
+  for (const key of ['configuration', 'sdk']) {
+    if (value[key] !== null && typeof value[key] !== 'string') {
+      fail(`transport build report ${key} must be a string or null`);
+    }
+  }
+}
+
+function validateManifest(data) {
+  exactKeys(data, ['app', 'archive', 'buildReport', 'schema'], 'transport manifest');
+  if (data.schema !== TRANSPORT_SCHEMA) {
+    fail(
+      `transport manifest schema must be ${TRANSPORT_SCHEMA}; got ${JSON.stringify(data.schema)}`,
+    );
+  }
+  exactKeys(data.archive, ['bytes', 'format', 'name', 'sha256'], 'transport manifest archive');
+  if (data.archive.name !== ARCHIVE_NAME || data.archive.format !== 'ditto-zip') {
+    fail(`transport archive must be ${ARCHIVE_NAME} in ditto-zip format`);
+  }
+  safeInteger(data.archive.bytes, 'transport archive bytes', { positive: true });
+  sha256Value(data.archive.sha256, 'transport archive sha256');
+
+  exactKeys(
+    data.app,
+    ['executable', 'executableMode', 'infoPlistSha256', 'name', 'payload'],
+    'transport manifest app',
+  );
+  safeLeaf(data.app.name, 'transport app name', '.app');
+  safeLeaf(data.app.executable, 'transport app executable');
+  if (typeof data.app.executableMode !== 'string' || !/^[0-7]{4}$/u.test(data.app.executableMode)) {
+    fail('transport app executableMode must be a four-digit octal mode');
+  }
+  if ((Number.parseInt(data.app.executableMode, 8) & 0o111) === 0) {
+    fail('transport app executableMode must include an executable bit');
+  }
+  sha256Value(data.app.infoPlistSha256, 'transport app Info.plist sha256');
+  exactKeys(data.app.payload, ['entries', 'sha256'], 'transport manifest app payload');
+  safeInteger(data.app.payload.entries, 'transport app payload entries', { positive: true });
+  sha256Value(data.app.payload.sha256, 'transport app payload sha256');
+
+  if (data.buildReport !== null) {
+    validateReportIdentity(data.buildReport);
+    if (data.buildReport.appArtifactName !== data.app.name) {
+      fail('transport build report and app names do not match');
+    }
+  }
+  return data;
+}
+
+async function readAt(handle, offset, length, label) {
+  if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(length) || length < 0) {
+    fail(`${label} has an invalid byte range`);
+  }
+  const buffer = Buffer.alloc(length);
+  let consumed = 0;
+  while (consumed < length) {
+    const { bytesRead } = await handle.read(buffer, consumed, length - consumed, offset + consumed);
+    if (bytesRead === 0) {
+      fail(`${label} is truncated at byte ${offset + consumed}`);
+    }
+    consumed += bytesRead;
+  }
+  return buffer;
+}
+
+function safeZipNumber(value, label) {
+  if (typeof value === 'bigint') {
+    if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
+      fail(`${label} exceeds the JavaScript safe-integer range`);
+    }
+    value = Number(value);
+  }
+  if (!Number.isSafeInteger(value) || value < 0) {
+    fail(`${label} must be a non-negative safe integer`);
+  }
+  return value;
+}
+
+function extraFields(buffer, label) {
+  const fields = new Map();
+  let cursor = 0;
+  while (cursor < buffer.length) {
+    if (cursor + 4 > buffer.length) fail(`${label} has a truncated extra-field header`);
+    const id = buffer.readUInt16LE(cursor);
+    const size = buffer.readUInt16LE(cursor + 2);
+    cursor += 4;
+    if (cursor + size > buffer.length)
+      fail(`${label} has a truncated 0x${id.toString(16)} extra field`);
+    if (fields.has(id)) fail(`${label} repeats extra field 0x${id.toString(16)}`);
+    fields.set(id, buffer.subarray(cursor, cursor + size));
+    cursor += size;
+  }
+  return fields;
+}
+
+function zip64EntryValues({
+  compressedSize,
+  diskStart,
+  extra,
+  localOffset,
+  uncompressedSize,
+  label,
+}) {
+  const needed =
+    uncompressedSize === 0xffffffff ||
+    compressedSize === 0xffffffff ||
+    localOffset === 0xffffffff ||
+    diskStart === 0xffff;
+  if (!needed) {
+    return { compressedSize, diskStart, localOffset, uncompressedSize };
+  }
+  const zip64 = extraFields(extra, label).get(ZIP64_EXTRA_ID);
+  if (zip64 === undefined) fail(`${label} requires a ZIP64 extra field`);
+  let cursor = 0;
+  const read64 = (field) => {
+    if (cursor + 8 > zip64.length) fail(`${label} ZIP64 ${field} is truncated`);
+    const value = safeZipNumber(zip64.readBigUInt64LE(cursor), `${label} ZIP64 ${field}`);
+    cursor += 8;
+    return value;
+  };
+  const read32 = (field) => {
+    if (cursor + 4 > zip64.length) fail(`${label} ZIP64 ${field} is truncated`);
+    const value = zip64.readUInt32LE(cursor);
+    cursor += 4;
+    return value;
+  };
+  if (uncompressedSize === 0xffffffff) uncompressedSize = read64('uncompressed size');
+  if (compressedSize === 0xffffffff) compressedSize = read64('compressed size');
+  if (localOffset === 0xffffffff) localOffset = read64('local-header offset');
+  if (diskStart === 0xffff) diskStart = read32('disk start');
+  return { compressedSize, diskStart, localOffset, uncompressedSize };
+}
+
+async function zipDirectory(handle, archiveSize) {
+  if (archiveSize < 22)
+    fail('iOS app ZIP is too short to contain an end-of-central-directory record');
+  const tailSize = Math.min(archiveSize, ZIP_EOCD_MAX_BYTES);
+  const tailOffset = archiveSize - tailSize;
+  const tail = await readAt(handle, tailOffset, tailSize, 'iOS app ZIP tail');
+  let eocdIndex = -1;
+  for (let index = tail.length - 22; index >= 0; index -= 1) {
+    if (tail.readUInt32LE(index) !== ZIP_EOCD_SIGNATURE) continue;
+    const commentBytes = tail.readUInt16LE(index + 20);
+    if (index + 22 + commentBytes === tail.length) {
+      eocdIndex = index;
+      break;
+    }
+  }
+  if (eocdIndex < 0) fail('iOS app ZIP has no well-formed end-of-central-directory record');
+
+  const eocdOffset = tailOffset + eocdIndex;
+  const disk = tail.readUInt16LE(eocdIndex + 4);
+  const centralDisk = tail.readUInt16LE(eocdIndex + 6);
+  let diskEntries = tail.readUInt16LE(eocdIndex + 8);
+  let entries = tail.readUInt16LE(eocdIndex + 10);
+  let centralSize = tail.readUInt32LE(eocdIndex + 12);
+  let centralOffset = tail.readUInt32LE(eocdIndex + 16);
+  let centralBoundary = eocdOffset;
+  const zip64 =
+    disk === 0xffff ||
+    centralDisk === 0xffff ||
+    diskEntries === 0xffff ||
+    entries === 0xffff ||
+    centralSize === 0xffffffff ||
+    centralOffset === 0xffffffff;
+
+  if (zip64) {
+    if (eocdOffset < 20) fail('iOS app ZIP64 locator is missing');
+    const locator = await readAt(handle, eocdOffset - 20, 20, 'iOS app ZIP64 locator');
+    if (locator.readUInt32LE(0) !== ZIP64_LOCATOR_SIGNATURE) {
+      fail('iOS app ZIP64 locator has an invalid signature');
+    }
+    const zip64Disk = locator.readUInt32LE(4);
+    const zip64Offset = safeZipNumber(locator.readBigUInt64LE(8), 'iOS app ZIP64 record offset');
+    const totalDisks = locator.readUInt32LE(16);
+    if (zip64Disk !== 0 || totalDisks !== 1)
+      fail('multi-disk iOS app ZIP64 archives are not supported');
+    const record = await readAt(handle, zip64Offset, 56, 'iOS app ZIP64 end record');
+    if (record.readUInt32LE(0) !== ZIP64_EOCD_SIGNATURE) {
+      fail('iOS app ZIP64 end record has an invalid signature');
+    }
+    const recordBytes = safeZipNumber(record.readBigUInt64LE(4), 'iOS app ZIP64 record size');
+    const locatorOffset = eocdOffset - 20;
+    if (
+      recordBytes < 44 ||
+      zip64Offset > locatorOffset ||
+      locatorOffset - zip64Offset < 12 ||
+      recordBytes !== locatorOffset - zip64Offset - 12
+    ) {
+      fail('iOS app ZIP64 end record has an invalid extent');
+    }
+    if (record.readUInt32LE(16) !== 0 || record.readUInt32LE(20) !== 0) {
+      fail('multi-disk iOS app ZIP64 archives are not supported');
+    }
+    diskEntries = safeZipNumber(record.readBigUInt64LE(24), 'iOS app ZIP64 disk entry count');
+    entries = safeZipNumber(record.readBigUInt64LE(32), 'iOS app ZIP64 entry count');
+    centralSize = safeZipNumber(record.readBigUInt64LE(40), 'iOS app ZIP64 central size');
+    centralOffset = safeZipNumber(record.readBigUInt64LE(48), 'iOS app ZIP64 central offset');
+    centralBoundary = zip64Offset;
+  } else if (disk !== 0 || centralDisk !== 0) {
+    fail('multi-disk iOS app ZIP archives are not supported');
+  }
+
+  if (diskEntries !== entries) fail('iOS app ZIP central-directory entry counts do not match');
+  if (entries === 0 || entries > ZIP_MAX_ENTRIES) {
+    fail(`iOS app ZIP entry count must be between 1 and ${ZIP_MAX_ENTRIES}`);
+  }
+  if (centralSize === 0 || centralSize > ZIP_MAX_CENTRAL_BYTES) {
+    fail(`iOS app ZIP central directory must be between 1 and ${ZIP_MAX_CENTRAL_BYTES} bytes`);
+  }
+  if (
+    centralBoundary > archiveSize ||
+    centralOffset > centralBoundary ||
+    centralSize !== centralBoundary - centralOffset
+  ) {
+    fail('iOS app ZIP central directory has an invalid or ambiguous extent');
+  }
+  return { centralOffset, centralSize, entries, zip64 };
+}
+
+function decodeZipName(buffer, label) {
+  if (buffer.length === 0 || buffer.length > ZIP_MAX_MEMBER_NAME_BYTES) {
+    fail(`${label} must contain between 1 and ${ZIP_MAX_MEMBER_NAME_BYTES} filename bytes`);
+  }
+  try {
+    return UTF8.decode(buffer);
+  } catch {
+    fail(`${label} is not valid UTF-8`);
+  }
+}
+
+function zipMemberPath(name, appName) {
+  if (
+    name.startsWith('/') ||
+    name.includes('\\') ||
+    /^[A-Za-z]:/u.test(name) ||
+    /[\u0000-\u001f\u007f]/u.test(name)
+  ) {
+    fail(`iOS app ZIP contains unsafe member path ${JSON.stringify(name)}`);
+  }
+  const directory = name.endsWith('/');
+  const components = name.split('/');
+  if (directory) components.pop();
+  if (
+    components.length === 0 ||
+    components.some(
+      (component) =>
+        component === '' ||
+        component === '.' ||
+        component === '..' ||
+        Buffer.byteLength(component, 'utf8') > 255,
+    )
+  ) {
+    fail(`iOS app ZIP contains unsafe member path ${JSON.stringify(name)}`);
+  }
+  const metadata = components[0] === '__MACOSX';
+  if (!metadata && components[0] !== appName) {
+    fail(`iOS app ZIP member is outside ${appName}: ${JSON.stringify(name)}`);
+  }
+  if (metadata) {
+    if (components.length === 1 && !directory) {
+      fail('iOS app ZIP __MACOSX root must be a directory');
+    }
+    if (components.length > 1 && components[1] !== appName && components[1] !== `._${appName}`) {
+      fail(`iOS app ZIP metadata member is unrelated to ${appName}: ${JSON.stringify(name)}`);
+    }
+  }
+  return {
+    canonical: components.join('/'),
+    directory,
+    metadata,
+    normalized: components.join('/').normalize('NFC'),
+  };
+}
+
+function portableCaseFold(value) {
+  // NFKC expands compatibility characters and the upper/lower round-trip
+  // catches multi-code-point folds such as sharp-s. This is deliberately
+  // conservative across the case-insensitive filesystems a macOS runner may
+  // use during extraction.
+  return value.normalize('NFKC').toUpperCase().toLowerCase().normalize('NFC');
+}
+
+function zipMemberType(versionMadeBy, externalAttributes, directoryHint, name) {
+  const host = versionMadeBy >>> 8;
+  const mode = externalAttributes >>> 16;
+  const unixType = mode & 0o170000;
+  let type;
+  if (unixType !== 0) {
+    type = new Map([
+      [0o040000, 'directory'],
+      [0o100000, 'file'],
+      [0o120000, 'symlink'],
+    ]).get(unixType);
+    if (type === undefined) {
+      fail(
+        `iOS app ZIP member ${JSON.stringify(name)} uses unsupported special mode ` +
+          `0${unixType.toString(8)} from host ${host}`,
+      );
+    }
+  } else {
+    type = (externalAttributes & 0x10) !== 0 || directoryHint ? 'directory' : 'file';
+  }
+  if ((type === 'directory') !== directoryHint) {
+    fail(`iOS app ZIP member ${JSON.stringify(name)} has inconsistent directory metadata`);
+  }
+  return type;
+}
+
+const CRC32_TABLE = (() => {
+  const table = new Uint32Array(256);
+  for (let index = 0; index < table.length; index += 1) {
+    let value = index;
+    for (let bit = 0; bit < 8; bit += 1) {
+      value = (value & 1) === 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;
+    }
+    table[index] = value >>> 0;
+  }
+  return table;
+})();
+
+function crc32(buffer) {
+  let value = 0xffffffff;
+  for (const byte of buffer) value = CRC32_TABLE[(value ^ byte) & 0xff] ^ (value >>> 8);
+  return (value ^ 0xffffffff) >>> 0;
+}
+
+async function validateZipLocalEntry(handle, entry, centralOffset) {
+  if (entry.localOffset > centralOffset || centralOffset - entry.localOffset < 30) {
+    fail(
+      `iOS app ZIP local header for ${JSON.stringify(entry.name)} is outside the payload region`,
+    );
+  }
+  const header = await readAt(
+    handle,
+    entry.localOffset,
+    30,
+    `iOS app ZIP local header for ${entry.name}`,
+  );
+  if (header.readUInt32LE(0) !== ZIP_LOCAL_SIGNATURE) {
+    fail(`iOS app ZIP local header for ${JSON.stringify(entry.name)} has an invalid signature`);
+  }
+  const flags = header.readUInt16LE(6);
+  const method = header.readUInt16LE(8);
+  const checksum = header.readUInt32LE(14);
+  const compressed32 = header.readUInt32LE(18);
+  const uncompressed32 = header.readUInt32LE(22);
+  const nameBytes = header.readUInt16LE(26);
+  const extraBytes = header.readUInt16LE(28);
+  if (flags !== entry.flags || method !== entry.method) {
+    fail(`iOS app ZIP local header metadata does not match ${JSON.stringify(entry.name)}`);
+  }
+  const localName = await readAt(
+    handle,
+    entry.localOffset + 30,
+    nameBytes,
+    `iOS app ZIP local filename for ${entry.name}`,
+  );
+  if (!localName.equals(entry.rawName)) {
+    fail(
+      `iOS app ZIP local header filename does not match central member ${JSON.stringify(entry.name)}`,
+    );
+  }
+  const localExtra = await readAt(
+    handle,
+    entry.localOffset + 30 + nameBytes,
+    extraBytes,
+    `iOS app ZIP local extra fields for ${entry.name}`,
+  );
+  const localSizes = zip64EntryValues({
+    compressedSize: compressed32,
+    diskStart: 0,
+    extra: localExtra,
+    label: `iOS app ZIP local header ${JSON.stringify(entry.name)}`,
+    localOffset: 0,
+    uncompressedSize: uncompressed32,
+  });
+  const descriptor = (flags & 0x0008) !== 0;
+  if (descriptor) {
+    if (checksum !== 0 && checksum !== entry.crc32) {
+      fail(`iOS app ZIP local CRC disagrees with central member ${JSON.stringify(entry.name)}`);
+    }
+    for (const [label, raw, resolved, expected] of [
+      ['compressed size', compressed32, localSizes.compressedSize, entry.compressedSize],
+      ['uncompressed size', uncompressed32, localSizes.uncompressedSize, entry.uncompressedSize],
+    ]) {
+      if (raw !== 0 && resolved !== 0 && resolved !== expected) {
+        fail(
+          `iOS app ZIP local ${label} disagrees with central member ${JSON.stringify(entry.name)}`,
+        );
+      }
+    }
+  } else if (
+    checksum !== entry.crc32 ||
+    localSizes.compressedSize !== entry.compressedSize ||
+    localSizes.uncompressedSize !== entry.uncompressedSize
+  ) {
+    fail(
+      `iOS app ZIP local CRC or sizes disagree with central member ${JSON.stringify(entry.name)}`,
+    );
+  }
+  const headerBytes = 30 + nameBytes + extraBytes;
+  if (entry.localOffset > centralOffset || headerBytes > centralOffset - entry.localOffset) {
+    fail(
+      `iOS app ZIP local header for ${JSON.stringify(entry.name)} overlaps the central directory`,
+    );
+  }
+  const dataOffset = entry.localOffset + headerBytes;
+  if (dataOffset > centralOffset || entry.compressedSize > centralOffset - dataOffset) {
+    fail(`iOS app ZIP data for ${JSON.stringify(entry.name)} overlaps the central directory`);
+  }
+  const dataEnd = dataOffset + entry.compressedSize;
+  entry.dataOffset = dataOffset;
+  entry.dataEnd = dataEnd;
+  entry.usesDataDescriptor = descriptor;
+}
+
+async function validateZipDataDescriptor(handle, entry, offset, length) {
+  const zip64Sizes = entry.zip64Sizes;
+  const unsignedBytes = zip64Sizes ? 20 : 12;
+  const signedBytes = unsignedBytes + 4;
+  if (length !== unsignedBytes && length !== signedBytes) {
+    fail(
+      `iOS app ZIP has an unreferenced or ambiguous ${length}-byte gap after ` +
+        JSON.stringify(entry.name),
+    );
+  }
+  const descriptor = await readAt(
+    handle,
+    offset,
+    length,
+    `iOS app ZIP data descriptor for ${entry.name}`,
+  );
+  let cursor = 0;
+  if (length === signedBytes) {
+    if (descriptor.readUInt32LE(0) !== 0x08074b50) {
+      fail(
+        `iOS app ZIP data descriptor for ${JSON.stringify(entry.name)} has an invalid signature`,
+      );
+    }
+    cursor = 4;
+  }
+  const checksum = descriptor.readUInt32LE(cursor);
+  cursor += 4;
+  const compressedSize = zip64Sizes
+    ? safeZipNumber(
+        descriptor.readBigUInt64LE(cursor),
+        `ZIP64 descriptor compressed size for ${entry.name}`,
+      )
+    : descriptor.readUInt32LE(cursor);
+  cursor += zip64Sizes ? 8 : 4;
+  const uncompressedSize = zip64Sizes
+    ? safeZipNumber(
+        descriptor.readBigUInt64LE(cursor),
+        `ZIP64 descriptor uncompressed size for ${entry.name}`,
+      )
+    : descriptor.readUInt32LE(cursor);
+  if (
+    checksum !== entry.crc32 ||
+    compressedSize !== entry.compressedSize ||
+    uncompressedSize !== entry.uncompressedSize
+  ) {
+    fail(`iOS app ZIP data descriptor disagrees with central member ${JSON.stringify(entry.name)}`);
+  }
+}
+
+async function validateZipSymlink(handle, entry, appName) {
+  if (entry.metadata)
+    fail(`iOS app ZIP metadata member ${JSON.stringify(entry.name)} must not be a symlink`);
+  if (
+    entry.uncompressedSize === 0 ||
+    entry.uncompressedSize > ZIP_MAX_SYMLINK_TARGET_BYTES ||
+    entry.compressedSize > ZIP_MAX_SYMLINK_TARGET_BYTES
+  ) {
+    fail(`iOS app ZIP symlink ${JSON.stringify(entry.name)} has an invalid target size`);
+  }
+  const compressed = await readAt(
+    handle,
+    entry.dataOffset,
+    entry.compressedSize,
+    `iOS app ZIP symlink data for ${entry.name}`,
+  );
+  let payload;
+  try {
+    payload =
+      entry.method === 0
+        ? compressed
+        : inflateRawSync(compressed, { maxOutputLength: ZIP_MAX_SYMLINK_TARGET_BYTES });
+  } catch (error) {
+    fail(
+      `iOS app ZIP symlink ${JSON.stringify(entry.name)} could not be decompressed: ${error.message}`,
+    );
+  }
+  if (payload.length !== entry.uncompressedSize || crc32(payload) !== entry.crc32) {
+    fail(`iOS app ZIP symlink ${JSON.stringify(entry.name)} fails size or CRC validation`);
+  }
+  let target;
+  try {
+    target = UTF8.decode(payload);
+  } catch {
+    fail(`iOS app ZIP symlink ${JSON.stringify(entry.name)} target is not valid UTF-8`);
+  }
+  if (
+    target.length === 0 ||
+    path.posix.isAbsolute(target) ||
+    target.includes('\\') ||
+    /^[A-Za-z]:/u.test(target) ||
+    /[\u0000-\u001f\u007f]/u.test(target)
+  ) {
+    fail(
+      `iOS app ZIP symlink ${JSON.stringify(entry.name)} has unsafe target ${JSON.stringify(target)}`,
+    );
+  }
+  const resolved = path.posix.normalize(
+    path.posix.join(path.posix.dirname(entry.canonical), target),
+  );
+  if (resolved !== appName && !resolved.startsWith(`${appName}/`)) {
+    fail(
+      `iOS app ZIP symlink ${JSON.stringify(entry.name)} escapes ${appName}: ${JSON.stringify(target)}`,
+    );
+  }
+}
+
+export async function validateIosAppZipArchive(archive, expectedAppName) {
+  const appName = safeLeaf(expectedAppName, 'ZIP app bundle name', '.app');
+  const stat = await requireRegularFile(archive, 'iOS app ZIP archive');
+  const handle = await fs.open(archive, 'r');
+  try {
+    const directory = await zipDirectory(handle, stat.size);
+    const central = await readAt(
+      handle,
+      directory.centralOffset,
+      directory.centralSize,
+      'iOS app ZIP central directory',
+    );
+    const entries = [];
+    const paths = new Map();
+    const normalizedPaths = new Map();
+    const foldedPaths = new Map();
+    let cursor = 0;
+    for (let index = 0; index < directory.entries; index += 1) {
+      if (cursor + 46 > central.length || central.readUInt32LE(cursor) !== ZIP_CENTRAL_SIGNATURE) {
+        fail(`iOS app ZIP central entry ${index + 1} is missing or malformed`);
+      }
+      const versionMadeBy = central.readUInt16LE(cursor + 4);
+      const flags = central.readUInt16LE(cursor + 8);
+      const method = central.readUInt16LE(cursor + 10);
+      const checksum = central.readUInt32LE(cursor + 16);
+      const compressed32 = central.readUInt32LE(cursor + 20);
+      const uncompressed32 = central.readUInt32LE(cursor + 24);
+      const nameBytes = central.readUInt16LE(cursor + 28);
+      const extraBytes = central.readUInt16LE(cursor + 30);
+      const commentBytes = central.readUInt16LE(cursor + 32);
+      const diskStart16 = central.readUInt16LE(cursor + 34);
+      const externalAttributes = central.readUInt32LE(cursor + 38);
+      const localOffset32 = central.readUInt32LE(cursor + 42);
+      const end = cursor + 46 + nameBytes + extraBytes + commentBytes;
+      if (end > central.length) fail(`iOS app ZIP central entry ${index + 1} is truncated`);
+      if ((flags & 0x0001) !== 0 || (flags & 0x0040) !== 0) {
+        fail(`iOS app ZIP central entry ${index + 1} is encrypted`);
+      }
+      if (method !== 0 && method !== 8) {
+        fail(
+          `iOS app ZIP central entry ${index + 1} uses unsupported compression method ${method}`,
+        );
+      }
+      const rawName = central.subarray(cursor + 46, cursor + 46 + nameBytes);
+      const name = decodeZipName(rawName, `iOS app ZIP central entry ${index + 1}`);
+      const member = zipMemberPath(name, appName);
+      const extra = central.subarray(cursor + 46 + nameBytes, cursor + 46 + nameBytes + extraBytes);
+      const sizes = zip64EntryValues({
+        compressedSize: compressed32,
+        diskStart: diskStart16,
+        extra,
+        label: `iOS app ZIP central entry ${JSON.stringify(name)}`,
+        localOffset: localOffset32,
+        uncompressedSize: uncompressed32,
+      });
+      if (sizes.diskStart !== 0) fail('multi-disk iOS app ZIP entries are not supported');
+      const type = zipMemberType(versionMadeBy, externalAttributes, member.directory, name);
+      if (type === 'directory' && (sizes.compressedSize !== 0 || sizes.uncompressedSize !== 0)) {
+        fail(`iOS app ZIP directory ${JSON.stringify(name)} must have an empty payload`);
+      }
+      const prior = paths.get(member.canonical);
+      if (prior !== undefined) {
+        fail(`iOS app ZIP repeats member path ${JSON.stringify(member.canonical)}`);
+      }
+      const normalizedPrior = normalizedPaths.get(member.normalized);
+      if (normalizedPrior !== undefined) {
+        fail(
+          `iOS app ZIP has Unicode-normalization-colliding members ` +
+            `${JSON.stringify(normalizedPrior)} and ${JSON.stringify(name)}`,
+        );
+      }
+      const entry = {
+        ...member,
+        compressedSize: sizes.compressedSize,
+        crc32: checksum,
+        flags,
+        localOffset: sizes.localOffset,
+        method,
+        name,
+        rawName: Buffer.from(rawName),
+        type,
+        uncompressedSize: sizes.uncompressedSize,
+        zip64Sizes: compressed32 === 0xffffffff || uncompressed32 === 0xffffffff,
+      };
+      paths.set(member.canonical, entry);
+      normalizedPaths.set(member.normalized, name);
+      const folded = portableCaseFold(member.normalized);
+      const foldedEntries = foldedPaths.get(folded) ?? [];
+      foldedEntries.push(entry);
+      foldedPaths.set(folded, foldedEntries);
+      entries.push(entry);
+      cursor = end;
+    }
+    if (cursor !== central.length) fail('iOS app ZIP central directory contains trailing records');
+
+    const root = paths.get(appName);
+    if (root?.type !== 'directory') {
+      fail(`iOS app ZIP must contain the direct app root ${appName}/`);
+    }
+    for (const entry of entries) {
+      await validateZipLocalEntry(handle, entry, directory.centralOffset);
+    }
+    const extents = entries
+      .map((entry) => ({ end: entry.dataEnd, entry, name: entry.name, start: entry.localOffset }))
+      .sort((left, right) => left.start - right.start || left.end - right.end);
+    if (extents[0].start !== 0) {
+      fail(
+        'iOS app ZIP must not contain an executable prefix or unreferenced bytes before its first local record',
+      );
+    }
+    for (let index = 1; index < extents.length; index += 1) {
+      if (extents[index].start < extents[index - 1].end) {
+        fail(
+          `iOS app ZIP local records overlap: ${JSON.stringify(extents[index - 1].name)} and ` +
+            JSON.stringify(extents[index].name),
+        );
+      }
+    }
+    // A ditto ZIP may place the standard data descriptor after a local
+    // payload. No other local-record gaps are accepted: that prevents an
+    // extractor that scans local records from seeing content omitted from the
+    // manifest-bound central directory.
+    for (let index = 0; index < extents.length; index += 1) {
+      const extent = extents[index];
+      const nextStart = extents[index + 1]?.start ?? directory.centralOffset;
+      const gap = nextStart - extent.end;
+      if (extent.entry.usesDataDescriptor) {
+        await validateZipDataDescriptor(handle, extent.entry, extent.end, gap);
+      } else if (gap !== 0) {
+        fail(
+          `iOS app ZIP has an unreferenced or ambiguous ${gap}-byte gap after ` +
+            JSON.stringify(extent.name),
+        );
+      }
+    }
+    for (const foldedEntries of foldedPaths.values()) {
+      if (foldedEntries.length > 1 && foldedEntries.some(({ type }) => type !== 'file')) {
+        fail(
+          `iOS app ZIP has case-ambiguous non-file members: ` +
+            foldedEntries.map(({ name }) => JSON.stringify(name)).join(', '),
+        );
+      }
+    }
+    for (const entry of entries) {
+      let parent = path.posix.dirname(entry.canonical);
+      while (parent !== '.') {
+        const declaredParent = paths.get(parent);
+        if (declaredParent !== undefined && declaredParent.type !== 'directory') {
+          fail(
+            `iOS app ZIP member ${JSON.stringify(entry.name)} descends through non-directory ` +
+              JSON.stringify(declaredParent.name),
+          );
+        }
+        const foldedParents = foldedPaths.get(portableCaseFold(parent)) ?? [];
+        const foldedNonDirectory = foldedParents.find(({ type }) => type !== 'directory');
+        if (foldedNonDirectory !== undefined) {
+          fail(
+            `iOS app ZIP member ${JSON.stringify(entry.name)} has a case-ambiguous ` +
+              `non-directory ancestor ${JSON.stringify(foldedNonDirectory.name)}`,
+          );
+        }
+        parent = path.posix.dirname(parent);
+      }
+      if (entry.type === 'symlink') await validateZipSymlink(handle, entry, appName);
+    }
+    return { entries: entries.length, zip64: directory.zip64 };
+  } finally {
+    await handle.close();
+  }
+}
+
+function regexEscape(value) {
+  return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
+}
+
+const OWNED_TEMPORARY_NAMES = [
+  new RegExp(`^\\.${regexEscape(ARCHIVE_NAME)}\\.[0-9]+(?:\\.[0-9a-f-]+)?\\.tmp\\.zip$`, 'u'),
+  new RegExp(`^\\.?${regexEscape(MANIFEST_NAME)}\\.[0-9]+(?:\\.[0-9a-f-]+)?\\.tmp$`, 'u'),
+];
+
+async function removeOwnedStaleTransportTemps(directory) {
+  for (const entry of await fs.readdir(directory, { withFileTypes: true })) {
+    if (!OWNED_TEMPORARY_NAMES.some((pattern) => pattern.test(entry.name))) continue;
+    if (!entry.isFile() && !entry.isSymbolicLink()) continue;
+    await fs.rm(path.join(directory, entry.name), { force: true });
+  }
+}
+
+async function ensureTransportDirectory(directory) {
+  await fs.mkdir(directory, { recursive: true });
+  const stat = await fs.lstat(directory);
+  if (!stat.isDirectory()) fail(`transport output is not a directory: ${directory}`);
+  await removeOwnedStaleTransportTemps(directory);
+  const allowed = new Set([ARCHIVE_NAME, MANIFEST_NAME, BUILD_REPORT_NAME]);
+  const unexpected = (await fs.readdir(directory))
+    .filter((name) => !allowed.has(name))
+    .sort(compareNames);
+  if (unexpected.length > 0) {
+    fail(`transport directory contains unexpected entries: ${unexpected.join(', ')}`);
+  }
+}
+
+async function validateTransportFiles(directory, manifest) {
+  const expected = new Set([ARCHIVE_NAME, MANIFEST_NAME]);
+  if (manifest.buildReport !== null) expected.add(BUILD_REPORT_NAME);
+  const actual = (await fs.readdir(directory)).sort(compareNames);
+  const wanted = [...expected].sort(compareNames);
+  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
+    fail(
+      `transport directory entries must be ${JSON.stringify(wanted)}; got ${JSON.stringify(actual)}`,
+    );
+  }
+  for (const name of wanted) {
+    await requireRegularFile(path.join(directory, name), `transport ${name}`);
+  }
+}
+
+async function writeJsonAtomic(file, value) {
+  const temporary = path.join(
+    path.dirname(file),
+    `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`,
+  );
+  try {
+    await fs.writeFile(temporary, `${JSON.stringify(value, null, 2)}\n`, { flag: 'wx' });
+    await fs.rename(temporary, file);
+  } finally {
+    await fs.rm(temporary, { force: true });
+  }
+}
+
+async function normalizeTreeTimes(file) {
+  const stat = await fs.lstat(file);
+  if (stat.isDirectory()) {
+    const children = await fs.readdir(file);
+    children.sort(compareNames);
+    for (const child of children) await normalizeTreeTimes(path.join(file, child));
+  }
+  if (stat.isSymbolicLink()) {
+    await fs.lutimes(file, ARCHIVE_TIMESTAMP, ARCHIVE_TIMESTAMP);
+  } else {
+    await fs.utimes(file, ARCHIVE_TIMESTAMP, ARCHIVE_TIMESTAMP);
+  }
+}
+
+async function preparePack(stateFile, { appDir, transportDir, buildReport = undefined }) {
+  await requireDirectory(appDir, 'iOS app artifact directory');
+  if (path.resolve(appDir) === path.resolve(transportDir)) {
+    fail('--app-dir and --transport-dir must be different directories');
+  }
+  const app = await exactlyOneApp(appDir);
+  const appData = await appIdentity(app.path, await fs.readFile(`${stateFile}.executable`, 'utf8'));
+
+  let report;
+  const automaticReport = path.join(appDir, BUILD_REPORT_NAME);
+  const reportFile =
+    buildReport ??
+    ((await statOrUndefined(automaticReport)) !== undefined ? automaticReport : undefined);
+  if (reportFile !== undefined) report = await loadBuildReport(reportFile, appData.name);
+
+  await ensureTransportDirectory(transportDir);
+  const archive = path.join(transportDir, ARCHIVE_NAME);
+  const manifestFile = path.join(transportDir, MANIFEST_NAME);
+  const copiedReport = path.join(transportDir, BUILD_REPORT_NAME);
+  for (const file of [archive, manifestFile, copiedReport]) await fs.rm(file, { force: true });
+
+  const work = path.join(transportDir, `.archive-stage.${process.pid}.${randomUUID()}`);
+  const temporaryArchive = path.join(work, 'archive.zip');
+  const stagedApp = path.join(work, appData.name);
+  await writeJsonAtomic(stateFile, {
+    command: 'pack',
+    appDir,
+    appPath: app.path,
+    transportDir,
+    appData,
+    report,
+    reportFile,
+    archive,
+    manifestFile,
+    copiedReport,
+    work,
+    temporaryArchive,
+    stagedApp,
+  });
+  await fs.mkdir(work);
+}
+
+async function finishPack(state) {
+  const { temporaryArchive, archive, appData, report, reportFile, copiedReport, manifestFile } =
+    state;
+  await requireRegularFile(temporaryArchive, 'iOS app ditto archive');
+  await fs.rename(temporaryArchive, archive);
+  const archiveStat = await requireRegularFile(archive, 'iOS app transport archive');
+  const archiveSha256 = await sha256File(archive);
+  await validateIosAppZipArchive(archive, appData.name);
+
+  if (report !== undefined) {
+    await fs.copyFile(reportFile, copiedReport);
+    const copied = await loadBuildReport(copiedReport, appData.name);
+    if (JSON.stringify(copied.identity) !== JSON.stringify(report.identity)) {
+      fail('copied iOS mobile build report does not match its manifest identity');
+    }
+  }
+  const manifest = {
+    schema: TRANSPORT_SCHEMA,
+    archive: {
+      bytes: archiveStat.size,
+      format: 'ditto-zip',
+      name: ARCHIVE_NAME,
+      sha256: archiveSha256,
+    },
+    app: appData,
+    buildReport: report?.identity ?? null,
+  };
+  await writeJsonAtomic(manifestFile, manifest);
+  process.stdout.write(
+    `${JSON.stringify({ archive, buildReport: report === undefined ? null : copiedReport, manifest: manifestFile })}\n`,
+  );
+  return {
+    archive,
+    buildReport: report === undefined ? null : copiedReport,
+    manifest: manifestFile,
+  };
+}
+
+async function prepareExtraction(stateFile, { transportDir, outputDir }) {
+  await requireDirectory(transportDir, 'iOS app transport directory');
+  if (inside(transportDir, outputDir)) {
+    fail('--output-dir must not be inside --transport-dir');
+  }
+  if ((await statOrUndefined(outputDir, { follow: false })) !== undefined) {
+    fail(`iOS app extraction output already exists: ${outputDir}`);
+  }
+
+  const manifestFile = path.join(transportDir, MANIFEST_NAME);
+  const manifest = validateManifest(await readJson(manifestFile, 'iOS app transport manifest'));
+  await validateTransportFiles(transportDir, manifest);
+
+  const archive = path.join(transportDir, ARCHIVE_NAME);
+  const archiveStat = await requireRegularFile(archive, 'iOS app transport archive');
+  if (archiveStat.size !== manifest.archive.bytes) {
+    fail(
+      `transport archive byte count mismatch: expected ${manifest.archive.bytes}, got ${archiveStat.size}`,
+    );
+  }
+  const archiveSha256 = await sha256File(archive);
+  if (archiveSha256 !== manifest.archive.sha256) {
+    fail(
+      `transport archive checksum mismatch: expected ${manifest.archive.sha256}, got ${archiveSha256}`,
+    );
+  }
+  await validateIosAppZipArchive(archive, manifest.app.name);
+
+  let reportFile;
+  if (manifest.buildReport !== null) {
+    reportFile = path.join(transportDir, BUILD_REPORT_NAME);
+    const report = await loadBuildReport(reportFile, manifest.app.name);
+    if (JSON.stringify(report.identity) !== JSON.stringify(manifest.buildReport)) {
+      fail('transport build report identity does not match its manifest binding');
+    }
+  }
+
+  await fs.mkdir(path.dirname(outputDir), { recursive: true });
+  const work = path.join(path.dirname(outputDir), `.ios-app-extract-${randomUUID()}`);
+  await writeJsonAtomic(stateFile, {
+    command: 'verify-extract',
+    outputDir,
+    archive,
+    work,
+    manifest,
+    reportFile,
+    appPath: path.join(work, manifest.app.name),
+  });
+  await fs.mkdir(work);
+}
+
+async function finishExtraction(stateFile, state) {
+  const { work: temporary, manifest, reportFile, outputDir } = state;
+  await requireExactDirectEntries(
+    temporary,
+    [manifest.app.name],
+    'extracted iOS app transport root',
+  );
+  const app = await exactlyOneApp(temporary, manifest.app.name);
+  const extracted = await appIdentity(
+    app.path,
+    await fs.readFile(`${stateFile}.executable`, 'utf8'),
+  );
+  for (const key of ['name', 'executable', 'executableMode', 'infoPlistSha256']) {
+    if (extracted[key] !== manifest.app[key]) {
+      fail(
+        `extracted app ${key} mismatch: expected ${JSON.stringify(manifest.app[key])}, ` +
+          `got ${JSON.stringify(extracted[key])}`,
+      );
+    }
+  }
+  if (
+    extracted.payload.entries !== manifest.app.payload.entries ||
+    extracted.payload.sha256 !== manifest.app.payload.sha256
+  ) {
+    fail(
+      `extracted app payload mismatch: expected ${JSON.stringify(manifest.app.payload)}, ` +
+        `got ${JSON.stringify(extracted.payload)}`,
+    );
+  }
+  if (reportFile !== undefined) {
+    const copiedReport = path.join(temporary, BUILD_REPORT_NAME);
+    await fs.copyFile(reportFile, copiedReport);
+    const copied = await loadBuildReport(copiedReport, manifest.app.name);
+    if (JSON.stringify(copied.identity) !== JSON.stringify(manifest.buildReport)) {
+      fail('extracted build report does not match its manifest binding');
+    }
+  }
+  await fs.rename(temporary, outputDir);
+  const extractedApp = path.join(outputDir, manifest.app.name);
+  const extractedReport = reportFile === undefined ? null : path.join(outputDir, BUILD_REPORT_NAME);
+  const result = {
+    app: extractedApp,
+    buildReport: extractedReport,
+    executable: manifest.app.executable,
+  };
+  process.stdout.write(`${JSON.stringify(result)}\n`);
+  return result;
+}
+
+async function main(argv) {
+  if (argv.length === 1 && ['--help', '-h'].includes(argv[0])) {
+    console.log(usage());
+    return;
+  }
+  const [phase, stateFile, ...args] = argv;
+  if (!stateFile) fail('use bash src/sdks/react-native/tools/ios-app-transport.sh');
+  if (phase === 'describe') {
+    await writeJsonAtomic(stateFile, parseArgs(args));
+    return;
+  }
+  const state = await readJson(stateFile, 'private transport state');
+  if (phase === 'locate') {
+    await requireDirectory(state.appDir, 'iOS app artifact directory');
+    console.log((await exactlyOneApp(state.appDir)).path);
+  } else if (phase === 'prepare') {
+    if (state.command === 'pack') await preparePack(stateFile, state);
+    else await prepareExtraction(stateFile, state);
+  } else if (phase === 'normalize') {
+    await normalizeTreeTimes(state.stagedApp);
+  } else if (phase === 'finish') {
+    if (state.command === 'pack') await finishPack(state);
+    else await finishExtraction(stateFile, state);
+  } else fail('unknown transport phase');
+}
+
+if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
+  try {
+    await main(process.argv.slice(2));
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : `${PREFIX}: ${String(error)}`);
+    process.exit(1);
+  }
+}
diff --git a/src/sdks/react-native/tools/ios-app-transport.sh b/src/sdks/react-native/tools/ios-app-transport.sh
new file mode 100644
index 000000000..3b80c072d
--- /dev/null
+++ b/src/sdks/react-native/tools/ios-app-transport.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+set -euo pipefail
+tool="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ios-app-transport.mts"
+if [ "$#" = 1 ] && { [ "$1" = --help ] || [ "$1" = -h ]; }; then
+  exec bun "$tool" --help
+fi
+command -v jq >/dev/null
+scratch="$(mktemp -d)"
+state="$scratch/state.json"
+# The Shell process owns staging directories across the TypeScript phases.
+# shellcheck disable=SC2317
+cleanup() {
+  if [ -f "$state" ]; then
+    work="$(jq -r '.work // empty' "$state")"
+    if [ -n "$work" ]; then rm -rf "$work"; fi
+  fi
+  rm -rf "$scratch"
+}
+trap cleanup EXIT
+bun "$tool" describe "$state" "$@"
+for command in ditto plutil; do
+  command -v "$command" >/dev/null || {
+    echo "required Apple command $command was not found; run this operation on macOS with ditto and plutil available" >&2
+    exit 1
+  }
+done
+export TZ=UTC
+if [ "$(jq -r '.command' "$state")" = pack ]; then
+  app="$(bun "$tool" locate "$state")"
+  plutil -extract CFBundleExecutable raw -o - "$app/Info.plist" > "$state.executable"
+  bun "$tool" prepare "$state"
+  staged_app="$(jq -r '.stagedApp' "$state")"
+  ditto "$app" "$staged_app"
+  bun "$tool" normalize "$state"
+  work="$(jq -r '.work' "$state")"
+  app_name="$(jq -r '.appData.name' "$state")"
+  temporary_archive="$(jq -r '.temporaryArchive' "$state")"
+  (cd "$work" && ditto -c -k --sequesterRsrc --keepParent "$app_name" "$temporary_archive")
+else
+  bun "$tool" prepare "$state"
+  archive="$(jq -r '.archive' "$state")"
+  work="$(jq -r '.work' "$state")"
+  ditto -x -k "$archive" "$work"
+  app="$(jq -r '.appPath' "$state")"
+  plutil -extract CFBundleExecutable raw -o - "$app/Info.plist" > "$state.executable"
+fi
+bun "$tool" finish "$state"
diff --git a/src/sdks/react-native/tools/ios-app-transport.test.mjs b/src/sdks/react-native/tools/ios-app-transport.test.mjs
deleted file mode 100755
index 05b16dd8f..000000000
--- a/src/sdks/react-native/tools/ios-app-transport.test.mjs
+++ /dev/null
@@ -1,709 +0,0 @@
-#!/usr/bin/env node
-
-import assert from "node:assert/strict";
-import { createHash } from "node:crypto";
-import {
-  createReadStream,
-  mkdtempSync,
-  readdirSync,
-  rmSync,
-  writeFileSync,
-} from "node:fs";
-import fs from "node:fs/promises";
-import os from "node:os";
-import path from "node:path";
-import test from "node:test";
-import { deflateRawSync } from "node:zlib";
-
-import { spawnSync } from "../../../../tools/test/fd-backed-spawn-sync.mjs";
-
-import {
-  ARCHIVE_NAME,
-  BUILD_REPORT_NAME,
-  MANIFEST_NAME,
-  TRANSPORT_SCHEMA,
-  validateIosAppZipArchive,
-} from "./ios-app-transport.mjs";
-
-const CLI = path.join(import.meta.dirname, "ios-app-transport.mjs");
-const IS_MACOS = process.platform === "darwin";
-
-function temporaryVolumeSupportsCaseDistinctNames() {
-  const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-ios-case-probe-"));
-  try {
-    writeFileSync(path.join(root, "Case.txt"), "upper\n");
-    writeFileSync(path.join(root, "case.txt"), "lower\n");
-    const names = new Set(readdirSync(root));
-    return names.has("Case.txt") && names.has("case.txt");
-  } finally {
-    rmSync(root, { force: true, recursive: true });
-  }
-}
-
-const CASE_DISTINCT_TEMP_VOLUME = IS_MACOS && temporaryVolumeSupportsCaseDistinctNames();
-
-function run(command, args, { cwd = undefined } = {}) {
-  return spawnSync(command, args, {
-    cwd,
-    encoding: "utf8",
-    env: { ...process.env, TZ: "UTC" },
-    maxBuffer: 16 * 1024 * 1024,
-  });
-}
-
-function runSuccess(command, args, options = {}) {
-  const result = run(command, args, options);
-  assert.equal(
-    result.status,
-    0,
-    `${command} ${args.join(" ")} failed:\n${result.stderr || result.stdout}`,
-  );
-  return result;
-}
-
-function runCli(args) {
-  return run(process.execPath, [CLI, ...args]);
-}
-
-function runCliSuccess(args) {
-  return runSuccess(process.execPath, [CLI, ...args]);
-}
-
-function expectCliFailure(args, pattern) {
-  const result = runCli(args);
-  assert.notEqual(result.status, 0, `CLI unexpectedly succeeded:\n${result.stdout}`);
-  assert.match(`${result.stderr}\n${result.stdout}`, pattern);
-  return result;
-}
-
-async function sha256(file) {
-  const hash = createHash("sha256");
-  await new Promise((resolve, reject) => {
-    const input = createReadStream(file);
-    input.on("data", (chunk) => hash.update(chunk));
-    input.on("error", reject);
-    input.on("end", resolve);
-  });
-  return hash.digest("hex");
-}
-
-async function writeJson(file, value) {
-  await fs.mkdir(path.dirname(file), { recursive: true });
-  await fs.writeFile(file, `${JSON.stringify(value, null, 2)}\n`);
-}
-
-function xml(value) {
-  return String(value)
-    .replaceAll("&", "&")
-    .replaceAll("<", "<")
-    .replaceAll(">", ">")
-    .replaceAll('"', """)
-    .replaceAll("'", "'");
-}
-
-async function createApp(
-  directory,
-  {
-    appName = "Fixture.app",
-    executable = "Fixture",
-    executableMode = 0o755,
-    includeSymlink = true,
-  } = {},
-) {
-  const app = path.join(directory, appName);
-  const resources = path.join(app, "Resources");
-  await fs.mkdir(resources, { recursive: true });
-  await fs.writeFile(
-    path.join(app, "Info.plist"),
-    [
-      '',
-      '',
-      '',
-      "",
-      "  CFBundleExecutable",
-      `  ${xml(executable)}`,
-      "  CFBundleIdentifier",
-      "  dev.oliphaunt.transport-fixture",
-      "",
-      "",
-      "",
-    ].join("\n"),
-  );
-  const executableFile = path.join(app, executable);
-  await fs.writeFile(executableFile, "#!/bin/sh\nexit 0\n");
-  await fs.chmod(executableFile, executableMode);
-  await fs.writeFile(path.join(resources, "Payload.txt"), "payload\n");
-  if (includeSymlink) {
-    await fs.symlink("Payload.txt", path.join(resources, "Payload.link"));
-  }
-  return { app, appName, executable, executableFile, resources };
-}
-
-async function createBuildReport(appDirectory, fixture) {
-  const report = path.join(appDirectory, BUILD_REPORT_NAME);
-  await writeJson(report, {
-    schema: "oliphaunt-react-native-mobile-build-v1",
-    platform: "ios",
-    configuration: "Release",
-    sdk: "iphonesimulator",
-    appArtifact: fixture.app,
-    appArtifactBytes: 12345,
-    reactNativePackage: "/tmp/oliphaunt-react-native.tgz",
-    reactNativePackageBytes: 456,
-    selectedExtensions: ["vector"],
-    scratchRoot: "/tmp/ios-build",
-  });
-  return report;
-}
-
-async function fixtureRoot(t, label) {
-  const root = await fs.mkdtemp(path.join(os.tmpdir(), `oliphaunt-ios-transport-${label}-`));
-  t.after(() => fs.rm(root, { force: true, recursive: true }));
-  return root;
-}
-
-async function makeTransport(t, label = "valid") {
-  const root = await fixtureRoot(t, label);
-  const appDirectory = path.join(root, "app");
-  await fs.mkdir(appDirectory, { recursive: true });
-  const fixture = await createApp(appDirectory);
-  await createBuildReport(appDirectory, fixture);
-  const transport = path.join(root, "transport");
-  runCliSuccess(["pack", "--app-dir", appDirectory, "--transport-dir", transport]);
-  return { appDirectory, fixture, root, transport };
-}
-
-async function manifest(transport) {
-  return JSON.parse(await fs.readFile(path.join(transport, MANIFEST_NAME), "utf8"));
-}
-
-async function rewriteArchiveBinding(transport) {
-  const archive = path.join(transport, ARCHIVE_NAME);
-  const data = await manifest(transport);
-  const stat = await fs.stat(archive);
-  data.archive.bytes = stat.size;
-  data.archive.sha256 = await sha256(archive);
-  await writeJson(path.join(transport, MANIFEST_NAME), data);
-}
-
-async function extractArchive(transport, output) {
-  await fs.mkdir(output, { recursive: true });
-  runSuccess("ditto", ["-x", "-k", path.join(transport, ARCHIVE_NAME), output]);
-}
-
-async function archiveDirectoryContents(source, archive) {
-  await fs.rm(archive, { force: true });
-  runSuccess("ditto", ["-c", "-k", "--sequesterRsrc", source, archive]);
-}
-
-const CRC32_TABLE = (() => {
-  const table = new Uint32Array(256);
-  for (let index = 0; index < table.length; index += 1) {
-    let value = index;
-    for (let bit = 0; bit < 8; bit += 1) {
-      value = (value & 1) === 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;
-    }
-    table[index] = value >>> 0;
-  }
-  return table;
-})();
-
-function crc32(buffer) {
-  let value = 0xffffffff;
-  for (const byte of buffer) value = CRC32_TABLE[(value ^ byte) & 0xff] ^ (value >>> 8);
-  return (value ^ 0xffffffff) >>> 0;
-}
-
-async function writeStoredZip(archive, entries) {
-  const localRecords = [];
-  const centralRecords = [];
-  let localOffset = 0;
-  for (const entry of entries) {
-    const centralName = Buffer.from(entry.name, "utf8");
-    const localName = Buffer.from(entry.localName ?? entry.name, "utf8");
-    const data = Buffer.isBuffer(entry.data) ? entry.data : Buffer.from(entry.data ?? "", "utf8");
-    const method = entry.method ?? 0;
-    const compressed = method === 8 ? deflateRawSync(data) : data;
-    const mode = entry.mode ?? (entry.name.endsWith("/") ? 0o040755 : 0o100644);
-    const checksum = crc32(data);
-    const flags = 0x0800 | (entry.dataDescriptor ? 0x0008 : 0);
-    const local = Buffer.alloc(30);
-    local.writeUInt32LE(0x04034b50, 0);
-    local.writeUInt16LE(20, 4);
-    local.writeUInt16LE(flags, 6);
-    local.writeUInt16LE(method, 8);
-    local.writeUInt32LE(entry.localCrc ?? (entry.dataDescriptor ? 0 : checksum), 14);
-    local.writeUInt32LE(entry.localCompressedSize ?? (entry.dataDescriptor ? 0 : compressed.length), 18);
-    local.writeUInt32LE(entry.localUncompressedSize ?? (entry.dataDescriptor ? 0 : data.length), 22);
-    local.writeUInt16LE(localName.length, 26);
-    local.writeUInt16LE(0, 28);
-    let descriptor = Buffer.alloc(0);
-    if (entry.dataDescriptor) {
-      const signatureBytes = entry.descriptorSignature === false ? 0 : 4;
-      descriptor = Buffer.alloc(12 + signatureBytes);
-      let cursor = 0;
-      if (signatureBytes > 0) {
-        descriptor.writeUInt32LE(0x08074b50, cursor);
-        cursor += 4;
-      }
-      descriptor.writeUInt32LE(entry.descriptorCrc ?? checksum, cursor);
-      descriptor.writeUInt32LE(compressed.length, cursor + 4);
-      descriptor.writeUInt32LE(data.length, cursor + 8);
-    }
-    const gap = Buffer.isBuffer(entry.gap) ? entry.gap : Buffer.from(entry.gap ?? "", "utf8");
-    localRecords.push(local, localName, compressed, descriptor, gap);
-
-    const central = Buffer.alloc(46);
-    central.writeUInt32LE(0x02014b50, 0);
-    central.writeUInt16LE((3 << 8) | 20, 4);
-    central.writeUInt16LE(20, 6);
-    central.writeUInt16LE(flags, 8);
-    central.writeUInt16LE(method, 10);
-    central.writeUInt32LE(checksum, 16);
-    central.writeUInt32LE(compressed.length, 20);
-    central.writeUInt32LE(data.length, 24);
-    central.writeUInt16LE(centralName.length, 28);
-    central.writeUInt16LE(0, 30);
-    central.writeUInt16LE(0, 32);
-    central.writeUInt16LE(0, 34);
-    central.writeUInt32LE((mode << 16) >>> 0, 38);
-    central.writeUInt32LE(localOffset, 42);
-    centralRecords.push(central, centralName);
-    localOffset += local.length + localName.length + compressed.length + descriptor.length + gap.length;
-  }
-
-  const central = Buffer.concat(centralRecords);
-  const eocd = Buffer.alloc(22);
-  eocd.writeUInt32LE(0x06054b50, 0);
-  eocd.writeUInt16LE(entries.length, 8);
-  eocd.writeUInt16LE(entries.length, 10);
-  eocd.writeUInt32LE(central.length, 12);
-  eocd.writeUInt32LE(localOffset, 16);
-  await fs.writeFile(archive, Buffer.concat([...localRecords, central, eocd]));
-}
-
-test("pre-extraction ZIP validation accepts contained regular, directory, and symlink entries", async (t) => {
-  const root = await fixtureRoot(t, "zip-valid");
-  const archive = path.join(root, "valid.zip");
-  await writeStoredZip(archive, [
-    { name: "Fixture.app/" },
-    { name: "Fixture.app/Resources/" },
-    {
-      data: "payload\n",
-      dataDescriptor: true,
-      name: "Fixture.app/Resources/Payload.txt",
-    },
-    {
-      data: "unsigned descriptor\n",
-      dataDescriptor: true,
-      descriptorSignature: false,
-      name: "Fixture.app/Resources/Unsigned.txt",
-    },
-    {
-      data: "Resources/Payload.txt",
-      method: 8,
-      mode: 0o120777,
-      name: "Fixture.app/Payload.link",
-    },
-  ]);
-  assert.deepEqual(await validateIosAppZipArchive(archive, "Fixture.app"), {
-    entries: 5,
-    zip64: false,
-  });
-});
-
-test("pre-extraction ZIP validation rejects traversal, absolute, and unrelated paths", async (t) => {
-  const root = await fixtureRoot(t, "zip-paths");
-  for (const [label, name, pattern] of [
-    ["parent", "../escaped.txt", /unsafe member path/u],
-    ["nested-parent", "Fixture.app/../../escaped.txt", /unsafe member path/u],
-    ["absolute", "/escaped.txt", /unsafe member path/u],
-    ["backslash", "Fixture.app\\escaped.txt", /unsafe member path/u],
-    ["unrelated", "Other.app/Payload.txt", /outside Fixture\.app/u],
-  ]) {
-    const archive = path.join(root, `${label}.zip`);
-    await writeStoredZip(archive, [{ name: "Fixture.app/" }, { data: "bad", name }]);
-    await assert.rejects(
-      () => validateIosAppZipArchive(archive, "Fixture.app"),
-      pattern,
-      label,
-    );
-  }
-});
-
-test("pre-extraction ZIP validation rejects special entries and header ambiguity", async (t) => {
-  const root = await fixtureRoot(t, "zip-special");
-  for (const [label, entries, pattern] of [
-    [
-      "fifo",
-      [{ name: "Fixture.app/" }, { mode: 0o010644, name: "Fixture.app/pipe" }],
-      /unsupported special mode/u,
-    ],
-    [
-      "local-name-mismatch",
-      [
-        { name: "Fixture.app/" },
-        { data: "bad", localName: "../escaped.txt", name: "Fixture.app/Safe.txt" },
-      ],
-      /local header filename does not match/u,
-    ],
-    [
-      "local-crc-mismatch",
-      [
-        { name: "Fixture.app/" },
-        { data: "bad", localCrc: 123, name: "Fixture.app/Payload.txt" },
-      ],
-      /local CRC or sizes disagree/u,
-    ],
-    [
-      "local-size-mismatch",
-      [
-        { name: "Fixture.app/" },
-        { data: "bad", localCompressedSize: 999, name: "Fixture.app/Payload.txt" },
-      ],
-      /local CRC or sizes disagree/u,
-    ],
-    [
-      "descriptor-mismatch",
-      [
-        { name: "Fixture.app/" },
-        {
-          data: "bad",
-          dataDescriptor: true,
-          descriptorCrc: 123,
-          name: "Fixture.app/Payload.txt",
-        },
-      ],
-      /data descriptor disagrees/u,
-    ],
-    [
-      "unreferenced-gap",
-      [
-        { name: "Fixture.app/" },
-        { data: "bad", gap: "hidden local bytes", name: "Fixture.app/Payload.txt" },
-      ],
-      /unreferenced or ambiguous .* gap/u,
-    ],
-    [
-      "escaping-symlink",
-      [
-        { name: "Fixture.app/" },
-        { data: "../../escaped.txt", mode: 0o120777, name: "Fixture.app/Escape.link" },
-      ],
-      /symlink .* escapes Fixture\.app/u,
-    ],
-    [
-      "symlink-descendant",
-      [
-        { name: "Fixture.app/" },
-        { data: "Resources", mode: 0o120777, name: "Fixture.app/Alias" },
-        { data: "bad", name: "Fixture.app/Alias/Payload.txt" },
-      ],
-      /descends through non-directory/u,
-    ],
-    [
-      "case-ambiguous-symlink-descendant",
-      [
-        { name: "Fixture.app/" },
-        { data: "Resources", mode: 0o120777, name: "Fixture.app/Alias" },
-        { data: "bad", name: "Fixture.app/alias/Payload.txt" },
-      ],
-      /case-ambiguous non-directory ancestor/u,
-    ],
-    [
-      "unicode-case-ambiguous-symlink-descendant",
-      [
-        { data: "Resources", mode: 0o120777, name: "Fixture.app/straße" },
-        { name: "Fixture.app/" },
-        { data: "bad", name: "Fixture.app/STRASSE/Payload.txt" },
-      ],
-      /case-ambiguous non-directory ancestor/u,
-    ],
-  ]) {
-    const archive = path.join(root, `${label}.zip`);
-    await writeStoredZip(archive, entries);
-    await assert.rejects(
-      () => validateIosAppZipArchive(archive, "Fixture.app"),
-      pattern,
-      label,
-    );
-  }
-});
-
-test(
-  "fails clearly when the required Apple transport tools are unavailable",
-  { skip: IS_MACOS },
-  async (t) => {
-    const root = await fixtureRoot(t, "unsupported");
-    expectCliFailure(
-      [
-        "pack",
-        "--app-dir",
-        path.join(root, "app"),
-        "--transport-dir",
-        path.join(root, "transport"),
-      ],
-      /required Apple command ditto was not found; run this operation on macOS/u,
-    );
-  },
-);
-
-test(
-  "packs deterministically and restores executable and symlink fidelity",
-  { skip: !IS_MACOS },
-  async (t) => {
-    const root = await fixtureRoot(t, "roundtrip");
-    const appDirectory = path.join(root, "app");
-    await fs.mkdir(appDirectory, { recursive: true });
-    const fixture = await createApp(appDirectory);
-    await createBuildReport(appDirectory, fixture);
-
-    const firstTransport = path.join(root, "transport-first");
-    const secondTransport = path.join(root, "transport-second");
-    runCliSuccess(["pack", "--app-dir", appDirectory, "--transport-dir", firstTransport]);
-    runCliSuccess(["pack", "--app-dir", appDirectory, "--transport-dir", secondTransport]);
-
-    const firstManifest = await manifest(firstTransport);
-    const secondManifest = await manifest(secondTransport);
-    assert.equal(firstManifest.schema, TRANSPORT_SCHEMA);
-    assert.deepEqual(firstManifest, secondManifest, "unchanged app input must produce a stable manifest");
-    assert.equal(
-      await sha256(path.join(firstTransport, ARCHIVE_NAME)),
-      await sha256(path.join(secondTransport, ARCHIVE_NAME)),
-      "unchanged app input must produce a byte-stable ditto archive",
-    );
-    assert.equal(firstManifest.buildReport.configuration, "Release");
-    assert.equal(firstManifest.buildReport.sdk, "iphonesimulator");
-    assert.equal(
-      await sha256(path.join(firstTransport, BUILD_REPORT_NAME)),
-      firstManifest.buildReport.sha256,
-    );
-
-    const output = path.join(root, "extracted");
-    runCliSuccess([
-      "verify-extract",
-      "--transport-dir",
-      firstTransport,
-      "--output-dir",
-      output,
-    ]);
-    const extractedApp = path.join(output, fixture.appName);
-    assert.equal(
-      await sha256(path.join(output, BUILD_REPORT_NAME)),
-      firstManifest.buildReport.sha256,
-      "verified extraction must restore the bound build report beside the app",
-    );
-    await fs.access(path.join(extractedApp, fixture.executable), fs.constants.X_OK);
-    const link = path.join(extractedApp, "Resources", "Payload.link");
-    assert.equal((await fs.lstat(link)).isSymbolicLink(), true);
-    assert.equal(await fs.readlink(link), "Payload.txt");
-    assert.equal(await fs.readFile(path.join(extractedApp, "Resources", "Payload.txt"), "utf8"), "payload\n");
-  },
-);
-
-test(
-  "rejects a checksum-bound traversal member before ditto can write outside extraction",
-  { skip: !IS_MACOS },
-  async (t) => {
-    const valid = await makeTransport(t, "zip-slip-cli");
-    const escaped = path.join(valid.root, "escaped.txt");
-    await writeStoredZip(path.join(valid.transport, ARCHIVE_NAME), [
-      { name: `${valid.fixture.appName}/` },
-      { data: "must never be extracted\n", name: "../escaped.txt" },
-    ]);
-    await rewriteArchiveBinding(valid.transport);
-    expectCliFailure(
-      [
-        "verify-extract",
-        "--transport-dir",
-        valid.transport,
-        "--output-dir",
-        path.join(valid.root, "output"),
-      ],
-      /ZIP contains unsafe member path/u,
-    );
-    await assert.rejects(() => fs.access(escaped), { code: "ENOENT" });
-  },
-);
-
-test(
-  "pack retries remove only owned stale transport temporaries",
-  { skip: !IS_MACOS },
-  async (t) => {
-    const root = await fixtureRoot(t, "stale-temporaries");
-    const appDirectory = path.join(root, "app");
-    const transport = path.join(root, "transport");
-    await fs.mkdir(appDirectory, { recursive: true });
-    const fixture = await createApp(appDirectory);
-    await createBuildReport(appDirectory, fixture);
-    await fs.mkdir(transport, { recursive: true });
-    const staleNames = [
-      `.${ARCHIVE_NAME}.999999.tmp.zip`,
-      `.${ARCHIVE_NAME}.999999.01234567-89ab-cdef-0123-456789abcdef.tmp.zip`,
-      `${MANIFEST_NAME}.999999.tmp`,
-      `.${MANIFEST_NAME}.999999.01234567-89ab-cdef-0123-456789abcdef.tmp`,
-    ];
-    for (const name of staleNames) await fs.writeFile(path.join(transport, name), "stale\n");
-    runCliSuccess(["pack", "--app-dir", appDirectory, "--transport-dir", transport]);
-    assert.deepEqual(
-      (await fs.readdir(transport)).sort(),
-      [ARCHIVE_NAME, BUILD_REPORT_NAME, MANIFEST_NAME].sort(),
-    );
-
-    for (const name of staleNames) await fs.writeFile(path.join(transport, name), "stale again\n");
-    runCliSuccess(["pack", "--app-dir", appDirectory, "--transport-dir", transport]);
-    assert.deepEqual(
-      (await fs.readdir(transport)).sort(),
-      [ARCHIVE_NAME, BUILD_REPORT_NAME, MANIFEST_NAME].sort(),
-    );
-  },
-);
-
-test(
-  "preserves case-distinct resources when the test volume supports them",
-  { skip: !IS_MACOS || !CASE_DISTINCT_TEMP_VOLUME },
-  async (t) => {
-    const root = await fixtureRoot(t, "case");
-    const appDirectory = path.join(root, "app");
-    await fs.mkdir(appDirectory, { recursive: true });
-    const fixture = await createApp(appDirectory, { includeSymlink: false });
-    await fs.writeFile(path.join(fixture.resources, "Case.txt"), "upper\n");
-    await fs.writeFile(path.join(fixture.resources, "case.txt"), "lower\n");
-    const sourceNames = new Set(await fs.readdir(fixture.resources));
-    assert(sourceNames.has("Case.txt") && sourceNames.has("case.txt"));
-
-    const transport = path.join(root, "transport");
-    const output = path.join(root, "output");
-    runCliSuccess(["pack", "--app-dir", appDirectory, "--transport-dir", transport]);
-    runCliSuccess(["verify-extract", "--transport-dir", transport, "--output-dir", output]);
-    const resources = path.join(output, fixture.appName, "Resources");
-    assert.equal(await fs.readFile(path.join(resources, "Case.txt"), "utf8"), "upper\n");
-    assert.equal(await fs.readFile(path.join(resources, "case.txt"), "utf8"), "lower\n");
-  },
-);
-
-test(
-  "rejects archive checksum tampering",
-  { skip: !IS_MACOS },
-  async (t) => {
-    const { root, transport } = await makeTransport(t, "checksum");
-    await fs.appendFile(path.join(transport, ARCHIVE_NAME), "tamper");
-    expectCliFailure(
-      [
-        "verify-extract",
-        "--transport-dir",
-        transport,
-        "--output-dir",
-        path.join(root, "output"),
-      ],
-      /transport archive (byte count|checksum) mismatch/u,
-    );
-  },
-);
-
-test(
-  "rejects transported build-report tampering",
-  { skip: !IS_MACOS },
-  async (t) => {
-    const { root, transport } = await makeTransport(t, "report-tamper");
-    await fs.appendFile(path.join(transport, BUILD_REPORT_NAME), " \n");
-    expectCliFailure(
-      [
-        "verify-extract",
-        "--transport-dir",
-        transport,
-        "--output-dir",
-        path.join(root, "output"),
-      ],
-      /transport build report identity does not match its manifest binding/u,
-    );
-  },
-);
-
-test(
-  "rejects unrelated top-level archive payloads",
-  { skip: !IS_MACOS },
-  async (t) => {
-    const valid = await makeTransport(t, "extra-root-entry");
-    const payload = path.join(valid.root, "extra-root-payload");
-    await extractArchive(valid.transport, payload);
-    await fs.writeFile(path.join(payload, "unrelated.txt"), "must not cross the transport boundary\n");
-    await archiveDirectoryContents(payload, path.join(valid.transport, ARCHIVE_NAME));
-    await rewriteArchiveBinding(valid.transport);
-    expectCliFailure(
-      [
-        "verify-extract",
-        "--transport-dir",
-        valid.transport,
-        "--output-dir",
-        path.join(valid.root, "output"),
-      ],
-      /iOS app ZIP member is outside Fixture\.app: "unrelated\.txt"/u,
-    );
-  },
-);
-
-test(
-  "pack and verifier reject multiple direct app bundles",
-  { skip: !IS_MACOS },
-  async (t) => {
-    const root = await fixtureRoot(t, "multiple-pack");
-    const appDirectory = path.join(root, "app");
-    await fs.mkdir(appDirectory, { recursive: true });
-    await createApp(appDirectory, { appName: "First.app", executable: "First" });
-    await createApp(appDirectory, { appName: "Second.app", executable: "Second" });
-    expectCliFailure(
-      ["pack", "--app-dir", appDirectory, "--transport-dir", path.join(root, "transport")],
-      /must contain exactly one direct \.app directory; found 2/u,
-    );
-
-    const valid = await makeTransport(t, "multiple-verify");
-    const payload = path.join(valid.root, "multiple-payload");
-    await extractArchive(valid.transport, payload);
-    await createApp(payload, { appName: "Second.app", executable: "Second" });
-    await archiveDirectoryContents(payload, path.join(valid.transport, ARCHIVE_NAME));
-    await rewriteArchiveBinding(valid.transport);
-    expectCliFailure(
-      [
-        "verify-extract",
-        "--transport-dir",
-        valid.transport,
-        "--output-dir",
-        path.join(valid.root, "output"),
-      ],
-      /iOS app ZIP member is outside Fixture\.app: "Second\.app\/"/u,
-    );
-  },
-);
-
-test(
-  "pack and verifier reject a non-executable CFBundleExecutable",
-  { skip: !IS_MACOS },
-  async (t) => {
-    const root = await fixtureRoot(t, "nonexec-pack");
-    const appDirectory = path.join(root, "app");
-    await fs.mkdir(appDirectory, { recursive: true });
-    await createApp(appDirectory, { executableMode: 0o644 });
-    expectCliFailure(
-      ["pack", "--app-dir", appDirectory, "--transport-dir", path.join(root, "transport")],
-      /executable is not executable/u,
-    );
-
-    const valid = await makeTransport(t, "nonexec-verify");
-    const payload = path.join(valid.root, "nonexec-payload");
-    await extractArchive(valid.transport, payload);
-    await fs.chmod(path.join(payload, valid.fixture.appName, valid.fixture.executable), 0o644);
-    await archiveDirectoryContents(payload, path.join(valid.transport, ARCHIVE_NAME));
-    await rewriteArchiveBinding(valid.transport);
-    expectCliFailure(
-      [
-        "verify-extract",
-        "--transport-dir",
-        valid.transport,
-        "--output-dir",
-        path.join(valid.root, "output"),
-      ],
-      /executable is not executable/u,
-    );
-  },
-);
diff --git a/src/sdks/react-native/tools/ios-app-transport.test.mts b/src/sdks/react-native/tools/ios-app-transport.test.mts
new file mode 100755
index 000000000..a720fa185
--- /dev/null
+++ b/src/sdks/react-native/tools/ios-app-transport.test.mts
@@ -0,0 +1,450 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { createReadStream } from 'node:fs';
+import fs from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { deflateRawSync } from 'node:zlib';
+
+import {
+  ARCHIVE_NAME,
+  BUILD_REPORT_NAME,
+  MANIFEST_NAME,
+  TRANSPORT_SCHEMA,
+  validateIosAppZipArchive,
+} from './ios-app-transport.mts';
+
+async function sha256(file) {
+  const hash = createHash('sha256');
+  await new Promise((resolve, reject) => {
+    const input = createReadStream(file);
+    input.on('data', (chunk) => hash.update(chunk));
+    input.on('error', reject);
+    input.on('end', resolve);
+  });
+  return hash.digest('hex');
+}
+
+async function writeJson(file, value) {
+  await fs.mkdir(path.dirname(file), { recursive: true });
+  await fs.writeFile(file, `${JSON.stringify(value, null, 2)}\n`);
+}
+
+function xml(value) {
+  return String(value)
+    .replaceAll('&', '&')
+    .replaceAll('<', '<')
+    .replaceAll('>', '>')
+    .replaceAll('"', '"')
+    .replaceAll("'", ''');
+}
+
+async function createApp(
+  directory,
+  {
+    appName = 'Fixture.app',
+    executable = 'Fixture',
+    executableMode = 0o755,
+    includeSymlink = true,
+  } = {},
+) {
+  const app = path.join(directory, appName);
+  const resources = path.join(app, 'Resources');
+  await fs.mkdir(resources, { recursive: true });
+  await fs.writeFile(
+    path.join(app, 'Info.plist'),
+    [
+      '',
+      '',
+      '',
+      '',
+      '  CFBundleExecutable',
+      `  ${xml(executable)}`,
+      '  CFBundleIdentifier',
+      '  dev.oliphaunt.transport-fixture',
+      '',
+      '',
+      '',
+    ].join('\n'),
+  );
+  const executableFile = path.join(app, executable);
+  await fs.writeFile(executableFile, '#!/bin/sh\nexit 0\n');
+  await fs.chmod(executableFile, executableMode);
+  await fs.writeFile(path.join(resources, 'Payload.txt'), 'payload\n');
+  if (includeSymlink) {
+    await fs.symlink('Payload.txt', path.join(resources, 'Payload.link'));
+  }
+  return { app, appName, executable, executableFile, resources };
+}
+
+async function createBuildReport(appDirectory, fixture) {
+  const report = path.join(appDirectory, BUILD_REPORT_NAME);
+  await writeJson(report, {
+    schema: 'oliphaunt-react-native-mobile-build-v1',
+    platform: 'ios',
+    configuration: 'Release',
+    sdk: 'iphonesimulator',
+    appArtifact: fixture.app,
+    appArtifactBytes: 12345,
+    reactNativePackage: '/tmp/oliphaunt-react-native.tgz',
+    reactNativePackageBytes: 456,
+    selectedExtensions: ['vector'],
+    scratchRoot: '/tmp/ios-build',
+  });
+  return report;
+}
+
+async function fixtureRoot(t, label) {
+  const root = await fs.mkdtemp(path.join(os.tmpdir(), `oliphaunt-ios-transport-${label}-`));
+  t.after(() => fs.rm(root, { force: true, recursive: true }));
+  return root;
+}
+
+async function manifest(transport) {
+  return JSON.parse(await fs.readFile(path.join(transport, MANIFEST_NAME), 'utf8'));
+}
+
+async function rewriteArchiveBinding(transport) {
+  const archive = path.join(transport, ARCHIVE_NAME);
+  const data = await manifest(transport);
+  const stat = await fs.stat(archive);
+  data.archive.bytes = stat.size;
+  data.archive.sha256 = await sha256(archive);
+  await writeJson(path.join(transport, MANIFEST_NAME), data);
+}
+
+const CRC32_TABLE = (() => {
+  const table = new Uint32Array(256);
+  for (let index = 0; index < table.length; index += 1) {
+    let value = index;
+    for (let bit = 0; bit < 8; bit += 1) {
+      value = (value & 1) === 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;
+    }
+    table[index] = value >>> 0;
+  }
+  return table;
+})();
+
+function crc32(buffer) {
+  let value = 0xffffffff;
+  for (const byte of buffer) value = CRC32_TABLE[(value ^ byte) & 0xff] ^ (value >>> 8);
+  return (value ^ 0xffffffff) >>> 0;
+}
+
+async function writeStoredZip(archive, entries) {
+  const localRecords = [];
+  const centralRecords = [];
+  let localOffset = 0;
+  for (const entry of entries) {
+    const centralName = Buffer.from(entry.name, 'utf8');
+    const localName = Buffer.from(entry.localName ?? entry.name, 'utf8');
+    const data = Buffer.isBuffer(entry.data) ? entry.data : Buffer.from(entry.data ?? '', 'utf8');
+    const method = entry.method ?? 0;
+    const compressed = method === 8 ? deflateRawSync(data) : data;
+    const mode = entry.mode ?? (entry.name.endsWith('/') ? 0o040755 : 0o100644);
+    const checksum = crc32(data);
+    const flags = 0x0800 | (entry.dataDescriptor ? 0x0008 : 0);
+    const local = Buffer.alloc(30);
+    local.writeUInt32LE(0x04034b50, 0);
+    local.writeUInt16LE(20, 4);
+    local.writeUInt16LE(flags, 6);
+    local.writeUInt16LE(method, 8);
+    local.writeUInt32LE(entry.localCrc ?? (entry.dataDescriptor ? 0 : checksum), 14);
+    local.writeUInt32LE(
+      entry.localCompressedSize ?? (entry.dataDescriptor ? 0 : compressed.length),
+      18,
+    );
+    local.writeUInt32LE(
+      entry.localUncompressedSize ?? (entry.dataDescriptor ? 0 : data.length),
+      22,
+    );
+    local.writeUInt16LE(localName.length, 26);
+    local.writeUInt16LE(0, 28);
+    let descriptor = Buffer.alloc(0);
+    if (entry.dataDescriptor) {
+      const signatureBytes = entry.descriptorSignature === false ? 0 : 4;
+      descriptor = Buffer.alloc(12 + signatureBytes);
+      let cursor = 0;
+      if (signatureBytes > 0) {
+        descriptor.writeUInt32LE(0x08074b50, cursor);
+        cursor += 4;
+      }
+      descriptor.writeUInt32LE(entry.descriptorCrc ?? checksum, cursor);
+      descriptor.writeUInt32LE(compressed.length, cursor + 4);
+      descriptor.writeUInt32LE(data.length, cursor + 8);
+    }
+    const gap = Buffer.isBuffer(entry.gap) ? entry.gap : Buffer.from(entry.gap ?? '', 'utf8');
+    localRecords.push(local, localName, compressed, descriptor, gap);
+
+    const central = Buffer.alloc(46);
+    central.writeUInt32LE(0x02014b50, 0);
+    central.writeUInt16LE((3 << 8) | 20, 4);
+    central.writeUInt16LE(20, 6);
+    central.writeUInt16LE(flags, 8);
+    central.writeUInt16LE(method, 10);
+    central.writeUInt32LE(checksum, 16);
+    central.writeUInt32LE(compressed.length, 20);
+    central.writeUInt32LE(data.length, 24);
+    central.writeUInt16LE(centralName.length, 28);
+    central.writeUInt16LE(0, 30);
+    central.writeUInt16LE(0, 32);
+    central.writeUInt16LE(0, 34);
+    central.writeUInt32LE((mode << 16) >>> 0, 38);
+    central.writeUInt32LE(localOffset, 42);
+    centralRecords.push(central, centralName);
+    localOffset +=
+      local.length + localName.length + compressed.length + descriptor.length + gap.length;
+  }
+
+  const central = Buffer.concat(centralRecords);
+  const eocd = Buffer.alloc(22);
+  eocd.writeUInt32LE(0x06054b50, 0);
+  eocd.writeUInt16LE(entries.length, 8);
+  eocd.writeUInt16LE(entries.length, 10);
+  eocd.writeUInt32LE(central.length, 12);
+  eocd.writeUInt32LE(localOffset, 16);
+  await fs.writeFile(archive, Buffer.concat([...localRecords, central, eocd]));
+}
+
+const [mode, root, variant] = process.argv.slice(2);
+if (mode) {
+  const appDirectory = path.join(root, 'app');
+  const transport = path.join(root, 'transport');
+  const output = path.join(root, 'output');
+  switch (mode) {
+    case 'prepare': {
+      const fixture = await createApp(appDirectory, {
+        executableMode: variant === 'nonexec' ? 0o644 : 0o755,
+      });
+      await createBuildReport(appDirectory, fixture);
+      if (variant === 'multiple')
+        await createApp(appDirectory, { appName: 'Second.app', executable: 'Second' });
+      if (variant === 'case') {
+        await fs.writeFile(path.join(fixture.resources, 'Case.txt'), 'upper\n');
+        await fs.writeFile(path.join(fixture.resources, 'case.txt'), 'lower\n');
+        const names = new Set(await fs.readdir(fixture.resources));
+        if (!names.has('Case.txt') || !names.has('case.txt')) process.exit(77);
+      }
+      break;
+    }
+    case 'check-roundtrip': {
+      const first = await manifest(transport);
+      assert.equal(first.schema, TRANSPORT_SCHEMA);
+      assert.deepEqual(first, await manifest(path.join(root, 'second')));
+      assert.equal(
+        await sha256(path.join(transport, ARCHIVE_NAME)),
+        await sha256(path.join(root, 'second', ARCHIVE_NAME)),
+      );
+      assert.equal(first.buildReport.configuration, 'Release');
+      assert.equal(first.buildReport.sdk, 'iphonesimulator');
+      assert.equal(await sha256(path.join(transport, BUILD_REPORT_NAME)), first.buildReport.sha256);
+      assert.equal(await sha256(path.join(output, BUILD_REPORT_NAME)), first.buildReport.sha256);
+      await fs.access(path.join(output, 'Fixture.app', 'Fixture'), fs.constants.X_OK);
+      const link = path.join(output, 'Fixture.app', 'Resources', 'Payload.link');
+      assert((await fs.lstat(link)).isSymbolicLink());
+      assert.equal(await fs.readlink(link), 'Payload.txt');
+      assert.equal(
+        await fs.readFile(path.join(output, 'Fixture.app', 'Resources', 'Payload.txt'), 'utf8'),
+        'payload\n',
+      );
+      break;
+    }
+    case 'stale':
+      await fs.mkdir(transport, { recursive: true });
+      for (const name of [
+        '.' + ARCHIVE_NAME + '.999999.tmp.zip',
+        '.' + ARCHIVE_NAME + '.999999.01234567-89ab-cdef-0123-456789abcdef.tmp.zip',
+        MANIFEST_NAME + '.999999.tmp',
+        '.' + MANIFEST_NAME + '.999999.01234567-89ab-cdef-0123-456789abcdef.tmp',
+      ])
+        await fs.writeFile(path.join(transport, name), 'stale\n');
+      break;
+    case 'check-clean':
+      assert.deepEqual(
+        (await fs.readdir(transport)).sort(),
+        [ARCHIVE_NAME, BUILD_REPORT_NAME, MANIFEST_NAME].sort(),
+      );
+      break;
+    case 'check-case':
+      assert.equal(
+        await fs.readFile(path.join(output, 'Fixture.app', 'Resources', 'Case.txt'), 'utf8'),
+        'upper\n',
+      );
+      assert.equal(
+        await fs.readFile(path.join(output, 'Fixture.app', 'Resources', 'case.txt'), 'utf8'),
+        'lower\n',
+      );
+      break;
+    case 'tamper-archive':
+      await fs.appendFile(path.join(transport, ARCHIVE_NAME), 'tamper');
+      break;
+    case 'tamper-report':
+      await fs.appendFile(path.join(transport, BUILD_REPORT_NAME), ' \n');
+      break;
+    case 'traversal':
+      await writeStoredZip(path.join(transport, ARCHIVE_NAME), [
+        { name: 'Fixture.app/' },
+        { name: '../escaped.txt', data: 'must never be extracted\n' },
+      ]);
+      await rewriteArchiveBinding(transport);
+      break;
+    case 'mutate-payload':
+      if (variant === 'unrelated')
+        await fs.writeFile(path.join(root, 'payload', 'unrelated.txt'), 'unrelated\n');
+      else if (variant === 'multiple')
+        await createApp(path.join(root, 'payload'), {
+          appName: 'Second.app',
+          executable: 'Second',
+        });
+      else if (variant === 'nonexec')
+        await fs.chmod(path.join(root, 'payload', 'Fixture.app', 'Fixture'), 0o644);
+      else throw Error('unknown payload mutation');
+      break;
+    case 'rebind':
+      await rewriteArchiveBinding(transport);
+      break;
+    default:
+      throw Error('unknown transport test mode: ' + mode);
+  }
+  process.exit(0);
+}
+
+test('pre-extraction ZIP validation accepts contained regular, directory, and symlink entries', async (t) => {
+  const root = await fixtureRoot(t, 'zip-valid');
+  const archive = path.join(root, 'valid.zip');
+  await writeStoredZip(archive, [
+    { name: 'Fixture.app/' },
+    { name: 'Fixture.app/Resources/' },
+    {
+      data: 'payload\n',
+      dataDescriptor: true,
+      name: 'Fixture.app/Resources/Payload.txt',
+    },
+    {
+      data: 'unsigned descriptor\n',
+      dataDescriptor: true,
+      descriptorSignature: false,
+      name: 'Fixture.app/Resources/Unsigned.txt',
+    },
+    {
+      data: 'Resources/Payload.txt',
+      method: 8,
+      mode: 0o120777,
+      name: 'Fixture.app/Payload.link',
+    },
+  ]);
+  assert.deepEqual(await validateIosAppZipArchive(archive, 'Fixture.app'), {
+    entries: 5,
+    zip64: false,
+  });
+});
+
+test('pre-extraction ZIP validation rejects traversal, absolute, and unrelated paths', async (t) => {
+  const root = await fixtureRoot(t, 'zip-paths');
+  for (const [label, name, pattern] of [
+    ['parent', '../escaped.txt', /unsafe member path/u],
+    ['nested-parent', 'Fixture.app/../../escaped.txt', /unsafe member path/u],
+    ['absolute', '/escaped.txt', /unsafe member path/u],
+    ['backslash', 'Fixture.app\\escaped.txt', /unsafe member path/u],
+    ['unrelated', 'Other.app/Payload.txt', /outside Fixture\.app/u],
+  ]) {
+    const archive = path.join(root, `${label}.zip`);
+    await writeStoredZip(archive, [{ name: 'Fixture.app/' }, { data: 'bad', name }]);
+    await assert.rejects(() => validateIosAppZipArchive(archive, 'Fixture.app'), pattern, label);
+  }
+});
+
+test('pre-extraction ZIP validation rejects special entries and header ambiguity', async (t) => {
+  const root = await fixtureRoot(t, 'zip-special');
+  for (const [label, entries, pattern] of [
+    [
+      'fifo',
+      [{ name: 'Fixture.app/' }, { mode: 0o010644, name: 'Fixture.app/pipe' }],
+      /unsupported special mode/u,
+    ],
+    [
+      'local-name-mismatch',
+      [
+        { name: 'Fixture.app/' },
+        { data: 'bad', localName: '../escaped.txt', name: 'Fixture.app/Safe.txt' },
+      ],
+      /local header filename does not match/u,
+    ],
+    [
+      'local-crc-mismatch',
+      [{ name: 'Fixture.app/' }, { data: 'bad', localCrc: 123, name: 'Fixture.app/Payload.txt' }],
+      /local CRC or sizes disagree/u,
+    ],
+    [
+      'local-size-mismatch',
+      [
+        { name: 'Fixture.app/' },
+        { data: 'bad', localCompressedSize: 999, name: 'Fixture.app/Payload.txt' },
+      ],
+      /local CRC or sizes disagree/u,
+    ],
+    [
+      'descriptor-mismatch',
+      [
+        { name: 'Fixture.app/' },
+        {
+          data: 'bad',
+          dataDescriptor: true,
+          descriptorCrc: 123,
+          name: 'Fixture.app/Payload.txt',
+        },
+      ],
+      /data descriptor disagrees/u,
+    ],
+    [
+      'unreferenced-gap',
+      [
+        { name: 'Fixture.app/' },
+        { data: 'bad', gap: 'hidden local bytes', name: 'Fixture.app/Payload.txt' },
+      ],
+      /unreferenced or ambiguous .* gap/u,
+    ],
+    [
+      'escaping-symlink',
+      [
+        { name: 'Fixture.app/' },
+        { data: '../../escaped.txt', mode: 0o120777, name: 'Fixture.app/Escape.link' },
+      ],
+      /symlink .* escapes Fixture\.app/u,
+    ],
+    [
+      'symlink-descendant',
+      [
+        { name: 'Fixture.app/' },
+        { data: 'Resources', mode: 0o120777, name: 'Fixture.app/Alias' },
+        { data: 'bad', name: 'Fixture.app/Alias/Payload.txt' },
+      ],
+      /descends through non-directory/u,
+    ],
+    [
+      'case-ambiguous-symlink-descendant',
+      [
+        { name: 'Fixture.app/' },
+        { data: 'Resources', mode: 0o120777, name: 'Fixture.app/Alias' },
+        { data: 'bad', name: 'Fixture.app/alias/Payload.txt' },
+      ],
+      /case-ambiguous non-directory ancestor/u,
+    ],
+    [
+      'unicode-case-ambiguous-symlink-descendant',
+      [
+        { data: 'Resources', mode: 0o120777, name: 'Fixture.app/straße' },
+        { name: 'Fixture.app/' },
+        { data: 'bad', name: 'Fixture.app/STRASSE/Payload.txt' },
+      ],
+      /case-ambiguous non-directory ancestor/u,
+    ],
+  ]) {
+    const archive = path.join(root, `${label}.zip`);
+    await writeStoredZip(archive, entries);
+    await assert.rejects(() => validateIosAppZipArchive(archive, 'Fixture.app'), pattern, label);
+  }
+});
diff --git a/src/sdks/react-native/tools/ios-app-transport.test.sh b/src/sdks/react-native/tools/ios-app-transport.test.sh
new file mode 100644
index 000000000..95bedeec6
--- /dev/null
+++ b/src/sdks/react-native/tools/ios-app-transport.test.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env bash
+set -euo pipefail
+tools="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+test_data="$tools/ios-app-transport.test.mts"
+cli="$tools/ios-app-transport.sh"
+bun test "$test_data"
+reject() {
+  local expected="$1"
+  shift
+  if bash "$cli" "$@" > "$scratch/failure.log" 2>&1; then
+    echo 'invalid iOS transport unexpectedly accepted' >&2
+    exit 1
+  fi
+  grep -Eq "$expected" "$scratch/failure.log" || { cat "$scratch/failure.log" >&2; exit 1; }
+}
+if [[ "$(uname -s)" != Darwin ]]; then
+  reject 'required Apple command ditto was not found; run this operation on macOS' pack --app-dir "$scratch/app" --transport-dir "$scratch/transport"
+  echo 'Apple transport roundtrip requires macOS; portable archive rejection tests passed.'
+  exit 0
+fi
+pack() { bash "$cli" pack --app-dir "$1/app" --transport-dir "$1/transport"; }
+extract() { bash "$cli" verify-extract --transport-dir "$1/transport" --output-dir "$1/output"; }
+root="$scratch/roundtrip"
+bun "$test_data" prepare "$root"
+pack "$root"
+bash "$cli" pack --app-dir "$root/app" --transport-dir "$root/second"
+extract "$root"
+bun "$test_data" check-roundtrip "$root"
+for attempt in 1 2; do
+  bun "$test_data" stale "$root"
+  pack "$root"
+  bun "$test_data" check-clean "$root"
+done
+root="$scratch/case"
+status=0
+bun "$test_data" prepare "$root" case || status=$?
+if [[ "$status" == 0 ]]; then
+  pack "$root"
+  extract "$root"
+  bun "$test_data" check-case "$root"
+elif [[ "$status" == 77 ]]; then
+  echo 'Case-distinct resource test requires a case-sensitive temporary volume.'
+else
+  exit "$status"
+fi
+for scenario in traversal tamper-archive tamper-report; do
+  root="$scratch/$scenario"
+  bun "$test_data" prepare "$root"
+  pack "$root"
+  bun "$test_data" "$scenario" "$root"
+  case "$scenario" in
+    traversal) expected='ZIP contains unsafe member path';;
+    tamper-archive) expected='transport archive (byte count|checksum) mismatch';;
+    tamper-report) expected='transport build report identity does not match its manifest binding';;
+  esac
+  reject "$expected" verify-extract --transport-dir "$root/transport" --output-dir "$root/output"
+  [[ ! -e "$root/escaped.txt" ]]
+done
+for scenario in multiple nonexec; do
+  root="$scratch/invalid-pack-$scenario"
+  bun "$test_data" prepare "$root" "$scenario"
+  if [[ "$scenario" == multiple ]]; then expected='must contain exactly one direct \.app directory; found 2'; else expected='executable is not executable'; fi
+  reject "$expected" pack --app-dir "$root/app" --transport-dir "$root/transport"
+done
+for scenario in unrelated multiple nonexec; do
+  root="$scratch/invalid-extract-$scenario"
+  bun "$test_data" prepare "$root"
+  pack "$root"
+  mkdir "$root/payload"
+  ditto -x -k "$root/transport/react-native-mobile-ios-app.zip" "$root/payload"
+  bun "$test_data" mutate-payload "$root" "$scenario"
+  rm "$root/transport/react-native-mobile-ios-app.zip"
+  ditto -c -k --sequesterRsrc "$root/payload" "$root/transport/react-native-mobile-ios-app.zip"
+  bun "$test_data" rebind "$root"
+  case "$scenario" in
+    unrelated) expected='iOS app ZIP member is outside Fixture\.app: "unrelated\.txt"';;
+    multiple) expected='iOS app ZIP member is outside Fixture\.app: "Second\.app/"';;
+    nonexec) expected='executable is not executable';;
+  esac
+  reject "$expected" verify-extract --transport-dir "$root/transport" --output-dir "$root/output"
+done
diff --git a/src/sdks/react-native/tools/ios-icu-autolinking.test.mjs b/src/sdks/react-native/tools/ios-icu-autolinking.test.mjs
deleted file mode 100644
index 2893144e8..000000000
--- a/src/sdks/react-native/tools/ios-icu-autolinking.test.mjs
+++ /dev/null
@@ -1,462 +0,0 @@
-#!/usr/bin/env node
-
-import assert from "node:assert/strict";
-import { spawnSync } from "node:child_process";
-import { createRequire } from "node:module";
-import fs from "node:fs/promises";
-import os from "node:os";
-import path from "node:path";
-
-const PREFIX = "ios-icu-autolinking.test.mjs";
-const COLLIDING_RESOURCE = "zh_TW.res";
-const PNPM = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
-const COMMUNITY_CLI_VERSION = "20.2.0";
-const COMMUNITY_CLI_PACKAGES = [
-  "@react-native-community/cli",
-  "@react-native-community/cli-platform-android",
-  "@react-native-community/cli-platform-ios",
-];
-
-function usage() {
-  console.error(
-    `usage: ${PREFIX} --react-native-tarball  ` +
-      `--icu-source  --expo-project `,
-  );
-}
-
-function parseArgs(argv) {
-  const options = new Map();
-  for (let index = 0; index < argv.length; index += 1) {
-    const name = argv[index];
-    if (name === "--help" || name === "-h") {
-      usage();
-      process.exit(0);
-    }
-    if (!new Set(["--react-native-tarball", "--icu-source", "--expo-project"]).has(name)) {
-      usage();
-      throw new Error(`${PREFIX}: unknown argument ${name}`);
-    }
-    const value = argv[index + 1];
-    if (!value || value.startsWith("--")) {
-      usage();
-      throw new Error(`${PREFIX}: ${name} requires a value`);
-    }
-    options.set(name, path.resolve(value));
-    index += 1;
-  }
-  for (const name of ["--react-native-tarball", "--icu-source", "--expo-project"]) {
-    if (!options.has(name)) {
-      usage();
-      throw new Error(`${PREFIX}: missing ${name}`);
-    }
-  }
-  return {
-    expoProject: options.get("--expo-project"),
-    icuSource: options.get("--icu-source"),
-    reactNativeTarball: options.get("--react-native-tarball"),
-  };
-}
-
-function run(command, args, { cwd = undefined, env = process.env } = {}) {
-  const result = spawnSync(command, args, {
-    cwd,
-    encoding: "utf8",
-    env,
-    maxBuffer: 16 * 1024 * 1024,
-  });
-  assert.equal(
-    result.status,
-    0,
-    `${command} ${args.join(" ")} failed:\n${result.stderr || result.stdout}`,
-  );
-  return result.stdout;
-}
-
-async function requireFile(file, label) {
-  const stat = await fs.stat(file).catch((error) => {
-    if (error?.code === "ENOENT") return undefined;
-    throw error;
-  });
-  assert.equal(stat?.isFile(), true, `${label} is missing: ${file}`);
-  assert.ok(stat.size > 0, `${label} is empty: ${file}`);
-}
-
-async function write(file, contents) {
-  await fs.mkdir(path.dirname(file), { recursive: true });
-  await fs.writeFile(file, contents);
-}
-
-async function copyIcuDescriptors(source, destination, { legacyFlatteningControl }) {
-  for (const descriptor of ["package.json", "README.md", "OliphauntICU.podspec"]) {
-    await requireFile(path.join(source, descriptor), `source ICU ${descriptor}`);
-  }
-  await fs.copyFile(path.join(source, "README.md"), path.join(destination, "README.md"));
-
-  const packageJson = JSON.parse(await fs.readFile(path.join(source, "package.json"), "utf8"));
-  assert.equal(packageJson.name, "@oliphaunt/icu");
-  if (!legacyFlatteningControl) {
-    assert.ok(
-      packageJson.files?.includes("react-native.config.js"),
-      "@oliphaunt/icu must publish react-native.config.js",
-    );
-    assert.ok(
-      packageJson.files?.includes("OliphauntICU.bundle"),
-      "@oliphaunt/icu must publish its structure-preserving resource bundle",
-    );
-    assert.equal(
-      packageJson.oliphaunt?.dataRelativePath,
-      "OliphauntICU.bundle/share/icu",
-      "@oliphaunt/icu metadata must select ICU data within the resource bundle",
-    );
-    await requireFile(
-      path.join(source, "react-native.config.js"),
-      "source ICU react-native.config.js",
-    );
-    await fs.copyFile(
-      path.join(source, "react-native.config.js"),
-      path.join(destination, "react-native.config.js"),
-    );
-  } else {
-    packageJson.files = (packageJson.files ?? [])
-      .filter((member) => member !== "react-native.config.js" && member !== "OliphauntICU.bundle");
-    packageJson.files.push("share");
-    packageJson.oliphaunt = {
-      ...(packageJson.oliphaunt ?? {}),
-      dataRelativePath: "share/icu",
-    };
-  }
-  await fs.writeFile(
-    path.join(destination, "package.json"),
-    `${JSON.stringify(packageJson, null, 2)}\n`,
-  );
-
-  const sourcePodspec = await fs.readFile(path.join(source, "OliphauntICU.podspec"), "utf8");
-  let podspec = sourcePodspec;
-  if (legacyFlatteningControl) {
-    podspec = sourcePodspec.replace(
-      /^  s\.resources = ['"]OliphauntICU\.bundle['"]$/mu,
-      "  s.resource_bundles = {\n    'OliphauntICU' => ['share/icu/**/*']\n  }",
-    );
-    assert.notEqual(
-      podspec,
-      sourcePodspec,
-      "legacy control must replace the source structure-preserving resource declaration",
-    );
-  }
-  await fs.writeFile(path.join(destination, "OliphauntICU.podspec"), podspec);
-
-  // These paths model the collision that the real ICU tree exposes hundreds of
-  // times. The names deliberately match while their source directories do not.
-  const resourceRoot = legacyFlatteningControl
-    ? path.join(destination, "share/icu")
-    : path.join(destination, "OliphauntICU.bundle/share/icu");
-  await write(
-    path.join(resourceRoot, "icudt-test/coll", COLLIDING_RESOURCE),
-    "collation fixture\n",
-  );
-  await write(
-    path.join(resourceRoot, "icudt-test/lang", COLLIDING_RESOURCE),
-    "language fixture\n",
-  );
-}
-
-async function packIcuFixture(source, root, name, { legacyFlatteningControl }) {
-  const stage = path.join(root, `${name}-source`);
-  const destination = path.join(root, `${name}-pack`);
-  await fs.mkdir(stage, { recursive: true });
-  await fs.mkdir(destination, { recursive: true });
-  await copyIcuDescriptors(source, stage, { legacyFlatteningControl });
-  run(
-    PNPM,
-    ["--dir", stage, "pack", "--pack-destination", destination],
-    { env: { ...process.env, PNPM_CONFIG_IGNORE_SCRIPTS: "true" } },
-  );
-  const archives = (await fs.readdir(destination))
-    .filter((entry) => entry.endsWith(".tgz"))
-    .sort();
-  assert.equal(archives.length, 1, `${name} fixture must produce exactly one npm archive`);
-  return path.join(destination, archives[0]);
-}
-
-async function extractNpmPackage(archive, destination) {
-  await fs.mkdir(destination, { recursive: true });
-  run("tar", ["-xzf", archive, "-C", destination, "--strip-components=1"]);
-}
-
-async function resolveBareToolchain(expoProject) {
-  const packageJson = JSON.parse(
-    await fs.readFile(path.join(expoProject, "package.json"), "utf8"),
-  );
-  const resolver = createRequire(path.join(expoProject, "package.json"));
-  const packages = new Map();
-  for (const name of COMMUNITY_CLI_PACKAGES) {
-    assert.equal(
-      packageJson.devDependencies?.[name],
-      COMMUNITY_CLI_VERSION,
-      `${name} must be workspace-pinned to ${COMMUNITY_CLI_VERSION}`,
-    );
-    const manifestPath = resolver.resolve(`${name}/package.json`);
-    const manifest = JSON.parse(await fs.readFile(manifestPath, "utf8"));
-    assert.equal(manifest.version, COMMUNITY_CLI_VERSION, `${name} installed version drifted`);
-    packages.set(name, { manifest, root: path.dirname(manifestPath) });
-  }
-  const reactNativeManifestPath = resolver.resolve("react-native/package.json");
-  const reactNativeManifest = JSON.parse(await fs.readFile(reactNativeManifestPath, "utf8"));
-  packages.set("react-native", {
-    manifest: reactNativeManifest,
-    root: path.dirname(reactNativeManifestPath),
-  });
-  const cli = packages.get("@react-native-community/cli");
-  const cliBin = typeof cli.manifest.bin === "string"
-    ? cli.manifest.bin
-    : cli.manifest.bin?.["rnc-cli"] ?? Object.values(cli.manifest.bin ?? {})[0];
-  assert.equal(typeof cliBin, "string", "Community CLI package must declare its executable");
-  return { cliBin: path.join(cli.root, cliBin), packages };
-}
-
-async function linkPackage(root, name, source) {
-  const destination = path.join(root, "node_modules", ...name.split("/"));
-  await fs.mkdir(path.dirname(destination), { recursive: true });
-  await fs.symlink(
-    await fs.realpath(source),
-    destination,
-    process.platform === "win32" ? "junction" : "dir",
-  );
-}
-
-async function writeConsumer(root, reactNativeTarball, icuTarball, bareToolchain) {
-  const reactNativeRoot = path.join(root, "node_modules/@oliphaunt/react-native");
-  const icuRoot = path.join(root, "node_modules/@oliphaunt/icu");
-  await extractNpmPackage(reactNativeTarball, reactNativeRoot);
-  await extractNpmPackage(icuTarball, icuRoot);
-  const cliDependencies = Object.fromEntries(
-    COMMUNITY_CLI_PACKAGES.map((name) => [
-      name,
-      bareToolchain.packages.get(name).manifest.version,
-    ]),
-  );
-  await write(
-    path.join(root, "package.json"),
-    `${JSON.stringify({
-      name: "oliphaunt-ios-autolinking-fixture",
-      private: true,
-      version: "0.0.0",
-      dependencies: {
-        "@oliphaunt/icu": "0.0.0",
-        "@oliphaunt/react-native": "0.0.0",
-        "react-native": bareToolchain.packages.get("react-native").manifest.version,
-      },
-      devDependencies: cliDependencies,
-    }, null, 2)}\n`,
-  );
-  for (const [name, descriptor] of bareToolchain.packages) {
-    await linkPackage(root, name, descriptor.root);
-  }
-  return { icuRoot, reactNativeRoot };
-}
-
-function autolink(expoProject, consumer, platform) {
-  const output = run(PNPM, [
-    "--dir",
-    expoProject,
-    "exec",
-    "expo-modules-autolinking",
-    "react-native-config",
-    path.join(consumer, "node_modules"),
-    "--project-root",
-    consumer,
-    "--platform",
-    platform,
-    "--json",
-  ]);
-  try {
-    return JSON.parse(output);
-  } catch (error) {
-    assert.fail(`Expo autolinking returned invalid JSON: ${error.message}\n${output}`);
-  }
-}
-
-function bareAutolink(cliBin, consumer, platform) {
-  const output = run(process.execPath, [cliBin, "config", "--platform", platform], {
-    cwd: consumer,
-  });
-  try {
-    return JSON.parse(output);
-  } catch (error) {
-    assert.fail(`React Native Community CLI returned invalid JSON: ${error.message}\n${output}`);
-  }
-}
-
-async function duplicateResourceBasenames(icuRoot) {
-  const packageJson = JSON.parse(await fs.readFile(path.join(icuRoot, "package.json"), "utf8"));
-  const dataRelativePath = packageJson.oliphaunt?.dataRelativePath;
-  assert.equal(typeof dataRelativePath, "string", "ICU fixture must declare oliphaunt.dataRelativePath");
-  const resourceRoot = path.join(icuRoot, ...dataRelativePath.split("/"));
-  const byBasename = new Map();
-  const pending = [resourceRoot];
-  while (pending.length > 0) {
-    const directory = pending.pop();
-    for (const entry of await fs.readdir(directory, { withFileTypes: true })) {
-      const file = path.join(directory, entry.name);
-      if (entry.isDirectory()) {
-        pending.push(file);
-      } else if (entry.isFile()) {
-        const relative = path.relative(icuRoot, file).split(path.sep).join("/");
-        const files = byBasename.get(entry.name) ?? [];
-        files.push(relative);
-        byBasename.set(entry.name, files);
-      }
-    }
-  }
-  return new Map(
-    [...byBasename.entries()]
-      .filter(([, files]) => files.length > 1)
-      .sort(([left], [right]) => left.localeCompare(right)),
-  );
-}
-
-async function assertBrokenControlIsMeaningful(config, icuRoot) {
-  const dependency = config.dependencies?.["@oliphaunt/icu"];
-  assert.ok(dependency, "control ICU package without an opt-out must be discovered by Expo autolinking");
-  assert.equal(
-    path.basename(dependency.platforms?.ios?.podspecPath ?? ""),
-    "OliphauntICU.podspec",
-    "control ICU package must resolve its CocoaPods carrier",
-  );
-  const podspec = await fs.readFile(path.join(icuRoot, "OliphauntICU.podspec"), "utf8");
-  assert.match(
-    podspec,
-    /resource_bundles[\s\S]*share\/icu\/\*\*\/\*/u,
-    "control podspec must expose the recursive ICU tree through a resource bundle",
-  );
-  const duplicates = await duplicateResourceBasenames(icuRoot);
-  assert.deepEqual(
-    duplicates.get(COLLIDING_RESOURCE)?.sort(),
-    [
-      `share/icu/icudt-test/coll/${COLLIDING_RESOURCE}`,
-      `share/icu/icudt-test/lang/${COLLIDING_RESOURCE}`,
-    ],
-    "control fixture must preserve a representative flattened-resource collision",
-  );
-}
-
-async function assertCandidateIsSafe(config, consumer, icuRoot, platform) {
-  const reactNative = config.dependencies?.["@oliphaunt/react-native"];
-  assert.ok(
-    reactNative,
-    `packed @oliphaunt/react-native must be discovered by Expo ${platform} autolinking`,
-  );
-  assert.ok(
-    reactNative.platforms?.[platform],
-    `packed @oliphaunt/react-native must expose its ${platform} native carrier`,
-  );
-  if (platform === "ios") {
-    assert.equal(
-      path.basename(reactNative.platforms.ios.podspecPath ?? ""),
-      "OliphauntReactNative.podspec",
-      "packed @oliphaunt/react-native must resolve its CocoaPods carrier",
-    );
-  }
-  assert.equal(
-    config.dependencies?.["@oliphaunt/icu"],
-    undefined,
-    `packed @oliphaunt/icu must opt out of ${platform} native autolinking`,
-  );
-
-  const resolver = createRequire(path.join(consumer, "resolve-icu.cjs"));
-  assert.equal(
-    await fs.realpath(resolver.resolve("@oliphaunt/icu/package.json")),
-    await fs.realpath(path.join(icuRoot, "package.json")),
-    "autolinking opt-out must not make the ICU data package unavailable to JavaScript",
-  );
-  const podspec = await fs.readFile(path.join(icuRoot, "OliphauntICU.podspec"), "utf8");
-  assert.match(
-    podspec,
-    /^  s\.resources = ['"]OliphauntICU\.bundle['"]$/mu,
-    "packed @oliphaunt/icu must expose the preassembled bundle as one Xcode resource",
-  );
-  const duplicates = await duplicateResourceBasenames(icuRoot);
-  assert.deepEqual(
-    duplicates.get(COLLIDING_RESOURCE)?.sort(),
-    [
-      `OliphauntICU.bundle/share/icu/icudt-test/coll/${COLLIDING_RESOURCE}`,
-      `OliphauntICU.bundle/share/icu/icudt-test/lang/${COLLIDING_RESOURCE}`,
-    ],
-    "packed bundle must retain colliding basenames in their distinct source directories",
-  );
-}
-
-async function main() {
-  const args = parseArgs(process.argv.slice(2));
-  await requireFile(args.reactNativeTarball, "packed @oliphaunt/react-native archive");
-  await requireFile(path.join(args.expoProject, "package.json"), "Expo fixture package.json");
-  const bareToolchain = await resolveBareToolchain(args.expoProject);
-  await requireFile(bareToolchain.cliBin, "React Native Community CLI executable");
-
-  const root = await fs.mkdtemp(path.join(os.tmpdir(), "oliphaunt-ios-icu-autolinking-"));
-  try {
-    const candidateArchive = await packIcuFixture(args.icuSource, root, "candidate", {
-      legacyFlatteningControl: false,
-    });
-    const candidateConsumer = path.join(root, "candidate-consumer");
-    const candidatePackages = await writeConsumer(
-      candidateConsumer,
-      args.reactNativeTarball,
-      candidateArchive,
-      bareToolchain,
-    );
-    await assertCandidateIsSafe(
-      autolink(args.expoProject, candidateConsumer, "ios"),
-      candidateConsumer,
-      candidatePackages.icuRoot,
-      "ios",
-    );
-    await assertCandidateIsSafe(
-      autolink(args.expoProject, candidateConsumer, "android"),
-      candidateConsumer,
-      candidatePackages.icuRoot,
-      "android",
-    );
-    await assertCandidateIsSafe(
-      bareAutolink(bareToolchain.cliBin, candidateConsumer, "ios"),
-      candidateConsumer,
-      candidatePackages.icuRoot,
-      "ios",
-    );
-    await assertCandidateIsSafe(
-      bareAutolink(bareToolchain.cliBin, candidateConsumer, "android"),
-      candidateConsumer,
-      candidatePackages.icuRoot,
-      "android",
-    );
-
-    // Reconstruct the legacy package contract from the current source
-    // descriptors: omit the opt-out and expose the recursive ICU tree through
-    // resource_bundles. This proves the test observes the old collision
-    // mechanism rather than passing merely because dependency discovery broke.
-    const controlArchive = await packIcuFixture(args.icuSource, root, "control", {
-      legacyFlatteningControl: true,
-    });
-    const controlConsumer = path.join(root, "control-consumer");
-    const controlPackages = await writeConsumer(
-      controlConsumer,
-      args.reactNativeTarball,
-      controlArchive,
-      bareToolchain,
-    );
-    await assertBrokenControlIsMeaningful(
-      autolink(args.expoProject, controlConsumer, "ios"),
-      controlPackages.icuRoot,
-    );
-    await assertBrokenControlIsMeaningful(
-      bareAutolink(bareToolchain.cliBin, controlConsumer, "ios"),
-      controlPackages.icuRoot,
-    );
-  } finally {
-    await fs.rm(root, { force: true, recursive: true });
-  }
-
-  console.log("Packed React Native and ICU Expo/bare autolinking contract passed");
-}
-
-await main();
diff --git a/src/sdks/react-native/tools/mobile-e2e.sh b/src/sdks/react-native/tools/mobile-e2e.sh
index e7de3d1ee..04f6f1525 100755
--- a/src/sdks/react-native/tools/mobile-e2e.sh
+++ b/src/sdks/react-native/tools/mobile-e2e.sh
@@ -73,9 +73,7 @@ case "$platform" in
     export OLIPHAUNT_MOBILE_E2E_ASSERTION_RUNNER="${OLIPHAUNT_MOBILE_E2E_ASSERTION_RUNNER:-maestro}"
     export OLIPHAUNT_EXPO_IOS_SCRATCH="$mobile_scratch"
     if [ "$mobile_runner" = "smoke" ]; then
-      export_mobile_e2e_icu_expectation_from_manifest \
-        "$app/OliphauntReactNativeResources.bundle/oliphaunt/runtime/manifest.properties" \
-        "iOS app"
+      export_mobile_e2e_icu_expectation_from_ios_app "$app"
       rm -f \
         "$mobile_scratch/reports/smoke-report.json" \
         "$mobile_scratch/reports/smoke-extension-receipt.json"
diff --git a/src/sdks/react-native/tools/mobile-extension-artifact-paths.mjs b/src/sdks/react-native/tools/mobile-extension-artifact-paths.mjs
deleted file mode 100644
index 37ace5c9f..000000000
--- a/src/sdks/react-native/tools/mobile-extension-artifact-paths.mjs
+++ /dev/null
@@ -1,1431 +0,0 @@
-#!/usr/bin/env bun
-import { createHash } from "node:crypto";
-import {
-  chmodSync,
-  closeSync,
-  copyFileSync,
-  createReadStream,
-  lstatSync,
-  mkdirSync,
-  mkdtempSync,
-  openSync,
-  readSync,
-  readFileSync,
-  renameSync,
-  rmSync,
-  statSync,
-} from "node:fs";
-import { readFile } from "node:fs/promises";
-import { dirname, join, relative, resolve, sep } from "node:path";
-import { isDeepStrictEqual } from "node:util";
-import { createGunzip } from "node:zlib";
-
-import { captureCommandOutput } from "../../../../tools/dev/capture-command-output.mjs";
-import {
-  extensionCarrierLegalContract,
-  extensionCarrierLegalFileInventory,
-} from "../../../../tools/release/extension-upstream-licenses.mjs";
-import { assertWasixExtensionMemberInstall } from "../../../../src/shared/extension-runtime-contract/wasix-extension-install.mjs";
-
-const OPTION_NAMES = new Set([
-  "--root",
-  "--artifact-root",
-  "--materialize-root",
-  "--extensions",
-  "--asset-kind",
-  "--asset-target",
-  "--required",
-]);
-const MOBILE_TARGETS = new Set(["android-arm64-v8a", "android-x86_64", "ios-xcframework"]);
-const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u;
-const C_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u;
-const MAX_ARTIFACT_BYTES = 2 * 1024 * 1024 * 1024;
-const MAX_BUNDLE_MEMBERS = 4096;
-const MAX_BUNDLE_ARCHIVE_MEMBERS = 32_768;
-const MAX_BUNDLE_EXPANDED_BYTES = 4 * 1024 * 1024 * 1024;
-const EXTENSION_MEMBER_KEYS = new Set([
-  "sqlName",
-  "createsExtension",
-  "dependencies",
-  "dataFiles",
-  "extensionSqlFileNames",
-  "extensionSqlFilePrefixes",
-  "nativeModuleStem",
-  "iosNativeDependencies",
-  "iosRegistration",
-  "wasixInstall",
-  "sharedPreloadLibraries",
-  "assets",
-]);
-const DIRECT_MANIFEST_KEYS = new Set([
-  "schema",
-  "product",
-  "version",
-  "compatibility",
-  ...EXTENSION_MEMBER_KEYS,
-]);
-const BUNDLE_MANIFEST_KEYS = new Set([
-  "schema",
-  "product",
-  "version",
-  "compatibility",
-  "extensions",
-  "carrierAssets",
-]);
-const DIRECT_ASSET_KEYS = new Set([
-  "name",
-  "path",
-  "source",
-  "sha256",
-  "bytes",
-  "family",
-  "kind",
-  "target",
-  "identity",
-]);
-const BUNDLE_MEMBER_ASSET_KEYS = new Set([
-  ...DIRECT_ASSET_KEYS,
-  "carrierAsset",
-  "carrierRoot",
-  "memberPath",
-]);
-const BUNDLE_CARRIER_ASSET_KEYS = new Set([
-  "name",
-  "path",
-  "sha256",
-  "bytes",
-  "family",
-  "target",
-  "kind",
-  "memberCount",
-]);
-
-function manifestEnvelopeKeys(baseKeys, manifest, repositoryContract) {
-  const owner = repositoryContract.products.get(manifest.product);
-  return owner?.releaseProduct === owner?.artifactProduct
-    ? baseKeys
-    : new Set([...baseKeys, "releaseProduct", "family"]);
-}
-
-class CliFailure extends Error {
-  constructor(message, code = 1) {
-    super(message);
-    this.code = code;
-  }
-}
-
-function fail(message, code = 1) {
-  throw new CliFailure(message, code);
-}
-
-function usage() {
-  fail(
-    "usage: mobile-extension-artifact-paths.mjs --root PATH --artifact-root PATH --materialize-root PATH --extensions CSV --asset-kind runtime|ios-xcframework --asset-target TARGET|* --required 0|1",
-    2,
-  );
-}
-
-function parseOptions(args) {
-  if (args.length % 2 !== 0) {
-    usage();
-  }
-  const options = new Map();
-  for (let index = 0; index < args.length; index += 2) {
-    const name = args[index];
-    const value = args[index + 1];
-    if (!OPTION_NAMES.has(name)) {
-      fail(`unknown option: ${name}`, 2);
-    }
-    if (options.has(name)) {
-      fail(`duplicate option: ${name}`, 2);
-    }
-    if (value === undefined || value.startsWith("--")) {
-      usage();
-    }
-    options.set(name, value);
-  }
-  for (const name of OPTION_NAMES) {
-    if (!options.has(name)) {
-      usage();
-    }
-  }
-  return options;
-}
-
-function isObject(value) {
-  return value !== null && !Array.isArray(value) && typeof value === "object";
-}
-
-function requireExactKeys(value, expected, context) {
-  if (!isObject(value)) {
-    fail(`${context} must be an object`);
-  }
-  const actual = Object.keys(value).sort(compareText);
-  const canonical = [...expected].sort(compareText);
-  if (!isDeepStrictEqual(actual, canonical)) {
-    fail(
-      `${context} fields must be exactly ${canonical.join(",")}; got ${actual.join(",")}`,
-    );
-  }
-}
-
-function isFile(file) {
-  try {
-    const metadata = lstatSync(file);
-    return metadata.isFile() && !metadata.isSymbolicLink();
-  } catch {
-    return false;
-  }
-}
-
-async function sha256File(file) {
-  return await new Promise((resolve, reject) => {
-    const digest = createHash("sha256");
-    const stream = createReadStream(file);
-    stream.on("data", (chunk) => digest.update(chunk));
-    stream.on("error", reject);
-    stream.on("end", () => resolve(digest.digest("hex")));
-  });
-}
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function safeComponent(value, context) {
-  if (
-    typeof value !== "string"
-    || value.length === 0
-    || value === "."
-    || value === ".."
-    || value.includes("/")
-    || value.includes("\\")
-    || value.includes("\0")
-  ) {
-    fail(`${context} must be a safe non-empty path component`);
-  }
-  return value;
-}
-
-function safeArchiveMember(value, context) {
-  if (typeof value !== "string" || value.length === 0 || value.includes("\\") || value.includes("\0")) {
-    fail(`${context} must be a safe relative archive path`);
-  }
-  const parts = value.split("/");
-  if (value.startsWith("/") || parts.some((part) => part.length === 0 || part === "." || part === "..")) {
-    fail(`${context} must be a safe relative archive path`);
-  }
-  return value;
-}
-
-function validatePublishedPath(value, name, context) {
-  if (typeof value !== "string" || value.length === 0 || value.includes("\\") || value.includes("\0")) {
-    fail(`${context} must declare a release-assets path`);
-  }
-  const suffix = `/release-assets/${name}`;
-  if (value !== `release-assets/${name}` && !value.endsWith(suffix)) {
-    fail(`${context} must point to release-assets/${name}`);
-  }
-}
-
-function validateDigestRow(value, context) {
-  if (!/^[0-9a-f]{64}$/u.test(value.sha256 ?? "")) {
-    fail(`${context} must declare a lowercase SHA-256 digest`);
-  }
-  if (!Number.isSafeInteger(value.bytes) || value.bytes <= 0) {
-    fail(`${context} must declare a positive safe-integer byte count`);
-  }
-  if (value.bytes > MAX_ARTIFACT_BYTES) {
-    fail(`${context} exceeds the maximum supported size of ${MAX_ARTIFACT_BYTES} bytes`);
-  }
-}
-
-function canonicalStringList(value, context, validate = safeComponent) {
-  if (!Array.isArray(value)) {
-    fail(`${context} must be an array`);
-  }
-  const result = value.map((item, index) => validate(item, `${context}[${index}]`)).sort(compareText);
-  if (new Set(result).size !== result.length) {
-    fail(`${context} must not contain duplicates`);
-  }
-  return result;
-}
-
-function sqlFileName(value, context) {
-  if (typeof value !== "string" || !/^[A-Za-z0-9._-]{1,128}$/u.test(value) || !value.endsWith(".sql")) {
-    fail(`${context} must be a portable SQL basename ending in .sql`);
-  }
-  return value;
-}
-
-function sqlFilePrefix(value, context) {
-  if (typeof value !== "string" || !/^[A-Za-z0-9_-]{1,128}$/u.test(value)) {
-    fail(`${context} must be a dot-free portable SQL basename prefix`);
-  }
-  return value;
-}
-
-function parseIosDependencyContract(text, source) {
-  const lines = text.split(/\r?\n/u).filter((line) => line.length > 0 && !line.startsWith("#"));
-  if (lines.length === 0) fail(`${source} is empty`);
-  const header = lines[0].split("\t");
-  const sqlIndex = header.indexOf("sql-name");
-  const dependenciesIndex = header.indexOf("ios-static-dependencies");
-  if (sqlIndex < 0 || dependenciesIndex < 0) {
-    fail(`${source} must declare sql-name and ios-static-dependencies columns`);
-  }
-  const result = new Map();
-  for (const [index, line] of lines.slice(1).entries()) {
-    const fields = line.split("\t");
-    const sqlName = safeComponent(fields[sqlIndex], `${source}:${index + 2} sql-name`);
-    const dependencies = canonicalStringList(
-      (fields[dependenciesIndex] ?? "").split(",").filter(Boolean),
-      `${source}:${index + 2} ios-static-dependencies`,
-    );
-    if (result.has(sqlName)) fail(`${source} repeats iOS dependency owner ${sqlName}`);
-    result.set(sqlName, dependencies);
-  }
-  return result;
-}
-
-function parseIosDependencyOverlay(value, source) {
-  if (!isObject(value) || value["format-version"] !== 1 || !Array.isArray(value.extensions)) {
-    fail(`${source} must use format-version 1 and declare extensions`);
-  }
-  const result = new Map();
-  for (const [index, row] of value.extensions.entries()) {
-    if (!isObject(row)) fail(`${source} extension ${index} must be an object`);
-    const sqlName = safeComponent(row["sql-name"], `${source} extension ${index} sql-name`);
-    const dependencies = canonicalStringList(
-      row["static-dependencies"],
-      `${source} extension ${sqlName} static-dependencies`,
-    );
-    if (result.has(sqlName)) fail(`${source} repeats iOS dependency owner ${sqlName}`);
-    result.set(sqlName, dependencies);
-  }
-  return result;
-}
-
-async function loadRepositoryContract(root) {
-  const metadataPath = join(root, "src/extensions/generated/sdk/extensions.json");
-  const iosOverlayPath = join(root, "src/extensions/generated/sdk/ios-static-dependencies.json");
-  const iosDependenciesPath = join(root, "src/extensions/generated/mobile/static-extensions.tsv");
-  const nativeVersionPath = join(root, "src/runtimes/liboliphaunt/native/VERSION");
-  const wasixVersionPath = join(root, "src/runtimes/liboliphaunt/wasix/VERSION");
-  let metadata;
-  let iosOverlay;
-  let iosDependenciesText;
-  let nativeRuntimeVersion;
-  let wasixRuntimeVersion;
-  try {
-    [metadata, iosOverlay, iosDependenciesText, nativeRuntimeVersion, wasixRuntimeVersion] = await Promise.all([
-      readFile(metadataPath, "utf8").then((value) => JSON.parse(value)),
-      readFile(iosOverlayPath, "utf8").then((value) => JSON.parse(value)),
-      readFile(iosDependenciesPath, "utf8"),
-      readFile(nativeVersionPath, "utf8").then((value) => value.trim()),
-      readFile(wasixVersionPath, "utf8").then((value) => value.trim()),
-    ]);
-  } catch (error) {
-    fail(`could not load generated mobile extension ownership and runtime versions: ${error.message}`);
-  }
-  if (!STABLE_SEMVER.test(nativeRuntimeVersion) || !STABLE_SEMVER.test(wasixRuntimeVersion)) {
-    fail("native and WASIX runtime VERSION files must contain stable SemVer");
-  }
-  if (!isObject(metadata) || !Array.isArray(metadata.extensions)) {
-    fail(`${metadataPath} must declare extensions`);
-  }
-  const generatedIosDependencies = parseIosDependencyOverlay(iosOverlay, iosOverlayPath);
-  const staticIosDependencies = parseIosDependencyContract(iosDependenciesText, iosDependenciesPath);
-  const products = new Map();
-  const sqlOwners = new Map();
-  for (const [index, row] of metadata.extensions.entries()) {
-    if (!isObject(row)) {
-      fail(`${metadataPath} extension ${index} must be an object`);
-    }
-    const sqlName = safeComponent(row["sql-name"], `${metadataPath} extension ${index} sql-name`);
-    const product = safeComponent(row["artifact-product"], `${metadataPath} extension ${sqlName} artifact-product`);
-    const releaseProduct = safeComponent(
-      row["release-product"],
-      `${metadataPath} extension ${sqlName} release-product`,
-    );
-    if (sqlOwners.has(sqlName)) {
-      fail(`${metadataPath} repeats SQL extension owner ${sqlName}`);
-    }
-    sqlOwners.set(sqlName, product);
-    const postgresMajor = String(row["postgres-major"] ?? "");
-    if (!/^[1-9][0-9]*$/u.test(postgresMajor)) {
-      fail(`${metadataPath} extension ${sqlName} has invalid postgres-major`);
-    }
-    if (typeof row["creates-extension"] !== "boolean") {
-      fail(`${metadataPath} extension ${sqlName} creates-extension must be boolean`);
-    }
-    const nativeModuleStem = row["native-module-stem"] === null
-      ? null
-      : safeComponent(row["native-module-stem"], `${metadataPath} extension ${sqlName} native-module-stem`);
-    const generatedDependencies = generatedIosDependencies.get(sqlName) ?? [];
-    const staticDependencies = staticIosDependencies.get(sqlName)
-      ?? (nativeModuleStem === null
-        ? []
-        : fail(`${iosDependenciesPath} has no row for native extension ${sqlName}`));
-    if (!isDeepStrictEqual(generatedDependencies, staticDependencies)) {
-      fail(`${iosOverlayPath} and ${iosDependenciesPath} disagree for iOS dependencies of ${sqlName}`);
-    }
-    if (nativeModuleStem === null && generatedDependencies.length > 0) {
-      fail(`${iosOverlayPath} SQL-only extension ${sqlName} must not declare iOS dependencies`);
-    }
-    const dependencies = canonicalStringList(
-      row["selected-extension-dependencies"],
-      `${metadataPath} extension ${sqlName} selected-extension-dependencies`,
-    );
-    if (dependencies.includes(sqlName)) {
-      fail(`${metadataPath} extension ${sqlName} must not depend on itself`);
-    }
-    const canonical = {
-      sqlName,
-      createsExtension: row["creates-extension"],
-      dependencies,
-      dataFiles: canonicalStringList(
-        row["runtime-share-data-files"],
-        `${metadataPath} extension ${sqlName} runtime-share-data-files`,
-        safeArchiveMember,
-      ),
-      extensionSqlFileNames: canonicalStringList(
-        row["extension-sql-file-names"],
-        `${metadataPath} extension ${sqlName} extension-sql-file-names`,
-        sqlFileName,
-      ),
-      extensionSqlFilePrefixes: canonicalStringList(
-        row["extension-sql-file-prefixes"],
-        `${metadataPath} extension ${sqlName} extension-sql-file-prefixes`,
-        sqlFilePrefix,
-      ),
-      nativeModuleStem,
-      canonicalIosNativeDependencies: generatedDependencies,
-      sharedPreloadLibraries: canonicalStringList(
-        row["shared-preload-libraries"],
-        `${metadataPath} extension ${sqlName} shared-preload-libraries`,
-      ),
-    };
-    const owner = products.get(product) ?? {
-      artifactProduct: product,
-      releaseProduct,
-      members: new Map(),
-      postgresMajor,
-      sqlNames: [],
-    };
-    if (owner.postgresMajor !== postgresMajor) {
-      fail(`${metadataPath} product ${product} spans multiple PostgreSQL majors`);
-    }
-    if (owner.releaseProduct !== releaseProduct) {
-      fail(`${metadataPath} artifact product ${product} spans multiple native release owners`);
-    }
-    owner.sqlNames.push(sqlName);
-    owner.members.set(sqlName, canonical);
-    products.set(product, owner);
-  }
-  for (const owner of products.values()) {
-    owner.sqlNames.sort(compareText);
-  }
-  return { nativeRuntimeVersion, products, wasixRuntimeVersion };
-}
-
-function validateCompatibility(manifest, manifestPath, repositoryContract) {
-  const owner = repositoryContract.products.get(manifest.product);
-  if (owner === undefined) {
-    fail(`${manifestPath} product ${manifest.product} has no generated React Native extension owner`);
-  }
-  const expected = {
-    extensionRuntimeContract: "src/shared/extension-runtime-contract/contract.toml",
-    nativeRuntimeProduct: "liboliphaunt-native",
-    nativeRuntimeVersion: repositoryContract.nativeRuntimeVersion,
-    postgresMajor: owner.postgresMajor,
-    wasixRuntimeProduct: "liboliphaunt-wasix",
-    wasixRuntimeVersion: repositoryContract.wasixRuntimeVersion,
-  };
-  if (!isDeepStrictEqual(manifest.compatibility, expected)) {
-    fail(`${manifestPath} compatibility metadata must exactly match the generated runtime contract`);
-  }
-  return owner;
-}
-
-function validateIdentity(asset, context) {
-  if (asset.kind === "runtime") {
-    if (asset.identity !== null) {
-      fail(`${context} runtime identity must be null`);
-    }
-    return;
-  }
-  if (asset.kind === "ios-dependency-xcframework") {
-    if (typeof asset.identity !== "string" || asset.identity.length === 0) {
-      fail(`${context} iOS dependency identity must be a non-empty string`);
-    }
-    return;
-  }
-  if (asset.kind === "ios-xcframework") {
-    if (!(asset.identity === null || typeof asset.identity === "string" && asset.identity.length > 0)) {
-      fail(`${context} iOS XCFramework identity must be null or a non-empty string`);
-    }
-    return;
-  }
-  if (asset.identity !== null) {
-    fail(`${context} identity must be null for kind=${asset.kind}`);
-  }
-}
-
-function validateIosRegistration(value, expected, context) {
-  if (!isObject(value)) {
-    fail(`${context} must contain build-derived iOS registration metadata`);
-  }
-  requireExactKeys(
-    value,
-    new Set(["initSymbol", "magicSymbol", "nativeModuleStem", "schema", "sqlName", "symbols"]),
-    context,
-  );
-  const prefix = `oliphaunt_static_${expected.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`;
-  if (
-    value.schema !== "oliphaunt-ios-extension-registration-v1"
-    || value.sqlName !== expected.sqlName
-    || value.nativeModuleStem !== expected.nativeModuleStem
-    || value.magicSymbol !== `${prefix}_Pg_magic_func`
-    || ![null, `${prefix}__PG_init`].includes(value.initSymbol)
-    || !C_IDENTIFIER.test(value.magicSymbol)
-    || !(value.initSymbol === null || C_IDENTIFIER.test(value.initSymbol))
-    || !Array.isArray(value.symbols)
-  ) {
-    fail(`${context} does not match canonical native module identity ${expected.sqlName}/${expected.nativeModuleStem}`);
-  }
-  const normalized = value.symbols.map((row, index) => {
-    requireExactKeys(row, new Set(["address", "name"]), `${context}.symbols[${index}]`);
-    if (!C_IDENTIFIER.test(row.name ?? "") || !C_IDENTIFIER.test(row.address ?? "")) {
-      fail(`${context}.symbols[${index}] must map canonical C identifiers`);
-    }
-    return `${row.name}\0${row.address}`;
-  });
-  if (
-    new Set(value.symbols.map(({ name }) => name)).size !== value.symbols.length
-    || !isDeepStrictEqual(normalized, [...normalized].sort(compareText))
-  ) {
-    fail(`${context}.symbols must be sorted with unique public names`);
-  }
-}
-
-function expectedMobileRoles(member, target) {
-  const roles = ["runtime:"];
-  if (target === "ios-xcframework" && member.nativeModuleStem !== null) {
-    roles.push(`ios-xcframework:${member.nativeModuleStem}`);
-    roles.push(...member.iosNativeDependencies.map((dependency) =>
-      `ios-dependency-xcframework:${dependency}`));
-  }
-  return roles.sort(compareText);
-}
-
-function validateExactMobileRoles(member, target, assets, context) {
-  const actual = assets.map((asset, index) => {
-    const assetContext = `${context} asset ${index}`;
-    safeComponent(asset.name, `${assetContext} name`);
-    validateDigestRow(asset, assetContext);
-    if (asset.family !== "native" || asset.target !== target) {
-      fail(`${assetContext} must belong to native/${target}`);
-    }
-    validateIdentity(asset, assetContext);
-    return `${asset.kind}:${asset.identity ?? ""}`;
-  }).sort(compareText);
-  const expected = expectedMobileRoles(member, target);
-  if (!isDeepStrictEqual(actual, expected)) {
-    fail(
-      `${context} mobile artifact roles are not exact and dependency-closed: ` +
-      `expected=${JSON.stringify(expected)}, actual=${JSON.stringify(actual)}`,
-    );
-  }
-}
-
-function validateMemberContract(member, expected, context) {
-  for (const field of [
-    "sqlName",
-    "createsExtension",
-    "dependencies",
-    "dataFiles",
-    "extensionSqlFileNames",
-    "extensionSqlFilePrefixes",
-    "nativeModuleStem",
-    "sharedPreloadLibraries",
-  ]) {
-    if (!isDeepStrictEqual(member[field], expected[field])) {
-      fail(`${context}.${field} must exactly match generated React Native extension metadata`);
-    }
-  }
-  if (!Array.isArray(member.assets)) fail(`${context}.assets must be an array`);
-  try {
-    assertWasixExtensionMemberInstall(member, { label: context });
-  } catch (error) {
-    fail(error instanceof Error ? error.message : String(error));
-  }
-  const mobileGroups = new Map();
-  for (const [index, asset] of member.assets.entries()) {
-    if (!isObject(asset) || !MOBILE_TARGETS.has(asset.target)) continue;
-    if (asset.family !== "native") {
-      fail(`${context}.assets[${index}] mobile target ${asset.target} must use the native family`);
-    }
-    const group = mobileGroups.get(asset.target) ?? [];
-    group.push(asset);
-    mobileGroups.set(asset.target, group);
-  }
-  const stagesIos = mobileGroups.has("ios-xcframework");
-  const expectedIosDependencies = stagesIos && expected.nativeModuleStem !== null
-    ? expected.canonicalIosNativeDependencies
-    : [];
-  if (!isDeepStrictEqual(member.iosNativeDependencies, expectedIosDependencies)) {
-    fail(`${context}.iosNativeDependencies must exactly match the canonical staged iOS dependency closure`);
-  }
-  if (expected.nativeModuleStem === null || !stagesIos) {
-    if (member.iosRegistration !== null) {
-      fail(`${context}.iosRegistration must be null without a staged native iOS module`);
-    }
-  } else {
-    validateIosRegistration(member.iosRegistration, expected, `${context}.iosRegistration`);
-  }
-  for (const [target, assets] of mobileGroups) {
-    validateExactMobileRoles(member, target, assets, `${context} ${target}`);
-  }
-}
-
-async function manifestPaths(artifactRoot, repositoryContract) {
-  return [...repositoryContract.products.values()]
-    .map((owner) => join(
-      artifactRoot,
-      ...(owner.releaseProduct === owner.artifactProduct
-        ? [owner.artifactProduct]
-        : [owner.releaseProduct, owner.artifactProduct]),
-      "extension-artifacts.json",
-    ))
-    .filter((file) => isFile(file))
-    .sort(compareText);
-}
-
-function assetMatches(asset, assetKind, assetTarget) {
-  if (!isObject(asset) || asset.family !== "native") {
-    return false;
-  }
-  if (assetTarget !== "*" && asset.target !== assetTarget) {
-    return false;
-  }
-  return asset.kind === assetKind;
-}
-
-function validateManifestEnvelope(manifest, manifestPath, repositoryContract, members) {
-  safeComponent(manifest.product, `${manifestPath} product`);
-  if (!STABLE_SEMVER.test(manifest.version ?? "")) {
-    fail(`${manifestPath} version must be stable SemVer`);
-  }
-  const owner = validateCompatibility(manifest, manifestPath, repositoryContract);
-  if (owner.releaseProduct !== owner.artifactProduct) {
-    if (manifest.releaseProduct !== owner.releaseProduct || manifest.family !== "native") {
-      fail(`${manifestPath} must be owned by ${owner.releaseProduct}/native`);
-    }
-    if (manifest.version !== repositoryContract.nativeRuntimeVersion) {
-      fail(`${manifestPath} version must match its native release owner`);
-    }
-  }
-  const actualSqlNames = members.map((member) => member?.sqlName);
-  if (new Set(actualSqlNames).size !== actualSqlNames.length) {
-    fail(`${manifestPath} repeats an extension SQL identity`);
-  }
-  if (!isDeepStrictEqual(actualSqlNames, owner.sqlNames)) {
-    fail(
-      `${manifestPath} member set must exactly match generated owner ${manifest.product}: `
-      + `expected=${JSON.stringify(owner.sqlNames)}, actual=${JSON.stringify(actualSqlNames)}`,
-    );
-  }
-  for (const [index, member] of members.entries()) {
-    const expected = owner.members.get(member.sqlName);
-    if (expected === undefined) {
-      fail(`${manifestPath} extension member ${index} has no generated React Native owner metadata`);
-    }
-    validateMemberContract(member, expected, `${manifestPath} extension member ${member.sqlName}`);
-  }
-}
-
-function manifestMembers(manifest, manifestPath, repositoryContract) {
-  if (!isObject(manifest)) {
-    fail(`${manifestPath} must contain an extension artifact manifest object`);
-  }
-  let members;
-  if (manifest.schema === "oliphaunt-extension-ci-artifacts-v1") {
-    requireExactKeys(
-      manifest,
-      manifestEnvelopeKeys(DIRECT_MANIFEST_KEYS, manifest, repositoryContract),
-      manifestPath,
-    );
-    if (!Array.isArray(manifest.assets)) {
-      fail(`${manifestPath} must declare an assets array`);
-    }
-    for (const [index, asset] of manifest.assets.entries()) {
-      requireExactKeys(asset, DIRECT_ASSET_KEYS, `${manifestPath} asset ${index}`);
-    }
-    members = [manifest];
-  } else if (manifest.schema === "oliphaunt-extension-ci-artifacts-v2") {
-    requireExactKeys(
-      manifest,
-      manifestEnvelopeKeys(BUNDLE_MANIFEST_KEYS, manifest, repositoryContract),
-      manifestPath,
-    );
-    if (!Array.isArray(manifest.extensions) || manifest.extensions.length === 0) {
-      fail(`${manifestPath} must declare a non-empty extensions array`);
-    }
-    for (const [index, member] of manifest.extensions.entries()) {
-      requireExactKeys(member, EXTENSION_MEMBER_KEYS, `${manifestPath} extension member ${index}`);
-      if (!Array.isArray(member.assets)) {
-        fail(`${manifestPath} extension member ${index} must declare an assets array`);
-      }
-      for (const [assetIndex, asset] of member.assets.entries()) {
-        requireExactKeys(
-          asset,
-          BUNDLE_MEMBER_ASSET_KEYS,
-          `${manifestPath} extension member ${index} asset ${assetIndex}`,
-        );
-      }
-    }
-    if (!Array.isArray(manifest.carrierAssets)) {
-      fail(`${manifestPath} must declare a carrierAssets array`);
-    }
-    for (const [index, carrier] of manifest.carrierAssets.entries()) {
-      requireExactKeys(carrier, BUNDLE_CARRIER_ASSET_KEYS, `${manifestPath} aggregate carrier ${index}`);
-    }
-    members = manifest.extensions;
-  } else {
-    fail(`${manifestPath} has unsupported extension artifact schema ${JSON.stringify(manifest.schema)}`);
-  }
-  validateManifestEnvelope(manifest, manifestPath, repositoryContract, members);
-  return members;
-}
-
-function validateDirectAsset(asset, entry, sqlName) {
-  const context = `${entry.manifestPath} ${asset.kind} asset for ${sqlName}`;
-  requireExactKeys(asset, DIRECT_ASSET_KEYS, context);
-  safeComponent(asset.name, `${context} name`);
-  validateDigestRow(asset, context);
-  validateIdentity(asset, context);
-  validatePublishedPath(asset.path, asset.name, context);
-}
-
-function validateBundleCarrier(manifest, manifestPath, carrier) {
-  const context = `${manifestPath} aggregate carrier`;
-  requireExactKeys(carrier, BUNDLE_CARRIER_ASSET_KEYS, context);
-  safeComponent(carrier.name, `${context} name`);
-  safeComponent(carrier.target, `${context} target`);
-  validateDigestRow(carrier, `${context} ${carrier.name}`);
-  if (
-    !Number.isSafeInteger(carrier.memberCount) || carrier.memberCount <= 0
-    || carrier.memberCount > MAX_BUNDLE_MEMBERS
-  ) {
-    fail(`${context} ${carrier.name} must declare a bounded positive memberCount`);
-  }
-  if (carrier.kind !== "extension-bundle" || carrier.family !== "native") {
-    fail(`${context} ${carrier.name} must be a native extension-bundle`);
-  }
-  if (!MOBILE_TARGETS.has(carrier.target)) {
-    fail(`${context} ${carrier.name} has unsupported mobile target ${JSON.stringify(carrier.target)}`);
-  }
-  const expectedName = `${manifest.product}-${manifest.version}-${carrier.family}-${carrier.target}-bundle.tar.gz`;
-  if (carrier.name !== expectedName) {
-    fail(`${context} ${carrier.name} must use canonical name ${expectedName}`);
-  }
-  validatePublishedPath(carrier.path, carrier.name, `${context} ${carrier.name}`);
-}
-
-function bundleCarrierFor(entry, asset) {
-  const carriers = Array.isArray(entry.manifest.carrierAssets)
-    ? entry.manifest.carrierAssets.filter((carrier) =>
-        isObject(carrier)
-        && carrier.family === asset.family
-        && carrier.target === asset.target
-        && carrier.kind === "extension-bundle"
-      )
-    : [];
-  if (carriers.length !== 1) {
-    fail(
-      `${entry.manifestPath} must declare exactly one native extension-bundle carrier for ${asset.target}, got ${carriers.length}`,
-    );
-  }
-  const carrier = carriers[0];
-  validateBundleCarrier(entry.manifest, entry.manifestPath, carrier);
-  if (asset.carrierAsset !== carrier.name) {
-    fail(`${entry.manifestPath} ${entry.sqlName} asset references the wrong aggregate carrier`);
-  }
-  return carrier;
-}
-
-function validateBundleMemberAsset({ manifestPath, carrier, member, asset }) {
-  const context = `${manifestPath} aggregate member ${member.sqlName}/${asset?.kind ?? "unknown"}`;
-  requireExactKeys(asset, BUNDLE_MEMBER_ASSET_KEYS, context);
-  safeComponent(asset.name, `${context} name`);
-  validateDigestRow(asset, context);
-  if (asset.family !== carrier.family || asset.target !== carrier.target) {
-    fail(`${context} must match carrier ${carrier.family}/${carrier.target}`);
-  }
-  const allowedKinds = carrier.target === "ios-xcframework"
-    ? new Set(["runtime", "ios-xcframework", "ios-dependency-xcframework"])
-    : new Set(["runtime"]);
-  if (!allowedKinds.has(asset.kind)) {
-    fail(`${context} has invalid kind for ${carrier.target}`);
-  }
-  validateIdentity(asset, context);
-  if (asset.carrierAsset !== carrier.name) {
-    fail(`${context} references the wrong aggregate carrier`);
-  }
-  const expectedRoot = carrier.name.replace(/\.tar\.gz$/u, "");
-  const expectedMemberPath = `extensions/${member.sqlName}/${asset.name}`;
-  if (asset.carrierRoot !== expectedRoot || asset.memberPath !== expectedMemberPath) {
-    fail(`${context} has a noncanonical nested locator`);
-  }
-  safeArchiveMember(`${asset.carrierRoot}/${asset.memberPath}`, `${context} locator`);
-  return {
-    sqlName: member.sqlName,
-    kind: asset.kind,
-    identity: asset.identity,
-    path: asset.memberPath,
-    sha256: asset.sha256,
-    bytes: asset.bytes,
-  };
-}
-
-function expectedBundleManifest(manifest, manifestPath, carrier) {
-  const rows = [];
-  const allSqlNames = [];
-  const identities = new Set();
-  const roles = new Set();
-  const memberPaths = new Set();
-  for (const member of manifest.extensions) {
-    if (!isObject(member)) {
-      fail(`${manifestPath} aggregate member must be an object`);
-    }
-    const sqlName = safeComponent(member.sqlName, `${manifestPath} aggregate member sqlName`);
-    allSqlNames.push(sqlName);
-    const assets = Array.isArray(member.assets) ? member.assets : [];
-    const carrierAssets = assets.filter((asset) =>
-      isObject(asset) && asset.family === carrier.family && asset.target === carrier.target
-    );
-    if (carrierAssets.length === 0) {
-      fail(`${manifestPath} aggregate carrier ${carrier.name} is missing exact member ${sqlName}`);
-    }
-    validateExactMobileRoles(
-      member,
-      carrier.target,
-      carrierAssets,
-      `${manifestPath} aggregate carrier ${carrier.name} member ${sqlName}`,
-    );
-    for (const asset of carrierAssets) {
-      const row = validateBundleMemberAsset({ manifestPath, carrier, member, asset });
-      const identityKey = `${row.sqlName}\0${row.kind}\0${row.path}`;
-      if (identities.has(identityKey)) {
-        fail(`${manifestPath} aggregate carrier ${carrier.name} repeats member identity ${sqlName}/${row.kind}/${row.path}`);
-      }
-      identities.add(identityKey);
-      const roleKey = `${row.sqlName}\0${row.kind}\0${row.identity ?? ""}`;
-      if (roles.has(roleKey)) {
-        fail(`${manifestPath} aggregate carrier ${carrier.name} repeats member role ${sqlName}/${row.kind}/${row.identity ?? ""}`);
-      }
-      roles.add(roleKey);
-      if (memberPaths.has(row.path)) {
-        fail(`${manifestPath} aggregate carrier ${carrier.name} repeats nested member path ${row.path}`);
-      }
-      memberPaths.add(row.path);
-      rows.push(row);
-    }
-    for (const asset of assets) {
-      if (isObject(asset) && asset.carrierAsset === carrier.name && !carrierAssets.includes(asset)) {
-        fail(`${manifestPath} aggregate carrier ${carrier.name} contains a member with the wrong family/target`);
-      }
-    }
-  }
-  if (new Set(allSqlNames).size !== allSqlNames.length) {
-    fail(`${manifestPath} aggregate manifest repeats an extension SQL identity`);
-  }
-  if (carrier.memberCount !== allSqlNames.length) {
-    fail(`${manifestPath} aggregate carrier ${carrier.name} must declare memberCount=${allSqlNames.length}`);
-  }
-  rows.sort((left, right) => compareText(
-    `${left.sqlName}\0${left.kind}\0${left.identity ?? ""}`,
-    `${right.sqlName}\0${right.kind}\0${right.identity ?? ""}`,
-  ));
-  const legal = extensionCarrierLegalContract(
-    manifest.product,
-    [...allSqlNames].sort(compareText),
-    { family: carrier.family, target: carrier.target },
-  );
-  return {
-    schema: "oliphaunt-extension-bundle-v1",
-    product: manifest.product,
-    version: manifest.version,
-    compatibility: manifest.compatibility,
-    family: carrier.family,
-    target: carrier.target,
-    licenseProfile: legal.profile,
-    licenseFiles: legal.licenseFiles,
-    members: rows,
-  };
-}
-
-function runTar(args, context) {
-  const result = captureCommandOutput("tar", args, {
-    label: context,
-    maxOutputBytes: 16 * 1024 * 1024,
-  });
-  if (result.error) {
-    fail(`${context} failed to start: ${result.error.message}`);
-  }
-  if (result.status !== 0) {
-    const detail = String(result.stderr ?? result.stdout ?? "").trim();
-    fail(`${context} failed${detail ? `: ${detail}` : ""}`);
-  }
-  return String(result.stdout ?? "");
-}
-
-function sortValue(value) {
-  if (Array.isArray(value)) {
-    return value.map(sortValue);
-  }
-  if (isObject(value)) {
-    return Object.fromEntries(
-      Object.keys(value).sort(compareText).map((key) => [key, sortValue(value[key])]),
-    );
-  }
-  return value;
-}
-
-function canonicalJson(value) {
-  return `${JSON.stringify(sortValue(value), null, 2)}\n`;
-}
-
-function tarString(header, offset, length, carrierPath) {
-  const field = header.subarray(offset, offset + length);
-  const end = field.indexOf(0);
-  try {
-    return new TextDecoder("utf-8", { fatal: true }).decode(field.subarray(0, end < 0 ? field.length : end));
-  } catch {
-    fail(`${carrierPath} contains a non-UTF-8 ustar header field`);
-  }
-}
-
-function tarOctal(header, offset, length, field, carrierPath) {
-  const value = header.subarray(offset, offset + length).toString("ascii").replaceAll("\0", "").trim();
-  if (!/^[0-7]+$/u.test(value)) {
-    fail(`${carrierPath} has invalid ustar ${field}`);
-  }
-  const parsed = Number.parseInt(value, 8);
-  if (!Number.isSafeInteger(parsed) || parsed < 0) {
-    fail(`${carrierPath} has unsafe ustar ${field}`);
-  }
-  return parsed;
-}
-
-function gzipHeader(carrierPath) {
-  const header = Buffer.alloc(10);
-  let descriptor;
-  let bytes;
-  try {
-    descriptor = openSync(carrierPath, "r");
-    bytes = readSync(descriptor, header, 0, header.length, 0);
-  } finally {
-    if (descriptor !== undefined) {
-      closeSync(descriptor);
-    }
-  }
-  const canonical = Buffer.from([0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03]);
-  if (bytes !== header.length || !header.equals(canonical)) {
-    fail(`${carrierPath} must use the canonical gzip method, flags, mtime, XFL, and OS header`);
-  }
-}
-
-async function verifyCanonicalArchive(carrierPath, expectedFiles) {
-  gzipHeader(carrierPath);
-  const expectedNames = [...expectedFiles.keys()].sort(compareText);
-  if (expectedNames.length > MAX_BUNDLE_ARCHIVE_MEMBERS) {
-    fail(`${carrierPath} exceeds the maximum supported physical archive member count`);
-  }
-  const expectedTarBytes = [...expectedFiles.values()].reduce(
-    (total, file) => total + 512 + Math.ceil(file.bytes / 512) * 512,
-    1024,
-  );
-  if (!Number.isSafeInteger(expectedTarBytes) || expectedTarBytes > MAX_BUNDLE_EXPANDED_BYTES) {
-    fail(`${carrierPath} declared ustar size exceeds the supported expanded bundle limit`);
-  }
-  const actualNames = [];
-  let buffer = Buffer.alloc(0);
-  let currentEntry = "archive header";
-  let currentExpected;
-  let payloadDigest;
-  let payloadRemaining = 0;
-  let paddingRemaining = 0;
-  let terminated = false;
-  let totalBytes = 0;
-  let zeroBlocks = 0;
-  try {
-    const stream = createReadStream(carrierPath).pipe(createGunzip());
-    for await (const chunk of stream) {
-      totalBytes += chunk.length;
-      if (totalBytes > expectedTarBytes) {
-        fail(`${carrierPath} expands beyond its exact declared ustar size`);
-      }
-      buffer = buffer.length === 0 ? Buffer.from(chunk) : Buffer.concat([buffer, chunk]);
-      while (buffer.length > 0) {
-        if (terminated) {
-          if (!buffer.every((value) => value === 0)) {
-            fail(`${carrierPath} has data after its ustar end marker`);
-          }
-          buffer = Buffer.alloc(0);
-          break;
-        }
-        if (payloadRemaining > 0) {
-          const consumed = Math.min(payloadRemaining, buffer.length);
-          payloadDigest.update(buffer.subarray(0, consumed));
-          payloadRemaining -= consumed;
-          buffer = buffer.subarray(consumed);
-          if (payloadRemaining === 0) {
-            const actualSha256 = payloadDigest.digest("hex");
-            if (actualSha256 !== currentExpected.sha256) {
-              fail(`${carrierPath} member ${currentEntry} does not match its canonical SHA-256`);
-            }
-            payloadDigest = undefined;
-          }
-          continue;
-        }
-        if (paddingRemaining > 0) {
-          const consumed = Math.min(paddingRemaining, buffer.length);
-          if (!buffer.subarray(0, consumed).every((value) => value === 0)) {
-            fail(`${carrierPath} member ${currentEntry} has nonzero ustar padding`);
-          }
-          paddingRemaining -= consumed;
-          buffer = buffer.subarray(consumed);
-          continue;
-        }
-        if (buffer.length < 512) {
-          break;
-        }
-        const header = buffer.subarray(0, 512);
-        buffer = buffer.subarray(512);
-        if (header.every((value) => value === 0)) {
-          zeroBlocks += 1;
-          if (zeroBlocks === 2) {
-            terminated = true;
-          }
-          continue;
-        }
-        if (zeroBlocks > 0) {
-          fail(`${carrierPath} has an incomplete ustar end marker`);
-        }
-        if (
-          !header.subarray(257, 263).equals(Buffer.from("ustar\0"))
-          || !header.subarray(263, 265).equals(Buffer.from("00"))
-        ) {
-          fail(`${carrierPath} must use canonical POSIX ustar headers`);
-        }
-        const checksumField = header.subarray(148, 156).toString("latin1");
-        if (!/^[0-7]{6}\0 $/u.test(checksumField)) {
-          fail(`${carrierPath} has a noncanonical ustar checksum field`);
-        }
-        const expectedChecksum = tarOctal(header, 148, 8, "checksum", carrierPath);
-        let actualChecksum = 0;
-        for (let index = 0; index < 512; index += 1) {
-          actualChecksum += index >= 148 && index < 156 ? 0x20 : header[index];
-        }
-        if (expectedChecksum !== actualChecksum) {
-          fail(`${carrierPath} has an invalid ustar header checksum`);
-        }
-        const name = tarString(header, 0, 100, carrierPath);
-        const prefix = tarString(header, 345, 155, carrierPath);
-        const archiveName = safeArchiveMember(prefix ? `${prefix}/${name}` : name, `${carrierPath} member`);
-        currentEntry = JSON.stringify(archiveName);
-        if (header[156] !== 0x30) {
-          fail(`${carrierPath} member ${archiveName} must be a canonical regular file`);
-        }
-        const mode = tarOctal(header, 100, 8, `mode for ${currentEntry}`, carrierPath);
-        const uid = tarOctal(header, 108, 8, `uid for ${currentEntry}`, carrierPath);
-        const gid = tarOctal(header, 116, 8, `gid for ${currentEntry}`, carrierPath);
-        const size = tarOctal(header, 124, 12, `size for ${currentEntry}`, carrierPath);
-        const mtime = tarOctal(header, 136, 12, `mtime for ${currentEntry}`, carrierPath);
-        if (mode !== 0o644 || uid !== 0 || gid !== 0 || mtime !== 0) {
-          fail(`${carrierPath} member ${archiveName} must use mode=0644 uid=0 gid=0 mtime=0`);
-        }
-        if (
-          !header.subarray(157, 257).every((value) => value === 0)
-          || !header.subarray(265, 345).every((value) => value === 0)
-          || !header.subarray(500, 512).every((value) => value === 0)
-        ) {
-          fail(`${carrierPath} member ${archiveName} has noncanonical ustar metadata`);
-        }
-        currentExpected = expectedFiles.get(archiveName);
-        if (currentExpected === undefined || size !== currentExpected.bytes) {
-          fail(`${carrierPath} member ${archiveName} is undeclared or has the wrong ustar size`);
-        }
-        if (actualNames.includes(archiveName)) {
-          fail(`${carrierPath} contains duplicate bundle member ${archiveName}`);
-        }
-        actualNames.push(archiveName);
-        payloadRemaining = size;
-        payloadDigest = createHash("sha256");
-        if (payloadRemaining === 0) {
-          const actualSha256 = payloadDigest.digest("hex");
-          if (actualSha256 !== currentExpected.sha256) {
-            fail(`${carrierPath} member ${currentEntry} does not match its canonical SHA-256`);
-          }
-          payloadDigest = undefined;
-        }
-        paddingRemaining = (512 - size % 512) % 512;
-      }
-    }
-  } catch (error) {
-    if (error instanceof CliFailure) {
-      throw error;
-    }
-    fail(`${carrierPath} is not a readable canonical gzip/ustar archive: ${error.message}`);
-  }
-  if (payloadRemaining > 0 || paddingRemaining > 0) {
-    fail(`${carrierPath} has a truncated member ${currentEntry}`);
-  }
-  if (buffer.length > 0) {
-    fail(`${carrierPath} has a truncated ustar header`);
-  }
-  if (!terminated || totalBytes !== expectedTarBytes || totalBytes % 512 !== 0) {
-    fail(`${carrierPath} must end at its exact two-block ustar marker`);
-  }
-  if (!isDeepStrictEqual(actualNames, expectedNames)) {
-    fail(`${carrierPath} contents do not exactly match its sorted declared bundle members`);
-  }
-}
-
-async function verifyFrozenFile(file, row, context) {
-  if (!isFile(file)) {
-    fail(`${context} is missing or is not a regular non-symlink file`);
-  }
-  if (statSync(file).size !== row.bytes || await sha256File(file) !== row.sha256) {
-    fail(`${context} does not match its frozen size/digest`);
-  }
-}
-
-function cacheMetadata(file) {
-  try {
-    return lstatSync(file);
-  } catch (error) {
-    if (error?.code === "ENOENT") return undefined;
-    throw error;
-  }
-}
-
-function requireCacheDirectory(materializeRoot, directory) {
-  const root = resolve(materializeRoot);
-  const target = resolve(directory);
-  const suffix = relative(root, target);
-  if (suffix === ".." || suffix.startsWith(`..${sep}`)) {
-    fail(`cache directory escapes materialization root: ${target}`);
-  }
-
-  mkdirSync(root, { recursive: true, mode: 0o700 });
-  const rootMetadata = cacheMetadata(root);
-  if (rootMetadata?.isSymbolicLink() || rootMetadata?.isDirectory() !== true) {
-    fail(`materialization cache root must be a real directory, not a symlink: ${root}`);
-  }
-
-  let current = root;
-  for (const component of suffix.split(sep).filter(Boolean)) {
-    current = join(current, component);
-    let metadata = cacheMetadata(current);
-    if (metadata === undefined) {
-      try {
-        mkdirSync(current, { mode: 0o700 });
-      } catch (error) {
-        if (error?.code !== "EEXIST") throw error;
-      }
-      metadata = cacheMetadata(current);
-    }
-    if (metadata?.isSymbolicLink() || metadata?.isDirectory() !== true) {
-      fail(`materialization cache path component must be a real directory, not a symlink: ${current}`);
-    }
-  }
-  return target;
-}
-
-async function installCacheFile(source, destination, row, context, materializeRoot) {
-  requireCacheDirectory(materializeRoot, dirname(destination));
-  const destinationMetadata = cacheMetadata(destination);
-  if (destinationMetadata?.isSymbolicLink()) {
-    fail(`materialization cache destination must not be a symlink: ${destination}`);
-  }
-  if (destinationMetadata !== undefined && !destinationMetadata.isFile()) {
-    fail(`materialization cache destination must be a regular file: ${destination}`);
-  }
-  if (destinationMetadata?.isFile()) {
-    if (statSync(destination).size === row.bytes && await sha256File(destination) === row.sha256) {
-      return destination;
-    }
-    rmSync(destination, { force: true });
-  }
-  const beforeRename = cacheMetadata(destination);
-  if (beforeRename?.isSymbolicLink() || beforeRename !== undefined) {
-    fail(`materialization cache destination changed while being prepared: ${destination}`);
-  }
-  renameSync(source, destination);
-  chmodSync(destination, 0o644);
-  await verifyFrozenFile(destination, row, `${context} after cache materialization`);
-  return destination;
-}
-
-async function materializeDirectAsset(entry, asset, source, materializeRoot) {
-  const safeMaterializeRoot = requireCacheDirectory(materializeRoot, materializeRoot);
-  const destination = join(
-    safeMaterializeRoot,
-    entry.manifest.product,
-    "direct",
-    asset.family,
-    asset.target,
-    asset.sha256,
-    entry.sqlName,
-    asset.name,
-  );
-  const stage = mkdtempSync(join(safeMaterializeRoot, ".direct-"));
-  try {
-    const snapshot = join(stage, asset.name);
-    copyFileSync(source, snapshot);
-    chmodSync(snapshot, 0o600);
-    await verifyFrozenFile(snapshot, asset, `${entry.manifestPath} immutable snapshot for ${entry.sqlName}`);
-    await verifyFrozenFile(source, asset, `${entry.manifestPath} direct source for ${entry.sqlName} after snapshot`);
-    return await installCacheFile(
-      snapshot,
-      destination,
-      asset,
-      `${entry.manifestPath} direct asset for ${entry.sqlName}`,
-      safeMaterializeRoot,
-    );
-  } finally {
-    rmSync(stage, { recursive: true, force: true });
-  }
-}
-
-async function materializeBundlePlan(plan, materializeRoot) {
-  const { manifest, manifestPath, carrier } = plan;
-  const expected = expectedBundleManifest(manifest, manifestPath, carrier);
-  const expectedText = canonicalJson(expected);
-  const carrierRoot = carrier.name.replace(/\.tar\.gz$/u, "");
-  const carrierPath = join(dirname(manifestPath), "release-assets", carrier.name);
-  await verifyFrozenFile(carrierPath, carrier, `${manifestPath} aggregate carrier ${carrier.name}`);
-  const safeMaterializeRoot = requireCacheDirectory(materializeRoot, materializeRoot);
-  const stage = mkdtempSync(join(safeMaterializeRoot, ".extract-"));
-  try {
-    // All structural validation and extraction operate on this private verified
-    // snapshot, so a mutable release-assets path cannot be swapped between the
-    // validation and extraction opens.
-    const carrierSnapshot = join(stage, carrier.name);
-    copyFileSync(carrierPath, carrierSnapshot);
-    chmodSync(carrierSnapshot, 0o600);
-    await verifyFrozenFile(
-      carrierSnapshot,
-      carrier,
-      `${manifestPath} aggregate carrier ${carrier.name} immutable snapshot`,
-    );
-    await verifyFrozenFile(
-      carrierPath,
-      carrier,
-      `${manifestPath} aggregate carrier ${carrier.name} after snapshot`,
-    );
-    const sqlNames = [...new Set(expected.members.map((member) => member.sqlName))]
-      .sort(compareText);
-    const legalFiles = extensionCarrierLegalFileInventory(manifest.product, sqlNames, {
-      family: carrier.family,
-      target: carrier.target,
-    });
-    const expectedFiles = new Map();
-    const addExpectedFile = (name, file) => {
-      if (expectedFiles.has(name)) {
-        fail(`${manifestPath} aggregate carrier ${carrier.name} repeats expected member ${name}`);
-      }
-      expectedFiles.set(name, file);
-    };
-    const expectedBytes = Buffer.from(expectedText);
-    addExpectedFile(`${carrierRoot}/bundle-manifest.json`, {
-      bytes: expectedBytes.length,
-      sha256: createHash("sha256").update(expectedBytes).digest("hex"),
-    });
-    for (const member of expected.members) {
-      addExpectedFile(`${carrierRoot}/${member.path}`, member);
-    }
-    for (const legalFile of legalFiles) {
-      addExpectedFile(`${carrierRoot}/${legalFile.path}`, legalFile);
-    }
-    await verifyCanonicalArchive(carrierSnapshot, expectedFiles);
-    const requestedNames = [
-      `${carrierRoot}/bundle-manifest.json`,
-      ...plan.selected.map(({ asset }) => `${asset.carrierRoot}/${asset.memberPath}`),
-    ].sort(compareText);
-    runTar(
-      ["-xf", carrierSnapshot, "-C", stage, ...new Set(requestedNames)],
-      `extract selected members from ${carrierSnapshot}`,
-    );
-    await verifyFrozenFile(
-      carrierSnapshot,
-      carrier,
-      `${manifestPath} aggregate carrier ${carrier.name} immutable snapshot after extraction`,
-    );
-
-    const embeddedPath = join(stage, carrierRoot, "bundle-manifest.json");
-    if (!isFile(embeddedPath)) {
-      fail(`${carrierPath} is missing a regular bundle-manifest.json`);
-    }
-    let embedded;
-    try {
-      embedded = JSON.parse(readFileSync(embeddedPath, "utf8"));
-    } catch (error) {
-      fail(`${carrierPath} has invalid bundle-manifest.json: ${error.message}`);
-    }
-    if (readFileSync(embeddedPath, "utf8") !== expectedText || !isDeepStrictEqual(embedded, expected)) {
-      fail(`${carrierPath} bundle-manifest.json does not exactly describe its product, compatibility, target, and nested members`);
-    }
-
-    for (const selected of plan.selected) {
-      const source = join(stage, selected.asset.carrierRoot, ...selected.asset.memberPath.split("/"));
-      await verifyFrozenFile(
-        source,
-        selected.asset,
-        `${carrierPath} nested member ${selected.asset.carrierRoot}/${selected.asset.memberPath}`,
-      );
-      const destination = join(
-        safeMaterializeRoot,
-        manifest.product,
-        carrier.family,
-        carrier.target,
-        carrier.sha256,
-        selected.sqlName,
-        selected.asset.name,
-      );
-      selected.destination = await installCacheFile(
-        source,
-        destination,
-        selected.asset,
-        `${carrierPath} nested member ${selected.asset.memberPath}`,
-        safeMaterializeRoot,
-      );
-    }
-  } finally {
-    rmSync(stage, { recursive: true, force: true });
-  }
-}
-
-async function main() {
-  const options = parseOptions(Bun.argv.slice(2));
-  const root = options.get("--root");
-  const artifactRoot = options.get("--artifact-root");
-  const materializeRoot = options.get("--materialize-root");
-  const selected = options.get("--extensions")
-    .split(",")
-    .map((item) => item.trim())
-    .filter(Boolean);
-  const assetKind = options.get("--asset-kind");
-  const assetTarget = options.get("--asset-target");
-  const requiredValue = options.get("--required");
-  if (!new Set(["runtime", "ios-xcframework"]).has(assetKind)) {
-    fail(`unknown extension asset kind: ${assetKind}`, 2);
-  }
-  if (assetTarget !== "*" && !MOBILE_TARGETS.has(assetTarget)) {
-    fail(`unknown mobile extension asset target: ${assetTarget}`, 2);
-  }
-  if (!new Set(["0", "1"]).has(requiredValue)) {
-    usage();
-  }
-  const required = requiredValue === "1";
-  if (new Set(selected).size !== selected.length) {
-    fail("selected exact-extension list must not contain duplicates");
-  }
-  const repositoryContract = await loadRepositoryContract(root);
-
-  const bySqlName = new Map();
-  for (const manifestPath of await manifestPaths(artifactRoot, repositoryContract)) {
-    let manifest;
-    try {
-      manifest = JSON.parse(await readFile(manifestPath, "utf8"));
-    } catch (error) {
-      fail(`${manifestPath} is not valid JSON: ${error.message}`);
-    }
-    for (const [index, member] of manifestMembers(manifest, manifestPath, repositoryContract).entries()) {
-      if (!isObject(member)) {
-        fail(`${manifestPath} extension member ${index} must be an object`);
-      }
-      const sqlName = safeComponent(member.sqlName, `${manifestPath} extension member ${index} sqlName`);
-      if (bySqlName.has(sqlName)) {
-        fail(`duplicate exact-extension artifact package for SQL extension ${sqlName}`);
-      }
-      bySqlName.set(sqlName, { manifestPath, manifest, member, sqlName });
-    }
-  }
-
-  const resolved = new Array(selected.length);
-  const missing = [];
-  const bundlePlans = new Map();
-  for (const [index, sqlName] of selected.entries()) {
-    const entry = bySqlName.get(sqlName);
-    if (entry === undefined) {
-      missing.push(`${sqlName}: package`);
-      continue;
-    }
-    const assets = Array.isArray(entry.member.assets) ? entry.member.assets : [];
-    const matches = assets.filter((asset) => assetMatches(asset, assetKind, assetTarget));
-    if (matches.length === 0) {
-      missing.push(`${sqlName}: ${assetKind} asset`);
-      continue;
-    }
-    if (matches.length !== 1) {
-      fail(`${entry.manifestPath} must contain exactly one ${assetKind} asset for ${sqlName}, got ${matches.length}`);
-    }
-    const asset = matches[0];
-    if (entry.manifest.schema === "oliphaunt-extension-ci-artifacts-v1") {
-      validateDirectAsset(asset, entry, sqlName);
-      const file = join(dirname(entry.manifestPath), "release-assets", asset.name);
-      if (!isFile(file)) {
-        missing.push(`${sqlName}: ${file}`);
-        continue;
-      }
-      await verifyFrozenFile(file, asset, `${entry.manifestPath} ${assetKind} asset for ${sqlName}`);
-      resolved[index] = await materializeDirectAsset(entry, asset, file, materializeRoot);
-      continue;
-    }
-
-    const carrier = bundleCarrierFor(entry, asset);
-    const key = `${entry.manifestPath}\0${carrier.name}`;
-    const plan = bundlePlans.get(key) ?? {
-      manifest: entry.manifest,
-      manifestPath: entry.manifestPath,
-      carrier,
-      selected: [],
-    };
-    plan.selected.push({ index, sqlName, asset, destination: null });
-    bundlePlans.set(key, plan);
-  }
-
-  for (const plan of bundlePlans.values()) {
-    const carrierPath = join(dirname(plan.manifestPath), "release-assets", plan.carrier.name);
-    if (!isFile(carrierPath)) {
-      missing.push(`${plan.manifest.product}: ${carrierPath}`);
-    }
-  }
-  if (missing.length > 0) {
-    fail(`missing exact-extension artifact(s): ${missing.join(", ")}`, required ? 1 : 3);
-  }
-
-  for (const plan of bundlePlans.values()) {
-    await materializeBundlePlan(plan, materializeRoot);
-    for (const selectedAsset of plan.selected) {
-      resolved[selectedAsset.index] = selectedAsset.destination;
-    }
-  }
-  if (resolved.some((file) => typeof file !== "string" || file.length === 0)) {
-    fail("internal error: exact-extension artifact selection was not fully resolved");
-  }
-  for (const file of resolved) {
-    console.log(file);
-  }
-}
-
-try {
-  await main();
-} catch (error) {
-  console.error(error instanceof Error ? error.message : String(error));
-  process.exit(error instanceof CliFailure ? error.code : 1);
-}
diff --git a/src/sdks/react-native/tools/mobile-extension-artifact-paths.mts b/src/sdks/react-native/tools/mobile-extension-artifact-paths.mts
new file mode 100644
index 000000000..cf121928f
--- /dev/null
+++ b/src/sdks/react-native/tools/mobile-extension-artifact-paths.mts
@@ -0,0 +1,1560 @@
+#!/usr/bin/env bun
+import { createHash } from 'node:crypto';
+import {
+  chmodSync,
+  closeSync,
+  copyFileSync,
+  createReadStream,
+  lstatSync,
+  mkdirSync,
+  mkdtempSync,
+  openSync,
+  readFileSync,
+  readSync,
+  renameSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import { readFile } from 'node:fs/promises';
+import { dirname, join, relative, resolve, sep } from 'node:path';
+import { isDeepStrictEqual } from 'node:util';
+import { createGunzip } from 'node:zlib';
+import { assertWasixExtensionMemberInstall } from '../../../extensions/contracts/wasix-extension-install.mts';
+import {
+  extensionCarrierLegalContract,
+  extensionCarrierLegalFileInventory,
+} from '../../../extensions/tools/extension-upstream-licenses.mts';
+
+const OPTION_NAMES = new Set([
+  '--root',
+  '--artifact-root',
+  '--materialize-root',
+  '--extensions',
+  '--asset-kind',
+  '--asset-target',
+  '--required',
+]);
+const MOBILE_TARGETS = new Set(['android-arm64-v8a', 'android-x86_64', 'ios-xcframework']);
+const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u;
+const C_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u;
+const MAX_ARTIFACT_BYTES = 2 * 1024 * 1024 * 1024;
+const MAX_BUNDLE_MEMBERS = 4096;
+const MAX_BUNDLE_ARCHIVE_MEMBERS = 32_768;
+const MAX_BUNDLE_EXPANDED_BYTES = 4 * 1024 * 1024 * 1024;
+const EXTENSION_MEMBER_KEYS = new Set([
+  'sqlName',
+  'createsExtension',
+  'dependencies',
+  'dataFiles',
+  'extensionSqlFileNames',
+  'extensionSqlFilePrefixes',
+  'nativeModuleStem',
+  'iosNativeDependencies',
+  'iosRegistration',
+  'wasixInstall',
+  'sharedPreloadLibraries',
+  'assets',
+]);
+const DIRECT_MANIFEST_KEYS = new Set([
+  'schema',
+  'product',
+  'version',
+  'compatibility',
+  ...EXTENSION_MEMBER_KEYS,
+]);
+const BUNDLE_MANIFEST_KEYS = new Set([
+  'schema',
+  'product',
+  'version',
+  'compatibility',
+  'extensions',
+  'carrierAssets',
+]);
+const DIRECT_ASSET_KEYS = new Set([
+  'name',
+  'path',
+  'source',
+  'sha256',
+  'bytes',
+  'family',
+  'kind',
+  'target',
+  'identity',
+]);
+const BUNDLE_MEMBER_ASSET_KEYS = new Set([
+  ...DIRECT_ASSET_KEYS,
+  'carrierAsset',
+  'carrierRoot',
+  'memberPath',
+]);
+const BUNDLE_CARRIER_ASSET_KEYS = new Set([
+  'name',
+  'path',
+  'sha256',
+  'bytes',
+  'family',
+  'target',
+  'kind',
+  'memberCount',
+]);
+
+function manifestEnvelopeKeys(baseKeys, manifest, repositoryContract) {
+  const owner = repositoryContract.products.get(manifest.product);
+  return owner?.releaseProduct === owner?.artifactProduct
+    ? baseKeys
+    : new Set([...baseKeys, 'releaseProduct', 'family']);
+}
+
+class CliFailure extends Error {
+  constructor(message, code = 1) {
+    super(message);
+    this.code = code;
+  }
+}
+
+function fail(message, code = 1) {
+  throw new CliFailure(message, code);
+}
+
+function usage() {
+  fail(
+    'usage: mobile-extension-artifact-paths.mts --root PATH --artifact-root PATH --materialize-root PATH --extensions CSV --asset-kind runtime|ios-xcframework --asset-target TARGET|* --required 0|1',
+    2,
+  );
+}
+
+function parseOptions(args) {
+  if (args.length % 2 !== 0) {
+    usage();
+  }
+  const options = new Map();
+  for (let index = 0; index < args.length; index += 2) {
+    const name = args[index];
+    const value = args[index + 1];
+    if (!OPTION_NAMES.has(name)) {
+      fail(`unknown option: ${name}`, 2);
+    }
+    if (options.has(name)) {
+      fail(`duplicate option: ${name}`, 2);
+    }
+    if (value === undefined || value.startsWith('--')) {
+      usage();
+    }
+    options.set(name, value);
+  }
+  for (const name of OPTION_NAMES) {
+    if (!options.has(name)) {
+      usage();
+    }
+  }
+  return options;
+}
+
+function isObject(value) {
+  return value !== null && !Array.isArray(value) && typeof value === 'object';
+}
+
+function requireExactKeys(value, expected, context) {
+  if (!isObject(value)) {
+    fail(`${context} must be an object`);
+  }
+  const actual = Object.keys(value).sort(compareText);
+  const canonical = [...expected].sort(compareText);
+  if (!isDeepStrictEqual(actual, canonical)) {
+    fail(`${context} fields must be exactly ${canonical.join(',')}; got ${actual.join(',')}`);
+  }
+}
+
+function isFile(file) {
+  try {
+    const metadata = lstatSync(file);
+    return metadata.isFile() && !metadata.isSymbolicLink();
+  } catch {
+    return false;
+  }
+}
+
+async function sha256File(file) {
+  return await new Promise((resolve, reject) => {
+    const digest = createHash('sha256');
+    const stream = createReadStream(file);
+    stream.on('data', (chunk) => digest.update(chunk));
+    stream.on('error', reject);
+    stream.on('end', () => resolve(digest.digest('hex')));
+  });
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function safeComponent(value, context) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value === '.' ||
+    value === '..' ||
+    value.includes('/') ||
+    value.includes('\\') ||
+    value.includes('\0')
+  ) {
+    fail(`${context} must be a safe non-empty path component`);
+  }
+  return value;
+}
+
+function safeArchiveMember(value, context) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    value.includes('\0')
+  ) {
+    fail(`${context} must be a safe relative archive path`);
+  }
+  const parts = value.split('/');
+  if (
+    value.startsWith('/') ||
+    parts.some((part) => part.length === 0 || part === '.' || part === '..')
+  ) {
+    fail(`${context} must be a safe relative archive path`);
+  }
+  return value;
+}
+
+function validatePublishedPath(value, name, context) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    value.includes('\0')
+  ) {
+    fail(`${context} must declare a release-assets path`);
+  }
+  const suffix = `/release-assets/${name}`;
+  if (value !== `release-assets/${name}` && !value.endsWith(suffix)) {
+    fail(`${context} must point to release-assets/${name}`);
+  }
+}
+
+function validateDigestRow(value, context) {
+  if (!/^[0-9a-f]{64}$/u.test(value.sha256 ?? '')) {
+    fail(`${context} must declare a lowercase SHA-256 digest`);
+  }
+  if (!Number.isSafeInteger(value.bytes) || value.bytes <= 0) {
+    fail(`${context} must declare a positive safe-integer byte count`);
+  }
+  if (value.bytes > MAX_ARTIFACT_BYTES) {
+    fail(`${context} exceeds the maximum supported size of ${MAX_ARTIFACT_BYTES} bytes`);
+  }
+}
+
+function canonicalStringList(value, context, validate = safeComponent) {
+  if (!Array.isArray(value)) {
+    fail(`${context} must be an array`);
+  }
+  const result = value
+    .map((item, index) => validate(item, `${context}[${index}]`))
+    .sort(compareText);
+  if (new Set(result).size !== result.length) {
+    fail(`${context} must not contain duplicates`);
+  }
+  return result;
+}
+
+function sqlFileName(value, context) {
+  if (
+    typeof value !== 'string' ||
+    !/^[A-Za-z0-9._-]{1,128}$/u.test(value) ||
+    !value.endsWith('.sql')
+  ) {
+    fail(`${context} must be a portable SQL basename ending in .sql`);
+  }
+  return value;
+}
+
+function sqlFilePrefix(value, context) {
+  if (typeof value !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/u.test(value)) {
+    fail(`${context} must be a dot-free portable SQL basename prefix`);
+  }
+  return value;
+}
+
+function parseIosDependencyContract(text, source) {
+  const lines = text.split(/\r?\n/u).filter((line) => line.length > 0 && !line.startsWith('#'));
+  if (lines.length === 0) fail(`${source} is empty`);
+  const header = lines[0].split('\t');
+  const sqlIndex = header.indexOf('sql-name');
+  const dependenciesIndex = header.indexOf('ios-static-dependencies');
+  if (sqlIndex < 0 || dependenciesIndex < 0) {
+    fail(`${source} must declare sql-name and ios-static-dependencies columns`);
+  }
+  const result = new Map();
+  for (const [index, line] of lines.slice(1).entries()) {
+    const fields = line.split('\t');
+    const sqlName = safeComponent(fields[sqlIndex], `${source}:${index + 2} sql-name`);
+    const dependencies = canonicalStringList(
+      (fields[dependenciesIndex] ?? '').split(',').filter(Boolean),
+      `${source}:${index + 2} ios-static-dependencies`,
+    );
+    if (result.has(sqlName)) fail(`${source} repeats iOS dependency owner ${sqlName}`);
+    result.set(sqlName, dependencies);
+  }
+  return result;
+}
+
+function parseIosDependencyOverlay(value, source) {
+  if (!isObject(value) || value['format-version'] !== 1 || !Array.isArray(value.extensions)) {
+    fail(`${source} must use format-version 1 and declare extensions`);
+  }
+  const result = new Map();
+  for (const [index, row] of value.extensions.entries()) {
+    if (!isObject(row)) fail(`${source} extension ${index} must be an object`);
+    const sqlName = safeComponent(row['sql-name'], `${source} extension ${index} sql-name`);
+    const dependencies = canonicalStringList(
+      row['static-dependencies'],
+      `${source} extension ${sqlName} static-dependencies`,
+    );
+    if (result.has(sqlName)) fail(`${source} repeats iOS dependency owner ${sqlName}`);
+    result.set(sqlName, dependencies);
+  }
+  return result;
+}
+
+async function loadRepositoryContract(root) {
+  const metadataPath = join(root, 'src/extensions/generated/sdk/extensions.json');
+  const iosOverlayPath = join(root, 'src/extensions/generated/sdk/ios-static-dependencies.json');
+  const iosDependenciesPath = join(root, 'src/extensions/generated/mobile/static-extensions.tsv');
+  const nativeVersionPath = join(root, 'src/runtimes/liboliphaunt-native/VERSION');
+  const wasixVersionPath = join(root, 'src/runtimes/liboliphaunt-wasix/VERSION');
+  let metadata;
+  let iosOverlay;
+  let iosDependenciesText;
+  let nativeRuntimeVersion;
+  let wasixRuntimeVersion;
+  try {
+    [metadata, iosOverlay, iosDependenciesText, nativeRuntimeVersion, wasixRuntimeVersion] =
+      await Promise.all([
+        readFile(metadataPath, 'utf8').then((value) => JSON.parse(value)),
+        readFile(iosOverlayPath, 'utf8').then((value) => JSON.parse(value)),
+        readFile(iosDependenciesPath, 'utf8'),
+        readFile(nativeVersionPath, 'utf8').then((value) => value.trim()),
+        readFile(wasixVersionPath, 'utf8').then((value) => value.trim()),
+      ]);
+  } catch (error) {
+    fail(
+      `could not load generated mobile extension ownership and runtime versions: ${error.message}`,
+    );
+  }
+  if (!STABLE_SEMVER.test(nativeRuntimeVersion) || !STABLE_SEMVER.test(wasixRuntimeVersion)) {
+    fail('native and WASIX runtime VERSION files must contain stable SemVer');
+  }
+  if (!isObject(metadata) || !Array.isArray(metadata.extensions)) {
+    fail(`${metadataPath} must declare extensions`);
+  }
+  const generatedIosDependencies = parseIosDependencyOverlay(iosOverlay, iosOverlayPath);
+  const staticIosDependencies = parseIosDependencyContract(
+    iosDependenciesText,
+    iosDependenciesPath,
+  );
+  const products = new Map();
+  const sqlOwners = new Map();
+  for (const [index, row] of metadata.extensions.entries()) {
+    if (!isObject(row)) {
+      fail(`${metadataPath} extension ${index} must be an object`);
+    }
+    const sqlName = safeComponent(row['sql-name'], `${metadataPath} extension ${index} sql-name`);
+    const product = safeComponent(
+      row['artifact-product'],
+      `${metadataPath} extension ${sqlName} artifact-product`,
+    );
+    const releaseProduct = safeComponent(
+      row['release-product'],
+      `${metadataPath} extension ${sqlName} release-product`,
+    );
+    if (sqlOwners.has(sqlName)) {
+      fail(`${metadataPath} repeats SQL extension owner ${sqlName}`);
+    }
+    sqlOwners.set(sqlName, product);
+    const postgresMajor = String(row['postgres-major'] ?? '');
+    if (!/^[1-9][0-9]*$/u.test(postgresMajor)) {
+      fail(`${metadataPath} extension ${sqlName} has invalid postgres-major`);
+    }
+    if (typeof row['creates-extension'] !== 'boolean') {
+      fail(`${metadataPath} extension ${sqlName} creates-extension must be boolean`);
+    }
+    const nativeModuleStem =
+      row['native-module-stem'] === null
+        ? null
+        : safeComponent(
+            row['native-module-stem'],
+            `${metadataPath} extension ${sqlName} native-module-stem`,
+          );
+    const generatedDependencies = generatedIosDependencies.get(sqlName) ?? [];
+    const staticDependencies =
+      staticIosDependencies.get(sqlName) ??
+      (nativeModuleStem === null
+        ? []
+        : fail(`${iosDependenciesPath} has no row for native extension ${sqlName}`));
+    if (!isDeepStrictEqual(generatedDependencies, staticDependencies)) {
+      fail(
+        `${iosOverlayPath} and ${iosDependenciesPath} disagree for iOS dependencies of ${sqlName}`,
+      );
+    }
+    if (nativeModuleStem === null && generatedDependencies.length > 0) {
+      fail(`${iosOverlayPath} SQL-only extension ${sqlName} must not declare iOS dependencies`);
+    }
+    const dependencies = canonicalStringList(
+      row['selected-extension-dependencies'],
+      `${metadataPath} extension ${sqlName} selected-extension-dependencies`,
+    );
+    if (dependencies.includes(sqlName)) {
+      fail(`${metadataPath} extension ${sqlName} must not depend on itself`);
+    }
+    const canonical = {
+      sqlName,
+      createsExtension: row['creates-extension'],
+      dependencies,
+      dataFiles: canonicalStringList(
+        row['runtime-share-data-files'],
+        `${metadataPath} extension ${sqlName} runtime-share-data-files`,
+        safeArchiveMember,
+      ),
+      extensionSqlFileNames: canonicalStringList(
+        row['extension-sql-file-names'],
+        `${metadataPath} extension ${sqlName} extension-sql-file-names`,
+        sqlFileName,
+      ),
+      extensionSqlFilePrefixes: canonicalStringList(
+        row['extension-sql-file-prefixes'],
+        `${metadataPath} extension ${sqlName} extension-sql-file-prefixes`,
+        sqlFilePrefix,
+      ),
+      nativeModuleStem,
+      canonicalIosNativeDependencies: generatedDependencies,
+      sharedPreloadLibraries: canonicalStringList(
+        row['shared-preload-libraries'],
+        `${metadataPath} extension ${sqlName} shared-preload-libraries`,
+      ),
+    };
+    const owner = products.get(product) ?? {
+      artifactProduct: product,
+      releaseProduct,
+      members: new Map(),
+      postgresMajor,
+      sqlNames: [],
+    };
+    if (owner.postgresMajor !== postgresMajor) {
+      fail(`${metadataPath} product ${product} spans multiple PostgreSQL majors`);
+    }
+    if (owner.releaseProduct !== releaseProduct) {
+      fail(`${metadataPath} artifact product ${product} spans multiple native release owners`);
+    }
+    owner.sqlNames.push(sqlName);
+    owner.members.set(sqlName, canonical);
+    products.set(product, owner);
+  }
+  for (const owner of products.values()) {
+    owner.sqlNames.sort(compareText);
+  }
+  return { nativeRuntimeVersion, products, wasixRuntimeVersion };
+}
+
+function validateCompatibility(manifest, manifestPath, repositoryContract) {
+  const owner = repositoryContract.products.get(manifest.product);
+  if (owner === undefined) {
+    fail(
+      `${manifestPath} product ${manifest.product} has no generated React Native extension owner`,
+    );
+  }
+  const expected = {
+    extensionRuntimeContract: 'src/extensions/contracts/contract.toml',
+    nativeRuntimeProduct: 'liboliphaunt-native',
+    nativeRuntimeVersion: repositoryContract.nativeRuntimeVersion,
+    postgresMajor: owner.postgresMajor,
+    wasixRuntimeProduct: 'liboliphaunt-wasix',
+    wasixRuntimeVersion: repositoryContract.wasixRuntimeVersion,
+  };
+  if (!isDeepStrictEqual(manifest.compatibility, expected)) {
+    fail(
+      `${manifestPath} compatibility metadata must exactly match the generated runtime contract`,
+    );
+  }
+  return owner;
+}
+
+function validateIdentity(asset, context) {
+  if (asset.kind === 'runtime') {
+    if (asset.identity !== null) {
+      fail(`${context} runtime identity must be null`);
+    }
+    return;
+  }
+  if (asset.kind === 'ios-dependency-xcframework') {
+    if (typeof asset.identity !== 'string' || asset.identity.length === 0) {
+      fail(`${context} iOS dependency identity must be a non-empty string`);
+    }
+    return;
+  }
+  if (asset.kind === 'ios-xcframework') {
+    if (
+      !(
+        asset.identity === null ||
+        (typeof asset.identity === 'string' && asset.identity.length > 0)
+      )
+    ) {
+      fail(`${context} iOS XCFramework identity must be null or a non-empty string`);
+    }
+    return;
+  }
+  if (asset.identity !== null) {
+    fail(`${context} identity must be null for kind=${asset.kind}`);
+  }
+}
+
+function validateIosRegistration(value, expected, context) {
+  if (!isObject(value)) {
+    fail(`${context} must contain build-derived iOS registration metadata`);
+  }
+  requireExactKeys(
+    value,
+    new Set(['initSymbol', 'magicSymbol', 'nativeModuleStem', 'schema', 'sqlName', 'symbols']),
+    context,
+  );
+  const prefix = `oliphaunt_static_${expected.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`;
+  if (
+    value.schema !== 'oliphaunt-ios-extension-registration-v1' ||
+    value.sqlName !== expected.sqlName ||
+    value.nativeModuleStem !== expected.nativeModuleStem ||
+    value.magicSymbol !== `${prefix}_Pg_magic_func` ||
+    ![null, `${prefix}__PG_init`].includes(value.initSymbol) ||
+    !C_IDENTIFIER.test(value.magicSymbol) ||
+    !(value.initSymbol === null || C_IDENTIFIER.test(value.initSymbol)) ||
+    !Array.isArray(value.symbols)
+  ) {
+    fail(
+      `${context} does not match canonical native module identity ${expected.sqlName}/${expected.nativeModuleStem}`,
+    );
+  }
+  const normalized = value.symbols.map((row, index) => {
+    requireExactKeys(row, new Set(['address', 'name']), `${context}.symbols[${index}]`);
+    if (!C_IDENTIFIER.test(row.name ?? '') || !C_IDENTIFIER.test(row.address ?? '')) {
+      fail(`${context}.symbols[${index}] must map canonical C identifiers`);
+    }
+    return `${row.name}\0${row.address}`;
+  });
+  if (
+    new Set(value.symbols.map(({ name }) => name)).size !== value.symbols.length ||
+    !isDeepStrictEqual(normalized, [...normalized].sort(compareText))
+  ) {
+    fail(`${context}.symbols must be sorted with unique public names`);
+  }
+}
+
+function expectedMobileRoles(member, target) {
+  const roles = ['runtime:'];
+  if (target === 'ios-xcframework' && member.nativeModuleStem !== null) {
+    roles.push(`ios-xcframework:${member.nativeModuleStem}`);
+    roles.push(
+      ...member.iosNativeDependencies.map(
+        (dependency) => `ios-dependency-xcframework:${dependency}`,
+      ),
+    );
+  }
+  return roles.sort(compareText);
+}
+
+function validateExactMobileRoles(member, target, assets, context) {
+  const actual = assets
+    .map((asset, index) => {
+      const assetContext = `${context} asset ${index}`;
+      safeComponent(asset.name, `${assetContext} name`);
+      validateDigestRow(asset, assetContext);
+      if (asset.family !== 'native' || asset.target !== target) {
+        fail(`${assetContext} must belong to native/${target}`);
+      }
+      validateIdentity(asset, assetContext);
+      return `${asset.kind}:${asset.identity ?? ''}`;
+    })
+    .sort(compareText);
+  const expected = expectedMobileRoles(member, target);
+  if (!isDeepStrictEqual(actual, expected)) {
+    fail(
+      `${context} mobile artifact roles are not exact and dependency-closed: ` +
+        `expected=${JSON.stringify(expected)}, actual=${JSON.stringify(actual)}`,
+    );
+  }
+}
+
+function validateMemberContract(member, expected, context) {
+  for (const field of [
+    'sqlName',
+    'createsExtension',
+    'dependencies',
+    'dataFiles',
+    'extensionSqlFileNames',
+    'extensionSqlFilePrefixes',
+    'nativeModuleStem',
+    'sharedPreloadLibraries',
+  ]) {
+    if (!isDeepStrictEqual(member[field], expected[field])) {
+      fail(`${context}.${field} must exactly match generated React Native extension metadata`);
+    }
+  }
+  if (!Array.isArray(member.assets)) fail(`${context}.assets must be an array`);
+  try {
+    assertWasixExtensionMemberInstall(member, { label: context });
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+  const mobileGroups = new Map();
+  for (const [index, asset] of member.assets.entries()) {
+    if (!isObject(asset) || !MOBILE_TARGETS.has(asset.target)) continue;
+    if (asset.family !== 'native') {
+      fail(`${context}.assets[${index}] mobile target ${asset.target} must use the native family`);
+    }
+    const group = mobileGroups.get(asset.target) ?? [];
+    group.push(asset);
+    mobileGroups.set(asset.target, group);
+  }
+  const stagesIos = mobileGroups.has('ios-xcframework');
+  const expectedIosDependencies =
+    stagesIos && expected.nativeModuleStem !== null ? expected.canonicalIosNativeDependencies : [];
+  if (!isDeepStrictEqual(member.iosNativeDependencies, expectedIosDependencies)) {
+    fail(
+      `${context}.iosNativeDependencies must exactly match the canonical staged iOS dependency closure`,
+    );
+  }
+  if (expected.nativeModuleStem === null || !stagesIos) {
+    if (member.iosRegistration !== null) {
+      fail(`${context}.iosRegistration must be null without a staged native iOS module`);
+    }
+  } else {
+    validateIosRegistration(member.iosRegistration, expected, `${context}.iosRegistration`);
+  }
+  for (const [target, assets] of mobileGroups) {
+    validateExactMobileRoles(member, target, assets, `${context} ${target}`);
+  }
+}
+
+async function manifestPaths(artifactRoot, repositoryContract) {
+  return [...repositoryContract.products.values()]
+    .map((owner) =>
+      join(
+        artifactRoot,
+        ...(owner.releaseProduct === owner.artifactProduct
+          ? [owner.artifactProduct]
+          : [owner.releaseProduct, owner.artifactProduct]),
+        'extension-artifacts.json',
+      ),
+    )
+    .filter((file) => isFile(file))
+    .sort(compareText);
+}
+
+function assetMatches(asset, assetKind, assetTarget) {
+  if (!isObject(asset) || asset.family !== 'native') {
+    return false;
+  }
+  if (assetTarget !== '*' && asset.target !== assetTarget) {
+    return false;
+  }
+  return asset.kind === assetKind;
+}
+
+function validateManifestEnvelope(manifest, manifestPath, repositoryContract, members) {
+  safeComponent(manifest.product, `${manifestPath} product`);
+  if (!STABLE_SEMVER.test(manifest.version ?? '')) {
+    fail(`${manifestPath} version must be stable SemVer`);
+  }
+  const owner = validateCompatibility(manifest, manifestPath, repositoryContract);
+  if (owner.releaseProduct !== owner.artifactProduct) {
+    if (manifest.releaseProduct !== owner.releaseProduct || manifest.family !== 'native') {
+      fail(`${manifestPath} must be owned by ${owner.releaseProduct}/native`);
+    }
+    if (manifest.version !== repositoryContract.nativeRuntimeVersion) {
+      fail(`${manifestPath} version must match its native release owner`);
+    }
+  }
+  const actualSqlNames = members.map((member) => member?.sqlName);
+  if (new Set(actualSqlNames).size !== actualSqlNames.length) {
+    fail(`${manifestPath} repeats an extension SQL identity`);
+  }
+  if (!isDeepStrictEqual(actualSqlNames, owner.sqlNames)) {
+    fail(
+      `${manifestPath} member set must exactly match generated owner ${manifest.product}: ` +
+        `expected=${JSON.stringify(owner.sqlNames)}, actual=${JSON.stringify(actualSqlNames)}`,
+    );
+  }
+  for (const [index, member] of members.entries()) {
+    const expected = owner.members.get(member.sqlName);
+    if (expected === undefined) {
+      fail(
+        `${manifestPath} extension member ${index} has no generated React Native owner metadata`,
+      );
+    }
+    validateMemberContract(member, expected, `${manifestPath} extension member ${member.sqlName}`);
+  }
+}
+
+function manifestMembers(manifest, manifestPath, repositoryContract) {
+  if (!isObject(manifest)) {
+    fail(`${manifestPath} must contain an extension artifact manifest object`);
+  }
+  let members;
+  if (manifest.schema === 'oliphaunt-extension-ci-artifacts-v1') {
+    requireExactKeys(
+      manifest,
+      manifestEnvelopeKeys(DIRECT_MANIFEST_KEYS, manifest, repositoryContract),
+      manifestPath,
+    );
+    if (!Array.isArray(manifest.assets)) {
+      fail(`${manifestPath} must declare an assets array`);
+    }
+    for (const [index, asset] of manifest.assets.entries()) {
+      requireExactKeys(asset, DIRECT_ASSET_KEYS, `${manifestPath} asset ${index}`);
+    }
+    members = [manifest];
+  } else if (manifest.schema === 'oliphaunt-extension-ci-artifacts-v2') {
+    requireExactKeys(
+      manifest,
+      manifestEnvelopeKeys(BUNDLE_MANIFEST_KEYS, manifest, repositoryContract),
+      manifestPath,
+    );
+    if (!Array.isArray(manifest.extensions) || manifest.extensions.length === 0) {
+      fail(`${manifestPath} must declare a non-empty extensions array`);
+    }
+    for (const [index, member] of manifest.extensions.entries()) {
+      requireExactKeys(member, EXTENSION_MEMBER_KEYS, `${manifestPath} extension member ${index}`);
+      if (!Array.isArray(member.assets)) {
+        fail(`${manifestPath} extension member ${index} must declare an assets array`);
+      }
+      for (const [assetIndex, asset] of member.assets.entries()) {
+        requireExactKeys(
+          asset,
+          BUNDLE_MEMBER_ASSET_KEYS,
+          `${manifestPath} extension member ${index} asset ${assetIndex}`,
+        );
+      }
+    }
+    if (!Array.isArray(manifest.carrierAssets)) {
+      fail(`${manifestPath} must declare a carrierAssets array`);
+    }
+    for (const [index, carrier] of manifest.carrierAssets.entries()) {
+      requireExactKeys(
+        carrier,
+        BUNDLE_CARRIER_ASSET_KEYS,
+        `${manifestPath} aggregate carrier ${index}`,
+      );
+    }
+    members = manifest.extensions;
+  } else {
+    fail(
+      `${manifestPath} has unsupported extension artifact schema ${JSON.stringify(manifest.schema)}`,
+    );
+  }
+  validateManifestEnvelope(manifest, manifestPath, repositoryContract, members);
+  return members;
+}
+
+function validateDirectAsset(asset, entry, sqlName) {
+  const context = `${entry.manifestPath} ${asset.kind} asset for ${sqlName}`;
+  requireExactKeys(asset, DIRECT_ASSET_KEYS, context);
+  safeComponent(asset.name, `${context} name`);
+  validateDigestRow(asset, context);
+  validateIdentity(asset, context);
+  validatePublishedPath(asset.path, asset.name, context);
+}
+
+function validateBundleCarrier(manifest, manifestPath, carrier) {
+  const context = `${manifestPath} aggregate carrier`;
+  requireExactKeys(carrier, BUNDLE_CARRIER_ASSET_KEYS, context);
+  safeComponent(carrier.name, `${context} name`);
+  safeComponent(carrier.target, `${context} target`);
+  validateDigestRow(carrier, `${context} ${carrier.name}`);
+  if (
+    !Number.isSafeInteger(carrier.memberCount) ||
+    carrier.memberCount <= 0 ||
+    carrier.memberCount > MAX_BUNDLE_MEMBERS
+  ) {
+    fail(`${context} ${carrier.name} must declare a bounded positive memberCount`);
+  }
+  if (carrier.kind !== 'extension-bundle' || carrier.family !== 'native') {
+    fail(`${context} ${carrier.name} must be a native extension-bundle`);
+  }
+  if (!MOBILE_TARGETS.has(carrier.target)) {
+    fail(
+      `${context} ${carrier.name} has unsupported mobile target ${JSON.stringify(carrier.target)}`,
+    );
+  }
+  const expectedName = `${manifest.product}-${manifest.version}-${carrier.family}-${carrier.target}-bundle.tar.gz`;
+  if (carrier.name !== expectedName) {
+    fail(`${context} ${carrier.name} must use canonical name ${expectedName}`);
+  }
+  validatePublishedPath(carrier.path, carrier.name, `${context} ${carrier.name}`);
+}
+
+function bundleCarrierFor(entry, asset) {
+  const carriers = Array.isArray(entry.manifest.carrierAssets)
+    ? entry.manifest.carrierAssets.filter(
+        (carrier) =>
+          isObject(carrier) &&
+          carrier.family === asset.family &&
+          carrier.target === asset.target &&
+          carrier.kind === 'extension-bundle',
+      )
+    : [];
+  if (carriers.length !== 1) {
+    fail(
+      `${entry.manifestPath} must declare exactly one native extension-bundle carrier for ${asset.target}, got ${carriers.length}`,
+    );
+  }
+  const carrier = carriers[0];
+  validateBundleCarrier(entry.manifest, entry.manifestPath, carrier);
+  if (asset.carrierAsset !== carrier.name) {
+    fail(`${entry.manifestPath} ${entry.sqlName} asset references the wrong aggregate carrier`);
+  }
+  return carrier;
+}
+
+function validateBundleMemberAsset({ manifestPath, carrier, member, asset }) {
+  const context = `${manifestPath} aggregate member ${member.sqlName}/${asset?.kind ?? 'unknown'}`;
+  requireExactKeys(asset, BUNDLE_MEMBER_ASSET_KEYS, context);
+  safeComponent(asset.name, `${context} name`);
+  validateDigestRow(asset, context);
+  if (asset.family !== carrier.family || asset.target !== carrier.target) {
+    fail(`${context} must match carrier ${carrier.family}/${carrier.target}`);
+  }
+  const allowedKinds =
+    carrier.target === 'ios-xcframework'
+      ? new Set(['runtime', 'ios-xcframework', 'ios-dependency-xcframework'])
+      : new Set(['runtime']);
+  if (!allowedKinds.has(asset.kind)) {
+    fail(`${context} has invalid kind for ${carrier.target}`);
+  }
+  validateIdentity(asset, context);
+  if (asset.carrierAsset !== carrier.name) {
+    fail(`${context} references the wrong aggregate carrier`);
+  }
+  const expectedRoot = carrier.name.replace(/\.tar\.gz$/u, '');
+  const expectedMemberPath = `extensions/${member.sqlName}/${asset.name}`;
+  if (asset.carrierRoot !== expectedRoot || asset.memberPath !== expectedMemberPath) {
+    fail(`${context} has a noncanonical nested locator`);
+  }
+  safeArchiveMember(`${asset.carrierRoot}/${asset.memberPath}`, `${context} locator`);
+  return {
+    sqlName: member.sqlName,
+    kind: asset.kind,
+    identity: asset.identity,
+    path: asset.memberPath,
+    sha256: asset.sha256,
+    bytes: asset.bytes,
+  };
+}
+
+function expectedBundleManifest(manifest, manifestPath, carrier) {
+  const rows = [];
+  const allSqlNames = [];
+  const identities = new Set();
+  const roles = new Set();
+  const memberPaths = new Set();
+  for (const member of manifest.extensions) {
+    if (!isObject(member)) {
+      fail(`${manifestPath} aggregate member must be an object`);
+    }
+    const sqlName = safeComponent(member.sqlName, `${manifestPath} aggregate member sqlName`);
+    allSqlNames.push(sqlName);
+    const assets = Array.isArray(member.assets) ? member.assets : [];
+    const carrierAssets = assets.filter(
+      (asset) =>
+        isObject(asset) && asset.family === carrier.family && asset.target === carrier.target,
+    );
+    if (carrierAssets.length === 0) {
+      fail(`${manifestPath} aggregate carrier ${carrier.name} is missing exact member ${sqlName}`);
+    }
+    validateExactMobileRoles(
+      member,
+      carrier.target,
+      carrierAssets,
+      `${manifestPath} aggregate carrier ${carrier.name} member ${sqlName}`,
+    );
+    for (const asset of carrierAssets) {
+      const row = validateBundleMemberAsset({ manifestPath, carrier, member, asset });
+      const identityKey = `${row.sqlName}\0${row.kind}\0${row.path}`;
+      if (identities.has(identityKey)) {
+        fail(
+          `${manifestPath} aggregate carrier ${carrier.name} repeats member identity ${sqlName}/${row.kind}/${row.path}`,
+        );
+      }
+      identities.add(identityKey);
+      const roleKey = `${row.sqlName}\0${row.kind}\0${row.identity ?? ''}`;
+      if (roles.has(roleKey)) {
+        fail(
+          `${manifestPath} aggregate carrier ${carrier.name} repeats member role ${sqlName}/${row.kind}/${row.identity ?? ''}`,
+        );
+      }
+      roles.add(roleKey);
+      if (memberPaths.has(row.path)) {
+        fail(
+          `${manifestPath} aggregate carrier ${carrier.name} repeats nested member path ${row.path}`,
+        );
+      }
+      memberPaths.add(row.path);
+      rows.push(row);
+    }
+    for (const asset of assets) {
+      if (
+        isObject(asset) &&
+        asset.carrierAsset === carrier.name &&
+        !carrierAssets.includes(asset)
+      ) {
+        fail(
+          `${manifestPath} aggregate carrier ${carrier.name} contains a member with the wrong family/target`,
+        );
+      }
+    }
+  }
+  if (new Set(allSqlNames).size !== allSqlNames.length) {
+    fail(`${manifestPath} aggregate manifest repeats an extension SQL identity`);
+  }
+  if (carrier.memberCount !== allSqlNames.length) {
+    fail(
+      `${manifestPath} aggregate carrier ${carrier.name} must declare memberCount=${allSqlNames.length}`,
+    );
+  }
+  rows.sort((left, right) =>
+    compareText(
+      `${left.sqlName}\0${left.kind}\0${left.identity ?? ''}`,
+      `${right.sqlName}\0${right.kind}\0${right.identity ?? ''}`,
+    ),
+  );
+  const legal = extensionCarrierLegalContract(
+    manifest.product,
+    [...allSqlNames].sort(compareText),
+    { family: carrier.family, target: carrier.target },
+  );
+  return {
+    schema: 'oliphaunt-extension-bundle-v1',
+    product: manifest.product,
+    version: manifest.version,
+    compatibility: manifest.compatibility,
+    family: carrier.family,
+    target: carrier.target,
+    licenseProfile: legal.profile,
+    licenseFiles: legal.licenseFiles,
+    members: rows,
+  };
+}
+
+function sortValue(value) {
+  if (Array.isArray(value)) {
+    return value.map(sortValue);
+  }
+  if (isObject(value)) {
+    return Object.fromEntries(
+      Object.keys(value)
+        .sort(compareText)
+        .map((key) => [key, sortValue(value[key])]),
+    );
+  }
+  return value;
+}
+
+function canonicalJson(value) {
+  return `${JSON.stringify(sortValue(value), null, 2)}\n`;
+}
+
+function tarString(header, offset, length, carrierPath) {
+  const field = header.subarray(offset, offset + length);
+  const end = field.indexOf(0);
+  try {
+    return new TextDecoder('utf-8', { fatal: true }).decode(
+      field.subarray(0, end < 0 ? field.length : end),
+    );
+  } catch {
+    fail(`${carrierPath} contains a non-UTF-8 ustar header field`);
+  }
+}
+
+function tarOctal(header, offset, length, field, carrierPath) {
+  const value = header
+    .subarray(offset, offset + length)
+    .toString('ascii')
+    .replaceAll('\0', '')
+    .trim();
+  if (!/^[0-7]+$/u.test(value)) {
+    fail(`${carrierPath} has invalid ustar ${field}`);
+  }
+  const parsed = Number.parseInt(value, 8);
+  if (!Number.isSafeInteger(parsed) || parsed < 0) {
+    fail(`${carrierPath} has unsafe ustar ${field}`);
+  }
+  return parsed;
+}
+
+function gzipHeader(carrierPath) {
+  const header = Buffer.alloc(10);
+  let descriptor;
+  let bytes;
+  try {
+    descriptor = openSync(carrierPath, 'r');
+    bytes = readSync(descriptor, header, 0, header.length, 0);
+  } finally {
+    if (descriptor !== undefined) {
+      closeSync(descriptor);
+    }
+  }
+  const canonical = Buffer.from([0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03]);
+  if (bytes !== header.length || !header.equals(canonical)) {
+    fail(`${carrierPath} must use the canonical gzip method, flags, mtime, XFL, and OS header`);
+  }
+}
+
+async function verifyCanonicalArchive(carrierPath, expectedFiles, stage, requestedNames) {
+  gzipHeader(carrierPath);
+  const expectedNames = [...expectedFiles.keys()].sort(compareText);
+  if (expectedNames.length > MAX_BUNDLE_ARCHIVE_MEMBERS) {
+    fail(`${carrierPath} exceeds the maximum supported physical archive member count`);
+  }
+  const expectedTarBytes = [...expectedFiles.values()].reduce(
+    (total, file) => total + 512 + Math.ceil(file.bytes / 512) * 512,
+    1024,
+  );
+  if (!Number.isSafeInteger(expectedTarBytes) || expectedTarBytes > MAX_BUNDLE_EXPANDED_BYTES) {
+    fail(`${carrierPath} declared ustar size exceeds the supported expanded bundle limit`);
+  }
+  const actualNames = [];
+  let buffer = Buffer.alloc(0);
+  let currentEntry = 'archive header';
+  let currentExpected;
+  let payloadDigest;
+  let payloadRemaining = 0;
+  let paddingRemaining = 0;
+  let terminated = false;
+  let totalBytes = 0;
+  let zeroBlocks = 0;
+  let output;
+  const source = createReadStream(carrierPath);
+  const stream = createGunzip();
+  source.on('error', (error) => stream.destroy(error));
+  source.pipe(stream);
+  try {
+    for await (const chunk of stream) {
+      totalBytes += chunk.length;
+      if (totalBytes > expectedTarBytes) {
+        fail(`${carrierPath} expands beyond its exact declared ustar size`);
+      }
+      buffer = buffer.length === 0 ? Buffer.from(chunk) : Buffer.concat([buffer, chunk]);
+      while (buffer.length > 0) {
+        if (terminated) {
+          if (!buffer.every((value) => value === 0)) {
+            fail(`${carrierPath} has data after its ustar end marker`);
+          }
+          buffer = Buffer.alloc(0);
+          break;
+        }
+        if (payloadRemaining > 0) {
+          const consumed = Math.min(payloadRemaining, buffer.length);
+          payloadDigest.update(buffer.subarray(0, consumed));
+          if (output !== undefined) writeFileSync(output, buffer.subarray(0, consumed));
+          payloadRemaining -= consumed;
+          buffer = buffer.subarray(consumed);
+          if (payloadRemaining === 0) {
+            const actualSha256 = payloadDigest.digest('hex');
+            if (actualSha256 !== currentExpected.sha256) {
+              fail(`${carrierPath} member ${currentEntry} does not match its canonical SHA-256`);
+            }
+            payloadDigest = undefined;
+            if (output !== undefined) closeSync(output);
+            output = undefined;
+          }
+          continue;
+        }
+        if (paddingRemaining > 0) {
+          const consumed = Math.min(paddingRemaining, buffer.length);
+          if (!buffer.subarray(0, consumed).every((value) => value === 0)) {
+            fail(`${carrierPath} member ${currentEntry} has nonzero ustar padding`);
+          }
+          paddingRemaining -= consumed;
+          buffer = buffer.subarray(consumed);
+          continue;
+        }
+        if (buffer.length < 512) {
+          break;
+        }
+        const header = buffer.subarray(0, 512);
+        buffer = buffer.subarray(512);
+        if (header.every((value) => value === 0)) {
+          zeroBlocks += 1;
+          if (zeroBlocks === 2) {
+            terminated = true;
+          }
+          continue;
+        }
+        if (zeroBlocks > 0) {
+          fail(`${carrierPath} has an incomplete ustar end marker`);
+        }
+        if (
+          !header.subarray(257, 263).equals(Buffer.from('ustar\0')) ||
+          !header.subarray(263, 265).equals(Buffer.from('00'))
+        ) {
+          fail(`${carrierPath} must use canonical POSIX ustar headers`);
+        }
+        const checksumField = header.subarray(148, 156).toString('latin1');
+        if (!/^[0-7]{6}\0 $/u.test(checksumField)) {
+          fail(`${carrierPath} has a noncanonical ustar checksum field`);
+        }
+        const expectedChecksum = tarOctal(header, 148, 8, 'checksum', carrierPath);
+        let actualChecksum = 0;
+        for (let index = 0; index < 512; index += 1) {
+          actualChecksum += index >= 148 && index < 156 ? 0x20 : header[index];
+        }
+        if (expectedChecksum !== actualChecksum) {
+          fail(`${carrierPath} has an invalid ustar header checksum`);
+        }
+        const name = tarString(header, 0, 100, carrierPath);
+        const prefix = tarString(header, 345, 155, carrierPath);
+        const archiveName = safeArchiveMember(
+          prefix ? `${prefix}/${name}` : name,
+          `${carrierPath} member`,
+        );
+        currentEntry = JSON.stringify(archiveName);
+        if (header[156] !== 0x30) {
+          fail(`${carrierPath} member ${archiveName} must be a canonical regular file`);
+        }
+        const mode = tarOctal(header, 100, 8, `mode for ${currentEntry}`, carrierPath);
+        const uid = tarOctal(header, 108, 8, `uid for ${currentEntry}`, carrierPath);
+        const gid = tarOctal(header, 116, 8, `gid for ${currentEntry}`, carrierPath);
+        const size = tarOctal(header, 124, 12, `size for ${currentEntry}`, carrierPath);
+        const mtime = tarOctal(header, 136, 12, `mtime for ${currentEntry}`, carrierPath);
+        if (mode !== 0o644 || uid !== 0 || gid !== 0 || mtime !== 0) {
+          fail(`${carrierPath} member ${archiveName} must use mode=0644 uid=0 gid=0 mtime=0`);
+        }
+        if (
+          !header.subarray(157, 257).every((value) => value === 0) ||
+          !header.subarray(265, 345).every((value) => value === 0) ||
+          !header.subarray(500, 512).every((value) => value === 0)
+        ) {
+          fail(`${carrierPath} member ${archiveName} has noncanonical ustar metadata`);
+        }
+        currentExpected = expectedFiles.get(archiveName);
+        if (currentExpected === undefined || size !== currentExpected.bytes) {
+          fail(`${carrierPath} member ${archiveName} is undeclared or has the wrong ustar size`);
+        }
+        if (actualNames.includes(archiveName)) {
+          fail(`${carrierPath} contains duplicate bundle member ${archiveName}`);
+        }
+        actualNames.push(archiveName);
+        if (requestedNames.has(archiveName)) {
+          const destination = join(stage, ...archiveName.split('/'));
+          mkdirSync(dirname(destination), { recursive: true, mode: 0o700 });
+          output = openSync(destination, 'wx', 0o600);
+        }
+        payloadRemaining = size;
+        payloadDigest = createHash('sha256');
+        if (payloadRemaining === 0) {
+          const actualSha256 = payloadDigest.digest('hex');
+          if (actualSha256 !== currentExpected.sha256) {
+            fail(`${carrierPath} member ${currentEntry} does not match its canonical SHA-256`);
+          }
+          payloadDigest = undefined;
+          if (output !== undefined) closeSync(output);
+          output = undefined;
+        }
+        paddingRemaining = (512 - (size % 512)) % 512;
+      }
+    }
+  } catch (error) {
+    if (error instanceof CliFailure) {
+      throw error;
+    }
+    fail(`${carrierPath} is not a readable canonical gzip/ustar archive: ${error.message}`);
+  } finally {
+    source.destroy();
+    stream.destroy();
+    if (output !== undefined) closeSync(output);
+  }
+  if (payloadRemaining > 0 || paddingRemaining > 0) {
+    fail(`${carrierPath} has a truncated member ${currentEntry}`);
+  }
+  if (buffer.length > 0) {
+    fail(`${carrierPath} has a truncated ustar header`);
+  }
+  if (!terminated || totalBytes !== expectedTarBytes || totalBytes % 512 !== 0) {
+    fail(`${carrierPath} must end at its exact two-block ustar marker`);
+  }
+  if (!isDeepStrictEqual(actualNames, expectedNames)) {
+    fail(`${carrierPath} contents do not exactly match its sorted declared bundle members`);
+  }
+}
+
+async function verifyFrozenFile(file, row, context) {
+  if (!isFile(file)) {
+    fail(`${context} is missing or is not a regular non-symlink file`);
+  }
+  if (statSync(file).size !== row.bytes || (await sha256File(file)) !== row.sha256) {
+    fail(`${context} does not match its frozen size/digest`);
+  }
+}
+
+function cacheMetadata(file) {
+  try {
+    return lstatSync(file);
+  } catch (error) {
+    if (error?.code === 'ENOENT') return undefined;
+    throw error;
+  }
+}
+
+function requireCacheDirectory(materializeRoot, directory) {
+  const root = resolve(materializeRoot);
+  const target = resolve(directory);
+  const suffix = relative(root, target);
+  if (suffix === '..' || suffix.startsWith(`..${sep}`)) {
+    fail(`cache directory escapes materialization root: ${target}`);
+  }
+
+  mkdirSync(root, { recursive: true, mode: 0o700 });
+  const rootMetadata = cacheMetadata(root);
+  if (rootMetadata?.isSymbolicLink() || rootMetadata?.isDirectory() !== true) {
+    fail(`materialization cache root must be a real directory, not a symlink: ${root}`);
+  }
+
+  let current = root;
+  for (const component of suffix.split(sep).filter(Boolean)) {
+    current = join(current, component);
+    let metadata = cacheMetadata(current);
+    if (metadata === undefined) {
+      try {
+        mkdirSync(current, { mode: 0o700 });
+      } catch (error) {
+        if (error?.code !== 'EEXIST') throw error;
+      }
+      metadata = cacheMetadata(current);
+    }
+    if (metadata?.isSymbolicLink() || metadata?.isDirectory() !== true) {
+      fail(
+        `materialization cache path component must be a real directory, not a symlink: ${current}`,
+      );
+    }
+  }
+  return target;
+}
+
+async function installCacheFile(source, destination, row, context, materializeRoot) {
+  requireCacheDirectory(materializeRoot, dirname(destination));
+  const destinationMetadata = cacheMetadata(destination);
+  if (destinationMetadata?.isSymbolicLink()) {
+    fail(`materialization cache destination must not be a symlink: ${destination}`);
+  }
+  if (destinationMetadata !== undefined && !destinationMetadata.isFile()) {
+    fail(`materialization cache destination must be a regular file: ${destination}`);
+  }
+  if (destinationMetadata?.isFile()) {
+    if (
+      statSync(destination).size === row.bytes &&
+      (await sha256File(destination)) === row.sha256
+    ) {
+      return destination;
+    }
+    rmSync(destination, { force: true });
+  }
+  const beforeRename = cacheMetadata(destination);
+  if (beforeRename?.isSymbolicLink() || beforeRename !== undefined) {
+    fail(`materialization cache destination changed while being prepared: ${destination}`);
+  }
+  renameSync(source, destination);
+  chmodSync(destination, 0o644);
+  await verifyFrozenFile(destination, row, `${context} after cache materialization`);
+  return destination;
+}
+
+async function materializeDirectAsset(entry, asset, source, materializeRoot) {
+  const safeMaterializeRoot = requireCacheDirectory(materializeRoot, materializeRoot);
+  const destination = join(
+    safeMaterializeRoot,
+    entry.manifest.product,
+    'direct',
+    asset.family,
+    asset.target,
+    asset.sha256,
+    entry.sqlName,
+    asset.name,
+  );
+  const stage = mkdtempSync(join(safeMaterializeRoot, '.direct-'));
+  try {
+    const snapshot = join(stage, asset.name);
+    copyFileSync(source, snapshot);
+    chmodSync(snapshot, 0o600);
+    await verifyFrozenFile(
+      snapshot,
+      asset,
+      `${entry.manifestPath} immutable snapshot for ${entry.sqlName}`,
+    );
+    await verifyFrozenFile(
+      source,
+      asset,
+      `${entry.manifestPath} direct source for ${entry.sqlName} after snapshot`,
+    );
+    return await installCacheFile(
+      snapshot,
+      destination,
+      asset,
+      `${entry.manifestPath} direct asset for ${entry.sqlName}`,
+      safeMaterializeRoot,
+    );
+  } finally {
+    rmSync(stage, { recursive: true, force: true });
+  }
+}
+
+async function materializeBundlePlan(plan, materializeRoot) {
+  const { manifest, manifestPath, carrier } = plan;
+  const expected = expectedBundleManifest(manifest, manifestPath, carrier);
+  const expectedText = canonicalJson(expected);
+  const carrierRoot = carrier.name.replace(/\.tar\.gz$/u, '');
+  const carrierPath = join(dirname(manifestPath), 'release-assets', carrier.name);
+  await verifyFrozenFile(carrierPath, carrier, `${manifestPath} aggregate carrier ${carrier.name}`);
+  const safeMaterializeRoot = requireCacheDirectory(materializeRoot, materializeRoot);
+  const stage = mkdtempSync(join(safeMaterializeRoot, '.extract-'));
+  try {
+    // All structural validation and extraction operate on this private verified
+    // snapshot, so a mutable release-assets path cannot be swapped between the
+    // validation and extraction opens.
+    const carrierSnapshot = join(stage, carrier.name);
+    copyFileSync(carrierPath, carrierSnapshot);
+    chmodSync(carrierSnapshot, 0o600);
+    await verifyFrozenFile(
+      carrierSnapshot,
+      carrier,
+      `${manifestPath} aggregate carrier ${carrier.name} immutable snapshot`,
+    );
+    await verifyFrozenFile(
+      carrierPath,
+      carrier,
+      `${manifestPath} aggregate carrier ${carrier.name} after snapshot`,
+    );
+    const sqlNames = [...new Set(expected.members.map((member) => member.sqlName))].sort(
+      compareText,
+    );
+    const legalFiles = extensionCarrierLegalFileInventory(manifest.product, sqlNames, {
+      family: carrier.family,
+      target: carrier.target,
+    });
+    const expectedFiles = new Map();
+    const addExpectedFile = (name, file) => {
+      if (expectedFiles.has(name)) {
+        fail(`${manifestPath} aggregate carrier ${carrier.name} repeats expected member ${name}`);
+      }
+      expectedFiles.set(name, file);
+    };
+    const expectedBytes = Buffer.from(expectedText);
+    addExpectedFile(`${carrierRoot}/bundle-manifest.json`, {
+      bytes: expectedBytes.length,
+      sha256: createHash('sha256').update(expectedBytes).digest('hex'),
+    });
+    for (const member of expected.members) {
+      addExpectedFile(`${carrierRoot}/${member.path}`, member);
+    }
+    for (const legalFile of legalFiles) {
+      addExpectedFile(`${carrierRoot}/${legalFile.path}`, legalFile);
+    }
+    const requestedNames = new Set([
+      `${carrierRoot}/bundle-manifest.json`,
+      ...plan.selected.map(({ asset }) => `${asset.carrierRoot}/${asset.memberPath}`),
+    ]);
+    await verifyCanonicalArchive(carrierSnapshot, expectedFiles, stage, requestedNames);
+    await verifyFrozenFile(
+      carrierSnapshot,
+      carrier,
+      `${manifestPath} aggregate carrier ${carrier.name} immutable snapshot after extraction`,
+    );
+
+    const embeddedPath = join(stage, carrierRoot, 'bundle-manifest.json');
+    if (!isFile(embeddedPath)) {
+      fail(`${carrierPath} is missing a regular bundle-manifest.json`);
+    }
+    let embedded;
+    try {
+      embedded = JSON.parse(readFileSync(embeddedPath, 'utf8'));
+    } catch (error) {
+      fail(`${carrierPath} has invalid bundle-manifest.json: ${error.message}`);
+    }
+    if (
+      readFileSync(embeddedPath, 'utf8') !== expectedText ||
+      !isDeepStrictEqual(embedded, expected)
+    ) {
+      fail(
+        `${carrierPath} bundle-manifest.json does not exactly describe its product, compatibility, target, and nested members`,
+      );
+    }
+
+    for (const selected of plan.selected) {
+      const source = join(
+        stage,
+        selected.asset.carrierRoot,
+        ...selected.asset.memberPath.split('/'),
+      );
+      await verifyFrozenFile(
+        source,
+        selected.asset,
+        `${carrierPath} nested member ${selected.asset.carrierRoot}/${selected.asset.memberPath}`,
+      );
+      const destination = join(
+        safeMaterializeRoot,
+        manifest.product,
+        carrier.family,
+        carrier.target,
+        carrier.sha256,
+        selected.sqlName,
+        selected.asset.name,
+      );
+      selected.destination = await installCacheFile(
+        source,
+        destination,
+        selected.asset,
+        `${carrierPath} nested member ${selected.asset.memberPath}`,
+        safeMaterializeRoot,
+      );
+    }
+  } finally {
+    rmSync(stage, { recursive: true, force: true });
+  }
+}
+
+export async function resolveMobileExtensionArtifactPaths(argv) {
+  const options = parseOptions(argv);
+  const root = options.get('--root');
+  const artifactRoot = options.get('--artifact-root');
+  const materializeRoot = options.get('--materialize-root');
+  const selected = options
+    .get('--extensions')
+    .split(',')
+    .map((item) => item.trim())
+    .filter(Boolean);
+  const assetKind = options.get('--asset-kind');
+  const assetTarget = options.get('--asset-target');
+  const requiredValue = options.get('--required');
+  if (!new Set(['runtime', 'ios-xcframework']).has(assetKind)) {
+    fail(`unknown extension asset kind: ${assetKind}`, 2);
+  }
+  if (assetTarget !== '*' && !MOBILE_TARGETS.has(assetTarget)) {
+    fail(`unknown mobile extension asset target: ${assetTarget}`, 2);
+  }
+  if (!new Set(['0', '1']).has(requiredValue)) {
+    usage();
+  }
+  const required = requiredValue === '1';
+  if (new Set(selected).size !== selected.length) {
+    fail('selected exact-extension list must not contain duplicates');
+  }
+  const repositoryContract = await loadRepositoryContract(root);
+
+  const bySqlName = new Map();
+  for (const manifestPath of await manifestPaths(artifactRoot, repositoryContract)) {
+    let manifest;
+    try {
+      manifest = JSON.parse(await readFile(manifestPath, 'utf8'));
+    } catch (error) {
+      fail(`${manifestPath} is not valid JSON: ${error.message}`);
+    }
+    for (const [index, member] of manifestMembers(
+      manifest,
+      manifestPath,
+      repositoryContract,
+    ).entries()) {
+      if (!isObject(member)) {
+        fail(`${manifestPath} extension member ${index} must be an object`);
+      }
+      const sqlName = safeComponent(
+        member.sqlName,
+        `${manifestPath} extension member ${index} sqlName`,
+      );
+      if (bySqlName.has(sqlName)) {
+        fail(`duplicate exact-extension artifact package for SQL extension ${sqlName}`);
+      }
+      bySqlName.set(sqlName, { manifestPath, manifest, member, sqlName });
+    }
+  }
+
+  const resolved = new Array(selected.length);
+  const missing = [];
+  const bundlePlans = new Map();
+  for (const [index, sqlName] of selected.entries()) {
+    const entry = bySqlName.get(sqlName);
+    if (entry === undefined) {
+      missing.push(`${sqlName}: package`);
+      continue;
+    }
+    const assets = Array.isArray(entry.member.assets) ? entry.member.assets : [];
+    const matches = assets.filter((asset) => assetMatches(asset, assetKind, assetTarget));
+    if (matches.length === 0) {
+      missing.push(`${sqlName}: ${assetKind} asset`);
+      continue;
+    }
+    if (matches.length !== 1) {
+      fail(
+        `${entry.manifestPath} must contain exactly one ${assetKind} asset for ${sqlName}, got ${matches.length}`,
+      );
+    }
+    const asset = matches[0];
+    if (entry.manifest.schema === 'oliphaunt-extension-ci-artifacts-v1') {
+      validateDirectAsset(asset, entry, sqlName);
+      const file = join(dirname(entry.manifestPath), 'release-assets', asset.name);
+      if (!isFile(file)) {
+        missing.push(`${sqlName}: ${file}`);
+        continue;
+      }
+      await verifyFrozenFile(
+        file,
+        asset,
+        `${entry.manifestPath} ${assetKind} asset for ${sqlName}`,
+      );
+      resolved[index] = await materializeDirectAsset(entry, asset, file, materializeRoot);
+      continue;
+    }
+
+    const carrier = bundleCarrierFor(entry, asset);
+    const key = `${entry.manifestPath}\0${carrier.name}`;
+    const plan = bundlePlans.get(key) ?? {
+      manifest: entry.manifest,
+      manifestPath: entry.manifestPath,
+      carrier,
+      selected: [],
+    };
+    plan.selected.push({ index, sqlName, asset, destination: null });
+    bundlePlans.set(key, plan);
+  }
+
+  for (const plan of bundlePlans.values()) {
+    const carrierPath = join(dirname(plan.manifestPath), 'release-assets', plan.carrier.name);
+    if (!isFile(carrierPath)) {
+      missing.push(`${plan.manifest.product}: ${carrierPath}`);
+    }
+  }
+  if (missing.length > 0) {
+    fail(`missing exact-extension artifact(s): ${missing.join(', ')}`, required ? 1 : 3);
+  }
+
+  for (const plan of bundlePlans.values()) {
+    await materializeBundlePlan(plan, materializeRoot);
+    for (const selectedAsset of plan.selected) {
+      resolved[selectedAsset.index] = selectedAsset.destination;
+    }
+  }
+  if (resolved.some((file) => typeof file !== 'string' || file.length === 0)) {
+    fail('internal error: exact-extension artifact selection was not fully resolved');
+  }
+  return resolved;
+}
+
+if (import.meta.main) {
+  try {
+    for (const file of await resolveMobileExtensionArtifactPaths(Bun.argv.slice(2)))
+      console.log(file);
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(error instanceof CliFailure ? error.code : 1);
+  }
+}
diff --git a/src/sdks/react-native/tools/mobile-extension-artifact-paths.test.mts b/src/sdks/react-native/tools/mobile-extension-artifact-paths.test.mts
new file mode 100644
index 000000000..abeba7c4a
--- /dev/null
+++ b/src/sdks/react-native/tools/mobile-extension-artifact-paths.test.mts
@@ -0,0 +1,1152 @@
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import {
+  appendFileSync,
+  existsSync,
+  mkdirSync,
+  mkdtempSync,
+  readdirSync,
+  readFileSync,
+  rmSync,
+  statSync,
+  symlinkSync,
+  writeFileSync,
+} from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { gunzipSync } from 'node:zlib';
+import { canonicalGzipSync } from '../../../../tools/packaging/portable-archive.mts';
+import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts';
+import { extensionMetadata } from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  extensionCarrierLegalContract,
+  extensionCarrierLegalFileInventory,
+} from '../../../extensions/tools/extension-upstream-licenses.mts';
+import { resolveMobileExtensionArtifactPaths } from './mobile-extension-artifact-paths.mts';
+
+const REPOSITORY_ROOT = path.resolve(import.meta.dirname, '../../../..');
+const VERSION = '1.2.3';
+const NATIVE_RUNTIME_VERSION = readFileSync(
+  path.join(REPOSITORY_ROOT, 'src/runtimes/liboliphaunt-native/VERSION'),
+  'utf8',
+).trim();
+const CONTRIB_VERSION = NATIVE_RUNTIME_VERSION;
+const REACT_NATIVE_EXTENSIONS = JSON.parse(
+  readFileSync(path.join(REPOSITORY_ROOT, 'src/extensions/generated/sdk/extensions.json'), 'utf8'),
+).extensions;
+const REACT_NATIVE_EXTENSION_BY_SQL_NAME = new Map(
+  REACT_NATIVE_EXTENSIONS.map((row) => [row['sql-name'], row]),
+);
+const IOS_OVERLAY_BY_SQL_NAME = new Map(
+  JSON.parse(
+    readFileSync(
+      path.join(REPOSITORY_ROOT, 'src/extensions/generated/sdk/ios-static-dependencies.json'),
+      'utf8',
+    ),
+  ).extensions.map((row) => [row['sql-name'], row['static-dependencies']]),
+);
+const NATIVE_RELEASE_PRODUCT_BY_ARTIFACT_PRODUCT = new Map(
+  REACT_NATIVE_EXTENSIONS.map((row) => [row['artifact-product'], row['release-product']]),
+);
+const STATIC_EXTENSION_LINES = readFileSync(
+  path.join(REPOSITORY_ROOT, 'src/extensions/generated/mobile/static-extensions.tsv'),
+  'utf8',
+)
+  .split(/\r?\n/u)
+  .filter((line) => line.length > 0 && !line.startsWith('#'));
+const STATIC_EXTENSION_HEADER = STATIC_EXTENSION_LINES[0].split('\t');
+const STATIC_SQL_INDEX = STATIC_EXTENSION_HEADER.indexOf('sql-name');
+const STATIC_IOS_DEPENDENCY_INDEX = STATIC_EXTENSION_HEADER.indexOf('ios-static-dependencies');
+assert(STATIC_SQL_INDEX >= 0 && STATIC_IOS_DEPENDENCY_INDEX >= 0);
+const IOS_DEPENDENCIES_BY_SQL_NAME = new Map(
+  STATIC_EXTENSION_LINES.slice(1).map((line) => {
+    const fields = line.split('\t');
+    return [
+      fields[STATIC_SQL_INDEX],
+      (fields[STATIC_IOS_DEPENDENCY_INDEX] ?? '').split(',').filter(Boolean).sort(),
+    ];
+  }),
+);
+const COMPATIBILITY = extensionMetadata('oliphaunt-extension-contrib-pg18').compatibility;
+const CONTRIB = 'oliphaunt-extension-contrib-pg18';
+const VECTOR = 'oliphaunt-extension-vector';
+const TARGETS = ['android-arm64-v8a', 'android-x86_64', 'ios-xcframework'];
+const CONTRIB_SQL_NAMES = REACT_NATIVE_EXTENSIONS.filter(
+  (row) => row['artifact-product'] === CONTRIB,
+)
+  .map((row) => row['sql-name'])
+  .sort();
+
+function sha256(value) {
+  return createHash('sha256').update(value).digest('hex');
+}
+
+function sha256File(file) {
+  return sha256(readFileSync(file));
+}
+
+function writeJson(file, value) {
+  mkdirSync(path.dirname(file), { recursive: true });
+  writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
+}
+
+function sortValue(value) {
+  if (Array.isArray(value)) return value.map(sortValue);
+  if (value !== null && !Array.isArray(value) && typeof value === 'object') {
+    return Object.fromEntries(
+      Object.keys(value)
+        .sort()
+        .map((key) => [key, sortValue(value[key])]),
+    );
+  }
+  return value;
+}
+
+function canonicalJson(value) {
+  return `${JSON.stringify(sortValue(value), null, 2)}\n`;
+}
+
+function tarPathParts(archivePath) {
+  if (Buffer.byteLength(archivePath) <= 100) {
+    return { name: archivePath, prefix: '' };
+  }
+  const parts = archivePath.split('/');
+  for (let index = 1; index < parts.length; index += 1) {
+    const prefix = parts.slice(0, index).join('/');
+    const name = parts.slice(index).join('/');
+    if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) {
+      return { name, prefix };
+    }
+  }
+  throw new Error(`fixture path is too long for ustar: ${archivePath}`);
+}
+
+function writeTarString(buffer, offset, length, value) {
+  const bytes = Buffer.from(value);
+  assert(bytes.length <= length, `fixture ustar field overflow: ${value}`);
+  bytes.copy(buffer, offset);
+}
+
+function writeTarOctal(buffer, offset, length, value) {
+  const text = value.toString(8);
+  assert(text.length <= length - 1, `fixture ustar octal overflow: ${value}`);
+  writeTarString(buffer, offset, length, `${text.padStart(length - 1, '0')}\0`);
+}
+
+function tarHeader(archivePath, size) {
+  const header = Buffer.alloc(512);
+  const { name, prefix } = tarPathParts(archivePath);
+  writeTarString(header, 0, 100, name);
+  writeTarOctal(header, 100, 8, 0o644);
+  writeTarOctal(header, 108, 8, 0);
+  writeTarOctal(header, 116, 8, 0);
+  writeTarOctal(header, 124, 12, size);
+  writeTarOctal(header, 136, 12, 0);
+  header.fill(0x20, 148, 156);
+  writeTarString(header, 156, 1, '0');
+  writeTarString(header, 257, 6, 'ustar\0');
+  writeTarString(header, 263, 2, '00');
+  writeTarString(header, 345, 155, prefix);
+  const checksum = [...header].reduce((total, byte) => total + byte, 0).toString(8);
+  assert(checksum.length <= 6);
+  writeTarString(header, 148, 8, `${checksum.padStart(6, '0')}\0 `);
+  return header;
+}
+
+function writeCanonicalTarGzip(output, stage, archiveNames) {
+  const chunks = [];
+  for (const archiveName of [...archiveNames].sort()) {
+    const data = readFileSync(path.join(stage, ...archiveName.split('/')));
+    chunks.push(tarHeader(archiveName, data.length), data);
+    const remainder = data.length % 512;
+    if (remainder !== 0) {
+      chunks.push(Buffer.alloc(512 - remainder));
+    }
+  }
+  chunks.push(Buffer.alloc(1024));
+  writeFileSync(output, canonicalGzipSync(Buffer.concat(chunks)));
+}
+
+function rewriteFirstTarMode(output, mode) {
+  const tar = gunzipSync(readFileSync(output));
+  writeTarOctal(tar, 100, 8, mode);
+  tar.fill(0x20, 148, 156);
+  const checksum = [...tar.subarray(0, 512)].reduce((total, byte) => total + byte, 0).toString(8);
+  assert(checksum.length <= 6);
+  writeTarString(tar, 148, 8, `${checksum.padStart(6, '0')}\0 `);
+  writeFileSync(output, canonicalGzipSync(tar));
+}
+
+function extensionMember(sqlName, stagesIos = true) {
+  const row = REACT_NATIVE_EXTENSION_BY_SQL_NAME.get(sqlName);
+  assert(row, `missing generated React Native fixture metadata for ${sqlName}`);
+  const nativeModuleStem = row['native-module-stem'];
+  const generatedIosDependencies = [...(IOS_OVERLAY_BY_SQL_NAME.get(sqlName) ?? [])].sort();
+  assert.deepEqual(
+    generatedIosDependencies,
+    IOS_DEPENDENCIES_BY_SQL_NAME.get(sqlName) ?? [],
+    `${sqlName} generated RN and mobile-static iOS dependency contracts must agree`,
+  );
+  const iosNativeDependencies =
+    stagesIos && nativeModuleStem !== null ? generatedIosDependencies : [];
+  const prefix =
+    nativeModuleStem === null
+      ? null
+      : `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`;
+  return {
+    sqlName,
+    createsExtension: row['creates-extension'],
+    dependencies: [...row['selected-extension-dependencies']].sort(),
+    dataFiles: [...row['runtime-share-data-files']].sort(),
+    extensionSqlFileNames: [...row['extension-sql-file-names']].sort(),
+    extensionSqlFilePrefixes: [...row['extension-sql-file-prefixes']].sort(),
+    nativeModuleStem,
+    iosNativeDependencies,
+    iosRegistration:
+      nativeModuleStem === null || !stagesIos
+        ? null
+        : {
+            initSymbol: null,
+            magicSymbol: `${prefix}_Pg_magic_func`,
+            nativeModuleStem,
+            schema: 'oliphaunt-ios-extension-registration-v1',
+            sqlName,
+            symbols: [],
+          },
+    wasixInstall: null,
+    sharedPreloadLibraries: [...row['shared-preload-libraries']].sort(),
+    assets: [],
+  };
+}
+
+function fixture(t) {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-mobile-extension-artifacts-'));
+  const artifactRoot = path.join(root, 'extension-artifacts');
+  const materializeRoot = path.join(root, 'materialized');
+  mkdirSync(artifactRoot, { recursive: true });
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+
+  function productRoot(product) {
+    const releaseProduct = NATIVE_RELEASE_PRODUCT_BY_ARTIFACT_PRODUCT.get(product);
+    assert(releaseProduct, `fixture requires a native release owner for ${product}`);
+    return path.join(
+      artifactRoot,
+      ...(releaseProduct === product ? [product] : [releaseProduct, product]),
+    );
+  }
+
+  function publishedProductRoot(product) {
+    const releaseProduct = NATIVE_RELEASE_PRODUCT_BY_ARTIFACT_PRODUCT.get(product);
+    assert(releaseProduct, `fixture requires a native release owner for ${product}`);
+    return [
+      'target/extension-artifacts',
+      ...(releaseProduct === product ? [product] : [releaseProduct, product]),
+    ].join('/');
+  }
+
+  function manifestPath(product) {
+    return path.join(productRoot(product), 'extension-artifacts.json');
+  }
+
+  function writeManifest(product, value) {
+    writeJson(manifestPath(product), value);
+  }
+
+  async function resolve({ extensions, assetKind, assetTarget, required = '1', extraArgs = [] }) {
+    try {
+      const files = await resolveMobileExtensionArtifactPaths([
+        '--root',
+        REPOSITORY_ROOT,
+        '--artifact-root',
+        artifactRoot,
+        '--materialize-root',
+        materializeRoot,
+        '--extensions',
+        extensions,
+        '--asset-kind',
+        assetKind,
+        '--asset-target',
+        assetTarget,
+        '--required',
+        required,
+        ...extraArgs,
+      ]);
+      return { status: 0, stdout: files.join('\n') + '\n', stderr: '' };
+    } catch (error) {
+      return { status: error.code ?? 1, stdout: '', stderr: String(error) };
+    }
+  }
+
+  function installAggregate({
+    targets = TARGETS,
+    embeddedMutator = (value) => value,
+    tamperNested = null,
+    tamperLegal = null,
+    omitLegal = null,
+    extraArchiveMember = null,
+    duplicatePhysicalRolePath = false,
+  } = {}) {
+    const members = CONTRIB_SQL_NAMES.map((sqlName) =>
+      extensionMember(sqlName, targets.includes('ios-xcframework')),
+    );
+    const manifest = {
+      schema: 'oliphaunt-extension-ci-artifacts-v2',
+      product: CONTRIB,
+      releaseProduct: 'liboliphaunt-native',
+      family: 'native',
+      version: CONTRIB_VERSION,
+      compatibility: COMPATIBILITY,
+      extensions: members,
+      carrierAssets: [],
+    };
+    const carriersByTarget = new Map();
+    const declaredContents = new Map();
+
+    for (const target of targets) {
+      const carrierRoot = `${CONTRIB}-${CONTRIB_VERSION}-native-${target}-bundle`;
+      const carrierName = `${carrierRoot}.tar.gz`;
+      const rows = [];
+      const stage = path.join(root, 'bundle-stage', target);
+      rmSync(stage, { recursive: true, force: true });
+      mkdirSync(stage, { recursive: true });
+
+      for (const member of members) {
+        const roles = [
+          { identity: null, kind: 'runtime' },
+          ...(target === 'ios-xcframework' && member.nativeModuleStem !== null
+            ? [
+                { identity: member.nativeModuleStem, kind: 'ios-xcframework' },
+                ...member.iosNativeDependencies.map((identity) => ({
+                  identity,
+                  kind: 'ios-dependency-xcframework',
+                })),
+              ]
+            : []),
+        ];
+        for (const { identity, kind } of roles) {
+          const duplicatesRuntimePath =
+            duplicatePhysicalRolePath &&
+            target === 'ios-xcframework' &&
+            member.sqlName === 'cube' &&
+            kind === 'ios-xcframework';
+          const name =
+            kind === 'runtime' || duplicatesRuntimePath
+              ? target === 'ios-xcframework'
+                ? `${CONTRIB}-${CONTRIB_VERSION}-native-ios-runtime.tar.gz`
+                : `${CONTRIB}-${CONTRIB_VERSION}-native-${target}-runtime.tar.gz`
+              : kind === 'ios-xcframework'
+                ? `${CONTRIB}-${CONTRIB_VERSION}-native-ios-xcframework.zip`
+                : `${CONTRIB}-${CONTRIB_VERSION}-native-ios-dependency-${identity}-xcframework.zip`;
+          const memberPath = `extensions/${member.sqlName}/${name}`;
+          const declaredKind = duplicatesRuntimePath ? 'runtime' : kind;
+          const declared = Buffer.from(`declared:${target}:${member.sqlName}:${declaredKind}\n`);
+          const nestedKey =
+            `${target}:${member.sqlName}:${kind}` +
+            (kind === 'ios-dependency-xcframework' ? `:${identity}` : '');
+          const archived =
+            tamperNested === nestedKey
+              ? Buffer.from(`tampered:${target}:${member.sqlName}:${kind}\n`)
+              : declared;
+          const asset = {
+            name,
+            path: `${publishedProductRoot(CONTRIB)}/member-assets/${member.sqlName}/${name}`,
+            source: `target/extensions/native/release-assets/${target}/${name}`,
+            sha256: sha256(declared),
+            bytes: declared.length,
+            family: 'native',
+            kind,
+            target,
+            identity,
+            carrierAsset: carrierName,
+            carrierRoot,
+            memberPath,
+          };
+          member.assets.push(asset);
+          rows.push({
+            sqlName: member.sqlName,
+            kind,
+            identity,
+            path: memberPath,
+            sha256: asset.sha256,
+            bytes: asset.bytes,
+          });
+          declaredContents.set(nestedKey, declared);
+          const stagedMember = path.join(stage, carrierRoot, ...memberPath.split('/'));
+          mkdirSync(path.dirname(stagedMember), { recursive: true });
+          writeFileSync(stagedMember, archived);
+        }
+      }
+
+      rows.sort((left, right) => {
+        const leftKey = `${left.sqlName}\0${left.kind}\0${left.identity ?? ''}`;
+        const rightKey = `${right.sqlName}\0${right.kind}\0${right.identity ?? ''}`;
+        return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0;
+      });
+      const legal = extensionCarrierLegalContract(CONTRIB, CONTRIB_SQL_NAMES, {
+        family: 'native',
+        target,
+      });
+      const embedded = embeddedMutator(
+        {
+          schema: 'oliphaunt-extension-bundle-v1',
+          product: CONTRIB,
+          version: CONTRIB_VERSION,
+          compatibility: COMPATIBILITY,
+          family: 'native',
+          target,
+          licenseProfile: legal.profile,
+          licenseFiles: legal.licenseFiles,
+          members: rows,
+        },
+        target,
+      );
+      const embeddedPath = path.join(stage, carrierRoot, 'bundle-manifest.json');
+      mkdirSync(path.dirname(embeddedPath), { recursive: true });
+      writeFileSync(embeddedPath, canonicalJson(embedded));
+      stageReleaseNotices(path.join(stage, carrierRoot), { profile: legal.profile });
+      const legalFiles = extensionCarrierLegalFileInventory(CONTRIB, CONTRIB_SQL_NAMES, {
+        family: 'native',
+        target,
+      });
+      if (tamperLegal !== null) {
+        const legalPath = path.join(stage, carrierRoot, ...tamperLegal.split('/'));
+        const bytes = readFileSync(legalPath);
+        assert(bytes.length > 0, `${tamperLegal} fixture must not be empty`);
+        bytes[0] ^= 0xff;
+        writeFileSync(legalPath, bytes);
+      }
+      if (extraArchiveMember !== null) {
+        const extraPath = path.join(stage, carrierRoot, ...extraArchiveMember.split('/'));
+        mkdirSync(path.dirname(extraPath), { recursive: true });
+        writeFileSync(extraPath, 'undeclared bundle member\n');
+      }
+
+      const releaseAssets = path.join(productRoot(CONTRIB), 'release-assets');
+      mkdirSync(releaseAssets, { recursive: true });
+      const carrierPath = path.join(releaseAssets, carrierName);
+      const archiveNames = [
+        `${carrierRoot}/bundle-manifest.json`,
+        ...rows.map((row) => `${carrierRoot}/${row.path}`),
+        ...legalFiles.map((file) => `${carrierRoot}/${file.path}`),
+        ...(extraArchiveMember === null ? [] : [`${carrierRoot}/${extraArchiveMember}`]),
+      ].filter((name) => name !== `${carrierRoot}/${omitLegal}`);
+      const uniqueArchiveNames = [...new Set(archiveNames)].sort();
+      writeCanonicalTarGzip(carrierPath, stage, uniqueArchiveNames);
+      const carrier = {
+        name: carrierName,
+        path: `${publishedProductRoot(CONTRIB)}/release-assets/${carrierName}`,
+        sha256: sha256File(carrierPath),
+        bytes: statSync(carrierPath).size,
+        family: 'native',
+        target,
+        kind: 'extension-bundle',
+        memberCount: members.length,
+      };
+      manifest.carrierAssets.push(carrier);
+      carriersByTarget.set(target, { carrier, carrierPath });
+      rmSync(stage, { recursive: true, force: true });
+    }
+    rmSync(path.join(root, 'bundle-stage'), { recursive: true, force: true });
+    writeManifest(CONTRIB, manifest);
+    return { manifest, carriersByTarget, declaredContents };
+  }
+
+  function installLeaf() {
+    const assets = [];
+    const contents = new Map();
+    const releaseAssets = path.join(productRoot(VECTOR), 'release-assets');
+    mkdirSync(releaseAssets, { recursive: true });
+    for (const target of TARGETS) {
+      const kinds = target === 'ios-xcframework' ? ['runtime', 'ios-xcframework'] : ['runtime'];
+      for (const kind of kinds) {
+        const name =
+          kind === 'runtime'
+            ? target === 'ios-xcframework'
+              ? `${VECTOR}-${VERSION}-native-ios-runtime.tar.gz`
+              : `${VECTOR}-${VERSION}-native-${target}-runtime.tar.gz`
+            : `${VECTOR}-${VERSION}-native-ios-xcframework.zip`;
+        const file = path.join(releaseAssets, name);
+        const content = Buffer.from(`leaf:${target}:${kind}\n`);
+        writeFileSync(file, content);
+        assets.push({
+          name,
+          path: `${publishedProductRoot(VECTOR)}/release-assets/${name}`,
+          source: `target/extensions/native/release-assets/${target}/${name}`,
+          sha256: sha256(content),
+          bytes: content.length,
+          family: 'native',
+          kind,
+          target,
+          identity: kind === 'runtime' ? null : 'vector',
+        });
+        contents.set(`${target}:${kind}`, content);
+      }
+    }
+    const manifest = {
+      schema: 'oliphaunt-extension-ci-artifacts-v1',
+      product: VECTOR,
+      version: VERSION,
+      compatibility: COMPATIBILITY,
+      ...extensionMember('vector'),
+      assets,
+    };
+    writeManifest(VECTOR, manifest);
+    return { manifest, contents, releaseAssets };
+  }
+
+  return {
+    artifactRoot,
+    installAggregate,
+    installLeaf,
+    manifestPath,
+    materializeRoot,
+    productRoot,
+    root,
+    resolve,
+    writeManifest,
+  };
+}
+
+function outputPaths(result) {
+  assert.equal(result.status, 0, result.stderr);
+  return result.stdout.trim().split(/\r?\n/u).filter(Boolean);
+}
+
+function assertContents(files, expected) {
+  assert.equal(files.length, expected.length);
+  for (const [index, file] of files.entries()) {
+    assert.deepEqual(readFileSync(file), expected[index]);
+  }
+}
+
+test('materializes aggregate and singleton assets into immutable content-addressed paths', async (t) => {
+  const value = fixture(t);
+  const aggregate = value.installAggregate();
+  const leaf = value.installLeaf();
+  assert.equal(existsSync(path.join(value.productRoot(CONTRIB), 'member-assets')), false);
+
+  for (const target of ['android-arm64-v8a', 'android-x86_64']) {
+    const files = outputPaths(
+      await value.resolve({
+        extensions: 'amcheck,cube,vector',
+        assetKind: 'runtime',
+        assetTarget: target,
+      }),
+    );
+    assertContents(files, [
+      aggregate.declaredContents.get(`${target}:amcheck:runtime`),
+      aggregate.declaredContents.get(`${target}:cube:runtime`),
+      leaf.contents.get(`${target}:runtime`),
+    ]);
+    assert(files[0].startsWith(value.materializeRoot));
+    assert(files[1].startsWith(value.materializeRoot));
+    assert(files[2].startsWith(value.materializeRoot));
+    assert(!files[2].startsWith(path.join(value.productRoot(VECTOR), 'release-assets')));
+    assert(files.every((file) => !file.includes('member-assets')));
+    const directAsset = leaf.manifest.assets.find(
+      (asset) => asset.target === target && asset.kind === 'runtime',
+    );
+    writeFileSync(path.join(leaf.releaseAssets, directAsset.name), 'mutated published source\n');
+    assert.deepEqual(
+      readFileSync(files[2]),
+      leaf.contents.get(`${target}:runtime`),
+      'resolved singleton path must not alias mutable release-assets input',
+    );
+  }
+
+  const iosRuntime = outputPaths(
+    await value.resolve({
+      extensions: 'amcheck,cube,vector',
+      assetKind: 'runtime',
+      assetTarget: 'ios-xcframework',
+    }),
+  );
+  assertContents(iosRuntime, [
+    aggregate.declaredContents.get('ios-xcframework:amcheck:runtime'),
+    aggregate.declaredContents.get('ios-xcframework:cube:runtime'),
+    leaf.contents.get('ios-xcframework:runtime'),
+  ]);
+
+  const iosFrameworks = outputPaths(
+    await value.resolve({
+      extensions: 'cube,vector',
+      assetKind: 'ios-xcframework',
+      assetTarget: 'ios-xcframework',
+    }),
+  );
+  assertContents(iosFrameworks, [
+    aggregate.declaredContents.get('ios-xcframework:cube:ios-xcframework'),
+    leaf.contents.get('ios-xcframework:ios-xcframework'),
+  ]);
+});
+
+test('rejects outer and nested carrier tampering independently', async (t) => {
+  const outer = fixture(t);
+  const outerAggregate = outer.installAggregate({ targets: ['android-arm64-v8a'] });
+  appendFileSync(outerAggregate.carriersByTarget.get('android-arm64-v8a').carrierPath, 'tamper');
+  const outerResult = await outer.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(outerResult.status, 1);
+  assert.match(outerResult.stderr, /aggregate carrier .* does not match its frozen size\/digest/u);
+
+  const nested = fixture(t);
+  nested.installAggregate({
+    targets: ['android-arm64-v8a'],
+    tamperNested: 'android-arm64-v8a:amcheck:runtime',
+  });
+  const nestedResult = await nested.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(nestedResult.status, 1);
+  assert.match(nestedResult.stderr, /member .* does not match its canonical SHA-256/u);
+});
+
+test('binds the production bundle manifest and exact legal-file closure', async (t) => {
+  const valid = fixture(t);
+  valid.installAggregate({ targets: ['android-arm64-v8a'] });
+  outputPaths(
+    await valid.resolve({
+      extensions: 'amcheck',
+      assetKind: 'runtime',
+      assetTarget: 'android-arm64-v8a',
+    }),
+  );
+
+  const tampered = fixture(t);
+  tampered.installAggregate({
+    targets: ['android-arm64-v8a'],
+    tamperLegal: 'LICENSE',
+  });
+  const tamperedResult = await tampered.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(tamperedResult.status, 1);
+  assert.match(tamperedResult.stderr, /LICENSE.*does not match its canonical SHA-256/u);
+
+  const missing = fixture(t);
+  missing.installAggregate({
+    targets: ['android-arm64-v8a'],
+    omitLegal: 'THIRD_PARTY_NOTICES.md',
+  });
+  const missingResult = await missing.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(missingResult.status, 1);
+  assert.match(missingResult.stderr, /exact two-block ustar marker/u);
+
+  const extra = fixture(t);
+  extra.installAggregate({
+    targets: ['android-arm64-v8a'],
+    extraArchiveMember: 'UNDECLARED-LEGAL.txt',
+  });
+  const extraResult = await extra.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(extraResult.status, 1);
+  assert.match(extraResult.stderr, /UNDECLARED-LEGAL\.txt.*undeclared/u);
+
+  const staleManifest = fixture(t);
+  staleManifest.installAggregate({
+    targets: ['android-arm64-v8a'],
+    embeddedMutator: (value) => {
+      const { licenseProfile: _licenseProfile, ...legacy } = value;
+      return legacy;
+    },
+  });
+  const staleManifestResult = await staleManifest.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(staleManifestResult.status, 1);
+  assert.match(staleManifestResult.stderr, /bundle-manifest\.json.*wrong ustar size/u);
+});
+
+test('rejects unsupported outer and embedded bundle schemas', async (t) => {
+  const outer = fixture(t);
+  outer.writeManifest(VECTOR, {
+    schema: 'oliphaunt-extension-ci-artifacts-v3',
+    product: 'bad-extension',
+    version: VERSION,
+    compatibility: COMPATIBILITY,
+    sqlName: 'bad',
+    assets: [],
+  });
+  const outerResult = await outer.resolve({
+    extensions: 'bad',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(outerResult.status, 1);
+  assert.match(outerResult.stderr, /unsupported extension artifact schema/u);
+
+  const embedded = fixture(t);
+  embedded.installAggregate({
+    targets: ['android-arm64-v8a'],
+    embeddedMutator: (value) => ({ ...value, schema: 'oliphaunt-extension-bundle-v2' }),
+  });
+  const embeddedResult = await embedded.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(embeddedResult.status, 1);
+  assert.match(embeddedResult.stderr, /bundle-manifest\.json.*canonical SHA-256/u);
+});
+
+test('rejects noncanonical public evidence-envelope key sets', async (t) => {
+  const bundleRoot = fixture(t);
+  const bundleRootAggregate = bundleRoot.installAggregate({ targets: ['android-arm64-v8a'] });
+  bundleRootAggregate.manifest.unexpected = true;
+  bundleRoot.writeManifest(CONTRIB, bundleRootAggregate.manifest);
+  const bundleRootResult = await bundleRoot.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(bundleRootResult.status, 1);
+  assert.match(bundleRootResult.stderr, /fields must be exactly .* got .*unexpected/u);
+
+  const bundleMember = fixture(t);
+  const bundleMemberAggregate = bundleMember.installAggregate({ targets: ['android-arm64-v8a'] });
+  delete bundleMemberAggregate.manifest.extensions[0].sharedPreloadLibraries;
+  bundleMember.writeManifest(CONTRIB, bundleMemberAggregate.manifest);
+  const bundleMemberResult = await bundleMember.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(bundleMemberResult.status, 1);
+  assert.match(bundleMemberResult.stderr, /extension member 0 fields must be exactly/u);
+
+  const bundleAsset = fixture(t);
+  const bundleAssetAggregate = bundleAsset.installAggregate({ targets: ['android-arm64-v8a'] });
+  bundleAssetAggregate.manifest.extensions[0].assets[0].unexpected = 'value';
+  bundleAsset.writeManifest(CONTRIB, bundleAssetAggregate.manifest);
+  const bundleAssetResult = await bundleAsset.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(bundleAssetResult.status, 1);
+  assert.match(bundleAssetResult.stderr, /extension member 0 asset 0 fields must be exactly/u);
+
+  const bundleCarrier = fixture(t);
+  const bundleCarrierAggregate = bundleCarrier.installAggregate({ targets: ['android-arm64-v8a'] });
+  delete bundleCarrierAggregate.manifest.carrierAssets[0].memberCount;
+  bundleCarrier.writeManifest(CONTRIB, bundleCarrierAggregate.manifest);
+  const bundleCarrierResult = await bundleCarrier.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(bundleCarrierResult.status, 1);
+  assert.match(bundleCarrierResult.stderr, /aggregate carrier 0 fields must be exactly/u);
+
+  const directRoot = fixture(t);
+  const directRootLeaf = directRoot.installLeaf();
+  directRootLeaf.manifest.unexpected = true;
+  directRoot.writeManifest(VECTOR, directRootLeaf.manifest);
+  const directRootResult = await directRoot.resolve({
+    extensions: 'vector',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(directRootResult.status, 1);
+  assert.match(directRootResult.stderr, /fields must be exactly .* got .*unexpected/u);
+
+  const directAsset = fixture(t);
+  const directAssetLeaf = directAsset.installLeaf();
+  directAssetLeaf.manifest.assets[0].unexpected = 'value';
+  directAsset.writeManifest(VECTOR, directAssetLeaf.manifest);
+  const directAssetResult = await directAsset.resolve({
+    extensions: 'vector',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(directAssetResult.status, 1);
+  assert.match(directAssetResult.stderr, /asset 0 fields must be exactly/u);
+});
+
+test('rejects duplicate extension, carrier, and nested member identities', async (t) => {
+  const extensionDuplicate = fixture(t);
+  const duplicateManifest = {
+    schema: 'oliphaunt-extension-ci-artifacts-v2',
+    product: CONTRIB,
+    releaseProduct: 'liboliphaunt-native',
+    family: 'native',
+    version: CONTRIB_VERSION,
+    compatibility: COMPATIBILITY,
+    extensions: [extensionMember('amcheck', false), extensionMember('amcheck', false)],
+    carrierAssets: [],
+  };
+  extensionDuplicate.writeManifest(CONTRIB, duplicateManifest);
+  const extensionResult = await extensionDuplicate.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(extensionResult.status, 1);
+  assert.match(extensionResult.stderr, /repeats an extension SQL identity/u);
+
+  const carrierDuplicate = fixture(t);
+  const carrierAggregate = carrierDuplicate.installAggregate({ targets: ['android-arm64-v8a'] });
+  carrierAggregate.manifest.carrierAssets.push({ ...carrierAggregate.manifest.carrierAssets[0] });
+  carrierDuplicate.writeManifest(CONTRIB, carrierAggregate.manifest);
+  const carrierResult = await carrierDuplicate.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(carrierResult.status, 1);
+  assert.match(carrierResult.stderr, /exactly one native extension-bundle carrier/u);
+
+  const memberDuplicate = fixture(t);
+  const memberAggregate = memberDuplicate.installAggregate({ targets: ['android-arm64-v8a'] });
+  const amcheck = memberAggregate.manifest.extensions.find(
+    (member) => member.sqlName === 'amcheck',
+  );
+  amcheck.assets.push({ ...amcheck.assets[0] });
+  memberDuplicate.writeManifest(CONTRIB, memberAggregate.manifest);
+  const memberResult = await memberDuplicate.resolve({
+    extensions: 'cube',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(memberResult.status, 1);
+  assert.match(memberResult.stderr, /mobile artifact roles are not exact and dependency-closed/u);
+
+  const physicalPathDuplicate = fixture(t);
+  physicalPathDuplicate.installAggregate({
+    targets: ['ios-xcframework'],
+    duplicatePhysicalRolePath: true,
+  });
+  const physicalPathResult = await physicalPathDuplicate.resolve({
+    extensions: 'cube',
+    assetKind: 'ios-xcframework',
+    assetTarget: 'ios-xcframework',
+  });
+  assert.equal(physicalPathResult.status, 1);
+  assert.match(physicalPathResult.stderr, /repeats nested member path/u);
+});
+
+test('binds aggregate ownership and compatibility to generated repository metadata', async (t) => {
+  for (const [field, value] of [
+    ['releaseProduct', 'liboliphaunt-wasix'],
+    ['family', 'wasix'],
+  ]) {
+    const ownership = fixture(t);
+    const aggregate = ownership.installAggregate({ targets: ['android-arm64-v8a'] });
+    aggregate.manifest[field] = value;
+    ownership.writeManifest(CONTRIB, aggregate.manifest);
+    const result = await ownership.resolve({
+      extensions: 'amcheck',
+      assetKind: 'runtime',
+      assetTarget: 'android-arm64-v8a',
+    });
+    assert.equal(result.status, 1);
+    assert.match(result.stderr, /must be owned by liboliphaunt-native\/native/u);
+  }
+
+  const subset = fixture(t);
+  const subsetAggregate = subset.installAggregate({ targets: ['android-arm64-v8a'] });
+  subsetAggregate.manifest.extensions.pop();
+  subset.writeManifest(CONTRIB, subsetAggregate.manifest);
+  const subsetResult = await subset.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(subsetResult.status, 1);
+  assert.match(subsetResult.stderr, /member set must exactly match generated owner/u);
+
+  const compatibility = fixture(t);
+  const compatibilityAggregate = compatibility.installAggregate({ targets: ['android-arm64-v8a'] });
+  compatibilityAggregate.manifest.compatibility = {
+    ...compatibilityAggregate.manifest.compatibility,
+    nativeRuntimeVersion: '9.9.9',
+  };
+  compatibility.writeManifest(CONTRIB, compatibilityAggregate.manifest);
+  const compatibilityResult = await compatibility.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(compatibilityResult.status, 1);
+  assert.match(compatibilityResult.stderr, /compatibility metadata must exactly match/u);
+
+  const semantics = fixture(t);
+  const semanticsAggregate = semantics.installAggregate({ targets: ['android-arm64-v8a'] });
+  semanticsAggregate.manifest.extensions
+    .find(({ sqlName }) => sqlName === 'amcheck')
+    .dataFiles.push('forged/catalog.dat');
+  semantics.writeManifest(CONTRIB, semanticsAggregate.manifest);
+  const semanticsResult = await semantics.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(semanticsResult.status, 1);
+  assert.match(
+    semanticsResult.stderr,
+    /\.dataFiles must exactly match generated React Native extension metadata/u,
+  );
+
+  for (const [field, forgedValue] of [
+    ['extensionSqlFileNames', 'forged-install.sql'],
+    ['extensionSqlFilePrefixes', 'forged-prefix'],
+  ]) {
+    const sqlOwnership = fixture(t);
+    const sqlOwnershipAggregate = sqlOwnership.installAggregate({ targets: ['android-arm64-v8a'] });
+    sqlOwnershipAggregate.manifest.extensions
+      .find(({ sqlName }) => sqlName === 'amcheck')
+      [field].push(forgedValue);
+    sqlOwnership.writeManifest(CONTRIB, sqlOwnershipAggregate.manifest);
+    const sqlOwnershipResult = await sqlOwnership.resolve({
+      extensions: 'amcheck',
+      assetKind: 'runtime',
+      assetTarget: 'android-arm64-v8a',
+    });
+    assert.equal(sqlOwnershipResult.status, 1);
+    assert.match(
+      sqlOwnershipResult.stderr,
+      new RegExp(`\\.${field} must exactly match generated React Native extension metadata`, 'u'),
+    );
+  }
+
+  const dependencyClosure = fixture(t);
+  const dependencyAggregate = dependencyClosure.installAggregate({ targets: ['ios-xcframework'] });
+  const pgcrypto = dependencyAggregate.manifest.extensions.find(
+    ({ sqlName }) => sqlName === 'pgcrypto',
+  );
+  assert.deepEqual(pgcrypto.iosNativeDependencies, ['openssl']);
+  pgcrypto.assets = pgcrypto.assets.filter(
+    (asset) => !(asset.kind === 'ios-dependency-xcframework' && asset.identity === 'openssl'),
+  );
+  dependencyClosure.writeManifest(CONTRIB, dependencyAggregate.manifest);
+  const dependencyResult = await dependencyClosure.resolve({
+    extensions: 'pgcrypto',
+    assetKind: 'runtime',
+    assetTarget: 'ios-xcframework',
+  });
+  assert.equal(dependencyResult.status, 1);
+  assert.match(
+    dependencyResult.stderr,
+    /mobile artifact roles are not exact and dependency-closed/u,
+  );
+
+  const registration = fixture(t);
+  const registrationAggregate = registration.installAggregate({ targets: ['ios-xcframework'] });
+  registrationAggregate.manifest.extensions.find(
+    ({ sqlName }) => sqlName === 'cube',
+  ).iosRegistration.schema = 'unfrozen-registration-v2';
+  registration.writeManifest(CONTRIB, registrationAggregate.manifest);
+  const registrationResult = await registration.resolve({
+    extensions: 'cube',
+    assetKind: 'ios-xcframework',
+    assetTarget: 'ios-xcframework',
+  });
+  assert.equal(registrationResult.status, 1);
+  assert.match(registrationResult.stderr, /does not match canonical native module identity/u);
+});
+
+test('rejects cache path escapes, noncanonical ustar metadata, and invalid CLI flags', async (t) => {
+  const escaping = fixture(t);
+  const escapeAggregate = escaping.installAggregate({ targets: ['android-arm64-v8a'] });
+  const escapeCarrier = escapeAggregate.manifest.carrierAssets[0];
+  const escapedName = `${CONTRIB}-${CONTRIB_VERSION}-native-..-bundle.tar.gz`;
+  escapeCarrier.target = '..';
+  escapeCarrier.name = escapedName;
+  escapeCarrier.path = `${escapeCarrier.path.slice(0, escapeCarrier.path.lastIndexOf('/') + 1)}${escapedName}`;
+  for (const member of escapeAggregate.manifest.extensions) {
+    for (const asset of member.assets) {
+      asset.target = '..';
+      asset.carrierAsset = escapedName;
+      asset.carrierRoot = escapedName.replace(/\.tar\.gz$/u, '');
+    }
+  }
+  escaping.writeManifest(CONTRIB, escapeAggregate.manifest);
+  const escapeResult = await escaping.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: '*',
+  });
+  assert.equal(escapeResult.status, 1);
+  assert.match(
+    escapeResult.stderr,
+    /aggregate carrier target must be a safe non-empty path component/u,
+  );
+
+  const canonical = fixture(t);
+  const canonicalAggregate = canonical.installAggregate({ targets: ['android-arm64-v8a'] });
+  const canonicalCarrier = canonicalAggregate.carriersByTarget.get('android-arm64-v8a');
+  rewriteFirstTarMode(canonicalCarrier.carrierPath, 0o600);
+  canonicalCarrier.carrier.bytes = statSync(canonicalCarrier.carrierPath).size;
+  canonicalCarrier.carrier.sha256 = sha256File(canonicalCarrier.carrierPath);
+  canonical.writeManifest(CONTRIB, canonicalAggregate.manifest);
+  const canonicalResult = await canonical.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(canonicalResult.status, 1);
+  assert.match(canonicalResult.stderr, /must use mode=0644 uid=0 gid=0 mtime=0/u);
+
+  const gzip = fixture(t);
+  const gzipAggregate = gzip.installAggregate({ targets: ['android-arm64-v8a'] });
+  const gzipCarrier = gzipAggregate.carriersByTarget.get('android-arm64-v8a');
+  const gzipBytes = readFileSync(gzipCarrier.carrierPath);
+  gzipBytes[9] = 0;
+  writeFileSync(gzipCarrier.carrierPath, gzipBytes);
+  gzipCarrier.carrier.bytes = statSync(gzipCarrier.carrierPath).size;
+  gzipCarrier.carrier.sha256 = sha256File(gzipCarrier.carrierPath);
+  gzip.writeManifest(CONTRIB, gzipAggregate.manifest);
+  const gzipResult = await gzip.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(gzipResult.status, 1);
+  assert.match(gzipResult.stderr, /canonical gzip method, flags, mtime, XFL, and OS header/u);
+
+  const oversized = fixture(t);
+  const oversizedLeaf = oversized.installLeaf();
+  oversizedLeaf.manifest.assets.find(
+    (asset) => asset.target === 'android-arm64-v8a' && asset.kind === 'runtime',
+  ).bytes = 2 * 1024 * 1024 * 1024 + 1;
+  oversized.writeManifest(VECTOR, oversizedLeaf.manifest);
+  const oversizedResult = await oversized.resolve({
+    extensions: 'vector',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(oversizedResult.status, 1);
+  assert.match(oversizedResult.stderr, /exceeds the maximum supported size/u);
+
+  const flags = fixture(t);
+  const unknownFlag = await flags.resolve({
+    extensions: 'missing',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+    extraArgs: ['--unknown', 'value'],
+  });
+  assert.equal(unknownFlag.status, 2);
+  assert.match(unknownFlag.stderr, /unknown option: --unknown/u);
+  const duplicateFlag = await flags.resolve({
+    extensions: 'missing',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+    extraArgs: ['--required', '1'],
+  });
+  assert.equal(duplicateFlag.status, 2);
+  assert.match(duplicateFlag.stderr, /duplicate option: --required/u);
+});
+
+test('rejects pre-existing materialization-cache symlink redirection', async (t) => {
+  const component = fixture(t);
+  component.installAggregate({ targets: ['android-arm64-v8a'] });
+  const redirected = path.join(component.root, 'redirected-component');
+  mkdirSync(component.materializeRoot, { recursive: true });
+  mkdirSync(redirected, { recursive: true });
+  symlinkSync(redirected, path.join(component.materializeRoot, CONTRIB), 'dir');
+  const componentResult = await component.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(componentResult.status, 1);
+  assert.match(
+    componentResult.stderr,
+    /cache path component must be a real directory, not a symlink/u,
+  );
+  assert.deepEqual(
+    readdirSync(redirected),
+    [],
+    'a rejected cache symlink must not receive materialized bytes',
+  );
+
+  const rootLink = fixture(t);
+  rootLink.installAggregate({ targets: ['android-arm64-v8a'] });
+  const redirectedRoot = path.join(rootLink.root, 'redirected-root');
+  mkdirSync(redirectedRoot, { recursive: true });
+  symlinkSync(redirectedRoot, rootLink.materializeRoot, 'dir');
+  const rootResult = await rootLink.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(rootResult.status, 1);
+  assert.match(rootResult.stderr, /cache root must be a real directory, not a symlink/u);
+  assert.deepEqual(
+    readdirSync(redirectedRoot),
+    [],
+    'a rejected cache-root symlink must not receive extraction state',
+  );
+
+  const direct = fixture(t);
+  const leaf = direct.installLeaf();
+  const asset = leaf.manifest.assets.find(
+    (row) => row.kind === 'runtime' && row.target === 'android-arm64-v8a',
+  );
+  const destination = path.join(
+    direct.materializeRoot,
+    VECTOR,
+    'direct',
+    'native',
+    'android-arm64-v8a',
+    asset.sha256,
+    'vector',
+    asset.name,
+  );
+  const redirectedFile = path.join(direct.root, 'redirected-direct-file');
+  mkdirSync(path.dirname(destination), { recursive: true });
+  writeFileSync(redirectedFile, 'must remain unchanged\n');
+  symlinkSync(redirectedFile, destination, 'file');
+  const directResult = await direct.resolve({
+    extensions: 'vector',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+  });
+  assert.equal(directResult.status, 1);
+  assert.match(directResult.stderr, /cache destination must not be a symlink/u);
+  assert.equal(readFileSync(redirectedFile, 'utf8'), 'must remain unchanged\n');
+});
+
+test('preserves optional missing-artifact exit status', async (t) => {
+  const value = fixture(t);
+  const result = await value.resolve({
+    extensions: 'missing',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+    required: '0',
+  });
+  assert.equal(result.status, 3);
+  assert.match(result.stderr, /missing exact-extension artifact\(s\): missing: package/u);
+
+  const carrier = fixture(t);
+  const aggregate = carrier.installAggregate({ targets: ['android-arm64-v8a'] });
+  rmSync(aggregate.carriersByTarget.get('android-arm64-v8a').carrierPath);
+  const carrierResult = await carrier.resolve({
+    extensions: 'amcheck',
+    assetKind: 'runtime',
+    assetTarget: 'android-arm64-v8a',
+    required: '0',
+  });
+  assert.equal(carrierResult.status, 3);
+  assert.match(
+    carrierResult.stderr,
+    /missing exact-extension artifact\(s\): oliphaunt-extension-contrib-pg18:/u,
+  );
+});
diff --git a/src/sdks/react-native/tools/mobile-extension-artifact-paths.test.sh b/src/sdks/react-native/tools/mobile-extension-artifact-paths.test.sh
new file mode 100644
index 000000000..a6e5aaabb
--- /dev/null
+++ b/src/sdks/react-native/tools/mobile-extension-artifact-paths.test.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+set -euo pipefail
+tools="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+root="$(cd "$tools/../../../.." && pwd)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+bun test "$tools/mobile-extension-artifact-paths.test.mts"
+mkdir "$scratch/artifacts"
+arguments=(--root "$root" --artifact-root "$scratch/artifacts" --materialize-root "$scratch/cache" --extensions vector --asset-kind runtime --asset-target android-arm64-v8a)
+for required in 0 1; do
+  status=0
+  bun "$tools/mobile-extension-artifact-paths.mts" "${arguments[@]}" --required "$required" > "$scratch/output" 2> "$scratch/error" || status=$?
+  if [[ "$required" == 0 ]]; then expected=3; else expected=1; fi
+  [[ "$status" == "$expected" && ! -s "$scratch/output" ]]
+  grep -q 'missing exact-extension artifact(s): vector: package' "$scratch/error"
+done
+status=0
+bun "$tools/mobile-extension-artifact-paths.mts" "${arguments[@]}" --required 0 --required 1 > "$scratch/output" 2> "$scratch/error" || status=$?
+[[ "$status" == 2 ]]
+grep -q 'duplicate option: --required' "$scratch/error"
diff --git a/src/sdks/react-native/tools/mobile-extension-runtime.mts b/src/sdks/react-native/tools/mobile-extension-runtime.mts
new file mode 100644
index 000000000..737f8d818
--- /dev/null
+++ b/src/sdks/react-native/tools/mobile-extension-runtime.mts
@@ -0,0 +1,178 @@
+import * as fs from 'node:fs';
+
+const [command, ...args] = process.argv.slice(2);
+switch (command) {
+  case 'normalize': {
+    const [metadataPath, requestedRaw, platformLabel] = args;
+    const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
+    const bySqlName = new Map();
+    for (const row of metadata.extensions ?? []) {
+      if (typeof row['sql-name'] === 'string') {
+        bySqlName.set(row['sql-name'], row);
+      }
+    }
+
+    const supported = [...bySqlName.values()].map((row) => row['sql-name']).sort();
+    const ordered = [];
+    const seen = new Set();
+    function visit(sqlName) {
+      if (seen.has(sqlName)) {
+        return;
+      }
+      const row = bySqlName.get(sqlName);
+      if (!row) {
+        throw new Error(
+          `unsupported mobile extension for ${platformLabel} Expo smoke: ${sqlName} ` +
+            `(supported: ${supported.join(',')})`,
+        );
+      }
+      seen.add(sqlName);
+      const dependencies = row['selected-extension-dependencies'] ?? [];
+      if (
+        !Array.isArray(dependencies) ||
+        dependencies.some((dependency) => typeof dependency !== 'string')
+      ) {
+        throw new Error(
+          `extension ${sqlName} has invalid selected-extension-dependencies metadata`,
+        );
+      }
+      for (const dependency of dependencies) {
+        visit(dependency);
+      }
+      ordered.push(sqlName);
+    }
+    for (const sqlName of requestedRaw
+      .split(',')
+      .map((value) => value.trim())
+      .filter(Boolean)) {
+      visit(sqlName);
+    }
+    process.stdout.write(ordered.join(','));
+    break;
+  }
+  case 'createable': {
+    const [metadataPath, selectedRaw] = args;
+    const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
+    const bySqlName = new Map(
+      (metadata.extensions ?? [])
+        .filter((row) => typeof row['sql-name'] === 'string')
+        .map((row) => [row['sql-name'], row]),
+    );
+    const selected = [
+      ...new Set(
+        selectedRaw
+          .split(',')
+          .map((value) => value.trim())
+          .filter(Boolean),
+      ),
+    ].sort();
+    const createable = [];
+    for (const sqlName of selected) {
+      const row = bySqlName.get(sqlName);
+      if (row === undefined) {
+        throw new Error(`selected mobile extension is missing from generated metadata: ${sqlName}`);
+      }
+      if (row['creates-extension'] === true) {
+        createable.push(sqlName);
+      }
+    }
+    process.stdout.write(createable.join(','));
+    break;
+  }
+  case 'static': {
+    const [metadataPath, staticSpecsPath, selectedRaw] = args;
+    const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
+    const bySqlName = new Map(
+      (metadata.extensions ?? [])
+        .filter((row) => typeof row['sql-name'] === 'string')
+        .map((row) => [row['sql-name'], row]),
+    );
+    const specLines = fs
+      .readFileSync(staticSpecsPath, 'utf8')
+      .split(/\r?\n/u)
+      .filter((line) => line.length > 0 && !line.startsWith('#'));
+    const header = specLines.shift()?.split('\t') ?? [];
+    const sqlNameIndex = header.indexOf('sql-name');
+    const moduleStemIndex = header.indexOf('native-module-stem');
+    if (sqlNameIndex === -1 || moduleStemIndex === -1) {
+      throw new Error('generated mobile static extension specs are missing identity columns');
+    }
+    const staticSpecs = new Map();
+    for (const line of specLines) {
+      const fields = line.split('\t');
+      staticSpecs.set(fields[sqlNameIndex], fields[moduleStemIndex]);
+    }
+    const selectedStatic = [];
+    const seen = new Set();
+    for (const sqlName of selectedRaw
+      .split(',')
+      .map((value) => value.trim())
+      .filter(Boolean)) {
+      if (seen.has(sqlName)) continue;
+      seen.add(sqlName);
+      const row = bySqlName.get(sqlName);
+      if (!row) {
+        throw new Error(
+          `selected mobile extension ${sqlName} is absent from generated React Native metadata`,
+        );
+      }
+      const metadataStem = row['native-module-stem'];
+      const staticStem = staticSpecs.get(sqlName);
+      if (metadataStem === null) {
+        if (staticStem !== undefined) {
+          throw new Error(
+            `SQL-only mobile extension ${sqlName} must not have a native static-module spec`,
+          );
+        }
+        continue;
+      }
+      if (typeof metadataStem !== 'string' || metadataStem.length === 0) {
+        throw new Error(
+          `selected mobile extension ${sqlName} has invalid native-module-stem metadata`,
+        );
+      }
+      if (staticStem === undefined) {
+        throw new Error(
+          `selected native mobile extension is missing a static-module spec: ${sqlName}`,
+        );
+      }
+      if (staticStem !== metadataStem) {
+        throw new Error(
+          `selected mobile extension ${sqlName} static-module stem mismatch: ` +
+            `metadata=${metadataStem}, static-spec=${staticStem}`,
+        );
+      }
+      selectedStatic.push(sqlName);
+    }
+    process.stdout.write(selectedStatic.join(','));
+    break;
+  }
+  case 'data-files': {
+    const [registryPath, mode, selectedRaw] = args;
+    const registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
+    const selected = new Set(
+      selectedRaw
+        .split(',')
+        .map((value) => value.trim())
+        .filter(Boolean),
+    );
+    const files = new Set();
+    for (const module of registry.modules ?? []) {
+      const sqlName = module['sql-name'];
+      if (mode === 'selected' && !selected.has(sqlName)) {
+        continue;
+      }
+      for (const file of module['data-files'] ?? []) {
+        if (typeof file === 'string' && file.length > 0) {
+          files.add(file);
+        }
+      }
+    }
+    for (const file of [...files].sort()) {
+      console.log(file);
+    }
+    break;
+  }
+  default:
+    throw new Error('unknown mobile-extension-runtime command: ' + command);
+}
diff --git a/src/sdks/react-native/tools/mobile-extension-runtime.sh b/src/sdks/react-native/tools/mobile-extension-runtime.sh
index 9a937abe8..ec549fc3f 100644
--- a/src/sdks/react-native/tools/mobile-extension-runtime.sh
+++ b/src/sdks/react-native/tools/mobile-extension-runtime.sh
@@ -2,10 +2,10 @@
 
 # Shared helpers for local React Native mobile smoke resource packaging.
 # The public selection model is exact SQL extension names. Runtime/source
-# metadata remains owned by src/extensions and the liboliphaunt native build
+# metadata remains owned by extensions and the liboliphaunt native build
 # scripts; this file only adapts that metadata for smoke-package assertions.
 
-. "$root/src/runtimes/liboliphaunt/native/bin/mobile-static-extensions.sh"
+. "$root/src/runtimes/liboliphaunt-native/bin/mobile-static-extensions.sh"
 
 oliphaunt_dev_mobile_registry_json() {
   printf '%s\n' "$root/src/extensions/generated/mobile/static-registry.json"
@@ -36,146 +36,27 @@ oliphaunt_dev_normalize_mobile_extensions() {
   local raw="$1"
   local platform="$2"
   case "$platform" in
-    Android*|iOS*) ;;
+    Android* | iOS*) ;;
     *) fail "unsupported mobile extension platform: $platform" ;;
   esac
 
   [ -n "$(printf '%s' "$raw" | tr -d '[:space:],')" ] || return 0
-  node - "$(oliphaunt_dev_sdk_extension_json)" "$raw" "$platform" <<'NODE'
-const fs = require('node:fs');
-const [metadataPath, requestedRaw, platformLabel] = process.argv.slice(2);
-const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
-const bySqlName = new Map();
-for (const row of metadata.extensions ?? []) {
-  if (typeof row['sql-name'] === 'string') {
-    bySqlName.set(row['sql-name'], row);
-  }
-}
-
-const supported = [...bySqlName.values()]
-  .map((row) => row['sql-name'])
-  .sort();
-const ordered = [];
-const seen = new Set();
-function visit(sqlName) {
-  if (seen.has(sqlName)) {
-    return;
-  }
-  const row = bySqlName.get(sqlName);
-  if (!row) {
-    throw new Error(
-      `unsupported mobile extension for ${platformLabel} Expo smoke: ${sqlName} `
-      + `(supported: ${supported.join(',')})`,
-    );
-  }
-  seen.add(sqlName);
-  const dependencies = row['selected-extension-dependencies'] ?? [];
-  if (!Array.isArray(dependencies) || dependencies.some((dependency) => typeof dependency !== 'string')) {
-    throw new Error(`extension ${sqlName} has invalid selected-extension-dependencies metadata`);
-  }
-  for (const dependency of dependencies) {
-    visit(dependency);
-  }
-  ordered.push(sqlName);
-}
-for (const sqlName of requestedRaw.split(',').map((value) => value.trim()).filter(Boolean)) {
-  visit(sqlName);
-}
-process.stdout.write(ordered.join(','));
-NODE
+  bun "$root/src/sdks/react-native/tools/mobile-extension-runtime.mts" normalize "$(oliphaunt_dev_sdk_extension_json)" "$raw" "$platform"
 }
 
 oliphaunt_dev_mobile_createable_extensions_for_selection() {
   local selected_extensions="$1"
   [ -n "$(printf '%s' "$selected_extensions" | tr -d '[:space:],')" ] || return 0
-  node - "$(oliphaunt_dev_sdk_extension_json)" "$selected_extensions" <<'NODE'
-const fs = require('node:fs');
-const [metadataPath, selectedRaw] = process.argv.slice(2);
-const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
-const bySqlName = new Map(
-  (metadata.extensions ?? [])
-    .filter((row) => typeof row['sql-name'] === 'string')
-    .map((row) => [row['sql-name'], row]),
-);
-const selected = [...new Set(
-  selectedRaw.split(',').map((value) => value.trim()).filter(Boolean),
-)].sort();
-const createable = [];
-for (const sqlName of selected) {
-  const row = bySqlName.get(sqlName);
-  if (row === undefined) {
-    throw new Error(`selected mobile extension is missing from generated metadata: ${sqlName}`);
-  }
-  if (row['creates-extension'] === true) {
-    createable.push(sqlName);
-  }
-}
-process.stdout.write(createable.join(','));
-NODE
+  bun "$root/src/sdks/react-native/tools/mobile-extension-runtime.mts" createable "$(oliphaunt_dev_sdk_extension_json)" "$selected_extensions"
 }
 
 oliphaunt_dev_mobile_static_extensions_for_selection() {
   local selected_extensions="$1"
   [ -n "$(printf '%s' "$selected_extensions" | tr -d '[:space:],')" ] || return 0
-  node - \
+  bun "$root/src/sdks/react-native/tools/mobile-extension-runtime.mts" static \
     "$(oliphaunt_dev_sdk_extension_json)" \
     "$(oliphaunt_mobile_static_specs_tsv)" \
-    "$selected_extensions" <<'NODE'
-const fs = require('node:fs');
-const [metadataPath, staticSpecsPath, selectedRaw] = process.argv.slice(2);
-const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
-const bySqlName = new Map(
-  (metadata.extensions ?? [])
-    .filter((row) => typeof row['sql-name'] === 'string')
-    .map((row) => [row['sql-name'], row]),
-);
-const specLines = fs.readFileSync(staticSpecsPath, 'utf8')
-  .split(/\r?\n/u)
-  .filter((line) => line.length > 0 && !line.startsWith('#'));
-const header = specLines.shift()?.split('\t') ?? [];
-const sqlNameIndex = header.indexOf('sql-name');
-const moduleStemIndex = header.indexOf('native-module-stem');
-if (sqlNameIndex === -1 || moduleStemIndex === -1) {
-  throw new Error('generated mobile static extension specs are missing identity columns');
-}
-const staticSpecs = new Map();
-for (const line of specLines) {
-  const fields = line.split('\t');
-  staticSpecs.set(fields[sqlNameIndex], fields[moduleStemIndex]);
-}
-const selectedStatic = [];
-const seen = new Set();
-for (const sqlName of selectedRaw.split(',').map((value) => value.trim()).filter(Boolean)) {
-  if (seen.has(sqlName)) continue;
-  seen.add(sqlName);
-  const row = bySqlName.get(sqlName);
-  if (!row) {
-    throw new Error(`selected mobile extension ${sqlName} is absent from generated React Native metadata`);
-  }
-  const metadataStem = row['native-module-stem'];
-  const staticStem = staticSpecs.get(sqlName);
-  if (metadataStem === null) {
-    if (staticStem !== undefined) {
-      throw new Error(`SQL-only mobile extension ${sqlName} must not have a native static-module spec`);
-    }
-    continue;
-  }
-  if (typeof metadataStem !== 'string' || metadataStem.length === 0) {
-    throw new Error(`selected mobile extension ${sqlName} has invalid native-module-stem metadata`);
-  }
-  if (staticStem === undefined) {
-    throw new Error(`selected native mobile extension is missing a static-module spec: ${sqlName}`);
-  }
-  if (staticStem !== metadataStem) {
-    throw new Error(
-      `selected mobile extension ${sqlName} static-module stem mismatch: `
-      + `metadata=${metadataStem}, static-spec=${staticStem}`,
-    );
-  }
-  selectedStatic.push(sqlName);
-}
-process.stdout.write(selectedStatic.join(','));
-NODE
+    "$selected_extensions"
 }
 
 oliphaunt_dev_mobile_module_stems_for_selection() {
@@ -227,7 +108,7 @@ oliphaunt_dev_prebuilt_extension_asset_paths_for_selection() {
     return 1
   fi
 
-  "$root/tools/dev/bun.sh" "$root/src/sdks/react-native/tools/mobile-extension-artifact-paths.mjs" \
+  "$root/tools/dev/bun.sh" "$root/src/sdks/react-native/tools/mobile-extension-artifact-paths.mts" \
     --root "$root" \
     --artifact-root "$artifact_root" \
     --materialize-root "$materialize_root" \
@@ -252,14 +133,13 @@ oliphaunt_dev_prebuilt_ios_extension_framework_zips_for_selection() {
 oliphaunt_dev_prepare_prebuilt_mobile_runtime_resource_package() {
   local platform="$1"
   local runtime_source="$2"
-  local initdb_source="$3"
-  local selected_extensions="$4"
-  local package_root="$5"
-  local icu_enabled="${6:-0}"
-  local icu_data_dir="${7:-}"
+  local selected_extensions="$3"
+  local package_root="$4"
+  local icu_enabled="${5:-0}"
+  local icu_data_dir="${6:-}"
 
   case "$icu_enabled" in
-    0|1) ;;
+    0 | 1) ;;
     *) fail "prebuilt mobile runtime ICU selection must be 0 or 1" ;;
   esac
   [ -n "$selected_extensions" ] || [ "$icu_enabled" = "1" ] || return 1
@@ -269,7 +149,7 @@ oliphaunt_dev_prepare_prebuilt_mobile_runtime_resource_package() {
 
   local prebuilt_runtime_artifacts native_runtime_version stable_semver_re
   need_cmd cargo
-  native_runtime_version="$(tr -d '\r\n' <"$root/src/runtimes/liboliphaunt/native/VERSION")"
+  native_runtime_version="$(tr -d '\r\n' <"$root/src/runtimes/liboliphaunt-native/VERSION")"
   stable_semver_re='^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
   [[ "$native_runtime_version" =~ $stable_semver_re ]] ||
     fail "liboliphaunt native VERSION must be stable SemVer"
@@ -300,7 +180,7 @@ oliphaunt_dev_prepare_prebuilt_mobile_runtime_resource_package() {
   module_stems="$(oliphaunt_dev_mobile_module_stems_for_selection "$selected_extensions")"
   local -a package_args=(
     run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked --
-    --mode native-direct
+
     --output "$package_root"
     --extension-target "$extension_target"
     --liboliphaunt-native-version "$native_runtime_version"
@@ -320,9 +200,6 @@ oliphaunt_dev_prepare_prebuilt_mobile_runtime_resource_package() {
   done < <(printf '%s\n' "$prebuilt_runtime_artifacts")
 
   local -a resource_env=(OLIPHAUNT_INSTALL_DIR="$runtime_source")
-  if [ -n "$initdb_source" ]; then
-    resource_env+=(OLIPHAUNT_INITDB="$initdb_source")
-  fi
   if [ "$icu_enabled" = "1" ]; then
     resource_env+=(OLIPHAUNT_ICU_DATA_DIR="$icu_data_dir")
   fi
@@ -357,7 +234,7 @@ oliphaunt_dev_unpack_ios_extension_frameworks_for_selection() {
     rm -rf "$dest"
     return 0
   fi
-  command -v node >/dev/null 2>&1 || fail "missing required command: node"
+  command -v bun >/dev/null 2>&1 || fail "missing required command: bun"
   command -v unzip >/dev/null 2>&1 || fail "missing required command: unzip"
 
   local framework_zips
@@ -373,7 +250,7 @@ oliphaunt_dev_unpack_ios_extension_frameworks_for_selection() {
   while IFS= read -r archive; do
     [ -n "$archive" ] || continue
     index=$((index + 1))
-    if ! node "$root/src/sdks/swift/tools/extract-verified-zip.mjs" \
+    if ! bun "$root/src/sdks/swift/tools/extract-verified-zip.mts" \
       --archive "$archive" \
       --destination "$extraction_root/$index"; then
       rm -rf "$extraction_root"
@@ -504,32 +381,7 @@ oliphaunt_dev_runtime_extension_files() {
 oliphaunt_dev_mobile_registry_data_files() {
   local mode="$1"
   local selected_extensions="${2:-}"
-  node - "$(oliphaunt_dev_mobile_registry_json)" "$mode" "$selected_extensions" <<'NODE'
-const fs = require('node:fs');
-const [registryPath, mode, selectedRaw] = process.argv.slice(2);
-const registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
-const selected = new Set(
-  selectedRaw
-    .split(',')
-    .map((value) => value.trim())
-    .filter(Boolean),
-);
-const files = new Set();
-for (const module of registry.modules ?? []) {
-  const sqlName = module['sql-name'];
-  if (mode === 'selected' && !selected.has(sqlName)) {
-    continue;
-  }
-  for (const file of module['data-files'] ?? []) {
-    if (typeof file === 'string' && file.length > 0) {
-      files.add(file);
-    }
-  }
-}
-for (const file of [...files].sort()) {
-  console.log(file);
-}
-NODE
+  bun "$root/src/sdks/react-native/tools/mobile-extension-runtime.mts" data-files "$(oliphaunt_dev_mobile_registry_json)" "$mode" "$selected_extensions"
 }
 
 oliphaunt_dev_hash_mobile_runtime_extension_assets() {
@@ -566,7 +418,7 @@ oliphaunt_dev_copy_mobile_runtime_extension_assets() {
       [ -n "$file" ] || continue
       file_name="$(basename "$file")"
       case "$file_name" in
-        "$extension.control"|"$extension.control.in")
+        "$extension.control" | "$extension.control.in")
           default_version="$(oliphaunt_dev_extension_default_version "$file" || true)"
           [ "$file_name" = "$extension.control.in" ] && file_name="$extension.control"
           ;;
@@ -649,7 +501,7 @@ oliphaunt_dev_assert_runtime_extension_tree() {
   local runtime_dest="$1"
   local selected_extensions="$2"
   local platform="$3"
-  node "$root/src/sdks/react-native/tools/validate-mobile-runtime-files.mjs" \
+  bun "$root/src/sdks/react-native/tools/validate-mobile-runtime-files.mts" \
     --metadata "$(oliphaunt_dev_sdk_extension_json)" \
     --registry "$(oliphaunt_dev_mobile_registry_json)" \
     --selected "$selected_extensions" \
@@ -663,13 +515,12 @@ oliphaunt_dev_assert_runtime_file_list() {
   local file_list
   file_list="$(mktemp "${TMPDIR:-/tmp}/oliphaunt-runtime-file-list.XXXXXX")"
   cat >"$file_list"
-  if ! node "$root/src/sdks/react-native/tools/validate-mobile-runtime-files.mjs" \
+  if ! bun "$root/src/sdks/react-native/tools/validate-mobile-runtime-files.mts" \
     --metadata "$(oliphaunt_dev_sdk_extension_json)" \
     --registry "$(oliphaunt_dev_mobile_registry_json)" \
     --selected "$selected_extensions" \
     --platform "$platform" \
-    --file-list "$file_list"
-  then
+    --file-list "$file_list"; then
     rm -f "$file_list"
     return 1
   fi
diff --git a/src/sdks/react-native/tools/mobile-extension-selection-fixture.mts b/src/sdks/react-native/tools/mobile-extension-selection-fixture.mts
new file mode 100644
index 000000000..aafa12446
--- /dev/null
+++ b/src/sdks/react-native/tools/mobile-extension-selection-fixture.mts
@@ -0,0 +1,69 @@
+import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { CORE_SNOWBALL_RUNTIME_DATA_FILES } from './validate-mobile-runtime-files.mts';
+
+const destination = process.argv[2];
+if (!destination) throw new Error('expected a disposable fixture directory');
+const root = fileURLToPath(new URL('../../../../', import.meta.url));
+const metadata = JSON.parse(
+  readFileSync(path.join(root, 'src/extensions/generated/sdk/extensions.json'), 'utf8'),
+);
+const registry = JSON.parse(
+  readFileSync(path.join(root, 'src/extensions/generated/mobile/static-registry.json'), 'utf8'),
+);
+mkdirSync(destination, { recursive: true });
+const prefix = 'assets/oliphaunt/runtime/files/';
+function list(name: string, sql: string[], data: string[] = []) {
+  const files = [
+    ...CORE_SNOWBALL_RUNTIME_DATA_FILES,
+    ...sql.map((file) => `share/postgresql/extension/${file}`),
+    ...data,
+  ];
+  writeFileSync(
+    path.join(destination, `${name}.txt`),
+    `${files.map((file) => prefix + file).join('\n')}\n`,
+  );
+  return files;
+}
+const pgtap = [
+  'pgtap.control',
+  'pgtap--1.0.sql',
+  'pgtap--1.0--1.1.sql',
+  'pgtap.sql',
+  'pgtap-core--1.1.sql',
+  'pgtap-schema.sql',
+  'uninstall_pgtap.sql',
+];
+const files = list('pgtap', pgtap);
+list(
+  'postgis',
+  [
+    'postgis.control',
+    'postgis--1.0.sql',
+    'postgis_comments.sql',
+    'postgis_proc_set_search_path--1.0.sql',
+    'rtpostgis.sql',
+    'uninstall_postgis.sql',
+  ],
+  registry.modules.find((row) => row['sql-name'] === 'postgis')['data-files'],
+);
+list('unselected', ['pgtap-core--1.1.sql']);
+list('undeclared', ['foreign--1.0.sql']);
+list(
+  'ancillary-only',
+  pgtap.filter((file) => !file.startsWith('pgtap--')),
+);
+for (const relative of files) {
+  const file = path.join(destination, 'runtime', relative);
+  mkdirSync(path.dirname(file), { recursive: true });
+  writeFileSync(
+    file,
+    relative.endsWith('/pgtap.control') ? "default_version = '1.1'\n" : '-- fixture\n',
+  );
+}
+metadata.extensions.find((row) => row['sql-name'] === 'vector')['extension-sql-file-prefixes'] = [
+  'pgtap-core',
+];
+writeFileSync(path.join(destination, 'ambiguous.json'), JSON.stringify(metadata));
diff --git a/src/sdks/react-native/tools/mobile-extension-selection.test.sh b/src/sdks/react-native/tools/mobile-extension-selection.test.sh
new file mode 100644
index 000000000..36084be8f
--- /dev/null
+++ b/src/sdks/react-native/tools/mobile-extension-selection.test.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)"
+cd "$root"
+fixture="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-mobile-selection.XXXXXX")"
+trap 'rm -rf "$fixture"' EXIT
+fail() { printf '%s\n' "$*" >&2; exit 1; }
+source "$root/src/sdks/react-native/tools/mobile-extension-runtime.sh"
+bun src/sdks/react-native/tools/mobile-extension-selection-fixture.mts "$fixture"
+expect_failure() {
+  local message="$1"
+  shift
+  if ( "$@" ) >"$fixture/error.log" 2>&1; then
+    fail "expected failure: $*"
+  fi
+  grep -Fq "$message" "$fixture/error.log" || { cat "$fixture/error.log" >&2; fail "missing diagnostic: $message"; }
+}
+for platform in Android iOS; do
+  selected="$(oliphaunt_dev_normalize_mobile_extensions ' pgtap,pgtap ' "$platform")"
+  [ "$selected" = pgtap ] || fail 'SQL-only selection was not normalized'
+  [ -z "$(oliphaunt_dev_mobile_static_extensions_for_selection "$selected")" ] || fail 'SQL-only extension requested static registration'
+  [ -z "$(oliphaunt_dev_mobile_module_stems_for_selection "$selected")" ] || fail 'SQL-only extension requested module stems'
+  [ -z "$(oliphaunt_dev_mobile_module_extensions_for_selection "$selected")" ] || fail 'SQL-only extension requested native module registration'
+  selected="$(oliphaunt_dev_normalize_mobile_extensions earthdistance "$platform")"
+  [ "$selected" = cube,earthdistance ] || fail 'dependency was not selected before its consumer'
+  [ "$(oliphaunt_dev_mobile_static_extensions_for_selection "$selected")" = "$selected" ] || fail 'native dependency missing from static selection'
+done
+(
+  oliphaunt_dev_prebuilt_extension_asset_paths_for_selection() { printf '%s|%s|%s\n' "$1" "$2" "$3"; }
+  [ "$(oliphaunt_dev_prebuilt_ios_extension_framework_zips_for_selection pgtap,vector)" = 'vector|ios-xcframework|ios-xcframework' ] || fail 'SQL-only extension requested framework'
+)
+(
+  oliphaunt_dev_prebuilt_extension_asset_paths_for_selection() { fail 'SQL-only selection requested a native framework'; }
+  mkdir -p "$fixture/frameworks/stale.xcframework"
+  oliphaunt_dev_unpack_ios_extension_frameworks_for_selection pgtap "$fixture/frameworks"
+  [ ! -e "$fixture/frameworks" ] || fail 'SQL-only selection retained stale native frameworks'
+)
+expect_failure 'unsupported mobile extension for Android Expo smoke: not_a_real_extension' oliphaunt_dev_normalize_mobile_extensions vector,not_a_real_extension Android
+expect_failure 'unsupported mobile extension platform: desktop' oliphaunt_dev_normalize_mobile_extensions vector desktop
+oliphaunt_dev_assert_runtime_file_list pgtap Android <"$fixture/pgtap.txt"
+oliphaunt_dev_assert_runtime_file_list postgis iOS <"$fixture/postgis.txt"
+expect_failure 'unselected PostgreSQL extension asset:' oliphaunt_dev_assert_runtime_file_list '' Android <"$fixture/unselected.txt"
+expect_failure 'undeclared PostgreSQL extension asset' oliphaunt_dev_assert_runtime_file_list '' Android <"$fixture/undeclared.txt"
+expect_failure 'missing selected pgtap canonical install SQL file' oliphaunt_dev_assert_runtime_file_list pgtap Android <"$fixture/ancillary-only.txt"
+(
+  oliphaunt_dev_sdk_extension_json() { printf '%s\n' "$fixture/ambiguous.json"; }
+  expect_failure 'ambiguous ownership' oliphaunt_dev_assert_runtime_file_list pgtap Android <"$fixture/pgtap.txt"
+)
+oliphaunt_dev_assert_runtime_extension_tree "$fixture/runtime" pgtap Android
+printf '%s\n' 'React Native extension selection and runtime inventory checks passed'
diff --git a/src/sdks/react-native/tools/native-resource-closure.mjs b/src/sdks/react-native/tools/native-resource-closure.mjs
deleted file mode 100644
index e5888eb20..000000000
--- a/src/sdks/react-native/tools/native-resource-closure.mjs
+++ /dev/null
@@ -1,194 +0,0 @@
-import { createHash } from "node:crypto";
-import fs from "node:fs/promises";
-import path from "node:path";
-
-const SHA256 = /^[0-9a-f]{64}$/u;
-const PORTABLE_ID = /^[A-Za-z0-9._-]{1,128}$/u;
-
-function validCacheKey(value) {
-  return PORTABLE_ID.test(value) && value !== "." && value !== "..";
-}
-const RUNTIME_SCHEMA = "oliphaunt-runtime-resources-v1";
-const TARGET = "ios-datum64";
-const COMPATIBILITY_KEY = "native-pg18-ios-datum64-v1";
-const RESOURCE_FIELDS = new Set([
-  "schema", "layout", "artifactRole", "catalogProfile", "clusterSeedTarget",
-  "icuDataTreeSha256", "mode", "cacheKey",
-  "selectedExtensions", "extensions", "runtimeFeatures", "sharedPreloadLibraries",
-  "mobileStaticRegistryState", "mobileStaticRegistryRegistered", "mobileStaticRegistryPending",
-  "nativeModuleStems", "mobileStaticRegistrySource",
-]);
-const CLUSTER_SEED_FIELDS = new Set([
-  "schema", "layout", "artifactRole", "catalogProfile", "postgresMajor", "physicalFormat",
-  "target", "compatibilityKey", "initialSuperuser", "runtimeFeatures", "icuDataVersion",
-  "icuDataForm", "icuDataTreeSha256", "cacheKey",
-]);
-
-export function parseProperties(text, source) {
-  const values = new Map();
-  for (const [index, line] of text.split(/\r?\n/u).entries()) {
-    if (!line) continue;
-    const separator = line.indexOf("=");
-    if (separator < 1) throw new Error(`${source}:${index + 1} is not key=value`);
-    const key = line.slice(0, separator);
-    if (values.has(key)) throw new Error(`${source}:${index + 1} repeats ${key}`);
-    values.set(key, line.slice(separator + 1));
-  }
-  return values;
-}
-
-export function requireProperty(values, key, expected, source) {
-  if (values.get(key) !== expected) {
-    throw new Error(
-      `${source} must declare ${key}=${expected}; got ${values.get(key) ?? ""}`,
-    );
-  }
-}
-
-async function readProperties(file) {
-  return parseProperties(await fs.readFile(file, "utf8"), file);
-}
-
-function requireResourceFields(values, source) {
-  const missing = [...RESOURCE_FIELDS].filter((key) => !values.has(key)).sort();
-  const unsupported = [...values.keys()].filter((key) => !RESOURCE_FIELDS.has(key)).sort();
-  if (missing.length > 0 || unsupported.length > 0) {
-    throw new Error(
-      `${source} must contain its exact canonical runtime fields; missing=${missing.join(",")}; unsupported=${unsupported.join(",")}`,
-    );
-  }
-}
-
-export async function logicalTreeSha256(root) {
-  const files = [];
-  async function visit(directory) {
-    for (const entry of await fs.readdir(directory, { withFileTypes: true })) {
-      const file = path.join(directory, entry.name);
-      const metadata = await fs.lstat(file);
-      if (metadata.isSymbolicLink()) throw new Error(`logical tree contains a symlink: ${file}`);
-      if (metadata.isDirectory()) await visit(file);
-      else if (metadata.isFile()) files.push(file);
-      else throw new Error(`logical tree contains a special file: ${file}`);
-    }
-  }
-  await visit(root);
-  files.sort((left, right) => Buffer.compare(
-    Buffer.from(path.relative(root, left).split(path.sep).join("/")),
-    Buffer.from(path.relative(root, right).split(path.sep).join("/")),
-  ));
-  const digest = createHash("sha256");
-  for (const file of files) {
-    const relative = path.relative(root, file).split(path.sep).join("/");
-    const bytes = await fs.readFile(file);
-    digest.update(relative);
-    digest.update(Buffer.of(0));
-    digest.update(String(bytes.length));
-    digest.update(Buffer.of(0));
-    digest.update(bytes);
-    digest.update("\n");
-  }
-  return digest.digest("hex");
-}
-
-async function validateClusterSeed(root, profile) {
-  const source = path.join(root, "manifest.properties");
-  await Promise.all([
-    fs.access(path.join(root, "files/PG_VERSION")),
-    fs.access(path.join(root, "files/global/pg_control")),
-  ]);
-  const values = await readProperties(source);
-  if (values.size !== CLUSTER_SEED_FIELDS.size
-      || [...CLUSTER_SEED_FIELDS].some((key) => !values.has(key))) {
-    throw new Error(`${source} must contain exactly the canonical cluster-seed fields`);
-  }
-  requireProperty(values, "schema", RUNTIME_SCHEMA, source);
-  requireProperty(values, "layout", "oliphaunt-cluster-seed-v1", source);
-  requireProperty(values, "artifactRole", `cluster-seed-${profile}`, source);
-  requireProperty(values, "catalogProfile", profile, source);
-  requireProperty(values, "postgresMajor", "18", source);
-  requireProperty(values, "physicalFormat", "native-pg18-v1", source);
-  requireProperty(values, "target", TARGET, source);
-  requireProperty(values, "compatibilityKey", COMPATIBILITY_KEY, source);
-  requireProperty(values, "initialSuperuser", "postgres", source);
-  requireProperty(values, "runtimeFeatures", profile === "icu" ? "icu" : "", source);
-  requireProperty(values, "icuDataVersion", profile === "icu" ? "76.1" : "", source);
-  requireProperty(values, "icuDataForm", profile === "icu" ? "files-le" : "", source);
-  const digest = values.get("icuDataTreeSha256") ?? "";
-  if (!validCacheKey(values.get("cacheKey") ?? "")) {
-    throw new Error(`${source} has an invalid cluster-seed cache key`);
-  }
-  if (profile === "icu" ? !SHA256.test(digest) : digest !== "") {
-    throw new Error(`${source} has an invalid ICU data identity`);
-  }
-  return { digest, values };
-}
-
-export async function validateNativeRuntimeClosure(root, { integrated } = {}) {
-  const receiptSource = path.join(root, "manifest.properties");
-  const receipt = await readProperties(receiptSource);
-  const receiptFields = new Set([
-    "schema", "clusterSeedTarget", "clusterSeedRelativePath", "icuClusterSeedRelativePath",
-  ]);
-  if (receipt.size !== receiptFields.size || [...receiptFields].some((key) => !receipt.has(key))) {
-    throw new Error(`${receiptSource} must contain exactly the canonical runtime-carrier fields`);
-  }
-  requireProperty(receipt, "schema", "oliphaunt-native-runtime-carrier-v1", receiptSource);
-  requireProperty(receipt, "clusterSeedTarget", TARGET, receiptSource);
-  requireProperty(receipt, "clusterSeedRelativePath", "cluster-seed", receiptSource);
-  requireProperty(receipt, "icuClusterSeedRelativePath", "cluster-seed-icu", receiptSource);
-  const source = path.join(root, "runtime/manifest.properties");
-  const runtime = await readProperties(source);
-  requireResourceFields(runtime, source);
-  requireProperty(runtime, "schema", RUNTIME_SCHEMA, source);
-  requireProperty(runtime, "layout", "postgres-runtime-files-v1", source);
-  requireProperty(runtime, "artifactRole", "runtime", source);
-  requireProperty(runtime, "catalogProfile", "", source);
-  requireProperty(runtime, "clusterSeedTarget", TARGET, source);
-  requireProperty(runtime, "mode", "native-direct", source);
-  if (!validCacheKey(runtime.get("cacheKey") ?? "")) {
-    throw new Error(`${source} has an invalid runtime cache key`);
-  }
-  const expectedRegistrySource = runtime.get("mobileStaticRegistryState") === "complete"
-    ? "static-registry/oliphaunt_static_registry.c"
-    : "";
-  requireProperty(runtime, "mobileStaticRegistrySource", expectedRegistrySource, source);
-  await validateClusterSeed(path.join(root, "cluster-seed"), "standard");
-  const icu = await validateClusterSeed(path.join(root, "cluster-seed-icu"), "icu");
-  const features = new Set((runtime.get("runtimeFeatures") ?? "").split(",").filter(Boolean));
-  integrated ??= features.has("icu");
-  if ([...features].some((feature) => feature !== "icu") || features.has("icu") !== integrated) {
-    throw new Error(`${source} has inconsistent runtimeFeatures for the selected catalog profile`);
-  }
-  const runtimeDigest = runtime.get("icuDataTreeSha256") ?? "";
-  if (integrated) {
-    if (runtimeDigest !== icu.digest) {
-      throw new Error(`${source} ICU identity does not match cluster-seed-icu`);
-    }
-    const data = path.join(root, "runtime/files/share/icu");
-    if (await logicalTreeSha256(data) !== runtimeDigest) {
-      throw new Error(`${source} ICU identity does not match runtime/files/share/icu`);
-    }
-  } else if (runtimeDigest !== "") {
-    throw new Error(`${source} selects ICU data without the ICU runtime feature`);
-  }
-  return { icuDigest: icu.digest, runtime };
-}
-
-export async function validateIcuDataCarrier(root) {
-  const source = path.join(root, "manifest.properties");
-  const values = await readProperties(source);
-  const expected = new Set([
-    "schema", "artifactRole", "icuDataVersion", "icuDataForm", "icuDataTreeSha256",
-  ]);
-  if (values.size !== expected.size || [...expected].some((key) => !values.has(key))) {
-    throw new Error(`${source} must contain exactly the canonical ICU data fields`);
-  }
-  requireProperty(values, "schema", "oliphaunt-icu-data-v1", source);
-  requireProperty(values, "artifactRole", "icu-data", source);
-  requireProperty(values, "icuDataVersion", "76.1", source);
-  requireProperty(values, "icuDataForm", "files-le", source);
-  const data = path.join(root, "share/icu");
-  const digest = await logicalTreeSha256(data);
-  requireProperty(values, "icuDataTreeSha256", digest, source);
-  return { data, digest };
-}
diff --git a/src/sdks/react-native/tools/native-resource-closure.mts b/src/sdks/react-native/tools/native-resource-closure.mts
new file mode 100644
index 000000000..f73720b36
--- /dev/null
+++ b/src/sdks/react-native/tools/native-resource-closure.mts
@@ -0,0 +1,97 @@
+import fs from 'node:fs/promises';
+import path from 'node:path';
+
+const PORTABLE_ID = /^[A-Za-z0-9._-]{1,128}$/u;
+
+function validCacheKey(value) {
+  return PORTABLE_ID.test(value) && value !== '.' && value !== '..';
+}
+const RUNTIME_SCHEMA = 'oliphaunt-runtime-resources-v1';
+const TARGET = 'ios-datum64';
+const RESOURCE_FIELDS = new Set([
+  'schema',
+  'layout',
+  'artifactRole',
+  'catalogProfile',
+  'clusterSeedTarget',
+  'icuDataTreeSha256',
+  'mode',
+  'cacheKey',
+  'selectedExtensions',
+  'extensions',
+  'runtimeFeatures',
+  'sharedPreloadLibraries',
+  'mobileStaticRegistryState',
+  'mobileStaticRegistryRegistered',
+  'mobileStaticRegistryPending',
+  'nativeModuleStems',
+  'mobileStaticRegistrySource',
+]);
+export function parseProperties(text, source) {
+  const values = new Map();
+  for (const [index, line] of text.split(/\r?\n/u).entries()) {
+    if (!line) continue;
+    const separator = line.indexOf('=');
+    if (separator < 1) throw new Error(`${source}:${index + 1} is not key=value`);
+    const key = line.slice(0, separator);
+    if (values.has(key)) throw new Error(`${source}:${index + 1} repeats ${key}`);
+    values.set(key, line.slice(separator + 1));
+  }
+  return values;
+}
+
+export function requireProperty(values, key, expected, source) {
+  if (values.get(key) !== expected) {
+    throw new Error(
+      `${source} must declare ${key}=${expected}; got ${values.get(key) ?? ''}`,
+    );
+  }
+}
+
+async function readProperties(file) {
+  return parseProperties(await fs.readFile(file, 'utf8'), file);
+}
+
+function requireResourceFields(values, source) {
+  const missing = [...RESOURCE_FIELDS].filter((key) => !values.has(key)).sort();
+  const unsupported = [...values.keys()].filter((key) => !RESOURCE_FIELDS.has(key)).sort();
+  if (missing.length > 0 || unsupported.length > 0) {
+    throw new Error(
+      `${source} must contain its exact canonical runtime fields; missing=${missing.join(',')}; unsupported=${unsupported.join(',')}`,
+    );
+  }
+}
+
+export async function validateNativeRuntimeClosure(root, { target = TARGET } = {}) {
+  const source = path.join(root, 'runtime/manifest.properties');
+  const runtime = await readProperties(source);
+  requireResourceFields(runtime, source);
+  requireProperty(runtime, 'schema', RUNTIME_SCHEMA, source);
+  requireProperty(runtime, 'layout', 'postgres-runtime-files-v1', source);
+  requireProperty(runtime, 'artifactRole', 'runtime', source);
+  requireProperty(runtime, 'catalogProfile', '', source);
+  requireProperty(runtime, 'clusterSeedTarget', target, source);
+  requireProperty(runtime, 'mode', 'native-direct', source);
+  if (!validCacheKey(runtime.get('cacheKey') ?? '')) {
+    throw new Error(`${source} has an invalid runtime cache key`);
+  }
+  const expectedRegistrySource =
+    runtime.get('mobileStaticRegistryState') === 'complete'
+      ? 'static-registry/oliphaunt_static_registry.c'
+      : '';
+  requireProperty(runtime, 'mobileStaticRegistrySource', expectedRegistrySource, source);
+  requireProperty(runtime, 'runtimeFeatures', '', source);
+  requireProperty(runtime, 'icuDataTreeSha256', '', source);
+  for (const relative of ['cluster-seed', 'cluster-seed-icu', 'runtime/files/share/icu']) {
+    const member = path.join(root, relative);
+    const exists = await fs.lstat(member).then(
+      () => true,
+      (error) => {
+        if (error.code === 'ENOENT') return false;
+        throw error;
+      },
+    );
+    if (exists) throw new Error(member + ' belongs to a separate database resource carrier');
+  }
+  return { runtime };
+}
diff --git a/src/sdks/react-native/tools/package.sh b/src/sdks/react-native/tools/package.sh
new file mode 100644
index 000000000..df9e24e41
--- /dev/null
+++ b/src/sdks/react-native/tools/package.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")"
+bash stage-release-artifacts.sh
+bun check-package.mts
diff --git a/src/sdks/react-native/tools/qualify-ios-carriers.mts b/src/sdks/react-native/tools/qualify-ios-carriers.mts
new file mode 100644
index 000000000..a6e91daae
--- /dev/null
+++ b/src/sdks/react-native/tools/qualify-ios-carriers.mts
@@ -0,0 +1,54 @@
+switch (Bun.argv[2]) {
+  case 'selection': {
+    const manifest = JSON.parse(await Bun.file(process.env.IOS_CARRIER_MANIFEST).text());
+    const planned = String(process.env.PLANNED_EXTENSION_SQL_NAMES ?? '')
+      .split(',')
+      .filter(Boolean)
+      .sort();
+    if (planned.length === 0) {
+      throw new Error('planner selected no exact iOS extension carriers');
+    }
+    if (!Array.isArray(manifest.extensions) || manifest.extensions.length === 0) {
+      throw new Error('exact iOS carrier manifest contains no extensions');
+    }
+    const names = manifest.extensions.map((row) => row.sqlName).sort();
+    if (names.some((name) => typeof name !== 'string') || new Set(names).size !== names.length) {
+      throw new Error('exact iOS carrier manifest has invalid or duplicate extension identities');
+    }
+    if (JSON.stringify(names) !== JSON.stringify(planned)) {
+      throw new Error(
+        'exact iOS carrier manifest does not match the planner-selected extension set',
+      );
+    }
+    process.stdout.write(names.join(','));
+
+    break;
+  }
+  case 'verify': {
+    const manifest = JSON.parse(await Bun.file(process.env.IOS_CARRIER_MANIFEST).text());
+    const selection = JSON.parse(
+      await Bun.file(process.env.IOS_CARRIER_STAGE + '/selection.json').text(),
+    );
+    const expected = String(process.env.PLANNED_EXTENSION_SQL_NAMES ?? '')
+      .split(',')
+      .filter(Boolean)
+      .sort();
+    const manifested = manifest.extensions.map((row) => row.sqlName).sort();
+    const requested = [...selection.requestedExtensions].sort();
+    const resolved = selection.extensions.map((row) => row.sqlName).sort();
+    if (
+      JSON.stringify(manifested) !== JSON.stringify(expected) ||
+      !selection.icu ||
+      JSON.stringify(requested) !== JSON.stringify(expected) ||
+      JSON.stringify(resolved) !== JSON.stringify(expected)
+    ) {
+      throw new Error(
+        'staged iOS carrier selection does not exactly cover every manifest extension plus ICU',
+      );
+    }
+
+    break;
+  }
+  default:
+    throw Error('unknown iOS carrier qualification command');
+}
diff --git a/src/sdks/react-native/tools/qualify-ios-carriers.sh b/src/sdks/react-native/tools/qualify-ios-carriers.sh
new file mode 100644
index 000000000..ab30e34ce
--- /dev/null
+++ b/src/sdks/react-native/tools/qualify-ios-carriers.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+
+extensions="$(bun src/sdks/react-native/tools/qualify-ios-carriers.mts selection)"
+bun src/sdks/react-native/tools/stage-ios-app.mts \
+  --carrier "$IOS_CARRIER_MANIFEST" \
+  --output-dir "$IOS_CARRIER_STAGE" \
+  --extensions "$extensions" \
+  --icu \
+  --cache-dir "$IOS_CARRIER_CACHE" \
+  --allow-file-urls
+bun src/sdks/react-native/tools/qualify-ios-carriers.mts verify
+mkdir -p target/release/ios-carriers/qualification
+cp "$IOS_CARRIER_STAGE/selection.json" \
+  target/release/ios-carriers/qualification/all-extensions-selection.json
+cp "$IOS_CARRIER_STAGE/resources/OliphauntReactNativeResources.bundle/oliphaunt/package-size.tsv" \
+  target/release/ios-carriers/qualification/all-extensions-package-size.tsv
+rm -rf "$IOS_CARRIER_STAGE" "$IOS_CARRIER_CACHE"
diff --git a/src/sdks/react-native/tools/react-native-package-inputs.mjs b/src/sdks/react-native/tools/react-native-package-inputs.mjs
deleted file mode 100644
index 55e0989c4..000000000
--- a/src/sdks/react-native/tools/react-native-package-inputs.mjs
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/bin/env node
-
-import { createHash } from 'node:crypto';
-import { lstatSync, readFileSync, readdirSync, readlinkSync } from 'node:fs';
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-
-const EXCLUDED = [
-  'node_modules',
-  'lib',
-  '.build',
-  'android/.gradle',
-  'android/.cxx',
-  'android/build',
-];
-
-export function reactNativePackageInputFingerprint({ root, rnDir, examplePackage }) {
-  const files = [
-    ...walk(rnDir),
-    path.join(root, 'src/extensions/generated/sdk/extensions.json'),
-    path.join(root, 'src/extensions/generated/sdk/ios-static-dependencies.json'),
-    ...(examplePackage ? [examplePackage] : []),
-  ].sort(compare);
-  const hash = createHash('sha256');
-  for (const file of files) {
-    const relative = slash(path.relative(root, file));
-    const stat = lstatSync(file);
-    hash.update(`${relative}\0${stat.mode & 0o111 ? 'x' : '-'}\0`);
-    if (stat.isSymbolicLink()) hash.update(`link:${readlinkSync(file)}`);
-    else hash.update(readFileSync(file));
-    hash.update('\0');
-  }
-  return hash.digest('hex');
-}
-
-function walk(root) {
-  const files = [];
-  visit(root, '');
-  return files;
-
-  function visit(directory, relativeDirectory) {
-    for (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) => compare(a.name, b.name))) {
-      const relative = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;
-      if (isExcluded(relative)) continue;
-      const absolute = path.join(directory, entry.name);
-      if (entry.isDirectory()) visit(absolute, relative);
-      else if (entry.isFile() || entry.isSymbolicLink()) files.push(absolute);
-    }
-  }
-}
-
-function isExcluded(relative) {
-  return EXCLUDED.some(prefix => relative === prefix || relative.startsWith(`${prefix}/`));
-}
-
-function slash(value) {
-  return value.split(path.sep).join('/');
-}
-
-function compare(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function parseCli(argv) {
-  const values = {};
-  for (let index = 0; index < argv.length; index += 2) {
-    if (!argv[index]?.startsWith('--') || argv[index + 1] === undefined) {
-      throw new Error('usage: react-native-package-inputs.mjs --root  --rn-dir  [--example-package ]');
-    }
-    values[argv[index].slice(2)] = argv[index + 1];
-  }
-  return values;
-}
-
-if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
-  try {
-    const args = parseCli(process.argv.slice(2));
-    console.log(
-      reactNativePackageInputFingerprint({
-        root: path.resolve(args.root),
-        rnDir: path.resolve(args['rn-dir']),
-        examplePackage: args['example-package'] ? path.resolve(args['example-package']) : undefined,
-      }),
-    );
-  } catch (error) {
-    console.error(`react-native-package-inputs.mjs: ${error.message}`);
-    process.exitCode = 1;
-  }
-}
diff --git a/src/sdks/react-native/tools/react-native-package-inputs.mts b/src/sdks/react-native/tools/react-native-package-inputs.mts
new file mode 100644
index 000000000..100a7542a
--- /dev/null
+++ b/src/sdks/react-native/tools/react-native-package-inputs.mts
@@ -0,0 +1,93 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { lstatSync, readFileSync, readdirSync, readlinkSync } from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const EXCLUDED = [
+  'node_modules',
+  'lib',
+  '.build',
+  'android/.gradle',
+  'android/.cxx',
+  'android/build',
+];
+
+export function reactNativePackageInputFingerprint({ root, rnDir, examplePackage }) {
+  const files = [
+    ...walk(rnDir),
+    path.join(root, 'src/extensions/generated/sdk/extensions.json'),
+    path.join(root, 'src/extensions/generated/sdk/ios-static-dependencies.json'),
+    ...(examplePackage ? [examplePackage] : []),
+  ].sort(compare);
+  const hash = createHash('sha256');
+  for (const file of files) {
+    const relative = slash(path.relative(root, file));
+    const stat = lstatSync(file);
+    hash.update(`${relative}\0${stat.mode & 0o111 ? 'x' : '-'}\0`);
+    if (stat.isSymbolicLink()) hash.update(`link:${readlinkSync(file)}`);
+    else hash.update(readFileSync(file));
+    hash.update('\0');
+  }
+  return hash.digest('hex');
+}
+
+function walk(root) {
+  const files = [];
+  visit(root, '');
+  return files;
+
+  function visit(directory, relativeDirectory) {
+    for (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) =>
+      compare(a.name, b.name),
+    )) {
+      const relative = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;
+      if (isExcluded(relative)) continue;
+      const absolute = path.join(directory, entry.name);
+      if (entry.isDirectory()) visit(absolute, relative);
+      else if (entry.isFile() || entry.isSymbolicLink()) files.push(absolute);
+    }
+  }
+}
+
+function isExcluded(relative) {
+  return EXCLUDED.some((prefix) => relative === prefix || relative.startsWith(`${prefix}/`));
+}
+
+function slash(value) {
+  return value.split(path.sep).join('/');
+}
+
+function compare(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function parseCli(argv) {
+  const values = {};
+  for (let index = 0; index < argv.length; index += 2) {
+    if (!argv[index]?.startsWith('--') || argv[index + 1] === undefined) {
+      throw new Error(
+        'usage: react-native-package-inputs.mts --root  --rn-dir  [--example-package ]',
+      );
+    }
+    values[argv[index].slice(2)] = argv[index + 1];
+  }
+  return values;
+}
+
+if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
+  try {
+    const args = parseCli(process.argv.slice(2));
+    console.log(
+      reactNativePackageInputFingerprint({
+        root: path.resolve(args.root),
+        rnDir: path.resolve(args['rn-dir']),
+        examplePackage: args['example-package'] ? path.resolve(args['example-package']) : undefined,
+      }),
+    );
+  } catch (error) {
+    console.error(`react-native-package-inputs.mts: ${error.message}`);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/sdks/react-native/tools/stage-ios-app.mjs b/src/sdks/react-native/tools/stage-ios-app.mjs
deleted file mode 100755
index 7ce5b4a0b..000000000
--- a/src/sdks/react-native/tools/stage-ios-app.mjs
+++ /dev/null
@@ -1,2808 +0,0 @@
-#!/usr/bin/env node
-
-import { createHash } from "node:crypto";
-import {
-  constants as fsConstants,
-  createReadStream,
-  createWriteStream,
-} from "node:fs";
-import fs from "node:fs/promises";
-import os from "node:os";
-import path from "node:path";
-import { Readable, Transform } from "node:stream";
-import { pipeline } from "node:stream/promises";
-import { fileURLToPath } from "node:url";
-import { spawnSync } from "node:child_process";
-import { createGunzip } from "node:zlib";
-
-import {
-  parseProperties,
-  requireProperty,
-  validateIcuDataCarrier,
-  validateNativeRuntimeClosure,
-} from "./native-resource-closure.mjs";
-
-const PREFIX = "stage-ios-app.mjs";
-const SCHEMA = "oliphaunt-react-native-ios-carrier-v1";
-const OUTPUT_SCHEMA = "oliphaunt-react-native-ios-selection-v1";
-const PORTABLE_RE = /^[A-Za-z0-9._-]{1,128}$/u;
-const C_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/u;
-const STABLE_SEMVER_RE = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u;
-const EXTRACTED_CACHE_SCHEMA = "oliphaunt-extracted-carrier-tree-v1";
-// GitHub release assets are bounded at the transport boundary and archives are
-// bounded again at their expanded boundary. These ceilings are intentionally
-// well above the production iOS payloads while making archive bombs fail before
-// extraction can consume unbounded disk or memory.
-const MAX_CARRIER_BYTES = 2 * 1024 * 1024 * 1024;
-const MAX_ZIP_CARRIER_BYTES = 512 * 1024 * 1024;
-const MAX_ARCHIVE_ENTRIES = 4096;
-// The canonical ICU data payload and base XCFramework contain the complete
-// bundled runtime resource trees and legitimately exceed the general carrier
-// ceiling. Keep that exception tied to those validated base-carrier roles
-// instead of weakening extension and runtime archive protection globally.
-const MAX_BUNDLED_RESOURCE_ARCHIVE_ENTRIES = 16384;
-const MAX_ARCHIVE_MEMBER_BYTES = 1024 * 1024 * 1024;
-const MAX_ARCHIVE_EXPANDED_BYTES = 4 * 1024 * 1024 * 1024;
-const MAX_LEGAL_FILE_BYTES = 16 * 1024 * 1024;
-const MAX_LEGAL_FILES = 1024;
-const SPDX_ID_RE = /^[A-Za-z0-9][A-Za-z0-9.-]*$/u;
-const ALLOWED_ZIP_EXTRA_FIELDS = new Set([0x5455, 0x5855, 0x7875]);
-const EXTENSION_ARTIFACT_PROPERTY_KEYS = new Set([
-  "packageLayout",
-  "pgMajor",
-  "sqlName",
-  "createsExtension",
-  "nativeModuleStem",
-  "nativeModuleFile",
-  "nativeTarget",
-  "nativeRuntimeProduct",
-  "nativeRuntimeVersion",
-  "dependencies",
-  "dataFiles",
-  "extensionSqlFileNames",
-  "extensionSqlFilePrefixes",
-  "sharedPreloadLibraries",
-  "mobilePrebuilt",
-  "mobileStaticArchives",
-  "mobileStaticDependencyArchives",
-  "staticSymbolPrefix",
-  "staticSymbolAliases",
-  "licenseFiles",
-  "licenseProfile",
-  "files",
-]);
-const GENERATED_EXTENSION_CATALOG = JSON.parse(
-  await fs.readFile(
-    await Promise.any([
-      new URL("../src/generated/extensions.json", import.meta.url),
-      new URL("../../../extensions/generated/sdk/extensions.json", import.meta.url),
-    ].map(async (url) => {
-      await fs.access(url);
-      return url;
-    })),
-    "utf8",
-  ),
-);
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function fail(message) {
-  throw new Error(`${PREFIX}: ${message}`);
-}
-
-function usage() {
-  console.error(
-    `usage: ${PREFIX} --carrier  [--carrier ]... ` +
-      `--output-dir  [--extensions ] [--icu] ` +
-      `[--cache-dir ] [--allow-file-urls]`,
-  );
-}
-
-function parseArgs(argv) {
-  const args = {
-    allowFileUrls: false,
-    cacheDir: path.join(os.homedir(), ".cache", "oliphaunt", "react-native-ios"),
-    carriers: [],
-    extensions: [],
-    icu: false,
-  };
-  for (let index = 0; index < argv.length; index += 1) {
-    const arg = argv[index];
-    if (arg === "--allow-file-urls") {
-      args.allowFileUrls = true;
-      continue;
-    }
-    if (arg === "--icu") {
-      args.icu = true;
-      continue;
-    }
-    if (arg === "--help" || arg === "-h") {
-      usage();
-      process.exit(0);
-    }
-    if (
-      ![
-        "--carrier",
-        "--base-carrier",
-        "--cache-dir",
-        "--extension-carrier",
-        "--extensions",
-        "--output-dir",
-      ].includes(arg)
-    ) {
-      usage();
-      fail(`unknown argument ${arg}`);
-    }
-    const value = argv[index + 1];
-    if (value === undefined || value.startsWith("--")) {
-      fail(`${arg} requires a value`);
-    }
-    index += 1;
-    if (arg === "--carrier" || arg === "--base-carrier") args.carriers.push(path.resolve(value));
-    if (arg === "--cache-dir") args.cacheDir = path.resolve(value);
-    if (arg === "--extension-carrier") args.carriers.push(path.resolve(value));
-    if (arg === "--output-dir") args.outputDir = path.resolve(value);
-    if (arg === "--extensions") {
-      args.extensions.push(...value.split(",").map((item) => item.trim()).filter(Boolean));
-    }
-  }
-  if (args.carriers.length === 0 || !args.outputDir) {
-    usage();
-    fail("at least one --carrier and --output-dir are required");
-  }
-  args.extensions = uniquePortable(args.extensions, "selected extension");
-  return args;
-}
-
-function object(value, label) {
-  if (value === null || Array.isArray(value) || typeof value !== "object") {
-    fail(`${label} must be an object`);
-  }
-  return value;
-}
-
-function exactKeys(value, allowed, label) {
-  const actual = Object.keys(value).sort(compareText);
-  const expected = [...allowed].sort(compareText);
-  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
-    fail(`${label} fields must be exactly ${expected.join(",")}; got ${actual.join(",")}`);
-  }
-}
-
-function portable(value, label) {
-  if (typeof value !== "string" || !PORTABLE_RE.test(value)) {
-    fail(`${label} must be a portable identifier`);
-  }
-  return value;
-}
-
-function stableVersion(value, label) {
-  if (typeof value !== "string" || !STABLE_SEMVER_RE.test(value)) {
-    fail(`${label} must be a stable SemVer X.Y.Z version`);
-  }
-  return value;
-}
-
-function cIdentifier(value, label) {
-  if (typeof value !== "string" || !C_IDENTIFIER_RE.test(value)) {
-    fail(`${label} must be a C identifier`);
-  }
-  return value;
-}
-
-function uniquePortable(value, label) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const result = value.map((item, index) => portable(item, `${label}[${index}]`));
-  if (new Set(result).size !== result.length) fail(`${label} must not contain duplicates`);
-  return result.sort(compareText);
-}
-
-function canonicalPortableList(value, label) {
-  const canonical = uniquePortable(value, label);
-  if (JSON.stringify(value) !== JSON.stringify(canonical)) {
-    fail(`${label} must be sorted in ordinal order`);
-  }
-  return canonical;
-}
-
-function generatedExtensionCatalog(value) {
-  const catalog = object(value, "generated React Native extension catalog");
-  if (!Array.isArray(catalog.extensions)) {
-    fail("generated React Native extension catalog.extensions must be an array");
-  }
-  const rows = new Map();
-  for (const [index, raw] of catalog.extensions.entries()) {
-    const row = object(raw, `generated React Native extension catalog.extensions[${index}]`);
-    const sqlName = portable(
-      row["sql-name"],
-      `generated React Native extension catalog.extensions[${index}].sql-name`,
-    );
-    const artifactProduct = portable(
-      row["artifact-product"],
-      `generated React Native extension catalog.extensions[${index}].artifact-product`,
-    );
-    const releaseProduct = portable(
-      row["release-product"],
-      `generated React Native extension catalog.extensions[${index}].release-product`,
-    );
-    if (!artifactProduct.startsWith("oliphaunt-extension-")) {
-      fail(`generated artifact product for ${sqlName} must be an extension product`);
-    }
-    if (typeof row["runtime-bound"] !== "boolean") {
-      fail(`generated runtime-bound flag for ${sqlName} must be boolean`);
-    }
-    if (rows.has(sqlName)) fail(`generated React Native extension catalog repeats ${sqlName}`);
-    rows.set(sqlName, {
-      artifactProduct,
-      releaseProduct,
-      runtimeBound: row["runtime-bound"],
-    });
-  }
-  return rows;
-}
-
-const GENERATED_EXTENSION_BY_SQL_NAME = generatedExtensionCatalog(GENERATED_EXTENSION_CATALOG);
-
-function safeRelative(value, label) {
-  if (
-    typeof value !== "string" || value.length === 0 || value.includes("\\") ||
-    /[\u0000-\u001f\u007f]/u.test(value) || /^[A-Za-z]:/u.test(value)
-  ) {
-    fail(`${label} must be a non-empty archive-relative path`);
-  }
-  if (value === ".") return value;
-  const normalized = value.replace(/^\.\//u, "");
-  const parts = normalized.split("/");
-  if (path.isAbsolute(value) || parts.some((part) => !part || part === "." || part === "..")) {
-    fail(`${label} is not a safe archive-relative path: ${JSON.stringify(value)}`);
-  }
-  return normalized;
-}
-
-function spdxConjunction(value, label) {
-  if (typeof value !== "string" || value.length === 0) {
-    fail(`${label} must be a non-empty SPDX conjunction`);
-  }
-  const terms = value.split(" AND ");
-  if (terms.some((term) => !SPDX_ID_RE.test(term))) {
-    fail(`${label} must contain only SPDX identifiers joined by AND`);
-  }
-  if (new Set(terms).size !== terms.length) fail(`${label} repeats an SPDX identifier`);
-  return value;
-}
-
-function validateLegalFiles(value, label) {
-  if (!Array.isArray(value) || value.length === 0 || value.length > MAX_LEGAL_FILES) {
-    fail(`${label} must contain between 1 and ${MAX_LEGAL_FILES} legal file locators`);
-  }
-  const rows = value.map((raw, index) => {
-    const row = object(raw, `${label}[${index}]`);
-    exactKeys(row, ["bytes", "kind", "member", "sha256"], `${label}[${index}]`);
-    const member = safeRelative(row.member, `${label}[${index}].member`);
-    if (member === ".") fail(`${label}[${index}].member must name a file`);
-    if (!Number.isSafeInteger(row.bytes) || row.bytes <= 0 || row.bytes > MAX_LEGAL_FILE_BYTES) {
-      fail(`${label}[${index}].bytes must be between 1 and ${MAX_LEGAL_FILE_BYTES}`);
-    }
-    if (!new Set(["license", "notice"]).has(row.kind)) {
-      fail(`${label}[${index}].kind must be license or notice`);
-    }
-    if (typeof row.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(row.sha256)) {
-      fail(`${label}[${index}].sha256 must be a lowercase SHA-256 digest`);
-    }
-    return { bytes: row.bytes, kind: row.kind, member, sha256: row.sha256 };
-  });
-  const canonical = [...rows].sort((left, right) => compareText(left.member, right.member));
-  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
-    fail(`${label} must be sorted by archive member in ordinal order`);
-  }
-  const folded = new Map();
-  for (const row of rows) {
-    const key = row.member.normalize("NFC").toLowerCase();
-    const prior = folded.get(key);
-    if (prior !== undefined) {
-      fail(`${label} has colliding legal members ${prior} and ${row.member}`);
-    }
-    folded.set(key, row.member);
-  }
-  return rows;
-}
-
-function validateLegalGroup(value, label, { sqlName = undefined } = {}) {
-  const row = object(value, label);
-  const keys = sqlName === undefined
-    ? ["assetRole", "files", "profile", "spdx"]
-    : ["assetRole", "files", "profile", "spdx", "sqlName"];
-  exactKeys(row, keys, label);
-  if (sqlName !== undefined && row.sqlName !== sqlName) {
-    fail(`${label}.sqlName must be ${sqlName}`);
-  }
-  return {
-    assetRole: portable(row.assetRole, `${label}.assetRole`),
-    files: validateLegalFiles(row.files, `${label}.files`),
-    profile: portable(row.profile, `${label}.profile`),
-    spdx: spdxConjunction(row.spdx, `${label}.spdx`),
-    ...(sqlName === undefined ? {} : { sqlName }),
-  };
-}
-
-function portableAssetName(value, label) {
-  if (
-    typeof value !== "string" || value.length === 0 || path.posix.basename(value) !== value ||
-    /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) || /[ .]$/u.test(value) ||
-    /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value)
-  ) {
-    fail(`${label} must be a portable release asset file name`);
-  }
-  return value;
-}
-
-function canonicalRelativeFileList(value, label) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((item, index) => {
-    const relative = safeRelative(item, `${label}[${index}]`);
-    if (relative === ".") fail(`${label}[${index}] must name a file`);
-    return relative;
-  });
-  const canonical = [...rows].sort(compareText);
-  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
-  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
-    fail(`${label} must be sorted in ordinal order`);
-  }
-  return rows;
-}
-
-function canonicalSqlFileNameList(value, label) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((item, index) => {
-    const name = portable(item, `${label}[${index}]`);
-    if (!name.endsWith(".sql")) fail(`${label}[${index}] must name a SQL file`);
-    return name;
-  });
-  const canonical = [...rows].sort(compareText);
-  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
-  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
-    fail(`${label} must be sorted in ordinal order`);
-  }
-  return rows;
-}
-
-function canonicalSqlFilePrefixList(value, label) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((item, index) => {
-    if (typeof item !== "string" || !/^[A-Za-z0-9_-]{1,128}$/u.test(item)) {
-      fail(`${label}[${index}] must be a dot-free portable SQL basename prefix`);
-    }
-    return item;
-  });
-  const canonical = [...rows].sort(compareText);
-  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
-  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
-    fail(`${label} must be sorted in ordinal order`);
-  }
-  return rows;
-}
-
-function boundedBytes(value, label, maximum = MAX_CARRIER_BYTES) {
-  if (!Number.isSafeInteger(value) || value <= 0) {
-    fail(`${label} must be a positive safe integer`);
-  }
-  if (value > maximum) {
-    fail(`${label} exceeds the maximum supported size of ${maximum} bytes`);
-  }
-  return value;
-}
-
-function archiveEntryLimit(asset) {
-  return asset.role === "icu-data" || asset.role === "base-xcframework"
-    ? MAX_BUNDLED_RESOURCE_ARCHIVE_ENTRIES
-    : MAX_ARCHIVE_ENTRIES;
-}
-
-function archiveStreamLimit(maxEntries) {
-  // Each ustar member contributes one 512-byte header and up to 511 bytes of
-  // payload padding in addition to its declared expanded size.
-  return MAX_ARCHIVE_EXPANDED_BYTES + maxEntries * 1024 + 1024;
-}
-
-function validateAsset(value, label, allowFileUrls) {
-  const asset = object(value, label);
-  exactKeys(asset, ["bytes", "format", "member", "name", "role", "sha256", "url"], label);
-  const role = portable(asset.role, `${label}.role`);
-  portableAssetName(asset.name, `${label}.name`);
-  if (!["tar.gz", "zip"].includes(asset.format)) {
-    fail(`${label}.format must be tar.gz or zip`);
-  }
-  if (typeof asset.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(asset.sha256)) {
-    fail(`${label}.sha256 must be a lowercase SHA-256 digest`);
-  }
-  boundedBytes(asset.bytes, `${label}.bytes`);
-  let url;
-  try {
-    url = new URL(asset.url);
-  } catch {
-    fail(`${label}.url must be an absolute URL`);
-  }
-  if (url.protocol !== "https:" && !(allowFileUrls && url.protocol === "file:")) {
-    fail(`${label}.url must use HTTPS${allowFileUrls ? " or an explicitly enabled file URL" : ""}`);
-  }
-  let urlName;
-  try {
-    urlName = decodeURIComponent(path.basename(url.pathname));
-  } catch {
-    fail(`${label}.url contains invalid escaping`);
-  }
-  if (urlName !== asset.name) {
-    fail(`${label}.url must end with ${asset.name}`);
-  }
-  if (
-    (asset.format === "zip" && !asset.name.endsWith(".zip")) ||
-    (asset.format === "tar.gz" && !asset.name.endsWith(".tar.gz"))
-  ) {
-    fail(`${label}.name does not match format ${asset.format}`);
-  }
-  return {
-    bytes: asset.bytes,
-    format: asset.format,
-    member: safeRelative(asset.member, `${label}.member`),
-    name: asset.name,
-    role,
-    sha256: asset.sha256,
-    url: url.href,
-  };
-}
-
-function validateCarrierEnvelope(value, label, allowFileUrls) {
-  const carrier = object(value, label);
-  exactKeys(carrier, ["bytes", "format", "name", "sha256", "url"], label);
-  portableAssetName(carrier.name, `${label}.name`);
-  boundedBytes(carrier.bytes, `${label}.bytes`);
-  if (typeof carrier.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(carrier.sha256)) {
-    fail(`${label}.sha256 must be a lowercase SHA-256 digest`);
-  }
-  if (!["tar.gz", "zip"].includes(carrier.format)) {
-    fail(`${label}.format must be tar.gz or zip`);
-  }
-  if (
-    (carrier.format === "zip" && !carrier.name.endsWith(".zip")) ||
-    (carrier.format === "tar.gz" && !carrier.name.endsWith(".tar.gz"))
-  ) {
-    fail(`${label}.name does not match format ${carrier.format}`);
-  }
-  let url;
-  try {
-    url = new URL(carrier.url);
-  } catch {
-    fail(`${label}.url must be an absolute URL`);
-  }
-  if (url.protocol !== "https:" && !(allowFileUrls && url.protocol === "file:")) {
-    fail(`${label}.url must use HTTPS${allowFileUrls ? " or an explicitly enabled file URL" : ""}`);
-  }
-  let urlName;
-  try {
-    urlName = decodeURIComponent(path.posix.basename(url.pathname));
-  } catch {
-    fail(`${label}.url contains invalid escaping`);
-  }
-  if (urlName !== carrier.name) fail(`${label}.url must end with ${carrier.name}`);
-  return {
-    bytes: carrier.bytes,
-    format: carrier.format,
-    name: carrier.name,
-    sha256: carrier.sha256,
-    url: url.href,
-  };
-}
-
-function validateCarrierEnvelopes(value, label, allowFileUrls) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((row, index) =>
-    validateCarrierEnvelope(row, `${label}[${index}]`, allowFileUrls));
-  if (new Set(rows.map(({ name }) => name)).size !== rows.length) {
-    fail(`${label} repeats a carrier name`);
-  }
-  rows.sort((left, right) => compareText(left.name, right.name));
-  return new Map(rows.map((row) => [row.name, row]));
-}
-
-function validateAssetLocator(value, label, carriers) {
-  const asset = object(value, label);
-  exactKeys(asset, ["bytes", "carrier", "format", "member", "path", "role", "sha256"], label);
-  const role = portable(asset.role, `${label}.role`);
-  const carrierName = portableAssetName(asset.carrier, `${label}.carrier`);
-  const envelope = carriers.get(carrierName);
-  if (envelope === undefined) {
-    fail(`${label}.carrier references undeclared envelope ${carrierName}`);
-  }
-  const logicalPath = safeRelative(asset.path, `${label}.path`);
-  const member = safeRelative(asset.member, `${label}.member`);
-  boundedBytes(asset.bytes, `${label}.bytes`);
-  if (typeof asset.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(asset.sha256)) {
-    fail(`${label}.sha256 must be a lowercase SHA-256 digest`);
-  }
-  if (!["tar.gz", "zip"].includes(asset.format)) {
-    fail(`${label}.format must be tar.gz or zip`);
-  }
-  if (logicalPath === ".") {
-    if (
-      asset.bytes !== envelope.bytes || asset.sha256 !== envelope.sha256 ||
-      asset.format !== envelope.format
-    ) {
-      fail(`${label} direct payload metadata must exactly match carrier ${carrierName}`);
-    }
-  } else {
-    if (envelope.format !== "tar.gz") {
-      fail(`${label} nested payload carrier must be a tar.gz archive`);
-    }
-    const nestedName = path.posix.basename(logicalPath);
-    portableAssetName(nestedName, `${label}.path basename`);
-    if (
-      (asset.format === "zip" && !nestedName.endsWith(".zip")) ||
-      (asset.format === "tar.gz" && !nestedName.endsWith(".tar.gz"))
-    ) {
-      fail(`${label}.path does not match logical payload format ${asset.format}`);
-    }
-  }
-  return {
-    bytes: asset.bytes,
-    carrier: carrierName,
-    envelope,
-    format: asset.format,
-    member,
-    path: logicalPath,
-    role,
-    sha256: asset.sha256,
-  };
-}
-
-function validateAssetLocatorList(value, label, carriers) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const assets = value.map((asset, index) =>
-    validateAssetLocator(asset, `${label}[${index}]`, carriers));
-  const identities = assets.map(({ carrier, member, path: logicalPath, role }) =>
-    `${role}\0${member}\0${carrier}\0${logicalPath}`);
-  if (new Set(identities).size !== assets.length) {
-    fail(`${label} repeats an asset locator identity`);
-  }
-  return assets.sort((left, right) => compareText(
-    `${left.role}\0${left.member}\0${left.carrier}\0${left.path}`,
-    `${right.role}\0${right.member}\0${right.carrier}\0${right.path}`,
-  ));
-}
-
-function validateRegistration(value, label) {
-  const registration = object(value, label);
-  exactKeys(registration, ["initSymbol", "magicSymbol", "symbols"], label);
-  const initSymbol = registration.initSymbol === null
-    ? null
-    : cIdentifier(registration.initSymbol, `${label}.initSymbol`);
-  const magicSymbol = cIdentifier(registration.magicSymbol, `${label}.magicSymbol`);
-  if (!Array.isArray(registration.symbols)) fail(`${label}.symbols must be an array`);
-  const declaredSymbols = registration.symbols.map((raw, index) => {
-    const row = object(raw, `${label}.symbols[${index}]`);
-    exactKeys(row, ["address", "name"], `${label}.symbols[${index}]`);
-    return {
-      address: cIdentifier(row.address, `${label}.symbols[${index}].address`),
-      name: cIdentifier(row.name, `${label}.symbols[${index}].name`),
-    };
-  });
-  const symbols = [...declaredSymbols].sort((left, right) => compareText(
-    `${left.name}\0${left.address}`,
-    `${right.name}\0${right.address}`,
-  ));
-  if (JSON.stringify(declaredSymbols) !== JSON.stringify(symbols)) {
-    fail(`${label}.symbols must be sorted in ordinal name/address order`);
-  }
-  if (new Set(symbols.map(({ name }) => name)).size !== symbols.length) {
-    fail(`${label}.symbols repeats a SQL symbol`);
-  }
-  return { initSymbol, magicSymbol, symbols };
-}
-
-function validateAssetList(value, label, allowFileUrls) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const assets = value.map((asset, index) =>
-    validateAsset(asset, `${label}[${index}]`, allowFileUrls));
-  const identities = assets.map(({ role, member }) => `${role}\0${member}`);
-  if (new Set(identities).size !== identities.length) {
-    fail(`${label} repeats an asset role/member identity`);
-  }
-  if (new Set(assets.map(({ name }) => name)).size !== assets.length) {
-    fail(`${label} repeats an asset name`);
-  }
-  return assets.sort((left, right) => compareText(
-    `${left.role}\0${left.member}`,
-    `${right.role}\0${right.member}`,
-  ));
-}
-
-function exactlyOneRole(assets, role, label) {
-  const matches = assets.filter((asset) => asset.role === role);
-  if (matches.length !== 1) fail(`${label} must contain exactly one ${role} asset`);
-  return matches[0];
-}
-
-function noOtherRoles(assets, roles, label) {
-  const extras = assets.filter((asset) => !roles.includes(asset.role));
-  if (extras.length > 0) {
-    fail(`${label} contains unsupported asset role(s): ${[...new Set(extras.map(({ role }) => role))].sort(compareText).join(",")}`);
-  }
-}
-
-function validateBase(value, label, allowFileUrls) {
-  const base = object(value, label);
-  exactKeys(base, ["assets", "product", "tag", "version"], label);
-  if (base.product !== "liboliphaunt-native") fail(`${label}.product must be liboliphaunt-native`);
-  const assets = validateAssetList(base.assets, `${label}.assets`, allowFileUrls);
-  noOtherRoles(assets, ["base-xcframework", "icu-data", "runtime-resources"], `${label}.assets`);
-  const framework = exactlyOneRole(assets, "base-xcframework", `${label}.assets`);
-  const runtime = exactlyOneRole(assets, "runtime-resources", `${label}.assets`);
-  const icu = exactlyOneRole(assets, "icu-data", `${label}.assets`);
-  const frameworkName = portable(
-    path.posix.basename(framework.member),
-    `${label} base-xcframework member basename`,
-  );
-  if (!frameworkName.endsWith(".xcframework")) {
-    fail(`${label} base-xcframework member must be an XCFramework directory`);
-  }
-  const version = stableVersion(base.version, `${label}.version`);
-  const expectedRuntimeName =
-    `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`;
-  if (runtime.name !== expectedRuntimeName) {
-    fail(`${label} runtime-resources asset must be ${expectedRuntimeName}`);
-  }
-  const expectedTag = `${base.product}-v${version}`;
-  if (base.tag !== expectedTag) fail(`${label}.tag must be ${expectedTag}`);
-  return {
-    assets: { framework, icu, runtime },
-    kind: "base",
-    product: base.product,
-    tag: base.tag,
-    version,
-  };
-}
-
-function validateExtension(value, label, carriers) {
-  const root = object(value, label);
-  exactKeys(
-    root,
-    [
-      "assets", "createsExtension", "dataFiles", "dependencies", "extensionSqlFileNames",
-      "extensionSqlFilePrefixes", "nativeDependencies", "nativeModuleStem", "product",
-      "registration", "releaseProduct", "sharedPreloadLibraries", "sqlName", "tag", "version",
-    ],
-    label,
-  );
-  const sqlName = portable(root.sqlName, `${label}.sqlName`);
-  const generated = GENERATED_EXTENSION_BY_SQL_NAME.get(sqlName);
-  if (generated === undefined) {
-    fail(`${label}.sqlName is not in the generated React Native extension catalog`);
-  }
-  const artifactProduct = portable(root.product, `${label}.product`);
-  if (artifactProduct !== generated.artifactProduct) {
-    fail(
-      `${label}.product must be canonical artifact product ${generated.artifactProduct} for SQL member ${sqlName}`,
-    );
-  }
-  const releaseProduct = portable(root.releaseProduct, `${label}.releaseProduct`);
-  if (releaseProduct !== generated.releaseProduct) {
-    fail(
-      `${label}.releaseProduct must be canonical owner ${generated.releaseProduct} for SQL member ${sqlName}`,
-    );
-  }
-  const version = stableVersion(root.version, `${label}.version`);
-  const expectedTag = `${releaseProduct}-v${version}`;
-  if (root.tag !== expectedTag) fail(`${label}.tag must be ${expectedTag}`);
-  if (typeof root.createsExtension !== "boolean") fail(`${label}.createsExtension must be boolean`);
-  const dataFiles = canonicalRelativeFileList(root.dataFiles, `${label}.dataFiles`);
-  const dependencies = canonicalPortableList(root.dependencies, `${label}.dependencies`);
-  if (dependencies.includes(sqlName)) fail(`${label}.dependencies must not include ${sqlName} itself`);
-  const extensionSqlFileNames = canonicalSqlFileNameList(
-    root.extensionSqlFileNames,
-    `${label}.extensionSqlFileNames`,
-  );
-  const extensionSqlFilePrefixes = canonicalSqlFilePrefixList(
-    root.extensionSqlFilePrefixes,
-    `${label}.extensionSqlFilePrefixes`,
-  );
-  const nativeDependencies = canonicalPortableList(
-    root.nativeDependencies,
-    `${label}.nativeDependencies`,
-  );
-  const nativeModuleStem = root.nativeModuleStem === null
-    ? null
-    : portable(root.nativeModuleStem, `${label}.nativeModuleStem`);
-  const sharedPreloadLibraries = canonicalPortableList(
-    root.sharedPreloadLibraries,
-    `${label}.sharedPreloadLibraries`,
-  );
-  const assets = validateAssetLocatorList(root.assets, `${label}.assets`, carriers);
-  noOtherRoles(
-    assets,
-    ["dependency-xcframework", "extension-xcframework", "runtime-resources"],
-    `${label}.assets`,
-  );
-  const runtime = exactlyOneRole(assets, "runtime-resources", `${label}.assets`);
-  let extension = null;
-  let dependencyFrameworks = [];
-  let registration = null;
-  if (nativeModuleStem === null) {
-    if (assets.some(({ role }) => role !== "runtime-resources") || root.registration !== null || nativeDependencies.length > 0) {
-      fail(`${label} SQL-only carrier must not fabricate frameworks, registration, or native dependencies`);
-    }
-  } else {
-    extension = exactlyOneRole(assets, "extension-xcframework", `${label}.assets`);
-    const expectedExtension = `liboliphaunt_extension_${nativeModuleStem}.xcframework`;
-    if (path.posix.basename(extension.member) !== expectedExtension) {
-      fail(`${label} extension-xcframework member must end with ${expectedExtension}`);
-    }
-    dependencyFrameworks = assets
-      .filter(({ role }) => role === "dependency-xcframework")
-      .map((asset) => {
-        const basename = path.posix.basename(asset.member);
-        const match = /^liboliphaunt_dependency_(.+)\.xcframework$/u.exec(basename);
-        if (!match || !PORTABLE_RE.test(match[1])) {
-          fail(`${label} dependency-xcframework member has invalid canonical name ${basename}`);
-        }
-        return { asset, dependency: match[1] };
-      })
-      .sort((left, right) => compareText(left.dependency, right.dependency));
-    if (new Set(dependencyFrameworks.map(({ dependency }) => dependency)).size !== dependencyFrameworks.length) {
-      fail(`${label} repeats a dependency carrier identity`);
-    }
-    if (
-      JSON.stringify(dependencyFrameworks.map(({ dependency }) => dependency)) !==
-      JSON.stringify(nativeDependencies)
-    ) {
-      fail(`${label} dependency-xcframework roles do not exactly match nativeDependencies`);
-    }
-    if (root.registration === null) fail(`${label} native carrier requires registration metadata`);
-    registration = validateRegistration(root.registration, `${label}.registration`);
-    const prefix = `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`;
-    if (registration.magicSymbol !== `${prefix}_Pg_magic_func`) {
-      fail(`${label}.registration.magicSymbol does not match nativeModuleStem`);
-    }
-    if (![null, `${prefix}__PG_init`].includes(registration.initSymbol)) {
-      fail(`${label}.registration.initSymbol does not match nativeModuleStem`);
-    }
-  }
-  return {
-    assets: { dependencyFrameworks, extension, runtime },
-    createsExtension: root.createsExtension,
-    dataFiles,
-    dependencies,
-    extensionSqlFileNames,
-    extensionSqlFilePrefixes,
-    kind: "extension",
-    nativeDependencies,
-    nativeModuleStem,
-    product: artifactProduct,
-    releaseProduct,
-    registration,
-    sharedPreloadLibraries,
-    sqlName,
-    tag: root.tag,
-    version,
-    runtimeBound: generated.runtimeBound,
-  };
-}
-
-function validateLegalDocument(value, label, base, extensions) {
-  const legal = object(value, label);
-  exactKeys(legal, ["base", "extensions"], label);
-  if (!Array.isArray(legal.base)) fail(`${label}.base must be an array`);
-  const baseGroups = legal.base.map((row, index) =>
-    validateLegalGroup(row, `${label}.base[${index}]`));
-  const expectedBaseRoles = ["base-xcframework", "runtime-resources", "icu-data"];
-  if (JSON.stringify(baseGroups.map(({ assetRole }) => assetRole)) !== JSON.stringify(expectedBaseRoles)) {
-    fail(`${label}.base asset roles must be exactly ${expectedBaseRoles.join(",")}`);
-  }
-  const baseAssets = new Map([
-    [base.assets.framework.role, base.assets.framework],
-    [base.assets.runtime.role, base.assets.runtime],
-    [base.assets.icu.role, base.assets.icu],
-  ]);
-  for (const group of baseGroups) {
-    if (!baseAssets.has(group.assetRole)) {
-      fail(`${label}.base legal group references missing asset role ${group.assetRole}`);
-    }
-  }
-
-  if (!Array.isArray(legal.extensions)) fail(`${label}.extensions must be an array`);
-  const extensionByName = new Map(extensions.map((extension) => [extension.sqlName, extension]));
-  const extensionGroups = legal.extensions.map((row, index) => {
-    const raw = object(row, `${label}.extensions[${index}]`);
-    const sqlName = portable(raw.sqlName, `${label}.extensions[${index}].sqlName`);
-    const extension = extensionByName.get(sqlName);
-    if (extension === undefined) {
-      fail(`${label}.extensions[${index}] references undeclared extension ${sqlName}`);
-    }
-    const group = validateLegalGroup(raw, `${label}.extensions[${index}]`, { sqlName });
-    if (group.assetRole !== "runtime-resources" || extension.assets.runtime.role !== group.assetRole) {
-      fail(`${label}.extensions[${index}] legal bytes must come from its runtime-resources asset`);
-    }
-    return group;
-  });
-  const expectedNames = [...extensionByName.keys()].sort(compareText);
-  const actualNames = extensionGroups.map(({ sqlName }) => sqlName);
-  if (JSON.stringify(actualNames) !== JSON.stringify(expectedNames)) {
-    fail(`${label}.extensions must exactly cover carrier extensions in ordinal order`);
-  }
-  const legalByName = new Map(extensionGroups.map((group) => [group.sqlName, group]));
-  return {
-    base: baseGroups,
-    extensions: legalByName,
-  };
-}
-
-function assertExactCarrierCoverage(carriers, extensions, label) {
-  const referenced = new Set(
-    extensions.flatMap((extension) => [
-      extension.assets.runtime,
-      extension.assets.extension,
-      ...extension.assets.dependencyFrameworks.map(({ asset }) => asset),
-    ].filter(Boolean).map(({ carrier }) => carrier)),
-  );
-  const declared = [...carriers.keys()].sort(compareText);
-  const used = [...referenced].sort(compareText);
-  if (JSON.stringify(declared) !== JSON.stringify(used)) {
-    fail(
-      `${label} carrier envelopes must exactly cover referenced logical payloads; ` +
-        `declared=${declared.join(",")}, used=${used.join(",")}`,
-    );
-  }
-}
-
-async function readCarrierDocument(file, allowFileUrls) {
-  let value;
-  try {
-    value = JSON.parse(await fs.readFile(file, "utf8"));
-  } catch (error) {
-    fail(`could not read carrier ${file}: ${error.message}`);
-  }
-  const root = object(value, file);
-  if (root.schema !== SCHEMA) fail(`${file} schema must be ${SCHEMA}`);
-  exactKeys(root, ["base", "carriers", "extensions", "legal", "schema"], file);
-  if (!Array.isArray(root.extensions)) fail(`${file}.extensions must be an array`);
-  const base = validateBase(root.base, `${file}.base`, allowFileUrls);
-  const carriers = validateCarrierEnvelopes(
-    root.carriers,
-    `${file}.carriers`,
-    allowFileUrls,
-  );
-  const extensions = root.extensions.map((extension, index) =>
-    validateExtension(extension, `${file}.extensions[${index}]`, carriers));
-  const names = extensions.map(({ sqlName }) => sqlName);
-  if (new Set(names).size !== names.length) fail(`${file}.extensions repeats an exact extension row`);
-  const legal = validateLegalDocument(root.legal, `${file}.legal`, base, extensions);
-  base.legal = legal.base;
-  for (const extension of extensions) extension.legal = legal.extensions.get(extension.sqlName);
-  assertExactCarrierCoverage(carriers, extensions, file);
-  const releases = new Map();
-  for (const extension of extensions) {
-    const prior = releases.get(extension.releaseProduct);
-    const release = { tag: extension.tag, version: extension.version };
-    if (prior !== undefined && JSON.stringify(prior) !== JSON.stringify(release)) {
-      fail(`${file} contains conflicting release versions for owner ${extension.releaseProduct}`);
-    }
-    releases.set(extension.releaseProduct, release);
-    if (extension.runtimeBound && extension.version !== base.version) {
-      fail(
-        `${file} runtime-bound owner ${extension.releaseProduct} version ${extension.version} ` +
-          `must match base runtime ${base.version}`,
-      );
-    }
-  }
-  return { base, carriers, extensions, source: file };
-}
-
-async function sha256File(file) {
-  const hash = createHash("sha256");
-  await pipeline(createReadStream(file), hash);
-  return hash.digest("hex");
-}
-
-async function statOrUndefined(file) {
-  return fs.lstat(file).catch((error) => {
-    if (error?.code === "ENOENT") return undefined;
-    throw error;
-  });
-}
-
-async function requireCacheDirectory(cacheDir, directory) {
-  const root = path.resolve(cacheDir);
-  const target = path.resolve(directory);
-  const suffix = path.relative(root, target);
-  if (suffix === ".." || suffix.startsWith(`..${path.sep}`)) {
-    fail(`cache directory escapes configured cache root: ${target}`);
-  }
-
-  await fs.mkdir(root, { recursive: true, mode: 0o700 });
-  const rootStat = await statOrUndefined(root);
-  if (rootStat?.isSymbolicLink() || rootStat?.isDirectory() !== true) {
-    fail(`cache root must be a real directory, not a symlink: ${root}`);
-  }
-
-  let current = root;
-  for (const component of suffix.split(path.sep).filter(Boolean)) {
-    current = path.join(current, component);
-    let stat = await statOrUndefined(current);
-    if (stat === undefined) {
-      try {
-        await fs.mkdir(current, { mode: 0o700 });
-      } catch (error) {
-        if (error?.code !== "EEXIST") throw error;
-      }
-      stat = await statOrUndefined(current);
-    }
-    if (stat?.isSymbolicLink() || stat?.isDirectory() !== true) {
-      fail(`cache path component must be a real directory, not a symlink: ${current}`);
-    }
-  }
-  return target;
-}
-
-async function rejectCacheLeafSymlink(file) {
-  if ((await statOrUndefined(file))?.isSymbolicLink()) {
-    fail(`cache entry must not be a symlink: ${file}`);
-  }
-}
-
-function byteLimitTransform(limit, label) {
-  let bytes = 0;
-  return new Transform({
-    transform(chunk, _encoding, callback) {
-      bytes += chunk.length;
-      if (bytes > limit) {
-        callback(new Error(`${PREFIX}: ${label} exceeds its frozen ${limit}-byte limit`));
-        return;
-      }
-      callback(null, chunk);
-    },
-  });
-}
-
-async function requirePayloadDirectory(file, label) {
-  if ((await statOrUndefined(file))?.isDirectory() !== true) {
-    fail(`${label} is missing: ${file}`);
-  }
-}
-
-async function materializeAsset(asset, cacheDir) {
-  const objects = await requireCacheDirectory(cacheDir, path.join(cacheDir, "objects"));
-  const cached = path.join(objects, `${asset.sha256}-${asset.name}`);
-  await rejectCacheLeafSymlink(cached);
-  if ((await statOrUndefined(cached))?.isFile() === true) {
-    const stat = await fs.stat(cached);
-    if (stat.size === asset.bytes && (await sha256File(cached)) === asset.sha256) return cached;
-  }
-  await fs.rm(cached, { force: true, recursive: true });
-  const temporary = `${cached}.tmp-${process.pid}-${Date.now()}`;
-  const url = new URL(asset.url);
-  try {
-    if (url.protocol === "file:") {
-      const source = fileURLToPath(url);
-      const sourceStat = await statOrUndefined(source);
-      if (sourceStat?.isFile() !== true || sourceStat.isSymbolicLink()) {
-        fail(`file URL is not a regular non-symlink file: ${asset.url}`);
-      }
-      if (sourceStat.size !== asset.bytes) {
-        fail(`size mismatch for ${asset.name}; expected ${asset.bytes}, got ${sourceStat.size}`);
-      }
-      await fs.copyFile(source, temporary, fsConstants.COPYFILE_EXCL);
-    } else {
-      const response = await fetch(url, { redirect: "follow" });
-      if (!response.ok || response.body === null) {
-        fail(`download ${asset.url} failed with HTTP ${response.status}`);
-      }
-      if (new URL(response.url).protocol !== "https:") {
-        fail(`download ${asset.url} redirected outside HTTPS`);
-      }
-      await pipeline(
-        Readable.fromWeb(response.body),
-        byteLimitTransform(asset.bytes, `download ${asset.name}`),
-        createWriteStream(temporary, { flags: "wx", mode: 0o600 }),
-      );
-    }
-    const actualBytes = (await fs.stat(temporary)).size;
-    if (actualBytes !== asset.bytes) {
-      fail(`size mismatch for ${asset.name}; expected ${asset.bytes}, got ${actualBytes}`);
-    }
-    const actual = await sha256File(temporary);
-    if (actual !== asset.sha256) {
-      fail(`checksum mismatch for ${asset.name}; expected ${asset.sha256}, got ${actual}`);
-    }
-    await fs.rename(temporary, cached).catch(async (error) => {
-      const existing = await statOrUndefined(cached);
-      if (existing?.isFile() !== true || existing.isSymbolicLink()) throw error;
-    });
-    const cachedStat = await statOrUndefined(cached);
-    if (
-      cachedStat?.isFile() !== true || cachedStat.isSymbolicLink() ||
-      cachedStat.size !== asset.bytes || (await sha256File(cached)) !== asset.sha256
-    ) {
-      fail(`cached object failed checksum verification after materialization: ${cached}`);
-    }
-    return cached;
-  } finally {
-    await fs.rm(temporary, { force: true });
-  }
-}
-
-async function materializeLogicalPayload(locator, carrierFile, cacheDir, carrierMemberCache) {
-  if (locator.path === ".") return carrierFile;
-  const directory = await requireCacheDirectory(cacheDir, path.join(cacheDir, "payloads"));
-  const output = path.join(directory, `${locator.sha256}-${path.posix.basename(locator.path)}`);
-  await rejectCacheLeafSymlink(output);
-  const existing = await statOrUndefined(output);
-  if (
-    existing?.isFile() === true && !existing.isSymbolicLink() &&
-    existing.size === locator.bytes && (await sha256File(output)) === locator.sha256
-  ) {
-    return output;
-  }
-  await fs.rm(output, { force: true, recursive: true });
-
-  let members = carrierMemberCache.get(locator.envelope.sha256);
-  if (members === undefined) {
-    members = await archiveMembers(carrierFile, locator.envelope.format);
-    carrierMemberCache.set(locator.envelope.sha256, members);
-  }
-  if (!members.has(locator.path)) {
-    fail(`${locator.envelope.name} is missing nested logical payload ${locator.path}`);
-  }
-
-  const temporaryRoot = path.join(
-    directory,
-    `.tmp-${process.pid}-${Date.now()}-${locator.sha256}`,
-  );
-  await fs.rm(temporaryRoot, { force: true, recursive: true });
-  await fs.mkdir(temporaryRoot, { recursive: true, mode: 0o700 });
-  try {
-    runWithCwd(
-      "tar",
-      ["-xzf", path.basename(carrierFile), "-C", temporaryRoot, locator.path],
-      path.dirname(carrierFile),
-      `extract ${locator.path} from ${locator.envelope.name}`,
-    );
-    const selected = path.join(temporaryRoot, ...locator.path.split("/"));
-    const selectedStat = await statOrUndefined(selected);
-    if (selectedStat?.isFile() !== true || selectedStat.isSymbolicLink()) {
-      fail(`${locator.envelope.name} nested payload ${locator.path} is not a regular file`);
-    }
-    const actualSha256 = await sha256File(selected);
-    if (selectedStat.size !== locator.bytes || actualSha256 !== locator.sha256) {
-      fail(
-        `${locator.envelope.name} nested payload ${locator.path} does not match ` +
-          `its frozen size/checksum`,
-      );
-    }
-    await fs.rename(selected, output);
-    const outputStat = await statOrUndefined(output);
-    if (
-      outputStat?.isFile() !== true || outputStat.isSymbolicLink() ||
-      outputStat.size !== locator.bytes || (await sha256File(output)) !== locator.sha256
-    ) {
-      fail(`nested payload cache entry failed verification after materialization: ${output}`);
-    }
-    return output;
-  } finally {
-    await fs.rm(temporaryRoot, { force: true, recursive: true });
-  }
-}
-
-function run(command, args, label) {
-  const result = spawnSync(command, args, { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 });
-  if (result.error) fail(`${label}: ${result.error.message}`);
-  if (result.status !== 0) {
-    fail(`${label} failed (${result.status}): ${(result.stderr || result.stdout).trim()}`);
-  }
-  return result.stdout;
-}
-
-function runWithCwd(command, args, cwd, label) {
-  const result = spawnSync(command, args, {
-    cwd,
-    encoding: "utf8",
-    maxBuffer: 64 * 1024 * 1024,
-  });
-  if (result.error) fail(`${label}: ${result.error.message}`);
-  if (result.status !== 0) {
-    fail(`${label} failed (${result.status}): ${(result.stderr || result.stdout).trim()}`);
-  }
-  return result.stdout;
-}
-
-const ZIP_UTF8 = new TextDecoder("utf-8", { fatal: true });
-
-function zipRange(buffer, offset, length, archive, label) {
-  if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(length) || offset < 0 || length < 0 || offset > buffer.length - length) {
-    fail(`${archive} has a truncated ZIP ${label}`);
-  }
-  return buffer.subarray(offset, offset + length);
-}
-
-function zipName(bytes, flags, archive, label) {
-  if (bytes.length === 0) fail(`${archive} has an empty ZIP ${label}`);
-  if ((flags & 0x0800) === 0 && bytes.some((value) => value >= 0x80)) {
-    fail(`${archive} has a non-UTF-8 ZIP ${label}`);
-  }
-  try {
-    return ZIP_UTF8.decode(bytes);
-  } catch {
-    fail(`${archive} has an invalid UTF-8 ZIP ${label}`);
-  }
-}
-
-function zipExtraFields(bytes, archive, label) {
-  const seen = new Set();
-  let offset = 0;
-  while (offset < bytes.length) {
-    if (bytes.length - offset < 4) fail(`${archive} has a truncated ZIP ${label}`);
-    const id = bytes.readUInt16LE(offset);
-    const size = bytes.readUInt16LE(offset + 2);
-    offset += 4;
-    if (size > bytes.length - offset) fail(`${archive} has a truncated ZIP ${label} field 0x${id.toString(16)}`);
-    if (seen.has(id)) fail(`${archive} repeats ZIP ${label} field 0x${id.toString(16)}`);
-    if (!ALLOWED_ZIP_EXTRA_FIELDS.has(id)) {
-      fail(`${archive} uses unsupported ZIP ${label} field 0x${id.toString(16)}`);
-    }
-    seen.add(id);
-    offset += size;
-  }
-}
-
-function zipDirectory(buffer, archive) {
-  if (buffer.length < 22) fail(`${archive} is too short to contain a ZIP end record`);
-  const minimum = Math.max(0, buffer.length - 65_557);
-  let eocd = -1;
-  for (let offset = buffer.length - 22; offset >= minimum; offset -= 1) {
-    if (
-      buffer.readUInt32LE(offset) === 0x06054b50
-      && offset + 22 + buffer.readUInt16LE(offset + 20) === buffer.length
-    ) {
-      eocd = offset;
-      break;
-    }
-  }
-  if (eocd < 0) fail(`${archive} has no well-formed ZIP end record`);
-  const disk = buffer.readUInt16LE(eocd + 4);
-  const centralDisk = buffer.readUInt16LE(eocd + 6);
-  const diskEntries = buffer.readUInt16LE(eocd + 8);
-  const entries = buffer.readUInt16LE(eocd + 10);
-  const centralSize = buffer.readUInt32LE(eocd + 12);
-  const centralOffset = buffer.readUInt32LE(eocd + 16);
-  if (
-    disk === 0xffff || centralDisk === 0xffff || diskEntries === 0xffff || entries === 0xffff
-    || centralSize === 0xffffffff || centralOffset === 0xffffffff
-  ) {
-    fail(`${archive} uses unsupported ZIP64 metadata`);
-  }
-  if (disk !== 0 || centralDisk !== 0 || diskEntries !== entries) {
-    fail(`${archive} uses unsupported multi-disk ZIP metadata`);
-  }
-  if (entries === 0 || centralOffset > eocd || centralSize !== eocd - centralOffset) {
-    fail(`${archive} has an invalid or ambiguous ZIP central-directory extent`);
-  }
-  return { centralEnd: eocd, centralOffset, entries };
-}
-
-function zipDescriptor(buffer, entry, offset, length, archive) {
-  if (length !== 12 && length !== 16) {
-    fail(`${archive} has an ambiguous ${length}-byte ZIP gap after ${JSON.stringify(entry.raw)}`);
-  }
-  const descriptor = zipRange(buffer, offset, length, archive, `data descriptor for ${JSON.stringify(entry.raw)}`);
-  let cursor = 0;
-  if (length === 16) {
-    if (descriptor.readUInt32LE(0) !== 0x08074b50) {
-      fail(`${archive} has an invalid ZIP data-descriptor signature for ${JSON.stringify(entry.raw)}`);
-    }
-    cursor = 4;
-  }
-  if (
-    descriptor.readUInt32LE(cursor) !== entry.crc32
-    || descriptor.readUInt32LE(cursor + 4) !== entry.compressedSize
-    || descriptor.readUInt32LE(cursor + 8) !== entry.size
-  ) {
-    fail(`${archive} has a ZIP data descriptor that disagrees with ${JSON.stringify(entry.raw)}`);
-  }
-}
-
-function zipMemberType(versionMadeBy, externalAttributes, raw, archive) {
-  const host = versionMadeBy >>> 8;
-  const unixType = (externalAttributes >>> 16) & 0o170000;
-  const pathDirectory = raw.endsWith("/");
-  const dosDirectory = (externalAttributes & 0x10) !== 0;
-  let type;
-
-  if (host === 3) {
-    if (unixType === 0o100000) {
-      type = "-";
-      if (dosDirectory) {
-        fail(`${archive} Unix regular file also carries the DOS directory bit: ${raw}`);
-      }
-    } else if (unixType === 0o040000) {
-      type = "d";
-    } else if (unixType === 0) {
-      fail(`${archive} has an ambiguous Unix member type: ${raw}`);
-    } else {
-      fail(`${archive} contains a link or special entry: ${raw}`);
-    }
-  } else if (host === 0) {
-    if (unixType !== 0) {
-      fail(`${archive} FAT-origin member carries conflicting Unix type metadata: ${raw}`);
-    }
-    if (dosDirectory !== pathDirectory) {
-      fail(`${archive} FAT-origin member has inconsistent directory metadata: ${raw}`);
-    }
-    type = pathDirectory ? "d" : "-";
-  } else {
-    fail(`${archive} uses unsupported ZIP creator host ${host} for ${raw}`);
-  }
-
-  if ((type === "d") !== pathDirectory) {
-    fail(`${archive} member type/path marker mismatch: ${raw}`);
-  }
-  return type;
-}
-
-async function zipEntries(archive, maxEntries) {
-  const buffer = await fs.readFile(archive);
-  const { centralEnd, centralOffset, entries: entryCount } = zipDirectory(buffer, archive);
-  if (entryCount > maxEntries) {
-    fail(`${archive} exceeds the maximum supported ${maxEntries} archive entries`);
-  }
-  const entries = [];
-  let offset = centralOffset;
-  for (let index = 0; index < entryCount; index += 1) {
-    const header = zipRange(buffer, offset, 46, archive, `central header ${index + 1}`);
-    if (header.readUInt32LE(0) !== 0x02014b50) fail(`${archive} has an invalid ZIP central header ${index + 1}`);
-    const versionMadeBy = header.readUInt16LE(4);
-    const flags = header.readUInt16LE(8);
-    const method = header.readUInt16LE(10);
-    if ((flags & 0x0001) !== 0 || (flags & 0x0040) !== 0) {
-      fail(`${archive} contains an encrypted ZIP member`);
-    }
-    if ((flags & ~0x080e) !== 0) {
-      fail(`${archive} uses unsupported ZIP general-purpose flags 0x${flags.toString(16)}`);
-    }
-    if (method !== 0 && method !== 8) fail(`${archive} uses unsupported ZIP compression method ${method}`);
-    if (method !== 8 && (flags & 0x0006) !== 0) {
-      fail(`${archive} uses deflate-only ZIP flags with compression method ${method}`);
-    }
-    const compressedSize = header.readUInt32LE(20);
-    const size = header.readUInt32LE(24);
-    const nameLength = header.readUInt16LE(28);
-    const extraLength = header.readUInt16LE(30);
-    const commentLength = header.readUInt16LE(32);
-    const diskStart = header.readUInt16LE(34);
-    const externalAttributes = header.readUInt32LE(38);
-    const localOffset = header.readUInt32LE(42);
-    if (compressedSize === 0xffffffff || size === 0xffffffff || localOffset === 0xffffffff || diskStart === 0xffff) {
-      fail(`${archive} uses unsupported ZIP64 entry metadata`);
-    }
-    if (diskStart !== 0) fail(`${archive} contains a multi-disk ZIP member`);
-    const recordLength = 46 + nameLength + extraLength + commentLength;
-    const record = zipRange(buffer, offset, recordLength, archive, `central entry ${index + 1}`);
-    const rawName = Buffer.from(record.subarray(46, 46 + nameLength));
-    const raw = zipName(rawName, flags, archive, `member name ${index + 1}`);
-    zipExtraFields(
-      record.subarray(46 + nameLength, 46 + nameLength + extraLength),
-      archive,
-      `central extra metadata for ${JSON.stringify(raw)}`,
-    );
-    const type = zipMemberType(versionMadeBy, externalAttributes, raw, archive);
-    if (type === "d" && (compressedSize !== 0 || size !== 0)) fail(`${archive} has a non-empty directory entry: ${raw}`);
-    if (method === 0 && compressedSize !== size) fail(`${archive} has an invalid stored ZIP size for ${raw}`);
-
-    const local = zipRange(buffer, localOffset, 30, archive, `local header for ${JSON.stringify(raw)}`);
-    if (local.readUInt32LE(0) !== 0x04034b50) fail(`${archive} has an invalid ZIP local header for ${raw}`);
-    if (local.readUInt16LE(6) !== flags || local.readUInt16LE(8) !== method) {
-      fail(`${archive} ZIP local metadata disagrees with ${raw}`);
-    }
-    const localNameLength = local.readUInt16LE(26);
-    const localExtraLength = local.readUInt16LE(28);
-    const localName = zipRange(buffer, localOffset + 30, localNameLength, archive, `local name for ${JSON.stringify(raw)}`);
-    if (!localName.equals(rawName)) fail(`${archive} ZIP local name disagrees with ${raw}`);
-    zipExtraFields(
-      zipRange(buffer, localOffset + 30 + localNameLength, localExtraLength, archive, `local extra metadata for ${JSON.stringify(raw)}`),
-      archive,
-      `local extra metadata for ${JSON.stringify(raw)}`,
-    );
-    const descriptor = (flags & 0x0008) !== 0;
-    const localCrc32 = local.readUInt32LE(14);
-    const localCompressedSize = local.readUInt32LE(18);
-    const localSize = local.readUInt32LE(22);
-    if (descriptor) {
-      if (
-        (localCrc32 !== 0 && localCrc32 !== header.readUInt32LE(16))
-        || (localCompressedSize !== 0 && localCompressedSize !== compressedSize)
-        || (localSize !== 0 && localSize !== size)
-      ) {
-        fail(`${archive} ZIP local descriptor metadata disagrees with ${raw}`);
-      }
-    } else if (
-      localCrc32 !== header.readUInt32LE(16)
-      || localCompressedSize !== compressedSize
-      || localSize !== size
-    ) {
-      fail(`${archive} ZIP local CRC or sizes disagree with ${raw}`);
-    }
-    const dataOffset = localOffset + 30 + localNameLength + localExtraLength;
-    if (dataOffset > centralOffset || compressedSize > centralOffset - dataOffset) {
-      fail(`${archive} ZIP payload overlaps the central directory for ${raw}`);
-    }
-    entries.push({
-      compressedSize,
-      crc32: header.readUInt32LE(16),
-      dataEnd: dataOffset + compressedSize,
-      descriptor,
-      localOffset,
-      raw,
-      size,
-      type,
-    });
-    offset += recordLength;
-  }
-  if (offset !== centralEnd) fail(`${archive} ZIP central directory contains trailing or missing records`);
-  const extents = [...entries].sort((left, right) => left.localOffset - right.localOffset || left.dataEnd - right.dataEnd);
-  if (extents[0]?.localOffset !== 0) fail(`${archive} has unreferenced bytes before its first ZIP local record`);
-  for (let index = 0; index < extents.length; index += 1) {
-    const entry = extents[index];
-    const nextOffset = extents[index + 1]?.localOffset ?? centralOffset;
-    if (entry.dataEnd > nextOffset) fail(`${archive} has overlapping ZIP local records`);
-    const gap = nextOffset - entry.dataEnd;
-    if (entry.descriptor) zipDescriptor(buffer, entry, entry.dataEnd, gap, archive);
-    else if (gap !== 0) fail(`${archive} has an ambiguous ${gap}-byte ZIP gap after ${JSON.stringify(entry.raw)}`);
-  }
-  return entries;
-}
-
-function tarString(header, offset, length, archive) {
-  const field = header.subarray(offset, offset + length);
-  const end = field.indexOf(0);
-  try {
-    return new TextDecoder("utf-8", { fatal: true }).decode(field.subarray(0, end < 0 ? field.length : end));
-  } catch {
-    fail(`${archive} contains a non-UTF-8 ustar header field`);
-  }
-}
-
-function tarOctal(header, offset, length, label, archive) {
-  const value = header.subarray(offset, offset + length).toString("ascii").replaceAll("\0", "").trim();
-  if (value !== "" && !/^[0-7]+$/u.test(value)) fail(`${archive} has invalid ustar ${label}`);
-  const parsed = value === "" ? 0 : Number.parseInt(value, 8);
-  if (!Number.isSafeInteger(parsed) || parsed < 0) fail(`${archive} has unsafe ustar ${label}`);
-  return parsed;
-}
-
-async function tarEntries(archive, maxEntries = MAX_ARCHIVE_ENTRIES) {
-  const entries = [];
-  let currentEntry = "archive header";
-  let pending = Buffer.alloc(0);
-  let remainingPayload = 0;
-  let expandedBytes = 0;
-  let streamedBytes = 0;
-  let terminated = false;
-  let zeroBlocks = 0;
-  try {
-    const stream = createReadStream(archive).pipe(createGunzip());
-    for await (const chunk of stream) {
-      streamedBytes += chunk.length;
-      if (streamedBytes > archiveStreamLimit(maxEntries)) {
-        fail(`${archive} expands beyond the maximum supported archive size`);
-      }
-      let offset = 0;
-      while (offset < chunk.length) {
-        if (terminated) {
-          if (!chunk.subarray(offset).every((value) => value === 0)) {
-            fail(`${archive} has data after its ustar end marker`);
-          }
-          break;
-        }
-        if (remainingPayload > 0) {
-          const consumed = Math.min(remainingPayload, chunk.length - offset);
-          remainingPayload -= consumed;
-          offset += consumed;
-          continue;
-        }
-        const consumed = Math.min(512 - pending.length, chunk.length - offset);
-        pending = pending.length === 0
-          ? Buffer.from(chunk.subarray(offset, offset + consumed))
-          : Buffer.concat([pending, chunk.subarray(offset, offset + consumed)]);
-        offset += consumed;
-        if (pending.length < 512) continue;
-
-        const header = pending;
-        pending = Buffer.alloc(0);
-        if (header.every((value) => value === 0)) {
-          zeroBlocks += 1;
-          if (zeroBlocks >= 2) terminated = true;
-          continue;
-        }
-        if (zeroBlocks > 0) fail(`${archive} has an incomplete ustar end marker`);
-
-        const posixUstar = header.subarray(257, 263).equals(Buffer.from("ustar\0"))
-          && header.subarray(263, 265).equals(Buffer.from("00"));
-        const gnuUstar = header.subarray(257, 263).equals(Buffer.from("ustar "))
-          && header[263] === 0x20 && header[264] === 0;
-        if (!posixUstar && !gnuUstar) fail(`${archive} contains a non-ustar header`);
-
-        const expectedChecksum = tarOctal(header, 148, 8, "checksum", archive);
-        let actualChecksum = 0;
-        for (let index = 0; index < 512; index += 1) {
-          actualChecksum += index >= 148 && index < 156 ? 0x20 : header[index];
-        }
-        if (expectedChecksum !== actualChecksum) fail(`${archive} has an invalid ustar header checksum`);
-
-        const name = tarString(header, 0, 100, archive);
-        const prefix = tarString(header, 345, 155, archive);
-        const raw = prefix ? `${prefix}/${name}` : name;
-        currentEntry = JSON.stringify(raw);
-        const size = tarOctal(header, 124, 12, `size for ${currentEntry}`, archive);
-        if (size > MAX_ARCHIVE_MEMBER_BYTES) {
-          fail(
-            `${archive} member ${currentEntry} exceeds the maximum expanded member size ` +
-              `of ${MAX_ARCHIVE_MEMBER_BYTES} bytes`,
-          );
-        }
-        expandedBytes += size;
-        if (!Number.isSafeInteger(expandedBytes) || expandedBytes > MAX_ARCHIVE_EXPANDED_BYTES) {
-          fail(`${archive} exceeds the maximum supported expanded archive size`);
-        }
-        const typeFlag = header[156];
-        const type = typeFlag === 0 || typeFlag === 0x30 ? "-" : typeFlag === 0x35 ? "d" : null;
-        if (type === null) fail(`${archive} contains a link or special entry: ${raw}`);
-        if (type === "d" && size !== 0) fail(`${archive} has a non-empty directory entry: ${raw}`);
-        remainingPayload = Math.ceil(size / 512) * 512;
-        if (!Number.isSafeInteger(remainingPayload)) fail(`${archive} has unsafe padded size for ${currentEntry}`);
-        entries.push({ raw, size, type });
-        if (entries.length > maxEntries) {
-          fail(`${archive} exceeds the maximum supported ${maxEntries} archive entries`);
-        }
-      }
-    }
-  } catch (error) {
-    if (error instanceof Error && error.message.startsWith(`${PREFIX}:`)) throw error;
-    fail(`${archive} is not a readable gzip tar archive: ${error.message}`);
-  }
-  if (remainingPayload > 0) fail(`${archive} has a truncated entry: ${currentEntry}`);
-  if (pending.length > 0) fail(`${archive} has a truncated ustar header`);
-  if (!terminated) fail(`${archive} is missing its two-block ustar end marker`);
-  return entries;
-}
-
-async function archiveMembers(archive, format, maxEntries = MAX_ARCHIVE_ENTRIES) {
-  const archiveStat = await statOrUndefined(archive);
-  if (archiveStat?.isFile() !== true || archiveStat.isSymbolicLink()) {
-    fail(`${archive} is not a regular archive file`);
-  }
-  if (archiveStat.size <= 0 || archiveStat.size > MAX_CARRIER_BYTES) {
-    fail(`${archive} exceeds the maximum supported carrier size of ${MAX_CARRIER_BYTES} bytes`);
-  }
-  if (format === "zip" && archiveStat.size > MAX_ZIP_CARRIER_BYTES) {
-    fail(`${archive} exceeds the maximum supported ZIP carrier size of ${MAX_ZIP_CARRIER_BYTES} bytes`);
-  }
-  let entries;
-  if (format === "tar.gz") {
-    entries = await tarEntries(archive, maxEntries);
-  } else {
-    const zipRows = await zipEntries(archive, maxEntries);
-    let expandedBytes = 0;
-    entries = zipRows.map(({ raw, size, type }) => {
-      if (size > MAX_ARCHIVE_MEMBER_BYTES) {
-        fail(
-          `${archive} member ${JSON.stringify(raw)} exceeds the maximum expanded member size ` +
-            `of ${MAX_ARCHIVE_MEMBER_BYTES} bytes`,
-        );
-      }
-      expandedBytes += size;
-      if (!Number.isSafeInteger(expandedBytes) || expandedBytes > MAX_ARCHIVE_EXPANDED_BYTES) {
-        fail(`${archive} exceeds the maximum supported expanded archive size`);
-      }
-      return { raw, size, type };
-    });
-  }
-  if (entries.length === 0) fail(`${archive} has no archive members`);
-  const normalizedEntries = entries.map(({ raw, size, type }) => {
-    if (!["-", "d"].includes(type)) fail(`${archive} contains a link or special entry: ${raw}`);
-    const directoryMarker = raw.endsWith("/");
-    // POSIX tar headers establish directories with typeflag 5; unlike ZIP, a
-    // trailing slash in the stored path is conventional rather than required.
-    // Keep rejecting file entries that masquerade as directories, and retain
-    // the stricter two-signal check for ZIP metadata.
-    const markerMismatch = format === "zip"
-      ? (type === "d") !== directoryMarker
-      : type !== "d" && directoryMarker;
-    if (markerMismatch && raw !== "." && raw !== "./") {
-      fail(`${archive} member type/path marker mismatch: ${raw}`);
-    }
-    return {
-      name: safeRelative(raw.replace(/\/$/u, "") || ".", `${archive} member`),
-      size,
-      type: type === "d" ? "directory" : "file",
-    };
-  });
-  const names = normalizedEntries.map(({ name }) => name);
-  if (new Set(names).size !== names.length) fail(`${archive} repeats a normalized archive member`);
-  const folded = names.map((name) => name.normalize("NFC").toLocaleLowerCase("en-US"));
-  if (new Set(folded).size !== folded.length) {
-    fail(`${archive} has case-colliding archive members or Unicode-normalization collisions`);
-  }
-  const files = new Set(normalizedEntries.filter(({ type }) => type === "file").map(({ name }) => name));
-  for (const entry of normalizedEntries) {
-    let separator = entry.name.indexOf("/");
-    while (separator >= 0) {
-      const parent = entry.name.slice(0, separator);
-      if (files.has(parent)) fail(`${archive} uses file ${parent} as an archive directory`);
-      separator = entry.name.indexOf("/", separator + 1);
-    }
-  }
-  return new Map(normalizedEntries.map(({ name, type }) => [name, type]));
-}
-
-function jsonDigest(value) {
-  return createHash("sha256").update(JSON.stringify(value)).digest("hex");
-}
-
-async function extractedTree(root, maxEntries = MAX_ARCHIVE_ENTRIES) {
-  const result = [];
-  const pending = [{ directory: root, relative: "" }];
-  let expandedBytes = 0;
-  while (pending.length > 0) {
-    const { directory, relative } = pending.pop();
-    for (const name of (await fs.readdir(directory)).sort(compareText).reverse()) {
-      const file = path.join(directory, name);
-      const fileRelative = relative ? `${relative}/${name}` : name;
-      safeRelative(fileRelative, `${root} extracted member`);
-      const stat = await fs.lstat(file);
-      if (stat.isSymbolicLink()) fail(`extracted carrier contains symlink: ${file}`);
-      if (stat.isDirectory()) {
-        result.push({ path: fileRelative, type: "directory" });
-        pending.push({ directory: file, relative: fileRelative });
-      } else if (stat.isFile()) {
-        if (stat.size > MAX_ARCHIVE_MEMBER_BYTES) {
-          fail(`${root} extracted member ${fileRelative} exceeds the maximum supported member size`);
-        }
-        expandedBytes += stat.size;
-        if (!Number.isSafeInteger(expandedBytes) || expandedBytes > MAX_ARCHIVE_EXPANDED_BYTES) {
-          fail(`${root} extracted tree exceeds the maximum supported expanded size`);
-        }
-        result.push({
-          bytes: stat.size,
-          executable: (stat.mode & 0o111) !== 0,
-          path: fileRelative,
-          sha256: await sha256File(file),
-          type: "file",
-        });
-      } else {
-        fail(`extracted carrier contains unsupported entry: ${file}`);
-      }
-      if (result.length > maxEntries) {
-        fail(`${root} extracted tree exceeds the maximum supported ${maxEntries} entries`);
-      }
-    }
-  }
-  result.sort((left, right) => compareText(left.path, right.path));
-  return result;
-}
-
-function assertArchiveTreeMatches(members, tree, archive) {
-  const expected = [...members]
-    .filter(([name]) => name !== ".")
-    .sort(([left], [right]) => compareText(left, right));
-  const actual = tree
-    .map(({ path: name, type }) => [name, type])
-    .sort(([left], [right]) => compareText(left, right));
-  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
-    fail(`${archive} extracted tree does not exactly match its validated archive member plan`);
-  }
-}
-
-async function extractedCacheValid(
-  root,
-  manifestFile,
-  archiveSha256,
-  maxEntries = MAX_ARCHIVE_ENTRIES,
-) {
-  if ((await statOrUndefined(root))?.isDirectory() !== true || (await statOrUndefined(manifestFile))?.isFile() !== true) return false;
-  try {
-    const manifest = object(JSON.parse(await fs.readFile(manifestFile, "utf8")), manifestFile);
-    exactKeys(manifest, ["archiveSha256", "entries", "schema", "treeSha256"], manifestFile);
-    if (manifest.schema !== EXTRACTED_CACHE_SCHEMA || manifest.archiveSha256 !== archiveSha256 || !Array.isArray(manifest.entries)) return false;
-    if (manifest.treeSha256 !== jsonDigest(manifest.entries)) return false;
-    const actual = await extractedTree(root, maxEntries);
-    return manifest.treeSha256 === jsonDigest(actual) && JSON.stringify(manifest.entries) === JSON.stringify(actual);
-  } catch {
-    return false;
-  }
-}
-
-async function extractedAsset(asset, archive, cacheDir) {
-  const maxEntries = archiveEntryLimit(asset);
-  const parent = await requireCacheDirectory(cacheDir, path.join(cacheDir, "extracted"));
-  const root = path.join(parent, asset.sha256);
-  const cacheManifest = `${root}.tree.json`;
-  await rejectCacheLeafSymlink(root);
-  await rejectCacheLeafSymlink(cacheManifest);
-  if (await extractedCacheValid(root, cacheManifest, asset.sha256, maxEntries)) return root;
-  await fs.rm(root, { force: true, recursive: true });
-  await fs.rm(cacheManifest, { force: true });
-  const members = await archiveMembers(archive, asset.format, maxEntries);
-  if (asset.member !== "." && !members.has(asset.member) && ![...members.keys()].some((entry) => entry.startsWith(`${asset.member}/`))) {
-    fail(`${asset.name} is missing declared member ${asset.member}`);
-  }
-  const temporary = path.join(parent, `.${asset.sha256}.tmp-${process.pid}-${Date.now()}`);
-  const temporaryManifest = `${cacheManifest}.tmp-${process.pid}-${Date.now()}`;
-  await fs.rm(temporary, { force: true, recursive: true });
-  await fs.mkdir(temporary, { recursive: true });
-  try {
-    if (asset.format === "zip") {
-      run("unzip", ["-q", archive, "-d", temporary], `extract ${asset.name}`);
-    } else {
-      runWithCwd(
-        "tar",
-        ["-xzf", path.basename(archive), "-C", temporary],
-        path.dirname(archive),
-        `extract ${asset.name}`,
-      );
-    }
-    const tree = await extractedTree(temporary, maxEntries);
-    if (asset.format === "zip") assertArchiveTreeMatches(members, tree, archive);
-    const manifest = {
-      archiveSha256: asset.sha256,
-      entries: tree,
-      schema: EXTRACTED_CACHE_SCHEMA,
-      treeSha256: jsonDigest(tree),
-    };
-    const selected = asset.member === "." ? temporary : path.join(temporary, ...asset.member.split("/"));
-    if ((await statOrUndefined(selected))?.isDirectory() !== true) {
-      fail(`${asset.name} member is not a directory: ${asset.member}`);
-    }
-    await fs.writeFile(temporaryManifest, `${JSON.stringify(manifest, null, 2)}\n`, { flag: "wx" });
-    await fs.rename(temporary, root);
-    await fs.rename(temporaryManifest, cacheManifest);
-    const rootStat = await statOrUndefined(root);
-    const manifestStat = await statOrUndefined(cacheManifest);
-    if (
-      rootStat?.isDirectory() !== true || rootStat.isSymbolicLink() ||
-      manifestStat?.isFile() !== true || manifestStat.isSymbolicLink() ||
-      !(await extractedCacheValid(root, cacheManifest, asset.sha256, maxEntries))
-    ) {
-      fail(`extracted cache failed verification after materialization: ${root}`);
-    }
-    return root;
-  } catch (error) {
-    await fs.rm(temporary, { force: true, recursive: true });
-    await fs.rm(temporaryManifest, { force: true });
-    await fs.rm(root, { force: true, recursive: true });
-    await fs.rm(cacheManifest, { force: true });
-    throw error;
-  }
-}
-
-async function resolveAssetArchiveRoot(asset, cacheDir) {
-  const archive = await materializeAsset(asset, cacheDir);
-  return extractedAsset(asset, archive, cacheDir);
-}
-
-async function resolveAsset(asset, cacheDir) {
-  const extracted = await resolveAssetArchiveRoot(asset, cacheDir);
-  const member = asset.member === "."
-    ? extracted
-    : path.join(extracted, ...asset.member.split("/"));
-  const stat = await statOrUndefined(member);
-  if (stat?.isDirectory() !== true) fail(`${asset.name} member is not a directory: ${asset.member}`);
-  return member;
-}
-
-async function resolveLogicalArchiveRoot(locator, cacheDir, carrierMemberCache) {
-  const carrierFile = await materializeAsset(locator.envelope, cacheDir);
-  const archive = await materializeLogicalPayload(
-    locator,
-    carrierFile,
-    cacheDir,
-    carrierMemberCache,
-  );
-  const logicalAsset = {
-    ...locator,
-    name: locator.path === "." ? locator.envelope.name : path.posix.basename(locator.path),
-  };
-  return extractedAsset(logicalAsset, archive, cacheDir);
-}
-
-async function resolveLogicalAsset(locator, cacheDir, carrierMemberCache) {
-  const extracted = await resolveLogicalArchiveRoot(locator, cacheDir, carrierMemberCache);
-  const member = locator.member === "."
-    ? extracted
-    : path.join(extracted, ...locator.member.split("/"));
-  const stat = await statOrUndefined(member);
-  if (stat?.isDirectory() !== true) {
-    fail(`${locator.envelope.name} logical member is not a directory: ${locator.member}`);
-  }
-  return member;
-}
-
-async function copyTree(source, destination) {
-  const stat = await fs.lstat(source);
-  if (stat.isSymbolicLink()) fail(`refusing to copy carrier symlink: ${source}`);
-  if (stat.isDirectory()) {
-    await fs.mkdir(destination, { recursive: true });
-    const entries = (await fs.readdir(source)).sort(compareText);
-    for (const name of entries) {
-      await copyTree(path.join(source, name), path.join(destination, name));
-    }
-  } else if (stat.isFile()) {
-    await fs.mkdir(path.dirname(destination), { recursive: true });
-    await fs.copyFile(source, destination);
-    await fs.chmod(destination, stat.mode & 0o111 ? 0o755 : 0o644);
-  } else {
-    fail(`unsupported carrier entry: ${source}`);
-  }
-}
-
-async function stripEmbeddedRuntimeClosures(frameworkRoot) {
-  let removed = 0;
-  const visit = async (directory) => {
-    for (const entry of await fs.readdir(directory, { withFileTypes: true })) {
-      const file = path.join(directory, entry.name);
-      if (!entry.isDirectory()) continue;
-      if (entry.name === "oliphaunt" && path.basename(directory) === "Resources") {
-        const receiptFile = path.join(file, "manifest.properties");
-        const receipt = parseProperties(await fs.readFile(receiptFile, "utf8"), receiptFile);
-        const fields = new Set([
-          "schema",
-          "clusterSeedTarget",
-          "clusterSeedRelativePath",
-          "icuClusterSeedRelativePath",
-        ]);
-        const target = receipt.get("clusterSeedTarget");
-        if (
-          receipt.size !== fields.size ||
-          [...fields].some((field) => !receipt.has(field)) ||
-          receipt.get("schema") !== "oliphaunt-native-runtime-carrier-v1" ||
-          !new Set(["ios-datum64", "macos-arm64"]).has(target) ||
-          receipt.get("clusterSeedRelativePath") !== "cluster-seed" ||
-          receipt.get("icuClusterSeedRelativePath") !== "cluster-seed-icu"
-        ) {
-          fail(`base framework contains an invalid embedded runtime closure: ${file}`);
-        }
-        await fs.rm(file, { recursive: true });
-        if ((await fs.readdir(directory)).length === 0) await fs.rmdir(directory);
-        removed += 1;
-      } else {
-        await visit(file);
-      }
-    }
-  };
-  await visit(frameworkRoot);
-  if (removed === 0) {
-    fail("base framework does not contain its per-slice runtime resource closure");
-  }
-}
-
-async function mergeTree(source, destination) {
-  const stat = await fs.lstat(source);
-  if (stat.isSymbolicLink()) fail(`refusing to merge carrier symlink: ${source}`);
-  if (stat.isDirectory()) {
-    await fs.mkdir(destination, { recursive: true });
-    for (const name of (await fs.readdir(source)).sort(compareText)) {
-      await mergeTree(path.join(source, name), path.join(destination, name));
-    }
-    return;
-  }
-  if (!stat.isFile()) fail(`unsupported carrier entry: ${source}`);
-  const existing = await statOrUndefined(destination);
-  if (existing !== undefined) {
-    if (!existing.isFile() || (await sha256File(source)) !== (await sha256File(destination))) {
-      fail(`selected carrier resources conflict at ${destination}`);
-    }
-    return;
-  }
-  await fs.mkdir(path.dirname(destination), { recursive: true });
-  await fs.copyFile(source, destination);
-  await fs.chmod(destination, stat.mode & 0o111 ? 0o755 : 0o644);
-}
-
-function legalRelativeMember(group, asset, member) {
-  const prefix = asset.member === "." ? "" : `${asset.member}/`;
-  if (prefix && member.startsWith(prefix)) return member.slice(prefix.length);
-  return member;
-}
-
-function checkedLegalDestinations(rows) {
-  const exact = new Set();
-  const portable = new Map();
-  for (const row of rows) {
-    const destination = safeRelative(row.destination, "staged legal destination");
-    if (destination === "." || exact.has(destination)) {
-      fail(`staged legal destination is repeated or invalid: ${destination}`);
-    }
-    const folded = destination.normalize("NFC").toLowerCase();
-    const prior = portable.get(folded);
-    if (prior !== undefined) {
-      fail(`staged legal destinations collide across case or Unicode normalization: ${prior}, ${destination}`);
-    }
-    exact.add(destination);
-    portable.set(folded, destination);
-  }
-  for (const destination of exact) {
-    let separator = destination.indexOf("/");
-    while (separator >= 0) {
-      const parent = destination.slice(0, separator);
-      if (exact.has(parent)) {
-        fail(`staged legal file ${parent} is also used as a directory`);
-      }
-      separator = destination.indexOf("/", separator + 1);
-    }
-  }
-}
-
-async function readVerifiedLegalFile(root, row, label) {
-  const rootStat = await fs.lstat(root);
-  if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
-    fail(`${label} archive root must be a real directory`);
-  }
-  const parts = row.member.split("/");
-  let cursor = root;
-  for (const part of parts.slice(0, -1)) {
-    cursor = path.join(cursor, part);
-    const stat = await fs.lstat(cursor).catch((error) => {
-      fail(`${label} legal parent is missing: ${row.member} (${error.message})`);
-    });
-    if (!stat.isDirectory() || stat.isSymbolicLink()) {
-      fail(`${label} legal parent must be a real directory: ${row.member}`);
-    }
-  }
-  const file = path.join(cursor, parts.at(-1));
-  const leaf = await fs.lstat(file).catch((error) => {
-    fail(`${label} legal file is missing: ${row.member} (${error.message})`);
-  });
-  if (!leaf.isFile() || leaf.isSymbolicLink()) {
-    fail(`${label} legal member must be a regular non-symlink file: ${row.member}`);
-  }
-  const handle = await fs.open(
-    file,
-    fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0),
-  );
-  try {
-    const opened = await handle.stat();
-    if (!opened.isFile() || opened.size !== row.bytes) {
-      fail(`${label} legal member has the wrong type or byte count: ${row.member}`);
-    }
-    const bytes = await handle.readFile();
-    const digest = createHash("sha256").update(bytes).digest("hex");
-    if (digest !== row.sha256) {
-      fail(`${label} legal member checksum mismatch: ${row.member}`);
-    }
-    return bytes;
-  } finally {
-    await handle.close();
-  }
-}
-
-async function writeSafeLegalFile(root, relative, bytes) {
-  const parts = relative.split("/");
-  let cursor = root;
-  for (const part of parts.slice(0, -1)) {
-    cursor = path.join(cursor, part);
-    await fs.mkdir(cursor, { mode: 0o755 }).catch((error) => {
-      if (error?.code !== "EEXIST") throw error;
-    });
-    const stat = await fs.lstat(cursor);
-    if (!stat.isDirectory() || stat.isSymbolicLink()) {
-      fail(`staged legal parent must be a real directory: ${cursor}`);
-    }
-    await fs.chmod(cursor, 0o755);
-  }
-  const destination = path.join(root, ...parts);
-  await fs.writeFile(destination, bytes, { flag: "wx", mode: 0o644 });
-  await fs.chmod(destination, 0o644);
-}
-
-function combinedSpdx(groups) {
-  const terms = [];
-  const seen = new Set();
-  for (const group of groups) {
-    for (const term of group.spdx.split(" AND ")) {
-      if (!seen.has(term)) {
-        seen.add(term);
-        terms.push(term);
-      }
-    }
-  }
-  return terms.join(" AND ");
-}
-
-function renderLegalNotice(spdx, files) {
-  return [
-    "# Oliphaunt app-owned iOS payload legal notices",
-    "",
-    `SPDX-License-Identifier: ${spdx}`,
-    "",
-    "This file indexes the exact legal files materialized from the selected frozen carriers.",
-    "",
-    ...files.map((row) => `- \`${row.destination}\` (${row.kind}; SHA-256 \`${row.sha256}\`)`),
-    "",
-  ].join("\n");
-}
-
-async function stageSelectedLegalFiles({
-  args,
-  base,
-  carrierMemberCache,
-  selected,
-  temporary,
-}) {
-  const baseAssets = new Map([
-    [base.assets.framework.role, base.assets.framework],
-    [base.assets.runtime.role, base.assets.runtime],
-    [base.assets.icu.role, base.assets.icu],
-  ]);
-  const groups = [];
-  for (const group of base.legal) {
-    if (group.assetRole === "icu-data" && !args.icu) continue;
-    const asset = baseAssets.get(group.assetRole);
-    if (asset === undefined) fail(`base legal group references missing ${group.assetRole} asset`);
-    groups.push({
-      asset,
-      group,
-      label: `base ${group.assetRole}`,
-      scope: `base/${group.assetRole}`,
-      source: "base",
-    });
-  }
-  for (const extension of [...selected].sort((left, right) => compareText(left.sqlName, right.sqlName))) {
-    groups.push({
-      asset: extension.assets.runtime,
-      group: extension.legal,
-      label: `extension ${extension.sqlName}`,
-      scope: `extensions/${extension.sqlName}`,
-      source: "extension",
-    });
-  }
-  const planned = groups
-    .flatMap(({ asset, group, label, scope, source }) =>
-      group.files.map((row) => ({
-        ...row,
-        asset,
-        destination: `licenses/${scope}/${legalRelativeMember(group, asset, row.member)}`,
-        label,
-        source,
-      })))
-    .sort((left, right) => compareText(left.destination, right.destination));
-  checkedLegalDestinations(planned);
-  const legalRoot = path.join(temporary, "licenses");
-  await fs.mkdir(legalRoot, { recursive: true, mode: 0o755 });
-  await fs.chmod(legalRoot, 0o755);
-  for (const row of planned) {
-    const sourceRoot = row.source === "base"
-      ? await resolveAssetArchiveRoot(row.asset, args.cacheDir)
-      : await resolveLogicalArchiveRoot(row.asset, args.cacheDir, carrierMemberCache);
-    const bytes = await readVerifiedLegalFile(sourceRoot, row, row.label);
-    await writeSafeLegalFile(temporary, row.destination, bytes);
-  }
-  const spdx = combinedSpdx(groups.map(({ group }) => group));
-  const notice = "licenses/NOTICE.md";
-  await writeSafeLegalFile(temporary, notice, Buffer.from(renderLegalNotice(spdx, planned), "utf8"));
-  return {
-    file: notice,
-    files: planned.map(({ bytes, destination, kind, member, sha256, source }) => ({
-      bytes,
-      destination,
-      kind,
-      member,
-      sha256,
-      source,
-    })),
-    spdx,
-  };
-}
-
-function csv(value, label) {
-  return value ? uniquePortable(value.split(","), label) : [];
-}
-
-function rejectUnsupportedProperties(values, allowed, source) {
-  const extras = [...values.keys()].filter((key) => !allowed.has(key)).sort(compareText);
-  if (extras.length > 0) {
-    fail(`${source} contains unsupported field(s): ${extras.join(", ")}`);
-  }
-}
-
-function requireExactPropertySet(values, expected, source) {
-  const missing = [...expected].filter((key) => !values.has(key)).sort(compareText);
-  if (missing.length > 0) {
-    fail(`${source} is missing canonical field(s): ${missing.join(", ")}`);
-  }
-}
-
-function requireExtensionNativeRuntime(values, base, source) {
-  const product = values.get("nativeRuntimeProduct");
-  if (product === undefined) fail(`${source} is missing nativeRuntimeProduct`);
-  portable(product, `${source} nativeRuntimeProduct`);
-  if (product !== base.product) {
-    fail(`${source} must declare nativeRuntimeProduct=${base.product}; got ${product}`);
-  }
-
-  const rawVersion = values.get("nativeRuntimeVersion");
-  if (rawVersion === undefined) fail(`${source} is missing nativeRuntimeVersion`);
-  const version = stableVersion(rawVersion, `${source} nativeRuntimeVersion`);
-  if (version !== base.version) {
-    fail(`${source} must declare nativeRuntimeVersion=${base.version}; got ${version}`);
-  }
-}
-
-function requireExtensionLinkageMetadata(values, carrier, source) {
-  const stem = carrier.nativeModuleStem;
-  requireProperty(values, "nativeModuleFile", stem === null ? "" : `${stem}.dylib`, source);
-  requireProperty(
-    values,
-    "staticSymbolPrefix",
-    stem === null ? "" : `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`,
-    source,
-  );
-  const aliases = carrier.registration?.symbols
-    .filter(({ name, address }) => name !== address)
-    .map(({ name, address }) => `${name}:${address}`)
-    .sort(compareText) ?? [];
-  requireProperty(values, "staticSymbolAliases", aliases.join(","), source);
-}
-
-function propertyRows(values, key, source) {
-  const raw = values.get(key);
-  if (raw === undefined) fail(`${source} is missing ${key}`);
-  if (raw === "") return [];
-  const rows = raw.split(",");
-  if (rows.some((row) => row.length === 0)) fail(`${source} ${key} contains an empty row`);
-  if (new Set(rows).size !== rows.length) fail(`${source} ${key} must not contain duplicates`);
-  return rows;
-}
-
-function mobileStaticArchivePaths(values, carrier, source) {
-  const rows = propertyRows(values, "mobileStaticArchives", source).map((row, index) => {
-    const fields = row.split(":");
-    if (fields.length !== 2) {
-      fail(`${source} mobileStaticArchives[${index}] must be target:path`);
-    }
-    const target = portable(fields[0], `${source} mobileStaticArchives[${index}] target`);
-    const relative = safeRelative(fields[1], `${source} mobileStaticArchives[${index}] path`);
-    if (relative === ".") fail(`${source} mobileStaticArchives[${index}] must name a file`);
-    return { relative, target };
-  });
-  const expectedTargets = carrier.nativeModuleStem === null
-    ? []
-    : ["ios-device", "ios-simulator"];
-  if (JSON.stringify(rows.map(({ target }) => target)) !== JSON.stringify(expectedTargets)) {
-    fail(
-      `${source} mobileStaticArchives targets must be exactly ` +
-      `${expectedTargets.join(",") || ""}`,
-    );
-  }
-  for (const { relative, target } of rows) {
-    const stem = carrier.nativeModuleStem;
-    const expected = `mobile-static/${target}/extensions/${stem}/liboliphaunt_extension_${stem}.a`;
-    if (relative !== expected) {
-      fail(`${source} mobileStaticArchives for ${target} must declare ${expected}; got ${relative}`);
-    }
-  }
-  return rows.map(({ relative }) => relative);
-}
-
-function mobileStaticDependencyArchivePaths(values, carrier, source) {
-  const rows = propertyRows(values, "mobileStaticDependencyArchives", source).map((row, index) => {
-    const fields = row.split(":");
-    if (fields.length !== 3) {
-      fail(`${source} mobileStaticDependencyArchives[${index}] must be target:dependency:path`);
-    }
-    const target = portable(
-      fields[0],
-      `${source} mobileStaticDependencyArchives[${index}] target`,
-    );
-    const dependency = portable(
-      fields[1],
-      `${source} mobileStaticDependencyArchives[${index}] dependency`,
-    );
-    const relative = safeRelative(
-      fields[2],
-      `${source} mobileStaticDependencyArchives[${index}] path`,
-    );
-    if (relative === ".") {
-      fail(`${source} mobileStaticDependencyArchives[${index}] must name a file`);
-    }
-    const directory = `mobile-static/${target}/dependencies/${dependency}`;
-    const archiveName = path.posix.basename(relative);
-    portableAssetName(archiveName, `${source} mobileStaticDependencyArchives[${index}] file`);
-    if (
-      path.posix.dirname(relative) !== directory ||
-      !/^lib[A-Za-z0-9._-]+\.a$/u.test(archiveName)
-    ) {
-      fail(
-        `${source} mobileStaticDependencyArchives[${index}] must name a portable static archive ` +
-        `lib*.a directly under ${directory}; got ${relative}`,
-      );
-    }
-    return { archiveName, dependency, relative, target };
-  });
-  const targets = carrier.nativeModuleStem === null ? [] : ["ios-device", "ios-simulator"];
-  const expectedKeys = targets.flatMap((target) =>
-    carrier.nativeDependencies.map((dependency) => `${target}\0${dependency}`));
-  const actualKeys = rows.map(({ dependency, target }) => `${target}\0${dependency}`);
-  if (JSON.stringify(actualKeys) !== JSON.stringify(expectedKeys)) {
-    fail(
-      `${source} mobileStaticDependencyArchives must exactly cover both iOS static targets ` +
-      `for nativeDependencies=${carrier.nativeDependencies.join(",") || ""}`,
-    );
-  }
-  const archiveNameByDependency = new Map();
-  for (const { archiveName, dependency } of rows) {
-    const prior = archiveNameByDependency.get(dependency);
-    if (prior !== undefined && archiveName !== prior) {
-      fail(
-        `${source} mobileStaticDependencyArchives must use the same archive file name across ` +
-        `both iOS static targets for dependency ${dependency}; got ${prior} and ${archiveName}`,
-      );
-    }
-    archiveNameByDependency.set(dependency, archiveName);
-  }
-  return rows.map(({ relative }) => relative);
-}
-
-async function extensionArtifactEntries(root) {
-  const entries = [];
-  const collisions = new Map();
-  const pending = [{ absolute: root, relative: "" }];
-  while (pending.length > 0) {
-    const { absolute, relative } = pending.pop();
-    for (const name of (await fs.readdir(absolute)).sort(compareText).reverse()) {
-      const file = path.join(absolute, name);
-      const fileRelative = relative ? `${relative}/${name}` : name;
-      safeRelative(fileRelative, `${root} extension artifact entry`);
-      const folded = fileRelative.normalize("NFC").toLocaleLowerCase("en-US");
-      const prior = collisions.get(folded);
-      if (prior !== undefined && prior !== fileRelative) {
-        fail(`${root} extension artifact paths collide across case or Unicode normalization: ${prior}, ${fileRelative}`);
-      }
-      collisions.set(folded, fileRelative);
-      const stat = await fs.lstat(file);
-      if (stat.isSymbolicLink()) fail(`${root} extension artifact contains symlink: ${fileRelative}`);
-      if (stat.isDirectory()) {
-        entries.push({ path: fileRelative, type: "directory" });
-        pending.push({ absolute: file, relative: fileRelative });
-      } else if (stat.isFile()) {
-        entries.push({ path: fileRelative, type: "file" });
-      } else {
-        fail(`${root} extension artifact contains a special entry: ${fileRelative}`);
-      }
-    }
-  }
-  return entries.sort((left, right) => compareText(left.path, right.path));
-}
-
-function expectedExtensionArtifactEntries(files, source) {
-  const expected = new Map();
-  for (const file of files) {
-    const relative = safeRelative(file, `${source} expected artifact file`);
-    if (relative === ".") fail(`${source} expected artifact file must not be the root`);
-    const existing = expected.get(relative);
-    if (existing !== undefined && existing !== "file") {
-      fail(`${source} expected artifact path is both a file and directory: ${relative}`);
-    }
-    expected.set(relative, "file");
-    let parent = path.posix.dirname(relative);
-    while (parent !== ".") {
-      if (expected.get(parent) === "file") {
-        fail(`${source} expected artifact file is used as a directory: ${parent}`);
-      }
-      expected.set(parent, "directory");
-      parent = path.posix.dirname(parent);
-    }
-  }
-  const collisions = new Map();
-  for (const relative of expected.keys()) {
-    const folded = relative.normalize("NFC").toLocaleLowerCase("en-US");
-    const prior = collisions.get(folded);
-    if (prior !== undefined && prior !== relative) {
-      fail(`${source} expected artifact paths collide across case or Unicode normalization: ${prior}, ${relative}`);
-    }
-    collisions.set(folded, relative);
-  }
-  return expected;
-}
-
-async function validateExactExtensionArtifactInventory(
-  root,
-  carrier,
-  dataFiles,
-  extensionSqlFileNames,
-  extensionSqlFilePrefixes,
-  mobileStaticArchives,
-  mobileStaticDependencyArchives,
-  source,
-) {
-  const actualEntries = await extensionArtifactEntries(root);
-  const actualFiles = new Set(
-    actualEntries.filter(({ type }) => type === "file").map(({ path: entry }) => entry),
-  );
-  const expectedFiles = new Set(["manifest.properties"]);
-  for (const legalFile of carrier.legal.files) expectedFiles.add(legalFile.member);
-  if (carrier.createsExtension) {
-    const extensionRoot = "files/share/postgresql/extension";
-    const control = `${extensionRoot}/${carrier.sqlName}.control`;
-    if (!actualFiles.has(control)) fail(`${source} is missing canonical control file ${control}`);
-    expectedFiles.add(control);
-    const ownedSqlFiles = [...actualFiles].filter((file) => {
-      if (path.posix.dirname(file) !== extensionRoot) return false;
-      const name = path.posix.basename(file);
-      if (name === `${carrier.sqlName}.sql`) return true;
-      const prefix = `${carrier.sqlName}--`;
-      if (!name.startsWith(prefix) || !name.endsWith(".sql")) return false;
-      const versionPath = name.slice(prefix.length, -".sql".length);
-      return /^[A-Za-z0-9][A-Za-z0-9._-]*$/u.test(versionPath);
-    });
-    const installSqlFiles = ownedSqlFiles.filter((file) => {
-      const name = path.posix.basename(file);
-      const prefix = `${carrier.sqlName}--`;
-      if (!name.startsWith(prefix) || !name.endsWith(".sql")) return false;
-      const version = name.slice(prefix.length, -".sql".length);
-      return !version.includes("--") && /^[0-9][A-Za-z0-9._-]*$/u.test(version);
-    });
-    if (installSqlFiles.length === 0) {
-      fail(`${source} is missing an install SQL file owned by ${carrier.sqlName}`);
-    }
-    const ancillarySqlFiles = [...actualFiles].filter((file) => {
-      if (path.posix.dirname(file) !== extensionRoot) return false;
-      const name = path.posix.basename(file);
-      return (
-        extensionSqlFileNames.includes(name) ||
-        extensionSqlFilePrefixes.some(
-          (prefix) => name.startsWith(prefix) && name.endsWith(".sql"),
-        )
-      );
-    });
-    for (const file of [...ownedSqlFiles, ...ancillarySqlFiles]) expectedFiles.add(file);
-  }
-  for (const dataFile of dataFiles) {
-    expectedFiles.add(`files/share/postgresql/${dataFile}`);
-  }
-  if (carrier.nativeModuleStem !== null) {
-    expectedFiles.add(`files/lib/postgresql/${carrier.nativeModuleStem}.dylib`);
-  }
-  for (const file of [...mobileStaticArchives, ...mobileStaticDependencyArchives]) {
-    expectedFiles.add(file);
-  }
-
-  const expected = expectedExtensionArtifactEntries(expectedFiles, source);
-  const actual = new Map(actualEntries.map((entry) => [entry.path, entry.type]));
-  const missing = [...expected].filter(([entry, type]) => actual.get(entry) !== type)
-    .map(([entry]) => entry);
-  const extra = [...actual].filter(([entry, type]) => expected.get(entry) !== type)
-    .map(([entry]) => entry);
-  if (missing.length > 0 || extra.length > 0) {
-    fail(
-      `${source} extension artifact inventory must be exact; ` +
-      `missing=${missing.slice(0, 10).join(",") || ""}; ` +
-      `extra=${extra.slice(0, 10).join(",") || ""}`,
-    );
-  }
-}
-
-async function validateBaseResources(root) {
-  const closure = await validateNativeRuntimeClosure(root, { integrated: false });
-  const manifest = closure.runtime;
-  const manifestFile = path.join(root, "runtime", "manifest.properties");
-  const createable = csv(manifest.get("extensions"), `${manifestFile} extensions`);
-  if (!manifest.has("selectedExtensions")) {
-    fail(`${manifestFile} is missing selectedExtensions`);
-  }
-  const selected = csv(manifest.get("selectedExtensions"), `${manifestFile} selectedExtensions`);
-  if (selected.length > 0 || createable.length > 0) {
-    fail("base React Native iOS carrier is not extension-free");
-  }
-  if (csv(manifest.get("nativeModuleStems"), `${manifestFile} stems`).length > 0) {
-    fail("base React Native iOS carrier contains native extension stems");
-  }
-  requireProperty(manifest, "mobileStaticRegistryState", "not-required", manifestFile);
-  return closure;
-}
-
-async function extensionResourceRoot(carrier, base, cacheDir, carrierMemberCache) {
-  const root = await resolveLogicalAsset(carrier.assets.runtime, cacheDir, carrierMemberCache);
-  const manifestFile = path.join(root, "manifest.properties");
-  const manifest = parseProperties(await fs.readFile(manifestFile, "utf8"), manifestFile);
-  rejectUnsupportedProperties(manifest, EXTENSION_ARTIFACT_PROPERTY_KEYS, manifestFile);
-  requireProperty(manifest, "packageLayout", "oliphaunt-extension-artifact-v1", manifestFile);
-  requireProperty(manifest, "pgMajor", "18", manifestFile);
-  requireProperty(manifest, "sqlName", carrier.sqlName, manifestFile);
-  requireProperty(manifest, "nativeTarget", "ios-xcframework", manifestFile);
-  requireExtensionNativeRuntime(manifest, base, manifestFile);
-  requireProperty(manifest, "createsExtension", carrier.createsExtension ? "yes" : "no", manifestFile);
-  requireProperty(manifest, "dependencies", carrier.dependencies.join(","), manifestFile);
-  const extensionSqlFileNames = propertyRows(manifest, "extensionSqlFileNames", manifestFile)
-    .map((value, index) => {
-      const name = portable(value, `${manifestFile} extensionSqlFileNames[${index}]`);
-      if (!name.endsWith(".sql")) {
-        fail(`${manifestFile} extensionSqlFileNames[${index}] must name a SQL file`);
-      }
-      return name;
-    });
-  const extensionSqlFilePrefixes = propertyRows(
-    manifest,
-    "extensionSqlFilePrefixes",
-    manifestFile,
-  ).map((value, index) => {
-    if (!/^[A-Za-z0-9_-]{1,128}$/u.test(value)) {
-      fail(
-        `${manifestFile} extensionSqlFilePrefixes[${index}] must be a dot-free ` +
-          "portable SQL basename prefix",
-      );
-    }
-    return value;
-  });
-  if (JSON.stringify(extensionSqlFileNames) !== JSON.stringify(carrier.extensionSqlFileNames)) {
-    fail(`${manifestFile} extensionSqlFileNames must exactly match the frozen carrier contract for ${carrier.sqlName}`);
-  }
-  if (JSON.stringify(extensionSqlFilePrefixes) !== JSON.stringify(carrier.extensionSqlFilePrefixes)) {
-    fail(`${manifestFile} extensionSqlFilePrefixes must exactly match the frozen carrier contract for ${carrier.sqlName}`);
-  }
-  requireProperty(manifest, "nativeModuleStem", carrier.nativeModuleStem ?? "", manifestFile);
-  requireExtensionLinkageMetadata(manifest, carrier, manifestFile);
-  requireProperty(
-    manifest,
-    "sharedPreloadLibraries",
-    carrier.sharedPreloadLibraries.join(","),
-    manifestFile,
-  );
-  requireProperty(manifest, "mobilePrebuilt", carrier.nativeModuleStem === null ? "no" : "yes", manifestFile);
-  requireProperty(manifest, "licenseProfile", carrier.legal.profile, manifestFile);
-  const expectedUpstreamLicenses = carrier.legal.files
-    .map(({ member }) => /^files\/(share\/licenses\/.+)$/u.exec(member)?.[1])
-    .filter((member) => member !== undefined)
-    .sort(compareText);
-  requireProperty(manifest, "licenseFiles", expectedUpstreamLicenses.join(","), manifestFile);
-  requireProperty(manifest, "files", "files", manifestFile);
-  const filesRoot = path.join(root, "files");
-  if ((await statOrUndefined(filesRoot))?.isDirectory() !== true) {
-    fail(`${carrier.sqlName} runtime carrier is missing files`);
-  }
-
-  if (!manifest.has("dataFiles")) fail(`${manifestFile} must declare dataFiles`);
-  const dataFiles = manifest.get("dataFiles") === ""
-    ? []
-    : manifest.get("dataFiles").split(",").map((value, index) => {
-        const relative = safeRelative(value, `${manifestFile} dataFiles[${index}]`);
-        if (relative === ".") fail(`${manifestFile} dataFiles[${index}] must name a file`);
-        return relative;
-      });
-  if (new Set(dataFiles).size !== dataFiles.length) fail(`${manifestFile} dataFiles must not contain duplicates`);
-  if (JSON.stringify(dataFiles) !== JSON.stringify(carrier.dataFiles)) {
-    fail(`${manifestFile} dataFiles must exactly match the frozen carrier contract for ${carrier.sqlName}`);
-  }
-  requireExactPropertySet(manifest, EXTENSION_ARTIFACT_PROPERTY_KEYS, manifestFile);
-  const mobileStaticArchives = mobileStaticArchivePaths(manifest, carrier, manifestFile);
-  const mobileStaticDependencyArchives = mobileStaticDependencyArchivePaths(
-    manifest,
-    carrier,
-    manifestFile,
-  );
-  await validateExactExtensionArtifactInventory(
-    root,
-    carrier,
-    dataFiles,
-    extensionSqlFileNames,
-    extensionSqlFilePrefixes,
-    mobileStaticArchives,
-    mobileStaticDependencyArchives,
-    manifestFile,
-  );
-
-  const share = path.join(filesRoot, "share", "postgresql");
-  const shareStat = await statOrUndefined(share);
-  if (shareStat !== undefined && !shareStat.isDirectory()) {
-    fail(`${carrier.sqlName} runtime carrier files/share/postgresql is not a directory`);
-  }
-  if (shareStat === undefined && (carrier.createsExtension || dataFiles.length > 0)) {
-    fail(`${carrier.sqlName} runtime carrier is missing files/share/postgresql`);
-  }
-  return { root, share: shareStat === undefined ? null : share };
-}
-
-function selectedClosure(requested, bySqlName) {
-  const ordered = [];
-  const visiting = new Set();
-  const visited = new Set();
-  function visit(sqlName, requiredBy) {
-    if (visited.has(sqlName)) return;
-    if (visiting.has(sqlName)) fail(`extension dependency cycle includes ${sqlName}`);
-    const carrier = bySqlName.get(sqlName);
-    if (!carrier) fail(`missing iOS carrier for ${sqlName}${requiredBy ? ` required by ${requiredBy}` : ""}`);
-    visiting.add(sqlName);
-    for (const dependency of carrier.dependencies) visit(dependency, sqlName);
-    visiting.delete(sqlName);
-    visited.add(sqlName);
-    ordered.push(carrier);
-  }
-  for (const sqlName of requested) visit(sqlName, undefined);
-  return ordered;
-}
-
-function writeProperties(values) {
-  const preferred = [
-    "schema", "layout", "artifactRole", "catalogProfile", "clusterSeedTarget", "target",
-    "postgresMajor", "physicalFormat", "compatibilityKey", "initialSuperuser",
-    "icuDataVersion", "icuDataForm", "icuDataTreeSha256", "mode", "cacheKey",
-    "selectedExtensions", "extensions", "runtimeFeatures",
-    "sharedPreloadLibraries", "mobileStaticRegistryState", "mobileStaticRegistryRegistered",
-    "mobileStaticRegistryPending", "nativeModuleStems", "mobileStaticRegistrySource",
-  ];
-  const keys = [
-    ...preferred.filter((key) => values.has(key)),
-    ...[...values.keys()].filter((key) => !preferred.includes(key)).sort(compareText),
-  ];
-  return `${keys.map((key) => `${key}=${values.get(key)}`).join("\n")}\n`;
-}
-
-function renderRegistrySource(nativeCarriers) {
-  const declarations = [];
-  const arrays = [];
-  const descriptors = [];
-  for (const carrier of nativeCarriers) {
-    const suffix = carrier.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, "_");
-    const array = `oliphaunt_${suffix}_symbols`;
-    declarations.push(`extern const void *${carrier.registration.magicSymbol}(void);`);
-    if (carrier.registration.initSymbol) declarations.push(`extern void ${carrier.registration.initSymbol}(void);`);
-    for (const symbol of carrier.registration.symbols) declarations.push(`extern void ${symbol.address}(void);`);
-    if (carrier.registration.symbols.length > 0) {
-      arrays.push(
-        `static const OliphauntStaticExtensionSymbol ${array}[] = {\n` +
-          carrier.registration.symbols
-            .map(({ name, address }) => `    { .name = ${JSON.stringify(name)}, .address = (void *)${address} },`)
-            .join("\n") +
-          `\n};`,
-      );
-    }
-    descriptors.push(
-      `    {\n` +
-        `        .abi_version = OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION,\n` +
-        `        .name = ${JSON.stringify(carrier.nativeModuleStem)},\n` +
-        `        .magic = ${carrier.registration.magicSymbol},\n` +
-        `        .init = ${carrier.registration.initSymbol ?? "NULL"},\n` +
-        `        .symbols = ${carrier.registration.symbols.length > 0 ? array : "NULL"},\n` +
-        `        .symbol_count = ${carrier.registration.symbols.length > 0 ? `sizeof(${array}) / sizeof(${array}[0])` : "0"},\n` +
-        `        .reserved_flags = 0,\n` +
-        `    },`,
-    );
-  }
-  return `/* Generated by ${PREFIX}. Do not edit. */\n` +
-    `#include \n#include "oliphaunt.h"\n\n` +
-    `${[...new Set(declarations)].sort(compareText).join("\n")}\n\n` +
-    `${arrays.join("\n\n")}\n\n` +
-    `static const OliphauntStaticExtension liboliphaunt_static_extensions[] = {\n` +
-    `${descriptors.join("\n")}\n};\n\n` +
-    `const OliphauntStaticExtension *liboliphaunt_selected_static_extensions(size_t *count) {\n` +
-    `    if (count != NULL) *count = sizeof(liboliphaunt_static_extensions) / sizeof(liboliphaunt_static_extensions[0]);\n` +
-    `    return liboliphaunt_static_extensions;\n}\n`;
-}
-
-async function treeSize(root) {
-  if ((await statOrUndefined(root)) === undefined) return { bytes: 0, files: 0 };
-  let bytes = 0;
-  let files = 0;
-  const pending = [root];
-  while (pending.length > 0) {
-    const current = pending.pop();
-    for (const name of await fs.readdir(current)) {
-      const file = path.join(current, name);
-      const stat = await fs.lstat(file);
-      if (stat.isDirectory()) pending.push(file);
-      else if (stat.isFile()) { bytes += stat.size; files += 1; }
-      else fail(`generated payload contains unsupported entry: ${file}`);
-    }
-  }
-  return { bytes, files };
-}
-
-function renderPayloadPodspec(version, hasNative, baseFrameworkName, legal) {
-  const baseFramework = JSON.stringify(`frameworks/base/${baseFrameworkName}`);
-  return `Pod::Spec.new do |s|\n` +
-    `  s.name = "OliphauntReactNativePayload"\n` +
-    `  s.version = ${JSON.stringify(version)}\n` +
-    `  s.summary = "Generated app-owned Oliphaunt iOS runtime payload."\n` +
-    `  s.license = { :type => ${JSON.stringify(legal.spdx)}, :file => ${JSON.stringify(legal.file)} }\n` +
-    `  s.homepage = "https://oliphaunt.dev"\n` +
-    `  s.authors = { "Oliphaunt" => "opensource@oliphaunt.dev" }\n` +
-    `  s.source = { :git => "https://github.com/f0rr0/oliphaunt.git", :tag => "app-owned-payload" }\n` +
-    `  s.platforms = { :ios => "17.0" }\n` +
-    `  s.resources = "resources/OliphauntReactNativeResources.bundle"\n` +
-    `  s.preserve_paths = "licenses/**/*"\n` +
-    `  s.vendored_frameworks = ${baseFramework}, "frameworks/extensions/**/*.xcframework"\n` +
-    (hasNative
-      ? `  s.source_files = "generated/static-registry/*.c"\n  s.user_target_xcconfig = { "OTHER_LDFLAGS" => "$(inherited) -u _liboliphaunt_selected_static_extensions" }\n`
-      : "") +
-    `  s.dependency "COliphaunt"\n` +
-    `end\n`;
-}
-
-async function stage(args, base, selected) {
-  const selectionHash = createHash("sha256")
-    .update(JSON.stringify({ base, icu: args.icu, selected }))
-    .digest("hex");
-  const outputParent = path.dirname(args.outputDir);
-  const temporary = path.join(outputParent, `.${path.basename(args.outputDir)}.tmp-${process.pid}-${Date.now()}`);
-  await fs.mkdir(outputParent, { recursive: true });
-  await fs.rm(temporary, { force: true, recursive: true });
-  try {
-    const carrierMemberCache = new Map();
-    const baseResources = await resolveAsset(base.assets.runtime, args.cacheDir);
-    const baseClosure = await validateBaseResources(baseResources);
-    const baseManifest = baseClosure.runtime;
-    const resourceRoot = path.join(
-      temporary,
-      "resources",
-      "OliphauntReactNativeResources.bundle",
-      "oliphaunt",
-    );
-    await copyTree(baseResources, resourceRoot);
-    let icuDataTreeSha256 = "";
-    if (args.icu) {
-      const icuClosure = await resolveAsset(base.assets.icu, args.cacheDir);
-      await requirePayloadDirectory(icuClosure, "ICU closure carrier member");
-      const icu = await validateIcuDataCarrier(icuClosure);
-      if (icu.digest !== baseClosure.icuDigest) {
-        fail("iOS ICU data does not match the target runtime's cluster-seed-icu");
-      }
-      icuDataTreeSha256 = icu.digest;
-      await mergeTree(icu.data, path.join(resourceRoot, "runtime", "files", "share", "icu"));
-    }
-    const baseFramework = await resolveAsset(base.assets.framework, args.cacheDir);
-    const baseFrameworkName = path.posix.basename(base.assets.framework.member);
-    if (
-      !baseFrameworkName.endsWith(".xcframework") ||
-      path.basename(baseFramework) !== baseFrameworkName
-    ) {
-      fail("base framework carrier member must resolve to its declared .xcframework directory");
-    }
-    const stagedBaseFramework = path.join(temporary, "frameworks", "base", baseFrameworkName);
-    await copyTree(baseFramework, stagedBaseFramework);
-    // Swift consumes the per-slice closure embedded by the XCFramework. React
-    // Native publishes one composed app-owned bundle instead, so retaining the
-    // embedded copies would ship the same PostgreSQL runtime and both seeds
-    // twice. Validate their receipts before removing only the staged copies.
-    await stripEmbeddedRuntimeClosures(stagedBaseFramework);
-
-    const extensionRows = [];
-    const nativeCarriers = selected.filter(({ nativeModuleStem }) => nativeModuleStem !== null);
-    for (const carrier of selected) {
-      const extensionResources = await extensionResourceRoot(
-        carrier,
-        base,
-        args.cacheDir,
-        carrierMemberCache,
-      );
-      if (extensionResources.share !== null) {
-        await mergeTree(
-          extensionResources.share,
-          path.join(resourceRoot, "runtime", "files", "share", "postgresql"),
-        );
-      }
-      extensionRows.push({
-        ...(extensionResources.share === null
-          ? { bytes: 0, files: 0 }
-          : await treeSize(extensionResources.share)),
-        sqlName: carrier.sqlName,
-      });
-      if (carrier.assets.extension) {
-        const frameworkAssets = [
-          { asset: carrier.assets.extension, expected: `liboliphaunt_extension_${carrier.nativeModuleStem}.xcframework` },
-          ...carrier.assets.dependencyFrameworks.map(({ asset, dependency }) => ({
-            asset,
-            expected: `liboliphaunt_dependency_${dependency}.xcframework`,
-          })),
-        ];
-        for (const { asset, expected } of frameworkAssets) {
-          const source = await resolveLogicalAsset(asset, args.cacheDir, carrierMemberCache);
-          if (path.basename(source) !== expected) {
-            fail(`${carrier.sqlName} framework asset resolved to ${path.basename(source)}, expected ${expected}`);
-          }
-          await mergeTree(
-            source,
-            path.join(temporary, "frameworks", "extensions", expected),
-          );
-        }
-      }
-    }
-
-    const legal = await stageSelectedLegalFiles({
-      args,
-      base,
-      carrierMemberCache,
-      selected,
-      temporary,
-    });
-
-    const selectedExtensions = selected.map(({ sqlName }) => sqlName).sort(compareText);
-    const createExtensions = selected.filter(({ createsExtension }) => createsExtension).map(({ sqlName }) => sqlName).sort(compareText);
-    const nativeStems = nativeCarriers.map(({ nativeModuleStem }) => nativeModuleStem).sort(compareText);
-    const nativeExtensions = nativeCarriers.map(({ sqlName }) => sqlName).sort(compareText);
-    const nativeDependencies = [...new Set(nativeCarriers.flatMap(({ nativeDependencies }) => nativeDependencies))].sort(compareText);
-    const sharedPreload = [...new Set(selected.flatMap(({ sharedPreloadLibraries }) => sharedPreloadLibraries))].sort(compareText);
-    baseManifest.set("cacheKey", `react-native-ios-${selectionHash.slice(0, 32)}`);
-    baseManifest.set("selectedExtensions", selectedExtensions.join(","));
-    baseManifest.set("extensions", createExtensions.join(","));
-    const runtimeFeatures = new Set(csv(baseManifest.get("runtimeFeatures"), "base runtime features"));
-    if (args.icu) runtimeFeatures.add("icu");
-    else runtimeFeatures.delete("icu");
-    baseManifest.set("runtimeFeatures", [...runtimeFeatures].sort(compareText).join(","));
-    baseManifest.set("icuDataTreeSha256", icuDataTreeSha256);
-    baseManifest.set("sharedPreloadLibraries", sharedPreload.join(","));
-    baseManifest.set("mobileStaticRegistryState", nativeStems.length > 0 ? "complete" : "not-required");
-    baseManifest.set("mobileStaticRegistryRegistered", nativeExtensions.join(","));
-    baseManifest.set("mobileStaticRegistryPending", "");
-    baseManifest.set("nativeModuleStems", nativeStems.join(","));
-    baseManifest.set(
-      "mobileStaticRegistrySource",
-      nativeStems.length > 0 ? "static-registry/oliphaunt_static_registry.c" : "",
-    );
-    await fs.writeFile(path.join(resourceRoot, "runtime", "manifest.properties"), writeProperties(baseManifest));
-
-    const registryRoot = path.join(resourceRoot, "static-registry");
-    await fs.rm(registryRoot, { force: true, recursive: true });
-    await fs.mkdir(registryRoot, { recursive: true });
-    await fs.writeFile(
-      path.join(registryRoot, "manifest.properties"),
-      [
-        "packageLayout=oliphaunt-static-registry-v1",
-        "abiVersion=1",
-        `state=${nativeStems.length > 0 ? "complete" : "not-required"}`,
-        `source=${nativeStems.length > 0 ? "oliphaunt_static_registry.c" : ""}`,
-        `registeredExtensions=${nativeExtensions.join(",")}`,
-        "pendingExtensions=",
-        `nativeModuleStems=${nativeStems.join(",")}`,
-        `modules=${nativeStems.join(",")}`,
-        `archiveTargets=${nativeStems.length > 0 ? "ios-device,ios-simulator" : ""}`,
-        `dependencyArchiveTargets=${nativeDependencies.length > 0 ? "ios-device,ios-simulator" : ""}`,
-        `dependencyArchives=${nativeDependencies.join(",")}`,
-        "",
-      ].join("\n"),
-    );
-    if (nativeCarriers.length > 0) {
-      const generated = path.join(temporary, "generated", "static-registry");
-      await fs.mkdir(generated, { recursive: true });
-      await fs.writeFile(
-        path.join(generated, "oliphaunt_static_registry.c"),
-        renderRegistrySource(nativeCarriers),
-      );
-    }
-
-    const runtimeSize = await treeSize(path.join(resourceRoot, "runtime", "files"));
-    const standardClusterSeedSize = await treeSize(path.join(resourceRoot, "cluster-seed", "files"));
-    const icuClusterSeedSize = await treeSize(path.join(resourceRoot, "cluster-seed-icu", "files"));
-    const registrySize = await treeSize(registryRoot);
-    const selectedBytes = extensionRows.reduce((total, row) => total + row.bytes, 0);
-    const selectedFiles = extensionRows.reduce((total, row) => total + row.files, 0);
-    const extensionNames = selectedExtensions.length > 0 ? selectedExtensions.join(",") : "-";
-    await fs.writeFile(
-      path.join(resourceRoot, "package-size.tsv"),
-      [
-        "kind\tid\textensions\tfiles\tbytes",
-        `package\ttotal\t${extensionNames}\t${runtimeSize.files + standardClusterSeedSize.files + icuClusterSeedSize.files + registrySize.files}\t${runtimeSize.bytes + standardClusterSeedSize.bytes + icuClusterSeedSize.bytes + registrySize.bytes}`,
-        `package\truntime\t${extensionNames}\t${runtimeSize.files}\t${runtimeSize.bytes}`,
-        `package\tcluster-seed\t-\t${standardClusterSeedSize.files}\t${standardClusterSeedSize.bytes}`,
-        `package\tcluster-seed-icu\t-\t${icuClusterSeedSize.files}\t${icuClusterSeedSize.bytes}`,
-        `package\tstatic-registry\t${extensionNames}\t${registrySize.files}\t${registrySize.bytes}`,
-        `extensions\tselected\t${extensionNames}\t${selectedFiles}\t${selectedBytes}`,
-        ...extensionRows.sort((left, right) => compareText(left.sqlName, right.sqlName))
-          .map((row) => `extension\t${row.sqlName}\t-\t${row.files}\t${row.bytes}`),
-        "",
-      ].join("\n"),
-    );
-
-    const frozen = {
-      base: { product: base.product, version: base.version, assets: base.assets },
-      cacheKey: `react-native-ios-${selectionHash.slice(0, 32)}`,
-      extensions: selected.map((carrier) => ({
-        assets: carrier.assets,
-        createsExtension: carrier.createsExtension,
-        dependencies: carrier.dependencies,
-        nativeDependencies: carrier.nativeDependencies,
-        nativeModuleStem: carrier.nativeModuleStem,
-        product: carrier.product,
-        releaseProduct: carrier.releaseProduct,
-        sqlName: carrier.sqlName,
-        version: carrier.version,
-      })),
-      requestedExtensions: args.extensions,
-      icu: args.icu,
-      legal,
-      schema: OUTPUT_SCHEMA,
-    };
-    await fs.writeFile(path.join(temporary, "selection.json"), `${JSON.stringify(frozen, null, 2)}\n`);
-    await fs.writeFile(
-      path.join(temporary, "OliphauntReactNativePayload.podspec"),
-      renderPayloadPodspec(base.version, nativeCarriers.length > 0, baseFrameworkName, legal),
-    );
-    await fs.rm(args.outputDir, { force: true, recursive: true });
-    await fs.rename(temporary, args.outputDir);
-  } catch (error) {
-    await fs.rm(temporary, { force: true, recursive: true });
-    throw error;
-  }
-}
-
-export async function stageIosApp(options) {
-  const carriers = options.carriers ?? [
-    ...(options.baseCarrier ? [options.baseCarrier] : []),
-    ...(options.extensionCarriers ?? []),
-  ];
-  const args = {
-    allowFileUrls: options.allowFileUrls === true,
-    carriers: carriers.map((file) => path.resolve(file)),
-    cacheDir: path.resolve(options.cacheDir ?? path.join(os.homedir(), ".cache", "oliphaunt", "react-native-ios")),
-    extensions: uniquePortable(options.extensions ?? [], "selected extension"),
-    icu: options.icu === true,
-    outputDir: path.resolve(options.outputDir),
-  };
-  if (args.carriers.length === 0) fail("at least one carrier manifest is required");
-  let base;
-  const bySqlName = new Map();
-  const carriersByName = new Map();
-  const releasesByOwner = new Map();
-  for (const file of args.carriers) {
-    const document = await readCarrierDocument(file, args.allowFileUrls);
-    if (base === undefined) {
-      base = document.base;
-    } else if (JSON.stringify(base) !== JSON.stringify(document.base)) {
-      fail(`${file} pins a different base carrier than the other selected manifests`);
-    }
-    for (const [name, envelope] of document.carriers) {
-      const existing = carriersByName.get(name);
-      if (existing !== undefined && JSON.stringify(existing) !== JSON.stringify(envelope)) {
-        fail(`carrier manifests disagree about envelope ${name}`);
-      }
-      carriersByName.set(name, envelope);
-    }
-    for (const carrier of document.extensions) {
-      const release = { tag: carrier.tag, version: carrier.version };
-      const existingRelease = releasesByOwner.get(carrier.releaseProduct);
-      if (
-        existingRelease !== undefined &&
-        JSON.stringify(existingRelease) !== JSON.stringify(release)
-      ) {
-        fail(`carrier manifests disagree about release version for owner ${carrier.releaseProduct}`);
-      }
-      releasesByOwner.set(carrier.releaseProduct, release);
-      const existing = bySqlName.get(carrier.sqlName);
-      if (existing && JSON.stringify(existing) !== JSON.stringify(carrier)) {
-        fail(`carrier manifests disagree for exact extension ${carrier.sqlName}`);
-      }
-      bySqlName.set(carrier.sqlName, carrier);
-    }
-  }
-  for (const carrier of bySqlName.values()) {
-    if (carrier.runtimeBound && carrier.version !== base.version) {
-      fail(
-        `runtime-bound owner ${carrier.releaseProduct} version ${carrier.version} ` +
-          `must match base runtime ${base.version}`,
-      );
-    }
-  }
-  const selected = selectedClosure(args.extensions, bySqlName);
-  await stage(args, base, selected);
-  return { outputDir: args.outputDir, selected: selected.map(({ sqlName }) => sqlName) };
-}
-
-async function main() {
-  const args = parseArgs(process.argv.slice(2));
-  const result = await stageIosApp(args);
-  console.log(
-    `${PREFIX}: staged ${result.outputDir} (extensions=${result.selected.join(",") || "none"})`,
-  );
-}
-
-if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
-  main().catch((error) => {
-    console.error(error instanceof Error ? error.message : String(error));
-    process.exit(1);
-  });
-}
diff --git a/src/sdks/react-native/tools/stage-ios-app.mts b/src/sdks/react-native/tools/stage-ios-app.mts
new file mode 100755
index 000000000..576737d33
--- /dev/null
+++ b/src/sdks/react-native/tools/stage-ios-app.mts
@@ -0,0 +1,2448 @@
+#!/usr/bin/env node
+
+import { createHash } from 'node:crypto';
+import { createReadStream, createWriteStream, constants as fsConstants } from 'node:fs';
+import fs from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
+import { Readable, Transform } from 'node:stream';
+import { pipeline } from 'node:stream/promises';
+import { fileURLToPath } from 'node:url';
+import {
+  extractPortableArchiveTree,
+  extractPortableTarGzipTree,
+} from '../../../../tools/packaging/portable-archive.mts';
+
+import {
+  parseProperties,
+  requireProperty,
+  validateNativeRuntimeClosure,
+} from './native-resource-closure.mts';
+
+const PREFIX = 'stage-ios-app.mjs';
+const SCHEMA = 'oliphaunt-react-native-ios-carrier-v1';
+const OUTPUT_SCHEMA = 'oliphaunt-react-native-ios-selection-v1';
+const PORTABLE_RE = /^[A-Za-z0-9._-]{1,128}$/u;
+const C_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/u;
+const STABLE_SEMVER_RE = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u;
+const EXTRACTED_CACHE_SCHEMA = 'oliphaunt-extracted-carrier-tree-v1';
+// GitHub release assets are bounded at the transport boundary and archives are
+// bounded again at their expanded boundary. These ceilings are intentionally
+// well above the production iOS payloads while making archive bombs fail before
+// extraction can consume unbounded disk or memory.
+const MAX_CARRIER_BYTES = 2 * 1024 * 1024 * 1024;
+const MAX_ZIP_CARRIER_BYTES = 512 * 1024 * 1024;
+const MAX_ARCHIVE_ENTRIES = 4096;
+// The canonical ICU data payload and base XCFramework contain the complete
+// bundled runtime resource trees and legitimately exceed the general carrier
+// ceiling. Keep that exception tied to those validated base-carrier roles
+// instead of weakening extension and runtime archive protection globally.
+const MAX_BUNDLED_RESOURCE_ARCHIVE_ENTRIES = 16384;
+const MAX_ARCHIVE_MEMBER_BYTES = 1024 * 1024 * 1024;
+const MAX_ARCHIVE_EXPANDED_BYTES = 4 * 1024 * 1024 * 1024;
+const MAX_LEGAL_FILE_BYTES = 16 * 1024 * 1024;
+const MAX_LEGAL_FILES = 1024;
+const SPDX_ID_RE = /^[A-Za-z0-9][A-Za-z0-9.-]*$/u;
+const EXTENSION_ARTIFACT_PROPERTY_KEYS = new Set([
+  'packageLayout',
+  'pgMajor',
+  'sqlName',
+  'createsExtension',
+  'nativeModuleStem',
+  'nativeModuleFile',
+  'nativeTarget',
+  'nativeRuntimeProduct',
+  'nativeRuntimeVersion',
+  'dependencies',
+  'dataFiles',
+  'extensionSqlFileNames',
+  'extensionSqlFilePrefixes',
+  'sharedPreloadLibraries',
+  'mobilePrebuilt',
+  'mobileStaticArchives',
+  'mobileStaticDependencyArchives',
+  'staticSymbolPrefix',
+  'staticSymbolAliases',
+  'licenseFiles',
+  'licenseProfile',
+  'files',
+]);
+const GENERATED_EXTENSION_CATALOG = JSON.parse(
+  await fs.readFile(
+    await Promise.any(
+      [
+        new URL('../src/generated/extensions.json', import.meta.url),
+        new URL('../../../extensions/generated/sdk/extensions.json', import.meta.url),
+      ].map(async (url) => {
+        await fs.access(url);
+        return url;
+      }),
+    ),
+    'utf8',
+  ),
+);
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+
+function usage() {
+  console.error(
+    `usage: ${PREFIX} --carrier  [--carrier ]... ` +
+      `--output-dir  [--extensions ] [--icu] [--seed-profile ] ` +
+      `[--cache-dir ] [--allow-file-urls]`,
+  );
+}
+
+function parseArgs(argv) {
+  const args = {
+    allowFileUrls: false,
+    cacheDir: path.join(os.homedir(), '.cache', 'oliphaunt', 'react-native-ios'),
+    carriers: [],
+    extensions: [],
+    icu: false,
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--allow-file-urls') {
+      args.allowFileUrls = true;
+      continue;
+    }
+    if (arg === '--icu') {
+      args.icu = true;
+      continue;
+    }
+    if (arg === '--help' || arg === '-h') {
+      usage();
+      process.exit(0);
+    }
+    if (
+      ![
+        '--carrier',
+        '--base-carrier',
+        '--cache-dir',
+        '--extension-carrier',
+        '--extensions',
+        '--output-dir',
+        '--seed-profile',
+      ].includes(arg)
+    ) {
+      usage();
+      fail(`unknown argument ${arg}`);
+    }
+    const value = argv[index + 1];
+    if (value === undefined || value.startsWith('--')) {
+      fail(`${arg} requires a value`);
+    }
+    index += 1;
+    if (arg === '--carrier' || arg === '--base-carrier') args.carriers.push(path.resolve(value));
+    if (arg === '--cache-dir') args.cacheDir = path.resolve(value);
+    if (arg === '--extension-carrier') args.carriers.push(path.resolve(value));
+    if (arg === '--output-dir') args.outputDir = path.resolve(value);
+    if (arg === '--seed-profile') args.seedProfile = value;
+    if (arg === '--extensions') {
+      args.extensions.push(
+        ...value
+          .split(',')
+          .map((item) => item.trim())
+          .filter(Boolean),
+      );
+    }
+  }
+  if (args.carriers.length === 0 || !args.outputDir) {
+    usage();
+    fail('at least one --carrier and --output-dir are required');
+  }
+  args.extensions = uniquePortable(args.extensions, 'selected extension');
+  return args;
+}
+
+function object(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(`${label} must be an object`);
+  }
+  return value;
+}
+
+function exactKeys(value, allowed, label) {
+  const actual = Object.keys(value).sort(compareText);
+  const expected = [...allowed].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+    fail(`${label} fields must be exactly ${expected.join(',')}; got ${actual.join(',')}`);
+  }
+}
+
+function portable(value, label) {
+  if (typeof value !== 'string' || !PORTABLE_RE.test(value)) {
+    fail(`${label} must be a portable identifier`);
+  }
+  return value;
+}
+
+function stableVersion(value, label) {
+  if (typeof value !== 'string' || !STABLE_SEMVER_RE.test(value)) {
+    fail(`${label} must be a stable SemVer X.Y.Z version`);
+  }
+  return value;
+}
+
+function cIdentifier(value, label) {
+  if (typeof value !== 'string' || !C_IDENTIFIER_RE.test(value)) {
+    fail(`${label} must be a C identifier`);
+  }
+  return value;
+}
+
+function uniquePortable(value, label) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const result = value.map((item, index) => portable(item, `${label}[${index}]`));
+  if (new Set(result).size !== result.length) fail(`${label} must not contain duplicates`);
+  return result.sort(compareText);
+}
+
+function canonicalPortableList(value, label) {
+  const canonical = uniquePortable(value, label);
+  if (JSON.stringify(value) !== JSON.stringify(canonical)) {
+    fail(`${label} must be sorted in ordinal order`);
+  }
+  return canonical;
+}
+
+function generatedExtensionCatalog(value) {
+  const catalog = object(value, 'generated React Native extension catalog');
+  if (!Array.isArray(catalog.extensions)) {
+    fail('generated React Native extension catalog.extensions must be an array');
+  }
+  const rows = new Map();
+  for (const [index, raw] of catalog.extensions.entries()) {
+    const row = object(raw, `generated React Native extension catalog.extensions[${index}]`);
+    const sqlName = portable(
+      row['sql-name'],
+      `generated React Native extension catalog.extensions[${index}].sql-name`,
+    );
+    const artifactProduct = portable(
+      row['artifact-product'],
+      `generated React Native extension catalog.extensions[${index}].artifact-product`,
+    );
+    const releaseProduct = portable(
+      row['release-product'],
+      `generated React Native extension catalog.extensions[${index}].release-product`,
+    );
+    if (!artifactProduct.startsWith('oliphaunt-extension-')) {
+      fail(`generated artifact product for ${sqlName} must be an extension product`);
+    }
+    if (typeof row['runtime-bound'] !== 'boolean') {
+      fail(`generated runtime-bound flag for ${sqlName} must be boolean`);
+    }
+    if (rows.has(sqlName)) fail(`generated React Native extension catalog repeats ${sqlName}`);
+    rows.set(sqlName, {
+      artifactProduct,
+      releaseProduct,
+      runtimeBound: row['runtime-bound'],
+    });
+  }
+  return rows;
+}
+
+const GENERATED_EXTENSION_BY_SQL_NAME = generatedExtensionCatalog(GENERATED_EXTENSION_CATALOG);
+
+function safeRelative(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    /[\u0000-\u001f\u007f]/u.test(value) ||
+    /^[A-Za-z]:/u.test(value)
+  ) {
+    fail(`${label} must be a non-empty archive-relative path`);
+  }
+  if (value === '.') return value;
+  const normalized = value.replace(/^\.\//u, '');
+  const parts = normalized.split('/');
+  if (path.isAbsolute(value) || parts.some((part) => !part || part === '.' || part === '..')) {
+    fail(`${label} is not a safe archive-relative path: ${JSON.stringify(value)}`);
+  }
+  return normalized;
+}
+
+function spdxConjunction(value, label) {
+  if (typeof value !== 'string' || value.length === 0) {
+    fail(`${label} must be a non-empty SPDX conjunction`);
+  }
+  const terms = value.split(' AND ');
+  if (terms.some((term) => !SPDX_ID_RE.test(term))) {
+    fail(`${label} must contain only SPDX identifiers joined by AND`);
+  }
+  if (new Set(terms).size !== terms.length) fail(`${label} repeats an SPDX identifier`);
+  return value;
+}
+
+function validateLegalFiles(value, label) {
+  if (!Array.isArray(value) || value.length === 0 || value.length > MAX_LEGAL_FILES) {
+    fail(`${label} must contain between 1 and ${MAX_LEGAL_FILES} legal file locators`);
+  }
+  const rows = value.map((raw, index) => {
+    const row = object(raw, `${label}[${index}]`);
+    exactKeys(row, ['bytes', 'kind', 'member', 'sha256'], `${label}[${index}]`);
+    const member = safeRelative(row.member, `${label}[${index}].member`);
+    if (member === '.') fail(`${label}[${index}].member must name a file`);
+    if (!Number.isSafeInteger(row.bytes) || row.bytes <= 0 || row.bytes > MAX_LEGAL_FILE_BYTES) {
+      fail(`${label}[${index}].bytes must be between 1 and ${MAX_LEGAL_FILE_BYTES}`);
+    }
+    if (!new Set(['license', 'notice']).has(row.kind)) {
+      fail(`${label}[${index}].kind must be license or notice`);
+    }
+    if (typeof row.sha256 !== 'string' || !/^[a-f0-9]{64}$/u.test(row.sha256)) {
+      fail(`${label}[${index}].sha256 must be a lowercase SHA-256 digest`);
+    }
+    return { bytes: row.bytes, kind: row.kind, member, sha256: row.sha256 };
+  });
+  const canonical = [...rows].sort((left, right) => compareText(left.member, right.member));
+  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
+    fail(`${label} must be sorted by archive member in ordinal order`);
+  }
+  const folded = new Map();
+  for (const row of rows) {
+    const key = row.member.normalize('NFC').toLowerCase();
+    const prior = folded.get(key);
+    if (prior !== undefined) {
+      fail(`${label} has colliding legal members ${prior} and ${row.member}`);
+    }
+    folded.set(key, row.member);
+  }
+  return rows;
+}
+
+function validateLegalGroup(value, label, { sqlName = undefined } = {}) {
+  const row = object(value, label);
+  const keys =
+    sqlName === undefined
+      ? ['assetRole', 'files', 'profile', 'spdx']
+      : ['assetRole', 'files', 'profile', 'spdx', 'sqlName'];
+  exactKeys(row, keys, label);
+  if (sqlName !== undefined && row.sqlName !== sqlName) {
+    fail(`${label}.sqlName must be ${sqlName}`);
+  }
+  return {
+    assetRole: portable(row.assetRole, `${label}.assetRole`),
+    files: validateLegalFiles(row.files, `${label}.files`),
+    profile: portable(row.profile, `${label}.profile`),
+    spdx: spdxConjunction(row.spdx, `${label}.spdx`),
+    ...(sqlName === undefined ? {} : { sqlName }),
+  };
+}
+
+function portableAssetName(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    path.posix.basename(value) !== value ||
+    /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) ||
+    /[ .]$/u.test(value) ||
+    /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value)
+  ) {
+    fail(`${label} must be a portable release asset file name`);
+  }
+  return value;
+}
+
+function canonicalRelativeFileList(value, label) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((item, index) => {
+    const relative = safeRelative(item, `${label}[${index}]`);
+    if (relative === '.') fail(`${label}[${index}] must name a file`);
+    return relative;
+  });
+  const canonical = [...rows].sort(compareText);
+  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
+  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
+    fail(`${label} must be sorted in ordinal order`);
+  }
+  return rows;
+}
+
+function canonicalSqlFileNameList(value, label) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((item, index) => {
+    const name = portable(item, `${label}[${index}]`);
+    if (!name.endsWith('.sql')) fail(`${label}[${index}] must name a SQL file`);
+    return name;
+  });
+  const canonical = [...rows].sort(compareText);
+  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
+  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
+    fail(`${label} must be sorted in ordinal order`);
+  }
+  return rows;
+}
+
+function canonicalSqlFilePrefixList(value, label) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((item, index) => {
+    if (typeof item !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/u.test(item)) {
+      fail(`${label}[${index}] must be a dot-free portable SQL basename prefix`);
+    }
+    return item;
+  });
+  const canonical = [...rows].sort(compareText);
+  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
+  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
+    fail(`${label} must be sorted in ordinal order`);
+  }
+  return rows;
+}
+
+function boundedBytes(value, label, maximum = MAX_CARRIER_BYTES) {
+  if (!Number.isSafeInteger(value) || value <= 0) {
+    fail(`${label} must be a positive safe integer`);
+  }
+  if (value > maximum) {
+    fail(`${label} exceeds the maximum supported size of ${maximum} bytes`);
+  }
+  return value;
+}
+
+function archiveEntryLimit(asset) {
+  return asset.role === 'base-xcframework'
+    ? MAX_BUNDLED_RESOURCE_ARCHIVE_ENTRIES
+    : MAX_ARCHIVE_ENTRIES;
+}
+
+function validateAsset(value, label, allowFileUrls) {
+  const asset = object(value, label);
+  exactKeys(asset, ['bytes', 'format', 'member', 'name', 'role', 'sha256', 'url'], label);
+  const role = portable(asset.role, `${label}.role`);
+  portableAssetName(asset.name, `${label}.name`);
+  if (!['tar.gz', 'zip'].includes(asset.format)) {
+    fail(`${label}.format must be tar.gz or zip`);
+  }
+  if (typeof asset.sha256 !== 'string' || !/^[a-f0-9]{64}$/u.test(asset.sha256)) {
+    fail(`${label}.sha256 must be a lowercase SHA-256 digest`);
+  }
+  boundedBytes(asset.bytes, `${label}.bytes`);
+  let url;
+  try {
+    url = new URL(asset.url);
+  } catch {
+    fail(`${label}.url must be an absolute URL`);
+  }
+  if (url.protocol !== 'https:' && !(allowFileUrls && url.protocol === 'file:')) {
+    fail(`${label}.url must use HTTPS${allowFileUrls ? ' or an explicitly enabled file URL' : ''}`);
+  }
+  let urlName;
+  try {
+    urlName = decodeURIComponent(path.basename(url.pathname));
+  } catch {
+    fail(`${label}.url contains invalid escaping`);
+  }
+  if (urlName !== asset.name) {
+    fail(`${label}.url must end with ${asset.name}`);
+  }
+  if (
+    (asset.format === 'zip' && !asset.name.endsWith('.zip')) ||
+    (asset.format === 'tar.gz' && !asset.name.endsWith('.tar.gz'))
+  ) {
+    fail(`${label}.name does not match format ${asset.format}`);
+  }
+  return {
+    bytes: asset.bytes,
+    format: asset.format,
+    member: safeRelative(asset.member, `${label}.member`),
+    name: asset.name,
+    role,
+    sha256: asset.sha256,
+    url: url.href,
+  };
+}
+
+function validateCarrierEnvelope(value, label, allowFileUrls) {
+  const carrier = object(value, label);
+  exactKeys(carrier, ['bytes', 'format', 'name', 'sha256', 'url'], label);
+  portableAssetName(carrier.name, `${label}.name`);
+  boundedBytes(carrier.bytes, `${label}.bytes`);
+  if (typeof carrier.sha256 !== 'string' || !/^[a-f0-9]{64}$/u.test(carrier.sha256)) {
+    fail(`${label}.sha256 must be a lowercase SHA-256 digest`);
+  }
+  if (!['tar.gz', 'zip'].includes(carrier.format)) {
+    fail(`${label}.format must be tar.gz or zip`);
+  }
+  if (
+    (carrier.format === 'zip' && !carrier.name.endsWith('.zip')) ||
+    (carrier.format === 'tar.gz' && !carrier.name.endsWith('.tar.gz'))
+  ) {
+    fail(`${label}.name does not match format ${carrier.format}`);
+  }
+  let url;
+  try {
+    url = new URL(carrier.url);
+  } catch {
+    fail(`${label}.url must be an absolute URL`);
+  }
+  if (url.protocol !== 'https:' && !(allowFileUrls && url.protocol === 'file:')) {
+    fail(`${label}.url must use HTTPS${allowFileUrls ? ' or an explicitly enabled file URL' : ''}`);
+  }
+  let urlName;
+  try {
+    urlName = decodeURIComponent(path.posix.basename(url.pathname));
+  } catch {
+    fail(`${label}.url contains invalid escaping`);
+  }
+  if (urlName !== carrier.name) fail(`${label}.url must end with ${carrier.name}`);
+  return {
+    bytes: carrier.bytes,
+    format: carrier.format,
+    name: carrier.name,
+    sha256: carrier.sha256,
+    url: url.href,
+  };
+}
+
+function validateCarrierEnvelopes(value, label, allowFileUrls) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((row, index) =>
+    validateCarrierEnvelope(row, `${label}[${index}]`, allowFileUrls),
+  );
+  if (new Set(rows.map(({ name }) => name)).size !== rows.length) {
+    fail(`${label} repeats a carrier name`);
+  }
+  rows.sort((left, right) => compareText(left.name, right.name));
+  return new Map(rows.map((row) => [row.name, row]));
+}
+
+function validateAssetLocator(value, label, carriers) {
+  const asset = object(value, label);
+  exactKeys(asset, ['bytes', 'carrier', 'format', 'member', 'path', 'role', 'sha256'], label);
+  const role = portable(asset.role, `${label}.role`);
+  const carrierName = portableAssetName(asset.carrier, `${label}.carrier`);
+  const envelope = carriers.get(carrierName);
+  if (envelope === undefined) {
+    fail(`${label}.carrier references undeclared envelope ${carrierName}`);
+  }
+  const logicalPath = safeRelative(asset.path, `${label}.path`);
+  const member = safeRelative(asset.member, `${label}.member`);
+  boundedBytes(asset.bytes, `${label}.bytes`);
+  if (typeof asset.sha256 !== 'string' || !/^[a-f0-9]{64}$/u.test(asset.sha256)) {
+    fail(`${label}.sha256 must be a lowercase SHA-256 digest`);
+  }
+  if (!['tar.gz', 'zip'].includes(asset.format)) {
+    fail(`${label}.format must be tar.gz or zip`);
+  }
+  if (logicalPath === '.') {
+    if (
+      asset.bytes !== envelope.bytes ||
+      asset.sha256 !== envelope.sha256 ||
+      asset.format !== envelope.format
+    ) {
+      fail(`${label} direct payload metadata must exactly match carrier ${carrierName}`);
+    }
+  } else {
+    if (envelope.format !== 'tar.gz') {
+      fail(`${label} nested payload carrier must be a tar.gz archive`);
+    }
+    const nestedName = path.posix.basename(logicalPath);
+    portableAssetName(nestedName, `${label}.path basename`);
+    if (
+      (asset.format === 'zip' && !nestedName.endsWith('.zip')) ||
+      (asset.format === 'tar.gz' && !nestedName.endsWith('.tar.gz'))
+    ) {
+      fail(`${label}.path does not match logical payload format ${asset.format}`);
+    }
+  }
+  return {
+    bytes: asset.bytes,
+    carrier: carrierName,
+    envelope,
+    format: asset.format,
+    member,
+    path: logicalPath,
+    role,
+    sha256: asset.sha256,
+  };
+}
+
+function validateAssetLocatorList(value, label, carriers) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const assets = value.map((asset, index) =>
+    validateAssetLocator(asset, `${label}[${index}]`, carriers),
+  );
+  const identities = assets.map(
+    ({ carrier, member, path: logicalPath, role }) =>
+      `${role}\0${member}\0${carrier}\0${logicalPath}`,
+  );
+  if (new Set(identities).size !== assets.length) {
+    fail(`${label} repeats an asset locator identity`);
+  }
+  return assets.sort((left, right) =>
+    compareText(
+      `${left.role}\0${left.member}\0${left.carrier}\0${left.path}`,
+      `${right.role}\0${right.member}\0${right.carrier}\0${right.path}`,
+    ),
+  );
+}
+
+function validateRegistration(value, label) {
+  const registration = object(value, label);
+  exactKeys(registration, ['initSymbol', 'magicSymbol', 'symbols'], label);
+  const initSymbol =
+    registration.initSymbol === null
+      ? null
+      : cIdentifier(registration.initSymbol, `${label}.initSymbol`);
+  const magicSymbol = cIdentifier(registration.magicSymbol, `${label}.magicSymbol`);
+  if (!Array.isArray(registration.symbols)) fail(`${label}.symbols must be an array`);
+  const declaredSymbols = registration.symbols.map((raw, index) => {
+    const row = object(raw, `${label}.symbols[${index}]`);
+    exactKeys(row, ['address', 'name'], `${label}.symbols[${index}]`);
+    return {
+      address: cIdentifier(row.address, `${label}.symbols[${index}].address`),
+      name: cIdentifier(row.name, `${label}.symbols[${index}].name`),
+    };
+  });
+  const symbols = [...declaredSymbols].sort((left, right) =>
+    compareText(`${left.name}\0${left.address}`, `${right.name}\0${right.address}`),
+  );
+  if (JSON.stringify(declaredSymbols) !== JSON.stringify(symbols)) {
+    fail(`${label}.symbols must be sorted in ordinal name/address order`);
+  }
+  if (new Set(symbols.map(({ name }) => name)).size !== symbols.length) {
+    fail(`${label}.symbols repeats a SQL symbol`);
+  }
+  return { initSymbol, magicSymbol, symbols };
+}
+
+function validateAssetList(value, label, allowFileUrls) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const assets = value.map((asset, index) =>
+    validateAsset(asset, `${label}[${index}]`, allowFileUrls),
+  );
+  const identities = assets.map(({ role, member }) => `${role}\0${member}`);
+  if (new Set(identities).size !== identities.length) {
+    fail(`${label} repeats an asset role/member identity`);
+  }
+  if (new Set(assets.map(({ name }) => name)).size !== assets.length) {
+    fail(`${label} repeats an asset name`);
+  }
+  return assets.sort((left, right) =>
+    compareText(`${left.role}\0${left.member}`, `${right.role}\0${right.member}`),
+  );
+}
+
+function exactlyOneRole(assets, role, label) {
+  const matches = assets.filter((asset) => asset.role === role);
+  if (matches.length !== 1) fail(`${label} must contain exactly one ${role} asset`);
+  return matches[0];
+}
+
+function noOtherRoles(assets, roles, label) {
+  const extras = assets.filter((asset) => !roles.includes(asset.role));
+  if (extras.length > 0) {
+    fail(
+      `${label} contains unsupported asset role(s): ${[...new Set(extras.map(({ role }) => role))].sort(compareText).join(',')}`,
+    );
+  }
+}
+
+function validateBase(value, label, allowFileUrls) {
+  const base = object(value, label);
+  exactKeys(base, ['assets', 'product', 'tag', 'version'], label);
+  if (base.product !== 'liboliphaunt-native') fail(`${label}.product must be liboliphaunt-native`);
+  const assets = validateAssetList(base.assets, `${label}.assets`, allowFileUrls);
+  noOtherRoles(assets, ['base-xcframework', 'runtime-resources'], `${label}.assets`);
+  const framework = exactlyOneRole(assets, 'base-xcframework', `${label}.assets`);
+  const runtime = exactlyOneRole(assets, 'runtime-resources', `${label}.assets`);
+  const frameworkName = portable(
+    path.posix.basename(framework.member),
+    `${label} base-xcframework member basename`,
+  );
+  if (!frameworkName.endsWith('.xcframework')) {
+    fail(`${label} base-xcframework member must be an XCFramework directory`);
+  }
+  const version = stableVersion(base.version, `${label}.version`);
+  const expectedRuntimeName = `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`;
+  if (runtime.name !== expectedRuntimeName) {
+    fail(`${label} runtime-resources asset must be ${expectedRuntimeName}`);
+  }
+  const expectedTag = `${base.product}-v${version}`;
+  if (base.tag !== expectedTag) fail(`${label}.tag must be ${expectedTag}`);
+  return {
+    assets: { framework, runtime },
+    kind: 'base',
+    product: base.product,
+    tag: base.tag,
+    version,
+  };
+}
+
+function validateExtension(value, label, carriers) {
+  const root = object(value, label);
+  exactKeys(
+    root,
+    [
+      'assets',
+      'createsExtension',
+      'dataFiles',
+      'dependencies',
+      'extensionSqlFileNames',
+      'extensionSqlFilePrefixes',
+      'nativeDependencies',
+      'nativeModuleStem',
+      'product',
+      'registration',
+      'releaseProduct',
+      'sharedPreloadLibraries',
+      'sqlName',
+      'tag',
+      'version',
+    ],
+    label,
+  );
+  const sqlName = portable(root.sqlName, `${label}.sqlName`);
+  const generated = GENERATED_EXTENSION_BY_SQL_NAME.get(sqlName);
+  if (generated === undefined) {
+    fail(`${label}.sqlName is not in the generated React Native extension catalog`);
+  }
+  const artifactProduct = portable(root.product, `${label}.product`);
+  if (artifactProduct !== generated.artifactProduct) {
+    fail(
+      `${label}.product must be canonical artifact product ${generated.artifactProduct} for SQL member ${sqlName}`,
+    );
+  }
+  const releaseProduct = portable(root.releaseProduct, `${label}.releaseProduct`);
+  if (releaseProduct !== generated.releaseProduct) {
+    fail(
+      `${label}.releaseProduct must be canonical owner ${generated.releaseProduct} for SQL member ${sqlName}`,
+    );
+  }
+  const version = stableVersion(root.version, `${label}.version`);
+  const expectedTag = `${releaseProduct}-v${version}`;
+  if (root.tag !== expectedTag) fail(`${label}.tag must be ${expectedTag}`);
+  if (typeof root.createsExtension !== 'boolean') fail(`${label}.createsExtension must be boolean`);
+  const dataFiles = canonicalRelativeFileList(root.dataFiles, `${label}.dataFiles`);
+  const dependencies = canonicalPortableList(root.dependencies, `${label}.dependencies`);
+  if (dependencies.includes(sqlName))
+    fail(`${label}.dependencies must not include ${sqlName} itself`);
+  const extensionSqlFileNames = canonicalSqlFileNameList(
+    root.extensionSqlFileNames,
+    `${label}.extensionSqlFileNames`,
+  );
+  const extensionSqlFilePrefixes = canonicalSqlFilePrefixList(
+    root.extensionSqlFilePrefixes,
+    `${label}.extensionSqlFilePrefixes`,
+  );
+  const nativeDependencies = canonicalPortableList(
+    root.nativeDependencies,
+    `${label}.nativeDependencies`,
+  );
+  const nativeModuleStem =
+    root.nativeModuleStem === null
+      ? null
+      : portable(root.nativeModuleStem, `${label}.nativeModuleStem`);
+  const sharedPreloadLibraries = canonicalPortableList(
+    root.sharedPreloadLibraries,
+    `${label}.sharedPreloadLibraries`,
+  );
+  const assets = validateAssetLocatorList(root.assets, `${label}.assets`, carriers);
+  noOtherRoles(
+    assets,
+    ['dependency-xcframework', 'extension-xcframework', 'runtime-resources'],
+    `${label}.assets`,
+  );
+  const runtime = exactlyOneRole(assets, 'runtime-resources', `${label}.assets`);
+  let extension = null;
+  let dependencyFrameworks = [];
+  let registration = null;
+  if (nativeModuleStem === null) {
+    if (
+      assets.some(({ role }) => role !== 'runtime-resources') ||
+      root.registration !== null ||
+      nativeDependencies.length > 0
+    ) {
+      fail(
+        `${label} SQL-only carrier must not fabricate frameworks, registration, or native dependencies`,
+      );
+    }
+  } else {
+    extension = exactlyOneRole(assets, 'extension-xcframework', `${label}.assets`);
+    const expectedExtension = `liboliphaunt_extension_${nativeModuleStem}.xcframework`;
+    if (path.posix.basename(extension.member) !== expectedExtension) {
+      fail(`${label} extension-xcframework member must end with ${expectedExtension}`);
+    }
+    dependencyFrameworks = assets
+      .filter(({ role }) => role === 'dependency-xcframework')
+      .map((asset) => {
+        const basename = path.posix.basename(asset.member);
+        const match = /^liboliphaunt_dependency_(.+)\.xcframework$/u.exec(basename);
+        if (!match || !PORTABLE_RE.test(match[1])) {
+          fail(`${label} dependency-xcframework member has invalid canonical name ${basename}`);
+        }
+        return { asset, dependency: match[1] };
+      })
+      .sort((left, right) => compareText(left.dependency, right.dependency));
+    if (
+      new Set(dependencyFrameworks.map(({ dependency }) => dependency)).size !==
+      dependencyFrameworks.length
+    ) {
+      fail(`${label} repeats a dependency carrier identity`);
+    }
+    if (
+      JSON.stringify(dependencyFrameworks.map(({ dependency }) => dependency)) !==
+      JSON.stringify(nativeDependencies)
+    ) {
+      fail(`${label} dependency-xcframework roles do not exactly match nativeDependencies`);
+    }
+    if (root.registration === null) fail(`${label} native carrier requires registration metadata`);
+    registration = validateRegistration(root.registration, `${label}.registration`);
+    const prefix = `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`;
+    if (registration.magicSymbol !== `${prefix}_Pg_magic_func`) {
+      fail(`${label}.registration.magicSymbol does not match nativeModuleStem`);
+    }
+    if (![null, `${prefix}__PG_init`].includes(registration.initSymbol)) {
+      fail(`${label}.registration.initSymbol does not match nativeModuleStem`);
+    }
+  }
+  return {
+    assets: { dependencyFrameworks, extension, runtime },
+    createsExtension: root.createsExtension,
+    dataFiles,
+    dependencies,
+    extensionSqlFileNames,
+    extensionSqlFilePrefixes,
+    kind: 'extension',
+    nativeDependencies,
+    nativeModuleStem,
+    product: artifactProduct,
+    releaseProduct,
+    registration,
+    sharedPreloadLibraries,
+    sqlName,
+    tag: root.tag,
+    version,
+    runtimeBound: generated.runtimeBound,
+  };
+}
+
+function validateLegalDocument(value, label, base, extensions) {
+  const legal = object(value, label);
+  exactKeys(legal, ['base', 'extensions'], label);
+  if (!Array.isArray(legal.base)) fail(`${label}.base must be an array`);
+  const baseGroups = legal.base.map((row, index) =>
+    validateLegalGroup(row, `${label}.base[${index}]`),
+  );
+  const expectedBaseRoles = ['base-xcframework', 'runtime-resources'];
+  if (
+    JSON.stringify(baseGroups.map(({ assetRole }) => assetRole)) !==
+    JSON.stringify(expectedBaseRoles)
+  ) {
+    fail(`${label}.base asset roles must be exactly ${expectedBaseRoles.join(',')}`);
+  }
+  const baseAssets = new Map([
+    [base.assets.framework.role, base.assets.framework],
+    [base.assets.runtime.role, base.assets.runtime],
+  ]);
+  for (const group of baseGroups) {
+    if (!baseAssets.has(group.assetRole)) {
+      fail(`${label}.base legal group references missing asset role ${group.assetRole}`);
+    }
+  }
+
+  if (!Array.isArray(legal.extensions)) fail(`${label}.extensions must be an array`);
+  const extensionByName = new Map(extensions.map((extension) => [extension.sqlName, extension]));
+  const extensionGroups = legal.extensions.map((row, index) => {
+    const raw = object(row, `${label}.extensions[${index}]`);
+    const sqlName = portable(raw.sqlName, `${label}.extensions[${index}].sqlName`);
+    const extension = extensionByName.get(sqlName);
+    if (extension === undefined) {
+      fail(`${label}.extensions[${index}] references undeclared extension ${sqlName}`);
+    }
+    const group = validateLegalGroup(raw, `${label}.extensions[${index}]`, { sqlName });
+    if (
+      group.assetRole !== 'runtime-resources' ||
+      extension.assets.runtime.role !== group.assetRole
+    ) {
+      fail(`${label}.extensions[${index}] legal bytes must come from its runtime-resources asset`);
+    }
+    return group;
+  });
+  const expectedNames = [...extensionByName.keys()].sort(compareText);
+  const actualNames = extensionGroups.map(({ sqlName }) => sqlName);
+  if (JSON.stringify(actualNames) !== JSON.stringify(expectedNames)) {
+    fail(`${label}.extensions must exactly cover carrier extensions in ordinal order`);
+  }
+  const legalByName = new Map(extensionGroups.map((group) => [group.sqlName, group]));
+  return {
+    base: baseGroups,
+    extensions: legalByName,
+  };
+}
+
+function assertExactCarrierCoverage(carriers, extensions, label) {
+  const referenced = new Set(
+    extensions.flatMap((extension) =>
+      [
+        extension.assets.runtime,
+        extension.assets.extension,
+        ...extension.assets.dependencyFrameworks.map(({ asset }) => asset),
+      ]
+        .filter(Boolean)
+        .map(({ carrier }) => carrier),
+    ),
+  );
+  const declared = [...carriers.keys()].sort(compareText);
+  const used = [...referenced].sort(compareText);
+  if (JSON.stringify(declared) !== JSON.stringify(used)) {
+    fail(
+      `${label} carrier envelopes must exactly cover referenced logical payloads; ` +
+        `declared=${declared.join(',')}, used=${used.join(',')}`,
+    );
+  }
+}
+
+async function readCarrierDocument(file, allowFileUrls) {
+  let value;
+  try {
+    value = JSON.parse(await fs.readFile(file, 'utf8'));
+  } catch (error) {
+    fail(`could not read carrier ${file}: ${error.message}`);
+  }
+  const root = object(value, file);
+  if (root.schema !== SCHEMA) fail(`${file} schema must be ${SCHEMA}`);
+  exactKeys(root, ['base', 'carriers', 'extensions', 'legal', 'schema'], file);
+  if (!Array.isArray(root.extensions)) fail(`${file}.extensions must be an array`);
+  const base = validateBase(root.base, `${file}.base`, allowFileUrls);
+  const carriers = validateCarrierEnvelopes(root.carriers, `${file}.carriers`, allowFileUrls);
+  const extensions = root.extensions.map((extension, index) =>
+    validateExtension(extension, `${file}.extensions[${index}]`, carriers),
+  );
+  const names = extensions.map(({ sqlName }) => sqlName);
+  if (new Set(names).size !== names.length)
+    fail(`${file}.extensions repeats an exact extension row`);
+  const legal = validateLegalDocument(root.legal, `${file}.legal`, base, extensions);
+  base.legal = legal.base;
+  for (const extension of extensions) extension.legal = legal.extensions.get(extension.sqlName);
+  assertExactCarrierCoverage(carriers, extensions, file);
+  const releases = new Map();
+  for (const extension of extensions) {
+    const prior = releases.get(extension.releaseProduct);
+    const release = { tag: extension.tag, version: extension.version };
+    if (prior !== undefined && JSON.stringify(prior) !== JSON.stringify(release)) {
+      fail(`${file} contains conflicting release versions for owner ${extension.releaseProduct}`);
+    }
+    releases.set(extension.releaseProduct, release);
+    if (extension.runtimeBound && extension.version !== base.version) {
+      fail(
+        `${file} runtime-bound owner ${extension.releaseProduct} version ${extension.version} ` +
+          `must match base runtime ${base.version}`,
+      );
+    }
+  }
+  return { base, carriers, extensions, source: file };
+}
+
+async function sha256File(file) {
+  const hash = createHash('sha256');
+  await pipeline(createReadStream(file), hash);
+  return hash.digest('hex');
+}
+
+async function statOrUndefined(file) {
+  return fs.lstat(file).catch((error) => {
+    if (error?.code === 'ENOENT') return undefined;
+    throw error;
+  });
+}
+
+async function requireCacheDirectory(cacheDir, directory) {
+  const root = path.resolve(cacheDir);
+  const target = path.resolve(directory);
+  const suffix = path.relative(root, target);
+  if (suffix === '..' || suffix.startsWith(`..${path.sep}`)) {
+    fail(`cache directory escapes configured cache root: ${target}`);
+  }
+
+  await fs.mkdir(root, { recursive: true, mode: 0o700 });
+  const rootStat = await statOrUndefined(root);
+  if (rootStat?.isSymbolicLink() || rootStat?.isDirectory() !== true) {
+    fail(`cache root must be a real directory, not a symlink: ${root}`);
+  }
+
+  let current = root;
+  for (const component of suffix.split(path.sep).filter(Boolean)) {
+    current = path.join(current, component);
+    let stat = await statOrUndefined(current);
+    if (stat === undefined) {
+      try {
+        await fs.mkdir(current, { mode: 0o700 });
+      } catch (error) {
+        if (error?.code !== 'EEXIST') throw error;
+      }
+      stat = await statOrUndefined(current);
+    }
+    if (stat?.isSymbolicLink() || stat?.isDirectory() !== true) {
+      fail(`cache path component must be a real directory, not a symlink: ${current}`);
+    }
+  }
+  return target;
+}
+
+async function rejectCacheLeafSymlink(file) {
+  if ((await statOrUndefined(file))?.isSymbolicLink()) {
+    fail(`cache entry must not be a symlink: ${file}`);
+  }
+}
+
+function byteLimitTransform(limit, label) {
+  let bytes = 0;
+  return new Transform({
+    transform(chunk, _encoding, callback) {
+      bytes += chunk.length;
+      if (bytes > limit) {
+        callback(new Error(`${PREFIX}: ${label} exceeds its frozen ${limit}-byte limit`));
+        return;
+      }
+      callback(null, chunk);
+    },
+  });
+}
+
+async function materializeAsset(asset, cacheDir) {
+  const objects = await requireCacheDirectory(cacheDir, path.join(cacheDir, 'objects'));
+  const cached = path.join(objects, `${asset.sha256}-${asset.name}`);
+  await rejectCacheLeafSymlink(cached);
+  if ((await statOrUndefined(cached))?.isFile() === true) {
+    const stat = await fs.stat(cached);
+    if (stat.size === asset.bytes && (await sha256File(cached)) === asset.sha256) return cached;
+  }
+  const temporary = `${cached}.tmp-${process.pid}-${Date.now()}`;
+  const url = new URL(asset.url);
+  try {
+    if (url.protocol === 'file:') {
+      const source = fileURLToPath(url);
+      const sourceStat = await statOrUndefined(source);
+      if (sourceStat?.isFile() !== true || sourceStat.isSymbolicLink()) {
+        fail(`file URL is not a regular non-symlink file: ${asset.url}`);
+      }
+      if (sourceStat.size !== asset.bytes) {
+        fail(`size mismatch for ${asset.name}; expected ${asset.bytes}, got ${sourceStat.size}`);
+      }
+      await fs.copyFile(source, temporary, fsConstants.COPYFILE_EXCL);
+    } else {
+      const response = await fetch(url, { redirect: 'follow' });
+      if (!response.ok || response.body === null) {
+        fail(`download ${asset.url} failed with HTTP ${response.status}`);
+      }
+      if (new URL(response.url).protocol !== 'https:') {
+        fail(`download ${asset.url} redirected outside HTTPS`);
+      }
+      await pipeline(
+        Readable.fromWeb(response.body),
+        byteLimitTransform(asset.bytes, `download ${asset.name}`),
+        createWriteStream(temporary, { flags: 'wx', mode: 0o600 }),
+      );
+    }
+    const actualBytes = (await fs.stat(temporary)).size;
+    if (actualBytes !== asset.bytes) {
+      fail(`size mismatch for ${asset.name}; expected ${asset.bytes}, got ${actualBytes}`);
+    }
+    const actual = await sha256File(temporary);
+    if (actual !== asset.sha256) {
+      fail(`checksum mismatch for ${asset.name}; expected ${asset.sha256}, got ${actual}`);
+    }
+    await fs.rm(cached, { force: true, recursive: true });
+    await fs.rename(temporary, cached).catch(async (error) => {
+      const existing = await statOrUndefined(cached);
+      if (existing?.isFile() !== true || existing.isSymbolicLink()) throw error;
+    });
+    const cachedStat = await statOrUndefined(cached);
+    if (
+      cachedStat?.isFile() !== true ||
+      cachedStat.isSymbolicLink() ||
+      cachedStat.size !== asset.bytes ||
+      (await sha256File(cached)) !== asset.sha256
+    ) {
+      fail(`cached object failed checksum verification after materialization: ${cached}`);
+    }
+    return cached;
+  } finally {
+    await fs.rm(temporary, { force: true });
+  }
+}
+
+async function materializeLogicalPayload(locator, carrierFile, cacheDir) {
+  if (locator.path === '.') return carrierFile;
+  const directory = await requireCacheDirectory(cacheDir, path.join(cacheDir, 'payloads'));
+  const output = path.join(directory, `${locator.sha256}-${path.posix.basename(locator.path)}`);
+  await rejectCacheLeafSymlink(output);
+  const existing = await statOrUndefined(output);
+  if (
+    existing?.isFile() === true &&
+    !existing.isSymbolicLink() &&
+    existing.size === locator.bytes &&
+    (await sha256File(output)) === locator.sha256
+  ) {
+    return output;
+  }
+  const temporaryRoot = path.join(directory, `.tmp-${process.pid}-${Date.now()}-${locator.sha256}`);
+  await fs.rm(temporaryRoot, { force: true, recursive: true });
+  await fs.mkdir(temporaryRoot, { recursive: true, mode: 0o700 });
+  try {
+    await extractPortableTarGzipTree(carrierFile, temporaryRoot, TAR_LIMITS, locator.path);
+    const selected = path.join(temporaryRoot, ...locator.path.split('/'));
+    const selectedStat = await statOrUndefined(selected);
+    if (selectedStat?.isFile() !== true || selectedStat.isSymbolicLink()) {
+      fail(`${locator.envelope.name} nested payload ${locator.path} is not a regular file`);
+    }
+    const actualSha256 = await sha256File(selected);
+    if (selectedStat.size !== locator.bytes || actualSha256 !== locator.sha256) {
+      fail(
+        `${locator.envelope.name} nested payload ${locator.path} does not match ` +
+          `its frozen size/checksum`,
+      );
+    }
+    await fs.rm(output, { force: true, recursive: true });
+    await fs.rename(selected, output);
+    const outputStat = await statOrUndefined(output);
+    if (
+      outputStat?.isFile() !== true ||
+      outputStat.isSymbolicLink() ||
+      outputStat.size !== locator.bytes ||
+      (await sha256File(output)) !== locator.sha256
+    ) {
+      fail(`nested payload cache entry failed verification after materialization: ${output}`);
+    }
+    return output;
+  } finally {
+    await fs.rm(temporaryRoot, { force: true, recursive: true });
+  }
+}
+
+const TAR_LIMITS = {
+  maxArchiveBytes: MAX_CARRIER_BYTES,
+  maxEntries: MAX_ARCHIVE_ENTRIES,
+  maxEntryBytes: MAX_ARCHIVE_MEMBER_BYTES,
+  maxExpandedBytes: MAX_ARCHIVE_EXPANDED_BYTES,
+};
+const ZIP_LIMITS = {
+  format: 'zip',
+  maxArchiveBytes: MAX_ZIP_CARRIER_BYTES,
+  maxEntries: MAX_ARCHIVE_ENTRIES,
+  maxEntryBytes: MAX_ARCHIVE_MEMBER_BYTES,
+  maxExpandedBytes: MAX_ARCHIVE_EXPANDED_BYTES,
+};
+
+function jsonDigest(value) {
+  return createHash('sha256').update(JSON.stringify(value)).digest('hex');
+}
+
+async function extractedTree(root, maxEntries = MAX_ARCHIVE_ENTRIES) {
+  const result = [];
+  const pending = [{ directory: root, relative: '' }];
+  let expandedBytes = 0;
+  while (pending.length > 0) {
+    const { directory, relative } = pending.pop();
+    for (const name of (await fs.readdir(directory)).sort(compareText).reverse()) {
+      const file = path.join(directory, name);
+      const fileRelative = relative ? `${relative}/${name}` : name;
+      safeRelative(fileRelative, `${root} extracted member`);
+      const stat = await fs.lstat(file);
+      if (stat.isSymbolicLink()) fail(`extracted carrier contains symlink: ${file}`);
+      if (stat.isDirectory()) {
+        result.push({ path: fileRelative, type: 'directory' });
+        pending.push({ directory: file, relative: fileRelative });
+      } else if (stat.isFile()) {
+        if (stat.size > MAX_ARCHIVE_MEMBER_BYTES) {
+          fail(
+            `${root} extracted member ${fileRelative} exceeds the maximum supported member size`,
+          );
+        }
+        expandedBytes += stat.size;
+        if (!Number.isSafeInteger(expandedBytes) || expandedBytes > MAX_ARCHIVE_EXPANDED_BYTES) {
+          fail(`${root} extracted tree exceeds the maximum supported expanded size`);
+        }
+        result.push({
+          bytes: stat.size,
+          executable: (stat.mode & 0o111) !== 0,
+          path: fileRelative,
+          sha256: await sha256File(file),
+          type: 'file',
+        });
+      } else {
+        fail(`extracted carrier contains unsupported entry: ${file}`);
+      }
+      if (result.length > maxEntries) {
+        fail(`${root} extracted tree exceeds the maximum supported ${maxEntries} entries`);
+      }
+    }
+  }
+  result.sort((left, right) => compareText(left.path, right.path));
+  return result;
+}
+
+async function extractedCacheValid(
+  root,
+  manifestFile,
+  archiveSha256,
+  maxEntries = MAX_ARCHIVE_ENTRIES,
+) {
+  if (
+    (await statOrUndefined(root))?.isDirectory() !== true ||
+    (await statOrUndefined(manifestFile))?.isFile() !== true
+  )
+    return false;
+  try {
+    const manifest = object(JSON.parse(await fs.readFile(manifestFile, 'utf8')), manifestFile);
+    exactKeys(manifest, ['archiveSha256', 'entries', 'schema', 'treeSha256'], manifestFile);
+    if (
+      manifest.schema !== EXTRACTED_CACHE_SCHEMA ||
+      manifest.archiveSha256 !== archiveSha256 ||
+      !Array.isArray(manifest.entries)
+    )
+      return false;
+    if (manifest.treeSha256 !== jsonDigest(manifest.entries)) return false;
+    const actual = await extractedTree(root, maxEntries);
+    return (
+      manifest.treeSha256 === jsonDigest(actual) &&
+      JSON.stringify(manifest.entries) === JSON.stringify(actual)
+    );
+  } catch {
+    return false;
+  }
+}
+
+async function extractedAsset(asset, archive, cacheDir) {
+  const maxEntries = archiveEntryLimit(asset);
+  const parent = await requireCacheDirectory(cacheDir, path.join(cacheDir, 'extracted'));
+  const root = path.join(parent, asset.sha256);
+  const cacheManifest = `${root}.tree.json`;
+  await rejectCacheLeafSymlink(root);
+  await rejectCacheLeafSymlink(cacheManifest);
+  if (await extractedCacheValid(root, cacheManifest, asset.sha256, maxEntries)) return root;
+  const temporary = path.join(parent, `.${asset.sha256}.tmp-${process.pid}-${Date.now()}`);
+  const temporaryManifest = `${cacheManifest}.tmp-${process.pid}-${Date.now()}`;
+  await fs.rm(temporary, { force: true, recursive: true });
+  await fs.mkdir(temporary, { recursive: true });
+  try {
+    if (asset.format === 'zip') {
+      extractPortableArchiveTree(archive, temporary, '', { ...ZIP_LIMITS, maxEntries });
+    } else {
+      await extractPortableTarGzipTree(archive, temporary, { ...TAR_LIMITS, maxEntries });
+    }
+    const tree = await extractedTree(temporary, maxEntries);
+    if (!tree.some(({ type }) => type === 'file')) fail(`${archive} contains no regular files`);
+    const manifest = {
+      archiveSha256: asset.sha256,
+      entries: tree,
+      schema: EXTRACTED_CACHE_SCHEMA,
+      treeSha256: jsonDigest(tree),
+    };
+    const selected =
+      asset.member === '.' ? temporary : path.join(temporary, ...asset.member.split('/'));
+    if ((await statOrUndefined(selected))?.isDirectory() !== true) {
+      fail(`${asset.name} member is not a directory: ${asset.member}`);
+    }
+    await fs.writeFile(temporaryManifest, `${JSON.stringify(manifest, null, 2)}\n`, { flag: 'wx' });
+    await fs.rm(root, { force: true, recursive: true });
+    await fs.rm(cacheManifest, { force: true });
+    await fs.rename(temporary, root);
+    await fs.rename(temporaryManifest, cacheManifest);
+    const rootStat = await statOrUndefined(root);
+    const manifestStat = await statOrUndefined(cacheManifest);
+    if (
+      rootStat?.isDirectory() !== true ||
+      rootStat.isSymbolicLink() ||
+      manifestStat?.isFile() !== true ||
+      manifestStat.isSymbolicLink() ||
+      !(await extractedCacheValid(root, cacheManifest, asset.sha256, maxEntries))
+    ) {
+      fail(`extracted cache failed verification after materialization: ${root}`);
+    }
+    return root;
+  } catch (error) {
+    await fs.rm(temporary, { force: true, recursive: true });
+    await fs.rm(temporaryManifest, { force: true });
+    throw error;
+  }
+}
+
+async function resolveAssetArchiveRoot(asset, cacheDir) {
+  const archive = await materializeAsset(asset, cacheDir);
+  return extractedAsset(asset, archive, cacheDir);
+}
+
+async function resolveAsset(asset, cacheDir) {
+  const extracted = await resolveAssetArchiveRoot(asset, cacheDir);
+  const member =
+    asset.member === '.' ? extracted : path.join(extracted, ...asset.member.split('/'));
+  const stat = await statOrUndefined(member);
+  if (stat?.isDirectory() !== true)
+    fail(`${asset.name} member is not a directory: ${asset.member}`);
+  return member;
+}
+
+async function resolveLogicalArchiveRoot(locator, cacheDir) {
+  const carrierFile = await materializeAsset(locator.envelope, cacheDir);
+  const archive = await materializeLogicalPayload(locator, carrierFile, cacheDir);
+  const logicalAsset = {
+    ...locator,
+    name: locator.path === '.' ? locator.envelope.name : path.posix.basename(locator.path),
+  };
+  return extractedAsset(logicalAsset, archive, cacheDir);
+}
+
+async function resolveLogicalAsset(locator, cacheDir) {
+  const extracted = await resolveLogicalArchiveRoot(locator, cacheDir);
+  const member =
+    locator.member === '.' ? extracted : path.join(extracted, ...locator.member.split('/'));
+  const stat = await statOrUndefined(member);
+  if (stat?.isDirectory() !== true) {
+    fail(`${locator.envelope.name} logical member is not a directory: ${locator.member}`);
+  }
+  return member;
+}
+
+async function copyTree(source, destination) {
+  const stat = await fs.lstat(source);
+  if (stat.isSymbolicLink()) fail(`refusing to copy carrier symlink: ${source}`);
+  if (stat.isDirectory()) {
+    await fs.mkdir(destination, { recursive: true });
+    const entries = (await fs.readdir(source)).sort(compareText);
+    for (const name of entries) {
+      await copyTree(path.join(source, name), path.join(destination, name));
+    }
+  } else if (stat.isFile()) {
+    await fs.mkdir(path.dirname(destination), { recursive: true });
+    await fs.copyFile(source, destination);
+    await fs.chmod(destination, stat.mode & 0o111 ? 0o755 : 0o644);
+  } else {
+    fail(`unsupported carrier entry: ${source}`);
+  }
+}
+
+async function stripEmbeddedRuntimeClosures(frameworkRoot) {
+  let removed = 0;
+  const visit = async (directory) => {
+    for (const entry of await fs.readdir(directory, { withFileTypes: true })) {
+      const file = path.join(directory, entry.name);
+      if (!entry.isDirectory()) continue;
+      if (entry.name === 'oliphaunt' && path.basename(directory) === 'Resources') {
+        const manifestFile = path.join(file, 'runtime/manifest.properties');
+        const manifest = parseProperties(await fs.readFile(manifestFile, 'utf8'), manifestFile);
+        const target = manifest.get('clusterSeedTarget');
+        if (!new Set(['ios-datum64', 'macos-arm64']).has(target))
+          fail('base framework contains an unsupported runtime target: ' + target);
+        await validateNativeRuntimeClosure(file, { target });
+        await fs.rm(file, { recursive: true });
+        if ((await fs.readdir(directory)).length === 0) await fs.rmdir(directory);
+        removed += 1;
+      } else {
+        await visit(file);
+      }
+    }
+  };
+  await visit(frameworkRoot);
+  if (removed === 0) {
+    fail('base framework does not contain its per-slice runtime resource closure');
+  }
+}
+
+async function mergeTree(source, destination) {
+  const stat = await fs.lstat(source);
+  if (stat.isSymbolicLink()) fail(`refusing to merge carrier symlink: ${source}`);
+  if (stat.isDirectory()) {
+    await fs.mkdir(destination, { recursive: true });
+    for (const name of (await fs.readdir(source)).sort(compareText)) {
+      await mergeTree(path.join(source, name), path.join(destination, name));
+    }
+    return;
+  }
+  if (!stat.isFile()) fail(`unsupported carrier entry: ${source}`);
+  const existing = await statOrUndefined(destination);
+  if (existing !== undefined) {
+    if (!existing.isFile() || (await sha256File(source)) !== (await sha256File(destination))) {
+      fail(`selected carrier resources conflict at ${destination}`);
+    }
+    return;
+  }
+  await fs.mkdir(path.dirname(destination), { recursive: true });
+  await fs.copyFile(source, destination);
+  await fs.chmod(destination, stat.mode & 0o111 ? 0o755 : 0o644);
+}
+
+function legalRelativeMember(group, asset, member) {
+  const prefix = asset.member === '.' ? '' : `${asset.member}/`;
+  if (prefix && member.startsWith(prefix)) return member.slice(prefix.length);
+  return member;
+}
+
+function checkedLegalDestinations(rows) {
+  const exact = new Set();
+  const portable = new Map();
+  for (const row of rows) {
+    const destination = safeRelative(row.destination, 'staged legal destination');
+    if (destination === '.' || exact.has(destination)) {
+      fail(`staged legal destination is repeated or invalid: ${destination}`);
+    }
+    const folded = destination.normalize('NFC').toLowerCase();
+    const prior = portable.get(folded);
+    if (prior !== undefined) {
+      fail(
+        `staged legal destinations collide across case or Unicode normalization: ${prior}, ${destination}`,
+      );
+    }
+    exact.add(destination);
+    portable.set(folded, destination);
+  }
+  for (const destination of exact) {
+    let separator = destination.indexOf('/');
+    while (separator >= 0) {
+      const parent = destination.slice(0, separator);
+      if (exact.has(parent)) {
+        fail(`staged legal file ${parent} is also used as a directory`);
+      }
+      separator = destination.indexOf('/', separator + 1);
+    }
+  }
+}
+
+async function readVerifiedLegalFile(root, row, label) {
+  const rootStat = await fs.lstat(root);
+  if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
+    fail(`${label} archive root must be a real directory`);
+  }
+  const parts = row.member.split('/');
+  let cursor = root;
+  for (const part of parts.slice(0, -1)) {
+    cursor = path.join(cursor, part);
+    const stat = await fs.lstat(cursor).catch((error) => {
+      fail(`${label} legal parent is missing: ${row.member} (${error.message})`);
+    });
+    if (!stat.isDirectory() || stat.isSymbolicLink()) {
+      fail(`${label} legal parent must be a real directory: ${row.member}`);
+    }
+  }
+  const file = path.join(cursor, parts.at(-1));
+  const leaf = await fs.lstat(file).catch((error) => {
+    fail(`${label} legal file is missing: ${row.member} (${error.message})`);
+  });
+  if (!leaf.isFile() || leaf.isSymbolicLink()) {
+    fail(`${label} legal member must be a regular non-symlink file: ${row.member}`);
+  }
+  const handle = await fs.open(file, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
+  try {
+    const opened = await handle.stat();
+    if (!opened.isFile() || opened.size !== row.bytes) {
+      fail(`${label} legal member has the wrong type or byte count: ${row.member}`);
+    }
+    const bytes = await handle.readFile();
+    const digest = createHash('sha256').update(bytes).digest('hex');
+    if (digest !== row.sha256) {
+      fail(`${label} legal member checksum mismatch: ${row.member}`);
+    }
+    return bytes;
+  } finally {
+    await handle.close();
+  }
+}
+
+async function writeSafeLegalFile(root, relative, bytes) {
+  const parts = relative.split('/');
+  let cursor = root;
+  for (const part of parts.slice(0, -1)) {
+    cursor = path.join(cursor, part);
+    await fs.mkdir(cursor, { mode: 0o755 }).catch((error) => {
+      if (error?.code !== 'EEXIST') throw error;
+    });
+    const stat = await fs.lstat(cursor);
+    if (!stat.isDirectory() || stat.isSymbolicLink()) {
+      fail(`staged legal parent must be a real directory: ${cursor}`);
+    }
+    await fs.chmod(cursor, 0o755);
+  }
+  const destination = path.join(root, ...parts);
+  await fs.writeFile(destination, bytes, { flag: 'wx', mode: 0o644 });
+  await fs.chmod(destination, 0o644);
+}
+
+function combinedSpdx(groups) {
+  const terms = [];
+  const seen = new Set();
+  for (const group of groups) {
+    for (const term of group.spdx.split(' AND ')) {
+      if (!seen.has(term)) {
+        seen.add(term);
+        terms.push(term);
+      }
+    }
+  }
+  return terms.join(' AND ');
+}
+
+function renderLegalNotice(spdx, files) {
+  return [
+    '# Oliphaunt app-owned iOS payload legal notices',
+    '',
+    `SPDX-License-Identifier: ${spdx}`,
+    '',
+    'This file indexes the exact legal files materialized from the selected frozen carriers.',
+    '',
+    ...files.map((row) => `- \`${row.destination}\` (${row.kind}; SHA-256 \`${row.sha256}\`)`),
+    '',
+  ].join('\n');
+}
+
+async function stageSelectedLegalFiles({ args, base, selected, temporary }) {
+  const baseAssets = new Map([
+    [base.assets.framework.role, base.assets.framework],
+    [base.assets.runtime.role, base.assets.runtime],
+  ]);
+  const groups = [];
+  for (const group of base.legal) {
+    const asset = baseAssets.get(group.assetRole);
+    if (asset === undefined) fail(`base legal group references missing ${group.assetRole} asset`);
+    groups.push({
+      asset,
+      group,
+      label: `base ${group.assetRole}`,
+      scope: `base/${group.assetRole}`,
+      source: 'base',
+    });
+  }
+  for (const extension of [...selected].sort((left, right) =>
+    compareText(left.sqlName, right.sqlName),
+  )) {
+    groups.push({
+      asset: extension.assets.runtime,
+      group: extension.legal,
+      label: `extension ${extension.sqlName}`,
+      scope: `extensions/${extension.sqlName}`,
+      source: 'extension',
+    });
+  }
+  const planned = groups
+    .flatMap(({ asset, group, label, scope, source }) =>
+      group.files.map((row) => ({
+        ...row,
+        asset,
+        destination: `licenses/${scope}/${legalRelativeMember(group, asset, row.member)}`,
+        label,
+        source,
+      })),
+    )
+    .sort((left, right) => compareText(left.destination, right.destination));
+  checkedLegalDestinations(planned);
+  const legalRoot = path.join(temporary, 'licenses');
+  await fs.mkdir(legalRoot, { recursive: true, mode: 0o755 });
+  await fs.chmod(legalRoot, 0o755);
+  for (const row of planned) {
+    const sourceRoot =
+      row.source === 'base'
+        ? await resolveAssetArchiveRoot(row.asset, args.cacheDir)
+        : await resolveLogicalArchiveRoot(row.asset, args.cacheDir);
+    const bytes = await readVerifiedLegalFile(sourceRoot, row, row.label);
+    await writeSafeLegalFile(temporary, row.destination, bytes);
+  }
+  const spdx = combinedSpdx(groups.map(({ group }) => group));
+  const notice = 'licenses/NOTICE.md';
+  await writeSafeLegalFile(
+    temporary,
+    notice,
+    Buffer.from(renderLegalNotice(spdx, planned), 'utf8'),
+  );
+  return {
+    file: notice,
+    files: planned.map(({ bytes, destination, kind, member, sha256, source }) => ({
+      bytes,
+      destination,
+      kind,
+      member,
+      sha256,
+      source,
+    })),
+    spdx,
+  };
+}
+
+function csv(value, label) {
+  return value ? uniquePortable(value.split(','), label) : [];
+}
+
+function rejectUnsupportedProperties(values, allowed, source) {
+  const extras = [...values.keys()].filter((key) => !allowed.has(key)).sort(compareText);
+  if (extras.length > 0) {
+    fail(`${source} contains unsupported field(s): ${extras.join(', ')}`);
+  }
+}
+
+function requireExactPropertySet(values, expected, source) {
+  const missing = [...expected].filter((key) => !values.has(key)).sort(compareText);
+  if (missing.length > 0) {
+    fail(`${source} is missing canonical field(s): ${missing.join(', ')}`);
+  }
+}
+
+function requireExtensionNativeRuntime(values, base, source) {
+  const product = values.get('nativeRuntimeProduct');
+  if (product === undefined) fail(`${source} is missing nativeRuntimeProduct`);
+  portable(product, `${source} nativeRuntimeProduct`);
+  if (product !== base.product) {
+    fail(`${source} must declare nativeRuntimeProduct=${base.product}; got ${product}`);
+  }
+
+  const rawVersion = values.get('nativeRuntimeVersion');
+  if (rawVersion === undefined) fail(`${source} is missing nativeRuntimeVersion`);
+  const version = stableVersion(rawVersion, `${source} nativeRuntimeVersion`);
+  if (version !== base.version) {
+    fail(`${source} must declare nativeRuntimeVersion=${base.version}; got ${version}`);
+  }
+}
+
+function requireExtensionLinkageMetadata(values, carrier, source) {
+  const stem = carrier.nativeModuleStem;
+  requireProperty(values, 'nativeModuleFile', stem === null ? '' : `${stem}.dylib`, source);
+  requireProperty(
+    values,
+    'staticSymbolPrefix',
+    stem === null ? '' : `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`,
+    source,
+  );
+  const aliases =
+    carrier.registration?.symbols
+      .filter(({ name, address }) => name !== address)
+      .map(({ name, address }) => `${name}:${address}`)
+      .sort(compareText) ?? [];
+  requireProperty(values, 'staticSymbolAliases', aliases.join(','), source);
+}
+
+function propertyRows(values, key, source) {
+  const raw = values.get(key);
+  if (raw === undefined) fail(`${source} is missing ${key}`);
+  if (raw === '') return [];
+  const rows = raw.split(',');
+  if (rows.some((row) => row.length === 0)) fail(`${source} ${key} contains an empty row`);
+  if (new Set(rows).size !== rows.length) fail(`${source} ${key} must not contain duplicates`);
+  return rows;
+}
+
+function mobileStaticArchivePaths(values, carrier, source) {
+  const rows = propertyRows(values, 'mobileStaticArchives', source).map((row, index) => {
+    const fields = row.split(':');
+    if (fields.length !== 2) {
+      fail(`${source} mobileStaticArchives[${index}] must be target:path`);
+    }
+    const target = portable(fields[0], `${source} mobileStaticArchives[${index}] target`);
+    const relative = safeRelative(fields[1], `${source} mobileStaticArchives[${index}] path`);
+    if (relative === '.') fail(`${source} mobileStaticArchives[${index}] must name a file`);
+    return { relative, target };
+  });
+  const expectedTargets = carrier.nativeModuleStem === null ? [] : ['ios-device', 'ios-simulator'];
+  if (JSON.stringify(rows.map(({ target }) => target)) !== JSON.stringify(expectedTargets)) {
+    fail(
+      `${source} mobileStaticArchives targets must be exactly ` +
+        `${expectedTargets.join(',') || ''}`,
+    );
+  }
+  for (const { relative, target } of rows) {
+    const stem = carrier.nativeModuleStem;
+    const expected = `mobile-static/${target}/extensions/${stem}/liboliphaunt_extension_${stem}.a`;
+    if (relative !== expected) {
+      fail(
+        `${source} mobileStaticArchives for ${target} must declare ${expected}; got ${relative}`,
+      );
+    }
+  }
+  return rows.map(({ relative }) => relative);
+}
+
+function mobileStaticDependencyArchivePaths(values, carrier, source) {
+  const rows = propertyRows(values, 'mobileStaticDependencyArchives', source).map((row, index) => {
+    const fields = row.split(':');
+    if (fields.length !== 3) {
+      fail(`${source} mobileStaticDependencyArchives[${index}] must be target:dependency:path`);
+    }
+    const target = portable(fields[0], `${source} mobileStaticDependencyArchives[${index}] target`);
+    const dependency = portable(
+      fields[1],
+      `${source} mobileStaticDependencyArchives[${index}] dependency`,
+    );
+    const relative = safeRelative(
+      fields[2],
+      `${source} mobileStaticDependencyArchives[${index}] path`,
+    );
+    if (relative === '.') {
+      fail(`${source} mobileStaticDependencyArchives[${index}] must name a file`);
+    }
+    const directory = `mobile-static/${target}/dependencies/${dependency}`;
+    const archiveName = path.posix.basename(relative);
+    portableAssetName(archiveName, `${source} mobileStaticDependencyArchives[${index}] file`);
+    if (
+      path.posix.dirname(relative) !== directory ||
+      !/^lib[A-Za-z0-9._-]+\.a$/u.test(archiveName)
+    ) {
+      fail(
+        `${source} mobileStaticDependencyArchives[${index}] must name a portable static archive ` +
+          `lib*.a directly under ${directory}; got ${relative}`,
+      );
+    }
+    return { archiveName, dependency, relative, target };
+  });
+  const targets = carrier.nativeModuleStem === null ? [] : ['ios-device', 'ios-simulator'];
+  const expectedKeys = targets.flatMap((target) =>
+    carrier.nativeDependencies.map((dependency) => `${target}\0${dependency}`),
+  );
+  const actualKeys = rows.map(({ dependency, target }) => `${target}\0${dependency}`);
+  if (JSON.stringify(actualKeys) !== JSON.stringify(expectedKeys)) {
+    fail(
+      `${source} mobileStaticDependencyArchives must exactly cover both iOS static targets ` +
+        `for nativeDependencies=${carrier.nativeDependencies.join(',') || ''}`,
+    );
+  }
+  const archiveNameByDependency = new Map();
+  for (const { archiveName, dependency } of rows) {
+    const prior = archiveNameByDependency.get(dependency);
+    if (prior !== undefined && archiveName !== prior) {
+      fail(
+        `${source} mobileStaticDependencyArchives must use the same archive file name across ` +
+          `both iOS static targets for dependency ${dependency}; got ${prior} and ${archiveName}`,
+      );
+    }
+    archiveNameByDependency.set(dependency, archiveName);
+  }
+  return rows.map(({ relative }) => relative);
+}
+
+async function extensionArtifactEntries(root) {
+  const entries = [];
+  const collisions = new Map();
+  const pending = [{ absolute: root, relative: '' }];
+  while (pending.length > 0) {
+    const { absolute, relative } = pending.pop();
+    for (const name of (await fs.readdir(absolute)).sort(compareText).reverse()) {
+      const file = path.join(absolute, name);
+      const fileRelative = relative ? `${relative}/${name}` : name;
+      safeRelative(fileRelative, `${root} extension artifact entry`);
+      const folded = fileRelative.normalize('NFC').toLocaleLowerCase('en-US');
+      const prior = collisions.get(folded);
+      if (prior !== undefined && prior !== fileRelative) {
+        fail(
+          `${root} extension artifact paths collide across case or Unicode normalization: ${prior}, ${fileRelative}`,
+        );
+      }
+      collisions.set(folded, fileRelative);
+      const stat = await fs.lstat(file);
+      if (stat.isSymbolicLink())
+        fail(`${root} extension artifact contains symlink: ${fileRelative}`);
+      if (stat.isDirectory()) {
+        entries.push({ path: fileRelative, type: 'directory' });
+        pending.push({ absolute: file, relative: fileRelative });
+      } else if (stat.isFile()) {
+        entries.push({ path: fileRelative, type: 'file' });
+      } else {
+        fail(`${root} extension artifact contains a special entry: ${fileRelative}`);
+      }
+    }
+  }
+  return entries.sort((left, right) => compareText(left.path, right.path));
+}
+
+function expectedExtensionArtifactEntries(files, source) {
+  const expected = new Map();
+  for (const file of files) {
+    const relative = safeRelative(file, `${source} expected artifact file`);
+    if (relative === '.') fail(`${source} expected artifact file must not be the root`);
+    const existing = expected.get(relative);
+    if (existing !== undefined && existing !== 'file') {
+      fail(`${source} expected artifact path is both a file and directory: ${relative}`);
+    }
+    expected.set(relative, 'file');
+    let parent = path.posix.dirname(relative);
+    while (parent !== '.') {
+      if (expected.get(parent) === 'file') {
+        fail(`${source} expected artifact file is used as a directory: ${parent}`);
+      }
+      expected.set(parent, 'directory');
+      parent = path.posix.dirname(parent);
+    }
+  }
+  const collisions = new Map();
+  for (const relative of expected.keys()) {
+    const folded = relative.normalize('NFC').toLocaleLowerCase('en-US');
+    const prior = collisions.get(folded);
+    if (prior !== undefined && prior !== relative) {
+      fail(
+        `${source} expected artifact paths collide across case or Unicode normalization: ${prior}, ${relative}`,
+      );
+    }
+    collisions.set(folded, relative);
+  }
+  return expected;
+}
+
+async function validateExactExtensionArtifactInventory(
+  root,
+  carrier,
+  dataFiles,
+  extensionSqlFileNames,
+  extensionSqlFilePrefixes,
+  mobileStaticArchives,
+  mobileStaticDependencyArchives,
+  source,
+) {
+  const actualEntries = await extensionArtifactEntries(root);
+  const actualFiles = new Set(
+    actualEntries.filter(({ type }) => type === 'file').map(({ path: entry }) => entry),
+  );
+  const expectedFiles = new Set(['manifest.properties']);
+  for (const legalFile of carrier.legal.files) expectedFiles.add(legalFile.member);
+  if (carrier.createsExtension) {
+    const extensionRoot = 'files/share/postgresql/extension';
+    const control = `${extensionRoot}/${carrier.sqlName}.control`;
+    if (!actualFiles.has(control)) fail(`${source} is missing canonical control file ${control}`);
+    expectedFiles.add(control);
+    const ownedSqlFiles = [...actualFiles].filter((file) => {
+      if (path.posix.dirname(file) !== extensionRoot) return false;
+      const name = path.posix.basename(file);
+      if (name === `${carrier.sqlName}.sql`) return true;
+      const prefix = `${carrier.sqlName}--`;
+      if (!name.startsWith(prefix) || !name.endsWith('.sql')) return false;
+      const versionPath = name.slice(prefix.length, -'.sql'.length);
+      return /^[A-Za-z0-9][A-Za-z0-9._-]*$/u.test(versionPath);
+    });
+    const installSqlFiles = ownedSqlFiles.filter((file) => {
+      const name = path.posix.basename(file);
+      const prefix = `${carrier.sqlName}--`;
+      if (!name.startsWith(prefix) || !name.endsWith('.sql')) return false;
+      const version = name.slice(prefix.length, -'.sql'.length);
+      return !version.includes('--') && /^[0-9][A-Za-z0-9._-]*$/u.test(version);
+    });
+    if (installSqlFiles.length === 0) {
+      fail(`${source} is missing an install SQL file owned by ${carrier.sqlName}`);
+    }
+    const ancillarySqlFiles = [...actualFiles].filter((file) => {
+      if (path.posix.dirname(file) !== extensionRoot) return false;
+      const name = path.posix.basename(file);
+      return (
+        extensionSqlFileNames.includes(name) ||
+        extensionSqlFilePrefixes.some((prefix) => name.startsWith(prefix) && name.endsWith('.sql'))
+      );
+    });
+    for (const file of [...ownedSqlFiles, ...ancillarySqlFiles]) expectedFiles.add(file);
+  }
+  for (const dataFile of dataFiles) {
+    expectedFiles.add(`files/share/postgresql/${dataFile}`);
+  }
+  if (carrier.nativeModuleStem !== null) {
+    expectedFiles.add(`files/lib/postgresql/${carrier.nativeModuleStem}.dylib`);
+  }
+  for (const file of [...mobileStaticArchives, ...mobileStaticDependencyArchives]) {
+    expectedFiles.add(file);
+  }
+
+  const expected = expectedExtensionArtifactEntries(expectedFiles, source);
+  const actual = new Map(actualEntries.map((entry) => [entry.path, entry.type]));
+  const missing = [...expected]
+    .filter(([entry, type]) => actual.get(entry) !== type)
+    .map(([entry]) => entry);
+  const extra = [...actual]
+    .filter(([entry, type]) => expected.get(entry) !== type)
+    .map(([entry]) => entry);
+  if (missing.length > 0 || extra.length > 0) {
+    fail(
+      `${source} extension artifact inventory must be exact; ` +
+        `missing=${missing.slice(0, 10).join(',') || ''}; ` +
+        `extra=${extra.slice(0, 10).join(',') || ''}`,
+    );
+  }
+}
+
+async function validateBaseResources(root) {
+  const closure = await validateNativeRuntimeClosure(root);
+  const manifest = closure.runtime;
+  const manifestFile = path.join(root, 'runtime', 'manifest.properties');
+  const createable = csv(manifest.get('extensions'), `${manifestFile} extensions`);
+  if (!manifest.has('selectedExtensions')) {
+    fail(`${manifestFile} is missing selectedExtensions`);
+  }
+  const selected = csv(manifest.get('selectedExtensions'), `${manifestFile} selectedExtensions`);
+  if (selected.length > 0 || createable.length > 0) {
+    fail('base React Native iOS carrier is not extension-free');
+  }
+  if (csv(manifest.get('nativeModuleStems'), `${manifestFile} stems`).length > 0) {
+    fail('base React Native iOS carrier contains native extension stems');
+  }
+  requireProperty(manifest, 'mobileStaticRegistryState', 'not-required', manifestFile);
+  return closure;
+}
+
+async function extensionResourceRoot(carrier, base, cacheDir) {
+  const root = await resolveLogicalAsset(carrier.assets.runtime, cacheDir);
+  const manifestFile = path.join(root, 'manifest.properties');
+  const manifest = parseProperties(await fs.readFile(manifestFile, 'utf8'), manifestFile);
+  rejectUnsupportedProperties(manifest, EXTENSION_ARTIFACT_PROPERTY_KEYS, manifestFile);
+  requireProperty(manifest, 'packageLayout', 'oliphaunt-extension-artifact-v1', manifestFile);
+  requireProperty(manifest, 'pgMajor', '18', manifestFile);
+  requireProperty(manifest, 'sqlName', carrier.sqlName, manifestFile);
+  requireProperty(manifest, 'nativeTarget', 'ios-xcframework', manifestFile);
+  requireExtensionNativeRuntime(manifest, base, manifestFile);
+  requireProperty(
+    manifest,
+    'createsExtension',
+    carrier.createsExtension ? 'yes' : 'no',
+    manifestFile,
+  );
+  requireProperty(manifest, 'dependencies', carrier.dependencies.join(','), manifestFile);
+  const extensionSqlFileNames = propertyRows(manifest, 'extensionSqlFileNames', manifestFile).map(
+    (value, index) => {
+      const name = portable(value, `${manifestFile} extensionSqlFileNames[${index}]`);
+      if (!name.endsWith('.sql')) {
+        fail(`${manifestFile} extensionSqlFileNames[${index}] must name a SQL file`);
+      }
+      return name;
+    },
+  );
+  const extensionSqlFilePrefixes = propertyRows(
+    manifest,
+    'extensionSqlFilePrefixes',
+    manifestFile,
+  ).map((value, index) => {
+    if (!/^[A-Za-z0-9_-]{1,128}$/u.test(value)) {
+      fail(
+        `${manifestFile} extensionSqlFilePrefixes[${index}] must be a dot-free ` +
+          'portable SQL basename prefix',
+      );
+    }
+    return value;
+  });
+  if (JSON.stringify(extensionSqlFileNames) !== JSON.stringify(carrier.extensionSqlFileNames)) {
+    fail(
+      `${manifestFile} extensionSqlFileNames must exactly match the frozen carrier contract for ${carrier.sqlName}`,
+    );
+  }
+  if (
+    JSON.stringify(extensionSqlFilePrefixes) !== JSON.stringify(carrier.extensionSqlFilePrefixes)
+  ) {
+    fail(
+      `${manifestFile} extensionSqlFilePrefixes must exactly match the frozen carrier contract for ${carrier.sqlName}`,
+    );
+  }
+  requireProperty(manifest, 'nativeModuleStem', carrier.nativeModuleStem ?? '', manifestFile);
+  requireExtensionLinkageMetadata(manifest, carrier, manifestFile);
+  requireProperty(
+    manifest,
+    'sharedPreloadLibraries',
+    carrier.sharedPreloadLibraries.join(','),
+    manifestFile,
+  );
+  requireProperty(
+    manifest,
+    'mobilePrebuilt',
+    carrier.nativeModuleStem === null ? 'no' : 'yes',
+    manifestFile,
+  );
+  requireProperty(manifest, 'licenseProfile', carrier.legal.profile, manifestFile);
+  const expectedUpstreamLicenses = carrier.legal.files
+    .map(({ member }) => /^files\/(share\/licenses\/.+)$/u.exec(member)?.[1])
+    .filter((member) => member !== undefined)
+    .sort(compareText);
+  requireProperty(manifest, 'licenseFiles', expectedUpstreamLicenses.join(','), manifestFile);
+  requireProperty(manifest, 'files', 'files', manifestFile);
+  const filesRoot = path.join(root, 'files');
+  if ((await statOrUndefined(filesRoot))?.isDirectory() !== true) {
+    fail(`${carrier.sqlName} runtime carrier is missing files`);
+  }
+
+  if (!manifest.has('dataFiles')) fail(`${manifestFile} must declare dataFiles`);
+  const dataFiles =
+    manifest.get('dataFiles') === ''
+      ? []
+      : manifest
+          .get('dataFiles')
+          .split(',')
+          .map((value, index) => {
+            const relative = safeRelative(value, `${manifestFile} dataFiles[${index}]`);
+            if (relative === '.') fail(`${manifestFile} dataFiles[${index}] must name a file`);
+            return relative;
+          });
+  if (new Set(dataFiles).size !== dataFiles.length)
+    fail(`${manifestFile} dataFiles must not contain duplicates`);
+  if (JSON.stringify(dataFiles) !== JSON.stringify(carrier.dataFiles)) {
+    fail(
+      `${manifestFile} dataFiles must exactly match the frozen carrier contract for ${carrier.sqlName}`,
+    );
+  }
+  requireExactPropertySet(manifest, EXTENSION_ARTIFACT_PROPERTY_KEYS, manifestFile);
+  const mobileStaticArchives = mobileStaticArchivePaths(manifest, carrier, manifestFile);
+  const mobileStaticDependencyArchives = mobileStaticDependencyArchivePaths(
+    manifest,
+    carrier,
+    manifestFile,
+  );
+  await validateExactExtensionArtifactInventory(
+    root,
+    carrier,
+    dataFiles,
+    extensionSqlFileNames,
+    extensionSqlFilePrefixes,
+    mobileStaticArchives,
+    mobileStaticDependencyArchives,
+    manifestFile,
+  );
+
+  const share = path.join(filesRoot, 'share', 'postgresql');
+  const shareStat = await statOrUndefined(share);
+  if (shareStat !== undefined && !shareStat.isDirectory()) {
+    fail(`${carrier.sqlName} runtime carrier files/share/postgresql is not a directory`);
+  }
+  if (shareStat === undefined && (carrier.createsExtension || dataFiles.length > 0)) {
+    fail(`${carrier.sqlName} runtime carrier is missing files/share/postgresql`);
+  }
+  return { root, share: shareStat === undefined ? null : share };
+}
+
+function selectedClosure(requested, bySqlName) {
+  const ordered = [];
+  const visiting = new Set();
+  const visited = new Set();
+  function visit(sqlName, requiredBy) {
+    if (visited.has(sqlName)) return;
+    if (visiting.has(sqlName)) fail(`extension dependency cycle includes ${sqlName}`);
+    const carrier = bySqlName.get(sqlName);
+    if (!carrier)
+      fail(`missing iOS carrier for ${sqlName}${requiredBy ? ` required by ${requiredBy}` : ''}`);
+    visiting.add(sqlName);
+    for (const dependency of carrier.dependencies) visit(dependency, sqlName);
+    visiting.delete(sqlName);
+    visited.add(sqlName);
+    ordered.push(carrier);
+  }
+  for (const sqlName of requested) visit(sqlName, undefined);
+  return ordered;
+}
+
+function writeProperties(values) {
+  const preferred = [
+    'schema',
+    'layout',
+    'artifactRole',
+    'catalogProfile',
+    'clusterSeedTarget',
+    'target',
+    'postgresMajor',
+    'physicalFormat',
+    'compatibilityKey',
+    'initialSuperuser',
+    'icuDataVersion',
+    'icuDataForm',
+    'icuDataTreeSha256',
+    'mode',
+    'cacheKey',
+    'selectedExtensions',
+    'extensions',
+    'runtimeFeatures',
+    'sharedPreloadLibraries',
+    'mobileStaticRegistryState',
+    'mobileStaticRegistryRegistered',
+    'mobileStaticRegistryPending',
+    'nativeModuleStems',
+    'mobileStaticRegistrySource',
+  ];
+  const keys = [
+    ...preferred.filter((key) => values.has(key)),
+    ...[...values.keys()].filter((key) => !preferred.includes(key)).sort(compareText),
+  ];
+  return `${keys.map((key) => `${key}=${values.get(key)}`).join('\n')}\n`;
+}
+
+function renderRegistrySource(nativeCarriers) {
+  const declarations = [];
+  const arrays = [];
+  const descriptors = [];
+  for (const carrier of nativeCarriers) {
+    const suffix = carrier.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_');
+    const array = `oliphaunt_${suffix}_symbols`;
+    declarations.push(`extern const void *${carrier.registration.magicSymbol}(void);`);
+    if (carrier.registration.initSymbol)
+      declarations.push(`extern void ${carrier.registration.initSymbol}(void);`);
+    for (const symbol of carrier.registration.symbols)
+      declarations.push(`extern void ${symbol.address}(void);`);
+    if (carrier.registration.symbols.length > 0) {
+      arrays.push(
+        `static const OliphauntStaticExtensionSymbol ${array}[] = {\n` +
+          carrier.registration.symbols
+            .map(
+              ({ name, address }) =>
+                `    { .name = ${JSON.stringify(name)}, .address = (void *)${address} },`,
+            )
+            .join('\n') +
+          `\n};`,
+      );
+    }
+    descriptors.push(
+      `    {\n` +
+        `        .abi_version = OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION,\n` +
+        `        .name = ${JSON.stringify(carrier.nativeModuleStem)},\n` +
+        `        .magic = ${carrier.registration.magicSymbol},\n` +
+        `        .init = ${carrier.registration.initSymbol ?? 'NULL'},\n` +
+        `        .symbols = ${carrier.registration.symbols.length > 0 ? array : 'NULL'},\n` +
+        `        .symbol_count = ${carrier.registration.symbols.length > 0 ? `sizeof(${array}) / sizeof(${array}[0])` : '0'},\n` +
+        `        .reserved_flags = 0,\n` +
+        `    },`,
+    );
+  }
+  return (
+    `/* Generated by ${PREFIX}. Do not edit. */\n` +
+    `#include \n#include "oliphaunt.h"\n\n` +
+    `${[...new Set(declarations)].sort(compareText).join('\n')}\n\n` +
+    `${arrays.join('\n\n')}\n\n` +
+    `static const OliphauntStaticExtension liboliphaunt_static_extensions[] = {\n` +
+    `${descriptors.join('\n')}\n};\n\n` +
+    `const OliphauntStaticExtension *liboliphaunt_selected_static_extensions(size_t *count) {\n` +
+    `    if (count != NULL) *count = sizeof(liboliphaunt_static_extensions) / sizeof(liboliphaunt_static_extensions[0]);\n` +
+    `    return liboliphaunt_static_extensions;\n}\n`
+  );
+}
+
+async function treeSize(root) {
+  if ((await statOrUndefined(root)) === undefined) return { bytes: 0, files: 0 };
+  let bytes = 0;
+  let files = 0;
+  const pending = [root];
+  while (pending.length > 0) {
+    const current = pending.pop();
+    for (const name of await fs.readdir(current)) {
+      const file = path.join(current, name);
+      const stat = await fs.lstat(file);
+      if (stat.isDirectory()) pending.push(file);
+      else if (stat.isFile()) {
+        bytes += stat.size;
+        files += 1;
+      } else fail(`generated payload contains unsupported entry: ${file}`);
+    }
+  }
+  return { bytes, files };
+}
+
+function renderPayloadPodspec(version, hasNative, baseFrameworkName, legal, icu, seedProfile) {
+  const baseFramework = JSON.stringify(`frameworks/base/${baseFrameworkName}`);
+  return (
+    `Pod::Spec.new do |s|\n` +
+    `  s.name = "OliphauntReactNativePayload"\n` +
+    `  s.version = ${JSON.stringify(version)}\n` +
+    `  s.summary = "Generated app-owned Oliphaunt iOS runtime payload."\n` +
+    `  s.license = { :type => ${JSON.stringify(legal.spdx)}, :file => ${JSON.stringify(legal.file)} }\n` +
+    `  s.homepage = "https://oliphaunt.dev"\n` +
+    `  s.authors = { "Oliphaunt" => "opensource@oliphaunt.dev" }\n` +
+    `  s.source = { :git => "https://github.com/f0rr0/oliphaunt.git", :tag => "app-owned-payload" }\n` +
+    `  s.platforms = { :ios => "17.0" }\n` +
+    `  s.resources = "resources/OliphauntReactNativeResources.bundle"\n` +
+    `  s.preserve_paths = "licenses/**/*"\n` +
+    `  s.vendored_frameworks = ${baseFramework}, "frameworks/extensions/**/*.xcframework"\n` +
+    (hasNative
+      ? `  s.source_files = "generated/static-registry/*.c"\n  s.user_target_xcconfig = { "OTHER_LDFLAGS" => "$(inherited) -u _liboliphaunt_selected_static_extensions" }\n`
+      : '') +
+    `  s.dependency "COliphaunt"\n` +
+    (seedProfile
+      ? `  s.dependency "OliphauntSeedNativeIOS${seedProfile === 'icu' ? 'ICU' : 'Standard'}"\n`
+      : '') +
+    (icu ? `  s.dependency "OliphauntICU"\n` : '') +
+    `end\n`
+  );
+}
+
+async function stage(args, base, selected) {
+  const selectionHash = createHash('sha256')
+    .update(JSON.stringify({ base, icu: args.icu, seedProfile: args.seedProfile, selected }))
+    .digest('hex');
+  const outputParent = path.dirname(args.outputDir);
+  const temporary = path.join(
+    outputParent,
+    `.${path.basename(args.outputDir)}.tmp-${process.pid}-${Date.now()}`,
+  );
+  await fs.mkdir(outputParent, { recursive: true });
+  await fs.rm(temporary, { force: true, recursive: true });
+  try {
+    const baseResources = await resolveAsset(base.assets.runtime, args.cacheDir);
+    const baseClosure = await validateBaseResources(baseResources);
+    const baseManifest = baseClosure.runtime;
+    const resourceRoot = path.join(
+      temporary,
+      'resources',
+      'OliphauntReactNativeResources.bundle',
+      'oliphaunt',
+    );
+    await copyTree(baseResources, resourceRoot);
+    const baseFramework = await resolveAsset(base.assets.framework, args.cacheDir);
+    const baseFrameworkName = path.posix.basename(base.assets.framework.member);
+    if (
+      !baseFrameworkName.endsWith('.xcframework') ||
+      path.basename(baseFramework) !== baseFrameworkName
+    ) {
+      fail('base framework carrier member must resolve to its declared .xcframework directory');
+    }
+    const stagedBaseFramework = path.join(temporary, 'frameworks', 'base', baseFrameworkName);
+    await copyTree(baseFramework, stagedBaseFramework);
+    // Swift consumes the per-slice closure embedded by the XCFramework. React
+    // Native publishes one composed app-owned bundle instead, so retaining the
+    // embedded copies would ship the same PostgreSQL runtime twice. Validate
+    // their target manifests before removing only the staged copies.
+    await stripEmbeddedRuntimeClosures(stagedBaseFramework);
+
+    const extensionRows = [];
+    const nativeCarriers = selected.filter(({ nativeModuleStem }) => nativeModuleStem !== null);
+    for (const carrier of selected) {
+      const extensionResources = await extensionResourceRoot(carrier, base, args.cacheDir);
+      if (extensionResources.share !== null) {
+        await mergeTree(
+          extensionResources.share,
+          path.join(resourceRoot, 'runtime', 'files', 'share', 'postgresql'),
+        );
+      }
+      extensionRows.push({
+        ...(extensionResources.share === null
+          ? { bytes: 0, files: 0 }
+          : await treeSize(extensionResources.share)),
+        sqlName: carrier.sqlName,
+      });
+      if (carrier.assets.extension) {
+        const frameworkAssets = [
+          {
+            asset: carrier.assets.extension,
+            expected: `liboliphaunt_extension_${carrier.nativeModuleStem}.xcframework`,
+          },
+          ...carrier.assets.dependencyFrameworks.map(({ asset, dependency }) => ({
+            asset,
+            expected: `liboliphaunt_dependency_${dependency}.xcframework`,
+          })),
+        ];
+        for (const { asset, expected } of frameworkAssets) {
+          const source = await resolveLogicalAsset(asset, args.cacheDir);
+          if (path.basename(source) !== expected) {
+            fail(
+              `${carrier.sqlName} framework asset resolved to ${path.basename(source)}, expected ${expected}`,
+            );
+          }
+          await mergeTree(source, path.join(temporary, 'frameworks', 'extensions', expected));
+        }
+      }
+    }
+
+    const legal = await stageSelectedLegalFiles({
+      args,
+      base,
+      selected,
+      temporary,
+    });
+
+    const selectedExtensions = selected.map(({ sqlName }) => sqlName).sort(compareText);
+    const createExtensions = selected
+      .filter(({ createsExtension }) => createsExtension)
+      .map(({ sqlName }) => sqlName)
+      .sort(compareText);
+    const nativeStems = nativeCarriers
+      .map(({ nativeModuleStem }) => nativeModuleStem)
+      .sort(compareText);
+    const nativeExtensions = nativeCarriers.map(({ sqlName }) => sqlName).sort(compareText);
+    const nativeDependencies = [
+      ...new Set(nativeCarriers.flatMap(({ nativeDependencies }) => nativeDependencies)),
+    ].sort(compareText);
+    const sharedPreload = [
+      ...new Set(selected.flatMap(({ sharedPreloadLibraries }) => sharedPreloadLibraries)),
+    ].sort(compareText);
+    baseManifest.set('cacheKey', `react-native-ios-${selectionHash.slice(0, 32)}`);
+    baseManifest.set('selectedExtensions', selectedExtensions.join(','));
+    baseManifest.set('extensions', createExtensions.join(','));
+    baseManifest.set('sharedPreloadLibraries', sharedPreload.join(','));
+    baseManifest.set(
+      'mobileStaticRegistryState',
+      nativeStems.length > 0 ? 'complete' : 'not-required',
+    );
+    baseManifest.set('mobileStaticRegistryRegistered', nativeExtensions.join(','));
+    baseManifest.set('mobileStaticRegistryPending', '');
+    baseManifest.set('nativeModuleStems', nativeStems.join(','));
+    baseManifest.set(
+      'mobileStaticRegistrySource',
+      nativeStems.length > 0 ? 'static-registry/oliphaunt_static_registry.c' : '',
+    );
+    await fs.writeFile(
+      path.join(resourceRoot, 'runtime', 'manifest.properties'),
+      writeProperties(baseManifest),
+    );
+
+    const registryRoot = path.join(resourceRoot, 'static-registry');
+    await fs.rm(registryRoot, { force: true, recursive: true });
+    await fs.mkdir(registryRoot, { recursive: true });
+    await fs.writeFile(
+      path.join(registryRoot, 'manifest.properties'),
+      [
+        'packageLayout=oliphaunt-static-registry-v1',
+        'abiVersion=1',
+        `state=${nativeStems.length > 0 ? 'complete' : 'not-required'}`,
+        `source=${nativeStems.length > 0 ? 'oliphaunt_static_registry.c' : ''}`,
+        `registeredExtensions=${nativeExtensions.join(',')}`,
+        'pendingExtensions=',
+        `nativeModuleStems=${nativeStems.join(',')}`,
+        `modules=${nativeStems.join(',')}`,
+        `archiveTargets=${nativeStems.length > 0 ? 'ios-device,ios-simulator' : ''}`,
+        `dependencyArchiveTargets=${nativeDependencies.length > 0 ? 'ios-device,ios-simulator' : ''}`,
+        `dependencyArchives=${nativeDependencies.join(',')}`,
+        '',
+      ].join('\n'),
+    );
+    if (nativeCarriers.length > 0) {
+      const generated = path.join(temporary, 'generated', 'static-registry');
+      await fs.mkdir(generated, { recursive: true });
+      await fs.writeFile(
+        path.join(generated, 'oliphaunt_static_registry.c'),
+        renderRegistrySource(nativeCarriers),
+      );
+    }
+
+    const runtimeSize = await treeSize(path.join(resourceRoot, 'runtime', 'files'));
+    const registrySize = await treeSize(registryRoot);
+    const selectedBytes = extensionRows.reduce((total, row) => total + row.bytes, 0);
+    const selectedFiles = extensionRows.reduce((total, row) => total + row.files, 0);
+    const extensionNames = selectedExtensions.length > 0 ? selectedExtensions.join(',') : '-';
+    await fs.writeFile(
+      path.join(resourceRoot, 'package-size.tsv'),
+      [
+        'kind\tid\textensions\tfiles\tbytes',
+        `package\ttotal\t${extensionNames}\t${runtimeSize.files + registrySize.files}\t${runtimeSize.bytes + registrySize.bytes}`,
+        `package\truntime\t${extensionNames}\t${runtimeSize.files}\t${runtimeSize.bytes}`,
+        `package\tstatic-registry\t${extensionNames}\t${registrySize.files}\t${registrySize.bytes}`,
+        `extensions\tselected\t${extensionNames}\t${selectedFiles}\t${selectedBytes}`,
+        ...extensionRows
+          .sort((left, right) => compareText(left.sqlName, right.sqlName))
+          .map((row) => `extension\t${row.sqlName}\t-\t${row.files}\t${row.bytes}`),
+        '',
+      ].join('\n'),
+    );
+
+    const frozen = {
+      base: { product: base.product, version: base.version, assets: base.assets },
+      cacheKey: `react-native-ios-${selectionHash.slice(0, 32)}`,
+      extensions: selected.map((carrier) => ({
+        assets: carrier.assets,
+        createsExtension: carrier.createsExtension,
+        dependencies: carrier.dependencies,
+        nativeDependencies: carrier.nativeDependencies,
+        nativeModuleStem: carrier.nativeModuleStem,
+        product: carrier.product,
+        releaseProduct: carrier.releaseProduct,
+        sqlName: carrier.sqlName,
+        version: carrier.version,
+      })),
+      requestedExtensions: args.extensions,
+      icu: args.icu,
+      seedProfile: args.seedProfile,
+      legal,
+      schema: OUTPUT_SCHEMA,
+    };
+    await fs.writeFile(
+      path.join(temporary, 'selection.json'),
+      `${JSON.stringify(frozen, null, 2)}\n`,
+    );
+    await fs.writeFile(
+      path.join(temporary, 'OliphauntReactNativePayload.podspec'),
+      renderPayloadPodspec(
+        base.version,
+        nativeCarriers.length > 0,
+        baseFrameworkName,
+        legal,
+        args.icu,
+        args.seedProfile,
+      ),
+    );
+    await fs.rm(args.outputDir, { force: true, recursive: true });
+    await fs.rename(temporary, args.outputDir);
+  } catch (error) {
+    await fs.rm(temporary, { force: true, recursive: true });
+    throw error;
+  }
+}
+
+export async function stageIosApp(options) {
+  const carriers = options.carriers ?? [
+    ...(options.baseCarrier ? [options.baseCarrier] : []),
+    ...(options.extensionCarriers ?? []),
+  ];
+  const args = {
+    allowFileUrls: options.allowFileUrls === true,
+    carriers: carriers.map((file) => path.resolve(file)),
+    cacheDir: path.resolve(
+      options.cacheDir ?? path.join(os.homedir(), '.cache', 'oliphaunt', 'react-native-ios'),
+    ),
+    extensions: uniquePortable(options.extensions ?? [], 'selected extension'),
+    icu: options.icu === true || options.seedProfile === 'icu',
+    seedProfile: options.seedProfile ?? null,
+    outputDir: path.resolve(options.outputDir),
+  };
+  if (args.carriers.length === 0) fail('at least one carrier manifest is required');
+  if (args.seedProfile !== null && !['standard', 'icu'].includes(args.seedProfile))
+    fail('seed profile must be standard or icu');
+  if (args.seedProfile === 'standard' && args.icu)
+    fail('standard seed cannot be selected with ICU data');
+  let base;
+  const bySqlName = new Map();
+  const carriersByName = new Map();
+  const releasesByOwner = new Map();
+  for (const file of args.carriers) {
+    const document = await readCarrierDocument(file, args.allowFileUrls);
+    if (base === undefined) {
+      base = document.base;
+    } else if (JSON.stringify(base) !== JSON.stringify(document.base)) {
+      fail(`${file} pins a different base carrier than the other selected manifests`);
+    }
+    for (const [name, envelope] of document.carriers) {
+      const existing = carriersByName.get(name);
+      if (existing !== undefined && JSON.stringify(existing) !== JSON.stringify(envelope)) {
+        fail(`carrier manifests disagree about envelope ${name}`);
+      }
+      carriersByName.set(name, envelope);
+    }
+    for (const carrier of document.extensions) {
+      const release = { tag: carrier.tag, version: carrier.version };
+      const existingRelease = releasesByOwner.get(carrier.releaseProduct);
+      if (
+        existingRelease !== undefined &&
+        JSON.stringify(existingRelease) !== JSON.stringify(release)
+      ) {
+        fail(
+          `carrier manifests disagree about release version for owner ${carrier.releaseProduct}`,
+        );
+      }
+      releasesByOwner.set(carrier.releaseProduct, release);
+      const existing = bySqlName.get(carrier.sqlName);
+      if (existing && JSON.stringify(existing) !== JSON.stringify(carrier)) {
+        fail(`carrier manifests disagree for exact extension ${carrier.sqlName}`);
+      }
+      bySqlName.set(carrier.sqlName, carrier);
+    }
+  }
+  for (const carrier of bySqlName.values()) {
+    if (carrier.runtimeBound && carrier.version !== base.version) {
+      fail(
+        `runtime-bound owner ${carrier.releaseProduct} version ${carrier.version} ` +
+          `must match base runtime ${base.version}`,
+      );
+    }
+  }
+  const selected = selectedClosure(args.extensions, bySqlName);
+  await stage(args, base, selected);
+  return { outputDir: args.outputDir, selected: selected.map(({ sqlName }) => sqlName) };
+}
+
+async function main() {
+  const args = parseArgs(process.argv.slice(2));
+  const result = await stageIosApp(args);
+  console.log(
+    `${PREFIX}: staged ${result.outputDir} (extensions=${result.selected.join(',') || 'none'})`,
+  );
+}
+
+if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
+  main().catch((error) => {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(1);
+  });
+}
diff --git a/src/sdks/react-native/tools/stage-ios-app.test.mjs b/src/sdks/react-native/tools/stage-ios-app.test.mjs
deleted file mode 100755
index e84ba25fd..000000000
--- a/src/sdks/react-native/tools/stage-ios-app.test.mjs
+++ /dev/null
@@ -1,2429 +0,0 @@
-#!/usr/bin/env node
-
-import assert from "node:assert/strict";
-import { createHash } from "node:crypto";
-import fs from "node:fs/promises";
-import os from "node:os";
-import path from "node:path";
-import { fileURLToPath, pathToFileURL } from "node:url";
-import { spawnSync } from "node:child_process";
-import { gunzipSync, gzipSync } from "node:zlib";
-import { stageIosApp } from "./stage-ios-app.mjs";
-import {
-  parseProperties,
-  validateNativeRuntimeClosure,
-} from "./native-resource-closure.mjs";
-
-const SCHEMA = "oliphaunt-react-native-ios-carrier-v1";
-assert.throws(
-  () => parseProperties("schema=one\nschema=two\n", "duplicate.properties"),
-  /repeats schema/u,
-);
-const GENERATED_EXTENSION_CATALOG = JSON.parse(
-  await fs.readFile(
-    await Promise.any([
-      new URL("../src/generated/extensions.json", import.meta.url),
-      new URL("../../../extensions/generated/sdk/extensions.json", import.meta.url),
-    ].map(async (url) => {
-      await fs.access(url);
-      return url;
-    })),
-    "utf8",
-  ),
-);
-const GENERATED_EXTENSION_BY_SQL_NAME = new Map(
-  GENERATED_EXTENSION_CATALOG.extensions.map((row) => [row["sql-name"], row]),
-);
-const GENERATED_IOS_DEPENDENCIES_BY_SQL_NAME = new Map(JSON.parse(
-  await fs.readFile(
-    await Promise.any([
-      new URL("../src/generated/ios-static-dependencies.json", import.meta.url),
-      new URL("../../../extensions/generated/sdk/ios-static-dependencies.json", import.meta.url),
-    ].map(async (url) => {
-      await fs.access(url);
-      return url;
-    })),
-    "utf8",
-  ),
-).extensions.map((row) => [row["sql-name"], row["static-dependencies"]]));
-const SHARED_NATIVE_SEED_FIXTURES = Object.freeze({
-  standard: await fs.readFile(
-    new URL("../../../shared/cluster-seed-contract/fixtures/native-standard.valid.properties", import.meta.url),
-    "utf8",
-  ),
-  icu: await fs.readFile(
-    new URL("../../../shared/cluster-seed-contract/fixtures/native-icu.valid.properties", import.meta.url),
-    "utf8",
-  ),
-});
-const SHARED_NATIVE_INVALID_CACHE_FIXTURES = await Promise.all([
-  "native-whitespace.invalid.properties",
-  "native-cache-key.invalid.properties",
-  "native-dot-cache-key.invalid.properties",
-  "native-dotdot-cache-key.invalid.properties",
-].map((name) => fs.readFile(
-  new URL(`../../../shared/cluster-seed-contract/fixtures/${name}`, import.meta.url),
-  "utf8",
-)));
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function run(command, args, cwd) {
-  const result = spawnSync(command, args, { cwd, encoding: "utf8" });
-  assert.equal(
-    result.status,
-    0,
-    `${command} ${args.join(" ")} failed:\n${result.stderr || result.stdout}`,
-  );
-}
-
-function runFailure(command, args, pattern, cwd) {
-  const result = spawnSync(command, args, { cwd, encoding: "utf8" });
-  assert.notEqual(result.status, 0, `${command} ${args.join(" ")} unexpectedly succeeded`);
-  assert.match(
-    `${result.stderr}\n${result.stdout}`,
-    pattern,
-    `${command} ${args.join(" ")} failed without the expected diagnostic`,
-  );
-}
-
-async function write(file, contents) {
-  await fs.mkdir(path.dirname(file), { recursive: true });
-  await fs.writeFile(file, contents);
-}
-
-function retargetNativeSeedFixture(source, target, icuDataTreeSha256) {
-  const overrides = new Map([
-    ["target", target],
-    ["compatibilityKey", `native-pg18-${target}-v1`],
-  ]);
-  if (icuDataTreeSha256 !== undefined) overrides.set("icuDataTreeSha256", icuDataTreeSha256);
-  return source.split("\n").map((line) => {
-    const separator = line.indexOf("=");
-    const key = separator < 0 ? line : line.slice(0, separator);
-    return overrides.has(key) ? `${key}=${overrides.get(key)}` : line;
-  }).join("\n");
-}
-
-function nativeSeedFixture(profile, target, icuDataTreeSha256 = "") {
-  return retargetNativeSeedFixture(
-    SHARED_NATIVE_SEED_FIXTURES[profile],
-    target,
-    profile === "icu" ? icuDataTreeSha256 : undefined,
-  );
-}
-
-async function sha256(file) {
-  return createHash("sha256").update(await fs.readFile(file)).digest("hex");
-}
-
-async function asset(role, file, format, member) {
-  const stat = await fs.stat(file);
-  return {
-    bytes: stat.size,
-    format,
-    member,
-    name: path.basename(file),
-    role,
-    sha256: await sha256(file),
-    url: pathToFileURL(file).href,
-  };
-}
-
-async function logicalAsset(role, file, format, member) {
-  const direct = await asset(role, file, format, member);
-  return {
-    envelope: {
-      bytes: direct.bytes,
-      format: direct.format,
-      name: direct.name,
-      sha256: direct.sha256,
-      url: direct.url,
-    },
-    locator: {
-      bytes: direct.bytes,
-      carrier: direct.name,
-      format: direct.format,
-      member: direct.member,
-      path: ".",
-      role: direct.role,
-      sha256: direct.sha256,
-    },
-  };
-}
-
-function retainReferencedCarriers(document) {
-  const referenced = new Set(
-    document.extensions.flatMap((extension) => extension.assets.map(({ carrier }) => carrier)),
-  );
-  document.carriers = document.carriers.filter(({ name }) => referenced.has(name));
-  if (document.legal?.extensions) {
-    const selected = new Set(document.extensions.map(({ sqlName }) => sqlName));
-    document.legal.extensions = document.legal.extensions.filter(({ sqlName }) => selected.has(sqlName));
-  }
-  return document;
-}
-
-function replaceExtensionAssets(document, sqlName, replacements) {
-  const row = document.extensions.find((candidate) => candidate.sqlName === sqlName);
-  assert.ok(row, `missing fixture extension ${sqlName}`);
-  const priorNames = new Set(row.assets.map(({ carrier }) => carrier));
-  row.assets = replacements.map(({ locator }) => locator);
-  document.carriers = [
-    ...document.carriers.filter(({ name }) => !priorNames.has(name)),
-    ...replacements.map(({ envelope }) => envelope),
-  ];
-  retainReferencedCarriers(document);
-}
-
-function replaceExtensionRuntimeAsset(document, sqlName, replacement) {
-  const row = document.extensions.find((candidate) => candidate.sqlName === sqlName);
-  assert.ok(row, `missing fixture extension ${sqlName}`);
-  const prior = row.assets.find(({ role }) => role === "runtime-resources");
-  assert.ok(prior, `missing runtime fixture asset for ${sqlName}`);
-  row.assets = row.assets.map((assetRow) =>
-    assetRow === prior ? replacement.locator : assetRow);
-  document.carriers = [
-    ...document.carriers.filter(({ name }) => name !== prior.carrier),
-    replacement.envelope,
-  ];
-  retainReferencedCarriers(document);
-}
-
-async function tarDirectory(source, archive, member = ".") {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  run("tar", ["--no-xattrs", "-czf", archive, "-C", source, member]);
-}
-
-async function tarMembers(source, archive, members) {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  run("tar", ["--no-xattrs", "-czf", archive, "-C", source, ...members]);
-}
-
-async function legalFile(root, member, kind, contents = undefined) {
-  const file = path.join(root, ...member.split("/"));
-  await write(file, contents ?? `${member} fixture legal text\n`);
-  const stat = await fs.stat(file);
-  return {
-    bytes: stat.size,
-    kind,
-    member,
-    sha256: await sha256(file),
-  };
-}
-
-async function legalGroup(root, { assetRole, files, profile, spdx }) {
-  const rows = await Promise.all(files.map(({ kind, member, contents }) =>
-    legalFile(root, member, kind, contents)));
-  rows.sort((left, right) => compareText(left.member, right.member));
-  return { assetRole, files: rows, profile, spdx };
-}
-
-async function removeTarDirectorySlash(archive, member) {
-  const tar = gunzipSync(await fs.readFile(archive));
-  let found = false;
-  for (let offset = 0; offset + 512 <= tar.length;) {
-    const header = tar.subarray(offset, offset + 512);
-    if (header.every((value) => value === 0)) break;
-    const field = (start, length) => {
-      const bytes = header.subarray(start, start + length);
-      const end = bytes.indexOf(0);
-      return bytes.subarray(0, end < 0 ? bytes.length : end).toString("utf8");
-    };
-    const name = field(0, 100);
-    const prefix = field(345, 155);
-    const fullName = prefix ? `${prefix}/${name}` : name;
-    const size = Number.parseInt(field(124, 12).trim() || "0", 8);
-    assert.ok(Number.isSafeInteger(size) && size >= 0, `invalid tar size for ${fullName}`);
-    if (fullName === member) {
-      assert.equal(String.fromCharCode(header[156]), "5", `${member} must be a directory header`);
-      assert.equal(prefix, "", `${member} test helper only supports the ustar name field`);
-      assert.ok(name.endsWith("/"), `${member} must initially use a canonical directory marker`);
-      header[name.length - 1] = 0;
-      header.fill(0x20, 148, 156);
-      const checksum = header.reduce((total, value) => total + value, 0);
-      Buffer.from(`${checksum.toString(8).padStart(6, "0")}\0 `, "ascii").copy(header, 148);
-      found = true;
-    }
-    offset += 512 + Math.ceil(size / 512) * 512;
-  }
-  assert.equal(found, true, `missing tar directory ${member}`);
-  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
-}
-
-async function addTarFileSlash(archive, member) {
-  const tar = gunzipSync(await fs.readFile(archive));
-  let found = false;
-  for (let offset = 0; offset + 512 <= tar.length;) {
-    const header = tar.subarray(offset, offset + 512);
-    if (header.every((value) => value === 0)) break;
-    const end = header.subarray(0, 100).indexOf(0);
-    const name = header.subarray(0, end < 0 ? 100 : end).toString("utf8");
-    const sizeEnd = header.subarray(124, 136).indexOf(0);
-    const size = Number.parseInt(
-      header.subarray(124, sizeEnd < 0 ? 136 : 124 + sizeEnd).toString("utf8").trim() || "0",
-      8,
-    );
-    if (name === member) {
-      assert.equal(String.fromCharCode(header[156]), "0", `${member} must be a regular file header`);
-      assert.ok(member.length < 99, `${member} must leave room for a slash`);
-      header[member.length] = "/".charCodeAt(0);
-      header[member.length + 1] = 0;
-      header.fill(0x20, 148, 156);
-      const checksum = header.reduce((total, value) => total + value, 0);
-      Buffer.from(`${checksum.toString(8).padStart(6, "0")}\0 `, "ascii").copy(header, 148);
-      found = true;
-    }
-    offset += 512 + Math.ceil(size / 512) * 512;
-  }
-  assert.equal(found, true, `missing tar file ${member}`);
-  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
-}
-
-async function zipMember(sourceParent, member, archive) {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  run("zip", ["-qry", archive, member], sourceParent);
-}
-
-async function maliciousZip(archive, entry, kind) {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  const script = [
-    "import stat, sys, zipfile",
-    "archive, entry, kind = sys.argv[1:]",
-    "info = zipfile.ZipInfo(entry)",
-    "info.create_system = 3",
-    "info.external_attr = ((stat.S_IFLNK | 0o777) if kind == 'symlink' else (stat.S_IFREG | 0o644)) << 16",
-    "with zipfile.ZipFile(archive, 'w') as output: output.writestr(info, '../outside' if kind == 'symlink' else 'malicious')",
-  ].join("\n");
-  run("python3", ["-c", script, archive, entry, kind]);
-}
-
-async function appendZipFiles(archive, prefix, count) {
-  const script = [
-    "import stat, sys, zipfile",
-    "archive, prefix, count = sys.argv[1], sys.argv[2], int(sys.argv[3])",
-    "with zipfile.ZipFile(archive, 'a') as output:",
-    "  directory = zipfile.ZipInfo(prefix + '/')",
-    "  directory.create_system = 3",
-    "  directory.external_attr = ((stat.S_IFDIR | 0o755) << 16) | 0x10",
-    "  output.writestr(directory, b'')",
-    "  for index in range(count):",
-    "    info = zipfile.ZipInfo(f'{prefix}/file-{index:04d}')",
-    "    info.create_system = 3",
-    "    info.external_attr = ((stat.S_IFREG | 0o644) << 16) | 0x20",
-    "    output.writestr(info, b'')",
-  ].join("\n");
-  run("python3", ["-c", script, archive, prefix, String(count)]);
-}
-
-async function metadataZip(archive, creator, legalRoot = "") {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  const script = [
-    "import os, sys, zipfile",
-    "archive, creator, legal_root = sys.argv[1:]",
-    "host = 0 if creator == 'fat' else 3",
-    "ambiguous = creator == 'ambiguous-unix'",
-    "root = zipfile.ZipInfo('liboliphaunt.xcframework/')",
-    "root.create_system = host",
-    "root.external_attr = (((0o755 if ambiguous else 0o40755) << 16) | 0x10) if host == 3 else 0x10",
-    "payload = zipfile.ZipInfo('liboliphaunt.xcframework/Info.plist')",
-    "payload.create_system = host",
-    "payload.external_attr = (((0o644 if ambiguous else 0o100644) << 16) | 0x20) if host == 3 else 0x20",
-    "if creator == 'unicode-extra': payload.extra = b'\\x75\\x70\\x05\\x00\\x01\\x00\\x00\\x00\\x00'",
-    "with zipfile.ZipFile(archive, 'w') as output:",
-    "  output.writestr(root, b'')",
-    "  output.writestr(payload, b'\\n')",
-    "  if legal_root:",
-    "    legal_files = []",
-    "    for directory, _, names in os.walk(legal_root):",
-    "      for leaf in sorted(names):",
-    "        source = os.path.join(directory, leaf)",
-    "        relative = os.path.relpath(source, legal_root).replace(os.sep, '/')",
-    "        if relative == 'Info.plist': continue",
-    "        legal_files.append((relative, source))",
-    "    parents = set()",
-    "    for relative, _ in legal_files:",
-    "      parts = relative.split('/')[:-1]",
-    "      for index in range(1, len(parts) + 1): parents.add('/'.join(parts[:index]))",
-    "    parents = sorted(parents)",
-    "    for parent in parents:",
-    "      info = zipfile.ZipInfo('liboliphaunt.xcframework/' + parent + '/')",
-    "      info.create_system = host",
-    "      info.external_attr = ((0o40755 << 16) | 0x10) if host == 3 else 0x10",
-    "      output.writestr(info, b'')",
-    "    for relative, source in legal_files:",
-    "        info = zipfile.ZipInfo('liboliphaunt.xcframework/' + relative)",
-    "        info.create_system = host",
-    "        info.external_attr = ((0o100644 << 16) | 0x20) if host == 3 else 0x20",
-    "        output.writestr(info, open(source, 'rb').read())",
-  ].join("\n");
-  run("python3", ["-c", script, archive, creator, legalRoot]);
-}
-
-async function addUnsupportedZipFlag(archive) {
-  const buffer = await fs.readFile(archive);
-  const eocd = buffer.length - 22;
-  assert.equal(buffer.readUInt32LE(eocd), 0x06054b50);
-  const centralOffset = buffer.readUInt32LE(eocd + 16);
-  assert.equal(buffer.readUInt32LE(centralOffset), 0x02014b50);
-  const localOffset = buffer.readUInt32LE(centralOffset + 42);
-  assert.equal(buffer.readUInt32LE(localOffset), 0x04034b50);
-  buffer.writeUInt16LE(buffer.readUInt16LE(centralOffset + 8) | 0x20, centralOffset + 8);
-  buffer.writeUInt16LE(buffer.readUInt16LE(localOffset + 6) | 0x20, localOffset + 6);
-  await fs.writeFile(archive, buffer);
-}
-
-async function craftedTar(archive, entries) {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  const script = [
-    "import io, json, sys, tarfile",
-    "archive, encoded = sys.argv[1:]",
-    "with tarfile.open(archive, 'w:gz', format=tarfile.USTAR_FORMAT) as output:",
-    "  for row in json.loads(encoded):",
-    "    info = tarfile.TarInfo(row['name'])",
-    "    info.mode = 0o755 if row['type'] == 'directory' else 0o644",
-    "    if row['type'] == 'directory': info.type = tarfile.DIRTYPE; output.addfile(info)",
-    "    elif row['type'] == 'symlink': info.type = tarfile.SYMTYPE; info.linkname = 'target'; output.addfile(info)",
-    "    else: data = b'fixture'; info.size = len(data); output.addfile(info, io.BytesIO(data))",
-  ].join("\n");
-  run("python3", ["-c", script, archive, JSON.stringify(entries)]);
-}
-
-async function highCardinalityIcuTar(archive, localeCount, legalRoot) {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  const script = [
-    "import hashlib, io, os, sys, tarfile",
-    "archive, encoded_count, legal_root = sys.argv[1:]",
-    "rows = [('share/icu/icudt77l.dat', b'fixture')] + [(f'share/icu/locale-{index:04d}.res', b'fixture') for index in range(int(encoded_count))]",
-    "digest = hashlib.sha256()",
-    "for name, data in rows:",
-    "  relative = name.removeprefix('share/icu/')",
-    "  digest.update(relative.encode()); digest.update(b'\\0'); digest.update(str(len(data)).encode()); digest.update(b'\\0'); digest.update(data); digest.update(b'\\n')",
-    "manifest = ('schema=oliphaunt-icu-data-v1\\nartifactRole=icu-data\\nicuDataVersion=76.1\\nicuDataForm=files-le\\nicuDataTreeSha256=' + digest.hexdigest() + '\\n').encode()",
-    "rows += [('manifest.properties', manifest)]",
-    "with tarfile.open(archive, 'w:gz', format=tarfile.USTAR_FORMAT) as output:",
-    "  for name, data in rows:",
-    "    info = tarfile.TarInfo(name)",
-    "    info.mode = 0o644",
-    "    info.size = len(data)",
-    "    output.addfile(info, io.BytesIO(data))",
-    "  for directory, _, names in os.walk(legal_root):",
-    "    for leaf in sorted(names):",
-    "      source = os.path.join(directory, leaf)",
-    "      name = os.path.relpath(source, legal_root).replace(os.sep, '/')",
-    "      if name == 'manifest.properties' or name.startswith('share/icu/'): continue",
-    "      data = open(source, 'rb').read()",
-    "      info = tarfile.TarInfo(name)",
-    "      info.mode = 0o644",
-    "      info.size = len(data)",
-    "      output.addfile(info, io.BytesIO(data))",
-  ].join("\n");
-  run("python3", ["-c", script, archive, String(localeCount), legalRoot]);
-}
-
-async function rewriteFirstTarSize(archive, size) {
-  const tar = gunzipSync(await fs.readFile(archive));
-  const header = tar.subarray(0, 512);
-  const octal = size.toString(8);
-  assert.ok(octal.length <= 11, "forged tar size must fit the ustar size field");
-  header.fill(0, 124, 136);
-  Buffer.from(`${octal.padStart(11, "0")}\0`, "ascii").copy(header, 124);
-  header.fill(0x20, 148, 156);
-  const checksum = header.reduce((total, value) => total + value, 0);
-  Buffer.from(`${checksum.toString(8).padStart(6, "0")}\0 `, "ascii").copy(header, 148);
-  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
-}
-
-async function baseAssets(root) {
-  const source = path.join(root, "source", "base");
-  const runtime = path.join(source, "runtime", "oliphaunt");
-  await write(
-    path.join(runtime, "manifest.properties"),
-    [
-      "schema=oliphaunt-native-runtime-carrier-v1",
-      "clusterSeedTarget=ios-datum64",
-      "clusterSeedRelativePath=cluster-seed",
-      "icuClusterSeedRelativePath=cluster-seed-icu",
-      "",
-    ].join("\n"),
-  );
-  await write(
-    path.join(runtime, "runtime", "manifest.properties"),
-    [
-      "schema=oliphaunt-runtime-resources-v1",
-      "cacheKey=fixture-base",
-      "layout=postgres-runtime-files-v1",
-      "artifactRole=runtime",
-      "catalogProfile=",
-      "clusterSeedTarget=ios-datum64",
-      "icuDataTreeSha256=",
-      "mode=native-direct",
-      "selectedExtensions=",
-      "extensions=",
-      "runtimeFeatures=",
-      "sharedPreloadLibraries=",
-      "mobileStaticRegistryState=not-required",
-      "mobileStaticRegistryRegistered=",
-      "mobileStaticRegistryPending=",
-      "nativeModuleStems=",
-      "mobileStaticRegistrySource=",
-      "",
-    ].join("\n"),
-  );
-  await write(
-    path.join(runtime, "cluster-seed", "manifest.properties"),
-    nativeSeedFixture("standard", "ios-datum64"),
-  );
-  await write(path.join(runtime, "runtime", "files", "share", "postgresql", "postgres.bki"), "base\n");
-  await write(path.join(runtime, "cluster-seed", "files", "PG_VERSION"), "18\n");
-  await write(path.join(runtime, "cluster-seed", "files", "global", "pg_control"), "control\n");
-  await write(
-    path.join(runtime, "package-size.tsv"),
-    "kind\tid\textensions\tfiles\tbytes\npackage\ttotal\t-\t2\t8\n",
-  );
-
-  const baseFramework = path.join(source, "framework", "liboliphaunt.xcframework");
-  await write(path.join(baseFramework, "Info.plist"), "\n");
-  await write(
-    path.join(baseFramework, "ios-arm64", "liboliphaunt.framework", "liboliphaunt"),
-    "fixture framework binary\n",
-  );
-  const icu = path.join(source, "icu", "share", "icu");
-  await write(path.join(icu, "icudt77l.dat"), "fixture icu\n");
-  const icuDigest = createHash("sha256")
-    .update("icudt77l.dat\0" + Buffer.byteLength("fixture icu\n") + "\0")
-    .update("fixture icu\n")
-    .update("\n")
-    .digest("hex");
-  const icuSeed = path.join(runtime, "cluster-seed-icu");
-  await write(
-    path.join(icuSeed, "manifest.properties"),
-    nativeSeedFixture("icu", "ios-datum64", icuDigest),
-  );
-  await write(path.join(icuSeed, "files", "PG_VERSION"), "18\n");
-  await write(path.join(icuSeed, "files", "global", "pg_control"), "control\n");
-  for (const [index, invalidFixture] of SHARED_NATIVE_INVALID_CACHE_FIXTURES.entries()) {
-    const invalidRoot = path.join(source, `invalid-cache-runtime-${index}`, "oliphaunt");
-    await fs.cp(runtime, invalidRoot, { recursive: true });
-    await write(
-      path.join(invalidRoot, "cluster-seed", "manifest.properties"),
-      retargetNativeSeedFixture(invalidFixture, "ios-datum64"),
-    );
-    await assert.rejects(validateNativeRuntimeClosure(invalidRoot), /cache key/u);
-    await fs.rm(path.dirname(invalidRoot), { recursive: true });
-  }
-  await write(
-    path.join(source, "icu", "manifest.properties"),
-    [
-      "schema=oliphaunt-icu-data-v1",
-      "artifactRole=icu-data",
-      "icuDataVersion=76.1",
-      "icuDataForm=files-le",
-      `icuDataTreeSha256=${icuDigest}`,
-      "",
-    ].join("\n"),
-  );
-  await fs.cp(
-    runtime,
-    path.join(
-      baseFramework,
-      "ios-arm64",
-      "liboliphaunt.framework",
-      "Resources",
-      "oliphaunt",
-    ),
-    { recursive: true },
-  );
-
-  const baseLegalSpecs = [
-    {
-      assetRole: "base-xcframework",
-      root: path.dirname(baseFramework),
-      profile: "native-runtime",
-      spdx: "MIT AND PostgreSQL AND Unicode-3.0",
-      files: [
-        "liboliphaunt.xcframework/LICENSE",
-        "liboliphaunt.xcframework/THIRD_PARTY_LICENSES/ICU-LICENSE",
-        "liboliphaunt.xcframework/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-        "liboliphaunt.xcframework/THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-        "liboliphaunt.xcframework/THIRD_PARTY_NOTICES.md",
-      ],
-    },
-    {
-      assetRole: "runtime-resources",
-      root: path.dirname(runtime),
-      profile: "native-runtime-resources",
-      spdx: "MIT AND PostgreSQL",
-      files: [
-        "LICENSE",
-        "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-        "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-        "THIRD_PARTY_NOTICES.md",
-      ],
-    },
-    {
-      assetRole: "icu-data",
-      root: path.join(source, "icu"),
-      profile: "native-icu-data",
-      spdx: "MIT AND PostgreSQL AND Unicode-3.0",
-      files: [
-        "LICENSE",
-        "THIRD_PARTY_LICENSES/ICU-LICENSE",
-        "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-        "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-        "THIRD_PARTY_NOTICES.md",
-      ],
-    },
-  ];
-  const legal = [];
-  for (const spec of baseLegalSpecs) {
-    legal.push(await legalGroup(spec.root, {
-      assetRole: spec.assetRole,
-      files: spec.files.map((member) => ({
-        kind: member.includes("NOTICE") ? "notice" : "license",
-        member,
-      })),
-      profile: spec.profile,
-      spdx: spec.spdx,
-    }));
-  }
-
-  const archiveRoot = path.join(root, "archives");
-  const runtimeArchive = path.join(
-    archiveRoot,
-    "liboliphaunt-1.0.0-runtime-resources-ios-datum64.tar.gz",
-  );
-  const frameworkArchive = path.join(archiveRoot, "liboliphaunt-1.0.0-apple-spm-xcframework.zip");
-  const icuArchive = path.join(archiveRoot, "liboliphaunt-1.0.0-icu-data.tar.gz");
-  await tarMembers(path.dirname(runtime), runtimeArchive, [
-    path.basename(runtime),
-    "LICENSE",
-    "THIRD_PARTY_LICENSES",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_NOTICES.md",
-  ]);
-  // POSIX typeflag 5 is authoritative even when an older producer omitted the
-  // conventional slash. This is the exact archive shape from the failed run.
-  await removeTarDirectorySlash(runtimeArchive, `${path.basename(runtime)}/`);
-  await zipMember(path.dirname(baseFramework), path.basename(baseFramework), frameworkArchive);
-  await tarMembers(path.join(source, "icu"), icuArchive, [
-    "manifest.properties",
-    "share/icu",
-    "LICENSE",
-    "THIRD_PARTY_LICENSES",
-    "THIRD_PARTY_NOTICES.liboliphaunt-native.md",
-    "THIRD_PARTY_NOTICES.md",
-  ]);
-  return {
-    assets: [
-      await asset("base-xcframework", frameworkArchive, "zip", "liboliphaunt.xcframework"),
-      await asset("runtime-resources", runtimeArchive, "tar.gz", "oliphaunt"),
-      await asset("icu-data", icuArchive, "tar.gz", "."),
-    ],
-    legal,
-  };
-}
-
-async function extensionRow(root, config) {
-  const source = path.join(root, "source", "extensions", config.sqlName, "runtime");
-  const createsExtension = config.createsExtension ?? true;
-  const dataFiles = config.dataFiles ?? [];
-  const sharedPreloadLibraries = config.sharedPreloadLibraries ?? [];
-  const mobilePrebuilt = config.mobilePrebuilt ?? (config.nativeModuleStem !== null);
-  const nativeModuleFile = config.nativeModuleStem === null ? "" : `${config.nativeModuleStem}.dylib`;
-  const nativeSymbolStem = config.nativeModuleStem?.replaceAll(/[^A-Za-z0-9_]/gu, "_") ?? "";
-  const registrationSymbols = config.registrationSymbols ?? [];
-  const staticSymbolAliases = registrationSymbols
-    .filter(({ address, name }) => address !== name)
-    .map(({ address, name }) => `${name}:${address}`)
-    .sort();
-  const mobileStaticArchives = config.nativeModuleStem === null
-    ? []
-    : ["ios-device", "ios-simulator"].map(
-        (target) =>
-          `${target}:mobile-static/${target}/extensions/${config.nativeModuleStem}/` +
-          `liboliphaunt_extension_${config.nativeModuleStem}.a`,
-      );
-  const productionDependencyArchiveNames = new Map([
-    ["geos-c", "libgeos_c.a"],
-    ["openssl", "libcrypto.a"],
-    ["sqlite", "libsqlite3.a"],
-  ]);
-  const mobileStaticDependencyArchives = ["ios-device", "ios-simulator"].flatMap((target) =>
-    config.nativeDependencies.map(
-      (dependency) =>
-        `${target}:${dependency}:mobile-static/${target}/dependencies/${dependency}/` +
-        `${productionDependencyArchiveNames.get(dependency) ?? `lib${dependency}.a`}`,
-    ));
-  const externalLicenseMembers = config.sqlName === "pgtap"
-    ? ["files/share/licenses/pgtap/LICENSE"]
-    : config.sqlName === "postgis"
-      ? ["files/share/licenses/postgis/COPYING"]
-      : [];
-  const profile = externalLicenseMembers.length > 0
-    ? "external-native"
-    : config.sqlName === "pgcrypto"
-      ? "contrib-native-openssl"
-      : "contrib-native";
-  const spdx = config.sqlName === "postgis"
-    ? "MIT AND Apache-2.0 AND GPL-2.0-or-later AND LGPL-2.1-or-later AND blessing"
-    : config.sqlName === "pgcrypto"
-      ? "MIT AND PostgreSQL AND Apache-2.0"
-      : "MIT AND PostgreSQL";
-  const legal = await legalGroup(source, {
-    assetRole: "runtime-resources",
-    files: [
-      { kind: "license", member: "LICENSE" },
-      ...(externalLicenseMembers.length === 0
-        ? [{ kind: "license", member: "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT" }]
-        : []),
-      ...(config.sqlName === "pgcrypto"
-        ? [{ kind: "license", member: "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt" }]
-        : []),
-      { kind: "notice", member: "THIRD_PARTY_NOTICES.md" },
-      ...externalLicenseMembers.map((member) => ({ kind: "license", member })),
-    ],
-    profile,
-    spdx,
-  });
-  const licenseFiles = legal.files
-    .map(({ member }) => /^files\/(share\/licenses\/.+)$/u.exec(member)?.[1])
-    .filter((member) => member !== undefined)
-    .sort();
-  await write(
-    path.join(source, "manifest.properties"),
-    [
-      "packageLayout=oliphaunt-extension-artifact-v1",
-      "pgMajor=18",
-      `sqlName=${config.sqlName}`,
-      `createsExtension=${createsExtension ? "yes" : "no"}`,
-      `nativeModuleStem=${config.nativeModuleStem ?? ""}`,
-      `nativeModuleFile=${nativeModuleFile}`,
-      "nativeTarget=ios-xcframework",
-      "nativeRuntimeProduct=liboliphaunt-native",
-      "nativeRuntimeVersion=1.0.0",
-      `dependencies=${config.dependencies.join(",")}`,
-      `dataFiles=${dataFiles.join(",")}`,
-      `extensionSqlFileNames=${config.extensionSqlFileNames.join(",")}`,
-      `extensionSqlFilePrefixes=${config.extensionSqlFilePrefixes.join(",")}`,
-      `sharedPreloadLibraries=${sharedPreloadLibraries.join(",")}`,
-      `mobilePrebuilt=${mobilePrebuilt ? "yes" : "no"}`,
-      `mobileStaticArchives=${mobileStaticArchives.join(",")}`,
-      `mobileStaticDependencyArchives=${mobileStaticDependencyArchives.join(",")}`,
-      `staticSymbolPrefix=${nativeSymbolStem ? `oliphaunt_static_${nativeSymbolStem}` : ""}`,
-      `staticSymbolAliases=${staticSymbolAliases.join(",")}`,
-      `licenseFiles=${licenseFiles.join(",")}`,
-      `licenseProfile=${profile}`,
-      "files=files",
-      "",
-    ].join("\n"),
-  );
-  if (createsExtension) {
-    await write(
-      path.join(source, "files", "share", "postgresql", "extension", `${config.sqlName}.control`),
-      `comment = '${config.sqlName} fixture'\n`,
-    );
-    await write(
-      path.join(source, "files", "share", "postgresql", "extension", `${config.sqlName}--1.0.sql`),
-      `select '${config.sqlName}';\n`,
-    );
-    if (config.includeUpdateSql === true) {
-      await write(
-        path.join(
-          source,
-          "files",
-          "share",
-          "postgresql",
-          "extension",
-          `${config.sqlName}--1.0--1.1.sql`,
-        ),
-        `select '${config.sqlName} update';\n`,
-      );
-    }
-    if (config.sqlName === "pgtap") {
-      await write(
-        path.join(
-          source,
-          "files",
-          "share",
-          "postgresql",
-          "extension",
-          "pgtap.sql",
-        ),
-        "select 'pgtap ancillary SQL';\n",
-      );
-      await write(
-        path.join(
-          source,
-          "files",
-          "share",
-          "postgresql",
-          "extension",
-          "pgtap--unpackaged--0.91.0.sql",
-        ),
-        "select 'pgtap legacy upgrade';\n",
-      );
-    }
-    if (config.sqlName === "postgis") {
-      await write(
-        path.join(
-          source,
-          "files",
-          "share",
-          "postgresql",
-          "extension",
-          "postgis--TEMPLATED--TO--ANY.sql",
-        ),
-        "select 'postgis template upgrade';\n",
-      );
-    }
-  }
-  for (const dataFile of dataFiles) {
-    await write(path.join(source, "files", "share", "postgresql", dataFile), `${config.sqlName} data\n`);
-  }
-  if (config.nativeModuleStem !== null) {
-    await write(
-      path.join(source, "files", "lib", "postgresql", `${config.nativeModuleStem}.dylib`),
-      `${config.sqlName} native fixture\n`,
-    );
-  }
-  for (const row of mobileStaticArchives) {
-    const [, relative] = row.split(":");
-    await write(path.join(source, ...relative.split("/")), `${config.sqlName} static fixture\n`);
-  }
-  for (const row of mobileStaticDependencyArchives) {
-    const [, dependency, relative] = row.split(":");
-    await write(path.join(source, ...relative.split("/")), `${dependency} static fixture\n`);
-  }
-  const archiveRoot = path.join(root, "archives");
-  const runtimeArchive = path.join(
-    archiveRoot,
-    `oliphaunt-extension-${config.sqlName.replaceAll("_", "-")}-1.0.0-native-ios-runtime.tar.gz`,
-  );
-  await tarDirectory(source, runtimeArchive);
-  const logicalAssets = [
-    await logicalAsset("runtime-resources", runtimeArchive, "tar.gz", "."),
-  ];
-  if (config.nativeModuleStem !== null) {
-    const framework = path.join(
-      root,
-      "source",
-      "extensions",
-      config.sqlName,
-      `liboliphaunt_extension_${config.nativeModuleStem}.xcframework`,
-    );
-    await write(path.join(framework, "Info.plist"), "\n");
-    const frameworkArchive = path.join(
-      archiveRoot,
-      `oliphaunt-extension-${config.sqlName.replaceAll("_", "-")}-1.0.0-native-ios-xcframework.zip`,
-    );
-    await zipMember(path.dirname(framework), path.basename(framework), frameworkArchive);
-    logicalAssets.push(
-      await logicalAsset(
-        "extension-xcframework",
-        frameworkArchive,
-        "zip",
-        path.basename(framework),
-      ),
-    );
-    for (const dependency of config.nativeDependencies) {
-      const dependencyFramework = path.join(
-        root,
-        "source",
-        "extensions",
-        config.sqlName,
-        `liboliphaunt_dependency_${dependency}.xcframework`,
-      );
-      await write(path.join(dependencyFramework, "Info.plist"), "\n");
-      const dependencyArchive = path.join(
-        archiveRoot,
-        `oliphaunt-extension-${config.sqlName.replaceAll("_", "-")}-1.0.0-native-ios-dependency-${dependency}.zip`,
-      );
-      await zipMember(path.dirname(dependencyFramework), path.basename(dependencyFramework), dependencyArchive);
-      logicalAssets.push(
-        await logicalAsset(
-          "dependency-xcframework",
-          dependencyArchive,
-          "zip",
-          path.basename(dependencyFramework),
-        ),
-      );
-    }
-  }
-  const generated = GENERATED_EXTENSION_BY_SQL_NAME.get(config.sqlName);
-  assert.ok(generated, `missing generated fixture metadata for ${config.sqlName}`);
-  const product = generated["artifact-product"];
-  const releaseProduct = generated["release-product"];
-  return {
-    carriers: logicalAssets.map(({ envelope }) => envelope),
-    legal,
-    extension: {
-      assets: logicalAssets.map(({ locator }) => locator),
-      createsExtension,
-      dataFiles,
-      dependencies: config.dependencies,
-      extensionSqlFileNames: config.extensionSqlFileNames,
-      extensionSqlFilePrefixes: config.extensionSqlFilePrefixes,
-      nativeDependencies: config.nativeDependencies,
-      nativeModuleStem: config.nativeModuleStem,
-      product,
-      releaseProduct,
-      registration: config.nativeModuleStem === null
-        ? null
-        : {
-            initSymbol: null,
-            magicSymbol: `oliphaunt_static_${config.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}_Pg_magic_func`,
-            symbols: registrationSymbols,
-          },
-      sharedPreloadLibraries,
-      sqlName: config.sqlName,
-      tag: `${releaseProduct}-v1.0.0`,
-      version: "1.0.0",
-    },
-  };
-}
-
-async function rewrittenExtensionRuntime(root, sqlName, archiveName, rewrite) {
-  const source = path.join(root, "source", "extensions", sqlName, "runtime");
-  const stage = path.join(root, "rewritten-extension-runtime", archiveName.replace(/\.tar\.gz$/u, ""));
-  await fs.rm(stage, { force: true, recursive: true });
-  await fs.cp(source, stage, { recursive: true });
-  const manifestFile = path.join(stage, "manifest.properties");
-  const original = await fs.readFile(manifestFile, "utf8");
-  const rewritten = rewrite(original);
-  assert.notEqual(rewritten, original, `${archiveName} rewrite must change manifest.properties`);
-  await fs.writeFile(manifestFile, rewritten);
-  const archive = path.join(root, "archives", archiveName);
-  await fs.rm(archive, { force: true });
-  await tarDirectory(stage, archive);
-  return logicalAsset("runtime-resources", archive, "tar.gz", ".");
-}
-
-async function extendedExtensionRuntime(root, sqlName, archiveName, additions) {
-  const source = path.join(root, "source", "extensions", sqlName, "runtime");
-  const stage = path.join(root, "extended-extension-runtime", archiveName.replace(/\.tar\.gz$/u, ""));
-  await fs.rm(stage, { force: true, recursive: true });
-  await fs.cp(source, stage, { recursive: true });
-  for (const [relativePath, contents] of Object.entries(additions)) {
-    await write(path.join(stage, relativePath), contents);
-  }
-  const archive = path.join(root, "archives", archiveName);
-  await fs.rm(archive, { force: true });
-  await tarDirectory(stage, archive);
-  return logicalAsset("runtime-resources", archive, "tar.gz", ".");
-}
-
-async function mutatedExtensionRuntime(root, sqlName, archiveName, mutate) {
-  const source = path.join(root, "source", "extensions", sqlName, "runtime");
-  const stage = path.join(root, "mutated-extension-runtime", archiveName.replace(/\.tar\.gz$/u, ""));
-  await fs.rm(stage, { force: true, recursive: true });
-  await fs.cp(source, stage, { recursive: true });
-  await mutate(stage);
-  const archive = path.join(root, "archives", archiveName);
-  await fs.rm(archive, { force: true });
-  await tarDirectory(stage, archive);
-  return logicalAsset("runtime-resources", archive, "tar.gz", ".");
-}
-
-async function createFixture(root) {
-  const builtBase = await baseAssets(root);
-  const base = {
-    assets: builtBase.assets,
-    product: "liboliphaunt-native",
-    tag: "liboliphaunt-native-v1.0.0",
-    version: "1.0.0",
-  };
-  const carriers = [];
-  const extensions = [];
-  const extensionLegal = [];
-  for (const fixture of [
-    { sqlName: "auto_explain" },
-    { sqlName: "cube" },
-    { sqlName: "earthdistance" },
-    { sqlName: "pgcrypto" },
-    { sqlName: "pgtap", includeUpdateSql: true },
-    {
-      sqlName: "postgis",
-      registrationSymbols: [
-        { address: "oliphaunt_static_postgis_3_difference", name: "difference" },
-        {
-          address: "pg_finfo_oliphaunt_static_postgis_3_difference",
-          name: "pg_finfo_difference",
-        },
-      ],
-    },
-  ]) {
-    const generated = GENERATED_EXTENSION_BY_SQL_NAME.get(fixture.sqlName);
-    assert.ok(generated, `missing generated fixture metadata for ${fixture.sqlName}`);
-    const iosDependencies = GENERATED_IOS_DEPENDENCIES_BY_SQL_NAME.get(fixture.sqlName) ?? [];
-    if (fixture.sqlName === "pgcrypto") {
-      assert.deepEqual(iosDependencies, ["openssl"]);
-    }
-    if (fixture.sqlName === "postgis") {
-      assert.deepEqual(
-        iosDependencies,
-        ["geos", "geos-c", "json-c", "libxml2", "proj", "sqlite"],
-      );
-    }
-    const config = {
-      ...fixture,
-      createsExtension: generated["creates-extension"],
-      dataFiles: generated["runtime-share-data-files"],
-      dependencies: generated["selected-extension-dependencies"],
-      extensionSqlFileNames: generated["extension-sql-file-names"],
-      extensionSqlFilePrefixes: generated["extension-sql-file-prefixes"],
-      nativeDependencies: iosDependencies,
-      nativeModuleStem: generated["native-module-stem"],
-      sharedPreloadLibraries: generated["shared-preload-libraries"],
-    };
-    const built = await extensionRow(root, config);
-    carriers.push(...built.carriers);
-    extensions.push(built.extension);
-    extensionLegal.push({ ...built.legal, sqlName: built.extension.sqlName });
-  }
-  extensionLegal.sort((left, right) => compareText(left.sqlName, right.sqlName));
-  const carrier = {
-    base,
-    carriers,
-    extensions,
-    legal: { base: builtBase.legal, extensions: extensionLegal },
-    schema: SCHEMA,
-  };
-  const carrierFile = path.join(root, "oliphaunt-react-native-ios-carriers.json");
-  await write(carrierFile, `${JSON.stringify(carrier, null, 2)}\n`);
-  return { carrier, carrierFile };
-}
-
-async function bundledCarrierDocument(root, sourceDocument, sqlNames, archiveName, tamperSqlName) {
-  const document = structuredClone(sourceDocument);
-  document.extensions = document.extensions.filter(({ sqlName }) => sqlNames.includes(sqlName));
-  document.legal.extensions = document.legal.extensions.filter(({ sqlName }) => sqlNames.includes(sqlName));
-  const sourceRoot = path.join(root, "bundle-source", archiveName.replace(/\.tar\.gz$/u, ""));
-  await fs.rm(sourceRoot, { force: true, recursive: true });
-  const sourceCarriers = new Map(sourceDocument.carriers.map((row) => [row.name, row]));
-  for (const extension of document.extensions) {
-    for (const locator of extension.assets) {
-      const envelope = sourceCarriers.get(locator.carrier);
-      assert.ok(envelope, `missing source envelope ${locator.carrier}`);
-      const nestedPath = `extensions/${extension.sqlName}/${envelope.name}`;
-      const nestedFile = path.join(sourceRoot, ...nestedPath.split("/"));
-      await fs.mkdir(path.dirname(nestedFile), { recursive: true });
-      await fs.copyFile(fileURLToPath(envelope.url), nestedFile);
-      if (extension.sqlName === tamperSqlName && locator.role === "runtime-resources") {
-        await fs.appendFile(nestedFile, "tampered nested payload\n");
-      }
-      locator.carrier = archiveName;
-      locator.path = nestedPath;
-    }
-  }
-  const archive = path.join(root, "archives", archiveName);
-  await fs.rm(archive, { force: true });
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  run("tar", ["--no-xattrs", "-czf", archive, "-C", sourceRoot, "extensions"]);
-  const direct = await asset("carrier", archive, "tar.gz", ".");
-  document.carriers = [{
-    bytes: direct.bytes,
-    format: direct.format,
-    name: direct.name,
-    sha256: direct.sha256,
-    url: direct.url,
-  }];
-  return document;
-}
-
-async function expectReject(action, pattern) {
-  let error;
-  try {
-    await action();
-  } catch (caught) {
-    error = caught;
-  }
-  assert.ok(error instanceof Error, "expected action to reject");
-  assert.match(error.message, pattern);
-}
-
-async function main() {
-  const root = await fs.mkdtemp(path.join(os.tmpdir(), "oliphaunt-rn-ios-carrier-"));
-  try {
-    const { carrier, carrierFile } = await createFixture(root);
-    const output = path.join(root, "consumer", "ios", "oliphaunt");
-    const cache = path.join(root, "cache");
-    const requested = ["auto_explain", "earthdistance", "pgcrypto", "pgtap", "postgis"];
-    const fakeArchiveTools = path.join(root, "fake-archive-tools");
-    await fs.mkdir(fakeArchiveTools, { recursive: true });
-    const fakeZipinfo = path.join(fakeArchiveTools, "zipinfo");
-    await fs.writeFile(fakeZipinfo, "#!/bin/sh\n# Reproduce a successful child whose formatted stdout was truncated.\nexit 0\n");
-    await fs.chmod(fakeZipinfo, 0o755);
-    const originalPath = process.env.PATH;
-    let result;
-    try {
-      process.env.PATH = `${fakeArchiveTools}${path.delimiter}${originalPath ?? ""}`;
-      result = await stageIosApp({
-        allowFileUrls: true,
-        cacheDir: cache,
-        carriers: [carrierFile],
-        extensions: requested,
-        icu: true,
-        outputDir: output,
-      });
-    } finally {
-      if (originalPath === undefined) delete process.env.PATH;
-      else process.env.PATH = originalPath;
-    }
-    assert.deepEqual(
-      result.selected,
-      ["auto_explain", "cube", "earthdistance", "pgcrypto", "pgtap", "postgis"],
-    );
-    run(
-      process.execPath,
-      [path.join(import.meta.dirname, "verify-ios-package.mjs"), "--payload-dir", output],
-    );
-
-    const payloadPodspec = await fs.readFile(
-      path.join(output, "OliphauntReactNativePayload.podspec"),
-      "utf8",
-    );
-    assert.match(
-      payloadPodspec,
-      /^  s[.]license = \{ :type => "MIT AND PostgreSQL AND Unicode-3[.]0 AND Apache-2[.]0 AND GPL-2[.]0-or-later AND LGPL-2[.]1-or-later AND blessing", :file => "licenses\/NOTICE[.]md" \}$/mu,
-    );
-    assert.match(payloadPodspec, /^  s[.]preserve_paths = "licenses\/\*\*\/\*"$/mu);
-    assert.match(
-      payloadPodspec,
-      /s\.resources = "resources\/OliphauntReactNativeResources\.bundle"/u,
-    );
-    assert.match(
-      payloadPodspec,
-      /s\.vendored_frameworks = "frameworks\/base\/liboliphaunt\.xcframework", "frameworks\/extensions\/\*\*\/\*\.xcframework"/u,
-    );
-    assert.doesNotMatch(payloadPodspec, /frameworks\/base\/[^"\n]*\*\*/u);
-    assert.doesNotMatch(payloadPodspec, /frameworks\/base\/[^"\n]*\.framework/u);
-    assert.match(payloadPodspec, /s\.source_files = "generated\/static-registry\/\*\.c"/u);
-    assert.doesNotMatch(payloadPodspec, /(?:^|["'])\.\.\//mu);
-    for (const relativeRoot of [
-      "resources/OliphauntReactNativeResources.bundle",
-      "frameworks/base",
-      "frameworks/extensions",
-      "generated/static-registry",
-      "licenses/base/base-xcframework",
-      "licenses/base/icu-data",
-      "licenses/base/runtime-resources",
-      "licenses/extensions/postgis",
-    ]) {
-      await fs.access(path.join(output, relativeRoot));
-    }
-    await fs.access(path.join(
-      output,
-      "frameworks",
-      "base",
-      "liboliphaunt.xcframework",
-      "ios-arm64",
-      "liboliphaunt.framework",
-      "liboliphaunt",
-    ));
-    await assert.rejects(
-      fs.access(path.join(
-        output,
-        "frameworks",
-        "base",
-        "liboliphaunt.xcframework",
-        "ios-arm64",
-        "liboliphaunt.framework",
-        "Resources",
-        "oliphaunt",
-      )),
-    );
-    await assert.rejects(
-      fs.access(path.join(
-        output,
-        "frameworks",
-        "base",
-        "liboliphaunt.xcframework",
-        "ios-arm64",
-        "liboliphaunt.framework",
-        "Resources",
-      )),
-    );
-
-    const frameworkNames = (await fs.readdir(path.join(output, "frameworks", "extensions"))).sort();
-    assert.deepEqual(frameworkNames, [
-      "liboliphaunt_dependency_geos-c.xcframework",
-      "liboliphaunt_dependency_geos.xcframework",
-      "liboliphaunt_dependency_json-c.xcframework",
-      "liboliphaunt_dependency_libxml2.xcframework",
-      "liboliphaunt_dependency_openssl.xcframework",
-      "liboliphaunt_dependency_proj.xcframework",
-      "liboliphaunt_dependency_sqlite.xcframework",
-      "liboliphaunt_extension_auto_explain.xcframework",
-      "liboliphaunt_extension_cube.xcframework",
-      "liboliphaunt_extension_earthdistance.xcframework",
-      "liboliphaunt_extension_pgcrypto.xcframework",
-      "liboliphaunt_extension_postgis-3.xcframework",
-    ]);
-    assert.equal(
-      await fs.readFile(
-        path.join(output, "resources", "OliphauntReactNativeResources.bundle", "oliphaunt", "runtime", "files", "share", "icu", "icudt77l.dat"),
-        "utf8",
-      ),
-      "fixture icu\n",
-    );
-    await fs.access(
-      path.join(output, "resources", "OliphauntReactNativeResources.bundle", "oliphaunt", "runtime", "files", "share", "postgresql", "extension", "pgtap.control"),
-    );
-    await assert.rejects(
-      fs.access(path.join(output, "frameworks", "extensions", "liboliphaunt_extension_pgtap.xcframework")),
-    );
-    await assert.rejects(
-      fs.access(
-        path.join(output, "resources", "OliphauntReactNativeResources.bundle", "oliphaunt", "runtime", "files", "share", "postgresql", "extension", "auto_explain.control"),
-      ),
-    );
-    const runtimeManifest = await fs.readFile(
-      path.join(
-        output,
-        "resources",
-        "OliphauntReactNativeResources.bundle",
-        "oliphaunt",
-        "runtime",
-        "manifest.properties",
-      ),
-      "utf8",
-    );
-    assert.match(
-      runtimeManifest,
-      /^selectedExtensions=auto_explain,cube,earthdistance,pgcrypto,pgtap,postgis$/mu,
-    );
-    assert.match(
-      runtimeManifest,
-      /^extensions=cube,earthdistance,pgcrypto,pgtap,postgis$/mu,
-    );
-    assert.match(
-      runtimeManifest,
-      /^mobileStaticRegistryRegistered=auto_explain,cube,earthdistance,pgcrypto,postgis$/mu,
-    );
-    const packageSize = await fs.readFile(
-      path.join(output, "resources", "OliphauntReactNativeResources.bundle", "oliphaunt", "package-size.tsv"),
-      "utf8",
-    );
-    assert.match(packageSize, /^extension\tauto_explain\t-\t0\t0$/mu);
-    assert.match(
-      packageSize,
-      /^extensions\tselected\tauto_explain,cube,earthdistance,pgcrypto,pgtap,postgis\t/mu,
-    );
-    const registry = await fs.readFile(
-      path.join(output, "generated", "static-registry", "oliphaunt_static_registry.c"),
-      "utf8",
-    );
-    assert.doesNotMatch(registry, /symbols\[\]\s*=\s*\{\s*\}/u);
-    assert.match(registry, /\.symbols = NULL,/u);
-    assert.match(registry, /\.name = "postgis-3"/u);
-    assert.match(
-      registry,
-      /\.name = "difference", \.address = \(void \*\)oliphaunt_static_postgis_3_difference/u,
-    );
-    assert.match(
-      registry,
-      /\.name = "pg_finfo_difference", \.address = \(void \*\)pg_finfo_oliphaunt_static_postgis_3_difference/u,
-    );
-
-    const selection = JSON.parse(await fs.readFile(path.join(output, "selection.json"), "utf8"));
-    assert.equal(selection.icu, true);
-    assert.equal(
-      selection.legal.spdx,
-      "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0 AND GPL-2.0-or-later AND LGPL-2.1-or-later AND blessing",
-    );
-    assert.equal(selection.legal.file, "licenses/NOTICE.md");
-    assert.ok(selection.legal.files.every(({ destination }) => destination.startsWith("licenses/")));
-    assert.match(
-      await fs.readFile(path.join(output, selection.legal.file), "utf8"),
-      /^SPDX-License-Identifier: MIT AND PostgreSQL AND Unicode-3[.]0/mu,
-    );
-    assert.equal(
-      selection.extensions.find(({ sqlName }) => sqlName === "auto_explain").createsExtension,
-      false,
-    );
-    assert.equal(
-      selection.extensions.find(({ sqlName }) => sqlName === "pgtap").createsExtension,
-      true,
-    );
-    await fs.access(
-      path.join(
-        output,
-        "resources",
-        "OliphauntReactNativeResources.bundle",
-        "oliphaunt",
-        "runtime",
-        "files",
-        "share",
-        "postgresql",
-        "extension",
-        "pgtap--1.0--1.1.sql",
-      ),
-    );
-    assert.deepEqual(selection.requestedExtensions, [...requested].sort());
-    assert.deepEqual(selection.extensions.map(({ sqlName }) => sqlName), result.selected);
-
-    const duplicateClosureOutput = path.join(root, "duplicate-framework-closure-output");
-    await fs.cp(output, duplicateClosureOutput, { recursive: true });
-    await fs.cp(
-      path.join(
-        duplicateClosureOutput,
-        "resources",
-        "OliphauntReactNativeResources.bundle",
-        "oliphaunt",
-      ),
-      path.join(
-        duplicateClosureOutput,
-        "frameworks",
-        "base",
-        "liboliphaunt.xcframework",
-        "ios-arm64",
-        "liboliphaunt.framework",
-        "Resources",
-        "oliphaunt",
-      ),
-      { recursive: true },
-    );
-    runFailure(
-      process.execPath,
-      [
-        path.join(import.meta.dirname, "verify-ios-package.mjs"),
-        "--payload-dir",
-        duplicateClosureOutput,
-      ],
-      /must not embed a second runtime-resource closure/u,
-    );
-
-    const missingCreateableOutput = path.join(root, "missing-createable-output");
-    await fs.cp(output, missingCreateableOutput, { recursive: true });
-    const missingCreateableManifest = path.join(
-      missingCreateableOutput,
-      "resources",
-      "OliphauntReactNativeResources.bundle",
-      "oliphaunt",
-      "runtime",
-      "manifest.properties",
-    );
-    await fs.writeFile(
-      missingCreateableManifest,
-      (await fs.readFile(missingCreateableManifest, "utf8")).replace(
-        /^extensions=cube,earthdistance,pgcrypto,pgtap,postgis$/mu,
-        "extensions=cube,earthdistance,pgcrypto,postgis",
-      ),
-    );
-    runFailure(
-      process.execPath,
-      [
-        path.join(import.meta.dirname, "verify-ios-package.mjs"),
-        "--payload-dir",
-        missingCreateableOutput,
-      ],
-      /extensions must match the exact canonical domain/u,
-    );
-
-    const missingNativeRegistrationOutput = path.join(root, "missing-native-registration-output");
-    await fs.cp(output, missingNativeRegistrationOutput, { recursive: true });
-    const missingNativeRegistrationManifest = path.join(
-      missingNativeRegistrationOutput,
-      "resources",
-      "OliphauntReactNativeResources.bundle",
-      "oliphaunt",
-      "runtime",
-      "manifest.properties",
-    );
-    await fs.writeFile(
-      missingNativeRegistrationManifest,
-      (await fs.readFile(missingNativeRegistrationManifest, "utf8")).replace(
-        /^mobileStaticRegistryRegistered=auto_explain,cube,earthdistance,pgcrypto,postgis$/mu,
-        "mobileStaticRegistryRegistered=cube,earthdistance,pgcrypto,postgis",
-      ),
-    );
-    runFailure(
-      process.execPath,
-      [
-        path.join(import.meta.dirname, "verify-ios-package.mjs"),
-        "--payload-dir",
-        missingNativeRegistrationOutput,
-      ],
-      /mobileStaticRegistryRegistered must match the exact canonical domain/u,
-    );
-
-    const tamperedLegalNoticeOutput = path.join(root, "tampered-legal-notice-output");
-    await fs.cp(output, tamperedLegalNoticeOutput, { recursive: true });
-    await fs.appendFile(
-      path.join(tamperedLegalNoticeOutput, "licenses", "NOTICE.md"),
-      "unfrozen notice text\n",
-    );
-    runFailure(
-      process.execPath,
-      [
-        path.join(import.meta.dirname, "verify-ios-package.mjs"),
-        "--payload-dir",
-        tamperedLegalNoticeOutput,
-      ],
-      /does not exactly index the frozen legal selection/u,
-    );
-
-    const unselectedLegalOutput = path.join(root, "unselected-legal-output");
-    await fs.cp(output, unselectedLegalOutput, { recursive: true });
-    await write(
-      path.join(unselectedLegalOutput, "licenses", "extensions", "unselected", "LICENSE"),
-      "unselected legal payload\n",
-    );
-    runFailure(
-      process.execPath,
-      [
-        path.join(import.meta.dirname, "verify-ios-package.mjs"),
-        "--payload-dir",
-        unselectedLegalOutput,
-      ],
-      /legal namespace contains missing or uncontracted files/u,
-    );
-
-    const contribBundle = await bundledCarrierDocument(
-      root,
-      carrier,
-      ["auto_explain", "cube", "earthdistance"],
-      "oliphaunt-extension-contrib-pg18-1.0.0-native-ios-bundle.tar.gz",
-    );
-    const contribBundleFile = path.join(root, "oliphaunt-extension-contrib-pg18-carrier.json");
-    await write(contribBundleFile, `${JSON.stringify(contribBundle, null, 2)}\n`);
-    const externalCarrier = structuredClone(carrier);
-    externalCarrier.extensions = externalCarrier.extensions.filter(({ sqlName }) => sqlName === "pgtap");
-    retainReferencedCarriers(externalCarrier);
-    const externalCarrierFile = path.join(root, "oliphaunt-extension-pgtap-carrier.json");
-    await write(externalCarrierFile, `${JSON.stringify(externalCarrier, null, 2)}\n`);
-    const bundleOutput = path.join(root, "consumer-bundle", "ios", "oliphaunt");
-    const bundleResult = await stageIosApp({
-      allowFileUrls: true,
-      cacheDir: path.join(root, "bundle-cache"),
-      carriers: [contribBundleFile, externalCarrierFile],
-      extensions: ["earthdistance", "pgtap"],
-      outputDir: bundleOutput,
-    });
-    assert.deepEqual(bundleResult.selected, ["cube", "earthdistance", "pgtap"]);
-    const bundleSelection = JSON.parse(await fs.readFile(path.join(bundleOutput, "selection.json"), "utf8"));
-    assert.deepEqual(bundleSelection.extensions.map(({ product, sqlName }) => [product, sqlName]), [
-      ["oliphaunt-extension-contrib-pg18", "cube"],
-      ["oliphaunt-extension-contrib-pg18", "earthdistance"],
-      ["oliphaunt-extension-pgtap", "pgtap"],
-    ]);
-    const unselectedAutoExplain = contribBundle.extensions
-      .find(({ sqlName }) => sqlName === "auto_explain")
-      .assets.find(({ role }) => role === "runtime-resources");
-    await assert.rejects(
-      fs.access(
-        path.join(
-          root,
-          "bundle-cache",
-          "payloads",
-          `${unselectedAutoExplain.sha256}-${path.posix.basename(unselectedAutoExplain.path)}`,
-        ),
-      ),
-    );
-    await fs.access(path.join(bundleOutput, "licenses", "extensions", "pgtap", "files", "share", "licenses", "pgtap", "LICENSE"));
-    await assert.rejects(fs.access(path.join(bundleOutput, "licenses", "extensions", "auto_explain")));
-    await assert.rejects(fs.access(path.join(bundleOutput, "licenses", "extensions", "postgis")));
-    await assert.rejects(fs.access(path.join(bundleOutput, "licenses", "base", "icu-data")));
-
-    // An independently versioned external extension is validated against the
-    // immutable carrier contract that shipped with that extension version, not
-    // against this SDK's newer generated extension catalog.
-    const frozenOldExternal = structuredClone(carrier);
-    frozenOldExternal.extensions = frozenOldExternal.extensions.filter(
-      ({ sqlName }) => sqlName === "pgtap",
-    );
-    const frozenOldPgtap = frozenOldExternal.extensions[0];
-    frozenOldPgtap.version = "0.9.0";
-    frozenOldPgtap.tag = "oliphaunt-extension-pgtap-v0.9.0";
-    frozenOldPgtap.dataFiles = ["legacy/pgtap-old.dat"];
-    frozenOldPgtap.extensionSqlFileNames = ["uninstall_pgtap_legacy.sql"];
-    frozenOldPgtap.extensionSqlFilePrefixes = ["pgtap-legacy"];
-    frozenOldPgtap.sharedPreloadLibraries = ["pgtap_legacy"];
-    replaceExtensionRuntimeAsset(
-      frozenOldExternal,
-      "pgtap",
-      await mutatedExtensionRuntime(
-        root,
-        "pgtap",
-        "pgtap-frozen-old-version.tar.gz",
-        async (stage) => {
-          const manifestFile = path.join(stage, "manifest.properties");
-          const manifest = await fs.readFile(manifestFile, "utf8");
-          await fs.writeFile(
-            manifestFile,
-            manifest
-              .replace("dataFiles=", "dataFiles=legacy/pgtap-old.dat")
-              .replace(
-                "extensionSqlFileNames=uninstall_pgtap.sql",
-                "extensionSqlFileNames=uninstall_pgtap_legacy.sql",
-              )
-              .replace(
-                "extensionSqlFilePrefixes=pgtap-core,pgtap-schema",
-                "extensionSqlFilePrefixes=pgtap-legacy",
-              )
-              .replace(
-                "sharedPreloadLibraries=",
-                "sharedPreloadLibraries=pgtap_legacy",
-              ),
-          );
-          await write(
-            path.join(stage, "files", "share", "postgresql", "legacy", "pgtap-old.dat"),
-            "old independently versioned pgtap data\n",
-          );
-        },
-      ),
-    );
-    retainReferencedCarriers(frozenOldExternal);
-    const frozenOldExternalFile = path.join(root, "pgtap-frozen-old-version.json");
-    await write(frozenOldExternalFile, `${JSON.stringify(frozenOldExternal, null, 2)}\n`);
-    const frozenOldOutput = path.join(root, "pgtap-frozen-old-output");
-    const frozenOldResult = await stageIosApp({
-      allowFileUrls: true,
-      cacheDir: path.join(root, "pgtap-frozen-old-cache"),
-      carriers: [frozenOldExternalFile],
-      extensions: ["pgtap"],
-      outputDir: frozenOldOutput,
-    });
-    assert.deepEqual(frozenOldResult.selected, ["pgtap"]);
-    assert.equal(
-      await fs.readFile(
-        path.join(
-          frozenOldOutput,
-          "resources",
-          "OliphauntReactNativeResources.bundle",
-          "oliphaunt",
-          "runtime",
-          "files",
-          "share",
-          "postgresql",
-          "legacy",
-          "pgtap-old.dat",
-        ),
-        "utf8",
-      ),
-      "old independently versioned pgtap data\n",
-    );
-
-    const tamperedBundle = await bundledCarrierDocument(
-      root,
-      carrier,
-      ["cube", "earthdistance"],
-      "oliphaunt-extension-contrib-pg18-1.0.0-native-ios-tampered-bundle.tar.gz",
-      "earthdistance",
-    );
-    const tamperedBundleFile = path.join(root, "tampered-contrib-bundle.json");
-    await write(tamperedBundleFile, `${JSON.stringify(tamperedBundle, null, 2)}\n`);
-    await expectReject(
-      () => stageIosApp({
-        allowFileUrls: true,
-        cacheDir: path.join(root, "tampered-bundle-cache"),
-        carriers: [tamperedBundleFile],
-        extensions: ["earthdistance"],
-        outputDir: path.join(root, "tampered-bundle-output"),
-      }),
-      /nested payload .* does not match its frozen size\/checksum/u,
-    );
-    await expectReject(
-      () => stageIosApp({
-        allowFileUrls: true,
-        carriers: [carrierFile, contribBundleFile],
-        extensions: ["cube"],
-        outputDir: path.join(root, "bundle-conflict"),
-      }),
-      /carrier manifests disagree for exact extension/u,
-    );
-
-    const baseRuntime = carrier.base.assets.find(({ role }) => role === "runtime-resources");
-    const cachedBase = path.join(cache, "extracted", baseRuntime.sha256);
-    await fs.writeFile(
-      path.join(cachedBase, "oliphaunt", "runtime", "manifest.properties"),
-      "tampered-cache-entry\n",
-    );
-    assert.equal((await fs.stat(`${cachedBase}.tree.json`)).isFile(), true);
-    const recoveredOutput = path.join(root, "consumer-recovered", "ios", "oliphaunt");
-    await stageIosApp({
-      allowFileUrls: true,
-      cacheDir: cache,
-      carriers: [carrierFile],
-      extensions: requested,
-      icu: true,
-      outputDir: recoveredOutput,
-    });
-    assert.doesNotMatch(
-      await fs.readFile(path.join(cachedBase, "oliphaunt", "runtime", "manifest.properties"), "utf8"),
-      /tampered-cache-entry/u,
-    );
-    run("diff", ["-ru", output, recoveredOutput]);
-
-    async function expectCarrierFailure(name, candidate, extensions, pattern, options = {}) {
-      const file = path.join(root, `${name}.json`);
-      await write(file, `${JSON.stringify(candidate, null, 2)}\n`);
-      await expectReject(
-        () => stageIosApp({
-          allowFileUrls: true,
-          cacheDir: path.join(root, `${name}-cache`),
-          carriers: [file],
-          extensions,
-          icu: options.icu ?? false,
-          outputDir: path.join(root, `${name}-output`),
-        }),
-        pattern,
-      );
-    }
-
-    async function expectResourceManifestFailure(name, rewrite, pattern, sqlName = "pgtap") {
-      const candidate = structuredClone(carrier);
-      const replacement = await rewrittenExtensionRuntime(
-        root,
-        sqlName,
-        `${name}.tar.gz`,
-        rewrite,
-      );
-      replaceExtensionAssets(candidate, sqlName, [replacement]);
-      await expectCarrierFailure(name, candidate, [sqlName], pattern);
-    }
-
-    const moduleOnlyBase = structuredClone(carrier);
-    const moduleOnlyBaseRoot = path.join(
-      root,
-      "mutated-base-module-only",
-      "oliphaunt",
-    );
-    await fs.cp(
-      path.join(root, "source", "base", "runtime", "oliphaunt"),
-      moduleOnlyBaseRoot,
-      { recursive: true },
-    );
-    const moduleOnlyBaseManifest = path.join(
-      moduleOnlyBaseRoot,
-      "runtime",
-      "manifest.properties",
-    );
-    await fs.writeFile(
-      moduleOnlyBaseManifest,
-      (await fs.readFile(moduleOnlyBaseManifest, "utf8")).replace(
-        "selectedExtensions=\n",
-        "selectedExtensions=auto_explain\n",
-      ),
-    );
-    await write(
-      path.join(moduleOnlyBaseRoot, "runtime", "files", "lib", "postgresql", "auto_explain.dylib"),
-      "hidden module-only base payload\n",
-    );
-    const moduleOnlyBaseArchive = path.join(
-      root,
-      "archives",
-      "module-only-base",
-      "liboliphaunt-1.0.0-runtime-resources-ios-datum64.tar.gz",
-    );
-    await tarDirectory(path.dirname(moduleOnlyBaseRoot), moduleOnlyBaseArchive, "oliphaunt");
-    moduleOnlyBase.base.assets = await Promise.all(
-      moduleOnlyBase.base.assets.map(async (row) => row.role === "runtime-resources"
-        ? asset("runtime-resources", moduleOnlyBaseArchive, "tar.gz", "oliphaunt")
-        : row),
-    );
-    await expectCarrierFailure(
-      "module-only-selection-in-base-runtime",
-      moduleOnlyBase,
-      [],
-      /base React Native iOS carrier is not extension-free/u,
-    );
-
-    const missingRootEnvelopeField = structuredClone(carrier);
-    delete missingRootEnvelopeField.carriers;
-    await expectCarrierFailure(
-      "missing-root-envelope-field",
-      missingRootEnvelopeField,
-      [],
-      /fields must be exactly base,carriers,extensions,legal,schema; got base,extensions,legal,schema/u,
-    );
-
-    const traversingLegalMember = structuredClone(carrier);
-    traversingLegalMember.legal.base[0].files[0].member = "../outside-license";
-    await expectCarrierFailure(
-      "traversing-legal-member",
-      traversingLegalMember,
-      [],
-      /not a safe archive-relative path/u,
-    );
-
-    const collidingLegalMember = structuredClone(carrier);
-    const collidingFiles = collidingLegalMember.legal.base[0].files;
-    collidingFiles.at(-1).member = collidingFiles[0].member.toLowerCase();
-    collidingFiles.sort((left, right) => compareText(left.member, right.member));
-    await expectCarrierFailure(
-      "colliding-legal-member",
-      collidingLegalMember,
-      [],
-      /colliding legal members/u,
-    );
-
-    const missingCarrierEnvelopeField = structuredClone(carrier);
-    delete missingCarrierEnvelopeField.carriers[0].bytes;
-    await expectCarrierFailure(
-      "missing-carrier-envelope-field",
-      missingCarrierEnvelopeField,
-      [],
-      /fields must be exactly bytes,format,name,sha256,url; got format,name,sha256,url/u,
-    );
-
-    const missingLogicalEnvelopeField = structuredClone(carrier);
-    delete missingLogicalEnvelopeField.extensions[0].assets[0].member;
-    await expectCarrierFailure(
-      "missing-logical-envelope-field",
-      missingLogicalEnvelopeField,
-      ["auto_explain"],
-      /fields must be exactly bytes,carrier,format,member,path,role,sha256; got bytes,carrier,format,path,role,sha256/u,
-    );
-
-    const missingFrozenContentField = structuredClone(carrier);
-    delete missingFrozenContentField.extensions.find(
-      ({ sqlName }) => sqlName === "pgtap",
-    ).dataFiles;
-    await expectCarrierFailure(
-      "missing-frozen-extension-content-field",
-      missingFrozenContentField,
-      ["pgtap"],
-      /fields must be exactly .*dataFiles.*; got .*[^A-Za-z]dependencies/u,
-    );
-
-    const nonCanonicalFrozenList = structuredClone(carrier);
-    nonCanonicalFrozenList.extensions.find(
-      ({ sqlName }) => sqlName === "pgtap",
-    ).extensionSqlFilePrefixes.reverse();
-    await expectCarrierFailure(
-      "non-canonical-frozen-extension-list",
-      nonCanonicalFrozenList,
-      ["pgtap"],
-      /extensionSqlFilePrefixes must be sorted in ordinal order/u,
-    );
-
-    const selfDependentFrozenContract = structuredClone(carrier);
-    selfDependentFrozenContract.extensions.find(
-      ({ sqlName }) => sqlName === "pgtap",
-    ).dependencies = ["pgtap"];
-    await expectCarrierFailure(
-      "self-dependent-frozen-extension-contract",
-      selfDependentFrozenContract,
-      ["pgtap"],
-      /dependencies must not include pgtap itself/u,
-    );
-
-    const dottedFrozenSqlPrefix = structuredClone(carrier);
-    dottedFrozenSqlPrefix.extensions.find(
-      ({ sqlName }) => sqlName === "pgtap",
-    ).extensionSqlFilePrefixes = ["pgtap.core"];
-    await expectCarrierFailure(
-      "dotted-frozen-extension-sql-prefix",
-      dottedFrozenSqlPrefix,
-      ["pgtap"],
-      /dot-free portable SQL basename prefix/u,
-    );
-
-    async function expectCacheComponentSymlinkFailure(name, component, candidate, extensions) {
-      const file = path.join(root, `${name}.json`);
-      const cacheDir = path.join(root, `${name}-cache`);
-      const redirected = path.join(root, `${name}-redirected`);
-      await write(file, `${JSON.stringify(candidate, null, 2)}\n`);
-      await fs.mkdir(cacheDir, { recursive: true });
-      await fs.mkdir(redirected, { recursive: true });
-      await fs.symlink(redirected, path.join(cacheDir, component), "dir");
-      await expectReject(
-        () => stageIosApp({
-          allowFileUrls: true,
-          cacheDir,
-          carriers: [file],
-          extensions,
-          outputDir: path.join(root, `${name}-output`),
-        }),
-        /cache path component must be a real directory, not a symlink/u,
-      );
-      assert.deepEqual(
-        await fs.readdir(redirected),
-        [],
-        `rejected ${component} cache symlink must not receive carrier bytes`,
-      );
-    }
-
-    await expectCacheComponentSymlinkFailure(
-      "objects-cache-symlink",
-      "objects",
-      carrier,
-      [],
-    );
-    await expectCacheComponentSymlinkFailure(
-      "extracted-cache-symlink",
-      "extracted",
-      carrier,
-      [],
-    );
-    await expectCacheComponentSymlinkFailure(
-      "payloads-cache-symlink",
-      "payloads",
-      contribBundle,
-      ["cube"],
-    );
-
-    const cacheRootLinkManifest = path.join(root, "cache-root-symlink.json");
-    const cacheRootLink = path.join(root, "cache-root-symlink-cache");
-    const cacheRootRedirected = path.join(root, "cache-root-symlink-redirected");
-    await write(cacheRootLinkManifest, `${JSON.stringify(carrier, null, 2)}\n`);
-    await fs.mkdir(cacheRootRedirected, { recursive: true });
-    await fs.symlink(cacheRootRedirected, cacheRootLink, "dir");
-    await expectReject(
-      () => stageIosApp({
-        allowFileUrls: true,
-        cacheDir: cacheRootLink,
-        carriers: [cacheRootLinkManifest],
-        extensions: [],
-        outputDir: path.join(root, "cache-root-symlink-output"),
-      }),
-      /cache root must be a real directory, not a symlink/u,
-    );
-    assert.deepEqual(
-      await fs.readdir(cacheRootRedirected),
-      [],
-      "rejected cache-root symlink must not receive carrier bytes",
-    );
-
-    await expectResourceManifestFailure(
-      "missing-native-runtime-product",
-      (manifest) => manifest.replace("nativeRuntimeProduct=liboliphaunt-native\n", ""),
-      /is missing nativeRuntimeProduct/u,
-    );
-    await expectResourceManifestFailure(
-      "missing-native-runtime-version",
-      (manifest) => manifest.replace("nativeRuntimeVersion=1.0.0\n", ""),
-      /is missing nativeRuntimeVersion/u,
-    );
-    await expectResourceManifestFailure(
-      "wrong-native-runtime-product",
-      (manifest) => manifest.replace(
-        "nativeRuntimeProduct=liboliphaunt-native",
-        "nativeRuntimeProduct=liboliphaunt-wasix",
-      ),
-      /must declare nativeRuntimeProduct=liboliphaunt-native; got liboliphaunt-wasix/u,
-    );
-    await expectResourceManifestFailure(
-      "wrong-native-target",
-      (manifest) => manifest.replace(
-        "nativeTarget=ios-xcframework",
-        "nativeTarget=linux-x64-gnu",
-      ),
-      /must declare nativeTarget=ios-xcframework; got linux-x64-gnu/u,
-    );
-    await expectResourceManifestFailure(
-      "wrong-native-runtime-version",
-      (manifest) => manifest.replace("nativeRuntimeVersion=1.0.0", "nativeRuntimeVersion=9.9.9"),
-      /must declare nativeRuntimeVersion=1\.0\.0; got 9\.9\.9/u,
-    );
-    await expectResourceManifestFailure(
-      "unstable-native-runtime-version",
-      (manifest) => manifest.replace(
-        "nativeRuntimeVersion=1.0.0",
-        "nativeRuntimeVersion=1.0.0-rc.1",
-      ),
-      /nativeRuntimeVersion must be a stable SemVer X\.Y\.Z version/u,
-    );
-    await expectResourceManifestFailure(
-      "unknown-extension-manifest-field",
-      (manifest) => manifest.replace("files=files\n", "unsupportedFutureField=value\nfiles=files\n"),
-      /contains unsupported field\(s\): unsupportedFutureField/u,
-    );
-    await expectResourceManifestFailure(
-      "missing-extension-canonical-field",
-      (manifest) => manifest.replace("nativeModuleFile=\n", ""),
-      /must declare nativeModuleFile=; got /u,
-    );
-    await expectResourceManifestFailure(
-      "missing-extension-sql-file-names",
-      (manifest) => manifest.replace("extensionSqlFileNames=uninstall_pgtap.sql\n", ""),
-      /is missing extensionSqlFileNames/u,
-    );
-    await expectResourceManifestFailure(
-      "wrong-extension-sql-file-prefixes",
-      (manifest) => manifest.replace(
-        "extensionSqlFilePrefixes=pgtap-core,pgtap-schema",
-        "extensionSqlFilePrefixes=pgtap-core,wildcard-trust",
-      ),
-      /extensionSqlFilePrefixes must exactly match the frozen carrier contract for pgtap/u,
-    );
-    await expectResourceManifestFailure(
-      "wrong-extension-native-module-file",
-      (manifest) => manifest.replace("nativeModuleFile=\n", "nativeModuleFile=other.dylib\n"),
-      /must declare nativeModuleFile=; got other\.dylib/u,
-    );
-    await expectResourceManifestFailure(
-      "wrong-extension-static-symbol-prefix",
-      (manifest) => manifest.replace(
-        "staticSymbolPrefix=\n",
-        "staticSymbolPrefix=oliphaunt_static_other\n",
-      ),
-      /must declare staticSymbolPrefix=; got oliphaunt_static_other/u,
-    );
-    await expectResourceManifestFailure(
-      "unselected-extension-static-symbol-alias",
-      (manifest) => manifest.replace("staticSymbolAliases=", "staticSymbolAliases=sql_symbol:linked_symbol"),
-      /must declare staticSymbolAliases=; got sql_symbol:linked_symbol/u,
-    );
-
-    const undeclaredExtensionFiles = structuredClone(carrier);
-    replaceExtensionAssets(undeclaredExtensionFiles, "pgtap", [
-      await extendedExtensionRuntime(
-        root,
-        "pgtap",
-        "undeclared-extension-files.tar.gz",
-        {
-          "files/share/postgresql/extension/evil--1.0.sql": "SELECT 'undeclared';\n",
-          "files/share/postgresql/extension/evil.control": "default_version = '1.0'\n",
-        },
-      ),
-    ]);
-    await expectCarrierFailure(
-      "undeclared-extension-files",
-      undeclaredExtensionFiles,
-      ["pgtap"],
-      /extension artifact inventory must be exact; .*extra=.*evil/u,
-    );
-
-    const undeclaredPrefixedNonSql = structuredClone(carrier);
-    replaceExtensionAssets(undeclaredPrefixedNonSql, "pgtap", [
-      await extendedExtensionRuntime(
-        root,
-        "pgtap",
-        "undeclared-prefixed-non-sql.tar.gz",
-        {
-          "files/share/postgresql/extension/pgtap-core-evil.control":
-            "default_version = '1.0'\n",
-        },
-      ),
-    ]);
-    await expectCarrierFailure(
-      "undeclared-prefixed-non-sql",
-      undeclaredPrefixedNonSql,
-      ["pgtap"],
-      /extension artifact inventory must be exact; .*extra=.*pgtap-core-evil\.control/u,
-    );
-
-    const ancillaryOnly = structuredClone(carrier);
-    replaceExtensionAssets(ancillaryOnly, "pgtap", [
-      await mutatedExtensionRuntime(
-        root,
-        "pgtap",
-        "ancillary-only-pgtap.tar.gz",
-        async (stage) => {
-          const extensionDirectory = path.join(stage, "files", "share", "postgresql", "extension");
-          for (const name of await fs.readdir(extensionDirectory)) {
-            if (name === "pgtap.sql" || /^pgtap--.*\.sql$/u.test(name)) {
-              await fs.rm(path.join(extensionDirectory, name));
-            }
-          }
-          await write(path.join(extensionDirectory, "uninstall_pgtap.sql"), "SELECT 'ancillary only';\n");
-        },
-      ),
-    ]);
-    await expectCarrierFailure(
-      "ancillary-only-install-sql",
-      ancillaryOnly,
-      ["pgtap"],
-      /missing an install SQL file owned by pgtap/u,
-    );
-
-    const updateOnly = structuredClone(carrier);
-    replaceExtensionAssets(updateOnly, "pgtap", [
-      await mutatedExtensionRuntime(
-        root,
-        "pgtap",
-        "update-only-pgtap.tar.gz",
-        async (stage) => {
-          await fs.rm(
-            path.join(
-              stage,
-              "files",
-              "share",
-              "postgresql",
-              "extension",
-              "pgtap--1.0.sql",
-            ),
-          );
-        },
-      ),
-    ]);
-    await expectCarrierFailure(
-      "update-only-install-sql",
-      updateOnly,
-      ["pgtap"],
-      /missing an install SQL file owned by pgtap/u,
-    );
-
-    const nonDigitVersion = structuredClone(carrier);
-    replaceExtensionAssets(nonDigitVersion, "pgtap", [
-      await mutatedExtensionRuntime(
-        root,
-        "pgtap",
-        "non-digit-version-pgtap.tar.gz",
-        async (stage) => {
-          const extensionDirectory = path.join(
-            stage,
-            "files",
-            "share",
-            "postgresql",
-            "extension",
-          );
-          await fs.rm(path.join(extensionDirectory, "pgtap--1.0.sql"));
-          await write(path.join(extensionDirectory, "pgtap--beta.sql"), "SELECT 'invalid';\n");
-        },
-      ),
-    ]);
-    await expectCarrierFailure(
-      "non-digit-install-version",
-      nonDigitVersion,
-      ["pgtap"],
-      /missing an install SQL file owned by pgtap/u,
-    );
-
-    const wrongDependencyArchive = structuredClone(carrier);
-    replaceExtensionRuntimeAsset(
-      wrongDependencyArchive,
-      "postgis",
-      await mutatedExtensionRuntime(
-        root,
-        "postgis",
-        "wrong-dependency-archive-name.tar.gz",
-        async (stage) => {
-          const manifestFile = path.join(stage, "manifest.properties");
-          const manifest = await fs.readFile(manifestFile, "utf8");
-          await fs.writeFile(
-            manifestFile,
-            manifest.replace(
-              "/dependencies/geos/libgeos.a",
-              "/dependencies/geos/arbitrary.a",
-            ),
-          );
-        },
-      ),
-    );
-    await expectCarrierFailure(
-      "wrong-dependency-archive-name",
-      wrongDependencyArchive,
-      ["postgis"],
-      /must name a portable static archive lib\*\.a directly under .*\/dependencies\/geos/u,
-    );
-
-    const skewedDependencyArchive = structuredClone(carrier);
-    replaceExtensionRuntimeAsset(
-      skewedDependencyArchive,
-      "pgcrypto",
-      await mutatedExtensionRuntime(
-        root,
-        "pgcrypto",
-        "skewed-dependency-archive-name.tar.gz",
-        async (stage) => {
-          const manifestFile = path.join(stage, "manifest.properties");
-          const manifest = await fs.readFile(manifestFile, "utf8");
-          await fs.writeFile(
-            manifestFile,
-            manifest.replace(
-              "/dependencies/openssl/libcrypto.a",
-              "/dependencies/openssl/libssl.a",
-            ),
-          );
-        },
-      ),
-    );
-    await expectCarrierFailure(
-      "skewed-dependency-archive-name",
-      skewedDependencyArchive,
-      ["pgcrypto"],
-      /must use the same archive file name across both iOS static targets for dependency openssl/u,
-    );
-
-    const oversizedEnvelope = structuredClone(carrier);
-    oversizedEnvelope.base.assets[0].bytes = 2 * 1024 * 1024 * 1024 + 1;
-    await expectCarrierFailure(
-      "oversized-carrier-envelope",
-      oversizedEnvelope,
-      [],
-      /exceeds the maximum supported size/u,
-    );
-
-    const oversizedTar = path.join(root, "archives", "oversized-member.tar.gz");
-    await craftedTar(oversizedTar, [{ name: "payload", type: "file" }]);
-    await rewriteFirstTarSize(oversizedTar, 4 * 1024 * 1024 * 1024);
-    const oversizedTarCarrier = structuredClone(carrier);
-    replaceExtensionAssets(oversizedTarCarrier, "pgtap", [
-      await logicalAsset("runtime-resources", oversizedTar, "tar.gz", "."),
-    ]);
-    await expectCarrierFailure(
-      "oversized-archive-member",
-      oversizedTarCarrier,
-      ["pgtap"],
-      /exceeds the maximum expanded member size/u,
-    );
-
-    // ICU ships thousands of small locale/resource files. Prove that its
-    // validated role receives the narrowly scoped higher ceiling while the
-    // same archive remains forbidden for ordinary runtime carriers.
-    const highCardinalityIcuArchive = path.join(
-      root,
-      "archives",
-      "liboliphaunt-1.0.0-high-cardinality-icu-data.tar.gz",
-    );
-    await highCardinalityIcuTar(
-      highCardinalityIcuArchive,
-      4098,
-      path.join(root, "source", "base", "icu"),
-    );
-    const highCardinalityIcu = structuredClone(carrier);
-    highCardinalityIcu.base.assets = await Promise.all(
-      highCardinalityIcu.base.assets.map(async (row) => row.role === "icu-data"
-        ? asset("icu-data", highCardinalityIcuArchive, "tar.gz", ".")
-        : row),
-    );
-    await expectCarrierFailure(
-      "high-cardinality-icu",
-      highCardinalityIcu,
-      [],
-      /does not match the target runtime's cluster-seed-icu/u,
-      { icu: true },
-    );
-
-    const highCardinalityRuntime = structuredClone(carrier);
-    const highCardinalityRuntimeArchive = path.join(
-      root,
-      "archives",
-      "high-cardinality-runtime",
-      "liboliphaunt-1.0.0-runtime-resources-ios-datum64.tar.gz",
-    );
-    await fs.mkdir(path.dirname(highCardinalityRuntimeArchive), { recursive: true });
-    await fs.copyFile(highCardinalityIcuArchive, highCardinalityRuntimeArchive);
-    highCardinalityRuntime.base.assets = await Promise.all(
-      highCardinalityRuntime.base.assets.map(async (row) => row.role === "runtime-resources"
-        ? asset(
-            "runtime-resources",
-            highCardinalityRuntimeArchive,
-            "tar.gz",
-            "share/icu",
-          )
-        : row),
-    );
-    await expectCarrierFailure(
-      "high-cardinality-non-icu",
-      highCardinalityRuntime,
-      [],
-      /exceeds the maximum supported 4096 archive entries/u,
-    );
-
-    const highCardinalityFrameworkArchive = path.join(
-      root,
-      "archives",
-      "liboliphaunt-1.0.0-high-cardinality.xcframework.zip",
-    );
-    const baseFrameworkAsset = carrier.base.assets.find(({ role }) => role === "base-xcframework");
-    await fs.copyFile(fileURLToPath(baseFrameworkAsset.url), highCardinalityFrameworkArchive);
-    await appendZipFiles(
-      highCardinalityFrameworkArchive,
-      "liboliphaunt.xcframework/ios-arm64/liboliphaunt.framework/Resources/oliphaunt/high-cardinality",
-      8192,
-    );
-    const highCardinalityFramework = structuredClone(carrier);
-    highCardinalityFramework.base.assets = await Promise.all(
-      highCardinalityFramework.base.assets.map(async (row) => row.role === "base-xcframework"
-        ? asset(
-            "base-xcframework",
-            highCardinalityFrameworkArchive,
-            "zip",
-            "liboliphaunt.xcframework",
-          )
-        : row),
-    );
-    const highCardinalityFrameworkCarrierFile = path.join(root, "high-cardinality-framework.json");
-    await write(
-      highCardinalityFrameworkCarrierFile,
-      `${JSON.stringify(highCardinalityFramework, null, 2)}\n`,
-    );
-    const highCardinalityFrameworkOutput = path.join(root, "high-cardinality-framework-output");
-    await stageIosApp({
-      allowFileUrls: true,
-      cacheDir: path.join(root, "high-cardinality-framework-cache"),
-      carriers: [highCardinalityFrameworkCarrierFile],
-      extensions: [],
-      icu: false,
-      outputDir: highCardinalityFrameworkOutput,
-    });
-    await fs.access(path.join(
-      highCardinalityFrameworkOutput,
-      "frameworks",
-      "base",
-      "liboliphaunt.xcframework",
-      "Info.plist",
-    ));
-
-    const traversalArchive = path.join(root, "archives", "malicious-traversal.zip");
-    await maliciousZip(traversalArchive, "../escaped-from-rn.txt", "file");
-    const traversal = structuredClone(carrier);
-    traversal.base.assets = await Promise.all(traversal.base.assets.map(async (row) => row.role === "base-xcframework"
-      ? asset("base-xcframework", traversalArchive, "zip", "liboliphaunt.xcframework")
-      : row));
-    await expectCarrierFailure("malicious-traversal", traversal, [], /not a safe archive-relative path/u);
-    await assert.rejects(fs.access(path.join(root, "malicious-traversal-cache", "extracted", "escaped-from-rn.txt")));
-
-    const symlinkArchive = path.join(root, "archives", "malicious-symlink.zip");
-    await maliciousZip(symlinkArchive, "liboliphaunt.xcframework", "symlink");
-    const symlink = structuredClone(carrier);
-    symlink.base.assets = await Promise.all(symlink.base.assets.map(async (row) => row.role === "base-xcframework"
-      ? asset("base-xcframework", symlinkArchive, "zip", "liboliphaunt.xcframework")
-      : row));
-    await expectCarrierFailure("malicious-symlink", symlink, [], /link or special entry/u);
-
-    const ambiguousUnixArchive = path.join(root, "archives", "ambiguous-unix-types.zip");
-    await metadataZip(ambiguousUnixArchive, "ambiguous-unix");
-    const ambiguousUnix = structuredClone(carrier);
-    ambiguousUnix.base.assets = await Promise.all(ambiguousUnix.base.assets.map(async (row) => row.role === "base-xcframework"
-      ? asset("base-xcframework", ambiguousUnixArchive, "zip", "liboliphaunt.xcframework")
-      : row));
-    await expectCarrierFailure("ambiguous-unix-types", ambiguousUnix, [], /ambiguous Unix member type/u);
-
-    const fatArchive = path.join(root, "archives", "fat-types.zip");
-    await metadataZip(
-      fatArchive,
-      "fat",
-      path.join(root, "source", "base", "framework", "liboliphaunt.xcframework"),
-    );
-    const fat = structuredClone(carrier);
-    fat.base.assets = await Promise.all(fat.base.assets.map(async (row) => row.role === "base-xcframework"
-      ? asset("base-xcframework", fatArchive, "zip", "liboliphaunt.xcframework")
-      : row));
-    const fatCarrierFile = path.join(root, "fat-types.json");
-    await write(fatCarrierFile, `${JSON.stringify(fat, null, 2)}\n`);
-    const fatOutput = path.join(root, "fat-types-output");
-    await stageIosApp({
-      allowFileUrls: true,
-      cacheDir: path.join(root, "fat-types-cache"),
-      carriers: [fatCarrierFile],
-      extensions: [],
-      icu: false,
-      outputDir: fatOutput,
-    });
-    await fs.access(path.join(fatOutput, "frameworks", "base", "liboliphaunt.xcframework", "Info.plist"));
-
-    const unicodeExtraArchive = path.join(root, "archives", "unicode-path-extra.zip");
-    await metadataZip(unicodeExtraArchive, "unicode-extra");
-    const unicodeExtra = structuredClone(carrier);
-    unicodeExtra.base.assets = await Promise.all(unicodeExtra.base.assets.map(async (row) => row.role === "base-xcframework"
-      ? asset("base-xcframework", unicodeExtraArchive, "zip", "liboliphaunt.xcframework")
-      : row));
-    await expectCarrierFailure(
-      "unicode-path-extra",
-      unicodeExtra,
-      [],
-      /unsupported ZIP .* extra metadata .* field 0x7075/u,
-    );
-
-    const unsupportedFlagsArchive = path.join(root, "archives", "unsupported-flags.zip");
-    await metadataZip(unsupportedFlagsArchive, "fat");
-    await addUnsupportedZipFlag(unsupportedFlagsArchive);
-    const unsupportedFlags = structuredClone(carrier);
-    unsupportedFlags.base.assets = await Promise.all(unsupportedFlags.base.assets.map(async (row) => row.role === "base-xcframework"
-      ? asset("base-xcframework", unsupportedFlagsArchive, "zip", "liboliphaunt.xcframework")
-      : row));
-    await expectCarrierFailure(
-      "unsupported-flags",
-      unsupportedFlags,
-      [],
-      /unsupported ZIP general-purpose flags 0x20/u,
-    );
-
-    for (const [name, entries, pattern] of [
-      ["tar-file-directory-marker", [{ name: "payload", type: "file" }], /member type\/path marker mismatch/u],
-      ["tar-traversal", [{ name: "../payload", type: "file" }], /not a safe archive-relative path/u],
-      ["tar-symlink", [{ name: "payload", type: "symlink" }], /link or special entry/u],
-      ["tar-duplicate", [{ name: "payload", type: "file" }, { name: "payload", type: "file" }], /repeats a normalized archive member/u],
-      ["tar-case-collision", [{ name: "Payload", type: "file" }, { name: "payload", type: "file" }], /case-colliding archive members/u],
-      ["tar-file-as-parent", [{ name: "parent", type: "file" }, { name: "parent/child", type: "file" }], /uses file parent as an archive directory/u],
-    ]) {
-      const archive = path.join(root, "archives", `${name}.tar.gz`);
-      await craftedTar(archive, entries);
-      if (name === "tar-file-directory-marker") await addTarFileSlash(archive, "payload");
-      const candidate = structuredClone(carrier);
-      replaceExtensionAssets(candidate, "pgtap", [
-        await logicalAsset("runtime-resources", archive, "tar.gz", "."),
-      ]);
-      await expectCarrierFailure(name, candidate, ["pgtap"], pattern);
-    }
-
-    const unstable = structuredClone(carrier);
-    unstable.base.version = "1.0.0-rc.1";
-    unstable.base.tag = "liboliphaunt-native-v1.0.0-rc.1";
-    await expectCarrierFailure("unstable-version", unstable, [], /stable SemVer/u);
-
-    const leadingZero = structuredClone(carrier);
-    leadingZero.extensions.find(({ sqlName }) => sqlName === "pgtap").version = "01.0.0";
-    leadingZero.extensions.find(({ sqlName }) => sqlName === "pgtap").tag =
-      "oliphaunt-extension-pgtap-v01.0.0";
-    await expectCarrierFailure("leading-zero-version", leadingZero, ["pgtap"], /stable SemVer/u);
-
-    const fakeOwner = structuredClone(carrier);
-    fakeOwner.extensions.find(({ sqlName }) => sqlName === "cube").product =
-      "oliphaunt-extension-fake-cube";
-    fakeOwner.extensions.find(({ sqlName }) => sqlName === "cube").tag =
-      "oliphaunt-extension-fake-cube-v1.0.0";
-    await expectCarrierFailure(
-      "fake-owner",
-      fakeOwner,
-      ["cube"],
-      /product must be canonical artifact product oliphaunt-extension-contrib-pg18/u,
-    );
-
-    const ownerVersionConflict = structuredClone(carrier);
-    ownerVersionConflict.extensions.find(({ sqlName }) => sqlName === "earthdistance").version =
-      "1.0.1";
-    ownerVersionConflict.extensions.find(({ sqlName }) => sqlName === "earthdistance").tag =
-      "liboliphaunt-native-v1.0.1";
-    await expectCarrierFailure(
-      "owner-version-conflict",
-      ownerVersionConflict,
-      ["earthdistance"],
-      /conflicting release versions for owner liboliphaunt-native/u,
-    );
-
-    const wrongTag = structuredClone(carrier);
-    wrongTag.extensions.find(({ sqlName }) => sqlName === "pgtap").tag = "unrelated-v1.0.0";
-    await expectCarrierFailure("wrong-tag", wrongTag, ["pgtap"], /\.tag must be oliphaunt-extension-pgtap-v1\.0\.0/u);
-
-    const malformedAssets = structuredClone(carrier);
-    malformedAssets.extensions.find(({ sqlName }) => sqlName === "pgtap").assets = {};
-    await expectCarrierFailure("malformed-assets", malformedAssets, ["pgtap"], /\.assets must be an array/u);
-
-    const malformedRegistration = structuredClone(carrier);
-    malformedRegistration.extensions.find(({ sqlName }) => sqlName === "cube").registration.symbols = "not-an-array";
-    await expectCarrierFailure("malformed-registration", malformedRegistration, ["cube"], /registration\.symbols must be an array/u);
-
-    const duplicateLocator = structuredClone(carrier);
-    const duplicateLocatorPostgis = duplicateLocator.extensions.find(({ sqlName }) => sqlName === "postgis");
-    duplicateLocatorPostgis.assets.push(structuredClone(duplicateLocatorPostgis.assets[0]));
-    await expectCarrierFailure(
-      "duplicate-asset-locator",
-      duplicateLocator,
-      ["postgis"],
-      /repeats an asset locator identity/u,
-    );
-
-    const duplicateIdentity = structuredClone(carrier);
-    const duplicateIdentityPostgis = duplicateIdentity.extensions.find(({ sqlName }) => sqlName === "postgis");
-    const geosAsset = duplicateIdentityPostgis.assets.find(({ role }) => role === "dependency-xcframework");
-    const geosEnvelope = duplicateIdentity.carriers.find(({ name }) => name === geosAsset.carrier);
-    const duplicateGeosArchive = path.join(root, "archives", "postgis-geos-duplicate.zip");
-    await fs.copyFile(new URL(geosEnvelope.url), duplicateGeosArchive);
-    const duplicateGeos = await logicalAsset(
-      "dependency-xcframework",
-      duplicateGeosArchive,
-      "zip",
-      `nested/${path.posix.basename(geosAsset.member)}`,
-    );
-    duplicateIdentityPostgis.assets.push(duplicateGeos.locator);
-    duplicateIdentity.carriers.push(duplicateGeos.envelope);
-    await expectCarrierFailure(
-      "duplicate-dependency-identity",
-      duplicateIdentity,
-      ["postgis"],
-      /repeats a dependency carrier identity/u,
-    );
-
-    await expectReject(
-      () => stageIosApp({ carriers: [carrierFile], extensions: [], outputDir: path.join(root, "https-only") }),
-      /must use HTTPS/u,
-    );
-
-    const missingDependencyFile = path.join(root, "missing-dependency.json");
-    await write(
-      missingDependencyFile,
-      `${JSON.stringify({
-        base: carrier.base,
-        carriers: carrier.carriers.filter(({ name }) =>
-          carrier.extensions
-            .find(({ sqlName }) => sqlName === "earthdistance")
-            .assets.some(({ carrier: carrierName }) => carrierName === name)),
-        extensions: carrier.extensions.filter(({ sqlName }) => sqlName === "earthdistance"),
-        legal: {
-          base: carrier.legal.base,
-          extensions: carrier.legal.extensions.filter(({ sqlName }) => sqlName === "earthdistance"),
-        },
-        schema: SCHEMA,
-      }, null, 2)}\n`,
-    );
-    await expectReject(
-      () => stageIosApp({
-        allowFileUrls: true,
-        cacheDir: path.join(root, "missing-cache"),
-        carriers: [missingDependencyFile],
-        extensions: ["earthdistance"],
-        outputDir: path.join(root, "missing-output"),
-      }),
-      /missing iOS carrier for cube required by earthdistance/u,
-    );
-
-    const tampered = structuredClone(carrier);
-    tampered.base.assets.find(({ role }) => role === "runtime-resources").sha256 = "0".repeat(64);
-    const tamperedFile = path.join(root, "tampered.json");
-    await write(tamperedFile, `${JSON.stringify(tampered, null, 2)}\n`);
-    await expectReject(
-      () => stageIosApp({
-        allowFileUrls: true,
-        cacheDir: path.join(root, "tampered-cache"),
-        carriers: [tamperedFile],
-        extensions: [],
-        outputDir: path.join(root, "tampered-output"),
-      }),
-      /checksum mismatch/u,
-    );
-
-    const carrierLeafDependencySkew = structuredClone(carrier);
-    const omittedPostgis = carrierLeafDependencySkew.extensions.find(
-      ({ sqlName }) => sqlName === "postgis",
-    );
-    omittedPostgis.nativeDependencies = omittedPostgis.nativeDependencies.filter(
-      (dependency) => dependency !== "geos",
-    );
-    omittedPostgis.assets = omittedPostgis.assets.filter(
-      ({ member, role }) =>
-        !(role === "dependency-xcframework" && member.endsWith("dependency_geos.xcframework")),
-    );
-    retainReferencedCarriers(carrierLeafDependencySkew);
-    await expectCarrierFailure(
-      "carrier-leaf-dependency-skew",
-      carrierLeafDependencySkew,
-      ["postgis"],
-      /mobileStaticDependencyArchives must exactly cover both iOS static targets/u,
-    );
-
-    const wrongInventory = structuredClone(carrier);
-    const postgis = wrongInventory.extensions.find(({ sqlName }) => sqlName === "postgis");
-    postgis.assets = postgis.assets.filter(({ role }) => role !== "dependency-xcframework");
-    retainReferencedCarriers(wrongInventory);
-    const wrongInventoryFile = path.join(root, "wrong-inventory.json");
-    await write(wrongInventoryFile, `${JSON.stringify(wrongInventory, null, 2)}\n`);
-    await expectReject(
-      () => stageIosApp({
-        allowFileUrls: true,
-        cacheDir: path.join(root, "inventory-cache"),
-        carriers: [wrongInventoryFile],
-        extensions: ["postgis"],
-        outputDir: path.join(root, "inventory-output"),
-      }),
-      /dependency-xcframework roles do not exactly match nativeDependencies/u,
-    );
-
-    console.log("stage-ios-app.test.mjs: carrier, malicious ZIP, cache-tamper, and payload checks passed");
-  } finally {
-    await fs.rm(root, { force: true, recursive: true });
-  }
-}
-
-main().catch((error) => {
-  console.error(error instanceof Error ? error.stack : String(error));
-  process.exit(1);
-});
diff --git a/src/sdks/react-native/tools/stage-ios-app.test.mts b/src/sdks/react-native/tools/stage-ios-app.test.mts
new file mode 100755
index 000000000..b097682eb
--- /dev/null
+++ b/src/sdks/react-native/tools/stage-ios-app.test.mts
@@ -0,0 +1,2334 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import fs from 'node:fs/promises';
+import { createRequire } from 'node:module';
+import os from 'node:os';
+import path from 'node:path';
+import { fileURLToPath, pathToFileURL } from 'node:url';
+import { gunzipSync, gzipSync } from 'node:zlib';
+import { archiveDirectory } from '../../../../tools/packaging/archive-directory.mts';
+import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts';
+import { craftedTar, tarArchive } from '../../../../tools/packaging/testdata/tar-fixture.mts';
+import {
+  fixtureFiles,
+  maliciousZip,
+  metadataZip,
+  zipArchive,
+} from '../../../../tools/packaging/testdata/zip-fixture.mts';
+import { parseProperties } from './native-resource-closure.mts';
+import { stageIosApp } from './stage-ios-app.mts';
+import { validateStagedPackage } from './verify-ios-package.mts';
+
+const { stageIosAppPayload } = createRequire(import.meta.url)('../app.plugin.cts');
+const SCHEMA = 'oliphaunt-react-native-ios-carrier-v1';
+assert.throws(
+  () => parseProperties('schema=one\nschema=two\n', 'duplicate.properties'),
+  /repeats schema/u,
+);
+const GENERATED_EXTENSION_CATALOG = JSON.parse(
+  await fs.readFile(
+    await Promise.any(
+      [
+        new URL('../src/generated/extensions.json', import.meta.url),
+        new URL('../../../extensions/generated/sdk/extensions.json', import.meta.url),
+      ].map(async (url) => {
+        await fs.access(url);
+        return url;
+      }),
+    ),
+    'utf8',
+  ),
+);
+const GENERATED_EXTENSION_BY_SQL_NAME = new Map(
+  GENERATED_EXTENSION_CATALOG.extensions.map((row) => [row['sql-name'], row]),
+);
+const GENERATED_IOS_DEPENDENCIES_BY_SQL_NAME = new Map(
+  JSON.parse(
+    await fs.readFile(
+      await Promise.any(
+        [
+          new URL('../src/generated/ios-static-dependencies.json', import.meta.url),
+          new URL(
+            '../../../extensions/generated/sdk/ios-static-dependencies.json',
+            import.meta.url,
+          ),
+        ].map(async (url) => {
+          await fs.access(url);
+          return url;
+        }),
+      ),
+      'utf8',
+    ),
+  ).extensions.map((row) => [row['sql-name'], row['static-dependencies']]),
+);
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+async function write(file, contents) {
+  await fs.mkdir(path.dirname(file), { recursive: true });
+  await fs.writeFile(file, contents);
+}
+
+async function sha256(file) {
+  return createHash('sha256')
+    .update(await fs.readFile(file))
+    .digest('hex');
+}
+
+async function asset(role, file, format, member) {
+  const stat = await fs.stat(file);
+  return {
+    bytes: stat.size,
+    format,
+    member,
+    name: path.basename(file),
+    role,
+    sha256: await sha256(file),
+    url: pathToFileURL(file).href,
+  };
+}
+
+async function logicalAsset(role, file, format, member) {
+  const direct = await asset(role, file, format, member);
+  return {
+    envelope: {
+      bytes: direct.bytes,
+      format: direct.format,
+      name: direct.name,
+      sha256: direct.sha256,
+      url: direct.url,
+    },
+    locator: {
+      bytes: direct.bytes,
+      carrier: direct.name,
+      format: direct.format,
+      member: direct.member,
+      path: '.',
+      role: direct.role,
+      sha256: direct.sha256,
+    },
+  };
+}
+
+function retainReferencedCarriers(document) {
+  const referenced = new Set(
+    document.extensions.flatMap((extension) => extension.assets.map(({ carrier }) => carrier)),
+  );
+  document.carriers = document.carriers.filter(({ name }) => referenced.has(name));
+  if (document.legal?.extensions) {
+    const selected = new Set(document.extensions.map(({ sqlName }) => sqlName));
+    document.legal.extensions = document.legal.extensions.filter(({ sqlName }) =>
+      selected.has(sqlName),
+    );
+  }
+  return document;
+}
+
+function replaceExtensionAssets(document, sqlName, replacements) {
+  const row = document.extensions.find((candidate) => candidate.sqlName === sqlName);
+  assert.ok(row, `missing fixture extension ${sqlName}`);
+  const priorNames = new Set(row.assets.map(({ carrier }) => carrier));
+  row.assets = replacements.map(({ locator }) => locator);
+  document.carriers = [
+    ...document.carriers.filter(({ name }) => !priorNames.has(name)),
+    ...replacements.map(({ envelope }) => envelope),
+  ];
+  retainReferencedCarriers(document);
+}
+
+function replaceExtensionRuntimeAsset(document, sqlName, replacement) {
+  const row = document.extensions.find((candidate) => candidate.sqlName === sqlName);
+  assert.ok(row, `missing fixture extension ${sqlName}`);
+  const prior = row.assets.find(({ role }) => role === 'runtime-resources');
+  assert.ok(prior, `missing runtime fixture asset for ${sqlName}`);
+  row.assets = row.assets.map((assetRow) => (assetRow === prior ? replacement.locator : assetRow));
+  document.carriers = [
+    ...document.carriers.filter(({ name }) => name !== prior.carrier),
+    replacement.envelope,
+  ];
+  retainReferencedCarriers(document);
+}
+
+async function tarDirectory(source, archive, member = '.') {
+  await fs.mkdir(path.dirname(archive), { recursive: true });
+  await archiveDirectory(member === '.' ? source : path.join(source, member), archive, {
+    keepParent: member !== '.',
+  });
+}
+
+async function tarMembers(source, archive, members) {
+  await fs.mkdir(path.dirname(archive), { recursive: true });
+  const rows = [];
+  for (const name of (await fs.readdir(source, { recursive: true })).sort()) {
+    if (
+      !members.some((member) => member === '.' || name === member || name.startsWith(`${member}/`))
+    )
+      continue;
+    const file = path.join(source, name);
+    const stat = await fs.lstat(file);
+    assert(stat.isDirectory() || stat.isFile());
+    rows.push({
+      name: stat.isDirectory() ? `${name}/` : name,
+      type: stat.isDirectory() ? '5' : '0',
+      mode: stat.mode & 0o777,
+      data: stat.isDirectory() ? '' : await fs.readFile(file),
+    });
+  }
+  await fs.writeFile(archive, tarArchive(rows));
+}
+
+async function legalFile(root, member, kind, contents = undefined) {
+  const file = path.join(root, ...member.split('/'));
+  await write(file, contents ?? `${member} fixture legal text\n`);
+  const stat = await fs.stat(file);
+  return {
+    bytes: stat.size,
+    kind,
+    member,
+    sha256: await sha256(file),
+  };
+}
+
+async function legalGroup(root, { assetRole, files, profile, spdx }) {
+  const rows = await Promise.all(
+    files.map(({ kind, member, contents }) => legalFile(root, member, kind, contents)),
+  );
+  rows.sort((left, right) => compareText(left.member, right.member));
+  return { assetRole, files: rows, profile, spdx };
+}
+
+async function removeTarDirectorySlash(archive, member) {
+  const tar = gunzipSync(await fs.readFile(archive));
+  let found = false;
+  for (let offset = 0; offset + 512 <= tar.length; ) {
+    const header = tar.subarray(offset, offset + 512);
+    if (header.every((value) => value === 0)) break;
+    const field = (start, length) => {
+      const bytes = header.subarray(start, start + length);
+      const end = bytes.indexOf(0);
+      return bytes.subarray(0, end < 0 ? bytes.length : end).toString('utf8');
+    };
+    const name = field(0, 100);
+    const prefix = field(345, 155);
+    const fullName = prefix ? `${prefix}/${name}` : name;
+    const size = Number.parseInt(field(124, 12).trim() || '0', 8);
+    assert.ok(Number.isSafeInteger(size) && size >= 0, `invalid tar size for ${fullName}`);
+    if (fullName === member) {
+      assert.equal(String.fromCharCode(header[156]), '5', `${member} must be a directory header`);
+      assert.equal(prefix, '', `${member} test helper only supports the ustar name field`);
+      assert.ok(name.endsWith('/'), `${member} must initially use a canonical directory marker`);
+      header[name.length - 1] = 0;
+      header.fill(0x20, 148, 156);
+      const checksum = header.reduce((total, value) => total + value, 0);
+      Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `, 'ascii').copy(header, 148);
+      found = true;
+    }
+    offset += 512 + Math.ceil(size / 512) * 512;
+  }
+  assert.equal(found, true, `missing tar directory ${member}`);
+  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
+}
+
+async function addTarFileSlash(archive, member) {
+  const tar = gunzipSync(await fs.readFile(archive));
+  let found = false;
+  for (let offset = 0; offset + 512 <= tar.length; ) {
+    const header = tar.subarray(offset, offset + 512);
+    if (header.every((value) => value === 0)) break;
+    const end = header.subarray(0, 100).indexOf(0);
+    const name = header.subarray(0, end < 0 ? 100 : end).toString('utf8');
+    const sizeEnd = header.subarray(124, 136).indexOf(0);
+    const size = Number.parseInt(
+      header
+        .subarray(124, sizeEnd < 0 ? 136 : 124 + sizeEnd)
+        .toString('utf8')
+        .trim() || '0',
+      8,
+    );
+    if (name === member) {
+      assert.equal(
+        String.fromCharCode(header[156]),
+        '0',
+        `${member} must be a regular file header`,
+      );
+      assert.ok(member.length < 99, `${member} must leave room for a slash`);
+      header[member.length] = '/'.charCodeAt(0);
+      header[member.length + 1] = 0;
+      header.fill(0x20, 148, 156);
+      const checksum = header.reduce((total, value) => total + value, 0);
+      Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `, 'ascii').copy(header, 148);
+      found = true;
+    }
+    offset += 512 + Math.ceil(size / 512) * 512;
+  }
+  assert.equal(found, true, `missing tar file ${member}`);
+  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
+}
+
+async function zipMember(sourceParent, member, archive) {
+  await fs.mkdir(path.dirname(archive), { recursive: true });
+  await archiveDirectory(path.join(sourceParent, member), archive, { keepParent: true });
+}
+
+async function appendZipFiles(archive, prefix, count) {
+  const rows = [...readPortableArchiveEntries(archive)].map(([, entry]) => ({
+    name: entry.name + (entry.isDirectory ? '/' : ''),
+    data: entry.data(),
+    externalAttributes:
+      (((entry.isDirectory ? 0o40000 : 0o100000) | entry.mode) << 16) |
+      (entry.isDirectory ? 0x10 : 0x20),
+  }));
+  rows.push({
+    name: prefix + '/',
+    data: Buffer.alloc(0),
+    externalAttributes: (0o40755 << 16) | 0x10,
+  });
+  for (let index = 0; index < count; index++)
+    rows.push({
+      name: prefix + '/file-' + String(index).padStart(4, '0'),
+      data: Buffer.alloc(0),
+      externalAttributes: (0o100644 << 16) | 0x20,
+    });
+  await fs.writeFile(archive, zipArchive(rows));
+}
+
+async function addUnsupportedZipFlag(archive) {
+  const buffer = await fs.readFile(archive);
+  const eocd = buffer.length - 22;
+  assert.equal(buffer.readUInt32LE(eocd), 0x06054b50);
+  const centralOffset = buffer.readUInt32LE(eocd + 16);
+  assert.equal(buffer.readUInt32LE(centralOffset), 0x02014b50);
+  const localOffset = buffer.readUInt32LE(centralOffset + 42);
+  assert.equal(buffer.readUInt32LE(localOffset), 0x04034b50);
+  buffer.writeUInt16LE(buffer.readUInt16LE(centralOffset + 8) | 0x20, centralOffset + 8);
+  buffer.writeUInt16LE(buffer.readUInt16LE(localOffset + 6) | 0x20, localOffset + 6);
+  await fs.writeFile(archive, buffer);
+}
+
+async function rewriteFirstTarSize(archive, size) {
+  const tar = gunzipSync(await fs.readFile(archive));
+  const header = tar.subarray(0, 512);
+  const octal = size.toString(8);
+  assert.ok(octal.length <= 11, 'forged tar size must fit the ustar size field');
+  header.fill(0, 124, 136);
+  Buffer.from(`${octal.padStart(11, '0')}\0`, 'ascii').copy(header, 124);
+  header.fill(0x20, 148, 156);
+  const checksum = header.reduce((total, value) => total + value, 0);
+  Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `, 'ascii').copy(header, 148);
+  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
+}
+
+async function baseAssets(root) {
+  const source = path.join(root, 'source', 'base');
+  const runtime = path.join(source, 'runtime', 'oliphaunt');
+  await write(
+    path.join(runtime, 'runtime', 'manifest.properties'),
+    [
+      'schema=oliphaunt-runtime-resources-v1',
+      'cacheKey=fixture-base',
+      'layout=postgres-runtime-files-v1',
+      'artifactRole=runtime',
+      'catalogProfile=',
+      'clusterSeedTarget=ios-datum64',
+      'icuDataTreeSha256=',
+      'mode=native-direct',
+      'selectedExtensions=',
+      'extensions=',
+      'runtimeFeatures=',
+      'sharedPreloadLibraries=',
+      'mobileStaticRegistryState=not-required',
+      'mobileStaticRegistryRegistered=',
+      'mobileStaticRegistryPending=',
+      'nativeModuleStems=',
+      'mobileStaticRegistrySource=',
+      '',
+    ].join('\n'),
+  );
+  await write(
+    path.join(runtime, 'runtime', 'files', 'share', 'postgresql', 'postgres.bki'),
+    'base\n',
+  );
+  await write(
+    path.join(runtime, 'package-size.tsv'),
+    'kind\tid\textensions\tfiles\tbytes\npackage\ttotal\t-\t2\t8\n',
+  );
+
+  const baseFramework = path.join(source, 'framework', 'liboliphaunt.xcframework');
+  await write(path.join(baseFramework, 'Info.plist'), '\n');
+  await write(
+    path.join(baseFramework, 'ios-arm64', 'liboliphaunt.framework', 'liboliphaunt'),
+    'fixture framework binary\n',
+  );
+  await fs.cp(
+    runtime,
+    path.join(baseFramework, 'ios-arm64', 'liboliphaunt.framework', 'Resources', 'oliphaunt'),
+    { recursive: true },
+  );
+
+  const baseLegalSpecs = [
+    {
+      assetRole: 'base-xcframework',
+      root: path.dirname(baseFramework),
+      profile: 'native-runtime',
+      spdx: 'MIT AND PostgreSQL AND Unicode-3.0',
+      files: [
+        'liboliphaunt.xcframework/LICENSE',
+        'liboliphaunt.xcframework/THIRD_PARTY_LICENSES/ICU-LICENSE',
+        'liboliphaunt.xcframework/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT',
+        'liboliphaunt.xcframework/THIRD_PARTY_NOTICES.liboliphaunt-native.md',
+        'liboliphaunt.xcframework/THIRD_PARTY_NOTICES.md',
+      ],
+    },
+    {
+      assetRole: 'runtime-resources',
+      root: path.dirname(runtime),
+      profile: 'native-runtime-resources',
+      spdx: 'MIT AND PostgreSQL',
+      files: [
+        'LICENSE',
+        'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT',
+        'THIRD_PARTY_NOTICES.liboliphaunt-native.md',
+        'THIRD_PARTY_NOTICES.md',
+      ],
+    },
+  ];
+  const legal = [];
+  for (const spec of baseLegalSpecs) {
+    legal.push(
+      await legalGroup(spec.root, {
+        assetRole: spec.assetRole,
+        files: spec.files.map((member) => ({
+          kind: member.includes('NOTICE') ? 'notice' : 'license',
+          member,
+        })),
+        profile: spec.profile,
+        spdx: spec.spdx,
+      }),
+    );
+  }
+
+  const archiveRoot = path.join(root, 'archives');
+  const runtimeArchive = path.join(
+    archiveRoot,
+    'liboliphaunt-1.0.0-runtime-resources-ios-datum64.tar.gz',
+  );
+  const frameworkArchive = path.join(archiveRoot, 'liboliphaunt-1.0.0-apple-spm-xcframework.zip');
+  await tarMembers(path.dirname(runtime), runtimeArchive, [
+    path.basename(runtime),
+    'LICENSE',
+    'THIRD_PARTY_LICENSES',
+    'THIRD_PARTY_NOTICES.liboliphaunt-native.md',
+    'THIRD_PARTY_NOTICES.md',
+  ]);
+  // POSIX typeflag 5 is authoritative even when an older producer omitted the
+  // conventional slash. This is the exact archive shape from the failed run.
+  await removeTarDirectorySlash(runtimeArchive, `${path.basename(runtime)}/`);
+  await zipMember(path.dirname(baseFramework), path.basename(baseFramework), frameworkArchive);
+  return {
+    assets: [
+      await asset('base-xcframework', frameworkArchive, 'zip', 'liboliphaunt.xcframework'),
+      await asset('runtime-resources', runtimeArchive, 'tar.gz', 'oliphaunt'),
+    ],
+    legal,
+  };
+}
+
+async function extensionRow(root, config) {
+  const source = path.join(root, 'source', 'extensions', config.sqlName, 'runtime');
+  const createsExtension = config.createsExtension ?? true;
+  const dataFiles = config.dataFiles ?? [];
+  const sharedPreloadLibraries = config.sharedPreloadLibraries ?? [];
+  const mobilePrebuilt = config.mobilePrebuilt ?? config.nativeModuleStem !== null;
+  const nativeModuleFile =
+    config.nativeModuleStem === null ? '' : `${config.nativeModuleStem}.dylib`;
+  const nativeSymbolStem = config.nativeModuleStem?.replaceAll(/[^A-Za-z0-9_]/gu, '_') ?? '';
+  const registrationSymbols = config.registrationSymbols ?? [];
+  const staticSymbolAliases = registrationSymbols
+    .filter(({ address, name }) => address !== name)
+    .map(({ address, name }) => `${name}:${address}`)
+    .sort();
+  const mobileStaticArchives =
+    config.nativeModuleStem === null
+      ? []
+      : ['ios-device', 'ios-simulator'].map(
+          (target) =>
+            `${target}:mobile-static/${target}/extensions/${config.nativeModuleStem}/` +
+            `liboliphaunt_extension_${config.nativeModuleStem}.a`,
+        );
+  const productionDependencyArchiveNames = new Map([
+    ['geos-c', 'libgeos_c.a'],
+    ['openssl', 'libcrypto.a'],
+    ['sqlite', 'libsqlite3.a'],
+  ]);
+  const mobileStaticDependencyArchives = ['ios-device', 'ios-simulator'].flatMap((target) =>
+    config.nativeDependencies.map(
+      (dependency) =>
+        `${target}:${dependency}:mobile-static/${target}/dependencies/${dependency}/` +
+        `${productionDependencyArchiveNames.get(dependency) ?? `lib${dependency}.a`}`,
+    ),
+  );
+  const externalLicenseMembers =
+    config.sqlName === 'pgtap'
+      ? ['files/share/licenses/pgtap/LICENSE']
+      : config.sqlName === 'postgis'
+        ? ['files/share/licenses/postgis/COPYING']
+        : [];
+  const profile =
+    externalLicenseMembers.length > 0
+      ? 'external-native'
+      : config.sqlName === 'pgcrypto'
+        ? 'contrib-native-openssl'
+        : 'contrib-native';
+  const spdx =
+    config.sqlName === 'postgis'
+      ? 'MIT AND Apache-2.0 AND GPL-2.0-or-later AND LGPL-2.1-or-later AND blessing'
+      : config.sqlName === 'pgcrypto'
+        ? 'MIT AND PostgreSQL AND Apache-2.0'
+        : 'MIT AND PostgreSQL';
+  const legal = await legalGroup(source, {
+    assetRole: 'runtime-resources',
+    files: [
+      { kind: 'license', member: 'LICENSE' },
+      ...(externalLicenseMembers.length === 0
+        ? [{ kind: 'license', member: 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT' }]
+        : []),
+      ...(config.sqlName === 'pgcrypto'
+        ? [{ kind: 'license', member: 'THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt' }]
+        : []),
+      { kind: 'notice', member: 'THIRD_PARTY_NOTICES.md' },
+      ...externalLicenseMembers.map((member) => ({ kind: 'license', member })),
+    ],
+    profile,
+    spdx,
+  });
+  const licenseFiles = legal.files
+    .map(({ member }) => /^files\/(share\/licenses\/.+)$/u.exec(member)?.[1])
+    .filter((member) => member !== undefined)
+    .sort();
+  await write(
+    path.join(source, 'manifest.properties'),
+    [
+      'packageLayout=oliphaunt-extension-artifact-v1',
+      'pgMajor=18',
+      `sqlName=${config.sqlName}`,
+      `createsExtension=${createsExtension ? 'yes' : 'no'}`,
+      `nativeModuleStem=${config.nativeModuleStem ?? ''}`,
+      `nativeModuleFile=${nativeModuleFile}`,
+      'nativeTarget=ios-xcframework',
+      'nativeRuntimeProduct=liboliphaunt-native',
+      'nativeRuntimeVersion=1.0.0',
+      `dependencies=${config.dependencies.join(',')}`,
+      `dataFiles=${dataFiles.join(',')}`,
+      `extensionSqlFileNames=${config.extensionSqlFileNames.join(',')}`,
+      `extensionSqlFilePrefixes=${config.extensionSqlFilePrefixes.join(',')}`,
+      `sharedPreloadLibraries=${sharedPreloadLibraries.join(',')}`,
+      `mobilePrebuilt=${mobilePrebuilt ? 'yes' : 'no'}`,
+      `mobileStaticArchives=${mobileStaticArchives.join(',')}`,
+      `mobileStaticDependencyArchives=${mobileStaticDependencyArchives.join(',')}`,
+      `staticSymbolPrefix=${nativeSymbolStem ? `oliphaunt_static_${nativeSymbolStem}` : ''}`,
+      `staticSymbolAliases=${staticSymbolAliases.join(',')}`,
+      `licenseFiles=${licenseFiles.join(',')}`,
+      `licenseProfile=${profile}`,
+      'files=files',
+      '',
+    ].join('\n'),
+  );
+  if (createsExtension) {
+    await write(
+      path.join(source, 'files', 'share', 'postgresql', 'extension', `${config.sqlName}.control`),
+      `comment = '${config.sqlName} fixture'\n`,
+    );
+    await write(
+      path.join(source, 'files', 'share', 'postgresql', 'extension', `${config.sqlName}--1.0.sql`),
+      `select '${config.sqlName}';\n`,
+    );
+    if (config.includeUpdateSql === true) {
+      await write(
+        path.join(
+          source,
+          'files',
+          'share',
+          'postgresql',
+          'extension',
+          `${config.sqlName}--1.0--1.1.sql`,
+        ),
+        `select '${config.sqlName} update';\n`,
+      );
+    }
+    if (config.sqlName === 'pgtap') {
+      await write(
+        path.join(source, 'files', 'share', 'postgresql', 'extension', 'pgtap.sql'),
+        "select 'pgtap ancillary SQL';\n",
+      );
+      await write(
+        path.join(
+          source,
+          'files',
+          'share',
+          'postgresql',
+          'extension',
+          'pgtap--unpackaged--0.91.0.sql',
+        ),
+        "select 'pgtap legacy upgrade';\n",
+      );
+    }
+    if (config.sqlName === 'postgis') {
+      await write(
+        path.join(
+          source,
+          'files',
+          'share',
+          'postgresql',
+          'extension',
+          'postgis--TEMPLATED--TO--ANY.sql',
+        ),
+        "select 'postgis template upgrade';\n",
+      );
+    }
+  }
+  for (const dataFile of dataFiles) {
+    await write(
+      path.join(source, 'files', 'share', 'postgresql', dataFile),
+      `${config.sqlName} data\n`,
+    );
+  }
+  if (config.nativeModuleStem !== null) {
+    await write(
+      path.join(source, 'files', 'lib', 'postgresql', `${config.nativeModuleStem}.dylib`),
+      `${config.sqlName} native fixture\n`,
+    );
+  }
+  for (const row of mobileStaticArchives) {
+    const [, relative] = row.split(':');
+    await write(path.join(source, ...relative.split('/')), `${config.sqlName} static fixture\n`);
+  }
+  for (const row of mobileStaticDependencyArchives) {
+    const [, dependency, relative] = row.split(':');
+    await write(path.join(source, ...relative.split('/')), `${dependency} static fixture\n`);
+  }
+  const archiveRoot = path.join(root, 'archives');
+  const runtimeArchive = path.join(
+    archiveRoot,
+    `oliphaunt-extension-${config.sqlName.replaceAll('_', '-')}-1.0.0-native-ios-runtime.tar.gz`,
+  );
+  await tarDirectory(source, runtimeArchive);
+  const logicalAssets = [await logicalAsset('runtime-resources', runtimeArchive, 'tar.gz', '.')];
+  if (config.nativeModuleStem !== null) {
+    const framework = path.join(
+      root,
+      'source',
+      'extensions',
+      config.sqlName,
+      `liboliphaunt_extension_${config.nativeModuleStem}.xcframework`,
+    );
+    await write(path.join(framework, 'Info.plist'), '\n');
+    const frameworkArchive = path.join(
+      archiveRoot,
+      `oliphaunt-extension-${config.sqlName.replaceAll('_', '-')}-1.0.0-native-ios-xcframework.zip`,
+    );
+    await zipMember(path.dirname(framework), path.basename(framework), frameworkArchive);
+    logicalAssets.push(
+      await logicalAsset(
+        'extension-xcframework',
+        frameworkArchive,
+        'zip',
+        path.basename(framework),
+      ),
+    );
+    for (const dependency of config.nativeDependencies) {
+      const dependencyFramework = path.join(
+        root,
+        'source',
+        'extensions',
+        config.sqlName,
+        `liboliphaunt_dependency_${dependency}.xcframework`,
+      );
+      await write(path.join(dependencyFramework, 'Info.plist'), '\n');
+      const dependencyArchive = path.join(
+        archiveRoot,
+        `oliphaunt-extension-${config.sqlName.replaceAll('_', '-')}-1.0.0-native-ios-dependency-${dependency}.zip`,
+      );
+      await zipMember(
+        path.dirname(dependencyFramework),
+        path.basename(dependencyFramework),
+        dependencyArchive,
+      );
+      logicalAssets.push(
+        await logicalAsset(
+          'dependency-xcframework',
+          dependencyArchive,
+          'zip',
+          path.basename(dependencyFramework),
+        ),
+      );
+    }
+  }
+  const generated = GENERATED_EXTENSION_BY_SQL_NAME.get(config.sqlName);
+  assert.ok(generated, `missing generated fixture metadata for ${config.sqlName}`);
+  const product = generated['artifact-product'];
+  const releaseProduct = generated['release-product'];
+  return {
+    carriers: logicalAssets.map(({ envelope }) => envelope),
+    legal,
+    extension: {
+      assets: logicalAssets.map(({ locator }) => locator),
+      createsExtension,
+      dataFiles,
+      dependencies: config.dependencies,
+      extensionSqlFileNames: config.extensionSqlFileNames,
+      extensionSqlFilePrefixes: config.extensionSqlFilePrefixes,
+      nativeDependencies: config.nativeDependencies,
+      nativeModuleStem: config.nativeModuleStem,
+      product,
+      releaseProduct,
+      registration:
+        config.nativeModuleStem === null
+          ? null
+          : {
+              initSymbol: null,
+              magicSymbol: `oliphaunt_static_${config.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}_Pg_magic_func`,
+              symbols: registrationSymbols,
+            },
+      sharedPreloadLibraries,
+      sqlName: config.sqlName,
+      tag: `${releaseProduct}-v1.0.0`,
+      version: '1.0.0',
+    },
+  };
+}
+
+async function rewrittenExtensionRuntime(root, sqlName, archiveName, rewrite) {
+  const source = path.join(root, 'source', 'extensions', sqlName, 'runtime');
+  const stage = path.join(
+    root,
+    'rewritten-extension-runtime',
+    archiveName.replace(/\.tar\.gz$/u, ''),
+  );
+  await fs.rm(stage, { force: true, recursive: true });
+  await fs.cp(source, stage, { recursive: true });
+  const manifestFile = path.join(stage, 'manifest.properties');
+  const original = await fs.readFile(manifestFile, 'utf8');
+  const rewritten = rewrite(original);
+  assert.notEqual(rewritten, original, `${archiveName} rewrite must change manifest.properties`);
+  await fs.writeFile(manifestFile, rewritten);
+  const archive = path.join(root, 'archives', archiveName);
+  await fs.rm(archive, { force: true });
+  await tarDirectory(stage, archive);
+  return logicalAsset('runtime-resources', archive, 'tar.gz', '.');
+}
+
+async function extendedExtensionRuntime(root, sqlName, archiveName, additions) {
+  const source = path.join(root, 'source', 'extensions', sqlName, 'runtime');
+  const stage = path.join(
+    root,
+    'extended-extension-runtime',
+    archiveName.replace(/\.tar\.gz$/u, ''),
+  );
+  await fs.rm(stage, { force: true, recursive: true });
+  await fs.cp(source, stage, { recursive: true });
+  for (const [relativePath, contents] of Object.entries(additions)) {
+    await write(path.join(stage, relativePath), contents);
+  }
+  const archive = path.join(root, 'archives', archiveName);
+  await fs.rm(archive, { force: true });
+  await tarDirectory(stage, archive);
+  return logicalAsset('runtime-resources', archive, 'tar.gz', '.');
+}
+
+async function mutatedExtensionRuntime(root, sqlName, archiveName, mutate) {
+  const source = path.join(root, 'source', 'extensions', sqlName, 'runtime');
+  const stage = path.join(
+    root,
+    'mutated-extension-runtime',
+    archiveName.replace(/\.tar\.gz$/u, ''),
+  );
+  await fs.rm(stage, { force: true, recursive: true });
+  await fs.cp(source, stage, { recursive: true });
+  await mutate(stage);
+  const archive = path.join(root, 'archives', archiveName);
+  await fs.rm(archive, { force: true });
+  await tarDirectory(stage, archive);
+  return logicalAsset('runtime-resources', archive, 'tar.gz', '.');
+}
+
+async function createFixture(root) {
+  const builtBase = await baseAssets(root);
+  const base = {
+    assets: builtBase.assets,
+    product: 'liboliphaunt-native',
+    tag: 'liboliphaunt-native-v1.0.0',
+    version: '1.0.0',
+  };
+  const carriers = [];
+  const extensions = [];
+  const extensionLegal = [];
+  for (const fixture of [
+    { sqlName: 'auto_explain' },
+    { sqlName: 'cube' },
+    { sqlName: 'earthdistance' },
+    { sqlName: 'pgcrypto' },
+    { sqlName: 'pgtap', includeUpdateSql: true },
+    {
+      sqlName: 'postgis',
+      registrationSymbols: [
+        { address: 'oliphaunt_static_postgis_3_difference', name: 'difference' },
+        {
+          address: 'pg_finfo_oliphaunt_static_postgis_3_difference',
+          name: 'pg_finfo_difference',
+        },
+      ],
+    },
+  ]) {
+    const generated = GENERATED_EXTENSION_BY_SQL_NAME.get(fixture.sqlName);
+    assert.ok(generated, `missing generated fixture metadata for ${fixture.sqlName}`);
+    const iosDependencies = GENERATED_IOS_DEPENDENCIES_BY_SQL_NAME.get(fixture.sqlName) ?? [];
+    if (fixture.sqlName === 'pgcrypto') {
+      assert.deepEqual(iosDependencies, ['openssl']);
+    }
+    if (fixture.sqlName === 'postgis') {
+      assert.deepEqual(iosDependencies, ['geos', 'geos-c', 'json-c', 'libxml2', 'proj', 'sqlite']);
+    }
+    const config = {
+      ...fixture,
+      createsExtension: generated['creates-extension'],
+      dataFiles: generated['runtime-share-data-files'],
+      dependencies: generated['selected-extension-dependencies'],
+      extensionSqlFileNames: generated['extension-sql-file-names'],
+      extensionSqlFilePrefixes: generated['extension-sql-file-prefixes'],
+      nativeDependencies: iosDependencies,
+      nativeModuleStem: generated['native-module-stem'],
+      sharedPreloadLibraries: generated['shared-preload-libraries'],
+    };
+    const built = await extensionRow(root, config);
+    carriers.push(...built.carriers);
+    extensions.push(built.extension);
+    extensionLegal.push({ ...built.legal, sqlName: built.extension.sqlName });
+  }
+  extensionLegal.sort((left, right) => compareText(left.sqlName, right.sqlName));
+  const carrier = {
+    base,
+    carriers,
+    extensions,
+    legal: { base: builtBase.legal, extensions: extensionLegal },
+    schema: SCHEMA,
+  };
+  const carrierFile = path.join(root, 'oliphaunt-react-native-ios-carriers.json');
+  await write(carrierFile, `${JSON.stringify(carrier, null, 2)}\n`);
+  return { carrier, carrierFile };
+}
+
+async function bundledCarrierDocument(root, sourceDocument, sqlNames, archiveName, tamperSqlName) {
+  const document = structuredClone(sourceDocument);
+  document.extensions = document.extensions.filter(({ sqlName }) => sqlNames.includes(sqlName));
+  document.legal.extensions = document.legal.extensions.filter(({ sqlName }) =>
+    sqlNames.includes(sqlName),
+  );
+  const sourceRoot = path.join(root, 'bundle-source', archiveName.replace(/\.tar\.gz$/u, ''));
+  await fs.rm(sourceRoot, { force: true, recursive: true });
+  const sourceCarriers = new Map(sourceDocument.carriers.map((row) => [row.name, row]));
+  for (const extension of document.extensions) {
+    for (const locator of extension.assets) {
+      const envelope = sourceCarriers.get(locator.carrier);
+      assert.ok(envelope, `missing source envelope ${locator.carrier}`);
+      const nestedPath = `extensions/${extension.sqlName}/${envelope.name}`;
+      const nestedFile = path.join(sourceRoot, ...nestedPath.split('/'));
+      await fs.mkdir(path.dirname(nestedFile), { recursive: true });
+      await fs.copyFile(fileURLToPath(envelope.url), nestedFile);
+      if (extension.sqlName === tamperSqlName && locator.role === 'runtime-resources') {
+        await fs.appendFile(nestedFile, 'tampered nested payload\n');
+      }
+      locator.carrier = archiveName;
+      locator.path = nestedPath;
+    }
+  }
+  const archive = path.join(root, 'archives', archiveName);
+  await fs.rm(archive, { force: true });
+  await fs.mkdir(path.dirname(archive), { recursive: true });
+  await archiveDirectory(path.join(sourceRoot, 'extensions'), archive, { keepParent: true });
+  const direct = await asset('carrier', archive, 'tar.gz', '.');
+  document.carriers = [
+    {
+      bytes: direct.bytes,
+      format: direct.format,
+      name: direct.name,
+      sha256: direct.sha256,
+      url: direct.url,
+    },
+  ];
+  return document;
+}
+
+async function expectReject(action, pattern) {
+  let error;
+  try {
+    await action();
+  } catch (caught) {
+    error = caught;
+  }
+  assert.ok(error instanceof Error, 'expected action to reject');
+  assert.match(error.message, pattern);
+}
+
+async function main() {
+  const root =
+    process.env.OLIPHAUNT_TEST_IOS_STAGE_ROOT ??
+    (await fs.mkdtemp(path.join(os.tmpdir(), 'oliphaunt-rn-ios-carrier-')));
+  try {
+    const { carrier, carrierFile } = await createFixture(root);
+    const output = path.join(root, 'consumer', 'ios', 'oliphaunt');
+    const cache = path.join(root, 'cache');
+    const requested = ['auto_explain', 'earthdistance', 'pgcrypto', 'pgtap', 'postgis'];
+    const result = await stageIosAppPayload(
+      path.join(root, 'consumer'),
+      path.dirname(output),
+      { extensions: requested, icu: true, seedProfile: 'icu' },
+      {
+        env: {
+          OLIPHAUNT_REACT_NATIVE_IOS_BASE_CARRIER: carrierFile,
+          OLIPHAUNT_REACT_NATIVE_IOS_ALLOW_FILE_URLS: 'true',
+          OLIPHAUNT_REACT_NATIVE_IOS_CACHE_DIR: cache,
+        },
+      },
+    );
+    assert.deepEqual(result.selected, [
+      'auto_explain',
+      'cube',
+      'earthdistance',
+      'pgcrypto',
+      'pgtap',
+      'postgis',
+    ]);
+    await validateStagedPackage(output, false);
+
+    const payloadPodspec = await fs.readFile(
+      path.join(output, 'OliphauntReactNativePayload.podspec'),
+      'utf8',
+    );
+    assert.match(
+      payloadPodspec,
+      /^ {2}s[.]license = \{ :type => "MIT AND PostgreSQL AND Unicode-3[.]0 AND Apache-2[.]0 AND GPL-2[.]0-or-later AND LGPL-2[.]1-or-later AND blessing", :file => "licenses\/NOTICE[.]md" \}$/mu,
+    );
+    assert.match(payloadPodspec, /^ {2}s[.]preserve_paths = "licenses\/\*\*\/\*"$/mu);
+    assert.match(
+      payloadPodspec,
+      /s\.resources = "resources\/OliphauntReactNativeResources\.bundle"/u,
+    );
+    assert.match(
+      payloadPodspec,
+      /s\.vendored_frameworks = "frameworks\/base\/liboliphaunt\.xcframework", "frameworks\/extensions\/\*\*\/\*\.xcframework"/u,
+    );
+    assert.doesNotMatch(payloadPodspec, /frameworks\/base\/[^"\n]*\*\*/u);
+    assert.doesNotMatch(payloadPodspec, /frameworks\/base\/[^"\n]*\.framework/u);
+    assert.match(payloadPodspec, /s\.source_files = "generated\/static-registry\/\*\.c"/u);
+    assert.doesNotMatch(payloadPodspec, /(?:^|["'])\.\.\//mu);
+    for (const relativeRoot of [
+      'resources/OliphauntReactNativeResources.bundle',
+      'frameworks/base',
+      'frameworks/extensions',
+      'generated/static-registry',
+      'licenses/base/base-xcframework',
+      'licenses/base/runtime-resources',
+      'licenses/extensions/postgis',
+    ]) {
+      await fs.access(path.join(output, relativeRoot));
+    }
+    await fs.access(
+      path.join(
+        output,
+        'frameworks',
+        'base',
+        'liboliphaunt.xcframework',
+        'ios-arm64',
+        'liboliphaunt.framework',
+        'liboliphaunt',
+      ),
+    );
+    await assert.rejects(
+      fs.access(
+        path.join(
+          output,
+          'frameworks',
+          'base',
+          'liboliphaunt.xcframework',
+          'ios-arm64',
+          'liboliphaunt.framework',
+          'Resources',
+          'oliphaunt',
+        ),
+      ),
+    );
+    await assert.rejects(
+      fs.access(
+        path.join(
+          output,
+          'frameworks',
+          'base',
+          'liboliphaunt.xcframework',
+          'ios-arm64',
+          'liboliphaunt.framework',
+          'Resources',
+        ),
+      ),
+    );
+
+    const frameworkNames = (await fs.readdir(path.join(output, 'frameworks', 'extensions'))).sort();
+    assert.deepEqual(frameworkNames, [
+      'liboliphaunt_dependency_geos-c.xcframework',
+      'liboliphaunt_dependency_geos.xcframework',
+      'liboliphaunt_dependency_json-c.xcframework',
+      'liboliphaunt_dependency_libxml2.xcframework',
+      'liboliphaunt_dependency_openssl.xcframework',
+      'liboliphaunt_dependency_proj.xcframework',
+      'liboliphaunt_dependency_sqlite.xcframework',
+      'liboliphaunt_extension_auto_explain.xcframework',
+      'liboliphaunt_extension_cube.xcframework',
+      'liboliphaunt_extension_earthdistance.xcframework',
+      'liboliphaunt_extension_pgcrypto.xcframework',
+      'liboliphaunt_extension_postgis-3.xcframework',
+    ]);
+    assert.match(payloadPodspec, /s\.dependency "OliphauntICU"/u);
+    assert.match(payloadPodspec, /s\.dependency "OliphauntSeedNativeIOSICU"/u);
+    assert.doesNotMatch(payloadPodspec, /OliphauntSeedNativeIOSStandard/u);
+    for (const member of ['cluster-seed', 'cluster-seed-icu', 'runtime/files/share/icu']) {
+      await assert.rejects(
+        fs.access(
+          path.join(
+            output,
+            'resources',
+            'OliphauntReactNativeResources.bundle',
+            'oliphaunt',
+            member,
+          ),
+        ),
+        { code: 'ENOENT' },
+      );
+    }
+    await fs.access(
+      path.join(
+        output,
+        'resources',
+        'OliphauntReactNativeResources.bundle',
+        'oliphaunt',
+        'runtime',
+        'files',
+        'share',
+        'postgresql',
+        'extension',
+        'pgtap.control',
+      ),
+    );
+    await assert.rejects(
+      fs.access(
+        path.join(output, 'frameworks', 'extensions', 'liboliphaunt_extension_pgtap.xcframework'),
+      ),
+    );
+    await assert.rejects(
+      fs.access(
+        path.join(
+          output,
+          'resources',
+          'OliphauntReactNativeResources.bundle',
+          'oliphaunt',
+          'runtime',
+          'files',
+          'share',
+          'postgresql',
+          'extension',
+          'auto_explain.control',
+        ),
+      ),
+    );
+    const runtimeManifest = await fs.readFile(
+      path.join(
+        output,
+        'resources',
+        'OliphauntReactNativeResources.bundle',
+        'oliphaunt',
+        'runtime',
+        'manifest.properties',
+      ),
+      'utf8',
+    );
+    assert.match(
+      runtimeManifest,
+      /^selectedExtensions=auto_explain,cube,earthdistance,pgcrypto,pgtap,postgis$/mu,
+    );
+    assert.match(runtimeManifest, /^extensions=cube,earthdistance,pgcrypto,pgtap,postgis$/mu);
+    assert.match(
+      runtimeManifest,
+      /^mobileStaticRegistryRegistered=auto_explain,cube,earthdistance,pgcrypto,postgis$/mu,
+    );
+    const packageSize = await fs.readFile(
+      path.join(
+        output,
+        'resources',
+        'OliphauntReactNativeResources.bundle',
+        'oliphaunt',
+        'package-size.tsv',
+      ),
+      'utf8',
+    );
+    assert.match(packageSize, /^extension\tauto_explain\t-\t0\t0$/mu);
+    assert.match(
+      packageSize,
+      /^extensions\tselected\tauto_explain,cube,earthdistance,pgcrypto,pgtap,postgis\t/mu,
+    );
+    const registry = await fs.readFile(
+      path.join(output, 'generated', 'static-registry', 'oliphaunt_static_registry.c'),
+      'utf8',
+    );
+    assert.doesNotMatch(registry, /symbols\[\]\s*=\s*\{\s*\}/u);
+    assert.match(registry, /\.symbols = NULL,/u);
+    assert.match(registry, /\.name = "postgis-3"/u);
+    assert.match(
+      registry,
+      /\.name = "difference", \.address = \(void \*\)oliphaunt_static_postgis_3_difference/u,
+    );
+    assert.match(
+      registry,
+      /\.name = "pg_finfo_difference", \.address = \(void \*\)pg_finfo_oliphaunt_static_postgis_3_difference/u,
+    );
+
+    const selection = JSON.parse(await fs.readFile(path.join(output, 'selection.json'), 'utf8'));
+    assert.equal(selection.icu, true);
+    assert.equal(
+      selection.legal.spdx,
+      'MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0 AND GPL-2.0-or-later AND LGPL-2.1-or-later AND blessing',
+    );
+    assert.equal(selection.legal.file, 'licenses/NOTICE.md');
+    assert.ok(
+      selection.legal.files.every(({ destination }) => destination.startsWith('licenses/')),
+    );
+    assert.match(
+      await fs.readFile(path.join(output, selection.legal.file), 'utf8'),
+      /^SPDX-License-Identifier: MIT AND PostgreSQL AND Unicode-3[.]0/mu,
+    );
+    assert.equal(
+      selection.extensions.find(({ sqlName }) => sqlName === 'auto_explain').createsExtension,
+      false,
+    );
+    assert.equal(
+      selection.extensions.find(({ sqlName }) => sqlName === 'pgtap').createsExtension,
+      true,
+    );
+    await fs.access(
+      path.join(
+        output,
+        'resources',
+        'OliphauntReactNativeResources.bundle',
+        'oliphaunt',
+        'runtime',
+        'files',
+        'share',
+        'postgresql',
+        'extension',
+        'pgtap--1.0--1.1.sql',
+      ),
+    );
+    assert.deepEqual(selection.requestedExtensions, [...requested].sort());
+    assert.deepEqual(
+      selection.extensions.map(({ sqlName }) => sqlName),
+      result.selected,
+    );
+
+    const duplicateClosureOutput = path.join(root, 'duplicate-framework-closure-output');
+    await fs.cp(output, duplicateClosureOutput, { recursive: true });
+    await fs.cp(
+      path.join(
+        duplicateClosureOutput,
+        'resources',
+        'OliphauntReactNativeResources.bundle',
+        'oliphaunt',
+      ),
+      path.join(
+        duplicateClosureOutput,
+        'frameworks',
+        'base',
+        'liboliphaunt.xcframework',
+        'ios-arm64',
+        'liboliphaunt.framework',
+        'Resources',
+        'oliphaunt',
+      ),
+      { recursive: true },
+    );
+    await assert.rejects(
+      () => validateStagedPackage(duplicateClosureOutput, false),
+      /must not embed a second runtime-resource closure/u,
+    );
+
+    const missingCreateableOutput = path.join(root, 'missing-createable-output');
+    await fs.cp(output, missingCreateableOutput, { recursive: true });
+    const missingCreateableManifest = path.join(
+      missingCreateableOutput,
+      'resources',
+      'OliphauntReactNativeResources.bundle',
+      'oliphaunt',
+      'runtime',
+      'manifest.properties',
+    );
+    await fs.writeFile(
+      missingCreateableManifest,
+      (await fs.readFile(missingCreateableManifest, 'utf8')).replace(
+        /^extensions=cube,earthdistance,pgcrypto,pgtap,postgis$/mu,
+        'extensions=cube,earthdistance,pgcrypto,postgis',
+      ),
+    );
+    await assert.rejects(
+      () => validateStagedPackage(missingCreateableOutput, false),
+      /extensions must match the exact canonical domain/u,
+    );
+
+    const missingNativeRegistrationOutput = path.join(root, 'missing-native-registration-output');
+    await fs.cp(output, missingNativeRegistrationOutput, { recursive: true });
+    const missingNativeRegistrationManifest = path.join(
+      missingNativeRegistrationOutput,
+      'resources',
+      'OliphauntReactNativeResources.bundle',
+      'oliphaunt',
+      'runtime',
+      'manifest.properties',
+    );
+    await fs.writeFile(
+      missingNativeRegistrationManifest,
+      (await fs.readFile(missingNativeRegistrationManifest, 'utf8')).replace(
+        /^mobileStaticRegistryRegistered=auto_explain,cube,earthdistance,pgcrypto,postgis$/mu,
+        'mobileStaticRegistryRegistered=cube,earthdistance,pgcrypto,postgis',
+      ),
+    );
+    await assert.rejects(
+      () => validateStagedPackage(missingNativeRegistrationOutput, false),
+      /mobileStaticRegistryRegistered must match the exact canonical domain/u,
+    );
+
+    const tamperedLegalNoticeOutput = path.join(root, 'tampered-legal-notice-output');
+    await fs.cp(output, tamperedLegalNoticeOutput, { recursive: true });
+    await fs.appendFile(
+      path.join(tamperedLegalNoticeOutput, 'licenses', 'NOTICE.md'),
+      'unfrozen notice text\n',
+    );
+    await assert.rejects(
+      () => validateStagedPackage(tamperedLegalNoticeOutput, false),
+      /does not exactly index the frozen legal selection/u,
+    );
+
+    const unselectedLegalOutput = path.join(root, 'unselected-legal-output');
+    await fs.cp(output, unselectedLegalOutput, { recursive: true });
+    await write(
+      path.join(unselectedLegalOutput, 'licenses', 'extensions', 'unselected', 'LICENSE'),
+      'unselected legal payload\n',
+    );
+    await assert.rejects(
+      () => validateStagedPackage(unselectedLegalOutput, false),
+      /legal namespace contains missing or uncontracted files/u,
+    );
+
+    const contribBundle = await bundledCarrierDocument(
+      root,
+      carrier,
+      ['auto_explain', 'cube', 'earthdistance'],
+      'oliphaunt-extension-contrib-pg18-1.0.0-native-ios-bundle.tar.gz',
+    );
+    const contribBundleFile = path.join(root, 'oliphaunt-extension-contrib-pg18-carrier.json');
+    await write(contribBundleFile, `${JSON.stringify(contribBundle, null, 2)}\n`);
+    const externalCarrier = structuredClone(carrier);
+    externalCarrier.extensions = externalCarrier.extensions.filter(
+      ({ sqlName }) => sqlName === 'pgtap',
+    );
+    retainReferencedCarriers(externalCarrier);
+    const externalCarrierFile = path.join(root, 'oliphaunt-extension-pgtap-carrier.json');
+    await write(externalCarrierFile, `${JSON.stringify(externalCarrier, null, 2)}\n`);
+    const bundleOutput = path.join(root, 'consumer-bundle', 'ios', 'oliphaunt');
+    const bundleResult = await stageIosApp({
+      allowFileUrls: true,
+      cacheDir: path.join(root, 'bundle-cache'),
+      carriers: [contribBundleFile, externalCarrierFile],
+      extensions: ['earthdistance', 'pgtap'],
+      outputDir: bundleOutput,
+    });
+    assert.deepEqual(bundleResult.selected, ['cube', 'earthdistance', 'pgtap']);
+    const bundleSelection = JSON.parse(
+      await fs.readFile(path.join(bundleOutput, 'selection.json'), 'utf8'),
+    );
+    assert.deepEqual(
+      bundleSelection.extensions.map(({ product, sqlName }) => [product, sqlName]),
+      [
+        ['oliphaunt-extension-contrib-pg18', 'cube'],
+        ['oliphaunt-extension-contrib-pg18', 'earthdistance'],
+        ['oliphaunt-extension-pgtap', 'pgtap'],
+      ],
+    );
+    const unselectedAutoExplain = contribBundle.extensions
+      .find(({ sqlName }) => sqlName === 'auto_explain')
+      .assets.find(({ role }) => role === 'runtime-resources');
+    await assert.rejects(
+      fs.access(
+        path.join(
+          root,
+          'bundle-cache',
+          'payloads',
+          `${unselectedAutoExplain.sha256}-${path.posix.basename(unselectedAutoExplain.path)}`,
+        ),
+      ),
+    );
+    await fs.access(
+      path.join(
+        bundleOutput,
+        'licenses',
+        'extensions',
+        'pgtap',
+        'files',
+        'share',
+        'licenses',
+        'pgtap',
+        'LICENSE',
+      ),
+    );
+    await assert.rejects(
+      fs.access(path.join(bundleOutput, 'licenses', 'extensions', 'auto_explain')),
+    );
+    await assert.rejects(fs.access(path.join(bundleOutput, 'licenses', 'extensions', 'postgis')));
+    await assert.rejects(fs.access(path.join(bundleOutput, 'licenses', 'base', 'icu-data')));
+
+    // An independently versioned external extension is validated against the
+    // immutable carrier contract that shipped with that extension version, not
+    // against this SDK's newer generated extension catalog.
+    const frozenOldExternal = structuredClone(carrier);
+    frozenOldExternal.extensions = frozenOldExternal.extensions.filter(
+      ({ sqlName }) => sqlName === 'pgtap',
+    );
+    const frozenOldPgtap = frozenOldExternal.extensions[0];
+    frozenOldPgtap.version = '0.9.0';
+    frozenOldPgtap.tag = 'oliphaunt-extension-pgtap-v0.9.0';
+    frozenOldPgtap.dataFiles = ['legacy/pgtap-old.dat'];
+    frozenOldPgtap.extensionSqlFileNames = ['uninstall_pgtap_legacy.sql'];
+    frozenOldPgtap.extensionSqlFilePrefixes = ['pgtap-legacy'];
+    frozenOldPgtap.sharedPreloadLibraries = ['pgtap_legacy'];
+    replaceExtensionRuntimeAsset(
+      frozenOldExternal,
+      'pgtap',
+      await mutatedExtensionRuntime(
+        root,
+        'pgtap',
+        'pgtap-frozen-old-version.tar.gz',
+        async (stage) => {
+          const manifestFile = path.join(stage, 'manifest.properties');
+          const manifest = await fs.readFile(manifestFile, 'utf8');
+          await fs.writeFile(
+            manifestFile,
+            manifest
+              .replace('dataFiles=', 'dataFiles=legacy/pgtap-old.dat')
+              .replace(
+                'extensionSqlFileNames=uninstall_pgtap.sql',
+                'extensionSqlFileNames=uninstall_pgtap_legacy.sql',
+              )
+              .replace(
+                'extensionSqlFilePrefixes=pgtap-core,pgtap-schema',
+                'extensionSqlFilePrefixes=pgtap-legacy',
+              )
+              .replace('sharedPreloadLibraries=', 'sharedPreloadLibraries=pgtap_legacy'),
+          );
+          await write(
+            path.join(stage, 'files', 'share', 'postgresql', 'legacy', 'pgtap-old.dat'),
+            'old independently versioned pgtap data\n',
+          );
+        },
+      ),
+    );
+    retainReferencedCarriers(frozenOldExternal);
+    const frozenOldExternalFile = path.join(root, 'pgtap-frozen-old-version.json');
+    await write(frozenOldExternalFile, `${JSON.stringify(frozenOldExternal, null, 2)}\n`);
+    const frozenOldOutput = path.join(root, 'pgtap-frozen-old-output');
+    const frozenOldResult = await stageIosApp({
+      allowFileUrls: true,
+      cacheDir: path.join(root, 'pgtap-frozen-old-cache'),
+      carriers: [frozenOldExternalFile],
+      extensions: ['pgtap'],
+      outputDir: frozenOldOutput,
+    });
+    assert.deepEqual(frozenOldResult.selected, ['pgtap']);
+    assert.equal(
+      await fs.readFile(
+        path.join(
+          frozenOldOutput,
+          'resources',
+          'OliphauntReactNativeResources.bundle',
+          'oliphaunt',
+          'runtime',
+          'files',
+          'share',
+          'postgresql',
+          'legacy',
+          'pgtap-old.dat',
+        ),
+        'utf8',
+      ),
+      'old independently versioned pgtap data\n',
+    );
+
+    const tamperedBundle = await bundledCarrierDocument(
+      root,
+      carrier,
+      ['cube', 'earthdistance'],
+      'oliphaunt-extension-contrib-pg18-1.0.0-native-ios-tampered-bundle.tar.gz',
+      'earthdistance',
+    );
+    const tamperedBundleFile = path.join(root, 'tampered-contrib-bundle.json');
+    await write(tamperedBundleFile, `${JSON.stringify(tamperedBundle, null, 2)}\n`);
+    await expectReject(
+      () =>
+        stageIosApp({
+          allowFileUrls: true,
+          cacheDir: path.join(root, 'tampered-bundle-cache'),
+          carriers: [tamperedBundleFile],
+          extensions: ['earthdistance'],
+          outputDir: path.join(root, 'tampered-bundle-output'),
+        }),
+      /nested payload .* does not match its frozen size\/checksum/u,
+    );
+    await expectReject(
+      () =>
+        stageIosApp({
+          allowFileUrls: true,
+          carriers: [carrierFile, contribBundleFile],
+          extensions: ['cube'],
+          outputDir: path.join(root, 'bundle-conflict'),
+        }),
+      /carrier manifests disagree for exact extension/u,
+    );
+
+    const baseRuntime = carrier.base.assets.find(({ role }) => role === 'runtime-resources');
+    const cachedBase = path.join(cache, 'extracted', baseRuntime.sha256);
+    await fs.writeFile(
+      path.join(cachedBase, 'oliphaunt', 'runtime', 'manifest.properties'),
+      'tampered-cache-entry\n',
+    );
+    assert.equal((await fs.stat(`${cachedBase}.tree.json`)).isFile(), true);
+    const recoveredOutput = path.join(root, 'consumer-recovered', 'ios', 'oliphaunt');
+    await stageIosApp({
+      allowFileUrls: true,
+      cacheDir: cache,
+      carriers: [carrierFile],
+      extensions: requested,
+      icu: true,
+      seedProfile: 'icu',
+      outputDir: recoveredOutput,
+    });
+    assert.doesNotMatch(
+      await fs.readFile(
+        path.join(cachedBase, 'oliphaunt', 'runtime', 'manifest.properties'),
+        'utf8',
+      ),
+      /tampered-cache-entry/u,
+    );
+    assert.deepEqual(await fixtureFiles(output), await fixtureFiles(recoveredOutput));
+
+    async function expectCarrierFailure(name, candidate, extensions, pattern, options = {}) {
+      const file = path.join(root, `${name}.json`);
+      await write(file, `${JSON.stringify(candidate, null, 2)}\n`);
+      await expectReject(
+        () =>
+          stageIosApp({
+            allowFileUrls: true,
+            cacheDir: path.join(root, `${name}-cache`),
+            carriers: [file],
+            extensions,
+            icu: options.icu ?? false,
+            outputDir: path.join(root, `${name}-output`),
+          }),
+        pattern,
+      );
+    }
+
+    async function expectResourceManifestFailure(name, rewrite, pattern, sqlName = 'pgtap') {
+      const candidate = structuredClone(carrier);
+      const replacement = await rewrittenExtensionRuntime(root, sqlName, `${name}.tar.gz`, rewrite);
+      replaceExtensionAssets(candidate, sqlName, [replacement]);
+      await expectCarrierFailure(name, candidate, [sqlName], pattern);
+    }
+
+    const moduleOnlyBase = structuredClone(carrier);
+    const moduleOnlyBaseRoot = path.join(root, 'mutated-base-module-only', 'oliphaunt');
+    await fs.cp(path.join(root, 'source', 'base', 'runtime', 'oliphaunt'), moduleOnlyBaseRoot, {
+      recursive: true,
+    });
+    const moduleOnlyBaseManifest = path.join(moduleOnlyBaseRoot, 'runtime', 'manifest.properties');
+    await fs.writeFile(
+      moduleOnlyBaseManifest,
+      (await fs.readFile(moduleOnlyBaseManifest, 'utf8')).replace(
+        'selectedExtensions=\n',
+        'selectedExtensions=auto_explain\n',
+      ),
+    );
+    await write(
+      path.join(moduleOnlyBaseRoot, 'runtime', 'files', 'lib', 'postgresql', 'auto_explain.dylib'),
+      'hidden module-only base payload\n',
+    );
+    const moduleOnlyBaseArchive = path.join(
+      root,
+      'archives',
+      'module-only-base',
+      'liboliphaunt-1.0.0-runtime-resources-ios-datum64.tar.gz',
+    );
+    await tarDirectory(path.dirname(moduleOnlyBaseRoot), moduleOnlyBaseArchive, 'oliphaunt');
+    moduleOnlyBase.base.assets = await Promise.all(
+      moduleOnlyBase.base.assets.map(async (row) =>
+        row.role === 'runtime-resources'
+          ? asset('runtime-resources', moduleOnlyBaseArchive, 'tar.gz', 'oliphaunt')
+          : row,
+      ),
+    );
+    await expectCarrierFailure(
+      'module-only-selection-in-base-runtime',
+      moduleOnlyBase,
+      [],
+      /base React Native iOS carrier is not extension-free/u,
+    );
+
+    const missingRootEnvelopeField = structuredClone(carrier);
+    delete missingRootEnvelopeField.carriers;
+    await expectCarrierFailure(
+      'missing-root-envelope-field',
+      missingRootEnvelopeField,
+      [],
+      /fields must be exactly base,carriers,extensions,legal,schema; got base,extensions,legal,schema/u,
+    );
+
+    const traversingLegalMember = structuredClone(carrier);
+    traversingLegalMember.legal.base[0].files[0].member = '../outside-license';
+    await expectCarrierFailure(
+      'traversing-legal-member',
+      traversingLegalMember,
+      [],
+      /not a safe archive-relative path/u,
+    );
+
+    const collidingLegalMember = structuredClone(carrier);
+    const collidingFiles = collidingLegalMember.legal.base[0].files;
+    collidingFiles.at(-1).member = collidingFiles[0].member.toLowerCase();
+    collidingFiles.sort((left, right) => compareText(left.member, right.member));
+    await expectCarrierFailure(
+      'colliding-legal-member',
+      collidingLegalMember,
+      [],
+      /colliding legal members/u,
+    );
+
+    const missingCarrierEnvelopeField = structuredClone(carrier);
+    delete missingCarrierEnvelopeField.carriers[0].bytes;
+    await expectCarrierFailure(
+      'missing-carrier-envelope-field',
+      missingCarrierEnvelopeField,
+      [],
+      /fields must be exactly bytes,format,name,sha256,url; got format,name,sha256,url/u,
+    );
+
+    const missingLogicalEnvelopeField = structuredClone(carrier);
+    delete missingLogicalEnvelopeField.extensions[0].assets[0].member;
+    await expectCarrierFailure(
+      'missing-logical-envelope-field',
+      missingLogicalEnvelopeField,
+      ['auto_explain'],
+      /fields must be exactly bytes,carrier,format,member,path,role,sha256; got bytes,carrier,format,path,role,sha256/u,
+    );
+
+    const missingFrozenContentField = structuredClone(carrier);
+    delete missingFrozenContentField.extensions.find(({ sqlName }) => sqlName === 'pgtap')
+      .dataFiles;
+    await expectCarrierFailure(
+      'missing-frozen-extension-content-field',
+      missingFrozenContentField,
+      ['pgtap'],
+      /fields must be exactly .*dataFiles.*; got .*[^A-Za-z]dependencies/u,
+    );
+
+    const nonCanonicalFrozenList = structuredClone(carrier);
+    nonCanonicalFrozenList.extensions
+      .find(({ sqlName }) => sqlName === 'pgtap')
+      .extensionSqlFilePrefixes.reverse();
+    await expectCarrierFailure(
+      'non-canonical-frozen-extension-list',
+      nonCanonicalFrozenList,
+      ['pgtap'],
+      /extensionSqlFilePrefixes must be sorted in ordinal order/u,
+    );
+
+    const selfDependentFrozenContract = structuredClone(carrier);
+    selfDependentFrozenContract.extensions.find(({ sqlName }) => sqlName === 'pgtap').dependencies =
+      ['pgtap'];
+    await expectCarrierFailure(
+      'self-dependent-frozen-extension-contract',
+      selfDependentFrozenContract,
+      ['pgtap'],
+      /dependencies must not include pgtap itself/u,
+    );
+
+    const dottedFrozenSqlPrefix = structuredClone(carrier);
+    dottedFrozenSqlPrefix.extensions.find(
+      ({ sqlName }) => sqlName === 'pgtap',
+    ).extensionSqlFilePrefixes = ['pgtap.core'];
+    await expectCarrierFailure(
+      'dotted-frozen-extension-sql-prefix',
+      dottedFrozenSqlPrefix,
+      ['pgtap'],
+      /dot-free portable SQL basename prefix/u,
+    );
+
+    async function expectCacheComponentSymlinkFailure(name, component, candidate, extensions) {
+      const file = path.join(root, `${name}.json`);
+      const cacheDir = path.join(root, `${name}-cache`);
+      const redirected = path.join(root, `${name}-redirected`);
+      await write(file, `${JSON.stringify(candidate, null, 2)}\n`);
+      await fs.mkdir(cacheDir, { recursive: true });
+      await fs.mkdir(redirected, { recursive: true });
+      await fs.symlink(redirected, path.join(cacheDir, component), 'dir');
+      await expectReject(
+        () =>
+          stageIosApp({
+            allowFileUrls: true,
+            cacheDir,
+            carriers: [file],
+            extensions,
+            outputDir: path.join(root, `${name}-output`),
+          }),
+        /cache path component must be a real directory, not a symlink/u,
+      );
+      assert.deepEqual(
+        await fs.readdir(redirected),
+        [],
+        `rejected ${component} cache symlink must not receive carrier bytes`,
+      );
+    }
+
+    await expectCacheComponentSymlinkFailure('objects-cache-symlink', 'objects', carrier, []);
+    await expectCacheComponentSymlinkFailure('extracted-cache-symlink', 'extracted', carrier, []);
+    await expectCacheComponentSymlinkFailure('payloads-cache-symlink', 'payloads', contribBundle, [
+      'cube',
+    ]);
+
+    const cacheRootLinkManifest = path.join(root, 'cache-root-symlink.json');
+    const cacheRootLink = path.join(root, 'cache-root-symlink-cache');
+    const cacheRootRedirected = path.join(root, 'cache-root-symlink-redirected');
+    await write(cacheRootLinkManifest, `${JSON.stringify(carrier, null, 2)}\n`);
+    await fs.mkdir(cacheRootRedirected, { recursive: true });
+    await fs.symlink(cacheRootRedirected, cacheRootLink, 'dir');
+    await expectReject(
+      () =>
+        stageIosApp({
+          allowFileUrls: true,
+          cacheDir: cacheRootLink,
+          carriers: [cacheRootLinkManifest],
+          extensions: [],
+          outputDir: path.join(root, 'cache-root-symlink-output'),
+        }),
+      /cache root must be a real directory, not a symlink/u,
+    );
+    assert.deepEqual(
+      await fs.readdir(cacheRootRedirected),
+      [],
+      'rejected cache-root symlink must not receive carrier bytes',
+    );
+
+    await expectResourceManifestFailure(
+      'missing-native-runtime-product',
+      (manifest) => manifest.replace('nativeRuntimeProduct=liboliphaunt-native\n', ''),
+      /is missing nativeRuntimeProduct/u,
+    );
+    await expectResourceManifestFailure(
+      'missing-native-runtime-version',
+      (manifest) => manifest.replace('nativeRuntimeVersion=1.0.0\n', ''),
+      /is missing nativeRuntimeVersion/u,
+    );
+    await expectResourceManifestFailure(
+      'wrong-native-runtime-product',
+      (manifest) =>
+        manifest.replace(
+          'nativeRuntimeProduct=liboliphaunt-native',
+          'nativeRuntimeProduct=liboliphaunt-wasix',
+        ),
+      /must declare nativeRuntimeProduct=liboliphaunt-native; got liboliphaunt-wasix/u,
+    );
+    await expectResourceManifestFailure(
+      'wrong-native-target',
+      (manifest) => manifest.replace('nativeTarget=ios-xcframework', 'nativeTarget=linux-x64-gnu'),
+      /must declare nativeTarget=ios-xcframework; got linux-x64-gnu/u,
+    );
+    await expectResourceManifestFailure(
+      'wrong-native-runtime-version',
+      (manifest) => manifest.replace('nativeRuntimeVersion=1.0.0', 'nativeRuntimeVersion=9.9.9'),
+      /must declare nativeRuntimeVersion=1\.0\.0; got 9\.9\.9/u,
+    );
+    await expectResourceManifestFailure(
+      'unstable-native-runtime-version',
+      (manifest) =>
+        manifest.replace('nativeRuntimeVersion=1.0.0', 'nativeRuntimeVersion=1.0.0-rc.1'),
+      /nativeRuntimeVersion must be a stable SemVer X\.Y\.Z version/u,
+    );
+    await expectResourceManifestFailure(
+      'unknown-extension-manifest-field',
+      (manifest) =>
+        manifest.replace('files=files\n', 'unsupportedFutureField=value\nfiles=files\n'),
+      /contains unsupported field\(s\): unsupportedFutureField/u,
+    );
+    await expectResourceManifestFailure(
+      'missing-extension-canonical-field',
+      (manifest) => manifest.replace('nativeModuleFile=\n', ''),
+      /must declare nativeModuleFile=; got /u,
+    );
+    await expectResourceManifestFailure(
+      'missing-extension-sql-file-names',
+      (manifest) => manifest.replace('extensionSqlFileNames=uninstall_pgtap.sql\n', ''),
+      /is missing extensionSqlFileNames/u,
+    );
+    await expectResourceManifestFailure(
+      'wrong-extension-sql-file-prefixes',
+      (manifest) =>
+        manifest.replace(
+          'extensionSqlFilePrefixes=pgtap-core,pgtap-schema',
+          'extensionSqlFilePrefixes=pgtap-core,wildcard-trust',
+        ),
+      /extensionSqlFilePrefixes must exactly match the frozen carrier contract for pgtap/u,
+    );
+    await expectResourceManifestFailure(
+      'wrong-extension-native-module-file',
+      (manifest) => manifest.replace('nativeModuleFile=\n', 'nativeModuleFile=other.dylib\n'),
+      /must declare nativeModuleFile=; got other\.dylib/u,
+    );
+    await expectResourceManifestFailure(
+      'wrong-extension-static-symbol-prefix',
+      (manifest) =>
+        manifest.replace('staticSymbolPrefix=\n', 'staticSymbolPrefix=oliphaunt_static_other\n'),
+      /must declare staticSymbolPrefix=; got oliphaunt_static_other/u,
+    );
+    await expectResourceManifestFailure(
+      'unselected-extension-static-symbol-alias',
+      (manifest) =>
+        manifest.replace('staticSymbolAliases=', 'staticSymbolAliases=sql_symbol:linked_symbol'),
+      /must declare staticSymbolAliases=; got sql_symbol:linked_symbol/u,
+    );
+
+    const undeclaredExtensionFiles = structuredClone(carrier);
+    replaceExtensionAssets(undeclaredExtensionFiles, 'pgtap', [
+      await extendedExtensionRuntime(root, 'pgtap', 'undeclared-extension-files.tar.gz', {
+        'files/share/postgresql/extension/evil--1.0.sql': "SELECT 'undeclared';\n",
+        'files/share/postgresql/extension/evil.control': "default_version = '1.0'\n",
+      }),
+    ]);
+    await expectCarrierFailure(
+      'undeclared-extension-files',
+      undeclaredExtensionFiles,
+      ['pgtap'],
+      /extension artifact inventory must be exact; .*extra=.*evil/u,
+    );
+
+    const undeclaredPrefixedNonSql = structuredClone(carrier);
+    replaceExtensionAssets(undeclaredPrefixedNonSql, 'pgtap', [
+      await extendedExtensionRuntime(root, 'pgtap', 'undeclared-prefixed-non-sql.tar.gz', {
+        'files/share/postgresql/extension/pgtap-core-evil.control': "default_version = '1.0'\n",
+      }),
+    ]);
+    await expectCarrierFailure(
+      'undeclared-prefixed-non-sql',
+      undeclaredPrefixedNonSql,
+      ['pgtap'],
+      /extension artifact inventory must be exact; .*extra=.*pgtap-core-evil\.control/u,
+    );
+
+    const ancillaryOnly = structuredClone(carrier);
+    replaceExtensionAssets(ancillaryOnly, 'pgtap', [
+      await mutatedExtensionRuntime(root, 'pgtap', 'ancillary-only-pgtap.tar.gz', async (stage) => {
+        const extensionDirectory = path.join(stage, 'files', 'share', 'postgresql', 'extension');
+        for (const name of await fs.readdir(extensionDirectory)) {
+          if (name === 'pgtap.sql' || /^pgtap--.*\.sql$/u.test(name)) {
+            await fs.rm(path.join(extensionDirectory, name));
+          }
+        }
+        await write(
+          path.join(extensionDirectory, 'uninstall_pgtap.sql'),
+          "SELECT 'ancillary only';\n",
+        );
+      }),
+    ]);
+    await expectCarrierFailure(
+      'ancillary-only-install-sql',
+      ancillaryOnly,
+      ['pgtap'],
+      /missing an install SQL file owned by pgtap/u,
+    );
+
+    const updateOnly = structuredClone(carrier);
+    replaceExtensionAssets(updateOnly, 'pgtap', [
+      await mutatedExtensionRuntime(root, 'pgtap', 'update-only-pgtap.tar.gz', async (stage) => {
+        await fs.rm(
+          path.join(stage, 'files', 'share', 'postgresql', 'extension', 'pgtap--1.0.sql'),
+        );
+      }),
+    ]);
+    await expectCarrierFailure(
+      'update-only-install-sql',
+      updateOnly,
+      ['pgtap'],
+      /missing an install SQL file owned by pgtap/u,
+    );
+
+    const nonDigitVersion = structuredClone(carrier);
+    replaceExtensionAssets(nonDigitVersion, 'pgtap', [
+      await mutatedExtensionRuntime(
+        root,
+        'pgtap',
+        'non-digit-version-pgtap.tar.gz',
+        async (stage) => {
+          const extensionDirectory = path.join(stage, 'files', 'share', 'postgresql', 'extension');
+          await fs.rm(path.join(extensionDirectory, 'pgtap--1.0.sql'));
+          await write(path.join(extensionDirectory, 'pgtap--beta.sql'), "SELECT 'invalid';\n");
+        },
+      ),
+    ]);
+    await expectCarrierFailure(
+      'non-digit-install-version',
+      nonDigitVersion,
+      ['pgtap'],
+      /missing an install SQL file owned by pgtap/u,
+    );
+
+    const wrongDependencyArchive = structuredClone(carrier);
+    replaceExtensionRuntimeAsset(
+      wrongDependencyArchive,
+      'postgis',
+      await mutatedExtensionRuntime(
+        root,
+        'postgis',
+        'wrong-dependency-archive-name.tar.gz',
+        async (stage) => {
+          const manifestFile = path.join(stage, 'manifest.properties');
+          const manifest = await fs.readFile(manifestFile, 'utf8');
+          await fs.writeFile(
+            manifestFile,
+            manifest.replace('/dependencies/geos/libgeos.a', '/dependencies/geos/arbitrary.a'),
+          );
+        },
+      ),
+    );
+    await expectCarrierFailure(
+      'wrong-dependency-archive-name',
+      wrongDependencyArchive,
+      ['postgis'],
+      /must name a portable static archive lib\*\.a directly under .*\/dependencies\/geos/u,
+    );
+
+    const skewedDependencyArchive = structuredClone(carrier);
+    replaceExtensionRuntimeAsset(
+      skewedDependencyArchive,
+      'pgcrypto',
+      await mutatedExtensionRuntime(
+        root,
+        'pgcrypto',
+        'skewed-dependency-archive-name.tar.gz',
+        async (stage) => {
+          const manifestFile = path.join(stage, 'manifest.properties');
+          const manifest = await fs.readFile(manifestFile, 'utf8');
+          await fs.writeFile(
+            manifestFile,
+            manifest.replace('/dependencies/openssl/libcrypto.a', '/dependencies/openssl/libssl.a'),
+          );
+        },
+      ),
+    );
+    await expectCarrierFailure(
+      'skewed-dependency-archive-name',
+      skewedDependencyArchive,
+      ['pgcrypto'],
+      /must use the same archive file name across both iOS static targets for dependency openssl/u,
+    );
+
+    const oversizedEnvelope = structuredClone(carrier);
+    oversizedEnvelope.base.assets[0].bytes = 2 * 1024 * 1024 * 1024 + 1;
+    await expectCarrierFailure(
+      'oversized-carrier-envelope',
+      oversizedEnvelope,
+      [],
+      /exceeds the maximum supported size/u,
+    );
+
+    const oversizedTar = path.join(root, 'archives', 'oversized-member.tar.gz');
+    await craftedTar(oversizedTar, [{ name: 'payload', type: 'file' }]);
+    await rewriteFirstTarSize(oversizedTar, 4 * 1024 * 1024 * 1024);
+    const oversizedTarCarrier = structuredClone(carrier);
+    replaceExtensionAssets(oversizedTarCarrier, 'pgtap', [
+      await logicalAsset('runtime-resources', oversizedTar, 'tar.gz', '.'),
+    ]);
+    await expectCarrierFailure(
+      'oversized-archive-member',
+      oversizedTarCarrier,
+      ['pgtap'],
+      /exceeds the entry-size limit/u,
+    );
+
+    // Runtime envelopes retain their bounded entry count even when the
+    // individual files are small.
+    const highCardinalityArchive = path.join(root, 'archives', 'many-members.tar.gz');
+    await fs.writeFile(
+      highCardinalityArchive,
+      tarArchive(
+        Array.from({ length: 4098 }, (_, index) => ({
+          name: 'files/member-' + index,
+          data: Buffer.from('fixture'),
+        })),
+      ),
+    );
+    const highCardinalityRuntime = structuredClone(carrier);
+    const highCardinalityRuntimeArchive = path.join(
+      root,
+      'archives',
+      'high-cardinality-runtime',
+      'liboliphaunt-1.0.0-runtime-resources-ios-datum64.tar.gz',
+    );
+    await fs.mkdir(path.dirname(highCardinalityRuntimeArchive), { recursive: true });
+    await fs.copyFile(highCardinalityArchive, highCardinalityRuntimeArchive);
+    highCardinalityRuntime.base.assets = await Promise.all(
+      highCardinalityRuntime.base.assets.map(async (row) =>
+        row.role === 'runtime-resources'
+          ? asset('runtime-resources', highCardinalityRuntimeArchive, 'tar.gz', 'files')
+          : row,
+      ),
+    );
+    await expectCarrierFailure(
+      'high-cardinality-runtime',
+      highCardinalityRuntime,
+      [],
+      /4096-entry limit/u,
+    );
+
+    const highCardinalityFrameworkArchive = path.join(
+      root,
+      'archives',
+      'liboliphaunt-1.0.0-high-cardinality.xcframework.zip',
+    );
+    const baseFrameworkAsset = carrier.base.assets.find(({ role }) => role === 'base-xcframework');
+    await fs.copyFile(fileURLToPath(baseFrameworkAsset.url), highCardinalityFrameworkArchive);
+    await appendZipFiles(
+      highCardinalityFrameworkArchive,
+      'liboliphaunt.xcframework/ios-arm64/liboliphaunt.framework/Resources/oliphaunt/high-cardinality',
+      8192,
+    );
+    const highCardinalityFramework = structuredClone(carrier);
+    highCardinalityFramework.base.assets = await Promise.all(
+      highCardinalityFramework.base.assets.map(async (row) =>
+        row.role === 'base-xcframework'
+          ? asset(
+              'base-xcframework',
+              highCardinalityFrameworkArchive,
+              'zip',
+              'liboliphaunt.xcframework',
+            )
+          : row,
+      ),
+    );
+    const highCardinalityFrameworkCarrierFile = path.join(root, 'high-cardinality-framework.json');
+    await write(
+      highCardinalityFrameworkCarrierFile,
+      `${JSON.stringify(highCardinalityFramework, null, 2)}\n`,
+    );
+    const highCardinalityFrameworkOutput = path.join(root, 'high-cardinality-framework-output');
+    await stageIosApp({
+      allowFileUrls: true,
+      cacheDir: path.join(root, 'high-cardinality-framework-cache'),
+      carriers: [highCardinalityFrameworkCarrierFile],
+      extensions: [],
+      icu: false,
+      outputDir: highCardinalityFrameworkOutput,
+    });
+    await fs.access(
+      path.join(
+        highCardinalityFrameworkOutput,
+        'frameworks',
+        'base',
+        'liboliphaunt.xcframework',
+        'Info.plist',
+      ),
+    );
+
+    const traversalArchive = path.join(root, 'archives', 'malicious-traversal.zip');
+    await maliciousZip(traversalArchive, '../escaped-from-rn.txt', 'file');
+    const traversal = structuredClone(carrier);
+    traversal.base.assets = await Promise.all(
+      traversal.base.assets.map(async (row) =>
+        row.role === 'base-xcframework'
+          ? asset('base-xcframework', traversalArchive, 'zip', 'liboliphaunt.xcframework')
+          : row,
+      ),
+    );
+    const rejectedAsset = traversal.base.assets.find(({ role }) => role === 'base-xcframework');
+    const previousExtraction = path.join(
+      root,
+      'malicious-traversal-cache',
+      'extracted',
+      rejectedAsset.sha256,
+    );
+    await write(path.join(previousExtraction, 'preserved.txt'), 'previous extraction\n');
+    await write(`${previousExtraction}.tree.json`, 'previous manifest\n');
+    await expectCarrierFailure('malicious-traversal', traversal, [], /unsafe archive member/u);
+    assert.equal(
+      await fs.readFile(path.join(previousExtraction, 'preserved.txt'), 'utf8'),
+      'previous extraction\n',
+    );
+    assert.equal(
+      await fs.readFile(`${previousExtraction}.tree.json`, 'utf8'),
+      'previous manifest\n',
+    );
+    await assert.rejects(
+      fs.access(path.join(root, 'malicious-traversal-cache', 'extracted', 'escaped-from-rn.txt')),
+    );
+
+    const symlinkArchive = path.join(root, 'archives', 'malicious-symlink.zip');
+    await maliciousZip(symlinkArchive, 'liboliphaunt.xcframework', 'symlink');
+    const symlink = structuredClone(carrier);
+    symlink.base.assets = await Promise.all(
+      symlink.base.assets.map(async (row) =>
+        row.role === 'base-xcframework'
+          ? asset('base-xcframework', symlinkArchive, 'zip', 'liboliphaunt.xcframework')
+          : row,
+      ),
+    );
+    await expectCarrierFailure('malicious-symlink', symlink, [], /link or special (?:ZIP )?entry/u);
+
+    const ambiguousUnixArchive = path.join(root, 'archives', 'ambiguous-unix-types.zip');
+    await metadataZip(ambiguousUnixArchive, 'ambiguous-unix');
+    const ambiguousUnix = structuredClone(carrier);
+    ambiguousUnix.base.assets = await Promise.all(
+      ambiguousUnix.base.assets.map(async (row) =>
+        row.role === 'base-xcframework'
+          ? asset('base-xcframework', ambiguousUnixArchive, 'zip', 'liboliphaunt.xcframework')
+          : row,
+      ),
+    );
+    await expectCarrierFailure(
+      'ambiguous-unix-types',
+      ambiguousUnix,
+      [],
+      /ambiguous Unix creator type/u,
+    );
+
+    const fatArchive = path.join(root, 'archives', 'fat-types.zip');
+    await metadataZip(
+      fatArchive,
+      'fat',
+      path.join(root, 'source', 'base', 'framework', 'liboliphaunt.xcframework'),
+    );
+    const fat = structuredClone(carrier);
+    fat.base.assets = await Promise.all(
+      fat.base.assets.map(async (row) =>
+        row.role === 'base-xcframework'
+          ? asset('base-xcframework', fatArchive, 'zip', 'liboliphaunt.xcframework')
+          : row,
+      ),
+    );
+    const fatCarrierFile = path.join(root, 'fat-types.json');
+    await write(fatCarrierFile, `${JSON.stringify(fat, null, 2)}\n`);
+    const fatOutput = path.join(root, 'fat-types-output');
+    await stageIosApp({
+      allowFileUrls: true,
+      cacheDir: path.join(root, 'fat-types-cache'),
+      carriers: [fatCarrierFile],
+      extensions: [],
+      icu: false,
+      outputDir: fatOutput,
+    });
+    await fs.access(
+      path.join(fatOutput, 'frameworks', 'base', 'liboliphaunt.xcframework', 'Info.plist'),
+    );
+
+    const unicodeExtraArchive = path.join(root, 'archives', 'unicode-path-extra.zip');
+    await metadataZip(unicodeExtraArchive, 'unicode-extra');
+    const unicodeExtra = structuredClone(carrier);
+    unicodeExtra.base.assets = await Promise.all(
+      unicodeExtra.base.assets.map(async (row) =>
+        row.role === 'base-xcframework'
+          ? asset('base-xcframework', unicodeExtraArchive, 'zip', 'liboliphaunt.xcframework')
+          : row,
+      ),
+    );
+    await expectCarrierFailure(
+      'unicode-path-extra',
+      unicodeExtra,
+      [],
+      /unsupported ZIP .* extra field 0x7075/u,
+    );
+
+    const unsupportedFlagsArchive = path.join(root, 'archives', 'unsupported-flags.zip');
+    await metadataZip(unsupportedFlagsArchive, 'fat');
+    await addUnsupportedZipFlag(unsupportedFlagsArchive);
+    const unsupportedFlags = structuredClone(carrier);
+    unsupportedFlags.base.assets = await Promise.all(
+      unsupportedFlags.base.assets.map(async (row) =>
+        row.role === 'base-xcframework'
+          ? asset('base-xcframework', unsupportedFlagsArchive, 'zip', 'liboliphaunt.xcframework')
+          : row,
+      ),
+    );
+    await expectCarrierFailure(
+      'unsupported-flags',
+      unsupportedFlags,
+      [],
+      /unsupported or encrypted ZIP flags 0x20/u,
+    );
+
+    for (const [name, entries, pattern] of [
+      [
+        'tar-file-directory-marker',
+        [{ name: 'payload', type: 'file' }],
+        /member type\/path-marker mismatch/u,
+      ],
+      ['tar-traversal', [{ name: '../payload', type: 'file' }], /unsafe archive member/u],
+      ['tar-symlink', [{ name: 'payload', type: 'symlink' }], /link or special ustar entry/u],
+      [
+        'tar-duplicate',
+        [
+          { name: 'payload', type: 'file' },
+          { name: 'payload', type: 'file' },
+        ],
+        /repeats archive member|EEXIST/u,
+      ],
+      [
+        'tar-case-collision',
+        [
+          { name: 'Payload', type: 'file' },
+          { name: 'payload', type: 'file' },
+        ],
+        /case\/NFC-colliding archive members/u,
+      ],
+      [
+        'tar-file-as-parent',
+        [
+          { name: 'parent', type: 'file' },
+          { name: 'parent/child', type: 'file' },
+        ],
+        /uses regular file parent as an archive directory|EEXIST|ENOTDIR/u,
+      ],
+    ]) {
+      const archive = path.join(root, 'archives', `${name}.tar.gz`);
+      await craftedTar(archive, entries);
+      if (name === 'tar-file-directory-marker') await addTarFileSlash(archive, 'payload');
+      const candidate = structuredClone(carrier);
+      replaceExtensionAssets(candidate, 'pgtap', [
+        await logicalAsset('runtime-resources', archive, 'tar.gz', '.'),
+      ]);
+      await expectCarrierFailure(name, candidate, ['pgtap'], pattern);
+    }
+
+    const unstable = structuredClone(carrier);
+    unstable.base.version = '1.0.0-rc.1';
+    unstable.base.tag = 'liboliphaunt-native-v1.0.0-rc.1';
+    await expectCarrierFailure('unstable-version', unstable, [], /stable SemVer/u);
+
+    const leadingZero = structuredClone(carrier);
+    leadingZero.extensions.find(({ sqlName }) => sqlName === 'pgtap').version = '01.0.0';
+    leadingZero.extensions.find(({ sqlName }) => sqlName === 'pgtap').tag =
+      'oliphaunt-extension-pgtap-v01.0.0';
+    await expectCarrierFailure('leading-zero-version', leadingZero, ['pgtap'], /stable SemVer/u);
+
+    const fakeOwner = structuredClone(carrier);
+    fakeOwner.extensions.find(({ sqlName }) => sqlName === 'cube').product =
+      'oliphaunt-extension-fake-cube';
+    fakeOwner.extensions.find(({ sqlName }) => sqlName === 'cube').tag =
+      'oliphaunt-extension-fake-cube-v1.0.0';
+    await expectCarrierFailure(
+      'fake-owner',
+      fakeOwner,
+      ['cube'],
+      /product must be canonical artifact product oliphaunt-extension-contrib-pg18/u,
+    );
+
+    const ownerVersionConflict = structuredClone(carrier);
+    ownerVersionConflict.extensions.find(({ sqlName }) => sqlName === 'earthdistance').version =
+      '1.0.1';
+    ownerVersionConflict.extensions.find(({ sqlName }) => sqlName === 'earthdistance').tag =
+      'liboliphaunt-native-v1.0.1';
+    await expectCarrierFailure(
+      'owner-version-conflict',
+      ownerVersionConflict,
+      ['earthdistance'],
+      /conflicting release versions for owner liboliphaunt-native/u,
+    );
+
+    const wrongTag = structuredClone(carrier);
+    wrongTag.extensions.find(({ sqlName }) => sqlName === 'pgtap').tag = 'unrelated-v1.0.0';
+    await expectCarrierFailure(
+      'wrong-tag',
+      wrongTag,
+      ['pgtap'],
+      /\.tag must be oliphaunt-extension-pgtap-v1\.0\.0/u,
+    );
+
+    const malformedAssets = structuredClone(carrier);
+    malformedAssets.extensions.find(({ sqlName }) => sqlName === 'pgtap').assets = {};
+    await expectCarrierFailure(
+      'malformed-assets',
+      malformedAssets,
+      ['pgtap'],
+      /\.assets must be an array/u,
+    );
+
+    const malformedRegistration = structuredClone(carrier);
+    malformedRegistration.extensions.find(
+      ({ sqlName }) => sqlName === 'cube',
+    ).registration.symbols = 'not-an-array';
+    await expectCarrierFailure(
+      'malformed-registration',
+      malformedRegistration,
+      ['cube'],
+      /registration\.symbols must be an array/u,
+    );
+
+    const duplicateLocator = structuredClone(carrier);
+    const duplicateLocatorPostgis = duplicateLocator.extensions.find(
+      ({ sqlName }) => sqlName === 'postgis',
+    );
+    duplicateLocatorPostgis.assets.push(structuredClone(duplicateLocatorPostgis.assets[0]));
+    await expectCarrierFailure(
+      'duplicate-asset-locator',
+      duplicateLocator,
+      ['postgis'],
+      /repeats an asset locator identity/u,
+    );
+
+    const duplicateIdentity = structuredClone(carrier);
+    const duplicateIdentityPostgis = duplicateIdentity.extensions.find(
+      ({ sqlName }) => sqlName === 'postgis',
+    );
+    const geosAsset = duplicateIdentityPostgis.assets.find(
+      ({ role }) => role === 'dependency-xcframework',
+    );
+    const geosEnvelope = duplicateIdentity.carriers.find(({ name }) => name === geosAsset.carrier);
+    const duplicateGeosArchive = path.join(root, 'archives', 'postgis-geos-duplicate.zip');
+    await fs.copyFile(new URL(geosEnvelope.url), duplicateGeosArchive);
+    const duplicateGeos = await logicalAsset(
+      'dependency-xcframework',
+      duplicateGeosArchive,
+      'zip',
+      `nested/${path.posix.basename(geosAsset.member)}`,
+    );
+    duplicateIdentityPostgis.assets.push(duplicateGeos.locator);
+    duplicateIdentity.carriers.push(duplicateGeos.envelope);
+    await expectCarrierFailure(
+      'duplicate-dependency-identity',
+      duplicateIdentity,
+      ['postgis'],
+      /repeats a dependency carrier identity/u,
+    );
+
+    await expectReject(
+      () =>
+        stageIosApp({
+          carriers: [carrierFile],
+          extensions: [],
+          outputDir: path.join(root, 'https-only'),
+        }),
+      /must use HTTPS/u,
+    );
+
+    const missingDependencyFile = path.join(root, 'missing-dependency.json');
+    await write(
+      missingDependencyFile,
+      `${JSON.stringify(
+        {
+          base: carrier.base,
+          carriers: carrier.carriers.filter(({ name }) =>
+            carrier.extensions
+              .find(({ sqlName }) => sqlName === 'earthdistance')
+              .assets.some(({ carrier: carrierName }) => carrierName === name),
+          ),
+          extensions: carrier.extensions.filter(({ sqlName }) => sqlName === 'earthdistance'),
+          legal: {
+            base: carrier.legal.base,
+            extensions: carrier.legal.extensions.filter(
+              ({ sqlName }) => sqlName === 'earthdistance',
+            ),
+          },
+          schema: SCHEMA,
+        },
+        null,
+        2,
+      )}\n`,
+    );
+    await expectReject(
+      () =>
+        stageIosApp({
+          allowFileUrls: true,
+          cacheDir: path.join(root, 'missing-cache'),
+          carriers: [missingDependencyFile],
+          extensions: ['earthdistance'],
+          outputDir: path.join(root, 'missing-output'),
+        }),
+      /missing iOS carrier for cube required by earthdistance/u,
+    );
+
+    const tampered = structuredClone(carrier);
+    tampered.base.assets.find(({ role }) => role === 'runtime-resources').sha256 = '0'.repeat(64);
+    const tamperedFile = path.join(root, 'tampered.json');
+    await write(tamperedFile, `${JSON.stringify(tampered, null, 2)}\n`);
+    await expectReject(
+      () =>
+        stageIosApp({
+          allowFileUrls: true,
+          cacheDir: path.join(root, 'tampered-cache'),
+          carriers: [tamperedFile],
+          extensions: [],
+          outputDir: path.join(root, 'tampered-output'),
+        }),
+      /checksum mismatch/u,
+    );
+
+    const carrierLeafDependencySkew = structuredClone(carrier);
+    const omittedPostgis = carrierLeafDependencySkew.extensions.find(
+      ({ sqlName }) => sqlName === 'postgis',
+    );
+    omittedPostgis.nativeDependencies = omittedPostgis.nativeDependencies.filter(
+      (dependency) => dependency !== 'geos',
+    );
+    omittedPostgis.assets = omittedPostgis.assets.filter(
+      ({ member, role }) =>
+        !(role === 'dependency-xcframework' && member.endsWith('dependency_geos.xcframework')),
+    );
+    retainReferencedCarriers(carrierLeafDependencySkew);
+    await expectCarrierFailure(
+      'carrier-leaf-dependency-skew',
+      carrierLeafDependencySkew,
+      ['postgis'],
+      /mobileStaticDependencyArchives must exactly cover both iOS static targets/u,
+    );
+
+    const wrongInventory = structuredClone(carrier);
+    const postgis = wrongInventory.extensions.find(({ sqlName }) => sqlName === 'postgis');
+    postgis.assets = postgis.assets.filter(({ role }) => role !== 'dependency-xcframework');
+    retainReferencedCarriers(wrongInventory);
+    const wrongInventoryFile = path.join(root, 'wrong-inventory.json');
+    await write(wrongInventoryFile, `${JSON.stringify(wrongInventory, null, 2)}\n`);
+    await expectReject(
+      () =>
+        stageIosApp({
+          allowFileUrls: true,
+          cacheDir: path.join(root, 'inventory-cache'),
+          carriers: [wrongInventoryFile],
+          extensions: ['postgis'],
+          outputDir: path.join(root, 'inventory-output'),
+        }),
+      /dependency-xcframework roles do not exactly match nativeDependencies/u,
+    );
+
+    console.log(
+      'stage-ios-app.test.mts: carrier, malicious ZIP, cache-tamper, and payload checks passed',
+    );
+  } finally {
+    if (!process.env.OLIPHAUNT_TEST_IOS_STAGE_ROOT)
+      await fs.rm(root, { force: true, recursive: true });
+  }
+}
+
+main().catch((error) => {
+  console.error(error instanceof Error ? error.stack : String(error));
+  process.exit(1);
+});
diff --git a/src/sdks/react-native/tools/stage-ios-app.test.sh b/src/sdks/react-native/tools/stage-ios-app.test.sh
new file mode 100644
index 000000000..98cc64baa
--- /dev/null
+++ b/src/sdks/react-native/tools/stage-ios-app.test.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+set -euo pipefail
+tools="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+OLIPHAUNT_TEST_IOS_STAGE_ROOT="$scratch" bun "$tools/stage-ios-app.test.mts"
+bun "$tools/verify-ios-package.mts" --payload-dir "$scratch/consumer/ios/oliphaunt"
+if bun "$tools/verify-ios-package.mts" --payload-dir "$scratch/tampered-legal-notice-output" > "$scratch/cli.log" 2>&1; then
+  echo 'tampered legal notice unexpectedly verified' >&2
+  exit 1
+fi
+grep -q 'does not exactly index the frozen legal selection' "$scratch/cli.log"
diff --git a/src/sdks/react-native/tools/stage-release-artifacts.mts b/src/sdks/react-native/tools/stage-release-artifacts.mts
new file mode 100644
index 000000000..85793d50b
--- /dev/null
+++ b/src/sdks/react-native/tools/stage-release-artifacts.mts
@@ -0,0 +1,49 @@
+import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+import {
+  IOS_CARRIER_FILENAME,
+  buildIosCarrierManifest,
+} from '../../swift/tools/ios-carrier-manifest.mts';
+import { fail, requireDir } from '../../../../tools/packaging/staging.mts';
+
+export function stageArtifacts(artifactRoot, workRoot) {
+  const releasePackageDir = path.join(workRoot, 'package');
+  requireDir(releasePackageDir);
+  const assetDir = process.env.OLIPHAUNT_REACT_NATIVE_IOS_RELEASE_ASSET_DIR;
+  if (!assetDir) {
+    fail(
+      'oliphaunt-react-native package artifacts require OLIPHAUNT_REACT_NATIVE_IOS_RELEASE_ASSET_DIR',
+    );
+  }
+  const carrier = buildIosCarrierManifest({
+    baseAssetDir: assetDir,
+    extensionManifests: [],
+  });
+  writeFileSync(
+    path.join(releasePackageDir, IOS_CARRIER_FILENAME),
+    `${JSON.stringify(carrier, null, 2)}\n`,
+    'utf8',
+  );
+  const packageJsonFile = path.join(releasePackageDir, 'package.json');
+  const packageJson = JSON.parse(readFileSync(packageJsonFile, 'utf8'));
+  packageJson.oliphaunt = {
+    ...(packageJson.oliphaunt ?? {}),
+    iosCarrierManifest: `./${IOS_CARRIER_FILENAME}`,
+  };
+  packageJson.files = [...new Set([...(packageJson.files ?? []), IOS_CARRIER_FILENAME])];
+  packageJson.exports = {
+    ...(packageJson.exports ?? {}),
+    './ios-carriers': `./${IOS_CARRIER_FILENAME}`,
+  };
+  writeFileSync(packageJsonFile, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf8');
+  const carrierEvidence = path.join(artifactRoot, 'ios-carriers', IOS_CARRIER_FILENAME);
+  mkdirSync(path.dirname(carrierEvidence), { recursive: true });
+  writeFileSync(carrierEvidence, `${JSON.stringify(carrier, null, 2)}\n`, 'utf8');
+}
+
+if (import.meta.main) {
+  if (process.argv.length !== 4)
+    throw new Error('usage: stage-release-artifacts.mts  ');
+  stageArtifacts(path.resolve(process.argv[2]), path.resolve(process.argv[3]));
+}
diff --git a/src/sdks/react-native/tools/stage-release-artifacts.sh b/src/sdks/react-native/tools/stage-release-artifacts.sh
new file mode 100644
index 000000000..9cacb7888
--- /dev/null
+++ b/src/sdks/react-native/tools/stage-release-artifacts.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+artifact_root="$PWD/target/sdk-artifacts/oliphaunt-react-native"
+work_root="$PWD/target/sdk-artifacts-work/oliphaunt-react-native"
+rm -rf "$artifact_root" "$work_root"
+mkdir -p "$artifact_root" "$work_root/package/src/generated"
+rsync -a --exclude node_modules --exclude .build --exclude android/.gradle --exclude android/.cxx --exclude android/build --exclude ios/vendor src/sdks/react-native/ "$work_root/package/"
+cp src/extensions/generated/sdk/extensions.json src/extensions/generated/sdk/ios-static-dependencies.json "$work_root/package/src/generated/"
+mkdir -p "$work_root/package/android/src/main/cpp/include"
+cp src/runtimes/liboliphaunt-native/include/oliphaunt.h "$work_root/package/android/src/main/cpp/include/oliphaunt.h"
+cp LICENSE THIRD_PARTY_NOTICES.md "$work_root/package/"
+bun src/sdks/react-native/tools/stage-release-artifacts.mts "$artifact_root" "$work_root"
+node "$work_root/package/tools/verify-ios-package.mjs" --package-dir "$work_root/package"
+bun tools/packaging/source-only-sdk-package.mts prepare-npm react-native "$work_root/package"
+filename="$(bun tools/packaging/npm-package.mts "$work_root/package")"
+archive="$artifact_root/$filename"
+bun pm pack --cwd "$work_root/package" --filename "$archive"
+
+bun tools/packaging/source-only-sdk-package.mts check-npm-archive react-native "$archive"
+bun tools/packaging/staging.mts "$artifact_root"
diff --git a/src/sdks/react-native/tools/test-consumer.sh b/src/sdks/react-native/tools/test-consumer.sh
new file mode 100644
index 000000000..182dff10f
--- /dev/null
+++ b/src/sdks/react-native/tools/test-consumer.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../../../.."
+archives=(target/sdk-artifacts/oliphaunt-react-native/*.tgz)
+[ "${#archives[@]}" -eq 1 ] && [ -f "${archives[0]}" ]
+bash src/sdks/react-native/tools/check-icu-autolinking.sh \
+  "$PWD/${archives[0]}" "$PWD/src/database-resources/icu/npm" "$PWD/src/examples/react-native-expo"
diff --git a/src/sdks/react-native/tools/test-cpp.sh b/src/sdks/react-native/tools/test-cpp.sh
new file mode 100644
index 000000000..0037a4ee1
--- /dev/null
+++ b/src/sdks/react-native/tools/test-cpp.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-rn-cpp-XXXXXX")
+trap 'rm -rf "$scratch"' EXIT
+"${CXX:-c++}" -std=c++17 -pthread -Wall -Wextra -Werror cpp/Lifecycle.test.cpp -o "$scratch/lifecycle"
+"$scratch/lifecycle"
diff --git a/src/sdks/react-native/tools/test.sh b/src/sdks/react-native/tools/test.sh
new file mode 100644
index 000000000..217415592
--- /dev/null
+++ b/src/sdks/react-native/tools/test.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
+tests=(./src/__tests__)
+for test in ./tools/*.test.mts; do
+  [[ -f "${test%.mts}.sh" ]] || tests+=("$test")
+done
+bun test --isolate --timeout=30000 "${tests[@]}"
+for test in tools/stage-ios-app.test.sh tools/ios-app-transport.test.sh tools/expo-ios-runner.test.sh tools/mobile-extension-artifact-paths.test.sh; do
+  bash "$test"
+done
+for test in tools/mobile-extension-selection.test.sh tools/verify-android-apk.test.sh tools/android-apk-resources.test.sh tools/expo-android-gradle-limits.test.sh tools/expo-runner-android-device.test.sh tools/expo-runner-ios-installed-app.test.sh tools/expo-runner-workspace.test.sh tools/expo-packed-workspace.test.sh; do
+  bash "$test"
+done
diff --git a/src/sdks/react-native/tools/validate-android-link-evidence.mjs b/src/sdks/react-native/tools/validate-android-link-evidence.mjs
deleted file mode 100644
index 896499ad3..000000000
--- a/src/sdks/react-native/tools/validate-android-link-evidence.mjs
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/env node
-
-import { readFileSync, statSync } from 'node:fs';
-import path from 'node:path';
-import { fileURLToPath } from 'node:url';
-
-const SCHEMA = 'oliphaunt-android-static-extension-link-v1';
-
-export function validateAndroidLinkEvidence({
-  evidenceFile,
-  expectedAbi,
-  expectedModuleStems,
-  staticRegistryManifest,
-  target,
-}) {
-  const registry = readProperties(staticRegistryManifest);
-  const expectedExtensions = new Set(csv(expectedModuleStems));
-  const expectedDependencies = new Set(csv(registry.dependencyArchives));
-  const extensions = new Set();
-  const dependencies = new Set();
-  let schemaRows = 0;
-  let abiRows = 0;
-  let runtimeRows = 0;
-
-  const lines = readFileSync(evidenceFile, 'utf8').split(/\r?\n/u);
-  for (let index = 0; index < lines.length; index += 1) {
-    if (!lines[index]) continue;
-    const parts = lines[index].split('\t');
-    const line = index + 1;
-    switch (parts[0]) {
-      case 'schema':
-        exact(parts, ['schema', SCHEMA], evidenceFile, line);
-        schemaRows += 1;
-        break;
-      case 'abi':
-        exact(parts, ['abi', expectedAbi], evidenceFile, line);
-        abiRows += 1;
-        break;
-      case 'runtime':
-        if (parts.length !== 3 || parts[1] !== 'liboliphaunt') {
-          fail(evidenceFile, line, 'invalid runtime row');
-        }
-        requireFile(parts[2], evidenceFile, line, 'runtime');
-        if (path.basename(parts[2]) !== 'liboliphaunt.so') {
-          fail(evidenceFile, line, 'runtime path must end in liboliphaunt.so');
-        }
-        runtimeRows += 1;
-        break;
-      case 'extension':
-        validateArchiveRow({
-          parts,
-          evidenceFile,
-          line,
-          registry,
-          target,
-          kind: 'extension',
-          expectedKey: stem => `module.${stem}.archive.${target}`,
-          expectedName: stem => `liboliphaunt_extension_${stem}.a`,
-        });
-        addUnique(extensions, parts[1], evidenceFile, line, 'extension');
-        break;
-      case 'dependency':
-        validateArchiveRow({
-          parts,
-          evidenceFile,
-          line,
-          registry,
-          target,
-          kind: 'dependency',
-          expectedKey: name => `dependency.${name}.archive.${target}`,
-        });
-        addUnique(dependencies, parts[1], evidenceFile, line, 'dependency');
-        break;
-      default:
-        fail(evidenceFile, line, `unknown row kind ${JSON.stringify(parts[0])}`);
-    }
-  }
-
-  if (schemaRows !== 1) throw new Error(`${evidenceFile} must contain exactly one schema row`);
-  if (abiRows !== 1) throw new Error(`${evidenceFile} must contain exactly one ABI row`);
-  if (runtimeRows !== 1) throw new Error(`${evidenceFile} must contain exactly one runtime row`);
-  exactSet(extensions, expectedExtensions, evidenceFile, 'extension');
-  exactSet(dependencies, expectedDependencies, evidenceFile, 'dependency');
-  return { extensions: [...extensions].sort(), dependencies: [...dependencies].sort() };
-}
-
-function validateArchiveRow({
-  parts,
-  evidenceFile,
-  line,
-  registry,
-  target,
-  kind,
-  expectedKey,
-  expectedName,
-}) {
-  if (parts.length !== 3 || !parts[1]) fail(evidenceFile, line, `invalid ${kind} row`);
-  const [name, rawArchive] = [parts[1], parts[2]];
-  const archive = requireFile(rawArchive, evidenceFile, line, kind);
-  const relative = registry[expectedKey(name)];
-  if (!relative) {
-    fail(evidenceFile, line, `${kind} ${JSON.stringify(name)} is absent from the static registry for ${target}`);
-  }
-  if (expectedName && path.basename(archive) !== expectedName(name)) {
-    fail(evidenceFile, line, `${kind} archive name does not match ${JSON.stringify(name)}`);
-  }
-  if (!slash(archive).endsWith(slash(relative))) {
-    fail(evidenceFile, line, `${kind} archive does not match registry path ${JSON.stringify(relative)}`);
-  }
-}
-
-function readProperties(file) {
-  const properties = {};
-  for (const rawLine of readFileSync(file, 'utf8').split(/\r?\n/u)) {
-    const line = rawLine.trim();
-    if (!line || line.startsWith('#')) continue;
-    const separator = line.indexOf('=');
-    if (separator < 1) throw new Error(`${file} contains an invalid properties row: ${rawLine}`);
-    properties[line.slice(0, separator)] = line.slice(separator + 1);
-  }
-  return properties;
-}
-
-function requireFile(raw, evidenceFile, line, kind) {
-  const resolved = path.isAbsolute(raw) ? raw : path.resolve(path.dirname(evidenceFile), raw);
-  try {
-    if (!statSync(resolved).isFile()) throw new Error('not a file');
-  } catch {
-    fail(evidenceFile, line, `${kind} path does not exist: ${resolved}`);
-  }
-  return resolved;
-}
-
-function exact(actual, expected, file, line) {
-  if (JSON.stringify(actual) !== JSON.stringify(expected)) fail(file, line, `expected ${expected.join('\t')}`);
-}
-
-function exactSet(actual, expected, file, kind) {
-  const missing = [...expected].filter(value => !actual.has(value)).sort();
-  const unexpected = [...actual].filter(value => !expected.has(value)).sort();
-  if (missing.length || unexpected.length) {
-    throw new Error(
-      `${file} ${kind} set mismatch (missing=${missing.join(',') || '-'}, unexpected=${unexpected.join(',') || '-'})`,
-    );
-  }
-}
-
-function addUnique(set, value, file, line, kind) {
-  if (set.has(value)) fail(file, line, `duplicate ${kind} ${JSON.stringify(value)}`);
-  set.add(value);
-}
-
-function csv(value) {
-  return String(value ?? '').split(',').map(item => item.trim()).filter(Boolean);
-}
-
-function slash(value) {
-  return String(value).split(path.sep).join('/');
-}
-
-function fail(file, line, message) {
-  throw new Error(`${file}:${line} ${message}`);
-}
-
-function parseCli(argv) {
-  const values = {};
-  for (let index = 0; index < argv.length; index += 2) {
-    const key = argv[index];
-    const value = argv[index + 1];
-    if (!key?.startsWith('--') || value === undefined) throw new Error('arguments must be --name value pairs');
-    values[key.slice(2)] = value;
-  }
-  return values;
-}
-
-if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
-  try {
-    const args = parseCli(process.argv.slice(2));
-    validateAndroidLinkEvidence({
-      evidenceFile: args.evidence,
-      expectedAbi: args.abi,
-      expectedModuleStems: args['module-stems'],
-      staticRegistryManifest: args['static-registry'],
-      target: args.target,
-    });
-    console.log(`validated Android static-extension link evidence: ${args.evidence}`);
-  } catch (error) {
-    console.error(`validate-android-link-evidence.mjs: ${error.message}`);
-    process.exitCode = 1;
-  }
-}
diff --git a/src/sdks/react-native/tools/validate-android-link-evidence.mts b/src/sdks/react-native/tools/validate-android-link-evidence.mts
new file mode 100644
index 000000000..34f6180b8
--- /dev/null
+++ b/src/sdks/react-native/tools/validate-android-link-evidence.mts
@@ -0,0 +1,204 @@
+#!/usr/bin/env bun
+
+import { readFileSync, statSync } from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const SCHEMA = 'oliphaunt-android-static-extension-link-v1';
+
+export function validateAndroidLinkEvidence({
+  evidenceFile,
+  expectedAbi,
+  expectedModuleStems,
+  staticRegistryManifest,
+  target,
+}) {
+  const registry = readProperties(staticRegistryManifest);
+  const expectedExtensions = new Set(csv(expectedModuleStems));
+  const expectedDependencies = new Set(csv(registry.dependencyArchives));
+  const extensions = new Set();
+  const dependencies = new Set();
+  let schemaRows = 0;
+  let abiRows = 0;
+  let runtimeRows = 0;
+
+  const lines = readFileSync(evidenceFile, 'utf8').split(/\r?\n/u);
+  for (let index = 0; index < lines.length; index += 1) {
+    if (!lines[index]) continue;
+    const parts = lines[index].split('\t');
+    const line = index + 1;
+    switch (parts[0]) {
+      case 'schema':
+        exact(parts, ['schema', SCHEMA], evidenceFile, line);
+        schemaRows += 1;
+        break;
+      case 'abi':
+        exact(parts, ['abi', expectedAbi], evidenceFile, line);
+        abiRows += 1;
+        break;
+      case 'runtime':
+        if (parts.length !== 3 || parts[1] !== 'liboliphaunt') {
+          fail(evidenceFile, line, 'invalid runtime row');
+        }
+        requireFile(parts[2], evidenceFile, line, 'runtime');
+        if (path.basename(parts[2]) !== 'liboliphaunt.so') {
+          fail(evidenceFile, line, 'runtime path must end in liboliphaunt.so');
+        }
+        runtimeRows += 1;
+        break;
+      case 'extension':
+        validateArchiveRow({
+          parts,
+          evidenceFile,
+          line,
+          registry,
+          target,
+          kind: 'extension',
+          expectedKey: (stem) => `module.${stem}.archive.${target}`,
+          expectedName: (stem) => `liboliphaunt_extension_${stem}.a`,
+        });
+        addUnique(extensions, parts[1], evidenceFile, line, 'extension');
+        break;
+      case 'dependency':
+        validateArchiveRow({
+          parts,
+          evidenceFile,
+          line,
+          registry,
+          target,
+          kind: 'dependency',
+          expectedKey: (name) => `dependency.${name}.archive.${target}`,
+        });
+        addUnique(dependencies, parts[1], evidenceFile, line, 'dependency');
+        break;
+      default:
+        fail(evidenceFile, line, `unknown row kind ${JSON.stringify(parts[0])}`);
+    }
+  }
+
+  if (schemaRows !== 1) throw new Error(`${evidenceFile} must contain exactly one schema row`);
+  if (abiRows !== 1) throw new Error(`${evidenceFile} must contain exactly one ABI row`);
+  if (runtimeRows !== 1) throw new Error(`${evidenceFile} must contain exactly one runtime row`);
+  exactSet(extensions, expectedExtensions, evidenceFile, 'extension');
+  exactSet(dependencies, expectedDependencies, evidenceFile, 'dependency');
+  return { extensions: [...extensions].sort(), dependencies: [...dependencies].sort() };
+}
+
+function validateArchiveRow({
+  parts,
+  evidenceFile,
+  line,
+  registry,
+  target,
+  kind,
+  expectedKey,
+  expectedName,
+}) {
+  if (parts.length !== 3 || !parts[1]) fail(evidenceFile, line, `invalid ${kind} row`);
+  const [name, rawArchive] = [parts[1], parts[2]];
+  const archive = requireFile(rawArchive, evidenceFile, line, kind);
+  const relative = registry[expectedKey(name)];
+  if (!relative) {
+    fail(
+      evidenceFile,
+      line,
+      `${kind} ${JSON.stringify(name)} is absent from the static registry for ${target}`,
+    );
+  }
+  if (expectedName && path.basename(archive) !== expectedName(name)) {
+    fail(evidenceFile, line, `${kind} archive name does not match ${JSON.stringify(name)}`);
+  }
+  if (!slash(archive).endsWith(slash(relative))) {
+    fail(
+      evidenceFile,
+      line,
+      `${kind} archive does not match registry path ${JSON.stringify(relative)}`,
+    );
+  }
+}
+
+function readProperties(file) {
+  const properties = {};
+  for (const rawLine of readFileSync(file, 'utf8').split(/\r?\n/u)) {
+    const line = rawLine.trim();
+    if (!line || line.startsWith('#')) continue;
+    const separator = line.indexOf('=');
+    if (separator < 1) throw new Error(`${file} contains an invalid properties row: ${rawLine}`);
+    properties[line.slice(0, separator)] = line.slice(separator + 1);
+  }
+  return properties;
+}
+
+function requireFile(raw, evidenceFile, line, kind) {
+  const resolved = path.isAbsolute(raw) ? raw : path.resolve(path.dirname(evidenceFile), raw);
+  try {
+    if (!statSync(resolved).isFile()) throw new Error('not a file');
+  } catch {
+    fail(evidenceFile, line, `${kind} path does not exist: ${resolved}`);
+  }
+  return resolved;
+}
+
+function exact(actual, expected, file, line) {
+  if (JSON.stringify(actual) !== JSON.stringify(expected))
+    fail(file, line, `expected ${expected.join('\t')}`);
+}
+
+function exactSet(actual, expected, file, kind) {
+  const missing = [...expected].filter((value) => !actual.has(value)).sort();
+  const unexpected = [...actual].filter((value) => !expected.has(value)).sort();
+  if (missing.length || unexpected.length) {
+    throw new Error(
+      `${file} ${kind} set mismatch (missing=${missing.join(',') || '-'}, unexpected=${unexpected.join(',') || '-'})`,
+    );
+  }
+}
+
+function addUnique(set, value, file, line, kind) {
+  if (set.has(value)) fail(file, line, `duplicate ${kind} ${JSON.stringify(value)}`);
+  set.add(value);
+}
+
+function csv(value) {
+  return String(value ?? '')
+    .split(',')
+    .map((item) => item.trim())
+    .filter(Boolean);
+}
+
+function slash(value) {
+  return String(value).split(path.sep).join('/');
+}
+
+function fail(file, line, message) {
+  throw new Error(`${file}:${line} ${message}`);
+}
+
+function parseCli(argv) {
+  const values = {};
+  for (let index = 0; index < argv.length; index += 2) {
+    const key = argv[index];
+    const value = argv[index + 1];
+    if (!key?.startsWith('--') || value === undefined)
+      throw new Error('arguments must be --name value pairs');
+    values[key.slice(2)] = value;
+  }
+  return values;
+}
+
+if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
+  try {
+    const args = parseCli(process.argv.slice(2));
+    validateAndroidLinkEvidence({
+      evidenceFile: args.evidence,
+      expectedAbi: args.abi,
+      expectedModuleStems: args['module-stems'],
+      staticRegistryManifest: args['static-registry'],
+      target: args.target,
+    });
+    console.log(`validated Android static-extension link evidence: ${args.evidence}`);
+  } catch (error) {
+    console.error(`validate-android-link-evidence.mts: ${error.message}`);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/sdks/react-native/tools/validate-android-link-evidence.test.mjs b/src/sdks/react-native/tools/validate-android-link-evidence.test.mjs
deleted file mode 100644
index e0508c7fd..000000000
--- a/src/sdks/react-native/tools/validate-android-link-evidence.test.mjs
+++ /dev/null
@@ -1,85 +0,0 @@
-import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
-import os from 'node:os';
-import path from 'node:path';
-import { afterEach, expect, test } from 'bun:test';
-import { rmSync } from 'node:fs';
-
-import { validateAndroidLinkEvidence } from './validate-android-link-evidence.mjs';
-
-const roots = [];
-afterEach(() => {
-  for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true });
-});
-
-test('accepts exact current Android link evidence and rejects stale selections', () => {
-  const fixture = makeFixture();
-  expect(() => validateAndroidLinkEvidence(fixture.args)).not.toThrow();
-  expect(() =>
-    validateAndroidLinkEvidence({ ...fixture.args, expectedModuleStems: 'vector,pg_ivm' }),
-  ).toThrow(/missing=pg_ivm/);
-  expect(() => validateAndroidLinkEvidence({ ...fixture.args, expectedModuleStems: '' })).toThrow(
-    /unexpected=vector/,
-  );
-});
-
-test('rejects stale ABI, archive paths, duplicates, and missing dependencies', () => {
-  const abi = makeFixture();
-  expect(() => validateAndroidLinkEvidence({ ...abi.args, expectedAbi: 'x86_64' })).toThrow(
-    /expected abi\tx86_64/,
-  );
-
-  const archive = makeFixture();
-  writeFileSync(archive.evidence, archive.text.replace('vector.a', 'wrong.a'));
-  expect(() => validateAndroidLinkEvidence(archive.args)).toThrow(/path does not exist/);
-
-  const duplicate = makeFixture();
-  writeFileSync(duplicate.evidence, `${duplicate.text}extension\tvector\t${duplicate.vector}\n`);
-  expect(() => validateAndroidLinkEvidence(duplicate.args)).toThrow(/duplicate extension/);
-
-  const dependency = makeFixture();
-  writeFileSync(dependency.evidence, dependency.text.replace(/^dependency.*\n/mu, ''));
-  expect(() => validateAndroidLinkEvidence(dependency.args)).toThrow(/missing=cxx/);
-});
-
-function makeFixture() {
-  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-link-evidence-'));
-  roots.push(root);
-  const archives = path.join(root, 'archives', 'android-arm64-v8a');
-  mkdirSync(archives, { recursive: true });
-  const runtime = path.join(root, 'liboliphaunt.so');
-  const vector = path.join(archives, 'liboliphaunt_extension_vector.a');
-  const dependency = path.join(archives, 'libcxx.a');
-  for (const file of [runtime, vector, dependency]) writeFileSync(file, file);
-  const registry = path.join(root, 'manifest.properties');
-  writeFileSync(
-    registry,
-    [
-      'dependencyArchives=cxx',
-      'module.vector.archive.android-arm64-v8a=archives/android-arm64-v8a/liboliphaunt_extension_vector.a',
-      'dependency.cxx.archive.android-arm64-v8a=archives/android-arm64-v8a/libcxx.a',
-      '',
-    ].join('\n'),
-  );
-  const evidence = path.join(root, 'evidence.tsv');
-  const text = [
-    'schema\toliphaunt-android-static-extension-link-v1',
-    'abi\tarm64-v8a',
-    `runtime\tliboliphaunt\t${runtime}`,
-    `extension\tvector\t${vector}`,
-    `dependency\tcxx\t${dependency}`,
-    '',
-  ].join('\n');
-  writeFileSync(evidence, text);
-  return {
-    args: {
-      evidenceFile: evidence,
-      expectedAbi: 'arm64-v8a',
-      expectedModuleStems: 'vector',
-      staticRegistryManifest: registry,
-      target: 'android-arm64-v8a',
-    },
-    evidence,
-    text,
-    vector,
-  };
-}
diff --git a/src/sdks/react-native/tools/validate-android-link-evidence.test.mts b/src/sdks/react-native/tools/validate-android-link-evidence.test.mts
new file mode 100644
index 000000000..bbf450a96
--- /dev/null
+++ b/src/sdks/react-native/tools/validate-android-link-evidence.test.mts
@@ -0,0 +1,85 @@
+import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { afterEach, expect, test } from 'bun:test';
+import { rmSync } from 'node:fs';
+
+import { validateAndroidLinkEvidence } from './validate-android-link-evidence.mts';
+
+const roots = [];
+afterEach(() => {
+  for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true });
+});
+
+test('accepts exact current Android link evidence and rejects stale selections', () => {
+  const fixture = makeFixture();
+  expect(() => validateAndroidLinkEvidence(fixture.args)).not.toThrow();
+  expect(() =>
+    validateAndroidLinkEvidence({ ...fixture.args, expectedModuleStems: 'vector,pg_ivm' }),
+  ).toThrow(/missing=pg_ivm/);
+  expect(() => validateAndroidLinkEvidence({ ...fixture.args, expectedModuleStems: '' })).toThrow(
+    /unexpected=vector/,
+  );
+});
+
+test('rejects stale ABI, archive paths, duplicates, and missing dependencies', () => {
+  const abi = makeFixture();
+  expect(() => validateAndroidLinkEvidence({ ...abi.args, expectedAbi: 'x86_64' })).toThrow(
+    /expected abi\tx86_64/,
+  );
+
+  const archive = makeFixture();
+  writeFileSync(archive.evidence, archive.text.replace('vector.a', 'wrong.a'));
+  expect(() => validateAndroidLinkEvidence(archive.args)).toThrow(/path does not exist/);
+
+  const duplicate = makeFixture();
+  writeFileSync(duplicate.evidence, `${duplicate.text}extension\tvector\t${duplicate.vector}\n`);
+  expect(() => validateAndroidLinkEvidence(duplicate.args)).toThrow(/duplicate extension/);
+
+  const dependency = makeFixture();
+  writeFileSync(dependency.evidence, dependency.text.replace(/^dependency.*\n/mu, ''));
+  expect(() => validateAndroidLinkEvidence(dependency.args)).toThrow(/missing=cxx/);
+});
+
+function makeFixture() {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-link-evidence-'));
+  roots.push(root);
+  const archives = path.join(root, 'archives', 'android-arm64-v8a');
+  mkdirSync(archives, { recursive: true });
+  const runtime = path.join(root, 'liboliphaunt.so');
+  const vector = path.join(archives, 'liboliphaunt_extension_vector.a');
+  const dependency = path.join(archives, 'libcxx.a');
+  for (const file of [runtime, vector, dependency]) writeFileSync(file, file);
+  const registry = path.join(root, 'manifest.properties');
+  writeFileSync(
+    registry,
+    [
+      'dependencyArchives=cxx',
+      'module.vector.archive.android-arm64-v8a=archives/android-arm64-v8a/liboliphaunt_extension_vector.a',
+      'dependency.cxx.archive.android-arm64-v8a=archives/android-arm64-v8a/libcxx.a',
+      '',
+    ].join('\n'),
+  );
+  const evidence = path.join(root, 'evidence.tsv');
+  const text = [
+    'schema\toliphaunt-android-static-extension-link-v1',
+    'abi\tarm64-v8a',
+    `runtime\tliboliphaunt\t${runtime}`,
+    `extension\tvector\t${vector}`,
+    `dependency\tcxx\t${dependency}`,
+    '',
+  ].join('\n');
+  writeFileSync(evidence, text);
+  return {
+    args: {
+      evidenceFile: evidence,
+      expectedAbi: 'arm64-v8a',
+      expectedModuleStems: 'vector',
+      staticRegistryManifest: registry,
+      target: 'android-arm64-v8a',
+    },
+    evidence,
+    text,
+    vector,
+  };
+}
diff --git a/src/sdks/react-native/tools/validate-mobile-runtime-files.mjs b/src/sdks/react-native/tools/validate-mobile-runtime-files.mjs
deleted file mode 100644
index 6d2df461a..000000000
--- a/src/sdks/react-native/tools/validate-mobile-runtime-files.mjs
+++ /dev/null
@@ -1,438 +0,0 @@
-#!/usr/bin/env node
-
-import fs from "node:fs";
-import path from "node:path";
-import { fileURLToPath } from "node:url";
-
-const TOOL = "validate-mobile-runtime-files.mjs";
-const BASELINE_EXTENSION_SQL_NAMES = new Set(["plpgsql"]);
-export const CORE_SNOWBALL_RUNTIME_DATA_FILES = Object.freeze([
-  "share/postgresql/snowball_create.sql",
-  ...[
-    "danish",
-    "dutch",
-    "english",
-    "finnish",
-    "french",
-    "german",
-    "hungarian",
-    "italian",
-    "nepali",
-    "norwegian",
-    "portuguese",
-    "russian",
-    "spanish",
-    "swedish",
-    "turkish",
-  ].map((language) => `share/postgresql/tsearch_data/${language}.stop`),
-]);
-const PORTABLE_SQL_NAME = /^[A-Za-z0-9_-]{1,128}$/u;
-const PORTABLE_SQL_FILE_NAME = /^[A-Za-z0-9_.-]{1,256}\.sql$/u;
-const PORTABLE_SQL_FILE_PREFIX = /^[A-Za-z0-9_-]{1,128}$/u;
-
-function fail(message) {
-  throw new Error(`${TOOL}: ${message}`);
-}
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function canonicalStringList(value, label, predicate = () => true) {
-  if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !predicate(item))) {
-    fail(`${label} must be an array of valid strings`);
-  }
-  const canonical = [...new Set(value)].sort(compareText);
-  if (JSON.stringify(value) !== JSON.stringify(canonical)) {
-    fail(`${label} must be sorted in ordinal order without duplicates`);
-  }
-  return canonical;
-}
-
-function portableRelativePath(value) {
-  if (typeof value !== "string" || value.length === 0 || value.includes("\\") || path.posix.isAbsolute(value)) {
-    return false;
-  }
-  const segments = value.split("/");
-  return segments.every((segment) => segment.length > 0 && segment !== "." && segment !== "..");
-}
-
-function extensionContracts(document, label) {
-  if (!document || typeof document !== "object" || !Array.isArray(document.extensions)) {
-    fail(`${label} must contain an extensions array`);
-  }
-  const contracts = [];
-  const seen = new Set();
-  for (const [index, row] of document.extensions.entries()) {
-    const rowLabel = `${label} extensions[${index}]`;
-    const sqlName = row?.["sql-name"];
-    if (typeof sqlName !== "string" || !PORTABLE_SQL_NAME.test(sqlName)) {
-      fail(`${rowLabel}.sql-name must be a portable SQL extension name`);
-    }
-    if (seen.has(sqlName)) fail(`${label} contains duplicate SQL extension ${sqlName}`);
-    seen.add(sqlName);
-    if (typeof row["creates-extension"] !== "boolean") {
-      fail(`${rowLabel}.creates-extension must be boolean`);
-    }
-    contracts.push({
-      createsExtension: row["creates-extension"],
-      dataFiles: canonicalStringList(
-        row["data-files"],
-        `${rowLabel}.data-files`,
-        portableRelativePath,
-      ),
-      extensionSqlFileNames: canonicalStringList(
-        row["extension-sql-file-names"],
-        `${rowLabel}.extension-sql-file-names`,
-        (value) => PORTABLE_SQL_FILE_NAME.test(value) && path.posix.basename(value) === value,
-      ),
-      extensionSqlFilePrefixes: canonicalStringList(
-        row["extension-sql-file-prefixes"],
-        `${rowLabel}.extension-sql-file-prefixes`,
-        (value) => PORTABLE_SQL_FILE_PREFIX.test(value),
-      ),
-      sqlName,
-    });
-  }
-  return contracts;
-}
-
-function registryDataFileOwners(document, contracts, label) {
-  if (!document || typeof document !== "object" || !Array.isArray(document.modules)) {
-    fail(`${label} must contain a modules array`);
-  }
-  const contractsBySqlName = new Map(contracts.map((contract) => [contract.sqlName, contract]));
-  const registryBySqlName = new Map();
-  const ownersByDataFile = new Map();
-  for (const [index, row] of document.modules.entries()) {
-    const rowLabel = `${label} modules[${index}]`;
-    const sqlName = row?.["sql-name"];
-    if (typeof sqlName !== "string" || !contractsBySqlName.has(sqlName)) {
-      fail(`${rowLabel}.sql-name must identify a generated React Native extension`);
-    }
-    if (registryBySqlName.has(sqlName)) fail(`${label} contains duplicate module ${sqlName}`);
-    const dataFiles = canonicalStringList(
-      row["data-files"],
-      `${rowLabel}.data-files`,
-      portableRelativePath,
-    );
-    registryBySqlName.set(sqlName, dataFiles);
-    for (const dataFile of dataFiles) {
-      const owners = ownersByDataFile.get(dataFile) ?? [];
-      owners.push(sqlName);
-      ownersByDataFile.set(dataFile, owners);
-    }
-  }
-  for (const contract of contracts) {
-    const registryFiles = registryBySqlName.get(contract.sqlName) ?? [];
-    if (JSON.stringify(registryFiles) !== JSON.stringify(contract.dataFiles)) {
-      fail(
-        `${label} data-file inventory for ${contract.sqlName} differs from generated React Native metadata`,
-      );
-    }
-  }
-  return ownersByDataFile;
-}
-
-function isBaselineExtensionAsset(fileName) {
-  for (const sqlName of BASELINE_EXTENSION_SQL_NAMES) {
-    if (fileName === `${sqlName}.control`) return true;
-    if (fileName.startsWith(`${sqlName}--`) && fileName.endsWith(".sql")) return true;
-  }
-  return false;
-}
-
-function ownsExtensionAsset(contract, fileName) {
-  return (
-    (contract.createsExtension && fileName === `${contract.sqlName}.control`)
-    || (contract.createsExtension && fileName === `${contract.sqlName}.sql`)
-    || (contract.createsExtension
-      && fileName.startsWith(`${contract.sqlName}--`)
-      && fileName.endsWith(".sql"))
-    || contract.extensionSqlFileNames.includes(fileName)
-    || (fileName.endsWith(".sql")
-      && contract.extensionSqlFilePrefixes.some((prefix) => fileName.startsWith(prefix)))
-  );
-}
-
-function isCanonicalInstallSql(fileName, sqlName) {
-  const prefix = `${sqlName}--`;
-  if (!fileName.startsWith(prefix) || !fileName.endsWith(".sql")) return false;
-  const version = fileName.slice(prefix.length, -".sql".length);
-  return /^[0-9][A-Za-z0-9._-]*$/u.test(version) && !version.includes("--");
-}
-
-function extensionSqlVersion(value) {
-  return /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value) && !value.includes("--");
-}
-
-function canonicalUpdateEdge(fileName, sqlName) {
-  const prefix = `${sqlName}--`;
-  if (!fileName.startsWith(prefix) || !fileName.endsWith(".sql")) return null;
-  const versions = fileName.slice(prefix.length, -".sql".length).split("--");
-  return versions.length === 2 && versions.every(extensionSqlVersion) ? versions : null;
-}
-
-function selectedSqlNames(value) {
-  if (typeof value !== "string") fail("selected extensions must be a string");
-  const names = value.split(",").map((item) => item.trim()).filter(Boolean);
-  if (names.some((name) => !PORTABLE_SQL_NAME.test(name))) {
-    fail("--selected must contain portable comma-separated SQL extension names");
-  }
-  if (new Set(names).size !== names.length) fail("--selected must not contain duplicates");
-  return new Set(names);
-}
-
-function controlDefaultVersion(control, sqlName, label) {
-  const values = [];
-  for (const [index, rawLine] of control.split(/\r?\n/u).entries()) {
-    const line = rawLine.trim();
-    if (!line || line.startsWith("#") || !/^default_version(?:\s|=)/u.test(line)) continue;
-    const match = line.match(/^default_version\s*=\s*'([^']+)'\s*(?:#.*)?$/u);
-    if (match === null || !extensionSqlVersion(match[1])) {
-      fail(`${label} has invalid default_version on line ${index + 1}`);
-    }
-    values.push(match[1]);
-  }
-  if (values.length > 1) fail(`${label} must not repeat default_version for ${sqlName}`);
-  return values[0] ?? null;
-}
-
-export function runtimePathsFromFileList(contents) {
-  const paths = new Set();
-  for (const rawLine of contents.split(/\r?\n/u)) {
-    const line = rawLine.trim().replaceAll("\\", "/");
-    if (!line || line.endsWith("/")) continue;
-    const marker = "runtime/files/";
-    const markerIndex = line.indexOf(marker);
-    if (markerIndex === -1) continue;
-    const relative = line.slice(markerIndex + marker.length);
-    if (!portableRelativePath(relative)) fail(`file list contains unsafe runtime path: ${rawLine}`);
-    paths.add(relative);
-  }
-  return paths;
-}
-
-export function runtimePathsFromDirectory(root) {
-  if (!fs.statSync(root, { throwIfNoEntry: false })?.isDirectory()) {
-    fail(`runtime root is not a directory: ${root}`);
-  }
-  const paths = new Set();
-  const pending = [[root, ""]];
-  while (pending.length > 0) {
-    const [directory, relativeDirectory] = pending.pop();
-    for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
-      const relative = relativeDirectory
-        ? `${relativeDirectory}/${entry.name}`
-        : entry.name;
-      if (!portableRelativePath(relative)) fail(`runtime root contains unsafe path: ${relative}`);
-      if (entry.isDirectory()) {
-        pending.push([path.join(directory, entry.name), relative]);
-      } else {
-        paths.add(relative);
-      }
-    }
-  }
-  return paths;
-}
-
-export function validateMobileRuntimeFiles({
-  metadata,
-  metadataLabel = "generated React Native metadata",
-  platform,
-  registry,
-  registryLabel = "generated mobile static registry",
-  runtimePaths,
-  runtimeRoot = undefined,
-  selected,
-}) {
-  if (typeof platform !== "string" || platform.length === 0) fail("platform label must be non-empty");
-  if (!(runtimePaths instanceof Set) || [...runtimePaths].some((item) => !portableRelativePath(item))) {
-    fail("runtimePaths must be a set of portable runtime-relative file paths");
-  }
-  const contracts = extensionContracts(metadata, metadataLabel);
-  for (const required of CORE_SNOWBALL_RUNTIME_DATA_FILES) {
-    if (!runtimePaths.has(required)) {
-      fail(`${platform} app is missing PostgreSQL core Snowball runtime data: ${required}`);
-    }
-  }
-  const contractsBySqlName = new Map(contracts.map((contract) => [contract.sqlName, contract]));
-  const selectedNames = selectedSqlNames(selected);
-  for (const sqlName of selectedNames) {
-    if (!contractsBySqlName.has(sqlName)) {
-      fail(`${platform} selected extension is absent from generated React Native metadata: ${sqlName}`);
-    }
-  }
-  const dataFileOwners = registryDataFileOwners(registry, contracts, registryLabel);
-  const selectedState = new Map(
-    [...selectedNames].map((sqlName) => [sqlName, {
-      control: false,
-      installVersions: new Set(),
-      sqlFileNames: new Set(),
-    }]),
-  );
-  const extensionRoot = "share/postgresql/extension/";
-  for (const relative of [...runtimePaths].sort(compareText)) {
-    if (!relative.startsWith(extensionRoot)) continue;
-    const fileName = relative.slice(extensionRoot.length);
-    if (!fileName || fileName.includes("/")) {
-      fail(`${platform} runtime contains a nested PostgreSQL extension asset: ${relative}`);
-    }
-    if (!fileName.endsWith(".control") && !fileName.endsWith(".sql")) {
-      fail(`${platform} runtime includes unsupported PostgreSQL extension asset: ${relative}`);
-    }
-    if (isBaselineExtensionAsset(fileName)) continue;
-    const owners = contracts.filter((contract) => ownsExtensionAsset(contract, fileName));
-    if (owners.length === 0) {
-      fail(`${platform} runtime includes undeclared PostgreSQL extension asset: ${relative}`);
-    }
-    if (owners.length !== 1) {
-      fail(
-        `${platform} runtime PostgreSQL extension asset has ambiguous ownership: ${relative} `
-        + `(${owners.map((owner) => owner.sqlName).sort(compareText).join(",")})`,
-      );
-    }
-    const owner = owners[0];
-    if (!selectedNames.has(owner.sqlName)) {
-      fail(`${platform} app includes unselected PostgreSQL extension asset: ${relative}`);
-    }
-    const state = selectedState.get(owner.sqlName);
-    if (fileName === `${owner.sqlName}.control`) state.control = true;
-    if (fileName.startsWith(`${owner.sqlName}--`) && fileName.endsWith(".sql")) {
-      state.sqlFileNames.add(fileName);
-    }
-    if (isCanonicalInstallSql(fileName, owner.sqlName)) {
-      state.installVersions.add(
-        fileName.slice(`${owner.sqlName}--`.length, -".sql".length),
-      );
-    }
-  }
-  for (const sqlName of selectedNames) {
-    const contract = contractsBySqlName.get(sqlName);
-    if (!contract.createsExtension) continue;
-    const state = selectedState.get(sqlName);
-    if (!state.control) fail(`${platform} app is missing selected ${sqlName} extension control file`);
-    if (state.installVersions.size === 0) {
-      fail(`${platform} app is missing selected ${sqlName} canonical install SQL file`);
-    }
-    if (runtimeRoot !== undefined) {
-      const controlPath = path.join(
-        runtimeRoot,
-        "share/postgresql/extension",
-        `${sqlName}.control`,
-      );
-      const defaultVersion = controlDefaultVersion(
-        fs.readFileSync(controlPath, "utf8"),
-        sqlName,
-        `${platform} runtime ${sqlName}.control`,
-      );
-      const reachable = new Set(state.installVersions);
-      const updates = new Map();
-      for (const fileName of state.sqlFileNames) {
-        const edge = canonicalUpdateEdge(fileName, sqlName);
-        if (edge === null) continue;
-        const [from, to] = edge;
-        const targets = updates.get(from) ?? new Set();
-        targets.add(to);
-        updates.set(from, targets);
-      }
-      const pending = [...reachable].sort(compareText);
-      for (let index = 0; index < pending.length; index += 1) {
-        for (const next of [...(updates.get(pending[index]) ?? [])].sort(compareText)) {
-          if (reachable.has(next)) continue;
-          reachable.add(next);
-          pending.push(next);
-        }
-      }
-      if (defaultVersion !== null && !reachable.has(defaultVersion)) {
-        fail(
-          `${platform} runtime selected ${sqlName} default_version=${defaultVersion} `
-          + "is unreachable from its canonical install SQL files",
-        );
-      }
-    }
-  }
-  for (const [dataFile, owners] of dataFileOwners) {
-    const selectedOwners = owners.filter((owner) => selectedNames.has(owner));
-    const present = runtimePaths.has(dataFile);
-    if (selectedOwners.length > 0 && !present) {
-      fail(
-        `${platform} app is missing selected ${selectedOwners.join(",")} extension data file: ${dataFile}`,
-      );
-    }
-    if (selectedOwners.length === 0 && present) {
-      fail(`${platform} app includes unselected ${owners.join(",")} extension data file: ${dataFile}`);
-    }
-  }
-}
-
-function parseArgs(argv) {
-  const options = new Map();
-  const valued = new Set([
-    "--file-list",
-    "--metadata",
-    "--platform",
-    "--registry",
-    "--runtime-root",
-    "--selected",
-  ]);
-  for (let index = 0; index < argv.length; index += 1) {
-    const flag = argv[index];
-    if (flag === "-h" || flag === "--help") {
-      process.stdout.write(
-        `usage: ${TOOL} --metadata FILE --registry FILE --selected CSV --platform LABEL `
-        + "(--runtime-root DIR | --file-list FILE)\n",
-      );
-      process.exit(0);
-    }
-    if (!valued.has(flag) || index + 1 >= argv.length || options.has(flag)) {
-      fail(`invalid or repeated argument: ${flag}`);
-    }
-    options.set(flag, argv[index + 1]);
-    index += 1;
-  }
-  for (const flag of ["--metadata", "--registry", "--selected", "--platform"]) {
-    if (!options.has(flag)) fail(`missing required argument ${flag}`);
-  }
-  if (options.has("--runtime-root") === options.has("--file-list")) {
-    fail("exactly one of --runtime-root or --file-list is required");
-  }
-  return options;
-}
-
-function readJson(file, label) {
-  try {
-    return JSON.parse(fs.readFileSync(file, "utf8"));
-  } catch (error) {
-    fail(`cannot read ${label} ${file}: ${error.message}`);
-  }
-}
-
-function main(argv) {
-  const options = parseArgs(argv);
-  const metadataPath = options.get("--metadata");
-  const registryPath = options.get("--registry");
-  const runtimeRoot = options.get("--runtime-root");
-  const runtimePaths = runtimeRoot !== undefined
-    ? runtimePathsFromDirectory(runtimeRoot)
-    : runtimePathsFromFileList(fs.readFileSync(options.get("--file-list"), "utf8"));
-  validateMobileRuntimeFiles({
-    metadata: readJson(metadataPath, "metadata"),
-    metadataLabel: metadataPath,
-    platform: options.get("--platform"),
-    registry: readJson(registryPath, "registry"),
-    registryLabel: registryPath,
-    runtimePaths,
-    runtimeRoot,
-    selected: options.get("--selected"),
-  });
-}
-
-if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
-  try {
-    main(process.argv.slice(2));
-  } catch (error) {
-    console.error(error.message);
-    process.exit(1);
-  }
-}
diff --git a/src/sdks/react-native/tools/validate-mobile-runtime-files.mts b/src/sdks/react-native/tools/validate-mobile-runtime-files.mts
new file mode 100644
index 000000000..16454b1fe
--- /dev/null
+++ b/src/sdks/react-native/tools/validate-mobile-runtime-files.mts
@@ -0,0 +1,458 @@
+#!/usr/bin/env bun
+
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const TOOL = 'validate-mobile-runtime-files.mts';
+const BASELINE_EXTENSION_SQL_NAMES = new Set(['plpgsql']);
+export const CORE_SNOWBALL_RUNTIME_DATA_FILES = Object.freeze([
+  'share/postgresql/snowball_create.sql',
+  ...[
+    'danish',
+    'dutch',
+    'english',
+    'finnish',
+    'french',
+    'german',
+    'hungarian',
+    'italian',
+    'nepali',
+    'norwegian',
+    'portuguese',
+    'russian',
+    'spanish',
+    'swedish',
+    'turkish',
+  ].map((language) => `share/postgresql/tsearch_data/${language}.stop`),
+]);
+const PORTABLE_SQL_NAME = /^[A-Za-z0-9_-]{1,128}$/u;
+const PORTABLE_SQL_FILE_NAME = /^[A-Za-z0-9_.-]{1,256}\.sql$/u;
+const PORTABLE_SQL_FILE_PREFIX = /^[A-Za-z0-9_-]{1,128}$/u;
+
+function fail(message) {
+  throw new Error(`${TOOL}: ${message}`);
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function canonicalStringList(value, label, predicate = () => true) {
+  if (!Array.isArray(value) || value.some((item) => typeof item !== 'string' || !predicate(item))) {
+    fail(`${label} must be an array of valid strings`);
+  }
+  const canonical = [...new Set(value)].sort(compareText);
+  if (JSON.stringify(value) !== JSON.stringify(canonical)) {
+    fail(`${label} must be sorted in ordinal order without duplicates`);
+  }
+  return canonical;
+}
+
+function portableRelativePath(value) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    path.posix.isAbsolute(value)
+  ) {
+    return false;
+  }
+  const segments = value.split('/');
+  return segments.every((segment) => segment.length > 0 && segment !== '.' && segment !== '..');
+}
+
+function extensionContracts(document, label) {
+  if (!document || typeof document !== 'object' || !Array.isArray(document.extensions)) {
+    fail(`${label} must contain an extensions array`);
+  }
+  const contracts = [];
+  const seen = new Set();
+  for (const [index, row] of document.extensions.entries()) {
+    const rowLabel = `${label} extensions[${index}]`;
+    const sqlName = row?.['sql-name'];
+    if (typeof sqlName !== 'string' || !PORTABLE_SQL_NAME.test(sqlName)) {
+      fail(`${rowLabel}.sql-name must be a portable SQL extension name`);
+    }
+    if (seen.has(sqlName)) fail(`${label} contains duplicate SQL extension ${sqlName}`);
+    seen.add(sqlName);
+    if (typeof row['creates-extension'] !== 'boolean') {
+      fail(`${rowLabel}.creates-extension must be boolean`);
+    }
+    contracts.push({
+      createsExtension: row['creates-extension'],
+      dataFiles: canonicalStringList(
+        row['data-files'],
+        `${rowLabel}.data-files`,
+        portableRelativePath,
+      ),
+      extensionSqlFileNames: canonicalStringList(
+        row['extension-sql-file-names'],
+        `${rowLabel}.extension-sql-file-names`,
+        (value) => PORTABLE_SQL_FILE_NAME.test(value) && path.posix.basename(value) === value,
+      ),
+      extensionSqlFilePrefixes: canonicalStringList(
+        row['extension-sql-file-prefixes'],
+        `${rowLabel}.extension-sql-file-prefixes`,
+        (value) => PORTABLE_SQL_FILE_PREFIX.test(value),
+      ),
+      sqlName,
+    });
+  }
+  return contracts;
+}
+
+function registryDataFileOwners(document, contracts, label) {
+  if (!document || typeof document !== 'object' || !Array.isArray(document.modules)) {
+    fail(`${label} must contain a modules array`);
+  }
+  const contractsBySqlName = new Map(contracts.map((contract) => [contract.sqlName, contract]));
+  const registryBySqlName = new Map();
+  const ownersByDataFile = new Map();
+  for (const [index, row] of document.modules.entries()) {
+    const rowLabel = `${label} modules[${index}]`;
+    const sqlName = row?.['sql-name'];
+    if (typeof sqlName !== 'string' || !contractsBySqlName.has(sqlName)) {
+      fail(`${rowLabel}.sql-name must identify a generated React Native extension`);
+    }
+    if (registryBySqlName.has(sqlName)) fail(`${label} contains duplicate module ${sqlName}`);
+    const dataFiles = canonicalStringList(
+      row['data-files'],
+      `${rowLabel}.data-files`,
+      portableRelativePath,
+    );
+    registryBySqlName.set(sqlName, dataFiles);
+    for (const dataFile of dataFiles) {
+      const owners = ownersByDataFile.get(dataFile) ?? [];
+      owners.push(sqlName);
+      ownersByDataFile.set(dataFile, owners);
+    }
+  }
+  for (const contract of contracts) {
+    const registryFiles = registryBySqlName.get(contract.sqlName) ?? [];
+    if (JSON.stringify(registryFiles) !== JSON.stringify(contract.dataFiles)) {
+      fail(
+        `${label} data-file inventory for ${contract.sqlName} differs from generated React Native metadata`,
+      );
+    }
+  }
+  return ownersByDataFile;
+}
+
+function isBaselineExtensionAsset(fileName) {
+  for (const sqlName of BASELINE_EXTENSION_SQL_NAMES) {
+    if (fileName === `${sqlName}.control`) return true;
+    if (fileName.startsWith(`${sqlName}--`) && fileName.endsWith('.sql')) return true;
+  }
+  return false;
+}
+
+function ownsExtensionAsset(contract, fileName) {
+  return (
+    (contract.createsExtension && fileName === `${contract.sqlName}.control`) ||
+    (contract.createsExtension && fileName === `${contract.sqlName}.sql`) ||
+    (contract.createsExtension &&
+      fileName.startsWith(`${contract.sqlName}--`) &&
+      fileName.endsWith('.sql')) ||
+    contract.extensionSqlFileNames.includes(fileName) ||
+    (fileName.endsWith('.sql') &&
+      contract.extensionSqlFilePrefixes.some((prefix) => fileName.startsWith(prefix)))
+  );
+}
+
+function isCanonicalInstallSql(fileName, sqlName) {
+  const prefix = `${sqlName}--`;
+  if (!fileName.startsWith(prefix) || !fileName.endsWith('.sql')) return false;
+  const version = fileName.slice(prefix.length, -'.sql'.length);
+  return /^[0-9][A-Za-z0-9._-]*$/u.test(version) && !version.includes('--');
+}
+
+function extensionSqlVersion(value) {
+  return /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value) && !value.includes('--');
+}
+
+function canonicalUpdateEdge(fileName, sqlName) {
+  const prefix = `${sqlName}--`;
+  if (!fileName.startsWith(prefix) || !fileName.endsWith('.sql')) return null;
+  const versions = fileName.slice(prefix.length, -'.sql'.length).split('--');
+  return versions.length === 2 && versions.every(extensionSqlVersion) ? versions : null;
+}
+
+function selectedSqlNames(value) {
+  if (typeof value !== 'string') fail('selected extensions must be a string');
+  const names = value
+    .split(',')
+    .map((item) => item.trim())
+    .filter(Boolean);
+  if (names.some((name) => !PORTABLE_SQL_NAME.test(name))) {
+    fail('--selected must contain portable comma-separated SQL extension names');
+  }
+  if (new Set(names).size !== names.length) fail('--selected must not contain duplicates');
+  return new Set(names);
+}
+
+function controlDefaultVersion(control, sqlName, label) {
+  const values = [];
+  for (const [index, rawLine] of control.split(/\r?\n/u).entries()) {
+    const line = rawLine.trim();
+    if (!line || line.startsWith('#') || !/^default_version(?:\s|=)/u.test(line)) continue;
+    const match = line.match(/^default_version\s*=\s*'([^']+)'\s*(?:#.*)?$/u);
+    if (match === null || !extensionSqlVersion(match[1])) {
+      fail(`${label} has invalid default_version on line ${index + 1}`);
+    }
+    values.push(match[1]);
+  }
+  if (values.length > 1) fail(`${label} must not repeat default_version for ${sqlName}`);
+  return values[0] ?? null;
+}
+
+export function runtimePathsFromFileList(contents) {
+  const paths = new Set();
+  for (const rawLine of contents.split(/\r?\n/u)) {
+    const line = rawLine.trim().replaceAll('\\', '/');
+    if (!line || line.endsWith('/')) continue;
+    const marker = 'runtime/files/';
+    const markerIndex = line.indexOf(marker);
+    if (markerIndex === -1) continue;
+    const relative = line.slice(markerIndex + marker.length);
+    if (!portableRelativePath(relative)) fail(`file list contains unsafe runtime path: ${rawLine}`);
+    paths.add(relative);
+  }
+  return paths;
+}
+
+export function runtimePathsFromDirectory(root) {
+  if (!fs.statSync(root, { throwIfNoEntry: false })?.isDirectory()) {
+    fail(`runtime root is not a directory: ${root}`);
+  }
+  const paths = new Set();
+  const pending = [[root, '']];
+  while (pending.length > 0) {
+    const [directory, relativeDirectory] = pending.pop();
+    for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
+      const relative = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;
+      if (!portableRelativePath(relative)) fail(`runtime root contains unsafe path: ${relative}`);
+      if (entry.isDirectory()) {
+        pending.push([path.join(directory, entry.name), relative]);
+      } else {
+        paths.add(relative);
+      }
+    }
+  }
+  return paths;
+}
+
+export function validateMobileRuntimeFiles({
+  metadata,
+  metadataLabel = 'generated React Native metadata',
+  platform,
+  registry,
+  registryLabel = 'generated mobile static registry',
+  runtimePaths,
+  runtimeRoot = undefined,
+  selected,
+}) {
+  if (typeof platform !== 'string' || platform.length === 0)
+    fail('platform label must be non-empty');
+  if (
+    !(runtimePaths instanceof Set) ||
+    [...runtimePaths].some((item) => !portableRelativePath(item))
+  ) {
+    fail('runtimePaths must be a set of portable runtime-relative file paths');
+  }
+  const contracts = extensionContracts(metadata, metadataLabel);
+  for (const required of CORE_SNOWBALL_RUNTIME_DATA_FILES) {
+    if (!runtimePaths.has(required)) {
+      fail(`${platform} app is missing PostgreSQL core Snowball runtime data: ${required}`);
+    }
+  }
+  const contractsBySqlName = new Map(contracts.map((contract) => [contract.sqlName, contract]));
+  const selectedNames = selectedSqlNames(selected);
+  for (const sqlName of selectedNames) {
+    if (!contractsBySqlName.has(sqlName)) {
+      fail(
+        `${platform} selected extension is absent from generated React Native metadata: ${sqlName}`,
+      );
+    }
+  }
+  const dataFileOwners = registryDataFileOwners(registry, contracts, registryLabel);
+  const selectedState = new Map(
+    [...selectedNames].map((sqlName) => [
+      sqlName,
+      {
+        control: false,
+        installVersions: new Set(),
+        sqlFileNames: new Set(),
+      },
+    ]),
+  );
+  const extensionRoot = 'share/postgresql/extension/';
+  for (const relative of [...runtimePaths].sort(compareText)) {
+    if (!relative.startsWith(extensionRoot)) continue;
+    const fileName = relative.slice(extensionRoot.length);
+    if (!fileName || fileName.includes('/')) {
+      fail(`${platform} runtime contains a nested PostgreSQL extension asset: ${relative}`);
+    }
+    if (!fileName.endsWith('.control') && !fileName.endsWith('.sql')) {
+      fail(`${platform} runtime includes unsupported PostgreSQL extension asset: ${relative}`);
+    }
+    if (isBaselineExtensionAsset(fileName)) continue;
+    const owners = contracts.filter((contract) => ownsExtensionAsset(contract, fileName));
+    if (owners.length === 0) {
+      fail(`${platform} runtime includes undeclared PostgreSQL extension asset: ${relative}`);
+    }
+    if (owners.length !== 1) {
+      fail(
+        `${platform} runtime PostgreSQL extension asset has ambiguous ownership: ${relative} ` +
+          `(${owners
+            .map((owner) => owner.sqlName)
+            .sort(compareText)
+            .join(',')})`,
+      );
+    }
+    const owner = owners[0];
+    if (!selectedNames.has(owner.sqlName)) {
+      fail(`${platform} app includes unselected PostgreSQL extension asset: ${relative}`);
+    }
+    const state = selectedState.get(owner.sqlName);
+    if (fileName === `${owner.sqlName}.control`) state.control = true;
+    if (fileName.startsWith(`${owner.sqlName}--`) && fileName.endsWith('.sql')) {
+      state.sqlFileNames.add(fileName);
+    }
+    if (isCanonicalInstallSql(fileName, owner.sqlName)) {
+      state.installVersions.add(fileName.slice(`${owner.sqlName}--`.length, -'.sql'.length));
+    }
+  }
+  for (const sqlName of selectedNames) {
+    const contract = contractsBySqlName.get(sqlName);
+    if (!contract.createsExtension) continue;
+    const state = selectedState.get(sqlName);
+    if (!state.control)
+      fail(`${platform} app is missing selected ${sqlName} extension control file`);
+    if (state.installVersions.size === 0) {
+      fail(`${platform} app is missing selected ${sqlName} canonical install SQL file`);
+    }
+    if (runtimeRoot !== undefined) {
+      const controlPath = path.join(
+        runtimeRoot,
+        'share/postgresql/extension',
+        `${sqlName}.control`,
+      );
+      const defaultVersion = controlDefaultVersion(
+        fs.readFileSync(controlPath, 'utf8'),
+        sqlName,
+        `${platform} runtime ${sqlName}.control`,
+      );
+      const reachable = new Set(state.installVersions);
+      const updates = new Map();
+      for (const fileName of state.sqlFileNames) {
+        const edge = canonicalUpdateEdge(fileName, sqlName);
+        if (edge === null) continue;
+        const [from, to] = edge;
+        const targets = updates.get(from) ?? new Set();
+        targets.add(to);
+        updates.set(from, targets);
+      }
+      const pending = [...reachable].sort(compareText);
+      for (let index = 0; index < pending.length; index += 1) {
+        for (const next of [...(updates.get(pending[index]) ?? [])].sort(compareText)) {
+          if (reachable.has(next)) continue;
+          reachable.add(next);
+          pending.push(next);
+        }
+      }
+      if (defaultVersion !== null && !reachable.has(defaultVersion)) {
+        fail(
+          `${platform} runtime selected ${sqlName} default_version=${defaultVersion} ` +
+            'is unreachable from its canonical install SQL files',
+        );
+      }
+    }
+  }
+  for (const [dataFile, owners] of dataFileOwners) {
+    const selectedOwners = owners.filter((owner) => selectedNames.has(owner));
+    const present = runtimePaths.has(dataFile);
+    if (selectedOwners.length > 0 && !present) {
+      fail(
+        `${platform} app is missing selected ${selectedOwners.join(',')} extension data file: ${dataFile}`,
+      );
+    }
+    if (selectedOwners.length === 0 && present) {
+      fail(
+        `${platform} app includes unselected ${owners.join(',')} extension data file: ${dataFile}`,
+      );
+    }
+  }
+}
+
+function parseArgs(argv) {
+  const options = new Map();
+  const valued = new Set([
+    '--file-list',
+    '--metadata',
+    '--platform',
+    '--registry',
+    '--runtime-root',
+    '--selected',
+  ]);
+  for (let index = 0; index < argv.length; index += 1) {
+    const flag = argv[index];
+    if (flag === '-h' || flag === '--help') {
+      process.stdout.write(
+        `usage: ${TOOL} --metadata FILE --registry FILE --selected CSV --platform LABEL ` +
+          '(--runtime-root DIR | --file-list FILE)\n',
+      );
+      process.exit(0);
+    }
+    if (!valued.has(flag) || index + 1 >= argv.length || options.has(flag)) {
+      fail(`invalid or repeated argument: ${flag}`);
+    }
+    options.set(flag, argv[index + 1]);
+    index += 1;
+  }
+  for (const flag of ['--metadata', '--registry', '--selected', '--platform']) {
+    if (!options.has(flag)) fail(`missing required argument ${flag}`);
+  }
+  if (options.has('--runtime-root') === options.has('--file-list')) {
+    fail('exactly one of --runtime-root or --file-list is required');
+  }
+  return options;
+}
+
+function readJson(file, label) {
+  try {
+    return JSON.parse(fs.readFileSync(file, 'utf8'));
+  } catch (error) {
+    fail(`cannot read ${label} ${file}: ${error.message}`);
+  }
+}
+
+function main(argv) {
+  const options = parseArgs(argv);
+  const metadataPath = options.get('--metadata');
+  const registryPath = options.get('--registry');
+  const runtimeRoot = options.get('--runtime-root');
+  const runtimePaths =
+    runtimeRoot !== undefined
+      ? runtimePathsFromDirectory(runtimeRoot)
+      : runtimePathsFromFileList(fs.readFileSync(options.get('--file-list'), 'utf8'));
+  validateMobileRuntimeFiles({
+    metadata: readJson(metadataPath, 'metadata'),
+    metadataLabel: metadataPath,
+    platform: options.get('--platform'),
+    registry: readJson(registryPath, 'registry'),
+    registryLabel: registryPath,
+    runtimePaths,
+    runtimeRoot,
+    selected: options.get('--selected'),
+  });
+}
+
+if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
+  try {
+    main(process.argv.slice(2));
+  } catch (error) {
+    console.error(error.message);
+    process.exit(1);
+  }
+}
diff --git a/src/sdks/react-native/tools/verify-android-apk.sh b/src/sdks/react-native/tools/verify-android-apk.sh
index a44ef772a..932712966 100755
--- a/src/sdks/react-native/tools/verify-android-apk.sh
+++ b/src/sdks/react-native/tools/verify-android-apk.sh
@@ -17,7 +17,7 @@ usage() {
 
 root="$(git rev-parse --show-toplevel 2>/dev/null)" ||
   fail "must run inside the Oliphaunt git checkout"
-manifest="${OLIPHAUNT_ANDROID_TOOLCHAIN_MANIFEST:-$root/src/sources/toolchains/android-sdk.toml}"
+manifest="${OLIPHAUNT_ANDROID_TOOLCHAIN_MANIFEST:-$root/tools/dev/android-sdk.toml}"
 if [ ! -f "$manifest" ] || [ -L "$manifest" ]; then
   fail "missing regular Android toolchain manifest: $manifest"
 fi
@@ -126,4 +126,7 @@ apk_classes="$("$apkanalyzer" dex packages "$apk")" ||
 if ! grep -Eq '^C d [^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+dev\.oliphaunt\.DatabaseStorage\$TemporaryDirectory$' <<<"$apk_classes"; then
   fail "APK does not define the staged Kotlin SDK storage class; a stale Maven artifact may have won dependency resolution"
 fi
+if ! grep -Eq '^C d [^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+[^[:space:]]+[[:space:]]+com\.sun\.jna\.Native$' <<<"$apk_classes"; then
+  fail "APK does not define the Kotlin SDK JNA runtime class"
+fi
 echo "Verified APK alignment, signature, and staged Kotlin SDK bytecode: $apk"
diff --git a/src/sdks/react-native/tools/verify-android-apk.test.sh b/src/sdks/react-native/tools/verify-android-apk.test.sh
index 77d21f3ba..6687ac225 100755
--- a/src/sdks/react-native/tools/verify-android-apk.test.sh
+++ b/src/sdks/react-native/tools/verify-android-apk.test.sh
@@ -55,6 +55,7 @@ set -euo pipefail
 if [ "${OLIPHAUNT_ANDROID_APK_VERIFY_TEST_STALE_KOTLIN_AAR:-0}" != "1" ]; then
   printf 'C d 1\t1\t1\tdev.oliphaunt.DatabaseStorage$TemporaryDirectory\n'
 fi
+printf 'C %s 1\t1\t1\tcom.sun.jna.Native\n' "${OLIPHAUNT_ANDROID_APK_VERIFY_TEST_JNA_STATE:-d}"
 EOF
 chmod +x "$tools/zipalign" "$tools/apksigner" "$command_line_tools/apkanalyzer"
 
@@ -157,6 +158,14 @@ expect_failure stale-kotlin-aar 'APK does not define the staged Kotlin SDK stora
   "$verifier" "$apk"
 cmp "$tmp/expected.log" "$log"
 
+# A reference to JNA does not supply its missing runtime implementation.
+expect_failure missing-jna 'APK does not define the Kotlin SDK JNA runtime class' env \
+  ANDROID_HOME="$sdk" ANDROID_SDK_ROOT="$sdk" \
+  OLIPHAUNT_ANDROID_TOOLCHAIN_MANIFEST="$manifest" \
+  OLIPHAUNT_ANDROID_APK_VERIFY_TEST_LOG="$log" \
+  OLIPHAUNT_ANDROID_APK_VERIFY_TEST_JNA_STATE=r \
+  "$verifier" "$apk"
+
 # Installed package identity, SDK-root identity, manifest shape, and artifact
 # type are independently fail-closed.
 printf 'Pkg.Revision=35.0.0\n' >"$tools/source.properties"
diff --git a/src/sdks/react-native/tools/verify-ios-package.mjs b/src/sdks/react-native/tools/verify-ios-package.mjs
deleted file mode 100755
index 1869c73f5..000000000
--- a/src/sdks/react-native/tools/verify-ios-package.mjs
+++ /dev/null
@@ -1,699 +0,0 @@
-#!/usr/bin/env node
-
-import { createHash } from "node:crypto";
-import fs from "node:fs/promises";
-import path from "node:path";
-
-import {
-  parseProperties,
-  requireProperty,
-  validateNativeRuntimeClosure,
-} from "./native-resource-closure.mjs";
-
-const PREFIX = "verify-ios-package.mjs";
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function fail(message) {
-  throw new Error(`${PREFIX}: ${message}`);
-}
-
-function usage() {
-  console.error(
-    `usage: ${PREFIX} (--package-dir  | --payload-dir ) ` +
-      `[--allow-runtime-dylib]`,
-  );
-}
-
-function parseArgs(argv) {
-  const args = {
-    allowRuntimeDylib: false,
-    packageDir: undefined,
-    payloadDir: undefined,
-  };
-  for (let index = 0; index < argv.length; index += 1) {
-    const arg = argv[index];
-    if (arg === "--package-dir") {
-      args.packageDir = argv[index + 1];
-      index += 1;
-    } else if (arg === "--payload-dir") {
-      args.payloadDir = argv[index + 1];
-      index += 1;
-    } else if (arg === "--allow-runtime-dylib") {
-      args.allowRuntimeDylib = true;
-    } else if (arg === "--help" || arg === "-h") {
-      usage();
-      process.exit(0);
-    } else {
-      usage();
-      fail(`unknown argument ${arg}`);
-    }
-  }
-  const roots = [args.packageDir, args.payloadDir].filter(
-    (value) => typeof value === "string" && value.length > 0,
-  );
-  if (roots.length !== 1) {
-    usage();
-    fail("exactly one of --package-dir or --payload-dir is required");
-  }
-  if (args.packageDir) args.packageDir = path.resolve(args.packageDir);
-  if (args.payloadDir) args.payloadDir = path.resolve(args.payloadDir);
-  return args;
-}
-
-async function statOrUndefined(file) {
-  return fs.stat(file).catch((error) => {
-    if (error?.code === "ENOENT") {
-      return undefined;
-    }
-    throw error;
-  });
-}
-
-async function requireFile(file, label) {
-  const stat = await statOrUndefined(file);
-  if (stat?.isFile() !== true || stat.size === 0) {
-    fail(`${label} is missing or empty: ${file}`);
-  }
-}
-
-async function requireDirectory(file, label) {
-  const stat = await statOrUndefined(file);
-  if (stat?.isDirectory() !== true) {
-    fail(`${label} is missing: ${file}`);
-  }
-}
-
-async function walk(root) {
-  const rootStat = await statOrUndefined(root);
-  if (rootStat?.isDirectory() !== true) {
-    return [];
-  }
-  const result = [];
-  const pending = [root];
-  while (pending.length > 0) {
-    const current = pending.pop();
-    const entries = await fs.readdir(current, { withFileTypes: true });
-    entries.sort((left, right) => compareText(left.name, right.name));
-    for (const entry of entries) {
-      const file = path.join(current, entry.name);
-      result.push({ entry, file });
-      if (entry.isDirectory()) {
-        pending.push(file);
-      }
-    }
-  }
-  return result.sort((left, right) => compareText(left.file, right.file));
-}
-
-async function requirePayloadFiles(root, label) {
-  const entries = await walk(root);
-  if (!entries.some(({ entry }) => entry.isFile())) {
-    fail(`${label} contains no payload files: ${root}`);
-  }
-}
-
-async function readProperties(file) {
-  await requireFile(file, "runtime-resource manifest");
-  return parseProperties(await fs.readFile(file, "utf8"), file);
-}
-
-function portableCsv(properties, key, source) {
-  const value = properties.get(key);
-  if (value === undefined) {
-    fail(`${source} is missing ${key}`);
-  }
-  if (!value) {
-    return [];
-  }
-  const items = value.split(",");
-  const seen = new Set();
-  for (const item of items) {
-    if (!/^[A-Za-z0-9._-]+$/u.test(item)) {
-      fail(`${source} ${key} contains invalid portable id ${JSON.stringify(item)}`);
-    }
-    if (seen.has(item)) {
-      fail(`${source} ${key} repeats ${item}`);
-    }
-    seen.add(item);
-  }
-  return items;
-}
-
-function requireExactDomain(actual, expected, label) {
-  const canonicalExpected = [...new Set(expected)].sort(compareText);
-  if (JSON.stringify(actual) !== JSON.stringify(canonicalExpected)) {
-    fail(
-      `${label} must match the exact canonical domain; ` +
-        `actual=${actual.join(",") || "-"} expected=${canonicalExpected.join(",") || "-"}`,
-    );
-  }
-}
-
-function requirePortableSelectionId(value, label) {
-  if (typeof value !== "string" || !/^[A-Za-z0-9._-]+$/u.test(value)) {
-    fail(`${label} must be a portable id; got ${JSON.stringify(value)}`);
-  }
-  return value;
-}
-
-function safeRelative(value, label) {
-  if (
-    typeof value !== "string" || value.length === 0 || value.includes("\\") ||
-    value.startsWith("/") || /^[A-Za-z]:/u.test(value) || /[\u0000-\u001f\u007f]/u.test(value)
-  ) {
-    fail(`${label} must be a safe relative path`);
-  }
-  const parts = value.split("/");
-  if (parts.some((part) => !part || part === "." || part === "..")) {
-    fail(`${label} must be a safe relative path`);
-  }
-  return value;
-}
-
-function renderLegalNotice(spdx, files) {
-  return [
-    "# Oliphaunt app-owned iOS payload legal notices",
-    "",
-    `SPDX-License-Identifier: ${spdx}`,
-    "",
-    "This file indexes the exact legal files materialized from the selected frozen carriers.",
-    "",
-    ...files.map((row) => `- \`${row.destination}\` (${row.kind}; SHA-256 \`${row.sha256}\`)`),
-    "",
-  ].join("\n");
-}
-
-async function validateLegalSelection(payloadDir, selection, frozenSelected) {
-  const legal = selection?.legal;
-  if (legal === null || Array.isArray(legal) || typeof legal !== "object") {
-    fail(`${payloadDir}/selection.json legal must be an object`);
-  }
-  const keys = Object.keys(legal).sort(compareText);
-  if (JSON.stringify(keys) !== JSON.stringify(["file", "files", "spdx"])) {
-    fail(`${payloadDir}/selection.json legal fields must be exactly file,files,spdx`);
-  }
-  if (legal.file !== "licenses/NOTICE.md") {
-    fail(`${payloadDir}/selection.json legal.file must be licenses/NOTICE.md`);
-  }
-  if (
-    typeof legal.spdx !== "string" ||
-    legal.spdx.split(" AND ").some((term) => !/^[A-Za-z0-9][A-Za-z0-9.-]*$/u.test(term))
-  ) {
-    fail(`${payloadDir}/selection.json legal.spdx must be a safe SPDX conjunction`);
-  }
-  if (!Array.isArray(legal.files) || legal.files.length === 0) {
-    fail(`${payloadDir}/selection.json legal.files must be non-empty`);
-  }
-  if (typeof selection.icu !== "boolean") {
-    fail(`${payloadDir}/selection.json icu must be boolean`);
-  }
-  const legalEntries = await walk(path.join(payloadDir, "licenses"));
-  const unsafeEntries = legalEntries.filter(
-    ({ entry }) => !entry.isDirectory() && !entry.isFile(),
-  );
-  if (unsafeEntries.length > 0) {
-    fail(
-      `${payloadDir} legal namespace contains symbolic links or special files: ` +
-        unsafeEntries.map(({ file }) => file).join(", "),
-    );
-  }
-  const selected = new Set(frozenSelected);
-  const expectedFiles = [];
-  const baseScopes = new Set();
-  const extensionScopes = new Set();
-  for (const [index, row] of legal.files.entries()) {
-    const label = `${payloadDir}/selection.json legal.files[${index}]`;
-    if (row === null || Array.isArray(row) || typeof row !== "object") fail(`${label} must be an object`);
-    const rowKeys = Object.keys(row).sort(compareText);
-    if (JSON.stringify(rowKeys) !== JSON.stringify(["bytes", "destination", "kind", "member", "sha256", "source"])) {
-      fail(`${label} fields must be exactly bytes,destination,kind,member,sha256,source`);
-    }
-    const destination = safeRelative(row.destination, `${label}.destination`);
-    safeRelative(row.member, `${label}.member`);
-    if (!destination.startsWith("licenses/base/") && !destination.startsWith("licenses/extensions/")) {
-      fail(`${label}.destination is outside the selected legal namespaces`);
-    }
-    const baseRole = /^licenses\/base\/([^/]+)\//u.exec(destination)?.[1];
-    if (baseRole !== undefined) {
-      requirePortableSelectionId(baseRole, `${label} base legal role`);
-      if (!new Set(["base-xcframework", "runtime-resources", "icu-data"]).has(baseRole)) {
-        fail(`${label}.destination carries unknown base legal role ${baseRole}`);
-      }
-      if (row.source !== "base") fail(`${label}.source must be base for a base legal destination`);
-      baseScopes.add(baseRole);
-    }
-    const extension = /^licenses\/extensions\/([^/]+)\//u.exec(destination)?.[1];
-    if (baseRole === undefined && extension === undefined) {
-      fail(`${label}.destination must name a file below one exact legal scope`);
-    }
-    if (extension !== undefined && !selected.has(extension)) {
-      fail(`${label}.destination leaks unselected extension ${extension}`);
-    }
-    if (extension !== undefined) {
-      requirePortableSelectionId(extension, `${label} extension legal scope`);
-      if (row.source !== "extension") {
-        fail(`${label}.source must be extension for an extension legal destination`);
-      }
-      extensionScopes.add(extension);
-    }
-    if (destination.startsWith("licenses/base/icu-data/") && selection.icu !== true) {
-      fail(`${label}.destination carries unselected ICU legal material`);
-    }
-    if (!new Set(["license", "notice"]).has(row.kind) || !new Set(["base", "extension"]).has(row.source)) {
-      fail(`${label} has an invalid legal kind/source`);
-    }
-    if (!Number.isSafeInteger(row.bytes) || row.bytes <= 0 || !/^[0-9a-f]{64}$/u.test(row.sha256)) {
-      fail(`${label} has an invalid byte count or SHA-256`);
-    }
-    const file = path.join(payloadDir, ...destination.split("/"));
-    const stat = await fs.lstat(file).catch((error) => {
-      fail(`${label} is missing from the payload: ${error.message}`);
-    });
-    if (!stat.isFile() || stat.isSymbolicLink() || stat.size !== row.bytes) {
-      fail(`${label} is not the frozen regular legal file`);
-    }
-    const digest = createHash("sha256").update(await fs.readFile(file)).digest("hex");
-    if (digest !== row.sha256) fail(`${label} checksum differs from selection.json`);
-    expectedFiles.push(destination);
-  }
-  const canonical = [...expectedFiles].sort(compareText);
-  if (new Set(expectedFiles).size !== expectedFiles.length || JSON.stringify(canonical) !== JSON.stringify(expectedFiles)) {
-    fail(`${payloadDir}/selection.json legal.files must be unique and sorted by destination`);
-  }
-  const expectedBaseScopes = [
-    "base-xcframework",
-    ...(selection.icu ? ["icu-data"] : []),
-    "runtime-resources",
-  ].sort(compareText);
-  requireExactDomain([...baseScopes].sort(compareText), expectedBaseScopes, `${payloadDir} base legal scopes`);
-  requireExactDomain(
-    [...extensionScopes].sort(compareText),
-    frozenSelected,
-    `${payloadDir} extension legal scopes`,
-  );
-  const actualFiles = legalEntries
-    .filter(({ entry }) => entry.isFile())
-    .map(({ file }) => path.relative(payloadDir, file).split(path.sep).join("/"))
-    .filter((relative) => relative !== legal.file)
-    .sort(compareText);
-  if (JSON.stringify(actualFiles) !== JSON.stringify(expectedFiles)) {
-    fail(`${payloadDir} legal namespace contains missing or uncontracted files`);
-  }
-  const notice = await fs.readFile(path.join(payloadDir, ...legal.file.split("/")), "utf8");
-  if (notice !== renderLegalNotice(legal.spdx, legal.files)) {
-    fail(`${legal.file} does not exactly index the frozen legal selection`);
-  }
-  const podspec = await fs.readFile(path.join(payloadDir, "OliphauntReactNativePayload.podspec"), "utf8");
-  const licenseLine = `  s.license = { :type => ${JSON.stringify(legal.spdx)}, :file => ${JSON.stringify(legal.file)} }\n`;
-  if (!podspec.includes(licenseLine) || !podspec.includes('  s.preserve_paths = "licenses/**/*"\n')) {
-    fail(`${payloadDir} Podspec does not reference its exact staged legal closure`);
-  }
-}
-
-async function validatePackageAllowlist(packageDir) {
-  const packageJsonFile = path.join(packageDir, "package.json");
-  await requireFile(packageJsonFile, "React Native package manifest");
-  const manifest = JSON.parse(await fs.readFile(packageJsonFile, "utf8"));
-  if (!Array.isArray(manifest.files)) {
-    fail(`${packageJsonFile} must define an npm files allowlist`);
-  }
-  if (!manifest.files.some((entry) => entry === "ios" || entry.startsWith("ios/"))) {
-    fail(`${packageJsonFile} files allowlist does not include the iOS package tree`);
-  }
-  for (const relative of ["extension-frameworks", "frameworks", "generated", "resources"]) {
-    for (const suffix of ["", "/**"]) {
-      const exclusion = `!ios/${relative}${suffix}`;
-      if (!manifest.files.includes(exclusion)) {
-        fail(`${packageJsonFile} must exclude app-specific payload via ${exclusion}`);
-      }
-    }
-  }
-  if (!manifest.files.includes("tools/verify-ios-package.mjs")) {
-    fail(`${packageJsonFile} must publish tools/verify-ios-package.mjs for clean-install verification`);
-  }
-  if (!manifest.files.includes("tools/stage-ios-app.mjs")) {
-    fail(`${packageJsonFile} must publish tools/stage-ios-app.mjs for app-owned iOS staging`);
-  }
-  await requireFile(
-    path.join(packageDir, "OliphauntReactNative.podspec"),
-    "React Native CocoaPods specification",
-  );
-  await requireFile(
-    path.join(packageDir, "tools/verify-ios-package.mjs"),
-    "installed iOS package verifier",
-  );
-  await requireFile(
-    path.join(packageDir, "tools/stage-ios-app.mjs"),
-    "app-owned iOS carrier resolver",
-  );
-  for (const relative of [
-    "ios/resources",
-    "ios/frameworks",
-    "ios/extension-frameworks",
-    "ios/generated",
-  ]) {
-    if ((await statOrUndefined(path.join(packageDir, relative))) !== undefined) {
-      fail(`selection-neutral React Native base package contains generated payload ${relative}`);
-    }
-  }
-}
-
-async function validateBaseLibrary(payloadDir, resourceRoot, allowRuntimeDylib) {
-  const frameworkRoot = path.join(payloadDir, "frameworks/base");
-  const frameworkRootStat = await statOrUndefined(frameworkRoot);
-  const frameworks =
-    frameworkRootStat?.isDirectory() === true
-      ? (await fs.readdir(frameworkRoot, { withFileTypes: true }))
-          .filter(
-            (entry) =>
-              entry.isDirectory() &&
-              (entry.name.endsWith(".xcframework") || entry.name.endsWith(".framework")),
-          )
-          .map((entry) => ({ entry, file: path.join(frameworkRoot, entry.name) }))
-      : [];
-  const runtimeDylib = path.join(resourceRoot, "lib/liboliphaunt.dylib");
-  if (frameworks.length > 0) {
-    if (frameworks.length !== 1) {
-      fail(`staged iOS package must contain exactly one base Apple framework; found ${frameworks.length}`);
-    }
-    if ((await statOrUndefined(runtimeDylib)) !== undefined) {
-      fail(`staged iOS package contains both a base Apple framework and ${runtimeDylib}`);
-    }
-    for (const { entry, file } of frameworks) {
-      await requireFile(path.join(file, "Info.plist"), `${entry.name} metadata`);
-      const embeddedClosures = (await walk(file)).filter(
-        ({ entry: member, file: memberFile }) =>
-          member.isDirectory() &&
-          member.name === "oliphaunt" &&
-          path.basename(path.dirname(memberFile)) === "Resources",
-      );
-      if (embeddedClosures.length > 0) {
-        fail(
-          `staged React Native base framework must not embed a second runtime-resource closure: ` +
-            embeddedClosures.map(({ file: memberFile }) => memberFile).join(", "),
-        );
-      }
-    }
-    return frameworks.length;
-  }
-  if (!allowRuntimeDylib) {
-    fail(
-      `staged iOS package has no base .xcframework or .framework under ${frameworkRoot}; ` +
-        "runtime dylibs are accepted only with --allow-runtime-dylib",
-    );
-  }
-  await requireFile(runtimeDylib, "runtime-resource liboliphaunt dylib");
-  return 0;
-}
-
-async function validateNoBuildInputsInResources(resourceRoot) {
-  const forbidden = (await walk(resourceRoot)).filter(
-    ({ entry }) =>
-      (entry.isDirectory() && entry.name.endsWith(".xcframework")) ||
-      (entry.isFile() && entry.name === "oliphaunt_static_registry.c") ||
-      entry.name === "archives",
-  );
-  if (forbidden.length > 0) {
-    fail(
-      `iOS resource bundle contains build-only input(s): ${forbidden
-        .map(({ file }) => file)
-        .join(", ")}`,
-    );
-  }
-}
-
-async function validateStagedPackage(payloadDir, allowRuntimeDylib) {
-  const resourceRoot = path.join(
-    payloadDir,
-    "resources/OliphauntReactNativeResources.bundle/oliphaunt",
-  );
-  const resourceRoots = (await walk(path.join(payloadDir, "resources"))).filter(
-    ({ entry, file }) =>
-      entry.isDirectory() &&
-      entry.name === "oliphaunt" &&
-      path.basename(path.dirname(file)) === "OliphauntReactNativeResources.bundle",
-  );
-  if (
-    resourceRoots.length !== 1 ||
-    path.resolve(resourceRoots[0].file) !== path.resolve(resourceRoot)
-  ) {
-    fail("staged React Native payload must contain exactly one composed runtime-resource root");
-  }
-  await requireDirectory(resourceRoot, "React Native iOS runtime-resource bundle");
-  const runtimeManifestFile = path.join(resourceRoot, "runtime/manifest.properties");
-  const closure = await validateNativeRuntimeClosure(resourceRoot);
-  const runtime = closure.runtime;
-  const selectedExtensions = portableCsv(runtime, "selectedExtensions", runtimeManifestFile);
-  const extensions = portableCsv(runtime, "extensions", runtimeManifestFile);
-  const stems = portableCsv(runtime, "nativeModuleStems", runtimeManifestFile);
-  const runtimeRegistered = portableCsv(
-    runtime,
-    "mobileStaticRegistryRegistered",
-    runtimeManifestFile,
-  );
-  const runtimePending = portableCsv(
-    runtime,
-    "mobileStaticRegistryPending",
-    runtimeManifestFile,
-  );
-  const selectedSet = new Set(selectedExtensions);
-  const unselectedCreateable = extensions.filter((extension) => !selectedSet.has(extension));
-  if (unselectedCreateable.length > 0) {
-    fail(
-      `${runtimeManifestFile} extensions must be a subset of selectedExtensions; ` +
-        `unselected=${unselectedCreateable.join(",")}`,
-    );
-  }
-  const selectionFile = path.join(payloadDir, "selection.json");
-  await requireFile(selectionFile, "iOS extension selection manifest");
-  const selection = JSON.parse(await fs.readFile(selectionFile, "utf8"));
-  if (!Array.isArray(selection.extensions)) {
-    fail(`${selectionFile} extensions must be an array`);
-  }
-  const frozenRows = selection.extensions.map((extension, index) => {
-    const label = `${selectionFile} extensions[${index}]`;
-    const sqlName = requirePortableSelectionId(extension?.sqlName, `${label}.sqlName`);
-    if (typeof extension?.createsExtension !== "boolean") {
-      fail(`${label}.createsExtension must be boolean`);
-    }
-    if (extension.nativeModuleStem === undefined) {
-      fail(`${label}.nativeModuleStem must be a portable id or null`);
-    }
-    if (extension.nativeModuleStem !== null) {
-      requirePortableSelectionId(extension.nativeModuleStem, `${label}.nativeModuleStem`);
-    }
-    return extension;
-  });
-  const frozenSelected = frozenRows.map(({ sqlName }) => sqlName);
-  requireExactDomain(frozenSelected, frozenSelected, `${selectionFile} extension SQL names`);
-  await validateLegalSelection(payloadDir, selection, frozenSelected);
-  const frozenCreateable = frozenRows
-    .filter(({ createsExtension }) => createsExtension)
-    .map(({ sqlName }) => sqlName);
-  const frozenNative = frozenRows.filter(
-    ({ nativeModuleStem }) => typeof nativeModuleStem === "string",
-  );
-  const frozenNativeExtensions = frozenNative.map(({ sqlName }) => sqlName);
-  const frozenNativeStems = frozenNative.map(({ nativeModuleStem }) => nativeModuleStem);
-  const frozenNativeDependencies = frozenNative.flatMap(({ sqlName, nativeDependencies }) => {
-    if (!Array.isArray(nativeDependencies)) {
-      fail(`${selectionFile} native extension ${sqlName} must list nativeDependencies`);
-    }
-    const dependencies = nativeDependencies.map((dependency) =>
-      requirePortableSelectionId(dependency, `${selectionFile} nativeDependencies`));
-    requireExactDomain(
-      dependencies,
-      dependencies,
-      `${selectionFile} native extension ${sqlName} nativeDependencies`,
-    );
-    return dependencies;
-  });
-  requireExactDomain(selectedExtensions, frozenSelected, `${runtimeManifestFile} selectedExtensions`);
-  requireExactDomain(extensions, frozenCreateable, `${runtimeManifestFile} extensions`);
-  requireExactDomain(stems, frozenNativeStems, `${runtimeManifestFile} nativeModuleStems`);
-  requireExactDomain(
-    runtimeRegistered,
-    frozenNativeExtensions,
-    `${runtimeManifestFile} mobileStaticRegistryRegistered`,
-  );
-  requireExactDomain(runtimePending, [], `${runtimeManifestFile} mobileStaticRegistryPending`);
-  requireProperty(
-    runtime,
-    "mobileStaticRegistryState",
-    frozenNative.length > 0 ? "complete" : "not-required",
-    runtimeManifestFile,
-  );
-  requireProperty(
-    runtime,
-    "mobileStaticRegistrySource",
-    frozenNative.length > 0 ? "static-registry/oliphaunt_static_registry.c" : "",
-    runtimeManifestFile,
-  );
-  await requirePayloadFiles(path.join(resourceRoot, "runtime/files"), "iOS PostgreSQL runtime");
-  await requirePayloadFiles(
-    path.join(resourceRoot, "cluster-seed/files"),
-    "iOS standard cluster seed",
-  );
-  await requirePayloadFiles(
-    path.join(resourceRoot, "cluster-seed-icu/files"),
-    "iOS ICU cluster seed",
-  );
-  await requireFile(path.join(resourceRoot, "package-size.tsv"), "iOS package-size report");
-  const baseFrameworks = await validateBaseLibrary(payloadDir, resourceRoot, allowRuntimeDylib);
-  await validateNoBuildInputsInResources(resourceRoot);
-
-  const generatedRegistry = path.join(
-    payloadDir,
-    "generated/static-registry/oliphaunt_static_registry.c",
-  );
-  const staticRegistryManifestFile = path.join(
-    resourceRoot,
-    "static-registry/manifest.properties",
-  );
-  const extensionFrameworkRoot = path.join(payloadDir, "frameworks/extensions");
-  const extensionFrameworks = (await walk(extensionFrameworkRoot)).filter(
-    ({ entry }) => entry.isDirectory() && entry.name.endsWith(".xcframework"),
-  );
-  const packagedFrameworks = new Set(extensionFrameworks.map(({ entry }) => entry.name));
-  const staticRegistry = await readProperties(staticRegistryManifestFile);
-  requireProperty(
-    staticRegistry,
-    "packageLayout",
-    "oliphaunt-static-registry-v1",
-    staticRegistryManifestFile,
-  );
-  requireProperty(staticRegistry, "abiVersion", "1", staticRegistryManifestFile);
-  requireProperty(
-    staticRegistry,
-    "state",
-    frozenNative.length > 0 ? "complete" : "not-required",
-    staticRegistryManifestFile,
-  );
-  const registryStems = portableCsv(
-    staticRegistry,
-    "nativeModuleStems",
-    staticRegistryManifestFile,
-  );
-  const modules = portableCsv(staticRegistry, "modules", staticRegistryManifestFile);
-  const registeredExtensions = portableCsv(
-    staticRegistry,
-    "registeredExtensions",
-    staticRegistryManifestFile,
-  );
-  const pendingExtensions = portableCsv(
-    staticRegistry,
-    "pendingExtensions",
-    staticRegistryManifestFile,
-  );
-  const nativeDependencies = portableCsv(
-    staticRegistry,
-    "dependencyArchives",
-    staticRegistryManifestFile,
-  );
-  const archiveTargets = portableCsv(
-    staticRegistry,
-    "archiveTargets",
-    staticRegistryManifestFile,
-  );
-  const dependencyArchiveTargets = portableCsv(
-    staticRegistry,
-    "dependencyArchiveTargets",
-    staticRegistryManifestFile,
-  );
-  requireExactDomain(
-    registeredExtensions,
-    frozenNativeExtensions,
-    `${staticRegistryManifestFile} registeredExtensions`,
-  );
-  requireExactDomain(
-    registryStems,
-    frozenNativeStems,
-    `${staticRegistryManifestFile} nativeModuleStems`,
-  );
-  requireExactDomain(modules, frozenNativeStems, `${staticRegistryManifestFile} modules`);
-  requireExactDomain(pendingExtensions, [], `${staticRegistryManifestFile} pendingExtensions`);
-  requireExactDomain(
-    nativeDependencies,
-    frozenNativeDependencies,
-    `${staticRegistryManifestFile} dependencyArchives`,
-  );
-  requireExactDomain(
-    archiveTargets,
-    frozenNative.length > 0 ? ["ios-device", "ios-simulator"] : [],
-    `${staticRegistryManifestFile} archiveTargets`,
-  );
-  requireExactDomain(
-    dependencyArchiveTargets,
-    frozenNativeDependencies.length > 0 ? ["ios-device", "ios-simulator"] : [],
-    `${staticRegistryManifestFile} dependencyArchiveTargets`,
-  );
-  requireProperty(
-    staticRegistry,
-    "source",
-    frozenNative.length > 0 ? "oliphaunt_static_registry.c" : "",
-    staticRegistryManifestFile,
-  );
-
-  if (stems.length === 0) {
-    if ((await statOrUndefined(generatedRegistry)) !== undefined) {
-      fail("iOS package contains a generated static registry but runtime manifest has no nativeModuleStems");
-    }
-    if (packagedFrameworks.size > 0) {
-      fail("iOS package links extension XCFrameworks but runtime manifest has no nativeModuleStems");
-    }
-  } else {
-    requireProperty(
-      staticRegistry,
-      "source",
-      "oliphaunt_static_registry.c",
-      staticRegistryManifestFile,
-    );
-    await requireFile(generatedRegistry, "generated iOS static-extension registry source");
-    const registrySource = await fs.readFile(generatedRegistry, "utf8");
-    if (!registrySource.includes("liboliphaunt_selected_static_extensions")) {
-      fail(`${generatedRegistry} does not define the selected static-extension registry`);
-    }
-    const expectedFrameworks = new Set([
-      ...stems.map((stem) => `liboliphaunt_extension_${stem}.xcframework`),
-      ...nativeDependencies.map(
-        (dependency) => `liboliphaunt_dependency_${dependency}.xcframework`,
-      ),
-    ]);
-    const missing = [...expectedFrameworks].filter((name) => !packagedFrameworks.has(name));
-    const extra = [...packagedFrameworks].filter((name) => !expectedFrameworks.has(name));
-    if (missing.length > 0 || extra.length > 0) {
-      fail(
-        `iOS extension XCFramework selection mismatch; missing=${missing.sort().join(",") || "-"} ` +
-          `extra=${extra.sort().join(",") || "-"}`,
-      );
-    }
-    for (const { entry, file } of extensionFrameworks) {
-      await requireFile(path.join(file, "Info.plist"), `${entry.name} metadata`);
-    }
-  }
-
-  console.log(
-    `${PREFIX}: verified ${payloadDir} ` +
-      `(selectedExtensions=${selectedExtensions.join(",") || "none"}, ` +
-        `extensions=${extensions.join(",") || "none"}, ` +
-        `nativeModuleStems=${stems.join(",") || "none"}, baseFrameworks=${baseFrameworks})`,
-  );
-}
-
-async function main() {
-  const args = parseArgs(process.argv.slice(2));
-  if (args.packageDir) {
-    await validatePackageAllowlist(args.packageDir);
-    console.log(`${PREFIX}: verified selection-neutral package contract for ${args.packageDir}`);
-  } else {
-    await validateStagedPackage(args.payloadDir, args.allowRuntimeDylib);
-  }
-}
-
-main().catch((error) => {
-  console.error(error instanceof Error ? error.message : String(error));
-  process.exit(1);
-});
diff --git a/src/sdks/react-native/tools/verify-ios-package.mts b/src/sdks/react-native/tools/verify-ios-package.mts
new file mode 100755
index 000000000..34b76055c
--- /dev/null
+++ b/src/sdks/react-native/tools/verify-ios-package.mts
@@ -0,0 +1,734 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+
+import {
+  parseProperties,
+  requireProperty,
+  validateNativeRuntimeClosure,
+} from './native-resource-closure.mts';
+
+const PREFIX = 'verify-ios-package.mts';
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+
+function usage() {
+  console.error(
+    `usage: ${PREFIX} (--package-dir  | --payload-dir ) ` +
+      `[--allow-runtime-dylib]`,
+  );
+}
+
+function parseArgs(argv) {
+  const args = {
+    allowRuntimeDylib: false,
+    packageDir: undefined,
+    payloadDir: undefined,
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--package-dir') {
+      args.packageDir = argv[index + 1];
+      index += 1;
+    } else if (arg === '--payload-dir') {
+      args.payloadDir = argv[index + 1];
+      index += 1;
+    } else if (arg === '--allow-runtime-dylib') {
+      args.allowRuntimeDylib = true;
+    } else if (arg === '--help' || arg === '-h') {
+      usage();
+      process.exit(0);
+    } else {
+      usage();
+      fail(`unknown argument ${arg}`);
+    }
+  }
+  const roots = [args.packageDir, args.payloadDir].filter(
+    (value) => typeof value === 'string' && value.length > 0,
+  );
+  if (roots.length !== 1) {
+    usage();
+    fail('exactly one of --package-dir or --payload-dir is required');
+  }
+  if (args.packageDir) args.packageDir = path.resolve(args.packageDir);
+  if (args.payloadDir) args.payloadDir = path.resolve(args.payloadDir);
+  return args;
+}
+
+async function statOrUndefined(file) {
+  return fs.stat(file).catch((error) => {
+    if (error?.code === 'ENOENT') {
+      return undefined;
+    }
+    throw error;
+  });
+}
+
+async function requireFile(file, label) {
+  const stat = await statOrUndefined(file);
+  if (stat?.isFile() !== true || stat.size === 0) {
+    fail(`${label} is missing or empty: ${file}`);
+  }
+}
+
+async function requireDirectory(file, label) {
+  const stat = await statOrUndefined(file);
+  if (stat?.isDirectory() !== true) {
+    fail(`${label} is missing: ${file}`);
+  }
+}
+
+async function walk(root) {
+  const rootStat = await statOrUndefined(root);
+  if (rootStat?.isDirectory() !== true) {
+    return [];
+  }
+  const result = [];
+  const pending = [root];
+  while (pending.length > 0) {
+    const current = pending.pop();
+    const entries = await fs.readdir(current, { withFileTypes: true });
+    entries.sort((left, right) => compareText(left.name, right.name));
+    for (const entry of entries) {
+      const file = path.join(current, entry.name);
+      result.push({ entry, file });
+      if (entry.isDirectory()) {
+        pending.push(file);
+      }
+    }
+  }
+  return result.sort((left, right) => compareText(left.file, right.file));
+}
+
+async function requirePayloadFiles(root, label) {
+  const entries = await walk(root);
+  if (!entries.some(({ entry }) => entry.isFile())) {
+    fail(`${label} contains no payload files: ${root}`);
+  }
+}
+
+async function readProperties(file) {
+  await requireFile(file, 'runtime-resource manifest');
+  return parseProperties(await fs.readFile(file, 'utf8'), file);
+}
+
+function portableCsv(properties, key, source) {
+  const value = properties.get(key);
+  if (value === undefined) {
+    fail(`${source} is missing ${key}`);
+  }
+  if (!value) {
+    return [];
+  }
+  const items = value.split(',');
+  const seen = new Set();
+  for (const item of items) {
+    if (!/^[A-Za-z0-9._-]+$/u.test(item)) {
+      fail(`${source} ${key} contains invalid portable id ${JSON.stringify(item)}`);
+    }
+    if (seen.has(item)) {
+      fail(`${source} ${key} repeats ${item}`);
+    }
+    seen.add(item);
+  }
+  return items;
+}
+
+function requireExactDomain(actual, expected, label) {
+  const canonicalExpected = [...new Set(expected)].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(canonicalExpected)) {
+    fail(
+      `${label} must match the exact canonical domain; ` +
+        `actual=${actual.join(',') || '-'} expected=${canonicalExpected.join(',') || '-'}`,
+    );
+  }
+}
+
+function requirePortableSelectionId(value, label) {
+  if (typeof value !== 'string' || !/^[A-Za-z0-9._-]+$/u.test(value)) {
+    fail(`${label} must be a portable id; got ${JSON.stringify(value)}`);
+  }
+  return value;
+}
+
+function safeRelative(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    value.startsWith('/') ||
+    /^[A-Za-z]:/u.test(value) ||
+    /[\u0000-\u001f\u007f]/u.test(value)
+  ) {
+    fail(`${label} must be a safe relative path`);
+  }
+  const parts = value.split('/');
+  if (parts.some((part) => !part || part === '.' || part === '..')) {
+    fail(`${label} must be a safe relative path`);
+  }
+  return value;
+}
+
+function renderLegalNotice(spdx, files) {
+  return [
+    '# Oliphaunt app-owned iOS payload legal notices',
+    '',
+    `SPDX-License-Identifier: ${spdx}`,
+    '',
+    'This file indexes the exact legal files materialized from the selected frozen carriers.',
+    '',
+    ...files.map((row) => `- \`${row.destination}\` (${row.kind}; SHA-256 \`${row.sha256}\`)`),
+    '',
+  ].join('\n');
+}
+
+async function validateLegalSelection(payloadDir, selection, frozenSelected) {
+  const legal = selection?.legal;
+  if (legal === null || Array.isArray(legal) || typeof legal !== 'object') {
+    fail(`${payloadDir}/selection.json legal must be an object`);
+  }
+  const keys = Object.keys(legal).sort(compareText);
+  if (JSON.stringify(keys) !== JSON.stringify(['file', 'files', 'spdx'])) {
+    fail(`${payloadDir}/selection.json legal fields must be exactly file,files,spdx`);
+  }
+  if (legal.file !== 'licenses/NOTICE.md') {
+    fail(`${payloadDir}/selection.json legal.file must be licenses/NOTICE.md`);
+  }
+  if (
+    typeof legal.spdx !== 'string' ||
+    legal.spdx.split(' AND ').some((term) => !/^[A-Za-z0-9][A-Za-z0-9.-]*$/u.test(term))
+  ) {
+    fail(`${payloadDir}/selection.json legal.spdx must be a safe SPDX conjunction`);
+  }
+  if (!Array.isArray(legal.files) || legal.files.length === 0) {
+    fail(`${payloadDir}/selection.json legal.files must be non-empty`);
+  }
+  if (typeof selection.icu !== 'boolean') {
+    fail(`${payloadDir}/selection.json icu must be boolean`);
+  }
+  const legalEntries = await walk(path.join(payloadDir, 'licenses'));
+  const unsafeEntries = legalEntries.filter(({ entry }) => !entry.isDirectory() && !entry.isFile());
+  if (unsafeEntries.length > 0) {
+    fail(
+      `${payloadDir} legal namespace contains symbolic links or special files: ` +
+        unsafeEntries.map(({ file }) => file).join(', '),
+    );
+  }
+  const selected = new Set(frozenSelected);
+  const expectedFiles = [];
+  const baseScopes = new Set();
+  const extensionScopes = new Set();
+  for (const [index, row] of legal.files.entries()) {
+    const label = `${payloadDir}/selection.json legal.files[${index}]`;
+    if (row === null || Array.isArray(row) || typeof row !== 'object')
+      fail(`${label} must be an object`);
+    const rowKeys = Object.keys(row).sort(compareText);
+    if (
+      JSON.stringify(rowKeys) !==
+      JSON.stringify(['bytes', 'destination', 'kind', 'member', 'sha256', 'source'])
+    ) {
+      fail(`${label} fields must be exactly bytes,destination,kind,member,sha256,source`);
+    }
+    const destination = safeRelative(row.destination, `${label}.destination`);
+    safeRelative(row.member, `${label}.member`);
+    if (
+      !destination.startsWith('licenses/base/') &&
+      !destination.startsWith('licenses/extensions/')
+    ) {
+      fail(`${label}.destination is outside the selected legal namespaces`);
+    }
+    const baseRole = /^licenses\/base\/([^/]+)\//u.exec(destination)?.[1];
+    if (baseRole !== undefined) {
+      requirePortableSelectionId(baseRole, `${label} base legal role`);
+      if (!new Set(['base-xcframework', 'runtime-resources']).has(baseRole)) {
+        fail(`${label}.destination carries unknown base legal role ${baseRole}`);
+      }
+      if (row.source !== 'base') fail(`${label}.source must be base for a base legal destination`);
+      baseScopes.add(baseRole);
+    }
+    const extension = /^licenses\/extensions\/([^/]+)\//u.exec(destination)?.[1];
+    if (baseRole === undefined && extension === undefined) {
+      fail(`${label}.destination must name a file below one exact legal scope`);
+    }
+    if (extension !== undefined && !selected.has(extension)) {
+      fail(`${label}.destination leaks unselected extension ${extension}`);
+    }
+    if (extension !== undefined) {
+      requirePortableSelectionId(extension, `${label} extension legal scope`);
+      if (row.source !== 'extension') {
+        fail(`${label}.source must be extension for an extension legal destination`);
+      }
+      extensionScopes.add(extension);
+    }
+    if (
+      !new Set(['license', 'notice']).has(row.kind) ||
+      !new Set(['base', 'extension']).has(row.source)
+    ) {
+      fail(`${label} has an invalid legal kind/source`);
+    }
+    if (!Number.isSafeInteger(row.bytes) || row.bytes <= 0 || !/^[0-9a-f]{64}$/u.test(row.sha256)) {
+      fail(`${label} has an invalid byte count or SHA-256`);
+    }
+    const file = path.join(payloadDir, ...destination.split('/'));
+    const stat = await fs.lstat(file).catch((error) => {
+      fail(`${label} is missing from the payload: ${error.message}`);
+    });
+    if (!stat.isFile() || stat.isSymbolicLink() || stat.size !== row.bytes) {
+      fail(`${label} is not the frozen regular legal file`);
+    }
+    const digest = createHash('sha256')
+      .update(await fs.readFile(file))
+      .digest('hex');
+    if (digest !== row.sha256) fail(`${label} checksum differs from selection.json`);
+    expectedFiles.push(destination);
+  }
+  const canonical = [...expectedFiles].sort(compareText);
+  if (
+    new Set(expectedFiles).size !== expectedFiles.length ||
+    JSON.stringify(canonical) !== JSON.stringify(expectedFiles)
+  ) {
+    fail(`${payloadDir}/selection.json legal.files must be unique and sorted by destination`);
+  }
+  const expectedBaseScopes = ['base-xcframework', 'runtime-resources'].sort(compareText);
+  requireExactDomain(
+    [...baseScopes].sort(compareText),
+    expectedBaseScopes,
+    `${payloadDir} base legal scopes`,
+  );
+  requireExactDomain(
+    [...extensionScopes].sort(compareText),
+    frozenSelected,
+    `${payloadDir} extension legal scopes`,
+  );
+  const actualFiles = legalEntries
+    .filter(({ entry }) => entry.isFile())
+    .map(({ file }) => path.relative(payloadDir, file).split(path.sep).join('/'))
+    .filter((relative) => relative !== legal.file)
+    .sort(compareText);
+  if (JSON.stringify(actualFiles) !== JSON.stringify(expectedFiles)) {
+    fail(`${payloadDir} legal namespace contains missing or uncontracted files`);
+  }
+  const notice = await fs.readFile(path.join(payloadDir, ...legal.file.split('/')), 'utf8');
+  if (notice !== renderLegalNotice(legal.spdx, legal.files)) {
+    fail(`${legal.file} does not exactly index the frozen legal selection`);
+  }
+  const podspec = await fs.readFile(
+    path.join(payloadDir, 'OliphauntReactNativePayload.podspec'),
+    'utf8',
+  );
+  const seedProfile = selection.seedProfile ?? null;
+  if (seedProfile !== null && !['standard', 'icu'].includes(seedProfile))
+    fail(`${payloadDir} has an invalid seed profile`);
+  if ((seedProfile === 'standard' && selection.icu) || (seedProfile === 'icu' && !selection.icu))
+    fail(`${payloadDir} seed profile conflicts with ICU selection`);
+  const resourcePods = [
+    ...podspec.matchAll(/s\.dependency "(OliphauntICU|OliphauntSeedNativeIOS(?:ICU|Standard))"/gu),
+  ]
+    .map((match) => match[1])
+    .sort(compareText);
+  const expectedResourcePods = [
+    ...(selection.icu ? ['OliphauntICU'] : []),
+    ...(seedProfile ? [`OliphauntSeedNativeIOS${seedProfile === 'icu' ? 'ICU' : 'Standard'}`] : []),
+  ].sort(compareText);
+  requireExactDomain(
+    resourcePods,
+    expectedResourcePods,
+    `${payloadDir} selected resource CocoaPods`,
+  );
+  const licenseLine = `  s.license = { :type => ${JSON.stringify(legal.spdx)}, :file => ${JSON.stringify(legal.file)} }\n`;
+  if (
+    !podspec.includes(licenseLine) ||
+    !podspec.includes('  s.preserve_paths = "licenses/**/*"\n')
+  ) {
+    fail(`${payloadDir} Podspec does not reference its exact staged legal closure`);
+  }
+}
+
+async function validatePackageAllowlist(packageDir) {
+  const packageJsonFile = path.join(packageDir, 'package.json');
+  await requireFile(packageJsonFile, 'React Native package manifest');
+  const manifest = JSON.parse(await fs.readFile(packageJsonFile, 'utf8'));
+  if (!Array.isArray(manifest.files)) {
+    fail(`${packageJsonFile} must define an npm files allowlist`);
+  }
+  if (!manifest.files.some((entry) => entry === 'ios' || entry.startsWith('ios/'))) {
+    fail(`${packageJsonFile} files allowlist does not include the iOS package tree`);
+  }
+  for (const relative of ['extension-frameworks', 'frameworks', 'generated', 'resources']) {
+    for (const suffix of ['', '/**']) {
+      const exclusion = `!ios/${relative}${suffix}`;
+      if (!manifest.files.includes(exclusion)) {
+        fail(`${packageJsonFile} must exclude app-specific payload via ${exclusion}`);
+      }
+    }
+  }
+  if (!manifest.files.includes('tools/verify-ios-package.mjs')) {
+    fail(
+      `${packageJsonFile} must publish tools/verify-ios-package.mjs for clean-install verification`,
+    );
+  }
+  if (!manifest.files.includes('tools/stage-ios-app.mjs')) {
+    fail(`${packageJsonFile} must publish tools/stage-ios-app.mjs for app-owned iOS staging`);
+  }
+  await requireFile(
+    path.join(packageDir, 'OliphauntReactNative.podspec'),
+    'React Native CocoaPods specification',
+  );
+  await requireFile(
+    path.join(packageDir, 'tools/verify-ios-package.mjs'),
+    'installed iOS package verifier',
+  );
+  await requireFile(
+    path.join(packageDir, 'tools/stage-ios-app.mjs'),
+    'app-owned iOS carrier resolver',
+  );
+  for (const relative of [
+    'ios/resources',
+    'ios/frameworks',
+    'ios/extension-frameworks',
+    'ios/generated',
+  ]) {
+    if ((await statOrUndefined(path.join(packageDir, relative))) !== undefined) {
+      fail(`selection-neutral React Native base package contains generated payload ${relative}`);
+    }
+  }
+}
+
+async function validateBaseLibrary(payloadDir, resourceRoot, allowRuntimeDylib) {
+  const frameworkRoot = path.join(payloadDir, 'frameworks/base');
+  const frameworkRootStat = await statOrUndefined(frameworkRoot);
+  const frameworks =
+    frameworkRootStat?.isDirectory() === true
+      ? (await fs.readdir(frameworkRoot, { withFileTypes: true }))
+          .filter(
+            (entry) =>
+              entry.isDirectory() &&
+              (entry.name.endsWith('.xcframework') || entry.name.endsWith('.framework')),
+          )
+          .map((entry) => ({ entry, file: path.join(frameworkRoot, entry.name) }))
+      : [];
+  const runtimeDylib = path.join(resourceRoot, 'lib/liboliphaunt.dylib');
+  if (frameworks.length > 0) {
+    if (frameworks.length !== 1) {
+      fail(
+        `staged iOS package must contain exactly one base Apple framework; found ${frameworks.length}`,
+      );
+    }
+    if ((await statOrUndefined(runtimeDylib)) !== undefined) {
+      fail(`staged iOS package contains both a base Apple framework and ${runtimeDylib}`);
+    }
+    for (const { entry, file } of frameworks) {
+      await requireFile(path.join(file, 'Info.plist'), `${entry.name} metadata`);
+      const embeddedClosures = (await walk(file)).filter(
+        ({ entry: member, file: memberFile }) =>
+          member.isDirectory() &&
+          member.name === 'oliphaunt' &&
+          path.basename(path.dirname(memberFile)) === 'Resources',
+      );
+      if (embeddedClosures.length > 0) {
+        fail(
+          `staged React Native base framework must not embed a second runtime-resource closure: ` +
+            embeddedClosures.map(({ file: memberFile }) => memberFile).join(', '),
+        );
+      }
+    }
+    return frameworks.length;
+  }
+  if (!allowRuntimeDylib) {
+    fail(
+      `staged iOS package has no base .xcframework or .framework under ${frameworkRoot}; ` +
+        'runtime dylibs are accepted only with --allow-runtime-dylib',
+    );
+  }
+  await requireFile(runtimeDylib, 'runtime-resource liboliphaunt dylib');
+  return 0;
+}
+
+async function validateNoBuildInputsInResources(resourceRoot) {
+  const forbidden = (await walk(resourceRoot)).filter(
+    ({ entry }) =>
+      (entry.isDirectory() && entry.name.endsWith('.xcframework')) ||
+      (entry.isFile() && entry.name === 'oliphaunt_static_registry.c') ||
+      entry.name === 'archives',
+  );
+  if (forbidden.length > 0) {
+    fail(
+      `iOS resource bundle contains build-only input(s): ${forbidden
+        .map(({ file }) => file)
+        .join(', ')}`,
+    );
+  }
+}
+
+export async function validateStagedPackage(payloadDir, allowRuntimeDylib) {
+  const resourceRoot = path.join(
+    payloadDir,
+    'resources/OliphauntReactNativeResources.bundle/oliphaunt',
+  );
+  const resourceRoots = (await walk(path.join(payloadDir, 'resources'))).filter(
+    ({ entry, file }) =>
+      entry.isDirectory() &&
+      entry.name === 'oliphaunt' &&
+      path.basename(path.dirname(file)) === 'OliphauntReactNativeResources.bundle',
+  );
+  if (
+    resourceRoots.length !== 1 ||
+    path.resolve(resourceRoots[0].file) !== path.resolve(resourceRoot)
+  ) {
+    fail('staged React Native payload must contain exactly one composed runtime-resource root');
+  }
+  await requireDirectory(resourceRoot, 'React Native iOS runtime-resource bundle');
+  const runtimeManifestFile = path.join(resourceRoot, 'runtime/manifest.properties');
+  const closure = await validateNativeRuntimeClosure(resourceRoot);
+  const runtime = closure.runtime;
+  const selectedExtensions = portableCsv(runtime, 'selectedExtensions', runtimeManifestFile);
+  const extensions = portableCsv(runtime, 'extensions', runtimeManifestFile);
+  const stems = portableCsv(runtime, 'nativeModuleStems', runtimeManifestFile);
+  const runtimeRegistered = portableCsv(
+    runtime,
+    'mobileStaticRegistryRegistered',
+    runtimeManifestFile,
+  );
+  const runtimePending = portableCsv(runtime, 'mobileStaticRegistryPending', runtimeManifestFile);
+  const selectedSet = new Set(selectedExtensions);
+  const unselectedCreateable = extensions.filter((extension) => !selectedSet.has(extension));
+  if (unselectedCreateable.length > 0) {
+    fail(
+      `${runtimeManifestFile} extensions must be a subset of selectedExtensions; ` +
+        `unselected=${unselectedCreateable.join(',')}`,
+    );
+  }
+  const selectionFile = path.join(payloadDir, 'selection.json');
+  await requireFile(selectionFile, 'iOS extension selection manifest');
+  const selection = JSON.parse(await fs.readFile(selectionFile, 'utf8'));
+  if (!Array.isArray(selection.extensions)) {
+    fail(`${selectionFile} extensions must be an array`);
+  }
+  const frozenRows = selection.extensions.map((extension, index) => {
+    const label = `${selectionFile} extensions[${index}]`;
+    requirePortableSelectionId(extension?.sqlName, `${label}.sqlName`);
+    if (typeof extension?.createsExtension !== 'boolean') {
+      fail(`${label}.createsExtension must be boolean`);
+    }
+    if (extension.nativeModuleStem === undefined) {
+      fail(`${label}.nativeModuleStem must be a portable id or null`);
+    }
+    if (extension.nativeModuleStem !== null) {
+      requirePortableSelectionId(extension.nativeModuleStem, `${label}.nativeModuleStem`);
+    }
+    return extension;
+  });
+  const frozenSelected = frozenRows.map(({ sqlName }) => sqlName);
+  requireExactDomain(frozenSelected, frozenSelected, `${selectionFile} extension SQL names`);
+  await validateLegalSelection(payloadDir, selection, frozenSelected);
+  const frozenCreateable = frozenRows
+    .filter(({ createsExtension }) => createsExtension)
+    .map(({ sqlName }) => sqlName);
+  const frozenNative = frozenRows.filter(
+    ({ nativeModuleStem }) => typeof nativeModuleStem === 'string',
+  );
+  const frozenNativeExtensions = frozenNative.map(({ sqlName }) => sqlName);
+  const frozenNativeStems = frozenNative.map(({ nativeModuleStem }) => nativeModuleStem);
+  const frozenNativeDependencies = frozenNative.flatMap(({ sqlName, nativeDependencies }) => {
+    if (!Array.isArray(nativeDependencies)) {
+      fail(`${selectionFile} native extension ${sqlName} must list nativeDependencies`);
+    }
+    const dependencies = nativeDependencies.map((dependency) =>
+      requirePortableSelectionId(dependency, `${selectionFile} nativeDependencies`),
+    );
+    requireExactDomain(
+      dependencies,
+      dependencies,
+      `${selectionFile} native extension ${sqlName} nativeDependencies`,
+    );
+    return dependencies;
+  });
+  requireExactDomain(
+    selectedExtensions,
+    frozenSelected,
+    `${runtimeManifestFile} selectedExtensions`,
+  );
+  requireExactDomain(extensions, frozenCreateable, `${runtimeManifestFile} extensions`);
+  requireExactDomain(stems, frozenNativeStems, `${runtimeManifestFile} nativeModuleStems`);
+  requireExactDomain(
+    runtimeRegistered,
+    frozenNativeExtensions,
+    `${runtimeManifestFile} mobileStaticRegistryRegistered`,
+  );
+  requireExactDomain(runtimePending, [], `${runtimeManifestFile} mobileStaticRegistryPending`);
+  requireProperty(
+    runtime,
+    'mobileStaticRegistryState',
+    frozenNative.length > 0 ? 'complete' : 'not-required',
+    runtimeManifestFile,
+  );
+  requireProperty(
+    runtime,
+    'mobileStaticRegistrySource',
+    frozenNative.length > 0 ? 'static-registry/oliphaunt_static_registry.c' : '',
+    runtimeManifestFile,
+  );
+  await requirePayloadFiles(path.join(resourceRoot, 'runtime/files'), 'iOS PostgreSQL runtime');
+  await requireFile(path.join(resourceRoot, 'package-size.tsv'), 'iOS package-size report');
+  const baseFrameworks = await validateBaseLibrary(payloadDir, resourceRoot, allowRuntimeDylib);
+  await validateNoBuildInputsInResources(resourceRoot);
+
+  const generatedRegistry = path.join(
+    payloadDir,
+    'generated/static-registry/oliphaunt_static_registry.c',
+  );
+  const staticRegistryManifestFile = path.join(resourceRoot, 'static-registry/manifest.properties');
+  const extensionFrameworkRoot = path.join(payloadDir, 'frameworks/extensions');
+  const extensionFrameworks = (await walk(extensionFrameworkRoot)).filter(
+    ({ entry }) => entry.isDirectory() && entry.name.endsWith('.xcframework'),
+  );
+  const packagedFrameworks = new Set(extensionFrameworks.map(({ entry }) => entry.name));
+  const staticRegistry = await readProperties(staticRegistryManifestFile);
+  requireProperty(
+    staticRegistry,
+    'packageLayout',
+    'oliphaunt-static-registry-v1',
+    staticRegistryManifestFile,
+  );
+  requireProperty(staticRegistry, 'abiVersion', '1', staticRegistryManifestFile);
+  requireProperty(
+    staticRegistry,
+    'state',
+    frozenNative.length > 0 ? 'complete' : 'not-required',
+    staticRegistryManifestFile,
+  );
+  const registryStems = portableCsv(
+    staticRegistry,
+    'nativeModuleStems',
+    staticRegistryManifestFile,
+  );
+  const modules = portableCsv(staticRegistry, 'modules', staticRegistryManifestFile);
+  const registeredExtensions = portableCsv(
+    staticRegistry,
+    'registeredExtensions',
+    staticRegistryManifestFile,
+  );
+  const pendingExtensions = portableCsv(
+    staticRegistry,
+    'pendingExtensions',
+    staticRegistryManifestFile,
+  );
+  const nativeDependencies = portableCsv(
+    staticRegistry,
+    'dependencyArchives',
+    staticRegistryManifestFile,
+  );
+  const archiveTargets = portableCsv(staticRegistry, 'archiveTargets', staticRegistryManifestFile);
+  const dependencyArchiveTargets = portableCsv(
+    staticRegistry,
+    'dependencyArchiveTargets',
+    staticRegistryManifestFile,
+  );
+  requireExactDomain(
+    registeredExtensions,
+    frozenNativeExtensions,
+    `${staticRegistryManifestFile} registeredExtensions`,
+  );
+  requireExactDomain(
+    registryStems,
+    frozenNativeStems,
+    `${staticRegistryManifestFile} nativeModuleStems`,
+  );
+  requireExactDomain(modules, frozenNativeStems, `${staticRegistryManifestFile} modules`);
+  requireExactDomain(pendingExtensions, [], `${staticRegistryManifestFile} pendingExtensions`);
+  requireExactDomain(
+    nativeDependencies,
+    frozenNativeDependencies,
+    `${staticRegistryManifestFile} dependencyArchives`,
+  );
+  requireExactDomain(
+    archiveTargets,
+    frozenNative.length > 0 ? ['ios-device', 'ios-simulator'] : [],
+    `${staticRegistryManifestFile} archiveTargets`,
+  );
+  requireExactDomain(
+    dependencyArchiveTargets,
+    frozenNativeDependencies.length > 0 ? ['ios-device', 'ios-simulator'] : [],
+    `${staticRegistryManifestFile} dependencyArchiveTargets`,
+  );
+  requireProperty(
+    staticRegistry,
+    'source',
+    frozenNative.length > 0 ? 'oliphaunt_static_registry.c' : '',
+    staticRegistryManifestFile,
+  );
+
+  if (stems.length === 0) {
+    if ((await statOrUndefined(generatedRegistry)) !== undefined) {
+      fail(
+        'iOS package contains a generated static registry but runtime manifest has no nativeModuleStems',
+      );
+    }
+    if (packagedFrameworks.size > 0) {
+      fail(
+        'iOS package links extension XCFrameworks but runtime manifest has no nativeModuleStems',
+      );
+    }
+  } else {
+    requireProperty(
+      staticRegistry,
+      'source',
+      'oliphaunt_static_registry.c',
+      staticRegistryManifestFile,
+    );
+    await requireFile(generatedRegistry, 'generated iOS static-extension registry source');
+    const registrySource = await fs.readFile(generatedRegistry, 'utf8');
+    if (!registrySource.includes('liboliphaunt_selected_static_extensions')) {
+      fail(`${generatedRegistry} does not define the selected static-extension registry`);
+    }
+    const expectedFrameworks = new Set([
+      ...stems.map((stem) => `liboliphaunt_extension_${stem}.xcframework`),
+      ...nativeDependencies.map(
+        (dependency) => `liboliphaunt_dependency_${dependency}.xcframework`,
+      ),
+    ]);
+    const missing = [...expectedFrameworks].filter((name) => !packagedFrameworks.has(name));
+    const extra = [...packagedFrameworks].filter((name) => !expectedFrameworks.has(name));
+    if (missing.length > 0 || extra.length > 0) {
+      fail(
+        `iOS extension XCFramework selection mismatch; missing=${missing.sort().join(',') || '-'} ` +
+          `extra=${extra.sort().join(',') || '-'}`,
+      );
+    }
+    for (const { entry, file } of extensionFrameworks) {
+      await requireFile(path.join(file, 'Info.plist'), `${entry.name} metadata`);
+    }
+  }
+
+  console.log(
+    `${PREFIX}: verified ${payloadDir} ` +
+      `(selectedExtensions=${selectedExtensions.join(',') || 'none'}, ` +
+      `extensions=${extensions.join(',') || 'none'}, ` +
+      `nativeModuleStems=${stems.join(',') || 'none'}, baseFrameworks=${baseFrameworks})`,
+  );
+}
+
+async function main() {
+  const args = parseArgs(process.argv.slice(2));
+  if (args.packageDir) {
+    await validatePackageAllowlist(args.packageDir);
+    console.log(`${PREFIX}: verified selection-neutral package contract for ${args.packageDir}`);
+  } else {
+    await validateStagedPackage(args.payloadDir, args.allowRuntimeDylib);
+  }
+}
+
+if (import.meta.main) {
+  main().catch((error) => {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(1);
+  });
+}
diff --git a/src/sdks/react-native/tsconfig.json b/src/sdks/react-native/tsconfig.json
index e55f8e213..33f5e9417 100644
--- a/src/sdks/react-native/tsconfig.json
+++ b/src/sdks/react-native/tsconfig.json
@@ -11,7 +11,7 @@
     "skipLibCheck": true,
     "strict": true,
     "target": "ES2022",
-    "types": ["node"]
+    "types": ["node", "bun"]
   },
   "include": ["src/**/*.ts"],
   "exclude": ["lib", "node_modules"]
diff --git a/src/sdks/react-native/typedoc.json b/src/sdks/react-native/typedoc.json
deleted file mode 100644
index 1d49110a5..000000000
--- a/src/sdks/react-native/typedoc.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "$schema": "https://typedoc.org/schema.json",
-  "entryPoints": ["src/index.ts"],
-  "exclude": ["src/__tests__/**"],
-  "excludePrivate": true,
-  "excludeProtected": true,
-  "gitRevision": "main",
-  "json": "../../target/docs/generated/api/react-native/typedoc.json",
-  "name": "Oliphaunt React Native SDK",
-  "out": "../../target/docs/generated/api/react-native/html",
-  "plugin": [],
-  "readme": "README.md",
-  "tsconfig": "tsconfig.build.json"
-}
diff --git a/src/sdks/rust-query/CHANGELOG.md b/src/sdks/rust-query/CHANGELOG.md
new file mode 100644
index 000000000..3b8aca158
--- /dev/null
+++ b/src/sdks/rust-query/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## Unreleased
+
+- Extract shared PostgreSQL query types, encoding and decoding from the native and WASIX Rust SDKs.
diff --git a/src/sdks/rust-query/Cargo.toml b/src/sdks/rust-query/Cargo.toml
new file mode 100644
index 000000000..838b55e5c
--- /dev/null
+++ b/src/sdks/rust-query/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "oliphaunt-query"
+version = "0.1.0"
+edition.workspace = true
+rust-version.workspace = true
+repository.workspace = true
+homepage.workspace = true
+license.workspace = true
+description = "PostgreSQL query encoding, result decoding and shared types for Oliphaunt SDKs."
+readme = "README.md"
+exclude = ["moon.yml", "release.toml"]
diff --git a/src/sdks/rust-query/LICENSE b/src/sdks/rust-query/LICENSE
new file mode 120000
index 000000000..5853aaea5
--- /dev/null
+++ b/src/sdks/rust-query/LICENSE
@@ -0,0 +1 @@
+../../../LICENSE
\ No newline at end of file
diff --git a/src/sdks/rust-query/README.md b/src/sdks/rust-query/README.md
new file mode 100644
index 000000000..759e63541
--- /dev/null
+++ b/src/sdks/rust-query/README.md
@@ -0,0 +1,22 @@
+# oliphaunt-query
+
+Runtime-independent PostgreSQL query encoding, decoding, results and diagnostics shared by the native and WASIX Rust SDKs. This crate depends only on the Rust standard library.
+
+Run `cargo test`, `cargo check`, or `cargo fmt --check` from this directory. Database execution and lifecycle belong to the consuming SDKs.
+
+## Maintainer commands
+
+Run these commands from this directory with the repository-pinned Rust toolchain, Moon and Bun available. Cargo resolves versioned workspace dependencies itself; no runtime build is needed for source tests. Bash is required for package staging (Git Bash on Windows). The initial locked Cargo fetch needs network access.
+
+| Command | Result |
+| --- | --- |
+| `moon run oliphaunt-query:format` | Rewrite Rust formatting. |
+| `moon run oliphaunt-query:format-check` | Check formatting without changing files. |
+| `moon run oliphaunt-query:lint` | Clippy diagnostics for all targets; no database execution. |
+| `moon run oliphaunt-query:build` | Compile this project and its Cargo dependencies. |
+| `moon run oliphaunt-query:test` | Run source tests; Cargo compiles the required test targets. |
+| `moon run oliphaunt-query:package` | Stage distributable source crates under target/sdk-artifacts/oliphaunt-query; repeated runs replace this owner’s candidates. |
+
+Native Cargo entry points remain available: `cargo build -p oliphaunt-query --locked`, `cargo test -p oliphaunt-query --locked`, `cargo clippy -p oliphaunt-query --all-targets --locked -- -D warnings`, and `cargo fmt -p oliphaunt-query --check`. Moon supplies the additional source-test feature matrix and artifact staging where defined. `package` assembles bytes; it does not run the project test suite.
+
+The native SDK’s `moon run oliphaunt-rust:test-consumer` installs the real packed query, bindings and broker crates together with the SDK. This tests their public dependency closure without duplicate per-crate consumer harnesses.
diff --git a/src/sdks/rust-query/THIRD_PARTY_NOTICES.md b/src/sdks/rust-query/THIRD_PARTY_NOTICES.md
new file mode 120000
index 000000000..a21e98eb3
--- /dev/null
+++ b/src/sdks/rust-query/THIRD_PARTY_NOTICES.md
@@ -0,0 +1 @@
+../../../THIRD_PARTY_NOTICES.md
\ No newline at end of file
diff --git a/src/sdks/rust-query/moon.yml b/src/sdks/rust-query/moon.yml
new file mode 100644
index 000000000..15bc0b5f0
--- /dev/null
+++ b/src/sdks/rust-query/moon.yml
@@ -0,0 +1,62 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+id: "oliphaunt-query"
+language: "rust"
+layer: "library"
+stack: "systems"
+tags: ["cargo-package", "shared", "rust", "sdk", "release-product"]
+project:
+  title: "Rust query"
+  description: "PostgreSQL query encoding, decoding and shared types."
+  owner: "oliphaunt"
+  release:
+    component: "oliphaunt-query"
+    packagePath: "src/sdks/rust-query"
+fileGroups:
+  sources: ["src/**/*", "Cargo.toml"]
+tasks:
+  format:
+    command: "cargo fmt"
+    options:
+      cache: false
+      runInCI: false
+
+  format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt --check"
+    inputs: ["@group(sources)"]
+  lint:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy --all-targets --locked -- -D warnings"
+    inputs: ["@group(sources)", "/Cargo.lock", "/Cargo.toml"]
+  build:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["build", "requires-rust"]
+    command: "cargo build --locked"
+    outputs: ["/target/debug/liboliphaunt_query.rlib"]
+    inputs: ["@group(sources)", "/Cargo.lock", "/Cargo.toml"]
+  test:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "unit", "requires-rust"]
+    command: "cargo test --locked"
+    inputs: ["@group(sources)", "/Cargo.lock", "/Cargo.toml"]
+
+  package:
+    tags: ["release", "artifact-package", "ci-rust-sdk-package"]
+    script: |
+      set -eu
+      version="$(bun ../../../tools/release/product-version.mts version oliphaunt-query)"
+      rm -f "../../../target/package/oliphaunt-query-$version.crate"
+      cargo package --locked --allow-dirty --no-verify
+      rm -rf ../../../target/sdk-artifacts/oliphaunt-query
+      mkdir -p ../../../target/sdk-artifacts/oliphaunt-query
+      cp "../../../target/package/oliphaunt-query-$version.crate" ../../../target/sdk-artifacts/oliphaunt-query/
+      bun ../../../tools/packaging/staging.mts ../../../target/sdk-artifacts/oliphaunt-query
+    inputs: ["**/*", "/Cargo.lock", "/Cargo.toml", "/LICENSE", "/THIRD_PARTY_NOTICES.md"]
+    outputs: ["/target/sdk-artifacts/oliphaunt-query/**/*"]
diff --git a/src/sdks/rust-query/release.toml b/src/sdks/rust-query/release.toml
new file mode 100644
index 000000000..5fb0c3f40
--- /dev/null
+++ b/src/sdks/rust-query/release.toml
@@ -0,0 +1,6 @@
+id = "oliphaunt-query"
+owner = "@oliphaunt/core"
+kind = "sdk"
+publish_targets = ["crates-io"]
+registry_packages = ["crates:oliphaunt-query"]
+release_artifacts = ["cargo-crate"]
diff --git a/src/sdks/rust-query/src/lib.rs b/src/sdks/rust-query/src/lib.rs
new file mode 100644
index 000000000..c301b1abf
--- /dev/null
+++ b/src/sdks/rust-query/src/lib.rs
@@ -0,0 +1,3695 @@
+// Runtime-neutral PostgreSQL query protocol core shared by the Rust SDKs.
+//
+// This module deliberately has no dependencies outside `std`. It owns the
+// public query data model and diagnostics re-exported by both Rust facades;
+// runtime-specific request transport and outer error mapping stay at the
+// facade boundary.
+
+use std::sync::Arc;
+use std::{fmt, str};
+
+/// PostgreSQL object identifier used for parameter and result types.
+#[repr(transparent)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct TypeOid(u32);
+
+impl TypeOid {
+    /// PostgreSQL bool.
+    pub const BOOL: Self = Self(16);
+    /// PostgreSQL bytea.
+    pub const BYTEA: Self = Self(17);
+    /// PostgreSQL internal single-byte char.
+    pub const CHAR: Self = Self(18);
+    /// PostgreSQL name.
+    pub const NAME: Self = Self(19);
+    /// PostgreSQL int8.
+    pub const INT8: Self = Self(20);
+    /// PostgreSQL int2.
+    pub const INT2: Self = Self(21);
+    /// PostgreSQL int4.
+    pub const INT4: Self = Self(23);
+    /// PostgreSQL text.
+    pub const TEXT: Self = Self(25);
+    /// PostgreSQL oid.
+    pub const OID: Self = Self(26);
+    /// PostgreSQL json.
+    pub const JSON: Self = Self(114);
+    /// PostgreSQL xml.
+    pub const XML: Self = Self(142);
+    /// PostgreSQL xml array.
+    pub const XML_ARRAY: Self = Self(143);
+    /// PostgreSQL json array.
+    pub const JSON_ARRAY: Self = Self(199);
+    /// PostgreSQL float4.
+    pub const FLOAT4: Self = Self(700);
+    /// PostgreSQL float8.
+    pub const FLOAT8: Self = Self(701);
+    /// PostgreSQL pseudo-type unknown.
+    pub const UNKNOWN: Self = Self(705);
+    /// PostgreSQL bool array.
+    pub const BOOL_ARRAY: Self = Self(1000);
+    /// PostgreSQL bytea array.
+    pub const BYTEA_ARRAY: Self = Self(1001);
+    /// PostgreSQL internal single-byte char array.
+    pub const CHAR_ARRAY: Self = Self(1002);
+    /// PostgreSQL name array.
+    pub const NAME_ARRAY: Self = Self(1003);
+    /// PostgreSQL int2 array.
+    pub const INT2_ARRAY: Self = Self(1005);
+    /// PostgreSQL int4 array.
+    pub const INT4_ARRAY: Self = Self(1007);
+    /// PostgreSQL text array.
+    pub const TEXT_ARRAY: Self = Self(1009);
+    /// PostgreSQL bpchar array.
+    pub const BPCHAR_ARRAY: Self = Self(1014);
+    /// PostgreSQL varchar array.
+    pub const VARCHAR_ARRAY: Self = Self(1015);
+    /// PostgreSQL int8 array.
+    pub const INT8_ARRAY: Self = Self(1016);
+    /// PostgreSQL float4 array.
+    pub const FLOAT4_ARRAY: Self = Self(1021);
+    /// PostgreSQL float8 array.
+    pub const FLOAT8_ARRAY: Self = Self(1022);
+    /// PostgreSQL oid array.
+    pub const OID_ARRAY: Self = Self(1028);
+    /// PostgreSQL bpchar.
+    pub const BPCHAR: Self = Self(1042);
+    /// PostgreSQL varchar.
+    pub const VARCHAR: Self = Self(1043);
+    /// PostgreSQL date.
+    pub const DATE: Self = Self(1082);
+    /// PostgreSQL time without time zone.
+    pub const TIME: Self = Self(1083);
+    /// PostgreSQL timestamp without time zone.
+    pub const TIMESTAMP: Self = Self(1114);
+    /// PostgreSQL timestamp array.
+    pub const TIMESTAMP_ARRAY: Self = Self(1115);
+    /// PostgreSQL date array.
+    pub const DATE_ARRAY: Self = Self(1182);
+    /// PostgreSQL time array.
+    pub const TIME_ARRAY: Self = Self(1183);
+    /// PostgreSQL timestamp with time zone.
+    pub const TIMESTAMPTZ: Self = Self(1184);
+    /// PostgreSQL timestamptz array.
+    pub const TIMESTAMPTZ_ARRAY: Self = Self(1185);
+    /// PostgreSQL interval.
+    pub const INTERVAL: Self = Self(1186);
+    /// PostgreSQL interval array.
+    pub const INTERVAL_ARRAY: Self = Self(1187);
+    /// PostgreSQL numeric array.
+    pub const NUMERIC_ARRAY: Self = Self(1231);
+    /// PostgreSQL time with time zone.
+    pub const TIMETZ: Self = Self(1266);
+    /// PostgreSQL timetz array.
+    pub const TIMETZ_ARRAY: Self = Self(1270);
+    /// PostgreSQL numeric.
+    pub const NUMERIC: Self = Self(1700);
+    /// PostgreSQL uuid.
+    pub const UUID: Self = Self(2950);
+    /// PostgreSQL uuid array.
+    pub const UUID_ARRAY: Self = Self(2951);
+    /// PostgreSQL jsonb.
+    pub const JSONB: Self = Self(3802);
+    /// PostgreSQL jsonb array.
+    pub const JSONB_ARRAY: Self = Self(3807);
+
+    /// Construct an OID, including an extension or application-defined type OID.
+    pub const fn new(oid: u32) -> Self {
+        Self(oid)
+    }
+
+    /// Return the numeric PostgreSQL OID.
+    pub const fn get(self) -> u32 {
+        self.0
+    }
+}
+
+impl From for TypeOid {
+    fn from(value: u32) -> Self {
+        Self::new(value)
+    }
+}
+
+impl From for u32 {
+    fn from(value: TypeOid) -> Self {
+        value.get()
+    }
+}
+
+/// PostgreSQL text or binary value format.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ValueFormat {
+    /// PostgreSQL text representation.
+    Text,
+    /// PostgreSQL binary representation.
+    Binary,
+}
+
+impl ValueFormat {
+    pub fn code(self) -> i16 {
+        match self {
+            Self::Text => 0,
+            Self::Binary => 1,
+        }
+    }
+}
+
+/// Owned, optionally typed PostgreSQL bind parameter.
+///
+/// An absent type OID asks PostgreSQL to infer the parameter type. A None
+/// value is SQL NULL; it is independent of the parameter format and type hint.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Parameter {
+    type_oid: Option,
+    format: ValueFormat,
+    value: Option>,
+}
+
+impl Parameter {
+    /// Construct an untyped SQL NULL whose type PostgreSQL will infer.
+    pub fn null() -> Self {
+        Self {
+            type_oid: None,
+            format: ValueFormat::Text,
+            value: None,
+        }
+    }
+
+    /// Construct an untyped text-format value.
+    pub fn text(value: impl Into) -> Self {
+        Self {
+            type_oid: None,
+            format: ValueFormat::Text,
+            value: Some(value.into().into_bytes()),
+        }
+    }
+
+    /// Construct an untyped binary-format value.
+    pub fn binary(value: impl Into>) -> Self {
+        Self {
+            type_oid: None,
+            format: ValueFormat::Binary,
+            value: Some(value.into()),
+        }
+    }
+
+    /// Attach an explicit PostgreSQL type OID.
+    ///
+    /// OID 0 is PostgreSQL's inference sentinel. It is accepted when describing
+    /// a statement, but execution rejects an explicitly attached zero; leave
+    /// the OID unset to request execution-time inference.
+    pub fn with_type_oid(mut self, type_oid: TypeOid) -> Self {
+        self.type_oid = Some(type_oid);
+        self
+    }
+
+    /// Construct a typed SQL NULL.
+    pub fn typed_null(type_oid: TypeOid) -> Self {
+        Self::null().with_type_oid(type_oid)
+    }
+
+    /// Construct a typed text-format value.
+    pub fn typed_text(type_oid: TypeOid, value: impl Into) -> Self {
+        Self::text(value).with_type_oid(type_oid)
+    }
+
+    /// Construct a typed binary-format value.
+    pub fn typed_binary(type_oid: TypeOid, value: impl Into>) -> Self {
+        Self::binary(value).with_type_oid(type_oid)
+    }
+
+    /// Return the declared PostgreSQL type, or None for server inference.
+    pub fn type_oid(&self) -> Option {
+        self.type_oid
+    }
+
+    /// Return the frontend parameter format.
+    pub fn format(&self) -> ValueFormat {
+        self.format
+    }
+
+    /// Return the encoded bytes, or None for SQL NULL.
+    pub fn value(&self) -> Option<&[u8]> {
+        self.value.as_deref()
+    }
+}
+
+/// Conversion into an owned, typed PostgreSQL bind parameter.
+pub trait IntoParameter: Sized {
+    /// Type OID retained when `Option` is bound as SQL NULL.
+    const TYPE_OID: Option;
+
+    /// Encode this value as one PostgreSQL parameter.
+    fn into_parameter(self) -> Parameter;
+}
+
+impl IntoParameter for Parameter {
+    const TYPE_OID: Option = None;
+
+    fn into_parameter(self) -> Parameter {
+        self
+    }
+}
+
+impl IntoParameter for &str {
+    const TYPE_OID: Option = Some(TypeOid::TEXT);
+
+    fn into_parameter(self) -> Parameter {
+        Parameter::typed_text(TypeOid::TEXT, self)
+    }
+}
+
+impl IntoParameter for String {
+    const TYPE_OID: Option = Some(TypeOid::TEXT);
+
+    fn into_parameter(self) -> Parameter {
+        Parameter::typed_text(TypeOid::TEXT, self)
+    }
+}
+
+impl IntoParameter for &String {
+    const TYPE_OID: Option = Some(TypeOid::TEXT);
+
+    fn into_parameter(self) -> Parameter {
+        Parameter::typed_text(TypeOid::TEXT, self)
+    }
+}
+
+macro_rules! binary_parameter {
+    ($type:ty, $oid:expr, $encode:expr) => {
+        impl IntoParameter for $type {
+            const TYPE_OID: Option = Some($oid);
+
+            fn into_parameter(self) -> Parameter {
+                Parameter::typed_binary($oid, $encode(self))
+            }
+        }
+    };
+}
+
+binary_parameter!(i16, TypeOid::INT2, i16::to_be_bytes);
+binary_parameter!(i32, TypeOid::INT4, i32::to_be_bytes);
+binary_parameter!(i64, TypeOid::INT8, i64::to_be_bytes);
+binary_parameter!(f32, TypeOid::FLOAT4, |value: f32| value
+    .to_bits()
+    .to_be_bytes());
+binary_parameter!(f64, TypeOid::FLOAT8, |value: f64| value
+    .to_bits()
+    .to_be_bytes());
+
+impl IntoParameter for bool {
+    const TYPE_OID: Option = Some(TypeOid::BOOL);
+
+    fn into_parameter(self) -> Parameter {
+        Parameter::typed_binary(TypeOid::BOOL, [u8::from(self)])
+    }
+}
+
+impl IntoParameter for &[u8] {
+    const TYPE_OID: Option = Some(TypeOid::BYTEA);
+
+    fn into_parameter(self) -> Parameter {
+        Parameter::typed_binary(TypeOid::BYTEA, self)
+    }
+}
+
+impl IntoParameter for Vec {
+    const TYPE_OID: Option = Some(TypeOid::BYTEA);
+
+    fn into_parameter(self) -> Parameter {
+        Parameter::typed_binary(TypeOid::BYTEA, self)
+    }
+}
+
+impl IntoParameter for Option
+where
+    T: IntoParameter,
+{
+    const TYPE_OID: Option = T::TYPE_OID;
+
+    fn into_parameter(self) -> Parameter {
+        self.map(IntoParameter::into_parameter)
+            .unwrap_or_else(|| match Self::TYPE_OID {
+                Some(type_oid) => Parameter::typed_null(type_oid),
+                None => Parameter::null(),
+            })
+    }
+}
+
+/// Metadata for one PostgreSQL result column.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct QueryField {
+    /// Column name.
+    pub name: String,
+    /// Table OID reported by PostgreSQL, or 0 when not tied to a table.
+    pub table_oid: u32,
+    /// Table attribute number reported by PostgreSQL.
+    pub table_attribute: i16,
+    /// PostgreSQL type OID.
+    pub type_oid: u32,
+    /// PostgreSQL type size.
+    pub type_size: i16,
+    /// PostgreSQL type modifier.
+    pub type_modifier: i32,
+    /// Format used for values in this column.
+    pub format: QueryFormat,
+}
+
+impl QueryField {
+    /// PostgreSQL type OID as the typed API value.
+    pub fn type_oid_value(&self) -> TypeOid {
+        TypeOid::new(self.type_oid)
+    }
+}
+
+/// PostgreSQL result-column value format.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum QueryFormat {
+    /// Text format.
+    Text,
+    /// Binary format.
+    Binary,
+    /// Unknown or extension format code.
+    Other(i16),
+}
+
+impl QueryFormat {
+    fn value_format(self) -> Option {
+        match self {
+            Self::Text => Some(ValueFormat::Text),
+            Self::Binary => Some(ValueFormat::Binary),
+            Self::Other(_) => None,
+        }
+    }
+}
+
+impl From for QueryFormat {
+    fn from(value: i16) -> Self {
+        match value {
+            0 => Self::Text,
+            1 => Self::Binary,
+            other => Self::Other(other),
+        }
+    }
+}
+
+/// Fallible row-column index accepted by row decoding APIs.
+pub trait RowIndex {
+    /// Resolve this index against result field metadata.
+    fn resolve(&self, fields: &[QueryField]) -> std::result::Result;
+}
+
+impl RowIndex for usize {
+    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
+        if *self < fields.len() {
+            Ok(*self)
+        } else {
+            Err(DecodeError::ColumnOutOfBounds {
+                index: *self,
+                len: fields.len(),
+            })
+        }
+    }
+}
+
+impl RowIndex for str {
+    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
+        let mut matches = fields
+            .iter()
+            .enumerate()
+            .filter_map(|(index, field)| (field.name == self).then_some(index));
+        let first = matches
+            .next()
+            .ok_or_else(|| DecodeError::ColumnNotFound(self.to_owned()))?;
+        if matches.next().is_some() {
+            Err(DecodeError::AmbiguousColumn(self.to_owned()))
+        } else {
+            Ok(first)
+        }
+    }
+}
+
+impl RowIndex for &str {
+    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
+        ::resolve(self, fields)
+    }
+}
+
+impl RowIndex for String {
+    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
+        ::resolve(self.as_str(), fields)
+    }
+}
+
+impl RowIndex for &String {
+    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
+        ::resolve(self.as_str(), fields)
+    }
+}
+
+/// Borrowed PostgreSQL value with its column metadata.
+#[derive(Debug, Clone, Copy)]
+pub struct ValueRef<'a> {
+    column: usize,
+    field: &'a QueryField,
+    value: Option<&'a [u8]>,
+}
+
+impl<'a> ValueRef<'a> {
+    pub fn new(column: usize, field: &'a QueryField, value: Option<&'a [u8]>) -> Self {
+        Self {
+            column,
+            field,
+            value,
+        }
+    }
+
+    /// Zero-based column position.
+    pub fn column(&self) -> usize {
+        self.column
+    }
+
+    /// Column metadata.
+    pub fn field(&self) -> &'a QueryField {
+        self.field
+    }
+
+    /// PostgreSQL type OID.
+    pub fn type_oid(&self) -> TypeOid {
+        TypeOid::new(self.field.type_oid)
+    }
+
+    /// PostgreSQL result format, when recognized.
+    pub fn format(&self) -> Option {
+        self.field.format.value_format()
+    }
+
+    /// Whether this value is SQL NULL.
+    pub fn is_null(&self) -> bool {
+        self.value.is_none()
+    }
+
+    /// Borrow encoded value bytes, or None for SQL NULL.
+    pub fn as_bytes(&self) -> Option<&'a [u8]> {
+        self.value
+    }
+
+    fn require_bytes(self, target: &'static str) -> std::result::Result<&'a [u8], DecodeError> {
+        self.value.ok_or(DecodeError::UnexpectedNull {
+            column: self.column,
+            target,
+        })
+    }
+}
+
+/// Decode one PostgreSQL value into a Rust type.
+pub trait FromSql<'a>: Sized {
+    /// Validate column metadata before decoding, including for SQL NULL.
+    ///
+    /// Custom decoders may leave the default when they accept arbitrary
+    /// PostgreSQL types. Built-in decoders use this hook so `Option` does
+    /// not silently accept a null value of the wrong database type.
+    fn check_type(_value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
+        Ok(())
+    }
+
+    /// Decode a possibly-null text or binary value.
+    fn from_sql(value: ValueRef<'a>) -> std::result::Result;
+}
+
+/// Error produced while locating or decoding a row value.
+#[non_exhaustive]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum DecodeError {
+    /// No result column had the requested name.
+    ColumnNotFound(String),
+    /// More than one result column had the requested name.
+    AmbiguousColumn(String),
+    /// A positional index exceeded the row width.
+    ColumnOutOfBounds {
+        /// Requested index.
+        index: usize,
+        /// Number of result columns.
+        len: usize,
+    },
+    /// SQL NULL cannot be decoded into the requested non-optional type.
+    UnexpectedNull {
+        /// Column index.
+        column: usize,
+        /// Requested Rust target.
+        target: &'static str,
+    },
+    /// PostgreSQL returned a type incompatible with the requested Rust target.
+    TypeMismatch {
+        /// Column index.
+        column: usize,
+        /// Actual PostgreSQL type OID.
+        type_oid: TypeOid,
+        /// Requested Rust target.
+        target: &'static str,
+    },
+    /// PostgreSQL returned an unsupported value format.
+    UnsupportedFormat {
+        /// Column index.
+        column: usize,
+        /// Raw PostgreSQL format code.
+        format: i16,
+    },
+    /// Encoded bytes were not a valid value for the requested Rust target.
+    InvalidValue {
+        /// Column index.
+        column: usize,
+        /// Requested Rust target.
+        target: &'static str,
+        /// Decoder detail.
+        message: String,
+    },
+}
+
+impl fmt::Display for DecodeError {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::ColumnNotFound(name) => {
+                write!(formatter, "query result has no column named {name:?}")
+            }
+            Self::AmbiguousColumn(name) => write!(
+                formatter,
+                "query result has more than one column named {name:?}; use a positional index"
+            ),
+            Self::ColumnOutOfBounds { index, len } => write!(
+                formatter,
+                "query row has no column at index {index}; row has {len} columns"
+            ),
+            Self::UnexpectedNull { column, target } => {
+                write!(
+                    formatter,
+                    "column {column} is NULL and cannot decode as {target}"
+                )
+            }
+            Self::TypeMismatch {
+                column,
+                type_oid,
+                target,
+            } => write!(
+                formatter,
+                "column {column} has PostgreSQL type OID {} and cannot decode as {target}",
+                type_oid.get()
+            ),
+            Self::UnsupportedFormat { column, format } => write!(
+                formatter,
+                "column {column} uses unsupported PostgreSQL format code {format}"
+            ),
+            Self::InvalidValue {
+                column,
+                target,
+                message,
+            } => write!(
+                formatter,
+                "column {column} could not decode as {target}: {message}"
+            ),
+        }
+    }
+}
+
+impl std::error::Error for DecodeError {}
+
+impl<'a> FromSql<'a> for &'a str {
+    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
+        require_text_compatible(value, "&str")
+    }
+
+    fn from_sql(value: ValueRef<'a>) -> std::result::Result {
+        Self::check_type(value)?;
+        let raw = value.require_bytes("&str")?;
+        str::from_utf8(raw).map_err(|error| DecodeError::InvalidValue {
+            column: value.column,
+            target: "&str",
+            message: error.to_string(),
+        })
+    }
+}
+
+impl FromSql<'_> for String {
+    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
+        <&str as FromSql>::check_type(value)
+    }
+
+    fn from_sql(value: ValueRef<'_>) -> std::result::Result {
+        <&str as FromSql>::from_sql(value).map(str::to_owned)
+    }
+}
+
+impl<'a> FromSql<'a> for &'a [u8] {
+    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
+        require_type(value, TypeOid::BYTEA, "&[u8]")?;
+        if value.format() == Some(ValueFormat::Binary) {
+            Ok(())
+        } else {
+            invalid_value(
+                value,
+                "&[u8]",
+                "borrowed bytea requires binary result format; use Vec for text bytea",
+            )
+        }
+    }
+
+    fn from_sql(value: ValueRef<'a>) -> std::result::Result {
+        Self::check_type(value)?;
+        value.require_bytes("&[u8]")
+    }
+}
+
+impl FromSql<'_> for Vec {
+    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
+        require_type(value, TypeOid::BYTEA, "Vec")
+    }
+
+    fn from_sql(value: ValueRef<'_>) -> std::result::Result {
+        Self::check_type(value)?;
+        let raw = value.require_bytes("Vec")?;
+        match value.format() {
+            Some(ValueFormat::Binary) => Ok(raw.to_vec()),
+            Some(ValueFormat::Text) => decode_text_bytea(value, raw),
+            None => unsupported_format(value),
+        }
+    }
+}
+
+impl FromSql<'_> for bool {
+    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
+        require_type(value, TypeOid::BOOL, "bool")
+    }
+
+    fn from_sql(value: ValueRef<'_>) -> std::result::Result {
+        Self::check_type(value)?;
+        let raw = value.require_bytes("bool")?;
+        match value.format() {
+            Some(ValueFormat::Text) => match raw {
+                b"t" | b"true" => Ok(true),
+                b"f" | b"false" => Ok(false),
+                _ => invalid_value(value, "bool", "expected t or f"),
+            },
+            Some(ValueFormat::Binary) => match raw {
+                [0] => Ok(false),
+                [1] => Ok(true),
+                _ => invalid_value(value, "bool", "expected one binary byte containing 0 or 1"),
+            },
+            None => unsupported_format(value),
+        }
+    }
+}
+
+macro_rules! integer_from_sql {
+    ($type:ty, $oid:expr, $width:literal) => {
+        impl FromSql<'_> for $type {
+            fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
+                require_type(value, $oid, stringify!($type))
+            }
+
+            fn from_sql(value: ValueRef<'_>) -> std::result::Result {
+                Self::check_type(value)?;
+                let raw = value.require_bytes(stringify!($type))?;
+                match value.format() {
+                    Some(ValueFormat::Text) => {
+                        let text =
+                            str::from_utf8(raw).map_err(|error| DecodeError::InvalidValue {
+                                column: value.column,
+                                target: stringify!($type),
+                                message: error.to_string(),
+                            })?;
+                        text.parse::<$type>()
+                            .map_err(|error| DecodeError::InvalidValue {
+                                column: value.column,
+                                target: stringify!($type),
+                                message: error.to_string(),
+                            })
+                    }
+                    Some(ValueFormat::Binary) => {
+                        let bytes: [u8; $width] =
+                            raw.try_into().map_err(|_| DecodeError::InvalidValue {
+                                column: value.column,
+                                target: stringify!($type),
+                                message: format!(
+                                    "expected {} binary bytes, got {}",
+                                    $width,
+                                    raw.len()
+                                ),
+                            })?;
+                        Ok(<$type>::from_be_bytes(bytes))
+                    }
+                    None => unsupported_format(value),
+                }
+            }
+        }
+    };
+}
+
+integer_from_sql!(i16, TypeOid::INT2, 2);
+integer_from_sql!(i32, TypeOid::INT4, 4);
+integer_from_sql!(i64, TypeOid::INT8, 8);
+
+macro_rules! float_from_sql {
+    ($type:ty, $bits:ty, $oid:expr, $width:literal) => {
+        impl FromSql<'_> for $type {
+            fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
+                require_type(value, $oid, stringify!($type))
+            }
+
+            fn from_sql(value: ValueRef<'_>) -> std::result::Result {
+                Self::check_type(value)?;
+                let raw = value.require_bytes(stringify!($type))?;
+                match value.format() {
+                    Some(ValueFormat::Text) => {
+                        let text =
+                            str::from_utf8(raw).map_err(|error| DecodeError::InvalidValue {
+                                column: value.column,
+                                target: stringify!($type),
+                                message: error.to_string(),
+                            })?;
+                        text.parse::<$type>()
+                            .map_err(|error| DecodeError::InvalidValue {
+                                column: value.column,
+                                target: stringify!($type),
+                                message: error.to_string(),
+                            })
+                    }
+                    Some(ValueFormat::Binary) => {
+                        let bytes: [u8; $width] =
+                            raw.try_into().map_err(|_| DecodeError::InvalidValue {
+                                column: value.column,
+                                target: stringify!($type),
+                                message: format!(
+                                    "expected {} binary bytes, got {}",
+                                    $width,
+                                    raw.len()
+                                ),
+                            })?;
+                        Ok(<$type>::from_bits(<$bits>::from_be_bytes(bytes)))
+                    }
+                    None => unsupported_format(value),
+                }
+            }
+        }
+    };
+}
+
+float_from_sql!(f32, u32, TypeOid::FLOAT4, 4);
+float_from_sql!(f64, u64, TypeOid::FLOAT8, 8);
+
+impl<'a, T> FromSql<'a> for Option
+where
+    T: FromSql<'a>,
+{
+    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
+        T::check_type(value)
+    }
+
+    fn from_sql(value: ValueRef<'a>) -> std::result::Result {
+        T::check_type(value)?;
+        if value.is_null() {
+            Ok(None)
+        } else {
+            T::from_sql(value).map(Some)
+        }
+    }
+}
+
+fn require_type(
+    value: ValueRef<'_>,
+    expected: TypeOid,
+    target: &'static str,
+) -> std::result::Result<(), DecodeError> {
+    if value.type_oid() == expected {
+        Ok(())
+    } else {
+        Err(DecodeError::TypeMismatch {
+            column: value.column,
+            type_oid: value.type_oid(),
+            target,
+        })
+    }
+}
+
+fn require_text_compatible(
+    value: ValueRef<'_>,
+    target: &'static str,
+) -> std::result::Result<(), DecodeError> {
+    if value.format() != Some(ValueFormat::Text) {
+        return invalid_value(
+            value,
+            target,
+            "string decoding requires PostgreSQL text format",
+        );
+    }
+    let oid = value.type_oid();
+    if matches!(
+        oid,
+        TypeOid::CHAR
+            | TypeOid::NAME
+            | TypeOid::TEXT
+            | TypeOid::UNKNOWN
+            | TypeOid::BPCHAR
+            | TypeOid::VARCHAR
+            | TypeOid::JSON
+            | TypeOid::JSONB
+            | TypeOid::XML
+            | TypeOid::NUMERIC
+            | TypeOid::DATE
+            | TypeOid::TIME
+            | TypeOid::TIMETZ
+            | TypeOid::TIMESTAMP
+            | TypeOid::TIMESTAMPTZ
+            | TypeOid::INTERVAL
+            | TypeOid::UUID
+    ) || oid.get() >= 16_384
+    {
+        Ok(())
+    } else {
+        Err(DecodeError::TypeMismatch {
+            column: value.column,
+            type_oid: oid,
+            target,
+        })
+    }
+}
+
+fn decode_text_bytea(value: ValueRef<'_>, raw: &[u8]) -> std::result::Result, DecodeError> {
+    if let Some(hex) = raw.strip_prefix(b"\\x") {
+        if hex.len() % 2 != 0 {
+            return invalid_value(value, "Vec", "hex bytea has odd length");
+        }
+        return hex
+            .chunks_exact(2)
+            .map(|pair| {
+                let digit = |byte: u8| match byte {
+                    b'0'..=b'9' => Some(byte - b'0'),
+                    b'a'..=b'f' => Some(byte - b'a' + 10),
+                    b'A'..=b'F' => Some(byte - b'A' + 10),
+                    _ => None,
+                };
+                let high = digit(pair[0]).ok_or_else(|| DecodeError::InvalidValue {
+                    column: value.column,
+                    target: "Vec",
+                    message: "hex bytea contains a non-hex digit".to_owned(),
+                })?;
+                let low = digit(pair[1]).ok_or_else(|| DecodeError::InvalidValue {
+                    column: value.column,
+                    target: "Vec",
+                    message: "hex bytea contains a non-hex digit".to_owned(),
+                })?;
+                Ok((high << 4) | low)
+            })
+            .collect();
+    }
+
+    let mut decoded = Vec::with_capacity(raw.len());
+    let mut index = 0;
+    while index < raw.len() {
+        if raw[index] != b'\\' {
+            decoded.push(raw[index]);
+            index += 1;
+            continue;
+        }
+        match raw.get(index + 1..) {
+            Some([b'\\', ..]) => {
+                decoded.push(b'\\');
+                index += 2;
+            }
+            Some([a @ b'0'..=b'3', b @ b'0'..=b'7', c @ b'0'..=b'7', ..]) => {
+                decoded.push((a - b'0') * 64 + (b - b'0') * 8 + (c - b'0'));
+                index += 4;
+            }
+            _ => return invalid_value(value, "Vec", "invalid escaped bytea sequence"),
+        }
+    }
+    Ok(decoded)
+}
+
+fn invalid_value(
+    value: ValueRef<'_>,
+    target: &'static str,
+    message: impl Into,
+) -> std::result::Result {
+    Err(DecodeError::InvalidValue {
+        column: value.column,
+        target,
+        message: message.into(),
+    })
+}
+
+fn unsupported_format(value: ValueRef<'_>) -> std::result::Result {
+    let QueryFormat::Other(format) = value.field.format else {
+        unreachable!("known formats are handled before unsupported_format")
+    };
+    Err(DecodeError::UnsupportedFormat {
+        column: value.column,
+        format,
+    })
+}
+
+/// One raw field from a PostgreSQL ErrorResponse.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct PostgresErrorField {
+    /// Single-byte PostgreSQL field code.
+    pub code: u8,
+    /// Field value decoded as UTF-8.
+    pub value: String,
+}
+
+/// Structured PostgreSQL NoticeResponse diagnostic.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct PostgresNotice {
+    /// Backend severity, such as NOTICE or WARNING.
+    pub severity: Option,
+    /// Localized severity reported in PostgreSQL field S.
+    pub localized_severity: Option,
+    /// Locale-independent severity reported in PostgreSQL field V.
+    pub nonlocalized_severity: Option,
+    /// SQLSTATE code when PostgreSQL supplied one.
+    pub sqlstate: Option,
+    /// Primary human-readable notice message.
+    pub message: String,
+    /// Optional detailed explanation.
+    pub detail: Option,
+    /// Optional hint.
+    pub hint: Option,
+    /// Optional source statement position.
+    pub position: Option,
+    /// Optional position within an internally generated query.
+    pub internal_position: Option,
+    /// Optional text of an internally generated query.
+    pub internal_query: Option,
+    /// Optional context stack.
+    pub where_: Option,
+    /// Optional schema name.
+    pub schema_name: Option,
+    /// Optional table name.
+    pub table_name: Option,
+    /// Optional column name.
+    pub column_name: Option,
+    /// Optional data type name.
+    pub data_type_name: Option,
+    /// Optional constraint name.
+    pub constraint_name: Option,
+    /// PostgreSQL source file that emitted the diagnostic.
+    pub file: Option,
+    /// PostgreSQL source line that emitted the diagnostic.
+    pub line: Option,
+    /// PostgreSQL source routine that emitted the diagnostic.
+    pub routine: Option,
+    /// Raw diagnostic fields in backend order.
+    pub fields: Vec,
+}
+
+/// Structured PostgreSQL ErrorResponse decoded from backend protocol bytes.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct PostgresError {
+    /// Backend severity, such as ERROR or FATAL.
+    pub severity: Option,
+    /// Localized severity reported in PostgreSQL field S.
+    pub localized_severity: Option,
+    /// Locale-independent severity reported in PostgreSQL field V.
+    pub nonlocalized_severity: Option,
+    /// SQLSTATE code, such as 23505 for unique violations.
+    pub sqlstate: Option,
+    /// Primary human-readable PostgreSQL error message.
+    pub message: String,
+    /// Optional detailed explanation from PostgreSQL.
+    pub detail: Option,
+    /// Optional hint from PostgreSQL.
+    pub hint: Option,
+    /// Optional source statement position.
+    pub position: Option,
+    /// Optional position within an internally generated query.
+    pub internal_position: Option,
+    /// Optional text of an internally generated query.
+    pub internal_query: Option,
+    /// Optional context stack, exposed as where by PostgreSQL.
+    pub where_: Option,
+    /// Optional schema name reported by PostgreSQL.
+    pub schema_name: Option,
+    /// Optional table name reported by PostgreSQL.
+    pub table_name: Option,
+    /// Optional column name reported by PostgreSQL.
+    pub column_name: Option,
+    /// Optional data type name reported by PostgreSQL.
+    pub data_type_name: Option,
+    /// Optional constraint name reported by PostgreSQL.
+    pub constraint_name: Option,
+    /// PostgreSQL source file that emitted the diagnostic.
+    pub file: Option,
+    /// PostgreSQL source line that emitted the diagnostic.
+    pub line: Option,
+    /// PostgreSQL source routine that emitted the diagnostic.
+    pub routine: Option,
+    /// Raw ErrorResponse fields in backend order.
+    pub fields: Vec,
+    /// Notices emitted earlier in the same structured operation.
+    pub notices: Vec,
+}
+
+impl fmt::Display for PostgresError {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match (&self.severity, &self.sqlstate) {
+            (Some(severity), Some(sqlstate)) => {
+                write!(formatter, "{severity} [{sqlstate}]: {}", self.message)
+            }
+            (Some(severity), None) => write!(formatter, "{severity}: {}", self.message),
+            (None, Some(sqlstate)) => write!(formatter, "[{sqlstate}]: {}", self.message),
+            (None, None) => formatter.write_str(&self.message),
+        }
+    }
+}
+
+impl std::error::Error for PostgresError {}
+
+/// One PostgreSQL query row.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct QueryRow {
+    fields: Arc<[QueryField]>,
+    values: Vec>>,
+}
+
+impl QueryRow {
+    /// Read nullable UTF-8 bytes by column index.
+    pub fn text(&self, column: usize) -> Result> {
+        let value = self
+            .values
+            .get(column)
+            .ok_or_else(|| protocol(format!("query row has no column at index {column}")))?;
+        value
+            .as_deref()
+            .map(|bytes| {
+                str::from_utf8(bytes)
+                    .map_err(|error| protocol(format!("query value is not valid UTF-8: {error}")))
+            })
+            .transpose()
+    }
+
+    fn new(fields: Arc<[QueryField]>, values: Vec>>) -> Self {
+        Self { fields, values }
+    }
+
+    /// Field metadata in column order.
+    pub fn fields(&self) -> &[QueryField] {
+        &self.fields
+    }
+
+    /// Raw column values in result-column order.
+    pub fn values(&self) -> &[Option>] {
+        &self.values
+    }
+
+    /// Number of columns in the row.
+    pub fn len(&self) -> usize {
+        self.values.len()
+    }
+
+    /// Whether the row contains no columns.
+    pub fn is_empty(&self) -> bool {
+        self.values.is_empty()
+    }
+
+    /// Read nullable raw wire bytes by column index or name.
+    pub fn try_get_raw(&self, index: I) -> std::result::Result, DecodeError>
+    where
+        I: RowIndex,
+    {
+        let index = index.resolve(&self.fields)?;
+        Ok(self.values[index].as_deref())
+    }
+
+    /// Decode a value by column index or name.
+    pub fn try_get<'a, T, I>(&'a self, index: I) -> std::result::Result
+    where
+        T: FromSql<'a>,
+        I: RowIndex,
+    {
+        let index = index.resolve(&self.fields)?;
+        T::from_sql(ValueRef::new(
+            index,
+            &self.fields[index],
+            self.values[index].as_deref(),
+        ))
+    }
+}
+
+/// Result of a PostgreSQL command that does not expose rows.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct CommandResult {
+    command_tag: Option,
+    row_count: Option,
+    notices: Vec,
+    ready_status: ReadyStatus,
+}
+
+impl CommandResult {
+    /// PostgreSQL command tag returned by the command.
+    pub fn command_tag(&self) -> Option<&str> {
+        self.command_tag.as_deref()
+    }
+
+    /// Affected-row count encoded by PostgreSQL in the command tag.
+    pub fn row_count(&self) -> Option {
+        self.row_count
+    }
+
+    /// Notices emitted while PostgreSQL processed this command.
+    pub fn notices(&self) -> &[PostgresNotice] {
+        &self.notices
+    }
+
+    pub fn ready_status(&self) -> ReadyStatus {
+        self.ready_status
+    }
+}
+
+/// Result of one PostgreSQL row-producing execution.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct QueryResult {
+    fields: Arc<[QueryField]>,
+    rows: Vec,
+    command_tag: Option,
+    row_count: Option,
+    notices: Vec,
+    ready_status: ReadyStatus,
+}
+
+impl QueryResult {
+    /// Read a nullable UTF-8 value by row index and column name.
+    pub fn get_text(&self, row: usize, column: &str) -> Result> {
+        let column = column
+            .resolve(self.fields())
+            .map_err(|error| protocol(error.to_string()))?;
+        self.row(row)
+            .ok_or_else(|| protocol(format!("query result has no row at index {row}")))?
+            .text(column)
+    }
+
+    /// Field metadata in result-column order.
+    pub fn fields(&self) -> &[QueryField] {
+        &self.fields
+    }
+
+    /// Rows returned by the query.
+    pub fn rows(&self) -> &[QueryRow] {
+        &self.rows
+    }
+
+    /// PostgreSQL command tag returned by the query.
+    pub fn command_tag(&self) -> Option<&str> {
+        self.command_tag.as_deref()
+    }
+
+    /// Row count encoded by PostgreSQL in the command tag.
+    pub fn row_count(&self) -> Option {
+        self.row_count
+    }
+
+    /// Notices emitted while PostgreSQL processed this query.
+    pub fn notices(&self) -> &[PostgresNotice] {
+        &self.notices
+    }
+
+    pub fn ready_status(&self) -> ReadyStatus {
+        self.ready_status
+    }
+
+    pub fn row(&self, index: usize) -> Option<&QueryRow> {
+        self.rows.get(index)
+    }
+}
+
+/// Metadata returned by PostgreSQL for a parsed statement.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct StatementDescription {
+    parameter_types: Vec,
+    fields: Option>,
+    notices: Vec,
+    ready_status: ReadyStatus,
+}
+
+impl StatementDescription {
+    /// Server-resolved parameter type OIDs in placeholder order.
+    pub fn parameter_types(&self) -> &[TypeOid] {
+        &self.parameter_types
+    }
+
+    /// Result fields, or None when PostgreSQL returned NoData.
+    pub fn fields(&self) -> Option<&[QueryField]> {
+        self.fields.as_deref()
+    }
+
+    /// Notices emitted while PostgreSQL parsed and described the statement.
+    pub fn notices(&self) -> &[PostgresNotice] {
+        &self.notices
+    }
+
+    pub fn ready_status(&self) -> ReadyStatus {
+        self.ready_status
+    }
+}
+
+/// One ordered result from PostgreSQL simple-query execution.
+#[non_exhaustive]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum StatementResult {
+    /// A command that did not return rows.
+    Command(CommandResult),
+    /// A row-producing statement.
+    Rows(QueryResult),
+}
+
+/// Ordered results from PostgreSQL simple-query execution.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ExecResult {
+    statements: Vec,
+    notices: Vec,
+    ready_status: ReadyStatus,
+}
+
+impl ExecResult {
+    /// Results in source-statement order.
+    pub fn statements(&self) -> &[StatementResult] {
+        &self.statements
+    }
+
+    /// Notices emitted while PostgreSQL executed the input.
+    pub fn notices(&self) -> &[PostgresNotice] {
+        &self.notices
+    }
+
+    pub fn ready_status(&self) -> ReadyStatus {
+        self.ready_status
+    }
+}
+
+pub type Result = std::result::Result;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Error {
+    Protocol(String),
+    Postgres {
+        diagnostic: Box,
+        notices: Vec,
+    },
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Protocol(message) => f.write_str(message),
+            Self::Postgres { diagnostic, .. } => f.write_str(&diagnostic.message),
+        }
+    }
+}
+impl std::error::Error for Error {}
+
+fn protocol(message: impl Into) -> Error {
+    Error::Protocol(message.into())
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct DiagnosticField {
+    pub code: u8,
+    pub value: String,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Diagnostic {
+    pub severity: Option,
+    pub localized_severity: Option,
+    pub nonlocalized_severity: Option,
+    pub sqlstate: Option,
+    pub message: String,
+    pub detail: Option,
+    pub hint: Option,
+    pub position: Option,
+    pub internal_position: Option,
+    pub internal_query: Option,
+    pub where_: Option,
+    pub schema_name: Option,
+    pub table_name: Option,
+    pub column_name: Option,
+    pub data_type_name: Option,
+    pub constraint_name: Option,
+    pub file: Option,
+    pub line: Option,
+    pub routine: Option,
+    pub fields: Vec,
+}
+
+pub fn diagnostic(fields: Vec, fallback_message: &str) -> Diagnostic {
+    let localized_severity = diagnostic_field_value(&fields, b'S');
+    let nonlocalized_severity = diagnostic_field_value(&fields, b'V');
+    Diagnostic {
+        severity: localized_severity
+            .clone()
+            .or_else(|| nonlocalized_severity.clone()),
+        localized_severity,
+        nonlocalized_severity,
+        sqlstate: diagnostic_field_value(&fields, b'C'),
+        message: diagnostic_field_value(&fields, b'M')
+            .unwrap_or_else(|| fallback_message.to_owned()),
+        detail: diagnostic_field_value(&fields, b'D'),
+        hint: diagnostic_field_value(&fields, b'H'),
+        position: diagnostic_field_value(&fields, b'P'),
+        internal_position: diagnostic_field_value(&fields, b'p'),
+        internal_query: diagnostic_field_value(&fields, b'q'),
+        where_: diagnostic_field_value(&fields, b'W'),
+        schema_name: diagnostic_field_value(&fields, b's'),
+        table_name: diagnostic_field_value(&fields, b't'),
+        column_name: diagnostic_field_value(&fields, b'c'),
+        data_type_name: diagnostic_field_value(&fields, b'd'),
+        constraint_name: diagnostic_field_value(&fields, b'n'),
+        file: diagnostic_field_value(&fields, b'F'),
+        line: diagnostic_field_value(&fields, b'L'),
+        routine: diagnostic_field_value(&fields, b'R'),
+        fields,
+    }
+}
+
+fn diagnostic_field_value(fields: &[DiagnosticField], code: u8) -> Option {
+    fields
+        .iter()
+        .find(|field| field.code == code)
+        .map(|field| field.value.clone())
+}
+
+impl PostgresError {
+    pub fn from_core(diagnostic: Diagnostic) -> Self {
+        Self {
+            severity: diagnostic.severity,
+            localized_severity: diagnostic.localized_severity,
+            nonlocalized_severity: diagnostic.nonlocalized_severity,
+            sqlstate: diagnostic.sqlstate,
+            message: diagnostic.message,
+            detail: diagnostic.detail,
+            hint: diagnostic.hint,
+            position: diagnostic.position,
+            internal_position: diagnostic.internal_position,
+            internal_query: diagnostic.internal_query,
+            where_: diagnostic.where_,
+            schema_name: diagnostic.schema_name,
+            table_name: diagnostic.table_name,
+            column_name: diagnostic.column_name,
+            data_type_name: diagnostic.data_type_name,
+            constraint_name: diagnostic.constraint_name,
+            file: diagnostic.file,
+            line: diagnostic.line,
+            routine: diagnostic.routine,
+            fields: diagnostic_fields_from_core(diagnostic.fields),
+            notices: Vec::new(),
+        }
+    }
+}
+
+impl PostgresNotice {
+    pub fn from_core(diagnostic: Diagnostic) -> Self {
+        Self {
+            severity: diagnostic.severity,
+            localized_severity: diagnostic.localized_severity,
+            nonlocalized_severity: diagnostic.nonlocalized_severity,
+            sqlstate: diagnostic.sqlstate,
+            message: diagnostic.message,
+            detail: diagnostic.detail,
+            hint: diagnostic.hint,
+            position: diagnostic.position,
+            internal_position: diagnostic.internal_position,
+            internal_query: diagnostic.internal_query,
+            where_: diagnostic.where_,
+            schema_name: diagnostic.schema_name,
+            table_name: diagnostic.table_name,
+            column_name: diagnostic.column_name,
+            data_type_name: diagnostic.data_type_name,
+            constraint_name: diagnostic.constraint_name,
+            file: diagnostic.file,
+            line: diagnostic.line,
+            routine: diagnostic.routine,
+            fields: diagnostic_fields_from_core(diagnostic.fields),
+        }
+    }
+}
+
+fn diagnostic_fields_from_core(fields: Vec) -> Vec {
+    fields
+        .into_iter()
+        .map(|field| PostgresErrorField {
+            code: field.code,
+            value: field.value,
+        })
+        .collect()
+}
+
+pub fn parse_diagnostic_fields(mut body: &[u8], label: &str) -> Result> {
+    let mut fields = Vec::new();
+    loop {
+        let Some((&code, rest)) = body.split_first() else {
+            return Err(protocol(format!("{label} is missing terminator")));
+        };
+        body = rest;
+        if code == 0 {
+            if body.is_empty() {
+                return Ok(fields);
+            }
+            return Err(protocol(format!("{label} contained trailing bytes")));
+        }
+        fields.push(DiagnosticField {
+            code,
+            value: read_cstring(&mut body, &format!("{label} field"))?.to_owned(),
+        });
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ReadyStatus {
+    Idle,
+    InTransaction,
+    FailedTransaction,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ExpectedProtocol {
+    Either,
+    Simple,
+    Extended,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Row {
+    pub values: Vec>>,
+}
+
+pub fn simple_query(sql: &str) -> Result> {
+    if sql.as_bytes().contains(&0) {
+        return Err(protocol("simple query SQL must not contain NUL bytes"));
+    }
+    let mut body = Vec::with_capacity(sql.len() + 1);
+    body.extend_from_slice(sql.as_bytes());
+    body.push(0);
+    let mut packet = Vec::with_capacity(body.len() + 5);
+    push_frontend_message(&mut packet, b'Q', &body)?;
+    Ok(packet)
+}
+
+pub fn extended_statement(
+    sql: &str,
+    params: &[Parameter],
+    result_format_code: i16,
+) -> Result> {
+    reject_copy_statements(sql)?;
+    validate_statement_input(sql, params.len())?;
+    validate_execution_parameters(params)?;
+    let mut packet = Vec::new();
+    push_parse(&mut packet, sql, params)?;
+    push_bind(&mut packet, params, result_format_code)?;
+    push_frontend_message(&mut packet, b'D', &[b'P', 0])?;
+    push_frontend_message(&mut packet, b'E', &[0, 0, 0, 0, 0])?;
+    push_frontend_message(&mut packet, b'S', &[])?;
+    Ok(packet)
+}
+
+pub fn describe_statement(sql: &str, params: &[Parameter]) -> Result> {
+    validate_statement_input(sql, params.len())?;
+    let mut packet = Vec::new();
+    push_parse(&mut packet, sql, params)?;
+    push_frontend_message(&mut packet, b'D', &[b'S', 0])?;
+    push_frontend_message(&mut packet, b'S', &[])?;
+    Ok(packet)
+}
+
+fn validate_statement_input(sql: &str, parameter_count: usize) -> Result<()> {
+    if sql.as_bytes().contains(&0) {
+        return Err(protocol("extended query SQL must not contain NUL bytes"));
+    }
+    if parameter_count > i16::MAX as usize {
+        return Err(protocol(format!(
+            "extended query supports at most {} parameters, got {parameter_count}",
+            i16::MAX
+        )));
+    }
+    Ok(())
+}
+
+fn validate_execution_parameters(params: &[Parameter]) -> Result<()> {
+    if let Some(index) = params
+        .iter()
+        .position(|parameter| parameter.type_oid().is_some_and(|oid| oid.get() == 0))
+    {
+        return Err(protocol(format!(
+            "execution parameter {index} explicitly declares PostgreSQL type OID 0; omit the type OID to request server inference"
+        )));
+    }
+    Ok(())
+}
+
+fn push_parse(out: &mut Vec, sql: &str, params: &[Parameter]) -> Result<()> {
+    let mut body = Vec::new();
+    push_cstring(&mut body, "")?;
+    push_cstring(&mut body, sql)?;
+    body.extend_from_slice(&(params.len() as i16).to_be_bytes());
+    for parameter in params {
+        body.extend_from_slice(
+            ¶meter
+                .type_oid()
+                .map(TypeOid::get)
+                .unwrap_or_default()
+                .to_be_bytes(),
+        );
+    }
+    push_frontend_message(out, b'P', &body)
+}
+
+fn push_bind(out: &mut Vec, params: &[Parameter], result_format_code: i16) -> Result<()> {
+    let mut body = Vec::new();
+    push_cstring(&mut body, "")?;
+    push_cstring(&mut body, "")?;
+    body.extend_from_slice(&(params.len() as i16).to_be_bytes());
+    for parameter in params {
+        body.extend_from_slice(¶meter.format().code().to_be_bytes());
+    }
+    body.extend_from_slice(&(params.len() as i16).to_be_bytes());
+    for parameter in params {
+        match parameter.value() {
+            None => body.extend_from_slice(&(-1_i32).to_be_bytes()),
+            Some(value) => push_sized_value(&mut body, value)?,
+        }
+    }
+    body.extend_from_slice(&1_i16.to_be_bytes());
+    body.extend_from_slice(&result_format_code.to_be_bytes());
+    push_frontend_message(out, b'B', &body)
+}
+
+fn push_frontend_message(out: &mut Vec, tag: u8, body: &[u8]) -> Result<()> {
+    let len = i32::try_from(body.len() + 4)
+        .map_err(|_| protocol("frontend protocol message is too large"))?;
+    out.push(tag);
+    out.extend_from_slice(&len.to_be_bytes());
+    out.extend_from_slice(body);
+    Ok(())
+}
+
+fn push_cstring(out: &mut Vec, value: &str) -> Result<()> {
+    if value.as_bytes().contains(&0) {
+        return Err(protocol(
+            "frontend protocol string must not contain NUL bytes",
+        ));
+    }
+    out.extend_from_slice(value.as_bytes());
+    out.push(0);
+    Ok(())
+}
+
+fn push_sized_value(out: &mut Vec, value: &[u8]) -> Result<()> {
+    let len = i32::try_from(value.len()).map_err(|_| protocol("query parameter is too large"))?;
+    out.extend_from_slice(&len.to_be_bytes());
+    out.extend_from_slice(value);
+    Ok(())
+}
+
+pub fn reject_copy_statements(sql: &str) -> Result<()> {
+    if contains_top_level_copy(sql, false) || contains_top_level_copy(sql, true) {
+        return Err(protocol(
+            "COPY is not supported by buffered SQL APIs; use exec_protocol_raw or exec_protocol_raw_stream with a complete COPY protocol flow",
+        ));
+    }
+    Ok(())
+}
+
+pub fn reject_transaction_chain(sql: &str) -> Result<()> {
+    if contains_transaction_chain(sql, false) || contains_transaction_chain(sql, true) {
+        return Err(protocol(
+            "ROLLBACK ... AND CHAIN and ABORT ... AND CHAIN are not allowed inside an SDK-managed callback transaction; roll back through the transaction handle and start a new transaction explicitly",
+        ));
+    }
+    Ok(())
+}
+
+fn contains_top_level_copy(sql: &str, ordinary_backslash_escapes: bool) -> bool {
+    let mut statement_start = true;
+    for token in TopLevelSqlTokens::new(sql, ordinary_backslash_escapes) {
+        match token {
+            TopLevelSqlToken::StatementBoundary => statement_start = true,
+            TopLevelSqlToken::Word(word) => {
+                if statement_start && word.eq_ignore_ascii_case(b"COPY") {
+                    return true;
+                }
+                statement_start = false;
+            }
+            TopLevelSqlToken::Other => statement_start = false,
+        }
+    }
+    false
+}
+
+#[derive(Clone, Copy)]
+enum TransactionChainState {
+    StatementStart,
+    AfterControl,
+    AfterQualifier,
+    AfterAnd,
+    Ineligible,
+}
+
+fn contains_transaction_chain(sql: &str, ordinary_backslash_escapes: bool) -> bool {
+    let mut state = TransactionChainState::StatementStart;
+    for token in TopLevelSqlTokens::new(sql, ordinary_backslash_escapes) {
+        state = match token {
+            TopLevelSqlToken::StatementBoundary => TransactionChainState::StatementStart,
+            TopLevelSqlToken::Other => TransactionChainState::Ineligible,
+            TopLevelSqlToken::Word(word) => match state {
+                TransactionChainState::StatementStart
+                    if word.eq_ignore_ascii_case(b"ROLLBACK")
+                        || word.eq_ignore_ascii_case(b"ABORT") =>
+                {
+                    TransactionChainState::AfterControl
+                }
+                TransactionChainState::AfterControl
+                    if word.eq_ignore_ascii_case(b"WORK")
+                        || word.eq_ignore_ascii_case(b"TRANSACTION") =>
+                {
+                    TransactionChainState::AfterQualifier
+                }
+                TransactionChainState::AfterControl | TransactionChainState::AfterQualifier
+                    if word.eq_ignore_ascii_case(b"AND") =>
+                {
+                    TransactionChainState::AfterAnd
+                }
+                TransactionChainState::AfterAnd if word.eq_ignore_ascii_case(b"CHAIN") => {
+                    return true;
+                }
+                _ => TransactionChainState::Ineligible,
+            },
+        };
+    }
+    false
+}
+
+#[derive(Clone, Copy)]
+enum TopLevelSqlToken<'a> {
+    StatementBoundary,
+    Word(&'a [u8]),
+    Other,
+}
+
+struct TopLevelSqlTokens<'a> {
+    bytes: &'a [u8],
+    index: usize,
+    depth: usize,
+    ordinary_backslash_escapes: bool,
+}
+
+impl<'a> TopLevelSqlTokens<'a> {
+    fn new(sql: &'a str, ordinary_backslash_escapes: bool) -> Self {
+        Self {
+            bytes: sql.as_bytes(),
+            index: 0,
+            depth: 0,
+            ordinary_backslash_escapes,
+        }
+    }
+}
+
+impl<'a> Iterator for TopLevelSqlTokens<'a> {
+    type Item = TopLevelSqlToken<'a>;
+
+    fn next(&mut self) -> Option {
+        while self.index < self.bytes.len() {
+            match self.bytes[self.index] {
+                byte if byte.is_ascii_whitespace() => self.index += 1,
+                b'-' if self.bytes.get(self.index + 1) == Some(&b'-') => {
+                    self.index += 2;
+                    while self.index < self.bytes.len()
+                        && !matches!(self.bytes[self.index], b'\n' | b'\r')
+                    {
+                        self.index += 1;
+                    }
+                }
+                b'/' if self.bytes.get(self.index + 1) == Some(&b'*') => {
+                    self.index = skip_block_comment(self.bytes, self.index);
+                }
+                b'\'' => {
+                    let top_level = self.depth == 0;
+                    self.index = skip_quoted(
+                        self.bytes,
+                        self.index,
+                        b'\'',
+                        self.ordinary_backslash_escapes,
+                    );
+                    if top_level {
+                        return Some(TopLevelSqlToken::Other);
+                    }
+                }
+                b'"' => {
+                    let top_level = self.depth == 0;
+                    self.index = skip_quoted(self.bytes, self.index, b'"', false);
+                    if top_level {
+                        return Some(TopLevelSqlToken::Other);
+                    }
+                }
+                b'$' if dollar_quote_delimiter(self.bytes, self.index).is_some() => {
+                    let top_level = self.depth == 0;
+                    self.index = skip_dollar_quote(self.bytes, self.index);
+                    if top_level {
+                        return Some(TopLevelSqlToken::Other);
+                    }
+                }
+                b'(' => {
+                    let top_level = self.depth == 0;
+                    self.depth += 1;
+                    self.index += 1;
+                    if top_level {
+                        return Some(TopLevelSqlToken::Other);
+                    }
+                }
+                b')' if self.depth > 0 => {
+                    self.depth -= 1;
+                    self.index += 1;
+                }
+                b';' if self.depth == 0 => {
+                    self.index += 1;
+                    return Some(TopLevelSqlToken::StatementBoundary);
+                }
+                byte if is_postgres_identifier_start(byte) => {
+                    let start = self.index;
+                    self.index += 1;
+                    while self
+                        .bytes
+                        .get(self.index)
+                        .is_some_and(|byte| is_postgres_identifier_continuation(*byte))
+                    {
+                        self.index += 1;
+                    }
+                    let word = &self.bytes[start..self.index];
+                    if word.eq_ignore_ascii_case(b"E") && self.bytes.get(self.index) == Some(&b'\'')
+                    {
+                        self.index = skip_quoted(self.bytes, self.index, b'\'', true);
+                        if self.depth == 0 {
+                            return Some(TopLevelSqlToken::Other);
+                        }
+                    } else if self.depth == 0 {
+                        return Some(TopLevelSqlToken::Word(word));
+                    }
+                }
+                _ => {
+                    self.index += 1;
+                    if self.depth == 0 {
+                        return Some(TopLevelSqlToken::Other);
+                    }
+                }
+            }
+        }
+        None
+    }
+}
+
+fn skip_quoted(bytes: &[u8], mut index: usize, quote: u8, backslash_escapes: bool) -> usize {
+    index += 1;
+    while index < bytes.len() {
+        if bytes[index] == quote {
+            if bytes.get(index + 1) == Some("e) {
+                index += 2;
+                continue;
+            }
+            return index + 1;
+        }
+        if backslash_escapes && bytes[index] == b'\\' && index + 1 < bytes.len() {
+            index += 2;
+        } else {
+            index += 1;
+        }
+    }
+    index
+}
+
+fn skip_block_comment(bytes: &[u8], mut index: usize) -> usize {
+    index += 2;
+    let mut depth = 1_usize;
+    while index < bytes.len() && depth > 0 {
+        if bytes.get(index..index + 2) == Some(b"/*") {
+            depth += 1;
+            index += 2;
+        } else if bytes.get(index..index + 2) == Some(b"*/") {
+            depth -= 1;
+            index += 2;
+        } else {
+            index += 1;
+        }
+    }
+    index
+}
+
+fn dollar_quote_delimiter(bytes: &[u8], index: usize) -> Option<&[u8]> {
+    if bytes.get(index) != Some(&b'$') {
+        return None;
+    }
+    let tail = &bytes[index + 1..];
+    let end = tail.iter().position(|byte| *byte == b'$')?;
+    let tag = &tail[..end];
+    (tag.is_empty()
+        || (is_postgres_identifier_start(tag[0])
+            && tag[1..]
+                .iter()
+                .all(|byte| is_postgres_identifier_continuation(*byte) && *byte != b'$')))
+    .then_some(&bytes[index..index + end + 2])
+}
+
+fn is_postgres_identifier_start(byte: u8) -> bool {
+    byte.is_ascii_alphabetic() || byte == b'_' || byte >= 0x80
+}
+
+fn is_postgres_identifier_continuation(byte: u8) -> bool {
+    is_postgres_identifier_start(byte) || byte.is_ascii_digit() || byte == b'$'
+}
+
+fn skip_dollar_quote(bytes: &[u8], index: usize) -> usize {
+    let Some(delimiter) = dollar_quote_delimiter(bytes, index) else {
+        return index + 1;
+    };
+    let content = index + delimiter.len();
+    bytes[content..]
+        .windows(delimiter.len())
+        .position(|window| window == delimiter)
+        .map_or(bytes.len(), |offset| content + offset + delimiter.len())
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum SingleStatementCompletion {
+    Command,
+    Empty,
+}
+
+pub fn parse_command_response(
+    bytes: &[u8],
+    expected_protocol: ExpectedProtocol,
+) -> Result {
+    let mut input = bytes;
+    let mut ready_status = None;
+    let mut command_tag = None;
+    let mut completion = None;
+    let mut saw_parse_complete = false;
+    let mut saw_bind_complete = false;
+    let mut saw_no_data = false;
+    let mut notices = Vec::new();
+    let mut postgres_error = None;
+
+    while !input.is_empty() {
+        let (tag, body, rest) = read_backend_message(input)?;
+        input = rest;
+        if expected_protocol == ExpectedProtocol::Simple && matches!(tag, b'1' | b'2' | b'n') {
+            return Err(protocol(format!(
+                "execute() simple-query response received extended-protocol message tag 0x{tag:02x}"
+            )));
+        }
+        if postgres_error.is_some() && !matches!(tag, b'N' | b'S' | b'A' | b'Z') {
+            return Err(protocol(format!(
+                "execute() received backend message 0x{tag:02x} after ErrorResponse"
+            )));
+        }
+        match tag {
+            b'E' => {
+                if completion.is_some() {
+                    return Err(protocol(
+                        "execute() received ErrorResponse after statement completion",
+                    ));
+                }
+                postgres_error = Some(parse_error_response(body)?);
+            }
+            b'C' => {
+                match completion {
+                    Some(SingleStatementCompletion::Command) => {
+                        return Err(protocol(
+                            "execute() received multiple CommandComplete messages",
+                        ));
+                    }
+                    Some(SingleStatementCompletion::Empty) => {
+                        return Err(protocol(
+                            "execute() received CommandComplete after EmptyQueryResponse",
+                        ));
+                    }
+                    None => {}
+                }
+                if saw_parse_complete != saw_bind_complete {
+                    return Err(protocol(
+                        "execute() received CommandComplete before the extended-query controls completed",
+                    ));
+                }
+                if saw_bind_complete && !saw_no_data {
+                    return Err(protocol("execute() received CommandComplete before NoData"));
+                }
+                command_tag = Some(parse_command_complete(body)?);
+                completion = Some(SingleStatementCompletion::Command);
+            }
+            b'Z' => {
+                ready_status = Some(parse_ready_for_query(body)?);
+                if !input.is_empty() {
+                    return Err(protocol("backend returned bytes after ReadyForQuery"));
+                }
+            }
+            b'1' => {
+                require_empty_backend_message(body, "ParseComplete")?;
+                if completion.is_some() || saw_parse_complete || saw_bind_complete || saw_no_data {
+                    return Err(protocol("execute() received ParseComplete out of order"));
+                }
+                saw_parse_complete = true;
+            }
+            b'2' => {
+                require_empty_backend_message(body, "BindComplete")?;
+                if completion.is_some() || !saw_parse_complete || saw_bind_complete || saw_no_data {
+                    return Err(protocol("execute() received BindComplete out of order"));
+                }
+                saw_bind_complete = true;
+            }
+            b'I' => {
+                require_empty_backend_message(body, "EmptyQueryResponse")?;
+                match completion {
+                    Some(SingleStatementCompletion::Command) => {
+                        return Err(protocol(
+                            "execute() received EmptyQueryResponse after CommandComplete",
+                        ));
+                    }
+                    Some(SingleStatementCompletion::Empty) => {
+                        return Err(protocol(
+                            "execute() received multiple EmptyQueryResponse messages",
+                        ));
+                    }
+                    None => {}
+                }
+                if saw_parse_complete != saw_bind_complete {
+                    return Err(protocol(
+                        "execute() received EmptyQueryResponse before the extended-query controls completed",
+                    ));
+                }
+                if saw_bind_complete && !saw_no_data {
+                    return Err(protocol(
+                        "execute() received EmptyQueryResponse before NoData",
+                    ));
+                }
+                completion = Some(SingleStatementCompletion::Empty);
+            }
+            b'n' => {
+                require_empty_backend_message(body, "NoData")?;
+                if completion.is_some() || !saw_bind_complete || saw_no_data {
+                    return Err(protocol("execute() received NoData out of order"));
+                }
+                saw_no_data = true;
+            }
+            b'S' => validate_parameter_status(body)?,
+            b'N' => notices.push(parse_notice_response(body)?),
+            b'A' => validate_notification_response(body)?,
+            b'T' | b'D' => {
+                return Err(protocol(
+                    "execute() received rows; use query() for row results",
+                ));
+            }
+            b'G' | b'H' | b'W' | b'd' | b'c' => {
+                return Err(protocol(
+                    "execute() does not support COPY protocol responses; use exec_protocol_raw or exec_protocol_raw_stream for COPY traffic",
+                ));
+            }
+            _ => {
+                return Err(protocol(format!(
+                    "execute() received unexpected backend message tag 0x{tag:02x}"
+                )));
+            }
+        }
+    }
+
+    let ready_status =
+        ready_status.ok_or_else(|| protocol("execute response ended before ReadyForQuery"))?;
+    if postgres_error.is_none()
+        && expected_protocol == ExpectedProtocol::Extended
+        && (!saw_parse_complete || !saw_bind_complete)
+    {
+        return Err(protocol(
+            "execute() extended-query response omitted ParseComplete or BindComplete",
+        ));
+    }
+    if let Some(diagnostic) = postgres_error {
+        return Err(Error::Postgres {
+            diagnostic: Box::new(diagnostic),
+            notices,
+        });
+    }
+    if completion.is_none() {
+        return Err(protocol(
+            "execute response ended before CommandComplete or EmptyQueryResponse",
+        ));
+    }
+
+    let row_count = command_tag.as_deref().and_then(command_tag_row_count);
+    Ok(CommandResult {
+        command_tag,
+        row_count,
+        notices: notices.into_iter().map(PostgresNotice::from_core).collect(),
+        ready_status,
+    })
+}
+
+pub fn parse_query_response(
+    bytes: &[u8],
+    expected_protocol: ExpectedProtocol,
+) -> Result {
+    let mut input = bytes;
+    let mut fields = None;
+    let mut rows = Vec::new();
+    let mut command_tag = None;
+    let mut completion = None;
+    let mut saw_parse_complete = false;
+    let mut saw_bind_complete = false;
+    let mut saw_no_data = false;
+    let mut ready_status = None;
+    let mut notices = Vec::new();
+    let mut postgres_error = None;
+
+    while !input.is_empty() {
+        let (tag, body, rest) = read_backend_message(input)?;
+        input = rest;
+        if expected_protocol == ExpectedProtocol::Simple && matches!(tag, b'1' | b'2' | b'n') {
+            return Err(protocol(format!(
+                "query() simple-query response received extended-protocol message tag 0x{tag:02x}"
+            )));
+        }
+        if postgres_error.is_some() && !matches!(tag, b'N' | b'S' | b'A' | b'Z') {
+            return Err(protocol(format!(
+                "query() received backend message 0x{tag:02x} after ErrorResponse"
+            )));
+        }
+        match tag {
+            b'T' => {
+                if fields.is_some() {
+                    return Err(protocol(
+                        "query() received multiple result sets; use exec_protocol_raw for multi-statement row results",
+                    ));
+                }
+                if completion.is_some() {
+                    return Err(protocol(
+                        "query() received a result after statement completion",
+                    ));
+                }
+                if saw_no_data || (saw_parse_complete && !saw_bind_complete) {
+                    return Err(protocol("query() received RowDescription out of order"));
+                }
+                fields = Some(parse_row_description(body)?);
+            }
+            b'D' => {
+                if completion.is_some() {
+                    return Err(protocol(
+                        "query() received DataRow after statement completion",
+                    ));
+                }
+                let field_count = fields
+                    .as_ref()
+                    .ok_or_else(|| protocol("DataRow arrived before RowDescription"))?
+                    .len();
+                rows.push(parse_data_row(body, field_count)?);
+            }
+            b'C' => {
+                match completion {
+                    Some(SingleStatementCompletion::Command) => {
+                        return Err(protocol(
+                            "query() received multiple CommandComplete messages",
+                        ));
+                    }
+                    Some(SingleStatementCompletion::Empty) => {
+                        return Err(protocol(
+                            "query() received CommandComplete after EmptyQueryResponse",
+                        ));
+                    }
+                    None => {}
+                }
+                if saw_parse_complete != saw_bind_complete {
+                    return Err(protocol(
+                        "query() received CommandComplete before the extended-query controls completed",
+                    ));
+                }
+                if saw_bind_complete && fields.is_none() && !saw_no_data {
+                    return Err(protocol(
+                        "query() received CommandComplete before RowDescription or NoData",
+                    ));
+                }
+                command_tag = Some(parse_command_complete(body)?);
+                completion = Some(SingleStatementCompletion::Command);
+            }
+            b'E' => {
+                if completion.is_some() {
+                    return Err(protocol(
+                        "query() received ErrorResponse after statement completion",
+                    ));
+                }
+                postgres_error = Some(parse_error_response(body)?);
+            }
+            b'G' | b'H' | b'W' | b'd' | b'c' => {
+                return Err(protocol(
+                    "query() does not support COPY protocol responses; use exec_protocol_raw or exec_protocol_raw_stream",
+                ));
+            }
+            b'Z' => {
+                ready_status = Some(parse_ready_for_query(body)?);
+                if !input.is_empty() {
+                    return Err(protocol("backend returned bytes after ReadyForQuery"));
+                }
+            }
+            b'1' => {
+                require_empty_backend_message(body, "ParseComplete")?;
+                if completion.is_some()
+                    || saw_parse_complete
+                    || saw_bind_complete
+                    || fields.is_some()
+                    || saw_no_data
+                {
+                    return Err(protocol("query() received ParseComplete out of order"));
+                }
+                saw_parse_complete = true;
+            }
+            b'2' => {
+                require_empty_backend_message(body, "BindComplete")?;
+                if completion.is_some()
+                    || !saw_parse_complete
+                    || saw_bind_complete
+                    || fields.is_some()
+                    || saw_no_data
+                {
+                    return Err(protocol("query() received BindComplete out of order"));
+                }
+                saw_bind_complete = true;
+            }
+            b'I' => {
+                require_empty_backend_message(body, "EmptyQueryResponse")?;
+                match completion {
+                    Some(SingleStatementCompletion::Command) => {
+                        return Err(protocol(
+                            "query() received EmptyQueryResponse after CommandComplete",
+                        ));
+                    }
+                    Some(SingleStatementCompletion::Empty) => {
+                        return Err(protocol(
+                            "query() received multiple EmptyQueryResponse messages",
+                        ));
+                    }
+                    None => {}
+                }
+                if fields.is_some() || !rows.is_empty() {
+                    return Err(protocol(
+                        "query() received EmptyQueryResponse after a row result",
+                    ));
+                }
+                if saw_parse_complete != saw_bind_complete {
+                    return Err(protocol(
+                        "query() received EmptyQueryResponse before the extended-query controls completed",
+                    ));
+                }
+                if saw_bind_complete && !saw_no_data {
+                    return Err(protocol(
+                        "query() received EmptyQueryResponse before RowDescription or NoData",
+                    ));
+                }
+                completion = Some(SingleStatementCompletion::Empty);
+            }
+            b'n' => {
+                require_empty_backend_message(body, "NoData")?;
+                if completion.is_some() || !saw_bind_complete || fields.is_some() || saw_no_data {
+                    return Err(protocol("query() received NoData out of order"));
+                }
+                saw_no_data = true;
+            }
+            b'S' => validate_parameter_status(body)?,
+            b'N' => notices.push(parse_notice_response(body)?),
+            b'A' => validate_notification_response(body)?,
+            _ => {
+                return Err(protocol(format!(
+                    "query() received unexpected backend message tag 0x{tag:02x}"
+                )));
+            }
+        }
+    }
+
+    let ready_status =
+        ready_status.ok_or_else(|| protocol("query response ended before ReadyForQuery"))?;
+    if postgres_error.is_none()
+        && expected_protocol == ExpectedProtocol::Extended
+        && (!saw_parse_complete || !saw_bind_complete)
+    {
+        return Err(protocol(
+            "query() extended-query response omitted ParseComplete or BindComplete",
+        ));
+    }
+    if let Some(diagnostic) = postgres_error {
+        return Err(Error::Postgres {
+            diagnostic: Box::new(diagnostic),
+            notices,
+        });
+    }
+    if completion.is_none() {
+        return Err(protocol(
+            "query response ended before CommandComplete or EmptyQueryResponse",
+        ));
+    }
+
+    let row_count = command_tag.as_deref().and_then(command_tag_row_count);
+    let fields: Arc<[QueryField]> = fields.unwrap_or_default().into();
+    let rows = rows
+        .into_iter()
+        .map(|row| QueryRow::new(Arc::clone(&fields), row.values))
+        .collect();
+    Ok(QueryResult {
+        fields,
+        rows,
+        command_tag,
+        row_count,
+        notices: notices.into_iter().map(PostgresNotice::from_core).collect(),
+        ready_status,
+    })
+}
+
+pub fn parse_exec_response(bytes: &[u8]) -> Result {
+    let mut input = bytes;
+    let mut fields = None;
+    let mut rows = Vec::new();
+    let mut statements = Vec::new();
+    let mut saw_completion = false;
+    let mut notices = Vec::new();
+    let mut statement_notices = Vec::new();
+    let mut ready_status = None;
+    let mut postgres_error = None;
+
+    while !input.is_empty() {
+        let (tag, body, rest) = read_backend_message(input)?;
+        input = rest;
+        if postgres_error.is_some() && !matches!(tag, b'N' | b'S' | b'A' | b'Z') {
+            return Err(protocol(format!(
+                "exec() received backend message 0x{tag:02x} after ErrorResponse"
+            )));
+        }
+        match tag {
+            b'T' => {
+                if fields.is_some() {
+                    return Err(protocol(
+                        "exec() received RowDescription before the prior result completed",
+                    ));
+                }
+                fields = Some(parse_row_description(body)?);
+            }
+            b'D' => {
+                let expected = fields
+                    .as_ref()
+                    .ok_or_else(|| protocol("DataRow arrived before RowDescription"))?
+                    .len();
+                rows.push(parse_data_row(body, expected)?);
+            }
+            b'C' => {
+                let command_tag = parse_command_complete(body)?;
+                let row_count = command_tag_row_count(&command_tag);
+                if let Some(result_fields) = fields.take() {
+                    let fields: Arc<[QueryField]> = result_fields.into();
+                    let rows = std::mem::take(&mut rows)
+                        .into_iter()
+                        .map(|row| QueryRow::new(Arc::clone(&fields), row.values))
+                        .collect();
+                    statements.push(StatementResult::Rows(QueryResult {
+                        fields,
+                        rows,
+                        command_tag: Some(command_tag),
+                        row_count,
+                        notices: take_notices(&mut statement_notices),
+                        ready_status: ReadyStatus::Idle,
+                    }));
+                } else {
+                    if !rows.is_empty() {
+                        return Err(protocol("exec() retained rows without field metadata"));
+                    }
+                    statements.push(StatementResult::Command(CommandResult {
+                        command_tag: Some(command_tag),
+                        row_count,
+                        notices: take_notices(&mut statement_notices),
+                        ready_status: ReadyStatus::Idle,
+                    }));
+                }
+                saw_completion = true;
+            }
+            b'I' => {
+                require_empty_backend_message(body, "EmptyQueryResponse")?;
+                if fields.is_some() || !rows.is_empty() {
+                    return Err(protocol(
+                        "exec() received EmptyQueryResponse before the prior row result completed",
+                    ));
+                }
+                statement_notices.clear();
+                saw_completion = true;
+            }
+            b'E' => postgres_error = Some(parse_error_response(body)?),
+            b'N' => {
+                let notice = parse_notice_response(body)?;
+                statement_notices.push(notice.clone());
+                notices.push(notice);
+            }
+            b'S' => validate_parameter_status(body)?,
+            b'A' => validate_notification_response(body)?,
+            b'Z' => {
+                ready_status = Some(parse_ready_for_query(body)?);
+                if !input.is_empty() {
+                    return Err(protocol("backend returned bytes after ReadyForQuery"));
+                }
+            }
+            b'G' | b'H' | b'W' | b'd' | b'c' => {
+                return Err(protocol(
+                    "exec() does not support COPY protocol responses; use exec_protocol_raw or exec_protocol_raw_stream",
+                ));
+            }
+            _ => {
+                return Err(protocol(format!(
+                    "exec() received unexpected backend message tag 0x{tag:02x}"
+                )));
+            }
+        }
+    }
+
+    let ready_status =
+        ready_status.ok_or_else(|| protocol("exec response ended before ReadyForQuery"))?;
+    if let Some(diagnostic) = postgres_error {
+        return Err(Error::Postgres {
+            diagnostic: Box::new(diagnostic),
+            notices,
+        });
+    }
+    if fields.is_some() || !rows.is_empty() {
+        return Err(protocol("exec response ended before CommandComplete"));
+    }
+    if !saw_completion {
+        return Err(protocol(
+            "exec response ended before CommandComplete or EmptyQueryResponse",
+        ));
+    }
+
+    Ok(ExecResult {
+        statements,
+        notices: notices.into_iter().map(PostgresNotice::from_core).collect(),
+        ready_status,
+    })
+}
+
+fn take_notices(notices: &mut Vec) -> Vec {
+    std::mem::take(notices)
+        .into_iter()
+        .map(PostgresNotice::from_core)
+        .collect()
+}
+
+pub fn parse_statement_description(bytes: &[u8]) -> Result {
+    let mut input = bytes;
+    let mut parameter_types = None;
+    let mut fields = None;
+    let mut saw_no_data = false;
+    let mut saw_parse_complete = false;
+    let mut ready_status = None;
+    let mut notices = Vec::new();
+    let mut postgres_error = None;
+
+    while !input.is_empty() {
+        let (tag, body, rest) = read_backend_message(input)?;
+        input = rest;
+        if postgres_error.is_some() && !matches!(tag, b'N' | b'S' | b'A' | b'Z') {
+            return Err(protocol(format!(
+                "describe() received backend message 0x{tag:02x} after ErrorResponse"
+            )));
+        }
+        match tag {
+            b'1' => {
+                require_empty_backend_message(body, "ParseComplete")?;
+                if saw_parse_complete
+                    || parameter_types.is_some()
+                    || fields.is_some()
+                    || saw_no_data
+                {
+                    return Err(protocol("describe() received ParseComplete out of order"));
+                }
+                saw_parse_complete = true;
+            }
+            b't' => {
+                if !saw_parse_complete
+                    || parameter_types.is_some()
+                    || fields.is_some()
+                    || saw_no_data
+                {
+                    return Err(protocol(
+                        "describe() received ParameterDescription out of order",
+                    ));
+                }
+                parameter_types = Some(parse_parameter_description(body)?);
+            }
+            b'T' => {
+                if parameter_types.is_none() || fields.is_some() || saw_no_data {
+                    return Err(protocol("describe() received RowDescription out of order"));
+                }
+                fields = Some(parse_row_description(body)?);
+            }
+            b'n' => {
+                require_empty_backend_message(body, "NoData")?;
+                if parameter_types.is_none() || fields.is_some() || saw_no_data {
+                    return Err(protocol("describe() received NoData out of order"));
+                }
+                saw_no_data = true;
+            }
+            b'E' => {
+                if fields.is_some() || saw_no_data {
+                    return Err(protocol(
+                        "describe() received ErrorResponse after result description",
+                    ));
+                }
+                postgres_error = Some(parse_error_response(body)?);
+            }
+            b'N' => notices.push(parse_notice_response(body)?),
+            b'S' => validate_parameter_status(body)?,
+            b'A' => validate_notification_response(body)?,
+            b'Z' => {
+                ready_status = Some(parse_ready_for_query(body)?);
+                if !input.is_empty() {
+                    return Err(protocol("backend returned bytes after ReadyForQuery"));
+                }
+            }
+            _ => {
+                return Err(protocol(format!(
+                    "describe() received unexpected backend message tag 0x{tag:02x}"
+                )));
+            }
+        }
+    }
+
+    let ready_status =
+        ready_status.ok_or_else(|| protocol("describe response ended before ReadyForQuery"))?;
+    if let Some(diagnostic) = postgres_error {
+        return Err(Error::Postgres {
+            diagnostic: Box::new(diagnostic),
+            notices,
+        });
+    }
+    if !saw_parse_complete {
+        return Err(protocol("describe response omitted ParseComplete"));
+    }
+    let parameter_types = parameter_types
+        .ok_or_else(|| protocol("describe response omitted ParameterDescription"))?;
+    if fields.is_none() && !saw_no_data {
+        return Err(protocol(
+            "describe response omitted RowDescription or NoData",
+        ));
+    }
+
+    Ok(StatementDescription {
+        parameter_types: parameter_types.into_iter().map(TypeOid::new).collect(),
+        fields,
+        notices: notices.into_iter().map(PostgresNotice::from_core).collect(),
+        ready_status,
+    })
+}
+
+pub fn response_ready_status(bytes: &[u8]) -> Result {
+    let mut input = bytes;
+    let mut ready = None;
+    while !input.is_empty() {
+        let (tag, body, rest) = read_backend_message(input)?;
+        input = rest;
+        if tag == b'Z' {
+            if ready.is_some() {
+                return Err(protocol("backend returned multiple ReadyForQuery messages"));
+            }
+            ready = Some(parse_ready_for_query(body)?);
+            if !input.is_empty() {
+                return Err(protocol("backend returned bytes after ReadyForQuery"));
+            }
+        }
+    }
+    ready.ok_or_else(|| protocol("response ended before ReadyForQuery"))
+}
+
+/// Validate that a structured operation kept ownership of a callback-scoped
+/// transaction. This works from raw backend frames so an earlier
+/// CommandComplete cannot be hidden by a later ErrorResponse.
+pub fn validate_managed_transaction_response(bytes: &[u8]) -> Result {
+    let mut input = bytes;
+    let mut ready = None;
+    let mut escaped_command = None;
+    while !input.is_empty() {
+        let (message, body, rest) = read_backend_message(input)?;
+        input = rest;
+        match message {
+            b'C' => {
+                let mut command = body;
+                let tag = read_cstring(&mut command, "CommandComplete tag")?;
+                if !command.is_empty() {
+                    return Err(protocol("CommandComplete contained trailing bytes"));
+                }
+                if matches!(
+                    tag,
+                    "BEGIN"
+                        | "START TRANSACTION"
+                        | "COMMIT"
+                        | "PREPARE TRANSACTION"
+                        | "COMMIT PREPARED"
+                        | "ROLLBACK PREPARED"
+                ) {
+                    escaped_command.get_or_insert_with(|| tag.to_owned());
+                }
+            }
+            b'Z' => {
+                if ready.is_some() {
+                    return Err(protocol("backend returned multiple ReadyForQuery messages"));
+                }
+                ready = Some(parse_ready_for_query(body)?);
+                if !input.is_empty() {
+                    return Err(protocol("backend returned bytes after ReadyForQuery"));
+                }
+            }
+            _ => {}
+        }
+    }
+    let ready = ready.ok_or_else(|| protocol("response ended before ReadyForQuery"))?;
+    if let Some(command) = escaped_command {
+        return Err(protocol(format!(
+            "PostgreSQL completed {command}, which changed the SDK-managed transaction lifecycle"
+        )));
+    }
+    if ready == ReadyStatus::Idle {
+        return Err(protocol(
+            "PostgreSQL returned idle readiness after SDK-managed transaction work",
+        ));
+    }
+    Ok(ready)
+}
+
+fn parse_parameter_description(mut body: &[u8]) -> Result> {
+    let count = read_i16(&mut body, "ParameterDescription parameter count")?;
+    if count < 0 {
+        return Err(protocol(format!(
+            "invalid ParameterDescription parameter count {count}"
+        )));
+    }
+    let mut types = Vec::with_capacity(count as usize);
+    for _ in 0..count {
+        types.push(read_u32(&mut body, "ParameterDescription type OID")?);
+    }
+    if !body.is_empty() {
+        return Err(protocol("ParameterDescription contained trailing bytes"));
+    }
+    Ok(types)
+}
+
+fn command_tag_row_count(tag: &str) -> Option {
+    let mut parts = tag.split_ascii_whitespace();
+    let command = parts.next()?;
+    if !matches!(
+        command,
+        "SELECT" | "INSERT" | "UPDATE" | "DELETE" | "MERGE" | "MOVE" | "FETCH" | "COPY"
+    ) {
+        return None;
+    }
+    parts.last().or(Some(command))?.parse().ok()
+}
+
+fn read_backend_message(bytes: &[u8]) -> Result<(u8, &[u8], &[u8])> {
+    if bytes.len() < 5 {
+        return Err(protocol("truncated backend message header"));
+    }
+    let tag = bytes[0];
+    let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
+    if len < 4 {
+        return Err(protocol(format!("invalid backend message length {len}")));
+    }
+    let total = 1usize
+        .checked_add(len as usize)
+        .ok_or_else(|| protocol("backend message length overflow"))?;
+    if bytes.len() < total {
+        return Err(protocol("truncated backend message body"));
+    }
+    Ok((tag, &bytes[5..total], &bytes[total..]))
+}
+
+fn parse_row_description(mut body: &[u8]) -> Result> {
+    let count = read_i16(&mut body, "RowDescription field count")?;
+    if count < 0 {
+        return Err(protocol(format!(
+            "invalid RowDescription field count {count}"
+        )));
+    }
+    let mut fields = Vec::with_capacity(count as usize);
+    for _ in 0..count {
+        fields.push(QueryField {
+            name: read_cstring(&mut body, "field name")?.to_owned(),
+            table_oid: read_u32(&mut body, "field table oid")?,
+            table_attribute: read_i16(&mut body, "field table attribute")?,
+            type_oid: read_u32(&mut body, "field type oid")?,
+            type_size: read_i16(&mut body, "field type size")?,
+            type_modifier: read_i32(&mut body, "field type modifier")?,
+            format: QueryFormat::from(read_i16(&mut body, "field format")?),
+        });
+    }
+    if !body.is_empty() {
+        return Err(protocol("RowDescription contained trailing bytes"));
+    }
+    Ok(fields)
+}
+
+fn parse_data_row(mut body: &[u8], expected_columns: usize) -> Result {
+    let count = read_i16(&mut body, "DataRow column count")?;
+    if count < 0 {
+        return Err(protocol(format!("invalid DataRow column count {count}")));
+    }
+    if count as usize != expected_columns {
+        return Err(protocol(format!(
+            "DataRow column count {count} does not match RowDescription count {expected_columns}"
+        )));
+    }
+    let mut values = Vec::with_capacity(count as usize);
+    for _ in 0..count {
+        let len = read_i32(&mut body, "DataRow value length")?;
+        if len == -1 {
+            values.push(None);
+            continue;
+        }
+        if len < 0 {
+            return Err(protocol(format!("invalid DataRow value length {len}")));
+        }
+        let len = len as usize;
+        if body.len() < len {
+            return Err(protocol("truncated DataRow value"));
+        }
+        values.push(Some(body[..len].to_vec()));
+        body = &body[len..];
+    }
+    if !body.is_empty() {
+        return Err(protocol("DataRow contained trailing bytes"));
+    }
+    Ok(Row { values })
+}
+
+fn parse_command_complete(mut body: &[u8]) -> Result {
+    let tag = read_cstring(&mut body, "CommandComplete tag")?.to_owned();
+    if !body.is_empty() {
+        return Err(protocol("CommandComplete contained trailing bytes"));
+    }
+    Ok(tag)
+}
+
+fn parse_error_response(body: &[u8]) -> Result {
+    parse_diagnostic_fields(body, "ErrorResponse")
+        .map(|fields| diagnostic(fields, "PostgreSQL ErrorResponse"))
+}
+
+fn parse_notice_response(body: &[u8]) -> Result {
+    parse_diagnostic_fields(body, "NoticeResponse")
+        .map(|fields| diagnostic(fields, "PostgreSQL NoticeResponse"))
+}
+
+fn require_empty_backend_message(body: &[u8], label: &str) -> Result<()> {
+    if body.is_empty() {
+        return Ok(());
+    }
+    Err(protocol(format!("{label} contained trailing bytes")))
+}
+
+fn parse_ready_for_query(body: &[u8]) -> Result {
+    match body {
+        [b'I'] => Ok(ReadyStatus::Idle),
+        [b'T'] => Ok(ReadyStatus::InTransaction),
+        [b'E'] => Ok(ReadyStatus::FailedTransaction),
+        [status] => Err(protocol(format!(
+            "ReadyForQuery contained invalid transaction status 0x{status:02x}"
+        ))),
+        _ => Err(protocol(format!(
+            "ReadyForQuery contained {} bytes, expected 1",
+            body.len()
+        ))),
+    }
+}
+
+fn validate_parameter_status(mut body: &[u8]) -> Result<()> {
+    read_cstring(&mut body, "ParameterStatus name")?;
+    read_cstring(&mut body, "ParameterStatus value")?;
+    if !body.is_empty() {
+        return Err(protocol("ParameterStatus contained trailing bytes"));
+    }
+    Ok(())
+}
+
+fn validate_notification_response(mut body: &[u8]) -> Result<()> {
+    read_i32(&mut body, "NotificationResponse process id")?;
+    read_cstring(&mut body, "NotificationResponse channel")?;
+    read_cstring(&mut body, "NotificationResponse payload")?;
+    if !body.is_empty() {
+        return Err(protocol("NotificationResponse contained trailing bytes"));
+    }
+    Ok(())
+}
+
+fn read_u32(input: &mut &[u8], label: &str) -> Result {
+    let bytes = take(input, 4, label)?;
+    Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
+}
+
+fn read_i32(input: &mut &[u8], label: &str) -> Result {
+    let bytes = take(input, 4, label)?;
+    Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
+}
+
+fn read_i16(input: &mut &[u8], label: &str) -> Result {
+    let bytes = take(input, 2, label)?;
+    Ok(i16::from_be_bytes([bytes[0], bytes[1]]))
+}
+
+fn read_cstring<'a>(input: &mut &'a [u8], label: &str) -> Result<&'a str> {
+    let nul = input
+        .iter()
+        .position(|byte| *byte == 0)
+        .ok_or_else(|| protocol(format!("{label} is missing null terminator")))?;
+    let raw = &input[..nul];
+    let value = str::from_utf8(raw)
+        .map_err(|error| protocol(format!("{label} is not valid UTF-8: {error}")))?;
+    *input = &input[nul + 1..];
+    Ok(value)
+}
+
+fn take<'a>(input: &mut &'a [u8], len: usize, label: &str) -> Result<&'a [u8]> {
+    if input.len() < len {
+        return Err(protocol(format!("truncated {label}")));
+    }
+    let (head, tail) = input.split_at(len);
+    *input = tail;
+    Ok(head)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[test]
+    fn typed_rows_decode_strict_text_binary_and_null_values() {
+        let fields: Arc<[QueryField]> = vec![
+            test_field("text_int", TypeOid::INT4, QueryFormat::Text),
+            test_field("binary_int", TypeOid::INT8, QueryFormat::Binary),
+            test_field("flag", TypeOid::BOOL, QueryFormat::Binary),
+            test_field("text_bytes", TypeOid::BYTEA, QueryFormat::Text),
+            test_field("binary_bytes", TypeOid::BYTEA, QueryFormat::Binary),
+            test_field("nullable_int", TypeOid::INT4, QueryFormat::Text),
+            test_field("label", TypeOid::TEXT, QueryFormat::Text),
+        ]
+        .into();
+        let row = QueryRow {
+            fields: Arc::clone(&fields),
+            values: vec![
+                Some(b"42".to_vec()),
+                Some(9_i64.to_be_bytes().to_vec()),
+                Some(vec![1]),
+                Some(br"\x00ff".to_vec()),
+                Some(vec![0, 255]),
+                None,
+                Some(b"hello".to_vec()),
+            ],
+        };
+
+        assert_eq!(row.try_get::("text_int").unwrap(), 42);
+        assert_eq!(row.try_get::("binary_int").unwrap(), 9);
+        assert!(row.try_get::("flag").unwrap());
+        assert_eq!(
+            row.try_get::, _>("text_bytes").unwrap(),
+            vec![0, 255]
+        );
+        assert_eq!(row.try_get::<&[u8], _>("binary_bytes").unwrap(), &[0, 255]);
+        assert_eq!(row.try_get::, _>("nullable_int").unwrap(), None);
+        assert_eq!(row.try_get::<&str, _>("label").unwrap(), "hello");
+        assert!(matches!(
+            row.try_get::, _>("nullable_int"),
+            Err(DecodeError::TypeMismatch { type_oid, .. }) if type_oid == TypeOid::INT4
+        ));
+        assert!(matches!(
+            row.try_get::("text_int"),
+            Err(DecodeError::TypeMismatch { type_oid, .. }) if type_oid == TypeOid::INT4
+        ));
+    }
+
+    #[test]
+    fn query_result_accessors_report_postgres_shapes() {
+        let fields: Arc<[QueryField]> = vec![QueryField {
+            name: "value".to_owned(),
+            table_oid: 0,
+            table_attribute: 0,
+            type_oid: 25,
+            type_size: -1,
+            type_modifier: -1,
+            format: QueryFormat::Text,
+        }]
+        .into();
+        let result = QueryResult {
+            fields: Arc::clone(&fields),
+            rows: vec![QueryRow {
+                fields,
+                values: vec![Some(b"ok".to_vec())],
+            }],
+            command_tag: Some("SELECT 1".to_owned()),
+            row_count: Some(1),
+            notices: Vec::new(),
+            ready_status: ReadyStatus::Idle,
+        };
+
+        assert_eq!(result.get_text(0, "value").expect("text value"), Some("ok"));
+        assert!(result.get_text(0, "missing").is_err());
+        assert!(result.get_text(1, "value").is_err());
+        assert_eq!(result.rows()[0].values(), &[Some(b"ok".to_vec())]);
+        assert_eq!(result.rows()[0].text(0).expect("row text"), Some("ok"));
+        assert!(result.rows()[0].text(1).is_err());
+        assert!(
+            QueryRow {
+                fields: Arc::from([]),
+                values: vec![Some(vec![0xff])],
+            }
+            .text(0)
+            .is_err()
+        );
+        assert_eq!(QueryFormat::from(0), QueryFormat::Text);
+        assert_eq!(QueryFormat::from(1), QueryFormat::Binary);
+        assert_eq!(QueryFormat::from(7), QueryFormat::Other(7));
+    }
+
+    #[test]
+    fn typed_rows_validate_oids_nulls_and_duplicate_names() {
+        let fields: Arc<[QueryField]> = vec![
+            test_field("same", TypeOid::INT4, QueryFormat::Text),
+            test_field("same", TypeOid::TEXT, QueryFormat::Text),
+            test_field("bytes", TypeOid::BYTEA, QueryFormat::Binary),
+            test_field("nullable", TypeOid::INT4, QueryFormat::Text),
+        ]
+        .into();
+        let row = QueryRow {
+            fields,
+            values: vec![
+                Some(b"42".to_vec()),
+                Some(b"label".to_vec()),
+                Some(vec![0, 255]),
+                None,
+            ],
+        };
+        assert_eq!(row.try_get::(0).unwrap(), 42);
+        assert_eq!(row.try_get::(1).unwrap(), "label");
+        assert_eq!(row.try_get::<&[u8], _>("bytes").unwrap(), &[0, 255]);
+        assert_eq!(row.try_get::, _>("nullable").unwrap(), None);
+        assert!(matches!(
+            row.try_get::, _>("nullable"),
+            Err(DecodeError::TypeMismatch { type_oid, .. }) if type_oid == TypeOid::INT4
+        ));
+        assert!(matches!(
+            row.try_get::("same"),
+            Err(DecodeError::AmbiguousColumn(name)) if name == "same"
+        ));
+
+        let result = QueryResult {
+            fields: Arc::clone(&row.fields),
+            rows: vec![row],
+            command_tag: Some("SELECT 1".to_owned()),
+            row_count: Some(1),
+            notices: Vec::new(),
+            ready_status: ReadyStatus::Idle,
+        };
+        assert!(
+            result
+                .get_text(0, "same")
+                .expect_err("text lookup must reject duplicate names")
+                .to_string()
+                .contains("more than one column")
+        );
+    }
+
+    fn test_field(name: &str, type_oid: TypeOid, format: QueryFormat) -> QueryField {
+        QueryField {
+            name: name.to_owned(),
+            table_oid: 0,
+            table_attribute: 0,
+            type_oid: type_oid.get(),
+            type_size: -1,
+            type_modifier: -1,
+            format,
+        }
+    }
+}
+
+#[cfg(test)]
+mod protocol_tests {
+    use super::*;
+    fn parse_query_response_bytes(bytes: &[u8]) -> Result {
+        parse_query_response(bytes, ExpectedProtocol::Either)
+    }
+    fn assert_other_error_contains(actual: Result, expected: &str) {
+        let error = match actual {
+            Ok(_) => panic!("expected error"),
+            Err(error) => error,
+        };
+        assert!(matches!(error, Error::Protocol(_)), "{error:?}");
+        assert!(
+            error.to_string().contains(expected),
+            "{error:?} omitted {expected:?}"
+        );
+    }
+    #[test]
+    fn parses_simple_query_result() {
+        let mut bytes = Vec::new();
+        push_row_description(&mut bytes, &[("value", 23), ("empty", 25)]);
+        push_data_row(&mut bytes, &[Some("1"), None]);
+        push_command_complete(&mut bytes, "SELECT 1");
+        push_ready_for_query(&mut bytes);
+
+        let result = parse_query_response_bytes(&bytes).unwrap();
+        assert_eq!(result.fields()[0].name, "value");
+        assert_eq!(result.fields()[0].type_oid, 23);
+        assert_eq!(result.row_count(), Some(1));
+        assert_eq!(result.command_tag(), Some("SELECT 1"));
+        assert_eq!(result.get_text(0, "value").unwrap(), Some("1"));
+        assert_eq!(result.get_text(0, "empty").unwrap(), None);
+    }
+
+    #[test]
+    fn every_name_lookup_rejects_duplicate_columns() {
+        let mut bytes = Vec::new();
+        push_row_description(&mut bytes, &[("same", 25), ("same", 25)]);
+        push_data_row(&mut bytes, &[Some("first"), Some("second")]);
+        push_command_complete(&mut bytes, "SELECT 1");
+        push_ready_for_query(&mut bytes);
+
+        let result = parse_query_response_bytes(&bytes).unwrap();
+        assert!(
+            result
+                .get_text(0, "same")
+                .unwrap_err()
+                .to_string()
+                .contains("more than one column")
+        );
+        assert!(matches!(
+            result.rows()[0].try_get::("same"),
+            Err(DecodeError::AmbiguousColumn(name)) if name == "same"
+        ));
+        assert!(matches!(
+            result.rows()[0].try_get_raw("same"),
+            Err(DecodeError::AmbiguousColumn(name)) if name == "same"
+        ));
+    }
+
+    #[test]
+    fn rejects_invalid_utf8_in_backend_cstrings() {
+        let mut bytes = Vec::new();
+        push_raw_row_description(&mut bytes, &[(&[0xff], 25)]);
+        push_ready_for_query(&mut bytes);
+
+        assert_other_error_contains(
+            parse_query_response_bytes(&bytes),
+            "field name is not valid UTF-8",
+        );
+    }
+
+    #[test]
+    fn text_accessors_reject_invalid_utf8_values() {
+        let mut bytes = Vec::new();
+        push_row_description(&mut bytes, &[("value", 25)]);
+        push_data_row_raw(&mut bytes, &[Some(&[0xff])]);
+        push_command_complete(&mut bytes, "SELECT 1");
+        push_ready_for_query(&mut bytes);
+
+        let result = parse_query_response_bytes(&bytes).unwrap();
+        assert_other_error_contains(
+            result.get_text(0, "value"),
+            "query value is not valid UTF-8",
+        );
+    }
+
+    #[test]
+    fn rejects_multiple_result_sets() {
+        let mut bytes = Vec::new();
+        push_row_description(&mut bytes, &[("one", 23)]);
+        push_data_row(&mut bytes, &[Some("1")]);
+        push_command_complete(&mut bytes, "SELECT 1");
+        push_row_description(&mut bytes, &[("two", 23)]);
+        push_data_row(&mut bytes, &[Some("2")]);
+        push_command_complete(&mut bytes, "SELECT 1");
+        push_ready_for_query(&mut bytes);
+
+        assert_other_error_contains(parse_query_response_bytes(&bytes), "multiple result sets");
+    }
+
+    #[test]
+    fn accepts_extended_query_control_messages() {
+        let mut bytes = Vec::new();
+        push_backend_message(&mut bytes, b'1', &[]);
+        push_backend_message(&mut bytes, b'2', &[]);
+        push_backend_message(&mut bytes, b'n', &[]);
+        push_command_complete(&mut bytes, "INSERT 0 0");
+        push_ready_for_query(&mut bytes);
+
+        let result = parse_query_response_bytes(&bytes).unwrap();
+        assert!(result.fields().is_empty());
+        assert!(result.rows().is_empty());
+        assert_eq!(result.command_tag(), Some("INSERT 0 0"));
+    }
+
+    #[test]
+    fn accepts_backend_async_control_messages() {
+        let mut bytes = Vec::new();
+        push_parameter_status(&mut bytes, "client_encoding", "UTF8");
+        push_notice_response(&mut bytes, "NOTICE", "hello");
+        push_notification_response(&mut bytes, 123, "channel", "payload");
+        push_command_complete(&mut bytes, "SELECT 0");
+        push_ready_for_query(&mut bytes);
+
+        let result = parse_query_response_bytes(&bytes).unwrap();
+        assert_eq!(result.command_tag(), Some("SELECT 0"));
+    }
+
+    #[test]
+    fn rejects_malformed_empty_control_messages() {
+        let mut bytes = Vec::new();
+        push_backend_message(&mut bytes, b'1', &[0]);
+        push_ready_for_query(&mut bytes);
+
+        assert_other_error_contains(
+            parse_query_response_bytes(&bytes),
+            "ParseComplete contained trailing bytes",
+        );
+    }
+
+    #[test]
+    fn rejects_malformed_async_control_messages() {
+        let mut malformed_parameter = Vec::new();
+        push_backend_message(&mut malformed_parameter, b'S', b"client_encoding\0");
+        push_ready_for_query(&mut malformed_parameter);
+        assert_other_error_contains(
+            parse_query_response_bytes(&malformed_parameter),
+            "ParameterStatus value is missing null terminator",
+        );
+
+        let mut malformed_notice = Vec::new();
+        push_backend_message(&mut malformed_notice, b'N', b"SNOTICE\0");
+        push_ready_for_query(&mut malformed_notice);
+        assert_other_error_contains(
+            parse_query_response_bytes(&malformed_notice),
+            "NoticeResponse is missing terminator",
+        );
+
+        let mut malformed_notification = Vec::new();
+        let mut body = 123_i32.to_be_bytes().to_vec();
+        body.extend_from_slice(b"channel");
+        push_backend_message(&mut malformed_notification, b'A', &body);
+        push_ready_for_query(&mut malformed_notification);
+        assert_other_error_contains(
+            parse_query_response_bytes(&malformed_notification),
+            "NotificationResponse channel is missing null terminator",
+        );
+    }
+
+    #[test]
+    fn rejects_unexpected_backend_message_tags() {
+        let mut bytes = Vec::new();
+        push_backend_message(&mut bytes, b'R', &[0, 0, 0, 0]);
+        push_ready_for_query(&mut bytes);
+
+        assert_other_error_contains(
+            parse_query_response_bytes(&bytes),
+            "unexpected backend message tag 0x52",
+        );
+    }
+
+    #[test]
+    fn backend_parser_is_panic_free_for_deterministic_malformed_input() {
+        use std::panic::{AssertUnwindSafe, catch_unwind};
+
+        let mut state = 0x6f6c_6970_6861_756e_u64;
+        for case in 0..1_000 {
+            state = state
+                .wrapping_mul(6_364_136_223_846_793_005)
+                .wrapping_add(1);
+            let len = (state as usize) % 384;
+            let mut bytes = Vec::with_capacity(len);
+            for _ in 0..len {
+                state = state
+                    .wrapping_mul(6_364_136_223_846_793_005)
+                    .wrapping_add(1);
+                bytes.push((state >> 56) as u8);
+            }
+            if bytes.len() >= 5 && case % 4 == 0 {
+                bytes[0] = [b'T', b'D', b'C', b'E', b'Z', b'S', b'N', b'A'][case % 8];
+                let declared = ((state as usize % 256) as i32) - 32;
+                bytes[1..5].copy_from_slice(&declared.to_be_bytes());
+            }
+
+            assert!(
+                catch_unwind(AssertUnwindSafe(|| parse_query_response_bytes(&bytes))).is_ok(),
+                "backend parser panicked for deterministic case {case}"
+            );
+        }
+    }
+
+    #[test]
+    fn rejects_copy_and_bytes_after_ready_for_query() {
+        let mut copy = Vec::new();
+        push_backend_message(&mut copy, b'G', &[0, 0, 0]);
+        assert_other_error_contains(parse_query_response_bytes(©), "does not support COPY");
+
+        let mut trailing = Vec::new();
+        push_command_complete(&mut trailing, "SELECT 0");
+        push_ready_for_query(&mut trailing);
+        trailing.push(0);
+        assert_other_error_contains(
+            parse_query_response_bytes(&trailing),
+            "bytes after ReadyForQuery",
+        );
+    }
+
+    #[test]
+    fn accepts_ready_for_query_transaction_states() {
+        for status in [b'I', b'T', b'E'] {
+            let mut bytes = Vec::new();
+            push_command_complete(&mut bytes, "SELECT 0");
+            push_backend_message(&mut bytes, b'Z', &[status]);
+
+            let result = parse_query_response_bytes(&bytes).unwrap();
+            assert_eq!(result.command_tag(), Some("SELECT 0"));
+        }
+    }
+
+    #[test]
+    fn rejects_malformed_ready_for_query_status() {
+        let mut missing = Vec::new();
+        push_backend_message(&mut missing, b'Z', &[]);
+        assert_other_error_contains(
+            parse_query_response_bytes(&missing),
+            "ReadyForQuery contained 0 bytes, expected 1",
+        );
+
+        let mut invalid = Vec::new();
+        push_backend_message(&mut invalid, b'Z', &[0]);
+        assert_other_error_contains(
+            parse_query_response_bytes(&invalid),
+            "ReadyForQuery contained invalid transaction status 0x00",
+        );
+    }
+
+    fn push_backend_message(bytes: &mut Vec, tag: u8, body: &[u8]) {
+        bytes.push(tag);
+        bytes.extend_from_slice(&((body.len() + 4) as i32).to_be_bytes());
+        bytes.extend_from_slice(body);
+    }
+
+    fn push_row_description(bytes: &mut Vec, fields: &[(&str, u32)]) {
+        let fields = fields
+            .iter()
+            .map(|(name, type_oid)| (name.as_bytes(), *type_oid))
+            .collect::>();
+        push_raw_row_description(bytes, &fields);
+    }
+
+    fn push_raw_row_description(bytes: &mut Vec, fields: &[(&[u8], u32)]) {
+        let mut body = Vec::new();
+        body.extend_from_slice(&(fields.len() as i16).to_be_bytes());
+        for (name, type_oid) in fields {
+            body.extend_from_slice(name);
+            body.push(0);
+            body.extend_from_slice(&0_u32.to_be_bytes());
+            body.extend_from_slice(&0_i16.to_be_bytes());
+            body.extend_from_slice(&type_oid.to_be_bytes());
+            body.extend_from_slice(&(-1_i16).to_be_bytes());
+            body.extend_from_slice(&(-1_i32).to_be_bytes());
+            body.extend_from_slice(&0_i16.to_be_bytes());
+        }
+        push_backend_message(bytes, b'T', &body);
+    }
+
+    fn push_data_row(bytes: &mut Vec, values: &[Option<&str>]) {
+        let values = values
+            .iter()
+            .map(|value| value.map(str::as_bytes))
+            .collect::>();
+        push_data_row_raw(bytes, &values);
+    }
+
+    fn push_data_row_raw(bytes: &mut Vec, values: &[Option<&[u8]>]) {
+        let mut body = Vec::new();
+        body.extend_from_slice(&(values.len() as i16).to_be_bytes());
+        for value in values {
+            match value {
+                Some(value) => {
+                    body.extend_from_slice(&(value.len() as i32).to_be_bytes());
+                    body.extend_from_slice(value);
+                }
+                None => body.extend_from_slice(&(-1_i32).to_be_bytes()),
+            }
+        }
+        push_backend_message(bytes, b'D', &body);
+    }
+
+    fn push_command_complete(bytes: &mut Vec, tag: &str) {
+        let mut body = Vec::new();
+        body.extend_from_slice(tag.as_bytes());
+        body.push(0);
+        push_backend_message(bytes, b'C', &body);
+    }
+
+    fn push_notice_response(bytes: &mut Vec, severity: &str, message: &str) {
+        let mut body = Vec::new();
+        body.push(b'S');
+        body.extend_from_slice(severity.as_bytes());
+        body.push(0);
+        body.push(b'M');
+        body.extend_from_slice(message.as_bytes());
+        body.push(0);
+        body.push(0);
+        push_backend_message(bytes, b'N', &body);
+    }
+
+    fn push_parameter_status(bytes: &mut Vec, name: &str, value: &str) {
+        let mut body = Vec::new();
+        body.extend_from_slice(name.as_bytes());
+        body.push(0);
+        body.extend_from_slice(value.as_bytes());
+        body.push(0);
+        push_backend_message(bytes, b'S', &body);
+    }
+
+    fn push_notification_response(bytes: &mut Vec, pid: i32, channel: &str, payload: &str) {
+        let mut body = Vec::new();
+        body.extend_from_slice(&pid.to_be_bytes());
+        body.extend_from_slice(channel.as_bytes());
+        body.push(0);
+        body.extend_from_slice(payload.as_bytes());
+        body.push(0);
+        push_backend_message(bytes, b'A', &body);
+    }
+
+    fn push_ready_for_query(bytes: &mut Vec) {
+        push_backend_message(bytes, b'Z', b"I");
+    }
+    #[test]
+    fn execute_rejects_rows_and_directs_callers_to_query() {
+        let mut bytes = Vec::new();
+        push_row_description(&mut bytes, &[("one", 23)]);
+        push_data_row(&mut bytes, &[Some("1")]);
+        push_command_complete(&mut bytes, "SELECT 1");
+        push_row_description(&mut bytes, &[("two", 23)]);
+        push_data_row(&mut bytes, &[Some("2")]);
+        push_command_complete(&mut bytes, "SELECT 1");
+        push_ready_for_query(&mut bytes);
+
+        assert_other_error_contains(
+            parse_any_command_response(&bytes),
+            "execute() received rows; use query()",
+        );
+    }
+
+    #[test]
+    fn exec_preserves_ordered_command_and_row_results_with_notices() {
+        let mut bytes = Vec::new();
+        push_notice_response(&mut bytes, "NOTICE", "table ready");
+        push_command_complete(&mut bytes, "CREATE TABLE");
+        push_notice_response(&mut bytes, "NOTICE", "select ready");
+        push_row_description(&mut bytes, &[("answer", 23)]);
+        push_data_row(&mut bytes, &[Some("42")]);
+        push_command_complete(&mut bytes, "SELECT 1");
+        push_ready_for_query(&mut bytes);
+
+        let result = parse_exec_response(&bytes).unwrap();
+        assert_eq!(result.statements().len(), 2);
+        let StatementResult::Command(command) = &result.statements()[0] else {
+            panic!("first statement should be a command");
+        };
+        assert_eq!(command.command_tag(), Some("CREATE TABLE"));
+        assert_eq!(command.notices()[0].message, "table ready");
+        let StatementResult::Rows(rows) = &result.statements()[1] else {
+            panic!("second statement should return rows");
+        };
+        assert_eq!(rows.rows()[0].try_get::("answer").unwrap(), 42);
+        assert_eq!(rows.notices()[0].message, "select ready");
+        assert_eq!(result.notices()[0].message, "table ready");
+        assert_eq!(result.notices()[1].message, "select ready");
+    }
+
+    #[test]
+    fn single_statement_parsers_require_exactly_one_completion() {
+        let mut ready_only = Vec::new();
+        push_ready_for_query(&mut ready_only);
+        assert_other_error_contains(
+            parse_any_command_response(&ready_only),
+            "before CommandComplete or EmptyQueryResponse",
+        );
+        assert_other_error_contains(
+            parse_query_response_bytes(&ready_only),
+            "before CommandComplete or EmptyQueryResponse",
+        );
+
+        let mut empty = Vec::new();
+        push_backend_message(&mut empty, b'I', &[]);
+        push_ready_for_query(&mut empty);
+        let command = parse_any_command_response(&empty).unwrap();
+        assert_eq!(command.command_tag(), None);
+        let query = parse_query_response_bytes(&empty).unwrap();
+        assert_eq!(query.command_tag(), None);
+        assert!(query.fields().is_empty());
+        assert!(query.rows().is_empty());
+
+        let mut command_then_empty = Vec::new();
+        push_command_complete(&mut command_then_empty, "UPDATE 1");
+        push_backend_message(&mut command_then_empty, b'I', &[]);
+        push_ready_for_query(&mut command_then_empty);
+        assert_other_error_contains(
+            parse_query_response_bytes(&command_then_empty),
+            "EmptyQueryResponse after CommandComplete",
+        );
+
+        let mut empty_then_command = Vec::new();
+        push_backend_message(&mut empty_then_command, b'I', &[]);
+        push_command_complete(&mut empty_then_command, "UPDATE 1");
+        push_ready_for_query(&mut empty_then_command);
+        assert_other_error_contains(
+            parse_any_command_response(&empty_then_command),
+            "CommandComplete after EmptyQueryResponse",
+        );
+
+        let mut duplicate_empty = Vec::new();
+        push_backend_message(&mut duplicate_empty, b'I', &[]);
+        push_backend_message(&mut duplicate_empty, b'I', &[]);
+        push_ready_for_query(&mut duplicate_empty);
+        assert_other_error_contains(
+            parse_query_response_bytes(&duplicate_empty),
+            "multiple EmptyQueryResponse",
+        );
+    }
+
+    #[test]
+    fn query_rejects_messages_after_completion_and_invalid_extended_order() {
+        let mut row_after_completion = Vec::new();
+        push_row_description(
+            &mut row_after_completion,
+            &[("answer", TypeOid::INT4.get())],
+        );
+        push_command_complete(&mut row_after_completion, "SELECT 0");
+        push_data_row(&mut row_after_completion, &[Some("42")]);
+        push_ready_for_query(&mut row_after_completion);
+        assert_other_error_contains(
+            parse_query_response_bytes(&row_after_completion),
+            "DataRow after statement completion",
+        );
+
+        let mut parse_after_completion = Vec::new();
+        push_command_complete(&mut parse_after_completion, "UPDATE 1");
+        push_backend_message(&mut parse_after_completion, b'1', &[]);
+        push_ready_for_query(&mut parse_after_completion);
+        assert_other_error_contains(
+            parse_query_response_bytes(&parse_after_completion),
+            "ParseComplete out of order",
+        );
+
+        let mut bind_before_parse = Vec::new();
+        push_backend_message(&mut bind_before_parse, b'2', &[]);
+        push_backend_message(&mut bind_before_parse, b'n', &[]);
+        push_command_complete(&mut bind_before_parse, "UPDATE 1");
+        push_ready_for_query(&mut bind_before_parse);
+        assert_other_error_contains(
+            parse_query_response_bytes(&bind_before_parse),
+            "BindComplete out of order",
+        );
+
+        let mut error_after_command = Vec::new();
+        push_command_complete(&mut error_after_command, "UPDATE 1");
+        push_error_response(&mut error_after_command, "ERROR", "XX000", "too late");
+        push_ready_for_query(&mut error_after_command);
+        assert_other_error_contains(
+            parse_query_response_bytes(&error_after_command),
+            "ErrorResponse after statement completion",
+        );
+
+        let mut error_after_empty = Vec::new();
+        push_backend_message(&mut error_after_empty, b'I', &[]);
+        push_error_response(&mut error_after_empty, "ERROR", "XX000", "too late");
+        push_ready_for_query(&mut error_after_empty);
+        assert_other_error_contains(
+            parse_any_command_response(&error_after_empty),
+            "ErrorResponse after statement completion",
+        );
+
+        let mut close_complete = Vec::new();
+        push_backend_message(&mut close_complete, b'3', &[]);
+        push_command_complete(&mut close_complete, "UPDATE 1");
+        push_ready_for_query(&mut close_complete);
+        assert_other_error_contains(
+            parse_query_response_bytes(&close_complete),
+            "unexpected backend message tag 0x33",
+        );
+        assert_other_error_contains(
+            parse_any_command_response(&close_complete),
+            "unexpected backend message tag 0x33",
+        );
+    }
+
+    #[test]
+    fn exec_accepts_but_omits_empty_statements_and_requires_a_completion() {
+        let mut bytes = Vec::new();
+        push_backend_message(&mut bytes, b'I', &[]);
+        push_command_complete(&mut bytes, "UPDATE 1");
+        push_backend_message(&mut bytes, b'I', &[]);
+        push_ready_for_query(&mut bytes);
+
+        let result = parse_exec_response(&bytes).unwrap();
+        assert_eq!(result.statements().len(), 1);
+        assert!(matches!(
+            &result.statements()[0],
+            StatementResult::Command(command) if command.command_tag() == Some("UPDATE 1")
+        ));
+
+        let mut empty = Vec::new();
+        push_backend_message(&mut empty, b'I', &[]);
+        push_ready_for_query(&mut empty);
+        assert!(parse_exec_response(&empty).unwrap().statements().is_empty());
+
+        let mut ready_only = Vec::new();
+        push_ready_for_query(&mut ready_only);
+        assert_other_error_contains(
+            parse_exec_response(&ready_only),
+            "before CommandComplete or EmptyQueryResponse",
+        );
+
+        for tag in [b'1', b'2', b'3', b't', b'n'] {
+            let mut extended_control = Vec::new();
+            push_backend_message(&mut extended_control, tag, &[]);
+            push_command_complete(&mut extended_control, "UPDATE 1");
+            push_ready_for_query(&mut extended_control);
+            assert_other_error_contains(
+                parse_exec_response(&extended_control),
+                "unexpected backend message tag",
+            );
+        }
+    }
+
+    #[test]
+    fn describe_returns_parameter_oids_fields_and_notices() {
+        let mut bytes = Vec::new();
+        push_backend_message(&mut bytes, b'1', &[]);
+        push_parameter_description(&mut bytes, &[TypeOid::INT4, TypeOid::TEXT]);
+        push_notice_response(&mut bytes, "NOTICE", "described");
+        push_row_description(&mut bytes, &[("answer", TypeOid::INT8.get())]);
+        push_ready_for_query(&mut bytes);
+
+        let description = parse_statement_description(&bytes).unwrap();
+        assert_eq!(
+            description.parameter_types(),
+            &[TypeOid::INT4, TypeOid::TEXT]
+        );
+        assert_eq!(
+            description.fields().unwrap()[0].type_oid_value(),
+            TypeOid::INT8
+        );
+        assert_eq!(description.notices()[0].message, "described");
+    }
+
+    #[test]
+    fn describe_requires_parse_complete_and_protocol_order() {
+        let mut ready_only = Vec::new();
+        push_ready_for_query(&mut ready_only);
+        assert_other_error_contains(
+            parse_statement_description(&ready_only),
+            "omitted ParseComplete",
+        );
+
+        let mut parameter_before_parse = Vec::new();
+        push_parameter_description(&mut parameter_before_parse, &[]);
+        push_backend_message(&mut parameter_before_parse, b'1', &[]);
+        push_backend_message(&mut parameter_before_parse, b'n', &[]);
+        push_ready_for_query(&mut parameter_before_parse);
+        assert_other_error_contains(
+            parse_statement_description(¶meter_before_parse),
+            "ParameterDescription out of order",
+        );
+
+        let mut duplicate_parse = Vec::new();
+        push_backend_message(&mut duplicate_parse, b'1', &[]);
+        push_backend_message(&mut duplicate_parse, b'1', &[]);
+        push_parameter_description(&mut duplicate_parse, &[]);
+        push_backend_message(&mut duplicate_parse, b'n', &[]);
+        push_ready_for_query(&mut duplicate_parse);
+        assert_other_error_contains(
+            parse_statement_description(&duplicate_parse),
+            "ParseComplete out of order",
+        );
+
+        let mut result_before_parameters = Vec::new();
+        push_backend_message(&mut result_before_parameters, b'1', &[]);
+        push_row_description(
+            &mut result_before_parameters,
+            &[("answer", TypeOid::INT4.get())],
+        );
+        push_parameter_description(&mut result_before_parameters, &[]);
+        push_ready_for_query(&mut result_before_parameters);
+        assert_other_error_contains(
+            parse_statement_description(&result_before_parameters),
+            "RowDescription out of order",
+        );
+
+        let mut error_after_result = Vec::new();
+        push_backend_message(&mut error_after_result, b'1', &[]);
+        push_parameter_description(&mut error_after_result, &[]);
+        push_backend_message(&mut error_after_result, b'n', &[]);
+        push_error_response(&mut error_after_result, "ERROR", "XX000", "too late");
+        push_ready_for_query(&mut error_after_result);
+        assert_other_error_contains(
+            parse_statement_description(&error_after_result),
+            "ErrorResponse after result description",
+        );
+    }
+
+    fn push_parameter_description(bytes: &mut Vec, types: &[TypeOid]) {
+        let mut body = Vec::new();
+        body.extend_from_slice(&(types.len() as i16).to_be_bytes());
+        for type_oid in types {
+            body.extend_from_slice(&type_oid.get().to_be_bytes());
+        }
+        push_backend_message(bytes, b't', &body);
+    }
+
+    fn push_error_response(bytes: &mut Vec, severity: &str, sqlstate: &str, message: &str) {
+        let mut body = Vec::new();
+        body.push(b'S');
+        body.extend_from_slice(severity.as_bytes());
+        body.push(0);
+        body.push(b'C');
+        body.extend_from_slice(sqlstate.as_bytes());
+        body.push(0);
+        body.push(b'M');
+        body.extend_from_slice(message.as_bytes());
+        body.push(0);
+        body.push(0);
+        push_backend_message(bytes, b'E', &body);
+    }
+
+    fn parse_any_command_response(bytes: &[u8]) -> Result {
+        crate::parse_command_response(bytes, ExpectedProtocol::Either)
+    }
+    #[test]
+    fn simple_query_encodes_one_postgres_message() {
+        assert_eq!(
+            simple_query("SELECT 1").expect("valid simple query"),
+            b"Q\0\0\0\rSELECT 1\0".as_slice()
+        );
+    }
+
+    #[test]
+    fn postgres_error_preserves_ordered_fields() {
+        let error = parse_postgres_error(
+            b"SERREUR\0VERROR\0C23505\0Mduplicate key\0DKey already exists\0titems\0p12\0qSELECT broken\0Fparse_expr.c\0L123\0RtransformExpr\0\0",
+        )
+        .expect("valid ErrorResponse");
+
+        assert_eq!(error.severity.as_deref(), Some("ERREUR"));
+        assert_eq!(error.localized_severity.as_deref(), Some("ERREUR"));
+        assert_eq!(error.nonlocalized_severity.as_deref(), Some("ERROR"));
+        assert_eq!(error.sqlstate.as_deref(), Some("23505"));
+        assert_eq!(error.message, "duplicate key");
+        assert_eq!(error.detail.as_deref(), Some("Key already exists"));
+        assert_eq!(error.table_name.as_deref(), Some("items"));
+        assert_eq!(error.internal_position.as_deref(), Some("12"));
+        assert_eq!(error.internal_query.as_deref(), Some("SELECT broken"));
+        assert_eq!(error.file.as_deref(), Some("parse_expr.c"));
+        assert_eq!(error.line.as_deref(), Some("123"));
+        assert_eq!(error.routine.as_deref(), Some("transformExpr"));
+        assert_eq!(
+            error
+                .fields
+                .iter()
+                .map(|field| field.code)
+                .collect::>(),
+            [
+                b'S', b'V', b'C', b'M', b'D', b't', b'p', b'q', b'F', b'L', b'R'
+            ]
+        );
+        assert_eq!(error.to_string(), "ERREUR [23505]: duplicate key");
+    }
+
+    #[test]
+    fn postgres_error_display_handles_partial_identity() {
+        let error = |severity: Option<&str>, sqlstate: Option<&str>| PostgresError {
+            severity: severity.map(str::to_owned),
+            localized_severity: severity.map(str::to_owned),
+            nonlocalized_severity: None,
+            sqlstate: sqlstate.map(str::to_owned),
+            message: "failed".to_owned(),
+            detail: None,
+            hint: None,
+            position: None,
+            internal_position: None,
+            internal_query: None,
+            where_: None,
+            schema_name: None,
+            table_name: None,
+            column_name: None,
+            data_type_name: None,
+            constraint_name: None,
+            file: None,
+            line: None,
+            routine: None,
+            fields: Vec::new(),
+            notices: Vec::new(),
+        };
+
+        assert_eq!(error(Some("ERROR"), None).to_string(), "ERROR: failed");
+        assert_eq!(error(None, Some("XX000")).to_string(), "[XX000]: failed");
+        assert_eq!(error(None, None).to_string(), "failed");
+    }
+
+    #[test]
+    fn parameter_conversions_feed_the_extended_protocol() {
+        let owned = "owned".to_owned();
+        let params = vec![
+            Parameter::text("text"),
+            Parameter::binary([1_u8, 2]),
+            "borrowed".into_parameter(),
+            owned.clone().into_parameter(),
+            (&owned).into_parameter(),
+            1_i16.into_parameter(),
+            2_i32.into_parameter(),
+            3_i64.into_parameter(),
+            4.5_f32.into_parameter(),
+            6.25_f64.into_parameter(),
+            true.into_parameter(),
+            (&[7_u8, 8][..]).into_parameter(),
+            vec![9_u8].into_parameter(),
+            Some("optional").into_parameter(),
+            None::<&str>.into_parameter(),
+        ];
+
+        let packet = extended_statement("SELECT $1", ¶ms, ValueFormat::Text.code())
+            .expect("valid extended query");
+        assert_eq!(packet.first(), Some(&b'P'));
+        assert!(packet.contains(&b'B'));
+        assert!(extended_statement("SELECT\0$1", &[], ValueFormat::Text.code()).is_err());
+        let too_many = vec![Parameter::null(); i16::MAX as usize + 1];
+        assert!(extended_statement("SELECT 1", &too_many, ValueFormat::Text.code()).is_err());
+    }
+
+    fn parse_postgres_error(body: &[u8]) -> Result {
+        Ok(PostgresError::from_core(diagnostic(
+            parse_diagnostic_fields(body, "ErrorResponse")?,
+            "PostgreSQL ErrorResponse",
+        )))
+    }
+}
+
+/// PostgreSQL connection framing independent of an execution backend.
+pub mod wire;
diff --git a/src/sdks/rust-query/src/wire.rs b/src/sdks/rust-query/src/wire.rs
new file mode 100644
index 000000000..ff040fea8
--- /dev/null
+++ b/src/sdks/rust-query/src/wire.rs
@@ -0,0 +1,267 @@
+//! PostgreSQL frontend framing and connection control messages, independent of any runtime.
+use std::io::{Error, ErrorKind, Result};
+
+macro_rules! anyhow { ($($args:tt)*) => { Error::new(ErrorKind::InvalidData, format!($($args)*)) }; }
+macro_rules! bail { ($($args:tt)*) => { return Err(anyhow!($($args)*)) }; }
+
+pub const SSL_REQUEST_CODE: i32 = 80_877_103;
+pub const GSSENC_REQUEST_CODE: i32 = 80_877_104;
+pub const CANCEL_REQUEST_CODE: i32 = 80_877_102;
+pub const PROTOCOL_3: i32 = 196_608;
+pub const MAX_FRONTEND_MESSAGE: usize = 128 * 1024 * 1024;
+
+#[derive(Default)]
+pub struct FrontendFrameReader {
+    buffer: Vec,
+}
+
+impl FrontendFrameReader {
+    pub fn append(&mut self, input: &[u8]) {
+        self.buffer.extend_from_slice(input);
+    }
+
+    pub fn next_frame(&mut self) -> Result>> {
+        let Some(message_len) = frontend_message_len_if_complete(&self.buffer)? else {
+            return Ok(None);
+        };
+        Ok(Some(self.buffer.drain(..message_len).collect()))
+    }
+
+    pub fn push(&mut self, input: &[u8]) -> Result>> {
+        self.append(input);
+        let mut messages = Vec::new();
+        while let Some(message) = self.next_frame()? {
+            messages.push(message);
+        }
+        Ok(messages)
+    }
+
+    pub fn pending(&self) -> &[u8] {
+        &self.buffer
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum FrontendFrameKind {
+    Protocol,
+    Startup,
+    SslOrGssRequest,
+    CancelRequest,
+    Terminate,
+}
+
+pub fn frontend_message_len_if_complete(buffer: &[u8]) -> Result> {
+    if buffer.len() < 4 {
+        return Ok(None);
+    }
+
+    if buffer[0] == 0 {
+        let len = i32::from_be_bytes(buffer[0..4].try_into().unwrap());
+        if len < 8 {
+            bail!("invalid startup packet length {len}");
+        }
+        let len = len as usize;
+        if len > MAX_FRONTEND_MESSAGE {
+            bail!("startup/control packet length {len} exceeds limit");
+        }
+        return Ok((buffer.len() >= len).then_some(len));
+    }
+
+    if buffer.len() < 5 {
+        return Ok(None);
+    }
+    let len = i32::from_be_bytes(buffer[1..5].try_into().unwrap());
+    if len < 4 {
+        bail!("invalid frontend message length {len}");
+    }
+    let total = 1usize
+        .checked_add(len as usize)
+        .ok_or_else(|| anyhow!("frontend message length overflow"))?;
+    if total > MAX_FRONTEND_MESSAGE {
+        bail!("frontend message length {total} exceeds limit");
+    }
+    Ok((buffer.len() >= total).then_some(total))
+}
+
+pub fn classify_frontend_message(message: &[u8]) -> Result {
+    if message.is_empty() {
+        bail!("empty frontend message");
+    }
+
+    if message[0] == 0 {
+        if message.len() < 8 {
+            bail!("startup/control packet is too short");
+        }
+        let code = i32::from_be_bytes(message[4..8].try_into().unwrap());
+        return Ok(match code {
+            SSL_REQUEST_CODE | GSSENC_REQUEST_CODE => FrontendFrameKind::SslOrGssRequest,
+            CANCEL_REQUEST_CODE => FrontendFrameKind::CancelRequest,
+            PROTOCOL_3 => FrontendFrameKind::Startup,
+            other => bail!("unsupported startup/control packet code {other}"),
+        });
+    }
+
+    if message[0] == b'X' {
+        return Ok(FrontendFrameKind::Terminate);
+    }
+
+    Ok(FrontendFrameKind::Protocol)
+}
+
+pub fn startup_parameter<'a>(message: &'a [u8], wanted: &str) -> Result> {
+    Ok(startup_parameters(message)?.get(wanted).copied())
+}
+
+/// Decode one complete protocol 3.0 startup packet without accepting ambiguous
+/// duplicate keys or ignoring bytes after the terminating empty key.
+pub fn startup_parameters(message: &[u8]) -> Result> {
+    if message.len() < 9
+        || frontend_message_len_if_complete(message)? != Some(message.len())
+        || i32::from_be_bytes(message[4..8].try_into().unwrap()) != PROTOCOL_3
+    {
+        bail!("expected one complete PostgreSQL protocol 3.0 startup packet");
+    }
+    let mut parameters = std::collections::BTreeMap::new();
+    let mut cursor = 8usize;
+    while cursor < message.len() {
+        if message[cursor] == 0 {
+            if cursor + 1 != message.len() {
+                bail!("startup packet contains bytes after its terminator");
+            }
+            return Ok(parameters);
+        }
+        let key_end = message[cursor..]
+            .iter()
+            .position(|byte| *byte == 0)
+            .map(|offset| cursor + offset)
+            .ok_or_else(|| anyhow!("startup parameter key is not nul-terminated"))?;
+        let key = std::str::from_utf8(&message[cursor..key_end])
+            .map_err(|error| anyhow!("startup parameter key is not UTF-8: {error}"))?;
+        cursor = key_end + 1;
+
+        let value_end = message[cursor..]
+            .iter()
+            .position(|byte| *byte == 0)
+            .map(|offset| cursor + offset)
+            .ok_or_else(|| anyhow!("startup parameter value is not nul-terminated"))?;
+        let value = std::str::from_utf8(&message[cursor..value_end])
+            .map_err(|error| anyhow!("startup parameter value is not UTF-8: {error}"))?;
+        cursor = value_end + 1;
+        if parameters.insert(key, value).is_some() {
+            bail!("duplicate startup parameter {key}");
+        }
+    }
+    bail!("startup packet is missing its terminating empty key");
+}
+
+pub fn response_contains_error(response: &[u8]) -> bool {
+    response_contains_tag(response, b'E')
+}
+
+pub fn response_contains_tag(response: &[u8], expected: u8) -> bool {
+    let mut cursor = 0usize;
+    while cursor + 5 <= response.len() {
+        let tag = response[cursor];
+        let len = i32::from_be_bytes(response[cursor + 1..cursor + 5].try_into().unwrap());
+        if len < 4 {
+            return false;
+        }
+        let total = 1usize.saturating_add(len as usize);
+        if cursor + total > response.len() {
+            return false;
+        }
+        if tag == expected {
+            return true;
+        }
+        cursor += total;
+    }
+    false
+}
+
+pub fn error_response(severity: &str, code: &str, message: &str) -> Vec {
+    let mut body = Vec::new();
+    push_error_field(&mut body, b'S', severity);
+    push_error_field(&mut body, b'V', severity);
+    push_error_field(&mut body, b'C', code);
+    push_error_field(&mut body, b'M', message);
+    body.push(0);
+
+    let mut response = Vec::with_capacity(body.len() + 5);
+    response.push(b'E');
+    response.extend_from_slice(&((body.len() + 4) as i32).to_be_bytes());
+    response.extend_from_slice(&body);
+    response
+}
+
+fn push_error_field(body: &mut Vec, tag: u8, value: &str) {
+    body.push(tag);
+    body.extend_from_slice(value.as_bytes());
+    body.push(0);
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn startup(body: &[u8]) -> Vec {
+        let mut packet = ((body.len() + 8) as i32).to_be_bytes().to_vec();
+        packet.extend(PROTOCOL_3.to_be_bytes());
+        packet.extend(body);
+        packet
+    }
+
+    #[test]
+    fn startup_parser_validates_the_entire_packet() -> Result<()> {
+        let packet = startup(b"user\0postgres\0application_name\0a'b\0\0");
+        assert_eq!(startup_parameter(&packet, "user")?, Some("postgres"));
+        assert_eq!(
+            startup_parameters(&packet)?.get("application_name"),
+            Some(&"a'b")
+        );
+        for body in [
+            b"user\0first\0user\0second\0\0".as_slice(),
+            b"user\0postgres\0\0ignored",
+            b"user\0postgres\0",
+            b"user\0postgres\0key\0",
+            b"user\0postgres\0bad\0\xff\0\0",
+        ] {
+            assert!(startup_parameter(&startup(body), "user").is_err());
+        }
+        let mut length_mismatch = packet.clone();
+        length_mismatch.push(0);
+        assert!(startup_parameters(&length_mismatch).is_err());
+        let mut unsupported = packet;
+        unsupported[7] = 2;
+        assert!(startup_parameters(&unsupported).is_err());
+        Ok(())
+    }
+
+    #[test]
+    fn frame_reader_buffers_split_messages() -> Result<()> {
+        let query = b"Q\0\0\0\rSELECT 1\0";
+        let mut reader = FrontendFrameReader::default();
+        assert!(reader.push(&query[..3])?.is_empty());
+        assert_eq!(reader.push(&query[3..])?, vec![query.to_vec()]);
+        Ok(())
+    }
+
+    #[test]
+    fn classifies_startup_and_control_packets() -> Result<()> {
+        let mut startup = Vec::new();
+        startup.extend_from_slice(&8_i32.to_be_bytes());
+        startup.extend_from_slice(&PROTOCOL_3.to_be_bytes());
+        assert_eq!(
+            classify_frontend_message(&startup)?,
+            FrontendFrameKind::Startup
+        );
+
+        let mut ssl = Vec::new();
+        ssl.extend_from_slice(&8_i32.to_be_bytes());
+        ssl.extend_from_slice(&SSL_REQUEST_CODE.to_be_bytes());
+        assert_eq!(
+            classify_frontend_message(&ssl)?,
+            FrontendFrameKind::SslOrGssRequest
+        );
+        Ok(())
+    }
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/CHANGELOG.md b/src/sdks/rust-wasix/CHANGELOG.md
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/CHANGELOG.md
rename to src/sdks/rust-wasix/CHANGELOG.md
diff --git a/src/sdks/rust-wasix/Cargo.toml b/src/sdks/rust-wasix/Cargo.toml
new file mode 100644
index 000000000..e851083af
--- /dev/null
+++ b/src/sdks/rust-wasix/Cargo.toml
@@ -0,0 +1,154 @@
+[package]
+name = "oliphaunt-wasix"
+version = "0.2.0"
+edition = "2024"
+rust-version = "1.93"
+description = "Embedded PostgreSQL 18 for Rust with synchronous and asynchronous APIs."
+readme = "README.md"
+repository = "https://github.com/f0rr0/oliphaunt"
+homepage = "https://oliphaunt.dev"
+documentation = "https://docs.rs/oliphaunt-wasix"
+keywords = ["postgres", "oliphaunt", "wasm", "database", "embedded"]
+categories = ["database-implementations", "wasm", "development-tools::testing"]
+license = "MIT"
+links = "oliphaunt_artifact_wasix_relay"
+build = "build.rs"
+exclude = [
+  "Cargo.toml.orig",
+  "moon.yml",
+  "release.toml",
+  "tools/**",
+]
+
+[package.metadata.oliphaunt]
+runtime-version = "0.2.0"
+
+[features]
+default = []
+__internal-napi = []
+extensions = []
+tools-execution = []
+tools = [
+  "tools-execution",
+  "dep:oliphaunt-wasix-tools",
+  "dep:oliphaunt-wasix-tools-aot-aarch64-apple-darwin",
+  "dep:oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu",
+  "dep:oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc",
+  "dep:oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu",
+]
+extension-amcheck = ["extensions", "liboliphaunt-wasix-portable/extension-amcheck"]
+extension-auto-explain = ["extensions", "liboliphaunt-wasix-portable/extension-auto-explain"]
+extension-bloom = ["extensions", "liboliphaunt-wasix-portable/extension-bloom"]
+extension-btree-gin = ["extensions", "liboliphaunt-wasix-portable/extension-btree-gin"]
+extension-btree-gist = ["extensions", "liboliphaunt-wasix-portable/extension-btree-gist"]
+extension-citext = ["extensions", "liboliphaunt-wasix-portable/extension-citext"]
+extension-cube = ["extensions", "liboliphaunt-wasix-portable/extension-cube"]
+extension-dict-int = ["extensions", "liboliphaunt-wasix-portable/extension-dict-int"]
+extension-dict-xsyn = ["extensions", "liboliphaunt-wasix-portable/extension-dict-xsyn"]
+extension-earthdistance = [
+  "extensions",
+  "extension-cube",
+  "liboliphaunt-wasix-portable/extension-earthdistance",
+]
+extension-file-fdw = ["extensions", "liboliphaunt-wasix-portable/extension-file-fdw"]
+extension-fuzzystrmatch = ["extensions", "liboliphaunt-wasix-portable/extension-fuzzystrmatch"]
+extension-hstore = ["extensions", "liboliphaunt-wasix-portable/extension-hstore"]
+extension-intarray = ["extensions", "liboliphaunt-wasix-portable/extension-intarray"]
+extension-isn = ["extensions", "liboliphaunt-wasix-portable/extension-isn"]
+extension-lo = ["extensions", "liboliphaunt-wasix-portable/extension-lo"]
+extension-ltree = ["extensions", "liboliphaunt-wasix-portable/extension-ltree"]
+extension-pageinspect = ["extensions", "liboliphaunt-wasix-portable/extension-pageinspect"]
+extension-pg-buffercache = ["extensions", "liboliphaunt-wasix-portable/extension-pg-buffercache"]
+extension-pg-freespacemap = ["extensions", "liboliphaunt-wasix-portable/extension-pg-freespacemap"]
+extension-pg-hashids = ["extensions", "liboliphaunt-wasix-portable/extension-pg-hashids"]
+extension-pg-ivm = ["extensions", "liboliphaunt-wasix-portable/extension-pg-ivm"]
+extension-pg-surgery = ["extensions", "liboliphaunt-wasix-portable/extension-pg-surgery"]
+extension-pg-textsearch = ["extensions", "liboliphaunt-wasix-portable/extension-pg-textsearch"]
+extension-pg-trgm = ["extensions", "liboliphaunt-wasix-portable/extension-pg-trgm"]
+extension-pg-uuidv7 = ["extensions", "liboliphaunt-wasix-portable/extension-pg-uuidv7"]
+extension-pg-visibility = ["extensions", "liboliphaunt-wasix-portable/extension-pg-visibility"]
+extension-pg-walinspect = ["extensions", "liboliphaunt-wasix-portable/extension-pg-walinspect"]
+extension-pgcrypto = ["extensions", "liboliphaunt-wasix-portable/extension-pgcrypto"]
+extension-pgtap = ["extensions", "liboliphaunt-wasix-portable/extension-pgtap"]
+extension-postgis = ["extensions", "liboliphaunt-wasix-portable/extension-postgis"]
+extension-seg = ["extensions", "liboliphaunt-wasix-portable/extension-seg"]
+extension-tablefunc = ["extensions", "liboliphaunt-wasix-portable/extension-tablefunc"]
+extension-tcn = ["extensions", "liboliphaunt-wasix-portable/extension-tcn"]
+extension-tsm-system-rows = ["extensions", "liboliphaunt-wasix-portable/extension-tsm-system-rows"]
+extension-tsm-system-time = ["extensions", "liboliphaunt-wasix-portable/extension-tsm-system-time"]
+extension-unaccent = ["extensions", "liboliphaunt-wasix-portable/extension-unaccent"]
+extension-uuid-ossp = ["extensions", "liboliphaunt-wasix-portable/extension-uuid-ossp"]
+extension-vector = ["extensions", "liboliphaunt-wasix-portable/extension-vector"]
+icu = ["dep:oliphaunt-icu"]
+
+[dependencies]
+oliphaunt-query = { version = "0.1.0", path = "../rust-query" }
+anyhow = "1"
+async-trait = "0.1"
+cap-fs-ext = "4"
+cap-std = "4"
+tar = "0.4"
+zstd = { version = "0.13", default-features = false }
+directories = "6"
+tracing = "0.1"
+flate2 = "1"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+tempfile = "3"
+sha2 = "0.10"
+dunce = "1"
+filetime = "0.2"
+liboliphaunt-wasix-portable = { version = "*", path = "../../runtimes/liboliphaunt-wasix/crates/assets" }
+oliphaunt-wasix-tools = { version = "*", path = "../../postgres-tools/wasix/crates/tools", optional = true }
+oliphaunt-icu = { version = "*", path = "../../database-resources/icu/cargo", optional = true }
+tokio = { version = "1", features = ["io-util", "rt-multi-thread", "sync"] }
+wasmer = { version = "=7.2.1", default-features = false, features = [
+  "sys",
+  "headless",
+  "compiler",
+  "wasmer-artifact-load",
+] }
+# Wasmer-WASIX 0.x crates use compatible ranges for packages in their own
+# release family. Keep the complete family constrained here so a fresh
+# consumer cannot silently mix a later patch generation with the runtime and
+# AOT artifacts built against this exact toolchain.
+wasmer-config = { version = "=0.702.1", default-features = false }
+wasmer-journal = { version = "=0.702.1", default-features = false }
+wasmer-package = { version = "=0.702.1", default-features = false }
+wasmer-types = "=7.2.1"
+wasmer-wasix = { version = "=0.702.1", default-features = false, features = [
+  "sys-minimal",
+  "sys-poll",
+  "host-vnet",
+  "time",
+] }
+wasmer-wasix-types = { version = "=0.702.1", default-features = false }
+virtual-fs = { version = "=0.702.1", default-features = false }
+virtual-mio = { version = "=0.702.1", default-features = false }
+virtual-net = { version = "=0.702.1", default-features = false }
+webc = "=12.0.0"
+
+[target.'cfg(all(target_os = "macos", target_arch = "aarch64"))'.dependencies]
+liboliphaunt-wasix-aot-aarch64-apple-darwin = { version = "*", path = "../../runtimes/liboliphaunt-wasix/crates/aot/aarch64-apple-darwin" }
+oliphaunt-wasix-tools-aot-aarch64-apple-darwin = { version = "*", path = "../../postgres-tools/wasix/crates/aot/aarch64-apple-darwin", optional = true }
+
+[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dependencies]
+liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu = { version = "*", path = "../../runtimes/liboliphaunt-wasix/crates/aot/x86_64-unknown-linux-gnu" }
+oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu = { version = "*", path = "../../postgres-tools/wasix/crates/aot/x86_64-unknown-linux-gnu", optional = true }
+
+[target.'cfg(all(target_os = "linux", target_arch = "aarch64", target_env = "gnu"))'.dependencies]
+liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu = { version = "*", path = "../../runtimes/liboliphaunt-wasix/crates/aot/aarch64-unknown-linux-gnu" }
+oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu = { version = "*", path = "../../postgres-tools/wasix/crates/aot/aarch64-unknown-linux-gnu", optional = true }
+
+[target.'cfg(all(target_os = "windows", target_arch = "x86_64", target_env = "msvc"))'.dependencies]
+liboliphaunt-wasix-aot-x86_64-pc-windows-msvc = { version = "*", path = "../../runtimes/liboliphaunt-wasix/crates/aot/x86_64-pc-windows-msvc" }
+oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc = { version = "*", path = "../../postgres-tools/wasix/crates/aot/x86_64-pc-windows-msvc", optional = true }
+
+[dev-dependencies]
+tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }
+tokio-postgres = "0.7"
+
+[[bin]]
+name = "oliphaunt-wasix-dump"
+path = "src/bin/oliphaunt_wasix_dump.rs"
+required-features = ["tools"]
diff --git a/src/sdks/rust-wasix/README.md b/src/sdks/rust-wasix/README.md
new file mode 100644
index 000000000..911a748f8
--- /dev/null
+++ b/src/sdks/rust-wasix/README.md
@@ -0,0 +1,309 @@
+# `oliphaunt-wasix`
+
+Embedded PostgreSQL 18 for Rust through the canonical `liboliphaunt-wasix`
+runtime. The root API is synchronous and runs PostgreSQL directly on the
+calling thread. Its retained Wasmer store is thread-affine, so root `Oliphaunt`
+is `!Send + !Sync` and must be created, used, closed, and dropped on one OS
+thread. Applications that need a movable/shared handle or need to keep an async
+executor responsive use the cloneable `Send + Sync` root `AsyncOliphaunt`
+handle, which owns a dedicated database thread.
+
+The separate `oliphaunt-pgwire-server` package exposes this runtime through a
+one-client local PostgreSQL endpoint.
+
+```sh
+cargo add oliphaunt-wasix
+```
+
+## Direct API
+
+```rust,no_run
+use oliphaunt_wasix::{DatabaseStorage, Error, Oliphaunt};
+
+fn main() -> anyhow::Result<()> {
+    let mut database = Oliphaunt::builder()
+        .storage(DatabaseStorage::Directory("./data/main".into()))
+        .startup_guc("work_mem", "8MB")
+        .open()?;
+
+    database.execute("CREATE TABLE items(id integer PRIMARY KEY, value text NOT NULL)")?;
+    database
+        .sql("INSERT INTO items VALUES ($1, $2)")
+        .bind(1_i32)
+        .bind("hello")
+        .execute()?;
+    let result = database.query_with_params(
+        "SELECT value FROM items WHERE id = $1",
+        [1_i32],
+    )?;
+    assert_eq!(result.get_text(0, "value")?, Some("hello"));
+
+    database.transaction(|transaction| {
+        transaction.execute("UPDATE items SET value = 'committed' WHERE id = 1")?;
+        Ok::<(), Error>(())
+    })?;
+    database.close()?;
+    Ok(())
+}
+```
+
+The root `Oliphaunt` is the no-hop database. Opening, queries, transactions,
+backup, restore, and close run synchronously on the calling thread. The handle
+is deliberately thread-affine and exclusive: it is `!Send + !Sync`, database
+methods take `&mut self`, and a transaction borrows that handle. Create, use,
+close, and drop it on one OS thread. This makes execution placement and ordering
+explicit without an internal queue or message boundary.
+
+Starting close permanently retires the handle. `is_closed()` becomes true,
+later work is rejected, and repeated close calls replay the first terminal
+result. A transaction callback panic is caught long enough to attempt rollback;
+the original panic is then resumed. If rollback or commit cannot be confirmed,
+the database is poisoned until close.
+
+`execute` and `query` are the parameter-free forms;
+`execute_with_params` and `query_with_params` use PostgreSQL positional
+parameters. Query rows retain ordered raw bytes and expose OID-aware typed
+access through `FromSql`. Natural Rust values use `IntoParameter` and carry
+their PostgreSQL type OID and preferred encoding. `Parameter` provides
+explicit OID, format, and nullable bytes; its `text`, `binary`, and `null`
+constructors leave the OID for PostgreSQL to infer. An explicit OID 0 is
+accepted by `describe` because it is PostgreSQL's wire-level inference
+sentinel; an absent OID is the single execution spelling for inference. `exec`
+returns ordered simple-query
+results, `describe` resolves
+wire metadata without executing, and the database and transaction publish
+`is_closed()`. `query` also accepts command-only statements, returning empty
+fields and rows while retaining the command tag and affected-row count. A
+transaction mirrors the structured methods and supports explicit `rollback()`
+without a later commit.
+
+Managed transaction handles intentionally omit raw-protocol methods. Do not
+send transaction lifecycle SQL (`BEGIN`, `COMMIT`, `END`, `ROLLBACK`, or
+`AND CHAIN`) through their structured methods; use callback completion or
+`rollback()` instead. Savepoints, including `ROLLBACK TO SAVEPOINT`, remain
+ordinary transaction work. Use the root database's raw-protocol adapter only
+when the application deliberately owns the full PostgreSQL session state.
+
+Transaction callbacks return ordinary `Result` with `E: From`, so
+database work uses `?` while typed business aborts stay application-owned. The
+outer `TransactionResult` distinguishes callback failure, an actually
+attempted rollback failure, and an independent database/protocol failure for
+which no rollback was sent.
+
+`exec_protocol_raw` is the buffered escape hatch for callers that need
+PostgreSQL frontend-protocol bytes. `exec_protocol_raw_stream` delivers
+bounded callback chunks and streams COPY output through the guest protocol
+pump instead of accumulating the complete response. Ordinary fallible methods
+return the crate-owned `Result`; transactions and streams use the generic
+`TransactionResult` and `RawStreamResult` wrappers. The opaque
+`Error` implements `std::error::Error`, exposes a stable non-exhaustive
+`ErrorKind` through `kind()`, and offers `postgres_error()`; PostgreSQL failures return the exported
+`PostgresError` details, notices, and SQLSTATE. Failed rollback or an uncertain
+COMMIT poisons the database and never sends a misleading second control command.
+Streaming callbacks execute synchronously before the direct method returns and
+provide backpressure to PostgreSQL. The retained WASIX stdio attachment requires
+the callback to own `Send + 'static` captures; use `Arc>` for mutable
+state. Return `()` for infallible delivery or `Result<(), E>` for a typed stop.
+A callback error or panic is surfaced only after a successful guest protocol
+pump confirms recovery. Direct callback panics then resume; async owner-thread
+panics become `RawStreamError::CallbackPanicked` without poisoning. If the pump
+fails, `RawStreamError::Database` is authoritative, the database becomes
+close-only, and a retained callback panic is not resumed into an unknown session
+state. WASIX query cancellation is intentionally absent
+until the guest runtime can interrupt execution and prove protocol recovery.
+
+The builder also supports `username`, `database`, `startup_gucs`, and bundled
+`extension`/`extensions` when the corresponding crate features are enabled.
+Selecting an extension makes its artifact and required pre-start configuration
+available; it never runs `CREATE EXTENSION`, `LOAD`, or migration SQL. Install
+database-local objects explicitly through your normal migrations. Each
+associated selector is compiled only by its matching `extension-*` feature;
+`Extension::ALL` and `Extension::by_sql_name` therefore describe exactly the
+artifacts enabled in the current Cargo build, not the full packaging catalog.
+
+## Storage and physical backup
+
+`DatabaseStorage::Memory` is the default and keeps mutable PGDATA in Wasmer's
+memory filesystem. `DatabaseStorage::Directory(path)` persists a managed root;
+the caller-supplied Rust path must be nonempty and contain no NUL bytes:
+
+```text
+data/main/
+├── .oliphaunt.json
+└── pgdata/
+```
+
+A new empty root runs the runtime's initializer, or imports an explicitly selected
+seed supplied through `.seed(ClusterSeed::new(archive, manifest))`. Seed Cargo
+packages expose `seed_archive()` and `seed_manifest()` for this purpose; selecting
+a seed does not change where mutable PGDATA is stored. Supply canonical ICU data
+with `.icu_data(IcuData::new(data_bytes, manifest_bytes)?)`; this validates the
+data and selects the ICU profile without embedding a data carrier in the SDK.
+The optional `icu` Cargo feature selects the separately owned ICU data carrier
+as a convenience. Standard builds do not include ICU data. An ICU database needs
+its selected ICU data on every open; its initialization seed is needed only once.
+
+An existing root requires no seed and must contain an exact descriptor and complete PostgreSQL 18 PGDATA;
+incomplete or unexpected contents fail without being adopted, deleted, or
+reinitialized.
+
+Rust uses one stable sibling advisory lock for both open and restore. It
+coordinates Rust WASIX and native-host WASIX TypeScript owners of that path,
+including before a new root exists, because the Node-API path delegates
+directory ownership to this Rust runtime. Sequential cross-binding root handoff
+is not yet a supported or qualified workflow.
+
+Physical backup is a PostgreSQL online backup in a plain tar archive:
+
+```rust,no_run
+use oliphaunt_wasix::{DatabaseStorage, Oliphaunt};
+
+fn main() -> anyhow::Result<()> {
+    let mut source = Oliphaunt::open()?;
+    let backup = source.backup()?;
+    source.close()?;
+
+    Oliphaunt::restore("./data/restored", backup)?;
+    let mut restored = Oliphaunt::builder()
+        .storage(DatabaseStorage::Directory("./data/restored".into()))
+        .open()?;
+    restored.close()?;
+    Ok(())
+}
+```
+
+`restore` accepts an absent or empty directory, validates and stages the whole
+archive, then publishes the managed root. The archive contains `pgdata/**` and
+`.oliphaunt/backup-manifest.properties`; it does not contain the destination's
+`.oliphaunt.json` descriptor. Physical archives are for the same PostgreSQL
+major and WASIX physical format. Restore is synchronous; once publication
+starts, it runs to completion or returns an error. Use logical dump/restore for
+upgrades.
+
+## Standard PostgreSQL clients and tools
+
+Use the separate [`oliphaunt-pgwire-server`](../../pgwire-server) library or CLI
+to connect an ordinary PostgreSQL driver to an embedded WASIX database.
+
+With the `tools` feature, an open database gains fluent methods for the matching
+packaged WASIX PostgreSQL programs. The optional `tools` namespace contains
+their options and structured error type:
+
+```rust,no_run
+# #[cfg(feature = "tools")]
+use oliphaunt_wasix::{Oliphaunt, tools};
+
+# #[cfg(feature = "tools")]
+fn main() -> anyhow::Result<()> {
+    let mut source = Oliphaunt::open()?;
+    let sql = source.pg_dump(tools::PgDumpOptions::new().arg("--schema-only"))?;
+    source.close()?;
+    let mut target = Oliphaunt::open()?;
+    target.psql(tools::PsqlOptions::new().script(sql))?;
+    target.close()?;
+    Ok(())
+}
+
+# #[cfg(not(feature = "tools"))]
+# fn main() {}
+```
+
+`pg_dump` returns standard plain PostgreSQL SQL unchanged. `psql` is
+non-interactive and accepts a command, a script, or ordinary passthrough
+arguments. Connection, file input/output, format, compression, encoding, and
+parallel-job flags are managed and rejected from passthrough arguments. Direct
+tools are exclusive operations on the database and reset session state before
+and after the tool run.
+
+## Asynchronous API
+
+Use `AsyncOliphaunt` when PostgreSQL must not block the calling async executor:
+
+```rust,no_run
+use oliphaunt_wasix::AsyncOliphaunt;
+
+#[tokio::main]
+async fn main() -> oliphaunt_wasix::Result<()> {
+    let database = AsyncOliphaunt::open().await?;
+    let rows = database.query("SELECT 42::int4 AS answer").await?;
+    assert_eq!(rows.get_text(0, "answer")?, Some("42"));
+    database.close().await
+}
+```
+
+`AsyncOliphaunt` is `Clone + Send + Sync`. Every clone targets one
+PostgreSQL session whose Wasmer store is constructed and retained on an
+SDK-owned thread. Database work therefore does not block the calling executor
+thread. All admitted operations, transaction boundaries, and close are placed
+into one FIFO. Ordinary work awaits fair, bounded admission; saturation applies
+async backpressure instead of returning a queue-full error. Lifecycle controls
+do not consume ordinary capacity but never overtake earlier admitted work.
+Individual futures are `Send` only when their captured inputs, callbacks, and
+outputs also satisfy the applicable `Send` bounds.
+Starting close establishes an atomic cutoff: work already in the owner FIFO
+drains, while capacity waiters and later work are rejected. A retryable close
+does not resurrect waiters that missed its cutoff.
+
+Dropping an ordinary operation before it starts removes its database effect.
+After asynchronous execution begins, it runs to a PostgreSQL readiness boundary
+even if its future is abandoned. Dropping an active transaction future queues
+best-effort rollback in the same order. While a callback transaction is active,
+unpinned work is rejected. Concurrent `close().await` callers join one close
+attempt and receive the same result.
+
+An async transaction-body panic unwinds the awaiting task immediately. Its
+active transaction is dropped and queues best-effort rollback in the owner
+FIFO. The unwind does not wait for rollback to finish, but later database work
+cannot overtake that cleanup. This differs from the direct callback transaction,
+which settles synchronously before resuming the panic.
+
+The `Async*` root types mirror the direct database, SQL builder, transaction,
+backup/restore, raw-protocol, server, and optional tools surfaces with async
+methods. Streaming callbacks run synchronously on the database owner and must
+not reenter the same database; reentrancy is rejected instead of deadlocking.
+Their captures must also be owned `Send + 'static`; use `Arc>` for
+shared mutable state.
+`database.pg_dump(options).await` and `database.psql(options).await` queue the
+packaged tools on that same owner.
+
+The direct local server has a synchronous lifecycle API, but its listener
+thread owns the wire-protocol backend. The handle is `Send + !Sync`; move its
+exclusive ownership between threads rather than sharing references. Its
+`close(&mut self)` preserves the handle so `is_closed()` can report terminal
+retirement and repeated close calls can replay the first result. The async
+server handle is cloneable `Send + Sync`.
+Server `is_closed()` reports SDK lifecycle state only. It does not poll the
+proxy listener or guarantee that the published PostgreSQL endpoint is
+reachable; use the connected driver or pool for connection health.
+
+TCP endpoints are loopback-only because the embedded proxy uses PostgreSQL
+trust authentication. The default listener uses an automatically assigned
+loopback port on every supported host. `ServerListen::tcp_port` selects a fixed
+TCP port. On Unix hosts only, `ServerListen::unix` or
+`ServerListen::unix_port` selects a PostgreSQL-style Unix socket directory.
+The resolved directory must be valid UTF-8 so the returned connection string
+preserves its exact path across Rust drivers and ORMs.
+The server deliberately owns one connected client at a time; use the separate
+postmaster product for concurrent sessions.
+
+The crate packages no mutable runtime downloads. Cargo resolves the matching
+runtime, AOT, tool, and selected extension artifacts built from the same
+`liboliphaunt-wasix` source identity.
+
+## Maintainer commands
+
+Run these commands from this directory with the repository-pinned Rust toolchain, Moon and Bun available. Cargo resolves versioned workspace dependencies itself; no runtime build is needed for source tests. Bash is required for package staging (Git Bash on Windows). The initial locked Cargo fetch needs network access.
+
+| Command | Result |
+| --- | --- |
+| `moon run oliphaunt-wasix-rust:format` | Rewrite Rust formatting. |
+| `moon run oliphaunt-wasix-rust:format-check` | Check formatting without changing files. |
+| `moon run oliphaunt-wasix-rust:lint` | Clippy diagnostics for all targets; no database execution. |
+| `moon run oliphaunt-wasix-rust:build` | Compile this project and its Cargo dependencies. |
+| `moon run oliphaunt-wasix-rust:test` | Run source tests; Cargo compiles the required test targets. |
+| `moon run oliphaunt-wasix-rust:package` | Stage distributable source crates under target/sdk-artifacts/oliphaunt-wasix-rust; repeated runs replace this owner’s candidates. |
+| `moon run oliphaunt-wasix-rust:test-consumer` | Package prerequisites, then check the extracted candidate and its dependency closure in a disposable consumer workspace. |
+
+Native Cargo entry points remain available: `cargo build -p oliphaunt-wasix --locked`, `cargo test -p oliphaunt-wasix --locked`, `cargo clippy -p oliphaunt-wasix --all-targets --locked -- -D warnings`, and `cargo fmt -p oliphaunt-wasix --check`. Moon supplies the additional source-test feature matrix and artifact staging where defined. `package` assembles bytes; it does not run the project test suite.
+
+`moon run oliphaunt-wasix-rust:test-aot` first produces the host AOT runtime, then runs the actual SDK/runtime and extension compatibility tests. Source tests do not require those artifacts.
diff --git a/src/sdks/rust-wasix/THIRD_PARTY_NOTICES.md b/src/sdks/rust-wasix/THIRD_PARTY_NOTICES.md
new file mode 100644
index 000000000..bef13130a
--- /dev/null
+++ b/src/sdks/rust-wasix/THIRD_PARTY_NOTICES.md
@@ -0,0 +1,24 @@
+# oliphaunt-wasix Third-Party Notices
+
+`oliphaunt-wasix` ships WASIX PostgreSQL runtime assets, selected SQL extensions,
+and target-specific Wasmer AOT artifacts.
+
+The PostgreSQL runtime is derived from PostgreSQL 18 source pinned under
+`src/third-party/postgres/` and built with the WASM/WASIX patch stack owned by
+`src/runtimes/liboliphaunt-wasix/assets/build/postgres/patches/`. Selected
+runtime and extension carriers also embed ICU 76.1 and OpenSSL 3.5.6.
+
+Every carrier that embeds these components includes their exact pinned license
+bytes under `THIRD_PARTY_LICENSES/`:
+
+- `PostgreSQL-COPYRIGHT` — PostgreSQL 18.4, source SHA-256
+  `81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094`.
+- `ICU-LICENSE` — ICU commit `8eca245c7484ac6cc179e3e5f7c1ea7680810f39`.
+- `OpenSSL-LICENSE.txt` — OpenSSL commit
+  `286ddeaac037533bbdce65b3c689e3f7ffebf0f6`.
+
+Third-party source pins for optional external extensions are maintained in
+`src/third-party/`, and WASIX toolchain inputs are maintained in
+`tools/dev/`. Exact SQL extension selection is modeled in
+`extensions/`; generated WASM assets must include only the
+extension artifacts explicitly selected for the release payload.
diff --git a/src/sdks/rust-wasix/build.rs b/src/sdks/rust-wasix/build.rs
new file mode 100644
index 000000000..2428c093d
--- /dev/null
+++ b/src/sdks/rust-wasix/build.rs
@@ -0,0 +1,100 @@
+use std::collections::BTreeMap;
+use std::env;
+
+const ARTIFACT_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_";
+const ARTIFACT_ENV_SUFFIX: &str = "_MANIFEST";
+const RELAY_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_";
+
+fn main() {
+    match relay_manifest_instructions(env::vars()) {
+        Ok(instructions) => {
+            for instruction in instructions {
+                println!("{instruction}");
+            }
+        }
+        Err(error) => {
+            println!("cargo::error={error}");
+            panic!("oliphaunt-wasix artifact relay failed: {error}");
+        }
+    }
+}
+
+fn relay_manifest_instructions(vars: I) -> Result, String>
+where
+    I: IntoIterator,
+{
+    let mut manifests = BTreeMap::new();
+    let mut instructions = Vec::new();
+    for (key, value) in vars {
+        let Some(metadata_key) = relay_metadata_key(&key) else {
+            continue;
+        };
+        if value.is_empty() {
+            continue;
+        }
+        if let Some(existing) = manifests.insert(metadata_key.clone(), value.clone())
+            && existing != value
+        {
+            return Err(format!(
+                "conflicting Cargo artifact manifests for metadata key {metadata_key}: {existing} and {value}"
+            ));
+        }
+        instructions.push(format!("cargo::rerun-if-changed={value}"));
+    }
+    for (metadata_key, manifest) in manifests {
+        instructions.push(format!("cargo::metadata={metadata_key}={manifest}"));
+    }
+    Ok(instructions)
+}
+
+fn relay_metadata_key(env_key: &str) -> Option {
+    if env_key.starts_with(RELAY_ENV_PREFIX) {
+        return None;
+    }
+    let stem = env_key
+        .strip_prefix(ARTIFACT_ENV_PREFIX)?
+        .strip_suffix(ARTIFACT_ENV_SUFFIX)?;
+    if stem.is_empty() {
+        return None;
+    }
+    Some(format!("{}_manifest", stem.to_ascii_lowercase()))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn re_emits_runtime_and_aot_manifests() {
+        let instructions = relay_manifest_instructions([
+            (
+                "DEP_OLIPHAUNT_ARTIFACT_LIBOLIPHAUNT_WASIX_RUNTIME_MANIFEST".to_owned(),
+                "/tmp/runtime.toml".to_owned(),
+            ),
+            (
+                "DEP_OLIPHAUNT_ARTIFACT_LIBOLIPHAUNT_WASIX_AOT_LINUX_X64_GNU_MANIFEST".to_owned(),
+                "/tmp/aot.toml".to_owned(),
+            ),
+        ])
+        .unwrap();
+        assert!(instructions.contains(
+            &"cargo::metadata=liboliphaunt_wasix_runtime_manifest=/tmp/runtime.toml".to_owned()
+        ));
+        assert!(
+            instructions.contains(
+                &"cargo::metadata=liboliphaunt_wasix_aot_linux_x64_gnu_manifest=/tmp/aot.toml"
+                    .to_owned()
+            )
+        );
+    }
+
+    #[test]
+    fn ignores_own_downstream_metadata() {
+        let instructions = relay_manifest_instructions([(
+            "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_LIBOLIPHAUNT_WASIX_RUNTIME_MANIFEST".to_owned(),
+            "/tmp/runtime.toml".to_owned(),
+        )])
+        .unwrap();
+        assert!(instructions.is_empty());
+    }
+}
diff --git a/src/sdks/rust-wasix/moon.yml b/src/sdks/rust-wasix/moon.yml
new file mode 100644
index 000000000..ee81172bb
--- /dev/null
+++ b/src/sdks/rust-wasix/moon.yml
@@ -0,0 +1,243 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "oliphaunt-wasix-rust"
+language: "rust"
+layer: "library"
+stack: "systems"
+tags: ["cargo-package", "javascript-quality", "binding", "wasix", "rust", "postgres", "sdk", "release-product"]
+dependsOn:
+  - id: "shared-test-fixtures"
+    scope: "development"
+  - "liboliphaunt-wasix"
+  - "oliphaunt-query"
+  - id: "postgres-tools-wasix"
+    scope: "build"
+  - id: "database-resources"
+    scope: "build"
+
+project:
+  title: "Oliphaunt Rust WASIX"
+  description: "Rust binding over the liboliphaunt WASIX runtime."
+  owner: "oliphaunt"
+  release:
+    component: "oliphaunt-wasix-rust"
+    packagePath: "src/sdks/rust-wasix"
+
+owners:
+  defaultOwner: "@oliphaunt/wasix-rust"
+  paths:
+    "**/*.rs": ["@oliphaunt/wasix-rust"]
+    "tools/**": ["@oliphaunt/wasix-rust"]
+
+fileGroups:
+  code:
+    - "**/*"
+    - "!**/*.md"
+    - "!moon.yml"
+    - "!release.toml"
+
+tasks:
+  cargo-sources:
+    inputs:
+      - project: "liboliphaunt-wasix"
+        group: "cargo-carrier-sources"
+      - project: "postgres-tools-wasix"
+        group: "cargo-carrier-sources"
+      - project: "database-resources"
+        group: "cargo-carrier-sources"
+  test-regression:
+    tags: ["regression", "runtime", "requires-rust"]
+    command: "bash src/runtimes/liboliphaunt-wasix/tools/runtime-smoke.sh regression"
+    deps: [{target: "cargo-sources", cacheStrategy: hash}, "liboliphaunt-wasix:runtime-aot", "extension-artifacts-wasix:build-aot", "postgres-tools-wasix:build-aot"]
+    inputs: ["@group(code)", "@group(cargo-workspace)", "/src/runtimes/liboliphaunt-wasix/tools/{runtime-smoke,runtime-preflight,cargo-test-filter}.sh", "/src/runtimes/liboliphaunt-wasix/tools/wasix-extension-features.mts", "/src/extensions/artifacts/packages/tools/**/*"]
+    options: {runFromWorkspaceRoot: true, cache: local}
+  test-integration:
+    tags: ["runtime", "integration", "requires-rust"]
+    command: "bash src/sdks/rust-wasix/tools/test-resources.sh"
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+      - "liboliphaunt-wasix:runtime-aot"
+      - "database-resources:build-wasix-standard"
+      - "database-resources:build-wasix-icu"
+      - "database-resources:package-icu"
+    inputs:
+      - "@group(code)"
+      - "@group(cargo-workspace)"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+
+  format:
+    command: "cargo fmt -p oliphaunt-wasix"
+    options:
+      cache: false
+      runInCI: false
+      runFromWorkspaceRoot: true
+
+  test-aot:
+    tags: ["runtime", "integration", "requires-rust", "ci-liboliphaunt-wasix-aot"]
+    command: "bash src/sdks/rust-wasix/tools/test-aot.sh"
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+      - "liboliphaunt-wasix:runtime-aot"
+      - "extension-artifacts-wasix:build-aot"
+      - "postgres-tools-wasix:build-aot"
+    inputs:
+      - "@group(code)"
+      - "@group(cargo-workspace)"
+      - "@group(rust-test-config)"
+      - "@group(legal-files)"
+      - project: "liboliphaunt-wasix"
+        group: "extension-smoke-inputs"
+      - project: "liboliphaunt-wasix"
+        group: "crates"
+      - "/src/runtimes/liboliphaunt-wasix/tools/{cargo-test-filter,runtime-preflight,runtime-smoke}.sh"
+      - "/src/runtimes/liboliphaunt-wasix/tools/xtask/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+
+  build:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["build", "requires-rust"]
+    command: "cargo build -p oliphaunt-wasix --locked"
+    outputs: ["/target/debug/liboliphaunt_wasix.rlib"]
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - "@group(code)"
+      - project: "liboliphaunt-wasix"
+        group: "crates"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  test:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "unit", "requires-rust"]
+    script: |
+      set -e
+      cargo test -p oliphaunt-wasix --doc --locked
+      cargo test -p oliphaunt-wasix --doc --locked --features tools
+      cargo nextest run -p oliphaunt-wasix --locked --profile ci --no-default-features --features extensions,tools,extension-vector --test public_api --no-tests=fail --test-threads=1
+      cargo nextest run -p oliphaunt-wasix --locked --profile ci --no-default-features --lib --no-tests=fail --test-threads=1
+    env:
+      # Cargo releases its build lock before rustdoc consumes the compiled libraries.
+      CARGO_TARGET_DIR: "target/moon/oliphaunt-wasix-rust/unit"
+    inputs:
+      - "@group(cargo-workspace)"
+      - "@group(rust-test-config)"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - "@group(code)"
+      - project: "liboliphaunt-wasix"
+        group: "crates"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  coverage:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["coverage", "requires-rust"]
+    script: |
+      set -e
+      mkdir -p target/coverage/oliphaunt-wasix-rust
+      cargo llvm-cov nextest -p oliphaunt-wasix --no-default-features --lib --locked --profile ci --no-tests=fail --test-threads=1 --lcov --output-path target/coverage/oliphaunt-wasix-rust/lcov.info
+    env:
+      CARGO_LLVM_COV_TARGET_DIR: "target/coverage-build/oliphaunt-wasix-rust"
+    inputs:
+      - "@group(code)"
+      - "@group(cargo-workspace)"
+      - "@group(rust-test-config)"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+    outputs: ["/target/coverage/oliphaunt-wasix-rust/**/*"]
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: false
+
+
+  format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt -p oliphaunt-wasix --check"
+    inputs: ["/src/sdks/rust-wasix/**/*.rs","/src/sdks/rust-wasix/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+  lint:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy -p oliphaunt-wasix --all-targets --locked -- -D warnings"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs: ["/src/sdks/rust-wasix/**/*.rs","/src/sdks/rust-wasix/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+
+  package:
+    tags: ["release", "artifact-package", "ci-wasix-rust-package"]
+    script: |
+      set -eu
+      cargo fetch --locked
+      bash src/sdks/rust-wasix/tools/stage-release-artifacts.sh
+
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs:
+      - "**/*"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - project: "oliphaunt-query"
+        group: "sources"
+      - "@group(legal-files)"
+      - "@group(cargo-workspace)"
+      - "@group(release-archive-contract)"
+      - "@group(release-target-contract)"
+      - "/tools/packaging/*.{mjs,mts}"
+      - "/tools/packaging/cargo-source-package.mts"
+      - "/tools/packaging/package-cargo-source.sh"
+      - "/tools/packaging/check-cargo-package-tests.sh"
+      - "/src/sdks/rust-wasix/tools/check-package.mts"
+      - "/src/extensions/artifacts/packages/tools/contrib-carriers.mts"
+      - "/src/sdks/rust-wasix/tools/prepare-rust-release-source.mts"
+      - "/tools/release/release-graph.mts"
+      - "/tools/packaging/staging.mts"
+      - "/src/sdks/rust-wasix/tools/stage-release-artifacts.sh"
+      - "/src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.mts"
+      - "/src/database-resources/icu/cargo/**/*"
+      - project: "liboliphaunt-wasix"
+        group: "crates"
+      - "/src/runtimes/liboliphaunt-wasix/toolchain.toml"
+      - "/tools/dev/bun.sh"
+      - "/src/third-party/tools/source-fetch-core.mts"
+    outputs:
+      - "/target/sdk-artifacts/oliphaunt-wasix-rust/**/*"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  test-consumer:
+    tags: ["release", "consumer", "ci-wasix-rust-package"]
+    deps: ["oliphaunt-wasix-rust:package", "oliphaunt-query:package"]
+    script: |
+      set -eu
+      bash tools/dev/bun.sh src/sdks/rust-wasix/tools/check-package.mts
+      version="$(bash tools/dev/bun.sh tools/release/product-version.mts version oliphaunt-wasix-rust)"
+      query_version="$(bun tools/release/product-version.mts version oliphaunt-query)"
+      bash tools/packaging/check-cargo-package-tests.sh --crate "target/sdk-artifacts/oliphaunt-wasix-rust/oliphaunt-wasix-$version.crate" --no-default-features --features extensions,tools,icu --dependency-crate "target/sdk-artifacts/oliphaunt-query/oliphaunt-query-$query_version.crate" --path-dependencies-from src/sdks/rust-wasix/Cargo.toml
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs: ["@group(code)", "@group(cargo-workspace)", "/tools/packaging/*.{mts,sh}"]
+    options:
+      runFromWorkspaceRoot: true
diff --git a/src/sdks/rust-wasix/release.toml b/src/sdks/rust-wasix/release.toml
new file mode 100644
index 000000000..c3fc4ed15
--- /dev/null
+++ b/src/sdks/rust-wasix/release.toml
@@ -0,0 +1,16 @@
+id = "oliphaunt-wasix-rust"
+owner = "@oliphaunt/wasix-rust"
+kind = "sdk"
+publish_targets = ["crates-io"]
+registry_packages = ["crates:oliphaunt-wasix"]
+release_artifacts = ["cargo-crate"]
+
+[compatibility_versions.runtime]
+source_product = "liboliphaunt-wasix"
+path = "src/sdks/rust-wasix/Cargo.toml"
+parser = "toml:package.metadata.oliphaunt.runtime-version"
+
+[compatibility_versions.oliphaunt-wasix-rust-query]
+source_product = "oliphaunt-query"
+path = "src/sdks/rust-wasix/Cargo.toml"
+parser = "toml:dependencies.oliphaunt-query.version"
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/async_api.rs b/src/sdks/rust-wasix/src/async_api.rs
similarity index 84%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/async_api.rs
rename to src/sdks/rust-wasix/src/async_api.rs
index b39b3ffde..f9c423dfa 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/async_api.rs
+++ b/src/sdks/rust-wasix/src/async_api.rs
@@ -22,7 +22,6 @@ use std::thread;
 use tokio::sync::TryAcquireError;
 use tokio::sync::{Mutex as AsyncMutex, OwnedSemaphorePermit, Semaphore, oneshot};
 
-#[cfg(any(feature = "__internal-napi", test))]
 use crate::CatalogProfile;
 use crate::oliphaunt::builder::OliphauntBuilder as DirectOliphauntBuilder;
 use crate::oliphaunt::client::Oliphaunt as DirectOliphaunt;
@@ -32,10 +31,6 @@ use crate::oliphaunt::query::{
     CommandResult, ExecResult, IntoParameter, Parameter, QueryResult, StatementDescription,
     ValueFormat,
 };
-use crate::oliphaunt::server::{
-    OliphauntServer as DirectOliphauntServer,
-    OliphauntServerBuilder as DirectOliphauntServerBuilder, ServerListen,
-};
 use crate::{
     DatabaseStorage, Error, RawStreamCallbackOutput, RawStreamError, RawStreamResult, Result,
     TransactionError, TransactionResult,
@@ -463,8 +458,9 @@ impl Drop for DatabaseOwnerInner {
 }
 
 impl DatabaseOwner {
-    fn open_with_completion(builder: DirectOliphauntBuilder, completion: C)
+    fn open_with_completion(configure: F, completion: C)
     where
+        F: FnOnce() -> Result + Send + 'static,
         C: FnOnce(Result) + Send + 'static,
     {
         let completion = SharedCompletion::new(completion);
@@ -486,7 +482,7 @@ impl DatabaseOwner {
                     "WASIX database owner stopped before open completed",
                 );
                 let opened =
-                    std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| builder.open()));
+                    std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| configure()?.open()));
                 let database = match opened {
                     Ok(Ok(database)) => {
                         completion.complete(Ok(Self {
@@ -1647,7 +1643,7 @@ impl AsyncOliphaunt {
     }
 
     /// Run packaged `pg_dump` against this database on its owner thread.
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub async fn pg_dump(&self, options: crate::oliphaunt::tools::PgDumpOptions) -> Result {
         self.owner
             .call(None, move |database| {
@@ -1658,7 +1654,7 @@ impl AsyncOliphaunt {
 
     /// Submit packaged `pg_dump` and return exact stdout/stderr bytes without
     /// creating or polling a Rust future.
-    #[cfg(all(feature = "tools", any(feature = "__internal-napi", test)))]
+    #[cfg(all(feature = "tools-execution", any(feature = "__internal-napi", test)))]
     #[doc(hidden)]
     pub fn pg_dump_output_with_completion(
         &self,
@@ -1675,7 +1671,7 @@ impl AsyncOliphaunt {
     }
 
     /// Run packaged non-interactive `psql` against this database on its owner thread.
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub async fn psql(&self, options: crate::oliphaunt::tools::PsqlOptions) -> Result {
         self.owner
             .call(None, move |database| {
@@ -1686,7 +1682,7 @@ impl AsyncOliphaunt {
 
     /// Submit packaged `psql` and return exact stdout/stderr bytes without
     /// creating or polling a Rust future.
-    #[cfg(all(feature = "tools", any(feature = "__internal-napi", test)))]
+    #[cfg(all(feature = "tools-execution", any(feature = "__internal-napi", test)))]
     #[doc(hidden)]
     pub fn psql_output_with_completion(
         &self,
@@ -1758,9 +1754,19 @@ impl AsyncOliphauntBuilder {
         self
     }
 
-    /// Select the packaged standard or ICU catalog and matching runtime data.
-    #[cfg(any(feature = "__internal-napi", test))]
-    #[doc(hidden)]
+    /// Supply verified ICU data for this database.
+    pub fn icu_data(mut self, data: crate::IcuData) -> Self {
+        self.inner = self.inner.icu_data(data);
+        self
+    }
+
+    /// Use an explicitly selected seed for new storage. Existing storage ignores it.
+    pub fn seed(mut self, seed: crate::ClusterSeed) -> Self {
+        self.inner = self.inner.seed(seed);
+        self
+    }
+
+    /// Select the standard or ICU catalog and matching runtime data.
     pub fn catalog_profile(mut self, profile: CatalogProfile) -> Self {
         self.inner = self.inner.catalog_profile(profile);
         self
@@ -1813,9 +1819,12 @@ impl AsyncOliphauntBuilder {
     /// Construct the Wasmer runtime and PostgreSQL session on its permanent owner thread.
     pub async fn open(self) -> Result {
         let (reply, receiver) = oneshot::channel();
-        DatabaseOwner::open_with_completion(self.inner, move |result| {
-            let _ = reply.send(result.map(|owner| AsyncOliphaunt { owner }));
-        });
+        DatabaseOwner::open_with_completion(
+            move || Ok(self.inner),
+            move |result| {
+                let _ = reply.send(result.map(|owner| AsyncOliphaunt { owner }));
+            },
+        );
         receiver
             .await
             .map_err(|_| Error::lifecycle("WASIX database owner stopped before open completed"))?
@@ -1833,9 +1842,27 @@ impl AsyncOliphauntBuilder {
     where
         C: FnOnce(Result) + Send + 'static,
     {
-        DatabaseOwner::open_with_completion(self.inner, move |result| {
-            completion(result.map(|owner| AsyncOliphaunt { owner }));
-        });
+        Self::open_configured_with_completion(move || Ok(self), completion);
+    }
+
+    /// Prepare resources and open on the permanent owner thread.
+    #[cfg(any(feature = "__internal-napi", test))]
+    #[doc(hidden)]
+    pub fn open_configured_with_completion(configure: F, completion: C)
+    where
+        F: FnOnce() -> std::result::Result + Send + 'static,
+        C: FnOnce(Result) + Send + 'static,
+    {
+        DatabaseOwner::open_with_completion(
+            move || {
+                configure()
+                    .map(|builder| builder.inner)
+                    .map_err(|error| Error::from_anyhow(crate::error::invalid_configuration(error)))
+            },
+            move |result| {
+                completion(result.map(|owner| AsyncOliphaunt { owner }));
+            },
+        );
     }
 }
 
@@ -2217,368 +2244,10 @@ where
     }
 }
 
-#[derive(Debug)]
-struct ServerInfo {
-    connection_string: String,
-}
-
-enum ServerControl {
-    Close { attempt: Arc },
-    Shutdown,
-}
-
-struct ServerOwnerInner {
-    control: mpsc::Sender,
-    admission: Arc>,
-    state: Arc,
-    close_attempt: Arc>>>,
-}
-
-impl Drop for ServerOwnerInner {
-    fn drop(&mut self) {
-        let _admission = self.admission.lock().ok();
-        let _ = self.control.send(ServerControl::Shutdown);
-    }
-}
-
-/// Asynchronous handle for a local PostgreSQL wire server.
-#[derive(Clone)]
-pub struct AsyncOliphauntServer {
-    owner: Arc,
-    info: Arc,
-}
-
-impl AsyncOliphauntServer {
-    /// Build an asynchronous local PostgreSQL server.
-    pub fn builder() -> AsyncOliphauntServerBuilder {
-        AsyncOliphauntServerBuilder::new()
-    }
-
-    /// Return the standard PostgreSQL connection string.
-    pub fn connection_string(&self) -> &str {
-        &self.info.connection_string
-    }
-
-    /// Whether the server is permanently retired.
-    ///
-    /// This includes both a settled terminal close attempt and an unexpectedly
-    /// stopped owner. A close attempt still in progress is not yet terminal.
-    /// This is not an endpoint health check: `false` does not poll the proxy
-    /// listener or prove that the published endpoint is reachable.
-    pub fn is_closed(&self) -> bool {
-        owner_is_terminal(&self.owner.state)
-    }
-
-    /// Stop the local server without blocking the calling executor thread.
-    ///
-    /// Concurrent callers await the exact same attempt and receive the same
-    /// success or failure. Once server stop begins, the server is permanently
-    /// retired and every later close replays that attempt's exact result.
-    /// Successful teardown releases the managed root; failed teardown retains
-    /// it until process exit.
-    pub async fn close(&self) -> Result<()> {
-        let (reply, receiver) = oneshot::channel();
-        self.close_with_reply(move |result| {
-            let _ = reply.send(result);
-        });
-        receiver
-            .await
-            .map_err(|_| Error::lifecycle("WASIX server owner stopped while closing"))?
-    }
-
-    fn close_with_reply(&self, completion: C)
-    where
-        C: FnOnce(Result<()>) + Send + 'static,
-    {
-        let completion = SharedCompletion::new(Box::new(completion) as CloseCallback);
-        let result = (|| -> Result<(Option>, Option)> {
-            let _admission = self
-                .owner
-                .admission
-                .lock()
-                .map_err(|_| Error::message("WASIX server owner admission lock poisoned"))?;
-            match admit_close(
-                &self.owner.state,
-                &self.owner.close_attempt,
-                "WASIX server owner",
-            )? {
-                CloseAdmission::Closed => Ok((None, None)),
-                CloseAdmission::Join(attempt) => Ok((Some(attempt), None)),
-                CloseAdmission::Start(attempt) => {
-                    let notifications = if self
-                        .owner
-                        .control
-                        .send(ServerControl::Close {
-                            attempt: Arc::clone(&attempt),
-                        })
-                        .is_err()
-                    {
-                        complete_close_attempt_locked(
-                            &self.owner.state,
-                            &self.owner.close_attempt,
-                            &attempt,
-                            Err(Error::lifecycle("WASIX server owner has stopped")),
-                            CloseDisposition::Terminal,
-                        )
-                        .1
-                    } else {
-                        None
-                    };
-                    Ok((Some(attempt), notifications))
-                }
-            }
-        })();
-
-        match result {
-            Ok((attempt, notifications)) => {
-                if let Some(notifications) = notifications {
-                    notifications.dispatch();
-                }
-                match attempt {
-                    Some(attempt) => attempt.register_completion(
-                        completion,
-                        "WASIX server owner stopped while closing",
-                    ),
-                    None => completion.complete(Ok(())),
-                }
-            }
-            Err(error) => completion.complete(Err(error)),
-        }
-    }
-
-    /// Begin the shared server close attempt without creating or polling a
-    /// Rust future. Completion uses the same cutoff and memoized result as
-    /// [`Self::close`] and runs exactly once.
-    #[cfg(any(feature = "__internal-napi", test))]
-    #[doc(hidden)]
-    pub fn close_with_completion(&self, completion: C)
-    where
-        C: FnOnce(Result<()>) + Send + 'static,
-    {
-        self.close_with_reply(completion);
-    }
-}
-
-/// Builder for an asynchronous local PostgreSQL wire server.
-#[derive(Debug, Clone)]
-pub struct AsyncOliphauntServerBuilder {
-    inner: DirectOliphauntServerBuilder,
-}
-
-impl Default for AsyncOliphauntServerBuilder {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-impl AsyncOliphauntServerBuilder {
-    /// Create a memory-backed server builder listening on loopback TCP.
-    pub fn new() -> Self {
-        Self {
-            inner: DirectOliphauntServerBuilder::new(),
-        }
-    }
-
-    /// Select memory or managed-directory storage.
-    pub fn storage(mut self, storage: DatabaseStorage) -> Self {
-        self.inner = self.inner.storage(storage);
-        self
-    }
-
-    /// Select the packaged standard or ICU catalog and matching runtime data.
-    #[cfg(any(feature = "__internal-napi", test))]
-    #[doc(hidden)]
-    pub fn catalog_profile(mut self, profile: CatalogProfile) -> Self {
-        self.inner = self.inner.catalog_profile(profile);
-        self
-    }
-
-    /// Select loopback TCP on any supported host or a PostgreSQL Unix-domain
-    /// socket on a Unix host.
-    pub fn listen(mut self, listen: ServerListen) -> Self {
-        self.inner = self.inner.listen(listen);
-        self
-    }
-
-    /// Set one PostgreSQL startup GUC.
-    pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self {
-        self.inner = self.inner.startup_guc(name, value);
-        self
-    }
-
-    /// Set multiple PostgreSQL startup GUCs.
-    pub fn startup_gucs(mut self, settings: impl IntoIterator) -> Self
-    where
-        K: Into,
-        V: Into,
-    {
-        self.inner = self.inner.startup_gucs(settings);
-        self
-    }
-
-    /// Set the default role encoded in the connection string.
-    pub fn username(mut self, username: impl Into) -> Self {
-        self.inner = self.inner.username(username);
-        self
-    }
-
-    /// Set the default database encoded in the connection string.
-    pub fn database(mut self, database: impl Into) -> Self {
-        self.inner = self.inner.database(database);
-        self
-    }
-
-    #[cfg(feature = "extensions")]
-    /// Make one bundled PostgreSQL extension artifact available to clients.
-    /// Database-local installation remains the application's migration concern.
-    pub fn extension(mut self, extension: Extension) -> Self {
-        self.inner = self.inner.extension(extension);
-        self
-    }
-
-    #[cfg(feature = "extensions")]
-    /// Make bundled PostgreSQL extension artifacts available to clients.
-    /// Database-local installation remains the application's migration concern.
-    pub fn extensions(mut self, extensions: impl IntoIterator) -> Self {
-        self.inner = self.inner.extensions(extensions);
-        self
-    }
-
-    /// Start the server and await its bound endpoint.
-    pub async fn start(self) -> Result {
-        let (reply, receiver) = oneshot::channel();
-        self.start_with_reply(move |result| {
-            let _ = reply.send(result);
-        });
-        receiver
-            .await
-            .map_err(|_| Error::lifecycle("WASIX server owner stopped before start completed"))?
-    }
-
-    fn start_with_reply(self, completion: C)
-    where
-        C: FnOnce(Result) + Send + 'static,
-    {
-        let completion = SharedCompletion::new(completion);
-        let thread_completion = completion.clone();
-        let (control, receiver) = mpsc::channel();
-        let state = Arc::new(AtomicU8::new(OWNER_OPEN));
-        let admission = Arc::new(Mutex::new(()));
-        let close_attempt = Arc::new(Mutex::new(None));
-        let thread_state = Arc::clone(&state);
-        let thread_admission = Arc::clone(&admission);
-        let thread_close_attempt = Arc::clone(&close_attempt);
-        if let Err(error) = thread::Builder::new()
-            .name("oliphaunt-wasix-server-owner".to_owned())
-            .spawn(move || {
-                let completion = CompletionGuard::new(
-                    thread_completion,
-                    "WASIX server owner stopped before start completed",
-                );
-                let opened =
-                    std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| self.inner.start()));
-                let server = match opened {
-                    Ok(Ok(server)) => server,
-                    Ok(Err(error)) => {
-                        thread_state.store(OWNER_STOPPED, Ordering::SeqCst);
-                        completion.complete(Err(error));
-                        return;
-                    }
-                    Err(_) => {
-                        thread_state.store(OWNER_STOPPED, Ordering::SeqCst);
-                        completion.complete(Err(Error::message(
-                            "WASIX server owner panicked while starting PostgreSQL",
-                        )));
-                        return;
-                    }
-                };
-                let info = ServerInfo {
-                    connection_string: server.connection_string().to_owned(),
-                };
-                completion.complete(Ok(AsyncOliphauntServer {
-                    owner: Arc::new(ServerOwnerInner {
-                        control,
-                        admission,
-                        state,
-                        close_attempt,
-                    }),
-                    info: Arc::new(info),
-                }));
-                let owner = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
-                    run_server_owner(
-                        server,
-                        receiver,
-                        &thread_state,
-                        &thread_admission,
-                        &thread_close_attempt,
-                    )
-                }));
-                if owner.is_err() {
-                    stop_close_owner(
-                        &thread_admission,
-                        &thread_state,
-                        &thread_close_attempt,
-                        "WASIX server owner panicked while closing",
-                    );
-                }
-            })
-        {
-            completion.complete(Err(Error::message(format!(
-                "spawn WASIX server owner: {error}"
-            ))));
-        }
-    }
-
-    /// Start the server and report its bound endpoint without creating or
-    /// polling a Rust future. Completion runs exactly once, including thread
-    /// spawn failure and owner loss during startup.
-    #[cfg(any(feature = "__internal-napi", test))]
-    #[doc(hidden)]
-    pub fn start_with_completion(self, completion: C)
-    where
-        C: FnOnce(Result) + Send + 'static,
-    {
-        self.start_with_reply(completion);
-    }
-}
-
-fn run_server_owner(
-    mut server: DirectOliphauntServer,
-    receiver: Receiver,
-    state: &AtomicU8,
-    admission: &Mutex<()>,
-    close_attempt: &Mutex>>,
-) {
-    match receiver.recv() {
-        Ok(ServerControl::Close { attempt }) => {
-            let result = server.owner_close();
-            // The direct server releases its root only on Ok; dropping after
-            // Err preserves its process-lifetime quarantine.
-            drop(server);
-            complete_close_attempt(
-                admission,
-                state,
-                close_attempt,
-                &attempt,
-                result,
-                CloseDisposition::Terminal,
-            );
-        }
-        Ok(ServerControl::Shutdown) | Err(_) => {
-            let result = server.owner_close();
-            // The direct server releases its root only on Ok; dropping after
-            // Err preserves its process-lifetime quarantine.
-            drop(server);
-            complete_owner_shutdown(admission, state, close_attempt, result);
-        }
-    }
-}
-
 const _: fn() = || {
     fn assert_send_sync() {}
     fn assert_send() {}
     assert_send_sync::();
-    assert_send_sync::();
     assert_send::();
 };
 
@@ -2650,8 +2319,6 @@ mod close_tests {
     use std::time::Duration;
 
     use super::*;
-    use crate::oliphaunt::base::DirectoryLock;
-    use crate::oliphaunt::server::server_with_worker_result_for_test;
 
     fn poll_once(future: std::pin::Pin<&mut F>) -> Poll {
         let mut context = Context::from_waker(Waker::noop());
@@ -3631,216 +3298,34 @@ mod close_tests {
             Err(mpsc::TryRecvError::Empty | mpsc::TryRecvError::Disconnected)
         ));
     }
+}
 
-    struct ServerCloseHarness {
-        server: AsyncOliphauntServer,
-        started: mpsc::Receiver,
-        completion: mpsc::Sender,
-    }
+#[cfg(test)]
+mod configured_owner_tests {
+    use super::*;
 
-    fn server_close_harness() -> ServerCloseHarness {
-        let (control, receiver) = mpsc::channel::();
-        let (started, started_rx) = mpsc::channel();
-        let (completion, completion_rx) = mpsc::channel::();
-        let state = Arc::new(AtomicU8::new(OWNER_OPEN));
-        let admission = Arc::new(Mutex::new(()));
-        let close_attempt = Arc::new(Mutex::new(None));
-        let thread_state = Arc::clone(&state);
-        let thread_admission = Arc::clone(&admission);
-        let thread_close_attempt = Arc::clone(&close_attempt);
-        thread::spawn(move || {
-            let mut close_index = 0;
-            while let Ok(control) = receiver.recv() {
-                match control {
-                    ServerControl::Close { attempt } => {
-                        started
-                            .send(close_index)
-                            .expect("announce fake server close");
-                        let completion = completion_rx.recv().expect("complete fake server close");
-                        close_index += 1;
-                        let (terminal, notifications) = {
-                            let _admission = thread_admission
-                                .lock()
-                                .unwrap_or_else(|error| error.into_inner());
-                            complete_close_attempt_locked(
-                                &thread_state,
-                                &thread_close_attempt,
-                                &attempt,
-                                completion.result,
-                                completion.disposition,
-                            )
-                        };
-                        if let Some(notifications) = notifications {
-                            notifications.dispatch();
-                        }
-                        if terminal {
-                            return;
-                        }
-                    }
-                    ServerControl::Shutdown => return,
-                }
-            }
-        });
-        ServerCloseHarness {
-            server: AsyncOliphauntServer {
-                owner: Arc::new(ServerOwnerInner {
-                    control,
-                    admission,
-                    state,
-                    close_attempt,
-                }),
-                info: Arc::new(ServerInfo {
-                    connection_string: "postgresql://fake".to_owned(),
-                }),
+    #[test]
+    fn preparation_runs_on_owner_and_failure_completes_once() {
+        let caller = thread::current().id();
+        let (sent, received) = mpsc::channel();
+        AsyncOliphauntBuilder::open_configured_with_completion(
+            move || {
+                assert_ne!(thread::current().id(), caller);
+                Err("invalid database resources".to_owned())
+            },
+            move |result| {
+                sent.send(result.err().unwrap()).unwrap();
             },
-            started: started_rx,
-            completion,
-        }
-    }
-
-    fn server_owner_for_direct(server: DirectOliphauntServer) -> AsyncOliphauntServer {
-        let (control, receiver) = mpsc::channel();
-        let state = Arc::new(AtomicU8::new(OWNER_OPEN));
-        let admission = Arc::new(Mutex::new(()));
-        let close_attempt = Arc::new(Mutex::new(None));
-        let thread_state = Arc::clone(&state);
-        let thread_admission = Arc::clone(&admission);
-        let thread_close_attempt = Arc::clone(&close_attempt);
-        thread::spawn(move || {
-            run_server_owner(
-                server,
-                receiver,
-                &thread_state,
-                &thread_admission,
-                &thread_close_attempt,
-            );
-        });
-        AsyncOliphauntServer {
-            owner: Arc::new(ServerOwnerInner {
-                control,
-                admission,
-                state,
-                close_attempt,
-            }),
-            info: Arc::new(ServerInfo {
-                connection_string: "postgresql://fake".to_owned(),
-            }),
-        }
-    }
-
-    #[tokio::test]
-    async fn failed_async_server_close_cannot_release_managed_root_ownership() {
-        let parent = tempfile::TempDir::new().expect("create test root parent");
-        let root = parent.path().join("failed-async-server-root");
-        let lock = DirectoryLock::acquire(&root).expect("own managed root");
-        let direct = server_with_worker_result_for_test(
-            Err(anyhow::anyhow!("injected async server stop failure")),
-            Some(lock),
         );
-        let server = server_owner_for_direct(direct);
-
-        let error = server.close().await.expect_err("server teardown fails");
+        let error = received
+            .recv_timeout(std::time::Duration::from_secs(5))
+            .unwrap();
+        assert_eq!(error.kind(), crate::ErrorKind::InvalidConfiguration);
+        assert!(error.to_string().contains("invalid database resources"));
         assert!(
-            error
-                .to_string()
-                .contains("injected async server stop failure")
+            received
+                .recv_timeout(std::time::Duration::from_secs(5))
+                .is_err()
         );
-        drop(server);
-
-        let reopen = DirectoryLock::acquire(&root)
-            .expect_err("async owner drop must not release a failed server root");
-        assert!(format!("{reopen:#}").contains("database root is already in use"));
-    }
-
-    #[tokio::test]
-    async fn server_stop_failure_is_terminal_and_replayed() {
-        let harness = server_close_harness();
-        let mut first = Box::pin(harness.server.close());
-        assert!(poll_once(first.as_mut()).is_pending());
-        assert!(!harness.server.is_closed());
-        assert_eq!(
-            harness
-                .started
-                .recv_timeout(Duration::from_secs(2))
-                .expect("first server close starts"),
-            0
-        );
-        let first_attempt = harness
-            .server
-            .owner
-            .close_attempt
-            .lock()
-            .unwrap_or_else(|error| error.into_inner())
-            .clone()
-            .expect("server close attempt is installed");
-
-        let mut second = Box::pin(harness.server.close());
-        assert!(poll_once(second.as_mut()).is_pending());
-        let joined_attempt = harness
-            .server
-            .owner
-            .close_attempt
-            .lock()
-            .unwrap_or_else(|error| error.into_inner())
-            .clone()
-            .expect("server close attempt remains installed");
-        assert!(Arc::ptr_eq(&first_attempt, &joined_attempt));
-        assert_eq!(first_attempt.waiter_count(), 2);
-        assert!(matches!(
-            harness.started.try_recv(),
-            Err(mpsc::TryRecvError::Empty)
-        ));
-
-        harness
-            .completion
-            .send(FakeCloseCompletion {
-                result: Err(Error::message("injected server stop failure")),
-                disposition: CloseDisposition::Terminal,
-            })
-            .expect("finish failed server close");
-        let (first, second) = tokio::join!(first, second);
-        assert_eq!(
-            first.expect_err("first server close fails").to_string(),
-            "injected server stop failure"
-        );
-        assert_eq!(
-            second.expect_err("joined server close fails").to_string(),
-            "injected server stop failure"
-        );
-        assert!(harness.server.is_closed());
-        let retained_attempt = harness
-            .server
-            .owner
-            .close_attempt
-            .lock()
-            .unwrap_or_else(|error| error.into_inner())
-            .clone()
-            .expect("terminal server close result is retained");
-        assert!(Arc::ptr_eq(&first_attempt, &retained_attempt));
-        assert_eq!(
-            harness
-                .server
-                .close()
-                .await
-                .expect_err("later close replays server stop failure")
-                .to_string(),
-            "injected server stop failure"
-        );
-        assert!(matches!(
-            harness.started.try_recv(),
-            Err(mpsc::TryRecvError::Empty | mpsc::TryRecvError::Disconnected)
-        ));
-    }
-
-    #[test]
-    fn stopped_server_owner_is_terminal() {
-        let harness = server_close_harness();
-        harness
-            .server
-            .owner
-            .state
-            .store(OWNER_STOPPED, Ordering::SeqCst);
-
-        assert!(harness.server.is_closed());
     }
 }
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/bin/oliphaunt_wasix_dump.rs b/src/sdks/rust-wasix/src/bin/oliphaunt_wasix_dump.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/bin/oliphaunt_wasix_dump.rs
rename to src/sdks/rust-wasix/src/bin/oliphaunt_wasix_dump.rs
diff --git a/src/sdks/rust-wasix/src/error.rs b/src/sdks/rust-wasix/src/error.rs
new file mode 100644
index 000000000..06b568d75
--- /dev/null
+++ b/src/sdks/rust-wasix/src/error.rs
@@ -0,0 +1,781 @@
+use std::{convert::Infallible, error, fmt, sync::Arc};
+
+/// Stable, programmatically useful classification for an Oliphaunt failure.
+///
+/// The concrete [`Error`] remains opaque so implementation and platform
+/// details can evolve without breaking callers. Match this non-exhaustive enum
+/// with a wildcard arm.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum ErrorKind {
+    /// A builder option, storage descriptor, or extension selection is invalid.
+    InvalidConfiguration,
+    /// The database or server is closing, closed, or its owner has stopped.
+    Lifecycle,
+    /// An operation conflicts with an active managed transaction.
+    TransactionActive,
+    /// PostgreSQL returned a structured backend `ErrorResponse`.
+    Postgres,
+    /// Managed storage ownership, validation, publication, or durability failed.
+    Storage,
+    /// A transport, runtime, protocol, callback, or other failure.
+    Other,
+}
+
+/// Stable classification for a managed-storage failure.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum StorageErrorCode {
+    /// Another database or server owns the selected managed root.
+    Busy,
+    /// Stored bytes or metadata are malformed or unsafe.
+    Corrupt,
+    /// A managed root contains only part of a valid database.
+    Incomplete,
+    /// Stored data belongs to an incompatible runtime or physical format.
+    Incompatible,
+    /// Publication crossed or may have crossed its atomic commit point but durability failed.
+    PublicationFailed,
+    /// The storage provider or host filesystem operation was unavailable.
+    Unavailable,
+}
+
+/// What is known about the stored generation after a storage failure.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum StorageCommitState {
+    /// The attempted generation was not published.
+    NotPersisted,
+    /// The attempted generation was published and made durable.
+    Persisted,
+    /// The pre-operation generation is known to be unchanged.
+    Unchanged,
+    /// Publication or durability may have happened before the failure.
+    Unknown,
+}
+
+/// Stable operation phase at which managed storage failed.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum StorageErrorPhase {
+    /// Acquiring exclusive ownership of a managed directory root.
+    Ownership,
+    /// Inspecting or opening an existing managed root.
+    Open,
+    /// Publishing a newly initialized managed root.
+    OpenPublication,
+    /// Persisting one database protocol operation.
+    Operation,
+    /// Reading or materializing a physical backup.
+    Backup,
+    /// Shutting down and durably closing a database or server.
+    Close,
+    /// Validating a physical restore archive and destination.
+    RestoreValidation,
+    /// Materializing a validated restore in private staging.
+    RestoreStaging,
+    /// Atomically publishing a staged restore.
+    RestorePublication,
+    /// Making an already-published restore durable.
+    RestoreDurability,
+}
+
+/// Programmatically useful details carried by a managed-storage failure.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct StorageErrorDetails {
+    code: StorageErrorCode,
+    commit_state: StorageCommitState,
+    phase: StorageErrorPhase,
+}
+
+impl StorageErrorDetails {
+    /// Stable storage classification suitable for branching.
+    pub const fn code(self) -> StorageErrorCode {
+        self.code
+    }
+
+    /// What is known about the stored generation after the failure.
+    pub const fn commit_state(self) -> StorageCommitState {
+        self.commit_state
+    }
+
+    /// Storage operation phase which failed.
+    pub const fn phase(self) -> StorageErrorPhase {
+        self.phase
+    }
+}
+
+/// Error returned by the Oliphaunt Rust WASIX API.
+#[derive(Clone)]
+pub struct Error {
+    kind: ErrorKind,
+    inner: Arc,
+}
+
+#[derive(Debug)]
+struct ClassifiedCause {
+    kind: ErrorKind,
+    message: String,
+}
+
+#[derive(Debug)]
+struct StorageCause {
+    details: StorageErrorDetails,
+    source: anyhow::Error,
+}
+
+#[derive(Debug, Clone)]
+struct TransactionRollbackCause {
+    callback: Box,
+    rollback: Box,
+}
+
+#[derive(Debug, Clone)]
+struct TransactionCallbackAndDatabaseCause {
+    callback: Box,
+    database: Box,
+}
+
+/// Result returned by the Oliphaunt Rust WASIX API.
+pub type Result = std::result::Result;
+
+/// Result returned by a callback-scoped transaction.
+///
+/// `E` is the callback's application error type. The default keeps callbacks
+/// which use only SDK errors concise.
+pub type TransactionResult = std::result::Result>;
+
+/// Result returned by raw protocol streaming.
+///
+/// `E` is the callback's parser or application error type. The default is
+/// [`Infallible`] for callbacks which cannot fail deliberately.
+pub type RawStreamResult = std::result::Result>;
+
+mod raw_stream_callback_output {
+    pub trait Sealed {}
+
+    impl Sealed for () {}
+    impl Sealed for std::result::Result<(), E> {}
+}
+
+/// Supported return values from a raw protocol stream callback.
+///
+/// Return `()` for an infallible callback or `Result<(), E>` to stop delivery
+/// with a typed parser or application error. This trait is sealed so the two
+/// stable callback forms remain exhaustive.
+pub trait RawStreamCallbackOutput: raw_stream_callback_output::Sealed {
+    /// Typed callback failure, or [`Infallible`] for a callback returning `()`.
+    type Error;
+
+    /// Convert the callback output into its typed result.
+    #[doc(hidden)]
+    fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error>;
+}
+
+impl RawStreamCallbackOutput for () {
+    type Error = Infallible;
+
+    fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error> {
+        Ok(())
+    }
+}
+
+impl RawStreamCallbackOutput for std::result::Result<(), E> {
+    type Error = E;
+
+    fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error> {
+        self
+    }
+}
+
+/// Error from a callback-scoped transaction.
+///
+/// Callback code follows the Diesel/sqlx convention `E: From`, allowing
+/// SQL operations to use `?` while deliberate business aborts remain the
+/// caller's concrete `E`. If both the callback and rollback fail, both typed
+/// causes remain available.
+#[derive(Debug, Clone)]
+#[non_exhaustive]
+pub enum TransactionError {
+    /// `BEGIN`, `COMMIT`, explicit settlement, or another SDK operation failed.
+    Database(Error),
+    /// The callback deliberately aborted with an application error.
+    Callback(E),
+    /// The callback returned an error and an attempted rollback failed, possibly
+    /// together with releasing the transaction's owner pin.
+    CallbackAndRollback {
+        /// Error returned by the callback.
+        callback: E,
+        /// Error returned while rolling back or releasing the transaction pin.
+        rollback: Error,
+    },
+    /// The callback returned an error after an independent database, transport,
+    /// or protocol-recovery failure had already expired the transaction. No
+    /// rollback was attempted.
+    CallbackAndDatabase {
+        /// Error returned by the callback.
+        callback: E,
+        /// Independent SDK, database, transport, or recovery failure.
+        database: Error,
+    },
+}
+
+impl TransactionError {
+    /// Wrap a deliberate application-level transaction abort.
+    pub fn callback(error: E) -> Self {
+        Self::Callback(error)
+    }
+
+    /// Return the application error, including when rollback also failed.
+    pub fn callback_error(&self) -> Option<&E> {
+        match self {
+            Self::Callback(error) => Some(error),
+            Self::CallbackAndRollback { callback, .. } => Some(callback),
+            Self::CallbackAndDatabase { callback, .. } => Some(callback),
+            Self::Database(_) => None,
+        }
+    }
+
+    /// Return the SDK failure which occurred before callback settlement.
+    pub fn database_error(&self) -> Option<&Error> {
+        match self {
+            Self::Database(error)
+            | Self::CallbackAndDatabase {
+                database: error, ..
+            } => Some(error),
+            Self::Callback(_) | Self::CallbackAndRollback { .. } => None,
+        }
+    }
+
+    /// Return the attempted rollback or transaction-pin release failure.
+    pub fn rollback_error(&self) -> Option<&Error> {
+        match self {
+            Self::CallbackAndRollback { rollback, .. } => Some(rollback),
+            Self::Database(_) | Self::Callback(_) | Self::CallbackAndDatabase { .. } => None,
+        }
+    }
+}
+
+impl From for TransactionError {
+    fn from(error: Error) -> Self {
+        Self::Database(error)
+    }
+}
+
+impl From> for Error {
+    fn from(error: TransactionError) -> Self {
+        match error {
+            TransactionError::Database(error) => error,
+            TransactionError::Callback(error) => error,
+            TransactionError::CallbackAndRollback { callback, rollback } => {
+                Self::transaction_rollback(callback, rollback)
+            }
+            TransactionError::CallbackAndDatabase { callback, database } => {
+                Self::transaction_callback_and_database(callback, database)
+            }
+        }
+    }
+}
+
+impl fmt::Display for TransactionError
+where
+    E: fmt::Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Database(error) => error.fmt(f),
+            Self::Callback(error) => error.fmt(f),
+            Self::CallbackAndRollback { callback, rollback } => write!(
+                f,
+                "transaction callback failed: {callback}; rollback also failed: {rollback}"
+            ),
+            Self::CallbackAndDatabase { callback, database } => write!(
+                f,
+                "transaction callback failed: {callback}; an independent database failure also occurred: {database}"
+            ),
+        }
+    }
+}
+
+impl error::Error for TransactionError
+where
+    E: error::Error + 'static,
+{
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        match self {
+            Self::Database(error) => Some(error),
+            Self::Callback(error) => Some(error),
+            Self::CallbackAndRollback { callback, .. }
+            | Self::CallbackAndDatabase { callback, .. } => Some(callback),
+        }
+    }
+}
+
+/// Error from raw PostgreSQL protocol streaming.
+///
+/// A callback error is returned only after the runtime confirms recovery to
+/// `ReadyForQuery`. An independent runtime or transport failure is represented
+/// by [`Self::Database`] and remains authoritative.
+#[derive(Debug, Clone)]
+#[non_exhaustive]
+pub enum RawStreamError {
+    /// The SDK, runtime, transport, or recovery operation failed.
+    Database(Error),
+    /// The runtime recovered successfully after the callback returned this
+    /// parser or application error.
+    Callback(E),
+    /// An owner-thread callback panicked after the runtime confirmed
+    /// `ReadyForQuery`. Blocking APIs resume the original unwind instead.
+    CallbackPanicked(Error),
+}
+
+impl RawStreamError {
+    /// Return the recovered callback error.
+    pub fn callback_error(&self) -> Option<&E> {
+        match self {
+            Self::Callback(error) => Some(error),
+            Self::Database(_) | Self::CallbackPanicked(_) => None,
+        }
+    }
+
+    /// Return the authoritative SDK or recovery failure.
+    pub fn database_error(&self) -> Option<&Error> {
+        match self {
+            Self::Database(error) => Some(error),
+            Self::Callback(_) | Self::CallbackPanicked(_) => None,
+        }
+    }
+
+    /// Return a recovered owner-thread callback panic. This is distinct from
+    /// an independent database/recovery failure and does not imply poisoning.
+    pub fn callback_panic_error(&self) -> Option<&Error> {
+        match self {
+            Self::CallbackPanicked(error) => Some(error),
+            Self::Database(_) | Self::Callback(_) => None,
+        }
+    }
+}
+
+impl From for RawStreamError {
+    fn from(error: Error) -> Self {
+        Self::Database(error)
+    }
+}
+
+impl From> for Error {
+    fn from(error: RawStreamError) -> Self {
+        match error {
+            RawStreamError::Database(error) => error,
+            RawStreamError::Callback(never) => match never {},
+            RawStreamError::CallbackPanicked(error) => error,
+        }
+    }
+}
+
+impl From> for Error {
+    fn from(error: RawStreamError) -> Self {
+        match error {
+            RawStreamError::Database(error)
+            | RawStreamError::Callback(error)
+            | RawStreamError::CallbackPanicked(error) => error,
+        }
+    }
+}
+
+impl fmt::Display for RawStreamError
+where
+    E: fmt::Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Database(error) => error.fmt(f),
+            Self::Callback(error) => error.fmt(f),
+            Self::CallbackPanicked(error) => error.fmt(f),
+        }
+    }
+}
+
+impl error::Error for RawStreamError
+where
+    E: error::Error + 'static,
+{
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        match self {
+            Self::Database(error) => Some(error),
+            Self::Callback(error) => Some(error),
+            Self::CallbackPanicked(error) => Some(error),
+        }
+    }
+}
+
+impl Error {
+    /// Return the stable category of this failure.
+    pub const fn kind(&self) -> ErrorKind {
+        self.kind
+    }
+
+    /// Return structured PostgreSQL error details when the failure came from
+    /// a backend `ErrorResponse`.
+    pub fn postgres_error(&self) -> Option<&crate::PostgresError> {
+        self.inner.downcast_ref()
+    }
+
+    /// Return structured managed-storage details without inspecting error text.
+    pub fn storage_error(&self) -> Option {
+        self.inner
+            .downcast_ref::()
+            .map(|cause| cause.details)
+    }
+
+    /// Return both failures when a transaction callback and rollback failed.
+    pub fn transaction_rollback_errors(&self) -> Option<(&Error, &Error)> {
+        self.inner
+            .downcast_ref::()
+            .map(|error| (error.callback.as_ref(), error.rollback.as_ref()))
+    }
+
+    /// Return both failures when a callback error follows an independent
+    /// database or protocol failure. This pair never implies that rollback ran.
+    pub fn transaction_callback_database_errors(&self) -> Option<(&Error, &Error)> {
+        self.inner
+            .downcast_ref::()
+            .map(|error| (error.callback.as_ref(), error.database.as_ref()))
+    }
+
+    /// Return structured frontend-program failure details for `pg_dump` or `psql`.
+    #[cfg(feature = "tools-execution")]
+    pub fn tool_error(&self) -> Option<&crate::tools::PostgresToolError> {
+        self.inner.downcast_ref()
+    }
+
+    /// Preserve runtime error categories when integrating a lower-level adapter.
+    pub fn from_anyhow(inner: anyhow::Error) -> Self {
+        if let Some(error) = inner.downcast_ref::() {
+            return error.clone();
+        }
+        let kind = inner
+            .downcast_ref::()
+            .map(|_| ErrorKind::Storage)
+            .or_else(|| {
+                inner
+                    .downcast_ref::()
+                    .map(|cause| cause.kind)
+            })
+            .or_else(|| {
+                inner
+                    .downcast_ref::()
+                    .map(|_| ErrorKind::Postgres)
+            })
+            .unwrap_or(ErrorKind::Other);
+        Self {
+            kind,
+            inner: Arc::new(inner),
+        }
+    }
+
+    pub(crate) fn message(message: impl fmt::Display + fmt::Debug + Send + Sync + 'static) -> Self {
+        Self::from_anyhow(anyhow::Error::msg(message))
+    }
+
+    pub(crate) fn lifecycle(message: impl fmt::Display + Send + Sync + 'static) -> Self {
+        Self::classified(ErrorKind::Lifecycle, message)
+    }
+
+    pub(crate) fn transaction_active(message: impl fmt::Display + Send + Sync + 'static) -> Self {
+        Self::classified(ErrorKind::TransactionActive, message)
+    }
+
+    /// Construct an adapter error with an explicit public category.
+    pub fn classified(kind: ErrorKind, message: impl fmt::Display + Send + Sync + 'static) -> Self {
+        Self::from_anyhow(classified_anyhow(kind, message))
+    }
+
+    pub(crate) fn transaction_rollback(callback: Self, rollback: Self) -> Self {
+        Self::from_anyhow(anyhow::Error::new(TransactionRollbackCause {
+            callback: Box::new(callback),
+            rollback: Box::new(rollback),
+        }))
+    }
+
+    pub(crate) fn transaction_callback_and_database(callback: Self, database: Self) -> Self {
+        Self::from_anyhow(anyhow::Error::new(TransactionCallbackAndDatabaseCause {
+            callback: Box::new(callback),
+            database: Box::new(database),
+        }))
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.inner.fmt(f)
+    }
+}
+
+impl error::Error for Error {
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        Some(self.inner.as_ref().as_ref())
+    }
+}
+
+impl From for Error {
+    fn from(error: oliphaunt_query::Error) -> Self {
+        Self::from_anyhow(crate::oliphaunt::query::query_core_error(error))
+    }
+}
+
+impl fmt::Display for ClassifiedCause {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.message.fmt(f)
+    }
+}
+
+impl error::Error for ClassifiedCause {}
+
+impl fmt::Display for StorageCause {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.source.fmt(f)
+    }
+}
+
+impl error::Error for StorageCause {
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        Some(self.source.as_ref())
+    }
+}
+
+pub(crate) fn classified_anyhow(
+    kind: ErrorKind,
+    message: impl fmt::Display + Send + Sync + 'static,
+) -> anyhow::Error {
+    anyhow::Error::new(ClassifiedCause {
+        kind,
+        message: message.to_string(),
+    })
+}
+
+pub(crate) fn invalid_configuration(
+    message: impl fmt::Display + Send + Sync + 'static,
+) -> anyhow::Error {
+    classified_anyhow(ErrorKind::InvalidConfiguration, message)
+}
+
+pub(crate) fn lifecycle(message: impl fmt::Display + Send + Sync + 'static) -> anyhow::Error {
+    classified_anyhow(ErrorKind::Lifecycle, message)
+}
+
+pub(crate) fn transaction_active(
+    message: impl fmt::Display + Send + Sync + 'static,
+) -> anyhow::Error {
+    classified_anyhow(ErrorKind::TransactionActive, message)
+}
+
+pub(crate) fn storage_error(
+    source: anyhow::Error,
+    code: StorageErrorCode,
+    commit_state: StorageCommitState,
+    phase: StorageErrorPhase,
+) -> anyhow::Error {
+    if source.downcast_ref::().is_some() {
+        return source;
+    }
+    anyhow::Error::new(StorageCause {
+        details: StorageErrorDetails {
+            code,
+            commit_state,
+            phase,
+        },
+        source,
+    })
+}
+
+pub(crate) fn storage_message(
+    message: impl fmt::Display + fmt::Debug + Send + Sync + 'static,
+    code: StorageErrorCode,
+    commit_state: StorageCommitState,
+    phase: StorageErrorPhase,
+) -> anyhow::Error {
+    storage_error(anyhow::Error::msg(message), code, commit_state, phase)
+}
+
+impl fmt::Display for TransactionRollbackCause {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "transaction callback failed: {}; rollback also failed: {}",
+            self.callback, self.rollback
+        )
+    }
+}
+
+impl error::Error for TransactionRollbackCause {
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        Some(self.callback.as_ref())
+    }
+}
+
+impl fmt::Display for TransactionCallbackAndDatabaseCause {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "transaction callback failed: {}; an independent database failure also occurred: {}",
+            self.callback, self.database
+        )
+    }
+}
+
+impl error::Error for TransactionCallbackAndDatabaseCause {
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        Some(self.callback.as_ref())
+    }
+}
+
+pub(crate) fn public_result(result: anyhow::Result) -> Result {
+    result.map_err(Error::from_anyhow)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::{PostgresError, PostgresErrorField};
+
+    #[test]
+    fn postgres_error_finds_structured_backend_error() {
+        let postgres = PostgresError {
+            severity: Some("ERROR".to_owned()),
+            localized_severity: None,
+            nonlocalized_severity: Some("ERROR".to_owned()),
+            sqlstate: Some("23505".to_owned()),
+            message: "duplicate key".to_owned(),
+            detail: None,
+            hint: None,
+            position: None,
+            internal_position: None,
+            internal_query: None,
+            where_: None,
+            schema_name: None,
+            table_name: None,
+            column_name: None,
+            data_type_name: None,
+            constraint_name: None,
+            file: None,
+            line: None,
+            routine: None,
+            fields: vec![PostgresErrorField {
+                code: b'C',
+                value: "23505".to_owned(),
+            }],
+            notices: Vec::new(),
+        };
+        let error = Error::from_anyhow(anyhow::Error::new(postgres));
+        assert_eq!(error.kind(), ErrorKind::Postgres);
+        assert_eq!(
+            error
+                .postgres_error()
+                .and_then(|error| error.sqlstate.as_deref()),
+            Some("23505")
+        );
+        assert!(error::Error::source(&error).is_some());
+
+        let replay = error.clone();
+        assert_eq!(replay.postgres_error(), error.postgres_error());
+        assert_eq!(replay.to_string(), error.to_string());
+    }
+
+    #[test]
+    fn typed_classification_survives_anyhow_context_without_message_inference() {
+        use anyhow::Context as _;
+
+        let invalid = Err::<(), _>(invalid_configuration("invalid storage"))
+            .context("open database")
+            .unwrap_err();
+        assert_eq!(
+            Error::from_anyhow(invalid).kind(),
+            ErrorKind::InvalidConfiguration
+        );
+
+        let same_words = Error::message("invalid storage");
+        assert_eq!(same_words.kind(), ErrorKind::Other);
+        assert_eq!(Error::lifecycle("closed").kind(), ErrorKind::Lifecycle);
+        assert_eq!(
+            Error::transaction_active("active transaction").kind(),
+            ErrorKind::TransactionActive
+        );
+
+        let storage = Err::<(), _>(storage_message(
+            "misleading words: corrupt but actually owned",
+            StorageErrorCode::Busy,
+            StorageCommitState::Unchanged,
+            StorageErrorPhase::Ownership,
+        ))
+        .context("open database")
+        .unwrap_err();
+        let storage = Error::from_anyhow(storage);
+        assert_eq!(storage.kind(), ErrorKind::Storage);
+        assert_eq!(
+            storage.storage_error(),
+            Some(StorageErrorDetails {
+                code: StorageErrorCode::Busy,
+                commit_state: StorageCommitState::Unchanged,
+                phase: StorageErrorPhase::Ownership,
+            })
+        );
+
+        let same_storage_words = Error::message("database root is already in use");
+        assert_eq!(same_storage_words.kind(), ErrorKind::Other);
+        assert_eq!(same_storage_words.storage_error(), None);
+    }
+
+    #[test]
+    fn transaction_rollback_error_preserves_both_typed_errors() {
+        let error = Error::transaction_rollback(
+            Error::message("callback failed"),
+            Error::message("rollback failed"),
+        );
+
+        assert_eq!(
+            error.to_string(),
+            "transaction callback failed: callback failed; rollback also failed: rollback failed"
+        );
+        let (callback, rollback) = error
+            .transaction_rollback_errors()
+            .expect("callback and rollback failures remain typed");
+        assert_eq!(callback.to_string(), "callback failed");
+        assert_eq!(rollback.to_string(), "rollback failed");
+
+        let transaction = TransactionError::CallbackAndDatabase {
+            callback: Error::message("callback failed"),
+            database: Error::message("stream recovery failed"),
+        };
+        assert!(transaction.rollback_error().is_none());
+        assert_eq!(
+            transaction
+                .database_error()
+                .map(ToString::to_string)
+                .as_deref(),
+            Some("stream recovery failed")
+        );
+        let flattened: Error = transaction.into();
+        let (callback, database) = flattened
+            .transaction_callback_database_errors()
+            .expect("callback and independent database failure remain typed");
+        assert_eq!(callback.to_string(), "callback failed");
+        assert_eq!(database.to_string(), "stream recovery failed");
+
+        let panic =
+            RawStreamError::::CallbackPanicked(Error::message("callback panicked"));
+        assert!(panic.database_error().is_none());
+        assert_eq!(
+            panic
+                .callback_panic_error()
+                .map(ToString::to_string)
+                .as_deref(),
+            Some("callback panicked")
+        );
+    }
+}
diff --git a/src/sdks/rust-wasix/src/lib.rs b/src/sdks/rust-wasix/src/lib.rs
new file mode 100644
index 000000000..282fb4059
--- /dev/null
+++ b/src/sdks/rust-wasix/src/lib.rs
@@ -0,0 +1,33 @@
+#![doc = include_str!("../README.md")]
+#![deny(unsafe_code)]
+
+mod async_api;
+mod error;
+mod oliphaunt;
+
+#[cfg(feature = "extensions")]
+pub use oliphaunt::extensions::Extension;
+
+pub use async_api::{AsyncOliphaunt, AsyncOliphauntBuilder, AsyncSql, AsyncTransaction};
+pub use error::{
+    Error, ErrorKind, RawStreamCallbackOutput, RawStreamError, RawStreamResult, Result,
+    StorageCommitState, StorageErrorCode, StorageErrorDetails, StorageErrorPhase, TransactionError,
+    TransactionResult,
+};
+pub use oliphaunt::{CatalogProfile, ClusterSeed, IcuData};
+pub use oliphaunt::{
+    CommandResult, DatabaseStorage, DecodeError, ExecResult, FromSql, IntoParameter, Oliphaunt,
+    OliphauntBuilder, Parameter, PostgresError, PostgresErrorField, PostgresNotice, QueryField,
+    QueryFormat, QueryResult, QueryRow, RowIndex, Sql, StatementDescription, StatementResult,
+    Transaction, TypeOid, ValueFormat, ValueRef,
+};
+
+/// Options and structured errors for packaged PostgreSQL frontend programs.
+#[cfg(feature = "tools-execution")]
+pub mod tools {
+    pub use crate::oliphaunt::tools::{
+        PgDumpOptions, PostgresToolError, PostgresToolOutput, PsqlOptions, ToolAssets,
+    };
+}
+
+pub mod session;
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/aot.rs b/src/sdks/rust-wasix/src/oliphaunt/aot.rs
similarity index 94%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/aot.rs
rename to src/sdks/rust-wasix/src/oliphaunt/aot.rs
index 785819eb0..742eda6d8 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/aot.rs
+++ b/src/sdks/rust-wasix/src/oliphaunt/aot.rs
@@ -100,12 +100,12 @@ pub(crate) fn load_artifact_module(engine: &Engine, artifact_name: &str) -> Resu
     Ok(module)
 }
 
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 pub(crate) fn load_pg_dump_module(engine: &Engine) -> Result {
     load_artifact_module(engine, "tool:pg_dump")
 }
 
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 pub(crate) fn load_psql_module(engine: &Engine) -> Result {
     load_artifact_module(engine, "tool:psql")
 }
@@ -344,6 +344,18 @@ fn expected_raw_hash(
 
 fn target_manifest_artifact(name: &str) -> Result {
     let manifest = target_aot_manifest()?;
+    validate_aot_manifest(&manifest)?;
+
+    let artifact = manifest
+        .artifacts
+        .into_iter()
+        .find(|artifact| artifact.name == name)
+        .ok_or_else(|| anyhow::anyhow!("AOT manifest does not list artifact '{name}'"))?;
+
+    Ok(artifact)
+}
+
+fn validate_aot_manifest(manifest: &AotManifest) -> Result<()> {
     ensure!(
         manifest.target_triple == target_triple(),
         "AOT manifest target mismatch: manifest={} actual={}",
@@ -389,13 +401,7 @@ fn target_manifest_artifact(name: &str) -> Result {
         );
     }
 
-    let artifact = manifest
-        .artifacts
-        .into_iter()
-        .find(|artifact| artifact.name == name)
-        .ok_or_else(|| anyhow::anyhow!("AOT manifest does not list artifact '{name}'"))?;
-
-    Ok(artifact)
+    Ok(())
 }
 
 fn validate_compressed_artifact_manifest(
@@ -412,6 +418,60 @@ fn validate_compressed_artifact_manifest(
     Ok(())
 }
 
+#[cfg(feature = "tools-execution")]
+#[allow(unsafe_code)]
+pub(crate) unsafe fn load_external_tool_module(
+    engine: &Engine,
+    tool: &str,
+    wasm: &[u8],
+    compressed: &[u8],
+    manifest_json: &str,
+) -> Result {
+    let name = format!("tool:{tool}");
+    let manifest: AotManifest = serde_json::from_str(manifest_json)
+        .context("parse separately installed tools AOT manifest")?;
+    validate_aot_manifest(&manifest)?;
+    validate_tools_aot_manifest_artifacts(&manifest.artifacts)?;
+    let artifact = manifest
+        .artifacts
+        .iter()
+        .find(|artifact| artifact.name == name)
+        .ok_or_else(|| anyhow::anyhow!("tools AOT manifest does not contain {name}"))?;
+    ensure!(
+        sha256_hex(wasm) == artifact.module_sha256,
+        "{name} WASM module hash mismatch"
+    );
+    validate_compressed_artifact_manifest(&name, artifact, compressed)?;
+    let expected_size = artifact
+        .raw_size
+        .context("tools AOT manifest requires raw-size")?;
+    ensure!(expected_size > 0, "tools AOT raw-size must be positive");
+    let raw = if compressed.starts_with(ZSTD_MAGIC) {
+        let mut raw = Vec::new();
+        ZstdDecoder::new(Cursor::new(compressed))?
+            .take(expected_size.saturating_add(1))
+            .read_to_end(&mut raw)?;
+        raw
+    } else {
+        compressed.to_vec()
+    };
+    let hash = expected_raw_hash(&name, artifact, &raw, AotVerifyMode::Full)?;
+    let cache_key = format!("{name}:{hash}");
+    let mut modules = MODULE_CACHE
+        .get_or_init(|| Mutex::new(HashMap::new()))
+        .lock()
+        .expect("AOT module cache poisoned");
+    if let Some(module) = modules.get(&cache_key) {
+        return Ok(module.clone());
+    }
+    // SAFETY: caller supplied trusted compiler output; its platform, runtime,
+    // portable module and serialized bytes were checked above.
+    let module = unsafe { Module::deserialize(engine, &raw) }
+        .with_context(|| format!("deserialize separately installed {name}"))?;
+    modules.insert(cache_key, module.clone());
+    Ok(module)
+}
+
 fn target_aot_manifest() -> Result {
     if let Some(json) = target_aot_manifest_json() {
         let mut manifest: AotManifest =
@@ -970,22 +1030,6 @@ struct AotCacheReceipt {
 mod tests {
     use super::*;
 
-    const WASIX_TOOLCHAIN: &str = include_str!("../testdata/wasix-toolchain.toml");
-
-    #[test]
-    fn runtime_aot_versions_match_asset_toolchain() {
-        assert_eq!(
-            EXPECTED_WASMER_VERSION,
-            toolchain_value("wasmer"),
-            "runtime AOT Wasmer expectation must match src/sources/toolchains/wasix.toml"
-        );
-        assert_eq!(
-            EXPECTED_WASMER_WASIX_VERSION,
-            toolchain_value("wasmer-wasix"),
-            "runtime AOT WASIX expectation must match src/sources/toolchains/wasix.toml"
-        );
-    }
-
     #[test]
     fn engine_identity_matches_runtime_aot_versions() {
         assert!(
@@ -1065,22 +1109,4 @@ mod tests {
             raw_size: Some(1),
         }
     }
-
-    fn toolchain_value(key: &str) -> &str {
-        let rest = WASIX_TOOLCHAIN
-            .split_once("[toolchain]")
-            .expect("WASIX toolchain manifest has a [toolchain] section")
-            .1;
-        let section = rest.split_once("\n[").map_or(rest, |(section, _)| section);
-
-        for line in section.lines() {
-            let Some((line_key, value)) = line.trim().split_once('=') else {
-                continue;
-            };
-            if line_key.trim() == key {
-                return value.trim().trim_matches('"');
-            }
-        }
-        panic!("WASIX toolchain manifest has toolchain.{key}");
-    }
 }
diff --git a/src/sdks/rust-wasix/src/oliphaunt/assets.rs b/src/sdks/rust-wasix/src/oliphaunt/assets.rs
new file mode 100644
index 000000000..61db5eb26
--- /dev/null
+++ b/src/sdks/rust-wasix/src/oliphaunt/assets.rs
@@ -0,0 +1,271 @@
+use anyhow::{Context, Result, ensure};
+use sha2::{Digest, Sha256};
+use std::sync::Arc;
+
+/// An explicitly selected seed archive and its resource manifest.
+/// Existing database directories do not need a seed.
+#[derive(Debug, Clone)]
+pub struct ClusterSeed {
+    pub(crate) archive: Arc<[u8]>,
+    pub(crate) manifest: Arc<[u8]>,
+}
+
+impl ClusterSeed {
+    pub fn new(archive: impl Into>, manifest: impl AsRef<[u8]>) -> Self {
+        Self {
+            archive: archive.into(),
+            manifest: Arc::from(manifest.as_ref()),
+        }
+    }
+}
+
+/// Explicitly selected canonical ICU data. Clones share the verified bytes.
+#[derive(Debug, Clone)]
+pub struct IcuData {
+    pub(crate) data: Arc<[u8]>,
+    pub(crate) tree_sha256: String,
+}
+
+impl IcuData {
+    pub fn new(data: impl Into>, manifest: impl AsRef<[u8]>) -> crate::Result {
+        crate::error::public_result(
+            Self::validate(data.into(), manifest.as_ref())
+                .map_err(crate::error::invalid_configuration),
+        )
+    }
+
+    fn validate(data: Arc<[u8]>, manifest: &[u8]) -> Result {
+        let mut fields = std::collections::BTreeMap::new();
+        for line in std::str::from_utf8(manifest)?
+            .lines()
+            .filter(|line| !line.is_empty())
+        {
+            let (key, value) = line.split_once('=').context("invalid ICU manifest entry")?;
+            ensure!(
+                fields.insert(key, value).is_none(),
+                "duplicate ICU manifest field {key}"
+            );
+        }
+        ensure!(fields.len() == 5, "unexpected ICU manifest fields");
+        for (key, expected) in [
+            ("schema", "oliphaunt-icu-data-v1"),
+            ("artifactRole", "icu-data"),
+            ("icuDataVersion", "76.1"),
+            ("icuDataForm", "files-le"),
+        ] {
+            ensure!(
+                fields.get(key) == Some(&expected),
+                "unsupported ICU manifest {key}"
+            );
+        }
+        ensure!(!data.is_empty(), "ICU data is empty");
+        let mut hash = Sha256::new();
+        hash.update(b"icudt76l.dat\0");
+        hash.update(data.len().to_string().as_bytes());
+        hash.update([0]);
+        hash.update(&data);
+        hash.update(b"\n");
+        let tree_sha256 = format!("{:x}", hash.finalize());
+        ensure!(
+            fields.get("icuDataTreeSha256") == Some(&tree_sha256.as_str()),
+            "ICU data does not match its manifest"
+        );
+        Ok(Self { data, tree_sha256 })
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct AssetManifestMetadata {
+    pub source_lane: Option,
+    pub source_fingerprint: Option,
+    pub postgres_version: String,
+    pub runtime_module_sha256: String,
+}
+
+/// Packaged PostgreSQL initialization and runtime-data profile.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
+#[serde(rename_all = "lowercase")]
+pub enum CatalogProfile {
+    /// The standard PostgreSQL catalog without packaged ICU data.
+    Standard,
+    /// The ICU catalog with its matching packaged ICU data.
+    Icu,
+}
+
+impl CatalogProfile {
+    pub const fn as_str(self) -> &'static str {
+        match self {
+            Self::Standard => "standard",
+            Self::Icu => "icu",
+        }
+    }
+
+    pub(crate) fn validate_available(self) -> Result<()> {
+        if self == Self::Icu && !cfg!(feature = "icu") {
+            return Err(crate::error::invalid_configuration(
+                "the ICU catalog profile requires the oliphaunt-wasix `icu` feature",
+            ));
+        }
+        Ok(())
+    }
+}
+
+impl Default for CatalogProfile {
+    fn default() -> Self {
+        default_catalog_profile()
+    }
+}
+
+pub const fn default_catalog_profile() -> CatalogProfile {
+    if cfg!(feature = "icu") {
+        CatalogProfile::Icu
+    } else {
+        CatalogProfile::Standard
+    }
+}
+
+pub fn asset_manifest_metadata() -> Result {
+    asset_manifest_metadata_for(default_catalog_profile())
+}
+
+pub(crate) fn asset_manifest_metadata_for(
+    _selected_profile: CatalogProfile,
+) -> Result {
+    let manifest =
+        liboliphaunt_wasix_portable::manifest().context("parse oliphaunt-wasix asset manifest")?;
+
+    Ok(AssetManifestMetadata {
+        source_lane: manifest.source_lane,
+        source_fingerprint: manifest.source_fingerprint,
+        postgres_version: manifest.runtime.postgres_version,
+        runtime_module_sha256: manifest.runtime.module_sha256,
+    })
+}
+
+pub(crate) fn runtime_archive() -> Option<&'static [u8]> {
+    liboliphaunt_wasix_portable::runtime_archive()
+}
+
+pub(crate) fn expected_runtime_archive_sha256() -> Result {
+    let manifest =
+        liboliphaunt_wasix_portable::manifest().context("parse oliphaunt-wasix asset manifest")?;
+    Ok(manifest.runtime.sha256)
+}
+
+#[cfg(feature = "tools")]
+pub(crate) fn pg_dump_wasm() -> Option<&'static [u8]> {
+    oliphaunt_wasix_tools::pg_dump_wasm()
+}
+
+#[cfg(feature = "tools")]
+pub(crate) fn psql_wasm() -> Option<&'static [u8]> {
+    oliphaunt_wasix_tools::psql_wasm()
+}
+
+#[cfg(all(feature = "tools-execution", not(feature = "tools")))]
+pub(crate) fn pg_dump_wasm() -> Option<&'static [u8]> {
+    None
+}
+
+#[cfg(all(feature = "tools-execution", not(feature = "tools")))]
+pub(crate) fn psql_wasm() -> Option<&'static [u8]> {
+    None
+}
+
+pub(crate) fn icu_data_archive(profile: CatalogProfile) -> Option<&'static [u8]> {
+    if profile == CatalogProfile::Standard {
+        return None;
+    }
+    #[cfg(feature = "icu")]
+    {
+        oliphaunt_icu::icu_data_archive()
+    }
+    #[cfg(not(feature = "icu"))]
+    {
+        None
+    }
+}
+
+pub(crate) fn expected_icu_data_archive_sha256() -> Option<&'static str> {
+    #[cfg(feature = "icu")]
+    {
+        oliphaunt_icu::ICU_DATA_ARCHIVE_SHA256
+    }
+    #[cfg(not(feature = "icu"))]
+    {
+        None
+    }
+}
+
+pub(crate) fn expected_icu_data_tree_sha256() -> Option<&'static str> {
+    #[cfg(feature = "icu")]
+    {
+        oliphaunt_icu::ICU_DATA_TREE_SHA256
+    }
+    #[cfg(not(feature = "icu"))]
+    {
+        None
+    }
+}
+
+#[cfg(feature = "extensions")]
+pub(crate) fn extension_archive(sql_name: &str) -> Option<&'static [u8]> {
+    liboliphaunt_wasix_portable::extension_archive(sql_name)
+}
+
+#[cfg(feature = "extensions")]
+pub(crate) fn expected_extension_archive_sha256(sql_name: &str) -> Result {
+    liboliphaunt_wasix_portable::expected_extension_archive_sha256(sql_name)
+        .map(str::to_owned)
+        .ok_or_else(|| {
+            crate::error::invalid_configuration(format!(
+                "extension asset '{sql_name}' is not embedded in this oliphaunt-wasix build"
+            ))
+        })
+}
+
+#[cfg(feature = "extensions")]
+pub(crate) fn extension_aot_manifest_json(target: &str, sql_name: &str) -> Option<&'static str> {
+    liboliphaunt_wasix_portable::extension_aot_manifest_json(target, sql_name)
+}
+
+#[cfg(feature = "extensions")]
+pub(crate) fn extension_aot_artifact_bytes(target: &str, name: &str) -> Option<&'static [u8]> {
+    liboliphaunt_wasix_portable::extension_aot_artifact_bytes(target, name)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{
+        CatalogProfile, asset_manifest_metadata, expected_icu_data_archive_sha256,
+        expected_icu_data_tree_sha256, expected_runtime_archive_sha256, icu_data_archive,
+        runtime_archive,
+    };
+
+    #[test]
+    fn asset_helpers_expose_a_consistent_feature_contract() {
+        let default_profile = if cfg!(feature = "icu") {
+            CatalogProfile::Icu
+        } else {
+            CatalogProfile::Standard
+        };
+        assert_eq!(CatalogProfile::default(), default_profile);
+        CatalogProfile::Standard.validate_available().unwrap();
+        assert_eq!(
+            CatalogProfile::Icu.validate_available().is_ok(),
+            cfg!(feature = "icu")
+        );
+
+        asset_manifest_metadata().unwrap();
+        let has_embedded_assets = liboliphaunt_wasix_portable::HAS_EMBEDDED_ASSETS;
+        assert_eq!(
+            !expected_runtime_archive_sha256().unwrap().is_empty(),
+            has_embedded_assets
+        );
+        assert_eq!(runtime_archive().is_some(), has_embedded_assets);
+        assert!(icu_data_archive(CatalogProfile::Standard).is_none());
+        let has_icu_assets = icu_data_archive(CatalogProfile::Icu).is_some();
+        assert_eq!(expected_icu_data_archive_sha256().is_some(), has_icu_assets);
+        assert_eq!(expected_icu_data_tree_sha256().is_some(), has_icu_assets);
+    }
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/backend.rs b/src/sdks/rust-wasix/src/oliphaunt/backend.rs
similarity index 98%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/backend.rs
rename to src/sdks/rust-wasix/src/oliphaunt/backend.rs
index 4b3f3b03a..449818c4e 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/backend.rs
+++ b/src/sdks/rust-wasix/src/oliphaunt/backend.rs
@@ -139,12 +139,12 @@ impl WasixBackendSession {
         self.pg.start_protocol_with_startup_packet(message)
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn existing_startup_response(&self) -> Option> {
         self.pg.existing_startup_response()
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn startup_config(&self) -> &StartupConfig {
         self.pg.startup_config()
     }
@@ -238,12 +238,12 @@ impl BackendSession {
         self.0.startup_with_packet(message)
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn existing_startup_response(&self) -> Option> {
         self.0.existing_startup_response()
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn startup_config(&self) -> &StartupConfig {
         self.0.startup_config()
     }
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/base.rs b/src/sdks/rust-wasix/src/oliphaunt/base.rs
similarity index 85%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/base.rs
rename to src/sdks/rust-wasix/src/oliphaunt/base.rs
index e34d21624..581f71cda 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/base.rs
+++ b/src/sdks/rust-wasix/src/oliphaunt/base.rs
@@ -1,4 +1,4 @@
-use std::collections::BTreeSet;
+use std::collections::{BTreeMap, BTreeSet};
 use std::ffi::OsString;
 use std::fs::OpenOptions;
 use std::fs::{self, File};
@@ -19,7 +19,7 @@ use tracing::info;
 use zstd::stream::read::Decoder as ZstdDecoder;
 
 use super::postgres_mod::PostgresMod;
-use crate::oliphaunt::assets::{self, CatalogProfile};
+use crate::oliphaunt::assets::{self, CatalogProfile, ClusterSeed, IcuData};
 use crate::oliphaunt::database_root_descriptor::{
     DirectoryState, PGDATA_DIRECTORY, inspect_directory_root, sync_directory,
     write_database_root_descriptor,
@@ -48,38 +48,12 @@ const CLUSTER_SEED_CACHE_FORMAT: &str = "v1";
 const DEFAULT_PASSWORD_FILE: &[u8] = b"password\n";
 const DATABASE_LOCK_FILE_SUFFIX: &str = ".oliphaunt-wasix-rust.lock";
 
-static RUNTIME_CACHE: ProfileOnceLock, String>> =
-    ProfileOnceLock::new();
-static RUNTIME_CACHE_KEY: ProfileOnceLock> =
-    ProfileOnceLock::new();
-static CLUSTER_SEED_CACHE: ProfileOnceLock, String>> =
-    ProfileOnceLock::new();
-static CLUSTER_SEED_MANIFEST: ProfileOnceLock> =
-    ProfileOnceLock::new();
+// ponytail: retain each selected resource identity for this process; use weak entries if
+// applications routinely rotate many distinct ICU datasets in one process.
+static RUNTIME_CACHE: OnceLock>>> = OnceLock::new();
 static ROOT_LOCKED_PATHS: OnceLock>> = OnceLock::new();
 const CLUSTER_SEED_RUNTIME_STATE_FILES: &[&str] = &["postmaster.pid", "postmaster.opts"];
 
-struct ProfileOnceLock {
-    standard: OnceLock,
-    icu: OnceLock,
-}
-
-impl ProfileOnceLock {
-    const fn new() -> Self {
-        Self {
-            standard: OnceLock::new(),
-            icu: OnceLock::new(),
-        }
-    }
-
-    fn get(&self, profile: CatalogProfile) -> &OnceLock {
-        match profile {
-            CatalogProfile::Standard => &self.standard,
-            CatalogProfile::Icu => &self.icu,
-        }
-    }
-}
-
 #[derive(Debug)]
 struct CachedRuntime {
     catalog_profile: CatalogProfile,
@@ -146,6 +120,8 @@ struct RuntimeLayoutManifest {
 pub(crate) struct DatabasePlan {
     pub(crate) storage: DatabaseStorage,
     pub(crate) catalog_profile: CatalogProfile,
+    pub(crate) seed: Option,
+    pub(crate) icu_data: Option,
 }
 
 impl DatabasePlan {
@@ -153,6 +129,8 @@ impl DatabasePlan {
         Self {
             storage,
             catalog_profile,
+            seed: None,
+            icu_data: None,
         }
     }
 }
@@ -175,6 +153,7 @@ struct ClusterSeedRuntimeIdentity {
     product: String,
     version: String,
     engine_family: String,
+    target: String,
     physical_format: String,
     postgres_major: u32,
     compatibility_key: String,
@@ -186,9 +165,6 @@ struct ClusterSeedRuntimeIdentity {
 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
 #[serde(rename_all = "camelCase", deny_unknown_fields)]
 struct ClusterSeedSourceIdentity {
-    fingerprint: String,
-    catalog_version: String,
-    lane: String,
     producer: String,
 }
 
@@ -214,7 +190,9 @@ struct ClusterSeedExtensionIdentity {
 #[serde(rename_all = "camelCase", deny_unknown_fields)]
 struct ClusterSeedIcuIdentity {
     artifact_role: String,
+    #[serde(default)]
     upstream_version: String,
+    #[serde(default)]
     source_commit: String,
     data_tree_sha256: String,
     data_version: String,
@@ -229,7 +207,6 @@ struct ClusterSeedManifest {
     catalog_profile: String,
     runtime: ClusterSeedRuntimeIdentity,
     source: ClusterSeedSourceIdentity,
-    init_profile: String,
     archive: ClusterSeedArchiveIdentity,
     required_runtime_features: Vec,
     extensions: ClusterSeedExtensionIdentity,
@@ -486,8 +463,12 @@ fn locate_runtime_module(paths: &OliphauntPaths) -> Option<(PathBuf, PathBuf)> {
     Some((module, bin_dir))
 }
 
-fn ensure_full_runtime(paths: &OliphauntPaths, profile: CatalogProfile) -> Result {
-    let source_key = runtime_cache_key(profile)?;
+fn ensure_full_runtime(
+    paths: &OliphauntPaths,
+    profile: CatalogProfile,
+    icu_data: Option<&IcuData>,
+) -> Result {
+    let source_key = runtime_cache_key(profile, icu_data)?;
     let existing_runtime = { locate_runtime_module(paths) };
     if existing_runtime.is_some() {
         let source_key_matches = full_runtime_layout_matches_current(paths, profile, &source_key)?;
@@ -496,7 +477,7 @@ fn ensure_full_runtime(paths: &OliphauntPaths, profile: CatalogProfile) -> Resul
         } else {
             false
         };
-        let repaired_icu = install_optional_icu_data(&paths.runtime_root(), profile)?;
+        let repaired_icu = install_optional_icu_data(&paths.runtime_root(), profile, icu_data)?;
         write_runtime_layout_manifest(
             &paths.runtime_root(),
             RuntimeLayoutKind::FullLocal,
@@ -515,7 +496,7 @@ fn ensure_full_runtime(paths: &OliphauntPaths, profile: CatalogProfile) -> Resul
     }
 
     install_runtime_from_tar(paths)?;
-    install_optional_icu_data(&paths.runtime_root(), profile)?;
+    install_optional_icu_data(&paths.runtime_root(), profile, icu_data)?;
     locate_runtime_module(paths).ok_or_else(|| {
         anyhow!(
             "runtime missing: could not locate module under {} after archive install",
@@ -587,9 +568,27 @@ fn install_runtime_from_tar(paths: &OliphauntPaths) -> Result {
 pub(crate) fn install_optional_icu_data(
     runtime_root: &Path,
     profile: CatalogProfile,
+    icu_data: Option<&IcuData>,
 ) -> Result {
     let icu_dir = runtime_root.join("share/icu");
     let marker = runtime_root.join(ICU_DATA_MARKER_NAME);
+    if let Some(data) = icu_data {
+        if installed_icu_marker_matches(runtime_root, &data.tree_sha256)?
+            && icu_data_root_contains_data(&icu_dir)?
+        {
+            if strict_asset_verification()? {
+                ensure_installed_icu_tree_matches(&icu_dir, &data.tree_sha256)?;
+            }
+            return Ok(false);
+        }
+        if icu_dir.exists() {
+            fs::remove_dir_all(&icu_dir)?;
+        }
+        fs::create_dir_all(&icu_dir)?;
+        fs::write(icu_dir.join("icudt76l.dat"), &data.data)?;
+        fs::write(&marker, format!("{}\n", data.tree_sha256))?;
+        return Ok(true);
+    }
     let Some(archive) = assets::icu_data_archive(profile) else {
         ensure!(
             profile == CatalogProfile::Standard,
@@ -658,13 +657,21 @@ fn installed_icu_marker_matches(runtime_root: &Path, expected_archive: &str) ->
     }
 }
 
-fn installed_profile_data_matches(runtime_root: &Path, profile: CatalogProfile) -> Result {
+fn installed_profile_data_matches(
+    runtime_root: &Path,
+    profile: CatalogProfile,
+    icu_data: Option<&IcuData>,
+) -> Result {
     let icu_root = runtime_root.join("share/icu");
     match profile {
         CatalogProfile::Standard => {
             Ok(!icu_root.exists() && !runtime_root.join(ICU_DATA_MARKER_NAME).exists())
         }
         CatalogProfile::Icu => {
+            if let Some(data) = icu_data {
+                return Ok(icu_data_root_contains_data(&icu_root)?
+                    && installed_icu_marker_matches(runtime_root, &data.tree_sha256)?);
+            }
             let Some(expected_archive) = assets::expected_icu_data_archive_sha256() else {
                 return Ok(false);
             };
@@ -874,21 +881,23 @@ fn validate_embedded_runtime_archive_strict(bytes: &[u8]) -> Result<()> {
     Ok(())
 }
 
-fn try_install_embedded_cluster_seed(
+fn try_install_cluster_seed(
     paths: &OliphauntPaths,
     module_path: &Path,
     profile: CatalogProfile,
+    selected: Option<&ClusterSeed>,
 ) -> Result {
     if cluster_is_complete(paths) {
         return Ok(false);
     }
 
-    let Some(manifest) = validated_embedded_cluster_seed_manifest(profile)? else {
+    let Some(selected) = selected else {
         return Ok(false);
     };
+    let manifest = validate_selected_cluster_seed(selected, profile)?;
 
     ensure_module_matches_seed(module_path, &manifest)?;
-    let seed = cluster_seed_cache(profile)?;
+    let seed = build_cluster_seed_cache(selected, profile, &manifest)?;
     ensure!(
         seed.catalog_profile == profile,
         "cached cluster seed catalog profile mismatch"
@@ -914,6 +923,7 @@ fn publish_cluster_seed_clone(source: &Path, pgdata: &Path) -> Result<()> {
     }
     let result = (|| -> Result<()> {
         clone_cluster_seed_dir(source, &staging)?;
+        super::data_dir::apply_private_permissions(&staging, 0o700)?;
         remove_cluster_seed_runtime_state(&staging)?;
         promote_synced_directory(&staging, pgdata, root, "cluster seed")?;
         Ok(())
@@ -1008,7 +1018,7 @@ fn ensure_module_matches_seed(module_path: &Path, manifest: &ClusterSeedManifest
             .context("WASIX runtime module has no runtime root")?;
         ensure_installed_icu_matches_seed(runtime_root, &icu.data_tree_sha256, strict)?;
     }
-    if strict {
+    {
         let actual_wasm = sha256_file(module_path)?;
         ensure!(
             actual_wasm.eq_ignore_ascii_case(&manifest.runtime.consumer_sha256),
@@ -1022,46 +1032,9 @@ fn ensure_module_matches_seed(module_path: &Path, manifest: &ClusterSeedManifest
 fn ensure_installed_icu_matches_seed(
     runtime_root: &Path,
     seed_tree_sha256: &str,
-    strict: bool,
+    _strict: bool,
 ) -> Result<()> {
-    let expected_archive = assets::expected_icu_data_archive_sha256()
-        .context("ICU cluster seed requires packaged ICU data")?;
-    let expected_tree = assets::expected_icu_data_tree_sha256()
-        .context("packaged ICU data is missing its logical tree digest")?;
-    ensure_installed_icu_identity(
-        runtime_root,
-        seed_tree_sha256,
-        expected_archive,
-        expected_tree,
-        strict,
-    )
-}
-
-fn ensure_installed_icu_identity(
-    runtime_root: &Path,
-    seed_tree_sha256: &str,
-    expected_archive: &str,
-    expected_tree: &str,
-    strict: bool,
-) -> Result<()> {
-    ensure!(
-        seed_tree_sha256.eq_ignore_ascii_case(expected_tree),
-        "packaged ICU data does not match the ICU cluster seed: seed={seed_tree_sha256} packaged={expected_tree}"
-    );
-    let icu_root = runtime_root.join("share/icu");
-    ensure!(
-        icu_data_root_contains_data(&icu_root)?,
-        "installed ICU data is missing under {}",
-        icu_root.display()
-    );
-    ensure!(
-        installed_icu_marker_matches(runtime_root, expected_archive)?,
-        "installed ICU data receipt does not match the packaged ICU data"
-    );
-    if strict {
-        ensure_installed_icu_tree_matches(&icu_root, expected_tree)?;
-    }
-    Ok(())
+    ensure_installed_icu_tree_matches(&runtime_root.join("share/icu"), seed_tree_sha256)
 }
 
 /// Digest the logical portable files tree as sorted `path NUL size NUL file-bytes LF` rows.
@@ -1131,38 +1104,19 @@ fn collect_regular_files(
     Ok(())
 }
 
-fn validated_embedded_cluster_seed_manifest(
+fn validate_selected_cluster_seed(
+    seed: &ClusterSeed,
     profile: CatalogProfile,
-) -> Result> {
-    let Some(seed_manifest) = assets::cluster_seed_manifest(profile) else {
-        return Ok(None);
-    };
-    let Some(seed_archive) = assets::cluster_seed_archive(profile) else {
-        return Ok(None);
-    };
-
-    let manifest = CLUSTER_SEED_MANIFEST
-        .get(profile)
-        .get_or_init(|| {
-            let manifest: ClusterSeedManifest = serde_json::from_slice(seed_manifest)
-                .context("parse embedded cluster seed manifest")
-                .map_err(|err| format!("{err:#}"))?;
-            validate_cluster_seed_manifest_metadata(&manifest, profile)
-                .map_err(|err| format!("{err:#}"))?;
-
-            Ok(manifest)
-        })
-        .clone()
-        .map_err(|message| anyhow!(message))?;
-    if strict_asset_verification()? {
-        let actual_archive = sha256_hex(seed_archive);
-        ensure!(
-            actual_archive.eq_ignore_ascii_case(&manifest.archive.sha256),
-            "embedded cluster seed archive hash mismatch: manifest={} actual={actual_archive}",
-            manifest.archive.sha256
-        );
-    }
-    Ok(Some(manifest))
+) -> Result {
+    let manifest: ClusterSeedManifest =
+        serde_json::from_slice(&seed.manifest).context("parse selected cluster seed manifest")?;
+    validate_cluster_seed_manifest_metadata(&manifest, profile)?;
+    ensure!(
+        seed.archive.len() as u64 == manifest.archive.compressed_bytes
+            && sha256_hex(&seed.archive).eq_ignore_ascii_case(&manifest.archive.sha256),
+        "selected cluster seed archive does not match its manifest"
+    );
+    Ok(manifest)
 }
 
 fn validate_cluster_seed_manifest_metadata(
@@ -1173,7 +1127,9 @@ fn validate_cluster_seed_manifest_metadata(
     validate_cluster_seed_profile_contract(ClusterSeedProfile::from(manifest), selected_profile)?;
     ensure!(
         manifest.runtime.product == "liboliphaunt-wasix"
+            && manifest.runtime.version == liboliphaunt_wasix_portable::PACKAGE_VERSION
             && manifest.runtime.engine_family == "wasix"
+            && manifest.runtime.target == "portable"
             && manifest.runtime.physical_format == "wasix-pg18-v1"
             && manifest.runtime.compatibility_key == "wasix-pg18-datum32-v1"
             && manifest.runtime.postgres_major == 18,
@@ -1184,7 +1140,7 @@ fn validate_cluster_seed_manifest_metadata(
         "embedded cluster seed producer and consumer runtime digests differ"
     );
     ensure!(
-        manifest.archive.path == format!("cluster-seeds/{selected_profile}.tar.zst")
+        !manifest.archive.path.is_empty()
             && manifest.archive.compressed_bytes > 0
             && manifest.archive.expanded_bytes > 0
             && manifest.archive.regular_files > 0
@@ -1196,49 +1152,10 @@ fn validate_cluster_seed_manifest_metadata(
             && manifest.extensions.startup_configuration.is_empty(),
         "embedded cluster seed must be extension-free"
     );
-    let metadata = assets::asset_manifest_metadata_for(profile)?;
-    ensure!(
-        metadata.cluster_seed_profile == selected_profile
-            && metadata.cluster_seed_compatibility_key == "wasix-pg18-datum32-v1",
-        "asset manifest selected cluster seed identity is inconsistent"
-    );
-    let asset_source_lane = metadata
-        .source_lane
-        .as_deref()
-        .context("asset manifest is missing source-lane metadata")?;
-    let seed_source_lane = manifest.source.lane.as_str();
     ensure!(
-        seed_source_lane == asset_source_lane,
-        "embedded cluster seed source lane mismatch: seed={} assets={asset_source_lane}",
-        seed_source_lane
+        manifest.source.producer == "wasix-initdb",
+        "invalid WASIX seed producer"
     );
-    if let Some(pgdata_source_lane) = metadata.cluster_seed_source_lane.as_deref() {
-        ensure!(
-            seed_source_lane == pgdata_source_lane,
-            "embedded cluster seed source lane mismatch: seed={} asset-entry={pgdata_source_lane}",
-            seed_source_lane
-        );
-    }
-
-    if let Some(expected) = metadata.cluster_seed_postgres_version.as_deref() {
-        ensure!(
-            manifest.runtime.postgres_major.to_string() == expected,
-            "embedded cluster seed PostgreSQL version mismatch: seed={} asset-entry={expected}",
-            manifest.runtime.postgres_major
-        );
-    }
-
-    let expected_fingerprint = metadata
-        .cluster_seed_source_fingerprint
-        .as_deref()
-        .or(metadata.source_fingerprint.as_deref());
-    if let Some(expected) = expected_fingerprint {
-        ensure!(
-            manifest.source.fingerprint == expected,
-            "embedded cluster seed source fingerprint mismatch: seed={} assets={expected}",
-            manifest.source.fingerprint
-        );
-    }
 
     Ok(())
 }
@@ -1291,7 +1208,6 @@ fn validate_cluster_seed_profile_contract(
         ensure!(
             manifest.required_runtime_features == ["icu"]
                 && icu.artifact_role == "icu-data"
-                && icu.upstream_version == "76.1"
                 && icu.data_version == "76.1"
                 && icu.data_form == "files-le",
             "ICU cluster seed has an incompatible ICU identity"
@@ -1305,26 +1221,12 @@ fn validate_cluster_seed_profile_contract(
     Ok(())
 }
 
-fn cluster_seed_cache(profile: CatalogProfile) -> Result> {
-    CLUSTER_SEED_CACHE
-        .get(profile)
-        .get_or_init(|| {
-            build_cluster_seed_cache(profile)
-                .map(Arc::new)
-                .map_err(|err| format!("{err:#}"))
-        })
-        .clone()
-        .map_err(|message| anyhow!(message))
-}
-
-fn build_cluster_seed_cache(profile: CatalogProfile) -> Result {
-    let Some(manifest) = validated_embedded_cluster_seed_manifest(profile)? else {
-        bail!("embedded cluster seed manifest is unavailable");
-    };
-    let Some(seed_archive) = assets::cluster_seed_archive(profile) else {
-        bail!("embedded cluster seed archive is unavailable");
-    };
-
+fn build_cluster_seed_cache(
+    selected: &ClusterSeed,
+    profile: CatalogProfile,
+    manifest: &ClusterSeedManifest,
+) -> Result {
+    let seed_archive = selected.archive.as_ref();
     let dirs = ProjectDirs::from("dev", "oliphaunt-wasix", "oliphaunt-wasix")
         .context("could not resolve oliphaunt-wasix cache directory")?;
     let cache_root = dirs
@@ -1355,7 +1257,7 @@ fn build_cluster_seed_cache(profile: CatalogProfile) -> Result Result<()> {
         unpack_cluster_seed_archive(seed_archive, &staging)?;
-        validate_cluster_seed_dir(&staging, &manifest)?;
+        validate_cluster_seed_dir(&staging, manifest)?;
         remove_cluster_seed_runtime_state(&staging)?;
         promote_synced_directory(&staging, &pgdata, &root, "cluster seed cache")
     })();
@@ -1637,8 +1539,10 @@ fn prepare_host_database(
     directory_lock: Option,
     initialize: bool,
     profile: CatalogProfile,
+    seed: Option<&ClusterSeed>,
+    icu_data: Option<&IcuData>,
 ) -> Result {
-    let outcome = prepare_database_root(paths, initialize, profile)?;
+    let outcome = prepare_database_root(paths, initialize, profile, seed, icu_data)?;
     Ok(PreparedDatabase {
         workspace,
         directory_lock,
@@ -1650,7 +1554,14 @@ pub(crate) fn prepare_database(
     plan: DatabasePlan,
     initial_username: &str,
 ) -> Result {
-    plan.catalog_profile.validate_available()?;
+    if plan.icu_data.is_none() {
+        plan.catalog_profile.validate_available()?;
+    } else {
+        ensure!(
+            plan.catalog_profile == CatalogProfile::Icu,
+            "explicit ICU data requires the ICU catalog profile"
+        );
+    }
     if matches!(plan.storage, DatabaseStorage::Memory) {
         ensure_initial_username(DirectoryState::New, initial_username)?;
         return prepare_memory_database(plan);
@@ -1716,6 +1627,8 @@ pub(crate) fn prepare_database(
         Some(directory_lock),
         state == DirectoryState::New,
         plan.catalog_profile,
+        plan.seed.as_ref(),
+        plan.icu_data.as_ref(),
     ) {
         Ok(prepared) => prepared,
         Err(error) if state == DirectoryState::New => {
@@ -1813,18 +1726,19 @@ fn cleanup_failed_open_publication(root: &Path, error: anyhow::Error) -> anyhow:
 
 fn prepare_memory_database(plan: DatabasePlan) -> Result {
     let profile = plan.catalog_profile;
-    let runtime_layout = prepare_memory_runtime_layout(profile)?;
+    let runtime_layout = prepare_memory_runtime_layout(profile, plan.icu_data.as_ref())?;
     let pgdata_storage = PgDataStorage::memory();
     let filesystem = pgdata_storage
         .memory_filesystem()
         .expect("memory storage has a virtual filesystem");
 
-    let manifest = validated_embedded_cluster_seed_manifest(profile)?
-        .context("packaged cluster seed is unavailable")?;
-    ensure_module_matches_seed(&runtime_layout.module_path(), &manifest)?;
-    let archive = assets::cluster_seed_archive(profile)
-        .context("packaged cluster seed archive is unavailable")?;
-    unpack_cluster_seed_archive_virtual(archive, filesystem.as_ref())?;
+    if let Some(seed) = plan.seed.as_ref() {
+        let manifest = validate_selected_cluster_seed(seed, profile)?;
+        ensure_module_matches_seed(&runtime_layout.module_path(), &manifest)?;
+        unpack_cluster_seed_archive_virtual(&seed.archive, filesystem.as_ref())?;
+    } else {
+        PostgresMod::run_split_initdb(&runtime_layout, &pgdata_storage)?;
+    }
 
     remove_virtual_runtime_state(filesystem.as_ref())?;
     ensure!(
@@ -1864,13 +1778,15 @@ pub(crate) fn install_missing_extension_archives(
     Ok(())
 }
 
-pub(crate) fn prepare_database_root(
+fn prepare_database_root(
     paths: OliphauntPaths,
     initialize: bool,
     profile: CatalogProfile,
+    seed: Option<&ClusterSeed>,
+    icu_data: Option<&IcuData>,
 ) -> Result {
-    let mut runtime_layout = prepare_runtime_layout(&paths, profile)?;
-    prepare_pgdata(&paths, initialize, profile, &mut runtime_layout)?;
+    let mut runtime_layout = prepare_runtime_layout(&paths, profile, icu_data)?;
+    prepare_pgdata(&paths, initialize, profile, &mut runtime_layout, seed)?;
     Ok(InstallOutcome {
         runtime_layout,
         pgdata_storage: PgDataStorage::host_directory(paths.pgdata),
@@ -1882,6 +1798,7 @@ fn prepare_pgdata(
     initialize: bool,
     profile: CatalogProfile,
     runtime_layout: &mut RuntimeLayout,
+    seed: Option<&ClusterSeed>,
 ) -> Result<()> {
     ensure!(
         runtime_layout.catalog_profile == profile,
@@ -1897,20 +1814,13 @@ fn prepare_pgdata(
         "existing managed database root has incomplete PGDATA at {}",
         paths.pgdata.display()
     );
-    if try_install_embedded_cluster_seed(paths, &runtime_layout.module_path(), profile)? {
+    if try_install_cluster_seed(paths, &runtime_layout.module_path(), profile, seed)? {
         return Ok(());
     }
-    if std::env::var("OLIPHAUNT_WASIX_DEVELOPMENT_INITDB").as_deref() == Ok("1") {
-        PostgresMod::run_split_initdb(
-            runtime_layout,
-            &PgDataStorage::host_directory(paths.pgdata.clone()),
-        )?;
-    } else {
-        bail!(
-            "the selected packaged {} cluster seed is unavailable; published packages do not silently fall back to initdb",
-            profile.as_str()
-        );
-    }
+    PostgresMod::run_split_initdb(
+        runtime_layout,
+        &PgDataStorage::host_directory(paths.pgdata.clone()),
+    )?;
     ensure!(
         cluster_is_complete(paths),
         "split WASIX initdb finished but did not create a complete PGDATA cluster at {}",
@@ -1919,16 +1829,27 @@ fn prepare_pgdata(
     remove_cluster_seed_runtime_state(&paths.pgdata)
 }
 
-fn runtime_cache(profile: CatalogProfile) -> Result> {
-    RUNTIME_CACHE
-        .get(profile)
-        .get_or_init(|| {
-            build_runtime_cache(profile)
-                .map(Arc::new)
-                .map_err(|err| format!("{err:#}"))
-        })
-        .clone()
-        .map_err(|message| anyhow!(message))
+fn runtime_cache(
+    profile: CatalogProfile,
+    icu_data: Option<&IcuData>,
+) -> Result> {
+    let key = runtime_cache_key(profile, icu_data)?;
+    let cache = RUNTIME_CACHE.get_or_init(|| Mutex::new(BTreeMap::new()));
+    if let Some(runtime) = cache
+        .lock()
+        .expect("runtime cache poisoned")
+        .get(&key)
+        .cloned()
+    {
+        return Ok(runtime);
+    }
+    let runtime = Arc::new(build_runtime_cache(profile, icu_data)?);
+    Ok(cache
+        .lock()
+        .expect("runtime cache poisoned")
+        .entry(key)
+        .or_insert(runtime)
+        .clone())
 }
 
 pub(crate) fn shared_runtime_overlay_enabled() -> bool {
@@ -1938,10 +1859,11 @@ pub(crate) fn shared_runtime_overlay_enabled() -> bool {
 fn prepare_runtime_layout(
     paths: &OliphauntPaths,
     profile: CatalogProfile,
+    icu_data: Option<&IcuData>,
 ) -> Result {
     match resolve_runtime_layout_kind(paths)? {
         RuntimeLayoutKind::FullLocal => {
-            ensure_full_runtime(paths, profile)?;
+            ensure_full_runtime(paths, profile, icu_data)?;
             let (module_path, _) = locate_runtime_module(paths).ok_or_else(|| {
                 anyhow!(
                     "runtime missing: could not locate module under {} after install",
@@ -1962,12 +1884,17 @@ fn prepare_runtime_layout(
             })
         }
         RuntimeLayoutKind::SharedRuntimeOverlay => {
-            let cached_runtime = runtime_cache(profile)?;
+            let cached_runtime = runtime_cache(profile, icu_data)?;
             ensure!(
                 cached_runtime.catalog_profile == profile,
                 "cached runtime catalog profile mismatch"
             );
-            prepare_shared_runtime_upper_root(&cached_runtime.runtime_root, paths, profile)?;
+            prepare_shared_runtime_upper_root(
+                &cached_runtime.runtime_root,
+                paths,
+                profile,
+                icu_data,
+            )?;
             Ok(RuntimeLayout {
                 catalog_profile: profile,
                 kind: RuntimeLayoutKind::SharedRuntimeOverlay,
@@ -1979,8 +1906,11 @@ fn prepare_runtime_layout(
     }
 }
 
-fn prepare_memory_runtime_layout(profile: CatalogProfile) -> Result {
-    let cached_runtime = runtime_cache(profile)?;
+fn prepare_memory_runtime_layout(
+    profile: CatalogProfile,
+    icu_data: Option<&IcuData>,
+) -> Result {
+    let cached_runtime = runtime_cache(profile, icu_data)?;
     ensure!(
         cached_runtime.catalog_profile == profile,
         "cached runtime catalog profile mismatch"
@@ -2052,8 +1982,11 @@ fn read_runtime_layout_manifest(runtime_root: &Path) -> Result Result {
-    let key = runtime_cache_key(profile)?;
+fn build_runtime_cache(
+    profile: CatalogProfile,
+    icu_data: Option<&IcuData>,
+) -> Result {
+    let key = runtime_cache_key(profile, icu_data)?;
     let dirs = ProjectDirs::from("dev", "oliphaunt-wasix", "oliphaunt-wasix")
         .context("could not resolve oliphaunt-wasix cache directory")?;
     let cache_root = dirs.cache_dir().join("runtime");
@@ -2063,7 +1996,7 @@ fn build_runtime_cache(profile: CatalogProfile) -> Result {
     let cache_is_current = runtime_cache_completion_matches(&root, &key)?
         && locate_runtime_module(&paths).is_some()
         && full_runtime_layout_matches_current(&paths, profile, &key)?
-        && installed_profile_data_matches(&paths.runtime_root(), profile)?
+        && installed_profile_data_matches(&paths.runtime_root(), profile, icu_data)?
         && !runtime_support_files_need_repair(&paths)?;
     if !cache_is_current {
         let staging = cache_root.join(format!(".{key}.build"));
@@ -2074,7 +2007,7 @@ fn build_runtime_cache(profile: CatalogProfile) -> Result {
         }
         let staging_paths = OliphauntPaths::with_root(&staging);
         let build_result = (|| -> Result<()> {
-            ensure_full_runtime(&staging_paths, profile)?;
+            ensure_full_runtime(&staging_paths, profile, icu_data)?;
             reset_runtime_cache_mutable_state(&staging_paths.runtime_root())?;
             let marker = staging.join(RUNTIME_CACHE_COMPLETION_MARKER);
             fs::write(&marker, format!("{key}\n")).with_context(|| {
@@ -2100,11 +2033,6 @@ fn build_runtime_cache(profile: CatalogProfile) -> Result {
             )
         })?
     };
-    if strict_asset_verification()?
-        && let Some(manifest) = validated_embedded_cluster_seed_manifest(profile)?
-    {
-        ensure_module_matches_seed(&module_path, &manifest)?;
-    }
     let runtime_root = module_path
         .parent()
         .and_then(Path::parent)
@@ -2199,21 +2127,19 @@ fn ensure_runtime_password_file(runtime_root: &Path) -> Result<()> {
     Ok(())
 }
 
-fn runtime_cache_key(profile: CatalogProfile) -> Result {
-    RUNTIME_CACHE_KEY
-        .get(profile)
-        .get_or_init(|| build_runtime_cache_key(profile).map_err(|error| format!("{error:#}")))
-        .clone()
-        .map_err(|message| anyhow!(message))
+fn runtime_cache_key(profile: CatalogProfile, icu_data: Option<&IcuData>) -> Result {
+    build_runtime_cache_key(profile, icu_data)
 }
 
-fn build_runtime_cache_key(profile: CatalogProfile) -> Result {
+fn build_runtime_cache_key(profile: CatalogProfile, icu_data: Option<&IcuData>) -> Result {
     ensure!(
         assets::runtime_archive().is_some(),
         "Oliphaunt WASIX runtime assets are unavailable; package-manager-resolved runtime artifacts were not staged"
     );
     let runtime_sha256 = assets::expected_runtime_archive_sha256()?;
-    let icu_sha256 = if assets::icu_data_archive(profile).is_some() {
+    let icu_sha256 = if let Some(data) = icu_data {
+        Some(data.tree_sha256.as_str())
+    } else if assets::icu_data_archive(profile).is_some() {
         Some(
             assets::expected_icu_data_archive_sha256()
                 .context("embedded ICU data archive is missing its packaged digest")?,
@@ -2253,6 +2179,7 @@ fn prepare_shared_runtime_upper_root(
     src_runtime: &Path,
     paths: &OliphauntPaths,
     profile: CatalogProfile,
+    icu_data: Option<&IcuData>,
 ) -> Result<()> {
     let dest_runtime = paths.runtime_root();
 
@@ -2285,7 +2212,7 @@ fn prepare_shared_runtime_upper_root(
         &dest_runtime,
         RuntimeLayoutKind::SharedRuntimeOverlay,
         profile,
-        &runtime_cache_key(profile)?,
+        &runtime_cache_key(profile, icu_data)?,
     )?;
     Ok(())
 }
@@ -2317,26 +2244,56 @@ fn copy_runtime_file_if_exists(src: PathBuf, dest: PathBuf) -> Result<()> {
 mod tests {
     use super::*;
 
+    #[test]
+    fn selected_seed_rejects_wrong_payload_profile_and_runtime() -> Result<()> {
+        let archive = b"selected resource bytes";
+        let digest = sha256_hex(archive);
+        let mut manifest = serde_json::json!({
+            "schema": "oliphaunt-cluster-seed-v1",
+            "artifactRole": "cluster-seed-standard",
+            "catalogProfile": "standard",
+            "runtime": {
+                "product": "liboliphaunt-wasix",
+                "version": liboliphaunt_wasix_portable::PACKAGE_VERSION,
+                "engineFamily": "wasix", "target": "portable",
+                "physicalFormat": "wasix-pg18-v1", "postgresMajor": 18,
+                "compatibilityKey": "wasix-pg18-datum32-v1",
+                "consumerSha256": digest, "producerSha256": digest, "initdbSha256": digest
+            },
+            "source": { "producer": "wasix-initdb" },
+            "archive": { "path": "seed.tar.zst", "sha256": digest,
+                "compressedBytes": archive.len(), "expandedBytes": 1,
+                "regularFiles": 1, "directories": 1 },
+            "requiredRuntimeFeatures": [],
+            "extensions": { "selected": [], "startupConfiguration": [] }, "icu": null
+        });
+        let seed = ClusterSeed::new(archive.as_slice(), serde_json::to_vec(&manifest)?);
+        validate_selected_cluster_seed(&seed, CatalogProfile::Standard)?;
+        assert!(validate_selected_cluster_seed(&seed, CatalogProfile::Icu).is_err());
+        let changed = ClusterSeed::new(b"changed resource bytes".as_slice(), seed.manifest.clone());
+        assert!(validate_selected_cluster_seed(&changed, CatalogProfile::Standard).is_err());
+        manifest["runtime"]["target"] = "linux-x64-gnu".into();
+        let foreign = ClusterSeed::new(archive.as_slice(), serde_json::to_vec(&manifest)?);
+        assert!(validate_selected_cluster_seed(&foreign, CatalogProfile::Standard).is_err());
+        manifest["runtime"]["target"] = "portable".into();
+        manifest["runtime"]["version"] = "different-runtime".into();
+        let foreign = ClusterSeed::new(archive.as_slice(), serde_json::to_vec(&manifest)?);
+        assert!(validate_selected_cluster_seed(&foreign, CatalogProfile::Standard).is_err());
+        Ok(())
+    }
+
     #[cfg(feature = "icu")]
     #[derive(Debug)]
     struct PreparedProfileSnapshot {
         profile: CatalogProfile,
         runtime_root: PathBuf,
         runtime_manifest_profile: Option,
-        seed_root: PathBuf,
-        seed_manifest_profile: String,
         has_icu_data: bool,
     }
 
     #[cfg(feature = "icu")]
     fn both_catalog_profiles_are_packaged() -> bool {
         assets::runtime_archive().is_some()
-            && [CatalogProfile::Standard, CatalogProfile::Icu]
-                .into_iter()
-                .all(|profile| {
-                    assets::cluster_seed_archive(profile).is_some()
-                        && assets::cluster_seed_manifest(profile).is_some()
-                })
             && assets::icu_data_archive(CatalogProfile::Icu).is_some()
     }
 
@@ -2353,24 +2310,15 @@ mod tests {
         );
         let runtime_manifest = read_runtime_layout_manifest(&layout.module_root)?
             .context("profile runtime cache is missing its layout manifest")?;
-        let seed_manifest = validated_embedded_cluster_seed_manifest(profile)?
-            .context("selected catalog profile is missing its seed manifest")?;
-        let seed = cluster_seed_cache(profile)?;
-        ensure!(
-            seed.catalog_profile == profile,
-            "selected catalog profile resolved the wrong seed cache"
-        );
         let has_icu_data = icu_data_root_contains_data(&layout.module_root.join("share/icu"))?;
         ensure!(
-            installed_profile_data_matches(&layout.module_root, profile)?,
+            installed_profile_data_matches(&layout.module_root, profile, None)?,
             "prepared runtime has a mismatched catalog-profile data receipt"
         );
         Ok(PreparedProfileSnapshot {
             profile,
             runtime_root: layout.module_root.clone(),
             runtime_manifest_profile: runtime_manifest.catalog_profile,
-            seed_root: seed.pgdata.clone(),
-            seed_manifest_profile: seed_manifest.catalog_profile,
             has_icu_data,
         })
     }
@@ -2385,16 +2333,13 @@ mod tests {
             standard.runtime_manifest_profile,
             Some(CatalogProfile::Standard)
         );
-        assert_eq!(standard.seed_manifest_profile, "standard");
         assert!(!standard.has_icu_data);
 
         assert_eq!(icu.profile, CatalogProfile::Icu);
         assert_eq!(icu.runtime_manifest_profile, Some(CatalogProfile::Icu));
-        assert_eq!(icu.seed_manifest_profile, "icu");
         assert!(icu.has_icu_data);
 
         assert_ne!(standard.runtime_root, icu.runtime_root);
-        assert_ne!(standard.seed_root, icu.seed_root);
     }
 
     #[derive(Deserialize)]
@@ -2471,53 +2416,28 @@ mod tests {
         let root = TempDir::new()?;
         assert!(installed_profile_data_matches(
             root.path(),
-            CatalogProfile::Standard
+            CatalogProfile::Standard,
+            None
         )?);
 
         fs::create_dir_all(root.path().join("share/icu/icudt76l"))?;
         fs::write(root.path().join("share/icu/icudt76l/data.res"), b"icu")?;
         assert!(!installed_profile_data_matches(
             root.path(),
-            CatalogProfile::Standard
+            CatalogProfile::Standard,
+            None
         )?);
 
         fs::remove_dir_all(root.path().join("share/icu"))?;
         fs::write(root.path().join(ICU_DATA_MARKER_NAME), b"stale\n")?;
         assert!(!installed_profile_data_matches(
             root.path(),
-            CatalogProfile::Standard
+            CatalogProfile::Standard,
+            None
         )?);
         Ok(())
     }
 
-    #[test]
-    fn profile_once_lock_keeps_parallel_profiles_independent() {
-        let cache = Arc::new(ProfileOnceLock::new());
-        let mut handles = Vec::new();
-        for profile in [
-            CatalogProfile::Standard,
-            CatalogProfile::Icu,
-            CatalogProfile::Icu,
-            CatalogProfile::Standard,
-        ] {
-            let cache = Arc::clone(&cache);
-            handles.push(std::thread::spawn(move || {
-                *cache.get(profile).get_or_init(|| match profile {
-                    CatalogProfile::Standard => 11_u8,
-                    CatalogProfile::Icu => 29_u8,
-                })
-            }));
-        }
-
-        let values = handles
-            .into_iter()
-            .map(|handle| handle.join().expect("profile cache worker must finish"))
-            .collect::>();
-        assert_eq!(values, [11, 29, 29, 11]);
-        assert_eq!(cache.get(CatalogProfile::Standard).get(), Some(&11));
-        assert_eq!(cache.get(CatalogProfile::Icu).get(), Some(&29));
-    }
-
     #[test]
     fn runtime_cache_identity_includes_catalog_profile() {
         let standard = runtime_cache_key_from_digests(
@@ -2557,9 +2477,7 @@ mod tests {
         let standard_second = prepare_profile_snapshot(CatalogProfile::Standard)?;
         assert_profile_snapshots_do_not_contaminate(&standard_second, &icu_first);
         assert_eq!(standard_first.runtime_root, standard_second.runtime_root);
-        assert_eq!(standard_first.seed_root, standard_second.seed_root);
         assert_eq!(icu_second.runtime_root, icu_first.runtime_root);
-        assert_eq!(icu_second.seed_root, icu_first.seed_root);
         Ok(())
     }
 
@@ -2583,63 +2501,10 @@ mod tests {
         Ok(())
     }
 
-    #[test]
-    fn installed_icu_uses_receipt_normally_and_hashes_the_tree_only_when_strict() -> Result<()> {
-        let root = tempfile::tempdir()?;
-        let icu_root = root.path().join("share/icu/icudt76l");
-        fs::create_dir_all(&icu_root)?;
-        fs::write(icu_root.join("data.dat"), b"installed bytes")?;
-
-        let archive_sha256 = "a".repeat(64);
-        let declared_tree_sha256 = "b".repeat(64);
-        fs::write(
-            root.path().join(ICU_DATA_MARKER_NAME),
-            format!("{archive_sha256}\n"),
-        )?;
-
-        ensure_installed_icu_identity(
-            root.path(),
-            &declared_tree_sha256,
-            &archive_sha256,
-            &declared_tree_sha256,
-            false,
-        )?;
-        let error = ensure_installed_icu_identity(
-            root.path(),
-            &declared_tree_sha256,
-            &archive_sha256,
-            &declared_tree_sha256,
-            true,
-        )
-        .expect_err("strict verification must hash the installed tree");
-        assert!(error.to_string().contains("tree hash mismatch"));
-
-        let actual_tree_sha256 = logical_tree_sha256(&root.path().join("share/icu"))?;
-        ensure_installed_icu_identity(
-            root.path(),
-            &actual_tree_sha256,
-            &archive_sha256,
-            &actual_tree_sha256,
-            true,
-        )?;
-
-        fs::write(root.path().join(ICU_DATA_MARKER_NAME), "stale\n")?;
-        let error = ensure_installed_icu_identity(
-            root.path(),
-            &declared_tree_sha256,
-            &archive_sha256,
-            &declared_tree_sha256,
-            false,
-        )
-        .expect_err("normal verification must reject a stale receipt");
-        assert!(error.to_string().contains("receipt does not match"));
-        Ok(())
-    }
-
     #[test]
     fn shared_cluster_seed_profile_fixtures_match_binding_semantics() -> Result<()> {
         let fixture_root = Path::new(env!("CARGO_MANIFEST_DIR"))
-            .join("../../../../shared/cluster-seed-contract/fixtures");
+            .join("../../database-resources/contracts/fixtures");
         let standard: SharedClusterSeedProfile = serde_json::from_str(&fs::read_to_string(
             fixture_root.join("standard.valid.json"),
         )?)?;
@@ -2706,6 +2571,12 @@ mod tests {
         fs::write(source.path().join("global/pg_control"), b"control")?;
         fs::write(source.path().join("postmaster.pid"), b"stale")?;
 
+        #[cfg(unix)]
+        {
+            use std::os::unix::fs::PermissionsExt;
+            fs::set_permissions(source.path(), fs::Permissions::from_mode(0o755))?;
+        }
+
         let parent = TempDir::new()?;
         let root = parent.path().join("database");
         fs::create_dir(&root)?;
@@ -2718,6 +2589,12 @@ mod tests {
 
         assert!(pgdata.join("PG_VERSION").is_file());
         assert!(pgdata.join("global/pg_control").is_file());
+        assert!(pgdata.join("pg_wal").is_dir());
+        #[cfg(unix)]
+        {
+            use std::os::unix::fs::PermissionsExt;
+            assert_eq!(fs::metadata(&pgdata)?.permissions().mode() & 0o777, 0o700);
+        }
         assert!(!pgdata.join("postmaster.pid").exists());
         assert!(!staging.exists());
         Ok(())
@@ -2758,8 +2635,7 @@ mod tests {
     #[test]
     fn memory_storage_uses_no_host_workspace() -> Result<()> {
         let profile = CatalogProfile::default();
-        if assets::cluster_seed_archive(profile).is_none()
-            || assets::cluster_seed_manifest(profile).is_none()
+        if assets::runtime_archive().is_none()
             || (profile == CatalogProfile::Icu && assets::icu_data_archive(profile).is_none())
         {
             return Ok(());
@@ -2812,69 +2688,6 @@ mod tests {
         Ok(())
     }
 
-    #[cfg(feature = "extensions")]
-    #[test]
-    fn embedded_cluster_seed_installs_valid_cluster() -> Result<()> {
-        if !embedded_cluster_seed_is_available() {
-            return Ok(());
-        }
-
-        let temp_dir = TempDir::new()?;
-        let paths = OliphauntPaths::with_root(temp_dir.path());
-        let profile = CatalogProfile::default();
-        ensure_full_runtime(&paths, profile)?;
-
-        let (module_path, _) =
-            locate_runtime_module(&paths).context("runtime module should be installed")?;
-        assert!(try_install_embedded_cluster_seed(
-            &paths,
-            &module_path,
-            profile,
-        )?);
-
-        assert!(paths.pgdata.join("PG_VERSION").exists());
-        assert!(paths.pgdata.join("global/pg_control").exists());
-        assert!(!paths.pgdata.join("postmaster.pid").exists());
-        Ok(())
-    }
-
-    #[cfg(feature = "extensions")]
-    #[test]
-    fn embedded_cluster_seed_replaces_interrupted_pgdata() -> Result<()> {
-        if !embedded_cluster_seed_is_available() {
-            return Ok(());
-        }
-
-        let temp_dir = TempDir::new()?;
-        let paths = OliphauntPaths::with_root(temp_dir.path());
-        let profile = CatalogProfile::default();
-        ensure_full_runtime(&paths, profile)?;
-        fs::create_dir_all(paths.pgdata.join("global"))?;
-        fs::write(paths.pgdata.join("postmaster.pid"), b"stale pid")?;
-        fs::write(paths.pgdata.join("base.tmp"), b"interrupted initdb")?;
-
-        let (module_path, _) =
-            locate_runtime_module(&paths).context("runtime module should be installed")?;
-        assert!(try_install_embedded_cluster_seed(
-            &paths,
-            &module_path,
-            profile,
-        )?);
-
-        assert!(paths.pgdata.join("PG_VERSION").exists());
-        assert!(paths.pgdata.join("global/pg_control").exists());
-        assert!(!paths.pgdata.join("postmaster.pid").exists());
-        assert!(!paths.pgdata.join("base.tmp").exists());
-        Ok(())
-    }
-
-    #[cfg(feature = "extensions")]
-    fn embedded_cluster_seed_is_available() -> bool {
-        let profile = CatalogProfile::default();
-        assets::cluster_seed_archive(profile).is_some()
-            && assets::cluster_seed_manifest(profile).is_some()
-    }
-
     #[test]
     fn directory_lock_is_exclusive_until_dropped() -> Result<()> {
         let temp_dir = TempDir::new()?;
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/base/cluster_seed_clone.rs b/src/sdks/rust-wasix/src/oliphaunt/base/cluster_seed_clone.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/base/cluster_seed_clone.rs
rename to src/sdks/rust-wasix/src/oliphaunt/base/cluster_seed_clone.rs
diff --git a/src/sdks/rust-wasix/src/oliphaunt/builder.rs b/src/sdks/rust-wasix/src/oliphaunt/builder.rs
new file mode 100644
index 000000000..fa38cc68a
--- /dev/null
+++ b/src/sdks/rust-wasix/src/oliphaunt/builder.rs
@@ -0,0 +1,287 @@
+use anyhow::Result;
+
+use crate::oliphaunt::assets::{CatalogProfile, ClusterSeed, IcuData, default_catalog_profile};
+#[cfg(feature = "extensions")]
+use crate::oliphaunt::base::install_missing_extension_archives;
+use crate::oliphaunt::base::{DatabasePlan, PreparedDatabase, prepare_database};
+use crate::oliphaunt::client::Oliphaunt;
+use crate::oliphaunt::config::{PostgresConfig, StartupConfig};
+#[cfg(feature = "extensions")]
+use crate::oliphaunt::extensions::{
+    Extension, postgres_config_with_extension_startup, resolve_extension_set,
+};
+use crate::oliphaunt::storage::DatabaseStorage;
+
+/// Builder for opening [`Oliphaunt`] databases.
+#[derive(Debug, Clone)]
+pub struct OliphauntBuilder {
+    storage: DatabaseStorage,
+    catalog_profile: CatalogProfile,
+    seed: Option,
+    icu_data: Option,
+    postgres_config: PostgresConfig,
+    startup_config: StartupConfig,
+    #[cfg(feature = "extensions")]
+    extensions: Vec,
+}
+
+impl Default for OliphauntBuilder {
+    fn default() -> Self {
+        Self {
+            storage: DatabaseStorage::Memory,
+            catalog_profile: default_catalog_profile(),
+            seed: None,
+            icu_data: None,
+            postgres_config: PostgresConfig::default(),
+            startup_config: StartupConfig::default(),
+            #[cfg(feature = "extensions")]
+            extensions: Vec::new(),
+        }
+    }
+}
+
+impl OliphauntBuilder {
+    /// Create a builder for a memory database.
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Select where PostgreSQL stores its mutable database files.
+    pub fn storage(mut self, storage: DatabaseStorage) -> Self {
+        self.storage = storage;
+        self
+    }
+
+    /// Use an explicitly selected seed for new storage. Existing storage ignores it.
+    pub fn seed(mut self, seed: ClusterSeed) -> Self {
+        self.seed = Some(seed);
+        self
+    }
+
+    /// Supply verified ICU data without embedding a resource carrier in the SDK.
+    pub fn icu_data(mut self, data: IcuData) -> Self {
+        self.icu_data = Some(data);
+        self.catalog_profile = CatalogProfile::Icu;
+        self
+    }
+
+    /// Select the standard or ICU catalog and matching runtime data.
+    pub fn catalog_profile(mut self, profile: CatalogProfile) -> Self {
+        self.catalog_profile = profile;
+        self
+    }
+
+    /// Set a PostgreSQL startup GUC for this embedded backend.
+    pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self {
+        self.postgres_config.insert(name, value);
+        self
+    }
+
+    /// Set multiple PostgreSQL startup GUCs for this embedded backend.
+    pub fn startup_gucs(mut self, settings: impl IntoIterator) -> Self
+    where
+        K: Into,
+        V: Into,
+    {
+        for (name, value) in settings {
+            self.postgres_config.insert(name, value);
+        }
+        self
+    }
+
+    /// Connect as a PostgreSQL role. The role must already exist in the
+    /// cluster.
+    pub fn username(mut self, username: impl Into) -> Self {
+        self.startup_config.username = username.into();
+        self
+    }
+
+    /// Connect to a PostgreSQL database. The database must already exist in the
+    /// cluster.
+    pub fn database(mut self, database: impl Into) -> Self {
+        self.startup_config.database = database.into();
+        self
+    }
+
+    /// Make one bundled PostgreSQL extension artifact available to the database.
+    /// Database-local installation remains the application's migration concern.
+    #[cfg(feature = "extensions")]
+    pub fn extension(mut self, extension: Extension) -> Self {
+        self.extensions.push(extension);
+        self
+    }
+
+    /// Make bundled PostgreSQL extension artifacts available to the database.
+    /// Database-local installation remains the application's migration concern.
+    #[cfg(feature = "extensions")]
+    pub fn extensions(mut self, extensions: impl IntoIterator) -> Self {
+        self.extensions.extend(extensions);
+        self
+    }
+
+    /// Install, initialize, and start the selected database.
+    pub fn open(self) -> crate::Result {
+        crate::error::public_result(self.open_inner())
+    }
+
+    pub(crate) fn open_inner(self) -> Result {
+        #[cfg(feature = "extensions")]
+        let (extensions, postgres_config) = self.resolved_extension_startup()?;
+        #[cfg(not(feature = "extensions"))]
+        let postgres_config = self.postgres_config.clone();
+        postgres_config.validate()?;
+        self.storage.validate()?;
+        self.startup_config.validate()?;
+        let mut plan = DatabasePlan::new(self.storage.clone(), self.catalog_profile);
+        plan.seed = self.seed.clone();
+        plan.icu_data = self.icu_data.clone();
+        let prepared = prepare_database(plan, &self.startup_config.username)?;
+        #[cfg(feature = "extensions")]
+        {
+            self.open_prepared_database(prepared, extensions, postgres_config)
+        }
+        #[cfg(not(feature = "extensions"))]
+        {
+            self.open_prepared_database(prepared, postgres_config)
+        }
+    }
+
+    #[cfg(feature = "extensions")]
+    fn resolved_extension_startup(&self) -> Result<(Vec, PostgresConfig)> {
+        let extensions = resolve_extension_set(&self.extensions)?;
+        let postgres_config =
+            postgres_config_with_extension_startup(self.postgres_config.clone(), &extensions)?;
+        Ok((extensions, postgres_config))
+    }
+
+    fn open_prepared_database(
+        self,
+        prepared: PreparedDatabase,
+        #[cfg(feature = "extensions")] extensions: Vec,
+        postgres_config: PostgresConfig,
+    ) -> Result {
+        let PreparedDatabase {
+            workspace,
+            directory_lock,
+            outcome,
+        } = prepared;
+        #[cfg(feature = "extensions")]
+        install_missing_extension_archives(&outcome, &extensions)?;
+        #[cfg(feature = "extensions")]
+        let mut instance = Oliphaunt::new_prepared_with_config_and_extension_preload(
+            outcome,
+            postgres_config,
+            self.startup_config,
+            &extensions,
+        )?;
+        #[cfg(not(feature = "extensions"))]
+        let mut instance =
+            Oliphaunt::new_prepared_with_config(outcome, postgres_config, self.startup_config)?;
+        if let Some(lock) = directory_lock {
+            instance.attach_directory_lock(lock);
+        }
+        if let Some(workspace) = workspace {
+            instance.attach_workspace(workspace);
+        }
+        Ok(instance)
+    }
+}
+
+#[cfg(test)]
+mod storage_tests {
+    use super::*;
+
+    #[test]
+    fn default_builder_selects_memory() {
+        let builder = OliphauntBuilder::default();
+        assert_eq!(builder.storage, DatabaseStorage::Memory);
+        assert_eq!(builder.catalog_profile, CatalogProfile::default());
+    }
+
+    #[test]
+    fn catalog_profile_is_an_immutable_builder_value() {
+        let standard = OliphauntBuilder::new().catalog_profile(CatalogProfile::Standard);
+        let icu = standard.clone().catalog_profile(CatalogProfile::Icu);
+
+        assert_eq!(standard.catalog_profile, CatalogProfile::Standard);
+        assert_eq!(icu.catalog_profile, CatalogProfile::Icu);
+    }
+
+    #[cfg(not(feature = "icu"))]
+    #[test]
+    fn unavailable_icu_profile_is_rejected_before_storage_mutation() {
+        let parent = tempfile::tempdir().expect("temporary parent");
+        let root = parent.path().join("database");
+        let error = OliphauntBuilder::new()
+            .storage(DatabaseStorage::Directory(root.clone()))
+            .catalog_profile(CatalogProfile::Icu)
+            .open()
+            .err()
+            .expect("ICU profile requires its packaging feature");
+
+        assert_eq!(error.kind(), crate::ErrorKind::InvalidConfiguration);
+        assert!(error.to_string().contains("requires"));
+        assert!(!root.exists());
+    }
+
+    #[test]
+    fn fluent_configuration_preserves_postgres_vocabulary() {
+        let directory = std::path::PathBuf::from("database-root");
+        let builder = OliphauntBuilder::new()
+            .storage(DatabaseStorage::Directory(directory.clone()))
+            .startup_guc("work_mem", "16MB")
+            .startup_gucs([("application_name", "builder-test")])
+            .username("app_user")
+            .database("app_database");
+
+        assert_eq!(builder.storage, DatabaseStorage::Directory(directory));
+        assert_eq!(
+            builder.postgres_config.iter().collect::>(),
+            vec![("application_name", "builder-test"), ("work_mem", "16MB")]
+        );
+        assert_eq!(builder.startup_config.username, "app_user");
+        assert_eq!(builder.startup_config.database, "app_database");
+    }
+
+    #[test]
+    fn open_rejects_invalid_startup_configuration_before_runtime_work() {
+        let error = OliphauntBuilder::new()
+            .startup_guc("bad=name", "value")
+            .open()
+            .err()
+            .expect("invalid GUCs must fail before preparing a database");
+
+        assert!(error.to_string().contains("must not contain"));
+    }
+}
+
+#[cfg(all(test, feature = "extension-pg-textsearch"))]
+mod tests {
+    use super::*;
+    use crate::oliphaunt::extensions::Extension;
+
+    #[test]
+    fn direct_path_merges_pg_textsearch_preload_once_before_open() {
+        let builder = OliphauntBuilder::new()
+            .startup_guc("shared_preload_libraries", "auto_explain")
+            .startup_guc("work_mem", "16MB")
+            .extensions([Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH]);
+
+        let (_, postgres_config) = builder.resolved_extension_startup().unwrap();
+
+        assert_eq!(
+            postgres_config.get("shared_preload_libraries"),
+            Some("auto_explain,pg_textsearch")
+        );
+        assert_eq!(postgres_config.get("work_mem"), Some("16MB"));
+        assert_eq!(
+            postgres_config
+                .get("shared_preload_libraries")
+                .unwrap()
+                .split(',')
+                .filter(|library| *library == "pg_textsearch")
+                .count(),
+            1
+        );
+    }
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/client.rs b/src/sdks/rust-wasix/src/oliphaunt/client.rs
similarity index 98%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/client.rs
rename to src/sdks/rust-wasix/src/oliphaunt/client.rs
index b01e49fe0..fc7af8911 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/client.rs
+++ b/src/sdks/rust-wasix/src/oliphaunt/client.rs
@@ -6,13 +6,13 @@ use std::sync::{Arc, Mutex};
 
 use anyhow::{Context, Result, bail, ensure};
 use tempfile::TempDir;
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 use tokio::io::AsyncWriteExt;
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 use tokio::runtime::Runtime;
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 use wasmer_wasix::virtual_net::tcp_pair::TcpSocketHalfRx;
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 use wasmer_wasix::virtual_net::tcp_pair::TcpSocketHalfTx;
 
 use crate::oliphaunt::backend::BackendSession;
@@ -39,16 +39,16 @@ use crate::oliphaunt::query::{
 use crate::oliphaunt::storage::PgDataStorage;
 #[cfg(all(feature = "extensions", test))]
 use crate::oliphaunt::storage::StorageRoot;
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 use crate::oliphaunt::tools::{
     DirectToolSocket, PgDumpOptions, PostgresToolOutput, PsqlOptions, decode_tool_output,
     is_direct_tool_outcome_unknown, run_direct_pg_dump_output, run_direct_psql_output,
 };
-#[cfg(feature = "tools")]
-use crate::oliphaunt::wire::{FrontendFrameKind, FrontendFrameReader, classify_frontend_message};
+#[cfg(feature = "tools-execution")]
+use oliphaunt_query::wire::{FrontendFrameKind, FrontendFrameReader, classify_frontend_message};
 
 const PROTOCOL_CALLBACK_CHUNK_BYTES: usize = 64 * 1024;
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 const DIRECT_TOOL_READ_BUFFER_BYTES: usize = 64 * 1024;
 
 /// Direct, single-session Oliphaunt WASIX database.
@@ -385,7 +385,7 @@ struct CallbackProtocolState {
     callback: Option,
     error: Option,
     panic: Option,
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     tool_io: Option,
 }
 
@@ -395,7 +395,7 @@ struct CallbackProtocolStream {
 
 impl Read for CallbackProtocolStream {
     fn read(&mut self, buffer: &mut [u8]) -> io::Result {
-        #[cfg(feature = "tools")]
+        #[cfg(feature = "tools-execution")]
         {
             let mut state = self
                 .state
@@ -416,7 +416,7 @@ impl Write for CallbackProtocolStream {
             .state
             .lock()
             .map_err(|_| io::Error::other("WASIX protocol callback lock poisoned"))?;
-        #[cfg(feature = "tools")]
+        #[cfg(feature = "tools-execution")]
         if let Some(tool_io) = state.tool_io.as_mut() {
             return tool_io.write(buffer);
         }
@@ -449,7 +449,7 @@ impl Write for CallbackProtocolStream {
     }
 
     fn flush(&mut self) -> io::Result<()> {
-        #[cfg(feature = "tools")]
+        #[cfg(feature = "tools-execution")]
         {
             let mut state = self
                 .state
@@ -465,7 +465,7 @@ impl Write for CallbackProtocolStream {
 
 impl ProtocolStream for CallbackProtocolStream {
     fn read_ready(&mut self) -> io::Result {
-        #[cfg(feature = "tools")]
+        #[cfg(feature = "tools-execution")]
         {
             let state = self
                 .state
@@ -1022,13 +1022,13 @@ impl Oliphaunt {
         Ok(())
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn run_pg_dump_tool(&mut self, options: PgDumpOptions) -> Result {
         self.run_pg_dump_tool_output(options)
             .and_then(|output| decode_tool_output("pg_dump", output))
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn run_pg_dump_tool_output(
         &mut self,
         options: PgDumpOptions,
@@ -1043,13 +1043,13 @@ impl Oliphaunt {
         self.finish_tool_session(result)
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn run_psql_tool(&mut self, options: PsqlOptions) -> Result {
         self.run_psql_tool_output(options)
             .and_then(|output| decode_tool_output("psql", output))
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn run_psql_tool_output(
         &mut self,
         options: PsqlOptions,
@@ -1064,7 +1064,7 @@ impl Oliphaunt {
         self.finish_tool_session(result)
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     fn prepare_tool_session(&mut self) -> Result<()> {
         self.check_ready()?;
         if self.in_transaction {
@@ -1076,7 +1076,7 @@ impl Oliphaunt {
             .context("prepare embedded session for WASIX tool")
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     fn finish_tool_session(&mut self, result: Result) -> Result {
         let outcome_unknown = result
             .as_ref()
@@ -1102,7 +1102,7 @@ impl Oliphaunt {
         }
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     fn reset_tool_session(&mut self) -> Result<()> {
         self.execute_inner("ROLLBACK")
             .context("roll back embedded session")?;
@@ -1119,7 +1119,7 @@ impl Oliphaunt {
         Ok(())
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     fn serve_direct_tool_protocol(&mut self, socket: DirectToolSocket) -> Result<()> {
         self.ensure_protocol_stream_attached()?;
         {
@@ -1148,7 +1148,7 @@ impl Oliphaunt {
         result.and(cleanup)
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     fn serve_direct_tool_protocol_inner(&mut self) -> Result<()> {
         let mut reader = FrontendFrameReader::default();
         let mut buffer = [0u8; DIRECT_TOOL_READ_BUFFER_BYTES];
@@ -1189,12 +1189,12 @@ impl Oliphaunt {
         }
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     fn write_direct_tool_protocol(&self, bytes: &[u8]) -> Result<()> {
         self.with_direct_tool_io(|tool_io| tool_io.write_all(bytes))
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     fn with_direct_tool_io(
         &self,
         operation: impl FnOnce(&mut DirectToolProtocolIo) -> io::Result,
@@ -1218,25 +1218,25 @@ impl Oliphaunt {
     }
 
     /// Run packaged `pg_dump` directly against this database.
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub fn pg_dump(&mut self, options: PgDumpOptions) -> crate::Result {
         crate::error::public_result(self.run_pg_dump_tool(options))
     }
 
     /// Run packaged `pg_dump` and return exact stdout/stderr bytes.
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub fn pg_dump_output(&mut self, options: PgDumpOptions) -> crate::Result {
         crate::error::public_result(self.run_pg_dump_tool_output(options))
     }
 
     /// Run packaged non-interactive `psql` directly against this database.
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub fn psql(&mut self, options: PsqlOptions) -> crate::Result {
         crate::error::public_result(self.run_psql_tool(options))
     }
 
     /// Run packaged non-interactive `psql` and return exact stdout/stderr bytes.
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub fn psql_output(&mut self, options: PsqlOptions) -> crate::Result {
         crate::error::public_result(self.run_psql_tool_output(options))
     }
@@ -1562,7 +1562,7 @@ impl Oliphaunt {
     }
 }
 
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 fn finish_direct_tool_frontend(reader: &FrontendFrameReader) -> Result<()> {
     ensure!(
         reader.pending().is_empty(),
@@ -1626,11 +1626,11 @@ fn parse_start_backup_result(result: &QueryResult) -> Result<(String, u64)> {
         "pg_backup_start returned an unexpected result"
     );
     let start_wal = result.rows()[0]
-        .text_inner(0)?
+        .text(0)?
         .context("pg_backup_start returned no WAL filename")?
         .to_owned();
     let wal_segment_size = result.rows()[0]
-        .text_inner(1)?
+        .text(1)?
         .context("pg_backup_start returned no WAL segment size")?
         .parse::()
         .context("pg_backup_start returned an invalid WAL segment size")?;
@@ -1700,15 +1700,15 @@ fn parse_stop_backup_result(result: &QueryResult) -> Result<(String, String, Opt
     );
     let row = &result.rows()[0];
     let stop_wal = row
-        .text_inner(0)?
+        .text(0)?
         .context("pg_backup_stop returned no WAL filename")?
         .to_owned();
     let label = row
-        .text_inner(1)?
+        .text(1)?
         .filter(|value| !value.is_empty())
         .context("pg_backup_stop returned an empty backup label")?
         .to_owned();
-    let tablespace_map = row.text_inner(2)?.map(str::to_owned);
+    let tablespace_map = row.text(2)?.map(str::to_owned);
     Ok((stop_wal, label, tablespace_map))
 }
 
@@ -1745,14 +1745,14 @@ fn combine_backup_failures(
     primary.context(format!("{cleanup_label}: {cleanup:#}"))
 }
 
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 struct DirectToolProtocolIo {
     runtime: Runtime,
     writer: TcpSocketHalfTx,
     reader: TcpSocketHalfRx,
 }
 
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 impl DirectToolProtocolIo {
     fn new(socket: DirectToolSocket) -> Result {
         let (writer, reader) = socket.split();
@@ -1767,7 +1767,7 @@ impl DirectToolProtocolIo {
     }
 }
 
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 impl Read for DirectToolProtocolIo {
     fn read(&mut self, buffer: &mut [u8]) -> io::Result {
         self.runtime.block_on(async {
@@ -1791,7 +1791,7 @@ impl Read for DirectToolProtocolIo {
     }
 }
 
-#[cfg(feature = "tools")]
+#[cfg(feature = "tools-execution")]
 impl Write for DirectToolProtocolIo {
     fn write(&mut self, bytes: &[u8]) -> io::Result {
         self.runtime.block_on(self.writer.write_all(bytes))?;
@@ -2240,7 +2240,7 @@ fn materialize_storage(storage: &PgDataStorage) -> Result {
     }
 }
 
-#[cfg(all(test, feature = "tools"))]
+#[cfg(all(test, feature = "tools-execution"))]
 mod direct_tool_protocol_tests {
     use super::*;
 
diff --git a/src/sdks/rust-wasix/src/oliphaunt/config.rs b/src/sdks/rust-wasix/src/oliphaunt/config.rs
new file mode 100644
index 000000000..ef4c67b4b
--- /dev/null
+++ b/src/sdks/rust-wasix/src/oliphaunt/config.rs
@@ -0,0 +1,274 @@
+use std::collections::BTreeMap;
+
+use anyhow::Result;
+
+use crate::error::invalid_configuration;
+
+pub(crate) const SINGLE_BACKEND_STARTUP_GUCS: &[(&str, &str)] = &[
+    ("exit_on_error", "false"),
+    ("max_wal_senders", "0"),
+    ("max_worker_processes", "0"),
+    ("max_parallel_workers", "0"),
+    ("max_parallel_workers_per_gather", "0"),
+    ("max_parallel_maintenance_workers", "0"),
+    ("io_method", "sync"),
+];
+
+/// PostgreSQL startup GUCs applied through normal `postgres -c` handling before
+/// the embedded backend starts.
+///
+/// Settings added here override `oliphaunt-wasix`'s default startup profile because
+/// they are appended after the defaults in the generated PostgreSQL argv. Settings
+/// that enforce the embedded single-backend runtime shape accept only their
+/// canonical value and are omitted from the user-specific configuration.
+#[derive(Debug, Clone, Default, PartialEq, Eq)]
+pub struct PostgresConfig {
+    settings: BTreeMap,
+}
+
+impl PostgresConfig {
+    #[cfg(test)]
+    fn new() -> Self {
+        Self::default()
+    }
+
+    #[cfg(test)]
+    fn set(mut self, name: impl Into, value: impl Into) -> Self {
+        self.insert(name, value);
+        self
+    }
+
+    pub fn insert(&mut self, name: impl Into, value: impl Into) {
+        let name = name.into();
+        self.settings
+            .insert(name.trim().to_ascii_lowercase(), value.into());
+    }
+
+    #[cfg(feature = "extensions")]
+    pub fn get(&self, name: &str) -> Option<&str> {
+        self.settings.get(name).map(String::as_str)
+    }
+
+    pub fn validate(&self) -> Result<()> {
+        for (name, value) in &self.settings {
+            validate_guc_name(name)?;
+            if matches!(name.as_str(), "config_file" | "data_directory") {
+                return Err(invalid_configuration(format!(
+                    "Oliphaunt owns PostgreSQL startup GUC '{name}'; configure the database through Oliphaunt's storage API"
+                )));
+            }
+            if let Some(required) = single_backend_guc_value(name)
+                && value != required
+            {
+                return Err(invalid_configuration(format!(
+                    "PostgreSQL startup GUC '{name}' is managed by oliphaunt-wasix and must remain '{required}'"
+                )));
+            }
+            if value.contains('\0') {
+                return Err(invalid_configuration(format!(
+                    "PostgreSQL startup GUC value for '{name}' must not contain NUL bytes"
+                )));
+            }
+        }
+        Ok(())
+    }
+
+    pub fn iter(&self) -> impl Iterator {
+        self.settings
+            .iter()
+            .filter(|(name, _)| single_backend_guc_value(name).is_none())
+            .map(|(name, value)| (name.as_str(), value.as_str()))
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct StartupConfig {
+    pub username: String,
+    pub database: String,
+}
+
+impl Default for StartupConfig {
+    fn default() -> Self {
+        Self {
+            username: "postgres".to_owned(),
+            database: "postgres".to_owned(),
+        }
+    }
+}
+
+impl StartupConfig {
+    pub fn validate(&self) -> Result<()> {
+        validate_startup_value("username", &self.username)?;
+        validate_startup_value("database", &self.database)?;
+        Ok(())
+    }
+}
+
+fn validate_guc_name(name: &str) -> Result<()> {
+    if name.is_empty() {
+        return Err(invalid_configuration(
+            "PostgreSQL startup GUC name must not be empty",
+        ));
+    }
+    if name.contains('\0') || name.contains('=') {
+        return Err(invalid_configuration(format!(
+            "PostgreSQL startup GUC name '{name}' must not contain NUL bytes or '='"
+        )));
+    }
+
+    for part in name.split('.') {
+        if part.is_empty() {
+            return Err(invalid_configuration(format!(
+                "PostgreSQL startup GUC name '{name}' contains an empty identifier part"
+            )));
+        }
+        let mut chars = part.chars();
+        let first = chars.next().expect("part is non-empty");
+        if !(first == '_' || first.is_ascii_alphabetic()) {
+            return Err(invalid_configuration(format!(
+                "PostgreSQL startup GUC name '{name}' must start each component with a letter or '_'"
+            )));
+        }
+        if chars.any(|ch| !(ch == '_' || ch == '$' || ch.is_ascii_alphanumeric())) {
+            return Err(invalid_configuration(format!(
+                "PostgreSQL startup GUC name '{name}' may only contain letters, digits, '_', '$', and '.'"
+            )));
+        }
+    }
+
+    Ok(())
+}
+
+fn single_backend_guc_value(name: &str) -> Option<&'static str> {
+    let normalized = name.trim().replace('-', "_");
+    SINGLE_BACKEND_STARTUP_GUCS
+        .iter()
+        .find_map(|(managed, value)| normalized.eq_ignore_ascii_case(managed).then_some(*value))
+}
+
+fn validate_startup_value(name: &str, value: &str) -> Result<()> {
+    if value.trim().is_empty() {
+        return Err(invalid_configuration(format!("{name} must not be empty")));
+    }
+    if value.contains('\0') {
+        return Err(invalid_configuration(format!(
+            "{name} must not contain NUL bytes"
+        )));
+    }
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{PostgresConfig, StartupConfig};
+
+    #[test]
+    fn validates_builtin_and_extension_guc_names() {
+        PostgresConfig::new()
+            .set("synchronous_commit", "off")
+            .set("pg_stat_statements.track", "all")
+            .set("_name", "")
+            .set("ext.name$1", "value")
+            .set("  trimmed_name  ", "  ")
+            .validate()
+            .unwrap();
+    }
+
+    #[test]
+    fn rejects_invalid_guc_names_before_startup() {
+        for name in [
+            "1name",
+            ".foo",
+            "a..b",
+            "a.1b",
+            "ext.$name",
+            "bad=name",
+            "bad\0name",
+        ] {
+            PostgresConfig::new()
+                .set(name, "off")
+                .validate()
+                .expect_err("invalid GUC name should be rejected");
+        }
+    }
+
+    #[test]
+    fn rejects_managed_single_backend_gucs() {
+        let err = PostgresConfig::new()
+            .set("MAX_WORKER_PROCESSES", "1")
+            .validate()
+            .expect_err("managed GUC should be rejected");
+        assert!(err.to_string().contains("must remain '0'"));
+    }
+
+    #[test]
+    fn accepts_and_canonicalizes_matching_single_backend_gucs() {
+        let config = PostgresConfig::new().set("MAX_WORKER_PROCESSES", "0");
+        config.validate().unwrap();
+        assert!(config.iter().next().is_none());
+    }
+
+    #[test]
+    fn guc_names_are_case_insensitive_and_last_insertion_wins() {
+        let config = PostgresConfig::new()
+            .set("work_mem", "1MB")
+            .set("WORK_MEM", "2MB");
+        config.validate().unwrap();
+        assert_eq!(config.iter().collect::>(), [("work_mem", "2MB")]);
+    }
+
+    #[test]
+    fn rejects_storage_redirection_gucs_case_insensitively() {
+        for name in ["CONFIG_FILE", "data_directory"] {
+            let error = PostgresConfig::new()
+                .set(name, "/tmp/other")
+                .validate()
+                .expect_err("storage is SDK-owned");
+            assert!(error.to_string().contains("Oliphaunt owns"));
+        }
+    }
+
+    #[test]
+    fn startup_values_match_native_rust_identity_validation() {
+        for (username, database, expected_name) in [
+            ("", "postgres", "username"),
+            (" \t\n", "postgres", "username"),
+            ("postgres", "", "database"),
+            ("postgres", " \t\n", "database"),
+        ] {
+            let error = StartupConfig {
+                username: username.to_owned(),
+                database: database.to_owned(),
+            }
+            .validate()
+            .expect_err("empty and whitespace-only startup identities must be rejected");
+            assert_eq!(
+                error.to_string(),
+                format!("{expected_name} must not be empty")
+            );
+        }
+
+        for (username, database, expected_name) in [
+            ("bad\0user", "postgres", "username"),
+            ("postgres", "bad\0database", "database"),
+        ] {
+            let error = StartupConfig {
+                username: username.to_owned(),
+                database: database.to_owned(),
+            }
+            .validate()
+            .expect_err("NUL cannot be encoded in a startup cstring");
+            assert_eq!(
+                error.to_string(),
+                format!("{expected_name} must not contain NUL bytes")
+            );
+        }
+
+        StartupConfig {
+            username: " application user ".to_owned(),
+            database: " application database ".to_owned(),
+        }
+        .validate()
+        .expect("nonempty PostgreSQL identities are preserved rather than trimmed");
+    }
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/data_dir.rs b/src/sdks/rust-wasix/src/oliphaunt/data_dir.rs
similarity index 98%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/data_dir.rs
rename to src/sdks/rust-wasix/src/oliphaunt/data_dir.rs
index 9a6cab123..fd5d294bd 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/data_dir.rs
+++ b/src/sdks/rust-wasix/src/oliphaunt/data_dir.rs
@@ -974,15 +974,15 @@ fn archive_entry_plan(entry: &tar::Entry<'_, R>) -> Result Result<()> {
+pub(super) fn apply_private_permissions(path: &Path, mode: u32) -> Result<()> {
     use std::os::unix::fs::PermissionsExt;
 
     fs::set_permissions(path, fs::Permissions::from_mode(mode))
-        .with_context(|| format!("set restored PGDATA permissions on {}", path.display()))
+        .with_context(|| format!("set PGDATA permissions on {}", path.display()))
 }
 
 #[cfg(not(unix))]
-fn apply_private_permissions(_path: &Path, _mode: u32) -> Result<()> {
+pub(super) fn apply_private_permissions(_path: &Path, _mode: u32) -> Result<()> {
     Ok(())
 }
 
@@ -1388,12 +1388,22 @@ fn should_skip_bulk_backup_entry(relative: &Path) -> bool {
 
 fn archive_path(relative: &Path) -> Result {
     let relative = relative
-        .to_str()
-        .with_context(|| format!("PGDATA archive path is not UTF-8: {}", relative.display()))?;
-    ensure!(
-        !relative.contains('\\'),
-        "PGDATA archive path contains a backslash: {relative:?}"
-    );
+        .components()
+        .map(|component| {
+            let Component::Normal(name) = component else {
+                bail!("unsafe PGDATA archive path: {}", relative.display());
+            };
+            let name = name.to_str().with_context(|| {
+                format!("PGDATA archive path is not UTF-8: {}", relative.display())
+            })?;
+            ensure!(
+                !name.contains('\\'),
+                "PGDATA archive path contains a backslash: {name:?}"
+            );
+            Ok(name)
+        })
+        .collect::>>()?
+        .join("/");
     let path = format!("pgdata/{relative}");
     ensure_ustar_path(&path)?;
     Ok(path)
@@ -1793,7 +1803,7 @@ mod tests {
     }
 
     #[test]
-    fn physical_archive_writer_uses_private_portable_modes() -> Result<()> {
+    fn physical_archive_writer_uses_portable_paths_and_private_modes() -> Result<()> {
         let source = tempfile::tempdir()?;
         fs::create_dir(source.path().join("base"))?;
         fs::write(source.path().join("base/value"), b"value")?;
@@ -1802,6 +1812,7 @@ mod tests {
         let mut archive = Archive::new(Cursor::new(bytes));
         for entry in archive.entries()? {
             let entry = entry?;
+            assert!(!entry.path_bytes().contains(&b'\\'));
             let path = entry.path()?.into_owned();
             let expected = if entry.header().entry_type().is_dir() {
                 0o700
@@ -2104,6 +2115,15 @@ mod tests {
         Ok(())
     }
 
+    #[test]
+    fn backup_paths_use_portable_archive_separators() -> Result<()> {
+        assert_eq!(archive_path(&Path::new("base").join("1"))?, "pgdata/base/1");
+        assert!(archive_path(Path::new("../outside")).is_err());
+        #[cfg(unix)]
+        assert!(archive_path(Path::new("base\\1")).is_err());
+        Ok(())
+    }
+
     #[test]
     fn archive_rejects_non_utf8_and_backslash_paths() -> Result<()> {
         let non_utf8 = test_archive_with_raw_path(b"pgdata/base/\xff", b"value")?;
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/database_root_descriptor.rs b/src/sdks/rust-wasix/src/oliphaunt/database_root_descriptor.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/database_root_descriptor.rs
rename to src/sdks/rust-wasix/src/oliphaunt/database_root_descriptor.rs
diff --git a/src/sdks/rust-wasix/src/oliphaunt/extensions.rs b/src/sdks/rust-wasix/src/oliphaunt/extensions.rs
new file mode 100644
index 000000000..5e2400e2c
--- /dev/null
+++ b/src/sdks/rust-wasix/src/oliphaunt/extensions.rs
@@ -0,0 +1,683 @@
+use std::collections::BTreeSet;
+
+use anyhow::Result;
+#[cfg(all(test, feature = "extension-pg-textsearch"))]
+use anyhow::bail;
+
+use crate::oliphaunt::config::PostgresConfig;
+
+const SHARED_PRELOAD_LIBRARIES: &str = "shared_preload_libraries";
+
+#[path = "generated_extensions.rs"]
+mod generated;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub(crate) struct ExtensionNativeModule {
+    runtime_path: &'static str,
+    aot_name: Option<&'static str>,
+}
+
+impl ExtensionNativeModule {
+    pub(crate) const fn runtime_path(self) -> &'static str {
+        self.runtime_path
+    }
+
+    pub(crate) const fn aot_name(self) -> Option<&'static str> {
+        self.aot_name
+    }
+}
+
+/// A bundled PostgreSQL extension artifact that Oliphaunt can make available.
+///
+/// Selecting an extension does not run `CREATE EXTENSION`, `LOAD`, or other
+/// database-local SQL. Applications retain ordinary migration ownership.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Extension {
+    sql_name: &'static str,
+    native_support_modules: &'static [ExtensionNativeModule],
+    native_module_file: Option<&'static str>,
+    aot_name: Option<&'static str>,
+    dependencies: &'static [&'static str],
+    startup_config: &'static [&'static str],
+}
+
+impl Extension {
+    /// SQL extension name used in `CREATE EXTENSION`.
+    pub const fn sql_name(self) -> &'static str {
+        self.sql_name
+    }
+
+    /// Resolve a known extension artifact by its SQL name.
+    pub fn by_sql_name(sql_name: &str) -> Option {
+        Self::ALL
+            .iter()
+            .copied()
+            .find(|extension| extension.sql_name == sql_name)
+    }
+
+    pub(crate) const fn aot_name(self) -> Option<&'static str> {
+        self.aot_name
+    }
+
+    pub(crate) const fn native_module_file(self) -> Option<&'static str> {
+        self.native_module_file
+    }
+
+    pub(crate) const fn native_support_modules(self) -> &'static [ExtensionNativeModule] {
+        self.native_support_modules
+    }
+
+    pub(crate) const fn dependencies(self) -> &'static [&'static str] {
+        self.dependencies
+    }
+
+    pub(crate) const fn startup_config(self) -> &'static [&'static str] {
+        self.startup_config
+    }
+}
+
+pub fn resolve_extension_set(extensions: &[Extension]) -> Result> {
+    let mut visiting = BTreeSet::new();
+    let mut visited = BTreeSet::new();
+    let mut resolved = Vec::new();
+    let mut requested = extensions.to_vec();
+    requested.sort_by_key(|extension| extension.sql_name());
+    for extension in requested {
+        visit_extension(extension, &mut visiting, &mut visited, &mut resolved)?;
+    }
+    Ok(resolved)
+}
+
+/// Merge startup settings required by selected extensions into the caller's
+/// PostgreSQL configuration before either a cluster seed or a backend is started.
+///
+/// `shared_preload_libraries` is a list-valued GUC, so caller-provided and
+/// extension-required entries are unioned in stable first-seen order. Other
+/// extension startup settings may reuse an identical caller value, but a
+/// conflicting value is rejected instead of silently weakening the extension
+/// contract.
+pub fn postgres_config_with_extension_startup(
+    mut postgres_config: PostgresConfig,
+    extensions: &[Extension],
+) -> Result {
+    let mut shared_preload_libraries = Vec::new();
+    let mut seen_shared_preload_libraries = BTreeSet::new();
+    if let Some(configured) = postgres_config.get(SHARED_PRELOAD_LIBRARIES) {
+        append_unique_csv_values(
+            configured,
+            &mut shared_preload_libraries,
+            &mut seen_shared_preload_libraries,
+        );
+    }
+
+    for extension in extensions {
+        for assignment in extension.startup_config() {
+            let (name, value) = parse_startup_config_assignment(*extension, assignment)?;
+
+            if name == SHARED_PRELOAD_LIBRARIES {
+                append_unique_csv_values(
+                    value,
+                    &mut shared_preload_libraries,
+                    &mut seen_shared_preload_libraries,
+                );
+                continue;
+            }
+
+            if let Some(configured) = postgres_config.get(name) {
+                if configured != value {
+                    return Err(crate::error::invalid_configuration(format!(
+                        "extension '{}' requires PostgreSQL startup config {name}={value}, but the caller configured {name}={configured}",
+                        extension.sql_name()
+                    )));
+                }
+            } else {
+                postgres_config.insert(name, value);
+            }
+        }
+    }
+
+    if !shared_preload_libraries.is_empty() {
+        postgres_config.insert(SHARED_PRELOAD_LIBRARIES, shared_preload_libraries.join(","));
+    }
+    postgres_config.validate()?;
+    Ok(postgres_config)
+}
+
+#[cfg(all(test, feature = "extension-pg-textsearch"))]
+pub(crate) fn ensure_extension_startup_config_is_active(
+    postgres_config: &PostgresConfig,
+    extension: Extension,
+) -> Result<()> {
+    for assignment in extension.startup_config() {
+        let (name, required) = parse_startup_config_assignment(extension, assignment)?;
+        let configured = postgres_config.get(name);
+        let satisfied = if name == SHARED_PRELOAD_LIBRARIES {
+            let configured_values = configured
+                .into_iter()
+                .flat_map(comma_separated_values)
+                .collect::>();
+            comma_separated_values(required).all(|value| configured_values.contains(value))
+        } else {
+            configured == Some(required)
+        };
+
+        if !satisfied {
+            let configured = configured
+                .filter(|value| !value.trim().is_empty())
+                .unwrap_or("");
+            bail!(
+                "extension '{}' requires PostgreSQL startup config {name}={required} before PostgreSQL starts, but the already-running backend has {name}={configured}; reopen the database with this extension selected on OliphauntBuilder (call .extension(...) before .open()), because it cannot be enabled safely after startup",
+                extension.sql_name()
+            );
+        }
+    }
+    Ok(())
+}
+
+fn parse_startup_config_assignment(extension: Extension, assignment: &str) -> Result<(&str, &str)> {
+    let (name, value) = assignment.split_once('=').ok_or_else(|| {
+        crate::error::invalid_configuration(format!(
+            "extension '{}' has invalid startup config assignment '{assignment}'; expected name=value",
+            extension.sql_name()
+        ))
+    })?;
+    let name = name.trim();
+    let value = value.trim();
+    if name.is_empty() {
+        return Err(crate::error::invalid_configuration(format!(
+            "extension '{}' has an empty startup config name in assignment '{assignment}'",
+            extension.sql_name()
+        )));
+    }
+    if value.is_empty() {
+        return Err(crate::error::invalid_configuration(format!(
+            "extension '{}' has an empty startup config value in assignment '{assignment}'",
+            extension.sql_name()
+        )));
+    }
+    Ok((name, value))
+}
+
+fn append_unique_csv_values(value: &str, ordered: &mut Vec, seen: &mut BTreeSet) {
+    for item in comma_separated_values(value) {
+        if seen.insert(item.to_owned()) {
+            ordered.push(item.to_owned());
+        }
+    }
+}
+
+fn comma_separated_values(value: &str) -> impl Iterator {
+    value
+        .split(',')
+        .map(str::trim)
+        .filter(|item| !item.is_empty())
+}
+
+fn visit_extension(
+    extension: Extension,
+    visiting: &mut BTreeSet<&'static str>,
+    visited: &mut BTreeSet<&'static str>,
+    resolved: &mut Vec,
+) -> Result<()> {
+    if visited.contains(extension.sql_name()) {
+        return Ok(());
+    }
+    if !visiting.insert(extension.sql_name()) {
+        return Err(crate::error::invalid_configuration(format!(
+            "cyclic bundled extension dependency involving '{}'",
+            extension.sql_name()
+        )));
+    }
+    for dependency in extension.dependencies() {
+        let dependency_extension = Extension::by_sql_name(dependency).ok_or_else(|| {
+            crate::error::invalid_configuration(format!(
+                "selected extension '{}' depends on missing catalog extension '{}'",
+                extension.sql_name(),
+                dependency
+            ))
+        })?;
+        visit_extension(dependency_extension, visiting, visited, resolved)?;
+    }
+    visiting.remove(extension.sql_name());
+    visited.insert(extension.sql_name());
+    resolved.push(extension);
+    Ok(())
+}
+
+#[cfg(test)]
+pub(crate) fn extension_smoke_sql(sql_name: &str) -> String {
+    crate::oliphaunt::test_fixtures::text(&format!("extensions/{sql_name}.sql"))
+}
+
+#[cfg(test)]
+pub(crate) fn extension_smoke_statements(sql: &str) -> impl Iterator {
+    sql.split("-- oliphaunt-statement")
+        .map(str::trim)
+        .filter(|statement| !statement.is_empty())
+}
+
+#[cfg(test)]
+fn extension_activation_sql_for_test(extension: Extension) -> Result> {
+    Ok(resolve_extension_set(&[extension])?
+        .into_iter()
+        .flat_map(|resolved| generated::activation_sql_for_test(resolved).iter().copied())
+        .collect())
+}
+
+#[cfg(all(test, feature = "extension-pg-textsearch"))]
+mod startup_config_tests {
+    use super::*;
+
+    #[test]
+    fn late_pg_textsearch_enable_requires_active_preload() {
+        let error = ensure_extension_startup_config_is_active(
+            &PostgresConfig::default(),
+            Extension::PG_TEXTSEARCH,
+        )
+        .unwrap_err();
+        let message = error.to_string();
+
+        assert!(message.contains("shared_preload_libraries=pg_textsearch"));
+        assert!(message.contains("already-running backend"));
+        assert!(message.contains(".extension(...) before .open()"));
+
+        let mut active = PostgresConfig::default();
+        active.insert(
+            "shared_preload_libraries",
+            "auto_explain, pg_textsearch,pg_textsearch",
+        );
+        ensure_extension_startup_config_is_active(&active, Extension::PG_TEXTSEARCH).unwrap();
+    }
+}
+
+#[cfg(all(test, feature = "extensions"))]
+mod extension_tests {
+    use super::*;
+    use crate::DatabaseStorage;
+    use crate::Oliphaunt;
+    use anyhow::{Context, Result, ensure};
+    use std::collections::BTreeSet;
+    use std::path::{Path, PathBuf};
+
+    #[test]
+    fn public_extensions_pass_direct_and_restart_smoke() -> Result<()> {
+        run_direct_and_restart_smoke_set(Extension::ALL)
+    }
+
+    #[test]
+    fn public_extensions_materialize_only_requested_libraries() -> Result<()> {
+        run_lifecycle_materialization_set(Extension::ALL)
+    }
+
+    #[test]
+    #[cfg(all(feature = "extension-cube", feature = "extension-earthdistance"))]
+    fn dependent_extension_activation_includes_dependencies_first() -> Result<()> {
+        let activation = extension_activation_sql_for_test(Extension::EARTHDISTANCE)?;
+        assert_eq!(activation.len(), 2);
+        assert!(activation[0].contains("\"cube\""));
+        assert!(activation[1].contains("\"earthdistance\""));
+        Ok(())
+    }
+
+    #[test]
+    #[cfg(feature = "extension-uuid-ossp")]
+    fn uuid_ossp_aot_direct_and_restart_smoke() -> Result<()> {
+        run_direct_and_restart_smoke_set(&[Extension::UUID_OSSP])
+    }
+
+    #[test]
+    #[cfg(feature = "extension-uuid-ossp")]
+    fn uuid_ossp_aot_materialization_smoke() -> Result<()> {
+        run_lifecycle_materialization_set(&[Extension::UUID_OSSP])
+    }
+
+    #[cfg(all(feature = "tools-execution", feature = "extension-uuid-ossp"))]
+    #[test]
+    fn uuid_ossp_aot_dump_restore_smoke() -> Result<()> {
+        use crate::tools::{PgDumpOptions, PsqlOptions};
+
+        let mut source = Oliphaunt::builder()
+            .extension(Extension::UUID_OSSP)
+            .open()
+            .context("open UUID-OSSP AOT dump source")?;
+        source
+            .psql(PsqlOptions::new().script(
+                "CREATE EXTENSION \"uuid-ossp\";\
+                 CREATE TABLE uuid_ossp_aot_items(\
+                   id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),\
+                   label text NOT NULL\
+                 );\
+                INSERT INTO uuid_ossp_aot_items(label) VALUES ('first'), ('second');",
+            ))
+            .context("seed UUID-OSSP AOT dump source through psql")?;
+        let dump = source
+            .pg_dump(PgDumpOptions::new())
+            .context("dump UUID-OSSP AOT source through pg_dump")?;
+        ensure!(
+            dump.contains("COPY public.uuid_ossp_aot_items"),
+            "UUID-OSSP AOT dump should retain PostgreSQL COPY output"
+        );
+        source.close().context("close UUID-OSSP AOT dump source")?;
+
+        let mut restored = Oliphaunt::builder()
+            .extension(Extension::UUID_OSSP)
+            .open()
+            .context("open UUID-OSSP AOT restore target")?;
+        restored
+            .psql(PsqlOptions::new().script(dump))
+            .context("restore UUID-OSSP AOT dump through psql")?;
+        let result = restored.query(
+            "SELECT count(*)::int4 AS rows,\
+                    count(DISTINCT id)::int4 AS ids,\
+                    bool_and(length(id::text) = 36) AS valid_ids,\
+                    length(uuid_generate_v4()::text)::int4 AS generated_length \
+             FROM uuid_ossp_aot_items",
+        )?;
+        ensure!(result.get_text(0, "rows")? == Some("2"));
+        ensure!(result.get_text(0, "ids")? == Some("2"));
+        ensure!(result.get_text(0, "valid_ids")? == Some("t"));
+        ensure!(result.get_text(0, "generated_length")? == Some("36"));
+        restored
+            .close()
+            .context("close UUID-OSSP AOT restore target")?;
+        Ok(())
+    }
+
+    fn embedded_extension_archives(extensions: &[Extension]) -> Result> {
+        let embedded: Vec<_> = extensions
+            .iter()
+            .copied()
+            .filter(|extension| {
+                crate::oliphaunt::assets::extension_archive(extension.sql_name()).is_some()
+            })
+            .collect();
+        let embedded_names: BTreeSet<_> = embedded
+            .iter()
+            .map(|extension| extension.sql_name())
+            .collect();
+        let missing: Vec<_> = extensions
+            .iter()
+            .map(|extension| extension.sql_name())
+            .filter(|name| !embedded_names.contains(name))
+            .collect();
+        ensure!(
+            missing.is_empty(),
+            "required WASIX extension archives are not embedded: {}",
+            missing.join(", ")
+        );
+        Ok(embedded)
+    }
+
+    fn run_direct_and_restart_smoke_set(extensions: &[Extension]) -> Result<()> {
+        let extensions = embedded_extension_archives(extensions)?;
+        let mut failures = Vec::new();
+        for extension in extensions {
+            if let Err(error) = run_one_direct_and_restart_smoke(extension) {
+                failures.push(format!("{}: {error:?}", extension.sql_name()));
+            }
+        }
+        ensure!(
+            failures.is_empty(),
+            "extension direct/restart smoke failures:\n{}",
+            failures.join("\n\n")
+        );
+        Ok(())
+    }
+
+    fn run_one_direct_and_restart_smoke(extension: Extension) -> Result<()> {
+        let name = extension.sql_name();
+        {
+            let mut db = Oliphaunt::builder()
+                .extension(extension)
+                .open()
+                .with_context(|| format!("open temporary database with extension {name}"))?;
+            assert_extension_not_installed(&mut db, extension)?;
+            run_direct_smoke(&mut db, extension)?;
+            db.close()
+                .with_context(|| format!("close temporary database with extension {name}"))?;
+            record_mode(extension, "direct")?;
+        }
+
+        let root = tempfile::TempDir::new()
+            .with_context(|| format!("create restart root for extension {name}"))?;
+        {
+            let mut db = Oliphaunt::builder()
+                .storage(DatabaseStorage::Directory(root.path().to_path_buf()))
+                .extension(extension)
+                .open()
+                .with_context(|| {
+                    format!("open persistent database with extension {name} before restart")
+                })?;
+            assert_extension_not_installed(&mut db, extension)?;
+            run_direct_smoke(&mut db, extension)?;
+            assert_extension_catalog_state(&mut db, extension)?;
+            db.close()
+                .with_context(|| format!("close persistent database with extension {name}"))?;
+        }
+        {
+            let mut db = Oliphaunt::builder()
+                .storage(DatabaseStorage::Directory(root.path().to_path_buf()))
+                .extension(extension)
+                .open()
+                .with_context(|| {
+                    format!("reopen persistent database with extension {name} after restart")
+                })?;
+            assert_extension_catalog_state(&mut db, extension)?;
+            verify_persisted_fixture(&mut db, extension)?;
+            verify_backup_restore(&mut db, extension)?;
+            db.close()
+                .with_context(|| format!("close restarted database with extension {name}"))?;
+            record_mode(extension, "restart")?;
+        }
+        Ok(())
+    }
+
+    fn run_lifecycle_materialization_set(extensions: &[Extension]) -> Result<()> {
+        let extensions = embedded_extension_archives(extensions)?;
+        let mut failures = Vec::new();
+        for extension in extensions {
+            if let Err(error) = run_one_lifecycle_materialization(extension) {
+                failures.push(format!("{}: {error:?}", extension.sql_name()));
+            }
+        }
+        ensure!(
+            failures.is_empty(),
+            "extension lifecycle/materialization failures:\n{}",
+            failures.join("\n\n")
+        );
+        Ok(())
+    }
+
+    fn run_one_lifecycle_materialization(extension: Extension) -> Result<()> {
+        let name = extension.sql_name();
+        let root = tempfile::TempDir::new()
+            .with_context(|| format!("create lifecycle root for extension {name}"))?;
+        {
+            let mut db = Oliphaunt::builder()
+                .storage(DatabaseStorage::Directory(root.path().to_path_buf()))
+                .extension(extension)
+                .open()
+                .with_context(|| format!("open lifecycle database with extension {name}"))?;
+            let runtime_root = db
+                .runtime_storage()
+                .host_path()
+                .context("directory database should use a host runtime workspace")?;
+            assert_only_resolved_extension_libraries_are_materialized(runtime_root, extension)?;
+            db.close()
+                .with_context(|| format!("close lifecycle database with extension {name}"))?;
+            record_mode(extension, "materialization")?;
+        }
+        Ok(())
+    }
+
+    fn run_direct_smoke(db: &mut Oliphaunt, extension: Extension) -> Result<()> {
+        ensure!(
+            db.exec("SELECT 1 / 0").is_err(),
+            "SQL errors must fail direct smoke"
+        );
+        for statement in extension_activation_sql_for_test(extension)? {
+            db.exec(statement).with_context(|| {
+                format!(
+                    "explicit activation failed for extension {} while running:\n{}",
+                    extension.sql_name(),
+                    statement
+                )
+            })?;
+        }
+        let smoke_sql = extension_smoke_sql(extension.sql_name());
+        for statement in extension_smoke_statements(&smoke_sql) {
+            db.exec(statement).with_context(|| {
+                format!(
+                    "direct smoke failed for extension {} while running:\n{}",
+                    extension.sql_name(),
+                    statement
+                )
+            })?;
+        }
+        Ok(())
+    }
+
+    fn record_mode(extension: Extension, mode: &str) -> Result<()> {
+        if let Some(root) = std::env::var_os("OLIPHAUNT_EXTENSION_EVIDENCE_DIR") {
+            std::fs::write(
+                Path::new(&root).join(format!("{}.{mode}", extension.sql_name())),
+                "passed\n",
+            )?;
+        }
+        Ok(())
+    }
+
+    fn verify_persisted_fixture(db: &mut Oliphaunt, extension: Extension) -> Result<()> {
+        let recipe = extension_smoke_sql(extension.sql_name());
+        if let Some((_, verification)) = recipe.split_once("-- oliphaunt-verify") {
+            for statement in extension_smoke_statements(verification) {
+                db.exec(statement).with_context(|| {
+                    format!("verify persisted state for {}", extension.sql_name())
+                })?;
+            }
+        }
+        Ok(())
+    }
+
+    fn verify_backup_restore(source: &mut Oliphaunt, extension: Extension) -> Result<()> {
+        source.exec("CREATE TABLE oliphaunt_restore_probe(value text); INSERT INTO oliphaunt_restore_probe VALUES ('retained')")?;
+        let backup = source.backup()?;
+        let root = tempfile::TempDir::new()?;
+        let destination = root.path().join("restored");
+        Oliphaunt::restore(&destination, backup)?;
+        let mut restored = Oliphaunt::builder()
+            .storage(DatabaseStorage::Directory(destination))
+            .extension(extension)
+            .open()?;
+        assert_extension_catalog_state(&mut restored, extension)?;
+        verify_persisted_fixture(&mut restored, extension)?;
+        ensure!(
+            restored
+                .query("SELECT value FROM oliphaunt_restore_probe")?
+                .get_text(0, "value")?
+                == Some("retained")
+        );
+        restored.close()?;
+        record_mode(extension, "backup-restore")
+    }
+
+    fn assert_extension_not_installed(db: &mut Oliphaunt, extension: Extension) -> Result<()> {
+        if !generated::creates_database_object_for_test(extension) {
+            return Ok(());
+        }
+        let result = db.query_with_params(
+            "SELECT count(*)::int4 AS count FROM pg_extension WHERE extname = $1",
+            [extension.sql_name()],
+        )?;
+        ensure!(
+            result.get_text(0, "count")? == Some("0"),
+            "selecting extension {} must not install it in pg_extension",
+            extension.sql_name()
+        );
+        Ok(())
+    }
+
+    fn assert_extension_catalog_state(db: &mut Oliphaunt, extension: Extension) -> Result<()> {
+        if generated::creates_database_object_for_test(extension) {
+            let result = db.query_with_params(
+                "SELECT count(*)::int4 AS count FROM pg_extension WHERE extname = $1",
+                [extension.sql_name()],
+            )?;
+            ensure!(
+                result.get_text(0, "count")? == Some("1"),
+                "extension {} should survive restart in pg_extension",
+                extension.sql_name()
+            );
+        } else {
+            let result = db.query("SELECT 1::int4 AS ok")?;
+            ensure!(
+                result.get_text(0, "ok")? == Some("1"),
+                "extension {} should reopen cleanly",
+                extension.sql_name()
+            );
+        }
+        Ok(())
+    }
+
+    fn assert_only_resolved_extension_libraries_are_materialized(
+        runtime_root: &Path,
+        extension: Extension,
+    ) -> Result<()> {
+        let expected = resolve_extension_set(&[extension])?
+            .into_iter()
+            .flat_map(|extension| {
+                let mut modules = extension
+                    .native_support_modules()
+                    .iter()
+                    .map(|module| {
+                        PathBuf::from(module.runtime_path())
+                            .strip_prefix("lib/postgresql")
+                            .map(PathBuf::from)
+                            .unwrap_or_else(|_| PathBuf::from(module.runtime_path()))
+                    })
+                    .collect::>();
+                if let Some(module) = extension.native_module_file() {
+                    modules.push(PathBuf::from(module));
+                }
+                modules
+            })
+            .collect::>();
+        let actual = relative_files(&runtime_root.join("lib/postgresql"))
+            .into_iter()
+            .collect::>();
+        ensure!(
+            actual == expected,
+            "upper runtime library layer for {} should contain only resolved requested libraries; expected {:?}, got {:?}",
+            extension.sql_name(),
+            expected,
+            actual
+        );
+        Ok(())
+    }
+
+    fn relative_files(root: &Path) -> Vec {
+        fn walk(base: &Path, current: &Path, files: &mut Vec) {
+            let Ok(entries) = std::fs::read_dir(current) else {
+                return;
+            };
+            for entry in entries {
+                let entry = entry.expect("read runtime test directory entry");
+                let path = entry.path();
+                if path.is_dir() {
+                    walk(base, &path, files);
+                } else if path.is_file() {
+                    files.push(
+                        path.strip_prefix(base)
+                            .expect("relative extension library path")
+                            .to_path_buf(),
+                    );
+                }
+            }
+        }
+
+        let mut files = Vec::new();
+        walk(root, root, &mut files);
+        files.sort();
+        files
+    }
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/generated_extensions.rs b/src/sdks/rust-wasix/src/oliphaunt/generated_extensions.rs
similarity index 99%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/generated_extensions.rs
rename to src/sdks/rust-wasix/src/oliphaunt/generated_extensions.rs
index 2b8089676..4d63fd783 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/generated_extensions.rs
+++ b/src/sdks/rust-wasix/src/oliphaunt/generated_extensions.rs
@@ -1,4 +1,4 @@
-// @generated by `cargo run -p xtask -- extensions generate`
+// @generated by src/extensions/tools/check-extension-model.sh --write
 
 use super::Extension;
 
diff --git a/src/sdks/rust-wasix/src/oliphaunt/lifecycle.rs b/src/sdks/rust-wasix/src/oliphaunt/lifecycle.rs
new file mode 100644
index 000000000..ccebc95df
--- /dev/null
+++ b/src/sdks/rust-wasix/src/oliphaunt/lifecycle.rs
@@ -0,0 +1,167 @@
+use std::mem::ManuallyDrop;
+use std::ops::{Deref, DerefMut};
+use std::panic::{AssertUnwindSafe, catch_unwind};
+
+use anyhow::Result;
+
+use crate::Error;
+
+pub(crate) type TerminalCloseResult = crate::Result<()>;
+
+/// Ownership which may only be released after teardown is known to have
+/// succeeded.
+///
+/// Dropping this wrapper deliberately does not run `T`'s destructor. This is
+/// the conservative terminal-failure path: once destructive PostgreSQL
+/// teardown has started and returned an error, running ordinary Rust
+/// destructors could release a managed-root lock or partially destroy a WASIX
+/// backend whose state is no longer known. [`Self::release`] is therefore the
+/// only way to destroy the value, and callers invoke it only after successful
+/// teardown.
+#[derive(Debug)]
+pub(crate) struct TeardownOwnership {
+    value: Option>,
+}
+
+impl TeardownOwnership {
+    pub(crate) fn new(value: T) -> Self {
+        Self {
+            value: Some(ManuallyDrop::new(value)),
+        }
+    }
+
+    /// Release this ownership exactly once after successful teardown.
+    pub(crate) fn release(&mut self) {
+        if let Some(value) = self.value.take() {
+            // `take` gives this call the sole remaining path to the value.
+            // Leaving `None` makes repeated release safe.
+            drop(ManuallyDrop::into_inner(value));
+        }
+    }
+}
+
+impl Deref for TeardownOwnership {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        self.value
+            .as_deref()
+            .expect("teardown ownership was already released")
+    }
+}
+
+impl DerefMut for TeardownOwnership {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.value
+            .as_deref_mut()
+            .expect("teardown ownership was already released")
+    }
+}
+
+/// Run a destructive close boundary once and retain its exact public outcome.
+pub(crate) fn terminal_close(
+    outcome: &mut Option,
+    owner: &'static str,
+    close: impl FnOnce() -> Result<()>,
+) -> TerminalCloseResult {
+    if let Some(outcome) = outcome {
+        return outcome.clone();
+    }
+    let result = teardown_result(owner, close);
+    *outcome = Some(result.clone());
+    result
+}
+
+/// Contain teardown panics at the ownership boundary. A panic means teardown
+/// began without proving completion, so callers quarantine ownership just as
+/// they do for an ordinary returned error.
+pub(crate) fn teardown_result(
+    owner: &'static str,
+    close: impl FnOnce() -> Result<()>,
+) -> TerminalCloseResult {
+    match catch_unwind(AssertUnwindSafe(close)) {
+        Ok(result) => result.map_err(Error::from_anyhow),
+        Err(panic) => Err(Error::message(format!(
+            "{owner} panicked during teardown: {}",
+            panic_message(panic.as_ref())
+        ))),
+    }
+}
+
+fn panic_message(panic: &(dyn std::any::Any + Send)) -> &str {
+    panic
+        .downcast_ref::()
+        .map(String::as_str)
+        .or_else(|| panic.downcast_ref::<&'static str>().copied())
+        .unwrap_or("unknown panic payload")
+}
+
+#[cfg(test)]
+mod tests {
+    use std::cell::Cell;
+    use std::rc::Rc;
+
+    use super::*;
+
+    #[test]
+    fn terminal_failure_is_executed_once_and_replayed_exactly() {
+        let calls = Cell::new(0);
+        let mut outcome = None;
+
+        for _ in 0..2 {
+            let result = terminal_close(&mut outcome, "test owner", || {
+                calls.set(calls.get() + 1);
+                anyhow::bail!("injected teardown failure")
+            });
+            assert_eq!(
+                result.expect_err("teardown fails").to_string(),
+                "injected teardown failure"
+            );
+        }
+        assert_eq!(calls.get(), 1);
+    }
+
+    #[test]
+    fn terminal_panic_is_contained_and_replayed_without_retry() {
+        let calls = Cell::new(0);
+        let mut outcome = None;
+
+        for _ in 0..2 {
+            let error = terminal_close(&mut outcome, "test owner", || {
+                calls.set(calls.get() + 1);
+                panic!("injected teardown panic")
+            })
+            .expect_err("teardown panic becomes a terminal error");
+            assert_eq!(
+                error.to_string(),
+                "test owner panicked during teardown: injected teardown panic"
+            );
+        }
+        assert_eq!(calls.get(), 1);
+    }
+
+    #[test]
+    fn teardown_ownership_releases_only_on_explicit_success_path() {
+        struct DropProbe(Rc>);
+
+        impl Drop for DropProbe {
+            fn drop(&mut self) {
+                self.0.set(self.0.get() + 1);
+            }
+        }
+
+        let successful_drops = Rc::new(Cell::new(0));
+        {
+            let mut successful = TeardownOwnership::new(DropProbe(Rc::clone(&successful_drops)));
+            successful.release();
+            successful.release();
+        }
+        assert_eq!(successful_drops.get(), 1);
+
+        let quarantined_drops = Rc::new(Cell::new(0));
+        {
+            let _quarantined = TeardownOwnership::new(DropProbe(Rc::clone(&quarantined_drops)));
+        }
+        assert_eq!(quarantined_drops.get(), 0);
+    }
+}
diff --git a/src/sdks/rust-wasix/src/oliphaunt/mod.rs b/src/sdks/rust-wasix/src/oliphaunt/mod.rs
new file mode 100644
index 000000000..bd1f00330
--- /dev/null
+++ b/src/sdks/rust-wasix/src/oliphaunt/mod.rs
@@ -0,0 +1,33 @@
+pub(crate) mod aot;
+pub(crate) mod assets;
+pub(crate) mod backend;
+pub(crate) mod base;
+pub(crate) mod builder;
+pub(crate) mod client;
+pub(crate) mod config;
+pub(crate) mod data_dir;
+pub(crate) mod database_root_descriptor;
+#[cfg(feature = "extensions")]
+pub(crate) mod extensions;
+pub(crate) mod lifecycle;
+pub(crate) mod postgres_mod;
+pub(crate) mod query;
+pub(crate) use oliphaunt_query as query_core;
+pub(crate) mod sql;
+pub(crate) mod storage;
+pub(crate) mod sync_host_fs;
+#[cfg(test)]
+pub(crate) mod test_fixtures;
+#[cfg(feature = "tools-execution")]
+pub mod tools;
+pub(crate) mod transport;
+
+pub use assets::{CatalogProfile, ClusterSeed, IcuData};
+pub use builder::OliphauntBuilder;
+pub use client::{Oliphaunt, Sql, Transaction};
+pub use query::{
+    CommandResult, DecodeError, ExecResult, FromSql, IntoParameter, Parameter, PostgresError,
+    PostgresErrorField, PostgresNotice, QueryField, QueryFormat, QueryResult, QueryRow, RowIndex,
+    StatementDescription, StatementResult, TypeOid, ValueFormat, ValueRef,
+};
+pub use storage::DatabaseStorage;
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod.rs b/src/sdks/rust-wasix/src/oliphaunt/postgres_mod.rs
similarity index 99%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod.rs
rename to src/sdks/rust-wasix/src/oliphaunt/postgres_mod.rs
index 10b039d5e..dfe5d4a64 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod.rs
+++ b/src/sdks/rust-wasix/src/oliphaunt/postgres_mod.rs
@@ -36,7 +36,7 @@ mod stdio;
 mod task_policy;
 mod wasix_fs;
 
-pub(crate) use stdio::ProtocolStream;
+pub use stdio::ProtocolStream;
 use stdio::{ProtocolStdioAttachment, ProtocolStdioFile, TailCaptureFile, TailCaptureHandle};
 use task_policy::{GuestWasmTasks, constrain_single_backend_tasks};
 use wasix_fs::{host_filesystem, wasi_root_with_devices};
@@ -91,9 +91,9 @@ pub struct PostgresMod {
     started: bool,
 }
 
-pub(crate) struct StartupProtocolResponse {
-    pub(crate) output: Vec,
-    pub(crate) accepted: bool,
+pub struct StartupProtocolResponse {
+    pub output: Vec,
+    pub accepted: bool,
 }
 
 #[derive(Debug)]
@@ -125,13 +125,13 @@ impl fmt::Display for StartupErrorResponse {
 
 impl std::error::Error for StartupErrorResponse {}
 
-pub(crate) fn startup_error_response_output(err: &anyhow::Error) -> Option<&[u8]> {
+pub fn startup_error_response_output(err: &anyhow::Error) -> Option<&[u8]> {
     err.downcast_ref::()
         .map(StartupErrorResponse::output)
 }
 
 #[derive(Debug)]
-pub(crate) enum ProtocolPumpOutcome {
+pub enum ProtocolPumpOutcome {
     Buffered(Vec),
     Streamed,
 }
@@ -755,12 +755,12 @@ impl PostgresMod {
         })
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn existing_startup_response(&self) -> Option> {
         self.startup_response.clone()
     }
 
-    #[cfg(feature = "tools")]
+    #[cfg(feature = "tools-execution")]
     pub(crate) fn startup_config(&self) -> &StartupConfig {
         &self.startup_config
     }
@@ -1008,7 +1008,7 @@ fn run_split_initdb(runtime_layout: &RuntimeLayout, pgdata_storage: &PgDataStora
     let postgres_module = runtime_layout.module_root.join("bin/postgres");
     ensure!(
         initdb_module.exists(),
-        "split WASIX initdb module is not installed at {}; regenerate assets with `xtask assets cluster-seeds`",
+        "split WASIX initdb module is not installed at {}; rebuild or reinstall the WASIX runtime package",
         initdb_module.display()
     );
     ensure!(
@@ -2017,7 +2017,7 @@ mod tests {
 
     #[test]
     fn startup_error_summary_includes_postgres_fields() {
-        let response = crate::oliphaunt::wire::error_response(
+        let response = oliphaunt_query::wire::error_response(
             "PANIC",
             "42501",
             "could not flush dirty data: Permission denied",
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod/stdio.rs b/src/sdks/rust-wasix/src/oliphaunt/postgres_mod/stdio.rs
similarity index 99%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod/stdio.rs
rename to src/sdks/rust-wasix/src/oliphaunt/postgres_mod/stdio.rs
index 8e22f9fc9..34878ce1f 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod/stdio.rs
+++ b/src/sdks/rust-wasix/src/oliphaunt/postgres_mod/stdio.rs
@@ -9,7 +9,7 @@ use anyhow::{Result, ensure};
 use tokio::io::ReadBuf;
 use wasmer_wasix::virtual_fs;
 
-pub(crate) trait ProtocolStream: Read + Write + Send {
+pub trait ProtocolStream: Read + Write + Send {
     fn read_ready(&mut self) -> io::Result;
 }
 
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod/task_policy.rs b/src/sdks/rust-wasix/src/oliphaunt/postgres_mod/task_policy.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod/task_policy.rs
rename to src/sdks/rust-wasix/src/oliphaunt/postgres_mod/task_policy.rs
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod/wasix_fs.rs b/src/sdks/rust-wasix/src/oliphaunt/postgres_mod/wasix_fs.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod/wasix_fs.rs
rename to src/sdks/rust-wasix/src/oliphaunt/postgres_mod/wasix_fs.rs
diff --git a/src/sdks/rust-wasix/src/oliphaunt/query.rs b/src/sdks/rust-wasix/src/oliphaunt/query.rs
new file mode 100644
index 000000000..53814c7f0
--- /dev/null
+++ b/src/sdks/rust-wasix/src/oliphaunt/query.rs
@@ -0,0 +1,144 @@
+use anyhow::{Result, anyhow};
+
+use crate::oliphaunt::query_core;
+
+pub(crate) use crate::oliphaunt::query_core::ReadyStatus;
+pub use crate::oliphaunt::query_core::{
+    CommandResult, DecodeError, ExecResult, FromSql, IntoParameter, Parameter, PostgresError,
+    PostgresErrorField, PostgresNotice, QueryField, QueryFormat, QueryResult, QueryRow, RowIndex,
+    StatementDescription, StatementResult, TypeOid, ValueFormat, ValueRef,
+};
+
+pub(crate) fn simple_query(sql: &str) -> Result> {
+    query_core_result(query_core::simple_query(sql))
+}
+
+fn query_core_result(result: query_core::Result) -> Result {
+    result.map_err(query_core_error)
+}
+
+pub(crate) fn query_core_error(error: query_core::Error) -> anyhow::Error {
+    match error {
+        query_core::Error::Protocol(message) => anyhow!(message),
+        query_core::Error::Postgres {
+            diagnostic,
+            notices,
+        } => {
+            let mut error = PostgresError::from_core(*diagnostic);
+            error.notices = notices.into_iter().map(PostgresNotice::from_core).collect();
+            anyhow::Error::new(error)
+        }
+    }
+}
+
+#[cfg(test)]
+pub(crate) fn parse_command_response(bytes: &[u8]) -> Result {
+    query_core_result(query_core::parse_command_response(
+        bytes,
+        query_core::ExpectedProtocol::Either,
+    ))
+}
+
+pub(crate) fn parse_extended_command_response(bytes: &[u8]) -> Result {
+    query_core_result(query_core::parse_command_response(
+        bytes,
+        query_core::ExpectedProtocol::Extended,
+    ))
+}
+
+pub(crate) fn parse_simple_command_response(bytes: &[u8]) -> Result {
+    query_core_result(query_core::parse_command_response(
+        bytes,
+        query_core::ExpectedProtocol::Simple,
+    ))
+}
+
+pub(crate) fn parse_extended_query_response(bytes: &[u8]) -> Result {
+    query_core_result(query_core::parse_query_response(
+        bytes,
+        query_core::ExpectedProtocol::Extended,
+    ))
+}
+
+pub(crate) fn parse_exec_response(bytes: &[u8]) -> Result {
+    query_core_result(query_core::parse_exec_response(bytes))
+}
+
+pub(crate) fn parse_statement_description(bytes: &[u8]) -> Result {
+    query_core_result(query_core::parse_statement_description(bytes))
+}
+
+pub(crate) fn extended_statement(
+    sql: &str,
+    params: &[Parameter],
+    result_format: ValueFormat,
+) -> Result> {
+    query_core_result(query_core::extended_statement(
+        sql,
+        params,
+        result_format.code(),
+    ))
+}
+
+pub(crate) fn describe_statement(sql: &str, params: &[Parameter]) -> Result> {
+    query_core_result(query_core::describe_statement(sql, params))
+}
+
+pub(crate) fn reject_copy_statements(sql: &str) -> Result<()> {
+    query_core_result(query_core::reject_copy_statements(sql))
+}
+
+pub(crate) fn reject_transaction_chain(sql: &str) -> Result<()> {
+    query_core_result(query_core::reject_transaction_chain(sql))
+}
+
+pub(crate) fn validate_managed_transaction_response(response: &[u8]) -> Result {
+    query_core_result(query_core::validate_managed_transaction_response(response))
+}
+
+pub(crate) fn response_ready_status(bytes: &[u8]) -> Result {
+    query_core_result(query_core::response_ready_status(bytes))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[test]
+    fn simple_query_rejects_embedded_nul() {
+        assert_eq!(
+            simple_query("SELECT\0 1")
+                .expect_err("embedded NUL must be rejected")
+                .to_string(),
+            "simple query SQL must not contain NUL bytes"
+        );
+    }
+
+    #[test]
+    fn error_parser_drains_ready_and_attaches_notices() {
+        let mut response = backend_message(b'N', b"SNOTICE\0Mbefore failure\0\0");
+        response.extend(backend_message(b'E', b"SERROR\0C23505\0Mduplicate\0\0"));
+        response.extend(backend_message(b'Z', b"I"));
+        let error = parse_command_response(&response).unwrap_err();
+        let postgres = error
+            .downcast_ref::()
+            .expect("PostgreSQL error");
+        assert_eq!(postgres.sqlstate.as_deref(), Some("23505"));
+        assert_eq!(postgres.notices[0].message, "before failure");
+
+        let missing_ready = backend_message(b'E', b"SERROR\0C42601\0Msyntax\0\0");
+        assert!(
+            parse_command_response(&missing_ready)
+                .unwrap_err()
+                .to_string()
+                .contains("before ReadyForQuery")
+        );
+    }
+
+    fn backend_message(tag: u8, body: &[u8]) -> Vec {
+        let mut message = Vec::new();
+        message.push(tag);
+        message.extend_from_slice(&((body.len() + 4) as i32).to_be_bytes());
+        message.extend_from_slice(body);
+        message
+    }
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/query/query_fixture_tests.rs b/src/sdks/rust-wasix/src/oliphaunt/query/query_fixture_tests.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/query/query_fixture_tests.rs
rename to src/sdks/rust-wasix/src/oliphaunt/query/query_fixture_tests.rs
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/sql.rs b/src/sdks/rust-wasix/src/oliphaunt/sql.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/sql.rs
rename to src/sdks/rust-wasix/src/oliphaunt/sql.rs
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/storage.rs b/src/sdks/rust-wasix/src/oliphaunt/storage.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/storage.rs
rename to src/sdks/rust-wasix/src/oliphaunt/storage.rs
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/sync_host_fs.rs b/src/sdks/rust-wasix/src/oliphaunt/sync_host_fs.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/sync_host_fs.rs
rename to src/sdks/rust-wasix/src/oliphaunt/sync_host_fs.rs
diff --git a/src/sdks/rust-wasix/src/oliphaunt/test_fixtures.rs b/src/sdks/rust-wasix/src/oliphaunt/test_fixtures.rs
new file mode 100644
index 000000000..deb0a780e
--- /dev/null
+++ b/src/sdks/rust-wasix/src/oliphaunt/test_fixtures.rs
@@ -0,0 +1,22 @@
+use std::fs;
+use std::path::Path;
+
+pub(crate) fn text(relative: &str) -> String {
+    let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
+    let shared = manifest_dir.join("../../test-fixtures").join(relative);
+    let packaged = manifest_dir.join("src/testdata").join(relative);
+    fs::read_to_string(&shared)
+        .or_else(|shared_error| {
+            fs::read_to_string(&packaged).map_err(|packaged_error| {
+                std::io::Error::new(
+                    packaged_error.kind(),
+                    format!(
+                        "read shared fixture {} ({shared_error}) or packaged fixture {} ({packaged_error})",
+                        shared.display(),
+                        packaged.display()
+                    ),
+                )
+            })
+        })
+        .unwrap_or_else(|error| panic!("{error}"))
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/tools.rs b/src/sdks/rust-wasix/src/oliphaunt/tools.rs
similarity index 95%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/tools.rs
rename to src/sdks/rust-wasix/src/oliphaunt/tools.rs
index aa39c6d80..f30c7895c 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/tools.rs
+++ b/src/sdks/rust-wasix/src/oliphaunt/tools.rs
@@ -66,6 +66,39 @@ const PSQL_VALUE_OPTIONS: &[&str] = &[
 #[derive(Debug, Clone, Default, PartialEq, Eq)]
 pub struct PgDumpOptions {
     args: Vec,
+    assets: Option>,
+}
+
+/// Explicit utility assets from the selected PostgreSQL tools package.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ToolAssets {
+    wasm: Vec,
+    aot: Vec,
+    manifest: String,
+}
+
+impl ToolAssets {
+    /// Supply a trusted compiler-produced utility and its target manifest.
+    ///
+    /// # Safety
+    /// AOT bytes contain native machine code and must come from a trusted package.
+    /// Manifest and checksum validation detects mismatches, not malicious code.
+    #[allow(unsafe_code)]
+    pub unsafe fn new(wasm: Vec, aot: Vec, manifest: String) -> Self {
+        Self {
+            wasm,
+            aot,
+            manifest,
+        }
+    }
+}
+
+impl PgDumpOptions {
+    /// Use separately installed utility assets instead of bundled Cargo assets.
+    pub fn assets(mut self, assets: ToolAssets) -> Self {
+        self.assets = Some(Arc::new(assets));
+        self
+    }
 }
 
 /// Structured failure from a packaged PostgreSQL frontend program.
@@ -205,6 +238,7 @@ impl PgDumpOptions {
 pub struct PsqlOptions {
     args: Vec,
     input: Option,
+    assets: Option>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -214,6 +248,12 @@ enum PsqlInput {
 }
 
 impl PsqlOptions {
+    /// Use separately installed utility assets instead of bundled Cargo assets.
+    pub fn assets(mut self, assets: ToolAssets) -> Self {
+        self.assets = Some(Arc::new(assets));
+        self
+    }
+
     pub fn new() -> Self {
         Self::default()
     }
@@ -469,14 +509,16 @@ impl PostgresToolOutput {
 
 struct ToolInvocation<'a, N> {
     name: &'static str,
-    wasm: &'static [u8],
+    wasm: &'a [u8],
     load_module: fn(&wasmer::Engine) -> Result,
+    assets: Option<&'a ToolAssets>,
     username: &'a str,
     networking: N,
     stdin: Option>,
     args: Vec,
 }
 
+#[allow(unsafe_code)]
 fn run_wasix_client_tool(invocation: ToolInvocation<'_, N>) -> Result
 where
     N: VirtualNetworking + Sync,
@@ -485,14 +527,21 @@ where
         name,
         wasm,
         load_module,
+        assets,
         username,
         networking,
         stdin,
         args,
     } = invocation;
     let engine = aot::headless_engine();
-    let module = load_module(&engine)
-        .with_context(|| format!("load {name} AOT artifact from oliphaunt-wasix-tools-aot-*"))?;
+    let module = match assets {
+        // SAFETY: ToolAssets construction requires trusted compiler output.
+        Some(assets) => unsafe {
+            aot::load_external_tool_module(&engine, name, wasm, &assets.aot, &assets.manifest)
+        },
+        None => load_module(&engine),
+    }
+    .with_context(|| format!("load {name} AOT artifact from oliphaunt-wasix-tools-aot-*"))?;
 
     let fs_root = TempDir::new().with_context(|| format!("create {name} WASIX filesystem root"))?;
     if let Some(runtime_archive) = assets::runtime_archive() {
@@ -592,8 +641,12 @@ where
     ]);
     run_wasix_client_tool(ToolInvocation {
         name: "pg_dump",
-        wasm: pg_dump_wasm_asset()?,
+        wasm: match &options.assets {
+            Some(assets) => &assets.wasm,
+            None => pg_dump_wasm_asset()?,
+        },
         load_module: aot::load_pg_dump_module,
+        assets: options.assets.as_deref(),
         username,
         networking,
         stdin: None,
@@ -619,8 +672,12 @@ where
     let args = psql_args(addr, username, database, options);
     run_wasix_client_tool(ToolInvocation {
         name: "psql",
-        wasm: psql_wasm_asset()?,
+        wasm: match &options.assets {
+            Some(assets) => &assets.wasm,
+            None => psql_wasm_asset()?,
+        },
         load_module: aot::load_psql_module,
+        assets: options.assets.as_deref(),
         username,
         networking,
         stdin,
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/transport.rs b/src/sdks/rust-wasix/src/oliphaunt/transport.rs
similarity index 100%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/transport.rs
rename to src/sdks/rust-wasix/src/oliphaunt/transport.rs
diff --git a/src/sdks/rust-wasix/src/session.rs b/src/sdks/rust-wasix/src/session.rs
new file mode 100644
index 000000000..20db96e1f
--- /dev/null
+++ b/src/sdks/rust-wasix/src/session.rs
@@ -0,0 +1,244 @@
+//! Prepared database ownership and low-level PostgreSQL protocol sessions.
+//!
+//! Socket adapters can own their transport without duplicating runtime setup.
+//! Release a prepared database only after every session has shut down successfully.
+
+use std::path::PathBuf;
+use std::sync::Arc;
+
+use anyhow::{Result, ensure};
+
+use crate::DatabaseStorage;
+use crate::oliphaunt::backend::BackendSession;
+use crate::oliphaunt::base::{DatabasePlan, InstallOutcome, prepare_database};
+use crate::oliphaunt::lifecycle::TeardownOwnership;
+
+pub use crate::oliphaunt::assets::{CatalogProfile, ClusterSeed, IcuData, default_catalog_profile};
+pub use crate::oliphaunt::config::{PostgresConfig, StartupConfig};
+#[cfg(feature = "extensions")]
+pub use crate::oliphaunt::extensions::{
+    postgres_config_with_extension_startup, resolve_extension_set,
+};
+pub use crate::oliphaunt::postgres_mod::{
+    ProtocolPumpOutcome, ProtocolStream, StartupProtocolResponse, startup_error_response_output,
+};
+
+/// Owns the prepared cluster's temporary directory and exclusive directory lock.
+/// A failed or omitted explicit release retains these resources until process exit.
+#[derive(Debug)]
+pub struct PreparedDatabase {
+    owned: TeardownOwnership,
+    runtime: PreparedRuntime,
+    released: bool,
+}
+
+/// Cloneable runtime descriptor. It keeps a prepared database from being released
+/// while an adapter or backend session still uses its files.
+#[derive(Debug, Clone)]
+pub struct PreparedRuntime {
+    outcome: InstallOutcome,
+    lifetime: Arc<()>,
+}
+
+impl PreparedDatabase {
+    pub fn prepare(
+        storage: DatabaseStorage,
+        profile: CatalogProfile,
+        username: &str,
+    ) -> Result {
+        Self::prepare_with_seed(storage, profile, username, None)
+    }
+
+    pub fn prepare_with_seed(
+        storage: DatabaseStorage,
+        profile: CatalogProfile,
+        username: &str,
+        seed: Option,
+    ) -> Result {
+        Self::prepare_with_resources(storage, profile, username, seed, None)
+    }
+
+    pub fn prepare_with_resources(
+        storage: DatabaseStorage,
+        profile: CatalogProfile,
+        username: &str,
+        seed: Option,
+        icu_data: Option,
+    ) -> Result {
+        storage.validate()?;
+        let mut plan = DatabasePlan::new(storage, profile);
+        plan.seed = seed;
+        plan.icu_data = icu_data;
+        let prepared = prepare_database(plan, username)?;
+        let runtime = PreparedRuntime {
+            outcome: prepared.outcome.clone(),
+            lifetime: Arc::new(()),
+        };
+        Ok(Self {
+            owned: TeardownOwnership::new(prepared),
+            runtime,
+            released: false,
+        })
+    }
+
+    pub fn runtime(&self) -> Result {
+        ensure!(!self.released, "prepared database was released");
+        Ok(self.runtime.clone())
+    }
+
+    /// Release files and root locking only after all runtime descriptors and
+    /// sessions have been dropped. Failed session shutdown deliberately retains
+    /// its descriptor, preventing accidental deletion of an uncertain backend.
+    pub fn release(&mut self) -> Result<()> {
+        ensure!(
+            Arc::strong_count(&self.runtime.lifetime) == 1,
+            "prepared database still has active runtime/session owners"
+        );
+        self.owned.release();
+        self.released = true;
+        Ok(())
+    }
+}
+
+impl PreparedRuntime {
+    pub fn catalog_profile(&self) -> CatalogProfile {
+        self.outcome.runtime_layout.catalog_profile
+    }
+    pub fn runtime_root(&self) -> PathBuf {
+        self.outcome.runtime_layout.module_root.clone()
+    }
+
+    pub fn open(&self, config: PostgresConfig, startup: StartupConfig) -> Result {
+        let backend = BackendSession::open(self.outcome.clone(), config, startup)?;
+        Ok(ProtocolSession::new(backend, self.lifetime.clone()))
+    }
+
+    #[cfg(feature = "extensions")]
+    pub fn open_with_extensions(
+        &self,
+        config: PostgresConfig,
+        startup: StartupConfig,
+        extensions: &[crate::Extension],
+    ) -> Result {
+        crate::oliphaunt::base::install_missing_extension_archives(&self.outcome, extensions)?;
+        let backend = BackendSession::open_with_extension_preload(
+            self.outcome.clone(),
+            config,
+            startup,
+            extensions,
+        )?;
+        Ok(ProtocolSession::new(backend, self.lifetime.clone()))
+    }
+}
+
+/// One backend with explicitly owned protocol I/O and terminal shutdown.
+pub struct ProtocolSession {
+    backend: TeardownOwnership,
+    lifetime: TeardownOwnership>,
+    closed: bool,
+    shutdown_error: Option,
+}
+
+impl ProtocolSession {
+    fn new(backend: BackendSession, lifetime: Arc<()>) -> Self {
+        Self {
+            backend: TeardownOwnership::new(backend),
+            lifetime: TeardownOwnership::new(lifetime),
+            closed: false,
+            shutdown_error: None,
+        }
+    }
+    pub fn startup_with_packet(&mut self, packet: &[u8]) -> Result {
+        ensure!(!self.closed, "protocol session was closed");
+        self.backend.startup_with_packet(packet)
+    }
+    pub fn send_buffered(&mut self, packet: &[u8]) -> Result> {
+        ensure!(!self.closed, "protocol session was closed");
+        self.backend.send_buffered(packet)
+    }
+    pub fn supports_protocol_pump(&self) -> bool {
+        !self.closed && self.backend.supports_protocol_pump()
+    }
+    pub fn attach_protocol_stream(&mut self, stream: S) -> Result<()> {
+        ensure!(!self.closed, "protocol session was closed");
+        self.backend.attach_protocol_stream(stream)
+    }
+    pub fn send_with_connection_protocol_pump(
+        &mut self,
+        packet: &[u8],
+        prefix: impl FnOnce() -> Vec,
+    ) -> Result {
+        ensure!(!self.closed, "protocol session was closed");
+        self.backend
+            .send_with_connection_protocol_pump(packet, prefix)
+    }
+    pub fn shutdown(&mut self) -> Result<()> {
+        if !self.closed {
+            self.closed = true;
+            if let Err(error) = self.backend.shutdown() {
+                self.shutdown_error = Some(error.to_string());
+                return Err(error);
+            }
+            self.backend.release();
+            self.lifetime.release();
+        }
+        if let Some(error) = &self.shutdown_error {
+            anyhow::bail!("{error}");
+        }
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::oliphaunt::base::{DirectoryLock, RuntimeLayout, RuntimeLayoutKind};
+    use crate::oliphaunt::storage::StorageRoot;
+
+    fn prepared(root: &std::path::Path) -> Result {
+        let outcome = InstallOutcome {
+            runtime_layout: RuntimeLayout {
+                catalog_profile: CatalogProfile::Standard,
+                kind: RuntimeLayoutKind::FullLocal,
+                mutable_root: StorageRoot::host_directory(root),
+                shared_root: None,
+                module_root: root.to_owned(),
+            },
+            pgdata_storage: StorageRoot::host_directory(root.join("pgdata")),
+        };
+        Ok(PreparedDatabase {
+            owned: TeardownOwnership::new(crate::oliphaunt::base::PreparedDatabase {
+                workspace: None,
+                directory_lock: Some(DirectoryLock::acquire(root)?),
+                outcome: outcome.clone(),
+            }),
+            runtime: PreparedRuntime {
+                outcome,
+                lifetime: Arc::new(()),
+            },
+            released: false,
+        })
+    }
+
+    #[test]
+    fn live_runtime_descriptor_prevents_release_then_success_unlocks_root() -> Result<()> {
+        let root = tempfile::tempdir()?;
+        let mut prepared = prepared(root.path())?;
+        let runtime = prepared.runtime()?;
+        assert!(prepared.release().is_err());
+        assert!(DirectoryLock::acquire(root.path()).is_err());
+        drop(runtime);
+        prepared.release()?;
+        assert!(prepared.runtime().is_err());
+        drop(DirectoryLock::acquire(root.path())?);
+        Ok(())
+    }
+
+    #[test]
+    fn omitted_release_retains_unknown_backend_root_ownership() -> Result<()> {
+        let root = tempfile::tempdir()?;
+        drop(prepared(root.path())?);
+        assert!(DirectoryLock::acquire(root.path()).is_err());
+        Ok(())
+    }
+}
diff --git a/src/sdks/rust-wasix/tests/extensions_smoke.rs b/src/sdks/rust-wasix/tests/extensions_smoke.rs
new file mode 100644
index 000000000..111138784
--- /dev/null
+++ b/src/sdks/rust-wasix/tests/extensions_smoke.rs
@@ -0,0 +1,17 @@
+#![cfg(feature = "extension-vector")]
+
+use anyhow::Result;
+use oliphaunt_wasix::{Extension, Oliphaunt};
+
+#[test]
+fn vector_extension_works_in_direct_mode() -> Result<()> {
+    let mut database = Oliphaunt::builder().extension(Extension::VECTOR).open()?;
+    let selected_only = database
+        .query("SELECT count(*)::int4 AS count FROM pg_extension WHERE extname = 'vector'")?;
+    assert_eq!(selected_only.get_text(0, "count")?, Some("0"));
+    database.execute("CREATE EXTENSION vector")?;
+    let result = database.query("SELECT '[1,2,3]'::vector <-> '[1,2,4]'::vector AS distance")?;
+    assert_eq!(result.get_text(0, "distance")?, Some("1"));
+    database.close()?;
+    Ok(())
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/postgres_regression.rs b/src/sdks/rust-wasix/tests/postgres_regression.rs
similarity index 99%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/postgres_regression.rs
rename to src/sdks/rust-wasix/tests/postgres_regression.rs
index 07f3f5436..7ce2cf9a2 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/postgres_regression.rs
+++ b/src/sdks/rust-wasix/tests/postgres_regression.rs
@@ -93,7 +93,7 @@ fn shared_postgres_behavior_contract() -> Result<()> {
 fn shared_fixture(shared_relative: &str, packaged_name: &str) -> Result {
     let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
     let shared = manifest_dir
-        .join("../../../../shared/fixtures")
+        .join("../../test-fixtures")
         .join(shared_relative);
     let packaged = manifest_dir.join("src/testdata").join(packaged_name);
     std::fs::read_to_string(&shared)
diff --git a/src/sdks/rust-wasix/tests/public_api.rs b/src/sdks/rust-wasix/tests/public_api.rs
new file mode 100644
index 000000000..2d165358a
--- /dev/null
+++ b/src/sdks/rust-wasix/tests/public_api.rs
@@ -0,0 +1,495 @@
+use std::error::Error as _;
+use std::path::PathBuf;
+
+use oliphaunt_wasix::{
+    AsyncOliphaunt, AsyncOliphauntBuilder, AsyncSql, AsyncTransaction, DatabaseStorage,
+    DecodeError, Error, ErrorKind, FromSql, IntoParameter, Oliphaunt, Parameter, PostgresError,
+    PostgresNotice, RawStreamCallbackOutput, RawStreamError, RawStreamResult, Result, Transaction,
+    TransactionError, TransactionResult, TypeOid, ValueFormat, ValueRef,
+};
+
+#[derive(Debug, Clone)]
+enum ApplicationError {
+    Database(Error),
+    Abort,
+}
+
+impl From for ApplicationError {
+    fn from(error: Error) -> Self {
+        Self::Database(error)
+    }
+}
+
+impl std::fmt::Display for ApplicationError {
+    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Database(error) => error.fmt(formatter),
+            Self::Abort => formatter.write_str("application aborted the transaction"),
+        }
+    }
+}
+
+impl std::error::Error for ApplicationError {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            Self::Database(error) => Some(error),
+            Self::Abort => None,
+        }
+    }
+}
+
+#[derive(Debug, Clone)]
+struct ParserError;
+
+impl std::fmt::Display for ParserError {
+    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        formatter.write_str("parser stopped the stream")
+    }
+}
+
+impl std::error::Error for ParserError {}
+
+fn sdk_only_blocking_callbacks(database: &mut Oliphaunt) -> Result<()> {
+    database.transaction(|transaction| {
+        transaction.execute("SELECT 1")?;
+        Ok(())
+    })?;
+    database.exec_protocol_raw_stream([], |_| ())?;
+    database.exec_protocol_raw_stream([], |_| -> Result<()> { Ok(()) })?;
+    Ok(())
+}
+
+fn typed_blocking_transaction(database: &mut Oliphaunt) -> TransactionResult<(), ApplicationError> {
+    database.transaction(|transaction| {
+        transaction.execute("SELECT 1")?;
+        Err(ApplicationError::Abort)
+    })
+}
+
+fn typed_blocking_stream(database: &mut Oliphaunt) -> RawStreamResult<(), ParserError> {
+    database.exec_protocol_raw_stream([], |_| Err(ParserError))
+}
+
+async fn sdk_only_async_callbacks(database: &AsyncOliphaunt) -> Result<()> {
+    database
+        .transaction(async |transaction| {
+            transaction.execute("SELECT 1").await?;
+            Ok(())
+        })
+        .await?;
+    database.exec_protocol_raw_stream([], |_| ()).await?;
+    database
+        .exec_protocol_raw_stream([], |_| -> Result<()> { Ok(()) })
+        .await?;
+    Ok(())
+}
+
+async fn typed_async_transaction(
+    database: &AsyncOliphaunt,
+) -> TransactionResult<(), ApplicationError> {
+    database
+        .transaction(async |transaction| {
+            transaction.execute("SELECT 1").await?;
+            Err(ApplicationError::Abort)
+        })
+        .await
+}
+
+async fn typed_async_stream(database: &AsyncOliphaunt) -> RawStreamResult<(), ParserError> {
+    database
+        .exec_protocol_raw_stream([], |_| Err(ParserError))
+        .await
+}
+
+fn assert_invalid_startup_identity(error: Error, name: &str) {
+    assert_invalid_configuration(error, &format!("{name} must not be empty"));
+}
+
+fn assert_invalid_configuration(error: Error, expected_message: &str) {
+    assert_eq!(error.kind(), ErrorKind::InvalidConfiguration);
+    assert_eq!(error.to_string(), expected_message);
+}
+
+fn expect_sdk_error(result: Result, message: &str) -> Error {
+    match result {
+        Ok(_) => panic!("{message}"),
+        Err(error) => error,
+    }
+}
+
+macro_rules! assert_not_impl {
+    ($type:ty: $bound:path) => {
+        const _: fn() = || {
+            trait AmbiguousIfImpl {
+                fn marker() {}
+            }
+            struct Invalid;
+            impl AmbiguousIfImpl<()> for T {}
+            impl AmbiguousIfImpl for T {}
+            let _ = <$type as AmbiguousIfImpl<_>>::marker;
+        };
+    };
+}
+
+assert_not_impl!(Oliphaunt: Send);
+assert_not_impl!(Oliphaunt: Sync);
+assert_not_impl!(AsyncTransaction: Sync);
+
+struct PublicParameter;
+
+impl IntoParameter for PublicParameter {
+    const TYPE_OID: Option = Some(TypeOid::INT4);
+
+    fn into_parameter(self) -> Parameter {
+        Parameter::typed_binary(TypeOid::INT4, 7_i32.to_be_bytes())
+    }
+}
+
+struct PublicDecoder;
+
+impl<'a> FromSql<'a> for PublicDecoder {
+    fn from_sql(_value: ValueRef<'a>) -> std::result::Result {
+        Ok(Self)
+    }
+}
+
+#[test]
+fn fallible_public_api_uses_the_sdk_result() {
+    fn assert_result(_: Result<()>) {}
+    fn assert_error() {}
+    fn assert_error_kind() {}
+
+    assert_error::();
+    assert_error_kind::();
+    assert_error::>();
+    assert_error::>();
+    let destination = tempfile::tempdir()
+        .expect("temporary directory")
+        .path()
+        .join("restored");
+    let result = Oliphaunt::restore(destination, b"not a physical archive");
+    let error = result.expect_err("invalid archive must fail");
+    assert!(!error.to_string().is_empty());
+    assert!(error.postgres_error().is_none());
+    assert!(error.transaction_rollback_errors().is_none());
+    assert!(error.transaction_callback_database_errors().is_none());
+    assert!(error.source().is_some());
+    assert_result(Err(error));
+
+    fn transaction_rollback_tuple_surface(error: &Error) {
+        let _: ErrorKind = error.kind();
+        let _stable_match = match error.kind() {
+            ErrorKind::InvalidConfiguration => "invalid-configuration",
+            ErrorKind::Lifecycle => "lifecycle",
+            ErrorKind::TransactionActive => "transaction-active",
+            ErrorKind::Postgres => "postgres",
+            _ => "other-or-future",
+        };
+        let _: Option<(&Error, &Error)> = error.transaction_rollback_errors();
+        let _: Option<(&Error, &Error)> = error.transaction_callback_database_errors();
+    }
+    let _: fn(&Error) = transaction_rollback_tuple_surface;
+
+    fn generic_error_surface(
+        transaction: &TransactionError,
+        stream: &RawStreamError,
+    ) {
+        let _: Option<&ApplicationError> = transaction.callback_error();
+        let _: Option<&Error> = transaction.database_error();
+        let _: Option<&Error> = transaction.rollback_error();
+        let _: Option<&ParserError> = stream.callback_error();
+        let _: Option<&Error> = stream.database_error();
+        let _: Option<&Error> = stream.callback_panic_error();
+    }
+    let _: fn(&TransactionError, &RawStreamError) =
+        generic_error_surface;
+
+    fn flatten_sdk_errors(
+        transaction: TransactionError,
+        stream: RawStreamError,
+        infallible: RawStreamError,
+    ) {
+        let _: Error = transaction.into();
+        let _: Error = stream.into();
+        let _: Error = infallible.into();
+    }
+    let _ = flatten_sdk_errors;
+
+    fn postgres_diagnostic_surface(error: &PostgresError, notice: &PostgresNotice) {
+        let _: (&Option, &Option) =
+            (&error.localized_severity, ¬ice.localized_severity);
+        let _: (&Option, &Option) =
+            (&error.nonlocalized_severity, ¬ice.nonlocalized_severity);
+        let _: (&Option, &Option) =
+            (&error.internal_position, ¬ice.internal_position);
+        let _: (&Option, &Option) = (&error.internal_query, ¬ice.internal_query);
+        let _: (&Option, &Option) = (&error.file, ¬ice.file);
+        let _: (&Option, &Option) = (&error.line, ¬ice.line);
+        let _: (&Option, &Option) = (&error.routine, ¬ice.routine);
+    }
+    let _: fn(&PostgresError, &PostgresNotice) = postgres_diagnostic_surface;
+}
+
+#[test]
+fn direct_builders_reject_empty_startup_identities_before_runtime_work() {
+    for value in ["", " \t\n"] {
+        let error = expect_sdk_error(
+            Oliphaunt::builder().username(value).open(),
+            "empty username must fail before runtime setup",
+        );
+        assert_invalid_startup_identity(error, "username");
+
+        let error = expect_sdk_error(
+            Oliphaunt::builder().database(value).open(),
+            "empty database must fail before runtime setup",
+        );
+        assert_invalid_startup_identity(error, "database");
+    }
+}
+
+#[tokio::test]
+async fn async_builders_preserve_startup_identity_validation() {
+    let error = expect_sdk_error(
+        AsyncOliphaunt::builder().username(" \t\n").open().await,
+        "async database must preserve direct username validation",
+    );
+    assert_invalid_startup_identity(error, "username");
+}
+
+#[test]
+fn sync_builders_reject_invalid_host_paths_before_filesystem_work() {
+    for (path, reason) in [
+        (PathBuf::new(), "must not be empty"),
+        (PathBuf::from("invalid\0path"), "must not contain NUL bytes"),
+    ] {
+        let error = expect_sdk_error(
+            Oliphaunt::builder()
+                .storage(DatabaseStorage::Directory(path.clone()))
+                .open(),
+            "invalid storage path must fail before runtime setup",
+        );
+        assert_invalid_configuration(error, &format!("database storage directory {reason}"));
+    }
+}
+
+#[tokio::test]
+async fn async_builders_preserve_host_path_validation() {
+    for (path, reason) in [
+        (PathBuf::new(), "must not be empty"),
+        (PathBuf::from("invalid\0path"), "must not contain NUL bytes"),
+    ] {
+        let error = expect_sdk_error(
+            AsyncOliphaunt::builder()
+                .storage(DatabaseStorage::Directory(path.clone()))
+                .open()
+                .await,
+            "async database must preserve storage path validation",
+        );
+        assert_invalid_configuration(error, &format!("database storage directory {reason}"));
+    }
+}
+
+#[test]
+fn typed_and_fluent_database_api_is_public() {
+    fn assert_decoder()
+    where
+        for<'a> T: FromSql<'a>,
+    {
+    }
+    assert_decoder::();
+    assert_decoder::();
+    assert_decoder::();
+
+    let parameter = Parameter::null().with_type_oid(TypeOid::UUID);
+    assert_eq!(parameter.type_oid(), Some(TypeOid::UUID));
+    assert_eq!(parameter.format(), ValueFormat::Text);
+    assert_eq!(TypeOid::TIMETZ.get(), 1266);
+    assert_eq!(TypeOid::CHAR_ARRAY.get(), 1002);
+    assert_eq!(TypeOid::NAME_ARRAY.get(), 1003);
+    assert_eq!(TypeOid::XML_ARRAY.get(), 143);
+    assert_eq!(TypeOid::TIMETZ_ARRAY.get(), 1270);
+    assert_eq!(
+        IntoParameter::into_parameter(None::).type_oid(),
+        Some(TypeOid::INT8)
+    );
+    assert_eq!(
+        IntoParameter::into_parameter(PublicParameter).type_oid(),
+        Some(TypeOid::INT4)
+    );
+
+    fn assert_send_sync() {}
+    fn assert_send_type() {}
+    fn assert_clone() {}
+    fn assert_debug() {}
+    fn assert_send(_: T) {}
+    fn assert_raw_callback_output() {}
+    assert_send_sync::();
+    assert_clone::();
+    assert_debug::();
+    assert_send_sync::();
+    assert_clone::();
+    assert_send_type::();
+    assert_send(AsyncOliphaunt::open());
+    assert_send(AsyncOliphaunt::builder().open());
+    assert_send(AsyncOliphaunt::restore("unused", b""));
+    assert_raw_callback_output::<()>();
+    assert_raw_callback_output::>();
+
+    fn async_sql_is_send<'db, 'q>(statement: AsyncSql<'db, 'q>) {
+        assert_send(statement);
+    }
+    let _: for<'db, 'q> fn(AsyncSql<'db, 'q>) = async_sql_is_send;
+
+    fn direct_construction_surface() {
+        let _: Result<_> = Oliphaunt::open();
+        let _: Result<_> = Oliphaunt::builder().open();
+    }
+    let _: fn() = direct_construction_surface;
+
+    fn direct_database_surface(database: &mut Oliphaunt) {
+        let _: Result<_> = database.query("SELECT 1");
+        let _query = database
+            .sql("SELECT $1::int4")
+            .bind(1_i32)
+            .result_format(ValueFormat::Binary)
+            .query();
+        let _execute = database
+            .sql("UPDATE items SET value = $1")
+            .bind("value")
+            .execute();
+        let _typed_query = database.query_with_params("SELECT $1::int4", [1_i32]);
+        let _typed_execute = database.execute_with_params("SELECT $1::bool", [true]);
+        let _describe = database
+            .sql("SELECT $1::uuid")
+            .bind_parameter(Parameter::typed_null(TypeOid::UUID))
+            .describe();
+        let _exec = database.exec("SELECT 1; SELECT 2");
+        let _description = database.describe("SELECT $1::uuid");
+        let _raw = database.exec_protocol_raw([]);
+        let streamed_bytes = std::sync::Arc::new(std::sync::Mutex::new(0_usize));
+        let callback_bytes = std::sync::Arc::clone(&streamed_bytes);
+        let _owned_raw_stream = database.exec_protocol_raw_stream([], move |chunk| {
+            *callback_bytes.lock().expect("stream byte counter") += chunk.len();
+        });
+        let _ = streamed_bytes;
+        let _raw_stream = database.exec_protocol_raw_stream([], |_| ());
+        let _backup = database.backup();
+        let _ = database.is_closed();
+        let _close = database.close();
+    }
+    fn direct_transaction_surface(transaction: &mut Transaction<'_>) {
+        let _ = transaction.is_closed();
+        let _query = transaction.sql("SELECT $1::int4").bind(1_i32).query();
+        let _execute = transaction
+            .sql("UPDATE items SET value = $1")
+            .bind("value")
+            .execute();
+        let _typed_query = transaction.query_with_params("SELECT $1::int8", [1_i64]);
+        let _describe = transaction.sql("SELECT 1").describe();
+        let _: Result<_> = transaction.exec("SELECT 1");
+        let _ = transaction.rollback();
+    }
+    let _: fn(&mut Oliphaunt) = direct_database_surface;
+    let _: fn(&mut Oliphaunt) -> Result<()> = sdk_only_blocking_callbacks;
+    let _: fn(&mut Oliphaunt) -> TransactionResult<(), ApplicationError> =
+        typed_blocking_transaction;
+    let _: fn(&mut Oliphaunt) -> RawStreamResult<(), ParserError> = typed_blocking_stream;
+    let _: fn(&mut Transaction<'_>) = direct_transaction_surface;
+
+    fn async_database_surface(database: &AsyncOliphaunt) {
+        let _clone = database.clone();
+        assert_send(database.query("SELECT 1"));
+        let _query = database
+            .sql("SELECT $1::int4")
+            .bind(1_i32)
+            .result_format(ValueFormat::Binary)
+            .query();
+        let _execute = database
+            .sql("UPDATE items SET value = $1")
+            .bind("value")
+            .execute();
+        let _typed_query = database.query_with_params("SELECT $1::int4", [1_i32]);
+        let _typed_execute = database.execute_with_params("SELECT $1::bool", [true]);
+        let _describe = database
+            .sql("SELECT $1::uuid")
+            .bind_parameter(Parameter::typed_null(TypeOid::UUID))
+            .describe();
+        let _exec = database.exec("SELECT 1; SELECT 2");
+        let _description = database.describe("SELECT $1::uuid");
+        let _raw = database.exec_protocol_raw([]);
+        let _raw_stream = database.exec_protocol_raw_stream([], |_| ());
+        let _backup = database.backup();
+        let _ = database.is_closed();
+        let _close = database.close();
+        std::mem::drop(sdk_only_async_callbacks(database));
+        std::mem::drop(typed_async_transaction(database));
+        assert_send(typed_async_stream(database));
+    }
+    fn async_transaction_surface(transaction: &mut AsyncTransaction) {
+        let _ = transaction.is_closed();
+        std::mem::drop(transaction.sql("SELECT $1::int4").bind(1_i32).query());
+        std::mem::drop(
+            transaction
+                .sql("UPDATE items SET value = $1")
+                .bind("value")
+                .execute(),
+        );
+        std::mem::drop(transaction.query_with_params("SELECT $1::int8", [1_i64]));
+        std::mem::drop(transaction.sql("SELECT 1").describe());
+        std::mem::drop(transaction.exec("SELECT 1"));
+        std::mem::drop(transaction.rollback());
+    }
+    let _: fn(&AsyncOliphaunt) = async_database_surface;
+    let _: fn(&mut AsyncTransaction) = async_transaction_surface;
+}
+
+#[cfg(feature = "extension-vector")]
+#[test]
+fn extensions_expose_only_the_selection_contract() {
+    use oliphaunt_wasix::Extension;
+
+    fn assert_extension_traits() {}
+    assert_extension_traits::();
+
+    let extension: Extension = Extension::VECTOR;
+    assert_eq!(extension.sql_name(), "vector");
+    assert_eq!(Extension::by_sql_name("vector"), Some(extension));
+    assert!(Extension::ALL.contains(&extension));
+}
+
+#[cfg(feature = "extension-earthdistance")]
+#[test]
+fn extension_features_expose_required_dependency_selectors() {
+    use oliphaunt_wasix::Extension;
+
+    assert_eq!(
+        Extension::by_sql_name("earthdistance"),
+        Some(Extension::EARTHDISTANCE)
+    );
+    assert_eq!(Extension::by_sql_name("cube"), Some(Extension::CUBE));
+    assert!(Extension::ALL.contains(&Extension::EARTHDISTANCE));
+    assert!(Extension::ALL.contains(&Extension::CUBE));
+}
+
+#[cfg(feature = "tools")]
+#[test]
+fn packaged_psql_accepts_standard_script_input() {
+    let options = oliphaunt_wasix::tools::PsqlOptions::new().script("SELECT 1;");
+    let _: oliphaunt_wasix::tools::PsqlOptions = options;
+    fn assert_tool_error() {}
+    assert_tool_error::();
+
+    fn direct_tool_surface(database: &mut Oliphaunt) {
+        let _: Result<_> = database.pg_dump(oliphaunt_wasix::tools::PgDumpOptions::new());
+        let _: Result<_> =
+            database.psql(oliphaunt_wasix::tools::PsqlOptions::new().command("SELECT 1"));
+    }
+    fn async_tool_surface(database: &AsyncOliphaunt) {
+        std::mem::drop(database.pg_dump(oliphaunt_wasix::tools::PgDumpOptions::new()));
+        std::mem::drop(
+            database.psql(oliphaunt_wasix::tools::PsqlOptions::new().command("SELECT 1")),
+        );
+    }
+    let _: fn(&mut Oliphaunt) = direct_tool_surface;
+    let _: fn(&AsyncOliphaunt) = async_tool_surface;
+}
diff --git a/src/sdks/rust-wasix/tests/resources.rs b/src/sdks/rust-wasix/tests/resources.rs
new file mode 100644
index 000000000..200a4c461
--- /dev/null
+++ b/src/sdks/rust-wasix/tests/resources.rs
@@ -0,0 +1,123 @@
+use anyhow::{Context, Result};
+use oliphaunt_wasix::{CatalogProfile, ClusterSeed, DatabaseStorage, Oliphaunt};
+use std::fs;
+
+fn seed(profile: CatalogProfile) -> Result {
+    let key = match profile {
+        CatalogProfile::Standard => "OLIPHAUNT_TEST_STANDARD_SEED",
+        CatalogProfile::Icu => "OLIPHAUNT_TEST_ICU_SEED",
+    };
+    let archive = std::path::PathBuf::from(std::env::var_os(key).with_context(|| key)?);
+    let manifest = archive.with_extension("").with_extension("json");
+    Ok(ClusterSeed::new(fs::read(archive)?, fs::read(manifest)?))
+}
+
+fn check_profile(database: &mut Oliphaunt, profile: CatalogProfile) -> Result<()> {
+    match profile {
+        CatalogProfile::Standard => assert_eq!(
+            database.query("SELECT (collversion IS NULL)::text AS value FROM pg_collation WHERE collname = 'unicode'")?.get_text(0, "value")?,
+            Some("true")
+        ),
+        CatalogProfile::Icu => assert_eq!(
+            database.query("SELECT string_agg(value, ',' ORDER BY value COLLATE \"en-x-icu\") AS value FROM (VALUES ('z'), ('a'), (chr(228))) AS input(value)")?.get_text(0, "value")?,
+            Some("a,ä,z")
+        ),
+    }
+    Ok(())
+}
+
+fn exercise(profile: CatalogProfile) -> Result<()> {
+    let seed = seed(profile)?;
+    let mut builder = Oliphaunt::builder().catalog_profile(profile);
+    if profile == CatalogProfile::Icu {
+        let root = std::path::PathBuf::from(
+            std::env::var_os("OLIPHAUNT_TEST_ICU_ROOT").context("OLIPHAUNT_TEST_ICU_ROOT")?,
+        );
+        let data = fs::read(root.join("share/icu/icudt76l.dat"))?;
+        let manifest = fs::read(root.join("manifest.properties"))?;
+        let mut tampered = data.clone();
+        tampered[0] ^= 1;
+        assert_eq!(
+            oliphaunt_wasix::IcuData::new(tampered, &manifest)
+                .unwrap_err()
+                .kind(),
+            oliphaunt_wasix::ErrorKind::InvalidConfiguration,
+        );
+        builder = builder.icu_data(oliphaunt_wasix::IcuData::new(data, manifest)?);
+    }
+    let mut memory = builder.clone().seed(seed.clone()).open()?;
+    check_profile(&mut memory, profile)?;
+    assert_eq!(
+        memory.query("SELECT 17 AS value")?.get_text(0, "value")?,
+        Some("17")
+    );
+    memory.close()?;
+
+    let workspace = tempfile::tempdir()?;
+    let root = workspace.path().join("seeded");
+    let mut database = builder
+        .clone()
+        .storage(DatabaseStorage::Directory(root.clone()))
+        .seed(seed)
+        .open()?;
+    database.execute("CREATE TABLE resource_proof(value integer)")?;
+    database.execute("INSERT INTO resource_proof VALUES (17)")?;
+    database.close()?;
+    drop(database);
+
+    // A seed is initialization input, so even unusable seed bytes are irrelevant on reopen.
+    let mut reopened = builder
+        .clone()
+        .storage(DatabaseStorage::Directory(root))
+        .seed(ClusterSeed::new(b"unused".as_slice(), b"unused".as_slice()))
+        .open()?;
+    assert_eq!(
+        reopened
+            .query("SELECT sum(value) AS value FROM resource_proof")?
+            .get_text(0, "value")?,
+        Some("17")
+    );
+    reopened.close()?;
+
+    for storage in [
+        DatabaseStorage::Memory,
+        DatabaseStorage::Directory(workspace.path().join("initialized")),
+    ] {
+        let mut database = builder.clone().storage(storage).open()?;
+        check_profile(&mut database, profile)?;
+        database.execute("CREATE TABLE initialized_proof(value integer)")?;
+        database.execute("INSERT INTO initialized_proof VALUES (17)")?;
+        assert_eq!(
+            database
+                .query("SELECT value FROM initialized_proof")?
+                .get_text(0, "value")?,
+            Some("17")
+        );
+        database.close()?;
+    }
+    let mut reopened = builder
+        .storage(DatabaseStorage::Directory(
+            workspace.path().join("initialized"),
+        ))
+        .open()?;
+    assert_eq!(
+        reopened
+            .query("SELECT value FROM initialized_proof")?
+            .get_text(0, "value")?,
+        Some("17")
+    );
+    reopened.close()?;
+    Ok(())
+}
+
+#[test]
+#[ignore = "requires compiled WASIX runtime and separately produced resources; run test-resources.sh"]
+fn standard_seed_and_initializer_support_memory_directory_and_reopen() -> Result<()> {
+    exercise(CatalogProfile::Standard)
+}
+
+#[test]
+#[ignore = "requires compiled WASIX runtime and separately produced resources; run test-resources.sh"]
+fn icu_seed_and_initializer_support_memory_directory_and_reopen() -> Result<()> {
+    exercise(CatalogProfile::Icu)
+}
diff --git a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/runtime_smoke.rs b/src/sdks/rust-wasix/tests/runtime_smoke.rs
similarity index 95%
rename from src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/runtime_smoke.rs
rename to src/sdks/rust-wasix/tests/runtime_smoke.rs
index 37966c7c7..2da39f3dd 100644
--- a/src/bindings/wasix-rust/crates/oliphaunt-wasix/tests/runtime_smoke.rs
+++ b/src/sdks/rust-wasix/tests/runtime_smoke.rs
@@ -2,8 +2,7 @@
 
 use anyhow::Result;
 use oliphaunt_wasix::{
-    AsyncOliphaunt, AsyncOliphauntServer, AsyncTransaction, DatabaseStorage, Error, Oliphaunt,
-    OliphauntServer, TransactionResult,
+    AsyncOliphaunt, AsyncTransaction, DatabaseStorage, Error, Oliphaunt, TransactionResult,
 };
 use std::convert::Infallible;
 use std::future::Future;
@@ -186,22 +185,6 @@ fn direct_protocol_callback_error_and_panic_recover_before_returning() -> Result
     Ok(())
 }
 
-#[test]
-fn direct_server_close_releases_directory_ownership_before_returning() -> Result<()> {
-    let workspace = tempfile::tempdir()?;
-    let root = workspace.path().join("server-root");
-    let mut server = OliphauntServer::builder()
-        .storage(DatabaseStorage::Directory(root.clone()))
-        .start()?;
-    server.close()?;
-    let mut database = Oliphaunt::builder()
-        .storage(DatabaseStorage::Directory(root))
-        .open()?;
-    database.close()?;
-    assert!(server.is_closed());
-    Ok(())
-}
-
 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
 async fn async_api_owns_the_runtime_and_serializes_clones() -> Result<()> {
     let caller_thread = std::thread::current().id();
@@ -443,23 +426,6 @@ async fn dropping_close_future_does_not_cancel_the_close_attempt() -> Result<()>
     Ok(())
 }
 
-#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
-async fn async_server_close_releases_directory_ownership_before_completion() -> Result<()> {
-    let workspace = tempfile::tempdir()?;
-    let root = workspace.path().join("async-server-root");
-    let server = AsyncOliphauntServer::builder()
-        .storage(DatabaseStorage::Directory(root.clone()))
-        .start()
-        .await?;
-    server.close().await?;
-    let mut database = Oliphaunt::builder()
-        .storage(DatabaseStorage::Directory(root))
-        .open()?;
-    database.close()?;
-    assert!(server.is_closed());
-    Ok(())
-}
-
 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
 async fn admitted_query_precedes_later_transaction_begin() -> Result<()> {
     let database = AsyncOliphaunt::open().await?;
diff --git a/src/sdks/rust-wasix/tools/check-package.mts b/src/sdks/rust-wasix/tools/check-package.mts
new file mode 100644
index 000000000..efc7b204d
--- /dev/null
+++ b/src/sdks/rust-wasix/tools/check-package.mts
@@ -0,0 +1,69 @@
+#!/usr/bin/env bun
+import { readdirSync, readFileSync } from 'node:fs';
+import path from 'node:path';
+import { assertPackagedCargoDependencies } from '../../../../tools/packaging/cargo-dependencies.mts';
+import {
+  archiveTarNames,
+  cargoCrateManifest,
+  fail,
+  inspectSdkProduct,
+  PREFIX,
+  rejectSdkRuntimePayload,
+  rel,
+  requireCrateMatchesCargoListing,
+} from '../../../../tools/packaging/release-carrier.mts';
+import {
+  compareText,
+  currentProductVersion,
+  ROOT,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { renderOliphauntWasixReleaseCargoToml } from './prepare-rust-release-source.mts';
+
+async function validateWasixSdkCrate(crate) {
+  const manifest = cargoCrateManifest(crate);
+  const packageConfig = manifest.package;
+  if (
+    packageConfig === null ||
+    Array.isArray(packageConfig) ||
+    typeof packageConfig !== 'object' ||
+    packageConfig.name !== 'oliphaunt-wasix'
+  ) {
+    fail(`${rel(crate)} must package the oliphaunt-wasix crate`);
+  }
+  const sdkVersion = await currentProductVersion('oliphaunt-wasix-rust', PREFIX);
+  if (packageConfig.version !== sdkVersion) {
+    fail(`${rel(crate)} package oliphaunt-wasix must use version ${sdkVersion}`);
+  }
+  const expected = Bun.TOML.parse(
+    renderOliphauntWasixReleaseCargoToml(
+      readFileSync(path.join(ROOT, 'src/sdks/rust-wasix/Cargo.toml'), 'utf8'),
+    ),
+  );
+  assertPackagedCargoDependencies(manifest, expected, rel(crate));
+}
+
+export async function checkWasixRustPackage(root) {
+  const product = 'oliphaunt-wasix-rust';
+
+  const crates = readdirSync(root)
+    .filter((name) => name.endsWith('.crate'))
+    .map((name) => path.join(root, name))
+    .sort(compareText);
+  if (crates.length === 0) {
+    fail(`${product} must stage a Cargo crate under ${rel(root)}`);
+  }
+  for (const crate of crates) {
+    rejectSdkRuntimePayload(product, crate, archiveTarNames(crate));
+    await validateWasixSdkCrate(crate);
+    const version = await currentProductVersion('oliphaunt-wasix-rust', PREFIX);
+    requireCrateMatchesCargoListing(
+      crate,
+      path.join(root, 'cargo-package-files.txt'),
+      'oliphaunt-wasix',
+      version,
+    );
+  }
+  return true;
+}
+
+if (import.meta.main) await inspectSdkProduct('oliphaunt-wasix-rust', checkWasixRustPackage);
diff --git a/src/sdks/rust-wasix/tools/package-source.mts b/src/sdks/rust-wasix/tools/package-source.mts
new file mode 100755
index 000000000..a8508ca51
--- /dev/null
+++ b/src/sdks/rust-wasix/tools/package-source.mts
@@ -0,0 +1,45 @@
+#!/usr/bin/env bun
+import { cp, copyFile, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
+import path from 'node:path';
+
+export const ROOT = path.resolve(import.meta.dirname, '../../../..');
+
+async function copy(source, destination) {
+  await mkdir(path.dirname(destination), { recursive: true });
+  await copyFile(source, destination);
+}
+
+export async function stageWasixRustPackageSource(outputDir) {
+  const destination = path.resolve(ROOT, outputDir);
+  const relative = path.relative(ROOT, destination);
+  if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
+    throw new Error(`WASIX Rust package stage must stay inside the repository: ${outputDir}`);
+  }
+
+  await rm(destination, { recursive: true, force: true });
+  await cp(path.join(ROOT, 'src/sdks/rust-wasix'), destination, {
+    recursive: true,
+    filter: (source) => path.basename(source) !== 'target',
+  });
+  await cp(path.join(ROOT, 'src/test-fixtures'), path.join(destination, 'src/testdata'), {
+    recursive: true,
+    filter: (source) => path.basename(source) !== 'moon.yml',
+  });
+  await copy(path.join(ROOT, 'LICENSE'), path.join(destination, 'LICENSE'));
+  await copy(
+    path.join(ROOT, 'THIRD_PARTY_NOTICES.md'),
+    path.join(destination, 'THIRD_PARTY_NOTICES.md'),
+  );
+
+  const manifest = path.join(destination, 'Cargo.toml');
+  const text = `${(await readFile(manifest, 'utf8'))
+    .replace(/,\s*path\s*=\s*"[^"]+"/gu, '')
+    .trimEnd()}\n\n[workspace]\n`;
+  await writeFile(manifest, text, 'utf8');
+  return manifest;
+}
+
+if (import.meta.main) {
+  const output = process.argv[2] ?? 'target/oliphaunt-wasix-rust/package/source';
+  console.log(path.relative(ROOT, await stageWasixRustPackageSource(output)));
+}
diff --git a/src/sdks/rust-wasix/tools/prepare-rust-release-source.mts b/src/sdks/rust-wasix/tools/prepare-rust-release-source.mts
new file mode 100644
index 000000000..f24e93dc7
--- /dev/null
+++ b/src/sdks/rust-wasix/tools/prepare-rust-release-source.mts
@@ -0,0 +1,114 @@
+#!/usr/bin/env bun
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import {
+  canonicalWasixCargoToolchainVersions,
+  validateWasixConsumerDependencyPins,
+} from '../../../runtimes/liboliphaunt-wasix/tools/wasix-cargo-toolchain-policy.mts';
+
+import {
+  packagedCargoManifestText,
+  parseCargoPackageNameVersion,
+} from '../../../../tools/packaging/cargo-source-package.mts';
+import {
+  assertReleaseNoticesInDirectory,
+  stageReleaseNotices,
+} from '../../../../tools/packaging/release-notices.mts';
+import { loadPublicationCatalog } from '../../../../tools/release/publication-catalog.mts';
+import { productCompatibilityVersion } from '../../../../tools/release/release-graph.mts';
+import { ROOT as root, stageWasixRustPackageSource } from './package-source.mts';
+
+const SOURCE_NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' });
+
+function fail(message) {
+  console.error(`prepare-rust-release-source.mts: ${message}`);
+  process.exit(2);
+}
+
+function rel(target) {
+  const relative = path.relative(root, target);
+  return relative.startsWith('..') || path.isAbsolute(relative)
+    ? target
+    : relative.split(path.sep).join('/');
+}
+
+async function readText(relativePath) {
+  return await fs.readFile(path.join(root, relativePath), 'utf8');
+}
+
+export async function currentOliphauntWasixSdkVersion() {
+  const text = await readText('src/sdks/rust-wasix/Cargo.toml');
+  return parseCargoPackageNameVersion(text, 'src/sdks/rust-wasix/Cargo.toml').version;
+}
+
+function escapeRegExp(value) {
+  return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
+}
+
+export function renderOliphauntWasixReleaseCargoToml(
+  source,
+  runtimeVersion = productCompatibilityVersion(
+    'oliphaunt-wasix-rust',
+    'liboliphaunt-wasix',
+    'prepare-rust-release-source.mts',
+  ),
+) {
+  let text = packagedCargoManifestText(source);
+  const catalog = loadPublicationCatalog('prepare-rust-release-source.mts');
+  for (const carrier of catalog.carriers.filter((entry) => entry.ecosystem === 'cargo')) {
+    const crate = carrier.name;
+    const pattern = new RegExp(
+      `^(${escapeRegExp(crate)}\\s*=\\s*\\{[^}\\n]*version\\s*=\\s*")[^"]+("[^}\\n]*\\})$`,
+      'gmu',
+    );
+    if (!pattern.test(text)) {
+      continue;
+    }
+    const version = carrier.product === 'liboliphaunt-wasix' ? runtimeVersion : carrier.version;
+    text = text.replace(pattern, `$1=${version}$2`);
+  }
+  return text;
+}
+
+function validateGeneratedOliphauntWasixReleaseArtifactCoverage(manifestText) {
+  if (/=\s*\{[^}\n]*path\s*=/u.test(manifestText)) {
+    fail('generated oliphaunt-wasix release source must not contain local path dependencies');
+  }
+  const toolchainVersions = canonicalWasixCargoToolchainVersions(root);
+  const toolchainFailures = validateWasixConsumerDependencyPins(Bun.TOML.parse(manifestText), {
+    manifestPath: 'generated oliphaunt-wasix release source',
+    toolchainVersions,
+  });
+  if (toolchainFailures.length > 0) {
+    fail(toolchainFailures.join('\n'));
+  }
+}
+
+export async function prepareOliphauntWasixReleaseSource(version) {
+  const runtimeVersion = productCompatibilityVersion(
+    'oliphaunt-wasix-rust',
+    'liboliphaunt-wasix',
+    'prepare-rust-release-source.mts',
+  );
+  const stageDir = path.join(root, 'target/release/cargo-package-sources/oliphaunt-wasix');
+  await stageWasixRustPackageSource(stageDir);
+  const cargoToml = path.join(stageDir, 'Cargo.toml');
+  const rendered = renderOliphauntWasixReleaseCargoToml(
+    await fs.readFile(cargoToml, 'utf8'),
+    runtimeVersion,
+  );
+  const generatedPackage = parseCargoPackageNameVersion(rendered, rel(cargoToml));
+  if (generatedPackage.version !== version) {
+    fail(`generated oliphaunt-wasix release source must keep SDK version ${version}`);
+  }
+  validateGeneratedOliphauntWasixReleaseArtifactCoverage(rendered);
+  await fs.writeFile(cargoToml, rendered);
+  stageReleaseNotices(stageDir, SOURCE_NOTICE_OPTIONS);
+  assertReleaseNoticesInDirectory(stageDir, SOURCE_NOTICE_OPTIONS);
+  return cargoToml;
+}
+
+if (import.meta.main) {
+  if (Bun.argv.length !== 2) fail('usage: prepare-rust-release-source.mts');
+  console.log(await prepareOliphauntWasixReleaseSource(await currentOliphauntWasixSdkVersion()));
+}
diff --git a/src/sdks/rust-wasix/tools/stage-release-artifacts.sh b/src/sdks/rust-wasix/tools/stage-release-artifacts.sh
new file mode 100644
index 000000000..4527795ef
--- /dev/null
+++ b/src/sdks/rust-wasix/tools/stage-release-artifacts.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+artifact_root="$PWD/target/sdk-artifacts/oliphaunt-wasix-rust"
+rm -rf "$artifact_root"
+mkdir -p "$artifact_root"
+manifest=$(bun src/sdks/rust-wasix/tools/prepare-rust-release-source.mts)
+crate=$(bash tools/packaging/package-cargo-source.sh "$manifest" "$PWD/target/sdk-artifacts-work/oliphaunt-wasix-rust" "$artifact_root/cargo-package-files.txt")
+prefix=$(basename "$crate" .crate)
+bun tools/packaging/release-notices.mts check-archive "$crate" --profile source-sdk --prefix "$prefix"
+cp "$crate" "$artifact_root/"
+bun tools/packaging/staging.mts "$artifact_root"
diff --git a/src/sdks/rust-wasix/tools/test-aot.sh b/src/sdks/rust-wasix/tools/test-aot.sh
new file mode 100644
index 000000000..26bfd7dc3
--- /dev/null
+++ b/src/sdks/rust-wasix/tools/test-aot.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "unable to determine repository root from $script_dir; run this script from a Git checkout" >&2
+  exit 1
+}
+[ -f "$root/package.json" ] && [ -d "$root/src/runtimes/liboliphaunt-wasix" ] || {
+  echo "must run inside the Oliphaunt workspace" >&2
+  exit 1
+}
+cd "$root"
+
+. "$root/src/runtimes/liboliphaunt-wasix/tools/cargo-test-filter.sh"
+
+target="${AOT_TARGET:-${1:-}}"
+if [ -z "$target" ]; then
+  target="$(rustc -vV | awk '/^host:/{print $2}')"
+fi
+host="$(rustc -vV | awk '/^host:/{print $2}')"
+if [ "$target" != "$host" ]; then
+  echo "target AOT execution requires the builder host $host to match AOT target $target" >&2
+  exit 1
+fi
+
+# Compiling and running the SDK consumes the host's actual AOT carrier crate;
+# producer tasks only serialize/package/check payload bytes.
+bash src/runtimes/liboliphaunt-wasix/tools/runtime-smoke.sh core-smoke
+
+# The portable/Linux regression exercises every catalogued extension. Each host
+# must also deserialize and execute machine code produced for that exact host,
+# including a side module and the split pg_dump/psql tool artifacts.  Keep this
+# bounded representative lane on all four AOT builders so cross-host coverage
+# does not multiply the exhaustive 39-extension lifecycle suite by four.
+proof_root="$root/target/wasix-target-aot-smoke"
+rm -rf "$proof_root"
+OLIPHAUNT_WASIX_GENERATED_ASSET_ROOT="$root/target/extensions/wasix/assets" \
+OLIPHAUNT_WASIX_EXTENSION_AOT_ARTIFACT_ROOT="$root/target/extensions/wasix/aot-artifacts" \
+  tools/dev/bun.sh src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts \
+    --output-root "$proof_root/extension-artifacts" \
+    --family wasix \
+    --require-wasix \
+    oliphaunt-extension-contrib-pg18
+aot_test_filter="extension_tests::uuid_ossp_aot_"
+aot_test_command=(
+  env
+  OLIPHAUNT_WASM_AOT_VERIFY=full
+  OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="$proof_root/extension-artifacts"
+  cargo test -p oliphaunt-wasix --locked --no-default-features
+  --features extension-uuid-ossp,tools
+  --lib "$aot_test_filter"
+)
+oliphaunt_require_cargo_test_filter "$aot_test_filter" "${aot_test_command[@]}"
+"${aot_test_command[@]}" -- --nocapture --test-threads=1
diff --git a/src/sdks/rust-wasix/tools/test-resources.sh b/src/sdks/rust-wasix/tools/test-resources.sh
new file mode 100644
index 000000000..923ed5dbe
--- /dev/null
+++ b/src/sdks/rust-wasix/tools/test-resources.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+cd "$root"
+version="$(cat src/database-resources/VERSION)"
+export OLIPHAUNT_TEST_STANDARD_SEED="$root/target/database-resources/release-assets/database-resources-$version-seed-wasix-standard.tar.zst"
+export OLIPHAUNT_TEST_ICU_SEED="$root/target/database-resources/release-assets/database-resources-$version-seed-wasix-icu.tar.zst"
+OLIPHAUNT_TEST_ICU_ROOT="$(mktemp -d)"
+export OLIPHAUNT_TEST_ICU_ROOT
+trap 'rm -rf "$OLIPHAUNT_TEST_ICU_ROOT"' EXIT
+tar -xzf "$root/target/database-resources/release-assets/database-resources-$version-icu-data.tar.gz" -C "$OLIPHAUNT_TEST_ICU_ROOT"
+cargo test -p oliphaunt-wasix --locked --test resources -- --ignored --test-threads=1
diff --git a/src/sdks/rust/ARCHITECTURE.md b/src/sdks/rust/ARCHITECTURE.md
deleted file mode 100644
index b742db5b7..000000000
--- a/src/sdks/rust/ARCHITECTURE.md
+++ /dev/null
@@ -1,175 +0,0 @@
-# Rust SDK architecture
-
-The Rust SDK is a native binding over `liboliphaunt`. It does not wrap the
-WASIX binding and has no runtime fallback matrix.
-
-## Public boundary
-
-The public database boundary is:
-
-- Root `Oliphaunt::open()` or `Oliphaunt::builder()` for synchronous,
-  exclusive direct and broker databases.
-- Root `AsyncOliphaunt::open()` or `AsyncOliphaunt::builder()` for the same
-  topology vocabulary on a dedicated owner thread with cloneable asynchronous
-  handles.
-- Dedicated `OliphauntServer::builder().start()` and
-  `AsyncOliphauntServer::builder().start().await` terminals for local-server
-  lifecycle handles.
-- PostgreSQL-shaped execute, query, parameter, result, transaction,
-  cancellation, raw protocol, and close methods on database handles.
-- Only `connection_string`, `is_closed`, and `close` on server handles; an
-  external driver or ORM owns SQL and protocol behavior.
-- One byte physical-backup method on direct and broker databases.
-- One static restore operation into an absent or empty destination.
-
-Internal engine modes, runtime profiles, lifecycle requests, backup envelopes,
-resource manifests, package reports, and protocol parsers are not public API.
-Database and server builders are distinct, so listener/server options cannot be
-combined with direct/broker options. Within the database builder,
-`broker_executable` is valid only after selecting `broker()`.
-
-## Runtime ownership
-
-Direct mode owns one embedded PostgreSQL backend in the application process.
-Broker mode owns the same backend in one authenticated helper process. These
-are database topologies, not scheduling modes. Root `Oliphaunt` handles block
-until either session completes; `AsyncOliphaunt` serializes either session on
-one owner thread.
-
-Server mode starts a normal local PostgreSQL server and returns
-`OliphauntServer` with a nonoptional libpq connection string. Startup readiness
-uses a short-lived probe; the lifecycle handle retains no privileged PostgreSQL
-connection. It is the only product that supports independent external client
-connections. Its handle has no physical-backup method because PostgreSQL already provides
-`pg_basebackup`; the optional endpoint-oriented `oliphaunt-tools` crate runs
-plain `pg_dump` and non-interactive `psql` without entering the core SDK API.
-
-The engine traits, C symbols, broker frames, server wire client, and artifact
-materialization helpers are crate-internal. The only `#[doc(hidden)]` exports are
-narrow cross-crate boundaries consumed by the unpublished broker and packaging
-tools.
-
-## Execution and transactions
-
-The root API is synchronous: its operations take `&mut self` and block the
-calling thread until the selected runtime reports completion. It does not add
-an SDK owner queue. Native direct mode nevertheless runs the embedded backend
-on `liboliphaunt`'s internal pthread; broker and server keep their own process
-or server boundaries. The contract is therefore caller blocking, not
-caller-thread PostgreSQL execution. The handle is `Send + !Sync`, so ownership
-may move between threads but references cannot be shared concurrently. A
-callback transaction exclusively borrows the database. Inline raw-stream
-callbacks may borrow caller state and cannot reenter the database through safe
-Rust while its mutable borrow is active.
-
-A broker handle owns exactly one helper-backed PostgreSQL session. Helper exit
-or IPC failure is terminal for that handle and retains the first failure; no
-runtime path launches a replacement beneath it. Explicit close cleans owned
-resources, and a new open on persistent storage is the only recovery boundary.
-Requests with unknown outcomes are never replayed.
-
-The `AsyncOliphaunt` API constructs and calls its session on one permanent
-SDK-owned thread. A session is never opened on a temporary thread and then
-transferred. Cloneable `Send + Sync` handles share that owner; cloning does not
-create a PostgreSQL connection. The public name describes its calling contract;
-the owner thread is an implementation placement guarantee, not a Rust
-`Worker` abstraction.
-
-Asynchronous application work awaits fair, bounded admission before entering
-one FIFO. Saturation suspends the admitting future rather than returning a
-queue-full error. Transaction control, rollback cleanup, and close enter the
-same FIFO without consuming ordinary capacity, so queue pressure cannot strand
-lifecycle work and cannot reorder cleanup ahead of an already-admitted COMMIT.
-Close and command admission share one lock: work
-admitted before the close cutoff remains ahead of Close and drains, while later
-application work, including capacity waiters that never entered the FIFO, is
-rejected. A rejected pre-cutoff waiter cannot cross a retryable close attempt
-after admission reopens. The closing state is never used to invalidate a
-command that is already in the FIFO. If a queued `BEGIN` succeeds before Close,
-the owner rejects that close attempt with `TransactionActive`, restores open
-admission, and retains the session for retry. If an operation future is dropped
-before the owner starts it, the command is skipped. Once PostgreSQL execution
-starts, dropping the future is not cancellation and the owner completes through
-its readiness boundary. Required `COMMIT` and `ROLLBACK` settlement for a pin
-created by a pre-cutoff `BEGIN` remains admissible after the cutoff through a
-reserved, reentrancy-checked path and retains FIFO order with Close.
-
-A transaction pin rejects unrelated work while its callback is active. Body
-failure rolls back. A failed rollback poisons the session. COMMIT uncertainty
-never triggers a later ROLLBACK because PostgreSQL may already have committed;
-the session is poisoned unless PostgreSQL explicitly returns the known idle
-`ROLLBACK` command tag. Pin cleanup remains admissible after poisoning so close
-cannot strand the owner thread.
-
-A root transaction callback panic is contained until synchronous settlement
-completes and is then resumed when the outcome is known. An async transaction
-body panic unwinds the awaiting task immediately. Dropping its active
-transaction enqueues best-effort rollback in the same owner FIFO, so later work
-cannot overtake cleanup even though the unwind does not wait for it.
-
-Cancellation is out of band: the C cancellation hook in direct mode and a
-separate authenticated endpoint in broker mode. External clients of server
-mode own PostgreSQL CancelRequest through their driver. Root database callers
-obtain a separate `CancelHandle` before blocking when
-another thread must interrupt the operation. Asynchronous cancellation is
-asynchronous and does not wait in the ordinary FIFO. Close does not implicitly
-cancel active work. Root close is synchronous; async close is an ordered queue
-boundary with shared concurrent waiters. Once direct detach, broker shutdown,
-or server shutdown begins, either handle is terminal and retains one exact
-close result. A failed teardown is never followed by a second implicit teardown.
-Session and managed-root ownership is released only after successful teardown.
-On failure the SDK intentionally retains that ownership until process exit;
-leaking the failed owner is safer than running an unproven second destructor.
-Final asynchronous-handle `Drop` requests cleanup without joining the owner
-thread.
-
-Every asynchronous reply channel turns sender disappearance into
-`EngineStopped`; an owner panic therefore cannot strand callers. Runtime panics
-stop the owner and reject pending work. Raw-stream callback panics are contained
-before any C boundary. A typed adapter outcome distinguishes confirmed
-`ReadyForQuery` recovery from an independent runtime or transport failure. The
-blocking root resumes the original panic only after confirmed recovery; the
-async API returns a recovered owner-thread panic as
-`RawStreamError::CallbackPanicked` and leaves the session reusable. An
-unconfirmed recovery failure is authoritative, becomes
-`RawStreamError::Database`, and poisons the session until close. Callbacks are
-synchronous owner-thread code, so reentrant work on the same async handle is
-rejected rather than deadlocking. Root callbacks run inline and rely on the
-exclusive borrow instead of runtime reentrancy detection.
-
-## Storage and identity
-
-Public storage is either a caller-owned directory or an SDK-owned temporary
-directory. A persistent directory contains an outer `.oliphaunt.json`
-descriptor and `pgdata/`.
-
-Root validation is shared in contract, not by pretending all host filesystems
-are one implementation. The native adapter rejects symlink roots and symlink
-structural directories, validates PostgreSQL 18 PGDATA, and writes the exact
-five-field descriptor last. A sibling admission lock prevents multiple
-supported native owners from opening the same root. The lock is an internal
-lifecycle implementation detail, not a public cross-binding coordination mode.
-
-The descriptor records schema, engine family, PGDATA directory name,
-PostgreSQL major, and physical format. A valid native or WASIX family/format
-pair is accepted. Cross-family rejection and conversion are not part of root
-admission.
-
-Direct and broker backup bytes carry a PostgreSQL physical initialization
-payload. They do not carry the outer descriptor. Restore stages and validates
-PGDATA, then creates the receiving root identity. Existing nonempty destinations
-are rejected; there is no replacement option.
-
-## Artifacts and extensions
-
-Build and release tooling stages the runtime, PostgreSQL tools, templates, and
-selected extension artifacts. The SDK selects extensions by exact generated SQL
-name and passes only runtime-relevant selection into root preparation.
-
-Runtime materialization maintains two internal layouts where PostgreSQL requires
-them: embedded modules for direct/broker and standalone server modules. This is
-natural implementation separation, not a public capability profile.
-
-Performance profiles and diagnostic knobs belong to the perf harness. They must
-not leak into the SDK unless a concrete application need establishes a stable
-public contract.
diff --git a/src/sdks/rust/CHANGELOG.md b/src/sdks/rust/CHANGELOG.md
deleted file mode 100644
index f7132fd93..000000000
--- a/src/sdks/rust/CHANGELOG.md
+++ /dev/null
@@ -1,118 +0,0 @@
-# Changelog
-
-## Unreleased
-
-- **Breaking:** make root `Oliphaunt` the synchronous, exclusive database API
-  for direct and broker topologies, with a separate synchronous
-  `OliphauntServer` lifecycle handle. Calls block until completion without an
-  SDK owner-queue hop; native direct PostgreSQL still uses `liboliphaunt`'s
-  internal backend thread.
-- **Migration from 0.1.1:** the previously asynchronous root
-  `oliphaunt::Oliphaunt` is now `oliphaunt::AsyncOliphaunt`. Rename that type
-  (and its `AsyncOliphauntBuilder`, `AsyncOliphauntServer`, `AsyncSql`, and
-  `AsyncTransaction` companions where named) and keep the existing `.await`
-  calls. Use the new root `Oliphaunt` only when a blocking API is intended.
-- Expose the cloneable asynchronous owner-thread API through named root
-  `Async*` types; there is no public Rust `worker` namespace.
-- Add default `Oliphaunt::open()` and `AsyncOliphaunt::open()` terminals and
-  dedicated cloneable `OliphauntServerBuilder` / `AsyncOliphauntServerBuilder`
-  terminals ending in `start()`.
-- Add a thread-safe root `CancelHandle` so another thread can interrupt a
-  synchronous operation without making the database handle shareable.
-- Keep async restore and cancellation asynchronous, apply fair awaitable
-  backpressure to ordinary owner work while reserving FIFO lifecycle admission,
-  and make explicit close coalesced, phase-aware, and definitive. Capacity
-  waiters that miss a close cutoff remain rejected even if that close is
-  retryable. Root restore and close execute synchronously.
-- Prevent owner failures and dropped reply senders from stranding futures;
-  contain raw-stream callback panics and reject callback reentrancy. Typed
-  direct and broker stream outcomes now resume a blocking callback
-  panic only after confirmed `ReadyForQuery`; independent recovery failure is
-  authoritative and poisons the session.
-- **Breaking:** accept typed transaction and raw-stream callback errors. Callback
-  transactions now return `TransactionResult` / `TransactionError`;
-  streams accept `()` or `Result<(), E>` and return `RawStreamError`. Literal
-  rollback failure, independent database failure, recovered callback abort, and
-  recovered async callback panic remain distinct public outcomes.
-- **Breaking:** remove raw protocol methods from managed transaction handles;
-  arbitrary protocol bytes cannot preserve the SDK-owned transaction boundary.
-  Root database raw APIs remain available to protocol adapters which own their
-  complete lifecycle. Structured callback-transaction methods reject
-  `ROLLBACK`/`ABORT ... AND CHAIN` before dispatch while preserving savepoints
-  and `ROLLBACK TO`.
-- **Breaking:** make server handles endpoint/lifecycle-only. Use
-  `connection_string()` with a PostgreSQL driver or ORM for SQL, transactions,
-  cancellation, and raw protocol; server handles retain only `is_closed()` and
-  `close()`.
-- Validate an explicit native server executable before preparing persistent
-  storage, so a deterministic path error cannot initialize or alter PGDATA.
-- **Breaking:** make `Error` opaque and expose the shared non-exhaustive
-  `ErrorKind` recovery categories plus typed PostgreSQL and transaction-cause
-  accessors. `Error` no longer promises equality or destructuring stability.
-- **Breaking:** make `Extension` an opaque selector with uppercase associated
-  constants, `Extension::ALL`, `Extension::by_sql_name`, and `sql_name`; remove
-  the old free constants and PascalCase aliases. Selecting an artifact never
-  installs database-local extension objects.
-- **Breaking:** remove the redundant `QueryParam` wrapper. Use natural
-  `IntoParameter` values or `Parameter::{text,binary,null}` for dynamically
-  typed values. Execution rejects an explicitly attached OID 0; leave the OID
-  unset for execution-time inference, while `describe` continues to accept 0.
-  Multi-statement `exec` now retains each notice on its statement result as
-  well as in the operation-wide ordered notice list.
-- Keep required transaction settlement admissible across an ordered close
-  cutoff, and make every teardown-started close result terminal and replayable
-  to concurrent or repeated callers. Pin-release failures are never discarded,
-  poison lifecycle state, and failed teardown retains root ownership until
-  process exit rather than invoking a second destructor.
-- Keep out-of-band cancellation admissible while pre-cutoff SQL drains, with an
-  atomic rejection boundary at destructive teardown.
-- Split database and server builders so cross-topology options are
-  unrepresentable; `broker_executable` is still rejected unless `broker()` is
-  selected.
-- Snapshot each ABI 10 native operation error through its same-call
-  `*_with_error` capture; synchronous cancellation alone uses
-  `oliphaunt_copy_last_error` because the C ABI has no cancel capture variant.
-- Fail native broker handles permanently after helper exit or IPC failure.
-  Recovery now requires an explicit close and new open; the SDK never replaces
-  a session invisibly or replays work with an uncertain outcome.
-
-## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-rust-v0.1.1...oliphaunt-rust-v0.2.0) (2026-09-05)
-
-
-### ⚠ BREAKING CHANGES
-
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
-
-### Features
-
-* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))
-* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
-
-
-### Bug Fixes
-
-* **ci:** preserve native lifecycle server sessions ([#165](https://github.com/f0rr0/oliphaunt/issues/165)) ([b8cab0b](https://github.com/f0rr0/oliphaunt/commit/b8cab0be2b86c6b9fab4c279add89113c5797d23))
-
-
-### Code Refactoring
-
-* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
-* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
-* **release:** publish frozen candidates ([#181](https://github.com/f0rr0/oliphaunt/issues/181)) ([327b3fc](https://github.com/f0rr0/oliphaunt/commit/327b3fc7caf272b1dbbc355c687a3db34ccc96ac))
-* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
-
-## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-rust-v0.1.0...oliphaunt-rust-v0.1.1) (2026-08-08)
-
-
-### Bug Fixes
-
-* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))
-
-## 0.1.0 (2026-07-28)
-
-
-### Features
-
-* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/sdks/rust/Cargo.toml b/src/sdks/rust/Cargo.toml
deleted file mode 100644
index b6e4258b9..000000000
--- a/src/sdks/rust/Cargo.toml
+++ /dev/null
@@ -1,44 +0,0 @@
-[package]
-name = "oliphaunt"
-version = "0.2.0"
-edition = "2024"
-rust-version = "1.93"
-description = "Native-first Rust SDK surface for embedded PostgreSQL through liboliphaunt."
-readme = "README.md"
-repository.workspace = true
-homepage.workspace = true
-license = "MIT"
-exclude = [
-  ".gitignore",
-  "crates/oliphaunt-build/**",
-  "moon.yml",
-  "release.toml",
-  "tools/**",
-]
-links = "oliphaunt_artifact_relay"
-build = "build.rs"
-
-[lib]
-name = "oliphaunt"
-path = "src/lib.rs"
-
-[features]
-default = []
-__internal-broker-helper = []
-internal-native-packaging = []
-
-[package.metadata.oliphaunt]
-broker-helper = "oliphaunt-broker"
-broker-version = "0.2.0"
-native-version = "0.2.0"
-
-[dependencies]
-fs2 = "0.4"
-getrandom = "0.3"
-libloading = "0.8"
-serde = { version = "1", features = ["derive"] }
-serde_json = "1"
-sha2 = "0.10"
-
-[dev-dependencies]
-tokio = { version = "1", features = ["rt", "time"] }
diff --git a/src/sdks/rust/README.md b/src/sdks/rust/README.md
deleted file mode 100644
index 0a9baa4f5..000000000
--- a/src/sdks/rust/README.md
+++ /dev/null
@@ -1,300 +0,0 @@
-# Oliphaunt Rust SDK
-
-`oliphaunt` embeds PostgreSQL 18 through the native `liboliphaunt` runtime. The
-public API is intentionally small and PostgreSQL-shaped: open, execute, query,
-exec, describe, transaction, cancel, physical backup, restore, and
-close. Dedicated server handles expose only endpoint and lifecycle state; use a
-PostgreSQL driver or ORM through their connection string.
-
-## Installation
-
-Add `oliphaunt` and use `oliphaunt-build` from the build script so the matching
-native runtime, tools, and selected extension artifacts are staged for the
-target platform.
-
-```rust
-fn main() {
-    oliphaunt_build::configure();
-}
-```
-
-## Execution placement and database topology
-
-Direct mode is the default. It runs the embedded backend in the application
-process. Broker mode uses the same database API while placing that backend in a
-helper process.
-
-The root API is synchronous and caller owned. `open`, SQL, backup, restore, and
-close block the calling thread until their result is available. They do not
-cross an SDK owner queue, but that is not a promise that PostgreSQL itself runs
-on the caller: native direct mode uses `liboliphaunt`'s internal backend thread,
-while broker and server topologies own their documented process or server
-boundaries. Synchronous database and server handles are exclusive,
-`Send + !Sync`, so ownership may move between threads but the same owner cannot
-be shared concurrently. This is the minimum-overhead path for CLIs, tests,
-dedicated application threads, and callers which already control scheduling.
-
-`Oliphaunt::open()` is the shortest default: it opens direct mode with an
-SDK-owned temporary directory. `AsyncOliphaunt::open().await` does the same on
-the async owner thread. Use the cloneable builders when configuration differs.
-
-```rust
-use oliphaunt::{DatabaseStorage, Oliphaunt};
-
-# fn example() -> oliphaunt::Result<()> {
-let mut db = Oliphaunt::builder()
-    .storage(DatabaseStorage::Directory(".oliphaunt".into()))
-    .startup_guc("application_name", "my-app")
-    .open()?;
-
-db.execute_with_params(
-    "INSERT INTO events(value) VALUES ($1)",
-    ["ready"],
-)?;
-let result = db.query("SELECT value FROM events")?;
-assert_eq!(result.get_text(0, "value")?, Some("ready"));
-db.close()?;
-# Ok(())
-# }
-```
-
-Use the named asynchronous handle when the calling executor must remain
-responsive:
-
-```rust
-use oliphaunt::AsyncOliphaunt;
-
-# async fn example() -> oliphaunt::Result<()> {
-let db = AsyncOliphaunt::open().await?;
-let rows = db.query("SELECT 42::int4 AS answer").await?;
-assert_eq!(rows.get_text(0, "answer")?, Some("42"));
-db.close().await?;
-# Ok(())
-# }
-```
-
-`AsyncOliphaunt` and `AsyncOliphauntServer` are cloneable and `Send + Sync`.
-Open constructs the selected topology on a permanent SDK-owned thread. Ordinary
-calls await fair, bounded admission before entering one owner FIFO; saturation
-applies async backpressure instead of blocking the executor or returning a
-queue-full error. Blocking runtime work occupies the owner, not the executor
-thread polling the future. Rust futures do not imply a thread by themselves;
-this placement is an explicit Oliphaunt guarantee. Dropping a pending future is
-not query cancellation.
-
-Select broker mode with `.broker()`. An explicit
-`.broker_executable(path)` is normally only needed by development and packaging
-harnesses; installed packages resolve their helper artifact automatically.
-If the helper exits or IPC fails, the database handle permanently rejects later
-work. Close it and explicitly open a new handle on the same persistent root for
-PostgreSQL WAL recovery; the SDK never substitutes a fresh session or replays an
-uncertain request under the old handle.
-The database builder represents only direct and broker databases;
-`broker_executable` requires `broker().open()`. Local servers have a dedicated
-`OliphauntServer::builder()` / `AsyncOliphauntServer::builder()` ending in
-`start()`, so server-only and database-only options cannot be mixed.
-
-`execute` and `execute_with_params` assert one command with no rows. `query` and
-`query_with_params` accept a command-only or row-producing statement and return
-ordered raw cells, complete field metadata, command metadata, notices, and
-typed access through `FromSql`. `exec` returns ordered command-or-rows results
-for simple-query SQL, while `describe` resolves parameter OIDs and optional
-result fields without executing. Call `db.describe(sql)` for an unparameterized
-statement, or `db.sql(sql).bind(...).describe()` when PostgreSQL needs explicit
-parameter values or type OIDs.
-
-Natural Rust values passed to `bind` or the `*_with_params` methods use
-`IntoParameter` and carry their PostgreSQL type OID and preferred encoding.
-`Parameter` provides explicit `TypeOid`, `ValueFormat`, and nullable owned
-bytes for typed nulls and extension types. Its `text`, `binary`, and `null`
-constructors deliberately leave the OID unspecified for PostgreSQL to infer.
-An absent OID is the single execution spelling for inference. `describe` also
-accepts explicit OID 0 because it is PostgreSQL's wire-level inference sentinel.
-Typed
-getters validate OID and format, reject ambiguous duplicate names, and preserve
-raw access as the lossless fallback. SQL errors are structured `PostgresError`
-values with operation notices. The public `Error` is opaque and cloneable;
-match its non-exhaustive `ErrorKind` through `kind()` and use typed accessors
-for PostgreSQL and paired transaction failures instead of destructuring or
-comparing implementation errors.
-
-`is_closed()` reports that the database handle is terminally retired.
-The synchronous `transaction` exclusively borrows its database; the async
-variant pins its one physical session and rejects unrelated clone work. Both
-transaction handles mirror query, execute, exec, and describe. One-shot
-`rollback()` closes the transaction and lets its callback return without
-committing. A failed rollback or uncertain COMMIT poisons the database and does
-not issue a misleading second control command.
-
-Transaction callbacks return ordinary `Result` with `E: From`.
-Database calls therefore use `?`, while a business rule can return its own
-concrete error. The outer `TransactionResult` reports `TransactionError`:
-`CallbackAndRollback` means rollback was actually attempted and failed;
-`CallbackAndDatabase` means an independent database, transport, or recovery
-failure had already expired the transaction and no rollback was sent. SDK-only
-callbacks keep the concise `oliphaunt::Result` call shape through `From`
-conversions.
-
-Managed transaction handles expose structured SQL, not raw protocol. Return an
-error from the callback or call `Transaction::rollback()` instead of issuing
-`BEGIN`, `COMMIT`, full `ROLLBACK`, or prepared-transaction control as SQL.
-Savepoints and `ROLLBACK TO SAVEPOINT` remain valid. Manual lifecycle SQL,
-including `AND CHAIN`, is unsupported; a protocol response that proves
-ownership escaped makes the database close-only. Protocol adapters that own the
-entire lifecycle can use the raw APIs on the root database handle.
-
-Synchronous `close()` blocks through teardown and replays its first terminal
-result. Asynchronous `close().await` is an ordered queue boundary: operations
-already in the owner FIFO drain, including an admitted `BEGIN`, while capacity
-waiters and later work are rejected.
-Once either variant begins runtime teardown, the handle is terminal even if
-teardown reports an error. Successful teardown releases the session and its
-managed-root ownership. A failed teardown intentionally retains that ownership
-until process exit so no implicit destructor can repeat an unproven destructive
-cleanup.
-
-For COPY or another protocol flow that the structured helpers cannot represent,
-use `exec_protocol_raw` for one owned response or
-`exec_protocol_raw_stream` to consume backend protocol chunks as they arrive.
-The stream is the raw PostgreSQL protocol; the SDK does not publish a second
-parser or a separate COPY-specific abstraction. Synchronous callbacks execute
-inline and may borrow caller state. Asynchronous callbacks execute serially on
-the owner thread and therefore require `Send + 'static`. In both cases the
-borrowed chunk is valid only until the callback returns, slow callbacks apply
-backpressure, and callback panics are contained before crossing the native ABI.
-Return `()` for infallible delivery without type annotations, or
-`Result<(), E>` for a typed parser/application stop. `RawStreamError::Callback`
-is produced only after confirmed recovery.
-The synchronous API resumes the original panic only after its adapter confirms
-`ReadyForQuery`; the async API returns a recovered owner-thread panic as
-`RawStreamError::CallbackPanicked` and leaves the session reusable. If transport
-or runtime recovery fails independently, `RawStreamError::Database` takes
-precedence and the session rejects further work until close.
-
-`AsyncOliphaunt::cancel().await` sends cancellation out of band. For the
-synchronous root, obtain `db.cancel_handle()` before a long call and move that
-cloneable, thread-safe capability to the thread which may interrupt it. Calling
-`cancel()` on the database itself is immediate but cannot interrupt code already
-blocking the same thread. Cancellation never replaces observing the original
-operation, which reports PostgreSQL's final result.
-
-## Physical backup and restore
-
-Direct and broker databases expose one physical backup format as bytes. Restore
-is a static operation into an absent or empty destination. It never overwrites
-an existing managed database.
-
-```rust
-use oliphaunt::{DatabaseStorage, Oliphaunt};
-
-# fn example() -> oliphaunt::Result<()> {
-let mut source = Oliphaunt::builder()
-    .storage(DatabaseStorage::Directory(".oliphaunt-source".into()))
-    .open()?;
-let backup = source.backup()?;
-source.close()?;
-
-Oliphaunt::restore(".oliphaunt-restored", backup)?;
-# Ok(())
-# }
-```
-
-The archive is a PostgreSQL physical initialization payload. It contains
-PGDATA and its backup metadata, not the outer managed-root descriptor. Restore
-creates and validates the receiving root and publishes `.oliphaunt.json` only
-after complete PGDATA exists. Root restore blocks synchronously;
-`AsyncOliphaunt::restore` copies its input and moves native and filesystem work
-to a dedicated thread.
-
-## Local server
-
-`OliphauntServer::builder().start()` returns a lifecycle handle with a
-nonoptional libpq connection string for standard PostgreSQL clients. The handle
-deliberately does not hide a privileged SDK query session: SQL, transactions,
-pools, cancellation, and raw protocol are owned by the external driver or ORM.
-Its stable surface is `connection_string()`, `is_closed()`, and `close()`.
-`is_closed()` reports SDK lifecycle state only; it does not poll the PostgreSQL
-child or guarantee that the endpoint is currently reachable. Use the ordinary
-driver or pool connected to `connection_string()` for connection health.
-
-The default listener is IPv4 loopback with an automatically assigned port.
-Select a fixed loopback port or, on Unix hosts, a PostgreSQL socket directory.
-Unix socket directories must resolve to valid UTF-8 so the returned connection
-string preserves the exact path for Rust drivers and ORMs:
-
-```rust,no_run
-use oliphaunt::{OliphauntServer, ServerListen};
-
-# fn open() -> oliphaunt::Result<()> {
-let mut server = OliphauntServer::builder()
-    .listen(ServerListen::tcp_port(15432))
-    .start()?;
-println!("{}", server.connection_string());
-server.close()?;
-# Ok(())
-# }
-```
-
-The dedicated server builder has no `.direct()` or `.broker()` selector and
-the database builders have no listener options. The split makes invalid
-cross-topology configuration unrepresentable.
-
-The server handle deliberately has no SDK backup method. Use `pg_basebackup`
-for a standard server physical backup. The optional `oliphaunt-tools` crate
-provides endpoint-oriented plain `pg_dump` and non-interactive `psql` runners;
-the core `oliphaunt` crate does not depend on or install client tools.
-
-```rust,no_run
-use oliphaunt_tools::{PgDumpOptions, pg_dump};
-
-# fn dump(connection_string: &str) -> Result {
-pg_dump(connection_string, PgDumpOptions::new().arg("--schema-only"))
-# }
-```
-
-Pass `server.connection_string()` to the standard tool and keep PostgreSQL's
-streamed-WAL behavior explicit:
-
-```sh
-pg_basebackup --dbname "$CONNECTION_STRING" --pgdata ./server-backup --wal-method=stream
-```
-
-## Storage ownership
-
-A persistent database is a managed root:
-
-```text
-.oliphaunt.json
-pgdata/
-```
-
-The descriptor has one exact five-field schema: schema name, engine family,
-PGDATA directory name, PostgreSQL major, and physical format. It describes the
-root layout; it is not a lock file and it does not encode an SDK or host
-language. Native and WASIX descriptors are both valid when family and format
-form one of the two defined pairs.
-
-Opening validates before mutating. Existing roots must have PostgreSQL 18
-`PG_VERSION`, a real `global` directory with nonempty `global/pg_control`, and a
-real `pg_wal` directory. Symlink roots and symlink structural directories are
-rejected. The descriptor is written last during initialization.
-
-The SDK prevents two supported owners from opening the same managed root at the
-same time by using a sibling admission lock. It does not add a public cross-SDK
-coordination protocol, and concurrent mutation by unrelated runtimes remains
-application error.
-
-## Extensions and platform support
-
-Choose extensions with `.extension(Extension::...)` or `.extensions(...)`.
-Selection uses exact PostgreSQL SQL names and the generated PostgreSQL 18
-catalog. `Extension` is an opaque `Copy + Eq + Hash + Ord` selector with
-uppercase associated constants, `ALL`, `by_sql_name`, and `sql_name`. Selection
-makes artifacts and required pre-start configuration available but never runs
-`CREATE EXTENSION`, `LOAD`, or migration SQL. Build and release tooling owns
-artifact resolution; the runtime API does not expose package manifests, size
-reports, capability profiles, or packaging internals.
-
-Supported native products and targets are declared by the repository SDK
-manifest and release packages. WASIX is a separate binding family and is not a
-fallback mode of this crate.
diff --git a/src/sdks/rust/build.rs b/src/sdks/rust/build.rs
deleted file mode 100644
index 15f0e873e..000000000
--- a/src/sdks/rust/build.rs
+++ /dev/null
@@ -1,276 +0,0 @@
-use std::collections::BTreeMap;
-use std::env;
-use std::fs;
-use std::path::{Path, PathBuf};
-
-const ARTIFACT_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_";
-const ARTIFACT_ENV_SUFFIX: &str = "_MANIFEST";
-const RELAY_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_RELAY_";
-const QUERY_CORE_ENV: &str = "OLIPHAUNT_QUERY_CORE_RS";
-const QUERY_CORE_OUTPUT: &str = "query_core.rs";
-const PACKAGED_QUERY_CORE: &str = "src/query_core.rs";
-const CHECKOUT_QUERY_CORE: &str = "../../shared/rust-query-core/query_core.rs";
-
-fn main() {
-    match build_instructions(env::vars()) {
-        Ok(instructions) => {
-            for instruction in instructions {
-                println!("{instruction}");
-            }
-        }
-        Err(error) => {
-            println!("cargo::error={error}");
-            panic!("oliphaunt artifact relay failed: {error}");
-        }
-    }
-}
-
-fn build_instructions(vars: I) -> Result, String>
-where
-    I: IntoIterator,
-{
-    let vars = vars.into_iter().collect::>();
-    let manifest_dir = required_path(&vars, "CARGO_MANIFEST_DIR")?;
-    let out_dir = required_path(&vars, "OUT_DIR")?;
-    let mut instructions = relay_manifest_instructions(vars)?;
-    instructions.extend(stage_query_core(&manifest_dir, &out_dir)?);
-    Ok(instructions)
-}
-
-fn required_path(vars: &BTreeMap, name: &str) -> Result {
-    vars.get(name)
-        .filter(|value| !value.is_empty())
-        .map(PathBuf::from)
-        .ok_or_else(|| format!("Cargo did not provide {name}"))
-}
-
-fn stage_query_core(manifest_dir: &Path, out_dir: &Path) -> Result, String> {
-    let packaged = manifest_dir.join(PACKAGED_QUERY_CORE);
-    let checkout = manifest_dir.join(CHECKOUT_QUERY_CORE);
-    let packaged_exists = packaged.is_file();
-    let checkout_exists = checkout.is_file();
-    let source = match (packaged_exists, checkout_exists) {
-        (true, true) => {
-            let packaged_bytes = fs::read(&packaged).map_err(|error| {
-                format!(
-                    "read packaged Rust query core {}: {error}",
-                    packaged.display()
-                )
-            })?;
-            let checkout_bytes = fs::read(&checkout).map_err(|error| {
-                format!(
-                    "read canonical Rust query core {}: {error}",
-                    checkout.display()
-                )
-            })?;
-            if packaged_bytes != checkout_bytes {
-                return Err(format!(
-                    "packaged Rust query core {} is stale relative to {}",
-                    packaged.display(),
-                    checkout.display()
-                ));
-            }
-            packaged.as_path()
-        }
-        (true, false) => packaged.as_path(),
-        (false, true) => checkout.as_path(),
-        (false, false) => {
-            return Err(format!(
-                "missing canonical Rust query core; checked {} and {}",
-                packaged.display(),
-                checkout.display()
-            ));
-        }
-    };
-    let source = fs::canonicalize(source)
-        .map_err(|error| format!("resolve Rust query core {}: {error}", source.display()))?;
-    let output = out_dir.join(QUERY_CORE_OUTPUT);
-    fs::copy(&source, &output).map_err(|error| {
-        format!(
-            "stage Rust query core {} at {}: {error}",
-            source.display(),
-            output.display()
-        )
-    })?;
-    let mut instructions = [(&packaged, packaged_exists), (&checkout, checkout_exists)]
-        .into_iter()
-        .filter(|(_, exists)| *exists)
-        .map(|(candidate, _)| {
-            fs::canonicalize(candidate)
-                .map(|candidate| format!("cargo::rerun-if-changed={}", candidate.display()))
-                .map_err(|error| {
-                    format!(
-                        "resolve watched Rust query core {}: {error}",
-                        candidate.display()
-                    )
-                })
-        })
-        .collect::, _>>()?;
-    instructions.push(format!(
-        "cargo::rustc-env={QUERY_CORE_ENV}={}",
-        output.display()
-    ));
-    Ok(instructions)
-}
-
-fn relay_manifest_instructions(vars: I) -> Result, String>
-where
-    I: IntoIterator,
-{
-    let mut manifests = BTreeMap::new();
-    let mut instructions = Vec::new();
-    for (key, value) in vars {
-        let Some(metadata_key) = relay_metadata_key(&key) else {
-            continue;
-        };
-        if value.is_empty() {
-            continue;
-        }
-        if let Some(existing) = manifests.insert(metadata_key.clone(), value.clone())
-            && existing != value
-        {
-            return Err(format!(
-                "conflicting Cargo artifact manifests for metadata key {metadata_key}: {existing} and {value}"
-            ));
-        }
-        instructions.push(format!("cargo::rerun-if-changed={value}"));
-    }
-    for (metadata_key, manifest) in manifests {
-        instructions.push(format!("cargo::metadata={metadata_key}={manifest}"));
-    }
-    Ok(instructions)
-}
-
-fn relay_metadata_key(env_key: &str) -> Option {
-    if env_key.starts_with(RELAY_ENV_PREFIX) {
-        return None;
-    }
-    let stem = env_key
-        .strip_prefix(ARTIFACT_ENV_PREFIX)?
-        .strip_suffix(ARTIFACT_ENV_SUFFIX)?;
-    if stem.is_empty() {
-        return None;
-    }
-    Some(format!("{}_manifest", stem.to_ascii_lowercase()))
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn query_core_fixture() -> (PathBuf, PathBuf, PathBuf) {
-        let root = std::env::temp_dir().join(format!(
-            "oliphaunt-native-query-core-{}-{}",
-            std::process::id(),
-            std::time::SystemTime::now()
-                .duration_since(std::time::UNIX_EPOCH)
-                .unwrap()
-                .as_nanos()
-        ));
-        let manifest = root.join("src/sdks/rust");
-        let canonical = root.join("src/shared/rust-query-core/query_core.rs");
-        let out = root.join("out");
-        fs::create_dir_all(canonical.parent().unwrap()).unwrap();
-        fs::create_dir_all(manifest.join("src")).unwrap();
-        fs::create_dir_all(&out).unwrap();
-        fs::write(&canonical, b"canonical query core\n").unwrap();
-        (root, manifest, out)
-    }
-
-    #[test]
-    fn ignores_unrelated_and_empty_vars() {
-        let instructions = relay_manifest_instructions([
-            ("TARGET".to_owned(), "x86_64-unknown-linux-gnu".to_owned()),
-            (
-                "DEP_OLIPHAUNT_ARTIFACT_BROKER_LINUX_X64_GNU_MANIFEST".to_owned(),
-                String::new(),
-            ),
-        ])
-        .unwrap();
-        assert!(instructions.is_empty());
-    }
-
-    #[test]
-    fn re_emits_multiple_artifact_manifests() {
-        let instructions = relay_manifest_instructions([
-            (
-                "DEP_OLIPHAUNT_ARTIFACT_BROKER_LINUX_X64_GNU_MANIFEST".to_owned(),
-                "/tmp/broker.toml".to_owned(),
-            ),
-            (
-                "DEP_OLIPHAUNT_ARTIFACT_NATIVE_LINUX_X64_GNU_MANIFEST".to_owned(),
-                "/tmp/native.toml".to_owned(),
-            ),
-        ])
-        .unwrap();
-        assert!(instructions.contains(&"cargo::rerun-if-changed=/tmp/broker.toml".to_owned()));
-        assert!(instructions.contains(
-            &"cargo::metadata=broker_linux_x64_gnu_manifest=/tmp/broker.toml".to_owned()
-        ));
-        assert!(instructions.contains(
-            &"cargo::metadata=native_linux_x64_gnu_manifest=/tmp/native.toml".to_owned()
-        ));
-    }
-
-    #[test]
-    fn does_not_relay_its_own_downstream_metadata() {
-        let instructions = relay_manifest_instructions([(
-            "DEP_OLIPHAUNT_ARTIFACT_RELAY_BROKER_HELPER_MANIFEST".to_owned(),
-            "/tmp/broker.toml".to_owned(),
-        )])
-        .unwrap();
-        assert!(instructions.is_empty());
-    }
-
-    #[test]
-    fn rejects_conflicting_duplicate_keys() {
-        let error = relay_manifest_instructions([
-            (
-                "DEP_OLIPHAUNT_ARTIFACT_BROKER_MANIFEST".to_owned(),
-                "/tmp/one.toml".to_owned(),
-            ),
-            (
-                "DEP_OLIPHAUNT_ARTIFACT_BROKER_MANIFEST".to_owned(),
-                "/tmp/two.toml".to_owned(),
-            ),
-        ])
-        .expect_err("conflicting duplicate metadata keys must fail");
-        assert!(error.contains("conflicting Cargo artifact manifests"));
-    }
-
-    #[test]
-    fn stages_checkout_query_core_and_rejects_a_stale_packaged_copy() {
-        let (root, manifest, out) = query_core_fixture();
-        let instructions = stage_query_core(&manifest, &out).unwrap();
-        assert_eq!(
-            fs::read(out.join(QUERY_CORE_OUTPUT)).unwrap(),
-            b"canonical query core\n"
-        );
-        assert!(
-            instructions
-                .iter()
-                .any(|line| line.starts_with("cargo::rerun-if-changed="))
-        );
-        assert!(
-            instructions
-                .iter()
-                .any(|line| line.starts_with(&format!("cargo::rustc-env={QUERY_CORE_ENV}=")))
-        );
-
-        let packaged = manifest.join(PACKAGED_QUERY_CORE);
-        let checkout = manifest.join(CHECKOUT_QUERY_CORE);
-        fs::write(&packaged, b"canonical query core\n").unwrap();
-        let instructions = stage_query_core(&manifest, &out).unwrap();
-        for candidate in [&packaged, &checkout] {
-            let candidate = fs::canonicalize(candidate).unwrap();
-            assert!(
-                instructions.contains(&format!("cargo::rerun-if-changed={}", candidate.display()))
-            );
-        }
-
-        fs::write(packaged, b"stale query core\n").unwrap();
-        let error = stage_query_core(&manifest, &out).unwrap_err();
-        assert!(error.contains("is stale relative to"));
-        fs::remove_dir_all(root).unwrap();
-    }
-}
diff --git a/src/sdks/rust/crates/oliphaunt-build/src/lib.rs b/src/sdks/rust/crates/oliphaunt-build/src/lib.rs
deleted file mode 100644
index 5a0321dda..000000000
--- a/src/sdks/rust/crates/oliphaunt-build/src/lib.rs
+++ /dev/null
@@ -1,2769 +0,0 @@
-//! Cargo build-script integration for Oliphaunt applications.
-//!
-//! `configure()` is intended to be called from an application `build.rs`.
-//! Cargo resolves target-specific artifact crates; this crate stages the
-//! already-resolved files into `OUT_DIR`.
-
-use serde::{Deserialize, Serialize};
-use sha2::{Digest, Sha256};
-use std::collections::{BTreeMap, BTreeSet};
-use std::env;
-use std::ffi::OsString;
-use std::fmt;
-use std::fs;
-use std::io;
-use std::path::{Component, Path, PathBuf};
-
-const LOCK_SCHEMA: &str = "oliphaunt-assets-lock-v1";
-const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
-const ARTIFACT_BUNDLE_SCHEMA: &str = "oliphaunt-artifact-manifest-v2";
-const ARTIFACT_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_";
-const ARTIFACT_ENV_SUFFIX: &str = "_MANIFEST";
-
-/// Run Oliphaunt build-script configuration and fail the Cargo build on error.
-pub fn configure() {
-    match try_configure() {
-        Ok(output) => {
-            for instruction in output.cargo_instructions {
-                println!("{instruction}");
-            }
-        }
-        Err(error) => {
-            println!("cargo::error={error}");
-            panic!("oliphaunt-build failed: {error}");
-        }
-    }
-}
-
-/// Run Oliphaunt build-script configuration from Cargo-provided environment.
-pub fn try_configure() -> Result {
-    BuildContext::from_env()?.configure()
-}
-
-/// Successful build-script output.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct BuildOutput {
-    pub resources_dir: PathBuf,
-    pub lock_file: PathBuf,
-    pub generated_rust: PathBuf,
-    pub cargo_instructions: Vec,
-}
-
-#[derive(Debug, Clone)]
-struct BuildContext {
-    manifest_dir: PathBuf,
-    out_dir: PathBuf,
-    target: String,
-    artifact_manifest_paths: Vec,
-}
-
-impl BuildContext {
-    fn from_env() -> Result {
-        let vars: BTreeMap = env::vars_os()
-            .filter_map(|(key, value)| key.into_string().ok().map(|key| (key, value)))
-            .collect();
-        let manifest_dir = required_path_var(&vars, "CARGO_MANIFEST_DIR")?;
-        let out_dir = required_path_var(&vars, "OUT_DIR")?;
-        let target = required_string_var(&vars, "TARGET")?;
-        let artifact_manifest_paths = vars
-            .iter()
-            .filter(|(key, value)| {
-                key.starts_with(ARTIFACT_ENV_PREFIX)
-                    && key.ends_with(ARTIFACT_ENV_SUFFIX)
-                    && !value.is_empty()
-            })
-            .map(|(_, value)| PathBuf::from(value))
-            .collect();
-        Ok(Self {
-            manifest_dir,
-            out_dir,
-            target,
-            artifact_manifest_paths,
-        })
-    }
-
-    fn configure(&self) -> Result {
-        let cargo_toml = self.manifest_dir.join("Cargo.toml");
-        let app = read_application_manifest(&cargo_toml)?;
-        let metadata = &app.package.metadata.oliphaunt;
-        let artifacts = self.read_artifact_manifests()?;
-        let selected = select_artifacts(&app, &artifacts, &self.target)?;
-
-        let root = self.out_dir.join("oliphaunt");
-        let resources_dir = root.join("resources");
-        let lock_file = root.join("oliphaunt-assets.lock");
-        let generated_rust = root.join("oliphaunt_assets.rs");
-
-        if resources_dir.exists() {
-            fs::remove_dir_all(&resources_dir).map_err(|source| {
-                Error::io(
-                    "clean stale Oliphaunt resources directory",
-                    &resources_dir,
-                    source,
-                )
-            })?;
-        }
-        fs::create_dir_all(&resources_dir).map_err(|source| {
-            Error::io(
-                "create Oliphaunt resources directory",
-                &resources_dir,
-                source,
-            )
-        })?;
-        fs::create_dir_all(&root)
-            .map_err(|source| Error::io("create Oliphaunt OUT_DIR", &root, source))?;
-
-        let staged = stage_artifacts(&selected, &resources_dir)?;
-        write_lock_file(&lock_file, metadata, &self.target, &staged)?;
-        write_generated_rust(&generated_rust, &resources_dir, &lock_file)?;
-
-        let mut cargo_instructions = vec![
-            format!("cargo::rerun-if-changed={}", cargo_toml.display()),
-            format!(
-                "cargo::rustc-env=OLIPHAUNT_RESOURCES_DIR={}",
-                resources_dir.display()
-            ),
-            format!(
-                "cargo::rustc-env=OLIPHAUNT_ASSETS_LOCK={}",
-                lock_file.display()
-            ),
-            format!(
-                "cargo::rustc-env=OLIPHAUNT_ASSETS_RS={}",
-                generated_rust.display()
-            ),
-        ];
-        for manifest in &self.artifact_manifest_paths {
-            cargo_instructions.push(format!("cargo::rerun-if-changed={}", manifest.display()));
-        }
-        for artifact in &selected {
-            for file in &artifact.files {
-                cargo_instructions
-                    .push(format!("cargo::rerun-if-changed={}", file.source.display()));
-            }
-        }
-
-        Ok(BuildOutput {
-            resources_dir,
-            lock_file,
-            generated_rust,
-            cargo_instructions,
-        })
-    }
-
-    fn read_artifact_manifests(&self) -> Result> {
-        let mut artifacts = Vec::new();
-        let mut seen = BTreeSet::new();
-        for path in &self.artifact_manifest_paths {
-            let canonical = path.canonicalize().unwrap_or_else(|_| path.clone());
-            if !seen.insert(canonical) {
-                continue;
-            }
-            let text = fs::read_to_string(path)
-                .map_err(|source| Error::io("read Oliphaunt artifact manifest", path, source))?;
-            let document: ArtifactManifestDocument =
-                toml::from_str(&text).map_err(|source| Error::parse(path, source))?;
-            for mut manifest in document.into_manifests(path)? {
-                manifest.source_manifest = Some(path.clone());
-                manifest.validate()?;
-                artifacts.push(manifest);
-            }
-        }
-        Ok(artifacts)
-    }
-}
-
-fn required_path_var(vars: &BTreeMap, key: &str) -> Result {
-    vars.get(key)
-        .map(PathBuf::from)
-        .filter(|path| !path.as_os_str().is_empty())
-        .ok_or_else(|| Error::new(format!("Cargo did not set {key}")))
-}
-
-fn required_string_var(vars: &BTreeMap, key: &str) -> Result {
-    vars.get(key)
-        .and_then(|value| value.clone().into_string().ok())
-        .filter(|value| !value.is_empty())
-        .ok_or_else(|| Error::new(format!("Cargo did not set {key}")))
-}
-
-fn read_application_manifest(path: &Path) -> Result {
-    let text = fs::read_to_string(path)
-        .map_err(|source| Error::io("read application Cargo.toml", path, source))?;
-    let manifest: ApplicationManifest =
-        toml::from_str(&text).map_err(|source| Error::parse(path, source))?;
-    manifest.package.metadata.oliphaunt.validate()?;
-    Ok(manifest)
-}
-
-fn select_artifacts(
-    app: &ApplicationManifest,
-    artifacts: &[ArtifactManifest],
-    target: &str,
-) -> Result> {
-    let metadata = &app.package.metadata.oliphaunt;
-    let extension_target = if metadata.runtime == "liboliphaunt-wasix" {
-        "portable"
-    } else {
-        target
-    };
-    let mut extension_artifacts = resolve_extension_artifacts(
-        artifacts,
-        &metadata.extensions,
-        extension_target,
-        &metadata.runtime,
-        &metadata.runtime_version,
-    )?;
-    if metadata.runtime == "liboliphaunt-wasix" {
-        let portable_extensions = extension_artifacts
-            .iter()
-            .filter_map(|artifact| artifact.extension.clone())
-            .collect::>();
-        for extension in portable_extensions {
-            if let Some(aot) = optional_extension_artifact(
-                artifacts,
-                &extension,
-                target,
-                &metadata.runtime,
-                &metadata.runtime_version,
-            )? {
-                extension_artifacts.push(aot);
-            }
-        }
-    }
-    let selected_extensions: BTreeSet<&str> = extension_artifacts
-        .iter()
-        .filter_map(|artifact| artifact.extension.as_deref())
-        .collect();
-    for artifact in artifacts {
-        if artifact.kind == ArtifactKind::Extension {
-            let extension = artifact.extension.as_deref().ok_or_else(|| {
-                Error::new(format!(
-                    "{} extension artifact is missing extension name",
-                    artifact.label()
-                ))
-            })?;
-            if !selected_extensions.contains(extension) && !artifact.bundle_member {
-                return Err(Error::new(format!(
-                    "{} was provided by Cargo but extension {extension:?} is not selected in [package.metadata.oliphaunt]",
-                    artifact.label()
-                )));
-            }
-        }
-    }
-
-    let mut selected = Vec::new();
-    match metadata.runtime.as_str() {
-        "liboliphaunt-native" => {
-            selected.push(require_artifact(
-                artifacts,
-                "liboliphaunt-native",
-                Some(&metadata.runtime_version),
-                ArtifactKind::NativeRuntime,
-                target,
-                "selected native runtime",
-            )?);
-            selected.push(require_artifact(
-                artifacts,
-                "oliphaunt-broker",
-                None,
-                ArtifactKind::BrokerHelper,
-                target,
-                "selected native broker helper",
-            )?);
-            if app.depends_on("oliphaunt-tools") {
-                selected.push(require_artifact(
-                    artifacts,
-                    "oliphaunt-tools",
-                    Some(&metadata.runtime_version),
-                    ArtifactKind::NativeTools,
-                    target,
-                    "selected native PostgreSQL tools",
-                )?);
-            }
-        }
-        "liboliphaunt-wasix" => {
-            selected.push(require_artifact(
-                artifacts,
-                "liboliphaunt-wasix",
-                Some(&metadata.runtime_version),
-                ArtifactKind::WasixRuntime,
-                "portable",
-                "selected WASIX portable runtime",
-            )?);
-            selected.push(require_artifact(
-                artifacts,
-                "liboliphaunt-wasix",
-                Some(&metadata.runtime_version),
-                ArtifactKind::WasixAot,
-                target,
-                "selected WASIX AOT runtime",
-            )?);
-            if app.oliphaunt_wasix_tools_enabled() {
-                selected.push(require_artifact(
-                    artifacts,
-                    "oliphaunt-wasix-tools",
-                    Some(&metadata.runtime_version),
-                    ArtifactKind::WasixTools,
-                    "portable",
-                    "selected WASIX tools",
-                )?);
-                selected.push(require_artifact(
-                    artifacts,
-                    "oliphaunt-wasix-tools",
-                    Some(&metadata.runtime_version),
-                    ArtifactKind::WasixToolsAot,
-                    target,
-                    "selected WASIX tools AOT runtime",
-                )?);
-            }
-        }
-        other => {
-            return Err(Error::new(format!(
-                "unsupported [package.metadata.oliphaunt] runtime {other:?}; use \"liboliphaunt-native\" or \"liboliphaunt-wasix\""
-            )));
-        }
-    }
-
-    if metadata.icu {
-        selected.push(require_artifact(
-            artifacts,
-            "oliphaunt-icu",
-            None,
-            ArtifactKind::IcuData,
-            "portable",
-            "selected ICU data",
-        )?);
-    }
-
-    selected.extend(extension_artifacts);
-
-    Ok(selected)
-}
-
-fn resolve_extension_artifacts(
-    artifacts: &[ArtifactManifest],
-    requested: &[String],
-    target: &str,
-    runtime_product: &str,
-    runtime_version: &str,
-) -> Result> {
-    fn visit(
-        extension: &str,
-        artifacts: &[ArtifactManifest],
-        target: &str,
-        runtime_product: &str,
-        runtime_version: &str,
-        visiting: &mut Vec,
-        resolved: &mut BTreeMap,
-    ) -> Result<()> {
-        if resolved.contains_key(extension) {
-            return Ok(());
-        }
-        if let Some(position) = visiting.iter().position(|candidate| candidate == extension) {
-            let mut cycle = visiting[position..].to_vec();
-            cycle.push(extension.to_owned());
-            return Err(Error::new(format!(
-                "Oliphaunt extension dependency cycle: {}",
-                cycle.join(" -> ")
-            )));
-        }
-        let artifact = require_extension_artifact(
-            artifacts,
-            extension,
-            target,
-            runtime_product,
-            runtime_version,
-        )?;
-        visiting.push(extension.to_owned());
-        for dependency in &artifact.dependencies {
-            visit(
-                dependency,
-                artifacts,
-                target,
-                runtime_product,
-                runtime_version,
-                visiting,
-                resolved,
-            )?;
-        }
-        visiting.pop();
-        resolved.insert(extension.to_owned(), artifact);
-        Ok(())
-    }
-
-    let mut visiting = Vec::new();
-    let mut resolved = BTreeMap::new();
-    for extension in requested {
-        visit(
-            extension,
-            artifacts,
-            target,
-            runtime_product,
-            runtime_version,
-            &mut visiting,
-            &mut resolved,
-        )?;
-    }
-    Ok(resolved.into_values().collect())
-}
-
-fn require_artifact(
-    artifacts: &[ArtifactManifest],
-    product: &str,
-    version: Option<&str>,
-    kind: ArtifactKind,
-    target: &str,
-    label: &str,
-) -> Result {
-    let matches: Vec<_> = artifacts
-        .iter()
-        .filter(|artifact| {
-            artifact.product == product
-                && version.is_none_or(|version| artifact.version == version)
-                && artifact.kind == kind
-                && artifact.target == target
-        })
-        .cloned()
-        .collect();
-    let version_label = version
-        .map(|version| format!(" version={version}"))
-        .unwrap_or_default();
-    if matches.len() > 1 {
-        return Err(Error::new(format!(
-            "multiple Cargo-resolved Oliphaunt artifacts match {label}: product={product}{version_label} kind={} target={target}",
-            kind.as_str()
-        )));
-    }
-    matches
-        .into_iter()
-        .next()
-        .ok_or_else(|| {
-            Error::new(format!(
-                "missing Cargo-resolved Oliphaunt artifact for {label}: product={product}{version_label} kind={} target={target}",
-                kind.as_str()
-            ))
-        })
-}
-
-fn require_extension_artifact(
-    artifacts: &[ArtifactManifest],
-    extension: &str,
-    target: &str,
-    runtime_product: &str,
-    runtime_version: &str,
-) -> Result {
-    let candidates: Vec<_> = artifacts
-        .iter()
-        .filter(|artifact| {
-            artifact.kind == ArtifactKind::Extension
-                && artifact.target == target
-                && artifact.extension.as_deref() == Some(extension)
-        })
-        .collect();
-    let matches: Vec<_> = candidates
-        .iter()
-        .filter(|artifact| {
-            artifact.runtime_product.as_deref() == Some(runtime_product)
-                && artifact.runtime_version.as_deref() == Some(runtime_version)
-        })
-        .map(|artifact| (**artifact).clone())
-        .collect();
-    if matches.len() > 1 {
-        return Err(Error::new(format!(
-            "multiple Cargo-resolved Oliphaunt extension artifacts match extension={extension} target={target} runtime={runtime_product} runtime-version={runtime_version}"
-        )));
-    }
-    if let Some(found) = matches.into_iter().next() {
-        return Ok(found);
-    }
-    if !candidates.is_empty() {
-        let bindings = candidates
-            .iter()
-            .map(|artifact| {
-                format!(
-                    "{}@{}",
-                    artifact.runtime_product.as_deref().unwrap_or(""),
-                    artifact.runtime_version.as_deref().unwrap_or("")
-                )
-            })
-            .collect::>()
-            .into_iter()
-            .collect::>()
-            .join(", ");
-        return Err(Error::new(format!(
-            "Cargo-resolved Oliphaunt extension artifact runtime mismatch for extension={extension} target={target}: app selects {runtime_product}@{runtime_version}, artifact binds [{bindings}]"
-        )));
-    }
-    Err(Error::new(format!(
-        "missing Cargo-resolved Oliphaunt extension artifact for extension={extension} target={target} runtime={runtime_product} runtime-version={runtime_version}"
-    )))
-}
-
-fn optional_extension_artifact(
-    artifacts: &[ArtifactManifest],
-    extension: &str,
-    target: &str,
-    runtime_product: &str,
-    runtime_version: &str,
-) -> Result> {
-    if !artifacts.iter().any(|artifact| {
-        artifact.kind == ArtifactKind::Extension
-            && artifact.target == target
-            && artifact.extension.as_deref() == Some(extension)
-    }) {
-        return Ok(None);
-    }
-    require_extension_artifact(
-        artifacts,
-        extension,
-        target,
-        runtime_product,
-        runtime_version,
-    )
-    .map(Some)
-}
-
-fn stage_artifacts(
-    artifacts: &[ArtifactManifest],
-    resources_dir: &Path,
-) -> Result> {
-    let mut staged = Vec::new();
-    for artifact in artifacts {
-        let artifact_dir = resources_dir
-            .join(artifact.kind.as_str())
-            .join(&artifact.product);
-        let mut locked_files = Vec::new();
-        for file in &artifact.files {
-            let relative = checked_relative_path(&file.relative)?;
-            let dest = artifact_dir.join(&relative);
-            let bytes = fs::read(&file.source).map_err(|source| {
-                Error::io("read Oliphaunt artifact file", &file.source, source)
-            })?;
-            let actual = sha256_hex(&bytes);
-            if actual != file.sha256 {
-                return Err(Error::new(format!(
-                    "checksum mismatch for {}: manifest={} actual={actual}",
-                    file.source.display(),
-                    file.sha256
-                )));
-            }
-            if let Some(parent) = dest.parent() {
-                fs::create_dir_all(parent).map_err(|source| {
-                    Error::io("create staged artifact directory", parent, source)
-                })?;
-            }
-            if dest.is_file() {
-                let existing = fs::read(&dest).map_err(|source| {
-                    Error::io("read colliding staged artifact file", &dest, source)
-                })?;
-                let existing_sha256 = sha256_hex(&existing);
-                if existing_sha256 != file.sha256 {
-                    return Err(Error::new(format!(
-                        "selected artifacts collide at {} with different bytes: existing={} incoming={}",
-                        dest.display(),
-                        existing_sha256,
-                        file.sha256
-                    )));
-                }
-            }
-            fs::write(&dest, bytes).map_err(|source| {
-                Error::io("write staged Oliphaunt artifact file", &dest, source)
-            })?;
-            set_executable_if_needed(&dest, file.executable)?;
-            locked_files.push(LockedFile {
-                path: dest
-                    .strip_prefix(resources_dir)
-                    .unwrap_or(&dest)
-                    .to_string_lossy()
-                    .replace('\\', "/"),
-                sha256: file.sha256.clone(),
-                executable: file.executable,
-            });
-        }
-        staged.push(LockedArtifact {
-            product: artifact.product.clone(),
-            version: artifact.version.clone(),
-            kind: artifact.kind.as_str().to_owned(),
-            target: artifact.target.clone(),
-            extension: artifact.extension.clone(),
-            runtime_product: artifact.runtime_product.clone(),
-            runtime_version: artifact.runtime_version.clone(),
-            files: locked_files,
-        });
-    }
-    Ok(staged)
-}
-
-fn checked_relative_path(path: &str) -> Result {
-    let value = Path::new(path);
-    if value.is_absolute()
-        || value
-            .components()
-            .any(|component| matches!(component, Component::ParentDir | Component::Prefix(_)))
-    {
-        return Err(Error::new(format!(
-            "artifact relative path must stay inside resources directory: {path:?}"
-        )));
-    }
-    Ok(value.to_path_buf())
-}
-
-fn set_executable_if_needed(path: &Path, executable: bool) -> Result<()> {
-    if !executable {
-        return Ok(());
-    }
-    #[cfg(unix)]
-    {
-        use std::os::unix::fs::PermissionsExt;
-        let mut permissions = fs::metadata(path)
-            .map_err(|source| Error::io("read staged file permissions", path, source))?
-            .permissions();
-        permissions.set_mode(0o755);
-        fs::set_permissions(path, permissions)
-            .map_err(|source| Error::io("set staged file executable bit", path, source))?;
-    }
-    Ok(())
-}
-
-fn write_lock_file(
-    path: &Path,
-    metadata: &OliphauntMetadata,
-    target: &str,
-    artifacts: &[LockedArtifact],
-) -> Result<()> {
-    let lock = LockFile {
-        schema: LOCK_SCHEMA.to_owned(),
-        target: target.to_owned(),
-        runtime: metadata.runtime.clone(),
-        runtime_version: metadata.runtime_version.clone(),
-        icu: metadata.icu,
-        extensions: metadata.extensions.clone(),
-        artifacts: artifacts.to_vec(),
-    };
-    let text = toml::to_string_pretty(&lock)
-        .map_err(|source| Error::new(format!("serialize Oliphaunt assets lock: {source}")))?;
-    fs::write(path, text).map_err(|source| Error::io("write Oliphaunt assets lock", path, source))
-}
-
-fn write_generated_rust(path: &Path, resources_dir: &Path, lock_file: &Path) -> Result<()> {
-    let text = format!(
-        "pub const OLIPHAUNT_RESOURCES_DIR: &str = {:?};\npub const OLIPHAUNT_ASSETS_LOCK: &str = {:?};\n",
-        resources_dir.display().to_string(),
-        lock_file.display().to_string(),
-    );
-    fs::write(path, text)
-        .map_err(|source| Error::io("write generated Oliphaunt Rust constants", path, source))
-}
-
-fn sha256_hex(bytes: &[u8]) -> String {
-    let digest = Sha256::digest(bytes);
-    let mut out = String::with_capacity(digest.len() * 2);
-    for byte in digest {
-        use std::fmt::Write as _;
-        let _ = write!(&mut out, "{byte:02x}");
-    }
-    out
-}
-
-fn dependencies_enable_feature(
-    dependencies: &BTreeMap,
-    package: &str,
-    feature: &str,
-) -> bool {
-    dependencies
-        .iter()
-        .any(|(name, spec)| dependency_enables_feature(name, spec, package, feature))
-}
-
-fn dependencies_contain_package(
-    dependencies: &BTreeMap,
-    package: &str,
-) -> bool {
-    dependencies.iter().any(|(name, spec)| match spec {
-        toml::Value::String(_) => name == package,
-        toml::Value::Table(table) => {
-            table
-                .get("package")
-                .and_then(toml::Value::as_str)
-                .unwrap_or(name)
-                == package
-        }
-        _ => false,
-    })
-}
-
-fn dependency_enables_feature(
-    name: &str,
-    spec: &toml::Value,
-    package: &str,
-    feature: &str,
-) -> bool {
-    let toml::Value::Table(table) = spec else {
-        return false;
-    };
-    let dependency_name = table
-        .get("package")
-        .and_then(toml::Value::as_str)
-        .unwrap_or(name);
-    if dependency_name != package {
-        return false;
-    }
-    let Some(toml::Value::Array(features)) = table.get("features") else {
-        return false;
-    };
-    features
-        .iter()
-        .any(|candidate| candidate.as_str() == Some(feature))
-}
-
-#[derive(Debug, Deserialize)]
-struct ApplicationManifest {
-    package: ApplicationPackage,
-    #[serde(default)]
-    dependencies: BTreeMap,
-    #[serde(default)]
-    target: BTreeMap,
-}
-
-impl ApplicationManifest {
-    fn depends_on(&self, package: &str) -> bool {
-        dependencies_contain_package(&self.dependencies, package)
-            || self
-                .target
-                .values()
-                .any(|target| dependencies_contain_package(&target.dependencies, package))
-    }
-
-    fn oliphaunt_wasix_tools_enabled(&self) -> bool {
-        self.package.metadata.oliphaunt.tools
-            || dependencies_enable_feature(&self.dependencies, "oliphaunt-wasix", "tools")
-            || self.target.values().any(|target| {
-                dependencies_enable_feature(&target.dependencies, "oliphaunt-wasix", "tools")
-            })
-    }
-}
-
-#[derive(Debug, Default, Deserialize)]
-struct ApplicationTargetTable {
-    #[serde(default)]
-    dependencies: BTreeMap,
-}
-
-#[derive(Debug, Deserialize)]
-struct ApplicationPackage {
-    #[serde(default)]
-    metadata: ApplicationPackageMetadata,
-}
-
-#[derive(Debug, Default, Deserialize)]
-struct ApplicationPackageMetadata {
-    oliphaunt: OliphauntMetadata,
-}
-
-#[derive(Debug, Clone, Default, Deserialize)]
-#[serde(rename_all = "kebab-case")]
-struct OliphauntMetadata {
-    runtime: String,
-    runtime_version: String,
-    #[serde(default)]
-    extensions: Vec,
-    #[serde(default)]
-    icu: bool,
-    #[serde(default)]
-    tools: bool,
-}
-
-impl OliphauntMetadata {
-    fn validate(&self) -> Result<()> {
-        if self.runtime.is_empty() {
-            return Err(Error::new(
-                "missing [package.metadata.oliphaunt].runtime".to_owned(),
-            ));
-        }
-        if self.runtime_version.is_empty() {
-            return Err(Error::new(
-                "missing [package.metadata.oliphaunt].runtime-version".to_owned(),
-            ));
-        }
-        let mut seen = BTreeSet::new();
-        for extension in &self.extensions {
-            if extension.is_empty() {
-                return Err(Error::new(
-                    "[package.metadata.oliphaunt].extensions must not contain empty names",
-                ));
-            }
-            if !seen.insert(extension) {
-                return Err(Error::new(format!(
-                    "duplicate [package.metadata.oliphaunt] extension {extension:?}"
-                )));
-            }
-        }
-        Ok(())
-    }
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "kebab-case", deny_unknown_fields)]
-struct ArtifactManifestDocument {
-    schema: String,
-    product: String,
-    version: String,
-    kind: ArtifactKind,
-    target: String,
-    runtime_product: Option,
-    runtime_version: Option,
-    extension: Option,
-    #[serde(default)]
-    dependencies: Vec,
-    #[serde(default)]
-    files: Vec,
-    #[serde(default)]
-    extensions: Vec,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct ArtifactBundleMember {
-    extension: String,
-    #[serde(default)]
-    dependencies: Vec,
-    files: Vec,
-}
-
-impl ArtifactManifestDocument {
-    fn into_manifests(self, path: &Path) -> Result> {
-        let common_missing =
-            self.product.is_empty() || self.version.is_empty() || self.target.is_empty();
-        if common_missing {
-            return Err(Error::new(format!(
-                "{} must declare product, version, and target",
-                path.display()
-            )));
-        }
-        if self.schema == ARTIFACT_SCHEMA {
-            if !self.extensions.is_empty() {
-                return Err(Error::new(format!(
-                    "{} v1 artifact manifest must not declare extensions rows",
-                    path.display()
-                )));
-            }
-            return Ok(vec![ArtifactManifest {
-                schema: self.schema,
-                product: self.product,
-                version: self.version,
-                kind: self.kind,
-                target: self.target,
-                runtime_product: self.runtime_product,
-                runtime_version: self.runtime_version,
-                extension: self.extension,
-                dependencies: self.dependencies,
-                files: self.files,
-                bundle_member: false,
-                source_manifest: None,
-            }]);
-        }
-        if self.schema != ARTIFACT_BUNDLE_SCHEMA {
-            return Err(Error::new(format!(
-                "{} must use schema {ARTIFACT_SCHEMA:?} or {ARTIFACT_BUNDLE_SCHEMA:?}",
-                path.display()
-            )));
-        }
-        if self.kind != ArtifactKind::Extension
-            || self.extension.is_some()
-            || !self.dependencies.is_empty()
-            || !self.files.is_empty()
-            || self.extensions.len() < 2
-        {
-            return Err(Error::new(format!(
-                "{} v2 artifact bundle must be an extension kind with at least two member rows and no root extension/files",
-                path.display()
-            )));
-        }
-        let mut seen = BTreeSet::new();
-        let mut members = Vec::new();
-        for member in self.extensions {
-            if member.extension.is_empty() || !seen.insert(member.extension.clone()) {
-                return Err(Error::new(format!(
-                    "{} v2 artifact bundle has an empty or duplicate extension member",
-                    path.display()
-                )));
-            }
-            members.push(ArtifactManifest {
-                schema: ARTIFACT_SCHEMA.to_owned(),
-                product: self.product.clone(),
-                version: self.version.clone(),
-                kind: self.kind,
-                target: self.target.clone(),
-                runtime_product: self.runtime_product.clone(),
-                runtime_version: self.runtime_version.clone(),
-                extension: Some(member.extension),
-                dependencies: member.dependencies,
-                files: member.files,
-                bundle_member: true,
-                source_manifest: None,
-            });
-        }
-        if members
-            .windows(2)
-            .any(|pair| pair[0].extension.as_deref() >= pair[1].extension.as_deref())
-        {
-            return Err(Error::new(format!(
-                "{} v2 artifact bundle members must be sorted by extension",
-                path.display()
-            )));
-        }
-        Ok(members)
-    }
-}
-
-#[derive(Debug, Clone)]
-struct ArtifactManifest {
-    schema: String,
-    product: String,
-    version: String,
-    kind: ArtifactKind,
-    target: String,
-    runtime_product: Option,
-    runtime_version: Option,
-    extension: Option,
-    dependencies: Vec,
-    files: Vec,
-    bundle_member: bool,
-    source_manifest: Option,
-}
-
-impl ArtifactManifest {
-    fn validate(&self) -> Result<()> {
-        if self.schema != ARTIFACT_SCHEMA {
-            return Err(Error::new(format!(
-                "{} must use schema {ARTIFACT_SCHEMA:?}",
-                self.label()
-            )));
-        }
-        if self.product.is_empty() || self.version.is_empty() || self.target.is_empty() {
-            return Err(Error::new(format!(
-                "{} must declare product, version, and target",
-                self.label()
-            )));
-        }
-        if self.kind == ArtifactKind::Extension
-            && self.extension.as_deref().unwrap_or("").is_empty()
-        {
-            return Err(Error::new(format!(
-                "{} extension artifact must declare extension",
-                self.label()
-            )));
-        }
-        if self.kind == ArtifactKind::Extension {
-            if self.runtime_product.as_deref().unwrap_or("").is_empty()
-                || self.runtime_version.as_deref().unwrap_or("").is_empty()
-            {
-                return Err(Error::new(format!(
-                    "{} extension artifact must declare runtime-product and runtime-version",
-                    self.label()
-                )));
-            }
-            if !matches!(
-                self.runtime_product.as_deref(),
-                Some("liboliphaunt-native" | "liboliphaunt-wasix")
-            ) {
-                return Err(Error::new(format!(
-                    "{} extension artifact runtime-product must be liboliphaunt-native or liboliphaunt-wasix",
-                    self.label()
-                )));
-            }
-            let canonical_dependencies: BTreeSet<&str> =
-                self.dependencies.iter().map(String::as_str).collect();
-            if canonical_dependencies.len() != self.dependencies.len()
-                || self.dependencies.windows(2).any(|pair| pair[0] >= pair[1])
-                || self
-                    .extension
-                    .as_ref()
-                    .is_some_and(|extension| canonical_dependencies.contains(extension.as_str()))
-                || self.dependencies.iter().any(String::is_empty)
-            {
-                return Err(Error::new(format!(
-                    "{} extension dependencies must be sorted, unique, non-empty, and exclude itself",
-                    self.label()
-                )));
-            }
-        } else if self.runtime_product.is_some() || self.runtime_version.is_some() {
-            return Err(Error::new(format!(
-                "{} non-extension artifact must not declare runtime-product or runtime-version",
-                self.label()
-            )));
-        } else if !self.dependencies.is_empty() {
-            return Err(Error::new(format!(
-                "{} non-extension artifact must not declare extension dependencies",
-                self.label()
-            )));
-        }
-        if self.files.is_empty() {
-            return Err(Error::new(format!(
-                "{} must contain at least one file",
-                self.label()
-            )));
-        }
-        self.validate_product_kind()?;
-        self.validate_payload()?;
-        Ok(())
-    }
-
-    fn label(&self) -> String {
-        self.source_manifest
-            .as_ref()
-            .map(|path| path.display().to_string())
-            .unwrap_or_else(|| format!("{} {} {}", self.product, self.kind.as_str(), self.target))
-    }
-
-    fn validate_product_kind(&self) -> Result<()> {
-        let expected = match self.kind {
-            ArtifactKind::NativeRuntime => Some("liboliphaunt-native"),
-            ArtifactKind::NativeTools => Some("oliphaunt-tools"),
-            ArtifactKind::WasixRuntime | ArtifactKind::WasixAot => Some("liboliphaunt-wasix"),
-            ArtifactKind::WasixTools | ArtifactKind::WasixToolsAot => Some("oliphaunt-wasix-tools"),
-            ArtifactKind::BrokerHelper => Some("oliphaunt-broker"),
-            ArtifactKind::IcuData => Some("oliphaunt-icu"),
-            ArtifactKind::Extension => None,
-        };
-        if let Some(expected) = expected {
-            if self.product != expected {
-                return Err(Error::new(format!(
-                    "{} kind {} must use product {expected:?}",
-                    self.label(),
-                    self.kind.as_str()
-                )));
-            }
-        } else if !self.product.starts_with("oliphaunt-extension-") {
-            return Err(Error::new(format!(
-                "{} extension artifact product must start with \"oliphaunt-extension-\"",
-                self.label()
-            )));
-        }
-        Ok(())
-    }
-
-    fn validate_payload(&self) -> Result<()> {
-        let relatives: BTreeSet<&str> = self
-            .files
-            .iter()
-            .map(|file| file.relative.as_str())
-            .collect();
-        match self.kind {
-            ArtifactKind::NativeRuntime => {
-                self.require_files(
-                    &relatives,
-                    &native_tool_paths(&self.target, &["postgres", "initdb", "pg_ctl"]),
-                )?;
-                self.require_files(
-                    &relatives,
-                    &[
-                        "cluster-seed/manifest.properties",
-                        "cluster-seed/files/PG_VERSION",
-                        "cluster-seed/files/global/pg_control",
-                        "cluster-seed-icu/manifest.properties",
-                        "cluster-seed-icu/files/PG_VERSION",
-                        "cluster-seed-icu/files/global/pg_control",
-                    ],
-                )?;
-                self.reject_files(
-                    &relatives,
-                    &native_tool_path_variants(&["pg_basebackup", "pg_dump", "psql"]),
-                )?;
-            }
-            ArtifactKind::NativeTools => {
-                self.require_files(
-                    &relatives,
-                    &native_tool_paths(&self.target, &["pg_basebackup", "pg_dump", "psql"]),
-                )?;
-                self.reject_files(
-                    &relatives,
-                    &native_tool_path_variants(&["postgres", "initdb", "pg_ctl"]),
-                )?;
-            }
-            ArtifactKind::WasixRuntime => {
-                self.require_files(
-                    &relatives,
-                    &[
-                        "oliphaunt.wasix.tar.zst",
-                        "bin/initdb.wasix.wasm",
-                        "cluster-seeds/standard.tar.zst",
-                        "cluster-seeds/standard.json",
-                        "cluster-seeds/icu.tar.zst",
-                        "cluster-seeds/icu.json",
-                    ],
-                )?;
-                self.reject_files(
-                    &relatives,
-                    &[
-                        "bin/pg_ctl.wasix.wasm",
-                        "bin/pg_dump.wasix.wasm",
-                        "bin/psql.wasix.wasm",
-                    ],
-                )?;
-            }
-            ArtifactKind::WasixTools => {
-                self.require_files(
-                    &relatives,
-                    &["bin/pg_dump.wasix.wasm", "bin/psql.wasix.wasm"],
-                )?;
-                self.reject_files(
-                    &relatives,
-                    &[
-                        "bin/postgres.wasix.wasm",
-                        "bin/initdb.wasix.wasm",
-                        "bin/pg_ctl.wasix.wasm",
-                    ],
-                )?;
-            }
-            ArtifactKind::WasixToolsAot => {
-                self.require_files(
-                    &relatives,
-                    &["pg_dump-llvm-opta.bin.zst", "psql-llvm-opta.bin.zst"],
-                )?;
-                self.reject_files(
-                    &relatives,
-                    &[
-                        "postgres-llvm-opta.bin.zst",
-                        "initdb-llvm-opta.bin.zst",
-                        "pg_ctl-llvm-opta.bin.zst",
-                    ],
-                )?;
-            }
-            ArtifactKind::WasixAot => {
-                self.require_files(&relatives, &["manifest.json"])?;
-                self.reject_files(
-                    &relatives,
-                    &[
-                        "pg_ctl-llvm-opta.bin.zst",
-                        "pg_dump-llvm-opta.bin.zst",
-                        "psql-llvm-opta.bin.zst",
-                    ],
-                )?;
-            }
-            ArtifactKind::BrokerHelper | ArtifactKind::IcuData | ArtifactKind::Extension => {}
-        }
-        Ok(())
-    }
-
-    fn require_files>(
-        &self,
-        relatives: &BTreeSet<&str>,
-        required: &[S],
-    ) -> Result<()> {
-        for relative in required {
-            let relative = relative.as_ref();
-            if !relatives.contains(relative) {
-                return Err(Error::new(format!(
-                    "{} {} artifact is missing required payload {relative:?}",
-                    self.label(),
-                    self.kind.as_str()
-                )));
-            }
-        }
-        Ok(())
-    }
-
-    fn reject_files>(
-        &self,
-        relatives: &BTreeSet<&str>,
-        rejected: &[S],
-    ) -> Result<()> {
-        for relative in rejected {
-            let relative = relative.as_ref();
-            if relatives.contains(relative) {
-                return Err(Error::new(format!(
-                    "{} {} artifact must not contain payload {relative:?}",
-                    self.label(),
-                    self.kind.as_str()
-                )));
-            }
-        }
-        Ok(())
-    }
-}
-
-fn native_tool_paths(target: &str, stems: &[&str]) -> Vec {
-    let suffix = if is_windows_target(target) {
-        ".exe"
-    } else {
-        ""
-    };
-    stems
-        .iter()
-        .map(|stem| format!("runtime/bin/{stem}{suffix}"))
-        .collect()
-}
-
-fn native_tool_path_variants(stems: &[&str]) -> Vec {
-    stems
-        .iter()
-        .flat_map(|stem| {
-            [
-                format!("runtime/bin/{stem}"),
-                format!("runtime/bin/{stem}.exe"),
-            ]
-        })
-        .collect()
-}
-
-fn is_windows_target(target: &str) -> bool {
-    target.contains("windows")
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize)]
-#[serde(rename_all = "kebab-case")]
-enum ArtifactKind {
-    NativeRuntime,
-    NativeTools,
-    WasixRuntime,
-    WasixTools,
-    WasixAot,
-    WasixToolsAot,
-    BrokerHelper,
-    IcuData,
-    Extension,
-}
-
-impl ArtifactKind {
-    fn as_str(self) -> &'static str {
-        match self {
-            Self::NativeRuntime => "native-runtime",
-            Self::NativeTools => "native-tools",
-            Self::WasixRuntime => "wasix-runtime",
-            Self::WasixTools => "wasix-tools",
-            Self::WasixAot => "wasix-aot",
-            Self::WasixToolsAot => "wasix-tools-aot",
-            Self::BrokerHelper => "broker-helper",
-            Self::IcuData => "icu-data",
-            Self::Extension => "extension",
-        }
-    }
-}
-
-#[derive(Debug, Clone, Deserialize)]
-#[serde(rename_all = "kebab-case")]
-struct ArtifactFile {
-    source: PathBuf,
-    relative: String,
-    sha256: String,
-    #[serde(default)]
-    executable: bool,
-}
-
-#[derive(Debug, Clone, Serialize)]
-#[serde(rename_all = "kebab-case")]
-struct LockFile {
-    schema: String,
-    target: String,
-    runtime: String,
-    runtime_version: String,
-    icu: bool,
-    extensions: Vec,
-    artifacts: Vec,
-}
-
-#[derive(Debug, Clone, Serialize)]
-#[serde(rename_all = "kebab-case")]
-struct LockedArtifact {
-    product: String,
-    version: String,
-    kind: String,
-    target: String,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    extension: Option,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    runtime_product: Option,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    runtime_version: Option,
-    files: Vec,
-}
-
-#[derive(Debug, Clone, Serialize)]
-#[serde(rename_all = "kebab-case")]
-struct LockedFile {
-    path: String,
-    sha256: String,
-    executable: bool,
-}
-
-type Result = std::result::Result;
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Error {
-    message: String,
-}
-
-impl Error {
-    fn new(message: impl Into) -> Self {
-        Self {
-            message: message.into(),
-        }
-    }
-
-    fn io(action: &str, path: &Path, source: io::Error) -> Self {
-        Self::new(format!("{action} {}: {source}", path.display()))
-    }
-
-    fn parse(path: &Path, source: toml::de::Error) -> Self {
-        Self::new(format!("parse {}: {source}", path.display()))
-    }
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        formatter.write_str(&self.message)
-    }
-}
-
-impl std::error::Error for Error {}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use std::io::Write;
-    use tempfile::TempDir;
-
-    #[test]
-    fn missing_application_metadata_fails() {
-        let temp = TempDir::new().unwrap();
-        fs::write(
-            temp.path().join("Cargo.toml"),
-            "[package]\nname = \"app\"\nversion = \"0.1.0\"\n",
-        )
-        .unwrap();
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![],
-        };
-        let error = context.configure().expect_err("missing metadata must fail");
-        assert!(
-            error
-                .to_string()
-                .contains("missing [package.metadata.oliphaunt].runtime")
-        );
-    }
-
-    #[test]
-    fn selected_runtime_requires_cargo_resolved_artifact() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-"#,
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![],
-        };
-        let error = context
-            .configure()
-            .expect_err("missing runtime artifact must fail");
-        assert!(
-            error
-                .to_string()
-                .contains("missing Cargo-resolved Oliphaunt artifact")
-        );
-        assert!(error.to_string().contains("kind=native-runtime"));
-    }
-
-    #[test]
-    fn icu_selection_requires_icu_artifact() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-icu = true
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let tools_manifest = write_artifact_manifest(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/pg_dump",
-        );
-        let broker_manifest = write_artifact_manifest(
-            &temp,
-            "broker.toml",
-            "oliphaunt-broker",
-            "0.1.0",
-            "broker-helper",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "bin/oliphaunt-broker",
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![runtime_manifest, tools_manifest, broker_manifest],
-        };
-        let error = context
-            .configure()
-            .expect_err("missing ICU artifact must fail");
-        assert!(error.to_string().contains("product=oliphaunt-icu"));
-        assert!(error.to_string().contains("kind=icu-data"));
-    }
-
-    #[test]
-    fn native_runtime_selection_requires_broker_helper_artifact() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let tools_manifest = write_artifact_manifest(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/pg_dump",
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![runtime_manifest, tools_manifest],
-        };
-        let error = context
-            .configure()
-            .expect_err("missing broker helper artifact must fail");
-        assert!(error.to_string().contains("product=oliphaunt-broker"));
-        assert!(error.to_string().contains("kind=broker-helper"));
-    }
-
-    #[test]
-    fn native_runtime_allows_independent_auxiliary_artifact_versions() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "1.2.0"
-extensions = ["vector"]
-icu = true
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "1.2.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let broker_manifest = write_artifact_manifest(
-            &temp,
-            "broker.toml",
-            "oliphaunt-broker",
-            "2.0.0",
-            "broker-helper",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "bin/oliphaunt-broker",
-        );
-        let icu_manifest = write_artifact_manifest(
-            &temp,
-            "icu.toml",
-            "oliphaunt-icu",
-            "3.0.0",
-            "icu-data",
-            "portable",
-            None,
-            "share/icu/icudt.dat",
-        );
-        let extension_manifest = write_artifact_manifest(
-            &temp,
-            "vector.toml",
-            "oliphaunt-extension-vector",
-            "4.0.0",
-            "extension",
-            "x86_64-unknown-linux-gnu",
-            Some("vector"),
-            "extensions/vector/vector.control",
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![
-                runtime_manifest,
-                broker_manifest,
-                icu_manifest,
-                extension_manifest,
-            ],
-        };
-
-        let output = context
-            .configure()
-            .expect("Cargo-resolved auxiliary artifact versions should be accepted");
-
-        let lock = fs::read_to_string(output.lock_file).unwrap();
-        assert!(lock.contains("product = \"liboliphaunt-native\""));
-        assert!(lock.contains("version = \"1.2.0\""));
-        assert!(!lock.contains("product = \"oliphaunt-tools\""));
-        assert!(lock.contains("product = \"oliphaunt-broker\""));
-        assert!(lock.contains("version = \"2.0.0\""));
-        assert!(lock.contains("product = \"oliphaunt-icu\""));
-        assert!(lock.contains("version = \"3.0.0\""));
-        assert!(lock.contains("product = \"oliphaunt-extension-vector\""));
-        assert!(lock.contains("version = \"4.0.0\""));
-    }
-
-    #[test]
-    fn unselected_extension_artifact_fails() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let broker_manifest = write_artifact_manifest(
-            &temp,
-            "broker.toml",
-            "oliphaunt-broker",
-            "0.1.0",
-            "broker-helper",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "bin/oliphaunt-broker",
-        );
-        let extension_manifest = write_artifact_manifest(
-            &temp,
-            "vector.toml",
-            "oliphaunt-extension-vector",
-            "0.1.0",
-            "extension",
-            "x86_64-unknown-linux-gnu",
-            Some("vector"),
-            "extensions/vector/vector.control",
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![runtime_manifest, broker_manifest, extension_manifest],
-        };
-        let error = context
-            .configure()
-            .expect_err("unselected extension artifact must fail");
-        assert!(error.to_string().contains("is not selected"));
-    }
-
-    #[test]
-    fn selected_artifact_files_are_staged_and_locked() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-extensions = ["vector"]
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let tools_manifest = write_artifact_manifest(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/pg_dump",
-        );
-        let broker_manifest = write_artifact_manifest(
-            &temp,
-            "broker.toml",
-            "oliphaunt-broker",
-            "0.1.0",
-            "broker-helper",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "bin/oliphaunt-broker",
-        );
-        let extension_manifest = write_artifact_manifest(
-            &temp,
-            "vector.toml",
-            "oliphaunt-extension-vector",
-            "0.1.0",
-            "extension",
-            "x86_64-unknown-linux-gnu",
-            Some("vector"),
-            "extensions/vector/vector.control",
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![
-                runtime_manifest,
-                tools_manifest,
-                broker_manifest,
-                extension_manifest,
-            ],
-        };
-
-        let output = context
-            .configure()
-            .expect("selected artifacts should stage");
-
-        assert!(
-            output
-                .resources_dir
-                .join("native-runtime/liboliphaunt-native/runtime/bin/postgres")
-                .is_file()
-        );
-        assert!(!output.resources_dir.join("native-tools").exists());
-        assert!(
-            output
-                .resources_dir
-                .join("broker-helper/oliphaunt-broker/bin/oliphaunt-broker")
-                .is_file()
-        );
-        assert!(
-            output
-                .resources_dir
-                .join("extension/oliphaunt-extension-vector/extensions/vector/vector.control")
-                .is_file()
-        );
-        let lock = fs::read_to_string(output.lock_file).unwrap();
-        assert!(lock.contains("schema = \"oliphaunt-assets-lock-v1\""));
-        assert!(lock.contains("runtime = \"liboliphaunt-native\""));
-        assert!(lock.contains("kind = \"broker-helper\""));
-        assert!(lock.contains("extension = \"vector\""));
-        let generated = fs::read_to_string(output.generated_rust).unwrap();
-        assert!(generated.contains("OLIPHAUNT_RESOURCES_DIR"));
-    }
-
-    #[test]
-    fn native_tools_are_staged_only_for_an_explicit_dependency() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-
-[dependencies]
-oliphaunt-tools = "0.1.0"
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let broker_manifest = write_artifact_manifest(
-            &temp,
-            "broker.toml",
-            "oliphaunt-broker",
-            "0.1.0",
-            "broker-helper",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "bin/oliphaunt-broker",
-        );
-        let tools_manifest = write_artifact_manifest(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/pg_dump",
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![runtime_manifest, broker_manifest, tools_manifest],
-        };
-
-        let output = context.configure().expect("native tools should stage");
-        assert!(
-            output
-                .resources_dir
-                .join("native-tools/oliphaunt-tools/runtime/bin/pg_dump")
-                .is_file()
-        );
-        let lock = fs::read_to_string(output.lock_file).unwrap();
-        assert!(lock.contains("product = \"oliphaunt-tools\""));
-    }
-
-    #[test]
-    fn bundle_manifest_resolves_dependency_closure_alongside_an_external_extension() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-extensions = ["earthdistance", "vector"]
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let tools_manifest = write_artifact_manifest(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/pg_dump",
-        );
-        let broker_manifest = write_artifact_manifest(
-            &temp,
-            "broker.toml",
-            "oliphaunt-broker",
-            "0.1.0",
-            "broker-helper",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "bin/oliphaunt-broker",
-        );
-        let bundle_manifest = write_bundle_artifact_manifest(
-            &temp,
-            "contrib.toml",
-            "oliphaunt-extension-contrib-pg18",
-            "0.1.0",
-            "x86_64-unknown-linux-gnu",
-            &["cube", "earthdistance", "hstore"],
-        );
-        let vector_manifest = write_artifact_manifest(
-            &temp,
-            "vector.toml",
-            "oliphaunt-extension-vector",
-            "0.2.0",
-            "extension",
-            "x86_64-unknown-linux-gnu",
-            Some("vector"),
-            "share/postgresql/extension/vector.control",
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![
-                runtime_manifest,
-                tools_manifest,
-                broker_manifest,
-                bundle_manifest,
-                vector_manifest,
-            ],
-        };
-
-        let output = context
-            .configure()
-            .expect("selected bundle members should stage");
-        let extension_root = output.resources_dir.join("extension");
-        for (product, extension) in [
-            ("oliphaunt-extension-contrib-pg18", "cube"),
-            ("oliphaunt-extension-contrib-pg18", "earthdistance"),
-            ("oliphaunt-extension-vector", "vector"),
-        ] {
-            assert!(
-                extension_root
-                    .join(product)
-                    .join(format!("share/postgresql/extension/{extension}.control"))
-                    .is_file()
-            );
-        }
-        assert!(
-            !extension_root
-                .join("oliphaunt-extension-contrib-pg18/share/postgresql/extension/hstore.control")
-                .exists()
-        );
-        let lock = fs::read_to_string(output.lock_file).unwrap();
-        assert!(lock.contains("extension = \"cube\""));
-        assert!(lock.contains("extension = \"earthdistance\""));
-        assert!(lock.contains("extension = \"vector\""));
-        assert!(!lock.contains("extension = \"hstore\""));
-    }
-
-    #[test]
-    fn external_extension_runtime_version_mismatch_fails() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-extensions = ["vector"]
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let tools_manifest = write_artifact_manifest(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/pg_dump",
-        );
-        let broker_manifest = write_artifact_manifest(
-            &temp,
-            "broker.toml",
-            "oliphaunt-broker",
-            "0.1.0",
-            "broker-helper",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "bin/oliphaunt-broker",
-        );
-        let extension_manifest = write_artifact_manifest(
-            &temp,
-            "vector.toml",
-            "oliphaunt-extension-vector",
-            "7.2.1",
-            "extension",
-            "x86_64-unknown-linux-gnu",
-            Some("vector"),
-            "share/postgresql/extension/vector.control",
-        );
-        let incompatible = fs::read_to_string(&extension_manifest)
-            .unwrap()
-            .replace("runtime-version = \"0.1.0\"", "runtime-version = \"9.9.9\"");
-        fs::write(&extension_manifest, incompatible).unwrap();
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![
-                runtime_manifest,
-                tools_manifest,
-                broker_manifest,
-                extension_manifest,
-            ],
-        };
-        let error = context.configure().expect_err(
-            "independently versioned external must bind its compatible runtime exactly",
-        );
-        let message = error.to_string();
-        assert!(message.contains("extension artifact runtime mismatch"));
-        assert!(message.contains("app selects liboliphaunt-native@0.1.0"));
-        assert!(message.contains("artifact binds [liboliphaunt-native@9.9.9]"));
-    }
-
-    #[test]
-    fn extension_bundle_runtime_product_mismatch_fails() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-extensions = ["cube"]
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let tools_manifest = write_artifact_manifest(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/pg_dump",
-        );
-        let broker_manifest = write_artifact_manifest(
-            &temp,
-            "broker.toml",
-            "oliphaunt-broker",
-            "0.1.0",
-            "broker-helper",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "bin/oliphaunt-broker",
-        );
-        let bundle_manifest = write_bundle_artifact_manifest(
-            &temp,
-            "contrib.toml",
-            "oliphaunt-extension-contrib-pg18",
-            "0.1.0",
-            "x86_64-unknown-linux-gnu",
-            &["cube", "hstore"],
-        );
-        let incompatible = fs::read_to_string(&bundle_manifest).unwrap().replace(
-            "runtime-product = \"liboliphaunt-native\"",
-            "runtime-product = \"liboliphaunt-wasix\"",
-        );
-        fs::write(&bundle_manifest, incompatible).unwrap();
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![
-                runtime_manifest,
-                tools_manifest,
-                broker_manifest,
-                bundle_manifest,
-            ],
-        };
-        let error = context
-            .configure()
-            .expect_err("every member flattened from a bundle must retain its runtime binding");
-        let message = error.to_string();
-        assert!(message.contains("extension artifact runtime mismatch"));
-        assert!(message.contains("app selects liboliphaunt-native@0.1.0"));
-        assert!(message.contains("artifact binds [liboliphaunt-wasix@0.1.0]"));
-    }
-
-    #[test]
-    fn staging_cleans_stale_resource_files() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-native"
-runtime-version = "0.1.0"
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/postgres",
-        );
-        let tools_manifest = write_artifact_manifest(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "runtime/bin/pg_dump",
-        );
-        let broker_manifest = write_artifact_manifest(
-            &temp,
-            "broker.toml",
-            "oliphaunt-broker",
-            "0.1.0",
-            "broker-helper",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "bin/oliphaunt-broker",
-        );
-        let out_dir = temp.path().join("out");
-        let stale = out_dir.join("oliphaunt/resources/extension/stale/stale.control");
-        fs::create_dir_all(stale.parent().unwrap()).unwrap();
-        fs::write(&stale, "stale").unwrap();
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir,
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![runtime_manifest, tools_manifest, broker_manifest],
-        };
-
-        let output = context.configure().expect("selected runtime should stage");
-
-        assert!(!stale.exists());
-        assert!(
-            output
-                .resources_dir
-                .join("native-runtime/liboliphaunt-native/runtime/bin/postgres")
-                .is_file()
-        );
-    }
-
-    #[test]
-    fn wasix_runtime_without_tools_stages_root_runtime_only() {
-        let temp = app_with_metadata(
-            r#"
-[dependencies]
-oliphaunt-wasix = "0.1.0"
-
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-wasix"
-runtime-version = "0.1.0"
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "wasix-runtime.toml",
-            "liboliphaunt-wasix",
-            "0.1.0",
-            "wasix-runtime",
-            "portable",
-            None,
-            "oliphaunt.wasix.tar.zst",
-        );
-        let aot_manifest = write_artifact_manifest(
-            &temp,
-            "wasix-aot.toml",
-            "liboliphaunt-wasix",
-            "0.1.0",
-            "wasix-aot",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "oliphaunt-llvm-opta.bin.zst",
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![runtime_manifest, aot_manifest],
-        };
-
-        let output = context
-            .configure()
-            .expect("root WASIX runtime should not require split tools");
-
-        let lock = fs::read_to_string(output.lock_file).unwrap();
-        assert!(lock.contains("product = \"liboliphaunt-wasix\""));
-        assert!(!lock.contains("product = \"oliphaunt-wasix-tools\""));
-        assert!(
-            output
-                .resources_dir
-                .join("wasix-runtime/liboliphaunt-wasix/bin/initdb.wasix.wasm")
-                .is_file()
-        );
-        assert!(
-            output
-                .resources_dir
-                .join("wasix-aot/liboliphaunt-wasix/manifest.json")
-                .is_file()
-        );
-        assert!(
-            !output
-                .resources_dir
-                .join("wasix-tools/oliphaunt-wasix-tools")
-                .exists()
-        );
-    }
-
-    #[test]
-    fn wasix_extension_bundle_selects_portable_and_host_aot_dependency_closure() {
-        let temp = app_with_metadata(
-            r#"
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-wasix"
-runtime-version = "0.1.0"
-extensions = ["earthdistance"]
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "wasix-runtime.toml",
-            "liboliphaunt-wasix",
-            "0.1.0",
-            "wasix-runtime",
-            "portable",
-            None,
-            "oliphaunt.wasix.tar.zst",
-        );
-        let runtime_aot_manifest = write_artifact_manifest(
-            &temp,
-            "wasix-aot.toml",
-            "liboliphaunt-wasix",
-            "0.1.0",
-            "wasix-aot",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "oliphaunt-llvm-opta.bin.zst",
-        );
-        let portable_extensions = write_bundle_artifact_manifest(
-            &temp,
-            "contrib-portable.toml",
-            "oliphaunt-extension-contrib-pg18",
-            "0.1.0",
-            "portable",
-            &["cube", "earthdistance", "hstore"],
-        );
-        let aot_extensions = write_bundle_artifact_manifest(
-            &temp,
-            "contrib-aot.toml",
-            "oliphaunt-extension-contrib-pg18",
-            "0.1.0",
-            "x86_64-unknown-linux-gnu",
-            &["cube", "earthdistance", "hstore"],
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![
-                runtime_manifest,
-                runtime_aot_manifest,
-                portable_extensions,
-                aot_extensions,
-            ],
-        };
-
-        let output = context
-            .configure()
-            .expect("WASIX bundle should resolve portable and host AOT closure");
-        let lock = fs::read_to_string(output.lock_file).unwrap();
-        assert!(lock.contains("target = \"portable\""));
-        assert!(lock.contains("target = \"x86_64-unknown-linux-gnu\""));
-        assert!(lock.contains("extension = \"cube\""));
-        assert!(lock.contains("extension = \"earthdistance\""));
-        assert!(!lock.contains("extension = \"hstore\""));
-    }
-
-    #[test]
-    fn wasix_runtime_with_tools_feature_stages_split_tools() {
-        let temp = app_with_metadata(
-            r#"
-[dependencies]
-oliphaunt-wasix = { version = "0.1.0", features = ["tools"] }
-
-[package.metadata.oliphaunt]
-runtime = "liboliphaunt-wasix"
-runtime-version = "0.1.0"
-"#,
-        );
-        let runtime_manifest = write_artifact_manifest(
-            &temp,
-            "wasix-runtime.toml",
-            "liboliphaunt-wasix",
-            "0.1.0",
-            "wasix-runtime",
-            "portable",
-            None,
-            "oliphaunt.wasix.tar.zst",
-        );
-        let tools_manifest = write_artifact_manifest(
-            &temp,
-            "wasix-tools.toml",
-            "oliphaunt-wasix-tools",
-            "0.1.0",
-            "wasix-tools",
-            "portable",
-            None,
-            "bin/pg_dump.wasix.wasm",
-        );
-        let aot_manifest = write_artifact_manifest(
-            &temp,
-            "wasix-aot.toml",
-            "liboliphaunt-wasix",
-            "0.1.0",
-            "wasix-aot",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "oliphaunt-llvm-opta.bin.zst",
-        );
-        let tools_aot_manifest = write_artifact_manifest(
-            &temp,
-            "wasix-tools-aot.toml",
-            "oliphaunt-wasix-tools",
-            "0.1.0",
-            "wasix-tools-aot",
-            "x86_64-unknown-linux-gnu",
-            None,
-            "pg_dump-llvm-opta.bin.zst",
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![
-                runtime_manifest,
-                tools_manifest,
-                aot_manifest,
-                tools_aot_manifest,
-            ],
-        };
-
-        let output = context
-            .configure()
-            .expect("WASIX tools feature should stage split tools artifacts");
-
-        let lock = fs::read_to_string(output.lock_file).unwrap();
-        assert!(lock.contains("product = \"oliphaunt-wasix-tools\""));
-        assert!(lock.contains("kind = \"wasix-tools-aot\""));
-        assert!(
-            output
-                .resources_dir
-                .join("wasix-tools/oliphaunt-wasix-tools/bin/pg_dump.wasix.wasm")
-                .is_file()
-        );
-        assert!(
-            output
-                .resources_dir
-                .join("wasix-tools/oliphaunt-wasix-tools/bin/psql.wasix.wasm")
-                .is_file()
-        );
-        assert!(
-            output
-                .resources_dir
-                .join("wasix-tools-aot/oliphaunt-wasix-tools/pg_dump-llvm-opta.bin.zst")
-                .is_file()
-        );
-    }
-
-    #[test]
-    fn artifact_manifest_rejects_incomplete_native_tools_payload() {
-        let required = [
-            "runtime/bin/pg_basebackup",
-            "runtime/bin/pg_dump",
-            "runtime/bin/psql",
-        ];
-        for missing in required {
-            let temp = app_with_metadata("");
-            let present = required
-                .iter()
-                .copied()
-                .filter(|relative| *relative != missing)
-                .collect::>();
-            let tools_manifest = write_artifact_manifest_with_relatives(
-                &temp,
-                "tools.toml",
-                "oliphaunt-tools",
-                "0.1.0",
-                "native-tools",
-                "x86_64-unknown-linux-gnu",
-                None,
-                &present,
-            );
-            let context = BuildContext {
-                manifest_dir: temp.path().to_path_buf(),
-                out_dir: temp.path().join("out"),
-                target: "x86_64-unknown-linux-gnu".to_owned(),
-                artifact_manifest_paths: vec![tools_manifest],
-            };
-
-            let error = context
-                .read_artifact_manifests()
-                .expect_err("incomplete native tools must fail validation");
-
-            assert!(error.to_string().contains("missing required payload"));
-            assert!(error.to_string().contains(missing));
-        }
-    }
-
-    #[test]
-    fn artifact_manifest_rejects_native_runtime_client_tool_payloads() {
-        for tool in [
-            "runtime/bin/pg_basebackup",
-            "runtime/bin/pg_dump",
-            "runtime/bin/psql",
-        ] {
-            let temp = app_with_metadata("");
-            let runtime_manifest = write_artifact_manifest_with_relatives(
-                &temp,
-                "runtime.toml",
-                "liboliphaunt-native",
-                "0.1.0",
-                "native-runtime",
-                "x86_64-unknown-linux-gnu",
-                None,
-                &[
-                    "runtime/bin/postgres",
-                    "runtime/bin/initdb",
-                    "runtime/bin/pg_ctl",
-                    tool,
-                    "cluster-seed/manifest.properties",
-                    "cluster-seed/files/PG_VERSION",
-                    "cluster-seed/files/global/pg_control",
-                    "cluster-seed-icu/manifest.properties",
-                    "cluster-seed-icu/files/PG_VERSION",
-                    "cluster-seed-icu/files/global/pg_control",
-                ],
-            );
-            let context = BuildContext {
-                manifest_dir: temp.path().to_path_buf(),
-                out_dir: temp.path().join("out"),
-                target: "x86_64-unknown-linux-gnu".to_owned(),
-                artifact_manifest_paths: vec![runtime_manifest],
-            };
-
-            let error = context
-                .read_artifact_manifests()
-                .expect_err("native runtime must not contain split client tools");
-
-            assert!(error.to_string().contains("must not contain payload"));
-            assert!(error.to_string().contains(tool));
-        }
-    }
-
-    #[test]
-    fn artifact_manifest_accepts_windows_native_split_payloads() {
-        let temp = app_with_metadata("");
-        let runtime_manifest = write_artifact_manifest_with_relatives(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-pc-windows-msvc",
-            None,
-            &[
-                "runtime/bin/postgres.exe",
-                "runtime/bin/initdb.exe",
-                "runtime/bin/pg_ctl.exe",
-                "cluster-seed/manifest.properties",
-                "cluster-seed/files/PG_VERSION",
-                "cluster-seed/files/global/pg_control",
-                "cluster-seed-icu/manifest.properties",
-                "cluster-seed-icu/files/PG_VERSION",
-                "cluster-seed-icu/files/global/pg_control",
-            ],
-        );
-        let tools_manifest = write_artifact_manifest_with_relatives(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-pc-windows-msvc",
-            None,
-            &[
-                "runtime/bin/pg_basebackup.exe",
-                "runtime/bin/pg_dump.exe",
-                "runtime/bin/psql.exe",
-            ],
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-pc-windows-msvc".to_owned(),
-            artifact_manifest_paths: vec![runtime_manifest, tools_manifest],
-        };
-
-        let manifests = context
-            .read_artifact_manifests()
-            .expect("Windows native runtime/tools split should validate");
-
-        assert_eq!(manifests.len(), 2);
-    }
-
-    #[test]
-    fn artifact_manifest_rejects_linux_native_runtime_with_windows_tool_names() {
-        let temp = app_with_metadata("");
-        let runtime_manifest = write_artifact_manifest_with_relatives(
-            &temp,
-            "runtime.toml",
-            "liboliphaunt-native",
-            "0.1.0",
-            "native-runtime",
-            "x86_64-unknown-linux-gnu",
-            None,
-            &[
-                "runtime/bin/postgres.exe",
-                "runtime/bin/initdb.exe",
-                "runtime/bin/pg_ctl.exe",
-                "cluster-seed/manifest.properties",
-                "cluster-seed/files/PG_VERSION",
-                "cluster-seed/files/global/pg_control",
-                "cluster-seed-icu/manifest.properties",
-                "cluster-seed-icu/files/PG_VERSION",
-                "cluster-seed-icu/files/global/pg_control",
-            ],
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-unknown-linux-gnu".to_owned(),
-            artifact_manifest_paths: vec![runtime_manifest],
-        };
-
-        let error = context
-            .read_artifact_manifests()
-            .expect_err("Linux native runtime must use Unix tool names");
-
-        assert!(error.to_string().contains("missing required payload"));
-        assert!(error.to_string().contains("runtime/bin/postgres"));
-    }
-
-    #[test]
-    fn artifact_manifest_rejects_windows_native_tools_with_unix_tool_names() {
-        let temp = app_with_metadata("");
-        let tools_manifest = write_artifact_manifest_with_relatives(
-            &temp,
-            "tools.toml",
-            "oliphaunt-tools",
-            "0.1.0",
-            "native-tools",
-            "x86_64-pc-windows-msvc",
-            None,
-            &[
-                "runtime/bin/pg_basebackup",
-                "runtime/bin/pg_dump",
-                "runtime/bin/psql",
-            ],
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "x86_64-pc-windows-msvc".to_owned(),
-            artifact_manifest_paths: vec![tools_manifest],
-        };
-
-        let error = context
-            .read_artifact_manifests()
-            .expect_err("Windows native tools must use .exe tool names");
-
-        assert!(error.to_string().contains("missing required payload"));
-        assert!(error.to_string().contains("runtime/bin/pg_basebackup.exe"));
-    }
-
-    #[test]
-    fn artifact_manifest_rejects_wasix_runtime_client_tool_payloads() {
-        for tool in ["bin/pg_dump.wasix.wasm", "bin/psql.wasix.wasm"] {
-            let temp = app_with_metadata("");
-            let runtime_manifest = write_artifact_manifest_with_relatives(
-                &temp,
-                "wasix-runtime.toml",
-                "liboliphaunt-wasix",
-                "0.1.0",
-                "wasix-runtime",
-                "portable",
-                None,
-                &[
-                    "oliphaunt.wasix.tar.zst",
-                    "bin/initdb.wasix.wasm",
-                    "cluster-seeds/standard.tar.zst",
-                    "cluster-seeds/standard.json",
-                    "cluster-seeds/icu.tar.zst",
-                    "cluster-seeds/icu.json",
-                    tool,
-                ],
-            );
-            let context = BuildContext {
-                manifest_dir: temp.path().to_path_buf(),
-                out_dir: temp.path().join("out"),
-                target: "wasm32-wasip1".to_owned(),
-                artifact_manifest_paths: vec![runtime_manifest],
-            };
-
-            let error = context
-                .read_artifact_manifests()
-                .expect_err("WASIX runtime must not contain split client tools");
-
-            assert!(error.to_string().contains("must not contain payload"));
-            assert!(error.to_string().contains(tool));
-        }
-    }
-
-    #[test]
-    fn artifact_manifest_rejects_wasix_pg_ctl_tool_payload() {
-        let temp = app_with_metadata("");
-        let tools_manifest = write_artifact_manifest_with_relatives(
-            &temp,
-            "wasix-tools.toml",
-            "oliphaunt-wasix-tools",
-            "0.1.0",
-            "wasix-tools",
-            "portable",
-            None,
-            &[
-                "bin/pg_dump.wasix.wasm",
-                "bin/psql.wasix.wasm",
-                "bin/pg_ctl.wasix.wasm",
-            ],
-        );
-        let context = BuildContext {
-            manifest_dir: temp.path().to_path_buf(),
-            out_dir: temp.path().join("out"),
-            target: "wasm32-wasip1".to_owned(),
-            artifact_manifest_paths: vec![tools_manifest],
-        };
-
-        let error = context
-            .read_artifact_manifests()
-            .expect_err("WASIX tools must not contain pg_ctl");
-
-        assert!(error.to_string().contains("must not contain payload"));
-        assert!(error.to_string().contains("bin/pg_ctl.wasix.wasm"));
-    }
-
-    fn app_with_metadata(metadata: &str) -> TempDir {
-        let temp = TempDir::new().unwrap();
-        let manifest = format!(
-            r#"[package]
-name = "app"
-version = "0.1.0"
-edition = "2024"
-{metadata}
-"#,
-        );
-        fs::write(temp.path().join("Cargo.toml"), manifest).unwrap();
-        temp
-    }
-
-    #[allow(clippy::too_many_arguments)] // Test fixture fields mirror the artifact manifest schema.
-    fn write_artifact_manifest(
-        temp: &TempDir,
-        manifest_name: &str,
-        product: &str,
-        version: &str,
-        kind: &str,
-        target: &str,
-        extension: Option<&str>,
-        relative: &str,
-    ) -> PathBuf {
-        let relatives = test_artifact_relatives(kind, relative);
-        let relative_refs: Vec<&str> = relatives.iter().map(String::as_str).collect();
-        write_artifact_manifest_with_relatives(
-            temp,
-            manifest_name,
-            product,
-            version,
-            kind,
-            target,
-            extension,
-            &relative_refs,
-        )
-    }
-
-    #[allow(clippy::too_many_arguments)] // Test fixture fields mirror the artifact manifest schema.
-    fn write_artifact_manifest_with_relatives(
-        temp: &TempDir,
-        manifest_name: &str,
-        product: &str,
-        version: &str,
-        kind: &str,
-        target: &str,
-        extension: Option<&str>,
-        relatives: &[&str],
-    ) -> PathBuf {
-        let extension_line = extension
-            .map(|value| format!("extension = {value:?}\n"))
-            .unwrap_or_default();
-        let runtime_binding = if kind == "extension" {
-            let app: toml::Value =
-                toml::from_str(&fs::read_to_string(temp.path().join("Cargo.toml")).unwrap())
-                    .unwrap();
-            let metadata = &app["package"]["metadata"]["oliphaunt"];
-            format!(
-                "runtime-product = {:?}\nruntime-version = {:?}\ndependencies = []\n",
-                metadata["runtime"].as_str().unwrap(),
-                metadata["runtime-version"].as_str().unwrap()
-            )
-        } else {
-            String::new()
-        };
-        let mut manifest = format!(
-            r#"schema = "oliphaunt-artifact-manifest-v1"
-product = {product:?}
-version = {version:?}
-kind = {kind:?}
-target = {target:?}
-{runtime_binding}
-{extension_line}
-"#,
-        );
-        let source_root = temp.path().join("artifacts").join(manifest_name);
-        for relative in relatives {
-            let source = source_root.join(relative.replace(['/', '\\'], "_"));
-            fs::create_dir_all(source.parent().unwrap()).unwrap();
-            let mut file = fs::File::create(&source).unwrap();
-            write!(file, "{product}:{kind}:{target}:{relative}").unwrap();
-            let bytes = fs::read(&source).unwrap();
-            let sha256 = sha256_hex(&bytes);
-            manifest.push_str(&format!(
-                r#"
-[[files]]
-source = "{}"
-relative = {relative:?}
-sha256 = {sha256:?}
-executable = true
-"#,
-                source.display(),
-            ));
-        }
-        let path = temp.path().join(manifest_name);
-        fs::write(&path, manifest).unwrap();
-        path
-    }
-
-    fn write_bundle_artifact_manifest(
-        temp: &TempDir,
-        manifest_name: &str,
-        product: &str,
-        version: &str,
-        target: &str,
-        extensions: &[&str],
-    ) -> PathBuf {
-        let app: toml::Value =
-            toml::from_str(&fs::read_to_string(temp.path().join("Cargo.toml")).unwrap()).unwrap();
-        let metadata = &app["package"]["metadata"]["oliphaunt"];
-        let runtime_product = metadata["runtime"].as_str().unwrap();
-        let runtime_version = metadata["runtime-version"].as_str().unwrap();
-        let mut manifest = format!(
-            r#"schema = "oliphaunt-artifact-manifest-v2"
-product = {product:?}
-version = {version:?}
-kind = "extension"
-target = {target:?}
-runtime-product = {runtime_product:?}
-runtime-version = {runtime_version:?}
-"#,
-        );
-        for extension in extensions {
-            let dependencies: Vec<&str> = if *extension == "earthdistance" {
-                vec!["cube"]
-            } else {
-                Vec::new()
-            };
-            let relative = format!("share/postgresql/extension/{extension}.control");
-            let source = temp
-                .path()
-                .join("artifacts")
-                .join(manifest_name)
-                .join(format!("{extension}.control"));
-            fs::create_dir_all(source.parent().unwrap()).unwrap();
-            fs::write(&source, format!("{product}:{extension}")).unwrap();
-            let sha256 = sha256_hex(&fs::read(&source).unwrap());
-            manifest.push_str(&format!(
-                r#"
-[[extensions]]
-extension = {extension:?}
-dependencies = {dependencies:?}
-
-[[extensions.files]]
-source = "{}"
-relative = {relative:?}
-sha256 = {sha256:?}
-executable = false
-"#,
-                source.display(),
-            ));
-        }
-        let path = temp.path().join(manifest_name);
-        fs::write(&path, manifest).unwrap();
-        path
-    }
-
-    fn test_artifact_relatives(kind: &str, primary: &str) -> Vec {
-        let mut relatives = match kind {
-            "native-runtime" => vec![
-                "runtime/bin/postgres".to_owned(),
-                "runtime/bin/initdb".to_owned(),
-                "runtime/bin/pg_ctl".to_owned(),
-                "cluster-seed/manifest.properties".to_owned(),
-                "cluster-seed/files/PG_VERSION".to_owned(),
-                "cluster-seed/files/global/pg_control".to_owned(),
-                "cluster-seed-icu/manifest.properties".to_owned(),
-                "cluster-seed-icu/files/PG_VERSION".to_owned(),
-                "cluster-seed-icu/files/global/pg_control".to_owned(),
-            ],
-            "native-tools" => vec![
-                "runtime/bin/pg_basebackup".to_owned(),
-                "runtime/bin/pg_dump".to_owned(),
-                "runtime/bin/psql".to_owned(),
-            ],
-            "wasix-runtime" => vec![
-                "manifest.json".to_owned(),
-                "oliphaunt.wasix.tar.zst".to_owned(),
-                "cluster-seeds/standard.tar.zst".to_owned(),
-                "cluster-seeds/standard.json".to_owned(),
-                "cluster-seeds/icu.tar.zst".to_owned(),
-                "cluster-seeds/icu.json".to_owned(),
-                "bin/initdb.wasix.wasm".to_owned(),
-            ],
-            "wasix-tools" => vec![
-                "bin/pg_dump.wasix.wasm".to_owned(),
-                "bin/psql.wasix.wasm".to_owned(),
-            ],
-            "wasix-aot" => vec![
-                "manifest.json".to_owned(),
-                "oliphaunt-llvm-opta.bin.zst".to_owned(),
-                "initdb-llvm-opta.bin.zst".to_owned(),
-            ],
-            "wasix-tools-aot" => vec![
-                "manifest.json".to_owned(),
-                "pg_dump-llvm-opta.bin.zst".to_owned(),
-                "psql-llvm-opta.bin.zst".to_owned(),
-            ],
-            _ => vec![primary.to_owned()],
-        };
-        if !relatives.iter().any(|relative| relative == primary) {
-            relatives.push(primary.to_owned());
-        }
-        relatives
-    }
-}
diff --git a/src/sdks/rust/liboliphaunt-native/CHANGELOG.md b/src/sdks/rust/liboliphaunt-native/CHANGELOG.md
new file mode 100644
index 000000000..c72f5e553
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## Unreleased
+
+- Extract native execution, cancellation, backups, and database resource preparation into a shared Rust package.
diff --git a/src/sdks/rust/liboliphaunt-native/Cargo.toml b/src/sdks/rust/liboliphaunt-native/Cargo.toml
new file mode 100644
index 000000000..2e7d3609d
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "liboliphaunt-native-bindings"
+version = "0.1.0"
+edition.workspace = true
+rust-version.workspace = true
+repository.workspace = true
+homepage.workspace = true
+license.workspace = true
+description = "Rust bindings and database resource management for native liboliphaunt."
+readme = "README.md"
+exclude = ["moon.yml", "release.toml", "tools/**"]
+[features]
+internal-native-packaging = []
+[dependencies]
+fs2 = "0.4"
+getrandom = "0.3"
+libloading = "0.8"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+sha2 = "0.10"
+tar = "0.4"
+zstd = { version = "0.13", default-features = false }
diff --git a/src/sdks/rust/liboliphaunt-native/LICENSE b/src/sdks/rust/liboliphaunt-native/LICENSE
new file mode 120000
index 000000000..147761543
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/LICENSE
@@ -0,0 +1 @@
+../../../../LICENSE
\ No newline at end of file
diff --git a/src/sdks/rust/liboliphaunt-native/README.md b/src/sdks/rust/liboliphaunt-native/README.md
new file mode 100644
index 000000000..206c5d50f
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/README.md
@@ -0,0 +1,54 @@
+# liboliphaunt-native-bindings
+
+Native liboliphaunt sessions, cancellation, raw PostgreSQL protocol execution, physical backups, and database resource preparation. The Rust SDK and broker consume this crate. Server process management and broker transport belong to their respective products.
+
+`NativeConfig::default()` selects no seed or ICU data. New roots use the prepared
+runtime's `initdb`; existing roots retain their catalog. `NativeClusterSeed::new`
+accepts an explicit seed carrier's `seed_archive()` and `seed_manifest()` bytes.
+`NativeClusterSeed::Directory` accepts an unpacked native seed directory and its
+receipt. `NativeResourceDirectory` supplies explicit ICU data and its receipt.
+These types are also reexported by the public Rust SDK, whose builders expose
+`seed` and `icu_data`. The broker uses the same guarded initialization.
+
+The ignored `resource_selection` integration test requires an actual native
+runtime plus selected resources. Set `LIBOLIPHAUNT_PATH`, `OLIPHAUNT_INSTALL_DIR`,
+`OLIPHAUNT_EMBEDDED_MODULE_DIR`, `OLIPHAUNT_TEST_STANDARD_SEED` and
+`OLIPHAUNT_TEST_ICU_SEED` (carrier directories containing `seed.tar.zst` and
+`manifest.json`), and `OLIPHAUNT_TEST_ICU_DATA` / `OLIPHAUNT_TEST_ICU_MANIFEST`.
+Run each profile in its own process because native terminal shutdown is final:
+
+```sh
+for profile in standard icu; do
+  OLIPHAUNT_TEST_PROFILE="$profile" cargo test --locked --test resource_selection -- --ignored
+done
+```
+
+It verifies actual seeded queries, ICU collation, seedless initialization,
+reopening without usable seed input, and corrupt-input rejection before PGDATA
+publication. Missing resource inputs fail this explicit command.
+
+`NativeSession::protocol_input()` resolves concurrent input support for a running
+raw protocol stream. Its cloned handle reports the active stream token and feeds
+complete frontend frames to that exact stream; a full native queue returns
+`false` without consuming bytes. Detached sessions and stale stream tokens fail.
+With `LIBOLIPHAUNT_PATH` and `OLIPHAUNT_INSTALL_DIR` pointing to a prepared native
+runtime, run `cargo test --locked --test protocol_input -- --ignored`. This proves
+extended-query Flush followed by a later Sync, incremental COPY FROM STDIN,
+malformed input rejection, and rejection of input from an earlier stream.
+
+## Maintainer commands
+
+Run these commands from this directory with the repository-pinned Rust toolchain, Moon and Bun available. Cargo resolves versioned workspace dependencies itself; no runtime build is needed for source tests. Bash is required for package staging (Git Bash on Windows). The initial locked Cargo fetch needs network access.
+
+| Command | Result |
+| --- | --- |
+| `moon run liboliphaunt-native-bindings:format` | Rewrite Rust formatting. |
+| `moon run liboliphaunt-native-bindings:format-check` | Check formatting without changing files. |
+| `moon run liboliphaunt-native-bindings:lint` | Clippy diagnostics for all targets; no database execution. |
+| `moon run liboliphaunt-native-bindings:build` | Compile this project and its Cargo dependencies. |
+| `moon run liboliphaunt-native-bindings:test` | Run source tests; Cargo compiles the required test targets. |
+| `moon run liboliphaunt-native-bindings:package` | Stage distributable source crates under target/sdk-artifacts/liboliphaunt-native-bindings; repeated runs replace this owner’s candidates. |
+
+Native Cargo entry points remain available: `cargo build -p liboliphaunt-native-bindings --locked`, `cargo test -p liboliphaunt-native-bindings --locked`, `cargo clippy -p liboliphaunt-native-bindings --all-targets --locked -- -D warnings`, and `cargo fmt -p liboliphaunt-native-bindings --check`. Moon supplies the additional source-test feature matrix and artifact staging where defined. `package` assembles bytes; it does not run the project test suite.
+
+The native SDK’s `moon run oliphaunt-rust:test-consumer` installs the real packed query, bindings and broker crates together with the SDK. This tests their public dependency closure without duplicate per-crate consumer harnesses.
diff --git a/src/sdks/rust/liboliphaunt-native/THIRD_PARTY_NOTICES.md b/src/sdks/rust/liboliphaunt-native/THIRD_PARTY_NOTICES.md
new file mode 120000
index 000000000..c8c7cb76e
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/THIRD_PARTY_NOTICES.md
@@ -0,0 +1 @@
+../../../../THIRD_PARTY_NOTICES.md
\ No newline at end of file
diff --git a/src/sdks/rust/liboliphaunt-native/moon.yml b/src/sdks/rust/liboliphaunt-native/moon.yml
new file mode 100644
index 000000000..b595f965f
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/moon.yml
@@ -0,0 +1,67 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+id: "liboliphaunt-native-bindings"
+language: "rust"
+layer: "library"
+stack: "systems"
+tags: ["cargo-package", "rust", "sdk", "native", "release-product"]
+dependsOn:
+  - id: "extensions"
+    scope: "build"
+  - id: "shared-test-fixtures"
+    scope: "development"
+project:
+  title: "Native liboliphaunt Rust bindings"
+  description: "Shared native sessions and database resource preparation."
+  owner: "oliphaunt"
+  release:
+    component: "liboliphaunt-native-bindings"
+    packagePath: "src/sdks/rust/liboliphaunt-native"
+fileGroups:
+  sources: ["src/**/*", "Cargo.toml"]
+  code: ["src/**/*", "tests/**/*", "Cargo.toml"]
+tasks:
+  format:
+    command: "cargo fmt"
+    options:
+      cache: false
+      runInCI: false
+
+  format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt --check"
+    inputs: ["@group(code)"]
+  lint:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy --all-targets --locked -- -D warnings"
+    inputs: ["@group(code)", "/Cargo.lock", "/Cargo.toml"]
+  build:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["build", "requires-rust"]
+    command: "cargo build --locked"
+    outputs: ["/target/debug/libliboliphaunt_native_bindings.rlib"]
+    inputs: ["@group(code)", "/Cargo.lock", "/Cargo.toml"]
+  test:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "unit", "requires-rust"]
+    command: "cargo test --locked"
+    inputs: ["@group(code)", "testdata/**/*", "/Cargo.lock", "/Cargo.toml"]
+  package:
+    tags: ["release", "artifact-package", "ci-rust-sdk-package"]
+    script: |
+      set -eu
+      version="$(bun ../../../../tools/release/product-version.mts version liboliphaunt-native-bindings)"
+      rm -f "../../../../target/package/liboliphaunt-native-bindings-$version.crate"
+      cargo package --locked --allow-dirty --no-verify
+      rm -rf ../../../../target/sdk-artifacts/liboliphaunt-native-bindings
+      mkdir -p ../../../../target/sdk-artifacts/liboliphaunt-native-bindings
+      cp "../../../../target/package/liboliphaunt-native-bindings-$version.crate" ../../../../target/sdk-artifacts/liboliphaunt-native-bindings/
+      bun ../../../../tools/packaging/staging.mts ../../../../target/sdk-artifacts/liboliphaunt-native-bindings
+    inputs: ["**/*", "/Cargo.lock", "/Cargo.toml", "/LICENSE", "/THIRD_PARTY_NOTICES.md"]
+    outputs: ["/target/sdk-artifacts/liboliphaunt-native-bindings/**/*"]
diff --git a/src/sdks/rust/liboliphaunt-native/release.toml b/src/sdks/rust/liboliphaunt-native/release.toml
new file mode 100644
index 000000000..e7c2aaebd
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/release.toml
@@ -0,0 +1,6 @@
+id = "liboliphaunt-native-bindings"
+owner = "@oliphaunt/sdk-rust"
+kind = "sdk"
+publish_targets = ["crates-io"]
+registry_packages = ["crates:liboliphaunt-native-bindings"]
+release_artifacts = ["cargo-crate"]
diff --git a/src/sdks/rust/liboliphaunt-native/src/build_resources.rs b/src/sdks/rust/liboliphaunt-native/src/build_resources.rs
new file mode 100644
index 000000000..084b8d48f
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/build_resources.rs
@@ -0,0 +1,76 @@
+use std::path::PathBuf;
+use std::sync::{OnceLock, RwLock};
+
+use crate::error::{Error, Result};
+
+static BUILD_RESOURCES_DIR: OnceLock>> = OnceLock::new();
+
+/// Register the Oliphaunt resource directory staged by `oliphaunt-build`.
+///
+/// Applications usually call their SDK registration macro once during startup
+/// after their `build.rs` has called `oliphaunt_build::configure()`. The native
+/// runtime locator uses this directory before falling back to
+/// `OLIPHAUNT_RESOURCES_DIR` and source-tree build layouts. Explicit library
+/// and install-directory environment overrides retain precedence.
+pub fn register_build_resources_dir(path: impl Into) -> Result<()> {
+    let path = path.into();
+    if path.as_os_str().is_empty() {
+        return Err(Error::InvalidConfig(
+            "Oliphaunt build resources directory cannot be empty".to_owned(),
+        ));
+    }
+
+    let lock = BUILD_RESOURCES_DIR.get_or_init(|| RwLock::new(None));
+    let mut guard = lock
+        .write()
+        .map_err(|_| Error::Engine("Oliphaunt build resources registry was poisoned".to_owned()))?;
+    if let Some(existing) = guard.as_ref() {
+        if existing == &path {
+            return Ok(());
+        }
+        return Err(Error::InvalidConfig(format!(
+            "Oliphaunt build resources are already registered as {}; cannot replace them with {}",
+            existing.display(),
+            path.display()
+        )));
+    }
+    *guard = Some(path);
+    Ok(())
+}
+
+pub fn registered_build_resources_dir() -> Option {
+    BUILD_RESOURCES_DIR
+        .get()
+        .and_then(|lock| lock.read().ok().and_then(|guard| guard.clone()))
+}
+
+pub(crate) fn resources_dir_candidates() -> Vec {
+    registered_build_resources_dir()
+        .into_iter()
+        .chain(std::env::var_os("OLIPHAUNT_RESOURCES_DIR").map(PathBuf::from))
+        .collect()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn resource_registration_is_immutable_and_idempotent() {
+        assert!(matches!(
+            register_build_resources_dir(""),
+            Err(Error::InvalidConfig(_))
+        ));
+        assert_eq!(registered_build_resources_dir(), None);
+        register_build_resources_dir("application-resources").unwrap();
+        register_build_resources_dir("application-resources").unwrap();
+        assert!(matches!(
+            register_build_resources_dir("different-resources"),
+            Err(Error::InvalidConfig(_))
+        ));
+        assert_eq!(
+            registered_build_resources_dir(),
+            Some(PathBuf::from("application-resources"))
+        );
+    }
+}
diff --git a/src/sdks/rust/liboliphaunt-native/src/config.rs b/src/sdks/rust/liboliphaunt-native/src/config.rs
new file mode 100644
index 000000000..8894c17dc
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/config.rs
@@ -0,0 +1,235 @@
+use crate::extension::resolve_extensions;
+use crate::storage::path_contains_nul;
+use crate::{DatabaseStorage, Error, Extension, Result};
+use std::collections::BTreeSet;
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
+pub const DEFAULT_USERNAME: &str = "postgres";
+pub const DEFAULT_DATABASE: &str = "postgres";
+/// Explicit PostgreSQL startup GUC override.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct PostgresStartupGuc {
+    /// PostgreSQL GUC name, such as `shared_buffers`.
+    pub name: String,
+    /// PostgreSQL GUC value, such as `32MB`.
+    pub value: String,
+}
+
+impl PostgresStartupGuc {
+    /// Create a startup GUC override.
+    pub fn new(name: impl Into, value: impl Into) -> Self {
+        Self {
+            name: name.into(),
+            value: value.into(),
+        }
+    }
+
+    fn startup_assignment(&self) -> String {
+        format!("{}={}", self.name.trim(), self.value)
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+/// An explicitly selected resource tree and the receipt describing its bytes.
+pub struct NativeResourceDirectory {
+    /// Root directory of PGDATA or ICU data files.
+    pub directory: PathBuf,
+    /// Seed JSON or ICU properties receipt supplied by the resource package.
+    pub manifest: PathBuf,
+}
+
+/// Independently selected seed bytes (Cargo) or a producer-unpacked directory.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum NativeClusterSeed {
+    /// Compressed native PGDATA and its independently packaged JSON receipt.
+    Archive {
+        /// Zstandard-compressed tar archive.
+        archive: Arc<[u8]>,
+        /// UTF-8 cluster-seed JSON manifest.
+        manifest: Arc<[u8]>,
+    },
+    /// A package-manager-extracted native seed directory.
+    Directory(NativeResourceDirectory),
+}
+
+impl NativeClusterSeed {
+    /// Select a Cargo carrier's `seed_archive()` and `seed_manifest()` outputs.
+    pub fn new(archive: impl Into>, manifest: impl AsRef<[u8]>) -> Self {
+        Self::Archive {
+            archive: archive.into(),
+            manifest: Arc::from(manifest.as_ref()),
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NativeConfig {
+    pub storage: DatabaseStorage,
+    pub startup_gucs: Vec,
+    pub username: String,
+    pub database: String,
+    pub extensions: Vec,
+    /// Initialization input for a new embedded database; ignored for existing roots.
+    pub seed: Option,
+    /// Explicit ICU data used by both initialization and database execution.
+    pub icu_data: Option,
+}
+impl Default for NativeConfig {
+    fn default() -> Self {
+        Self {
+            storage: DatabaseStorage::default(),
+            startup_gucs: Vec::new(),
+            username: DEFAULT_USERNAME.to_owned(),
+            database: DEFAULT_DATABASE.to_owned(),
+            extensions: Vec::new(),
+            seed: None,
+            icu_data: None,
+        }
+    }
+}
+impl NativeConfig {
+    pub fn direct(directory: impl Into) -> Self {
+        Self {
+            storage: DatabaseStorage::Directory(directory.into()),
+            ..Self::default()
+        }
+    }
+    pub fn validate(&self) -> Result<()> {
+        if let Some(NativeClusterSeed::Directory(resource)) = &self.seed {
+            validate_config_path("seed directory", &resource.directory)?;
+            validate_config_path("seed manifest", &resource.manifest)?;
+        }
+        if let Some(resource) = &self.icu_data {
+            validate_config_path("ICU data directory", &resource.directory)?;
+            validate_config_path("ICU data manifest", &resource.manifest)?;
+        }
+        for guc in &self.startup_gucs {
+            validate_postgres_startup_guc(guc)?;
+            let name = guc.name.trim();
+            if ["config_file", "data_directory"]
+                .iter()
+                .any(|owned| name.eq_ignore_ascii_case(owned))
+            {
+                return Err(Error::InvalidConfig(format!(
+                    "Oliphaunt owns PostgreSQL startup GUC '{name}'; configure the database through Oliphaunt's storage API"
+                )));
+            }
+        }
+        if let DatabaseStorage::Directory(directory) = &self.storage {
+            validate_config_path("database storage directory", directory)?;
+        }
+        validate_startup_identity("username", &self.username)?;
+        validate_startup_identity("database", &self.database)?;
+        let _ = self.resolved_extensions()?;
+        Ok(())
+    }
+    pub fn resolved_extensions(&self) -> Result> {
+        resolve_extensions(&self.extensions)
+    }
+
+    pub fn postgres_startup_assignments(&self, extensions: &[Extension]) -> Vec {
+        let required_preloads = crate::extension::required_shared_preload_libraries(extensions);
+        if required_preloads.is_empty() {
+            return self
+                .startup_gucs
+                .iter()
+                .map(PostgresStartupGuc::startup_assignment)
+                .collect();
+        }
+
+        let configured_preloads = self
+            .startup_gucs
+            .iter()
+            .rev()
+            .find(|guc| {
+                guc.name
+                    .trim()
+                    .eq_ignore_ascii_case("shared_preload_libraries")
+            })
+            .map(|guc| guc.value.as_str());
+        let mut preloads = Vec::new();
+        let mut seen = BTreeSet::new();
+        if let Some(configured) = configured_preloads {
+            append_unique_csv_values(configured, &mut preloads, &mut seen);
+        }
+        for required in required_preloads {
+            append_unique_csv_values(required, &mut preloads, &mut seen);
+        }
+
+        let mut assignments = self
+            .startup_gucs
+            .iter()
+            .filter(|guc| {
+                !guc.name
+                    .trim()
+                    .eq_ignore_ascii_case("shared_preload_libraries")
+            })
+            .map(PostgresStartupGuc::startup_assignment)
+            .collect::>();
+        assignments.push(format!("shared_preload_libraries={}", preloads.join(",")));
+        assignments
+    }
+}
+
+fn append_unique_csv_values(value: &str, ordered: &mut Vec, seen: &mut BTreeSet) {
+    for item in value
+        .split(',')
+        .map(str::trim)
+        .filter(|item| !item.is_empty())
+    {
+        if seen.insert(item.to_owned()) {
+            ordered.push(item.to_owned());
+        }
+    }
+}
+
+fn validate_config_path(label: &str, path: &Path) -> Result<()> {
+    if path.as_os_str().is_empty() {
+        return Err(Error::InvalidConfig(format!("{label} must not be empty")));
+    }
+    if path_contains_nul(path) {
+        return Err(Error::InvalidConfig(format!(
+            "{label} must not contain NUL bytes"
+        )));
+    }
+    Ok(())
+}
+
+fn validate_startup_identity(label: &str, value: &str) -> Result<()> {
+    if value.trim().is_empty() {
+        return Err(Error::InvalidConfig(format!("{label} must not be empty")));
+    }
+    if value.as_bytes().contains(&0) {
+        return Err(Error::InvalidConfig(format!(
+            "{label} must not contain NUL bytes"
+        )));
+    }
+    Ok(())
+}
+
+fn validate_postgres_startup_guc(guc: &PostgresStartupGuc) -> Result<()> {
+    let name = guc.name.trim();
+    if name.is_empty() {
+        return Err(Error::InvalidConfig(
+            "PostgreSQL startup GUC name must not be empty".to_owned(),
+        ));
+    }
+    if name.as_bytes().contains(&0) || guc.value.as_bytes().contains(&0) {
+        return Err(Error::InvalidConfig(
+            "PostgreSQL startup GUC must not contain NUL bytes".to_owned(),
+        ));
+    }
+    if !name.split('.').all(|component| {
+        let mut bytes = component.bytes();
+        bytes
+            .next()
+            .is_some_and(|byte| byte.is_ascii_alphabetic() || byte == b'_')
+            && bytes.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'$'))
+    }) {
+        return Err(Error::InvalidConfig(format!(
+            "PostgreSQL startup GUC name '{}': each dot-separated component must start with an ASCII letter or '_', followed by ASCII letters, digits, '_', or '$'",
+            guc.name
+        )));
+    }
+    Ok(())
+}
diff --git a/src/sdks/rust/liboliphaunt-native/src/error.rs b/src/sdks/rust/liboliphaunt-native/src/error.rs
new file mode 100644
index 000000000..ddb7fd7d9
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/error.rs
@@ -0,0 +1,16 @@
+pub type Result = std::result::Result;
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Error {
+    InvalidConfig(String),
+    Engine(String),
+    EngineStopped,
+}
+impl std::fmt::Display for Error {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::InvalidConfig(s) | Self::Engine(s) => f.write_str(s),
+            Self::EngineStopped => f.write_str("native session is closed"),
+        }
+    }
+}
+impl std::error::Error for Error {}
diff --git a/src/sdks/rust/liboliphaunt-native/src/extension.rs b/src/sdks/rust/liboliphaunt-native/src/extension.rs
new file mode 100644
index 000000000..2417642bc
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/extension.rs
@@ -0,0 +1,151 @@
+use std::collections::BTreeSet;
+
+use crate::error::{Error, Result};
+
+#[path = "generated/extensions.rs"]
+mod generated_extensions;
+pub use generated_extensions::Extension;
+
+impl Extension {
+    /// SQL extension name used by `CREATE EXTENSION`.
+    pub const fn sql_name(self) -> &'static str {
+        generated_extensions::sql_name(self)
+    }
+
+    pub const fn native_module_stem(self) -> Option<&'static str> {
+        generated_extensions::native_module_stem(self)
+    }
+
+    pub fn native_module_file(self) -> Option {
+        self.native_module_stem()
+            .map(|stem| format!("{}{}", stem, std::env::consts::DLL_SUFFIX))
+    }
+
+    pub const fn creates_extension(self) -> bool {
+        generated_extensions::creates_extension(self)
+    }
+
+    pub const fn dependencies(self) -> &'static [Extension] {
+        generated_extensions::dependencies(self)
+    }
+
+    pub const fn required_shared_preload_library(self) -> Option<&'static str> {
+        generated_extensions::required_shared_preload_library(self)
+    }
+
+    /// Resolve an extension by SQL name.
+    pub fn by_sql_name(sql_name: &str) -> Option {
+        Self::ALL
+            .iter()
+            .copied()
+            .find(|extension| extension.sql_name() == sql_name)
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ExtensionRuntimeEnvironment {
+    pub name: &'static str,
+    pub relative_path: &'static str,
+    pub required_file: &'static str,
+}
+
+pub fn resolve_extensions(direct_extensions: &[Extension]) -> Result> {
+    let mut requested = Vec::new();
+    requested.extend_from_slice(direct_extensions);
+
+    let mut resolved = Vec::new();
+    let mut visiting = BTreeSet::new();
+    let mut visited = BTreeSet::new();
+    for extension in requested {
+        visit_extension(extension, &mut visiting, &mut visited, &mut resolved)?;
+    }
+    Ok(resolved)
+}
+
+pub fn required_shared_preload_libraries(extensions: &[Extension]) -> Vec<&'static str> {
+    extensions
+        .iter()
+        .filter_map(|extension| extension.required_shared_preload_library())
+        .collect::>()
+        .into_iter()
+        .collect()
+}
+
+fn visit_extension(
+    extension: Extension,
+    visiting: &mut BTreeSet,
+    visited: &mut BTreeSet,
+    resolved: &mut Vec,
+) -> Result<()> {
+    if visited.contains(&extension) {
+        return Ok(());
+    }
+    if !visiting.insert(extension) {
+        return Err(Error::InvalidConfig(format!(
+            "cyclic native extension dependency involving '{}'",
+            extension.sql_name()
+        )));
+    }
+    for dependency in extension.dependencies() {
+        visit_extension(*dependency, visiting, visited, resolved)?;
+    }
+    visiting.remove(&extension);
+    visited.insert(extension);
+    resolved.push(extension);
+    Ok(())
+}
+
+pub fn extension_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
+    file_name == format!("{sql_name}.control")
+        || file_name == format!("{sql_name}.sql")
+        || extension_install_sql_file_belongs(sql_name, file_name)
+        || extension_versioned_sql_file_belongs(sql_name, file_name)
+        || extension_extra_sql_file_belongs(sql_name, file_name)
+}
+
+fn extension_versioned_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
+    file_name
+        .strip_prefix(&format!("{sql_name}--"))
+        .and_then(|value| value.strip_suffix(".sql"))
+        .is_some_and(|version_path| {
+            !version_path.is_empty()
+                && version_path
+                    .bytes()
+                    .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
+        })
+}
+
+pub fn extension_install_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
+    let Some(version) = file_name
+        .strip_prefix(&format!("{sql_name}--"))
+        .and_then(|value| value.strip_suffix(".sql"))
+    else {
+        return false;
+    };
+    !version.is_empty()
+        && !version.contains("--")
+        && version.as_bytes()[0].is_ascii_digit()
+        && version
+            .bytes()
+            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
+}
+
+pub const fn extension_runtime_environment(
+    extension: Extension,
+) -> &'static [ExtensionRuntimeEnvironment] {
+    generated_extensions::runtime_environment(extension)
+}
+
+fn extension_extra_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
+    let Some(extension) = Extension::by_sql_name(sql_name) else {
+        return false;
+    };
+    generated_extensions::extension_sql_file_names(extension).contains(&file_name)
+        || generated_extensions::extension_sql_file_prefixes(extension)
+            .iter()
+            .any(|prefix| file_name.starts_with(prefix))
+}
+
+pub const fn extension_data_files(extension: Extension) -> &'static [&'static str] {
+    generated_extensions::extension_data_files(extension)
+}
diff --git a/src/sdks/rust/liboliphaunt-native/src/generated/extensions.rs b/src/sdks/rust/liboliphaunt-native/src/generated/extensions.rs
new file mode 100644
index 000000000..b9120b342
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/generated/extensions.rs
@@ -0,0 +1,719 @@
+// @generated by src/extensions/tools/check-extension-model.sh --write
+// Do not edit by hand.
+
+use super::ExtensionRuntimeEnvironment;
+
+/// Native PostgreSQL 18 extension artifact that can be selected by an app.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct Extension {
+    id: ExtensionId,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+enum ExtensionId {
+    /// PostgreSQL `amcheck`.
+    Amcheck,
+    /// PostgreSQL `auto_explain`.
+    AutoExplain,
+    /// PostgreSQL `bloom`.
+    Bloom,
+    /// PostgreSQL `btree_gin`.
+    BtreeGin,
+    /// PostgreSQL `btree_gist`.
+    BtreeGist,
+    /// PostgreSQL `citext`.
+    Citext,
+    /// PostgreSQL `cube`.
+    Cube,
+    /// PostgreSQL `dict_int`.
+    DictInt,
+    /// PostgreSQL `dict_xsyn`.
+    DictXsyn,
+    /// PostgreSQL `earthdistance`.
+    Earthdistance,
+    /// PostgreSQL `file_fdw`.
+    FileFdw,
+    /// PostgreSQL `fuzzystrmatch`.
+    Fuzzystrmatch,
+    /// PostgreSQL `hstore`.
+    Hstore,
+    /// PostgreSQL `intarray`.
+    Intarray,
+    /// PostgreSQL `isn`.
+    Isn,
+    /// PostgreSQL `lo`.
+    Lo,
+    /// PostgreSQL `ltree`.
+    Ltree,
+    /// PostgreSQL `pageinspect`.
+    Pageinspect,
+    /// PostgreSQL `pg_buffercache`.
+    PgBuffercache,
+    /// PostgreSQL `pg_freespacemap`.
+    PgFreespacemap,
+    /// PostgreSQL `pg_hashids`.
+    PgHashids,
+    /// PostgreSQL `pg_ivm`.
+    PgIvm,
+    /// PostgreSQL `pg_surgery`.
+    PgSurgery,
+    /// PostgreSQL `pg_textsearch`.
+    PgTextsearch,
+    /// PostgreSQL `pg_trgm`.
+    PgTrgm,
+    /// PostgreSQL `pg_uuidv7`.
+    PgUuidv7,
+    /// PostgreSQL `pg_visibility`.
+    PgVisibility,
+    /// PostgreSQL `pg_walinspect`.
+    PgWalinspect,
+    /// PostgreSQL `pgcrypto`.
+    Pgcrypto,
+    /// PostgreSQL `pgtap`.
+    Pgtap,
+    /// PostgreSQL `postgis`.
+    Postgis,
+    /// PostgreSQL `seg`.
+    Seg,
+    /// PostgreSQL `tablefunc`.
+    Tablefunc,
+    /// PostgreSQL `tcn`.
+    Tcn,
+    /// PostgreSQL `tsm_system_rows`.
+    TsmSystemRows,
+    /// PostgreSQL `tsm_system_time`.
+    TsmSystemTime,
+    /// PostgreSQL `unaccent`.
+    Unaccent,
+    /// PostgreSQL `uuid-ossp`.
+    UuidOssp,
+    /// PostgreSQL `vector`.
+    Vector,
+}
+
+impl Extension {
+    /// Select the `amcheck` artifact.
+    pub const AMCHECK: Self = Self {
+        id: ExtensionId::Amcheck,
+    };
+    /// Select the `auto_explain` artifact.
+    pub const AUTO_EXPLAIN: Self = Self {
+        id: ExtensionId::AutoExplain,
+    };
+    /// Select the `bloom` artifact.
+    pub const BLOOM: Self = Self {
+        id: ExtensionId::Bloom,
+    };
+    /// Select the `btree_gin` artifact.
+    pub const BTREE_GIN: Self = Self {
+        id: ExtensionId::BtreeGin,
+    };
+    /// Select the `btree_gist` artifact.
+    pub const BTREE_GIST: Self = Self {
+        id: ExtensionId::BtreeGist,
+    };
+    /// Select the `citext` artifact.
+    pub const CITEXT: Self = Self {
+        id: ExtensionId::Citext,
+    };
+    /// Select the `cube` artifact.
+    pub const CUBE: Self = Self {
+        id: ExtensionId::Cube,
+    };
+    /// Select the `dict_int` artifact.
+    pub const DICT_INT: Self = Self {
+        id: ExtensionId::DictInt,
+    };
+    /// Select the `dict_xsyn` artifact.
+    pub const DICT_XSYN: Self = Self {
+        id: ExtensionId::DictXsyn,
+    };
+    /// Select the `earthdistance` artifact.
+    pub const EARTHDISTANCE: Self = Self {
+        id: ExtensionId::Earthdistance,
+    };
+    /// Select the `file_fdw` artifact.
+    pub const FILE_FDW: Self = Self {
+        id: ExtensionId::FileFdw,
+    };
+    /// Select the `fuzzystrmatch` artifact.
+    pub const FUZZYSTRMATCH: Self = Self {
+        id: ExtensionId::Fuzzystrmatch,
+    };
+    /// Select the `hstore` artifact.
+    pub const HSTORE: Self = Self {
+        id: ExtensionId::Hstore,
+    };
+    /// Select the `intarray` artifact.
+    pub const INTARRAY: Self = Self {
+        id: ExtensionId::Intarray,
+    };
+    /// Select the `isn` artifact.
+    pub const ISN: Self = Self {
+        id: ExtensionId::Isn,
+    };
+    /// Select the `lo` artifact.
+    pub const LO: Self = Self {
+        id: ExtensionId::Lo,
+    };
+    /// Select the `ltree` artifact.
+    pub const LTREE: Self = Self {
+        id: ExtensionId::Ltree,
+    };
+    /// Select the `pageinspect` artifact.
+    pub const PAGEINSPECT: Self = Self {
+        id: ExtensionId::Pageinspect,
+    };
+    /// Select the `pg_buffercache` artifact.
+    pub const PG_BUFFERCACHE: Self = Self {
+        id: ExtensionId::PgBuffercache,
+    };
+    /// Select the `pg_freespacemap` artifact.
+    pub const PG_FREESPACEMAP: Self = Self {
+        id: ExtensionId::PgFreespacemap,
+    };
+    /// Select the `pg_hashids` artifact.
+    pub const PG_HASHIDS: Self = Self {
+        id: ExtensionId::PgHashids,
+    };
+    /// Select the `pg_ivm` artifact.
+    pub const PG_IVM: Self = Self {
+        id: ExtensionId::PgIvm,
+    };
+    /// Select the `pg_surgery` artifact.
+    pub const PG_SURGERY: Self = Self {
+        id: ExtensionId::PgSurgery,
+    };
+    /// Select the `pg_textsearch` artifact.
+    pub const PG_TEXTSEARCH: Self = Self {
+        id: ExtensionId::PgTextsearch,
+    };
+    /// Select the `pg_trgm` artifact.
+    pub const PG_TRGM: Self = Self {
+        id: ExtensionId::PgTrgm,
+    };
+    /// Select the `pg_uuidv7` artifact.
+    pub const PG_UUIDV7: Self = Self {
+        id: ExtensionId::PgUuidv7,
+    };
+    /// Select the `pg_visibility` artifact.
+    pub const PG_VISIBILITY: Self = Self {
+        id: ExtensionId::PgVisibility,
+    };
+    /// Select the `pg_walinspect` artifact.
+    pub const PG_WALINSPECT: Self = Self {
+        id: ExtensionId::PgWalinspect,
+    };
+    /// Select the `pgcrypto` artifact.
+    pub const PGCRYPTO: Self = Self {
+        id: ExtensionId::Pgcrypto,
+    };
+    /// Select the `pgtap` artifact.
+    pub const PGTAP: Self = Self {
+        id: ExtensionId::Pgtap,
+    };
+    /// Select the `postgis` artifact.
+    pub const POSTGIS: Self = Self {
+        id: ExtensionId::Postgis,
+    };
+    /// Select the `seg` artifact.
+    pub const SEG: Self = Self {
+        id: ExtensionId::Seg,
+    };
+    /// Select the `tablefunc` artifact.
+    pub const TABLEFUNC: Self = Self {
+        id: ExtensionId::Tablefunc,
+    };
+    /// Select the `tcn` artifact.
+    pub const TCN: Self = Self {
+        id: ExtensionId::Tcn,
+    };
+    /// Select the `tsm_system_rows` artifact.
+    pub const TSM_SYSTEM_ROWS: Self = Self {
+        id: ExtensionId::TsmSystemRows,
+    };
+    /// Select the `tsm_system_time` artifact.
+    pub const TSM_SYSTEM_TIME: Self = Self {
+        id: ExtensionId::TsmSystemTime,
+    };
+    /// Select the `unaccent` artifact.
+    pub const UNACCENT: Self = Self {
+        id: ExtensionId::Unaccent,
+    };
+    /// Select the `uuid-ossp` artifact.
+    pub const UUID_OSSP: Self = Self {
+        id: ExtensionId::UuidOssp,
+    };
+    /// Select the `vector` artifact.
+    pub const VECTOR: Self = Self {
+        id: ExtensionId::Vector,
+    };
+
+    /// All PostgreSQL 18 extension artifacts known to the native SDK.
+    pub const ALL: &'static [Self] = &[
+        Extension::AMCHECK,
+        Extension::AUTO_EXPLAIN,
+        Extension::BLOOM,
+        Extension::BTREE_GIN,
+        Extension::BTREE_GIST,
+        Extension::CITEXT,
+        Extension::CUBE,
+        Extension::DICT_INT,
+        Extension::DICT_XSYN,
+        Extension::EARTHDISTANCE,
+        Extension::FILE_FDW,
+        Extension::FUZZYSTRMATCH,
+        Extension::HSTORE,
+        Extension::INTARRAY,
+        Extension::ISN,
+        Extension::LO,
+        Extension::LTREE,
+        Extension::PAGEINSPECT,
+        Extension::PG_BUFFERCACHE,
+        Extension::PG_FREESPACEMAP,
+        Extension::PG_HASHIDS,
+        Extension::PG_IVM,
+        Extension::PG_SURGERY,
+        Extension::PG_TEXTSEARCH,
+        Extension::PG_TRGM,
+        Extension::PG_UUIDV7,
+        Extension::PG_VISIBILITY,
+        Extension::PG_WALINSPECT,
+        Extension::PGCRYPTO,
+        Extension::PGTAP,
+        Extension::POSTGIS,
+        Extension::SEG,
+        Extension::TABLEFUNC,
+        Extension::TCN,
+        Extension::TSM_SYSTEM_ROWS,
+        Extension::TSM_SYSTEM_TIME,
+        Extension::UNACCENT,
+        Extension::UUID_OSSP,
+        Extension::VECTOR,
+    ];
+}
+
+/// Generated extension metadata accessor.
+pub(super) const fn sql_name(extension: Extension) -> &'static str {
+    match extension.id {
+        ExtensionId::Amcheck => "amcheck",
+        ExtensionId::AutoExplain => "auto_explain",
+        ExtensionId::Bloom => "bloom",
+        ExtensionId::BtreeGin => "btree_gin",
+        ExtensionId::BtreeGist => "btree_gist",
+        ExtensionId::Citext => "citext",
+        ExtensionId::Cube => "cube",
+        ExtensionId::DictInt => "dict_int",
+        ExtensionId::DictXsyn => "dict_xsyn",
+        ExtensionId::Earthdistance => "earthdistance",
+        ExtensionId::FileFdw => "file_fdw",
+        ExtensionId::Fuzzystrmatch => "fuzzystrmatch",
+        ExtensionId::Hstore => "hstore",
+        ExtensionId::Intarray => "intarray",
+        ExtensionId::Isn => "isn",
+        ExtensionId::Lo => "lo",
+        ExtensionId::Ltree => "ltree",
+        ExtensionId::Pageinspect => "pageinspect",
+        ExtensionId::PgBuffercache => "pg_buffercache",
+        ExtensionId::PgFreespacemap => "pg_freespacemap",
+        ExtensionId::PgHashids => "pg_hashids",
+        ExtensionId::PgIvm => "pg_ivm",
+        ExtensionId::PgSurgery => "pg_surgery",
+        ExtensionId::PgTextsearch => "pg_textsearch",
+        ExtensionId::PgTrgm => "pg_trgm",
+        ExtensionId::PgUuidv7 => "pg_uuidv7",
+        ExtensionId::PgVisibility => "pg_visibility",
+        ExtensionId::PgWalinspect => "pg_walinspect",
+        ExtensionId::Pgcrypto => "pgcrypto",
+        ExtensionId::Pgtap => "pgtap",
+        ExtensionId::Postgis => "postgis",
+        ExtensionId::Seg => "seg",
+        ExtensionId::Tablefunc => "tablefunc",
+        ExtensionId::Tcn => "tcn",
+        ExtensionId::TsmSystemRows => "tsm_system_rows",
+        ExtensionId::TsmSystemTime => "tsm_system_time",
+        ExtensionId::Unaccent => "unaccent",
+        ExtensionId::UuidOssp => "uuid-ossp",
+        ExtensionId::Vector => "vector",
+    }
+}
+
+/// Generated extension metadata accessor.
+pub(super) const fn native_module_stem(extension: Extension) -> Option<&'static str> {
+    match extension.id {
+        ExtensionId::Amcheck => Some("amcheck"),
+        ExtensionId::AutoExplain => Some("auto_explain"),
+        ExtensionId::Bloom => Some("bloom"),
+        ExtensionId::BtreeGin => Some("btree_gin"),
+        ExtensionId::BtreeGist => Some("btree_gist"),
+        ExtensionId::Citext => Some("citext"),
+        ExtensionId::Cube => Some("cube"),
+        ExtensionId::DictInt => Some("dict_int"),
+        ExtensionId::DictXsyn => Some("dict_xsyn"),
+        ExtensionId::Earthdistance => Some("earthdistance"),
+        ExtensionId::FileFdw => Some("file_fdw"),
+        ExtensionId::Fuzzystrmatch => Some("fuzzystrmatch"),
+        ExtensionId::Hstore => Some("hstore"),
+        ExtensionId::Intarray => Some("_int"),
+        ExtensionId::Isn => Some("isn"),
+        ExtensionId::Lo => Some("lo"),
+        ExtensionId::Ltree => Some("ltree"),
+        ExtensionId::Pageinspect => Some("pageinspect"),
+        ExtensionId::PgBuffercache => Some("pg_buffercache"),
+        ExtensionId::PgFreespacemap => Some("pg_freespacemap"),
+        ExtensionId::PgHashids => Some("pg_hashids"),
+        ExtensionId::PgIvm => Some("pg_ivm"),
+        ExtensionId::PgSurgery => Some("pg_surgery"),
+        ExtensionId::PgTextsearch => Some("pg_textsearch"),
+        ExtensionId::PgTrgm => Some("pg_trgm"),
+        ExtensionId::PgUuidv7 => Some("pg_uuidv7"),
+        ExtensionId::PgVisibility => Some("pg_visibility"),
+        ExtensionId::PgWalinspect => Some("pg_walinspect"),
+        ExtensionId::Pgcrypto => Some("pgcrypto"),
+        ExtensionId::Pgtap => None,
+        ExtensionId::Postgis => Some("postgis-3"),
+        ExtensionId::Seg => Some("seg"),
+        ExtensionId::Tablefunc => Some("tablefunc"),
+        ExtensionId::Tcn => Some("tcn"),
+        ExtensionId::TsmSystemRows => Some("tsm_system_rows"),
+        ExtensionId::TsmSystemTime => Some("tsm_system_time"),
+        ExtensionId::Unaccent => Some("unaccent"),
+        ExtensionId::UuidOssp => Some("uuid-ossp"),
+        ExtensionId::Vector => Some("vector"),
+    }
+}
+
+/// Generated extension metadata accessor.
+pub(super) const fn creates_extension(extension: Extension) -> bool {
+    match extension.id {
+        ExtensionId::Amcheck => true,
+        ExtensionId::AutoExplain => false,
+        ExtensionId::Bloom => true,
+        ExtensionId::BtreeGin => true,
+        ExtensionId::BtreeGist => true,
+        ExtensionId::Citext => true,
+        ExtensionId::Cube => true,
+        ExtensionId::DictInt => true,
+        ExtensionId::DictXsyn => true,
+        ExtensionId::Earthdistance => true,
+        ExtensionId::FileFdw => true,
+        ExtensionId::Fuzzystrmatch => true,
+        ExtensionId::Hstore => true,
+        ExtensionId::Intarray => true,
+        ExtensionId::Isn => true,
+        ExtensionId::Lo => true,
+        ExtensionId::Ltree => true,
+        ExtensionId::Pageinspect => true,
+        ExtensionId::PgBuffercache => true,
+        ExtensionId::PgFreespacemap => true,
+        ExtensionId::PgHashids => true,
+        ExtensionId::PgIvm => true,
+        ExtensionId::PgSurgery => true,
+        ExtensionId::PgTextsearch => true,
+        ExtensionId::PgTrgm => true,
+        ExtensionId::PgUuidv7 => true,
+        ExtensionId::PgVisibility => true,
+        ExtensionId::PgWalinspect => true,
+        ExtensionId::Pgcrypto => true,
+        ExtensionId::Pgtap => true,
+        ExtensionId::Postgis => true,
+        ExtensionId::Seg => true,
+        ExtensionId::Tablefunc => true,
+        ExtensionId::Tcn => true,
+        ExtensionId::TsmSystemRows => true,
+        ExtensionId::TsmSystemTime => true,
+        ExtensionId::Unaccent => true,
+        ExtensionId::UuidOssp => true,
+        ExtensionId::Vector => true,
+    }
+}
+
+/// Generated extension metadata accessor.
+pub(super) const fn dependencies(extension: Extension) -> &'static [Extension] {
+    match extension.id {
+        ExtensionId::Amcheck => &[],
+        ExtensionId::AutoExplain => &[],
+        ExtensionId::Bloom => &[],
+        ExtensionId::BtreeGin => &[],
+        ExtensionId::BtreeGist => &[],
+        ExtensionId::Citext => &[],
+        ExtensionId::Cube => &[],
+        ExtensionId::DictInt => &[],
+        ExtensionId::DictXsyn => &[],
+        ExtensionId::Earthdistance => &[Extension::CUBE],
+        ExtensionId::FileFdw => &[],
+        ExtensionId::Fuzzystrmatch => &[],
+        ExtensionId::Hstore => &[],
+        ExtensionId::Intarray => &[],
+        ExtensionId::Isn => &[],
+        ExtensionId::Lo => &[],
+        ExtensionId::Ltree => &[],
+        ExtensionId::Pageinspect => &[],
+        ExtensionId::PgBuffercache => &[],
+        ExtensionId::PgFreespacemap => &[],
+        ExtensionId::PgHashids => &[],
+        ExtensionId::PgIvm => &[],
+        ExtensionId::PgSurgery => &[],
+        ExtensionId::PgTextsearch => &[],
+        ExtensionId::PgTrgm => &[],
+        ExtensionId::PgUuidv7 => &[],
+        ExtensionId::PgVisibility => &[],
+        ExtensionId::PgWalinspect => &[],
+        ExtensionId::Pgcrypto => &[],
+        ExtensionId::Pgtap => &[],
+        ExtensionId::Postgis => &[],
+        ExtensionId::Seg => &[],
+        ExtensionId::Tablefunc => &[],
+        ExtensionId::Tcn => &[],
+        ExtensionId::TsmSystemRows => &[],
+        ExtensionId::TsmSystemTime => &[],
+        ExtensionId::Unaccent => &[],
+        ExtensionId::UuidOssp => &[],
+        ExtensionId::Vector => &[],
+    }
+}
+
+/// Generated extension metadata accessor.
+pub(super) const fn required_shared_preload_library(extension: Extension) -> Option<&'static str> {
+    match extension.id {
+        ExtensionId::Amcheck => None,
+        ExtensionId::AutoExplain => None,
+        ExtensionId::Bloom => None,
+        ExtensionId::BtreeGin => None,
+        ExtensionId::BtreeGist => None,
+        ExtensionId::Citext => None,
+        ExtensionId::Cube => None,
+        ExtensionId::DictInt => None,
+        ExtensionId::DictXsyn => None,
+        ExtensionId::Earthdistance => None,
+        ExtensionId::FileFdw => None,
+        ExtensionId::Fuzzystrmatch => None,
+        ExtensionId::Hstore => None,
+        ExtensionId::Intarray => None,
+        ExtensionId::Isn => None,
+        ExtensionId::Lo => None,
+        ExtensionId::Ltree => None,
+        ExtensionId::Pageinspect => None,
+        ExtensionId::PgBuffercache => None,
+        ExtensionId::PgFreespacemap => None,
+        ExtensionId::PgHashids => None,
+        ExtensionId::PgIvm => None,
+        ExtensionId::PgSurgery => None,
+        ExtensionId::PgTextsearch => Some("pg_textsearch"),
+        ExtensionId::PgTrgm => None,
+        ExtensionId::PgUuidv7 => None,
+        ExtensionId::PgVisibility => None,
+        ExtensionId::PgWalinspect => None,
+        ExtensionId::Pgcrypto => None,
+        ExtensionId::Pgtap => None,
+        ExtensionId::Postgis => None,
+        ExtensionId::Seg => None,
+        ExtensionId::Tablefunc => None,
+        ExtensionId::Tcn => None,
+        ExtensionId::TsmSystemRows => None,
+        ExtensionId::TsmSystemTime => None,
+        ExtensionId::Unaccent => None,
+        ExtensionId::UuidOssp => None,
+        ExtensionId::Vector => None,
+    }
+}
+
+/// Generated extension metadata accessor.
+pub(super) const fn extension_data_files(extension: Extension) -> &'static [&'static str] {
+    match extension.id {
+        ExtensionId::Amcheck => &[],
+        ExtensionId::AutoExplain => &[],
+        ExtensionId::Bloom => &[],
+        ExtensionId::BtreeGin => &[],
+        ExtensionId::BtreeGist => &[],
+        ExtensionId::Citext => &[],
+        ExtensionId::Cube => &[],
+        ExtensionId::DictInt => &[],
+        ExtensionId::DictXsyn => &["tsearch_data/xsyn_sample.rules"],
+        ExtensionId::Earthdistance => &[],
+        ExtensionId::FileFdw => &[],
+        ExtensionId::Fuzzystrmatch => &[],
+        ExtensionId::Hstore => &[],
+        ExtensionId::Intarray => &[],
+        ExtensionId::Isn => &[],
+        ExtensionId::Lo => &[],
+        ExtensionId::Ltree => &[],
+        ExtensionId::Pageinspect => &[],
+        ExtensionId::PgBuffercache => &[],
+        ExtensionId::PgFreespacemap => &[],
+        ExtensionId::PgHashids => &[],
+        ExtensionId::PgIvm => &[],
+        ExtensionId::PgSurgery => &[],
+        ExtensionId::PgTextsearch => &[],
+        ExtensionId::PgTrgm => &[],
+        ExtensionId::PgUuidv7 => &[],
+        ExtensionId::PgVisibility => &[],
+        ExtensionId::PgWalinspect => &[],
+        ExtensionId::Pgcrypto => &[],
+        ExtensionId::Pgtap => &[],
+        ExtensionId::Postgis => &[
+            "contrib/postgis-3.6/legacy.sql",
+            "contrib/postgis-3.6/legacy_gist.sql",
+            "contrib/postgis-3.6/legacy_minimal.sql",
+            "contrib/postgis-3.6/postgis.sql",
+            "contrib/postgis-3.6/postgis_upgrade.sql",
+            "contrib/postgis-3.6/spatial_ref_sys.sql",
+            "contrib/postgis-3.6/uninstall_legacy.sql",
+            "contrib/postgis-3.6/uninstall_postgis.sql",
+            "proj/proj.db",
+        ],
+        ExtensionId::Seg => &[],
+        ExtensionId::Tablefunc => &[],
+        ExtensionId::Tcn => &[],
+        ExtensionId::TsmSystemRows => &[],
+        ExtensionId::TsmSystemTime => &[],
+        ExtensionId::Unaccent => &["tsearch_data/unaccent.rules"],
+        ExtensionId::UuidOssp => &[],
+        ExtensionId::Vector => &[],
+    }
+}
+
+/// Generated extension metadata accessor.
+pub(super) const fn extension_sql_file_prefixes(extension: Extension) -> &'static [&'static str] {
+    match extension.id {
+        ExtensionId::Amcheck => &[],
+        ExtensionId::AutoExplain => &[],
+        ExtensionId::Bloom => &[],
+        ExtensionId::BtreeGin => &[],
+        ExtensionId::BtreeGist => &[],
+        ExtensionId::Citext => &[],
+        ExtensionId::Cube => &[],
+        ExtensionId::DictInt => &[],
+        ExtensionId::DictXsyn => &[],
+        ExtensionId::Earthdistance => &[],
+        ExtensionId::FileFdw => &[],
+        ExtensionId::Fuzzystrmatch => &[],
+        ExtensionId::Hstore => &[],
+        ExtensionId::Intarray => &[],
+        ExtensionId::Isn => &[],
+        ExtensionId::Lo => &[],
+        ExtensionId::Ltree => &[],
+        ExtensionId::Pageinspect => &[],
+        ExtensionId::PgBuffercache => &[],
+        ExtensionId::PgFreespacemap => &[],
+        ExtensionId::PgHashids => &[],
+        ExtensionId::PgIvm => &[],
+        ExtensionId::PgSurgery => &[],
+        ExtensionId::PgTextsearch => &[],
+        ExtensionId::PgTrgm => &[],
+        ExtensionId::PgUuidv7 => &[],
+        ExtensionId::PgVisibility => &[],
+        ExtensionId::PgWalinspect => &[],
+        ExtensionId::Pgcrypto => &[],
+        ExtensionId::Pgtap => &["pgtap-core", "pgtap-schema"],
+        ExtensionId::Postgis => &[
+            "postgis_comments",
+            "postgis_proc_set_search_path",
+            "rtpostgis",
+        ],
+        ExtensionId::Seg => &[],
+        ExtensionId::Tablefunc => &[],
+        ExtensionId::Tcn => &[],
+        ExtensionId::TsmSystemRows => &[],
+        ExtensionId::TsmSystemTime => &[],
+        ExtensionId::Unaccent => &[],
+        ExtensionId::UuidOssp => &[],
+        ExtensionId::Vector => &[],
+    }
+}
+
+/// Generated extension metadata accessor.
+pub(super) const fn extension_sql_file_names(extension: Extension) -> &'static [&'static str] {
+    match extension.id {
+        ExtensionId::Amcheck => &[],
+        ExtensionId::AutoExplain => &[],
+        ExtensionId::Bloom => &[],
+        ExtensionId::BtreeGin => &[],
+        ExtensionId::BtreeGist => &[],
+        ExtensionId::Citext => &[],
+        ExtensionId::Cube => &[],
+        ExtensionId::DictInt => &[],
+        ExtensionId::DictXsyn => &[],
+        ExtensionId::Earthdistance => &[],
+        ExtensionId::FileFdw => &[],
+        ExtensionId::Fuzzystrmatch => &[],
+        ExtensionId::Hstore => &[],
+        ExtensionId::Intarray => &[],
+        ExtensionId::Isn => &[],
+        ExtensionId::Lo => &[],
+        ExtensionId::Ltree => &[],
+        ExtensionId::Pageinspect => &[],
+        ExtensionId::PgBuffercache => &[],
+        ExtensionId::PgFreespacemap => &[],
+        ExtensionId::PgHashids => &[],
+        ExtensionId::PgIvm => &[],
+        ExtensionId::PgSurgery => &[],
+        ExtensionId::PgTextsearch => &[],
+        ExtensionId::PgTrgm => &[],
+        ExtensionId::PgUuidv7 => &[],
+        ExtensionId::PgVisibility => &[],
+        ExtensionId::PgWalinspect => &[],
+        ExtensionId::Pgcrypto => &[],
+        ExtensionId::Pgtap => &["uninstall_pgtap.sql"],
+        ExtensionId::Postgis => &["uninstall_postgis.sql"],
+        ExtensionId::Seg => &[],
+        ExtensionId::Tablefunc => &[],
+        ExtensionId::Tcn => &[],
+        ExtensionId::TsmSystemRows => &[],
+        ExtensionId::TsmSystemTime => &[],
+        ExtensionId::Unaccent => &[],
+        ExtensionId::UuidOssp => &[],
+        ExtensionId::Vector => &[],
+    }
+}
+
+/// Generated extension metadata accessor.
+pub(super) const fn runtime_environment(
+    extension: Extension,
+) -> &'static [ExtensionRuntimeEnvironment] {
+    match extension.id {
+        ExtensionId::Amcheck => &[],
+        ExtensionId::AutoExplain => &[],
+        ExtensionId::Bloom => &[],
+        ExtensionId::BtreeGin => &[],
+        ExtensionId::BtreeGist => &[],
+        ExtensionId::Citext => &[],
+        ExtensionId::Cube => &[],
+        ExtensionId::DictInt => &[],
+        ExtensionId::DictXsyn => &[],
+        ExtensionId::Earthdistance => &[],
+        ExtensionId::FileFdw => &[],
+        ExtensionId::Fuzzystrmatch => &[],
+        ExtensionId::Hstore => &[],
+        ExtensionId::Intarray => &[],
+        ExtensionId::Isn => &[],
+        ExtensionId::Lo => &[],
+        ExtensionId::Ltree => &[],
+        ExtensionId::Pageinspect => &[],
+        ExtensionId::PgBuffercache => &[],
+        ExtensionId::PgFreespacemap => &[],
+        ExtensionId::PgHashids => &[],
+        ExtensionId::PgIvm => &[],
+        ExtensionId::PgSurgery => &[],
+        ExtensionId::PgTextsearch => &[],
+        ExtensionId::PgTrgm => &[],
+        ExtensionId::PgUuidv7 => &[],
+        ExtensionId::PgVisibility => &[],
+        ExtensionId::PgWalinspect => &[],
+        ExtensionId::Pgcrypto => &[],
+        ExtensionId::Pgtap => &[],
+        ExtensionId::Postgis => &[ExtensionRuntimeEnvironment {
+            name: "PROJ_DATA",
+            relative_path: "share/postgresql/proj",
+            required_file: "proj.db",
+        }],
+        ExtensionId::Seg => &[],
+        ExtensionId::Tablefunc => &[],
+        ExtensionId::Tcn => &[],
+        ExtensionId::TsmSystemRows => &[],
+        ExtensionId::TsmSystemTime => &[],
+        ExtensionId::Unaccent => &[],
+        ExtensionId::UuidOssp => &[],
+        ExtensionId::Vector => &[],
+    }
+}
diff --git a/src/sdks/rust/liboliphaunt-native/src/lib.rs b/src/sdks/rust/liboliphaunt-native/src/lib.rs
new file mode 100644
index 000000000..6178290d2
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/lib.rs
@@ -0,0 +1,25 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+//! Shared native liboliphaunt execution and resource ownership.
+mod build_resources;
+pub mod config;
+pub mod error;
+pub mod extension;
+mod liboliphaunt;
+pub mod storage;
+#[cfg(test)]
+mod test_fixtures;
+pub use build_resources::register_build_resources_dir;
+#[doc(hidden)]
+pub use build_resources::registered_build_resources_dir;
+pub use config::{NativeClusterSeed, NativeConfig, NativeResourceDirectory, PostgresStartupGuc};
+pub use error::{Error, Result};
+pub use extension::Extension;
+pub use liboliphaunt::root::{PreparedNativeRoot, configure_native_tool_env, native_root_key};
+pub use liboliphaunt::{
+    NativeCancel, NativeOpenOptions, NativeProtocolInput, NativeSession, ProtocolStreamOutcome,
+};
+#[cfg(feature = "internal-native-packaging")]
+pub use liboliphaunt::{
+    NativePackagingCatalogProfile, NativePackagingResources, materialize_native_packaging_resources,
+};
+pub use storage::DatabaseStorage;
diff --git a/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/ffi.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/ffi.rs
new file mode 100644
index 000000000..f0760f5ac
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/ffi.rs
@@ -0,0 +1,422 @@
+use std::ffi::{CString, c_char, c_int, c_uchar, c_void};
+use std::mem::ManuallyDrop;
+use std::path::{Path, PathBuf};
+
+use libloading::Library;
+
+use crate::error::{Error, Result};
+
+pub(super) const ABI_VERSION: u32 = 11;
+pub(super) const CONFIG_EXTERNAL_ROOT_LOCK: u64 = 1 << 0;
+pub(super) const ERROR_CAPTURE_CAPACITY: usize = 1024;
+/// Positive stream status reserved by ABI 10 for a callback abort after the
+/// runtime has independently confirmed the request's ReadyForQuery boundary.
+pub(super) const STREAM_CALLBACK_ABORTED_STATUS: c_int = 1;
+
+pub(super) const ENV_OLIPHAUNT: &str = "LIBOLIPHAUNT_PATH";
+pub(super) const ENV_INSTALL_DIR: &str = "OLIPHAUNT_INSTALL_DIR";
+pub(super) const ENV_EMBEDDED_MODULE_DIR: &str = "OLIPHAUNT_EMBEDDED_MODULE_DIR";
+pub(super) const ENV_POSTGRES: &str = "OLIPHAUNT_POSTGRES";
+pub(super) const ENV_INITDB: &str = "OLIPHAUNT_INITDB";
+
+#[repr(C)]
+pub(super) struct NativeConfig {
+    pub(super) abi_version: u32,
+    pub(super) pgdata: *const c_char,
+    pub(super) runtime_dir: *const c_char,
+    pub(super) module_dir: *const c_char,
+    pub(super) username: *const c_char,
+    pub(super) database: *const c_char,
+    pub(super) flags: u64,
+    pub(super) startup_args: *const *const c_char,
+    pub(super) startup_arg_count: usize,
+    pub(super) icu_data_dir: *const c_char,
+}
+
+#[repr(C)]
+pub(super) struct NativeResponse {
+    pub(super) data: *mut c_uchar,
+    pub(super) len: usize,
+}
+
+#[repr(C)]
+pub(super) struct NativeErrorCapture {
+    length: u32,
+    message: [c_char; ERROR_CAPTURE_CAPACITY],
+}
+
+impl NativeErrorCapture {
+    pub(super) const fn zeroed() -> Self {
+        Self {
+            length: 0,
+            message: [0; ERROR_CAPTURE_CAPACITY],
+        }
+    }
+
+    pub(super) fn error_text(&self) -> Option {
+        decode_error_text(self.length as usize, &self.message)
+    }
+}
+
+#[repr(C)]
+pub(super) struct NativeRestoreOptions {
+    pub(super) abi_version: u32,
+    pub(super) destination: *const c_char,
+    pub(super) data: *const c_uchar,
+    pub(super) len: usize,
+}
+
+pub(super) type NativeHandle = c_void;
+type InitWithErrorFn = unsafe extern "C" fn(
+    *const NativeConfig,
+    *mut *mut NativeHandle,
+    *mut NativeErrorCapture,
+) -> c_int;
+type ExecProtocolWithErrorFn = unsafe extern "C" fn(
+    *mut NativeHandle,
+    *const c_uchar,
+    usize,
+    *mut NativeResponse,
+    *mut NativeErrorCapture,
+) -> c_int;
+pub(super) type StreamCallbackFn =
+    unsafe extern "C" fn(*mut c_void, *const c_uchar, usize) -> c_int;
+type ExecProtocolRawStreamWithErrorFn = unsafe extern "C" fn(
+    *mut NativeHandle,
+    *const c_uchar,
+    usize,
+    StreamCallbackFn,
+    *mut c_void,
+    *mut NativeErrorCapture,
+) -> c_int;
+type ExecSimpleQueryWithErrorFn = unsafe extern "C" fn(
+    *mut NativeHandle,
+    *const c_char,
+    usize,
+    *mut NativeResponse,
+    *mut NativeErrorCapture,
+) -> c_int;
+type CloseFn = unsafe extern "C" fn(*mut NativeHandle) -> c_int;
+type DetachWithErrorFn = unsafe extern "C" fn(*mut NativeHandle, *mut NativeErrorCapture) -> c_int;
+type CancelFn = unsafe extern "C" fn(*mut NativeHandle) -> c_int;
+pub(super) type StreamTokenFn = unsafe extern "C" fn(*mut NativeHandle) -> u64;
+pub(super) type FeedStreamFn = unsafe extern "C" fn(
+    *mut NativeHandle,
+    u64,
+    *const c_uchar,
+    usize,
+    *mut NativeErrorCapture,
+) -> c_int;
+type CopyLastErrorFn = unsafe extern "C" fn(*mut NativeHandle, *mut c_char, usize) -> usize;
+type VersionFn = unsafe extern "C" fn() -> *const c_char;
+type FreeResponseFn = unsafe extern "C" fn(*mut NativeResponse);
+type BackupWithErrorFn =
+    unsafe extern "C" fn(*mut NativeHandle, *mut NativeResponse, *mut NativeErrorCapture) -> c_int;
+type RestoreWithErrorFn =
+    unsafe extern "C" fn(*const NativeRestoreOptions, *mut NativeErrorCapture) -> c_int;
+
+pub(super) struct NativeSymbols {
+    _library: ManuallyDrop,
+    pub(super) logical_generation: unsafe extern "C" fn(*mut NativeHandle) -> u64,
+    pub(super) close_if_generation: unsafe extern "C" fn(u64) -> c_int,
+    pub(super) init_with_error: InitWithErrorFn,
+    pub(super) exec_protocol_with_error: ExecProtocolWithErrorFn,
+    pub(super) exec_protocol_raw_stream_with_error: ExecProtocolRawStreamWithErrorFn,
+    pub(super) exec_simple_query_with_error: ExecSimpleQueryWithErrorFn,
+    pub(super) cancel: CancelFn,
+    pub(super) detach_with_error: DetachWithErrorFn,
+    _close: CloseFn,
+    copy_last_error: CopyLastErrorFn,
+    pub(super) version: VersionFn,
+    pub(super) free_response: FreeResponseFn,
+    pub(super) backup_with_error: BackupWithErrorFn,
+    pub(super) restore_with_error: RestoreWithErrorFn,
+}
+
+// SAFETY: NativeSymbols is immutable after load. Function pointers are plain C
+// symbols tied to `_library`, and the library is intentionally leaked for the
+// process lifetime so those pointers cannot dangle while shared between the SDK
+// executor and cancellation paths.
+unsafe impl Send for NativeSymbols {}
+// SAFETY: See the Send impl. Calling through a symbol still requires the caller
+// to provide a valid synchronized handle; this table only shares immutable
+// function addresses and the pinned dynamic library ownership.
+unsafe impl Sync for NativeSymbols {}
+
+impl NativeSymbols {
+    /// Register the app-selected static table before native initialization. The
+    /// table is opaque here: its layout remains owned by the canonical C ABI.
+    pub(super) fn register_selected_extensions(&self) -> Result<()> {
+        type Selected = unsafe extern "C" fn(*mut usize) -> *const c_void;
+        type Register = unsafe extern "C" fn(*const c_void, usize) -> c_int;
+        const NAME: &[u8] = b"liboliphaunt_selected_static_extensions\0";
+        let selected = unsafe { self._library.get::(NAME).ok().map(|s| *s) };
+        #[cfg(unix)]
+        let mut selected = selected;
+        #[cfg(target_os = "android")]
+        if selected.is_none() {
+            // Android packages its selected static archives in this companion
+            // library. Keep it resident just like the PostgreSQL library.
+            if let Ok(library) = load_native_library(Path::new("liboliphaunt_extensions.so")) {
+                selected = unsafe { library.get::(NAME).ok().map(|s| *s) };
+                let _ = ManuallyDrop::new(library);
+            }
+        }
+        #[cfg(unix)]
+        if selected.is_none() {
+            let process = libloading::os::unix::Library::this();
+            selected = unsafe { process.get::(NAME).ok().map(|s| *s) };
+        }
+        let Some(selected) = selected else {
+            return Ok(());
+        };
+        let mut count = 0;
+        let extensions = unsafe { selected(&mut count) };
+        if count == 0 {
+            return Ok(());
+        }
+        if extensions.is_null() {
+            return Err(Error::Engine(
+                "selected native static extension registry returned null extensions".into(),
+            ));
+        }
+        let register: Register =
+            load_symbol(&self._library, b"oliphaunt_register_static_extensions\0")?;
+        if unsafe { register(extensions, count) } != 0 {
+            return Err(Error::Engine(
+                self.last_error_text(std::ptr::null_mut())
+                    .unwrap_or_else(|| "native static extension registration failed".into()),
+            ));
+        }
+        Ok(())
+    }
+
+    pub(super) fn stream_input_symbols(&self) -> Result<(StreamTokenFn, FeedStreamFn)> {
+        Ok((
+            load_symbol(&self._library, b"oliphaunt_protocol_stream_token\0")?,
+            load_symbol(&self._library, b"oliphaunt_feed_protocol_stream\0")?,
+        ))
+    }
+
+    pub(super) fn load() -> Result {
+        let path = resolve_library_path()?;
+        Self::load_path(&path)
+    }
+
+    pub(super) fn load_path(path: &Path) -> Result {
+        Self::from_library(load_native_library(path)?)
+    }
+
+    pub(super) fn load_current_process() -> Result {
+        #[cfg(unix)]
+        {
+            Self::from_library(libloading::os::unix::Library::this().into())
+        }
+        #[cfg(not(unix))]
+        {
+            Err(Error::InvalidConfig(
+                "native library path is required on this platform".into(),
+            ))
+        }
+    }
+
+    fn from_library(library: Library) -> Result {
+        let init_with_error = load_symbol(&library, b"oliphaunt_init_with_error\0")?;
+        let exec_protocol_with_error =
+            load_symbol(&library, b"oliphaunt_exec_protocol_with_error\0")?;
+        let exec_protocol_raw_stream_with_error =
+            load_symbol(&library, b"oliphaunt_exec_protocol_raw_stream_with_error\0")?;
+        let exec_simple_query_with_error =
+            load_symbol(&library, b"oliphaunt_exec_simple_query_with_error\0")?;
+        let cancel = load_symbol(&library, b"oliphaunt_cancel\0")?;
+        let detach_with_error = load_symbol(&library, b"oliphaunt_detach_with_error\0")?;
+        let close = load_symbol(&library, b"oliphaunt_close\0")?;
+        let copy_last_error = load_symbol(&library, b"oliphaunt_copy_last_error\0")?;
+        let version = load_symbol(&library, b"oliphaunt_version\0")?;
+        let free_response = load_symbol(&library, b"oliphaunt_free_response\0")?;
+        let backup_with_error = load_symbol(&library, b"oliphaunt_backup_with_error\0")?;
+        let restore_with_error = load_symbol(&library, b"oliphaunt_restore_with_error\0")?;
+        Ok(Self {
+            // liboliphaunt embeds PostgreSQL, which owns process-global runtime
+            // state while a backend session is active. Logical SDK close uses
+            // oliphaunt_detach; oliphaunt_close remains terminal for the process
+            // lifetime. Dropping the dynamic library can invalidate callbacks,
+            // signal handlers, or other global runtime pointers that PostgreSQL
+            // installed inside the host process.
+            logical_generation: load_symbol(&library, b"oliphaunt_logical_generation\0")?,
+            close_if_generation: load_symbol(&library, b"oliphaunt_close_if_generation\0")?,
+            init_with_error,
+            exec_protocol_with_error,
+            exec_protocol_raw_stream_with_error,
+            exec_simple_query_with_error,
+            cancel,
+            detach_with_error,
+            _close: close,
+            copy_last_error,
+            version,
+            free_response,
+            backup_with_error,
+            restore_with_error,
+            _library: ManuallyDrop::new(library),
+        })
+    }
+
+    /// Cancel has no `_with_error` ABI entry point. It is synchronous in this
+    /// adapter, so copy its same-thread result into one ABI-sized buffer before
+    /// returning to the caller. Every other operation uses its own capture.
+    pub(super) fn last_error_text(&self, handle: *mut NativeHandle) -> Option {
+        let mut message = [0; ERROR_CAPTURE_CAPACITY];
+        let length = unsafe { (self.copy_last_error)(handle, message.as_mut_ptr(), message.len()) };
+        decode_error_text(length, &message)
+    }
+}
+
+fn decode_error_text(length: usize, message: &[c_char]) -> Option {
+    let bounded_length = length.min(message.len().saturating_sub(1));
+    if bounded_length == 0 {
+        return None;
+    }
+    let bytes =
+        unsafe { std::slice::from_raw_parts(message.as_ptr().cast::(), bounded_length) };
+    let text_length = bytes
+        .iter()
+        .position(|byte| *byte == 0)
+        .unwrap_or(bytes.len());
+    (text_length != 0).then(|| String::from_utf8_lossy(&bytes[..text_length]).into_owned())
+}
+
+fn resolve_library_path() -> Result {
+    if let Some(path) = std::env::var_os(ENV_OLIPHAUNT) {
+        return Ok(PathBuf::from(path));
+    }
+    resolve_library_path_candidates()
+        .into_iter()
+        .find(|path| path.is_file())
+        .ok_or_else(|| {
+            Error::Engine(format!(
+                "native liboliphaunt dynamic library was not found; set {ENV_OLIPHAUNT} or register oliphaunt-build resources; searched {:?}",
+                resolve_library_path_candidates()
+            ))
+        })
+}
+
+pub(super) fn resolve_library_path_candidates() -> Vec {
+    let mut candidates = env_path_candidates([ENV_OLIPHAUNT]);
+    candidates.extend(
+        crate::build_resources::resources_dir_candidates()
+            .into_iter()
+            .map(|root| {
+                root.join("native-runtime")
+                    .join("liboliphaunt-native")
+                    .join(if cfg!(windows) { "bin" } else { "lib" })
+                    .join(libloading::library_filename("oliphaunt"))
+            }),
+    );
+    candidates
+}
+
+pub(super) fn env_path_candidates(names: [&str; N]) -> Vec {
+    names
+        .into_iter()
+        .filter_map(std::env::var_os)
+        .map(PathBuf::from)
+        .collect()
+}
+
+fn load_native_library(path: &Path) -> Result {
+    #[cfg(unix)]
+    {
+        use libloading::os::unix::{Library as UnixLibrary, RTLD_GLOBAL, RTLD_NOW};
+
+        let library = unsafe { UnixLibrary::open(Some(path.as_os_str()), RTLD_NOW | RTLD_GLOBAL) }
+            .map_err(|err| {
+                Error::Engine(format!(
+                    "load native liboliphaunt library {}: {err}",
+                    path.display()
+                ))
+            })?;
+        Ok(Library::from(library))
+    }
+    #[cfg(not(unix))]
+    {
+        let library = unsafe { Library::new(path) }.map_err(|err| {
+            Error::Engine(format!(
+                "load native liboliphaunt library {}: {err}",
+                path.display()
+            ))
+        })?;
+        Ok(library)
+    }
+}
+
+fn load_symbol(library: &Library, name: &[u8]) -> Result {
+    let symbol = unsafe { library.get::(name) }.map_err(|err| {
+        Error::Engine(format!(
+            "native liboliphaunt is missing required symbol {}: {err}",
+            String::from_utf8_lossy(name).trim_end_matches('\0')
+        ))
+    })?;
+    Ok(*symbol)
+}
+
+pub(super) fn path_to_cstring(path: &Path, label: &str) -> Result {
+    #[cfg(unix)]
+    {
+        use std::os::unix::ffi::OsStrExt;
+
+        CString::new(path.as_os_str().as_bytes())
+            .map_err(|_| Error::InvalidConfig(format!("{label} contains an interior NUL")))
+    }
+    #[cfg(not(unix))]
+    {
+        let text = path.to_str().ok_or_else(|| {
+            Error::InvalidConfig(format!("{label} is not representable as UTF-8"))
+        })?;
+        CString::new(text)
+            .map_err(|_| Error::InvalidConfig(format!("{label} contains an interior NUL")))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::mem::{align_of, offset_of, size_of};
+
+    use super::*;
+
+    #[test]
+    fn error_capture_matches_abi_10_layout() {
+        assert_eq!(offset_of!(NativeErrorCapture, length), 0);
+        assert_eq!(offset_of!(NativeErrorCapture, message), size_of::());
+        assert_eq!(
+            size_of::(),
+            size_of::() + ERROR_CAPTURE_CAPACITY
+        );
+        assert_eq!(align_of::(), align_of::());
+    }
+
+    #[test]
+    fn error_capture_decode_is_zeroed_bounded_and_lossy() {
+        let mut capture = NativeErrorCapture::zeroed();
+        assert_eq!(capture.error_text(), None);
+        assert!(capture.message.iter().all(|byte| *byte == 0));
+
+        capture.length = 5;
+        for (slot, byte) in capture.message.iter_mut().zip(b"error") {
+            *slot = *byte as c_char;
+        }
+        assert_eq!(capture.error_text().as_deref(), Some("error"));
+
+        capture.length = u32::MAX;
+        capture.message.fill(b'x' as c_char);
+        let bounded = capture.error_text().expect("bounded capture text");
+        assert_eq!(bounded.len(), ERROR_CAPTURE_CAPACITY - 1);
+        assert!(bounded.bytes().all(|byte| byte == b'x'));
+
+        capture.message[2] = 0;
+        assert_eq!(capture.error_text().as_deref(), Some("xx"));
+
+        capture.length = 1;
+        capture.message[0] = -1_i8 as c_char;
+        assert_eq!(capture.error_text().as_deref(), Some("�"));
+    }
+}
diff --git a/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/mod.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/mod.rs
new file mode 100644
index 000000000..30d44be6d
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/mod.rs
@@ -0,0 +1,1251 @@
+use std::ffi::CString;
+use std::ffi::c_char;
+use std::panic::{AssertUnwindSafe, catch_unwind};
+use std::path::PathBuf;
+use std::ptr;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::{Arc, Mutex, OnceLock, RwLock};
+
+mod ffi;
+pub mod root;
+
+pub(crate) use self::root::{PreparedNativeRoot, native_root_key};
+
+use self::ffi::{
+    ABI_VERSION, CONFIG_EXTERNAL_ROOT_LOCK, NativeConfig as FfiNativeConfig, NativeErrorCapture,
+    NativeHandle, NativeResponse, NativeRestoreOptions, NativeSymbols,
+    STREAM_CALLBACK_ABORTED_STATUS, path_to_cstring,
+};
+use crate::config::NativeConfig as OpenConfig;
+pub enum ProtocolStreamOutcome {
+    ReadyForQuery(std::result::Result<(), E>),
+    SessionStateUnknown(Error),
+}
+use crate::error::{Error, Result};
+use crate::extension::Extension;
+use crate::storage::DatabaseStorage;
+
+static DIRECT_INSTANCE_ACTIVE: AtomicBool = AtomicBool::new(false);
+static DIRECT_RESIDENT_ROOT: OnceLock>> = OnceLock::new();
+
+/// Materialized native inputs consumed only by Oliphaunt's unpublished
+/// packaging tool.
+#[cfg(feature = "internal-native-packaging")]
+#[doc(hidden)]
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct NativePackagingResources {
+    /// Fully materialized PostgreSQL runtime directory.
+    pub runtime_dir: PathBuf,
+    /// Content key for the runtime directory.
+    pub runtime_cache_key: String,
+}
+
+/// PostgreSQL catalog profile requested by unpublished native packaging tools.
+#[cfg(feature = "internal-native-packaging")]
+#[doc(hidden)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum NativePackagingCatalogProfile {
+    /// Cluster initialized without the optional ICU data carrier.
+    Standard,
+    /// Cluster initialized with the exact optional ICU data carrier.
+    Icu,
+}
+
+/// Materialize the exact native inputs used by the unpublished packaging tool.
+#[cfg(feature = "internal-native-packaging")]
+#[doc(hidden)]
+pub fn materialize_native_packaging_resources(
+    extensions: &[Extension],
+    catalog_profile: NativePackagingCatalogProfile,
+) -> Result {
+    let catalog_profile = match catalog_profile {
+        NativePackagingCatalogProfile::Standard => root::NativeCatalogProfile::Standard,
+        NativePackagingCatalogProfile::Icu => root::NativeCatalogProfile::Icu,
+    };
+    let resources = root::materialize_native_resources_for_runtime(
+        root::NativeRuntimeProfile::OliphauntEmbedded,
+        extensions,
+        catalog_profile,
+    )?;
+    Ok(NativePackagingResources {
+        runtime_dir: resources.runtime_dir,
+        runtime_cache_key: resources.runtime_cache_key,
+    })
+}
+
+impl NativeSession {
+    /// Read the runtime version without opening a database or acquiring a session.
+    pub fn version_from_library(path: &std::path::Path) -> Result {
+        let symbols = NativeSymbols::load_path(path)?;
+        let version = unsafe { (symbols.version)() };
+        if version.is_null() {
+            return Err(Error::Engine(
+                "native runtime returned a null version".into(),
+            ));
+        }
+        Ok(unsafe { std::ffi::CStr::from_ptr(version) }
+            .to_string_lossy()
+            .into_owned())
+    }
+
+    pub fn restore(destination: &std::path::Path, bytes: &[u8]) -> Result<()> {
+        Self::restore_with_symbols(NativeSymbols::load()?, destination, bytes)
+    }
+
+    pub fn restore_from_library(
+        library: &std::path::Path,
+        destination: &std::path::Path,
+        bytes: &[u8],
+    ) -> Result<()> {
+        Self::restore_with_symbols(NativeSymbols::load_path(library)?, destination, bytes)
+    }
+
+    /// Restore using a runtime already linked into the current process.
+    pub fn restore_from_current_process(destination: &std::path::Path, bytes: &[u8]) -> Result<()> {
+        Self::restore_with_symbols(NativeSymbols::load_current_process()?, destination, bytes)
+    }
+
+    fn restore_with_symbols(
+        symbols: NativeSymbols,
+        destination: &std::path::Path,
+        bytes: &[u8],
+    ) -> Result<()> {
+        let destination = path_to_cstring(destination, "restore destination")?;
+        let options = NativeRestoreOptions {
+            abi_version: ABI_VERSION,
+            destination: destination.as_ptr(),
+            data: if bytes.is_empty() {
+                std::ptr::null()
+            } else {
+                bytes.as_ptr()
+            },
+            len: bytes.len(),
+        };
+        let mut error = NativeErrorCapture::zeroed();
+        let rc = unsafe { (symbols.restore_with_error)(&options, &mut error) };
+        if rc != 0 {
+            let message = captured_native_error(&error, "oliphaunt_restore", rc);
+            return Err(Error::Engine(format!(
+                "native liboliphaunt restore failed: {message}"
+            )));
+        }
+        Ok(())
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+struct DirectResidentKey {
+    requested_root_key: Option,
+    actual_root_key: PathBuf,
+    username: String,
+    database: String,
+    startup_args: Vec,
+    selected_extensions: Vec,
+    icu_data: Option<(crate::NativeResourceDirectory, String)>,
+}
+
+impl DirectResidentKey {
+    fn requested(
+        config: &OpenConfig,
+        extensions: &[Extension],
+        startup_args: Vec,
+    ) -> Result {
+        let requested_root_key = match &config.storage {
+            DatabaseStorage::Directory(root) => Some(native_root_key(root)?),
+            DatabaseStorage::TemporaryDirectory => None,
+        };
+        Ok(Self {
+            actual_root_key: requested_root_key.clone().unwrap_or_default(),
+            requested_root_key,
+            username: config.username.clone(),
+            database: config.database.clone(),
+            startup_args,
+            selected_extensions: extensions.to_vec(),
+            icu_data: config
+                .icu_data
+                .as_ref()
+                .map(|data| {
+                    root::resources::validate_icu_data(data).map(|digest| (data.clone(), digest))
+                })
+                .transpose()?,
+        })
+    }
+
+    fn bind_actual_root(mut self, root: &PreparedNativeRoot) -> Result {
+        self.actual_root_key = root.root_key()?;
+        Ok(self)
+    }
+
+    fn matches_storage(&self, requested: &Self) -> bool {
+        match (&self.requested_root_key, &requested.requested_root_key) {
+            (None, None) => true,
+            (_, Some(requested_root)) => requested_root == &self.actual_root_key,
+            (Some(_), None) => false,
+        }
+    }
+
+    fn matches_configuration(&self, requested: &Self) -> bool {
+        self.matches_storage(requested)
+            && self.username == requested.username
+            && self.database == requested.database
+            && self.startup_args == requested.startup_args
+            && self.selected_extensions == requested.selected_extensions
+            && self.icu_data == requested.icu_data
+    }
+}
+
+struct DirectResidentRoot {
+    root: PreparedNativeRoot,
+    key: DirectResidentKey,
+    configuration_bound: bool,
+}
+
+impl NativeSession {
+    pub fn open(config: OpenConfig) -> Result {
+        config.validate()?;
+        let instance_lease = acquire_direct_instance_lease()?;
+        let extensions = config.resolved_extensions()?;
+        let startup_args = startup_arg_strings(&config, &extensions);
+        let requested_key = DirectResidentKey::requested(&config, &extensions, startup_args)?;
+        let symbols = Arc::new(NativeSymbols::load()?);
+        let (root, configuration_bound) =
+            take_or_prepare_direct_root(&config, &extensions, &requested_key)?;
+        let resident_key = requested_key.bind_actual_root(&root)?;
+        match NativeSession::open_prepared(
+            symbols,
+            root,
+            config,
+            &extensions,
+            resident_key.clone(),
+            instance_lease,
+        ) {
+            Ok(session) => Ok(session),
+            Err(failure) => {
+                let DirectOpenFailure {
+                    root,
+                    error,
+                    native_open_attempted,
+                } = *failure;
+                if configuration_bound || native_open_attempted {
+                    // Once oliphaunt_init has run, the process-resident backend may
+                    // still own PGDATA even when it rejects the logical open.
+                    // Keep both persistent and SDK-temporary storage available
+                    // for a coherent retry instead of deleting or replacing it.
+                    store_direct_resident_root(root, resident_key, configuration_bound)?;
+                }
+                Err(error)
+            }
+        }
+    }
+}
+
+fn take_or_prepare_direct_root(
+    config: &OpenConfig,
+    extensions: &[Extension],
+    requested_key: &DirectResidentKey,
+) -> Result<(PreparedNativeRoot, bool)> {
+    let slot = DIRECT_RESIDENT_ROOT.get_or_init(|| Mutex::new(None));
+    let mut resident = slot
+        .lock()
+        .map_err(|_| Error::Engine("native direct resident root lock was poisoned".to_owned()))?;
+    if let Some(existing) = resident.take() {
+        let matches = if existing.configuration_bound {
+            existing.key.matches_configuration(requested_key)
+        } else {
+            existing.key.matches_storage(requested_key)
+        };
+        if matches {
+            return Ok((existing.root, existing.configuration_bound));
+        }
+        let bound_root = existing.key.actual_root_key.display().to_string();
+        *resident = Some(existing);
+        return Err(Error::Engine(format!(
+            "native direct resident runtime is already bound to root {bound_root}; use .broker() or OliphauntServer::builder().start() for multiple roots in one process"
+        )));
+    }
+    drop(resident);
+
+    PreparedNativeRoot::prepare(config, extensions).map(|root| (root, false))
+}
+
+fn store_direct_resident_root(
+    root: PreparedNativeRoot,
+    key: DirectResidentKey,
+    configuration_bound: bool,
+) -> Result<()> {
+    let slot = DIRECT_RESIDENT_ROOT.get_or_init(|| Mutex::new(None));
+    let mut resident = match slot.lock() {
+        Ok(resident) => resident,
+        Err(_) => {
+            std::mem::forget(root);
+            return Err(Error::Engine(
+                "native direct resident root lock was poisoned".into(),
+            ));
+        }
+    };
+    *resident = Some(DirectResidentRoot {
+        root,
+        key,
+        configuration_bound,
+    });
+    Ok(())
+}
+
+fn acquire_direct_instance_lease() -> Result {
+    DIRECT_INSTANCE_ACTIVE
+        .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
+        .map(|_| DirectInstanceLease)
+        .map_err(|_| {
+            Error::Engine("native direct already has an active process-wide instance".to_owned())
+        })
+}
+
+struct DirectInstanceLease;
+
+impl Drop for DirectInstanceLease {
+    fn drop(&mut self) {
+        DIRECT_INSTANCE_ACTIVE.store(false, Ordering::Release);
+    }
+}
+
+pub struct NativeSession {
+    symbols: Arc,
+    handle: Arc,
+    cancel: Arc,
+    root: Option,
+    resident_key: Option,
+    _lease: Option,
+}
+
+struct DirectOpenFailure {
+    root: PreparedNativeRoot,
+    error: Error,
+    native_open_attempted: bool,
+}
+
+impl DirectOpenFailure {
+    fn before_native(root: PreparedNativeRoot, error: Error) -> Box {
+        Box::new(Self {
+            root,
+            error,
+            native_open_attempted: false,
+        })
+    }
+
+    fn after_native(root: PreparedNativeRoot, error: Error) -> Box {
+        Box::new(Self {
+            root,
+            error,
+            native_open_attempted: true,
+        })
+    }
+}
+
+struct SharedNativeHandle {
+    generation: u64,
+    handle: RwLock<*mut NativeHandle>,
+}
+
+// SAFETY: The raw native handle is never accessed directly through shared
+// references. All users first take the RwLock: executor-owned protocol/backup
+// work holds a read lock, cancellation holds a read lock, and logical close
+// takes the write lock, calls `oliphaunt_detach`, then replaces the pointer
+// with null before releasing the process-wide direct-instance lease.
+unsafe impl Send for SharedNativeHandle {}
+// SAFETY: See the Send impl. The RwLock serializes pointer reads against close,
+// so shared references can only observe either the still-open handle or null.
+unsafe impl Sync for SharedNativeHandle {}
+
+#[derive(Clone)]
+pub struct NativeCancel {
+    symbols: Arc,
+    handle: Arc,
+}
+
+/// Concurrent input for an executing PostgreSQL protocol stream.
+///
+/// This keeps the native library and logical session alive, but does not keep a
+/// detached session usable. Each feed must name the exact active stream token.
+#[derive(Clone)]
+pub struct NativeProtocolInput {
+    _symbols: Arc,
+    handle: Arc,
+    token: ffi::StreamTokenFn,
+    feed: ffi::FeedStreamFn,
+}
+
+impl NativeProtocolInput {
+    /// Return the current stream token, or `None` while no stream is running.
+    pub fn active_token(&self) -> Result> {
+        let guard =
+            self.handle.handle.read().map_err(|_| {
+                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
+            })?;
+        if guard.is_null() {
+            return Err(Error::EngineStopped);
+        }
+        let token = unsafe { (self.token)(*guard) };
+        Ok((token != 0).then_some(token))
+    }
+
+    /// Supply complete frontend frames to the named stream.
+    ///
+    /// `false` means bounded native input storage is full: no bytes were
+    /// accepted, and the caller may retry the same bytes. Errors, including a
+    /// stale stream token, must not be retried against a newer stream.
+    pub fn feed(&self, token: u64, request: &[u8]) -> Result {
+        let guard =
+            self.handle.handle.read().map_err(|_| {
+                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
+            })?;
+        if guard.is_null() {
+            return Err(Error::EngineStopped);
+        }
+        let mut error = NativeErrorCapture::zeroed();
+        let rc = unsafe { (self.feed)(*guard, token, request.as_ptr(), request.len(), &mut error) };
+        match rc {
+            0 => Ok(true),
+            1 => Ok(false),
+            _ => Err(Error::Engine(captured_native_error(
+                &error,
+                "oliphaunt_feed_protocol_stream",
+                rc,
+            ))),
+        }
+    }
+}
+
+impl NativeCancel {
+    pub fn cancel(&self) -> Result<()> {
+        let guard =
+            self.handle.handle.read().map_err(|_| {
+                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
+            })?;
+        let handle = *guard;
+        if handle.is_null() {
+            return Err(Error::EngineStopped);
+        }
+        let rc = unsafe { (self.symbols.cancel)(handle) };
+        if rc != 0 {
+            let message = self
+                .symbols
+                .last_error_text(handle)
+                .unwrap_or_else(|| format!("oliphaunt_cancel failed with status {rc}"));
+            return Err(Error::Engine(format!(
+                "native liboliphaunt cancel failed: {message}"
+            )));
+        }
+        Ok(())
+    }
+}
+
+impl NativeSession {
+    fn open_prepared(
+        symbols: Arc,
+        root: PreparedNativeRoot,
+        config: OpenConfig,
+        extensions: &[Extension],
+        resident_key: DirectResidentKey,
+        lease: DirectInstanceLease,
+    ) -> std::result::Result> {
+        if let Err(error) = root.refresh_descriptor() {
+            return Err(DirectOpenFailure::before_native(root, error));
+        }
+        let pgdata = match path_to_cstring(&root.pgdata, "PGDATA") {
+            Ok(value) => value,
+            Err(error) => return Err(DirectOpenFailure::before_native(root, error)),
+        };
+        let runtime_dir = match path_to_cstring(&root.runtime_dir, "runtime dir") {
+            Ok(value) => value,
+            Err(error) => return Err(DirectOpenFailure::before_native(root, error)),
+        };
+        let module_dir = match path_to_cstring(
+            &root.runtime_dir.join("lib/postgresql"),
+            "embedded module dir",
+        ) {
+            Ok(value) => value,
+            Err(error) => return Err(DirectOpenFailure::before_native(root, error)),
+        };
+        let username = match CString::new(config.username.as_str()) {
+            Ok(value) => value,
+            Err(_) => {
+                return Err(DirectOpenFailure::before_native(
+                    root,
+                    Error::InvalidConfig("username contains an interior NUL".to_owned()),
+                ));
+            }
+        };
+        let database = match CString::new(config.database.as_str()) {
+            Ok(value) => value,
+            Err(_) => {
+                return Err(DirectOpenFailure::before_native(
+                    root,
+                    Error::InvalidConfig("database contains an interior NUL".to_owned()),
+                ));
+            }
+        };
+        let startup_args = match startup_args(&config, extensions) {
+            Ok(value) => value,
+            Err(error) => return Err(DirectOpenFailure::before_native(root, error)),
+        };
+        let icu_data = match config
+            .icu_data
+            .as_ref()
+            .map(|data| path_to_cstring(&data.directory, "ICU data directory"))
+            .transpose()
+        {
+            Ok(value) => value,
+            Err(error) => return Err(DirectOpenFailure::before_native(root, error)),
+        };
+        let startup_arg_ptrs = startup_args
+            .iter()
+            .map(|arg| arg.as_ptr())
+            .collect::>();
+        let native_config = FfiNativeConfig {
+            abi_version: ABI_VERSION,
+            pgdata: pgdata.as_ptr(),
+            runtime_dir: runtime_dir.as_ptr(),
+            module_dir: module_dir.as_ptr(),
+            username: username.as_ptr(),
+            database: database.as_ptr(),
+            flags: CONFIG_EXTERNAL_ROOT_LOCK,
+            startup_args: startup_arg_ptrs.as_ptr(),
+            startup_arg_count: startup_arg_ptrs.len(),
+            icu_data_dir: icu_data.as_ref().map_or(ptr::null(), |path| path.as_ptr()),
+        };
+        let handle = match init_handle(&symbols, &native_config) {
+            Ok(handle) => handle,
+            Err(error) => return Err(DirectOpenFailure::after_native(root, error)),
+        };
+
+        let handle = Arc::new(handle);
+        let cancel = Arc::new(NativeCancel {
+            symbols: Arc::clone(&symbols),
+            handle: Arc::clone(&handle),
+        });
+
+        Ok(Self {
+            symbols,
+            handle,
+            cancel,
+            root: Some(root),
+            resident_key: Some(resident_key),
+            _lease: Some(lease),
+        })
+    }
+
+    fn close_handle(&mut self) -> Result<()> {
+        let mut guard =
+            self.handle.handle.write().map_err(|_| {
+                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
+            })?;
+        let handle = *guard;
+        if handle.is_null() {
+            return Ok(());
+        }
+        let mut error = NativeErrorCapture::zeroed();
+        let rc = unsafe { (self.symbols.detach_with_error)(handle, &mut error) };
+        if rc != 0 {
+            let message = captured_native_error(&error, "oliphaunt_detach", rc);
+            return Err(Error::Engine(format!(
+                "native liboliphaunt detach failed: {message}"
+            )));
+        }
+        *guard = ptr::null_mut();
+        if let Some(root) = self.root.take() {
+            store_direct_resident_root(
+                root,
+                self.resident_key
+                    .take()
+                    .expect("prepared root has resident identity"),
+                true,
+            )?;
+        }
+        self._lease = None;
+        Ok(())
+    }
+
+    fn bytes_from_native_response(&self, mut response: NativeResponse) -> Vec {
+        let bytes = if response.data.is_null() {
+            Vec::new()
+        } else {
+            unsafe { std::slice::from_raw_parts(response.data, response.len).to_vec() }
+        };
+        unsafe { (self.symbols.free_response)(&mut response) };
+        bytes
+    }
+
+    fn free_failed_response(&self, response: &mut NativeResponse) {
+        if !response.data.is_null() {
+            unsafe { (self.symbols.free_response)(response) };
+        }
+    }
+}
+
+impl NativeSession {
+    pub fn cancel_handle(&self) -> NativeCancel {
+        (*self.cancel).clone()
+    }
+
+    /// Resolve the optional incremental-input capability before starting work.
+    /// Existing complete-buffer operations do not require these ABI symbols.
+    pub fn protocol_input(&self) -> Result {
+        let (token, feed) = self.symbols.stream_input_symbols()?;
+        Ok(NativeProtocolInput {
+            _symbols: Arc::clone(&self.symbols),
+            handle: Arc::clone(&self.handle),
+            token,
+            feed,
+        })
+    }
+
+    pub fn exec_protocol_raw(&mut self, request: &[u8]) -> Result> {
+        let guard =
+            self.handle.handle.read().map_err(|_| {
+                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
+            })?;
+        let handle = *guard;
+        if handle.is_null() {
+            return Err(Error::EngineStopped);
+        }
+        let bytes = request;
+        let mut response = NativeResponse {
+            data: ptr::null_mut(),
+            len: 0,
+        };
+        let mut error = NativeErrorCapture::zeroed();
+        let rc = unsafe {
+            (self.symbols.exec_protocol_with_error)(
+                handle,
+                bytes.as_ptr(),
+                bytes.len(),
+                &mut response,
+                &mut error,
+            )
+        };
+        if rc != 0 {
+            self.free_failed_response(&mut response);
+            let message = captured_native_error(&error, "oliphaunt_exec_protocol", rc);
+            return Err(Error::Engine(format!(
+                "native liboliphaunt protocol execution failed: {message}"
+            )));
+        }
+        if response.data.is_null() {
+            return Ok(Vec::new());
+        }
+        Ok(self.bytes_from_native_response(response))
+    }
+
+    pub fn exec_protocol_raw_stream>(
+        &mut self,
+        request: &[u8],
+        on_chunk: &mut dyn FnMut(&[u8]) -> std::result::Result<(), E>,
+    ) -> ProtocolStreamOutcome {
+        let guard = match self.handle.handle.read() {
+            Ok(guard) => guard,
+            Err(_) => {
+                return ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(
+                    "native liboliphaunt handle lock poisoned".to_owned(),
+                ));
+            }
+        };
+        let handle = *guard;
+        if handle.is_null() {
+            return ProtocolStreamOutcome::SessionStateUnknown(Error::EngineStopped);
+        }
+
+        let bytes = request;
+        let mut context = StreamContext {
+            on_chunk,
+            error: None,
+        };
+        let mut error = NativeErrorCapture::zeroed();
+        let rc = unsafe {
+            (self.symbols.exec_protocol_raw_stream_with_error)(
+                handle,
+                bytes.as_ptr(),
+                bytes.len(),
+                stream_callback::,
+                (&mut context as *mut StreamContext<'_, E>).cast(),
+                &mut error,
+            )
+        };
+        if rc == STREAM_CALLBACK_ABORTED_STATUS {
+            return match context.error {
+                Some(error) => ProtocolStreamOutcome::ReadyForQuery(Err(error.into_consumer_error())),
+                None => ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(
+                    "native liboliphaunt reported a recovered callback abort without a callback error"
+                        .to_owned(),
+                )),
+            };
+        }
+        if rc != 0 {
+            let message = captured_native_error(&error, "oliphaunt_exec_protocol_raw_stream", rc);
+            // Every non-sentinel failure is independently authoritative: it
+            // may have interrupted recovery and must not be masked by a
+            // callback error (or by the original panic retained by the
+            // blocking API).
+            return ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(format!(
+                "native liboliphaunt protocol stream failed: {message}"
+            )));
+        }
+        if context.error.is_some() {
+            return ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(
+                "native liboliphaunt reported stream success after rejecting its callback"
+                    .to_owned(),
+            ));
+        }
+        ProtocolStreamOutcome::ReadyForQuery(Ok(()))
+    }
+
+    pub fn exec_simple_query(&mut self, sql: &str) -> Result> {
+        if sql.as_bytes().contains(&0) {
+            return Err(Error::InvalidConfig(
+                "simple query contains an interior NUL byte".to_owned(),
+            ));
+        }
+        let guard =
+            self.handle.handle.read().map_err(|_| {
+                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
+            })?;
+        let handle = *guard;
+        if handle.is_null() {
+            return Err(Error::EngineStopped);
+        }
+        let mut response = NativeResponse {
+            data: ptr::null_mut(),
+            len: 0,
+        };
+        let mut error = NativeErrorCapture::zeroed();
+        let rc = unsafe {
+            (self.symbols.exec_simple_query_with_error)(
+                handle,
+                sql.as_ptr().cast::(),
+                sql.len(),
+                &mut response,
+                &mut error,
+            )
+        };
+        if rc != 0 {
+            self.free_failed_response(&mut response);
+            let message = captured_native_error(&error, "oliphaunt_exec_simple_query", rc);
+            return Err(Error::Engine(format!(
+                "native liboliphaunt simple query failed: {message}"
+            )));
+        }
+        Ok(self.bytes_from_native_response(response))
+    }
+
+    pub fn backup(&mut self) -> Result> {
+        let guard =
+            self.handle.handle.read().map_err(|_| {
+                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
+            })?;
+        let handle = *guard;
+        if handle.is_null() {
+            return Err(Error::EngineStopped);
+        }
+        let mut response = NativeResponse {
+            data: ptr::null_mut(),
+            len: 0,
+        };
+        let mut error = NativeErrorCapture::zeroed();
+        let rc = unsafe { (self.symbols.backup_with_error)(handle, &mut response, &mut error) };
+        if rc != 0 {
+            self.free_failed_response(&mut response);
+            let message = captured_native_error(&error, "oliphaunt_backup", rc);
+            return Err(Error::Engine(format!(
+                "native liboliphaunt physical backup failed: {message}"
+            )));
+        }
+        Ok(self.bytes_from_native_response(response))
+    }
+
+    pub fn close(&mut self) -> Result<()> {
+        self.close_handle()
+    }
+}
+
+fn captured_native_error(
+    capture: &NativeErrorCapture,
+    operation: &str,
+    status: std::ffi::c_int,
+) -> String {
+    capture
+        .error_text()
+        .unwrap_or_else(|| format!("{operation} failed with status {status}"))
+}
+
+impl Drop for NativeSession {
+    fn drop(&mut self) {
+        if self.close_handle().is_err() {
+            // Native teardown is unconfirmed. Keep storage and the process
+            // lease alive rather than delete a database still owned by C.
+            if let Some(root) = self.root.take() {
+                std::mem::forget(root);
+            }
+            if let Some(lease) = self._lease.take() {
+                std::mem::forget(lease);
+            }
+        }
+    }
+}
+
+fn startup_arg_strings(config: &OpenConfig, extensions: &[Extension]) -> Vec {
+    let mut args = Vec::new();
+    for assignment in config.postgres_startup_assignments(extensions) {
+        args.push("-c".to_owned());
+        args.push(assignment);
+    }
+    args
+}
+
+fn startup_args(config: &OpenConfig, extensions: &[Extension]) -> Result> {
+    let args = startup_arg_strings(config, extensions);
+    args.into_iter()
+        .map(|arg| {
+            CString::new(arg).map_err(|_| {
+                Error::InvalidConfig("startup argument contains an interior NUL".to_owned())
+            })
+        })
+        .collect()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn direct_temporary_storage_matches_the_process_resident_instance() {
+        let key = DirectResidentKey {
+            requested_root_key: None,
+            actual_root_key: PathBuf::from("/tmp/oliphaunt-resident"),
+            username: "postgres".to_owned(),
+            database: "postgres".to_owned(),
+            startup_args: Vec::new(),
+            selected_extensions: Vec::new(),
+            icu_data: None,
+        };
+        let requested = DirectResidentKey {
+            actual_root_key: PathBuf::new(),
+            ..key.clone()
+        };
+
+        assert!(key.matches_storage(&requested));
+        assert!(key.matches_configuration(&requested));
+    }
+
+    #[test]
+    fn failed_direct_open_storage_can_retry_with_corrected_configuration() {
+        let key = DirectResidentKey {
+            requested_root_key: None,
+            actual_root_key: PathBuf::from("/tmp/oliphaunt-failed-open"),
+            username: "missing-role".to_owned(),
+            database: "postgres".to_owned(),
+            startup_args: Vec::new(),
+            selected_extensions: Vec::new(),
+            icu_data: None,
+        };
+        let corrected = DirectResidentKey {
+            requested_root_key: None,
+            actual_root_key: PathBuf::new(),
+            username: "postgres".to_owned(),
+            database: "postgres".to_owned(),
+            startup_args: Vec::new(),
+            selected_extensions: Vec::new(),
+            icu_data: None,
+        };
+
+        assert!(key.matches_storage(&corrected));
+        assert!(!key.matches_configuration(&corrected));
+    }
+
+    #[test]
+    fn direct_startup_args_include_required_preload_libraries_before_init() {
+        let mut config = OpenConfig::direct("target/test-roots/native-direct-preload");
+        config.startup_gucs = vec![crate::config::PostgresStartupGuc::new(
+            "shared_preload_libraries",
+            "auto_explain, pg_textsearch",
+        )];
+        config.extensions = vec![Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH];
+        let extensions = config.resolved_extensions().unwrap();
+        let args = startup_args(&config, &extensions).unwrap();
+        let args = args
+            .iter()
+            .map(|arg| arg.to_string_lossy().into_owned())
+            .collect::>();
+
+        assert_startup_config_arg(&args, "shared_preload_libraries=auto_explain,pg_textsearch");
+        assert_eq!(
+            args.iter()
+                .filter(|arg| arg.starts_with("shared_preload_libraries="))
+                .count(),
+            1,
+            "caller and extension preload libraries must be merged once before oliphaunt_init"
+        );
+    }
+
+    #[test]
+    fn direct_startup_args_omit_preload_when_selected_extensions_do_not_require_it() {
+        let config = OpenConfig::direct("target/test-roots/native-direct-no-preload");
+        let args = startup_args(&config, &[Extension::VECTOR]).unwrap();
+        let args = args
+            .iter()
+            .map(|arg| arg.to_string_lossy().into_owned())
+            .collect::>();
+
+        assert!(
+            !args
+                .iter()
+                .any(|arg| arg.starts_with("shared_preload_libraries=")),
+            "direct startup args must not add preload settings for extensions that do not require them: {args:?}"
+        );
+    }
+
+    #[test]
+    fn invalid_startup_gucs_are_rejected_before_open() {
+        let mut config = OpenConfig::direct("target/test-roots/native-direct-invalid-guc");
+        config.startup_gucs = vec![crate::config::PostgresStartupGuc::new(
+            "shared-buffers",
+            "16MB",
+        )];
+
+        let error = config.validate().unwrap_err();
+        assert!(
+            error
+                .to_string()
+                .contains("each dot-separated component must start"),
+            "{error}"
+        );
+    }
+
+    fn assert_startup_config_arg(args: &[String], expected: &str) {
+        let Some(index) = args.iter().position(|arg| arg == expected) else {
+            panic!("missing direct startup argument {expected:?} in {args:?}");
+        };
+        assert_eq!(
+            args.get(index.saturating_sub(1)).map(String::as_str),
+            Some("-c"),
+            "direct startup argument {expected:?} must be passed through postgres -c"
+        );
+    }
+}
+
+/// Native inputs already prepared and owned by the host application.
+pub struct NativeOpenOptions {
+    /// Load this library, or resolve already linked/global symbols on Unix.
+    pub library_path: Option,
+    pub pgdata: PathBuf,
+    pub runtime_directory: Option,
+    pub module_directory: Option,
+    /// Explicit ICU data directory; independent of the host process environment.
+    pub icu_data_directory: Option,
+    pub username: String,
+    pub database: String,
+    pub startup_args: Vec,
+}
+
+impl NativeSession {
+    /// Open host-prepared inputs without assembling or deleting their resources.
+    /// The native library acquires the database root lock itself.
+    pub fn open_prepared_inputs(options: NativeOpenOptions) -> Result {
+        let lease = acquire_direct_instance_lease()?;
+        let symbols = Arc::new(match &options.library_path {
+            Some(path) => NativeSymbols::load_path(path)?,
+            None => NativeSymbols::load_current_process()?,
+        });
+        let pgdata = path_to_cstring(&options.pgdata, "PGDATA")?;
+        let runtime = options
+            .runtime_directory
+            .as_deref()
+            .filter(|path| !path.as_os_str().is_empty())
+            .map(|p| path_to_cstring(p, "runtime directory"))
+            .transpose()?;
+        let modules = options
+            .module_directory
+            .as_deref()
+            .filter(|path| !path.as_os_str().is_empty())
+            .map(|p| path_to_cstring(p, "module directory"))
+            .transpose()?;
+        let username = CString::new(options.username)
+            .map_err(|_| Error::InvalidConfig("username contains an interior NUL".into()))?;
+        let database = CString::new(options.database)
+            .map_err(|_| Error::InvalidConfig("database contains an interior NUL".into()))?;
+        let icu_data = options
+            .icu_data_directory
+            .as_deref()
+            .map(|path| path_to_cstring(path, "ICU data directory"))
+            .transpose()?;
+        let args = options
+            .startup_args
+            .into_iter()
+            .map(|arg| {
+                CString::new(arg).map_err(|_| {
+                    Error::InvalidConfig("startup argument contains an interior NUL".into())
+                })
+            })
+            .collect::>>()?;
+        let arg_ptrs = args.iter().map(|arg| arg.as_ptr()).collect::>();
+        let config = FfiNativeConfig {
+            abi_version: ABI_VERSION,
+            pgdata: pgdata.as_ptr(),
+            runtime_dir: runtime.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
+            module_dir: modules.as_ref().map_or(ptr::null(), |p| p.as_ptr()),
+            username: username.as_ptr(),
+            database: database.as_ptr(),
+            flags: 0,
+            startup_args: arg_ptrs.as_ptr(),
+            startup_arg_count: arg_ptrs.len(),
+            icu_data_dir: icu_data.as_ref().map_or(ptr::null(), |path| path.as_ptr()),
+        };
+        let handle = Arc::new(init_handle(&symbols, &config)?);
+        let cancel = Arc::new(NativeCancel {
+            symbols: symbols.clone(),
+            handle: handle.clone(),
+        });
+        Ok(Self {
+            symbols,
+            handle,
+            cancel,
+            root: None,
+            resident_key: None,
+            _lease: Some(lease),
+        })
+    }
+}
+
+fn init_handle(symbols: &NativeSymbols, config: &FfiNativeConfig) -> Result {
+    symbols.register_selected_extensions()?;
+    let mut handle = ptr::null_mut();
+    let mut error = NativeErrorCapture::zeroed();
+    let rc = unsafe { (symbols.init_with_error)(config, &mut handle, &mut error) };
+    if rc != 0 || handle.is_null() {
+        let message = error.error_text().unwrap_or_else(|| {
+            if rc == 0 {
+                "oliphaunt_init returned a null handle".to_owned()
+            } else {
+                format!("oliphaunt_init failed with status {rc}")
+            }
+        });
+        return Err(Error::Engine(format!(
+            "native liboliphaunt init failed: {message}"
+        )));
+    }
+    let generation = unsafe { (symbols.logical_generation)(handle) };
+    if generation == 0 {
+        return Err(Error::Engine(
+            "native session has no logical generation".into(),
+        ));
+    }
+    Ok(SharedNativeHandle {
+        generation,
+        handle: RwLock::new(handle),
+    })
+}
+
+impl NativeSession {
+    /// Terminally close this native generation before releasing its root and
+    /// process-wide instance lease. Hosts must first release any stream callback
+    /// waiting for their event loop so active execution can finish.
+    pub fn close_terminal(&mut self) -> Result<()> {
+        if self.close_terminal_if_owned()? {
+            Ok(())
+        } else {
+            Err(Error::Engine(
+                "native session no longer owns terminal cleanup".into(),
+            ))
+        }
+    }
+
+    /// Close this generation, returning false if a newer owner has authority.
+    /// Actual cleanup failures remain errors and retain the root and lease.
+    pub fn close_terminal_if_owned(&mut self) -> Result {
+        // A detached session no longer owns the Rust process lease. Do not
+        // wait for or interrupt a newer active session or an in-progress open.
+        let _detached_lease = if self._lease.is_none() {
+            match acquire_direct_instance_lease() {
+                Ok(lease) => Some(lease),
+                Err(_) => return Ok(false),
+            }
+        } else {
+            None
+        };
+        let mut guard = self
+            .handle
+            .handle
+            .write()
+            .map_err(|_| Error::Engine("native handle lock poisoned".into()))?;
+        let status = unsafe { (self.symbols.close_if_generation)(self.handle.generation) };
+        match status {
+            0 => {}
+            1 => return Ok(false),
+            _ => {
+                return Err(Error::Engine(format!(
+                    "native generation cleanup failed with status {status}"
+                )));
+            }
+        }
+        *guard = ptr::null_mut();
+        drop(guard);
+        self.root = None;
+        self.resident_key = None;
+        if let Some(slot) = DIRECT_RESIDENT_ROOT.get() {
+            // C has stopped. No Rust opener can race the detached lease held
+            // above, so its retained temporary root can now be removed safely.
+            if let Ok(mut resident) = slot.lock() {
+                resident.take();
+            }
+        }
+        self._lease = None;
+        Ok(true)
+    }
+}
+
+enum StreamCallbackFailure {
+    Consumer(E),
+    Native(Error),
+    Panic(Box),
+}
+impl> StreamCallbackFailure {
+    // Called only after the C function has confirmed recovery and returned.
+    fn into_consumer_error(self) -> E {
+        match self {
+            Self::Consumer(error) => error,
+            Self::Native(error) => error.into(),
+            Self::Panic(payload) => std::panic::resume_unwind(payload),
+        }
+    }
+}
+struct StreamContext<'a, E> {
+    on_chunk: &'a mut dyn FnMut(&[u8]) -> std::result::Result<(), E>,
+    error: Option>,
+}
+
+unsafe extern "C" fn stream_callback>(
+    context: *mut std::ffi::c_void,
+    data: *const std::ffi::c_uchar,
+    len: usize,
+) -> std::ffi::c_int {
+    let context = unsafe { &mut *(context.cast::>()) };
+    if context.error.is_some() {
+        return -1;
+    }
+    if data.is_null() && len > 0 {
+        context.error = Some(StreamCallbackFailure::Native(Error::Engine(
+            "native liboliphaunt stream callback received null data".to_owned(),
+        )));
+        return -1;
+    }
+    let bytes = if len == 0 {
+        &[]
+    } else {
+        unsafe { std::slice::from_raw_parts(data, len) }
+    };
+    match catch_unwind(AssertUnwindSafe(|| (context.on_chunk)(bytes))) {
+        Ok(Ok(())) => 0,
+        Ok(Err(error)) => {
+            context.error = Some(StreamCallbackFailure::Consumer(error));
+            -1
+        }
+        Err(payload) => {
+            context.error = Some(StreamCallbackFailure::Panic(payload));
+            -1
+        }
+    }
+}
+
+#[cfg(test)]
+mod callback_safety_tests {
+    use super::*;
+
+    struct ConsumerError(Arc<()>);
+    impl From for ConsumerError {
+        fn from(_: Error) -> Self {
+            std::panic::panic_any("consumer conversion panicked");
+        }
+    }
+
+    #[test]
+    fn native_callback_error_conversion_cannot_unwind_through_c() {
+        let mut callback = |_: &[u8]| Ok::<(), ConsumerError>(());
+        let mut context = StreamContext {
+            on_chunk: &mut callback,
+            error: None,
+        };
+        assert_eq!(
+            unsafe {
+                stream_callback::(
+                    (&mut context as *mut StreamContext<'_, ConsumerError>).cast(),
+                    ptr::null(),
+                    1,
+                )
+            },
+            -1
+        );
+        let failure = context.error.take().unwrap();
+        let panic = catch_unwind(AssertUnwindSafe(|| failure.into_consumer_error()));
+        assert_eq!(
+            panic.err().unwrap().downcast_ref::<&str>(),
+            Some(&"consumer conversion panicked")
+        );
+    }
+
+    #[test]
+    fn callback_panic_payload_is_resumed_after_returning_from_c() {
+        let original = Arc::new(());
+        let payload = original.clone();
+        let mut callback = move |_: &[u8]| -> std::result::Result<(), ConsumerError> {
+            std::panic::panic_any(payload.clone())
+        };
+        let mut context = StreamContext {
+            on_chunk: &mut callback,
+            error: None,
+        };
+        assert_eq!(
+            unsafe {
+                stream_callback::(
+                    (&mut context as *mut StreamContext<'_, ConsumerError>).cast(),
+                    ptr::null(),
+                    0,
+                )
+            },
+            -1
+        );
+        let failure = context.error.take().unwrap();
+        let panic = catch_unwind(AssertUnwindSafe(|| failure.into_consumer_error()));
+        assert!(Arc::ptr_eq(
+            &original,
+            panic.err().unwrap().downcast_ref::>().unwrap()
+        ));
+    }
+
+    #[test]
+    fn callback_error_identity_survives_additional_recovery_chunks() {
+        let original = Arc::new(());
+        let error = original.clone();
+        let mut calls = 0;
+        let mut callback = |_: &[u8]| {
+            calls += 1;
+            Err(ConsumerError(error.clone()))
+        };
+        let mut context = StreamContext {
+            on_chunk: &mut callback,
+            error: None,
+        };
+        for _ in 0..2 {
+            assert_eq!(
+                unsafe {
+                    stream_callback::(
+                        (&mut context as *mut StreamContext<'_, ConsumerError>).cast(),
+                        ptr::null(),
+                        0,
+                    )
+                },
+                -1
+            );
+        }
+        let error = context.error.take().unwrap().into_consumer_error();
+        assert!(Arc::ptr_eq(&original, &error.0));
+        assert_eq!(calls, 1);
+    }
+}
diff --git a/src/sdks/rust/src/liboliphaunt/root.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root.rs
similarity index 92%
rename from src/sdks/rust/src/liboliphaunt/root.rs
rename to src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root.rs
index 4b8e3b2b9..bd5a29ef1 100644
--- a/src/sdks/rust/src/liboliphaunt/root.rs
+++ b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root.rs
@@ -3,6 +3,7 @@ mod descriptor;
 mod extensions;
 mod files;
 mod fingerprint;
+pub(super) mod resources;
 mod runtime;
 
 use std::env;
@@ -17,7 +18,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
 use fs2::FileExt;
 use sha2::{Digest, Sha256};
 
-use crate::config::{DEFAULT_USERNAME, EngineMode, OpenConfig};
+use crate::config::{DEFAULT_USERNAME, NativeConfig as OpenConfig};
 use crate::error::{Error, Result};
 use crate::extension::Extension;
 use crate::storage::DatabaseStorage;
@@ -43,37 +44,48 @@ impl NativeCatalogProfile {
 
 #[cfg(feature = "internal-native-packaging")]
 pub(crate) struct MaterializedNativeResources {
-    pub(crate) runtime_dir: PathBuf,
-    pub(crate) cluster_seed: PathBuf,
+    pub runtime_dir: PathBuf,
     pub(crate) runtime_cache_key: String,
-    pub(crate) cluster_seed_cache_key: String,
 }
 
-pub(crate) struct PreparedNativeRoot {
-    pub(crate) root: PathBuf,
-    pub(crate) pgdata: PathBuf,
-    pub(crate) runtime_dir: PathBuf,
+pub struct PreparedNativeRoot {
+    pub root: PathBuf,
+    pub pgdata: PathBuf,
+    pub runtime_dir: PathBuf,
     lock: Option,
     temporary: bool,
 }
 
 impl PreparedNativeRoot {
-    pub(crate) fn prepare(config: &OpenConfig, extensions: &[Extension]) -> Result {
-        Self::prepare_inner(config, extensions, true)
+    pub fn prepare(config: &OpenConfig, extensions: &[Extension]) -> Result {
+        Self::prepare_inner(
+            config,
+            extensions,
+            true,
+            NativeRuntimeProfile::OliphauntEmbedded,
+        )
     }
 
-    pub(crate) fn prepare_for_server(
-        config: &OpenConfig,
-        extensions: &[Extension],
-    ) -> Result {
-        Self::prepare_inner(config, extensions, true)
+    pub fn prepare_for_server(config: &OpenConfig, extensions: &[Extension]) -> Result {
+        Self::prepare_inner(
+            config,
+            extensions,
+            true,
+            NativeRuntimeProfile::PostgresServer,
+        )
     }
 
     fn prepare_inner(
         config: &OpenConfig,
         extensions: &[Extension],
         lock_root: bool,
+        profile: NativeRuntimeProfile,
     ) -> Result {
+        if profile == NativeRuntimeProfile::PostgresServer && config.seed.is_some() {
+            return Err(Error::InvalidConfig(
+                "embedded cluster seeds cannot initialize server mode".into(),
+            ));
+        }
         let (root, temporary) = match &config.storage {
             DatabaseStorage::Directory(root) => (root.clone(), false),
             DatabaseStorage::TemporaryDirectory => (create_temporary_root()?, true),
@@ -111,11 +123,23 @@ impl PreparedNativeRoot {
             )));
         }
         let pgdata = root.join("pgdata");
-        let runtime_closure = runtime::resolve_runtime_closure(
-            NativeRuntimeProfile::for_mode(config.mode),
-            extensions,
-            None,
-        )?;
+        let runtime_closure =
+            runtime::resolve_runtime_closure(profile, extensions, None, config.icu_data.as_ref())?;
+        let selected_seed = if initialized {
+            None
+        } else {
+            config
+                .seed
+                .as_ref()
+                .map(|seed| {
+                    resources::validate_seed(
+                        seed,
+                        runtime_closure.catalog_profile,
+                        runtime_closure.icu_tree_sha256.as_deref(),
+                    )
+                })
+                .transpose()?
+        };
         let runtime_dir = runtime_closure.runtime_dir;
         let mut pgdata_cleanup = CreatedPgdataCleanup::new();
         if !initialized {
@@ -132,14 +156,16 @@ impl PreparedNativeRoot {
                     ))
                 })?;
                 pgdata_cleanup.arm(staging_pgdata.clone());
-                cluster_seed::bootstrap_pgdata_if_needed(
-                    NativeRuntimeProfile::for_mode(config.mode),
-                    &runtime_dir,
-                    &runtime_closure.initdb_runtime_dir,
-                    runtime_closure.catalog_profile,
-                    runtime_closure.cluster_seed_dir.as_deref(),
-                    &staging_pgdata,
-                )?;
+                if let Some(seed) = selected_seed {
+                    resources::restore_seed(seed, &staging_pgdata)?;
+                } else {
+                    cluster_seed::bootstrap_pgdata_if_needed(
+                        &runtime_dir,
+                        &runtime_closure.initdb_runtime_dir,
+                        runtime_closure.catalog_profile,
+                        &staging_pgdata,
+                    )?;
+                }
                 sync_directory_tree(&staging_pgdata)?;
                 fs::rename(&staging_pgdata, &pgdata).map_err(|err| {
                     Error::Engine(format!(
@@ -173,15 +199,15 @@ impl PreparedNativeRoot {
         Ok(prepared)
     }
 
-    pub(crate) fn tool_path(&self, tool_name: &str) -> PathBuf {
+    pub fn tool_path(&self, tool_name: &str) -> PathBuf {
         native_tool_path(&self.runtime_dir, tool_name)
     }
 
-    pub(crate) fn refresh_descriptor(&self) -> Result<()> {
+    pub fn refresh_descriptor(&self) -> Result<()> {
         descriptor::validate_existing_root(&self.root)
     }
 
-    pub(crate) fn root_key(&self) -> Result {
+    pub fn root_key(&self) -> Result {
         native_root_key(&self.root)
     }
 }
@@ -293,7 +319,7 @@ pub(super) fn existing_native_tool_path(root: &Path, tool_name: &str) -> PathBuf
     root.join("bin").join(tool_name)
 }
 
-pub(crate) fn configure_native_tool_env(command: &mut Command, runtime_dir: &Path) {
+pub fn configure_native_tool_env(command: &mut Command, runtime_dir: &Path) {
     for key in [
         "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY",
         "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY",
@@ -480,7 +506,7 @@ fn canonical_root_key(root: &Path) -> Result {
     Ok(normalize_path(&absolute))
 }
 
-pub(crate) fn native_root_key(root: &Path) -> Result {
+pub fn native_root_key(root: &Path) -> Result {
     canonical_root_key(root)
 }
 
@@ -528,37 +554,18 @@ fn release_active_root(key: &Path) {
 }
 
 #[cfg(feature = "internal-native-packaging")]
-pub(crate) fn materialize_native_resources_for_runtime(
-    mode: EngineMode,
+pub(super) fn materialize_native_resources_for_runtime(
+    profile: NativeRuntimeProfile,
     extensions: &[Extension],
     catalog_profile: NativeCatalogProfile,
 ) -> Result {
-    let profile = NativeRuntimeProfile::for_mode(mode);
     let runtime_closure =
-        runtime::resolve_runtime_closure(profile, extensions, Some(catalog_profile))?;
+        runtime::resolve_runtime_closure(profile, extensions, Some(catalog_profile), None)?;
     let runtime_dir = runtime_closure.runtime_dir;
-    let cluster_seed = cluster_seed::materialize_cluster_seed(
-        profile,
-        &runtime_dir,
-        &runtime_closure.initdb_runtime_dir,
-        runtime_closure.catalog_profile,
-    )?;
     let runtime_cache_key = cache_key_from_leaf(&runtime_dir, "native runtime cache")?;
-    let cluster_seed_cache_key = cluster_seed
-        .parent()
-        .ok_or_else(|| {
-            Error::Engine(format!(
-                "native cluster-seed path {} has no cache-key parent",
-                cluster_seed.display()
-            ))
-        })
-        .and_then(|parent| cache_key_from_leaf(parent, "native PGDATA cluster seed cache"))?;
-
     Ok(MaterializedNativeResources {
         runtime_dir,
-        cluster_seed,
         runtime_cache_key,
-        cluster_seed_cache_key,
     })
 }
 
@@ -569,13 +576,6 @@ pub(super) enum NativeRuntimeProfile {
 }
 
 impl NativeRuntimeProfile {
-    fn for_mode(mode: EngineMode) -> Self {
-        match mode {
-            EngineMode::Direct | EngineMode::Broker => Self::OliphauntEmbedded,
-            EngineMode::Server => Self::PostgresServer,
-        }
-    }
-
     pub(super) const fn cache_id(self) -> &'static str {
         match self {
             Self::OliphauntEmbedded => "liboliphaunt-embedded",
@@ -925,6 +925,7 @@ mod tests {
             flags: 0,
             startup_args: std::ptr::null(),
             startup_arg_count: 0,
+            icu_data_dir: std::ptr::null(),
         };
         let symbols = NativeSymbols::load().unwrap();
         let mut handle: *mut NativeHandle = std::ptr::null_mut();
diff --git a/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/cluster_seed.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/cluster_seed.rs
new file mode 100644
index 000000000..1dac37f4a
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/cluster_seed.rs
@@ -0,0 +1,456 @@
+use std::ffi::OsString;
+use std::fs;
+use std::path::Path;
+use std::process::{Command, Stdio};
+
+use super::{NativeCatalogProfile, configure_native_tool_env, native_tool_path};
+use crate::error::{Error, Result};
+
+const SKIP_SYSTEM_COLLATION_DISCOVERY_ENV: &str =
+    "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY";
+const SKIP_ICU_COLLATION_DISCOVERY_ENV: &str = "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY";
+
+pub(super) fn bootstrap_pgdata_if_needed(
+    runtime_dir: &Path,
+    initdb_runtime_dir: &Path,
+    catalog_profile: NativeCatalogProfile,
+    pgdata: &Path,
+) -> Result<()> {
+    if pgdata.join("PG_VERSION").is_file() {
+        return Ok(());
+    }
+    run_initdb(
+        initdb_runtime_dir,
+        runtime_dir,
+        catalog_profile,
+        pgdata,
+        "database",
+        false,
+    )
+}
+
+fn run_initdb(
+    initdb_runtime_dir: &Path,
+    runtime_dir: &Path,
+    catalog_profile: NativeCatalogProfile,
+    pgdata: &Path,
+    context: &str,
+    skip_system_collation_discovery: bool,
+) -> Result<()> {
+    let initdb = native_tool_path(initdb_runtime_dir, "initdb");
+    if !initdb.is_file() {
+        return Err(Error::Engine(format!(
+            "native {context} initialization requires initdb at {}",
+            initdb.display()
+        )));
+    }
+    let mut command = Command::new(&initdb);
+    configure_cluster_seed_runtime_env(
+        &mut command,
+        initdb_runtime_dir,
+        runtime_dir,
+        catalog_profile,
+        skip_system_collation_discovery,
+    );
+    let output = command
+        .args(initdb_args(initdb_runtime_dir, pgdata))
+        .stdout(Stdio::null())
+        .stderr(Stdio::piped())
+        .output()
+        .map_err(|err| {
+            Error::Engine(format!(
+                "run native {context} initdb {}: {err}",
+                initdb.display()
+            ))
+        })?;
+    if output.status.success() {
+        return Ok(());
+    }
+    let stderr = String::from_utf8_lossy(&output.stderr);
+    Err(Error::Engine(format!(
+        "native {context} initdb {} failed with status {}: {}",
+        initdb.display(),
+        output.status,
+        stderr.trim()
+    )))
+}
+
+fn initdb_args(runtime_dir: &Path, pgdata: &Path) -> Vec {
+    vec![
+        "-D".into(),
+        pgdata.as_os_str().to_owned(),
+        "-U".into(),
+        "postgres".into(),
+        "--auth=trust".into(),
+        "--locale-provider=libc".into(),
+        "--locale=C".into(),
+        "--encoding=UTF8".into(),
+        "-L".into(),
+        runtime_dir.join("share/postgresql").into_os_string(),
+    ]
+}
+
+fn configure_cluster_seed_runtime_env(
+    command: &mut Command,
+    initdb_runtime_dir: &Path,
+    runtime_dir: &Path,
+    catalog_profile: super::NativeCatalogProfile,
+    skip_system_collation_discovery: bool,
+) {
+    configure_native_tool_env(command, initdb_runtime_dir);
+    command.env_remove("ICU_DATA");
+    command.env_remove("OLIPHAUNT_INTERNAL_ICU_READY");
+    command.env_remove(SKIP_SYSTEM_COLLATION_DISCOVERY_ENV);
+    command.env_remove(SKIP_ICU_COLLATION_DISCOVERY_ENV);
+    if skip_system_collation_discovery {
+        command.env(SKIP_SYSTEM_COLLATION_DISCOVERY_ENV, "1");
+    }
+    if catalog_profile == super::NativeCatalogProfile::Standard {
+        command.env(SKIP_ICU_COLLATION_DISCOVERY_ENV, "1");
+    }
+    let icu_data = runtime_dir.join("share/icu");
+    if catalog_profile == super::NativeCatalogProfile::Icu && icu_data.is_dir() {
+        command.env("ICU_DATA", icu_data);
+        command.env("OLIPHAUNT_INTERNAL_ICU_READY", "1");
+    }
+}
+
+pub(super) const fn native_dynamic_shared_memory_type() -> &'static str {
+    if cfg!(target_os = "windows") {
+        "windows"
+    } else {
+        "mmap"
+    }
+}
+
+pub(super) fn normalize_cluster_seed_conf(
+    pgdata: &Path,
+    dynamic_shared_memory_type: &str,
+) -> Result<()> {
+    let conf = pgdata.join("postgresql.conf");
+    if !conf.is_file() {
+        return Ok(());
+    }
+    let contents = fs::read_to_string(&conf).map_err(|err| {
+        Error::Engine(format!(
+            "read native cluster-seed config {}: {err}",
+            conf.display()
+        ))
+    })?;
+    let settings = [
+        ("shared_memory_type", dynamic_shared_memory_type),
+        ("dynamic_shared_memory_type", dynamic_shared_memory_type),
+        ("log_timezone", "'UTC'"),
+        ("timezone", "'UTC'"),
+        ("lc_messages", "'C'"),
+        ("lc_monetary", "'C'"),
+        ("lc_numeric", "'C'"),
+        ("lc_time", "'C'"),
+    ];
+    let mut seen = vec![false; settings.len()];
+    let mut normalized = String::with_capacity(contents.len());
+    for line in contents.lines() {
+        if let Some(index) = settings
+            .iter()
+            .position(|(key, _)| active_config_key(line) == Some(*key))
+        {
+            let (key, value) = settings[index];
+            normalized.push_str(key);
+            normalized.push_str(" = ");
+            normalized.push_str(value);
+            seen[index] = true;
+        } else {
+            normalized.push_str(line);
+        }
+        normalized.push('\n');
+    }
+    for (index, (key, value)) in settings.iter().enumerate() {
+        if !seen[index] {
+            normalized.push_str(key);
+            normalized.push_str(" = ");
+            normalized.push_str(value);
+            normalized.push('\n');
+        }
+    }
+    if normalized != contents {
+        fs::write(&conf, normalized).map_err(|err| {
+            Error::Engine(format!(
+                "write native cluster-seed config {}: {err}",
+                conf.display()
+            ))
+        })?;
+    }
+    Ok(())
+}
+
+fn active_config_key(line: &str) -> Option<&str> {
+    let trimmed = line.trim_start();
+    if trimmed.starts_with('#') {
+        return None;
+    }
+    let (key, _) = trimmed.split_once('=')?;
+    let key = key.trim_end();
+    (!key.is_empty()).then_some(key)
+}
+
+#[cfg(test)]
+mod tests {
+    use std::ffi::OsStr;
+    use std::fs;
+    use std::path::Path;
+
+    use super::{
+        SKIP_ICU_COLLATION_DISCOVERY_ENV, SKIP_SYSTEM_COLLATION_DISCOVERY_ENV,
+        configure_cluster_seed_runtime_env, initdb_args, normalize_cluster_seed_conf,
+    };
+    use crate::liboliphaunt::root::NativeCatalogProfile;
+
+    #[test]
+    fn cluster_seed_initdb_forces_mobile_safe_locale() {
+        let args = initdb_args(
+            Path::new("/runtime"),
+            Path::new("/cache/cluster-seed/pgdata"),
+        );
+
+        assert!(args.iter().any(|arg| arg == OsStr::new("--locale=C")));
+        assert!(
+            args.iter()
+                .any(|arg| arg == OsStr::new("--locale-provider=libc"))
+        );
+        assert!(args.iter().any(|arg| arg == OsStr::new("--encoding=UTF8")));
+    }
+
+    #[test]
+    fn fresh_initdb_uses_fixed_bootstrap_identity_and_packaged_storage() {
+        let args = initdb_args(Path::new("/runtime"), Path::new("/app/database/pgdata"));
+
+        assert_eq!(args[0], OsStr::new("-D"));
+        assert_eq!(args[1], OsStr::new("/app/database/pgdata"));
+        assert_eq!(args[2], OsStr::new("-U"));
+        assert_eq!(args[3], OsStr::new("postgres"));
+        assert!(args.iter().any(|arg| arg == OsStr::new("--auth=trust")));
+        assert!(!args.iter().any(|arg| arg == OsStr::new("--no-sync")));
+        assert!(
+            args.iter()
+                .any(|arg| arg == OsStr::new("/runtime/share/postgresql"))
+        );
+    }
+
+    #[test]
+    fn cluster_seed_initdb_sets_icu_data_when_materialized() {
+        let root = std::env::temp_dir().join(format!(
+            "oliphaunt-cluster-seed-icu-{}-{}",
+            std::process::id(),
+            std::thread::current().name().unwrap_or("test")
+        ));
+        let _ = fs::remove_dir_all(&root);
+        let runtime = root.join("runtime");
+        let icu_data = runtime.join("share/icu");
+        fs::create_dir_all(&icu_data).unwrap();
+
+        let mut command = std::process::Command::new("initdb");
+        configure_cluster_seed_runtime_env(
+            &mut command,
+            &runtime,
+            &runtime,
+            NativeCatalogProfile::Icu,
+            false,
+        );
+
+        assert_eq!(
+            command
+                .get_envs()
+                .find(|(key, _)| *key == OsStr::new("ICU_DATA"))
+                .and_then(|(_, value)| value)
+                .map(std::path::PathBuf::from),
+            Some(icu_data)
+        );
+        assert_eq!(
+            command
+                .get_envs()
+                .find(|(key, _)| *key == OsStr::new("OLIPHAUNT_INTERNAL_ICU_READY"))
+                .and_then(|(_, value)| value),
+            Some(OsStr::new("1"))
+        );
+        let _ = fs::remove_dir_all(&root);
+    }
+
+    #[test]
+    fn standard_seed_clears_ambient_icu_selection() {
+        let mut command = std::process::Command::new("initdb");
+        command.env("ICU_DATA", "/ambient/icu");
+        command.env("OLIPHAUNT_INTERNAL_ICU_READY", "1");
+        configure_cluster_seed_runtime_env(
+            &mut command,
+            Path::new("/runtime"),
+            Path::new("/runtime"),
+            NativeCatalogProfile::Standard,
+            false,
+        );
+        assert_eq!(
+            command
+                .get_envs()
+                .find(|(key, _)| *key == OsStr::new("ICU_DATA"))
+                .and_then(|(_, value)| value),
+            None
+        );
+        assert_eq!(
+            command
+                .get_envs()
+                .find(|(key, _)| *key == OsStr::new(SKIP_SYSTEM_COLLATION_DISCOVERY_ENV))
+                .and_then(|(_, value)| value),
+            None
+        );
+        assert_eq!(
+            command
+                .get_envs()
+                .find(|(key, _)| *key == OsStr::new(SKIP_ICU_COLLATION_DISCOVERY_ENV))
+                .and_then(|(_, value)| value),
+            Some(OsStr::new("1"))
+        );
+        assert_eq!(
+            command
+                .get_envs()
+                .find(|(key, _)| *key == OsStr::new("OLIPHAUNT_INTERNAL_ICU_READY"))
+                .and_then(|(_, value)| value),
+            None
+        );
+    }
+
+    #[test]
+    fn distributed_icu_seed_suppresses_only_host_locale_discovery() {
+        let root = std::env::temp_dir().join(format!(
+            "oliphaunt-cluster-seed-mobile-{}-{}",
+            std::process::id(),
+            std::thread::current().name().unwrap_or("test")
+        ));
+        let _ = fs::remove_dir_all(&root);
+        let runtime = root.join("runtime");
+        fs::create_dir_all(runtime.join("share/icu")).unwrap();
+
+        let mut command = std::process::Command::new("initdb");
+        configure_cluster_seed_runtime_env(
+            &mut command,
+            &runtime,
+            &runtime,
+            NativeCatalogProfile::Icu,
+            true,
+        );
+
+        assert_eq!(
+            command
+                .get_envs()
+                .find(|(key, _)| *key == OsStr::new(SKIP_SYSTEM_COLLATION_DISCOVERY_ENV))
+                .and_then(|(_, value)| value),
+            Some(OsStr::new("1"))
+        );
+        assert_eq!(
+            command
+                .get_envs()
+                .find(|(key, _)| *key == OsStr::new(SKIP_ICU_COLLATION_DISCOVERY_ENV))
+                .and_then(|(_, value)| value),
+            None
+        );
+        assert_eq!(
+            command
+                .get_envs()
+                .find(|(key, _)| *key == OsStr::new("OLIPHAUNT_INTERNAL_ICU_READY"))
+                .and_then(|(_, value)| value),
+            Some(OsStr::new("1"))
+        );
+        let _ = fs::remove_dir_all(&root);
+    }
+
+    #[test]
+    fn distributed_standard_seed_suppresses_host_and_icu_discovery() {
+        let mut command = std::process::Command::new("initdb");
+        configure_cluster_seed_runtime_env(
+            &mut command,
+            Path::new("/runtime"),
+            Path::new("/runtime"),
+            NativeCatalogProfile::Standard,
+            true,
+        );
+        for key in [
+            SKIP_SYSTEM_COLLATION_DISCOVERY_ENV,
+            SKIP_ICU_COLLATION_DISCOVERY_ENV,
+        ] {
+            assert_eq!(
+                command
+                    .get_envs()
+                    .find(|(candidate, _)| *candidate == OsStr::new(key))
+                    .and_then(|(_, value)| value),
+                Some(OsStr::new("1"))
+            );
+        }
+    }
+
+    #[test]
+    fn cluster_seed_config_normalization_forces_posix_host_values() {
+        let root = std::env::temp_dir().join(format!(
+            "oliphaunt-cluster-seed-normalize-{}-{}",
+            std::process::id(),
+            std::thread::current().name().unwrap_or("test")
+        ));
+        let _ = fs::remove_dir_all(&root);
+        fs::create_dir_all(&root).unwrap();
+        let conf = root.join("postgresql.conf");
+        fs::write(
+            &conf,
+            [
+                "# dynamic_shared_memory_type = posix",
+                "dynamic_shared_memory_type = posix",
+                "log_timezone = 'America/Los_Angeles'",
+                "timezone = 'America/Los_Angeles'",
+                "lc_messages = 'en_US.UTF-8'",
+                "lc_monetary = 'en_US.UTF-8'",
+                "lc_numeric = 'en_US.UTF-8'",
+                "lc_time = 'en_US.UTF-8'",
+            ]
+            .join("\n"),
+        )
+        .unwrap();
+
+        normalize_cluster_seed_conf(&root, "mmap").unwrap();
+
+        let normalized = fs::read_to_string(&conf).unwrap();
+        assert!(normalized.contains("# dynamic_shared_memory_type = posix"));
+        assert!(normalized.contains("dynamic_shared_memory_type = mmap"));
+        assert!(normalized.contains("log_timezone = 'UTC'"));
+        assert!(normalized.contains("timezone = 'UTC'"));
+        assert!(normalized.contains("lc_messages = 'C'"));
+        assert!(normalized.contains("lc_monetary = 'C'"));
+        assert!(normalized.contains("lc_numeric = 'C'"));
+        assert!(normalized.contains("lc_time = 'C'"));
+        let _ = fs::remove_dir_all(&root);
+    }
+
+    #[test]
+    fn cluster_seed_config_normalization_uses_windows_dsm_on_windows() {
+        let root = std::env::temp_dir().join(format!(
+            "oliphaunt-cluster-seed-normalize-windows-{}-{}",
+            std::process::id(),
+            std::thread::current().name().unwrap_or("test")
+        ));
+        let _ = fs::remove_dir_all(&root);
+        fs::create_dir_all(&root).unwrap();
+        let conf = root.join("postgresql.conf");
+        fs::write(
+            &conf,
+            [
+                "# dynamic_shared_memory_type = windows",
+                "dynamic_shared_memory_type = posix",
+            ]
+            .join("\n"),
+        )
+        .unwrap();
+
+        normalize_cluster_seed_conf(&root, "windows").unwrap();
+
+        let normalized = fs::read_to_string(&conf).unwrap();
+        assert!(normalized.contains("# dynamic_shared_memory_type = windows"));
+        assert!(normalized.contains("dynamic_shared_memory_type = windows"));
+        assert!(!normalized.contains("dynamic_shared_memory_type = mmap"));
+        let _ = fs::remove_dir_all(&root);
+    }
+}
diff --git a/src/sdks/rust/src/liboliphaunt/root/descriptor.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/descriptor.rs
similarity index 100%
rename from src/sdks/rust/src/liboliphaunt/root/descriptor.rs
rename to src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/descriptor.rs
diff --git a/src/sdks/rust/src/liboliphaunt/root/extensions.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/extensions.rs
similarity index 100%
rename from src/sdks/rust/src/liboliphaunt/root/extensions.rs
rename to src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/extensions.rs
diff --git a/src/sdks/rust/src/liboliphaunt/root/files.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/files.rs
similarity index 96%
rename from src/sdks/rust/src/liboliphaunt/root/files.rs
rename to src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/files.rs
index f7c72be7f..61502ec1c 100644
--- a/src/sdks/rust/src/liboliphaunt/root/files.rs
+++ b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/files.rs
@@ -263,16 +263,6 @@ pub(super) fn sorted_read_dir(path: &Path) -> Result> {
     Ok(entries)
 }
 
-pub(super) fn directory_is_empty(path: &Path) -> Result {
-    let mut entries = fs::read_dir(path)
-        .map_err(|err| Error::Engine(format!("read directory {}: {err}", path.display())))?;
-    entries
-        .next()
-        .transpose()
-        .map(|entry| entry.is_none())
-        .map_err(|err| Error::Engine(format!("read directory entry in {}: {err}", path.display())))
-}
-
 pub(super) fn remove_file_if_exists(path: &Path) -> Result<()> {
     match fs::remove_file(path) {
         Ok(()) => Ok(()),
diff --git a/src/sdks/rust/src/liboliphaunt/root/fingerprint.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/fingerprint.rs
similarity index 100%
rename from src/sdks/rust/src/liboliphaunt/root/fingerprint.rs
rename to src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/fingerprint.rs
diff --git a/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/resources.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/resources.rs
new file mode 100644
index 000000000..8b65554eb
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/resources.rs
@@ -0,0 +1,313 @@
+use super::NativeCatalogProfile;
+use crate::{Error, NativeClusterSeed, NativeResourceDirectory, Result};
+use sha2::{Digest, Sha256};
+use std::fs;
+use std::io::{Cursor, Read};
+use std::path::{Component, Path, PathBuf};
+
+const MAX_RESOURCE_BYTES: u64 = 1024 * 1024 * 1024;
+
+fn resource_error(error: impl std::fmt::Display) -> Error {
+    Error::InvalidConfig(format!("invalid native resource: {error}"))
+}
+
+pub(super) fn logical_tree_sha256(root: &Path) -> Result {
+    fn visit(root: &Path, path: &Path, files: &mut Vec<(String, PathBuf)>) -> Result<()> {
+        let metadata = fs::symlink_metadata(path).map_err(resource_error)?;
+        if metadata.file_type().is_symlink() {
+            return Err(resource_error("resource contains a symbolic link"));
+        }
+        if metadata.is_dir() {
+            for entry in fs::read_dir(path).map_err(resource_error)? {
+                visit(root, &entry.map_err(resource_error)?.path(), files)?;
+            }
+        } else if metadata.is_file() {
+            let relative = path.strip_prefix(root).map_err(resource_error)?;
+            let relative = relative
+                .to_str()
+                .ok_or_else(|| resource_error("resource path is not UTF-8"))?
+                .replace('\\', "/");
+            files.push((relative, path.to_path_buf()));
+            if files.len() > 8192 {
+                return Err(resource_error("too many resource files"));
+            }
+        } else {
+            return Err(resource_error("resource contains a special file"));
+        }
+        Ok(())
+    }
+    if !fs::symlink_metadata(root).map_err(resource_error)?.is_dir() {
+        return Err(resource_error("resource must be a directory"));
+    }
+    let mut files = Vec::new();
+    visit(root, root, &mut files)?;
+    files.sort_by(|left, right| left.0.cmp(&right.0));
+    let mut digest = Sha256::new();
+    let mut total = 0;
+    let mut buffer = [0_u8; 65536];
+    for (relative, path) in files {
+        let mut file = fs::File::open(path).map_err(resource_error)?;
+        let length = file.metadata().map_err(resource_error)?.len();
+        total += length;
+        if total > MAX_RESOURCE_BYTES {
+            return Err(resource_error("resource exceeds 1 GiB"));
+        }
+        digest.update(relative.as_bytes());
+        digest.update([0]);
+        digest.update(length.to_string().as_bytes());
+        digest.update([0]);
+        loop {
+            let read = file.read(&mut buffer).map_err(resource_error)?;
+            if read == 0 {
+                break;
+            }
+            digest.update(&buffer[..read]);
+        }
+        digest.update(b"\n");
+    }
+    Ok(format!("{:x}", digest.finalize()))
+}
+
+pub(in crate::liboliphaunt) fn validate_icu_data(
+    resource: &NativeResourceDirectory,
+) -> Result {
+    let text = fs::read_to_string(&resource.manifest).map_err(resource_error)?;
+    let mut fields = std::collections::BTreeMap::new();
+    for line in text.lines().filter(|line| !line.is_empty()) {
+        let (key, value) = line
+            .split_once('=')
+            .ok_or_else(|| resource_error("invalid ICU manifest property"))?;
+        if fields.insert(key, value).is_some() {
+            return Err(resource_error("duplicate ICU manifest property"));
+        }
+    }
+    if fields.len() != 5
+        || fields.get("schema") != Some(&"oliphaunt-icu-data-v1")
+        || fields.get("artifactRole") != Some(&"icu-data")
+        || fields.get("icuDataVersion") != Some(&"76.1")
+        || fields.get("icuDataForm") != Some(&"files-le")
+    {
+        return Err(resource_error("incompatible ICU manifest"));
+    }
+    let digest = logical_tree_sha256(&resource.directory)?;
+    if fields.get("icuDataTreeSha256") != Some(&digest.as_str()) {
+        return Err(resource_error("ICU data does not match its manifest"));
+    }
+    Ok(digest)
+}
+
+pub(super) enum ValidatedSeed<'a> {
+    Archive(Vec),
+    Directory(&'a Path, Vec),
+}
+
+pub(super) fn validate_seed<'a>(
+    seed: &'a NativeClusterSeed,
+    profile: NativeCatalogProfile,
+    icu_hash: Option<&str>,
+) -> Result> {
+    let manifest_bytes = match seed {
+        NativeClusterSeed::Archive { manifest, .. } => manifest.to_vec(),
+        NativeClusterSeed::Directory(resource) => {
+            fs::read(&resource.manifest).map_err(resource_error)?
+        }
+    };
+    let manifest: serde_json::Value =
+        serde_json::from_slice(&manifest_bytes).map_err(resource_error)?;
+    let target = super::runtime::native_host_target_id()
+        .ok_or_else(|| resource_error("unsupported native seed target"))?;
+    let runtime = &manifest["runtime"];
+    if manifest["schema"] != "oliphaunt-cluster-seed-v1"
+        || manifest["catalogProfile"] != profile.id()
+        || manifest["artifactRole"] != format!("cluster-seed-{}", profile.id())
+        || runtime["product"] != "liboliphaunt-native"
+        || runtime["engineFamily"] != "native"
+        || runtime["target"] != target
+        || runtime["postgresMajor"] != 18
+        || runtime["physicalFormat"] != "native-pg18-v1"
+        || runtime["compatibilityKey"] != format!("native-pg18-{target}-v1")
+    {
+        return Err(resource_error(
+            "seed has incompatible runtime, physical format, target or catalog profile",
+        ));
+    }
+    match profile {
+        NativeCatalogProfile::Icu
+            if icu_hash.is_some()
+                && manifest["icu"]["dataVersion"] == "76.1"
+                && manifest["icu"]["dataForm"] == "files-le"
+                && manifest["icu"]["dataTreeSha256"].as_str() == icu_hash => {}
+        NativeCatalogProfile::Standard if manifest["icu"].is_null() && icu_hash.is_none() => {}
+        _ => {
+            return Err(resource_error(
+                "seed requires matching explicitly selected ICU data",
+            ));
+        }
+    }
+    match seed {
+        NativeClusterSeed::Directory(resource) => {
+            let relative = manifest["directory"]["path"]
+                .as_str()
+                .ok_or_else(|| resource_error("seed directory manifest is missing"))?;
+            let expected_path = resource
+                .manifest
+                .parent()
+                .unwrap_or(Path::new("."))
+                .join(relative);
+            if fs::canonicalize(expected_path).map_err(resource_error)?
+                != fs::canonicalize(&resource.directory).map_err(resource_error)?
+                || manifest["directory"]["treeSha256"] != logical_tree_sha256(&resource.directory)?
+            {
+                return Err(resource_error("seed directory does not match its manifest"));
+            }
+            if fs::read_to_string(resource.directory.join("PG_VERSION"))
+                .map_err(resource_error)?
+                .trim()
+                != "18"
+                || !resource.directory.join("global/pg_control").is_file()
+            {
+                return Err(resource_error("seed lacks PostgreSQL control files"));
+            }
+            let inventory = manifest["directory"]["emptyDirectories"]
+                .as_array()
+                .ok_or_else(|| resource_error("seed lacks an empty-directory inventory"))?;
+            if inventory.len() > 8192 {
+                return Err(resource_error("too many seed directories"));
+            }
+            let mut directories = std::collections::BTreeSet::new();
+            for value in inventory {
+                let name = value
+                    .as_str()
+                    .ok_or_else(|| resource_error("invalid seed directory path"))?;
+                if name.contains(['\\', ':', '\0'])
+                    || name
+                        .split('/')
+                        .any(|part| part.is_empty() || part == "." || part == "..")
+                {
+                    return Err(resource_error("unsafe seed directory path"));
+                }
+                let relative = PathBuf::from(name);
+                if !directories.insert(relative.clone()) {
+                    return Err(resource_error("duplicate seed directory"));
+                }
+                let mut parent = resource.directory.clone();
+                for part in relative.components() {
+                    parent.push(part.as_os_str());
+                    match fs::symlink_metadata(&parent) {
+                        Ok(metadata) if metadata.is_dir() && !metadata.file_type().is_symlink() => {
+                        }
+                        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
+                        _ => return Err(resource_error("seed directory overlaps a file or link")),
+                    }
+                }
+            }
+            Ok(ValidatedSeed::Directory(
+                &resource.directory,
+                directories.into_iter().collect(),
+            ))
+        }
+        NativeClusterSeed::Archive { archive, .. } => {
+            if archive.len() as u64 > MAX_RESOURCE_BYTES
+                || manifest["archive"]["compressedBytes"].as_u64() != Some(archive.len() as u64)
+                || manifest["archive"]["sha256"] != format!("{:x}", Sha256::digest(archive))
+            {
+                return Err(resource_error("seed archive checksum/size mismatch"));
+            }
+            let decoder = zstd::stream::read::Decoder::new(Cursor::new(archive.as_ref()))
+                .map_err(resource_error)?;
+            let mut bytes = Vec::new();
+            decoder
+                .take(MAX_RESOURCE_BYTES + 1)
+                .read_to_end(&mut bytes)
+                .map_err(resource_error)?;
+            if bytes.len() as u64 > MAX_RESOURCE_BYTES {
+                return Err(resource_error("expanded seed exceeds 1 GiB"));
+            }
+            let mut files = 0_u64;
+            let mut expanded = 0_u64;
+            let mut control = false;
+            let mut version = false;
+            for entry in tar::Archive::new(Cursor::new(&bytes))
+                .entries()
+                .map_err(resource_error)?
+            {
+                let mut entry = entry.map_err(resource_error)?;
+                let path = entry.path().map_err(resource_error)?.into_owned();
+                if path.is_absolute()
+                    || path
+                        .components()
+                        .any(|part| !matches!(part, Component::Normal(_) | Component::CurDir))
+                {
+                    return Err(resource_error("seed archive contains an unsafe path"));
+                }
+                let kind = entry.header().entry_type();
+                if kind.is_file() {
+                    files += 1;
+                    expanded += entry.size();
+                    if files > 8192 || expanded > MAX_RESOURCE_BYTES {
+                        return Err(resource_error("seed archive is too large"));
+                    }
+                    if path == Path::new("PG_VERSION") {
+                        let mut value = String::new();
+                        entry.read_to_string(&mut value).map_err(resource_error)?;
+                        version = value.trim() == "18";
+                    }
+                    if path == Path::new("global/pg_control") {
+                        control = entry.size() > 0;
+                    }
+                } else if !kind.is_dir() {
+                    return Err(resource_error(
+                        "seed archive contains links or special entries",
+                    ));
+                }
+            }
+            if !version
+                || !control
+                || manifest["archive"]["regularFiles"].as_u64() != Some(files)
+                || manifest["archive"]["expandedBytes"].as_u64() != Some(expanded)
+            {
+                return Err(resource_error(
+                    "seed archive has invalid control files or content counts",
+                ));
+            }
+            Ok(ValidatedSeed::Archive(bytes))
+        }
+    }
+}
+
+pub(super) fn restore_seed(seed: ValidatedSeed<'_>, destination: &Path) -> Result<()> {
+    match seed {
+        ValidatedSeed::Directory(directory, empty_directories) => {
+            super::files::copy_directory_tree(
+                directory,
+                destination,
+                super::files::cluster_seed_copy_mode(),
+            )?;
+            for path in empty_directories {
+                fs::create_dir_all(destination.join(path)).map_err(resource_error)?;
+            }
+        }
+        ValidatedSeed::Archive(bytes) => {
+            for entry in tar::Archive::new(Cursor::new(bytes))
+                .entries()
+                .map_err(resource_error)?
+            {
+                let mut entry = entry.map_err(resource_error)?;
+                entry.set_preserve_permissions(false);
+                if !entry.unpack_in(destination).map_err(resource_error)? {
+                    return Err(resource_error("seed path escaped its destination"));
+                }
+            }
+        }
+    }
+    #[cfg(unix)]
+    {
+        use std::os::unix::fs::PermissionsExt;
+        fs::set_permissions(destination, fs::Permissions::from_mode(0o700))
+            .map_err(resource_error)?;
+    }
+    super::cluster_seed::normalize_cluster_seed_conf(
+        destination,
+        super::cluster_seed::native_dynamic_shared_memory_type(),
+    )
+}
diff --git a/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime.rs
new file mode 100644
index 000000000..8e0e80ea3
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime.rs
@@ -0,0 +1,427 @@
+mod cache_key;
+mod install;
+mod locate;
+
+use std::fs::{self, OpenOptions};
+#[cfg(unix)]
+use std::os::unix::fs::PermissionsExt;
+use std::path::{Path, PathBuf};
+use std::time::{SystemTime, UNIX_EPOCH};
+
+use fs2::FileExt;
+
+use cache_key::{
+    cached_runtime_is_valid_with_icu, runtime_cache_key_with_icu, runtime_cache_manifest_with_icu,
+};
+use install::install_cached_runtime_with_icu;
+pub(super) use locate::native_host_target_id;
+use locate::{
+    locate_native_embedded_modules_dir, locate_native_extension_artifact_dirs,
+    locate_native_icu_data, locate_native_install_dir,
+};
+
+use super::files::{sorted_read_dir, sync_directory, sync_file};
+use super::{NativeCatalogProfile, NativeRuntimeProfile};
+use crate::error::{Error, Result};
+use crate::extension::Extension;
+
+const ENV_RUNTIME_CACHE_DIR: &str = "OLIPHAUNT_RUNTIME_CACHE_DIR";
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(super) struct ResolvedRuntimeClosure {
+    pub(super) runtime_dir: PathBuf,
+    pub(super) initdb_runtime_dir: PathBuf,
+    pub(super) catalog_profile: NativeCatalogProfile,
+    pub(super) icu_tree_sha256: Option,
+}
+
+pub(super) fn resolve_runtime_closure(
+    profile: NativeRuntimeProfile,
+    extensions: &[Extension],
+    requested_catalog_profile: Option,
+    selected_icu: Option<&crate::NativeResourceDirectory>,
+) -> Result {
+    let install_dir = locate_native_install_dir()?;
+    let available_icu_data = locate_native_icu_data(selected_icu)?;
+    let catalog_profile = requested_catalog_profile.unwrap_or_else(|| {
+        if available_icu_data.is_some() {
+            NativeCatalogProfile::Icu
+        } else {
+            NativeCatalogProfile::Standard
+        }
+    });
+    let icu_data = match catalog_profile {
+        NativeCatalogProfile::Standard => None,
+        NativeCatalogProfile::Icu => Some(available_icu_data.ok_or_else(|| {
+            Error::Engine(
+                "ICU was selected, but the package-managed ICU data tree is unavailable; add the matching oliphaunt-icu artifact or set OLIPHAUNT_ICU_DATA_DIR"
+                    .to_owned(),
+            )
+        })?),
+    };
+    let icu_directory = icu_data.as_ref().map(|data| data.directory.as_path());
+    let icu_tree_sha256 = icu_data
+        .as_ref()
+        .and_then(|data| data.tree_sha256.as_deref());
+    let runtime_dir = materialize_runtime(
+        profile,
+        &install_dir,
+        extensions,
+        icu_directory,
+        icu_tree_sha256,
+    )?;
+    Ok(ResolvedRuntimeClosure {
+        runtime_dir,
+        initdb_runtime_dir: install_dir,
+        catalog_profile,
+        icu_tree_sha256: icu_tree_sha256.map(str::to_owned),
+    })
+}
+
+pub(super) fn materialize_runtime(
+    profile: NativeRuntimeProfile,
+    install_dir: &Path,
+    extensions: &[Extension],
+    icu_data: Option<&Path>,
+    icu_data_tree_sha256: Option<&str>,
+) -> Result {
+    let extension_artifact_dirs = locate_native_extension_artifact_dirs();
+    let embedded_modules = if profile.needs_embedded_modules() {
+        Some(locate_native_embedded_modules_dir(install_dir)?)
+    } else {
+        None
+    };
+    let key = runtime_cache_key_with_icu(
+        profile,
+        install_dir,
+        embedded_modules.as_deref(),
+        &extension_artifact_dirs,
+        extensions,
+        icu_data,
+        icu_data_tree_sha256,
+    )?;
+    let cache_root = runtime_cache_root()?;
+    fs::create_dir_all(&cache_root).map_err(|err| {
+        Error::Engine(format!(
+            "create native runtime cache root {}: {err}",
+            cache_root.display()
+        ))
+    })?;
+    #[cfg(unix)]
+    fs::set_permissions(&cache_root, fs::Permissions::from_mode(0o700)).map_err(|err| {
+        Error::Engine(format!(
+            "set permissions on native runtime cache root {}: {err}",
+            cache_root.display()
+        ))
+    })?;
+
+    let cache_dir = cache_root.join(&key);
+    let lock_path = cache_root.join(format!("{key}.lock"));
+    let lock = OpenOptions::new()
+        .create(true)
+        .truncate(false)
+        .write(true)
+        .read(true)
+        .open(&lock_path)
+        .map_err(|err| {
+            Error::Engine(format!(
+                "open native runtime cache lock {}: {err}",
+                lock_path.display()
+            ))
+        })?;
+    lock.lock_exclusive().map_err(|err| {
+        Error::Engine(format!(
+            "lock native runtime cache {}: {err}",
+            lock_path.display()
+        ))
+    })?;
+
+    if !cached_runtime_is_valid_with_icu(profile, &cache_dir, &key, extensions, icu_data.is_some())
+    {
+        let build_dir = cache_root.join(format!(
+            ".build-{}-{}",
+            std::process::id(),
+            monotonic_cache_nonce()?
+        ));
+        if build_dir.exists() {
+            fs::remove_dir_all(&build_dir).map_err(|err| {
+                Error::Engine(format!(
+                    "remove stale native runtime build dir {}: {err}",
+                    build_dir.display()
+                ))
+            })?;
+        }
+        fs::create_dir_all(&build_dir).map_err(|err| {
+            Error::Engine(format!(
+                "create native runtime build dir {}: {err}",
+                build_dir.display()
+            ))
+        })?;
+
+        let build_result = install_cached_runtime_with_icu(
+            profile,
+            install_dir,
+            embedded_modules.as_deref(),
+            &extension_artifact_dirs,
+            &build_dir,
+            extensions,
+            icu_data,
+        );
+        if let Err(error) = build_result {
+            let _ = fs::remove_dir_all(&build_dir);
+            return Err(error);
+        }
+        fs::write(
+            build_dir.join(".manifest"),
+            runtime_cache_manifest_with_icu(profile, &key, extensions, icu_data.is_some()),
+        )
+        .map_err(|err| {
+            Error::Engine(format!(
+                "write native runtime cache manifest {}: {err}",
+                build_dir.display()
+            ))
+        })?;
+        fs::write(build_dir.join(".complete"), b"ok\n").map_err(|err| {
+            Error::Engine(format!(
+                "write native runtime cache completion marker {}: {err}",
+                build_dir.display()
+            ))
+        })?;
+        if let Err(error) = sync_runtime_cache_tree(&build_dir) {
+            let _ = fs::remove_dir_all(&build_dir);
+            return Err(error);
+        }
+        if cache_dir.exists() {
+            fs::remove_dir_all(&cache_dir).map_err(|err| {
+                Error::Engine(format!(
+                    "remove invalid native runtime cache {}: {err}",
+                    cache_dir.display()
+                ))
+            })?;
+        }
+        fs::rename(&build_dir, &cache_dir).map_err(|err| {
+            Error::Engine(format!(
+                "publish native runtime cache {} -> {}: {err}",
+                build_dir.display(),
+                cache_dir.display()
+            ))
+        })?;
+        sync_directory(&cache_root)?;
+    }
+
+    lock.unlock().map_err(|err| {
+        Error::Engine(format!(
+            "unlock native runtime cache {}: {err}",
+            lock_path.display()
+        ))
+    })?;
+    Ok(cache_dir)
+}
+
+/// Flush a staged runtime without following packaged symbolic links.
+///
+/// Runtime carriers may contain symlinked libraries. The link itself becomes
+/// durable with its containing directory; ordinary files still need an
+/// explicit flush before the cache directory is published.
+fn sync_runtime_cache_tree(path: &Path) -> Result<()> {
+    let metadata = fs::symlink_metadata(path).map_err(|err| {
+        Error::Engine(format!(
+            "inspect native runtime cache directory {}: {err}",
+            path.display()
+        ))
+    })?;
+    if !metadata.is_dir() || metadata.file_type().is_symlink() {
+        return Err(Error::Engine(format!(
+            "native runtime cache publication root must be a real directory: {}",
+            path.display()
+        )));
+    }
+
+    for entry in sorted_read_dir(path)? {
+        let entry_path = entry.path();
+        let file_type = entry.file_type().map_err(|err| {
+            Error::Engine(format!(
+                "read file type for {} while syncing runtime cache: {err}",
+                entry_path.display()
+            ))
+        })?;
+        if file_type.is_dir() {
+            sync_runtime_cache_tree(&entry_path)?;
+        } else if file_type.is_file() {
+            sync_file(&entry_path)?;
+        } else if file_type.is_symlink() {
+            fs::read_link(&entry_path).map_err(|err| {
+                Error::Engine(format!(
+                    "read native runtime cache symlink {}: {err}",
+                    entry_path.display()
+                ))
+            })?;
+        } else {
+            return Err(Error::Engine(format!(
+                "native runtime cache contains a special file: {}",
+                entry_path.display()
+            )));
+        }
+    }
+    sync_directory(path)
+}
+
+pub(super) fn extension_artifact_root_for<'a>(
+    install_dir: &'a std::path::Path,
+    extension_artifact_dirs: &'a [PathBuf],
+    extension: Extension,
+) -> &'a std::path::Path {
+    extension_artifact_dirs
+        .iter()
+        .find(|root| extension_artifact_root_contains(root, extension))
+        .map(PathBuf::as_path)
+        .unwrap_or(install_dir)
+}
+
+fn extension_artifact_root_contains(root: &std::path::Path, extension: Extension) -> bool {
+    if extension.creates_extension() {
+        return root
+            .join("share/postgresql/extension")
+            .join(format!("{}.control", extension.sql_name()))
+            .is_file();
+    }
+    extension
+        .native_module_file()
+        .is_some_and(|module| root.join("lib/postgresql").join(module).is_file())
+}
+
+pub(super) fn runtime_cache_root() -> Result {
+    if let Some(path) = std::env::var_os(ENV_RUNTIME_CACHE_DIR) {
+        return Ok(PathBuf::from(path));
+    }
+    Ok(std::env::temp_dir().join("oliphaunt-runtime-cache"))
+}
+
+pub(super) fn monotonic_cache_nonce() -> Result {
+    SystemTime::now()
+        .duration_since(UNIX_EPOCH)
+        .map(|duration| duration.as_nanos())
+        .map_err(|err| Error::Engine(format!("system clock before epoch: {err}")))
+}
+
+#[cfg(test)]
+mod tests {
+    use std::fs;
+    use std::path::{Path, PathBuf};
+    use std::time::{SystemTime, UNIX_EPOCH};
+
+    use super::*;
+
+    #[test]
+    fn product_root_identity_uses_control_or_module_according_to_extension_contract() {
+        let temp = TempTree::new("extension-product-root");
+        let install_dir = temp.path().join("runtime");
+        let product_root = temp
+            .path()
+            .join("resources/extension/oliphaunt-extension-contrib-pg18");
+        fs::create_dir_all(&install_dir).expect("create fallback runtime");
+
+        let amcheck_module = Extension::AMCHECK
+            .native_module_file()
+            .expect("amcheck has a native module");
+        write_artifact_file(&product_root, &format!("lib/postgresql/{amcheck_module}"));
+        assert!(!extension_artifact_root_contains(
+            &product_root,
+            Extension::AMCHECK
+        ));
+        assert_eq!(
+            extension_artifact_root_for(
+                &install_dir,
+                std::slice::from_ref(&product_root),
+                Extension::AMCHECK,
+            ),
+            install_dir
+        );
+
+        write_artifact_file(&product_root, "share/postgresql/extension/amcheck.control");
+        assert!(extension_artifact_root_contains(
+            &product_root,
+            Extension::AMCHECK
+        ));
+
+        let auto_explain_module = Extension::AUTO_EXPLAIN
+            .native_module_file()
+            .expect("auto_explain has a native module");
+        write_artifact_file(
+            &product_root,
+            &format!("lib/postgresql/{auto_explain_module}"),
+        );
+        assert!(!Extension::AUTO_EXPLAIN.creates_extension());
+        assert!(extension_artifact_root_contains(
+            &product_root,
+            Extension::AUTO_EXPLAIN
+        ));
+        assert_eq!(
+            extension_artifact_root_for(
+                &install_dir,
+                std::slice::from_ref(&product_root),
+                Extension::AUTO_EXPLAIN,
+            ),
+            product_root
+        );
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn runtime_cache_sync_accepts_packaged_relative_symlinks() {
+        use std::os::unix::fs::symlink;
+
+        let temp = TempTree::new("runtime-cache-symlink");
+        let lib = temp.path().join("lib");
+        fs::create_dir(&lib).expect("create runtime lib directory");
+        fs::write(lib.join("libicu.so.1"), b"icu").expect("write runtime library");
+        symlink("libicu.so.1", lib.join("libicu.so")).expect("create packaged symlink");
+
+        sync_runtime_cache_tree(temp.path()).expect("sync runtime cache with symlink");
+    }
+
+    #[test]
+    fn runtime_cache_sync_flushes_regular_files() {
+        let temp = TempTree::new("runtime-cache-regular-file");
+        fs::write(temp.path().join(".complete"), b"ok\n")
+            .expect("write runtime cache completion marker");
+
+        sync_runtime_cache_tree(temp.path()).expect("sync runtime cache regular file");
+    }
+
+    fn write_artifact_file(root: &Path, relative: &str) {
+        let file = root.join(relative);
+        fs::create_dir_all(file.parent().expect("artifact file parent"))
+            .expect("create artifact file parent");
+        fs::write(file, b"test\n").expect("write artifact file");
+    }
+
+    struct TempTree {
+        path: PathBuf,
+    }
+
+    impl TempTree {
+        fn new(name: &str) -> Self {
+            let nanos = SystemTime::now()
+                .duration_since(UNIX_EPOCH)
+                .expect("clock before epoch")
+                .as_nanos();
+            let path = std::env::temp_dir().join(format!(
+                "oliphaunt-runtime-test-{name}-{nanos}-{}",
+                std::process::id()
+            ));
+            fs::create_dir_all(&path).expect("create temp tree");
+            Self { path }
+        }
+
+        fn path(&self) -> &Path {
+            &self.path
+        }
+    }
+
+    impl Drop for TempTree {
+        fn drop(&mut self) {
+            let _ = fs::remove_dir_all(&self.path);
+        }
+    }
+}
diff --git a/src/sdks/rust/src/liboliphaunt/root/runtime/cache_key.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime/cache_key.rs
similarity index 100%
rename from src/sdks/rust/src/liboliphaunt/root/runtime/cache_key.rs
rename to src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime/cache_key.rs
diff --git a/src/sdks/rust/src/liboliphaunt/root/runtime/install.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime/install.rs
similarity index 100%
rename from src/sdks/rust/src/liboliphaunt/root/runtime/install.rs
rename to src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime/install.rs
diff --git a/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime/locate.rs b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime/locate.rs
new file mode 100644
index 000000000..7acc2a059
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/liboliphaunt/root/runtime/locate.rs
@@ -0,0 +1,285 @@
+use std::path::{Path, PathBuf};
+
+use super::super::super::ffi::{
+    ENV_EMBEDDED_MODULE_DIR, ENV_INITDB, ENV_INSTALL_DIR, ENV_POSTGRES, env_path_candidates,
+    resolve_library_path_candidates,
+};
+use crate::build_resources::resources_dir_candidates;
+use crate::error::{Error, Result};
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(super) struct LocatedIcuData {
+    pub(super) directory: PathBuf,
+    pub(super) tree_sha256: Option,
+}
+
+pub(super) fn locate_native_install_dir() -> Result {
+    let mut candidates = Vec::new();
+    candidates.extend(env_path_candidates([ENV_INSTALL_DIR]));
+    for path in resources_dir_candidates() {
+        candidates.push(path.join("native-runtime/liboliphaunt-native/runtime"));
+    }
+    for env_name in [ENV_POSTGRES, ENV_INITDB] {
+        if let Some(path) = std::env::var_os(env_name) {
+            let path = PathBuf::from(path);
+            if let Some(install_dir) = path.parent().and_then(Path::parent) {
+                candidates.push(install_dir.to_path_buf());
+            }
+        }
+    }
+    for path in resolve_library_path_candidates() {
+        if let Some(work_root) = path.parent().and_then(Path::parent) {
+            candidates.push(work_root.join("install"));
+        }
+    }
+    if let Ok(cwd) = std::env::current_dir() {
+        candidates.push(cwd.join("target/liboliphaunt-pg18/install"));
+        candidates.push(cwd.join("target/native-liboliphaunt-pg18/install"));
+        if let Some(target_id) = native_host_target_id() {
+            candidates.push(cwd.join(format!("target/liboliphaunt-pg18-{target_id}/install")));
+        }
+    }
+
+    for candidate in candidates {
+        if native_install_dir_is_valid(&candidate) {
+            return Ok(candidate);
+        }
+    }
+    Err(Error::Engine(format!(
+        "could not locate native PostgreSQL 18 install tree; set {ENV_INSTALL_DIR} or {ENV_POSTGRES}"
+    )))
+}
+
+pub(super) fn locate_native_extension_artifact_dirs() -> Vec {
+    let mut dirs = Vec::new();
+    for resources_dir in resources_dir_candidates() {
+        let extension_root = resources_dir.join("extension");
+        let Ok(entries) = std::fs::read_dir(extension_root) else {
+            continue;
+        };
+        for entry in entries.flatten() {
+            let path = entry.path();
+            if path.is_dir() {
+                dirs.push(path);
+            }
+        }
+    }
+    dirs.sort();
+    dirs.dedup();
+    dirs
+}
+
+pub(super) fn locate_native_embedded_modules_dir(install_dir: &Path) -> Result {
+    locate_native_embedded_modules_dir_from_libraries(
+        install_dir,
+        resolve_library_path_candidates(),
+    )
+}
+
+fn locate_native_embedded_modules_dir_from_libraries(
+    install_dir: &Path,
+    library_paths: impl IntoIterator,
+) -> Result {
+    let mut candidates = Vec::new();
+    candidates.extend(env_path_candidates([ENV_EMBEDDED_MODULE_DIR]));
+    for path in library_paths {
+        if let Some(out_dir) = path.parent() {
+            candidates.push(out_dir.join("modules"));
+        }
+        if let Some(release_root) = path.parent().and_then(Path::parent) {
+            candidates.push(release_root.join("lib/modules"));
+        }
+    }
+    if let Some(work_root) = install_dir.parent() {
+        candidates.push(work_root.join("out/modules"));
+    }
+    if let Ok(cwd) = std::env::current_dir() {
+        candidates.push(cwd.join("target/liboliphaunt-pg18/out/modules"));
+        candidates.push(cwd.join("target/native-liboliphaunt-pg18/out/modules"));
+        if let Some(target_id) = native_host_target_id() {
+            candidates.push(cwd.join(format!("target/liboliphaunt-pg18-{target_id}/out/modules")));
+        }
+    }
+
+    for candidate in candidates {
+        if candidate.is_dir() {
+            return Ok(candidate);
+        }
+    }
+    Err(Error::Engine(
+        "could not locate native embedded PostgreSQL 18 module artifacts; build native liboliphaunt first"
+            .to_owned(),
+    ))
+}
+
+fn native_install_dir_is_valid(path: &Path) -> bool {
+    native_tool_is_file(path, "postgres")
+        && native_tool_is_file(path, "initdb")
+        && native_tool_is_file(path, "pg_ctl")
+        && path
+            .join("share/postgresql/postgresql.conf.sample")
+            .is_file()
+        && path.join("lib/postgresql").is_dir()
+}
+
+fn native_tool_is_file(path: &Path, tool: &str) -> bool {
+    path.join("bin").join(tool).is_file() || path.join("bin").join(format!("{tool}.exe")).is_file()
+}
+
+pub(super) fn locate_native_icu_data(
+    selected: Option<&crate::NativeResourceDirectory>,
+) -> Result> {
+    if let Some(resource) = selected {
+        let tree_sha256 = super::super::resources::validate_icu_data(resource)?;
+        return Ok(Some(LocatedIcuData {
+            directory: resource.directory.clone(),
+            tree_sha256: Some(tree_sha256),
+        }));
+    }
+    // An explicit environment path remains useful for prepared custom runtimes.
+    if let Some(path) = std::env::var_os("OLIPHAUNT_ICU_DATA_DIR") {
+        let directory = PathBuf::from(path);
+        if !icu_data_dir_is_valid(&directory) {
+            return Err(Error::InvalidConfig(
+                "OLIPHAUNT_ICU_DATA_DIR does not contain ICU data".into(),
+            ));
+        }
+        let tree_sha256 = super::super::resources::logical_tree_sha256(&directory)?;
+        return Ok(Some(LocatedIcuData {
+            directory,
+            tree_sha256: Some(tree_sha256),
+        }));
+    }
+    Ok(None)
+}
+
+fn icu_data_dir_is_valid(path: &Path) -> bool {
+    let Ok(entries) = std::fs::read_dir(path) else {
+        return false;
+    };
+    entries.flatten().any(|entry| {
+        let name = entry.file_name().to_string_lossy().into_owned();
+        let path = entry.path();
+        (path.is_file() && name.starts_with("icudt") && name.ends_with(".dat"))
+            || (path.is_dir()
+                && name.starts_with("icudt")
+                && std::fs::read_dir(path)
+                    .ok()
+                    .into_iter()
+                    .flatten()
+                    .flatten()
+                    .any(|child| child.path().is_file()))
+    })
+}
+
+pub(in crate::liboliphaunt::root) fn native_host_target_id() -> Option<&'static str> {
+    match (std::env::consts::OS, std::env::consts::ARCH) {
+        ("macos", "aarch64") => Some("macos-arm64"),
+        ("linux", "x86_64") => Some("linux-x64-gnu"),
+        ("linux", "aarch64") => Some("linux-arm64-gnu"),
+        ("windows", "x86_64") => Some("windows-x64-msvc"),
+        ("android", "aarch64" | "x86_64") => Some("android-datum64"),
+        ("ios", "aarch64" | "x86_64") => Some("ios-datum64"),
+        _ => None,
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::fs;
+    use std::path::{Path, PathBuf};
+    use std::sync::{Mutex, OnceLock};
+    use std::time::{SystemTime, UNIX_EPOCH};
+
+    use super::*;
+
+    static ENV_LOCK: OnceLock> = OnceLock::new();
+
+    #[test]
+    fn embedded_modules_locator_accepts_release_lib_modules_next_to_dll() {
+        let _guard = ENV_LOCK.get_or_init(|| Mutex::new(())).lock().unwrap();
+        let previous = std::env::var_os(ENV_EMBEDDED_MODULE_DIR);
+        unsafe {
+            std::env::remove_var(ENV_EMBEDDED_MODULE_DIR);
+        }
+        let temp = TempTree::new("release-lib-modules");
+        let release_root = temp.path().join("liboliphaunt-0.0.0-windows-x64-msvc");
+        let install_dir = release_root.join("runtime");
+        let modules_dir = release_root.join("lib/modules");
+        fs::create_dir_all(release_root.join("bin")).expect("create release bin");
+        fs::create_dir_all(&modules_dir).expect("create release modules");
+        fs::create_dir_all(&install_dir).expect("create release runtime");
+
+        let located = locate_native_embedded_modules_dir_from_libraries(
+            &install_dir,
+            [release_root.join("bin/oliphaunt.dll")],
+        )
+        .expect("locate release modules");
+
+        restore_env(ENV_EMBEDDED_MODULE_DIR, previous);
+        assert_eq!(located, modules_dir);
+    }
+
+    #[test]
+    fn embedded_modules_locator_prefers_explicit_environment_dir() {
+        let _guard = ENV_LOCK.get_or_init(|| Mutex::new(())).lock().unwrap();
+        let temp = TempTree::new("explicit-env-modules");
+        let install_dir = temp.path().join("runtime");
+        let modules_dir = temp.path().join("registry/modules");
+        fs::create_dir_all(&install_dir).expect("create runtime");
+        fs::create_dir_all(&modules_dir).expect("create modules");
+        let previous = std::env::var_os(ENV_EMBEDDED_MODULE_DIR);
+        unsafe {
+            std::env::set_var(ENV_EMBEDDED_MODULE_DIR, &modules_dir);
+        }
+
+        let located = locate_native_embedded_modules_dir_from_libraries(
+            &install_dir,
+            [temp.path().join("lib/liboliphaunt.so")],
+        )
+        .expect("locate env modules");
+
+        restore_env(ENV_EMBEDDED_MODULE_DIR, previous);
+        assert_eq!(located, modules_dir);
+    }
+
+    fn restore_env(name: &str, previous: Option) {
+        match previous {
+            Some(value) => unsafe {
+                std::env::set_var(name, value);
+            },
+            None => unsafe {
+                std::env::remove_var(name);
+            },
+        }
+    }
+
+    struct TempTree {
+        path: PathBuf,
+    }
+
+    impl TempTree {
+        fn new(name: &str) -> Self {
+            let nanos = SystemTime::now()
+                .duration_since(UNIX_EPOCH)
+                .expect("clock before epoch")
+                .as_nanos();
+            let path = std::env::temp_dir().join(format!(
+                "oliphaunt-locate-test-{name}-{nanos}-{}",
+                std::process::id()
+            ));
+            fs::create_dir_all(&path).expect("create temp tree");
+            Self { path }
+        }
+
+        fn path(&self) -> &Path {
+            &self.path
+        }
+    }
+
+    impl Drop for TempTree {
+        fn drop(&mut self) {
+            let _ = fs::remove_dir_all(&self.path);
+        }
+    }
+}
diff --git a/src/sdks/rust/liboliphaunt-native/src/storage.rs b/src/sdks/rust/liboliphaunt-native/src/storage.rs
new file mode 100644
index 000000000..3821a032c
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/storage.rs
@@ -0,0 +1,31 @@
+use std::path::{Path, PathBuf};
+
+#[cfg(unix)]
+use std::os::unix::ffi::OsStrExt;
+#[cfg(windows)]
+use std::os::windows::ffi::OsStrExt;
+
+/// Storage used by a native database instance.
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
+pub enum DatabaseStorage {
+    /// SDK-owned temporary directory.
+    #[default]
+    TemporaryDirectory,
+    /// Caller-owned persistent directory.
+    Directory(PathBuf),
+}
+
+pub fn path_contains_nul(path: &Path) -> bool {
+    #[cfg(unix)]
+    {
+        path.as_os_str().as_bytes().contains(&0)
+    }
+    #[cfg(windows)]
+    {
+        path.as_os_str().encode_wide().any(|unit| unit == 0)
+    }
+    #[cfg(not(any(unix, windows)))]
+    {
+        path.to_string_lossy().bytes().any(|byte| byte == 0)
+    }
+}
diff --git a/src/sdks/rust/liboliphaunt-native/src/test_fixtures.rs b/src/sdks/rust/liboliphaunt-native/src/test_fixtures.rs
new file mode 100644
index 000000000..8c8054ffa
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/src/test_fixtures.rs
@@ -0,0 +1,21 @@
+use std::fs;
+use std::path::{Path, PathBuf};
+
+pub(crate) fn root() -> PathBuf {
+    let package_root = Path::new(env!("CARGO_MANIFEST_DIR"));
+    let packaged = package_root.join("testdata");
+    if packaged.is_dir() {
+        return packaged;
+    }
+    package_root
+        .ancestors()
+        .map(|ancestor| ancestor.join("test-fixtures"))
+        .find(|candidate| candidate.is_dir())
+        .expect("shared test fixtures are missing from the checkout or package")
+}
+
+pub(crate) fn text(relative: &str) -> String {
+    let path = root().join(relative);
+    fs::read_to_string(&path)
+        .unwrap_or_else(|error| panic!("read test fixture {}: {error}", path.display()))
+}
diff --git a/src/sdks/rust/liboliphaunt-native/testdata/storage/database-root.json b/src/sdks/rust/liboliphaunt-native/testdata/storage/database-root.json
new file mode 120000
index 000000000..af0acb11f
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/testdata/storage/database-root.json
@@ -0,0 +1 @@
+../../../../../test-fixtures/storage/database-root.json
\ No newline at end of file
diff --git a/src/sdks/rust/liboliphaunt-native/tests/protocol_input.rs b/src/sdks/rust/liboliphaunt-native/tests/protocol_input.rs
new file mode 100644
index 000000000..0c5242465
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/tests/protocol_input.rs
@@ -0,0 +1,104 @@
+use std::{
+    sync::mpsc,
+    thread,
+    time::{Duration, Instant},
+};
+
+use liboliphaunt_native_bindings::{NativeConfig, NativeSession, ProtocolStreamOutcome};
+
+fn frame(tag: u8, body: &[u8]) -> Vec {
+    let mut bytes = vec![tag];
+    bytes.extend_from_slice(&((body.len() + 4) as u32).to_be_bytes());
+    bytes.extend_from_slice(body);
+    bytes
+}
+
+#[test]
+#[ignore = "requires a prepared native runtime via LIBOLIPHAUNT_PATH and OLIPHAUNT_INSTALL_DIR"]
+fn incremental_sync_copy_and_stale_input() {
+    std::env::var_os("LIBOLIPHAUNT_PATH").expect("LIBOLIPHAUNT_PATH is required");
+    std::env::var_os("OLIPHAUNT_INSTALL_DIR").expect("OLIPHAUNT_INSTALL_DIR is required");
+    let mut session = NativeSession::open(NativeConfig::default()).unwrap();
+    let input = session.protocol_input().unwrap();
+    assert_eq!(input.active_token().unwrap(), None);
+
+    let mut request = frame(b'P', b"\0SELECT 42\0\0\0");
+    request.extend(frame(b'B', b"\0\0\0\0\0\0\0\0"));
+    request.extend(frame(b'E', b"\0\0\0\0\0"));
+    request.extend(frame(b'H', b""));
+    let mut response = Vec::new();
+    let old_token = thread::scope(|scope| {
+        let feeder = scope.spawn(|| {
+            let deadline = Instant::now() + Duration::from_secs(5);
+            let token = loop {
+                if let Some(token) = input.active_token().unwrap() {
+                    break token;
+                }
+                assert!(Instant::now() < deadline, "stream did not start");
+                thread::sleep(Duration::from_millis(1));
+            };
+            assert!(input.feed(token, b"malformed").is_err());
+            while !input.feed(token, &frame(b'S', b"")).unwrap() {
+                assert!(Instant::now() < deadline, "native input remained full");
+                thread::sleep(Duration::from_millis(1));
+            }
+            token
+        });
+        assert!(matches!(
+            session.exec_protocol_raw_stream::(
+                &request,
+                &mut |chunk| {
+                    response.extend_from_slice(chunk);
+                    Ok(())
+                },
+            ),
+            ProtocolStreamOutcome::ReadyForQuery(Ok(()))
+        ));
+        feeder.join().unwrap()
+    });
+    assert!(response.windows(2).any(|bytes| bytes == b"42"));
+    assert!(input.feed(old_token, &frame(b'S', b"")).is_err());
+
+    session
+        .exec_simple_query("CREATE TABLE input_copy(value integer)")
+        .unwrap();
+    let (copy_ready, ready) = mpsc::sync_channel(1);
+    let copy = frame(b'Q', b"COPY input_copy FROM STDIN\0");
+    thread::scope(|scope| {
+        let input = &input;
+        let feeder = scope.spawn(move || {
+            ready
+                .recv_timeout(Duration::from_secs(5))
+                .expect("COPY input response");
+            let token = input.active_token().unwrap().expect("active COPY stream");
+            assert_ne!(token, old_token);
+            assert!(input.feed(old_token, &frame(b'c', b"")).is_err());
+            let mut data = frame(b'd', b"7\n8\n");
+            data.extend(frame(b'c', b""));
+            assert!(input.feed(token, &data).unwrap());
+        });
+        let mut notified = false;
+        assert!(matches!(
+            session.exec_protocol_raw_stream::(
+                ©,
+                &mut |_| {
+                    if !notified {
+                        copy_ready.send(()).unwrap();
+                        notified = true;
+                    }
+                    Ok(())
+                },
+            ),
+            ProtocolStreamOutcome::ReadyForQuery(Ok(()))
+        ));
+        feeder.join().unwrap();
+    });
+    let rows = session
+        .exec_simple_query("SELECT sum(value) FROM input_copy")
+        .unwrap();
+    assert!(String::from_utf8_lossy(&rows).contains("15"));
+    session.close().unwrap();
+    assert!(input.active_token().is_err());
+    assert!(input.feed(old_token, &frame(b'S', b"")).is_err());
+    session.close_terminal().unwrap();
+}
diff --git a/src/sdks/rust/liboliphaunt-native/tests/resource_selection.rs b/src/sdks/rust/liboliphaunt-native/tests/resource_selection.rs
new file mode 100644
index 000000000..a343b0a24
--- /dev/null
+++ b/src/sdks/rust/liboliphaunt-native/tests/resource_selection.rs
@@ -0,0 +1,108 @@
+use std::{fs, path::PathBuf};
+
+use liboliphaunt_native_bindings::{
+    DatabaseStorage, NativeClusterSeed, NativeConfig, NativeResourceDirectory, NativeSession,
+    PreparedNativeRoot,
+};
+
+#[test]
+#[ignore = "requires prepared native runtime and explicit standard/ICU seed and ICU data resources"]
+fn explicit_resources_initialize_reopen_and_reject_corruption() {
+    let path = |name| {
+        PathBuf::from(std::env::var_os(name).unwrap_or_else(|| panic!("{name} is required")))
+    };
+    let standard = path("OLIPHAUNT_TEST_STANDARD_SEED");
+    let icu = path("OLIPHAUNT_TEST_ICU_SEED");
+    let icu_data = NativeResourceDirectory {
+        directory: path("OLIPHAUNT_TEST_ICU_DATA"),
+        manifest: path("OLIPHAUNT_TEST_ICU_MANIFEST"),
+    };
+    let scratch = Scratch(std::env::temp_dir().join(format!(
+            "oliphaunt-explicit-resources-{}-{}",
+            std::process::id(),
+            std::time::SystemTime::now()
+                .duration_since(std::time::UNIX_EPOCH)
+                .unwrap()
+                .as_nanos()
+        )));
+    fs::create_dir_all(scratch.path()).unwrap();
+    let profile = std::env::var("OLIPHAUNT_TEST_PROFILE")
+        .expect("OLIPHAUNT_TEST_PROFILE is required (standard or icu), each in a fresh process");
+    assert!(profile == "standard" || profile == "icu");
+    for (name, seed_dir, data) in [("standard", &standard, None), ("icu", &icu, Some(icu_data))]
+        .into_iter()
+        .filter(|(name, _, _)| *name == profile)
+    {
+        let root = scratch.path().join(name);
+        let mut config = NativeConfig {
+            storage: DatabaseStorage::Directory(root.clone()),
+            seed: Some(NativeClusterSeed::new(
+                fs::read(seed_dir.join("seed.tar.zst")).unwrap(),
+                fs::read(seed_dir.join("manifest.json")).unwrap(),
+            )),
+            icu_data: data,
+            ..NativeConfig::default()
+        };
+        let mut session = NativeSession::open(config.clone()).unwrap();
+        let sql = if name == "icu" {
+            "SELECT 'a' < 'b' COLLATE \"und-x-icu\""
+        } else {
+            "SELECT 42"
+        };
+        let mut request = vec![b'Q'];
+        request.extend_from_slice(&((sql.len() + 5) as u32).to_be_bytes());
+        request.extend_from_slice(sql.as_bytes());
+        request.push(0);
+        let response = session.exec_protocol_raw(&request).unwrap();
+        let mut frames = response.as_slice();
+        let mut has_row = false;
+        while !frames.is_empty() {
+            assert!(frames.len() >= 5);
+            let length = u32::from_be_bytes(frames[1..5].try_into().unwrap()) as usize;
+            assert!(length >= 4 && frames.len() > length);
+            assert_ne!(
+                frames[0],
+                b'E',
+                "query returned an error: {:?}",
+                String::from_utf8_lossy(frames)
+            );
+            has_row |= frames[0] == b'D';
+            frames = &frames[length + 1..];
+        }
+        assert!(has_row, "query must return a data row");
+        session.close_terminal().unwrap();
+        config.seed = Some(NativeClusterSeed::new(vec![0], b"invalid"));
+        let reopened = PreparedNativeRoot::prepare(&config, &[]).unwrap();
+        assert!(reopened.pgdata.join("global/pg_control").is_file());
+        drop(reopened);
+        config.storage = DatabaseStorage::Directory(scratch.path().join(format!("corrupt-{name}")));
+        assert!(PreparedNativeRoot::prepare(&config, &[]).is_err());
+        let DatabaseStorage::Directory(rejected) = &config.storage else {
+            unreachable!()
+        };
+        assert!(!rejected.join("pgdata").exists());
+    }
+    let fresh = NativeConfig {
+        storage: DatabaseStorage::Directory(scratch.path().join("initdb")),
+        ..NativeConfig::default()
+    };
+    let prepared = PreparedNativeRoot::prepare(&fresh, &[]).unwrap();
+    assert_eq!(
+        fs::read_to_string(prepared.pgdata.join("PG_VERSION"))
+            .unwrap()
+            .trim(),
+        "18"
+    );
+}
+
+struct Scratch(PathBuf);
+impl Scratch {
+    fn path(&self) -> &std::path::Path {
+        &self.0
+    }
+}
+impl Drop for Scratch {
+    fn drop(&mut self) {
+        let _ = fs::remove_dir_all(&self.0);
+    }
+}
diff --git a/src/sdks/rust/mobile-bindings/Cargo.toml b/src/sdks/rust/mobile-bindings/Cargo.toml
new file mode 100644
index 000000000..bfcb5491d
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "oliphaunt-mobile-bindings"
+version = "0.0.0"
+edition.workspace = true
+rust-version.workspace = true
+license.workspace = true
+publish = false
+
+[lib]
+crate-type = ["cdylib", "staticlib"]
+
+[features]
+bindgen = ["uniffi/cli"]
+
+[dependencies]
+oliphaunt = { path = "../sdk", default-features = false, features = ["mobile-bindings"] }
+liboliphaunt-native-bindings = { path = "../liboliphaunt-native" }
+uniffi = { version = "=0.32.1", default-features = false }
+thiserror = "2"
+
+[[bin]]
+name = "oliphaunt-mobile-bindgen"
+path = "src/bin/bindgen.rs"
+required-features = ["bindgen"]
diff --git a/src/sdks/rust/mobile-bindings/README.md b/src/sdks/rust/mobile-bindings/README.md
new file mode 100644
index 000000000..f44ff69c7
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/README.md
@@ -0,0 +1,33 @@
+# Mobile native bindings
+
+Private UniFFI adapter for the Swift and Kotlin SDKs. It uses the existing Rust
+SDK owner, shared native ABI bindings and request cancellation. It has no public
+registry version or separate release. Runtime binaries and database resources
+remain separate inputs.
+
+Run `cargo build --lib` or `bash tools/generate.sh` here. Generation writes Swift
+and Kotlin source under `target/mobile-bindings/generated`; generated files are
+not maintained source. Cross-compile the library with ordinary Cargo targets
+and the platform linker. Android outputs retain 16 KiB page alignment.
+
+For Android, install the required Rust target, set `ANDROID_NDK_HOME`, and run
+`bash tools/build-android.sh arm64-v8a` (or the requested ABI). It uses API 24,
+matching the Kotlin SDK minimum, and writes ordinary Cargo target outputs.
+The Swift owner assembles its supported Apple slices with
+`bash src/sdks/swift/tools/build-bindings-xcframework.sh` from the workspace root;
+that command requires Xcode and the corresponding Rust targets.
+
+Swift wraps a generated request with `withTaskCancellationHandler`; UniFFI does
+not propagate Swift task cancellation itself. Kotlin carries the caller's Job
+across its existing noncancellable admission wrapper. Both target the individual
+Rust request and await its confirmed outcome. Unsubmitted cancellation leaves
+SQL untouched; completed protocol bytes retain their ReadyForQuery boundary.
+The ordinary database `cancel` method separately targets current database work.
+
+The Swift and Kotlin SDKs now use this bridge. Linux validates their generated
+facades against real PostgreSQL and builds Android AARs; actual Apple framework
+and mobile device execution remain platform qualification gates.
+
+The adapter source is MIT licensed. Compiled mobile libraries include dependencies under MIT, ISC, Unicode-3.0, BSD-3-Clause, and MPL-2.0. Platform packages carry the selected target’s exact license texts and an inventory with source-download URLs under `THIRD_PARTY_LICENSES/rust`. UniFFI is used unmodified; its MPL-2.0 source remains available through those pinned package URLs. The six UniFFI registry crates omit LICENSE, so the contract includes the full upstream file from their recorded source commit.
+
+Run `moon run oliphaunt-mobile-bindings:dependency-license-audit` to compare every released target’s normal Cargo graph with the pinned source and license inventory. No platform compiler is needed for that audit.
diff --git a/src/sdks/rust/mobile-bindings/build.rs b/src/sdks/rust/mobile-bindings/build.rs
new file mode 100644
index 000000000..66e64c9b0
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/build.rs
@@ -0,0 +1,5 @@
+fn main() {
+    if std::env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("android") {
+        println!("cargo:rustc-link-arg=-Wl,-z,max-page-size=16384");
+    }
+}
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64
new file mode 100644
index 000000000..7c5335ec4
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64
@@ -0,0 +1,3 @@
+VGhpcyBwcm9qZWN0IGlzIGR1YWwtbGljZW5zZWQgdW5kZXIgdGhlIFVubGljZW5zZSBhbmQgTUlU
+IGxpY2Vuc2VzLgoKWW91IG1heSB1c2UgdGhpcyBjb2RlIHVuZGVyIHRoZSB0ZXJtcyBvZiBlaXRo
+ZXIgbGljZW5zZS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594.base64
new file mode 100644
index 000000000..3cea07385
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594.base64
@@ -0,0 +1,179 @@
+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAg
+ICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAg
+ICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5E
+IENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAx
+LiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24g
+YXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAg
+ICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1
+dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRo
+ZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2Yg
+dGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRy
+b2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wg
+d2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAg
+ICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRv
+IGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwg
+d2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlw
+IG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcg
+c2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAg
+ICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBF
+bnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5z
+ZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y
+IG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRv
+IHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNv
+bmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZv
+cm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFu
+c2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVk
+IHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAg
+YW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxs
+IG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAg
+T2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0
+ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0
+YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFw
+cGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3
+b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNl
+ZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBl
+ZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBt
+b2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29y
+ayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwg
+RGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAg
+ICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhl
+IGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJl
+b2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNo
+aXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg
+YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJp
+dmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0
+ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0
+IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6
+ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3Ig
+dGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMg
+YW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24g
+c2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVk
+aW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMg
+bWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNz
+dWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2Ys
+IHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1w
+cm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBp
+cyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3
+cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgog
+ICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFs
+IG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBo
+YXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29y
+cG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5z
+ZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNl
+bnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAog
+ICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBp
+cnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUg
+RGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy
+Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2gg
+RGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBv
+ZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YK
+ICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91
+IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwg
+cm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlz
+IHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBv
+ZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdv
+cmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50
+IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVj
+ZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBv
+ciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUg
+V29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UK
+ICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5j
+bHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkg
+YWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0
+ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRv
+cnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdy
+YW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1p
+bmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0
+LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVz
+IG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVk
+aXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv
+ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5n
+IGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50
+cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhp
+cyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmls
+ZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3Ug
+Y2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhl
+IFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBk
+aXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAg
+ICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAog
+ICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBh
+bnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQp
+IElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRz
+CiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZ
+b3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0
+aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5P
+VElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAg
+cGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qg
+b25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRl
+eHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBX
+b3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwg
+aWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAg
+ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg
+YW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkg
+YXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9y
+IGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkg
+dGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBu
+b3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25n
+c2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20g
+dGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1
+dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0
+aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1l
+bnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFs
+IG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IK
+ICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQg
+WW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29y
+ayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4g
+dGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3Mg
+WW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGlu
+dGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkg
+WW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlv
+bnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9y
+IGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVy
+ZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh
+cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBM
+aWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4g
+VGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQog
+ICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBv
+ZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBh
+bmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdv
+cmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcu
+IERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxh
+dyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdv
+cmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25z
+KSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElU
+SU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVk
+aW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAg
+ICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVT
+UyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNp
+YmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9y
+IHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29j
+aWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5z
+ZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIg
+bm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdl
+bmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFw
+cGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGln
+ZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3Ig
+YmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs
+IGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRh
+bWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMg
+TGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBX
+b3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29v
+ZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rp
+b24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3Nz
+ZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0
+aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5
+IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUg
+V29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVy
+LAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJy
+YW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5k
+L29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBp
+biBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZ
+b3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJl
+aGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3Jl
+ZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBo
+YXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFz
+c2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIg
+YWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAg
+RU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64
new file mode 100644
index 000000000..2f7b4a717
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64
@@ -0,0 +1,19 @@
+VGhlIE1JVCBMaWNlbnNlIChNSVQpCgpDb3B5cmlnaHQgKGMpIDIwMTUgQW5kcmV3IEdhbGxhbnQK
+ClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVy
+c29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1
+bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJl
+IHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJp
+Z2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1
+YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJt
+aXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1
+YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBu
+b3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4KYWxs
+IGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09G
+VFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwg
+RVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJS
+QU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBP
+U0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1Ig
+Q09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RI
+RVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBP
+VEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUg
+U09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTgpUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64
new file mode 100644
index 000000000..5093c7c30
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSBUaGUgUnVzdCBQcm9qZWN0IERldmVsb3BlcnMKClBlcm1pc3Npb24gaXMg
+aGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBh
+IGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVz
+ICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJp
+Y3Rpb24sIGluY2x1ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNv
+cHksIG1vZGlmeSwgbWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9v
+ciBzZWxsIGNvcGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3
+aG9tIHRoZSBTb2Z0d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZv
+bGxvd2luZwpjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMg
+cGVybWlzc2lvbiBub3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJz
+dGFudGlhbCBwb3J0aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklE
+RUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBM
+SUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNI
+QU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJ
+TkdFTUVOVC4gSU4gTk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERF
+UlMgQkUgTElBQkxFIEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBX
+SEVUSEVSIElOIEFOIEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJ
+TkcgRlJPTSwgT1VUIE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhF
+IFVTRSBPUiBPVEhFUgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8.base64
new file mode 100644
index 000000000..e11847ef7
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8.base64
@@ -0,0 +1,19 @@
+VGhlIE1JVCBMaWNlbnNlIChNSVQpCkNvcHlyaWdodCAoYykgMjAxNiBBbGV4YW5kcmUgQnVyeQoK
+UGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJz
+b24gb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3Vt
+ZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUg
+d2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmln
+aHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3Vi
+bGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1p
+dCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3Vi
+amVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5v
+dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwg
+Y29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZU
+V0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBF
+WFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJB
+TlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9T
+RSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBD
+T1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhF
+UiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9U
+SEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBT
+T0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5.base64
new file mode 100644
index 000000000..2f7c36af5
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5.base64
@@ -0,0 +1,294 @@
+TW96aWxsYSBQdWJsaWMgTGljZW5zZSBWZXJzaW9uIDIuMAo9PT09PT09PT09PT09PT09PT09PT09
+PT09PT09PT09PT09CgoxLiBEZWZpbml0aW9ucwotLS0tLS0tLS0tLS0tLQoKMS4xLiAiQ29udHJp
+YnV0b3IiCiAgICBtZWFucyBlYWNoIGluZGl2aWR1YWwgb3IgbGVnYWwgZW50aXR5IHRoYXQgY3Jl
+YXRlcywgY29udHJpYnV0ZXMgdG8KICAgIHRoZSBjcmVhdGlvbiBvZiwgb3Igb3ducyBDb3ZlcmVk
+IFNvZnR3YXJlLgoKMS4yLiAiQ29udHJpYnV0b3IgVmVyc2lvbiIKICAgIG1lYW5zIHRoZSBjb21i
+aW5hdGlvbiBvZiB0aGUgQ29udHJpYnV0aW9ucyBvZiBvdGhlcnMgKGlmIGFueSkgdXNlZAogICAg
+YnkgYSBDb250cmlidXRvciBhbmQgdGhhdCBwYXJ0aWN1bGFyIENvbnRyaWJ1dG9yJ3MgQ29udHJp
+YnV0aW9uLgoKMS4zLiAiQ29udHJpYnV0aW9uIgogICAgbWVhbnMgQ292ZXJlZCBTb2Z0d2FyZSBv
+ZiBhIHBhcnRpY3VsYXIgQ29udHJpYnV0b3IuCgoxLjQuICJDb3ZlcmVkIFNvZnR3YXJlIgogICAg
+bWVhbnMgU291cmNlIENvZGUgRm9ybSB0byB3aGljaCB0aGUgaW5pdGlhbCBDb250cmlidXRvciBo
+YXMgYXR0YWNoZWQKICAgIHRoZSBub3RpY2UgaW4gRXhoaWJpdCBBLCB0aGUgRXhlY3V0YWJsZSBG
+b3JtIG9mIHN1Y2ggU291cmNlIENvZGUKICAgIEZvcm0sIGFuZCBNb2RpZmljYXRpb25zIG9mIHN1
+Y2ggU291cmNlIENvZGUgRm9ybSwgaW4gZWFjaCBjYXNlCiAgICBpbmNsdWRpbmcgcG9ydGlvbnMg
+dGhlcmVvZi4KCjEuNS4gIkluY29tcGF0aWJsZSBXaXRoIFNlY29uZGFyeSBMaWNlbnNlcyIKICAg
+IG1lYW5zCgogICAgKGEpIHRoYXQgdGhlIGluaXRpYWwgQ29udHJpYnV0b3IgaGFzIGF0dGFjaGVk
+IHRoZSBub3RpY2UgZGVzY3JpYmVkCiAgICAgICAgaW4gRXhoaWJpdCBCIHRvIHRoZSBDb3ZlcmVk
+IFNvZnR3YXJlOyBvcgoKICAgIChiKSB0aGF0IHRoZSBDb3ZlcmVkIFNvZnR3YXJlIHdhcyBtYWRl
+IGF2YWlsYWJsZSB1bmRlciB0aGUgdGVybXMgb2YKICAgICAgICB2ZXJzaW9uIDEuMSBvciBlYXJs
+aWVyIG9mIHRoZSBMaWNlbnNlLCBidXQgbm90IGFsc28gdW5kZXIgdGhlCiAgICAgICAgdGVybXMg
+b2YgYSBTZWNvbmRhcnkgTGljZW5zZS4KCjEuNi4gIkV4ZWN1dGFibGUgRm9ybSIKICAgIG1lYW5z
+IGFueSBmb3JtIG9mIHRoZSB3b3JrIG90aGVyIHRoYW4gU291cmNlIENvZGUgRm9ybS4KCjEuNy4g
+IkxhcmdlciBXb3JrIgogICAgbWVhbnMgYSB3b3JrIHRoYXQgY29tYmluZXMgQ292ZXJlZCBTb2Z0
+d2FyZSB3aXRoIG90aGVyIG1hdGVyaWFsLCBpbgogICAgYSBzZXBhcmF0ZSBmaWxlIG9yIGZpbGVz
+LCB0aGF0IGlzIG5vdCBDb3ZlcmVkIFNvZnR3YXJlLgoKMS44LiAiTGljZW5zZSIKICAgIG1lYW5z
+IHRoaXMgZG9jdW1lbnQuCgoxLjkuICJMaWNlbnNhYmxlIgogICAgbWVhbnMgaGF2aW5nIHRoZSBy
+aWdodCB0byBncmFudCwgdG8gdGhlIG1heGltdW0gZXh0ZW50IHBvc3NpYmxlLAogICAgd2hldGhl
+ciBhdCB0aGUgdGltZSBvZiB0aGUgaW5pdGlhbCBncmFudCBvciBzdWJzZXF1ZW50bHksIGFueSBh
+bmQKICAgIGFsbCBvZiB0aGUgcmlnaHRzIGNvbnZleWVkIGJ5IHRoaXMgTGljZW5zZS4KCjEuMTAu
+ICJNb2RpZmljYXRpb25zIgogICAgbWVhbnMgYW55IG9mIHRoZSBmb2xsb3dpbmc6CgogICAgKGEp
+IGFueSBmaWxlIGluIFNvdXJjZSBDb2RlIEZvcm0gdGhhdCByZXN1bHRzIGZyb20gYW4gYWRkaXRp
+b24gdG8sCiAgICAgICAgZGVsZXRpb24gZnJvbSwgb3IgbW9kaWZpY2F0aW9uIG9mIHRoZSBjb250
+ZW50cyBvZiBDb3ZlcmVkCiAgICAgICAgU29mdHdhcmU7IG9yCgogICAgKGIpIGFueSBuZXcgZmls
+ZSBpbiBTb3VyY2UgQ29kZSBGb3JtIHRoYXQgY29udGFpbnMgYW55IENvdmVyZWQKICAgICAgICBT
+b2Z0d2FyZS4KCjEuMTEuICJQYXRlbnQgQ2xhaW1zIiBvZiBhIENvbnRyaWJ1dG9yCiAgICBtZWFu
+cyBhbnkgcGF0ZW50IGNsYWltKHMpLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uLCBtZXRo
+b2QsCiAgICBwcm9jZXNzLCBhbmQgYXBwYXJhdHVzIGNsYWltcywgaW4gYW55IHBhdGVudCBMaWNl
+bnNhYmxlIGJ5IHN1Y2gKICAgIENvbnRyaWJ1dG9yIHRoYXQgd291bGQgYmUgaW5mcmluZ2VkLCBi
+dXQgZm9yIHRoZSBncmFudCBvZiB0aGUKICAgIExpY2Vuc2UsIGJ5IHRoZSBtYWtpbmcsIHVzaW5n
+LCBzZWxsaW5nLCBvZmZlcmluZyBmb3Igc2FsZSwgaGF2aW5nCiAgICBtYWRlLCBpbXBvcnQsIG9y
+IHRyYW5zZmVyIG9mIGVpdGhlciBpdHMgQ29udHJpYnV0aW9ucyBvciBpdHMKICAgIENvbnRyaWJ1
+dG9yIFZlcnNpb24uCgoxLjEyLiAiU2Vjb25kYXJ5IExpY2Vuc2UiCiAgICBtZWFucyBlaXRoZXIg
+dGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLCBWZXJzaW9uIDIuMCwgdGhlIEdOVQogICAg
+TGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UsIFZlcnNpb24gMi4xLCB0aGUgR05VIEFmZmVy
+byBHZW5lcmFsCiAgICBQdWJsaWMgTGljZW5zZSwgVmVyc2lvbiAzLjAsIG9yIGFueSBsYXRlciB2
+ZXJzaW9ucyBvZiB0aG9zZQogICAgbGljZW5zZXMuCgoxLjEzLiAiU291cmNlIENvZGUgRm9ybSIK
+ICAgIG1lYW5zIHRoZSBmb3JtIG9mIHRoZSB3b3JrIHByZWZlcnJlZCBmb3IgbWFraW5nIG1vZGlm
+aWNhdGlvbnMuCgoxLjE0LiAiWW91IiAob3IgIllvdXIiKQogICAgbWVhbnMgYW4gaW5kaXZpZHVh
+bCBvciBhIGxlZ2FsIGVudGl0eSBleGVyY2lzaW5nIHJpZ2h0cyB1bmRlciB0aGlzCiAgICBMaWNl
+bnNlLiBGb3IgbGVnYWwgZW50aXRpZXMsICJZb3UiIGluY2x1ZGVzIGFueSBlbnRpdHkgdGhhdAog
+ICAgY29udHJvbHMsIGlzIGNvbnRyb2xsZWQgYnksIG9yIGlzIHVuZGVyIGNvbW1vbiBjb250cm9s
+IHdpdGggWW91LiBGb3IKICAgIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgImNvbnRyb2wi
+IG1lYW5zIChhKSB0aGUgcG93ZXIsIGRpcmVjdAogICAgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRo
+ZSBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwKICAgIHdoZXRoZXIgYnkg
+Y29udHJhY3Qgb3Igb3RoZXJ3aXNlLCBvciAoYikgb3duZXJzaGlwIG9mIG1vcmUgdGhhbgogICAg
+ZmlmdHkgcGVyY2VudCAoNTAlKSBvZiB0aGUgb3V0c3RhbmRpbmcgc2hhcmVzIG9yIGJlbmVmaWNp
+YWwKICAgIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCjIuIExpY2Vuc2UgR3JhbnRzIGFuZCBD
+b25kaXRpb25zCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoyLjEuIEdyYW50cwoK
+RWFjaCBDb250cmlidXRvciBoZXJlYnkgZ3JhbnRzIFlvdSBhIHdvcmxkLXdpZGUsIHJveWFsdHkt
+ZnJlZSwKbm9uLWV4Y2x1c2l2ZSBsaWNlbnNlOgoKKGEpIHVuZGVyIGludGVsbGVjdHVhbCBwcm9w
+ZXJ0eSByaWdodHMgKG90aGVyIHRoYW4gcGF0ZW50IG9yIHRyYWRlbWFyaykKICAgIExpY2Vuc2Fi
+bGUgYnkgc3VjaCBDb250cmlidXRvciB0byB1c2UsIHJlcHJvZHVjZSwgbWFrZSBhdmFpbGFibGUs
+CiAgICBtb2RpZnksIGRpc3BsYXksIHBlcmZvcm0sIGRpc3RyaWJ1dGUsIGFuZCBvdGhlcndpc2Ug
+ZXhwbG9pdCBpdHMKICAgIENvbnRyaWJ1dGlvbnMsIGVpdGhlciBvbiBhbiB1bm1vZGlmaWVkIGJh
+c2lzLCB3aXRoIE1vZGlmaWNhdGlvbnMsIG9yCiAgICBhcyBwYXJ0IG9mIGEgTGFyZ2VyIFdvcms7
+IGFuZAoKKGIpIHVuZGVyIFBhdGVudCBDbGFpbXMgb2Ygc3VjaCBDb250cmlidXRvciB0byBtYWtl
+LCB1c2UsIHNlbGwsIG9mZmVyCiAgICBmb3Igc2FsZSwgaGF2ZSBtYWRlLCBpbXBvcnQsIGFuZCBv
+dGhlcndpc2UgdHJhbnNmZXIgZWl0aGVyIGl0cwogICAgQ29udHJpYnV0aW9ucyBvciBpdHMgQ29u
+dHJpYnV0b3IgVmVyc2lvbi4KCjIuMi4gRWZmZWN0aXZlIERhdGUKClRoZSBsaWNlbnNlcyBncmFu
+dGVkIGluIFNlY3Rpb24gMi4xIHdpdGggcmVzcGVjdCB0byBhbnkgQ29udHJpYnV0aW9uCmJlY29t
+ZSBlZmZlY3RpdmUgZm9yIGVhY2ggQ29udHJpYnV0aW9uIG9uIHRoZSBkYXRlIHRoZSBDb250cmli
+dXRvciBmaXJzdApkaXN0cmlidXRlcyBzdWNoIENvbnRyaWJ1dGlvbi4KCjIuMy4gTGltaXRhdGlv
+bnMgb24gR3JhbnQgU2NvcGUKClRoZSBsaWNlbnNlcyBncmFudGVkIGluIHRoaXMgU2VjdGlvbiAy
+IGFyZSB0aGUgb25seSByaWdodHMgZ3JhbnRlZCB1bmRlcgp0aGlzIExpY2Vuc2UuIE5vIGFkZGl0
+aW9uYWwgcmlnaHRzIG9yIGxpY2Vuc2VzIHdpbGwgYmUgaW1wbGllZCBmcm9tIHRoZQpkaXN0cmli
+dXRpb24gb3IgbGljZW5zaW5nIG9mIENvdmVyZWQgU29mdHdhcmUgdW5kZXIgdGhpcyBMaWNlbnNl
+LgpOb3R3aXRoc3RhbmRpbmcgU2VjdGlvbiAyLjEoYikgYWJvdmUsIG5vIHBhdGVudCBsaWNlbnNl
+IGlzIGdyYW50ZWQgYnkgYQpDb250cmlidXRvcjoKCihhKSBmb3IgYW55IGNvZGUgdGhhdCBhIENv
+bnRyaWJ1dG9yIGhhcyByZW1vdmVkIGZyb20gQ292ZXJlZCBTb2Z0d2FyZTsKICAgIG9yCgooYikg
+Zm9yIGluZnJpbmdlbWVudHMgY2F1c2VkIGJ5OiAoaSkgWW91ciBhbmQgYW55IG90aGVyIHRoaXJk
+IHBhcnR5J3MKICAgIG1vZGlmaWNhdGlvbnMgb2YgQ292ZXJlZCBTb2Z0d2FyZSwgb3IgKGlpKSB0
+aGUgY29tYmluYXRpb24gb2YgaXRzCiAgICBDb250cmlidXRpb25zIHdpdGggb3RoZXIgc29mdHdh
+cmUgKGV4Y2VwdCBhcyBwYXJ0IG9mIGl0cyBDb250cmlidXRvcgogICAgVmVyc2lvbik7IG9yCgoo
+YykgdW5kZXIgUGF0ZW50IENsYWltcyBpbmZyaW5nZWQgYnkgQ292ZXJlZCBTb2Z0d2FyZSBpbiB0
+aGUgYWJzZW5jZSBvZgogICAgaXRzIENvbnRyaWJ1dGlvbnMuCgpUaGlzIExpY2Vuc2UgZG9lcyBu
+b3QgZ3JhbnQgYW55IHJpZ2h0cyBpbiB0aGUgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywKb3Ig
+bG9nb3Mgb2YgYW55IENvbnRyaWJ1dG9yIChleGNlcHQgYXMgbWF5IGJlIG5lY2Vzc2FyeSB0byBj
+b21wbHkgd2l0aAp0aGUgbm90aWNlIHJlcXVpcmVtZW50cyBpbiBTZWN0aW9uIDMuNCkuCgoyLjQu
+IFN1YnNlcXVlbnQgTGljZW5zZXMKCk5vIENvbnRyaWJ1dG9yIG1ha2VzIGFkZGl0aW9uYWwgZ3Jh
+bnRzIGFzIGEgcmVzdWx0IG9mIFlvdXIgY2hvaWNlIHRvCmRpc3RyaWJ1dGUgdGhlIENvdmVyZWQg
+U29mdHdhcmUgdW5kZXIgYSBzdWJzZXF1ZW50IHZlcnNpb24gb2YgdGhpcwpMaWNlbnNlIChzZWUg
+U2VjdGlvbiAxMC4yKSBvciB1bmRlciB0aGUgdGVybXMgb2YgYSBTZWNvbmRhcnkgTGljZW5zZSAo
+aWYKcGVybWl0dGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiBTZWN0aW9uIDMuMykuCgoyLjUuIFJlcHJl
+c2VudGF0aW9uCgpFYWNoIENvbnRyaWJ1dG9yIHJlcHJlc2VudHMgdGhhdCB0aGUgQ29udHJpYnV0
+b3IgYmVsaWV2ZXMgaXRzCkNvbnRyaWJ1dGlvbnMgYXJlIGl0cyBvcmlnaW5hbCBjcmVhdGlvbihz
+KSBvciBpdCBoYXMgc3VmZmljaWVudCByaWdodHMKdG8gZ3JhbnQgdGhlIHJpZ2h0cyB0byBpdHMg
+Q29udHJpYnV0aW9ucyBjb252ZXllZCBieSB0aGlzIExpY2Vuc2UuCgoyLjYuIEZhaXIgVXNlCgpU
+aGlzIExpY2Vuc2UgaXMgbm90IGludGVuZGVkIHRvIGxpbWl0IGFueSByaWdodHMgWW91IGhhdmUg
+dW5kZXIKYXBwbGljYWJsZSBjb3B5cmlnaHQgZG9jdHJpbmVzIG9mIGZhaXIgdXNlLCBmYWlyIGRl
+YWxpbmcsIG9yIG90aGVyCmVxdWl2YWxlbnRzLgoKMi43LiBDb25kaXRpb25zCgpTZWN0aW9ucyAz
+LjEsIDMuMiwgMy4zLCBhbmQgMy40IGFyZSBjb25kaXRpb25zIG9mIHRoZSBsaWNlbnNlcyBncmFu
+dGVkCmluIFNlY3Rpb24gMi4xLgoKMy4gUmVzcG9uc2liaWxpdGllcwotLS0tLS0tLS0tLS0tLS0t
+LS0tCgozLjEuIERpc3RyaWJ1dGlvbiBvZiBTb3VyY2UgRm9ybQoKQWxsIGRpc3RyaWJ1dGlvbiBv
+ZiBDb3ZlcmVkIFNvZnR3YXJlIGluIFNvdXJjZSBDb2RlIEZvcm0sIGluY2x1ZGluZyBhbnkKTW9k
+aWZpY2F0aW9ucyB0aGF0IFlvdSBjcmVhdGUgb3IgdG8gd2hpY2ggWW91IGNvbnRyaWJ1dGUsIG11
+c3QgYmUgdW5kZXIKdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZS4gWW91IG11c3QgaW5mb3JtIHJl
+Y2lwaWVudHMgdGhhdCB0aGUgU291cmNlCkNvZGUgRm9ybSBvZiB0aGUgQ292ZXJlZCBTb2Z0d2Fy
+ZSBpcyBnb3Zlcm5lZCBieSB0aGUgdGVybXMgb2YgdGhpcwpMaWNlbnNlLCBhbmQgaG93IHRoZXkg
+Y2FuIG9idGFpbiBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlLiBZb3UgbWF5IG5vdAphdHRlbXB0IHRv
+IGFsdGVyIG9yIHJlc3RyaWN0IHRoZSByZWNpcGllbnRzJyByaWdodHMgaW4gdGhlIFNvdXJjZSBD
+b2RlCkZvcm0uCgozLjIuIERpc3RyaWJ1dGlvbiBvZiBFeGVjdXRhYmxlIEZvcm0KCklmIFlvdSBk
+aXN0cmlidXRlIENvdmVyZWQgU29mdHdhcmUgaW4gRXhlY3V0YWJsZSBGb3JtIHRoZW46CgooYSkg
+c3VjaCBDb3ZlcmVkIFNvZnR3YXJlIG11c3QgYWxzbyBiZSBtYWRlIGF2YWlsYWJsZSBpbiBTb3Vy
+Y2UgQ29kZQogICAgRm9ybSwgYXMgZGVzY3JpYmVkIGluIFNlY3Rpb24gMy4xLCBhbmQgWW91IG11
+c3QgaW5mb3JtIHJlY2lwaWVudHMgb2YKICAgIHRoZSBFeGVjdXRhYmxlIEZvcm0gaG93IHRoZXkg
+Y2FuIG9idGFpbiBhIGNvcHkgb2Ygc3VjaCBTb3VyY2UgQ29kZQogICAgRm9ybSBieSByZWFzb25h
+YmxlIG1lYW5zIGluIGEgdGltZWx5IG1hbm5lciwgYXQgYSBjaGFyZ2Ugbm8gbW9yZQogICAgdGhh
+biB0aGUgY29zdCBvZiBkaXN0cmlidXRpb24gdG8gdGhlIHJlY2lwaWVudDsgYW5kCgooYikgWW91
+IG1heSBkaXN0cmlidXRlIHN1Y2ggRXhlY3V0YWJsZSBGb3JtIHVuZGVyIHRoZSB0ZXJtcyBvZiB0
+aGlzCiAgICBMaWNlbnNlLCBvciBzdWJsaWNlbnNlIGl0IHVuZGVyIGRpZmZlcmVudCB0ZXJtcywg
+cHJvdmlkZWQgdGhhdCB0aGUKICAgIGxpY2Vuc2UgZm9yIHRoZSBFeGVjdXRhYmxlIEZvcm0gZG9l
+cyBub3QgYXR0ZW1wdCB0byBsaW1pdCBvciBhbHRlcgogICAgdGhlIHJlY2lwaWVudHMnIHJpZ2h0
+cyBpbiB0aGUgU291cmNlIENvZGUgRm9ybSB1bmRlciB0aGlzIExpY2Vuc2UuCgozLjMuIERpc3Ry
+aWJ1dGlvbiBvZiBhIExhcmdlciBXb3JrCgpZb3UgbWF5IGNyZWF0ZSBhbmQgZGlzdHJpYnV0ZSBh
+IExhcmdlciBXb3JrIHVuZGVyIHRlcm1zIG9mIFlvdXIgY2hvaWNlLApwcm92aWRlZCB0aGF0IFlv
+dSBhbHNvIGNvbXBseSB3aXRoIHRoZSByZXF1aXJlbWVudHMgb2YgdGhpcyBMaWNlbnNlIGZvcgp0
+aGUgQ292ZXJlZCBTb2Z0d2FyZS4gSWYgdGhlIExhcmdlciBXb3JrIGlzIGEgY29tYmluYXRpb24g
+b2YgQ292ZXJlZApTb2Z0d2FyZSB3aXRoIGEgd29yayBnb3Zlcm5lZCBieSBvbmUgb3IgbW9yZSBT
+ZWNvbmRhcnkgTGljZW5zZXMsIGFuZCB0aGUKQ292ZXJlZCBTb2Z0d2FyZSBpcyBub3QgSW5jb21w
+YXRpYmxlIFdpdGggU2Vjb25kYXJ5IExpY2Vuc2VzLCB0aGlzCkxpY2Vuc2UgcGVybWl0cyBZb3Ug
+dG8gYWRkaXRpb25hbGx5IGRpc3RyaWJ1dGUgc3VjaCBDb3ZlcmVkIFNvZnR3YXJlCnVuZGVyIHRo
+ZSB0ZXJtcyBvZiBzdWNoIFNlY29uZGFyeSBMaWNlbnNlKHMpLCBzbyB0aGF0IHRoZSByZWNpcGll
+bnQgb2YKdGhlIExhcmdlciBXb3JrIG1heSwgYXQgdGhlaXIgb3B0aW9uLCBmdXJ0aGVyIGRpc3Ry
+aWJ1dGUgdGhlIENvdmVyZWQKU29mdHdhcmUgdW5kZXIgdGhlIHRlcm1zIG9mIGVpdGhlciB0aGlz
+IExpY2Vuc2Ugb3Igc3VjaCBTZWNvbmRhcnkKTGljZW5zZShzKS4KCjMuNC4gTm90aWNlcwoKWW91
+IG1heSBub3QgcmVtb3ZlIG9yIGFsdGVyIHRoZSBzdWJzdGFuY2Ugb2YgYW55IGxpY2Vuc2Ugbm90
+aWNlcwooaW5jbHVkaW5nIGNvcHlyaWdodCBub3RpY2VzLCBwYXRlbnQgbm90aWNlcywgZGlzY2xh
+aW1lcnMgb2Ygd2FycmFudHksCm9yIGxpbWl0YXRpb25zIG9mIGxpYWJpbGl0eSkgY29udGFpbmVk
+IHdpdGhpbiB0aGUgU291cmNlIENvZGUgRm9ybSBvZgp0aGUgQ292ZXJlZCBTb2Z0d2FyZSwgZXhj
+ZXB0IHRoYXQgWW91IG1heSBhbHRlciBhbnkgbGljZW5zZSBub3RpY2VzIHRvCnRoZSBleHRlbnQg
+cmVxdWlyZWQgdG8gcmVtZWR5IGtub3duIGZhY3R1YWwgaW5hY2N1cmFjaWVzLgoKMy41LiBBcHBs
+aWNhdGlvbiBvZiBBZGRpdGlvbmFsIFRlcm1zCgpZb3UgbWF5IGNob29zZSB0byBvZmZlciwgYW5k
+IHRvIGNoYXJnZSBhIGZlZSBmb3IsIHdhcnJhbnR5LCBzdXBwb3J0LAppbmRlbW5pdHkgb3IgbGlh
+YmlsaXR5IG9ibGlnYXRpb25zIHRvIG9uZSBvciBtb3JlIHJlY2lwaWVudHMgb2YgQ292ZXJlZApT
+b2Z0d2FyZS4gSG93ZXZlciwgWW91IG1heSBkbyBzbyBvbmx5IG9uIFlvdXIgb3duIGJlaGFsZiwg
+YW5kIG5vdCBvbgpiZWhhbGYgb2YgYW55IENvbnRyaWJ1dG9yLiBZb3UgbXVzdCBtYWtlIGl0IGFi
+c29sdXRlbHkgY2xlYXIgdGhhdCBhbnkKc3VjaCB3YXJyYW50eSwgc3VwcG9ydCwgaW5kZW1uaXR5
+LCBvciBsaWFiaWxpdHkgb2JsaWdhdGlvbiBpcyBvZmZlcmVkIGJ5CllvdSBhbG9uZSwgYW5kIFlv
+dSBoZXJlYnkgYWdyZWUgdG8gaW5kZW1uaWZ5IGV2ZXJ5IENvbnRyaWJ1dG9yIGZvciBhbnkKbGlh
+YmlsaXR5IGluY3VycmVkIGJ5IHN1Y2ggQ29udHJpYnV0b3IgYXMgYSByZXN1bHQgb2Ygd2FycmFu
+dHksIHN1cHBvcnQsCmluZGVtbml0eSBvciBsaWFiaWxpdHkgdGVybXMgWW91IG9mZmVyLiBZb3Ug
+bWF5IGluY2x1ZGUgYWRkaXRpb25hbApkaXNjbGFpbWVycyBvZiB3YXJyYW50eSBhbmQgbGltaXRh
+dGlvbnMgb2YgbGlhYmlsaXR5IHNwZWNpZmljIHRvIGFueQpqdXJpc2RpY3Rpb24uCgo0LiBJbmFi
+aWxpdHkgdG8gQ29tcGx5IER1ZSB0byBTdGF0dXRlIG9yIFJlZ3VsYXRpb24KLS0tLS0tLS0tLS0t
+LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpJZiBpdCBpcyBpbXBvc3Np
+YmxlIGZvciBZb3UgdG8gY29tcGx5IHdpdGggYW55IG9mIHRoZSB0ZXJtcyBvZiB0aGlzCkxpY2Vu
+c2Ugd2l0aCByZXNwZWN0IHRvIHNvbWUgb3IgYWxsIG9mIHRoZSBDb3ZlcmVkIFNvZnR3YXJlIGR1
+ZSB0bwpzdGF0dXRlLCBqdWRpY2lhbCBvcmRlciwgb3IgcmVndWxhdGlvbiB0aGVuIFlvdSBtdXN0
+OiAoYSkgY29tcGx5IHdpdGgKdGhlIHRlcm1zIG9mIHRoaXMgTGljZW5zZSB0byB0aGUgbWF4aW11
+bSBleHRlbnQgcG9zc2libGU7IGFuZCAoYikKZGVzY3JpYmUgdGhlIGxpbWl0YXRpb25zIGFuZCB0
+aGUgY29kZSB0aGV5IGFmZmVjdC4gU3VjaCBkZXNjcmlwdGlvbiBtdXN0CmJlIHBsYWNlZCBpbiBh
+IHRleHQgZmlsZSBpbmNsdWRlZCB3aXRoIGFsbCBkaXN0cmlidXRpb25zIG9mIHRoZSBDb3ZlcmVk
+ClNvZnR3YXJlIHVuZGVyIHRoaXMgTGljZW5zZS4gRXhjZXB0IHRvIHRoZSBleHRlbnQgcHJvaGli
+aXRlZCBieSBzdGF0dXRlCm9yIHJlZ3VsYXRpb24sIHN1Y2ggZGVzY3JpcHRpb24gbXVzdCBiZSBz
+dWZmaWNpZW50bHkgZGV0YWlsZWQgZm9yIGEKcmVjaXBpZW50IG9mIG9yZGluYXJ5IHNraWxsIHRv
+IGJlIGFibGUgdG8gdW5kZXJzdGFuZCBpdC4KCjUuIFRlcm1pbmF0aW9uCi0tLS0tLS0tLS0tLS0t
+Cgo1LjEuIFRoZSByaWdodHMgZ3JhbnRlZCB1bmRlciB0aGlzIExpY2Vuc2Ugd2lsbCB0ZXJtaW5h
+dGUgYXV0b21hdGljYWxseQppZiBZb3UgZmFpbCB0byBjb21wbHkgd2l0aCBhbnkgb2YgaXRzIHRl
+cm1zLiBIb3dldmVyLCBpZiBZb3UgYmVjb21lCmNvbXBsaWFudCwgdGhlbiB0aGUgcmlnaHRzIGdy
+YW50ZWQgdW5kZXIgdGhpcyBMaWNlbnNlIGZyb20gYSBwYXJ0aWN1bGFyCkNvbnRyaWJ1dG9yIGFy
+ZSByZWluc3RhdGVkIChhKSBwcm92aXNpb25hbGx5LCB1bmxlc3MgYW5kIHVudGlsIHN1Y2gKQ29u
+dHJpYnV0b3IgZXhwbGljaXRseSBhbmQgZmluYWxseSB0ZXJtaW5hdGVzIFlvdXIgZ3JhbnRzLCBh
+bmQgKGIpIG9uIGFuCm9uZ29pbmcgYmFzaXMsIGlmIHN1Y2ggQ29udHJpYnV0b3IgZmFpbHMgdG8g
+bm90aWZ5IFlvdSBvZiB0aGUKbm9uLWNvbXBsaWFuY2UgYnkgc29tZSByZWFzb25hYmxlIG1lYW5z
+IHByaW9yIHRvIDYwIGRheXMgYWZ0ZXIgWW91IGhhdmUKY29tZSBiYWNrIGludG8gY29tcGxpYW5j
+ZS4gTW9yZW92ZXIsIFlvdXIgZ3JhbnRzIGZyb20gYSBwYXJ0aWN1bGFyCkNvbnRyaWJ1dG9yIGFy
+ZSByZWluc3RhdGVkIG9uIGFuIG9uZ29pbmcgYmFzaXMgaWYgc3VjaCBDb250cmlidXRvcgpub3Rp
+ZmllcyBZb3Ugb2YgdGhlIG5vbi1jb21wbGlhbmNlIGJ5IHNvbWUgcmVhc29uYWJsZSBtZWFucywg
+dGhpcyBpcyB0aGUKZmlyc3QgdGltZSBZb3UgaGF2ZSByZWNlaXZlZCBub3RpY2Ugb2Ygbm9uLWNv
+bXBsaWFuY2Ugd2l0aCB0aGlzIExpY2Vuc2UKZnJvbSBzdWNoIENvbnRyaWJ1dG9yLCBhbmQgWW91
+IGJlY29tZSBjb21wbGlhbnQgcHJpb3IgdG8gMzAgZGF5cyBhZnRlcgpZb3VyIHJlY2VpcHQgb2Yg
+dGhlIG5vdGljZS4KCjUuMi4gSWYgWW91IGluaXRpYXRlIGxpdGlnYXRpb24gYWdhaW5zdCBhbnkg
+ZW50aXR5IGJ5IGFzc2VydGluZyBhIHBhdGVudAppbmZyaW5nZW1lbnQgY2xhaW0gKGV4Y2x1ZGlu
+ZyBkZWNsYXJhdG9yeSBqdWRnbWVudCBhY3Rpb25zLApjb3VudGVyLWNsYWltcywgYW5kIGNyb3Nz
+LWNsYWltcykgYWxsZWdpbmcgdGhhdCBhIENvbnRyaWJ1dG9yIFZlcnNpb24KZGlyZWN0bHkgb3Ig
+aW5kaXJlY3RseSBpbmZyaW5nZXMgYW55IHBhdGVudCwgdGhlbiB0aGUgcmlnaHRzIGdyYW50ZWQg
+dG8KWW91IGJ5IGFueSBhbmQgYWxsIENvbnRyaWJ1dG9ycyBmb3IgdGhlIENvdmVyZWQgU29mdHdh
+cmUgdW5kZXIgU2VjdGlvbgoyLjEgb2YgdGhpcyBMaWNlbnNlIHNoYWxsIHRlcm1pbmF0ZS4KCjUu
+My4gSW4gdGhlIGV2ZW50IG9mIHRlcm1pbmF0aW9uIHVuZGVyIFNlY3Rpb25zIDUuMSBvciA1LjIg
+YWJvdmUsIGFsbAplbmQgdXNlciBsaWNlbnNlIGFncmVlbWVudHMgKGV4Y2x1ZGluZyBkaXN0cmli
+dXRvcnMgYW5kIHJlc2VsbGVycykgd2hpY2gKaGF2ZSBiZWVuIHZhbGlkbHkgZ3JhbnRlZCBieSBZ
+b3Ugb3IgWW91ciBkaXN0cmlidXRvcnMgdW5kZXIgdGhpcyBMaWNlbnNlCnByaW9yIHRvIHRlcm1p
+bmF0aW9uIHNoYWxsIHN1cnZpdmUgdGVybWluYXRpb24uCgoqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKKiAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAqCiogIDYuIERpc2NsYWltZXIgb2YgV2FycmFudHkgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgKgoqICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICoKKiAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAq
+CiogIENvdmVyZWQgU29mdHdhcmUgaXMgcHJvdmlkZWQgdW5kZXIgdGhpcyBMaWNlbnNlIG9uIGFu
+ICJhcyBpcyIgICAgICAgKgoqICBiYXNpcywgd2l0aG91dCB3YXJyYW50eSBvZiBhbnkga2luZCwg
+ZWl0aGVyIGV4cHJlc3NlZCwgaW1wbGllZCwgb3IgICoKKiAgc3RhdHV0b3J5LCBpbmNsdWRpbmcs
+IHdpdGhvdXQgbGltaXRhdGlvbiwgd2FycmFudGllcyB0aGF0IHRoZSAgICAgICAqCiogIENvdmVy
+ZWQgU29mdHdhcmUgaXMgZnJlZSBvZiBkZWZlY3RzLCBtZXJjaGFudGFibGUsIGZpdCBmb3IgYSAg
+ICAgICAgKgoqICBwYXJ0aWN1bGFyIHB1cnBvc2Ugb3Igbm9uLWluZnJpbmdpbmcuIFRoZSBlbnRp
+cmUgcmlzayBhcyB0byB0aGUgICAgICoKKiAgcXVhbGl0eSBhbmQgcGVyZm9ybWFuY2Ugb2YgdGhl
+IENvdmVyZWQgU29mdHdhcmUgaXMgd2l0aCBZb3UuICAgICAgICAqCiogIFNob3VsZCBhbnkgQ292
+ZXJlZCBTb2Z0d2FyZSBwcm92ZSBkZWZlY3RpdmUgaW4gYW55IHJlc3BlY3QsIFlvdSAgICAgKgoq
+ICAobm90IGFueSBDb250cmlidXRvcikgYXNzdW1lIHRoZSBjb3N0IG9mIGFueSBuZWNlc3Nhcnkg
+c2VydmljaW5nLCAgICoKKiAgcmVwYWlyLCBvciBjb3JyZWN0aW9uLiBUaGlzIGRpc2NsYWltZXIg
+b2Ygd2FycmFudHkgY29uc3RpdHV0ZXMgYW4gICAqCiogIGVzc2VudGlhbCBwYXJ0IG9mIHRoaXMg
+TGljZW5zZS4gTm8gdXNlIG9mIGFueSBDb3ZlcmVkIFNvZnR3YXJlIGlzICAgKgoqICBhdXRob3Jp
+emVkIHVuZGVyIHRoaXMgTGljZW5zZSBleGNlcHQgdW5kZXIgdGhpcyBkaXNjbGFpbWVyLiAgICAg
+ICAgICoKKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAqCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgoKKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiog
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgKgoqICA3LiBMaW1pdGF0aW9uIG9mIExpYWJpbGl0eSAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICoKKiAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
+LS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAqCiogICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgKgoqICBVbmRlciBubyBjaXJjdW1zdGFuY2VzIGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnks
+IHdoZXRoZXIgdG9ydCAgICAgICoKKiAgKGluY2x1ZGluZyBuZWdsaWdlbmNlKSwgY29udHJhY3Qs
+IG9yIG90aGVyd2lzZSwgc2hhbGwgYW55ICAgICAgICAgICAqCiogIENvbnRyaWJ1dG9yLCBvciBh
+bnlvbmUgd2hvIGRpc3RyaWJ1dGVzIENvdmVyZWQgU29mdHdhcmUgYXMgICAgICAgICAgKgoqICBw
+ZXJtaXR0ZWQgYWJvdmUsIGJlIGxpYWJsZSB0byBZb3UgZm9yIGFueSBkaXJlY3QsIGluZGlyZWN0
+LCAgICAgICAgICoKKiAgc3BlY2lhbCwgaW5jaWRlbnRhbCwgb3IgY29uc2VxdWVudGlhbCBkYW1h
+Z2VzIG9mIGFueSBjaGFyYWN0ZXIgICAgICAqCiogIGluY2x1ZGluZywgd2l0aG91dCBsaW1pdGF0
+aW9uLCBkYW1hZ2VzIGZvciBsb3N0IHByb2ZpdHMsIGxvc3Mgb2YgICAgKgoqICBnb29kd2lsbCwg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55ICAg
+ICoKKiAgYW5kIGFsbCBvdGhlciBjb21tZXJjaWFsIGRhbWFnZXMgb3IgbG9zc2VzLCBldmVuIGlm
+IHN1Y2ggcGFydHkgICAgICAqCiogIHNoYWxsIGhhdmUgYmVlbiBpbmZvcm1lZCBvZiB0aGUgcG9z
+c2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLiBUaGlzICAgKgoqICBsaW1pdGF0aW9uIG9mIGxpYWJp
+bGl0eSBzaGFsbCBub3QgYXBwbHkgdG8gbGlhYmlsaXR5IGZvciBkZWF0aCBvciAgICoKKiAgcGVy
+c29uYWwgaW5qdXJ5IHJlc3VsdGluZyBmcm9tIHN1Y2ggcGFydHkncyBuZWdsaWdlbmNlIHRvIHRo
+ZSAgICAgICAqCiogIGV4dGVudCBhcHBsaWNhYmxlIGxhdyBwcm9oaWJpdHMgc3VjaCBsaW1pdGF0
+aW9uLiBTb21lICAgICAgICAgICAgICAgKgoqICBqdXJpc2RpY3Rpb25zIGRvIG5vdCBhbGxvdyB0
+aGUgZXhjbHVzaW9uIG9yIGxpbWl0YXRpb24gb2YgICAgICAgICAgICoKKiAgaW5jaWRlbnRhbCBv
+ciBjb25zZXF1ZW50aWFsIGRhbWFnZXMsIHNvIHRoaXMgZXhjbHVzaW9uIGFuZCAgICAgICAgICAq
+CiogIGxpbWl0YXRpb24gbWF5IG5vdCBhcHBseSB0byBZb3UuICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgKgoqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICoKKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCgo4LiBMaXRp
+Z2F0aW9uCi0tLS0tLS0tLS0tLS0KCkFueSBsaXRpZ2F0aW9uIHJlbGF0aW5nIHRvIHRoaXMgTGlj
+ZW5zZSBtYXkgYmUgYnJvdWdodCBvbmx5IGluIHRoZQpjb3VydHMgb2YgYSBqdXJpc2RpY3Rpb24g
+d2hlcmUgdGhlIGRlZmVuZGFudCBtYWludGFpbnMgaXRzIHByaW5jaXBhbApwbGFjZSBvZiBidXNp
+bmVzcyBhbmQgc3VjaCBsaXRpZ2F0aW9uIHNoYWxsIGJlIGdvdmVybmVkIGJ5IGxhd3Mgb2YgdGhh
+dApqdXJpc2RpY3Rpb24sIHdpdGhvdXQgcmVmZXJlbmNlIHRvIGl0cyBjb25mbGljdC1vZi1sYXcg
+cHJvdmlzaW9ucy4KTm90aGluZyBpbiB0aGlzIFNlY3Rpb24gc2hhbGwgcHJldmVudCBhIHBhcnR5
+J3MgYWJpbGl0eSB0byBicmluZwpjcm9zcy1jbGFpbXMgb3IgY291bnRlci1jbGFpbXMuCgo5LiBN
+aXNjZWxsYW5lb3VzCi0tLS0tLS0tLS0tLS0tLS0KClRoaXMgTGljZW5zZSByZXByZXNlbnRzIHRo
+ZSBjb21wbGV0ZSBhZ3JlZW1lbnQgY29uY2VybmluZyB0aGUgc3ViamVjdAptYXR0ZXIgaGVyZW9m
+LiBJZiBhbnkgcHJvdmlzaW9uIG9mIHRoaXMgTGljZW5zZSBpcyBoZWxkIHRvIGJlCnVuZW5mb3Jj
+ZWFibGUsIHN1Y2ggcHJvdmlzaW9uIHNoYWxsIGJlIHJlZm9ybWVkIG9ubHkgdG8gdGhlIGV4dGVu
+dApuZWNlc3NhcnkgdG8gbWFrZSBpdCBlbmZvcmNlYWJsZS4gQW55IGxhdyBvciByZWd1bGF0aW9u
+IHdoaWNoIHByb3ZpZGVzCnRoYXQgdGhlIGxhbmd1YWdlIG9mIGEgY29udHJhY3Qgc2hhbGwgYmUg
+Y29uc3RydWVkIGFnYWluc3QgdGhlIGRyYWZ0ZXIKc2hhbGwgbm90IGJlIHVzZWQgdG8gY29uc3Ry
+dWUgdGhpcyBMaWNlbnNlIGFnYWluc3QgYSBDb250cmlidXRvci4KCjEwLiBWZXJzaW9ucyBvZiB0
+aGUgTGljZW5zZQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCjEwLjEuIE5ldyBWZXJzaW9u
+cwoKTW96aWxsYSBGb3VuZGF0aW9uIGlzIHRoZSBsaWNlbnNlIHN0ZXdhcmQuIEV4Y2VwdCBhcyBw
+cm92aWRlZCBpbiBTZWN0aW9uCjEwLjMsIG5vIG9uZSBvdGhlciB0aGFuIHRoZSBsaWNlbnNlIHN0
+ZXdhcmQgaGFzIHRoZSByaWdodCB0byBtb2RpZnkgb3IKcHVibGlzaCBuZXcgdmVyc2lvbnMgb2Yg
+dGhpcyBMaWNlbnNlLiBFYWNoIHZlcnNpb24gd2lsbCBiZSBnaXZlbiBhCmRpc3Rpbmd1aXNoaW5n
+IHZlcnNpb24gbnVtYmVyLgoKMTAuMi4gRWZmZWN0IG9mIE5ldyBWZXJzaW9ucwoKWW91IG1heSBk
+aXN0cmlidXRlIHRoZSBDb3ZlcmVkIFNvZnR3YXJlIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgdmVy
+c2lvbgpvZiB0aGUgTGljZW5zZSB1bmRlciB3aGljaCBZb3Ugb3JpZ2luYWxseSByZWNlaXZlZCB0
+aGUgQ292ZXJlZCBTb2Z0d2FyZSwKb3IgdW5kZXIgdGhlIHRlcm1zIG9mIGFueSBzdWJzZXF1ZW50
+IHZlcnNpb24gcHVibGlzaGVkIGJ5IHRoZSBsaWNlbnNlCnN0ZXdhcmQuCgoxMC4zLiBNb2RpZmll
+ZCBWZXJzaW9ucwoKSWYgeW91IGNyZWF0ZSBzb2Z0d2FyZSBub3QgZ292ZXJuZWQgYnkgdGhpcyBM
+aWNlbnNlLCBhbmQgeW91IHdhbnQgdG8KY3JlYXRlIGEgbmV3IGxpY2Vuc2UgZm9yIHN1Y2ggc29m
+dHdhcmUsIHlvdSBtYXkgY3JlYXRlIGFuZCB1c2UgYQptb2RpZmllZCB2ZXJzaW9uIG9mIHRoaXMg
+TGljZW5zZSBpZiB5b3UgcmVuYW1lIHRoZSBsaWNlbnNlIGFuZCByZW1vdmUKYW55IHJlZmVyZW5j
+ZXMgdG8gdGhlIG5hbWUgb2YgdGhlIGxpY2Vuc2Ugc3Rld2FyZCAoZXhjZXB0IHRvIG5vdGUgdGhh
+dApzdWNoIG1vZGlmaWVkIGxpY2Vuc2UgZGlmZmVycyBmcm9tIHRoaXMgTGljZW5zZSkuCgoxMC40
+LiBEaXN0cmlidXRpbmcgU291cmNlIENvZGUgRm9ybSB0aGF0IGlzIEluY29tcGF0aWJsZSBXaXRo
+IFNlY29uZGFyeQpMaWNlbnNlcwoKSWYgWW91IGNob29zZSB0byBkaXN0cmlidXRlIFNvdXJjZSBD
+b2RlIEZvcm0gdGhhdCBpcyBJbmNvbXBhdGlibGUgV2l0aApTZWNvbmRhcnkgTGljZW5zZXMgdW5k
+ZXIgdGhlIHRlcm1zIG9mIHRoaXMgdmVyc2lvbiBvZiB0aGUgTGljZW5zZSwgdGhlCm5vdGljZSBk
+ZXNjcmliZWQgaW4gRXhoaWJpdCBCIG9mIHRoaXMgTGljZW5zZSBtdXN0IGJlIGF0dGFjaGVkLgoK
+RXhoaWJpdCBBIC0gU291cmNlIENvZGUgRm9ybSBMaWNlbnNlIE5vdGljZQotLS0tLS0tLS0tLS0t
+LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgogIFRoaXMgU291cmNlIENvZGUgRm9ybSBp
+cyBzdWJqZWN0IHRvIHRoZSB0ZXJtcyBvZiB0aGUgTW96aWxsYSBQdWJsaWMKICBMaWNlbnNlLCB2
+LiAyLjAuIElmIGEgY29weSBvZiB0aGUgTVBMIHdhcyBub3QgZGlzdHJpYnV0ZWQgd2l0aCB0aGlz
+CiAgZmlsZSwgWW91IGNhbiBvYnRhaW4gb25lIGF0IGh0dHA6Ly9tb3ppbGxhLm9yZy9NUEwvMi4w
+Ly4KCklmIGl0IGlzIG5vdCBwb3NzaWJsZSBvciBkZXNpcmFibGUgdG8gcHV0IHRoZSBub3RpY2Ug
+aW4gYSBwYXJ0aWN1bGFyCmZpbGUsIHRoZW4gWW91IG1heSBpbmNsdWRlIHRoZSBub3RpY2UgaW4g
+YSBsb2NhdGlvbiAoc3VjaCBhcyBhIExJQ0VOU0UKZmlsZSBpbiBhIHJlbGV2YW50IGRpcmVjdG9y
+eSkgd2hlcmUgYSByZWNpcGllbnQgd291bGQgYmUgbGlrZWx5IHRvIGxvb2sKZm9yIHN1Y2ggYSBu
+b3RpY2UuCgpZb3UgbWF5IGFkZCBhZGRpdGlvbmFsIGFjY3VyYXRlIG5vdGljZXMgb2YgY29weXJp
+Z2h0IG93bmVyc2hpcC4KCkV4aGliaXQgQiAtICJJbmNvbXBhdGlibGUgV2l0aCBTZWNvbmRhcnkg
+TGljZW5zZXMiIE5vdGljZQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0t
+LS0tLS0tLS0tLS0tLS0tLS0KCiAgVGhpcyBTb3VyY2UgQ29kZSBGb3JtIGlzICJJbmNvbXBhdGli
+bGUgV2l0aCBTZWNvbmRhcnkgTGljZW5zZXMiLCBhcwogIGRlZmluZWQgYnkgdGhlIE1vemlsbGEg
+UHVibGljIExpY2Vuc2UsIHYuIDIuMC4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64
new file mode 100644
index 000000000..0eb7839e0
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64
@@ -0,0 +1,18 @@
+UGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJz
+b24gb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3Vt
+ZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUg
+d2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmln
+aHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3Vi
+bGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1p
+dCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3Vi
+amVjdCB0byB0aGUgZm9sbG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5v
+dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwg
+Y29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZU
+V0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBF
+WFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJB
+TlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9T
+RSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBD
+T1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhF
+UiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9U
+SEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBT
+T0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.base64
new file mode 100644
index 000000000..bc239132a
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.base64
@@ -0,0 +1,215 @@
+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAg
+ICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAg
+ICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5E
+IENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAx
+LiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24g
+YXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAg
+ICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1
+dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRo
+ZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2Yg
+dGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRy
+b2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wg
+d2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAg
+ICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRv
+IGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwg
+d2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlw
+IG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcg
+c2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAg
+ICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBF
+bnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5z
+ZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y
+IG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRv
+IHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNv
+bmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZv
+cm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFu
+c2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVk
+IHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAg
+YW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxs
+IG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAg
+T2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0
+ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0
+YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFw
+cGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3
+b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNl
+ZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBl
+ZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBt
+b2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29y
+ayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwg
+RGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAg
+ICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhl
+IGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJl
+b2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNo
+aXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg
+YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJp
+dmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0
+ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0
+IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6
+ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3Ig
+dGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMg
+YW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24g
+c2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVk
+aW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMg
+bWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNz
+dWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2Ys
+IHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1w
+cm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBp
+cyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3
+cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgog
+ICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFs
+IG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBo
+YXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29y
+cG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5z
+ZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNl
+bnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAog
+ICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBp
+cnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUg
+RGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy
+Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2gg
+RGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBv
+ZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YK
+ICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91
+IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwg
+cm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlz
+IHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBv
+ZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdv
+cmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50
+IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVj
+ZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBv
+ciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUg
+V29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UK
+ICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5j
+bHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkg
+YWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0
+ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRv
+cnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdy
+YW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1p
+bmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0
+LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVz
+IG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVk
+aXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv
+ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5n
+IGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50
+cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhp
+cyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmls
+ZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3Ug
+Y2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhl
+IFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBk
+aXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAg
+ICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAog
+ICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBh
+bnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQp
+IElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRz
+CiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZ
+b3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0
+aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5P
+VElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAg
+cGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qg
+b25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRl
+eHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBX
+b3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwg
+aWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAg
+ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg
+YW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkg
+YXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9y
+IGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkg
+dGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBu
+b3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25n
+c2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20g
+dGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1
+dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0
+aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1l
+bnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFs
+IG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IK
+ICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQg
+WW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29y
+ayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4g
+dGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3Mg
+WW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGlu
+dGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkg
+WW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlv
+bnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9y
+IGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVy
+ZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh
+cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBM
+aWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4g
+VGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQog
+ICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBv
+ZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBh
+bmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdv
+cmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcu
+IERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxh
+dyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdv
+cmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25z
+KSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElU
+SU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVk
+aW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAg
+ICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVT
+UyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNp
+YmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9y
+IHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29j
+aWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5z
+ZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIg
+bm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdl
+bmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFw
+cGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGln
+ZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3Ig
+YmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs
+IGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRh
+bWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMg
+TGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBX
+b3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29v
+ZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rp
+b24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3Nz
+ZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0
+aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5
+IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUg
+V29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVy
+LAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJy
+YW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5k
+L29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBp
+biBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZ
+b3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJl
+aGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3Jl
+ZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBo
+YXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFz
+c2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIg
+YWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAg
+RU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRo
+ZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hl
+IExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJw
+bGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAg
+ICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24n
+dCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9z
+ZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBm
+b3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUg
+YW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUg
+InByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBp
+ZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQg
+W3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBB
+cGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5v
+dCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAg
+IFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93
+d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5
+IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0
+cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJB
+U0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0
+aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lm
+aWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRl
+ciB0aGUgTGljZW5zZS4KCgotLS0gTExWTSBFeGNlcHRpb25zIHRvIHRoZSBBcGFjaGUgMi4wIExp
+Y2Vuc2UgLS0tLQoKQXMgYW4gZXhjZXB0aW9uLCBpZiwgYXMgYSByZXN1bHQgb2YgeW91ciBjb21w
+aWxpbmcgeW91ciBzb3VyY2UgY29kZSwgcG9ydGlvbnMKb2YgdGhpcyBTb2Z0d2FyZSBhcmUgZW1i
+ZWRkZWQgaW50byBhbiBPYmplY3QgZm9ybSBvZiBzdWNoIHNvdXJjZSBjb2RlLCB5b3UKbWF5IHJl
+ZGlzdHJpYnV0ZSBzdWNoIGVtYmVkZGVkIHBvcnRpb25zIGluIHN1Y2ggT2JqZWN0IGZvcm0gd2l0
+aG91dCBjb21wbHlpbmcKd2l0aCB0aGUgY29uZGl0aW9ucyBvZiBTZWN0aW9ucyA0KGEpLCA0KGIp
+IGFuZCA0KGQpIG9mIHRoZSBMaWNlbnNlLgoKSW4gYWRkaXRpb24sIGlmIHlvdSBjb21iaW5lIG9y
+IGxpbmsgY29tcGlsZWQgZm9ybXMgb2YgdGhpcyBTb2Z0d2FyZSB3aXRoCnNvZnR3YXJlIHRoYXQg
+aXMgbGljZW5zZWQgdW5kZXIgdGhlIEdQTHYyICgiQ29tYmluZWQgU29mdHdhcmUiKSBhbmQgaWYg
+YQpjb3VydCBvZiBjb21wZXRlbnQganVyaXNkaWN0aW9uIGRldGVybWluZXMgdGhhdCB0aGUgcGF0
+ZW50IHByb3Zpc2lvbiAoU2VjdGlvbgozKSwgdGhlIGluZGVtbml0eSBwcm92aXNpb24gKFNlY3Rp
+b24gOSkgb3Igb3RoZXIgU2VjdGlvbiBvZiB0aGUgTGljZW5zZQpjb25mbGljdHMgd2l0aCB0aGUg
+Y29uZGl0aW9ucyBvZiB0aGUgR1BMdjIsIHlvdSBtYXkgcmV0cm9hY3RpdmVseSBhbmQKcHJvc3Bl
+Y3RpdmVseSBjaG9vc2UgdG8gZGVlbSB3YWl2ZWQgb3Igb3RoZXJ3aXNlIGV4Y2x1ZGUgc3VjaCBT
+ZWN0aW9uKHMpIG9mCnRoZSBMaWNlbnNlLCBidXQgb25seSBpbiB0aGVpciBlbnRpcmV0eSBhbmQg
+b25seSB3aXRoIHJlc3BlY3QgdG8gdGhlIENvbWJpbmVkClNvZnR3YXJlLgoK
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64
new file mode 100644
index 000000000..d977c9dbf
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64
@@ -0,0 +1,20 @@
+Q29weXJpZ2h0IChjKSAyMDE4LTIwMjUgVGhlIHJ1c3QtcmFuZG9tIFByb2plY3QgRGV2ZWxvcGVy
+cwpDb3B5cmlnaHQgKGMpIDIwMTQgVGhlIFJ1c3QgUHJvamVjdCBEZXZlbG9wZXJzCgpQZXJtaXNz
+aW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRh
+aW5pbmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlv
+biBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0
+IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8g
+dXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNl
+LCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNv
+bnMgdG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRv
+IHRoZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFu
+ZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMg
+b3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElT
+IFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1Mg
+T1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBP
+RiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBO
+T05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdI
+VCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJ
+TElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNF
+LCBBUklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJF
+IE9SIFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b.base64
new file mode 100644
index 000000000..41dcc5852
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b.base64
@@ -0,0 +1,16 @@
+U2hvcnQgdmVyc2lvbiBmb3Igbm9uLWxhd3llcnM6CgpgbGludXgtcmF3LXN5c2AgaXMgdHJpcGxl
+LWxpY2Vuc2VkIHVuZGVyIEFwYWNoZSAyLjAgd2l0aCB0aGUgTExWTSBFeGNlcHRpb24sCkFwYWNo
+ZSAyLjAsIGFuZCBNSVQgdGVybXMuCgoKTG9uZ2VyIHZlcnNpb246CgpDb3B5cmlnaHRzIGluIHRo
+ZSBgbGludXgtcmF3LXN5c2AgcHJvamVjdCBhcmUgcmV0YWluZWQgYnkgdGhlaXIgY29udHJpYnV0
+b3JzLgpObyBjb3B5cmlnaHQgYXNzaWdubWVudCBpcyByZXF1aXJlZCB0byBjb250cmlidXRlIHRv
+IHRoZSBgbGludXgtcmF3LXN5c2AKcHJvamVjdC4KClNvbWUgZmlsZXMgaW5jbHVkZSBjb2RlIGRl
+cml2ZWQgZnJvbSBSdXN0J3MgYGxpYnN0ZGA7IHNlZSB0aGUgY29tbWVudHMgaW4KdGhlIGNvZGUg
+Zm9yIGRldGFpbHMuCgpFeGNlcHQgYXMgb3RoZXJ3aXNlIG5vdGVkIChiZWxvdyBhbmQvb3IgaW4g
+aW5kaXZpZHVhbCBmaWxlcyksIGBsaW51eC1yYXctc3lzYAppcyBsaWNlbnNlZCB1bmRlcjoKCiAt
+IHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAsIHdpdGggdGhlIExMVk0gRXhjZXB0aW9u
+CiAgIDxMSUNFTlNFLUFwYWNoZS0yLjBfV0lUSF9MTFZNLWV4Y2VwdGlvbj4gb3IKICAgPGh0dHA6
+Ly9sbHZtLm9yZy9mb3VuZGF0aW9uL3JlbGljZW5zaW5nL0xJQ0VOU0UudHh0PgogLSB0aGUgQXBh
+Y2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wCiAgIDxMSUNFTlNFLUFQQUNIRT4gb3IKICAgPGh0dHA6
+Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMD4sCiAtIG9yIHRoZSBNSVQgbGlj
+ZW5zZQogICA8TElDRU5TRS1NSVQ+IG9yCiAgIDxodHRwOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5z
+ZXMvTUlUPiwKCmF0IHlvdXIgb3B0aW9uLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64
new file mode 100644
index 000000000..a44c99db0
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDIxIFJ1c3RDcnlwdG8gRGV2ZWxvcGVycwoKUGVybWlzc2lvbiBpcyBo
+ZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWluaW5nIGEg
+Y29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24gZmlsZXMg
+KHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCByZXN0cmlj
+dGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29w
+eSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29y
+IHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdo
+b20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9s
+bG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBw
+ZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0
+YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURF
+RCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9SIElNUExJ
+RUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hB
+TlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklO
+R0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVS
+UyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdI
+RVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lO
+RyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUg
+VVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9.base64
new file mode 100644
index 000000000..f45073822
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9.base64
@@ -0,0 +1,19 @@
+UGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQ0KcGVy
+c29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZA0KZG9j
+dW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQ0KU29mdHdh
+cmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQNCmxpbWl0YXRpb24gdGhl
+IHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsDQpwdWJsaXNoLCBkaXN0cmlidXRl
+LCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YNCnRoZSBTb2Z0d2FyZSwgYW5kIHRv
+IHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlDQppcyBmdXJuaXNoZWQgdG8gZG8g
+c28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZw0KY29uZGl0aW9uczoNCg0KVGhlIGFib3ZlIGNv
+cHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2UNCnNoYWxsIGJlIGluY2x1
+ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMNCm9mIHRoZSBTb2Z0d2Fy
+ZS4NCg0KVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkg
+T0YNCkFOWSBLSU5ELCBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlU
+RUQNClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQQ0K
+UEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UDQpTSEFM
+TCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWQ0KQ0xB
+SU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTg0KT0Yg
+Q09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUg0KSU4g
+Q09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSDQpERUFMSU5H
+UyBJTiBUSEUgU09GVFdBUkUuDQo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9.base64
new file mode 100644
index 000000000..435dc2fa0
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9.base64
@@ -0,0 +1,15 @@
+U2hvcnQgdmVyc2lvbiBmb3Igbm9uLWxhd3llcnM6CgpgcnVzdGl4YCBpcyB0cmlwbGUtbGljZW5z
+ZWQgdW5kZXIgQXBhY2hlIDIuMCB3aXRoIHRoZSBMTFZNIEV4Y2VwdGlvbiwKQXBhY2hlIDIuMCwg
+YW5kIE1JVCB0ZXJtcy4KCgpMb25nZXIgdmVyc2lvbjoKCkNvcHlyaWdodHMgaW4gdGhlIGBydXN0
+aXhgIHByb2plY3QgYXJlIHJldGFpbmVkIGJ5IHRoZWlyIGNvbnRyaWJ1dG9ycy4KTm8gY29weXJp
+Z2h0IGFzc2lnbm1lbnQgaXMgcmVxdWlyZWQgdG8gY29udHJpYnV0ZSB0byB0aGUgYHJ1c3RpeGAK
+cHJvamVjdC4KClNvbWUgZmlsZXMgaW5jbHVkZSBjb2RlIGRlcml2ZWQgZnJvbSBSdXN0J3MgYGxp
+YnN0ZGA7IHNlZSB0aGUgY29tbWVudHMgaW4KdGhlIGNvZGUgZm9yIGRldGFpbHMuCgpFeGNlcHQg
+YXMgb3RoZXJ3aXNlIG5vdGVkIChiZWxvdyBhbmQvb3IgaW4gaW5kaXZpZHVhbCBmaWxlcyksIGBy
+dXN0aXhgCmlzIGxpY2Vuc2VkIHVuZGVyOgoKIC0gdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9u
+IDIuMCwgd2l0aCB0aGUgTExWTSBFeGNlcHRpb24KICAgPExJQ0VOU0UtQXBhY2hlLTIuMF9XSVRI
+X0xMVk0tZXhjZXB0aW9uPiBvcgogICA8aHR0cDovL2xsdm0ub3JnL2ZvdW5kYXRpb24vcmVsaWNl
+bnNpbmcvTElDRU5TRS50eHQ+CiAtIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAKICAg
+PExJQ0VOU0UtQVBBQ0hFPiBvcgogICA8aHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJ
+Q0VOU0UtMi4wPiwKIC0gb3IgdGhlIE1JVCBsaWNlbnNlCiAgIDxMSUNFTlNFLU1JVD4gb3IKICAg
+PGh0dHA6Ly9vcGVuc291cmNlLm9yZy9saWNlbnNlcy9NSVQ+LAoKYXQgeW91ciBvcHRpb24uCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64
new file mode 100644
index 000000000..b53aaa660
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE0IEFsZXggQ3JpY2h0b24KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdy
+YW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2Yg
+dGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNv
+ZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGlu
+Y2x1ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlm
+eSwgbWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNv
+cGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBT
+b2Z0d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZwpj
+b25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lv
+biBub3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBw
+b3J0aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElT
+IiwgV0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNM
+VURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElU
+WSwgRklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4g
+SU4gTk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElB
+QkxFIEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElO
+IEFOIEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwg
+T1VUIE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBP
+VEhFUgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42.base64
new file mode 100644
index 000000000..34e6d73be
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE4IENhcmwgTGVyY2hlCgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFu
+dGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRo
+aXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0
+d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNs
+dWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnks
+IG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3Bp
+ZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29m
+dHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcKY29u
+ZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24g
+bm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9y
+dGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIs
+IFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVE
+SU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFks
+IEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElO
+IE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJM
+RSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBB
+TiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9V
+VCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RI
+RVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd.base64
new file mode 100644
index 000000000..d8a50af44
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd.base64
@@ -0,0 +1,28 @@
+VGhlIGF1dG8tZ2VuZXJhdGVkIGJpbmRpbmdzIGFyZSB1bmRlciB0aGUgMy1jbGF1c2UgQlNEIGxp
+Y2Vuc2U6CgpCU0QgTGljZW5zZQoKRm9yIFpzdGFuZGFyZCBzb2Z0d2FyZQoKQ29weXJpZ2h0IChj
+KSAyMDE2LXByZXNlbnQsIEZhY2Vib29rLCBJbmMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgpSZWRp
+c3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdp
+dGhvdXQgbW9kaWZpY2F0aW9uLAphcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxv
+d2luZyBjb25kaXRpb25zIGFyZSBtZXQ6CgogKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNv
+ZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsIHRoaXMKICAgbGlzdCBv
+ZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgogKiBSZWRpc3RyaWJ1
+dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodCBu
+b3RpY2UsCiAgIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2Ns
+YWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb24KICAgYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92
+aWRlZCB3aXRoIHRoZSBkaXN0cmlidXRpb24uCgogKiBOZWl0aGVyIHRoZSBuYW1lIEZhY2Vib29r
+IG5vciB0aGUgbmFtZXMgb2YgaXRzIGNvbnRyaWJ1dG9ycyBtYXkgYmUgdXNlZCB0bwogICBlbmRv
+cnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZCBmcm9tIHRoaXMgc29mdHdhcmUgd2l0aG91
+dCBzcGVjaWZpYwogICBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgpUSElTIFNPRlRXQVJFIElT
+IFBST1ZJREVEIEJZIFRIRSBDT1BZUklHSFQgSE9MREVSUyBBTkQgQ09OVFJJQlVUT1JTICJBUyBJ
+UyIgQU5ECkFOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQg
+Tk9UIExJTUlURUQgVE8sIFRIRSBJTVBMSUVECldBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZ
+IEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUKRElTQ0xBSU1FRC4gSU4g
+Tk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVCBIT0xERVIgT1IgQ09OVFJJQlVUT1JTIEJFIExJ
+QUJMRSBGT1IKQU5ZIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsIFNQRUNJQUwsIEVYRU1Q
+TEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTCihJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRF
+RCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUzsKTE9TUyBP
+RiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikgSE9XRVZF
+UiBDQVVTRUQgQU5EIE9OCkFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRS
+QUNULCBTVFJJQ1QgTElBQklMSVRZLCBPUiBUT1JUCihJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBP
+VEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRiBUSElTClNPRlRX
+QVJFLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64
new file mode 100644
index 000000000..f8430850f
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64
@@ -0,0 +1,191 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCkFQUEVORElYOiBIb3cgdG8gYXBwbHkg
+dGhlIEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgIGJvaWxlcnBsYXRl
+IG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJbXSIKICAgcmVw
+bGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0IGluY2x1
+ZGUKICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3NlZCBpbiB0aGUg
+YXBwcm9wcmlhdGUKICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZvcm1hdC4gV2UgYWxz
+byByZWNvbW1lbmQgdGhhdCBhCiAgIGZpbGUgb3IgY2xhc3MgbmFtZSBhbmQgZGVzY3JpcHRpb24g
+b2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgc2FtZSAicHJpbnRlZCBwYWdlIiBhcyB0
+aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgIGlkZW50aWZpY2F0aW9uIHdpdGhpbiB0
+aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCkNvcHlyaWdodCAyMDE0IFBhaG8gTHVyaWUtR3JlZ2cKCkxp
+Y2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5z
+ZSIpOwp5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGgg
+dGhlIExpY2Vuc2UuCllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKCWh0
+dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKVW5sZXNzIHJlcXVpcmVk
+IGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQpkaXN0
+cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJB
+U0lTLApXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVy
+IGV4cHJlc3Mgb3IgaW1wbGllZC4KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFu
+Z3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZApsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGlj
+ZW5zZS4=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/523a42c25d245dde9c015f882cec7f4555aad883382a6cf19b4b7d9b2cd5419b.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/523a42c25d245dde9c015f882cec7f4555aad883382a6cf19b4b7d9b2cd5419b.base64
new file mode 100644
index 000000000..9d42f4545
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/523a42c25d245dde9c015f882cec7f4555aad883382a6cf19b4b7d9b2cd5419b.base64
@@ -0,0 +1,20 @@
+Q29weXJpZ2h0IChjKSAyMDE4LTIwMjYgVGhlIHJ1c3QtcmFuZG9tIFByb2plY3QgRGV2ZWxvcGVy
+cwpDb3B5cmlnaHQgKGMpIDIwMTQgVGhlIFJ1c3QgUHJvamVjdCBEZXZlbG9wZXJzCgpQZXJtaXNz
+aW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRh
+aW5pbmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlv
+biBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0
+IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8g
+dXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNl
+LCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNv
+bnMgdG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRv
+IHRoZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFu
+ZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMg
+b3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElT
+IFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1Mg
+T1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBP
+RiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBO
+T05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdI
+VCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJ
+TElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNF
+LCBBUklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJF
+IE9SIFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64
new file mode 100644
index 000000000..f2778470e
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64
@@ -0,0 +1,171 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMK
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.base64
new file mode 100644
index 000000000..63f5ccfa7
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE0IFRoZSBSdXN0IFByb2plY3QgRGV2ZWxvcGVycwoKUGVybWlzc2lv
+biBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWlu
+aW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24g
+ZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCBy
+ZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVz
+ZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwg
+YW5kL29yIHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25z
+IHRvIHdob20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0
+aGUgZm9sbG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQg
+dGhpcyBwZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9y
+IHN1YnN0YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQ
+Uk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9S
+IElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0Yg
+TUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9O
+SU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQg
+SE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJ
+VFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwg
+QVJJU0lORyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBP
+UiBUSEUgVVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6.base64
new file mode 100644
index 000000000..1031a138d
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSBJbmRpdmlkdWFsIGNvbnRyaWJ1dG9ycwoKUGVybWlzc2lvbiBpcyBoZXJl
+YnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29w
+eQpvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRo
+ZSAiU29mdHdhcmUiKSwgdG8gZGVhbAppbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlv
+biwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzCnRvIHVzZSwgY29weSwg
+bW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNl
+bGwKY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20g
+dGhlIFNvZnR3YXJlIGlzCmZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93
+aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJt
+aXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwKY29waWVzIG9yIHN1YnN0YW50
+aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAi
+QVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SCklNUExJRUQs
+IElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRB
+QklMSVRZLApGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VN
+RU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUKQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBC
+RSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUgpMSUFCSUxJVFksIFdIRVRI
+RVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBG
+Uk9NLApPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNF
+IE9SIE9USEVSIERFQUxJTkdTIElOIFRIRQpTT0ZUV0FSRS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8.base64
new file mode 100644
index 000000000..3ea11f2c8
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8.base64
@@ -0,0 +1,28 @@
+QlNEIExpY2Vuc2UKCkZvciBac3RhbmRhcmQgc29mdHdhcmUKCkNvcHlyaWdodCAoYykgTWV0YSBQ
+bGF0Zm9ybXMsIEluYy4gYW5kIGFmZmlsaWF0ZXMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgpSZWRp
+c3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdp
+dGhvdXQgbW9kaWZpY2F0aW9uLAphcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxv
+d2luZyBjb25kaXRpb25zIGFyZSBtZXQ6CgogKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNv
+ZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsIHRoaXMKICAgbGlzdCBv
+ZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgogKiBSZWRpc3RyaWJ1
+dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodCBu
+b3RpY2UsCiAgIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2Ns
+YWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb24KICAgYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92
+aWRlZCB3aXRoIHRoZSBkaXN0cmlidXRpb24uCgogKiBOZWl0aGVyIHRoZSBuYW1lIEZhY2Vib29r
+LCBub3IgTWV0YSwgbm9yIHRoZSBuYW1lcyBvZiBpdHMgY29udHJpYnV0b3JzIG1heQogICBiZSB1
+c2VkIHRvIGVuZG9yc2Ugb3IgcHJvbW90ZSBwcm9kdWN0cyBkZXJpdmVkIGZyb20gdGhpcyBzb2Z0
+d2FyZSB3aXRob3V0CiAgIHNwZWNpZmljIHByaW9yIHdyaXR0ZW4gcGVybWlzc2lvbi4KClRISVMg
+U09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORCBDT05UUklC
+VVRPUlMgIkFTIElTIiBBTkQKQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNM
+VURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQKV0FSUkFOVElFUyBPRiBNRVJD
+SEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRQpESVND
+TEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQ09QWVJJR0hUIEhPTERFUiBPUiBDT05UUklC
+VVRPUlMgQkUgTElBQkxFIEZPUgpBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BF
+Q0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMKKElOQ0xVRElORywgQlVU
+IE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJ
+Q0VTOwpMT1NTIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBU
+SU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT04KQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRI
+RVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQKKElOQ0xVRElORyBORUdM
+SUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgVVNFIE9G
+IFRISVMKU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VD
+SCBEQU1BR0UuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349.base64
new file mode 100644
index 000000000..349320f20
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE2LS0yMDIzCgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBm
+cmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRoaXMgc29m
+dHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIp
+LCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcg
+d2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdl
+LApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YK
+dGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUK
+aXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcKY29uZGl0aW9u
+czoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNl
+CnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMK
+b2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhP
+VVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIEJV
+VCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5F
+U1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVW
+RU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1Ig
+QU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJ
+T04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBP
+UgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIKREVB
+TElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64
new file mode 100644
index 000000000..d3bb917f5
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE1IFRoZSBSdXN0IFByb2plY3QgRGV2ZWxvcGVycwoKUGVybWlzc2lv
+biBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWlu
+aW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24g
+ZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCBy
+ZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVz
+ZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwg
+YW5kL29yIHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25z
+IHRvIHdob20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0
+aGUgZm9sbG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQg
+dGhpcyBwZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9y
+IHN1YnN0YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQ
+Uk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9S
+IElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0Yg
+TUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9O
+SU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQg
+SE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJ
+VFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwg
+QVJJU0lORyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBP
+UiBUSEUgVVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c.base64
new file mode 100644
index 000000000..037f43cf2
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c.base64
@@ -0,0 +1,194 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UNCiAgICAgICAgICAg
+ICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQNCiAgICAgICAgICAgICAgICAg
+ICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy8NCg0KVEVSTVMgQU5EIENPTkRJVElP
+TlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9ODQoNCjEuIERlZmluaXRp
+b25zLg0KDQogICAiTGljZW5zZSIgc2hhbGwgbWVhbiB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMg
+Zm9yIHVzZSwgcmVwcm9kdWN0aW9uLA0KICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5
+IFNlY3Rpb25zIDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuDQoNCiAgICJMaWNlbnNvciIg
+c2hhbGwgbWVhbiB0aGUgY29weXJpZ2h0IG93bmVyIG9yIGVudGl0eSBhdXRob3JpemVkIGJ5DQog
+ICB0aGUgY29weXJpZ2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuDQoNCiAg
+ICJMZWdhbCBFbnRpdHkiIHNoYWxsIG1lYW4gdGhlIHVuaW9uIG9mIHRoZSBhY3RpbmcgZW50aXR5
+IGFuZCBhbGwNCiAgIG90aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQg
+YnksIG9yIGFyZSB1bmRlciBjb21tb24NCiAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9y
+IHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sDQogICAiY29udHJvbCIgbWVhbnMgKGkp
+IHRoZSBwb3dlciwgZGlyZWN0IG9yIGluZGlyZWN0LCB0byBjYXVzZSB0aGUNCiAgIGRpcmVjdGlv
+biBvciBtYW5hZ2VtZW50IG9mIHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yDQog
+ICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3Ig
+bW9yZSBvZiB0aGUNCiAgIG91dHN0YW5kaW5nIHNoYXJlcywgb3IgKGlpaSkgYmVuZWZpY2lhbCBv
+d25lcnNoaXAgb2Ygc3VjaCBlbnRpdHkuDQoNCiAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1l
+YW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkNCiAgIGV4ZXJjaXNpbmcgcGVybWlzc2lv
+bnMgZ3JhbnRlZCBieSB0aGlzIExpY2Vuc2UuDQoNCiAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVh
+biB0aGUgcHJlZmVycmVkIGZvcm0gZm9yIG1ha2luZyBtb2RpZmljYXRpb25zLA0KICAgaW5jbHVk
+aW5nIGJ1dCBub3QgbGltaXRlZCB0byBzb2Z0d2FyZSBzb3VyY2UgY29kZSwgZG9jdW1lbnRhdGlv
+bg0KICAgc291cmNlLCBhbmQgY29uZmlndXJhdGlvbiBmaWxlcy4NCg0KICAgIk9iamVjdCIgZm9y
+bSBzaGFsbCBtZWFuIGFueSBmb3JtIHJlc3VsdGluZyBmcm9tIG1lY2hhbmljYWwNCiAgIHRyYW5z
+Zm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEgU291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQN
+CiAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1l
+bnRhdGlvbiwNCiAgIGFuZCBjb252ZXJzaW9ucyB0byBvdGhlciBtZWRpYSB0eXBlcy4NCg0KICAg
+IldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3Vy
+Y2Ugb3INCiAgIE9iamVjdCBmb3JtLCBtYWRlIGF2YWlsYWJsZSB1bmRlciB0aGUgTGljZW5zZSwg
+YXMgaW5kaWNhdGVkIGJ5IGENCiAgIGNvcHlyaWdodCBub3RpY2UgdGhhdCBpcyBpbmNsdWRlZCBp
+biBvciBhdHRhY2hlZCB0byB0aGUgd29yaw0KICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4g
+dGhlIEFwcGVuZGl4IGJlbG93KS4NCg0KICAgIkRlcml2YXRpdmUgV29ya3MiIHNoYWxsIG1lYW4g
+YW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdA0KICAgZm9ybSwgdGhhdCBpcyBi
+YXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQ0KICAg
+ZWRpdG9yaWFsIHJldmlzaW9ucywgYW5ub3RhdGlvbnMsIGVsYWJvcmF0aW9ucywgb3Igb3RoZXIg
+bW9kaWZpY2F0aW9ucw0KICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBhbiBvcmlnaW5hbCB3b3Jr
+IG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMNCiAgIG9mIHRoaXMgTGljZW5zZSwgRGVy
+aXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbg0KICAgc2Vw
+YXJhYmxlIGZyb20sIG9yIG1lcmVseSBsaW5rIChvciBiaW5kIGJ5IG5hbWUpIHRvIHRoZSBpbnRl
+cmZhY2VzIG9mLA0KICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZi4NCg0K
+ICAgIkNvbnRyaWJ1dGlvbiIgc2hhbGwgbWVhbiBhbnkgd29yayBvZiBhdXRob3JzaGlwLCBpbmNs
+dWRpbmcNCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBhbnkgbW9kaWZp
+Y2F0aW9ucyBvciBhZGRpdGlvbnMNCiAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0aXZlIFdvcmtz
+IHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQ0KICAgc3VibWl0dGVkIHRvIExpY2Vuc29y
+IGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsgYnkgdGhlIGNvcHlyaWdodCBvd25lcg0KICAgb3Ig
+YnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJtaXQgb24g
+YmVoYWxmIG9mDQogICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRo
+aXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCINCiAgIG1lYW5zIGFueSBmb3JtIG9mIGVsZWN0cm9u
+aWMsIHZlcmJhbCwgb3Igd3JpdHRlbiBjb21tdW5pY2F0aW9uIHNlbnQNCiAgIHRvIHRoZSBMaWNl
+bnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRv
+DQogICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNlIGNv
+ZGUgY29udHJvbCBzeXN0ZW1zLA0KICAgYW5kIGlzc3VlIHRyYWNraW5nIHN5c3RlbXMgdGhhdCBh
+cmUgbWFuYWdlZCBieSwgb3Igb24gYmVoYWxmIG9mLCB0aGUNCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dA0KICAgZXhj
+bHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhl
+cndpc2UNCiAgIGRlc2lnbmF0ZWQgaW4gd3JpdGluZyBieSB0aGUgY29weXJpZ2h0IG93bmVyIGFz
+ICJOb3QgYSBDb250cmlidXRpb24uIg0KDQogICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGlj
+ZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQ0KICAgb24gYmVoYWxmIG9m
+IHdob20gYSBDb250cmlidXRpb24gaGFzIGJlZW4gcmVjZWl2ZWQgYnkgTGljZW5zb3IgYW5kDQog
+ICBzdWJzZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4NCg0KMi4gR3JhbnQg
+b2YgQ29weXJpZ2h0IExpY2Vuc2UuIFN1YmplY3QgdG8gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25z
+IG9mDQogICB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZ
+b3UgYSBwZXJwZXR1YWwsDQogICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwg
+cm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQ0KICAgY29weXJpZ2h0IGxpY2Vuc2UgdG8gcmVwcm9k
+dWNlLCBwcmVwYXJlIERlcml2YXRpdmUgV29ya3Mgb2YsDQogICBwdWJsaWNseSBkaXNwbGF5LCBw
+dWJsaWNseSBwZXJmb3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUNCiAgIFdvcmsg
+YW5kIHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uDQoNCjMu
+IEdyYW50IG9mIFBhdGVudCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0
+aW9ucyBvZg0KICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMg
+dG8gWW91IGEgcGVycGV0dWFsLA0KICAgd29ybGR3aWRlLCBub24tZXhjbHVzaXZlLCBuby1jaGFy
+Z2UsIHJveWFsdHktZnJlZSwgaXJyZXZvY2FibGUNCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRo
+aXMgc2VjdGlvbikgcGF0ZW50IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLA0KICAgdXNlLCBv
+ZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdv
+cmssDQogICB3aGVyZSBzdWNoIGxpY2Vuc2UgYXBwbGllcyBvbmx5IHRvIHRob3NlIHBhdGVudCBj
+bGFpbXMgbGljZW5zYWJsZQ0KICAgYnkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3Nh
+cmlseSBpbmZyaW5nZWQgYnkgdGhlaXINCiAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBj
+b21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykNCiAgIHdpdGggdGhlIFdvcmsgdG8g
+d2hpY2ggc3VjaCBDb250cmlidXRpb24ocykgd2FzIHN1Ym1pdHRlZC4gSWYgWW91DQogICBpbnN0
+aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24gYWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQ0K
+ICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhh
+dCB0aGUgV29yaw0KICAgb3IgYSBDb250cmlidXRpb24gaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUg
+V29yayBjb25zdGl0dXRlcyBkaXJlY3QNCiAgIG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmlu
+Z2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGljZW5zZXMNCiAgIGdyYW50ZWQgdG8gWW91IHVuZGVy
+IHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1pbmF0ZQ0KICAgYXMgb2YgdGhl
+IGRhdGUgc3VjaCBsaXRpZ2F0aW9uIGlzIGZpbGVkLg0KDQo0LiBSZWRpc3RyaWJ1dGlvbi4gWW91
+IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVzIG9mIHRoZQ0KICAgV29yayBvciBE
+ZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YgaW4gYW55IG1lZGl1bSwgd2l0aCBvciB3aXRob3V0DQog
+ICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCBwcm92aWRlZCB0
+aGF0IFlvdQ0KICAgbWVldCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6DQoNCiAgIChhKSBZb3Ug
+bXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRoZSBXb3JrIG9yDQogICAgICAgRGVy
+aXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNlOyBhbmQNCg0KICAgKGIpIFlvdSBt
+dXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcw0K
+ICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmlsZXM7IGFuZA0KDQogICAoYykg
+WW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55IERlcml2YXRpdmUgV29y
+a3MNCiAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRy
+YWRlbWFyaywgYW5kDQogICAgICAgYXR0cmlidXRpb24gbm90aWNlcyBmcm9tIHRoZSBTb3VyY2Ug
+Zm9ybSBvZiB0aGUgV29yaywNCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRv
+IG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mDQogICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7
+IGFuZA0KDQogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0ZXh0IGZpbGUg
+YXMgcGFydCBvZiBpdHMNCiAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUg
+V29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0DQogICAgICAgaW5jbHVkZSBhIHJlYWRhYmxl
+IGNvcHkgb2YgdGhlIGF0dHJpYnV0aW9uIG5vdGljZXMgY29udGFpbmVkDQogICAgICAgd2l0aGlu
+IHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8gbm90DQog
+ICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQg
+bGVhc3Qgb25lDQogICAgICAgb2YgdGhlIGZvbGxvd2luZyBwbGFjZXM6IHdpdGhpbiBhIE5PVElD
+RSB0ZXh0IGZpbGUgZGlzdHJpYnV0ZWQNCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZl
+IFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yDQogICAgICAgZG9jdW1lbnRhdGlvbiwg
+aWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsDQogICAgICAg
+d2l0aGluIGEgZGlzcGxheSBnZW5lcmF0ZWQgYnkgdGhlIERlcml2YXRpdmUgV29ya3MsIGlmIGFu
+ZA0KICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cw0KICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9y
+bWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQNCiAgICAgICBkbyBub3QgbW9kaWZ5IHRoZSBMaWNl
+bnNlLiBZb3UgbWF5IGFkZCBZb3VyIG93biBhdHRyaWJ1dGlvbg0KICAgICAgIG5vdGljZXMgd2l0
+aGluIERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlDQogICAg
+ICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHBy
+b3ZpZGVkDQogICAgICAgdGhhdCBzdWNoIGFkZGl0aW9uYWwgYXR0cmlidXRpb24gbm90aWNlcyBj
+YW5ub3QgYmUgY29uc3RydWVkDQogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLg0KDQog
+ICBZb3UgbWF5IGFkZCBZb3VyIG93biBjb3B5cmlnaHQgc3RhdGVtZW50IHRvIFlvdXIgbW9kaWZp
+Y2F0aW9ucyBhbmQNCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vu
+c2UgdGVybXMgYW5kIGNvbmRpdGlvbnMNCiAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlz
+dHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3INCiAgIGZvciBhbnkgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGFzIGEgd2hvbGUsIHByb3ZpZGVkIFlvdXIgdXNlLA0KICAgcmVwcm9kdWN0
+aW9uLCBhbmQgZGlzdHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRo
+DQogICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLg0KDQo1LiBTdWJtaXNz
+aW9uIG9mIENvbnRyaWJ1dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndp
+c2UsDQogICBhbnkgQ29udHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNs
+dXNpb24gaW4gdGhlIFdvcmsNCiAgIGJ5IFlvdSB0byB0aGUgTGljZW5zb3Igc2hhbGwgYmUgdW5k
+ZXIgdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mDQogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQg
+YW55IGFkZGl0aW9uYWwgdGVybXMgb3IgY29uZGl0aW9ucy4NCiAgIE5vdHdpdGhzdGFuZGluZyB0
+aGUgYWJvdmUsIG5vdGhpbmcgaGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkNCiAgIHRo
+ZSB0ZXJtcyBvZiBhbnkgc2VwYXJhdGUgbGljZW5zZSBhZ3JlZW1lbnQgeW91IG1heSBoYXZlIGV4
+ZWN1dGVkDQogICB3aXRoIExpY2Vuc29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuDQoN
+CjYuIFRyYWRlbWFya3MuIFRoaXMgTGljZW5zZSBkb2VzIG5vdCBncmFudCBwZXJtaXNzaW9uIHRv
+IHVzZSB0aGUgdHJhZGUNCiAgIG5hbWVzLCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBw
+cm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNlbnNvciwNCiAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3Ig
+cmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQ0KICAgb3JpZ2lu
+IG9mIHRoZSBXb3JrIGFuZCByZXByb2R1Y2luZyB0aGUgY29udGVudCBvZiB0aGUgTk9USUNFIGZp
+bGUuDQoNCjcuIERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBs
+aWNhYmxlIGxhdyBvcg0KICAgYWdyZWVkIHRvIGluIHdyaXRpbmcsIExpY2Vuc29yIHByb3ZpZGVz
+IHRoZSBXb3JrIChhbmQgZWFjaA0KICAgQ29udHJpYnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1
+dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsDQogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09O
+RElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3INCiAgIGltcGxpZWQsIGluY2x1
+ZGluZywgd2l0aG91dCBsaW1pdGF0aW9uLCBhbnkgd2FycmFudGllcyBvciBjb25kaXRpb25zDQog
+ICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVSQ0hBTlRBQklMSVRZLCBvciBGSVRORVNT
+IEZPUiBBDQogICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNpYmxl
+IGZvciBkZXRlcm1pbmluZyB0aGUNCiAgIGFwcHJvcHJpYXRlbmVzcyBvZiB1c2luZyBvciByZWRp
+c3RyaWJ1dGluZyB0aGUgV29yayBhbmQgYXNzdW1lIGFueQ0KICAgcmlza3MgYXNzb2NpYXRlZCB3
+aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5kZXIgdGhpcyBMaWNlbnNlLg0KDQo4
+LiBMaW1pdGF0aW9uIG9mIExpYWJpbGl0eS4gSW4gbm8gZXZlbnQgYW5kIHVuZGVyIG5vIGxlZ2Fs
+IHRoZW9yeSwNCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5nIG5lZ2xpZ2VuY2UpLCBjb250
+cmFjdCwgb3Igb3RoZXJ3aXNlLA0KICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3
+IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkNCiAgIG5lZ2xpZ2VudCBhY3RzKSBvciBh
+Z3JlZWQgdG8gaW4gd3JpdGluZywgc2hhbGwgYW55IENvbnRyaWJ1dG9yIGJlDQogICBsaWFibGUg
+dG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwgaW5kaXJlY3QsIHNwZWNp
+YWwsDQogICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFnZXMgb2YgYW55IGNoYXJh
+Y3RlciBhcmlzaW5nIGFzIGENCiAgIHJlc3VsdCBvZiB0aGlzIExpY2Vuc2Ugb3Igb3V0IG9mIHRo
+ZSB1c2Ugb3IgaW5hYmlsaXR5IHRvIHVzZSB0aGUNCiAgIFdvcmsgKGluY2x1ZGluZyBidXQgbm90
+IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwNCiAgIHdvcmsgc3RvcHBh
+Z2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBhbmQgYWxsDQogICBv
+dGhlciBjb21tZXJjaWFsIGRhbWFnZXMgb3IgbG9zc2VzKSwgZXZlbiBpZiBzdWNoIENvbnRyaWJ1
+dG9yDQogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBzdWNoIGRhbWFn
+ZXMuDQoNCjkuIEFjY2VwdGluZyBXYXJyYW50eSBvciBBZGRpdGlvbmFsIExpYWJpbGl0eS4gV2hp
+bGUgcmVkaXN0cmlidXRpbmcNCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVv
+ZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsDQogICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNj
+ZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LA0KICAgb3Igb3RoZXIgbGlh
+YmlsaXR5IG9ibGlnYXRpb25zIGFuZC9vciByaWdodHMgY29uc2lzdGVudCB3aXRoIHRoaXMNCiAg
+IExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3UgbWF5
+IGFjdCBvbmx5DQogICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25z
+aWJpbGl0eSwgbm90IG9uIGJlaGFsZg0KICAgb2YgYW55IG90aGVyIENvbnRyaWJ1dG9yLCBhbmQg
+b25seSBpZiBZb3UgYWdyZWUgdG8gaW5kZW1uaWZ5LA0KICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5DQogICBpbmN1cnJlZCBieSwg
+b3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uDQog
+ICBvZiB5b3VyIGFjY2VwdGluZyBhbnkgc3VjaCB3YXJyYW50eSBvciBhZGRpdGlvbmFsIGxpYWJp
+bGl0eS4NCg0KRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TDQoNCkFQUEVORElYOiBIb3cgdG8g
+YXBwbHkgdGhlIEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4NCg0KICAgVG8gYXBwbHkgdGhl
+IEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yaywgYXR0YWNoIHRoZSBmb2xsb3dpbmcNCiAgIGJv
+aWxlcnBsYXRlIG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJb
+XSINCiAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChE
+b24ndCBpbmNsdWRlDQogICB0aGUgYnJhY2tldHMhKSAgVGhlIHRleHQgc2hvdWxkIGJlIGVuY2xv
+c2VkIGluIHRoZSBhcHByb3ByaWF0ZQ0KICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZv
+cm1hdC4gV2UgYWxzbyByZWNvbW1lbmQgdGhhdCBhDQogICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5k
+IGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlDQogICBzYW1lICJwcmlu
+dGVkIHBhZ2UiIGFzIHRoZSBjb3B5cmlnaHQgbm90aWNlIGZvciBlYXNpZXINCiAgIGlkZW50aWZp
+Y2F0aW9uIHdpdGhpbiB0aGlyZC1wYXJ0eSBhcmNoaXZlcy4NCg0KQ29weXJpZ2h0IFt5eXl5XSBb
+bmFtZSBvZiBjb3B5cmlnaHQgb3duZXJdDQoNCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGlj
+ZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOw0KeW91IG1heSBub3QgdXNlIHRoaXMg
+ZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLg0KWW91IG1heSBvYnRh
+aW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0DQoNCglodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGlj
+ZW5zZXMvTElDRU5TRS0yLjANCg0KVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9y
+IGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQ0KZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExp
+Y2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywNCldJVEhPVVQgV0FSUkFO
+VElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVk
+Lg0KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBl
+cm1pc3Npb25zIGFuZA0KbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuDQo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64
new file mode 100644
index 000000000..36c0b0762
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64
@@ -0,0 +1,22 @@
+VGhpcyBpcyBmcmVlIGFuZCB1bmVuY3VtYmVyZWQgc29mdHdhcmUgcmVsZWFzZWQgaW50byB0aGUg
+cHVibGljIGRvbWFpbi4KCkFueW9uZSBpcyBmcmVlIHRvIGNvcHksIG1vZGlmeSwgcHVibGlzaCwg
+dXNlLCBjb21waWxlLCBzZWxsLCBvcgpkaXN0cmlidXRlIHRoaXMgc29mdHdhcmUsIGVpdGhlciBp
+biBzb3VyY2UgY29kZSBmb3JtIG9yIGFzIGEgY29tcGlsZWQKYmluYXJ5LCBmb3IgYW55IHB1cnBv
+c2UsIGNvbW1lcmNpYWwgb3Igbm9uLWNvbW1lcmNpYWwsIGFuZCBieSBhbnkKbWVhbnMuCgpJbiBq
+dXJpc2RpY3Rpb25zIHRoYXQgcmVjb2duaXplIGNvcHlyaWdodCBsYXdzLCB0aGUgYXV0aG9yIG9y
+IGF1dGhvcnMKb2YgdGhpcyBzb2Z0d2FyZSBkZWRpY2F0ZSBhbnkgYW5kIGFsbCBjb3B5cmlnaHQg
+aW50ZXJlc3QgaW4gdGhlCnNvZnR3YXJlIHRvIHRoZSBwdWJsaWMgZG9tYWluLiBXZSBtYWtlIHRo
+aXMgZGVkaWNhdGlvbiBmb3IgdGhlIGJlbmVmaXQKb2YgdGhlIHB1YmxpYyBhdCBsYXJnZSBhbmQg
+dG8gdGhlIGRldHJpbWVudCBvZiBvdXIgaGVpcnMgYW5kCnN1Y2Nlc3NvcnMuIFdlIGludGVuZCB0
+aGlzIGRlZGljYXRpb24gdG8gYmUgYW4gb3ZlcnQgYWN0IG9mCnJlbGlucXVpc2htZW50IGluIHBl
+cnBldHVpdHkgb2YgYWxsIHByZXNlbnQgYW5kIGZ1dHVyZSByaWdodHMgdG8gdGhpcwpzb2Z0d2Fy
+ZSB1bmRlciBjb3B5cmlnaHQgbGF3LgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIs
+IFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsCkVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVE
+SU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRgpNRVJDSEFOVEFCSUxJVFks
+IEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuCklO
+IE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1B
+R0VTIE9SCk9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1Qs
+IFRPUlQgT1IgT1RIRVJXSVNFLApBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9O
+IFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IKT1RIRVIgREVBTElOR1MgSU4gVEhFIFNP
+RlRXQVJFLgoKRm9yIG1vcmUgaW5mb3JtYXRpb24sIHBsZWFzZSByZWZlciB0byA8aHR0cDovL3Vu
+bGljZW5zZS5vcmcvPgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2.base64
new file mode 100644
index 000000000..8ca7d5553
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE0IENocmlzIFdvbmcKClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50
+ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhp
+cyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3
+YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1
+ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwg
+bWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGll
+cyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0
+d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZwpjb25k
+aXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBu
+b3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0
+aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwg
+V0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJ
+TkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwg
+RklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4g
+Tk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxF
+IEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFO
+IEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VU
+IE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhF
+UgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36.base64
new file mode 100644
index 000000000..7744e2c5b
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE1IFN0ZXZlbiBBbGxlbgoKUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3Jh
+bnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWluaW5nIGEgY29weSBvZiB0
+aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29m
+dHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5j
+bHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5
+LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29w
+aWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNv
+ZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nCmNv
+bmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9u
+IG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBv
+cnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMi
+LCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xV
+RElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZ
+LCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJ
+TiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFC
+TEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4g
+QU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBP
+VVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9U
+SEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077.base64
new file mode 100644
index 000000000..66df04367
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSBUaGUgdGFyLXJzIFByb2plY3QgQ29udHJpYnV0b3JzCgpQZXJtaXNzaW9u
+IGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRhaW5p
+bmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlvbiBm
+aWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0IHJl
+c3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNl
+LCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBh
+bmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMg
+dG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRo
+ZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0
+aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Ig
+c3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElTIFBS
+T1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1MgT1Ig
+SU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBPRiBN
+RVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05J
+TkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBI
+T0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElU
+WSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBB
+UklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9S
+IFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64
new file mode 100644
index 000000000..c81079b6f
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE3IEFydHlvbSBQYXZsb3YKClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdy
+YW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2Yg
+dGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNv
+ZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGlu
+Y2x1ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlm
+eSwgbWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNv
+cGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBT
+b2Z0d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZwpj
+b25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lv
+biBub3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBw
+b3J0aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElT
+IiwgV0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNM
+VURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElU
+WSwgRklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4g
+SU4gTk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElB
+QkxFIEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElO
+IEFOIEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwg
+T1VUIE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBP
+VEhFUgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64
new file mode 100644
index 000000000..6ead32cec
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64
@@ -0,0 +1,191 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCkFQUEVORElYOiBIb3cgdG8gYXBwbHkg
+dGhlIEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgIGJvaWxlcnBsYXRl
+IG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJbXSIKICAgcmVw
+bGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0IGluY2x1
+ZGUKICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3NlZCBpbiB0aGUg
+YXBwcm9wcmlhdGUKICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZvcm1hdC4gV2UgYWxz
+byByZWNvbW1lbmQgdGhhdCBhCiAgIGZpbGUgb3IgY2xhc3MgbmFtZSBhbmQgZGVzY3JpcHRpb24g
+b2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgc2FtZSAicHJpbnRlZCBwYWdlIiBhcyB0
+aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgIGlkZW50aWZpY2F0aW9uIHdpdGhpbiB0
+aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCkNvcHlyaWdodCBbeXl5eV0gW25hbWUgb2YgY29weXJpZ2h0
+IG93bmVyXQoKTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAo
+dGhlICJMaWNlbnNlIik7CnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBs
+aWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNl
+bnNlIGF0CgoJaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgpVbmxl
+c3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNv
+ZnR3YXJlCmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFu
+ICJBUyBJUyIgQkFTSVMsCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBL
+SU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgpTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBz
+cGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCmxpbWl0YXRpb25zIHVu
+ZGVyIHRoZSBMaWNlbnNlLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63.base64
new file mode 100644
index 000000000..078caa305
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63.base64
@@ -0,0 +1 @@
+TUlUIG9yIEFwYWNoZS0yLjAK
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64
new file mode 100644
index 000000000..10ff42af9
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64
@@ -0,0 +1,19 @@
+VGhlIE1JVCBMaWNlbnNlIChNSVQpCgpDb3B5cmlnaHQgKGMpIDIwMTQgUGFobyBMdXJpZS1HcmVn
+ZwoKUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBw
+ZXJzb24gb2J0YWluaW5nIGEgY29weQpvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRv
+Y3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbAppbiB0aGUgU29mdHdh
+cmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUg
+cmlnaHRzCnRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwg
+c3VibGljZW5zZSwgYW5kL29yIHNlbGwKY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBl
+cm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzCmZ1cm5pc2hlZCB0byBkbyBzbywg
+c3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0
+IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBh
+bGwKY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBT
+T0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5E
+LCBFWFBSRVNTIE9SCklNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdB
+UlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLApGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVS
+UE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUKQVVUSE9SUyBP
+UiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBP
+VEhFUgpMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9S
+IE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLApPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRI
+RSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRQpTT0ZUV0FSRS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64
new file mode 100644
index 000000000..266160f58
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64
@@ -0,0 +1,191 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCkFQUEVORElYOiBIb3cgdG8gYXBwbHkg
+dGhlIEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgIGJvaWxlcnBsYXRl
+IG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJbXSIKICAgcmVw
+bGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0IGluY2x1
+ZGUKICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3NlZCBpbiB0aGUg
+YXBwcm9wcmlhdGUKICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZvcm1hdC4gV2UgYWxz
+byByZWNvbW1lbmQgdGhhdCBhCiAgIGZpbGUgb3IgY2xhc3MgbmFtZSBhbmQgZGVzY3JpcHRpb24g
+b2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgc2FtZSAicHJpbnRlZCBwYWdlIiBhcyB0
+aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgIGlkZW50aWZpY2F0aW9uIHdpdGhpbiB0
+aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCkNvcHlyaWdodCBbeXl5eV0gW25hbWUgb2YgY29weXJpZ2h0
+IG93bmVyXQoKTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAo
+dGhlICJMaWNlbnNlIik7CnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBs
+aWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNl
+bnNlIGF0CgogICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKClVu
+bGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywg
+c29mdHdhcmUKZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24g
+YW4gIkFTIElTIiBCQVNJUywKV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5Z
+IEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuClNlZSB0aGUgTGljZW5zZSBmb3IgdGhl
+IHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKbGltaXRhdGlvbnMg
+dW5kZXIgdGhlIExpY2Vuc2UuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64
new file mode 100644
index 000000000..611d21f96
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64
@@ -0,0 +1,191 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwczovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKVEVSTVMgQU5EIENPTkRJVElPTlMg
+Rk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgoxLiBEZWZpbml0aW9ucy4K
+CiAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNl
+LCByZXByb2R1Y3Rpb24sCiAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9u
+cyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFu
+IHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgdGhlIGNvcHly
+aWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgIkxlZ2FsIEVudGl0
+eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICBv
+dGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5k
+ZXIgY29tbW9uCiAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBv
+ZiB0aGlzIGRlZmluaXRpb24sCiAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJl
+Y3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBv
+ZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICBvdGhlcndpc2UsIG9yIChp
+aSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgb3V0
+c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVu
+dGl0eS4KCiAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBM
+ZWdhbCBFbnRpdHkKICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGlj
+ZW5zZS4KCiAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y
+IG1ha2luZyBtb2RpZmljYXRpb25zLAogICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNv
+ZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgIHNvdXJjZSwgYW5kIGNvbmZpZ3Vy
+YXRpb24gZmlsZXMuCgogICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0
+aW5nIGZyb20gbWVjaGFuaWNhbAogICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBh
+IFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9i
+amVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgYW5kIGNvbnZlcnNpb25zIHRv
+IG90aGVyIG1lZGlhIHR5cGVzLgoKICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0
+aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxh
+YmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICBjb3B5cmlnaHQgbm90
+aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgKGFuIGV4
+YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICJEZXJpdmF0aXZl
+IFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QK
+ICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQg
+Zm9yIHdoaWNoIHRoZQogICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9y
+YXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwg
+YW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgIG9mIHRo
+aXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0
+IHJlbWFpbgogICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFt
+ZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtz
+IHRoZXJlb2YuCgogICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhv
+cnNoaXAsIGluY2x1ZGluZwogICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg
+YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0
+aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICBzdWJtaXR0ZWQgdG8g
+TGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVy
+CiAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3Vi
+bWl0IG9uIGJlaGFsZiBvZgogICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2Vz
+IG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgbWVhbnMgYW55IGZvcm0gb2YgZWxl
+Y3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICB0byB0aGUg
+TGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRl
+ZCB0bwogICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNl
+IGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0
+IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICBMaWNlbnNvciBmb3IgdGhl
+IHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgZXhj
+bHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhl
+cndpc2UKICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMg
+Ik5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5z
+b3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICBvbiBiZWhhbGYgb2Ygd2hv
+bSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgc3Vi
+c2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgoyLiBHcmFudCBvZiBDb3B5
+cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAg
+dGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVy
+cGV0dWFsLAogICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1m
+cmVlLCBpcnJldm9jYWJsZQogICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBh
+cmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy
+Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgIFdvcmsgYW5kIHN1Y2ggRGVy
+aXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgozLiBHcmFudCBvZiBQYXRl
+bnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgdGhp
+cyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0
+dWFsLAogICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVl
+LCBpcnJldm9jYWJsZQogICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVu
+dCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxs
+LCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgIHdoZXJlIHN1Y2gg
+bGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAg
+IGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRo
+ZWlyCiAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBD
+b250cmlidXRpb24ocykKICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlv
+bihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9u
+IGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgY3Jvc3MtY2xhaW0gb3IgY291bnRl
+cmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICBvciBhIENvbnRy
+aWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAog
+ICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxp
+Y2Vuc2VzCiAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3Jr
+IHNoYWxsIHRlcm1pbmF0ZQogICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmls
+ZWQuCgo0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUg
+Y29waWVzIG9mIHRoZQogICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkg
+bWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv
+ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgbWVldCB0aGUgZm9sbG93aW5nIGNv
+bmRpdGlvbnM6CgogICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0
+aGUgV29yayBvcgogICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNl
+OyBhbmQKCiAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2Fycnkg
+cHJvbWluZW50IG5vdGljZXMKICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmls
+ZXM7IGFuZAoKICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFu
+eSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJp
+Z2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZy
+b20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgZXhjbHVkaW5nIHRob3NlIG5v
+dGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgdGhlIERlcml2
+YXRpdmUgV29ya3M7IGFuZAoKICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIg
+dGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERl
+cml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICBpbmNsdWRlIGEg
+cmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAg
+IHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRv
+IG5vdAogICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrcywg
+aW4gYXQgbGVhc3Qgb25lCiAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEg
+Tk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZh
+dGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgZG9jdW1lbnRhdGlv
+biwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAg
+ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg
+YW5kCiAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBw
+ZWFyLiBUaGUgY29udGVudHMKICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9y
+bWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vu
+c2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICBub3RpY2VzIHdpdGhp
+biBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAg
+b3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3Zp
+ZGVkCiAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5v
+dCBiZSBjb25zdHJ1ZWQKICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgIFlvdSBt
+YXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25z
+IGFuZAogICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1z
+IGFuZCBjb25kaXRpb25zCiAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9u
+IG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29y
+a3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgIHJlcHJvZHVjdGlvbiwgYW5kIGRp
+c3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICB0aGUgY29u
+ZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKNS4gU3VibWlzc2lvbiBvZiBDb250cmli
+dXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICBhbnkgQ29u
+dHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdv
+cmsKICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5k
+IGNvbmRpdGlvbnMgb2YKICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRl
+cm1zIG9yIGNvbmRpdGlvbnMuCiAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcg
+aGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh
+cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgd2l0aCBMaWNl
+bnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKNi4gVHJhZGVtYXJrcy4gVGhpcyBM
+aWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICBuYW1l
+cywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGlj
+ZW5zb3IsCiAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5
+IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVj
+aW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCjcuIERpc2NsYWltZXIgb2YgV2Fy
+cmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICBhZ3JlZWQgdG8g
+aW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgIENvbnRy
+aWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAog
+ICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4
+cHJlc3Mgb3IKICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3
+YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1F
+UkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlv
+dSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgYXBwcm9wcmlh
+dGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55
+CiAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVu
+ZGVyIHRoaXMgTGljZW5zZS4KCjguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVu
+dCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGlu
+ZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgdW5sZXNzIHJlcXVpcmVk
+IGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgbmVn
+bGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0
+b3IgYmUKICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs
+IGluZGlyZWN0LCBzcGVjaWFsLAogICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFn
+ZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgcmVzdWx0IG9mIHRoaXMgTGljZW5z
+ZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICBXb3JrIChpbmNs
+dWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAg
+IHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBh
+bmQgYWxsCiAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1
+Y2ggQ29udHJpYnV0b3IKICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Yg
+c3VjaCBkYW1hZ2VzLgoKOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmls
+aXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtz
+IHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICBhbmQgY2hhcmdlIGEgZmVlIGZv
+ciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICBvciBvdGhl
+ciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhp
+cwogICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91
+IG1heSBhY3Qgb25seQogICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNw
+b25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFu
+ZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgIGRlZmVuZCwgYW5kIGhvbGQgZWFj
+aCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICBpbmN1cnJlZCBieSwg
+b3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAg
+IG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmls
+aXR5LgoKRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgpBUFBFTkRJWDogSG93IHRvIGFwcGx5
+IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICBUbyBhcHBseSB0aGUgQXBhY2hl
+IExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICBib2lsZXJwbGF0
+ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgIHJl
+cGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNs
+dWRlCiAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhl
+IGFwcHJvcHJpYXRlCiAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFs
+c28gcmVjb21tZW5kIHRoYXQgYQogICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9u
+IG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMg
+dGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICBpZGVudGlmaWNhdGlvbiB3aXRoaW4g
+dGhpcmQtcGFydHkgYXJjaGl2ZXMuCgpDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdo
+dCBvd25lcl0KCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAg
+KHRoZSAiTGljZW5zZSIpOwp5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21w
+bGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGlj
+ZW5zZSBhdAoKCWh0dHBzOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKClVu
+bGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywg
+c29mdHdhcmUKZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24g
+YW4gIkFTIElTIiBCQVNJUywKV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5Z
+IEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuClNlZSB0aGUgTGljZW5zZSBmb3IgdGhl
+IHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKbGltaXRhdGlvbnMg
+dW5kZXIgdGhlIExpY2Vuc2UuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64
new file mode 100644
index 000000000..e731812cd
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDIwLTIwMjUgVGhlIFJ1c3RDcnlwdG8gUHJvamVjdCBEZXZlbG9wZXJz
+CgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBl
+cnNvbiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9j
+dW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2Fy
+ZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSBy
+aWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBz
+dWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVy
+bWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBz
+dWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQg
+bm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFs
+bCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNP
+RlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQs
+IEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FS
+UkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQ
+T1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9S
+IENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9U
+SEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1Ig
+T1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhF
+IFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64
new file mode 100644
index 000000000..af13c8e66
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64
@@ -0,0 +1,13 @@
+Q29weXJpZ2h0IMKpIDIwMTUsIFNpbW9uYXMgS2F6bGF1c2thcwoKUGVybWlzc2lvbiB0byB1c2Us
+IGNvcHksIG1vZGlmeSwgYW5kL29yIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBmb3IgYW55IHB1
+cnBvc2Ugd2l0aCBvciB3aXRob3V0CmZlZSBpcyBoZXJlYnkgZ3JhbnRlZCwgcHJvdmlkZWQgdGhh
+dCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBh
+cHBlYXIKaW4gYWxsIGNvcGllcy4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiIEFO
+RCBUSEUgQVVUSE9SIERJU0NMQUlNUyBBTEwgV0FSUkFOVElFUyBXSVRIIFJFR0FSRCBUTyBUSElT
+ClNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJ
+TElUWSBBTkQgRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUiBCRSBMSUFCTEUg
+Rk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsIElORElSRUNULCBPUiBDT05TRVFVRU5USUFMIERBTUFH
+RVMgT1IgQU5ZIERBTUFHRVMKV0hBVFNPRVZFUiBSRVNVTFRJTkcgRlJPTSBMT1NTIE9GIFVTRSwg
+REFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwKTkVHTElH
+RU5DRSBPUiBPVEhFUiBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5F
+Q1RJT04gV0lUSCBUSEUgVVNFIE9SIFBFUkZPUk1BTkNFIE9GClRISVMgU09GVFdBUkUuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64
new file mode 100644
index 000000000..7d7e9de8a
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64
@@ -0,0 +1,20 @@
+Q29weXJpZ2h0IChjKSAyMDA2LTIwMDkgR3JheWRvbiBIb2FyZQpDb3B5cmlnaHQgKGMpIDIwMDkt
+MjAxMyBNb3ppbGxhIEZvdW5kYXRpb24KQ29weXJpZ2h0IChjKSAyMDE2IEFydHlvbSBQYXZsb3YK
+ClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVy
+c29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1
+bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJl
+IHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJp
+Z2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1
+YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJt
+aXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1
+YmplY3QgdG8gdGhlIGZvbGxvd2luZwpjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBu
+b3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxs
+IGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09G
+VFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwg
+RVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJS
+QU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBP
+U0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1Ig
+Q09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RI
+RVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBP
+VEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUg
+U09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64
new file mode 100644
index 000000000..bd0f672a5
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64
@@ -0,0 +1,20 @@
+VGhlIE1JVCBMaWNlbnNlIChNSVQpDQoNCkNvcHlyaWdodCAoYykgMjAxNSBCYXJ0xYJvbWllaiBL
+YW1pxYRza2kNCg0KUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2Us
+IHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weQ0Kb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNz
+b2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwNCmlu
+IHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1p
+dGF0aW9uIHRoZSByaWdodHMNCnRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwg
+ZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwNCmNvcGllcyBvZiB0aGUgU29mdHdh
+cmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcw0KZnVybmlz
+aGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoNCg0KVGhl
+IGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwg
+YmUgaW5jbHVkZWQgaW4gYWxsDQpjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhl
+IFNvZnR3YXJlLg0KDQpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBX
+QVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUg0KSU1QTElFRCwgSU5DTFVESU5HIEJVVCBO
+T1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksDQpGSVRORVNT
+IEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVO
+VCBTSEFMTCBUSEUNCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBB
+TlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVINCkxJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJ
+T04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sDQpPVVQgT0Yg
+T1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERF
+QUxJTkdTIElOIFRIRQ0KU09GVFdBUkUu
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08.base64
new file mode 100644
index 000000000..91020bb09
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08.base64
@@ -0,0 +1,200 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAg
+ICAgICAgICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgogICBURVJNUyBBTkQg
+Q09ORElUSU9OUyBGT1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCiAgIDEu
+IERlZmluaXRpb25zLgoKICAgICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBj
+b25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwKICAgICAgYW5kIGRpc3RyaWJ1dGlvbiBh
+cyBkZWZpbmVkIGJ5IFNlY3Rpb25zIDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAg
+ICAiTGljZW5zb3IiIHNoYWxsIG1lYW4gdGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0
+aG9yaXplZCBieQogICAgICB0aGUgY29weXJpZ2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhl
+IExpY2Vuc2UuCgogICAgICAiTGVnYWwgRW50aXR5IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0
+aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgICAgIG90aGVyIGVudGl0aWVzIHRoYXQgY29udHJv
+bCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRlciBjb21tb24KICAgICAgY29udHJvbCB3
+aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwKICAg
+ICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVjdCBvciBpbmRpcmVjdCwgdG8g
+Y2F1c2UgdGhlCiAgICAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9mIHN1Y2ggZW50aXR5LCB3
+aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgICAgIG90aGVyd2lzZSwgb3IgKGlpKSBvd25lcnNoaXAg
+b2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICAgICBvdXRzdGFuZGluZyBz
+aGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50aXR5LgoKICAg
+ICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExlZ2FsIEVu
+dGl0eQogICAgICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNlbnNl
+LgoKICAgICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgICAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8g
+c29mdHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgICAgc291cmNlLCBhbmQgY29u
+ZmlndXJhdGlvbiBmaWxlcy4KCiAgICAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9y
+bSByZXN1bHRpbmcgZnJvbSBtZWNoYW5pY2FsCiAgICAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5z
+bGF0aW9uIG9mIGEgU291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgICAgbm90IGxpbWl0ZWQg
+dG8gY29tcGlsZWQgb2JqZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICAgICBh
+bmQgY29udmVyc2lvbnMgdG8gb3RoZXIgbWVkaWEgdHlwZXMuCgogICAgICAiV29yayIgc2hhbGwg
+bWVhbiB0aGUgd29yayBvZiBhdXRob3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICAgICBP
+YmplY3QgZm9ybSwgbWFkZSBhdmFpbGFibGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRl
+ZCBieSBhCiAgICAgIGNvcHlyaWdodCBub3RpY2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRh
+Y2hlZCB0byB0aGUgd29yawogICAgICAoYW4gZXhhbXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBw
+ZW5kaXggYmVsb3cpLgoKICAgICAgIkRlcml2YXRpdmUgV29ya3MiIHNoYWxsIG1lYW4gYW55IHdv
+cmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAogICAgICBmb3JtLCB0aGF0IGlzIGJhc2Vk
+IG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBmb3Igd2hpY2ggdGhlCiAgICAgIGVk
+aXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3JhdGlvbnMsIG9yIG90aGVyIG1v
+ZGlmaWNhdGlvbnMKICAgICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBhbiBvcmlnaW5hbCB3b3Jr
+IG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgICAgb2YgdGhpcyBMaWNlbnNlLCBE
+ZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQgcmVtYWluCiAgICAg
+IHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1lKSB0byB0aGUg
+aW50ZXJmYWNlcyBvZiwKICAgICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3MgdGhlcmVv
+Zi4KCiAgICAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9yc2hp
+cCwgaW5jbHVkaW5nCiAgICAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgICAgdG8gdGhhdCBXb3JrIG9yIERlcml2
+YXRpdmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgICAgIHN1Ym1pdHRl
+ZCB0byBMaWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQg
+b3duZXIKICAgICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXpl
+ZCB0byBzdWJtaXQgb24gYmVoYWxmIG9mCiAgICAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0
+aGUgcHVycG9zZXMgb2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICAgICBtZWFucyBh
+bnkgZm9ybSBvZiBlbGVjdHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBz
+ZW50CiAgICAgIHRvIHRoZSBMaWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRp
+bmcgYnV0IG5vdCBsaW1pdGVkIHRvCiAgICAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBt
+YWlsaW5nIGxpc3RzLCBzb3VyY2UgY29kZSBjb250cm9sIHN5c3RlbXMsCiAgICAgIGFuZCBpc3N1
+ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQgYXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwg
+dGhlCiAgICAgIExpY2Vuc29yIGZvciB0aGUgcHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXBy
+b3ZpbmcgdGhlIFdvcmssIGJ1dAogICAgICBleGNsdWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlz
+IGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVyd2lzZQogICAgICBkZXNpZ25hdGVkIGluIHdy
+aXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAiTm90IGEgQ29udHJpYnV0aW9uLiIKCiAg
+ICAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNvciBhbmQgYW55IGluZGl2aWR1YWwg
+b3IgTGVnYWwgRW50aXR5CiAgICAgIG9uIGJlaGFsZiBvZiB3aG9tIGEgQ29udHJpYnV0aW9uIGhh
+cyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICAgICBzdWJzZXF1ZW50bHkgaW5jb3Jw
+b3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCiAgIDIuIEdyYW50IG9mIENvcHlyaWdodCBMaWNlbnNl
+LiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICAgICB0aGlzIExpY2Vu
+c2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsCiAg
+ICAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGly
+cmV2b2NhYmxlCiAgICAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFyZSBE
+ZXJpdmF0aXZlIFdvcmtzIG9mLAogICAgICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgICAgV29yayBhbmQgc3VjaCBE
+ZXJpdmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCiAgIDMuIEdyYW50IG9m
+IFBhdGVudCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgog
+ICAgICB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3Ug
+YSBwZXJwZXR1YWwsCiAgICAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCBy
+b3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlCiAgICAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMg
+c2VjdGlvbikgcGF0ZW50IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICAgICB1c2UsIG9m
+ZmVyIHRvIHNlbGwsIHNlbGwsIGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29y
+aywKICAgICAgd2hlcmUgc3VjaCBsaWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQg
+Y2xhaW1zIGxpY2Vuc2FibGUKICAgICAgYnkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNl
+c3NhcmlseSBpbmZyaW5nZWQgYnkgdGhlaXIKICAgICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9y
+IGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENvbnRyaWJ1dGlvbihzKQogICAgICB3aXRoIHRoZSBX
+b3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9uKHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQog
+ICAgICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24gYWdhaW5zdCBhbnkgZW50aXR5IChpbmNs
+dWRpbmcgYQogICAgICBjcm9zcy1jbGFpbSBvciBjb3VudGVyY2xhaW0gaW4gYSBsYXdzdWl0KSBh
+bGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgICAgIG9yIGEgQ29udHJpYnV0aW9uIGluY29ycG9yYXRl
+ZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAgICAgIG9yIGNvbnRyaWJ1dG9y
+eSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGljZW5zZXMKICAgICAgZ3Jh
+bnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsgc2hhbGwgdGVybWlu
+YXRlCiAgICAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxlZC4KCiAgIDQu
+IFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBjb3BpZXMg
+b2YgdGhlCiAgICAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBtZWRp
+dW0sIHdpdGggb3Igd2l0aG91dAogICAgICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICAgICBtZWV0IHRoZSBmb2xsb3dpbmcg
+Y29uZGl0aW9uczoKCiAgICAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRz
+IG9mIHRoZSBXb3JrIG9yCiAgICAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlz
+IExpY2Vuc2U7IGFuZAoKICAgICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxl
+cyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcwogICAgICAgICAgc3RhdGluZyB0aGF0IFlvdSBj
+aGFuZ2VkIHRoZSBmaWxlczsgYW5kCgogICAgICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUg
+U291cmNlIGZvcm0gb2YgYW55IERlcml2YXRpdmUgV29ya3MKICAgICAgICAgIHRoYXQgWW91IGRp
+c3RyaWJ1dGUsIGFsbCBjb3B5cmlnaHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgICAg
+IGF0dHJpYnV0aW9uIG5vdGljZXMgZnJvbSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAg
+ICAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFu
+eSBwYXJ0IG9mCiAgICAgICAgICB0aGUgRGVyaXZhdGl2ZSBXb3JrczsgYW5kCgogICAgICAoZCkg
+SWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMK
+ICAgICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlv
+dSBkaXN0cmlidXRlIG11c3QKICAgICAgICAgIGluY2x1ZGUgYSByZWFkYWJsZSBjb3B5IG9mIHRo
+ZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAgICAgd2l0aGluIHN1Y2ggTk9U
+SUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8gbm90CiAgICAgICAgICBw
+ZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpbiBhdCBsZWFzdCBv
+bmUKICAgICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBOT1RJQ0UgdGV4
+dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdv
+cmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICAgICBkb2N1bWVudGF0aW9uLCBp
+ZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBh
+cHBlYXIuIFRoZSBjb250ZW50cwogICAgICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3Ig
+aW5mb3JtYXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgICAgZG8gbm90IG1vZGlmeSB0
+aGUgTGljZW5zZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgICAgIG5v
+dGljZXMgd2l0aGluIERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdz
+aWRlCiAgICAgICAgICBvciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0
+aGUgV29yaywgcHJvdmlkZWQKICAgICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0
+aW9uIG5vdGljZXMgY2Fubm90IGJlIGNvbnN0cnVlZAogICAgICAgICAgYXMgbW9kaWZ5aW5nIHRo
+ZSBMaWNlbnNlLgoKICAgICAgWW91IG1heSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVu
+dCB0byBZb3VyIG1vZGlmaWNhdGlvbnMgYW5kCiAgICAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwg
+b3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMgYW5kIGNvbmRpdGlvbnMKICAgICAgZm9yIHVzZSwg
+cmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24gb2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgog
+ICAgICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBhcyBhIHdob2xlLCBwcm92aWRlZCBZ
+b3VyIHVzZSwKICAgICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlzdHJpYnV0aW9uIG9mIHRoZSBXb3Jr
+IG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgICAgIHRoZSBjb25kaXRpb25zIHN0YXRlZCBpbiB0
+aGlzIExpY2Vuc2UuCgogICA1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1dGlvbnMuIFVubGVzcyBZ
+b3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgICAgIGFueSBDb250cmlidXRpb24gaW50
+ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yawogICAgICBieSBZ
+b3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9u
+cyBvZgogICAgICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVybXMgb3Ig
+Y29uZGl0aW9ucy4KICAgICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBoZXJl
+aW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICAgICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICAgICB3aXRoIExp
+Y2Vuc29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgogICA2LiBUcmFkZW1hcmtzLiBU
+aGlzIExpY2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAg
+ICAgIG5hbWVzLCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9m
+IHRoZSBMaWNlbnNvciwKICAgICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFu
+ZCBjdXN0b21hcnkgdXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgICAgIG9yaWdpbiBvZiB0aGUgV29y
+ayBhbmQgcmVwcm9kdWNpbmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKICAgNy4g
+RGlzY2xhaW1lciBvZiBXYXJyYW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3
+IG9yCiAgICAgIGFncmVlZCB0byBpbiB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29y
+ayAoYW5kIGVhY2gKICAgICAgQ29udHJpYnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMp
+IG9uIGFuICJBUyBJUyIgQkFTSVMsCiAgICAgIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJ
+T05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvcgogICAgICBpbXBsaWVkLCBpbmNsdWRp
+bmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdhcnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICAg
+ICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVSQ0hBTlRBQklMSVRZLCBvciBGSVRORVNT
+IEZPUiBBCiAgICAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91IGFyZSBzb2xlbHkgcmVzcG9uc2li
+bGUgZm9yIGRldGVybWluaW5nIHRoZQogICAgICBhcHByb3ByaWF0ZW5lc3Mgb2YgdXNpbmcgb3Ig
+cmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkKICAgICAgcmlza3MgYXNzb2Np
+YXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5kZXIgdGhpcyBMaWNlbnNl
+LgoKICAgOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50IGFuZCB1bmRlciBu
+byBsZWdhbCB0aGVvcnksCiAgICAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5nIG5lZ2xpZ2Vu
+Y2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICAgICB1bmxlc3MgcmVxdWlyZWQgYnkgYXBw
+bGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICAgICBuZWdsaWdl
+bnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRvciBi
+ZQogICAgICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgICAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFt
+YWdlcyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICAgICByZXN1bHQgb2YgdGhpcyBM
+aWNlbnNlIG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgICAgIFdv
+cmsgKGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29k
+d2lsbCwKICAgICAgd29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlv
+biwgb3IgYW55IGFuZCBhbGwKICAgICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3Nl
+cyksIGV2ZW4gaWYgc3VjaCBDb250cmlidXRvcgogICAgICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRo
+ZSBwb3NzaWJpbGl0eSBvZiBzdWNoIGRhbWFnZXMuCgogICA5LiBBY2NlcHRpbmcgV2FycmFudHkg
+b3IgQWRkaXRpb25hbCBMaWFiaWxpdHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgICAgIHRoZSBX
+b3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIs
+CiAgICAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9yLCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJh
+bnR5LCBpbmRlbW5pdHksCiAgICAgIG9yIG90aGVyIGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQv
+b3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlzCiAgICAgIExpY2Vuc2UuIEhvd2V2ZXIsIGlu
+IGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3UgbWF5IGFjdCBvbmx5CiAgICAgIG9uIFlv
+dXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3BvbnNpYmlsaXR5LCBub3Qgb24gYmVo
+YWxmCiAgICAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5kIG9ubHkgaWYgWW91IGFncmVl
+IHRvIGluZGVtbmlmeSwKICAgICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNoIENvbnRyaWJ1dG9yIGhh
+cm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgICAgIGluY3VycmVkIGJ5LCBvciBjbGFpbXMgYXNz
+ZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAgICAgb2YgeW91ciBh
+Y2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxpdHkuCgogICBF
+TkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCiAgIEFQUEVORElYOiBIb3cgdG8gYXBwbHkgdGhl
+IEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgICAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgICAgIGJvaWxlcnBs
+YXRlIG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJ7fSIKICAg
+ICAgcmVwbGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0
+IGluY2x1ZGUKICAgICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3Nl
+ZCBpbiB0aGUgYXBwcm9wcmlhdGUKICAgICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZv
+cm1hdC4gV2UgYWxzbyByZWNvbW1lbmQgdGhhdCBhCiAgICAgIGZpbGUgb3IgY2xhc3MgbmFtZSBh
+bmQgZGVzY3JpcHRpb24gb2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgICAgc2FtZSAi
+cHJpbnRlZCBwYWdlIiBhcyB0aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgICAgIGlk
+ZW50aWZpY2F0aW9uIHdpdGhpbiB0aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCiAgIENvcHlyaWdodCB7
+eXl5eX0ge25hbWUgb2YgY29weXJpZ2h0IG93bmVyfQoKICAgTGljZW5zZWQgdW5kZXIgdGhlIEFw
+YWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiAgIHlvdSBtYXkgbm90
+IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICAg
+WW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CgogICAgICAgaHR0cDovL3d3
+dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgogICBVbmxlc3MgcmVxdWlyZWQgYnkg
+YXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAgIGRpc3Ry
+aWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFT
+SVMsCiAgIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRo
+ZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogICBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZp
+YyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAgIGxpbWl0YXRpb25zIHVuZGVy
+IHRoZSBMaWNlbnNlLgoK
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/c962ee4d1d05ddc138b202b2540219ebc57893fcf97b364852094a9a94ce1365.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/c962ee4d1d05ddc138b202b2540219ebc57893fcf97b364852094a9a94ce1365.base64
new file mode 100644
index 000000000..b13a05a12
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/c962ee4d1d05ddc138b202b2540219ebc57893fcf97b364852094a9a94ce1365.base64
@@ -0,0 +1,5 @@
+Q29weXJpZ2h0IDIwMTItMjAxNiBUaGUgUnVzdCBQcm9qZWN0IERldmVsb3BlcnMuCkNvcHlyaWdo
+dCAyMDE2LTIwMjYgRnJhbmsgRGVuaXMuCgpMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vu
+c2UsIFZlcnNpb24gMi4wIDxMSUNFTlNFLUFQQUNIRSBvcgpodHRwOi8vd3d3LmFwYWNoZS5vcmcv
+bGljZW5zZXMvTElDRU5TRS0yLjA+IG9yIHRoZSBNSVQgbGljZW5zZQo8TElDRU5TRS1NSVQgb3Ig
+aHR0cDovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL01JVD4sIGF0IHlvdXIKb3B0aW9uLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/cb5aedb296c5246d1f22e9099f925a65146f9f0d6b4eebba97fd27a6cdbbab2d.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/cb5aedb296c5246d1f22e9099f925a65146f9f0d6b4eebba97fd27a6cdbbab2d.base64
new file mode 100644
index 000000000..2c3f9d851
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/cb5aedb296c5246d1f22e9099f925a65146f9f0d6b4eebba97fd27a6cdbbab2d.base64
@@ -0,0 +1,18 @@
+UGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJz
+b24gb2J0YWluaW5nCmEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3Vt
+ZW50YXRpb24gZmlsZXMgKHRoZQoiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUg
+d2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nCndpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmln
+aHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwKZGlzdHJpYnV0ZSwgc3Vi
+bGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvCnBlcm1p
+dCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3Vi
+amVjdCB0bwp0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5v
+dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZQppbmNsdWRlZCBpbiBhbGwg
+Y29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZU
+V0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELApF
+WFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJB
+TlRJRVMgT0YKTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9T
+RSBBTkQKTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBD
+T1BZUklHSFQgSE9MREVSUyBCRQpMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhF
+UiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9U
+SEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTgpXSVRIIFRIRSBT
+T0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30.base64
new file mode 100644
index 000000000..95c577e82
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30.base64
@@ -0,0 +1,200 @@
+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAg
+ICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAg
+ICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5E
+IENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAx
+LiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24g
+YXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAg
+ICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1
+dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRo
+ZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2Yg
+dGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRy
+b2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wg
+d2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAg
+ICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRv
+IGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwg
+d2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlw
+IG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcg
+c2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAg
+ICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBF
+bnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5z
+ZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y
+IG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRv
+IHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNv
+bmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZv
+cm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFu
+c2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVk
+IHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAg
+YW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxs
+IG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAg
+T2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0
+ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0
+YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFw
+cGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3
+b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNl
+ZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBl
+ZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBt
+b2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29y
+ayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwg
+RGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAg
+ICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhl
+IGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJl
+b2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNo
+aXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg
+YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJp
+dmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0
+ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0
+IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6
+ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3Ig
+dGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMg
+YW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24g
+c2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVk
+aW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMg
+bWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNz
+dWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2Ys
+IHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1w
+cm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBp
+cyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3
+cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgog
+ICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFs
+IG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBo
+YXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29y
+cG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5z
+ZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNl
+bnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAog
+ICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBp
+cnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUg
+RGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy
+Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2gg
+RGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBv
+ZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YK
+ICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91
+IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwg
+cm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlz
+IHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBv
+ZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdv
+cmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50
+IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVj
+ZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBv
+ciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUg
+V29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UK
+ICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5j
+bHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkg
+YWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0
+ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRv
+cnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdy
+YW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1p
+bmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0
+LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVz
+IG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVk
+aXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv
+ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5n
+IGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50
+cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhp
+cyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmls
+ZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3Ug
+Y2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhl
+IFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBk
+aXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAg
+ICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAog
+ICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBh
+bnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQp
+IElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRz
+CiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZ
+b3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0
+aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5P
+VElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAg
+cGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qg
+b25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRl
+eHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBX
+b3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwg
+aWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAg
+ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg
+YW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkg
+YXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9y
+IGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkg
+dGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBu
+b3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25n
+c2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20g
+dGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1
+dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0
+aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1l
+bnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFs
+IG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IK
+ICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQg
+WW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29y
+ayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4g
+dGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3Mg
+WW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGlu
+dGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkg
+WW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlv
+bnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9y
+IGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVy
+ZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh
+cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBM
+aWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4g
+VGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQog
+ICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBv
+ZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBh
+bmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdv
+cmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcu
+IERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxh
+dyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdv
+cmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25z
+KSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElU
+SU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVk
+aW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAg
+ICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVT
+UyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNp
+YmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9y
+IHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29j
+aWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5z
+ZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIg
+bm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdl
+bmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFw
+cGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGln
+ZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3Ig
+YmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs
+IGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRh
+bWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMg
+TGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBX
+b3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29v
+ZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rp
+b24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3Nz
+ZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0
+aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5
+IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUg
+V29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVy
+LAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJy
+YW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5k
+L29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBp
+biBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZ
+b3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJl
+aGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3Jl
+ZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBo
+YXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFz
+c2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIg
+YWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAg
+RU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRo
+ZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hl
+IExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJw
+bGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAg
+ICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24n
+dCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9z
+ZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBm
+b3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUg
+YW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUg
+InByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBp
+ZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQg
+W3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBB
+cGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5v
+dCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAg
+IFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93
+d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5
+IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0
+cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJB
+U0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0
+aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lm
+aWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRl
+ciB0aGUgTGljZW5zZS4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64
new file mode 100644
index 000000000..bfc309f00
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE4LTIwMTkgVGhlIFJ1c3RDcnlwdG8gUHJvamVjdCBEZXZlbG9wZXJz
+CgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBl
+cnNvbiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9j
+dW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2Fy
+ZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSBy
+aWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBz
+dWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVy
+bWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBz
+dWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQg
+bm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFs
+bCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNP
+RlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQs
+IEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FS
+UkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQ
+T1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9S
+IENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9U
+SEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1Ig
+T1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhF
+IFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64
new file mode 100644
index 000000000..5eb6ec8ad
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64
@@ -0,0 +1 @@
+TUlUIE9SIEFwYWNoZS0yLjA=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/ea084a2373ebc1f0902c09266e7bf25a05ab3814c1805bb017ffa7308f90c061.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/ea084a2373ebc1f0902c09266e7bf25a05ab3814c1805bb017ffa7308f90c061.base64
new file mode 100644
index 000000000..338863513
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/ea084a2373ebc1f0902c09266e7bf25a05ab3814c1805bb017ffa7308f90c061.base64
@@ -0,0 +1,19 @@
+TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAxNyBOaWtvbGFpIFZhenF1ZXoKClBlcm1pc3Np
+b24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFp
+bmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9u
+IGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQg
+cmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1
+c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2Us
+IGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29u
+cyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8g
+dGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5k
+IHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBv
+ciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMg
+UFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBP
+UgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9G
+IE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5P
+TklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hU
+IEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklM
+SVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0Us
+IEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUg
+T1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055.base64
new file mode 100644
index 000000000..187325692
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE2LS0yMDE3CgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBm
+cmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRoaXMgc29m
+dHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIp
+LCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcg
+d2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdl
+LApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YK
+dGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUK
+aXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcKY29uZGl0aW9u
+czoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNl
+CnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMK
+b2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhP
+VVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIEJV
+VCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5F
+U1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVW
+RU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1Ig
+QU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJ
+T04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBP
+UgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIKREVB
+TElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64
new file mode 100644
index 000000000..817bcfcf1
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64
@@ -0,0 +1,35 @@
+VU5JQ09ERSBMSUNFTlNFIFYzCgpDT1BZUklHSFQgQU5EIFBFUk1JU1NJT04gTk9USUNFCgpDb3B5
+cmlnaHQgwqkgMTk5MS0yMDIzIFVuaWNvZGUsIEluYy4KCk5PVElDRSBUTyBVU0VSOiBDYXJlZnVs
+bHkgcmVhZCB0aGUgZm9sbG93aW5nIGxlZ2FsIGFncmVlbWVudC4gQlkKRE9XTkxPQURJTkcsIElO
+U1RBTExJTkcsIENPUFlJTkcgT1IgT1RIRVJXSVNFIFVTSU5HIERBVEEgRklMRVMsIEFORC9PUgpT
+T0ZUV0FSRSwgWU9VIFVORVFVSVZPQ0FMTFkgQUNDRVBULCBBTkQgQUdSRUUgVE8gQkUgQk9VTkQg
+QlksIEFMTCBPRiBUSEUKVEVSTVMgQU5EIENPTkRJVElPTlMgT0YgVEhJUyBBR1JFRU1FTlQuIElG
+IFlPVSBETyBOT1QgQUdSRUUsIERPIE5PVApET1dOTE9BRCwgSU5TVEFMTCwgQ09QWSwgRElTVFJJ
+QlVURSBPUiBVU0UgVEhFIERBVEEgRklMRVMgT1IgU09GVFdBUkUuCgpQZXJtaXNzaW9uIGlzIGhl
+cmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYQpj
+b3B5IG9mIGRhdGEgZmlsZXMgYW5kIGFueSBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gKHRoZSAi
+RGF0YSBGaWxlcyIpIG9yCnNvZnR3YXJlIGFuZCBhbnkgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9u
+ICh0aGUgIlNvZnR3YXJlIikgdG8gZGVhbCBpbiB0aGUKRGF0YSBGaWxlcyBvciBTb2Z0d2FyZSB3
+aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uCnRoZSByaWdo
+dHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBhbmQv
+b3Igc2VsbApjb3BpZXMgb2YgdGhlIERhdGEgRmlsZXMgb3IgU29mdHdhcmUsIGFuZCB0byBwZXJt
+aXQgcGVyc29ucyB0byB3aG9tIHRoZQpEYXRhIEZpbGVzIG9yIFNvZnR3YXJlIGFyZSBmdXJuaXNo
+ZWQgdG8gZG8gc28sIHByb3ZpZGVkIHRoYXQgZWl0aGVyIChhKQp0aGlzIGNvcHlyaWdodCBhbmQg
+cGVybWlzc2lvbiBub3RpY2UgYXBwZWFyIHdpdGggYWxsIGNvcGllcyBvZiB0aGUgRGF0YQpGaWxl
+cyBvciBTb2Z0d2FyZSwgb3IgKGIpIHRoaXMgY29weXJpZ2h0IGFuZCBwZXJtaXNzaW9uIG5vdGlj
+ZSBhcHBlYXIgaW4KYXNzb2NpYXRlZCBEb2N1bWVudGF0aW9uLgoKVEhFIERBVEEgRklMRVMgQU5E
+IFNPRlRXQVJFIEFSRSBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWQpL
+SU5ELCBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhF
+IFdBUlJBTlRJRVMgT0YKTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIg
+UFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5UIE9GClRISVJEIFBBUlRZIFJJR0hUUy4KCklOIE5P
+IEVWRU5UIFNIQUxMIFRIRSBDT1BZUklHSFQgSE9MREVSIE9SIEhPTERFUlMgSU5DTFVERUQgSU4g
+VEhJUyBOT1RJQ0UKQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIE9SIEFOWSBTUEVDSUFMIElORElS
+RUNUIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUywKT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUiBS
+RVNVTFRJTkcgRlJPTSBMT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLApXSEVUSEVSIElOIEFO
+IEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5DRSBPUiBPVEhFUiBUT1JUSU9VUyBBQ1RJT04s
+CkFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SIFBFUkZPUk1B
+TkNFIE9GIFRIRSBEQVRBCkZJTEVTIE9SIFNPRlRXQVJFLgoKRXhjZXB0IGFzIGNvbnRhaW5lZCBp
+biB0aGlzIG5vdGljZSwgdGhlIG5hbWUgb2YgYSBjb3B5cmlnaHQgaG9sZGVyIHNoYWxsCm5vdCBi
+ZSB1c2VkIGluIGFkdmVydGlzaW5nIG9yIG90aGVyd2lzZSB0byBwcm9tb3RlIHRoZSBzYWxlLCB1
+c2Ugb3Igb3RoZXIKZGVhbGluZ3MgaW4gdGhlc2UgRGF0YSBGaWxlcyBvciBTb2Z0d2FyZSB3aXRo
+b3V0IHByaW9yIHdyaXR0ZW4KYXV0aG9yaXphdGlvbiBvZiB0aGUgY29weXJpZ2h0IGhvbGRlci4K
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505.base64
new file mode 100644
index 000000000..f598c992e
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505.base64
@@ -0,0 +1,318 @@
+ICAgICAgICAgICAgICAgICAgICBHTlUgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAgICAgICAg
+ICAgICAgICAgICAgIFZlcnNpb24gMiwgSnVuZSAxOTkxCgogQ29weXJpZ2h0IChDKSAxOTg5LCAx
+OTkxIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiwKIDUxIEZyYW5rbGluIFN0cmVldCwg
+RmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgMDIxMTAtMTMwMSBVU0EKIEV2ZXJ5b25lIGlzIHBlcm1p
+dHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNvcGllcwogb2YgdGhpcyBsaWNl
+bnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFsbG93ZWQuCgogICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgUHJlYW1ibGUKCiAgVGhlIGxpY2Vuc2VzIGZvciBtb3N0IHNvZnR3
+YXJlIGFyZSBkZXNpZ25lZCB0byB0YWtlIGF3YXkgeW91cgpmcmVlZG9tIHRvIHNoYXJlIGFuZCBj
+aGFuZ2UgaXQuICBCeSBjb250cmFzdCwgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYwpMaWNlbnNlIGlz
+IGludGVuZGVkIHRvIGd1YXJhbnRlZSB5b3VyIGZyZWVkb20gdG8gc2hhcmUgYW5kIGNoYW5nZSBm
+cmVlCnNvZnR3YXJlLS10byBtYWtlIHN1cmUgdGhlIHNvZnR3YXJlIGlzIGZyZWUgZm9yIGFsbCBp
+dHMgdXNlcnMuICBUaGlzCkdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXBwbGllcyB0byBtb3N0IG9m
+IHRoZSBGcmVlIFNvZnR3YXJlCkZvdW5kYXRpb24ncyBzb2Z0d2FyZSBhbmQgdG8gYW55IG90aGVy
+IHByb2dyYW0gd2hvc2UgYXV0aG9ycyBjb21taXQgdG8KdXNpbmcgaXQuICAoU29tZSBvdGhlciBG
+cmVlIFNvZnR3YXJlIEZvdW5kYXRpb24gc29mdHdhcmUgaXMgY292ZXJlZCBieQp0aGUgR05VIExl
+c3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGluc3RlYWQuKSAgWW91IGNhbiBhcHBseSBpdCB0
+bwp5b3VyIHByb2dyYW1zLCB0b28uCgogIFdoZW4gd2Ugc3BlYWsgb2YgZnJlZSBzb2Z0d2FyZSwg
+d2UgYXJlIHJlZmVycmluZyB0byBmcmVlZG9tLCBub3QKcHJpY2UuICBPdXIgR2VuZXJhbCBQdWJs
+aWMgTGljZW5zZXMgYXJlIGRlc2lnbmVkIHRvIG1ha2Ugc3VyZSB0aGF0IHlvdQpoYXZlIHRoZSBm
+cmVlZG9tIHRvIGRpc3RyaWJ1dGUgY29waWVzIG9mIGZyZWUgc29mdHdhcmUgKGFuZCBjaGFyZ2Ug
+Zm9yCnRoaXMgc2VydmljZSBpZiB5b3Ugd2lzaCksIHRoYXQgeW91IHJlY2VpdmUgc291cmNlIGNv
+ZGUgb3IgY2FuIGdldCBpdAppZiB5b3Ugd2FudCBpdCwgdGhhdCB5b3UgY2FuIGNoYW5nZSB0aGUg
+c29mdHdhcmUgb3IgdXNlIHBpZWNlcyBvZiBpdAppbiBuZXcgZnJlZSBwcm9ncmFtczsgYW5kIHRo
+YXQgeW91IGtub3cgeW91IGNhbiBkbyB0aGVzZSB0aGluZ3MuCgogIFRvIHByb3RlY3QgeW91ciBy
+aWdodHMsIHdlIG5lZWQgdG8gbWFrZSByZXN0cmljdGlvbnMgdGhhdCBmb3JiaWQKYW55b25lIHRv
+IGRlbnkgeW91IHRoZXNlIHJpZ2h0cyBvciB0byBhc2sgeW91IHRvIHN1cnJlbmRlciB0aGUgcmln
+aHRzLgpUaGVzZSByZXN0cmljdGlvbnMgdHJhbnNsYXRlIHRvIGNlcnRhaW4gcmVzcG9uc2liaWxp
+dGllcyBmb3IgeW91IGlmIHlvdQpkaXN0cmlidXRlIGNvcGllcyBvZiB0aGUgc29mdHdhcmUsIG9y
+IGlmIHlvdSBtb2RpZnkgaXQuCgogIEZvciBleGFtcGxlLCBpZiB5b3UgZGlzdHJpYnV0ZSBjb3Bp
+ZXMgb2Ygc3VjaCBhIHByb2dyYW0sIHdoZXRoZXIKZ3JhdGlzIG9yIGZvciBhIGZlZSwgeW91IG11
+c3QgZ2l2ZSB0aGUgcmVjaXBpZW50cyBhbGwgdGhlIHJpZ2h0cyB0aGF0CnlvdSBoYXZlLiAgWW91
+IG11c3QgbWFrZSBzdXJlIHRoYXQgdGhleSwgdG9vLCByZWNlaXZlIG9yIGNhbiBnZXQgdGhlCnNv
+dXJjZSBjb2RlLiAgQW5kIHlvdSBtdXN0IHNob3cgdGhlbSB0aGVzZSB0ZXJtcyBzbyB0aGV5IGtu
+b3cgdGhlaXIKcmlnaHRzLgoKICBXZSBwcm90ZWN0IHlvdXIgcmlnaHRzIHdpdGggdHdvIHN0ZXBz
+OiAoMSkgY29weXJpZ2h0IHRoZSBzb2Z0d2FyZSwgYW5kCigyKSBvZmZlciB5b3UgdGhpcyBsaWNl
+bnNlIHdoaWNoIGdpdmVzIHlvdSBsZWdhbCBwZXJtaXNzaW9uIHRvIGNvcHksCmRpc3RyaWJ1dGUg
+YW5kL29yIG1vZGlmeSB0aGUgc29mdHdhcmUuCgogIEFsc28sIGZvciBlYWNoIGF1dGhvcidzIHBy
+b3RlY3Rpb24gYW5kIG91cnMsIHdlIHdhbnQgdG8gbWFrZSBjZXJ0YWluCnRoYXQgZXZlcnlvbmUg
+dW5kZXJzdGFuZHMgdGhhdCB0aGVyZSBpcyBubyB3YXJyYW50eSBmb3IgdGhpcyBmcmVlCnNvZnR3
+YXJlLiAgSWYgdGhlIHNvZnR3YXJlIGlzIG1vZGlmaWVkIGJ5IHNvbWVvbmUgZWxzZSBhbmQgcGFz
+c2VkIG9uLCB3ZQp3YW50IGl0cyByZWNpcGllbnRzIHRvIGtub3cgdGhhdCB3aGF0IHRoZXkgaGF2
+ZSBpcyBub3QgdGhlIG9yaWdpbmFsLCBzbwp0aGF0IGFueSBwcm9ibGVtcyBpbnRyb2R1Y2VkIGJ5
+IG90aGVycyB3aWxsIG5vdCByZWZsZWN0IG9uIHRoZSBvcmlnaW5hbAphdXRob3JzJyByZXB1dGF0
+aW9ucy4KCiAgRmluYWxseSwgYW55IGZyZWUgcHJvZ3JhbSBpcyB0aHJlYXRlbmVkIGNvbnN0YW50
+bHkgYnkgc29mdHdhcmUKcGF0ZW50cy4gIFdlIHdpc2ggdG8gYXZvaWQgdGhlIGRhbmdlciB0aGF0
+IHJlZGlzdHJpYnV0b3JzIG9mIGEgZnJlZQpwcm9ncmFtIHdpbGwgaW5kaXZpZHVhbGx5IG9idGFp
+biBwYXRlbnQgbGljZW5zZXMsIGluIGVmZmVjdCBtYWtpbmcgdGhlCnByb2dyYW0gcHJvcHJpZXRh
+cnkuICBUbyBwcmV2ZW50IHRoaXMsIHdlIGhhdmUgbWFkZSBpdCBjbGVhciB0aGF0IGFueQpwYXRl
+bnQgbXVzdCBiZSBsaWNlbnNlZCBmb3IgZXZlcnlvbmUncyBmcmVlIHVzZSBvciBub3QgbGljZW5z
+ZWQgYXQgYWxsLgoKICBUaGUgcHJlY2lzZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgY29weWlu
+ZywgZGlzdHJpYnV0aW9uIGFuZAptb2RpZmljYXRpb24gZm9sbG93LgoKICAgICAgICAgICAgICAg
+ICAgICBHTlUgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICBURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgQ09QWUlORywgRElTVFJJQlVUSU9OIEFORCBNT0RJRklDQVRJT04KCiAgMC4gVGhpcyBMaWNl
+bnNlIGFwcGxpZXMgdG8gYW55IHByb2dyYW0gb3Igb3RoZXIgd29yayB3aGljaCBjb250YWlucwph
+IG5vdGljZSBwbGFjZWQgYnkgdGhlIGNvcHlyaWdodCBob2xkZXIgc2F5aW5nIGl0IG1heSBiZSBk
+aXN0cmlidXRlZAp1bmRlciB0aGUgdGVybXMgb2YgdGhpcyBHZW5lcmFsIFB1YmxpYyBMaWNlbnNl
+LiAgVGhlICJQcm9ncmFtIiwgYmVsb3csCnJlZmVycyB0byBhbnkgc3VjaCBwcm9ncmFtIG9yIHdv
+cmssIGFuZCBhICJ3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtIgptZWFucyBlaXRoZXIgdGhlIFBy
+b2dyYW0gb3IgYW55IGRlcml2YXRpdmUgd29yayB1bmRlciBjb3B5cmlnaHQgbGF3Ogp0aGF0IGlz
+IHRvIHNheSwgYSB3b3JrIGNvbnRhaW5pbmcgdGhlIFByb2dyYW0gb3IgYSBwb3J0aW9uIG9mIGl0
+LAplaXRoZXIgdmVyYmF0aW0gb3Igd2l0aCBtb2RpZmljYXRpb25zIGFuZC9vciB0cmFuc2xhdGVk
+IGludG8gYW5vdGhlcgpsYW5ndWFnZS4gIChIZXJlaW5hZnRlciwgdHJhbnNsYXRpb24gaXMgaW5j
+bHVkZWQgd2l0aG91dCBsaW1pdGF0aW9uIGluCnRoZSB0ZXJtICJtb2RpZmljYXRpb24iLikgIEVh
+Y2ggbGljZW5zZWUgaXMgYWRkcmVzc2VkIGFzICJ5b3UiLgoKQWN0aXZpdGllcyBvdGhlciB0aGFu
+IGNvcHlpbmcsIGRpc3RyaWJ1dGlvbiBhbmQgbW9kaWZpY2F0aW9uIGFyZSBub3QKY292ZXJlZCBi
+eSB0aGlzIExpY2Vuc2U7IHRoZXkgYXJlIG91dHNpZGUgaXRzIHNjb3BlLiAgVGhlIGFjdCBvZgpy
+dW5uaW5nIHRoZSBQcm9ncmFtIGlzIG5vdCByZXN0cmljdGVkLCBhbmQgdGhlIG91dHB1dCBmcm9t
+IHRoZSBQcm9ncmFtCmlzIGNvdmVyZWQgb25seSBpZiBpdHMgY29udGVudHMgY29uc3RpdHV0ZSBh
+IHdvcmsgYmFzZWQgb24gdGhlClByb2dyYW0gKGluZGVwZW5kZW50IG9mIGhhdmluZyBiZWVuIG1h
+ZGUgYnkgcnVubmluZyB0aGUgUHJvZ3JhbSkuCldoZXRoZXIgdGhhdCBpcyB0cnVlIGRlcGVuZHMg
+b24gd2hhdCB0aGUgUHJvZ3JhbSBkb2VzLgoKICAxLiBZb3UgbWF5IGNvcHkgYW5kIGRpc3RyaWJ1
+dGUgdmVyYmF0aW0gY29waWVzIG9mIHRoZSBQcm9ncmFtJ3MKc291cmNlIGNvZGUgYXMgeW91IHJl
+Y2VpdmUgaXQsIGluIGFueSBtZWRpdW0sIHByb3ZpZGVkIHRoYXQgeW91CmNvbnNwaWN1b3VzbHkg
+YW5kIGFwcHJvcHJpYXRlbHkgcHVibGlzaCBvbiBlYWNoIGNvcHkgYW4gYXBwcm9wcmlhdGUKY29w
+eXJpZ2h0IG5vdGljZSBhbmQgZGlzY2xhaW1lciBvZiB3YXJyYW50eTsga2VlcCBpbnRhY3QgYWxs
+IHRoZQpub3RpY2VzIHRoYXQgcmVmZXIgdG8gdGhpcyBMaWNlbnNlIGFuZCB0byB0aGUgYWJzZW5j
+ZSBvZiBhbnkgd2FycmFudHk7CmFuZCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRoZSBQ
+cm9ncmFtIGEgY29weSBvZiB0aGlzIExpY2Vuc2UKYWxvbmcgd2l0aCB0aGUgUHJvZ3JhbS4KCllv
+dSBtYXkgY2hhcmdlIGEgZmVlIGZvciB0aGUgcGh5c2ljYWwgYWN0IG9mIHRyYW5zZmVycmluZyBh
+IGNvcHksIGFuZAp5b3UgbWF5IGF0IHlvdXIgb3B0aW9uIG9mZmVyIHdhcnJhbnR5IHByb3RlY3Rp
+b24gaW4gZXhjaGFuZ2UgZm9yIGEgZmVlLgoKICAyLiBZb3UgbWF5IG1vZGlmeSB5b3VyIGNvcHkg
+b3IgY29waWVzIG9mIHRoZSBQcm9ncmFtIG9yIGFueSBwb3J0aW9uCm9mIGl0LCB0aHVzIGZvcm1p
+bmcgYSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtLCBhbmQgY29weSBhbmQKZGlzdHJpYnV0ZSBz
+dWNoIG1vZGlmaWNhdGlvbnMgb3Igd29yayB1bmRlciB0aGUgdGVybXMgb2YgU2VjdGlvbiAxCmFi
+b3ZlLCBwcm92aWRlZCB0aGF0IHlvdSBhbHNvIG1lZXQgYWxsIG9mIHRoZXNlIGNvbmRpdGlvbnM6
+CgogICAgYSkgWW91IG11c3QgY2F1c2UgdGhlIG1vZGlmaWVkIGZpbGVzIHRvIGNhcnJ5IHByb21p
+bmVudCBub3RpY2VzCiAgICBzdGF0aW5nIHRoYXQgeW91IGNoYW5nZWQgdGhlIGZpbGVzIGFuZCB0
+aGUgZGF0ZSBvZiBhbnkgY2hhbmdlLgoKICAgIGIpIFlvdSBtdXN0IGNhdXNlIGFueSB3b3JrIHRo
+YXQgeW91IGRpc3RyaWJ1dGUgb3IgcHVibGlzaCwgdGhhdCBpbgogICAgd2hvbGUgb3IgaW4gcGFy
+dCBjb250YWlucyBvciBpcyBkZXJpdmVkIGZyb20gdGhlIFByb2dyYW0gb3IgYW55CiAgICBwYXJ0
+IHRoZXJlb2YsIHRvIGJlIGxpY2Vuc2VkIGFzIGEgd2hvbGUgYXQgbm8gY2hhcmdlIHRvIGFsbCB0
+aGlyZAogICAgcGFydGllcyB1bmRlciB0aGUgdGVybXMgb2YgdGhpcyBMaWNlbnNlLgoKICAgIGMp
+IElmIHRoZSBtb2RpZmllZCBwcm9ncmFtIG5vcm1hbGx5IHJlYWRzIGNvbW1hbmRzIGludGVyYWN0
+aXZlbHkKICAgIHdoZW4gcnVuLCB5b3UgbXVzdCBjYXVzZSBpdCwgd2hlbiBzdGFydGVkIHJ1bm5p
+bmcgZm9yIHN1Y2gKICAgIGludGVyYWN0aXZlIHVzZSBpbiB0aGUgbW9zdCBvcmRpbmFyeSB3YXks
+IHRvIHByaW50IG9yIGRpc3BsYXkgYW4KICAgIGFubm91bmNlbWVudCBpbmNsdWRpbmcgYW4gYXBw
+cm9wcmlhdGUgY29weXJpZ2h0IG5vdGljZSBhbmQgYQogICAgbm90aWNlIHRoYXQgdGhlcmUgaXMg
+bm8gd2FycmFudHkgKG9yIGVsc2UsIHNheWluZyB0aGF0IHlvdSBwcm92aWRlCiAgICBhIHdhcnJh
+bnR5KSBhbmQgdGhhdCB1c2VycyBtYXkgcmVkaXN0cmlidXRlIHRoZSBwcm9ncmFtIHVuZGVyCiAg
+ICB0aGVzZSBjb25kaXRpb25zLCBhbmQgdGVsbGluZyB0aGUgdXNlciBob3cgdG8gdmlldyBhIGNv
+cHkgb2YgdGhpcwogICAgTGljZW5zZS4gIChFeGNlcHRpb246IGlmIHRoZSBQcm9ncmFtIGl0c2Vs
+ZiBpcyBpbnRlcmFjdGl2ZSBidXQKICAgIGRvZXMgbm90IG5vcm1hbGx5IHByaW50IHN1Y2ggYW4g
+YW5ub3VuY2VtZW50LCB5b3VyIHdvcmsgYmFzZWQgb24KICAgIHRoZSBQcm9ncmFtIGlzIG5vdCBy
+ZXF1aXJlZCB0byBwcmludCBhbiBhbm5vdW5jZW1lbnQuKQoKVGhlc2UgcmVxdWlyZW1lbnRzIGFw
+cGx5IHRvIHRoZSBtb2RpZmllZCB3b3JrIGFzIGEgd2hvbGUuICBJZgppZGVudGlmaWFibGUgc2Vj
+dGlvbnMgb2YgdGhhdCB3b3JrIGFyZSBub3QgZGVyaXZlZCBmcm9tIHRoZSBQcm9ncmFtLAphbmQg
+Y2FuIGJlIHJlYXNvbmFibHkgY29uc2lkZXJlZCBpbmRlcGVuZGVudCBhbmQgc2VwYXJhdGUgd29y
+a3MgaW4KdGhlbXNlbHZlcywgdGhlbiB0aGlzIExpY2Vuc2UsIGFuZCBpdHMgdGVybXMsIGRvIG5v
+dCBhcHBseSB0byB0aG9zZQpzZWN0aW9ucyB3aGVuIHlvdSBkaXN0cmlidXRlIHRoZW0gYXMgc2Vw
+YXJhdGUgd29ya3MuICBCdXQgd2hlbiB5b3UKZGlzdHJpYnV0ZSB0aGUgc2FtZSBzZWN0aW9ucyBh
+cyBwYXJ0IG9mIGEgd2hvbGUgd2hpY2ggaXMgYSB3b3JrIGJhc2VkCm9uIHRoZSBQcm9ncmFtLCB0
+aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB3aG9sZSBtdXN0IGJlIG9uIHRoZSB0ZXJtcyBvZgp0aGlz
+IExpY2Vuc2UsIHdob3NlIHBlcm1pc3Npb25zIGZvciBvdGhlciBsaWNlbnNlZXMgZXh0ZW5kIHRv
+IHRoZQplbnRpcmUgd2hvbGUsIGFuZCB0aHVzIHRvIGVhY2ggYW5kIGV2ZXJ5IHBhcnQgcmVnYXJk
+bGVzcyBvZiB3aG8gd3JvdGUgaXQuCgpUaHVzLCBpdCBpcyBub3QgdGhlIGludGVudCBvZiB0aGlz
+IHNlY3Rpb24gdG8gY2xhaW0gcmlnaHRzIG9yIGNvbnRlc3QKeW91ciByaWdodHMgdG8gd29yayB3
+cml0dGVuIGVudGlyZWx5IGJ5IHlvdTsgcmF0aGVyLCB0aGUgaW50ZW50IGlzIHRvCmV4ZXJjaXNl
+IHRoZSByaWdodCB0byBjb250cm9sIHRoZSBkaXN0cmlidXRpb24gb2YgZGVyaXZhdGl2ZSBvcgpj
+b2xsZWN0aXZlIHdvcmtzIGJhc2VkIG9uIHRoZSBQcm9ncmFtLgoKSW4gYWRkaXRpb24sIG1lcmUg
+YWdncmVnYXRpb24gb2YgYW5vdGhlciB3b3JrIG5vdCBiYXNlZCBvbiB0aGUgUHJvZ3JhbQp3aXRo
+IHRoZSBQcm9ncmFtIChvciB3aXRoIGEgd29yayBiYXNlZCBvbiB0aGUgUHJvZ3JhbSkgb24gYSB2
+b2x1bWUgb2YKYSBzdG9yYWdlIG9yIGRpc3RyaWJ1dGlvbiBtZWRpdW0gZG9lcyBub3QgYnJpbmcg
+dGhlIG90aGVyIHdvcmsgdW5kZXIKdGhlIHNjb3BlIG9mIHRoaXMgTGljZW5zZS4KCiAgMy4gWW91
+IG1heSBjb3B5IGFuZCBkaXN0cmlidXRlIHRoZSBQcm9ncmFtIChvciBhIHdvcmsgYmFzZWQgb24g
+aXQsCnVuZGVyIFNlY3Rpb24gMikgaW4gb2JqZWN0IGNvZGUgb3IgZXhlY3V0YWJsZSBmb3JtIHVu
+ZGVyIHRoZSB0ZXJtcyBvZgpTZWN0aW9ucyAxIGFuZCAyIGFib3ZlIHByb3ZpZGVkIHRoYXQgeW91
+IGFsc28gZG8gb25lIG9mIHRoZSBmb2xsb3dpbmc6CgogICAgYSkgQWNjb21wYW55IGl0IHdpdGgg
+dGhlIGNvbXBsZXRlIGNvcnJlc3BvbmRpbmcgbWFjaGluZS1yZWFkYWJsZQogICAgc291cmNlIGNv
+ZGUsIHdoaWNoIG11c3QgYmUgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIHRlcm1zIG9mIFNlY3Rpb25z
+CiAgICAxIGFuZCAyIGFib3ZlIG9uIGEgbWVkaXVtIGN1c3RvbWFyaWx5IHVzZWQgZm9yIHNvZnR3
+YXJlIGludGVyY2hhbmdlOyBvciwKCiAgICBiKSBBY2NvbXBhbnkgaXQgd2l0aCBhIHdyaXR0ZW4g
+b2ZmZXIsIHZhbGlkIGZvciBhdCBsZWFzdCB0aHJlZQogICAgeWVhcnMsIHRvIGdpdmUgYW55IHRo
+aXJkIHBhcnR5LCBmb3IgYSBjaGFyZ2Ugbm8gbW9yZSB0aGFuIHlvdXIKICAgIGNvc3Qgb2YgcGh5
+c2ljYWxseSBwZXJmb3JtaW5nIHNvdXJjZSBkaXN0cmlidXRpb24sIGEgY29tcGxldGUKICAgIG1h
+Y2hpbmUtcmVhZGFibGUgY29weSBvZiB0aGUgY29ycmVzcG9uZGluZyBzb3VyY2UgY29kZSwgdG8g
+YmUKICAgIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiBTZWN0aW9ucyAxIGFuZCAyIGFi
+b3ZlIG9uIGEgbWVkaXVtCiAgICBjdXN0b21hcmlseSB1c2VkIGZvciBzb2Z0d2FyZSBpbnRlcmNo
+YW5nZTsgb3IsCgogICAgYykgQWNjb21wYW55IGl0IHdpdGggdGhlIGluZm9ybWF0aW9uIHlvdSBy
+ZWNlaXZlZCBhcyB0byB0aGUgb2ZmZXIKICAgIHRvIGRpc3RyaWJ1dGUgY29ycmVzcG9uZGluZyBz
+b3VyY2UgY29kZS4gIChUaGlzIGFsdGVybmF0aXZlIGlzCiAgICBhbGxvd2VkIG9ubHkgZm9yIG5v
+bmNvbW1lcmNpYWwgZGlzdHJpYnV0aW9uIGFuZCBvbmx5IGlmIHlvdQogICAgcmVjZWl2ZWQgdGhl
+IHByb2dyYW0gaW4gb2JqZWN0IGNvZGUgb3IgZXhlY3V0YWJsZSBmb3JtIHdpdGggc3VjaAogICAg
+YW4gb2ZmZXIsIGluIGFjY29yZCB3aXRoIFN1YnNlY3Rpb24gYiBhYm92ZS4pCgpUaGUgc291cmNl
+IGNvZGUgZm9yIGEgd29yayBtZWFucyB0aGUgcHJlZmVycmVkIGZvcm0gb2YgdGhlIHdvcmsgZm9y
+Cm1ha2luZyBtb2RpZmljYXRpb25zIHRvIGl0LiAgRm9yIGFuIGV4ZWN1dGFibGUgd29yaywgY29t
+cGxldGUgc291cmNlCmNvZGUgbWVhbnMgYWxsIHRoZSBzb3VyY2UgY29kZSBmb3IgYWxsIG1vZHVs
+ZXMgaXQgY29udGFpbnMsIHBsdXMgYW55CmFzc29jaWF0ZWQgaW50ZXJmYWNlIGRlZmluaXRpb24g
+ZmlsZXMsIHBsdXMgdGhlIHNjcmlwdHMgdXNlZCB0bwpjb250cm9sIGNvbXBpbGF0aW9uIGFuZCBp
+bnN0YWxsYXRpb24gb2YgdGhlIGV4ZWN1dGFibGUuICBIb3dldmVyLCBhcyBhCnNwZWNpYWwgZXhj
+ZXB0aW9uLCB0aGUgc291cmNlIGNvZGUgZGlzdHJpYnV0ZWQgbmVlZCBub3QgaW5jbHVkZQphbnl0
+aGluZyB0aGF0IGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIChpbiBlaXRoZXIgc291cmNlIG9yIGJp
+bmFyeQpmb3JtKSB3aXRoIHRoZSBtYWpvciBjb21wb25lbnRzIChjb21waWxlciwga2VybmVsLCBh
+bmQgc28gb24pIG9mIHRoZQpvcGVyYXRpbmcgc3lzdGVtIG9uIHdoaWNoIHRoZSBleGVjdXRhYmxl
+IHJ1bnMsIHVubGVzcyB0aGF0IGNvbXBvbmVudAppdHNlbGYgYWNjb21wYW5pZXMgdGhlIGV4ZWN1
+dGFibGUuCgpJZiBkaXN0cmlidXRpb24gb2YgZXhlY3V0YWJsZSBvciBvYmplY3QgY29kZSBpcyBt
+YWRlIGJ5IG9mZmVyaW5nCmFjY2VzcyB0byBjb3B5IGZyb20gYSBkZXNpZ25hdGVkIHBsYWNlLCB0
+aGVuIG9mZmVyaW5nIGVxdWl2YWxlbnQKYWNjZXNzIHRvIGNvcHkgdGhlIHNvdXJjZSBjb2RlIGZy
+b20gdGhlIHNhbWUgcGxhY2UgY291bnRzIGFzCmRpc3RyaWJ1dGlvbiBvZiB0aGUgc291cmNlIGNv
+ZGUsIGV2ZW4gdGhvdWdoIHRoaXJkIHBhcnRpZXMgYXJlIG5vdApjb21wZWxsZWQgdG8gY29weSB0
+aGUgc291cmNlIGFsb25nIHdpdGggdGhlIG9iamVjdCBjb2RlLgoKICA0LiBZb3UgbWF5IG5vdCBj
+b3B5LCBtb2RpZnksIHN1YmxpY2Vuc2UsIG9yIGRpc3RyaWJ1dGUgdGhlIFByb2dyYW0KZXhjZXB0
+IGFzIGV4cHJlc3NseSBwcm92aWRlZCB1bmRlciB0aGlzIExpY2Vuc2UuICBBbnkgYXR0ZW1wdApv
+dGhlcndpc2UgdG8gY29weSwgbW9kaWZ5LCBzdWJsaWNlbnNlIG9yIGRpc3RyaWJ1dGUgdGhlIFBy
+b2dyYW0gaXMKdm9pZCwgYW5kIHdpbGwgYXV0b21hdGljYWxseSB0ZXJtaW5hdGUgeW91ciByaWdo
+dHMgdW5kZXIgdGhpcyBMaWNlbnNlLgpIb3dldmVyLCBwYXJ0aWVzIHdobyBoYXZlIHJlY2VpdmVk
+IGNvcGllcywgb3IgcmlnaHRzLCBmcm9tIHlvdSB1bmRlcgp0aGlzIExpY2Vuc2Ugd2lsbCBub3Qg
+aGF2ZSB0aGVpciBsaWNlbnNlcyB0ZXJtaW5hdGVkIHNvIGxvbmcgYXMgc3VjaApwYXJ0aWVzIHJl
+bWFpbiBpbiBmdWxsIGNvbXBsaWFuY2UuCgogIDUuIFlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIGFj
+Y2VwdCB0aGlzIExpY2Vuc2UsIHNpbmNlIHlvdSBoYXZlIG5vdApzaWduZWQgaXQuICBIb3dldmVy
+LCBub3RoaW5nIGVsc2UgZ3JhbnRzIHlvdSBwZXJtaXNzaW9uIHRvIG1vZGlmeSBvcgpkaXN0cmli
+dXRlIHRoZSBQcm9ncmFtIG9yIGl0cyBkZXJpdmF0aXZlIHdvcmtzLiAgVGhlc2UgYWN0aW9ucyBh
+cmUKcHJvaGliaXRlZCBieSBsYXcgaWYgeW91IGRvIG5vdCBhY2NlcHQgdGhpcyBMaWNlbnNlLiAg
+VGhlcmVmb3JlLCBieQptb2RpZnlpbmcgb3IgZGlzdHJpYnV0aW5nIHRoZSBQcm9ncmFtIChvciBh
+bnkgd29yayBiYXNlZCBvbiB0aGUKUHJvZ3JhbSksIHlvdSBpbmRpY2F0ZSB5b3VyIGFjY2VwdGFu
+Y2Ugb2YgdGhpcyBMaWNlbnNlIHRvIGRvIHNvLCBhbmQKYWxsIGl0cyB0ZXJtcyBhbmQgY29uZGl0
+aW9ucyBmb3IgY29weWluZywgZGlzdHJpYnV0aW5nIG9yIG1vZGlmeWluZwp0aGUgUHJvZ3JhbSBv
+ciB3b3JrcyBiYXNlZCBvbiBpdC4KCiAgNi4gRWFjaCB0aW1lIHlvdSByZWRpc3RyaWJ1dGUgdGhl
+IFByb2dyYW0gKG9yIGFueSB3b3JrIGJhc2VkIG9uIHRoZQpQcm9ncmFtKSwgdGhlIHJlY2lwaWVu
+dCBhdXRvbWF0aWNhbGx5IHJlY2VpdmVzIGEgbGljZW5zZSBmcm9tIHRoZQpvcmlnaW5hbCBsaWNl
+bnNvciB0byBjb3B5LCBkaXN0cmlidXRlIG9yIG1vZGlmeSB0aGUgUHJvZ3JhbSBzdWJqZWN0IHRv
+CnRoZXNlIHRlcm1zIGFuZCBjb25kaXRpb25zLiAgWW91IG1heSBub3QgaW1wb3NlIGFueSBmdXJ0
+aGVyCnJlc3RyaWN0aW9ucyBvbiB0aGUgcmVjaXBpZW50cycgZXhlcmNpc2Ugb2YgdGhlIHJpZ2h0
+cyBncmFudGVkIGhlcmVpbi4KWW91IGFyZSBub3QgcmVzcG9uc2libGUgZm9yIGVuZm9yY2luZyBj
+b21wbGlhbmNlIGJ5IHRoaXJkIHBhcnRpZXMgdG8KdGhpcyBMaWNlbnNlLgoKICA3LiBJZiwgYXMg
+YSBjb25zZXF1ZW5jZSBvZiBhIGNvdXJ0IGp1ZGdtZW50IG9yIGFsbGVnYXRpb24gb2YgcGF0ZW50
+CmluZnJpbmdlbWVudCBvciBmb3IgYW55IG90aGVyIHJlYXNvbiAobm90IGxpbWl0ZWQgdG8gcGF0
+ZW50IGlzc3VlcyksCmNvbmRpdGlvbnMgYXJlIGltcG9zZWQgb24geW91ICh3aGV0aGVyIGJ5IGNv
+dXJ0IG9yZGVyLCBhZ3JlZW1lbnQgb3IKb3RoZXJ3aXNlKSB0aGF0IGNvbnRyYWRpY3QgdGhlIGNv
+bmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLCB0aGV5IGRvIG5vdApleGN1c2UgeW91IGZyb20gdGhl
+IGNvbmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLiAgSWYgeW91IGNhbm5vdApkaXN0cmlidXRlIHNv
+IGFzIHRvIHNhdGlzZnkgc2ltdWx0YW5lb3VzbHkgeW91ciBvYmxpZ2F0aW9ucyB1bmRlciB0aGlz
+CkxpY2Vuc2UgYW5kIGFueSBvdGhlciBwZXJ0aW5lbnQgb2JsaWdhdGlvbnMsIHRoZW4gYXMgYSBj
+b25zZXF1ZW5jZSB5b3UKbWF5IG5vdCBkaXN0cmlidXRlIHRoZSBQcm9ncmFtIGF0IGFsbC4gIEZv
+ciBleGFtcGxlLCBpZiBhIHBhdGVudApsaWNlbnNlIHdvdWxkIG5vdCBwZXJtaXQgcm95YWx0eS1m
+cmVlIHJlZGlzdHJpYnV0aW9uIG9mIHRoZSBQcm9ncmFtIGJ5CmFsbCB0aG9zZSB3aG8gcmVjZWl2
+ZSBjb3BpZXMgZGlyZWN0bHkgb3IgaW5kaXJlY3RseSB0aHJvdWdoIHlvdSwgdGhlbgp0aGUgb25s
+eSB3YXkgeW91IGNvdWxkIHNhdGlzZnkgYm90aCBpdCBhbmQgdGhpcyBMaWNlbnNlIHdvdWxkIGJl
+IHRvCnJlZnJhaW4gZW50aXJlbHkgZnJvbSBkaXN0cmlidXRpb24gb2YgdGhlIFByb2dyYW0uCgpJ
+ZiBhbnkgcG9ydGlvbiBvZiB0aGlzIHNlY3Rpb24gaXMgaGVsZCBpbnZhbGlkIG9yIHVuZW5mb3Jj
+ZWFibGUgdW5kZXIKYW55IHBhcnRpY3VsYXIgY2lyY3Vtc3RhbmNlLCB0aGUgYmFsYW5jZSBvZiB0
+aGUgc2VjdGlvbiBpcyBpbnRlbmRlZCB0bwphcHBseSBhbmQgdGhlIHNlY3Rpb24gYXMgYSB3aG9s
+ZSBpcyBpbnRlbmRlZCB0byBhcHBseSBpbiBvdGhlcgpjaXJjdW1zdGFuY2VzLgoKSXQgaXMgbm90
+IHRoZSBwdXJwb3NlIG9mIHRoaXMgc2VjdGlvbiB0byBpbmR1Y2UgeW91IHRvIGluZnJpbmdlIGFu
+eQpwYXRlbnRzIG9yIG90aGVyIHByb3BlcnR5IHJpZ2h0IGNsYWltcyBvciB0byBjb250ZXN0IHZh
+bGlkaXR5IG9mIGFueQpzdWNoIGNsYWltczsgdGhpcyBzZWN0aW9uIGhhcyB0aGUgc29sZSBwdXJw
+b3NlIG9mIHByb3RlY3RpbmcgdGhlCmludGVncml0eSBvZiB0aGUgZnJlZSBzb2Z0d2FyZSBkaXN0
+cmlidXRpb24gc3lzdGVtLCB3aGljaCBpcwppbXBsZW1lbnRlZCBieSBwdWJsaWMgbGljZW5zZSBw
+cmFjdGljZXMuICBNYW55IHBlb3BsZSBoYXZlIG1hZGUKZ2VuZXJvdXMgY29udHJpYnV0aW9ucyB0
+byB0aGUgd2lkZSByYW5nZSBvZiBzb2Z0d2FyZSBkaXN0cmlidXRlZAp0aHJvdWdoIHRoYXQgc3lz
+dGVtIGluIHJlbGlhbmNlIG9uIGNvbnNpc3RlbnQgYXBwbGljYXRpb24gb2YgdGhhdApzeXN0ZW07
+IGl0IGlzIHVwIHRvIHRoZSBhdXRob3IvZG9ub3IgdG8gZGVjaWRlIGlmIGhlIG9yIHNoZSBpcyB3
+aWxsaW5nCnRvIGRpc3RyaWJ1dGUgc29mdHdhcmUgdGhyb3VnaCBhbnkgb3RoZXIgc3lzdGVtIGFu
+ZCBhIGxpY2Vuc2VlIGNhbm5vdAppbXBvc2UgdGhhdCBjaG9pY2UuCgpUaGlzIHNlY3Rpb24gaXMg
+aW50ZW5kZWQgdG8gbWFrZSB0aG9yb3VnaGx5IGNsZWFyIHdoYXQgaXMgYmVsaWV2ZWQgdG8KYmUg
+YSBjb25zZXF1ZW5jZSBvZiB0aGUgcmVzdCBvZiB0aGlzIExpY2Vuc2UuCgogIDguIElmIHRoZSBk
+aXN0cmlidXRpb24gYW5kL29yIHVzZSBvZiB0aGUgUHJvZ3JhbSBpcyByZXN0cmljdGVkIGluCmNl
+cnRhaW4gY291bnRyaWVzIGVpdGhlciBieSBwYXRlbnRzIG9yIGJ5IGNvcHlyaWdodGVkIGludGVy
+ZmFjZXMsIHRoZQpvcmlnaW5hbCBjb3B5cmlnaHQgaG9sZGVyIHdobyBwbGFjZXMgdGhlIFByb2dy
+YW0gdW5kZXIgdGhpcyBMaWNlbnNlCm1heSBhZGQgYW4gZXhwbGljaXQgZ2VvZ3JhcGhpY2FsIGRp
+c3RyaWJ1dGlvbiBsaW1pdGF0aW9uIGV4Y2x1ZGluZwp0aG9zZSBjb3VudHJpZXMsIHNvIHRoYXQg
+ZGlzdHJpYnV0aW9uIGlzIHBlcm1pdHRlZCBvbmx5IGluIG9yIGFtb25nCmNvdW50cmllcyBub3Qg
+dGh1cyBleGNsdWRlZC4gIEluIHN1Y2ggY2FzZSwgdGhpcyBMaWNlbnNlIGluY29ycG9yYXRlcwp0
+aGUgbGltaXRhdGlvbiBhcyBpZiB3cml0dGVuIGluIHRoZSBib2R5IG9mIHRoaXMgTGljZW5zZS4K
+CiAgOS4gVGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiBtYXkgcHVibGlzaCByZXZpc2VkIGFu
+ZC9vciBuZXcgdmVyc2lvbnMKb2YgdGhlIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZnJvbSB0aW1l
+IHRvIHRpbWUuICBTdWNoIG5ldyB2ZXJzaW9ucyB3aWxsCmJlIHNpbWlsYXIgaW4gc3Bpcml0IHRv
+IHRoZSBwcmVzZW50IHZlcnNpb24sIGJ1dCBtYXkgZGlmZmVyIGluIGRldGFpbCB0bwphZGRyZXNz
+IG5ldyBwcm9ibGVtcyBvciBjb25jZXJucy4KCkVhY2ggdmVyc2lvbiBpcyBnaXZlbiBhIGRpc3Rp
+bmd1aXNoaW5nIHZlcnNpb24gbnVtYmVyLiAgSWYgdGhlIFByb2dyYW0Kc3BlY2lmaWVzIGEgdmVy
+c2lvbiBudW1iZXIgb2YgdGhpcyBMaWNlbnNlIHdoaWNoIGFwcGxpZXMgdG8gaXQgYW5kICJhbnkK
+bGF0ZXIgdmVyc2lvbiIsIHlvdSBoYXZlIHRoZSBvcHRpb24gb2YgZm9sbG93aW5nIHRoZSB0ZXJt
+cyBhbmQgY29uZGl0aW9ucwplaXRoZXIgb2YgdGhhdCB2ZXJzaW9uIG9yIG9mIGFueSBsYXRlciB2
+ZXJzaW9uIHB1Ymxpc2hlZCBieSB0aGUgRnJlZQpTb2Z0d2FyZSBGb3VuZGF0aW9uLiAgSWYgdGhl
+IFByb2dyYW0gZG9lcyBub3Qgc3BlY2lmeSBhIHZlcnNpb24gbnVtYmVyIG9mCnRoaXMgTGljZW5z
+ZSwgeW91IG1heSBjaG9vc2UgYW55IHZlcnNpb24gZXZlciBwdWJsaXNoZWQgYnkgdGhlIEZyZWUg
+U29mdHdhcmUKRm91bmRhdGlvbi4KCiAgMTAuIElmIHlvdSB3aXNoIHRvIGluY29ycG9yYXRlIHBh
+cnRzIG9mIHRoZSBQcm9ncmFtIGludG8gb3RoZXIgZnJlZQpwcm9ncmFtcyB3aG9zZSBkaXN0cmli
+dXRpb24gY29uZGl0aW9ucyBhcmUgZGlmZmVyZW50LCB3cml0ZSB0byB0aGUgYXV0aG9yCnRvIGFz
+ayBmb3IgcGVybWlzc2lvbi4gIEZvciBzb2Z0d2FyZSB3aGljaCBpcyBjb3B5cmlnaHRlZCBieSB0
+aGUgRnJlZQpTb2Z0d2FyZSBGb3VuZGF0aW9uLCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZSBG
+b3VuZGF0aW9uOyB3ZSBzb21ldGltZXMKbWFrZSBleGNlcHRpb25zIGZvciB0aGlzLiAgT3VyIGRl
+Y2lzaW9uIHdpbGwgYmUgZ3VpZGVkIGJ5IHRoZSB0d28gZ29hbHMKb2YgcHJlc2VydmluZyB0aGUg
+ZnJlZSBzdGF0dXMgb2YgYWxsIGRlcml2YXRpdmVzIG9mIG91ciBmcmVlIHNvZnR3YXJlIGFuZApv
+ZiBwcm9tb3RpbmcgdGhlIHNoYXJpbmcgYW5kIHJldXNlIG9mIHNvZnR3YXJlIGdlbmVyYWxseS4K
+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBOTyBXQVJSQU5UWQoKICAxMS4gQkVDQVVTRSBU
+SEUgUFJPR1JBTSBJUyBMSUNFTlNFRCBGUkVFIE9GIENIQVJHRSwgVEhFUkUgSVMgTk8gV0FSUkFO
+VFkKRk9SIFRIRSBQUk9HUkFNLCBUTyBUSEUgRVhURU5UIFBFUk1JVFRFRCBCWSBBUFBMSUNBQkxF
+IExBVy4gIEVYQ0VQVCBXSEVOCk9USEVSV0lTRSBTVEFURUQgSU4gV1JJVElORyBUSEUgQ09QWVJJ
+R0hUIEhPTERFUlMgQU5EL09SIE9USEVSIFBBUlRJRVMKUFJPVklERSBUSEUgUFJPR1JBTSAiQVMg
+SVMiIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVJVEhFUiBFWFBSRVNTRUQKT1IgSU1Q
+TElFRCwgSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJ
+RVMgT0YKTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9T
+RS4gIFRIRSBFTlRJUkUgUklTSyBBUwpUTyBUSEUgUVVBTElUWSBBTkQgUEVSRk9STUFOQ0UgT0Yg
+VEhFIFBST0dSQU0gSVMgV0lUSCBZT1UuICBTSE9VTEQgVEhFClBST0dSQU0gUFJPVkUgREVGRUNU
+SVZFLCBZT1UgQVNTVU1FIFRIRSBDT1NUIE9GIEFMTCBORUNFU1NBUlkgU0VSVklDSU5HLApSRVBB
+SVIgT1IgQ09SUkVDVElPTi4KCiAgMTIuIElOIE5PIEVWRU5UIFVOTEVTUyBSRVFVSVJFRCBCWSBB
+UFBMSUNBQkxFIExBVyBPUiBBR1JFRUQgVE8gSU4gV1JJVElORwpXSUxMIEFOWSBDT1BZUklHSFQg
+SE9MREVSLCBPUiBBTlkgT1RIRVIgUEFSVFkgV0hPIE1BWSBNT0RJRlkgQU5EL09SClJFRElTVFJJ
+QlVURSBUSEUgUFJPR1JBTSBBUyBQRVJNSVRURUQgQUJPVkUsIEJFIExJQUJMRSBUTyBZT1UgRk9S
+IERBTUFHRVMsCklOQ0xVRElORyBBTlkgR0VORVJBTCwgU1BFQ0lBTCwgSU5DSURFTlRBTCBPUiBD
+T05TRVFVRU5USUFMIERBTUFHRVMgQVJJU0lORwpPVVQgT0YgVEhFIFVTRSBPUiBJTkFCSUxJVFkg
+VE8gVVNFIFRIRSBQUk9HUkFNIChJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIExPU1MgT0Yg
+REFUQSBPUiBEQVRBIEJFSU5HIFJFTkRFUkVEIElOQUNDVVJBVEUgT1IgTE9TU0VTIFNVU1RBSU5F
+RCBCWQpZT1UgT1IgVEhJUkQgUEFSVElFUyBPUiBBIEZBSUxVUkUgT0YgVEhFIFBST0dSQU0gVE8g
+T1BFUkFURSBXSVRIIEFOWSBPVEhFUgpQUk9HUkFNUyksIEVWRU4gSUYgU1VDSCBIT0xERVIgT1Ig
+T1RIRVIgUEFSVFkgSEFTIEJFRU4gQURWSVNFRCBPRiBUSEUKUE9TU0lCSUxJVFkgT0YgU1VDSCBE
+QU1BR0VTLgoKICAgICAgICAgICAgICAgICAgICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05T
+CgogICAgICAgICAgICBIb3cgdG8gQXBwbHkgVGhlc2UgVGVybXMgdG8gWW91ciBOZXcgUHJvZ3Jh
+bXMKCiAgSWYgeW91IGRldmVsb3AgYSBuZXcgcHJvZ3JhbSwgYW5kIHlvdSB3YW50IGl0IHRvIGJl
+IG9mIHRoZSBncmVhdGVzdApwb3NzaWJsZSB1c2UgdG8gdGhlIHB1YmxpYywgdGhlIGJlc3Qgd2F5
+IHRvIGFjaGlldmUgdGhpcyBpcyB0byBtYWtlIGl0CmZyZWUgc29mdHdhcmUgd2hpY2ggZXZlcnlv
+bmUgY2FuIHJlZGlzdHJpYnV0ZSBhbmQgY2hhbmdlIHVuZGVyIHRoZXNlIHRlcm1zLgoKICBUbyBk
+byBzbywgYXR0YWNoIHRoZSBmb2xsb3dpbmcgbm90aWNlcyB0byB0aGUgcHJvZ3JhbS4gIEl0IGlz
+IHNhZmVzdAp0byBhdHRhY2ggdGhlbSB0byB0aGUgc3RhcnQgb2YgZWFjaCBzb3VyY2UgZmlsZSB0
+byBtb3N0IGVmZmVjdGl2ZWx5CmNvbnZleSB0aGUgZXhjbHVzaW9uIG9mIHdhcnJhbnR5OyBhbmQg
+ZWFjaCBmaWxlIHNob3VsZCBoYXZlIGF0IGxlYXN0CnRoZSAiY29weXJpZ2h0IiBsaW5lIGFuZCBh
+IHBvaW50ZXIgdG8gd2hlcmUgdGhlIGZ1bGwgbm90aWNlIGlzIGZvdW5kLgoKICAgIDxvbmUgbGlu
+ZSB0byBnaXZlIHRoZSBwcm9ncmFtJ3MgbmFtZSBhbmQgYSBicmllZiBpZGVhIG9mIHdoYXQgaXQg
+ZG9lcy4+CiAgICBDb3B5cmlnaHQgKEMpIDx5ZWFyPiAgPG5hbWUgb2YgYXV0aG9yPgoKICAgIFRo
+aXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQv
+b3IgbW9kaWZ5CiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1Ymxp
+YyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieQogICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlv
+bjsgZWl0aGVyIHZlcnNpb24gMiBvZiB0aGUgTGljZW5zZSwgb3IKICAgIChhdCB5b3VyIG9wdGlv
+bikgYW55IGxhdGVyIHZlcnNpb24uCgogICAgVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGlu
+IHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCiAgICBidXQgV0lUSE9VVCBBTlkgV0FS
+UkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgogICAgTUVSQ0hBTlRB
+QklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQogICAg
+R05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KCiAgICBZb3Ugc2hv
+dWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5z
+ZSBhbG9uZwogICAgd2l0aCB0aGlzIHByb2dyYW07IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUg
+U29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiwKICAgIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGgg
+Rmxvb3IsIEJvc3RvbiwgTUEgMDIxMTAtMTMwMSBVU0EuCgpBbHNvIGFkZCBpbmZvcm1hdGlvbiBv
+biBob3cgdG8gY29udGFjdCB5b3UgYnkgZWxlY3Ryb25pYyBhbmQgcGFwZXIgbWFpbC4KCklmIHRo
+ZSBwcm9ncmFtIGlzIGludGVyYWN0aXZlLCBtYWtlIGl0IG91dHB1dCBhIHNob3J0IG5vdGljZSBs
+aWtlIHRoaXMKd2hlbiBpdCBzdGFydHMgaW4gYW4gaW50ZXJhY3RpdmUgbW9kZToKCiAgICBHbm9t
+b3Zpc2lvbiB2ZXJzaW9uIDY5LCBDb3B5cmlnaHQgKEMpIHllYXIgbmFtZSBvZiBhdXRob3IKICAg
+IEdub21vdmlzaW9uIGNvbWVzIHdpdGggQUJTT0xVVEVMWSBOTyBXQVJSQU5UWTsgZm9yIGRldGFp
+bHMgdHlwZSBgc2hvdyB3Jy4KICAgIFRoaXMgaXMgZnJlZSBzb2Z0d2FyZSwgYW5kIHlvdSBhcmUg
+d2VsY29tZSB0byByZWRpc3RyaWJ1dGUgaXQKICAgIHVuZGVyIGNlcnRhaW4gY29uZGl0aW9uczsg
+dHlwZSBgc2hvdyBjJyBmb3IgZGV0YWlscy4KClRoZSBoeXBvdGhldGljYWwgY29tbWFuZHMgYHNo
+b3cgdycgYW5kIGBzaG93IGMnIHNob3VsZCBzaG93IHRoZSBhcHByb3ByaWF0ZQpwYXJ0cyBvZiB0
+aGUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZS4gIE9mIGNvdXJzZSwgdGhlIGNvbW1hbmRzIHlvdSB1
+c2UgbWF5CmJlIGNhbGxlZCBzb21ldGhpbmcgb3RoZXIgdGhhbiBgc2hvdyB3JyBhbmQgYHNob3cg
+Yyc7IHRoZXkgY291bGQgZXZlbiBiZQptb3VzZS1jbGlja3Mgb3IgbWVudSBpdGVtcy0td2hhdGV2
+ZXIgc3VpdHMgeW91ciBwcm9ncmFtLgoKWW91IHNob3VsZCBhbHNvIGdldCB5b3VyIGVtcGxveWVy
+IChpZiB5b3Ugd29yayBhcyBhIHByb2dyYW1tZXIpIG9yIHlvdXIKc2Nob29sLCBpZiBhbnksIHRv
+IHNpZ24gYSAiY29weXJpZ2h0IGRpc2NsYWltZXIiIGZvciB0aGUgcHJvZ3JhbSwgaWYKbmVjZXNz
+YXJ5LiAgSGVyZSBpcyBhIHNhbXBsZTsgYWx0ZXIgdGhlIG5hbWVzOgoKICBZb3lvZHluZSwgSW5j
+LiwgaGVyZWJ5IGRpc2NsYWltcyBhbGwgY29weXJpZ2h0IGludGVyZXN0IGluIHRoZSBwcm9ncmFt
+CiAgYEdub21vdmlzaW9uJyAod2hpY2ggbWFrZXMgcGFzc2VzIGF0IGNvbXBpbGVycykgd3JpdHRl
+biBieSBKYW1lcyBIYWNrZXIuCgogIDxzaWduYXR1cmUgb2YgVHkgQ29vbj4sIDEgQXByaWwgMTk4
+OQogIFR5IENvb24sIFByZXNpZGVudCBvZiBWaWNlCgpUaGlzIEdlbmVyYWwgUHVibGljIExpY2Vu
+c2UgZG9lcyBub3QgcGVybWl0IGluY29ycG9yYXRpbmcgeW91ciBwcm9ncmFtIGludG8KcHJvcHJp
+ZXRhcnkgcHJvZ3JhbXMuICBJZiB5b3VyIHByb2dyYW0gaXMgYSBzdWJyb3V0aW5lIGxpYnJhcnks
+IHlvdSBtYXkKY29uc2lkZXIgaXQgbW9yZSB1c2VmdWwgdG8gcGVybWl0IGxpbmtpbmcgcHJvcHJp
+ZXRhcnkgYXBwbGljYXRpb25zIHdpdGggdGhlCmxpYnJhcnkuICBJZiB0aGlzIGlzIHdoYXQgeW91
+IHdhbnQgdG8gZG8sIHVzZSB0aGUgR05VIExlc3NlciBHZW5lcmFsClB1YmxpYyBMaWNlbnNlIGlu
+c3RlYWQgb2YgdGhpcyBMaWNlbnNlLg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-license-blobs/ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2.base64 b/src/sdks/rust/mobile-bindings/dependency-license-blobs/ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2.base64
new file mode 100644
index 000000000..77e2e27d7
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-license-blobs/ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE2IEFtYW5pZXUgZCdBbnRyYXMKClBlcm1pc3Npb24gaXMgaGVyZWJ5
+IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBhIGNvcHkg
+b2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUg
+IlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24s
+IGluY2x1ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1v
+ZGlmeSwgbWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxs
+IGNvcGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRo
+ZSBTb2Z0d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2lu
+Zwpjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlz
+c2lvbiBub3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlh
+bCBwb3J0aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFT
+IElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJ
+TkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJ
+TElUWSwgRklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVO
+VC4gSU4gTk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUg
+TElBQkxFIEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVS
+IElOIEFOIEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJP
+TSwgT1VUIE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBP
+UiBPVEhFUgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/rust/mobile-bindings/dependency-licenses.json b/src/sdks/rust/mobile-bindings/dependency-licenses.json
new file mode 100644
index 000000000..8e47fb8b1
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/dependency-licenses.json
@@ -0,0 +1,2203 @@
+{
+  "schema": "oliphaunt-mobile-bindings-dependency-license-contract-v1",
+  "product": "oliphaunt-mobile-bindings",
+  "cargoSource": "registry+https://github.com/rust-lang/crates.io-index",
+  "payloadLicense": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause AND MPL-2.0",
+  "targets": {
+    "android-arm64": {
+      "cargoTarget": "aarch64-linux-android",
+      "packages": [
+        "anyhow@1.0.103",
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "bytes@1.11.1",
+        "camino@1.2.5",
+        "cfg-if@1.0.4",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "digest@0.10.7",
+        "equivalent@1.0.2",
+        "errno@0.3.14",
+        "fastrand@2.4.1",
+        "filetime@0.2.29",
+        "fs-err@3.3.1",
+        "fs2@0.4.3",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "getrandom@0.4.2",
+        "hashbrown@0.17.1",
+        "heck@0.5.0",
+        "indexmap@2.14.0",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "linux-raw-sys@0.12.1",
+        "memchr@2.8.1",
+        "once_cell@1.21.4",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustix@1.1.4",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "serde_spanned@1.1.1",
+        "sha2@0.10.9",
+        "siphasher@1.0.3",
+        "static_assertions@1.1.0",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "tempfile@3.27.0",
+        "thiserror-impl@2.0.18",
+        "thiserror@2.0.18",
+        "toml@1.1.2+spec-1.1.0",
+        "toml_datetime@1.1.1+spec-1.1.0",
+        "toml_parser@1.1.2+spec-1.1.0",
+        "toml_writer@1.1.1+spec-1.1.0",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "uniffi@0.32.1",
+        "uniffi_core@0.32.1",
+        "uniffi_internal_macros@0.32.1",
+        "uniffi_macros@0.32.1",
+        "uniffi_meta@0.32.1",
+        "uniffi_pipeline@0.32.1",
+        "winnow@1.0.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    },
+    "android-x86_64": {
+      "cargoTarget": "x86_64-linux-android",
+      "packages": [
+        "anyhow@1.0.103",
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "bytes@1.11.1",
+        "camino@1.2.5",
+        "cfg-if@1.0.4",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "digest@0.10.7",
+        "equivalent@1.0.2",
+        "errno@0.3.14",
+        "fastrand@2.4.1",
+        "filetime@0.2.29",
+        "fs-err@3.3.1",
+        "fs2@0.4.3",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "getrandom@0.4.2",
+        "hashbrown@0.17.1",
+        "heck@0.5.0",
+        "indexmap@2.14.0",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "linux-raw-sys@0.12.1",
+        "memchr@2.8.1",
+        "once_cell@1.21.4",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustix@1.1.4",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "serde_spanned@1.1.1",
+        "sha2@0.10.9",
+        "siphasher@1.0.3",
+        "static_assertions@1.1.0",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "tempfile@3.27.0",
+        "thiserror-impl@2.0.18",
+        "thiserror@2.0.18",
+        "toml@1.1.2+spec-1.1.0",
+        "toml_datetime@1.1.1+spec-1.1.0",
+        "toml_parser@1.1.2+spec-1.1.0",
+        "toml_writer@1.1.1+spec-1.1.0",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "uniffi@0.32.1",
+        "uniffi_core@0.32.1",
+        "uniffi_internal_macros@0.32.1",
+        "uniffi_macros@0.32.1",
+        "uniffi_meta@0.32.1",
+        "uniffi_pipeline@0.32.1",
+        "winnow@1.0.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    },
+    "android-arm": {
+      "cargoTarget": "armv7-linux-androideabi",
+      "packages": [
+        "anyhow@1.0.103",
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "bytes@1.11.1",
+        "camino@1.2.5",
+        "cfg-if@1.0.4",
+        "crypto-common@0.1.7",
+        "digest@0.10.7",
+        "equivalent@1.0.2",
+        "errno@0.3.14",
+        "fastrand@2.4.1",
+        "filetime@0.2.29",
+        "fs-err@3.3.1",
+        "fs2@0.4.3",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "getrandom@0.4.2",
+        "hashbrown@0.17.1",
+        "heck@0.5.0",
+        "indexmap@2.14.0",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "linux-raw-sys@0.12.1",
+        "memchr@2.8.1",
+        "once_cell@1.21.4",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustix@1.1.4",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "serde_spanned@1.1.1",
+        "sha2@0.10.9",
+        "siphasher@1.0.3",
+        "static_assertions@1.1.0",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "tempfile@3.27.0",
+        "thiserror-impl@2.0.18",
+        "thiserror@2.0.18",
+        "toml@1.1.2+spec-1.1.0",
+        "toml_datetime@1.1.1+spec-1.1.0",
+        "toml_parser@1.1.2+spec-1.1.0",
+        "toml_writer@1.1.1+spec-1.1.0",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "uniffi@0.32.1",
+        "uniffi_core@0.32.1",
+        "uniffi_internal_macros@0.32.1",
+        "uniffi_macros@0.32.1",
+        "uniffi_meta@0.32.1",
+        "uniffi_pipeline@0.32.1",
+        "winnow@1.0.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    },
+    "android-x86": {
+      "cargoTarget": "i686-linux-android",
+      "packages": [
+        "anyhow@1.0.103",
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "bytes@1.11.1",
+        "camino@1.2.5",
+        "cfg-if@1.0.4",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "digest@0.10.7",
+        "equivalent@1.0.2",
+        "errno@0.3.14",
+        "fastrand@2.4.1",
+        "filetime@0.2.29",
+        "fs-err@3.3.1",
+        "fs2@0.4.3",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "getrandom@0.4.2",
+        "hashbrown@0.17.1",
+        "heck@0.5.0",
+        "indexmap@2.14.0",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "linux-raw-sys@0.12.1",
+        "memchr@2.8.1",
+        "once_cell@1.21.4",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustix@1.1.4",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "serde_spanned@1.1.1",
+        "sha2@0.10.9",
+        "siphasher@1.0.3",
+        "static_assertions@1.1.0",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "tempfile@3.27.0",
+        "thiserror-impl@2.0.18",
+        "thiserror@2.0.18",
+        "toml@1.1.2+spec-1.1.0",
+        "toml_datetime@1.1.1+spec-1.1.0",
+        "toml_parser@1.1.2+spec-1.1.0",
+        "toml_writer@1.1.1+spec-1.1.0",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "uniffi@0.32.1",
+        "uniffi_core@0.32.1",
+        "uniffi_internal_macros@0.32.1",
+        "uniffi_macros@0.32.1",
+        "uniffi_meta@0.32.1",
+        "uniffi_pipeline@0.32.1",
+        "winnow@1.0.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    },
+    "ios-arm64": {
+      "cargoTarget": "aarch64-apple-ios",
+      "packages": [
+        "anyhow@1.0.103",
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "bytes@1.11.1",
+        "camino@1.2.5",
+        "cfg-if@1.0.4",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "digest@0.10.7",
+        "equivalent@1.0.2",
+        "errno@0.3.14",
+        "fastrand@2.4.1",
+        "filetime@0.2.29",
+        "fs-err@3.3.1",
+        "fs2@0.4.3",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "getrandom@0.4.2",
+        "hashbrown@0.17.1",
+        "heck@0.5.0",
+        "indexmap@2.14.0",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "linux-raw-sys@0.12.1",
+        "memchr@2.8.1",
+        "once_cell@1.21.4",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustix@1.1.4",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "serde_spanned@1.1.1",
+        "sha2@0.10.9",
+        "siphasher@1.0.3",
+        "static_assertions@1.1.0",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "tempfile@3.27.0",
+        "thiserror-impl@2.0.18",
+        "thiserror@2.0.18",
+        "toml@1.1.2+spec-1.1.0",
+        "toml_datetime@1.1.1+spec-1.1.0",
+        "toml_parser@1.1.2+spec-1.1.0",
+        "toml_writer@1.1.1+spec-1.1.0",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "uniffi@0.32.1",
+        "uniffi_core@0.32.1",
+        "uniffi_internal_macros@0.32.1",
+        "uniffi_macros@0.32.1",
+        "uniffi_meta@0.32.1",
+        "uniffi_pipeline@0.32.1",
+        "winnow@1.0.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    },
+    "ios-simulator-arm64": {
+      "cargoTarget": "aarch64-apple-ios-sim",
+      "packages": [
+        "anyhow@1.0.103",
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "bytes@1.11.1",
+        "camino@1.2.5",
+        "cfg-if@1.0.4",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "digest@0.10.7",
+        "equivalent@1.0.2",
+        "errno@0.3.14",
+        "fastrand@2.4.1",
+        "filetime@0.2.29",
+        "fs-err@3.3.1",
+        "fs2@0.4.3",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "getrandom@0.4.2",
+        "hashbrown@0.17.1",
+        "heck@0.5.0",
+        "indexmap@2.14.0",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "linux-raw-sys@0.12.1",
+        "memchr@2.8.1",
+        "once_cell@1.21.4",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustix@1.1.4",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "serde_spanned@1.1.1",
+        "sha2@0.10.9",
+        "siphasher@1.0.3",
+        "static_assertions@1.1.0",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "tempfile@3.27.0",
+        "thiserror-impl@2.0.18",
+        "thiserror@2.0.18",
+        "toml@1.1.2+spec-1.1.0",
+        "toml_datetime@1.1.1+spec-1.1.0",
+        "toml_parser@1.1.2+spec-1.1.0",
+        "toml_writer@1.1.1+spec-1.1.0",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "uniffi@0.32.1",
+        "uniffi_core@0.32.1",
+        "uniffi_internal_macros@0.32.1",
+        "uniffi_macros@0.32.1",
+        "uniffi_meta@0.32.1",
+        "uniffi_pipeline@0.32.1",
+        "winnow@1.0.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    },
+    "macos-arm64": {
+      "cargoTarget": "aarch64-apple-darwin",
+      "packages": [
+        "anyhow@1.0.103",
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "bytes@1.11.1",
+        "camino@1.2.5",
+        "cfg-if@1.0.4",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "digest@0.10.7",
+        "equivalent@1.0.2",
+        "errno@0.3.14",
+        "fastrand@2.4.1",
+        "filetime@0.2.29",
+        "fs-err@3.3.1",
+        "fs2@0.4.3",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "getrandom@0.4.2",
+        "hashbrown@0.17.1",
+        "heck@0.5.0",
+        "indexmap@2.14.0",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "linux-raw-sys@0.12.1",
+        "memchr@2.8.1",
+        "once_cell@1.21.4",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustix@1.1.4",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "serde_spanned@1.1.1",
+        "sha2@0.10.9",
+        "siphasher@1.0.3",
+        "static_assertions@1.1.0",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "tempfile@3.27.0",
+        "thiserror-impl@2.0.18",
+        "thiserror@2.0.18",
+        "toml@1.1.2+spec-1.1.0",
+        "toml_datetime@1.1.1+spec-1.1.0",
+        "toml_parser@1.1.2+spec-1.1.0",
+        "toml_writer@1.1.1+spec-1.1.0",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "uniffi@0.32.1",
+        "uniffi_core@0.32.1",
+        "uniffi_internal_macros@0.32.1",
+        "uniffi_macros@0.32.1",
+        "uniffi_meta@0.32.1",
+        "uniffi_pipeline@0.32.1",
+        "winnow@1.0.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    }
+  },
+  "packages": [
+    {
+      "name": "anyhow",
+      "version": "1.0.103",
+      "checksum": "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "bitflags",
+      "version": "2.12.1",
+      "checksum": "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
+          "bytes": 1071
+        }
+      ]
+    },
+    {
+      "name": "block-buffer",
+      "version": "0.10.4",
+      "checksum": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef",
+          "bytes": 1082
+        }
+      ]
+    },
+    {
+      "name": "bytes",
+      "version": "1.11.1",
+      "checksum": "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "45f522cacecb1023856e46df79ca625dfc550c94910078bd8aec6e02880b3d42",
+          "bytes": 1055
+        }
+      ]
+    },
+    {
+      "name": "camino",
+      "version": "1.2.5",
+      "checksum": "bb1307f12aa967b5a58416e87b3653360e0fd614a016b6e970db08fecbb1b80d",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "cfg-if",
+      "version": "1.0.4",
+      "checksum": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
+          "bytes": 1057
+        }
+      ]
+    },
+    {
+      "name": "cpufeatures",
+      "version": "0.2.17",
+      "checksum": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985",
+          "bytes": 1082
+        }
+      ]
+    },
+    {
+      "name": "crypto-common",
+      "version": "0.1.7",
+      "checksum": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897",
+          "bytes": 1065
+        }
+      ]
+    },
+    {
+      "name": "digest",
+      "version": "0.10.7",
+      "checksum": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba",
+          "bytes": 1057
+        }
+      ]
+    },
+    {
+      "name": "equivalent",
+      "version": "1.0.2",
+      "checksum": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f",
+      "declaredLicense": "Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "7365cc8878a1d7ce155a58c4ca09c3d7a6be413efa5334a80ea842912b669349",
+          "bytes": 1049
+        }
+      ]
+    },
+    {
+      "name": "errno",
+      "version": "0.3.14",
+      "checksum": "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2",
+          "bytes": 1054
+        }
+      ]
+    },
+    {
+      "name": "fastrand",
+      "version": "2.4.1",
+      "checksum": "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6",
+      "declaredLicense": "Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "filetime",
+      "version": "0.2.29",
+      "checksum": "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759",
+      "declaredLicense": "MIT/Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
+          "bytes": 1057
+        }
+      ]
+    },
+    {
+      "name": "fs-err",
+      "version": "3.3.1",
+      "checksum": "b91aa448ca50d7e79433bdf3ee8d99215430d2ec02ade5aefab2a073a1822e8a",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c",
+          "bytes": 11048
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9",
+          "bytes": 1046
+        }
+      ]
+    },
+    {
+      "name": "fs2",
+      "version": "0.4.3",
+      "checksum": "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213",
+      "declaredLicense": "MIT/Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
+          "bytes": 1071
+        }
+      ]
+    },
+    {
+      "name": "generic-array",
+      "version": "0.14.7",
+      "checksum": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583",
+          "bytes": 1107
+        }
+      ]
+    },
+    {
+      "name": "getrandom",
+      "version": "0.3.4",
+      "checksum": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4",
+          "bytes": 1130
+        }
+      ]
+    },
+    {
+      "name": "getrandom",
+      "version": "0.4.2",
+      "checksum": "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "523a42c25d245dde9c015f882cec7f4555aad883382a6cf19b4b7d9b2cd5419b",
+          "bytes": 1130
+        }
+      ]
+    },
+    {
+      "name": "hashbrown",
+      "version": "0.17.1",
+      "checksum": "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2",
+          "bytes": 1060
+        }
+      ]
+    },
+    {
+      "name": "heck",
+      "version": "0.5.0",
+      "checksum": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
+          "bytes": 1071
+        }
+      ]
+    },
+    {
+      "name": "indexmap",
+      "version": "2.14.0",
+      "checksum": "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9",
+      "declaredLicense": "Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055",
+          "bytes": 1049
+        }
+      ]
+    },
+    {
+      "name": "itoa",
+      "version": "1.0.18",
+      "checksum": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "libc",
+      "version": "0.2.186",
+      "checksum": "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e",
+          "bytes": 1066
+        }
+      ]
+    },
+    {
+      "name": "libloading",
+      "version": "0.8.9",
+      "checksum": "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55",
+      "declaredLicense": "ISC",
+      "selectedLicense": "ISC",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f",
+          "bytes": 736
+        }
+      ]
+    },
+    {
+      "name": "linux-raw-sys",
+      "version": "0.12.1",
+      "checksum": "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53",
+      "declaredLicense": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "COPYRIGHT",
+          "sha256": "3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b",
+          "bytes": 881
+        },
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-Apache-2.0_WITH_LLVM-exception",
+          "sha256": "268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5",
+          "bytes": 12243
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "memchr",
+      "version": "2.8.1",
+      "checksum": "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8",
+      "declaredLicense": "Unlicense OR MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "COPYING",
+          "sha256": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
+          "bytes": 126
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f",
+          "bytes": 1081
+        },
+        {
+          "name": "UNLICENSE",
+          "sha256": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
+          "bytes": 1211
+        }
+      ]
+    },
+    {
+      "name": "once_cell",
+      "version": "1.21.4",
+      "checksum": "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "proc-macro2",
+      "version": "1.0.106",
+      "checksum": "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "quote",
+      "version": "1.0.45",
+      "checksum": "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "rustix",
+      "version": "1.1.4",
+      "checksum": "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190",
+      "declaredLicense": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "COPYRIGHT",
+          "sha256": "377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9",
+          "bytes": 853
+        },
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-Apache-2.0_WITH_LLVM-exception",
+          "sha256": "268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5",
+          "bytes": 12243
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "serde",
+      "version": "1.0.228",
+      "checksum": "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "serde_core",
+      "version": "1.0.228",
+      "checksum": "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "serde_derive",
+      "version": "1.0.228",
+      "checksum": "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "serde_json",
+      "version": "1.0.150",
+      "checksum": "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "serde_spanned",
+      "version": "1.1.1",
+      "checksum": "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08",
+          "bytes": 11358
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6",
+          "bytes": 1062
+        }
+      ]
+    },
+    {
+      "name": "sha2",
+      "version": "0.10.9",
+      "checksum": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1",
+          "bytes": 1138
+        }
+      ]
+    },
+    {
+      "name": "siphasher",
+      "version": "1.0.3",
+      "checksum": "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649",
+      "declaredLicense": "MIT/Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "COPYING",
+          "sha256": "c962ee4d1d05ddc138b202b2540219ebc57893fcf97b364852094a9a94ce1365",
+          "bytes": 281
+        }
+      ]
+    },
+    {
+      "name": "static_assertions",
+      "version": "1.1.0",
+      "checksum": "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
+          "bytes": 11358
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "ea084a2373ebc1f0902c09266e7bf25a05ab3814c1805bb017ffa7308f90c061",
+          "bytes": 1072
+        }
+      ]
+    },
+    {
+      "name": "syn",
+      "version": "2.0.117",
+      "checksum": "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "tar",
+      "version": "0.4.46",
+      "checksum": "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077",
+          "bytes": 1070
+        }
+      ]
+    },
+    {
+      "name": "tempfile",
+      "version": "3.27.0",
+      "checksum": "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36",
+          "bytes": 1056
+        }
+      ]
+    },
+    {
+      "name": "thiserror-impl",
+      "version": "2.0.18",
+      "checksum": "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "thiserror",
+      "version": "2.0.18",
+      "checksum": "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "toml",
+      "version": "1.1.2+spec-1.1.0",
+      "checksum": "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08",
+          "bytes": 11358
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6",
+          "bytes": 1062
+        }
+      ]
+    },
+    {
+      "name": "toml_datetime",
+      "version": "1.1.1+spec-1.1.0",
+      "checksum": "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08",
+          "bytes": 11358
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6",
+          "bytes": 1062
+        }
+      ]
+    },
+    {
+      "name": "toml_parser",
+      "version": "1.1.2+spec-1.1.0",
+      "checksum": "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08",
+          "bytes": 11358
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6",
+          "bytes": 1062
+        }
+      ]
+    },
+    {
+      "name": "toml_writer",
+      "version": "1.1.1+spec-1.1.0",
+      "checksum": "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08",
+          "bytes": 11358
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6",
+          "bytes": 1062
+        }
+      ]
+    },
+    {
+      "name": "typenum",
+      "version": "1.20.1",
+      "checksum": "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a",
+          "bytes": 17
+        },
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406",
+          "bytes": 10835
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f",
+          "bytes": 1083
+        }
+      ]
+    },
+    {
+      "name": "unicode-ident",
+      "version": "1.0.24",
+      "checksum": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75",
+      "declaredLicense": "(MIT OR Apache-2.0) AND Unicode-3.0",
+      "selectedLicense": "MIT AND Unicode-3.0",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        },
+        {
+          "name": "LICENSE-UNICODE",
+          "sha256": "f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1",
+          "bytes": 1995
+        }
+      ]
+    },
+    {
+      "name": "uniffi",
+      "version": "0.32.1",
+      "checksum": "edf78ecfb9bb8d7c4f8da11e8eb2ab6304e8ec0adb3ab32d8fc77c21a5bb0b86",
+      "declaredLicense": "MPL-2.0",
+      "selectedLicense": "MPL-2.0",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5",
+          "bytes": 16725,
+          "upstream": {
+            "repository": "https://github.com/mozilla/uniffi-rs",
+            "commit": "35a47433d8f015302fbf608f2b395eff6972c36f",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "uniffi_core",
+      "version": "0.32.1",
+      "checksum": "f8b1c62ee415b805f063c82e8ef6bbcaa1b87f8eed360cf217537b7724e05601",
+      "declaredLicense": "MPL-2.0",
+      "selectedLicense": "MPL-2.0",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5",
+          "bytes": 16725,
+          "upstream": {
+            "repository": "https://github.com/mozilla/uniffi-rs",
+            "commit": "35a47433d8f015302fbf608f2b395eff6972c36f",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "uniffi_internal_macros",
+      "version": "0.32.1",
+      "checksum": "c79d4a3129d6c2c15e367d3954886a0533dd3e85d445ce4d93379f62c6949d7b",
+      "declaredLicense": "MPL-2.0",
+      "selectedLicense": "MPL-2.0",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5",
+          "bytes": 16725,
+          "upstream": {
+            "repository": "https://github.com/mozilla/uniffi-rs",
+            "commit": "35a47433d8f015302fbf608f2b395eff6972c36f",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "uniffi_macros",
+      "version": "0.32.1",
+      "checksum": "2f6a9826a83f1140b2ec67c7944f562e1ef616e6eaf40e76247adccbd5b8a091",
+      "declaredLicense": "MPL-2.0",
+      "selectedLicense": "MPL-2.0",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5",
+          "bytes": 16725,
+          "upstream": {
+            "repository": "https://github.com/mozilla/uniffi-rs",
+            "commit": "35a47433d8f015302fbf608f2b395eff6972c36f",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "uniffi_meta",
+      "version": "0.32.1",
+      "checksum": "cf233eb014b595e8997c98df4ac6863b486a4ac6d54bd00230c7700753d7ef13",
+      "declaredLicense": "MPL-2.0",
+      "selectedLicense": "MPL-2.0",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5",
+          "bytes": 16725,
+          "upstream": {
+            "repository": "https://github.com/mozilla/uniffi-rs",
+            "commit": "35a47433d8f015302fbf608f2b395eff6972c36f",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "uniffi_pipeline",
+      "version": "0.32.1",
+      "checksum": "55179706fbb6e7a23e729780d2c6165e6afe1ce725fa63754bcf217b440afc04",
+      "declaredLicense": "MPL-2.0",
+      "selectedLicense": "MPL-2.0",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5",
+          "bytes": 16725,
+          "upstream": {
+            "repository": "https://github.com/mozilla/uniffi-rs",
+            "commit": "35a47433d8f015302fbf608f2b395eff6972c36f",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "winnow",
+      "version": "1.0.3",
+      "checksum": "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "cb5aedb296c5246d1f22e9099f925a65146f9f0d6b4eebba97fd27a6cdbbab2d",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "xattr",
+      "version": "1.6.1",
+      "checksum": "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36",
+          "bytes": 1056
+        }
+      ]
+    },
+    {
+      "name": "zmij",
+      "version": "1.0.21",
+      "checksum": "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "zstd-safe",
+      "version": "7.2.4",
+      "checksum": "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63",
+          "bytes": 18
+        },
+        {
+          "name": "LICENSE.Apache-2.0",
+          "sha256": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
+          "bytes": 10174
+        },
+        {
+          "name": "LICENSE.Mit",
+          "sha256": "129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8",
+          "bytes": 1080
+        }
+      ]
+    },
+    {
+      "name": "zstd-sys",
+      "version": "2.0.16+zstd.1.5.7",
+      "checksum": "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748",
+      "declaredLicense": "MIT/Apache-2.0",
+      "selectedLicense": "MIT AND BSD-3-Clause",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63",
+          "bytes": 18
+        },
+        {
+          "name": "LICENSE.Apache-2.0",
+          "sha256": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
+          "bytes": 10174
+        },
+        {
+          "name": "LICENSE.BSD-3-Clause",
+          "sha256": "48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd",
+          "bytes": 1595
+        },
+        {
+          "name": "LICENSE.Mit",
+          "sha256": "129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8",
+          "bytes": 1080
+        },
+        {
+          "name": "zstd/COPYING",
+          "sha256": "f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505",
+          "bytes": 18091
+        },
+        {
+          "name": "zstd/LICENSE",
+          "sha256": "7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8",
+          "bytes": 1549
+        }
+      ]
+    },
+    {
+      "name": "zstd",
+      "version": "0.13.3",
+      "checksum": "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": [
+        "android-arm",
+        "android-arm64",
+        "android-x86",
+        "android-x86_64",
+        "ios-arm64",
+        "ios-simulator-arm64",
+        "macos-arm64"
+      ],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8",
+          "bytes": 1080
+        }
+      ]
+    }
+  ]
+}
diff --git a/src/sdks/rust/mobile-bindings/moon.yml b/src/sdks/rust/mobile-bindings/moon.yml
new file mode 100644
index 000000000..d4153bbde
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/moon.yml
@@ -0,0 +1,72 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+id: "oliphaunt-mobile-bindings"
+language: "rust"
+tags: ["cargo-package"]
+layer: "library"
+stack: "systems"
+dependsOn:
+  - "oliphaunt-rust"
+  - "liboliphaunt-native-bindings"
+  - id: "oliphaunt-query"
+    scope: "build"
+fileGroups:
+  cargo-sources:
+    - "uniffi.toml"
+    - "tools/generate.sh"
+tasks:
+  dependency-license-audit:
+    tags: ["quality", "static", "requires-rust"]
+    command: "bash tools/packaging/audit-rust-dependency-licenses.sh src/sdks/rust/mobile-bindings/tools/dependency-license-contract.mts oliphaunt-mobile-bindings"
+    inputs:
+      - "dependency-licenses.json"
+      - "dependency-license-blobs/**/*"
+      - "tools/dependency-license-contract.mts"
+      - "/Cargo.lock"
+      - "/**/Cargo.toml"
+      - "/tools/packaging/audit-rust-dependency-licenses.sh"
+      - "/tools/packaging/rust-dependency-license-contract.mts"
+      - "/tools/packaging/release-directory-safety.mts"
+    options:
+      runFromWorkspaceRoot: true
+
+  format:
+    command: "cargo fmt"
+    options:
+      cache: false
+      runInCI: false
+  format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt --check"
+    inputs: ["src/**/*", "build.rs", "Cargo.toml"]
+  lint:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy --locked --all-targets -- -D warnings"
+    inputs: ["src/**/*", "build.rs", "Cargo.toml", "/Cargo.lock", "/Cargo.toml"]
+  build:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["build", "requires-rust"]
+    command: "cargo build --locked --lib"
+    # Consumers also use Cargo's native libraries, not only generated declarations.
+    # Cargo owns incremental caching until all consumed artifacts are restorable.
+    options:
+      cache: false
+    inputs:
+      - "src/**/*"
+      - "build.rs"
+      - "Cargo.toml"
+      - "@group(cargo-workspace)"
+      - project: "oliphaunt-query"
+        group: "sources"
+  generate:
+    tags: ["build", "requires-rust"]
+    command: "bash tools/generate.sh"
+    options:
+      cache: false
+    deps: [{target: "cargo-sources", cacheStrategy: hash}]
+    inputs: ["src/**/*", "tools/generate.sh", "uniffi.toml", "Cargo.toml", "/Cargo.lock", "/Cargo.toml"]
+    outputs: ["/target/mobile-bindings/generated/**/*"]
diff --git a/src/sdks/rust/mobile-bindings/src/bin/bindgen.rs b/src/sdks/rust/mobile-bindings/src/bin/bindgen.rs
new file mode 100644
index 000000000..a01b54706
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/src/bin/bindgen.rs
@@ -0,0 +1,3 @@
+fn main() {
+    uniffi::uniffi_bindgen_main();
+}
diff --git a/src/sdks/rust/mobile-bindings/src/lib.rs b/src/sdks/rust/mobile-bindings/src/lib.rs
new file mode 100644
index 000000000..6d39d0b8e
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/src/lib.rs
@@ -0,0 +1,140 @@
+use liboliphaunt_native_bindings::NativeOpenOptions;
+use std::sync::Arc;
+
+uniffi::setup_scaffolding!();
+
+#[uniffi::export]
+pub async fn restore(
+    library_path: Option,
+    destination: String,
+    bytes: Vec,
+) -> Result<(), NativeError> {
+    Ok(oliphaunt::mobile::restore(library_path.map(Into::into), destination.into(), bytes).await?)
+}
+
+#[derive(Debug, thiserror::Error, uniffi::Error)]
+pub enum NativeError {
+    #[error("request was not submitted")]
+    NotSubmitted,
+    #[error("{detail}")]
+    Database { detail: String },
+    #[error("stream callback stopped delivery")]
+    Callback,
+}
+
+impl From for NativeError {
+    fn from(error: oliphaunt::Error) -> Self {
+        Self::Database {
+            detail: error.to_string(),
+        }
+    }
+}
+
+#[derive(uniffi::Record)]
+pub struct OpenOptions {
+    pub library_path: Option,
+    pub pgdata: String,
+    pub runtime_directory: Option,
+    pub module_directory: Option,
+    pub icu_data_directory: Option,
+    pub username: String,
+    pub database: String,
+    pub startup_args: Vec,
+}
+
+#[uniffi::export(callback_interface)]
+pub trait ChunkSink: Send + Sync {
+    fn on_chunk(&self, bytes: Vec) -> bool;
+}
+
+#[derive(uniffi::Object)]
+pub struct NativeDatabase {
+    database: oliphaunt::AsyncOliphaunt,
+}
+
+#[uniffi::export]
+impl NativeDatabase {
+    #[uniffi::constructor]
+    pub async fn open(options: OpenOptions) -> Result, NativeError> {
+        let database = oliphaunt::mobile::open(NativeOpenOptions {
+            library_path: options.library_path.map(Into::into),
+            pgdata: options.pgdata.into(),
+            runtime_directory: options.runtime_directory.map(Into::into),
+            module_directory: options.module_directory.map(Into::into),
+            icu_data_directory: options.icu_data_directory.map(Into::into),
+            username: options.username,
+            database: options.database,
+            startup_args: options.startup_args,
+        })
+        .await?;
+        Ok(Arc::new(Self { database }))
+    }
+
+    pub fn request(&self) -> Arc {
+        Arc::new(NativeRequest {
+            request: oliphaunt::mobile::Request::new(&self.database),
+        })
+    }
+
+    pub async fn cancel(&self) -> Result<(), NativeError> {
+        Ok(self.database.cancel().await?)
+    }
+    pub async fn backup(&self) -> Result, NativeError> {
+        Ok(self.database.backup().await?)
+    }
+    pub async fn detach(&self) -> Result<(), NativeError> {
+        Ok(self.database.close().await?)
+    }
+}
+
+#[derive(uniffi::Object)]
+pub struct NativeRequest {
+    request: oliphaunt::mobile::Request,
+}
+
+#[uniffi::export]
+impl NativeRequest {
+    pub async fn execute(&self, bytes: Vec) -> Result, NativeError> {
+        self.request.execute(bytes).await.map_err(|error| {
+            if self.request.was_cancelled() && !self.request.was_submitted() {
+                NativeError::NotSubmitted
+            } else {
+                error.into()
+            }
+        })
+    }
+
+    pub async fn stream(
+        &self,
+        bytes: Vec,
+        sink: Box,
+    ) -> Result<(), NativeError> {
+        self.request
+            .stream(bytes, move |chunk| {
+                if sink.on_chunk(chunk.to_vec()) {
+                    Ok(())
+                } else {
+                    Err(NativeError::Callback)
+                }
+            })
+            .await
+            .map_err(|error| {
+                if self.request.was_cancelled() && !self.request.was_submitted() {
+                    NativeError::NotSubmitted
+                } else {
+                    match error {
+                        oliphaunt::RawStreamError::Callback(error) => error,
+                        oliphaunt::RawStreamError::Database(error)
+                        | oliphaunt::RawStreamError::CallbackPanicked(error) => error.into(),
+                        other => NativeError::Database {
+                            detail: other.to_string(),
+                        },
+                    }
+                }
+            })
+    }
+
+    pub fn cancel(&self) -> Result<(), NativeError> {
+        Ok(self.request.cancel()?)
+    }
+}
diff --git a/src/sdks/rust/mobile-bindings/tools/build-android.sh b/src/sdks/rust/mobile-bindings/tools/build-android.sh
new file mode 100644
index 000000000..7703475df
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/tools/build-android.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+cd "$root"
+: "${ANDROID_NDK_HOME:?Set ANDROID_NDK_HOME to the Android build NDK}"
+case "${1:-arm64-v8a}" in
+  arm64-v8a) target=aarch64-linux-android; clang_target=aarch64-linux-android ;;
+  armeabi-v7a) target=armv7-linux-androideabi; clang_target=armv7a-linux-androideabi ;;
+  x86) target=i686-linux-android; clang_target=i686-linux-android ;;
+  x86_64) target=x86_64-linux-android; clang_target=x86_64-linux-android ;;
+  *) echo "unsupported Android ABI: $1" >&2; exit 2 ;;
+esac
+compiler_suffix=
+tool_suffix=
+case "$(uname -s)" in
+  Darwin) host=darwin-x86_64 ;;
+  Linux) host=linux-x86_64 ;;
+  MINGW*|MSYS*|CYGWIN*) host=windows-x86_64; compiler_suffix=.cmd; tool_suffix=.exe ;;
+  *) echo "unsupported NDK host: $(uname -s)" >&2; exit 2 ;;
+esac
+ndk_bin="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$host/bin"
+target_key="${target//-/_}"
+linker_key="$(printf '%s' "$target_key" | tr '[:lower:]' '[:upper:]')"
+env \
+  "CARGO_TARGET_${linker_key}_LINKER=$ndk_bin/${clang_target}${OLIPHAUNT_ANDROID_API:-24}-clang$compiler_suffix" \
+  "CC_${target_key}=$ndk_bin/${clang_target}${OLIPHAUNT_ANDROID_API:-24}-clang$compiler_suffix" \
+  "CXX_${target_key}=$ndk_bin/${clang_target}${OLIPHAUNT_ANDROID_API:-24}-clang++$compiler_suffix" \
+  "AR_${target_key}=$ndk_bin/llvm-ar$tool_suffix" \
+  cargo build --locked -p oliphaunt-mobile-bindings --target "$target" --release --lib
+if [[ -n "${2:-}" ]]; then
+  mkdir -p "$2/${1:-arm64-v8a}"
+  cp "${CARGO_TARGET_DIR:-$root/target}/$target/release/liboliphaunt_mobile_bindings.so" "$2/${1:-arm64-v8a}/"
+fi
+if [[ -n "${3:-}" ]]; then
+  case "${1:-arm64-v8a}" in
+    arm64-v8a) license_target=android-arm64 ;;
+    x86_64) license_target=android-x86_64 ;;
+    armeabi-v7a) license_target=android-arm ;;
+    x86) license_target=android-x86 ;;
+    *) echo "no mobile distribution license inventory for ABI $1" >&2; exit 2 ;;
+  esac
+  rm -rf -- "$3/oliphaunt-native-bindings/$license_target"
+  bash tools/dev/bun.sh tools/packaging/release-notices.mts stage \
+    "$3/oliphaunt-native-bindings/$license_target" --profile source-sdk
+  bash tools/dev/bun.sh src/sdks/rust/mobile-bindings/tools/dependency-license-contract.mts stage \
+    "$3/oliphaunt-native-bindings/$license_target" --target "$license_target"
+fi
diff --git a/src/sdks/rust/mobile-bindings/tools/dependency-license-contract.mts b/src/sdks/rust/mobile-bindings/tools/dependency-license-contract.mts
new file mode 100644
index 000000000..c73fa224a
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/tools/dependency-license-contract.mts
@@ -0,0 +1,27 @@
+import { createRustDependencyLicenseContract } from '../../../../../tools/packaging/rust-dependency-license-contract.mts';
+
+const contract = createRustDependencyLicenseContract({
+  owner: 'src/sdks/rust/mobile-bindings',
+  product: 'oliphaunt-mobile-bindings',
+  payloadLicense: 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause AND MPL-2.0',
+  targets: [
+    { id: 'android-arm64', cargoTarget: 'aarch64-linux-android' },
+    { id: 'android-x86_64', cargoTarget: 'x86_64-linux-android' },
+    { id: 'android-arm', cargoTarget: 'armv7-linux-androideabi' },
+    { id: 'android-x86', cargoTarget: 'i686-linux-android' },
+    { id: 'ios-arm64', cargoTarget: 'aarch64-apple-ios' },
+    { id: 'ios-simulator-arm64', cargoTarget: 'aarch64-apple-ios-sim' },
+    { id: 'macos-arm64', cargoTarget: 'aarch64-apple-darwin' },
+  ],
+});
+export const {
+  RUST_DEPENDENCY_LICENSE_ROOT,
+  RUST_PAYLOAD_LICENSE,
+  loadRustDependencyLicenseContract,
+  rustDependencyLicenseMembers,
+  stageRustDependencyLicenses,
+  assertRustDependencyLicensesInDirectory,
+  assertRustDependencyLicensesInEntries,
+  assertRustDependencyLicensesInArchive,
+} = contract;
+if (import.meta.main) contract.runCli();
diff --git a/src/sdks/rust/mobile-bindings/tools/generate.sh b/src/sdks/rust/mobile-bindings/tools/generate.sh
new file mode 100644
index 000000000..8e689b936
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/tools/generate.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+cd "$root"
+case "$(uname -s)" in
+  Darwin) library=liboliphaunt_mobile_bindings.dylib ;;
+  Linux) library=liboliphaunt_mobile_bindings.so ;;
+  MINGW*|MSYS*|CYGWIN*) library=oliphaunt_mobile_bindings.dll ;;
+  *) echo "unsupported generation host: $(uname -s)" >&2; exit 2 ;;
+esac
+cargo build --locked -p oliphaunt-mobile-bindings --features bindgen
+mkdir -p "$root/target/mobile-bindings"
+stage="$(mktemp -d "$root/target/mobile-bindings/generated.XXXXXX")"
+trap 'rm -rf "$stage"' EXIT
+"${CARGO_TARGET_DIR:-$root/target}/debug/oliphaunt-mobile-bindgen" \
+  generate --library "${CARGO_TARGET_DIR:-$root/target}/debug/$library" \
+  --config src/sdks/rust/mobile-bindings/uniffi.toml \
+  --language swift --language kotlin --no-format \
+  --out-dir "$stage"
+rm -rf "$root/target/mobile-bindings/generated"
+mv "$stage" "$root/target/mobile-bindings/generated"
diff --git a/src/sdks/rust/mobile-bindings/uniffi.toml b/src/sdks/rust/mobile-bindings/uniffi.toml
new file mode 100644
index 000000000..33188f23b
--- /dev/null
+++ b/src/sdks/rust/mobile-bindings/uniffi.toml
@@ -0,0 +1,9 @@
+[crates.oliphaunt_mobile_bindings.bindings.swift]
+module_name = "OliphauntNativeBindings"
+ffi_module_name = "OliphauntNativeBindingsFFI"
+
+[crates.oliphaunt_mobile_bindings.bindings.kotlin]
+package_name = "dev.oliphaunt.bindings"
+cdylib_name = "oliphaunt_mobile_bindings"
+# JNA's cleaner supports Android API 24 and the JVM test host.
+disable_java_cleaner = true
diff --git a/src/sdks/rust/moon.yml b/src/sdks/rust/moon.yml
deleted file mode 100644
index 5a4935a39..000000000
--- a/src/sdks/rust/moon.yml
+++ /dev/null
@@ -1,192 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "oliphaunt-rust"
-language: "rust"
-layer: "library"
-stack: "systems"
-tags: ["sdk", "rust", "tauri", "native", "release-product"]
-dependsOn:
-  - id: "shared-test-fixtures"
-    scope: "development"
-  - id: "extensions"
-    scope: "build"
-  - "liboliphaunt-native"
-  - "shared-rust-query-core"
-
-project:
-  title: "Oliphaunt Rust SDK"
-  description: "Canonical Rust SDK for native embedded PostgreSQL in Tauri and Rust desktop apps."
-  owner: "oliphaunt"
-  release:
-    component: "oliphaunt-rust"
-    packagePath: "src/sdks/rust"
-
-owners:
-  defaultOwner: "@oliphaunt/sdk-rust"
-  paths:
-    "**/*.rs": ["@oliphaunt/sdk-rust"]
-    "Cargo.toml": ["@oliphaunt/sdk-rust"]
-
-fileGroups:
-  code:
-    - "**/*"
-    - "!**/*.md"
-    - "!moon.yml"
-    - "!release.toml"
-
-tasks:
-  compile:
-    tags: ["quality", "static", "requires-rust"]
-    script: |
-      set -e
-      cargo check -p oliphaunt --locked --all-targets
-      cargo check -p oliphaunt-build --locked --all-targets
-    env:
-      CARGO_TARGET_DIR: "target/moon/oliphaunt-rust/check"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "/clippy.toml"
-      - project: "shared-rust-query-core"
-        group: "sources"
-      - "@group(code)"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  unit-distinct:
-    tags: ["quality", "unit", "requires-rust"]
-    script: |
-      set -e
-      mkdir -p "$CARGO_TARGET_DIR"
-      if [ -n "${CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER:-}" ]; then
-        rustc --edition=2024 --test src/sdks/rust/build.rs -C "linker=$CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER" -o "$CARGO_TARGET_DIR/build-script-tests"
-      else
-        rustc --edition=2024 --test src/sdks/rust/build.rs -o "$CARGO_TARGET_DIR/build-script-tests"
-      fi
-      "$CARGO_TARGET_DIR/build-script-tests"
-      cargo test -p oliphaunt --doc --locked
-      cargo test -p oliphaunt-build --locked
-    env:
-      CARGO_TARGET_DIR: "target/moon/oliphaunt-rust/test"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "@group(rust-test-config)"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - project: "shared-rust-query-core"
-        group: "sources"
-      - "@group(code)"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  unit-shared:
-    command: "cargo nextest run -p oliphaunt --locked --profile ci --no-tests=fail --lib --test public_api --test sdk_extensions"
-    env:
-      CARGO_TARGET_DIR: "target/moon/oliphaunt-rust/test"
-    inputs:
-      - "@group(cargo-workspace)"
-      - "@group(rust-test-config)"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - project: "shared-rust-query-core"
-        group: "sources"
-      - "@group(code)"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-      runInCI: false
-  unit:
-    command: "true"
-    deps:
-      - "oliphaunt-rust:unit-distinct"
-      - "oliphaunt-rust:unit-shared"
-    inputs: []
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: false
-  package:
-    tags: ["package"]
-    script: |
-      set -e
-      node src/sdks/rust/tools/package-source.mjs
-      cargo package --manifest-path target/liboliphaunt-sdk-check/oliphaunt-rust/package-source/Cargo.toml --allow-dirty --no-verify
-      cargo package --manifest-path target/liboliphaunt-sdk-check/oliphaunt-rust/package-source/Cargo.toml --allow-dirty --list > target/liboliphaunt-sdk-check/rust-cargo-package-list.txt
-      cargo package -p oliphaunt-build --locked --allow-dirty --no-verify
-    env:
-      CARGO_TARGET_DIR: "target/moon/oliphaunt-rust/package"
-    inputs:
-      - "@group(legal-files)"
-      - "@group(cargo-workspace)"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - project: "shared-rust-query-core"
-        group: "sources"
-      - "**/*"
-    outputs:
-      - "/target/liboliphaunt-sdk-check/rust-cargo-package-list.txt"
-      - "/target/liboliphaunt-sdk-check/oliphaunt-rust/package-source/**/*"
-      - "/target/moon/oliphaunt-rust/package/package/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  qualify:
-    tags: ["release", "package"]
-    command: "true"
-    deps:
-      - "oliphaunt-rust:compile"
-      - "oliphaunt-rust:unit-distinct"
-      - "oliphaunt-rust:package"
-      - "oliphaunt-rust:regression"
-    inputs: []
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  regression:
-    tags: ["regression", "runtime"]
-    script: |
-      set -e
-      . src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh
-      oliphaunt_runtime_native_host_require basic
-      cargo test -p oliphaunt --locked --test native_smoke --test native_sql_regression -- --test-threads=1
-    env:
-      CARGO_TARGET_DIR: "target/moon/oliphaunt-rust/regression"
-    deps:
-      - "liboliphaunt-native:host-smoke"
-    inputs:
-      - "@group(cargo-workspace)"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - project: "shared-rust-query-core"
-        group: "sources"
-      - "@group(code)"
-      - "/src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh"
-    options:
-      cache: local
-      runFromWorkspaceRoot: true
-  extension-regression:
-    tags: ["regression", "runtime", "extensions"]
-    script: |
-      set -e
-      . src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh
-      oliphaunt_runtime_native_host_require extensions
-      cargo test -p oliphaunt --locked --test native_extensions -- --test-threads=1
-    env:
-      CARGO_TARGET_DIR: "target/moon/oliphaunt-rust/extension-regression"
-    deps:
-      - "extension-artifacts-native:build-target"
-    inputs:
-      - "@group(cargo-workspace)"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - project: "shared-rust-query-core"
-        group: "sources"
-      - project: "extensions"
-        group: "build"
-      - project: "liboliphaunt-native"
-        group: "runtime"
-      - "@group(code)"
-      - "/src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh"
-    options:
-      cache: local
-      runFromWorkspaceRoot: true
-      runInCI: false
diff --git a/src/sdks/rust/release.toml b/src/sdks/rust/release.toml
deleted file mode 100644
index 9e8771017..000000000
--- a/src/sdks/rust/release.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-id = "oliphaunt-rust"
-owner = "@oliphaunt/sdk-rust"
-kind = "sdk"
-publish_targets = ["crates-io"]
-registry_packages = ["crates:oliphaunt", "crates:oliphaunt-build"]
-release_artifacts = ["cargo-crate", "runtime-resource-cli"]
-
-[compatibility_versions.native_runtime]
-source_product = "liboliphaunt-native"
-path = "src/sdks/rust/Cargo.toml"
-parser = "toml:package.metadata.oliphaunt.native-version"
-
-[compatibility_versions.broker_runtime]
-source_product = "oliphaunt-broker"
-path = "src/sdks/rust/Cargo.toml"
-parser = "toml:package.metadata.oliphaunt.broker-version"
-
-[compatibility_versions.broker_runtime_constant]
-source_product = "oliphaunt-broker"
-path = "src/sdks/rust/src/broker.rs"
-parser = "rust-const:BROKER_RELEASE_VERSION"
diff --git a/src/sdks/rust/.gitignore b/src/sdks/rust/sdk/.gitignore
similarity index 100%
rename from src/sdks/rust/.gitignore
rename to src/sdks/rust/sdk/.gitignore
diff --git a/src/sdks/rust/sdk/ARCHITECTURE.md b/src/sdks/rust/sdk/ARCHITECTURE.md
new file mode 100644
index 000000000..27a424399
--- /dev/null
+++ b/src/sdks/rust/sdk/ARCHITECTURE.md
@@ -0,0 +1,186 @@
+# Rust SDK architecture
+
+The Rust SDK is a native binding over `liboliphaunt`. It does not wrap the
+WASIX binding and has no runtime fallback matrix.
+
+## Public boundary
+
+The public database boundary is:
+
+- Root `Oliphaunt::open()` or `Oliphaunt::builder()` for synchronous,
+  exclusive direct and broker databases.
+- Root `AsyncOliphaunt::open()` or `AsyncOliphaunt::builder()` for the same
+  topology vocabulary on a dedicated owner thread with cloneable asynchronous
+  handles.
+- Dedicated `OliphauntServer::builder().start()` and
+  `AsyncOliphauntServer::builder().start().await` terminals for local-server
+  lifecycle handles.
+- PostgreSQL-shaped execute, query, parameter, result, transaction,
+  cancellation, raw protocol, and close methods on database handles.
+- Only `connection_string`, `is_closed`, and `close` on server handles; an
+  external driver or ORM owns SQL and protocol behavior.
+- One byte physical-backup method on direct and broker databases.
+- One static restore operation into an absent or empty destination.
+
+Internal engine modes, runtime profiles, lifecycle requests, backup envelopes,
+resource manifests, package reports, and protocol parsers are not public API.
+Database and server builders are distinct, so listener/server options cannot be
+combined with direct/broker options. Within the database builder,
+`broker_executable` is valid only after selecting `broker()`.
+
+## Runtime ownership
+
+Direct mode owns one embedded PostgreSQL backend in the application process.
+Broker mode owns the same backend in one authenticated helper process. These
+are database topologies, not scheduling modes. Root `Oliphaunt` handles block
+until either session completes; `AsyncOliphaunt` serializes either session on
+one owner thread.
+
+Server mode starts a normal local PostgreSQL server and returns
+`OliphauntServer` with a nonoptional libpq connection string. Startup readiness
+uses a short-lived probe; the lifecycle handle retains no privileged PostgreSQL
+connection. It is the only product that supports independent external client
+connections. Its handle has no physical-backup method because PostgreSQL already provides
+`pg_basebackup`; the optional endpoint-oriented `oliphaunt-tools` crate runs
+plain `pg_dump` and non-interactive `psql` without entering the core SDK API.
+
+The SDK keeps its engine traits and server wire client internal.
+`liboliphaunt-native-bindings` owns native execution, cancellation, physical
+backups, database resources, storage types, and extension metadata. The SDK
+adapts its session to those bindings and preserves its public error categories.
+The broker package owns its transport library and executable and depends on the
+native bindings directly. It does not depend on the public SDK.
+
+## Execution and transactions
+
+The root API is synchronous: its operations take `&mut self` and block the
+calling thread until the selected runtime reports completion. It does not add
+an SDK owner queue. Native direct mode nevertheless runs the embedded backend
+on `liboliphaunt`'s internal pthread; broker and server keep their own process
+or server boundaries. The contract is therefore caller blocking, not
+caller-thread PostgreSQL execution. The handle is `Send + !Sync`, so ownership
+may move between threads but references cannot be shared concurrently. A
+callback transaction exclusively borrows the database. Inline raw-stream
+callbacks may borrow caller state and cannot reenter the database through safe
+Rust while its mutable borrow is active.
+
+A broker handle owns exactly one helper-backed PostgreSQL session. Helper exit
+or IPC failure is terminal for that handle and retains the first failure; no
+runtime path launches a replacement beneath it. Explicit close cleans owned
+resources, and a new open on persistent storage is the only recovery boundary.
+Requests with unknown outcomes are never replayed.
+
+SQL uses PostgreSQL protocol 3.0 on the broker's SQL socket. A separate persistent
+authenticated management socket owns backup and shutdown; losing that socket
+retires the helper. The SQL write half progresses while the caller drains raw
+backend frames, so large pipelined requests and results cannot block each other.
+A callback error suppresses later callbacks while all requested ReadyForQuery
+boundaries drain. If a disconnected partial batch cannot drain, the helper exits
+instead of manufacturing Sync or silently replacing the session.
+
+The `AsyncOliphaunt` API constructs and calls its session on one permanent
+SDK-owned thread. A session is never opened on a temporary thread and then
+transferred. Cloneable `Send + Sync` handles share that owner; cloning does not
+create a PostgreSQL connection. The public name describes its calling contract;
+the owner thread is an implementation placement guarantee, not a Rust
+`Worker` abstraction.
+
+Asynchronous application work awaits fair, bounded admission before entering
+one FIFO. Saturation suspends the admitting future rather than returning a
+queue-full error. Transaction control, rollback cleanup, and close enter the
+same FIFO without consuming ordinary capacity, so queue pressure cannot strand
+lifecycle work and cannot reorder cleanup ahead of an already-admitted COMMIT.
+Close and command admission share one lock: work
+admitted before the close cutoff remains ahead of Close and drains, while later
+application work, including capacity waiters that never entered the FIFO, is
+rejected. A rejected pre-cutoff waiter cannot cross a retryable close attempt
+after admission reopens. The closing state is never used to invalidate a
+command that is already in the FIFO. If a queued `BEGIN` succeeds before Close,
+the owner rejects that close attempt with `TransactionActive`, restores open
+admission, and retains the session for retry. If an operation future is dropped
+before the owner starts it, the command is skipped. Once PostgreSQL execution
+starts, dropping the future is not cancellation and the owner completes through
+its readiness boundary. Required `COMMIT` and `ROLLBACK` settlement for a pin
+created by a pre-cutoff `BEGIN` remains admissible after the cutoff through a
+reserved, reentrancy-checked path and retains FIFO order with Close.
+
+A transaction pin rejects unrelated work while its callback is active. Body
+failure rolls back. A failed rollback poisons the session. COMMIT uncertainty
+never triggers a later ROLLBACK because PostgreSQL may already have committed;
+the session is poisoned unless PostgreSQL explicitly returns the known idle
+`ROLLBACK` command tag. Pin cleanup remains admissible after poisoning so close
+cannot strand the owner thread.
+
+A root transaction callback panic is contained until synchronous settlement
+completes and is then resumed when the outcome is known. An async transaction
+body panic unwinds the awaiting task immediately. Dropping its active
+transaction enqueues best-effort rollback in the same owner FIFO, so later work
+cannot overtake cleanup even though the unwind does not wait for it.
+
+Cancellation is out of band: the C cancellation hook in direct mode and a
+standard CancelRequest to the broker SQL endpoint using its fresh BackendKeyData.
+External clients of server
+mode own PostgreSQL CancelRequest through their driver. Root database callers
+obtain a separate `CancelHandle` before blocking when
+another thread must interrupt the operation. Asynchronous cancellation is
+asynchronous and does not wait in the ordinary FIFO. Close does not implicitly
+cancel active work. Root close is synchronous; async close is an ordered queue
+boundary with shared concurrent waiters. Once direct detach, broker shutdown,
+or server shutdown begins, either handle is terminal and retains one exact
+close result. A failed teardown is never followed by a second implicit teardown.
+Session and managed-root ownership is released only after successful teardown.
+On failure the SDK intentionally retains that ownership until process exit;
+leaking the failed owner is safer than running an unproven second destructor.
+Final asynchronous-handle `Drop` requests cleanup without joining the owner
+thread.
+
+Every asynchronous reply channel turns sender disappearance into
+`EngineStopped`; an owner panic therefore cannot strand callers. Runtime panics
+stop the owner and reject pending work. Raw-stream callback panics are contained
+before any C boundary. A typed adapter outcome distinguishes confirmed
+`ReadyForQuery` recovery from an independent runtime or transport failure. The
+blocking root resumes the original panic only after confirmed recovery; the
+async API returns a recovered owner-thread panic as
+`RawStreamError::CallbackPanicked` and leaves the session reusable. An
+unconfirmed recovery failure is authoritative, becomes
+`RawStreamError::Database`, and poisons the session until close. Callbacks are
+synchronous owner-thread code, so reentrant work on the same async handle is
+rejected rather than deadlocking. Root callbacks run inline and rely on the
+exclusive borrow instead of runtime reentrancy detection.
+
+## Storage and identity
+
+Public storage is either a caller-owned directory or an SDK-owned temporary
+directory. A persistent directory contains an outer `.oliphaunt.json`
+descriptor and `pgdata/`.
+
+Root validation is shared in contract, not by pretending all host filesystems
+are one implementation. The native adapter rejects symlink roots and symlink
+structural directories, validates PostgreSQL 18 PGDATA, and writes the exact
+five-field descriptor last. A sibling admission lock prevents multiple
+supported native owners from opening the same root. The lock is an internal
+lifecycle implementation detail, not a public cross-binding coordination mode.
+
+The descriptor records schema, engine family, PGDATA directory name,
+PostgreSQL major, and physical format. A valid native or WASIX family/format
+pair is accepted. Cross-family rejection and conversion are not part of root
+admission.
+
+Direct and broker backup bytes carry a PostgreSQL physical initialization
+payload. They do not carry the outer descriptor. Restore stages and validates
+PGDATA, then creates the receiving root identity. Existing nonempty destinations
+are rejected; there is no replacement option.
+
+## Artifacts and extensions
+
+Build and release tooling stages the runtime, PostgreSQL tools, templates, and
+selected extension artifacts. The SDK selects extensions by exact generated SQL
+name and passes only runtime-relevant selection into root preparation.
+
+Runtime materialization maintains two internal layouts where PostgreSQL requires
+them: embedded modules for direct/broker and standalone server modules. This is
+natural implementation separation, not a public capability profile.
+
+Performance profiles and diagnostic knobs belong to the perf harness. They must
+not leak into the SDK unless a concrete application need establishes a stable
+public contract.
diff --git a/src/sdks/rust/sdk/CHANGELOG.md b/src/sdks/rust/sdk/CHANGELOG.md
new file mode 100644
index 000000000..4c5512959
--- /dev/null
+++ b/src/sdks/rust/sdk/CHANGELOG.md
@@ -0,0 +1,117 @@
+# Changelog
+
+## Unreleased
+
+- **Breaking:** make root `Oliphaunt` the synchronous, exclusive database API
+  for direct and broker topologies, with a separate synchronous
+  `OliphauntServer` lifecycle handle. Calls block until completion without an
+  SDK owner-queue hop; native direct PostgreSQL still uses `liboliphaunt`'s
+  internal backend thread.
+- **Migration from 0.1.1:** the previously asynchronous root
+  `oliphaunt::Oliphaunt` is now `oliphaunt::AsyncOliphaunt`. Rename that type
+  (and its `AsyncOliphauntBuilder`, `AsyncOliphauntServer`, `AsyncSql`, and
+  `AsyncTransaction` companions where named) and keep the existing `.await`
+  calls. Use the new root `Oliphaunt` only when a blocking API is intended.
+- Expose the cloneable asynchronous owner-thread API through named root
+  `Async*` types; there is no public Rust `worker` namespace.
+- Add default `Oliphaunt::open()` and `AsyncOliphaunt::open()` terminals and
+  dedicated cloneable `OliphauntServerBuilder` / `AsyncOliphauntServerBuilder`
+  terminals ending in `start()`.
+- Add a thread-safe root `CancelHandle` so another thread can interrupt a
+  synchronous operation without making the database handle shareable.
+- Keep async restore and cancellation asynchronous, apply fair awaitable
+  backpressure to ordinary owner work while reserving FIFO lifecycle admission,
+  and make explicit close coalesced, phase-aware, and definitive. Capacity
+  waiters that miss a close cutoff remain rejected even if that close is
+  retryable. Root restore and close execute synchronously.
+- Prevent owner failures and dropped reply senders from stranding futures;
+  contain raw-stream callback panics and reject callback reentrancy. Typed
+  direct and broker stream outcomes now resume a blocking callback
+  panic only after confirmed `ReadyForQuery`; independent recovery failure is
+  authoritative and poisons the session.
+- **Breaking:** accept typed transaction and raw-stream callback errors. Callback
+  transactions now return `TransactionResult` / `TransactionError`;
+  streams accept `()` or `Result<(), E>` and return `RawStreamError`. Literal
+  rollback failure, independent database failure, recovered callback abort, and
+  recovered async callback panic remain distinct public outcomes.
+- **Breaking:** remove raw protocol methods from managed transaction handles;
+  arbitrary protocol bytes cannot preserve the SDK-owned transaction boundary.
+  Root database raw APIs remain available to protocol adapters which own their
+  complete lifecycle. Structured callback-transaction methods reject
+  `ROLLBACK`/`ABORT ... AND CHAIN` before dispatch while preserving savepoints
+  and `ROLLBACK TO`.
+- **Breaking:** make server handles endpoint/lifecycle-only. Use
+  `connection_string()` with a PostgreSQL driver or ORM for SQL, transactions,
+  cancellation, and raw protocol; server handles retain only `is_closed()` and
+  `close()`.
+- Validate an explicit native server executable before preparing persistent
+  storage, so a deterministic path error cannot initialize or alter PGDATA.
+- **Breaking:** make `Error` opaque and expose the shared non-exhaustive
+  `ErrorKind` recovery categories plus typed PostgreSQL and transaction-cause
+  accessors. `Error` no longer promises equality or destructuring stability.
+- **Breaking:** make `Extension` an opaque selector with uppercase associated
+  constants, `Extension::ALL`, `Extension::by_sql_name`, and `sql_name`; remove
+  the old free constants and PascalCase aliases. Selecting an artifact never
+  installs database-local extension objects.
+- **Breaking:** remove the redundant `QueryParam` wrapper. Use natural
+  `IntoParameter` values or `Parameter::{text,binary,null}` for dynamically
+  typed values. Execution rejects an explicitly attached OID 0; leave the OID
+  unset for execution-time inference, while `describe` continues to accept 0.
+  Multi-statement `exec` now retains each notice on its statement result as
+  well as in the operation-wide ordered notice list.
+- Keep required transaction settlement admissible across an ordered close
+  cutoff, and make every teardown-started close result terminal and replayable
+  to concurrent or repeated callers. Pin-release failures are never discarded,
+  poison lifecycle state, and failed teardown retains root ownership until
+  process exit rather than invoking a second destructor.
+- Keep out-of-band cancellation admissible while pre-cutoff SQL drains, with an
+  atomic rejection boundary at destructive teardown.
+- Split database and server builders so cross-topology options are
+  unrepresentable; `broker_executable` is still rejected unless `broker()` is
+  selected.
+- Snapshot each ABI 10 native operation error through its same-call
+  `*_with_error` capture; synchronous cancellation alone uses
+  `oliphaunt_copy_last_error` because the C ABI has no cancel capture variant.
+- Fail native broker handles permanently after helper exit or IPC failure.
+  Recovery now requires an explicit close and new open; the SDK never replaces
+  a session invisibly or replays work with an uncertain outcome.
+
+## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-rust-v0.1.1...oliphaunt-rust-v0.2.0) (2026-09-05)
+
+
+### ⚠ BREAKING CHANGES
+
+* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
+
+### Features
+
+* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))
+* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
+
+
+### Bug Fixes
+
+* **ci:** preserve native lifecycle server sessions ([#165](https://github.com/f0rr0/oliphaunt/issues/165)) ([b8cab0b](https://github.com/f0rr0/oliphaunt/commit/b8cab0be2b86c6b9fab4c279add89113c5797d23))
+
+
+### Code Refactoring
+
+* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
+* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
+* **release:** publish frozen candidates ([#181](https://github.com/f0rr0/oliphaunt/issues/181)) ([327b3fc](https://github.com/f0rr0/oliphaunt/commit/327b3fc7caf272b1dbbc355c687a3db34ccc96ac))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
+
+## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-rust-v0.1.0...oliphaunt-rust-v0.1.1) (2026-08-08)
+
+
+### Bug Fixes
+
+* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))
+
+## 0.1.0 (2026-07-28)
+
+
+### Features
+
+* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/sdks/rust/sdk/Cargo.toml b/src/sdks/rust/sdk/Cargo.toml
new file mode 100644
index 000000000..9953d37b1
--- /dev/null
+++ b/src/sdks/rust/sdk/Cargo.toml
@@ -0,0 +1,44 @@
+[package]
+name = "oliphaunt"
+version = "0.2.0"
+edition = "2024"
+rust-version = "1.93"
+description = "Native-first Rust SDK surface for embedded PostgreSQL through liboliphaunt."
+readme = "README.md"
+repository.workspace = true
+homepage.workspace = true
+license = "MIT"
+exclude = [
+  ".gitignore",
+  "crates/oliphaunt-build/**",
+  "moon.yml",
+  "release.toml",
+  "tools/**",
+]
+links = "oliphaunt_artifact_relay"
+build = "build.rs"
+
+[lib]
+name = "oliphaunt"
+path = "src/lib.rs"
+
+[features]
+default = ["desktop"]
+desktop = ["dep:oliphaunt-broker", "dep:getrandom"]
+mobile-bindings = []
+
+[package.metadata.oliphaunt]
+broker-helper = "oliphaunt-broker"
+broker-version = "0.2.0"
+native-version = "0.2.0"
+
+[dependencies]
+oliphaunt-broker = { path = "../../../broker", version = "0.2.0", optional = true }
+liboliphaunt-native-bindings = { version = "0.1.0", path = "../liboliphaunt-native" }
+oliphaunt-query = { version = "0.1.0", path = "../../rust-query" }
+getrandom = { version = "0.3", optional = true }
+
+[dev-dependencies]
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+tokio = { version = "1", features = ["rt", "time"] }
diff --git a/src/sdks/rust/sdk/README.md b/src/sdks/rust/sdk/README.md
new file mode 100644
index 000000000..bf4c73c7f
--- /dev/null
+++ b/src/sdks/rust/sdk/README.md
@@ -0,0 +1,339 @@
+# Oliphaunt Rust SDK
+
+`oliphaunt` embeds PostgreSQL 18 through the native `liboliphaunt` runtime. The
+public API is intentionally small and PostgreSQL-shaped: open, execute, query,
+exec, describe, transaction, cancel, physical backup, restore, and
+close. Dedicated server handles expose only endpoint and lifecycle state; use a
+PostgreSQL driver or ORM through their connection string.
+
+## Installation
+
+Add `oliphaunt` and use `oliphaunt-build` from the build script so the matching
+native runtime, tools, and selected extension artifacts are staged for the
+target platform.
+
+```rust
+fn main() {
+    oliphaunt_build::configure();
+}
+```
+
+## Execution placement and database topology
+
+Direct mode is the default. It runs the embedded backend in the application
+process. Broker mode uses the same database API while placing that backend in a
+helper process.
+
+The root API is synchronous and caller owned. `open`, SQL, backup, restore, and
+close block the calling thread until their result is available. They do not
+cross an SDK owner queue, but that is not a promise that PostgreSQL itself runs
+on the caller: native direct mode uses `liboliphaunt`'s internal backend thread,
+while broker and server topologies own their documented process or server
+boundaries. Synchronous database and server handles are exclusive,
+`Send + !Sync`, so ownership may move between threads but the same owner cannot
+be shared concurrently. This is the minimum-overhead path for CLIs, tests,
+dedicated application threads, and callers which already control scheduling.
+
+`Oliphaunt::open()` is the shortest default: it opens direct mode with an
+SDK-owned temporary directory. `AsyncOliphaunt::open().await` does the same on
+the async owner thread. Use the cloneable builders when configuration differs.
+
+```rust
+use oliphaunt::{DatabaseStorage, Oliphaunt};
+
+# fn example() -> oliphaunt::Result<()> {
+let mut db = Oliphaunt::builder()
+    .storage(DatabaseStorage::Directory(".oliphaunt".into()))
+    .startup_guc("application_name", "my-app")
+    .open()?;
+
+db.execute_with_params(
+    "INSERT INTO events(value) VALUES ($1)",
+    ["ready"],
+)?;
+let result = db.query("SELECT value FROM events")?;
+assert_eq!(result.get_text(0, "value")?, Some("ready"));
+db.close()?;
+# Ok(())
+# }
+```
+
+Use the named asynchronous handle when the calling executor must remain
+responsive:
+
+```rust
+use oliphaunt::AsyncOliphaunt;
+
+# async fn example() -> oliphaunt::Result<()> {
+let db = AsyncOliphaunt::open().await?;
+let rows = db.query("SELECT 42::int4 AS answer").await?;
+assert_eq!(rows.get_text(0, "answer")?, Some("42"));
+db.close().await?;
+# Ok(())
+# }
+```
+
+`AsyncOliphaunt` and `AsyncOliphauntServer` are cloneable and `Send + Sync`.
+Open constructs the selected topology on a permanent SDK-owned thread. Ordinary
+calls await fair, bounded admission before entering one owner FIFO; saturation
+applies async backpressure instead of blocking the executor or returning a
+queue-full error. Blocking runtime work occupies the owner, not the executor
+thread polling the future. Rust futures do not imply a thread by themselves;
+this placement is an explicit Oliphaunt guarantee. Dropping a pending future is
+not query cancellation.
+
+Select broker mode with `.broker()`. An explicit
+`.broker_executable(path)` is normally only needed by development and packaging
+harnesses; installed packages resolve their helper artifact automatically.
+SQL and cancellation use PostgreSQL's wire protocol. The SDK separately owns a
+management connection for physical backup and process shutdown.
+If the helper exits or IPC fails, the database handle permanently rejects later
+work. Close it and explicitly open a new handle on the same persistent root for
+PostgreSQL WAL recovery; the SDK never substitutes a fresh session or replays an
+uncertain request under the old handle.
+The database builder represents only direct and broker databases;
+`broker_executable` requires `broker().open()`. Local servers have a dedicated
+`OliphauntServer::builder()` / `AsyncOliphauntServer::builder()` ending in
+`start()`, so server-only and database-only options cannot be mixed.
+
+`execute` and `execute_with_params` assert one command with no rows. `query` and
+`query_with_params` accept a command-only or row-producing statement and return
+ordered raw cells, complete field metadata, command metadata, notices, and
+typed access through `FromSql`. `exec` returns ordered command-or-rows results
+for simple-query SQL, while `describe` resolves parameter OIDs and optional
+result fields without executing. Call `db.describe(sql)` for an unparameterized
+statement, or `db.sql(sql).bind(...).describe()` when PostgreSQL needs explicit
+parameter values or type OIDs.
+
+Natural Rust values passed to `bind` or the `*_with_params` methods use
+`IntoParameter` and carry their PostgreSQL type OID and preferred encoding.
+`Parameter` provides explicit `TypeOid`, `ValueFormat`, and nullable owned
+bytes for typed nulls and extension types. Its `text`, `binary`, and `null`
+constructors deliberately leave the OID unspecified for PostgreSQL to infer.
+An absent OID is the single execution spelling for inference. `describe` also
+accepts explicit OID 0 because it is PostgreSQL's wire-level inference sentinel.
+Typed
+getters validate OID and format, reject ambiguous duplicate names, and preserve
+raw access as the lossless fallback. SQL errors are structured `PostgresError`
+values with operation notices. The public `Error` is opaque and cloneable;
+match its non-exhaustive `ErrorKind` through `kind()` and use typed accessors
+for PostgreSQL and paired transaction failures instead of destructuring or
+comparing implementation errors.
+
+`is_closed()` reports that the database handle is terminally retired.
+The synchronous `transaction` exclusively borrows its database; the async
+variant pins its one physical session and rejects unrelated clone work. Both
+transaction handles mirror query, execute, exec, and describe. One-shot
+`rollback()` closes the transaction and lets its callback return without
+committing. A failed rollback or uncertain COMMIT poisons the database and does
+not issue a misleading second control command.
+
+Transaction callbacks return ordinary `Result` with `E: From`.
+Database calls therefore use `?`, while a business rule can return its own
+concrete error. The outer `TransactionResult` reports `TransactionError`:
+`CallbackAndRollback` means rollback was actually attempted and failed;
+`CallbackAndDatabase` means an independent database, transport, or recovery
+failure had already expired the transaction and no rollback was sent. SDK-only
+callbacks keep the concise `oliphaunt::Result` call shape through `From`
+conversions.
+
+Managed transaction handles expose structured SQL, not raw protocol. Return an
+error from the callback or call `Transaction::rollback()` instead of issuing
+`BEGIN`, `COMMIT`, full `ROLLBACK`, or prepared-transaction control as SQL.
+Savepoints and `ROLLBACK TO SAVEPOINT` remain valid. Manual lifecycle SQL,
+including `AND CHAIN`, is unsupported; a protocol response that proves
+ownership escaped makes the database close-only. Protocol adapters that own the
+entire lifecycle can use the raw APIs on the root database handle.
+
+Synchronous `close()` blocks through teardown and replays its first terminal
+result. Asynchronous `close().await` is an ordered queue boundary: operations
+already in the owner FIFO drain, including an admitted `BEGIN`, while capacity
+waiters and later work are rejected.
+Once either variant begins runtime teardown, the handle is terminal even if
+teardown reports an error. Successful teardown releases the session and its
+managed-root ownership. A failed teardown intentionally retains that ownership
+until process exit so no implicit destructor can repeat an unproven destructive
+cleanup.
+
+For COPY or another protocol flow that the structured helpers cannot represent,
+use `exec_protocol_raw` for one owned response or
+`exec_protocol_raw_stream` to consume backend protocol chunks as they arrive.
+The stream is the raw PostgreSQL protocol; the SDK does not publish a second
+parser or a separate COPY-specific abstraction. Synchronous callbacks execute
+inline and may borrow caller state. Asynchronous callbacks execute serially on
+the owner thread and therefore require `Send + 'static`. In both cases the
+borrowed chunk is valid only until the callback returns, slow callbacks apply
+backpressure, and callback panics are contained before crossing the native ABI.
+Return `()` for infallible delivery without type annotations, or
+`Result<(), E>` for a typed parser/application stop. `RawStreamError::Callback`
+is produced only after confirmed recovery.
+The synchronous API resumes the original panic only after its adapter confirms
+`ReadyForQuery`; the async API returns a recovered owner-thread panic as
+`RawStreamError::CallbackPanicked` and leaves the session reusable. If transport
+or runtime recovery fails independently, `RawStreamError::Database` takes
+precedence and the session rejects further work until close.
+
+`AsyncOliphaunt::cancel().await` sends cancellation out of band. For the
+synchronous root, obtain `db.cancel_handle()` before a long call and move that
+cloneable, thread-safe capability to the thread which may interrupt it. Calling
+`cancel()` on the database itself is immediate but cannot interrupt code already
+blocking the same thread. Cancellation never replaces observing the original
+operation, which reports PostgreSQL's final result.
+
+## Physical backup and restore
+
+Direct and broker databases expose one physical backup format as bytes. Restore
+is a static operation into an absent or empty destination. It never overwrites
+an existing managed database.
+
+```rust
+use oliphaunt::{DatabaseStorage, Oliphaunt};
+
+# fn example() -> oliphaunt::Result<()> {
+let mut source = Oliphaunt::builder()
+    .storage(DatabaseStorage::Directory(".oliphaunt-source".into()))
+    .open()?;
+let backup = source.backup()?;
+source.close()?;
+
+Oliphaunt::restore(".oliphaunt-restored", backup)?;
+# Ok(())
+# }
+```
+
+The archive is a PostgreSQL physical initialization payload. It contains
+PGDATA and its backup metadata, not the outer managed-root descriptor. Restore
+creates and validates the receiving root and publishes `.oliphaunt.json` only
+after complete PGDATA exists. Root restore blocks synchronously;
+`AsyncOliphaunt::restore` copies its input and moves native and filesystem work
+to a dedicated thread.
+
+## Local server
+
+`OliphauntServer::builder().start()` returns a lifecycle handle with a
+nonoptional libpq connection string for standard PostgreSQL clients. The handle
+deliberately does not hide a privileged SDK query session: SQL, transactions,
+pools, cancellation, and raw protocol are owned by the external driver or ORM.
+Its stable surface is `connection_string()`, `is_closed()`, and `close()`.
+`is_closed()` reports SDK lifecycle state only; it does not poll the PostgreSQL
+child or guarantee that the endpoint is currently reachable. Use the ordinary
+driver or pool connected to `connection_string()` for connection health.
+
+The default listener is IPv4 loopback with an automatically assigned port.
+Select a fixed loopback port or, on Unix hosts, a PostgreSQL socket directory.
+Unix socket directories must resolve to valid UTF-8 so the returned connection
+string preserves the exact path for Rust drivers and ORMs:
+
+```rust,no_run
+use oliphaunt::{OliphauntServer, ServerListen};
+
+# fn open() -> oliphaunt::Result<()> {
+let mut server = OliphauntServer::builder()
+    .listen(ServerListen::tcp_port(15432))
+    .start()?;
+println!("{}", server.connection_string());
+server.close()?;
+# Ok(())
+# }
+```
+
+The dedicated server builder has no `.direct()` or `.broker()` selector and
+the database builders have no listener options. The split makes invalid
+cross-topology configuration unrepresentable.
+
+The server handle deliberately has no SDK backup method. Use `pg_basebackup`
+for a standard server physical backup. The optional `oliphaunt-tools` crate
+provides endpoint-oriented plain `pg_dump` and non-interactive `psql` runners;
+the core `oliphaunt` crate does not depend on or install client tools.
+
+```rust,no_run
+use oliphaunt_tools::{PgDumpOptions, pg_dump};
+
+# fn dump(connection_string: &str) -> Result {
+pg_dump(connection_string, PgDumpOptions::new().arg("--schema-only"))
+# }
+```
+
+Pass `server.connection_string()` to the standard tool and keep PostgreSQL's
+streamed-WAL behavior explicit:
+
+```sh
+pg_basebackup --dbname "$CONNECTION_STRING" --pgdata ./server-backup --wal-method=stream
+```
+
+## Storage ownership
+
+A persistent database is a managed root:
+
+```text
+.oliphaunt.json
+pgdata/
+```
+
+The descriptor has one exact five-field schema: schema name, engine family,
+PGDATA directory name, PostgreSQL major, and physical format. It describes the
+root layout; it is not a lock file and it does not encode an SDK or host
+language. Native and WASIX descriptors are both valid when family and format
+form one of the two defined pairs.
+
+Opening validates before mutating. Existing roots must have PostgreSQL 18
+`PG_VERSION`, a real `global` directory with nonempty `global/pg_control`, and a
+real `pg_wal` directory. Symlink roots and symlink structural directories are
+rejected. The descriptor is written last during initialization.
+
+The SDK prevents two supported owners from opening the same managed root at the
+same time by using a sibling admission lock. It does not add a public cross-SDK
+coordination protocol, and concurrent mutation by unrelated runtimes remains
+application error.
+
+## Extensions and platform support
+
+Choose extensions with `.extension(Extension::...)` or `.extensions(...)`.
+Selection uses exact PostgreSQL SQL names and the generated PostgreSQL 18
+catalog. `Extension` is an opaque `Copy + Eq + Hash + Ord` selector with
+uppercase associated constants, `ALL`, `by_sql_name`, and `sql_name`. Selection
+makes artifacts and required pre-start configuration available but never runs
+`CREATE EXTENSION`, `LOAD`, or migration SQL. Build and release tooling owns
+artifact resolution; the runtime API does not expose package manifests, size
+reports, capability profiles, or packaging internals.
+
+Supported native products and targets are declared by the repository SDK
+manifest and release packages. WASIX is a separate binding family and is not a
+fallback mode of this crate.
+
+## Maintainer commands
+
+Seeds and ICU data are independently selected resources; default builders use
+`initdb` for new storage. Both sync and async database builders accept
+`.seed(NativeClusterSeed::new(seed_archive, seed_manifest))` and
+`.icu_data(NativeResourceDirectory { directory, manifest })`. Those input types
+are reexported by `oliphaunt`. Server builders accept ICU data but not embedded
+seeds. Existing roots ignore seed bytes. Broker mode prepares an explicitly
+selected Cargo seed through the shared guarded initializer before starting its
+helper process.
+
+The ignored `broker_initializes_explicit_cargo_seed_and_reopens_without_seed`
+test in `native_smoke` exercises that public SDK boundary. With a built runtime,
+set `LIBOLIPHAUNT_PATH`, `OLIPHAUNT_INSTALL_DIR`, `OLIPHAUNT_EMBEDDED_MODULE_DIR`,
+`OLIPHAUNT_BROKER`, and `OLIPHAUNT_TEST_STANDARD_SEED` (a carrier directory with
+`seed.tar.zst` and `manifest.json`), then run:
+
+```sh
+cargo test --locked --test native_smoke broker_initializes_explicit_cargo_seed_and_reopens_without_seed -- --ignored --exact
+```
+
+Run these commands from this directory with the repository-pinned Rust toolchain, Moon and Bun available. Cargo resolves versioned workspace dependencies itself; no runtime build is needed for source tests. Bash is required for package staging (Git Bash on Windows). The initial locked Cargo fetch needs network access.
+
+| Command | Result |
+| --- | --- |
+| `moon run oliphaunt-rust:format` | Rewrite Rust formatting. |
+| `moon run oliphaunt-rust:format-check` | Check formatting without changing files. |
+| `moon run oliphaunt-rust:lint` | Clippy diagnostics for all targets; no database execution. |
+| `moon run oliphaunt-rust:build` | Compile this project and its Cargo dependencies. |
+| `moon run oliphaunt-rust:test` | Run source tests; Cargo compiles the required test targets. |
+| `moon run oliphaunt-rust:package` | Stage distributable source crates under target/sdk-artifacts/oliphaunt-rust; repeated runs replace this owner’s candidates. |
+| `moon run oliphaunt-rust:test-consumer` | Package prerequisites, then check the extracted candidate and its dependency closure in a disposable consumer workspace. |
+
+Native Cargo entry points remain available: `cargo build -p oliphaunt -p oliphaunt-build --locked`, `cargo test -p oliphaunt -p oliphaunt-build --locked`, `cargo clippy -p oliphaunt -p oliphaunt-build --all-targets --locked -- -D warnings`, and `cargo fmt -p oliphaunt -p oliphaunt-build --check`. Moon supplies the additional source-test feature matrix and artifact staging where defined. `package` assembles bytes; it does not run the project test suite.
+
+`moon run oliphaunt-rust:test-integration` builds the native runtime prerequisites and runs real database smoke/SQL tests. `test-extensions` additionally requires native extension artifacts. The packaged consumer command produces a portable proof executable; CI runs it against the independently produced runtime/extension artifacts.
diff --git a/src/sdks/rust/sdk/build.rs b/src/sdks/rust/sdk/build.rs
new file mode 100644
index 000000000..99bf5b36f
--- /dev/null
+++ b/src/sdks/rust/sdk/build.rs
@@ -0,0 +1,127 @@
+use std::collections::BTreeMap;
+use std::env;
+
+const ARTIFACT_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_";
+const ARTIFACT_ENV_SUFFIX: &str = "_MANIFEST";
+const RELAY_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_RELAY_";
+
+fn main() {
+    match relay_manifest_instructions(env::vars()) {
+        Ok(instructions) => {
+            for instruction in instructions {
+                println!("{instruction}");
+            }
+        }
+        Err(error) => {
+            println!("cargo::error={error}");
+            panic!("oliphaunt artifact relay failed: {error}");
+        }
+    }
+}
+
+fn relay_manifest_instructions(vars: I) -> Result, String>
+where
+    I: IntoIterator,
+{
+    let mut manifests = BTreeMap::new();
+    let mut instructions = Vec::new();
+    for (key, value) in vars {
+        let Some(metadata_key) = relay_metadata_key(&key) else {
+            continue;
+        };
+        if value.is_empty() {
+            continue;
+        }
+        if let Some(existing) = manifests.insert(metadata_key.clone(), value.clone())
+            && existing != value
+        {
+            return Err(format!(
+                "conflicting Cargo artifact manifests for metadata key {metadata_key}: {existing} and {value}"
+            ));
+        }
+        instructions.push(format!("cargo::rerun-if-changed={value}"));
+    }
+    for (metadata_key, manifest) in manifests {
+        instructions.push(format!("cargo::metadata={metadata_key}={manifest}"));
+    }
+    Ok(instructions)
+}
+
+fn relay_metadata_key(env_key: &str) -> Option {
+    if env_key.starts_with(RELAY_ENV_PREFIX) {
+        return None;
+    }
+    let stem = env_key
+        .strip_prefix(ARTIFACT_ENV_PREFIX)?
+        .strip_suffix(ARTIFACT_ENV_SUFFIX)?;
+    if stem.is_empty() {
+        return None;
+    }
+    Some(format!("{}_manifest", stem.to_ascii_lowercase()))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn ignores_unrelated_and_empty_vars() {
+        let instructions = relay_manifest_instructions([
+            ("TARGET".to_owned(), "x86_64-unknown-linux-gnu".to_owned()),
+            (
+                "DEP_OLIPHAUNT_ARTIFACT_BROKER_LINUX_X64_GNU_MANIFEST".to_owned(),
+                String::new(),
+            ),
+        ])
+        .unwrap();
+        assert!(instructions.is_empty());
+    }
+
+    #[test]
+    fn re_emits_multiple_artifact_manifests() {
+        let instructions = relay_manifest_instructions([
+            (
+                "DEP_OLIPHAUNT_ARTIFACT_BROKER_LINUX_X64_GNU_MANIFEST".to_owned(),
+                "/tmp/broker.toml".to_owned(),
+            ),
+            (
+                "DEP_OLIPHAUNT_ARTIFACT_NATIVE_LINUX_X64_GNU_MANIFEST".to_owned(),
+                "/tmp/native.toml".to_owned(),
+            ),
+        ])
+        .unwrap();
+        assert!(instructions.contains(&"cargo::rerun-if-changed=/tmp/broker.toml".to_owned()));
+        assert!(instructions.contains(
+            &"cargo::metadata=broker_linux_x64_gnu_manifest=/tmp/broker.toml".to_owned()
+        ));
+        assert!(instructions.contains(
+            &"cargo::metadata=native_linux_x64_gnu_manifest=/tmp/native.toml".to_owned()
+        ));
+    }
+
+    #[test]
+    fn does_not_relay_its_own_downstream_metadata() {
+        let instructions = relay_manifest_instructions([(
+            "DEP_OLIPHAUNT_ARTIFACT_RELAY_BROKER_HELPER_MANIFEST".to_owned(),
+            "/tmp/broker.toml".to_owned(),
+        )])
+        .unwrap();
+        assert!(instructions.is_empty());
+    }
+
+    #[test]
+    fn rejects_conflicting_duplicate_keys() {
+        let error = relay_manifest_instructions([
+            (
+                "DEP_OLIPHAUNT_ARTIFACT_BROKER_MANIFEST".to_owned(),
+                "/tmp/one.toml".to_owned(),
+            ),
+            (
+                "DEP_OLIPHAUNT_ARTIFACT_BROKER_MANIFEST".to_owned(),
+                "/tmp/two.toml".to_owned(),
+            ),
+        ])
+        .expect_err("conflicting duplicate metadata keys must fail");
+        assert!(error.contains("conflicting Cargo artifact manifests"));
+    }
+}
diff --git a/src/sdks/rust/crates/oliphaunt-build/Cargo.toml b/src/sdks/rust/sdk/crates/oliphaunt-build/Cargo.toml
similarity index 100%
rename from src/sdks/rust/crates/oliphaunt-build/Cargo.toml
rename to src/sdks/rust/sdk/crates/oliphaunt-build/Cargo.toml
diff --git a/src/sdks/rust/crates/oliphaunt-build/README.md b/src/sdks/rust/sdk/crates/oliphaunt-build/README.md
similarity index 100%
rename from src/sdks/rust/crates/oliphaunt-build/README.md
rename to src/sdks/rust/sdk/crates/oliphaunt-build/README.md
diff --git a/src/sdks/rust/sdk/crates/oliphaunt-build/src/lib.rs b/src/sdks/rust/sdk/crates/oliphaunt-build/src/lib.rs
new file mode 100644
index 000000000..16cfa4d23
--- /dev/null
+++ b/src/sdks/rust/sdk/crates/oliphaunt-build/src/lib.rs
@@ -0,0 +1,2730 @@
+//! Cargo build-script integration for Oliphaunt applications.
+//!
+//! `configure()` is intended to be called from an application `build.rs`.
+//! Cargo resolves target-specific artifact crates; this crate stages the
+//! already-resolved files into `OUT_DIR`.
+
+use serde::{Deserialize, Serialize};
+use sha2::{Digest, Sha256};
+use std::collections::{BTreeMap, BTreeSet};
+use std::env;
+use std::ffi::OsString;
+use std::fmt;
+use std::fs;
+use std::io;
+use std::path::{Component, Path, PathBuf};
+
+const LOCK_SCHEMA: &str = "oliphaunt-assets-lock-v1";
+const ARTIFACT_SCHEMA: &str = "oliphaunt-artifact-manifest-v1";
+const ARTIFACT_BUNDLE_SCHEMA: &str = "oliphaunt-artifact-manifest-v2";
+const ARTIFACT_ENV_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_";
+const ARTIFACT_ENV_SUFFIX: &str = "_MANIFEST";
+
+/// Run Oliphaunt build-script configuration and fail the Cargo build on error.
+pub fn configure() {
+    match try_configure() {
+        Ok(output) => {
+            for instruction in output.cargo_instructions {
+                println!("{instruction}");
+            }
+        }
+        Err(error) => {
+            println!("cargo::error={error}");
+            panic!("oliphaunt-build failed: {error}");
+        }
+    }
+}
+
+/// Run Oliphaunt build-script configuration from Cargo-provided environment.
+pub fn try_configure() -> Result {
+    BuildContext::from_env()?.configure()
+}
+
+/// Successful build-script output.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct BuildOutput {
+    pub resources_dir: PathBuf,
+    pub lock_file: PathBuf,
+    pub generated_rust: PathBuf,
+    pub cargo_instructions: Vec,
+}
+
+#[derive(Debug, Clone)]
+struct BuildContext {
+    manifest_dir: PathBuf,
+    out_dir: PathBuf,
+    target: String,
+    artifact_manifest_paths: Vec,
+}
+
+impl BuildContext {
+    fn from_env() -> Result {
+        let vars: BTreeMap = env::vars_os()
+            .filter_map(|(key, value)| key.into_string().ok().map(|key| (key, value)))
+            .collect();
+        let manifest_dir = required_path_var(&vars, "CARGO_MANIFEST_DIR")?;
+        let out_dir = required_path_var(&vars, "OUT_DIR")?;
+        let target = required_string_var(&vars, "TARGET")?;
+        let artifact_manifest_paths = vars
+            .iter()
+            .filter(|(key, value)| {
+                key.starts_with(ARTIFACT_ENV_PREFIX)
+                    && key.ends_with(ARTIFACT_ENV_SUFFIX)
+                    && !value.is_empty()
+            })
+            .map(|(_, value)| PathBuf::from(value))
+            .collect();
+        Ok(Self {
+            manifest_dir,
+            out_dir,
+            target,
+            artifact_manifest_paths,
+        })
+    }
+
+    fn configure(&self) -> Result {
+        let cargo_toml = self.manifest_dir.join("Cargo.toml");
+        let app = read_application_manifest(&cargo_toml)?;
+        let metadata = &app.package.metadata.oliphaunt;
+        let artifacts = self.read_artifact_manifests()?;
+        let selected = select_artifacts(&app, &artifacts, &self.target)?;
+
+        let root = self.out_dir.join("oliphaunt");
+        let resources_dir = root.join("resources");
+        let lock_file = root.join("oliphaunt-assets.lock");
+        let generated_rust = root.join("oliphaunt_assets.rs");
+
+        if resources_dir.exists() {
+            fs::remove_dir_all(&resources_dir).map_err(|source| {
+                Error::io(
+                    "clean stale Oliphaunt resources directory",
+                    &resources_dir,
+                    source,
+                )
+            })?;
+        }
+        fs::create_dir_all(&resources_dir).map_err(|source| {
+            Error::io(
+                "create Oliphaunt resources directory",
+                &resources_dir,
+                source,
+            )
+        })?;
+        fs::create_dir_all(&root)
+            .map_err(|source| Error::io("create Oliphaunt OUT_DIR", &root, source))?;
+
+        let staged = stage_artifacts(&selected, &resources_dir)?;
+        write_lock_file(&lock_file, metadata, &self.target, &staged)?;
+        write_generated_rust(&generated_rust, &resources_dir, &lock_file)?;
+
+        let mut cargo_instructions = vec![
+            format!("cargo::rerun-if-changed={}", cargo_toml.display()),
+            format!(
+                "cargo::rustc-env=OLIPHAUNT_RESOURCES_DIR={}",
+                resources_dir.display()
+            ),
+            format!(
+                "cargo::rustc-env=OLIPHAUNT_ASSETS_LOCK={}",
+                lock_file.display()
+            ),
+            format!(
+                "cargo::rustc-env=OLIPHAUNT_ASSETS_RS={}",
+                generated_rust.display()
+            ),
+        ];
+        for manifest in &self.artifact_manifest_paths {
+            cargo_instructions.push(format!("cargo::rerun-if-changed={}", manifest.display()));
+        }
+        for artifact in &selected {
+            for file in &artifact.files {
+                cargo_instructions
+                    .push(format!("cargo::rerun-if-changed={}", file.source.display()));
+            }
+        }
+
+        Ok(BuildOutput {
+            resources_dir,
+            lock_file,
+            generated_rust,
+            cargo_instructions,
+        })
+    }
+
+    fn read_artifact_manifests(&self) -> Result> {
+        let mut artifacts = Vec::new();
+        let mut seen = BTreeSet::new();
+        for path in &self.artifact_manifest_paths {
+            let canonical = path.canonicalize().unwrap_or_else(|_| path.clone());
+            if !seen.insert(canonical) {
+                continue;
+            }
+            let text = fs::read_to_string(path)
+                .map_err(|source| Error::io("read Oliphaunt artifact manifest", path, source))?;
+            let document: ArtifactManifestDocument =
+                toml::from_str(&text).map_err(|source| Error::parse(path, source))?;
+            for mut manifest in document.into_manifests(path)? {
+                manifest.source_manifest = Some(path.clone());
+                manifest.validate()?;
+                artifacts.push(manifest);
+            }
+        }
+        Ok(artifacts)
+    }
+}
+
+fn required_path_var(vars: &BTreeMap, key: &str) -> Result {
+    vars.get(key)
+        .map(PathBuf::from)
+        .filter(|path| !path.as_os_str().is_empty())
+        .ok_or_else(|| Error::new(format!("Cargo did not set {key}")))
+}
+
+fn required_string_var(vars: &BTreeMap, key: &str) -> Result {
+    vars.get(key)
+        .and_then(|value| value.clone().into_string().ok())
+        .filter(|value| !value.is_empty())
+        .ok_or_else(|| Error::new(format!("Cargo did not set {key}")))
+}
+
+fn read_application_manifest(path: &Path) -> Result {
+    let text = fs::read_to_string(path)
+        .map_err(|source| Error::io("read application Cargo.toml", path, source))?;
+    let manifest: ApplicationManifest =
+        toml::from_str(&text).map_err(|source| Error::parse(path, source))?;
+    manifest.package.metadata.oliphaunt.validate()?;
+    Ok(manifest)
+}
+
+fn select_artifacts(
+    app: &ApplicationManifest,
+    artifacts: &[ArtifactManifest],
+    target: &str,
+) -> Result> {
+    let metadata = &app.package.metadata.oliphaunt;
+    let extension_target = if metadata.runtime == "liboliphaunt-wasix" {
+        "portable"
+    } else {
+        target
+    };
+    let mut extension_artifacts = resolve_extension_artifacts(
+        artifacts,
+        &metadata.extensions,
+        extension_target,
+        &metadata.runtime,
+        &metadata.runtime_version,
+    )?;
+    if metadata.runtime == "liboliphaunt-wasix" {
+        let portable_extensions = extension_artifacts
+            .iter()
+            .filter_map(|artifact| artifact.extension.clone())
+            .collect::>();
+        for extension in portable_extensions {
+            if let Some(aot) = optional_extension_artifact(
+                artifacts,
+                &extension,
+                target,
+                &metadata.runtime,
+                &metadata.runtime_version,
+            )? {
+                extension_artifacts.push(aot);
+            }
+        }
+    }
+    let selected_extensions: BTreeSet<&str> = extension_artifacts
+        .iter()
+        .filter_map(|artifact| artifact.extension.as_deref())
+        .collect();
+    for artifact in artifacts {
+        if artifact.kind == ArtifactKind::Extension {
+            let extension = artifact.extension.as_deref().ok_or_else(|| {
+                Error::new(format!(
+                    "{} extension artifact is missing extension name",
+                    artifact.label()
+                ))
+            })?;
+            if !selected_extensions.contains(extension) && !artifact.bundle_member {
+                return Err(Error::new(format!(
+                    "{} was provided by Cargo but extension {extension:?} is not selected in [package.metadata.oliphaunt]",
+                    artifact.label()
+                )));
+            }
+        }
+    }
+
+    let mut selected = Vec::new();
+    match metadata.runtime.as_str() {
+        "liboliphaunt-native" => {
+            selected.push(require_artifact(
+                artifacts,
+                "liboliphaunt-native",
+                Some(&metadata.runtime_version),
+                ArtifactKind::NativeRuntime,
+                target,
+                "selected native runtime",
+            )?);
+            selected.push(require_artifact(
+                artifacts,
+                "oliphaunt-broker",
+                None,
+                ArtifactKind::BrokerHelper,
+                target,
+                "selected native broker helper",
+            )?);
+            if app.depends_on("oliphaunt-tools") {
+                selected.push(require_artifact(
+                    artifacts,
+                    "oliphaunt-tools",
+                    None,
+                    ArtifactKind::NativeTools,
+                    target,
+                    "selected native PostgreSQL tools",
+                )?);
+            }
+        }
+        "liboliphaunt-wasix" => {
+            selected.push(require_artifact(
+                artifacts,
+                "liboliphaunt-wasix",
+                Some(&metadata.runtime_version),
+                ArtifactKind::WasixRuntime,
+                "portable",
+                "selected WASIX portable runtime",
+            )?);
+            selected.push(require_artifact(
+                artifacts,
+                "liboliphaunt-wasix",
+                Some(&metadata.runtime_version),
+                ArtifactKind::WasixAot,
+                target,
+                "selected WASIX AOT runtime",
+            )?);
+            if app.oliphaunt_wasix_tools_enabled() {
+                selected.push(require_artifact(
+                    artifacts,
+                    "oliphaunt-wasix-tools",
+                    None,
+                    ArtifactKind::WasixTools,
+                    "portable",
+                    "selected WASIX tools",
+                )?);
+                selected.push(require_artifact(
+                    artifacts,
+                    "oliphaunt-wasix-tools",
+                    None,
+                    ArtifactKind::WasixToolsAot,
+                    target,
+                    "selected WASIX tools AOT runtime",
+                )?);
+            }
+        }
+        other => {
+            return Err(Error::new(format!(
+                "unsupported [package.metadata.oliphaunt] runtime {other:?}; use \"liboliphaunt-native\" or \"liboliphaunt-wasix\""
+            )));
+        }
+    }
+
+    if metadata.icu {
+        selected.push(require_artifact(
+            artifacts,
+            "oliphaunt-icu",
+            None,
+            ArtifactKind::IcuData,
+            "portable",
+            "selected ICU data",
+        )?);
+    }
+
+    selected.extend(extension_artifacts);
+
+    Ok(selected)
+}
+
+fn resolve_extension_artifacts(
+    artifacts: &[ArtifactManifest],
+    requested: &[String],
+    target: &str,
+    runtime_product: &str,
+    runtime_version: &str,
+) -> Result> {
+    fn visit(
+        extension: &str,
+        artifacts: &[ArtifactManifest],
+        target: &str,
+        runtime_product: &str,
+        runtime_version: &str,
+        visiting: &mut Vec,
+        resolved: &mut BTreeMap,
+    ) -> Result<()> {
+        if resolved.contains_key(extension) {
+            return Ok(());
+        }
+        if let Some(position) = visiting.iter().position(|candidate| candidate == extension) {
+            let mut cycle = visiting[position..].to_vec();
+            cycle.push(extension.to_owned());
+            return Err(Error::new(format!(
+                "Oliphaunt extension dependency cycle: {}",
+                cycle.join(" -> ")
+            )));
+        }
+        let artifact = require_extension_artifact(
+            artifacts,
+            extension,
+            target,
+            runtime_product,
+            runtime_version,
+        )?;
+        visiting.push(extension.to_owned());
+        for dependency in &artifact.dependencies {
+            visit(
+                dependency,
+                artifacts,
+                target,
+                runtime_product,
+                runtime_version,
+                visiting,
+                resolved,
+            )?;
+        }
+        visiting.pop();
+        resolved.insert(extension.to_owned(), artifact);
+        Ok(())
+    }
+
+    let mut visiting = Vec::new();
+    let mut resolved = BTreeMap::new();
+    for extension in requested {
+        visit(
+            extension,
+            artifacts,
+            target,
+            runtime_product,
+            runtime_version,
+            &mut visiting,
+            &mut resolved,
+        )?;
+    }
+    Ok(resolved.into_values().collect())
+}
+
+fn require_artifact(
+    artifacts: &[ArtifactManifest],
+    product: &str,
+    version: Option<&str>,
+    kind: ArtifactKind,
+    target: &str,
+    label: &str,
+) -> Result {
+    let matches: Vec<_> = artifacts
+        .iter()
+        .filter(|artifact| {
+            artifact.product == product
+                && version.is_none_or(|version| artifact.version == version)
+                && artifact.kind == kind
+                && artifact.target == target
+        })
+        .cloned()
+        .collect();
+    let version_label = version
+        .map(|version| format!(" version={version}"))
+        .unwrap_or_default();
+    if matches.len() > 1 {
+        return Err(Error::new(format!(
+            "multiple Cargo-resolved Oliphaunt artifacts match {label}: product={product}{version_label} kind={} target={target}",
+            kind.as_str()
+        )));
+    }
+    matches
+        .into_iter()
+        .next()
+        .ok_or_else(|| {
+            Error::new(format!(
+                "missing Cargo-resolved Oliphaunt artifact for {label}: product={product}{version_label} kind={} target={target}",
+                kind.as_str()
+            ))
+        })
+}
+
+fn require_extension_artifact(
+    artifacts: &[ArtifactManifest],
+    extension: &str,
+    target: &str,
+    runtime_product: &str,
+    runtime_version: &str,
+) -> Result {
+    let candidates: Vec<_> = artifacts
+        .iter()
+        .filter(|artifact| {
+            artifact.kind == ArtifactKind::Extension
+                && artifact.target == target
+                && artifact.extension.as_deref() == Some(extension)
+        })
+        .collect();
+    let matches: Vec<_> = candidates
+        .iter()
+        .filter(|artifact| {
+            artifact.runtime_product.as_deref() == Some(runtime_product)
+                && artifact.runtime_version.as_deref() == Some(runtime_version)
+        })
+        .map(|artifact| (**artifact).clone())
+        .collect();
+    if matches.len() > 1 {
+        return Err(Error::new(format!(
+            "multiple Cargo-resolved Oliphaunt extension artifacts match extension={extension} target={target} runtime={runtime_product} runtime-version={runtime_version}"
+        )));
+    }
+    if let Some(found) = matches.into_iter().next() {
+        return Ok(found);
+    }
+    if !candidates.is_empty() {
+        let bindings = candidates
+            .iter()
+            .map(|artifact| {
+                format!(
+                    "{}@{}",
+                    artifact.runtime_product.as_deref().unwrap_or(""),
+                    artifact.runtime_version.as_deref().unwrap_or("")
+                )
+            })
+            .collect::>()
+            .into_iter()
+            .collect::>()
+            .join(", ");
+        return Err(Error::new(format!(
+            "Cargo-resolved Oliphaunt extension artifact runtime mismatch for extension={extension} target={target}: app selects {runtime_product}@{runtime_version}, artifact binds [{bindings}]"
+        )));
+    }
+    Err(Error::new(format!(
+        "missing Cargo-resolved Oliphaunt extension artifact for extension={extension} target={target} runtime={runtime_product} runtime-version={runtime_version}"
+    )))
+}
+
+fn optional_extension_artifact(
+    artifacts: &[ArtifactManifest],
+    extension: &str,
+    target: &str,
+    runtime_product: &str,
+    runtime_version: &str,
+) -> Result> {
+    if !artifacts.iter().any(|artifact| {
+        artifact.kind == ArtifactKind::Extension
+            && artifact.target == target
+            && artifact.extension.as_deref() == Some(extension)
+    }) {
+        return Ok(None);
+    }
+    require_extension_artifact(
+        artifacts,
+        extension,
+        target,
+        runtime_product,
+        runtime_version,
+    )
+    .map(Some)
+}
+
+fn stage_artifacts(
+    artifacts: &[ArtifactManifest],
+    resources_dir: &Path,
+) -> Result> {
+    let mut staged = Vec::new();
+    for artifact in artifacts {
+        let artifact_dir = resources_dir
+            .join(artifact.kind.as_str())
+            .join(&artifact.product);
+        let mut locked_files = Vec::new();
+        for file in &artifact.files {
+            let relative = checked_relative_path(&file.relative)?;
+            let dest = artifact_dir.join(&relative);
+            let bytes = fs::read(&file.source).map_err(|source| {
+                Error::io("read Oliphaunt artifact file", &file.source, source)
+            })?;
+            let actual = sha256_hex(&bytes);
+            if actual != file.sha256 {
+                return Err(Error::new(format!(
+                    "checksum mismatch for {}: manifest={} actual={actual}",
+                    file.source.display(),
+                    file.sha256
+                )));
+            }
+            if let Some(parent) = dest.parent() {
+                fs::create_dir_all(parent).map_err(|source| {
+                    Error::io("create staged artifact directory", parent, source)
+                })?;
+            }
+            if dest.is_file() {
+                let existing = fs::read(&dest).map_err(|source| {
+                    Error::io("read colliding staged artifact file", &dest, source)
+                })?;
+                let existing_sha256 = sha256_hex(&existing);
+                if existing_sha256 != file.sha256 {
+                    return Err(Error::new(format!(
+                        "selected artifacts collide at {} with different bytes: existing={} incoming={}",
+                        dest.display(),
+                        existing_sha256,
+                        file.sha256
+                    )));
+                }
+            }
+            fs::write(&dest, bytes).map_err(|source| {
+                Error::io("write staged Oliphaunt artifact file", &dest, source)
+            })?;
+            set_executable_if_needed(&dest, file.executable)?;
+            locked_files.push(LockedFile {
+                path: dest
+                    .strip_prefix(resources_dir)
+                    .unwrap_or(&dest)
+                    .to_string_lossy()
+                    .replace('\\', "/"),
+                sha256: file.sha256.clone(),
+                executable: file.executable,
+            });
+        }
+        staged.push(LockedArtifact {
+            product: artifact.product.clone(),
+            version: artifact.version.clone(),
+            kind: artifact.kind.as_str().to_owned(),
+            target: artifact.target.clone(),
+            extension: artifact.extension.clone(),
+            runtime_product: artifact.runtime_product.clone(),
+            runtime_version: artifact.runtime_version.clone(),
+            files: locked_files,
+        });
+    }
+    Ok(staged)
+}
+
+fn checked_relative_path(path: &str) -> Result {
+    let value = Path::new(path);
+    if value.is_absolute()
+        || value
+            .components()
+            .any(|component| matches!(component, Component::ParentDir | Component::Prefix(_)))
+    {
+        return Err(Error::new(format!(
+            "artifact relative path must stay inside resources directory: {path:?}"
+        )));
+    }
+    Ok(value.to_path_buf())
+}
+
+fn set_executable_if_needed(path: &Path, executable: bool) -> Result<()> {
+    if !executable {
+        return Ok(());
+    }
+    #[cfg(unix)]
+    {
+        use std::os::unix::fs::PermissionsExt;
+        let mut permissions = fs::metadata(path)
+            .map_err(|source| Error::io("read staged file permissions", path, source))?
+            .permissions();
+        permissions.set_mode(0o755);
+        fs::set_permissions(path, permissions)
+            .map_err(|source| Error::io("set staged file executable bit", path, source))?;
+    }
+    Ok(())
+}
+
+fn write_lock_file(
+    path: &Path,
+    metadata: &OliphauntMetadata,
+    target: &str,
+    artifacts: &[LockedArtifact],
+) -> Result<()> {
+    let lock = LockFile {
+        schema: LOCK_SCHEMA.to_owned(),
+        target: target.to_owned(),
+        runtime: metadata.runtime.clone(),
+        runtime_version: metadata.runtime_version.clone(),
+        icu: metadata.icu,
+        extensions: metadata.extensions.clone(),
+        artifacts: artifacts.to_vec(),
+    };
+    let text = toml::to_string_pretty(&lock)
+        .map_err(|source| Error::new(format!("serialize Oliphaunt assets lock: {source}")))?;
+    fs::write(path, text).map_err(|source| Error::io("write Oliphaunt assets lock", path, source))
+}
+
+fn write_generated_rust(path: &Path, resources_dir: &Path, lock_file: &Path) -> Result<()> {
+    let text = format!(
+        "pub const OLIPHAUNT_RESOURCES_DIR: &str = {:?};\npub const OLIPHAUNT_ASSETS_LOCK: &str = {:?};\n",
+        resources_dir.display().to_string(),
+        lock_file.display().to_string(),
+    );
+    fs::write(path, text)
+        .map_err(|source| Error::io("write generated Oliphaunt Rust constants", path, source))
+}
+
+fn sha256_hex(bytes: &[u8]) -> String {
+    let digest = Sha256::digest(bytes);
+    let mut out = String::with_capacity(digest.len() * 2);
+    for byte in digest {
+        use std::fmt::Write as _;
+        let _ = write!(&mut out, "{byte:02x}");
+    }
+    out
+}
+
+fn dependencies_enable_feature(
+    dependencies: &BTreeMap,
+    package: &str,
+    feature: &str,
+) -> bool {
+    dependencies
+        .iter()
+        .any(|(name, spec)| dependency_enables_feature(name, spec, package, feature))
+}
+
+fn dependencies_contain_package(
+    dependencies: &BTreeMap,
+    package: &str,
+) -> bool {
+    dependencies.iter().any(|(name, spec)| match spec {
+        toml::Value::String(_) => name == package,
+        toml::Value::Table(table) => {
+            table
+                .get("package")
+                .and_then(toml::Value::as_str)
+                .unwrap_or(name)
+                == package
+        }
+        _ => false,
+    })
+}
+
+fn dependency_enables_feature(
+    name: &str,
+    spec: &toml::Value,
+    package: &str,
+    feature: &str,
+) -> bool {
+    let toml::Value::Table(table) = spec else {
+        return false;
+    };
+    let dependency_name = table
+        .get("package")
+        .and_then(toml::Value::as_str)
+        .unwrap_or(name);
+    if dependency_name != package {
+        return false;
+    }
+    let Some(toml::Value::Array(features)) = table.get("features") else {
+        return false;
+    };
+    features
+        .iter()
+        .any(|candidate| candidate.as_str() == Some(feature))
+}
+
+#[derive(Debug, Deserialize)]
+struct ApplicationManifest {
+    package: ApplicationPackage,
+    #[serde(default)]
+    dependencies: BTreeMap,
+    #[serde(default)]
+    target: BTreeMap,
+}
+
+impl ApplicationManifest {
+    fn depends_on(&self, package: &str) -> bool {
+        dependencies_contain_package(&self.dependencies, package)
+            || self
+                .target
+                .values()
+                .any(|target| dependencies_contain_package(&target.dependencies, package))
+    }
+
+    fn oliphaunt_wasix_tools_enabled(&self) -> bool {
+        self.package.metadata.oliphaunt.tools
+            || dependencies_enable_feature(&self.dependencies, "oliphaunt-wasix", "tools")
+            || self.target.values().any(|target| {
+                dependencies_enable_feature(&target.dependencies, "oliphaunt-wasix", "tools")
+            })
+    }
+}
+
+#[derive(Debug, Default, Deserialize)]
+struct ApplicationTargetTable {
+    #[serde(default)]
+    dependencies: BTreeMap,
+}
+
+#[derive(Debug, Deserialize)]
+struct ApplicationPackage {
+    #[serde(default)]
+    metadata: ApplicationPackageMetadata,
+}
+
+#[derive(Debug, Default, Deserialize)]
+struct ApplicationPackageMetadata {
+    oliphaunt: OliphauntMetadata,
+}
+
+#[derive(Debug, Clone, Default, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+struct OliphauntMetadata {
+    runtime: String,
+    runtime_version: String,
+    #[serde(default)]
+    extensions: Vec,
+    #[serde(default)]
+    icu: bool,
+    #[serde(default)]
+    tools: bool,
+}
+
+impl OliphauntMetadata {
+    fn validate(&self) -> Result<()> {
+        if self.runtime.is_empty() {
+            return Err(Error::new(
+                "missing [package.metadata.oliphaunt].runtime".to_owned(),
+            ));
+        }
+        if self.runtime_version.is_empty() {
+            return Err(Error::new(
+                "missing [package.metadata.oliphaunt].runtime-version".to_owned(),
+            ));
+        }
+        let mut seen = BTreeSet::new();
+        for extension in &self.extensions {
+            if extension.is_empty() {
+                return Err(Error::new(
+                    "[package.metadata.oliphaunt].extensions must not contain empty names",
+                ));
+            }
+            if !seen.insert(extension) {
+                return Err(Error::new(format!(
+                    "duplicate [package.metadata.oliphaunt] extension {extension:?}"
+                )));
+            }
+        }
+        Ok(())
+    }
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "kebab-case", deny_unknown_fields)]
+struct ArtifactManifestDocument {
+    schema: String,
+    product: String,
+    version: String,
+    kind: ArtifactKind,
+    target: String,
+    runtime_product: Option,
+    runtime_version: Option,
+    extension: Option,
+    #[serde(default)]
+    dependencies: Vec,
+    #[serde(default)]
+    files: Vec,
+    #[serde(default)]
+    extensions: Vec,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(deny_unknown_fields)]
+struct ArtifactBundleMember {
+    extension: String,
+    #[serde(default)]
+    dependencies: Vec,
+    files: Vec,
+}
+
+impl ArtifactManifestDocument {
+    fn into_manifests(self, path: &Path) -> Result> {
+        let common_missing =
+            self.product.is_empty() || self.version.is_empty() || self.target.is_empty();
+        if common_missing {
+            return Err(Error::new(format!(
+                "{} must declare product, version, and target",
+                path.display()
+            )));
+        }
+        if self.schema == ARTIFACT_SCHEMA {
+            if !self.extensions.is_empty() {
+                return Err(Error::new(format!(
+                    "{} v1 artifact manifest must not declare extensions rows",
+                    path.display()
+                )));
+            }
+            return Ok(vec![ArtifactManifest {
+                schema: self.schema,
+                product: self.product,
+                version: self.version,
+                kind: self.kind,
+                target: self.target,
+                runtime_product: self.runtime_product,
+                runtime_version: self.runtime_version,
+                extension: self.extension,
+                dependencies: self.dependencies,
+                files: self.files,
+                bundle_member: false,
+                source_manifest: None,
+            }]);
+        }
+        if self.schema != ARTIFACT_BUNDLE_SCHEMA {
+            return Err(Error::new(format!(
+                "{} must use schema {ARTIFACT_SCHEMA:?} or {ARTIFACT_BUNDLE_SCHEMA:?}",
+                path.display()
+            )));
+        }
+        if self.kind != ArtifactKind::Extension
+            || self.extension.is_some()
+            || !self.dependencies.is_empty()
+            || !self.files.is_empty()
+            || self.extensions.len() < 2
+        {
+            return Err(Error::new(format!(
+                "{} v2 artifact bundle must be an extension kind with at least two member rows and no root extension/files",
+                path.display()
+            )));
+        }
+        let mut seen = BTreeSet::new();
+        let mut members = Vec::new();
+        for member in self.extensions {
+            if member.extension.is_empty() || !seen.insert(member.extension.clone()) {
+                return Err(Error::new(format!(
+                    "{} v2 artifact bundle has an empty or duplicate extension member",
+                    path.display()
+                )));
+            }
+            members.push(ArtifactManifest {
+                schema: ARTIFACT_SCHEMA.to_owned(),
+                product: self.product.clone(),
+                version: self.version.clone(),
+                kind: self.kind,
+                target: self.target.clone(),
+                runtime_product: self.runtime_product.clone(),
+                runtime_version: self.runtime_version.clone(),
+                extension: Some(member.extension),
+                dependencies: member.dependencies,
+                files: member.files,
+                bundle_member: true,
+                source_manifest: None,
+            });
+        }
+        if members
+            .windows(2)
+            .any(|pair| pair[0].extension.as_deref() >= pair[1].extension.as_deref())
+        {
+            return Err(Error::new(format!(
+                "{} v2 artifact bundle members must be sorted by extension",
+                path.display()
+            )));
+        }
+        Ok(members)
+    }
+}
+
+#[derive(Debug, Clone)]
+struct ArtifactManifest {
+    schema: String,
+    product: String,
+    version: String,
+    kind: ArtifactKind,
+    target: String,
+    runtime_product: Option,
+    runtime_version: Option,
+    extension: Option,
+    dependencies: Vec,
+    files: Vec,
+    bundle_member: bool,
+    source_manifest: Option,
+}
+
+impl ArtifactManifest {
+    fn validate(&self) -> Result<()> {
+        if self.schema != ARTIFACT_SCHEMA {
+            return Err(Error::new(format!(
+                "{} must use schema {ARTIFACT_SCHEMA:?}",
+                self.label()
+            )));
+        }
+        if self.product.is_empty() || self.version.is_empty() || self.target.is_empty() {
+            return Err(Error::new(format!(
+                "{} must declare product, version, and target",
+                self.label()
+            )));
+        }
+        if self.kind == ArtifactKind::Extension
+            && self.extension.as_deref().unwrap_or("").is_empty()
+        {
+            return Err(Error::new(format!(
+                "{} extension artifact must declare extension",
+                self.label()
+            )));
+        }
+        if self.kind == ArtifactKind::Extension {
+            if self.runtime_product.as_deref().unwrap_or("").is_empty()
+                || self.runtime_version.as_deref().unwrap_or("").is_empty()
+            {
+                return Err(Error::new(format!(
+                    "{} extension artifact must declare runtime-product and runtime-version",
+                    self.label()
+                )));
+            }
+            if !matches!(
+                self.runtime_product.as_deref(),
+                Some("liboliphaunt-native" | "liboliphaunt-wasix")
+            ) {
+                return Err(Error::new(format!(
+                    "{} extension artifact runtime-product must be liboliphaunt-native or liboliphaunt-wasix",
+                    self.label()
+                )));
+            }
+            let canonical_dependencies: BTreeSet<&str> =
+                self.dependencies.iter().map(String::as_str).collect();
+            if canonical_dependencies.len() != self.dependencies.len()
+                || self.dependencies.windows(2).any(|pair| pair[0] >= pair[1])
+                || self
+                    .extension
+                    .as_ref()
+                    .is_some_and(|extension| canonical_dependencies.contains(extension.as_str()))
+                || self.dependencies.iter().any(String::is_empty)
+            {
+                return Err(Error::new(format!(
+                    "{} extension dependencies must be sorted, unique, non-empty, and exclude itself",
+                    self.label()
+                )));
+            }
+        } else if self.runtime_product.is_some() || self.runtime_version.is_some() {
+            return Err(Error::new(format!(
+                "{} non-extension artifact must not declare runtime-product or runtime-version",
+                self.label()
+            )));
+        } else if !self.dependencies.is_empty() {
+            return Err(Error::new(format!(
+                "{} non-extension artifact must not declare extension dependencies",
+                self.label()
+            )));
+        }
+        if self.files.is_empty() {
+            return Err(Error::new(format!(
+                "{} must contain at least one file",
+                self.label()
+            )));
+        }
+        self.validate_product_kind()?;
+        self.validate_payload()?;
+        Ok(())
+    }
+
+    fn label(&self) -> String {
+        self.source_manifest
+            .as_ref()
+            .map(|path| path.display().to_string())
+            .unwrap_or_else(|| format!("{} {} {}", self.product, self.kind.as_str(), self.target))
+    }
+
+    fn validate_product_kind(&self) -> Result<()> {
+        let expected = match self.kind {
+            ArtifactKind::NativeRuntime => Some("liboliphaunt-native"),
+            ArtifactKind::NativeTools => Some("oliphaunt-tools"),
+            ArtifactKind::WasixRuntime | ArtifactKind::WasixAot => Some("liboliphaunt-wasix"),
+            ArtifactKind::WasixTools | ArtifactKind::WasixToolsAot => Some("oliphaunt-wasix-tools"),
+            ArtifactKind::BrokerHelper => Some("oliphaunt-broker"),
+            ArtifactKind::IcuData => Some("oliphaunt-icu"),
+            ArtifactKind::Extension => None,
+        };
+        if let Some(expected) = expected {
+            if self.product != expected {
+                return Err(Error::new(format!(
+                    "{} kind {} must use product {expected:?}",
+                    self.label(),
+                    self.kind.as_str()
+                )));
+            }
+        } else if !self.product.starts_with("oliphaunt-extension-") {
+            return Err(Error::new(format!(
+                "{} extension artifact product must start with \"oliphaunt-extension-\"",
+                self.label()
+            )));
+        }
+        Ok(())
+    }
+
+    fn validate_payload(&self) -> Result<()> {
+        let relatives: BTreeSet<&str> = self
+            .files
+            .iter()
+            .map(|file| file.relative.as_str())
+            .collect();
+        match self.kind {
+            ArtifactKind::NativeRuntime => {
+                self.require_files(
+                    &relatives,
+                    &native_tool_paths(&self.target, &["postgres", "initdb", "pg_ctl"]),
+                )?;
+                self.reject_files(
+                    &relatives,
+                    &native_tool_path_variants(&["pg_basebackup", "pg_dump", "psql"]),
+                )?;
+            }
+            ArtifactKind::NativeTools => {
+                self.require_files(
+                    &relatives,
+                    &native_tool_paths(&self.target, &["pg_basebackup", "pg_dump", "psql"]),
+                )?;
+                self.reject_files(
+                    &relatives,
+                    &native_tool_path_variants(&["postgres", "initdb", "pg_ctl"]),
+                )?;
+            }
+            ArtifactKind::WasixRuntime => {
+                self.require_files(
+                    &relatives,
+                    &["oliphaunt.wasix.tar.zst", "bin/initdb.wasix.wasm"],
+                )?;
+                self.reject_files(
+                    &relatives,
+                    &[
+                        "bin/pg_ctl.wasix.wasm",
+                        "bin/pg_dump.wasix.wasm",
+                        "bin/psql.wasix.wasm",
+                    ],
+                )?;
+            }
+            ArtifactKind::WasixTools => {
+                self.require_files(
+                    &relatives,
+                    &["bin/pg_dump.wasix.wasm", "bin/psql.wasix.wasm"],
+                )?;
+                self.reject_files(
+                    &relatives,
+                    &[
+                        "bin/postgres.wasix.wasm",
+                        "bin/initdb.wasix.wasm",
+                        "bin/pg_ctl.wasix.wasm",
+                    ],
+                )?;
+            }
+            ArtifactKind::WasixToolsAot => {
+                self.require_files(
+                    &relatives,
+                    &["pg_dump-llvm-opta.bin.zst", "psql-llvm-opta.bin.zst"],
+                )?;
+                self.reject_files(
+                    &relatives,
+                    &[
+                        "postgres-llvm-opta.bin.zst",
+                        "initdb-llvm-opta.bin.zst",
+                        "pg_ctl-llvm-opta.bin.zst",
+                    ],
+                )?;
+            }
+            ArtifactKind::WasixAot => {
+                self.require_files(&relatives, &["manifest.json"])?;
+                self.reject_files(
+                    &relatives,
+                    &[
+                        "pg_ctl-llvm-opta.bin.zst",
+                        "pg_dump-llvm-opta.bin.zst",
+                        "psql-llvm-opta.bin.zst",
+                    ],
+                )?;
+            }
+            ArtifactKind::BrokerHelper | ArtifactKind::IcuData | ArtifactKind::Extension => {}
+        }
+        Ok(())
+    }
+
+    fn require_files>(
+        &self,
+        relatives: &BTreeSet<&str>,
+        required: &[S],
+    ) -> Result<()> {
+        for relative in required {
+            let relative = relative.as_ref();
+            if !relatives.contains(relative) {
+                return Err(Error::new(format!(
+                    "{} {} artifact is missing required payload {relative:?}",
+                    self.label(),
+                    self.kind.as_str()
+                )));
+            }
+        }
+        Ok(())
+    }
+
+    fn reject_files>(
+        &self,
+        relatives: &BTreeSet<&str>,
+        rejected: &[S],
+    ) -> Result<()> {
+        for relative in rejected {
+            let relative = relative.as_ref();
+            if relatives.contains(relative) {
+                return Err(Error::new(format!(
+                    "{} {} artifact must not contain payload {relative:?}",
+                    self.label(),
+                    self.kind.as_str()
+                )));
+            }
+        }
+        Ok(())
+    }
+}
+
+fn native_tool_paths(target: &str, stems: &[&str]) -> Vec {
+    let suffix = if is_windows_target(target) {
+        ".exe"
+    } else {
+        ""
+    };
+    stems
+        .iter()
+        .map(|stem| format!("runtime/bin/{stem}{suffix}"))
+        .collect()
+}
+
+fn native_tool_path_variants(stems: &[&str]) -> Vec {
+    stems
+        .iter()
+        .flat_map(|stem| {
+            [
+                format!("runtime/bin/{stem}"),
+                format!("runtime/bin/{stem}.exe"),
+            ]
+        })
+        .collect()
+}
+
+fn is_windows_target(target: &str) -> bool {
+    target.contains("windows")
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+enum ArtifactKind {
+    NativeRuntime,
+    NativeTools,
+    WasixRuntime,
+    WasixTools,
+    WasixAot,
+    WasixToolsAot,
+    BrokerHelper,
+    IcuData,
+    Extension,
+}
+
+impl ArtifactKind {
+    fn as_str(self) -> &'static str {
+        match self {
+            Self::NativeRuntime => "native-runtime",
+            Self::NativeTools => "native-tools",
+            Self::WasixRuntime => "wasix-runtime",
+            Self::WasixTools => "wasix-tools",
+            Self::WasixAot => "wasix-aot",
+            Self::WasixToolsAot => "wasix-tools-aot",
+            Self::BrokerHelper => "broker-helper",
+            Self::IcuData => "icu-data",
+            Self::Extension => "extension",
+        }
+    }
+}
+
+#[derive(Debug, Clone, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+struct ArtifactFile {
+    source: PathBuf,
+    relative: String,
+    sha256: String,
+    #[serde(default)]
+    executable: bool,
+}
+
+#[derive(Debug, Clone, Serialize)]
+#[serde(rename_all = "kebab-case")]
+struct LockFile {
+    schema: String,
+    target: String,
+    runtime: String,
+    runtime_version: String,
+    icu: bool,
+    extensions: Vec,
+    artifacts: Vec,
+}
+
+#[derive(Debug, Clone, Serialize)]
+#[serde(rename_all = "kebab-case")]
+struct LockedArtifact {
+    product: String,
+    version: String,
+    kind: String,
+    target: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    extension: Option,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    runtime_product: Option,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    runtime_version: Option,
+    files: Vec,
+}
+
+#[derive(Debug, Clone, Serialize)]
+#[serde(rename_all = "kebab-case")]
+struct LockedFile {
+    path: String,
+    sha256: String,
+    executable: bool,
+}
+
+type Result = std::result::Result;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Error {
+    message: String,
+}
+
+impl Error {
+    fn new(message: impl Into) -> Self {
+        Self {
+            message: message.into(),
+        }
+    }
+
+    fn io(action: &str, path: &Path, source: io::Error) -> Self {
+        Self::new(format!("{action} {}: {source}", path.display()))
+    }
+
+    fn parse(path: &Path, source: toml::de::Error) -> Self {
+        Self::new(format!("parse {}: {source}", path.display()))
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        formatter.write_str(&self.message)
+    }
+}
+
+impl std::error::Error for Error {}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::io::Write;
+    use tempfile::TempDir;
+
+    #[test]
+    fn missing_application_metadata_fails() {
+        let temp = TempDir::new().unwrap();
+        fs::write(
+            temp.path().join("Cargo.toml"),
+            "[package]\nname = \"app\"\nversion = \"0.1.0\"\n",
+        )
+        .unwrap();
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![],
+        };
+        let error = context.configure().expect_err("missing metadata must fail");
+        assert!(
+            error
+                .to_string()
+                .contains("missing [package.metadata.oliphaunt].runtime")
+        );
+    }
+
+    #[test]
+    fn selected_runtime_requires_cargo_resolved_artifact() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+"#,
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![],
+        };
+        let error = context
+            .configure()
+            .expect_err("missing runtime artifact must fail");
+        assert!(
+            error
+                .to_string()
+                .contains("missing Cargo-resolved Oliphaunt artifact")
+        );
+        assert!(error.to_string().contains("kind=native-runtime"));
+    }
+
+    #[test]
+    fn icu_selection_requires_icu_artifact() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+icu = true
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/pg_dump",
+        );
+        let broker_manifest = write_artifact_manifest(
+            &temp,
+            "broker.toml",
+            "oliphaunt-broker",
+            "0.1.0",
+            "broker-helper",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "bin/oliphaunt-broker",
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![runtime_manifest, tools_manifest, broker_manifest],
+        };
+        let error = context
+            .configure()
+            .expect_err("missing ICU artifact must fail");
+        assert!(error.to_string().contains("product=oliphaunt-icu"));
+        assert!(error.to_string().contains("kind=icu-data"));
+    }
+
+    #[test]
+    fn native_runtime_selection_requires_broker_helper_artifact() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/pg_dump",
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![runtime_manifest, tools_manifest],
+        };
+        let error = context
+            .configure()
+            .expect_err("missing broker helper artifact must fail");
+        assert!(error.to_string().contains("product=oliphaunt-broker"));
+        assert!(error.to_string().contains("kind=broker-helper"));
+    }
+
+    #[test]
+    fn native_runtime_allows_independent_auxiliary_artifact_versions() {
+        let temp = app_with_metadata(
+            r#"
+[dependencies]
+oliphaunt-tools = "5.0.0"
+
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "1.2.0"
+extensions = ["vector"]
+icu = true
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "1.2.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let broker_manifest = write_artifact_manifest(
+            &temp,
+            "broker.toml",
+            "oliphaunt-broker",
+            "2.0.0",
+            "broker-helper",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "bin/oliphaunt-broker",
+        );
+        let icu_manifest = write_artifact_manifest(
+            &temp,
+            "icu.toml",
+            "oliphaunt-icu",
+            "3.0.0",
+            "icu-data",
+            "portable",
+            None,
+            "share/icu/icudt.dat",
+        );
+        let extension_manifest = write_artifact_manifest(
+            &temp,
+            "vector.toml",
+            "oliphaunt-extension-vector",
+            "4.0.0",
+            "extension",
+            "x86_64-unknown-linux-gnu",
+            Some("vector"),
+            "extensions/vector/vector.control",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "5.0.0",
+            "native-tools",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/pg_dump",
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![
+                runtime_manifest,
+                tools_manifest,
+                broker_manifest,
+                icu_manifest,
+                extension_manifest,
+            ],
+        };
+
+        let output = context
+            .configure()
+            .expect("Cargo-resolved auxiliary artifact versions should be accepted");
+
+        let lock = fs::read_to_string(output.lock_file).unwrap();
+        assert!(lock.contains("product = \"liboliphaunt-native\""));
+        assert!(lock.contains("version = \"1.2.0\""));
+        assert!(lock.contains("product = \"oliphaunt-tools\""));
+        assert!(lock.contains("version = \"5.0.0\""));
+        assert!(lock.contains("product = \"oliphaunt-broker\""));
+        assert!(lock.contains("version = \"2.0.0\""));
+        assert!(lock.contains("product = \"oliphaunt-icu\""));
+        assert!(lock.contains("version = \"3.0.0\""));
+        assert!(lock.contains("product = \"oliphaunt-extension-vector\""));
+        assert!(lock.contains("version = \"4.0.0\""));
+    }
+
+    #[test]
+    fn unselected_extension_artifact_fails() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let broker_manifest = write_artifact_manifest(
+            &temp,
+            "broker.toml",
+            "oliphaunt-broker",
+            "0.1.0",
+            "broker-helper",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "bin/oliphaunt-broker",
+        );
+        let extension_manifest = write_artifact_manifest(
+            &temp,
+            "vector.toml",
+            "oliphaunt-extension-vector",
+            "0.1.0",
+            "extension",
+            "x86_64-unknown-linux-gnu",
+            Some("vector"),
+            "extensions/vector/vector.control",
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![runtime_manifest, broker_manifest, extension_manifest],
+        };
+        let error = context
+            .configure()
+            .expect_err("unselected extension artifact must fail");
+        assert!(error.to_string().contains("is not selected"));
+    }
+
+    #[test]
+    fn selected_artifact_files_are_staged_and_locked() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+extensions = ["vector"]
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/pg_dump",
+        );
+        let broker_manifest = write_artifact_manifest(
+            &temp,
+            "broker.toml",
+            "oliphaunt-broker",
+            "0.1.0",
+            "broker-helper",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "bin/oliphaunt-broker",
+        );
+        let extension_manifest = write_artifact_manifest(
+            &temp,
+            "vector.toml",
+            "oliphaunt-extension-vector",
+            "0.1.0",
+            "extension",
+            "x86_64-unknown-linux-gnu",
+            Some("vector"),
+            "extensions/vector/vector.control",
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![
+                runtime_manifest,
+                tools_manifest,
+                broker_manifest,
+                extension_manifest,
+            ],
+        };
+
+        let output = context
+            .configure()
+            .expect("selected artifacts should stage");
+
+        assert!(
+            output
+                .resources_dir
+                .join("native-runtime/liboliphaunt-native/runtime/bin/postgres")
+                .is_file()
+        );
+        assert!(!output.resources_dir.join("native-tools").exists());
+        assert!(
+            output
+                .resources_dir
+                .join("broker-helper/oliphaunt-broker/bin/oliphaunt-broker")
+                .is_file()
+        );
+        assert!(
+            output
+                .resources_dir
+                .join("extension/oliphaunt-extension-vector/extensions/vector/vector.control")
+                .is_file()
+        );
+        let lock = fs::read_to_string(output.lock_file).unwrap();
+        assert!(lock.contains("schema = \"oliphaunt-assets-lock-v1\""));
+        assert!(lock.contains("runtime = \"liboliphaunt-native\""));
+        assert!(lock.contains("kind = \"broker-helper\""));
+        assert!(lock.contains("extension = \"vector\""));
+        let generated = fs::read_to_string(output.generated_rust).unwrap();
+        assert!(generated.contains("OLIPHAUNT_RESOURCES_DIR"));
+    }
+
+    #[test]
+    fn native_tools_are_staged_only_for_an_explicit_dependency() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+
+[dependencies]
+oliphaunt-tools = "0.1.0"
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let broker_manifest = write_artifact_manifest(
+            &temp,
+            "broker.toml",
+            "oliphaunt-broker",
+            "0.1.0",
+            "broker-helper",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "bin/oliphaunt-broker",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/pg_dump",
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![runtime_manifest, broker_manifest, tools_manifest],
+        };
+
+        let output = context.configure().expect("native tools should stage");
+        assert!(
+            output
+                .resources_dir
+                .join("native-tools/oliphaunt-tools/runtime/bin/pg_dump")
+                .is_file()
+        );
+        let lock = fs::read_to_string(output.lock_file).unwrap();
+        assert!(lock.contains("product = \"oliphaunt-tools\""));
+    }
+
+    #[test]
+    fn bundle_manifest_resolves_dependency_closure_alongside_an_external_extension() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+extensions = ["earthdistance", "vector"]
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/pg_dump",
+        );
+        let broker_manifest = write_artifact_manifest(
+            &temp,
+            "broker.toml",
+            "oliphaunt-broker",
+            "0.1.0",
+            "broker-helper",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "bin/oliphaunt-broker",
+        );
+        let bundle_manifest = write_bundle_artifact_manifest(
+            &temp,
+            "contrib.toml",
+            "oliphaunt-extension-contrib-pg18",
+            "0.1.0",
+            "x86_64-unknown-linux-gnu",
+            &["cube", "earthdistance", "hstore"],
+        );
+        let vector_manifest = write_artifact_manifest(
+            &temp,
+            "vector.toml",
+            "oliphaunt-extension-vector",
+            "0.2.0",
+            "extension",
+            "x86_64-unknown-linux-gnu",
+            Some("vector"),
+            "share/postgresql/extension/vector.control",
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![
+                runtime_manifest,
+                tools_manifest,
+                broker_manifest,
+                bundle_manifest,
+                vector_manifest,
+            ],
+        };
+
+        let output = context
+            .configure()
+            .expect("selected bundle members should stage");
+        let extension_root = output.resources_dir.join("extension");
+        for (product, extension) in [
+            ("oliphaunt-extension-contrib-pg18", "cube"),
+            ("oliphaunt-extension-contrib-pg18", "earthdistance"),
+            ("oliphaunt-extension-vector", "vector"),
+        ] {
+            assert!(
+                extension_root
+                    .join(product)
+                    .join(format!("share/postgresql/extension/{extension}.control"))
+                    .is_file()
+            );
+        }
+        assert!(
+            !extension_root
+                .join("oliphaunt-extension-contrib-pg18/share/postgresql/extension/hstore.control")
+                .exists()
+        );
+        let lock = fs::read_to_string(output.lock_file).unwrap();
+        assert!(lock.contains("extension = \"cube\""));
+        assert!(lock.contains("extension = \"earthdistance\""));
+        assert!(lock.contains("extension = \"vector\""));
+        assert!(!lock.contains("extension = \"hstore\""));
+    }
+
+    #[test]
+    fn external_extension_runtime_version_mismatch_fails() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+extensions = ["vector"]
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/pg_dump",
+        );
+        let broker_manifest = write_artifact_manifest(
+            &temp,
+            "broker.toml",
+            "oliphaunt-broker",
+            "0.1.0",
+            "broker-helper",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "bin/oliphaunt-broker",
+        );
+        let extension_manifest = write_artifact_manifest(
+            &temp,
+            "vector.toml",
+            "oliphaunt-extension-vector",
+            "7.2.1",
+            "extension",
+            "x86_64-unknown-linux-gnu",
+            Some("vector"),
+            "share/postgresql/extension/vector.control",
+        );
+        let incompatible = fs::read_to_string(&extension_manifest)
+            .unwrap()
+            .replace("runtime-version = \"0.1.0\"", "runtime-version = \"9.9.9\"");
+        fs::write(&extension_manifest, incompatible).unwrap();
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![
+                runtime_manifest,
+                tools_manifest,
+                broker_manifest,
+                extension_manifest,
+            ],
+        };
+        let error = context.configure().expect_err(
+            "independently versioned external must bind its compatible runtime exactly",
+        );
+        let message = error.to_string();
+        assert!(message.contains("extension artifact runtime mismatch"));
+        assert!(message.contains("app selects liboliphaunt-native@0.1.0"));
+        assert!(message.contains("artifact binds [liboliphaunt-native@9.9.9]"));
+    }
+
+    #[test]
+    fn extension_bundle_runtime_product_mismatch_fails() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+extensions = ["cube"]
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/pg_dump",
+        );
+        let broker_manifest = write_artifact_manifest(
+            &temp,
+            "broker.toml",
+            "oliphaunt-broker",
+            "0.1.0",
+            "broker-helper",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "bin/oliphaunt-broker",
+        );
+        let bundle_manifest = write_bundle_artifact_manifest(
+            &temp,
+            "contrib.toml",
+            "oliphaunt-extension-contrib-pg18",
+            "0.1.0",
+            "x86_64-unknown-linux-gnu",
+            &["cube", "hstore"],
+        );
+        let incompatible = fs::read_to_string(&bundle_manifest).unwrap().replace(
+            "runtime-product = \"liboliphaunt-native\"",
+            "runtime-product = \"liboliphaunt-wasix\"",
+        );
+        fs::write(&bundle_manifest, incompatible).unwrap();
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![
+                runtime_manifest,
+                tools_manifest,
+                broker_manifest,
+                bundle_manifest,
+            ],
+        };
+        let error = context
+            .configure()
+            .expect_err("every member flattened from a bundle must retain its runtime binding");
+        let message = error.to_string();
+        assert!(message.contains("extension artifact runtime mismatch"));
+        assert!(message.contains("app selects liboliphaunt-native@0.1.0"));
+        assert!(message.contains("artifact binds [liboliphaunt-wasix@0.1.0]"));
+    }
+
+    #[test]
+    fn staging_cleans_stale_resource_files() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-native"
+runtime-version = "0.1.0"
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/postgres",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "runtime/bin/pg_dump",
+        );
+        let broker_manifest = write_artifact_manifest(
+            &temp,
+            "broker.toml",
+            "oliphaunt-broker",
+            "0.1.0",
+            "broker-helper",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "bin/oliphaunt-broker",
+        );
+        let out_dir = temp.path().join("out");
+        let stale = out_dir.join("oliphaunt/resources/extension/stale/stale.control");
+        fs::create_dir_all(stale.parent().unwrap()).unwrap();
+        fs::write(&stale, "stale").unwrap();
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir,
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![runtime_manifest, tools_manifest, broker_manifest],
+        };
+
+        let output = context.configure().expect("selected runtime should stage");
+
+        assert!(!stale.exists());
+        assert!(
+            output
+                .resources_dir
+                .join("native-runtime/liboliphaunt-native/runtime/bin/postgres")
+                .is_file()
+        );
+    }
+
+    #[test]
+    fn wasix_runtime_without_tools_stages_root_runtime_only() {
+        let temp = app_with_metadata(
+            r#"
+[dependencies]
+oliphaunt-wasix = "0.1.0"
+
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-wasix"
+runtime-version = "0.1.0"
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "wasix-runtime.toml",
+            "liboliphaunt-wasix",
+            "0.1.0",
+            "wasix-runtime",
+            "portable",
+            None,
+            "oliphaunt.wasix.tar.zst",
+        );
+        let aot_manifest = write_artifact_manifest(
+            &temp,
+            "wasix-aot.toml",
+            "liboliphaunt-wasix",
+            "0.1.0",
+            "wasix-aot",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "oliphaunt-llvm-opta.bin.zst",
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![runtime_manifest, aot_manifest],
+        };
+
+        let output = context
+            .configure()
+            .expect("root WASIX runtime should not require split tools");
+
+        let lock = fs::read_to_string(output.lock_file).unwrap();
+        assert!(lock.contains("product = \"liboliphaunt-wasix\""));
+        assert!(!lock.contains("product = \"oliphaunt-wasix-tools\""));
+        assert!(
+            output
+                .resources_dir
+                .join("wasix-runtime/liboliphaunt-wasix/bin/initdb.wasix.wasm")
+                .is_file()
+        );
+        assert!(
+            output
+                .resources_dir
+                .join("wasix-aot/liboliphaunt-wasix/manifest.json")
+                .is_file()
+        );
+        assert!(
+            !output
+                .resources_dir
+                .join("wasix-tools/oliphaunt-wasix-tools")
+                .exists()
+        );
+    }
+
+    #[test]
+    fn wasix_extension_bundle_selects_portable_and_host_aot_dependency_closure() {
+        let temp = app_with_metadata(
+            r#"
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-wasix"
+runtime-version = "0.1.0"
+extensions = ["earthdistance"]
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "wasix-runtime.toml",
+            "liboliphaunt-wasix",
+            "0.1.0",
+            "wasix-runtime",
+            "portable",
+            None,
+            "oliphaunt.wasix.tar.zst",
+        );
+        let runtime_aot_manifest = write_artifact_manifest(
+            &temp,
+            "wasix-aot.toml",
+            "liboliphaunt-wasix",
+            "0.1.0",
+            "wasix-aot",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "oliphaunt-llvm-opta.bin.zst",
+        );
+        let portable_extensions = write_bundle_artifact_manifest(
+            &temp,
+            "contrib-portable.toml",
+            "oliphaunt-extension-contrib-pg18",
+            "0.1.0",
+            "portable",
+            &["cube", "earthdistance", "hstore"],
+        );
+        let aot_extensions = write_bundle_artifact_manifest(
+            &temp,
+            "contrib-aot.toml",
+            "oliphaunt-extension-contrib-pg18",
+            "0.1.0",
+            "x86_64-unknown-linux-gnu",
+            &["cube", "earthdistance", "hstore"],
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![
+                runtime_manifest,
+                runtime_aot_manifest,
+                portable_extensions,
+                aot_extensions,
+            ],
+        };
+
+        let output = context
+            .configure()
+            .expect("WASIX bundle should resolve portable and host AOT closure");
+        let lock = fs::read_to_string(output.lock_file).unwrap();
+        assert!(lock.contains("target = \"portable\""));
+        assert!(lock.contains("target = \"x86_64-unknown-linux-gnu\""));
+        assert!(lock.contains("extension = \"cube\""));
+        assert!(lock.contains("extension = \"earthdistance\""));
+        assert!(!lock.contains("extension = \"hstore\""));
+    }
+
+    #[test]
+    fn wasix_runtime_with_tools_feature_stages_split_tools() {
+        let temp = app_with_metadata(
+            r#"
+[dependencies]
+oliphaunt-wasix = { version = "0.1.0", features = ["tools"] }
+
+[package.metadata.oliphaunt]
+runtime = "liboliphaunt-wasix"
+runtime-version = "0.1.0"
+"#,
+        );
+        let runtime_manifest = write_artifact_manifest(
+            &temp,
+            "wasix-runtime.toml",
+            "liboliphaunt-wasix",
+            "0.1.0",
+            "wasix-runtime",
+            "portable",
+            None,
+            "oliphaunt.wasix.tar.zst",
+        );
+        let tools_manifest = write_artifact_manifest(
+            &temp,
+            "wasix-tools.toml",
+            "oliphaunt-wasix-tools",
+            "5.0.0",
+            "wasix-tools",
+            "portable",
+            None,
+            "bin/pg_dump.wasix.wasm",
+        );
+        let aot_manifest = write_artifact_manifest(
+            &temp,
+            "wasix-aot.toml",
+            "liboliphaunt-wasix",
+            "0.1.0",
+            "wasix-aot",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "oliphaunt-llvm-opta.bin.zst",
+        );
+        let tools_aot_manifest = write_artifact_manifest(
+            &temp,
+            "wasix-tools-aot.toml",
+            "oliphaunt-wasix-tools",
+            "5.0.0",
+            "wasix-tools-aot",
+            "x86_64-unknown-linux-gnu",
+            None,
+            "pg_dump-llvm-opta.bin.zst",
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![
+                runtime_manifest,
+                tools_manifest,
+                aot_manifest,
+                tools_aot_manifest,
+            ],
+        };
+
+        let output = context
+            .configure()
+            .expect("WASIX tools feature should stage split tools artifacts");
+
+        let lock = fs::read_to_string(output.lock_file).unwrap();
+        assert!(lock.contains("product = \"oliphaunt-wasix-tools\""));
+        assert!(lock.contains("kind = \"wasix-tools-aot\""));
+        assert!(
+            output
+                .resources_dir
+                .join("wasix-tools/oliphaunt-wasix-tools/bin/pg_dump.wasix.wasm")
+                .is_file()
+        );
+        assert!(
+            output
+                .resources_dir
+                .join("wasix-tools/oliphaunt-wasix-tools/bin/psql.wasix.wasm")
+                .is_file()
+        );
+        assert!(
+            output
+                .resources_dir
+                .join("wasix-tools-aot/oliphaunt-wasix-tools/pg_dump-llvm-opta.bin.zst")
+                .is_file()
+        );
+    }
+
+    #[test]
+    fn artifact_manifest_rejects_incomplete_native_tools_payload() {
+        let required = [
+            "runtime/bin/pg_basebackup",
+            "runtime/bin/pg_dump",
+            "runtime/bin/psql",
+        ];
+        for missing in required {
+            let temp = app_with_metadata("");
+            let present = required
+                .iter()
+                .copied()
+                .filter(|relative| *relative != missing)
+                .collect::>();
+            let tools_manifest = write_artifact_manifest_with_relatives(
+                &temp,
+                "tools.toml",
+                "oliphaunt-tools",
+                "0.1.0",
+                "native-tools",
+                "x86_64-unknown-linux-gnu",
+                None,
+                &present,
+            );
+            let context = BuildContext {
+                manifest_dir: temp.path().to_path_buf(),
+                out_dir: temp.path().join("out"),
+                target: "x86_64-unknown-linux-gnu".to_owned(),
+                artifact_manifest_paths: vec![tools_manifest],
+            };
+
+            let error = context
+                .read_artifact_manifests()
+                .expect_err("incomplete native tools must fail validation");
+
+            assert!(error.to_string().contains("missing required payload"));
+            assert!(error.to_string().contains(missing));
+        }
+    }
+
+    #[test]
+    fn artifact_manifest_rejects_native_runtime_client_tool_payloads() {
+        for tool in [
+            "runtime/bin/pg_basebackup",
+            "runtime/bin/pg_dump",
+            "runtime/bin/psql",
+        ] {
+            let temp = app_with_metadata("");
+            let runtime_manifest = write_artifact_manifest_with_relatives(
+                &temp,
+                "runtime.toml",
+                "liboliphaunt-native",
+                "0.1.0",
+                "native-runtime",
+                "x86_64-unknown-linux-gnu",
+                None,
+                &[
+                    "runtime/bin/postgres",
+                    "runtime/bin/initdb",
+                    "runtime/bin/pg_ctl",
+                    tool,
+                ],
+            );
+            let context = BuildContext {
+                manifest_dir: temp.path().to_path_buf(),
+                out_dir: temp.path().join("out"),
+                target: "x86_64-unknown-linux-gnu".to_owned(),
+                artifact_manifest_paths: vec![runtime_manifest],
+            };
+
+            let error = context
+                .read_artifact_manifests()
+                .expect_err("native runtime must not contain split client tools");
+
+            assert!(error.to_string().contains("must not contain payload"));
+            assert!(error.to_string().contains(tool));
+        }
+    }
+
+    #[test]
+    fn artifact_manifest_accepts_windows_native_split_payloads() {
+        let temp = app_with_metadata("");
+        let runtime_manifest = write_artifact_manifest_with_relatives(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-pc-windows-msvc",
+            None,
+            &[
+                "runtime/bin/postgres.exe",
+                "runtime/bin/initdb.exe",
+                "runtime/bin/pg_ctl.exe",
+            ],
+        );
+        let tools_manifest = write_artifact_manifest_with_relatives(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-pc-windows-msvc",
+            None,
+            &[
+                "runtime/bin/pg_basebackup.exe",
+                "runtime/bin/pg_dump.exe",
+                "runtime/bin/psql.exe",
+            ],
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-pc-windows-msvc".to_owned(),
+            artifact_manifest_paths: vec![runtime_manifest, tools_manifest],
+        };
+
+        let manifests = context
+            .read_artifact_manifests()
+            .expect("Windows native runtime/tools split should validate");
+
+        assert_eq!(manifests.len(), 2);
+    }
+
+    #[test]
+    fn artifact_manifest_rejects_linux_native_runtime_with_windows_tool_names() {
+        let temp = app_with_metadata("");
+        let runtime_manifest = write_artifact_manifest_with_relatives(
+            &temp,
+            "runtime.toml",
+            "liboliphaunt-native",
+            "0.1.0",
+            "native-runtime",
+            "x86_64-unknown-linux-gnu",
+            None,
+            &[
+                "runtime/bin/postgres.exe",
+                "runtime/bin/initdb.exe",
+                "runtime/bin/pg_ctl.exe",
+            ],
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-unknown-linux-gnu".to_owned(),
+            artifact_manifest_paths: vec![runtime_manifest],
+        };
+
+        let error = context
+            .read_artifact_manifests()
+            .expect_err("Linux native runtime must use Unix tool names");
+
+        assert!(error.to_string().contains("missing required payload"));
+        assert!(error.to_string().contains("runtime/bin/postgres"));
+    }
+
+    #[test]
+    fn artifact_manifest_rejects_windows_native_tools_with_unix_tool_names() {
+        let temp = app_with_metadata("");
+        let tools_manifest = write_artifact_manifest_with_relatives(
+            &temp,
+            "tools.toml",
+            "oliphaunt-tools",
+            "0.1.0",
+            "native-tools",
+            "x86_64-pc-windows-msvc",
+            None,
+            &[
+                "runtime/bin/pg_basebackup",
+                "runtime/bin/pg_dump",
+                "runtime/bin/psql",
+            ],
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "x86_64-pc-windows-msvc".to_owned(),
+            artifact_manifest_paths: vec![tools_manifest],
+        };
+
+        let error = context
+            .read_artifact_manifests()
+            .expect_err("Windows native tools must use .exe tool names");
+
+        assert!(error.to_string().contains("missing required payload"));
+        assert!(error.to_string().contains("runtime/bin/pg_basebackup.exe"));
+    }
+
+    #[test]
+    fn artifact_manifest_rejects_wasix_runtime_client_tool_payloads() {
+        for tool in ["bin/pg_dump.wasix.wasm", "bin/psql.wasix.wasm"] {
+            let temp = app_with_metadata("");
+            let runtime_manifest = write_artifact_manifest_with_relatives(
+                &temp,
+                "wasix-runtime.toml",
+                "liboliphaunt-wasix",
+                "0.1.0",
+                "wasix-runtime",
+                "portable",
+                None,
+                &["oliphaunt.wasix.tar.zst", "bin/initdb.wasix.wasm", tool],
+            );
+            let context = BuildContext {
+                manifest_dir: temp.path().to_path_buf(),
+                out_dir: temp.path().join("out"),
+                target: "wasm32-wasip1".to_owned(),
+                artifact_manifest_paths: vec![runtime_manifest],
+            };
+
+            let error = context
+                .read_artifact_manifests()
+                .expect_err("WASIX runtime must not contain split client tools");
+
+            assert!(error.to_string().contains("must not contain payload"));
+            assert!(error.to_string().contains(tool));
+        }
+    }
+
+    #[test]
+    fn artifact_manifest_rejects_wasix_pg_ctl_tool_payload() {
+        let temp = app_with_metadata("");
+        let tools_manifest = write_artifact_manifest_with_relatives(
+            &temp,
+            "wasix-tools.toml",
+            "oliphaunt-wasix-tools",
+            "0.1.0",
+            "wasix-tools",
+            "portable",
+            None,
+            &[
+                "bin/pg_dump.wasix.wasm",
+                "bin/psql.wasix.wasm",
+                "bin/pg_ctl.wasix.wasm",
+            ],
+        );
+        let context = BuildContext {
+            manifest_dir: temp.path().to_path_buf(),
+            out_dir: temp.path().join("out"),
+            target: "wasm32-wasip1".to_owned(),
+            artifact_manifest_paths: vec![tools_manifest],
+        };
+
+        let error = context
+            .read_artifact_manifests()
+            .expect_err("WASIX tools must not contain pg_ctl");
+
+        assert!(error.to_string().contains("must not contain payload"));
+        assert!(error.to_string().contains("bin/pg_ctl.wasix.wasm"));
+    }
+
+    fn app_with_metadata(metadata: &str) -> TempDir {
+        let temp = TempDir::new().unwrap();
+        let manifest = format!(
+            r#"[package]
+name = "app"
+version = "0.1.0"
+edition = "2024"
+{metadata}
+"#,
+        );
+        fs::write(temp.path().join("Cargo.toml"), manifest).unwrap();
+        temp
+    }
+
+    #[allow(clippy::too_many_arguments)] // Test fixture fields mirror the artifact manifest schema.
+    fn write_artifact_manifest(
+        temp: &TempDir,
+        manifest_name: &str,
+        product: &str,
+        version: &str,
+        kind: &str,
+        target: &str,
+        extension: Option<&str>,
+        relative: &str,
+    ) -> PathBuf {
+        let relatives = test_artifact_relatives(kind, relative);
+        let relative_refs: Vec<&str> = relatives.iter().map(String::as_str).collect();
+        write_artifact_manifest_with_relatives(
+            temp,
+            manifest_name,
+            product,
+            version,
+            kind,
+            target,
+            extension,
+            &relative_refs,
+        )
+    }
+
+    #[allow(clippy::too_many_arguments)] // Test fixture fields mirror the artifact manifest schema.
+    fn write_artifact_manifest_with_relatives(
+        temp: &TempDir,
+        manifest_name: &str,
+        product: &str,
+        version: &str,
+        kind: &str,
+        target: &str,
+        extension: Option<&str>,
+        relatives: &[&str],
+    ) -> PathBuf {
+        let extension_line = extension
+            .map(|value| format!("extension = {value:?}\n"))
+            .unwrap_or_default();
+        let runtime_binding = if kind == "extension" {
+            let app: toml::Value =
+                toml::from_str(&fs::read_to_string(temp.path().join("Cargo.toml")).unwrap())
+                    .unwrap();
+            let metadata = &app["package"]["metadata"]["oliphaunt"];
+            format!(
+                "runtime-product = {:?}\nruntime-version = {:?}\ndependencies = []\n",
+                metadata["runtime"].as_str().unwrap(),
+                metadata["runtime-version"].as_str().unwrap()
+            )
+        } else {
+            String::new()
+        };
+        let mut manifest = format!(
+            r#"schema = "oliphaunt-artifact-manifest-v1"
+product = {product:?}
+version = {version:?}
+kind = {kind:?}
+target = {target:?}
+{runtime_binding}
+{extension_line}
+"#,
+        );
+        let source_root = temp.path().join("artifacts").join(manifest_name);
+        for relative in relatives {
+            let source = source_root.join(relative.replace(['/', '\\'], "_"));
+            fs::create_dir_all(source.parent().unwrap()).unwrap();
+            let mut file = fs::File::create(&source).unwrap();
+            write!(file, "{product}:{kind}:{target}:{relative}").unwrap();
+            let bytes = fs::read(&source).unwrap();
+            let sha256 = sha256_hex(&bytes);
+            manifest.push_str(&format!(
+                r#"
+[[files]]
+source = "{}"
+relative = {relative:?}
+sha256 = {sha256:?}
+executable = true
+"#,
+                source.display(),
+            ));
+        }
+        let path = temp.path().join(manifest_name);
+        fs::write(&path, manifest).unwrap();
+        path
+    }
+
+    fn write_bundle_artifact_manifest(
+        temp: &TempDir,
+        manifest_name: &str,
+        product: &str,
+        version: &str,
+        target: &str,
+        extensions: &[&str],
+    ) -> PathBuf {
+        let app: toml::Value =
+            toml::from_str(&fs::read_to_string(temp.path().join("Cargo.toml")).unwrap()).unwrap();
+        let metadata = &app["package"]["metadata"]["oliphaunt"];
+        let runtime_product = metadata["runtime"].as_str().unwrap();
+        let runtime_version = metadata["runtime-version"].as_str().unwrap();
+        let mut manifest = format!(
+            r#"schema = "oliphaunt-artifact-manifest-v2"
+product = {product:?}
+version = {version:?}
+kind = "extension"
+target = {target:?}
+runtime-product = {runtime_product:?}
+runtime-version = {runtime_version:?}
+"#,
+        );
+        for extension in extensions {
+            let dependencies: Vec<&str> = if *extension == "earthdistance" {
+                vec!["cube"]
+            } else {
+                Vec::new()
+            };
+            let relative = format!("share/postgresql/extension/{extension}.control");
+            let source = temp
+                .path()
+                .join("artifacts")
+                .join(manifest_name)
+                .join(format!("{extension}.control"));
+            fs::create_dir_all(source.parent().unwrap()).unwrap();
+            fs::write(&source, format!("{product}:{extension}")).unwrap();
+            let sha256 = sha256_hex(&fs::read(&source).unwrap());
+            manifest.push_str(&format!(
+                r#"
+[[extensions]]
+extension = {extension:?}
+dependencies = {dependencies:?}
+
+[[extensions.files]]
+source = "{}"
+relative = {relative:?}
+sha256 = {sha256:?}
+executable = false
+"#,
+                source.display(),
+            ));
+        }
+        let path = temp.path().join(manifest_name);
+        fs::write(&path, manifest).unwrap();
+        path
+    }
+
+    fn test_artifact_relatives(kind: &str, primary: &str) -> Vec {
+        let mut relatives = match kind {
+            "native-runtime" => vec![
+                "runtime/bin/postgres".to_owned(),
+                "runtime/bin/initdb".to_owned(),
+                "runtime/bin/pg_ctl".to_owned(),
+            ],
+            "native-tools" => vec![
+                "runtime/bin/pg_basebackup".to_owned(),
+                "runtime/bin/pg_dump".to_owned(),
+                "runtime/bin/psql".to_owned(),
+            ],
+            "wasix-runtime" => vec![
+                "manifest.json".to_owned(),
+                "oliphaunt.wasix.tar.zst".to_owned(),
+                "bin/initdb.wasix.wasm".to_owned(),
+            ],
+            "wasix-tools" => vec![
+                "bin/pg_dump.wasix.wasm".to_owned(),
+                "bin/psql.wasix.wasm".to_owned(),
+            ],
+            "wasix-aot" => vec![
+                "manifest.json".to_owned(),
+                "oliphaunt-llvm-opta.bin.zst".to_owned(),
+                "initdb-llvm-opta.bin.zst".to_owned(),
+            ],
+            "wasix-tools-aot" => vec![
+                "manifest.json".to_owned(),
+                "pg_dump-llvm-opta.bin.zst".to_owned(),
+                "psql-llvm-opta.bin.zst".to_owned(),
+            ],
+            _ => vec![primary.to_owned()],
+        };
+        if !relatives.iter().any(|relative| relative == primary) {
+            relatives.push(primary.to_owned());
+        }
+        relatives
+    }
+}
diff --git a/src/sdks/rust/sdk/moon.yml b/src/sdks/rust/sdk/moon.yml
new file mode 100644
index 000000000..27d51f5ba
--- /dev/null
+++ b/src/sdks/rust/sdk/moon.yml
@@ -0,0 +1,289 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "oliphaunt-rust"
+language: "rust"
+layer: "library"
+stack: "systems"
+tags: ["cargo-package", "javascript-quality", "sdk", "rust", "tauri", "native", "release-product"]
+dependsOn:
+  - id: "shared-test-fixtures"
+    scope: "development"
+  - id: "extensions"
+    scope: "build"
+  - "liboliphaunt-native"
+  - "oliphaunt-query"
+  - "liboliphaunt-native-bindings"
+  - "oliphaunt-broker"
+
+project:
+  title: "Oliphaunt Rust SDK"
+  description: "Canonical Rust SDK for native embedded PostgreSQL in Tauri and Rust desktop apps."
+  owner: "oliphaunt"
+  release:
+    component: "oliphaunt-rust"
+    packagePath: "src/sdks/rust/sdk"
+
+owners:
+  defaultOwner: "@oliphaunt/sdk-rust"
+  paths:
+    "**/*.rs": ["@oliphaunt/sdk-rust"]
+    "Cargo.toml": ["@oliphaunt/sdk-rust"]
+
+fileGroups:
+  cargo-sources: ["crates/oliphaunt-build/src/**/*", "crates/oliphaunt-build/Cargo.toml"]
+  sources: ["src/**/*", "build.rs", "Cargo.toml"]
+  code:
+    - "**/*"
+    - "!**/*.md"
+    - "!moon.yml"
+    - "!release.toml"
+
+tasks:
+  format:
+    command: "cargo fmt -p oliphaunt-build -p oliphaunt"
+    options:
+      cache: false
+      runInCI: false
+      runFromWorkspaceRoot: true
+
+  build:
+    tags: ["build", "requires-rust"]
+    script: |
+      set -e
+      cargo build -p oliphaunt -p oliphaunt-build --locked
+    outputs: ["/target/debug/liboliphaunt.rlib", "/target/debug/liboliphaunt_build.rlib"]
+    env:
+      CARGO_TARGET_DIR: "target"
+    deps:
+      - target: "~:cargo-sources"
+        cacheStrategy: hash
+    inputs:
+      - "@group(cargo-workspace)"
+      - "/clippy.toml"
+      - "@group(code)"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  test:
+    tags: ["quality", "unit", "requires-rust"]
+    script: |
+      set -e
+      mkdir -p "$CARGO_TARGET_DIR"
+      if [ -n "${CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER:-}" ]; then
+        rustc --edition=2024 --test src/sdks/rust/sdk/build.rs -C "linker=$CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER" -o "$CARGO_TARGET_DIR/build-script-tests"
+      else
+        rustc --edition=2024 --test src/sdks/rust/sdk/build.rs -o "$CARGO_TARGET_DIR/build-script-tests"
+      fi
+      "$CARGO_TARGET_DIR/build-script-tests"
+      cargo test -p oliphaunt --doc --locked
+      cargo test -p oliphaunt-build --locked
+      cargo nextest run -p oliphaunt --locked --profile ci --no-tests=fail --test-threads=1
+    env:
+      # Cargo releases its build lock before rustdoc consumes the compiled libraries.
+      CARGO_TARGET_DIR: "target/moon/oliphaunt-rust/unit"
+    deps:
+      - target: "~:cargo-sources"
+        cacheStrategy: hash
+    inputs:
+      - "@group(cargo-workspace)"
+      - "@group(rust-test-config)"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - "@group(code)"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  test-integration:
+    tags: ["regression", "runtime"]
+    script: |
+      set -e
+      . src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+      oliphaunt_runtime_native_host_require basic
+      cargo test -p oliphaunt --locked --test native_smoke --test native_sql_regression -- --test-threads=1
+    env:
+      CARGO_TARGET_DIR: "target"
+    deps:
+      - target: "~:cargo-sources"
+        cacheStrategy: hash
+      - "liboliphaunt-native:build-runtime-desktop-target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - "@group(code)"
+      - "/src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh"
+    options:
+      cache: local
+      runFromWorkspaceRoot: true
+  test-extensions:
+    tags: ["regression", "runtime", "extensions"]
+    script: |
+      set -e
+      . src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+      oliphaunt_runtime_native_host_require extensions
+      cargo test -p oliphaunt --locked --test native_extensions -- --test-threads=1
+    env:
+      CARGO_TARGET_DIR: "target"
+    deps:
+      - target: "~:cargo-sources"
+        cacheStrategy: hash
+      - "extension-artifacts-native:build-target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - project: "extensions"
+        group: "build"
+      - project: "liboliphaunt-native"
+        group: "runtime"
+      - "@group(code)"
+      - "/src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh"
+    options:
+      cache: local
+      runFromWorkspaceRoot: true
+      runInCI: false
+
+  coverage:
+    tags: ["coverage", "requires-rust"]
+    script: |
+      set -e
+      mkdir -p target/coverage/oliphaunt-rust
+      cargo llvm-cov nextest -p oliphaunt --locked --profile ci --no-tests=fail --test-threads=1 --lcov --output-path target/coverage/oliphaunt-rust/lcov.info
+    env:
+      CARGO_LLVM_COV_TARGET_DIR: "target/coverage-build/oliphaunt-rust"
+    deps:
+      - target: "~:cargo-sources"
+        cacheStrategy: hash
+    inputs:
+      - "@group(code)"
+      - "@group(cargo-workspace)"
+      - "@group(rust-test-config)"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+    outputs: ["/target/coverage/oliphaunt-rust/**/*"]
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: false
+
+  format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt -p oliphaunt-build -p oliphaunt --check"
+    inputs: ["/src/sdks/rust/sdk/crates/oliphaunt-build/**/*.rs","/src/sdks/rust/sdk/crates/oliphaunt-build/Cargo.toml","/src/sdks/rust/sdk/**/*.rs","/src/sdks/rust/sdk/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+  lint:
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy -p oliphaunt-build -p oliphaunt --all-targets --locked -- -D warnings"
+    env:
+      CARGO_TARGET_DIR: "target"
+    deps:
+      - target: "~:cargo-sources"
+        cacheStrategy: hash
+    inputs: ["/src/sdks/rust/sdk/crates/oliphaunt-build/**/*.rs","/src/sdks/rust/sdk/crates/oliphaunt-build/Cargo.toml","/src/sdks/rust/sdk/**/*.rs","/src/sdks/rust/sdk/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+
+  package:
+    tags: ["release", "artifact-package", "ci-rust-sdk-package"]
+    script: |
+      set -eu
+      cargo fetch --locked
+      bash src/sdks/rust/sdk/tools/stage-release-artifacts.sh
+
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs:
+      - "**/*"
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - project: "oliphaunt-query"
+        group: "sources"
+      - "@group(legal-files)"
+      - "@group(cargo-workspace)"
+      - "@group(release-archive-contract)"
+      - "@group(release-target-contract)"
+      - "/tools/packaging/*.{mjs,mts}"
+      - "/tools/packaging/cargo-source-package.mts"
+      - "/tools/packaging/package-cargo-source.sh"
+      - "/tools/packaging/check-cargo-package-tests.sh"
+      - "/src/sdks/rust/sdk/tools/check-package.mts"
+      - "/src/extensions/artifacts/packages/tools/contrib-carriers.mts"
+      - "/src/sdks/rust/sdk/tools/prepare-rust-release-source.mts"
+      - "/tools/release/release-graph.mts"
+      - "/tools/packaging/rust-native-targets.mts"
+      - "/src/sdks/rust/sdk/tools/stage-release-artifacts.sh"
+      - "/tools/packaging/staging.mts"
+      - "/tools/dev/bun.sh"
+      - "/src/third-party/tools/source-fetch-core.mts"
+    outputs:
+      - "/target/sdk-artifacts/oliphaunt-rust/**/*"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  test-consumer:
+    tags: ["release", "runtime", "ci-rust-sdk-package"]
+    script: |
+      set -eu
+      bash tools/dev/bun.sh src/sdks/rust/sdk/tools/check-package.mts
+      version="$(bash tools/dev/bun.sh tools/release/product-version.mts version oliphaunt-rust)"
+      dependencies=()
+      for product in oliphaunt-query liboliphaunt-native-bindings oliphaunt-broker; do
+        for archive in target/sdk-artifacts/"$product"/*.crate; do dependencies+=(--dependency-crate "${archive}"); done
+      done
+      bash tools/packaging/check-cargo-package-tests.sh --crate "target/sdk-artifacts/oliphaunt-rust/oliphaunt-$version.crate" --all-features "${dependencies[@]}" --stub-dependency-prefix liboliphaunt-native- --stub-dependency-prefix oliphaunt-broker-
+      bash src/sdks/rust/sdk/tools/check-release-consumer.sh build target/sdk-artifacts/oliphaunt-rust target/oliphaunt-rust/release-consumer/oliphaunt-rust-release-consumer
+    deps:
+      - "oliphaunt-rust:package"
+      - "oliphaunt-query:package"
+      - "liboliphaunt-native-bindings:package"
+      - "oliphaunt-broker:package"
+    env:
+      CARGO_TARGET_DIR: "target/moon/oliphaunt-rust/release-consumer"
+    inputs:
+      - "/rust-toolchain.toml"
+      - "/src/sdks/rust/sdk/tests/release-consumer/**/*"
+      - "/src/sdks/rust/sdk/tools/check-release-consumer.sh"
+      - "/src/sdks/rust/sdk/tools/artifact-dependencies.mts"
+      - "/tools/dev/bun.sh"
+    outputs:
+      - "/target/oliphaunt-rust/release-consumer/oliphaunt-rust-release-consumer"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+
+  test-consumer-runtime:
+    tags: [consumer, integration, ci-native-consumers, platform-linux-x64-gnu]
+    command: "bash src/sdks/rust/sdk/tools/check-release-consumer.sh run target/oliphaunt-rust/release-consumer/oliphaunt-rust-release-consumer target/liboliphaunt/desktop-release-assets/linux-x64-gnu target/postgres-tools/native/release-assets target/oliphaunt-broker/release-assets"
+    deps:
+      - "~:test-consumer"
+      - "liboliphaunt-native:package-runtime-desktop-target"
+      - "postgres-tools-native:package-assets"
+      - "oliphaunt-broker:build-release-assets"
+    inputs:
+      - "tools/check-release-consumer.sh"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+
+  packaging-unit:
+    tags: ["quality", "unit", "requires-rust"]
+    command: "bash src/sdks/rust/sdk/tools/prepare-rust-release-source.test.sh"
+    inputs:
+      - "**/*"
+      - "/src/sdks/rust-query/src/lib.rs"
+      - "/src/sdks/rust/liboliphaunt-native/**/*"
+      - "/src/test-fixtures/**/*"
+      - "@group(cargo-workspace)"
+      - "@group(legal-files)"
+      - "@group(release-target-contract)"
+      - "@group(package-test-metadata)"
+      - "**/*.{mjs,mts}"
+      - "/tools/packaging/testdata/**/*"
+      - "/tools/dev/bun.sh"
+      - "/tools/packaging/*.{mts,sh}"
+      - "/tools/release/*.{mjs,mts}"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/sdks/rust/sdk/release.toml b/src/sdks/rust/sdk/release.toml
new file mode 100644
index 000000000..d2c31acab
--- /dev/null
+++ b/src/sdks/rust/sdk/release.toml
@@ -0,0 +1,36 @@
+id = "oliphaunt-rust"
+owner = "@oliphaunt/sdk-rust"
+kind = "sdk"
+publish_targets = ["crates-io"]
+registry_packages = ["crates:oliphaunt", "crates:oliphaunt-build"]
+release_artifacts = ["cargo-crate", "runtime-resource-cli"]
+
+[compatibility_versions.native_runtime]
+source_product = "liboliphaunt-native"
+path = "src/sdks/rust/sdk/Cargo.toml"
+parser = "toml:package.metadata.oliphaunt.native-version"
+
+[compatibility_versions.broker_runtime]
+source_product = "oliphaunt-broker"
+path = "src/sdks/rust/sdk/Cargo.toml"
+parser = "toml:package.metadata.oliphaunt.broker-version"
+
+[compatibility_versions.broker_runtime_constant]
+source_product = "oliphaunt-broker"
+path = "src/sdks/rust/sdk/src/broker.rs"
+parser = "rust-const:BROKER_RELEASE_VERSION"
+
+[compatibility_versions.oliphaunt-rust-query]
+source_product = "oliphaunt-query"
+path = "src/sdks/rust/sdk/Cargo.toml"
+parser = "toml:dependencies.oliphaunt-query.version"
+
+[compatibility_versions.rust_native_bindings]
+source_product = "liboliphaunt-native-bindings"
+path = "src/sdks/rust/sdk/Cargo.toml"
+parser = "toml:dependencies.liboliphaunt-native-bindings.version"
+
+[compatibility_versions.broker_library]
+source_product = "oliphaunt-broker"
+path = "src/sdks/rust/sdk/Cargo.toml"
+parser = "toml:dependencies.oliphaunt-broker.version"
diff --git a/src/sdks/rust/src/broker.rs b/src/sdks/rust/sdk/src/broker.rs
similarity index 80%
rename from src/sdks/rust/src/broker.rs
rename to src/sdks/rust/sdk/src/broker.rs
index f047b8a1d..2dbd0716d 100644
--- a/src/sdks/rust/src/broker.rs
+++ b/src/sdks/rust/sdk/src/broker.rs
@@ -19,6 +19,7 @@ use crate::extension::Extension;
 use crate::ipc::{RequestFrame, ResponseFrame, read_response, write_request};
 use crate::protocol::{ProtocolRequest, ProtocolResponse};
 use crate::storage::DatabaseStorage;
+use oliphaunt_broker::pgwire::{self, Connection as BrokerTransport};
 
 const ENV_BROKER: &str = "OLIPHAUNT_BROKER";
 const ENV_BROKER_ASSET_DIR: &str = "OLIPHAUNT_BROKER_ASSET_DIR";
@@ -30,15 +31,11 @@ const BROKER_RELEASE_VERSION: &str = "0.2.0";
 const BROKER_STARTUP_TIMEOUT: Duration = Duration::from_secs(20);
 const BROKER_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
 
-trait BrokerTransport: Read + Write + Send {}
-
-impl BrokerTransport for T where T: Read + Write + Send {}
-
 /// Broker runtime backed by a local helper process.
 ///
 /// Broker mode is intentionally separate from direct mode. The helper process
 /// owns the native database instance and the direct PostgreSQL backend; the Rust SDK client
-/// talks to it over a small length-prefixed local IPC protocol.
+/// uses PostgreSQL wire messages for SQL and a separate local management channel.
 #[derive(Debug, Clone)]
 pub(crate) struct NativeBrokerRuntime {
     executable: Option,
@@ -84,6 +81,16 @@ impl NativeRuntime for NativeBrokerRuntime {
         let endpoint = BrokerEndpoint::allocate()?;
         open_guard.ipc_cleanup = endpoint.cleanup_path();
         let extensions = config.resolved_extensions()?;
+        if config.seed.is_some() {
+            // Seed bytes stay in this process. Prepare the root using the same
+            // guarded initialization as direct mode, then let the broker own it.
+            let mut native = config.native_config();
+            native.storage = DatabaseStorage::Directory(root_path.clone());
+            drop(liboliphaunt_native_bindings::PreparedNativeRoot::prepare(
+                &native,
+                &extensions,
+            )?);
+        }
         let auth_token = BrokerAuthToken::generate()?;
         let launch_plan = BrokerLaunchPlan {
             executable,
@@ -94,15 +101,13 @@ impl NativeRuntime for NativeBrokerRuntime {
             auth_token,
         };
         let launch = launch_plan.launch(&mut open_guard)?;
-        let cancel = Arc::new(BrokerCancel::new(
-            launch.cancel_endpoint,
-            launch_plan.auth_token.as_str().to_owned(),
-        ));
+        let cancel = Arc::new(BrokerCancel::new(launch.sql_endpoint, launch.cancel_key));
         let (child, temporary_root, ipc_cleanup) = open_guard.into_session_parts();
 
         Ok(Box::new(NativeBrokerSession {
             child: Some(child),
             transport: Some(launch.transport),
+            control: Some(launch.control),
             cancel,
             temporary_root,
             ipc_cleanup,
@@ -115,6 +120,7 @@ impl NativeRuntime for NativeBrokerRuntime {
 struct NativeBrokerSession {
     child: Option,
     transport: Option>,
+    control: Option>,
     cancel: Arc,
     temporary_root: Option,
     ipc_cleanup: Option,
@@ -129,24 +135,20 @@ impl EngineSession for NativeBrokerSession {
     }
 
     fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-        let response = {
-            let transport = self.ensure_transport()?;
-            write_request(
-                transport,
-                RequestFrame::ExecProtocol(request.as_bytes().to_vec()),
-            )
-            .and_then(|()| read_response(transport))
-        };
-        match self.read_response_or_mark_failed(response)? {
-            ResponseFrame::Ok(bytes) => Ok(ProtocolResponse::new(bytes)),
-            ResponseFrame::Error(message) => Err(Error::Engine(message)),
-            ResponseFrame::Chunk(_) => Err(Error::Engine(
-                "broker returned a stream chunk for buffered protocol execution".to_owned(),
-            )),
-            ResponseFrame::StreamCallbackAborted(message) => Err(unexpected_stream_abort(
-                "buffered protocol execution",
-                message,
-            )),
+        let mut bytes = Vec::new();
+        match self.exec_protocol_raw_stream(request, &mut |chunk| {
+            if bytes.len().saturating_add(chunk.len()) > oliphaunt_query::wire::MAX_FRONTEND_MESSAGE
+            {
+                return Err(Error::Engine(
+                    "broker buffered response exceeds size limit".to_owned(),
+                ));
+            }
+            bytes.extend_from_slice(chunk);
+            Ok(())
+        }) {
+            ProtocolStreamOutcome::ReadyForQuery(Ok(())) => Ok(ProtocolResponse::new(bytes)),
+            ProtocolStreamOutcome::ReadyForQuery(Err(error))
+            | ProtocolStreamOutcome::SessionStateUnknown(error) => Err(error),
         }
     }
 
@@ -155,79 +157,32 @@ impl EngineSession for NativeBrokerSession {
         request: ProtocolRequest,
         on_chunk: &mut dyn FnMut(&[u8]) -> Result<()>,
     ) -> ProtocolStreamOutcome {
-        {
-            let transport = match self.ensure_transport() {
-                Ok(transport) => transport,
-                Err(error) => return ProtocolStreamOutcome::SessionStateUnknown(error),
-            };
-            if let Err(error) = write_request(
-                transport,
-                RequestFrame::ExecProtocolStream(request.as_bytes().to_vec()),
-            ) {
-                self.mark_broker_failed(error.clone());
-                return ProtocolStreamOutcome::SessionStateUnknown(error);
-            }
-        }
-
-        let mut callback_error = None;
-        loop {
-            let response = {
-                let transport = match self.ensure_transport() {
-                    Ok(transport) => transport,
-                    Err(error) => return ProtocolStreamOutcome::SessionStateUnknown(error),
-                };
-                read_response(transport)
-            };
-            let response = match self.read_response_or_mark_failed(response) {
-                Ok(response) => response,
-                Err(error) => return ProtocolStreamOutcome::SessionStateUnknown(error),
-            };
-            match response {
-                ResponseFrame::Chunk(bytes) => {
-                    if callback_error.is_none()
-                        && let Err(error) = on_chunk(&bytes)
-                    {
-                        callback_error = Some(error);
-                    }
-                }
-                terminal => return classify_stream_completion(terminal, callback_error),
-            }
+        if let Err(error) = pgwire::completion_count(request.as_bytes()) {
+            return ProtocolStreamOutcome::ReadyForQuery(Err(Error::Engine(error.to_string())));
         }
-    }
-
-    #[cfg(feature = "__internal-broker-helper")]
-    fn exec_simple_query(&mut self, sql: &str) -> Result {
-        let response = {
-            let transport = self.ensure_transport()?;
-            write_request(transport, RequestFrame::ExecSimpleQuery(sql.to_owned()))
-                .and_then(|()| read_response(transport))
+        let transport = match self.ensure_transport() {
+            Ok(transport) => transport,
+            Err(error) => return ProtocolStreamOutcome::SessionStateUnknown(error),
         };
-        match self.read_response_or_mark_failed(response)? {
-            ResponseFrame::Ok(bytes) => Ok(ProtocolResponse::new(bytes)),
-            ResponseFrame::Error(message) => Err(Error::Engine(message)),
-            ResponseFrame::Chunk(_) => Err(Error::Engine(
-                "broker returned a stream chunk for simple-query execution".to_owned(),
-            )),
-            ResponseFrame::StreamCallbackAborted(message) => {
-                Err(unexpected_stream_abort("simple-query execution", message))
-            }
+        match pgwire::exchange(transport.as_mut(), request.as_bytes(), &mut |chunk| {
+            on_chunk(chunk)
+        }) {
+            Ok(Some(error)) => ProtocolStreamOutcome::ReadyForQuery(Err(error)),
+            Ok(None) => ProtocolStreamOutcome::ReadyForQuery(Ok(())),
+            Err(error) => ProtocolStreamOutcome::SessionStateUnknown(
+                self.mark_broker_failed(Error::Engine(error.to_string())),
+            ),
         }
     }
 
     fn backup(&mut self) -> Result> {
-        let response = {
-            let transport = self.ensure_transport()?;
-            write_request(transport, RequestFrame::Backup).and_then(|()| read_response(transport))
-        };
+        self.ensure_transport()?;
+        let control = self.control.as_mut().ok_or(Error::EngineStopped)?;
+        let response =
+            write_request(control, RequestFrame::Backup).and_then(|()| read_response(control));
         match self.read_response_or_mark_failed(response)? {
             ResponseFrame::Ok(bytes) => Ok(bytes),
             ResponseFrame::Error(message) => Err(Error::Engine(message)),
-            ResponseFrame::Chunk(_) => Err(Error::Engine(
-                "broker returned a stream chunk for backup".to_owned(),
-            )),
-            ResponseFrame::StreamCallbackAborted(message) => {
-                Err(unexpected_stream_abort("backup", message))
-            }
         }
     }
 
@@ -247,7 +202,9 @@ struct BrokerLaunchPlan {
 
 struct BrokerLaunch {
     transport: Box,
-    cancel_endpoint: String,
+    control: Box,
+    sql_endpoint: String,
+    cancel_key: [u8; 8],
 }
 
 impl BrokerLaunchPlan {
@@ -274,47 +231,40 @@ impl BrokerLaunchPlan {
                 .expect("broker launch guard owns child while waiting for ready line"),
             stdout,
         )?;
+        let mut control = connect_ready_endpoint(&ready.control)?;
+        authenticate_broker(&mut control, &self.auth_token)?;
         let mut transport = self.endpoint.connect_primary(&ready)?;
-        authenticate_broker(&mut transport, &self.auth_token)?;
+        let cancel_key = pgwire::authenticate(
+            &mut transport,
+            &self.config.username,
+            &self.config.database,
+            self.auth_token.as_str(),
+        )
+        .map_err(|error| Error::Engine(error.to_string()))?;
         Ok(BrokerLaunch {
             transport,
-            cancel_endpoint: ready.cancel,
+            control,
+            sql_endpoint: ready.primary,
+            cancel_key,
         })
     }
 }
 
 struct BrokerCancel {
     endpoint: String,
-    auth_token: String,
+    key: [u8; 8],
 }
 
 impl BrokerCancel {
-    fn new(endpoint: String, auth_token: String) -> Self {
-        Self {
-            endpoint,
-            auth_token,
-        }
+    fn new(endpoint: String, key: [u8; 8]) -> Self {
+        Self { endpoint, key }
     }
 }
 
 impl EngineCancel for BrokerCancel {
     fn cancel(&self) -> Result<()> {
         let mut transport = connect_ready_endpoint(&self.endpoint)?;
-        let token = BrokerAuthToken(self.auth_token.clone());
-        authenticate_broker(&mut transport, &token)?;
-        write_request(&mut transport, RequestFrame::Cancel)?;
-        match read_response(&mut transport)? {
-            ResponseFrame::Ok(_) => Ok(()),
-            ResponseFrame::Error(message) => Err(Error::Engine(format!(
-                "native broker cancel failed: {message}"
-            ))),
-            ResponseFrame::Chunk(_) => Err(Error::Engine(
-                "native broker cancel endpoint returned a stream chunk".to_owned(),
-            )),
-            ResponseFrame::StreamCallbackAborted(message) => {
-                Err(unexpected_stream_abort("cancellation", message))
-            }
-        }
+        pgwire::cancel(&mut transport, &self.key).map_err(|error| Error::Engine(error.to_string()))
     }
 }
 
@@ -381,6 +331,7 @@ impl NativeBrokerSession {
     fn mark_broker_failed(&mut self, error: Error) -> Error {
         let first_error = self.failure.get_or_insert(error).clone();
         self.transport = None;
+        self.control = None;
         if let Some(mut child) = self.child.take() {
             let outcome = reap_child_process(
                 &mut child,
@@ -402,10 +353,14 @@ impl NativeBrokerSession {
         self.closed = true;
         if first_attempt {
             if let Some(transport) = self.transport.as_mut() {
-                let _ = write_request(transport, RequestFrame::Close);
-                let _ = read_response(transport);
+                let _ = transport.write_all(&[b'X', 0, 0, 0, 4]);
             }
             self.transport = None;
+            if let Some(control) = self.control.as_mut() {
+                let _ = write_request(control, RequestFrame::Close);
+                let _ = read_response(control);
+            }
+            self.control = None;
         }
         let mut cleanup_failures = Vec::new();
         if let Some(child) = self.child.as_mut() {
@@ -558,6 +513,9 @@ fn spawn_broker(
     auth_token: &BrokerAuthToken,
 ) -> Result {
     let mut command = Command::new(executable);
+    if let Some(resources) = liboliphaunt_native_bindings::registered_build_resources_dir() {
+        command.env("OLIPHAUNT_RESOURCES_DIR", resources);
+    }
     command
         .args(broker_spawn_args(config, root, extensions, endpoint))
         .stdin(Stdio::null())
@@ -584,6 +542,12 @@ fn broker_spawn_args(
     args.push(OsString::from("--database"));
     args.push(OsString::from(&config.database));
     endpoint.add_args_to(&mut args);
+    if let Some(data) = &config.icu_data {
+        args.push(OsString::from("--icu-data-directory"));
+        args.push(data.directory.as_os_str().to_os_string());
+        args.push(OsString::from("--icu-data-manifest"));
+        args.push(data.manifest.as_os_str().to_os_string());
+    }
     for extension in extensions {
         args.push(OsString::from("--extension"));
         args.push(OsString::from(extension.sql_name()));
@@ -608,36 +572,6 @@ fn authenticate_broker(
         ResponseFrame::Error(message) => Err(Error::Engine(format!(
             "native broker authentication failed: {message}"
         ))),
-        ResponseFrame::Chunk(_) => Err(Error::Engine(
-            "native broker authentication returned a stream chunk".to_owned(),
-        )),
-        ResponseFrame::StreamCallbackAborted(message) => {
-            Err(unexpected_stream_abort("authentication", message))
-        }
-    }
-}
-
-fn unexpected_stream_abort(operation: &str, message: String) -> Error {
-    Error::Engine(format!(
-        "native broker returned a stream callback-aborted completion for {operation}: {message}"
-    ))
-}
-
-fn classify_stream_completion(
-    response: ResponseFrame,
-    callback_error: Option,
-) -> ProtocolStreamOutcome {
-    match response {
-        ResponseFrame::Ok(_) => {
-            ProtocolStreamOutcome::ReadyForQuery(callback_error.map_or(Ok(()), Err))
-        }
-        ResponseFrame::StreamCallbackAborted(message) => ProtocolStreamOutcome::ReadyForQuery(
-            callback_error.map_or_else(|| Err(Error::Engine(message)), Err),
-        ),
-        ResponseFrame::Error(message) => {
-            ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(message))
-        }
-        ResponseFrame::Chunk(_) => unreachable!("stream chunks are consumed before completion"),
     }
 }
 
@@ -668,7 +602,7 @@ fn hex_encode(bytes: &[u8]) -> String {
 
 struct BrokerReadyEndpoints {
     primary: String,
-    cancel: String,
+    control: String,
 }
 
 fn read_ready_line(stdout: &mut impl BufRead) -> Result {
@@ -681,17 +615,17 @@ fn read_ready_line(stdout: &mut impl BufRead) -> Result {
         let primary = parts.next().ok_or_else(|| {
             Error::Engine("native broker ready line did not include a primary endpoint".to_owned())
         })?;
-        let cancel = parts
+        let control = parts
             .next()
-            .and_then(|part| part.strip_prefix("cancel="))
+            .and_then(|part| part.strip_prefix("control="))
             .ok_or_else(|| {
                 Error::Engine(
-                    "native broker ready line did not include a cancel endpoint".to_owned(),
+                    "native broker ready line did not include a management endpoint".to_owned(),
                 )
             })?;
         return Ok(BrokerReadyEndpoints {
             primary: primary.to_owned(),
-            cancel: cancel.to_owned(),
+            control: control.to_owned(),
         });
     }
     if let Some(message) = line.trim().strip_prefix(ERROR_PREFIX) {
@@ -854,11 +788,11 @@ enum BrokerEndpoint {
     Unix {
         dir: PathBuf,
         socket: PathBuf,
-        cancel_socket: PathBuf,
+        control_socket: PathBuf,
     },
     Tcp {
         listen: String,
-        cancel_listen: String,
+        control_listen: String,
     },
 }
 
@@ -867,18 +801,18 @@ impl BrokerEndpoint {
         if env::var(ENV_BROKER_TRANSPORT).ok().as_deref() == Some("tcp") {
             Ok(Self::Tcp {
                 listen: "127.0.0.1:0".to_owned(),
-                cancel_listen: "127.0.0.1:0".to_owned(),
+                control_listen: "127.0.0.1:0".to_owned(),
             })
         } else {
             #[cfg(unix)]
             {
                 let dir = create_temporary_ipc_dir()?;
                 let socket = dir.join("s");
-                let cancel_socket = dir.join("c");
+                let control_socket = dir.join("c");
                 Ok(Self::Unix {
                     dir,
                     socket,
-                    cancel_socket,
+                    control_socket,
                 })
             }
 
@@ -886,7 +820,7 @@ impl BrokerEndpoint {
             {
                 Ok(Self::Tcp {
                     listen: "127.0.0.1:0".to_owned(),
-                    cancel_listen: "127.0.0.1:0".to_owned(),
+                    control_listen: "127.0.0.1:0".to_owned(),
                 })
             }
         }
@@ -897,22 +831,22 @@ impl BrokerEndpoint {
             #[cfg(unix)]
             Self::Unix {
                 socket,
-                cancel_socket,
+                control_socket,
                 ..
             } => {
                 args.push(OsString::from("--socket"));
                 args.push(socket.as_os_str().to_os_string());
-                args.push(OsString::from("--cancel-socket"));
-                args.push(cancel_socket.as_os_str().to_os_string());
+                args.push(OsString::from("--control-socket"));
+                args.push(control_socket.as_os_str().to_os_string());
             }
             Self::Tcp {
                 listen,
-                cancel_listen,
+                control_listen,
             } => {
                 args.push(OsString::from("--listen"));
                 args.push(OsString::from(listen));
-                args.push(OsString::from("--cancel-listen"));
-                args.push(OsString::from(cancel_listen));
+                args.push(OsString::from("--control-listen"));
+                args.push(OsString::from(control_listen));
             }
         }
     }
@@ -1022,7 +956,6 @@ fn create_temporary_ipc_dir() -> Result {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use std::io::Cursor;
 
     #[test]
     fn exited_broker_is_terminal_for_the_existing_session_and_close_still_cleans_up() {
@@ -1041,11 +974,9 @@ mod tests {
         let ipc_cleanup = create_temporary_root().expect("temporary broker IPC root");
         let mut session = NativeBrokerSession {
             child: Some(child),
-            transport: Some(Box::new(Cursor::new(Vec::::new()))),
-            cancel: Arc::new(BrokerCancel::new(
-                "tcp:127.0.0.1:1".to_owned(),
-                "fixture-token".to_owned(),
-            )),
+            transport: None,
+            control: None,
+            cancel: Arc::new(BrokerCancel::new("tcp:127.0.0.1:1".to_owned(), [0; 8])),
             temporary_root: Some(temporary_root.clone()),
             ipc_cleanup: Some(ipc_cleanup.clone()),
             failure: None,
@@ -1089,31 +1020,6 @@ mod tests {
         assert!(!ipc_cleanup.exists());
     }
 
-    #[test]
-    fn broker_stream_recovery_proof_controls_callback_error_precedence() {
-        let callback = Error::Engine("consumer stopped".to_owned());
-        match classify_stream_completion(
-            ResponseFrame::StreamCallbackAborted("helper callback stopped".to_owned()),
-            Some(callback.clone()),
-        ) {
-            ProtocolStreamOutcome::ReadyForQuery(Err(error)) => {
-                assert_eq!(error.kind(), callback.kind());
-                assert_eq!(error.to_string(), callback.to_string());
-            }
-            _ => panic!("typed callback abort must retain ReadyForQuery proof"),
-        }
-
-        let recovery = Error::Engine("broker transport failed before ReadyForQuery".to_owned());
-        match classify_stream_completion(ResponseFrame::Error(recovery.to_string()), Some(callback))
-        {
-            ProtocolStreamOutcome::SessionStateUnknown(error) => {
-                assert_eq!(error.kind(), recovery.kind());
-                assert_eq!(error.to_string(), recovery.to_string());
-            }
-            _ => panic!("independent broker failure must override the callback error"),
-        }
-    }
-
     #[test]
     fn broker_spawn_args_forward_preload_required_extensions_to_helper_before_startup() {
         let mut config = OpenConfig::direct("target/liboliphaunt-broker-preload");
@@ -1124,7 +1030,7 @@ mod tests {
         let extensions = config.resolved_extensions().unwrap();
         let endpoint = BrokerEndpoint::Tcp {
             listen: "127.0.0.1:0".to_owned(),
-            cancel_listen: "127.0.0.1:0".to_owned(),
+            control_listen: "127.0.0.1:0".to_owned(),
         };
         let args = broker_spawn_args(
             &config,
diff --git a/src/sdks/rust/sdk/src/build_resources.rs b/src/sdks/rust/sdk/src/build_resources.rs
new file mode 100644
index 000000000..cd1c30a1b
--- /dev/null
+++ b/src/sdks/rust/sdk/src/build_resources.rs
@@ -0,0 +1,28 @@
+use crate::Result;
+use std::path::PathBuf;
+/// Register resources staged for the application by oliphaunt-build.
+pub fn register_build_resources_dir(path: impl Into) -> Result<()> {
+    liboliphaunt_native_bindings::register_build_resources_dir(path).map_err(Into::into)
+}
+
+#[doc(hidden)]
+pub fn __register_build_resources(path: Option<&str>) -> Result<()> {
+    match path {
+        Some(path) => register_build_resources_dir(path),
+        None => Err(crate::Error::InvalidConfig(
+            "OLIPHAUNT_RESOURCES_DIR was not emitted for this package; add oliphaunt-build as a build dependency and call oliphaunt_build::configure() from build.rs".to_owned(),
+        )),
+    }
+}
+
+/// Register the resources staged by `oliphaunt-build` for the current package.
+///
+/// The macro expands in the application crate, so it can read the
+/// `OLIPHAUNT_RESOURCES_DIR` compile-time value emitted by
+/// `oliphaunt_build::configure()`.
+#[macro_export]
+macro_rules! register_build_resources {
+    () => {
+        $crate::__register_build_resources(option_env!("OLIPHAUNT_RESOURCES_DIR"))
+    };
+}
diff --git a/src/sdks/rust/sdk/src/builder.rs b/src/sdks/rust/sdk/src/builder.rs
new file mode 100644
index 000000000..3de568333
--- /dev/null
+++ b/src/sdks/rust/sdk/src/builder.rs
@@ -0,0 +1,368 @@
+use std::path::PathBuf;
+
+#[cfg(feature = "desktop")]
+use crate::broker::NativeBrokerRuntime;
+use crate::config::{
+    DEFAULT_DATABASE, DEFAULT_USERNAME, EngineMode, NativeBrokerConfig, NativeServerConfig,
+    OpenConfig, PostgresStartupGuc, ServerListen,
+};
+use crate::database::{AsyncOliphaunt, AsyncOliphauntServer};
+use crate::engine::{EngineSession, NativeRuntime};
+use crate::error::{Error, Result};
+use crate::executor::EngineExecutor;
+use crate::extension::Extension;
+use crate::liboliphaunt::OliphauntRuntime;
+#[cfg(feature = "desktop")]
+use crate::server::NativeServerRuntime;
+use crate::storage::DatabaseStorage;
+
+/// Builder for opening native Oliphaunt databases on a dedicated SDK owner thread.
+#[derive(Debug, Clone)]
+pub struct AsyncOliphauntBuilder {
+    mode: EngineMode,
+    broker: NativeBrokerConfig,
+    common: CommonOpenOptions,
+}
+
+/// Builder for starting a native PostgreSQL server on a dedicated SDK owner thread.
+#[derive(Debug, Clone, Default)]
+pub struct AsyncOliphauntServerBuilder {
+    server: NativeServerConfig,
+    common: CommonOpenOptions,
+}
+
+#[derive(Debug, Clone)]
+struct CommonOpenOptions {
+    storage: DatabaseStorage,
+    startup_gucs: Vec,
+    username: String,
+    database: String,
+    extensions: Vec,
+    seed: Option,
+    icu_data: Option,
+}
+
+impl Default for CommonOpenOptions {
+    fn default() -> Self {
+        Self {
+            storage: DatabaseStorage::TemporaryDirectory,
+            startup_gucs: Vec::new(),
+            username: DEFAULT_USERNAME.to_owned(),
+            database: DEFAULT_DATABASE.to_owned(),
+            extensions: Vec::new(),
+            seed: None,
+            icu_data: None,
+        }
+    }
+}
+
+impl CommonOpenOptions {
+    fn build_config(
+        &self,
+        mode: EngineMode,
+        broker: NativeBrokerConfig,
+        server: NativeServerConfig,
+    ) -> Result {
+        let config = OpenConfig {
+            mode,
+            storage: self.storage.clone(),
+            broker,
+            server,
+            startup_gucs: self.startup_gucs.clone(),
+            username: self.username.clone(),
+            database: self.database.clone(),
+            extensions: self.extensions.clone(),
+            seed: self.seed.clone(),
+            icu_data: self.icu_data.clone(),
+        };
+        config.validate()?;
+        Ok(config)
+    }
+}
+
+impl Default for AsyncOliphauntBuilder {
+    fn default() -> Self {
+        Self {
+            mode: EngineMode::Direct,
+            broker: NativeBrokerConfig::default(),
+            common: CommonOpenOptions::default(),
+        }
+    }
+}
+
+impl AsyncOliphauntBuilder {
+    /// Select an explicit cluster seed for a new database.
+    pub fn seed(mut self, seed: liboliphaunt_native_bindings::NativeClusterSeed) -> Self {
+        self.common.seed = Some(seed);
+        self
+    }
+    /// Select independently packaged ICU data and its receipt.
+    pub fn icu_data(mut self, data: liboliphaunt_native_bindings::NativeResourceDirectory) -> Self {
+        self.common.icu_data = Some(data);
+        self
+    }
+    /// Create an asynchronous builder. The database topology defaults to direct.
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Select the in-process direct topology for [`Self::open`].
+    pub fn direct(mut self) -> Self {
+        self.mode = EngineMode::Direct;
+        self
+    }
+
+    /// Select the broker-process topology for [`Self::open`].
+    pub fn broker(mut self) -> Self {
+        self.mode = EngineMode::Broker;
+        self
+    }
+
+    /// Select database storage.
+    pub fn storage(mut self, storage: DatabaseStorage) -> Self {
+        self.common.storage = storage;
+        self
+    }
+
+    /// Use an explicit broker helper executable with `broker().open()`.
+    pub fn broker_executable(mut self, path: impl Into) -> Self {
+        self.broker.executable = Some(path.into());
+        self
+    }
+
+    /// Add an explicit PostgreSQL startup GUC.
+    pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self {
+        self.common
+            .startup_gucs
+            .push(PostgresStartupGuc::new(name, value));
+        self
+    }
+
+    /// Add explicit PostgreSQL startup GUCs.
+    pub fn startup_gucs(mut self, gucs: impl IntoIterator) -> Self
+    where
+        N: Into,
+        V: Into,
+    {
+        self.common.startup_gucs.extend(
+            gucs.into_iter()
+                .map(|(name, value)| PostgresStartupGuc::new(name, value)),
+        );
+        self
+    }
+
+    /// Set the PostgreSQL startup user.
+    pub fn username(mut self, username: impl Into) -> Self {
+        self.common.username = username.into();
+        self
+    }
+
+    /// Set the PostgreSQL database name.
+    pub fn database(mut self, database: impl Into) -> Self {
+        self.common.database = database.into();
+        self
+    }
+
+    /// Make one bundled PostgreSQL extension artifact available to the database.
+    /// Database-local installation remains the application's migration concern.
+    pub fn extension(mut self, extension: Extension) -> Self {
+        self.common.extensions.push(extension);
+        self
+    }
+
+    /// Make bundled PostgreSQL extension artifacts available to the database.
+    /// Database-local installation remains the application's migration concern.
+    pub fn extensions(mut self, extensions: impl IntoIterator) -> Self {
+        self.common.extensions.extend(extensions);
+        self
+    }
+
+    pub(crate) fn build_config(&self) -> Result {
+        if self.mode == EngineMode::Direct && self.broker.executable.is_some() {
+            return Err(Error::InvalidConfig(
+                "broker_executable(...) requires broker().open()".to_owned(),
+            ));
+        }
+        self.common.build_config(
+            self.mode,
+            self.broker.clone(),
+            NativeServerConfig::default(),
+        )
+    }
+
+    /// Open a direct or broker database on a dedicated owner thread.
+    pub async fn open(self) -> Result {
+        let config = self.build_config()?;
+        let (executor, ()) = EngineExecutor::open("oliphaunt-owner", move || {
+            open_embedded_session(config).map(|session| (session, ()))
+        })
+        .await?;
+        Ok(AsyncOliphaunt::from_executor(executor))
+    }
+}
+
+impl AsyncOliphauntServerBuilder {
+    /// Select independently packaged ICU data and its receipt.
+    pub fn icu_data(mut self, data: liboliphaunt_native_bindings::NativeResourceDirectory) -> Self {
+        self.common.icu_data = Some(data);
+        self
+    }
+    /// Create an asynchronous local-server builder.
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Select server storage.
+    pub fn storage(mut self, storage: DatabaseStorage) -> Self {
+        self.common.storage = storage;
+        self
+    }
+
+    /// Use an explicit PostgreSQL server executable.
+    pub fn server_executable(mut self, path: impl Into) -> Self {
+        self.server.executable = Some(path.into());
+        self
+    }
+
+    /// Select the endpoint exposed by the local server.
+    pub fn listen(mut self, listen: ServerListen) -> Self {
+        self.server.listen = listen;
+        self
+    }
+
+    /// Add an explicit PostgreSQL startup GUC.
+    pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self {
+        self.common
+            .startup_gucs
+            .push(PostgresStartupGuc::new(name, value));
+        self
+    }
+
+    /// Add explicit PostgreSQL startup GUCs.
+    pub fn startup_gucs(mut self, gucs: impl IntoIterator) -> Self
+    where
+        N: Into,
+        V: Into,
+    {
+        self.common.startup_gucs.extend(
+            gucs.into_iter()
+                .map(|(name, value)| PostgresStartupGuc::new(name, value)),
+        );
+        self
+    }
+
+    /// Set the PostgreSQL startup user.
+    pub fn username(mut self, username: impl Into) -> Self {
+        self.common.username = username.into();
+        self
+    }
+
+    /// Set the PostgreSQL database name.
+    pub fn database(mut self, database: impl Into) -> Self {
+        self.common.database = database.into();
+        self
+    }
+
+    /// Make one bundled PostgreSQL extension artifact available to clients.
+    /// Database-local installation remains the application's migration concern.
+    pub fn extension(mut self, extension: Extension) -> Self {
+        self.common.extensions.push(extension);
+        self
+    }
+
+    /// Make bundled PostgreSQL extension artifacts available to clients.
+    /// Database-local installation remains the application's migration concern.
+    pub fn extensions(mut self, extensions: impl IntoIterator) -> Self {
+        self.common.extensions.extend(extensions);
+        self
+    }
+
+    pub(crate) fn build_config(&self) -> Result {
+        self.common.build_config(
+            EngineMode::Server,
+            NativeBrokerConfig::default(),
+            self.server.clone(),
+        )
+    }
+
+    /// Start a local PostgreSQL server and return its lifecycle handle.
+    pub async fn start(self) -> Result {
+        let config = self.build_config()?;
+        let (executor, connection_string) =
+            EngineExecutor::open("oliphaunt-server-owner", move || {
+                start_server_session(config)
+            })
+            .await?;
+        Ok(AsyncOliphauntServer::from_executor(
+            executor,
+            connection_string,
+        ))
+    }
+}
+
+pub(crate) fn open_embedded_session(config: OpenConfig) -> Result> {
+    match config.mode {
+        EngineMode::Direct => OliphauntRuntime::from_env().open(config),
+        #[cfg(feature = "desktop")]
+        EngineMode::Broker => NativeBrokerRuntime::from_config(&config.broker).open(config),
+        #[cfg(not(feature = "desktop"))]
+        EngineMode::Broker => Err(Error::InvalidConfig(
+            "broker requires the desktop feature".into(),
+        )),
+        EngineMode::Server => unreachable!("server mode uses its dedicated builder"),
+    }
+}
+
+#[cfg(feature = "desktop")]
+pub(crate) fn start_server_session(config: OpenConfig) -> Result<(Box, String)> {
+    let session = NativeServerRuntime::from_config(&config.server).open(config)?;
+    let connection_string = session.connection_string().ok_or_else(|| {
+        Error::Engine("native server did not expose its connection string".to_owned())
+    })?;
+    Ok((session, connection_string))
+}
+
+#[cfg(not(feature = "desktop"))]
+pub(crate) fn start_server_session(
+    _config: OpenConfig,
+) -> Result<(Box, String)> {
+    Err(Error::InvalidConfig(
+        "server requires the desktop feature".into(),
+    ))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn direct_open_rejects_a_broker_executable_instead_of_ignoring_it() {
+        let error = AsyncOliphauntBuilder::new()
+            .broker_executable("oliphaunt-broker")
+            .build_config()
+            .expect_err("direct cannot silently ignore a broker executable");
+        assert_eq!(error.kind(), crate::error::ErrorKind::InvalidConfiguration);
+        assert_eq!(
+            error.to_string(),
+            "broker_executable(...) requires broker().open()"
+        );
+        AsyncOliphauntBuilder::new()
+            .broker()
+            .broker_executable("oliphaunt-broker")
+            .build_config()
+            .expect("broker executable is valid for broker open");
+    }
+
+    #[test]
+    fn dedicated_server_builder_produces_only_server_configuration() {
+        let config = AsyncOliphauntServerBuilder::new()
+            .listen(ServerListen::tcp_port(6543))
+            .server_executable("postgres")
+            .build_config()
+            .expect("server configuration");
+        assert_eq!(config.mode, EngineMode::Server);
+        assert_eq!(config.server.listen, ServerListen::tcp_port(6543));
+        assert_eq!(config.server.executable, Some(PathBuf::from("postgres")));
+        assert!(config.broker.executable.is_none());
+    }
+}
diff --git a/src/sdks/rust/src/cancellation.rs b/src/sdks/rust/sdk/src/cancellation.rs
similarity index 100%
rename from src/sdks/rust/src/cancellation.rs
rename to src/sdks/rust/sdk/src/cancellation.rs
diff --git a/src/sdks/rust/src/child_process.rs b/src/sdks/rust/sdk/src/child_process.rs
similarity index 100%
rename from src/sdks/rust/src/child_process.rs
rename to src/sdks/rust/sdk/src/child_process.rs
diff --git a/src/sdks/rust/sdk/src/config.rs b/src/sdks/rust/sdk/src/config.rs
new file mode 100644
index 000000000..efad3898e
--- /dev/null
+++ b/src/sdks/rust/sdk/src/config.rs
@@ -0,0 +1,368 @@
+use std::path::{Path, PathBuf};
+
+use crate::error::{Error, Result};
+use crate::extension::Extension;
+use crate::storage::{DatabaseStorage, path_contains_nul};
+
+/// Default PostgreSQL role used by SDK-managed native sessions.
+pub(crate) const DEFAULT_USERNAME: &str = "postgres";
+
+/// Default PostgreSQL database used by SDK-managed native sessions.
+pub(crate) const DEFAULT_DATABASE: &str = "postgres";
+
+/// Native runtime mode.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub(crate) enum EngineMode {
+    /// In-process embedded PostgreSQL.
+    Direct,
+    /// Process-isolated embedded PostgreSQL.
+    Broker,
+    /// Local PostgreSQL-compatible server.
+    Server,
+}
+
+pub(crate) use liboliphaunt_native_bindings::PostgresStartupGuc;
+
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
+pub(crate) struct NativeBrokerConfig {
+    pub(crate) executable: Option,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
+pub(crate) struct NativeServerConfig {
+    pub(crate) executable: Option,
+    pub(crate) listen: ServerListen,
+}
+
+/// Local endpoint exposed by a native PostgreSQL server.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum ServerListen {
+    /// Listen on the fixed loopback address. `None` allocates an ephemeral port.
+    Tcp {
+        /// PostgreSQL port, or `None` for an ephemeral port.
+        port: Option,
+    },
+    /// Listen in a PostgreSQL Unix-domain socket directory.
+    ///
+    /// The resolved directory must be valid UTF-8 because server handles
+    /// publish it through a portable PostgreSQL connection string.
+    #[cfg(unix)]
+    Unix {
+        /// Directory containing `.s.PGSQL.`.
+        directory: PathBuf,
+        /// PostgreSQL port encoded in the socket filename.
+        port: u16,
+    },
+}
+
+impl Default for ServerListen {
+    fn default() -> Self {
+        Self::tcp()
+    }
+}
+
+impl ServerListen {
+    /// Listen on loopback using an ephemeral TCP port.
+    pub const fn tcp() -> Self {
+        Self::Tcp { port: None }
+    }
+
+    /// Listen on loopback using a fixed TCP port.
+    pub const fn tcp_port(port: u16) -> Self {
+        Self::Tcp { port: Some(port) }
+    }
+
+    /// Listen in a UTF-8 Unix-domain socket directory using PostgreSQL port
+    /// 5432.
+    #[cfg(unix)]
+    pub fn unix(directory: impl Into) -> Self {
+        Self::Unix {
+            directory: directory.into(),
+            port: 5432,
+        }
+    }
+
+    /// Listen in a UTF-8 Unix-domain socket directory using a fixed PostgreSQL
+    /// port.
+    #[cfg(unix)]
+    pub fn unix_port(directory: impl Into, port: u16) -> Self {
+        Self::Unix {
+            directory: directory.into(),
+            port,
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub(crate) struct OpenConfig {
+    pub(crate) mode: EngineMode,
+    pub(crate) storage: DatabaseStorage,
+    pub(crate) broker: NativeBrokerConfig,
+    pub(crate) server: NativeServerConfig,
+    pub(crate) startup_gucs: Vec,
+    pub(crate) username: String,
+    pub(crate) database: String,
+    pub(crate) extensions: Vec,
+    pub(crate) seed: Option,
+    pub(crate) icu_data: Option,
+}
+
+impl OpenConfig {
+    #[cfg(test)]
+    pub(crate) fn direct(directory: impl Into) -> Self {
+        Self {
+            mode: EngineMode::Direct,
+            storage: DatabaseStorage::Directory(directory.into()),
+            broker: NativeBrokerConfig::default(),
+            server: NativeServerConfig::default(),
+            startup_gucs: Vec::new(),
+            username: DEFAULT_USERNAME.to_owned(),
+            database: DEFAULT_DATABASE.to_owned(),
+            extensions: Vec::new(),
+            seed: None,
+            icu_data: None,
+        }
+    }
+
+    pub(crate) fn validate(&self) -> Result<()> {
+        self.native_config().validate()?;
+        match self.mode {
+            EngineMode::Broker => {
+                if let Some(executable) = &self.broker.executable {
+                    validate_config_path("native broker executable path", executable)?;
+                }
+            }
+            EngineMode::Server => {
+                for guc in &self.startup_gucs {
+                    let name = guc.name.trim();
+                    if ["listen_addresses", "port", "unix_socket_directories"]
+                        .iter()
+                        .any(|owned| name.eq_ignore_ascii_case(owned))
+                    {
+                        return Err(Error::InvalidConfig(format!(
+                            "native server owns PostgreSQL startup GUC '{name}'; configure its storage and listener through OliphauntServerBuilder"
+                        )));
+                    }
+                }
+                match &self.server.listen {
+                    ServerListen::Tcp { port: Some(0) } => {
+                        return Err(Error::InvalidConfig(
+                            "native TCP server port must be greater than zero; omit the port to allocate one"
+                                .to_owned(),
+                        ));
+                    }
+                    #[cfg(unix)]
+                    ServerListen::Unix { directory, port } => {
+                        validate_config_path("native server Unix socket directory", directory)?;
+                        let resolved_directory = if directory.is_absolute() {
+                            directory.clone()
+                        } else {
+                            std::env::current_dir()
+                                .map_err(|error| {
+                                    Error::Engine(format!(
+                                        "resolve current directory for native server Unix socket: {error}"
+                                    ))
+                                })?
+                                .join(directory)
+                        };
+                        server_unix_socket_directory_str(&resolved_directory)?;
+                        validate_server_unix_socket_path(&resolved_directory, *port)?;
+                        if *port == 0 {
+                            return Err(Error::InvalidConfig(
+                                "native Unix server port must be greater than zero".to_owned(),
+                            ));
+                        }
+                    }
+                    _ => {}
+                }
+                if let Some(executable) = &self.server.executable {
+                    validate_config_path("native server executable path", executable)?;
+                }
+            }
+            EngineMode::Direct => {}
+        }
+        Ok(())
+    }
+
+    pub(crate) fn native_config(&self) -> liboliphaunt_native_bindings::NativeConfig {
+        liboliphaunt_native_bindings::NativeConfig {
+            storage: self.storage.clone(),
+            startup_gucs: self.startup_gucs.clone(),
+            username: self.username.clone(),
+            database: self.database.clone(),
+            extensions: self.extensions.clone(),
+            seed: self.seed.clone(),
+            icu_data: self.icu_data.clone(),
+        }
+    }
+    #[cfg(feature = "desktop")]
+    pub(crate) fn resolved_extensions(&self) -> Result> {
+        self.native_config()
+            .resolved_extensions()
+            .map_err(Into::into)
+    }
+    #[cfg(any(feature = "desktop", test))]
+    pub(crate) fn postgres_startup_assignments(&self, extensions: &[Extension]) -> Vec {
+        self.native_config()
+            .postgres_startup_assignments(extensions)
+    }
+}
+fn validate_config_path(label: &str, path: &Path) -> Result<()> {
+    if path.as_os_str().is_empty() {
+        return Err(Error::InvalidConfig(format!("{label} must not be empty")));
+    }
+    if path_contains_nul(path) {
+        return Err(Error::InvalidConfig(format!(
+            "{label} must not contain NUL bytes"
+        )));
+    }
+    Ok(())
+}
+
+#[cfg(unix)]
+pub(crate) fn server_unix_socket_directory_str(directory: &Path) -> Result<&str> {
+    directory.to_str().ok_or_else(|| {
+        Error::InvalidConfig(
+            "native server Unix socket directory must be valid UTF-8 so the published PostgreSQL connection string preserves the exact path"
+                .to_owned(),
+        )
+    })
+}
+
+#[cfg(unix)]
+fn validate_server_unix_socket_path(directory: &Path, port: u16) -> Result<()> {
+    let socket = directory.join(format!(".s.PGSQL.{port}"));
+    if socket.as_os_str().len() >= 100 {
+        return Err(Error::InvalidConfig(format!(
+            "native server Unix socket path is too long: {}",
+            socket.display()
+        )));
+    }
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{EngineMode, OpenConfig, PostgresStartupGuc, ServerListen};
+
+    #[test]
+    fn startup_guc_names_use_portable_postgres_grammar() {
+        let mut config = OpenConfig::direct("target/test-roots/native-direct-guc-grammar");
+        config.startup_gucs = vec![
+            PostgresStartupGuc::new("_name", ""),
+            PostgresStartupGuc::new("ext.name$1", "on"),
+        ];
+        config.validate().unwrap();
+        assert_eq!(
+            config.postgres_startup_assignments(&[]),
+            ["_name=", "ext.name$1=on"]
+        );
+
+        for name in ["1name", ".foo", "a..b", "a.1b", "ext.$name"] {
+            config.startup_gucs = vec![PostgresStartupGuc::new(name, "1")];
+            assert!(
+                config.validate().is_err(),
+                "accepted invalid GUC name {name}"
+            );
+        }
+        config.startup_gucs = vec![PostgresStartupGuc::new("good", "bad\0value")];
+        assert!(config.validate().is_err());
+    }
+
+    #[test]
+    fn native_server_rejects_caller_owned_topology_gucs() {
+        for name in ["LISTEN_ADDRESSES", "port", "unix_socket_directories"] {
+            let mut config = OpenConfig::direct("target/test-roots/native-server-owned-guc");
+            config.mode = EngineMode::Server;
+            config.startup_gucs = vec![PostgresStartupGuc::new(name, "override")];
+
+            let error = config.validate().expect_err("server topology is SDK-owned");
+            assert!(error.to_string().contains("native server owns"), "{error}");
+        }
+    }
+
+    #[test]
+    fn every_native_topology_rejects_storage_redirection_gucs() {
+        for mode in [EngineMode::Direct, EngineMode::Broker, EngineMode::Server] {
+            for name in ["CONFIG_FILE", "data_directory"] {
+                let mut config = OpenConfig::direct("target/test-roots/native-owned-guc");
+                config.mode = mode;
+                config.startup_gucs = vec![PostgresStartupGuc::new(name, "/tmp/other")];
+
+                let error = config.validate().expect_err("storage is SDK-owned");
+                assert!(error.to_string().contains("Oliphaunt owns"), "{error}");
+            }
+        }
+    }
+
+    #[test]
+    fn server_listen_matches_shared_postgres_vocabulary() {
+        let fixture: serde_json::Value =
+            serde_json::from_str(&crate::test_fixtures::text("postgres/server-listen.json"))
+                .unwrap();
+        assert_eq!(fixture["tcp"]["host"], "127.0.0.1");
+        assert_eq!(fixture["unix"]["defaultPort"], 5432);
+        assert_eq!(fixture["unix"]["filePrefix"], ".s.PGSQL.");
+
+        let mut config = OpenConfig::direct("target/test-roots/native-server-listen");
+        config.mode = EngineMode::Server;
+        for port in fixture["tcp"]["validPorts"].as_array().unwrap() {
+            config.server.listen = ServerListen::tcp_port(port.as_u64().unwrap() as u16);
+            config.validate().unwrap();
+        }
+        config.server.listen = ServerListen::tcp_port(0);
+        assert!(config.validate().is_err());
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn server_listen_rejects_non_utf8_unix_socket_directory_without_mutation() {
+        use std::ffi::OsString;
+        use std::os::unix::ffi::OsStringExt;
+        use std::time::{SystemTime, UNIX_EPOCH};
+
+        let mut leaf = format!(
+            "oliphaunt-native-socket-{}-{}-",
+            std::process::id(),
+            SystemTime::now()
+                .duration_since(UNIX_EPOCH)
+                .expect("system clock should be after epoch")
+                .as_nanos()
+        )
+        .into_bytes();
+        leaf.push(0xff);
+        let directory = std::env::temp_dir().join(OsString::from_vec(leaf));
+        assert!(!directory.exists());
+
+        let mut config = OpenConfig::direct("target/test-roots/native-server-non-utf8-uri");
+        config.mode = EngineMode::Server;
+        config.server.listen = ServerListen::unix_port(directory.clone(), 15432);
+        let error = config
+            .validate()
+            .expect_err("a String connection URI cannot preserve a non-UTF-8 socket path");
+
+        assert!(error.to_string().contains("must be valid UTF-8"));
+        assert!(!directory.exists());
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn server_listen_rejects_too_long_unix_socket_path_without_mutation() {
+        let directory = std::env::temp_dir().join(format!(
+            "oliphaunt-native-socket-{}-{}",
+            std::process::id(),
+            "x".repeat(120)
+        ));
+        assert!(!directory.exists());
+
+        let mut config = OpenConfig::direct("target/test-roots/native-server-long-uri");
+        config.mode = EngineMode::Server;
+        config.server.listen = ServerListen::unix_port(directory.clone(), 15432);
+        let error = config
+            .validate()
+            .expect_err("Unix socket sockaddr length must be validated before root preparation");
+
+        assert!(error.to_string().contains("socket path is too long"));
+        assert!(!directory.exists());
+    }
+}
diff --git a/src/sdks/rust/src/database.rs b/src/sdks/rust/sdk/src/database.rs
similarity index 99%
rename from src/sdks/rust/src/database.rs
rename to src/sdks/rust/sdk/src/database.rs
index ffd177a5d..4320ecca3 100644
--- a/src/sdks/rust/src/database.rs
+++ b/src/sdks/rust/sdk/src/database.rs
@@ -32,7 +32,7 @@ use crate::session::{
 /// async runtime is required.
 #[derive(Clone)]
 pub struct AsyncOliphaunt {
-    executor: Arc,
+    pub(crate) executor: Arc,
 }
 
 /// Cloneable asynchronous local PostgreSQL server lifecycle handle.
@@ -55,7 +55,7 @@ pub struct AsyncSql<'db, 'q> {
     result_format: ValueFormat,
 }
 
-fn adapt_raw_stream_callback(
+pub(crate) fn adapt_raw_stream_callback(
     mut on_chunk: F,
     callback_error: Arc>>,
 ) -> impl FnMut(&[u8]) -> Result<()> + Send + 'static
@@ -77,7 +77,7 @@ where
     }
 }
 
-fn resolve_raw_stream_outcome(
+pub(crate) fn resolve_raw_stream_outcome(
     outcome: Result,
     callback_error: Arc>>,
 ) -> RawStreamResult<(), E> {
diff --git a/src/sdks/rust/src/direct.rs b/src/sdks/rust/sdk/src/direct.rs
similarity index 98%
rename from src/sdks/rust/src/direct.rs
rename to src/sdks/rust/sdk/src/direct.rs
index 293c6e61d..e4f761692 100644
--- a/src/sdks/rust/src/direct.rs
+++ b/src/sdks/rust/sdk/src/direct.rs
@@ -52,6 +52,16 @@ impl Default for OliphauntBuilder {
 }
 
 impl OliphauntBuilder {
+    /// Select an explicit cluster seed for a new database.
+    pub fn seed(mut self, seed: liboliphaunt_native_bindings::NativeClusterSeed) -> Self {
+        self.inner = self.inner.seed(seed);
+        self
+    }
+    /// Select independently packaged ICU data and its receipt.
+    pub fn icu_data(mut self, data: liboliphaunt_native_bindings::NativeResourceDirectory) -> Self {
+        self.inner = self.inner.icu_data(data);
+        self
+    }
     /// Create a blocking builder. The database topology defaults to direct.
     pub fn new() -> Self {
         Self::default()
@@ -140,6 +150,11 @@ pub struct OliphauntServerBuilder {
 }
 
 impl OliphauntServerBuilder {
+    /// Select independently packaged ICU data and its receipt.
+    pub fn icu_data(mut self, data: liboliphaunt_native_bindings::NativeResourceDirectory) -> Self {
+        self.inner = self.inner.icu_data(data);
+        self
+    }
     /// Create a blocking local-server builder.
     pub fn new() -> Self {
         Self::default()
diff --git a/src/sdks/rust/src/engine.rs b/src/sdks/rust/sdk/src/engine.rs
similarity index 94%
rename from src/sdks/rust/src/engine.rs
rename to src/sdks/rust/sdk/src/engine.rs
index bedeb9e88..85426fd96 100644
--- a/src/sdks/rust/src/engine.rs
+++ b/src/sdks/rust/sdk/src/engine.rs
@@ -20,6 +20,7 @@ pub(crate) trait NativeRuntime: Send + Sync + 'static {
 }
 
 pub(crate) trait EngineSession: Send + 'static {
+    #[cfg(any(feature = "desktop", test))]
     fn connection_string(&self) -> Option {
         None
     }
@@ -41,11 +42,6 @@ pub(crate) trait EngineSession: Send + 'static {
         }
     }
 
-    #[cfg(feature = "__internal-broker-helper")]
-    fn exec_simple_query(&mut self, sql: &str) -> Result {
-        self.exec_protocol_raw(ProtocolRequest::simple_query(sql)?)
-    }
-
     fn backup(&mut self) -> Result> {
         Err(Error::Engine(
             "physical backup is not supported by this runtime".into(),
diff --git a/src/sdks/rust/sdk/src/error.rs b/src/sdks/rust/sdk/src/error.rs
new file mode 100644
index 000000000..14714be73
--- /dev/null
+++ b/src/sdks/rust/sdk/src/error.rs
@@ -0,0 +1,593 @@
+use std::convert::Infallible;
+use std::error;
+use std::fmt;
+
+pub use crate::query_core::{PostgresError, PostgresErrorField};
+
+/// Result alias used by the native SDK.
+pub type Result = std::result::Result;
+
+/// Result returned by a callback-scoped transaction.
+///
+/// `E` is the callback's application error type. The default keeps callbacks
+/// which use only SDK errors concise.
+pub type TransactionResult = std::result::Result>;
+
+/// Result returned by raw protocol streaming.
+///
+/// `E` is the callback's parser or application error type. The default is
+/// [`Infallible`] for callbacks which cannot fail deliberately.
+pub type RawStreamResult = std::result::Result>;
+
+mod raw_stream_callback_output {
+    pub trait Sealed {}
+
+    impl Sealed for () {}
+    impl Sealed for std::result::Result<(), E> {}
+}
+
+/// Supported return values from a raw protocol stream callback.
+///
+/// Return `()` for an infallible callback or `Result<(), E>` to stop delivery
+/// with a typed parser or application error. This trait is sealed so the two
+/// stable callback forms remain exhaustive.
+pub trait RawStreamCallbackOutput: raw_stream_callback_output::Sealed {
+    /// Typed callback failure, or [`Infallible`] for a callback returning `()`.
+    type Error;
+
+    /// Convert the callback output into its typed result.
+    #[doc(hidden)]
+    fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error>;
+}
+
+impl RawStreamCallbackOutput for () {
+    type Error = Infallible;
+
+    fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error> {
+        Ok(())
+    }
+}
+
+impl RawStreamCallbackOutput for std::result::Result<(), E> {
+    type Error = E;
+
+    fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error> {
+        self
+    }
+}
+
+/// Error from a callback-scoped transaction.
+///
+/// Callback code follows the Diesel/sqlx convention `E: From`, allowing
+/// SQL operations to use `?` while deliberate business aborts remain the
+/// caller's concrete `E`. If both the callback and rollback fail, both typed
+/// causes remain available.
+#[derive(Debug, Clone)]
+#[non_exhaustive]
+pub enum TransactionError {
+    /// `BEGIN`, `COMMIT`, explicit settlement, or another SDK operation failed.
+    Database(Error),
+    /// The callback deliberately aborted with an application error.
+    Callback(E),
+    /// The callback returned an error and an attempted rollback failed, possibly
+    /// together with releasing the transaction's owner pin.
+    CallbackAndRollback {
+        /// Error returned by the callback.
+        callback: E,
+        /// Error returned while rolling back or releasing the transaction pin.
+        rollback: Error,
+    },
+    /// The callback returned an error after an independent database, transport,
+    /// or protocol-recovery failure had already expired the transaction. No
+    /// rollback was attempted.
+    CallbackAndDatabase {
+        /// Error returned by the callback.
+        callback: E,
+        /// Independent SDK, database, transport, or recovery failure.
+        database: Error,
+    },
+}
+
+impl TransactionError {
+    /// Wrap a deliberate application-level transaction abort.
+    pub fn callback(error: E) -> Self {
+        Self::Callback(error)
+    }
+
+    /// Return the application error, including when rollback also failed.
+    pub fn callback_error(&self) -> Option<&E> {
+        match self {
+            Self::Callback(error) => Some(error),
+            Self::CallbackAndRollback { callback, .. } => Some(callback),
+            Self::CallbackAndDatabase { callback, .. } => Some(callback),
+            Self::Database(_) => None,
+        }
+    }
+
+    /// Return the SDK failure which occurred before callback settlement.
+    pub fn database_error(&self) -> Option<&Error> {
+        match self {
+            Self::Database(error)
+            | Self::CallbackAndDatabase {
+                database: error, ..
+            } => Some(error),
+            Self::Callback(_) | Self::CallbackAndRollback { .. } => None,
+        }
+    }
+
+    /// Return the attempted rollback or transaction-pin release failure.
+    pub fn rollback_error(&self) -> Option<&Error> {
+        match self {
+            Self::CallbackAndRollback { rollback, .. } => Some(rollback),
+            Self::Database(_) | Self::Callback(_) | Self::CallbackAndDatabase { .. } => None,
+        }
+    }
+}
+
+impl From for TransactionError {
+    fn from(error: Error) -> Self {
+        Self::Database(error)
+    }
+}
+
+impl From> for Error {
+    fn from(error: TransactionError) -> Self {
+        match error {
+            TransactionError::Database(error) => error,
+            TransactionError::Callback(error) => error,
+            TransactionError::CallbackAndRollback { callback, rollback } => {
+                Self::transaction_rollback(callback, rollback)
+            }
+            TransactionError::CallbackAndDatabase { callback, database } => {
+                Self::transaction_callback_and_database(callback, database)
+            }
+        }
+    }
+}
+
+impl fmt::Display for TransactionError
+where
+    E: fmt::Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Database(error) => error.fmt(f),
+            Self::Callback(error) => error.fmt(f),
+            Self::CallbackAndRollback { callback, rollback } => write!(
+                f,
+                "transaction callback failed: {callback}; rollback also failed: {rollback}"
+            ),
+            Self::CallbackAndDatabase { callback, database } => write!(
+                f,
+                "transaction callback failed: {callback}; an independent database failure also occurred: {database}"
+            ),
+        }
+    }
+}
+
+impl error::Error for TransactionError
+where
+    E: error::Error + 'static,
+{
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        match self {
+            Self::Database(error) => Some(error),
+            Self::Callback(error) => Some(error),
+            Self::CallbackAndRollback { callback, .. }
+            | Self::CallbackAndDatabase { callback, .. } => Some(callback),
+        }
+    }
+}
+
+/// Error from raw PostgreSQL protocol streaming.
+///
+/// A callback error is returned only after the runtime confirms recovery to
+/// `ReadyForQuery`. An independent runtime or transport failure is represented
+/// by [`Self::Database`] and remains authoritative.
+#[derive(Debug, Clone)]
+#[non_exhaustive]
+pub enum RawStreamError {
+    /// The SDK, runtime, transport, or recovery operation failed.
+    Database(Error),
+    /// The runtime recovered successfully after the callback returned this
+    /// parser or application error.
+    Callback(E),
+    /// An owner-thread callback panicked after the runtime confirmed
+    /// `ReadyForQuery`. Blocking APIs resume the original unwind instead.
+    CallbackPanicked(Error),
+}
+
+impl RawStreamError {
+    /// Return the recovered callback error.
+    pub fn callback_error(&self) -> Option<&E> {
+        match self {
+            Self::Callback(error) => Some(error),
+            Self::Database(_) | Self::CallbackPanicked(_) => None,
+        }
+    }
+
+    /// Return the authoritative SDK or recovery failure.
+    pub fn database_error(&self) -> Option<&Error> {
+        match self {
+            Self::Database(error) => Some(error),
+            Self::Callback(_) | Self::CallbackPanicked(_) => None,
+        }
+    }
+
+    /// Return a recovered owner-thread callback panic. This is distinct from
+    /// an independent database/recovery failure and does not imply poisoning.
+    pub fn callback_panic_error(&self) -> Option<&Error> {
+        match self {
+            Self::CallbackPanicked(error) => Some(error),
+            Self::Database(_) | Self::Callback(_) => None,
+        }
+    }
+}
+
+impl From for RawStreamError {
+    fn from(error: Error) -> Self {
+        Self::Database(error)
+    }
+}
+
+impl From> for Error {
+    fn from(error: RawStreamError) -> Self {
+        match error {
+            RawStreamError::Database(error) => error,
+            RawStreamError::Callback(never) => match never {},
+            RawStreamError::CallbackPanicked(error) => error,
+        }
+    }
+}
+
+impl From> for Error {
+    fn from(error: RawStreamError) -> Self {
+        match error {
+            RawStreamError::Database(error)
+            | RawStreamError::Callback(error)
+            | RawStreamError::CallbackPanicked(error) => error,
+        }
+    }
+}
+
+impl fmt::Display for RawStreamError
+where
+    E: fmt::Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Database(error) => error.fmt(f),
+            Self::Callback(error) => error.fmt(f),
+            Self::CallbackPanicked(error) => error.fmt(f),
+        }
+    }
+}
+
+impl error::Error for RawStreamError
+where
+    E: error::Error + 'static,
+{
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        match self {
+            Self::Database(error) => Some(error),
+            Self::Callback(error) => Some(error),
+            Self::CallbackPanicked(error) => Some(error),
+        }
+    }
+}
+
+pub(crate) const SESSION_STATE_UNKNOWN: &str =
+    "PostgreSQL session state is unknown; close the database";
+
+/// Stable category for an Oliphaunt SDK error.
+///
+/// Match this value when an application needs recovery policy. The concrete
+/// [`Error`] remains opaque so implementation details and platform-specific
+/// causes can evolve without expanding a public error enum.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum ErrorKind {
+    /// A builder option or other caller-supplied configuration is invalid.
+    InvalidConfiguration,
+    /// The requested work crossed a database or owner lifecycle boundary.
+    Lifecycle,
+    /// Root work was rejected because a callback transaction owns the session.
+    TransactionActive,
+    /// PostgreSQL returned a structured `ErrorResponse`.
+    Postgres,
+    /// An engine, protocol, storage, transport, callback, or other failure.
+    Other,
+}
+
+/// Opaque error returned by the native Rust SDK.
+#[derive(Debug, Clone)]
+pub struct Error {
+    inner: ErrorInner,
+}
+
+#[derive(Debug, Clone)]
+enum ErrorInner {
+    EngineStopped,
+    Engine(String),
+    Postgres(Box),
+    TransactionActive,
+    TransactionRollback {
+        callback: Box,
+        rollback: Box,
+    },
+    TransactionCallbackAndDatabase {
+        callback: Box,
+        database: Box,
+    },
+    InvalidConfiguration(String),
+}
+
+impl Error {
+    /// Return the stable recovery category for this failure.
+    pub const fn kind(&self) -> ErrorKind {
+        match &self.inner {
+            ErrorInner::EngineStopped => ErrorKind::Lifecycle,
+            ErrorInner::Postgres(_) => ErrorKind::Postgres,
+            ErrorInner::TransactionActive => ErrorKind::TransactionActive,
+            ErrorInner::InvalidConfiguration(_) => ErrorKind::InvalidConfiguration,
+            ErrorInner::Engine(_)
+            | ErrorInner::TransactionRollback { .. }
+            | ErrorInner::TransactionCallbackAndDatabase { .. } => ErrorKind::Other,
+        }
+    }
+
+    /// Return structured PostgreSQL diagnostics when this is a backend error.
+    pub fn postgres_error(&self) -> Option<&PostgresError> {
+        match &self.inner {
+            ErrorInner::Postgres(error) => Some(error.as_ref()),
+            _ => None,
+        }
+    }
+
+    /// Return both failures when a transaction callback and rollback failed.
+    pub fn transaction_rollback_errors(&self) -> Option<(&Error, &Error)> {
+        match &self.inner {
+            ErrorInner::TransactionRollback { callback, rollback } => {
+                Some((callback.as_ref(), rollback.as_ref()))
+            }
+            _ => None,
+        }
+    }
+
+    /// Return both failures when a callback error follows an independent
+    /// database or protocol failure. This pair never implies that rollback ran.
+    pub fn transaction_callback_database_errors(&self) -> Option<(&Error, &Error)> {
+        match &self.inner {
+            ErrorInner::TransactionCallbackAndDatabase { callback, database } => {
+                Some((callback.as_ref(), database.as_ref()))
+            }
+            _ => None,
+        }
+    }
+
+    #[allow(non_upper_case_globals)]
+    pub(crate) const EngineStopped: Self = Self {
+        inner: ErrorInner::EngineStopped,
+    };
+
+    #[allow(non_upper_case_globals)]
+    pub(crate) const TransactionActive: Self = Self {
+        inner: ErrorInner::TransactionActive,
+    };
+
+    #[allow(non_snake_case)]
+    pub(crate) fn Engine(message: String) -> Self {
+        Self {
+            inner: ErrorInner::Engine(message),
+        }
+    }
+
+    #[allow(non_snake_case)]
+    pub(crate) fn Postgres(error: Box) -> Self {
+        Self {
+            inner: ErrorInner::Postgres(error),
+        }
+    }
+
+    #[allow(non_snake_case)]
+    pub(crate) fn InvalidConfig(message: String) -> Self {
+        Self {
+            inner: ErrorInner::InvalidConfiguration(message),
+        }
+    }
+
+    fn transaction_rollback(callback: Self, rollback: Self) -> Self {
+        Self {
+            inner: ErrorInner::TransactionRollback {
+                callback: Box::new(callback),
+                rollback: Box::new(rollback),
+            },
+        }
+    }
+
+    fn transaction_callback_and_database(callback: Self, database: Self) -> Self {
+        Self {
+            inner: ErrorInner::TransactionCallbackAndDatabase {
+                callback: Box::new(callback),
+                database: Box::new(database),
+            },
+        }
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match &self.inner {
+            ErrorInner::EngineStopped => f.write_str("native database session has stopped"),
+            ErrorInner::Engine(message) => f.write_str(message),
+            ErrorInner::Postgres(error) => error.fmt(f),
+            ErrorInner::TransactionActive => {
+                f.write_str("a transaction is active; use the active transaction handle")
+            }
+            ErrorInner::TransactionRollback { callback, rollback } => write!(
+                f,
+                "transaction callback failed: {callback}; rollback also failed: {rollback}"
+            ),
+            ErrorInner::TransactionCallbackAndDatabase { callback, database } => write!(
+                f,
+                "transaction callback failed: {callback}; an independent database failure also occurred: {database}"
+            ),
+            ErrorInner::InvalidConfiguration(message) => f.write_str(message),
+        }
+    }
+}
+
+impl error::Error for Error {
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        match &self.inner {
+            ErrorInner::Postgres(error) => Some(error.as_ref()),
+            ErrorInner::TransactionRollback { callback, .. }
+            | ErrorInner::TransactionCallbackAndDatabase { callback, .. } => {
+                Some(callback.as_ref())
+            }
+            _ => None,
+        }
+    }
+}
+
+impl From for Error {
+    fn from(error: oliphaunt_query::Error) -> Self {
+        crate::query::error_from_core(error)
+    }
+}
+
+impl From for Error {
+    fn from(error: liboliphaunt_native_bindings::Error) -> Self {
+        match error {
+            liboliphaunt_native_bindings::Error::InvalidConfig(message) => {
+                Self::InvalidConfig(message)
+            }
+            liboliphaunt_native_bindings::Error::Engine(message) => Self::Engine(message),
+            liboliphaunt_native_bindings::Error::EngineStopped => Self::EngineStopped,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::query_core as core;
+
+    #[test]
+    fn localized_severity_is_primary_and_both_forms_remain_available() {
+        let fields = vec![
+            PostgresErrorField {
+                code: b'S',
+                value: "ERREUR".to_owned(),
+            },
+            PostgresErrorField {
+                code: b'V',
+                value: "ERROR".to_owned(),
+            },
+            PostgresErrorField {
+                code: b'M',
+                value: "failure".to_owned(),
+            },
+            PostgresErrorField {
+                code: b'p',
+                value: "12".to_owned(),
+            },
+            PostgresErrorField {
+                code: b'q',
+                value: "SELECT broken".to_owned(),
+            },
+            PostgresErrorField {
+                code: b'F',
+                value: "parse_expr.c".to_owned(),
+            },
+            PostgresErrorField {
+                code: b'L',
+                value: "123".to_owned(),
+            },
+            PostgresErrorField {
+                code: b'R',
+                value: "transformExpr".to_owned(),
+            },
+        ];
+        let diagnostic_fields = fields
+            .into_iter()
+            .map(|field| core::DiagnosticField {
+                code: field.code,
+                value: field.value,
+            })
+            .collect();
+        let error = PostgresError::from_core(core::diagnostic(
+            diagnostic_fields,
+            "PostgreSQL ErrorResponse",
+        ));
+        assert_eq!(error.severity.as_deref(), Some("ERREUR"));
+        assert_eq!(error.localized_severity.as_deref(), Some("ERREUR"));
+        assert_eq!(error.nonlocalized_severity.as_deref(), Some("ERROR"));
+        assert_eq!(error.internal_position.as_deref(), Some("12"));
+        assert_eq!(error.internal_query.as_deref(), Some("SELECT broken"));
+        assert_eq!(error.file.as_deref(), Some("parse_expr.c"));
+        assert_eq!(error.line.as_deref(), Some("123"));
+        assert_eq!(error.routine.as_deref(), Some("transformExpr"));
+    }
+
+    #[test]
+    fn stable_accessors_preserve_typed_failures() {
+        let postgres = PostgresError::from_core(core::diagnostic(
+            vec![core::DiagnosticField {
+                code: b'C',
+                value: "23505".to_owned(),
+            }],
+            "duplicate key",
+        ));
+        let postgres = Error::Postgres(Box::new(postgres));
+        assert_eq!(
+            postgres
+                .postgres_error()
+                .and_then(|error| error.sqlstate.as_deref()),
+            Some("23505")
+        );
+        assert!(postgres.transaction_rollback_errors().is_none());
+
+        let rollback = Error::transaction_rollback(
+            Error::Engine("callback".to_owned()),
+            Error::Engine("rollback".to_owned()),
+        );
+        let (callback, rollback_error) = rollback
+            .transaction_rollback_errors()
+            .expect("composite error remains typed");
+        assert_eq!(callback.to_string(), "callback");
+        assert_eq!(rollback_error.to_string(), "rollback");
+        assert!(rollback.postgres_error().is_none());
+
+        let transaction = TransactionError::CallbackAndDatabase {
+            callback: Error::Engine("callback".to_owned()),
+            database: Error::Engine("stream recovery".to_owned()),
+        };
+        assert!(transaction.rollback_error().is_none());
+        assert_eq!(
+            transaction
+                .database_error()
+                .map(ToString::to_string)
+                .as_deref(),
+            Some("stream recovery")
+        );
+        let flattened: Error = transaction.into();
+        let (callback, database) = flattened
+            .transaction_callback_database_errors()
+            .expect("callback and independent database failure remain typed");
+        assert_eq!(callback.to_string(), "callback");
+        assert_eq!(database.to_string(), "stream recovery");
+
+        let panic = RawStreamError::::CallbackPanicked(Error::Engine(
+            "callback panicked".to_owned(),
+        ));
+        assert!(panic.database_error().is_none());
+        assert_eq!(
+            panic
+                .callback_panic_error()
+                .map(ToString::to_string)
+                .as_deref(),
+            Some("callback panicked")
+        );
+    }
+}
diff --git a/src/sdks/rust/sdk/src/executor.rs b/src/sdks/rust/sdk/src/executor.rs
new file mode 100644
index 000000000..2f6b8b3cd
--- /dev/null
+++ b/src/sdks/rust/sdk/src/executor.rs
@@ -0,0 +1,3097 @@
+use std::any::Any;
+use std::collections::VecDeque;
+use std::future::poll_fn;
+use std::panic::{AssertUnwindSafe, catch_unwind};
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::{Arc, Condvar, Mutex, OnceLock};
+use std::task::{Context, Poll, Waker};
+use std::thread;
+
+use crate::cancellation::CancellationGate;
+use crate::engine::{EngineSession, ProtocolStreamOutcome};
+use crate::error::{Error, Result, SESSION_STATE_UNKNOWN};
+use crate::protocol::{ProtocolRequest, ProtocolResponse};
+use crate::query::{ReadyStatus, parse_simple_command_response};
+use crate::reply;
+use crate::session::{
+    TransactionGuard, begin_transaction, execute_structured_operation,
+    execute_transaction_structured_operation, inactive_transaction_error,
+};
+
+type ProtocolChunkCallback = Box Result<()> + Send>;
+
+pub(crate) enum ExecutorStreamOutcome {
+    ReadyForQuery(Result<()>),
+    CallbackPanicked(Error),
+    SessionStateUnknown(Error),
+}
+
+impl ExecutorStreamOutcome {
+    #[cfg(test)]
+    fn into_result(self) -> Result<()> {
+        match self {
+            Self::ReadyForQuery(result) => result,
+            Self::CallbackPanicked(error) | Self::SessionStateUnknown(error) => Err(error),
+        }
+    }
+}
+
+/// Ordinary application work is bounded. Lifecycle and transaction-recovery
+/// commands share the same FIFO but do not consume this capacity, so cleanup
+/// can always be admitted without inventing a public queue-tuning surface.
+const ORDINARY_QUEUE_CAPACITY: usize = 256;
+
+pub(crate) struct EngineExecutor {
+    shared: Arc,
+}
+
+#[cfg(feature = "mobile-bindings")]
+pub(crate) struct RequestCancellation {
+    phase: Mutex,
+    cancelled: AtomicBool,
+    started: AtomicBool,
+    gate: Arc,
+}
+
+#[cfg(feature = "mobile-bindings")]
+enum RequestPhase {
+    Queued,
+    Active,
+    Finished,
+}
+
+#[cfg(feature = "mobile-bindings")]
+impl RequestCancellation {
+    pub(crate) fn was_submitted(&self) -> bool {
+        !matches!(
+            *self.phase.lock().unwrap_or_else(|error| error.into_inner()),
+            RequestPhase::Queued
+        )
+    }
+    pub(crate) fn was_cancelled(&self) -> bool {
+        self.cancelled.load(Ordering::Acquire)
+    }
+    pub(crate) fn cancel(self: &Arc) -> Result<()> {
+        if self.cancelled.swap(true, Ordering::AcqRel) {
+            return Ok(());
+        }
+        if !matches!(
+            *self.phase.lock().unwrap_or_else(|error| error.into_inner()),
+            RequestPhase::Active
+        ) {
+            return Ok(());
+        }
+        let request = Arc::clone(self);
+        thread::Builder::new()
+            .name("oliphaunt-request-cancel".into())
+            .spawn(move || {
+                // Keep this request active until its cancellation call returns;
+                // the owner cannot advance and accidentally cancel later SQL.
+                loop {
+                    let phase = request
+                        .phase
+                        .lock()
+                        .unwrap_or_else(|error| error.into_inner());
+                    if !matches!(*phase, RequestPhase::Active) {
+                        break;
+                    }
+                    if let Ok(admission) = request.gate.admit() {
+                        let _ = admission.cancel();
+                    }
+                    drop(phase);
+                    // A cancellation racing the native call entry may arrive
+                    // before PostgreSQL becomes busy. Retry only this request.
+                    thread::sleep(std::time::Duration::from_millis(1));
+                }
+            })
+            .map_err(|error| Error::Engine(format!("could not request cancellation: {error}")))?;
+        Ok(())
+    }
+}
+
+#[cfg(feature = "mobile-bindings")]
+struct ActiveRequest(Arc);
+#[cfg(feature = "mobile-bindings")]
+impl Drop for ActiveRequest {
+    fn drop(&mut self) {
+        *self
+            .0
+            .phase
+            .lock()
+            .unwrap_or_else(|error| error.into_inner()) = RequestPhase::Finished;
+    }
+}
+
+#[cfg(feature = "mobile-bindings")]
+struct RequestFuture(Option>);
+#[cfg(feature = "mobile-bindings")]
+impl Drop for RequestFuture {
+    fn drop(&mut self) {
+        if let Some(request) = self.0.take() {
+            let _ = request.cancel();
+        }
+    }
+}
+
+struct ExecutorShared {
+    queue: CommandQueue,
+    // SQL admission and the owner-side transition into teardown share this
+    // lock. Out-of-band cancellation has its own counted lifecycle gate.
+    admission: Mutex<()>,
+    cancellation: Arc,
+    active_work: AtomicBool,
+    session_pinned: AtomicBool,
+    transaction_poisoned: AtomicBool,
+    // This is an admission cutoff, not an owner-side execution predicate.
+    // Commands already ahead of `Command::Close` must run even while it is set.
+    closing: AtomicBool,
+    teardown_started: AtomicBool,
+    closed: AtomicBool,
+    terminal_drop: AtomicBool,
+    close_state: Mutex,
+    owner_thread: OnceLock,
+}
+
+impl ExecutorShared {
+    fn new() -> Self {
+        Self {
+            queue: CommandQueue::new(),
+            admission: Mutex::new(()),
+            cancellation: CancellationGate::pending(),
+            active_work: AtomicBool::new(false),
+            session_pinned: AtomicBool::new(false),
+            transaction_poisoned: AtomicBool::new(false),
+            closing: AtomicBool::new(false),
+            teardown_started: AtomicBool::new(false),
+            closed: AtomicBool::new(false),
+            terminal_drop: AtomicBool::new(false),
+            close_state: Mutex::new(CloseState::default()),
+            owner_thread: OnceLock::new(),
+        }
+    }
+}
+
+#[derive(Default)]
+struct CloseState {
+    in_progress: bool,
+    terminal_result: Option>,
+    waiters: Vec>,
+}
+
+struct CommandQueue {
+    state: Mutex,
+    ready: Condvar,
+}
+
+struct CommandQueueState {
+    commands: VecDeque,
+    ordinary_count: usize,
+    admission_waiters: VecDeque,
+    stopped: bool,
+}
+
+struct AdmissionWaiter {
+    token: Arc,
+    waker: Waker,
+}
+
+struct AdmissionToken {
+    rejected: AtomicBool,
+}
+
+struct AdmissionRegistration<'queue> {
+    queue: &'queue CommandQueue,
+    // The uncontended path does not allocate. A stable token is created only
+    // if this operation actually has to join the capacity-waiter FIFO.
+    token: Option>,
+}
+
+impl<'queue> AdmissionRegistration<'queue> {
+    fn new(queue: &'queue CommandQueue) -> Self {
+        Self { queue, token: None }
+    }
+}
+
+impl Drop for AdmissionRegistration<'_> {
+    fn drop(&mut self) {
+        if let Some(token) = &self.token {
+            self.queue.cancel_admission(token);
+        }
+    }
+}
+
+impl CommandQueue {
+    fn new() -> Self {
+        Self {
+            state: Mutex::new(CommandQueueState {
+                commands: VecDeque::new(),
+                ordinary_count: 0,
+                admission_waiters: VecDeque::new(),
+                stopped: false,
+            }),
+            ready: Condvar::new(),
+        }
+    }
+
+    fn send_control(&self, command: Command) -> Result<()> {
+        debug_assert!(!command.is_ordinary());
+        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
+        if state.stopped {
+            return Err(Error::EngineStopped);
+        }
+        state.commands.push_back(command);
+        self.ready.notify_one();
+        Ok(())
+    }
+
+    fn poll_send_ordinary(
+        &self,
+        token: &mut Option>,
+        command: &mut Option,
+        cx: &mut Context<'_>,
+    ) -> (Poll>, Option) {
+        debug_assert!(command.as_ref().is_some_and(Command::is_ordinary));
+        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
+        if state.stopped
+            || token
+                .as_ref()
+                .is_some_and(|token| token.rejected.load(Ordering::SeqCst))
+        {
+            return (Poll::Ready(Err(Error::EngineStopped)), None);
+        }
+
+        let position = token.as_ref().and_then(|token| {
+            state
+                .admission_waiters
+                .iter()
+                .position(|waiter| Arc::ptr_eq(&waiter.token, token))
+        });
+        let is_next = match position {
+            Some(0) => true,
+            Some(_) => false,
+            None => state.admission_waiters.is_empty(),
+        };
+        if state.ordinary_count < ORDINARY_QUEUE_CAPACITY && is_next {
+            if position.is_some() {
+                state.admission_waiters.pop_front();
+            }
+            state.ordinary_count += 1;
+            state
+                .commands
+                .push_back(command.take().expect("ordinary command is admitted once"));
+            let next = (state.ordinary_count < ORDINARY_QUEUE_CAPACITY)
+                .then(|| {
+                    state
+                        .admission_waiters
+                        .front()
+                        .map(|waiter| waiter.waker.clone())
+                })
+                .flatten();
+            self.ready.notify_one();
+            return (Poll::Ready(Ok(())), next);
+        }
+
+        let token = token.get_or_insert_with(|| {
+            Arc::new(AdmissionToken {
+                rejected: AtomicBool::new(false),
+            })
+        });
+        match position {
+            Some(position) => {
+                let waiter = &mut state.admission_waiters[position];
+                if !waiter.waker.will_wake(cx.waker()) {
+                    waiter.waker = cx.waker().clone();
+                }
+            }
+            None => state.admission_waiters.push_back(AdmissionWaiter {
+                token: Arc::clone(token),
+                waker: cx.waker().clone(),
+            }),
+        }
+        (Poll::Pending, None)
+    }
+
+    fn cancel_admission(&self, token: &Arc) {
+        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
+        let Some(position) = state
+            .admission_waiters
+            .iter()
+            .position(|waiter| Arc::ptr_eq(&waiter.token, token))
+        else {
+            return;
+        };
+        let was_next = position == 0;
+        state.admission_waiters.remove(position);
+        let next = (was_next && state.ordinary_count < ORDINARY_QUEUE_CAPACITY)
+            .then(|| {
+                state
+                    .admission_waiters
+                    .front()
+                    .map(|waiter| waiter.waker.clone())
+            })
+            .flatten();
+        drop(state);
+        if let Some(waker) = next {
+            waker.wake();
+        }
+    }
+
+    fn reject_admissions(&self) -> Vec {
+        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
+        state
+            .admission_waiters
+            .drain(..)
+            .map(|waiter| {
+                waiter.token.rejected.store(true, Ordering::SeqCst);
+                waiter.waker
+            })
+            .collect()
+    }
+
+    fn receive(&self) -> Option {
+        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
+        loop {
+            if let Some(command) = state.commands.pop_front() {
+                if command.is_ordinary() {
+                    state.ordinary_count -= 1;
+                }
+                let next = state
+                    .admission_waiters
+                    .front()
+                    .map(|waiter| waiter.waker.clone());
+                drop(state);
+                if let Some(waker) = next {
+                    waker.wake();
+                }
+                return Some(command);
+            }
+            if state.stopped {
+                return None;
+            }
+            state = self
+                .ready
+                .wait(state)
+                .unwrap_or_else(|error| error.into_inner());
+        }
+    }
+
+    fn stop(&self) -> Vec {
+        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
+        state.stopped = true;
+        state.ordinary_count = 0;
+        let pending = state.commands.drain(..).collect();
+        let wakers = state
+            .admission_waiters
+            .drain(..)
+            .map(|waiter| {
+                waiter.token.rejected.store(true, Ordering::SeqCst);
+                waiter.waker
+            })
+            .collect::>();
+        self.ready.notify_all();
+        drop(state);
+        for waker in wakers {
+            waker.wake();
+        }
+        pending
+    }
+}
+
+impl EngineExecutor {
+    #[cfg(feature = "mobile-bindings")]
+    pub(crate) fn request_cancellation(&self) -> Arc {
+        Arc::new(RequestCancellation {
+            phase: Mutex::new(RequestPhase::Queued),
+            cancelled: AtomicBool::new(false),
+            started: AtomicBool::new(false),
+            gate: Arc::clone(&self.shared.cancellation),
+        })
+    }
+
+    #[cfg(feature = "mobile-bindings")]
+    pub(crate) async fn exec_cancellable(
+        &self,
+        request: ProtocolRequest,
+        cancellation: Arc,
+    ) -> Result {
+        let (reply, receiver) = reply::channel();
+        self.run_cancellable(Command::Exec { request, reply }, receiver, cancellation)
+            .await
+    }
+
+    #[cfg(feature = "mobile-bindings")]
+    pub(crate) async fn stream_cancellable(
+        &self,
+        request: ProtocolRequest,
+        on_chunk: F,
+        cancellation: Arc,
+    ) -> Result
+    where
+        F: FnMut(&[u8]) -> Result<()> + Send + 'static,
+    {
+        let (reply, receiver) = reply::channel();
+        self.run_cancellable(
+            Command::Stream {
+                request,
+                on_chunk: Box::new(on_chunk),
+                reply,
+            },
+            receiver,
+            cancellation,
+        )
+        .await
+    }
+
+    #[cfg(feature = "mobile-bindings")]
+    async fn run_cancellable(
+        &self,
+        command: Command,
+        receiver: reply::Receiver,
+        cancellation: Arc,
+    ) -> Result {
+        if cancellation.started.swap(true, Ordering::AcqRel) {
+            return Err(Error::InvalidConfig(
+                "a native request can only execute once".into(),
+            ));
+        }
+        let mut future = RequestFuture(Some(Arc::clone(&cancellation)));
+        self.send(Command::Cancellable {
+            command: Box::new(command),
+            cancellation,
+        })
+        .await?;
+        let result = receiver.await;
+        future.0 = None;
+        result
+    }
+    /// Construct a runtime session on the thread which permanently owns it.
+    pub(crate) async fn open(
+        thread_name: &'static str,
+        operation: F,
+    ) -> Result<(Arc, M)>
+    where
+        M: Send + 'static,
+        F: FnOnce() -> Result<(Box, M)> + Send + 'static,
+    {
+        let (executor, opened) = Self::start_owner(thread_name, operation)?;
+        let metadata = opened.await?;
+        Ok((executor, metadata))
+    }
+
+    fn start_owner(
+        thread_name: &'static str,
+        operation: F,
+    ) -> Result<(Arc, reply::Receiver)>
+    where
+        M: Send + 'static,
+        F: FnOnce() -> Result<(Box, M)> + Send + 'static,
+    {
+        let shared = Arc::new(ExecutorShared::new());
+        let executor = Arc::new(Self {
+            shared: Arc::clone(&shared),
+        });
+        let (opened, receiver) = reply::channel();
+        thread::Builder::new()
+            .name(thread_name.to_owned())
+            .spawn(move || owner_thread(shared, opened, operation, thread_name))
+            .map_err(|error| Error::Engine(format!("failed to start {thread_name}: {error}")))?;
+        Ok((executor, receiver))
+    }
+
+    #[cfg(test)]
+    pub(crate) fn spawn(session: Box) -> Arc {
+        use std::future::Future;
+        use std::task::{Context, Poll, Wake, Waker};
+
+        struct ThreadWake(thread::Thread);
+
+        impl Wake for ThreadWake {
+            fn wake(self: Arc) {
+                self.0.unpark();
+            }
+        }
+
+        let (executor, opened) =
+            Self::start_owner("oliphaunt-test-owner", move || Ok((session, ())))
+                .expect("spawn test owner thread");
+        let mut opened = std::pin::pin!(opened);
+        let waker = Waker::from(Arc::new(ThreadWake(thread::current())));
+        let mut context = Context::from_waker(&waker);
+        loop {
+            match opened.as_mut().poll(&mut context) {
+                Poll::Ready(result) => {
+                    result.expect("test owner opens");
+                    break;
+                }
+                Poll::Pending => thread::park(),
+            }
+        }
+        executor
+    }
+
+    pub(crate) async fn cancel(&self) -> Result<()> {
+        // `closing` is only an ordinary-work cutoff. Cancellation is
+        // out-of-band and remains useful while already-admitted SQL drains.
+        // The counted cancellation gate orders this request exactly before or
+        // after destructive teardown and lets close wait for admitted calls.
+        let cancellation = self.shared.cancellation.admit()?;
+        run_off_thread("oliphaunt-cancel", move || cancellation.cancel()).await
+    }
+
+    pub(crate) async fn exec_protocol_raw(
+        &self,
+        request: ProtocolRequest,
+    ) -> Result {
+        let (reply, receiver) = reply::channel();
+        self.send(Command::Exec { request, reply }).await?;
+        receiver.await
+    }
+
+    pub(crate) async fn exec_structured(
+        &self,
+        request: ProtocolRequest,
+        operation: impl Into,
+    ) -> Result {
+        let (reply, receiver) = reply::channel();
+        self.send(Command::StructuredExec {
+            request,
+            operation: operation.into(),
+            reply,
+        })
+        .await?;
+        receiver.await
+    }
+
+    pub(crate) async fn pinned_exec_protocol_control(
+        &self,
+        token: u64,
+        request: ProtocolRequest,
+        guard: Arc,
+    ) -> Result {
+        let (reply, receiver) = reply::channel();
+        let command = Command::PinnedExec {
+            token,
+            request,
+            guard,
+            reply,
+        };
+        self.send_transaction_settlement(command)?;
+        receiver.await
+    }
+
+    pub(crate) async fn pinned_exec_structured(
+        &self,
+        token: u64,
+        request: ProtocolRequest,
+        operation: impl Into,
+        guard: Arc,
+    ) -> Result {
+        let (reply, receiver) = reply::channel();
+        self.send(Command::PinnedStructuredExec {
+            token,
+            request,
+            operation: operation.into(),
+            guard,
+            reply,
+        })
+        .await?;
+        receiver.await
+    }
+
+    #[cfg(test)]
+    pub(crate) async fn exec_protocol_raw_stream(
+        &self,
+        request: ProtocolRequest,
+        on_chunk: F,
+    ) -> Result<()>
+    where
+        F: FnMut(&[u8]) -> Result<()> + Send + 'static,
+    {
+        self.exec_protocol_raw_stream_outcome(request, on_chunk)
+            .await?
+            .into_result()
+    }
+
+    pub(crate) async fn exec_protocol_raw_stream_outcome(
+        &self,
+        request: ProtocolRequest,
+        on_chunk: F,
+    ) -> Result
+    where
+        F: FnMut(&[u8]) -> Result<()> + Send + 'static,
+    {
+        let (reply, receiver) = reply::channel();
+        self.send(Command::Stream {
+            request,
+            on_chunk: Box::new(on_chunk),
+            reply,
+        })
+        .await?;
+        receiver.await
+    }
+
+    pub(crate) async fn begin_transaction(&self) -> Result {
+        let (reply, receiver) = reply::channel();
+        self.send(Command::Begin { reply }).await?;
+        receiver.await
+    }
+
+    pub(crate) async fn release_pin(&self, token: u64) -> Result<()> {
+        let (reply, receiver) = reply::channel();
+        self.send_cleanup(Command::ReleasePin {
+            token,
+            reply: Some(reply),
+        })?;
+        receiver.await
+    }
+
+    pub(crate) fn release_pin_best_effort(&self, token: u64) {
+        let _ = self.send_cleanup(Command::ReleasePin { token, reply: None });
+    }
+
+    pub(crate) fn rollback_and_release_pin_best_effort(&self, token: u64) {
+        let _ = self.send_cleanup(Command::RollbackAndReleasePin { token });
+    }
+
+    pub(crate) fn poison_transaction_state(&self) {
+        self.shared
+            .transaction_poisoned
+            .store(true, Ordering::SeqCst);
+    }
+
+    pub(crate) fn is_closed(&self) -> bool {
+        self.shared.closed.load(Ordering::SeqCst)
+    }
+
+    #[cfg(test)]
+    pub(crate) fn session_is_pinned(&self) -> bool {
+        self.shared.session_pinned.load(Ordering::SeqCst)
+    }
+
+    pub(crate) async fn backup(&self) -> Result> {
+        let (reply, receiver) = reply::channel();
+        self.send(Command::Backup { reply }).await?;
+        receiver.await
+    }
+
+    pub(crate) async fn close(&self) -> Result<()> {
+        self.ensure_not_owner_thread()?;
+        let (reply, receiver) = reply::channel();
+        let mut rejected_admissions = Vec::new();
+        {
+            // Setting the cutoff and appending Close happen under the same
+            // admission lock used by every command submission. Commands that
+            // acquired admission first are ahead of Close and drain; commands
+            // that acquire it later observe `closing` and are rejected.
+            let _admission = self.shared.admission.lock().map_err(|_| {
+                Error::Engine("database command admission lock was poisoned".to_owned())
+            })?;
+            let mut close = self
+                .shared
+                .close_state
+                .lock()
+                .unwrap_or_else(|error| error.into_inner());
+            if let Some(result) = &close.terminal_result {
+                return result.clone();
+            }
+            if close.in_progress {
+                close.waiters.push(reply);
+            } else {
+                close.in_progress = true;
+                close.waiters.push(reply);
+                self.shared.closing.store(true, Ordering::SeqCst);
+                // Mark every already-registered capacity waiter while the
+                // admission cutoff is held. Waking is deferred until after the
+                // lock is released so even a synchronous waker cannot deadlock.
+                rejected_admissions = self.shared.queue.reject_admissions();
+                if let Err(error) = self.shared.queue.send_control(Command::Close) {
+                    drop(close);
+                    complete_terminal_close(&self.shared, Err(error));
+                }
+            }
+        }
+        for waker in rejected_admissions {
+            waker.wake();
+        }
+        receiver.await
+    }
+
+    async fn send(&self, command: Command) -> Result<()> {
+        debug_assert!(command.is_ordinary());
+        let mut registration = AdmissionRegistration::new(&self.shared.queue);
+        let mut command = Some(command);
+        poll_fn(|cx| {
+            if let Err(error) = self.ensure_not_owner_thread() {
+                return Poll::Ready(Err(error));
+            }
+            let (poll, next) = {
+                let _admission = match self.shared.admission.lock() {
+                    Ok(admission) => admission,
+                    Err(_) => {
+                        return Poll::Ready(Err(Error::Engine(
+                            "database command admission lock was poisoned".to_owned(),
+                        )));
+                    }
+                };
+                if self.shared.closed.load(Ordering::SeqCst)
+                    || self.shared.closing.load(Ordering::SeqCst)
+                {
+                    return Poll::Ready(Err(Error::EngineStopped));
+                }
+                if self.shared.transaction_poisoned.load(Ordering::SeqCst) {
+                    return Poll::Ready(Err(Error::Engine(SESSION_STATE_UNKNOWN.to_owned())));
+                }
+                self.shared
+                    .queue
+                    .poll_send_ordinary(&mut registration.token, &mut command, cx)
+            };
+            if let Some(waker) = next {
+                waker.wake();
+            }
+            poll
+        })
+        .await
+    }
+
+    /// COMMIT and ROLLBACK are required settlement for an existing pin, not
+    /// new application work. A transaction whose BEGIN was admitted before a
+    /// close cutoff must still be able to enqueue that settlement behind the
+    /// cutoff. The owner validates the pin token when the command reaches it.
+    fn send_transaction_settlement(&self, command: Command) -> Result<()> {
+        self.ensure_not_owner_thread()?;
+        let _admission = self.shared.admission.lock().map_err(|_| {
+            Error::Engine("database command admission lock was poisoned".to_owned())
+        })?;
+        if self.shared.closed.load(Ordering::SeqCst)
+            || self.shared.teardown_started.load(Ordering::SeqCst)
+        {
+            return Err(Error::EngineStopped);
+        }
+        self.shared.queue.send_control(command)
+    }
+
+    /// Cleanup stays admissible after poisoning or a close cutoff and does not
+    /// consume ordinary queue capacity. It retains FIFO order with
+    /// already-admitted SQL and Close; the owner decides whether Close can
+    /// proceed before later transaction cleanup.
+    fn send_cleanup(&self, command: Command) -> Result<()> {
+        let _admission = self.shared.admission.lock().map_err(|_| {
+            Error::Engine("database command admission lock was poisoned".to_owned())
+        })?;
+        if self.shared.closed.load(Ordering::SeqCst)
+            || self.shared.teardown_started.load(Ordering::SeqCst)
+        {
+            return Err(Error::EngineStopped);
+        }
+        self.shared.queue.send_control(command)
+    }
+
+    fn ensure_not_owner_thread(&self) -> Result<()> {
+        if self
+            .shared
+            .owner_thread
+            .get()
+            .is_some_and(|owner| *owner == thread::current().id())
+        {
+            return Err(Error::Engine(
+                "reentrant database work from a raw-stream callback is not supported".to_owned(),
+            ));
+        }
+        Ok(())
+    }
+}
+
+impl Drop for EngineExecutor {
+    fn drop(&mut self) {
+        if self.shared.closed.load(Ordering::SeqCst) {
+            return;
+        }
+        // Dropping JoinHandle detaches in Rust; this executor intentionally
+        // owns no handle to join. Final drop only establishes a terminal close
+        // request and returns immediately.
+        self.shared.terminal_drop.store(true, Ordering::SeqCst);
+        schedule_terminal_drop_close(&self.shared);
+    }
+}
+
+enum Command {
+    #[cfg(feature = "mobile-bindings")]
+    Cancellable {
+        command: Box,
+        cancellation: Arc,
+    },
+    Exec {
+        request: ProtocolRequest,
+        reply: reply::Sender,
+    },
+    StructuredExec {
+        request: ProtocolRequest,
+        operation: String,
+        reply: reply::Sender,
+    },
+    PinnedExec {
+        token: u64,
+        request: ProtocolRequest,
+        guard: Arc,
+        reply: reply::Sender,
+    },
+    PinnedStructuredExec {
+        token: u64,
+        request: ProtocolRequest,
+        operation: String,
+        guard: Arc,
+        reply: reply::Sender,
+    },
+    Stream {
+        request: ProtocolRequest,
+        on_chunk: ProtocolChunkCallback,
+        reply: reply::Sender,
+    },
+    Begin {
+        reply: reply::Sender,
+    },
+    ReleasePin {
+        token: u64,
+        reply: Option>,
+    },
+    RollbackAndReleasePin {
+        token: u64,
+    },
+    Backup {
+        reply: reply::Sender>,
+    },
+    Close,
+}
+
+impl Command {
+    fn is_ordinary(&self) -> bool {
+        !matches!(
+            self,
+            Self::PinnedExec { .. }
+                | Self::ReleasePin { .. }
+                | Self::RollbackAndReleasePin { .. }
+                | Self::Close
+        )
+    }
+
+    fn is_abandoned(&self) -> bool {
+        match self {
+            #[cfg(feature = "mobile-bindings")]
+            Self::Cancellable {
+                command,
+                cancellation,
+            } => cancellation.cancelled.load(Ordering::Acquire) || command.is_abandoned(),
+            Self::Exec { reply, .. }
+            | Self::StructuredExec { reply, .. }
+            | Self::PinnedStructuredExec { reply, .. } => reply.is_abandoned(),
+            Self::Stream { reply, .. } => reply.is_abandoned(),
+            Self::Begin { reply } => reply.is_abandoned(),
+            Self::Backup { reply } => reply.is_abandoned(),
+            Self::PinnedExec { .. }
+            | Self::ReleasePin { .. }
+            | Self::RollbackAndReleasePin { .. }
+            | Self::Close => false,
+        }
+    }
+}
+
+struct OwnerState {
+    active_pin: Option,
+    next_pin: u64,
+}
+
+enum OwnerAction {
+    Continue,
+    RetryableClose(Error),
+    TerminalClose(Result<()>),
+}
+
+fn owner_thread(
+    shared: Arc,
+    opened: reply::Sender,
+    operation: F,
+    thread_name: &'static str,
+) where
+    M: Send + 'static,
+    F: FnOnce() -> Result<(Box, M)>,
+{
+    let _ = shared.owner_thread.set(thread::current().id());
+    let opened_session = catch_unwind(AssertUnwindSafe(operation)).unwrap_or_else(|panic| {
+        Err(Error::Engine(format!(
+            "{thread_name} panicked while opening: {}",
+            panic_message(panic.as_ref())
+        )))
+    });
+    let (session, metadata) = match opened_session {
+        Ok(opened_session) => opened_session,
+        Err(error) => {
+            opened.send(Err(error));
+            stop_owner(&shared);
+            return;
+        }
+    };
+    let cancel = match catch_unwind(AssertUnwindSafe(|| session.cancel_handle())) {
+        Ok(cancel) => cancel,
+        Err(panic) => {
+            opened.send(Err(Error::Engine(format!(
+                "{thread_name} panicked while obtaining its cancellation handle: {}",
+                panic_message(panic.as_ref())
+            ))));
+            dispose_session_after_owner_failure(session);
+            stop_owner(&shared);
+            return;
+        }
+    };
+    if let Err(error) = shared.cancellation.install_target(cancel) {
+        opened.send(Err(error));
+        dispose_session_after_owner_failure(session);
+        stop_owner(&shared);
+        return;
+    }
+    let mut session = Some(session);
+    if !opened.send(Ok(metadata)) {
+        dispose_session_after_owner_failure(session.take().expect("opened session"));
+        stop_owner(&shared);
+        return;
+    }
+
+    let mut owner = OwnerState {
+        active_pin: None,
+        next_pin: 1,
+    };
+    while let Some(command) = shared.queue.receive() {
+        if command.is_abandoned() {
+            continue;
+        }
+        let action = catch_unwind(AssertUnwindSafe(|| {
+            execute_command(
+                session.as_mut().expect("owner session exists").as_mut(),
+                &shared,
+                &mut owner,
+                command,
+            )
+        }));
+        match action {
+            Ok(OwnerAction::Continue) => {}
+            Ok(OwnerAction::RetryableClose(error)) => {
+                complete_retryable_close(&shared, error);
+                // Final EngineExecutor drop may race with validation after the
+                // owner has already observed `terminal_drop == false`. Recheck
+                // after reopening the attempt so the last handle cannot leave
+                // an owner thread and transaction pin stranded.
+                schedule_terminal_drop_close(&shared);
+            }
+            Ok(OwnerAction::TerminalClose(result)) => {
+                shared.session_pinned.store(false, Ordering::SeqCst);
+                let result = match result {
+                    Ok(()) => {
+                        // Drop the session and its root lock before resolving
+                        // close. A destructor panic is still one terminal close
+                        // outcome and must not strand or reopen the handle.
+                        match catch_unwind(AssertUnwindSafe(|| drop(session.take()))) {
+                            Ok(()) => Ok(()),
+                            Err(panic) => Err(Error::Engine(format!(
+                                "native engine session destructor panicked after close: {}",
+                                panic_message(panic.as_ref())
+                            ))),
+                        }
+                    }
+                    Err(error) => {
+                        // Teardown has already started, so the session cannot
+                        // safely return to service. Retain any native ownership
+                        // that its failed close may still hold through process
+                        // exit instead of running a second implicit teardown.
+                        std::mem::forget(session.take().expect("owner session exists"));
+                        Err(error)
+                    }
+                };
+                let pending = shared.queue.stop();
+                drop(pending);
+                complete_terminal_close(&shared, result);
+                return;
+            }
+            Err(_) => {
+                shared.cancellation.stop_and_wait();
+                dispose_session_after_owner_failure(session.take().expect("owner session exists"));
+                stop_owner(&shared);
+                return;
+            }
+        }
+    }
+    if let Some(session) = session.take() {
+        shared.cancellation.stop_and_wait();
+        dispose_session_after_owner_failure(session);
+    }
+    stop_owner(&shared);
+}
+
+fn execute_command(
+    session: &mut dyn EngineSession,
+    shared: &ExecutorShared,
+    owner: &mut OwnerState,
+    command: Command,
+) -> OwnerAction {
+    match command {
+        #[cfg(feature = "mobile-bindings")]
+        Command::Cancellable {
+            command,
+            cancellation,
+        } => {
+            let mut phase = cancellation
+                .phase
+                .lock()
+                .unwrap_or_else(|error| error.into_inner());
+            if cancellation.cancelled.load(Ordering::Acquire) {
+                *phase = RequestPhase::Finished;
+                return OwnerAction::Continue;
+            }
+            *phase = RequestPhase::Active;
+            drop(phase);
+            let _active = ActiveRequest(cancellation);
+            return execute_command(session, shared, owner, *command);
+        }
+        Command::Exec { request, reply } => {
+            let result = if owner.active_pin.is_some() {
+                Err(Error::TransactionActive)
+            } else {
+                run_active_work(&shared.active_work, || {
+                    execute_raw_operation(session, request, &shared.transaction_poisoned, None)
+                })
+            };
+            reply.send(result);
+        }
+        Command::StructuredExec {
+            request,
+            operation,
+            reply,
+        } => {
+            let result = if owner.active_pin.is_some() {
+                Err(Error::TransactionActive)
+            } else {
+                run_active_work(&shared.active_work, || {
+                    execute_structured_operation(
+                        session,
+                        &shared.transaction_poisoned,
+                        request,
+                        &operation,
+                    )
+                })
+            };
+            reply.send(result);
+        }
+        Command::PinnedExec {
+            token,
+            request,
+            guard,
+            reply,
+        } => {
+            let result = if owner.active_pin != Some(token) {
+                Err(inactive_transaction_error())
+            } else if shared.transaction_poisoned.load(Ordering::SeqCst) {
+                Err(transaction_terminal_error(&guard)
+                    .unwrap_or_else(|| Error::Engine(SESSION_STATE_UNKNOWN.to_owned())))
+            } else {
+                run_active_work(&shared.active_work, || {
+                    execute_raw_operation(session, request, &shared.transaction_poisoned, None)
+                })
+            };
+            reply.send(result);
+        }
+        Command::PinnedStructuredExec {
+            token,
+            request,
+            operation,
+            guard,
+            reply,
+        } => {
+            let result = if owner.active_pin == Some(token) {
+                run_active_work(&shared.active_work, || {
+                    execute_transaction_structured_operation(
+                        session,
+                        &shared.transaction_poisoned,
+                        &guard,
+                        request,
+                        &operation,
+                    )
+                })
+            } else {
+                Err(inactive_transaction_error())
+            };
+            reply.send(result);
+        }
+        Command::Stream {
+            request,
+            on_chunk,
+            reply,
+        } => {
+            let result = if owner.active_pin.is_some() {
+                Err(Error::TransactionActive)
+            } else {
+                Ok(run_active_work(&shared.active_work, || {
+                    execute_stream(session, request, on_chunk, &shared.transaction_poisoned)
+                }))
+            };
+            reply.send(result);
+        }
+        Command::Begin { reply } => {
+            if owner.active_pin.is_some() {
+                reply.send(Err(Error::TransactionActive));
+            } else {
+                let result = allocate_pin(owner).and_then(|token| {
+                    begin_transaction(session, &shared.transaction_poisoned).map(|()| token)
+                });
+                match result {
+                    Ok(token) => {
+                        owner.active_pin = Some(token);
+                        shared.session_pinned.store(true, Ordering::SeqCst);
+                        if !reply.send(Ok(token)) {
+                            rollback_active_pin(session, shared, owner, token);
+                        }
+                    }
+                    Err(error) => {
+                        reply.send(Err(error));
+                    }
+                }
+            }
+        }
+        Command::ReleasePin { token, reply } => {
+            let result = if owner.active_pin == Some(token) {
+                owner.active_pin = None;
+                shared.session_pinned.store(false, Ordering::SeqCst);
+                Ok(())
+            } else {
+                Err(inactive_transaction_error())
+            };
+            if let Some(reply) = reply {
+                reply.send(result);
+            }
+        }
+        Command::RollbackAndReleasePin { token } => {
+            rollback_active_pin(session, shared, owner, token);
+        }
+        Command::Backup { reply } => {
+            let result = if owner.active_pin.is_some() {
+                Err(Error::TransactionActive)
+            } else {
+                run_active_work(&shared.active_work, || session.backup())
+            };
+            reply.send(result);
+        }
+        Command::Close => {
+            if let Some(token) = owner.active_pin {
+                if shared.terminal_drop.load(Ordering::SeqCst) {
+                    rollback_active_pin(session, shared, owner, token);
+                } else {
+                    return OwnerAction::RetryableClose(Error::TransactionActive);
+                }
+            }
+            // `closing` has so far rejected only new ordinary work. Establish
+            // the destructive boundary while SQL admission is excluded, then
+            // release every lock and wait for out-of-band cancellations which
+            // crossed their own gate first.
+            let (admission, admission_poisoned) = match shared.admission.lock() {
+                Ok(admission) => (admission, false),
+                Err(error) => (error.into_inner(), true),
+            };
+            let cancellation_target = shared.cancellation.stop_accepting();
+            shared.teardown_started.store(true, Ordering::SeqCst);
+            drop(admission);
+            drop(cancellation_target);
+            shared.cancellation.wait_for_idle();
+            if admission_poisoned {
+                return OwnerAction::TerminalClose(Err(Error::Engine(
+                    "database command admission lock was poisoned".to_owned(),
+                )));
+            }
+            let result = run_active_work(&shared.active_work, || {
+                catch_unwind(AssertUnwindSafe(|| session.close())).unwrap_or_else(|panic| {
+                    Err(Error::Engine(format!(
+                        "native engine session panicked during close: {}",
+                        panic_message(panic.as_ref())
+                    )))
+                })
+            });
+            return OwnerAction::TerminalClose(result);
+        }
+    }
+    OwnerAction::Continue
+}
+
+fn allocate_pin(owner: &mut OwnerState) -> Result {
+    let token = owner.next_pin;
+    owner.next_pin = owner
+        .next_pin
+        .checked_add(1)
+        .ok_or_else(|| Error::Engine("native transaction token space is exhausted".to_owned()))?;
+    Ok(token)
+}
+
+fn rollback_active_pin(
+    session: &mut dyn EngineSession,
+    shared: &ExecutorShared,
+    owner: &mut OwnerState,
+    token: u64,
+) {
+    if owner.active_pin != Some(token) {
+        return;
+    }
+    if shared.transaction_poisoned.load(Ordering::SeqCst) {
+        // The physical transaction boundary is unknown. Releasing the SDK pin
+        // is safe, but sending ROLLBACK could act on a different protocol state
+        // and would falsely imply recovery.
+        owner.active_pin = None;
+        shared.session_pinned.store(false, Ordering::SeqCst);
+        return;
+    }
+    let rollback = run_active_work(&shared.active_work, || {
+        ProtocolRequest::simple_query("ROLLBACK")
+            .and_then(|request| session.exec_protocol_raw(request))
+            .and_then(|response| parse_simple_command_response(&response))
+    });
+    let confirmed = rollback.is_ok_and(|result| {
+        result.command_tag() == Some("ROLLBACK") && result.ready_status() == ReadyStatus::Idle
+    });
+    if !confirmed {
+        shared.transaction_poisoned.store(true, Ordering::SeqCst);
+    }
+    owner.active_pin = None;
+    shared.session_pinned.store(false, Ordering::SeqCst);
+}
+
+fn transaction_terminal_error(guard: &TransactionGuard) -> Option {
+    guard
+        .terminal_error
+        .lock()
+        .ok()
+        .and_then(|error| error.as_ref().cloned())
+}
+
+fn execute_raw_operation(
+    session: &mut dyn EngineSession,
+    request: ProtocolRequest,
+    transaction_poisoned: &AtomicBool,
+    guard: Option<&TransactionGuard>,
+) -> Result {
+    let result = session.exec_protocol_raw(request);
+    if let Err(error) = &result {
+        // Unlike a returned ErrorResponse byte stream, an engine error does
+        // not prove a terminal ReadyForQuery boundary for this raw exchange.
+        transaction_poisoned.store(true, Ordering::SeqCst);
+        if let Some(guard) = guard {
+            guard.fail(error.clone());
+        }
+    }
+    result
+}
+
+fn execute_stream(
+    session: &mut dyn EngineSession,
+    request: ProtocolRequest,
+    mut on_chunk: ProtocolChunkCallback,
+    transaction_poisoned: &AtomicBool,
+) -> ExecutorStreamOutcome {
+    let mut callback_panic = None;
+    let outcome = {
+        let mut guarded = |chunk: &[u8]| {
+            catch_unwind(AssertUnwindSafe(|| on_chunk(chunk))).unwrap_or_else(|panic| {
+                let error = Error::Engine(format!(
+                    "raw protocol stream callback panicked: {}",
+                    panic_message(panic.as_ref())
+                ));
+                callback_panic = Some(error.clone());
+                Err(error)
+            })
+        };
+        session.exec_protocol_raw_stream(request, &mut guarded)
+    };
+    match outcome {
+        ProtocolStreamOutcome::ReadyForQuery(_) if callback_panic.is_some() => {
+            ExecutorStreamOutcome::CallbackPanicked(
+                callback_panic.expect("callback panic was checked"),
+            )
+        }
+        ProtocolStreamOutcome::ReadyForQuery(result) => {
+            ExecutorStreamOutcome::ReadyForQuery(result)
+        }
+        ProtocolStreamOutcome::SessionStateUnknown(error) => {
+            transaction_poisoned.store(true, Ordering::SeqCst);
+            ExecutorStreamOutcome::SessionStateUnknown(error)
+        }
+    }
+}
+
+fn complete_retryable_close(shared: &ExecutorShared, error: Error) {
+    let waiters = {
+        let mut close = shared
+            .close_state
+            .lock()
+            .unwrap_or_else(|error| error.into_inner());
+        close.in_progress = false;
+        shared.closing.store(false, Ordering::SeqCst);
+        std::mem::take(&mut close.waiters)
+    };
+    for waiter in waiters {
+        waiter.send(Err(error.clone()));
+    }
+}
+
+fn complete_terminal_close(shared: &ExecutorShared, result: Result<()>) {
+    let (result, waiters) = {
+        let mut close = shared
+            .close_state
+            .lock()
+            .unwrap_or_else(|error| error.into_inner());
+        let result = close
+            .terminal_result
+            .get_or_insert_with(|| result.clone())
+            .clone();
+        close.in_progress = false;
+        shared.closing.store(false, Ordering::SeqCst);
+        shared.closed.store(true, Ordering::SeqCst);
+        (result, std::mem::take(&mut close.waiters))
+    };
+    for waiter in waiters {
+        waiter.send(result.clone());
+    }
+}
+
+fn schedule_terminal_drop_close(shared: &ExecutorShared) {
+    if !shared.terminal_drop.load(Ordering::SeqCst) {
+        return;
+    }
+    let send_error = {
+        let mut close = shared
+            .close_state
+            .lock()
+            .unwrap_or_else(|error| error.into_inner());
+        if close.terminal_result.is_none() && !close.in_progress {
+            close.in_progress = true;
+            shared.closing.store(true, Ordering::SeqCst);
+            shared.queue.send_control(Command::Close).err()
+        } else {
+            None
+        }
+    };
+    if let Some(error) = send_error {
+        complete_terminal_close(shared, Err(error));
+    }
+}
+
+fn stop_owner(shared: &ExecutorShared) {
+    shared.active_work.store(false, Ordering::SeqCst);
+    shared.cancellation.stop_and_wait();
+    shared.teardown_started.store(true, Ordering::SeqCst);
+    shared.session_pinned.store(false, Ordering::SeqCst);
+    let pending = shared.queue.stop();
+    drop(pending);
+    complete_terminal_close(shared, Err(Error::EngineStopped));
+}
+
+fn dispose_session_after_owner_failure(mut session: Box) {
+    let closed =
+        catch_unwind(AssertUnwindSafe(|| session.close())).is_ok_and(|result| result.is_ok());
+    if closed {
+        let _ = catch_unwind(AssertUnwindSafe(|| drop(session)));
+    } else {
+        std::mem::forget(session);
+    }
+}
+
+pub(crate) async fn run_off_thread(thread_name: &'static str, operation: F) -> Result
+where
+    T: Send + 'static,
+    F: FnOnce() -> Result + Send + 'static,
+{
+    let (reply, receiver) = reply::channel();
+    thread::Builder::new()
+        .name(thread_name.to_owned())
+        .spawn(move || {
+            let result = catch_unwind(AssertUnwindSafe(operation)).unwrap_or_else(|panic| {
+                Err(Error::Engine(format!(
+                    "{thread_name} panicked: {}",
+                    panic_message(panic.as_ref())
+                )))
+            });
+            reply.send(result);
+        })
+        .map_err(|error| Error::Engine(format!("failed to start {thread_name}: {error}")))?;
+    receiver.await
+}
+
+fn panic_message(panic: &(dyn Any + Send)) -> String {
+    if let Some(message) = panic.downcast_ref::() {
+        message.clone()
+    } else if let Some(message) = panic.downcast_ref::<&'static str>() {
+        (*message).to_owned()
+    } else {
+        "unknown panic payload".to_owned()
+    }
+}
+
+fn run_active_work(active_work: &AtomicBool, work: impl FnOnce() -> T) -> T {
+    let _guard = ActiveWorkGuard::new(active_work);
+    work()
+}
+
+struct ActiveWorkGuard<'a> {
+    active_work: &'a AtomicBool,
+}
+
+impl<'a> ActiveWorkGuard<'a> {
+    fn new(active_work: &'a AtomicBool) -> Self {
+        active_work.store(true, Ordering::SeqCst);
+        Self { active_work }
+    }
+}
+
+impl Drop for ActiveWorkGuard<'_> {
+    fn drop(&mut self) {
+        self.active_work.store(false, Ordering::SeqCst);
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::future::Future;
+    use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+    use std::sync::{Arc, Weak, mpsc};
+    use std::task::{Context, Poll, Wake, Waker};
+    use std::time::{Duration, Instant};
+
+    use super::*;
+    use crate::engine::EngineCancel;
+    use crate::error::ErrorKind;
+
+    #[cfg(feature = "mobile-bindings")]
+    #[test]
+    fn request_cancellation_is_scoped_and_abandoned_queued_work_never_runs() {
+        struct Cancel {
+            calls: AtomicUsize,
+            release: mpsc::Sender<()>,
+        }
+        impl EngineCancel for Cancel {
+            fn cancel(&self) -> Result<()> {
+                self.calls.fetch_add(1, Ordering::SeqCst);
+                let _ = self.release.send(());
+                Ok(())
+            }
+        }
+        struct Session {
+            cancel: Arc,
+            started: mpsc::Sender,
+            release: mpsc::Receiver<()>,
+        }
+        impl EngineSession for Session {
+            fn cancel_handle(&self) -> Option> {
+                Some(self.cancel.clone())
+            }
+            fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+                let tag = request.as_bytes()[0];
+                self.started.send(tag).unwrap();
+                if tag == 2 {
+                    self.release.recv_timeout(Duration::from_secs(2)).unwrap();
+                }
+                Ok(ProtocolResponse::new([tag]))
+            }
+        }
+        let (release, release_rx) = mpsc::channel();
+        let (started, started_rx) = mpsc::channel();
+        let cancel = Arc::new(Cancel {
+            calls: AtomicUsize::new(0),
+            release,
+        });
+        let executor = EngineExecutor::spawn(Box::new(Session {
+            cancel: cancel.clone(),
+            started,
+            release: release_rx,
+        }));
+        let old = executor.request_cancellation();
+        block_on(executor.exec_cancellable(ProtocolRequest::new([1]), old.clone())).unwrap();
+        assert_eq!(started_rx.recv().unwrap(), 1);
+        let current = executor.request_cancellation();
+        let mut active =
+            Box::pin(executor.exec_cancellable(ProtocolRequest::new([2]), current.clone()));
+        assert!(poll_once(active.as_mut()).is_pending());
+        assert_eq!(started_rx.recv_timeout(Duration::from_secs(2)).unwrap(), 2);
+        old.cancel().unwrap();
+        let queued = executor.request_cancellation();
+        let mut waiting =
+            Box::pin(executor.exec_cancellable(ProtocolRequest::new([3]), queued.clone()));
+        assert!(poll_once(waiting.as_mut()).is_pending());
+        queued.cancel().unwrap();
+        let mut abandoned = Box::pin(
+            executor.exec_cancellable(ProtocolRequest::new([4]), executor.request_cancellation()),
+        );
+        assert!(poll_once(abandoned.as_mut()).is_pending());
+        drop(abandoned);
+        assert_eq!(cancel.calls.load(Ordering::SeqCst), 0);
+        // Dropping the active foreign future must release the owner, but its
+        // cancellation authority must end before the next request executes.
+        drop(active);
+        block_on(executor.exec_protocol_raw(ProtocolRequest::new([5]))).unwrap();
+        assert_eq!(started_rx.recv_timeout(Duration::from_secs(2)).unwrap(), 5);
+        assert!(started_rx.try_recv().is_err());
+        assert!(cancel.calls.load(Ordering::SeqCst) >= 1);
+        assert!(block_on(waiting).is_err());
+        block_on(executor.close()).unwrap();
+    }
+
+    struct ThreadWake(thread::Thread);
+
+    impl Wake for ThreadWake {
+        fn wake(self: Arc) {
+            self.0.unpark();
+        }
+    }
+
+    struct WakeCounter(AtomicUsize);
+
+    impl Wake for WakeCounter {
+        fn wake(self: Arc) {
+            self.0.fetch_add(1, Ordering::SeqCst);
+        }
+
+        fn wake_by_ref(self: &Arc) {
+            self.0.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+
+    struct GateWake {
+        gate: Mutex, mpsc::Receiver<()>)>>,
+    }
+
+    struct AdmissionLockProbe {
+        shared: Weak,
+        woke: AtomicBool,
+        admission_was_unlocked: AtomicBool,
+    }
+
+    impl Wake for AdmissionLockProbe {
+        fn wake(self: Arc) {
+            self.woke.store(true, Ordering::SeqCst);
+            let admission_was_unlocked = self
+                .shared
+                .upgrade()
+                .is_some_and(|shared| shared.admission.try_lock().is_ok());
+            self.admission_was_unlocked
+                .store(admission_was_unlocked, Ordering::SeqCst);
+        }
+    }
+
+    impl GateWake {
+        fn block_owner_once(&self) {
+            let gate = self
+                .gate
+                .lock()
+                .unwrap_or_else(|error| error.into_inner())
+                .take();
+            if let Some((started, release)) = gate {
+                started.send(()).expect("announce gated wake");
+                release.recv().expect("release gated wake");
+            }
+        }
+    }
+
+    impl Wake for GateWake {
+        fn wake(self: Arc) {
+            self.block_owner_once();
+        }
+
+        fn wake_by_ref(self: &Arc) {
+            self.block_owner_once();
+        }
+    }
+
+    fn block_on(future: F) -> F::Output {
+        let mut future = std::pin::pin!(future);
+        let waker = Waker::from(Arc::new(ThreadWake(thread::current())));
+        let mut context = Context::from_waker(&waker);
+        loop {
+            match future.as_mut().poll(&mut context) {
+                Poll::Ready(value) => return value,
+                Poll::Pending => thread::park(),
+            }
+        }
+    }
+
+    fn poll_once(future: std::pin::Pin<&mut F>) -> Poll {
+        let mut context = Context::from_waker(Waker::noop());
+        future.poll(&mut context)
+    }
+
+    fn assert_error_value(error: &Error, kind: ErrorKind, message: &str) {
+        assert_eq!(error.kind(), kind);
+        assert_eq!(error.to_string(), message);
+    }
+
+    fn assert_error_result(result: Result, kind: ErrorKind, message: &str) {
+        let error = result.err().expect("operation must fail");
+        assert_error_value(&error, kind, message);
+    }
+
+    fn assert_poll_error(poll: Poll>, kind: ErrorKind, message: &str) {
+        match poll {
+            Poll::Ready(Err(error)) => assert_error_value(&error, kind, message),
+            Poll::Ready(Ok(_)) => panic!("operation unexpectedly succeeded"),
+            Poll::Pending => panic!("operation unexpectedly remained pending"),
+        }
+    }
+
+    fn abandoned_ordinary_command(value: u8) -> Command {
+        let (reply, receiver) = reply::channel();
+        drop(receiver);
+        Command::Exec {
+            request: ProtocolRequest::new([value]),
+            reply,
+        }
+    }
+
+    fn poll_queue_send(
+        queue: &CommandQueue,
+        registration: &mut AdmissionRegistration<'_>,
+        command: &mut Option,
+        context: &mut Context<'_>,
+    ) -> Poll> {
+        let (poll, next) = queue.poll_send_ordinary(&mut registration.token, command, context);
+        if let Some(waker) = next {
+            waker.wake();
+        }
+        poll
+    }
+
+    fn fill_ordinary_queue(queue: &CommandQueue) {
+        for value in 0..ORDINARY_QUEUE_CAPACITY {
+            let mut registration = AdmissionRegistration::new(queue);
+            let mut command = Some(abandoned_ordinary_command(
+                u8::try_from(value).expect("queue fixture fits in one byte"),
+            ));
+            assert!(matches!(
+                poll_queue_send(
+                    queue,
+                    &mut registration,
+                    &mut command,
+                    &mut Context::from_waker(Waker::noop()),
+                ),
+                Poll::Ready(Ok(()))
+            ));
+        }
+    }
+
+    #[test]
+    fn cancelling_the_next_capacity_waiter_does_not_strand_its_fifo_successor() {
+        let queue = CommandQueue::new();
+        fill_ordinary_queue(&queue);
+
+        let first_wake = Arc::new(WakeCounter(AtomicUsize::new(0)));
+        let first_waker = Waker::from(Arc::clone(&first_wake));
+        let mut first = AdmissionRegistration::new(&queue);
+        let mut first_command = Some(abandoned_ordinary_command(1));
+        assert!(
+            poll_queue_send(
+                &queue,
+                &mut first,
+                &mut first_command,
+                &mut Context::from_waker(&first_waker),
+            )
+            .is_pending()
+        );
+
+        let second_wake = Arc::new(WakeCounter(AtomicUsize::new(0)));
+        let second_waker = Waker::from(Arc::clone(&second_wake));
+        let mut second = AdmissionRegistration::new(&queue);
+        let mut second_command = Some(abandoned_ordinary_command(2));
+        assert!(
+            poll_queue_send(
+                &queue,
+                &mut second,
+                &mut second_command,
+                &mut Context::from_waker(&second_waker),
+            )
+            .is_pending()
+        );
+
+        drop(first);
+        assert_eq!(second_wake.0.load(Ordering::SeqCst), 0);
+        drop(queue.receive().expect("free one ordinary queue slot"));
+        assert_eq!(second_wake.0.load(Ordering::SeqCst), 1);
+        assert_eq!(first_wake.0.load(Ordering::SeqCst), 0);
+        assert!(matches!(
+            poll_queue_send(
+                &queue,
+                &mut second,
+                &mut second_command,
+                &mut Context::from_waker(&second_waker),
+            ),
+            Poll::Ready(Ok(()))
+        ));
+        drop(second);
+        drop(queue.stop());
+    }
+
+    #[test]
+    fn rejected_capacity_waiter_cannot_cross_a_reopened_close_cutoff() {
+        let queue = CommandQueue::new();
+        fill_ordinary_queue(&queue);
+        let mut registration = AdmissionRegistration::new(&queue);
+        let mut command = Some(abandoned_ordinary_command(3));
+        assert!(
+            poll_queue_send(
+                &queue,
+                &mut registration,
+                &mut command,
+                &mut Context::from_waker(Waker::noop()),
+            )
+            .is_pending()
+        );
+
+        drop(queue.reject_admissions());
+        drop(queue.receive().expect("capacity becomes available later"));
+        assert_poll_error(
+            poll_queue_send(
+                &queue,
+                &mut registration,
+                &mut command,
+                &mut Context::from_waker(Waker::noop()),
+            ),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+        drop(queue.stop());
+    }
+
+    #[test]
+    fn capacity_successor_is_woken_after_releasing_admission() {
+        let shared = Arc::new(ExecutorShared::new());
+        let executor = EngineExecutor {
+            shared: Arc::clone(&shared),
+        };
+        fill_ordinary_queue(&shared.queue);
+
+        let mut first = Box::pin(executor.send(abandoned_ordinary_command(1)));
+        assert!(poll_once(first.as_mut()).is_pending());
+
+        let probe = Arc::new(AdmissionLockProbe {
+            shared: Arc::downgrade(&shared),
+            woke: AtomicBool::new(false),
+            admission_was_unlocked: AtomicBool::new(false),
+        });
+        let probe_waker = Waker::from(Arc::clone(&probe));
+        let mut second = Box::pin(executor.send(abandoned_ordinary_command(2)));
+        assert!(
+            second
+                .as_mut()
+                .poll(&mut Context::from_waker(&probe_waker))
+                .is_pending()
+        );
+
+        {
+            let mut state = shared
+                .queue
+                .state
+                .lock()
+                .unwrap_or_else(|error| error.into_inner());
+            for _ in 0..2 {
+                drop(state.commands.pop_front().expect("free saturated slot"));
+                state.ordinary_count -= 1;
+            }
+        }
+
+        assert!(matches!(poll_once(first.as_mut()), Poll::Ready(Ok(()))));
+        assert!(probe.woke.load(Ordering::SeqCst));
+        assert!(
+            probe.admission_was_unlocked.load(Ordering::SeqCst),
+            "a synchronous successor waker must never run under the admission lock"
+        );
+
+        drop(second);
+        drop(first);
+        drop(shared.queue.stop());
+        shared.closed.store(true, Ordering::SeqCst);
+    }
+
+    fn command_response(tag: &str, ready: u8) -> ProtocolResponse {
+        let mut bytes = Vec::new();
+        let mut body = tag.as_bytes().to_vec();
+        body.push(0);
+        push_backend_message(&mut bytes, b'C', &body);
+        push_backend_message(&mut bytes, b'Z', &[ready]);
+        ProtocolResponse::new(bytes)
+    }
+
+    fn push_backend_message(bytes: &mut Vec, tag: u8, body: &[u8]) {
+        bytes.push(tag);
+        bytes.extend_from_slice(&i32::try_from(body.len() + 4).unwrap().to_be_bytes());
+        bytes.extend_from_slice(body);
+    }
+
+    struct EchoSession;
+
+    impl EngineSession for EchoSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+    }
+
+    #[test]
+    fn open_constructs_the_session_on_its_permanent_owner_thread() {
+        let caller = thread::current().id();
+        let (executor, constructed_on) = block_on(EngineExecutor::open(
+            "oliphaunt-owner-construction-test",
+            || {
+                Ok((
+                    Box::new(EchoSession) as Box,
+                    thread::current().id(),
+                ))
+            },
+        ))
+        .expect("owner opens");
+
+        assert_ne!(caller, constructed_on);
+        assert_eq!(executor.shared.owner_thread.get(), Some(&constructed_on));
+        block_on(executor.close()).expect("owner closes");
+    }
+
+    #[test]
+    fn open_panic_is_an_error_instead_of_a_stranded_future() {
+        let error = block_on(EngineExecutor::open::<(), _>(
+            "oliphaunt-owner-open-panic-test",
+            || panic!("open panic probe"),
+        ))
+        .err()
+        .expect("open panic is reported");
+
+        assert_error_value(
+            &error,
+            ErrorKind::Other,
+            "oliphaunt-owner-open-panic-test panicked while opening: open panic probe",
+        );
+    }
+
+    struct DropSignalSession(Option>);
+
+    impl EngineSession for DropSignalSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+    }
+
+    impl Drop for DropSignalSession {
+        fn drop(&mut self) {
+            if let Some(dropped) = self.0.take() {
+                let _ = dropped.send(());
+            }
+        }
+    }
+
+    #[test]
+    fn abandoned_open_closes_a_session_that_finishes_late() {
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let (dropped, dropped_rx) = mpsc::channel();
+        let mut open = Box::pin(EngineExecutor::open(
+            "oliphaunt-owner-abandoned-open-test",
+            move || {
+                started.send(()).expect("announce open");
+                release_rx.recv().expect("release open");
+                Ok((
+                    Box::new(DropSignalSession(Some(dropped))) as Box,
+                    (),
+                ))
+            },
+        ));
+        assert!(poll_once(open.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("open reaches owner");
+        drop(open);
+        release.send(()).expect("finish abandoned open");
+        dropped_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("late session is closed and dropped");
+    }
+
+    struct PanickingSession;
+
+    impl EngineSession for PanickingSession {
+        fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
+            panic!("injected owner command panic")
+        }
+    }
+
+    #[test]
+    fn owner_panic_wakes_active_and_future_operations() {
+        let executor = EngineExecutor::spawn(Box::new(PanickingSession));
+        assert_error_result(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([1]))),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+        assert_error_result(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([2]))),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+    }
+
+    struct BlockingSession {
+        calls: Arc,
+        started: mpsc::Sender<()>,
+        release: mpsc::Receiver<()>,
+        dropped: Option>,
+    }
+
+    impl EngineSession for BlockingSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            self.calls.fetch_add(1, Ordering::SeqCst);
+            self.started.send(()).expect("announce active owner work");
+            self.release.recv().expect("release active owner work");
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+    }
+
+    impl Drop for BlockingSession {
+        fn drop(&mut self) {
+            if let Some(dropped) = self.dropped.take() {
+                let _ = dropped.send(());
+            }
+        }
+    }
+
+    #[test]
+    fn bounded_fifo_awaits_capacity_then_close_rejects_later_work() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(BlockingSession {
+            calls: Arc::clone(&calls),
+            started,
+            release: release_rx,
+            dropped: None,
+        }));
+
+        let mut active = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1])));
+        assert!(poll_once(active.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("first operation reaches owner");
+
+        let mut queued = Vec::with_capacity(ORDINARY_QUEUE_CAPACITY);
+        for value in 0..ORDINARY_QUEUE_CAPACITY {
+            let mut future =
+                Box::pin(executor.exec_protocol_raw(ProtocolRequest::new(value.to_le_bytes())));
+            assert!(poll_once(future.as_mut()).is_pending());
+            queued.push(future);
+        }
+        let mut overflow = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([9, 9, 9])));
+        assert!(
+            poll_once(overflow.as_mut()).is_pending(),
+            "queue saturation applies asynchronous backpressure"
+        );
+
+        // Free one queue slot. The owner immediately occupies itself with the
+        // next operation, while the overflow future can now acquire the slot.
+        release.send(()).expect("release active operation");
+        assert_eq!(
+            block_on(active).expect("active work drains").as_bytes(),
+            &[1]
+        );
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("next operation reaches owner");
+        assert!(poll_once(overflow.as_mut()).is_pending());
+        {
+            let queue = executor
+                .shared
+                .queue
+                .state
+                .lock()
+                .unwrap_or_else(|error| error.into_inner());
+            assert_eq!(queue.ordinary_count, ORDINARY_QUEUE_CAPACITY);
+            assert!(queue.admission_waiters.is_empty());
+        }
+
+        let mut cutoff_waiter =
+            Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([8, 8, 8])));
+        assert!(poll_once(cutoff_waiter.as_mut()).is_pending());
+
+        // Close is a control command and still enters the same FIFO after all
+        // already-admitted ordinary work.
+        let mut close = Box::pin(executor.close());
+        assert!(poll_once(close.as_mut()).is_pending());
+        assert_poll_error(
+            poll_once(cutoff_waiter.as_mut()),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+        let mut after_cutoff = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([7, 7])));
+        assert_poll_error(
+            poll_once(after_cutoff.as_mut()),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+
+        // The remaining permits may be buffered, allowing every pre-cutoff
+        // command to run without depending on scheduler timing in this test.
+        for _ in 0..=ORDINARY_QUEUE_CAPACITY {
+            release.send(()).expect("release admitted operation");
+        }
+        for operation in queued {
+            block_on(operation).expect("pre-cutoff queued work drains");
+        }
+        block_on(overflow).expect("capacity waiter is admitted before close");
+        block_on(close).expect("reserved close command completes");
+        assert_eq!(calls.load(Ordering::SeqCst), ORDINARY_QUEUE_CAPACITY + 2);
+    }
+
+    struct BlockingTransactionSession {
+        calls: Arc,
+        started: mpsc::Sender<()>,
+        release: mpsc::Receiver<()>,
+    }
+
+    impl EngineSession for BlockingTransactionSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            match self.calls.fetch_add(1, Ordering::SeqCst) {
+                0 => {
+                    self.started.send(()).expect("announce blocking work");
+                    self.release.recv().expect("release blocking work");
+                    Ok(ProtocolResponse::new(request.as_bytes()))
+                }
+                1 => Ok(command_response("BEGIN", b'T')),
+                2 => Ok(command_response("ROLLBACK", b'I')),
+                call => panic!("unexpected transaction session call {call}"),
+            }
+        }
+    }
+
+    #[test]
+    fn begin_admitted_before_close_runs_and_close_observes_its_pin() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(BlockingTransactionSession {
+            calls: Arc::clone(&calls),
+            started,
+            release: release_rx,
+        }));
+
+        let mut active = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1])));
+        assert!(poll_once(active.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("first operation reaches owner");
+
+        let mut begin = Box::pin(executor.begin_transaction());
+        assert!(poll_once(begin.as_mut()).is_pending());
+        let mut close = Box::pin(executor.close());
+        assert!(poll_once(close.as_mut()).is_pending());
+        let mut later_begin = Box::pin(executor.begin_transaction());
+        assert_poll_error(
+            poll_once(later_begin.as_mut()),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+
+        release.send(()).expect("release first operation");
+        block_on(active).expect("active operation drains");
+        let token = block_on(begin).expect("pre-cutoff BEGIN runs");
+        assert_error_result(
+            block_on(close),
+            ErrorKind::TransactionActive,
+            "a transaction is active; use the active transaction handle",
+        );
+        assert!(!executor.is_closed());
+        assert!(executor.session_is_pinned());
+
+        let rollback = block_on(executor.pinned_exec_protocol_control(
+            token,
+            ProtocolRequest::simple_query("ROLLBACK").expect("rollback request"),
+            TransactionGuard::active(),
+        ))
+        .expect("rollback after failed close");
+        assert_eq!(
+            parse_simple_command_response(&rollback)
+                .expect("rollback response")
+                .ready_status(),
+            ReadyStatus::Idle
+        );
+        block_on(executor.release_pin(token)).expect("release transaction pin");
+        block_on(executor.close()).expect("retry closes after transaction cleanup");
+        assert_eq!(calls.load(Ordering::SeqCst), 3);
+    }
+
+    struct PreCutoffSettlementSession {
+        settlement_tag: &'static str,
+        calls: Arc,
+        started: mpsc::Sender<()>,
+        release: mpsc::Receiver<()>,
+    }
+
+    impl EngineSession for PreCutoffSettlementSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            match self.calls.fetch_add(1, Ordering::SeqCst) {
+                0 => {
+                    self.started.send(()).expect("announce blocking work");
+                    self.release.recv().expect("release blocking work");
+                    Ok(ProtocolResponse::new(request.as_bytes()))
+                }
+                1 => {
+                    assert_eq!(
+                        request.as_bytes(),
+                        ProtocolRequest::simple_query("BEGIN")
+                            .expect("BEGIN request")
+                            .as_bytes()
+                    );
+                    Ok(command_response("BEGIN", b'T'))
+                }
+                2 => {
+                    assert_eq!(
+                        request.as_bytes(),
+                        ProtocolRequest::simple_query(self.settlement_tag)
+                            .expect("settlement request")
+                            .as_bytes()
+                    );
+                    Ok(command_response(self.settlement_tag, b'I'))
+                }
+                call => panic!("unexpected pre-cutoff settlement call {call}"),
+            }
+        }
+    }
+
+    fn assert_pre_cutoff_begin_can_settle_after_close_cutoff(settlement_tag: &'static str) {
+        use crate::database::AsyncOliphaunt;
+
+        let calls = Arc::new(AtomicUsize::new(0));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(PreCutoffSettlementSession {
+            settlement_tag,
+            calls: Arc::clone(&calls),
+            started,
+            release: release_rx,
+        }));
+        let database = AsyncOliphaunt::from_executor(Arc::clone(&executor));
+
+        let mut active = Box::pin(database.exec_protocol_raw([1]));
+        assert!(poll_once(active.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("first operation reaches owner");
+
+        // The owner's wake for the BEGIN reply is synchronous. Gate that first
+        // wake so this thread can poll the real transaction future through its
+        // COMMIT/ROLLBACK admission while the owner is still before Close.
+        let (begin_woke, begin_woke_rx) = mpsc::channel();
+        let (release_owner, release_owner_rx) = mpsc::channel();
+        let gate_waker = Waker::from(Arc::new(GateWake {
+            gate: Mutex::new(Some((begin_woke, release_owner_rx))),
+        }));
+        let mut transaction = Box::pin(database.transaction(async |transaction| {
+            if settlement_tag == "ROLLBACK" {
+                transaction.rollback().await?;
+            }
+            Ok::<(), Error>(())
+        }));
+        let mut gate_context = Context::from_waker(&gate_waker);
+        assert!(transaction.as_mut().poll(&mut gate_context).is_pending());
+
+        let mut close = Box::pin(database.close());
+        assert!(poll_once(close.as_mut()).is_pending());
+        assert!(executor.shared.closing.load(Ordering::SeqCst));
+
+        release.send(()).expect("release first operation");
+        block_on(active).expect("active operation drains");
+        begin_woke_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("BEGIN reply wakes the transaction future");
+        assert!(
+            transaction
+                .as_mut()
+                .poll(&mut Context::from_waker(Waker::noop()))
+                .is_pending()
+        );
+
+        {
+            let queue = executor
+                .shared
+                .queue
+                .state
+                .lock()
+                .unwrap_or_else(|error| error.into_inner());
+            assert_eq!(queue.commands.len(), 2);
+            assert!(matches!(queue.commands.front(), Some(Command::Close)));
+            assert!(matches!(
+                queue.commands.back(),
+                Some(Command::PinnedExec { .. })
+            ));
+        }
+        release_owner
+            .send(())
+            .expect("release owner after settlement admission");
+
+        block_on(transaction).expect("callback transaction settles");
+        assert_error_result(
+            block_on(close),
+            ErrorKind::TransactionActive,
+            "a transaction is active; use the active transaction handle",
+        );
+        assert!(!executor.is_closed());
+        block_on(database.close()).expect("retry closes settled session");
+        assert_eq!(calls.load(Ordering::SeqCst), 3);
+    }
+
+    #[test]
+    fn pre_cutoff_begin_can_commit_after_close_cutoff_without_deadlock() {
+        assert_pre_cutoff_begin_can_settle_after_close_cutoff("COMMIT");
+    }
+
+    #[test]
+    fn pre_cutoff_begin_can_rollback_after_close_cutoff_without_deadlock() {
+        assert_pre_cutoff_begin_can_settle_after_close_cutoff("ROLLBACK");
+    }
+
+    struct TransactionControlSession {
+        calls: Arc,
+        started: mpsc::Sender<()>,
+        release: mpsc::Receiver<()>,
+    }
+
+    impl EngineSession for TransactionControlSession {
+        fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
+            match self.calls.fetch_add(1, Ordering::SeqCst) {
+                0 => Ok(command_response("BEGIN", b'T')),
+                1 => {
+                    self.started.send(()).expect("announce pinned work");
+                    self.release.recv().expect("release pinned work");
+                    Ok(command_response("SELECT", b'T'))
+                }
+                2 => Ok(command_response("ROLLBACK", b'I')),
+                call => panic!("unexpected transaction-control session call {call}"),
+            }
+        }
+    }
+
+    #[test]
+    fn transaction_control_admitted_before_close_is_not_retroactively_rejected() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(TransactionControlSession {
+            calls: Arc::clone(&calls),
+            started,
+            release: release_rx,
+        }));
+
+        let token = block_on(executor.begin_transaction()).expect("transaction begins");
+        let guard = TransactionGuard::active();
+        let mut pinned = Box::pin(executor.pinned_exec_structured(
+            token,
+            ProtocolRequest::simple_query("SELECT 1").expect("query request"),
+            "transaction test",
+            Arc::clone(&guard),
+        ));
+        assert!(poll_once(pinned.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("pinned operation reaches owner");
+
+        let mut rollback = Box::pin(executor.pinned_exec_protocol_control(
+            token,
+            ProtocolRequest::simple_query("ROLLBACK").expect("rollback request"),
+            guard,
+        ));
+        assert!(poll_once(rollback.as_mut()).is_pending());
+        let mut close = Box::pin(executor.close());
+        assert!(poll_once(close.as_mut()).is_pending());
+
+        release.send(()).expect("release pinned operation");
+        block_on(pinned).expect("pinned operation drains");
+        let rollback = block_on(rollback).expect("pre-cutoff rollback control runs");
+        assert_eq!(
+            parse_simple_command_response(&rollback)
+                .expect("rollback response")
+                .ready_status(),
+            ReadyStatus::Idle
+        );
+        // The protocol transaction is idle, but the SDK pin is deliberately a
+        // separate ownership boundary and is still active at Close.
+        assert_error_result(
+            block_on(close),
+            ErrorKind::TransactionActive,
+            "a transaction is active; use the active transaction handle",
+        );
+        block_on(executor.release_pin(token)).expect("release transaction pin");
+        block_on(executor.close()).expect("retry closes released session");
+        assert_eq!(calls.load(Ordering::SeqCst), 3);
+    }
+
+    struct FailedBeginAfterBlockSession {
+        calls: Arc,
+        started: mpsc::Sender<()>,
+        release: mpsc::Receiver<()>,
+    }
+
+    impl EngineSession for FailedBeginAfterBlockSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            match self.calls.fetch_add(1, Ordering::SeqCst) {
+                0 => {
+                    self.started.send(()).expect("announce blocking work");
+                    self.release.recv().expect("release blocking work");
+                    Ok(ProtocolResponse::new(request.as_bytes()))
+                }
+                1 => Err(Error::Engine("injected BEGIN failure".to_owned())),
+                call => panic!("unexpected failed-begin session call {call}"),
+            }
+        }
+    }
+
+    #[test]
+    fn failed_pre_cutoff_begin_transport_does_not_send_blind_rollback() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(FailedBeginAfterBlockSession {
+            calls: Arc::clone(&calls),
+            started,
+            release: release_rx,
+        }));
+
+        let mut active = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1])));
+        assert!(poll_once(active.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("first operation reaches owner");
+        let mut begin = Box::pin(executor.begin_transaction());
+        assert!(poll_once(begin.as_mut()).is_pending());
+        let mut close = Box::pin(executor.close());
+        assert!(poll_once(close.as_mut()).is_pending());
+
+        release.send(()).expect("release first operation");
+        block_on(active).expect("active operation drains");
+        assert_error_result(block_on(begin), ErrorKind::Other, "injected BEGIN failure");
+        block_on(close).expect("unknown BEGIN failure remains closeable");
+        assert_eq!(calls.load(Ordering::SeqCst), 2);
+    }
+
+    #[test]
+    fn abandoned_pre_cutoff_begin_is_skipped_before_close() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(BlockingTransactionSession {
+            calls: Arc::clone(&calls),
+            started,
+            release: release_rx,
+        }));
+
+        let mut active = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1])));
+        assert!(poll_once(active.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("first operation reaches owner");
+        let mut begin = Box::pin(executor.begin_transaction());
+        assert!(poll_once(begin.as_mut()).is_pending());
+        drop(begin);
+        let mut close = Box::pin(executor.close());
+        assert!(poll_once(close.as_mut()).is_pending());
+
+        release.send(()).expect("release first operation");
+        block_on(active).expect("active operation drains");
+        block_on(close).expect("abandoned BEGIN does not create a pin");
+        assert_eq!(calls.load(Ordering::SeqCst), 1);
+    }
+
+    struct BlockingBeginSession {
+        calls: Arc,
+        started: mpsc::Sender<()>,
+        release: mpsc::Receiver<()>,
+    }
+
+    impl EngineSession for BlockingBeginSession {
+        fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
+            match self.calls.fetch_add(1, Ordering::SeqCst) {
+                0 => {
+                    self.started.send(()).expect("announce BEGIN execution");
+                    self.release.recv().expect("release BEGIN execution");
+                    Ok(command_response("BEGIN", b'T'))
+                }
+                1 => Ok(command_response("ROLLBACK", b'I')),
+                call => panic!("unexpected blocking-begin session call {call}"),
+            }
+        }
+    }
+
+    #[test]
+    fn begin_abandoned_during_execution_rolls_back_before_close() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(BlockingBeginSession {
+            calls: Arc::clone(&calls),
+            started,
+            release: release_rx,
+        }));
+
+        let mut begin = Box::pin(executor.begin_transaction());
+        assert!(poll_once(begin.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("BEGIN reaches PostgreSQL");
+        drop(begin);
+        let mut close = Box::pin(executor.close());
+        assert!(poll_once(close.as_mut()).is_pending());
+
+        release.send(()).expect("finish abandoned BEGIN");
+        block_on(close).expect("owner rolls back abandoned BEGIN before close");
+        assert_eq!(calls.load(Ordering::SeqCst), 2);
+    }
+
+    #[test]
+    fn final_drop_never_joins_a_blocked_owner() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let (dropped, dropped_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(BlockingSession {
+            calls,
+            started,
+            release: release_rx,
+            dropped: Some(dropped),
+        }));
+        let mut operation = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1, 2, 3])));
+        assert!(poll_once(operation.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("owner operation starts");
+        drop(operation);
+
+        let started_drop = Instant::now();
+        drop(executor);
+        assert!(
+            started_drop.elapsed() < Duration::from_millis(100),
+            "final drop synchronously waited for the owner"
+        );
+
+        release.send(()).expect("release detached owner");
+        dropped_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("detached owner eventually closed and dropped the session");
+    }
+
+    #[test]
+    fn final_drop_racing_retryable_validation_requeues_terminal_cleanup() {
+        let shared = ExecutorShared::new();
+        shared.terminal_drop.store(true, Ordering::SeqCst);
+        shared.closing.store(true, Ordering::SeqCst);
+        shared
+            .close_state
+            .lock()
+            .unwrap_or_else(|error| error.into_inner())
+            .in_progress = true;
+
+        // Model the owner having observed a non-terminal explicit close just
+        // before the final handle marked terminal_drop. Completion must recheck
+        // that bit and schedule a new close rather than leaving the owner idle.
+        complete_retryable_close(&shared, Error::TransactionActive);
+        schedule_terminal_drop_close(&shared);
+
+        assert!(shared.closing.load(Ordering::SeqCst));
+        assert!(
+            shared
+                .close_state
+                .lock()
+                .unwrap_or_else(|error| error.into_inner())
+                .in_progress
+        );
+        assert!(matches!(shared.queue.receive(), Some(Command::Close)));
+    }
+
+    struct StreamSession {
+        calls: Arc,
+    }
+
+    impl EngineSession for StreamSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            self.calls.fetch_add(1, Ordering::SeqCst);
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+
+        fn exec_protocol_raw_stream(
+            &mut self,
+            _request: ProtocolRequest,
+            on_chunk: &mut dyn FnMut(&[u8]) -> Result<()>,
+        ) -> ProtocolStreamOutcome {
+            ProtocolStreamOutcome::ReadyForQuery(on_chunk(&[1, 2, 3]))
+        }
+    }
+
+    struct FailedRawSession {
+        calls: Arc,
+    }
+
+    impl EngineSession for FailedRawSession {
+        fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
+            self.calls.fetch_add(1, Ordering::SeqCst);
+            Err(Error::Engine(
+                "raw transport failed before ReadyForQuery".to_owned(),
+            ))
+        }
+    }
+
+    #[test]
+    fn raw_transport_failure_poisons_without_a_second_owner_call() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let executor = EngineExecutor::spawn(Box::new(FailedRawSession {
+            calls: Arc::clone(&calls),
+        }));
+
+        assert_error_result(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([1]))),
+            ErrorKind::Other,
+            "raw transport failed before ReadyForQuery",
+        );
+        assert_error_result(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([2]))),
+            ErrorKind::Other,
+            SESSION_STATE_UNKNOWN,
+        );
+        assert_eq!(calls.load(Ordering::SeqCst), 1);
+        block_on(executor.close()).expect("close poisoned raw session");
+    }
+
+    #[test]
+    fn callback_panic_is_contained_and_the_session_remains_usable() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let executor = EngineExecutor::spawn(Box::new(StreamSession {
+            calls: Arc::clone(&calls),
+        }));
+
+        let error = block_on(
+            executor.exec_protocol_raw_stream(ProtocolRequest::new([1]), |_| {
+                panic!("callback panic probe")
+            }),
+        )
+        .expect_err("callback panic is returned");
+        assert_eq!(error.kind(), ErrorKind::Other);
+        assert!(error.to_string().contains("stream callback panicked"));
+        assert_eq!(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([7])))
+                .expect("session remains usable")
+                .as_bytes(),
+            &[7]
+        );
+        assert_eq!(calls.load(Ordering::SeqCst), 1);
+        block_on(executor.close()).expect("close stream session");
+    }
+
+    struct FailedRecoveryStreamSession;
+
+    impl EngineSession for FailedRecoveryStreamSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+
+        fn exec_protocol_raw_stream(
+            &mut self,
+            _request: ProtocolRequest,
+            on_chunk: &mut dyn FnMut(&[u8]) -> Result<()>,
+        ) -> ProtocolStreamOutcome {
+            let _ = on_chunk(&[1, 2, 3]);
+            ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(
+                "stream transport failed before ReadyForQuery".to_owned(),
+            ))
+        }
+    }
+
+    #[test]
+    fn recovery_failure_overrides_callback_panic_and_poisons_the_session() {
+        let executor = EngineExecutor::spawn(Box::new(FailedRecoveryStreamSession));
+
+        assert_error_result(
+            block_on(
+                executor.exec_protocol_raw_stream(ProtocolRequest::new([1]), |_| {
+                    panic!("callback panic probe")
+                }),
+            ),
+            ErrorKind::Other,
+            "stream transport failed before ReadyForQuery",
+        );
+        assert_error_result(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([7]))),
+            ErrorKind::Other,
+            SESSION_STATE_UNKNOWN,
+        );
+        block_on(executor.close()).expect("close failed-recovery stream session");
+    }
+
+    #[test]
+    fn callback_reentrancy_fails_immediately_instead_of_deadlocking() {
+        let executor = EngineExecutor::spawn(Box::new(StreamSession {
+            calls: Arc::new(AtomicUsize::new(0)),
+        }));
+        let reentrant = Arc::clone(&executor);
+        block_on(
+            executor.exec_protocol_raw_stream(ProtocolRequest::new([1]), move |_| {
+                let error = block_on(reentrant.exec_protocol_raw(ProtocolRequest::new([2])))
+                    .expect_err("reentrant owner work is rejected");
+                assert!(error.to_string().contains("reentrant database work"));
+                let error = block_on(reentrant.pinned_exec_protocol_control(
+                    1,
+                    ProtocolRequest::simple_query("COMMIT").expect("control request"),
+                    TransactionGuard::active(),
+                ))
+                .expect_err("reentrant transaction settlement is rejected");
+                assert!(error.to_string().contains("reentrant database work"));
+                let error = block_on(reentrant.close())
+                    .expect_err("reentrant pre-teardown close is rejected");
+                assert!(error.to_string().contains("reentrant database work"));
+                assert!(!reentrant.is_closed());
+                Ok(())
+            }),
+        )
+        .expect("outer stream remains usable");
+        assert!(!executor.is_closed());
+        block_on(executor.close()).expect("close stream session");
+    }
+
+    struct BlockingCancel {
+        started: Mutex>>,
+        release: Mutex>,
+    }
+
+    impl EngineCancel for BlockingCancel {
+        fn cancel(&self) -> Result<()> {
+            if let Some(started) = self
+                .started
+                .lock()
+                .unwrap_or_else(|error| error.into_inner())
+                .take()
+            {
+                started
+                    .send(thread::current().id())
+                    .expect("announce cancellation thread");
+            }
+            self.release
+                .lock()
+                .unwrap_or_else(|error| error.into_inner())
+                .recv()
+                .expect("release cancellation");
+            Ok(())
+        }
+    }
+
+    struct CancellableSession {
+        cancel: Arc,
+    }
+
+    impl EngineSession for CancellableSession {
+        fn cancel_handle(&self) -> Option> {
+            let cancel: Arc = self.cancel.clone();
+            Some(cancel)
+        }
+
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+    }
+
+    #[test]
+    fn cancellation_transport_work_is_async_and_out_of_band() {
+        let caller = thread::current().id();
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(CancellableSession {
+            cancel: Arc::new(BlockingCancel {
+                started: Mutex::new(Some(started)),
+                release: Mutex::new(release_rx),
+            }),
+        }));
+
+        let mut cancel = Box::pin(executor.cancel());
+        assert!(poll_once(cancel.as_mut()).is_pending());
+        let cancellation_thread = started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("cancellation starts without blocking the poller");
+        assert_ne!(caller, cancellation_thread);
+        assert_eq!(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([8])))
+                .expect("ordinary owner work is not queued behind cancellation")
+                .as_bytes(),
+            &[8]
+        );
+        release.send(()).expect("finish cancellation");
+        block_on(cancel).expect("cancellation completes");
+        block_on(executor.close()).expect("close cancellable session");
+    }
+
+    #[test]
+    fn close_waits_for_admitted_cancellation_and_rejects_later_calls() {
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(CancellableSession {
+            cancel: Arc::new(BlockingCancel {
+                started: Mutex::new(Some(started)),
+                release: Mutex::new(release_rx),
+            }),
+        }));
+
+        let mut cancel = Box::pin(executor.cancel());
+        assert!(poll_once(cancel.as_mut()).is_pending());
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("cancellation reaches its engine target");
+
+        let mut close = Box::pin(executor.close());
+        assert!(poll_once(close.as_mut()).is_pending());
+        assert!(
+            executor
+                .shared
+                .cancellation
+                .wait_for_cutoff(Duration::from_secs(2)),
+            "close establishes its destructive cancellation cutoff"
+        );
+        assert_eq!(executor.shared.cancellation.active_cancellations(), 1);
+        assert_error_result(
+            block_on(executor.cancel()),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+        assert!(poll_once(close.as_mut()).is_pending());
+
+        release.send(()).expect("finish admitted cancellation");
+        block_on(cancel).expect("admitted cancellation settles");
+        block_on(close).expect("close proceeds after cancellation settles");
+        assert_eq!(executor.shared.cancellation.active_cancellations(), 0);
+        assert!(executor.is_closed());
+    }
+
+    struct CountingCancel {
+        calls: AtomicUsize,
+    }
+
+    impl EngineCancel for CountingCancel {
+        fn cancel(&self) -> Result<()> {
+            self.calls.fetch_add(1, Ordering::SeqCst);
+            Ok(())
+        }
+    }
+
+    struct DrainingCancellableSession {
+        cancel: Arc,
+        query_started: mpsc::Sender<()>,
+        query_release: mpsc::Receiver<()>,
+    }
+
+    impl EngineSession for DrainingCancellableSession {
+        fn cancel_handle(&self) -> Option> {
+            let cancel: Arc = self.cancel.clone();
+            Some(cancel)
+        }
+
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            self.query_started.send(()).expect("announce active query");
+            self.query_release.recv().expect("release active query");
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+    }
+
+    #[test]
+    fn cancellation_remains_admissible_after_close_cutoff_while_query_drains() {
+        let cancel = Arc::new(CountingCancel {
+            calls: AtomicUsize::new(0),
+        });
+        let (query_started, query_started_rx) = mpsc::channel();
+        let (query_release, query_release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(DrainingCancellableSession {
+            cancel: Arc::clone(&cancel),
+            query_started,
+            query_release: query_release_rx,
+        }));
+
+        let mut query = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([8])));
+        assert!(poll_once(query.as_mut()).is_pending());
+        query_started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("query reaches the owner");
+
+        let mut close = Box::pin(executor.close());
+        assert!(poll_once(close.as_mut()).is_pending());
+        assert!(executor.shared.closing.load(Ordering::SeqCst));
+        assert!(!executor.shared.teardown_started.load(Ordering::SeqCst));
+
+        block_on(executor.cancel()).expect("cancel remains out of band after the close cutoff");
+        assert_eq!(cancel.calls.load(Ordering::SeqCst), 1);
+
+        query_release.send(()).expect("finish the active query");
+        block_on(query).expect("pre-cutoff query drains");
+        block_on(close).expect("close runs after the query");
+        assert!(executor.shared.teardown_started.load(Ordering::SeqCst));
+        assert_error_result(
+            block_on(executor.cancel()),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+        assert_eq!(cancel.calls.load(Ordering::SeqCst), 1);
+    }
+
+    struct InjectedTopologyCloseFailureSession {
+        topology: &'static str,
+        close_attempts: Arc,
+    }
+
+    impl EngineSession for InjectedTopologyCloseFailureSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+
+        fn close(&mut self) -> Result<()> {
+            self.close_attempts.fetch_add(1, Ordering::SeqCst);
+            Err(Error::Engine(format!(
+                "injected {} teardown failure",
+                self.topology
+            )))
+        }
+    }
+
+    fn assert_topology_close_failure_is_terminal(topology: &'static str) {
+        // Direct, broker, and server sessions converge at this EngineSession
+        // boundary. Inject each topology's teardown error here so the shared
+        // lifecycle state machine is tested without native libraries or child
+        // processes making the failure nondeterministic.
+        let attempts = Arc::new(AtomicUsize::new(0));
+        let executor = EngineExecutor::spawn(Box::new(InjectedTopologyCloseFailureSession {
+            topology,
+            close_attempts: Arc::clone(&attempts),
+        }));
+        let expected = format!("injected {topology} teardown failure");
+        assert_error_result(block_on(executor.close()), ErrorKind::Other, &expected);
+        assert!(executor.is_closed());
+        assert_error_result(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([4]))),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+        assert_error_result(block_on(executor.close()), ErrorKind::Other, &expected);
+        assert_error_result(block_on(executor.close()), ErrorKind::Other, &expected);
+        assert_eq!(attempts.load(Ordering::SeqCst), 1);
+    }
+
+    #[test]
+    fn direct_teardown_failure_terminally_retires_the_handle() {
+        assert_topology_close_failure_is_terminal("direct");
+    }
+
+    #[test]
+    fn broker_teardown_failure_terminally_retires_the_handle() {
+        assert_topology_close_failure_is_terminal("broker");
+    }
+
+    #[test]
+    fn server_teardown_failure_terminally_retires_the_handle() {
+        assert_topology_close_failure_is_terminal("server");
+    }
+
+    struct PanickingCloseSession;
+
+    impl EngineSession for PanickingCloseSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+
+        fn close(&mut self) -> Result<()> {
+            panic!("injected close panic");
+        }
+    }
+
+    #[test]
+    fn close_panic_is_one_exact_terminal_outcome() {
+        let executor = EngineExecutor::spawn(Box::new(PanickingCloseSession));
+        let expected = "native engine session panicked during close: injected close panic";
+
+        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
+        assert!(executor.is_closed());
+        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
+        assert_error_result(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([1]))),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+    }
+
+    struct PanickingDropSession;
+
+    impl EngineSession for PanickingDropSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+    }
+
+    impl Drop for PanickingDropSession {
+        fn drop(&mut self) {
+            panic!("injected session destructor panic");
+        }
+    }
+
+    #[test]
+    fn destructor_panic_fails_close_without_stranding_its_waiter() {
+        let executor = EngineExecutor::spawn(Box::new(PanickingDropSession));
+        let expected = "native engine session destructor panicked after close: injected session destructor panic";
+        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
+        assert!(executor.is_closed());
+        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
+        assert_error_result(
+            block_on(executor.exec_protocol_raw(ProtocolRequest::new([1]))),
+            ErrorKind::Lifecycle,
+            "native database session has stopped",
+        );
+    }
+
+    struct CoalescingCloseSession {
+        calls: Arc,
+        started: mpsc::Sender<()>,
+        release: mpsc::Receiver<()>,
+        closed: Arc,
+    }
+
+    impl EngineSession for CoalescingCloseSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+
+        fn close(&mut self) -> Result<()> {
+            self.calls.fetch_add(1, Ordering::SeqCst);
+            self.started.send(()).expect("announce close");
+            self.release.recv().expect("release close");
+            self.closed.store(true, Ordering::SeqCst);
+            Ok(())
+        }
+    }
+
+    #[test]
+    fn concurrent_close_calls_coalesce_onto_one_definitive_attempt() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let closed = Arc::new(AtomicBool::new(false));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(CoalescingCloseSession {
+            calls: Arc::clone(&calls),
+            started,
+            release: release_rx,
+            closed: Arc::clone(&closed),
+        }));
+
+        let first_executor = Arc::clone(&executor);
+        let first = thread::spawn(move || block_on(first_executor.close()));
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("first close reaches owner");
+        let second_executor = Arc::clone(&executor);
+        let second = thread::spawn(move || block_on(second_executor.close()));
+        let deadline = Instant::now() + Duration::from_secs(2);
+        while executor
+            .shared
+            .close_state
+            .lock()
+            .unwrap_or_else(|error| error.into_inner())
+            .waiters
+            .len()
+            < 2
+            && Instant::now() < deadline
+        {
+            thread::yield_now();
+        }
+        release.send(()).expect("finish close");
+
+        first
+            .join()
+            .expect("join first close")
+            .expect("first close");
+        second
+            .join()
+            .expect("join second close")
+            .expect("second close");
+        assert!(closed.load(Ordering::SeqCst));
+        assert_eq!(calls.load(Ordering::SeqCst), 1);
+    }
+
+    struct CoalescingFailedCloseSession {
+        calls: Arc,
+        started: mpsc::Sender<()>,
+        release: mpsc::Receiver<()>,
+    }
+
+    impl EngineSession for CoalescingFailedCloseSession {
+        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+            Ok(ProtocolResponse::new(request.as_bytes()))
+        }
+
+        fn close(&mut self) -> Result<()> {
+            self.calls.fetch_add(1, Ordering::SeqCst);
+            self.started.send(()).expect("announce failed close");
+            self.release.recv().expect("release failed close");
+            Err(Error::Engine(
+                "injected concurrent teardown failure".to_owned(),
+            ))
+        }
+    }
+
+    #[test]
+    fn concurrent_and_repeated_failed_closes_share_one_exact_terminal_outcome() {
+        let calls = Arc::new(AtomicUsize::new(0));
+        let (started, started_rx) = mpsc::channel();
+        let (release, release_rx) = mpsc::channel();
+        let executor = EngineExecutor::spawn(Box::new(CoalescingFailedCloseSession {
+            calls: Arc::clone(&calls),
+            started,
+            release: release_rx,
+        }));
+        let expected = "injected concurrent teardown failure";
+
+        let first_executor = Arc::clone(&executor);
+        let first = thread::spawn(move || block_on(first_executor.close()));
+        started_rx
+            .recv_timeout(Duration::from_secs(2))
+            .expect("first close reaches owner");
+        let second_executor = Arc::clone(&executor);
+        let second = thread::spawn(move || block_on(second_executor.close()));
+        let deadline = Instant::now() + Duration::from_secs(2);
+        while executor
+            .shared
+            .close_state
+            .lock()
+            .unwrap_or_else(|error| error.into_inner())
+            .waiters
+            .len()
+            < 2
+            && Instant::now() < deadline
+        {
+            thread::yield_now();
+        }
+        assert_eq!(
+            executor
+                .shared
+                .close_state
+                .lock()
+                .unwrap_or_else(|error| error.into_inner())
+                .waiters
+                .len(),
+            2,
+            "second close must join the in-flight attempt before it resolves"
+        );
+        release.send(()).expect("finish failed close");
+
+        assert_error_result(
+            first.join().expect("join first close"),
+            ErrorKind::Other,
+            expected,
+        );
+        assert_error_result(
+            second.join().expect("join second close"),
+            ErrorKind::Other,
+            expected,
+        );
+        assert!(executor.is_closed());
+        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
+        assert_eq!(calls.load(Ordering::SeqCst), 1);
+    }
+}
diff --git a/src/sdks/rust/sdk/src/extension.rs b/src/sdks/rust/sdk/src/extension.rs
new file mode 100644
index 000000000..4de9b4323
--- /dev/null
+++ b/src/sdks/rust/sdk/src/extension.rs
@@ -0,0 +1,3 @@
+pub use liboliphaunt_native_bindings::Extension;
+#[cfg(feature = "desktop")]
+pub(crate) use liboliphaunt_native_bindings::extension::extension_runtime_environment;
diff --git a/src/sdks/rust/sdk/src/ipc.rs b/src/sdks/rust/sdk/src/ipc.rs
new file mode 100644
index 000000000..c64e4ad49
--- /dev/null
+++ b/src/sdks/rust/sdk/src/ipc.rs
@@ -0,0 +1,9 @@
+use crate::Result;
+pub(crate) use oliphaunt_broker::ipc::{RequestFrame, ResponseFrame};
+use std::io::{Read, Write};
+pub(crate) fn write_request(writer: &mut impl Write, frame: RequestFrame) -> Result<()> {
+    oliphaunt_broker::ipc::write_request(writer, frame).map_err(Into::into)
+}
+pub(crate) fn read_response(reader: &mut impl Read) -> Result {
+    oliphaunt_broker::ipc::read_response(reader).map_err(Into::into)
+}
diff --git a/src/sdks/rust/sdk/src/lib.rs b/src/sdks/rust/sdk/src/lib.rs
new file mode 100644
index 000000000..a0c78a5e5
--- /dev/null
+++ b/src/sdks/rust/sdk/src/lib.rs
@@ -0,0 +1,62 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+#![forbid(missing_docs)]
+//! Native-first Rust SDK surface for embedded Oliphaunt.
+//!
+//! This crate is deliberately native-only. It does not expose a WASIX engine
+//! and it does not depend on the current `oliphaunt-wasix` runtime layout.
+
+#[cfg(feature = "desktop")]
+mod broker;
+mod build_resources;
+mod builder;
+mod cancellation;
+#[cfg(feature = "desktop")]
+mod child_process;
+mod config;
+mod database;
+mod direct;
+mod engine;
+mod error;
+mod executor;
+mod extension;
+#[cfg(feature = "desktop")]
+mod ipc;
+#[allow(unsafe_code)]
+mod liboliphaunt;
+#[cfg(feature = "mobile-bindings")]
+#[doc(hidden)]
+pub mod mobile;
+#[cfg(feature = "desktop")]
+mod pgwire;
+mod protocol;
+mod query;
+pub(crate) use oliphaunt_query as query_core;
+mod reply;
+#[cfg(feature = "desktop")]
+mod server;
+mod session;
+mod storage;
+#[cfg(test)]
+mod test_fixtures;
+#[doc(hidden)]
+pub use build_resources::__register_build_resources;
+pub use build_resources::register_build_resources_dir;
+pub use builder::{AsyncOliphauntBuilder, AsyncOliphauntServerBuilder};
+pub use config::ServerListen;
+pub use database::{AsyncOliphaunt, AsyncOliphauntServer, AsyncSql, AsyncTransaction};
+pub use direct::{
+    CancelHandle, Oliphaunt, OliphauntBuilder, OliphauntServer, OliphauntServerBuilder, Sql,
+    Transaction,
+};
+pub use error::{
+    Error, ErrorKind, PostgresError, PostgresErrorField, RawStreamCallbackOutput, RawStreamError,
+    RawStreamResult, Result, TransactionError, TransactionResult,
+};
+pub use extension::Extension;
+pub use liboliphaunt_native_bindings::{NativeClusterSeed, NativeResourceDirectory};
+pub use query::{
+    CommandResult, DecodeError, ExecResult, FromSql, IntoParameter, Parameter, PostgresNotice,
+    QueryField, QueryFormat, QueryResult, QueryRow, RowIndex, StatementDescription,
+    StatementResult, TypeOid, ValueFormat, ValueRef,
+};
+pub use storage::DatabaseStorage;
diff --git a/src/sdks/rust/sdk/src/liboliphaunt.rs b/src/sdks/rust/sdk/src/liboliphaunt.rs
new file mode 100644
index 000000000..0dba4ce1d
--- /dev/null
+++ b/src/sdks/rust/sdk/src/liboliphaunt.rs
@@ -0,0 +1,59 @@
+use crate::config::OpenConfig;
+use crate::engine::{EngineCancel, EngineSession, NativeRuntime, ProtocolStreamOutcome};
+use crate::protocol::{ProtocolRequest, ProtocolResponse};
+use crate::{Error, Result};
+use liboliphaunt_native_bindings::{NativeCancel, NativeSession};
+#[cfg(feature = "desktop")]
+pub(crate) use liboliphaunt_native_bindings::{PreparedNativeRoot, configure_native_tool_env};
+use std::sync::Arc;
+#[derive(Debug, Clone, Default)]
+pub struct OliphauntRuntime;
+impl OliphauntRuntime {
+    pub fn from_env() -> Self {
+        Self
+    }
+    pub(crate) fn restore(&self, destination: &std::path::Path, bytes: &[u8]) -> Result<()> {
+        NativeSession::restore(destination, bytes).map_err(Into::into)
+    }
+}
+impl NativeRuntime for OliphauntRuntime {
+    fn open(&self, config: OpenConfig) -> Result> {
+        config.validate()?;
+        Ok(Box::new(NativeSession::open(config.native_config())?))
+    }
+}
+impl EngineCancel for NativeCancel {
+    fn cancel(&self) -> Result<()> {
+        NativeCancel::cancel(self).map_err(Into::into)
+    }
+}
+impl EngineSession for NativeSession {
+    fn cancel_handle(&self) -> Option> {
+        Some(Arc::new(NativeSession::cancel_handle(self)))
+    }
+    fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
+        NativeSession::exec_protocol_raw(self, request.as_bytes())
+            .map(ProtocolResponse::new)
+            .map_err(Into::into)
+    }
+    fn exec_protocol_raw_stream(
+        &mut self,
+        request: ProtocolRequest,
+        on_chunk: &mut dyn FnMut(&[u8]) -> Result<()>,
+    ) -> ProtocolStreamOutcome {
+        match NativeSession::exec_protocol_raw_stream::(self, request.as_bytes(), on_chunk) {
+            liboliphaunt_native_bindings::ProtocolStreamOutcome::ReadyForQuery(result) => {
+                ProtocolStreamOutcome::ReadyForQuery(result)
+            }
+            liboliphaunt_native_bindings::ProtocolStreamOutcome::SessionStateUnknown(error) => {
+                ProtocolStreamOutcome::SessionStateUnknown(error.into())
+            }
+        }
+    }
+    fn backup(&mut self) -> Result> {
+        NativeSession::backup(self).map_err(Into::into)
+    }
+    fn close(&mut self) -> Result<()> {
+        NativeSession::close(self).map_err(Into::into)
+    }
+}
diff --git a/src/sdks/rust/sdk/src/mobile.rs b/src/sdks/rust/sdk/src/mobile.rs
new file mode 100644
index 000000000..4db279530
--- /dev/null
+++ b/src/sdks/rust/sdk/src/mobile.rs
@@ -0,0 +1,97 @@
+//! Prepared native inputs for the private generated mobile bindings.
+
+use crate::executor::EngineExecutor;
+use crate::{AsyncOliphaunt, Result};
+use liboliphaunt_native_bindings::{NativeOpenOptions, NativeSession};
+use std::sync::Arc;
+
+/// One request with cancellation authority limited to that request.
+pub struct Request {
+    database: AsyncOliphaunt,
+    cancellation: Arc,
+}
+
+impl Request {
+    /// Whether the owner started this request; false failures leave SQL untouched.
+    pub fn was_submitted(&self) -> bool {
+        self.cancellation.was_submitted()
+    }
+    /// Whether cancellation was requested for this operation.
+    pub fn was_cancelled(&self) -> bool {
+        self.cancellation.was_cancelled()
+    }
+    /// Create an independent cancellation handle before starting foreign work.
+    pub fn new(database: &AsyncOliphaunt) -> Self {
+        Self {
+            database: database.clone(),
+            cancellation: database.executor.request_cancellation(),
+        }
+    }
+
+    /// Execute once through the existing owner queue. Abandoning this future cancels its work.
+    pub async fn execute(&self, bytes: Vec) -> Result> {
+        self.database
+            .executor
+            .exec_cancellable(
+                crate::protocol::ProtocolRequest::new(bytes),
+                Arc::clone(&self.cancellation),
+            )
+            .await
+            .map(crate::protocol::ProtocolResponse::into_bytes)
+    }
+
+    /// Stream once with the same owned request cancellation and recovery boundary.
+    pub async fn stream(
+        &self,
+        bytes: Vec,
+        on_chunk: F,
+    ) -> crate::RawStreamResult<(), O::Error>
+    where
+        F: FnMut(&[u8]) -> O + Send + 'static,
+        O: crate::RawStreamCallbackOutput,
+        O::Error: Send + 'static,
+    {
+        let callback_error = Arc::new(std::sync::Mutex::new(None));
+        let result = self
+            .database
+            .executor
+            .stream_cancellable(
+                crate::protocol::ProtocolRequest::new(bytes),
+                crate::database::adapt_raw_stream_callback(on_chunk, Arc::clone(&callback_error)),
+                Arc::clone(&self.cancellation),
+            )
+            .await;
+        crate::database::resolve_raw_stream_outcome(result, callback_error)
+    }
+
+    /// Request cancellation without targeting any other queued or later operation.
+    pub fn cancel(&self) -> Result<()> {
+        self.cancellation.cancel()
+    }
+}
+
+/// Open host-prepared resources on the existing serialized SDK owner thread.
+pub async fn open(options: NativeOpenOptions) -> Result {
+    let (executor, ()) = EngineExecutor::open("oliphaunt-mobile", move || {
+        let session = NativeSession::open_prepared_inputs(options)?;
+        Ok((Box::new(session), ()))
+    })
+    .await?;
+    Ok(AsyncOliphaunt::from_executor(executor))
+}
+
+/// Restore host-owned bytes without blocking the foreign async executor.
+pub async fn restore(
+    library: Option,
+    destination: std::path::PathBuf,
+    bytes: Vec,
+) -> Result<()> {
+    crate::executor::run_off_thread("oliphaunt-mobile-restore", move || {
+        match library {
+            Some(path) => NativeSession::restore_from_library(&path, &destination, &bytes),
+            None => NativeSession::restore_from_current_process(&destination, &bytes),
+        }
+        .map_err(Into::into)
+    })
+    .await
+}
diff --git a/src/sdks/rust/src/pgwire.rs b/src/sdks/rust/sdk/src/pgwire.rs
similarity index 100%
rename from src/sdks/rust/src/pgwire.rs
rename to src/sdks/rust/sdk/src/pgwire.rs
diff --git a/src/sdks/rust/src/protocol.rs b/src/sdks/rust/sdk/src/protocol.rs
similarity index 100%
rename from src/sdks/rust/src/protocol.rs
rename to src/sdks/rust/sdk/src/protocol.rs
diff --git a/src/sdks/rust/sdk/src/query.rs b/src/sdks/rust/sdk/src/query.rs
new file mode 100644
index 000000000..d10a8dc7b
--- /dev/null
+++ b/src/sdks/rust/sdk/src/query.rs
@@ -0,0 +1,820 @@
+use std::str;
+
+use crate::error::{Error, PostgresError, Result};
+use crate::protocol::{ProtocolRequest, ProtocolResponse};
+use crate::query_core as core;
+
+pub(crate) use crate::query_core::ReadyStatus;
+pub use crate::query_core::{
+    CommandResult, DecodeError, ExecResult, FromSql, IntoParameter, Parameter, PostgresNotice,
+    QueryField, QueryFormat, QueryResult, QueryRow, RowIndex, StatementDescription,
+    StatementResult, TypeOid, ValueFormat, ValueRef,
+};
+
+#[cfg(test)]
+pub(crate) fn parse_query_response(response: &ProtocolResponse) -> Result {
+    parse_query_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Either)
+}
+
+#[cfg(test)]
+pub(crate) fn parse_command_response(response: &ProtocolResponse) -> Result {
+    parse_command_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Either)
+}
+
+pub(crate) fn parse_extended_command_response(
+    response: &ProtocolResponse,
+) -> Result {
+    parse_command_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Extended)
+}
+
+pub(crate) fn parse_simple_command_response(response: &ProtocolResponse) -> Result {
+    parse_command_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Simple)
+}
+
+fn parse_command_response_with_protocol(
+    bytes: &[u8],
+    expected_protocol: core::ExpectedProtocol,
+) -> Result {
+    core::parse_command_response(bytes, expected_protocol).map_err(error_from_core)
+}
+
+pub(crate) fn extended_statement_request(
+    sql: &str,
+    params: &[Parameter],
+    result_format: ValueFormat,
+) -> Result {
+    core::extended_statement(sql, params, result_format.code())
+        .map(ProtocolRequest::new)
+        .map_err(error_from_core)
+}
+
+pub(crate) fn reject_copy_statements(sql: &str) -> Result<()> {
+    core::reject_copy_statements(sql).map_err(error_from_core)
+}
+
+pub(crate) fn reject_transaction_chain(sql: &str) -> Result<()> {
+    core::reject_transaction_chain(sql).map_err(error_from_core)
+}
+
+#[cfg(test)]
+pub(crate) fn parse_query_response_bytes(bytes: &[u8]) -> Result {
+    parse_query_response_with_protocol(bytes, core::ExpectedProtocol::Either)
+}
+
+pub(crate) fn parse_extended_query_response(response: &ProtocolResponse) -> Result {
+    parse_query_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Extended)
+}
+
+fn parse_query_response_with_protocol(
+    bytes: &[u8],
+    expected_protocol: core::ExpectedProtocol,
+) -> Result {
+    core::parse_query_response(bytes, expected_protocol).map_err(error_from_core)
+}
+
+pub(crate) fn parse_exec_response(response: &ProtocolResponse) -> Result {
+    core::parse_exec_response(response.as_bytes()).map_err(error_from_core)
+}
+
+pub(crate) fn parse_statement_description(
+    response: &ProtocolResponse,
+) -> Result {
+    core::parse_statement_description(response.as_bytes()).map_err(error_from_core)
+}
+
+pub(crate) fn describe_statement_request(
+    sql: &str,
+    params: &[Parameter],
+) -> Result {
+    core::describe_statement(sql, params)
+        .map(ProtocolRequest::new)
+        .map_err(error_from_core)
+}
+
+pub(crate) fn response_ready_status(response: &ProtocolResponse) -> Result {
+    core::response_ready_status(response.as_bytes()).map_err(error_from_core)
+}
+
+pub(crate) fn validate_managed_transaction_response(
+    response: &ProtocolResponse,
+) -> Result {
+    core::validate_managed_transaction_response(response.as_bytes()).map_err(error_from_core)
+}
+
+pub(crate) fn error_from_core(error: core::Error) -> Error {
+    match error {
+        core::Error::Protocol(message) => Error::Engine(message),
+        core::Error::Postgres {
+            diagnostic,
+            notices,
+        } => {
+            let mut error = PostgresError::from_core(*diagnostic);
+            error.notices = notices.into_iter().map(PostgresNotice::from_core).collect();
+            Error::Postgres(Box::new(error))
+        }
+    }
+}
+
+#[cfg(test)]
+fn parse_notice_response(body: &[u8]) -> Result {
+    core::parse_diagnostic_fields(body, "NoticeResponse")
+        .map(|fields| core::diagnostic(fields, "PostgreSQL NoticeResponse"))
+        .map(PostgresNotice::from_core)
+        .map_err(error_from_core)
+}
+
+#[cfg(test)]
+fn read_u32(input: &mut &[u8], label: &str) -> Result {
+    let bytes = take(input, 4, label)?;
+    Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
+}
+
+#[cfg(test)]
+fn read_i32(input: &mut &[u8], label: &str) -> Result {
+    let bytes = take(input, 4, label)?;
+    Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
+}
+
+#[cfg(test)]
+fn read_i16(input: &mut &[u8], label: &str) -> Result {
+    let bytes = take(input, 2, label)?;
+    Ok(i16::from_be_bytes([bytes[0], bytes[1]]))
+}
+
+#[cfg(test)]
+fn read_cstring<'a>(input: &mut &'a [u8], label: &str) -> Result<&'a str> {
+    let nul = input
+        .iter()
+        .position(|byte| *byte == 0)
+        .ok_or_else(|| Error::Engine(format!("{label} is missing null terminator")))?;
+    let value = str::from_utf8(&input[..nul])
+        .map_err(|error| Error::Engine(format!("{label} is not valid UTF-8: {error}")))?;
+    *input = &input[nul + 1..];
+    Ok(value)
+}
+
+#[cfg(test)]
+fn take<'a>(input: &mut &'a [u8], len: usize, label: &str) -> Result<&'a [u8]> {
+    if input.len() < len {
+        return Err(Error::Engine(format!("truncated {label}")));
+    }
+    let (head, tail) = input.split_at(len);
+    *input = tail;
+    Ok(head)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn assert_other_error_contains(actual: Result, expected: &str) {
+        let error = match actual {
+            Ok(_) => panic!("expected error containing {expected:?}"),
+            Err(error) => error,
+        };
+        assert_eq!(error.kind(), crate::error::ErrorKind::Other);
+        assert!(
+            error.to_string().contains(expected),
+            "{error:?} omitted {expected:?}"
+        );
+    }
+
+    #[test]
+    fn consumes_shared_query_response_contract() {
+        let source = crate::test_fixtures::text("protocol/query-response-cases.json");
+        let fixture: serde_json::Value =
+            serde_json::from_str(&source).expect("shared query response fixture is valid JSON");
+        assert_eq!(fixture["schemaVersion"], 1);
+        let type_oids = &fixture["typeOids"];
+        for (name, actual) in [
+            ("xmlArray", TypeOid::XML_ARRAY),
+            ("charArray", TypeOid::CHAR_ARRAY),
+            ("nameArray", TypeOid::NAME_ARRAY),
+            ("timetz", TypeOid::TIMETZ),
+            ("timetzArray", TypeOid::TIMETZ_ARRAY),
+        ] {
+            assert_eq!(
+                u64::from(actual.get()),
+                type_oids[name].as_u64().expect("shared type OID"),
+                "shared PostgreSQL type OID {name}"
+            );
+        }
+        for case in fixture["cases"].as_array().expect("fixture cases") {
+            let name = case["name"].as_str().expect("case name");
+            let bytes = decode_hex(case["responseHex"].as_str().expect("response hex"));
+            if let Some(expected_modes) = case["protocolModeExpectation"].as_object() {
+                let response = ProtocolResponse::new(bytes.clone());
+                assert_protocol_mode_result(
+                    name,
+                    "simpleCommand",
+                    parse_simple_command_response(&response)
+                        .map(|result| result.command_tag().map(str::to_owned)),
+                    &expected_modes["simpleCommand"],
+                );
+                assert_protocol_mode_result(
+                    name,
+                    "extendedCommand",
+                    parse_extended_command_response(&response)
+                        .map(|result| result.command_tag().map(str::to_owned)),
+                    &expected_modes["extendedCommand"],
+                );
+                assert_protocol_mode_result(
+                    name,
+                    "extendedQuery",
+                    parse_extended_query_response(&response)
+                        .map(|result| result.command_tag().map(str::to_owned)),
+                    &expected_modes["extendedQuery"],
+                );
+            }
+            let Some(expectation) = case["queryExpectation"].as_object() else {
+                continue;
+            };
+            match parse_query_response(&ProtocolResponse::new(bytes)) {
+                Ok(result) => {
+                    let expected = expectation["ok"]
+                        .as_object()
+                        .unwrap_or_else(|| panic!("{name}: expected parser error"));
+                    assert_eq!(
+                        result.command_tag(),
+                        expected["commandTag"].as_str(),
+                        "{name}"
+                    );
+                    assert_eq!(result.row_count(), expected["rowCount"].as_u64(), "{name}");
+                    let fields = expected["fields"].as_array().expect("expected fields");
+                    assert_eq!(result.fields().len(), fields.len(), "{name}");
+                    for (actual, expected) in result.fields().iter().zip(fields) {
+                        assert_eq!(actual.name, expected["name"].as_str().unwrap(), "{name}");
+                        assert_eq!(
+                            u64::from(actual.type_oid),
+                            expected["typeOid"].as_u64().unwrap(),
+                            "{name}"
+                        );
+                        assert_eq!(actual.format, QueryFormat::Text, "{name}");
+                    }
+                    let rows = expected["rows"].as_array().expect("expected rows");
+                    assert_eq!(result.rows().len(), rows.len(), "{name}");
+                    for (actual, expected) in result.rows().iter().zip(rows) {
+                        let expected = expected.as_array().expect("expected row values");
+                        assert_eq!(actual.values().len(), expected.len(), "{name}");
+                        for (column, expected) in expected.iter().enumerate() {
+                            assert_eq!(actual.text(column).unwrap(), expected.as_str(), "{name}");
+                        }
+                    }
+                    if let Some(expected_notices) = expected
+                        .get("notices")
+                        .and_then(serde_json::Value::as_array)
+                    {
+                        assert_eq!(result.notices().len(), expected_notices.len(), "{name}");
+                        for (actual, expected) in result.notices().iter().zip(expected_notices) {
+                            assert_notice_diagnostic(name, actual, expected);
+                        }
+                    }
+                }
+                Err(error) if error.postgres_error().is_some() => {
+                    let error = error
+                        .postgres_error()
+                        .expect("guard established PostgreSQL error identity");
+                    let expected = expectation["postgresError"]
+                        .as_object()
+                        .unwrap_or_else(|| panic!("{name}: unexpected PostgreSQL error {error:?}"));
+                    assert_eq!(
+                        error.severity.as_deref(),
+                        expected["severity"].as_str(),
+                        "{name}"
+                    );
+                    assert_eq!(
+                        error.sqlstate.as_deref(),
+                        expected["sqlstate"].as_str(),
+                        "{name}"
+                    );
+                    assert_eq!(
+                        error.message,
+                        expected["message"].as_str().unwrap(),
+                        "{name}"
+                    );
+                    assert_optional_diagnostic_field(
+                        name,
+                        "localizedSeverity",
+                        error.localized_severity.as_deref(),
+                        expected,
+                    );
+                    assert_optional_diagnostic_field(
+                        name,
+                        "nonlocalizedSeverity",
+                        error.nonlocalized_severity.as_deref(),
+                        expected,
+                    );
+                    assert_optional_diagnostic_field(
+                        name,
+                        "internalPosition",
+                        error.internal_position.as_deref(),
+                        expected,
+                    );
+                    assert_optional_diagnostic_field(
+                        name,
+                        "internalQuery",
+                        error.internal_query.as_deref(),
+                        expected,
+                    );
+                    assert_optional_diagnostic_field(name, "file", error.file.as_deref(), expected);
+                    assert_optional_diagnostic_field(name, "line", error.line.as_deref(), expected);
+                    assert_optional_diagnostic_field(
+                        name,
+                        "routine",
+                        error.routine.as_deref(),
+                        expected,
+                    );
+                }
+                Err(error) => {
+                    assert_eq!(error.kind(), crate::error::ErrorKind::Other, "{name}");
+                    let message = error.to_string();
+                    let expected = expectation["engineErrorContains"]
+                        .as_str()
+                        .unwrap_or_else(|| panic!("{name}: unexpected engine error {message}"));
+                    assert!(
+                        message.contains(expected),
+                        "{name}: {message:?} omitted {expected:?}"
+                    );
+                }
+            }
+        }
+    }
+
+    fn assert_protocol_mode_result(
+        case: &str,
+        mode: &str,
+        actual: Result>,
+        expected: &serde_json::Value,
+    ) {
+        match expected["outcome"].as_str().expect("mode outcome") {
+            "ok" => assert_eq!(
+                actual.unwrap_or_else(|error| panic!("{case} {mode}: {error}")),
+                expected["commandTag"].as_str().map(str::to_owned),
+                "{case} {mode} command tag"
+            ),
+            "engineError" => {
+                let error = actual.expect_err(&format!("{case} {mode} must fail"));
+                assert_eq!(error.kind(), crate::error::ErrorKind::Other);
+                let message = error.to_string();
+                let expected = expected["contains"].as_str().expect("error substring");
+                assert!(
+                    message.contains(expected),
+                    "{case} {mode}: {message:?} omitted {expected:?}"
+                );
+            }
+            outcome => panic!("{case} {mode}: unknown outcome {outcome:?}"),
+        }
+    }
+
+    fn assert_notice_diagnostic(case: &str, actual: &PostgresNotice, expected: &serde_json::Value) {
+        let expected = expected.as_object().expect("notice diagnostic expectation");
+        assert_optional_diagnostic_field(case, "severity", actual.severity.as_deref(), expected);
+        assert_optional_diagnostic_field(
+            case,
+            "localizedSeverity",
+            actual.localized_severity.as_deref(),
+            expected,
+        );
+        assert_optional_diagnostic_field(
+            case,
+            "nonlocalizedSeverity",
+            actual.nonlocalized_severity.as_deref(),
+            expected,
+        );
+        assert_optional_diagnostic_field(case, "message", Some(&actual.message), expected);
+        assert_optional_diagnostic_field(
+            case,
+            "internalPosition",
+            actual.internal_position.as_deref(),
+            expected,
+        );
+        assert_optional_diagnostic_field(
+            case,
+            "internalQuery",
+            actual.internal_query.as_deref(),
+            expected,
+        );
+        assert_optional_diagnostic_field(case, "file", actual.file.as_deref(), expected);
+        assert_optional_diagnostic_field(case, "line", actual.line.as_deref(), expected);
+        assert_optional_diagnostic_field(case, "routine", actual.routine.as_deref(), expected);
+    }
+
+    fn assert_optional_diagnostic_field(
+        case: &str,
+        field: &str,
+        actual: Option<&str>,
+        expected: &serde_json::Map,
+    ) {
+        if let Some(expected) = expected.get(field) {
+            assert_eq!(actual, expected.as_str(), "{case} diagnostic {field}");
+        }
+    }
+
+    fn decode_hex(value: &str) -> Vec {
+        assert_eq!(value.len() % 2, 0, "hex fixture has even length");
+        value
+            .as_bytes()
+            .chunks_exact(2)
+            .map(|pair| {
+                let pair = std::str::from_utf8(pair).expect("hex pair is ASCII");
+                u8::from_str_radix(pair, 16).expect("hex pair is valid")
+            })
+            .collect()
+    }
+
+    #[test]
+    fn returns_sql_errors_as_errors() {
+        let mut bytes = Vec::new();
+        push_error_response(&mut bytes, "ERROR", "42P01", "relation does not exist");
+        push_ready_for_query(&mut bytes);
+
+        let error = parse_query_response_bytes(&bytes).unwrap_err();
+        assert_eq!(error.kind(), crate::error::ErrorKind::Postgres);
+        let postgres = error
+            .postgres_error()
+            .expect("Postgres errors expose structured diagnostics");
+        assert_eq!(postgres.severity.as_deref(), Some("ERROR"));
+        assert_eq!(postgres.sqlstate.as_deref(), Some("42P01"));
+        assert_eq!(postgres.message, "relation does not exist");
+    }
+
+    #[test]
+    fn execute_validation_returns_structured_postgres_errors() {
+        let mut bytes = Vec::new();
+        push_notice_response(&mut bytes, "NOTICE", "before failure");
+        push_error_response(&mut bytes, "ERROR", "23505", "duplicate key value");
+        push_ready_for_query(&mut bytes);
+
+        let error = parse_command_response(&ProtocolResponse::new(bytes)).unwrap_err();
+        assert_eq!(error.kind(), crate::error::ErrorKind::Postgres);
+        let postgres = error
+            .postgres_error()
+            .expect("Postgres errors expose structured diagnostics");
+        assert_eq!(postgres.sqlstate.as_deref(), Some("23505"));
+        assert_eq!(postgres.message, "duplicate key value");
+        assert_eq!(postgres.notices.len(), 1);
+        assert_eq!(postgres.notices[0].message, "before failure");
+    }
+
+    #[test]
+    fn postgres_notice_exposes_finite_standard_diagnostic_fields() {
+        let notice = parse_notice_response(
+            b"SAVERTISSEMENT\0VWARNING\0Mcheck value\0p12\0qSELECT broken\0Fparse_expr.c\0L123\0RtransformExpr\0\0",
+        )
+        .expect("valid NoticeResponse");
+
+        assert_eq!(notice.severity.as_deref(), Some("AVERTISSEMENT"));
+        assert_eq!(notice.localized_severity.as_deref(), Some("AVERTISSEMENT"));
+        assert_eq!(notice.nonlocalized_severity.as_deref(), Some("WARNING"));
+        assert_eq!(notice.internal_position.as_deref(), Some("12"));
+        assert_eq!(notice.internal_query.as_deref(), Some("SELECT broken"));
+        assert_eq!(notice.file.as_deref(), Some("parse_expr.c"));
+        assert_eq!(notice.line.as_deref(), Some("123"));
+        assert_eq!(notice.routine.as_deref(), Some("transformExpr"));
+        assert_eq!(
+            notice
+                .fields
+                .iter()
+                .map(|field| field.code)
+                .collect::>(),
+            [b'S', b'V', b'M', b'p', b'q', b'F', b'L', b'R']
+        );
+    }
+
+    #[test]
+    fn error_response_requires_one_terminal_ready_boundary() {
+        let mut missing_ready = Vec::new();
+        push_error_response(&mut missing_ready, "ERROR", "42601", "syntax error");
+        assert_other_error_contains(
+            parse_command_response(&ProtocolResponse::new(missing_ready)),
+            "before ReadyForQuery",
+        );
+
+        let mut trailing = Vec::new();
+        push_error_response(&mut trailing, "ERROR", "42601", "syntax error");
+        push_ready_for_query(&mut trailing);
+        push_notice_response(&mut trailing, "NOTICE", "too late");
+        assert_other_error_contains(
+            parse_command_response(&ProtocolResponse::new(trailing)),
+            "bytes after ReadyForQuery",
+        );
+    }
+
+    #[test]
+    fn malformed_error_response_is_a_protocol_error() {
+        let mut malformed = Vec::new();
+        push_backend_message(&mut malformed, b'E', b"SERROR\0Mmissing terminator");
+        push_ready_for_query(&mut malformed);
+        assert_other_error_contains(
+            parse_command_response(&ProtocolResponse::new(malformed)),
+            "ErrorResponse field is missing null terminator",
+        );
+
+        let mut valid_without_message = Vec::new();
+        push_backend_message(&mut valid_without_message, b'E', b"CXX000\0\0");
+        push_ready_for_query(&mut valid_without_message);
+        let sdk_error =
+            parse_command_response(&ProtocolResponse::new(valid_without_message)).unwrap_err();
+        assert_eq!(sdk_error.kind(), crate::error::ErrorKind::Postgres);
+        let error = sdk_error
+            .postgres_error()
+            .expect("a valid ErrorResponse must retain PostgreSQL error identity");
+        assert_eq!(error.sqlstate.as_deref(), Some("XX000"));
+        assert_eq!(error.message, "PostgreSQL ErrorResponse");
+    }
+
+    #[test]
+    fn returns_query_cancellation_as_structured_postgres_error() {
+        let mut bytes = Vec::new();
+        push_error_response(
+            &mut bytes,
+            "ERROR",
+            "57014",
+            "canceling statement due to user request",
+        );
+        push_ready_for_query(&mut bytes);
+
+        let error = parse_query_response_bytes(&bytes).unwrap_err();
+        assert_eq!(error.kind(), crate::error::ErrorKind::Postgres);
+        let postgres = error
+            .postgres_error()
+            .expect("Postgres errors expose structured cancellation diagnostics");
+        assert_eq!(postgres.severity.as_deref(), Some("ERROR"));
+        assert_eq!(postgres.sqlstate.as_deref(), Some("57014"));
+        assert_eq!(postgres.message, "canceling statement due to user request");
+    }
+
+    #[test]
+    fn builds_extended_query_protocol_request() {
+        let params = [
+            7_i32.into_parameter(),
+            Some("hello").into_parameter(),
+            Parameter::binary([0_u8, 1, 2]),
+            None::<&str>.into_parameter(),
+        ];
+        let request = extended_statement_request(
+            "SELECT $1::int4, $2::text, $3::bytea, $4::text",
+            ¶ms,
+            ValueFormat::Text,
+        )
+        .unwrap();
+
+        assert_eq!(
+            frontend_message_tags(request.as_bytes()),
+            vec![b'P', b'B', b'D', b'E', b'S']
+        );
+        assert!(
+            request
+                .as_bytes()
+                .windows(b"hello".len())
+                .any(|window| window == b"hello")
+        );
+        assert!(
+            request
+                .as_bytes()
+                .windows([0_u8, 1, 2].len())
+                .any(|window| window == [0_u8, 1, 2])
+        );
+    }
+
+    #[test]
+    fn typed_parameters_encode_parse_oids_formats_nulls_and_result_format() {
+        let params = [
+            Parameter::typed_null(TypeOid::INT4),
+            7_i32.into_parameter(),
+            Parameter::text("hello"),
+        ];
+        let request =
+            extended_statement_request("SELECT $1, $2, $3", ¶ms, ValueFormat::Binary).unwrap();
+        let messages = frontend_messages(request.as_bytes());
+        assert_eq!(
+            messages.iter().map(|(tag, _)| *tag).collect::>(),
+            vec![b'P', b'B', b'D', b'E', b'S']
+        );
+
+        let mut parse = messages[0].1;
+        assert_eq!(read_cstring(&mut parse, "statement").unwrap(), "");
+        assert_eq!(
+            read_cstring(&mut parse, "SQL").unwrap(),
+            "SELECT $1, $2, $3"
+        );
+        assert_eq!(read_i16(&mut parse, "OID count").unwrap(), 3);
+        assert_eq!(read_u32(&mut parse, "OID").unwrap(), TypeOid::INT4.get());
+        assert_eq!(read_u32(&mut parse, "OID").unwrap(), TypeOid::INT4.get());
+        assert_eq!(read_u32(&mut parse, "OID").unwrap(), 0);
+        assert!(parse.is_empty());
+
+        let mut bind = messages[1].1;
+        assert_eq!(read_cstring(&mut bind, "portal").unwrap(), "");
+        assert_eq!(read_cstring(&mut bind, "statement").unwrap(), "");
+        assert_eq!(read_i16(&mut bind, "format count").unwrap(), 3);
+        assert_eq!(read_i16(&mut bind, "format").unwrap(), 0);
+        assert_eq!(read_i16(&mut bind, "format").unwrap(), 1);
+        assert_eq!(read_i16(&mut bind, "format").unwrap(), 0);
+        assert_eq!(read_i16(&mut bind, "value count").unwrap(), 3);
+        assert_eq!(read_i32(&mut bind, "null length").unwrap(), -1);
+        assert_eq!(read_i32(&mut bind, "int length").unwrap(), 4);
+        assert_eq!(take(&mut bind, 4, "int").unwrap(), &7_i32.to_be_bytes());
+        assert_eq!(read_i32(&mut bind, "text length").unwrap(), 5);
+        assert_eq!(take(&mut bind, 5, "text").unwrap(), b"hello");
+        assert_eq!(read_i16(&mut bind, "result format count").unwrap(), 1);
+        assert_eq!(read_i16(&mut bind, "result format").unwrap(), 1);
+        assert!(bind.is_empty());
+    }
+
+    #[test]
+    fn explicit_oid_zero_is_describe_only() {
+        let parameter = Parameter::typed_text(TypeOid::new(0), "infer me");
+        assert_other_error_contains(
+            extended_statement_request(
+                "SELECT $1",
+                std::slice::from_ref(¶meter),
+                ValueFormat::Text,
+            ),
+            "explicitly declares PostgreSQL type OID 0",
+        );
+
+        let request = describe_statement_request("SELECT $1", &[parameter])
+            .expect("describe permits OID 0 as PostgreSQL inference");
+        let messages = frontend_messages(request.as_bytes());
+        let mut parse = messages[0].1;
+        assert_eq!(read_cstring(&mut parse, "statement").unwrap(), "");
+        assert_eq!(read_cstring(&mut parse, "SQL").unwrap(), "SELECT $1");
+        assert_eq!(read_i16(&mut parse, "OID count").unwrap(), 1);
+        assert_eq!(read_u32(&mut parse, "OID").unwrap(), 0);
+    }
+
+    #[test]
+    fn structured_sql_preflight_matches_shared_corpus() {
+        let source = crate::test_fixtures::text("protocol/structured-sql-cases.json");
+        let fixture: serde_json::Value =
+            serde_json::from_str(&source).expect("structured SQL fixture is valid JSON");
+        assert_eq!(fixture["schemaVersion"], 2);
+        for case in fixture["cases"].as_array().expect("fixture cases") {
+            let name = case["name"].as_str().expect("case name");
+            let sql = case["sql"].as_str().expect("case SQL");
+            let expected = case["containsTopLevelCopy"]
+                .as_bool()
+                .expect("COPY expectation");
+            assert_eq!(reject_copy_statements(sql).is_err(), expected, "{name}");
+            let expected = case["containsTransactionChain"]
+                .as_bool()
+                .expect("transaction-chain expectation");
+            assert_eq!(reject_transaction_chain(sql).is_err(), expected, "{name}");
+        }
+    }
+
+    #[test]
+    fn managed_transaction_wire_classifier_uses_command_tags_and_final_readiness() {
+        fn response(tags: &[&str], ready: u8) -> ProtocolResponse {
+            let mut bytes = Vec::new();
+            for tag in tags {
+                push_command_complete(&mut bytes, tag);
+            }
+            push_backend_message(&mut bytes, b'Z', &[ready]);
+            ProtocolResponse::new(bytes)
+        }
+
+        for tag in [
+            "BEGIN",
+            "START TRANSACTION",
+            "COMMIT",
+            "PREPARE TRANSACTION",
+            "COMMIT PREPARED",
+            "ROLLBACK PREPARED",
+        ] {
+            assert!(
+                validate_managed_transaction_response(&response(&[tag], b'T')).is_err(),
+                "{tag} changes transaction ownership"
+            );
+        }
+        assert!(validate_managed_transaction_response(&response(&["ROLLBACK"], b'I')).is_err());
+        assert!(
+            validate_managed_transaction_response(&response(&["COMMIT", "BEGIN"], b'T')).is_err()
+        );
+        for tags in [
+            &["ROLLBACK"][..],
+            &["SAVEPOINT"][..],
+            &["RELEASE"][..],
+            &["SET"][..],
+            &["PREPARE"][..],
+            &["CREATE FUNCTION"][..],
+            &["CALL"][..],
+            &["DO"][..],
+        ] {
+            validate_managed_transaction_response(&response(tags, b'T'))
+                .expect("ordinary or savepoint-preserving command remains managed");
+        }
+
+        let mut malformed = Vec::new();
+        push_backend_message(&mut malformed, b'C', b"COMMIT");
+        push_backend_message(&mut malformed, b'Z', b"T");
+        assert!(validate_managed_transaction_response(&ProtocolResponse::new(malformed)).is_err());
+    }
+
+    #[test]
+    fn describe_allows_copy_because_it_does_not_execute() {
+        describe_statement_request("COPY public.items TO STDOUT", &[])
+            .expect("Parse + Describe + Sync cannot enter COPY mode");
+    }
+
+    #[test]
+    fn rejects_nul_in_extended_query_sql() {
+        let params = [Parameter::null()];
+        assert_other_error_contains(
+            extended_statement_request("SELECT '\0'", ¶ms, ValueFormat::Text),
+            "extended query SQL must not contain NUL bytes",
+        );
+    }
+
+    #[test]
+    fn rejects_too_many_extended_query_parameters() {
+        let params = vec![Parameter::null(); i16::MAX as usize + 1];
+
+        assert_other_error_contains(
+            extended_statement_request("SELECT 1", ¶ms, ValueFormat::Text),
+            &format!(
+                "extended query supports at most {} parameters, got {}",
+                i16::MAX,
+                i16::MAX as usize + 1,
+            ),
+        );
+    }
+
+    fn frontend_message_tags(mut bytes: &[u8]) -> Vec {
+        let mut tags = Vec::new();
+        while bytes.len() >= 5 {
+            let tag = bytes[0];
+            let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
+            if len < 4 {
+                break;
+            }
+            let total = 1 + len as usize;
+            if bytes.len() < total {
+                break;
+            }
+            tags.push(tag);
+            bytes = &bytes[total..];
+        }
+        tags
+    }
+
+    fn frontend_messages(mut bytes: &[u8]) -> Vec<(u8, &[u8])> {
+        let mut messages = Vec::new();
+        while !bytes.is_empty() {
+            assert!(bytes.len() >= 5, "complete frontend message header");
+            let tag = bytes[0];
+            let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
+            assert!(len >= 4, "valid frontend message length");
+            let total = 1 + len as usize;
+            assert!(bytes.len() >= total, "complete frontend message body");
+            messages.push((tag, &bytes[5..total]));
+            bytes = &bytes[total..];
+        }
+        messages
+    }
+
+    fn push_backend_message(bytes: &mut Vec, tag: u8, body: &[u8]) {
+        bytes.push(tag);
+        bytes.extend_from_slice(&((body.len() + 4) as i32).to_be_bytes());
+        bytes.extend_from_slice(body);
+    }
+
+    fn push_command_complete(bytes: &mut Vec, tag: &str) {
+        let mut body = Vec::new();
+        body.extend_from_slice(tag.as_bytes());
+        body.push(0);
+        push_backend_message(bytes, b'C', &body);
+    }
+
+    fn push_error_response(bytes: &mut Vec, severity: &str, sqlstate: &str, message: &str) {
+        let mut body = Vec::new();
+        body.push(b'S');
+        body.extend_from_slice(severity.as_bytes());
+        body.push(0);
+        body.push(b'C');
+        body.extend_from_slice(sqlstate.as_bytes());
+        body.push(0);
+        body.push(b'M');
+        body.extend_from_slice(message.as_bytes());
+        body.push(0);
+        body.push(0);
+        push_backend_message(bytes, b'E', &body);
+    }
+
+    fn push_notice_response(bytes: &mut Vec, severity: &str, message: &str) {
+        let mut body = Vec::new();
+        body.push(b'S');
+        body.extend_from_slice(severity.as_bytes());
+        body.push(0);
+        body.push(b'M');
+        body.extend_from_slice(message.as_bytes());
+        body.push(0);
+        body.push(0);
+        push_backend_message(bytes, b'N', &body);
+    }
+
+    fn push_ready_for_query(bytes: &mut Vec) {
+        push_backend_message(bytes, b'Z', b"I");
+    }
+}
diff --git a/src/sdks/rust/src/reply.rs b/src/sdks/rust/sdk/src/reply.rs
similarity index 100%
rename from src/sdks/rust/src/reply.rs
rename to src/sdks/rust/sdk/src/reply.rs
diff --git a/src/sdks/rust/sdk/src/server.rs b/src/sdks/rust/sdk/src/server.rs
new file mode 100644
index 000000000..bac9e7bce
--- /dev/null
+++ b/src/sdks/rust/sdk/src/server.rs
@@ -0,0 +1,981 @@
+use std::ffi::OsString;
+use std::fs;
+use std::net::{SocketAddr, TcpListener};
+#[cfg(unix)]
+use std::os::unix::fs::PermissionsExt;
+use std::path::{Path, PathBuf};
+use std::process::{Child, Command, Stdio};
+use std::thread;
+use std::time::{Duration, Instant};
+#[cfg(unix)]
+use std::time::{SystemTime, UNIX_EPOCH};
+
+use crate::child_process::reap_child_process;
+#[cfg(unix)]
+use crate::config::server_unix_socket_directory_str;
+use crate::config::{EngineMode, NativeServerConfig, OpenConfig, ServerListen};
+use crate::engine::{EngineSession, NativeRuntime};
+use crate::error::{Error, Result};
+use crate::extension::{Extension, extension_runtime_environment};
+use crate::liboliphaunt::{PreparedNativeRoot, configure_native_tool_env};
+use crate::pgwire::{PostgresEndpoint, PostgresWireClient};
+use crate::protocol::{ProtocolRequest, ProtocolResponse};
+
+const SERVER_HOST: &str = "127.0.0.1";
+#[cfg(unix)]
+const ENV_SERVER_SDK_TRANSPORT: &str = "OLIPHAUNT_SERVER_SDK_TRANSPORT";
+const STARTUP_TIMEOUT: Duration = Duration::from_secs(20);
+const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
+const CONNECT_ATTEMPT_TIMEOUT: Duration = Duration::from_millis(250);
+const AUTO_PORT_START_ATTEMPTS: usize = 16;
+
+/// Native PostgreSQL server runtime.
+///
+/// Server mode starts and owns a real local PostgreSQL-compatible server
+/// process. It is the mode to use for independent client connections, external
+/// PostgreSQL clients, pools, and ORMs.
+#[derive(Debug, Clone, Default)]
+pub(crate) struct NativeServerRuntime {
+    executable: Option,
+    listen: ServerListen,
+}
+
+impl NativeServerRuntime {
+    /// Create a server runtime from builder/server configuration.
+    pub fn from_config(config: &NativeServerConfig) -> Self {
+        Self {
+            executable: config.executable.clone(),
+            listen: config.listen.clone(),
+        }
+    }
+}
+
+impl NativeRuntime for NativeServerRuntime {
+    fn open(&self, config: OpenConfig) -> Result> {
+        debug_assert_eq!(config.mode, EngineMode::Server);
+        config.validate()?;
+        let extensions = config.resolved_extensions()?;
+        let explicit_executable = self
+            .executable
+            .clone()
+            .or_else(|| config.server.executable.clone());
+        if let Some(executable) = explicit_executable.as_ref()
+            && !executable.is_file()
+        {
+            return Err(Error::InvalidConfig(format!(
+                "native server executable must be an existing file: {}",
+                executable.display()
+            )));
+        }
+        let root = PreparedNativeRoot::prepare_for_server(&config.native_config(), &extensions)?;
+        let executable = explicit_executable.unwrap_or_else(|| root.tool_path("postgres"));
+        let listen = self.listen.clone();
+        let fixed_port = match &listen {
+            ServerListen::Tcp { port } => *port,
+            #[cfg(unix)]
+            ServerListen::Unix { port, .. } => Some(*port),
+        };
+        let attempts = if fixed_port.is_some() {
+            1
+        } else {
+            AUTO_PORT_START_ATTEMPTS
+        };
+        let mut last_error = None;
+        for attempt in 0..attempts {
+            let port = match fixed_port {
+                Some(port) => port,
+                None => pick_port()?,
+            };
+            let (process_listen, sdk_endpoint, connection_string, mut owned_socket_dir) =
+                prepare_server_listen(&listen, &config, port)?;
+            let mut child =
+                match start_postgres(&root, &executable, &config, &extensions, &process_listen) {
+                    Ok(child) => child,
+                    Err(error) => {
+                        let mut cleanup_failures = Vec::new();
+                        remove_owned_socket_dir(&mut owned_socket_dir, &mut cleanup_failures);
+                        return Err(failed_start_error(error, cleanup_failures));
+                    }
+                };
+            match wait_for_server(sdk_endpoint, &mut child, &config) {
+                Ok(()) => {
+                    return Ok(Box::new(NativeServerSession {
+                        root: Some(root),
+                        child: Some(child),
+                        connection_string,
+                        owned_socket_dir,
+                        retain_root_on_drop: false,
+                        closed: false,
+                    }));
+                }
+                Err(error) => {
+                    let (reaped, cleanup_failures) =
+                        cleanup_failed_start(&mut child, &mut owned_socket_dir);
+                    if !reaped {
+                        // The process may still be using PGDATA and its socket.
+                        // Retain resources with ownership-bearing destructors
+                        // rather than unlock PGDATA beneath a live backend.
+                        // Dropping the socket PathBuf does not delete it.
+                        std::mem::forget(child);
+                        std::mem::forget(root);
+                        return Err(failed_start_error(error, cleanup_failures));
+                    }
+                    if !cleanup_failures.is_empty() {
+                        return Err(failed_start_error(error, cleanup_failures));
+                    }
+                    let retry_auto_port = fixed_port.is_none()
+                        && attempt + 1 < attempts
+                        && tcp_port_is_occupied(port);
+                    if retry_auto_port {
+                        last_error = Some(error);
+                    } else {
+                        return Err(error);
+                    }
+                }
+            }
+        }
+        Err(last_error.unwrap_or_else(|| {
+            Error::Engine(format!(
+                "native server failed to allocate a free localhost port after {attempts} attempts"
+            ))
+        }))
+    }
+}
+
+struct NativeServerSession {
+    root: Option,
+    child: Option,
+    connection_string: String,
+    owned_socket_dir: Option,
+    retain_root_on_drop: bool,
+    closed: bool,
+}
+
+impl EngineSession for NativeServerSession {
+    fn connection_string(&self) -> Option {
+        Some(self.connection_string.clone())
+    }
+
+    fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
+        Err(Error::Engine(
+            "native server lifecycle handles do not expose an SDK query connection; connect an ordinary PostgreSQL client to connection_string()"
+                .to_owned(),
+        ))
+    }
+
+    fn close(&mut self) -> Result<()> {
+        self.close_server()
+    }
+}
+
+impl NativeServerSession {
+    fn close_server(&mut self) -> Result<()> {
+        let first_attempt = !self.closed;
+        self.closed = true;
+        let mut cleanup_failures = Vec::new();
+        if first_attempt {
+            let root = self
+                .root
+                .as_ref()
+                .expect("native server session retains its prepared root");
+            let pg_ctl = root.tool_path("pg_ctl");
+            if pg_ctl.is_file() {
+                let mut command = Command::new(&pg_ctl);
+                configure_native_tool_env(&mut command, &root.runtime_dir);
+                let stop = command
+                    .arg("-D")
+                    .arg(&root.pgdata)
+                    .arg("-m")
+                    .arg("fast")
+                    .arg("-w")
+                    .arg("stop")
+                    .stdout(Stdio::null())
+                    .stderr(Stdio::null())
+                    .spawn();
+                match stop {
+                    Ok(mut child) => {
+                        let outcome = reap_child_process(
+                            &mut child,
+                            SHUTDOWN_TIMEOUT,
+                            SHUTDOWN_TIMEOUT,
+                            "pg_ctl stop",
+                        );
+                        cleanup_failures.extend(outcome.failures);
+                        if outcome.reaped {
+                            if outcome.exit_success == Some(false) {
+                                cleanup_failures
+                                    .push("pg_ctl stop exited unsuccessfully".to_owned());
+                            }
+                        } else {
+                            // No enclosing owner can safely retry an unconfirmed
+                            // pg_ctl child after this terminal close attempt.
+                            self.retain_root_on_drop = true;
+                            std::mem::forget(child);
+                        }
+                    }
+                    Err(err) => cleanup_failures.push(format!("run pg_ctl stop: {err}")),
+                }
+            } else {
+                cleanup_failures.push(format!(
+                    "native server shutdown requires pg_ctl at {}",
+                    pg_ctl.display()
+                ));
+            }
+        }
+
+        if let Some(child) = self.child.as_mut() {
+            let outcome = reap_child_process(
+                child,
+                SHUTDOWN_TIMEOUT,
+                SHUTDOWN_TIMEOUT,
+                "native server process",
+            );
+            cleanup_failures.extend(outcome.failures);
+            if outcome.reaped {
+                self.child = None;
+            }
+        }
+
+        if self.child.is_none()
+            && let Some(socket_dir) = self.owned_socket_dir.as_ref()
+        {
+            match fs::remove_dir_all(socket_dir) {
+                Ok(()) => self.owned_socket_dir = None,
+                Err(error) => cleanup_failures.push(format!(
+                    "remove native server socket directory {}: {error}",
+                    socket_dir.display()
+                )),
+            }
+        }
+        if !cleanup_failures.is_empty() {
+            return Err(Error::Engine(format!(
+                "native server cleanup failed: {}",
+                cleanup_failures.join("; ")
+            )));
+        }
+        Ok(())
+    }
+}
+
+impl Drop for NativeServerSession {
+    fn drop(&mut self) {
+        let close_failed = self.close_server().is_err();
+        let retain_root = self.retain_root_on_drop || self.child.is_some();
+        if close_failed {
+            // Drop is the last package-internal cleanup opportunity. Preserve
+            // every unresolved exact owner process-lifetime; in particular,
+            // never let PreparedNativeRoot unlock or delete PGDATA beneath an
+            // unconfirmed PostgreSQL/pg_ctl process.
+            if let Some(child) = self.child.take() {
+                std::mem::forget(child);
+            }
+        }
+        if retain_root && let Some(root) = self.root.take() {
+            std::mem::forget(root);
+        }
+    }
+}
+
+fn pick_port() -> Result {
+    let listener = TcpListener::bind((SERVER_HOST, 0))
+        .map_err(|err| Error::Engine(format!("allocate native server port: {err}")))?;
+    listener
+        .local_addr()
+        .map(|addr| addr.port())
+        .map_err(|err| Error::Engine(format!("read native server port: {err}")))
+}
+
+fn start_postgres(
+    root: &PreparedNativeRoot,
+    executable: &Path,
+    config: &OpenConfig,
+    extensions: &[Extension],
+    listen: &PostgresProcessListen,
+) -> Result {
+    if !executable.is_file() {
+        return Err(Error::Engine(format!(
+            "native server executable is missing at {}",
+            executable.display()
+        )));
+    }
+    let mut command = Command::new(executable);
+    command.env("PGDATA", &root.pgdata);
+    configure_native_runtime_env(&mut command, &root.runtime_dir, extensions);
+    command
+        .args(postgres_startup_args(
+            &root.pgdata,
+            config,
+            extensions,
+            listen,
+        )?)
+        .stdout(Stdio::null())
+        .stderr(Stdio::inherit());
+    command
+        .spawn()
+        .map_err(|err| Error::Engine(format!("start native server postgres: {err}")))
+}
+
+fn configure_native_runtime_env(
+    command: &mut Command,
+    runtime_dir: &Path,
+    extensions: &[Extension],
+) {
+    configure_native_tool_env(command, runtime_dir);
+    configure_icu_data_env(command, runtime_dir);
+    configure_extension_runtime_env(command, runtime_dir, extensions);
+}
+
+fn configure_icu_data_env(command: &mut Command, runtime_dir: &Path) {
+    command.env_remove("ICU_DATA");
+    let icu_data = runtime_dir.join("share/icu");
+    if icu_data.is_dir() {
+        command.env("ICU_DATA", icu_data);
+    }
+}
+
+fn configure_extension_runtime_env(
+    command: &mut Command,
+    runtime_dir: &Path,
+    extensions: &[Extension],
+) {
+    for extension in extensions {
+        for entry in extension_runtime_environment(*extension) {
+            let value = runtime_dir.join(entry.relative_path);
+            if value.join(entry.required_file).is_file() {
+                command.env(entry.name, value);
+            }
+        }
+    }
+}
+
+fn postgres_startup_args(
+    pgdata: &Path,
+    config: &OpenConfig,
+    extensions: &[Extension],
+    listen: &PostgresProcessListen,
+) -> Result> {
+    let (host, port, socket_dir) = match listen {
+        PostgresProcessListen::Tcp {
+            port,
+            private_socket_dir,
+        } => (SERVER_HOST, *port, private_socket_dir.as_deref()),
+        #[cfg(unix)]
+        PostgresProcessListen::Unix { directory, port } => ("", *port, Some(directory.as_path())),
+    };
+    let mut args = vec![
+        OsString::from("-D"),
+        pgdata.as_os_str().to_os_string(),
+        OsString::from("-h"),
+        OsString::from(host),
+        OsString::from("-p"),
+        OsString::from(port.to_string()),
+        OsString::from("-c"),
+        OsString::from("logging_collector=off"),
+        OsString::from("-c"),
+        OsString::from(if host.is_empty() {
+            "listen_addresses="
+        } else {
+            "listen_addresses=127.0.0.1"
+        }),
+    ];
+    #[cfg(unix)]
+    {
+        args.push(OsString::from("-c"));
+        let socket_dir = socket_dir.ok_or_else(|| {
+            Error::Engine("native server socket directory was not allocated".to_owned())
+        })?;
+        args.push(postgres_unix_socket_assignment(socket_dir)?);
+    }
+    #[cfg(not(unix))]
+    {
+        let _ = socket_dir;
+        args.push(OsString::from("-c"));
+        args.push(OsString::from("unix_socket_directories="));
+    }
+
+    for assignment in config.postgres_startup_assignments(extensions) {
+        args.push(OsString::from("-c"));
+        args.push(OsString::from(assignment));
+    }
+    Ok(args)
+}
+
+fn wait_for_server(
+    endpoint: PostgresEndpoint,
+    child: &mut Child,
+    config: &OpenConfig,
+) -> Result<()> {
+    let deadline = Instant::now() + STARTUP_TIMEOUT;
+    let mut last_error = None;
+    while Instant::now() < deadline {
+        if let Some(status) = child
+            .try_wait()
+            .map_err(|err| Error::Engine(format!("poll native server startup: {err}")))?
+        {
+            return Err(Error::Engine(format!(
+                "native server exited before accepting connections: {status}; PostgreSQL diagnostics were written to the parent process stderr"
+            )));
+        }
+        match PostgresWireClient::connect_endpoint(
+            endpoint.clone(),
+            &config.username,
+            &config.database,
+            CONNECT_ATTEMPT_TIMEOUT,
+            STARTUP_TIMEOUT,
+        ) {
+            Ok(mut connection) => {
+                connection.terminate()?;
+                return Ok(());
+            }
+            Err(err) => last_error = Some(err),
+        }
+        thread::sleep(Duration::from_millis(50));
+    }
+    Err(last_error.unwrap_or_else(|| {
+        Error::Engine(format!(
+            "native server did not accept SDK connections on {:?} within {:?}",
+            endpoint, STARTUP_TIMEOUT
+        ))
+    }))
+}
+
+fn tcp_connection_string(config: &OpenConfig, port: u16) -> String {
+    format!(
+        "postgresql://{}@{}:{}/{}?sslmode=disable",
+        percent_encode_connection_component(&config.username),
+        SERVER_HOST,
+        port,
+        percent_encode_connection_component(&config.database)
+    )
+}
+
+#[cfg(unix)]
+fn postgres_unix_socket_assignment(directory: &Path) -> Result {
+    let directory = server_unix_socket_directory_str(directory)?;
+    let mut assignment =
+        String::with_capacity(directory.len() + "unix_socket_directories=\"\"".len());
+    assignment.push_str("unix_socket_directories=\"");
+    for character in directory.chars() {
+        if character == '"' {
+            assignment.push('"');
+        }
+        assignment.push(character);
+    }
+    assignment.push('"');
+    Ok(assignment.into())
+}
+
+#[cfg(unix)]
+fn unix_connection_string(config: &OpenConfig, directory: &Path, port: u16) -> Result {
+    let directory = server_unix_socket_directory_str(directory)?;
+    Ok(format!(
+        "postgresql:///{database}?host={host}&port={port}&user={user}&sslmode=disable",
+        database = percent_encode_connection_component(&config.database),
+        host = percent_encode_connection_component(directory),
+        user = percent_encode_connection_component(&config.username),
+    ))
+}
+
+fn percent_encode_connection_component(value: &str) -> String {
+    let mut encoded = String::with_capacity(value.len());
+    for byte in value.bytes() {
+        if byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'.' | b'_' | b'~') {
+            encoded.push(byte as char);
+        } else {
+            encoded.push('%');
+            encoded.push(nibble_hex(byte >> 4));
+            encoded.push(nibble_hex(byte & 0x0f));
+        }
+    }
+    encoded
+}
+
+fn nibble_hex(value: u8) -> char {
+    match value {
+        0..=9 => (b'0' + value) as char,
+        10..=15 => (b'A' + value - 10) as char,
+        _ => unreachable!("hex nibble is out of range"),
+    }
+}
+
+fn server_sdk_endpoint(addr: SocketAddr, port: u16, socket_dir: Option<&Path>) -> PostgresEndpoint {
+    #[cfg(unix)]
+    {
+        if std::env::var(ENV_SERVER_SDK_TRANSPORT)
+            .map(|value| value.eq_ignore_ascii_case("tcp"))
+            .unwrap_or(false)
+        {
+            return PostgresEndpoint::Tcp(addr);
+        }
+        let socket_dir =
+            socket_dir.expect("Unix native server socket directory is allocated before endpoint");
+        PostgresEndpoint::Unix(socket_dir.join(format!(".s.PGSQL.{port}")))
+    }
+    #[cfg(not(unix))]
+    {
+        let _ = port;
+        let _ = socket_dir;
+        PostgresEndpoint::Tcp(addr)
+    }
+}
+
+#[derive(Debug)]
+enum PostgresProcessListen {
+    Tcp {
+        port: u16,
+        private_socket_dir: Option,
+    },
+    #[cfg(unix)]
+    Unix { directory: PathBuf, port: u16 },
+}
+
+fn prepare_server_listen(
+    listen: &ServerListen,
+    config: &OpenConfig,
+    resolved_port: u16,
+) -> Result<(
+    PostgresProcessListen,
+    PostgresEndpoint,
+    String,
+    Option,
+)> {
+    match listen {
+        ServerListen::Tcp { .. } => {
+            let addr = SocketAddr::from(([127, 0, 0, 1], resolved_port));
+            let socket_dir = create_server_socket_dir(resolved_port)?;
+            let endpoint = server_sdk_endpoint(addr, resolved_port, socket_dir.as_deref());
+            Ok((
+                PostgresProcessListen::Tcp {
+                    port: resolved_port,
+                    private_socket_dir: socket_dir.clone(),
+                },
+                endpoint,
+                tcp_connection_string(config, resolved_port),
+                socket_dir,
+            ))
+        }
+        #[cfg(unix)]
+        ServerListen::Unix { directory, port } => {
+            let directory = if directory.is_absolute() {
+                directory.clone()
+            } else {
+                std::env::current_dir()
+                    .map_err(|error| {
+                        Error::Engine(format!(
+                            "resolve current directory for native server Unix socket: {error}"
+                        ))
+                    })?
+                    .join(directory)
+            };
+            let connection_string = unix_connection_string(config, &directory, *port)?;
+            prepare_public_socket_directory(&directory, *port)?;
+            let socket = directory.join(format!(".s.PGSQL.{port}"));
+            Ok((
+                PostgresProcessListen::Unix {
+                    directory: directory.clone(),
+                    port: *port,
+                },
+                PostgresEndpoint::Unix(socket),
+                connection_string,
+                None,
+            ))
+        }
+    }
+}
+
+#[cfg(unix)]
+fn prepare_public_socket_directory(directory: &Path, port: u16) -> Result<()> {
+    let socket = directory.join(format!(".s.PGSQL.{port}"));
+    if socket.as_os_str().len() >= 100 {
+        return Err(Error::InvalidConfig(format!(
+            "native server Unix socket path is too long: {}",
+            socket.display()
+        )));
+    }
+    if directory.exists() {
+        let metadata = fs::symlink_metadata(directory).map_err(|err| {
+            Error::Engine(format!(
+                "inspect native server Unix socket directory {}: {err}",
+                directory.display()
+            ))
+        })?;
+        if !metadata.is_dir() || metadata.file_type().is_symlink() {
+            return Err(Error::InvalidConfig(format!(
+                "native server Unix socket directory must be a real directory: {}",
+                directory.display()
+            )));
+        }
+    } else {
+        fs::create_dir_all(directory).map_err(|err| {
+            Error::Engine(format!(
+                "create native server Unix socket directory {}: {err}",
+                directory.display()
+            ))
+        })?;
+        fs::set_permissions(directory, fs::Permissions::from_mode(0o700)).map_err(|err| {
+            Error::Engine(format!(
+                "set native server Unix socket directory permissions {}: {err}",
+                directory.display()
+            ))
+        })?;
+    }
+    ensure_public_socket_path_available(&socket)?;
+    let mut lock = socket.as_os_str().to_os_string();
+    lock.push(".lock");
+    ensure_public_socket_path_available(Path::new(&lock))?;
+    Ok(())
+}
+
+#[cfg(unix)]
+fn ensure_public_socket_path_available(path: &Path) -> Result<()> {
+    match fs::symlink_metadata(path) {
+        Ok(_) => Err(Error::InvalidConfig(format!(
+            "native server refuses to replace existing Unix endpoint {}; remove it explicitly if it is stale",
+            path.display()
+        ))),
+        Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
+        Err(error) => Err(Error::Engine(format!(
+            "inspect native server Unix endpoint {}: {error}",
+            path.display()
+        ))),
+    }
+}
+
+#[cfg(unix)]
+fn create_server_socket_dir(port: u16) -> Result> {
+    let base = Path::new("/tmp");
+    let pid = std::process::id();
+    let nanos = SystemTime::now()
+        .duration_since(UNIX_EPOCH)
+        .map_err(|err| Error::Engine(format!("system clock before epoch: {err}")))?
+        .as_nanos();
+    for attempt in 0..100_u32 {
+        let socket_dir = base.join(format!("lpo-s-{pid}-{port}-{nanos}-{attempt}"));
+        match fs::create_dir(&socket_dir) {
+            Ok(()) => {
+                fs::set_permissions(&socket_dir, fs::Permissions::from_mode(0o700)).map_err(
+                    |err| {
+                        Error::Engine(format!(
+                            "set native server socket dir permissions {}: {err}",
+                            socket_dir.display()
+                        ))
+                    },
+                )?;
+                return Ok(Some(socket_dir));
+            }
+            Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => continue,
+            Err(err) => {
+                return Err(Error::Engine(format!(
+                    "create native server socket dir {}: {err}",
+                    socket_dir.display()
+                )));
+            }
+        }
+    }
+    Err(Error::Engine(
+        "failed to allocate a unique native server socket directory".to_owned(),
+    ))
+}
+
+#[cfg(not(unix))]
+fn create_server_socket_dir(_port: u16) -> Result> {
+    Ok(None)
+}
+
+fn cleanup_failed_start(
+    child: &mut Child,
+    owned_socket_dir: &mut Option,
+) -> (bool, Vec) {
+    let outcome = reap_child_process(
+        child,
+        Duration::ZERO,
+        SHUTDOWN_TIMEOUT,
+        "failed native server startup",
+    );
+    let mut failures = outcome.failures;
+    if outcome.reaped {
+        remove_owned_socket_dir(owned_socket_dir, &mut failures);
+    }
+    (outcome.reaped, failures)
+}
+
+fn remove_owned_socket_dir(socket_dir: &mut Option, failures: &mut Vec) {
+    if let Some(path) = socket_dir.as_ref() {
+        match fs::remove_dir_all(path) {
+            Ok(()) => *socket_dir = None,
+            Err(error) => failures.push(format!(
+                "remove failed native server startup socket directory {}: {error}",
+                path.display()
+            )),
+        }
+    }
+}
+
+fn failed_start_error(error: Error, cleanup_failures: Vec) -> Error {
+    if cleanup_failures.is_empty() {
+        return error;
+    }
+    Error::Engine(format!(
+        "{error}; native server failed-start cleanup failed: {}",
+        cleanup_failures.join("; ")
+    ))
+}
+
+fn tcp_port_is_occupied(port: u16) -> bool {
+    TcpListener::bind((SERVER_HOST, port))
+        .is_err_and(|error| error.kind() == std::io::ErrorKind::AddrInUse)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn missing_explicit_server_executable_is_rejected_before_persistent_root_mutation() {
+        let test_root = std::env::temp_dir().join(format!(
+            "oliphaunt-native-server-executable-preflight-{}-{}",
+            std::process::id(),
+            std::time::SystemTime::now()
+                .duration_since(std::time::UNIX_EPOCH)
+                .expect("system clock should be after epoch")
+                .as_nanos()
+        ));
+        let _cleanup = RuntimeDirCleanup(test_root.clone());
+        std::fs::create_dir_all(&test_root).expect("create server preflight test root");
+        let storage = test_root.join("database");
+        let missing_executable = test_root.join("missing-postgres");
+        let mut config = OpenConfig::direct(storage.clone());
+        config.mode = EngineMode::Server;
+        config.server.executable = Some(missing_executable.clone());
+        let runtime = NativeServerRuntime::from_config(&config.server);
+
+        let error = match runtime.open(config) {
+            Ok(_) => panic!("missing explicit server executable unexpectedly started"),
+            Err(error) => error,
+        };
+
+        assert!(error.to_string().contains("must be an existing file"));
+        assert!(!missing_executable.exists());
+        assert!(
+            !storage.exists(),
+            "deterministic executable validation must run before PGDATA preparation"
+        );
+    }
+
+    #[test]
+    fn auto_port_retry_only_classifies_a_current_loopback_owner() {
+        let listener = TcpListener::bind((SERVER_HOST, 0)).expect("bind loopback fixture");
+        let port = listener.local_addr().expect("read fixture address").port();
+        assert!(tcp_port_is_occupied(port));
+        drop(listener);
+        assert!(!tcp_port_is_occupied(port));
+    }
+
+    #[test]
+    fn server_startup_args_include_required_preload_libraries_before_spawn() {
+        let mut config = OpenConfig::direct("target/test-roots/native-server-preload");
+        config.mode = EngineMode::Server;
+        config.startup_gucs = vec![crate::config::PostgresStartupGuc::new(
+            "shared_preload_libraries",
+            "auto_explain, pg_textsearch",
+        )];
+        let args = postgres_startup_args(
+            Path::new("/tmp/oliphaunt-preload/pgdata"),
+            &config,
+            &[Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH],
+            &PostgresProcessListen::Tcp {
+                port: 15432,
+                private_socket_dir: Some(PathBuf::from("/tmp/oliphaunt-preload-socket")),
+            },
+        )
+        .unwrap();
+        let args = args
+            .iter()
+            .map(|arg| arg.to_string_lossy().into_owned())
+            .collect::>();
+
+        assert_startup_config_arg(&args, "shared_preload_libraries=auto_explain,pg_textsearch");
+        assert_eq!(
+            args.iter()
+                .filter(|arg| arg.starts_with("shared_preload_libraries="))
+                .count(),
+            1,
+            "caller and extension preload libraries must be merged once in server startup args"
+        );
+    }
+
+    #[test]
+    fn extension_runtime_env_is_set_only_when_required_file_is_materialized() {
+        let runtime_dir = std::env::temp_dir().join(format!(
+            "oliphaunt-extension-runtime-env-{}-{}",
+            std::process::id(),
+            std::time::SystemTime::now()
+                .duration_since(std::time::UNIX_EPOCH)
+                .expect("system clock should be after epoch")
+                .as_nanos()
+        ));
+        let _cleanup = RuntimeDirCleanup(runtime_dir.clone());
+        let mut missing = Command::new("postgres");
+        configure_extension_runtime_env(&mut missing, &runtime_dir, &[Extension::POSTGIS]);
+        assert_eq!(
+            missing
+                .get_envs()
+                .find(|(key, _)| *key == std::ffi::OsStr::new("PROJ_DATA")),
+            None
+        );
+
+        let proj_data = runtime_dir.join("share/postgresql/proj");
+        std::fs::create_dir_all(&proj_data).expect("create proj data dir");
+        std::fs::write(proj_data.join("proj.db"), b"fixture").expect("write proj.db");
+
+        let mut present = Command::new("postgres");
+        configure_extension_runtime_env(&mut present, &runtime_dir, &[Extension::POSTGIS]);
+        assert_eq!(
+            present
+                .get_envs()
+                .find(|(key, _)| *key == std::ffi::OsStr::new("PROJ_DATA"))
+                .and_then(|(_, value)| value)
+                .map(PathBuf::from),
+            Some(proj_data)
+        );
+
+        let mut unselected = Command::new("postgres");
+        configure_extension_runtime_env(&mut unselected, &runtime_dir, &[]);
+        assert_eq!(
+            unselected
+                .get_envs()
+                .find(|(key, _)| *key == std::ffi::OsStr::new("PROJ_DATA")),
+            None
+        );
+    }
+
+    #[test]
+    fn native_runtime_env_sets_icu_data_when_materialized() {
+        let runtime_dir = std::env::temp_dir().join(format!(
+            "oliphaunt-icu-runtime-env-{}-{}",
+            std::process::id(),
+            std::time::SystemTime::now()
+                .duration_since(std::time::UNIX_EPOCH)
+                .expect("system clock should be after epoch")
+                .as_nanos()
+        ));
+        let _cleanup = RuntimeDirCleanup(runtime_dir.clone());
+
+        let mut missing = Command::new("postgres");
+        for key in [
+            "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY",
+            "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY",
+            "OLIPHAUNT_INTERNAL_ICU_READY",
+            "ICU_DATA",
+        ] {
+            missing.env(key, "ambient");
+        }
+        configure_native_runtime_env(&mut missing, &runtime_dir, &[]);
+        assert_eq!(
+            missing
+                .get_envs()
+                .find(|(key, _)| *key == std::ffi::OsStr::new("ICU_DATA"))
+                .and_then(|(_, value)| value),
+            None
+        );
+        for key in [
+            "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY",
+            "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY",
+            "OLIPHAUNT_INTERNAL_ICU_READY",
+        ] {
+            assert_eq!(
+                missing
+                    .get_envs()
+                    .find(|(candidate, _)| *candidate == std::ffi::OsStr::new(key))
+                    .and_then(|(_, value)| value),
+                None
+            );
+        }
+
+        let icu_data = runtime_dir.join("share/icu");
+        std::fs::create_dir_all(&icu_data).expect("create ICU data dir");
+        let mut present = Command::new("postgres");
+        configure_native_runtime_env(&mut present, &runtime_dir, &[]);
+        assert_eq!(
+            present
+                .get_envs()
+                .find(|(key, _)| *key == std::ffi::OsStr::new("ICU_DATA"))
+                .and_then(|(_, value)| value)
+                .map(PathBuf::from),
+            Some(icu_data)
+        );
+    }
+
+    struct RuntimeDirCleanup(PathBuf);
+
+    impl Drop for RuntimeDirCleanup {
+        fn drop(&mut self) {
+            let _ = std::fs::remove_dir_all(&self.0);
+        }
+    }
+
+    #[test]
+    fn server_connection_string_uses_configured_identity() {
+        let mut config = OpenConfig::direct("target/test-roots/native-server-identity");
+        config.mode = EngineMode::Server;
+        config.username = "app user".to_owned();
+        config.database = "app/db".to_owned();
+
+        assert_eq!(
+            tcp_connection_string(&config, 15432),
+            "postgresql://app%20user@127.0.0.1:15432/app%2Fdb?sslmode=disable"
+        );
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_connection_string_uses_postgresql_socket_directory_and_port() {
+        let mut config = OpenConfig::direct("target/test-roots/native-server-unix-uri");
+        config.mode = EngineMode::Server;
+        config.username = "app user".to_owned();
+        config.database = "app/db".to_owned();
+
+        assert_eq!(
+            unix_connection_string(&config, Path::new("/tmp/app sockets"), 15432).unwrap(),
+            "postgresql:///app%2Fdb?host=%2Ftmp%2Fapp%20sockets&port=15432&user=app%20user&sslmode=disable"
+        );
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn unix_socket_directory_is_one_quoted_postgres_guc_list_item() {
+        let mut config = OpenConfig::direct("target/test-roots/native-server-unix-guc-list");
+        config.mode = EngineMode::Server;
+        let directory = PathBuf::from("/tmp/ application,\"primary\" ");
+        let args = postgres_startup_args(
+            Path::new("/tmp/pgdata"),
+            &config,
+            &[],
+            &PostgresProcessListen::Unix {
+                directory,
+                port: 15432,
+            },
+        )
+        .expect("a quoted PostgreSQL list item accepts path punctuation");
+        let args = args
+            .iter()
+            .map(|arg| arg.to_string_lossy().into_owned())
+            .collect::>();
+
+        assert_startup_config_arg(
+            &args,
+            "unix_socket_directories=\"/tmp/ application,\"\"primary\"\" \"",
+        );
+    }
+
+    fn assert_startup_config_arg(args: &[String], expected: &str) {
+        let Some(index) = args.iter().position(|arg| arg == expected) else {
+            panic!("missing server startup argument {expected:?} in {args:?}");
+        };
+        assert_eq!(
+            args.get(index.saturating_sub(1)).map(String::as_str),
+            Some("-c"),
+            "server startup argument {expected:?} must be passed through postgres -c"
+        );
+    }
+}
diff --git a/src/sdks/rust/src/session.rs b/src/sdks/rust/sdk/src/session.rs
similarity index 100%
rename from src/sdks/rust/src/session.rs
rename to src/sdks/rust/sdk/src/session.rs
diff --git a/src/sdks/rust/sdk/src/storage.rs b/src/sdks/rust/sdk/src/storage.rs
new file mode 100644
index 000000000..e8546af15
--- /dev/null
+++ b/src/sdks/rust/sdk/src/storage.rs
@@ -0,0 +1,2 @@
+pub use liboliphaunt_native_bindings::DatabaseStorage;
+pub(crate) use liboliphaunt_native_bindings::storage::path_contains_nul;
diff --git a/src/sdks/rust/sdk/src/test_fixtures.rs b/src/sdks/rust/sdk/src/test_fixtures.rs
new file mode 100644
index 000000000..8c8054ffa
--- /dev/null
+++ b/src/sdks/rust/sdk/src/test_fixtures.rs
@@ -0,0 +1,21 @@
+use std::fs;
+use std::path::{Path, PathBuf};
+
+pub(crate) fn root() -> PathBuf {
+    let package_root = Path::new(env!("CARGO_MANIFEST_DIR"));
+    let packaged = package_root.join("testdata");
+    if packaged.is_dir() {
+        return packaged;
+    }
+    package_root
+        .ancestors()
+        .map(|ancestor| ancestor.join("test-fixtures"))
+        .find(|candidate| candidate.is_dir())
+        .expect("shared test fixtures are missing from the checkout or package")
+}
+
+pub(crate) fn text(relative: &str) -> String {
+    let path = root().join(relative);
+    fs::read_to_string(&path)
+        .unwrap_or_else(|error| panic!("read test fixture {}: {error}", path.display()))
+}
diff --git a/src/sdks/rust/sdk/tests/build_resources.rs b/src/sdks/rust/sdk/tests/build_resources.rs
new file mode 100644
index 000000000..5615852c6
--- /dev/null
+++ b/src/sdks/rust/sdk/tests/build_resources.rs
@@ -0,0 +1,31 @@
+#[test]
+fn registered_resources_supply_the_native_library() {
+    if std::env::var_os("LIBOLIPHAUNT_PATH").is_some() {
+        return;
+    }
+    let root =
+        std::env::temp_dir().join(format!("oliphaunt-build-resources-{}", std::process::id()));
+    let _ = std::fs::remove_dir_all(&root);
+    let library = root
+        .join("native-runtime/liboliphaunt-native")
+        .join(if cfg!(windows) { "bin" } else { "lib" })
+        .join(if cfg!(windows) {
+            "oliphaunt.dll"
+        } else if cfg!(target_os = "macos") {
+            "liboliphaunt.dylib"
+        } else {
+            "liboliphaunt.so"
+        });
+    std::fs::create_dir_all(library.parent().unwrap()).unwrap();
+    std::fs::write(&library, b"invalid native library").unwrap();
+    oliphaunt::register_build_resources_dir(&root).unwrap();
+    let error = match oliphaunt::Oliphaunt::open() {
+        Ok(_) => panic!("invalid native library unexpectedly loaded"),
+        Err(error) => error,
+    };
+    assert!(
+        error.to_string().contains(library.to_str().unwrap()),
+        "{error}"
+    );
+    std::fs::remove_dir_all(root).unwrap();
+}
diff --git a/src/sdks/rust/tests/native_extensions.rs b/src/sdks/rust/sdk/tests/native_extensions.rs
similarity index 90%
rename from src/sdks/rust/tests/native_extensions.rs
rename to src/sdks/rust/sdk/tests/native_extensions.rs
index a92f10420..fba094efc 100644
--- a/src/sdks/rust/tests/native_extensions.rs
+++ b/src/sdks/rust/sdk/tests/native_extensions.rs
@@ -14,6 +14,7 @@ use oliphaunt::{
 };
 
 mod support;
+use support::first_data_row_text_values;
 
 type Result = std::result::Result>;
 
@@ -56,15 +57,7 @@ fn native_release_proof_catalog_and_smoke_recipes_match() {
         "native proof manifest must remain sorted by SQL name"
     );
 
-    let package_root = Path::new(env!("CARGO_MANIFEST_DIR"));
-    let recipe_directory = [
-        package_root.join("../../shared/fixtures/extensions"),
-        package_root.join("../../src/shared/fixtures/extensions"),
-        package_root.join("testdata/extensions"),
-    ]
-    .into_iter()
-    .find(|candidate| candidate.is_dir())
-    .expect("canonical extension smoke recipe directory is missing");
+    let recipe_directory = support::fixtures::root().join("extensions");
     let recipes = fs::read_dir(recipe_directory)
         .expect("read canonical extension smoke recipes")
         .filter_map(|entry| {
@@ -354,8 +347,7 @@ fn run_direct_extension_child_install_backup(
     install_or_load_extension(&db, TestMode::Direct, extension)?;
     assert_repeated_create_extension_error_recovers(&db, TestMode::Direct, extension)?;
     assert_extension_visible(&db, TestMode::Direct, extension)?;
-    run_extension_functional_smoke(&db, TestMode::Direct, extension)?;
-    assert_extension_root_artifacts(root, TestMode::Direct, extension);
+    run_extension_functional_smoke(&db, TestMode::Direct, extension, false)?;
     let archive = block_on(db.backup())?;
     fs::write(backup_path, &archive).expect("failed to write direct extension backup artifact");
     block_on(db.close())
@@ -370,8 +362,7 @@ fn run_direct_extension_child_assert_existing(extension: Extension, root: &Path)
             .open(),
     )?);
     assert_extension_visible(&db, TestMode::Direct, extension)?;
-    run_extension_functional_smoke(&db, TestMode::Direct, extension)?;
-    assert_extension_root_artifacts(root, TestMode::Direct, extension);
+    run_extension_functional_smoke(&db, TestMode::Direct, extension, true)?;
     block_on(db.close())
 }
 
@@ -403,8 +394,7 @@ fn run_extension_recovery_smoke(
     install_or_load_extension(&db, mode, extension)?;
     assert_repeated_create_extension_error_recovers(&db, mode, extension)?;
     assert_extension_visible(&db, mode, extension)?;
-    run_extension_functional_smoke(&db, mode, extension)?;
-    assert_extension_root_artifacts(root, mode, extension);
+    run_extension_functional_smoke(&db, mode, extension, false)?;
     let archive = if mode == TestMode::Server {
         None
     } else {
@@ -414,8 +404,7 @@ fn run_extension_recovery_smoke(
 
     let reopened = block_on(open_extension_database(mode, broker, extension, root))?;
     assert_extension_visible(&reopened, mode, extension)?;
-    run_extension_functional_smoke(&reopened, mode, extension)?;
-    assert_extension_root_artifacts(root, mode, extension);
+    run_extension_functional_smoke(&reopened, mode, extension, true)?;
     block_on(reopened.close())?;
 
     let Some(archive) = archive else {
@@ -429,8 +418,7 @@ fn run_extension_recovery_smoke(
         restored_root,
     ))?;
     assert_extension_visible(&restored, mode, extension)?;
-    run_extension_functional_smoke(&restored, mode, extension)?;
-    assert_extension_root_artifacts(restored_root, mode, extension);
+    run_extension_functional_smoke(&restored, mode, extension, true)?;
     block_on(restored.close())
 }
 
@@ -641,9 +629,17 @@ fn run_extension_functional_smoke(
     db: &TestDatabase,
     mode: TestMode,
     extension: Extension,
+    existing: bool,
 ) -> Result<()> {
     let recipe = extension_smoke_recipe(extension.sql_name());
-    for statement in extension_smoke_statements(&recipe) {
+    let sql = if existing {
+        recipe
+            .split_once("-- oliphaunt-verify")
+            .map_or(recipe.as_str(), |(_, sql)| sql)
+    } else {
+        &recipe
+    };
+    for statement in extension_smoke_statements(sql) {
         exec_extension_sql(db, mode, extension, "functional smoke", statement)?;
     }
     Ok(())
@@ -700,8 +696,6 @@ fn assert_success_response(
     Ok(())
 }
 
-fn assert_extension_root_artifacts(_root: &Path, _mode: TestMode, _extension: Extension) {}
-
 fn native_runtime_env_is_unavailable() -> bool {
     std::env::var_os("LIBOLIPHAUNT_PATH").is_none()
 }
@@ -736,63 +730,6 @@ fn raw_message_tags(mut bytes: &[u8]) -> Vec {
     tags
 }
 
-fn first_data_row_text_values(mut bytes: &[u8]) -> Vec {
-    while bytes.len() >= 5 {
-        let tag = bytes[0];
-        let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
-        if len < 4 {
-            break;
-        }
-        let total = 1 + len as usize;
-        if bytes.len() < total {
-            break;
-        }
-        if tag == b'D' {
-            return parse_data_row_text_values(&bytes[5..total]);
-        }
-        bytes = &bytes[total..];
-    }
-    Vec::new()
-}
-
-fn parse_data_row_text_values(payload: &[u8]) -> Vec {
-    if payload.len() < 2 {
-        return Vec::new();
-    }
-    let columns = i16::from_be_bytes([payload[0], payload[1]]);
-    if columns < 0 {
-        return Vec::new();
-    }
-    let mut offset = 2;
-    let mut values = Vec::with_capacity(columns as usize);
-    for _ in 0..columns {
-        if payload.len().saturating_sub(offset) < 4 {
-            return Vec::new();
-        }
-        let len = i32::from_be_bytes([
-            payload[offset],
-            payload[offset + 1],
-            payload[offset + 2],
-            payload[offset + 3],
-        ]);
-        offset += 4;
-        if len == -1 {
-            values.push("NULL".to_owned());
-            continue;
-        }
-        if len < 0 {
-            return Vec::new();
-        }
-        let len = len as usize;
-        if payload.len().saturating_sub(offset) < len {
-            return Vec::new();
-        }
-        values.push(String::from_utf8_lossy(&payload[offset..offset + len]).into_owned());
-        offset += len;
-    }
-    values
-}
-
 fn mode_label(mode: TestMode) -> &'static str {
     match mode {
         TestMode::Direct => "direct",
diff --git a/src/sdks/rust/tests/native_smoke.rs b/src/sdks/rust/sdk/tests/native_smoke.rs
similarity index 91%
rename from src/sdks/rust/tests/native_smoke.rs
rename to src/sdks/rust/sdk/tests/native_smoke.rs
index 17fc8df30..d2feee679 100644
--- a/src/sdks/rust/tests/native_smoke.rs
+++ b/src/sdks/rust/sdk/tests/native_smoke.rs
@@ -17,6 +17,48 @@ const DIRECT_CHILD_ACTION: &str = "OLIPHAUNT_NATIVE_SMOKE_DIRECT_CHILD";
 const DIRECT_CHILD_ROOT: &str = "OLIPHAUNT_NATIVE_SMOKE_DIRECT_ROOT";
 const DIRECT_CHILD_BACKUP: &str = "OLIPHAUNT_NATIVE_SMOKE_DIRECT_BACKUP";
 
+#[test]
+#[ignore = "requires built broker/runtime and explicit standard seed carrier"]
+fn broker_initializes_explicit_cargo_seed_and_reopens_without_seed() {
+    let seed = PathBuf::from(
+        std::env::var_os("OLIPHAUNT_TEST_STANDARD_SEED")
+            .expect("OLIPHAUNT_TEST_STANDARD_SEED is required"),
+    );
+    let broker =
+        PathBuf::from(std::env::var_os("OLIPHAUNT_BROKER").expect("OLIPHAUNT_BROKER is required"));
+    let root = unique_root("explicit-broker-seed");
+    let result = std::panic::catch_unwind(|| {
+        let mut database = DirectOliphaunt::builder()
+            .broker()
+            .broker_executable(&broker)
+            .storage(DatabaseStorage::Directory(root.clone()))
+            .seed(oliphaunt::NativeClusterSeed::new(
+                std::fs::read(seed.join("seed.tar.zst")).unwrap(),
+                std::fs::read(seed.join("manifest.json")).unwrap(),
+            ))
+            .open()
+            .unwrap();
+        database.exec("CREATE TABLE selected_seed_probe(value integer); INSERT INTO selected_seed_probe VALUES (42)").unwrap();
+        database.close().unwrap();
+        let mut reopened = DirectOliphaunt::builder()
+            .broker()
+            .broker_executable(&broker)
+            .storage(DatabaseStorage::Directory(root.clone()))
+            .seed(oliphaunt::NativeClusterSeed::new(vec![0], b"invalid"))
+            .open()
+            .unwrap();
+        let result = reopened
+            .query("SELECT value::text AS value FROM selected_seed_probe")
+            .unwrap();
+        assert_eq!(result.get_text(0, "value").unwrap(), Some("42"));
+        reopened.close().unwrap();
+    });
+    let _ = std::fs::remove_dir_all(&root);
+    if let Err(panic) = result {
+        std::panic::resume_unwind(panic);
+    }
+}
+
 #[test]
 fn server_supports_external_psql_and_pg_basebackup_when_available() {
     if std::env::var_os("LIBOLIPHAUNT_PATH").is_none() {
diff --git a/src/sdks/rust/tests/native_sql_regression.rs b/src/sdks/rust/sdk/tests/native_sql_regression.rs
similarity index 100%
rename from src/sdks/rust/tests/native_sql_regression.rs
rename to src/sdks/rust/sdk/tests/native_sql_regression.rs
diff --git a/src/sdks/rust/sdk/tests/public_api.rs b/src/sdks/rust/sdk/tests/public_api.rs
new file mode 100644
index 000000000..8a4a5c6a0
--- /dev/null
+++ b/src/sdks/rust/sdk/tests/public_api.rs
@@ -0,0 +1,418 @@
+use oliphaunt::{
+    AsyncOliphaunt, AsyncOliphauntBuilder, AsyncOliphauntServer, AsyncOliphauntServerBuilder,
+    AsyncSql, AsyncTransaction, CancelHandle, DatabaseStorage, DecodeError, Error, ErrorKind,
+    ExecResult, Extension, FromSql, IntoParameter, Oliphaunt, OliphauntBuilder, OliphauntServer,
+    OliphauntServerBuilder, Parameter, PostgresError, PostgresNotice, QueryFormat,
+    RawStreamCallbackOutput, RawStreamError, RawStreamResult, Sql, StatementDescription,
+    Transaction, TransactionError, TransactionResult, TypeOid, ValueFormat, ValueRef,
+};
+
+#[test]
+fn build_resources_macro_is_callable_from_an_application() {
+    if option_env!("OLIPHAUNT_RESOURCES_DIR").is_none() {
+        assert_eq!(
+            oliphaunt::register_build_resources!().unwrap_err().kind(),
+            ErrorKind::InvalidConfiguration,
+        );
+    }
+}
+
+#[derive(Debug)]
+enum ApplicationError {
+    Database(Error),
+    Abort,
+}
+
+impl From for ApplicationError {
+    fn from(error: Error) -> Self {
+        Self::Database(error)
+    }
+}
+
+impl std::fmt::Display for ApplicationError {
+    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::Database(error) => error.fmt(formatter),
+            Self::Abort => formatter.write_str("application aborted the transaction"),
+        }
+    }
+}
+
+impl std::error::Error for ApplicationError {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            Self::Database(error) => Some(error),
+            Self::Abort => None,
+        }
+    }
+}
+
+#[derive(Debug)]
+struct ParserError;
+
+impl std::fmt::Display for ParserError {
+    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        formatter.write_str("parser stopped the stream")
+    }
+}
+
+impl std::error::Error for ParserError {}
+
+fn sdk_only_blocking_callbacks(database: &mut Oliphaunt) -> oliphaunt::Result<()> {
+    database.transaction(|transaction| {
+        transaction.execute("SELECT 1")?;
+        Ok(())
+    })?;
+    database.exec_protocol_raw_stream([], |_| ())?;
+    database.exec_protocol_raw_stream([], |_| -> oliphaunt::Result<()> { Ok(()) })?;
+    Ok(())
+}
+
+fn typed_blocking_transaction(database: &mut Oliphaunt) -> TransactionResult<(), ApplicationError> {
+    database.transaction(|transaction| {
+        transaction.execute("SELECT 1")?;
+        Err(ApplicationError::Abort)
+    })
+}
+
+fn typed_blocking_stream(database: &mut Oliphaunt) -> RawStreamResult<(), ParserError> {
+    database.exec_protocol_raw_stream([], |_| Err(ParserError))
+}
+
+async fn sdk_only_async_callbacks(database: &AsyncOliphaunt) -> oliphaunt::Result<()> {
+    database
+        .transaction(async |transaction| {
+            transaction.execute("SELECT 1").await?;
+            Ok(())
+        })
+        .await?;
+    database.exec_protocol_raw_stream([], |_| ()).await?;
+    database
+        .exec_protocol_raw_stream([], |_| -> oliphaunt::Result<()> { Ok(()) })
+        .await?;
+    Ok(())
+}
+
+async fn typed_async_transaction(
+    database: &AsyncOliphaunt,
+) -> TransactionResult<(), ApplicationError> {
+    database
+        .transaction(async |transaction| {
+            transaction.execute("SELECT 1").await?;
+            Err(ApplicationError::Abort)
+        })
+        .await
+}
+
+async fn typed_async_stream(database: &AsyncOliphaunt) -> RawStreamResult<(), ParserError> {
+    database
+        .exec_protocol_raw_stream([], |_| Err(ParserError))
+        .await
+}
+
+struct PublicParameter;
+
+impl IntoParameter for PublicParameter {
+    const TYPE_OID: Option = Some(TypeOid::INT4);
+
+    fn into_parameter(self) -> Parameter {
+        Parameter::typed_binary(TypeOid::INT4, 7_i32.to_be_bytes())
+    }
+}
+
+struct PublicDecoder;
+
+impl<'a> FromSql<'a> for PublicDecoder {
+    fn from_sql(_value: ValueRef<'a>) -> std::result::Result {
+        Ok(Self)
+    }
+}
+
+fn assert_send_future(_: T) {}
+
+macro_rules! assert_not_impl {
+    ($type:ty: $bound:path) => {
+        const _: fn() = || {
+            trait AmbiguousIfImpl {
+                fn marker() {}
+            }
+            struct Invalid;
+            impl AmbiguousIfImpl<()> for T {}
+            impl AmbiguousIfImpl for T {}
+            let _ = <$type as AmbiguousIfImpl<_>>::marker;
+        };
+    };
+}
+
+assert_not_impl!(Oliphaunt: Sync);
+assert_not_impl!(OliphauntServer: Sync);
+assert_not_impl!(AsyncTransaction: Sync);
+
+// OLIPHAUNT_DOCS_SNIPPET rust-quickstart
+
+#[test]
+fn public_api_has_only_the_deliberate_native_vocabulary() {
+    let _: OliphauntBuilder = Oliphaunt::builder()
+        .direct()
+        .storage(DatabaseStorage::TemporaryDirectory)
+        .startup_guc("work_mem", "8MB")
+        .startup_gucs([("application_name", "oliphaunt")])
+        .username("postgres")
+        .database("postgres")
+        .extension(Extension::VECTOR);
+
+    let _: Parameter = "text".into_parameter();
+    let _: QueryFormat = QueryFormat::Text;
+
+    fn assert_error() {}
+    fn assert_clone() {}
+    fn assert_copy() {}
+    fn assert_debug() {}
+    fn assert_eq_type() {}
+    fn assert_hash() {}
+    fn assert_ord() {}
+    fn assert_send() {}
+    fn assert_send_sync() {}
+    fn assert_raw_callback_output() {}
+    assert_send::();
+    assert_send::();
+    assert_clone::();
+    assert_clone::();
+    assert_clone::();
+    assert_clone::();
+    assert_debug::();
+    assert_debug::();
+    assert_debug::();
+    assert_debug::();
+    assert_send_sync::();
+    assert_send_sync::();
+    assert_send_sync::();
+    assert_send_sync::();
+    assert_send_sync::();
+    fn cancellation_surface(handle: &CancelHandle) {
+        let _: CancelHandle = handle.clone();
+        let _: oliphaunt::Result<()> = handle.cancel();
+    }
+    let _: fn(&CancelHandle) = cancellation_surface;
+    assert_send_sync::();
+    assert_send_sync::();
+    assert_send::();
+    assert_send_future(AsyncOliphaunt::builder().open());
+    assert_send_future(AsyncOliphauntServer::builder().start());
+    assert_send_future(AsyncOliphaunt::restore(
+        std::path::PathBuf::from("unused-async-public-api-check"),
+        Vec::::new(),
+    ));
+    assert_error::();
+    assert_clone::();
+    assert_copy::();
+    assert_debug::();
+    assert_eq_type::();
+    assert_send_sync::();
+    assert_copy::();
+    assert_debug::();
+    assert_eq_type::();
+    assert_hash::();
+    assert_ord::();
+    assert_send_sync::();
+    assert_error::();
+    assert_error::>();
+    assert_error::>();
+    assert_raw_callback_output::<()>();
+    assert_raw_callback_output::>();
+
+    fn generic_error_surface(
+        transaction: &TransactionError,
+        stream: &RawStreamError,
+    ) {
+        let _: Option<&ApplicationError> = transaction.callback_error();
+        let _: Option<&Error> = transaction.database_error();
+        let _: Option<&Error> = transaction.rollback_error();
+        let _: Option<&ParserError> = stream.callback_error();
+        let _: Option<&Error> = stream.database_error();
+        let _: Option<&Error> = stream.callback_panic_error();
+    }
+    let _: fn(&TransactionError, &RawStreamError) =
+        generic_error_surface;
+
+    fn flatten_sdk_errors(
+        transaction: TransactionError,
+        stream: RawStreamError,
+        infallible: RawStreamError,
+    ) {
+        let _: Error = transaction.into();
+        let _: Error = stream.into();
+        let _: Error = infallible.into();
+    }
+    let _ = flatten_sdk_errors;
+
+    fn caller_thread_terminals(builder: OliphauntBuilder) {
+        let _: oliphaunt::Result = builder.open();
+        let _: oliphaunt::Result = Oliphaunt::open();
+        let _: oliphaunt::Result = OliphauntServer::builder().start();
+        let _: oliphaunt::Result<()> = Oliphaunt::restore(
+            std::path::PathBuf::from("unused-public-api-check"),
+            Vec::::new(),
+        );
+    }
+    let _: fn(OliphauntBuilder) = caller_thread_terminals;
+
+    fn transaction_rollback_surface(error: &Error) {
+        let _: ErrorKind = error.kind();
+        let _: Error = error.clone();
+        let _: Option<&PostgresError> = error.postgres_error();
+        let _: Option<(&Error, &Error)> = error.transaction_rollback_errors();
+        let _: Option<(&Error, &Error)> = error.transaction_callback_database_errors();
+    }
+    let _: fn(&Error) = transaction_rollback_surface;
+
+    fn postgres_diagnostic_surface(error: &PostgresError, notice: &PostgresNotice) {
+        let _: (&Option, &Option) =
+            (&error.localized_severity, ¬ice.localized_severity);
+        let _: (&Option, &Option) =
+            (&error.nonlocalized_severity, ¬ice.nonlocalized_severity);
+        let _: (&Option, &Option) =
+            (&error.internal_position, ¬ice.internal_position);
+        let _: (&Option, &Option) = (&error.internal_query, ¬ice.internal_query);
+        let _: (&Option, &Option) = (&error.file, ¬ice.file);
+        let _: (&Option, &Option) = (&error.line, ¬ice.line);
+        let _: (&Option, &Option) = (&error.routine, ¬ice.routine);
+    }
+    let _: fn(&PostgresError, &PostgresNotice) = postgres_diagnostic_surface;
+}
+
+#[test]
+fn typed_and_fluent_database_api_is_public() {
+    fn assert_decoder()
+    where
+        for<'a> T: FromSql<'a>,
+    {
+    }
+    assert_decoder::();
+    assert_decoder::();
+    assert_decoder::();
+
+    let parameter = Parameter::null().with_type_oid(TypeOid::UUID);
+    assert_eq!(parameter.type_oid(), Some(TypeOid::UUID));
+    assert_eq!(parameter.format(), ValueFormat::Text);
+    assert_eq!(TypeOid::TIMETZ.get(), 1266);
+    assert_eq!(TypeOid::CHAR_ARRAY.get(), 1002);
+    assert_eq!(TypeOid::NAME_ARRAY.get(), 1003);
+    assert_eq!(TypeOid::XML_ARRAY.get(), 143);
+    assert_eq!(TypeOid::TIMETZ_ARRAY.get(), 1270);
+    let typed_null = IntoParameter::into_parameter(None::);
+    assert_eq!(typed_null.type_oid(), Some(TypeOid::INT8));
+    assert_eq!(
+        IntoParameter::into_parameter(PublicParameter).type_oid(),
+        Some(TypeOid::INT4)
+    );
+
+    fn database_surface(database: &mut Oliphaunt) {
+        let _query = database
+            .sql("SELECT $1::int4")
+            .bind(1_i32)
+            .result_format(ValueFormat::Binary)
+            .query();
+        let _execute = database
+            .sql("UPDATE items SET value = $1")
+            .bind("value")
+            .execute();
+        let _typed_query = database.query_with_params("SELECT $1::int4", [1_i32]);
+        let _typed_execute = database.execute_with_params("SELECT $1::bool", [true]);
+        let _describe_convenience = database.describe("SELECT 1");
+        let _describe = database
+            .sql("SELECT $1::uuid")
+            .bind_parameter(Parameter::typed_null(TypeOid::UUID))
+            .describe();
+        let _exec: oliphaunt::Result = database.exec("SELECT 1; SELECT 2");
+        let _description: oliphaunt::Result =
+            database.sql("SELECT 1").describe();
+        let mut streamed_bytes = 0_usize;
+        let _borrowed_raw_stream = database.exec_protocol_raw_stream([], |chunk| {
+            streamed_bytes += chunk.len();
+        });
+        let _ = streamed_bytes;
+        let _raw_stream = database.exec_protocol_raw_stream([], |_| ());
+        let _cancel = database.cancel();
+        let _cancel_handle = database.cancel_handle();
+        let _closed = database.is_closed();
+        let _transaction = database.transaction(|transaction: &mut Transaction<'_>| {
+            let _closed = transaction.is_closed();
+            let _typed_query = transaction.query_with_params("SELECT $1::int8", [1_i64]);
+            transaction.rollback()?;
+            Ok::<(), Error>(())
+        });
+    }
+    let _: fn(&mut Oliphaunt) = database_surface;
+    let _: fn(&mut Oliphaunt) -> oliphaunt::Result<()> = sdk_only_blocking_callbacks;
+    let _: fn(&mut Oliphaunt) -> TransactionResult<(), ApplicationError> =
+        typed_blocking_transaction;
+    let _: fn(&mut Oliphaunt) -> RawStreamResult<(), ParserError> = typed_blocking_stream;
+
+    fn server_surface(server: &mut OliphauntServer) {
+        let _: &str = server.connection_string();
+        let _: bool = server.is_closed();
+        let _: oliphaunt::Result<()> = server.close();
+    }
+    let _: fn(&mut OliphauntServer) = server_surface;
+
+    fn async_database_surface(database: &AsyncOliphaunt) {
+        let _: AsyncOliphauntBuilder = AsyncOliphaunt::builder();
+        assert_send_future(AsyncOliphaunt::open());
+        assert_send_future(AsyncOliphauntServer::builder().start());
+        let _: AsyncSql<'_, '_> = database.sql("SELECT 1");
+        assert_send_future(database.sql("SELECT $1::int4").bind(1_i32).query());
+        assert_send_future(database.execute_with_params("SELECT $1::bool", [true]));
+        assert_send_future(database.exec("SELECT 1; SELECT 2"));
+        assert_send_future(database.describe("SELECT 1"));
+        assert_send_future(database.exec_protocol_raw([]));
+        assert_send_future(database.exec_protocol_raw_stream([], |_| ()));
+        assert_send_future(database.backup());
+        assert_send_future(database.cancel());
+        assert_send_future(
+            database.transaction(async |transaction: &mut AsyncTransaction| {
+                assert_send_future(transaction.query_with_params("SELECT $1::int8", [1_i64]));
+                assert_send_future(transaction.exec("SELECT 1; SELECT 2"));
+                assert_send_future(transaction.describe("SELECT 1"));
+                transaction.rollback().await?;
+                Ok::<(), Error>(())
+            }),
+        );
+        assert_send_future(database.close());
+        assert_send_future(sdk_only_async_callbacks(database));
+        assert_send_future(typed_async_transaction(database));
+        assert_send_future(typed_async_stream(database));
+    }
+    let _: fn(&AsyncOliphaunt) = async_database_surface;
+
+    fn async_server_surface(server: &AsyncOliphauntServer) {
+        let _: &str = server.connection_string();
+        let _: bool = server.is_closed();
+        assert_send_future(server.close());
+    }
+    let _: fn(&AsyncOliphauntServer) = async_server_surface;
+
+    fn blocking_statement_type<'db, 'q>(
+        database: &'db mut Oliphaunt,
+        sql: &'q str,
+    ) -> Sql<'db, 'q> {
+        database.sql(sql)
+    }
+    let _ = blocking_statement_type;
+}
+
+#[test]
+fn extension_catalog_is_exact_and_sorted() {
+    let names = Extension::ALL
+        .iter()
+        .map(|extension| extension.sql_name())
+        .collect::>();
+    assert!(names.windows(2).all(|pair| pair[0] < pair[1]));
+    assert_eq!(names.len(), 39);
+    for extension in Extension::ALL {
+        assert_eq!(
+            Extension::by_sql_name(extension.sql_name()),
+            Some(*extension)
+        );
+    }
+}
diff --git a/src/sdks/rust/tests/release-consumer/Cargo.toml b/src/sdks/rust/sdk/tests/release-consumer/Cargo.toml
similarity index 100%
rename from src/sdks/rust/tests/release-consumer/Cargo.toml
rename to src/sdks/rust/sdk/tests/release-consumer/Cargo.toml
diff --git a/src/sdks/rust/sdk/tests/release-consumer/src/main.rs b/src/sdks/rust/sdk/tests/release-consumer/src/main.rs
new file mode 100644
index 000000000..9438ecb64
--- /dev/null
+++ b/src/sdks/rust/sdk/tests/release-consumer/src/main.rs
@@ -0,0 +1,290 @@
+use std::error::Error;
+use std::future::Future;
+use std::io;
+use std::net::TcpListener;
+use std::path::{Path, PathBuf};
+use std::process::{Command, Output};
+use std::task::{Context, Poll, Waker};
+use std::thread;
+use std::time::Duration;
+
+use oliphaunt::{AsyncOliphauntServer, DatabaseStorage, IntoParameter, Oliphaunt, ServerListen};
+
+fn main() -> Result<(), Box> {
+    if let Some(resources) = std::env::var_os("OLIPHAUNT_CONSUMER_RESOURCES_DIR") {
+        oliphaunt::register_build_resources_dir(PathBuf::from(resources))?;
+    }
+    let root = std::env::args_os()
+        .nth(1)
+        .map(PathBuf::from)
+        .ok_or_else(|| io::Error::other("usage: oliphaunt-rust-release-consumer DATABASE_ROOT"))?;
+    if let Some(mode) = std::env::args().nth(2) {
+        return exercise_embedded(&root, &mode);
+    }
+    for mode in ["direct", "broker"] {
+        let database_root = root.with_file_name(format!("database-{mode}"));
+        for action in [mode.to_owned(), format!("{mode}-verify")] {
+            command_succeeded(
+                &action,
+                &Command::new(std::env::current_exe()?)
+                    .arg(&database_root)
+                    .arg(&action)
+                    .output()?,
+            )?;
+        }
+    }
+    let backup = root.with_file_name("database-basebackup");
+    let copied_log = root.with_file_name("database-basebackup.log");
+    let psql = packaged_tool("psql")?;
+    let pg_basebackup = packaged_tool("pg_basebackup")?;
+    let pg_ctl = packaged_runtime_tool("pg_ctl")?;
+
+    let database = block_on(
+        AsyncOliphauntServer::builder()
+            .storage(DatabaseStorage::Directory(root.clone()))
+            .listen(ServerListen::tcp())
+            .start(),
+    )?;
+    let exercise_source = (|| -> Result<(), Box> {
+        command_succeeded(
+            "packaged psql seed",
+            &Command::new(&psql)
+                .args([
+                    "--no-psqlrc",
+                    "--no-password",
+                    "--set=ON_ERROR_STOP=1",
+                    "--dbname",
+                    database.connection_string(),
+                    "--command",
+                    "CREATE SEQUENCE packed_backup_seq START 40; \
+                     CREATE TABLE packed_backup_items(\
+                       id bigint PRIMARY KEY DEFAULT nextval('packed_backup_seq'),\
+                       value text NOT NULL, payload bytea NOT NULL, optional_value text NULL\
+                     ); \
+                     CREATE UNIQUE INDEX packed_backup_items_value_idx ON packed_backup_items(value); \
+                     INSERT INTO packed_backup_items(value, payload, optional_value) VALUES\
+                       ('café 🐘', decode('00ff10', 'hex'), NULL),\
+                       ('東京', decode('deadbeef', 'hex'), 'present');",
+                ])
+                .env("PGCONNECT_TIMEOUT", "5")
+                .output()?,
+        )?;
+        command_succeeded(
+            "packaged pg_basebackup",
+            &Command::new(&pg_basebackup)
+                .arg("--dbname")
+                .arg(database.connection_string())
+                .arg("--pgdata")
+                .arg(&backup)
+                .args([
+                    "--format=plain",
+                    "--wal-method=stream",
+                    "--checkpoint=fast",
+                    "--no-password",
+                ])
+                .env("PGCONNECT_TIMEOUT", "5")
+                .output()?,
+        )?;
+        require_file(&backup.join("PG_VERSION"))?;
+        require_file(&backup.join("backup_label"))?;
+        require_file(&backup.join("global/pg_control"))?;
+        Ok(())
+    })();
+    let close_source = block_on(database.close());
+    exercise_source?;
+    close_source?;
+
+    let port_probe = TcpListener::bind(("127.0.0.1", 0))?;
+    let port = port_probe.local_addr()?.port();
+    drop(port_probe);
+    command_succeeded(
+        "packaged pg_ctl start copied PGDATA",
+        &Command::new(&pg_ctl)
+            .arg("--pgdata")
+            .arg(&backup)
+            .arg("--log")
+            .arg(&copied_log)
+            .args(["--wait", "--timeout=60", "start", "--options"])
+            .arg(format!("-c listen_addresses=127.0.0.1 -c port={port}"))
+            .output()?,
+    )?;
+    let mut copied = PgCtlGuard::new(pg_ctl, backup);
+    let copied_uri = format!("postgresql://postgres@127.0.0.1:{port}/postgres?sslmode=disable");
+    let copied_query = Command::new(&psql)
+        .args([
+            "--no-psqlrc",
+            "--no-align",
+            "--tuples-only",
+            "--quiet",
+            "--no-password",
+            "--dbname",
+            &copied_uri,
+            "--command",
+            "SELECT string_agg(value || ':' || encode(payload, 'hex') || ':' || \
+               coalesce(optional_value, 'NULL'), '|' ORDER BY value COLLATE \"C\") \
+             FROM packed_backup_items; \
+             SELECT to_regclass('packed_backup_items_value_idx')::text; \
+             SELECT nextval('packed_backup_seq')::text;",
+        ])
+        .env("PGCONNECT_TIMEOUT", "10")
+        .output()?;
+    command_succeeded("packaged psql copied PGDATA query", &copied_query)?;
+    let rows = String::from_utf8(copied_query.stdout)?
+        .lines()
+        .map(str::trim)
+        .filter(|line| !line.is_empty())
+        .map(str::to_owned)
+        .collect::>();
+    let expected = [
+        "café 🐘:00ff10:NULL|東京:deadbeef:present",
+        "packed_backup_items_value_idx",
+        "42",
+    ];
+    if rows != expected {
+        return Err(io::Error::other(format!(
+            "copied PGDATA query returned {rows:?}, expected {expected:?}"
+        ))
+        .into());
+    }
+    copied.stop()?;
+    println!(
+        "OLIPHAUNT_RUST_RELEASE_CONSUMER_PASS checks=direct,broker,parameters,transaction,backup,restore,external-psql,pg-basebackup,restart,query,close"
+    );
+    Ok(())
+}
+
+fn exercise_embedded(root: &Path, mode: &str) -> Result<(), Box> {
+    let verify = mode.ends_with("-verify");
+    let restored = root.with_extension("restored");
+    if verify {
+        Oliphaunt::restore(&restored, std::fs::read(root.with_extension("backup"))?)?;
+    }
+    let mut builder = Oliphaunt::builder().storage(DatabaseStorage::Directory(if verify {
+        restored
+    } else {
+        root.to_owned()
+    }));
+    if mode.starts_with("broker") {
+        builder = builder.broker();
+    }
+    let mut database = builder.open()?;
+    if !verify {
+        database.execute("CREATE TABLE items(id integer PRIMARY KEY, value text)")?;
+        database.execute_with_params(
+            "INSERT INTO items VALUES ($1, $2)",
+            [1_i32.into_parameter(), "café 🐘".into_parameter()],
+        )?;
+        database.transaction(|transaction| {
+            transaction.execute("INSERT INTO items VALUES (2, '東京')")?;
+            Ok::<(), oliphaunt::Error>(())
+        })?;
+        assert!(database.execute("SELECT 1; SELECT 2").is_err());
+    }
+    let rows = database.query("SELECT value FROM items ORDER BY id")?;
+    assert_eq!(rows.row_count(), Some(2));
+    assert_eq!(rows.get_text(0, "value")?, Some("café 🐘"));
+    assert_eq!(rows.get_text(1, "value")?, Some("東京"));
+    if !verify {
+        std::fs::write(root.with_extension("backup"), database.backup()?)?;
+    }
+    database.close()?;
+    Ok(())
+}
+
+fn packaged_tool(name: &str) -> io::Result {
+    packaged_binary("OLIPHAUNT_TOOLS_DIR", name)
+}
+
+fn packaged_runtime_tool(name: &str) -> io::Result {
+    packaged_binary("OLIPHAUNT_INSTALL_DIR", name)
+}
+
+fn packaged_binary(root_variable: &str, name: &str) -> io::Result {
+    let root = std::env::var_os(root_variable)
+        .map(PathBuf::from)
+        .ok_or_else(|| io::Error::other(format!("{root_variable} is unset")))?;
+    let name = if cfg!(windows) {
+        format!("{name}.exe")
+    } else {
+        name.to_owned()
+    };
+    let path = root.join("bin").join(name);
+    require_file(&path)?;
+    Ok(path)
+}
+
+fn require_file(path: &Path) -> io::Result<()> {
+    if path.is_file() {
+        Ok(())
+    } else {
+        Err(io::Error::other(format!(
+            "required packaged file is missing: {}",
+            path.display()
+        )))
+    }
+}
+
+fn command_succeeded(name: &str, output: &Output) -> io::Result<()> {
+    if output.status.success() {
+        return Ok(());
+    }
+    Err(io::Error::other(format!(
+        "{name} failed with {}\nstdout:\n{}\nstderr:\n{}",
+        output.status,
+        String::from_utf8_lossy(&output.stdout),
+        String::from_utf8_lossy(&output.stderr)
+    )))
+}
+
+struct PgCtlGuard {
+    pg_ctl: PathBuf,
+    pgdata: PathBuf,
+    active: bool,
+}
+
+impl PgCtlGuard {
+    fn new(pg_ctl: PathBuf, pgdata: PathBuf) -> Self {
+        Self {
+            pg_ctl,
+            pgdata,
+            active: true,
+        }
+    }
+
+    fn stop(&mut self) -> io::Result<()> {
+        if !self.active {
+            return Ok(());
+        }
+        let output = Command::new(&self.pg_ctl)
+            .arg("--pgdata")
+            .arg(&self.pgdata)
+            .args(["--wait", "--timeout=60", "stop", "--mode=fast"])
+            .output()?;
+        command_succeeded("packaged pg_ctl stop copied PGDATA", &output)?;
+        self.active = false;
+        Ok(())
+    }
+}
+
+impl Drop for PgCtlGuard {
+    fn drop(&mut self) {
+        if self.active {
+            let _ = Command::new(&self.pg_ctl)
+                .arg("--pgdata")
+                .arg(&self.pgdata)
+                .args(["--wait", "--timeout=60", "stop", "--mode=immediate"])
+                .output();
+        }
+    }
+}
+
+fn block_on(future: F) -> F::Output {
+    let mut context = Context::from_waker(Waker::noop());
+    let mut future = Box::pin(future);
+    loop {
+        match future.as_mut().poll(&mut context) {
+            Poll::Ready(value) => return value,
+            Poll::Pending => thread::park_timeout(Duration::from_millis(1)),
+        }
+    }
+}
diff --git a/src/sdks/rust/sdk/tests/support/mod.rs b/src/sdks/rust/sdk/tests/support/mod.rs
new file mode 100644
index 000000000..0ae2c2ae0
--- /dev/null
+++ b/src/sdks/rust/sdk/tests/support/mod.rs
@@ -0,0 +1,316 @@
+use std::io::{self, Read, Write};
+use std::net::{Shutdown, TcpStream};
+use std::time::Duration;
+
+#[path = "../../src/test_fixtures.rs"]
+#[allow(dead_code)]
+pub(crate) mod fixtures;
+#[allow(unused_imports)]
+pub(crate) use fixtures::text as fixture_text;
+
+/// Execute a raw frontend-protocol request through the public server endpoint.
+///
+/// Native server handles intentionally expose lifecycle and endpoint state only;
+/// integration tests use this tiny external client to exercise the same wire
+/// boundary that PostgreSQL drivers and ORMs use.
+#[allow(dead_code)]
+pub(crate) fn external_raw_query(
+    connection_string: &str,
+    request: impl AsRef<[u8]>,
+) -> io::Result> {
+    ExternalRawSession::connect(connection_string)?.exec_protocol_raw(request)
+}
+
+/// Minimal persistent PostgreSQL session for server-bound integration tests.
+///
+/// A session must be reused when a test relies on connection-local state such
+/// as temporary tables. Opening one TCP connection per statement would not
+/// model an ordinary PostgreSQL client and would discard that state.
+pub(crate) struct ExternalRawSession {
+    stream: Option,
+}
+
+impl ExternalRawSession {
+    pub(crate) fn connect(connection_string: &str) -> io::Result {
+        let (address, user, database) = parse_tcp_connection_string(connection_string)?;
+        let mut stream = TcpStream::connect(&address).map_err(|error| {
+            io::Error::other(format!(
+                "connect external test client to {address}: {error}"
+            ))
+        })?;
+        let timeout = Some(Duration::from_secs(30));
+        stream
+            .set_read_timeout(timeout)
+            .and_then(|()| stream.set_write_timeout(timeout))
+            .map_err(|error| {
+                io::Error::other(format!("configure external test client: {error}"))
+            })?;
+
+        write_startup(&mut stream, &user, &database)?;
+        read_until_ready(&mut stream, false, true)?;
+        Ok(Self {
+            stream: Some(stream),
+        })
+    }
+
+    pub(crate) fn exec_protocol_raw(&mut self, request: impl AsRef<[u8]>) -> io::Result> {
+        let stream = self
+            .stream
+            .as_mut()
+            .ok_or_else(|| io::Error::other("external test client session is already closed"))?;
+        stream
+            .write_all(request.as_ref())
+            .and_then(|()| stream.flush())
+            .map_err(|error| io::Error::other(format!("write external test request: {error}")))?;
+        read_until_ready(stream, true, false)
+    }
+
+    pub(crate) fn close(&mut self) -> io::Result<()> {
+        let Some(mut stream) = self.stream.take() else {
+            return Ok(());
+        };
+        stream
+            .write_all(&[b'X', 0, 0, 0, 4])
+            .and_then(|()| stream.flush())
+            .and_then(|()| stream.shutdown(Shutdown::Both))
+            .map_err(|error| io::Error::other(format!("close external test client: {error}")))
+    }
+}
+
+impl Drop for ExternalRawSession {
+    fn drop(&mut self) {
+        let _ = self.close();
+    }
+}
+
+#[allow(dead_code)]
+pub(crate) fn first_data_row_text_values(mut bytes: &[u8]) -> Vec {
+    while bytes.len() >= 5 {
+        let tag = bytes[0];
+        let length = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
+        if length < 4 {
+            return Vec::new();
+        }
+        let total = 1 + length as usize;
+        if bytes.len() < total {
+            return Vec::new();
+        }
+        if tag == b'D' {
+            return parse_data_row_text_values(&bytes[5..total]);
+        }
+        bytes = &bytes[total..];
+    }
+    Vec::new()
+}
+
+#[allow(dead_code)]
+fn parse_data_row_text_values(payload: &[u8]) -> Vec {
+    if payload.len() < 2 {
+        return Vec::new();
+    }
+    let columns = i16::from_be_bytes([payload[0], payload[1]]);
+    if columns < 0 {
+        return Vec::new();
+    }
+    let mut offset = 2;
+    let mut values = Vec::with_capacity(columns as usize);
+    for _ in 0..columns {
+        if payload.len().saturating_sub(offset) < 4 {
+            return Vec::new();
+        }
+        let length = i32::from_be_bytes([
+            payload[offset],
+            payload[offset + 1],
+            payload[offset + 2],
+            payload[offset + 3],
+        ]);
+        offset += 4;
+        if length == -1 {
+            values.push("NULL".to_owned());
+            continue;
+        }
+        if length < 0 {
+            return Vec::new();
+        }
+        let length = length as usize;
+        if payload.len().saturating_sub(offset) < length {
+            return Vec::new();
+        }
+        values.push(String::from_utf8_lossy(&payload[offset..offset + length]).into_owned());
+        offset += length;
+    }
+    values
+}
+
+fn parse_tcp_connection_string(connection_string: &str) -> io::Result<(String, String, String)> {
+    let target = connection_string
+        .strip_prefix("postgresql://")
+        .ok_or_else(|| io::Error::other("external test connection string is not PostgreSQL TCP"))?;
+    let (user, target) = target
+        .split_once('@')
+        .ok_or_else(|| io::Error::other("external test connection string omitted user"))?;
+    let (address, database) = target
+        .split_once('/')
+        .ok_or_else(|| io::Error::other("external test connection string omitted database"))?;
+    if !address.contains(':') || address.starts_with('/') {
+        return Err(io::Error::other(
+            "external test client requires a TCP server listener",
+        ));
+    }
+    let database = database.split('?').next().unwrap_or(database);
+    Ok((address.to_owned(), user.to_owned(), database.to_owned()))
+}
+
+fn write_startup(stream: &mut TcpStream, user: &str, database: &str) -> io::Result<()> {
+    let mut body = 196_608_i32.to_be_bytes().to_vec();
+    for value in ["user", user, "database", database] {
+        body.extend_from_slice(value.as_bytes());
+        body.push(0);
+    }
+    body.push(0);
+    let length = i32::try_from(body.len() + 4)
+        .map_err(|_| io::Error::other("external test startup packet is too large"))?;
+    stream
+        .write_all(&length.to_be_bytes())
+        .and_then(|()| stream.write_all(&body))
+        .and_then(|()| stream.flush())
+        .map_err(|error| io::Error::other(format!("write external test startup: {error}")))
+}
+
+fn read_until_ready(
+    stream: &mut TcpStream,
+    capture: bool,
+    error_is_fatal: bool,
+) -> io::Result> {
+    let mut response = Vec::new();
+    loop {
+        let mut header = [0_u8; 5];
+        stream.read_exact(&mut header).map_err(|error| {
+            io::Error::other(format!("read external test response header: {error}"))
+        })?;
+        let length = i32::from_be_bytes([header[1], header[2], header[3], header[4]]);
+        if length < 4 {
+            return Err(io::Error::other(format!(
+                "external test server returned invalid frame length {length}"
+            )));
+        }
+        let body_length = usize::try_from(length - 4)
+            .map_err(|_| io::Error::other("external test frame length overflowed"))?;
+        let mut body = vec![0_u8; body_length];
+        stream.read_exact(&mut body).map_err(|error| {
+            io::Error::other(format!("read external test response body: {error}"))
+        })?;
+        if capture {
+            response.extend_from_slice(&header);
+            response.extend_from_slice(&body);
+        }
+        if header[0] == b'E' && error_is_fatal {
+            return Err(io::Error::other(
+                "external test client startup received ErrorResponse",
+            ));
+        }
+        if header[0] == b'Z' {
+            return Ok(response);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::net::TcpListener;
+    use std::thread;
+
+    use super::*;
+
+    #[test]
+    fn external_raw_session_reuses_one_tcp_connection() {
+        let listener = TcpListener::bind(("127.0.0.1", 0)).expect("bind mock PostgreSQL server");
+        let address = listener.local_addr().expect("read mock server address");
+        let server = thread::spawn(move || {
+            let (mut stream, _) = listener.accept().expect("accept external test client");
+            read_startup_packet(&mut stream);
+            write_ready(&mut stream);
+
+            for (expected_sql, error) in [
+                ("CREATE TEMP TABLE proof (id int)", false),
+                ("SELECT broken", true),
+                ("SELECT * FROM proof", false),
+            ] {
+                let request = read_tagged_packet(&mut stream);
+                assert_eq!(request[0], b'Q');
+                assert_eq!(&request[5..request.len() - 1], expected_sql.as_bytes());
+                if error {
+                    write_error_ready(&mut stream);
+                } else {
+                    write_ready(&mut stream);
+                }
+            }
+
+            assert_eq!(read_tagged_packet(&mut stream), [b'X', 0, 0, 0, 4]);
+        });
+
+        let connection_string = format!("postgresql://postgres@{address}/postgres");
+        let mut session =
+            ExternalRawSession::connect(&connection_string).expect("connect external test session");
+        for sql in ["CREATE TEMP TABLE proof (id int)", "SELECT broken"] {
+            let response = session
+                .exec_protocol_raw(raw_query_packet(sql))
+                .expect("execute mock external query");
+            if sql == "SELECT broken" {
+                assert_eq!(response, [b'E', 0, 0, 0, 4, b'Z', 0, 0, 0, 5, b'I']);
+            } else {
+                assert_eq!(response, [b'Z', 0, 0, 0, 5, b'I']);
+            }
+        }
+        let recovered = session
+            .exec_protocol_raw(raw_query_packet("SELECT * FROM proof"))
+            .expect("reuse external session after ErrorResponse");
+        assert_eq!(recovered, [b'Z', 0, 0, 0, 5, b'I']);
+        session.close().expect("close external test session");
+        server.join().expect("join mock PostgreSQL server");
+    }
+
+    fn raw_query_packet(sql: &str) -> Vec {
+        let mut body = sql.as_bytes().to_vec();
+        body.push(0);
+        let mut packet = vec![b'Q'];
+        packet.extend_from_slice(&i32::try_from(body.len() + 4).unwrap().to_be_bytes());
+        packet.extend_from_slice(&body);
+        packet
+    }
+
+    fn read_startup_packet(stream: &mut TcpStream) {
+        let mut length = [0_u8; 4];
+        stream.read_exact(&mut length).expect("read startup length");
+        let body_length = i32::from_be_bytes(length) - 4;
+        assert!(body_length >= 0);
+        let mut body = vec![0_u8; usize::try_from(body_length).unwrap()];
+        stream.read_exact(&mut body).expect("read startup body");
+    }
+
+    fn read_tagged_packet(stream: &mut TcpStream) -> Vec {
+        let mut header = [0_u8; 5];
+        stream.read_exact(&mut header).expect("read packet header");
+        let body_length = i32::from_be_bytes([header[1], header[2], header[3], header[4]]) - 4;
+        assert!(body_length >= 0);
+        let mut packet = header.to_vec();
+        let mut body = vec![0_u8; usize::try_from(body_length).unwrap()];
+        stream.read_exact(&mut body).expect("read packet body");
+        packet.extend_from_slice(&body);
+        packet
+    }
+
+    fn write_ready(stream: &mut TcpStream) {
+        stream
+            .write_all(&[b'Z', 0, 0, 0, 5, b'I'])
+            .and_then(|()| stream.flush())
+            .expect("write ReadyForQuery");
+    }
+
+    fn write_error_ready(stream: &mut TcpStream) {
+        stream
+            .write_all(&[b'E', 0, 0, 0, 4, b'Z', 0, 0, 0, 5, b'I'])
+            .and_then(|()| stream.flush())
+            .expect("write ErrorResponse and ReadyForQuery");
+    }
+}
diff --git a/src/sdks/rust/sdk/tools/artifact-dependencies.mts b/src/sdks/rust/sdk/tools/artifact-dependencies.mts
new file mode 100644
index 000000000..d7a49d63c
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/artifact-dependencies.mts
@@ -0,0 +1,13 @@
+const metadata = await Bun.file(process.env.OLIPHAUNT_CARGO_METADATA).json();
+for (const dependency of metadata.packages[0].dependencies) {
+  if (
+    dependency.target !== null &&
+    (dependency.name.startsWith('liboliphaunt-native-') ||
+      dependency.name.startsWith('oliphaunt-broker-'))
+  ) {
+    const version = dependency.req.match(/^=([0-9A-Za-z.+-]+)$/)?.[1];
+    if (!version)
+      throw new Error(`artifact dependency ${dependency.name} must use an exact version`);
+    console.log(`${dependency.name}\t${version}`);
+  }
+}
diff --git a/src/sdks/rust/sdk/tools/cargo-artifact-patches.mts b/src/sdks/rust/sdk/tools/cargo-artifact-patches.mts
new file mode 100644
index 000000000..cdb7e3c7c
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/cargo-artifact-patches.mts
@@ -0,0 +1,51 @@
+#!/usr/bin/env bun
+import fs from 'node:fs/promises';
+import path from 'node:path';
+
+function fail(message) {
+  console.error(`cargo-artifact-patches.mts: ${message}`);
+  process.exit(2);
+}
+
+function parseArgs(argv) {
+  if (argv.length !== 2) {
+    fail('usage: src/sdks/rust/sdk/tools/cargo-artifact-patches.mts  ');
+  }
+  return {
+    root: path.resolve(argv[0]),
+    manifest: path.isAbsolute(argv[1]) ? argv[1] : path.resolve(argv[0], argv[1]),
+  };
+}
+
+function tomlString(value) {
+  return JSON.stringify(value);
+}
+
+const { root, manifest } = parseArgs(Bun.argv.slice(2));
+let data;
+try {
+  data = JSON.parse(await fs.readFile(manifest, 'utf8'));
+} catch (error) {
+  fail(`could not read Cargo artifact package manifest ${manifest}: ${error.message}`);
+}
+
+if (data === null || typeof data !== 'object' || !Array.isArray(data.packages)) {
+  fail(`${manifest} must contain a packages array`);
+}
+
+for (const [index, artifact] of data.packages.entries()) {
+  if (artifact === null || typeof artifact !== 'object' || Array.isArray(artifact)) {
+    fail(`${manifest} package row ${index} must be an object`);
+  }
+  const { name, manifestPath } = artifact;
+  if (typeof name !== 'string' || name.length === 0) {
+    fail(`${manifest} package row ${index} must declare a non-empty name`);
+  }
+  if (typeof manifestPath !== 'string' || manifestPath.length === 0) {
+    fail(`${manifest} package row ${index} must declare a non-empty manifestPath`);
+  }
+  const artifactManifest = path.isAbsolute(manifestPath)
+    ? manifestPath
+    : path.join(root, manifestPath);
+  console.log(`${name} = { path = ${tomlString(path.dirname(artifactManifest))} }`);
+}
diff --git a/src/sdks/rust/sdk/tools/check-package.mts b/src/sdks/rust/sdk/tools/check-package.mts
new file mode 100644
index 000000000..61cf73141
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/check-package.mts
@@ -0,0 +1,115 @@
+#!/usr/bin/env bun
+import { readdirSync, readFileSync } from 'node:fs';
+import path from 'node:path';
+import { assertPackagedCargoDependencies } from '../../../../../tools/packaging/cargo-dependencies.mts';
+import { packagedCargoManifestText } from '../../../../../tools/packaging/cargo-source-package.mts';
+import {
+  archiveTarNames,
+  cargoCrateManifest,
+  fail,
+  inspectSdkProduct,
+  PREFIX,
+  rejectSdkRuntimePayload,
+  rel,
+  requireCrateMatchesCargoListing,
+} from '../../../../../tools/packaging/release-carrier.mts';
+import { assertReleaseNoticesInArchive } from '../../../../../tools/packaging/release-notices.mts';
+import {
+  compareText,
+  currentProductVersion,
+  ROOT,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import { renderReleaseCargoToml } from './prepare-rust-release-source.mts';
+
+function exactSortedStrings(label, actual, expected) {
+  const actualSorted = [...actual].sort(compareText);
+  const expectedSorted = [...expected].sort(compareText);
+  if (JSON.stringify(actualSorted) !== JSON.stringify(expectedSorted)) {
+    fail(
+      `${label} mismatch: expected=${JSON.stringify(expectedSorted)}, actual=${JSON.stringify(actualSorted)}`,
+    );
+  }
+}
+
+async function validateRustSdkCrate(crate) {
+  const manifest = cargoCrateManifest(crate);
+  const packageConfig = manifest.package;
+  if (packageConfig === null || Array.isArray(packageConfig) || typeof packageConfig !== 'object') {
+    fail(`${rel(crate)} must declare a Cargo package`);
+  }
+  const packageName = packageConfig.name;
+  if (!['oliphaunt', 'oliphaunt-build'].includes(packageName)) {
+    fail(`${rel(crate)} contains unexpected oliphaunt-rust package ${JSON.stringify(packageName)}`);
+  }
+  const sdkVersion = await currentProductVersion('oliphaunt-rust', PREFIX);
+  if (packageConfig.version !== sdkVersion) {
+    fail(`${rel(crate)} package ${packageName} must use oliphaunt-rust version ${sdkVersion}`);
+  }
+  if (packageConfig.license !== 'MIT') {
+    fail(`${rel(crate)} source-only package ${packageName} must declare license MIT`);
+  }
+  try {
+    assertReleaseNoticesInArchive(crate, {
+      profile: 'source-sdk',
+      prefix: `${packageName}-${sdkVersion}`,
+    });
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+  const source = packagedCargoManifestText(
+    readFileSync(
+      path.join(
+        ROOT,
+        packageName === 'oliphaunt'
+          ? 'src/sdks/rust/sdk/Cargo.toml'
+          : 'src/sdks/rust/sdk/crates/oliphaunt-build/Cargo.toml',
+      ),
+      'utf8',
+    ),
+  );
+  const expected = Bun.TOML.parse(
+    packageName === 'oliphaunt' ? renderReleaseCargoToml(source) : source,
+  );
+  assertPackagedCargoDependencies(manifest, expected, rel(crate));
+
+  return packageName;
+}
+
+export async function checkRustPackage(root) {
+  const product = 'oliphaunt-rust';
+  let checked = false;
+
+  const crates = readdirSync(root)
+    .filter((name) => name.endsWith('.crate'))
+    .map((name) => path.join(root, name))
+    .sort(compareText);
+  if (crates.length === 0) {
+    fail(`${product} must stage a Cargo crate under ${rel(root)}`);
+  }
+  const packageNames = [];
+  const cratesByPackage = new Map();
+  for (const crate of crates) {
+    rejectSdkRuntimePayload(product, crate, archiveTarNames(crate));
+    const packageName = await validateRustSdkCrate(crate);
+    packageNames.push(packageName);
+    cratesByPackage.set(packageName, crate);
+    checked = true;
+  }
+  if (crates.length > 0) {
+    exactSortedStrings(`${product} staged Cargo packages`, packageNames, [
+      'oliphaunt',
+      'oliphaunt-build',
+    ]);
+    const version = await currentProductVersion('oliphaunt-rust', PREFIX);
+    requireCrateMatchesCargoListing(
+      cratesByPackage.get('oliphaunt'),
+      path.join(root, 'cargo-package-files.txt'),
+      'oliphaunt',
+      version,
+    );
+  }
+
+  return checked;
+}
+
+if (import.meta.main) await inspectSdkProduct('oliphaunt-rust', checkRustPackage);
diff --git a/src/sdks/rust/sdk/tools/check-release-consumer.sh b/src/sdks/rust/sdk/tools/check-release-consumer.sh
new file mode 100755
index 000000000..303bf9f0f
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/check-release-consumer.sh
@@ -0,0 +1,165 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "check-release-consumer.sh: must run inside the Oliphaunt checkout" >&2
+  exit 1
+}
+cd "$root"
+
+scratch=""
+cleanup() {
+  [ -z "$scratch" ] || rm -rf "$scratch"
+}
+trap cleanup EXIT
+
+fail() {
+  echo "check-release-consumer.sh: $*" >&2
+  exit 1
+}
+
+require_file() {
+  [ -s "$1" ] || fail "missing or empty file: $1"
+}
+
+find_one() {
+  local directory="$1"
+  local pattern="$2"
+  local matches=()
+  while IFS= read -r file; do
+    matches+=("$file")
+  done < <(find "$directory" -type f -name "$pattern" -print)
+  [ "${#matches[@]}" -eq 1 ] ||
+    fail "expected one $pattern under $directory, found ${#matches[@]}"
+  printf '%s\n' "${matches[0]}"
+}
+
+require_linux_x64() {
+  [ "$(uname -s)" = "Linux" ] || fail "release consumer requires Linux"
+  case "$(uname -m)" in
+    x86_64|amd64) ;;
+    *) fail "release consumer requires x64, found $(uname -m)" ;;
+  esac
+}
+
+build_consumer() {
+  local sdk_artifacts="$1"
+  local output="$2"
+  local crate dependency_crate dependency_source product packed_manifest metadata dependency_rows name version stub
+  local manifests=()
+  local dependency_sources=()
+  [ -d "$sdk_artifacts" ] || fail "Rust SDK artifact directory is missing: $sdk_artifacts"
+  crate="$(find_one "$sdk_artifacts" 'oliphaunt-[0-9]*.crate')"
+  scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-rust-release-consumer-build.XXXXXX")"
+
+  mkdir -p "$scratch/unpacked" "$scratch/packed" "$scratch/consumer/src" "$scratch/consumer/.cargo"
+  tar -xzf "$crate" -C "$scratch/unpacked"
+  while IFS= read -r file; do
+    manifests+=("$file")
+  done < <(find "$scratch/unpacked" -mindepth 2 -maxdepth 2 -type f -name Cargo.toml -print)
+  [ "${#manifests[@]}" -eq 1 ] ||
+    fail "packed crate must contain one root Cargo.toml, found ${#manifests[@]}"
+  packed_manifest="${manifests[0]}"
+  mv "$(dirname "$packed_manifest")" "$scratch/packed/oliphaunt"
+  cp src/sdks/rust/sdk/tests/release-consumer/Cargo.toml "$scratch/consumer/Cargo.toml"
+  cp src/sdks/rust/sdk/tests/release-consumer/src/main.rs "$scratch/consumer/src/main.rs"
+  if [ -f "$scratch/packed/oliphaunt/Cargo.lock" ]; then
+    cp "$scratch/packed/oliphaunt/Cargo.lock" "$scratch/consumer/Cargo.lock"
+  else
+    cp Cargo.lock "$scratch/consumer/Cargo.lock"
+  fi
+
+  for product in oliphaunt-query liboliphaunt-native-bindings oliphaunt-broker; do
+    dependency_crate="$(find_one "target/sdk-artifacts/$product" "$product-*.crate")"
+    mkdir -p "$scratch/dependencies/$product"
+    tar -xzf "$dependency_crate" -C "$scratch/dependencies/$product"
+    dependency_source="$(dirname "$(find_one "$scratch/dependencies/$product" Cargo.toml)")"
+    dependency_sources+=("$product" "$dependency_source")
+  done
+
+  metadata="$scratch/metadata.json"
+  dependency_rows="$scratch/artifact-dependencies.tsv"
+  cargo metadata --manifest-path "$scratch/packed/oliphaunt/Cargo.toml" \
+    --format-version 1 --no-deps --offline >"$metadata"
+  OLIPHAUNT_CARGO_METADATA="$metadata" tools/dev/bun.sh src/sdks/rust/sdk/tools/artifact-dependencies.mts | sort -u >"$dependency_rows"
+  for pattern in '^liboliphaunt-native-' '^oliphaunt-broker-'; do
+    rg -q "$pattern" "$dependency_rows" || fail "packed crate is missing artifact dependency $pattern"
+  done
+
+  {
+    printf '[net]\noffline = true\n\n[patch.crates-io]\n'
+    for ((index=0; index<${#dependency_sources[@]}; index+=2)); do
+      printf '"%s" = { path = "%s" }\n' "${dependency_sources[index]}" "${dependency_sources[index+1]}"
+    done
+    while IFS=$'\t' read -r name version; do
+      stub="$scratch/stubs/$name"
+      mkdir -p "$stub/src"
+      printf '[package]\nname = "%s"\nversion = "%s"\nedition = "2024"\npublish = false\n\n[lib]\npath = "src/lib.rs"\n' \
+        "$name" "$version" >"$stub/Cargo.toml"
+      printf '#![forbid(unsafe_code)]\n' >"$stub/src/lib.rs"
+      printf '"%s" = { path = "%s" }\n' "$name" "$stub"
+    done <"$dependency_rows"
+  } >"$scratch/consumer/.cargo/config.toml"
+
+  CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$scratch/target}" \
+    cargo --config "$scratch/consumer/.cargo/config.toml" metadata \
+      --manifest-path "$scratch/consumer/Cargo.toml" --offline --format-version 1 > /dev/null
+  CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$scratch/target}" \
+    cargo --config "$scratch/consumer/.cargo/config.toml" build \
+      --manifest-path "$scratch/consumer/Cargo.toml" --locked --offline --release
+  mkdir -p "$(dirname "$output")"
+  install -m 0755 \
+    "${CARGO_TARGET_DIR:-$scratch/target}/release/oliphaunt-rust-release-consumer" "$output"
+  echo "Built packed-crate Rust release consumer: $output"
+}
+
+run_consumer() {
+  local consumer="$1"
+  local native_assets="$2"
+  local tools_assets="$3"
+  local broker_assets="$4"
+  local runtime_archive tools_archive broker_archive install_dir tools_dir native_dir
+  require_linux_x64
+  require_file "$consumer"
+  [ -x "$consumer" ] || fail "release consumer is not executable: $consumer"
+  [ -d "$native_assets" ] || fail "native asset directory is missing: $native_assets"
+  runtime_archive="$(find_one "$native_assets" 'liboliphaunt-*-linux-x64-gnu.tar.gz')"
+  tools_archive="$(find_one "$tools_assets" 'oliphaunt-tools-*-linux-x64-gnu.tar.gz')"
+  broker_archive="$(find_one "$broker_assets" 'oliphaunt-broker-*-linux-x64-gnu.tar.gz')"
+  scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-rust-release-consumer-run.XXXXXX")"
+
+  native_dir="$scratch/resources/native-runtime/liboliphaunt-native"
+  mkdir -p "$native_dir" "$scratch/tools" "$scratch/broker" "$scratch/runtime-cache"
+  tar -xzf "$runtime_archive" -C "$native_dir"
+  tar -xzf "$tools_archive" -C "$scratch/tools"
+  tar -xzf "$broker_archive" -C "$scratch/broker"
+  install_dir="$native_dir/runtime"
+  tools_dir="$scratch/tools/runtime"
+  for file in "$native_dir/lib/liboliphaunt.so" "$scratch/broker/bin/oliphaunt-broker" "$install_dir/bin/postgres" "$install_dir/bin/initdb" "$install_dir/bin/pg_ctl" \
+    "$tools_dir/bin/pg_basebackup" "$tools_dir/bin/pg_dump" "$tools_dir/bin/psql"; do
+    require_file "$file"
+  done
+
+  env \
+    -u LIBOLIPHAUNT_PATH -u OLIPHAUNT_RESOURCES_DIR \
+    OLIPHAUNT_CONSUMER_RESOURCES_DIR="$scratch/resources" \
+    OLIPHAUNT_EMBEDDED_MODULE_DIR="$native_dir/lib/modules" \
+    OLIPHAUNT_BROKER="$scratch/broker/bin/oliphaunt-broker" \
+    OLIPHAUNT_INSTALL_DIR="$install_dir" \
+    OLIPHAUNT_TOOLS_DIR="$tools_dir" \
+    OLIPHAUNT_RUNTIME_CACHE_DIR="$scratch/runtime-cache" \
+    LD_LIBRARY_PATH="$install_dir/lib:$native_dir/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \
+    "$consumer" "$scratch/database"
+}
+
+case "${1:-}" in
+  build)
+    [ "$#" -eq 3 ] || fail "usage: $0 build SDK_ARTIFACT_DIR OUTPUT"
+    build_consumer "$2" "$3"
+    ;;
+  run)
+    [ "$#" -eq 5 ] || fail "usage: $0 run CONSUMER NATIVE_ASSET_DIR TOOLS_ASSET_DIR BROKER_ASSET_DIR"
+    run_consumer "$2" "$3" "$4" "$5"
+    ;;
+  *) fail "usage: $0 {build SDK_ARTIFACT_DIR OUTPUT|run CONSUMER NATIVE_ASSET_DIR TOOLS_ASSET_DIR BROKER_ASSET_DIR}" ;;
+esac
diff --git a/src/sdks/rust/sdk/tools/package-source.mts b/src/sdks/rust/sdk/tools/package-source.mts
new file mode 100644
index 000000000..6fc809b2c
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/package-source.mts
@@ -0,0 +1,46 @@
+#!/usr/bin/env bun
+import { copyFileSync, cpSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+export const ROOT = path.resolve(import.meta.dirname, '../../../../..');
+
+function copy(source, destination) {
+  mkdirSync(path.dirname(destination), { recursive: true });
+  copyFileSync(source, destination);
+}
+
+export function stageRustPackageSource(outputDir) {
+  const destination = path.resolve(ROOT, outputDir);
+  const relative = path.relative(ROOT, destination);
+  if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
+    throw new Error(`Rust package stage must stay inside the repository: ${outputDir}`);
+  }
+
+  rmSync(destination, { recursive: true, force: true });
+  cpSync(path.join(ROOT, 'src/sdks/rust/sdk'), destination, {
+    recursive: true,
+    filter: (source) => path.basename(source) !== 'target',
+  });
+  rmSync(path.join(destination, 'crates/oliphaunt-build'), { recursive: true, force: true });
+  cpSync(path.join(ROOT, 'src/test-fixtures'), path.join(destination, 'testdata'), {
+    recursive: true,
+    filter: (source) => path.basename(source) !== 'moon.yml',
+  });
+  copy(path.join(ROOT, 'LICENSE'), path.join(destination, 'LICENSE'));
+  copy(path.join(ROOT, 'THIRD_PARTY_NOTICES.md'), path.join(destination, 'THIRD_PARTY_NOTICES.md'));
+
+  const manifest = path.join(destination, 'Cargo.toml');
+  let text = readFileSync(manifest, 'utf8')
+    .replace(/(\{\s*)path\s*=\s*"[^"]+",\s*/gu, '$1')
+    .replace(/,\s*path\s*=\s*"[^"]+"/gu, '')
+    .replace('repository.workspace = true', 'repository = "https://github.com/f0rr0/oliphaunt"')
+    .replace('homepage.workspace = true', 'homepage = "https://oliphaunt.dev"');
+  if (!text.includes('[workspace]')) text = `${text.trimEnd()}\n\n[workspace]\n`;
+  writeFileSync(manifest, text, 'utf8');
+  return manifest;
+}
+
+if (import.meta.main) {
+  const output = process.argv[2] ?? 'target/liboliphaunt-sdk-check/oliphaunt-rust/package-source';
+  console.log(path.relative(ROOT, stageRustPackageSource(output)));
+}
diff --git a/src/sdks/rust/sdk/tools/prepare-rust-release-source.mts b/src/sdks/rust/sdk/tools/prepare-rust-release-source.mts
new file mode 100644
index 000000000..ce52512e4
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/prepare-rust-release-source.mts
@@ -0,0 +1,260 @@
+#!/usr/bin/env bun
+import { cpSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { packagedCargoManifestText } from '../../../../../tools/packaging/cargo-source-package.mts';
+import {
+  assertReleaseNoticesInDirectory,
+  stageReleaseNotices,
+} from '../../../../../tools/packaging/release-notices.mts';
+import {
+  assertSameNativeTargetSet,
+  renderUnsupportedNativeTargetGuard,
+  rustNativeTargetCfg,
+} from '../../../../../tools/packaging/rust-native-targets.mts';
+import {
+  allArtifactTargets,
+  compareText,
+  currentProductVersionSync,
+  ROOT,
+  registryPackageRows,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts';
+import { stageRustPackageSource } from './package-source.mts';
+
+const TOOL = 'prepare-rust-release-source.mts';
+const LIBOLIPHAUNT_NATIVE_PRODUCT = 'liboliphaunt-native';
+const BROKER_PRODUCT = 'oliphaunt-broker';
+const RUST_PRODUCT = 'oliphaunt-rust';
+const DEFAULT_STAGE_DIR = path.join(ROOT, 'target/release/cargo-package-sources/oliphaunt');
+const DEFAULT_BUILD_STAGE_DIR = path.join(
+  ROOT,
+  'target/release/cargo-package-sources/oliphaunt-build',
+);
+const SOURCE_NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' });
+
+function fail(message) {
+  console.error(`${TOOL}: ${message}`);
+  process.exit(2);
+}
+
+function rel(file) {
+  return path.relative(ROOT, file).split(path.sep).join('/');
+}
+
+function liboliphauntCargoPackageName(targetId, packageBase = LIBOLIPHAUNT_NATIVE_PRODUCT) {
+  return `${packageBase}-${targetId}`;
+}
+
+function brokerCargoPackageName(targetId) {
+  return `${BROKER_PRODUCT}-${targetId}`;
+}
+
+function packageSection(text) {
+  const parts = text.split('[package]');
+  if (parts.length < 2) {
+    fail('generated oliphaunt release source is missing [package]');
+  }
+  return parts[1].split('\n[', 1)[0];
+}
+
+function artifactTargets({ product, kind, surface }) {
+  return allArtifactTargets({ product, kind, surface }, TOOL);
+}
+
+function nativeSdkArtifactTargets() {
+  const nativeTargets = artifactTargets({
+    product: LIBOLIPHAUNT_NATIVE_PRODUCT,
+    kind: 'native-runtime',
+    surface: 'rust-native-direct',
+  });
+  const brokerTargets = artifactTargets({
+    product: BROKER_PRODUCT,
+    kind: 'broker-helper',
+    surface: 'rust-broker',
+  });
+  const nativeTargetIds = nativeTargets.map((target) => target.target);
+  assertSameNativeTargetSet(
+    'oliphaunt Rust SDK native runtime/broker',
+    nativeTargetIds,
+    brokerTargets.map((target) => target.target),
+  );
+  return { nativeTargets, brokerTargets };
+}
+
+export function renderRustSdkNativeTargetGuard(nativeTargets) {
+  const targetIds = nativeTargets.map((target) =>
+    typeof target === 'string' ? target : target.target,
+  );
+  return renderUnsupportedNativeTargetGuard({
+    product: 'oliphaunt',
+    nativeTargets: targetIds,
+    nativeCfgs: targetIds.map((target) => rustNativeTargetCfg(target)),
+    guidance: 'use the separately versioned oliphaunt-wasix crate for WASIX environments.',
+  });
+}
+
+export function renderReleaseCargoToml(
+  source,
+  nativeVersion = productCompatibilityVersion(RUST_PRODUCT, LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL),
+  brokerVersion = productCompatibilityVersion(RUST_PRODUCT, BROKER_PRODUCT, TOOL),
+  artifactTargets = nativeSdkArtifactTargets(),
+) {
+  let text = source
+    .replace('repository.workspace = true', 'repository = "https://github.com/f0rr0/oliphaunt"')
+    .replace('homepage.workspace = true', 'homepage = "https://oliphaunt.dev"');
+  if (!text.includes('[workspace]')) {
+    text = `${text.trimEnd()}\n\n[workspace]\n`;
+  }
+
+  const lines = [
+    '',
+    '# Generated for crates.io publishing. Source checkouts keep native runtime',
+    '# and broker artifact crates out of the local dependency graph until those',
+    '# artifacts are published and indexed.',
+  ];
+  const targetDependencies = new Map();
+  const addTargetDependency = (cfg, dependency) => {
+    const dependencies = targetDependencies.get(cfg) ?? [];
+    dependencies.push(dependency);
+    targetDependencies.set(cfg, dependencies);
+  };
+
+  for (const target of artifactTargets.nativeTargets) {
+    const cfg = rustNativeTargetCfg(target);
+    addTargetDependency(
+      cfg,
+      `${liboliphauntCargoPackageName(target.target)} = { version = "=${nativeVersion}" }`,
+    );
+  }
+  for (const target of artifactTargets.brokerTargets) {
+    const cfg = rustNativeTargetCfg(target);
+    addTargetDependency(
+      cfg,
+      `${brokerCargoPackageName(target.target)} = { version = "=${brokerVersion}" }`,
+    );
+  }
+
+  for (const cfg of [...targetDependencies.keys()].sort(compareText)) {
+    lines.push('', `[target.'cfg(${cfg})'.dependencies]`);
+    lines.push(...targetDependencies.get(cfg).sort(compareText));
+  }
+  return `${text.trimEnd()}\n${lines.join('\n')}\n`;
+}
+
+function validateReleaseArtifactCoverage(manifest, nativeVersion, nativeTargets) {
+  const brokerCrates = registryPackageRows(
+    { product: BROKER_PRODUCT, packageKind: 'crates' },
+    TOOL,
+  ).map((row) => row.packageName);
+  const missingBroker = brokerCrates.filter((crate) => !manifest.includes(`${crate} = `));
+  if (missingBroker.length > 0) {
+    fail(
+      `generated oliphaunt release source is missing broker Cargo artifact dependencies: ${missingBroker.join(', ')}`,
+    );
+  }
+
+  const nativeRuntimeCrates = nativeTargets.map((target) =>
+    liboliphauntCargoPackageName(target.target),
+  );
+  const nativeCrates = registryPackageRows(
+    { product: LIBOLIPHAUNT_NATIVE_PRODUCT, packageKind: 'crates' },
+    TOOL,
+  ).map((row) => row.packageName);
+  if (nativeCrates.length === 0) {
+    fail(
+      'oliphaunt-rust cannot publish a working native Cargo consumer path: ' +
+        'oliphaunt-build requires Cargo-resolved liboliphaunt-native native-runtime ' +
+        `artifacts for ${nativeTargets.map((target) => target.target).join(', ')}, but liboliphaunt-native declares no crates.io ` +
+        'artifact packages. Split/size native runtime artifacts into crates.io-sized packages before publishing oliphaunt-rust.',
+    );
+  }
+
+  const missingNative = nativeRuntimeCrates.filter(
+    (crate) => !manifest.includes(`${crate} = { version = "=${nativeVersion}" }`),
+  );
+  if (missingNative.length > 0) {
+    fail(
+      `generated oliphaunt release source is missing native runtime Cargo artifact dependencies: ${missingNative.join(', ')}`,
+    );
+  }
+}
+
+function releaseStageDir(stageDir) {
+  const resolved = path.resolve(ROOT, stageDir);
+  const relative = path.relative(ROOT, resolved);
+  if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
+    fail(`generated Rust release stage must be a repository-contained directory, got ${stageDir}`);
+  }
+  return resolved;
+}
+
+export function prepareRustReleaseSource({ stageDir = DEFAULT_STAGE_DIR, log = true } = {}) {
+  const version = currentProductVersionSync(RUST_PRODUCT, TOOL);
+  const nativeVersion = productCompatibilityVersion(
+    RUST_PRODUCT,
+    LIBOLIPHAUNT_NATIVE_PRODUCT,
+    TOOL,
+  );
+  const brokerVersion = productCompatibilityVersion(RUST_PRODUCT, BROKER_PRODUCT, TOOL);
+  const artifactTargets = nativeSdkArtifactTargets();
+  const outputDir = releaseStageDir(stageDir);
+  stageRustPackageSource(outputDir);
+
+  const cargoToml = path.join(outputDir, 'Cargo.toml');
+  const rendered = renderReleaseCargoToml(
+    readFileSync(cargoToml, 'utf8'),
+    nativeVersion,
+    brokerVersion,
+    artifactTargets,
+  );
+  writeFileSync(cargoToml, rendered, 'utf8');
+  if (!packageSection(rendered).includes(`version = "${version}"`)) {
+    fail(`generated oliphaunt release source must keep SDK version ${version}`);
+  }
+  validateReleaseArtifactCoverage(rendered, nativeVersion, artifactTargets.nativeTargets);
+  const libRs = path.join(outputDir, 'src/lib.rs');
+  writeFileSync(
+    libRs,
+    `${readFileSync(libRs, 'utf8').trimEnd()}\n\n// Generated release-only native target guard.\n` +
+      `${renderRustSdkNativeTargetGuard(artifactTargets.nativeTargets)}\n`,
+    'utf8',
+  );
+  stageReleaseNotices(outputDir, SOURCE_NOTICE_OPTIONS);
+  assertReleaseNoticesInDirectory(outputDir, SOURCE_NOTICE_OPTIONS);
+  if (log) console.log(rel(cargoToml));
+  return cargoToml;
+}
+
+export function prepareOliphauntBuildReleaseSource({
+  stageDir = DEFAULT_BUILD_STAGE_DIR,
+  log = true,
+} = {}) {
+  const version = currentProductVersionSync(RUST_PRODUCT, TOOL);
+  const sourceDir = path.join(ROOT, 'src/sdks/rust/sdk/crates/oliphaunt-build');
+  const outputDir = releaseStageDir(stageDir);
+  rmSync(outputDir, { recursive: true, force: true });
+  cpSync(sourceDir, outputDir, {
+    recursive: true,
+    filter: (source) => path.basename(source) !== 'target',
+  });
+  const cargoToml = path.join(outputDir, 'Cargo.toml');
+  const rendered = packagedCargoManifestText(readFileSync(cargoToml, 'utf8'));
+  writeFileSync(cargoToml, rendered, 'utf8');
+  if (!packageSection(rendered).includes(`version = "${version}"`)) {
+    fail(`generated oliphaunt-build release source must keep SDK version ${version}`);
+  }
+  stageReleaseNotices(outputDir, SOURCE_NOTICE_OPTIONS);
+  assertReleaseNoticesInDirectory(outputDir, SOURCE_NOTICE_OPTIONS);
+  if (log) console.log(rel(cargoToml));
+  return cargoToml;
+}
+
+if (import.meta.main) {
+  const [kind = 'oliphaunt', stageDir, ...extra] = Bun.argv.slice(2);
+  if (extra.length || !['oliphaunt', 'oliphaunt-build'].includes(kind)) {
+    fail('usage: prepare-rust-release-source.mts [oliphaunt|oliphaunt-build] [STAGE_DIRECTORY]');
+  }
+  (kind === 'oliphaunt' ? prepareRustReleaseSource : prepareOliphauntBuildReleaseSource)({
+    stageDir,
+  });
+}
diff --git a/src/sdks/rust/sdk/tools/prepare-rust-release-source.test-inputs.mts b/src/sdks/rust/sdk/tools/prepare-rust-release-source.test-inputs.mts
new file mode 100644
index 000000000..58a772b70
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/prepare-rust-release-source.test-inputs.mts
@@ -0,0 +1,10 @@
+import path from 'node:path';
+import {
+  prepareOliphauntBuildReleaseSource,
+  prepareRustReleaseSource,
+} from './prepare-rust-release-source.mts';
+
+const root = process.env.OLIPHAUNT_RUST_RELEASE_SOURCE_TEST_ROOT;
+if (!root) throw new Error('Run bash src/sdks/rust/sdk/tools/prepare-rust-release-source.test.sh');
+prepareRustReleaseSource({ stageDir: path.join(root, 'sdk/source'), log: false });
+prepareOliphauntBuildReleaseSource({ stageDir: path.join(root, 'build/source'), log: false });
diff --git a/src/sdks/rust/sdk/tools/prepare-rust-release-source.test.mts b/src/sdks/rust/sdk/tools/prepare-rust-release-source.test.mts
new file mode 100644
index 000000000..2b8089c3f
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/prepare-rust-release-source.test.mts
@@ -0,0 +1,101 @@
+import assert from 'node:assert/strict';
+import { readdirSync, readFileSync } from 'node:fs';
+import path from 'node:path';
+import test from 'node:test';
+import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+} from '../../../../../tools/packaging/release-notices.mts';
+import { rustNativeTargetCfg } from '../../../../../tools/packaging/rust-native-targets.mts';
+import {
+  allArtifactTargets,
+  currentProductVersionSync,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts';
+
+const scratch = process.env.OLIPHAUNT_RUST_RELEASE_SOURCE_TEST_ROOT;
+if (!scratch)
+  throw new Error('Run bash src/sdks/rust/sdk/tools/prepare-rust-release-source.test.sh');
+function crateAt(root) {
+  const directory = path.join(root, 'crate');
+  const names = readdirSync(directory).filter((name) => name.endsWith('.crate'));
+  assert.equal(names.length, 1);
+  return path.join(directory, names[0]);
+}
+
+test('freezes the generated target-wired Rust SDK source instead of the workspace facade', () => {
+  const root = path.join(scratch, 'sdk');
+  const manifestPath = path.join(root, 'source/Cargo.toml');
+  const manifest = readFileSync(manifestPath, 'utf8');
+  const source = readFileSync(path.join(root, 'source/src/lib.rs'), 'utf8');
+  const nativeVersion = productCompatibilityVersion(
+    'oliphaunt-rust',
+    'liboliphaunt-native',
+    'prepare-rust-release-source.test.mts',
+  );
+  const brokerVersion = productCompatibilityVersion(
+    'oliphaunt-rust',
+    'oliphaunt-broker',
+    'prepare-rust-release-source.test.mts',
+  );
+  const sdkVersion = currentProductVersionSync(
+    'oliphaunt-rust',
+    'prepare-rust-release-source.test.mts',
+  );
+  const targets = allArtifactTargets(
+    {
+      product: 'liboliphaunt-native',
+      kind: 'native-runtime',
+      surface: 'rust-native-direct',
+    },
+    'prepare-rust-release-source.test.mts',
+  );
+  assert.equal(Bun.TOML.parse(manifest).package.license, 'MIT');
+  assertReleaseNoticesInDirectory(path.join(root, 'source'), { profile: 'source-sdk' });
+
+  const parsed = Bun.TOML.parse(manifest);
+  for (const target of targets) {
+    const cfg = rustNativeTargetCfg(target);
+    const dependencies = parsed.target['cfg(' + cfg + ')'].dependencies;
+    assert.equal(dependencies['liboliphaunt-native-' + target.target].version, '=' + nativeVersion);
+    assert.equal(dependencies['oliphaunt-broker-' + target.target].version, '=' + brokerVersion);
+  }
+  assert.equal(parsed.dependencies?.['oliphaunt-tools'], undefined);
+
+  const cratePath = crateAt(root);
+  assert.equal(path.basename(cratePath), `oliphaunt-${sdkVersion}.crate`);
+  const packageRoot = `oliphaunt-${sdkVersion}`;
+  assertReleaseNoticesInArchive(cratePath, {
+    profile: 'source-sdk',
+    prefix: packageRoot,
+  });
+  const entries = readPortableArchiveEntries(cratePath);
+  const packedManifest = entries.get(`${packageRoot}/Cargo.toml`).data().toString('utf8');
+  const packedSource = entries.get(`${packageRoot}/src/lib.rs`).data().toString('utf8');
+  const packedNames = [...entries.keys()].join('\n');
+  assert.equal(packedManifest, manifest);
+  assert.equal(packedSource, source);
+  assert.doesNotMatch(packedManifest, /=\s*\{[^}\n]*\bpath\s*=/u);
+  assert.doesNotMatch(packedNames, /crates\/oliphaunt-build/u);
+});
+
+test('freezes oliphaunt-build with truthful metadata and canonical notices', () => {
+  const root = path.join(scratch, 'build');
+  const manifestPath = path.join(root, 'source/Cargo.toml');
+  const manifest = readFileSync(manifestPath, 'utf8');
+  const version = currentProductVersionSync(
+    'oliphaunt-rust',
+    'prepare-rust-release-source.test.mts',
+  );
+  assert.equal(Bun.TOML.parse(manifest).package.license, 'MIT');
+  assert.doesNotMatch(manifest, /\.workspace\s*=\s*true/u);
+  assertReleaseNoticesInDirectory(path.join(root, 'source'), { profile: 'source-sdk' });
+
+  const cratePath = crateAt(root);
+  assert.equal(path.basename(cratePath), `oliphaunt-build-${version}.crate`);
+  assertReleaseNoticesInArchive(cratePath, {
+    profile: 'source-sdk',
+    prefix: `oliphaunt-build-${version}`,
+  });
+});
diff --git a/src/sdks/rust/sdk/tools/prepare-rust-release-source.test.sh b/src/sdks/rust/sdk/tools/prepare-rust-release-source.test.sh
new file mode 100644
index 000000000..2ea4b75d5
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/prepare-rust-release-source.test.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+export OLIPHAUNT_RUST_RELEASE_SOURCE_TEST_ROOT
+mkdir -p target
+OLIPHAUNT_RUST_RELEASE_SOURCE_TEST_ROOT="$(mktemp -d "$PWD/target/rust-release-source-test-XXXXXX")"
+trap 'rm -rf "$OLIPHAUNT_RUST_RELEASE_SOURCE_TEST_ROOT"' EXIT
+bun src/sdks/rust/sdk/tools/prepare-rust-release-source.test-inputs.mts
+for owner in sdk build; do
+  root="$OLIPHAUNT_RUST_RELEASE_SOURCE_TEST_ROOT/$owner"
+  bash tools/packaging/package-cargo-source.sh "$root/source/Cargo.toml" "$root/crate"
+done
+bun test --timeout=30000 ./src/sdks/rust/sdk/tools/prepare-rust-release-source.test.mts
diff --git a/src/sdks/rust/sdk/tools/stage-release-artifacts.sh b/src/sdks/rust/sdk/tools/stage-release-artifacts.sh
new file mode 100644
index 000000000..ca84e6349
--- /dev/null
+++ b/src/sdks/rust/sdk/tools/stage-release-artifacts.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+artifact_root="$PWD/target/sdk-artifacts/oliphaunt-rust"
+work_root="$PWD/target/sdk-artifacts-work/oliphaunt-rust"
+rm -rf "$artifact_root" "$work_root"
+mkdir -p "$artifact_root" "$work_root"
+for package in oliphaunt oliphaunt-build; do
+  manifest=$(bun src/sdks/rust/sdk/tools/prepare-rust-release-source.mts "$package" "$work_root/$package-source")
+  crate=$(bash tools/packaging/package-cargo-source.sh "$manifest" "$work_root/$package-crate" "$work_root/$package-files.txt")
+  prefix=$(basename "$crate" .crate)
+  bun tools/packaging/release-notices.mts check-archive "$crate" --profile source-sdk --prefix "$prefix"
+  cp "$crate" "$artifact_root/"
+done
+cp "$work_root/oliphaunt-files.txt" "$artifact_root/cargo-package-files.txt"
+bun tools/packaging/staging.mts "$artifact_root"
diff --git a/src/sdks/rust/src/broker_support.rs b/src/sdks/rust/src/broker_support.rs
deleted file mode 100644
index 154171d8c..000000000
--- a/src/sdks/rust/src/broker_support.rs
+++ /dev/null
@@ -1,129 +0,0 @@
-use std::path::PathBuf;
-use std::sync::Arc;
-
-use crate::config::{
-    DEFAULT_DATABASE, DEFAULT_USERNAME, EngineMode, NativeBrokerConfig, NativeServerConfig,
-    OpenConfig, PostgresStartupGuc,
-};
-use crate::engine::{EngineCancel, EngineSession, NativeRuntime, ProtocolStreamOutcome};
-use crate::error::{Error, Result};
-use crate::extension::Extension;
-use crate::liboliphaunt::OliphauntRuntime;
-use crate::storage::DatabaseStorage;
-
-/// Narrow process-helper boundary used by the unpublished broker executable.
-#[doc(hidden)]
-pub struct BrokerSession {
-    session: Box,
-}
-
-/// Out-of-band cancellation handle for a broker-owned session.
-#[doc(hidden)]
-#[derive(Clone)]
-pub struct BrokerCancel {
-    cancel: Arc,
-}
-
-/// Version-locked streamed-protocol completion used by the broker helper.
-#[doc(hidden)]
-pub enum BrokerStreamOutcome {
-    /// The direct runtime confirmed ReadyForQuery; the nested result is the
-    /// chunk callback outcome.
-    ReadyForQuery(Result<()>),
-    /// The direct runtime could not confirm ReadyForQuery after an independent
-    /// runtime or transport failure.
-    SessionStateUnknown(Error),
-}
-
-impl BrokerCancel {
-    /// Cancel the active PostgreSQL command.
-    pub fn cancel(&self) -> Result<()> {
-        self.cancel.cancel()
-    }
-}
-
-/// Open the direct runtime owned by the broker process.
-#[doc(hidden)]
-pub fn open(
-    root: PathBuf,
-    startup_gucs: Vec<(String, String)>,
-    username: Option,
-    database: Option,
-    extensions: Vec,
-) -> Result {
-    let config = OpenConfig {
-        mode: EngineMode::Direct,
-        storage: DatabaseStorage::Directory(root),
-        broker: NativeBrokerConfig::default(),
-        server: NativeServerConfig::default(),
-        startup_gucs: startup_gucs
-            .into_iter()
-            .map(|(name, value)| PostgresStartupGuc::new(name, value))
-            .collect(),
-        username: username.unwrap_or_else(|| DEFAULT_USERNAME.to_owned()),
-        database: database.unwrap_or_else(|| DEFAULT_DATABASE.to_owned()),
-        extensions,
-    };
-    config.validate()?;
-    Ok(BrokerSession {
-        session: OliphauntRuntime::from_env().open(config)?,
-    })
-}
-
-impl BrokerSession {
-    /// Obtain an out-of-band cancellation handle.
-    pub fn cancel_handle(&self) -> Result {
-        self.session
-            .cancel_handle()
-            .map(|cancel| BrokerCancel { cancel })
-            .ok_or_else(|| {
-                Error::Engine("native broker session does not support cancellation".into())
-            })
-    }
-
-    /// Execute raw PostgreSQL protocol bytes.
-    pub fn exec_protocol_raw(&mut self, bytes: Vec) -> Result> {
-        self.session
-            .exec_protocol_raw(bytes.into())
-            .map(|response| response.into_bytes())
-    }
-
-    /// Execute raw PostgreSQL protocol bytes and forward native response chunks.
-    pub fn exec_protocol_raw_stream(
-        &mut self,
-        bytes: Vec,
-        on_chunk: &mut dyn FnMut(&[u8]) -> Result<()>,
-    ) -> BrokerStreamOutcome {
-        match self.session.exec_protocol_raw_stream(bytes.into(), on_chunk) {
-            ProtocolStreamOutcome::ReadyForQuery(result) => {
-                BrokerStreamOutcome::ReadyForQuery(result)
-            }
-            ProtocolStreamOutcome::SessionStateUnknown(error) => {
-                BrokerStreamOutcome::SessionStateUnknown(error)
-            }
-        }
-    }
-
-    /// Execute a PostgreSQL simple query.
-    pub fn execute(&mut self, sql: &str) -> Result> {
-        self.session
-            .exec_simple_query(sql)
-            .map(|response| response.into_bytes())
-    }
-
-    /// Create a physical backup.
-    pub fn backup(&mut self) -> Result> {
-        self.session.backup()
-    }
-
-    /// Close the broker-owned session.
-    pub fn close(&mut self) -> Result<()> {
-        self.session.close()
-    }
-}
-
-/// Restore physical backup bytes into an absent destination.
-#[doc(hidden)]
-pub fn restore(destination: PathBuf, bytes: Vec) -> Result<()> {
-    OliphauntRuntime::from_env().restore(&destination, &bytes)
-}
diff --git a/src/sdks/rust/src/build_resources.rs b/src/sdks/rust/src/build_resources.rs
deleted file mode 100644
index 4339f8d67..000000000
--- a/src/sdks/rust/src/build_resources.rs
+++ /dev/null
@@ -1,138 +0,0 @@
-use std::path::PathBuf;
-use std::sync::{OnceLock, RwLock};
-
-use crate::error::{Error, Result};
-
-static BUILD_RESOURCES_DIR: OnceLock>> = OnceLock::new();
-
-/// Register the Oliphaunt resource directory staged by `oliphaunt-build`.
-///
-/// Applications usually call [`crate::register_build_resources!`] once during startup
-/// after their `build.rs` has called `oliphaunt_build::configure()`. The native
-/// runtime locator uses this directory before falling back to explicit
-/// environment variables and source-tree build layouts.
-pub fn register_build_resources_dir(path: impl Into) -> Result<()> {
-    let path = path.into();
-    if path.as_os_str().is_empty() {
-        return Err(Error::InvalidConfig(
-            "Oliphaunt build resources directory cannot be empty".to_owned(),
-        ));
-    }
-
-    let lock = BUILD_RESOURCES_DIR.get_or_init(|| RwLock::new(None));
-    let mut guard = lock
-        .write()
-        .map_err(|_| Error::Engine("Oliphaunt build resources registry was poisoned".to_owned()))?;
-    if let Some(existing) = guard.as_ref() {
-        if existing == &path {
-            return Ok(());
-        }
-        return Err(Error::InvalidConfig(format!(
-            "Oliphaunt build resources are already registered as {}; cannot replace them with {}",
-            existing.display(),
-            path.display()
-        )));
-    }
-    *guard = Some(path);
-    Ok(())
-}
-
-pub(crate) fn registered_build_resources_dir() -> Option {
-    BUILD_RESOURCES_DIR
-        .get()
-        .and_then(|lock| lock.read().ok().and_then(|guard| guard.clone()))
-}
-
-/// Register the resources staged by `oliphaunt-build` for the current package.
-///
-/// The macro expands in the application crate, so it can read the
-/// `OLIPHAUNT_RESOURCES_DIR` compile-time value emitted by
-/// `oliphaunt_build::configure()`.
-#[macro_export]
-macro_rules! register_build_resources {
-    () => {
-        match option_env!("OLIPHAUNT_RESOURCES_DIR") {
-            Some(path) => $crate::register_build_resources_dir(path),
-            None => Err($crate::Error::InvalidConfig(
-                "OLIPHAUNT_RESOURCES_DIR was not emitted for this package; add oliphaunt-build as a build dependency and call oliphaunt_build::configure() from build.rs"
-                    .to_owned(),
-            )),
-        }
-    };
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn registration_and_macro_contract_is_process_wide_and_immutable() {
-        assert_eq!(registered_build_resources_dir(), None);
-
-        let empty_error = register_build_resources_dir(PathBuf::new())
-            .expect_err("an empty resource directory must be rejected");
-        assert_eq!(
-            empty_error.kind(),
-            crate::error::ErrorKind::InvalidConfiguration
-        );
-        assert_eq!(registered_build_resources_dir(), None);
-
-        // Keep the singleton's complete contract in one test so ordinary
-        // `cargo test` execution cannot make assertions order-dependent. If a
-        // caller intentionally supplies the compile-time override while
-        // testing this crate, use that path for the initial registration so
-        // the macro's configured branch remains idempotent.
-        let compile_time_resources = option_env!("OLIPHAUNT_RESOURCES_DIR").map(PathBuf::from);
-        let registered = compile_time_resources
-            .as_ref()
-            .filter(|path| !path.as_os_str().is_empty())
-            .cloned()
-            .unwrap_or_else(|| PathBuf::from("oliphaunt-test-resources"));
-        register_build_resources_dir(registered.clone())
-            .expect("the first nonempty resource directory must be accepted");
-        assert_eq!(registered_build_resources_dir(), Some(registered.clone()));
-
-        register_build_resources_dir(registered.clone())
-            .expect("registering the exact same resource directory must be idempotent");
-
-        let replacement =
-            if registered.as_path() == std::path::Path::new("oliphaunt-other-resources") {
-                PathBuf::from("oliphaunt-third-resources")
-            } else {
-                PathBuf::from("oliphaunt-other-resources")
-            };
-        let replacement_error = register_build_resources_dir(replacement.clone())
-            .expect_err("a process-wide resource directory must not be replaceable");
-        assert_eq!(
-            replacement_error.kind(),
-            crate::error::ErrorKind::InvalidConfiguration
-        );
-        let message = replacement_error.to_string();
-        assert!(message.contains(®istered.display().to_string()));
-        assert!(message.contains(&replacement.display().to_string()));
-        assert_eq!(registered_build_resources_dir(), Some(registered.clone()));
-
-        match compile_time_resources {
-            Some(path) if path.as_os_str().is_empty() => {
-                let error = crate::register_build_resources!()
-                    .expect_err("an empty compile-time resource directory must be rejected");
-                assert_eq!(error.kind(), crate::error::ErrorKind::InvalidConfiguration);
-                assert!(error.to_string().contains("cannot be empty"));
-            }
-            Some(_) => {
-                crate::register_build_resources!().expect(
-                    "the configured macro path must be idempotent with direct registration",
-                );
-            }
-            None => {
-                let error = crate::register_build_resources!()
-                    .expect_err("the SDK crate itself has no oliphaunt-build configuration");
-                assert_eq!(error.kind(), crate::error::ErrorKind::InvalidConfiguration);
-                let message = error.to_string();
-                assert!(message.contains("OLIPHAUNT_RESOURCES_DIR was not emitted"));
-                assert!(message.contains("oliphaunt_build::configure()"));
-            }
-        }
-        assert_eq!(registered_build_resources_dir(), Some(registered));
-    }
-}
diff --git a/src/sdks/rust/src/builder.rs b/src/sdks/rust/src/builder.rs
deleted file mode 100644
index 3fb7269cc..000000000
--- a/src/sdks/rust/src/builder.rs
+++ /dev/null
@@ -1,330 +0,0 @@
-use std::path::PathBuf;
-
-use crate::broker::NativeBrokerRuntime;
-use crate::config::{
-    DEFAULT_DATABASE, DEFAULT_USERNAME, EngineMode, NativeBrokerConfig, NativeServerConfig,
-    OpenConfig, PostgresStartupGuc, ServerListen,
-};
-use crate::database::{AsyncOliphaunt, AsyncOliphauntServer};
-use crate::engine::{EngineSession, NativeRuntime};
-use crate::error::{Error, Result};
-use crate::executor::EngineExecutor;
-use crate::extension::Extension;
-use crate::liboliphaunt::OliphauntRuntime;
-use crate::server::NativeServerRuntime;
-use crate::storage::DatabaseStorage;
-
-/// Builder for opening native Oliphaunt databases on a dedicated SDK owner thread.
-#[derive(Debug, Clone)]
-pub struct AsyncOliphauntBuilder {
-    mode: EngineMode,
-    broker: NativeBrokerConfig,
-    common: CommonOpenOptions,
-}
-
-/// Builder for starting a native PostgreSQL server on a dedicated SDK owner thread.
-#[derive(Debug, Clone, Default)]
-pub struct AsyncOliphauntServerBuilder {
-    server: NativeServerConfig,
-    common: CommonOpenOptions,
-}
-
-#[derive(Debug, Clone)]
-struct CommonOpenOptions {
-    storage: DatabaseStorage,
-    startup_gucs: Vec,
-    username: String,
-    database: String,
-    extensions: Vec,
-}
-
-impl Default for CommonOpenOptions {
-    fn default() -> Self {
-        Self {
-            storage: DatabaseStorage::TemporaryDirectory,
-            startup_gucs: Vec::new(),
-            username: DEFAULT_USERNAME.to_owned(),
-            database: DEFAULT_DATABASE.to_owned(),
-            extensions: Vec::new(),
-        }
-    }
-}
-
-impl CommonOpenOptions {
-    fn build_config(
-        &self,
-        mode: EngineMode,
-        broker: NativeBrokerConfig,
-        server: NativeServerConfig,
-    ) -> Result {
-        let config = OpenConfig {
-            mode,
-            storage: self.storage.clone(),
-            broker,
-            server,
-            startup_gucs: self.startup_gucs.clone(),
-            username: self.username.clone(),
-            database: self.database.clone(),
-            extensions: self.extensions.clone(),
-        };
-        config.validate()?;
-        Ok(config)
-    }
-}
-
-impl Default for AsyncOliphauntBuilder {
-    fn default() -> Self {
-        Self {
-            mode: EngineMode::Direct,
-            broker: NativeBrokerConfig::default(),
-            common: CommonOpenOptions::default(),
-        }
-    }
-}
-
-impl AsyncOliphauntBuilder {
-    /// Create an asynchronous builder. The database topology defaults to direct.
-    pub fn new() -> Self {
-        Self::default()
-    }
-
-    /// Select the in-process direct topology for [`Self::open`].
-    pub fn direct(mut self) -> Self {
-        self.mode = EngineMode::Direct;
-        self
-    }
-
-    /// Select the broker-process topology for [`Self::open`].
-    pub fn broker(mut self) -> Self {
-        self.mode = EngineMode::Broker;
-        self
-    }
-
-    /// Select database storage.
-    pub fn storage(mut self, storage: DatabaseStorage) -> Self {
-        self.common.storage = storage;
-        self
-    }
-
-    /// Use an explicit broker helper executable with `broker().open()`.
-    pub fn broker_executable(mut self, path: impl Into) -> Self {
-        self.broker.executable = Some(path.into());
-        self
-    }
-
-    /// Add an explicit PostgreSQL startup GUC.
-    pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self {
-        self.common
-            .startup_gucs
-            .push(PostgresStartupGuc::new(name, value));
-        self
-    }
-
-    /// Add explicit PostgreSQL startup GUCs.
-    pub fn startup_gucs(mut self, gucs: impl IntoIterator) -> Self
-    where
-        N: Into,
-        V: Into,
-    {
-        self.common.startup_gucs.extend(
-            gucs.into_iter()
-                .map(|(name, value)| PostgresStartupGuc::new(name, value)),
-        );
-        self
-    }
-
-    /// Set the PostgreSQL startup user.
-    pub fn username(mut self, username: impl Into) -> Self {
-        self.common.username = username.into();
-        self
-    }
-
-    /// Set the PostgreSQL database name.
-    pub fn database(mut self, database: impl Into) -> Self {
-        self.common.database = database.into();
-        self
-    }
-
-    /// Make one bundled PostgreSQL extension artifact available to the database.
-    /// Database-local installation remains the application's migration concern.
-    pub fn extension(mut self, extension: Extension) -> Self {
-        self.common.extensions.push(extension);
-        self
-    }
-
-    /// Make bundled PostgreSQL extension artifacts available to the database.
-    /// Database-local installation remains the application's migration concern.
-    pub fn extensions(mut self, extensions: impl IntoIterator) -> Self {
-        self.common.extensions.extend(extensions);
-        self
-    }
-
-    pub(crate) fn build_config(&self) -> Result {
-        if self.mode == EngineMode::Direct && self.broker.executable.is_some() {
-            return Err(Error::InvalidConfig(
-                "broker_executable(...) requires broker().open()".to_owned(),
-            ));
-        }
-        self.common.build_config(
-            self.mode,
-            self.broker.clone(),
-            NativeServerConfig::default(),
-        )
-    }
-
-    /// Open a direct or broker database on a dedicated owner thread.
-    pub async fn open(self) -> Result {
-        let config = self.build_config()?;
-        let (executor, ()) = EngineExecutor::open("oliphaunt-owner", move || {
-            open_embedded_session(config).map(|session| (session, ()))
-        })
-        .await?;
-        Ok(AsyncOliphaunt::from_executor(executor))
-    }
-}
-
-impl AsyncOliphauntServerBuilder {
-    /// Create an asynchronous local-server builder.
-    pub fn new() -> Self {
-        Self::default()
-    }
-
-    /// Select server storage.
-    pub fn storage(mut self, storage: DatabaseStorage) -> Self {
-        self.common.storage = storage;
-        self
-    }
-
-    /// Use an explicit PostgreSQL server executable.
-    pub fn server_executable(mut self, path: impl Into) -> Self {
-        self.server.executable = Some(path.into());
-        self
-    }
-
-    /// Select the endpoint exposed by the local server.
-    pub fn listen(mut self, listen: ServerListen) -> Self {
-        self.server.listen = listen;
-        self
-    }
-
-    /// Add an explicit PostgreSQL startup GUC.
-    pub fn startup_guc(mut self, name: impl Into, value: impl Into) -> Self {
-        self.common
-            .startup_gucs
-            .push(PostgresStartupGuc::new(name, value));
-        self
-    }
-
-    /// Add explicit PostgreSQL startup GUCs.
-    pub fn startup_gucs(mut self, gucs: impl IntoIterator) -> Self
-    where
-        N: Into,
-        V: Into,
-    {
-        self.common.startup_gucs.extend(
-            gucs.into_iter()
-                .map(|(name, value)| PostgresStartupGuc::new(name, value)),
-        );
-        self
-    }
-
-    /// Set the PostgreSQL startup user.
-    pub fn username(mut self, username: impl Into) -> Self {
-        self.common.username = username.into();
-        self
-    }
-
-    /// Set the PostgreSQL database name.
-    pub fn database(mut self, database: impl Into) -> Self {
-        self.common.database = database.into();
-        self
-    }
-
-    /// Make one bundled PostgreSQL extension artifact available to clients.
-    /// Database-local installation remains the application's migration concern.
-    pub fn extension(mut self, extension: Extension) -> Self {
-        self.common.extensions.push(extension);
-        self
-    }
-
-    /// Make bundled PostgreSQL extension artifacts available to clients.
-    /// Database-local installation remains the application's migration concern.
-    pub fn extensions(mut self, extensions: impl IntoIterator) -> Self {
-        self.common.extensions.extend(extensions);
-        self
-    }
-
-    pub(crate) fn build_config(&self) -> Result {
-        self.common.build_config(
-            EngineMode::Server,
-            NativeBrokerConfig::default(),
-            self.server.clone(),
-        )
-    }
-
-    /// Start a local PostgreSQL server and return its lifecycle handle.
-    pub async fn start(self) -> Result {
-        let config = self.build_config()?;
-        let (executor, connection_string) =
-            EngineExecutor::open("oliphaunt-server-owner", move || {
-                start_server_session(config)
-            })
-            .await?;
-        Ok(AsyncOliphauntServer::from_executor(
-            executor,
-            connection_string,
-        ))
-    }
-}
-
-pub(crate) fn open_embedded_session(config: OpenConfig) -> Result> {
-    match config.mode {
-        EngineMode::Direct => OliphauntRuntime::from_env().open(config),
-        EngineMode::Broker => NativeBrokerRuntime::from_config(&config.broker).open(config),
-        EngineMode::Server => unreachable!("server mode uses its dedicated builder"),
-    }
-}
-
-pub(crate) fn start_server_session(config: OpenConfig) -> Result<(Box, String)> {
-    let session = NativeServerRuntime::from_config(&config.server).open(config)?;
-    let connection_string = session.connection_string().ok_or_else(|| {
-        Error::Engine("native server did not expose its connection string".to_owned())
-    })?;
-    Ok((session, connection_string))
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn direct_open_rejects_a_broker_executable_instead_of_ignoring_it() {
-        let error = AsyncOliphauntBuilder::new()
-            .broker_executable("oliphaunt-broker")
-            .build_config()
-            .expect_err("direct cannot silently ignore a broker executable");
-        assert_eq!(error.kind(), crate::error::ErrorKind::InvalidConfiguration);
-        assert_eq!(
-            error.to_string(),
-            "broker_executable(...) requires broker().open()"
-        );
-        AsyncOliphauntBuilder::new()
-            .broker()
-            .broker_executable("oliphaunt-broker")
-            .build_config()
-            .expect("broker executable is valid for broker open");
-    }
-
-    #[test]
-    fn dedicated_server_builder_produces_only_server_configuration() {
-        let config = AsyncOliphauntServerBuilder::new()
-            .listen(ServerListen::tcp_port(6543))
-            .server_executable("postgres")
-            .build_config()
-            .expect("server configuration");
-        assert_eq!(config.mode, EngineMode::Server);
-        assert_eq!(config.server.listen, ServerListen::tcp_port(6543));
-        assert_eq!(config.server.executable, Some(PathBuf::from("postgres")));
-        assert!(config.broker.executable.is_none());
-    }
-}
diff --git a/src/sdks/rust/src/config.rs b/src/sdks/rust/src/config.rs
deleted file mode 100644
index dc57218c6..000000000
--- a/src/sdks/rust/src/config.rs
+++ /dev/null
@@ -1,479 +0,0 @@
-use std::collections::BTreeSet;
-use std::path::{Path, PathBuf};
-
-use crate::error::{Error, Result};
-use crate::extension::{Extension, resolve_extensions};
-use crate::storage::{DatabaseStorage, path_contains_nul};
-
-/// Default PostgreSQL role used by SDK-managed native sessions.
-pub(crate) const DEFAULT_USERNAME: &str = "postgres";
-
-/// Default PostgreSQL database used by SDK-managed native sessions.
-pub(crate) const DEFAULT_DATABASE: &str = "postgres";
-
-/// Native runtime mode.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(crate) enum EngineMode {
-    /// In-process embedded PostgreSQL.
-    Direct,
-    /// Process-isolated embedded PostgreSQL.
-    Broker,
-    /// Local PostgreSQL-compatible server.
-    Server,
-}
-
-/// Explicit PostgreSQL startup GUC override.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub(crate) struct PostgresStartupGuc {
-    /// PostgreSQL GUC name, such as `shared_buffers`.
-    pub(crate) name: String,
-    /// PostgreSQL GUC value, such as `32MB`.
-    pub(crate) value: String,
-}
-
-impl PostgresStartupGuc {
-    /// Create a startup GUC override.
-    pub(crate) fn new(name: impl Into, value: impl Into) -> Self {
-        Self {
-            name: name.into(),
-            value: value.into(),
-        }
-    }
-
-    fn startup_assignment(&self) -> String {
-        format!("{}={}", self.name.trim(), self.value)
-    }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Default)]
-pub(crate) struct NativeBrokerConfig {
-    pub(crate) executable: Option,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Default)]
-pub(crate) struct NativeServerConfig {
-    pub(crate) executable: Option,
-    pub(crate) listen: ServerListen,
-}
-
-/// Local endpoint exposed by a native PostgreSQL server.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ServerListen {
-    /// Listen on the fixed loopback address. `None` allocates an ephemeral port.
-    Tcp {
-        /// PostgreSQL port, or `None` for an ephemeral port.
-        port: Option,
-    },
-    /// Listen in a PostgreSQL Unix-domain socket directory.
-    ///
-    /// The resolved directory must be valid UTF-8 because server handles
-    /// publish it through a portable PostgreSQL connection string.
-    #[cfg(unix)]
-    Unix {
-        /// Directory containing `.s.PGSQL.`.
-        directory: PathBuf,
-        /// PostgreSQL port encoded in the socket filename.
-        port: u16,
-    },
-}
-
-impl Default for ServerListen {
-    fn default() -> Self {
-        Self::tcp()
-    }
-}
-
-impl ServerListen {
-    /// Listen on loopback using an ephemeral TCP port.
-    pub const fn tcp() -> Self {
-        Self::Tcp { port: None }
-    }
-
-    /// Listen on loopback using a fixed TCP port.
-    pub const fn tcp_port(port: u16) -> Self {
-        Self::Tcp { port: Some(port) }
-    }
-
-    /// Listen in a UTF-8 Unix-domain socket directory using PostgreSQL port
-    /// 5432.
-    #[cfg(unix)]
-    pub fn unix(directory: impl Into) -> Self {
-        Self::Unix {
-            directory: directory.into(),
-            port: 5432,
-        }
-    }
-
-    /// Listen in a UTF-8 Unix-domain socket directory using a fixed PostgreSQL
-    /// port.
-    #[cfg(unix)]
-    pub fn unix_port(directory: impl Into, port: u16) -> Self {
-        Self::Unix {
-            directory: directory.into(),
-            port,
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) struct OpenConfig {
-    pub(crate) mode: EngineMode,
-    pub(crate) storage: DatabaseStorage,
-    pub(crate) broker: NativeBrokerConfig,
-    pub(crate) server: NativeServerConfig,
-    pub(crate) startup_gucs: Vec,
-    pub(crate) username: String,
-    pub(crate) database: String,
-    pub(crate) extensions: Vec,
-}
-
-impl OpenConfig {
-    #[cfg(test)]
-    pub(crate) fn direct(directory: impl Into) -> Self {
-        Self {
-            mode: EngineMode::Direct,
-            storage: DatabaseStorage::Directory(directory.into()),
-            broker: NativeBrokerConfig::default(),
-            server: NativeServerConfig::default(),
-            startup_gucs: Vec::new(),
-            username: DEFAULT_USERNAME.to_owned(),
-            database: DEFAULT_DATABASE.to_owned(),
-            extensions: Vec::new(),
-        }
-    }
-
-    pub(crate) fn validate(&self) -> Result<()> {
-        for guc in &self.startup_gucs {
-            validate_postgres_startup_guc(guc)?;
-            let name = guc.name.trim();
-            if ["config_file", "data_directory"]
-                .iter()
-                .any(|owned| name.eq_ignore_ascii_case(owned))
-            {
-                return Err(Error::InvalidConfig(format!(
-                    "Oliphaunt owns PostgreSQL startup GUC '{name}'; configure the database through Oliphaunt's storage API"
-                )));
-            }
-        }
-        if let DatabaseStorage::Directory(directory) = &self.storage {
-            validate_config_path("database storage directory", directory)?;
-        }
-        validate_startup_identity("username", &self.username)?;
-        validate_startup_identity("database", &self.database)?;
-        let _ = self.resolved_extensions()?;
-        match self.mode {
-            EngineMode::Broker => {
-                if let Some(executable) = &self.broker.executable {
-                    validate_config_path("native broker executable path", executable)?;
-                }
-            }
-            EngineMode::Server => {
-                for guc in &self.startup_gucs {
-                    let name = guc.name.trim();
-                    if ["listen_addresses", "port", "unix_socket_directories"]
-                        .iter()
-                        .any(|owned| name.eq_ignore_ascii_case(owned))
-                    {
-                        return Err(Error::InvalidConfig(format!(
-                            "native server owns PostgreSQL startup GUC '{name}'; configure its storage and listener through OliphauntServerBuilder"
-                        )));
-                    }
-                }
-                match &self.server.listen {
-                    ServerListen::Tcp { port: Some(0) } => {
-                        return Err(Error::InvalidConfig(
-                            "native TCP server port must be greater than zero; omit the port to allocate one"
-                                .to_owned(),
-                        ));
-                    }
-                    #[cfg(unix)]
-                    ServerListen::Unix { directory, port } => {
-                        validate_config_path("native server Unix socket directory", directory)?;
-                        let resolved_directory = if directory.is_absolute() {
-                            directory.clone()
-                        } else {
-                            std::env::current_dir()
-                                .map_err(|error| {
-                                    Error::Engine(format!(
-                                        "resolve current directory for native server Unix socket: {error}"
-                                    ))
-                                })?
-                                .join(directory)
-                        };
-                        server_unix_socket_directory_str(&resolved_directory)?;
-                        validate_server_unix_socket_path(&resolved_directory, *port)?;
-                        if *port == 0 {
-                            return Err(Error::InvalidConfig(
-                                "native Unix server port must be greater than zero".to_owned(),
-                            ));
-                        }
-                    }
-                    _ => {}
-                }
-                if let Some(executable) = &self.server.executable {
-                    validate_config_path("native server executable path", executable)?;
-                }
-            }
-            EngineMode::Direct => {}
-        }
-        Ok(())
-    }
-
-    pub(crate) fn resolved_extensions(&self) -> Result> {
-        resolve_extensions(&self.extensions)
-    }
-
-    pub(crate) fn postgres_startup_assignments(&self, extensions: &[Extension]) -> Vec {
-        let required_preloads = crate::extension::required_shared_preload_libraries(extensions);
-        if required_preloads.is_empty() {
-            return self
-                .startup_gucs
-                .iter()
-                .map(PostgresStartupGuc::startup_assignment)
-                .collect();
-        }
-
-        let configured_preloads = self
-            .startup_gucs
-            .iter()
-            .rev()
-            .find(|guc| {
-                guc.name
-                    .trim()
-                    .eq_ignore_ascii_case("shared_preload_libraries")
-            })
-            .map(|guc| guc.value.as_str());
-        let mut preloads = Vec::new();
-        let mut seen = BTreeSet::new();
-        if let Some(configured) = configured_preloads {
-            append_unique_csv_values(configured, &mut preloads, &mut seen);
-        }
-        for required in required_preloads {
-            append_unique_csv_values(required, &mut preloads, &mut seen);
-        }
-
-        let mut assignments = self
-            .startup_gucs
-            .iter()
-            .filter(|guc| {
-                !guc.name
-                    .trim()
-                    .eq_ignore_ascii_case("shared_preload_libraries")
-            })
-            .map(PostgresStartupGuc::startup_assignment)
-            .collect::>();
-        assignments.push(format!("shared_preload_libraries={}", preloads.join(",")));
-        assignments
-    }
-}
-
-fn append_unique_csv_values(value: &str, ordered: &mut Vec, seen: &mut BTreeSet) {
-    for item in value
-        .split(',')
-        .map(str::trim)
-        .filter(|item| !item.is_empty())
-    {
-        if seen.insert(item.to_owned()) {
-            ordered.push(item.to_owned());
-        }
-    }
-}
-
-fn validate_config_path(label: &str, path: &Path) -> Result<()> {
-    if path.as_os_str().is_empty() {
-        return Err(Error::InvalidConfig(format!("{label} must not be empty")));
-    }
-    if path_contains_nul(path) {
-        return Err(Error::InvalidConfig(format!(
-            "{label} must not contain NUL bytes"
-        )));
-    }
-    Ok(())
-}
-
-#[cfg(unix)]
-pub(crate) fn server_unix_socket_directory_str(directory: &Path) -> Result<&str> {
-    directory.to_str().ok_or_else(|| {
-        Error::InvalidConfig(
-            "native server Unix socket directory must be valid UTF-8 so the published PostgreSQL connection string preserves the exact path"
-                .to_owned(),
-        )
-    })
-}
-
-#[cfg(unix)]
-fn validate_server_unix_socket_path(directory: &Path, port: u16) -> Result<()> {
-    let socket = directory.join(format!(".s.PGSQL.{port}"));
-    if socket.as_os_str().len() >= 100 {
-        return Err(Error::InvalidConfig(format!(
-            "native server Unix socket path is too long: {}",
-            socket.display()
-        )));
-    }
-    Ok(())
-}
-
-fn validate_startup_identity(label: &str, value: &str) -> Result<()> {
-    if value.trim().is_empty() {
-        return Err(Error::InvalidConfig(format!("{label} must not be empty")));
-    }
-    if value.as_bytes().contains(&0) {
-        return Err(Error::InvalidConfig(format!(
-            "{label} must not contain NUL bytes"
-        )));
-    }
-    Ok(())
-}
-
-fn validate_postgres_startup_guc(guc: &PostgresStartupGuc) -> Result<()> {
-    let name = guc.name.trim();
-    if name.is_empty() {
-        return Err(Error::InvalidConfig(
-            "PostgreSQL startup GUC name must not be empty".to_owned(),
-        ));
-    }
-    if name.as_bytes().contains(&0) || guc.value.as_bytes().contains(&0) {
-        return Err(Error::InvalidConfig(
-            "PostgreSQL startup GUC must not contain NUL bytes".to_owned(),
-        ));
-    }
-    if !name.split('.').all(|component| {
-        let mut bytes = component.bytes();
-        bytes
-            .next()
-            .is_some_and(|byte| byte.is_ascii_alphabetic() || byte == b'_')
-            && bytes.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'$'))
-    }) {
-        return Err(Error::InvalidConfig(format!(
-            "PostgreSQL startup GUC name '{}': each dot-separated component must start with an ASCII letter or '_', followed by ASCII letters, digits, '_', or '$'",
-            guc.name
-        )));
-    }
-    Ok(())
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{EngineMode, OpenConfig, PostgresStartupGuc, ServerListen};
-
-    #[test]
-    fn startup_guc_names_use_portable_postgres_grammar() {
-        let mut config = OpenConfig::direct("target/test-roots/native-direct-guc-grammar");
-        config.startup_gucs = vec![
-            PostgresStartupGuc::new("_name", ""),
-            PostgresStartupGuc::new("ext.name$1", "on"),
-        ];
-        config.validate().unwrap();
-        assert_eq!(
-            config.postgres_startup_assignments(&[]),
-            ["_name=", "ext.name$1=on"]
-        );
-
-        for name in ["1name", ".foo", "a..b", "a.1b", "ext.$name"] {
-            config.startup_gucs = vec![PostgresStartupGuc::new(name, "1")];
-            assert!(
-                config.validate().is_err(),
-                "accepted invalid GUC name {name}"
-            );
-        }
-        config.startup_gucs = vec![PostgresStartupGuc::new("good", "bad\0value")];
-        assert!(config.validate().is_err());
-    }
-
-    #[test]
-    fn native_server_rejects_caller_owned_topology_gucs() {
-        for name in ["LISTEN_ADDRESSES", "port", "unix_socket_directories"] {
-            let mut config = OpenConfig::direct("target/test-roots/native-server-owned-guc");
-            config.mode = EngineMode::Server;
-            config.startup_gucs = vec![PostgresStartupGuc::new(name, "override")];
-
-            let error = config.validate().expect_err("server topology is SDK-owned");
-            assert!(error.to_string().contains("native server owns"), "{error}");
-        }
-    }
-
-    #[test]
-    fn every_native_topology_rejects_storage_redirection_gucs() {
-        for mode in [EngineMode::Direct, EngineMode::Broker, EngineMode::Server] {
-            for name in ["CONFIG_FILE", "data_directory"] {
-                let mut config = OpenConfig::direct("target/test-roots/native-owned-guc");
-                config.mode = mode;
-                config.startup_gucs = vec![PostgresStartupGuc::new(name, "/tmp/other")];
-
-                let error = config.validate().expect_err("storage is SDK-owned");
-                assert!(error.to_string().contains("Oliphaunt owns"), "{error}");
-            }
-        }
-    }
-
-    #[test]
-    fn server_listen_matches_shared_postgres_vocabulary() {
-        let fixture: serde_json::Value =
-            serde_json::from_str(&crate::test_fixtures::text("postgres/server-listen.json"))
-                .unwrap();
-        assert_eq!(fixture["tcp"]["host"], "127.0.0.1");
-        assert_eq!(fixture["unix"]["defaultPort"], 5432);
-        assert_eq!(fixture["unix"]["filePrefix"], ".s.PGSQL.");
-
-        let mut config = OpenConfig::direct("target/test-roots/native-server-listen");
-        config.mode = EngineMode::Server;
-        for port in fixture["tcp"]["validPorts"].as_array().unwrap() {
-            config.server.listen = ServerListen::tcp_port(port.as_u64().unwrap() as u16);
-            config.validate().unwrap();
-        }
-        config.server.listen = ServerListen::tcp_port(0);
-        assert!(config.validate().is_err());
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn server_listen_rejects_non_utf8_unix_socket_directory_without_mutation() {
-        use std::ffi::OsString;
-        use std::os::unix::ffi::OsStringExt;
-        use std::time::{SystemTime, UNIX_EPOCH};
-
-        let mut leaf = format!(
-            "oliphaunt-native-socket-{}-{}-",
-            std::process::id(),
-            SystemTime::now()
-                .duration_since(UNIX_EPOCH)
-                .expect("system clock should be after epoch")
-                .as_nanos()
-        )
-        .into_bytes();
-        leaf.push(0xff);
-        let directory = std::env::temp_dir().join(OsString::from_vec(leaf));
-        assert!(!directory.exists());
-
-        let mut config = OpenConfig::direct("target/test-roots/native-server-non-utf8-uri");
-        config.mode = EngineMode::Server;
-        config.server.listen = ServerListen::unix_port(directory.clone(), 15432);
-        let error = config
-            .validate()
-            .expect_err("a String connection URI cannot preserve a non-UTF-8 socket path");
-
-        assert!(error.to_string().contains("must be valid UTF-8"));
-        assert!(!directory.exists());
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn server_listen_rejects_too_long_unix_socket_path_without_mutation() {
-        let directory = std::env::temp_dir().join(format!(
-            "oliphaunt-native-socket-{}-{}",
-            std::process::id(),
-            "x".repeat(120)
-        ));
-        assert!(!directory.exists());
-
-        let mut config = OpenConfig::direct("target/test-roots/native-server-long-uri");
-        config.mode = EngineMode::Server;
-        config.server.listen = ServerListen::unix_port(directory.clone(), 15432);
-        let error = config
-            .validate()
-            .expect_err("Unix socket sockaddr length must be validated before root preparation");
-
-        assert!(error.to_string().contains("socket path is too long"));
-        assert!(!directory.exists());
-    }
-}
diff --git a/src/sdks/rust/src/error.rs b/src/sdks/rust/src/error.rs
deleted file mode 100644
index 56c87a95e..000000000
--- a/src/sdks/rust/src/error.rs
+++ /dev/null
@@ -1,575 +0,0 @@
-use std::convert::Infallible;
-use std::error;
-use std::fmt;
-
-pub use crate::query_core::{PostgresError, PostgresErrorField};
-
-/// Result alias used by the native SDK.
-pub type Result = std::result::Result;
-
-/// Result returned by a callback-scoped transaction.
-///
-/// `E` is the callback's application error type. The default keeps callbacks
-/// which use only SDK errors concise.
-pub type TransactionResult = std::result::Result>;
-
-/// Result returned by raw protocol streaming.
-///
-/// `E` is the callback's parser or application error type. The default is
-/// [`Infallible`] for callbacks which cannot fail deliberately.
-pub type RawStreamResult = std::result::Result>;
-
-mod raw_stream_callback_output {
-    pub trait Sealed {}
-
-    impl Sealed for () {}
-    impl Sealed for std::result::Result<(), E> {}
-}
-
-/// Supported return values from a raw protocol stream callback.
-///
-/// Return `()` for an infallible callback or `Result<(), E>` to stop delivery
-/// with a typed parser or application error. This trait is sealed so the two
-/// stable callback forms remain exhaustive.
-pub trait RawStreamCallbackOutput: raw_stream_callback_output::Sealed {
-    /// Typed callback failure, or [`Infallible`] for a callback returning `()`.
-    type Error;
-
-    /// Convert the callback output into its typed result.
-    #[doc(hidden)]
-    fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error>;
-}
-
-impl RawStreamCallbackOutput for () {
-    type Error = Infallible;
-
-    fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error> {
-        Ok(())
-    }
-}
-
-impl RawStreamCallbackOutput for std::result::Result<(), E> {
-    type Error = E;
-
-    fn into_raw_stream_callback_result(self) -> std::result::Result<(), Self::Error> {
-        self
-    }
-}
-
-/// Error from a callback-scoped transaction.
-///
-/// Callback code follows the Diesel/sqlx convention `E: From`, allowing
-/// SQL operations to use `?` while deliberate business aborts remain the
-/// caller's concrete `E`. If both the callback and rollback fail, both typed
-/// causes remain available.
-#[derive(Debug, Clone)]
-#[non_exhaustive]
-pub enum TransactionError {
-    /// `BEGIN`, `COMMIT`, explicit settlement, or another SDK operation failed.
-    Database(Error),
-    /// The callback deliberately aborted with an application error.
-    Callback(E),
-    /// The callback returned an error and an attempted rollback failed, possibly
-    /// together with releasing the transaction's owner pin.
-    CallbackAndRollback {
-        /// Error returned by the callback.
-        callback: E,
-        /// Error returned while rolling back or releasing the transaction pin.
-        rollback: Error,
-    },
-    /// The callback returned an error after an independent database, transport,
-    /// or protocol-recovery failure had already expired the transaction. No
-    /// rollback was attempted.
-    CallbackAndDatabase {
-        /// Error returned by the callback.
-        callback: E,
-        /// Independent SDK, database, transport, or recovery failure.
-        database: Error,
-    },
-}
-
-impl TransactionError {
-    /// Wrap a deliberate application-level transaction abort.
-    pub fn callback(error: E) -> Self {
-        Self::Callback(error)
-    }
-
-    /// Return the application error, including when rollback also failed.
-    pub fn callback_error(&self) -> Option<&E> {
-        match self {
-            Self::Callback(error) => Some(error),
-            Self::CallbackAndRollback { callback, .. } => Some(callback),
-            Self::CallbackAndDatabase { callback, .. } => Some(callback),
-            Self::Database(_) => None,
-        }
-    }
-
-    /// Return the SDK failure which occurred before callback settlement.
-    pub fn database_error(&self) -> Option<&Error> {
-        match self {
-            Self::Database(error)
-            | Self::CallbackAndDatabase {
-                database: error, ..
-            } => Some(error),
-            Self::Callback(_) | Self::CallbackAndRollback { .. } => None,
-        }
-    }
-
-    /// Return the attempted rollback or transaction-pin release failure.
-    pub fn rollback_error(&self) -> Option<&Error> {
-        match self {
-            Self::CallbackAndRollback { rollback, .. } => Some(rollback),
-            Self::Database(_) | Self::Callback(_) | Self::CallbackAndDatabase { .. } => None,
-        }
-    }
-}
-
-impl From for TransactionError {
-    fn from(error: Error) -> Self {
-        Self::Database(error)
-    }
-}
-
-impl From> for Error {
-    fn from(error: TransactionError) -> Self {
-        match error {
-            TransactionError::Database(error) => error,
-            TransactionError::Callback(error) => error,
-            TransactionError::CallbackAndRollback { callback, rollback } => {
-                Self::transaction_rollback(callback, rollback)
-            }
-            TransactionError::CallbackAndDatabase { callback, database } => {
-                Self::transaction_callback_and_database(callback, database)
-            }
-        }
-    }
-}
-
-impl fmt::Display for TransactionError
-where
-    E: fmt::Display,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Database(error) => error.fmt(f),
-            Self::Callback(error) => error.fmt(f),
-            Self::CallbackAndRollback { callback, rollback } => write!(
-                f,
-                "transaction callback failed: {callback}; rollback also failed: {rollback}"
-            ),
-            Self::CallbackAndDatabase { callback, database } => write!(
-                f,
-                "transaction callback failed: {callback}; an independent database failure also occurred: {database}"
-            ),
-        }
-    }
-}
-
-impl error::Error for TransactionError
-where
-    E: error::Error + 'static,
-{
-    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
-        match self {
-            Self::Database(error) => Some(error),
-            Self::Callback(error) => Some(error),
-            Self::CallbackAndRollback { callback, .. }
-            | Self::CallbackAndDatabase { callback, .. } => Some(callback),
-        }
-    }
-}
-
-/// Error from raw PostgreSQL protocol streaming.
-///
-/// A callback error is returned only after the runtime confirms recovery to
-/// `ReadyForQuery`. An independent runtime or transport failure is represented
-/// by [`Self::Database`] and remains authoritative.
-#[derive(Debug, Clone)]
-#[non_exhaustive]
-pub enum RawStreamError {
-    /// The SDK, runtime, transport, or recovery operation failed.
-    Database(Error),
-    /// The runtime recovered successfully after the callback returned this
-    /// parser or application error.
-    Callback(E),
-    /// An owner-thread callback panicked after the runtime confirmed
-    /// `ReadyForQuery`. Blocking APIs resume the original unwind instead.
-    CallbackPanicked(Error),
-}
-
-impl RawStreamError {
-    /// Return the recovered callback error.
-    pub fn callback_error(&self) -> Option<&E> {
-        match self {
-            Self::Callback(error) => Some(error),
-            Self::Database(_) | Self::CallbackPanicked(_) => None,
-        }
-    }
-
-    /// Return the authoritative SDK or recovery failure.
-    pub fn database_error(&self) -> Option<&Error> {
-        match self {
-            Self::Database(error) => Some(error),
-            Self::Callback(_) | Self::CallbackPanicked(_) => None,
-        }
-    }
-
-    /// Return a recovered owner-thread callback panic. This is distinct from
-    /// an independent database/recovery failure and does not imply poisoning.
-    pub fn callback_panic_error(&self) -> Option<&Error> {
-        match self {
-            Self::CallbackPanicked(error) => Some(error),
-            Self::Database(_) | Self::Callback(_) => None,
-        }
-    }
-}
-
-impl From for RawStreamError {
-    fn from(error: Error) -> Self {
-        Self::Database(error)
-    }
-}
-
-impl From> for Error {
-    fn from(error: RawStreamError) -> Self {
-        match error {
-            RawStreamError::Database(error) => error,
-            RawStreamError::Callback(never) => match never {},
-            RawStreamError::CallbackPanicked(error) => error,
-        }
-    }
-}
-
-impl From> for Error {
-    fn from(error: RawStreamError) -> Self {
-        match error {
-            RawStreamError::Database(error)
-            | RawStreamError::Callback(error)
-            | RawStreamError::CallbackPanicked(error) => error,
-        }
-    }
-}
-
-impl fmt::Display for RawStreamError
-where
-    E: fmt::Display,
-{
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Database(error) => error.fmt(f),
-            Self::Callback(error) => error.fmt(f),
-            Self::CallbackPanicked(error) => error.fmt(f),
-        }
-    }
-}
-
-impl error::Error for RawStreamError
-where
-    E: error::Error + 'static,
-{
-    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
-        match self {
-            Self::Database(error) => Some(error),
-            Self::Callback(error) => Some(error),
-            Self::CallbackPanicked(error) => Some(error),
-        }
-    }
-}
-
-pub(crate) const SESSION_STATE_UNKNOWN: &str =
-    "PostgreSQL session state is unknown; close the database";
-
-/// Stable category for an Oliphaunt SDK error.
-///
-/// Match this value when an application needs recovery policy. The concrete
-/// [`Error`] remains opaque so implementation details and platform-specific
-/// causes can evolve without expanding a public error enum.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-#[non_exhaustive]
-pub enum ErrorKind {
-    /// A builder option or other caller-supplied configuration is invalid.
-    InvalidConfiguration,
-    /// The requested work crossed a database or owner lifecycle boundary.
-    Lifecycle,
-    /// Root work was rejected because a callback transaction owns the session.
-    TransactionActive,
-    /// PostgreSQL returned a structured `ErrorResponse`.
-    Postgres,
-    /// An engine, protocol, storage, transport, callback, or other failure.
-    Other,
-}
-
-/// Opaque error returned by the native Rust SDK.
-#[derive(Debug, Clone)]
-pub struct Error {
-    inner: ErrorInner,
-}
-
-#[derive(Debug, Clone)]
-enum ErrorInner {
-    EngineStopped,
-    Engine(String),
-    Postgres(Box),
-    TransactionActive,
-    TransactionRollback {
-        callback: Box,
-        rollback: Box,
-    },
-    TransactionCallbackAndDatabase {
-        callback: Box,
-        database: Box,
-    },
-    InvalidConfiguration(String),
-}
-
-impl Error {
-    /// Return the stable recovery category for this failure.
-    pub const fn kind(&self) -> ErrorKind {
-        match &self.inner {
-            ErrorInner::EngineStopped => ErrorKind::Lifecycle,
-            ErrorInner::Postgres(_) => ErrorKind::Postgres,
-            ErrorInner::TransactionActive => ErrorKind::TransactionActive,
-            ErrorInner::InvalidConfiguration(_) => ErrorKind::InvalidConfiguration,
-            ErrorInner::Engine(_)
-            | ErrorInner::TransactionRollback { .. }
-            | ErrorInner::TransactionCallbackAndDatabase { .. } => ErrorKind::Other,
-        }
-    }
-
-    /// Return structured PostgreSQL diagnostics when this is a backend error.
-    pub fn postgres_error(&self) -> Option<&PostgresError> {
-        match &self.inner {
-            ErrorInner::Postgres(error) => Some(error.as_ref()),
-            _ => None,
-        }
-    }
-
-    /// Return both failures when a transaction callback and rollback failed.
-    pub fn transaction_rollback_errors(&self) -> Option<(&Error, &Error)> {
-        match &self.inner {
-            ErrorInner::TransactionRollback { callback, rollback } => {
-                Some((callback.as_ref(), rollback.as_ref()))
-            }
-            _ => None,
-        }
-    }
-
-    /// Return both failures when a callback error follows an independent
-    /// database or protocol failure. This pair never implies that rollback ran.
-    pub fn transaction_callback_database_errors(&self) -> Option<(&Error, &Error)> {
-        match &self.inner {
-            ErrorInner::TransactionCallbackAndDatabase { callback, database } => {
-                Some((callback.as_ref(), database.as_ref()))
-            }
-            _ => None,
-        }
-    }
-
-    #[allow(non_upper_case_globals)]
-    pub(crate) const EngineStopped: Self = Self {
-        inner: ErrorInner::EngineStopped,
-    };
-
-    #[allow(non_upper_case_globals)]
-    pub(crate) const TransactionActive: Self = Self {
-        inner: ErrorInner::TransactionActive,
-    };
-
-    #[allow(non_snake_case)]
-    pub(crate) fn Engine(message: String) -> Self {
-        Self {
-            inner: ErrorInner::Engine(message),
-        }
-    }
-
-    #[allow(non_snake_case)]
-    pub(crate) fn Postgres(error: Box) -> Self {
-        Self {
-            inner: ErrorInner::Postgres(error),
-        }
-    }
-
-    #[allow(non_snake_case)]
-    pub(crate) fn InvalidConfig(message: String) -> Self {
-        Self {
-            inner: ErrorInner::InvalidConfiguration(message),
-        }
-    }
-
-    fn transaction_rollback(callback: Self, rollback: Self) -> Self {
-        Self {
-            inner: ErrorInner::TransactionRollback {
-                callback: Box::new(callback),
-                rollback: Box::new(rollback),
-            },
-        }
-    }
-
-    fn transaction_callback_and_database(callback: Self, database: Self) -> Self {
-        Self {
-            inner: ErrorInner::TransactionCallbackAndDatabase {
-                callback: Box::new(callback),
-                database: Box::new(database),
-            },
-        }
-    }
-}
-
-impl fmt::Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match &self.inner {
-            ErrorInner::EngineStopped => f.write_str("native database session has stopped"),
-            ErrorInner::Engine(message) => f.write_str(message),
-            ErrorInner::Postgres(error) => error.fmt(f),
-            ErrorInner::TransactionActive => {
-                f.write_str("a transaction is active; use the active transaction handle")
-            }
-            ErrorInner::TransactionRollback { callback, rollback } => write!(
-                f,
-                "transaction callback failed: {callback}; rollback also failed: {rollback}"
-            ),
-            ErrorInner::TransactionCallbackAndDatabase { callback, database } => write!(
-                f,
-                "transaction callback failed: {callback}; an independent database failure also occurred: {database}"
-            ),
-            ErrorInner::InvalidConfiguration(message) => f.write_str(message),
-        }
-    }
-}
-
-impl error::Error for Error {
-    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
-        match &self.inner {
-            ErrorInner::Postgres(error) => Some(error.as_ref()),
-            ErrorInner::TransactionRollback { callback, .. }
-            | ErrorInner::TransactionCallbackAndDatabase { callback, .. } => {
-                Some(callback.as_ref())
-            }
-            _ => None,
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::query_core as core;
-
-    #[test]
-    fn localized_severity_is_primary_and_both_forms_remain_available() {
-        let fields = vec![
-            PostgresErrorField {
-                code: b'S',
-                value: "ERREUR".to_owned(),
-            },
-            PostgresErrorField {
-                code: b'V',
-                value: "ERROR".to_owned(),
-            },
-            PostgresErrorField {
-                code: b'M',
-                value: "failure".to_owned(),
-            },
-            PostgresErrorField {
-                code: b'p',
-                value: "12".to_owned(),
-            },
-            PostgresErrorField {
-                code: b'q',
-                value: "SELECT broken".to_owned(),
-            },
-            PostgresErrorField {
-                code: b'F',
-                value: "parse_expr.c".to_owned(),
-            },
-            PostgresErrorField {
-                code: b'L',
-                value: "123".to_owned(),
-            },
-            PostgresErrorField {
-                code: b'R',
-                value: "transformExpr".to_owned(),
-            },
-        ];
-        let diagnostic_fields = fields
-            .into_iter()
-            .map(|field| core::DiagnosticField {
-                code: field.code,
-                value: field.value,
-            })
-            .collect();
-        let error = PostgresError::from_core(core::diagnostic(
-            diagnostic_fields,
-            "PostgreSQL ErrorResponse",
-        ));
-        assert_eq!(error.severity.as_deref(), Some("ERREUR"));
-        assert_eq!(error.localized_severity.as_deref(), Some("ERREUR"));
-        assert_eq!(error.nonlocalized_severity.as_deref(), Some("ERROR"));
-        assert_eq!(error.internal_position.as_deref(), Some("12"));
-        assert_eq!(error.internal_query.as_deref(), Some("SELECT broken"));
-        assert_eq!(error.file.as_deref(), Some("parse_expr.c"));
-        assert_eq!(error.line.as_deref(), Some("123"));
-        assert_eq!(error.routine.as_deref(), Some("transformExpr"));
-    }
-
-    #[test]
-    fn stable_accessors_preserve_typed_failures() {
-        let postgres = PostgresError::from_core(core::diagnostic(
-            vec![core::DiagnosticField {
-                code: b'C',
-                value: "23505".to_owned(),
-            }],
-            "duplicate key",
-        ));
-        let postgres = Error::Postgres(Box::new(postgres));
-        assert_eq!(
-            postgres
-                .postgres_error()
-                .and_then(|error| error.sqlstate.as_deref()),
-            Some("23505")
-        );
-        assert!(postgres.transaction_rollback_errors().is_none());
-
-        let rollback = Error::transaction_rollback(
-            Error::Engine("callback".to_owned()),
-            Error::Engine("rollback".to_owned()),
-        );
-        let (callback, rollback_error) = rollback
-            .transaction_rollback_errors()
-            .expect("composite error remains typed");
-        assert_eq!(callback.to_string(), "callback");
-        assert_eq!(rollback_error.to_string(), "rollback");
-        assert!(rollback.postgres_error().is_none());
-
-        let transaction = TransactionError::CallbackAndDatabase {
-            callback: Error::Engine("callback".to_owned()),
-            database: Error::Engine("stream recovery".to_owned()),
-        };
-        assert!(transaction.rollback_error().is_none());
-        assert_eq!(
-            transaction
-                .database_error()
-                .map(ToString::to_string)
-                .as_deref(),
-            Some("stream recovery")
-        );
-        let flattened: Error = transaction.into();
-        let (callback, database) = flattened
-            .transaction_callback_database_errors()
-            .expect("callback and independent database failure remain typed");
-        assert_eq!(callback.to_string(), "callback");
-        assert_eq!(database.to_string(), "stream recovery");
-
-        let panic = RawStreamError::::CallbackPanicked(Error::Engine(
-            "callback panicked".to_owned(),
-        ));
-        assert!(panic.database_error().is_none());
-        assert_eq!(
-            panic
-                .callback_panic_error()
-                .map(ToString::to_string)
-                .as_deref(),
-            Some("callback panicked")
-        );
-    }
-}
diff --git a/src/sdks/rust/src/executor.rs b/src/sdks/rust/src/executor.rs
deleted file mode 100644
index 8e6c78f87..000000000
--- a/src/sdks/rust/src/executor.rs
+++ /dev/null
@@ -1,2841 +0,0 @@
-use std::any::Any;
-use std::collections::VecDeque;
-use std::future::poll_fn;
-use std::panic::{AssertUnwindSafe, catch_unwind};
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Condvar, Mutex, OnceLock};
-use std::task::{Context, Poll, Waker};
-use std::thread;
-
-use crate::cancellation::CancellationGate;
-use crate::engine::{EngineSession, ProtocolStreamOutcome};
-use crate::error::{Error, Result, SESSION_STATE_UNKNOWN};
-use crate::protocol::{ProtocolRequest, ProtocolResponse};
-use crate::query::{ReadyStatus, parse_simple_command_response};
-use crate::reply;
-use crate::session::{
-    TransactionGuard, begin_transaction, execute_structured_operation,
-    execute_transaction_structured_operation, inactive_transaction_error,
-};
-
-type ProtocolChunkCallback = Box Result<()> + Send>;
-
-pub(crate) enum ExecutorStreamOutcome {
-    ReadyForQuery(Result<()>),
-    CallbackPanicked(Error),
-    SessionStateUnknown(Error),
-}
-
-impl ExecutorStreamOutcome {
-    #[cfg(test)]
-    fn into_result(self) -> Result<()> {
-        match self {
-            Self::ReadyForQuery(result) => result,
-            Self::CallbackPanicked(error) | Self::SessionStateUnknown(error) => Err(error),
-        }
-    }
-}
-
-/// Ordinary application work is bounded. Lifecycle and transaction-recovery
-/// commands share the same FIFO but do not consume this capacity, so cleanup
-/// can always be admitted without inventing a public queue-tuning surface.
-const ORDINARY_QUEUE_CAPACITY: usize = 256;
-
-pub(crate) struct EngineExecutor {
-    shared: Arc,
-}
-
-struct ExecutorShared {
-    queue: CommandQueue,
-    // SQL admission and the owner-side transition into teardown share this
-    // lock. Out-of-band cancellation has its own counted lifecycle gate.
-    admission: Mutex<()>,
-    cancellation: Arc,
-    active_work: AtomicBool,
-    session_pinned: AtomicBool,
-    transaction_poisoned: AtomicBool,
-    // This is an admission cutoff, not an owner-side execution predicate.
-    // Commands already ahead of `Command::Close` must run even while it is set.
-    closing: AtomicBool,
-    teardown_started: AtomicBool,
-    closed: AtomicBool,
-    terminal_drop: AtomicBool,
-    close_state: Mutex,
-    owner_thread: OnceLock,
-}
-
-impl ExecutorShared {
-    fn new() -> Self {
-        Self {
-            queue: CommandQueue::new(),
-            admission: Mutex::new(()),
-            cancellation: CancellationGate::pending(),
-            active_work: AtomicBool::new(false),
-            session_pinned: AtomicBool::new(false),
-            transaction_poisoned: AtomicBool::new(false),
-            closing: AtomicBool::new(false),
-            teardown_started: AtomicBool::new(false),
-            closed: AtomicBool::new(false),
-            terminal_drop: AtomicBool::new(false),
-            close_state: Mutex::new(CloseState::default()),
-            owner_thread: OnceLock::new(),
-        }
-    }
-}
-
-#[derive(Default)]
-struct CloseState {
-    in_progress: bool,
-    terminal_result: Option>,
-    waiters: Vec>,
-}
-
-struct CommandQueue {
-    state: Mutex,
-    ready: Condvar,
-}
-
-struct CommandQueueState {
-    commands: VecDeque,
-    ordinary_count: usize,
-    admission_waiters: VecDeque,
-    stopped: bool,
-}
-
-struct AdmissionWaiter {
-    token: Arc,
-    waker: Waker,
-}
-
-struct AdmissionToken {
-    rejected: AtomicBool,
-}
-
-struct AdmissionRegistration<'queue> {
-    queue: &'queue CommandQueue,
-    // The uncontended path does not allocate. A stable token is created only
-    // if this operation actually has to join the capacity-waiter FIFO.
-    token: Option>,
-}
-
-impl<'queue> AdmissionRegistration<'queue> {
-    fn new(queue: &'queue CommandQueue) -> Self {
-        Self { queue, token: None }
-    }
-}
-
-impl Drop for AdmissionRegistration<'_> {
-    fn drop(&mut self) {
-        if let Some(token) = &self.token {
-            self.queue.cancel_admission(token);
-        }
-    }
-}
-
-impl CommandQueue {
-    fn new() -> Self {
-        Self {
-            state: Mutex::new(CommandQueueState {
-                commands: VecDeque::new(),
-                ordinary_count: 0,
-                admission_waiters: VecDeque::new(),
-                stopped: false,
-            }),
-            ready: Condvar::new(),
-        }
-    }
-
-    fn send_control(&self, command: Command) -> Result<()> {
-        debug_assert!(!command.is_ordinary());
-        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
-        if state.stopped {
-            return Err(Error::EngineStopped);
-        }
-        state.commands.push_back(command);
-        self.ready.notify_one();
-        Ok(())
-    }
-
-    fn poll_send_ordinary(
-        &self,
-        token: &mut Option>,
-        command: &mut Option,
-        cx: &mut Context<'_>,
-    ) -> (Poll>, Option) {
-        debug_assert!(command.as_ref().is_some_and(Command::is_ordinary));
-        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
-        if state.stopped
-            || token
-                .as_ref()
-                .is_some_and(|token| token.rejected.load(Ordering::SeqCst))
-        {
-            return (Poll::Ready(Err(Error::EngineStopped)), None);
-        }
-
-        let position = token.as_ref().and_then(|token| {
-            state
-                .admission_waiters
-                .iter()
-                .position(|waiter| Arc::ptr_eq(&waiter.token, token))
-        });
-        let is_next = match position {
-            Some(0) => true,
-            Some(_) => false,
-            None => state.admission_waiters.is_empty(),
-        };
-        if state.ordinary_count < ORDINARY_QUEUE_CAPACITY && is_next {
-            if position.is_some() {
-                state.admission_waiters.pop_front();
-            }
-            state.ordinary_count += 1;
-            state
-                .commands
-                .push_back(command.take().expect("ordinary command is admitted once"));
-            let next = (state.ordinary_count < ORDINARY_QUEUE_CAPACITY)
-                .then(|| {
-                    state
-                        .admission_waiters
-                        .front()
-                        .map(|waiter| waiter.waker.clone())
-                })
-                .flatten();
-            self.ready.notify_one();
-            return (Poll::Ready(Ok(())), next);
-        }
-
-        let token = token.get_or_insert_with(|| {
-            Arc::new(AdmissionToken {
-                rejected: AtomicBool::new(false),
-            })
-        });
-        match position {
-            Some(position) => {
-                let waiter = &mut state.admission_waiters[position];
-                if !waiter.waker.will_wake(cx.waker()) {
-                    waiter.waker = cx.waker().clone();
-                }
-            }
-            None => state.admission_waiters.push_back(AdmissionWaiter {
-                token: Arc::clone(token),
-                waker: cx.waker().clone(),
-            }),
-        }
-        (Poll::Pending, None)
-    }
-
-    fn cancel_admission(&self, token: &Arc) {
-        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
-        let Some(position) = state
-            .admission_waiters
-            .iter()
-            .position(|waiter| Arc::ptr_eq(&waiter.token, token))
-        else {
-            return;
-        };
-        let was_next = position == 0;
-        state.admission_waiters.remove(position);
-        let next = (was_next && state.ordinary_count < ORDINARY_QUEUE_CAPACITY)
-            .then(|| {
-                state
-                    .admission_waiters
-                    .front()
-                    .map(|waiter| waiter.waker.clone())
-            })
-            .flatten();
-        drop(state);
-        if let Some(waker) = next {
-            waker.wake();
-        }
-    }
-
-    fn reject_admissions(&self) -> Vec {
-        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
-        state
-            .admission_waiters
-            .drain(..)
-            .map(|waiter| {
-                waiter.token.rejected.store(true, Ordering::SeqCst);
-                waiter.waker
-            })
-            .collect()
-    }
-
-    fn receive(&self) -> Option {
-        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
-        loop {
-            if let Some(command) = state.commands.pop_front() {
-                if command.is_ordinary() {
-                    state.ordinary_count -= 1;
-                }
-                let next = state
-                    .admission_waiters
-                    .front()
-                    .map(|waiter| waiter.waker.clone());
-                drop(state);
-                if let Some(waker) = next {
-                    waker.wake();
-                }
-                return Some(command);
-            }
-            if state.stopped {
-                return None;
-            }
-            state = self
-                .ready
-                .wait(state)
-                .unwrap_or_else(|error| error.into_inner());
-        }
-    }
-
-    fn stop(&self) -> Vec {
-        let mut state = self.state.lock().unwrap_or_else(|error| error.into_inner());
-        state.stopped = true;
-        state.ordinary_count = 0;
-        let pending = state.commands.drain(..).collect();
-        let wakers = state
-            .admission_waiters
-            .drain(..)
-            .map(|waiter| {
-                waiter.token.rejected.store(true, Ordering::SeqCst);
-                waiter.waker
-            })
-            .collect::>();
-        self.ready.notify_all();
-        drop(state);
-        for waker in wakers {
-            waker.wake();
-        }
-        pending
-    }
-}
-
-impl EngineExecutor {
-    /// Construct a runtime session on the thread which permanently owns it.
-    pub(crate) async fn open(
-        thread_name: &'static str,
-        operation: F,
-    ) -> Result<(Arc, M)>
-    where
-        M: Send + 'static,
-        F: FnOnce() -> Result<(Box, M)> + Send + 'static,
-    {
-        let (executor, opened) = Self::start_owner(thread_name, operation)?;
-        let metadata = opened.await?;
-        Ok((executor, metadata))
-    }
-
-    fn start_owner(
-        thread_name: &'static str,
-        operation: F,
-    ) -> Result<(Arc, reply::Receiver)>
-    where
-        M: Send + 'static,
-        F: FnOnce() -> Result<(Box, M)> + Send + 'static,
-    {
-        let shared = Arc::new(ExecutorShared::new());
-        let executor = Arc::new(Self {
-            shared: Arc::clone(&shared),
-        });
-        let (opened, receiver) = reply::channel();
-        thread::Builder::new()
-            .name(thread_name.to_owned())
-            .spawn(move || owner_thread(shared, opened, operation, thread_name))
-            .map_err(|error| Error::Engine(format!("failed to start {thread_name}: {error}")))?;
-        Ok((executor, receiver))
-    }
-
-    #[cfg(test)]
-    pub(crate) fn spawn(session: Box) -> Arc {
-        use std::future::Future;
-        use std::task::{Context, Poll, Wake, Waker};
-
-        struct ThreadWake(thread::Thread);
-
-        impl Wake for ThreadWake {
-            fn wake(self: Arc) {
-                self.0.unpark();
-            }
-        }
-
-        let (executor, opened) =
-            Self::start_owner("oliphaunt-test-owner", move || Ok((session, ())))
-                .expect("spawn test owner thread");
-        let mut opened = std::pin::pin!(opened);
-        let waker = Waker::from(Arc::new(ThreadWake(thread::current())));
-        let mut context = Context::from_waker(&waker);
-        loop {
-            match opened.as_mut().poll(&mut context) {
-                Poll::Ready(result) => {
-                    result.expect("test owner opens");
-                    break;
-                }
-                Poll::Pending => thread::park(),
-            }
-        }
-        executor
-    }
-
-    pub(crate) async fn cancel(&self) -> Result<()> {
-        // `closing` is only an ordinary-work cutoff. Cancellation is
-        // out-of-band and remains useful while already-admitted SQL drains.
-        // The counted cancellation gate orders this request exactly before or
-        // after destructive teardown and lets close wait for admitted calls.
-        let cancellation = self.shared.cancellation.admit()?;
-        run_off_thread("oliphaunt-cancel", move || cancellation.cancel()).await
-    }
-
-    pub(crate) async fn exec_protocol_raw(
-        &self,
-        request: ProtocolRequest,
-    ) -> Result {
-        let (reply, receiver) = reply::channel();
-        self.send(Command::Exec { request, reply }).await?;
-        receiver.await
-    }
-
-    pub(crate) async fn exec_structured(
-        &self,
-        request: ProtocolRequest,
-        operation: impl Into,
-    ) -> Result {
-        let (reply, receiver) = reply::channel();
-        self.send(Command::StructuredExec {
-            request,
-            operation: operation.into(),
-            reply,
-        })
-        .await?;
-        receiver.await
-    }
-
-    pub(crate) async fn pinned_exec_protocol_control(
-        &self,
-        token: u64,
-        request: ProtocolRequest,
-        guard: Arc,
-    ) -> Result {
-        let (reply, receiver) = reply::channel();
-        let command = Command::PinnedExec {
-            token,
-            request,
-            guard,
-            reply,
-        };
-        self.send_transaction_settlement(command)?;
-        receiver.await
-    }
-
-    pub(crate) async fn pinned_exec_structured(
-        &self,
-        token: u64,
-        request: ProtocolRequest,
-        operation: impl Into,
-        guard: Arc,
-    ) -> Result {
-        let (reply, receiver) = reply::channel();
-        self.send(Command::PinnedStructuredExec {
-            token,
-            request,
-            operation: operation.into(),
-            guard,
-            reply,
-        })
-        .await?;
-        receiver.await
-    }
-
-    #[cfg(test)]
-    pub(crate) async fn exec_protocol_raw_stream(
-        &self,
-        request: ProtocolRequest,
-        on_chunk: F,
-    ) -> Result<()>
-    where
-        F: FnMut(&[u8]) -> Result<()> + Send + 'static,
-    {
-        self.exec_protocol_raw_stream_outcome(request, on_chunk)
-            .await?
-            .into_result()
-    }
-
-    pub(crate) async fn exec_protocol_raw_stream_outcome(
-        &self,
-        request: ProtocolRequest,
-        on_chunk: F,
-    ) -> Result
-    where
-        F: FnMut(&[u8]) -> Result<()> + Send + 'static,
-    {
-        let (reply, receiver) = reply::channel();
-        self.send(Command::Stream {
-            request,
-            on_chunk: Box::new(on_chunk),
-            reply,
-        })
-        .await?;
-        receiver.await
-    }
-
-    pub(crate) async fn begin_transaction(&self) -> Result {
-        let (reply, receiver) = reply::channel();
-        self.send(Command::Begin { reply }).await?;
-        receiver.await
-    }
-
-    pub(crate) async fn release_pin(&self, token: u64) -> Result<()> {
-        let (reply, receiver) = reply::channel();
-        self.send_cleanup(Command::ReleasePin {
-            token,
-            reply: Some(reply),
-        })?;
-        receiver.await
-    }
-
-    pub(crate) fn release_pin_best_effort(&self, token: u64) {
-        let _ = self.send_cleanup(Command::ReleasePin { token, reply: None });
-    }
-
-    pub(crate) fn rollback_and_release_pin_best_effort(&self, token: u64) {
-        let _ = self.send_cleanup(Command::RollbackAndReleasePin { token });
-    }
-
-    pub(crate) fn poison_transaction_state(&self) {
-        self.shared
-            .transaction_poisoned
-            .store(true, Ordering::SeqCst);
-    }
-
-    pub(crate) fn is_closed(&self) -> bool {
-        self.shared.closed.load(Ordering::SeqCst)
-    }
-
-    #[cfg(test)]
-    pub(crate) fn session_is_pinned(&self) -> bool {
-        self.shared.session_pinned.load(Ordering::SeqCst)
-    }
-
-    pub(crate) async fn backup(&self) -> Result> {
-        let (reply, receiver) = reply::channel();
-        self.send(Command::Backup { reply }).await?;
-        receiver.await
-    }
-
-    pub(crate) async fn close(&self) -> Result<()> {
-        self.ensure_not_owner_thread()?;
-        let (reply, receiver) = reply::channel();
-        let mut rejected_admissions = Vec::new();
-        {
-            // Setting the cutoff and appending Close happen under the same
-            // admission lock used by every command submission. Commands that
-            // acquired admission first are ahead of Close and drain; commands
-            // that acquire it later observe `closing` and are rejected.
-            let _admission = self.shared.admission.lock().map_err(|_| {
-                Error::Engine("database command admission lock was poisoned".to_owned())
-            })?;
-            let mut close = self
-                .shared
-                .close_state
-                .lock()
-                .unwrap_or_else(|error| error.into_inner());
-            if let Some(result) = &close.terminal_result {
-                return result.clone();
-            }
-            if close.in_progress {
-                close.waiters.push(reply);
-            } else {
-                close.in_progress = true;
-                close.waiters.push(reply);
-                self.shared.closing.store(true, Ordering::SeqCst);
-                // Mark every already-registered capacity waiter while the
-                // admission cutoff is held. Waking is deferred until after the
-                // lock is released so even a synchronous waker cannot deadlock.
-                rejected_admissions = self.shared.queue.reject_admissions();
-                if let Err(error) = self.shared.queue.send_control(Command::Close) {
-                    drop(close);
-                    complete_terminal_close(&self.shared, Err(error));
-                }
-            }
-        }
-        for waker in rejected_admissions {
-            waker.wake();
-        }
-        receiver.await
-    }
-
-    async fn send(&self, command: Command) -> Result<()> {
-        debug_assert!(command.is_ordinary());
-        let mut registration = AdmissionRegistration::new(&self.shared.queue);
-        let mut command = Some(command);
-        poll_fn(|cx| {
-            if let Err(error) = self.ensure_not_owner_thread() {
-                return Poll::Ready(Err(error));
-            }
-            let (poll, next) = {
-                let _admission = match self.shared.admission.lock() {
-                    Ok(admission) => admission,
-                    Err(_) => {
-                        return Poll::Ready(Err(Error::Engine(
-                            "database command admission lock was poisoned".to_owned(),
-                        )));
-                    }
-                };
-                if self.shared.closed.load(Ordering::SeqCst)
-                    || self.shared.closing.load(Ordering::SeqCst)
-                {
-                    return Poll::Ready(Err(Error::EngineStopped));
-                }
-                if self.shared.transaction_poisoned.load(Ordering::SeqCst) {
-                    return Poll::Ready(Err(Error::Engine(SESSION_STATE_UNKNOWN.to_owned())));
-                }
-                self.shared
-                    .queue
-                    .poll_send_ordinary(&mut registration.token, &mut command, cx)
-            };
-            if let Some(waker) = next {
-                waker.wake();
-            }
-            poll
-        })
-        .await
-    }
-
-    /// COMMIT and ROLLBACK are required settlement for an existing pin, not
-    /// new application work. A transaction whose BEGIN was admitted before a
-    /// close cutoff must still be able to enqueue that settlement behind the
-    /// cutoff. The owner validates the pin token when the command reaches it.
-    fn send_transaction_settlement(&self, command: Command) -> Result<()> {
-        self.ensure_not_owner_thread()?;
-        let _admission = self.shared.admission.lock().map_err(|_| {
-            Error::Engine("database command admission lock was poisoned".to_owned())
-        })?;
-        if self.shared.closed.load(Ordering::SeqCst)
-            || self.shared.teardown_started.load(Ordering::SeqCst)
-        {
-            return Err(Error::EngineStopped);
-        }
-        self.shared.queue.send_control(command)
-    }
-
-    /// Cleanup stays admissible after poisoning or a close cutoff and does not
-    /// consume ordinary queue capacity. It retains FIFO order with
-    /// already-admitted SQL and Close; the owner decides whether Close can
-    /// proceed before later transaction cleanup.
-    fn send_cleanup(&self, command: Command) -> Result<()> {
-        let _admission = self.shared.admission.lock().map_err(|_| {
-            Error::Engine("database command admission lock was poisoned".to_owned())
-        })?;
-        if self.shared.closed.load(Ordering::SeqCst)
-            || self.shared.teardown_started.load(Ordering::SeqCst)
-        {
-            return Err(Error::EngineStopped);
-        }
-        self.shared.queue.send_control(command)
-    }
-
-    fn ensure_not_owner_thread(&self) -> Result<()> {
-        if self
-            .shared
-            .owner_thread
-            .get()
-            .is_some_and(|owner| *owner == thread::current().id())
-        {
-            return Err(Error::Engine(
-                "reentrant database work from a raw-stream callback is not supported".to_owned(),
-            ));
-        }
-        Ok(())
-    }
-}
-
-impl Drop for EngineExecutor {
-    fn drop(&mut self) {
-        if self.shared.closed.load(Ordering::SeqCst) {
-            return;
-        }
-        // Dropping JoinHandle detaches in Rust; this executor intentionally
-        // owns no handle to join. Final drop only establishes a terminal close
-        // request and returns immediately.
-        self.shared.terminal_drop.store(true, Ordering::SeqCst);
-        schedule_terminal_drop_close(&self.shared);
-    }
-}
-
-enum Command {
-    Exec {
-        request: ProtocolRequest,
-        reply: reply::Sender,
-    },
-    StructuredExec {
-        request: ProtocolRequest,
-        operation: String,
-        reply: reply::Sender,
-    },
-    PinnedExec {
-        token: u64,
-        request: ProtocolRequest,
-        guard: Arc,
-        reply: reply::Sender,
-    },
-    PinnedStructuredExec {
-        token: u64,
-        request: ProtocolRequest,
-        operation: String,
-        guard: Arc,
-        reply: reply::Sender,
-    },
-    Stream {
-        request: ProtocolRequest,
-        on_chunk: ProtocolChunkCallback,
-        reply: reply::Sender,
-    },
-    Begin {
-        reply: reply::Sender,
-    },
-    ReleasePin {
-        token: u64,
-        reply: Option>,
-    },
-    RollbackAndReleasePin {
-        token: u64,
-    },
-    Backup {
-        reply: reply::Sender>,
-    },
-    Close,
-}
-
-impl Command {
-    fn is_ordinary(&self) -> bool {
-        !matches!(
-            self,
-            Self::PinnedExec { .. }
-                | Self::ReleasePin { .. }
-                | Self::RollbackAndReleasePin { .. }
-                | Self::Close
-        )
-    }
-
-    fn is_abandoned(&self) -> bool {
-        match self {
-            Self::Exec { reply, .. }
-            | Self::StructuredExec { reply, .. }
-            | Self::PinnedStructuredExec { reply, .. } => reply.is_abandoned(),
-            Self::Stream { reply, .. } => reply.is_abandoned(),
-            Self::Begin { reply } => reply.is_abandoned(),
-            Self::Backup { reply } => reply.is_abandoned(),
-            Self::PinnedExec { .. }
-            | Self::ReleasePin { .. }
-            | Self::RollbackAndReleasePin { .. }
-            | Self::Close => false,
-        }
-    }
-}
-
-struct OwnerState {
-    active_pin: Option,
-    next_pin: u64,
-}
-
-enum OwnerAction {
-    Continue,
-    RetryableClose(Error),
-    TerminalClose(Result<()>),
-}
-
-fn owner_thread(
-    shared: Arc,
-    opened: reply::Sender,
-    operation: F,
-    thread_name: &'static str,
-) where
-    M: Send + 'static,
-    F: FnOnce() -> Result<(Box, M)>,
-{
-    let _ = shared.owner_thread.set(thread::current().id());
-    let opened_session = catch_unwind(AssertUnwindSafe(operation)).unwrap_or_else(|panic| {
-        Err(Error::Engine(format!(
-            "{thread_name} panicked while opening: {}",
-            panic_message(panic.as_ref())
-        )))
-    });
-    let (session, metadata) = match opened_session {
-        Ok(opened_session) => opened_session,
-        Err(error) => {
-            opened.send(Err(error));
-            stop_owner(&shared);
-            return;
-        }
-    };
-    let cancel = match catch_unwind(AssertUnwindSafe(|| session.cancel_handle())) {
-        Ok(cancel) => cancel,
-        Err(panic) => {
-            opened.send(Err(Error::Engine(format!(
-                "{thread_name} panicked while obtaining its cancellation handle: {}",
-                panic_message(panic.as_ref())
-            ))));
-            dispose_session_after_owner_failure(session);
-            stop_owner(&shared);
-            return;
-        }
-    };
-    if let Err(error) = shared.cancellation.install_target(cancel) {
-        opened.send(Err(error));
-        dispose_session_after_owner_failure(session);
-        stop_owner(&shared);
-        return;
-    }
-    let mut session = Some(session);
-    if !opened.send(Ok(metadata)) {
-        dispose_session_after_owner_failure(session.take().expect("opened session"));
-        stop_owner(&shared);
-        return;
-    }
-
-    let mut owner = OwnerState {
-        active_pin: None,
-        next_pin: 1,
-    };
-    while let Some(command) = shared.queue.receive() {
-        if command.is_abandoned() {
-            continue;
-        }
-        let action = catch_unwind(AssertUnwindSafe(|| {
-            execute_command(
-                session.as_mut().expect("owner session exists").as_mut(),
-                &shared,
-                &mut owner,
-                command,
-            )
-        }));
-        match action {
-            Ok(OwnerAction::Continue) => {}
-            Ok(OwnerAction::RetryableClose(error)) => {
-                complete_retryable_close(&shared, error);
-                // Final EngineExecutor drop may race with validation after the
-                // owner has already observed `terminal_drop == false`. Recheck
-                // after reopening the attempt so the last handle cannot leave
-                // an owner thread and transaction pin stranded.
-                schedule_terminal_drop_close(&shared);
-            }
-            Ok(OwnerAction::TerminalClose(result)) => {
-                shared.session_pinned.store(false, Ordering::SeqCst);
-                let result = match result {
-                    Ok(()) => {
-                        // Drop the session and its root lock before resolving
-                        // close. A destructor panic is still one terminal close
-                        // outcome and must not strand or reopen the handle.
-                        match catch_unwind(AssertUnwindSafe(|| drop(session.take()))) {
-                            Ok(()) => Ok(()),
-                            Err(panic) => Err(Error::Engine(format!(
-                                "native engine session destructor panicked after close: {}",
-                                panic_message(panic.as_ref())
-                            ))),
-                        }
-                    }
-                    Err(error) => {
-                        // Teardown has already started, so the session cannot
-                        // safely return to service. Retain any native ownership
-                        // that its failed close may still hold through process
-                        // exit instead of running a second implicit teardown.
-                        std::mem::forget(session.take().expect("owner session exists"));
-                        Err(error)
-                    }
-                };
-                let pending = shared.queue.stop();
-                drop(pending);
-                complete_terminal_close(&shared, result);
-                return;
-            }
-            Err(_) => {
-                shared.cancellation.stop_and_wait();
-                dispose_session_after_owner_failure(session.take().expect("owner session exists"));
-                stop_owner(&shared);
-                return;
-            }
-        }
-    }
-    if let Some(session) = session.take() {
-        shared.cancellation.stop_and_wait();
-        dispose_session_after_owner_failure(session);
-    }
-    stop_owner(&shared);
-}
-
-fn execute_command(
-    session: &mut dyn EngineSession,
-    shared: &ExecutorShared,
-    owner: &mut OwnerState,
-    command: Command,
-) -> OwnerAction {
-    match command {
-        Command::Exec { request, reply } => {
-            let result = if owner.active_pin.is_some() {
-                Err(Error::TransactionActive)
-            } else {
-                run_active_work(&shared.active_work, || {
-                    execute_raw_operation(session, request, &shared.transaction_poisoned, None)
-                })
-            };
-            reply.send(result);
-        }
-        Command::StructuredExec {
-            request,
-            operation,
-            reply,
-        } => {
-            let result = if owner.active_pin.is_some() {
-                Err(Error::TransactionActive)
-            } else {
-                run_active_work(&shared.active_work, || {
-                    execute_structured_operation(
-                        session,
-                        &shared.transaction_poisoned,
-                        request,
-                        &operation,
-                    )
-                })
-            };
-            reply.send(result);
-        }
-        Command::PinnedExec {
-            token,
-            request,
-            guard,
-            reply,
-        } => {
-            let result = if owner.active_pin != Some(token) {
-                Err(inactive_transaction_error())
-            } else if shared.transaction_poisoned.load(Ordering::SeqCst) {
-                Err(transaction_terminal_error(&guard)
-                    .unwrap_or_else(|| Error::Engine(SESSION_STATE_UNKNOWN.to_owned())))
-            } else {
-                run_active_work(&shared.active_work, || {
-                    execute_raw_operation(session, request, &shared.transaction_poisoned, None)
-                })
-            };
-            reply.send(result);
-        }
-        Command::PinnedStructuredExec {
-            token,
-            request,
-            operation,
-            guard,
-            reply,
-        } => {
-            let result = if owner.active_pin == Some(token) {
-                run_active_work(&shared.active_work, || {
-                    execute_transaction_structured_operation(
-                        session,
-                        &shared.transaction_poisoned,
-                        &guard,
-                        request,
-                        &operation,
-                    )
-                })
-            } else {
-                Err(inactive_transaction_error())
-            };
-            reply.send(result);
-        }
-        Command::Stream {
-            request,
-            on_chunk,
-            reply,
-        } => {
-            let result = if owner.active_pin.is_some() {
-                Err(Error::TransactionActive)
-            } else {
-                Ok(run_active_work(&shared.active_work, || {
-                    execute_stream(session, request, on_chunk, &shared.transaction_poisoned)
-                }))
-            };
-            reply.send(result);
-        }
-        Command::Begin { reply } => {
-            if owner.active_pin.is_some() {
-                reply.send(Err(Error::TransactionActive));
-            } else {
-                let result = allocate_pin(owner).and_then(|token| {
-                    begin_transaction(session, &shared.transaction_poisoned).map(|()| token)
-                });
-                match result {
-                    Ok(token) => {
-                        owner.active_pin = Some(token);
-                        shared.session_pinned.store(true, Ordering::SeqCst);
-                        if !reply.send(Ok(token)) {
-                            rollback_active_pin(session, shared, owner, token);
-                        }
-                    }
-                    Err(error) => {
-                        reply.send(Err(error));
-                    }
-                }
-            }
-        }
-        Command::ReleasePin { token, reply } => {
-            let result = if owner.active_pin == Some(token) {
-                owner.active_pin = None;
-                shared.session_pinned.store(false, Ordering::SeqCst);
-                Ok(())
-            } else {
-                Err(inactive_transaction_error())
-            };
-            if let Some(reply) = reply {
-                reply.send(result);
-            }
-        }
-        Command::RollbackAndReleasePin { token } => {
-            rollback_active_pin(session, shared, owner, token);
-        }
-        Command::Backup { reply } => {
-            let result = if owner.active_pin.is_some() {
-                Err(Error::TransactionActive)
-            } else {
-                run_active_work(&shared.active_work, || session.backup())
-            };
-            reply.send(result);
-        }
-        Command::Close => {
-            if let Some(token) = owner.active_pin {
-                if shared.terminal_drop.load(Ordering::SeqCst) {
-                    rollback_active_pin(session, shared, owner, token);
-                } else {
-                    return OwnerAction::RetryableClose(Error::TransactionActive);
-                }
-            }
-            // `closing` has so far rejected only new ordinary work. Establish
-            // the destructive boundary while SQL admission is excluded, then
-            // release every lock and wait for out-of-band cancellations which
-            // crossed their own gate first.
-            let (admission, admission_poisoned) = match shared.admission.lock() {
-                Ok(admission) => (admission, false),
-                Err(error) => (error.into_inner(), true),
-            };
-            let cancellation_target = shared.cancellation.stop_accepting();
-            shared.teardown_started.store(true, Ordering::SeqCst);
-            drop(admission);
-            drop(cancellation_target);
-            shared.cancellation.wait_for_idle();
-            if admission_poisoned {
-                return OwnerAction::TerminalClose(Err(Error::Engine(
-                    "database command admission lock was poisoned".to_owned(),
-                )));
-            }
-            let result = run_active_work(&shared.active_work, || {
-                catch_unwind(AssertUnwindSafe(|| session.close())).unwrap_or_else(|panic| {
-                    Err(Error::Engine(format!(
-                        "native engine session panicked during close: {}",
-                        panic_message(panic.as_ref())
-                    )))
-                })
-            });
-            return OwnerAction::TerminalClose(result);
-        }
-    }
-    OwnerAction::Continue
-}
-
-fn allocate_pin(owner: &mut OwnerState) -> Result {
-    let token = owner.next_pin;
-    owner.next_pin = owner
-        .next_pin
-        .checked_add(1)
-        .ok_or_else(|| Error::Engine("native transaction token space is exhausted".to_owned()))?;
-    Ok(token)
-}
-
-fn rollback_active_pin(
-    session: &mut dyn EngineSession,
-    shared: &ExecutorShared,
-    owner: &mut OwnerState,
-    token: u64,
-) {
-    if owner.active_pin != Some(token) {
-        return;
-    }
-    if shared.transaction_poisoned.load(Ordering::SeqCst) {
-        // The physical transaction boundary is unknown. Releasing the SDK pin
-        // is safe, but sending ROLLBACK could act on a different protocol state
-        // and would falsely imply recovery.
-        owner.active_pin = None;
-        shared.session_pinned.store(false, Ordering::SeqCst);
-        return;
-    }
-    let rollback = run_active_work(&shared.active_work, || {
-        ProtocolRequest::simple_query("ROLLBACK")
-            .and_then(|request| session.exec_protocol_raw(request))
-            .and_then(|response| parse_simple_command_response(&response))
-    });
-    let confirmed = rollback.is_ok_and(|result| {
-        result.command_tag() == Some("ROLLBACK") && result.ready_status() == ReadyStatus::Idle
-    });
-    if !confirmed {
-        shared.transaction_poisoned.store(true, Ordering::SeqCst);
-    }
-    owner.active_pin = None;
-    shared.session_pinned.store(false, Ordering::SeqCst);
-}
-
-fn transaction_terminal_error(guard: &TransactionGuard) -> Option {
-    guard
-        .terminal_error
-        .lock()
-        .ok()
-        .and_then(|error| error.as_ref().cloned())
-}
-
-fn execute_raw_operation(
-    session: &mut dyn EngineSession,
-    request: ProtocolRequest,
-    transaction_poisoned: &AtomicBool,
-    guard: Option<&TransactionGuard>,
-) -> Result {
-    let result = session.exec_protocol_raw(request);
-    if let Err(error) = &result {
-        // Unlike a returned ErrorResponse byte stream, an engine error does
-        // not prove a terminal ReadyForQuery boundary for this raw exchange.
-        transaction_poisoned.store(true, Ordering::SeqCst);
-        if let Some(guard) = guard {
-            guard.fail(error.clone());
-        }
-    }
-    result
-}
-
-fn execute_stream(
-    session: &mut dyn EngineSession,
-    request: ProtocolRequest,
-    mut on_chunk: ProtocolChunkCallback,
-    transaction_poisoned: &AtomicBool,
-) -> ExecutorStreamOutcome {
-    let mut callback_panic = None;
-    let outcome = {
-        let mut guarded = |chunk: &[u8]| {
-            catch_unwind(AssertUnwindSafe(|| on_chunk(chunk))).unwrap_or_else(|panic| {
-                let error = Error::Engine(format!(
-                    "raw protocol stream callback panicked: {}",
-                    panic_message(panic.as_ref())
-                ));
-                callback_panic = Some(error.clone());
-                Err(error)
-            })
-        };
-        session.exec_protocol_raw_stream(request, &mut guarded)
-    };
-    match outcome {
-        ProtocolStreamOutcome::ReadyForQuery(_) if callback_panic.is_some() => {
-            ExecutorStreamOutcome::CallbackPanicked(
-                callback_panic.expect("callback panic was checked"),
-            )
-        }
-        ProtocolStreamOutcome::ReadyForQuery(result) => {
-            ExecutorStreamOutcome::ReadyForQuery(result)
-        }
-        ProtocolStreamOutcome::SessionStateUnknown(error) => {
-            transaction_poisoned.store(true, Ordering::SeqCst);
-            ExecutorStreamOutcome::SessionStateUnknown(error)
-        }
-    }
-}
-
-fn complete_retryable_close(shared: &ExecutorShared, error: Error) {
-    let waiters = {
-        let mut close = shared
-            .close_state
-            .lock()
-            .unwrap_or_else(|error| error.into_inner());
-        close.in_progress = false;
-        shared.closing.store(false, Ordering::SeqCst);
-        std::mem::take(&mut close.waiters)
-    };
-    for waiter in waiters {
-        waiter.send(Err(error.clone()));
-    }
-}
-
-fn complete_terminal_close(shared: &ExecutorShared, result: Result<()>) {
-    let (result, waiters) = {
-        let mut close = shared
-            .close_state
-            .lock()
-            .unwrap_or_else(|error| error.into_inner());
-        let result = close
-            .terminal_result
-            .get_or_insert_with(|| result.clone())
-            .clone();
-        close.in_progress = false;
-        shared.closing.store(false, Ordering::SeqCst);
-        shared.closed.store(true, Ordering::SeqCst);
-        (result, std::mem::take(&mut close.waiters))
-    };
-    for waiter in waiters {
-        waiter.send(result.clone());
-    }
-}
-
-fn schedule_terminal_drop_close(shared: &ExecutorShared) {
-    if !shared.terminal_drop.load(Ordering::SeqCst) {
-        return;
-    }
-    let send_error = {
-        let mut close = shared
-            .close_state
-            .lock()
-            .unwrap_or_else(|error| error.into_inner());
-        if close.terminal_result.is_none() && !close.in_progress {
-            close.in_progress = true;
-            shared.closing.store(true, Ordering::SeqCst);
-            shared.queue.send_control(Command::Close).err()
-        } else {
-            None
-        }
-    };
-    if let Some(error) = send_error {
-        complete_terminal_close(shared, Err(error));
-    }
-}
-
-fn stop_owner(shared: &ExecutorShared) {
-    shared.active_work.store(false, Ordering::SeqCst);
-    shared.cancellation.stop_and_wait();
-    shared.teardown_started.store(true, Ordering::SeqCst);
-    shared.session_pinned.store(false, Ordering::SeqCst);
-    let pending = shared.queue.stop();
-    drop(pending);
-    complete_terminal_close(shared, Err(Error::EngineStopped));
-}
-
-fn dispose_session_after_owner_failure(mut session: Box) {
-    let closed =
-        catch_unwind(AssertUnwindSafe(|| session.close())).is_ok_and(|result| result.is_ok());
-    if closed {
-        let _ = catch_unwind(AssertUnwindSafe(|| drop(session)));
-    } else {
-        std::mem::forget(session);
-    }
-}
-
-pub(crate) async fn run_off_thread(thread_name: &'static str, operation: F) -> Result
-where
-    T: Send + 'static,
-    F: FnOnce() -> Result + Send + 'static,
-{
-    let (reply, receiver) = reply::channel();
-    thread::Builder::new()
-        .name(thread_name.to_owned())
-        .spawn(move || {
-            let result = catch_unwind(AssertUnwindSafe(operation)).unwrap_or_else(|panic| {
-                Err(Error::Engine(format!(
-                    "{thread_name} panicked: {}",
-                    panic_message(panic.as_ref())
-                )))
-            });
-            reply.send(result);
-        })
-        .map_err(|error| Error::Engine(format!("failed to start {thread_name}: {error}")))?;
-    receiver.await
-}
-
-fn panic_message(panic: &(dyn Any + Send)) -> String {
-    if let Some(message) = panic.downcast_ref::() {
-        message.clone()
-    } else if let Some(message) = panic.downcast_ref::<&'static str>() {
-        (*message).to_owned()
-    } else {
-        "unknown panic payload".to_owned()
-    }
-}
-
-fn run_active_work(active_work: &AtomicBool, work: impl FnOnce() -> T) -> T {
-    let _guard = ActiveWorkGuard::new(active_work);
-    work()
-}
-
-struct ActiveWorkGuard<'a> {
-    active_work: &'a AtomicBool,
-}
-
-impl<'a> ActiveWorkGuard<'a> {
-    fn new(active_work: &'a AtomicBool) -> Self {
-        active_work.store(true, Ordering::SeqCst);
-        Self { active_work }
-    }
-}
-
-impl Drop for ActiveWorkGuard<'_> {
-    fn drop(&mut self) {
-        self.active_work.store(false, Ordering::SeqCst);
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use std::future::Future;
-    use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
-    use std::sync::{Arc, Weak, mpsc};
-    use std::task::{Context, Poll, Wake, Waker};
-    use std::time::{Duration, Instant};
-
-    use super::*;
-    use crate::engine::EngineCancel;
-    use crate::error::ErrorKind;
-
-    struct ThreadWake(thread::Thread);
-
-    impl Wake for ThreadWake {
-        fn wake(self: Arc) {
-            self.0.unpark();
-        }
-    }
-
-    struct WakeCounter(AtomicUsize);
-
-    impl Wake for WakeCounter {
-        fn wake(self: Arc) {
-            self.0.fetch_add(1, Ordering::SeqCst);
-        }
-
-        fn wake_by_ref(self: &Arc) {
-            self.0.fetch_add(1, Ordering::SeqCst);
-        }
-    }
-
-    struct GateWake {
-        gate: Mutex, mpsc::Receiver<()>)>>,
-    }
-
-    struct AdmissionLockProbe {
-        shared: Weak,
-        woke: AtomicBool,
-        admission_was_unlocked: AtomicBool,
-    }
-
-    impl Wake for AdmissionLockProbe {
-        fn wake(self: Arc) {
-            self.woke.store(true, Ordering::SeqCst);
-            let admission_was_unlocked = self
-                .shared
-                .upgrade()
-                .is_some_and(|shared| shared.admission.try_lock().is_ok());
-            self.admission_was_unlocked
-                .store(admission_was_unlocked, Ordering::SeqCst);
-        }
-    }
-
-    impl GateWake {
-        fn block_owner_once(&self) {
-            let gate = self
-                .gate
-                .lock()
-                .unwrap_or_else(|error| error.into_inner())
-                .take();
-            if let Some((started, release)) = gate {
-                started.send(()).expect("announce gated wake");
-                release.recv().expect("release gated wake");
-            }
-        }
-    }
-
-    impl Wake for GateWake {
-        fn wake(self: Arc) {
-            self.block_owner_once();
-        }
-
-        fn wake_by_ref(self: &Arc) {
-            self.block_owner_once();
-        }
-    }
-
-    fn block_on(future: F) -> F::Output {
-        let mut future = std::pin::pin!(future);
-        let waker = Waker::from(Arc::new(ThreadWake(thread::current())));
-        let mut context = Context::from_waker(&waker);
-        loop {
-            match future.as_mut().poll(&mut context) {
-                Poll::Ready(value) => return value,
-                Poll::Pending => thread::park(),
-            }
-        }
-    }
-
-    fn poll_once(future: std::pin::Pin<&mut F>) -> Poll {
-        let mut context = Context::from_waker(Waker::noop());
-        future.poll(&mut context)
-    }
-
-    fn assert_error_value(error: &Error, kind: ErrorKind, message: &str) {
-        assert_eq!(error.kind(), kind);
-        assert_eq!(error.to_string(), message);
-    }
-
-    fn assert_error_result(result: Result, kind: ErrorKind, message: &str) {
-        let error = result.err().expect("operation must fail");
-        assert_error_value(&error, kind, message);
-    }
-
-    fn assert_poll_error(poll: Poll>, kind: ErrorKind, message: &str) {
-        match poll {
-            Poll::Ready(Err(error)) => assert_error_value(&error, kind, message),
-            Poll::Ready(Ok(_)) => panic!("operation unexpectedly succeeded"),
-            Poll::Pending => panic!("operation unexpectedly remained pending"),
-        }
-    }
-
-    fn abandoned_ordinary_command(value: u8) -> Command {
-        let (reply, receiver) = reply::channel();
-        drop(receiver);
-        Command::Exec {
-            request: ProtocolRequest::new([value]),
-            reply,
-        }
-    }
-
-    fn poll_queue_send(
-        queue: &CommandQueue,
-        registration: &mut AdmissionRegistration<'_>,
-        command: &mut Option,
-        context: &mut Context<'_>,
-    ) -> Poll> {
-        let (poll, next) = queue.poll_send_ordinary(&mut registration.token, command, context);
-        if let Some(waker) = next {
-            waker.wake();
-        }
-        poll
-    }
-
-    fn fill_ordinary_queue(queue: &CommandQueue) {
-        for value in 0..ORDINARY_QUEUE_CAPACITY {
-            let mut registration = AdmissionRegistration::new(queue);
-            let mut command = Some(abandoned_ordinary_command(
-                u8::try_from(value).expect("queue fixture fits in one byte"),
-            ));
-            assert!(matches!(
-                poll_queue_send(
-                    queue,
-                    &mut registration,
-                    &mut command,
-                    &mut Context::from_waker(Waker::noop()),
-                ),
-                Poll::Ready(Ok(()))
-            ));
-        }
-    }
-
-    #[test]
-    fn cancelling_the_next_capacity_waiter_does_not_strand_its_fifo_successor() {
-        let queue = CommandQueue::new();
-        fill_ordinary_queue(&queue);
-
-        let first_wake = Arc::new(WakeCounter(AtomicUsize::new(0)));
-        let first_waker = Waker::from(Arc::clone(&first_wake));
-        let mut first = AdmissionRegistration::new(&queue);
-        let mut first_command = Some(abandoned_ordinary_command(1));
-        assert!(
-            poll_queue_send(
-                &queue,
-                &mut first,
-                &mut first_command,
-                &mut Context::from_waker(&first_waker),
-            )
-            .is_pending()
-        );
-
-        let second_wake = Arc::new(WakeCounter(AtomicUsize::new(0)));
-        let second_waker = Waker::from(Arc::clone(&second_wake));
-        let mut second = AdmissionRegistration::new(&queue);
-        let mut second_command = Some(abandoned_ordinary_command(2));
-        assert!(
-            poll_queue_send(
-                &queue,
-                &mut second,
-                &mut second_command,
-                &mut Context::from_waker(&second_waker),
-            )
-            .is_pending()
-        );
-
-        drop(first);
-        assert_eq!(second_wake.0.load(Ordering::SeqCst), 0);
-        drop(queue.receive().expect("free one ordinary queue slot"));
-        assert_eq!(second_wake.0.load(Ordering::SeqCst), 1);
-        assert_eq!(first_wake.0.load(Ordering::SeqCst), 0);
-        assert!(matches!(
-            poll_queue_send(
-                &queue,
-                &mut second,
-                &mut second_command,
-                &mut Context::from_waker(&second_waker),
-            ),
-            Poll::Ready(Ok(()))
-        ));
-        drop(second);
-        drop(queue.stop());
-    }
-
-    #[test]
-    fn rejected_capacity_waiter_cannot_cross_a_reopened_close_cutoff() {
-        let queue = CommandQueue::new();
-        fill_ordinary_queue(&queue);
-        let mut registration = AdmissionRegistration::new(&queue);
-        let mut command = Some(abandoned_ordinary_command(3));
-        assert!(
-            poll_queue_send(
-                &queue,
-                &mut registration,
-                &mut command,
-                &mut Context::from_waker(Waker::noop()),
-            )
-            .is_pending()
-        );
-
-        drop(queue.reject_admissions());
-        drop(queue.receive().expect("capacity becomes available later"));
-        assert_poll_error(
-            poll_queue_send(
-                &queue,
-                &mut registration,
-                &mut command,
-                &mut Context::from_waker(Waker::noop()),
-            ),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-        drop(queue.stop());
-    }
-
-    #[test]
-    fn capacity_successor_is_woken_after_releasing_admission() {
-        let shared = Arc::new(ExecutorShared::new());
-        let executor = EngineExecutor {
-            shared: Arc::clone(&shared),
-        };
-        fill_ordinary_queue(&shared.queue);
-
-        let mut first = Box::pin(executor.send(abandoned_ordinary_command(1)));
-        assert!(poll_once(first.as_mut()).is_pending());
-
-        let probe = Arc::new(AdmissionLockProbe {
-            shared: Arc::downgrade(&shared),
-            woke: AtomicBool::new(false),
-            admission_was_unlocked: AtomicBool::new(false),
-        });
-        let probe_waker = Waker::from(Arc::clone(&probe));
-        let mut second = Box::pin(executor.send(abandoned_ordinary_command(2)));
-        assert!(
-            second
-                .as_mut()
-                .poll(&mut Context::from_waker(&probe_waker))
-                .is_pending()
-        );
-
-        {
-            let mut state = shared
-                .queue
-                .state
-                .lock()
-                .unwrap_or_else(|error| error.into_inner());
-            for _ in 0..2 {
-                drop(state.commands.pop_front().expect("free saturated slot"));
-                state.ordinary_count -= 1;
-            }
-        }
-
-        assert!(matches!(poll_once(first.as_mut()), Poll::Ready(Ok(()))));
-        assert!(probe.woke.load(Ordering::SeqCst));
-        assert!(
-            probe.admission_was_unlocked.load(Ordering::SeqCst),
-            "a synchronous successor waker must never run under the admission lock"
-        );
-
-        drop(second);
-        drop(first);
-        drop(shared.queue.stop());
-        shared.closed.store(true, Ordering::SeqCst);
-    }
-
-    fn command_response(tag: &str, ready: u8) -> ProtocolResponse {
-        let mut bytes = Vec::new();
-        let mut body = tag.as_bytes().to_vec();
-        body.push(0);
-        push_backend_message(&mut bytes, b'C', &body);
-        push_backend_message(&mut bytes, b'Z', &[ready]);
-        ProtocolResponse::new(bytes)
-    }
-
-    fn push_backend_message(bytes: &mut Vec, tag: u8, body: &[u8]) {
-        bytes.push(tag);
-        bytes.extend_from_slice(&i32::try_from(body.len() + 4).unwrap().to_be_bytes());
-        bytes.extend_from_slice(body);
-    }
-
-    struct EchoSession;
-
-    impl EngineSession for EchoSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-    }
-
-    #[test]
-    fn open_constructs_the_session_on_its_permanent_owner_thread() {
-        let caller = thread::current().id();
-        let (executor, constructed_on) = block_on(EngineExecutor::open(
-            "oliphaunt-owner-construction-test",
-            || {
-                Ok((
-                    Box::new(EchoSession) as Box,
-                    thread::current().id(),
-                ))
-            },
-        ))
-        .expect("owner opens");
-
-        assert_ne!(caller, constructed_on);
-        assert_eq!(executor.shared.owner_thread.get(), Some(&constructed_on));
-        block_on(executor.close()).expect("owner closes");
-    }
-
-    #[test]
-    fn open_panic_is_an_error_instead_of_a_stranded_future() {
-        let error = block_on(EngineExecutor::open::<(), _>(
-            "oliphaunt-owner-open-panic-test",
-            || panic!("open panic probe"),
-        ))
-        .err()
-        .expect("open panic is reported");
-
-        assert_error_value(
-            &error,
-            ErrorKind::Other,
-            "oliphaunt-owner-open-panic-test panicked while opening: open panic probe",
-        );
-    }
-
-    struct DropSignalSession(Option>);
-
-    impl EngineSession for DropSignalSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-    }
-
-    impl Drop for DropSignalSession {
-        fn drop(&mut self) {
-            if let Some(dropped) = self.0.take() {
-                let _ = dropped.send(());
-            }
-        }
-    }
-
-    #[test]
-    fn abandoned_open_closes_a_session_that_finishes_late() {
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let (dropped, dropped_rx) = mpsc::channel();
-        let mut open = Box::pin(EngineExecutor::open(
-            "oliphaunt-owner-abandoned-open-test",
-            move || {
-                started.send(()).expect("announce open");
-                release_rx.recv().expect("release open");
-                Ok((
-                    Box::new(DropSignalSession(Some(dropped))) as Box,
-                    (),
-                ))
-            },
-        ));
-        assert!(poll_once(open.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("open reaches owner");
-        drop(open);
-        release.send(()).expect("finish abandoned open");
-        dropped_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("late session is closed and dropped");
-    }
-
-    struct PanickingSession;
-
-    impl EngineSession for PanickingSession {
-        fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
-            panic!("injected owner command panic")
-        }
-    }
-
-    #[test]
-    fn owner_panic_wakes_active_and_future_operations() {
-        let executor = EngineExecutor::spawn(Box::new(PanickingSession));
-        assert_error_result(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([1]))),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-        assert_error_result(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([2]))),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-    }
-
-    struct BlockingSession {
-        calls: Arc,
-        started: mpsc::Sender<()>,
-        release: mpsc::Receiver<()>,
-        dropped: Option>,
-    }
-
-    impl EngineSession for BlockingSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            self.calls.fetch_add(1, Ordering::SeqCst);
-            self.started.send(()).expect("announce active owner work");
-            self.release.recv().expect("release active owner work");
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-    }
-
-    impl Drop for BlockingSession {
-        fn drop(&mut self) {
-            if let Some(dropped) = self.dropped.take() {
-                let _ = dropped.send(());
-            }
-        }
-    }
-
-    #[test]
-    fn bounded_fifo_awaits_capacity_then_close_rejects_later_work() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(BlockingSession {
-            calls: Arc::clone(&calls),
-            started,
-            release: release_rx,
-            dropped: None,
-        }));
-
-        let mut active = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1])));
-        assert!(poll_once(active.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("first operation reaches owner");
-
-        let mut queued = Vec::with_capacity(ORDINARY_QUEUE_CAPACITY);
-        for value in 0..ORDINARY_QUEUE_CAPACITY {
-            let mut future =
-                Box::pin(executor.exec_protocol_raw(ProtocolRequest::new(value.to_le_bytes())));
-            assert!(poll_once(future.as_mut()).is_pending());
-            queued.push(future);
-        }
-        let mut overflow = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([9, 9, 9])));
-        assert!(
-            poll_once(overflow.as_mut()).is_pending(),
-            "queue saturation applies asynchronous backpressure"
-        );
-
-        // Free one queue slot. The owner immediately occupies itself with the
-        // next operation, while the overflow future can now acquire the slot.
-        release.send(()).expect("release active operation");
-        assert_eq!(
-            block_on(active).expect("active work drains").as_bytes(),
-            &[1]
-        );
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("next operation reaches owner");
-        assert!(poll_once(overflow.as_mut()).is_pending());
-        {
-            let queue = executor
-                .shared
-                .queue
-                .state
-                .lock()
-                .unwrap_or_else(|error| error.into_inner());
-            assert_eq!(queue.ordinary_count, ORDINARY_QUEUE_CAPACITY);
-            assert!(queue.admission_waiters.is_empty());
-        }
-
-        let mut cutoff_waiter =
-            Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([8, 8, 8])));
-        assert!(poll_once(cutoff_waiter.as_mut()).is_pending());
-
-        // Close is a control command and still enters the same FIFO after all
-        // already-admitted ordinary work.
-        let mut close = Box::pin(executor.close());
-        assert!(poll_once(close.as_mut()).is_pending());
-        assert_poll_error(
-            poll_once(cutoff_waiter.as_mut()),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-        let mut after_cutoff = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([7, 7])));
-        assert_poll_error(
-            poll_once(after_cutoff.as_mut()),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-
-        // The remaining permits may be buffered, allowing every pre-cutoff
-        // command to run without depending on scheduler timing in this test.
-        for _ in 0..=ORDINARY_QUEUE_CAPACITY {
-            release.send(()).expect("release admitted operation");
-        }
-        for operation in queued {
-            block_on(operation).expect("pre-cutoff queued work drains");
-        }
-        block_on(overflow).expect("capacity waiter is admitted before close");
-        block_on(close).expect("reserved close command completes");
-        assert_eq!(calls.load(Ordering::SeqCst), ORDINARY_QUEUE_CAPACITY + 2);
-    }
-
-    struct BlockingTransactionSession {
-        calls: Arc,
-        started: mpsc::Sender<()>,
-        release: mpsc::Receiver<()>,
-    }
-
-    impl EngineSession for BlockingTransactionSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            match self.calls.fetch_add(1, Ordering::SeqCst) {
-                0 => {
-                    self.started.send(()).expect("announce blocking work");
-                    self.release.recv().expect("release blocking work");
-                    Ok(ProtocolResponse::new(request.as_bytes()))
-                }
-                1 => Ok(command_response("BEGIN", b'T')),
-                2 => Ok(command_response("ROLLBACK", b'I')),
-                call => panic!("unexpected transaction session call {call}"),
-            }
-        }
-    }
-
-    #[test]
-    fn begin_admitted_before_close_runs_and_close_observes_its_pin() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(BlockingTransactionSession {
-            calls: Arc::clone(&calls),
-            started,
-            release: release_rx,
-        }));
-
-        let mut active = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1])));
-        assert!(poll_once(active.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("first operation reaches owner");
-
-        let mut begin = Box::pin(executor.begin_transaction());
-        assert!(poll_once(begin.as_mut()).is_pending());
-        let mut close = Box::pin(executor.close());
-        assert!(poll_once(close.as_mut()).is_pending());
-        let mut later_begin = Box::pin(executor.begin_transaction());
-        assert_poll_error(
-            poll_once(later_begin.as_mut()),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-
-        release.send(()).expect("release first operation");
-        block_on(active).expect("active operation drains");
-        let token = block_on(begin).expect("pre-cutoff BEGIN runs");
-        assert_error_result(
-            block_on(close),
-            ErrorKind::TransactionActive,
-            "a transaction is active; use the active transaction handle",
-        );
-        assert!(!executor.is_closed());
-        assert!(executor.session_is_pinned());
-
-        let rollback = block_on(executor.pinned_exec_protocol_control(
-            token,
-            ProtocolRequest::simple_query("ROLLBACK").expect("rollback request"),
-            TransactionGuard::active(),
-        ))
-        .expect("rollback after failed close");
-        assert_eq!(
-            parse_simple_command_response(&rollback)
-                .expect("rollback response")
-                .ready_status(),
-            ReadyStatus::Idle
-        );
-        block_on(executor.release_pin(token)).expect("release transaction pin");
-        block_on(executor.close()).expect("retry closes after transaction cleanup");
-        assert_eq!(calls.load(Ordering::SeqCst), 3);
-    }
-
-    struct PreCutoffSettlementSession {
-        settlement_tag: &'static str,
-        calls: Arc,
-        started: mpsc::Sender<()>,
-        release: mpsc::Receiver<()>,
-    }
-
-    impl EngineSession for PreCutoffSettlementSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            match self.calls.fetch_add(1, Ordering::SeqCst) {
-                0 => {
-                    self.started.send(()).expect("announce blocking work");
-                    self.release.recv().expect("release blocking work");
-                    Ok(ProtocolResponse::new(request.as_bytes()))
-                }
-                1 => {
-                    assert_eq!(
-                        request.as_bytes(),
-                        ProtocolRequest::simple_query("BEGIN")
-                            .expect("BEGIN request")
-                            .as_bytes()
-                    );
-                    Ok(command_response("BEGIN", b'T'))
-                }
-                2 => {
-                    assert_eq!(
-                        request.as_bytes(),
-                        ProtocolRequest::simple_query(self.settlement_tag)
-                            .expect("settlement request")
-                            .as_bytes()
-                    );
-                    Ok(command_response(self.settlement_tag, b'I'))
-                }
-                call => panic!("unexpected pre-cutoff settlement call {call}"),
-            }
-        }
-    }
-
-    fn assert_pre_cutoff_begin_can_settle_after_close_cutoff(settlement_tag: &'static str) {
-        use crate::database::AsyncOliphaunt;
-
-        let calls = Arc::new(AtomicUsize::new(0));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(PreCutoffSettlementSession {
-            settlement_tag,
-            calls: Arc::clone(&calls),
-            started,
-            release: release_rx,
-        }));
-        let database = AsyncOliphaunt::from_executor(Arc::clone(&executor));
-
-        let mut active = Box::pin(database.exec_protocol_raw([1]));
-        assert!(poll_once(active.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("first operation reaches owner");
-
-        // The owner's wake for the BEGIN reply is synchronous. Gate that first
-        // wake so this thread can poll the real transaction future through its
-        // COMMIT/ROLLBACK admission while the owner is still before Close.
-        let (begin_woke, begin_woke_rx) = mpsc::channel();
-        let (release_owner, release_owner_rx) = mpsc::channel();
-        let gate_waker = Waker::from(Arc::new(GateWake {
-            gate: Mutex::new(Some((begin_woke, release_owner_rx))),
-        }));
-        let mut transaction = Box::pin(database.transaction(async |transaction| {
-            if settlement_tag == "ROLLBACK" {
-                transaction.rollback().await?;
-            }
-            Ok::<(), Error>(())
-        }));
-        let mut gate_context = Context::from_waker(&gate_waker);
-        assert!(transaction.as_mut().poll(&mut gate_context).is_pending());
-
-        let mut close = Box::pin(database.close());
-        assert!(poll_once(close.as_mut()).is_pending());
-        assert!(executor.shared.closing.load(Ordering::SeqCst));
-
-        release.send(()).expect("release first operation");
-        block_on(active).expect("active operation drains");
-        begin_woke_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("BEGIN reply wakes the transaction future");
-        assert!(
-            transaction
-                .as_mut()
-                .poll(&mut Context::from_waker(Waker::noop()))
-                .is_pending()
-        );
-
-        {
-            let queue = executor
-                .shared
-                .queue
-                .state
-                .lock()
-                .unwrap_or_else(|error| error.into_inner());
-            assert_eq!(queue.commands.len(), 2);
-            assert!(matches!(queue.commands.front(), Some(Command::Close)));
-            assert!(matches!(
-                queue.commands.back(),
-                Some(Command::PinnedExec { .. })
-            ));
-        }
-        release_owner
-            .send(())
-            .expect("release owner after settlement admission");
-
-        block_on(transaction).expect("callback transaction settles");
-        assert_error_result(
-            block_on(close),
-            ErrorKind::TransactionActive,
-            "a transaction is active; use the active transaction handle",
-        );
-        assert!(!executor.is_closed());
-        block_on(database.close()).expect("retry closes settled session");
-        assert_eq!(calls.load(Ordering::SeqCst), 3);
-    }
-
-    #[test]
-    fn pre_cutoff_begin_can_commit_after_close_cutoff_without_deadlock() {
-        assert_pre_cutoff_begin_can_settle_after_close_cutoff("COMMIT");
-    }
-
-    #[test]
-    fn pre_cutoff_begin_can_rollback_after_close_cutoff_without_deadlock() {
-        assert_pre_cutoff_begin_can_settle_after_close_cutoff("ROLLBACK");
-    }
-
-    struct TransactionControlSession {
-        calls: Arc,
-        started: mpsc::Sender<()>,
-        release: mpsc::Receiver<()>,
-    }
-
-    impl EngineSession for TransactionControlSession {
-        fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
-            match self.calls.fetch_add(1, Ordering::SeqCst) {
-                0 => Ok(command_response("BEGIN", b'T')),
-                1 => {
-                    self.started.send(()).expect("announce pinned work");
-                    self.release.recv().expect("release pinned work");
-                    Ok(command_response("SELECT", b'T'))
-                }
-                2 => Ok(command_response("ROLLBACK", b'I')),
-                call => panic!("unexpected transaction-control session call {call}"),
-            }
-        }
-    }
-
-    #[test]
-    fn transaction_control_admitted_before_close_is_not_retroactively_rejected() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(TransactionControlSession {
-            calls: Arc::clone(&calls),
-            started,
-            release: release_rx,
-        }));
-
-        let token = block_on(executor.begin_transaction()).expect("transaction begins");
-        let guard = TransactionGuard::active();
-        let mut pinned = Box::pin(executor.pinned_exec_structured(
-            token,
-            ProtocolRequest::simple_query("SELECT 1").expect("query request"),
-            "transaction test",
-            Arc::clone(&guard),
-        ));
-        assert!(poll_once(pinned.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("pinned operation reaches owner");
-
-        let mut rollback = Box::pin(executor.pinned_exec_protocol_control(
-            token,
-            ProtocolRequest::simple_query("ROLLBACK").expect("rollback request"),
-            guard,
-        ));
-        assert!(poll_once(rollback.as_mut()).is_pending());
-        let mut close = Box::pin(executor.close());
-        assert!(poll_once(close.as_mut()).is_pending());
-
-        release.send(()).expect("release pinned operation");
-        block_on(pinned).expect("pinned operation drains");
-        let rollback = block_on(rollback).expect("pre-cutoff rollback control runs");
-        assert_eq!(
-            parse_simple_command_response(&rollback)
-                .expect("rollback response")
-                .ready_status(),
-            ReadyStatus::Idle
-        );
-        // The protocol transaction is idle, but the SDK pin is deliberately a
-        // separate ownership boundary and is still active at Close.
-        assert_error_result(
-            block_on(close),
-            ErrorKind::TransactionActive,
-            "a transaction is active; use the active transaction handle",
-        );
-        block_on(executor.release_pin(token)).expect("release transaction pin");
-        block_on(executor.close()).expect("retry closes released session");
-        assert_eq!(calls.load(Ordering::SeqCst), 3);
-    }
-
-    struct FailedBeginAfterBlockSession {
-        calls: Arc,
-        started: mpsc::Sender<()>,
-        release: mpsc::Receiver<()>,
-    }
-
-    impl EngineSession for FailedBeginAfterBlockSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            match self.calls.fetch_add(1, Ordering::SeqCst) {
-                0 => {
-                    self.started.send(()).expect("announce blocking work");
-                    self.release.recv().expect("release blocking work");
-                    Ok(ProtocolResponse::new(request.as_bytes()))
-                }
-                1 => Err(Error::Engine("injected BEGIN failure".to_owned())),
-                call => panic!("unexpected failed-begin session call {call}"),
-            }
-        }
-    }
-
-    #[test]
-    fn failed_pre_cutoff_begin_transport_does_not_send_blind_rollback() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(FailedBeginAfterBlockSession {
-            calls: Arc::clone(&calls),
-            started,
-            release: release_rx,
-        }));
-
-        let mut active = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1])));
-        assert!(poll_once(active.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("first operation reaches owner");
-        let mut begin = Box::pin(executor.begin_transaction());
-        assert!(poll_once(begin.as_mut()).is_pending());
-        let mut close = Box::pin(executor.close());
-        assert!(poll_once(close.as_mut()).is_pending());
-
-        release.send(()).expect("release first operation");
-        block_on(active).expect("active operation drains");
-        assert_error_result(block_on(begin), ErrorKind::Other, "injected BEGIN failure");
-        block_on(close).expect("unknown BEGIN failure remains closeable");
-        assert_eq!(calls.load(Ordering::SeqCst), 2);
-    }
-
-    #[test]
-    fn abandoned_pre_cutoff_begin_is_skipped_before_close() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(BlockingTransactionSession {
-            calls: Arc::clone(&calls),
-            started,
-            release: release_rx,
-        }));
-
-        let mut active = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1])));
-        assert!(poll_once(active.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("first operation reaches owner");
-        let mut begin = Box::pin(executor.begin_transaction());
-        assert!(poll_once(begin.as_mut()).is_pending());
-        drop(begin);
-        let mut close = Box::pin(executor.close());
-        assert!(poll_once(close.as_mut()).is_pending());
-
-        release.send(()).expect("release first operation");
-        block_on(active).expect("active operation drains");
-        block_on(close).expect("abandoned BEGIN does not create a pin");
-        assert_eq!(calls.load(Ordering::SeqCst), 1);
-    }
-
-    struct BlockingBeginSession {
-        calls: Arc,
-        started: mpsc::Sender<()>,
-        release: mpsc::Receiver<()>,
-    }
-
-    impl EngineSession for BlockingBeginSession {
-        fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
-            match self.calls.fetch_add(1, Ordering::SeqCst) {
-                0 => {
-                    self.started.send(()).expect("announce BEGIN execution");
-                    self.release.recv().expect("release BEGIN execution");
-                    Ok(command_response("BEGIN", b'T'))
-                }
-                1 => Ok(command_response("ROLLBACK", b'I')),
-                call => panic!("unexpected blocking-begin session call {call}"),
-            }
-        }
-    }
-
-    #[test]
-    fn begin_abandoned_during_execution_rolls_back_before_close() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(BlockingBeginSession {
-            calls: Arc::clone(&calls),
-            started,
-            release: release_rx,
-        }));
-
-        let mut begin = Box::pin(executor.begin_transaction());
-        assert!(poll_once(begin.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("BEGIN reaches PostgreSQL");
-        drop(begin);
-        let mut close = Box::pin(executor.close());
-        assert!(poll_once(close.as_mut()).is_pending());
-
-        release.send(()).expect("finish abandoned BEGIN");
-        block_on(close).expect("owner rolls back abandoned BEGIN before close");
-        assert_eq!(calls.load(Ordering::SeqCst), 2);
-    }
-
-    #[test]
-    fn final_drop_never_joins_a_blocked_owner() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let (dropped, dropped_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(BlockingSession {
-            calls,
-            started,
-            release: release_rx,
-            dropped: Some(dropped),
-        }));
-        let mut operation = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([1, 2, 3])));
-        assert!(poll_once(operation.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("owner operation starts");
-        drop(operation);
-
-        let started_drop = Instant::now();
-        drop(executor);
-        assert!(
-            started_drop.elapsed() < Duration::from_millis(100),
-            "final drop synchronously waited for the owner"
-        );
-
-        release.send(()).expect("release detached owner");
-        dropped_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("detached owner eventually closed and dropped the session");
-    }
-
-    #[test]
-    fn final_drop_racing_retryable_validation_requeues_terminal_cleanup() {
-        let shared = ExecutorShared::new();
-        shared.terminal_drop.store(true, Ordering::SeqCst);
-        shared.closing.store(true, Ordering::SeqCst);
-        shared
-            .close_state
-            .lock()
-            .unwrap_or_else(|error| error.into_inner())
-            .in_progress = true;
-
-        // Model the owner having observed a non-terminal explicit close just
-        // before the final handle marked terminal_drop. Completion must recheck
-        // that bit and schedule a new close rather than leaving the owner idle.
-        complete_retryable_close(&shared, Error::TransactionActive);
-        schedule_terminal_drop_close(&shared);
-
-        assert!(shared.closing.load(Ordering::SeqCst));
-        assert!(
-            shared
-                .close_state
-                .lock()
-                .unwrap_or_else(|error| error.into_inner())
-                .in_progress
-        );
-        assert!(matches!(shared.queue.receive(), Some(Command::Close)));
-    }
-
-    struct StreamSession {
-        calls: Arc,
-    }
-
-    impl EngineSession for StreamSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            self.calls.fetch_add(1, Ordering::SeqCst);
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-
-        fn exec_protocol_raw_stream(
-            &mut self,
-            _request: ProtocolRequest,
-            on_chunk: &mut dyn FnMut(&[u8]) -> Result<()>,
-        ) -> ProtocolStreamOutcome {
-            ProtocolStreamOutcome::ReadyForQuery(on_chunk(&[1, 2, 3]))
-        }
-    }
-
-    struct FailedRawSession {
-        calls: Arc,
-    }
-
-    impl EngineSession for FailedRawSession {
-        fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
-            self.calls.fetch_add(1, Ordering::SeqCst);
-            Err(Error::Engine(
-                "raw transport failed before ReadyForQuery".to_owned(),
-            ))
-        }
-    }
-
-    #[test]
-    fn raw_transport_failure_poisons_without_a_second_owner_call() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let executor = EngineExecutor::spawn(Box::new(FailedRawSession {
-            calls: Arc::clone(&calls),
-        }));
-
-        assert_error_result(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([1]))),
-            ErrorKind::Other,
-            "raw transport failed before ReadyForQuery",
-        );
-        assert_error_result(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([2]))),
-            ErrorKind::Other,
-            SESSION_STATE_UNKNOWN,
-        );
-        assert_eq!(calls.load(Ordering::SeqCst), 1);
-        block_on(executor.close()).expect("close poisoned raw session");
-    }
-
-    #[test]
-    fn callback_panic_is_contained_and_the_session_remains_usable() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let executor = EngineExecutor::spawn(Box::new(StreamSession {
-            calls: Arc::clone(&calls),
-        }));
-
-        let error = block_on(
-            executor.exec_protocol_raw_stream(ProtocolRequest::new([1]), |_| {
-                panic!("callback panic probe")
-            }),
-        )
-        .expect_err("callback panic is returned");
-        assert_eq!(error.kind(), ErrorKind::Other);
-        assert!(error.to_string().contains("stream callback panicked"));
-        assert_eq!(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([7])))
-                .expect("session remains usable")
-                .as_bytes(),
-            &[7]
-        );
-        assert_eq!(calls.load(Ordering::SeqCst), 1);
-        block_on(executor.close()).expect("close stream session");
-    }
-
-    struct FailedRecoveryStreamSession;
-
-    impl EngineSession for FailedRecoveryStreamSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-
-        fn exec_protocol_raw_stream(
-            &mut self,
-            _request: ProtocolRequest,
-            on_chunk: &mut dyn FnMut(&[u8]) -> Result<()>,
-        ) -> ProtocolStreamOutcome {
-            let _ = on_chunk(&[1, 2, 3]);
-            ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(
-                "stream transport failed before ReadyForQuery".to_owned(),
-            ))
-        }
-    }
-
-    #[test]
-    fn recovery_failure_overrides_callback_panic_and_poisons_the_session() {
-        let executor = EngineExecutor::spawn(Box::new(FailedRecoveryStreamSession));
-
-        assert_error_result(
-            block_on(
-                executor.exec_protocol_raw_stream(ProtocolRequest::new([1]), |_| {
-                    panic!("callback panic probe")
-                }),
-            ),
-            ErrorKind::Other,
-            "stream transport failed before ReadyForQuery",
-        );
-        assert_error_result(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([7]))),
-            ErrorKind::Other,
-            SESSION_STATE_UNKNOWN,
-        );
-        block_on(executor.close()).expect("close failed-recovery stream session");
-    }
-
-    #[test]
-    fn callback_reentrancy_fails_immediately_instead_of_deadlocking() {
-        let executor = EngineExecutor::spawn(Box::new(StreamSession {
-            calls: Arc::new(AtomicUsize::new(0)),
-        }));
-        let reentrant = Arc::clone(&executor);
-        block_on(
-            executor.exec_protocol_raw_stream(ProtocolRequest::new([1]), move |_| {
-                let error = block_on(reentrant.exec_protocol_raw(ProtocolRequest::new([2])))
-                    .expect_err("reentrant owner work is rejected");
-                assert!(error.to_string().contains("reentrant database work"));
-                let error = block_on(reentrant.pinned_exec_protocol_control(
-                    1,
-                    ProtocolRequest::simple_query("COMMIT").expect("control request"),
-                    TransactionGuard::active(),
-                ))
-                .expect_err("reentrant transaction settlement is rejected");
-                assert!(error.to_string().contains("reentrant database work"));
-                let error = block_on(reentrant.close())
-                    .expect_err("reentrant pre-teardown close is rejected");
-                assert!(error.to_string().contains("reentrant database work"));
-                assert!(!reentrant.is_closed());
-                Ok(())
-            }),
-        )
-        .expect("outer stream remains usable");
-        assert!(!executor.is_closed());
-        block_on(executor.close()).expect("close stream session");
-    }
-
-    struct BlockingCancel {
-        started: Mutex>>,
-        release: Mutex>,
-    }
-
-    impl EngineCancel for BlockingCancel {
-        fn cancel(&self) -> Result<()> {
-            if let Some(started) = self
-                .started
-                .lock()
-                .unwrap_or_else(|error| error.into_inner())
-                .take()
-            {
-                started
-                    .send(thread::current().id())
-                    .expect("announce cancellation thread");
-            }
-            self.release
-                .lock()
-                .unwrap_or_else(|error| error.into_inner())
-                .recv()
-                .expect("release cancellation");
-            Ok(())
-        }
-    }
-
-    struct CancellableSession {
-        cancel: Arc,
-    }
-
-    impl EngineSession for CancellableSession {
-        fn cancel_handle(&self) -> Option> {
-            let cancel: Arc = self.cancel.clone();
-            Some(cancel)
-        }
-
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-    }
-
-    #[test]
-    fn cancellation_transport_work_is_async_and_out_of_band() {
-        let caller = thread::current().id();
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(CancellableSession {
-            cancel: Arc::new(BlockingCancel {
-                started: Mutex::new(Some(started)),
-                release: Mutex::new(release_rx),
-            }),
-        }));
-
-        let mut cancel = Box::pin(executor.cancel());
-        assert!(poll_once(cancel.as_mut()).is_pending());
-        let cancellation_thread = started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("cancellation starts without blocking the poller");
-        assert_ne!(caller, cancellation_thread);
-        assert_eq!(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([8])))
-                .expect("ordinary owner work is not queued behind cancellation")
-                .as_bytes(),
-            &[8]
-        );
-        release.send(()).expect("finish cancellation");
-        block_on(cancel).expect("cancellation completes");
-        block_on(executor.close()).expect("close cancellable session");
-    }
-
-    #[test]
-    fn close_waits_for_admitted_cancellation_and_rejects_later_calls() {
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(CancellableSession {
-            cancel: Arc::new(BlockingCancel {
-                started: Mutex::new(Some(started)),
-                release: Mutex::new(release_rx),
-            }),
-        }));
-
-        let mut cancel = Box::pin(executor.cancel());
-        assert!(poll_once(cancel.as_mut()).is_pending());
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("cancellation reaches its engine target");
-
-        let mut close = Box::pin(executor.close());
-        assert!(poll_once(close.as_mut()).is_pending());
-        assert!(
-            executor
-                .shared
-                .cancellation
-                .wait_for_cutoff(Duration::from_secs(2)),
-            "close establishes its destructive cancellation cutoff"
-        );
-        assert_eq!(executor.shared.cancellation.active_cancellations(), 1);
-        assert_error_result(
-            block_on(executor.cancel()),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-        assert!(poll_once(close.as_mut()).is_pending());
-
-        release.send(()).expect("finish admitted cancellation");
-        block_on(cancel).expect("admitted cancellation settles");
-        block_on(close).expect("close proceeds after cancellation settles");
-        assert_eq!(executor.shared.cancellation.active_cancellations(), 0);
-        assert!(executor.is_closed());
-    }
-
-    struct CountingCancel {
-        calls: AtomicUsize,
-    }
-
-    impl EngineCancel for CountingCancel {
-        fn cancel(&self) -> Result<()> {
-            self.calls.fetch_add(1, Ordering::SeqCst);
-            Ok(())
-        }
-    }
-
-    struct DrainingCancellableSession {
-        cancel: Arc,
-        query_started: mpsc::Sender<()>,
-        query_release: mpsc::Receiver<()>,
-    }
-
-    impl EngineSession for DrainingCancellableSession {
-        fn cancel_handle(&self) -> Option> {
-            let cancel: Arc = self.cancel.clone();
-            Some(cancel)
-        }
-
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            self.query_started.send(()).expect("announce active query");
-            self.query_release.recv().expect("release active query");
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-    }
-
-    #[test]
-    fn cancellation_remains_admissible_after_close_cutoff_while_query_drains() {
-        let cancel = Arc::new(CountingCancel {
-            calls: AtomicUsize::new(0),
-        });
-        let (query_started, query_started_rx) = mpsc::channel();
-        let (query_release, query_release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(DrainingCancellableSession {
-            cancel: Arc::clone(&cancel),
-            query_started,
-            query_release: query_release_rx,
-        }));
-
-        let mut query = Box::pin(executor.exec_protocol_raw(ProtocolRequest::new([8])));
-        assert!(poll_once(query.as_mut()).is_pending());
-        query_started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("query reaches the owner");
-
-        let mut close = Box::pin(executor.close());
-        assert!(poll_once(close.as_mut()).is_pending());
-        assert!(executor.shared.closing.load(Ordering::SeqCst));
-        assert!(!executor.shared.teardown_started.load(Ordering::SeqCst));
-
-        block_on(executor.cancel()).expect("cancel remains out of band after the close cutoff");
-        assert_eq!(cancel.calls.load(Ordering::SeqCst), 1);
-
-        query_release.send(()).expect("finish the active query");
-        block_on(query).expect("pre-cutoff query drains");
-        block_on(close).expect("close runs after the query");
-        assert!(executor.shared.teardown_started.load(Ordering::SeqCst));
-        assert_error_result(
-            block_on(executor.cancel()),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-        assert_eq!(cancel.calls.load(Ordering::SeqCst), 1);
-    }
-
-    struct InjectedTopologyCloseFailureSession {
-        topology: &'static str,
-        close_attempts: Arc,
-    }
-
-    impl EngineSession for InjectedTopologyCloseFailureSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-
-        fn close(&mut self) -> Result<()> {
-            self.close_attempts.fetch_add(1, Ordering::SeqCst);
-            Err(Error::Engine(format!(
-                "injected {} teardown failure",
-                self.topology
-            )))
-        }
-    }
-
-    fn assert_topology_close_failure_is_terminal(topology: &'static str) {
-        // Direct, broker, and server sessions converge at this EngineSession
-        // boundary. Inject each topology's teardown error here so the shared
-        // lifecycle state machine is tested without native libraries or child
-        // processes making the failure nondeterministic.
-        let attempts = Arc::new(AtomicUsize::new(0));
-        let executor = EngineExecutor::spawn(Box::new(InjectedTopologyCloseFailureSession {
-            topology,
-            close_attempts: Arc::clone(&attempts),
-        }));
-        let expected = format!("injected {topology} teardown failure");
-        assert_error_result(block_on(executor.close()), ErrorKind::Other, &expected);
-        assert!(executor.is_closed());
-        assert_error_result(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([4]))),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-        assert_error_result(block_on(executor.close()), ErrorKind::Other, &expected);
-        assert_error_result(block_on(executor.close()), ErrorKind::Other, &expected);
-        assert_eq!(attempts.load(Ordering::SeqCst), 1);
-    }
-
-    #[test]
-    fn direct_teardown_failure_terminally_retires_the_handle() {
-        assert_topology_close_failure_is_terminal("direct");
-    }
-
-    #[test]
-    fn broker_teardown_failure_terminally_retires_the_handle() {
-        assert_topology_close_failure_is_terminal("broker");
-    }
-
-    #[test]
-    fn server_teardown_failure_terminally_retires_the_handle() {
-        assert_topology_close_failure_is_terminal("server");
-    }
-
-    struct PanickingCloseSession;
-
-    impl EngineSession for PanickingCloseSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-
-        fn close(&mut self) -> Result<()> {
-            panic!("injected close panic");
-        }
-    }
-
-    #[test]
-    fn close_panic_is_one_exact_terminal_outcome() {
-        let executor = EngineExecutor::spawn(Box::new(PanickingCloseSession));
-        let expected = "native engine session panicked during close: injected close panic";
-
-        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
-        assert!(executor.is_closed());
-        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
-        assert_error_result(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([1]))),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-    }
-
-    struct PanickingDropSession;
-
-    impl EngineSession for PanickingDropSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-    }
-
-    impl Drop for PanickingDropSession {
-        fn drop(&mut self) {
-            panic!("injected session destructor panic");
-        }
-    }
-
-    #[test]
-    fn destructor_panic_fails_close_without_stranding_its_waiter() {
-        let executor = EngineExecutor::spawn(Box::new(PanickingDropSession));
-        let expected = "native engine session destructor panicked after close: injected session destructor panic";
-        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
-        assert!(executor.is_closed());
-        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
-        assert_error_result(
-            block_on(executor.exec_protocol_raw(ProtocolRequest::new([1]))),
-            ErrorKind::Lifecycle,
-            "native database session has stopped",
-        );
-    }
-
-    struct CoalescingCloseSession {
-        calls: Arc,
-        started: mpsc::Sender<()>,
-        release: mpsc::Receiver<()>,
-        closed: Arc,
-    }
-
-    impl EngineSession for CoalescingCloseSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-
-        fn close(&mut self) -> Result<()> {
-            self.calls.fetch_add(1, Ordering::SeqCst);
-            self.started.send(()).expect("announce close");
-            self.release.recv().expect("release close");
-            self.closed.store(true, Ordering::SeqCst);
-            Ok(())
-        }
-    }
-
-    #[test]
-    fn concurrent_close_calls_coalesce_onto_one_definitive_attempt() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let closed = Arc::new(AtomicBool::new(false));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(CoalescingCloseSession {
-            calls: Arc::clone(&calls),
-            started,
-            release: release_rx,
-            closed: Arc::clone(&closed),
-        }));
-
-        let first_executor = Arc::clone(&executor);
-        let first = thread::spawn(move || block_on(first_executor.close()));
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("first close reaches owner");
-        let second_executor = Arc::clone(&executor);
-        let second = thread::spawn(move || block_on(second_executor.close()));
-        let deadline = Instant::now() + Duration::from_secs(2);
-        while executor
-            .shared
-            .close_state
-            .lock()
-            .unwrap_or_else(|error| error.into_inner())
-            .waiters
-            .len()
-            < 2
-            && Instant::now() < deadline
-        {
-            thread::yield_now();
-        }
-        release.send(()).expect("finish close");
-
-        first
-            .join()
-            .expect("join first close")
-            .expect("first close");
-        second
-            .join()
-            .expect("join second close")
-            .expect("second close");
-        assert!(closed.load(Ordering::SeqCst));
-        assert_eq!(calls.load(Ordering::SeqCst), 1);
-    }
-
-    struct CoalescingFailedCloseSession {
-        calls: Arc,
-        started: mpsc::Sender<()>,
-        release: mpsc::Receiver<()>,
-    }
-
-    impl EngineSession for CoalescingFailedCloseSession {
-        fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-            Ok(ProtocolResponse::new(request.as_bytes()))
-        }
-
-        fn close(&mut self) -> Result<()> {
-            self.calls.fetch_add(1, Ordering::SeqCst);
-            self.started.send(()).expect("announce failed close");
-            self.release.recv().expect("release failed close");
-            Err(Error::Engine(
-                "injected concurrent teardown failure".to_owned(),
-            ))
-        }
-    }
-
-    #[test]
-    fn concurrent_and_repeated_failed_closes_share_one_exact_terminal_outcome() {
-        let calls = Arc::new(AtomicUsize::new(0));
-        let (started, started_rx) = mpsc::channel();
-        let (release, release_rx) = mpsc::channel();
-        let executor = EngineExecutor::spawn(Box::new(CoalescingFailedCloseSession {
-            calls: Arc::clone(&calls),
-            started,
-            release: release_rx,
-        }));
-        let expected = "injected concurrent teardown failure";
-
-        let first_executor = Arc::clone(&executor);
-        let first = thread::spawn(move || block_on(first_executor.close()));
-        started_rx
-            .recv_timeout(Duration::from_secs(2))
-            .expect("first close reaches owner");
-        let second_executor = Arc::clone(&executor);
-        let second = thread::spawn(move || block_on(second_executor.close()));
-        let deadline = Instant::now() + Duration::from_secs(2);
-        while executor
-            .shared
-            .close_state
-            .lock()
-            .unwrap_or_else(|error| error.into_inner())
-            .waiters
-            .len()
-            < 2
-            && Instant::now() < deadline
-        {
-            thread::yield_now();
-        }
-        assert_eq!(
-            executor
-                .shared
-                .close_state
-                .lock()
-                .unwrap_or_else(|error| error.into_inner())
-                .waiters
-                .len(),
-            2,
-            "second close must join the in-flight attempt before it resolves"
-        );
-        release.send(()).expect("finish failed close");
-
-        assert_error_result(
-            first.join().expect("join first close"),
-            ErrorKind::Other,
-            expected,
-        );
-        assert_error_result(
-            second.join().expect("join second close"),
-            ErrorKind::Other,
-            expected,
-        );
-        assert!(executor.is_closed());
-        assert_error_result(block_on(executor.close()), ErrorKind::Other, expected);
-        assert_eq!(calls.load(Ordering::SeqCst), 1);
-    }
-}
diff --git a/src/sdks/rust/src/extension.rs b/src/sdks/rust/src/extension.rs
deleted file mode 100644
index 67a95b1a9..000000000
--- a/src/sdks/rust/src/extension.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-use std::collections::BTreeSet;
-
-use crate::error::{Error, Result};
-
-#[path = "generated/extensions.rs"]
-mod generated_extensions;
-pub use generated_extensions::Extension;
-
-impl Extension {
-    /// SQL extension name used by `CREATE EXTENSION`.
-    pub const fn sql_name(self) -> &'static str {
-        generated_extensions::sql_name(self)
-    }
-
-    pub(crate) const fn native_module_stem(self) -> Option<&'static str> {
-        generated_extensions::native_module_stem(self)
-    }
-
-    pub(crate) fn native_module_file(self) -> Option {
-        self.native_module_stem()
-            .map(|stem| format!("{}{}", stem, std::env::consts::DLL_SUFFIX))
-    }
-
-    pub(crate) const fn creates_extension(self) -> bool {
-        generated_extensions::creates_extension(self)
-    }
-
-    pub(crate) const fn dependencies(self) -> &'static [Extension] {
-        generated_extensions::dependencies(self)
-    }
-
-    pub(crate) const fn required_shared_preload_library(self) -> Option<&'static str> {
-        generated_extensions::required_shared_preload_library(self)
-    }
-
-    /// Resolve an extension by SQL name.
-    pub fn by_sql_name(sql_name: &str) -> Option {
-        Self::ALL
-            .iter()
-            .copied()
-            .find(|extension| extension.sql_name() == sql_name)
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub(crate) struct ExtensionRuntimeEnvironment {
-    pub(crate) name: &'static str,
-    pub(crate) relative_path: &'static str,
-    pub(crate) required_file: &'static str,
-}
-
-pub(crate) fn resolve_extensions(direct_extensions: &[Extension]) -> Result> {
-    let mut requested = Vec::new();
-    requested.extend_from_slice(direct_extensions);
-
-    let mut resolved = Vec::new();
-    let mut visiting = BTreeSet::new();
-    let mut visited = BTreeSet::new();
-    for extension in requested {
-        visit_extension(extension, &mut visiting, &mut visited, &mut resolved)?;
-    }
-    Ok(resolved)
-}
-
-pub(crate) fn required_shared_preload_libraries(extensions: &[Extension]) -> Vec<&'static str> {
-    extensions
-        .iter()
-        .filter_map(|extension| extension.required_shared_preload_library())
-        .collect::>()
-        .into_iter()
-        .collect()
-}
-
-fn visit_extension(
-    extension: Extension,
-    visiting: &mut BTreeSet,
-    visited: &mut BTreeSet,
-    resolved: &mut Vec,
-) -> Result<()> {
-    if visited.contains(&extension) {
-        return Ok(());
-    }
-    if !visiting.insert(extension) {
-        return Err(Error::InvalidConfig(format!(
-            "cyclic native extension dependency involving '{}'",
-            extension.sql_name()
-        )));
-    }
-    for dependency in extension.dependencies() {
-        visit_extension(*dependency, visiting, visited, resolved)?;
-    }
-    visiting.remove(&extension);
-    visited.insert(extension);
-    resolved.push(extension);
-    Ok(())
-}
-
-pub(crate) fn extension_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
-    file_name == format!("{sql_name}.control")
-        || file_name == format!("{sql_name}.sql")
-        || extension_install_sql_file_belongs(sql_name, file_name)
-        || extension_versioned_sql_file_belongs(sql_name, file_name)
-        || extension_extra_sql_file_belongs(sql_name, file_name)
-}
-
-fn extension_versioned_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
-    file_name
-        .strip_prefix(&format!("{sql_name}--"))
-        .and_then(|value| value.strip_suffix(".sql"))
-        .is_some_and(|version_path| {
-            !version_path.is_empty()
-                && version_path
-                    .bytes()
-                    .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
-        })
-}
-
-pub(crate) fn extension_install_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
-    let Some(version) = file_name
-        .strip_prefix(&format!("{sql_name}--"))
-        .and_then(|value| value.strip_suffix(".sql"))
-    else {
-        return false;
-    };
-    !version.is_empty()
-        && !version.contains("--")
-        && version.as_bytes()[0].is_ascii_digit()
-        && version
-            .bytes()
-            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
-}
-
-pub(crate) const fn extension_runtime_environment(
-    extension: Extension,
-) -> &'static [ExtensionRuntimeEnvironment] {
-    generated_extensions::runtime_environment(extension)
-}
-
-fn extension_extra_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
-    let Some(extension) = Extension::by_sql_name(sql_name) else {
-        return false;
-    };
-    generated_extensions::extension_sql_file_names(extension).contains(&file_name)
-        || generated_extensions::extension_sql_file_prefixes(extension)
-            .iter()
-            .any(|prefix| file_name.starts_with(prefix))
-}
-
-pub(crate) const fn extension_data_files(extension: Extension) -> &'static [&'static str] {
-    generated_extensions::extension_data_files(extension)
-}
diff --git a/src/sdks/rust/src/generated/extensions.rs b/src/sdks/rust/src/generated/extensions.rs
deleted file mode 100644
index ecd5d499f..000000000
--- a/src/sdks/rust/src/generated/extensions.rs
+++ /dev/null
@@ -1,719 +0,0 @@
-// @generated by src/extensions/tools/check-extension-model.mjs --write
-// Do not edit by hand.
-
-use super::ExtensionRuntimeEnvironment;
-
-/// Native PostgreSQL 18 extension artifact that can be selected by an app.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct Extension {
-    id: ExtensionId,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
-enum ExtensionId {
-    /// PostgreSQL `amcheck`.
-    Amcheck,
-    /// PostgreSQL `auto_explain`.
-    AutoExplain,
-    /// PostgreSQL `bloom`.
-    Bloom,
-    /// PostgreSQL `btree_gin`.
-    BtreeGin,
-    /// PostgreSQL `btree_gist`.
-    BtreeGist,
-    /// PostgreSQL `citext`.
-    Citext,
-    /// PostgreSQL `cube`.
-    Cube,
-    /// PostgreSQL `dict_int`.
-    DictInt,
-    /// PostgreSQL `dict_xsyn`.
-    DictXsyn,
-    /// PostgreSQL `earthdistance`.
-    Earthdistance,
-    /// PostgreSQL `file_fdw`.
-    FileFdw,
-    /// PostgreSQL `fuzzystrmatch`.
-    Fuzzystrmatch,
-    /// PostgreSQL `hstore`.
-    Hstore,
-    /// PostgreSQL `intarray`.
-    Intarray,
-    /// PostgreSQL `isn`.
-    Isn,
-    /// PostgreSQL `lo`.
-    Lo,
-    /// PostgreSQL `ltree`.
-    Ltree,
-    /// PostgreSQL `pageinspect`.
-    Pageinspect,
-    /// PostgreSQL `pg_buffercache`.
-    PgBuffercache,
-    /// PostgreSQL `pg_freespacemap`.
-    PgFreespacemap,
-    /// PostgreSQL `pg_hashids`.
-    PgHashids,
-    /// PostgreSQL `pg_ivm`.
-    PgIvm,
-    /// PostgreSQL `pg_surgery`.
-    PgSurgery,
-    /// PostgreSQL `pg_textsearch`.
-    PgTextsearch,
-    /// PostgreSQL `pg_trgm`.
-    PgTrgm,
-    /// PostgreSQL `pg_uuidv7`.
-    PgUuidv7,
-    /// PostgreSQL `pg_visibility`.
-    PgVisibility,
-    /// PostgreSQL `pg_walinspect`.
-    PgWalinspect,
-    /// PostgreSQL `pgcrypto`.
-    Pgcrypto,
-    /// PostgreSQL `pgtap`.
-    Pgtap,
-    /// PostgreSQL `postgis`.
-    Postgis,
-    /// PostgreSQL `seg`.
-    Seg,
-    /// PostgreSQL `tablefunc`.
-    Tablefunc,
-    /// PostgreSQL `tcn`.
-    Tcn,
-    /// PostgreSQL `tsm_system_rows`.
-    TsmSystemRows,
-    /// PostgreSQL `tsm_system_time`.
-    TsmSystemTime,
-    /// PostgreSQL `unaccent`.
-    Unaccent,
-    /// PostgreSQL `uuid-ossp`.
-    UuidOssp,
-    /// PostgreSQL `vector`.
-    Vector,
-}
-
-impl Extension {
-    /// Select the `amcheck` artifact.
-    pub const AMCHECK: Self = Self {
-        id: ExtensionId::Amcheck,
-    };
-    /// Select the `auto_explain` artifact.
-    pub const AUTO_EXPLAIN: Self = Self {
-        id: ExtensionId::AutoExplain,
-    };
-    /// Select the `bloom` artifact.
-    pub const BLOOM: Self = Self {
-        id: ExtensionId::Bloom,
-    };
-    /// Select the `btree_gin` artifact.
-    pub const BTREE_GIN: Self = Self {
-        id: ExtensionId::BtreeGin,
-    };
-    /// Select the `btree_gist` artifact.
-    pub const BTREE_GIST: Self = Self {
-        id: ExtensionId::BtreeGist,
-    };
-    /// Select the `citext` artifact.
-    pub const CITEXT: Self = Self {
-        id: ExtensionId::Citext,
-    };
-    /// Select the `cube` artifact.
-    pub const CUBE: Self = Self {
-        id: ExtensionId::Cube,
-    };
-    /// Select the `dict_int` artifact.
-    pub const DICT_INT: Self = Self {
-        id: ExtensionId::DictInt,
-    };
-    /// Select the `dict_xsyn` artifact.
-    pub const DICT_XSYN: Self = Self {
-        id: ExtensionId::DictXsyn,
-    };
-    /// Select the `earthdistance` artifact.
-    pub const EARTHDISTANCE: Self = Self {
-        id: ExtensionId::Earthdistance,
-    };
-    /// Select the `file_fdw` artifact.
-    pub const FILE_FDW: Self = Self {
-        id: ExtensionId::FileFdw,
-    };
-    /// Select the `fuzzystrmatch` artifact.
-    pub const FUZZYSTRMATCH: Self = Self {
-        id: ExtensionId::Fuzzystrmatch,
-    };
-    /// Select the `hstore` artifact.
-    pub const HSTORE: Self = Self {
-        id: ExtensionId::Hstore,
-    };
-    /// Select the `intarray` artifact.
-    pub const INTARRAY: Self = Self {
-        id: ExtensionId::Intarray,
-    };
-    /// Select the `isn` artifact.
-    pub const ISN: Self = Self {
-        id: ExtensionId::Isn,
-    };
-    /// Select the `lo` artifact.
-    pub const LO: Self = Self {
-        id: ExtensionId::Lo,
-    };
-    /// Select the `ltree` artifact.
-    pub const LTREE: Self = Self {
-        id: ExtensionId::Ltree,
-    };
-    /// Select the `pageinspect` artifact.
-    pub const PAGEINSPECT: Self = Self {
-        id: ExtensionId::Pageinspect,
-    };
-    /// Select the `pg_buffercache` artifact.
-    pub const PG_BUFFERCACHE: Self = Self {
-        id: ExtensionId::PgBuffercache,
-    };
-    /// Select the `pg_freespacemap` artifact.
-    pub const PG_FREESPACEMAP: Self = Self {
-        id: ExtensionId::PgFreespacemap,
-    };
-    /// Select the `pg_hashids` artifact.
-    pub const PG_HASHIDS: Self = Self {
-        id: ExtensionId::PgHashids,
-    };
-    /// Select the `pg_ivm` artifact.
-    pub const PG_IVM: Self = Self {
-        id: ExtensionId::PgIvm,
-    };
-    /// Select the `pg_surgery` artifact.
-    pub const PG_SURGERY: Self = Self {
-        id: ExtensionId::PgSurgery,
-    };
-    /// Select the `pg_textsearch` artifact.
-    pub const PG_TEXTSEARCH: Self = Self {
-        id: ExtensionId::PgTextsearch,
-    };
-    /// Select the `pg_trgm` artifact.
-    pub const PG_TRGM: Self = Self {
-        id: ExtensionId::PgTrgm,
-    };
-    /// Select the `pg_uuidv7` artifact.
-    pub const PG_UUIDV7: Self = Self {
-        id: ExtensionId::PgUuidv7,
-    };
-    /// Select the `pg_visibility` artifact.
-    pub const PG_VISIBILITY: Self = Self {
-        id: ExtensionId::PgVisibility,
-    };
-    /// Select the `pg_walinspect` artifact.
-    pub const PG_WALINSPECT: Self = Self {
-        id: ExtensionId::PgWalinspect,
-    };
-    /// Select the `pgcrypto` artifact.
-    pub const PGCRYPTO: Self = Self {
-        id: ExtensionId::Pgcrypto,
-    };
-    /// Select the `pgtap` artifact.
-    pub const PGTAP: Self = Self {
-        id: ExtensionId::Pgtap,
-    };
-    /// Select the `postgis` artifact.
-    pub const POSTGIS: Self = Self {
-        id: ExtensionId::Postgis,
-    };
-    /// Select the `seg` artifact.
-    pub const SEG: Self = Self {
-        id: ExtensionId::Seg,
-    };
-    /// Select the `tablefunc` artifact.
-    pub const TABLEFUNC: Self = Self {
-        id: ExtensionId::Tablefunc,
-    };
-    /// Select the `tcn` artifact.
-    pub const TCN: Self = Self {
-        id: ExtensionId::Tcn,
-    };
-    /// Select the `tsm_system_rows` artifact.
-    pub const TSM_SYSTEM_ROWS: Self = Self {
-        id: ExtensionId::TsmSystemRows,
-    };
-    /// Select the `tsm_system_time` artifact.
-    pub const TSM_SYSTEM_TIME: Self = Self {
-        id: ExtensionId::TsmSystemTime,
-    };
-    /// Select the `unaccent` artifact.
-    pub const UNACCENT: Self = Self {
-        id: ExtensionId::Unaccent,
-    };
-    /// Select the `uuid-ossp` artifact.
-    pub const UUID_OSSP: Self = Self {
-        id: ExtensionId::UuidOssp,
-    };
-    /// Select the `vector` artifact.
-    pub const VECTOR: Self = Self {
-        id: ExtensionId::Vector,
-    };
-
-    /// All PostgreSQL 18 extension artifacts known to the native SDK.
-    pub const ALL: &'static [Self] = &[
-        Extension::AMCHECK,
-        Extension::AUTO_EXPLAIN,
-        Extension::BLOOM,
-        Extension::BTREE_GIN,
-        Extension::BTREE_GIST,
-        Extension::CITEXT,
-        Extension::CUBE,
-        Extension::DICT_INT,
-        Extension::DICT_XSYN,
-        Extension::EARTHDISTANCE,
-        Extension::FILE_FDW,
-        Extension::FUZZYSTRMATCH,
-        Extension::HSTORE,
-        Extension::INTARRAY,
-        Extension::ISN,
-        Extension::LO,
-        Extension::LTREE,
-        Extension::PAGEINSPECT,
-        Extension::PG_BUFFERCACHE,
-        Extension::PG_FREESPACEMAP,
-        Extension::PG_HASHIDS,
-        Extension::PG_IVM,
-        Extension::PG_SURGERY,
-        Extension::PG_TEXTSEARCH,
-        Extension::PG_TRGM,
-        Extension::PG_UUIDV7,
-        Extension::PG_VISIBILITY,
-        Extension::PG_WALINSPECT,
-        Extension::PGCRYPTO,
-        Extension::PGTAP,
-        Extension::POSTGIS,
-        Extension::SEG,
-        Extension::TABLEFUNC,
-        Extension::TCN,
-        Extension::TSM_SYSTEM_ROWS,
-        Extension::TSM_SYSTEM_TIME,
-        Extension::UNACCENT,
-        Extension::UUID_OSSP,
-        Extension::VECTOR,
-    ];
-}
-
-/// Generated extension metadata accessor.
-pub(super) const fn sql_name(extension: Extension) -> &'static str {
-    match extension.id {
-        ExtensionId::Amcheck => "amcheck",
-        ExtensionId::AutoExplain => "auto_explain",
-        ExtensionId::Bloom => "bloom",
-        ExtensionId::BtreeGin => "btree_gin",
-        ExtensionId::BtreeGist => "btree_gist",
-        ExtensionId::Citext => "citext",
-        ExtensionId::Cube => "cube",
-        ExtensionId::DictInt => "dict_int",
-        ExtensionId::DictXsyn => "dict_xsyn",
-        ExtensionId::Earthdistance => "earthdistance",
-        ExtensionId::FileFdw => "file_fdw",
-        ExtensionId::Fuzzystrmatch => "fuzzystrmatch",
-        ExtensionId::Hstore => "hstore",
-        ExtensionId::Intarray => "intarray",
-        ExtensionId::Isn => "isn",
-        ExtensionId::Lo => "lo",
-        ExtensionId::Ltree => "ltree",
-        ExtensionId::Pageinspect => "pageinspect",
-        ExtensionId::PgBuffercache => "pg_buffercache",
-        ExtensionId::PgFreespacemap => "pg_freespacemap",
-        ExtensionId::PgHashids => "pg_hashids",
-        ExtensionId::PgIvm => "pg_ivm",
-        ExtensionId::PgSurgery => "pg_surgery",
-        ExtensionId::PgTextsearch => "pg_textsearch",
-        ExtensionId::PgTrgm => "pg_trgm",
-        ExtensionId::PgUuidv7 => "pg_uuidv7",
-        ExtensionId::PgVisibility => "pg_visibility",
-        ExtensionId::PgWalinspect => "pg_walinspect",
-        ExtensionId::Pgcrypto => "pgcrypto",
-        ExtensionId::Pgtap => "pgtap",
-        ExtensionId::Postgis => "postgis",
-        ExtensionId::Seg => "seg",
-        ExtensionId::Tablefunc => "tablefunc",
-        ExtensionId::Tcn => "tcn",
-        ExtensionId::TsmSystemRows => "tsm_system_rows",
-        ExtensionId::TsmSystemTime => "tsm_system_time",
-        ExtensionId::Unaccent => "unaccent",
-        ExtensionId::UuidOssp => "uuid-ossp",
-        ExtensionId::Vector => "vector",
-    }
-}
-
-/// Generated extension metadata accessor.
-pub(super) const fn native_module_stem(extension: Extension) -> Option<&'static str> {
-    match extension.id {
-        ExtensionId::Amcheck => Some("amcheck"),
-        ExtensionId::AutoExplain => Some("auto_explain"),
-        ExtensionId::Bloom => Some("bloom"),
-        ExtensionId::BtreeGin => Some("btree_gin"),
-        ExtensionId::BtreeGist => Some("btree_gist"),
-        ExtensionId::Citext => Some("citext"),
-        ExtensionId::Cube => Some("cube"),
-        ExtensionId::DictInt => Some("dict_int"),
-        ExtensionId::DictXsyn => Some("dict_xsyn"),
-        ExtensionId::Earthdistance => Some("earthdistance"),
-        ExtensionId::FileFdw => Some("file_fdw"),
-        ExtensionId::Fuzzystrmatch => Some("fuzzystrmatch"),
-        ExtensionId::Hstore => Some("hstore"),
-        ExtensionId::Intarray => Some("_int"),
-        ExtensionId::Isn => Some("isn"),
-        ExtensionId::Lo => Some("lo"),
-        ExtensionId::Ltree => Some("ltree"),
-        ExtensionId::Pageinspect => Some("pageinspect"),
-        ExtensionId::PgBuffercache => Some("pg_buffercache"),
-        ExtensionId::PgFreespacemap => Some("pg_freespacemap"),
-        ExtensionId::PgHashids => Some("pg_hashids"),
-        ExtensionId::PgIvm => Some("pg_ivm"),
-        ExtensionId::PgSurgery => Some("pg_surgery"),
-        ExtensionId::PgTextsearch => Some("pg_textsearch"),
-        ExtensionId::PgTrgm => Some("pg_trgm"),
-        ExtensionId::PgUuidv7 => Some("pg_uuidv7"),
-        ExtensionId::PgVisibility => Some("pg_visibility"),
-        ExtensionId::PgWalinspect => Some("pg_walinspect"),
-        ExtensionId::Pgcrypto => Some("pgcrypto"),
-        ExtensionId::Pgtap => None,
-        ExtensionId::Postgis => Some("postgis-3"),
-        ExtensionId::Seg => Some("seg"),
-        ExtensionId::Tablefunc => Some("tablefunc"),
-        ExtensionId::Tcn => Some("tcn"),
-        ExtensionId::TsmSystemRows => Some("tsm_system_rows"),
-        ExtensionId::TsmSystemTime => Some("tsm_system_time"),
-        ExtensionId::Unaccent => Some("unaccent"),
-        ExtensionId::UuidOssp => Some("uuid-ossp"),
-        ExtensionId::Vector => Some("vector"),
-    }
-}
-
-/// Generated extension metadata accessor.
-pub(super) const fn creates_extension(extension: Extension) -> bool {
-    match extension.id {
-        ExtensionId::Amcheck => true,
-        ExtensionId::AutoExplain => false,
-        ExtensionId::Bloom => true,
-        ExtensionId::BtreeGin => true,
-        ExtensionId::BtreeGist => true,
-        ExtensionId::Citext => true,
-        ExtensionId::Cube => true,
-        ExtensionId::DictInt => true,
-        ExtensionId::DictXsyn => true,
-        ExtensionId::Earthdistance => true,
-        ExtensionId::FileFdw => true,
-        ExtensionId::Fuzzystrmatch => true,
-        ExtensionId::Hstore => true,
-        ExtensionId::Intarray => true,
-        ExtensionId::Isn => true,
-        ExtensionId::Lo => true,
-        ExtensionId::Ltree => true,
-        ExtensionId::Pageinspect => true,
-        ExtensionId::PgBuffercache => true,
-        ExtensionId::PgFreespacemap => true,
-        ExtensionId::PgHashids => true,
-        ExtensionId::PgIvm => true,
-        ExtensionId::PgSurgery => true,
-        ExtensionId::PgTextsearch => true,
-        ExtensionId::PgTrgm => true,
-        ExtensionId::PgUuidv7 => true,
-        ExtensionId::PgVisibility => true,
-        ExtensionId::PgWalinspect => true,
-        ExtensionId::Pgcrypto => true,
-        ExtensionId::Pgtap => true,
-        ExtensionId::Postgis => true,
-        ExtensionId::Seg => true,
-        ExtensionId::Tablefunc => true,
-        ExtensionId::Tcn => true,
-        ExtensionId::TsmSystemRows => true,
-        ExtensionId::TsmSystemTime => true,
-        ExtensionId::Unaccent => true,
-        ExtensionId::UuidOssp => true,
-        ExtensionId::Vector => true,
-    }
-}
-
-/// Generated extension metadata accessor.
-pub(super) const fn dependencies(extension: Extension) -> &'static [Extension] {
-    match extension.id {
-        ExtensionId::Amcheck => &[],
-        ExtensionId::AutoExplain => &[],
-        ExtensionId::Bloom => &[],
-        ExtensionId::BtreeGin => &[],
-        ExtensionId::BtreeGist => &[],
-        ExtensionId::Citext => &[],
-        ExtensionId::Cube => &[],
-        ExtensionId::DictInt => &[],
-        ExtensionId::DictXsyn => &[],
-        ExtensionId::Earthdistance => &[Extension::CUBE],
-        ExtensionId::FileFdw => &[],
-        ExtensionId::Fuzzystrmatch => &[],
-        ExtensionId::Hstore => &[],
-        ExtensionId::Intarray => &[],
-        ExtensionId::Isn => &[],
-        ExtensionId::Lo => &[],
-        ExtensionId::Ltree => &[],
-        ExtensionId::Pageinspect => &[],
-        ExtensionId::PgBuffercache => &[],
-        ExtensionId::PgFreespacemap => &[],
-        ExtensionId::PgHashids => &[],
-        ExtensionId::PgIvm => &[],
-        ExtensionId::PgSurgery => &[],
-        ExtensionId::PgTextsearch => &[],
-        ExtensionId::PgTrgm => &[],
-        ExtensionId::PgUuidv7 => &[],
-        ExtensionId::PgVisibility => &[],
-        ExtensionId::PgWalinspect => &[],
-        ExtensionId::Pgcrypto => &[],
-        ExtensionId::Pgtap => &[],
-        ExtensionId::Postgis => &[],
-        ExtensionId::Seg => &[],
-        ExtensionId::Tablefunc => &[],
-        ExtensionId::Tcn => &[],
-        ExtensionId::TsmSystemRows => &[],
-        ExtensionId::TsmSystemTime => &[],
-        ExtensionId::Unaccent => &[],
-        ExtensionId::UuidOssp => &[],
-        ExtensionId::Vector => &[],
-    }
-}
-
-/// Generated extension metadata accessor.
-pub(super) const fn required_shared_preload_library(extension: Extension) -> Option<&'static str> {
-    match extension.id {
-        ExtensionId::Amcheck => None,
-        ExtensionId::AutoExplain => None,
-        ExtensionId::Bloom => None,
-        ExtensionId::BtreeGin => None,
-        ExtensionId::BtreeGist => None,
-        ExtensionId::Citext => None,
-        ExtensionId::Cube => None,
-        ExtensionId::DictInt => None,
-        ExtensionId::DictXsyn => None,
-        ExtensionId::Earthdistance => None,
-        ExtensionId::FileFdw => None,
-        ExtensionId::Fuzzystrmatch => None,
-        ExtensionId::Hstore => None,
-        ExtensionId::Intarray => None,
-        ExtensionId::Isn => None,
-        ExtensionId::Lo => None,
-        ExtensionId::Ltree => None,
-        ExtensionId::Pageinspect => None,
-        ExtensionId::PgBuffercache => None,
-        ExtensionId::PgFreespacemap => None,
-        ExtensionId::PgHashids => None,
-        ExtensionId::PgIvm => None,
-        ExtensionId::PgSurgery => None,
-        ExtensionId::PgTextsearch => Some("pg_textsearch"),
-        ExtensionId::PgTrgm => None,
-        ExtensionId::PgUuidv7 => None,
-        ExtensionId::PgVisibility => None,
-        ExtensionId::PgWalinspect => None,
-        ExtensionId::Pgcrypto => None,
-        ExtensionId::Pgtap => None,
-        ExtensionId::Postgis => None,
-        ExtensionId::Seg => None,
-        ExtensionId::Tablefunc => None,
-        ExtensionId::Tcn => None,
-        ExtensionId::TsmSystemRows => None,
-        ExtensionId::TsmSystemTime => None,
-        ExtensionId::Unaccent => None,
-        ExtensionId::UuidOssp => None,
-        ExtensionId::Vector => None,
-    }
-}
-
-/// Generated extension metadata accessor.
-pub(super) const fn extension_data_files(extension: Extension) -> &'static [&'static str] {
-    match extension.id {
-        ExtensionId::Amcheck => &[],
-        ExtensionId::AutoExplain => &[],
-        ExtensionId::Bloom => &[],
-        ExtensionId::BtreeGin => &[],
-        ExtensionId::BtreeGist => &[],
-        ExtensionId::Citext => &[],
-        ExtensionId::Cube => &[],
-        ExtensionId::DictInt => &[],
-        ExtensionId::DictXsyn => &["tsearch_data/xsyn_sample.rules"],
-        ExtensionId::Earthdistance => &[],
-        ExtensionId::FileFdw => &[],
-        ExtensionId::Fuzzystrmatch => &[],
-        ExtensionId::Hstore => &[],
-        ExtensionId::Intarray => &[],
-        ExtensionId::Isn => &[],
-        ExtensionId::Lo => &[],
-        ExtensionId::Ltree => &[],
-        ExtensionId::Pageinspect => &[],
-        ExtensionId::PgBuffercache => &[],
-        ExtensionId::PgFreespacemap => &[],
-        ExtensionId::PgHashids => &[],
-        ExtensionId::PgIvm => &[],
-        ExtensionId::PgSurgery => &[],
-        ExtensionId::PgTextsearch => &[],
-        ExtensionId::PgTrgm => &[],
-        ExtensionId::PgUuidv7 => &[],
-        ExtensionId::PgVisibility => &[],
-        ExtensionId::PgWalinspect => &[],
-        ExtensionId::Pgcrypto => &[],
-        ExtensionId::Pgtap => &[],
-        ExtensionId::Postgis => &[
-            "contrib/postgis-3.6/legacy.sql",
-            "contrib/postgis-3.6/legacy_gist.sql",
-            "contrib/postgis-3.6/legacy_minimal.sql",
-            "contrib/postgis-3.6/postgis.sql",
-            "contrib/postgis-3.6/postgis_upgrade.sql",
-            "contrib/postgis-3.6/spatial_ref_sys.sql",
-            "contrib/postgis-3.6/uninstall_legacy.sql",
-            "contrib/postgis-3.6/uninstall_postgis.sql",
-            "proj/proj.db",
-        ],
-        ExtensionId::Seg => &[],
-        ExtensionId::Tablefunc => &[],
-        ExtensionId::Tcn => &[],
-        ExtensionId::TsmSystemRows => &[],
-        ExtensionId::TsmSystemTime => &[],
-        ExtensionId::Unaccent => &["tsearch_data/unaccent.rules"],
-        ExtensionId::UuidOssp => &[],
-        ExtensionId::Vector => &[],
-    }
-}
-
-/// Generated extension metadata accessor.
-pub(super) const fn extension_sql_file_prefixes(extension: Extension) -> &'static [&'static str] {
-    match extension.id {
-        ExtensionId::Amcheck => &[],
-        ExtensionId::AutoExplain => &[],
-        ExtensionId::Bloom => &[],
-        ExtensionId::BtreeGin => &[],
-        ExtensionId::BtreeGist => &[],
-        ExtensionId::Citext => &[],
-        ExtensionId::Cube => &[],
-        ExtensionId::DictInt => &[],
-        ExtensionId::DictXsyn => &[],
-        ExtensionId::Earthdistance => &[],
-        ExtensionId::FileFdw => &[],
-        ExtensionId::Fuzzystrmatch => &[],
-        ExtensionId::Hstore => &[],
-        ExtensionId::Intarray => &[],
-        ExtensionId::Isn => &[],
-        ExtensionId::Lo => &[],
-        ExtensionId::Ltree => &[],
-        ExtensionId::Pageinspect => &[],
-        ExtensionId::PgBuffercache => &[],
-        ExtensionId::PgFreespacemap => &[],
-        ExtensionId::PgHashids => &[],
-        ExtensionId::PgIvm => &[],
-        ExtensionId::PgSurgery => &[],
-        ExtensionId::PgTextsearch => &[],
-        ExtensionId::PgTrgm => &[],
-        ExtensionId::PgUuidv7 => &[],
-        ExtensionId::PgVisibility => &[],
-        ExtensionId::PgWalinspect => &[],
-        ExtensionId::Pgcrypto => &[],
-        ExtensionId::Pgtap => &["pgtap-core", "pgtap-schema"],
-        ExtensionId::Postgis => &[
-            "postgis_comments",
-            "postgis_proc_set_search_path",
-            "rtpostgis",
-        ],
-        ExtensionId::Seg => &[],
-        ExtensionId::Tablefunc => &[],
-        ExtensionId::Tcn => &[],
-        ExtensionId::TsmSystemRows => &[],
-        ExtensionId::TsmSystemTime => &[],
-        ExtensionId::Unaccent => &[],
-        ExtensionId::UuidOssp => &[],
-        ExtensionId::Vector => &[],
-    }
-}
-
-/// Generated extension metadata accessor.
-pub(super) const fn extension_sql_file_names(extension: Extension) -> &'static [&'static str] {
-    match extension.id {
-        ExtensionId::Amcheck => &[],
-        ExtensionId::AutoExplain => &[],
-        ExtensionId::Bloom => &[],
-        ExtensionId::BtreeGin => &[],
-        ExtensionId::BtreeGist => &[],
-        ExtensionId::Citext => &[],
-        ExtensionId::Cube => &[],
-        ExtensionId::DictInt => &[],
-        ExtensionId::DictXsyn => &[],
-        ExtensionId::Earthdistance => &[],
-        ExtensionId::FileFdw => &[],
-        ExtensionId::Fuzzystrmatch => &[],
-        ExtensionId::Hstore => &[],
-        ExtensionId::Intarray => &[],
-        ExtensionId::Isn => &[],
-        ExtensionId::Lo => &[],
-        ExtensionId::Ltree => &[],
-        ExtensionId::Pageinspect => &[],
-        ExtensionId::PgBuffercache => &[],
-        ExtensionId::PgFreespacemap => &[],
-        ExtensionId::PgHashids => &[],
-        ExtensionId::PgIvm => &[],
-        ExtensionId::PgSurgery => &[],
-        ExtensionId::PgTextsearch => &[],
-        ExtensionId::PgTrgm => &[],
-        ExtensionId::PgUuidv7 => &[],
-        ExtensionId::PgVisibility => &[],
-        ExtensionId::PgWalinspect => &[],
-        ExtensionId::Pgcrypto => &[],
-        ExtensionId::Pgtap => &["uninstall_pgtap.sql"],
-        ExtensionId::Postgis => &["uninstall_postgis.sql"],
-        ExtensionId::Seg => &[],
-        ExtensionId::Tablefunc => &[],
-        ExtensionId::Tcn => &[],
-        ExtensionId::TsmSystemRows => &[],
-        ExtensionId::TsmSystemTime => &[],
-        ExtensionId::Unaccent => &[],
-        ExtensionId::UuidOssp => &[],
-        ExtensionId::Vector => &[],
-    }
-}
-
-/// Generated extension metadata accessor.
-pub(super) const fn runtime_environment(
-    extension: Extension,
-) -> &'static [ExtensionRuntimeEnvironment] {
-    match extension.id {
-        ExtensionId::Amcheck => &[],
-        ExtensionId::AutoExplain => &[],
-        ExtensionId::Bloom => &[],
-        ExtensionId::BtreeGin => &[],
-        ExtensionId::BtreeGist => &[],
-        ExtensionId::Citext => &[],
-        ExtensionId::Cube => &[],
-        ExtensionId::DictInt => &[],
-        ExtensionId::DictXsyn => &[],
-        ExtensionId::Earthdistance => &[],
-        ExtensionId::FileFdw => &[],
-        ExtensionId::Fuzzystrmatch => &[],
-        ExtensionId::Hstore => &[],
-        ExtensionId::Intarray => &[],
-        ExtensionId::Isn => &[],
-        ExtensionId::Lo => &[],
-        ExtensionId::Ltree => &[],
-        ExtensionId::Pageinspect => &[],
-        ExtensionId::PgBuffercache => &[],
-        ExtensionId::PgFreespacemap => &[],
-        ExtensionId::PgHashids => &[],
-        ExtensionId::PgIvm => &[],
-        ExtensionId::PgSurgery => &[],
-        ExtensionId::PgTextsearch => &[],
-        ExtensionId::PgTrgm => &[],
-        ExtensionId::PgUuidv7 => &[],
-        ExtensionId::PgVisibility => &[],
-        ExtensionId::PgWalinspect => &[],
-        ExtensionId::Pgcrypto => &[],
-        ExtensionId::Pgtap => &[],
-        ExtensionId::Postgis => &[ExtensionRuntimeEnvironment {
-            name: "PROJ_DATA",
-            relative_path: "share/postgresql/proj",
-            required_file: "proj.db",
-        }],
-        ExtensionId::Seg => &[],
-        ExtensionId::Tablefunc => &[],
-        ExtensionId::Tcn => &[],
-        ExtensionId::TsmSystemRows => &[],
-        ExtensionId::TsmSystemTime => &[],
-        ExtensionId::Unaccent => &[],
-        ExtensionId::UuidOssp => &[],
-        ExtensionId::Vector => &[],
-    }
-}
diff --git a/src/sdks/rust/src/ipc.rs b/src/sdks/rust/src/ipc.rs
deleted file mode 100644
index 1b45f14e8..000000000
--- a/src/sdks/rust/src/ipc.rs
+++ /dev/null
@@ -1,299 +0,0 @@
-use std::io::{Read, Write};
-
-use crate::error::{Error, Result};
-
-const MAGIC: &[u8; 4] = b"PGOB";
-const HEADER_LEN: usize = 13;
-const MAX_FRAME_LEN: u64 = 128 * 1024 * 1024;
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) enum RequestFrame {
-    Authenticate(String),
-    ExecProtocol(Vec),
-    ExecProtocolStream(Vec),
-    #[cfg(any(feature = "__internal-broker-helper", test))]
-    ExecSimpleQuery(String),
-    Close,
-    Backup,
-    Cancel,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) enum ResponseFrame {
-    Ok(Vec),
-    Error(String),
-    Chunk(Vec),
-    StreamCallbackAborted(String),
-}
-
-/// Internal broker IPC request used by the packaged broker helper.
-#[cfg(feature = "__internal-broker-helper")]
-#[doc(hidden)]
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum BrokerIpcRequest {
-    /// Authenticate the parent SDK process to the broker helper.
-    Authenticate(String),
-    /// Execute raw PostgreSQL protocol bytes.
-    ExecProtocol(Vec),
-    /// Execute raw PostgreSQL protocol bytes and stream backend response chunks.
-    ExecProtocolStream(Vec),
-    /// Execute SQL through PostgreSQL's simple-query protocol.
-    ExecSimpleQuery(String),
-    /// Create a backup artifact.
-    Backup,
-    /// Cancel the active backend query.
-    Cancel,
-    /// Close the broker session.
-    Close,
-}
-
-/// Read one broker IPC request from a stream.
-#[cfg(feature = "__internal-broker-helper")]
-#[doc(hidden)]
-pub fn broker_ipc_read_request(reader: &mut impl Read) -> Result {
-    match read_request(reader)? {
-        RequestFrame::Authenticate(token) => Ok(BrokerIpcRequest::Authenticate(token)),
-        RequestFrame::ExecProtocol(bytes) => Ok(BrokerIpcRequest::ExecProtocol(bytes)),
-        RequestFrame::ExecProtocolStream(bytes) => Ok(BrokerIpcRequest::ExecProtocolStream(bytes)),
-        RequestFrame::ExecSimpleQuery(sql) => Ok(BrokerIpcRequest::ExecSimpleQuery(sql)),
-        RequestFrame::Backup => Ok(BrokerIpcRequest::Backup),
-        RequestFrame::Cancel => Ok(BrokerIpcRequest::Cancel),
-        RequestFrame::Close => Ok(BrokerIpcRequest::Close),
-    }
-}
-
-/// Write a successful broker IPC response.
-#[cfg(feature = "__internal-broker-helper")]
-#[doc(hidden)]
-pub fn broker_ipc_write_ok(writer: &mut impl Write, bytes: Vec) -> Result<()> {
-    write_response(writer, ResponseFrame::Ok(bytes))
-}
-
-/// Write one successful broker IPC stream chunk.
-#[cfg(any(feature = "__internal-broker-helper", test))]
-#[doc(hidden)]
-pub fn broker_ipc_write_chunk(writer: &mut impl Write, bytes: &[u8]) -> Result<()> {
-    write_response(writer, ResponseFrame::Chunk(bytes.to_vec()))
-}
-
-/// Write a failed broker IPC response.
-#[cfg(feature = "__internal-broker-helper")]
-#[doc(hidden)]
-pub fn broker_ipc_write_error(writer: &mut impl Write, message: String) -> Result<()> {
-    write_response(writer, ResponseFrame::Error(message))
-}
-
-/// Write a streamed-protocol callback failure after the broker runtime has
-/// independently confirmed ReadyForQuery.
-#[cfg(any(feature = "__internal-broker-helper", test))]
-#[doc(hidden)]
-pub fn broker_ipc_write_stream_callback_aborted(
-    writer: &mut impl Write,
-    message: String,
-) -> Result<()> {
-    write_response(writer, ResponseFrame::StreamCallbackAborted(message))
-}
-
-pub(crate) fn write_request(writer: &mut impl Write, frame: RequestFrame) -> Result<()> {
-    match frame {
-        RequestFrame::Authenticate(token) => write_frame(writer, 6, token.as_bytes()),
-        RequestFrame::ExecProtocol(bytes) => write_frame(writer, 1, &bytes),
-        RequestFrame::ExecProtocolStream(bytes) => write_frame(writer, 4, &bytes),
-        #[cfg(any(feature = "__internal-broker-helper", test))]
-        RequestFrame::ExecSimpleQuery(sql) => write_frame(writer, 8, sql.as_bytes()),
-        RequestFrame::Close => write_frame(writer, 3, &[]),
-        RequestFrame::Backup => write_frame(writer, 5, &[]),
-        RequestFrame::Cancel => write_frame(writer, 7, &[]),
-    }
-}
-
-#[cfg(any(feature = "__internal-broker-helper", test))]
-pub(crate) fn read_request(reader: &mut impl Read) -> Result {
-    let (kind, payload) = read_frame(reader)?;
-    match kind {
-        6 => String::from_utf8(payload)
-            .map(RequestFrame::Authenticate)
-            .map_err(|err| Error::Engine(format!("broker auth frame is not UTF-8: {err}"))),
-        1 => Ok(RequestFrame::ExecProtocol(payload)),
-        4 => Ok(RequestFrame::ExecProtocolStream(payload)),
-        8 => String::from_utf8(payload)
-            .map(RequestFrame::ExecSimpleQuery)
-            .map_err(|err| Error::Engine(format!("broker simple-query frame is not UTF-8: {err}"))),
-        3 => empty_payload(payload, RequestFrame::Close),
-        5 => empty_payload(payload, RequestFrame::Backup),
-        7 => empty_payload(payload, RequestFrame::Cancel),
-        _ => Err(Error::Engine(format!(
-            "unknown broker request frame {kind}"
-        ))),
-    }
-}
-
-#[cfg(any(feature = "__internal-broker-helper", test))]
-pub(crate) fn write_response(writer: &mut impl Write, frame: ResponseFrame) -> Result<()> {
-    match frame {
-        ResponseFrame::Ok(bytes) => write_frame(writer, 101, &bytes),
-        ResponseFrame::Error(message) => write_frame(writer, 102, message.as_bytes()),
-        ResponseFrame::Chunk(bytes) => write_frame(writer, 103, &bytes),
-        ResponseFrame::StreamCallbackAborted(message) => {
-            write_frame(writer, 104, message.as_bytes())
-        }
-    }
-}
-
-pub(crate) fn read_response(reader: &mut impl Read) -> Result {
-    let (kind, payload) = read_frame(reader)?;
-    match kind {
-        101 => Ok(ResponseFrame::Ok(payload)),
-        102 => String::from_utf8(payload)
-            .map(ResponseFrame::Error)
-            .map_err(|err| Error::Engine(format!("broker error frame is not UTF-8: {err}"))),
-        103 => Ok(ResponseFrame::Chunk(payload)),
-        104 => String::from_utf8(payload)
-            .map(ResponseFrame::StreamCallbackAborted)
-            .map_err(|err| {
-                Error::Engine(format!(
-                    "broker stream callback-aborted frame is not UTF-8: {err}"
-                ))
-            }),
-        _ => Err(Error::Engine(format!(
-            "unknown broker response frame {kind}"
-        ))),
-    }
-}
-
-#[cfg(any(feature = "__internal-broker-helper", test))]
-fn empty_payload(payload: Vec, frame: RequestFrame) -> Result {
-    if payload.is_empty() {
-        Ok(frame)
-    } else {
-        Err(Error::Engine(
-            "broker control frame unexpectedly had a payload".to_owned(),
-        ))
-    }
-}
-
-fn write_frame(writer: &mut impl Write, kind: u8, payload: &[u8]) -> Result<()> {
-    let len = u64::try_from(payload.len())
-        .map_err(|_| Error::Engine("broker frame payload is too large".to_owned()))?;
-    let mut header = [0_u8; HEADER_LEN];
-    header[..4].copy_from_slice(MAGIC);
-    header[4] = kind;
-    header[5..].copy_from_slice(&len.to_be_bytes());
-    writer
-        .write_all(&header)
-        .and_then(|()| writer.write_all(payload))
-        .and_then(|()| writer.flush())
-        .map_err(|err| Error::Engine(format!("write broker frame: {err}")))
-}
-
-fn read_frame(reader: &mut impl Read) -> Result<(u8, Vec)> {
-    let mut header = [0_u8; HEADER_LEN];
-    reader
-        .read_exact(&mut header)
-        .map_err(|err| Error::Engine(format!("read broker frame header: {err}")))?;
-    if &header[..4] != MAGIC {
-        return Err(Error::Engine("broker frame magic mismatch".to_owned()));
-    }
-    let kind = header[4];
-    let len = u64::from_be_bytes(
-        header[5..]
-            .try_into()
-            .expect("frame header contains an 8-byte payload length"),
-    );
-    if len > MAX_FRAME_LEN {
-        return Err(Error::Engine(format!(
-            "broker frame payload length {len} exceeds limit {MAX_FRAME_LEN}"
-        )));
-    }
-    let mut payload = vec![0_u8; len as usize];
-    reader
-        .read_exact(&mut payload)
-        .map_err(|err| Error::Engine(format!("read broker frame payload: {err}")))?;
-    Ok((kind, payload))
-}
-
-#[cfg(test)]
-mod tests {
-    use std::io::Cursor;
-
-    use super::*;
-
-    #[test]
-    fn auth_frame_round_trips() {
-        let mut bytes = Vec::new();
-        write_request(
-            &mut bytes,
-            RequestFrame::Authenticate("token-123".to_owned()),
-        )
-        .unwrap();
-
-        let mut cursor = Cursor::new(bytes);
-        assert_eq!(
-            read_request(&mut cursor).unwrap(),
-            RequestFrame::Authenticate("token-123".to_owned())
-        );
-    }
-
-    #[test]
-    fn backup_frame_still_round_trips() {
-        let mut bytes = Vec::new();
-        write_request(&mut bytes, RequestFrame::Backup).unwrap();
-
-        let mut cursor = Cursor::new(bytes);
-        assert_eq!(read_request(&mut cursor).unwrap(), RequestFrame::Backup);
-    }
-
-    #[test]
-    fn simple_query_frame_round_trips() {
-        let mut bytes = Vec::new();
-        write_request(
-            &mut bytes,
-            RequestFrame::ExecSimpleQuery("SELECT 1".to_owned()),
-        )
-        .unwrap();
-
-        let mut cursor = Cursor::new(bytes);
-        assert_eq!(
-            read_request(&mut cursor).unwrap(),
-            RequestFrame::ExecSimpleQuery("SELECT 1".to_owned())
-        );
-    }
-
-    #[test]
-    fn cancel_frame_round_trips() {
-        let mut bytes = Vec::new();
-        write_request(&mut bytes, RequestFrame::Cancel).unwrap();
-
-        let mut cursor = Cursor::new(bytes);
-        assert_eq!(read_request(&mut cursor).unwrap(), RequestFrame::Cancel);
-    }
-
-    #[test]
-    fn streaming_request_and_chunk_frames_round_trip() {
-        let mut request = Vec::new();
-        write_request(
-            &mut request,
-            RequestFrame::ExecProtocolStream(vec![0x51, 0, 0, 0, 4]),
-        )
-        .unwrap();
-        assert_eq!(
-            read_request(&mut Cursor::new(request)).unwrap(),
-            RequestFrame::ExecProtocolStream(vec![0x51, 0, 0, 0, 4])
-        );
-
-        let mut response = Vec::new();
-        broker_ipc_write_chunk(&mut response, &[0x5a]).unwrap();
-        assert_eq!(
-            read_response(&mut Cursor::new(response)).unwrap(),
-            ResponseFrame::Chunk(vec![0x5a])
-        );
-
-        let mut response = Vec::new();
-        broker_ipc_write_stream_callback_aborted(&mut response, "consumer stopped".to_owned())
-            .unwrap();
-        assert_eq!(
-            read_response(&mut Cursor::new(response)).unwrap(),
-            ResponseFrame::StreamCallbackAborted("consumer stopped".to_owned())
-        );
-    }
-}
diff --git a/src/sdks/rust/src/lib.rs b/src/sdks/rust/src/lib.rs
deleted file mode 100644
index ec60036e9..000000000
--- a/src/sdks/rust/src/lib.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-#![deny(unsafe_op_in_unsafe_fn)]
-#![forbid(missing_docs)]
-//! Native-first Rust SDK surface for embedded Oliphaunt.
-//!
-//! This crate is deliberately native-only. It does not expose a WASIX engine
-//! and it does not depend on the current `oliphaunt-wasix` runtime layout.
-
-mod broker;
-#[cfg(any(
-    feature = "__internal-broker-helper",
-    feature = "internal-native-packaging"
-))]
-#[doc(hidden)]
-pub mod __private {
-    #[cfg(feature = "__internal-broker-helper")]
-    // This is a version-locked cross-package seam for the separately built
-    // Oliphaunt broker executable. It is not an application SDK surface.
-    include!("broker_support.rs");
-
-    #[cfg(feature = "__internal-broker-helper")]
-    #[doc(hidden)]
-    pub use crate::ipc::{
-        BrokerIpcRequest, broker_ipc_read_request, broker_ipc_write_chunk, broker_ipc_write_error,
-        broker_ipc_write_ok, broker_ipc_write_stream_callback_aborted,
-    };
-
-    /// Version-locked bridge for the unpublished native packaging workspace tool.
-    #[cfg(feature = "internal-native-packaging")]
-    #[doc(hidden)]
-    pub mod packaging {
-        #[doc(hidden)]
-        pub use crate::liboliphaunt::{
-            NativePackagingCatalogProfile, NativePackagingResources, NativePackagingRuntime,
-            materialize_native_packaging_resources,
-        };
-    }
-}
-mod build_resources;
-mod builder;
-mod cancellation;
-mod child_process;
-mod config;
-mod database;
-mod direct;
-mod engine;
-mod error;
-mod executor;
-mod extension;
-mod ipc;
-#[allow(unsafe_code)]
-mod liboliphaunt;
-mod pgwire;
-mod protocol;
-mod query;
-mod query_core {
-    include!(env!("OLIPHAUNT_QUERY_CORE_RS"));
-}
-mod reply;
-mod server;
-mod session;
-mod storage;
-#[cfg(test)]
-mod test_fixtures;
-pub use build_resources::register_build_resources_dir;
-pub use builder::{AsyncOliphauntBuilder, AsyncOliphauntServerBuilder};
-pub use config::ServerListen;
-pub use database::{AsyncOliphaunt, AsyncOliphauntServer, AsyncSql, AsyncTransaction};
-pub use direct::{
-    CancelHandle, Oliphaunt, OliphauntBuilder, OliphauntServer, OliphauntServerBuilder, Sql,
-    Transaction,
-};
-pub use error::{
-    Error, ErrorKind, PostgresError, PostgresErrorField, RawStreamCallbackOutput, RawStreamError,
-    RawStreamResult, Result, TransactionError, TransactionResult,
-};
-pub use extension::Extension;
-pub use query::{
-    CommandResult, DecodeError, ExecResult, FromSql, IntoParameter, Parameter, PostgresNotice,
-    QueryField, QueryFormat, QueryResult, QueryRow, RowIndex, StatementDescription,
-    StatementResult, TypeOid, ValueFormat, ValueRef,
-};
-pub use storage::DatabaseStorage;
diff --git a/src/sdks/rust/src/liboliphaunt/ffi.rs b/src/sdks/rust/src/liboliphaunt/ffi.rs
deleted file mode 100644
index 44794f5f3..000000000
--- a/src/sdks/rust/src/liboliphaunt/ffi.rs
+++ /dev/null
@@ -1,321 +0,0 @@
-use std::ffi::{CString, c_char, c_int, c_uchar, c_void};
-use std::mem::ManuallyDrop;
-use std::path::{Path, PathBuf};
-
-use libloading::Library;
-
-use crate::error::{Error, Result};
-
-pub(super) const ABI_VERSION: u32 = 10;
-pub(super) const CONFIG_EXTERNAL_ROOT_LOCK: u64 = 1 << 0;
-pub(super) const ERROR_CAPTURE_CAPACITY: usize = 1024;
-/// Positive stream status reserved by ABI 10 for a callback abort after the
-/// runtime has independently confirmed the request's ReadyForQuery boundary.
-pub(super) const STREAM_CALLBACK_ABORTED_STATUS: c_int = 1;
-
-pub(super) const ENV_OLIPHAUNT: &str = "LIBOLIPHAUNT_PATH";
-pub(super) const ENV_INSTALL_DIR: &str = "OLIPHAUNT_INSTALL_DIR";
-pub(super) const ENV_EMBEDDED_MODULE_DIR: &str = "OLIPHAUNT_EMBEDDED_MODULE_DIR";
-pub(super) const ENV_POSTGRES: &str = "OLIPHAUNT_POSTGRES";
-pub(super) const ENV_INITDB: &str = "OLIPHAUNT_INITDB";
-
-#[repr(C)]
-pub(super) struct NativeConfig {
-    pub(super) abi_version: u32,
-    pub(super) pgdata: *const c_char,
-    pub(super) runtime_dir: *const c_char,
-    pub(super) module_dir: *const c_char,
-    pub(super) username: *const c_char,
-    pub(super) database: *const c_char,
-    pub(super) flags: u64,
-    pub(super) startup_args: *const *const c_char,
-    pub(super) startup_arg_count: usize,
-}
-
-#[repr(C)]
-pub(super) struct NativeResponse {
-    pub(super) data: *mut c_uchar,
-    pub(super) len: usize,
-}
-
-#[repr(C)]
-pub(super) struct NativeErrorCapture {
-    length: u32,
-    message: [c_char; ERROR_CAPTURE_CAPACITY],
-}
-
-impl NativeErrorCapture {
-    pub(super) const fn zeroed() -> Self {
-        Self {
-            length: 0,
-            message: [0; ERROR_CAPTURE_CAPACITY],
-        }
-    }
-
-    pub(super) fn error_text(&self) -> Option {
-        decode_error_text(self.length as usize, &self.message)
-    }
-}
-
-#[repr(C)]
-pub(super) struct NativeRestoreOptions {
-    pub(super) abi_version: u32,
-    pub(super) destination: *const c_char,
-    pub(super) data: *const c_uchar,
-    pub(super) len: usize,
-}
-
-pub(super) type NativeHandle = c_void;
-type InitWithErrorFn = unsafe extern "C" fn(
-    *const NativeConfig,
-    *mut *mut NativeHandle,
-    *mut NativeErrorCapture,
-) -> c_int;
-type ExecProtocolWithErrorFn = unsafe extern "C" fn(
-    *mut NativeHandle,
-    *const c_uchar,
-    usize,
-    *mut NativeResponse,
-    *mut NativeErrorCapture,
-) -> c_int;
-pub(super) type StreamCallbackFn =
-    unsafe extern "C" fn(*mut c_void, *const c_uchar, usize) -> c_int;
-type ExecProtocolRawStreamWithErrorFn = unsafe extern "C" fn(
-    *mut NativeHandle,
-    *const c_uchar,
-    usize,
-    StreamCallbackFn,
-    *mut c_void,
-    *mut NativeErrorCapture,
-) -> c_int;
-type ExecSimpleQueryWithErrorFn = unsafe extern "C" fn(
-    *mut NativeHandle,
-    *const c_char,
-    usize,
-    *mut NativeResponse,
-    *mut NativeErrorCapture,
-) -> c_int;
-type CloseFn = unsafe extern "C" fn(*mut NativeHandle) -> c_int;
-type DetachWithErrorFn = unsafe extern "C" fn(*mut NativeHandle, *mut NativeErrorCapture) -> c_int;
-type CancelFn = unsafe extern "C" fn(*mut NativeHandle) -> c_int;
-type CopyLastErrorFn = unsafe extern "C" fn(*mut NativeHandle, *mut c_char, usize) -> usize;
-type VersionFn = unsafe extern "C" fn() -> *const c_char;
-type FreeResponseFn = unsafe extern "C" fn(*mut NativeResponse);
-type BackupWithErrorFn =
-    unsafe extern "C" fn(*mut NativeHandle, *mut NativeResponse, *mut NativeErrorCapture) -> c_int;
-type RestoreWithErrorFn =
-    unsafe extern "C" fn(*const NativeRestoreOptions, *mut NativeErrorCapture) -> c_int;
-
-pub(super) struct NativeSymbols {
-    _library: ManuallyDrop,
-    pub(super) init_with_error: InitWithErrorFn,
-    pub(super) exec_protocol_with_error: ExecProtocolWithErrorFn,
-    pub(super) exec_protocol_raw_stream_with_error: ExecProtocolRawStreamWithErrorFn,
-    #[cfg_attr(not(feature = "__internal-broker-helper"), allow(dead_code))]
-    pub(super) exec_simple_query_with_error: ExecSimpleQueryWithErrorFn,
-    pub(super) cancel: CancelFn,
-    pub(super) detach_with_error: DetachWithErrorFn,
-    _close: CloseFn,
-    copy_last_error: CopyLastErrorFn,
-    _version: VersionFn,
-    pub(super) free_response: FreeResponseFn,
-    pub(super) backup_with_error: BackupWithErrorFn,
-    pub(super) restore_with_error: RestoreWithErrorFn,
-}
-
-// SAFETY: NativeSymbols is immutable after load. Function pointers are plain C
-// symbols tied to `_library`, and the library is intentionally leaked for the
-// process lifetime so those pointers cannot dangle while shared between the SDK
-// executor and cancellation paths.
-unsafe impl Send for NativeSymbols {}
-// SAFETY: See the Send impl. Calling through a symbol still requires the caller
-// to provide a valid synchronized handle; this table only shares immutable
-// function addresses and the pinned dynamic library ownership.
-unsafe impl Sync for NativeSymbols {}
-
-impl NativeSymbols {
-    pub(super) fn load() -> Result {
-        let path = resolve_library_path()?;
-        let library = load_native_library(&path)?;
-        let init_with_error = load_symbol(&library, b"oliphaunt_init_with_error\0")?;
-        let exec_protocol_with_error =
-            load_symbol(&library, b"oliphaunt_exec_protocol_with_error\0")?;
-        let exec_protocol_raw_stream_with_error =
-            load_symbol(&library, b"oliphaunt_exec_protocol_raw_stream_with_error\0")?;
-        let exec_simple_query_with_error =
-            load_symbol(&library, b"oliphaunt_exec_simple_query_with_error\0")?;
-        let cancel = load_symbol(&library, b"oliphaunt_cancel\0")?;
-        let detach_with_error = load_symbol(&library, b"oliphaunt_detach_with_error\0")?;
-        let close = load_symbol(&library, b"oliphaunt_close\0")?;
-        let copy_last_error = load_symbol(&library, b"oliphaunt_copy_last_error\0")?;
-        let version = load_symbol(&library, b"oliphaunt_version\0")?;
-        let free_response = load_symbol(&library, b"oliphaunt_free_response\0")?;
-        let backup_with_error = load_symbol(&library, b"oliphaunt_backup_with_error\0")?;
-        let restore_with_error = load_symbol(&library, b"oliphaunt_restore_with_error\0")?;
-        Ok(Self {
-            // liboliphaunt embeds PostgreSQL, which owns process-global runtime
-            // state while a backend session is active. Logical SDK close uses
-            // oliphaunt_detach; oliphaunt_close remains terminal for the process
-            // lifetime. Dropping the dynamic library can invalidate callbacks,
-            // signal handlers, or other global runtime pointers that PostgreSQL
-            // installed inside the host process.
-            _library: ManuallyDrop::new(library),
-            init_with_error,
-            exec_protocol_with_error,
-            exec_protocol_raw_stream_with_error,
-            exec_simple_query_with_error,
-            cancel,
-            detach_with_error,
-            _close: close,
-            copy_last_error,
-            _version: version,
-            free_response,
-            backup_with_error,
-            restore_with_error,
-        })
-    }
-
-    /// Cancel has no `_with_error` ABI entry point. It is synchronous in this
-    /// adapter, so copy its same-thread result into one ABI-sized buffer before
-    /// returning to the caller. Every other operation uses its own capture.
-    pub(super) fn last_error_text(&self, handle: *mut NativeHandle) -> Option {
-        let mut message = [0; ERROR_CAPTURE_CAPACITY];
-        let length = unsafe { (self.copy_last_error)(handle, message.as_mut_ptr(), message.len()) };
-        decode_error_text(length, &message)
-    }
-}
-
-fn decode_error_text(length: usize, message: &[c_char]) -> Option {
-    let bounded_length = length.min(message.len().saturating_sub(1));
-    if bounded_length == 0 {
-        return None;
-    }
-    let bytes =
-        unsafe { std::slice::from_raw_parts(message.as_ptr().cast::(), bounded_length) };
-    let text_length = bytes
-        .iter()
-        .position(|byte| *byte == 0)
-        .unwrap_or(bytes.len());
-    (text_length != 0).then(|| String::from_utf8_lossy(&bytes[..text_length]).into_owned())
-}
-
-fn resolve_library_path() -> Result {
-    resolve_library_path_candidates()
-        .into_iter()
-        .next()
-        .ok_or_else(|| {
-            Error::Engine(format!(
-                "{ENV_OLIPHAUNT} is not set; set it to a native liboliphaunt dynamic library"
-            ))
-        })
-}
-
-pub(super) fn resolve_library_path_candidates() -> Vec {
-    env_path_candidates([ENV_OLIPHAUNT])
-}
-
-pub(super) fn env_path_candidates(names: [&str; N]) -> Vec {
-    names
-        .into_iter()
-        .filter_map(std::env::var_os)
-        .map(PathBuf::from)
-        .collect()
-}
-
-fn load_native_library(path: &Path) -> Result {
-    #[cfg(unix)]
-    {
-        use libloading::os::unix::{Library as UnixLibrary, RTLD_GLOBAL, RTLD_NOW};
-
-        let library = unsafe { UnixLibrary::open(Some(path.as_os_str()), RTLD_NOW | RTLD_GLOBAL) }
-            .map_err(|err| {
-                Error::Engine(format!(
-                    "load native liboliphaunt library {}: {err}",
-                    path.display()
-                ))
-            })?;
-        Ok(Library::from(library))
-    }
-    #[cfg(not(unix))]
-    {
-        let library = unsafe { Library::new(path) }.map_err(|err| {
-            Error::Engine(format!(
-                "load native liboliphaunt library {}: {err}",
-                path.display()
-            ))
-        })?;
-        Ok(library)
-    }
-}
-
-fn load_symbol(library: &Library, name: &[u8]) -> Result {
-    let symbol = unsafe { library.get::(name) }.map_err(|err| {
-        Error::Engine(format!(
-            "native liboliphaunt is missing required symbol {}: {err}",
-            String::from_utf8_lossy(name).trim_end_matches('\0')
-        ))
-    })?;
-    Ok(*symbol)
-}
-
-pub(super) fn path_to_cstring(path: &Path, label: &str) -> Result {
-    #[cfg(unix)]
-    {
-        use std::os::unix::ffi::OsStrExt;
-
-        CString::new(path.as_os_str().as_bytes())
-            .map_err(|_| Error::InvalidConfig(format!("{label} contains an interior NUL")))
-    }
-    #[cfg(not(unix))]
-    {
-        let text = path.to_str().ok_or_else(|| {
-            Error::InvalidConfig(format!("{label} is not representable as UTF-8"))
-        })?;
-        CString::new(text)
-            .map_err(|_| Error::InvalidConfig(format!("{label} contains an interior NUL")))
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use std::mem::{align_of, offset_of, size_of};
-
-    use super::*;
-
-    #[test]
-    fn error_capture_matches_abi_10_layout() {
-        assert_eq!(offset_of!(NativeErrorCapture, length), 0);
-        assert_eq!(offset_of!(NativeErrorCapture, message), size_of::());
-        assert_eq!(
-            size_of::(),
-            size_of::() + ERROR_CAPTURE_CAPACITY
-        );
-        assert_eq!(align_of::(), align_of::());
-    }
-
-    #[test]
-    fn error_capture_decode_is_zeroed_bounded_and_lossy() {
-        let mut capture = NativeErrorCapture::zeroed();
-        assert_eq!(capture.error_text(), None);
-        assert!(capture.message.iter().all(|byte| *byte == 0));
-
-        capture.length = 5;
-        for (slot, byte) in capture.message.iter_mut().zip(b"error") {
-            *slot = *byte as c_char;
-        }
-        assert_eq!(capture.error_text().as_deref(), Some("error"));
-
-        capture.length = u32::MAX;
-        capture.message.fill(b'x' as c_char);
-        let bounded = capture.error_text().expect("bounded capture text");
-        assert_eq!(bounded.len(), ERROR_CAPTURE_CAPACITY - 1);
-        assert!(bounded.bytes().all(|byte| byte == b'x'));
-
-        capture.message[2] = 0;
-        assert_eq!(capture.error_text().as_deref(), Some("xx"));
-
-        capture.length = 1;
-        capture.message[0] = -1_i8 as c_char;
-        assert_eq!(capture.error_text().as_deref(), Some("�"));
-    }
-}
diff --git a/src/sdks/rust/src/liboliphaunt/mod.rs b/src/sdks/rust/src/liboliphaunt/mod.rs
deleted file mode 100644
index 413e54e2d..000000000
--- a/src/sdks/rust/src/liboliphaunt/mod.rs
+++ /dev/null
@@ -1,883 +0,0 @@
-use std::ffi::CString;
-#[cfg(feature = "__internal-broker-helper")]
-use std::ffi::c_char;
-use std::panic::{AssertUnwindSafe, catch_unwind};
-use std::path::PathBuf;
-use std::ptr;
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Mutex, OnceLock, RwLock};
-
-mod ffi;
-mod root;
-
-pub(crate) use self::root::{PreparedNativeRoot, configure_native_tool_env, native_root_key};
-
-use self::ffi::{
-    ABI_VERSION, CONFIG_EXTERNAL_ROOT_LOCK, NativeConfig, NativeErrorCapture, NativeHandle,
-    NativeResponse, NativeRestoreOptions, NativeSymbols, STREAM_CALLBACK_ABORTED_STATUS,
-    path_to_cstring,
-};
-use crate::config::{EngineMode, OpenConfig};
-use crate::engine::{EngineCancel, EngineSession, NativeRuntime, ProtocolStreamOutcome};
-use crate::error::{Error, Result};
-use crate::extension::Extension;
-use crate::protocol::{ProtocolRequest, ProtocolResponse};
-use crate::storage::DatabaseStorage;
-
-static DIRECT_INSTANCE_ACTIVE: AtomicBool = AtomicBool::new(false);
-static DIRECT_RESIDENT_ROOT: OnceLock>> = OnceLock::new();
-
-/// Runtime implementation backed by the native PostgreSQL `liboliphaunt` C ABI.
-#[derive(Debug, Clone, Default)]
-pub struct OliphauntRuntime;
-
-/// Materialized native inputs consumed only by Oliphaunt's unpublished
-/// packaging tool.
-#[cfg(feature = "internal-native-packaging")]
-#[doc(hidden)]
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativePackagingResources {
-    /// Fully materialized PostgreSQL runtime directory.
-    pub runtime_dir: PathBuf,
-    /// Fully initialized PostgreSQL cluster seed directory.
-    pub cluster_seed: PathBuf,
-    /// Content key for the runtime directory.
-    pub runtime_cache_key: String,
-    /// Content key for the PostgreSQL cluster seed directory.
-    pub cluster_seed_cache_key: String,
-}
-
-/// Physical runtime layout requested by unpublished native packaging tools.
-#[cfg(feature = "internal-native-packaging")]
-#[doc(hidden)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum NativePackagingRuntime {
-    /// In-process and broker products share the embedded layout.
-    Embedded,
-    /// The local PostgreSQL server layout.
-    PostgresServer,
-}
-
-/// PostgreSQL catalog profile requested by unpublished native packaging tools.
-#[cfg(feature = "internal-native-packaging")]
-#[doc(hidden)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum NativePackagingCatalogProfile {
-    /// Cluster initialized without the optional ICU data carrier.
-    Standard,
-    /// Cluster initialized with the exact optional ICU data carrier.
-    Icu,
-}
-
-/// Materialize the exact native inputs used by the unpublished packaging tool.
-#[cfg(feature = "internal-native-packaging")]
-#[doc(hidden)]
-pub fn materialize_native_packaging_resources(
-    runtime: NativePackagingRuntime,
-    extensions: &[Extension],
-    catalog_profile: NativePackagingCatalogProfile,
-) -> Result {
-    let mode = match runtime {
-        NativePackagingRuntime::Embedded => EngineMode::Direct,
-        NativePackagingRuntime::PostgresServer => EngineMode::Server,
-    };
-    let catalog_profile = match catalog_profile {
-        NativePackagingCatalogProfile::Standard => root::NativeCatalogProfile::Standard,
-        NativePackagingCatalogProfile::Icu => root::NativeCatalogProfile::Icu,
-    };
-    let resources =
-        root::materialize_native_resources_for_runtime(mode, extensions, catalog_profile)?;
-    Ok(NativePackagingResources {
-        runtime_dir: resources.runtime_dir,
-        cluster_seed: resources.cluster_seed,
-        runtime_cache_key: resources.runtime_cache_key,
-        cluster_seed_cache_key: resources.cluster_seed_cache_key,
-    })
-}
-
-impl OliphauntRuntime {
-    /// Create a runtime that resolves the library path from the environment.
-    pub fn from_env() -> Self {
-        Self
-    }
-
-    pub(crate) fn restore(&self, destination: &std::path::Path, bytes: &[u8]) -> Result<()> {
-        let symbols = NativeSymbols::load()?;
-        let destination = path_to_cstring(destination, "restore destination")?;
-        let options = NativeRestoreOptions {
-            abi_version: ABI_VERSION,
-            destination: destination.as_ptr(),
-            data: if bytes.is_empty() {
-                std::ptr::null()
-            } else {
-                bytes.as_ptr()
-            },
-            len: bytes.len(),
-        };
-        let mut error = NativeErrorCapture::zeroed();
-        let rc = unsafe { (symbols.restore_with_error)(&options, &mut error) };
-        if rc != 0 {
-            let message = captured_native_error(&error, "oliphaunt_restore", rc);
-            return Err(Error::Engine(format!(
-                "native liboliphaunt restore failed: {message}"
-            )));
-        }
-        Ok(())
-    }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-struct DirectResidentKey {
-    requested_root_key: Option,
-    actual_root_key: PathBuf,
-    username: String,
-    database: String,
-    startup_args: Vec,
-    selected_extensions: Vec,
-}
-
-impl DirectResidentKey {
-    fn requested(
-        config: &OpenConfig,
-        extensions: &[Extension],
-        startup_args: Vec,
-    ) -> Result {
-        let requested_root_key = match &config.storage {
-            DatabaseStorage::Directory(root) => Some(native_root_key(root)?),
-            DatabaseStorage::TemporaryDirectory => None,
-        };
-        Ok(Self {
-            actual_root_key: requested_root_key.clone().unwrap_or_default(),
-            requested_root_key,
-            username: config.username.clone(),
-            database: config.database.clone(),
-            startup_args,
-            selected_extensions: extensions.to_vec(),
-        })
-    }
-
-    fn bind_actual_root(mut self, root: &PreparedNativeRoot) -> Result {
-        self.actual_root_key = root.root_key()?;
-        Ok(self)
-    }
-
-    fn matches_storage(&self, requested: &Self) -> bool {
-        match (&self.requested_root_key, &requested.requested_root_key) {
-            (None, None) => true,
-            (_, Some(requested_root)) => requested_root == &self.actual_root_key,
-            (Some(_), None) => false,
-        }
-    }
-
-    fn matches_configuration(&self, requested: &Self) -> bool {
-        self.matches_storage(requested)
-            && self.username == requested.username
-            && self.database == requested.database
-            && self.startup_args == requested.startup_args
-            && self.selected_extensions == requested.selected_extensions
-    }
-}
-
-struct DirectResidentRoot {
-    root: PreparedNativeRoot,
-    key: DirectResidentKey,
-    configuration_bound: bool,
-}
-
-impl NativeRuntime for OliphauntRuntime {
-    fn open(&self, config: OpenConfig) -> Result> {
-        debug_assert_eq!(config.mode, EngineMode::Direct);
-        config.validate()?;
-        let instance_lease = acquire_direct_instance_lease()?;
-        let extensions = config.resolved_extensions()?;
-        let startup_args = startup_arg_strings(&config, &extensions);
-        let requested_key = DirectResidentKey::requested(&config, &extensions, startup_args)?;
-        let symbols = Arc::new(NativeSymbols::load()?);
-        let (root, configuration_bound) =
-            take_or_prepare_direct_root(&config, &extensions, &requested_key)?;
-        let resident_key = requested_key.bind_actual_root(&root)?;
-        match OliphauntSession::open(
-            symbols,
-            root,
-            config,
-            &extensions,
-            resident_key.clone(),
-            instance_lease,
-        ) {
-            Ok(session) => Ok(Box::new(session)),
-            Err(failure) => {
-                let DirectOpenFailure {
-                    root,
-                    error,
-                    native_open_attempted,
-                } = *failure;
-                if configuration_bound || native_open_attempted {
-                    // Once oliphaunt_init has run, the process-resident backend may
-                    // still own PGDATA even when it rejects the logical open.
-                    // Keep both persistent and SDK-temporary storage available
-                    // for a coherent retry instead of deleting or replacing it.
-                    store_direct_resident_root(root, resident_key, configuration_bound)?;
-                }
-                Err(error)
-            }
-        }
-    }
-}
-
-fn take_or_prepare_direct_root(
-    config: &OpenConfig,
-    extensions: &[Extension],
-    requested_key: &DirectResidentKey,
-) -> Result<(PreparedNativeRoot, bool)> {
-    let slot = DIRECT_RESIDENT_ROOT.get_or_init(|| Mutex::new(None));
-    let mut resident = slot
-        .lock()
-        .map_err(|_| Error::Engine("native direct resident root lock was poisoned".to_owned()))?;
-    if let Some(existing) = resident.take() {
-        let matches = if existing.configuration_bound {
-            existing.key.matches_configuration(requested_key)
-        } else {
-            existing.key.matches_storage(requested_key)
-        };
-        if matches {
-            return Ok((existing.root, existing.configuration_bound));
-        }
-        let bound_root = existing.key.actual_root_key.display().to_string();
-        *resident = Some(existing);
-        return Err(Error::Engine(format!(
-            "native direct resident runtime is already bound to root {bound_root}; use .broker() or OliphauntServer::builder().start() for multiple roots in one process"
-        )));
-    }
-    drop(resident);
-
-    PreparedNativeRoot::prepare(config, extensions).map(|root| (root, false))
-}
-
-fn store_direct_resident_root(
-    root: PreparedNativeRoot,
-    key: DirectResidentKey,
-    configuration_bound: bool,
-) -> Result<()> {
-    let slot = DIRECT_RESIDENT_ROOT.get_or_init(|| Mutex::new(None));
-    let mut resident = slot
-        .lock()
-        .map_err(|_| Error::Engine("native direct resident root lock was poisoned".to_owned()))?;
-    *resident = Some(DirectResidentRoot {
-        root,
-        key,
-        configuration_bound,
-    });
-    Ok(())
-}
-
-fn acquire_direct_instance_lease() -> Result {
-    DIRECT_INSTANCE_ACTIVE
-        .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
-        .map(|_| DirectInstanceLease)
-        .map_err(|_| {
-            Error::Engine("native direct already has an active process-wide instance".to_owned())
-        })
-}
-
-struct DirectInstanceLease;
-
-impl Drop for DirectInstanceLease {
-    fn drop(&mut self) {
-        DIRECT_INSTANCE_ACTIVE.store(false, Ordering::Release);
-    }
-}
-
-struct OliphauntSession {
-    symbols: Arc,
-    handle: Arc,
-    cancel: Arc,
-    root: Option,
-    resident_key: DirectResidentKey,
-    _lease: Option,
-}
-
-struct DirectOpenFailure {
-    root: PreparedNativeRoot,
-    error: Error,
-    native_open_attempted: bool,
-}
-
-impl DirectOpenFailure {
-    fn before_native(root: PreparedNativeRoot, error: Error) -> Box {
-        Box::new(Self {
-            root,
-            error,
-            native_open_attempted: false,
-        })
-    }
-
-    fn after_native(root: PreparedNativeRoot, error: Error) -> Box {
-        Box::new(Self {
-            root,
-            error,
-            native_open_attempted: true,
-        })
-    }
-}
-
-struct SharedNativeHandle {
-    handle: RwLock<*mut NativeHandle>,
-}
-
-// SAFETY: The raw native handle is never accessed directly through shared
-// references. All users first take the RwLock: executor-owned protocol/backup
-// work holds a read lock, cancellation holds a read lock, and logical close
-// takes the write lock, calls `oliphaunt_detach`, then replaces the pointer
-// with null before releasing the process-wide direct-instance lease.
-unsafe impl Send for SharedNativeHandle {}
-// SAFETY: See the Send impl. The RwLock serializes pointer reads against close,
-// so shared references can only observe either the still-open handle or null.
-unsafe impl Sync for SharedNativeHandle {}
-
-impl SharedNativeHandle {
-    fn new(handle: *mut NativeHandle) -> Self {
-        Self {
-            handle: RwLock::new(handle),
-        }
-    }
-}
-
-struct OliphauntCancel {
-    symbols: Arc,
-    handle: Arc,
-}
-
-impl EngineCancel for OliphauntCancel {
-    fn cancel(&self) -> Result<()> {
-        let guard =
-            self.handle.handle.read().map_err(|_| {
-                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
-            })?;
-        let handle = *guard;
-        if handle.is_null() {
-            return Err(Error::EngineStopped);
-        }
-        let rc = unsafe { (self.symbols.cancel)(handle) };
-        if rc != 0 {
-            let message = self
-                .symbols
-                .last_error_text(handle)
-                .unwrap_or_else(|| format!("oliphaunt_cancel failed with status {rc}"));
-            return Err(Error::Engine(format!(
-                "native liboliphaunt cancel failed: {message}"
-            )));
-        }
-        Ok(())
-    }
-}
-
-impl OliphauntSession {
-    fn open(
-        symbols: Arc,
-        root: PreparedNativeRoot,
-        config: OpenConfig,
-        extensions: &[Extension],
-        resident_key: DirectResidentKey,
-        lease: DirectInstanceLease,
-    ) -> std::result::Result> {
-        if let Err(error) = root.refresh_descriptor() {
-            return Err(DirectOpenFailure::before_native(root, error));
-        }
-        let pgdata = match path_to_cstring(&root.pgdata, "PGDATA") {
-            Ok(value) => value,
-            Err(error) => return Err(DirectOpenFailure::before_native(root, error)),
-        };
-        let runtime_dir = match path_to_cstring(&root.runtime_dir, "runtime dir") {
-            Ok(value) => value,
-            Err(error) => return Err(DirectOpenFailure::before_native(root, error)),
-        };
-        let module_dir = match path_to_cstring(
-            &root.runtime_dir.join("lib/postgresql"),
-            "embedded module dir",
-        ) {
-            Ok(value) => value,
-            Err(error) => return Err(DirectOpenFailure::before_native(root, error)),
-        };
-        let username = match CString::new(config.username.as_str()) {
-            Ok(value) => value,
-            Err(_) => {
-                return Err(DirectOpenFailure::before_native(
-                    root,
-                    Error::InvalidConfig("username contains an interior NUL".to_owned()),
-                ));
-            }
-        };
-        let database = match CString::new(config.database.as_str()) {
-            Ok(value) => value,
-            Err(_) => {
-                return Err(DirectOpenFailure::before_native(
-                    root,
-                    Error::InvalidConfig("database contains an interior NUL".to_owned()),
-                ));
-            }
-        };
-        let startup_args = match startup_args(&config, extensions) {
-            Ok(value) => value,
-            Err(error) => return Err(DirectOpenFailure::before_native(root, error)),
-        };
-        let startup_arg_ptrs = startup_args
-            .iter()
-            .map(|arg| arg.as_ptr())
-            .collect::>();
-        let native_config = NativeConfig {
-            abi_version: ABI_VERSION,
-            pgdata: pgdata.as_ptr(),
-            runtime_dir: runtime_dir.as_ptr(),
-            module_dir: module_dir.as_ptr(),
-            username: username.as_ptr(),
-            database: database.as_ptr(),
-            flags: CONFIG_EXTERNAL_ROOT_LOCK,
-            startup_args: startup_arg_ptrs.as_ptr(),
-            startup_arg_count: startup_arg_ptrs.len(),
-        };
-        let mut handle = ptr::null_mut();
-        let mut error = NativeErrorCapture::zeroed();
-        let rc = unsafe { (symbols.init_with_error)(&native_config, &mut handle, &mut error) };
-        if rc != 0 || handle.is_null() {
-            let message = error.error_text().unwrap_or_else(|| {
-                if rc == 0 {
-                    "oliphaunt_init returned a null handle".to_owned()
-                } else {
-                    format!("oliphaunt_init failed with status {rc}")
-                }
-            });
-            return Err(DirectOpenFailure::after_native(
-                root,
-                Error::Engine(format!("native liboliphaunt init failed: {message}")),
-            ));
-        }
-
-        let handle = Arc::new(SharedNativeHandle::new(handle));
-        let cancel = Arc::new(OliphauntCancel {
-            symbols: Arc::clone(&symbols),
-            handle: Arc::clone(&handle),
-        });
-
-        Ok(Self {
-            symbols,
-            handle,
-            cancel,
-            root: Some(root),
-            resident_key,
-            _lease: Some(lease),
-        })
-    }
-
-    fn close_handle(&mut self) -> Result<()> {
-        let mut guard =
-            self.handle.handle.write().map_err(|_| {
-                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
-            })?;
-        let handle = *guard;
-        if handle.is_null() {
-            return Ok(());
-        }
-        let mut error = NativeErrorCapture::zeroed();
-        let rc = unsafe { (self.symbols.detach_with_error)(handle, &mut error) };
-        if rc != 0 {
-            let message = captured_native_error(&error, "oliphaunt_detach", rc);
-            return Err(Error::Engine(format!(
-                "native liboliphaunt detach failed: {message}"
-            )));
-        }
-        *guard = ptr::null_mut();
-        if let Some(root) = self.root.take() {
-            store_direct_resident_root(root, self.resident_key.clone(), true)?;
-        }
-        self._lease = None;
-        Ok(())
-    }
-
-    fn bytes_from_native_response(&self, mut response: NativeResponse) -> Vec {
-        let bytes = if response.data.is_null() {
-            Vec::new()
-        } else {
-            unsafe { std::slice::from_raw_parts(response.data, response.len).to_vec() }
-        };
-        unsafe { (self.symbols.free_response)(&mut response) };
-        bytes
-    }
-
-    fn protocol_response_from_native(&self, response: NativeResponse) -> ProtocolResponse {
-        let bytes = self.bytes_from_native_response(response);
-        ProtocolResponse::new(bytes)
-    }
-
-    fn free_failed_response(&self, response: &mut NativeResponse) {
-        if !response.data.is_null() {
-            unsafe { (self.symbols.free_response)(response) };
-        }
-    }
-}
-
-impl EngineSession for OliphauntSession {
-    fn cancel_handle(&self) -> Option> {
-        let cancel: Arc = self.cancel.clone();
-        Some(cancel)
-    }
-
-    fn exec_protocol_raw(&mut self, request: ProtocolRequest) -> Result {
-        let guard =
-            self.handle.handle.read().map_err(|_| {
-                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
-            })?;
-        let handle = *guard;
-        if handle.is_null() {
-            return Err(Error::EngineStopped);
-        }
-        let bytes = request.as_bytes();
-        let mut response = NativeResponse {
-            data: ptr::null_mut(),
-            len: 0,
-        };
-        let mut error = NativeErrorCapture::zeroed();
-        let rc = unsafe {
-            (self.symbols.exec_protocol_with_error)(
-                handle,
-                bytes.as_ptr(),
-                bytes.len(),
-                &mut response,
-                &mut error,
-            )
-        };
-        if rc != 0 {
-            self.free_failed_response(&mut response);
-            let message = captured_native_error(&error, "oliphaunt_exec_protocol", rc);
-            return Err(Error::Engine(format!(
-                "native liboliphaunt protocol execution failed: {message}"
-            )));
-        }
-        if response.data.is_null() {
-            return Ok(ProtocolResponse::new(Vec::new()));
-        }
-        Ok(self.protocol_response_from_native(response))
-    }
-
-    fn exec_protocol_raw_stream(
-        &mut self,
-        request: ProtocolRequest,
-        on_chunk: &mut dyn FnMut(&[u8]) -> Result<()>,
-    ) -> ProtocolStreamOutcome {
-        let guard = match self.handle.handle.read() {
-            Ok(guard) => guard,
-            Err(_) => {
-                return ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(
-                    "native liboliphaunt handle lock poisoned".to_owned(),
-                ));
-            }
-        };
-        let handle = *guard;
-        if handle.is_null() {
-            return ProtocolStreamOutcome::SessionStateUnknown(Error::EngineStopped);
-        }
-
-        struct StreamContext<'a> {
-            on_chunk: &'a mut dyn FnMut(&[u8]) -> Result<()>,
-            error: Option,
-        }
-
-        unsafe extern "C" fn stream_callback(
-            context: *mut std::ffi::c_void,
-            data: *const std::ffi::c_uchar,
-            len: usize,
-        ) -> std::ffi::c_int {
-            let context = unsafe { &mut *(context.cast::>()) };
-            if data.is_null() && len > 0 {
-                context.error = Some(Error::Engine(
-                    "native liboliphaunt stream callback received null data".to_owned(),
-                ));
-                return -1;
-            }
-            let bytes = if len == 0 {
-                &[]
-            } else {
-                unsafe { std::slice::from_raw_parts(data, len) }
-            };
-            match catch_unwind(AssertUnwindSafe(|| (context.on_chunk)(bytes))) {
-                Ok(Ok(())) => 0,
-                Ok(Err(error)) => {
-                    context.error = Some(error);
-                    -1
-                }
-                Err(_) => {
-                    // A Rust unwind across this C ABI callback is undefined
-                    // behavior. Retain a stable SDK error while liboliphaunt
-                    // drains through ReadyForQuery and returns normally.
-                    context.error = Some(Error::Engine(
-                        "raw protocol stream callback panicked".to_owned(),
-                    ));
-                    -1
-                }
-            }
-        }
-
-        let bytes = request.as_bytes();
-        let mut context = StreamContext {
-            on_chunk,
-            error: None,
-        };
-        let mut error = NativeErrorCapture::zeroed();
-        let rc = unsafe {
-            (self.symbols.exec_protocol_raw_stream_with_error)(
-                handle,
-                bytes.as_ptr(),
-                bytes.len(),
-                stream_callback,
-                (&mut context as *mut StreamContext<'_>).cast(),
-                &mut error,
-            )
-        };
-        if rc == STREAM_CALLBACK_ABORTED_STATUS {
-            return match context.error {
-                Some(error) => ProtocolStreamOutcome::ReadyForQuery(Err(error)),
-                None => ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(
-                    "native liboliphaunt reported a recovered callback abort without a callback error"
-                        .to_owned(),
-                )),
-            };
-        }
-        if rc != 0 {
-            let message = captured_native_error(&error, "oliphaunt_exec_protocol_raw_stream", rc);
-            // Every non-sentinel failure is independently authoritative: it
-            // may have interrupted recovery and must not be masked by a
-            // callback error (or by the original panic retained by the
-            // blocking API).
-            return ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(format!(
-                "native liboliphaunt protocol stream failed: {message}"
-            )));
-        }
-        if context.error.is_some() {
-            return ProtocolStreamOutcome::SessionStateUnknown(Error::Engine(
-                "native liboliphaunt reported stream success after rejecting its callback"
-                    .to_owned(),
-            ));
-        }
-        ProtocolStreamOutcome::ReadyForQuery(Ok(()))
-    }
-
-    #[cfg(feature = "__internal-broker-helper")]
-    fn exec_simple_query(&mut self, sql: &str) -> Result {
-        if sql.as_bytes().contains(&0) {
-            return Err(Error::InvalidConfig(
-                "simple query contains an interior NUL byte".to_owned(),
-            ));
-        }
-        let guard =
-            self.handle.handle.read().map_err(|_| {
-                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
-            })?;
-        let handle = *guard;
-        if handle.is_null() {
-            return Err(Error::EngineStopped);
-        }
-        let mut response = NativeResponse {
-            data: ptr::null_mut(),
-            len: 0,
-        };
-        let mut error = NativeErrorCapture::zeroed();
-        let rc = unsafe {
-            (self.symbols.exec_simple_query_with_error)(
-                handle,
-                sql.as_ptr().cast::(),
-                sql.len(),
-                &mut response,
-                &mut error,
-            )
-        };
-        if rc != 0 {
-            self.free_failed_response(&mut response);
-            let message = captured_native_error(&error, "oliphaunt_exec_simple_query", rc);
-            return Err(Error::Engine(format!(
-                "native liboliphaunt simple query failed: {message}"
-            )));
-        }
-        Ok(self.protocol_response_from_native(response))
-    }
-
-    fn backup(&mut self) -> Result> {
-        let guard =
-            self.handle.handle.read().map_err(|_| {
-                Error::Engine("native liboliphaunt handle lock poisoned".to_owned())
-            })?;
-        let handle = *guard;
-        if handle.is_null() {
-            return Err(Error::EngineStopped);
-        }
-        let mut response = NativeResponse {
-            data: ptr::null_mut(),
-            len: 0,
-        };
-        let mut error = NativeErrorCapture::zeroed();
-        let rc = unsafe { (self.symbols.backup_with_error)(handle, &mut response, &mut error) };
-        if rc != 0 {
-            self.free_failed_response(&mut response);
-            let message = captured_native_error(&error, "oliphaunt_backup", rc);
-            return Err(Error::Engine(format!(
-                "native liboliphaunt physical backup failed: {message}"
-            )));
-        }
-        Ok(self.bytes_from_native_response(response))
-    }
-
-    fn close(&mut self) -> Result<()> {
-        self.close_handle()
-    }
-}
-
-fn captured_native_error(
-    capture: &NativeErrorCapture,
-    operation: &str,
-    status: std::ffi::c_int,
-) -> String {
-    capture
-        .error_text()
-        .unwrap_or_else(|| format!("{operation} failed with status {status}"))
-}
-
-impl Drop for OliphauntSession {
-    fn drop(&mut self) {
-        let _ = self.close_handle();
-    }
-}
-
-fn startup_arg_strings(config: &OpenConfig, extensions: &[Extension]) -> Vec {
-    let mut args = Vec::new();
-    for assignment in config.postgres_startup_assignments(extensions) {
-        args.push("-c".to_owned());
-        args.push(assignment);
-    }
-    args
-}
-
-fn startup_args(config: &OpenConfig, extensions: &[Extension]) -> Result> {
-    let args = startup_arg_strings(config, extensions);
-    args.into_iter()
-        .map(|arg| {
-            CString::new(arg).map_err(|_| {
-                Error::InvalidConfig("startup argument contains an interior NUL".to_owned())
-            })
-        })
-        .collect()
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn direct_temporary_storage_matches_the_process_resident_instance() {
-        let key = DirectResidentKey {
-            requested_root_key: None,
-            actual_root_key: PathBuf::from("/tmp/oliphaunt-resident"),
-            username: "postgres".to_owned(),
-            database: "postgres".to_owned(),
-            startup_args: Vec::new(),
-            selected_extensions: Vec::new(),
-        };
-        let requested = DirectResidentKey {
-            actual_root_key: PathBuf::new(),
-            ..key.clone()
-        };
-
-        assert!(key.matches_storage(&requested));
-        assert!(key.matches_configuration(&requested));
-    }
-
-    #[test]
-    fn failed_direct_open_storage_can_retry_with_corrected_configuration() {
-        let key = DirectResidentKey {
-            requested_root_key: None,
-            actual_root_key: PathBuf::from("/tmp/oliphaunt-failed-open"),
-            username: "missing-role".to_owned(),
-            database: "postgres".to_owned(),
-            startup_args: Vec::new(),
-            selected_extensions: Vec::new(),
-        };
-        let corrected = DirectResidentKey {
-            requested_root_key: None,
-            actual_root_key: PathBuf::new(),
-            username: "postgres".to_owned(),
-            database: "postgres".to_owned(),
-            startup_args: Vec::new(),
-            selected_extensions: Vec::new(),
-        };
-
-        assert!(key.matches_storage(&corrected));
-        assert!(!key.matches_configuration(&corrected));
-    }
-
-    #[test]
-    fn direct_startup_args_include_required_preload_libraries_before_init() {
-        let mut config = OpenConfig::direct("target/test-roots/native-direct-preload");
-        config.startup_gucs = vec![crate::config::PostgresStartupGuc::new(
-            "shared_preload_libraries",
-            "auto_explain, pg_textsearch",
-        )];
-        config.extensions = vec![Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH];
-        let extensions = config.resolved_extensions().unwrap();
-        let args = startup_args(&config, &extensions).unwrap();
-        let args = args
-            .iter()
-            .map(|arg| arg.to_string_lossy().into_owned())
-            .collect::>();
-
-        assert_startup_config_arg(&args, "shared_preload_libraries=auto_explain,pg_textsearch");
-        assert_eq!(
-            args.iter()
-                .filter(|arg| arg.starts_with("shared_preload_libraries="))
-                .count(),
-            1,
-            "caller and extension preload libraries must be merged once before oliphaunt_init"
-        );
-    }
-
-    #[test]
-    fn direct_startup_args_omit_preload_when_selected_extensions_do_not_require_it() {
-        let config = OpenConfig::direct("target/test-roots/native-direct-no-preload");
-        let args = startup_args(&config, &[Extension::VECTOR]).unwrap();
-        let args = args
-            .iter()
-            .map(|arg| arg.to_string_lossy().into_owned())
-            .collect::>();
-
-        assert!(
-            !args
-                .iter()
-                .any(|arg| arg.starts_with("shared_preload_libraries=")),
-            "direct startup args must not add preload settings for extensions that do not require them: {args:?}"
-        );
-    }
-
-    #[test]
-    fn invalid_startup_gucs_are_rejected_before_open() {
-        let mut config = OpenConfig::direct("target/test-roots/native-direct-invalid-guc");
-        config.startup_gucs = vec![crate::config::PostgresStartupGuc::new(
-            "shared-buffers",
-            "16MB",
-        )];
-
-        let error = config.validate().unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("each dot-separated component must start"),
-            "{error}"
-        );
-    }
-
-    fn assert_startup_config_arg(args: &[String], expected: &str) {
-        let Some(index) = args.iter().position(|arg| arg == expected) else {
-            panic!("missing direct startup argument {expected:?} in {args:?}");
-        };
-        assert_eq!(
-            args.get(index.saturating_sub(1)).map(String::as_str),
-            Some("-c"),
-            "direct startup argument {expected:?} must be passed through postgres -c"
-        );
-    }
-}
diff --git a/src/sdks/rust/src/liboliphaunt/root/cluster_seed.rs b/src/sdks/rust/src/liboliphaunt/root/cluster_seed.rs
deleted file mode 100644
index 51c2e66ea..000000000
--- a/src/sdks/rust/src/liboliphaunt/root/cluster_seed.rs
+++ /dev/null
@@ -1,815 +0,0 @@
-use std::ffi::OsString;
-use std::fs;
-#[cfg(feature = "internal-native-packaging")]
-use std::fs::OpenOptions;
-#[cfg(unix)]
-use std::os::unix::fs::PermissionsExt;
-use std::path::Path;
-#[cfg(feature = "internal-native-packaging")]
-use std::path::PathBuf;
-use std::process::{Command, Stdio};
-
-#[cfg(feature = "internal-native-packaging")]
-use fs2::FileExt;
-
-use super::files::{cluster_seed_copy_mode, copy_directory_tree, directory_is_empty};
-#[cfg(feature = "internal-native-packaging")]
-use super::files::{remove_file_if_exists, sync_directory, sync_directory_tree};
-#[cfg(feature = "internal-native-packaging")]
-use super::fingerprint::{hash_path, hash_str, new_state};
-use super::runtime::monotonic_cache_nonce;
-#[cfg(feature = "internal-native-packaging")]
-use super::runtime::runtime_cache_root;
-use super::{
-    NativeCatalogProfile, NativeRuntimeProfile, configure_native_tool_env, native_tool_path,
-};
-use crate::error::{Error, Result};
-
-#[cfg(feature = "internal-native-packaging")]
-const CLUSTER_SEED_CACHE_VERSION: &str = "pg18-cluster-seed-v6";
-const SKIP_SYSTEM_COLLATION_DISCOVERY_ENV: &str =
-    "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY";
-const SKIP_ICU_COLLATION_DISCOVERY_ENV: &str = "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY";
-
-#[cfg(unix)]
-fn set_private_directory_permissions(path: &Path, context: &str) -> Result<()> {
-    fs::set_permissions(path, fs::Permissions::from_mode(0o700)).map_err(|err| {
-        Error::Engine(format!(
-            "set permissions on {context} {}: {err}",
-            path.display()
-        ))
-    })
-}
-
-#[cfg(not(unix))]
-fn set_private_directory_permissions(_path: &Path, _context: &str) -> Result<()> {
-    Ok(())
-}
-
-pub(super) fn bootstrap_pgdata_if_needed(
-    profile: NativeRuntimeProfile,
-    runtime_dir: &Path,
-    initdb_runtime_dir: &Path,
-    catalog_profile: super::NativeCatalogProfile,
-    packaged_cluster_seed: Option<&Path>,
-    pgdata: &Path,
-) -> Result<()> {
-    if pgdata.join("PG_VERSION").is_file() {
-        return Ok(());
-    }
-
-    if profile == NativeRuntimeProfile::PostgresServer || packaged_cluster_seed.is_none() {
-        return run_initdb(
-            initdb_runtime_dir,
-            runtime_dir,
-            catalog_profile,
-            pgdata,
-            "database",
-            false,
-        );
-    }
-    restore_cluster_seed(
-        packaged_cluster_seed.expect("packaged cluster seed checked above"),
-        pgdata,
-    )
-}
-
-fn run_initdb(
-    initdb_runtime_dir: &Path,
-    runtime_dir: &Path,
-    catalog_profile: NativeCatalogProfile,
-    pgdata: &Path,
-    context: &str,
-    skip_system_collation_discovery: bool,
-) -> Result<()> {
-    let initdb = native_tool_path(initdb_runtime_dir, "initdb");
-    if !initdb.is_file() {
-        return Err(Error::Engine(format!(
-            "native {context} initialization requires initdb at {}",
-            initdb.display()
-        )));
-    }
-    let mut command = Command::new(&initdb);
-    configure_cluster_seed_runtime_env(
-        &mut command,
-        initdb_runtime_dir,
-        runtime_dir,
-        catalog_profile,
-        skip_system_collation_discovery,
-    );
-    let output = command
-        .args(initdb_args(initdb_runtime_dir, pgdata))
-        .stdout(Stdio::null())
-        .stderr(Stdio::piped())
-        .output()
-        .map_err(|err| {
-            Error::Engine(format!(
-                "run native {context} initdb {}: {err}",
-                initdb.display()
-            ))
-        })?;
-    if output.status.success() {
-        return Ok(());
-    }
-    let stderr = String::from_utf8_lossy(&output.stderr);
-    Err(Error::Engine(format!(
-        "native {context} initdb {} failed with status {}: {}",
-        initdb.display(),
-        output.status,
-        stderr.trim()
-    )))
-}
-
-fn initdb_args(runtime_dir: &Path, pgdata: &Path) -> Vec {
-    vec![
-        "-D".into(),
-        pgdata.as_os_str().to_owned(),
-        "-U".into(),
-        "postgres".into(),
-        "--auth=trust".into(),
-        "--locale-provider=libc".into(),
-        "--locale=C".into(),
-        "--encoding=UTF8".into(),
-        "-L".into(),
-        runtime_dir.join("share/postgresql").into_os_string(),
-    ]
-}
-
-fn restore_cluster_seed(packaged_cluster_seed: &Path, pgdata: &Path) -> Result<()> {
-    let cluster_seed = packaged_cluster_seed.join("files");
-    copy_cluster_seed(&cluster_seed, pgdata)
-}
-
-#[cfg(feature = "internal-native-packaging")]
-pub(super) fn materialize_cluster_seed(
-    _profile: NativeRuntimeProfile,
-    runtime_dir: &Path,
-    initdb_runtime_dir: &Path,
-    catalog_profile: super::NativeCatalogProfile,
-) -> Result {
-    let skip_system_collation_discovery = distributed_seed_requested();
-    let key = cluster_seed_key(
-        runtime_dir,
-        catalog_profile,
-        skip_system_collation_discovery,
-    )?;
-    let cache_root = runtime_cache_root()?.join("cluster-seeds");
-    fs::create_dir_all(&cache_root).map_err(|err| {
-        Error::Engine(format!(
-            "create native PGDATA cluster seed cache root {}: {err}",
-            cache_root.display()
-        ))
-    })?;
-    set_private_directory_permissions(&cache_root, "native PGDATA cluster seed cache root")?;
-
-    let seed_dir = cache_root.join(&key);
-    let lock_path = cache_root.join(format!("{key}.lock"));
-    let lock = OpenOptions::new()
-        .create(true)
-        .truncate(false)
-        .write(true)
-        .read(true)
-        .open(&lock_path)
-        .map_err(|err| {
-            Error::Engine(format!(
-                "open native cluster-seed lock {}: {err}",
-                lock_path.display()
-            ))
-        })?;
-    lock.lock_exclusive().map_err(|err| {
-        Error::Engine(format!(
-            "lock native cluster seed {}: {err}",
-            lock_path.display()
-        ))
-    })?;
-
-    if !cluster_seed_is_valid(&seed_dir, &key) {
-        let build_dir = cache_root.join(format!(
-            ".build-{}-{}",
-            std::process::id(),
-            monotonic_cache_nonce()?
-        ));
-        if build_dir.exists() {
-            fs::remove_dir_all(&build_dir).map_err(|err| {
-                Error::Engine(format!(
-                    "remove stale native cluster-seed build dir {}: {err}",
-                    build_dir.display()
-                ))
-            })?;
-        }
-        fs::create_dir_all(&build_dir).map_err(|err| {
-            Error::Engine(format!(
-                "create native cluster-seed build dir {}: {err}",
-                build_dir.display()
-            ))
-        })?;
-
-        let pgdata = build_dir.join("pgdata");
-        let build_result = run_cluster_seed_initdb(
-            initdb_runtime_dir,
-            runtime_dir,
-            catalog_profile,
-            &pgdata,
-            skip_system_collation_discovery,
-        )
-        .and_then(|()| clean_cluster_seed(&pgdata, native_dynamic_shared_memory_type()))
-        .and_then(|()| {
-            fs::write(build_dir.join(".manifest"), cluster_seed_manifest(&key)).map_err(|err| {
-                Error::Engine(format!(
-                    "write native cluster-seed manifest {}: {err}",
-                    build_dir.display()
-                ))
-            })
-        })
-        .and_then(|()| {
-            fs::write(build_dir.join(".complete"), b"ok\n").map_err(|err| {
-                Error::Engine(format!(
-                    "write native cluster-seed completion marker {}: {err}",
-                    build_dir.display()
-                ))
-            })
-        })
-        .and_then(|()| sync_directory_tree(&build_dir));
-
-        if let Err(error) = build_result {
-            let _ = fs::remove_dir_all(&build_dir);
-            return Err(error);
-        }
-        if seed_dir.exists() {
-            fs::remove_dir_all(&seed_dir).map_err(|err| {
-                Error::Engine(format!(
-                    "remove invalid native cluster seed {}: {err}",
-                    seed_dir.display()
-                ))
-            })?;
-        }
-        fs::rename(&build_dir, &seed_dir).map_err(|err| {
-            Error::Engine(format!(
-                "publish native cluster seed {} -> {}: {err}",
-                build_dir.display(),
-                seed_dir.display()
-            ))
-        })?;
-        sync_directory(&cache_root)?;
-    }
-
-    lock.unlock().map_err(|err| {
-        Error::Engine(format!(
-            "unlock native cluster seed {}: {err}",
-            lock_path.display()
-        ))
-    })?;
-    Ok(seed_dir.join("pgdata"))
-}
-
-#[cfg(feature = "internal-native-packaging")]
-fn cluster_seed_key(
-    bootstrap_runtime: &Path,
-    catalog_profile: super::NativeCatalogProfile,
-    skip_system_collation_discovery: bool,
-) -> Result {
-    let runtime_manifest =
-        fs::read_to_string(bootstrap_runtime.join(".manifest")).map_err(|err| {
-            Error::Engine(format!(
-                "read native runtime manifest {}: {err}",
-                bootstrap_runtime.join(".manifest").display()
-            ))
-        })?;
-    let mut state = new_state();
-    hash_str(&mut state, CLUSTER_SEED_CACHE_VERSION);
-    hash_str(&mut state, catalog_profile.id());
-    hash_str(
-        &mut state,
-        if skip_system_collation_discovery {
-            "distributed"
-        } else {
-            "host"
-        },
-    );
-    hash_path(&mut state, bootstrap_runtime);
-    hash_str(&mut state, &runtime_manifest);
-    Ok(format!("{state:016x}"))
-}
-
-#[cfg(feature = "internal-native-packaging")]
-fn cluster_seed_manifest(key: &str) -> String {
-    format!("version={CLUSTER_SEED_CACHE_VERSION}\nkey={key}\n")
-}
-
-#[cfg(feature = "internal-native-packaging")]
-fn cluster_seed_is_valid(seed_dir: &Path, key: &str) -> bool {
-    if !seed_dir.join(".complete").is_file()
-        || !seed_dir.join("pgdata/PG_VERSION").is_file()
-        || !seed_dir.join("pgdata/global/pg_control").is_file()
-    {
-        return false;
-    }
-    let Ok(manifest) = fs::read_to_string(seed_dir.join(".manifest")) else {
-        return false;
-    };
-    manifest
-        .lines()
-        .any(|line| line == format!("version={CLUSTER_SEED_CACHE_VERSION}"))
-        && manifest.lines().any(|line| line == format!("key={key}"))
-}
-
-#[cfg(feature = "internal-native-packaging")]
-fn run_cluster_seed_initdb(
-    initdb_runtime_dir: &Path,
-    runtime_dir: &Path,
-    catalog_profile: super::NativeCatalogProfile,
-    pgdata: &Path,
-    skip_system_collation_discovery: bool,
-) -> Result<()> {
-    run_initdb(
-        initdb_runtime_dir,
-        runtime_dir,
-        catalog_profile,
-        pgdata,
-        "cluster seed",
-        skip_system_collation_discovery,
-    )
-}
-
-#[cfg(feature = "internal-native-packaging")]
-fn distributed_seed_requested() -> bool {
-    std::env::var_os(SKIP_SYSTEM_COLLATION_DISCOVERY_ENV).is_some_and(|value| value == "1")
-}
-
-fn configure_cluster_seed_runtime_env(
-    command: &mut Command,
-    initdb_runtime_dir: &Path,
-    runtime_dir: &Path,
-    catalog_profile: super::NativeCatalogProfile,
-    skip_system_collation_discovery: bool,
-) {
-    configure_native_tool_env(command, initdb_runtime_dir);
-    command.env_remove("ICU_DATA");
-    command.env_remove("OLIPHAUNT_INTERNAL_ICU_READY");
-    command.env_remove(SKIP_SYSTEM_COLLATION_DISCOVERY_ENV);
-    command.env_remove(SKIP_ICU_COLLATION_DISCOVERY_ENV);
-    if skip_system_collation_discovery {
-        command.env(SKIP_SYSTEM_COLLATION_DISCOVERY_ENV, "1");
-    }
-    if catalog_profile == super::NativeCatalogProfile::Standard {
-        command.env(SKIP_ICU_COLLATION_DISCOVERY_ENV, "1");
-    }
-    let icu_data = runtime_dir.join("share/icu");
-    if catalog_profile == super::NativeCatalogProfile::Icu && icu_data.is_dir() {
-        command.env("ICU_DATA", icu_data);
-        command.env("OLIPHAUNT_INTERNAL_ICU_READY", "1");
-    }
-}
-
-const fn native_dynamic_shared_memory_type() -> &'static str {
-    if cfg!(target_os = "windows") {
-        "windows"
-    } else {
-        "mmap"
-    }
-}
-
-#[cfg(feature = "internal-native-packaging")]
-fn clean_cluster_seed(pgdata: &Path, dynamic_shared_memory_type: &str) -> Result<()> {
-    for relative in ["postmaster.pid", "postmaster.opts"] {
-        remove_file_if_exists(&pgdata.join(relative))?;
-    }
-    normalize_cluster_seed_conf(pgdata, dynamic_shared_memory_type)?;
-    Ok(())
-}
-
-fn normalize_cluster_seed_conf(pgdata: &Path, dynamic_shared_memory_type: &str) -> Result<()> {
-    let conf = pgdata.join("postgresql.conf");
-    if !conf.is_file() {
-        return Ok(());
-    }
-    let contents = fs::read_to_string(&conf).map_err(|err| {
-        Error::Engine(format!(
-            "read native cluster-seed config {}: {err}",
-            conf.display()
-        ))
-    })?;
-    let settings = [
-        ("shared_memory_type", dynamic_shared_memory_type),
-        ("dynamic_shared_memory_type", dynamic_shared_memory_type),
-        ("log_timezone", "'UTC'"),
-        ("timezone", "'UTC'"),
-        ("lc_messages", "'C'"),
-        ("lc_monetary", "'C'"),
-        ("lc_numeric", "'C'"),
-        ("lc_time", "'C'"),
-    ];
-    let mut seen = vec![false; settings.len()];
-    let mut normalized = String::with_capacity(contents.len());
-    for line in contents.lines() {
-        if let Some(index) = settings
-            .iter()
-            .position(|(key, _)| active_config_key(line) == Some(*key))
-        {
-            let (key, value) = settings[index];
-            normalized.push_str(key);
-            normalized.push_str(" = ");
-            normalized.push_str(value);
-            seen[index] = true;
-        } else {
-            normalized.push_str(line);
-        }
-        normalized.push('\n');
-    }
-    for (index, (key, value)) in settings.iter().enumerate() {
-        if !seen[index] {
-            normalized.push_str(key);
-            normalized.push_str(" = ");
-            normalized.push_str(value);
-            normalized.push('\n');
-        }
-    }
-    if normalized != contents {
-        fs::write(&conf, normalized).map_err(|err| {
-            Error::Engine(format!(
-                "write native cluster-seed config {}: {err}",
-                conf.display()
-            ))
-        })?;
-    }
-    Ok(())
-}
-
-fn active_config_key(line: &str) -> Option<&str> {
-    let trimmed = line.trim_start();
-    if trimmed.starts_with('#') {
-        return None;
-    }
-    let (key, _) = trimmed.split_once('=')?;
-    let key = key.trim_end();
-    (!key.is_empty()).then_some(key)
-}
-
-fn copy_cluster_seed(cluster_seed: &Path, pgdata: &Path) -> Result<()> {
-    if pgdata.join("PG_VERSION").is_file() {
-        return Ok(());
-    }
-    if pgdata.exists() {
-        if !directory_is_empty(pgdata)? {
-            return Err(Error::Engine(format!(
-                "refusing to bootstrap non-empty native PGDATA without PG_VERSION at {}",
-                pgdata.display()
-            )));
-        }
-        fs::remove_dir_all(pgdata).map_err(|err| {
-            Error::Engine(format!("remove empty PGDATA {}: {err}", pgdata.display()))
-        })?;
-    }
-    let parent = pgdata.parent().ok_or_else(|| {
-        Error::Engine(format!(
-            "native PGDATA {} does not have a parent directory",
-            pgdata.display()
-        ))
-    })?;
-    let staging = parent.join(format!(
-        ".pgdata-bootstrap-{}-{}",
-        std::process::id(),
-        monotonic_cache_nonce()?
-    ));
-    if staging.exists() {
-        fs::remove_dir_all(&staging).map_err(|err| {
-            Error::Engine(format!(
-                "remove stale PGDATA bootstrap staging dir {}: {err}",
-                staging.display()
-            ))
-        })?;
-    }
-
-    let copy_result = copy_directory_tree(cluster_seed, &staging, cluster_seed_copy_mode())
-        .and_then(|()| {
-            set_private_directory_permissions(&staging, "native PGDATA bootstrap directory")
-        });
-    if let Err(error) = copy_result {
-        let _ = fs::remove_dir_all(&staging);
-        let _ = fs::create_dir_all(pgdata);
-        return Err(error);
-    }
-    if let Err(error) = normalize_cluster_seed_conf(&staging, native_dynamic_shared_memory_type()) {
-        let _ = fs::remove_dir_all(&staging);
-        let _ = fs::create_dir_all(pgdata);
-        return Err(error);
-    }
-    fs::rename(&staging, pgdata).map_err(|err| {
-        let _ = fs::remove_dir_all(&staging);
-        Error::Engine(format!(
-            "publish native PGDATA bootstrap {} -> {}: {err}",
-            staging.display(),
-            pgdata.display()
-        ))
-    })
-}
-
-#[cfg(test)]
-mod tests {
-    use std::ffi::OsStr;
-    use std::fs;
-    #[cfg(unix)]
-    use std::os::unix::fs::PermissionsExt;
-    use std::path::Path;
-    #[cfg(unix)]
-    use std::time::{SystemTime, UNIX_EPOCH};
-
-    use super::{
-        SKIP_ICU_COLLATION_DISCOVERY_ENV, SKIP_SYSTEM_COLLATION_DISCOVERY_ENV,
-        configure_cluster_seed_runtime_env, copy_cluster_seed, initdb_args,
-        native_dynamic_shared_memory_type, normalize_cluster_seed_conf,
-    };
-    use crate::liboliphaunt::root::NativeCatalogProfile;
-
-    #[test]
-    fn cluster_seed_initdb_forces_mobile_safe_locale() {
-        let args = initdb_args(
-            Path::new("/runtime"),
-            Path::new("/cache/cluster-seed/pgdata"),
-        );
-
-        assert!(args.iter().any(|arg| arg == OsStr::new("--locale=C")));
-        assert!(
-            args.iter()
-                .any(|arg| arg == OsStr::new("--locale-provider=libc"))
-        );
-        assert!(args.iter().any(|arg| arg == OsStr::new("--encoding=UTF8")));
-    }
-
-    #[test]
-    fn fresh_initdb_uses_fixed_bootstrap_identity_and_packaged_storage() {
-        let args = initdb_args(Path::new("/runtime"), Path::new("/app/database/pgdata"));
-
-        assert_eq!(args[0], OsStr::new("-D"));
-        assert_eq!(args[1], OsStr::new("/app/database/pgdata"));
-        assert_eq!(args[2], OsStr::new("-U"));
-        assert_eq!(args[3], OsStr::new("postgres"));
-        assert!(args.iter().any(|arg| arg == OsStr::new("--auth=trust")));
-        assert!(!args.iter().any(|arg| arg == OsStr::new("--no-sync")));
-        assert!(
-            args.iter()
-                .any(|arg| arg == OsStr::new("/runtime/share/postgresql"))
-        );
-    }
-
-    #[test]
-    fn cluster_seed_initdb_sets_icu_data_when_materialized() {
-        let root = std::env::temp_dir().join(format!(
-            "oliphaunt-cluster-seed-icu-{}-{}",
-            std::process::id(),
-            std::thread::current().name().unwrap_or("test")
-        ));
-        let _ = fs::remove_dir_all(&root);
-        let runtime = root.join("runtime");
-        let icu_data = runtime.join("share/icu");
-        fs::create_dir_all(&icu_data).unwrap();
-
-        let mut command = std::process::Command::new("initdb");
-        configure_cluster_seed_runtime_env(
-            &mut command,
-            &runtime,
-            &runtime,
-            NativeCatalogProfile::Icu,
-            false,
-        );
-
-        assert_eq!(
-            command
-                .get_envs()
-                .find(|(key, _)| *key == OsStr::new("ICU_DATA"))
-                .and_then(|(_, value)| value)
-                .map(std::path::PathBuf::from),
-            Some(icu_data)
-        );
-        assert_eq!(
-            command
-                .get_envs()
-                .find(|(key, _)| *key == OsStr::new("OLIPHAUNT_INTERNAL_ICU_READY"))
-                .and_then(|(_, value)| value),
-            Some(OsStr::new("1"))
-        );
-        let _ = fs::remove_dir_all(&root);
-    }
-
-    #[test]
-    fn standard_seed_clears_ambient_icu_selection() {
-        let mut command = std::process::Command::new("initdb");
-        command.env("ICU_DATA", "/ambient/icu");
-        command.env("OLIPHAUNT_INTERNAL_ICU_READY", "1");
-        configure_cluster_seed_runtime_env(
-            &mut command,
-            Path::new("/runtime"),
-            Path::new("/runtime"),
-            NativeCatalogProfile::Standard,
-            false,
-        );
-        assert_eq!(
-            command
-                .get_envs()
-                .find(|(key, _)| *key == OsStr::new("ICU_DATA"))
-                .and_then(|(_, value)| value),
-            None
-        );
-        assert_eq!(
-            command
-                .get_envs()
-                .find(|(key, _)| *key == OsStr::new(SKIP_SYSTEM_COLLATION_DISCOVERY_ENV))
-                .and_then(|(_, value)| value),
-            None
-        );
-        assert_eq!(
-            command
-                .get_envs()
-                .find(|(key, _)| *key == OsStr::new(SKIP_ICU_COLLATION_DISCOVERY_ENV))
-                .and_then(|(_, value)| value),
-            Some(OsStr::new("1"))
-        );
-        assert_eq!(
-            command
-                .get_envs()
-                .find(|(key, _)| *key == OsStr::new("OLIPHAUNT_INTERNAL_ICU_READY"))
-                .and_then(|(_, value)| value),
-            None
-        );
-    }
-
-    #[test]
-    fn distributed_icu_seed_suppresses_only_host_locale_discovery() {
-        let root = std::env::temp_dir().join(format!(
-            "oliphaunt-cluster-seed-mobile-{}-{}",
-            std::process::id(),
-            std::thread::current().name().unwrap_or("test")
-        ));
-        let _ = fs::remove_dir_all(&root);
-        let runtime = root.join("runtime");
-        fs::create_dir_all(runtime.join("share/icu")).unwrap();
-
-        let mut command = std::process::Command::new("initdb");
-        configure_cluster_seed_runtime_env(
-            &mut command,
-            &runtime,
-            &runtime,
-            NativeCatalogProfile::Icu,
-            true,
-        );
-
-        assert_eq!(
-            command
-                .get_envs()
-                .find(|(key, _)| *key == OsStr::new(SKIP_SYSTEM_COLLATION_DISCOVERY_ENV))
-                .and_then(|(_, value)| value),
-            Some(OsStr::new("1"))
-        );
-        assert_eq!(
-            command
-                .get_envs()
-                .find(|(key, _)| *key == OsStr::new(SKIP_ICU_COLLATION_DISCOVERY_ENV))
-                .and_then(|(_, value)| value),
-            None
-        );
-        assert_eq!(
-            command
-                .get_envs()
-                .find(|(key, _)| *key == OsStr::new("OLIPHAUNT_INTERNAL_ICU_READY"))
-                .and_then(|(_, value)| value),
-            Some(OsStr::new("1"))
-        );
-        let _ = fs::remove_dir_all(&root);
-    }
-
-    #[test]
-    fn distributed_standard_seed_suppresses_host_and_icu_discovery() {
-        let mut command = std::process::Command::new("initdb");
-        configure_cluster_seed_runtime_env(
-            &mut command,
-            Path::new("/runtime"),
-            Path::new("/runtime"),
-            NativeCatalogProfile::Standard,
-            true,
-        );
-        for key in [
-            SKIP_SYSTEM_COLLATION_DISCOVERY_ENV,
-            SKIP_ICU_COLLATION_DISCOVERY_ENV,
-        ] {
-            assert_eq!(
-                command
-                    .get_envs()
-                    .find(|(candidate, _)| *candidate == OsStr::new(key))
-                    .and_then(|(_, value)| value),
-                Some(OsStr::new("1"))
-            );
-        }
-    }
-
-    #[test]
-    fn cluster_seed_config_normalization_forces_posix_host_values() {
-        let root = std::env::temp_dir().join(format!(
-            "oliphaunt-cluster-seed-normalize-{}-{}",
-            std::process::id(),
-            std::thread::current().name().unwrap_or("test")
-        ));
-        let _ = fs::remove_dir_all(&root);
-        fs::create_dir_all(&root).unwrap();
-        let conf = root.join("postgresql.conf");
-        fs::write(
-            &conf,
-            [
-                "# dynamic_shared_memory_type = posix",
-                "dynamic_shared_memory_type = posix",
-                "log_timezone = 'America/Los_Angeles'",
-                "timezone = 'America/Los_Angeles'",
-                "lc_messages = 'en_US.UTF-8'",
-                "lc_monetary = 'en_US.UTF-8'",
-                "lc_numeric = 'en_US.UTF-8'",
-                "lc_time = 'en_US.UTF-8'",
-            ]
-            .join("\n"),
-        )
-        .unwrap();
-
-        normalize_cluster_seed_conf(&root, "mmap").unwrap();
-
-        let normalized = fs::read_to_string(&conf).unwrap();
-        assert!(normalized.contains("# dynamic_shared_memory_type = posix"));
-        assert!(normalized.contains("dynamic_shared_memory_type = mmap"));
-        assert!(normalized.contains("log_timezone = 'UTC'"));
-        assert!(normalized.contains("timezone = 'UTC'"));
-        assert!(normalized.contains("lc_messages = 'C'"));
-        assert!(normalized.contains("lc_monetary = 'C'"));
-        assert!(normalized.contains("lc_numeric = 'C'"));
-        assert!(normalized.contains("lc_time = 'C'"));
-        let _ = fs::remove_dir_all(&root);
-    }
-
-    #[test]
-    fn cluster_seed_config_normalization_uses_windows_dsm_on_windows() {
-        let root = std::env::temp_dir().join(format!(
-            "oliphaunt-cluster-seed-normalize-windows-{}-{}",
-            std::process::id(),
-            std::thread::current().name().unwrap_or("test")
-        ));
-        let _ = fs::remove_dir_all(&root);
-        fs::create_dir_all(&root).unwrap();
-        let conf = root.join("postgresql.conf");
-        fs::write(
-            &conf,
-            [
-                "# dynamic_shared_memory_type = windows",
-                "dynamic_shared_memory_type = posix",
-            ]
-            .join("\n"),
-        )
-        .unwrap();
-
-        normalize_cluster_seed_conf(&root, "windows").unwrap();
-
-        let normalized = fs::read_to_string(&conf).unwrap();
-        assert!(normalized.contains("# dynamic_shared_memory_type = windows"));
-        assert!(normalized.contains("dynamic_shared_memory_type = windows"));
-        assert!(!normalized.contains("dynamic_shared_memory_type = mmap"));
-        let _ = fs::remove_dir_all(&root);
-    }
-
-    #[test]
-    fn native_dsm_type_matches_the_compiled_host() {
-        assert_eq!(
-            native_dynamic_shared_memory_type(),
-            if cfg!(target_os = "windows") {
-                "windows"
-            } else {
-                "mmap"
-            }
-        );
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn copied_cluster_seed_publishes_private_pgdata() {
-        let nonce = SystemTime::now()
-            .duration_since(UNIX_EPOCH)
-            .unwrap()
-            .as_nanos();
-        let root = std::env::temp_dir().join(format!(
-            "oliphaunt-cluster-seed-permissions-{}-{nonce}",
-            std::process::id()
-        ));
-        let source = root.join("source");
-        let pgdata = root.join("database/pgdata");
-        fs::create_dir_all(&source).unwrap();
-        fs::create_dir_all(pgdata.parent().unwrap()).unwrap();
-        fs::write(source.join("PG_VERSION"), "18\n").unwrap();
-        fs::set_permissions(&source, fs::Permissions::from_mode(0o755)).unwrap();
-
-        copy_cluster_seed(&source, &pgdata).unwrap();
-
-        assert_eq!(
-            fs::metadata(&pgdata).unwrap().permissions().mode() & 0o777,
-            0o700
-        );
-        assert_eq!(
-            fs::read_to_string(pgdata.join("PG_VERSION")).unwrap(),
-            "18\n"
-        );
-        let _ = fs::remove_dir_all(&root);
-    }
-}
diff --git a/src/sdks/rust/src/liboliphaunt/root/runtime.rs b/src/sdks/rust/src/liboliphaunt/root/runtime.rs
deleted file mode 100644
index 73b2af3c1..000000000
--- a/src/sdks/rust/src/liboliphaunt/root/runtime.rs
+++ /dev/null
@@ -1,462 +0,0 @@
-mod cache_key;
-mod install;
-mod locate;
-
-use std::fs::{self, OpenOptions};
-#[cfg(unix)]
-use std::os::unix::fs::PermissionsExt;
-use std::path::{Path, PathBuf};
-use std::time::{SystemTime, UNIX_EPOCH};
-
-use fs2::FileExt;
-
-use cache_key::{
-    cached_runtime_is_valid_with_icu, runtime_cache_key_with_icu, runtime_cache_manifest_with_icu,
-};
-use install::install_cached_runtime_with_icu;
-use locate::{
-    locate_native_cluster_seed, locate_native_embedded_modules_dir,
-    locate_native_extension_artifact_dirs, locate_native_icu_data, locate_native_install_dir,
-    package_resources_root_for_install,
-};
-
-use super::files::{sorted_read_dir, sync_directory, sync_file};
-use super::{NativeCatalogProfile, NativeRuntimeProfile};
-use crate::error::{Error, Result};
-use crate::extension::Extension;
-
-const ENV_RUNTIME_CACHE_DIR: &str = "OLIPHAUNT_RUNTIME_CACHE_DIR";
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(super) struct ResolvedRuntimeClosure {
-    pub(super) runtime_dir: PathBuf,
-    pub(super) initdb_runtime_dir: PathBuf,
-    pub(super) catalog_profile: NativeCatalogProfile,
-    pub(super) cluster_seed_dir: Option,
-}
-
-pub(super) fn resolve_runtime_closure(
-    profile: NativeRuntimeProfile,
-    extensions: &[Extension],
-    requested_catalog_profile: Option,
-) -> Result {
-    let install_dir = locate_native_install_dir()?;
-    let package_resources_root = package_resources_root_for_install(&install_dir);
-    let available_icu_data = locate_native_icu_data()?;
-    let catalog_profile = requested_catalog_profile.unwrap_or_else(|| {
-        if available_icu_data.is_some() {
-            NativeCatalogProfile::Icu
-        } else {
-            NativeCatalogProfile::Standard
-        }
-    });
-    let icu_data = match catalog_profile {
-        NativeCatalogProfile::Standard => None,
-        NativeCatalogProfile::Icu => Some(available_icu_data.ok_or_else(|| {
-            Error::Engine(
-                "ICU was selected, but the package-managed ICU data tree is unavailable; add the matching oliphaunt-icu artifact or set OLIPHAUNT_ICU_DATA_DIR"
-                    .to_owned(),
-            )
-        })?),
-    };
-    let icu_directory = icu_data.as_ref().map(|data| data.directory.as_path());
-    let icu_tree_sha256 = icu_data
-        .as_ref()
-        .and_then(|data| data.tree_sha256.as_deref());
-    let runtime_dir = materialize_runtime(
-        profile,
-        &install_dir,
-        extensions,
-        icu_directory,
-        icu_tree_sha256,
-    )?;
-    let package_closure_root = package_resources_root.filter(|resources_root| match &icu_data {
-        None => catalog_profile == NativeCatalogProfile::Standard,
-        Some(icu) => {
-            catalog_profile == NativeCatalogProfile::Icu
-                && icu.package_resources_root.as_ref() == Some(resources_root)
-        }
-    });
-    // Packaging materializes the seeds after resolving the runtime closure. Only an
-    // ordinary SDK open consumes a seed that already belongs to a released carrier.
-    let cluster_seed = if requested_catalog_profile.is_none() {
-        package_closure_root
-            .as_deref()
-            .map(|resources_root| locate_native_cluster_seed(resources_root, catalog_profile))
-            .transpose()?
-            .flatten()
-    } else {
-        None
-    };
-    if requested_catalog_profile.is_none()
-        && package_closure_root.is_some()
-        && cluster_seed.is_none()
-    {
-        return Err(Error::Engine(format!(
-            "the package-managed {} runtime closure is missing its matching target-qualified cluster seed",
-            catalog_profile.id()
-        )));
-    }
-    if let (Some(seed), Some(expected)) = (&cluster_seed, icu_tree_sha256)
-        && seed.icu_data_tree_sha256.as_deref() != Some(expected)
-    {
-        return Err(Error::Engine(format!(
-            "the package-managed ICU cluster seed for target {} and ICU data receipt identify different logical trees",
-            seed.target
-        )));
-    }
-    Ok(ResolvedRuntimeClosure {
-        runtime_dir,
-        initdb_runtime_dir: install_dir,
-        catalog_profile,
-        cluster_seed_dir: cluster_seed.map(|seed| seed.directory),
-    })
-}
-
-pub(super) fn materialize_runtime(
-    profile: NativeRuntimeProfile,
-    install_dir: &Path,
-    extensions: &[Extension],
-    icu_data: Option<&Path>,
-    icu_data_tree_sha256: Option<&str>,
-) -> Result {
-    let extension_artifact_dirs = locate_native_extension_artifact_dirs();
-    let embedded_modules = if profile.needs_embedded_modules() {
-        Some(locate_native_embedded_modules_dir(install_dir)?)
-    } else {
-        None
-    };
-    let key = runtime_cache_key_with_icu(
-        profile,
-        install_dir,
-        embedded_modules.as_deref(),
-        &extension_artifact_dirs,
-        extensions,
-        icu_data,
-        icu_data_tree_sha256,
-    )?;
-    let cache_root = runtime_cache_root()?;
-    fs::create_dir_all(&cache_root).map_err(|err| {
-        Error::Engine(format!(
-            "create native runtime cache root {}: {err}",
-            cache_root.display()
-        ))
-    })?;
-    #[cfg(unix)]
-    fs::set_permissions(&cache_root, fs::Permissions::from_mode(0o700)).map_err(|err| {
-        Error::Engine(format!(
-            "set permissions on native runtime cache root {}: {err}",
-            cache_root.display()
-        ))
-    })?;
-
-    let cache_dir = cache_root.join(&key);
-    let lock_path = cache_root.join(format!("{key}.lock"));
-    let lock = OpenOptions::new()
-        .create(true)
-        .truncate(false)
-        .write(true)
-        .read(true)
-        .open(&lock_path)
-        .map_err(|err| {
-            Error::Engine(format!(
-                "open native runtime cache lock {}: {err}",
-                lock_path.display()
-            ))
-        })?;
-    lock.lock_exclusive().map_err(|err| {
-        Error::Engine(format!(
-            "lock native runtime cache {}: {err}",
-            lock_path.display()
-        ))
-    })?;
-
-    if !cached_runtime_is_valid_with_icu(profile, &cache_dir, &key, extensions, icu_data.is_some())
-    {
-        let build_dir = cache_root.join(format!(
-            ".build-{}-{}",
-            std::process::id(),
-            monotonic_cache_nonce()?
-        ));
-        if build_dir.exists() {
-            fs::remove_dir_all(&build_dir).map_err(|err| {
-                Error::Engine(format!(
-                    "remove stale native runtime build dir {}: {err}",
-                    build_dir.display()
-                ))
-            })?;
-        }
-        fs::create_dir_all(&build_dir).map_err(|err| {
-            Error::Engine(format!(
-                "create native runtime build dir {}: {err}",
-                build_dir.display()
-            ))
-        })?;
-
-        let build_result = install_cached_runtime_with_icu(
-            profile,
-            install_dir,
-            embedded_modules.as_deref(),
-            &extension_artifact_dirs,
-            &build_dir,
-            extensions,
-            icu_data,
-        );
-        if let Err(error) = build_result {
-            let _ = fs::remove_dir_all(&build_dir);
-            return Err(error);
-        }
-        fs::write(
-            build_dir.join(".manifest"),
-            runtime_cache_manifest_with_icu(profile, &key, extensions, icu_data.is_some()),
-        )
-        .map_err(|err| {
-            Error::Engine(format!(
-                "write native runtime cache manifest {}: {err}",
-                build_dir.display()
-            ))
-        })?;
-        fs::write(build_dir.join(".complete"), b"ok\n").map_err(|err| {
-            Error::Engine(format!(
-                "write native runtime cache completion marker {}: {err}",
-                build_dir.display()
-            ))
-        })?;
-        if let Err(error) = sync_runtime_cache_tree(&build_dir) {
-            let _ = fs::remove_dir_all(&build_dir);
-            return Err(error);
-        }
-        if cache_dir.exists() {
-            fs::remove_dir_all(&cache_dir).map_err(|err| {
-                Error::Engine(format!(
-                    "remove invalid native runtime cache {}: {err}",
-                    cache_dir.display()
-                ))
-            })?;
-        }
-        fs::rename(&build_dir, &cache_dir).map_err(|err| {
-            Error::Engine(format!(
-                "publish native runtime cache {} -> {}: {err}",
-                build_dir.display(),
-                cache_dir.display()
-            ))
-        })?;
-        sync_directory(&cache_root)?;
-    }
-
-    lock.unlock().map_err(|err| {
-        Error::Engine(format!(
-            "unlock native runtime cache {}: {err}",
-            lock_path.display()
-        ))
-    })?;
-    Ok(cache_dir)
-}
-
-/// Flush a staged runtime without following packaged symbolic links.
-///
-/// Runtime carriers may contain symlinked libraries. The link itself becomes
-/// durable with its containing directory; ordinary files still need an
-/// explicit flush before the cache directory is published.
-fn sync_runtime_cache_tree(path: &Path) -> Result<()> {
-    let metadata = fs::symlink_metadata(path).map_err(|err| {
-        Error::Engine(format!(
-            "inspect native runtime cache directory {}: {err}",
-            path.display()
-        ))
-    })?;
-    if !metadata.is_dir() || metadata.file_type().is_symlink() {
-        return Err(Error::Engine(format!(
-            "native runtime cache publication root must be a real directory: {}",
-            path.display()
-        )));
-    }
-
-    for entry in sorted_read_dir(path)? {
-        let entry_path = entry.path();
-        let file_type = entry.file_type().map_err(|err| {
-            Error::Engine(format!(
-                "read file type for {} while syncing runtime cache: {err}",
-                entry_path.display()
-            ))
-        })?;
-        if file_type.is_dir() {
-            sync_runtime_cache_tree(&entry_path)?;
-        } else if file_type.is_file() {
-            sync_file(&entry_path)?;
-        } else if file_type.is_symlink() {
-            fs::read_link(&entry_path).map_err(|err| {
-                Error::Engine(format!(
-                    "read native runtime cache symlink {}: {err}",
-                    entry_path.display()
-                ))
-            })?;
-        } else {
-            return Err(Error::Engine(format!(
-                "native runtime cache contains a special file: {}",
-                entry_path.display()
-            )));
-        }
-    }
-    sync_directory(path)
-}
-
-pub(super) fn extension_artifact_root_for<'a>(
-    install_dir: &'a std::path::Path,
-    extension_artifact_dirs: &'a [PathBuf],
-    extension: Extension,
-) -> &'a std::path::Path {
-    extension_artifact_dirs
-        .iter()
-        .find(|root| extension_artifact_root_contains(root, extension))
-        .map(PathBuf::as_path)
-        .unwrap_or(install_dir)
-}
-
-fn extension_artifact_root_contains(root: &std::path::Path, extension: Extension) -> bool {
-    if extension.creates_extension() {
-        return root
-            .join("share/postgresql/extension")
-            .join(format!("{}.control", extension.sql_name()))
-            .is_file();
-    }
-    extension
-        .native_module_file()
-        .is_some_and(|module| root.join("lib/postgresql").join(module).is_file())
-}
-
-pub(super) fn runtime_cache_root() -> Result {
-    if let Some(path) = std::env::var_os(ENV_RUNTIME_CACHE_DIR) {
-        return Ok(PathBuf::from(path));
-    }
-    Ok(std::env::temp_dir().join("oliphaunt-runtime-cache"))
-}
-
-pub(super) fn monotonic_cache_nonce() -> Result {
-    SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .map(|duration| duration.as_nanos())
-        .map_err(|err| Error::Engine(format!("system clock before epoch: {err}")))
-}
-
-#[cfg(test)]
-mod tests {
-    use std::fs;
-    use std::path::{Path, PathBuf};
-    use std::time::{SystemTime, UNIX_EPOCH};
-
-    use super::*;
-
-    #[test]
-    fn product_root_identity_uses_control_or_module_according_to_extension_contract() {
-        let temp = TempTree::new("extension-product-root");
-        let install_dir = temp.path().join("runtime");
-        let product_root = temp
-            .path()
-            .join("resources/extension/oliphaunt-extension-contrib-pg18");
-        fs::create_dir_all(&install_dir).expect("create fallback runtime");
-
-        let amcheck_module = Extension::AMCHECK
-            .native_module_file()
-            .expect("amcheck has a native module");
-        write_artifact_file(&product_root, &format!("lib/postgresql/{amcheck_module}"));
-        assert!(!extension_artifact_root_contains(
-            &product_root,
-            Extension::AMCHECK
-        ));
-        assert_eq!(
-            extension_artifact_root_for(
-                &install_dir,
-                std::slice::from_ref(&product_root),
-                Extension::AMCHECK,
-            ),
-            install_dir
-        );
-
-        write_artifact_file(&product_root, "share/postgresql/extension/amcheck.control");
-        assert!(extension_artifact_root_contains(
-            &product_root,
-            Extension::AMCHECK
-        ));
-
-        let auto_explain_module = Extension::AUTO_EXPLAIN
-            .native_module_file()
-            .expect("auto_explain has a native module");
-        write_artifact_file(
-            &product_root,
-            &format!("lib/postgresql/{auto_explain_module}"),
-        );
-        assert!(!Extension::AUTO_EXPLAIN.creates_extension());
-        assert!(extension_artifact_root_contains(
-            &product_root,
-            Extension::AUTO_EXPLAIN
-        ));
-        assert_eq!(
-            extension_artifact_root_for(
-                &install_dir,
-                std::slice::from_ref(&product_root),
-                Extension::AUTO_EXPLAIN,
-            ),
-            product_root
-        );
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn runtime_cache_sync_accepts_packaged_relative_symlinks() {
-        use std::os::unix::fs::symlink;
-
-        let temp = TempTree::new("runtime-cache-symlink");
-        let lib = temp.path().join("lib");
-        fs::create_dir(&lib).expect("create runtime lib directory");
-        fs::write(lib.join("libicu.so.1"), b"icu").expect("write runtime library");
-        symlink("libicu.so.1", lib.join("libicu.so")).expect("create packaged symlink");
-
-        sync_runtime_cache_tree(temp.path()).expect("sync runtime cache with symlink");
-    }
-
-    #[test]
-    fn runtime_cache_sync_flushes_regular_files() {
-        let temp = TempTree::new("runtime-cache-regular-file");
-        fs::write(temp.path().join(".complete"), b"ok\n")
-            .expect("write runtime cache completion marker");
-
-        sync_runtime_cache_tree(temp.path()).expect("sync runtime cache regular file");
-    }
-
-    fn write_artifact_file(root: &Path, relative: &str) {
-        let file = root.join(relative);
-        fs::create_dir_all(file.parent().expect("artifact file parent"))
-            .expect("create artifact file parent");
-        fs::write(file, b"test\n").expect("write artifact file");
-    }
-
-    struct TempTree {
-        path: PathBuf,
-    }
-
-    impl TempTree {
-        fn new(name: &str) -> Self {
-            let nanos = SystemTime::now()
-                .duration_since(UNIX_EPOCH)
-                .expect("clock before epoch")
-                .as_nanos();
-            let path = std::env::temp_dir().join(format!(
-                "oliphaunt-runtime-test-{name}-{nanos}-{}",
-                std::process::id()
-            ));
-            fs::create_dir_all(&path).expect("create temp tree");
-            Self { path }
-        }
-
-        fn path(&self) -> &Path {
-            &self.path
-        }
-    }
-
-    impl Drop for TempTree {
-        fn drop(&mut self) {
-            let _ = fs::remove_dir_all(&self.path);
-        }
-    }
-}
diff --git a/src/sdks/rust/src/liboliphaunt/root/runtime/locate.rs b/src/sdks/rust/src/liboliphaunt/root/runtime/locate.rs
deleted file mode 100644
index e55f79bb3..000000000
--- a/src/sdks/rust/src/liboliphaunt/root/runtime/locate.rs
+++ /dev/null
@@ -1,692 +0,0 @@
-use std::path::{Path, PathBuf};
-
-use super::super::super::ffi::{
-    ENV_EMBEDDED_MODULE_DIR, ENV_INITDB, ENV_INSTALL_DIR, ENV_POSTGRES, env_path_candidates,
-    resolve_library_path_candidates,
-};
-use crate::build_resources::registered_build_resources_dir;
-use crate::error::{Error, Result};
-
-const ENV_RESOURCES_DIR: &str = "OLIPHAUNT_RESOURCES_DIR";
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(super) struct LocatedIcuData {
-    pub(super) directory: PathBuf,
-    pub(super) package_resources_root: Option,
-    pub(super) tree_sha256: Option,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(super) struct LocatedClusterSeed {
-    pub(super) directory: PathBuf,
-    pub(super) target: String,
-    pub(super) icu_data_tree_sha256: Option,
-}
-
-pub(super) fn locate_native_install_dir() -> Result {
-    let mut candidates = Vec::new();
-    candidates.extend(env_path_candidates([ENV_INSTALL_DIR]));
-    for path in resources_dir_candidates() {
-        candidates.push(path.join("native-runtime/liboliphaunt-native/runtime"));
-    }
-    for env_name in [ENV_POSTGRES, ENV_INITDB] {
-        if let Some(path) = std::env::var_os(env_name) {
-            let path = PathBuf::from(path);
-            if let Some(install_dir) = path.parent().and_then(Path::parent) {
-                candidates.push(install_dir.to_path_buf());
-            }
-        }
-    }
-    for path in resolve_library_path_candidates() {
-        if let Some(work_root) = path.parent().and_then(Path::parent) {
-            candidates.push(work_root.join("install"));
-        }
-    }
-    if let Ok(cwd) = std::env::current_dir() {
-        candidates.push(cwd.join("target/liboliphaunt-pg18/install"));
-        candidates.push(cwd.join("target/native-liboliphaunt-pg18/install"));
-        if let Some(target_id) = native_host_target_id() {
-            candidates.push(cwd.join(format!("target/liboliphaunt-pg18-{target_id}/install")));
-        }
-    }
-
-    for candidate in candidates {
-        if native_install_dir_is_valid(&candidate) {
-            return Ok(candidate);
-        }
-    }
-    Err(Error::Engine(format!(
-        "could not locate native PostgreSQL 18 install tree; set {ENV_INSTALL_DIR} or {ENV_POSTGRES}"
-    )))
-}
-
-pub(super) fn locate_native_extension_artifact_dirs() -> Vec {
-    let mut dirs = Vec::new();
-    for resources_dir in resources_dir_candidates() {
-        let extension_root = resources_dir.join("extension");
-        let Ok(entries) = std::fs::read_dir(extension_root) else {
-            continue;
-        };
-        for entry in entries.flatten() {
-            let path = entry.path();
-            if path.is_dir() {
-                dirs.push(path);
-            }
-        }
-    }
-    dirs.sort();
-    dirs.dedup();
-    dirs
-}
-
-pub(super) fn locate_native_embedded_modules_dir(install_dir: &Path) -> Result {
-    locate_native_embedded_modules_dir_from_libraries(
-        install_dir,
-        resolve_library_path_candidates(),
-    )
-}
-
-fn locate_native_embedded_modules_dir_from_libraries(
-    install_dir: &Path,
-    library_paths: impl IntoIterator,
-) -> Result {
-    let mut candidates = Vec::new();
-    candidates.extend(env_path_candidates([ENV_EMBEDDED_MODULE_DIR]));
-    for path in library_paths {
-        if let Some(out_dir) = path.parent() {
-            candidates.push(out_dir.join("modules"));
-        }
-        if let Some(release_root) = path.parent().and_then(Path::parent) {
-            candidates.push(release_root.join("lib/modules"));
-        }
-    }
-    if let Some(work_root) = install_dir.parent() {
-        candidates.push(work_root.join("out/modules"));
-    }
-    if let Ok(cwd) = std::env::current_dir() {
-        candidates.push(cwd.join("target/liboliphaunt-pg18/out/modules"));
-        candidates.push(cwd.join("target/native-liboliphaunt-pg18/out/modules"));
-        if let Some(target_id) = native_host_target_id() {
-            candidates.push(cwd.join(format!("target/liboliphaunt-pg18-{target_id}/out/modules")));
-        }
-    }
-
-    for candidate in candidates {
-        if candidate.is_dir() {
-            return Ok(candidate);
-        }
-    }
-    Err(Error::Engine(
-        "could not locate native embedded PostgreSQL 18 module artifacts; build native liboliphaunt first"
-            .to_owned(),
-    ))
-}
-
-fn native_install_dir_is_valid(path: &Path) -> bool {
-    native_tool_is_file(path, "postgres")
-        && native_tool_is_file(path, "initdb")
-        && native_tool_is_file(path, "pg_ctl")
-        && path
-            .join("share/postgresql/postgresql.conf.sample")
-            .is_file()
-        && path.join("lib/postgresql").is_dir()
-}
-
-fn native_tool_is_file(path: &Path, tool: &str) -> bool {
-    path.join("bin").join(tool).is_file() || path.join("bin").join(format!("{tool}.exe")).is_file()
-}
-
-pub(super) fn resources_dir_candidates() -> Vec {
-    let mut candidates = Vec::new();
-    if let Some(path) = registered_build_resources_dir() {
-        candidates.push(path);
-    }
-    if let Some(path) = std::env::var_os(ENV_RESOURCES_DIR) {
-        candidates.push(PathBuf::from(path));
-    }
-    candidates
-}
-
-pub(super) fn locate_native_icu_data() -> Result> {
-    for resources_dir in resources_dir_candidates() {
-        let directory = resources_dir.join("icu-data/oliphaunt-icu/share/icu");
-        if !icu_data_dir_is_valid(&directory) {
-            continue;
-        }
-        let receipt = resources_dir.join("icu-data/oliphaunt-icu/manifest.properties");
-        let tree_sha256 = read_icu_data_receipt(&receipt)?;
-        return Ok(Some(LocatedIcuData {
-            directory,
-            package_resources_root: Some(resources_dir),
-            tree_sha256: Some(tree_sha256),
-        }));
-    }
-    if let Some(path) = std::env::var_os("OLIPHAUNT_ICU_DATA_DIR") {
-        let directory = PathBuf::from(path);
-        if icu_data_dir_is_valid(&directory) {
-            return Ok(Some(LocatedIcuData {
-                directory,
-                package_resources_root: None,
-                tree_sha256: None,
-            }));
-        }
-    }
-    Ok(None)
-}
-
-pub(super) fn locate_native_cluster_seed(
-    resources_dir: &Path,
-    profile: super::super::NativeCatalogProfile,
-) -> Result> {
-    let payload = resources_dir.join("native-runtime/liboliphaunt-native");
-    let carrier_target = read_native_runtime_carrier(&payload.join("manifest.properties"))?;
-    let relative = match profile {
-        super::super::NativeCatalogProfile::Standard => "cluster-seed",
-        super::super::NativeCatalogProfile::Icu => "cluster-seed-icu",
-    };
-    let directory = payload.join(relative);
-    if !directory.is_dir() {
-        return Ok(None);
-    }
-    let seed = parse_native_cluster_seed(&directory, profile)?;
-    if seed.target != carrier_target {
-        return Err(Error::Engine(format!(
-            "native runtime carrier target {} does not match {} cluster seed target {}",
-            carrier_target,
-            profile.id(),
-            seed.target
-        )));
-    }
-    Ok(Some(seed))
-}
-
-pub(super) fn package_resources_root_for_install(install_dir: &Path) -> Option {
-    resources_dir_candidates()
-        .into_iter()
-        .find(|resources_dir| {
-            paths_identical(
-                install_dir,
-                &resources_dir.join("native-runtime/liboliphaunt-native/runtime"),
-            )
-        })
-}
-
-fn parse_native_cluster_seed(
-    path: &Path,
-    profile: super::super::NativeCatalogProfile,
-) -> Result {
-    if !path.join("files/PG_VERSION").is_file() || !path.join("files/global/pg_control").is_file() {
-        return Err(Error::Engine(format!(
-            "native {} cluster seed is incomplete: {}",
-            profile.id(),
-            path.display()
-        )));
-    }
-    let manifest_path = path.join("manifest.properties");
-    let manifest = std::fs::read_to_string(&manifest_path).map_err(|err| {
-        Error::Engine(format!(
-            "read native cluster seed manifest {}: {err}",
-            manifest_path.display()
-        ))
-    })?;
-    let fields = parse_properties(&manifest, &manifest_path)?;
-    let expected_role = format!("cluster-seed-{}", profile.id());
-    let expected_features = if profile == super::super::NativeCatalogProfile::Icu {
-        "icu"
-    } else {
-        ""
-    };
-    const CLUSTER_SEED_FIELDS: [&str; 14] = [
-        "schema",
-        "layout",
-        "artifactRole",
-        "catalogProfile",
-        "target",
-        "postgresMajor",
-        "physicalFormat",
-        "compatibilityKey",
-        "initialSuperuser",
-        "icuDataVersion",
-        "icuDataForm",
-        "icuDataTreeSha256",
-        "runtimeFeatures",
-        "cacheKey",
-    ];
-    let target = fields.get("target").filter(|value| valid_identity(value));
-    if fields.len() != CLUSTER_SEED_FIELDS.len()
-        || CLUSTER_SEED_FIELDS
-            .iter()
-            .any(|key| !fields.contains_key(*key))
-        || fields.get("schema").map(String::as_str) != Some("oliphaunt-runtime-resources-v1")
-        || fields.get("layout").map(String::as_str) != Some("oliphaunt-cluster-seed-v1")
-        || fields.get("artifactRole").map(String::as_str) != Some(expected_role.as_str())
-        || fields.get("catalogProfile").map(String::as_str) != Some(profile.id())
-        || fields.get("postgresMajor").map(String::as_str) != Some("18")
-        || fields.get("physicalFormat").map(String::as_str) != Some("native-pg18-v1")
-        || target.is_none()
-        || fields.get("compatibilityKey").map(String::as_str)
-            != target
-                .map(|value| format!("native-pg18-{value}-v1"))
-                .as_deref()
-        || fields.get("initialSuperuser").map(String::as_str) != Some("postgres")
-        || fields.get("runtimeFeatures").map(String::as_str) != Some(expected_features)
-        || !fields
-            .get("cacheKey")
-            .is_some_and(|value| valid_seed_cache_key(value))
-    {
-        return Err(Error::Engine(format!(
-            "native cluster seed manifest {} does not declare the {} target-qualified contract",
-            manifest_path.display(),
-            profile.id()
-        )));
-    }
-    let icu_data_tree_sha256 = match profile {
-        super::super::NativeCatalogProfile::Standard => {
-            if fields.get("icuDataVersion").is_some_and(String::is_empty)
-                && fields.get("icuDataForm").is_some_and(String::is_empty)
-                && fields
-                    .get("icuDataTreeSha256")
-                    .is_some_and(String::is_empty)
-            {
-                None
-            } else {
-                return Err(Error::Engine(format!(
-                    "native standard cluster seed manifest {} must not identify ICU data",
-                    manifest_path.display()
-                )));
-            }
-        }
-        super::super::NativeCatalogProfile::Icu => {
-            let digest = fields.get("icuDataTreeSha256");
-            if fields.get("icuDataVersion").map(String::as_str) == Some("76.1")
-                && fields.get("icuDataForm").map(String::as_str) == Some("files-le")
-                && digest.is_some_and(|value| valid_sha256(value))
-            {
-                digest.cloned()
-            } else {
-                return Err(Error::Engine(format!(
-                    "native ICU cluster seed manifest {} does not bind canonical ICU data",
-                    manifest_path.display()
-                )));
-            }
-        }
-    };
-    Ok(LocatedClusterSeed {
-        directory: path.to_path_buf(),
-        target: target.expect("target validated above").clone(),
-        icu_data_tree_sha256,
-    })
-}
-
-fn read_icu_data_receipt(path: &Path) -> Result {
-    let manifest = std::fs::read_to_string(path).map_err(|err| {
-        Error::Engine(format!(
-            "read native ICU data receipt {}: {err}",
-            path.display()
-        ))
-    })?;
-    let fields = parse_properties(&manifest, path)?;
-    let digest = fields.get("icuDataTreeSha256");
-    if fields.len() != 5
-        || fields.get("schema").map(String::as_str) != Some("oliphaunt-icu-data-v1")
-        || fields.get("artifactRole").map(String::as_str) != Some("icu-data")
-        || fields.get("icuDataVersion").map(String::as_str) != Some("76.1")
-        || fields.get("icuDataForm").map(String::as_str) != Some("files-le")
-        || !digest.is_some_and(|value| valid_sha256(value))
-    {
-        return Err(Error::Engine(format!(
-            "native ICU data receipt {} is invalid",
-            path.display()
-        )));
-    }
-    Ok(digest.expect("digest validated above").clone())
-}
-
-fn read_native_runtime_carrier(path: &Path) -> Result {
-    let manifest = std::fs::read_to_string(path).map_err(|err| {
-        Error::Engine(format!(
-            "read native runtime carrier receipt {}: {err}",
-            path.display()
-        ))
-    })?;
-    let fields = parse_properties(&manifest, path)?;
-    let target = fields.get("clusterSeedTarget");
-    let expected_target = native_host_target_id().ok_or_else(|| {
-        Error::Engine(format!(
-            "native runtime carrier {} is not supported on {}/{}",
-            path.display(),
-            std::env::consts::OS,
-            std::env::consts::ARCH
-        ))
-    })?;
-    if fields.len() != 4
-        || fields.get("schema").map(String::as_str) != Some("oliphaunt-native-runtime-carrier-v1")
-        || target.map(String::as_str) != Some(expected_target)
-        || fields.get("clusterSeedRelativePath").map(String::as_str) != Some("cluster-seed")
-        || fields.get("icuClusterSeedRelativePath").map(String::as_str) != Some("cluster-seed-icu")
-    {
-        return Err(Error::Engine(format!(
-            "native runtime carrier receipt {} must be the exact {} cluster-seed carrier contract",
-            path.display(),
-            expected_target
-        )));
-    }
-    Ok(target.expect("target validated above").clone())
-}
-
-fn parse_properties(
-    contents: &str,
-    path: &Path,
-) -> Result> {
-    let mut fields = std::collections::BTreeMap::new();
-    for line in contents.lines().filter(|line| !line.is_empty()) {
-        let Some((key, value)) = line.split_once('=') else {
-            return Err(Error::Engine(format!(
-                "manifest {} contains malformed properties",
-                path.display()
-            )));
-        };
-        if key.is_empty() || fields.insert(key.to_owned(), value.to_owned()).is_some() {
-            return Err(Error::Engine(format!(
-                "manifest {} contains duplicate properties",
-                path.display()
-            )));
-        }
-    }
-    Ok(fields)
-}
-
-fn paths_identical(left: &Path, right: &Path) -> bool {
-    left.canonicalize().unwrap_or_else(|_| left.to_path_buf())
-        == right.canonicalize().unwrap_or_else(|_| right.to_path_buf())
-}
-
-fn valid_identity(value: &str) -> bool {
-    value
-        .bytes()
-        .next()
-        .is_some_and(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit())
-        && value
-            .bytes()
-            .all(|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-')
-}
-
-fn valid_seed_cache_key(value: &str) -> bool {
-    !value.is_empty()
-        && value != "."
-        && value != ".."
-        && value.len() <= 128
-        && value
-            .bytes()
-            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
-}
-
-fn valid_sha256(value: &str) -> bool {
-    value.len() == 64
-        && value
-            .bytes()
-            .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
-}
-
-fn icu_data_dir_is_valid(path: &Path) -> bool {
-    let Ok(entries) = std::fs::read_dir(path) else {
-        return false;
-    };
-    entries.flatten().any(|entry| {
-        let name = entry.file_name().to_string_lossy().into_owned();
-        let path = entry.path();
-        (path.is_file() && name.starts_with("icudt") && name.ends_with(".dat"))
-            || (path.is_dir()
-                && name.starts_with("icudt")
-                && std::fs::read_dir(path)
-                    .ok()
-                    .into_iter()
-                    .flatten()
-                    .flatten()
-                    .any(|child| child.path().is_file()))
-    })
-}
-
-fn native_host_target_id() -> Option<&'static str> {
-    match (std::env::consts::OS, std::env::consts::ARCH) {
-        ("macos", "aarch64") => Some("macos-arm64"),
-        ("linux", "x86_64") => Some("linux-x64-gnu"),
-        ("linux", "aarch64") => Some("linux-arm64-gnu"),
-        ("windows", "x86_64") => Some("windows-x64-msvc"),
-        ("android", "aarch64" | "x86_64") => Some("android-datum64"),
-        ("ios", "aarch64" | "x86_64") => Some("ios-datum64"),
-        _ => None,
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use std::fs;
-    use std::path::{Path, PathBuf};
-    use std::sync::{Mutex, OnceLock};
-    use std::time::{SystemTime, UNIX_EPOCH};
-
-    use super::*;
-    use crate::liboliphaunt::root::NativeCatalogProfile;
-
-    static ENV_LOCK: OnceLock> = OnceLock::new();
-
-    #[test]
-    fn embedded_modules_locator_accepts_release_lib_modules_next_to_dll() {
-        let _guard = ENV_LOCK.get_or_init(|| Mutex::new(())).lock().unwrap();
-        let previous = std::env::var_os(ENV_EMBEDDED_MODULE_DIR);
-        unsafe {
-            std::env::remove_var(ENV_EMBEDDED_MODULE_DIR);
-        }
-        let temp = TempTree::new("release-lib-modules");
-        let release_root = temp.path().join("liboliphaunt-0.0.0-windows-x64-msvc");
-        let install_dir = release_root.join("runtime");
-        let modules_dir = release_root.join("lib/modules");
-        fs::create_dir_all(release_root.join("bin")).expect("create release bin");
-        fs::create_dir_all(&modules_dir).expect("create release modules");
-        fs::create_dir_all(&install_dir).expect("create release runtime");
-
-        let located = locate_native_embedded_modules_dir_from_libraries(
-            &install_dir,
-            [release_root.join("bin/oliphaunt.dll")],
-        )
-        .expect("locate release modules");
-
-        restore_env(ENV_EMBEDDED_MODULE_DIR, previous);
-        assert_eq!(located, modules_dir);
-    }
-
-    #[test]
-    fn embedded_modules_locator_prefers_explicit_environment_dir() {
-        let _guard = ENV_LOCK.get_or_init(|| Mutex::new(())).lock().unwrap();
-        let temp = TempTree::new("explicit-env-modules");
-        let install_dir = temp.path().join("runtime");
-        let modules_dir = temp.path().join("registry/modules");
-        fs::create_dir_all(&install_dir).expect("create runtime");
-        fs::create_dir_all(&modules_dir).expect("create modules");
-        let previous = std::env::var_os(ENV_EMBEDDED_MODULE_DIR);
-        unsafe {
-            std::env::set_var(ENV_EMBEDDED_MODULE_DIR, &modules_dir);
-        }
-
-        let located = locate_native_embedded_modules_dir_from_libraries(
-            &install_dir,
-            [temp.path().join("lib/liboliphaunt.so")],
-        )
-        .expect("locate env modules");
-
-        restore_env(ENV_EMBEDDED_MODULE_DIR, previous);
-        assert_eq!(located, modules_dir);
-    }
-
-    #[test]
-    fn cluster_seed_manifest_accepts_shared_standard_and_icu_fixtures() {
-        let temp = TempTree::new("target-qualified-seed");
-        let seed = temp.path().join("cluster-seed");
-        write_cluster_seed_fixture(&seed, "native-standard.valid.properties");
-
-        let located = parse_native_cluster_seed(&seed, NativeCatalogProfile::Standard)
-            .expect("accept target-qualified cluster seed");
-        assert_eq!(located.target, "linux-x64-gnu");
-
-        write_cluster_seed_fixture(&seed, "native-icu.valid.properties");
-        let located = parse_native_cluster_seed(&seed, NativeCatalogProfile::Icu)
-            .expect("accept ICU cluster seed");
-        assert_eq!(
-            located.icu_data_tree_sha256.as_deref(),
-            Some("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
-        );
-    }
-
-    #[test]
-    fn cluster_seed_manifest_rejects_shared_invalid_vectors() {
-        let temp = TempTree::new("invalid-seed-manifests");
-        let seed = temp.path().join("cluster-seed");
-        for fixture in [
-            "native-malformed.invalid.properties",
-            "native-whitespace.invalid.properties",
-            "native-cache-key.invalid.properties",
-            "native-dot-cache-key.invalid.properties",
-            "native-dotdot-cache-key.invalid.properties",
-            "native-extra-field.invalid.properties",
-            "native-target-mismatch.invalid.properties",
-            "native-profile-mismatch.invalid.properties",
-        ] {
-            write_cluster_seed_fixture(&seed, fixture);
-            assert!(
-                parse_native_cluster_seed(&seed, NativeCatalogProfile::Standard).is_err(),
-                "accepted invalid fixture {fixture}"
-            );
-        }
-    }
-
-    #[test]
-    fn icu_receipt_is_an_exact_canonical_identity() {
-        let temp = TempTree::new("icu-receipt");
-        let receipt = temp.path().join("manifest.properties");
-        let digest = "a".repeat(64);
-        fs::write(
-            &receipt,
-            format!(
-                "schema=oliphaunt-icu-data-v1\nartifactRole=icu-data\nicuDataVersion=76.1\nicuDataForm=files-le\nicuDataTreeSha256={digest}\n"
-            ),
-        )
-        .expect("write ICU receipt");
-        assert_eq!(read_icu_data_receipt(&receipt).unwrap(), digest);
-
-        fs::write(
-            &receipt,
-            format!(
-                "schema=oliphaunt-icu-data-v1\nartifactRole=icu-data\nicuDataVersion=76.1\nicuDataForm=files-le\nicuDataTreeSha256={digest}\nextra=value\n"
-            ),
-        )
-        .expect("write invalid ICU receipt");
-        assert!(read_icu_data_receipt(&receipt).is_err());
-    }
-
-    #[test]
-    fn runtime_carrier_receipt_is_exact_and_host_bound() {
-        let Some(target) = native_host_target_id() else {
-            return;
-        };
-        let temp = TempTree::new("runtime-carrier-receipt");
-        let receipt = temp.path().join("manifest.properties");
-
-        write_runtime_carrier_receipt(&receipt, target, "cluster-seed", "cluster-seed-icu", "");
-        assert_eq!(read_native_runtime_carrier(&receipt).unwrap(), target);
-
-        write_runtime_carrier_receipt(
-            &receipt,
-            target,
-            "nested/cluster-seed",
-            "cluster-seed-icu",
-            "",
-        );
-        assert!(read_native_runtime_carrier(&receipt).is_err());
-
-        write_runtime_carrier_receipt(
-            &receipt,
-            target,
-            "cluster-seed",
-            "cluster-seed-icu",
-            "extra=value\n",
-        );
-        assert!(read_native_runtime_carrier(&receipt).is_err());
-
-        write_runtime_carrier_receipt(
-            &receipt,
-            "other-target",
-            "cluster-seed",
-            "cluster-seed-icu",
-            "",
-        );
-        assert!(read_native_runtime_carrier(&receipt).is_err());
-    }
-
-    fn write_runtime_carrier_receipt(
-        path: &Path,
-        target: &str,
-        standard_path: &str,
-        icu_path: &str,
-        extra: &str,
-    ) {
-        fs::write(
-            path,
-            format!(
-                "schema=oliphaunt-native-runtime-carrier-v1\nclusterSeedTarget={target}\nclusterSeedRelativePath={standard_path}\nicuClusterSeedRelativePath={icu_path}\n{extra}"
-            ),
-        )
-        .expect("write runtime carrier receipt");
-    }
-
-    fn write_cluster_seed_fixture(path: &Path, fixture: &str) {
-        fs::create_dir_all(path.join("files/global")).expect("create cluster seed tree");
-        fs::write(path.join("files/PG_VERSION"), b"18\n").expect("write PG_VERSION");
-        fs::write(path.join("files/global/pg_control"), b"control").expect("write pg_control");
-        let fixture = Path::new(env!("CARGO_MANIFEST_DIR"))
-            .join("../../shared/cluster-seed-contract/fixtures")
-            .join(fixture);
-        fs::copy(fixture, path.join("manifest.properties"))
-            .expect("copy shared cluster seed fixture");
-    }
-
-    fn restore_env(name: &str, previous: Option) {
-        match previous {
-            Some(value) => unsafe {
-                std::env::set_var(name, value);
-            },
-            None => unsafe {
-                std::env::remove_var(name);
-            },
-        }
-    }
-
-    struct TempTree {
-        path: PathBuf,
-    }
-
-    impl TempTree {
-        fn new(name: &str) -> Self {
-            let nanos = SystemTime::now()
-                .duration_since(UNIX_EPOCH)
-                .expect("clock before epoch")
-                .as_nanos();
-            let path = std::env::temp_dir().join(format!(
-                "oliphaunt-locate-test-{name}-{nanos}-{}",
-                std::process::id()
-            ));
-            fs::create_dir_all(&path).expect("create temp tree");
-            Self { path }
-        }
-
-        fn path(&self) -> &Path {
-            &self.path
-        }
-    }
-
-    impl Drop for TempTree {
-        fn drop(&mut self) {
-            let _ = fs::remove_dir_all(&self.path);
-        }
-    }
-}
diff --git a/src/sdks/rust/src/query.rs b/src/sdks/rust/src/query.rs
deleted file mode 100644
index 9ad7533b6..000000000
--- a/src/sdks/rust/src/query.rs
+++ /dev/null
@@ -1,1504 +0,0 @@
-use std::str;
-#[cfg(test)]
-use std::sync::Arc;
-
-use crate::error::{Error, PostgresError, Result};
-use crate::protocol::{ProtocolRequest, ProtocolResponse};
-use crate::query_core as core;
-
-pub(crate) use crate::query_core::ReadyStatus;
-pub use crate::query_core::{
-    CommandResult, DecodeError, ExecResult, FromSql, IntoParameter, Parameter, PostgresNotice,
-    QueryField, QueryFormat, QueryResult, QueryRow, RowIndex, StatementDescription,
-    StatementResult, TypeOid, ValueFormat, ValueRef,
-};
-
-impl QueryResult {
-    /// Read a text-format value by row index and column name.
-    pub fn get_text(&self, row: usize, column: &str) -> Result> {
-        let column = column
-            .resolve(self.fields())
-            .map_err(|error| Error::Engine(error.to_string()))?;
-        let row = self
-            .row(row)
-            .ok_or_else(|| Error::Engine(format!("query result has no row at index {row}")))?;
-        row.text(column)
-    }
-}
-
-impl QueryRow {
-    /// Read a text-format value by column index.
-    pub fn text(&self, column: usize) -> Result> {
-        let value = self
-            .value(column)
-            .ok_or_else(|| Error::Engine(format!("query row has no column at index {column}")))?;
-        value
-            .as_deref()
-            .map(|bytes| {
-                str::from_utf8(bytes)
-                    .map_err(|err| Error::Engine(format!("query value is not valid UTF-8: {err}")))
-            })
-            .transpose()
-    }
-}
-
-#[cfg(test)]
-pub(crate) fn parse_query_response(response: &ProtocolResponse) -> Result {
-    parse_query_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Either)
-}
-
-#[cfg(test)]
-pub(crate) fn parse_command_response(response: &ProtocolResponse) -> Result {
-    parse_command_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Either)
-}
-
-pub(crate) fn parse_extended_command_response(
-    response: &ProtocolResponse,
-) -> Result {
-    parse_command_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Extended)
-}
-
-pub(crate) fn parse_simple_command_response(response: &ProtocolResponse) -> Result {
-    parse_command_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Simple)
-}
-
-fn parse_command_response_with_protocol(
-    bytes: &[u8],
-    expected_protocol: core::ExpectedProtocol,
-) -> Result {
-    core::parse_command_response(bytes, expected_protocol).map_err(error_from_core)
-}
-
-pub(crate) fn extended_statement_request(
-    sql: &str,
-    params: &[Parameter],
-    result_format: ValueFormat,
-) -> Result {
-    core::extended_statement(sql, params, result_format.code())
-        .map(ProtocolRequest::new)
-        .map_err(error_from_core)
-}
-
-pub(crate) fn reject_copy_statements(sql: &str) -> Result<()> {
-    core::reject_copy_statements(sql).map_err(error_from_core)
-}
-
-pub(crate) fn reject_transaction_chain(sql: &str) -> Result<()> {
-    core::reject_transaction_chain(sql).map_err(error_from_core)
-}
-
-#[cfg(test)]
-pub(crate) fn parse_query_response_bytes(bytes: &[u8]) -> Result {
-    parse_query_response_with_protocol(bytes, core::ExpectedProtocol::Either)
-}
-
-pub(crate) fn parse_extended_query_response(response: &ProtocolResponse) -> Result {
-    parse_query_response_with_protocol(response.as_bytes(), core::ExpectedProtocol::Extended)
-}
-
-fn parse_query_response_with_protocol(
-    bytes: &[u8],
-    expected_protocol: core::ExpectedProtocol,
-) -> Result {
-    core::parse_query_response(bytes, expected_protocol).map_err(error_from_core)
-}
-
-pub(crate) fn parse_exec_response(response: &ProtocolResponse) -> Result {
-    core::parse_exec_response(response.as_bytes()).map_err(error_from_core)
-}
-
-pub(crate) fn parse_statement_description(
-    response: &ProtocolResponse,
-) -> Result {
-    core::parse_statement_description(response.as_bytes()).map_err(error_from_core)
-}
-
-pub(crate) fn describe_statement_request(
-    sql: &str,
-    params: &[Parameter],
-) -> Result {
-    core::describe_statement(sql, params)
-        .map(ProtocolRequest::new)
-        .map_err(error_from_core)
-}
-
-pub(crate) fn response_ready_status(response: &ProtocolResponse) -> Result {
-    core::response_ready_status(response.as_bytes()).map_err(error_from_core)
-}
-
-pub(crate) fn validate_managed_transaction_response(
-    response: &ProtocolResponse,
-) -> Result {
-    core::validate_managed_transaction_response(response.as_bytes()).map_err(error_from_core)
-}
-
-fn error_from_core(error: core::Error) -> Error {
-    match error {
-        core::Error::Protocol(message) => Error::Engine(message),
-        core::Error::Postgres {
-            diagnostic,
-            notices,
-        } => {
-            let mut error = PostgresError::from_core(*diagnostic);
-            error.notices = notices.into_iter().map(PostgresNotice::from_core).collect();
-            Error::Postgres(Box::new(error))
-        }
-    }
-}
-
-#[cfg(test)]
-fn parse_notice_response(body: &[u8]) -> Result {
-    core::parse_diagnostic_fields(body, "NoticeResponse")
-        .map(|fields| core::diagnostic(fields, "PostgreSQL NoticeResponse"))
-        .map(PostgresNotice::from_core)
-        .map_err(error_from_core)
-}
-
-#[cfg(test)]
-fn read_u32(input: &mut &[u8], label: &str) -> Result {
-    let bytes = take(input, 4, label)?;
-    Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
-}
-
-#[cfg(test)]
-fn read_i32(input: &mut &[u8], label: &str) -> Result {
-    let bytes = take(input, 4, label)?;
-    Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
-}
-
-#[cfg(test)]
-fn read_i16(input: &mut &[u8], label: &str) -> Result {
-    let bytes = take(input, 2, label)?;
-    Ok(i16::from_be_bytes([bytes[0], bytes[1]]))
-}
-
-#[cfg(test)]
-fn read_cstring<'a>(input: &mut &'a [u8], label: &str) -> Result<&'a str> {
-    let nul = input
-        .iter()
-        .position(|byte| *byte == 0)
-        .ok_or_else(|| Error::Engine(format!("{label} is missing null terminator")))?;
-    let value = str::from_utf8(&input[..nul])
-        .map_err(|error| Error::Engine(format!("{label} is not valid UTF-8: {error}")))?;
-    *input = &input[nul + 1..];
-    Ok(value)
-}
-
-#[cfg(test)]
-fn take<'a>(input: &mut &'a [u8], len: usize, label: &str) -> Result<&'a [u8]> {
-    if input.len() < len {
-        return Err(Error::Engine(format!("truncated {label}")));
-    }
-    let (head, tail) = input.split_at(len);
-    *input = tail;
-    Ok(head)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    fn assert_other_error_contains(actual: Result, expected: &str) {
-        let error = match actual {
-            Ok(_) => panic!("expected error containing {expected:?}"),
-            Err(error) => error,
-        };
-        assert_eq!(error.kind(), crate::error::ErrorKind::Other);
-        assert!(
-            error.to_string().contains(expected),
-            "{error:?} omitted {expected:?}"
-        );
-    }
-
-    #[test]
-    fn consumes_shared_query_response_contract() {
-        let source = crate::test_fixtures::text("protocol/query-response-cases.json");
-        let fixture: serde_json::Value =
-            serde_json::from_str(&source).expect("shared query response fixture is valid JSON");
-        assert_eq!(fixture["schemaVersion"], 1);
-        let type_oids = &fixture["typeOids"];
-        for (name, actual) in [
-            ("xmlArray", TypeOid::XML_ARRAY),
-            ("charArray", TypeOid::CHAR_ARRAY),
-            ("nameArray", TypeOid::NAME_ARRAY),
-            ("timetz", TypeOid::TIMETZ),
-            ("timetzArray", TypeOid::TIMETZ_ARRAY),
-        ] {
-            assert_eq!(
-                u64::from(actual.get()),
-                type_oids[name].as_u64().expect("shared type OID"),
-                "shared PostgreSQL type OID {name}"
-            );
-        }
-        for case in fixture["cases"].as_array().expect("fixture cases") {
-            let name = case["name"].as_str().expect("case name");
-            let bytes = decode_hex(case["responseHex"].as_str().expect("response hex"));
-            if let Some(expected_modes) = case["protocolModeExpectation"].as_object() {
-                let response = ProtocolResponse::new(bytes.clone());
-                assert_protocol_mode_result(
-                    name,
-                    "simpleCommand",
-                    parse_simple_command_response(&response)
-                        .map(|result| result.command_tag().map(str::to_owned)),
-                    &expected_modes["simpleCommand"],
-                );
-                assert_protocol_mode_result(
-                    name,
-                    "extendedCommand",
-                    parse_extended_command_response(&response)
-                        .map(|result| result.command_tag().map(str::to_owned)),
-                    &expected_modes["extendedCommand"],
-                );
-                assert_protocol_mode_result(
-                    name,
-                    "extendedQuery",
-                    parse_extended_query_response(&response)
-                        .map(|result| result.command_tag().map(str::to_owned)),
-                    &expected_modes["extendedQuery"],
-                );
-            }
-            let Some(expectation) = case["queryExpectation"].as_object() else {
-                continue;
-            };
-            match parse_query_response(&ProtocolResponse::new(bytes)) {
-                Ok(result) => {
-                    let expected = expectation["ok"]
-                        .as_object()
-                        .unwrap_or_else(|| panic!("{name}: expected parser error"));
-                    assert_eq!(
-                        result.command_tag(),
-                        expected["commandTag"].as_str(),
-                        "{name}"
-                    );
-                    assert_eq!(result.row_count(), expected["rowCount"].as_u64(), "{name}");
-                    let fields = expected["fields"].as_array().expect("expected fields");
-                    assert_eq!(result.fields().len(), fields.len(), "{name}");
-                    for (actual, expected) in result.fields().iter().zip(fields) {
-                        assert_eq!(actual.name, expected["name"].as_str().unwrap(), "{name}");
-                        assert_eq!(
-                            u64::from(actual.type_oid),
-                            expected["typeOid"].as_u64().unwrap(),
-                            "{name}"
-                        );
-                        assert_eq!(actual.format, QueryFormat::Text, "{name}");
-                    }
-                    let rows = expected["rows"].as_array().expect("expected rows");
-                    assert_eq!(result.rows().len(), rows.len(), "{name}");
-                    for (actual, expected) in result.rows().iter().zip(rows) {
-                        let expected = expected.as_array().expect("expected row values");
-                        assert_eq!(actual.values().len(), expected.len(), "{name}");
-                        for (column, expected) in expected.iter().enumerate() {
-                            assert_eq!(actual.text(column).unwrap(), expected.as_str(), "{name}");
-                        }
-                    }
-                    if let Some(expected_notices) = expected
-                        .get("notices")
-                        .and_then(serde_json::Value::as_array)
-                    {
-                        assert_eq!(result.notices().len(), expected_notices.len(), "{name}");
-                        for (actual, expected) in result.notices().iter().zip(expected_notices) {
-                            assert_notice_diagnostic(name, actual, expected);
-                        }
-                    }
-                }
-                Err(error) if error.postgres_error().is_some() => {
-                    let error = error
-                        .postgres_error()
-                        .expect("guard established PostgreSQL error identity");
-                    let expected = expectation["postgresError"]
-                        .as_object()
-                        .unwrap_or_else(|| panic!("{name}: unexpected PostgreSQL error {error:?}"));
-                    assert_eq!(
-                        error.severity.as_deref(),
-                        expected["severity"].as_str(),
-                        "{name}"
-                    );
-                    assert_eq!(
-                        error.sqlstate.as_deref(),
-                        expected["sqlstate"].as_str(),
-                        "{name}"
-                    );
-                    assert_eq!(
-                        error.message,
-                        expected["message"].as_str().unwrap(),
-                        "{name}"
-                    );
-                    assert_optional_diagnostic_field(
-                        name,
-                        "localizedSeverity",
-                        error.localized_severity.as_deref(),
-                        expected,
-                    );
-                    assert_optional_diagnostic_field(
-                        name,
-                        "nonlocalizedSeverity",
-                        error.nonlocalized_severity.as_deref(),
-                        expected,
-                    );
-                    assert_optional_diagnostic_field(
-                        name,
-                        "internalPosition",
-                        error.internal_position.as_deref(),
-                        expected,
-                    );
-                    assert_optional_diagnostic_field(
-                        name,
-                        "internalQuery",
-                        error.internal_query.as_deref(),
-                        expected,
-                    );
-                    assert_optional_diagnostic_field(name, "file", error.file.as_deref(), expected);
-                    assert_optional_diagnostic_field(name, "line", error.line.as_deref(), expected);
-                    assert_optional_diagnostic_field(
-                        name,
-                        "routine",
-                        error.routine.as_deref(),
-                        expected,
-                    );
-                }
-                Err(error) => {
-                    assert_eq!(error.kind(), crate::error::ErrorKind::Other, "{name}");
-                    let message = error.to_string();
-                    let expected = expectation["engineErrorContains"]
-                        .as_str()
-                        .unwrap_or_else(|| panic!("{name}: unexpected engine error {message}"));
-                    assert!(
-                        message.contains(expected),
-                        "{name}: {message:?} omitted {expected:?}"
-                    );
-                }
-            }
-        }
-    }
-
-    fn assert_protocol_mode_result(
-        case: &str,
-        mode: &str,
-        actual: Result>,
-        expected: &serde_json::Value,
-    ) {
-        match expected["outcome"].as_str().expect("mode outcome") {
-            "ok" => assert_eq!(
-                actual.unwrap_or_else(|error| panic!("{case} {mode}: {error}")),
-                expected["commandTag"].as_str().map(str::to_owned),
-                "{case} {mode} command tag"
-            ),
-            "engineError" => {
-                let error = actual.expect_err(&format!("{case} {mode} must fail"));
-                assert_eq!(error.kind(), crate::error::ErrorKind::Other);
-                let message = error.to_string();
-                let expected = expected["contains"].as_str().expect("error substring");
-                assert!(
-                    message.contains(expected),
-                    "{case} {mode}: {message:?} omitted {expected:?}"
-                );
-            }
-            outcome => panic!("{case} {mode}: unknown outcome {outcome:?}"),
-        }
-    }
-
-    fn assert_notice_diagnostic(case: &str, actual: &PostgresNotice, expected: &serde_json::Value) {
-        let expected = expected.as_object().expect("notice diagnostic expectation");
-        assert_optional_diagnostic_field(case, "severity", actual.severity.as_deref(), expected);
-        assert_optional_diagnostic_field(
-            case,
-            "localizedSeverity",
-            actual.localized_severity.as_deref(),
-            expected,
-        );
-        assert_optional_diagnostic_field(
-            case,
-            "nonlocalizedSeverity",
-            actual.nonlocalized_severity.as_deref(),
-            expected,
-        );
-        assert_optional_diagnostic_field(case, "message", Some(&actual.message), expected);
-        assert_optional_diagnostic_field(
-            case,
-            "internalPosition",
-            actual.internal_position.as_deref(),
-            expected,
-        );
-        assert_optional_diagnostic_field(
-            case,
-            "internalQuery",
-            actual.internal_query.as_deref(),
-            expected,
-        );
-        assert_optional_diagnostic_field(case, "file", actual.file.as_deref(), expected);
-        assert_optional_diagnostic_field(case, "line", actual.line.as_deref(), expected);
-        assert_optional_diagnostic_field(case, "routine", actual.routine.as_deref(), expected);
-    }
-
-    fn assert_optional_diagnostic_field(
-        case: &str,
-        field: &str,
-        actual: Option<&str>,
-        expected: &serde_json::Map,
-    ) {
-        if let Some(expected) = expected.get(field) {
-            assert_eq!(actual, expected.as_str(), "{case} diagnostic {field}");
-        }
-    }
-
-    fn decode_hex(value: &str) -> Vec {
-        assert_eq!(value.len() % 2, 0, "hex fixture has even length");
-        value
-            .as_bytes()
-            .chunks_exact(2)
-            .map(|pair| {
-                let pair = std::str::from_utf8(pair).expect("hex pair is ASCII");
-                u8::from_str_radix(pair, 16).expect("hex pair is valid")
-            })
-            .collect()
-    }
-
-    #[test]
-    fn parses_simple_query_result() {
-        let mut bytes = Vec::new();
-        push_row_description(&mut bytes, &[("value", 23), ("empty", 25)]);
-        push_data_row(&mut bytes, &[Some("1"), None]);
-        push_command_complete(&mut bytes, "SELECT 1");
-        push_ready_for_query(&mut bytes);
-
-        let result = parse_query_response_bytes(&bytes).unwrap();
-        assert_eq!(result.fields()[0].name, "value");
-        assert_eq!(result.fields()[0].type_oid, 23);
-        assert_eq!(result.row_count(), Some(1));
-        assert_eq!(result.command_tag(), Some("SELECT 1"));
-        assert_eq!(result.get_text(0, "value").unwrap(), Some("1"));
-        assert_eq!(result.get_text(0, "empty").unwrap(), None);
-    }
-
-    #[test]
-    fn typed_rows_decode_strict_text_binary_and_null_values() {
-        let fields: Arc<[QueryField]> = vec![
-            test_field("text_int", TypeOid::INT4, QueryFormat::Text),
-            test_field("binary_int", TypeOid::INT8, QueryFormat::Binary),
-            test_field("flag", TypeOid::BOOL, QueryFormat::Binary),
-            test_field("text_bytes", TypeOid::BYTEA, QueryFormat::Text),
-            test_field("binary_bytes", TypeOid::BYTEA, QueryFormat::Binary),
-            test_field("nullable_int", TypeOid::INT4, QueryFormat::Text),
-            test_field("label", TypeOid::TEXT, QueryFormat::Text),
-        ]
-        .into();
-        let row = QueryRow {
-            fields: Arc::clone(&fields),
-            values: vec![
-                Some(b"42".to_vec()),
-                Some(9_i64.to_be_bytes().to_vec()),
-                Some(vec![1]),
-                Some(br"\x00ff".to_vec()),
-                Some(vec![0, 255]),
-                None,
-                Some(b"hello".to_vec()),
-            ],
-        };
-
-        assert_eq!(row.try_get::("text_int").unwrap(), 42);
-        assert_eq!(row.try_get::("binary_int").unwrap(), 9);
-        assert!(row.try_get::("flag").unwrap());
-        assert_eq!(
-            row.try_get::, _>("text_bytes").unwrap(),
-            vec![0, 255]
-        );
-        assert_eq!(row.try_get::<&[u8], _>("binary_bytes").unwrap(), &[0, 255]);
-        assert_eq!(row.try_get::, _>("nullable_int").unwrap(), None);
-        assert_eq!(row.try_get::<&str, _>("label").unwrap(), "hello");
-        assert!(matches!(
-            row.try_get::, _>("nullable_int"),
-            Err(DecodeError::TypeMismatch { type_oid, .. }) if type_oid == TypeOid::INT4
-        ));
-        assert!(matches!(
-            row.try_get::("text_int"),
-            Err(DecodeError::TypeMismatch { type_oid, .. }) if type_oid == TypeOid::INT4
-        ));
-    }
-
-    #[test]
-    fn every_name_lookup_rejects_duplicate_columns() {
-        let mut bytes = Vec::new();
-        push_row_description(&mut bytes, &[("same", 25), ("same", 25)]);
-        push_data_row(&mut bytes, &[Some("first"), Some("second")]);
-        push_command_complete(&mut bytes, "SELECT 1");
-        push_ready_for_query(&mut bytes);
-
-        let result = parse_query_response_bytes(&bytes).unwrap();
-        assert!(
-            result
-                .get_text(0, "same")
-                .unwrap_err()
-                .to_string()
-                .contains("more than one column")
-        );
-        assert!(matches!(
-            result.rows()[0].try_get::("same"),
-            Err(DecodeError::AmbiguousColumn(name)) if name == "same"
-        ));
-        assert!(matches!(
-            result.rows()[0].try_get_raw("same"),
-            Err(DecodeError::AmbiguousColumn(name)) if name == "same"
-        ));
-    }
-
-    #[test]
-    fn returns_sql_errors_as_errors() {
-        let mut bytes = Vec::new();
-        push_error_response(&mut bytes, "ERROR", "42P01", "relation does not exist");
-        push_ready_for_query(&mut bytes);
-
-        let error = parse_query_response_bytes(&bytes).unwrap_err();
-        assert_eq!(error.kind(), crate::error::ErrorKind::Postgres);
-        let postgres = error
-            .postgres_error()
-            .expect("Postgres errors expose structured diagnostics");
-        assert_eq!(postgres.severity.as_deref(), Some("ERROR"));
-        assert_eq!(postgres.sqlstate.as_deref(), Some("42P01"));
-        assert_eq!(postgres.message, "relation does not exist");
-    }
-
-    #[test]
-    fn execute_rejects_rows_and_directs_callers_to_query() {
-        let mut bytes = Vec::new();
-        push_row_description(&mut bytes, &[("one", 23)]);
-        push_data_row(&mut bytes, &[Some("1")]);
-        push_command_complete(&mut bytes, "SELECT 1");
-        push_row_description(&mut bytes, &[("two", 23)]);
-        push_data_row(&mut bytes, &[Some("2")]);
-        push_command_complete(&mut bytes, "SELECT 1");
-        push_ready_for_query(&mut bytes);
-
-        assert_other_error_contains(
-            parse_command_response(&ProtocolResponse::new(bytes)),
-            "execute() received rows; use query()",
-        );
-    }
-
-    #[test]
-    fn execute_validation_returns_structured_postgres_errors() {
-        let mut bytes = Vec::new();
-        push_notice_response(&mut bytes, "NOTICE", "before failure");
-        push_error_response(&mut bytes, "ERROR", "23505", "duplicate key value");
-        push_ready_for_query(&mut bytes);
-
-        let error = parse_command_response(&ProtocolResponse::new(bytes)).unwrap_err();
-        assert_eq!(error.kind(), crate::error::ErrorKind::Postgres);
-        let postgres = error
-            .postgres_error()
-            .expect("Postgres errors expose structured diagnostics");
-        assert_eq!(postgres.sqlstate.as_deref(), Some("23505"));
-        assert_eq!(postgres.message, "duplicate key value");
-        assert_eq!(postgres.notices.len(), 1);
-        assert_eq!(postgres.notices[0].message, "before failure");
-    }
-
-    #[test]
-    fn postgres_notice_exposes_finite_standard_diagnostic_fields() {
-        let notice = parse_notice_response(
-            b"SAVERTISSEMENT\0VWARNING\0Mcheck value\0p12\0qSELECT broken\0Fparse_expr.c\0L123\0RtransformExpr\0\0",
-        )
-        .expect("valid NoticeResponse");
-
-        assert_eq!(notice.severity.as_deref(), Some("AVERTISSEMENT"));
-        assert_eq!(notice.localized_severity.as_deref(), Some("AVERTISSEMENT"));
-        assert_eq!(notice.nonlocalized_severity.as_deref(), Some("WARNING"));
-        assert_eq!(notice.internal_position.as_deref(), Some("12"));
-        assert_eq!(notice.internal_query.as_deref(), Some("SELECT broken"));
-        assert_eq!(notice.file.as_deref(), Some("parse_expr.c"));
-        assert_eq!(notice.line.as_deref(), Some("123"));
-        assert_eq!(notice.routine.as_deref(), Some("transformExpr"));
-        assert_eq!(
-            notice
-                .fields
-                .iter()
-                .map(|field| field.code)
-                .collect::>(),
-            [b'S', b'V', b'M', b'p', b'q', b'F', b'L', b'R']
-        );
-    }
-
-    #[test]
-    fn error_response_requires_one_terminal_ready_boundary() {
-        let mut missing_ready = Vec::new();
-        push_error_response(&mut missing_ready, "ERROR", "42601", "syntax error");
-        assert_other_error_contains(
-            parse_command_response(&ProtocolResponse::new(missing_ready)),
-            "before ReadyForQuery",
-        );
-
-        let mut trailing = Vec::new();
-        push_error_response(&mut trailing, "ERROR", "42601", "syntax error");
-        push_ready_for_query(&mut trailing);
-        push_notice_response(&mut trailing, "NOTICE", "too late");
-        assert_other_error_contains(
-            parse_command_response(&ProtocolResponse::new(trailing)),
-            "bytes after ReadyForQuery",
-        );
-    }
-
-    #[test]
-    fn malformed_error_response_is_a_protocol_error() {
-        let mut malformed = Vec::new();
-        push_backend_message(&mut malformed, b'E', b"SERROR\0Mmissing terminator");
-        push_ready_for_query(&mut malformed);
-        assert_other_error_contains(
-            parse_command_response(&ProtocolResponse::new(malformed)),
-            "ErrorResponse field is missing null terminator",
-        );
-
-        let mut valid_without_message = Vec::new();
-        push_backend_message(&mut valid_without_message, b'E', b"CXX000\0\0");
-        push_ready_for_query(&mut valid_without_message);
-        let sdk_error =
-            parse_command_response(&ProtocolResponse::new(valid_without_message)).unwrap_err();
-        assert_eq!(sdk_error.kind(), crate::error::ErrorKind::Postgres);
-        let error = sdk_error
-            .postgres_error()
-            .expect("a valid ErrorResponse must retain PostgreSQL error identity");
-        assert_eq!(error.sqlstate.as_deref(), Some("XX000"));
-        assert_eq!(error.message, "PostgreSQL ErrorResponse");
-    }
-
-    #[test]
-    fn exec_preserves_ordered_command_and_row_results_with_notices() {
-        let mut bytes = Vec::new();
-        push_notice_response(&mut bytes, "NOTICE", "table ready");
-        push_command_complete(&mut bytes, "CREATE TABLE");
-        push_notice_response(&mut bytes, "NOTICE", "select ready");
-        push_row_description(&mut bytes, &[("answer", 23)]);
-        push_data_row(&mut bytes, &[Some("42")]);
-        push_command_complete(&mut bytes, "SELECT 1");
-        push_ready_for_query(&mut bytes);
-
-        let result = parse_exec_response(&ProtocolResponse::new(bytes)).unwrap();
-        assert_eq!(result.statements().len(), 2);
-        let StatementResult::Command(command) = &result.statements()[0] else {
-            panic!("first statement should be a command");
-        };
-        assert_eq!(command.command_tag(), Some("CREATE TABLE"));
-        assert_eq!(command.notices()[0].message, "table ready");
-        let StatementResult::Rows(rows) = &result.statements()[1] else {
-            panic!("second statement should return rows");
-        };
-        assert_eq!(rows.rows()[0].try_get::("answer").unwrap(), 42);
-        assert_eq!(rows.notices()[0].message, "select ready");
-        assert_eq!(result.notices()[0].message, "table ready");
-        assert_eq!(result.notices()[1].message, "select ready");
-    }
-
-    #[test]
-    fn single_statement_parsers_require_exactly_one_completion() {
-        let mut ready_only = Vec::new();
-        push_ready_for_query(&mut ready_only);
-        assert_other_error_contains(
-            parse_command_response(&ProtocolResponse::new(ready_only.clone())),
-            "before CommandComplete or EmptyQueryResponse",
-        );
-        assert_other_error_contains(
-            parse_query_response_bytes(&ready_only),
-            "before CommandComplete or EmptyQueryResponse",
-        );
-
-        let mut empty = Vec::new();
-        push_backend_message(&mut empty, b'I', &[]);
-        push_ready_for_query(&mut empty);
-        let command = parse_command_response(&ProtocolResponse::new(empty.clone())).unwrap();
-        assert_eq!(command.command_tag(), None);
-        let query = parse_query_response_bytes(&empty).unwrap();
-        assert_eq!(query.command_tag(), None);
-        assert!(query.fields().is_empty());
-        assert!(query.rows().is_empty());
-
-        let mut command_then_empty = Vec::new();
-        push_command_complete(&mut command_then_empty, "UPDATE 1");
-        push_backend_message(&mut command_then_empty, b'I', &[]);
-        push_ready_for_query(&mut command_then_empty);
-        assert_other_error_contains(
-            parse_query_response_bytes(&command_then_empty),
-            "EmptyQueryResponse after CommandComplete",
-        );
-
-        let mut empty_then_command = Vec::new();
-        push_backend_message(&mut empty_then_command, b'I', &[]);
-        push_command_complete(&mut empty_then_command, "UPDATE 1");
-        push_ready_for_query(&mut empty_then_command);
-        assert_other_error_contains(
-            parse_command_response(&ProtocolResponse::new(empty_then_command)),
-            "CommandComplete after EmptyQueryResponse",
-        );
-
-        let mut duplicate_empty = Vec::new();
-        push_backend_message(&mut duplicate_empty, b'I', &[]);
-        push_backend_message(&mut duplicate_empty, b'I', &[]);
-        push_ready_for_query(&mut duplicate_empty);
-        assert_other_error_contains(
-            parse_query_response_bytes(&duplicate_empty),
-            "multiple EmptyQueryResponse",
-        );
-    }
-
-    #[test]
-    fn query_rejects_messages_after_completion_and_invalid_extended_order() {
-        let mut row_after_completion = Vec::new();
-        push_row_description(
-            &mut row_after_completion,
-            &[("answer", TypeOid::INT4.get())],
-        );
-        push_command_complete(&mut row_after_completion, "SELECT 0");
-        push_data_row(&mut row_after_completion, &[Some("42")]);
-        push_ready_for_query(&mut row_after_completion);
-        assert_other_error_contains(
-            parse_query_response_bytes(&row_after_completion),
-            "DataRow after statement completion",
-        );
-
-        let mut parse_after_completion = Vec::new();
-        push_command_complete(&mut parse_after_completion, "UPDATE 1");
-        push_backend_message(&mut parse_after_completion, b'1', &[]);
-        push_ready_for_query(&mut parse_after_completion);
-        assert_other_error_contains(
-            parse_query_response_bytes(&parse_after_completion),
-            "ParseComplete out of order",
-        );
-
-        let mut bind_before_parse = Vec::new();
-        push_backend_message(&mut bind_before_parse, b'2', &[]);
-        push_backend_message(&mut bind_before_parse, b'n', &[]);
-        push_command_complete(&mut bind_before_parse, "UPDATE 1");
-        push_ready_for_query(&mut bind_before_parse);
-        assert_other_error_contains(
-            parse_query_response_bytes(&bind_before_parse),
-            "BindComplete out of order",
-        );
-
-        let mut error_after_command = Vec::new();
-        push_command_complete(&mut error_after_command, "UPDATE 1");
-        push_error_response(&mut error_after_command, "ERROR", "XX000", "too late");
-        push_ready_for_query(&mut error_after_command);
-        assert_other_error_contains(
-            parse_query_response_bytes(&error_after_command),
-            "ErrorResponse after statement completion",
-        );
-
-        let mut error_after_empty = Vec::new();
-        push_backend_message(&mut error_after_empty, b'I', &[]);
-        push_error_response(&mut error_after_empty, "ERROR", "XX000", "too late");
-        push_ready_for_query(&mut error_after_empty);
-        assert_other_error_contains(
-            parse_command_response(&ProtocolResponse::new(error_after_empty)),
-            "ErrorResponse after statement completion",
-        );
-
-        let mut close_complete = Vec::new();
-        push_backend_message(&mut close_complete, b'3', &[]);
-        push_command_complete(&mut close_complete, "UPDATE 1");
-        push_ready_for_query(&mut close_complete);
-        assert_other_error_contains(
-            parse_query_response_bytes(&close_complete),
-            "unexpected backend message tag 0x33",
-        );
-        assert_other_error_contains(
-            parse_command_response(&ProtocolResponse::new(close_complete)),
-            "unexpected backend message tag 0x33",
-        );
-    }
-
-    #[test]
-    fn exec_accepts_but_omits_empty_statements_and_requires_a_completion() {
-        let mut bytes = Vec::new();
-        push_backend_message(&mut bytes, b'I', &[]);
-        push_command_complete(&mut bytes, "UPDATE 1");
-        push_backend_message(&mut bytes, b'I', &[]);
-        push_ready_for_query(&mut bytes);
-
-        let result = parse_exec_response(&ProtocolResponse::new(bytes)).unwrap();
-        assert_eq!(result.statements().len(), 1);
-        assert!(matches!(
-            &result.statements()[0],
-            StatementResult::Command(command) if command.command_tag() == Some("UPDATE 1")
-        ));
-
-        let mut empty = Vec::new();
-        push_backend_message(&mut empty, b'I', &[]);
-        push_ready_for_query(&mut empty);
-        assert!(
-            parse_exec_response(&ProtocolResponse::new(empty))
-                .unwrap()
-                .statements()
-                .is_empty()
-        );
-
-        let mut ready_only = Vec::new();
-        push_ready_for_query(&mut ready_only);
-        assert_other_error_contains(
-            parse_exec_response(&ProtocolResponse::new(ready_only)),
-            "before CommandComplete or EmptyQueryResponse",
-        );
-
-        for tag in [b'1', b'2', b'3', b't', b'n'] {
-            let mut extended_control = Vec::new();
-            push_backend_message(&mut extended_control, tag, &[]);
-            push_command_complete(&mut extended_control, "UPDATE 1");
-            push_ready_for_query(&mut extended_control);
-            assert_other_error_contains(
-                parse_exec_response(&ProtocolResponse::new(extended_control)),
-                "unexpected backend message tag",
-            );
-        }
-    }
-
-    #[test]
-    fn describe_returns_parameter_oids_fields_and_notices() {
-        let mut bytes = Vec::new();
-        push_backend_message(&mut bytes, b'1', &[]);
-        push_parameter_description(&mut bytes, &[TypeOid::INT4, TypeOid::TEXT]);
-        push_notice_response(&mut bytes, "NOTICE", "described");
-        push_row_description(&mut bytes, &[("answer", TypeOid::INT8.get())]);
-        push_ready_for_query(&mut bytes);
-
-        let description = parse_statement_description(&ProtocolResponse::new(bytes)).unwrap();
-        assert_eq!(
-            description.parameter_types(),
-            &[TypeOid::INT4, TypeOid::TEXT]
-        );
-        assert_eq!(
-            description.fields().unwrap()[0].type_oid_value(),
-            TypeOid::INT8
-        );
-        assert_eq!(description.notices()[0].message, "described");
-    }
-
-    #[test]
-    fn describe_requires_parse_complete_and_protocol_order() {
-        let mut ready_only = Vec::new();
-        push_ready_for_query(&mut ready_only);
-        assert_other_error_contains(
-            parse_statement_description(&ProtocolResponse::new(ready_only)),
-            "omitted ParseComplete",
-        );
-
-        let mut parameter_before_parse = Vec::new();
-        push_parameter_description(&mut parameter_before_parse, &[]);
-        push_backend_message(&mut parameter_before_parse, b'1', &[]);
-        push_backend_message(&mut parameter_before_parse, b'n', &[]);
-        push_ready_for_query(&mut parameter_before_parse);
-        assert_other_error_contains(
-            parse_statement_description(&ProtocolResponse::new(parameter_before_parse)),
-            "ParameterDescription out of order",
-        );
-
-        let mut duplicate_parse = Vec::new();
-        push_backend_message(&mut duplicate_parse, b'1', &[]);
-        push_backend_message(&mut duplicate_parse, b'1', &[]);
-        push_parameter_description(&mut duplicate_parse, &[]);
-        push_backend_message(&mut duplicate_parse, b'n', &[]);
-        push_ready_for_query(&mut duplicate_parse);
-        assert_other_error_contains(
-            parse_statement_description(&ProtocolResponse::new(duplicate_parse)),
-            "ParseComplete out of order",
-        );
-
-        let mut result_before_parameters = Vec::new();
-        push_backend_message(&mut result_before_parameters, b'1', &[]);
-        push_row_description(
-            &mut result_before_parameters,
-            &[("answer", TypeOid::INT4.get())],
-        );
-        push_parameter_description(&mut result_before_parameters, &[]);
-        push_ready_for_query(&mut result_before_parameters);
-        assert_other_error_contains(
-            parse_statement_description(&ProtocolResponse::new(result_before_parameters)),
-            "RowDescription out of order",
-        );
-
-        let mut error_after_result = Vec::new();
-        push_backend_message(&mut error_after_result, b'1', &[]);
-        push_parameter_description(&mut error_after_result, &[]);
-        push_backend_message(&mut error_after_result, b'n', &[]);
-        push_error_response(&mut error_after_result, "ERROR", "XX000", "too late");
-        push_ready_for_query(&mut error_after_result);
-        assert_other_error_contains(
-            parse_statement_description(&ProtocolResponse::new(error_after_result)),
-            "ErrorResponse after result description",
-        );
-    }
-
-    #[test]
-    fn returns_query_cancellation_as_structured_postgres_error() {
-        let mut bytes = Vec::new();
-        push_error_response(
-            &mut bytes,
-            "ERROR",
-            "57014",
-            "canceling statement due to user request",
-        );
-        push_ready_for_query(&mut bytes);
-
-        let error = parse_query_response_bytes(&bytes).unwrap_err();
-        assert_eq!(error.kind(), crate::error::ErrorKind::Postgres);
-        let postgres = error
-            .postgres_error()
-            .expect("Postgres errors expose structured cancellation diagnostics");
-        assert_eq!(postgres.severity.as_deref(), Some("ERROR"));
-        assert_eq!(postgres.sqlstate.as_deref(), Some("57014"));
-        assert_eq!(postgres.message, "canceling statement due to user request");
-    }
-
-    #[test]
-    fn rejects_invalid_utf8_in_backend_cstrings() {
-        let mut bytes = Vec::new();
-        push_raw_row_description(&mut bytes, &[(&[0xff], 25)]);
-        push_ready_for_query(&mut bytes);
-
-        assert_other_error_contains(
-            parse_query_response_bytes(&bytes),
-            "field name is not valid UTF-8",
-        );
-    }
-
-    #[test]
-    fn text_accessors_reject_invalid_utf8_values() {
-        let mut bytes = Vec::new();
-        push_row_description(&mut bytes, &[("value", 25)]);
-        push_data_row_raw(&mut bytes, &[Some(&[0xff])]);
-        push_command_complete(&mut bytes, "SELECT 1");
-        push_ready_for_query(&mut bytes);
-
-        let result = parse_query_response_bytes(&bytes).unwrap();
-        assert_other_error_contains(
-            result.get_text(0, "value"),
-            "query value is not valid UTF-8",
-        );
-    }
-
-    #[test]
-    fn rejects_multiple_result_sets() {
-        let mut bytes = Vec::new();
-        push_row_description(&mut bytes, &[("one", 23)]);
-        push_data_row(&mut bytes, &[Some("1")]);
-        push_command_complete(&mut bytes, "SELECT 1");
-        push_row_description(&mut bytes, &[("two", 23)]);
-        push_data_row(&mut bytes, &[Some("2")]);
-        push_command_complete(&mut bytes, "SELECT 1");
-        push_ready_for_query(&mut bytes);
-
-        assert_other_error_contains(parse_query_response_bytes(&bytes), "multiple result sets");
-    }
-
-    #[test]
-    fn accepts_extended_query_control_messages() {
-        let mut bytes = Vec::new();
-        push_backend_message(&mut bytes, b'1', &[]);
-        push_backend_message(&mut bytes, b'2', &[]);
-        push_backend_message(&mut bytes, b'n', &[]);
-        push_command_complete(&mut bytes, "INSERT 0 0");
-        push_ready_for_query(&mut bytes);
-
-        let result = parse_query_response_bytes(&bytes).unwrap();
-        assert!(result.fields().is_empty());
-        assert!(result.rows().is_empty());
-        assert_eq!(result.command_tag(), Some("INSERT 0 0"));
-    }
-
-    #[test]
-    fn accepts_backend_async_control_messages() {
-        let mut bytes = Vec::new();
-        push_parameter_status(&mut bytes, "client_encoding", "UTF8");
-        push_notice_response(&mut bytes, "NOTICE", "hello");
-        push_notification_response(&mut bytes, 123, "channel", "payload");
-        push_command_complete(&mut bytes, "SELECT 0");
-        push_ready_for_query(&mut bytes);
-
-        let result = parse_query_response_bytes(&bytes).unwrap();
-        assert_eq!(result.command_tag(), Some("SELECT 0"));
-    }
-
-    #[test]
-    fn rejects_malformed_empty_control_messages() {
-        let mut bytes = Vec::new();
-        push_backend_message(&mut bytes, b'1', &[0]);
-        push_ready_for_query(&mut bytes);
-
-        assert_other_error_contains(
-            parse_query_response_bytes(&bytes),
-            "ParseComplete contained trailing bytes",
-        );
-    }
-
-    #[test]
-    fn rejects_malformed_async_control_messages() {
-        let mut malformed_parameter = Vec::new();
-        push_backend_message(&mut malformed_parameter, b'S', b"client_encoding\0");
-        push_ready_for_query(&mut malformed_parameter);
-        assert_other_error_contains(
-            parse_query_response_bytes(&malformed_parameter),
-            "ParameterStatus value is missing null terminator",
-        );
-
-        let mut malformed_notice = Vec::new();
-        push_backend_message(&mut malformed_notice, b'N', b"SNOTICE\0");
-        push_ready_for_query(&mut malformed_notice);
-        assert_other_error_contains(
-            parse_query_response_bytes(&malformed_notice),
-            "NoticeResponse is missing terminator",
-        );
-
-        let mut malformed_notification = Vec::new();
-        let mut body = 123_i32.to_be_bytes().to_vec();
-        body.extend_from_slice(b"channel");
-        push_backend_message(&mut malformed_notification, b'A', &body);
-        push_ready_for_query(&mut malformed_notification);
-        assert_other_error_contains(
-            parse_query_response_bytes(&malformed_notification),
-            "NotificationResponse channel is missing null terminator",
-        );
-    }
-
-    #[test]
-    fn rejects_unexpected_backend_message_tags() {
-        let mut bytes = Vec::new();
-        push_backend_message(&mut bytes, b'R', &[0, 0, 0, 0]);
-        push_ready_for_query(&mut bytes);
-
-        assert_other_error_contains(
-            parse_query_response_bytes(&bytes),
-            "unexpected backend message tag 0x52",
-        );
-    }
-
-    #[test]
-    fn backend_parser_is_panic_free_for_deterministic_malformed_input() {
-        use std::panic::{AssertUnwindSafe, catch_unwind};
-
-        let mut state = 0x6f6c_6970_6861_756e_u64;
-        for case in 0..1_000 {
-            state = state
-                .wrapping_mul(6_364_136_223_846_793_005)
-                .wrapping_add(1);
-            let len = (state as usize) % 384;
-            let mut bytes = Vec::with_capacity(len);
-            for _ in 0..len {
-                state = state
-                    .wrapping_mul(6_364_136_223_846_793_005)
-                    .wrapping_add(1);
-                bytes.push((state >> 56) as u8);
-            }
-            if bytes.len() >= 5 && case % 4 == 0 {
-                bytes[0] = [b'T', b'D', b'C', b'E', b'Z', b'S', b'N', b'A'][case % 8];
-                let declared = ((state as usize % 256) as i32) - 32;
-                bytes[1..5].copy_from_slice(&declared.to_be_bytes());
-            }
-
-            assert!(
-                catch_unwind(AssertUnwindSafe(|| parse_query_response_bytes(&bytes))).is_ok(),
-                "backend parser panicked for deterministic case {case}"
-            );
-        }
-    }
-
-    #[test]
-    fn rejects_copy_and_bytes_after_ready_for_query() {
-        let mut copy = Vec::new();
-        push_backend_message(&mut copy, b'G', &[0, 0, 0]);
-        assert_other_error_contains(parse_query_response_bytes(©), "does not support COPY");
-
-        let mut trailing = Vec::new();
-        push_command_complete(&mut trailing, "SELECT 0");
-        push_ready_for_query(&mut trailing);
-        trailing.push(0);
-        assert_other_error_contains(
-            parse_query_response_bytes(&trailing),
-            "bytes after ReadyForQuery",
-        );
-    }
-
-    #[test]
-    fn accepts_ready_for_query_transaction_states() {
-        for status in [b'I', b'T', b'E'] {
-            let mut bytes = Vec::new();
-            push_command_complete(&mut bytes, "SELECT 0");
-            push_backend_message(&mut bytes, b'Z', &[status]);
-
-            let result = parse_query_response_bytes(&bytes).unwrap();
-            assert_eq!(result.command_tag(), Some("SELECT 0"));
-        }
-    }
-
-    #[test]
-    fn rejects_malformed_ready_for_query_status() {
-        let mut missing = Vec::new();
-        push_backend_message(&mut missing, b'Z', &[]);
-        assert_other_error_contains(
-            parse_query_response_bytes(&missing),
-            "ReadyForQuery contained 0 bytes, expected 1",
-        );
-
-        let mut invalid = Vec::new();
-        push_backend_message(&mut invalid, b'Z', &[0]);
-        assert_other_error_contains(
-            parse_query_response_bytes(&invalid),
-            "ReadyForQuery contained invalid transaction status 0x00",
-        );
-    }
-
-    #[test]
-    fn builds_extended_query_protocol_request() {
-        let params = [
-            7_i32.into_parameter(),
-            Some("hello").into_parameter(),
-            Parameter::binary([0_u8, 1, 2]),
-            None::<&str>.into_parameter(),
-        ];
-        let request = extended_statement_request(
-            "SELECT $1::int4, $2::text, $3::bytea, $4::text",
-            ¶ms,
-            ValueFormat::Text,
-        )
-        .unwrap();
-
-        assert_eq!(
-            frontend_message_tags(request.as_bytes()),
-            vec![b'P', b'B', b'D', b'E', b'S']
-        );
-        assert!(
-            request
-                .as_bytes()
-                .windows(b"hello".len())
-                .any(|window| window == b"hello")
-        );
-        assert!(
-            request
-                .as_bytes()
-                .windows([0_u8, 1, 2].len())
-                .any(|window| window == [0_u8, 1, 2])
-        );
-    }
-
-    #[test]
-    fn typed_parameters_encode_parse_oids_formats_nulls_and_result_format() {
-        let params = [
-            Parameter::typed_null(TypeOid::INT4),
-            7_i32.into_parameter(),
-            Parameter::text("hello"),
-        ];
-        let request =
-            extended_statement_request("SELECT $1, $2, $3", ¶ms, ValueFormat::Binary).unwrap();
-        let messages = frontend_messages(request.as_bytes());
-        assert_eq!(
-            messages.iter().map(|(tag, _)| *tag).collect::>(),
-            vec![b'P', b'B', b'D', b'E', b'S']
-        );
-
-        let mut parse = messages[0].1;
-        assert_eq!(read_cstring(&mut parse, "statement").unwrap(), "");
-        assert_eq!(
-            read_cstring(&mut parse, "SQL").unwrap(),
-            "SELECT $1, $2, $3"
-        );
-        assert_eq!(read_i16(&mut parse, "OID count").unwrap(), 3);
-        assert_eq!(read_u32(&mut parse, "OID").unwrap(), TypeOid::INT4.get());
-        assert_eq!(read_u32(&mut parse, "OID").unwrap(), TypeOid::INT4.get());
-        assert_eq!(read_u32(&mut parse, "OID").unwrap(), 0);
-        assert!(parse.is_empty());
-
-        let mut bind = messages[1].1;
-        assert_eq!(read_cstring(&mut bind, "portal").unwrap(), "");
-        assert_eq!(read_cstring(&mut bind, "statement").unwrap(), "");
-        assert_eq!(read_i16(&mut bind, "format count").unwrap(), 3);
-        assert_eq!(read_i16(&mut bind, "format").unwrap(), 0);
-        assert_eq!(read_i16(&mut bind, "format").unwrap(), 1);
-        assert_eq!(read_i16(&mut bind, "format").unwrap(), 0);
-        assert_eq!(read_i16(&mut bind, "value count").unwrap(), 3);
-        assert_eq!(read_i32(&mut bind, "null length").unwrap(), -1);
-        assert_eq!(read_i32(&mut bind, "int length").unwrap(), 4);
-        assert_eq!(take(&mut bind, 4, "int").unwrap(), &7_i32.to_be_bytes());
-        assert_eq!(read_i32(&mut bind, "text length").unwrap(), 5);
-        assert_eq!(take(&mut bind, 5, "text").unwrap(), b"hello");
-        assert_eq!(read_i16(&mut bind, "result format count").unwrap(), 1);
-        assert_eq!(read_i16(&mut bind, "result format").unwrap(), 1);
-        assert!(bind.is_empty());
-    }
-
-    #[test]
-    fn explicit_oid_zero_is_describe_only() {
-        let parameter = Parameter::typed_text(TypeOid::new(0), "infer me");
-        assert_other_error_contains(
-            extended_statement_request(
-                "SELECT $1",
-                std::slice::from_ref(¶meter),
-                ValueFormat::Text,
-            ),
-            "explicitly declares PostgreSQL type OID 0",
-        );
-
-        let request = describe_statement_request("SELECT $1", &[parameter])
-            .expect("describe permits OID 0 as PostgreSQL inference");
-        let messages = frontend_messages(request.as_bytes());
-        let mut parse = messages[0].1;
-        assert_eq!(read_cstring(&mut parse, "statement").unwrap(), "");
-        assert_eq!(read_cstring(&mut parse, "SQL").unwrap(), "SELECT $1");
-        assert_eq!(read_i16(&mut parse, "OID count").unwrap(), 1);
-        assert_eq!(read_u32(&mut parse, "OID").unwrap(), 0);
-    }
-
-    #[test]
-    fn structured_sql_preflight_matches_shared_corpus() {
-        let source = crate::test_fixtures::text("protocol/structured-sql-cases.json");
-        let fixture: serde_json::Value =
-            serde_json::from_str(&source).expect("structured SQL fixture is valid JSON");
-        assert_eq!(fixture["schemaVersion"], 2);
-        for case in fixture["cases"].as_array().expect("fixture cases") {
-            let name = case["name"].as_str().expect("case name");
-            let sql = case["sql"].as_str().expect("case SQL");
-            let expected = case["containsTopLevelCopy"]
-                .as_bool()
-                .expect("COPY expectation");
-            assert_eq!(reject_copy_statements(sql).is_err(), expected, "{name}");
-            let expected = case["containsTransactionChain"]
-                .as_bool()
-                .expect("transaction-chain expectation");
-            assert_eq!(reject_transaction_chain(sql).is_err(), expected, "{name}");
-        }
-    }
-
-    #[test]
-    fn managed_transaction_wire_classifier_uses_command_tags_and_final_readiness() {
-        fn response(tags: &[&str], ready: u8) -> ProtocolResponse {
-            let mut bytes = Vec::new();
-            for tag in tags {
-                push_command_complete(&mut bytes, tag);
-            }
-            push_backend_message(&mut bytes, b'Z', &[ready]);
-            ProtocolResponse::new(bytes)
-        }
-
-        for tag in [
-            "BEGIN",
-            "START TRANSACTION",
-            "COMMIT",
-            "PREPARE TRANSACTION",
-            "COMMIT PREPARED",
-            "ROLLBACK PREPARED",
-        ] {
-            assert!(
-                validate_managed_transaction_response(&response(&[tag], b'T')).is_err(),
-                "{tag} changes transaction ownership"
-            );
-        }
-        assert!(validate_managed_transaction_response(&response(&["ROLLBACK"], b'I')).is_err());
-        assert!(
-            validate_managed_transaction_response(&response(&["COMMIT", "BEGIN"], b'T')).is_err()
-        );
-        for tags in [
-            &["ROLLBACK"][..],
-            &["SAVEPOINT"][..],
-            &["RELEASE"][..],
-            &["SET"][..],
-            &["PREPARE"][..],
-            &["CREATE FUNCTION"][..],
-            &["CALL"][..],
-            &["DO"][..],
-        ] {
-            validate_managed_transaction_response(&response(tags, b'T'))
-                .expect("ordinary or savepoint-preserving command remains managed");
-        }
-
-        let mut malformed = Vec::new();
-        push_backend_message(&mut malformed, b'C', b"COMMIT");
-        push_backend_message(&mut malformed, b'Z', b"T");
-        assert!(validate_managed_transaction_response(&ProtocolResponse::new(malformed)).is_err());
-    }
-
-    #[test]
-    fn describe_allows_copy_because_it_does_not_execute() {
-        describe_statement_request("COPY public.items TO STDOUT", &[])
-            .expect("Parse + Describe + Sync cannot enter COPY mode");
-    }
-
-    #[test]
-    fn rejects_nul_in_extended_query_sql() {
-        let params = [Parameter::null()];
-        assert_other_error_contains(
-            extended_statement_request("SELECT '\0'", ¶ms, ValueFormat::Text),
-            "extended query SQL must not contain NUL bytes",
-        );
-    }
-
-    #[test]
-    fn rejects_too_many_extended_query_parameters() {
-        let params = vec![Parameter::null(); i16::MAX as usize + 1];
-
-        assert_other_error_contains(
-            extended_statement_request("SELECT 1", ¶ms, ValueFormat::Text),
-            &format!(
-                "extended query supports at most {} parameters, got {}",
-                i16::MAX,
-                i16::MAX as usize + 1,
-            ),
-        );
-    }
-
-    fn frontend_message_tags(mut bytes: &[u8]) -> Vec {
-        let mut tags = Vec::new();
-        while bytes.len() >= 5 {
-            let tag = bytes[0];
-            let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
-            if len < 4 {
-                break;
-            }
-            let total = 1 + len as usize;
-            if bytes.len() < total {
-                break;
-            }
-            tags.push(tag);
-            bytes = &bytes[total..];
-        }
-        tags
-    }
-
-    fn frontend_messages(mut bytes: &[u8]) -> Vec<(u8, &[u8])> {
-        let mut messages = Vec::new();
-        while !bytes.is_empty() {
-            assert!(bytes.len() >= 5, "complete frontend message header");
-            let tag = bytes[0];
-            let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
-            assert!(len >= 4, "valid frontend message length");
-            let total = 1 + len as usize;
-            assert!(bytes.len() >= total, "complete frontend message body");
-            messages.push((tag, &bytes[5..total]));
-            bytes = &bytes[total..];
-        }
-        messages
-    }
-
-    fn test_field(name: &str, type_oid: TypeOid, format: QueryFormat) -> QueryField {
-        QueryField {
-            name: name.to_owned(),
-            table_oid: 0,
-            table_attribute: 0,
-            type_oid: type_oid.get(),
-            type_size: -1,
-            type_modifier: -1,
-            format,
-        }
-    }
-
-    fn push_backend_message(bytes: &mut Vec, tag: u8, body: &[u8]) {
-        bytes.push(tag);
-        bytes.extend_from_slice(&((body.len() + 4) as i32).to_be_bytes());
-        bytes.extend_from_slice(body);
-    }
-
-    fn push_row_description(bytes: &mut Vec, fields: &[(&str, u32)]) {
-        let fields = fields
-            .iter()
-            .map(|(name, type_oid)| (name.as_bytes(), *type_oid))
-            .collect::>();
-        push_raw_row_description(bytes, &fields);
-    }
-
-    fn push_raw_row_description(bytes: &mut Vec, fields: &[(&[u8], u32)]) {
-        let mut body = Vec::new();
-        body.extend_from_slice(&(fields.len() as i16).to_be_bytes());
-        for (name, type_oid) in fields {
-            body.extend_from_slice(name);
-            body.push(0);
-            body.extend_from_slice(&0_u32.to_be_bytes());
-            body.extend_from_slice(&0_i16.to_be_bytes());
-            body.extend_from_slice(&type_oid.to_be_bytes());
-            body.extend_from_slice(&(-1_i16).to_be_bytes());
-            body.extend_from_slice(&(-1_i32).to_be_bytes());
-            body.extend_from_slice(&0_i16.to_be_bytes());
-        }
-        push_backend_message(bytes, b'T', &body);
-    }
-
-    fn push_data_row(bytes: &mut Vec, values: &[Option<&str>]) {
-        let values = values
-            .iter()
-            .map(|value| value.map(str::as_bytes))
-            .collect::>();
-        push_data_row_raw(bytes, &values);
-    }
-
-    fn push_parameter_description(bytes: &mut Vec, types: &[TypeOid]) {
-        let mut body = Vec::new();
-        body.extend_from_slice(&(types.len() as i16).to_be_bytes());
-        for type_oid in types {
-            body.extend_from_slice(&type_oid.get().to_be_bytes());
-        }
-        push_backend_message(bytes, b't', &body);
-    }
-
-    fn push_data_row_raw(bytes: &mut Vec, values: &[Option<&[u8]>]) {
-        let mut body = Vec::new();
-        body.extend_from_slice(&(values.len() as i16).to_be_bytes());
-        for value in values {
-            match value {
-                Some(value) => {
-                    body.extend_from_slice(&(value.len() as i32).to_be_bytes());
-                    body.extend_from_slice(value);
-                }
-                None => body.extend_from_slice(&(-1_i32).to_be_bytes()),
-            }
-        }
-        push_backend_message(bytes, b'D', &body);
-    }
-
-    fn push_command_complete(bytes: &mut Vec, tag: &str) {
-        let mut body = Vec::new();
-        body.extend_from_slice(tag.as_bytes());
-        body.push(0);
-        push_backend_message(bytes, b'C', &body);
-    }
-
-    fn push_error_response(bytes: &mut Vec, severity: &str, sqlstate: &str, message: &str) {
-        let mut body = Vec::new();
-        body.push(b'S');
-        body.extend_from_slice(severity.as_bytes());
-        body.push(0);
-        body.push(b'C');
-        body.extend_from_slice(sqlstate.as_bytes());
-        body.push(0);
-        body.push(b'M');
-        body.extend_from_slice(message.as_bytes());
-        body.push(0);
-        body.push(0);
-        push_backend_message(bytes, b'E', &body);
-    }
-
-    fn push_notice_response(bytes: &mut Vec, severity: &str, message: &str) {
-        let mut body = Vec::new();
-        body.push(b'S');
-        body.extend_from_slice(severity.as_bytes());
-        body.push(0);
-        body.push(b'M');
-        body.extend_from_slice(message.as_bytes());
-        body.push(0);
-        body.push(0);
-        push_backend_message(bytes, b'N', &body);
-    }
-
-    fn push_parameter_status(bytes: &mut Vec, name: &str, value: &str) {
-        let mut body = Vec::new();
-        body.extend_from_slice(name.as_bytes());
-        body.push(0);
-        body.extend_from_slice(value.as_bytes());
-        body.push(0);
-        push_backend_message(bytes, b'S', &body);
-    }
-
-    fn push_notification_response(bytes: &mut Vec, pid: i32, channel: &str, payload: &str) {
-        let mut body = Vec::new();
-        body.extend_from_slice(&pid.to_be_bytes());
-        body.extend_from_slice(channel.as_bytes());
-        body.push(0);
-        body.extend_from_slice(payload.as_bytes());
-        body.push(0);
-        push_backend_message(bytes, b'A', &body);
-    }
-
-    fn push_ready_for_query(bytes: &mut Vec) {
-        push_backend_message(bytes, b'Z', b"I");
-    }
-}
diff --git a/src/sdks/rust/src/server.rs b/src/sdks/rust/src/server.rs
deleted file mode 100644
index b5fd2cb49..000000000
--- a/src/sdks/rust/src/server.rs
+++ /dev/null
@@ -1,981 +0,0 @@
-use std::ffi::OsString;
-use std::fs;
-use std::net::{SocketAddr, TcpListener};
-#[cfg(unix)]
-use std::os::unix::fs::PermissionsExt;
-use std::path::{Path, PathBuf};
-use std::process::{Child, Command, Stdio};
-use std::thread;
-use std::time::{Duration, Instant};
-#[cfg(unix)]
-use std::time::{SystemTime, UNIX_EPOCH};
-
-use crate::child_process::reap_child_process;
-#[cfg(unix)]
-use crate::config::server_unix_socket_directory_str;
-use crate::config::{EngineMode, NativeServerConfig, OpenConfig, ServerListen};
-use crate::engine::{EngineSession, NativeRuntime};
-use crate::error::{Error, Result};
-use crate::extension::{Extension, extension_runtime_environment};
-use crate::liboliphaunt::{PreparedNativeRoot, configure_native_tool_env};
-use crate::pgwire::{PostgresEndpoint, PostgresWireClient};
-use crate::protocol::{ProtocolRequest, ProtocolResponse};
-
-const SERVER_HOST: &str = "127.0.0.1";
-#[cfg(unix)]
-const ENV_SERVER_SDK_TRANSPORT: &str = "OLIPHAUNT_SERVER_SDK_TRANSPORT";
-const STARTUP_TIMEOUT: Duration = Duration::from_secs(20);
-const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
-const CONNECT_ATTEMPT_TIMEOUT: Duration = Duration::from_millis(250);
-const AUTO_PORT_START_ATTEMPTS: usize = 16;
-
-/// Native PostgreSQL server runtime.
-///
-/// Server mode starts and owns a real local PostgreSQL-compatible server
-/// process. It is the mode to use for independent client connections, external
-/// PostgreSQL clients, pools, and ORMs.
-#[derive(Debug, Clone, Default)]
-pub(crate) struct NativeServerRuntime {
-    executable: Option,
-    listen: ServerListen,
-}
-
-impl NativeServerRuntime {
-    /// Create a server runtime from builder/server configuration.
-    pub fn from_config(config: &NativeServerConfig) -> Self {
-        Self {
-            executable: config.executable.clone(),
-            listen: config.listen.clone(),
-        }
-    }
-}
-
-impl NativeRuntime for NativeServerRuntime {
-    fn open(&self, config: OpenConfig) -> Result> {
-        debug_assert_eq!(config.mode, EngineMode::Server);
-        config.validate()?;
-        let extensions = config.resolved_extensions()?;
-        let explicit_executable = self
-            .executable
-            .clone()
-            .or_else(|| config.server.executable.clone());
-        if let Some(executable) = explicit_executable.as_ref()
-            && !executable.is_file()
-        {
-            return Err(Error::InvalidConfig(format!(
-                "native server executable must be an existing file: {}",
-                executable.display()
-            )));
-        }
-        let root = PreparedNativeRoot::prepare_for_server(&config, &extensions)?;
-        let executable = explicit_executable.unwrap_or_else(|| root.tool_path("postgres"));
-        let listen = self.listen.clone();
-        let fixed_port = match &listen {
-            ServerListen::Tcp { port } => *port,
-            #[cfg(unix)]
-            ServerListen::Unix { port, .. } => Some(*port),
-        };
-        let attempts = if fixed_port.is_some() {
-            1
-        } else {
-            AUTO_PORT_START_ATTEMPTS
-        };
-        let mut last_error = None;
-        for attempt in 0..attempts {
-            let port = match fixed_port {
-                Some(port) => port,
-                None => pick_port()?,
-            };
-            let (process_listen, sdk_endpoint, connection_string, mut owned_socket_dir) =
-                prepare_server_listen(&listen, &config, port)?;
-            let mut child =
-                match start_postgres(&root, &executable, &config, &extensions, &process_listen) {
-                    Ok(child) => child,
-                    Err(error) => {
-                        let mut cleanup_failures = Vec::new();
-                        remove_owned_socket_dir(&mut owned_socket_dir, &mut cleanup_failures);
-                        return Err(failed_start_error(error, cleanup_failures));
-                    }
-                };
-            match wait_for_server(sdk_endpoint, &mut child, &config) {
-                Ok(()) => {
-                    return Ok(Box::new(NativeServerSession {
-                        root: Some(root),
-                        child: Some(child),
-                        connection_string,
-                        owned_socket_dir,
-                        retain_root_on_drop: false,
-                        closed: false,
-                    }));
-                }
-                Err(error) => {
-                    let (reaped, cleanup_failures) =
-                        cleanup_failed_start(&mut child, &mut owned_socket_dir);
-                    if !reaped {
-                        // The process may still be using PGDATA and its socket.
-                        // Retain resources with ownership-bearing destructors
-                        // rather than unlock PGDATA beneath a live backend.
-                        // Dropping the socket PathBuf does not delete it.
-                        std::mem::forget(child);
-                        std::mem::forget(root);
-                        return Err(failed_start_error(error, cleanup_failures));
-                    }
-                    if !cleanup_failures.is_empty() {
-                        return Err(failed_start_error(error, cleanup_failures));
-                    }
-                    let retry_auto_port = fixed_port.is_none()
-                        && attempt + 1 < attempts
-                        && tcp_port_is_occupied(port);
-                    if retry_auto_port {
-                        last_error = Some(error);
-                    } else {
-                        return Err(error);
-                    }
-                }
-            }
-        }
-        Err(last_error.unwrap_or_else(|| {
-            Error::Engine(format!(
-                "native server failed to allocate a free localhost port after {attempts} attempts"
-            ))
-        }))
-    }
-}
-
-struct NativeServerSession {
-    root: Option,
-    child: Option,
-    connection_string: String,
-    owned_socket_dir: Option,
-    retain_root_on_drop: bool,
-    closed: bool,
-}
-
-impl EngineSession for NativeServerSession {
-    fn connection_string(&self) -> Option {
-        Some(self.connection_string.clone())
-    }
-
-    fn exec_protocol_raw(&mut self, _request: ProtocolRequest) -> Result {
-        Err(Error::Engine(
-            "native server lifecycle handles do not expose an SDK query connection; connect an ordinary PostgreSQL client to connection_string()"
-                .to_owned(),
-        ))
-    }
-
-    fn close(&mut self) -> Result<()> {
-        self.close_server()
-    }
-}
-
-impl NativeServerSession {
-    fn close_server(&mut self) -> Result<()> {
-        let first_attempt = !self.closed;
-        self.closed = true;
-        let mut cleanup_failures = Vec::new();
-        if first_attempt {
-            let root = self
-                .root
-                .as_ref()
-                .expect("native server session retains its prepared root");
-            let pg_ctl = root.tool_path("pg_ctl");
-            if pg_ctl.is_file() {
-                let mut command = Command::new(&pg_ctl);
-                configure_native_tool_env(&mut command, &root.runtime_dir);
-                let stop = command
-                    .arg("-D")
-                    .arg(&root.pgdata)
-                    .arg("-m")
-                    .arg("fast")
-                    .arg("-w")
-                    .arg("stop")
-                    .stdout(Stdio::null())
-                    .stderr(Stdio::null())
-                    .spawn();
-                match stop {
-                    Ok(mut child) => {
-                        let outcome = reap_child_process(
-                            &mut child,
-                            SHUTDOWN_TIMEOUT,
-                            SHUTDOWN_TIMEOUT,
-                            "pg_ctl stop",
-                        );
-                        cleanup_failures.extend(outcome.failures);
-                        if outcome.reaped {
-                            if outcome.exit_success == Some(false) {
-                                cleanup_failures
-                                    .push("pg_ctl stop exited unsuccessfully".to_owned());
-                            }
-                        } else {
-                            // No enclosing owner can safely retry an unconfirmed
-                            // pg_ctl child after this terminal close attempt.
-                            self.retain_root_on_drop = true;
-                            std::mem::forget(child);
-                        }
-                    }
-                    Err(err) => cleanup_failures.push(format!("run pg_ctl stop: {err}")),
-                }
-            } else {
-                cleanup_failures.push(format!(
-                    "native server shutdown requires pg_ctl at {}",
-                    pg_ctl.display()
-                ));
-            }
-        }
-
-        if let Some(child) = self.child.as_mut() {
-            let outcome = reap_child_process(
-                child,
-                SHUTDOWN_TIMEOUT,
-                SHUTDOWN_TIMEOUT,
-                "native server process",
-            );
-            cleanup_failures.extend(outcome.failures);
-            if outcome.reaped {
-                self.child = None;
-            }
-        }
-
-        if self.child.is_none()
-            && let Some(socket_dir) = self.owned_socket_dir.as_ref()
-        {
-            match fs::remove_dir_all(socket_dir) {
-                Ok(()) => self.owned_socket_dir = None,
-                Err(error) => cleanup_failures.push(format!(
-                    "remove native server socket directory {}: {error}",
-                    socket_dir.display()
-                )),
-            }
-        }
-        if !cleanup_failures.is_empty() {
-            return Err(Error::Engine(format!(
-                "native server cleanup failed: {}",
-                cleanup_failures.join("; ")
-            )));
-        }
-        Ok(())
-    }
-}
-
-impl Drop for NativeServerSession {
-    fn drop(&mut self) {
-        let close_failed = self.close_server().is_err();
-        let retain_root = self.retain_root_on_drop || self.child.is_some();
-        if close_failed {
-            // Drop is the last package-internal cleanup opportunity. Preserve
-            // every unresolved exact owner process-lifetime; in particular,
-            // never let PreparedNativeRoot unlock or delete PGDATA beneath an
-            // unconfirmed PostgreSQL/pg_ctl process.
-            if let Some(child) = self.child.take() {
-                std::mem::forget(child);
-            }
-        }
-        if retain_root && let Some(root) = self.root.take() {
-            std::mem::forget(root);
-        }
-    }
-}
-
-fn pick_port() -> Result {
-    let listener = TcpListener::bind((SERVER_HOST, 0))
-        .map_err(|err| Error::Engine(format!("allocate native server port: {err}")))?;
-    listener
-        .local_addr()
-        .map(|addr| addr.port())
-        .map_err(|err| Error::Engine(format!("read native server port: {err}")))
-}
-
-fn start_postgres(
-    root: &PreparedNativeRoot,
-    executable: &Path,
-    config: &OpenConfig,
-    extensions: &[Extension],
-    listen: &PostgresProcessListen,
-) -> Result {
-    if !executable.is_file() {
-        return Err(Error::Engine(format!(
-            "native server executable is missing at {}",
-            executable.display()
-        )));
-    }
-    let mut command = Command::new(executable);
-    command.env("PGDATA", &root.pgdata);
-    configure_native_runtime_env(&mut command, &root.runtime_dir, extensions);
-    command
-        .args(postgres_startup_args(
-            &root.pgdata,
-            config,
-            extensions,
-            listen,
-        )?)
-        .stdout(Stdio::null())
-        .stderr(Stdio::inherit());
-    command
-        .spawn()
-        .map_err(|err| Error::Engine(format!("start native server postgres: {err}")))
-}
-
-fn configure_native_runtime_env(
-    command: &mut Command,
-    runtime_dir: &Path,
-    extensions: &[Extension],
-) {
-    configure_native_tool_env(command, runtime_dir);
-    configure_icu_data_env(command, runtime_dir);
-    configure_extension_runtime_env(command, runtime_dir, extensions);
-}
-
-fn configure_icu_data_env(command: &mut Command, runtime_dir: &Path) {
-    command.env_remove("ICU_DATA");
-    let icu_data = runtime_dir.join("share/icu");
-    if icu_data.is_dir() {
-        command.env("ICU_DATA", icu_data);
-    }
-}
-
-fn configure_extension_runtime_env(
-    command: &mut Command,
-    runtime_dir: &Path,
-    extensions: &[Extension],
-) {
-    for extension in extensions {
-        for entry in extension_runtime_environment(*extension) {
-            let value = runtime_dir.join(entry.relative_path);
-            if value.join(entry.required_file).is_file() {
-                command.env(entry.name, value);
-            }
-        }
-    }
-}
-
-fn postgres_startup_args(
-    pgdata: &Path,
-    config: &OpenConfig,
-    extensions: &[Extension],
-    listen: &PostgresProcessListen,
-) -> Result> {
-    let (host, port, socket_dir) = match listen {
-        PostgresProcessListen::Tcp {
-            port,
-            private_socket_dir,
-        } => (SERVER_HOST, *port, private_socket_dir.as_deref()),
-        #[cfg(unix)]
-        PostgresProcessListen::Unix { directory, port } => ("", *port, Some(directory.as_path())),
-    };
-    let mut args = vec![
-        OsString::from("-D"),
-        pgdata.as_os_str().to_os_string(),
-        OsString::from("-h"),
-        OsString::from(host),
-        OsString::from("-p"),
-        OsString::from(port.to_string()),
-        OsString::from("-c"),
-        OsString::from("logging_collector=off"),
-        OsString::from("-c"),
-        OsString::from(if host.is_empty() {
-            "listen_addresses="
-        } else {
-            "listen_addresses=127.0.0.1"
-        }),
-    ];
-    #[cfg(unix)]
-    {
-        args.push(OsString::from("-c"));
-        let socket_dir = socket_dir.ok_or_else(|| {
-            Error::Engine("native server socket directory was not allocated".to_owned())
-        })?;
-        args.push(postgres_unix_socket_assignment(socket_dir)?);
-    }
-    #[cfg(not(unix))]
-    {
-        let _ = socket_dir;
-        args.push(OsString::from("-c"));
-        args.push(OsString::from("unix_socket_directories="));
-    }
-
-    for assignment in config.postgres_startup_assignments(extensions) {
-        args.push(OsString::from("-c"));
-        args.push(OsString::from(assignment));
-    }
-    Ok(args)
-}
-
-fn wait_for_server(
-    endpoint: PostgresEndpoint,
-    child: &mut Child,
-    config: &OpenConfig,
-) -> Result<()> {
-    let deadline = Instant::now() + STARTUP_TIMEOUT;
-    let mut last_error = None;
-    while Instant::now() < deadline {
-        if let Some(status) = child
-            .try_wait()
-            .map_err(|err| Error::Engine(format!("poll native server startup: {err}")))?
-        {
-            return Err(Error::Engine(format!(
-                "native server exited before accepting connections: {status}; PostgreSQL diagnostics were written to the parent process stderr"
-            )));
-        }
-        match PostgresWireClient::connect_endpoint(
-            endpoint.clone(),
-            &config.username,
-            &config.database,
-            CONNECT_ATTEMPT_TIMEOUT,
-            STARTUP_TIMEOUT,
-        ) {
-            Ok(mut connection) => {
-                connection.terminate()?;
-                return Ok(());
-            }
-            Err(err) => last_error = Some(err),
-        }
-        thread::sleep(Duration::from_millis(50));
-    }
-    Err(last_error.unwrap_or_else(|| {
-        Error::Engine(format!(
-            "native server did not accept SDK connections on {:?} within {:?}",
-            endpoint, STARTUP_TIMEOUT
-        ))
-    }))
-}
-
-fn tcp_connection_string(config: &OpenConfig, port: u16) -> String {
-    format!(
-        "postgresql://{}@{}:{}/{}?sslmode=disable",
-        percent_encode_connection_component(&config.username),
-        SERVER_HOST,
-        port,
-        percent_encode_connection_component(&config.database)
-    )
-}
-
-#[cfg(unix)]
-fn postgres_unix_socket_assignment(directory: &Path) -> Result {
-    let directory = server_unix_socket_directory_str(directory)?;
-    let mut assignment =
-        String::with_capacity(directory.len() + "unix_socket_directories=\"\"".len());
-    assignment.push_str("unix_socket_directories=\"");
-    for character in directory.chars() {
-        if character == '"' {
-            assignment.push('"');
-        }
-        assignment.push(character);
-    }
-    assignment.push('"');
-    Ok(assignment.into())
-}
-
-#[cfg(unix)]
-fn unix_connection_string(config: &OpenConfig, directory: &Path, port: u16) -> Result {
-    let directory = server_unix_socket_directory_str(directory)?;
-    Ok(format!(
-        "postgresql:///{database}?host={host}&port={port}&user={user}&sslmode=disable",
-        database = percent_encode_connection_component(&config.database),
-        host = percent_encode_connection_component(directory),
-        user = percent_encode_connection_component(&config.username),
-    ))
-}
-
-fn percent_encode_connection_component(value: &str) -> String {
-    let mut encoded = String::with_capacity(value.len());
-    for byte in value.bytes() {
-        if byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'.' | b'_' | b'~') {
-            encoded.push(byte as char);
-        } else {
-            encoded.push('%');
-            encoded.push(nibble_hex(byte >> 4));
-            encoded.push(nibble_hex(byte & 0x0f));
-        }
-    }
-    encoded
-}
-
-fn nibble_hex(value: u8) -> char {
-    match value {
-        0..=9 => (b'0' + value) as char,
-        10..=15 => (b'A' + value - 10) as char,
-        _ => unreachable!("hex nibble is out of range"),
-    }
-}
-
-fn server_sdk_endpoint(addr: SocketAddr, port: u16, socket_dir: Option<&Path>) -> PostgresEndpoint {
-    #[cfg(unix)]
-    {
-        if std::env::var(ENV_SERVER_SDK_TRANSPORT)
-            .map(|value| value.eq_ignore_ascii_case("tcp"))
-            .unwrap_or(false)
-        {
-            return PostgresEndpoint::Tcp(addr);
-        }
-        let socket_dir =
-            socket_dir.expect("Unix native server socket directory is allocated before endpoint");
-        PostgresEndpoint::Unix(socket_dir.join(format!(".s.PGSQL.{port}")))
-    }
-    #[cfg(not(unix))]
-    {
-        let _ = port;
-        let _ = socket_dir;
-        PostgresEndpoint::Tcp(addr)
-    }
-}
-
-#[derive(Debug)]
-enum PostgresProcessListen {
-    Tcp {
-        port: u16,
-        private_socket_dir: Option,
-    },
-    #[cfg(unix)]
-    Unix { directory: PathBuf, port: u16 },
-}
-
-fn prepare_server_listen(
-    listen: &ServerListen,
-    config: &OpenConfig,
-    resolved_port: u16,
-) -> Result<(
-    PostgresProcessListen,
-    PostgresEndpoint,
-    String,
-    Option,
-)> {
-    match listen {
-        ServerListen::Tcp { .. } => {
-            let addr = SocketAddr::from(([127, 0, 0, 1], resolved_port));
-            let socket_dir = create_server_socket_dir(resolved_port)?;
-            let endpoint = server_sdk_endpoint(addr, resolved_port, socket_dir.as_deref());
-            Ok((
-                PostgresProcessListen::Tcp {
-                    port: resolved_port,
-                    private_socket_dir: socket_dir.clone(),
-                },
-                endpoint,
-                tcp_connection_string(config, resolved_port),
-                socket_dir,
-            ))
-        }
-        #[cfg(unix)]
-        ServerListen::Unix { directory, port } => {
-            let directory = if directory.is_absolute() {
-                directory.clone()
-            } else {
-                std::env::current_dir()
-                    .map_err(|error| {
-                        Error::Engine(format!(
-                            "resolve current directory for native server Unix socket: {error}"
-                        ))
-                    })?
-                    .join(directory)
-            };
-            let connection_string = unix_connection_string(config, &directory, *port)?;
-            prepare_public_socket_directory(&directory, *port)?;
-            let socket = directory.join(format!(".s.PGSQL.{port}"));
-            Ok((
-                PostgresProcessListen::Unix {
-                    directory: directory.clone(),
-                    port: *port,
-                },
-                PostgresEndpoint::Unix(socket),
-                connection_string,
-                None,
-            ))
-        }
-    }
-}
-
-#[cfg(unix)]
-fn prepare_public_socket_directory(directory: &Path, port: u16) -> Result<()> {
-    let socket = directory.join(format!(".s.PGSQL.{port}"));
-    if socket.as_os_str().len() >= 100 {
-        return Err(Error::InvalidConfig(format!(
-            "native server Unix socket path is too long: {}",
-            socket.display()
-        )));
-    }
-    if directory.exists() {
-        let metadata = fs::symlink_metadata(directory).map_err(|err| {
-            Error::Engine(format!(
-                "inspect native server Unix socket directory {}: {err}",
-                directory.display()
-            ))
-        })?;
-        if !metadata.is_dir() || metadata.file_type().is_symlink() {
-            return Err(Error::InvalidConfig(format!(
-                "native server Unix socket directory must be a real directory: {}",
-                directory.display()
-            )));
-        }
-    } else {
-        fs::create_dir_all(directory).map_err(|err| {
-            Error::Engine(format!(
-                "create native server Unix socket directory {}: {err}",
-                directory.display()
-            ))
-        })?;
-        fs::set_permissions(directory, fs::Permissions::from_mode(0o700)).map_err(|err| {
-            Error::Engine(format!(
-                "set native server Unix socket directory permissions {}: {err}",
-                directory.display()
-            ))
-        })?;
-    }
-    ensure_public_socket_path_available(&socket)?;
-    let mut lock = socket.as_os_str().to_os_string();
-    lock.push(".lock");
-    ensure_public_socket_path_available(Path::new(&lock))?;
-    Ok(())
-}
-
-#[cfg(unix)]
-fn ensure_public_socket_path_available(path: &Path) -> Result<()> {
-    match fs::symlink_metadata(path) {
-        Ok(_) => Err(Error::InvalidConfig(format!(
-            "native server refuses to replace existing Unix endpoint {}; remove it explicitly if it is stale",
-            path.display()
-        ))),
-        Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
-        Err(error) => Err(Error::Engine(format!(
-            "inspect native server Unix endpoint {}: {error}",
-            path.display()
-        ))),
-    }
-}
-
-#[cfg(unix)]
-fn create_server_socket_dir(port: u16) -> Result> {
-    let base = Path::new("/tmp");
-    let pid = std::process::id();
-    let nanos = SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .map_err(|err| Error::Engine(format!("system clock before epoch: {err}")))?
-        .as_nanos();
-    for attempt in 0..100_u32 {
-        let socket_dir = base.join(format!("lpo-s-{pid}-{port}-{nanos}-{attempt}"));
-        match fs::create_dir(&socket_dir) {
-            Ok(()) => {
-                fs::set_permissions(&socket_dir, fs::Permissions::from_mode(0o700)).map_err(
-                    |err| {
-                        Error::Engine(format!(
-                            "set native server socket dir permissions {}: {err}",
-                            socket_dir.display()
-                        ))
-                    },
-                )?;
-                return Ok(Some(socket_dir));
-            }
-            Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => continue,
-            Err(err) => {
-                return Err(Error::Engine(format!(
-                    "create native server socket dir {}: {err}",
-                    socket_dir.display()
-                )));
-            }
-        }
-    }
-    Err(Error::Engine(
-        "failed to allocate a unique native server socket directory".to_owned(),
-    ))
-}
-
-#[cfg(not(unix))]
-fn create_server_socket_dir(_port: u16) -> Result> {
-    Ok(None)
-}
-
-fn cleanup_failed_start(
-    child: &mut Child,
-    owned_socket_dir: &mut Option,
-) -> (bool, Vec) {
-    let outcome = reap_child_process(
-        child,
-        Duration::ZERO,
-        SHUTDOWN_TIMEOUT,
-        "failed native server startup",
-    );
-    let mut failures = outcome.failures;
-    if outcome.reaped {
-        remove_owned_socket_dir(owned_socket_dir, &mut failures);
-    }
-    (outcome.reaped, failures)
-}
-
-fn remove_owned_socket_dir(socket_dir: &mut Option, failures: &mut Vec) {
-    if let Some(path) = socket_dir.as_ref() {
-        match fs::remove_dir_all(path) {
-            Ok(()) => *socket_dir = None,
-            Err(error) => failures.push(format!(
-                "remove failed native server startup socket directory {}: {error}",
-                path.display()
-            )),
-        }
-    }
-}
-
-fn failed_start_error(error: Error, cleanup_failures: Vec) -> Error {
-    if cleanup_failures.is_empty() {
-        return error;
-    }
-    Error::Engine(format!(
-        "{error}; native server failed-start cleanup failed: {}",
-        cleanup_failures.join("; ")
-    ))
-}
-
-fn tcp_port_is_occupied(port: u16) -> bool {
-    TcpListener::bind((SERVER_HOST, port))
-        .is_err_and(|error| error.kind() == std::io::ErrorKind::AddrInUse)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn missing_explicit_server_executable_is_rejected_before_persistent_root_mutation() {
-        let test_root = std::env::temp_dir().join(format!(
-            "oliphaunt-native-server-executable-preflight-{}-{}",
-            std::process::id(),
-            std::time::SystemTime::now()
-                .duration_since(std::time::UNIX_EPOCH)
-                .expect("system clock should be after epoch")
-                .as_nanos()
-        ));
-        let _cleanup = RuntimeDirCleanup(test_root.clone());
-        std::fs::create_dir_all(&test_root).expect("create server preflight test root");
-        let storage = test_root.join("database");
-        let missing_executable = test_root.join("missing-postgres");
-        let mut config = OpenConfig::direct(storage.clone());
-        config.mode = EngineMode::Server;
-        config.server.executable = Some(missing_executable.clone());
-        let runtime = NativeServerRuntime::from_config(&config.server);
-
-        let error = match runtime.open(config) {
-            Ok(_) => panic!("missing explicit server executable unexpectedly started"),
-            Err(error) => error,
-        };
-
-        assert!(error.to_string().contains("must be an existing file"));
-        assert!(!missing_executable.exists());
-        assert!(
-            !storage.exists(),
-            "deterministic executable validation must run before PGDATA preparation"
-        );
-    }
-
-    #[test]
-    fn auto_port_retry_only_classifies_a_current_loopback_owner() {
-        let listener = TcpListener::bind((SERVER_HOST, 0)).expect("bind loopback fixture");
-        let port = listener.local_addr().expect("read fixture address").port();
-        assert!(tcp_port_is_occupied(port));
-        drop(listener);
-        assert!(!tcp_port_is_occupied(port));
-    }
-
-    #[test]
-    fn server_startup_args_include_required_preload_libraries_before_spawn() {
-        let mut config = OpenConfig::direct("target/test-roots/native-server-preload");
-        config.mode = EngineMode::Server;
-        config.startup_gucs = vec![crate::config::PostgresStartupGuc::new(
-            "shared_preload_libraries",
-            "auto_explain, pg_textsearch",
-        )];
-        let args = postgres_startup_args(
-            Path::new("/tmp/oliphaunt-preload/pgdata"),
-            &config,
-            &[Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH],
-            &PostgresProcessListen::Tcp {
-                port: 15432,
-                private_socket_dir: Some(PathBuf::from("/tmp/oliphaunt-preload-socket")),
-            },
-        )
-        .unwrap();
-        let args = args
-            .iter()
-            .map(|arg| arg.to_string_lossy().into_owned())
-            .collect::>();
-
-        assert_startup_config_arg(&args, "shared_preload_libraries=auto_explain,pg_textsearch");
-        assert_eq!(
-            args.iter()
-                .filter(|arg| arg.starts_with("shared_preload_libraries="))
-                .count(),
-            1,
-            "caller and extension preload libraries must be merged once in server startup args"
-        );
-    }
-
-    #[test]
-    fn extension_runtime_env_is_set_only_when_required_file_is_materialized() {
-        let runtime_dir = std::env::temp_dir().join(format!(
-            "oliphaunt-extension-runtime-env-{}-{}",
-            std::process::id(),
-            std::time::SystemTime::now()
-                .duration_since(std::time::UNIX_EPOCH)
-                .expect("system clock should be after epoch")
-                .as_nanos()
-        ));
-        let _cleanup = RuntimeDirCleanup(runtime_dir.clone());
-        let mut missing = Command::new("postgres");
-        configure_extension_runtime_env(&mut missing, &runtime_dir, &[Extension::POSTGIS]);
-        assert_eq!(
-            missing
-                .get_envs()
-                .find(|(key, _)| *key == std::ffi::OsStr::new("PROJ_DATA")),
-            None
-        );
-
-        let proj_data = runtime_dir.join("share/postgresql/proj");
-        std::fs::create_dir_all(&proj_data).expect("create proj data dir");
-        std::fs::write(proj_data.join("proj.db"), b"fixture").expect("write proj.db");
-
-        let mut present = Command::new("postgres");
-        configure_extension_runtime_env(&mut present, &runtime_dir, &[Extension::POSTGIS]);
-        assert_eq!(
-            present
-                .get_envs()
-                .find(|(key, _)| *key == std::ffi::OsStr::new("PROJ_DATA"))
-                .and_then(|(_, value)| value)
-                .map(PathBuf::from),
-            Some(proj_data)
-        );
-
-        let mut unselected = Command::new("postgres");
-        configure_extension_runtime_env(&mut unselected, &runtime_dir, &[]);
-        assert_eq!(
-            unselected
-                .get_envs()
-                .find(|(key, _)| *key == std::ffi::OsStr::new("PROJ_DATA")),
-            None
-        );
-    }
-
-    #[test]
-    fn native_runtime_env_sets_icu_data_when_materialized() {
-        let runtime_dir = std::env::temp_dir().join(format!(
-            "oliphaunt-icu-runtime-env-{}-{}",
-            std::process::id(),
-            std::time::SystemTime::now()
-                .duration_since(std::time::UNIX_EPOCH)
-                .expect("system clock should be after epoch")
-                .as_nanos()
-        ));
-        let _cleanup = RuntimeDirCleanup(runtime_dir.clone());
-
-        let mut missing = Command::new("postgres");
-        for key in [
-            "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY",
-            "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY",
-            "OLIPHAUNT_INTERNAL_ICU_READY",
-            "ICU_DATA",
-        ] {
-            missing.env(key, "ambient");
-        }
-        configure_native_runtime_env(&mut missing, &runtime_dir, &[]);
-        assert_eq!(
-            missing
-                .get_envs()
-                .find(|(key, _)| *key == std::ffi::OsStr::new("ICU_DATA"))
-                .and_then(|(_, value)| value),
-            None
-        );
-        for key in [
-            "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY",
-            "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY",
-            "OLIPHAUNT_INTERNAL_ICU_READY",
-        ] {
-            assert_eq!(
-                missing
-                    .get_envs()
-                    .find(|(candidate, _)| *candidate == std::ffi::OsStr::new(key))
-                    .and_then(|(_, value)| value),
-                None
-            );
-        }
-
-        let icu_data = runtime_dir.join("share/icu");
-        std::fs::create_dir_all(&icu_data).expect("create ICU data dir");
-        let mut present = Command::new("postgres");
-        configure_native_runtime_env(&mut present, &runtime_dir, &[]);
-        assert_eq!(
-            present
-                .get_envs()
-                .find(|(key, _)| *key == std::ffi::OsStr::new("ICU_DATA"))
-                .and_then(|(_, value)| value)
-                .map(PathBuf::from),
-            Some(icu_data)
-        );
-    }
-
-    struct RuntimeDirCleanup(PathBuf);
-
-    impl Drop for RuntimeDirCleanup {
-        fn drop(&mut self) {
-            let _ = std::fs::remove_dir_all(&self.0);
-        }
-    }
-
-    #[test]
-    fn server_connection_string_uses_configured_identity() {
-        let mut config = OpenConfig::direct("target/test-roots/native-server-identity");
-        config.mode = EngineMode::Server;
-        config.username = "app user".to_owned();
-        config.database = "app/db".to_owned();
-
-        assert_eq!(
-            tcp_connection_string(&config, 15432),
-            "postgresql://app%20user@127.0.0.1:15432/app%2Fdb?sslmode=disable"
-        );
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn unix_connection_string_uses_postgresql_socket_directory_and_port() {
-        let mut config = OpenConfig::direct("target/test-roots/native-server-unix-uri");
-        config.mode = EngineMode::Server;
-        config.username = "app user".to_owned();
-        config.database = "app/db".to_owned();
-
-        assert_eq!(
-            unix_connection_string(&config, Path::new("/tmp/app sockets"), 15432).unwrap(),
-            "postgresql:///app%2Fdb?host=%2Ftmp%2Fapp%20sockets&port=15432&user=app%20user&sslmode=disable"
-        );
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn unix_socket_directory_is_one_quoted_postgres_guc_list_item() {
-        let mut config = OpenConfig::direct("target/test-roots/native-server-unix-guc-list");
-        config.mode = EngineMode::Server;
-        let directory = PathBuf::from("/tmp/ application,\"primary\" ");
-        let args = postgres_startup_args(
-            Path::new("/tmp/pgdata"),
-            &config,
-            &[],
-            &PostgresProcessListen::Unix {
-                directory,
-                port: 15432,
-            },
-        )
-        .expect("a quoted PostgreSQL list item accepts path punctuation");
-        let args = args
-            .iter()
-            .map(|arg| arg.to_string_lossy().into_owned())
-            .collect::>();
-
-        assert_startup_config_arg(
-            &args,
-            "unix_socket_directories=\"/tmp/ application,\"\"primary\"\" \"",
-        );
-    }
-
-    fn assert_startup_config_arg(args: &[String], expected: &str) {
-        let Some(index) = args.iter().position(|arg| arg == expected) else {
-            panic!("missing server startup argument {expected:?} in {args:?}");
-        };
-        assert_eq!(
-            args.get(index.saturating_sub(1)).map(String::as_str),
-            Some("-c"),
-            "server startup argument {expected:?} must be passed through postgres -c"
-        );
-    }
-}
diff --git a/src/sdks/rust/src/storage.rs b/src/sdks/rust/src/storage.rs
deleted file mode 100644
index f2a10ff81..000000000
--- a/src/sdks/rust/src/storage.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-use std::path::{Path, PathBuf};
-
-#[cfg(unix)]
-use std::os::unix::ffi::OsStrExt;
-#[cfg(windows)]
-use std::os::windows::ffi::OsStrExt;
-
-/// Storage used by a native database instance.
-#[derive(Debug, Clone, PartialEq, Eq, Default)]
-pub enum DatabaseStorage {
-    /// SDK-owned temporary directory.
-    #[default]
-    TemporaryDirectory,
-    /// Caller-owned persistent directory.
-    Directory(PathBuf),
-}
-
-pub(crate) fn path_contains_nul(path: &Path) -> bool {
-    #[cfg(unix)]
-    {
-        path.as_os_str().as_bytes().contains(&0)
-    }
-    #[cfg(windows)]
-    {
-        path.as_os_str().encode_wide().any(|unit| unit == 0)
-    }
-    #[cfg(not(any(unix, windows)))]
-    {
-        path.to_string_lossy().bytes().any(|byte| byte == 0)
-    }
-}
diff --git a/src/sdks/rust/src/test_fixtures.rs b/src/sdks/rust/src/test_fixtures.rs
deleted file mode 100644
index a2ad717a3..000000000
--- a/src/sdks/rust/src/test_fixtures.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-use std::fs;
-use std::path::Path;
-
-pub(crate) fn text(relative: &str) -> String {
-    let package_root = Path::new(env!("CARGO_MANIFEST_DIR"));
-    let candidates = [
-        package_root.join("../../shared/fixtures").join(relative),
-        package_root.join("testdata").join(relative),
-    ];
-    for candidate in &candidates {
-        if let Ok(value) = fs::read_to_string(candidate) {
-            return value;
-        }
-    }
-    panic!(
-        "missing shared test fixture {relative}; checked {}",
-        candidates
-            .iter()
-            .map(|path| path.display().to_string())
-            .collect::>()
-            .join(", ")
-    );
-}
diff --git a/src/sdks/rust/tests/public_api.rs b/src/sdks/rust/tests/public_api.rs
deleted file mode 100644
index e472eb9cb..000000000
--- a/src/sdks/rust/tests/public_api.rs
+++ /dev/null
@@ -1,408 +0,0 @@
-use oliphaunt::{
-    AsyncOliphaunt, AsyncOliphauntBuilder, AsyncOliphauntServer, AsyncOliphauntServerBuilder,
-    AsyncSql, AsyncTransaction, CancelHandle, DatabaseStorage, DecodeError, Error, ErrorKind,
-    ExecResult, Extension, FromSql, IntoParameter, Oliphaunt, OliphauntBuilder, OliphauntServer,
-    OliphauntServerBuilder, Parameter, PostgresError, PostgresNotice, QueryFormat,
-    RawStreamCallbackOutput, RawStreamError, RawStreamResult, Sql, StatementDescription,
-    Transaction, TransactionError, TransactionResult, TypeOid, ValueFormat, ValueRef,
-};
-
-#[derive(Debug)]
-enum ApplicationError {
-    Database(Error),
-    Abort,
-}
-
-impl From for ApplicationError {
-    fn from(error: Error) -> Self {
-        Self::Database(error)
-    }
-}
-
-impl std::fmt::Display for ApplicationError {
-    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::Database(error) => error.fmt(formatter),
-            Self::Abort => formatter.write_str("application aborted the transaction"),
-        }
-    }
-}
-
-impl std::error::Error for ApplicationError {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        match self {
-            Self::Database(error) => Some(error),
-            Self::Abort => None,
-        }
-    }
-}
-
-#[derive(Debug)]
-struct ParserError;
-
-impl std::fmt::Display for ParserError {
-    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        formatter.write_str("parser stopped the stream")
-    }
-}
-
-impl std::error::Error for ParserError {}
-
-fn sdk_only_blocking_callbacks(database: &mut Oliphaunt) -> oliphaunt::Result<()> {
-    database.transaction(|transaction| {
-        transaction.execute("SELECT 1")?;
-        Ok(())
-    })?;
-    database.exec_protocol_raw_stream([], |_| ())?;
-    database.exec_protocol_raw_stream([], |_| -> oliphaunt::Result<()> { Ok(()) })?;
-    Ok(())
-}
-
-fn typed_blocking_transaction(database: &mut Oliphaunt) -> TransactionResult<(), ApplicationError> {
-    database.transaction(|transaction| {
-        transaction.execute("SELECT 1")?;
-        Err(ApplicationError::Abort)
-    })
-}
-
-fn typed_blocking_stream(database: &mut Oliphaunt) -> RawStreamResult<(), ParserError> {
-    database.exec_protocol_raw_stream([], |_| Err(ParserError))
-}
-
-async fn sdk_only_async_callbacks(database: &AsyncOliphaunt) -> oliphaunt::Result<()> {
-    database
-        .transaction(async |transaction| {
-            transaction.execute("SELECT 1").await?;
-            Ok(())
-        })
-        .await?;
-    database.exec_protocol_raw_stream([], |_| ()).await?;
-    database
-        .exec_protocol_raw_stream([], |_| -> oliphaunt::Result<()> { Ok(()) })
-        .await?;
-    Ok(())
-}
-
-async fn typed_async_transaction(
-    database: &AsyncOliphaunt,
-) -> TransactionResult<(), ApplicationError> {
-    database
-        .transaction(async |transaction| {
-            transaction.execute("SELECT 1").await?;
-            Err(ApplicationError::Abort)
-        })
-        .await
-}
-
-async fn typed_async_stream(database: &AsyncOliphaunt) -> RawStreamResult<(), ParserError> {
-    database
-        .exec_protocol_raw_stream([], |_| Err(ParserError))
-        .await
-}
-
-struct PublicParameter;
-
-impl IntoParameter for PublicParameter {
-    const TYPE_OID: Option = Some(TypeOid::INT4);
-
-    fn into_parameter(self) -> Parameter {
-        Parameter::typed_binary(TypeOid::INT4, 7_i32.to_be_bytes())
-    }
-}
-
-struct PublicDecoder;
-
-impl<'a> FromSql<'a> for PublicDecoder {
-    fn from_sql(_value: ValueRef<'a>) -> std::result::Result {
-        Ok(Self)
-    }
-}
-
-fn assert_send_future(_: T) {}
-
-macro_rules! assert_not_impl {
-    ($type:ty: $bound:path) => {
-        const _: fn() = || {
-            trait AmbiguousIfImpl {
-                fn marker() {}
-            }
-            struct Invalid;
-            impl AmbiguousIfImpl<()> for T {}
-            impl AmbiguousIfImpl for T {}
-            let _ = <$type as AmbiguousIfImpl<_>>::marker;
-        };
-    };
-}
-
-assert_not_impl!(Oliphaunt: Sync);
-assert_not_impl!(OliphauntServer: Sync);
-assert_not_impl!(AsyncTransaction: Sync);
-
-// OLIPHAUNT_DOCS_SNIPPET rust-quickstart
-
-#[test]
-fn public_api_has_only_the_deliberate_native_vocabulary() {
-    let _: OliphauntBuilder = Oliphaunt::builder()
-        .direct()
-        .storage(DatabaseStorage::TemporaryDirectory)
-        .startup_guc("work_mem", "8MB")
-        .startup_gucs([("application_name", "oliphaunt")])
-        .username("postgres")
-        .database("postgres")
-        .extension(Extension::VECTOR);
-
-    let _: Parameter = "text".into_parameter();
-    let _: QueryFormat = QueryFormat::Text;
-
-    fn assert_error() {}
-    fn assert_clone() {}
-    fn assert_copy() {}
-    fn assert_debug() {}
-    fn assert_eq_type() {}
-    fn assert_hash() {}
-    fn assert_ord() {}
-    fn assert_send() {}
-    fn assert_send_sync() {}
-    fn assert_raw_callback_output() {}
-    assert_send::();
-    assert_send::();
-    assert_clone::();
-    assert_clone::();
-    assert_clone::();
-    assert_clone::();
-    assert_debug::();
-    assert_debug::();
-    assert_debug::();
-    assert_debug::();
-    assert_send_sync::();
-    assert_send_sync::();
-    assert_send_sync::();
-    assert_send_sync::();
-    assert_send_sync::();
-    fn cancellation_surface(handle: &CancelHandle) {
-        let _: CancelHandle = handle.clone();
-        let _: oliphaunt::Result<()> = handle.cancel();
-    }
-    let _: fn(&CancelHandle) = cancellation_surface;
-    assert_send_sync::();
-    assert_send_sync::();
-    assert_send::();
-    assert_send_future(AsyncOliphaunt::builder().open());
-    assert_send_future(AsyncOliphauntServer::builder().start());
-    assert_send_future(AsyncOliphaunt::restore(
-        std::path::PathBuf::from("unused-async-public-api-check"),
-        Vec::::new(),
-    ));
-    assert_error::();
-    assert_clone::();
-    assert_copy::();
-    assert_debug::();
-    assert_eq_type::();
-    assert_send_sync::();
-    assert_copy::();
-    assert_debug::();
-    assert_eq_type::();
-    assert_hash::();
-    assert_ord::();
-    assert_send_sync::();
-    assert_error::();
-    assert_error::>();
-    assert_error::>();
-    assert_raw_callback_output::<()>();
-    assert_raw_callback_output::>();
-
-    fn generic_error_surface(
-        transaction: &TransactionError,
-        stream: &RawStreamError,
-    ) {
-        let _: Option<&ApplicationError> = transaction.callback_error();
-        let _: Option<&Error> = transaction.database_error();
-        let _: Option<&Error> = transaction.rollback_error();
-        let _: Option<&ParserError> = stream.callback_error();
-        let _: Option<&Error> = stream.database_error();
-        let _: Option<&Error> = stream.callback_panic_error();
-    }
-    let _: fn(&TransactionError, &RawStreamError) =
-        generic_error_surface;
-
-    fn flatten_sdk_errors(
-        transaction: TransactionError,
-        stream: RawStreamError,
-        infallible: RawStreamError,
-    ) {
-        let _: Error = transaction.into();
-        let _: Error = stream.into();
-        let _: Error = infallible.into();
-    }
-    let _ = flatten_sdk_errors;
-
-    fn caller_thread_terminals(builder: OliphauntBuilder) {
-        let _: oliphaunt::Result = builder.open();
-        let _: oliphaunt::Result = Oliphaunt::open();
-        let _: oliphaunt::Result = OliphauntServer::builder().start();
-        let _: oliphaunt::Result<()> = Oliphaunt::restore(
-            std::path::PathBuf::from("unused-public-api-check"),
-            Vec::::new(),
-        );
-    }
-    let _: fn(OliphauntBuilder) = caller_thread_terminals;
-
-    fn transaction_rollback_surface(error: &Error) {
-        let _: ErrorKind = error.kind();
-        let _: Error = error.clone();
-        let _: Option<&PostgresError> = error.postgres_error();
-        let _: Option<(&Error, &Error)> = error.transaction_rollback_errors();
-        let _: Option<(&Error, &Error)> = error.transaction_callback_database_errors();
-    }
-    let _: fn(&Error) = transaction_rollback_surface;
-
-    fn postgres_diagnostic_surface(error: &PostgresError, notice: &PostgresNotice) {
-        let _: (&Option, &Option) =
-            (&error.localized_severity, ¬ice.localized_severity);
-        let _: (&Option, &Option) =
-            (&error.nonlocalized_severity, ¬ice.nonlocalized_severity);
-        let _: (&Option, &Option) =
-            (&error.internal_position, ¬ice.internal_position);
-        let _: (&Option, &Option) = (&error.internal_query, ¬ice.internal_query);
-        let _: (&Option, &Option) = (&error.file, ¬ice.file);
-        let _: (&Option, &Option) = (&error.line, ¬ice.line);
-        let _: (&Option, &Option) = (&error.routine, ¬ice.routine);
-    }
-    let _: fn(&PostgresError, &PostgresNotice) = postgres_diagnostic_surface;
-}
-
-#[test]
-fn typed_and_fluent_database_api_is_public() {
-    fn assert_decoder()
-    where
-        for<'a> T: FromSql<'a>,
-    {
-    }
-    assert_decoder::();
-    assert_decoder::();
-    assert_decoder::();
-
-    let parameter = Parameter::null().with_type_oid(TypeOid::UUID);
-    assert_eq!(parameter.type_oid(), Some(TypeOid::UUID));
-    assert_eq!(parameter.format(), ValueFormat::Text);
-    assert_eq!(TypeOid::TIMETZ.get(), 1266);
-    assert_eq!(TypeOid::CHAR_ARRAY.get(), 1002);
-    assert_eq!(TypeOid::NAME_ARRAY.get(), 1003);
-    assert_eq!(TypeOid::XML_ARRAY.get(), 143);
-    assert_eq!(TypeOid::TIMETZ_ARRAY.get(), 1270);
-    let typed_null = IntoParameter::into_parameter(None::);
-    assert_eq!(typed_null.type_oid(), Some(TypeOid::INT8));
-    assert_eq!(
-        IntoParameter::into_parameter(PublicParameter).type_oid(),
-        Some(TypeOid::INT4)
-    );
-
-    fn database_surface(database: &mut Oliphaunt) {
-        let _query = database
-            .sql("SELECT $1::int4")
-            .bind(1_i32)
-            .result_format(ValueFormat::Binary)
-            .query();
-        let _execute = database
-            .sql("UPDATE items SET value = $1")
-            .bind("value")
-            .execute();
-        let _typed_query = database.query_with_params("SELECT $1::int4", [1_i32]);
-        let _typed_execute = database.execute_with_params("SELECT $1::bool", [true]);
-        let _describe_convenience = database.describe("SELECT 1");
-        let _describe = database
-            .sql("SELECT $1::uuid")
-            .bind_parameter(Parameter::typed_null(TypeOid::UUID))
-            .describe();
-        let _exec: oliphaunt::Result = database.exec("SELECT 1; SELECT 2");
-        let _description: oliphaunt::Result =
-            database.sql("SELECT 1").describe();
-        let mut streamed_bytes = 0_usize;
-        let _borrowed_raw_stream = database.exec_protocol_raw_stream([], |chunk| {
-            streamed_bytes += chunk.len();
-        });
-        let _ = streamed_bytes;
-        let _raw_stream = database.exec_protocol_raw_stream([], |_| ());
-        let _cancel = database.cancel();
-        let _cancel_handle = database.cancel_handle();
-        let _closed = database.is_closed();
-        let _transaction = database.transaction(|transaction: &mut Transaction<'_>| {
-            let _closed = transaction.is_closed();
-            let _typed_query = transaction.query_with_params("SELECT $1::int8", [1_i64]);
-            transaction.rollback()?;
-            Ok::<(), Error>(())
-        });
-    }
-    let _: fn(&mut Oliphaunt) = database_surface;
-    let _: fn(&mut Oliphaunt) -> oliphaunt::Result<()> = sdk_only_blocking_callbacks;
-    let _: fn(&mut Oliphaunt) -> TransactionResult<(), ApplicationError> =
-        typed_blocking_transaction;
-    let _: fn(&mut Oliphaunt) -> RawStreamResult<(), ParserError> = typed_blocking_stream;
-
-    fn server_surface(server: &mut OliphauntServer) {
-        let _: &str = server.connection_string();
-        let _: bool = server.is_closed();
-        let _: oliphaunt::Result<()> = server.close();
-    }
-    let _: fn(&mut OliphauntServer) = server_surface;
-
-    fn async_database_surface(database: &AsyncOliphaunt) {
-        let _: AsyncOliphauntBuilder = AsyncOliphaunt::builder();
-        assert_send_future(AsyncOliphaunt::open());
-        assert_send_future(AsyncOliphauntServer::builder().start());
-        let _: AsyncSql<'_, '_> = database.sql("SELECT 1");
-        assert_send_future(database.sql("SELECT $1::int4").bind(1_i32).query());
-        assert_send_future(database.execute_with_params("SELECT $1::bool", [true]));
-        assert_send_future(database.exec("SELECT 1; SELECT 2"));
-        assert_send_future(database.describe("SELECT 1"));
-        assert_send_future(database.exec_protocol_raw([]));
-        assert_send_future(database.exec_protocol_raw_stream([], |_| ()));
-        assert_send_future(database.backup());
-        assert_send_future(database.cancel());
-        assert_send_future(
-            database.transaction(async |transaction: &mut AsyncTransaction| {
-                assert_send_future(transaction.query_with_params("SELECT $1::int8", [1_i64]));
-                assert_send_future(transaction.exec("SELECT 1; SELECT 2"));
-                assert_send_future(transaction.describe("SELECT 1"));
-                transaction.rollback().await?;
-                Ok::<(), Error>(())
-            }),
-        );
-        assert_send_future(database.close());
-        assert_send_future(sdk_only_async_callbacks(database));
-        assert_send_future(typed_async_transaction(database));
-        assert_send_future(typed_async_stream(database));
-    }
-    let _: fn(&AsyncOliphaunt) = async_database_surface;
-
-    fn async_server_surface(server: &AsyncOliphauntServer) {
-        let _: &str = server.connection_string();
-        let _: bool = server.is_closed();
-        assert_send_future(server.close());
-    }
-    let _: fn(&AsyncOliphauntServer) = async_server_surface;
-
-    fn blocking_statement_type<'db, 'q>(
-        database: &'db mut Oliphaunt,
-        sql: &'q str,
-    ) -> Sql<'db, 'q> {
-        database.sql(sql)
-    }
-    let _ = blocking_statement_type;
-}
-
-#[test]
-fn extension_catalog_is_exact_and_sorted() {
-    let names = Extension::ALL
-        .iter()
-        .map(|extension| extension.sql_name())
-        .collect::>();
-    assert!(names.windows(2).all(|pair| pair[0] < pair[1]));
-    assert_eq!(names.len(), 39);
-    for extension in Extension::ALL {
-        assert_eq!(
-            Extension::by_sql_name(extension.sql_name()),
-            Some(*extension)
-        );
-    }
-}
diff --git a/src/sdks/rust/tests/release-consumer/src/main.rs b/src/sdks/rust/tests/release-consumer/src/main.rs
deleted file mode 100644
index c52183ed6..000000000
--- a/src/sdks/rust/tests/release-consumer/src/main.rs
+++ /dev/null
@@ -1,234 +0,0 @@
-use std::error::Error;
-use std::future::Future;
-use std::io;
-use std::net::TcpListener;
-use std::path::{Path, PathBuf};
-use std::process::{Command, Output};
-use std::task::{Context, Poll, Waker};
-use std::thread;
-use std::time::Duration;
-
-use oliphaunt::{AsyncOliphauntServer, DatabaseStorage, ServerListen};
-
-fn main() -> Result<(), Box> {
-    let root = std::env::args_os()
-        .nth(1)
-        .map(PathBuf::from)
-        .ok_or_else(|| io::Error::other("usage: oliphaunt-rust-release-consumer DATABASE_ROOT"))?;
-    let backup = root.with_file_name("database-basebackup");
-    let copied_log = root.with_file_name("database-basebackup.log");
-    let psql = packaged_tool("psql")?;
-    let pg_basebackup = packaged_tool("pg_basebackup")?;
-    let pg_ctl = packaged_runtime_tool("pg_ctl")?;
-
-    let database = block_on(
-        AsyncOliphauntServer::builder()
-            .storage(DatabaseStorage::Directory(root.clone()))
-            .listen(ServerListen::tcp())
-            .start(),
-    )?;
-    let exercise_source = (|| -> Result<(), Box> {
-        command_succeeded(
-            "packaged psql seed",
-            &Command::new(&psql)
-                .args([
-                    "--no-psqlrc",
-                    "--no-password",
-                    "--set=ON_ERROR_STOP=1",
-                    "--dbname",
-                    database.connection_string(),
-                    "--command",
-                    "CREATE SEQUENCE packed_backup_seq START 40; \
-                     CREATE TABLE packed_backup_items(\
-                       id bigint PRIMARY KEY DEFAULT nextval('packed_backup_seq'),\
-                       value text NOT NULL, payload bytea NOT NULL, optional_value text NULL\
-                     ); \
-                     CREATE UNIQUE INDEX packed_backup_items_value_idx ON packed_backup_items(value); \
-                     INSERT INTO packed_backup_items(value, payload, optional_value) VALUES\
-                       ('café 🐘', decode('00ff10', 'hex'), NULL),\
-                       ('東京', decode('deadbeef', 'hex'), 'present');",
-                ])
-                .env("PGCONNECT_TIMEOUT", "5")
-                .output()?,
-        )?;
-        command_succeeded(
-            "packaged pg_basebackup",
-            &Command::new(&pg_basebackup)
-                .arg("--dbname")
-                .arg(database.connection_string())
-                .arg("--pgdata")
-                .arg(&backup)
-                .args([
-                    "--format=plain",
-                    "--wal-method=stream",
-                    "--checkpoint=fast",
-                    "--no-password",
-                ])
-                .env("PGCONNECT_TIMEOUT", "5")
-                .output()?,
-        )?;
-        require_file(&backup.join("PG_VERSION"))?;
-        require_file(&backup.join("backup_label"))?;
-        require_file(&backup.join("global/pg_control"))?;
-        Ok(())
-    })();
-    let close_source = block_on(database.close());
-    exercise_source?;
-    close_source?;
-
-    let port_probe = TcpListener::bind(("127.0.0.1", 0))?;
-    let port = port_probe.local_addr()?.port();
-    drop(port_probe);
-    command_succeeded(
-        "packaged pg_ctl start copied PGDATA",
-        &Command::new(&pg_ctl)
-            .arg("--pgdata")
-            .arg(&backup)
-            .arg("--log")
-            .arg(&copied_log)
-            .args(["--wait", "--timeout=60", "start", "--options"])
-            .arg(format!("-c listen_addresses=127.0.0.1 -c port={port}"))
-            .output()?,
-    )?;
-    let mut copied = PgCtlGuard::new(pg_ctl, backup);
-    let copied_uri = format!("postgresql://postgres@127.0.0.1:{port}/postgres?sslmode=disable");
-    let copied_query = Command::new(&psql)
-        .args([
-            "--no-psqlrc",
-            "--no-align",
-            "--tuples-only",
-            "--quiet",
-            "--no-password",
-            "--dbname",
-            &copied_uri,
-            "--command",
-            "SELECT string_agg(value || ':' || encode(payload, 'hex') || ':' || \
-               coalesce(optional_value, 'NULL'), '|' ORDER BY value COLLATE \"C\") \
-             FROM packed_backup_items; \
-             SELECT to_regclass('packed_backup_items_value_idx')::text; \
-             SELECT nextval('packed_backup_seq')::text;",
-        ])
-        .env("PGCONNECT_TIMEOUT", "10")
-        .output()?;
-    command_succeeded("packaged psql copied PGDATA query", &copied_query)?;
-    let rows = String::from_utf8(copied_query.stdout)?
-        .lines()
-        .map(str::trim)
-        .filter(|line| !line.is_empty())
-        .map(str::to_owned)
-        .collect::>();
-    let expected = [
-        "café 🐘:00ff10:NULL|東京:deadbeef:present",
-        "packed_backup_items_value_idx",
-        "42",
-    ];
-    if rows != expected {
-        return Err(io::Error::other(format!(
-            "copied PGDATA query returned {rows:?}, expected {expected:?}"
-        ))
-        .into());
-    }
-    copied.stop()?;
-    println!(
-        "OLIPHAUNT_RUST_RELEASE_CONSUMER_PASS checks=open,external-psql,pg-basebackup,restart,query,close"
-    );
-    Ok(())
-}
-
-fn packaged_tool(name: &str) -> io::Result {
-    packaged_binary("OLIPHAUNT_TOOLS_DIR", name)
-}
-
-fn packaged_runtime_tool(name: &str) -> io::Result {
-    packaged_binary("OLIPHAUNT_INSTALL_DIR", name)
-}
-
-fn packaged_binary(root_variable: &str, name: &str) -> io::Result {
-    let root = std::env::var_os(root_variable)
-        .map(PathBuf::from)
-        .ok_or_else(|| io::Error::other(format!("{root_variable} is unset")))?;
-    let name = if cfg!(windows) {
-        format!("{name}.exe")
-    } else {
-        name.to_owned()
-    };
-    let path = root.join("bin").join(name);
-    require_file(&path)?;
-    Ok(path)
-}
-
-fn require_file(path: &Path) -> io::Result<()> {
-    if path.is_file() {
-        Ok(())
-    } else {
-        Err(io::Error::other(format!(
-            "required packaged file is missing: {}",
-            path.display()
-        )))
-    }
-}
-
-fn command_succeeded(name: &str, output: &Output) -> io::Result<()> {
-    if output.status.success() {
-        return Ok(());
-    }
-    Err(io::Error::other(format!(
-        "{name} failed with {}\nstdout:\n{}\nstderr:\n{}",
-        output.status,
-        String::from_utf8_lossy(&output.stdout),
-        String::from_utf8_lossy(&output.stderr)
-    )))
-}
-
-struct PgCtlGuard {
-    pg_ctl: PathBuf,
-    pgdata: PathBuf,
-    active: bool,
-}
-
-impl PgCtlGuard {
-    fn new(pg_ctl: PathBuf, pgdata: PathBuf) -> Self {
-        Self {
-            pg_ctl,
-            pgdata,
-            active: true,
-        }
-    }
-
-    fn stop(&mut self) -> io::Result<()> {
-        if !self.active {
-            return Ok(());
-        }
-        let output = Command::new(&self.pg_ctl)
-            .arg("--pgdata")
-            .arg(&self.pgdata)
-            .args(["--wait", "--timeout=60", "stop", "--mode=fast"])
-            .output()?;
-        command_succeeded("packaged pg_ctl stop copied PGDATA", &output)?;
-        self.active = false;
-        Ok(())
-    }
-}
-
-impl Drop for PgCtlGuard {
-    fn drop(&mut self) {
-        if self.active {
-            let _ = Command::new(&self.pg_ctl)
-                .arg("--pgdata")
-                .arg(&self.pgdata)
-                .args(["--wait", "--timeout=60", "stop", "--mode=immediate"])
-                .output();
-        }
-    }
-}
-
-fn block_on(future: F) -> F::Output {
-    let mut context = Context::from_waker(Waker::noop());
-    let mut future = Box::pin(future);
-    loop {
-        match future.as_mut().poll(&mut context) {
-            Poll::Ready(value) => return value,
-            Poll::Pending => thread::park_timeout(Duration::from_millis(1)),
-        }
-    }
-}
diff --git a/src/sdks/rust/tests/sdk_extensions.rs b/src/sdks/rust/tests/sdk_extensions.rs
deleted file mode 100644
index e086e6796..000000000
--- a/src/sdks/rust/tests/sdk_extensions.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use std::collections::BTreeSet;
-use std::path::PathBuf;
-
-use oliphaunt::Extension;
-
-fn generated_extension_metadata() -> serde_json::Value {
-    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
-        .join("../../extensions/generated/sdk/extensions.json");
-    let text = std::fs::read_to_string(&path)
-        .unwrap_or_else(|error| panic!("read {}: {error}", path.display()));
-    serde_json::from_str(&text).unwrap_or_else(|error| panic!("parse {}: {error}", path.display()))
-}
-
-#[test]
-fn public_extension_catalog_matches_generated_extension_selection_metadata() {
-    fn assert_extension_traits() {}
-    assert_extension_traits::();
-
-    let metadata = generated_extension_metadata();
-    let rows = metadata["extensions"]
-        .as_array()
-        .expect("generated Rust SDK extension metadata must define extensions");
-    let generated_names = rows
-        .iter()
-        .map(|row| {
-            row["sql-name"]
-                .as_str()
-                .expect("extension row must define sql-name")
-        })
-        .collect::>();
-    let public_names = Extension::ALL
-        .iter()
-        .map(|extension| extension.sql_name())
-        .collect::>();
-
-    assert_eq!(public_names, generated_names);
-    assert_eq!(public_names.len(), Extension::ALL.len());
-
-    for extension in Extension::ALL {
-        assert_eq!(
-            Extension::by_sql_name(extension.sql_name()),
-            Some(*extension)
-        );
-    }
-}
-
-#[test]
-fn extension_selection_uses_exact_sql_names_without_aliases() {
-    assert_eq!(Extension::by_sql_name("vector"), Some(Extension::VECTOR));
-    assert_eq!(
-        Extension::by_sql_name("uuid-ossp"),
-        Some(Extension::UUID_OSSP)
-    );
-    for unsupported_alias in [
-        "core",
-        "search",
-        "geo",
-        "vector-pack",
-        "vector_pack",
-        "vector+search",
-    ] {
-        assert_eq!(Extension::by_sql_name(unsupported_alias), None);
-    }
-}
diff --git a/src/sdks/rust/tests/support/mod.rs b/src/sdks/rust/tests/support/mod.rs
deleted file mode 100644
index e78a0ca03..000000000
--- a/src/sdks/rust/tests/support/mod.rs
+++ /dev/null
@@ -1,337 +0,0 @@
-use std::fs;
-use std::io::{self, Read, Write};
-use std::net::{Shutdown, TcpStream};
-use std::path::Path;
-use std::time::Duration;
-
-#[allow(dead_code)]
-pub(crate) fn fixture_text(relative: &str) -> String {
-    let package_root = Path::new(env!("CARGO_MANIFEST_DIR"));
-    let candidates = [
-        package_root.join("../../shared/fixtures").join(relative),
-        package_root
-            .join("../../src/shared/fixtures")
-            .join(relative),
-        package_root.join("testdata").join(relative),
-    ];
-    for candidate in &candidates {
-        if let Ok(value) = fs::read_to_string(candidate) {
-            return value;
-        }
-    }
-    panic!(
-        "missing canonical test fixture {relative}; checked {}",
-        candidates
-            .iter()
-            .map(|path| path.display().to_string())
-            .collect::>()
-            .join(", ")
-    );
-}
-
-/// Execute a raw frontend-protocol request through the public server endpoint.
-///
-/// Native server handles intentionally expose lifecycle and endpoint state only;
-/// integration tests use this tiny external client to exercise the same wire
-/// boundary that PostgreSQL drivers and ORMs use.
-#[allow(dead_code)]
-pub(crate) fn external_raw_query(
-    connection_string: &str,
-    request: impl AsRef<[u8]>,
-) -> io::Result> {
-    ExternalRawSession::connect(connection_string)?.exec_protocol_raw(request)
-}
-
-/// Minimal persistent PostgreSQL session for server-bound integration tests.
-///
-/// A session must be reused when a test relies on connection-local state such
-/// as temporary tables. Opening one TCP connection per statement would not
-/// model an ordinary PostgreSQL client and would discard that state.
-pub(crate) struct ExternalRawSession {
-    stream: Option,
-}
-
-impl ExternalRawSession {
-    pub(crate) fn connect(connection_string: &str) -> io::Result {
-        let (address, user, database) = parse_tcp_connection_string(connection_string)?;
-        let mut stream = TcpStream::connect(&address).map_err(|error| {
-            io::Error::other(format!(
-                "connect external test client to {address}: {error}"
-            ))
-        })?;
-        let timeout = Some(Duration::from_secs(30));
-        stream
-            .set_read_timeout(timeout)
-            .and_then(|()| stream.set_write_timeout(timeout))
-            .map_err(|error| {
-                io::Error::other(format!("configure external test client: {error}"))
-            })?;
-
-        write_startup(&mut stream, &user, &database)?;
-        read_until_ready(&mut stream, false, true)?;
-        Ok(Self {
-            stream: Some(stream),
-        })
-    }
-
-    pub(crate) fn exec_protocol_raw(&mut self, request: impl AsRef<[u8]>) -> io::Result> {
-        let stream = self
-            .stream
-            .as_mut()
-            .ok_or_else(|| io::Error::other("external test client session is already closed"))?;
-        stream
-            .write_all(request.as_ref())
-            .and_then(|()| stream.flush())
-            .map_err(|error| io::Error::other(format!("write external test request: {error}")))?;
-        read_until_ready(stream, true, false)
-    }
-
-    pub(crate) fn close(&mut self) -> io::Result<()> {
-        let Some(mut stream) = self.stream.take() else {
-            return Ok(());
-        };
-        stream
-            .write_all(&[b'X', 0, 0, 0, 4])
-            .and_then(|()| stream.flush())
-            .and_then(|()| stream.shutdown(Shutdown::Both))
-            .map_err(|error| io::Error::other(format!("close external test client: {error}")))
-    }
-}
-
-impl Drop for ExternalRawSession {
-    fn drop(&mut self) {
-        let _ = self.close();
-    }
-}
-
-#[allow(dead_code)]
-pub(crate) fn first_data_row_text_values(mut bytes: &[u8]) -> Vec {
-    while bytes.len() >= 5 {
-        let tag = bytes[0];
-        let length = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
-        if length < 4 {
-            return Vec::new();
-        }
-        let total = 1 + length as usize;
-        if bytes.len() < total {
-            return Vec::new();
-        }
-        if tag == b'D' {
-            return parse_data_row_text_values(&bytes[5..total]);
-        }
-        bytes = &bytes[total..];
-    }
-    Vec::new()
-}
-
-#[allow(dead_code)]
-fn parse_data_row_text_values(payload: &[u8]) -> Vec {
-    if payload.len() < 2 {
-        return Vec::new();
-    }
-    let columns = i16::from_be_bytes([payload[0], payload[1]]);
-    if columns < 0 {
-        return Vec::new();
-    }
-    let mut offset = 2;
-    let mut values = Vec::with_capacity(columns as usize);
-    for _ in 0..columns {
-        if payload.len().saturating_sub(offset) < 4 {
-            return Vec::new();
-        }
-        let length = i32::from_be_bytes([
-            payload[offset],
-            payload[offset + 1],
-            payload[offset + 2],
-            payload[offset + 3],
-        ]);
-        offset += 4;
-        if length == -1 {
-            values.push("NULL".to_owned());
-            continue;
-        }
-        if length < 0 {
-            return Vec::new();
-        }
-        let length = length as usize;
-        if payload.len().saturating_sub(offset) < length {
-            return Vec::new();
-        }
-        values.push(String::from_utf8_lossy(&payload[offset..offset + length]).into_owned());
-        offset += length;
-    }
-    values
-}
-
-fn parse_tcp_connection_string(connection_string: &str) -> io::Result<(String, String, String)> {
-    let target = connection_string
-        .strip_prefix("postgresql://")
-        .ok_or_else(|| io::Error::other("external test connection string is not PostgreSQL TCP"))?;
-    let (user, target) = target
-        .split_once('@')
-        .ok_or_else(|| io::Error::other("external test connection string omitted user"))?;
-    let (address, database) = target
-        .split_once('/')
-        .ok_or_else(|| io::Error::other("external test connection string omitted database"))?;
-    if !address.contains(':') || address.starts_with('/') {
-        return Err(io::Error::other(
-            "external test client requires a TCP server listener",
-        ));
-    }
-    let database = database.split('?').next().unwrap_or(database);
-    Ok((address.to_owned(), user.to_owned(), database.to_owned()))
-}
-
-fn write_startup(stream: &mut TcpStream, user: &str, database: &str) -> io::Result<()> {
-    let mut body = 196_608_i32.to_be_bytes().to_vec();
-    for value in ["user", user, "database", database] {
-        body.extend_from_slice(value.as_bytes());
-        body.push(0);
-    }
-    body.push(0);
-    let length = i32::try_from(body.len() + 4)
-        .map_err(|_| io::Error::other("external test startup packet is too large"))?;
-    stream
-        .write_all(&length.to_be_bytes())
-        .and_then(|()| stream.write_all(&body))
-        .and_then(|()| stream.flush())
-        .map_err(|error| io::Error::other(format!("write external test startup: {error}")))
-}
-
-fn read_until_ready(
-    stream: &mut TcpStream,
-    capture: bool,
-    error_is_fatal: bool,
-) -> io::Result> {
-    let mut response = Vec::new();
-    loop {
-        let mut header = [0_u8; 5];
-        stream.read_exact(&mut header).map_err(|error| {
-            io::Error::other(format!("read external test response header: {error}"))
-        })?;
-        let length = i32::from_be_bytes([header[1], header[2], header[3], header[4]]);
-        if length < 4 {
-            return Err(io::Error::other(format!(
-                "external test server returned invalid frame length {length}"
-            )));
-        }
-        let body_length = usize::try_from(length - 4)
-            .map_err(|_| io::Error::other("external test frame length overflowed"))?;
-        let mut body = vec![0_u8; body_length];
-        stream.read_exact(&mut body).map_err(|error| {
-            io::Error::other(format!("read external test response body: {error}"))
-        })?;
-        if capture {
-            response.extend_from_slice(&header);
-            response.extend_from_slice(&body);
-        }
-        if header[0] == b'E' && error_is_fatal {
-            return Err(io::Error::other(
-                "external test client startup received ErrorResponse",
-            ));
-        }
-        if header[0] == b'Z' {
-            return Ok(response);
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use std::net::TcpListener;
-    use std::thread;
-
-    use super::*;
-
-    #[test]
-    fn external_raw_session_reuses_one_tcp_connection() {
-        let listener = TcpListener::bind(("127.0.0.1", 0)).expect("bind mock PostgreSQL server");
-        let address = listener.local_addr().expect("read mock server address");
-        let server = thread::spawn(move || {
-            let (mut stream, _) = listener.accept().expect("accept external test client");
-            read_startup_packet(&mut stream);
-            write_ready(&mut stream);
-
-            for (expected_sql, error) in [
-                ("CREATE TEMP TABLE proof (id int)", false),
-                ("SELECT broken", true),
-                ("SELECT * FROM proof", false),
-            ] {
-                let request = read_tagged_packet(&mut stream);
-                assert_eq!(request[0], b'Q');
-                assert_eq!(&request[5..request.len() - 1], expected_sql.as_bytes());
-                if error {
-                    write_error_ready(&mut stream);
-                } else {
-                    write_ready(&mut stream);
-                }
-            }
-
-            assert_eq!(read_tagged_packet(&mut stream), [b'X', 0, 0, 0, 4]);
-        });
-
-        let connection_string = format!("postgresql://postgres@{address}/postgres");
-        let mut session =
-            ExternalRawSession::connect(&connection_string).expect("connect external test session");
-        for sql in ["CREATE TEMP TABLE proof (id int)", "SELECT broken"] {
-            let response = session
-                .exec_protocol_raw(raw_query_packet(sql))
-                .expect("execute mock external query");
-            if sql == "SELECT broken" {
-                assert_eq!(response, [b'E', 0, 0, 0, 4, b'Z', 0, 0, 0, 5, b'I']);
-            } else {
-                assert_eq!(response, [b'Z', 0, 0, 0, 5, b'I']);
-            }
-        }
-        let recovered = session
-            .exec_protocol_raw(raw_query_packet("SELECT * FROM proof"))
-            .expect("reuse external session after ErrorResponse");
-        assert_eq!(recovered, [b'Z', 0, 0, 0, 5, b'I']);
-        session.close().expect("close external test session");
-        server.join().expect("join mock PostgreSQL server");
-    }
-
-    fn raw_query_packet(sql: &str) -> Vec {
-        let mut body = sql.as_bytes().to_vec();
-        body.push(0);
-        let mut packet = vec![b'Q'];
-        packet.extend_from_slice(&i32::try_from(body.len() + 4).unwrap().to_be_bytes());
-        packet.extend_from_slice(&body);
-        packet
-    }
-
-    fn read_startup_packet(stream: &mut TcpStream) {
-        let mut length = [0_u8; 4];
-        stream.read_exact(&mut length).expect("read startup length");
-        let body_length = i32::from_be_bytes(length) - 4;
-        assert!(body_length >= 0);
-        let mut body = vec![0_u8; usize::try_from(body_length).unwrap()];
-        stream.read_exact(&mut body).expect("read startup body");
-    }
-
-    fn read_tagged_packet(stream: &mut TcpStream) -> Vec {
-        let mut header = [0_u8; 5];
-        stream.read_exact(&mut header).expect("read packet header");
-        let body_length = i32::from_be_bytes([header[1], header[2], header[3], header[4]]) - 4;
-        assert!(body_length >= 0);
-        let mut packet = header.to_vec();
-        let mut body = vec![0_u8; usize::try_from(body_length).unwrap()];
-        stream.read_exact(&mut body).expect("read packet body");
-        packet.extend_from_slice(&body);
-        packet
-    }
-
-    fn write_ready(stream: &mut TcpStream) {
-        stream
-            .write_all(&[b'Z', 0, 0, 0, 5, b'I'])
-            .and_then(|()| stream.flush())
-            .expect("write ReadyForQuery");
-    }
-
-    fn write_error_ready(stream: &mut TcpStream) {
-        stream
-            .write_all(&[b'E', 0, 0, 0, 4, b'Z', 0, 0, 0, 5, b'I'])
-            .and_then(|()| stream.flush())
-            .expect("write ErrorResponse and ReadyForQuery");
-    }
-}
diff --git a/src/sdks/rust/tools/cargo-artifact-patches.mjs b/src/sdks/rust/tools/cargo-artifact-patches.mjs
deleted file mode 100644
index 5cb8eef8f..000000000
--- a/src/sdks/rust/tools/cargo-artifact-patches.mjs
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env bun
-import fs from 'node:fs/promises';
-import path from 'node:path';
-
-function fail(message) {
-  console.error(`cargo-artifact-patches.mjs: ${message}`);
-  process.exit(2);
-}
-
-function parseArgs(argv) {
-  if (argv.length !== 2) {
-    fail('usage: src/sdks/rust/tools/cargo-artifact-patches.mjs  ');
-  }
-  return {
-    root: path.resolve(argv[0]),
-    manifest: path.isAbsolute(argv[1]) ? argv[1] : path.resolve(argv[0], argv[1]),
-  };
-}
-
-function tomlString(value) {
-  return JSON.stringify(value);
-}
-
-const { root, manifest } = parseArgs(Bun.argv.slice(2));
-let data;
-try {
-  data = JSON.parse(await fs.readFile(manifest, 'utf8'));
-} catch (error) {
-  fail(`could not read Cargo artifact package manifest ${manifest}: ${error.message}`);
-}
-
-if (data === null || typeof data !== 'object' || !Array.isArray(data.packages)) {
-  fail(`${manifest} must contain a packages array`);
-}
-
-for (const [index, artifact] of data.packages.entries()) {
-  if (artifact === null || typeof artifact !== 'object' || Array.isArray(artifact)) {
-    fail(`${manifest} package row ${index} must be an object`);
-  }
-  const { name, manifestPath } = artifact;
-  if (typeof name !== 'string' || name.length === 0) {
-    fail(`${manifest} package row ${index} must declare a non-empty name`);
-  }
-  if (typeof manifestPath !== 'string' || manifestPath.length === 0) {
-    fail(`${manifest} package row ${index} must declare a non-empty manifestPath`);
-  }
-  const artifactManifest = path.isAbsolute(manifestPath)
-    ? manifestPath
-    : path.join(root, manifestPath);
-  console.log(`${name} = { path = ${tomlString(path.dirname(artifactManifest))} }`);
-}
diff --git a/src/sdks/rust/tools/check-release-consumer.sh b/src/sdks/rust/tools/check-release-consumer.sh
deleted file mode 100755
index dc36708e3..000000000
--- a/src/sdks/rust/tools/check-release-consumer.sh
+++ /dev/null
@@ -1,148 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "check-release-consumer.sh: must run inside the Oliphaunt checkout" >&2
-  exit 1
-}
-cd "$root"
-
-scratch=""
-cleanup() {
-  [ -z "$scratch" ] || rm -rf "$scratch"
-}
-trap cleanup EXIT
-
-fail() {
-  echo "check-release-consumer.sh: $*" >&2
-  exit 1
-}
-
-require_file() {
-  [ -s "$1" ] || fail "missing or empty file: $1"
-}
-
-find_one() {
-  local directory="$1"
-  local pattern="$2"
-  local matches=()
-  while IFS= read -r file; do
-    matches+=("$file")
-  done < <(find "$directory" -type f -name "$pattern" -print)
-  [ "${#matches[@]}" -eq 1 ] ||
-    fail "expected one $pattern under $directory, found ${#matches[@]}"
-  printf '%s\n' "${matches[0]}"
-}
-
-require_linux_x64() {
-  [ "$(uname -s)" = "Linux" ] || fail "release consumer requires Linux"
-  case "$(uname -m)" in
-    x86_64|amd64) ;;
-    *) fail "release consumer requires x64, found $(uname -m)" ;;
-  esac
-}
-
-build_consumer() {
-  local sdk_artifacts="$1"
-  local output="$2"
-  local crate packed_manifest metadata dependency_rows name version stub
-  local manifests=()
-  [ -d "$sdk_artifacts" ] || fail "Rust SDK artifact directory is missing: $sdk_artifacts"
-  crate="$(find_one "$sdk_artifacts" 'oliphaunt-[0-9]*.crate')"
-  scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-rust-release-consumer-build.XXXXXX")"
-
-  mkdir -p "$scratch/unpacked" "$scratch/packed" "$scratch/consumer/src" "$scratch/consumer/.cargo"
-  tar -xzf "$crate" -C "$scratch/unpacked"
-  while IFS= read -r file; do
-    manifests+=("$file")
-  done < <(find "$scratch/unpacked" -mindepth 2 -maxdepth 2 -type f -name Cargo.toml -print)
-  [ "${#manifests[@]}" -eq 1 ] ||
-    fail "packed crate must contain one root Cargo.toml, found ${#manifests[@]}"
-  packed_manifest="${manifests[0]}"
-  mv "$(dirname "$packed_manifest")" "$scratch/packed/oliphaunt"
-  cp src/sdks/rust/tests/release-consumer/Cargo.toml "$scratch/consumer/Cargo.toml"
-  cp src/sdks/rust/tests/release-consumer/src/main.rs "$scratch/consumer/src/main.rs"
-
-  metadata="$scratch/metadata.json"
-  dependency_rows="$scratch/artifact-dependencies.tsv"
-  cargo metadata --manifest-path "$scratch/packed/oliphaunt/Cargo.toml" \
-    --format-version 1 --no-deps --offline >"$metadata"
-  OLIPHAUNT_CARGO_METADATA="$metadata" tools/dev/bun.sh -e '
-    const metadata = await Bun.file(process.env.OLIPHAUNT_CARGO_METADATA).json();
-    for (const dependency of metadata.packages[0].dependencies) {
-      if (dependency.name.startsWith("liboliphaunt-native-") || dependency.name.startsWith("oliphaunt-broker-")) {
-        const version = dependency.req.match(/^=([0-9A-Za-z.+-]+)$/)?.[1];
-        if (!version) throw new Error(`artifact dependency ${dependency.name} must use an exact version`);
-        console.log(`${dependency.name}\t${version}`);
-      }
-    }
-  ' | sort -u >"$dependency_rows"
-  for pattern in '^liboliphaunt-native-' '^oliphaunt-broker-'; do
-    rg -q "$pattern" "$dependency_rows" || fail "packed crate is missing artifact dependency $pattern"
-  done
-
-  {
-    printf '[net]\noffline = true\n\n[patch.crates-io]\n'
-    while IFS=$'\t' read -r name version; do
-      stub="$scratch/stubs/$name"
-      mkdir -p "$stub/src"
-      printf '[package]\nname = "%s"\nversion = "%s"\nedition = "2024"\npublish = false\n\n[lib]\npath = "src/lib.rs"\n' \
-        "$name" "$version" >"$stub/Cargo.toml"
-      printf '#![forbid(unsafe_code)]\n' >"$stub/src/lib.rs"
-      printf '"%s" = { path = "%s" }\n' "$name" "$stub"
-    done <"$dependency_rows"
-  } >"$scratch/consumer/.cargo/config.toml"
-
-  CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$scratch/target}" \
-    cargo --config "$scratch/consumer/.cargo/config.toml" generate-lockfile \
-      --manifest-path "$scratch/consumer/Cargo.toml" --offline
-  CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$scratch/target}" \
-    cargo --config "$scratch/consumer/.cargo/config.toml" build \
-      --manifest-path "$scratch/consumer/Cargo.toml" --locked --offline --release
-  mkdir -p "$(dirname "$output")"
-  install -m 0755 \
-    "${CARGO_TARGET_DIR:-$scratch/target}/release/oliphaunt-rust-release-consumer" "$output"
-  echo "Built packed-crate Rust release consumer: $output"
-}
-
-run_consumer() {
-  local consumer="$1"
-  local native_assets="$2"
-  local runtime_archive tools_archive install_dir tools_dir
-  require_linux_x64
-  require_file "$consumer"
-  [ -x "$consumer" ] || fail "release consumer is not executable: $consumer"
-  [ -d "$native_assets" ] || fail "native asset directory is missing: $native_assets"
-  runtime_archive="$(find_one "$native_assets" 'liboliphaunt-*-linux-x64-gnu.tar.gz')"
-  tools_archive="$(find_one "$native_assets" 'oliphaunt-tools-*-linux-x64-gnu.tar.gz')"
-  scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-rust-release-consumer-run.XXXXXX")"
-
-  mkdir -p "$scratch/native" "$scratch/tools" "$scratch/runtime-cache"
-  tar -xzf "$runtime_archive" -C "$scratch/native"
-  tar -xzf "$tools_archive" -C "$scratch/tools"
-  install_dir="$scratch/native/runtime"
-  tools_dir="$scratch/tools/runtime"
-  for file in "$install_dir/bin/postgres" "$install_dir/bin/initdb" "$install_dir/bin/pg_ctl" \
-    "$tools_dir/bin/pg_basebackup" "$tools_dir/bin/pg_dump" "$tools_dir/bin/psql"; do
-    require_file "$file"
-  done
-
-  env \
-    OLIPHAUNT_INSTALL_DIR="$install_dir" \
-    OLIPHAUNT_TOOLS_DIR="$tools_dir" \
-    OLIPHAUNT_RUNTIME_CACHE_DIR="$scratch/runtime-cache" \
-    LD_LIBRARY_PATH="$install_dir/lib:$scratch/native/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \
-    "$consumer" "$scratch/database"
-}
-
-case "${1:-}" in
-  build)
-    [ "$#" -eq 3 ] || fail "usage: $0 build SDK_ARTIFACT_DIR OUTPUT"
-    build_consumer "$2" "$3"
-    ;;
-  run)
-    [ "$#" -eq 3 ] || fail "usage: $0 run CONSUMER NATIVE_ASSET_DIR"
-    run_consumer "$2" "$3"
-    ;;
-  *) fail "usage: $0 {build SDK_ARTIFACT_DIR OUTPUT|run CONSUMER NATIVE_ASSET_DIR}" ;;
-esac
diff --git a/src/sdks/rust/tools/package-source.mjs b/src/sdks/rust/tools/package-source.mjs
deleted file mode 100644
index c87768edd..000000000
--- a/src/sdks/rust/tools/package-source.mjs
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env node
-import {
-  copyFileSync,
-  cpSync,
-  mkdirSync,
-  readFileSync,
-  rmSync,
-  writeFileSync,
-} from "node:fs";
-import path from "node:path";
-
-export const ROOT = path.resolve(import.meta.dirname, "../../../..");
-
-function copy(source, destination) {
-  mkdirSync(path.dirname(destination), { recursive: true });
-  copyFileSync(source, destination);
-}
-
-export function stageRustPackageSource(outputDir) {
-  const destination = path.resolve(ROOT, outputDir);
-  const relative = path.relative(ROOT, destination);
-  if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
-    throw new Error(`Rust package stage must stay inside the repository: ${outputDir}`);
-  }
-
-  rmSync(destination, { recursive: true, force: true });
-  cpSync(path.join(ROOT, "src/sdks/rust"), destination, {
-    recursive: true,
-    filter: (source) => path.basename(source) !== "target",
-  });
-  rmSync(path.join(destination, "crates/oliphaunt-build"), { recursive: true, force: true });
-  cpSync(path.join(ROOT, "src/shared/fixtures"), path.join(destination, "testdata"), {
-    recursive: true,
-    filter: (source) => path.basename(source) !== "moon.yml",
-  });
-  copy(
-    path.join(ROOT, "src/shared/rust-query-core/query_core.rs"),
-    path.join(destination, "src/query_core.rs"),
-  );
-  copy(path.join(ROOT, "LICENSE"), path.join(destination, "LICENSE"));
-  copy(path.join(ROOT, "THIRD_PARTY_NOTICES.md"), path.join(destination, "THIRD_PARTY_NOTICES.md"));
-
-  const manifest = path.join(destination, "Cargo.toml");
-  let text = readFileSync(manifest, "utf8")
-    .replace("repository.workspace = true", 'repository = "https://github.com/f0rr0/oliphaunt"')
-    .replace("homepage.workspace = true", 'homepage = "https://oliphaunt.dev"');
-  if (!text.includes("[workspace]")) text = `${text.trimEnd()}\n\n[workspace]\n`;
-  writeFileSync(manifest, text, "utf8");
-  return manifest;
-}
-
-if (import.meta.main) {
-  const output = process.argv[2] ?? "target/liboliphaunt-sdk-check/oliphaunt-rust/package-source";
-  console.log(path.relative(ROOT, stageRustPackageSource(output)));
-}
diff --git a/src/sdks/swift/.swift-version b/src/sdks/swift/.swift-version
new file mode 100644
index 000000000..7849b73dc
--- /dev/null
+++ b/src/sdks/swift/.swift-version
@@ -0,0 +1 @@
+6.3.3
diff --git a/src/sdks/swift/CHANGELOG.md b/src/sdks/swift/CHANGELOG.md
index 456636727..31cdae3bb 100644
--- a/src/sdks/swift/CHANGELOG.md
+++ b/src/sdks/swift/CHANGELOG.md
@@ -6,7 +6,6 @@
 ### ⚠ BREAKING CHANGES
 
 * **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
-* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.
 * **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
 
 ### Features
diff --git a/src/sdks/swift/Package.resolved b/src/sdks/swift/Package.resolved
deleted file mode 100644
index 92d5e61a2..000000000
--- a/src/sdks/swift/Package.resolved
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "originHash" : "19cbc346cefec85c6d9cad47d3bb6c3e83d2b178ca97dbf92b4a1e39146bcd5d",
-  "pins" : [
-    {
-      "identity" : "swift-docc-plugin",
-      "kind" : "remoteSourceControl",
-      "location" : "https://github.com/swiftlang/swift-docc-plugin",
-      "state" : {
-        "revision" : "647c708be89f834fa6a6d4945442793a77ddf5b6",
-        "version" : "1.5.0"
-      }
-    },
-    {
-      "identity" : "swift-docc-symbolkit",
-      "kind" : "remoteSourceControl",
-      "location" : "https://github.com/swiftlang/swift-docc-symbolkit",
-      "state" : {
-        "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34",
-        "version" : "1.0.0"
-      }
-    }
-  ],
-  "version" : 3
-}
diff --git a/src/sdks/swift/Package.swift b/src/sdks/swift/Package.swift
index 21bf1b803..84dbb07fb 100644
--- a/src/sdks/swift/Package.swift
+++ b/src/sdks/swift/Package.swift
@@ -1,6 +1,10 @@
 // swift-tools-version: 6.0
 
 import PackageDescription
+import Foundation
+
+let nativeBindings = URL(fileURLWithPath: #filePath).deletingLastPathComponent()
+    .appendingPathComponent(".build/native-bindings")
 
 let package = Package(
     name: "Oliphaunt",
@@ -13,17 +17,26 @@ let package = Package(
         .library(name: "Oliphaunt", targets: ["Oliphaunt"]),
         .library(name: "OliphauntExtensionSupport", targets: ["OliphauntExtensionSupport"])
     ],
-    dependencies: [
-        .package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.4.0")
-    ],
     targets: [
+        .systemLibrary(
+            name: "OliphauntNativeBindingsFFI",
+            path: ".build/native-bindings/ffi"
+        ),
+        .target(
+            name: "OliphauntNativeBindings",
+            dependencies: ["OliphauntNativeBindingsFFI"],
+            path: ".build/native-bindings/swift",
+            linkerSettings: [.unsafeFlags([
+                nativeBindings.appendingPathComponent("liboliphaunt_mobile_bindings.a").path
+            ])]
+        ),
         .target(
             name: "COliphaunt",
             publicHeadersPath: "include"
         ),
         .target(
             name: "Oliphaunt",
-            dependencies: ["COliphaunt"]
+            dependencies: ["COliphaunt", "OliphauntNativeBindings"]
         ),
         .target(
             name: "OliphauntExtensionSupport",
diff --git a/src/sdks/swift/README.md b/src/sdks/swift/README.md
index 75ac0718e..0c7f8bc58 100644
--- a/src/sdks/swift/README.md
+++ b/src/sdks/swift/README.md
@@ -24,12 +24,14 @@ PostgreSQL, or copy local Oliphaunt artifacts. SwiftPM resolves the Swift API
 and checksum-pinned binary/runtime assets for the selected release.
 
 Base Apple packages do not include full ICU data. Applications that need
-PostgreSQL ICU collations add the `OliphauntICU` SwiftPM product to the same app
-target as `Oliphaunt`. The generated release manifest exposes `OliphauntICU` as
-a resource-only product containing the canonical ICU data. The target runtime
-resources carry the matching platform-qualified cluster seed, and `Oliphaunt`
-resolves the pair as one checked closure. Do not add `OliphauntICU` for
-applications that do not use ICU collations.
+PostgreSQL ICU collations select `OliphauntICU` from the independent database
+resources package. First-open iOS initialization also selects
+`OliphauntSeedNativeIOSStandard` or `OliphauntSeedNativeIOSICU`; the ICU seed
+product depends on the canonical ICU data product. Existing PGDATA does not
+require a seed dependency. The SDK discovers selected resource bundles and
+validates their native compatibility and ICU data binding. See
+[database resources](../../database-resources/README.md) for its source archive
+and distribution status.
 
 Optional PostgreSQL extensions are exact-extension artifacts. PostgreSQL 18
 contrib members share the logical `oliphaunt-extension-contrib-pg18` artifact;
@@ -314,35 +316,38 @@ the extracted PGDATA.
 
 ## Local Development
 
+Build and source tests run on Linux and macOS. Linux CI installs the exact Swift
+version in `.swift-version`; Apple qualification uses the pinned Xcode toolchain.
 For local contributor tests from this repository:
 
 ```bash
 cd src/sdks/swift
-swift test
+bash tools/swift.sh test
 ```
 
-To run the native C ABI smoke from Swift:
+To run the native first-open smoke on macOS with built runtime assets:
 
 ```bash
+OLIPHAUNT_SWIFT_REQUIRE_NATIVE=1 \
 LIBOLIPHAUNT_PATH=/path/to/liboliphaunt.dylib \
 OLIPHAUNT_INSTALL_DIR=/path/to/postgres/install \
-swift test
+bash tools/swift.sh test --filter NativeRuntimeTests
 ```
 
-The native-direct env-backed test opens temporary storage, executes `SELECT 1`
-through PostgreSQL protocol bytes, cancels an active
-`pg_sleep`, creates a
-same-version physical backup through the C ABI, restores it into a new destination, and
-closes the runtime. Exact extensions are accepted when the app links their
-generated SwiftPM products and calls each product's `register()` method before
-opening the database. Extension names are validated before loading native code.
+The native test opens fresh storage, executes a parameterized query, checks a
+PostgreSQL error, and closes the database. Other platforms require a packaged
+cluster seed for first open. `moon run oliphaunt-swift:test-native` first builds
+the runtime, then runs this suite; it does not rerun runtime-owner tests.
+
+`package-source` creates a portable source ZIP without invoking Swift. `package`
+stages the release manifest and carrier metadata from completed Apple assets.
+Actual Apple binary linking and app/device execution remain Apple checks.
 
 For iOS and app-bundled macOS builds, generated products package resources using
 this layout; the SDK discovers them automatically:
 
 ```text
 oliphaunt/
-  manifest.properties
   runtime/
     manifest.properties
     files/
@@ -365,8 +370,9 @@ application receives one target-qualified closure. React Native uses the separat
 composes its app-owned resource bundle; there is no generic or multi-target
 runtime-resource archive.
 
-The root receipt binds the closure to one seed target and the two sibling seed
-paths. Both seed manifests use the exact native cluster-seed contract; extension
+The runtime manifest identifies its physical target. Initialization seed packages
+are selected separately; they are not bundled into the SDK or runtime.
+Selected seed manifests use the exact native cluster-seed contract; extension
 selection and static-registry metadata belong only to the runtime manifest.
 `runtime/manifest.properties` must include
 `schema=oliphaunt-runtime-resources-v1`,
@@ -397,7 +403,7 @@ storage whose `pgdata` child contains `PG_VERSION`; they do not rely on executin
 When a selected extension contains native modules, the Swift package must
 link those modules with the generated static-registry source. Complete Rust
 runtime-resource generator output includes
-`static-registry/oliphaunt_static_registry.c`; the Swift C bridge discovers
+`static-registry/oliphaunt_static_registry.c`; the shared Rust binding discovers
 `liboliphaunt_selected_static_extensions` and registers the returned rows
 through `oliphaunt_register_static_extensions` before the first database open.
 The manifest state is a release gate, not a loader substitute.
@@ -417,3 +423,18 @@ SQL symbols. If an app selects `vector` but omits the matching prebuilt
 shipping an app that fails later at `CREATE EXTENSION vector`.
 The generated resource root also includes `package-size.tsv` for release and
 bundle-size auditing.
+
+For checkout builds, run `bash tools/swift.sh build` or `bash tools/swift.sh test`
+inside `src/sdks/swift`, or use the corresponding Moon tasks. The Shell entry point
+builds the Rust dependency and generates the Swift bridge before invoking SwiftPM.
+Published packages use the SDK-owned bindings XCFramework and require no Rust
+toolchain. Runtime assets and optional database resources remain independent.
+
+`moon run oliphaunt-swift:build` and `moon run oliphaunt-swift:test` prepare the
+Rust bridge before invoking SwiftPM. These source checks work on Linux with
+Swift, Rust and Bun installed. `moon run oliphaunt-swift:test-native` additionally
+builds the host PostgreSQL runtime and exercises the native facade.
+`moon run oliphaunt-swift:package` produces the source and bindings carriers plus
+their native runtime prerequisites; its Apple XCFramework tasks require macOS,
+Xcode and the declared Apple Rust targets. Source checks do not imply that this
+Apple package or an installed iOS application has been qualified.
diff --git a/src/sdks/swift/Sources/COliphaunt/bridge.c b/src/sdks/swift/Sources/COliphaunt/bridge.c
deleted file mode 100644
index ee463af1b..000000000
--- a/src/sdks/swift/Sources/COliphaunt/bridge.c
+++ /dev/null
@@ -1,464 +0,0 @@
-#if defined(__APPLE__) && !defined(_DARWIN_C_SOURCE)
-#define _DARWIN_C_SOURCE 1
-#endif
-
-#include "COliphaunt.h"
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-typedef int32_t (*OliphauntInitFn)(const OliphauntConfig *config, OliphauntHandle **out);
-typedef int32_t (*OliphauntExecProtocolFn)(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out);
-typedef int32_t (*OliphauntExecProtocolRawStreamFn)(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context);
-typedef int32_t (*OliphauntCancelFn)(OliphauntHandle *handle);
-typedef int32_t (*OliphauntDetachFn)(OliphauntHandle *handle);
-typedef int32_t (*OliphauntCloseFn)(OliphauntHandle *handle);
-typedef int32_t (*OliphauntRegisterStaticExtensionsFn)(const OliphauntStaticExtension *extensions, size_t count);
-typedef const OliphauntStaticExtension *(*OliphauntSelectedStaticExtensionsFn)(size_t *count);
-typedef size_t (*OliphauntCopyLastErrorFn)(
-    OliphauntHandle *handle,
-    char *out,
-    size_t capacity);
-typedef const char *(*OliphauntVersionFn)(void);
-typedef void (*OliphauntFreeResponseFn)(OliphauntResponse *response);
-typedef int32_t (*OliphauntBackupFn)(
-    OliphauntHandle *handle,
-    OliphauntResponse *out);
-typedef int32_t (*OliphauntRestoreFn)(const OliphauntRestoreOptions *options);
-
-typedef struct OliphauntSymbols {
-    void *library;
-    bool owns_library;
-    OliphauntInitFn init;
-    OliphauntExecProtocolFn exec_protocol;
-    OliphauntExecProtocolRawStreamFn exec_protocol_raw_stream;
-    OliphauntCancelFn cancel;
-    OliphauntDetachFn detach;
-    OliphauntCloseFn close;
-    OliphauntRegisterStaticExtensionsFn register_static_extensions;
-    OliphauntCopyLastErrorFn copy_last_error;
-    OliphauntVersionFn version;
-    OliphauntFreeResponseFn free_response;
-    OliphauntBackupFn backup;
-    OliphauntRestoreFn restore;
-} OliphauntSymbols;
-
-struct OliphauntSession {
-    OliphauntSymbols symbols;
-    OliphauntHandle *handle;
-    pthread_mutex_t error_lock;
-    char *last_error;
-};
-
-static char *global_last_error;
-static pthread_mutex_t global_error_lock = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_global_error(const char *message) {
-    const char *resolved = message ? message : "unknown liboliphaunt Swift bridge error";
-    char *owned = strdup(resolved);
-    pthread_mutex_lock(&global_error_lock);
-    if (owned != NULL) {
-        free(global_last_error);
-        global_last_error = owned;
-    }
-    pthread_mutex_unlock(&global_error_lock);
-}
-
-static void set_session_error(OliphauntSession *session, const char *message) {
-    if (session == NULL) {
-        set_global_error(message);
-        return;
-    }
-    const char *resolved = message ? message : "unknown liboliphaunt Swift bridge error";
-    char *owned = strdup(resolved);
-    pthread_mutex_lock(&session->error_lock);
-    if (owned != NULL) {
-        free(session->last_error);
-        session->last_error = owned;
-    }
-    pthread_mutex_unlock(&session->error_lock);
-}
-
-static char *copy_native_error(
-    OliphauntSymbols *symbols,
-    OliphauntHandle *handle,
-    const char *fallback) {
-    if (symbols == NULL || symbols->copy_last_error == NULL) {
-        return strdup(fallback);
-    }
-    size_t required = symbols->copy_last_error(handle, NULL, 0);
-    for (int attempt = 0; attempt < 3 && required < SIZE_MAX; attempt += 1) {
-        char *message = (char *)calloc(required + 1, 1);
-        if (message == NULL) {
-            break;
-        }
-        size_t current_required = symbols->copy_last_error(
-            handle,
-            message,
-            required + 1);
-        if (current_required <= required) {
-            if (message[0] != '\0') {
-                return message;
-            }
-            free(message);
-            break;
-        }
-        free(message);
-        required = current_required;
-    }
-    return strdup(fallback);
-}
-
-static void set_global_native_error(
-    OliphauntSymbols *symbols,
-    OliphauntHandle *handle,
-    const char *fallback) {
-    char *message = copy_native_error(
-        symbols,
-        handle,
-        fallback);
-    set_global_error(message);
-    free(message);
-}
-
-static void set_session_native_error(
-    OliphauntSession *session,
-    const char *fallback) {
-    if (session == NULL) {
-        set_global_error(fallback);
-        return;
-    }
-    char *message = copy_native_error(
-        &session->symbols,
-        session->handle,
-        fallback);
-    set_session_error(session, message);
-    free(message);
-}
-
-static const char *env_library_path(void) {
-    const char *path = getenv("OLIPHAUNT_SWIFT_LIBRARY");
-    if (path == NULL || path[0] == '\0') {
-        path = getenv("LIBOLIPHAUNT_PATH");
-    }
-    if (path == NULL || path[0] == '\0') {
-        path = getenv("OLIPHAUNT_LIBRARY");
-    }
-    return path != NULL && path[0] != '\0' ? path : NULL;
-}
-
-static void *symbol_lookup_handle(OliphauntSymbols *symbols) {
-    return symbols->library != NULL ? symbols->library : RTLD_DEFAULT;
-}
-
-static int load_symbol(OliphauntSymbols *symbols, const char *name, void **out) {
-    dlerror();
-    *out = dlsym(symbol_lookup_handle(symbols), name);
-    const char *error = dlerror();
-    if (error != NULL || *out == NULL) {
-        char message[1024];
-        snprintf(message, sizeof(message), "liboliphaunt symbol %s is unavailable: %s", name, error ? error : "symbol not found");
-        set_global_error(message);
-        return -1;
-    }
-    return 0;
-}
-
-static void unload_symbols(OliphauntSymbols *symbols) {
-    /*
-     * liboliphaunt embeds PostgreSQL, which owns process-global runtime state
-     * while a backend session is active. Ordinary SDK close calls oliphaunt_detach;
-     * oliphaunt_close is terminal for the process lifetime. Unloading the code
-     * image can leave host-process callbacks or handlers pointing at unmapped
-     * addresses. Keep the native engine resident once it has been loaded.
-     */
-    memset(symbols, 0, sizeof(*symbols));
-}
-
-static int load_symbols(const char *library_path, OliphauntSymbols *symbols) {
-    memset(symbols, 0, sizeof(*symbols));
-
-    const char *path = library_path != NULL && library_path[0] != '\0'
-        ? library_path
-        : env_library_path();
-    if (path != NULL) {
-        symbols->library = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
-        if (symbols->library == NULL) {
-            char message[1024];
-            snprintf(message, sizeof(message), "failed to load liboliphaunt at %s: %s", path, dlerror());
-            set_global_error(message);
-            return -1;
-        }
-        symbols->owns_library = true;
-    }
-
-    if (load_symbol(symbols, "oliphaunt_init", (void **)&symbols->init) != 0 ||
-        load_symbol(symbols, "oliphaunt_exec_protocol", (void **)&symbols->exec_protocol) != 0 ||
-        load_symbol(symbols, "oliphaunt_exec_protocol_raw_stream", (void **)&symbols->exec_protocol_raw_stream) != 0 ||
-        load_symbol(symbols, "oliphaunt_cancel", (void **)&symbols->cancel) != 0 ||
-        load_symbol(symbols, "oliphaunt_detach", (void **)&symbols->detach) != 0 ||
-        load_symbol(symbols, "oliphaunt_close", (void **)&symbols->close) != 0 ||
-        load_symbol(symbols, "oliphaunt_register_static_extensions", (void **)&symbols->register_static_extensions) != 0 ||
-        load_symbol(symbols, "oliphaunt_copy_last_error", (void **)&symbols->copy_last_error) != 0 ||
-        load_symbol(symbols, "oliphaunt_version", (void **)&symbols->version) != 0 ||
-        load_symbol(symbols, "oliphaunt_free_response", (void **)&symbols->free_response) != 0 ||
-        load_symbol(symbols, "oliphaunt_backup", (void **)&symbols->backup) != 0 ||
-        load_symbol(symbols, "oliphaunt_restore", (void **)&symbols->restore) != 0) {
-        unload_symbols(symbols);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int register_selected_static_extensions(OliphauntSymbols *symbols) {
-    dlerror();
-    OliphauntSelectedStaticExtensionsFn selected = NULL;
-    if (symbols->library != NULL) {
-        selected = (OliphauntSelectedStaticExtensionsFn)dlsym(
-            symbols->library,
-            "liboliphaunt_selected_static_extensions");
-        const char *library_error = dlerror();
-        if (library_error != NULL) {
-            selected = NULL;
-        }
-        dlerror();
-    }
-    if (selected == NULL) {
-        selected = (OliphauntSelectedStaticExtensionsFn)dlsym(
-            RTLD_DEFAULT,
-            "liboliphaunt_selected_static_extensions");
-    }
-    const char *error = dlerror();
-    if (selected == NULL || error != NULL) {
-        return 0;
-    }
-    size_t count = 0;
-    const OliphauntStaticExtension *extensions = selected(&count);
-    if (count == 0) {
-        return 0;
-    }
-    if (extensions == NULL) {
-        set_global_error("selected liboliphaunt static extension registry returned null extensions");
-        return -1;
-    }
-    if (symbols->register_static_extensions(extensions, count) != 0) {
-        set_global_native_error(
-            symbols,
-            NULL,
-            "liboliphaunt static extension registration failed");
-        return -1;
-    }
-    return 0;
-}
-
-int32_t oliphaunt_swift_open(
-    const char *library_path,
-    const OliphauntConfig *config,
-    OliphauntSession **out) {
-    if (out == NULL) {
-        set_global_error("oliphaunt_swift_open out parameter is null");
-        return -1;
-    }
-    *out = NULL;
-    if (config == NULL) {
-        set_global_error("oliphaunt_swift_open config is null");
-        return -1;
-    }
-
-    OliphauntSession *session = (OliphauntSession *)calloc(1, sizeof(OliphauntSession));
-    if (session == NULL) {
-        set_global_error("out of memory allocating OliphauntSession");
-        return -1;
-    }
-    int error_lock_status = pthread_mutex_init(&session->error_lock, NULL);
-    if (error_lock_status != 0) {
-        char message[256];
-        snprintf(
-            message,
-            sizeof(message),
-            "failed to initialize OliphauntSession error mutex: %s (%d)",
-            strerror(error_lock_status),
-            error_lock_status);
-        set_global_error(message);
-        free(session);
-        return -1;
-    }
-    if (load_symbols(library_path, &session->symbols) != 0) {
-        pthread_mutex_destroy(&session->error_lock);
-        free(session->last_error);
-        free(session);
-        return -1;
-    }
-    if (register_selected_static_extensions(&session->symbols) != 0) {
-        unload_symbols(&session->symbols);
-        pthread_mutex_destroy(&session->error_lock);
-        free(session->last_error);
-        free(session);
-        return -1;
-    }
-    if (session->symbols.init(config, &session->handle) != 0) {
-        set_global_native_error(
-            &session->symbols,
-            session->handle,
-            "unknown liboliphaunt Swift runtime error");
-        unload_symbols(&session->symbols);
-        pthread_mutex_destroy(&session->error_lock);
-        free(session->last_error);
-        free(session);
-        return -1;
-    }
-
-    *out = session;
-    return 0;
-}
-
-int32_t oliphaunt_swift_exec_protocol(
-    OliphauntSession *session,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out) {
-    if (session == NULL || out == NULL) {
-        set_session_error(session, "invalid oliphaunt_swift_exec_protocol arguments");
-        return -1;
-    }
-    int32_t rc = session->symbols.exec_protocol(session->handle, request, request_len, out);
-    if (rc != 0) {
-        set_session_native_error(session, "unknown liboliphaunt Swift runtime error");
-    }
-    return rc;
-}
-
-int32_t oliphaunt_swift_exec_protocol_raw_stream(
-    OliphauntSession *session,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context) {
-    if (session == NULL || callback == NULL) {
-        set_session_error(session, "invalid oliphaunt_swift_exec_protocol_raw_stream arguments");
-        return -1;
-    }
-    int32_t rc = session->symbols.exec_protocol_raw_stream(
-        session->handle,
-        request,
-        request_len,
-        callback,
-        callback_context);
-    if (rc != 0) {
-        set_session_native_error(session, "unknown liboliphaunt Swift runtime error");
-    }
-    return rc;
-}
-
-int32_t oliphaunt_swift_backup(OliphauntSession *session, OliphauntResponse *out) {
-    if (session == NULL || out == NULL) {
-        set_session_error(session, "invalid oliphaunt_swift_backup arguments");
-        return -1;
-    }
-    int32_t rc = session->symbols.backup(session->handle, out);
-    if (rc != 0) {
-        set_session_native_error(session, "unknown liboliphaunt Swift runtime error");
-    }
-    return rc;
-}
-
-int32_t oliphaunt_swift_restore(const char *library_path, const OliphauntRestoreOptions *options) {
-    OliphauntSymbols symbols;
-    if (load_symbols(library_path, &symbols) != 0) {
-        return -1;
-    }
-    int32_t rc = symbols.restore(options);
-    if (rc != 0) {
-        set_global_native_error(
-            &symbols,
-            NULL,
-            "unknown liboliphaunt Swift restore error");
-    }
-    unload_symbols(&symbols);
-    return rc;
-}
-
-int32_t oliphaunt_swift_cancel(OliphauntSession *session) {
-    if (session == NULL) {
-        set_global_error("invalid oliphaunt_swift_cancel arguments");
-        return -1;
-    }
-    int32_t rc = session->symbols.cancel(session->handle);
-    if (rc != 0) {
-        set_session_native_error(session, "unknown liboliphaunt Swift runtime error");
-    }
-    return rc;
-}
-
-int32_t oliphaunt_swift_close(OliphauntSession *session) {
-    if (session == NULL) {
-        return 0;
-    }
-    int32_t rc = 0;
-    if (session->symbols.detach != NULL && session->handle != NULL) {
-        rc = session->symbols.detach(session->handle);
-        if (rc != 0) {
-            set_session_native_error(session, "unknown liboliphaunt Swift close error");
-            pthread_mutex_lock(&session->error_lock);
-            set_global_error(session->last_error);
-            pthread_mutex_unlock(&session->error_lock);
-        }
-        if (rc != 0) {
-            return rc;
-        }
-        session->handle = NULL;
-    }
-    unload_symbols(&session->symbols);
-    free(session->last_error);
-    pthread_mutex_destroy(&session->error_lock);
-    free(session);
-    return rc;
-}
-
-size_t oliphaunt_swift_copy_last_error(
-    OliphauntSession *session,
-    char *out,
-    size_t capacity) {
-    pthread_mutex_t *lock = session != NULL ? &session->error_lock : &global_error_lock;
-    pthread_mutex_lock(lock);
-    const char *message = session != NULL ? session->last_error : global_last_error;
-    if (message == NULL) {
-        message = "unknown liboliphaunt Swift bridge error";
-    }
-    size_t length = strlen(message);
-    if (capacity > 0 && out != NULL) {
-        size_t copied = length < capacity - 1 ? length : capacity - 1;
-        memcpy(out, message, copied);
-        out[copied] = '\0';
-    }
-    pthread_mutex_unlock(lock);
-    return length;
-}
-
-const char *oliphaunt_swift_version(OliphauntSession *session) {
-    if (session == NULL || session->symbols.version == NULL) {
-        return "";
-    }
-    return session->symbols.version();
-}
-
-void oliphaunt_swift_free_response(OliphauntSession *session, OliphauntResponse *response) {
-    if (session == NULL || response == NULL || session->symbols.free_response == NULL) {
-        return;
-    }
-    session->symbols.free_response(response);
-}
diff --git a/src/sdks/swift/Sources/COliphaunt/empty.c b/src/sdks/swift/Sources/COliphaunt/empty.c
deleted file mode 100644
index 52f3bd778..000000000
--- a/src/sdks/swift/Sources/COliphaunt/empty.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "COliphaunt.h"
diff --git a/src/sdks/swift/Sources/COliphaunt/include/COliphaunt.h b/src/sdks/swift/Sources/COliphaunt/include/COliphaunt.h
index 6ee0734b8..be7d525f7 100644
--- a/src/sdks/swift/Sources/COliphaunt/include/COliphaunt.h
+++ b/src/sdks/swift/Sources/COliphaunt/include/COliphaunt.h
@@ -1,34 +1,5 @@
 #ifndef C_OLIPHAUNT_H
 #define C_OLIPHAUNT_H
-
 #include "oliphaunt.h"
-
-typedef struct OliphauntSession OliphauntSession;
-
-int32_t oliphaunt_swift_open(
-    const char *library_path,
-    const OliphauntConfig *config,
-    OliphauntSession **out);
-int32_t oliphaunt_swift_exec_protocol(
-    OliphauntSession *session,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out);
-int32_t oliphaunt_swift_exec_protocol_raw_stream(
-    OliphauntSession *session,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context);
-int32_t oliphaunt_swift_backup(OliphauntSession *session, OliphauntResponse *out);
-int32_t oliphaunt_swift_restore(const char *library_path, const OliphauntRestoreOptions *options);
-int32_t oliphaunt_swift_cancel(OliphauntSession *session);
-int32_t oliphaunt_swift_close(OliphauntSession *session);
-size_t oliphaunt_swift_copy_last_error(
-    OliphauntSession *session,
-    char *out,
-    size_t capacity);
-const char *oliphaunt_swift_version(OliphauntSession *session);
-void oliphaunt_swift_free_response(OliphauntSession *session, OliphauntResponse *response);
-
+void oliphaunt_swift_link_runtime(void);
 #endif
diff --git a/src/sdks/swift/Sources/COliphaunt/include/oliphaunt.h b/src/sdks/swift/Sources/COliphaunt/include/oliphaunt.h
index d96facff7..80191a26c 100644
--- a/src/sdks/swift/Sources/COliphaunt/include/oliphaunt.h
+++ b/src/sdks/swift/Sources/COliphaunt/include/oliphaunt.h
@@ -1,257 +1,3 @@
-#ifndef OLIPHAUNT_H
-#define OLIPHAUNT_H
-
-#include 
-#include 
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define OLIPHAUNT_ABI_VERSION 10u
-#define OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION 1u
-#define OLIPHAUNT_ERROR_CAPTURE_CAPACITY 1024u
-#define OLIPHAUNT_STREAM_CALLBACK_ABORTED 1
-/* The caller already owns liboliphaunt's stable sibling root lease. */
-#define OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK (1ull << 0)
-
-#if defined(_WIN32) && defined(OLIPHAUNT_BUILDING_DLL)
-#define OLIPHAUNT_API __declspec(dllexport)
-#elif defined(_WIN32)
-#define OLIPHAUNT_API __declspec(dllimport)
-#else
-#define OLIPHAUNT_API
-#endif
-
-typedef struct OliphauntHandle OliphauntHandle;
-
-typedef struct OliphauntStaticExtensionSymbol {
-    const char *name;
-    void *address;
-} OliphauntStaticExtensionSymbol;
-
-typedef struct OliphauntStaticExtension {
-    uint32_t abi_version;
-    const char *name;
-    const void *(*magic)(void);
-    void (*init)(void);
-    const OliphauntStaticExtensionSymbol *symbols;
-    size_t symbol_count;
-    uint64_t reserved_flags;
-} OliphauntStaticExtension;
-
-/*
- * Direct-mode extension compatibility contract:
- *
- * oliphaunt_init sets the process PGDATA environment variable to this config's
- * pgdata path while the embedded backend is active, because PostgreSQL
- * extensions may read PGDATA through standard process APIs. oliphaunt_detach
- * releases a logical direct-mode lease but keeps the resident backend alive;
- * oliphaunt_close is terminal for the process lifetime and restores the caller's
- * previous PGDATA value, or unsets it if it was unset.
- *
- * Every successful oliphaunt_init establishes a current
- * logical lease generation. Hosts with independent cleanup owners must capture
- * its non-zero value immediately with oliphaunt_logical_generation and use
- * oliphaunt_close_if_generation: a stale owner then cannot terminate a newer
- * logical lease on the same resident handle.
- *
- * Callers that require process environment isolation should use broker/server
- * mode through the Rust SDK instead of keeping multiple direct-mode backends in
- * one process.
- */
-typedef struct OliphauntConfig {
-    uint32_t abi_version;
-    /* The pgdata child of an already-prepared managed root. Init does not create it. */
-    const char *pgdata;
-    const char *runtime_dir;
-    /*
-     * Exact PostgreSQL $libdir for the embedded handle. It must name an
-     * existing directory. Pass NULL to use OLIPHAUNT_EMBEDDED_MODULE_DIR and
-     * release-layout discovery.
-     */
-    const char *module_dir;
-    const char *username;
-    const char *database;
-    /* OLIPHAUNT_CONFIG_EXTERNAL_ROOT_LOCK or zero. */
-    uint64_t flags;
-    /* Zero or more `-c`, `name=value` pairs. Storage-routing GUCs are rejected. */
-    const char *const *startup_args;
-    size_t startup_arg_count;
-} OliphauntConfig;
-
-typedef struct OliphauntResponse {
-    uint8_t *data;
-    size_t len;
-} OliphauntResponse;
-
-/*
- * Operation-owned error storage for hosts whose FFI scheduler resumes the
- * caller on a different thread. The `_with_error` entry points below execute
- * the operation and capture its thread-local failure before that native
- * invocation returns. `length` excludes the trailing NUL and is at most
- * OLIPHAUNT_ERROR_CAPTURE_CAPACITY - 1; `message` is always NUL-terminated
- * and is empty on success. The entire capture is zeroed on success. Native
- * error sources use the same bound, so a valid runtime error is not
- * additionally truncated during capture.
- */
-typedef struct OliphauntErrorCapture {
-    uint32_t length;
-    char message[OLIPHAUNT_ERROR_CAPTURE_CAPACITY];
-} OliphauntErrorCapture;
-
-typedef struct OliphauntRestoreOptions {
-    uint32_t abi_version;
-    /* New or existing-empty managed-root path; this is not a PGDATA path. */
-    const char *destination;
-    /* Bytes in the single native physical archive format returned by oliphaunt_backup. */
-    const uint8_t *data;
-    size_t len;
-} OliphauntRestoreOptions;
-
-/*
- * Same-handle ownership and streaming contract:
- *
- * Hosts serialize ordinary non-cancel operations on one logical handle.
- * oliphaunt_cancel is the deliberate cross-thread exception and may interrupt
- * the active PostgreSQL operation. A successful detach ends that logical
- * lease; a successful close terminally invalidates the opaque handle, which
- * must never be dereferenced again.
- *
- * A raw-stream callback borrows data only for that callback invocation. It may
- * copy the bytes, inspect errors, or call oliphaunt_cancel. It must not call
- * query, backup, detach, close, or another raw-stream operation on the same
- * handle. Those calls fail with a busy error while streaming is active,
- * including from another thread, so the callback cannot corrupt protocol
- * ordering or free its own handle. A non-zero callback result stops later
- * callback delivery and drains the backend to ReadyForQuery. The stream then
- * returns OLIPHAUNT_STREAM_CALLBACK_ABORTED; negative results identify
- * validation, transport, backend, or recovery failures for which reuse may be
- * unsafe.
- */
-typedef int32_t (*OliphauntStreamCallback)(void *context, const uint8_t *data, size_t len);
-
-OLIPHAUNT_API int32_t oliphaunt_init(const OliphauntConfig *config, OliphauntHandle **out);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_exec_simple_query(
-    OliphauntHandle *handle,
-    const char *sql,
-    size_t sql_len,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context);
-/*
- * Creates a session-preserving online physical archive. If an error says that
- * backup-mode exit is unconfirmed, no later query is safe: detach/close the
- * handle and restart the process before reopening PostgreSQL.
- */
-OLIPHAUNT_API int32_t oliphaunt_backup(
-    OliphauntHandle *handle,
-    OliphauntResponse *out);
-OLIPHAUNT_API int32_t oliphaunt_restore(const OliphauntRestoreOptions *options);
-/*
- * Scheduler-safe variants for asynchronous FFI hosts. These preserve the
- * return code and response ownership of their corresponding operation while
- * filling a required caller-owned capture before returning.
- */
-OLIPHAUNT_API int32_t oliphaunt_init_with_error(
-    const OliphauntConfig *config,
-    OliphauntHandle **out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_with_error(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_simple_query_with_error(
-    OliphauntHandle *handle,
-    const char *sql,
-    size_t sql_len,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream_with_error(
-    OliphauntHandle *handle,
-    const uint8_t *request,
-    size_t request_len,
-    OliphauntStreamCallback callback,
-    void *callback_context,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_backup_with_error(
-    OliphauntHandle *handle,
-    OliphauntResponse *out,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_restore_with_error(
-    const OliphauntRestoreOptions *options,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_detach_with_error(
-    OliphauntHandle *handle,
-    OliphauntErrorCapture *error);
-OLIPHAUNT_API int32_t oliphaunt_cancel(OliphauntHandle *handle);
-/* A poisoned backup session is terminally closed instead of retained. */
-OLIPHAUNT_API int32_t oliphaunt_detach(OliphauntHandle *handle);
-/*
- * Returns the non-zero generation of the currently published logical lease.
- * Returns zero for NULL, stale, terminally closed, or otherwise non-current
- * handles. The registry is validated before the opaque handle is dereferenced.
- */
-OLIPHAUNT_API uint64_t oliphaunt_logical_generation(OliphauntHandle *handle);
-/*
- * Terminally closes the process-wide resident handle only when generation
- * still owns its current logical lease. Returns 0 when terminal close completes
- * or had already completed, 1 for an active stale/non-owner generation no-op,
- * and -1 for generation zero or an internal failure.
- */
-OLIPHAUNT_API int32_t oliphaunt_close_if_generation(
-    uint64_t generation);
-/*
- * Unconditionally performs process-terminal close for the current published
- * resident handle. Hosts with multiple cleanup owners should use
- * oliphaunt_close_if_generation and retain only its generation token.
- */
-OLIPHAUNT_API int32_t oliphaunt_close(OliphauntHandle *handle);
-/*
- * Registers statically linked PostgreSQL extension modules for the embedded
- * backend's normal LOAD path.
- *
- * Call this before oliphaunt_init in processes that link extension code directly
- * into the application or SDK library. The registry is process-wide and becomes
- * immutable once backend startup begins. Each extension name is the module stem
- * used by SQL, for example AS 'vector', and each symbol row exposes the C
- * symbols PostgreSQL would otherwise resolve with dlsym().
- */
-OLIPHAUNT_API int32_t oliphaunt_register_static_extensions(const OliphauntStaticExtension *extensions, size_t count);
-/*
- * Copies an error into caller-owned storage. Immediately after a fallible C
- * operation returns failure, calls on that same thread read the operation's
- * owned snapshot. It takes precedence over the shared handle/global error and
- * remains stable across a size probe and repeated copies until the thread
- * begins another fallible C operation, even if another thread updates the
- * shared error. With no operation snapshot, this atomically reads the latest
- * handle error, or the process-global error when handle is NULL.
- *
- * The return value is the full UTF-8 byte length excluding the trailing NUL.
- * When capacity is non-zero, out must be non-NULL and is always
- * NUL-terminated; content is truncated when capacity is smaller than length +
- * 1.
- */
-OLIPHAUNT_API size_t oliphaunt_copy_last_error(
-    OliphauntHandle *handle,
-    char *out,
-    size_t capacity);
-OLIPHAUNT_API const char *oliphaunt_version(void);
-OLIPHAUNT_API void oliphaunt_free_response(OliphauntResponse *response);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+// Checkout builds consume the runtime-owned ABI; distribution staging replaces
+// this forwarding header with the canonical header for standalone consumers.
+#include "../../../../../runtimes/liboliphaunt-native/include/oliphaunt.h"
diff --git a/src/sdks/swift/Sources/COliphaunt/link.c b/src/sdks/swift/Sources/COliphaunt/link.c
new file mode 100644
index 000000000..afa9e7eea
--- /dev/null
+++ b/src/sdks/swift/Sources/COliphaunt/link.c
@@ -0,0 +1,9 @@
+#include "COliphaunt.h"
+
+void oliphaunt_swift_link_runtime(void) {
+#ifdef OLIPHAUNT_LINK_RUNTIME
+    /* Keep the packaged runtime linked when Rust resolves its ABI dynamically. */
+    const char *(*volatile version)(void) = oliphaunt_version;
+    (void)version;
+#endif
+}
diff --git a/src/sdks/swift/Sources/Oliphaunt/Oliphaunt.swift b/src/sdks/swift/Sources/Oliphaunt/Oliphaunt.swift
index 55e894268..bf0799732 100644
--- a/src/sdks/swift/Sources/Oliphaunt/Oliphaunt.swift
+++ b/src/sdks/swift/Sources/Oliphaunt/Oliphaunt.swift
@@ -200,6 +200,7 @@ enum OliphauntProtocolStreamOutcome: @unchecked Sendable {
 
 protocol OliphauntSession: Sendable {
     func execProtocolRaw(_ bytes: Data) async throws -> Data
+    func execProtocolRawUncancelled(_ bytes: Data) async throws -> Data
     func execProtocolRawStream(
         _ bytes: Data,
         onChunk: @escaping @Sendable (Data) throws -> Void
@@ -209,6 +210,14 @@ protocol OliphauntSession: Sendable {
     func close() async throws
 }
 
+struct OliphauntRequestNotSubmitted: Error {}
+
+extension OliphauntSession {
+    func execProtocolRawUncancelled(_ bytes: Data) async throws -> Data {
+        try await execProtocolRaw(bytes)
+    }
+}
+
 struct OliphauntDefaultEngine: OliphauntEngine {
     func open(configuration: OliphauntConfiguration) async throws -> any OliphauntSession {
         try await OliphauntNativeDirectEngine().open(configuration: configuration)
@@ -667,7 +676,7 @@ public actor OliphauntDatabase {
             }
             let response: Data
             do {
-                response = try await session.execProtocolRaw(request)
+                response = try await session.execProtocolRawUncancelled(request)
             } catch {
                 if settlement == nil {
                     try throwUnknownTypedOperation(transactionToken: token, error: error)
@@ -768,7 +777,7 @@ public actor OliphauntDatabase {
     ) async throws {
         guard status != .idle else { return }
         let request = try OliphauntProtocol.simpleQuery("ROLLBACK")
-        let response = try await session.execProtocolRaw(request)
+        let response = try await session.execProtocolRawUncancelled(request)
         let terminalStatus = try inspectOliphauntTerminalReadyStatus(response)
         let rollback = try parseOliphauntCommandResponse(
             response,
@@ -1017,7 +1026,7 @@ public actor OliphauntDatabase {
         do {
             let request = try OliphauntProtocol.simpleQuery("ROLLBACK")
             let rollback = try parseOliphauntCommandResponse(
-                try await session.execProtocolRaw(request),
+                try await session.execProtocolRawUncancelled(request),
                 expectedProtocol: .simple
             )
             guard rollback.commandTag == "ROLLBACK", rollback.readyStatus == .idle else {
@@ -1060,6 +1069,7 @@ public actor OliphauntDatabase {
         transactionToken: UInt64?,
         error: any Error
     ) throws -> Never {
+        if error is OliphauntRequestNotSubmitted { throw CancellationError() }
         poisonUnknownTypedOperation(
             transactionToken: transactionToken,
             error: error
@@ -1092,6 +1102,7 @@ public actor OliphauntDatabase {
             do {
                 result = try await body(session)
             } catch {
+                if error is OliphauntRequestNotSubmitted { throw CancellationError() }
                 if failurePolicy == .poisonRawProtocol {
                     poisonUnknownRawProtocolOperation(error: error)
                 }
diff --git a/src/sdks/swift/Sources/Oliphaunt/OliphauntExtensionResources.swift b/src/sdks/swift/Sources/Oliphaunt/OliphauntExtensionResources.swift
index 0b0eba2d2..e318289a7 100644
--- a/src/sdks/swift/Sources/Oliphaunt/OliphauntExtensionResources.swift
+++ b/src/sdks/swift/Sources/Oliphaunt/OliphauntExtensionResources.swift
@@ -295,7 +295,7 @@ private func readPackagedExtensionResource(
     )
     let allowedRootEntries = Set(["files", "manifest.properties"])
     let actualRootEntries = Set(rootEntries.map(\.lastPathComponent))
-    guard actualRootEntries == allowedRootEntries else {
+    guard actualRootEntries.isSubset(of: allowedRootEntries), actualRootEntries.contains("manifest.properties") else {
         let unexpected = actualRootEntries.subtracting(allowedRootEntries).sorted()
         let missing = allowedRootEntries.subtracting(actualRootEntries).sorted()
         throw OliphauntError.engine(
@@ -351,7 +351,6 @@ private func readPackagedExtensionResource(
         expected: sharedPreloadLibraries.joined(separator: ","),
         source: manifestURL
     )
-    try requirePackagedExtensionProperty(manifest, key: "files", expected: "files", source: manifestURL)
     let createsExtension: Bool
     switch manifest["createsExtension"] {
     case "yes": createsExtension = true
@@ -362,8 +361,16 @@ private func readPackagedExtensionResource(
         )
     }
 
-    let filesRoot = standardizedRoot.appendingPathComponent("files", isDirectory: true)
-    let files = try packagedExtensionFiles(in: filesRoot)
+    let files: [OliphauntPackagedExtensionResource.File]
+    switch manifest["files"] {
+    case "files":
+        let filesRoot = standardizedRoot.appendingPathComponent("files", isDirectory: true)
+        files = try packagedExtensionFiles(in: filesRoot)
+    case "" where !createsExtension && !actualRootEntries.contains("files"):
+        files = []
+    default:
+        throw OliphauntError.engine("SwiftPM exact-extension resource \(sqlName) has an invalid files declaration")
+    }
     if createsExtension {
         let control = "share/postgresql/extension/\(sqlName).control"
         let installPrefix = "share/postgresql/extension/\(sqlName)--"
diff --git a/src/sdks/swift/Sources/Oliphaunt/OliphauntNativeDirect.swift b/src/sdks/swift/Sources/Oliphaunt/OliphauntNativeDirect.swift
index f5390387d..eae83b34d 100644
--- a/src/sdks/swift/Sources/Oliphaunt/OliphauntNativeDirect.swift
+++ b/src/sdks/swift/Sources/Oliphaunt/OliphauntNativeDirect.swift
@@ -1,30 +1,6 @@
 import Foundation
 import COliphaunt
-
-enum OliphauntNativeStreamCompletion: Equatable {
-    case success
-    case callbackAborted
-    case nativeFailure
-    case protocolInconsistency
-
-    static let callbackAbortedResult = Int32(OLIPHAUNT_STREAM_CALLBACK_ABORTED)
-}
-
-func classifyOliphauntNativeStreamCompletion(
-    result: Int32,
-    callbackFailed: Bool
-) -> OliphauntNativeStreamCompletion {
-    if result < 0 {
-        return .nativeFailure
-    }
-    if result == OliphauntNativeStreamCompletion.callbackAbortedResult {
-        return callbackFailed ? .callbackAborted : .protocolInconsistency
-    }
-    if result == 0 {
-        return callbackFailed ? .protocolInconsistency : .success
-    }
-    return .protocolInconsistency
-}
+import OliphauntNativeBindings
 
 struct OliphauntNativeDirectEngine: OliphauntEngine {
     var libraryURL: URL?
@@ -41,15 +17,23 @@ struct OliphauntNativeDirectEngine: OliphauntEngine {
         self.runtimeResources = runtimeResources
     }
 
+    private var resolvedLibraryPath: String? {
+        libraryURL?.path ?? ["OLIPHAUNT_SWIFT_LIBRARY", "LIBOLIPHAUNT_PATH", "OLIPHAUNT_LIBRARY"]
+            .compactMap { ProcessInfo.processInfo.environment[$0] }
+            .first { !$0.isEmpty }
+    }
+
     func open(configuration: OliphauntConfiguration) async throws -> any OliphauntSession {
-        let owner = OliphauntNativeOwner(label: "dev.oliphaunt.swift.native-direct")
-        let box = try await owner.run { [self] in
-            try openOnOwner(configuration: configuration)
-        }
-        return NativeDirectSession(box: box, owner: owner)
+        oliphaunt_swift_link_runtime()
+        let options = try await Task.detached { [self] in
+            try prepare(configuration: configuration)
+        }.value
+        do {
+            return NativeDirectSession(database: try await NativeDatabase.open(options: options))
+        } catch { throw nativeError(error) }
     }
 
-    private func openOnOwner(configuration: OliphauntConfiguration) throws -> NativeSessionBox {
+    private func prepare(configuration: OliphauntConfiguration) throws -> OpenOptions {
         try validateOliphauntStorage(configuration.storage)
         try validateOliphauntStartupIdentity(configuration.username, label: "username")
         try validateOliphauntStartupIdentity(configuration.database, label: "database")
@@ -128,69 +112,27 @@ struct OliphauntNativeDirectEngine: OliphauntEngine {
         let startupArgs = configuration.postgresStartupArgs(
             sharedPreloadLibraries: resolvedRuntime.sharedPreloadLibraries
         )
-        let libraryPath = libraryURL?.path
-        let runtimePath = resolvedRuntime.directory?.path ?? ""
-        var session: OpaquePointer?
-        let rc = withCStringArray(startupArgs) { startupArgPointers in
-            pgdata.path.withCString { pgdataCString in
-                runtimePath.withCString { runtimeCString in
-                    username.withCString { usernameCString in
-                        database.withCString { databaseCString in
-                            libraryPath.withOptionalCString { libraryCString in
-                                var config = OliphauntConfig(
-                                    abi_version: UInt32(OLIPHAUNT_ABI_VERSION),
-                                    pgdata: pgdataCString,
-                                    runtime_dir: runtimeCString,
-                                    module_dir: nil,
-                                    username: usernameCString,
-                                    database: databaseCString,
-                                    flags: 0,
-                                    startup_args: startupArgPointers,
-                                    startup_arg_count: startupArgs.count
-                                )
-                                return oliphaunt_swift_open(libraryCString, &config, &session)
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        guard rc == 0, let session else {
-            // The native direct runtime is process-resident and may still own
-            // this directory after rejecting an incompatible logical reopen.
-            // Process-temporary storage is therefore reclaimed only with the
-            // process, never on a failed native open.
-            throw OliphauntError.engine(Self.lastError(nil))
-        }
-        return NativeSessionBox(pointer: session)
+        return OpenOptions(
+            libraryPath: resolvedLibraryPath,
+            pgdata: pgdata.path,
+            runtimeDirectory: resolvedRuntime.directory?.path,
+            moduleDirectory: nil,
+            icuDataDirectory: resolvedRuntime.catalogProfile == .icu
+                ? resolvedRuntime.directory?.appendingPathComponent("share/icu").path : nil,
+            username: username,
+            database: database,
+            startupArgs: startupArgs
+        )
     }
 
     func restore(destination: URL, bytes: Data) async throws {
-        let owner = OliphauntNativeOwner(label: "dev.oliphaunt.swift.native-direct.restore")
-        try await owner.run { [self] in
-            try restoreOnOwner(destination: destination, bytes: bytes)
-        }
-    }
-
-    private func restoreOnOwner(destination: URL, bytes: Data) throws {
+        oliphaunt_swift_link_runtime()
         try validateOliphauntDirectory(destination, label: "restore destination")
-        let libraryPath = libraryURL?.path
-        let rc = destination.path.withCString { destinationCString in
-            libraryPath.withOptionalCString { libraryCString in
-                bytes.withUnsafeBytes { rawBuffer in
-                    var options = OliphauntRestoreOptions(
-                        abi_version: UInt32(OLIPHAUNT_ABI_VERSION),
-                        destination: destinationCString,
-                        data: rawBuffer.bindMemory(to: UInt8.self).baseAddress,
-                        len: bytes.count
-                    )
-                    return oliphaunt_swift_restore(libraryCString, &options)
-                }
-            }
-        }
-        guard rc == 0 else {
-            throw OliphauntError.engine(Self.lastError(nil))
-        }
+        do {
+            try await OliphauntNativeBindings.restore(
+                libraryPath: resolvedLibraryPath, destination: destination.path, bytes: bytes
+            )
+        } catch { throw nativeError(error) }
     }
 
     private func resolveRuntime(
@@ -299,7 +241,7 @@ struct OliphauntNativeDirectEngine: OliphauntEngine {
         username: String,
         catalogProfile: OliphauntNativeCatalogProfile
     ) throws {
-#if os(macOS)
+#if os(macOS) || os(Linux)
         let environment = ProcessInfo.processInfo.environment
         let initdb: URL
         if let configured = environment["OLIPHAUNT_INITDB"]?.trimmingCharacters(in: .whitespacesAndNewlines),
@@ -337,8 +279,13 @@ struct OliphauntNativeDirectEngine: OliphauntEngine {
         }
         if let runtimeDirectory {
             let libraryDirectory = runtimeDirectory.appendingPathComponent("lib", isDirectory: true).path
-            let inherited = environment["DYLD_LIBRARY_PATH"]?.trimmingCharacters(in: .whitespacesAndNewlines)
-            childEnvironment["DYLD_LIBRARY_PATH"] = [libraryDirectory, inherited]
+            #if os(Linux)
+            let libraryVariable = "LD_LIBRARY_PATH"
+            #else
+            let libraryVariable = "DYLD_LIBRARY_PATH"
+            #endif
+            let inherited = environment[libraryVariable]?.trimmingCharacters(in: .whitespacesAndNewlines)
+            childEnvironment[libraryVariable] = [libraryDirectory, inherited]
                 .compactMap { $0 }
                 .filter { !$0.isEmpty }
                 .joined(separator: ":")
@@ -501,26 +448,6 @@ struct OliphauntNativeDirectEngine: OliphauntEngine {
             )
     }()
 
-    fileprivate static func lastError(_ session: OpaquePointer?) -> String {
-        let required = oliphaunt_swift_copy_last_error(session, nil, 0)
-        guard required > 0, required < Int.max else {
-            return "unknown liboliphaunt Swift runtime error"
-        }
-        var bytes = [CChar](repeating: 0, count: required + 1)
-        let currentRequired = bytes.withUnsafeMutableBufferPointer { buffer in
-            oliphaunt_swift_copy_last_error(session, buffer.baseAddress, buffer.count)
-        }
-        if currentRequired >= bytes.count {
-            bytes = [CChar](repeating: 0, count: currentRequired + 1)
-            bytes.withUnsafeMutableBufferPointer { buffer in
-                _ = oliphaunt_swift_copy_last_error(session, buffer.baseAddress, buffer.count)
-            }
-        }
-        let message = bytes.withUnsafeBufferPointer { buffer in
-            String(cString: buffer.baseAddress!)
-        }
-        return message.isEmpty ? "unknown liboliphaunt Swift runtime error" : message
-    }
 
 }
 
@@ -656,345 +583,82 @@ private struct OliphauntFlatJSONParser {
     }
 }
 
-private final class NativeDirectSession: OliphauntSession, @unchecked Sendable {
-    private let box: NativeSessionBox
-    private let owner: OliphauntNativeOwner
-    private let cancellationOwner = OliphauntNativeOwner(
-        label: "dev.oliphaunt.swift.native-direct.cancel"
-    )
+private final class NativeDirectSession: OliphauntSession, Sendable {
+    private let database: NativeDatabase
 
-    init(box: NativeSessionBox, owner: OliphauntNativeOwner) {
-        self.box = box
-        self.owner = owner
-    }
+    init(database: NativeDatabase) { self.database = database }
 
-    deinit {
-        let box = box
-        owner.enqueue {
-            box.closeBestEffort()
-        }
+    func execProtocolRaw(_ bytes: Data) async throws -> Data {
+        let request = database.request()
+        return try await withTaskCancellationHandler {
+            do {
+                let result = try await request.execute(bytes: bytes)
+                return result
+            } catch NativeError.NotSubmitted {
+                throw OliphauntRequestNotSubmitted()
+            } catch {
+                throw nativeError(error)
+            }
+        } onCancel: { try? request.cancel() }
     }
 
-    func execProtocolRaw(_ bytes: Data) async throws -> Data {
-        try await owner.run { [box] in
-            try box.execProtocolRaw(bytes)
-        }
+    func execProtocolRawUncancelled(_ bytes: Data) async throws -> Data {
+        do { return try await database.request().execute(bytes: bytes) }
+        catch { throw nativeError(error) }
     }
 
     func execProtocolRawStream(
         _ bytes: Data,
         onChunk: @escaping @Sendable (Data) throws -> Void
     ) async throws -> OliphauntProtocolStreamOutcome {
-        try await owner.run { [box] in
-            try box.execProtocolRawStream(bytes, onChunk: onChunk)
-        }
+        let request = database.request()
+        let sink = NativeStreamSink(onChunk: onChunk)
+        return try await withTaskCancellationHandler {
+            do {
+                try await request.stream(bytes: bytes, sink: sink)
+                return .complete
+            } catch NativeError.Callback {
+                // Rust reports Callback only after confirming ReadyForQuery.
+                guard let error = sink.callbackError else {
+                    throw OliphauntError.engine("stream callback failed without its original error")
+                }
+                return .callbackAborted(error)
+            } catch NativeError.NotSubmitted {
+                throw OliphauntRequestNotSubmitted()
+            } catch {
+                throw nativeError(error)
+            }
+        } onCancel: { try? request.cancel() }
     }
 
     func backup() async throws -> Data {
-        try await owner.run { [box] in
-            try box.backup()
-        }
+        do { return try await database.backup() }
+        catch { throw nativeError(error) }
     }
-
     func cancel() async throws {
-        try await cancellationOwner.run { [box] in
-            try box.cancel()
-        }
+        do { try await database.cancel() }
+        catch { throw nativeError(error) }
     }
-
     func close() async throws {
-        try await owner.run { [box] in
-            try box.close()
-        }
-    }
-}
-
-final class OliphauntNativeOwner: @unchecked Sendable {
-    private let queue: DispatchQueue
-
-    init(label: String) {
-        queue = DispatchQueue(label: label, qos: .userInitiated)
-    }
-
-    func run(
-        _ operation: @escaping @Sendable () throws -> Value
-    ) async throws -> Value {
-        try await withCheckedThrowingContinuation { continuation in
-            queue.async {
-                continuation.resume(with: Result(catching: operation))
-            }
-        }
-    }
-
-    func enqueue(_ operation: @escaping @Sendable () -> Void) {
-        queue.async(execute: operation)
-    }
-}
-
-private final class NativeSessionBox: @unchecked Sendable {
-    private let condition = NSCondition()
-    private var pointer: OpaquePointer?
-    private var closing = false
-    private var closed = false
-    private var activeCalls = 0
-
-    init(pointer: OpaquePointer) {
-        self.pointer = pointer
-    }
-
-    deinit {
-        closeBestEffort()
-    }
-
-    func execProtocolRaw(_ bytes: Data) throws -> Data {
-        let pointer = try beginCall()
-        defer {
-            endCall()
-        }
-
-        var response = OliphauntResponse(data: nil, len: 0)
-        let rc = bytes.withUnsafeBytes { rawBuffer in
-            let base = rawBuffer.bindMemory(to: UInt8.self).baseAddress
-            return oliphaunt_swift_exec_protocol(pointer, base, bytes.count, &response)
-        }
-        guard rc == 0 else {
-            throw OliphauntError.engine(OliphauntNativeDirectEngine.lastError(pointer))
-        }
-        defer {
-            oliphaunt_swift_free_response(pointer, &response)
-        }
-        guard let data = response.data, response.len > 0 else {
-            return Data()
-        }
-        return Data(bytes: data, count: response.len)
-    }
-
-    func execProtocolRawStream(
-        _ bytes: Data,
-        onChunk: @escaping @Sendable (Data) throws -> Void
-    ) throws -> OliphauntProtocolStreamOutcome {
-        let pointer = try beginCall()
-        defer {
-            endCall()
-        }
-
-        let callbackBox = NativeStreamCallbackBox(onChunk: onChunk)
-        let context = Unmanaged.passUnretained(callbackBox).toOpaque()
-        let rc = bytes.withUnsafeBytes { rawBuffer in
-            let base = rawBuffer.bindMemory(to: UInt8.self).baseAddress
-            return oliphaunt_swift_exec_protocol_raw_stream(
-                pointer,
-                base,
-                bytes.count,
-                { context, data, len in
-                    guard let context else {
-                        return -1
-                    }
-                    let callbackBox = Unmanaged
-                        .fromOpaque(context)
-                        .takeUnretainedValue()
-                    do {
-                        if let data, len > 0 {
-                            try callbackBox.onChunk(Data(bytes: data, count: len))
-                        } else {
-                            try callbackBox.onChunk(Data())
-                        }
-                        return 0
-                    } catch {
-                        callbackBox.error = error
-                        return -1
-                    }
-                },
-                context
-            )
-        }
-        switch classifyOliphauntNativeStreamCompletion(
-            result: rc,
-            callbackFailed: callbackBox.error != nil
-        ) {
-        case .success:
-            return .complete
-        case .callbackAborted:
-            // The positive status proves liboliphaunt drained through
-            // ReadyForQuery; only this outcome may preserve callback identity.
-            guard let callbackError = callbackBox.error else {
-                throw OliphauntError.engine(
-                    "liboliphaunt reported a recovered callback abort without a callback failure"
-                )
-            }
-            return .callbackAborted(callbackError)
-        case .nativeFailure:
-            // A negative result means transport or recovery failed. Its native
-            // diagnostic is authoritative even when the callback also threw.
-            throw OliphauntError.engine(OliphauntNativeDirectEngine.lastError(pointer))
-        case .protocolInconsistency:
-            throw OliphauntError.engine(
-                "liboliphaunt returned protocol stream result \(rc) with " +
-                    (callbackBox.error == nil ? "no callback failure" : "an unconfirmed callback failure")
-            )
-        }
-    }
-
-    func backup() throws -> Data {
-        let pointer = try beginCall()
-        defer {
-            endCall()
-        }
-
-        var response = OliphauntResponse(data: nil, len: 0)
-        let rc = oliphaunt_swift_backup(pointer, &response)
-        guard rc == 0 else {
-            throw OliphauntError.engine(OliphauntNativeDirectEngine.lastError(pointer))
-        }
-        defer {
-            oliphaunt_swift_free_response(pointer, &response)
-        }
-        guard let data = response.data, response.len > 0 else {
-            return Data()
-        }
-        return Data(bytes: data, count: response.len)
-    }
-
-    func cancel() throws {
-        let pointer = try beginCancellation()
-        defer {
-            endCall()
-        }
-        let rc = oliphaunt_swift_cancel(pointer)
-        guard rc == 0 else {
-            throw OliphauntError.engine(OliphauntNativeDirectEngine.lastError(pointer))
-        }
-    }
-
-    func close() throws {
-        let pointer = beginClose()
-        guard let pointer else {
-            return
-        }
-        let rc = oliphaunt_swift_close(pointer)
-        if rc == 0 {
-            finishClose(detached: true)
-            return
-        }
-        let message = OliphauntNativeDirectEngine.lastError(pointer)
-        finishClose(detached: false)
-        throw OliphauntError.engine(message)
-    }
-
-    func closeBestEffort() {
-        let pointer = beginClose()
-        if let pointer {
-            let rc = oliphaunt_swift_close(pointer)
-            finishClose(detached: rc == 0)
-        }
-    }
-
-    private func beginCall() throws -> OpaquePointer {
-        condition.lock()
-        defer {
-            condition.unlock()
-        }
-        while !closing && !closed && activeCalls > 0 {
-            condition.wait()
-        }
-        guard let pointer, !closing, !closed else {
-            throw OliphauntError.databaseClosed
-        }
-        activeCalls += 1
-        return pointer
-    }
-
-    private func beginCancellation() throws -> OpaquePointer {
-        condition.lock()
-        defer {
-            condition.unlock()
-        }
-        guard let pointer, !closing, !closed else {
-            throw OliphauntError.databaseClosed
-        }
-        // Cancellation is intentionally out of band and may overlap the
-        // serialized query call it interrupts. Counting it here still makes
-        // close wait until the native cancel call has released the pointer.
-        activeCalls += 1
-        return pointer
+        do { try await database.detach() }
+        catch { throw nativeError(error) }
     }
-
-    private func endCall() {
-        condition.lock()
-        activeCalls -= 1
-        condition.broadcast()
-        condition.unlock()
-    }
-
-    private func beginClose() -> OpaquePointer? {
-        condition.lock()
-        while closing {
-            condition.wait()
-        }
-        if closed {
-            condition.unlock()
-            return nil
-        }
-        closing = true
-        let pointer = self.pointer
-        while activeCalls > 0 {
-            condition.wait()
-        }
-        condition.unlock()
-        return pointer
-    }
-
-    private func finishClose(detached: Bool) {
-        condition.lock()
-        if detached {
-            pointer = nil
-            closed = true
-        }
-        closing = false
-        condition.broadcast()
-        condition.unlock()
-    }
-
 }
 
-private final class NativeStreamCallbackBox: @unchecked Sendable {
-    let onChunk: @Sendable (Data) throws -> Void
-    var error: Error?
+private final class NativeStreamSink: ChunkSink, @unchecked Sendable {
+    private let lock = NSLock()
+    private let onChunk: @Sendable (Data) throws -> Void
+    private var error: Error?
 
-    init(onChunk: @escaping @Sendable (Data) throws -> Void) {
-        self.onChunk = onChunk
+    init(onChunk: @escaping @Sendable (Data) throws -> Void) { self.onChunk = onChunk }
+    var callbackError: Error? { lock.withLock { error } }
+    func onChunk(bytes: Data) -> Bool {
+        do { try onChunk(bytes); return true }
+        catch { lock.withLock { self.error = error }; return false }
     }
 }
 
-
-private func withCStringArray(
-    _ strings: [String],
-    _ body: (UnsafePointer?>?) throws -> T
-) rethrows -> T {
-    let cStrings = strings.map { strdup($0) }
-    defer {
-        for cString in cStrings {
-            free(cString)
-        }
-    }
-    let pointers = cStrings.map { cString -> UnsafePointer? in
-        guard let cString else {
-            return nil
-        }
-        return UnsafePointer(cString)
-    }
-    return try pointers.withUnsafeBufferPointer { buffer in
-        try body(buffer.baseAddress)
-    }
-}
-
-private extension Optional where Wrapped == String {
-    func withOptionalCString(_ body: (UnsafePointer?) throws -> T) rethrows -> T {
-        switch self {
-        case .some(let value):
-            return try value.withCString(body)
-        case .none:
-            return try body(nil)
-        }
-    }
+private func nativeError(_ error: Error) -> OliphauntError {
+    if case NativeError.Database(let detail) = error { return .engine(detail) }
+    return .engine(String(describing: error))
 }
diff --git a/src/sdks/swift/Sources/Oliphaunt/OliphauntRuntimeResources.swift b/src/sdks/swift/Sources/Oliphaunt/OliphauntRuntimeResources.swift
index 108e55e3b..6135edcdb 100644
--- a/src/sdks/swift/Sources/Oliphaunt/OliphauntRuntimeResources.swift
+++ b/src/sdks/swift/Sources/Oliphaunt/OliphauntRuntimeResources.swift
@@ -201,12 +201,12 @@ struct OliphauntExtensionSizeReport: Equatable, Sendable {
             inResourceDirectories: icuResourceDirectories ?? defaultBundleResourceURLs()
         )
         let profile: OliphauntNativeCatalogProfile = integratedIcu || externalIcu != nil ? .icu : .standard
-        let seed = try matchingClusterSeed(
+        _ = try matchingClusterSeed(
             profile: profile,
             runtime: runtime,
             icuDataTreeSha256: externalIcu?.treeSha256
         )
-        let target = try materialize(runtime, seed: seed, profile: profile, externalIcu: externalIcu)
+        let target = try materialize(runtime, profile: profile, externalIcu: externalIcu)
         return ResolvedOliphauntRuntimeResources(
             directory: target,
             sharedPreloadLibraries: runtime.sharedPreloadLibraries.sorted(),
@@ -362,13 +362,13 @@ struct OliphauntExtensionSizeReport: Equatable, Sendable {
         profile: OliphauntNativeCatalogProfile,
         runtime: AssetPackage,
         icuDataTreeSha256: String?
-    ) throws -> AssetPackage {
+    ) throws -> AssetPackage? {
         guard runtime.clusterSeedTarget == oliphauntSwiftClusterSeedTarget else {
             throw OliphauntError.engine(
                 "Swift Oliphaunt runtime resources do not carry cluster seeds for \(oliphauntSwiftClusterSeedTarget)"
             )
         }
-        let seed = try assetPackage(kind: .clusterSeed(profile))
+        guard let seed = try optionalAssetPackage(kind: .clusterSeed(profile)) else { return nil }
         if profile == .icu {
             let selectedDigest = icuDataTreeSha256 ?? runtime.icuDataTreeSha256
             guard !selectedDigest.isEmpty, selectedDigest == seed.icuDataTreeSha256 else {
@@ -382,22 +382,19 @@ struct OliphauntExtensionSizeReport: Equatable, Sendable {
 
     private func materialize(
         _ runtime: AssetPackage,
-        seed: AssetPackage,
         profile: OliphauntNativeCatalogProfile,
         externalIcu: OliphauntIcuDataCarrier?
     ) throws -> URL {
-        let digest = profile == .icu ? seed.icuDataTreeSha256 : "none"
+        let digest = profile == .icu ? (externalIcu?.treeSha256 ?? runtime.icuDataTreeSha256) : "none"
         let target = cacheRoot
             .appendingPathComponent("runtime", isDirectory: true)
             .appendingPathComponent(runtime.cacheKey, isDirectory: true)
             .appendingPathComponent(profile.rawValue, isDirectory: true)
-            .appendingPathComponent(seed.cacheKey, isDirectory: true)
             .appendingPathComponent(digest, isDirectory: true)
         let identity = [
             "runtime=\(runtime.cacheKey)",
             "target=\(oliphauntSwiftClusterSeedTarget)",
             "profile=\(profile.rawValue)",
-            "seed=\(seed.cacheKey)",
             "icuDataTreeSha256=\(profile == .icu ? digest : "")",
             "",
         ].joined(separator: "\n")
@@ -555,10 +552,24 @@ struct OliphauntExtensionSizeReport: Equatable, Sendable {
     }
 
     private func optionalAssetPackage(kind: AssetPackageKind) throws -> AssetPackage? {
-        if case .runtime = kind {
-            try validateRuntimeCarrierReceipt()
+        var rootURL = kind.root(in: resourceRoot)
+        if case .clusterSeed = kind,
+           !FileManager.default.fileExists(atPath: rootURL.appendingPathComponent("manifest.properties").path) {
+            let directories = icuResourceDirectories ?? defaultBundleResourceURLs()
+            var candidates: [URL] = []
+            var seen = Set()
+            for directory in directories {
+                for base in [directory, directory.appendingPathComponent("oliphaunt", isDirectory: true)] {
+                    let candidate = kind.root(in: base)
+                    if FileManager.default.fileExists(atPath: candidate.appendingPathComponent("manifest.properties").path),
+                       seen.insert(candidate.standardizedFileURL.path).inserted {
+                        candidates.append(candidate)
+                    }
+                }
+            }
+            if candidates.count > 1 { throw OliphauntError.engine("Multiple selected \(kind.label) resource carriers") }
+            if let selected = candidates.first { rootURL = selected }
         }
-        let rootURL = kind.root(in: resourceRoot)
         let manifestURL = rootURL.appendingPathComponent("manifest.properties")
         guard FileManager.default.fileExists(atPath: manifestURL.path) else {
             return nil
@@ -782,27 +793,6 @@ struct OliphauntExtensionSizeReport: Equatable, Sendable {
         )
     }
 
-    private func validateRuntimeCarrierReceipt() throws {
-        let url = resourceRoot.appendingPathComponent("manifest.properties")
-        let values = try readManifest(url)
-        let expectedKeys: Set = [
-            "schema", "clusterSeedTarget", "clusterSeedRelativePath",
-            "icuClusterSeedRelativePath",
-        ]
-        guard Set(values.keys) == expectedKeys,
-              values["schema"] == "oliphaunt-native-runtime-carrier-v1",
-              values["clusterSeedTarget"] == oliphauntSwiftClusterSeedTarget,
-              values["clusterSeedRelativePath"] == "cluster-seed",
-              values["icuClusterSeedRelativePath"] == "cluster-seed-icu"
-        else {
-            throw OliphauntError.engine(
-                "liboliphaunt runtime carrier does not contain the exact \(oliphauntSwiftClusterSeedTarget) seed receipt"
-            )
-        }
-        _ = try assetPackage(kind: .clusterSeed(.standard))
-        _ = try assetPackage(kind: .clusterSeed(.icu))
-    }
-
     private func readManifest(_ url: URL) throws -> [String: String] {
         let text = try String(contentsOf: url, encoding: .utf8)
         var values: [String: String] = [:]
diff --git a/src/sdks/swift/Tests/OliphauntTests/ApplePlatformTests.swift b/src/sdks/swift/Tests/OliphauntTests/ApplePlatformTests.swift
new file mode 100644
index 000000000..65e2a94dd
--- /dev/null
+++ b/src/sdks/swift/Tests/OliphauntTests/ApplePlatformTests.swift
@@ -0,0 +1,33 @@
+import Foundation
+@testable import Oliphaunt
+import Testing
+
+#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
+@Suite
+struct ApplePlatformTests {
+    @Test
+    func discoversCocoaPodsRuntimeResourceBundlesBeforeTheyAreLoaded() throws {
+        let root = FileManager.default.temporaryDirectory
+            .appendingPathComponent("oliphaunt-swift-bundle-discovery-\(UUID().uuidString)", isDirectory: true)
+        defer { try? FileManager.default.removeItem(at: root) }
+
+        let bundleRoot = root.appendingPathComponent("OliphauntReactNativeResources.bundle", isDirectory: true)
+        let runtimeRoot = bundleRoot.appendingPathComponent("oliphaunt", isDirectory: true)
+        try FileManager.default.createDirectory(at: runtimeRoot, withIntermediateDirectories: true)
+        try Data(
+            """
+            
+            
+            
+              CFBundleIdentifierdev.oliphaunt.test.resources
+              CFBundleNameOliphauntReactNativeResources
+              CFBundlePackageTypeBNDL
+            
+            """.utf8
+        ).write(to: bundleRoot.appendingPathComponent("Info.plist"))
+
+        let urls = bundleResourceURLs([], discoveringChildBundlesAt: root)
+        #expect(urls.map(\.standardizedFileURL).contains(bundleRoot.standardizedFileURL))
+    }
+}
+#endif
diff --git a/src/sdks/swift/Tests/OliphauntTests/ExtensionResourceCompositionTests.swift b/src/sdks/swift/Tests/OliphauntTests/ExtensionResourceCompositionTests.swift
index def642f26..c6d2620f9 100644
--- a/src/sdks/swift/Tests/OliphauntTests/ExtensionResourceCompositionTests.swift
+++ b/src/sdks/swift/Tests/OliphauntTests/ExtensionResourceCompositionTests.swift
@@ -59,7 +59,7 @@ func swiftPMExtensionResourcesComposeBaseNativeDependenciesMultipleAndSQLOnly()
             nativeDependencies: nativeDependencies,
             sharedPreloadLibraries: sharedPreload
         )
-        #expect(try OliphauntRuntimeResources.registerPackagedExtensionResource(
+        let register = { try OliphauntRuntimeResources.registerPackagedExtensionResource(
             product: product,
             version: version,
             sqlName: sqlName,
@@ -68,7 +68,20 @@ func swiftPMExtensionResourcesComposeBaseNativeDependenciesMultipleAndSQLOnly()
             nativeModuleStem: stem,
             sharedPreloadLibraries: sharedPreload,
             resourceRoot: fragment
-        ))
+        ) }
+        if !createsExtension {
+            let manifestURL = fragment.appendingPathComponent("manifest.properties")
+            let manifest = try String(contentsOf: manifestURL, encoding: .utf8)
+            for invalid in [
+                manifest.replacingOccurrences(of: "files=", with: "files=files"),
+                manifest.replacingOccurrences(of: "createsExtension=no", with: "createsExtension=yes"),
+            ] {
+                try writeExtensionCompositionText(manifestURL, invalid)
+                #expect(throws: OliphauntError.self) { try register() }
+            }
+            try writeExtensionCompositionText(manifestURL, manifest)
+        }
+        #expect(try register())
     }
 
     let requested = Set(["auto_explain", "earthdistance", "postgis", "pgtap"])
@@ -259,6 +272,21 @@ func swiftRuntimeResourcesRejectDuplicateManifestProperties() throws {
     }
 }
 
+@Test
+func swiftRuntimeMaterializationDoesNotRequireAnInitializationSeed() throws {
+    let root = FileManager.default.temporaryDirectory.appendingPathComponent("oliphaunt-seedless-\(UUID().uuidString)")
+    defer { try? FileManager.default.removeItem(at: root) }
+    try writeExtensionCompositionStandardSeeds(root)
+    try FileManager.default.removeItem(at: root.appendingPathComponent("cluster-seed"))
+    try FileManager.default.removeItem(at: root.appendingPathComponent("cluster-seed-icu"))
+    try writeExtensionCompositionText(root.appendingPathComponent("runtime/manifest.properties"), extensionCompositionRuntimeManifest(cacheKey: "seedless-runtime"))
+    try writeExtensionCompositionText(root.appendingPathComponent("runtime/files/share/postgresql/postgres.bki"), "runtime\n")
+    let resources = OliphauntRuntimeResources(resourceRoot: root, cacheRoot: root.appendingPathComponent("cache"), icuResourceDirectories: [])
+    let runtime = try resources.materializeRuntime()
+    #expect(FileManager.default.fileExists(atPath: runtime.appendingPathComponent("share/postgresql/postgres.bki").path))
+    #expect(try resources.preparePgdata(at: root.appendingPathComponent("fresh"), profile: .standard, didPublishDestination: {}) == nil)
+}
+
 @Test
 func swiftRuntimeResourcesRejectSharedWhitespaceInvalidClusterSeedManifest() throws {
     let root = FileManager.default.temporaryDirectory.appendingPathComponent(
@@ -479,15 +507,6 @@ func swiftRuntimeCacheNeverReplacesAnInvalidPublishedTarget() throws {
 
 private func writeExtensionCompositionStandardSeeds(_ resourceRoot: URL) throws {
     let target = "macos-arm64"
-    try writeExtensionCompositionText(
-        resourceRoot.appendingPathComponent("manifest.properties"),
-        """
-        schema=oliphaunt-native-runtime-carrier-v1
-        clusterSeedTarget=\(target)
-        clusterSeedRelativePath=cluster-seed
-        icuClusterSeedRelativePath=cluster-seed-icu
-        """
-    )
     let seed = resourceRoot.appendingPathComponent("cluster-seed", isDirectory: true)
     try writeExtensionCompositionText(
         seed.appendingPathComponent("manifest.properties"),
@@ -562,7 +581,7 @@ private func nativeClusterSeedFixture(named name: String, target: String) throws
         sourceRoot.deleteLastPathComponent()
     }
     let fixture = sourceRoot
-        .appendingPathComponent("shared/cluster-seed-contract/fixtures")
+        .appendingPathComponent("database-resources/contracts/fixtures")
         .appendingPathComponent(name)
     let source = try String(contentsOf: fixture, encoding: .utf8)
     let overrides = [
@@ -639,7 +658,7 @@ private func makeExtensionCompositionFragment(
         nativeModuleStem=\(nativeModuleStem ?? "")
         nativeDependencies=\(nativeDependencies.sorted().joined(separator: ","))
         sharedPreloadLibraries=\(sharedPreloadLibraries.sorted().joined(separator: ","))
-        files=files
+        files=\(createsExtension ? "files" : "")
         """
     )
     if createsExtension {
@@ -651,11 +670,6 @@ private func makeExtensionCompositionFragment(
             root.appendingPathComponent("files/share/postgresql/extension/\(sqlName)--\(version).sql"),
             "SELECT 1;\n"
         )
-    } else {
-        try writeExtensionCompositionText(
-            root.appendingPathComponent("files/share/postgresql/README.\(sqlName)"),
-            "module-only product \(sqlName)\n"
-        )
     }
 }
 
diff --git a/src/sdks/swift/Tests/OliphauntTests/NativeRuntimeTests.swift b/src/sdks/swift/Tests/OliphauntTests/NativeRuntimeTests.swift
new file mode 100644
index 000000000..21fc7922e
--- /dev/null
+++ b/src/sdks/swift/Tests/OliphauntTests/NativeRuntimeTests.swift
@@ -0,0 +1,69 @@
+import Foundation
+import Oliphaunt
+import Testing
+
+@Suite(.enabled(if: ProcessInfo.processInfo.environment["OLIPHAUNT_SWIFT_REQUIRE_NATIVE"] == "1"))
+struct NativeRuntimeTests {
+    @Test
+    func nativeDatabaseExecutesSQLAndCloses() async throws {
+        let database = try await OliphauntDatabase.open()
+        do {
+            let result = try await database.query("SELECT $1::int4 AS answer", parameters: [.int32(42)])
+            #expect(try result.rows[0].value(named: "answer", as: Int32.self) == 42)
+            await #expect(throws: (any Error).self) {
+                _ = try await database.exec("SELECT 1 / 0")
+            }
+            let transactionResult = try await database.transaction { transaction in
+                try await transaction.query("SELECT 7::int4 AS answer")
+            }
+            #expect(try transactionResult.rows[0].value(named: "answer", as: Int32.self) == 7)
+
+            enum CallbackFailure: Error { case stopped }
+            let sql = Data("SELECT generate_series(1, 1000)\0".utf8)
+            var length = UInt32(sql.count + 4).bigEndian
+            let request = Data([81]) + withUnsafeBytes(of: &length) { Data($0) } + sql
+            do {
+                try await database.execProtocolRawStream(request) { _ in throw CallbackFailure.stopped }
+                Issue.record("stream must preserve the callback failure")
+            } catch CallbackFailure.stopped {}
+            _ = try await database.query("SELECT 1")
+
+            let sleeping = Task { try await database.query("SELECT pg_sleep(60)") }
+            try await Task.sleep(for: .milliseconds(100))
+            let start = ContinuousClock.now
+            sleeping.cancel()
+            do {
+                _ = try await sleeping.value
+                Issue.record("cancelled query must not succeed")
+            } catch is CancellationError {
+            } catch OliphauntError.postgres(let error) {
+                #expect(error.sqlstate == "57014")
+            }
+            #expect(start.duration(to: .now) < .seconds(3))
+            _ = try await database.query("SELECT 1")
+            let transactionSleep = Task {
+                try await database.transaction { transaction in
+                    try await transaction.query("SELECT pg_sleep(60)")
+                }
+            }
+            try await Task.sleep(for: .milliseconds(100))
+            transactionSleep.cancel()
+            do { _ = try await transactionSleep.value }
+            catch is CancellationError {}
+            catch OliphauntError.postgres(let error) { #expect(error.sqlstate == "57014") }
+            _ = try await database.query("SELECT 1")
+            let backup = try await database.backup()
+            #expect(!backup.isEmpty)
+            try await database.close()
+            #expect(await database.isClosed)
+            let restored = FileManager.default.temporaryDirectory
+                .appendingPathComponent("oliphaunt-swift-restore-\(UUID().uuidString)")
+            defer { try? FileManager.default.removeItem(at: restored) }
+            try await OliphauntDatabase.restore(destination: restored, bytes: backup)
+            #expect(FileManager.default.fileExists(atPath: restored.appendingPathComponent("pgdata/PG_VERSION").path))
+        } catch {
+            try? await database.close()
+            throw error
+        }
+    }
+}
diff --git a/src/sdks/swift/Tests/OliphauntTests/OliphauntTests.swift b/src/sdks/swift/Tests/OliphauntTests/OliphauntTests.swift
index a3c7c3637..8314f996b 100644
--- a/src/sdks/swift/Tests/OliphauntTests/OliphauntTests.swift
+++ b/src/sdks/swift/Tests/OliphauntTests/OliphauntTests.swift
@@ -8,32 +8,7 @@ import Darwin
 import Glibc
 #endif
 
-#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) || os(visionOS)
-@Test
-func discoversCocoaPodsRuntimeResourceBundlesBeforeTheyAreLoaded() throws {
-    let root = FileManager.default.temporaryDirectory
-        .appendingPathComponent("oliphaunt-swift-bundle-discovery-\(UUID().uuidString)", isDirectory: true)
-    defer { try? FileManager.default.removeItem(at: root) }
 
-    let bundleRoot = root.appendingPathComponent("OliphauntReactNativeResources.bundle", isDirectory: true)
-    let runtimeRoot = bundleRoot.appendingPathComponent("oliphaunt", isDirectory: true)
-    try FileManager.default.createDirectory(at: runtimeRoot, withIntermediateDirectories: true)
-    try Data(
-        """
-        
-        
-        
-          CFBundleIdentifierdev.oliphaunt.test.resources
-          CFBundleNameOliphauntReactNativeResources
-          CFBundlePackageTypeBNDL
-        
-        """.utf8
-    ).write(to: bundleRoot.appendingPathComponent("Info.plist"))
-
-    let urls = bundleResourceURLs([], discoveringChildBundlesAt: root)
-    #expect(urls.map(\.standardizedFileURL).contains(bundleRoot.standardizedFileURL))
-}
-#endif
 
 @Test
 func runtimeCacheUsesApplicationDataNamespaceCasing() {
@@ -42,8 +17,8 @@ func runtimeCacheUsesApplicationDataNamespaceCasing() {
     #expect(cacheRoot.deletingLastPathComponent().lastPathComponent == "Oliphaunt")
 }
 
-// OLIPHAUNT_DOCS_SNIPPET swift-quickstart
 
+// OLIPHAUNT_DOCS_SNIPPET swift-quickstart
 @Test
 func executeReturnsPostgresCommandMetadata() async throws {
     let session = TestSession(response: commandResponse("UPDATE 3"))
@@ -1406,46 +1381,6 @@ func cancellationCannotStrandCloseOwnership() async throws {
     #expect(await database.isClosed)
 }
 
-@Test
-@MainActor
-func nativeOwnerRunsAwayFromTheMainThread() async throws {
-    let owner = OliphauntNativeOwner(label: "dev.oliphaunt.swift.tests.owner")
-    let ranOnMainThread = try await owner.run { Thread.isMainThread }
-    #expect(!ranOnMainThread)
-}
-
-@Test
-func nativeStreamCompletionPreservesCallbackOnlyAfterConfirmedRecovery() {
-    #expect(
-        classifyOliphauntNativeStreamCompletion(result: 0, callbackFailed: false) == .success
-    )
-    #expect(
-        classifyOliphauntNativeStreamCompletion(
-            result: OliphauntNativeStreamCompletion.callbackAbortedResult,
-            callbackFailed: true
-        ) == .callbackAborted
-    )
-    #expect(
-        classifyOliphauntNativeStreamCompletion(result: -1, callbackFailed: true) == .nativeFailure
-    )
-    #expect(
-        classifyOliphauntNativeStreamCompletion(result: -1, callbackFailed: false) == .nativeFailure
-    )
-    #expect(
-        classifyOliphauntNativeStreamCompletion(result: 0, callbackFailed: true) ==
-            .protocolInconsistency
-    )
-    #expect(
-        classifyOliphauntNativeStreamCompletion(
-            result: OliphauntNativeStreamCompletion.callbackAbortedResult,
-            callbackFailed: false
-        ) == .protocolInconsistency
-    )
-    #expect(
-        classifyOliphauntNativeStreamCompletion(result: 2, callbackFailed: true) ==
-            .protocolInconsistency
-    )
-}
 
 @Test
 func rawStreamCallbackFailureRejectsAndReleasesTheSession() async throws {
@@ -1733,7 +1668,7 @@ func nativeOpenDoesNotRejectAValidWasixRootDescriptor() async throws {
         )
         Issue.record("open should fail for a missing native library")
     } catch OliphauntError.engine(let message) {
-        #expect(message.contains("failed to load liboliphaunt"))
+        #expect(message.contains("/tmp/oliphaunt-swift-missing.dylib"))
     }
 }
 
@@ -2596,7 +2531,7 @@ private func databaseRootFixture() throws -> [String: Any] {
         .deletingLastPathComponent()
         .deletingLastPathComponent()
         .deletingLastPathComponent()
-        .appendingPathComponent("shared/fixtures/storage/database-root.json")
+        .appendingPathComponent("test-fixtures/storage/database-root.json")
     return try #require(
         JSONSerialization.jsonObject(with: Data(contentsOf: source)) as? [String: Any]
     )
diff --git a/src/sdks/swift/moon.yml b/src/sdks/swift/moon.yml
index 03aa94817..fbf4220c9 100644
--- a/src/sdks/swift/moon.yml
+++ b/src/sdks/swift/moon.yml
@@ -4,9 +4,14 @@ id: "oliphaunt-swift"
 language: "swift"
 layer: "library"
 stack: "systems"
-tags: ["sdk", "swift", "ios", "macos", "native", "release-product"]
+tags: ["javascript-quality", "sdk", "swift", "ios", "macos", "native", "release-product"]
 dependsOn:
+  - "oliphaunt-mobile-bindings"
   - "liboliphaunt-native"
+  - id: "shared-test-fixtures"
+    scope: "development"
+  - id: "cluster-seed-contract"
+    scope: "development"
 
 project:
   title: "Oliphaunt Swift SDK"
@@ -32,58 +37,108 @@ fileGroups:
     - "!release.toml"
 
 tasks:
-  compile:
-    tags: ["quality", "static"]
-    command: "swift build --scratch-path ../../../target/moon/oliphaunt-swift/compile"
+  prepare-bindings:
+    tags: ["build", "requires-rust"]
+    deps:
+      - "oliphaunt-mobile-bindings:generate"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    command: "bash tools/prepare-bindings.sh"
+    options:
+      cache: false
+  package-bindings:
+    tags: ["package", "requires-apple", "requires-rust", "requires-swift", "ci-swift-bindings"]
+    deps:
+      - "oliphaunt-mobile-bindings:generate"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    command: "bash tools/build-bindings-xcframework.sh"
+    outputs:
+      - "/target/oliphaunt-swift/release-assets/*"
+      - "/target/mobile-bindings/generated/OliphauntNativeBindings.swift"
+    options:
+      cache: false
+  build:
+    deps:
+      - "prepare-bindings"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    tags: ["build", "requires-swift"]
+    command: "swift build"
     inputs:
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
       - "@group(code)"
     options:
-      cache: true
-  unit:
-    tags: ["quality", "unit"]
+      cache: false
+  test:
+    deps:
+      - "prepare-bindings"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    tags: ["quality", "unit", "requires-swift"]
     script: |
       set -e
-      sh tools/test-c-bridge.sh
-      swift test --scratch-path ../../../target/moon/oliphaunt-swift/unit
+      swift test
     inputs:
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - project: "cluster-seed-contract"
+        group: "contract"
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
       - "@group(code)"
       - "!/src/sdks/swift/.build"
       - "!/src/sdks/swift/.build/**"
     options:
       cache: true
-  smoke:
-    tags: ["runtime", "smoke"]
+  test-apple:
+    deps:
+      - "prepare-bindings"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    tags: ["quality", "unit", "requires-apple", "requires-swift"]
+    command: "swift test --filter ApplePlatformTests"
+    inputs:
+      - "@group(code)"
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
+  test-native:
+    tags: ["runtime", "smoke", "requires-swift"]
     script: |
       set -e
-      . src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh
+      . src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
       oliphaunt_runtime_native_host_require basic
       env OLIPHAUNT_SWIFT_REQUIRE_NATIVE=1 \
         LIBOLIPHAUNT_PATH="$(oliphaunt_runtime_native_host_lib)" \
         OLIPHAUNT_INSTALL_DIR="$(oliphaunt_runtime_native_host_install_dir)" \
-        swift test --package-path src/sdks/swift --scratch-path target/moon/oliphaunt-swift/smoke
+        swift test --package-path src/sdks/swift --filter NativeRuntimeTests
     deps:
-      - "liboliphaunt-native:host-smoke"
+      - "oliphaunt-swift:prepare-bindings"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+      - "liboliphaunt-native:build-runtime-desktop-target"
     inputs:
+      - project: "shared-test-fixtures"
+        group: "fixtures"
+      - project: "cluster-seed-contract"
+        group: "contract"
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
       - project: "liboliphaunt-native"
         group: "runtime"
       - "@group(code)"
       - "!/src/sdks/swift/.build"
       - "!/src/sdks/swift/.build/**"
-      - "/src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh"
+      - "/src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh"
     options:
       cache: local
       runFromWorkspaceRoot: true
-  package:
+  package-source:
     tags: ["package"]
     script: |
       set -e
       rm -rf target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive
       mkdir -p target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/package
       rsync -a --exclude .build --exclude .swiftpm src/sdks/swift/ target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/package/
+      cp src/runtimes/liboliphaunt-native/include/oliphaunt.h target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/package/Sources/COliphaunt/include/oliphaunt.h
       cp LICENSE THIRD_PARTY_NOTICES.md target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/package/
       chmod 0644 target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/package/LICENSE target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/package/THIRD_PARTY_NOTICES.md
-      swift package --package-path target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/package archive-source --output target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/Oliphaunt-source.zip
+      bun tools/packaging/archive-directory.mts --keep-parent target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/package target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/Oliphaunt-source.zip
     inputs:
+      - "/tools/packaging/archive-directory.mts"
+      - "/tools/packaging/portable-archive.mts"
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
       - "@group(legal-files)"
       - "**/*"
       - "!/src/sdks/swift/.build"
@@ -93,14 +148,76 @@ tasks:
     options:
       cache: local
       runFromWorkspaceRoot: true
-  qualify:
-    tags: ["release", "package"]
-    command: "true"
+  coverage:
+    deps:
+      - "prepare-bindings"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+    tags: ["coverage", "requires-swift"]
+    command: "swift test --enable-code-coverage --scratch-path ../../../target/coverage/oliphaunt-swift"
+    inputs: ["@group(code)"]
+    outputs: ["/target/coverage/oliphaunt-swift/**/*"]
+    options:
+      cache: false
+      runInCI: false
+
+  package:
+    tags: ["release", "artifact-package", "ci-swift-sdk-package"]
+    script: |
+      set -eu
+      bash tools/dev/bun.sh src/sdks/swift/tools/stage-release-artifacts.mts
+      bash tools/dev/bun.sh src/sdks/swift/tools/check-package.mts
+    env:
+      OLIPHAUNT_SWIFT_RELEASE_ASSET_DIR: "target/liboliphaunt/abi-compatible-release-assets/ios-datum64"
     deps:
-      - "oliphaunt-swift:compile"
-      - "oliphaunt-swift:unit"
-      - "oliphaunt-swift:package"
-      - "oliphaunt-swift:smoke"
-    inputs: []
+      - "oliphaunt-swift:package-bindings"
+      - {target: "oliphaunt-mobile-bindings:cargo-sources", cacheStrategy: hash}
+      - "oliphaunt-swift:package-source"
+      - "liboliphaunt-native:finalize-runtime-ios-abi"
+    inputs:
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
+      - "/tools/packaging/portable-archive.mts"
+      - "/src/database-resources/contracts/*.mts"
+      - "/tools/packaging/emit-javascript.mts"
+      - "@group(legal-files)"
+      - "@group(release-archive-contract)"
+      - "@group(release-target-contract)"
+      - "/src/sdks/swift/tools/check-package.mts"
+      - "/src/extensions/artifacts/packages/tools/contrib-carriers.mts"
+      - "/src/sdks/swift/tools/ios-carrier-manifest.mts"
+      - "/src/sdks/swift/tools/prepare-swift-release-consumer.mts"
+      - "/tools/release/release-graph.mts"
+      - "/tools/packaging/staging.mts"
+      - "/src/sdks/swift/tools/stage-release-artifacts.mts"
+      - "/src/sdks/swift/tools/swift-source-carrier-contract.mts"
+      - "/Package.swift"
+      - "/src/extensions/generated/sdk/extensions.json"
+      - "/target/liboliphaunt/abi-compatible-release-assets/ios-datum64/**/*"
+      - "/tools/dev/bun.sh"
+      - "/src/third-party/tools/source-fetch-core.mts"
+    outputs:
+      - "/target/sdk-artifacts/oliphaunt-swift/**/*"
+    options:
+      cache: local
+      runFromWorkspaceRoot: true
+
+  test-packaging:
+    tags: ["quality", "unit"]
+    script: |
+      set -eu
+      bash src/sdks/swift/tools/swift-carrier-resolver.test.sh
+      bun src/sdks/swift/tools/extension-resource-inventory.test.mts
+      bash tools/dev/bun.sh test --timeout=30000 ./src/sdks/swift/tools/ios-carrier-manifest.test.mts ./src/sdks/swift/tools/render_swiftpm_release_package.test.mts ./src/sdks/swift/tools/check-package.test.mts ./src/sdks/swift/tools/prepare-swift-release-consumer.test.mts ./src/sdks/swift/tools/swift-extension-release-consumer-inputs.test.mts
+    inputs:
+      - "@group(release-target-contract)"
+      - "@group(package-test-metadata)"
+      - "**/*.{mjs,mts,sh}"
+      - "Tests/Fixtures/**/*"
+      - "@group(legal-files)"
+      - "/tools/packaging/testdata/**/*"
+      - "/tools/dev/bun.sh"
+      - "/tools/packaging/*.{mts,sh}"
+      - "/src/database-resources/contracts/*.mts"
+      - "/tools/release/*.{mjs,mts}"
     options:
       cache: true
+      runFromWorkspaceRoot: true
diff --git a/src/sdks/swift/release.toml b/src/sdks/swift/release.toml
index babaea9db..c7f14bdc9 100644
--- a/src/sdks/swift/release.toml
+++ b/src/sdks/swift/release.toml
@@ -8,7 +8,6 @@ release_artifacts = [
   "apple-assets-via-liboliphaunt",
   "exact-extension-xcframework-inputs",
 ]
-derived_version_files = ["Package.swift"]
 
 [compatibility_versions.oliphaunt-swift-liboliphaunt]
 source_product = "liboliphaunt-native"
diff --git a/src/sdks/swift/tools/bridge-mutex-init-failure.c b/src/sdks/swift/tools/bridge-mutex-init-failure.c
deleted file mode 100644
index b54c23b36..000000000
--- a/src/sdks/swift/tools/bridge-mutex-init-failure.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 200809L
-#endif
-
-#define pthread_mutex_init oliphaunt_test_pthread_mutex_init
-#define pthread_mutex_destroy oliphaunt_test_pthread_mutex_destroy
-#include "../Sources/COliphaunt/bridge.c"
-#undef pthread_mutex_init
-#undef pthread_mutex_destroy
-
-#include 
-
-static int mutex_init_calls;
-static int mutex_destroy_calls;
-
-int oliphaunt_test_pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attributes) {
-    (void)mutex;
-    (void)attributes;
-    mutex_init_calls += 1;
-    return EAGAIN;
-}
-
-int oliphaunt_test_pthread_mutex_destroy(pthread_mutex_t *mutex) {
-    (void)mutex;
-    mutex_destroy_calls += 1;
-    return 0;
-}
-
-int main(void) {
-    OliphauntConfig config = {0};
-    OliphauntSession *session = (OliphauntSession *)(uintptr_t)1;
-    int32_t rc = oliphaunt_swift_open(NULL, &config, &session);
-    if (rc == 0 || session != NULL || mutex_init_calls != 1 || mutex_destroy_calls != 0) {
-        fprintf(stderr, "Swift bridge accepted a failed session mutex initialization\n");
-        return 1;
-    }
-
-    char error[256] = {0};
-    char expected_status[32];
-    snprintf(expected_status, sizeof(expected_status), "(%d)", EAGAIN);
-    size_t required = oliphaunt_swift_copy_last_error(NULL, error, sizeof(error));
-    if (required != strlen(error) ||
-        strstr(error, "failed to initialize OliphauntSession error mutex") == NULL ||
-        strstr(error, expected_status) == NULL) {
-        fprintf(stderr, "Swift bridge did not preserve the mutex failure: %s\n", error);
-        return 1;
-    }
-
-    puts("Swift bridge mutex initialization failure handling passed");
-    return 0;
-}
diff --git a/src/sdks/swift/tools/build-bindings-xcframework.sh b/src/sdks/swift/tools/build-bindings-xcframework.sh
new file mode 100644
index 000000000..79b919ec2
--- /dev/null
+++ b/src/sdks/swift/tools/build-bindings-xcframework.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+cd "$root"
+[[ "$(uname -s)" == Darwin ]] || { echo "XCFramework assembly requires Xcode on macOS" >&2; exit 2; }
+bash src/sdks/rust/mobile-bindings/tools/generate.sh
+stage="$root/target/mobile-bindings/apple"
+mkdir -p "$stage/headers"
+cp target/mobile-bindings/generated/OliphauntNativeBindingsFFI.h "$stage/headers/"
+cp target/mobile-bindings/generated/OliphauntNativeBindingsFFI.modulemap "$stage/headers/module.modulemap"
+export IPHONEOS_DEPLOYMENT_TARGET=17.0
+export MACOSX_DEPLOYMENT_TARGET=14.0
+arguments=()
+for target in aarch64-apple-ios aarch64-apple-ios-sim aarch64-apple-darwin; do
+  cargo rustc --locked -p oliphaunt-mobile-bindings --release --target "$target" --lib --crate-type staticlib
+  arguments+=(-library "${CARGO_TARGET_DIR:-$root/target}/$target/release/liboliphaunt_mobile_bindings.a" -headers "$stage/headers")
+done
+rm -rf "$stage/OliphauntNativeBindingsFFI.xcframework"
+xcodebuild -create-xcframework "${arguments[@]}" -output "$stage/OliphauntNativeBindingsFFI.xcframework"
+for target in ios-arm64 ios-simulator-arm64 macos-arm64; do
+  bash tools/dev/bun.sh tools/packaging/release-notices.mts stage \
+    "$stage/OliphauntNativeBindingsFFI.xcframework/licenses/$target" --profile source-sdk
+  bash tools/dev/bun.sh src/sdks/rust/mobile-bindings/tools/dependency-license-contract.mts stage \
+    "$stage/OliphauntNativeBindingsFFI.xcframework/licenses/$target" --target "$target"
+done
+version="$(cat src/sdks/swift/VERSION)"
+mkdir -p target/oliphaunt-swift/release-assets
+bash tools/dev/bun.sh tools/packaging/archive-directory.mts --keep-parent \
+  "$stage/OliphauntNativeBindingsFFI.xcframework" \
+  "target/oliphaunt-swift/release-assets/oliphaunt-swift-$version-bindings.xcframework.zip"
+cd target/oliphaunt-swift/release-assets
+shasum -a 256 "./oliphaunt-swift-$version-bindings.xcframework.zip" > "oliphaunt-swift-$version-release-assets.sha256"
diff --git a/src/sdks/swift/tools/check-extension-release-consumer.sh b/src/sdks/swift/tools/check-extension-release-consumer.sh
index 69ca97d8e..534d2488a 100755
--- a/src/sdks/swift/tools/check-extension-release-consumer.sh
+++ b/src/sdks/swift/tools/check-extension-release-consumer.sh
@@ -74,12 +74,12 @@ safe_extract_zip() {
 	if [ -e "$destination" ] || [ -L "$destination" ]; then
 		fail "verified ZIP destination already exists: $destination"
 	fi
-	node src/sdks/swift/tools/extract-verified-zip.mjs \
+	bun src/sdks/swift/tools/extract-verified-zip.mts \
 		--archive "$archive" \
 		--destination "$destination"
 }
 
-for command in git node swift unzip; do
+for command in git bun swift unzip; do
 	require_command "$command"
 done
 
@@ -110,32 +110,20 @@ for carrier in "${extension_carriers[@]}"; do
 	extension_carrier_args+=(--extension-carrier "$carrier")
 done
 carrier_plan="$(
-	tools/dev/bun.sh tools/release/swift-extension-release-consumer-inputs.mjs \
+	tools/dev/bun.sh src/sdks/swift/tools/swift-extension-release-consumer-inputs.mts \
 		"${carrier_input_args[@]}"
 )"
 extensions_csv="$(
-	tools/dev/bun.sh -e '
-    const plan = JSON.parse(Bun.argv[1]);
-    process.stdout.write(plan.extensionsCsv);
-  ' "$carrier_plan"
+	tools/dev/bun.sh src/sdks/swift/tools/extension-release-consumer.mts extensions "$carrier_plan"
 )"
 extension="$(
-	tools/dev/bun.sh -e '
-    const plan = JSON.parse(Bun.argv[1]);
-    process.stdout.write(plan.finalLink.nativeExtension ?? "");
-  ' "$carrier_plan"
+	tools/dev/bun.sh src/sdks/swift/tools/extension-release-consumer.mts extension "$carrier_plan"
 )"
 final_link_kind="$(
-	tools/dev/bun.sh -e '
-    const plan = JSON.parse(Bun.argv[1]);
-    process.stdout.write(plan.finalLink.kind);
-  ' "$carrier_plan"
+	tools/dev/bun.sh src/sdks/swift/tools/extension-release-consumer.mts kind "$carrier_plan"
 )"
 planned_native_version="$(
-	tools/dev/bun.sh -e '
-    const plan = JSON.parse(Bun.argv[1]);
-    process.stdout.write(plan.finalLink.runtimeVersion);
-  ' "$carrier_plan"
+	tools/dev/bun.sh src/sdks/swift/tools/extension-release-consumer.mts version "$carrier_plan"
 )"
 [ -n "$extensions_csv" ] || fail "independent extension carriers selected no extensions"
 case "$final_link_kind" in
@@ -148,7 +136,7 @@ native-extension)
 *) fail "independent extension carrier plan returned unknown final-link kind: $final_link_kind" ;;
 esac
 
-native_version="$(tools/dev/bun.sh tools/release/product-version.mjs version liboliphaunt-native)"
+native_version="$(tools/dev/bun.sh tools/release/product-version.mts version liboliphaunt-native)"
 [ "$planned_native_version" = "$native_version" ] ||
 	fail "carrier plan requires liboliphaunt-native $planned_native_version, but the candidate builds $native_version"
 source_archive="$sdk_artifact_dir/Oliphaunt-source.zip"
@@ -169,19 +157,25 @@ require_directory swift-source-package "$scratch/source/package"
 cp -R "$scratch/source/package/." "$release_package/src/sdks/swift/"
 cp -R "$release_tree/." "$release_package/"
 safe_extract_zip "$xcframework_archive" "$release_package/Artifacts"
+swift_version="$(cat src/sdks/swift/VERSION)"
+bindings_archive="$sdk_artifact_dir/release-assets/oliphaunt-swift-$swift_version-bindings.xcframework.zip"
+require_file "$bindings_archive"
+safe_extract_zip "$bindings_archive" "$scratch/bindings"
+mv "$scratch/bindings/OliphauntNativeBindingsFFI.xcframework" "$release_package/Artifacts/"
 require_directory apple-xcframework "$release_package/Artifacts/liboliphaunt.xcframework"
 require_directory macos-arm64-base-slice "$release_package/Artifacts/liboliphaunt.xcframework/macos-arm64"
 library="$release_package/Artifacts/liboliphaunt.xcframework/macos-arm64/liboliphaunt.framework/liboliphaunt"
 require_file "$library"
 [ -x "$library" ] || fail "macOS base framework library is not executable: $library"
-tools/dev/bun.sh tools/release/prepare-swift-release-consumer.mjs \
+tools/dev/bun.sh src/sdks/swift/tools/prepare-swift-release-consumer.mts \
 	--manifest "$release_manifest" \
 	--asset "$xcframework_archive" \
+	--bindings-asset "$bindings_archive" \
 	--output "$release_package/Package.swift"
 
 selected_package="$scratch/selected-extensions"
 cache="$scratch/carrier-cache"
-node src/sdks/swift/tools/render-extension-products.mjs \
+bun src/sdks/swift/tools/render-extension-products.mts \
 	--carrier "$cache_warm_carrier" \
 	--extensions "$extensions_csv" \
 	--cache-dir "$cache" \
@@ -189,7 +183,7 @@ node src/sdks/swift/tools/render-extension-products.mjs \
 	--local-binary-targets \
 	--base-package-path "$release_package" \
 	--output-dir "$scratch/cache-warm-package"
-node src/sdks/swift/tools/render-extension-products.mjs \
+bun src/sdks/swift/tools/render-extension-products.mts \
 	--carrier "$source_carrier" \
 	"${extension_carrier_args[@]}" \
 	--extensions "$extensions_csv" \
@@ -203,127 +197,12 @@ products="$selected_package/extension-products.json"
 require_file "$products"
 consumer="$scratch/consumer"
 mkdir -p "$consumer/Sources/OliphauntExtensionReleaseConsumer"
-# JavaScript template interpolation is evaluated by Bun.
-# shellcheck disable=SC2016
 OLIPHAUNT_CARRIER_PLAN="$carrier_plan" \
 	OLIPHAUNT_EXTENSION_PRODUCTS="$products" \
 	OLIPHAUNT_RELEASE_PACKAGE="$release_package" \
 	OLIPHAUNT_SELECTED_PACKAGE="$selected_package" \
 	OLIPHAUNT_EXTENSION_CONSUMER="$consumer" \
-	tools/dev/bun.sh -e '
-    import path from "node:path";
-    const plan = JSON.parse(process.env.OLIPHAUNT_CARRIER_PLAN);
-    const products = JSON.parse(await Bun.file(process.env.OLIPHAUNT_EXTENSION_PRODUCTS).text());
-    if (!Array.isArray(products.selected) || products.selected.length === 0) {
-      throw new Error("generated extension package selected no products");
-    }
-    const selected = products.selected.map((row, index) => {
-      const swiftProduct = row?.swiftProduct;
-      if (typeof swiftProduct !== "string" || !/^[A-Za-z][A-Za-z0-9]*$/u.test(swiftProduct)) {
-        throw new Error(`generated extension package selected[${index}] has an invalid Swift product name`);
-      }
-      if (typeof row.sqlName !== "string" || !/^[A-Za-z0-9._-]+$/u.test(row.sqlName)) {
-        throw new Error(`generated extension package selected[${index}] has an invalid SQL name`);
-      }
-      if (typeof row.product !== "string" || !/^oliphaunt-extension-[A-Za-z0-9._-]+$/u.test(row.product)) {
-        throw new Error(`generated extension package selected[${index}] has an invalid release product`);
-      }
-      if (
-        row.nativeModuleStem !== null
-        && (typeof row.nativeModuleStem !== "string" || !/^[A-Za-z0-9._-]+$/u.test(row.nativeModuleStem))
-      ) {
-        throw new Error(`generated extension package selected[${index}] has an invalid native module stem`);
-      }
-      return {
-        nativeModuleStem: row.nativeModuleStem,
-        product: row.product,
-        sqlName: row.sqlName,
-        swiftProduct,
-      };
-    });
-    if (new Set(selected.map(({ swiftProduct }) => swiftProduct)).size !== selected.length) {
-      throw new Error("generated extension package repeats a Swift product name");
-    }
-    if (new Set(selected.map(({ sqlName }) => sqlName)).size !== selected.length) {
-      throw new Error("generated extension package repeats an extension SQL name");
-    }
-    const actualExtensions = selected.map(({ sqlName }) => sqlName).sort();
-    if (JSON.stringify(actualExtensions) !== JSON.stringify(plan.extensions)) {
-      throw new Error("generated extension package does not exactly cover the carrier-planned extension set");
-    }
-    const actualProducts = [...new Set(selected.map(({ product }) => product))].sort();
-    if (JSON.stringify(actualProducts) !== JSON.stringify(plan.extensionProducts)) {
-      throw new Error("generated extension package does not exactly cover the carrier-planned release products");
-    }
-    if (
-      products.nativeRuntime?.product !== plan.finalLink.runtimeProduct
-      || products.nativeRuntime?.version !== plan.finalLink.runtimeVersion
-    ) {
-      throw new Error("generated extension package native runtime identity differs from the final-link plan");
-    }
-    let finalLink = null;
-    if (plan.finalLink.kind === "native-extension") {
-      finalLink = selected.find(({ sqlName }) => sqlName === plan.finalLink.nativeExtension) ?? null;
-      if (finalLink === null || finalLink.nativeModuleStem !== plan.finalLink.nativeModuleStem) {
-        throw new Error(
-          `generated extension package is missing the planned native final-link extension ${plan.finalLink.nativeExtension}/${plan.finalLink.nativeModuleStem}`,
-        );
-      }
-    } else if (plan.finalLink.kind === "base-runtime") {
-      if (
-        plan.finalLink.nativeExtension !== null
-        || plan.finalLink.nativeModuleStem !== null
-        || selected.some(({ nativeModuleStem }) => nativeModuleStem !== null)
-      ) {
-        throw new Error("base-runtime final-link proof requires an entirely SQL-only extension selection");
-      }
-    } else {
-      throw new Error(`unknown final-link proof kind ${plan.finalLink.kind}`);
-    }
-    const packagePath = JSON.stringify(path.resolve(process.env.OLIPHAUNT_SELECTED_PACKAGE));
-    const releasePackagePath = JSON.stringify(path.resolve(process.env.OLIPHAUNT_RELEASE_PACKAGE));
-    const dependencies = [
-      `.product(name: "COliphaunt", package: "oliphaunt")`,
-      ...selected.map(({ swiftProduct }) =>
-        `.product(name: ${JSON.stringify(swiftProduct)}, package: "selectedExtensions")`),
-    ].join(", ");
-    const packageFile = `// swift-tools-version: 6.0\n\n` +
-      `import PackageDescription\n\n` +
-      `let package = Package(\n` +
-      `    name: "OliphauntExtensionReleaseConsumer",\n` +
-      `    platforms: [.macOS(.v14)],\n` +
-      `    dependencies: [\n` +
-      `        .package(name: "oliphaunt", path: ${releasePackagePath}),\n` +
-      `        .package(name: "selectedExtensions", path: ${packagePath})\n` +
-      `    ],\n` +
-      `    targets: [\n` +
-      `        .executableTarget(\n` +
-      `            name: "OliphauntExtensionReleaseConsumer",\n` +
-      `            dependencies: [${dependencies}]\n` +
-      `        )\n` +
-      `    ]\n` +
-      `)\n`;
-    const runtimeVersion = JSON.stringify(plan.finalLink.runtimeVersion);
-    const nativeAssertion = finalLink === null
-      ? `print("OLIPHAUNT_SWIFT_BASE_RUNTIME_LINK_PASS runtime=\\(linkedNativeRuntimeVersion!) products=${selected.length}")\n`
-      : `precondition(${finalLink.swiftProduct}.sqlName == ${JSON.stringify(finalLink.sqlName)} && ${finalLink.swiftProduct}.product == ${JSON.stringify(finalLink.product)}, "planned native extension identity mismatch")\n` +
-        `print("OLIPHAUNT_SWIFT_NATIVE_EXTENSION_LINK_PASS extension=${finalLink.sqlName} native_module=${finalLink.nativeModuleStem} runtime=\\(linkedNativeRuntimeVersion!) products=${selected.length}")\n`;
-    const main = `import COliphaunt\n${selected.map(({ swiftProduct }) => `import ${swiftProduct}`).join("\n")}\n\n` +
-      `${selected.map(({ swiftProduct }) => `try ${swiftProduct}.register()`).join("\n")}\n` +
-      `let linkedNativeRuntimeVersion = oliphaunt_version().map { String(cString: $0) }\n` +
-      `precondition(linkedNativeRuntimeVersion == ${runtimeVersion}, "linked liboliphaunt runtime version mismatch")\n` +
-      nativeAssertion;
-    await Bun.write(path.join(process.env.OLIPHAUNT_EXTENSION_CONSUMER, "Package.swift"), packageFile);
-    await Bun.write(
-      path.join(
-        process.env.OLIPHAUNT_EXTENSION_CONSUMER,
-        "Sources",
-        "OliphauntExtensionReleaseConsumer",
-        "main.swift",
-      ),
-      main,
-    );
-  '
+	tools/dev/bun.sh src/sdks/swift/tools/extension-release-consumer.mts write-consumer
 
 echo "==> Building and running a macOS exact-extension Swift consumer (proof=$final_link_kind${extension:+ extension=$extension})"
 swift package \
diff --git a/src/sdks/swift/tools/check-package.mts b/src/sdks/swift/tools/check-package.mts
new file mode 100644
index 000000000..d94eb66df
--- /dev/null
+++ b/src/sdks/swift/tools/check-package.mts
@@ -0,0 +1,184 @@
+#!/usr/bin/env bun
+import path from 'node:path';
+import { ROOT, compareText } from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  PREFIX,
+  directoryNames,
+  fail,
+  inspectSdkProduct,
+  isDirectory,
+  isFile,
+  readZipEntries,
+  rejectSdkRuntimePayload,
+  rel,
+} from '../../../../tools/packaging/release-carrier.mts';
+import { existsSync, readFileSync, readdirSync } from 'node:fs';
+import {
+  validateSelectionNeutralSwiftSourceCarrierFile,
+  validateSwiftSourceReleaseContract,
+} from './swift-source-carrier-contract.mts';
+import { productCompatibilityVersion } from '../../../../tools/release/release-graph.mts';
+import {
+  bundleJavaScript,
+  releaseJavaScript,
+} from '../../../../tools/packaging/emit-javascript.mts';
+
+const SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT = path.join(
+  ROOT,
+  'src/sdks/swift/Tests/Fixtures/swiftpm-extension-resources',
+);
+
+const SWIFT_SOURCE_FIXTURE_ARCHIVE_ROOT = 'package/Tests/Fixtures/swiftpm-extension-resources';
+
+export function validateSwiftSourceFixtureEntries(artifact, entries) {
+  if (!(entries instanceof Map)) {
+    throw new Error(`${rel(artifact)} Swift source fixture entries must be a Map`);
+  }
+  if (!isDirectory(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT)) {
+    throw new Error(
+      `${rel(artifact)} cannot validate Swift source fixtures because ` +
+        `${rel(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT)} is missing`,
+    );
+  }
+
+  const prefix = `${SWIFT_SOURCE_FIXTURE_ARCHIVE_ROOT}/`;
+  const expectedNames = directoryNames(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT)
+    .map((name) => `${prefix}${name}`)
+    .sort(compareText);
+  const actualNames = [...entries]
+    .filter(([name, entry]) => name.startsWith(prefix) && entry.isFile)
+    .map(([name]) => name)
+    .sort(compareText);
+  if (JSON.stringify(actualNames) !== JSON.stringify(expectedNames)) {
+    const expected = new Set(expectedNames);
+    const actual = new Set(actualNames);
+    const missing = expectedNames.filter((name) => !actual.has(name));
+    const extra = actualNames.filter((name) => !expected.has(name));
+    throw new Error(
+      `${rel(artifact)} Swift source fixture file set must exactly match ` +
+        `${rel(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT)}; missing=${JSON.stringify(missing)}, ` +
+        `extra=${JSON.stringify(extra)}`,
+    );
+  }
+
+  for (const archiveName of expectedNames) {
+    const repositoryName = archiveName.slice(prefix.length);
+    const repositoryFile = path.join(
+      SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT,
+      ...repositoryName.split('/'),
+    );
+    const actual = Buffer.from(entries.get(archiveName).data());
+    const expected = readFileSync(repositoryFile);
+    if (!actual.equals(expected)) {
+      throw new Error(
+        `${rel(artifact)} Swift source fixture ${archiveName} must byte-for-byte match ` +
+          rel(repositoryFile),
+      );
+    }
+  }
+
+  return new Set(expectedNames);
+}
+
+export async function checkSwiftPackage(root) {
+  const product = 'oliphaunt-swift';
+  let checked = false;
+
+  const archives = readdirSync(root)
+    .filter((name) => name.endsWith('.zip'))
+    .map((name) => path.join(root, name))
+    .sort(compareText);
+  if (archives.length === 0) {
+    fail(`${product} must stage a source zip under ${rel(root)}`);
+  }
+  for (const archive of archives) {
+    const entries = readZipEntries(archive);
+    const names = [...entries]
+      .filter(([, entry]) => entry.isFile)
+      .map(([name]) => name)
+      .sort(compareText);
+    let allowedFixtureNames;
+    try {
+      allowedFixtureNames = validateSwiftSourceFixtureEntries(archive, entries);
+    } catch (error) {
+      fail(error instanceof Error ? error.message : String(error));
+    }
+    rejectSdkRuntimePayload(product, archive, names, allowedFixtureNames);
+    checked = true;
+  }
+  const releaseManifest = path.join(root, 'Package.swift.release');
+  if (!existsSync(releaseManifest)) {
+    fail(`${product} must stage ${rel(releaseManifest)} for release installation`);
+  }
+  if (existsSync(releaseManifest)) {
+    const text = readFileSync(releaseManifest, 'utf8');
+    if (text.includes('file://')) {
+      fail(`${rel(releaseManifest)} must not contain local file URLs`);
+    }
+    if (!text.includes('liboliphaunt-native-v') || !text.includes('checksum:')) {
+      fail(`${rel(releaseManifest)} must reference checksummed public liboliphaunt assets`);
+    }
+    const sourceCarrier = path.join(
+      root,
+      'release-tree/src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json',
+    );
+    if (!isFile(sourceCarrier)) {
+      fail(`${product} must stage its selection-neutral source carrier at ${rel(sourceCarrier)}`);
+    }
+    try {
+      const carrier = validateSelectionNeutralSwiftSourceCarrierFile(
+        sourceCarrier,
+        rel(sourceCarrier),
+      );
+      validateSwiftSourceReleaseContract({
+        carrier,
+        expectedNativeVersion: productCompatibilityVersion(
+          'oliphaunt-swift',
+          'liboliphaunt-native',
+          PREFIX,
+        ),
+        label: `${product} staged source release`,
+        manifestText: text,
+      });
+    } catch (error) {
+      fail(error instanceof Error ? error.message : String(error));
+    }
+  }
+  const generatorRoot = path.join(root, 'extension-generator');
+  for (const [name, source] of [
+    [
+      'extension-owner-catalog.json',
+      path.join(ROOT, 'src/extensions/generated/sdk/extensions.json'),
+    ],
+    [
+      'extension-resource-inventory.mjs',
+      path.join(ROOT, 'src/sdks/swift/tools/extension-resource-inventory.mts'),
+    ],
+    [
+      'render-extension-products.mjs',
+      path.join(ROOT, 'src/sdks/swift/tools/render-extension-products.mts'),
+    ],
+    [
+      'swift-carrier-resolver.mjs',
+      path.join(ROOT, 'src/sdks/swift/tools/swift-carrier-resolver.mts'),
+    ],
+  ]) {
+    const frozen = path.join(generatorRoot, name);
+    if (!isFile(frozen)) {
+      fail(`${product} must stage frozen extension generator input ${rel(frozen)}`);
+    }
+    const expected =
+      name === 'swift-carrier-resolver.mjs'
+        ? await bundleJavaScript(source)
+        : source.endsWith('.mts')
+          ? releaseJavaScript(source)
+          : readFileSync(source);
+    if (!readFileSync(frozen).equals(expected)) {
+      fail(`${rel(frozen)} must byte-for-byte match the release output of ${rel(source)}`);
+    }
+  }
+
+  return checked;
+}
+
+if (import.meta.main) await inspectSdkProduct('oliphaunt-swift', checkSwiftPackage);
diff --git a/src/sdks/swift/tools/check-package.test.mts b/src/sdks/swift/tools/check-package.test.mts
new file mode 100644
index 000000000..9a6409d8f
--- /dev/null
+++ b/src/sdks/swift/tools/check-package.test.mts
@@ -0,0 +1,92 @@
+import test from 'node:test';
+import path from 'node:path';
+import { readFileSync, readdirSync, statSync } from 'node:fs';
+import { validateSwiftSourceFixtureEntries } from './check-package.mts';
+import assert from 'node:assert/strict';
+import { findSdkRuntimePayloadViolation } from '../../../../tools/packaging/release-carrier.mts';
+
+const REPOSITORY_ROOT = path.join(import.meta.dir, '../Tests/Fixtures/swiftpm-extension-resources');
+
+const ARCHIVE_ROOT = 'package/Tests/Fixtures/swiftpm-extension-resources';
+
+function fixtureFiles(root = REPOSITORY_ROOT) {
+  const files = [];
+  const visit = (directory) => {
+    for (const name of readdirSync(directory).sort()) {
+      const file = path.join(directory, name);
+      if (statSync(file).isDirectory()) {
+        visit(file);
+      } else if (statSync(file).isFile()) {
+        files.push(file);
+      }
+    }
+  };
+  visit(root);
+  return files;
+}
+
+function repositoryFixtureEntries() {
+  return new Map(
+    fixtureFiles().map((file) => {
+      const relative = path.relative(REPOSITORY_ROOT, file).split(path.sep).join('/');
+      const bytes = readFileSync(file);
+      return [`${ARCHIVE_ROOT}/${relative}`, { isFile: true, data: () => bytes }];
+    }),
+  );
+}
+
+test('permits only an exact byte-for-byte Swift extension-resource fixture mirror', () => {
+  const entries = repositoryFixtureEntries();
+  const allowed = validateSwiftSourceFixtureEntries('Oliphaunt-source.zip', entries);
+
+  assert.deepEqual([...allowed].sort(), [...entries.keys()].sort());
+  assert.equal(
+    findSdkRuntimePayloadViolation('oliphaunt-swift', [...entries.keys()], allowed),
+    null,
+  );
+});
+
+test('rejects missing and extra Swift extension-resource fixture files', () => {
+  const missing = repositoryFixtureEntries();
+  missing.delete(missing.keys().next().value);
+  assert.throws(
+    () => validateSwiftSourceFixtureEntries('missing.zip', missing),
+    /file set must exactly match.*missing=\["/u,
+  );
+
+  const extra = repositoryFixtureEntries();
+  extra.set(`${ARCHIVE_ROOT}/unexpected/extra.control`, {
+    isFile: true,
+    data: () => Buffer.from('unexpected\n'),
+  });
+  assert.throws(
+    () => validateSwiftSourceFixtureEntries('extra.zip', extra),
+    /file set must exactly match.*extra=\["/u,
+  );
+});
+
+test('rejects tampered Swift extension-resource fixture bytes', () => {
+  const entries = repositoryFixtureEntries();
+  const [name, entry] = entries.entries().next().value;
+  entries.set(name, {
+    ...entry,
+    data: () => Buffer.concat([Buffer.from(entry.data()), Buffer.from('tampered')]),
+  });
+
+  assert.throws(
+    () => validateSwiftSourceFixtureEntries('tampered.zip', entries),
+    /must byte-for-byte match/u,
+  );
+});
+
+test('continues to reject runtime payloads outside the exact fixture subtree', () => {
+  const entries = repositoryFixtureEntries();
+  const allowed = validateSwiftSourceFixtureEntries('Oliphaunt-source.zip', entries);
+  const outsideFixture =
+    'package/Sources/Oliphaunt/Resources/runtime/files/share/postgresql/extension/pgtap.control';
+
+  assert.equal(
+    findSdkRuntimePayloadViolation('oliphaunt-swift', [...entries.keys(), outsideFixture], allowed),
+    outsideFixture,
+  );
+});
diff --git a/src/sdks/swift/tools/extension-release-consumer.mts b/src/sdks/swift/tools/extension-release-consumer.mts
new file mode 100644
index 000000000..43884beaf
--- /dev/null
+++ b/src/sdks/swift/tools/extension-release-consumer.mts
@@ -0,0 +1,150 @@
+import path from 'node:path';
+const [command, input] = Bun.argv.slice(2);
+if (command === 'write-consumer') {
+  const plan = JSON.parse(process.env.OLIPHAUNT_CARRIER_PLAN);
+  const products = JSON.parse(await Bun.file(process.env.OLIPHAUNT_EXTENSION_PRODUCTS).text());
+  if (!Array.isArray(products.selected) || products.selected.length === 0) {
+    throw new Error('generated extension package selected no products');
+  }
+  const selected = products.selected.map((row, index) => {
+    const swiftProduct = row?.swiftProduct;
+    if (typeof swiftProduct !== 'string' || !/^[A-Za-z][A-Za-z0-9]*$/u.test(swiftProduct)) {
+      throw new Error(
+        `generated extension package selected[${index}] has an invalid Swift product name`,
+      );
+    }
+    if (typeof row.sqlName !== 'string' || !/^[A-Za-z0-9._-]+$/u.test(row.sqlName)) {
+      throw new Error(`generated extension package selected[${index}] has an invalid SQL name`);
+    }
+    if (
+      typeof row.product !== 'string' ||
+      !/^oliphaunt-extension-[A-Za-z0-9._-]+$/u.test(row.product)
+    ) {
+      throw new Error(
+        `generated extension package selected[${index}] has an invalid release product`,
+      );
+    }
+    if (
+      row.nativeModuleStem !== null &&
+      (typeof row.nativeModuleStem !== 'string' || !/^[A-Za-z0-9._-]+$/u.test(row.nativeModuleStem))
+    ) {
+      throw new Error(
+        `generated extension package selected[${index}] has an invalid native module stem`,
+      );
+    }
+    return {
+      nativeModuleStem: row.nativeModuleStem,
+      product: row.product,
+      sqlName: row.sqlName,
+      swiftProduct,
+    };
+  });
+  if (new Set(selected.map(({ swiftProduct }) => swiftProduct)).size !== selected.length) {
+    throw new Error('generated extension package repeats a Swift product name');
+  }
+  if (new Set(selected.map(({ sqlName }) => sqlName)).size !== selected.length) {
+    throw new Error('generated extension package repeats an extension SQL name');
+  }
+  const actualExtensions = selected.map(({ sqlName }) => sqlName).sort();
+  if (JSON.stringify(actualExtensions) !== JSON.stringify(plan.extensions)) {
+    throw new Error(
+      'generated extension package does not exactly cover the carrier-planned extension set',
+    );
+  }
+  const actualProducts = [...new Set(selected.map(({ product }) => product))].sort();
+  if (JSON.stringify(actualProducts) !== JSON.stringify(plan.extensionProducts)) {
+    throw new Error(
+      'generated extension package does not exactly cover the carrier-planned release products',
+    );
+  }
+  if (
+    products.nativeRuntime?.product !== plan.finalLink.runtimeProduct ||
+    products.nativeRuntime?.version !== plan.finalLink.runtimeVersion
+  ) {
+    throw new Error(
+      'generated extension package native runtime identity differs from the final-link plan',
+    );
+  }
+  let finalLink = null;
+  if (plan.finalLink.kind === 'native-extension') {
+    finalLink = selected.find(({ sqlName }) => sqlName === plan.finalLink.nativeExtension) ?? null;
+    if (finalLink === null || finalLink.nativeModuleStem !== plan.finalLink.nativeModuleStem) {
+      throw new Error(
+        `generated extension package is missing the planned native final-link extension ${plan.finalLink.nativeExtension}/${plan.finalLink.nativeModuleStem}`,
+      );
+    }
+  } else if (plan.finalLink.kind === 'base-runtime') {
+    if (
+      plan.finalLink.nativeExtension !== null ||
+      plan.finalLink.nativeModuleStem !== null ||
+      selected.some(({ nativeModuleStem }) => nativeModuleStem !== null)
+    ) {
+      throw new Error(
+        'base-runtime final-link proof requires an entirely SQL-only extension selection',
+      );
+    }
+  } else {
+    throw new Error(`unknown final-link proof kind ${plan.finalLink.kind}`);
+  }
+  const packagePath = JSON.stringify(path.resolve(process.env.OLIPHAUNT_SELECTED_PACKAGE));
+  const releasePackagePath = JSON.stringify(path.resolve(process.env.OLIPHAUNT_RELEASE_PACKAGE));
+  const dependencies = [
+    `.product(name: "COliphaunt", package: "oliphaunt")`,
+    ...selected.map(
+      ({ swiftProduct }) =>
+        `.product(name: ${JSON.stringify(swiftProduct)}, package: "selectedExtensions")`,
+    ),
+  ].join(', ');
+  const packageFile =
+    `// swift-tools-version: 6.0\n\n` +
+    `import PackageDescription\n\n` +
+    `let package = Package(\n` +
+    `    name: "OliphauntExtensionReleaseConsumer",\n` +
+    `    platforms: [.macOS(.v14)],\n` +
+    `    dependencies: [\n` +
+    `        .package(name: "oliphaunt", path: ${releasePackagePath}),\n` +
+    `        .package(name: "selectedExtensions", path: ${packagePath})\n` +
+    `    ],\n` +
+    `    targets: [\n` +
+    `        .executableTarget(\n` +
+    `            name: "OliphauntExtensionReleaseConsumer",\n` +
+    `            dependencies: [${dependencies}]\n` +
+    `        )\n` +
+    `    ]\n` +
+    `)\n`;
+  const runtimeVersion = JSON.stringify(plan.finalLink.runtimeVersion);
+  const nativeAssertion =
+    finalLink === null
+      ? `print("OLIPHAUNT_SWIFT_BASE_RUNTIME_LINK_PASS runtime=\\(linkedNativeRuntimeVersion!) products=${selected.length}")\n`
+      : `precondition(${finalLink.swiftProduct}.sqlName == ${JSON.stringify(finalLink.sqlName)} && ${finalLink.swiftProduct}.product == ${JSON.stringify(finalLink.product)}, "planned native extension identity mismatch")\n` +
+        `print("OLIPHAUNT_SWIFT_NATIVE_EXTENSION_LINK_PASS extension=${finalLink.sqlName} native_module=${finalLink.nativeModuleStem} runtime=\\(linkedNativeRuntimeVersion!) products=${selected.length}")\n`;
+  const main =
+    `import COliphaunt\n${selected.map(({ swiftProduct }) => `import ${swiftProduct}`).join('\n')}\n\n` +
+    `${selected.map(({ swiftProduct }) => `try ${swiftProduct}.register()`).join('\n')}\n` +
+    `let linkedNativeRuntimeVersion = oliphaunt_version().map { String(cString: $0) }\n` +
+    `precondition(linkedNativeRuntimeVersion == ${runtimeVersion}, "linked liboliphaunt runtime version mismatch")\n` +
+    nativeAssertion;
+  await Bun.write(
+    path.join(process.env.OLIPHAUNT_EXTENSION_CONSUMER, 'Package.swift'),
+    packageFile,
+  );
+  await Bun.write(
+    path.join(
+      process.env.OLIPHAUNT_EXTENSION_CONSUMER,
+      'Sources',
+      'OliphauntExtensionReleaseConsumer',
+      'main.swift',
+    ),
+    main,
+  );
+} else {
+  const plan = JSON.parse(input);
+  const value = {
+    extensions: plan.extensionsCsv,
+    extension: plan.finalLink.nativeExtension ?? '',
+    kind: plan.finalLink.kind,
+    version: plan.finalLink.runtimeVersion,
+  }[command];
+  if (typeof value !== 'string') throw Error('unknown Swift release consumer command');
+  process.stdout.write(value);
+}
diff --git a/src/sdks/swift/tools/extension-resource-inventory.mjs b/src/sdks/swift/tools/extension-resource-inventory.mjs
deleted file mode 100644
index f42b9b432..000000000
--- a/src/sdks/swift/tools/extension-resource-inventory.mjs
+++ /dev/null
@@ -1,781 +0,0 @@
-import { createHash } from "node:crypto";
-import { constants as fsConstants } from "node:fs";
-import fs from "node:fs/promises";
-import path from "node:path";
-import { TextDecoder } from "node:util";
-
-const PROPERTY_KEYS = Object.freeze([
-  "packageLayout",
-  "pgMajor",
-  "sqlName",
-  "createsExtension",
-  "nativeModuleStem",
-  "nativeModuleFile",
-  "nativeTarget",
-  "nativeRuntimeProduct",
-  "nativeRuntimeVersion",
-  "dependencies",
-  "dataFiles",
-  "extensionSqlFileNames",
-  "extensionSqlFilePrefixes",
-  "sharedPreloadLibraries",
-  "mobilePrebuilt",
-  "mobileStaticArchives",
-  "mobileStaticDependencyArchives",
-  "staticSymbolPrefix",
-  "staticSymbolAliases",
-  "licenseFiles",
-  "licenseProfile",
-  "files",
-]);
-const LEGAL_MEMBERS_BY_PROFILE = Object.freeze({
-  "contrib-native": Object.freeze([
-    "LICENSE",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "THIRD_PARTY_NOTICES.md",
-  ]),
-  "contrib-native-openssl": Object.freeze([
-    "LICENSE",
-    "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt",
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT",
-    "THIRD_PARTY_NOTICES.md",
-  ]),
-  "external-native": Object.freeze([
-    "LICENSE",
-    "THIRD_PARTY_NOTICES.md",
-  ]),
-});
-const PORTABLE = /^[A-Za-z0-9._-]{1,128}$/u;
-const C_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u;
-const STABLE_SEMVER = /^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u;
-const MAX_FILES = 4096;
-const MAX_FILE_BYTES = 48 * 1024 * 1024;
-const MAX_TREE_BYTES = 256 * 1024 * 1024;
-const OWNER_CATALOG_FILENAME = "extension-owner-catalog.json";
-const UTF8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
-
-function fail(label, message) {
-  throw new Error(`${label}: ${message}`);
-}
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function canonicalRelativePath(value, label) {
-  if (
-    typeof value !== "string"
-    || value.length === 0
-    || value.includes("\\")
-    || value !== value.normalize("NFC")
-    || /[\u0000-\u001f\u007f]/u.test(value)
-    || value.startsWith("/")
-    || /^[A-Za-z]:/u.test(value)
-  ) {
-    fail(label, "must be a canonical NFC relative path without backslashes");
-  }
-  const parts = value.split("/");
-  if (parts.some((part) => part.length === 0 || part === "." || part === "..")) {
-    fail(label, "must not contain empty, '.' or '..' components");
-  }
-  return parts.join("/");
-}
-
-export function createPortablePathCollisionTracker(label) {
-  const paths = new Map();
-  return (relative) => {
-    if (typeof relative !== "string") fail(label, "contains a non-string path");
-    // The upper/lower round-trip catches multi-code-point folds such as
-    // sharp-s while NFC gives canonically equivalent spellings one key.
-    const collisionKey = relative
-      .normalize("NFC")
-      .toUpperCase()
-      .toLowerCase()
-      .normalize("NFC");
-    const collision = paths.get(collisionKey);
-    if (collision !== undefined && collision !== relative) {
-      fail(label, `contains case/NFC-colliding paths ${collision} and ${relative}`);
-    }
-    paths.set(collisionKey, relative);
-  };
-}
-
-function canonicalList(value, label, validator = undefined) {
-  if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
-    fail(label, "must be a string array");
-  }
-  const rows = value.map((item, index) => validator?.(item, `${label}[${index}]`) ?? item);
-  const sorted = [...rows].sort(compareText);
-  if (new Set(rows).size !== rows.length || JSON.stringify(rows) !== JSON.stringify(sorted)) {
-    fail(label, "must be sorted and unique");
-  }
-  return rows;
-}
-
-function portable(value, label) {
-  if (typeof value !== "string" || !PORTABLE.test(value)) fail(label, "must be a portable identifier");
-  return value;
-}
-
-function normalizeCanonicalRow(row, label) {
-  const sqlName = portable(row?.["sql-name"], `${label}.sql-name`);
-  const product = portable(row?.["artifact-product"], `${label}.artifact-product`);
-  const releaseProduct = portable(row?.["release-product"], `${label}.release-product`);
-  const createsExtension = row?.["creates-extension"];
-  if (typeof createsExtension !== "boolean") fail(label, "creates-extension must be boolean");
-  const nativeModuleStem = row?.["native-module-stem"] ?? null;
-  if (nativeModuleStem !== null) portable(nativeModuleStem, `${label}.native-module-stem`);
-  const extensionSqlFileNames = canonicalList(
-    row?.["extension-sql-file-names"],
-    `${label}.extension-sql-file-names`,
-  );
-  if (extensionSqlFileNames.some((name) =>
-    !PORTABLE.test(name) || path.posix.basename(name) !== name || !name.endsWith(".sql"))) {
-    fail(label, "extension-sql-file-names must contain SQL basenames");
-  }
-  const extensionSqlFilePrefixes = canonicalList(
-    row?.["extension-sql-file-prefixes"],
-    `${label}.extension-sql-file-prefixes`,
-  );
-  if (extensionSqlFilePrefixes.some((prefix) => !PORTABLE.test(prefix) || prefix.includes("."))) {
-    fail(label, "extension-sql-file-prefixes must contain portable basename prefixes");
-  }
-  return {
-    sqlName,
-    product,
-    releaseProduct,
-    createsExtension,
-    nativeModuleStem,
-    dependencies: canonicalList(
-      row?.["selected-extension-dependencies"],
-      `${label}.selected-extension-dependencies`,
-      portable,
-    ),
-    dataFiles: canonicalList(
-      row?.["runtime-share-data-files"],
-      `${label}.runtime-share-data-files`,
-      canonicalRelativePath,
-    ),
-    extensionSqlFileNames,
-    extensionSqlFilePrefixes,
-    sharedPreloadLibraries: canonicalList(
-      row?.["shared-preload-libraries"],
-      `${label}.shared-preload-libraries`,
-      portable,
-    ),
-  };
-}
-
-function normalizeFrozenRuntimeContract(row, label) {
-  const sqlName = portable(row?.sqlName, `${label}.sqlName`);
-  const product = portable(row?.product, `${label}.product`);
-  const releaseProduct = portable(row?.releaseProduct, `${label}.releaseProduct`);
-  if (typeof row?.createsExtension !== "boolean") fail(label, "createsExtension must be boolean");
-  const nativeModuleStem = row?.nativeModuleStem ?? null;
-  if (nativeModuleStem !== null) portable(nativeModuleStem, `${label}.nativeModuleStem`);
-  const dependencies = canonicalList(
-    row?.dependencies,
-    `${label}.dependencies`,
-    portable,
-  );
-  if (dependencies.includes(sqlName)) fail(label, "dependencies must not include the extension itself");
-  const extensionSqlFileNames = canonicalList(
-    row?.extensionSqlFileNames,
-    `${label}.extensionSqlFileNames`,
-    portable,
-  );
-  if (extensionSqlFileNames.some((name) => !name.endsWith(".sql"))) {
-    fail(label, "extensionSqlFileNames must contain SQL basenames");
-  }
-  const extensionSqlFilePrefixes = canonicalList(
-    row?.extensionSqlFilePrefixes,
-    `${label}.extensionSqlFilePrefixes`,
-  );
-  if (extensionSqlFilePrefixes.some((prefix) => !/^[A-Za-z0-9_-]{1,128}$/u.test(prefix))) {
-    fail(label, "extensionSqlFilePrefixes must contain dot-free portable basename prefixes");
-  }
-  return {
-    createsExtension: row.createsExtension,
-    dataFiles: canonicalList(
-      row?.dataFiles,
-      `${label}.dataFiles`,
-      canonicalRelativePath,
-    ),
-    dependencies,
-    extensionSqlFileNames,
-    extensionSqlFilePrefixes,
-    nativeModuleStem,
-    product,
-    releaseProduct,
-    sharedPreloadLibraries: canonicalList(
-      row?.sharedPreloadLibraries,
-      `${label}.sharedPreloadLibraries`,
-      portable,
-    ),
-    sqlName,
-  };
-}
-
-export async function loadSwiftExtensionInventoryCatalog(ownerCatalogFile = undefined) {
-  const candidates = ownerCatalogFile === undefined
-    ? [
-        path.join(import.meta.dirname, OWNER_CATALOG_FILENAME),
-        path.resolve(import.meta.dirname, "../../../extensions/generated/sdk/extensions.json"),
-      ]
-    : [path.resolve(ownerCatalogFile)];
-  let selected;
-  for (const candidate of candidates) {
-    const metadata = await fs.stat(candidate).catch(() => null);
-    if (metadata?.isFile() === true) {
-      selected = candidate;
-      break;
-    }
-  }
-  if (selected === undefined) {
-    fail("Swift extension inventory", `canonical owner catalog is missing; expected ${candidates.join(" or ")}`);
-  }
-  let document;
-  try {
-    document = JSON.parse(await fs.readFile(selected, "utf8"));
-  } catch (error) {
-    fail("Swift extension inventory", `could not read ${selected}: ${error.message}`);
-  }
-  if (document?.["format-version"] !== 1 || !Array.isArray(document.extensions) || document.extensions.length === 0) {
-    fail(selected, "is not the generated extension catalog");
-  }
-  const rows = new Map();
-  for (const [index, row] of document.extensions.entries()) {
-    const normalized = normalizeCanonicalRow(row, `${selected}.extensions[${index}]`);
-    if (rows.has(normalized.sqlName)) fail(selected, `repeats canonical SQL name ${normalized.sqlName}`);
-    rows.set(normalized.sqlName, normalized);
-  }
-  return rows;
-}
-
-function parseProperties(text, label) {
-  if (
-    typeof text !== "string"
-    || text.startsWith("\uFEFF")
-    || text.includes("\r")
-    || text.includes("\\")
-    || text !== text.normalize("NFC")
-    || /[\u0000-\u0009\u000b-\u001f\u007f]/u.test(text)
-    || !text.endsWith("\n")
-    || text.endsWith("\n\n")
-  ) {
-    fail(label, "must be canonical NFC UTF-8 key=value text with LF and one final newline");
-  }
-  const properties = new Map();
-  for (const [index, line] of text.slice(0, -1).split("\n").entries()) {
-    const separator = line.indexOf("=");
-    if (line.length === 0 || separator <= 0 || line.trim() !== line) {
-      fail(label, `has malformed physical line ${index + 1}`);
-    }
-    const key = line.slice(0, separator);
-    if (properties.has(key)) fail(label, `repeats property ${key}`);
-    properties.set(key, line.slice(separator + 1));
-  }
-  if (JSON.stringify([...properties.keys()]) !== JSON.stringify(PROPERTY_KEYS)) {
-    fail(label, `must contain the exact canonical fields in canonical order: ${PROPERTY_KEYS.join(",")}`);
-  }
-  return properties;
-}
-
-function decodeUtf8(bytes, label) {
-  try {
-    return UTF8.decode(bytes);
-  } catch (error) {
-    fail(label, `contains invalid UTF-8: ${error.message}`);
-  }
-}
-
-function csv(value, label) {
-  if (typeof value !== "string") fail(label, "must be a string");
-  if (value === "") return [];
-  const rows = value.split(",");
-  if (
-    rows.some((row) => row.length === 0 || row.trim() !== row)
-    || new Set(rows).size !== rows.length
-    || JSON.stringify(rows) !== JSON.stringify([...rows].sort(compareText))
-  ) {
-    fail(label, "must be a sorted unique canonical CSV");
-  }
-  return rows;
-}
-
-function orderedCsv(value, label) {
-  if (typeof value !== "string") fail(label, "must be a string");
-  if (value === "") return [];
-  const rows = value.split(",");
-  if (
-    rows.some((row) => row.length === 0 || row.trim() !== row)
-    || new Set(rows).size !== rows.length
-  ) {
-    fail(label, "must be a unique canonical CSV");
-  }
-  return rows;
-}
-
-function legalPaths(properties, extension, contract, label) {
-  const licenseFiles = csv(
-    properties.get("licenseFiles"),
-    `${label} licenseFiles`,
-  ).map((relative, index) => canonicalRelativePath(
-    relative,
-    `${label} licenseFiles[${index}]`,
-  ));
-  if (licenseFiles.some((relative) => !relative.startsWith("share/licenses/"))) {
-    fail(label, "manifest licenseFiles must live under share/licenses/");
-  }
-  const contrib = extension.product === "oliphaunt-extension-contrib-pg18";
-  const dependencyNames = Array.isArray(extension?.nativeDependencies)
-    ? extension.nativeDependencies.map(({ name }) => name)
-    : [];
-  const expectedProfile = contrib
-    ? contract.sqlName === "pgcrypto" && dependencyNames.includes("openssl")
-      ? "contrib-native-openssl"
-      : "contrib-native"
-    : "external-native";
-  if (properties.get("licenseProfile") !== expectedProfile) {
-    fail(label, `manifest licenseProfile must be ${JSON.stringify(expectedProfile)}`);
-  }
-  if (contrib && licenseFiles.length !== 0) {
-    fail(label, "contrib artifacts must not declare external upstream licenseFiles");
-  }
-  if (!contrib && licenseFiles.length === 0) {
-    fail(label, "external artifacts must declare at least one upstream licenseFile");
-  }
-  return [
-    ...LEGAL_MEMBERS_BY_PROFILE[expectedProfile],
-    ...licenseFiles.map((relative) => `files/${relative}`),
-  ].sort(compareText);
-}
-
-function mobileStaticPaths(
-  properties,
-  extension,
-  contract,
-  label,
-  allowMobileCarrierArchives,
-) {
-  const archiveRows = csv(
-    properties.get("mobileStaticArchives"),
-    `${label} mobileStaticArchives`,
-  );
-  const dependencyRows = orderedCsv(
-    properties.get("mobileStaticDependencyArchives"),
-    `${label} mobileStaticDependencyArchives`,
-  );
-  if (!Array.isArray(extension?.nativeDependencies)) {
-    fail(label, "nativeDependencies must be an array");
-  }
-  const dependencyNames = canonicalList(
-    extension.nativeDependencies.map((dependency, index) =>
-      portable(dependency?.name, `${label}.nativeDependencies[${index}].name`)),
-    `${label}.nativeDependencies`,
-  );
-  if (allowMobileCarrierArchives !== true) {
-    if (archiveRows.length > 0 || dependencyRows.length > 0) {
-      fail(label, "manifest mobile static archives are only valid for carrier-resolved inputs");
-    }
-    return [];
-  }
-  if (contract.nativeModuleStem === null) {
-    if (dependencyNames.length > 0) {
-      fail(label, "SQL-only artifacts must not declare native dependencies");
-    }
-    if (archiveRows.length > 0 || dependencyRows.length > 0) {
-      fail(label, "SQL-only artifacts must not declare mobile static archives");
-    }
-    return [];
-  }
-
-  const targets = ["ios-device", "ios-simulator"];
-  const expectedArchives = targets.map(
-    (target) =>
-      `${target}:mobile-static/${target}/extensions/${contract.nativeModuleStem}/` +
-      `liboliphaunt_extension_${contract.nativeModuleStem}.a`,
-  );
-  if (JSON.stringify(archiveRows) !== JSON.stringify(expectedArchives)) {
-    fail(
-      label,
-      `mobileStaticArchives must exactly cover ${expectedArchives.join(",")}`,
-    );
-  }
-
-  const parsedDependencies = dependencyRows.map((row, index) => {
-    const fields = row.split(":");
-    if (fields.length !== 3) {
-      fail(label, `mobileStaticDependencyArchives[${index}] is malformed`);
-    }
-    const [target, dependency, relative] = fields;
-    if (!targets.includes(target) || !dependencyNames.includes(dependency)) {
-      fail(
-        label,
-        `mobileStaticDependencyArchives[${index}] has an unknown target or dependency`,
-      );
-    }
-    const canonical = canonicalRelativePath(
-      relative,
-      `${label} mobileStaticDependencyArchives[${index}] path`,
-    );
-    const directory = `mobile-static/${target}/dependencies/${dependency}`;
-    const archiveName = path.posix.basename(canonical);
-    if (
-      path.posix.dirname(canonical) !== directory ||
-      !/^lib[A-Za-z0-9._-]+\.a$/u.test(archiveName)
-    ) {
-      fail(
-        label,
-        `mobileStaticDependencyArchives[${index}] must name a portable lib*.a directly under ${directory}`,
-      );
-    }
-    return { archiveName, dependency, relative: canonical, target };
-  });
-  const expectedDependencyKeys = targets.flatMap((target) =>
-    dependencyNames.map((dependency) => `${target}\0${dependency}`));
-  const dependencyKeys = parsedDependencies.map(
-    ({ dependency, target }) => `${target}\0${dependency}`,
-  );
-  if (JSON.stringify(dependencyKeys) !== JSON.stringify(expectedDependencyKeys)) {
-    fail(
-      label,
-      "mobileStaticDependencyArchives must exactly cover both iOS targets and every native dependency",
-    );
-  }
-  const archiveNameByDependency = new Map();
-  for (const { archiveName, dependency } of parsedDependencies) {
-    const prior = archiveNameByDependency.get(dependency);
-    if (prior !== undefined && archiveName !== prior) {
-      fail(
-        label,
-        `mobileStaticDependencyArchives must use the same archive file name across both iOS targets for ${dependency}`,
-      );
-    }
-    archiveNameByDependency.set(dependency, archiveName);
-  }
-  return [
-    ...archiveRows.map((row) => row.slice(row.indexOf(":") + 1)),
-    ...parsedDependencies.map(({ relative }) => relative),
-  ];
-}
-
-function sameFileIdentity(left, right) {
-  return (
-    left.dev === right.dev
-    && left.ino === right.ino
-    && left.mode === right.mode
-    && left.size === right.size
-    && left.mtimeNs === right.mtimeNs
-    && left.ctimeNs === right.ctimeNs
-  );
-}
-
-async function snapshotRegularFile(absolute, label, maxFileBytes) {
-  const before = await fs.lstat(absolute, { bigint: true });
-  if (before.isSymbolicLink() || !before.isFile()) {
-    fail(label, "must remain a regular file and must not be a symlink");
-  }
-  if (before.size > BigInt(maxFileBytes)) {
-    fail(label, "exceeds the bounded member size");
-  }
-  let handle;
-  try {
-    handle = await fs.open(
-      absolute,
-      fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0),
-    );
-  } catch (error) {
-    fail(label, `could not be opened without following a symlink: ${error.message}`);
-  }
-  try {
-    const opened = await handle.stat({ bigint: true });
-    if (!opened.isFile() || !sameFileIdentity(before, opened)) {
-      fail(label, "changed between path validation and opening");
-    }
-    const contents = await handle.readFile();
-    const after = await handle.stat({ bigint: true });
-    if (
-      !sameFileIdentity(opened, after)
-      || BigInt(contents.length) !== opened.size
-    ) {
-      fail(label, "changed while its bytes were being read");
-    }
-    return {
-      bytes: contents.length,
-      contents,
-      device: opened.dev.toString(),
-      inode: opened.ino.toString(),
-      mode: Number(opened.mode & 0o777n),
-      sha256: createHash("sha256").update(contents).digest("hex"),
-    };
-  } finally {
-    await handle.close();
-  }
-}
-
-export async function readSafeFileSnapshot(file, label = file?.absolute ?? "file snapshot") {
-  if (
-    file === null
-    || typeof file !== "object"
-    || typeof file.absolute !== "string"
-    || !Number.isSafeInteger(file.bytes)
-    || file.bytes < 0
-    || typeof file.device !== "string"
-    || typeof file.inode !== "string"
-    || !Number.isInteger(file.mode)
-    || file.mode < 0
-    || file.mode > 0o777
-    || typeof file.sha256 !== "string"
-    || !/^[a-f0-9]{64}$/u.test(file.sha256)
-  ) {
-    fail(label, "is not a validated file snapshot");
-  }
-  const current = await snapshotRegularFile(
-    file.absolute,
-    label,
-    Math.max(file.bytes, 1),
-  );
-  if (
-    current.bytes !== file.bytes
-    || current.device !== file.device
-    || current.inode !== file.inode
-    || current.mode !== file.mode
-    || current.sha256 !== file.sha256
-  ) {
-    fail(label, "changed after validation; refusing to copy unvalidated bytes");
-  }
-  return current.contents;
-}
-
-export async function snapshotSafeFileTree(
-  root,
-  label,
-  {
-    maxFiles = MAX_FILES,
-    maxFileBytes = MAX_FILE_BYTES,
-    maxTreeBytes = MAX_TREE_BYTES,
-  } = {},
-) {
-  for (const [value, name] of [
-    [maxFiles, "maxFiles"],
-    [maxFileBytes, "maxFileBytes"],
-    [maxTreeBytes, "maxTreeBytes"],
-  ]) {
-    if (!Number.isSafeInteger(value) || value <= 0) {
-      fail(label, `${name} must be a positive safe integer`);
-    }
-  }
-  const files = [];
-  const directories = [];
-  const trackPortablePath = createPortablePathCollisionTracker(label);
-  let totalBytes = 0;
-  const visit = async (absolute, relative) => {
-    if (relative !== "") {
-      trackPortablePath(relative);
-      canonicalRelativePath(relative, `${label} path`);
-    }
-    const metadata = await fs.lstat(absolute, { bigint: true });
-    if (metadata.isSymbolicLink()) fail(label, `contains symlink ${relative || "."}`);
-    if (metadata.isDirectory()) {
-      const entries = (await fs.readdir(absolute)).sort(compareText);
-      for (const entry of entries) {
-        await visit(path.join(absolute, entry), relative === "" ? entry : `${relative}/${entry}`);
-      }
-      const after = await fs.lstat(absolute, { bigint: true });
-      if (!after.isDirectory() || !sameFileIdentity(metadata, after)) {
-        fail(label, `directory ${relative || "."} changed while it was being inventoried`);
-      }
-      if (relative !== "") {
-        directories.push({
-          device: after.dev.toString(),
-          inode: after.ino.toString(),
-          mode: Number(after.mode & 0o777n),
-          relative,
-        });
-      }
-      return;
-    }
-    if (!metadata.isFile()) fail(label, `contains unsupported entry ${relative}`);
-    const snapshot = await snapshotRegularFile(absolute, `${label} file ${relative}`, maxFileBytes);
-    totalBytes += snapshot.bytes;
-    if (totalBytes > maxTreeBytes) fail(label, "exceeds the bounded expanded tree size");
-    files.push({
-      absolute,
-      bytes: snapshot.bytes,
-      device: snapshot.device,
-      inode: snapshot.inode,
-      mode: snapshot.mode,
-      relative,
-      sha256: snapshot.sha256,
-    });
-    if (files.length > maxFiles) fail(label, "contains too many files");
-  };
-  await visit(root, "");
-  directories.sort((left, right) => compareText(left.relative, right.relative));
-  Object.defineProperty(files, "directories", {
-    configurable: false,
-    enumerable: false,
-    value: directories,
-    writable: false,
-  });
-  return files;
-}
-
-function sqlOwned(fileName, canonical) {
-  return (
-    (canonical.createsExtension && fileName === `${canonical.sqlName}.control`)
-    || (canonical.createsExtension && fileName === `${canonical.sqlName}.sql`)
-    || (canonical.createsExtension
-      && fileName.startsWith(`${canonical.sqlName}--`)
-      && fileName.endsWith(".sql"))
-    || canonical.extensionSqlFileNames.includes(fileName)
-    || (fileName.endsWith(".sql")
-      && canonical.extensionSqlFilePrefixes.some((prefix) => fileName.startsWith(prefix)))
-  );
-}
-
-function isCanonicalInstallSql(fileName, sqlName) {
-  if (fileName === `${sqlName}.sql`) return true;
-  const prefix = `${sqlName}--`;
-  if (!fileName.startsWith(prefix) || !fileName.endsWith(".sql")) return false;
-  const version = fileName.slice(prefix.length, -".sql".length);
-  return /^[0-9][A-Za-z0-9._-]*$/u.test(version) && !version.includes("--");
-}
-
-export function assertSwiftExtensionMatchesCanonical(extension, canonical, label) {
-  if (canonical === undefined) fail(label, `has no generated canonical metadata for ${extension.sqlName}`);
-  if (extension.product !== canonical.product) {
-    fail(label, "product does not match generated canonical ownership metadata");
-  }
-  if (extension.releaseProduct !== canonical.releaseProduct) {
-    fail(label, "releaseProduct does not match generated canonical ownership metadata");
-  }
-}
-
-export async function validateSwiftExtensionResourceArtifact({
-  extension,
-  canonical,
-  nativeRuntime,
-  label = extension.resourceRoot,
-  allowMobileCarrierArchives = false,
-}) {
-  assertSwiftExtensionMatchesCanonical(extension, canonical, label);
-  const contract = normalizeFrozenRuntimeContract(extension, `${label} frozen carrier contract`);
-  if (nativeRuntime?.product !== "liboliphaunt-native" || !STABLE_SEMVER.test(nativeRuntime?.version ?? "")) {
-    fail(label, "requires liboliphaunt-native at a stable X.Y.Z version");
-  }
-  const files = await snapshotSafeFileTree(extension.resourceRoot, label);
-  const byPath = new Map(files.map((file) => [file.relative, file]));
-  const manifestFile = byPath.get("manifest.properties");
-  if (manifestFile === undefined) fail(label, "is missing manifest.properties");
-  const properties = parseProperties(
-    decodeUtf8(
-      await readSafeFileSnapshot(manifestFile, manifestFile.absolute),
-      manifestFile.absolute,
-    ),
-    manifestFile.absolute,
-  );
-  const expected = new Map([
-    ["packageLayout", "oliphaunt-extension-artifact-v1"],
-    ["pgMajor", "18"],
-    ["sqlName", contract.sqlName],
-    ["createsExtension", contract.createsExtension ? "yes" : "no"],
-    ["nativeModuleStem", contract.nativeModuleStem ?? ""],
-    ["nativeModuleFile", contract.nativeModuleStem === null ? "" : `${contract.nativeModuleStem}.dylib`],
-    ["nativeTarget", "ios-xcframework"],
-    ["nativeRuntimeProduct", nativeRuntime.product],
-    ["nativeRuntimeVersion", nativeRuntime.version],
-    ["dependencies", contract.dependencies.join(",")],
-    ["dataFiles", contract.dataFiles.join(",")],
-    ["extensionSqlFileNames", contract.extensionSqlFileNames.join(",")],
-    ["extensionSqlFilePrefixes", contract.extensionSqlFilePrefixes.join(",")],
-    ["sharedPreloadLibraries", contract.sharedPreloadLibraries.join(",")],
-    ["mobilePrebuilt", contract.nativeModuleStem === null ? "no" : "yes"],
-    ["files", "files"],
-  ]);
-  for (const [key, value] of expected) {
-    if (properties.get(key) !== value) fail(label, `manifest ${key} must be ${JSON.stringify(value)}`);
-  }
-  const symbolPrefix = contract.nativeModuleStem === null
-    ? ""
-    : `oliphaunt_static_${contract.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`;
-  if (properties.get("staticSymbolPrefix") !== symbolPrefix) {
-    fail(label, `manifest staticSymbolPrefix must be ${JSON.stringify(symbolPrefix)}`);
-  }
-  const aliases = extension.registration?.symbols
-    .filter(({ name, address }) => name !== address)
-    .map(({ name, address }) => `${name}:${address}`)
-    .sort(compareText) ?? [];
-  const aliasSqlNames = aliases.map((alias) => alias.split(":")[0]);
-  if (
-    aliases.some((alias) => alias.split(":").length !== 2 || alias.split(":").some((item) => !C_IDENTIFIER.test(item)))
-    || new Set(aliasSqlNames).size !== aliasSqlNames.length
-  ) {
-    fail(label, "carrier registration contains a non-C-identifier alias pair");
-  }
-  if (properties.get("staticSymbolAliases") !== aliases.join(",")) {
-    fail(label, "manifest staticSymbolAliases do not match carrier registration metadata");
-  }
-  const allowed = new Set(["manifest.properties"]);
-  const legalFiles = legalPaths(properties, extension, contract, label);
-  for (const legalFile of legalFiles) allowed.add(legalFile);
-  for (const mobilePath of mobileStaticPaths(
-    properties,
-    extension,
-    contract,
-    label,
-    allowMobileCarrierArchives,
-  )) {
-    allowed.add(mobilePath);
-  }
-  const sqlPrefix = "files/share/postgresql/extension/";
-  let hasControl = false;
-  let hasSql = false;
-  for (const file of files) {
-    if (!file.relative.startsWith(sqlPrefix)) continue;
-    const fileName = file.relative.slice(sqlPrefix.length);
-    if (fileName.includes("/") || !sqlOwned(fileName, contract)) {
-      fail(label, `contains undeclared extension SQL/control file ${file.relative}`);
-    }
-    allowed.add(file.relative);
-    if (fileName === `${contract.sqlName}.control`) hasControl = true;
-    if (isCanonicalInstallSql(fileName, contract.sqlName)) hasSql = true;
-  }
-  if (contract.createsExtension && (!hasControl || !hasSql)) {
-    fail(label, `must contain ${contract.sqlName}.control and canonical base installation SQL`);
-  }
-  for (const dataFile of contract.dataFiles) allowed.add(`files/share/postgresql/${dataFile}`);
-  if (contract.nativeModuleStem !== null) {
-    allowed.add(`files/lib/postgresql/${contract.nativeModuleStem}.dylib`);
-  }
-  const actual = [...byPath.keys()].sort(compareText);
-  const wanted = [...allowed].sort(compareText);
-  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
-    const undeclared = actual.filter((name) => !allowed.has(name));
-    const missing = wanted.filter((name) => !byPath.has(name));
-    fail(
-      label,
-      `leaf inventory mismatch${undeclared.length ? `; undeclared: ${undeclared.join(",")}` : ""}`
-        + `${missing.length ? `; missing: ${missing.join(",")}` : ""}`,
-    );
-  }
-  for (const legalFile of legalFiles) {
-    const snapshot = byPath.get(legalFile);
-    if (snapshot.bytes === 0 || (snapshot.mode & 0o111) !== 0) {
-      fail(label, `legal file ${legalFile} must be non-empty and non-executable`);
-    }
-  }
-  return {
-    bytes: files
-      .filter(({ relative }) => relative.startsWith("files/share/postgresql/"))
-      .reduce((sum, file) => sum + file.bytes, 0),
-    createsExtension: contract.createsExtension,
-    files: files
-      .filter(({ relative }) => relative.startsWith("files/share/postgresql/"))
-      .map((file) => ({
-        ...file,
-        relative: file.relative.slice("files/share/postgresql/".length),
-      })),
-  };
-}
diff --git a/src/sdks/swift/tools/extension-resource-inventory.mts b/src/sdks/swift/tools/extension-resource-inventory.mts
new file mode 100644
index 000000000..a30af34d5
--- /dev/null
+++ b/src/sdks/swift/tools/extension-resource-inventory.mts
@@ -0,0 +1,766 @@
+import { createHash } from 'node:crypto';
+import { constants as fsConstants } from 'node:fs';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import { TextDecoder } from 'node:util';
+
+const PROPERTY_KEYS = Object.freeze([
+  'packageLayout',
+  'pgMajor',
+  'sqlName',
+  'createsExtension',
+  'nativeModuleStem',
+  'nativeModuleFile',
+  'nativeTarget',
+  'nativeRuntimeProduct',
+  'nativeRuntimeVersion',
+  'dependencies',
+  'dataFiles',
+  'extensionSqlFileNames',
+  'extensionSqlFilePrefixes',
+  'sharedPreloadLibraries',
+  'mobilePrebuilt',
+  'mobileStaticArchives',
+  'mobileStaticDependencyArchives',
+  'staticSymbolPrefix',
+  'staticSymbolAliases',
+  'licenseFiles',
+  'licenseProfile',
+  'files',
+]);
+const LEGAL_MEMBERS_BY_PROFILE = Object.freeze({
+  'contrib-native': Object.freeze([
+    'LICENSE',
+    'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT',
+    'THIRD_PARTY_NOTICES.md',
+  ]),
+  'contrib-native-openssl': Object.freeze([
+    'LICENSE',
+    'THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt',
+    'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT',
+    'THIRD_PARTY_NOTICES.md',
+  ]),
+  'external-native': Object.freeze(['LICENSE', 'THIRD_PARTY_NOTICES.md']),
+});
+const PORTABLE = /^[A-Za-z0-9._-]{1,128}$/u;
+const C_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u;
+const STABLE_SEMVER = /^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u;
+const MAX_FILES = 4096;
+const MAX_FILE_BYTES = 48 * 1024 * 1024;
+const MAX_TREE_BYTES = 256 * 1024 * 1024;
+const OWNER_CATALOG_FILENAME = 'extension-owner-catalog.json';
+const UTF8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
+
+function fail(label, message) {
+  throw new Error(`${label}: ${message}`);
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function canonicalRelativePath(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    value !== value.normalize('NFC') ||
+    /[\u0000-\u001f\u007f]/u.test(value) ||
+    value.startsWith('/') ||
+    /^[A-Za-z]:/u.test(value)
+  ) {
+    fail(label, 'must be a canonical NFC relative path without backslashes');
+  }
+  const parts = value.split('/');
+  if (parts.some((part) => part.length === 0 || part === '.' || part === '..')) {
+    fail(label, "must not contain empty, '.' or '..' components");
+  }
+  return parts.join('/');
+}
+
+export function createPortablePathCollisionTracker(label) {
+  const paths = new Map();
+  return (relative) => {
+    if (typeof relative !== 'string') fail(label, 'contains a non-string path');
+    // The upper/lower round-trip catches multi-code-point folds such as
+    // sharp-s while NFC gives canonically equivalent spellings one key.
+    const collisionKey = relative.normalize('NFC').toUpperCase().toLowerCase().normalize('NFC');
+    const collision = paths.get(collisionKey);
+    if (collision !== undefined && collision !== relative) {
+      fail(label, `contains case/NFC-colliding paths ${collision} and ${relative}`);
+    }
+    paths.set(collisionKey, relative);
+  };
+}
+
+function canonicalList(value, label, validator = undefined) {
+  if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
+    fail(label, 'must be a string array');
+  }
+  const rows = value.map((item, index) => validator?.(item, `${label}[${index}]`) ?? item);
+  const sorted = [...rows].sort(compareText);
+  if (new Set(rows).size !== rows.length || JSON.stringify(rows) !== JSON.stringify(sorted)) {
+    fail(label, 'must be sorted and unique');
+  }
+  return rows;
+}
+
+function portable(value, label) {
+  if (typeof value !== 'string' || !PORTABLE.test(value))
+    fail(label, 'must be a portable identifier');
+  return value;
+}
+
+function normalizeCanonicalRow(row, label) {
+  const sqlName = portable(row?.['sql-name'], `${label}.sql-name`);
+  const product = portable(row?.['artifact-product'], `${label}.artifact-product`);
+  const releaseProduct = portable(row?.['release-product'], `${label}.release-product`);
+  const createsExtension = row?.['creates-extension'];
+  if (typeof createsExtension !== 'boolean') fail(label, 'creates-extension must be boolean');
+  const nativeModuleStem = row?.['native-module-stem'] ?? null;
+  if (nativeModuleStem !== null) portable(nativeModuleStem, `${label}.native-module-stem`);
+  const extensionSqlFileNames = canonicalList(
+    row?.['extension-sql-file-names'],
+    `${label}.extension-sql-file-names`,
+  );
+  if (
+    extensionSqlFileNames.some(
+      (name) =>
+        !PORTABLE.test(name) || path.posix.basename(name) !== name || !name.endsWith('.sql'),
+    )
+  ) {
+    fail(label, 'extension-sql-file-names must contain SQL basenames');
+  }
+  const extensionSqlFilePrefixes = canonicalList(
+    row?.['extension-sql-file-prefixes'],
+    `${label}.extension-sql-file-prefixes`,
+  );
+  if (extensionSqlFilePrefixes.some((prefix) => !PORTABLE.test(prefix) || prefix.includes('.'))) {
+    fail(label, 'extension-sql-file-prefixes must contain portable basename prefixes');
+  }
+  return {
+    sqlName,
+    product,
+    releaseProduct,
+    createsExtension,
+    nativeModuleStem,
+    dependencies: canonicalList(
+      row?.['selected-extension-dependencies'],
+      `${label}.selected-extension-dependencies`,
+      portable,
+    ),
+    dataFiles: canonicalList(
+      row?.['runtime-share-data-files'],
+      `${label}.runtime-share-data-files`,
+      canonicalRelativePath,
+    ),
+    extensionSqlFileNames,
+    extensionSqlFilePrefixes,
+    sharedPreloadLibraries: canonicalList(
+      row?.['shared-preload-libraries'],
+      `${label}.shared-preload-libraries`,
+      portable,
+    ),
+  };
+}
+
+function normalizeFrozenRuntimeContract(row, label) {
+  const sqlName = portable(row?.sqlName, `${label}.sqlName`);
+  const product = portable(row?.product, `${label}.product`);
+  const releaseProduct = portable(row?.releaseProduct, `${label}.releaseProduct`);
+  if (typeof row?.createsExtension !== 'boolean') fail(label, 'createsExtension must be boolean');
+  const nativeModuleStem = row?.nativeModuleStem ?? null;
+  if (nativeModuleStem !== null) portable(nativeModuleStem, `${label}.nativeModuleStem`);
+  const dependencies = canonicalList(row?.dependencies, `${label}.dependencies`, portable);
+  if (dependencies.includes(sqlName))
+    fail(label, 'dependencies must not include the extension itself');
+  const extensionSqlFileNames = canonicalList(
+    row?.extensionSqlFileNames,
+    `${label}.extensionSqlFileNames`,
+    portable,
+  );
+  if (extensionSqlFileNames.some((name) => !name.endsWith('.sql'))) {
+    fail(label, 'extensionSqlFileNames must contain SQL basenames');
+  }
+  const extensionSqlFilePrefixes = canonicalList(
+    row?.extensionSqlFilePrefixes,
+    `${label}.extensionSqlFilePrefixes`,
+  );
+  if (extensionSqlFilePrefixes.some((prefix) => !/^[A-Za-z0-9_-]{1,128}$/u.test(prefix))) {
+    fail(label, 'extensionSqlFilePrefixes must contain dot-free portable basename prefixes');
+  }
+  return {
+    createsExtension: row.createsExtension,
+    dataFiles: canonicalList(row?.dataFiles, `${label}.dataFiles`, canonicalRelativePath),
+    dependencies,
+    extensionSqlFileNames,
+    extensionSqlFilePrefixes,
+    nativeModuleStem,
+    product,
+    releaseProduct,
+    sharedPreloadLibraries: canonicalList(
+      row?.sharedPreloadLibraries,
+      `${label}.sharedPreloadLibraries`,
+      portable,
+    ),
+    sqlName,
+  };
+}
+
+export async function loadSwiftExtensionInventoryCatalog(ownerCatalogFile = undefined) {
+  const candidates =
+    ownerCatalogFile === undefined
+      ? [
+          path.join(import.meta.dirname, OWNER_CATALOG_FILENAME),
+          path.resolve(import.meta.dirname, '../../../extensions/generated/sdk/extensions.json'),
+        ]
+      : [path.resolve(ownerCatalogFile)];
+  let selected;
+  for (const candidate of candidates) {
+    const metadata = await fs.stat(candidate).catch(() => null);
+    if (metadata?.isFile() === true) {
+      selected = candidate;
+      break;
+    }
+  }
+  if (selected === undefined) {
+    fail(
+      'Swift extension inventory',
+      `canonical owner catalog is missing; expected ${candidates.join(' or ')}`,
+    );
+  }
+  let document;
+  try {
+    document = JSON.parse(await fs.readFile(selected, 'utf8'));
+  } catch (error) {
+    fail('Swift extension inventory', `could not read ${selected}: ${error.message}`);
+  }
+  if (
+    document?.['format-version'] !== 1 ||
+    !Array.isArray(document.extensions) ||
+    document.extensions.length === 0
+  ) {
+    fail(selected, 'is not the generated extension catalog');
+  }
+  const rows = new Map();
+  for (const [index, row] of document.extensions.entries()) {
+    const normalized = normalizeCanonicalRow(row, `${selected}.extensions[${index}]`);
+    if (rows.has(normalized.sqlName))
+      fail(selected, `repeats canonical SQL name ${normalized.sqlName}`);
+    rows.set(normalized.sqlName, normalized);
+  }
+  return rows;
+}
+
+function parseProperties(text, label) {
+  if (
+    typeof text !== 'string' ||
+    text.startsWith('\uFEFF') ||
+    text.includes('\r') ||
+    text.includes('\\') ||
+    text !== text.normalize('NFC') ||
+    /[\u0000-\u0009\u000b-\u001f\u007f]/u.test(text) ||
+    !text.endsWith('\n') ||
+    text.endsWith('\n\n')
+  ) {
+    fail(label, 'must be canonical NFC UTF-8 key=value text with LF and one final newline');
+  }
+  const properties = new Map();
+  for (const [index, line] of text.slice(0, -1).split('\n').entries()) {
+    const separator = line.indexOf('=');
+    if (line.length === 0 || separator <= 0 || line.trim() !== line) {
+      fail(label, `has malformed physical line ${index + 1}`);
+    }
+    const key = line.slice(0, separator);
+    if (properties.has(key)) fail(label, `repeats property ${key}`);
+    properties.set(key, line.slice(separator + 1));
+  }
+  if (JSON.stringify([...properties.keys()]) !== JSON.stringify(PROPERTY_KEYS)) {
+    fail(
+      label,
+      `must contain the exact canonical fields in canonical order: ${PROPERTY_KEYS.join(',')}`,
+    );
+  }
+  return properties;
+}
+
+function decodeUtf8(bytes, label) {
+  try {
+    return UTF8.decode(bytes);
+  } catch (error) {
+    fail(label, `contains invalid UTF-8: ${error.message}`);
+  }
+}
+
+function csv(value, label) {
+  if (typeof value !== 'string') fail(label, 'must be a string');
+  if (value === '') return [];
+  const rows = value.split(',');
+  if (
+    rows.some((row) => row.length === 0 || row.trim() !== row) ||
+    new Set(rows).size !== rows.length ||
+    JSON.stringify(rows) !== JSON.stringify([...rows].sort(compareText))
+  ) {
+    fail(label, 'must be a sorted unique canonical CSV');
+  }
+  return rows;
+}
+
+function orderedCsv(value, label) {
+  if (typeof value !== 'string') fail(label, 'must be a string');
+  if (value === '') return [];
+  const rows = value.split(',');
+  if (
+    rows.some((row) => row.length === 0 || row.trim() !== row) ||
+    new Set(rows).size !== rows.length
+  ) {
+    fail(label, 'must be a unique canonical CSV');
+  }
+  return rows;
+}
+
+function legalPaths(properties, extension, contract, label) {
+  const licenseFiles = csv(properties.get('licenseFiles'), `${label} licenseFiles`).map(
+    (relative, index) => canonicalRelativePath(relative, `${label} licenseFiles[${index}]`),
+  );
+  if (licenseFiles.some((relative) => !relative.startsWith('share/licenses/'))) {
+    fail(label, 'manifest licenseFiles must live under share/licenses/');
+  }
+  const contrib = extension.product === 'oliphaunt-extension-contrib-pg18';
+  const dependencyNames = Array.isArray(extension?.nativeDependencies)
+    ? extension.nativeDependencies.map(({ name }) => name)
+    : [];
+  const expectedProfile = contrib
+    ? contract.sqlName === 'pgcrypto' && dependencyNames.includes('openssl')
+      ? 'contrib-native-openssl'
+      : 'contrib-native'
+    : 'external-native';
+  if (properties.get('licenseProfile') !== expectedProfile) {
+    fail(label, `manifest licenseProfile must be ${JSON.stringify(expectedProfile)}`);
+  }
+  if (contrib && licenseFiles.length !== 0) {
+    fail(label, 'contrib artifacts must not declare external upstream licenseFiles');
+  }
+  if (!contrib && licenseFiles.length === 0) {
+    fail(label, 'external artifacts must declare at least one upstream licenseFile');
+  }
+  return [
+    ...LEGAL_MEMBERS_BY_PROFILE[expectedProfile],
+    ...licenseFiles.map((relative) => `files/${relative}`),
+  ].sort(compareText);
+}
+
+function mobileStaticPaths(properties, extension, contract, label, allowMobileCarrierArchives) {
+  const archiveRows = csv(properties.get('mobileStaticArchives'), `${label} mobileStaticArchives`);
+  const dependencyRows = orderedCsv(
+    properties.get('mobileStaticDependencyArchives'),
+    `${label} mobileStaticDependencyArchives`,
+  );
+  if (!Array.isArray(extension?.nativeDependencies)) {
+    fail(label, 'nativeDependencies must be an array');
+  }
+  const dependencyNames = canonicalList(
+    extension.nativeDependencies.map((dependency, index) =>
+      portable(dependency?.name, `${label}.nativeDependencies[${index}].name`),
+    ),
+    `${label}.nativeDependencies`,
+  );
+  if (allowMobileCarrierArchives !== true) {
+    if (archiveRows.length > 0 || dependencyRows.length > 0) {
+      fail(label, 'manifest mobile static archives are only valid for carrier-resolved inputs');
+    }
+    return [];
+  }
+  if (contract.nativeModuleStem === null) {
+    if (dependencyNames.length > 0) {
+      fail(label, 'SQL-only artifacts must not declare native dependencies');
+    }
+    if (archiveRows.length > 0 || dependencyRows.length > 0) {
+      fail(label, 'SQL-only artifacts must not declare mobile static archives');
+    }
+    return [];
+  }
+
+  const targets = ['ios-device', 'ios-simulator'];
+  const expectedArchives = targets.map(
+    (target) =>
+      `${target}:mobile-static/${target}/extensions/${contract.nativeModuleStem}/` +
+      `liboliphaunt_extension_${contract.nativeModuleStem}.a`,
+  );
+  if (JSON.stringify(archiveRows) !== JSON.stringify(expectedArchives)) {
+    fail(label, `mobileStaticArchives must exactly cover ${expectedArchives.join(',')}`);
+  }
+
+  const parsedDependencies = dependencyRows.map((row, index) => {
+    const fields = row.split(':');
+    if (fields.length !== 3) {
+      fail(label, `mobileStaticDependencyArchives[${index}] is malformed`);
+    }
+    const [target, dependency, relative] = fields;
+    if (!targets.includes(target) || !dependencyNames.includes(dependency)) {
+      fail(label, `mobileStaticDependencyArchives[${index}] has an unknown target or dependency`);
+    }
+    const canonical = canonicalRelativePath(
+      relative,
+      `${label} mobileStaticDependencyArchives[${index}] path`,
+    );
+    const directory = `mobile-static/${target}/dependencies/${dependency}`;
+    const archiveName = path.posix.basename(canonical);
+    if (
+      path.posix.dirname(canonical) !== directory ||
+      !/^lib[A-Za-z0-9._-]+\.a$/u.test(archiveName)
+    ) {
+      fail(
+        label,
+        `mobileStaticDependencyArchives[${index}] must name a portable lib*.a directly under ${directory}`,
+      );
+    }
+    return { archiveName, dependency, relative: canonical, target };
+  });
+  const expectedDependencyKeys = targets.flatMap((target) =>
+    dependencyNames.map((dependency) => `${target}\0${dependency}`),
+  );
+  const dependencyKeys = parsedDependencies.map(
+    ({ dependency, target }) => `${target}\0${dependency}`,
+  );
+  if (JSON.stringify(dependencyKeys) !== JSON.stringify(expectedDependencyKeys)) {
+    fail(
+      label,
+      'mobileStaticDependencyArchives must exactly cover both iOS targets and every native dependency',
+    );
+  }
+  const archiveNameByDependency = new Map();
+  for (const { archiveName, dependency } of parsedDependencies) {
+    const prior = archiveNameByDependency.get(dependency);
+    if (prior !== undefined && archiveName !== prior) {
+      fail(
+        label,
+        `mobileStaticDependencyArchives must use the same archive file name across both iOS targets for ${dependency}`,
+      );
+    }
+    archiveNameByDependency.set(dependency, archiveName);
+  }
+  return [
+    ...archiveRows.map((row) => row.slice(row.indexOf(':') + 1)),
+    ...parsedDependencies.map(({ relative }) => relative),
+  ];
+}
+
+function sameFileIdentity(left, right) {
+  return (
+    left.dev === right.dev &&
+    left.ino === right.ino &&
+    left.mode === right.mode &&
+    left.size === right.size &&
+    left.mtimeNs === right.mtimeNs &&
+    left.ctimeNs === right.ctimeNs
+  );
+}
+
+async function snapshotRegularFile(absolute, label, maxFileBytes) {
+  const before = await fs.lstat(absolute, { bigint: true });
+  if (before.isSymbolicLink() || !before.isFile()) {
+    fail(label, 'must remain a regular file and must not be a symlink');
+  }
+  if (before.size > BigInt(maxFileBytes)) {
+    fail(label, 'exceeds the bounded member size');
+  }
+  let handle;
+  try {
+    handle = await fs.open(absolute, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
+  } catch (error) {
+    fail(label, `could not be opened without following a symlink: ${error.message}`);
+  }
+  try {
+    const opened = await handle.stat({ bigint: true });
+    if (!opened.isFile() || !sameFileIdentity(before, opened)) {
+      fail(label, 'changed between path validation and opening');
+    }
+    const contents = await handle.readFile();
+    const after = await handle.stat({ bigint: true });
+    if (!sameFileIdentity(opened, after) || BigInt(contents.length) !== opened.size) {
+      fail(label, 'changed while its bytes were being read');
+    }
+    return {
+      bytes: contents.length,
+      contents,
+      device: opened.dev.toString(),
+      inode: opened.ino.toString(),
+      mode: Number(opened.mode & 0o777n),
+      sha256: createHash('sha256').update(contents).digest('hex'),
+    };
+  } finally {
+    await handle.close();
+  }
+}
+
+export async function readSafeFileSnapshot(file, label = file?.absolute ?? 'file snapshot') {
+  if (
+    file === null ||
+    typeof file !== 'object' ||
+    typeof file.absolute !== 'string' ||
+    !Number.isSafeInteger(file.bytes) ||
+    file.bytes < 0 ||
+    typeof file.device !== 'string' ||
+    typeof file.inode !== 'string' ||
+    !Number.isInteger(file.mode) ||
+    file.mode < 0 ||
+    file.mode > 0o777 ||
+    typeof file.sha256 !== 'string' ||
+    !/^[a-f0-9]{64}$/u.test(file.sha256)
+  ) {
+    fail(label, 'is not a validated file snapshot');
+  }
+  const current = await snapshotRegularFile(file.absolute, label, Math.max(file.bytes, 1));
+  if (
+    current.bytes !== file.bytes ||
+    current.device !== file.device ||
+    current.inode !== file.inode ||
+    current.mode !== file.mode ||
+    current.sha256 !== file.sha256
+  ) {
+    fail(label, 'changed after validation; refusing to copy unvalidated bytes');
+  }
+  return current.contents;
+}
+
+export async function snapshotSafeFileTree(
+  root,
+  label,
+  { maxFiles = MAX_FILES, maxFileBytes = MAX_FILE_BYTES, maxTreeBytes = MAX_TREE_BYTES } = {},
+) {
+  for (const [value, name] of [
+    [maxFiles, 'maxFiles'],
+    [maxFileBytes, 'maxFileBytes'],
+    [maxTreeBytes, 'maxTreeBytes'],
+  ]) {
+    if (!Number.isSafeInteger(value) || value <= 0) {
+      fail(label, `${name} must be a positive safe integer`);
+    }
+  }
+  const files = [];
+  const directories = [];
+  const trackPortablePath = createPortablePathCollisionTracker(label);
+  let totalBytes = 0;
+  const visit = async (absolute, relative) => {
+    if (relative !== '') {
+      trackPortablePath(relative);
+      canonicalRelativePath(relative, `${label} path`);
+    }
+    const metadata = await fs.lstat(absolute, { bigint: true });
+    if (metadata.isSymbolicLink()) fail(label, `contains symlink ${relative || '.'}`);
+    if (metadata.isDirectory()) {
+      const entries = (await fs.readdir(absolute)).sort(compareText);
+      for (const entry of entries) {
+        await visit(path.join(absolute, entry), relative === '' ? entry : `${relative}/${entry}`);
+      }
+      const after = await fs.lstat(absolute, { bigint: true });
+      if (!after.isDirectory() || !sameFileIdentity(metadata, after)) {
+        fail(label, `directory ${relative || '.'} changed while it was being inventoried`);
+      }
+      if (relative !== '') {
+        directories.push({
+          device: after.dev.toString(),
+          inode: after.ino.toString(),
+          mode: Number(after.mode & 0o777n),
+          relative,
+        });
+      }
+      return;
+    }
+    if (!metadata.isFile()) fail(label, `contains unsupported entry ${relative}`);
+    const snapshot = await snapshotRegularFile(absolute, `${label} file ${relative}`, maxFileBytes);
+    totalBytes += snapshot.bytes;
+    if (totalBytes > maxTreeBytes) fail(label, 'exceeds the bounded expanded tree size');
+    files.push({
+      absolute,
+      bytes: snapshot.bytes,
+      device: snapshot.device,
+      inode: snapshot.inode,
+      mode: snapshot.mode,
+      relative,
+      sha256: snapshot.sha256,
+    });
+    if (files.length > maxFiles) fail(label, 'contains too many files');
+  };
+  await visit(root, '');
+  directories.sort((left, right) => compareText(left.relative, right.relative));
+  Object.defineProperty(files, 'directories', {
+    configurable: false,
+    enumerable: false,
+    value: directories,
+    writable: false,
+  });
+  return files;
+}
+
+function sqlOwned(fileName, canonical) {
+  return (
+    (canonical.createsExtension && fileName === `${canonical.sqlName}.control`) ||
+    (canonical.createsExtension && fileName === `${canonical.sqlName}.sql`) ||
+    (canonical.createsExtension &&
+      fileName.startsWith(`${canonical.sqlName}--`) &&
+      fileName.endsWith('.sql')) ||
+    canonical.extensionSqlFileNames.includes(fileName) ||
+    (fileName.endsWith('.sql') &&
+      canonical.extensionSqlFilePrefixes.some((prefix) => fileName.startsWith(prefix)))
+  );
+}
+
+function isCanonicalInstallSql(fileName, sqlName) {
+  if (fileName === `${sqlName}.sql`) return true;
+  const prefix = `${sqlName}--`;
+  if (!fileName.startsWith(prefix) || !fileName.endsWith('.sql')) return false;
+  const version = fileName.slice(prefix.length, -'.sql'.length);
+  return /^[0-9][A-Za-z0-9._-]*$/u.test(version) && !version.includes('--');
+}
+
+export function assertSwiftExtensionMatchesCanonical(extension, canonical, label) {
+  if (canonical === undefined)
+    fail(label, `has no generated canonical metadata for ${extension.sqlName}`);
+  if (extension.product !== canonical.product) {
+    fail(label, 'product does not match generated canonical ownership metadata');
+  }
+  if (extension.releaseProduct !== canonical.releaseProduct) {
+    fail(label, 'releaseProduct does not match generated canonical ownership metadata');
+  }
+}
+
+export async function validateSwiftExtensionResourceArtifact({
+  extension,
+  canonical,
+  nativeRuntime,
+  label = extension.resourceRoot,
+  allowMobileCarrierArchives = false,
+}) {
+  assertSwiftExtensionMatchesCanonical(extension, canonical, label);
+  const contract = normalizeFrozenRuntimeContract(extension, `${label} frozen carrier contract`);
+  if (
+    nativeRuntime?.product !== 'liboliphaunt-native' ||
+    !STABLE_SEMVER.test(nativeRuntime?.version ?? '')
+  ) {
+    fail(label, 'requires liboliphaunt-native at a stable X.Y.Z version');
+  }
+  const files = await snapshotSafeFileTree(extension.resourceRoot, label);
+  const byPath = new Map(files.map((file) => [file.relative, file]));
+  const manifestFile = byPath.get('manifest.properties');
+  if (manifestFile === undefined) fail(label, 'is missing manifest.properties');
+  const properties = parseProperties(
+    decodeUtf8(
+      await readSafeFileSnapshot(manifestFile, manifestFile.absolute),
+      manifestFile.absolute,
+    ),
+    manifestFile.absolute,
+  );
+  const expected = new Map([
+    ['packageLayout', 'oliphaunt-extension-artifact-v1'],
+    ['pgMajor', '18'],
+    ['sqlName', contract.sqlName],
+    ['createsExtension', contract.createsExtension ? 'yes' : 'no'],
+    ['nativeModuleStem', contract.nativeModuleStem ?? ''],
+    [
+      'nativeModuleFile',
+      contract.nativeModuleStem === null ? '' : `${contract.nativeModuleStem}.dylib`,
+    ],
+    ['nativeTarget', 'ios-xcframework'],
+    ['nativeRuntimeProduct', nativeRuntime.product],
+    ['nativeRuntimeVersion', nativeRuntime.version],
+    ['dependencies', contract.dependencies.join(',')],
+    ['dataFiles', contract.dataFiles.join(',')],
+    ['extensionSqlFileNames', contract.extensionSqlFileNames.join(',')],
+    ['extensionSqlFilePrefixes', contract.extensionSqlFilePrefixes.join(',')],
+    ['sharedPreloadLibraries', contract.sharedPreloadLibraries.join(',')],
+    ['mobilePrebuilt', contract.nativeModuleStem === null ? 'no' : 'yes'],
+    ['files', 'files'],
+  ]);
+  for (const [key, value] of expected) {
+    if (properties.get(key) !== value)
+      fail(label, `manifest ${key} must be ${JSON.stringify(value)}`);
+  }
+  const symbolPrefix =
+    contract.nativeModuleStem === null
+      ? ''
+      : `oliphaunt_static_${contract.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`;
+  if (properties.get('staticSymbolPrefix') !== symbolPrefix) {
+    fail(label, `manifest staticSymbolPrefix must be ${JSON.stringify(symbolPrefix)}`);
+  }
+  const aliases =
+    extension.registration?.symbols
+      .filter(({ name, address }) => name !== address)
+      .map(({ name, address }) => `${name}:${address}`)
+      .sort(compareText) ?? [];
+  const aliasSqlNames = aliases.map((alias) => alias.split(':')[0]);
+  if (
+    aliases.some(
+      (alias) =>
+        alias.split(':').length !== 2 || alias.split(':').some((item) => !C_IDENTIFIER.test(item)),
+    ) ||
+    new Set(aliasSqlNames).size !== aliasSqlNames.length
+  ) {
+    fail(label, 'carrier registration contains a non-C-identifier alias pair');
+  }
+  if (properties.get('staticSymbolAliases') !== aliases.join(',')) {
+    fail(label, 'manifest staticSymbolAliases do not match carrier registration metadata');
+  }
+  const allowed = new Set(['manifest.properties']);
+  const legalFiles = legalPaths(properties, extension, contract, label);
+  for (const legalFile of legalFiles) allowed.add(legalFile);
+  for (const mobilePath of mobileStaticPaths(
+    properties,
+    extension,
+    contract,
+    label,
+    allowMobileCarrierArchives,
+  )) {
+    allowed.add(mobilePath);
+  }
+  const sqlPrefix = 'files/share/postgresql/extension/';
+  let hasControl = false;
+  let hasSql = false;
+  for (const file of files) {
+    if (!file.relative.startsWith(sqlPrefix)) continue;
+    const fileName = file.relative.slice(sqlPrefix.length);
+    if (fileName.includes('/') || !sqlOwned(fileName, contract)) {
+      fail(label, `contains undeclared extension SQL/control file ${file.relative}`);
+    }
+    allowed.add(file.relative);
+    if (fileName === `${contract.sqlName}.control`) hasControl = true;
+    if (isCanonicalInstallSql(fileName, contract.sqlName)) hasSql = true;
+  }
+  if (contract.createsExtension && (!hasControl || !hasSql)) {
+    fail(label, `must contain ${contract.sqlName}.control and canonical base installation SQL`);
+  }
+  for (const dataFile of contract.dataFiles) allowed.add(`files/share/postgresql/${dataFile}`);
+  if (contract.nativeModuleStem !== null) {
+    allowed.add(`files/lib/postgresql/${contract.nativeModuleStem}.dylib`);
+  }
+  const actual = [...byPath.keys()].sort(compareText);
+  const wanted = [...allowed].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
+    const undeclared = actual.filter((name) => !allowed.has(name));
+    const missing = wanted.filter((name) => !byPath.has(name));
+    fail(
+      label,
+      `leaf inventory mismatch${undeclared.length ? `; undeclared: ${undeclared.join(',')}` : ''}` +
+        `${missing.length ? `; missing: ${missing.join(',')}` : ''}`,
+    );
+  }
+  for (const legalFile of legalFiles) {
+    const snapshot = byPath.get(legalFile);
+    if (snapshot.bytes === 0 || (snapshot.mode & 0o111) !== 0) {
+      fail(label, `legal file ${legalFile} must be non-empty and non-executable`);
+    }
+  }
+  return {
+    bytes: files
+      .filter(({ relative }) => relative.startsWith('files/share/postgresql/'))
+      .reduce((sum, file) => sum + file.bytes, 0),
+    createsExtension: contract.createsExtension,
+    files: files
+      .filter(({ relative }) => relative.startsWith('files/share/postgresql/'))
+      .map((file) => ({
+        ...file,
+        relative: file.relative.slice('files/share/postgresql/'.length),
+      })),
+  };
+}
diff --git a/src/sdks/swift/tools/extension-resource-inventory.test.mjs b/src/sdks/swift/tools/extension-resource-inventory.test.mjs
deleted file mode 100644
index 92cedd215..000000000
--- a/src/sdks/swift/tools/extension-resource-inventory.test.mjs
+++ /dev/null
@@ -1,534 +0,0 @@
-#!/usr/bin/env node
-
-import assert from "node:assert/strict";
-import fs from "node:fs/promises";
-import path from "node:path";
-
-import {
-  createPortablePathCollisionTracker,
-  loadSwiftExtensionInventoryCatalog,
-  readSafeFileSnapshot,
-  validateSwiftExtensionResourceArtifact,
-} from "./extension-resource-inventory.mjs";
-import {
-  publishCreateOnly,
-  safeGeneratedOutput,
-} from "./render-extension-products.mjs";
-
-const sdk = path.resolve(import.meta.dirname, "..");
-const root = path.resolve(process.argv[2] ?? path.join(sdk, ".build", "inventory-test"));
-const fixtureFile = path.join(sdk, "Tests", "Fixtures", "swiftpm-extension-selection.json");
-
-async function main() {
-  await fs.rm(root, { recursive: true, force: true });
-  await fs.mkdir(root, { recursive: true });
-
-  const workspaceRoot = path.join(root, "workspace");
-  const cacheRoot = path.join(root, "carrier-cache");
-  await fs.mkdir(workspaceRoot);
-  await fs.mkdir(cacheRoot);
-  const allowedWorkspaceOutput = path.join(workspaceRoot, "generated-package");
-  assert.equal(
-    await safeGeneratedOutput(allowedWorkspaceOutput, [{
-      label: "working directory",
-      mode: "containment",
-      path: workspaceRoot,
-    }]),
-    allowedWorkspaceOutput,
-    "working-directory protection must allow a generated descendant",
-  );
-  await assert.rejects(
-    () => safeGeneratedOutput(path.join(cacheRoot, "generated-package"), [{
-      label: "carrier cache",
-      mode: "disjoint",
-      path: cacheRoot,
-    }]),
-    /overlaps protected carrier cache/u,
-  );
-  await assert.rejects(
-    () => safeGeneratedOutput(root, [{
-      label: "carrier cache",
-      mode: "disjoint",
-      path: cacheRoot,
-    }]),
-    /overlaps protected carrier cache/u,
-  );
-
-  const publicationStaging = path.join(root, ".publication-output.tmp-fixture");
-  const publicationOutput = path.join(root, "publication-output");
-  const completionMarker = ".oliphaunt-swiftpm-extension-products";
-  await fs.mkdir(path.join(publicationStaging, "Sources"), { recursive: true });
-  await Promise.all([
-    fs.writeFile(path.join(publicationStaging, completionMarker), "completion marker\n"),
-    fs.writeFile(path.join(publicationStaging, "Package.swift"), "package fixture\n"),
-    fs.writeFile(path.join(publicationStaging, "extension-products.json"), "{}\n"),
-  ]);
-  const publicationEntries = [
-    completionMarker,
-    "Package.swift",
-    "Sources",
-    "extension-products.json",
-  ];
-  await assert.rejects(
-    () => publishCreateOnly(
-      publicationStaging,
-      publicationOutput,
-      publicationEntries,
-      async () => {
-        const conflictingSources = path.join(publicationOutput, "Sources");
-        await fs.mkdir(conflictingSources);
-        await fs.writeFile(path.join(conflictingSources, "do-not-delete.txt"), "same-user race\n");
-      },
-    ),
-    /(?:directory not empty|file already exists|EEXIST|ENOTEMPTY)/iu,
-  );
-  assert.equal(
-    await fs.lstat(path.join(publicationOutput, completionMarker)).catch(() => null),
-    null,
-    "a failed publication must not expose its completion marker",
-  );
-  assert.equal(
-    await fs.readFile(path.join(publicationOutput, "Sources", "do-not-delete.txt"), "utf8"),
-    "same-user race\n",
-    "a conflicting nonempty publication entry must not be deleted",
-  );
-  assert.ok(
-    (await fs.lstat(path.join(publicationStaging, completionMarker))).isFile(),
-    "a failed publication must retain its completion marker in private staging",
-  );
-
-  const document = JSON.parse(await fs.readFile(fixtureFile, "utf8"));
-  const catalog = await loadSwiftExtensionInventoryCatalog();
-  const extensions = new Map();
-  for (const row of document.extensions) {
-    const resourceRoot = path.join(root, row.sqlName);
-    await fs.cp(
-      path.resolve(path.dirname(fixtureFile), row.resourceRoot),
-      resourceRoot,
-      { recursive: true },
-    );
-    const extension = { ...row, resourceRoot };
-    extensions.set(row.sqlName, extension);
-    await validateSwiftExtensionResourceArtifact({
-      extension,
-      canonical: catalog.get(row.sqlName),
-      nativeRuntime: document.nativeRuntime,
-      label: `legitimate ${row.sqlName} fixture`,
-    });
-  }
-
-  const postgis = extensions.get("postgis");
-  const postgisManifest = path.join(postgis.resourceRoot, "manifest.properties");
-  const postgisManifestText = await fs.readFile(postgisManifest, "utf8");
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: postgis,
-      canonical: catalog.get("postgis"),
-      nativeRuntime: document.nativeRuntime,
-      allowMobileCarrierArchives: true,
-    }),
-    /mobileStaticArchives must exactly cover/u,
-    "carrier-resolved native artifacts must include both iOS static archives",
-  );
-  const mobileTargets = ["ios-device", "ios-simulator"];
-  const mobileStaticArchives = mobileTargets.map(
-    (target) =>
-      `${target}:mobile-static/${target}/extensions/${postgis.nativeModuleStem}/` +
-      `liboliphaunt_extension_${postgis.nativeModuleStem}.a`,
-  );
-  const mobileStaticDependencyArchives = mobileTargets.flatMap((target) =>
-    postgis.nativeDependencies.map(
-      ({ name }) =>
-        `${target}:${name}:mobile-static/${target}/dependencies/${name}/lib${name}.a`,
-    ));
-  const productionPostgisManifest = postgisManifestText
-    .replace(
-      "mobileStaticArchives=\n",
-      `mobileStaticArchives=${mobileStaticArchives.join(",")}\n`,
-    )
-    .replace(
-      "mobileStaticDependencyArchives=\n",
-      `mobileStaticDependencyArchives=${mobileStaticDependencyArchives.join(",")}\n`,
-    );
-  await fs.writeFile(postgisManifest, productionPostgisManifest);
-  for (const row of [...mobileStaticArchives, ...mobileStaticDependencyArchives]) {
-    const relative = row.slice(row.lastIndexOf(":") + 1);
-    const archive = path.join(postgis.resourceRoot, ...relative.split("/"));
-    await fs.mkdir(path.dirname(archive), { recursive: true });
-    await fs.writeFile(archive, "production-shaped static archive\n");
-  }
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: postgis,
-      canonical: catalog.get("postgis"),
-      nativeRuntime: document.nativeRuntime,
-    }),
-    /mobile static archives are only valid for carrier-resolved inputs/u,
-  );
-  const productionResources = await validateSwiftExtensionResourceArtifact({
-    extension: postgis,
-    canonical: catalog.get("postgis"),
-    nativeRuntime: document.nativeRuntime,
-    allowMobileCarrierArchives: true,
-  });
-  assert.ok(
-    productionResources.files.every(({ relative }) => !relative.endsWith(".a")),
-    "mobile static carrier inputs must not enter rendered Swift resources",
-  );
-
-  const wronglyOrderedDependencies = [...mobileStaticDependencyArchives].reverse();
-  await fs.writeFile(
-    postgisManifest,
-    productionPostgisManifest.replace(
-      mobileStaticDependencyArchives.join(","),
-      wronglyOrderedDependencies.join(","),
-    ),
-  );
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: postgis,
-      canonical: catalog.get("postgis"),
-      nativeRuntime: document.nativeRuntime,
-      allowMobileCarrierArchives: true,
-    }),
-    /must exactly cover both iOS targets and every native dependency/u,
-  );
-
-  await fs.writeFile(
-    postgisManifest,
-    productionPostgisManifest.replace(
-      mobileStaticArchives.join(","),
-      mobileStaticArchives[0],
-    ),
-  );
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: postgis,
-      canonical: catalog.get("postgis"),
-      nativeRuntime: document.nativeRuntime,
-      allowMobileCarrierArchives: true,
-    }),
-    /mobileStaticArchives must exactly cover/u,
-  );
-  const simulatorDependency = mobileStaticDependencyArchives.find((row) =>
-    row.startsWith("ios-simulator:"));
-  assert.ok(simulatorDependency, "production fixture must include a simulator dependency archive");
-  await fs.writeFile(
-    postgisManifest,
-    productionPostgisManifest.replace(
-      simulatorDependency,
-      simulatorDependency.replace(/libgeos\.a$/u, "libgeos_skew.a"),
-    ),
-  );
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: postgis,
-      canonical: catalog.get("postgis"),
-      nativeRuntime: document.nativeRuntime,
-      allowMobileCarrierArchives: true,
-    }),
-    /same archive file name across both iOS targets/u,
-  );
-  await fs.writeFile(postgisManifest, productionPostgisManifest);
-  const undeclaredStatic = path.join(
-    postgis.resourceRoot,
-    "mobile-static/ios-device/dependencies/geos/libundeclared.a",
-  );
-  await fs.writeFile(undeclaredStatic, "undeclared static archive\n");
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: postgis,
-      canonical: catalog.get("postgis"),
-      nativeRuntime: document.nativeRuntime,
-      allowMobileCarrierArchives: true,
-    }),
-    /leaf inventory mismatch.*libundeclared\.a/u,
-  );
-  await fs.rm(undeclaredStatic);
-  await fs.writeFile(postgisManifest, postgisManifestText);
-  await fs.rm(path.join(postgis.resourceRoot, "mobile-static"), { recursive: true, force: true });
-
-  const pgtap = extensions.get("pgtap");
-  const pgtapManifest = path.join(pgtap.resourceRoot, "manifest.properties");
-  const pgtapManifestText = await fs.readFile(pgtapManifest, "utf8");
-  for (const [from, to, pattern] of [
-    [
-      "licenseProfile=external-native\n",
-      "licenseProfile=contrib-native\n",
-      /manifest licenseProfile must be/u,
-    ],
-    [
-      "licenseFiles=share/licenses/pgtap/README.md\n",
-      "licenseFiles=outside/licenses/pgtap/README.md\n",
-      /manifest licenseFiles must live under share\/licenses/u,
-    ],
-    [
-      "licenseProfile=external-native\n",
-      "",
-      /exact canonical fields/u,
-    ],
-  ]) {
-    await fs.writeFile(pgtapManifest, pgtapManifestText.replace(from, to));
-    await assert.rejects(
-      () => validateSwiftExtensionResourceArtifact({
-        extension: pgtap,
-        canonical: catalog.get("pgtap"),
-        nativeRuntime: document.nativeRuntime,
-      }),
-      pattern,
-    );
-  }
-  await fs.writeFile(pgtapManifest, pgtapManifestText);
-  const pgtapLicense = path.join(
-    pgtap.resourceRoot,
-    "files/share/licenses/pgtap/README.md",
-  );
-  const pgtapLicenseBytes = await fs.readFile(pgtapLicense);
-  await fs.rm(pgtapLicense);
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: pgtap,
-      canonical: catalog.get("pgtap"),
-      nativeRuntime: document.nativeRuntime,
-    }),
-    /missing: files\/share\/licenses\/pgtap\/README\.md/u,
-  );
-  await fs.writeFile(pgtapLicense, pgtapLicenseBytes);
-  const undeclaredLegalFile = path.join(
-    pgtap.resourceRoot,
-    "files/share/licenses/pgtap/UNDECLARED",
-  );
-  await fs.writeFile(undeclaredLegalFile, "undeclared legal fixture\n");
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: pgtap,
-      canonical: catalog.get("pgtap"),
-      nativeRuntime: document.nativeRuntime,
-    }),
-    /undeclared: files\/share\/licenses\/pgtap\/UNDECLARED/u,
-  );
-  await fs.rm(undeclaredLegalFile);
-  for (const [from, to, pattern] of [
-    [
-      "extensionSqlFileNames=uninstall_pgtap.sql\n",
-      "extensionSqlFileNames=foreign.sql\n",
-      /manifest extensionSqlFileNames must be/u,
-    ],
-    [
-      "extensionSqlFilePrefixes=pgtap-core,pgtap-schema\n",
-      "extensionSqlFilePrefixes=foreign-prefix\n",
-      /manifest extensionSqlFilePrefixes must be/u,
-    ],
-    [
-      "extensionSqlFileNames=uninstall_pgtap.sql\n",
-      "",
-      /exact canonical fields/u,
-    ],
-  ]) {
-    await fs.writeFile(pgtapManifest, pgtapManifestText.replace(from, to));
-    await assert.rejects(
-      () => validateSwiftExtensionResourceArtifact({
-        extension: pgtap,
-        canonical: catalog.get("pgtap"),
-        nativeRuntime: document.nativeRuntime,
-      }),
-      pattern,
-    );
-  }
-  await fs.writeFile(pgtapManifest, pgtapManifestText);
-  const extensionDirectory = path.join(
-    pgtap.resourceRoot,
-    "files/share/postgresql/extension",
-  );
-  const prefixedControl = path.join(extensionDirectory, "pgtap-core-evil.control");
-  await fs.writeFile(prefixedControl, "undeclared\n");
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: pgtap,
-      canonical: catalog.get("pgtap"),
-      nativeRuntime: document.nativeRuntime,
-    }),
-    /undeclared extension SQL\/control file.*pgtap-core-evil\.control/u,
-  );
-  await fs.rm(prefixedControl);
-
-  const foreign = path.join(extensionDirectory, "foreign.control");
-  await fs.writeFile(foreign, "undeclared\n");
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: pgtap,
-      canonical: catalog.get("pgtap"),
-      nativeRuntime: document.nativeRuntime,
-    }),
-    /undeclared extension SQL\/control file.*foreign\.control/u,
-  );
-  await fs.rm(foreign);
-
-  const pgtapInstall = path.join(extensionDirectory, "pgtap--1.3.5.sql");
-  const pgtapInstallBytes = await fs.readFile(pgtapInstall);
-  const pgtapTransition = path.join(extensionDirectory, "pgtap--1.3.4--1.3.5.sql");
-  await fs.rm(pgtapInstall);
-  await fs.writeFile(pgtapTransition, "owned transition is not a base install\n");
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: pgtap,
-      canonical: catalog.get("pgtap"),
-      nativeRuntime: document.nativeRuntime,
-    }),
-    /pgtap\.control and canonical base installation SQL/u,
-  );
-  await fs.rm(pgtapTransition);
-  const pgtapLetterLeading = path.join(extensionDirectory, "pgtap--release.sql");
-  await fs.writeFile(pgtapLetterLeading, "letter-leading version is not a base install\n");
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: pgtap,
-      canonical: catalog.get("pgtap"),
-      nativeRuntime: document.nativeRuntime,
-    }),
-    /pgtap\.control and canonical base installation SQL/u,
-  );
-  await fs.rm(pgtapLetterLeading);
-  await fs.writeFile(pgtapInstall, pgtapInstallBytes);
-
-  const cube = extensions.get("cube");
-  const cubeControl = path.join(
-    cube.resourceRoot,
-    "files/share/postgresql/extension/cube.control",
-  );
-  for (const [label, paths] of [
-    [
-      "case collision",
-      [
-        "files/share/postgresql/extension/cube.control",
-        "files/share/postgresql/extension/Cube.control",
-      ],
-    ],
-    [
-      "NFC collision",
-      [
-        "files/share/postgresql/extension/caf\u00e9.control",
-        "files/share/postgresql/extension/cafe\u0301.control",
-      ],
-    ],
-    [
-      "multi-code-point case collision",
-      [
-        "files/share/postgresql/extension/stra\u00dfe.control",
-        "files/share/postgresql/extension/STRASSE.control",
-      ],
-    ],
-  ]) {
-    const trackPortablePath = createPortablePathCollisionTracker(`synthetic ${label}`);
-    trackPortablePath(paths[0]);
-    assert.throws(
-      () => trackPortablePath(paths[1]),
-      /case\/NFC-colliding paths/u,
-      `${label} policy must be testable without materializing aliases on the host filesystem`,
-    );
-  }
-
-  const cubeControlBytes = await fs.readFile(cubeControl);
-  const collision = path.join(path.dirname(cubeControl), "Cube.control");
-  let collisionCreated = false;
-  try {
-    await fs.writeFile(collision, "collision\n", { flag: "wx" });
-    collisionCreated = true;
-  } catch (error) {
-    if (error?.code !== "EEXIST") throw error;
-    assert.deepEqual(
-      await fs.readFile(cubeControl),
-      cubeControlBytes,
-      "an aliased case-collision probe must not overwrite the canonical cube.control fixture",
-    );
-  }
-  if (collisionCreated) {
-    try {
-      await assert.rejects(
-        () => validateSwiftExtensionResourceArtifact({
-          extension: cube,
-          canonical: catalog.get("cube"),
-          nativeRuntime: document.nativeRuntime,
-        }),
-        /case\/NFC-colliding paths/u,
-      );
-    } finally {
-      await fs.rm(collision);
-    }
-  }
-  assert.deepEqual(
-    await fs.readFile(cubeControl),
-    cubeControlBytes,
-    "the physical collision probe must preserve the canonical cube.control fixture",
-  );
-
-  const validatedCube = await validateSwiftExtensionResourceArtifact({
-    extension: cube,
-    canonical: catalog.get("cube"),
-    nativeRuntime: document.nativeRuntime,
-  });
-  const cubeControlSnapshot = validatedCube.files.find(
-    ({ relative }) => relative === "extension/cube.control",
-  );
-  assert.ok(cubeControlSnapshot, "cube.control must be present in the validated resource snapshot");
-  await fs.writeFile(cubeControl, "changed after validation\n");
-  await assert.rejects(
-    () => readSafeFileSnapshot(cubeControlSnapshot, "mutated cube.control"),
-    /changed after validation/u,
-  );
-  await fs.writeFile(cubeControl, cubeControlBytes);
-
-  const symlinkValidatedCube = await validateSwiftExtensionResourceArtifact({
-    extension: cube,
-    canonical: catalog.get("cube"),
-    nativeRuntime: document.nativeRuntime,
-  });
-  const symlinkCubeControlSnapshot = symlinkValidatedCube.files.find(
-    ({ relative }) => relative === "extension/cube.control",
-  );
-  const outsideResource = path.join(root, "outside-resource.txt");
-  await fs.writeFile(outsideResource, "bytes that must never enter the generated package\n");
-  await fs.rm(cubeControl);
-  await fs.symlink(outsideResource, cubeControl);
-  await assert.rejects(
-    () => readSafeFileSnapshot(symlinkCubeControlSnapshot, "symlink-swapped cube.control"),
-    /must remain a regular file and must not be a symlink/u,
-  );
-  await fs.rm(cubeControl);
-  await fs.writeFile(cubeControl, cubeControlBytes);
-
-  const injectedMobileArchive = path.join(
-    cube.resourceRoot,
-    "mobile-static/ios-device/extensions/cube/liboliphaunt_extension_cube.a",
-  );
-  await fs.mkdir(path.dirname(injectedMobileArchive), { recursive: true });
-  await fs.writeFile(injectedMobileArchive, "undeclared mobile archive\n");
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: cube,
-      canonical: catalog.get("cube"),
-      nativeRuntime: document.nativeRuntime,
-    }),
-    /leaf inventory mismatch; undeclared: mobile-static\/ios-device/u,
-  );
-  await fs.rm(path.join(cube.resourceRoot, "mobile-static"), { recursive: true, force: true });
-
-  const manifest = path.join(cube.resourceRoot, "manifest.properties");
-  const canonicalManifest = await fs.readFile(manifest);
-  await fs.writeFile(manifest, Buffer.concat([Buffer.from([0xef, 0xbb, 0xbf]), canonicalManifest]));
-  await assert.rejects(
-    () => validateSwiftExtensionResourceArtifact({
-      extension: cube,
-      canonical: catalog.get("cube"),
-      nativeRuntime: document.nativeRuntime,
-    }),
-    /canonical NFC UTF-8/u,
-  );
-
-  console.log("extension-resource-inventory.test.mjs: legitimate inventories and adversarial contamination checks passed");
-}
-
-main().catch((error) => {
-  console.error(error.stack ?? String(error));
-  process.exit(1);
-});
diff --git a/src/sdks/swift/tools/extension-resource-inventory.test.mts b/src/sdks/swift/tools/extension-resource-inventory.test.mts
new file mode 100644
index 000000000..77cba817d
--- /dev/null
+++ b/src/sdks/swift/tools/extension-resource-inventory.test.mts
@@ -0,0 +1,530 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+
+import {
+  createPortablePathCollisionTracker,
+  loadSwiftExtensionInventoryCatalog,
+  readSafeFileSnapshot,
+  validateSwiftExtensionResourceArtifact,
+} from './extension-resource-inventory.mts';
+import { publishCreateOnly, safeGeneratedOutput } from './render-extension-products.mts';
+
+const sdk = path.resolve(import.meta.dirname, '..');
+const root = path.resolve(process.argv[2] ?? path.join(sdk, '.build', 'inventory-test'));
+const fixtureFile = path.join(sdk, 'Tests', 'Fixtures', 'swiftpm-extension-selection.json');
+
+async function main() {
+  await fs.rm(root, { recursive: true, force: true });
+  await fs.mkdir(root, { recursive: true });
+
+  const workspaceRoot = path.join(root, 'workspace');
+  const cacheRoot = path.join(root, 'carrier-cache');
+  await fs.mkdir(workspaceRoot);
+  await fs.mkdir(cacheRoot);
+  const allowedWorkspaceOutput = path.join(workspaceRoot, 'generated-package');
+  assert.equal(
+    await safeGeneratedOutput(allowedWorkspaceOutput, [
+      {
+        label: 'working directory',
+        mode: 'containment',
+        path: workspaceRoot,
+      },
+    ]),
+    allowedWorkspaceOutput,
+    'working-directory protection must allow a generated descendant',
+  );
+  await assert.rejects(
+    () =>
+      safeGeneratedOutput(path.join(cacheRoot, 'generated-package'), [
+        {
+          label: 'carrier cache',
+          mode: 'disjoint',
+          path: cacheRoot,
+        },
+      ]),
+    /overlaps protected carrier cache/u,
+  );
+  await assert.rejects(
+    () =>
+      safeGeneratedOutput(root, [
+        {
+          label: 'carrier cache',
+          mode: 'disjoint',
+          path: cacheRoot,
+        },
+      ]),
+    /overlaps protected carrier cache/u,
+  );
+
+  const publicationStaging = path.join(root, '.publication-output.tmp-fixture');
+  const publicationOutput = path.join(root, 'publication-output');
+  const completionMarker = '.oliphaunt-swiftpm-extension-products';
+  await fs.mkdir(path.join(publicationStaging, 'Sources'), { recursive: true });
+  await Promise.all([
+    fs.writeFile(path.join(publicationStaging, completionMarker), 'completion marker\n'),
+    fs.writeFile(path.join(publicationStaging, 'Package.swift'), 'package fixture\n'),
+    fs.writeFile(path.join(publicationStaging, 'extension-products.json'), '{}\n'),
+  ]);
+  const publicationEntries = [
+    completionMarker,
+    'Package.swift',
+    'Sources',
+    'extension-products.json',
+  ];
+  await assert.rejects(
+    () =>
+      publishCreateOnly(publicationStaging, publicationOutput, publicationEntries, async () => {
+        const conflictingSources = path.join(publicationOutput, 'Sources');
+        await fs.mkdir(conflictingSources);
+        await fs.writeFile(path.join(conflictingSources, 'do-not-delete.txt'), 'same-user race\n');
+      }),
+    /(?:directory not empty|file already exists|EEXIST|ENOTEMPTY)/iu,
+  );
+  assert.equal(
+    await fs.lstat(path.join(publicationOutput, completionMarker)).catch(() => null),
+    null,
+    'a failed publication must not expose its completion marker',
+  );
+  assert.equal(
+    await fs.readFile(path.join(publicationOutput, 'Sources', 'do-not-delete.txt'), 'utf8'),
+    'same-user race\n',
+    'a conflicting nonempty publication entry must not be deleted',
+  );
+  assert.ok(
+    (await fs.lstat(path.join(publicationStaging, completionMarker))).isFile(),
+    'a failed publication must retain its completion marker in private staging',
+  );
+
+  const document = JSON.parse(await fs.readFile(fixtureFile, 'utf8'));
+  const catalog = await loadSwiftExtensionInventoryCatalog();
+  const extensions = new Map();
+  for (const row of document.extensions) {
+    const resourceRoot = path.join(root, row.sqlName);
+    await fs.cp(path.resolve(path.dirname(fixtureFile), row.resourceRoot), resourceRoot, {
+      recursive: true,
+    });
+    const extension = { ...row, resourceRoot };
+    extensions.set(row.sqlName, extension);
+    await validateSwiftExtensionResourceArtifact({
+      extension,
+      canonical: catalog.get(row.sqlName),
+      nativeRuntime: document.nativeRuntime,
+      label: `legitimate ${row.sqlName} fixture`,
+    });
+  }
+
+  const postgis = extensions.get('postgis');
+  const postgisManifest = path.join(postgis.resourceRoot, 'manifest.properties');
+  const postgisManifestText = await fs.readFile(postgisManifest, 'utf8');
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: postgis,
+        canonical: catalog.get('postgis'),
+        nativeRuntime: document.nativeRuntime,
+        allowMobileCarrierArchives: true,
+      }),
+    /mobileStaticArchives must exactly cover/u,
+    'carrier-resolved native artifacts must include both iOS static archives',
+  );
+  const mobileTargets = ['ios-device', 'ios-simulator'];
+  const mobileStaticArchives = mobileTargets.map(
+    (target) =>
+      `${target}:mobile-static/${target}/extensions/${postgis.nativeModuleStem}/` +
+      `liboliphaunt_extension_${postgis.nativeModuleStem}.a`,
+  );
+  const mobileStaticDependencyArchives = mobileTargets.flatMap((target) =>
+    postgis.nativeDependencies.map(
+      ({ name }) => `${target}:${name}:mobile-static/${target}/dependencies/${name}/lib${name}.a`,
+    ),
+  );
+  const productionPostgisManifest = postgisManifestText
+    .replace('mobileStaticArchives=\n', `mobileStaticArchives=${mobileStaticArchives.join(',')}\n`)
+    .replace(
+      'mobileStaticDependencyArchives=\n',
+      `mobileStaticDependencyArchives=${mobileStaticDependencyArchives.join(',')}\n`,
+    );
+  await fs.writeFile(postgisManifest, productionPostgisManifest);
+  for (const row of [...mobileStaticArchives, ...mobileStaticDependencyArchives]) {
+    const relative = row.slice(row.lastIndexOf(':') + 1);
+    const archive = path.join(postgis.resourceRoot, ...relative.split('/'));
+    await fs.mkdir(path.dirname(archive), { recursive: true });
+    await fs.writeFile(archive, 'production-shaped static archive\n');
+  }
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: postgis,
+        canonical: catalog.get('postgis'),
+        nativeRuntime: document.nativeRuntime,
+      }),
+    /mobile static archives are only valid for carrier-resolved inputs/u,
+  );
+  const productionResources = await validateSwiftExtensionResourceArtifact({
+    extension: postgis,
+    canonical: catalog.get('postgis'),
+    nativeRuntime: document.nativeRuntime,
+    allowMobileCarrierArchives: true,
+  });
+  assert.ok(
+    productionResources.files.every(({ relative }) => !relative.endsWith('.a')),
+    'mobile static carrier inputs must not enter rendered Swift resources',
+  );
+
+  const wronglyOrderedDependencies = [...mobileStaticDependencyArchives].reverse();
+  await fs.writeFile(
+    postgisManifest,
+    productionPostgisManifest.replace(
+      mobileStaticDependencyArchives.join(','),
+      wronglyOrderedDependencies.join(','),
+    ),
+  );
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: postgis,
+        canonical: catalog.get('postgis'),
+        nativeRuntime: document.nativeRuntime,
+        allowMobileCarrierArchives: true,
+      }),
+    /must exactly cover both iOS targets and every native dependency/u,
+  );
+
+  await fs.writeFile(
+    postgisManifest,
+    productionPostgisManifest.replace(mobileStaticArchives.join(','), mobileStaticArchives[0]),
+  );
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: postgis,
+        canonical: catalog.get('postgis'),
+        nativeRuntime: document.nativeRuntime,
+        allowMobileCarrierArchives: true,
+      }),
+    /mobileStaticArchives must exactly cover/u,
+  );
+  const simulatorDependency = mobileStaticDependencyArchives.find((row) =>
+    row.startsWith('ios-simulator:'),
+  );
+  assert.ok(simulatorDependency, 'production fixture must include a simulator dependency archive');
+  await fs.writeFile(
+    postgisManifest,
+    productionPostgisManifest.replace(
+      simulatorDependency,
+      simulatorDependency.replace(/libgeos\.a$/u, 'libgeos_skew.a'),
+    ),
+  );
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: postgis,
+        canonical: catalog.get('postgis'),
+        nativeRuntime: document.nativeRuntime,
+        allowMobileCarrierArchives: true,
+      }),
+    /same archive file name across both iOS targets/u,
+  );
+  await fs.writeFile(postgisManifest, productionPostgisManifest);
+  const undeclaredStatic = path.join(
+    postgis.resourceRoot,
+    'mobile-static/ios-device/dependencies/geos/libundeclared.a',
+  );
+  await fs.writeFile(undeclaredStatic, 'undeclared static archive\n');
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: postgis,
+        canonical: catalog.get('postgis'),
+        nativeRuntime: document.nativeRuntime,
+        allowMobileCarrierArchives: true,
+      }),
+    /leaf inventory mismatch.*libundeclared\.a/u,
+  );
+  await fs.rm(undeclaredStatic);
+  await fs.writeFile(postgisManifest, postgisManifestText);
+  await fs.rm(path.join(postgis.resourceRoot, 'mobile-static'), { recursive: true, force: true });
+
+  const pgtap = extensions.get('pgtap');
+  const pgtapManifest = path.join(pgtap.resourceRoot, 'manifest.properties');
+  const pgtapManifestText = await fs.readFile(pgtapManifest, 'utf8');
+  for (const [from, to, pattern] of [
+    [
+      'licenseProfile=external-native\n',
+      'licenseProfile=contrib-native\n',
+      /manifest licenseProfile must be/u,
+    ],
+    [
+      'licenseFiles=share/licenses/pgtap/README.md\n',
+      'licenseFiles=outside/licenses/pgtap/README.md\n',
+      /manifest licenseFiles must live under share\/licenses/u,
+    ],
+    ['licenseProfile=external-native\n', '', /exact canonical fields/u],
+  ]) {
+    await fs.writeFile(pgtapManifest, pgtapManifestText.replace(from, to));
+    await assert.rejects(
+      () =>
+        validateSwiftExtensionResourceArtifact({
+          extension: pgtap,
+          canonical: catalog.get('pgtap'),
+          nativeRuntime: document.nativeRuntime,
+        }),
+      pattern,
+    );
+  }
+  await fs.writeFile(pgtapManifest, pgtapManifestText);
+  const pgtapLicense = path.join(pgtap.resourceRoot, 'files/share/licenses/pgtap/README.md');
+  const pgtapLicenseBytes = await fs.readFile(pgtapLicense);
+  await fs.rm(pgtapLicense);
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: pgtap,
+        canonical: catalog.get('pgtap'),
+        nativeRuntime: document.nativeRuntime,
+      }),
+    /missing: files\/share\/licenses\/pgtap\/README\.md/u,
+  );
+  await fs.writeFile(pgtapLicense, pgtapLicenseBytes);
+  const undeclaredLegalFile = path.join(
+    pgtap.resourceRoot,
+    'files/share/licenses/pgtap/UNDECLARED',
+  );
+  await fs.writeFile(undeclaredLegalFile, 'undeclared legal fixture\n');
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: pgtap,
+        canonical: catalog.get('pgtap'),
+        nativeRuntime: document.nativeRuntime,
+      }),
+    /undeclared: files\/share\/licenses\/pgtap\/UNDECLARED/u,
+  );
+  await fs.rm(undeclaredLegalFile);
+  for (const [from, to, pattern] of [
+    [
+      'extensionSqlFileNames=uninstall_pgtap.sql\n',
+      'extensionSqlFileNames=foreign.sql\n',
+      /manifest extensionSqlFileNames must be/u,
+    ],
+    [
+      'extensionSqlFilePrefixes=pgtap-core,pgtap-schema\n',
+      'extensionSqlFilePrefixes=foreign-prefix\n',
+      /manifest extensionSqlFilePrefixes must be/u,
+    ],
+    ['extensionSqlFileNames=uninstall_pgtap.sql\n', '', /exact canonical fields/u],
+  ]) {
+    await fs.writeFile(pgtapManifest, pgtapManifestText.replace(from, to));
+    await assert.rejects(
+      () =>
+        validateSwiftExtensionResourceArtifact({
+          extension: pgtap,
+          canonical: catalog.get('pgtap'),
+          nativeRuntime: document.nativeRuntime,
+        }),
+      pattern,
+    );
+  }
+  await fs.writeFile(pgtapManifest, pgtapManifestText);
+  const extensionDirectory = path.join(pgtap.resourceRoot, 'files/share/postgresql/extension');
+  const prefixedControl = path.join(extensionDirectory, 'pgtap-core-evil.control');
+  await fs.writeFile(prefixedControl, 'undeclared\n');
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: pgtap,
+        canonical: catalog.get('pgtap'),
+        nativeRuntime: document.nativeRuntime,
+      }),
+    /undeclared extension SQL\/control file.*pgtap-core-evil\.control/u,
+  );
+  await fs.rm(prefixedControl);
+
+  const foreign = path.join(extensionDirectory, 'foreign.control');
+  await fs.writeFile(foreign, 'undeclared\n');
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: pgtap,
+        canonical: catalog.get('pgtap'),
+        nativeRuntime: document.nativeRuntime,
+      }),
+    /undeclared extension SQL\/control file.*foreign\.control/u,
+  );
+  await fs.rm(foreign);
+
+  const pgtapInstall = path.join(extensionDirectory, 'pgtap--1.3.5.sql');
+  const pgtapInstallBytes = await fs.readFile(pgtapInstall);
+  const pgtapTransition = path.join(extensionDirectory, 'pgtap--1.3.4--1.3.5.sql');
+  await fs.rm(pgtapInstall);
+  await fs.writeFile(pgtapTransition, 'owned transition is not a base install\n');
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: pgtap,
+        canonical: catalog.get('pgtap'),
+        nativeRuntime: document.nativeRuntime,
+      }),
+    /pgtap\.control and canonical base installation SQL/u,
+  );
+  await fs.rm(pgtapTransition);
+  const pgtapLetterLeading = path.join(extensionDirectory, 'pgtap--release.sql');
+  await fs.writeFile(pgtapLetterLeading, 'letter-leading version is not a base install\n');
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: pgtap,
+        canonical: catalog.get('pgtap'),
+        nativeRuntime: document.nativeRuntime,
+      }),
+    /pgtap\.control and canonical base installation SQL/u,
+  );
+  await fs.rm(pgtapLetterLeading);
+  await fs.writeFile(pgtapInstall, pgtapInstallBytes);
+
+  const cube = extensions.get('cube');
+  const cubeControl = path.join(cube.resourceRoot, 'files/share/postgresql/extension/cube.control');
+  for (const [label, paths] of [
+    [
+      'case collision',
+      [
+        'files/share/postgresql/extension/cube.control',
+        'files/share/postgresql/extension/Cube.control',
+      ],
+    ],
+    [
+      'NFC collision',
+      [
+        'files/share/postgresql/extension/caf\u00e9.control',
+        'files/share/postgresql/extension/cafe\u0301.control',
+      ],
+    ],
+    [
+      'multi-code-point case collision',
+      [
+        'files/share/postgresql/extension/stra\u00dfe.control',
+        'files/share/postgresql/extension/STRASSE.control',
+      ],
+    ],
+  ]) {
+    const trackPortablePath = createPortablePathCollisionTracker(`synthetic ${label}`);
+    trackPortablePath(paths[0]);
+    assert.throws(
+      () => trackPortablePath(paths[1]),
+      /case\/NFC-colliding paths/u,
+      `${label} policy must be testable without materializing aliases on the host filesystem`,
+    );
+  }
+
+  const cubeControlBytes = await fs.readFile(cubeControl);
+  const collision = path.join(path.dirname(cubeControl), 'Cube.control');
+  let collisionCreated = false;
+  try {
+    await fs.writeFile(collision, 'collision\n', { flag: 'wx' });
+    collisionCreated = true;
+  } catch (error) {
+    if (error?.code !== 'EEXIST') throw error;
+    assert.deepEqual(
+      await fs.readFile(cubeControl),
+      cubeControlBytes,
+      'an aliased case-collision probe must not overwrite the canonical cube.control fixture',
+    );
+  }
+  if (collisionCreated) {
+    try {
+      await assert.rejects(
+        () =>
+          validateSwiftExtensionResourceArtifact({
+            extension: cube,
+            canonical: catalog.get('cube'),
+            nativeRuntime: document.nativeRuntime,
+          }),
+        /case\/NFC-colliding paths/u,
+      );
+    } finally {
+      await fs.rm(collision);
+    }
+  }
+  assert.deepEqual(
+    await fs.readFile(cubeControl),
+    cubeControlBytes,
+    'the physical collision probe must preserve the canonical cube.control fixture',
+  );
+
+  const validatedCube = await validateSwiftExtensionResourceArtifact({
+    extension: cube,
+    canonical: catalog.get('cube'),
+    nativeRuntime: document.nativeRuntime,
+  });
+  const cubeControlSnapshot = validatedCube.files.find(
+    ({ relative }) => relative === 'extension/cube.control',
+  );
+  assert.ok(cubeControlSnapshot, 'cube.control must be present in the validated resource snapshot');
+  await fs.writeFile(cubeControl, 'changed after validation\n');
+  await assert.rejects(
+    () => readSafeFileSnapshot(cubeControlSnapshot, 'mutated cube.control'),
+    /changed after validation/u,
+  );
+  await fs.writeFile(cubeControl, cubeControlBytes);
+
+  const symlinkValidatedCube = await validateSwiftExtensionResourceArtifact({
+    extension: cube,
+    canonical: catalog.get('cube'),
+    nativeRuntime: document.nativeRuntime,
+  });
+  const symlinkCubeControlSnapshot = symlinkValidatedCube.files.find(
+    ({ relative }) => relative === 'extension/cube.control',
+  );
+  const outsideResource = path.join(root, 'outside-resource.txt');
+  await fs.writeFile(outsideResource, 'bytes that must never enter the generated package\n');
+  await fs.rm(cubeControl);
+  await fs.symlink(outsideResource, cubeControl);
+  await assert.rejects(
+    () => readSafeFileSnapshot(symlinkCubeControlSnapshot, 'symlink-swapped cube.control'),
+    /must remain a regular file and must not be a symlink/u,
+  );
+  await fs.rm(cubeControl);
+  await fs.writeFile(cubeControl, cubeControlBytes);
+
+  const injectedMobileArchive = path.join(
+    cube.resourceRoot,
+    'mobile-static/ios-device/extensions/cube/liboliphaunt_extension_cube.a',
+  );
+  await fs.mkdir(path.dirname(injectedMobileArchive), { recursive: true });
+  await fs.writeFile(injectedMobileArchive, 'undeclared mobile archive\n');
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: cube,
+        canonical: catalog.get('cube'),
+        nativeRuntime: document.nativeRuntime,
+      }),
+    /leaf inventory mismatch; undeclared: mobile-static\/ios-device/u,
+  );
+  await fs.rm(path.join(cube.resourceRoot, 'mobile-static'), { recursive: true, force: true });
+
+  const manifest = path.join(cube.resourceRoot, 'manifest.properties');
+  const canonicalManifest = await fs.readFile(manifest);
+  await fs.writeFile(manifest, Buffer.concat([Buffer.from([0xef, 0xbb, 0xbf]), canonicalManifest]));
+  await assert.rejects(
+    () =>
+      validateSwiftExtensionResourceArtifact({
+        extension: cube,
+        canonical: catalog.get('cube'),
+        nativeRuntime: document.nativeRuntime,
+      }),
+    /canonical NFC UTF-8/u,
+  );
+
+  console.log(
+    'extension-resource-inventory.test.mts: legitimate inventories and adversarial contamination checks passed',
+  );
+}
+
+main().catch((error) => {
+  console.error(error.stack ?? String(error));
+  process.exit(1);
+});
diff --git a/src/sdks/swift/tools/extract-verified-zip.mjs b/src/sdks/swift/tools/extract-verified-zip.mjs
deleted file mode 100755
index 8c48cd6d8..000000000
--- a/src/sdks/swift/tools/extract-verified-zip.mjs
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env node
-
-import path from "node:path";
-import { extractVerifiedZipArchive } from "./swift-carrier-resolver.mjs";
-
-function fail(message) {
-  throw new Error(`extract-verified-zip.mjs: ${message}`);
-}
-
-function parseArgs(argv) {
-  const result = {};
-  for (let index = 0; index < argv.length; index += 1) {
-    const key = argv[index];
-    if (key === "--help" || key === "-h") {
-      console.log("usage: extract-verified-zip.mjs --archive FILE --destination DIRECTORY");
-      process.exit(0);
-    }
-    const field = new Map([
-      ["--archive", "archive"],
-      ["--destination", "destination"],
-    ]).get(key);
-    if (field === undefined || argv[index + 1] === undefined) {
-      fail(`unknown or incomplete option: ${key}`);
-    }
-    result[field] = argv[index + 1];
-    index += 1;
-  }
-  for (const field of ["archive", "destination"]) {
-    if (typeof result[field] !== "string" || result[field].length === 0) {
-      fail(`--${field} is required`);
-    }
-  }
-  return result;
-}
-
-try {
-  const args = parseArgs(process.argv.slice(2));
-  const tree = await extractVerifiedZipArchive({
-    archive: path.resolve(args.archive),
-    destination: path.resolve(args.destination),
-  });
-  console.log(`verified and extracted ${tree.length} ZIP entries to ${path.resolve(args.destination)}`);
-} catch (error) {
-  console.error(error.stack ?? String(error));
-  process.exit(1);
-}
diff --git a/src/sdks/swift/tools/extract-verified-zip.mts b/src/sdks/swift/tools/extract-verified-zip.mts
new file mode 100755
index 000000000..31237d37f
--- /dev/null
+++ b/src/sdks/swift/tools/extract-verified-zip.mts
@@ -0,0 +1,48 @@
+#!/usr/bin/env bun
+
+import path from 'node:path';
+import { extractVerifiedZipArchive } from './swift-carrier-resolver.mts';
+
+function fail(message) {
+  throw new Error(`extract-verified-zip.mts: ${message}`);
+}
+
+function parseArgs(argv) {
+  const result = {};
+  for (let index = 0; index < argv.length; index += 1) {
+    const key = argv[index];
+    if (key === '--help' || key === '-h') {
+      console.log('usage: extract-verified-zip.mts --archive FILE --destination DIRECTORY');
+      process.exit(0);
+    }
+    const field = new Map([
+      ['--archive', 'archive'],
+      ['--destination', 'destination'],
+    ]).get(key);
+    if (field === undefined || argv[index + 1] === undefined) {
+      fail(`unknown or incomplete option: ${key}`);
+    }
+    result[field] = argv[index + 1];
+    index += 1;
+  }
+  for (const field of ['archive', 'destination']) {
+    if (typeof result[field] !== 'string' || result[field].length === 0) {
+      fail(`--${field} is required`);
+    }
+  }
+  return result;
+}
+
+try {
+  const args = parseArgs(process.argv.slice(2));
+  const tree = await extractVerifiedZipArchive({
+    archive: path.resolve(args.archive),
+    destination: path.resolve(args.destination),
+  });
+  console.log(
+    `verified and extracted ${tree.length} ZIP entries to ${path.resolve(args.destination)}`,
+  );
+} catch (error) {
+  console.error(error.stack ?? String(error));
+  process.exit(1);
+}
diff --git a/src/sdks/swift/tools/ios-carrier-manifest.mts b/src/sdks/swift/tools/ios-carrier-manifest.mts
new file mode 100644
index 000000000..f1b5350b9
--- /dev/null
+++ b/src/sdks/swift/tools/ios-carrier-manifest.mts
@@ -0,0 +1,1242 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import {
+  existsSync,
+  lstatSync,
+  mkdirSync,
+  readFileSync,
+  readdirSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import { pathToFileURL } from 'node:url';
+import path from 'node:path';
+
+import { ROOT, compareText, tagPrefix } from '../../../../tools/release/release-graph.mts';
+import {
+  currentProductVersionSync,
+  extensionProductForSqlName,
+  extensionReleaseProductForSqlName,
+  extensionSqlNames,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import {
+  extensionCarrierLegalContract,
+  extensionUpstreamLicenseRow,
+} from '../../../extensions/tools/extension-upstream-licenses.mts';
+import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts';
+import {
+  releaseNoticeRows,
+  releaseProfilePackageLicense,
+} from '../../../../tools/packaging/release-notices.mts';
+
+export const IOS_CARRIER_SCHEMA = 'oliphaunt-react-native-ios-carrier-v1';
+export const IOS_CARRIER_FILENAME = 'oliphaunt-react-native-ios-carriers.json';
+export const SWIFT_EXTENSION_CARRIER_SCHEMA = 'oliphaunt-swift-extension-carrier-v1';
+export const DEFAULT_IOS_CARRIER = path.join(
+  ROOT,
+  'target/release/ios-carriers',
+  IOS_CARRIER_FILENAME,
+);
+
+const DEFAULT_REPOSITORY = 'f0rr0/oliphaunt';
+const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u;
+const PORTABLE_IDENTIFIER = /^[A-Za-z0-9._-]{1,128}$/u;
+const C_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u;
+const MAX_ARCHIVE_BYTES = 2 * 1024 * 1024 * 1024;
+const MAX_ARCHIVE_ENTRIES = 32_768;
+const IOS_CARRIER_ARCHIVE_LIMITS = Object.freeze({
+  maxArchiveBytes: MAX_ARCHIVE_BYTES,
+  maxEntries: MAX_ARCHIVE_ENTRIES,
+  maxEntryBytes: MAX_ARCHIVE_BYTES,
+  maxExpandedBytes: MAX_ARCHIVE_BYTES,
+});
+const BASE_LEGAL_PROFILES = Object.freeze([
+  Object.freeze({
+    assetRole: 'base-xcframework',
+    memberPrefix: 'liboliphaunt.xcframework',
+    profile: 'native-runtime',
+  }),
+  Object.freeze({
+    assetRole: 'runtime-resources',
+    memberPrefix: '',
+    profile: 'native-runtime-resources',
+  }),
+]);
+
+function error(message) {
+  return new Error(`ios-carrier-manifest: ${message}`);
+}
+
+function stableVersion(value, label) {
+  if (typeof value !== 'string' || !STABLE_SEMVER.test(value)) {
+    throw error(`${label} must be a stable SemVer X.Y.Z version`);
+  }
+  return value;
+}
+
+function exactObjectKeys(value, expected, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    throw error(`${label} must be an object`);
+  }
+  const actual = Object.keys(value).sort(compareText);
+  const canonical = [...expected].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(canonical)) {
+    throw error(`${label} fields must be exactly ${canonical.join(',')}; got ${actual.join(',')}`);
+  }
+  return value;
+}
+
+function portableIdentifier(value, label) {
+  if (typeof value !== 'string' || !PORTABLE_IDENTIFIER.test(value)) {
+    throw error(`${label} must be a portable identifier`);
+  }
+  return value;
+}
+
+function canonicalStringList(value, label, validate = portableIdentifier) {
+  if (!Array.isArray(value)) throw error(`${label} must be an array`);
+  const rows = value.map((item, index) => validate(item, `${label}[${index}]`));
+  if (new Set(rows).size !== rows.length) throw error(`${label} must not contain duplicates`);
+  const canonical = [...rows].sort(compareText);
+  if (JSON.stringify(value) !== JSON.stringify(canonical)) {
+    throw error(`${label} must be sorted in ordinal order`);
+  }
+  return canonical;
+}
+
+function compatibilityMetadata(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    throw error(`${label} must be an object`);
+  }
+  const expectedKeys = [
+    'extensionRuntimeContract',
+    'nativeRuntimeProduct',
+    'nativeRuntimeVersion',
+    'postgresMajor',
+    'wasixRuntimeProduct',
+    'wasixRuntimeVersion',
+  ];
+  const actualKeys = Object.keys(value).sort(compareText);
+  if (JSON.stringify(actualKeys) !== JSON.stringify([...expectedKeys].sort(compareText))) {
+    throw error(`${label} must contain the exact stable compatibility fields`);
+  }
+  if (value.postgresMajor !== '18') throw error(`${label}.postgresMajor must be 18`);
+  if (value.nativeRuntimeProduct !== 'liboliphaunt-native') {
+    throw error(`${label}.nativeRuntimeProduct must be liboliphaunt-native`);
+  }
+  if (value.wasixRuntimeProduct !== 'liboliphaunt-wasix') {
+    throw error(`${label}.wasixRuntimeProduct must be liboliphaunt-wasix`);
+  }
+  if (
+    typeof value.extensionRuntimeContract !== 'string' ||
+    value.extensionRuntimeContract.length === 0
+  ) {
+    throw error(`${label}.extensionRuntimeContract must be a non-empty path`);
+  }
+  return {
+    extensionRuntimeContract: value.extensionRuntimeContract,
+    nativeRuntimeProduct: value.nativeRuntimeProduct,
+    nativeRuntimeVersion: stableVersion(
+      value.nativeRuntimeVersion,
+      `${label}.nativeRuntimeVersion`,
+    ),
+    postgresMajor: value.postgresMajor,
+    wasixRuntimeProduct: value.wasixRuntimeProduct,
+    wasixRuntimeVersion: stableVersion(value.wasixRuntimeVersion, `${label}.wasixRuntimeVersion`),
+  };
+}
+
+function validateRepository(repository) {
+  if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository)) {
+    throw error(`invalid GitHub repository ${repository}`);
+  }
+  return repository;
+}
+
+function sha256(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function requireFile(file, label) {
+  let fileStat;
+  try {
+    fileStat = lstatSync(file);
+  } catch {
+    throw error(`missing ${label}: ${path.relative(ROOT, file)}`);
+  }
+  if (!fileStat.isFile()) {
+    throw error(`${label} must be a regular file: ${path.relative(ROOT, file)}`);
+  }
+  return file;
+}
+
+function stable(value) {
+  if (Array.isArray(value)) return value.map(stable);
+  if (value !== null && typeof value === 'object') {
+    return Object.fromEntries(
+      Object.keys(value)
+        .sort(compareText)
+        .map((key) => [key, stable(value[key])]),
+    );
+  }
+  return value;
+}
+
+function archiveStat(file) {
+  const stat = lstatSync(file, { bigint: true });
+  if (!stat.isFile() || stat.size <= 0n || stat.size > BigInt(MAX_ARCHIVE_BYTES)) {
+    throw error(
+      `${path.basename(file)} must be a non-empty regular archive no larger than ${MAX_ARCHIVE_BYTES} bytes`,
+    );
+  }
+  return stat;
+}
+
+function archiveCacheKey(file, format, stat, includeDigests) {
+  return [
+    format,
+    includeDigests ? 'digests' : 'metadata',
+    path.resolve(file),
+    stat.dev,
+    stat.ino,
+    stat.size,
+    stat.mtimeNs,
+    stat.ctimeNs,
+  ].join('\0');
+}
+
+function archiveIndex(file, format, cache = new Map(), { includeDigests = false } = {}) {
+  if (format !== 'zip' && format !== 'tar.gz')
+    throw error(`unsupported archive listing format ${format}`);
+  const stat = archiveStat(file);
+  const key = archiveCacheKey(file, format, stat, includeDigests);
+  const cached = cache.get(key);
+  if (cached !== undefined) return cached;
+  const portableEntries = readPortableArchiveEntries(file, {
+    ...IOS_CARRIER_ARCHIVE_LIMITS,
+    format,
+  });
+  // The portable reader's lazy ZIP payload closures retain the whole archive,
+  // and tar payload closures retain the inflated tar buffer. Cache only inert
+  // metadata (plus one digest per aggregate member) so a complete manifest
+  // build never keeps dozens of carrier archives resident.
+  const entries = [...portableEntries.values()].map((entry) =>
+    Object.freeze({
+      ...(includeDigests && entry.type === 'file'
+        ? { sha256: createHash('sha256').update(entry.data()).digest('hex') }
+        : {}),
+      name: entry.name,
+      mode: entry.mode,
+      size: entry.size,
+      type: entry.type,
+    }),
+  );
+  portableEntries.clear();
+  const index = Object.freeze({
+    byName: new Map(entries.map((entry) => [entry.name, entry])),
+    entries: Object.freeze(entries),
+  });
+  cache.set(key, index);
+  return index;
+}
+
+function listArchive(file, format, cache) {
+  return archiveIndex(file, format, cache).entries.map(({ name }) => name);
+}
+
+function verifyMember(file, format, member, cache) {
+  const members = listArchive(file, format, cache);
+  if (member === '.') return;
+  if (!members.some((value) => value === member || value.startsWith(`${member}/`))) {
+    throw error(`${path.basename(file)} is missing declared archive member ${member}`);
+  }
+}
+
+function verifyFileMember(file, format, member, expected, cache) {
+  if (format !== 'tar.gz') {
+    throw error(`${path.basename(file)} aggregate carrier must be a tar.gz archive`);
+  }
+  if (
+    !Number.isSafeInteger(expected.bytes) ||
+    expected.bytes <= 0 ||
+    expected.bytes > MAX_ARCHIVE_BYTES ||
+    typeof expected.sha256 !== 'string' ||
+    !/^[0-9a-f]{64}$/u.test(expected.sha256)
+  ) {
+    throw error(`${path.basename(file)} declares invalid nested payload metadata for ${member}`);
+  }
+  const index = archiveIndex(file, format, cache, { includeDigests: true });
+  const entry = index.byName.get(member);
+  if (entry?.type !== 'file') {
+    throw error(`${path.basename(file)} is missing or cannot read declared archive file ${member}`);
+  }
+  if (entry.size !== expected.bytes || entry.sha256 !== expected.sha256) {
+    throw error(
+      `${path.basename(file)} nested payload ${member} does not match its declared bytes/SHA-256`,
+    );
+  }
+}
+
+function portableAssetName(value, label = 'release asset name') {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    path.posix.basename(value) !== value ||
+    /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) ||
+    /[ .]$/u.test(value) ||
+    /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value)
+  ) {
+    throw error(`${label} is not a portable release asset filename: ${JSON.stringify(value)}`);
+  }
+  return value;
+}
+
+function archiveFormat(name, label = 'release asset') {
+  portableAssetName(name, `${label} name`);
+  if (name.endsWith('.zip')) return 'zip';
+  if (name.endsWith('.tar.gz')) return 'tar.gz';
+  throw error(`${label} ${name} must be a .zip or .tar.gz archive`);
+}
+
+function safeArchivePath(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    value.startsWith('/') ||
+    /^[A-Za-z]:/u.test(value) ||
+    /[\u0000-\u001f\u007f]/u.test(value)
+  ) {
+    throw error(`${label} must be a safe POSIX archive path`);
+  }
+  const parts = value.replace(/^\.\//u, '').split('/');
+  if (parts.some((part) => part.length === 0 || part === '.' || part === '..')) {
+    throw error(`${label} must be a safe POSIX archive path`);
+  }
+  return parts.join('/');
+}
+
+function legalKind(member, declared = undefined) {
+  if (declared !== undefined) return declared;
+  return path.posix.basename(member).includes('NOTICE') ? 'notice' : 'license';
+}
+
+function prefixedMember(prefix, member) {
+  return prefix ? `${prefix}/${member}` : member;
+}
+
+function canonicalLegalFileSpecs(profile, memberPrefix = '') {
+  return releaseNoticeRows({ profile }).map((row) => ({
+    bytes: statSync(row.source).size,
+    kind: legalKind(row.member),
+    member: prefixedMember(memberPrefix, row.member),
+    sha256: sha256(row.source),
+  }));
+}
+
+function legalGroupShape({ assetRole, files, profile, spdx }) {
+  const canonical = [...files].sort((left, right) => compareText(left.member, right.member));
+  if (new Set(canonical.map(({ member }) => member)).size !== canonical.length) {
+    throw error(`${assetRole} legal metadata repeats an archive member`);
+  }
+  return {
+    assetRole,
+    files: canonical,
+    profile,
+    spdx,
+  };
+}
+
+/**
+ * Canonical legal locators for the three native Apple base assets. The
+ * locators remain archive-relative; a consumer chooses the applicable groups
+ * (the ICU sidecar is optional) and never needs this repository to stage them.
+ */
+export function iosBaseLegalMetadata() {
+  return BASE_LEGAL_PROFILES.map(({ assetRole, memberPrefix, profile }) =>
+    legalGroupShape({
+      assetRole,
+      files: canonicalLegalFileSpecs(profile, memberPrefix),
+      profile,
+      spdx: releaseProfilePackageLicense(profile).spdx,
+    }),
+  );
+}
+
+function assertLegalGroupArchiveBytes(file, format, group, archiveCache, label) {
+  const index = archiveIndex(file, format, archiveCache, { includeDigests: true });
+  return legalGroupShape({
+    ...group,
+    files: group.files.map((expected) => {
+      const member = safeArchivePath(expected.member, `${label} legal member`);
+      const entry = index.byName.get(member);
+      if (entry?.type !== 'file') {
+        throw error(`${label} is missing regular legal file ${member}`);
+      }
+      if ((entry.mode & 0o777) !== 0o644) {
+        throw error(`${label} legal file ${member} must have mode 0644`);
+      }
+      if (entry.sha256 !== expected.sha256) {
+        throw error(`${label} legal file ${member} does not match its canonical SHA-256`);
+      }
+      if (expected.bytes !== undefined && entry.size !== expected.bytes) {
+        throw error(`${label} legal file ${member} does not match its canonical byte count`);
+      }
+      if (entry.size <= 0) throw error(`${label} legal file ${member} must be non-empty`);
+      return {
+        bytes: entry.size,
+        kind: expected.kind,
+        member,
+        sha256: entry.sha256,
+      };
+    }),
+  });
+}
+
+function extensionLegalGroup({ archiveCache, file, format, product, sqlName }) {
+  const contract = extensionCarrierLegalContract(product, [sqlName], {
+    family: 'native',
+    target: 'ios-xcframework',
+  });
+  const noticeFiles = canonicalLegalFileSpecs(contract.profile);
+  const upstreamFiles = contract.upstreamMembers.flatMap((member) =>
+    extensionUpstreamLicenseRow(member).files.map((row) => ({
+      kind: legalKind(row.destination, row.role),
+      member: `files/${row.destination}`,
+      sha256: row.sha256,
+    })),
+  );
+  const contractedDestinations = upstreamFiles
+    .map(({ member }) => member.replace(/^files\//u, ''))
+    .sort(compareText);
+  if (JSON.stringify(contractedDestinations) !== JSON.stringify([...contract.licenseFiles])) {
+    throw error(
+      `${product}/${sqlName} iOS legal files disagree with the canonical upstream contract`,
+    );
+  }
+  return assertLegalGroupArchiveBytes(
+    file,
+    format,
+    legalGroupShape({
+      assetRole: 'runtime-resources',
+      files: [...noticeFiles, ...upstreamFiles],
+      profile: contract.profile,
+      spdx: contract.packageSpdx,
+    }),
+    archiveCache,
+    `${product}/${sqlName} iOS runtime carrier`,
+  );
+}
+
+function validateFrozenBaseLegalMetadata(value, label) {
+  if (!Array.isArray(value)) throw error(`${label} must be an array`);
+  const expected = iosBaseLegalMetadata();
+  if (JSON.stringify(stable(value)) !== JSON.stringify(stable(expected))) {
+    throw error(`${label} does not match the canonical native Apple legal locators`);
+  }
+  return expected;
+}
+
+function assetUrl({ file, name, tag, repository, localUrls }) {
+  if (localUrls) return pathToFileURL(file).href;
+  return `https://github.com/${repository}/releases/download/${encodeURIComponent(tag)}/${encodeURIComponent(name)}`;
+}
+
+function asset({ file, role, member, tag, repository, localUrls, verifyMembers, archiveCache }) {
+  requireFile(file, `${role} asset`);
+  const name = portableAssetName(path.basename(file), `${role} asset name`);
+  const format = archiveFormat(name, `${role} asset`);
+  if (verifyMembers) verifyMember(file, format, member, archiveCache);
+  return {
+    role,
+    name,
+    url: assetUrl({ file, name, tag, repository, localUrls }),
+    sha256: sha256(file),
+    bytes: statSync(file).size,
+    format,
+    member,
+  };
+}
+
+function carrierEnvelope({ file, tag, repository, localUrls }) {
+  requireFile(file, 'carrier archive');
+  const name = portableAssetName(path.basename(file), 'carrier archive name');
+  return {
+    name,
+    url: assetUrl({ file, name, tag, repository, localUrls }),
+    sha256: sha256(file),
+    bytes: statSync(file).size,
+    format: archiveFormat(name, 'carrier archive'),
+  };
+}
+
+function baseCarrier({ baseAssetDir, repository, localUrls, verifyMembers, archiveCache }) {
+  const product = 'liboliphaunt-native';
+  const version = currentProductVersionSync(product, 'ios-carrier-manifest');
+  const tag = `${tagPrefix(product, 'ios-carrier-manifest')}${version}`;
+  const rows = [
+    {
+      role: 'base-xcframework',
+      name: `liboliphaunt-${version}-apple-spm-xcframework.zip`,
+      member: 'liboliphaunt.xcframework',
+    },
+    {
+      role: 'runtime-resources',
+      name: `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`,
+      member: 'oliphaunt',
+    },
+  ];
+  const assets = rows.map((row) =>
+    asset({
+      ...row,
+      file: path.join(baseAssetDir, row.name),
+      tag,
+      repository,
+      localUrls,
+      verifyMembers,
+      archiveCache,
+    }),
+  );
+  const legal = iosBaseLegalMetadata().map((group) => {
+    const selected = rows.find(({ role }) => role === group.assetRole);
+    if (selected === undefined)
+      throw error(`base legal group references unknown asset role ${group.assetRole}`);
+    return assertLegalGroupArchiveBytes(
+      path.join(baseAssetDir, selected.name),
+      archiveFormat(selected.name, `${selected.role} asset`),
+      group,
+      archiveCache,
+      `${product} ${selected.role}`,
+    );
+  });
+  return {
+    base: { product, version, tag, assets },
+    legal,
+  };
+}
+
+function frozenBaseCarrier(file) {
+  let manifest;
+  try {
+    manifest = JSON.parse(
+      readFileSync(requireFile(path.resolve(file), 'base carrier manifest'), 'utf8'),
+    );
+  } catch (cause) {
+    throw error(`cannot read base carrier manifest ${file}: ${cause.message}`);
+  }
+  const base = manifest?.schema === IOS_CARRIER_SCHEMA ? manifest.base : manifest;
+  const legal = manifest?.schema === IOS_CARRIER_SCHEMA ? manifest.legal?.base : manifest?.legal;
+  const product = 'liboliphaunt-native';
+  const version = currentProductVersionSync(product, 'ios-carrier-manifest');
+  const tag = `${tagPrefix(product, 'ios-carrier-manifest')}${version}`;
+  if (
+    base?.product !== product ||
+    base.version !== version ||
+    base.tag !== tag ||
+    !Array.isArray(base.assets)
+  ) {
+    throw error(`${file} does not freeze the current ${product} base carrier`);
+  }
+  const expectedRoles = ['base-xcframework', 'runtime-resources'];
+  if (JSON.stringify(base.assets.map(({ role }) => role)) !== JSON.stringify(expectedRoles)) {
+    throw error(`${file} base carrier roles must be exactly ${expectedRoles.join(', ')}`);
+  }
+  for (const [index, row] of base.assets.entries()) {
+    if (
+      typeof row.name !== 'string' ||
+      typeof row.url !== 'string' ||
+      !row.url.startsWith('https://') ||
+      typeof row.sha256 !== 'string' ||
+      !/^[0-9a-f]{64}$/u.test(row.sha256) ||
+      !Number.isSafeInteger(row.bytes) ||
+      row.bytes <= 0 ||
+      !['zip', 'tar.gz'].includes(row.format) ||
+      typeof row.member !== 'string' ||
+      row.member.length === 0
+    ) {
+      throw error(`${file} contains invalid base asset ${index}`);
+    }
+    portableAssetName(row.name, `${file} base asset ${index} name`);
+    if (archiveFormat(row.name, `${file} base asset ${index}`) !== row.format) {
+      throw error(`${file} base asset ${index} name does not match its archive format`);
+    }
+  }
+  return {
+    base: stable(base),
+    legal: validateFrozenBaseLegalMetadata(legal, `${file} base legal metadata`),
+  };
+}
+
+function validateRegistration(
+  value,
+  manifestPath,
+  { nativeModuleStem: expectedNativeModuleStem, sqlName: expectedSqlName },
+) {
+  exactObjectKeys(
+    value,
+    ['initSymbol', 'magicSymbol', 'nativeModuleStem', 'schema', 'sqlName', 'symbols'],
+    `${manifestPath} iOS registration`,
+  );
+  const { schema, sqlName, nativeModuleStem, magicSymbol, initSymbol, symbols } = value;
+  if (
+    schema !== 'oliphaunt-ios-extension-registration-v1' ||
+    sqlName !== expectedSqlName ||
+    nativeModuleStem !== expectedNativeModuleStem ||
+    typeof magicSymbol !== 'string' ||
+    !C_IDENTIFIER.test(magicSymbol) ||
+    !(initSymbol === null || (typeof initSymbol === 'string' && C_IDENTIFIER.test(initSymbol))) ||
+    !Array.isArray(symbols)
+  ) {
+    throw error(`${manifestPath} contains invalid iOS registration metadata`);
+  }
+  const canonicalSymbols = symbols
+    .map((row, index) => {
+      exactObjectKeys(row, ['address', 'name'], `${manifestPath} iOS registration symbol ${index}`);
+      if (!C_IDENTIFIER.test(row.name) || !C_IDENTIFIER.test(row.address)) {
+        throw error(`${manifestPath} iOS registration symbol ${index} must use C identifiers`);
+      }
+      return { name: row.name, address: row.address };
+    })
+    .sort((left, right) =>
+      compareText(`${left.name}\0${left.address}`, `${right.name}\0${right.address}`),
+    );
+  if (new Set(canonicalSymbols.map(({ name }) => name)).size !== canonicalSymbols.length) {
+    throw error(`${manifestPath} iOS registration repeats a SQL symbol name`);
+  }
+  return {
+    magicSymbol,
+    initSymbol,
+    symbols: canonicalSymbols,
+  };
+}
+
+function extensionCarrier(
+  manifest,
+  manifestPath,
+  {
+    aggregateCarriers,
+    artifactProduct,
+    repository,
+    localUrls,
+    release,
+    verifyMembers,
+    archiveCache,
+    includeLegal,
+  },
+) {
+  if (
+    typeof manifest.product !== 'string' ||
+    typeof manifest.version !== 'string' ||
+    typeof manifest.sqlName !== 'string' ||
+    !Array.isArray(manifest.assets)
+  ) {
+    throw error(`${manifestPath} is not an exact-extension CI artifact manifest`);
+  }
+  if (manifest.product !== artifactProduct || manifest.version !== release.version) {
+    throw error(
+      `${manifestPath} extension member identity does not match its artifact product/release version`,
+    );
+  }
+  const sqlName = portableIdentifier(manifest.sqlName, `${manifestPath}.sqlName`);
+  if (typeof manifest.createsExtension !== 'boolean') {
+    throw error(`${manifestPath} ${sqlName}.createsExtension must be boolean`);
+  }
+  const dependencies = canonicalStringList(
+    manifest.dependencies,
+    `${manifestPath} ${sqlName}.dependencies`,
+  );
+  if (dependencies.includes(sqlName)) {
+    throw error(`${manifestPath} ${sqlName}.dependencies must not include itself`);
+  }
+  const dataFiles = canonicalStringList(
+    manifest.dataFiles,
+    `${manifestPath} ${sqlName}.dataFiles`,
+    (value, label) => {
+      const relative = safeArchivePath(value, label);
+      if (relative === '.') throw error(`${label} must name a file`);
+      return relative;
+    },
+  );
+  const extensionSqlFileNames = canonicalStringList(
+    manifest.extensionSqlFileNames,
+    `${manifestPath} ${sqlName}.extensionSqlFileNames`,
+    (value, label) => {
+      const name = portableIdentifier(value, label);
+      if (!name.endsWith('.sql')) throw error(`${label} must name a SQL file`);
+      return name;
+    },
+  );
+  const extensionSqlFilePrefixes = canonicalStringList(
+    manifest.extensionSqlFilePrefixes,
+    `${manifestPath} ${sqlName}.extensionSqlFilePrefixes`,
+    (value, label) => {
+      if (typeof value !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/u.test(value)) {
+        throw error(`${label} must be a dot-free portable SQL basename prefix`);
+      }
+      return value;
+    },
+  );
+  const sharedPreloadLibraries = canonicalStringList(
+    manifest.sharedPreloadLibraries,
+    `${manifestPath} ${sqlName}.sharedPreloadLibraries`,
+  );
+  const tag = release.tag;
+  const iOS = manifest.assets.filter(
+    (row) => row?.family === 'native' && row.target === 'ios-xcframework',
+  );
+  const allowedKinds = new Set(['runtime', 'ios-xcframework', 'ios-dependency-xcframework']);
+  if (iOS.some((row) => !allowedKinds.has(row.kind))) {
+    throw error(`${manifestPath} contains an unsupported iOS asset role`);
+  }
+  const carriers = new Map();
+  const rows = iOS.map((row) => {
+    const file = path.resolve(ROOT, row.path);
+    requireFile(file, `${manifest.product} ${row.kind}`);
+    const logicalName = portableAssetName(row.name, `${manifest.product} ${row.kind} name`);
+    const logicalFormat = archiveFormat(logicalName, `${manifest.product} ${row.kind}`);
+    if (
+      statSync(file).size !== row.bytes ||
+      sha256(file) !== row.sha256 ||
+      path.basename(file) !== logicalName
+    ) {
+      throw error(`${manifestPath} metadata does not match ${row.path}`);
+    }
+    let envelope;
+    let memberPath;
+    if (row.carrierAsset === undefined) {
+      if (aggregateCarriers.size > 0) {
+        throw error(
+          `${manifestPath} bundle member ${manifest.sqlName} lacks an aggregate carrier locator`,
+        );
+      }
+      envelope = carrierEnvelope({ file, tag, repository, localUrls });
+      memberPath = '.';
+    } else {
+      const carrierName = portableAssetName(row.carrierAsset, `${manifest.product} carrierAsset`);
+      const aggregate = aggregateCarriers.get(carrierName);
+      if (aggregate === undefined) {
+        throw error(`${manifestPath} references undeclared aggregate carrier ${carrierName}`);
+      }
+      if (aggregate.family !== row.family || aggregate.target !== row.target) {
+        throw error(
+          `${manifestPath} ${manifest.sqlName}/${row.kind} references a carrier for the wrong family/target`,
+        );
+      }
+      const carrierRoot = safeArchivePath(row.carrierRoot, `${manifestPath} carrierRoot`);
+      const nestedPath = safeArchivePath(row.memberPath, `${manifestPath} memberPath`);
+      memberPath = `${carrierRoot}/${nestedPath}`;
+      envelope = aggregate.envelope;
+      if (verifyMembers)
+        verifyFileMember(aggregate.file, envelope.format, memberPath, row, archiveCache);
+    }
+    const prior = carriers.get(envelope.name);
+    if (prior !== undefined && JSON.stringify(prior) !== JSON.stringify(envelope)) {
+      throw error(`${manifestPath} has conflicting carrier envelopes named ${envelope.name}`);
+    }
+    carriers.set(envelope.name, envelope);
+    if (row.kind === 'runtime') {
+      return { row, logicalFormat, envelope, role: 'runtime-resources', member: '.', memberPath };
+    }
+    if (row.kind === 'ios-xcframework') {
+      return {
+        row,
+        logicalFormat,
+        envelope,
+        role: 'extension-xcframework',
+        member: `liboliphaunt_extension_${row.identity}.xcframework`,
+        memberPath,
+      };
+    }
+    return {
+      row,
+      logicalFormat,
+      envelope,
+      role: 'dependency-xcframework',
+      member: `liboliphaunt_dependency_${row.identity}.xcframework`,
+      memberPath,
+    };
+  });
+  const assets = rows
+    .map(({ row, logicalFormat, envelope, role, member, memberPath }) => {
+      if (verifyMembers)
+        verifyMember(path.resolve(ROOT, row.path), logicalFormat, member, archiveCache);
+      return {
+        role,
+        carrier: envelope.name,
+        path: memberPath,
+        sha256: row.sha256,
+        bytes: row.bytes,
+        format: logicalFormat,
+        member,
+      };
+    })
+    .sort((left, right) =>
+      compareText(
+        `${left.role}\0${left.member}\0${left.path}`,
+        `${right.role}\0${right.member}\0${right.path}`,
+      ),
+    );
+  const runtimeCount = assets.filter(({ role }) => role === 'runtime-resources').length;
+  const nativeModuleStem =
+    manifest.nativeModuleStem === null
+      ? null
+      : portableIdentifier(
+          manifest.nativeModuleStem,
+          `${manifestPath} ${sqlName}.nativeModuleStem`,
+        );
+  const nativeDependencies = canonicalStringList(
+    manifest.iosNativeDependencies,
+    `${manifestPath} ${sqlName}.iosNativeDependencies`,
+  );
+  if (runtimeCount !== 1)
+    throw error(`${manifestPath} must contain exactly one iOS runtime-resources asset`);
+  if (nativeModuleStem === null) {
+    if (
+      assets.some(({ role }) => role !== 'runtime-resources') ||
+      nativeDependencies.length > 0 ||
+      manifest.iosRegistration !== null
+    ) {
+      throw error(`${manifestPath} SQL-only extension fabricates iOS native roles`);
+    }
+  } else {
+    const primary = rows.filter(({ row }) => row.kind === 'ios-xcframework');
+    const dependencies = rows
+      .filter(({ row }) => row.kind === 'ios-dependency-xcframework')
+      .map(({ row }) => row.identity)
+      .sort(compareText);
+    if (primary.length !== 1 || primary[0].row.identity !== nativeModuleStem) {
+      throw error(`${manifestPath} lacks its canonical primary iOS XCFramework`);
+    }
+    if (JSON.stringify(dependencies) !== JSON.stringify(nativeDependencies)) {
+      throw error(`${manifestPath} iOS dependency assets do not match iosNativeDependencies`);
+    }
+  }
+  const registration =
+    nativeModuleStem === null
+      ? null
+      : validateRegistration(manifest.iosRegistration, manifestPath, { nativeModuleStem, sqlName });
+  const runtimeRow = rows.find(({ row }) => row.kind === 'runtime');
+  if (runtimeRow === undefined) throw error(`${manifestPath} lacks its iOS runtime legal carrier`);
+  const legal =
+    includeLegal !== false
+      ? extensionLegalGroup({
+          archiveCache,
+          file: path.resolve(ROOT, runtimeRow.row.path),
+          format: runtimeRow.logicalFormat,
+          product: artifactProduct,
+          sqlName,
+        })
+      : undefined;
+  return {
+    carriers: [...carriers.values()].sort((left, right) => compareText(left.name, right.name)),
+    extension: {
+      product: artifactProduct,
+      releaseProduct: release.product,
+      version: release.version,
+      tag,
+      sqlName,
+      createsExtension: manifest.createsExtension,
+      dataFiles,
+      dependencies,
+      extensionSqlFileNames,
+      extensionSqlFilePrefixes,
+      nativeDependencies,
+      nativeModuleStem,
+      sharedPreloadLibraries,
+      registration,
+      assets,
+    },
+    legal,
+  };
+}
+
+function extensionArtifactDocument(manifestPath) {
+  const document = JSON.parse(readFileSync(manifestPath, 'utf8'));
+  if (
+    document?.schema === 'oliphaunt-extension-ci-artifacts-v1' &&
+    typeof document.product === 'string' &&
+    typeof document.version === 'string'
+  ) {
+    if (document.carrierAssets !== undefined) {
+      throw error(`${manifestPath} singleton manifest must not declare carrierAssets`);
+    }
+    return {
+      schema: document.schema,
+      product: document.product,
+      version: document.version,
+      compatibility: compatibilityMetadata(document.compatibility, `${manifestPath}.compatibility`),
+      carrierAssets: [],
+      rows: [document],
+    };
+  }
+  if (
+    document?.schema === 'oliphaunt-extension-ci-artifacts-v2' &&
+    typeof document.product === 'string' &&
+    typeof document.version === 'string' &&
+    Array.isArray(document.extensions) &&
+    document.extensions.length > 0
+  ) {
+    return {
+      schema: document.schema,
+      product: document.product,
+      version: document.version,
+      compatibility: compatibilityMetadata(document.compatibility, `${manifestPath}.compatibility`),
+      carrierAssets: document.carrierAssets,
+      rows: document.extensions.map((row, index) => {
+        if (row === null || Array.isArray(row) || typeof row !== 'object') {
+          throw error(`${manifestPath}.extensions[${index}] must be an object`);
+        }
+        return { ...row, product: document.product, version: document.version };
+      }),
+    };
+  }
+  throw error(`${manifestPath} has unsupported exact-extension CI artifact schema`);
+}
+
+function aggregateCarrierMap(document, manifestPath, { repository, localUrls, release }) {
+  if (document.schema === 'oliphaunt-extension-ci-artifacts-v1') return new Map();
+  if (!Array.isArray(document.carrierAssets) || document.carrierAssets.length === 0) {
+    throw error(`${manifestPath} bundle manifest must declare aggregate carrierAssets`);
+  }
+  const result = new Map();
+  const groups = new Set();
+  const expectedMemberCount = extensionSqlNames(document.product, 'ios-carrier-manifest').length;
+  for (const [index, row] of document.carrierAssets.entries()) {
+    if (
+      row === null ||
+      Array.isArray(row) ||
+      typeof row !== 'object' ||
+      row.kind !== 'extension-bundle' ||
+      typeof row.family !== 'string' ||
+      row.family.length === 0 ||
+      typeof row.target !== 'string' ||
+      row.target.length === 0 ||
+      typeof row.path !== 'string' ||
+      typeof row.sha256 !== 'string' ||
+      !/^[0-9a-f]{64}$/u.test(row.sha256) ||
+      !Number.isSafeInteger(row.bytes) ||
+      row.bytes <= 0 ||
+      row.memberCount !== expectedMemberCount
+    ) {
+      throw error(`${manifestPath}.carrierAssets[${index}] is not an exact aggregate carrier row`);
+    }
+    const name = portableAssetName(row.name, `${manifestPath}.carrierAssets[${index}].name`);
+    const file = requireFile(path.resolve(ROOT, row.path), `${document.product} aggregate carrier`);
+    if (
+      path.basename(file) !== name ||
+      statSync(file).size !== row.bytes ||
+      sha256(file) !== row.sha256
+    ) {
+      throw error(`${manifestPath}.carrierAssets[${index}] metadata does not match ${row.path}`);
+    }
+    const group = `${row.family}\0${row.target}`;
+    if (result.has(name) || groups.has(group)) {
+      throw error(`${manifestPath} repeats an aggregate carrier name or family/target`);
+    }
+    groups.add(group);
+    result.set(name, {
+      envelope: carrierEnvelope({ file, tag: release.tag, repository, localUrls }),
+      family: row.family,
+      file,
+      target: row.target,
+    });
+  }
+  return result;
+}
+
+function extensionCarriers(manifestPath, options) {
+  const document = extensionArtifactDocument(manifestPath);
+  stableVersion(document.version, `${document.product} version`);
+  const releaseProducts = new Set(
+    document.rows.map((row) =>
+      extensionReleaseProductForSqlName(row.sqlName, 'native', 'ios-carrier-manifest'),
+    ),
+  );
+  if (releaseProducts.size !== 1) {
+    throw error(`${manifestPath} members do not share one native release owner`);
+  }
+  const releaseProduct = [...releaseProducts][0];
+  const expectedReleaseVersion = currentProductVersionSync(releaseProduct, 'ios-carrier-manifest');
+  if (document.version !== expectedReleaseVersion) {
+    throw error(
+      `${manifestPath} version ${document.version} does not match ${releaseProduct} ${expectedReleaseVersion}`,
+    );
+  }
+  if (options.nativeRuntimeVersion !== undefined) {
+    const requested = stableVersion(
+      options.nativeRuntimeVersion,
+      'caller-supplied liboliphaunt-native version',
+    );
+    if (requested !== document.compatibility.nativeRuntimeVersion) {
+      throw error(
+        `${manifestPath} pins liboliphaunt-native ${document.compatibility.nativeRuntimeVersion}, ` +
+          `but caller supplied ${requested}`,
+      );
+    }
+  }
+  const release = {
+    product: releaseProduct,
+    tag: `${tagPrefix(releaseProduct, 'ios-carrier-manifest')}${document.version}`,
+    version: document.version,
+  };
+  const aggregateCarriers = aggregateCarrierMap(document, manifestPath, { ...options, release });
+  const built = document.rows.map((row) =>
+    extensionCarrier(row, manifestPath, {
+      ...options,
+      aggregateCarriers,
+      artifactProduct: document.product,
+      release,
+    }),
+  );
+  const rows = built.map(({ extension }) => extension);
+  const legal =
+    options.includeLegal === false
+      ? []
+      : built
+          .map(({ extension, legal: group }) => ({ ...group, sqlName: extension.sqlName }))
+          .sort((left, right) => compareText(left.sqlName, right.sqlName));
+  if (new Set(rows.map(({ sqlName }) => sqlName)).size !== rows.length) {
+    throw error(`${manifestPath} repeats an extension SQL name`);
+  }
+  const actualSqlNames = rows.map(({ sqlName }) => sqlName).sort(compareText);
+  const expectedSqlNames = extensionSqlNames(document.product, 'ios-carrier-manifest');
+  if (JSON.stringify(actualSqlNames) !== JSON.stringify(expectedSqlNames)) {
+    throw error(
+      `${manifestPath} does not contain the exact ${document.product} extension member set`,
+    );
+  }
+  const carriers = new Map();
+  for (const carrier of built.flatMap((row) => row.carriers)) {
+    const existing = carriers.get(carrier.name);
+    if (existing !== undefined && JSON.stringify(existing) !== JSON.stringify(carrier)) {
+      throw error(`${manifestPath} has conflicting carrier envelopes named ${carrier.name}`);
+    }
+    carriers.set(carrier.name, carrier);
+  }
+  return {
+    carriers: [...carriers.values()].sort((left, right) => compareText(left.name, right.name)),
+    nativeRuntimeVersion: document.compatibility.nativeRuntimeVersion,
+    legal,
+    release,
+    rows,
+  };
+}
+
+export function swiftExtensionCarrierAssetName(product, version) {
+  if (typeof product !== 'string' || !/^oliphaunt-extension-[A-Za-z0-9._-]+$/u.test(product)) {
+    throw error(`invalid exact-extension product ${product}`);
+  }
+  stableVersion(version, `${product} version`);
+  return `${product}-${version}-swift-extension-carrier.json`;
+}
+
+function dependencyCarrierReference(sqlName) {
+  const product = extensionProductForSqlName(sqlName, 'ios-carrier-manifest');
+  const releaseProduct = extensionReleaseProductForSqlName(
+    sqlName,
+    'native',
+    'ios-carrier-manifest',
+  );
+  const version = currentProductVersionSync(releaseProduct, 'ios-carrier-manifest');
+  stableVersion(version, `${product} version`);
+  return {
+    product,
+    releaseProduct,
+    sqlName,
+    tag: `${tagPrefix(releaseProduct, 'ios-carrier-manifest')}${version}`,
+    version,
+  };
+}
+
+/**
+ * Build the immutable extension carrier published on its native release owner.
+ * It references, rather than duplicates, the compatible native base.
+ */
+export function buildSwiftExtensionCarrierManifest({
+  extensionManifest,
+  nativeRuntimeVersion = undefined,
+  repository = DEFAULT_REPOSITORY,
+  localUrls = false,
+  verifyMembers = true,
+} = {}) {
+  validateRepository(repository);
+  if (typeof extensionManifest !== 'string' || extensionManifest.length === 0) {
+    throw error('extensionManifest must be an exact-extension CI artifact manifest path');
+  }
+  const archiveCache = new Map();
+  const resolved = extensionCarriers(path.resolve(extensionManifest), {
+    archiveCache,
+    includeLegal: false,
+    repository,
+    localUrls,
+    nativeRuntimeVersion,
+    verifyMembers,
+  });
+  const { carriers, release, rows } = resolved;
+  const version = resolved.nativeRuntimeVersion;
+  return stable({
+    schema: SWIFT_EXTENSION_CARRIER_SCHEMA,
+    release,
+    base: {
+      product: 'liboliphaunt-native',
+      tag: `${tagPrefix('liboliphaunt-native', 'ios-carrier-manifest')}${version}`,
+      version,
+    },
+    carriers,
+    entries: rows.map((extension) => ({
+      dependencyCarriers: extension.dependencies.map(dependencyCarrierReference),
+      extension,
+    })),
+  });
+}
+
+export function writeSwiftExtensionCarrierManifest(output, options = {}) {
+  const manifest = buildSwiftExtensionCarrierManifest(options);
+  mkdirSync(path.dirname(output), { recursive: true });
+  writeFileSync(output, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
+  return manifest;
+}
+
+export function discoveredExtensionManifests(root) {
+  if (!existsSync(root)) return [];
+  const manifests = [];
+  const visit = (directory) => {
+    const manifest = path.join(directory, 'extension-artifacts.json');
+    if (existsSync(manifest)) {
+      manifests.push(manifest);
+      return;
+    }
+    for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) =>
+      compareText(left.name, right.name),
+    )) {
+      if (entry.isDirectory()) visit(path.join(directory, entry.name));
+    }
+  };
+  visit(root);
+  return manifests.sort(compareText);
+}
+
+export function buildIosCarrierManifest({
+  baseAssetDir = path.join(ROOT, 'target/liboliphaunt/release-assets'),
+  baseCarrierManifest = undefined,
+  extensionManifests = discoveredExtensionManifests(path.join(ROOT, 'target/extension-artifacts')),
+  repository = DEFAULT_REPOSITORY,
+  localUrls = false,
+  verifyMembers = true,
+} = {}) {
+  validateRepository(repository);
+  const archiveCache = new Map();
+  const frozenBase =
+    baseCarrierManifest === undefined
+      ? baseCarrier({
+          archiveCache,
+          baseAssetDir: path.resolve(baseAssetDir),
+          repository,
+          localUrls,
+          verifyMembers,
+        })
+      : frozenBaseCarrier(baseCarrierManifest);
+  const { base, legal: baseLegal } = frozenBase;
+  const documents = extensionManifests.map((file) => {
+    const document = extensionCarriers(path.resolve(file), {
+      archiveCache,
+      repository,
+      localUrls,
+      verifyMembers,
+    });
+    if (document.nativeRuntimeVersion !== base.version) {
+      throw error(
+        `${file} pins liboliphaunt-native ${document.nativeRuntimeVersion}, ` +
+          `but the selected base carrier is ${base.version}`,
+      );
+    }
+    return document;
+  });
+  const extensions = documents
+    .flatMap(({ rows }) => rows)
+    .sort((left, right) => compareText(left.sqlName, right.sqlName));
+  if (new Set(extensions.map(({ sqlName }) => sqlName)).size !== extensions.length) {
+    throw error('extension carrier set contains duplicate SQL names');
+  }
+  const carriers = new Map();
+  for (const carrier of documents.flatMap((document) => document.carriers)) {
+    const existing = carriers.get(carrier.name);
+    if (existing !== undefined && JSON.stringify(existing) !== JSON.stringify(carrier)) {
+      throw error(`extension carrier set has conflicting envelopes named ${carrier.name}`);
+    }
+    carriers.set(carrier.name, carrier);
+  }
+  return stable({
+    schema: IOS_CARRIER_SCHEMA,
+    base,
+    carriers: [...carriers.values()].sort((left, right) => compareText(left.name, right.name)),
+    extensions,
+    legal: {
+      base: baseLegal,
+      extensions: documents
+        .flatMap(({ legal }) => legal)
+        .sort((left, right) => compareText(left.sqlName, right.sqlName)),
+    },
+  });
+}
+
+export function writeIosCarrierManifest(output, options = {}) {
+  const manifest = buildIosCarrierManifest(options);
+  mkdirSync(path.dirname(output), { recursive: true });
+  writeFileSync(output, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
+  return manifest;
+}
+
+function parseArgs(argv) {
+  const options = { extensionManifests: [] };
+  let output = DEFAULT_IOS_CARRIER;
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--local-urls') {
+      options.localUrls = true;
+      continue;
+    }
+    if (arg === '--help' || arg === '-h') {
+      console.log(
+        `usage: ${path.basename(import.meta.path)} [--base-asset-dir DIR] [--extension-manifest FILE ...] ` +
+          `[--base-carrier FILE] [--extension-root DIR] [--repository OWNER/REPO] [--output FILE] [--local-urls]`,
+      );
+      process.exit(0);
+    }
+    const value = argv[index + 1];
+    if (value === undefined) throw error(`${arg} requires a value`);
+    index += 1;
+    if (arg === '--base-asset-dir') options.baseAssetDir = value;
+    else if (arg === '--base-carrier') options.baseCarrierManifest = value;
+    else if (arg === '--extension-manifest') options.extensionManifests.push(value);
+    else if (arg === '--extension-root')
+      options.extensionManifests.push(...discoveredExtensionManifests(path.resolve(value)));
+    else if (arg === '--repository') options.repository = value;
+    else if (arg === '--output') output = path.resolve(value);
+    else throw error(`unknown argument ${arg}`);
+  }
+  if (options.extensionManifests.length === 0) delete options.extensionManifests;
+  return { options, output };
+}
+
+if (import.meta.main) {
+  try {
+    if (process.argv[2] === 'list-extensions' && process.argv.length === 4) {
+      const manifest = JSON.parse(readFileSync(process.argv[3], 'utf8'));
+      console.log(
+        manifest.extensions
+          .map(({ sqlName }) => sqlName)
+          .sort()
+          .join(','),
+      );
+      process.exit(0);
+    }
+    const { options, output } = parseArgs(process.argv.slice(2));
+    const manifest = writeIosCarrierManifest(output, options);
+    console.log(`${path.relative(ROOT, output)}\t${manifest.extensions.length} extensions`);
+  } catch (cause) {
+    console.error(cause instanceof Error ? cause.message : String(cause));
+    process.exit(1);
+  }
+}
diff --git a/src/sdks/swift/tools/ios-carrier-manifest.test.mts b/src/sdks/swift/tools/ios-carrier-manifest.test.mts
new file mode 100644
index 000000000..ad3586ca2
--- /dev/null
+++ b/src/sdks/swift/tools/ios-carrier-manifest.test.mts
@@ -0,0 +1,536 @@
+#!/usr/bin/env bun
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import {
+  mkdirSync,
+  mkdtempSync,
+  readFileSync,
+  renameSync,
+  rmSync,
+  statSync,
+  symlinkSync,
+  unlinkSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import test from 'node:test';
+import { archiveDirectory } from '../../../../tools/packaging/archive-directory.mts';
+import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts';
+import {
+  currentProductVersionSync,
+  extensionMetadata,
+  extensionReleaseProduct,
+  extensionSqlNames,
+} from '../../../../tools/release/release-artifact-targets.mts';
+import { stageExtensionUpstreamLicenses } from '../../../extensions/tools/extension-upstream-licenses.mts';
+import {
+  buildIosCarrierManifest,
+  buildSwiftExtensionCarrierManifest,
+  discoveredExtensionManifests,
+  swiftExtensionCarrierAssetName,
+} from './ios-carrier-manifest.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../../../..');
+
+test('discovers flat extensions and nested runtime-owned contrib carriers', () => {
+  mkdirSync(path.join(ROOT, 'target'), { recursive: true });
+  const root = mkdtempSync(path.join(ROOT, 'target', 'ios-carrier-discovery-test-'));
+  try {
+    const flat = path.join(root, 'oliphaunt-extension-vector', 'extension-artifacts.json');
+    const nested = path.join(
+      root,
+      'liboliphaunt-native',
+      'oliphaunt-extension-contrib-pg18',
+      'extension-artifacts.json',
+    );
+    mkdirSync(path.dirname(flat), { recursive: true });
+    mkdirSync(path.dirname(nested), { recursive: true });
+    writeFileSync(flat, '{}\n');
+    writeFileSync(nested, '{}\n');
+
+    assert.deepEqual(discoveredExtensionManifests(root), [nested, flat].sort());
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
+
+function sha256(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+async function archive(root, name, member, _format, legal = undefined) {
+  const staging = path.join(root, `stage-${name}`);
+  const leaf = path.join(staging, member);
+  mkdirSync(leaf, { recursive: true });
+  writeFileSync(path.join(leaf, 'payload.txt'), `${name}\n`);
+  if (legal !== undefined) {
+    const noticeRoot = legal.insideMember ? leaf : staging;
+    stageReleaseNotices(noticeRoot, { profile: legal.profile });
+    if (legal.sqlName !== undefined) {
+      stageExtensionUpstreamLicenses(legal.sqlName, path.join(noticeRoot, 'files'));
+    }
+  }
+  const output = path.join(root, name);
+  await archiveDirectory(legal?.insideMember === false ? staging : leaf, output, {
+    keepParent: legal?.insideMember !== false,
+  });
+  return output;
+}
+
+function assetRow(file, kind, identity = null) {
+  return {
+    family: 'native',
+    target: 'ios-xcframework',
+    kind,
+    identity,
+    name: path.basename(file),
+    path: path.relative(ROOT, file).split(path.sep).join('/'),
+    bytes: statSync(file).size,
+    sha256: sha256(file),
+  };
+}
+
+function compatibility(
+  nativeRuntimeVersion = currentProductVersionSync(
+    'liboliphaunt-native',
+    'ios-carrier-manifest.test',
+  ),
+) {
+  return {
+    ...extensionMetadata('oliphaunt-extension-contrib-pg18').compatibility,
+    nativeRuntimeVersion,
+  };
+}
+
+function nextStableVersion(version) {
+  const [major, minor, patch] = version.split('.').map(Number);
+  return `${major}.${minor}.${patch + 1}`;
+}
+
+function writeManifest(root, product, body) {
+  const directory = path.join(root, product);
+  mkdirSync(directory, { recursive: true });
+  const file = path.join(directory, 'extension-artifacts.json');
+  writeFileSync(
+    file,
+    `${JSON.stringify(
+      {
+        schema: 'oliphaunt-extension-ci-artifacts-v1',
+        product,
+        version: currentProductVersionSync(product, 'ios-carrier-manifest.test'),
+        compatibility: compatibility(),
+        createsExtension: true,
+        dataFiles: [],
+        dependencies: [],
+        extensionSqlFileNames: [],
+        extensionSqlFilePrefixes: [],
+        nativeDependencies: [],
+        sharedPreloadLibraries: [],
+        ...body,
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  return file;
+}
+
+test('produces exact local and GitHub carrier envelopes ', async () => {
+  mkdirSync(path.join(ROOT, 'target'), { recursive: true });
+  const root = mkdtempSync(path.join(ROOT, 'target', 'ios-carrier-test-'));
+  try {
+    const version = currentProductVersionSync('liboliphaunt-native', 'ios-carrier-manifest.test');
+    const base = path.join(root, 'base');
+    mkdirSync(base, { recursive: true });
+    await archive(
+      base,
+      `liboliphaunt-${version}-apple-spm-xcframework.zip`,
+      'liboliphaunt.xcframework',
+      'zip',
+      {
+        insideMember: true,
+        profile: 'native-runtime',
+      },
+    );
+    await archive(
+      base,
+      `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`,
+      'oliphaunt',
+      'tar.gz',
+      {
+        insideMember: false,
+        profile: 'native-runtime-resources',
+      },
+    );
+
+    const pgtapRuntime = await archive(root, 'pgtap-runtime.tar.gz', 'oliphaunt', 'tar.gz', {
+      insideMember: false,
+      profile: 'external-native',
+      sqlName: 'pgtap',
+    });
+    const pgtap = writeManifest(root, 'oliphaunt-extension-pgtap', {
+      sqlName: 'pgtap',
+      extensionSqlFileNames: ['uninstall_pgtap.sql'],
+      extensionSqlFilePrefixes: ['pgtap-core', 'pgtap-schema'],
+      nativeModuleStem: null,
+      iosNativeDependencies: [],
+      iosRegistration: null,
+      assets: [assetRow(pgtapRuntime, 'runtime')],
+    });
+
+    const postgisRuntime = await archive(root, 'postgis-runtime.tar.gz', 'oliphaunt', 'tar.gz', {
+      insideMember: false,
+      profile: 'external-native',
+      sqlName: 'postgis',
+    });
+    const postgisPrimary = await archive(
+      root,
+      'postgis-primary.zip',
+      'liboliphaunt_extension_postgis-3.xcframework',
+      'zip',
+    );
+    const postgisGeos = await archive(
+      root,
+      'postgis-geos.zip',
+      'liboliphaunt_dependency_geos.xcframework',
+      'zip',
+    );
+    const postgis = writeManifest(root, 'oliphaunt-extension-postgis', {
+      sqlName: 'postgis',
+      nativeModuleStem: 'postgis-3',
+      iosNativeDependencies: ['geos'],
+      iosRegistration: {
+        schema: 'oliphaunt-ios-extension-registration-v1',
+        sqlName: 'postgis',
+        nativeModuleStem: 'postgis-3',
+        magicSymbol: 'oliphaunt_static_postgis_3_Pg_magic_func',
+        initSymbol: 'oliphaunt_static_postgis_3__PG_init',
+        symbols: [],
+      },
+      assets: [
+        assetRow(postgisRuntime, 'runtime'),
+        assetRow(postgisPrimary, 'ios-xcframework', 'postgis-3'),
+        assetRow(postgisGeos, 'ios-dependency-xcframework', 'geos'),
+      ],
+    });
+
+    const local = buildIosCarrierManifest({
+      baseAssetDir: base,
+      extensionManifests: [postgis, pgtap],
+      localUrls: true,
+    });
+    assert.deepEqual(
+      local.base.assets.map(({ role }) => role),
+      ['base-xcframework', 'runtime-resources'],
+    );
+    assert.deepEqual(
+      local.legal.base.map(({ assetRole }) => assetRole),
+      ['base-xcframework', 'runtime-resources'],
+    );
+    assert.deepEqual(
+      local.legal.base.map(({ spdx }) => spdx),
+      ['MIT AND PostgreSQL AND Unicode-3.0', 'MIT AND PostgreSQL'],
+    );
+    assert.deepEqual(
+      local.extensions.map(({ sqlName }) => sqlName),
+      ['pgtap', 'postgis'],
+    );
+    assert.deepEqual(
+      local.legal.extensions.map(({ sqlName }) => sqlName),
+      ['pgtap', 'postgis'],
+    );
+    assert.ok(
+      local.legal.extensions.every(({ files }) =>
+        files.every(({ bytes, sha256 }) => bytes > 0 && /^[0-9a-f]{64}$/u.test(sha256)),
+      ),
+    );
+    assert.ok(
+      local.legal.extensions
+        .find(({ sqlName }) => sqlName === 'postgis')
+        .files.some(({ member }) => member === 'files/share/licenses/postgis/COPYING'),
+    );
+    const sqlOnly = local.extensions[0];
+    assert.equal(sqlOnly.nativeModuleStem, null);
+    assert.equal(sqlOnly.registration, null);
+    assert.deepEqual(sqlOnly.dataFiles, []);
+    assert.deepEqual(sqlOnly.extensionSqlFileNames, ['uninstall_pgtap.sql']);
+    assert.deepEqual(sqlOnly.extensionSqlFilePrefixes, ['pgtap-core', 'pgtap-schema']);
+    assert.deepEqual(
+      sqlOnly.assets.map(({ role }) => role),
+      ['runtime-resources'],
+    );
+    const native = local.extensions[1];
+    assert.deepEqual(native.nativeDependencies, ['geos']);
+    assert.deepEqual(native.assets.map(({ role }) => role).sort(), [
+      'dependency-xcframework',
+      'extension-xcframework',
+      'runtime-resources',
+    ]);
+    assert.ok(local.base.assets.every(({ url }) => url.startsWith('file:')));
+
+    const publicManifest = buildIosCarrierManifest({
+      baseAssetDir: base,
+      extensionManifests: [pgtap],
+      repository: 'f0rr0/oliphaunt',
+    });
+    assert.ok(
+      publicManifest.base.assets.every(({ url }) =>
+        url.startsWith(
+          `https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v${version}/`,
+        ),
+      ),
+    );
+
+    const baseXcframework = path.join(base, `liboliphaunt-${version}-apple-spm-xcframework.zip`);
+    const realBaseXcframework = `${baseXcframework}.real`;
+    renameSync(baseXcframework, realBaseXcframework);
+    symlinkSync(path.basename(realBaseXcframework), baseXcframework);
+    assert.throws(
+      () =>
+        buildIosCarrierManifest({
+          baseAssetDir: base,
+          extensionManifests: [pgtap],
+          localUrls: true,
+        }),
+      /base-xcframework asset must be a regular file/u,
+    );
+    unlinkSync(baseXcframework);
+    renameSync(realBaseXcframework, baseXcframework);
+
+    const swiftCarrier = buildSwiftExtensionCarrierManifest({
+      extensionManifest: pgtap,
+      nativeRuntimeVersion: version,
+    });
+    const pgtapVersion = currentProductVersionSync(
+      'oliphaunt-extension-pgtap',
+      'ios-carrier-manifest.test',
+    );
+    assert.equal(swiftCarrier.schema, 'oliphaunt-swift-extension-carrier-v1');
+    assert.deepEqual(swiftCarrier.release, {
+      product: 'oliphaunt-extension-pgtap',
+      tag: `oliphaunt-extension-pgtap-v${pgtapVersion}`,
+      version: pgtapVersion,
+    });
+    assert.equal(swiftCarrier.entries.length, 1);
+    assert.equal(swiftCarrier.entries[0].extension.sqlName, 'pgtap');
+    assert.deepEqual(swiftCarrier.entries[0].dependencyCarriers, []);
+    assert.equal(
+      swiftExtensionCarrierAssetName('oliphaunt-extension-pgtap', pgtapVersion),
+      `oliphaunt-extension-pgtap-${pgtapVersion}-swift-extension-carrier.json`,
+    );
+
+    const canonicalPgtap = JSON.parse(readFileSync(pgtap, 'utf8'));
+    for (const [label, mutate, pattern] of [
+      [
+        'self dependency',
+        (document) => {
+          document.dependencies = ['pgtap'];
+        },
+        /dependencies must not include itself/u,
+      ],
+      [
+        'dot-bearing SQL prefix',
+        (document) => {
+          document.extensionSqlFilePrefixes = ['pgtap.core'];
+        },
+        /dot-free portable SQL basename prefix/u,
+      ],
+      [
+        'non-portable SQL name',
+        (document) => {
+          document.extensionSqlFileNames = ['foreign name.sql'];
+        },
+        /portable identifier/u,
+      ],
+      [
+        'non-canonical SQL-name order',
+        (document) => {
+          document.extensionSqlFileNames = ['z.sql', 'a.sql'];
+        },
+        /sorted in ordinal order/u,
+      ],
+    ]) {
+      const candidate = structuredClone(canonicalPgtap);
+      mutate(candidate);
+      writeFileSync(pgtap, `${JSON.stringify(candidate, null, 2)}\n`);
+      assert.throws(
+        () =>
+          buildIosCarrierManifest({
+            baseAssetDir: base,
+            extensionManifests: [pgtap],
+            localUrls: true,
+          }),
+        pattern,
+        label,
+      );
+    }
+    writeFileSync(pgtap, `${JSON.stringify(canonicalPgtap, null, 2)}\n`);
+
+    const incompatibleVersion = nextStableVersion(version);
+    assert.throws(
+      () =>
+        buildSwiftExtensionCarrierManifest({
+          extensionManifest: pgtap,
+          nativeRuntimeVersion: incompatibleVersion,
+        }),
+      new RegExp(
+        `pins liboliphaunt-native ${version.replaceAll('.', '\\.')}, but caller supplied ${incompatibleVersion.replaceAll('.', '\\.')}`,
+        'u',
+      ),
+    );
+    const incompatiblePgtap = JSON.parse(readFileSync(pgtap, 'utf8'));
+    incompatiblePgtap.compatibility.nativeRuntimeVersion = incompatibleVersion;
+    writeFileSync(pgtap, `${JSON.stringify(incompatiblePgtap, null, 2)}\n`);
+    assert.throws(
+      () =>
+        buildIosCarrierManifest({
+          baseAssetDir: base,
+          extensionManifests: [pgtap],
+          localUrls: true,
+        }),
+      new RegExp(
+        `pins liboliphaunt-native ${incompatibleVersion.replaceAll('.', '\\.')}, but the selected base carrier is ${version.replaceAll('.', '\\.')}`,
+        'u',
+      ),
+    );
+
+    const malformed = JSON.parse(readFileSync(postgis, 'utf8'));
+    malformed.iosNativeDependencies = ['geos', 'proj'];
+    writeFileSync(postgis, `${JSON.stringify(malformed, null, 2)}\n`);
+    assert.throws(
+      () =>
+        buildIosCarrierManifest({
+          baseAssetDir: base,
+          extensionManifests: [postgis],
+          localUrls: true,
+        }),
+      /dependency assets do not match/u,
+    );
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
+
+test('bundle carriers verify exact nested bytes ', async () => {
+  mkdirSync(path.join(ROOT, 'target'), { recursive: true });
+  const root = mkdtempSync(path.join(ROOT, 'target', 'ios-bundle-carrier-test-'));
+  try {
+    const product = 'oliphaunt-extension-contrib-pg18';
+    const releaseProduct = extensionReleaseProduct(product, 'native', 'ios-carrier-manifest.test');
+    const version = currentProductVersionSync(releaseProduct, 'ios-carrier-manifest.test');
+    const sqlNames = extensionSqlNames(product, 'ios-carrier-manifest.test');
+    const carrierRoot = `${product}-${version}-native-ios-xcframework-bundle`;
+    const carrierName = `${carrierRoot}.tar.gz`;
+    const carrierStage = path.join(root, 'carrier-stage', carrierRoot);
+    const extensions = [];
+    for (const sqlName of sqlNames) {
+      const logicalRoot = path.join(root, 'logical', sqlName);
+      mkdirSync(logicalRoot, { recursive: true });
+      const logicalName = `${product}-${version}-native-ios-runtime.tar.gz`;
+      const logicalFile = await archive(logicalRoot, logicalName, 'oliphaunt', 'tar.gz', {
+        insideMember: false,
+        profile: 'contrib-native',
+      });
+      const memberPath = `extensions/${sqlName}/${logicalName}`;
+      const nested = path.join(carrierStage, ...memberPath.split('/'));
+      mkdirSync(path.dirname(nested), { recursive: true });
+      writeFileSync(nested, readFileSync(logicalFile));
+      extensions.push({
+        sqlName,
+        createsExtension: true,
+        dataFiles: [],
+        dependencies: [],
+        extensionSqlFileNames: [],
+        extensionSqlFilePrefixes: [],
+        nativeDependencies: [],
+        nativeModuleStem: null,
+        iosNativeDependencies: [],
+        iosRegistration: null,
+        sharedPreloadLibraries: [],
+        assets: [
+          {
+            family: 'native',
+            target: 'ios-xcframework',
+            kind: 'runtime',
+            identity: null,
+            name: logicalName,
+            path: path.relative(ROOT, logicalFile).split(path.sep).join('/'),
+            bytes: statSync(logicalFile).size,
+            sha256: sha256(logicalFile),
+            carrierAsset: carrierName,
+            carrierRoot,
+            memberPath,
+          },
+        ],
+      });
+    }
+    writeFileSync(path.join(carrierStage, 'bundle-manifest.json'), '{}\n');
+    const releaseAssets = path.join(root, 'release-assets');
+    mkdirSync(releaseAssets, { recursive: true });
+    const carrierFile = path.join(releaseAssets, carrierName);
+    await archiveDirectory(carrierStage, carrierFile, { keepParent: true });
+    const manifestFile = path.join(root, 'extension-artifacts.json');
+    const writeBundle = () =>
+      writeFileSync(
+        manifestFile,
+        `${JSON.stringify(
+          {
+            schema: 'oliphaunt-extension-ci-artifacts-v2',
+            product,
+            version,
+            compatibility: compatibility(),
+            extensions,
+            carrierAssets: [
+              {
+                name: carrierName,
+                path: path.relative(ROOT, carrierFile).split(path.sep).join('/'),
+                sha256: sha256(carrierFile),
+                bytes: statSync(carrierFile).size,
+                family: 'native',
+                target: 'ios-xcframework',
+                kind: 'extension-bundle',
+                memberCount: sqlNames.length,
+              },
+            ],
+          },
+          null,
+          2,
+        )}\n`,
+      );
+    writeBundle();
+
+    const carrier = buildSwiftExtensionCarrierManifest({
+      extensionManifest: manifestFile,
+      localUrls: true,
+    });
+    assert.equal(carrier.carriers.length, 1);
+    assert.equal(carrier.entries.length, sqlNames.length);
+    assert.ok(
+      carrier.entries.every(
+        ({ extension }) =>
+          extension.product === product &&
+          extension.releaseProduct === releaseProduct &&
+          extension.assets.length === 1 &&
+          extension.assets[0].carrier === carrierName &&
+          extension.assets[0].path.startsWith(`${carrierRoot}/extensions/${extension.sqlName}/`),
+      ),
+    );
+
+    const tampered = path.join(
+      carrierStage,
+      'extensions',
+      sqlNames[0],
+      extensions[0].assets[0].name,
+    );
+    writeFileSync(tampered, 'repacked bytes that do not match the logical row\n');
+    await archiveDirectory(carrierStage, carrierFile, { keepParent: true });
+    writeBundle();
+    assert.throws(
+      () =>
+        buildSwiftExtensionCarrierManifest({ extensionManifest: manifestFile, localUrls: true }),
+      /nested payload .* does not match its declared bytes\/SHA-256/u,
+    );
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
diff --git a/src/sdks/swift/tools/prepare-bindings.sh b/src/sdks/swift/tools/prepare-bindings.sh
new file mode 100644
index 000000000..36ff3ba86
--- /dev/null
+++ b/src/sdks/swift/tools/prepare-bindings.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+cd "$root"
+bash src/sdks/rust/mobile-bindings/tools/generate.sh
+stage="$root/src/sdks/swift/.build/native-bindings"
+mkdir -p "$stage/swift" "$stage/ffi"
+cp target/mobile-bindings/generated/OliphauntNativeBindings.swift "$stage/swift/"
+cp target/mobile-bindings/generated/OliphauntNativeBindingsFFI.h "$stage/ffi/"
+cp target/mobile-bindings/generated/OliphauntNativeBindingsFFI.modulemap "$stage/ffi/module.modulemap"
+cp "${CARGO_TARGET_DIR:-$root/target}/debug/liboliphaunt_mobile_bindings.a" "$stage/"
diff --git a/src/sdks/swift/tools/prepare-swift-release-consumer.mts b/src/sdks/swift/tools/prepare-swift-release-consumer.mts
new file mode 100755
index 000000000..939427c2c
--- /dev/null
+++ b/src/sdks/swift/tools/prepare-swift-release-consumer.mts
@@ -0,0 +1,152 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+const TOOL = 'prepare-swift-release-consumer.mts';
+const LOCAL_XCFRAMEWORK_PATH = 'Artifacts/liboliphaunt.xcframework';
+const BINARY_TARGET =
+  /\.binaryTarget\(\s*name:\s*"liboliphaunt"\s*,\s*url:\s*"([^"]+)"\s*,\s*checksum:\s*"([0-9a-f]{64})"\s*\)/gmu;
+
+function sha256(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function releaseAssetIdentity(assetFile) {
+  const basename = path.basename(assetFile);
+  const match = /^liboliphaunt-(.+)-apple-spm-xcframework\.zip$/u.exec(basename);
+  if (!match || !match[1]) {
+    throw new Error(
+      `Apple XCFramework asset must be named liboliphaunt--apple-spm-xcframework.zip: ${basename}`,
+    );
+  }
+  return { basename, version: match[1] };
+}
+
+export function parseSwiftReleaseBinaryTarget(manifest, label = 'release manifest') {
+  if (typeof manifest !== 'string') {
+    throw new Error(`${label} must be text`);
+  }
+  const matches = [...manifest.matchAll(BINARY_TARGET)];
+  if (matches.length !== 1) {
+    throw new Error(
+      `${label} must contain exactly one checksum-pinned liboliphaunt binary target; found ${matches.length}`,
+    );
+  }
+  const [match] = matches;
+  return {
+    checksum: match[2],
+    end: match.index + match[0].length,
+    index: match.index,
+    url: match[1],
+  };
+}
+
+export function localizeSwiftReleaseManifest({
+  manifestFile,
+  assetFile,
+  bindingsAssetFile,
+  outputFile,
+}) {
+  const manifest = readFileSync(manifestFile, 'utf8');
+  const { checksum, end, index, url } = parseSwiftReleaseBinaryTarget(manifest);
+  const { basename, version } = releaseAssetIdentity(assetFile);
+  const expectedUrl =
+    `https://github.com/f0rr0/oliphaunt/releases/download/` +
+    `liboliphaunt-native-v${version}/${basename}`;
+  if (url !== expectedUrl) {
+    throw new Error(`release manifest binary URL is not the canonical ${expectedUrl}: ${url}`);
+  }
+  const actualChecksum = sha256(assetFile);
+  if (checksum !== actualChecksum) {
+    throw new Error(
+      `release manifest checksum ${checksum} does not match ${basename} SHA-256 ${actualChecksum}`,
+    );
+  }
+
+  const replacement =
+    `.binaryTarget(\n` +
+    `            name: "liboliphaunt",\n` +
+    `            path: "${LOCAL_XCFRAMEWORK_PATH}"\n` +
+    `        )`;
+  let localized = manifest.slice(0, index) + replacement + manifest.slice(end);
+  const bindings =
+    /\.binaryTarget\(\s*name:\s*"OliphauntNativeBindingsFFI"\s*,\s*url:\s*"([^"]+)"\s*,\s*checksum:\s*"([0-9a-f]{64})"\s*\)/u.exec(
+      localized,
+    );
+  if (bindings) {
+    if (!bindingsAssetFile)
+      throw new Error('generated mobile bindings target requires --bindings-asset');
+    const name = path.basename(bindingsAssetFile);
+    const version = /^oliphaunt-swift-(.+)-bindings\.xcframework\.zip$/u.exec(name)?.[1];
+    const expected = `https://github.com/f0rr0/oliphaunt/releases/download/oliphaunt-swift-v${version}/${name}`;
+    if (!version || bindings[1] !== expected || bindings[2] !== sha256(bindingsAssetFile)) {
+      throw new Error(
+        'generated mobile bindings asset does not match the checksum-pinned public target',
+      );
+    }
+    localized = localized.replace(
+      bindings[0],
+      '.binaryTarget(name: "OliphauntNativeBindingsFFI", path: "Artifacts/OliphauntNativeBindingsFFI.xcframework")',
+    );
+  }
+  if (localized.includes('file://')) {
+    throw new Error('localized release manifest must not contain a file URL');
+  }
+  if (!localized.includes(`path: "${LOCAL_XCFRAMEWORK_PATH}"`)) {
+    throw new Error(
+      'localized release manifest did not retain the exact local XCFramework projection',
+    );
+  }
+  mkdirSync(path.dirname(outputFile), { recursive: true });
+  writeFileSync(outputFile, localized, 'utf8');
+  return {
+    asset: basename,
+    checksum: actualChecksum,
+    publicUrl: expectedUrl,
+    xcframeworkPath: LOCAL_XCFRAMEWORK_PATH,
+  };
+}
+
+function parseArgs(argv) {
+  const values = new Map();
+  for (let index = 0; index < argv.length; index += 1) {
+    const key = argv[index];
+    if (!['--manifest', '--asset', '--bindings-asset', '--output'].includes(key)) {
+      throw new Error(`unknown argument ${key}`);
+    }
+    const value = argv[index + 1];
+    if (!value || value.startsWith('--')) {
+      throw new Error(`${key} requires a value`);
+    }
+    if (values.has(key)) {
+      throw new Error(`${key} may be specified only once`);
+    }
+    values.set(key, value);
+    index += 1;
+  }
+  for (const key of ['--manifest', '--asset', '--output']) {
+    if (!values.has(key)) {
+      throw new Error(`${key} is required`);
+    }
+  }
+  return {
+    assetFile: path.resolve(values.get('--asset')),
+    bindingsAssetFile: values.has('--bindings-asset')
+      ? path.resolve(values.get('--bindings-asset'))
+      : undefined,
+    manifestFile: path.resolve(values.get('--manifest')),
+    outputFile: path.resolve(values.get('--output')),
+  };
+}
+
+if (import.meta.main) {
+  try {
+    const result = localizeSwiftReleaseManifest(parseArgs(Bun.argv.slice(2)));
+    console.log(JSON.stringify(result));
+  } catch (error) {
+    console.error(`${TOOL}: ${error.message}`);
+    process.exit(1);
+  }
+}
diff --git a/src/sdks/swift/tools/prepare-swift-release-consumer.test.mts b/src/sdks/swift/tools/prepare-swift-release-consumer.test.mts
new file mode 100644
index 000000000..fc39bdbe6
--- /dev/null
+++ b/src/sdks/swift/tools/prepare-swift-release-consumer.test.mts
@@ -0,0 +1,94 @@
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import { localizeSwiftReleaseManifest } from './prepare-swift-release-consumer.mts';
+
+function fixture(context) {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-swift-release-consumer-'));
+  context.after(() => rmSync(root, { recursive: true, force: true }));
+  const version = '1.2.3';
+  const asset = path.join(root, `liboliphaunt-${version}-apple-spm-xcframework.zip`);
+  writeFileSync(asset, 'xcframework bytes\n');
+  const checksum = createHash('sha256').update(readFileSync(asset)).digest('hex');
+  const url =
+    `https://github.com/f0rr0/oliphaunt/releases/download/` +
+    `liboliphaunt-native-v${version}/${path.basename(asset)}`;
+  const binaryTarget =
+    `.binaryTarget(\n` +
+    `            name: "liboliphaunt",\n` +
+    `            url: "${url}",\n` +
+    `            checksum: "${checksum}"\n` +
+    `        )`;
+  const manifest = path.join(root, 'Package.swift.release');
+  const output = path.join(root, 'consumer', 'Package.swift');
+  writeFileSync(manifest, `// swift-tools-version: 6.0\nlet target = ${binaryTarget}\n`);
+  return { asset, binaryTarget, checksum, manifest, output, url };
+}
+
+test('localizes only the exact checksum-bound canonical Apple binary target', (context) => {
+  const value = fixture(context);
+  const result = localizeSwiftReleaseManifest({
+    manifestFile: value.manifest,
+    assetFile: value.asset,
+    outputFile: value.output,
+  });
+  assert.deepEqual(result, {
+    asset: path.basename(value.asset),
+    checksum: value.checksum,
+    publicUrl: value.url,
+    xcframeworkPath: 'Artifacts/liboliphaunt.xcframework',
+  });
+  const output = readFileSync(value.output, 'utf8');
+  assert.match(output, /path: "Artifacts\/liboliphaunt\.xcframework"/u);
+  assert.doesNotMatch(output, /url:|checksum:|file:\/\//u);
+});
+
+test('rejects checksum drift instead of projecting substituted bytes', (context) => {
+  const value = fixture(context);
+  writeFileSync(value.asset, 'substituted bytes\n');
+  assert.throws(
+    () =>
+      localizeSwiftReleaseManifest({
+        manifestFile: value.manifest,
+        assetFile: value.asset,
+        outputFile: value.output,
+      }),
+    /does not match .* SHA-256/u,
+  );
+});
+
+test('rejects noncanonical and duplicate binary target identities', (context) => {
+  const value = fixture(context);
+  writeFileSync(
+    value.manifest,
+    readFileSync(value.manifest, 'utf8').replace(value.url, 'https://example.invalid/runtime.zip'),
+  );
+  assert.throws(
+    () =>
+      localizeSwiftReleaseManifest({
+        manifestFile: value.manifest,
+        assetFile: value.asset,
+        outputFile: value.output,
+      }),
+    /is not the canonical/u,
+  );
+
+  const duplicate = fixture(context);
+  writeFileSync(
+    duplicate.manifest,
+    `${readFileSync(duplicate.manifest, 'utf8')}\n${duplicate.binaryTarget}\n`,
+  );
+  assert.throws(
+    () =>
+      localizeSwiftReleaseManifest({
+        manifestFile: duplicate.manifest,
+        assetFile: duplicate.asset,
+        outputFile: duplicate.output,
+      }),
+    /exactly one .* found 2/u,
+  );
+});
diff --git a/src/sdks/swift/tools/render-extension-products.mjs b/src/sdks/swift/tools/render-extension-products.mjs
deleted file mode 100755
index f11f6342b..000000000
--- a/src/sdks/swift/tools/render-extension-products.mjs
+++ /dev/null
@@ -1,1243 +0,0 @@
-#!/usr/bin/env node
-
-import fs from "node:fs/promises";
-import os from "node:os";
-import path from "node:path";
-import { fileURLToPath } from "node:url";
-
-import { resolveSwiftCarrierSelection } from "./swift-carrier-resolver.mjs";
-import {
-  loadSwiftExtensionInventoryCatalog,
-  readSafeFileSnapshot,
-  snapshotSafeFileTree,
-  validateSwiftExtensionResourceArtifact,
-} from "./extension-resource-inventory.mjs";
-
-const PREFIX = "render-extension-products.mjs";
-const SELECTION_SCHEMA = "oliphaunt-swiftpm-extension-selection-v1";
-const OUTPUT_SCHEMA = "oliphaunt-swiftpm-extension-products-v1";
-const NATIVE_RUNTIME_PRODUCT = "liboliphaunt-native";
-const OUTPUT_OWNER_MARKER = ".oliphaunt-swiftpm-extension-products";
-const OUTPUT_OWNER_MARKER_CONTENT = `${PREFIX}\n${OUTPUT_SCHEMA}\n`;
-const MAX_XCFRAMEWORK_FILES = 32768;
-const MAX_XCFRAMEWORK_FILE_BYTES = 512 * 1024 * 1024;
-const MAX_XCFRAMEWORK_TREE_BYTES = 2 * 1024 * 1024 * 1024;
-const DEFAULT_CARRIER = path.resolve(
-  path.dirname(fileURLToPath(import.meta.url)),
-  "../Carriers/oliphaunt-react-native-ios-carriers.json",
-);
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function fail(message) {
-  throw new Error(`${PREFIX}: ${message}`);
-}
-
-function usage() {
-  console.error(
-    `usage: ${PREFIX} [--carrier ] ` +
-      `[--extension-carrier  ...] --extensions  ` +
-      `--output-dir  [--cache-dir ] [--offline] [--allow-file-urls] ` +
-      `[--local-binary-targets] ` +
-      `[--base-package-url ] [--base-package-version ] ` +
-      `[--base-package-path ]`,
-  );
-}
-
-function parseArgs(argv) {
-  const args = { allowFileUrls: false, extensionCarriers: [], localBinaryTargets: false, offline: false };
-  for (let index = 0; index < argv.length; index += 1) {
-    const arg = argv[index];
-    if (arg === "--help" || arg === "-h") {
-      usage();
-      process.exit(0);
-    }
-    if (arg === "--allow-file-urls" || arg === "--local-binary-targets" || arg === "--offline") {
-      if (arg === "--allow-file-urls") args.allowFileUrls = true;
-      else if (arg === "--local-binary-targets") args.localBinaryTargets = true;
-      else args.offline = true;
-      continue;
-    }
-    if (!["--carrier", "--extension-carrier", "--extensions", "--cache-dir", "--output-dir", "--base-package-path", "--base-package-url", "--base-package-version"].includes(arg)) {
-      usage();
-      fail(`unknown argument ${arg}`);
-    }
-    const value = argv[index + 1];
-    if (value === undefined || value.startsWith("--")) {
-      fail(`${arg} requires a value`);
-    }
-    index += 1;
-    if (arg === "--carrier") args.carrier = value;
-    if (arg === "--extension-carrier") args.extensionCarriers.push(value);
-    if (arg === "--extensions") args.extensions = value.split(",").map((row) => row.trim()).filter(Boolean);
-    if (arg === "--cache-dir") args.cacheDir = path.resolve(value);
-    if (arg === "--output-dir") args.outputDir = value;
-    if (arg === "--base-package-path") args.basePackagePath = path.resolve(value);
-    if (arg === "--base-package-url") args.basePackageUrl = value;
-    if (arg === "--base-package-version") args.basePackageVersion = value;
-  }
-  if (!args.outputDir || !args.extensions?.length) {
-    usage();
-    fail("provide --extensions and --output-dir; carrier options are optional");
-  }
-  if (!args.carrier) args.carrier = DEFAULT_CARRIER;
-  return args;
-}
-
-function object(value, label) {
-  if (value === null || Array.isArray(value) || typeof value !== "object") {
-    fail(`${label} must be an object`);
-  }
-  return value;
-}
-
-function exactKeys(value, allowed, label) {
-  const extras = Object.keys(value).filter((key) => !allowed.includes(key)).sort();
-  if (extras.length > 0) {
-    fail(`${label} contains unsupported field(s): ${extras.join(", ")}`);
-  }
-}
-
-function portable(value, label) {
-  if (typeof value !== "string" || !/^[A-Za-z0-9._-]+$/u.test(value)) {
-    fail(`${label} must contain only ASCII letters, digits, '.', '_' or '-'`);
-  }
-  return value;
-}
-
-function cIdentifier(value, label) {
-  if (typeof value !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(value)) {
-    fail(`${label} must be a C identifier`);
-  }
-  return value;
-}
-
-function uniquePortableList(value, label) {
-  if (!Array.isArray(value)) {
-    fail(`${label} must be an array`);
-  }
-  const items = value.map((item, index) => portable(item, `${label}[${index}]`));
-  if (new Set(items).size !== items.length) {
-    fail(`${label} must not contain duplicates`);
-  }
-  const canonical = [...items].sort(compareText);
-  if (JSON.stringify(items) !== JSON.stringify(canonical)) {
-    fail(`${label} must be sorted in ordinal order`);
-  }
-  return items;
-}
-
-function frozenDataFiles(value, label) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((item, index) => {
-    if (
-      typeof item !== "string" || item.length === 0 || item.includes("\\") || item.startsWith("/")
-      || /^[A-Za-z]:/u.test(item) || item.split("/").some((part) => !part || part === "." || part === "..")
-    ) {
-      fail(`${label}[${index}] must be a safe canonical relative file path`);
-    }
-    return item;
-  });
-  const canonical = [...rows].sort(compareText);
-  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
-  if (JSON.stringify(rows) !== JSON.stringify(canonical)) fail(`${label} must be sorted in ordinal order`);
-  return rows;
-}
-
-function frozenSqlFileNames(value, label) {
-  const rows = uniquePortableList(value, label);
-  if (rows.some((name) => !name.endsWith(".sql"))) fail(`${label} must contain SQL basenames`);
-  return rows;
-}
-
-function frozenSqlFilePrefixes(value, label) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((item, index) => {
-    if (typeof item !== "string" || !/^[A-Za-z0-9_-]{1,128}$/u.test(item)) {
-      fail(`${label}[${index}] must be a dot-free portable SQL basename prefix`);
-    }
-    return item;
-  });
-  const canonical = [...rows].sort(compareText);
-  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
-  if (JSON.stringify(rows) !== JSON.stringify(canonical)) fail(`${label} must be sorted in ordinal order`);
-  return rows;
-}
-
-function nullablePortable(value, label) {
-  if (value === null) {
-    return null;
-  }
-  return portable(value, label);
-}
-
-function localResourceRoot(value, label) {
-  if (typeof value !== "string" || value.trim().length === 0 || value.includes("\0")) {
-    fail(`${label} must be a non-empty local directory path`);
-  }
-  return value;
-}
-
-function semanticVersion(value, label) {
-  if (
-    typeof value !== "string" ||
-    !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u.test(value)
-  ) {
-    fail(`${label} must be a semantic version accepted by SwiftPM`);
-  }
-  return value;
-}
-
-function stableSemanticVersion(value, label) {
-  if (
-    typeof value !== "string" ||
-    !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(value)
-  ) {
-    fail(`${label} must be a stable semantic version in X.Y.Z form`);
-  }
-  return value;
-}
-
-function validateBasePackage(value) {
-  const base = object(value, "basePackage");
-  exactKeys(base, ["name", "url", "version"], "basePackage");
-  if (base.name !== "Oliphaunt") {
-    fail("basePackage.name must be Oliphaunt");
-  }
-  if (typeof base.url !== "string") {
-    fail("basePackage.url must be an HTTPS Git URL");
-  }
-  let url;
-  try {
-    url = new URL(base.url);
-  } catch {
-    fail("basePackage.url must be a valid HTTPS Git URL");
-  }
-  if (url.protocol !== "https:" || !url.pathname.endsWith(".git")) {
-    fail("basePackage.url must be an HTTPS Git URL ending in .git");
-  }
-  return {
-    name: base.name,
-    url: base.url,
-    version: semanticVersion(base.version, "basePackage.version"),
-  };
-}
-
-function validateNativeRuntime(value) {
-  const runtime = object(value, "nativeRuntime");
-  exactKeys(runtime, ["product", "version"], "nativeRuntime");
-  if (runtime.product !== NATIVE_RUNTIME_PRODUCT) {
-    fail(`nativeRuntime.product must be ${NATIVE_RUNTIME_PRODUCT}`);
-  }
-  return {
-    product: runtime.product,
-    version: stableSemanticVersion(runtime.version, "nativeRuntime.version"),
-  };
-}
-
-function swiftSuffix(sqlName) {
-  const words = sqlName.split(/[^A-Za-z0-9]+/u).filter(Boolean);
-  if (words.length === 0) {
-    fail(`cannot derive a Swift product name from ${sqlName}`);
-  }
-  const suffix = words
-    .map((word) => `${word[0].toUpperCase()}${word.slice(1)}`)
-    .join("");
-  if (!/^[A-Za-z][A-Za-z0-9]*$/u.test(suffix)) {
-    fail(`cannot derive a Swift identifier from ${sqlName}`);
-  }
-  return suffix;
-}
-
-function swiftString(value) {
-  return JSON.stringify(value);
-}
-
-function expectedSymbolPrefix(stem) {
-  return `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`;
-}
-
-function validateAsset(value, label, allowFileUrls = false, localBinaryTargets = false) {
-  const asset = object(value, label);
-  exactKeys(asset, ["checksum", "localPath", "name", "url"], label);
-  if (
-    typeof asset.name !== "string"
-    || asset.name.length === 0
-    || path.posix.basename(asset.name) !== asset.name
-    || /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(asset.name)
-    || /[ .]$/u.test(asset.name)
-    || /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(asset.name)
-  ) {
-    fail(`${label}.name must be a plain release asset file name`);
-  }
-  if (typeof asset.url !== "string") {
-    fail(`${label}.url must be an HTTPS URL`);
-  }
-  let url;
-  try {
-    url = new URL(asset.url);
-  } catch {
-    fail(`${label}.url must be a valid HTTPS URL`);
-  }
-  if (
-    (url.protocol !== "https:" && !(allowFileUrls && url.protocol === "file:")) ||
-    decodeURIComponent(path.basename(url.pathname)) !== asset.name
-  ) {
-    fail(`${label}.url must be HTTPS${allowFileUrls ? " or an explicitly enabled file URL" : ""} and end with ${asset.name}`);
-  }
-  if (typeof asset.checksum !== "string" || !/^[a-f0-9]{64}$/u.test(asset.checksum)) {
-    fail(`${label}.checksum must be a lowercase SHA-256 digest`);
-  }
-  let localPath;
-  if (localBinaryTargets || asset.localPath !== undefined) {
-    if (
-      typeof asset.localPath !== "string" ||
-      !path.isAbsolute(asset.localPath) ||
-      path.extname(asset.localPath) !== ".xcframework"
-    ) {
-      fail(`${label}.localPath must be an absolute XCFramework directory path`);
-    }
-    localPath = path.normalize(asset.localPath);
-  }
-  return {
-    checksum: asset.checksum,
-    name: asset.name,
-    url: asset.url,
-    ...(localPath === undefined ? {} : { localPath }),
-  };
-}
-
-function validateRegistration(value, stem, label) {
-  const registration = object(value, label);
-  exactKeys(registration, ["hasInit", "symbols"], label);
-  if (typeof registration.hasInit !== "boolean") {
-    fail(`${label}.hasInit must be a boolean`);
-  }
-  if (!Array.isArray(registration.symbols)) {
-    fail(`${label}.symbols must be an array derived from the built extension archive`);
-  }
-  const symbols = registration.symbols.map((raw, index) => {
-    const symbol = object(raw, `${label}.symbols[${index}]`);
-    exactKeys(symbol, ["address", "name"], `${label}.symbols[${index}]`);
-    return {
-      address: cIdentifier(symbol.address, `${label}.symbols[${index}].address`),
-      name: cIdentifier(symbol.name, `${label}.symbols[${index}].name`),
-    };
-  });
-  const names = symbols.map(({ name }) => name);
-  if (new Set(names).size !== names.length) {
-    fail(`${label}.symbols repeats a SQL-visible symbol name`);
-  }
-  symbols.sort((left, right) =>
-    compareText(`${left.name}\0${left.address}`, `${right.name}\0${right.address}`),
-  );
-  const symbolPrefix = expectedSymbolPrefix(stem);
-  return {
-    hasInit: registration.hasInit,
-    initSymbol: registration.hasInit ? `${symbolPrefix}__PG_init` : undefined,
-    magicSymbol: `${symbolPrefix}_Pg_magic_func`,
-    symbolPrefix,
-    symbols,
-  };
-}
-
-function validateNativeDependencies(
-  value,
-  label,
-  allowFileUrls = false,
-  localBinaryTargets = false,
-) {
-  if (!Array.isArray(value)) {
-    fail(`${label} must be an array of separately checksum-pinned XCFramework assets`);
-  }
-  const dependencies = value.map((raw, index) => {
-    const dependency = object(raw, `${label}[${index}]`);
-    exactKeys(dependency, ["asset", "name"], `${label}[${index}]`);
-    const name = portable(dependency.name, `${label}[${index}].name`);
-    return {
-      asset: validateAsset(
-        dependency.asset,
-        `${label}[${index}].asset`,
-        allowFileUrls,
-        localBinaryTargets,
-      ),
-      binaryTarget: `OliphauntNativeDependency${swiftSuffix(name)}`,
-      name,
-    };
-  });
-  dependencies.sort((left, right) => compareText(left.name, right.name));
-  if (new Set(dependencies.map(({ name }) => name)).size !== dependencies.length) {
-    fail(`${label} repeats a native dependency name`);
-  }
-  return dependencies;
-}
-
-export function validateSelection(
-  input,
-  inputDirectory,
-  { allowFileUrls = false, localBinaryTargets = false } = {},
-) {
-  const root = object(input, "input");
-  exactKeys(root, ["basePackage", "extensions", "nativeRuntime", "schema"], "input");
-  if (root.schema !== SELECTION_SCHEMA) {
-    fail(`input schema must be ${SELECTION_SCHEMA}`);
-  }
-  if (!Array.isArray(root.extensions) || root.extensions.length === 0) {
-    fail("input extensions must be a non-empty selected extension array");
-  }
-  const basePackage = validateBasePackage(root.basePackage);
-  const nativeRuntime = validateNativeRuntime(root.nativeRuntime);
-  const extensions = root.extensions.map((raw, index) => {
-    const row = object(raw, `extensions[${index}]`);
-    exactKeys(
-      row,
-      [
-        "asset",
-        "createsExtension",
-        "dataFiles",
-        "dependencies",
-        "extensionSqlFileNames",
-        "extensionSqlFilePrefixes",
-        "nativeModuleStem",
-        "nativeDependencies",
-        "product",
-        "registration",
-        "releaseProduct",
-        "resourceRoot",
-        "sharedPreloadLibraries",
-        "sqlName",
-        "version",
-      ],
-      `extensions[${index}]`,
-    );
-    const sqlName = portable(row.sqlName, `extensions[${index}].sqlName`);
-    const product = portable(row.product, `extensions[${index}].product`);
-    if (!product.startsWith("oliphaunt-extension-")) {
-      fail(`extensions[${index}].product must be an exact-extension artifact product; got ${product}`);
-    }
-    const releaseProduct = portable(
-      row.releaseProduct,
-      `extensions[${index}].releaseProduct`,
-    );
-    const nativeModuleStem = nullablePortable(
-      row.nativeModuleStem,
-      `extensions[${index}].nativeModuleStem`,
-    );
-    if (typeof row.createsExtension !== "boolean") {
-      fail(`extensions[${index}].createsExtension must be boolean`);
-    }
-    const cModuleStem = nativeModuleStem?.replaceAll(/[^A-Za-z0-9_]/gu, "_");
-    const suffix = swiftSuffix(sqlName);
-    if (nativeModuleStem === null && row.registration !== null) {
-      fail(`extensions[${index}] SQL-only extension must use null registration metadata`);
-    }
-    const asset = row.asset === null
-      ? null
-      : validateAsset(
-          row.asset,
-          `extensions[${index}].asset`,
-          allowFileUrls,
-          localBinaryTargets,
-        );
-    const registration =
-      row.registration === null
-        ? null
-        : validateRegistration(
-            row.registration,
-            nativeModuleStem,
-            `extensions[${index}].registration`,
-          );
-    const nativeDependencies = validateNativeDependencies(
-      row.nativeDependencies,
-      `extensions[${index}].nativeDependencies`,
-      allowFileUrls,
-      localBinaryTargets,
-    );
-    if (nativeModuleStem === null) {
-      if (asset !== null || registration !== null || nativeDependencies.length > 0) {
-        fail(
-          `extensions[${index}] is SQL-only and must use null asset/registration with no nativeDependencies`,
-        );
-      }
-    } else if (asset === null || registration === null) {
-      fail(`extensions[${index}] native extension requires asset and registration metadata`);
-    }
-    const dependencies = uniquePortableList(
-      row.dependencies,
-      `extensions[${index}].dependencies`,
-    );
-    if (dependencies.includes(sqlName)) {
-      fail(`extensions[${index}].dependencies must not include ${sqlName} itself`);
-    }
-    return {
-      asset,
-      binaryTarget: nativeModuleStem === null ? null : `OliphauntExtension${suffix}Binary`,
-      cFunction: nativeModuleStem === null ? null : `oliphaunt_extension_${cModuleStem}_descriptor`,
-      cTarget: nativeModuleStem === null ? null : `COliphauntExtension${suffix}`,
-      createsExtension: row.createsExtension,
-      dataFiles: frozenDataFiles(row.dataFiles, `extensions[${index}].dataFiles`),
-      dependencies,
-      extensionSqlFileNames: frozenSqlFileNames(
-        row.extensionSqlFileNames,
-        `extensions[${index}].extensionSqlFileNames`,
-      ),
-      extensionSqlFilePrefixes: frozenSqlFilePrefixes(
-        row.extensionSqlFilePrefixes,
-        `extensions[${index}].extensionSqlFilePrefixes`,
-      ),
-      nativeDependencies,
-      nativeModuleStem,
-      product,
-      releaseProduct,
-      registration,
-      resourceRoot: path.resolve(
-        inputDirectory,
-        localResourceRoot(row.resourceRoot, `extensions[${index}].resourceRoot`),
-      ),
-      sharedPreloadLibraries: uniquePortableList(
-        row.sharedPreloadLibraries,
-        `extensions[${index}].sharedPreloadLibraries`,
-      ),
-      sqlName,
-      swiftTarget: `OliphauntExtension${suffix}`,
-      version: stableSemanticVersion(row.version, `extensions[${index}].version`),
-    };
-  });
-  extensions.sort((left, right) => compareText(left.sqlName, right.sqlName));
-  const bySqlName = new Map();
-  const targetNames = new Set();
-  const nativeDependencies = new Map();
-  for (const extension of extensions) {
-    if (bySqlName.has(extension.sqlName)) {
-      fail(`selected extension ${extension.sqlName} is duplicated`);
-    }
-    bySqlName.set(extension.sqlName, extension);
-    for (const name of [extension.binaryTarget, extension.cTarget, extension.swiftTarget].filter(Boolean)) {
-      if (targetNames.has(name)) {
-        fail(`generated SwiftPM target name collision: ${name}`);
-      }
-      targetNames.add(name);
-    }
-    for (const dependency of extension.nativeDependencies) {
-      const existing = nativeDependencies.get(dependency.name);
-      if (existing !== undefined) {
-        if (JSON.stringify(existing.asset) !== JSON.stringify(dependency.asset)) {
-          fail(
-            `selected extensions require conflicting ${dependency.name} native dependency assets`,
-          );
-        }
-      } else {
-        nativeDependencies.set(dependency.name, dependency);
-      }
-    }
-  }
-  for (const dependency of nativeDependencies.values()) {
-    if (targetNames.has(dependency.binaryTarget)) {
-      fail(`generated SwiftPM target name collision: ${dependency.binaryTarget}`);
-    }
-    targetNames.add(dependency.binaryTarget);
-  }
-  for (const extension of extensions) {
-    for (const dependency of extension.dependencies) {
-      if (!bySqlName.has(dependency)) {
-        fail(`${extension.sqlName} dependency ${dependency} is not present in the selected input`);
-      }
-    }
-  }
-  const visiting = new Set();
-  const visited = new Set();
-  function visit(sqlName) {
-    if (visiting.has(sqlName)) fail(`selected extension dependency cycle includes ${sqlName}`);
-    if (visited.has(sqlName)) return;
-    visiting.add(sqlName);
-    for (const dependency of bySqlName.get(sqlName).dependencies) visit(dependency);
-    visiting.delete(sqlName);
-    visited.add(sqlName);
-  }
-  for (const extension of extensions) visit(extension.sqlName);
-  return {
-    basePackage,
-    bySqlName,
-    extensions,
-    nativeRuntime,
-    nativeDependencies: [...nativeDependencies.values()].sort((left, right) =>
-      compareText(left.name, right.name),
-    ),
-  };
-}
-
-function snapshotRows(files, { includeIdentity = false, mode = undefined } = {}) {
-  return files.map((file) => ({
-    bytes: file.bytes,
-    ...(includeIdentity ? { device: file.device, inode: file.inode } : {}),
-    mode: mode ?? file.mode,
-    relative: file.relative,
-    sha256: file.sha256,
-  }));
-}
-
-function snapshotDirectoryRows(
-  directories,
-  { includeIdentity = false } = {},
-) {
-  return directories.map((directory) => ({
-    ...(includeIdentity
-      ? { device: directory.device, inode: directory.inode }
-      : {}),
-    mode: directory.mode,
-    relative: directory.relative,
-  }));
-}
-
-function assertSnapshotRowsEqual(expected, actual, label, options = {}) {
-  const filesChanged = (
-    JSON.stringify(snapshotRows(expected, options))
-    !== JSON.stringify(snapshotRows(actual, { includeIdentity: options.includeIdentity }))
-  );
-  const directoriesChanged = options.includeDirectories === true && (
-    JSON.stringify(snapshotDirectoryRows(
-      options.expectedDirectories ?? expected.directories ?? [],
-      options,
-    ))
-    !== JSON.stringify(snapshotDirectoryRows(actual.directories ?? [], options))
-  );
-  if (filesChanged || directoriesChanged) {
-    fail(`${label} tree inventory changed`);
-  }
-}
-
-function safeSnapshotRelativePath(value, label) {
-  if (
-    typeof value !== "string"
-    || value.length === 0
-    || value.includes("\\")
-    || value.startsWith("/")
-    || /^[A-Za-z]:/u.test(value)
-    || value.split("/").some((part) => !part || part === "." || part === "..")
-  ) {
-    fail(`${label} contains unsafe snapshot path ${JSON.stringify(value)}`);
-  }
-  return value;
-}
-
-export async function materializeFileSnapshots(
-  files,
-  destinationRoot,
-  label,
-  { mode = undefined } = {},
-) {
-  if (!Array.isArray(files)) {
-    fail(`${label} must be an array of validated file snapshots`);
-  }
-  if ((await lstatIfPresent(destinationRoot)) !== null) {
-    fail(`${label} destination already exists: ${destinationRoot}`);
-  }
-  await fs.mkdir(destinationRoot, { recursive: true, mode: 0o755 });
-  const preserveDirectories = Object.hasOwn(files, "directories");
-  const directories = preserveDirectories ? files.directories : [];
-  for (const directory of [...directories].sort((left, right) => {
-    const depth = left.relative.split("/").length - right.relative.split("/").length;
-    return depth === 0 ? compareText(left.relative, right.relative) : depth;
-  })) {
-    const relative = safeSnapshotRelativePath(directory.relative, label);
-    const destination = path.join(destinationRoot, ...relative.split("/"));
-    await fs.mkdir(destination, { recursive: true, mode: directory.mode });
-    await fs.chmod(destination, directory.mode);
-  }
-  for (const file of files) {
-    const relative = safeSnapshotRelativePath(file.relative, label);
-    const destination = path.join(destinationRoot, ...relative.split("/"));
-    await fs.mkdir(path.dirname(destination), { recursive: true, mode: 0o755 });
-    const contents = await readSafeFileSnapshot(file, `${label} source ${relative}`);
-    const fileMode = mode ?? file.mode;
-    await fs.writeFile(destination, contents, { flag: "wx", mode: fileMode });
-    await fs.chmod(destination, fileMode);
-  }
-  const expectedBytes = files.reduce((sum, file) => sum + file.bytes, 0);
-  const staged = await snapshotSafeFileTree(destinationRoot, `${label} staged copy`, {
-    maxFiles: Math.max(files.length, 1),
-    maxFileBytes: Math.max(...files.map(({ bytes }) => bytes), 1),
-    maxTreeBytes: Math.max(expectedBytes, 1),
-  });
-  assertSnapshotRowsEqual(files, staged, `${label} staged copy`, {
-    expectedDirectories: directories,
-    includeDirectories: preserveDirectories,
-    mode,
-  });
-}
-
-async function copyResourceArtifact(extension, swiftRoot) {
-  const resourceTarget = path.join(swiftRoot, "Resources", "extension-artifact");
-  const shareTarget = path.join(resourceTarget, "files", "share", "postgresql");
-  await materializeFileSnapshots(
-    extension.resources.files,
-    shareTarget,
-    `${extension.sqlName} Swift resource artifact`,
-    { mode: 0o644 },
-  );
-  const manifest = [
-    "schema=oliphaunt-swift-extension-resource-v1",
-    `product=${extension.product}`,
-    `version=${extension.version}`,
-    `sqlName=${extension.sqlName}`,
-    `createsExtension=${extension.resources.createsExtension ? "yes" : "no"}`,
-    `dependencies=${extension.dependencies.join(",")}`,
-    `nativeModuleStem=${extension.nativeModuleStem ?? ""}`,
-    `nativeDependencies=${extension.nativeDependencies.map(({ name }) => name).join(",")}`,
-    `sharedPreloadLibraries=${extension.sharedPreloadLibraries.join(",")}`,
-    "files=files",
-    "",
-  ].join("\n");
-  await fs.writeFile(path.join(resourceTarget, "manifest.properties"), manifest);
-}
-
-function renderHeader(extension) {
-  const guard = `${extension.cTarget.replaceAll(/[^A-Za-z0-9]/gu, "_").toUpperCase()}_H`;
-  return `#ifndef ${guard}\n#define ${guard}\n\n#include "COliphaunt.h"\n\n` +
-    `const OliphauntStaticExtension *${extension.cFunction}(void);\n\n#endif\n`;
-}
-
-function renderC(extension) {
-  const registration = extension.registration;
-  const externs = new Set([
-    `extern const void *${registration.magicSymbol}(void);`,
-    ...(registration.initSymbol ? [`extern void ${registration.initSymbol}(void);`] : []),
-    ...registration.symbols.map(({ address }) => `extern void ${address}(void);`),
-  ]);
-  const symbols = registration.symbols.length
-    ? `static const OliphauntStaticExtensionSymbol extension_symbols[] = {\n${registration.symbols
-        .map(
-          ({ name, address }) =>
-            `    { .name = ${JSON.stringify(name)}, .address = (void *)${address} },`,
-        )
-        .join("\n")}\n};\n\n`
-    : "";
-  const symbolPointer = registration.symbols.length ? "extension_symbols" : "NULL";
-  const symbolCount = registration.symbols.length
-    ? "sizeof(extension_symbols) / sizeof(extension_symbols[0])"
-    : "0";
-  return `/* Generated by ${PREFIX}. Do not edit. */\n` +
-    `#include "${extension.cTarget}.h"\n\n${[...externs].sort().join("\n")}\n\n${symbols}` +
-    `static const OliphauntStaticExtension extension_descriptor = {\n` +
-    `    .abi_version = OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION,\n` +
-    `    .name = ${JSON.stringify(extension.nativeModuleStem)},\n` +
-    `    .magic = ${registration.magicSymbol},\n` +
-    `    .init = ${registration.initSymbol ?? "NULL"},\n` +
-    `    .symbols = ${symbolPointer},\n` +
-    `    .symbol_count = ${symbolCount},\n` +
-    `    .reserved_flags = 0,\n};\n\n` +
-    `const OliphauntStaticExtension *${extension.cFunction}(void) {\n` +
-    `    return &extension_descriptor;\n}\n`;
-}
-
-function renderSwift(extension, bySqlName) {
-  const dependencyImports = extension.dependencies
-    .map((dependency) => `import ${bySqlName.get(dependency).swiftTarget}`)
-    .join("\n");
-  const dependencyRegistrations = extension.dependencies
-    .map((dependency) => `        try ${bySqlName.get(dependency).swiftTarget}.register()`)
-    .join("\n");
-  const cImport = extension.cTarget ? `import ${extension.cTarget}\nimport COliphaunt\n` : "";
-  const descriptor = extension.cFunction
-    ? `        guard let descriptor = ${extension.cFunction}() else {\n` +
-      `            throw OliphauntError.engine("${extension.sqlName} static-extension descriptor is unavailable")\n` +
-      `        }\n`
-    : "";
-  return `${cImport}import Foundation\nimport Oliphaunt\nimport OliphauntExtensionSupport` +
-    `${dependencyImports ? `\n${dependencyImports}` : ""}\n\n` +
-    `public enum ${extension.swiftTarget} {\n` +
-    `    public static let product = ${swiftString(extension.product)}\n` +
-    `    public static let releaseProduct = ${swiftString(extension.releaseProduct)}\n` +
-    `    public static let sqlName = ${swiftString(extension.sqlName)}\n` +
-    `    public static let version = ${swiftString(extension.version)}\n` +
-    `    public static let dependencies: [String] = [${extension.dependencies.map(swiftString).join(", ")}]\n\n` +
-    `    public static let nativeDependencies: [String] = [${extension.nativeDependencies.map(({ name }) => swiftString(name)).join(", ")}]\n\n` +
-    `    public static let sharedPreloadLibraries: [String] = [${extension.sharedPreloadLibraries.map(swiftString).join(", ")}]\n\n` +
-    `    public static func register() throws {\n` +
-    `${dependencyRegistrations ? `${dependencyRegistrations}\n` : ""}` +
-    `        guard let resourceRoot = Bundle.module.url(forResource: "extension-artifact", withExtension: nil) else {\n` +
-    `            throw OliphauntError.engine("${extension.sqlName} SwiftPM resource fragment is unavailable")\n` +
-    `        }\n` +
-    descriptor +
-    `        try OliphauntExtensionSupport.register(\n` +
-    `            product: product,\n` +
-    `            sqlName: sqlName,\n` +
-    `            version: version,\n` +
-    `            dependencies: dependencies,\n` +
-    `            nativeDependencies: nativeDependencies,\n` +
-    `            sharedPreloadLibraries: sharedPreloadLibraries,\n` +
-    `            nativeModuleStem: ${extension.nativeModuleStem === null ? "nil" : swiftString(extension.nativeModuleStem)},\n` +
-    `            resourceRoot: resourceRoot,\n` +
-    `            descriptor: ${extension.cFunction ? "descriptor" : "nil"}\n` +
-    `        )\n` +
-    `    }\n}\n`;
-}
-
-function baseProduct(name) {
-  return { package: "oliphaunt", product: name };
-}
-
-function binaryTargetIR(name, asset, localBinaryTargets) {
-  return localBinaryTargets || asset.localPath !== undefined
-    ? {
-        kind: "binaryTarget",
-        name,
-        path: `Artifacts/${name}.xcframework`,
-      }
-    : {
-        checksum: asset.checksum,
-        kind: "binaryTarget",
-        name,
-        url: asset.url,
-      };
-}
-
-function targetIR(extension, bySqlName, localBinaryTargets) {
-  const swiftPath = `Sources/${extension.swiftTarget}`;
-  const targets = [];
-  if (extension.nativeModuleStem !== null) {
-    const nativeDependencyNames = new Set(
-      extension.nativeDependencies.map(({ name }) => name),
-    );
-    const linkedLibraries = ["geos", "geos-c", "proj"].some((name) => nativeDependencyNames.has(name))
-      ? ["c++"]
-      : [];
-    targets.push(
-      binaryTargetIR(extension.binaryTarget, extension.asset, localBinaryTargets),
-      {
-        dependencies: [
-          baseProduct("COliphaunt"),
-          extension.binaryTarget,
-          ...extension.nativeDependencies.map(({ binaryTarget }) => binaryTarget),
-        ],
-        kind: "target",
-        linkedLibraries,
-        name: extension.cTarget,
-        path: `Sources/${extension.cTarget}`,
-        publicHeadersPath: "include",
-      },
-    );
-  }
-  targets.push({
-    dependencies: [
-      ...(extension.cTarget ? [baseProduct("COliphaunt")] : []),
-      baseProduct("Oliphaunt"),
-      baseProduct("OliphauntExtensionSupport"),
-      ...(extension.cTarget ? [extension.cTarget] : []),
-      ...extension.dependencies.map((dependency) => bySqlName.get(dependency).swiftTarget),
-    ],
-    kind: "target",
-    name: extension.swiftTarget,
-    path: swiftPath,
-    resources: [{ path: "Resources/extension-artifact", rule: "copy" }],
-  });
-  return targets;
-}
-
-function renderTargetDependency(dependency) {
-  if (typeof dependency === "string") {
-    return swiftString(dependency);
-  }
-  return `.product(name: ${swiftString(dependency.product)}, package: ${swiftString(dependency.package)})`;
-}
-
-function renderPackage(manifest, basePackagePath) {
-  const products = manifest.products
-    .map(
-      (product) =>
-        `    .library(name: ${swiftString(product.name)}, targets: [${product.targets
-          .map(swiftString)
-          .join(", ")}])`,
-    )
-    .join(",\n");
-  const targets = manifest.targets
-    .map((target) => {
-      if (target.kind === "binaryTarget") {
-        if (target.path !== undefined) {
-          return `    .binaryTarget(\n        name: ${swiftString(target.name)},\n        path: ${swiftString(target.path)}\n    )`;
-        }
-        return `    .binaryTarget(\n        name: ${swiftString(target.name)},\n        url: ${swiftString(target.url)},\n        checksum: ${swiftString(target.checksum)}\n    )`;
-      }
-      const headers = target.publicHeadersPath
-        ? `,\n        publicHeadersPath: ${swiftString(target.publicHeadersPath)}`
-        : "";
-      const resources = target.resources
-        ? `,\n        resources: [${target.resources
-            .map((resource) => `.${resource.rule}(${swiftString(resource.path)})`)
-            .join(", ")}]`
-        : "";
-      const linkerSettings = target.linkedLibraries?.length
-        ? `,\n        linkerSettings: [${target.linkedLibraries
-            .map((library) => `.linkedLibrary(${swiftString(library)})`)
-            .join(", ")}]`
-        : "";
-      return `    .target(\n        name: ${swiftString(target.name)},\n        dependencies: [${target.dependencies
-        .map(renderTargetDependency)
-        .join(", ")}],\n        path: ${swiftString(target.path)}${headers}${resources}${linkerSettings}\n    )`;
-    })
-    .join(",\n");
-  const baseDependency = basePackagePath
-    ? `.package(name: "oliphaunt", path: ${swiftString(basePackagePath)})`
-    : `.package(\n            url: ${swiftString(manifest.basePackage.url)},\n            exact: ${swiftString(manifest.basePackage.version)}\n        )`;
-  return `// swift-tools-version: 6.0\n\n` +
-    `import PackageDescription\n\n` +
-    `// Generated by ${PREFIX}. Do not edit. This local package belongs to the\n` +
-    `// consuming application; exact-extension assets remain separately released.\n` +
-    `let package = Package(\n` +
-    `    name: "OliphauntSelectedExtensions",\n` +
-    `    platforms: [.iOS(.v17), .macOS(.v14)],\n` +
-    `    products: [\n${products}\n    ],\n` +
-    `    dependencies: [\n        ${baseDependency}\n    ],\n` +
-    `    targets: [\n${targets}\n    ]\n` +
-    `)\n`;
-}
-
-async function copyLocalBinaryArtifact(asset, targetName, outputDir) {
-  const source = asset.localPath;
-  const sourceStat = await fs.lstat(source).catch(() => null);
-  if (sourceStat?.isDirectory() !== true || sourceStat.isSymbolicLink()) {
-    fail(`local binary target ${targetName} is not a real XCFramework directory: ${source}`);
-  }
-  const label = `local binary target ${targetName}`;
-  const sourceFiles = await snapshotSafeFileTree(source, label, {
-    maxFiles: MAX_XCFRAMEWORK_FILES,
-    maxFileBytes: MAX_XCFRAMEWORK_FILE_BYTES,
-    maxTreeBytes: MAX_XCFRAMEWORK_TREE_BYTES,
-  });
-  if (!sourceFiles.some(({ relative }) => relative === "Info.plist")) {
-    fail(`${label} is missing Info.plist: ${source}`);
-  }
-  const destination = path.join(outputDir, "Artifacts", `${targetName}.xcframework`);
-  await fs.mkdir(path.dirname(destination), { recursive: true });
-  await materializeFileSnapshots(sourceFiles, destination, label);
-  const sourceAfterCopy = await snapshotSafeFileTree(source, `${label} post-copy source`, {
-    maxFiles: MAX_XCFRAMEWORK_FILES,
-    maxFileBytes: MAX_XCFRAMEWORK_FILE_BYTES,
-    maxTreeBytes: MAX_XCFRAMEWORK_TREE_BYTES,
-  });
-  assertSnapshotRowsEqual(sourceFiles, sourceAfterCopy, `${label} source`, {
-    includeDirectories: true,
-    includeIdentity: true,
-  });
-}
-
-async function writeGeneratedTree(selection, outputDir, basePackagePath, localBinaryTargets) {
-  const products = [];
-  const targets = [];
-  const selected = [];
-  for (const dependency of selection.nativeDependencies) {
-    if (localBinaryTargets || dependency.asset.localPath !== undefined) {
-      await copyLocalBinaryArtifact(dependency.asset, dependency.binaryTarget, outputDir);
-    }
-    targets.push(binaryTargetIR(dependency.binaryTarget, dependency.asset, localBinaryTargets));
-  }
-  for (const extension of selection.extensions) {
-    const swiftRoot = path.join(outputDir, "Sources", extension.swiftTarget);
-    if (extension.cTarget) {
-      if (localBinaryTargets || extension.asset.localPath !== undefined) {
-        await copyLocalBinaryArtifact(extension.asset, extension.binaryTarget, outputDir);
-      }
-      const cRoot = path.join(outputDir, "Sources", extension.cTarget);
-      await fs.mkdir(path.join(cRoot, "include"), { recursive: true });
-      await fs.writeFile(
-        path.join(cRoot, "include", `${extension.cTarget}.h`),
-        renderHeader(extension),
-      );
-      await fs.writeFile(path.join(cRoot, "registration.c"), renderC(extension));
-    }
-    await fs.mkdir(swiftRoot, { recursive: true });
-    await copyResourceArtifact(extension, swiftRoot);
-    await fs.writeFile(
-      path.join(swiftRoot, `${extension.swiftTarget}.swift`),
-      renderSwift(extension, selection.bySqlName),
-    );
-    products.push({ name: extension.swiftTarget, targets: [extension.swiftTarget], type: "library" });
-    targets.push(...targetIR(extension, selection.bySqlName, localBinaryTargets));
-    selected.push({
-      asset: extension.asset,
-      createsExtension: extension.resources.createsExtension,
-      dependencies: extension.dependencies,
-      nativeDependencies: extension.nativeDependencies,
-      nativeModuleStem: extension.nativeModuleStem,
-      product: extension.product,
-      releaseProduct: extension.releaseProduct,
-      registration: extension.registration,
-      resourceBytes: extension.resources.bytes,
-      resourceFiles: extension.resources.files.length,
-      sharedPreloadLibraries: extension.sharedPreloadLibraries,
-      sqlName: extension.sqlName,
-      swiftProduct: extension.swiftTarget,
-      version: extension.version,
-    });
-  }
-  const manifest = {
-    basePackage: selection.basePackage,
-    consumerOwned: true,
-    nativeRuntime: selection.nativeRuntime,
-    products,
-    requiredBaseProducts: ["COliphaunt", "Oliphaunt", "OliphauntExtensionSupport"],
-    schema: OUTPUT_SCHEMA,
-    selected,
-    targets,
-  };
-  await fs.writeFile(
-    path.join(outputDir, "extension-products.json"),
-    `${JSON.stringify(manifest, null, 2)}\n`,
-  );
-  await fs.writeFile(path.join(outputDir, "Package.swift"), renderPackage(manifest, basePackagePath));
-  await fs.writeFile(
-    path.join(outputDir, OUTPUT_OWNER_MARKER),
-    OUTPUT_OWNER_MARKER_CONTENT,
-    { flag: "wx", mode: 0o644 },
-  );
-}
-
-async function lstatIfPresent(target) {
-  try {
-    return await fs.lstat(target);
-  } catch (error) {
-    if (error?.code === "ENOENT") return null;
-    throw error;
-  }
-}
-
-async function canonicalPathAllowMissing(target) {
-  let existing = path.resolve(target);
-  const suffix = [];
-  while ((await lstatIfPresent(existing)) === null) {
-    const parent = path.dirname(existing);
-    if (parent === existing) {
-      fail(`cannot resolve an existing ancestor for ${path.resolve(target)}`);
-    }
-    suffix.unshift(path.basename(existing));
-    existing = parent;
-  }
-  return path.resolve(await fs.realpath(existing), ...suffix);
-}
-
-function isEqualOrAncestor(ancestor, descendant) {
-  return ancestor === descendant || descendant.startsWith(`${ancestor}${path.sep}`);
-}
-
-export async function safeGeneratedOutput(outputDir, protectedPaths) {
-  const requested = path.resolve(outputDir);
-  if (requested === path.parse(requested).root) {
-    fail(`refusing filesystem root as the generated output: ${requested}`);
-  }
-  const requestedStat = await lstatIfPresent(requested);
-  if (requestedStat?.isSymbolicLink()) {
-    fail(`generated output already exists as a symbolic link; refusing to replace it: ${requested}`);
-  }
-  const output = await canonicalPathAllowMissing(requested);
-  for (const protection of protectedPaths.filter(({ path: protectedPath }) => Boolean(protectedPath))) {
-    if (
-      protection.mode !== "containment"
-      && protection.mode !== "disjoint"
-    ) {
-      fail(`internal protected-path mode is invalid for ${protection.label}`);
-    }
-    const protectedCanonical = await canonicalPathAllowMissing(protection.path);
-    const outputContainsProtected = isEqualOrAncestor(output, protectedCanonical);
-    const protectedContainsOutput = isEqualOrAncestor(protectedCanonical, output);
-    if (
-      outputContainsProtected
-      || (protection.mode === "disjoint" && protectedContainsOutput)
-    ) {
-      const relationship = protection.mode === "disjoint"
-        ? "overlaps"
-        : "is equal to or contains";
-      fail(
-        `refusing generated output ${output}; it ${relationship} protected ${protection.label} ${protectedCanonical}`,
-      );
-    }
-  }
-  if (requestedStat !== null) {
-    fail(`generated output already exists; create-only generation refuses to replace it: ${output}`);
-  }
-  return output;
-}
-
-async function validatedStagingEntries(staging) {
-  const required = new Set([
-    OUTPUT_OWNER_MARKER,
-    "Package.swift",
-    "Sources",
-    "extension-products.json",
-  ]);
-  const allowed = new Set([...required, "Artifacts"]);
-  const entries = (await fs.readdir(staging)).sort(compareText);
-  const missing = [...required].filter((entry) => !entries.includes(entry));
-  const unexpected = entries.filter((entry) => !allowed.has(entry));
-  if (missing.length > 0 || unexpected.length > 0) {
-    fail(
-      `private staging tree has an invalid top-level inventory`
-      + `${missing.length > 0 ? `; missing: ${missing.join(", ")}` : ""}`
-      + `${unexpected.length > 0 ? `; unexpected: ${unexpected.join(", ")}` : ""}`,
-    );
-  }
-  for (const entry of entries) {
-    const metadata = await fs.lstat(path.join(staging, entry));
-    const shouldBeDirectory = entry === "Sources" || entry === "Artifacts";
-    if (
-      metadata.isSymbolicLink()
-      || (shouldBeDirectory ? !metadata.isDirectory() : !metadata.isFile())
-    ) {
-      fail(`private staging entry has an invalid filesystem type: ${entry}`);
-    }
-  }
-  return entries;
-}
-
-export async function publishCreateOnly(staging, output, entries, onClaim = () => {}) {
-  try {
-    await fs.mkdir(output, { mode: 0o700, recursive: false });
-  } catch (error) {
-    if ((await lstatIfPresent(output)) !== null) {
-      fail(`generated output appeared during publication; refusing to replace it: ${output}`);
-    }
-    throw error;
-  }
-  await onClaim();
-  const publicationOrder = [
-    "Artifacts",
-    "Sources",
-    "extension-products.json",
-    "Package.swift",
-  ].filter((entry) => entries.includes(entry));
-  for (const entry of publicationOrder) {
-    await fs.rename(path.join(staging, entry), path.join(output, entry));
-  }
-  await fs.chmod(output, 0o755);
-  await fs.rename(
-    path.join(staging, OUTPUT_OWNER_MARKER),
-    path.join(output, OUTPUT_OWNER_MARKER),
-  );
-}
-
-export async function writeGenerated(
-  selection,
-  outputDir,
-  basePackagePath,
-  localBinaryTargets,
-  protectedPaths,
-) {
-  const resolvedOutput = await safeGeneratedOutput(outputDir, protectedPaths);
-  const parent = path.dirname(resolvedOutput);
-  await fs.mkdir(parent, { recursive: true });
-  const confirmedParent = await fs.realpath(parent);
-  if (path.join(confirmedParent, path.basename(resolvedOutput)) !== resolvedOutput) {
-    fail(`generated output parent changed while resolving ${resolvedOutput}`);
-  }
-  const staging = await fs.mkdtemp(
-    path.join(parent, `.${path.basename(resolvedOutput)}.tmp-`),
-  );
-  await fs.chmod(staging, 0o700);
-  let outputClaimed = false;
-  let outputComplete = false;
-  let operationError;
-  try {
-    await writeGeneratedTree(selection, staging, basePackagePath, localBinaryTargets);
-    const stagingEntries = await validatedStagingEntries(staging);
-    const publishOutput = await safeGeneratedOutput(outputDir, protectedPaths);
-    if (publishOutput !== resolvedOutput) {
-      fail(`generated output resolution changed before publication: ${resolvedOutput}`);
-    }
-    await publishCreateOnly(staging, resolvedOutput, stagingEntries, () => {
-      outputClaimed = true;
-    });
-    outputComplete = true;
-    await fs.rmdir(staging);
-  } catch (error) {
-    operationError = error;
-  }
-  if (operationError) {
-    const detail = operationError instanceof Error ? operationError.message : String(operationError);
-    const retained = outputClaimed
-      ? `${outputComplete ? "completed" : "incomplete"} create-only output is retained at ${resolvedOutput}; private staging, if any, is retained at ${staging}`
-      : `private staging is retained for explicit cleanup at ${staging}`;
-    throw new Error(`${detail}; ${retained}`, { cause: operationError });
-  }
-}
-
-async function main() {
-  const args = parseArgs(process.argv.slice(2));
-  const toolDirectory = path.dirname(fileURLToPath(import.meta.url));
-  const version = args.basePackageVersion ??
-    (await fs.readFile(path.resolve(toolDirectory, "../VERSION"), "utf8")).trim();
-  const carrierCacheDir = args.cacheDir ?? path.join(os.homedir(), ".cache", "oliphaunt", "swift-extensions");
-  const input = await resolveSwiftCarrierSelection({
-    allowFileUrls: args.allowFileUrls,
-    basePackageUrl: args.basePackageUrl,
-    basePackageVersion: version,
-    cacheDir: carrierCacheDir,
-    carrierFile: path.resolve(args.carrier),
-    extensionCarrierFiles: args.extensionCarriers.map((file) => path.resolve(file)),
-    extensions: args.extensions,
-    offline: args.offline,
-    localBinaryTargets: args.localBinaryTargets,
-  });
-  const inputDirectory = process.cwd();
-  const selection = validateSelection(input, inputDirectory, {
-    allowFileUrls: args.allowFileUrls,
-    localBinaryTargets: args.localBinaryTargets,
-  });
-  const canonicalInventory = await loadSwiftExtensionInventoryCatalog();
-  if (args.basePackagePath !== undefined) {
-    const baseManifest = path.join(args.basePackagePath, "Package.swift");
-    const stat = await fs.stat(baseManifest).catch(() => null);
-    if (stat?.isFile() !== true) {
-      fail(`--base-package-path does not contain Package.swift: ${args.basePackagePath}`);
-    }
-  }
-  for (const extension of selection.extensions) {
-    extension.resources = await validateSwiftExtensionResourceArtifact({
-      extension,
-      canonical: canonicalInventory.get(extension.sqlName),
-      nativeRuntime: selection.nativeRuntime,
-      label: `${extension.sqlName} resource artifact`,
-      allowMobileCarrierArchives: args.carrier !== undefined,
-    });
-  }
-  await writeGenerated(
-    selection,
-    path.resolve(args.outputDir),
-    args.basePackagePath,
-    args.localBinaryTargets,
-    [
-      { label: "working directory", mode: "containment", path: process.cwd() },
-      { label: "base carrier", mode: "containment", path: args.carrier },
-      ...args.extensionCarriers.map((carrier) => ({
-        label: "extension carrier",
-        mode: "containment",
-        path: carrier,
-      })),
-      {
-        label: "carrier cache",
-        mode: "disjoint",
-        path: args.cacheDir ?? carrierCacheDir,
-      },
-      { label: "base package", mode: "disjoint", path: args.basePackagePath },
-      ...selection.extensions.flatMap((extension) => [
-        { label: `${extension.sqlName} resource root`, mode: "disjoint", path: extension.resourceRoot },
-        { label: `${extension.sqlName} XCFramework`, mode: "disjoint", path: extension.asset?.localPath },
-        ...extension.nativeDependencies.map((dependency) => ({
-          label: `${dependency.name} XCFramework`,
-          mode: "disjoint",
-          path: dependency.asset.localPath,
-        })),
-      ]),
-    ].filter(({ path: protectedPath }) => protectedPath !== undefined),
-  );
-  console.log(
-    `${PREFIX}: generated ${selection.extensions.length} selected extension product(s) in ${path.resolve(args.outputDir)}`,
-  );
-}
-
-if (path.resolve(process.argv[1] ?? "") === fileURLToPath(import.meta.url)) {
-  main().catch((error) => {
-    console.error(error instanceof Error ? error.message : String(error));
-    process.exit(1);
-  });
-}
diff --git a/src/sdks/swift/tools/render-extension-products.mts b/src/sdks/swift/tools/render-extension-products.mts
new file mode 100755
index 000000000..1ecfbe8a1
--- /dev/null
+++ b/src/sdks/swift/tools/render-extension-products.mts
@@ -0,0 +1,1279 @@
+#!/usr/bin/env bun
+
+import fs from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import {
+  loadSwiftExtensionInventoryCatalog,
+  readSafeFileSnapshot,
+  snapshotSafeFileTree,
+  validateSwiftExtensionResourceArtifact,
+} from './extension-resource-inventory.mts';
+import { resolveSwiftCarrierSelection } from './swift-carrier-resolver.mts';
+
+const PREFIX = 'render-extension-products.mjs';
+const SELECTION_SCHEMA = 'oliphaunt-swiftpm-extension-selection-v1';
+const OUTPUT_SCHEMA = 'oliphaunt-swiftpm-extension-products-v1';
+const NATIVE_RUNTIME_PRODUCT = 'liboliphaunt-native';
+const OUTPUT_OWNER_MARKER = '.oliphaunt-swiftpm-extension-products';
+const OUTPUT_OWNER_MARKER_CONTENT = `${PREFIX}\n${OUTPUT_SCHEMA}\n`;
+const MAX_XCFRAMEWORK_FILES = 32768;
+const MAX_XCFRAMEWORK_FILE_BYTES = 512 * 1024 * 1024;
+const MAX_XCFRAMEWORK_TREE_BYTES = 2 * 1024 * 1024 * 1024;
+const DEFAULT_CARRIER = path.resolve(
+  path.dirname(fileURLToPath(import.meta.url)),
+  '../Carriers/oliphaunt-react-native-ios-carriers.json',
+);
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+
+function usage() {
+  console.error(
+    `usage: ${PREFIX} [--carrier ] ` +
+      `[--extension-carrier  ...] --extensions  ` +
+      `--output-dir  [--cache-dir ] [--offline] [--allow-file-urls] ` +
+      `[--local-binary-targets] ` +
+      `[--base-package-url ] [--base-package-version ] ` +
+      `[--base-package-path ]`,
+  );
+}
+
+function parseArgs(argv) {
+  const args = {
+    allowFileUrls: false,
+    extensionCarriers: [],
+    localBinaryTargets: false,
+    offline: false,
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--help' || arg === '-h') {
+      usage();
+      process.exit(0);
+    }
+    if (arg === '--allow-file-urls' || arg === '--local-binary-targets' || arg === '--offline') {
+      if (arg === '--allow-file-urls') args.allowFileUrls = true;
+      else if (arg === '--local-binary-targets') args.localBinaryTargets = true;
+      else args.offline = true;
+      continue;
+    }
+    if (
+      ![
+        '--carrier',
+        '--extension-carrier',
+        '--extensions',
+        '--cache-dir',
+        '--output-dir',
+        '--base-package-path',
+        '--base-package-url',
+        '--base-package-version',
+      ].includes(arg)
+    ) {
+      usage();
+      fail(`unknown argument ${arg}`);
+    }
+    const value = argv[index + 1];
+    if (value === undefined || value.startsWith('--')) {
+      fail(`${arg} requires a value`);
+    }
+    index += 1;
+    if (arg === '--carrier') args.carrier = value;
+    if (arg === '--extension-carrier') args.extensionCarriers.push(value);
+    if (arg === '--extensions')
+      args.extensions = value
+        .split(',')
+        .map((row) => row.trim())
+        .filter(Boolean);
+    if (arg === '--cache-dir') args.cacheDir = path.resolve(value);
+    if (arg === '--output-dir') args.outputDir = value;
+    if (arg === '--base-package-path') args.basePackagePath = path.resolve(value);
+    if (arg === '--base-package-url') args.basePackageUrl = value;
+    if (arg === '--base-package-version') args.basePackageVersion = value;
+  }
+  if (!args.outputDir || !args.extensions?.length) {
+    usage();
+    fail('provide --extensions and --output-dir; carrier options are optional');
+  }
+  if (!args.carrier) args.carrier = DEFAULT_CARRIER;
+  return args;
+}
+
+function object(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(`${label} must be an object`);
+  }
+  return value;
+}
+
+function exactKeys(value, allowed, label) {
+  const extras = Object.keys(value)
+    .filter((key) => !allowed.includes(key))
+    .sort();
+  if (extras.length > 0) {
+    fail(`${label} contains unsupported field(s): ${extras.join(', ')}`);
+  }
+}
+
+function portable(value, label) {
+  if (typeof value !== 'string' || !/^[A-Za-z0-9._-]+$/u.test(value)) {
+    fail(`${label} must contain only ASCII letters, digits, '.', '_' or '-'`);
+  }
+  return value;
+}
+
+function cIdentifier(value, label) {
+  if (typeof value !== 'string' || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(value)) {
+    fail(`${label} must be a C identifier`);
+  }
+  return value;
+}
+
+function uniquePortableList(value, label) {
+  if (!Array.isArray(value)) {
+    fail(`${label} must be an array`);
+  }
+  const items = value.map((item, index) => portable(item, `${label}[${index}]`));
+  if (new Set(items).size !== items.length) {
+    fail(`${label} must not contain duplicates`);
+  }
+  const canonical = [...items].sort(compareText);
+  if (JSON.stringify(items) !== JSON.stringify(canonical)) {
+    fail(`${label} must be sorted in ordinal order`);
+  }
+  return items;
+}
+
+function frozenDataFiles(value, label) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((item, index) => {
+    if (
+      typeof item !== 'string' ||
+      item.length === 0 ||
+      item.includes('\\') ||
+      item.startsWith('/') ||
+      /^[A-Za-z]:/u.test(item) ||
+      item.split('/').some((part) => !part || part === '.' || part === '..')
+    ) {
+      fail(`${label}[${index}] must be a safe canonical relative file path`);
+    }
+    return item;
+  });
+  const canonical = [...rows].sort(compareText);
+  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
+  if (JSON.stringify(rows) !== JSON.stringify(canonical))
+    fail(`${label} must be sorted in ordinal order`);
+  return rows;
+}
+
+function frozenSqlFileNames(value, label) {
+  const rows = uniquePortableList(value, label);
+  if (rows.some((name) => !name.endsWith('.sql'))) fail(`${label} must contain SQL basenames`);
+  return rows;
+}
+
+function frozenSqlFilePrefixes(value, label) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((item, index) => {
+    if (typeof item !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/u.test(item)) {
+      fail(`${label}[${index}] must be a dot-free portable SQL basename prefix`);
+    }
+    return item;
+  });
+  const canonical = [...rows].sort(compareText);
+  if (new Set(rows).size !== rows.length) fail(`${label} must not contain duplicates`);
+  if (JSON.stringify(rows) !== JSON.stringify(canonical))
+    fail(`${label} must be sorted in ordinal order`);
+  return rows;
+}
+
+function nullablePortable(value, label) {
+  if (value === null) {
+    return null;
+  }
+  return portable(value, label);
+}
+
+function localResourceRoot(value, label) {
+  if (typeof value !== 'string' || value.trim().length === 0 || value.includes('\0')) {
+    fail(`${label} must be a non-empty local directory path`);
+  }
+  return value;
+}
+
+function semanticVersion(value, label) {
+  if (
+    typeof value !== 'string' ||
+    !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u.test(
+      value,
+    )
+  ) {
+    fail(`${label} must be a semantic version accepted by SwiftPM`);
+  }
+  return value;
+}
+
+function stableSemanticVersion(value, label) {
+  if (
+    typeof value !== 'string' ||
+    !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(value)
+  ) {
+    fail(`${label} must be a stable semantic version in X.Y.Z form`);
+  }
+  return value;
+}
+
+function validateBasePackage(value) {
+  const base = object(value, 'basePackage');
+  exactKeys(base, ['name', 'url', 'version'], 'basePackage');
+  if (base.name !== 'Oliphaunt') {
+    fail('basePackage.name must be Oliphaunt');
+  }
+  if (typeof base.url !== 'string') {
+    fail('basePackage.url must be an HTTPS Git URL');
+  }
+  let url;
+  try {
+    url = new URL(base.url);
+  } catch {
+    fail('basePackage.url must be a valid HTTPS Git URL');
+  }
+  if (url.protocol !== 'https:' || !url.pathname.endsWith('.git')) {
+    fail('basePackage.url must be an HTTPS Git URL ending in .git');
+  }
+  return {
+    name: base.name,
+    url: base.url,
+    version: semanticVersion(base.version, 'basePackage.version'),
+  };
+}
+
+function validateNativeRuntime(value) {
+  const runtime = object(value, 'nativeRuntime');
+  exactKeys(runtime, ['product', 'version'], 'nativeRuntime');
+  if (runtime.product !== NATIVE_RUNTIME_PRODUCT) {
+    fail(`nativeRuntime.product must be ${NATIVE_RUNTIME_PRODUCT}`);
+  }
+  return {
+    product: runtime.product,
+    version: stableSemanticVersion(runtime.version, 'nativeRuntime.version'),
+  };
+}
+
+function swiftSuffix(sqlName) {
+  const words = sqlName.split(/[^A-Za-z0-9]+/u).filter(Boolean);
+  if (words.length === 0) {
+    fail(`cannot derive a Swift product name from ${sqlName}`);
+  }
+  const suffix = words.map((word) => `${word[0].toUpperCase()}${word.slice(1)}`).join('');
+  if (!/^[A-Za-z][A-Za-z0-9]*$/u.test(suffix)) {
+    fail(`cannot derive a Swift identifier from ${sqlName}`);
+  }
+  return suffix;
+}
+
+function swiftString(value) {
+  return JSON.stringify(value);
+}
+
+function expectedSymbolPrefix(stem) {
+  return `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`;
+}
+
+function validateAsset(value, label, allowFileUrls = false, localBinaryTargets = false) {
+  const asset = object(value, label);
+  exactKeys(asset, ['checksum', 'localPath', 'name', 'url'], label);
+  if (
+    typeof asset.name !== 'string' ||
+    asset.name.length === 0 ||
+    path.posix.basename(asset.name) !== asset.name ||
+    /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(asset.name) ||
+    /[ .]$/u.test(asset.name) ||
+    /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(asset.name)
+  ) {
+    fail(`${label}.name must be a plain release asset file name`);
+  }
+  if (typeof asset.url !== 'string') {
+    fail(`${label}.url must be an HTTPS URL`);
+  }
+  let url;
+  try {
+    url = new URL(asset.url);
+  } catch {
+    fail(`${label}.url must be a valid HTTPS URL`);
+  }
+  if (
+    (url.protocol !== 'https:' && !(allowFileUrls && url.protocol === 'file:')) ||
+    decodeURIComponent(path.basename(url.pathname)) !== asset.name
+  ) {
+    fail(
+      `${label}.url must be HTTPS${allowFileUrls ? ' or an explicitly enabled file URL' : ''} and end with ${asset.name}`,
+    );
+  }
+  if (typeof asset.checksum !== 'string' || !/^[a-f0-9]{64}$/u.test(asset.checksum)) {
+    fail(`${label}.checksum must be a lowercase SHA-256 digest`);
+  }
+  let localPath;
+  if (localBinaryTargets || asset.localPath !== undefined) {
+    if (
+      typeof asset.localPath !== 'string' ||
+      !path.isAbsolute(asset.localPath) ||
+      path.extname(asset.localPath) !== '.xcframework'
+    ) {
+      fail(`${label}.localPath must be an absolute XCFramework directory path`);
+    }
+    localPath = path.normalize(asset.localPath);
+  }
+  return {
+    checksum: asset.checksum,
+    name: asset.name,
+    url: asset.url,
+    ...(localPath === undefined ? {} : { localPath }),
+  };
+}
+
+function validateRegistration(value, stem, label) {
+  const registration = object(value, label);
+  exactKeys(registration, ['hasInit', 'symbols'], label);
+  if (typeof registration.hasInit !== 'boolean') {
+    fail(`${label}.hasInit must be a boolean`);
+  }
+  if (!Array.isArray(registration.symbols)) {
+    fail(`${label}.symbols must be an array derived from the built extension archive`);
+  }
+  const symbols = registration.symbols.map((raw, index) => {
+    const symbol = object(raw, `${label}.symbols[${index}]`);
+    exactKeys(symbol, ['address', 'name'], `${label}.symbols[${index}]`);
+    return {
+      address: cIdentifier(symbol.address, `${label}.symbols[${index}].address`),
+      name: cIdentifier(symbol.name, `${label}.symbols[${index}].name`),
+    };
+  });
+  const names = symbols.map(({ name }) => name);
+  if (new Set(names).size !== names.length) {
+    fail(`${label}.symbols repeats a SQL-visible symbol name`);
+  }
+  symbols.sort((left, right) =>
+    compareText(`${left.name}\0${left.address}`, `${right.name}\0${right.address}`),
+  );
+  const symbolPrefix = expectedSymbolPrefix(stem);
+  return {
+    hasInit: registration.hasInit,
+    initSymbol: registration.hasInit ? `${symbolPrefix}__PG_init` : undefined,
+    magicSymbol: `${symbolPrefix}_Pg_magic_func`,
+    symbolPrefix,
+    symbols,
+  };
+}
+
+function validateNativeDependencies(
+  value,
+  label,
+  allowFileUrls = false,
+  localBinaryTargets = false,
+) {
+  if (!Array.isArray(value)) {
+    fail(`${label} must be an array of separately checksum-pinned XCFramework assets`);
+  }
+  const dependencies = value.map((raw, index) => {
+    const dependency = object(raw, `${label}[${index}]`);
+    exactKeys(dependency, ['asset', 'name'], `${label}[${index}]`);
+    const name = portable(dependency.name, `${label}[${index}].name`);
+    return {
+      asset: validateAsset(
+        dependency.asset,
+        `${label}[${index}].asset`,
+        allowFileUrls,
+        localBinaryTargets,
+      ),
+      binaryTarget: `OliphauntNativeDependency${swiftSuffix(name)}`,
+      name,
+    };
+  });
+  dependencies.sort((left, right) => compareText(left.name, right.name));
+  if (new Set(dependencies.map(({ name }) => name)).size !== dependencies.length) {
+    fail(`${label} repeats a native dependency name`);
+  }
+  return dependencies;
+}
+
+export function validateSelection(
+  input,
+  inputDirectory,
+  { allowFileUrls = false, localBinaryTargets = false } = {},
+) {
+  const root = object(input, 'input');
+  exactKeys(root, ['basePackage', 'extensions', 'nativeRuntime', 'schema'], 'input');
+  if (root.schema !== SELECTION_SCHEMA) {
+    fail(`input schema must be ${SELECTION_SCHEMA}`);
+  }
+  if (!Array.isArray(root.extensions) || root.extensions.length === 0) {
+    fail('input extensions must be a non-empty selected extension array');
+  }
+  const basePackage = validateBasePackage(root.basePackage);
+  const nativeRuntime = validateNativeRuntime(root.nativeRuntime);
+  const extensions = root.extensions.map((raw, index) => {
+    const row = object(raw, `extensions[${index}]`);
+    exactKeys(
+      row,
+      [
+        'asset',
+        'createsExtension',
+        'dataFiles',
+        'dependencies',
+        'extensionSqlFileNames',
+        'extensionSqlFilePrefixes',
+        'nativeModuleStem',
+        'nativeDependencies',
+        'product',
+        'registration',
+        'releaseProduct',
+        'resourceRoot',
+        'sharedPreloadLibraries',
+        'sqlName',
+        'version',
+      ],
+      `extensions[${index}]`,
+    );
+    const sqlName = portable(row.sqlName, `extensions[${index}].sqlName`);
+    const product = portable(row.product, `extensions[${index}].product`);
+    if (!product.startsWith('oliphaunt-extension-')) {
+      fail(
+        `extensions[${index}].product must be an exact-extension artifact product; got ${product}`,
+      );
+    }
+    const releaseProduct = portable(row.releaseProduct, `extensions[${index}].releaseProduct`);
+    const nativeModuleStem = nullablePortable(
+      row.nativeModuleStem,
+      `extensions[${index}].nativeModuleStem`,
+    );
+    if (typeof row.createsExtension !== 'boolean') {
+      fail(`extensions[${index}].createsExtension must be boolean`);
+    }
+    const cModuleStem = nativeModuleStem?.replaceAll(/[^A-Za-z0-9_]/gu, '_');
+    const suffix = swiftSuffix(sqlName);
+    if (nativeModuleStem === null && row.registration !== null) {
+      fail(`extensions[${index}] SQL-only extension must use null registration metadata`);
+    }
+    const asset =
+      row.asset === null
+        ? null
+        : validateAsset(row.asset, `extensions[${index}].asset`, allowFileUrls, localBinaryTargets);
+    const registration =
+      row.registration === null
+        ? null
+        : validateRegistration(
+            row.registration,
+            nativeModuleStem,
+            `extensions[${index}].registration`,
+          );
+    const nativeDependencies = validateNativeDependencies(
+      row.nativeDependencies,
+      `extensions[${index}].nativeDependencies`,
+      allowFileUrls,
+      localBinaryTargets,
+    );
+    if (nativeModuleStem === null) {
+      if (asset !== null || registration !== null || nativeDependencies.length > 0) {
+        fail(
+          `extensions[${index}] is SQL-only and must use null asset/registration with no nativeDependencies`,
+        );
+      }
+    } else if (asset === null || registration === null) {
+      fail(`extensions[${index}] native extension requires asset and registration metadata`);
+    }
+    const dependencies = uniquePortableList(row.dependencies, `extensions[${index}].dependencies`);
+    if (dependencies.includes(sqlName)) {
+      fail(`extensions[${index}].dependencies must not include ${sqlName} itself`);
+    }
+    return {
+      asset,
+      binaryTarget: nativeModuleStem === null ? null : `OliphauntExtension${suffix}Binary`,
+      cFunction: nativeModuleStem === null ? null : `oliphaunt_extension_${cModuleStem}_descriptor`,
+      cTarget: nativeModuleStem === null ? null : `COliphauntExtension${suffix}`,
+      createsExtension: row.createsExtension,
+      dataFiles: frozenDataFiles(row.dataFiles, `extensions[${index}].dataFiles`),
+      dependencies,
+      extensionSqlFileNames: frozenSqlFileNames(
+        row.extensionSqlFileNames,
+        `extensions[${index}].extensionSqlFileNames`,
+      ),
+      extensionSqlFilePrefixes: frozenSqlFilePrefixes(
+        row.extensionSqlFilePrefixes,
+        `extensions[${index}].extensionSqlFilePrefixes`,
+      ),
+      nativeDependencies,
+      nativeModuleStem,
+      product,
+      releaseProduct,
+      registration,
+      resourceRoot: path.resolve(
+        inputDirectory,
+        localResourceRoot(row.resourceRoot, `extensions[${index}].resourceRoot`),
+      ),
+      sharedPreloadLibraries: uniquePortableList(
+        row.sharedPreloadLibraries,
+        `extensions[${index}].sharedPreloadLibraries`,
+      ),
+      sqlName,
+      swiftTarget: `OliphauntExtension${suffix}`,
+      version: stableSemanticVersion(row.version, `extensions[${index}].version`),
+    };
+  });
+  extensions.sort((left, right) => compareText(left.sqlName, right.sqlName));
+  const bySqlName = new Map();
+  const targetNames = new Set();
+  const nativeDependencies = new Map();
+  for (const extension of extensions) {
+    if (bySqlName.has(extension.sqlName)) {
+      fail(`selected extension ${extension.sqlName} is duplicated`);
+    }
+    bySqlName.set(extension.sqlName, extension);
+    for (const name of [extension.binaryTarget, extension.cTarget, extension.swiftTarget].filter(
+      Boolean,
+    )) {
+      if (targetNames.has(name)) {
+        fail(`generated SwiftPM target name collision: ${name}`);
+      }
+      targetNames.add(name);
+    }
+    for (const dependency of extension.nativeDependencies) {
+      const existing = nativeDependencies.get(dependency.name);
+      if (existing !== undefined) {
+        if (JSON.stringify(existing.asset) !== JSON.stringify(dependency.asset)) {
+          fail(
+            `selected extensions require conflicting ${dependency.name} native dependency assets`,
+          );
+        }
+      } else {
+        nativeDependencies.set(dependency.name, dependency);
+      }
+    }
+  }
+  for (const dependency of nativeDependencies.values()) {
+    if (targetNames.has(dependency.binaryTarget)) {
+      fail(`generated SwiftPM target name collision: ${dependency.binaryTarget}`);
+    }
+    targetNames.add(dependency.binaryTarget);
+  }
+  for (const extension of extensions) {
+    for (const dependency of extension.dependencies) {
+      if (!bySqlName.has(dependency)) {
+        fail(`${extension.sqlName} dependency ${dependency} is not present in the selected input`);
+      }
+    }
+  }
+  const visiting = new Set();
+  const visited = new Set();
+  function visit(sqlName) {
+    if (visiting.has(sqlName)) fail(`selected extension dependency cycle includes ${sqlName}`);
+    if (visited.has(sqlName)) return;
+    visiting.add(sqlName);
+    for (const dependency of bySqlName.get(sqlName).dependencies) visit(dependency);
+    visiting.delete(sqlName);
+    visited.add(sqlName);
+  }
+  for (const extension of extensions) visit(extension.sqlName);
+  return {
+    basePackage,
+    bySqlName,
+    extensions,
+    nativeRuntime,
+    nativeDependencies: [...nativeDependencies.values()].sort((left, right) =>
+      compareText(left.name, right.name),
+    ),
+  };
+}
+
+function snapshotRows(files, { includeIdentity = false, mode = undefined } = {}) {
+  return files.map((file) => ({
+    bytes: file.bytes,
+    ...(includeIdentity ? { device: file.device, inode: file.inode } : {}),
+    mode: mode ?? file.mode,
+    relative: file.relative,
+    sha256: file.sha256,
+  }));
+}
+
+function snapshotDirectoryRows(directories, { includeIdentity = false } = {}) {
+  return directories.map((directory) => ({
+    ...(includeIdentity ? { device: directory.device, inode: directory.inode } : {}),
+    mode: directory.mode,
+    relative: directory.relative,
+  }));
+}
+
+function assertSnapshotRowsEqual(expected, actual, label, options = {}) {
+  const filesChanged =
+    JSON.stringify(snapshotRows(expected, options)) !==
+    JSON.stringify(snapshotRows(actual, { includeIdentity: options.includeIdentity }));
+  const directoriesChanged =
+    options.includeDirectories === true &&
+    JSON.stringify(
+      snapshotDirectoryRows(options.expectedDirectories ?? expected.directories ?? [], options),
+    ) !== JSON.stringify(snapshotDirectoryRows(actual.directories ?? [], options));
+  if (filesChanged || directoriesChanged) {
+    fail(`${label} tree inventory changed`);
+  }
+}
+
+function safeSnapshotRelativePath(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    value.startsWith('/') ||
+    /^[A-Za-z]:/u.test(value) ||
+    value.split('/').some((part) => !part || part === '.' || part === '..')
+  ) {
+    fail(`${label} contains unsafe snapshot path ${JSON.stringify(value)}`);
+  }
+  return value;
+}
+
+export async function materializeFileSnapshots(
+  files,
+  destinationRoot,
+  label,
+  { mode = undefined } = {},
+) {
+  if (!Array.isArray(files)) {
+    fail(`${label} must be an array of validated file snapshots`);
+  }
+  if ((await lstatIfPresent(destinationRoot)) !== null) {
+    fail(`${label} destination already exists: ${destinationRoot}`);
+  }
+  await fs.mkdir(destinationRoot, { recursive: true, mode: 0o755 });
+  const preserveDirectories = Object.hasOwn(files, 'directories');
+  const directories = preserveDirectories ? files.directories : [];
+  for (const directory of [...directories].sort((left, right) => {
+    const depth = left.relative.split('/').length - right.relative.split('/').length;
+    return depth === 0 ? compareText(left.relative, right.relative) : depth;
+  })) {
+    const relative = safeSnapshotRelativePath(directory.relative, label);
+    const destination = path.join(destinationRoot, ...relative.split('/'));
+    await fs.mkdir(destination, { recursive: true, mode: directory.mode });
+    await fs.chmod(destination, directory.mode);
+  }
+  for (const file of files) {
+    const relative = safeSnapshotRelativePath(file.relative, label);
+    const destination = path.join(destinationRoot, ...relative.split('/'));
+    await fs.mkdir(path.dirname(destination), { recursive: true, mode: 0o755 });
+    const contents = await readSafeFileSnapshot(file, `${label} source ${relative}`);
+    const fileMode = mode ?? file.mode;
+    await fs.writeFile(destination, contents, { flag: 'wx', mode: fileMode });
+    await fs.chmod(destination, fileMode);
+  }
+  const expectedBytes = files.reduce((sum, file) => sum + file.bytes, 0);
+  const staged = await snapshotSafeFileTree(destinationRoot, `${label} staged copy`, {
+    maxFiles: Math.max(files.length, 1),
+    maxFileBytes: Math.max(...files.map(({ bytes }) => bytes), 1),
+    maxTreeBytes: Math.max(expectedBytes, 1),
+  });
+  assertSnapshotRowsEqual(files, staged, `${label} staged copy`, {
+    expectedDirectories: directories,
+    includeDirectories: preserveDirectories,
+    mode,
+  });
+}
+
+async function copyResourceArtifact(extension, swiftRoot) {
+  const resourceTarget = path.join(swiftRoot, 'Resources', 'extension-artifact');
+  const shareTarget = path.join(resourceTarget, 'files', 'share', 'postgresql');
+  if (extension.resources.files.length > 0) {
+    await materializeFileSnapshots(
+      extension.resources.files,
+      shareTarget,
+      `${extension.sqlName} Swift resource artifact`,
+      { mode: 0o644 },
+    );
+  } else {
+    await fs.mkdir(resourceTarget, { recursive: true });
+  }
+  const manifest = [
+    'schema=oliphaunt-swift-extension-resource-v1',
+    `product=${extension.product}`,
+    `version=${extension.version}`,
+    `sqlName=${extension.sqlName}`,
+    `createsExtension=${extension.resources.createsExtension ? 'yes' : 'no'}`,
+    `dependencies=${extension.dependencies.join(',')}`,
+    `nativeModuleStem=${extension.nativeModuleStem ?? ''}`,
+    `nativeDependencies=${extension.nativeDependencies.map(({ name }) => name).join(',')}`,
+    `sharedPreloadLibraries=${extension.sharedPreloadLibraries.join(',')}`,
+    `files=${extension.resources.files.length > 0 ? 'files' : ''}`,
+    '',
+  ].join('\n');
+  await fs.writeFile(path.join(resourceTarget, 'manifest.properties'), manifest);
+}
+
+function renderHeader(extension) {
+  const guard = `${extension.cTarget.replaceAll(/[^A-Za-z0-9]/gu, '_').toUpperCase()}_H`;
+  return (
+    `#ifndef ${guard}\n#define ${guard}\n\n#include "COliphaunt.h"\n\n` +
+    `const OliphauntStaticExtension *${extension.cFunction}(void);\n\n#endif\n`
+  );
+}
+
+function renderC(extension) {
+  const registration = extension.registration;
+  const externs = new Set([
+    `extern const void *${registration.magicSymbol}(void);`,
+    ...(registration.initSymbol ? [`extern void ${registration.initSymbol}(void);`] : []),
+    ...registration.symbols.map(({ address }) => `extern void ${address}(void);`),
+  ]);
+  const symbols = registration.symbols.length
+    ? `static const OliphauntStaticExtensionSymbol extension_symbols[] = {\n${registration.symbols
+        .map(
+          ({ name, address }) =>
+            `    { .name = ${JSON.stringify(name)}, .address = (void *)${address} },`,
+        )
+        .join('\n')}\n};\n\n`
+    : '';
+  const symbolPointer = registration.symbols.length ? 'extension_symbols' : 'NULL';
+  const symbolCount = registration.symbols.length
+    ? 'sizeof(extension_symbols) / sizeof(extension_symbols[0])'
+    : '0';
+  return (
+    `/* Generated by ${PREFIX}. Do not edit. */\n` +
+    `#include "${extension.cTarget}.h"\n\n${[...externs].sort().join('\n')}\n\n${symbols}` +
+    `static const OliphauntStaticExtension extension_descriptor = {\n` +
+    `    .abi_version = OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION,\n` +
+    `    .name = ${JSON.stringify(extension.nativeModuleStem)},\n` +
+    `    .magic = ${registration.magicSymbol},\n` +
+    `    .init = ${registration.initSymbol ?? 'NULL'},\n` +
+    `    .symbols = ${symbolPointer},\n` +
+    `    .symbol_count = ${symbolCount},\n` +
+    `    .reserved_flags = 0,\n};\n\n` +
+    `const OliphauntStaticExtension *${extension.cFunction}(void) {\n` +
+    `    return &extension_descriptor;\n}\n`
+  );
+}
+
+function renderSwift(extension, bySqlName) {
+  const dependencyImports = extension.dependencies
+    .map((dependency) => `import ${bySqlName.get(dependency).swiftTarget}`)
+    .join('\n');
+  const dependencyRegistrations = extension.dependencies
+    .map((dependency) => `        try ${bySqlName.get(dependency).swiftTarget}.register()`)
+    .join('\n');
+  const cImport = extension.cTarget ? `import ${extension.cTarget}\nimport COliphaunt\n` : '';
+  const descriptor = extension.cFunction
+    ? `        guard let descriptor = ${extension.cFunction}() else {\n` +
+      `            throw OliphauntError.engine("${extension.sqlName} static-extension descriptor is unavailable")\n` +
+      `        }\n`
+    : '';
+  return (
+    `${cImport}import Foundation\nimport Oliphaunt\nimport OliphauntExtensionSupport` +
+    `${dependencyImports ? `\n${dependencyImports}` : ''}\n\n` +
+    `public enum ${extension.swiftTarget} {\n` +
+    `    public static let product = ${swiftString(extension.product)}\n` +
+    `    public static let releaseProduct = ${swiftString(extension.releaseProduct)}\n` +
+    `    public static let sqlName = ${swiftString(extension.sqlName)}\n` +
+    `    public static let version = ${swiftString(extension.version)}\n` +
+    `    public static let dependencies: [String] = [${extension.dependencies.map(swiftString).join(', ')}]\n\n` +
+    `    public static let nativeDependencies: [String] = [${extension.nativeDependencies.map(({ name }) => swiftString(name)).join(', ')}]\n\n` +
+    `    public static let sharedPreloadLibraries: [String] = [${extension.sharedPreloadLibraries.map(swiftString).join(', ')}]\n\n` +
+    `    public static func register() throws {\n` +
+    `${dependencyRegistrations ? `${dependencyRegistrations}\n` : ''}` +
+    `        guard let resourceRoot = Bundle.module.url(forResource: "extension-artifact", withExtension: nil) else {\n` +
+    `            throw OliphauntError.engine("${extension.sqlName} SwiftPM resource fragment is unavailable")\n` +
+    `        }\n` +
+    descriptor +
+    `        try OliphauntExtensionSupport.register(\n` +
+    `            product: product,\n` +
+    `            sqlName: sqlName,\n` +
+    `            version: version,\n` +
+    `            dependencies: dependencies,\n` +
+    `            nativeDependencies: nativeDependencies,\n` +
+    `            sharedPreloadLibraries: sharedPreloadLibraries,\n` +
+    `            nativeModuleStem: ${extension.nativeModuleStem === null ? 'nil' : swiftString(extension.nativeModuleStem)},\n` +
+    `            resourceRoot: resourceRoot,\n` +
+    `            descriptor: ${extension.cFunction ? 'descriptor' : 'nil'}\n` +
+    `        )\n` +
+    `    }\n}\n`
+  );
+}
+
+function baseProduct(name) {
+  return { package: 'oliphaunt', product: name };
+}
+
+function binaryTargetIR(name, asset, localBinaryTargets) {
+  return localBinaryTargets || asset.localPath !== undefined
+    ? {
+        kind: 'binaryTarget',
+        name,
+        path: `Artifacts/${name}.xcframework`,
+      }
+    : {
+        checksum: asset.checksum,
+        kind: 'binaryTarget',
+        name,
+        url: asset.url,
+      };
+}
+
+function targetIR(extension, bySqlName, localBinaryTargets) {
+  const swiftPath = `Sources/${extension.swiftTarget}`;
+  const targets = [];
+  if (extension.nativeModuleStem !== null) {
+    const nativeDependencyNames = new Set(extension.nativeDependencies.map(({ name }) => name));
+    const linkedLibraries = ['geos', 'geos-c', 'proj'].some((name) =>
+      nativeDependencyNames.has(name),
+    )
+      ? ['c++']
+      : [];
+    targets.push(binaryTargetIR(extension.binaryTarget, extension.asset, localBinaryTargets), {
+      dependencies: [
+        baseProduct('COliphaunt'),
+        extension.binaryTarget,
+        ...extension.nativeDependencies.map(({ binaryTarget }) => binaryTarget),
+      ],
+      kind: 'target',
+      linkedLibraries,
+      name: extension.cTarget,
+      path: `Sources/${extension.cTarget}`,
+      publicHeadersPath: 'include',
+    });
+  }
+  targets.push({
+    dependencies: [
+      ...(extension.cTarget ? [baseProduct('COliphaunt')] : []),
+      baseProduct('Oliphaunt'),
+      baseProduct('OliphauntExtensionSupport'),
+      ...(extension.cTarget ? [extension.cTarget] : []),
+      ...extension.dependencies.map((dependency) => bySqlName.get(dependency).swiftTarget),
+    ],
+    kind: 'target',
+    name: extension.swiftTarget,
+    path: swiftPath,
+    resources: [{ path: 'Resources/extension-artifact', rule: 'copy' }],
+  });
+  return targets;
+}
+
+function renderTargetDependency(dependency) {
+  if (typeof dependency === 'string') {
+    return swiftString(dependency);
+  }
+  return `.product(name: ${swiftString(dependency.product)}, package: ${swiftString(dependency.package)})`;
+}
+
+function renderPackage(manifest, basePackagePath) {
+  const products = manifest.products
+    .map(
+      (product) =>
+        `    .library(name: ${swiftString(product.name)}, targets: [${product.targets
+          .map(swiftString)
+          .join(', ')}])`,
+    )
+    .join(',\n');
+  const targets = manifest.targets
+    .map((target) => {
+      if (target.kind === 'binaryTarget') {
+        if (target.path !== undefined) {
+          return `    .binaryTarget(\n        name: ${swiftString(target.name)},\n        path: ${swiftString(target.path)}\n    )`;
+        }
+        return `    .binaryTarget(\n        name: ${swiftString(target.name)},\n        url: ${swiftString(target.url)},\n        checksum: ${swiftString(target.checksum)}\n    )`;
+      }
+      const headers = target.publicHeadersPath
+        ? `,\n        publicHeadersPath: ${swiftString(target.publicHeadersPath)}`
+        : '';
+      const resources = target.resources
+        ? `,\n        resources: [${target.resources
+            .map((resource) => `.${resource.rule}(${swiftString(resource.path)})`)
+            .join(', ')}]`
+        : '';
+      const linkerSettings = target.linkedLibraries?.length
+        ? `,\n        linkerSettings: [${target.linkedLibraries
+            .map((library) => `.linkedLibrary(${swiftString(library)})`)
+            .join(', ')}]`
+        : '';
+      return `    .target(\n        name: ${swiftString(target.name)},\n        dependencies: [${target.dependencies
+        .map(renderTargetDependency)
+        .join(
+          ', ',
+        )}],\n        path: ${swiftString(target.path)}${headers}${resources}${linkerSettings}\n    )`;
+    })
+    .join(',\n');
+  const baseDependency = basePackagePath
+    ? `.package(name: "oliphaunt", path: ${swiftString(basePackagePath)})`
+    : `.package(\n            url: ${swiftString(manifest.basePackage.url)},\n            exact: ${swiftString(manifest.basePackage.version)}\n        )`;
+  return (
+    `// swift-tools-version: 6.0\n\n` +
+    `import PackageDescription\n\n` +
+    `// Generated by ${PREFIX}. Do not edit. This local package belongs to the\n` +
+    `// consuming application; exact-extension assets remain separately released.\n` +
+    `let package = Package(\n` +
+    `    name: "OliphauntSelectedExtensions",\n` +
+    `    platforms: [.iOS(.v17), .macOS(.v14)],\n` +
+    `    products: [\n${products}\n    ],\n` +
+    `    dependencies: [\n        ${baseDependency}\n    ],\n` +
+    `    targets: [\n${targets}\n    ]\n` +
+    `)\n`
+  );
+}
+
+async function copyLocalBinaryArtifact(asset, targetName, outputDir) {
+  const source = asset.localPath;
+  const sourceStat = await fs.lstat(source).catch(() => null);
+  if (sourceStat?.isDirectory() !== true || sourceStat.isSymbolicLink()) {
+    fail(`local binary target ${targetName} is not a real XCFramework directory: ${source}`);
+  }
+  const label = `local binary target ${targetName}`;
+  const sourceFiles = await snapshotSafeFileTree(source, label, {
+    maxFiles: MAX_XCFRAMEWORK_FILES,
+    maxFileBytes: MAX_XCFRAMEWORK_FILE_BYTES,
+    maxTreeBytes: MAX_XCFRAMEWORK_TREE_BYTES,
+  });
+  if (!sourceFiles.some(({ relative }) => relative === 'Info.plist')) {
+    fail(`${label} is missing Info.plist: ${source}`);
+  }
+  const destination = path.join(outputDir, 'Artifacts', `${targetName}.xcframework`);
+  await fs.mkdir(path.dirname(destination), { recursive: true });
+  await materializeFileSnapshots(sourceFiles, destination, label);
+  const sourceAfterCopy = await snapshotSafeFileTree(source, `${label} post-copy source`, {
+    maxFiles: MAX_XCFRAMEWORK_FILES,
+    maxFileBytes: MAX_XCFRAMEWORK_FILE_BYTES,
+    maxTreeBytes: MAX_XCFRAMEWORK_TREE_BYTES,
+  });
+  assertSnapshotRowsEqual(sourceFiles, sourceAfterCopy, `${label} source`, {
+    includeDirectories: true,
+    includeIdentity: true,
+  });
+}
+
+async function writeGeneratedTree(selection, outputDir, basePackagePath, localBinaryTargets) {
+  const products = [];
+  const targets = [];
+  const selected = [];
+  for (const dependency of selection.nativeDependencies) {
+    if (localBinaryTargets || dependency.asset.localPath !== undefined) {
+      await copyLocalBinaryArtifact(dependency.asset, dependency.binaryTarget, outputDir);
+    }
+    targets.push(binaryTargetIR(dependency.binaryTarget, dependency.asset, localBinaryTargets));
+  }
+  for (const extension of selection.extensions) {
+    const swiftRoot = path.join(outputDir, 'Sources', extension.swiftTarget);
+    if (extension.cTarget) {
+      if (localBinaryTargets || extension.asset.localPath !== undefined) {
+        await copyLocalBinaryArtifact(extension.asset, extension.binaryTarget, outputDir);
+      }
+      const cRoot = path.join(outputDir, 'Sources', extension.cTarget);
+      await fs.mkdir(path.join(cRoot, 'include'), { recursive: true });
+      await fs.writeFile(
+        path.join(cRoot, 'include', `${extension.cTarget}.h`),
+        renderHeader(extension),
+      );
+      await fs.writeFile(path.join(cRoot, 'registration.c'), renderC(extension));
+    }
+    await fs.mkdir(swiftRoot, { recursive: true });
+    await copyResourceArtifact(extension, swiftRoot);
+    await fs.writeFile(
+      path.join(swiftRoot, `${extension.swiftTarget}.swift`),
+      renderSwift(extension, selection.bySqlName),
+    );
+    products.push({
+      name: extension.swiftTarget,
+      targets: [extension.swiftTarget],
+      type: 'library',
+    });
+    targets.push(...targetIR(extension, selection.bySqlName, localBinaryTargets));
+    selected.push({
+      asset: extension.asset,
+      createsExtension: extension.resources.createsExtension,
+      dependencies: extension.dependencies,
+      nativeDependencies: extension.nativeDependencies,
+      nativeModuleStem: extension.nativeModuleStem,
+      product: extension.product,
+      releaseProduct: extension.releaseProduct,
+      registration: extension.registration,
+      resourceBytes: extension.resources.bytes,
+      resourceFiles: extension.resources.files.length,
+      sharedPreloadLibraries: extension.sharedPreloadLibraries,
+      sqlName: extension.sqlName,
+      swiftProduct: extension.swiftTarget,
+      version: extension.version,
+    });
+  }
+  const manifest = {
+    basePackage: selection.basePackage,
+    consumerOwned: true,
+    nativeRuntime: selection.nativeRuntime,
+    products,
+    requiredBaseProducts: ['COliphaunt', 'Oliphaunt', 'OliphauntExtensionSupport'],
+    schema: OUTPUT_SCHEMA,
+    selected,
+    targets,
+  };
+  await fs.writeFile(
+    path.join(outputDir, 'extension-products.json'),
+    `${JSON.stringify(manifest, null, 2)}\n`,
+  );
+  await fs.writeFile(
+    path.join(outputDir, 'Package.swift'),
+    renderPackage(manifest, basePackagePath),
+  );
+  await fs.writeFile(path.join(outputDir, OUTPUT_OWNER_MARKER), OUTPUT_OWNER_MARKER_CONTENT, {
+    flag: 'wx',
+    mode: 0o644,
+  });
+}
+
+async function lstatIfPresent(target) {
+  try {
+    return await fs.lstat(target);
+  } catch (error) {
+    if (error?.code === 'ENOENT') return null;
+    throw error;
+  }
+}
+
+async function canonicalPathAllowMissing(target) {
+  let existing = path.resolve(target);
+  const suffix = [];
+  while ((await lstatIfPresent(existing)) === null) {
+    const parent = path.dirname(existing);
+    if (parent === existing) {
+      fail(`cannot resolve an existing ancestor for ${path.resolve(target)}`);
+    }
+    suffix.unshift(path.basename(existing));
+    existing = parent;
+  }
+  return path.resolve(await fs.realpath(existing), ...suffix);
+}
+
+function isEqualOrAncestor(ancestor, descendant) {
+  return ancestor === descendant || descendant.startsWith(`${ancestor}${path.sep}`);
+}
+
+export async function safeGeneratedOutput(outputDir, protectedPaths) {
+  const requested = path.resolve(outputDir);
+  if (requested === path.parse(requested).root) {
+    fail(`refusing filesystem root as the generated output: ${requested}`);
+  }
+  const requestedStat = await lstatIfPresent(requested);
+  if (requestedStat?.isSymbolicLink()) {
+    fail(
+      `generated output already exists as a symbolic link; refusing to replace it: ${requested}`,
+    );
+  }
+  const output = await canonicalPathAllowMissing(requested);
+  for (const protection of protectedPaths.filter(({ path: protectedPath }) =>
+    Boolean(protectedPath),
+  )) {
+    if (protection.mode !== 'containment' && protection.mode !== 'disjoint') {
+      fail(`internal protected-path mode is invalid for ${protection.label}`);
+    }
+    const protectedCanonical = await canonicalPathAllowMissing(protection.path);
+    const outputContainsProtected = isEqualOrAncestor(output, protectedCanonical);
+    const protectedContainsOutput = isEqualOrAncestor(protectedCanonical, output);
+    if (outputContainsProtected || (protection.mode === 'disjoint' && protectedContainsOutput)) {
+      const relationship = protection.mode === 'disjoint' ? 'overlaps' : 'is equal to or contains';
+      fail(
+        `refusing generated output ${output}; it ${relationship} protected ${protection.label} ${protectedCanonical}`,
+      );
+    }
+  }
+  if (requestedStat !== null) {
+    fail(
+      `generated output already exists; create-only generation refuses to replace it: ${output}`,
+    );
+  }
+  return output;
+}
+
+async function validatedStagingEntries(staging) {
+  const required = new Set([
+    OUTPUT_OWNER_MARKER,
+    'Package.swift',
+    'Sources',
+    'extension-products.json',
+  ]);
+  const allowed = new Set([...required, 'Artifacts']);
+  const entries = (await fs.readdir(staging)).sort(compareText);
+  const missing = [...required].filter((entry) => !entries.includes(entry));
+  const unexpected = entries.filter((entry) => !allowed.has(entry));
+  if (missing.length > 0 || unexpected.length > 0) {
+    fail(
+      `private staging tree has an invalid top-level inventory` +
+        `${missing.length > 0 ? `; missing: ${missing.join(', ')}` : ''}` +
+        `${unexpected.length > 0 ? `; unexpected: ${unexpected.join(', ')}` : ''}`,
+    );
+  }
+  for (const entry of entries) {
+    const metadata = await fs.lstat(path.join(staging, entry));
+    const shouldBeDirectory = entry === 'Sources' || entry === 'Artifacts';
+    if (
+      metadata.isSymbolicLink() ||
+      (shouldBeDirectory ? !metadata.isDirectory() : !metadata.isFile())
+    ) {
+      fail(`private staging entry has an invalid filesystem type: ${entry}`);
+    }
+  }
+  return entries;
+}
+
+export async function publishCreateOnly(staging, output, entries, onClaim = () => {}) {
+  try {
+    await fs.mkdir(output, { mode: 0o700, recursive: false });
+  } catch (error) {
+    if ((await lstatIfPresent(output)) !== null) {
+      fail(`generated output appeared during publication; refusing to replace it: ${output}`);
+    }
+    throw error;
+  }
+  await onClaim();
+  const publicationOrder = [
+    'Artifacts',
+    'Sources',
+    'extension-products.json',
+    'Package.swift',
+  ].filter((entry) => entries.includes(entry));
+  for (const entry of publicationOrder) {
+    await fs.rename(path.join(staging, entry), path.join(output, entry));
+  }
+  await fs.chmod(output, 0o755);
+  await fs.rename(path.join(staging, OUTPUT_OWNER_MARKER), path.join(output, OUTPUT_OWNER_MARKER));
+}
+
+export async function writeGenerated(
+  selection,
+  outputDir,
+  basePackagePath,
+  localBinaryTargets,
+  protectedPaths,
+) {
+  const resolvedOutput = await safeGeneratedOutput(outputDir, protectedPaths);
+  const parent = path.dirname(resolvedOutput);
+  await fs.mkdir(parent, { recursive: true });
+  const confirmedParent = await fs.realpath(parent);
+  if (path.join(confirmedParent, path.basename(resolvedOutput)) !== resolvedOutput) {
+    fail(`generated output parent changed while resolving ${resolvedOutput}`);
+  }
+  const staging = await fs.mkdtemp(path.join(parent, `.${path.basename(resolvedOutput)}.tmp-`));
+  await fs.chmod(staging, 0o700);
+  let outputClaimed = false;
+  let outputComplete = false;
+  let operationError;
+  try {
+    await writeGeneratedTree(selection, staging, basePackagePath, localBinaryTargets);
+    const stagingEntries = await validatedStagingEntries(staging);
+    const publishOutput = await safeGeneratedOutput(outputDir, protectedPaths);
+    if (publishOutput !== resolvedOutput) {
+      fail(`generated output resolution changed before publication: ${resolvedOutput}`);
+    }
+    await publishCreateOnly(staging, resolvedOutput, stagingEntries, () => {
+      outputClaimed = true;
+    });
+    outputComplete = true;
+    await fs.rmdir(staging);
+  } catch (error) {
+    operationError = error;
+  }
+  if (operationError) {
+    const detail =
+      operationError instanceof Error ? operationError.message : String(operationError);
+    const retained = outputClaimed
+      ? `${outputComplete ? 'completed' : 'incomplete'} create-only output is retained at ${resolvedOutput}; private staging, if any, is retained at ${staging}`
+      : `private staging is retained for explicit cleanup at ${staging}`;
+    throw new Error(`${detail}; ${retained}`, { cause: operationError });
+  }
+}
+
+export async function renderExtensionProducts(argv = process.argv.slice(2)) {
+  const args = parseArgs(argv);
+  const toolDirectory = path.dirname(fileURLToPath(import.meta.url));
+  const version =
+    args.basePackageVersion ??
+    (await fs.readFile(path.resolve(toolDirectory, '../VERSION'), 'utf8')).trim();
+  const carrierCacheDir =
+    args.cacheDir ?? path.join(os.homedir(), '.cache', 'oliphaunt', 'swift-extensions');
+  const input = await resolveSwiftCarrierSelection({
+    allowFileUrls: args.allowFileUrls,
+    basePackageUrl: args.basePackageUrl,
+    basePackageVersion: version,
+    cacheDir: carrierCacheDir,
+    carrierFile: path.resolve(args.carrier),
+    extensionCarrierFiles: args.extensionCarriers.map((file) => path.resolve(file)),
+    extensions: args.extensions,
+    offline: args.offline,
+    localBinaryTargets: args.localBinaryTargets,
+  });
+  const inputDirectory = process.cwd();
+  const selection = validateSelection(input, inputDirectory, {
+    allowFileUrls: args.allowFileUrls,
+    localBinaryTargets: args.localBinaryTargets,
+  });
+  const canonicalInventory = await loadSwiftExtensionInventoryCatalog();
+  if (args.basePackagePath !== undefined) {
+    const baseManifest = path.join(args.basePackagePath, 'Package.swift');
+    const stat = await fs.stat(baseManifest).catch(() => null);
+    if (stat?.isFile() !== true) {
+      fail(`--base-package-path does not contain Package.swift: ${args.basePackagePath}`);
+    }
+  }
+  for (const extension of selection.extensions) {
+    extension.resources = await validateSwiftExtensionResourceArtifact({
+      extension,
+      canonical: canonicalInventory.get(extension.sqlName),
+      nativeRuntime: selection.nativeRuntime,
+      label: `${extension.sqlName} resource artifact`,
+      allowMobileCarrierArchives: args.carrier !== undefined,
+    });
+  }
+  await writeGenerated(
+    selection,
+    path.resolve(args.outputDir),
+    args.basePackagePath,
+    args.localBinaryTargets,
+    [
+      { label: 'working directory', mode: 'containment', path: process.cwd() },
+      { label: 'base carrier', mode: 'containment', path: args.carrier },
+      ...args.extensionCarriers.map((carrier) => ({
+        label: 'extension carrier',
+        mode: 'containment',
+        path: carrier,
+      })),
+      {
+        label: 'carrier cache',
+        mode: 'disjoint',
+        path: args.cacheDir ?? carrierCacheDir,
+      },
+      { label: 'base package', mode: 'disjoint', path: args.basePackagePath },
+      ...selection.extensions.flatMap((extension) => [
+        {
+          label: `${extension.sqlName} resource root`,
+          mode: 'disjoint',
+          path: extension.resourceRoot,
+        },
+        {
+          label: `${extension.sqlName} XCFramework`,
+          mode: 'disjoint',
+          path: extension.asset?.localPath,
+        },
+        ...extension.nativeDependencies.map((dependency) => ({
+          label: `${dependency.name} XCFramework`,
+          mode: 'disjoint',
+          path: dependency.asset.localPath,
+        })),
+      ]),
+    ].filter(({ path: protectedPath }) => protectedPath !== undefined),
+  );
+  console.log(
+    `${PREFIX}: generated ${selection.extensions.length} selected extension product(s) in ${path.resolve(args.outputDir)}`,
+  );
+}
+
+if (path.resolve(process.argv[1] ?? '') === fileURLToPath(import.meta.url)) {
+  renderExtensionProducts().catch((error) => {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(1);
+  });
+}
diff --git a/src/sdks/swift/tools/render-extension-products.test-driver.mjs b/src/sdks/swift/tools/render-extension-products.test-driver.mjs
deleted file mode 100644
index b8d0afcbd..000000000
--- a/src/sdks/swift/tools/render-extension-products.test-driver.mjs
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env node
-
-import fs from "node:fs/promises";
-import path from "node:path";
-
-import {
-  loadSwiftExtensionInventoryCatalog,
-  validateSwiftExtensionResourceArtifact,
-} from "./extension-resource-inventory.mjs";
-import {
-  validateSelection,
-  writeGenerated,
-} from "./render-extension-products.mjs";
-
-function fail(message) {
-  throw new Error(`render-extension-products.test-driver.mjs: ${message}`);
-}
-
-function parseArgs(argv) {
-  const args = { allowFileUrls: false, localBinaryTargets: false };
-  for (let index = 0; index < argv.length; index += 1) {
-    const arg = argv[index];
-    if (arg === "--allow-file-urls" || arg === "--local-binary-targets") {
-      if (arg === "--allow-file-urls") args.allowFileUrls = true;
-      else args.localBinaryTargets = true;
-      continue;
-    }
-    if (!["--selection", "--output-dir", "--base-package-path"].includes(arg)) {
-      fail(`unknown argument ${arg}`);
-    }
-    const value = argv[index + 1];
-    if (value === undefined || value.startsWith("--")) fail(`${arg} requires a value`);
-    index += 1;
-    if (arg === "--selection") args.selection = path.resolve(value);
-    if (arg === "--output-dir") args.outputDir = path.resolve(value);
-    if (arg === "--base-package-path") args.basePackagePath = path.resolve(value);
-  }
-  if (!args.selection || !args.outputDir) fail("--selection and --output-dir are required");
-  return args;
-}
-
-async function main() {
-  const args = parseArgs(process.argv.slice(2));
-  const input = JSON.parse(await fs.readFile(args.selection, "utf8"));
-  const selection = validateSelection(input, path.dirname(args.selection), {
-    allowFileUrls: args.allowFileUrls,
-    localBinaryTargets: args.localBinaryTargets,
-  });
-  const catalog = await loadSwiftExtensionInventoryCatalog();
-  if (args.basePackagePath !== undefined) {
-    const manifest = path.join(args.basePackagePath, "Package.swift");
-    if ((await fs.stat(manifest).catch(() => null))?.isFile() !== true) {
-      fail(`--base-package-path does not contain Package.swift: ${args.basePackagePath}`);
-    }
-  }
-  for (const extension of selection.extensions) {
-    extension.resources = await validateSwiftExtensionResourceArtifact({
-      extension,
-      canonical: catalog.get(extension.sqlName),
-      nativeRuntime: selection.nativeRuntime,
-      label: `${extension.sqlName} resource artifact`,
-      allowMobileCarrierArchives: false,
-    });
-  }
-  await writeGenerated(
-    selection,
-    args.outputDir,
-    args.basePackagePath,
-    args.localBinaryTargets,
-    [
-      { label: "working directory", mode: "containment", path: process.cwd() },
-      { label: "selection fixture", mode: "containment", path: args.selection },
-      { label: "base package", mode: "disjoint", path: args.basePackagePath },
-      ...selection.extensions.flatMap((extension) => [
-        { label: `${extension.sqlName} resource root`, mode: "disjoint", path: extension.resourceRoot },
-        { label: `${extension.sqlName} XCFramework`, mode: "disjoint", path: extension.asset?.localPath },
-        ...extension.nativeDependencies.map((dependency) => ({
-          label: `${dependency.name} XCFramework`,
-          mode: "disjoint",
-          path: dependency.asset.localPath,
-        })),
-      ]),
-    ].filter(({ path: protectedPath }) => protectedPath !== undefined),
-  );
-}
-
-main().catch((error) => {
-  console.error(error instanceof Error ? error.message : String(error));
-  process.exit(1);
-});
diff --git a/src/sdks/swift/tools/render-extension-products.test-driver.mts b/src/sdks/swift/tools/render-extension-products.test-driver.mts
new file mode 100644
index 000000000..7c87dfc93
--- /dev/null
+++ b/src/sdks/swift/tools/render-extension-products.test-driver.mts
@@ -0,0 +1,95 @@
+#!/usr/bin/env bun
+
+import fs from 'node:fs/promises';
+import path from 'node:path';
+
+import {
+  loadSwiftExtensionInventoryCatalog,
+  validateSwiftExtensionResourceArtifact,
+} from './extension-resource-inventory.mts';
+import { validateSelection, writeGenerated } from './render-extension-products.mts';
+
+function fail(message) {
+  throw new Error(`render-extension-products.test-driver.mts: ${message}`);
+}
+
+function parseArgs(argv) {
+  const args = { allowFileUrls: false, localBinaryTargets: false };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--allow-file-urls' || arg === '--local-binary-targets') {
+      if (arg === '--allow-file-urls') args.allowFileUrls = true;
+      else args.localBinaryTargets = true;
+      continue;
+    }
+    if (!['--selection', '--output-dir', '--base-package-path'].includes(arg)) {
+      fail(`unknown argument ${arg}`);
+    }
+    const value = argv[index + 1];
+    if (value === undefined || value.startsWith('--')) fail(`${arg} requires a value`);
+    index += 1;
+    if (arg === '--selection') args.selection = path.resolve(value);
+    if (arg === '--output-dir') args.outputDir = path.resolve(value);
+    if (arg === '--base-package-path') args.basePackagePath = path.resolve(value);
+  }
+  if (!args.selection || !args.outputDir) fail('--selection and --output-dir are required');
+  return args;
+}
+
+async function main() {
+  const args = parseArgs(process.argv.slice(2));
+  const input = JSON.parse(await fs.readFile(args.selection, 'utf8'));
+  const selection = validateSelection(input, path.dirname(args.selection), {
+    allowFileUrls: args.allowFileUrls,
+    localBinaryTargets: args.localBinaryTargets,
+  });
+  const catalog = await loadSwiftExtensionInventoryCatalog();
+  if (args.basePackagePath !== undefined) {
+    const manifest = path.join(args.basePackagePath, 'Package.swift');
+    if ((await fs.stat(manifest).catch(() => null))?.isFile() !== true) {
+      fail(`--base-package-path does not contain Package.swift: ${args.basePackagePath}`);
+    }
+  }
+  for (const extension of selection.extensions) {
+    extension.resources = await validateSwiftExtensionResourceArtifact({
+      extension,
+      canonical: catalog.get(extension.sqlName),
+      nativeRuntime: selection.nativeRuntime,
+      label: `${extension.sqlName} resource artifact`,
+      allowMobileCarrierArchives: false,
+    });
+  }
+  await writeGenerated(
+    selection,
+    args.outputDir,
+    args.basePackagePath,
+    args.localBinaryTargets,
+    [
+      { label: 'working directory', mode: 'containment', path: process.cwd() },
+      { label: 'selection fixture', mode: 'containment', path: args.selection },
+      { label: 'base package', mode: 'disjoint', path: args.basePackagePath },
+      ...selection.extensions.flatMap((extension) => [
+        {
+          label: `${extension.sqlName} resource root`,
+          mode: 'disjoint',
+          path: extension.resourceRoot,
+        },
+        {
+          label: `${extension.sqlName} XCFramework`,
+          mode: 'disjoint',
+          path: extension.asset?.localPath,
+        },
+        ...extension.nativeDependencies.map((dependency) => ({
+          label: `${dependency.name} XCFramework`,
+          mode: 'disjoint',
+          path: dependency.asset.localPath,
+        })),
+      ]),
+    ].filter(({ path: protectedPath }) => protectedPath !== undefined),
+  );
+}
+
+main().catch((error) => {
+  console.error(error instanceof Error ? error.message : String(error));
+  process.exit(1);
+});
diff --git a/src/sdks/swift/tools/render_swiftpm_release_package.mts b/src/sdks/swift/tools/render_swiftpm_release_package.mts
new file mode 100755
index 000000000..713eef658
--- /dev/null
+++ b/src/sdks/swift/tools/render_swiftpm_release_package.mts
@@ -0,0 +1,557 @@
+#!/usr/bin/env bun
+import { createHash } from 'node:crypto';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+
+import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts';
+import { productCompatibilityVersion } from '../../../../tools/release/release-graph.mts';
+import { assertRustDependencyLicensesInEntries } from '../../rust/mobile-bindings/tools/dependency-license-contract.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../../../..');
+const REPOSITORY = 'f0rr0/oliphaunt';
+const MAX_REMOTE_CHECKSUM_MANIFEST_BYTES = 1024 * 1024;
+
+function fail(message) {
+  console.error(`render_swiftpm_release_package.mts: ${message}`);
+  process.exit(1);
+}
+
+async function fileStat(file) {
+  return fs.stat(file).catch(() => null);
+}
+
+async function isFile(file) {
+  const stat = await fileStat(file);
+  return stat?.isFile() === true;
+}
+
+async function sha256(file) {
+  return createHash('sha256')
+    .update(await fs.readFile(file))
+    .digest('hex');
+}
+
+function checksumFromManifest(text, asset) {
+  for (const rawLine of text.split(/\r?\n/u)) {
+    const line = rawLine.trim();
+    if (!line) {
+      continue;
+    }
+    const parts = line.split(/\s+/u);
+    if (parts.length !== 2) {
+      continue;
+    }
+    const [digest, filename] = parts;
+    if (filename === `./${asset}` || filename === asset) {
+      return digest;
+    }
+  }
+  return undefined;
+}
+
+async function readZipArchive(file) {
+  const entries = readPortableArchiveEntries(file, { format: 'zip' });
+  return {
+    names: new Set(entries.keys()),
+    read(entryName) {
+      const entry = entries.get(entryName);
+      return entry?.isFile ? Buffer.from(entry.data()) : undefined;
+    },
+  };
+}
+
+function xmlDecode(value) {
+  return value
+    .replaceAll('"', '"')
+    .replaceAll(''', "'")
+    .replaceAll('<', '<')
+    .replaceAll('>', '>')
+    .replaceAll('&', '&');
+}
+
+function tokenizeXml(text) {
+  return Array.from(text.matchAll(/<[^>]+>|[^<]+/gu), (match) => match[0]);
+}
+
+function tagName(token) {
+  return token
+    .replace(/^<\//u, '')
+    .replace(/^$/u, '')
+    .trim()
+    .split(/\s+/u)[0];
+}
+
+class PlistParser {
+  constructor(text) {
+    this.tokens = tokenizeXml(text);
+    this.index = 0;
+  }
+
+  parse() {
+    const token = this.nextToken();
+    if (!this.isOpening(token, 'plist')) {
+      throw new Error('plist root element is missing');
+    }
+    const value = this.parseValue();
+    const closing = this.nextToken();
+    if (!this.isClosing(closing, 'plist')) {
+      throw new Error('plist root element is not closed');
+    }
+    return value;
+  }
+
+  nextToken() {
+    while (this.index < this.tokens.length) {
+      const token = this.tokens[this.index];
+      this.index += 1;
+      if (!token.startsWith('<') && token.trim() === '') {
+        continue;
+      }
+      if (token.startsWith('')
+    );
+  }
+
+  isClosing(token, name) {
+    return token.startsWith('');
+  }
+
+  parseValue() {
+    const token = this.nextToken();
+    if (this.isOpening(token, 'dict')) {
+      return this.parseDict();
+    }
+    if (this.isOpening(token, 'array')) {
+      return this.parseArray();
+    }
+    if (this.isOpening(token, 'string')) {
+      return this.parseTextElement('string');
+    }
+    if (this.isSelfClosing(token, 'string')) {
+      return '';
+    }
+    if (this.isOpening(token, 'integer')) {
+      return Number.parseInt(this.parseTextElement('integer'), 10);
+    }
+    if (this.isSelfClosing(token, 'true')) {
+      return true;
+    }
+    if (this.isSelfClosing(token, 'false')) {
+      return false;
+    }
+    throw new Error(`unsupported plist value ${token}`);
+  }
+
+  parseDict() {
+    const result = {};
+    while (true) {
+      const token = this.peekToken();
+      if (this.isClosing(token, 'dict')) {
+        this.nextToken();
+        return result;
+      }
+      const keyOpen = this.nextToken();
+      if (!this.isOpening(keyOpen, 'key')) {
+        throw new Error(`expected plist dict key, got ${keyOpen}`);
+      }
+      const key = this.parseTextElement('key');
+      result[key] = this.parseValue();
+    }
+  }
+
+  parseArray() {
+    const result = [];
+    while (true) {
+      const token = this.peekToken();
+      if (this.isClosing(token, 'array')) {
+        this.nextToken();
+        return result;
+      }
+      result.push(this.parseValue());
+    }
+  }
+
+  parseTextElement(name) {
+    let text = '';
+    while (true) {
+      const token = this.nextToken();
+      if (this.isClosing(token, name)) {
+        return xmlDecode(text);
+      }
+      if (token.startsWith('<')) {
+        throw new Error(`unexpected tag in plist ${name}: ${token}`);
+      }
+      text += token;
+    }
+  }
+}
+
+function parsePlist(buffer, source) {
+  const prefix = buffer.subarray(0, 6).toString('utf8');
+  if (prefix === 'bplist') {
+    fail(`SwiftPM Apple XCFramework Info.plist must be XML for release validation: ${source}`);
+  }
+  try {
+    return new PlistParser(buffer.toString('utf8')).parse();
+  } catch (error) {
+    fail(`SwiftPM Apple XCFramework Info.plist is invalid in ${source}: ${error.message}`);
+  }
+}
+
+async function validateAppleXcframeworkAsset(file, framework = 'liboliphaunt') {
+  let archive;
+  try {
+    archive = await readZipArchive(file);
+  } catch (error) {
+    fail(`SwiftPM Apple XCFramework asset is not a readable zip file: ${file}: ${error.message}`);
+  }
+  const infoData = archive.read(`${framework}.xcframework/Info.plist`);
+  if (infoData === undefined) {
+    fail(`SwiftPM Apple XCFramework asset is missing ${framework}.xcframework/Info.plist: ${file}`);
+  }
+  const info = parsePlist(infoData, file);
+  if (info === null || Array.isArray(info) || typeof info !== 'object') {
+    fail(`SwiftPM Apple XCFramework Info.plist must be a plist dictionary in ${file}`);
+  }
+  const libraries = info.AvailableLibraries;
+  if (!Array.isArray(libraries) || libraries.length === 0) {
+    fail(`SwiftPM Apple XCFramework Info.plist has no AvailableLibraries in ${file}`);
+  }
+
+  const slices = new Set();
+  for (const library of libraries) {
+    if (library === null || Array.isArray(library) || typeof library !== 'object') {
+      continue;
+    }
+    const platform = library.SupportedPlatform;
+    const variant = library.SupportedPlatformVariant ?? '';
+    const libraryPath = library.LibraryPath;
+    const identifier = library.LibraryIdentifier;
+    const architectures = library.SupportedArchitectures;
+    if (
+      typeof platform !== 'string' ||
+      typeof libraryPath !== 'string' ||
+      typeof identifier !== 'string' ||
+      !Array.isArray(architectures) ||
+      architectures.some((architecture) => typeof architecture !== 'string')
+    ) {
+      continue;
+    }
+    for (const architecture of architectures) {
+      slices.add(`${platform}\0${typeof variant === 'string' ? variant : ''}\0${architecture}`);
+    }
+    const candidate = `${framework}.xcframework/${identifier}/${libraryPath}`;
+    if (
+      !archive.names.has(candidate) &&
+      !Array.from(archive.names).some((name) => name.startsWith(`${candidate}/`))
+    ) {
+      fail(`SwiftPM Apple XCFramework is missing declared library ${candidate}`);
+    }
+  }
+
+  const missing = missingRequiredAppleArm64Slices(slices);
+  if (missing.length > 0) {
+    fail(
+      `SwiftPM Apple XCFramework asset ${file} is missing required arm64 slice(s): ${missing.join(', ')}`,
+    );
+  }
+}
+
+export function missingRequiredAppleArm64Slices(slices) {
+  const required = [
+    ['macos', '', 'arm64'],
+    ['ios', '', 'arm64'],
+    ['ios', 'simulator', 'arm64'],
+  ];
+  return required
+    .filter(
+      ([platform, variant, architecture]) =>
+        !slices.has(`${platform}\0${variant}\0${architecture}`),
+    )
+    .map(
+      ([platform, variant, architecture]) =>
+        `${platform}${variant ? `-${variant}` : ''}-${architecture}`,
+    )
+    .sort();
+}
+
+export async function fetchText(url, { fetchImpl = fetch, timeoutMs = 20_000 } = {}) {
+  const response = await fetchImpl(url, {
+    redirect: 'follow',
+    signal: AbortSignal.timeout(timeoutMs),
+  });
+  if (!response.ok) {
+    await response.body?.cancel?.().catch(() => {});
+    throw new Error(`HTTP ${response.status}`);
+  }
+  const contentLength = response.headers?.get?.('content-length');
+  if (contentLength !== null && contentLength !== undefined) {
+    const declared = Number(contentLength);
+    if (!Number.isSafeInteger(declared) || declared < 0) {
+      await response.body?.cancel?.().catch(() => {});
+      throw new Error('checksum manifest returned an invalid Content-Length');
+    }
+    if (declared > MAX_REMOTE_CHECKSUM_MANIFEST_BYTES) {
+      await response.body?.cancel?.().catch(() => {});
+      throw new Error(`checksum manifest exceeds ${MAX_REMOTE_CHECKSUM_MANIFEST_BYTES} bytes`);
+    }
+  }
+  const reader = response.body?.getReader?.();
+  if (reader === undefined) {
+    const text = await response.text();
+    if (Buffer.byteLength(text) > MAX_REMOTE_CHECKSUM_MANIFEST_BYTES) {
+      throw new Error(`checksum manifest exceeds ${MAX_REMOTE_CHECKSUM_MANIFEST_BYTES} bytes`);
+    }
+    return text;
+  }
+  const chunks = [];
+  let size = 0;
+  try {
+    for (;;) {
+      const { done, value } = await reader.read();
+      if (done) break;
+      size += value.byteLength;
+      if (size > MAX_REMOTE_CHECKSUM_MANIFEST_BYTES) {
+        await reader.cancel().catch(() => {});
+        throw new Error(`checksum manifest exceeds ${MAX_REMOTE_CHECKSUM_MANIFEST_BYTES} bytes`);
+      }
+      chunks.push(Buffer.from(value));
+    }
+  } finally {
+    reader.releaseLock();
+  }
+  return Buffer.concat(chunks, size).toString('utf8');
+}
+
+async function resolveChecksum(assetDir, assetBaseUrl, asset, version) {
+  const localAsset = path.join(assetDir, asset);
+  const localAssetStat = await fileStat(localAsset);
+  if (localAssetStat?.isFile()) {
+    if (localAssetStat.size <= 0) {
+      fail(`SwiftPM Apple XCFramework asset is empty: ${localAsset}`);
+    }
+    await validateAppleXcframeworkAsset(localAsset);
+    return sha256(localAsset);
+  }
+
+  const localManifest = path.join(assetDir, `liboliphaunt-${version}-release-assets.sha256`);
+  if (await isFile(localManifest)) {
+    const checksum = checksumFromManifest(await fs.readFile(localManifest, 'utf8'), asset);
+    if (checksum) {
+      return checksum;
+    }
+  }
+
+  const manifestUrl = `${assetBaseUrl.replace(/\/+$/u, '')}/liboliphaunt-${version}-release-assets.sha256`;
+  let text;
+  try {
+    text = await fetchText(manifestUrl);
+  } catch (error) {
+    fail(
+      `SwiftPM asset ${asset} is not present in ${assetDir}, and checksum ` +
+        `manifest could not be read from ${manifestUrl}: ${error.message}`,
+    );
+  }
+  const checksum = checksumFromManifest(text, asset);
+  if (!checksum) {
+    fail(`checksum manifest ${manifestUrl} does not contain ${asset}`);
+  }
+  return checksum;
+}
+
+function renderManifest(
+  assetBaseUrl,
+  liboliphauntVersion,
+  checksum,
+  bindingsUrl,
+  bindingsChecksum,
+) {
+  const asset = `liboliphaunt-${liboliphauntVersion}-apple-spm-xcframework.zip`;
+  const url = `${assetBaseUrl.replace(/\/+$/u, '')}/${asset}`;
+  return `// swift-tools-version: 6.0
+
+import PackageDescription
+
+// Generated by src/sdks/swift/tools/render_swiftpm_release_package.mts.
+// This is the public SwiftPM release manifest. The source package under
+// src/sdks/swift remains the local development package.
+// Exact PostgreSQL extensions are released as separate opt-in extension
+// artifacts. The base Swift package must not require or publish extension files.
+let package = Package(
+    name: "Oliphaunt",
+    platforms: [
+        .iOS(.v17),
+        .macOS(.v14)
+    ],
+    products: [
+        .library(name: "COliphaunt", targets: ["COliphaunt"]),
+        .library(name: "Oliphaunt", targets: ["Oliphaunt"]),
+        .library(name: "OliphauntExtensionSupport", targets: ["OliphauntExtensionSupport"])
+    ],
+    targets: [
+        .binaryTarget(
+            name: "OliphauntNativeBindingsFFI",
+            url: "${bindingsUrl}",
+            checksum: "${bindingsChecksum}"
+        ),
+        .target(
+            name: "OliphauntNativeBindings",
+            dependencies: ["OliphauntNativeBindingsFFI"],
+            path: "src/sdks/swift/Sources/OliphauntNativeBindings"
+        ),
+        .binaryTarget(
+            name: "liboliphaunt",
+            url: "${url}",
+            checksum: "${checksum}"
+        ),
+        .target(
+            name: "COliphaunt",
+            dependencies: ["liboliphaunt"],
+            path: "src/sdks/swift/Sources/COliphaunt",
+            publicHeadersPath: "include",
+            cSettings: [.define("OLIPHAUNT_LINK_RUNTIME")]
+        ),
+        .target(
+            name: "Oliphaunt",
+            dependencies: ["COliphaunt", "OliphauntNativeBindings"],
+            path: "src/sdks/swift/Sources/Oliphaunt"
+        ),
+        .target(
+            name: "OliphauntExtensionSupport",
+            dependencies: ["COliphaunt", "Oliphaunt"],
+            path: "src/sdks/swift/Sources/OliphauntExtensionSupport"
+        )
+    ]
+)
+`;
+}
+
+function parseArgs(argv) {
+  const usage =
+    'usage: src/sdks/swift/tools/render_swiftpm_release_package.mts [--asset-dir DIR] [--asset-base-url URL] [--output FILE] [--generated-tree DIR]';
+  if (argv.length === 1 && (argv[0] === '--help' || argv[0] === '-h')) {
+    console.log(usage);
+    process.exit(0);
+  }
+  const args = {};
+  for (let index = 0; index < argv.length; index += 1) {
+    let arg = argv[index];
+    if (!arg.startsWith('--')) {
+      fail(usage);
+    }
+    let value;
+    const equals = arg.indexOf('=');
+    if (equals >= 0) {
+      value = arg.slice(equals + 1);
+      arg = arg.slice(0, equals);
+    } else {
+      value = argv[index + 1];
+      if (value === undefined || value.startsWith('--')) {
+        fail(`${arg} requires a value`);
+      }
+      index += 1;
+    }
+    if (
+      ![
+        '--asset-dir',
+        '--asset-base-url',
+        '--bindings-asset-dir',
+        '--output',
+        '--generated-tree',
+      ].includes(arg)
+    ) {
+      fail(`unknown argument ${arg}`);
+    }
+    args[arg.slice(2)] = value;
+  }
+  return {
+    assetBaseUrl: args['asset-base-url'],
+    bindingsAssetDir: args['bindings-asset-dir'] ?? 'target/oliphaunt-swift/release-assets',
+    assetDir: args['asset-dir'] ?? 'target/liboliphaunt/release-assets',
+    generatedTree: args['generated-tree'],
+    output: args.output,
+  };
+}
+
+export async function renderSwiftpmReleasePackage(argv) {
+  const args = parseArgs(argv);
+  const liboliphauntVersion = productCompatibilityVersion(
+    'oliphaunt-swift',
+    'liboliphaunt-native',
+    'render_swiftpm_release_package.mts',
+  );
+  const assetDir = path.resolve(ROOT, args.assetDir);
+  const asset = `liboliphaunt-${liboliphauntVersion}-apple-spm-xcframework.zip`;
+  const assetBaseUrl =
+    args.assetBaseUrl ??
+    `https://github.com/${REPOSITORY}/releases/download/liboliphaunt-native-v${liboliphauntVersion}`;
+  const checksum = await resolveChecksum(assetDir, assetBaseUrl, asset, liboliphauntVersion);
+  const swiftVersion = (
+    await fs.readFile(path.join(ROOT, 'src/sdks/swift/VERSION'), 'utf8')
+  ).trim();
+  const bindingsAsset = `oliphaunt-swift-${swiftVersion}-bindings.xcframework.zip`;
+  const bindingsFile = path.resolve(ROOT, args.bindingsAssetDir, bindingsAsset);
+  await validateAppleXcframeworkAsset(bindingsFile, 'OliphauntNativeBindingsFFI');
+  const bindingsEntries = readPortableArchiveEntries(bindingsFile, { format: 'zip' });
+  for (const target of ['ios-arm64', 'ios-simulator-arm64', 'macos-arm64']) {
+    await assertRustDependencyLicensesInEntries(bindingsEntries, {
+      target,
+      prefix: `OliphauntNativeBindingsFFI.xcframework/licenses/${target}`,
+      label: bindingsFile,
+    });
+  }
+  const bindingsChecksum = await sha256(bindingsFile);
+  const bindingsUrl = `https://github.com/${REPOSITORY}/releases/download/oliphaunt-swift-v${swiftVersion}/${bindingsAsset}`;
+  const generatedTree = args.generatedTree ? path.resolve(ROOT, args.generatedTree) : undefined;
+  if (generatedTree !== undefined) {
+    await fs.mkdir(generatedTree, { recursive: true });
+    const sources = path.join(generatedTree, 'src/sdks/swift/Sources/OliphauntNativeBindings');
+    await fs.mkdir(sources, { recursive: true });
+    await fs.copyFile(
+      path.join(ROOT, 'target/mobile-bindings/generated/OliphauntNativeBindings.swift'),
+      path.join(sources, 'OliphauntNativeBindings.swift'),
+    );
+  }
+  const manifest = renderManifest(
+    assetBaseUrl,
+    liboliphauntVersion,
+    checksum,
+    bindingsUrl,
+    bindingsChecksum,
+  );
+  if (args.output) {
+    const output = path.resolve(ROOT, args.output);
+    await fs.mkdir(path.dirname(output), { recursive: true });
+    await fs.writeFile(output, manifest, 'utf8');
+  } else {
+    process.stdout.write(manifest);
+  }
+}
+
+if (import.meta.main) {
+  await renderSwiftpmReleasePackage(Bun.argv.slice(2));
+}
diff --git a/src/sdks/swift/tools/render_swiftpm_release_package.test.mts b/src/sdks/swift/tools/render_swiftpm_release_package.test.mts
new file mode 100644
index 000000000..6aba9045c
--- /dev/null
+++ b/src/sdks/swift/tools/render_swiftpm_release_package.test.mts
@@ -0,0 +1,46 @@
+import { describe, expect, test } from 'bun:test';
+
+import { fetchText, missingRequiredAppleArm64Slices } from './render_swiftpm_release_package.mts';
+
+describe('SwiftPM Apple carrier architecture contract', () => {
+  test('accepts the three published arm64 slices', () => {
+    expect(
+      missingRequiredAppleArm64Slices(
+        new Set(['macos\0\0arm64', 'ios\0\0arm64', 'ios\0simulator\0arm64']),
+      ),
+    ).toEqual([]);
+  });
+
+  test('does not mistake Intel-only slices for the published arm64 support', () => {
+    expect(
+      missingRequiredAppleArm64Slices(new Set(['macos\0\0x86_64', 'ios\0simulator\0x86_64'])),
+    ).toEqual(['ios-arm64', 'ios-simulator-arm64', 'macos-arm64']);
+  });
+});
+
+describe('SwiftPM remote checksum manifest', () => {
+  test('uses a bounded, timed request that permits the release-asset redirect', async () => {
+    let request;
+    const text = await fetchText('https://github.example/release/checksums', {
+      fetchImpl: async (url, options) => {
+        request = { url, options };
+        return new Response('a'.repeat(64) + '  ./asset.zip\n');
+      },
+      timeoutMs: 1_000,
+    });
+    expect(text).toContain('./asset.zip');
+    expect(request.options.redirect).toBe('follow');
+    expect(request.options.signal).toBeInstanceOf(AbortSignal);
+  });
+
+  test('rejects an oversized checksum manifest before reading it', async () => {
+    await expect(
+      fetchText('https://github.example/release/checksums', {
+        fetchImpl: async () =>
+          new Response('x', {
+            headers: { 'content-length': String(1024 * 1024 + 1) },
+          }),
+      }),
+    ).rejects.toThrow('checksum manifest exceeds 1048576 bytes');
+  });
+});
diff --git a/src/sdks/swift/tools/stage-release-artifacts.mts b/src/sdks/swift/tools/stage-release-artifacts.mts
new file mode 100644
index 000000000..f13c6221e
--- /dev/null
+++ b/src/sdks/swift/tools/stage-release-artifacts.mts
@@ -0,0 +1,129 @@
+import { renderSwiftpmReleasePackage } from './render_swiftpm_release_package.mts';
+import { bundleJavaScript, emitJavaScript } from '../../../../tools/packaging/emit-javascript.mts';
+import { copyFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { createDeterministicZip } from '../../../../tools/packaging/archive-directory.mts';
+import { extractPortableArchiveTree } from '../../../../tools/packaging/portable-archive.mts';
+
+import { IOS_CARRIER_FILENAME, buildIosCarrierManifest } from './ios-carrier-manifest.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  stageReleaseNotices,
+} from '../../../../tools/packaging/release-notices.mts';
+import { productCompatibilityVersion } from '../../../../tools/release/release-graph.mts';
+import { validateSwiftSourceReleaseContract } from './swift-source-carrier-contract.mts';
+import {
+  ROOT,
+  copyDirContents,
+  fail,
+  rel,
+  requireFile,
+} from '../../../../tools/packaging/staging.mts';
+
+const PREFIX = 'swift stage-release-artifacts.mts';
+
+export async function stageArtifacts(artifactRoot, workRoot) {
+  const swiftSourceArchive = path.join(
+    ROOT,
+    'target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/Oliphaunt-source.zip',
+  );
+  requireFile(swiftSourceArchive);
+  const stagedSourceArchive = path.join(artifactRoot, 'Oliphaunt-source.zip');
+  copyFileSync(swiftSourceArchive, stagedSourceArchive);
+  const assetDir = process.env.OLIPHAUNT_SWIFT_RELEASE_ASSET_DIR;
+  if (!assetDir) {
+    fail('oliphaunt-swift package artifacts require OLIPHAUNT_SWIFT_RELEASE_ASSET_DIR');
+  }
+  await renderSwiftpmReleasePackage([
+    '--asset-dir',
+    assetDir,
+    '--output',
+    path.join(artifactRoot, 'Package.swift.release'),
+    '--generated-tree',
+    path.join(workRoot, 'swiftpm-release-tree'),
+  ]);
+  const releaseTree = path.join(artifactRoot, 'release-tree');
+  rmSync(releaseTree, { recursive: true, force: true });
+  copyDirContents(path.join(workRoot, 'swiftpm-release-tree'), releaseTree);
+  stageReleaseNotices(releaseTree);
+  assertReleaseNoticesInDirectory(releaseTree);
+  const carrier = buildIosCarrierManifest({
+    baseAssetDir: assetDir,
+    extensionManifests: [],
+  });
+  const carrierFile = path.join(releaseTree, 'src/sdks/swift/Carriers', IOS_CARRIER_FILENAME);
+  mkdirSync(path.dirname(carrierFile), { recursive: true });
+  writeFileSync(carrierFile, `${JSON.stringify(carrier, null, 2)}\n`, 'utf8');
+  const manifest = readFileSync(path.join(artifactRoot, 'Package.swift.release'), 'utf8');
+  const swiftVersion = readFileSync(path.join(ROOT, 'src/sdks/swift/VERSION'), 'utf8').trim();
+  const releaseAssets = path.join(artifactRoot, 'release-assets');
+  mkdirSync(releaseAssets, { recursive: true });
+  for (const name of [
+    `oliphaunt-swift-${swiftVersion}-bindings.xcframework.zip`,
+    `oliphaunt-swift-${swiftVersion}-release-assets.sha256`,
+  ]) {
+    copyFileSync(
+      path.join(ROOT, 'target/oliphaunt-swift/release-assets', name),
+      path.join(releaseAssets, name),
+    );
+  }
+  // The downloadable source package is independently buildable: use the
+  // frozen public binary dependencies, not checkout-only Cargo output paths.
+  const sourcePackage = path.join(workRoot, 'source', 'package');
+  extractPortableArchiveTree(swiftSourceArchive, sourcePackage, 'package');
+  const generatedSource = path.join(sourcePackage, 'Sources/OliphauntNativeBindings');
+  mkdirSync(generatedSource, { recursive: true });
+  copyFileSync(
+    path.join(ROOT, 'target/mobile-bindings/generated/OliphauntNativeBindings.swift'),
+    path.join(generatedSource, 'OliphauntNativeBindings.swift'),
+  );
+  writeFileSync(
+    path.join(sourcePackage, 'Package.swift'),
+    manifest.replaceAll('"src/sdks/swift/Sources/', '"Sources/'),
+  );
+  writeFileSync(
+    stagedSourceArchive,
+    await createDeterministicZip(sourcePackage, { keepParent: true }),
+  );
+  assertReleaseNoticesInArchive(stagedSourceArchive, { prefix: 'package' });
+  try {
+    validateSwiftSourceReleaseContract({
+      carrier,
+      expectedNativeVersion: productCompatibilityVersion(
+        'oliphaunt-swift',
+        'liboliphaunt-native',
+        PREFIX,
+      ),
+      label: `${rel(artifactRoot)} source release`,
+      manifestText: manifest,
+    });
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+  if (manifest.includes('file://')) {
+    fail('staged SwiftPM release manifest must not contain local file URLs');
+  }
+  const generatorRoot = path.join(artifactRoot, 'extension-generator');
+  mkdirSync(generatorRoot, { recursive: true });
+  for (const name of [
+    'extension-resource-inventory.mjs',
+    'render-extension-products.mjs',
+    'swift-carrier-resolver.mjs',
+  ]) {
+    const source = path.join(ROOT, 'src/sdks/swift/tools', name.replace(/\.mjs$/, '.mts'));
+    const destination = path.join(generatorRoot, name);
+    if (name === 'swift-carrier-resolver.mjs') {
+      writeFileSync(destination, await bundleJavaScript(source), { mode: 0o644 });
+    } else {
+      emitJavaScript(source, destination);
+    }
+  }
+  copyFileSync(
+    path.join(ROOT, 'src/extensions/generated/sdk/extensions.json'),
+    path.join(generatorRoot, 'extension-owner-catalog.json'),
+  );
+}
+
+import { stageSdkArtifacts } from '../../../../tools/packaging/staging.mts';
+if (import.meta.main) await stageSdkArtifacts('oliphaunt-swift', stageArtifacts);
diff --git a/src/sdks/swift/tools/swift-carrier-resolver.mjs b/src/sdks/swift/tools/swift-carrier-resolver.mjs
deleted file mode 100644
index 38af3d069..000000000
--- a/src/sdks/swift/tools/swift-carrier-resolver.mjs
+++ /dev/null
@@ -1,1297 +0,0 @@
-import { createHash } from "node:crypto";
-import { constants as fsConstants, createReadStream, createWriteStream } from "node:fs";
-import fs from "node:fs/promises";
-import os from "node:os";
-import path from "node:path";
-import { Readable, Transform } from "node:stream";
-import { pipeline } from "node:stream/promises";
-import { fileURLToPath } from "node:url";
-import { spawnSync } from "node:child_process";
-import { createGunzip } from "node:zlib";
-import {
-  createPortablePathCollisionTracker,
-  loadSwiftExtensionInventoryCatalog,
-  validateSwiftExtensionResourceArtifact,
-} from "./extension-resource-inventory.mjs";
-
-const PREFIX = "swift-carrier-resolver";
-const SCHEMA = "oliphaunt-react-native-ios-carrier-v1";
-const EXTENSION_CARRIER_SCHEMA = "oliphaunt-swift-extension-carrier-v1";
-const ID = /^[A-Za-z0-9._-]{1,128}$/u;
-const C_ID = /^[A-Za-z_][A-Za-z0-9_]*$/u;
-const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u;
-const EXTRACTED_CACHE_SCHEMA = "oliphaunt-extracted-carrier-tree-v1";
-const MAX_CARRIER_BYTES = 2 * 1024 * 1024 * 1024;
-const MAX_ZIP_CARRIER_BYTES = 512 * 1024 * 1024;
-// Match the release-side iOS carrier envelope. Current XCFrameworks contain
-// one runtime-resource tree per slice, so the consumer must accept the same
-// bounded archive shape that the producer validates.
-const MAX_ARCHIVE_ENTRIES = 32_768;
-const MAX_ARCHIVE_MEMBER_BYTES = 1024 * 1024 * 1024;
-const MAX_ARCHIVE_EXPANDED_BYTES = 4 * 1024 * 1024 * 1024;
-const ALLOWED_ZIP_EXTRA_FIELDS = new Set([0x5455, 0x5855, 0x7875]);
-
-function compareText(left, right) { return left < right ? -1 : left > right ? 1 : 0; }
-function fail(message) { throw new Error(`${PREFIX}: ${message}`); }
-function object(value, label) {
-  if (value === null || Array.isArray(value) || typeof value !== "object") fail(`${label} must be an object`);
-  return value;
-}
-function exactKeys(value, allowed, label) {
-  const actual = Object.keys(value).sort(compareText);
-  const expected = [...allowed].sort(compareText);
-  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
-    fail(`${label} fields must be exactly ${expected.join(",")}; got ${actual.join(",")}`);
-  }
-}
-function identifier(value, label) {
-  if (typeof value !== "string" || !ID.test(value)) fail(`${label} must be a portable identifier`);
-  return value;
-}
-function cIdentifier(value, label) {
-  if (typeof value !== "string" || !C_ID.test(value)) fail(`${label} must be a C identifier`);
-  return value;
-}
-function stableVersion(value, label) {
-  if (typeof value !== "string" || !STABLE_SEMVER.test(value)) fail(`${label} must be a stable SemVer X.Y.Z version`);
-  return value;
-}
-function ids(value, label) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((row, index) => identifier(row, `${label}[${index}]`)).sort(compareText);
-  if (new Set(rows).size !== rows.length) fail(`${label} repeats an identifier`);
-  return rows;
-}
-function canonicalIds(value, label) {
-  const rows = ids(value, label);
-  if (JSON.stringify(value) !== JSON.stringify(rows)) fail(`${label} must be sorted in ordinal order`);
-  return rows;
-}
-function canonicalRelativeFiles(value, label) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((row, index) => {
-    const relative = safeMember(row, `${label}[${index}]`);
-    if (relative === ".") fail(`${label}[${index}] must name a file`);
-    return relative;
-  });
-  const canonical = [...rows].sort(compareText);
-  if (new Set(rows).size !== rows.length) fail(`${label} repeats a path`);
-  if (JSON.stringify(rows) !== JSON.stringify(canonical)) fail(`${label} must be sorted in ordinal order`);
-  return rows;
-}
-function canonicalSqlFileNames(value, label) {
-  const rows = canonicalIds(value, label);
-  if (rows.some((name) => !name.endsWith(".sql"))) fail(`${label} must contain SQL basenames`);
-  return rows;
-}
-function canonicalSqlFilePrefixes(value, label) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((row, index) => {
-    if (typeof row !== "string" || !/^[A-Za-z0-9_-]{1,128}$/u.test(row)) {
-      fail(`${label}[${index}] must be a dot-free portable SQL basename prefix`);
-    }
-    return row;
-  });
-  const canonical = [...rows].sort(compareText);
-  if (new Set(rows).size !== rows.length) fail(`${label} repeats a prefix`);
-  if (JSON.stringify(rows) !== JSON.stringify(canonical)) fail(`${label} must be sorted in ordinal order`);
-  return rows;
-}
-async function loadCanonicalOwners(ownerCatalogFile) {
-  return loadSwiftExtensionInventoryCatalog(ownerCatalogFile);
-}
-function assertCanonicalOwner(extension, owners, label) {
-  const owner = owners.get(extension.sqlName);
-  if (owner === undefined) fail(`${label} has no generated canonical release owner for ${extension.sqlName}`);
-  if (extension.product !== owner.product) {
-    fail(`${label}.product must be canonical artifact product ${owner.product} for ${extension.sqlName}`);
-  }
-  if (extension.releaseProduct !== owner.releaseProduct) {
-    fail(`${label}.releaseProduct must be canonical owner ${owner.releaseProduct} for ${extension.sqlName}`);
-  }
-}
-function assertOwnerReleaseConsistency(extensions, label) {
-  const releases = new Map();
-  for (const extension of extensions) {
-    const identity = `${extension.version}\0${extension.tag}`;
-    const existing = releases.get(extension.releaseProduct);
-    if (existing !== undefined && existing !== identity) {
-      fail(`${label} assigns inconsistent version/tag identities to release owner ${extension.releaseProduct}`);
-    }
-    releases.set(extension.releaseProduct, identity);
-  }
-}
-async function digest(file) {
-  const hash = createHash("sha256");
-  await pipeline(createReadStream(file), hash);
-  return hash.digest("hex");
-}
-async function stat(file) { return fs.lstat(file).catch((error) => error?.code === "ENOENT" ? undefined : Promise.reject(error)); }
-function run(command, args, label) {
-  const result = spawnSync(command, args, { encoding: "utf8", maxBuffer: 64 * 1024 * 1024 });
-  if (result.error || result.status !== 0) fail(`${label}: ${(result.stderr || result.error?.message || result.stdout).trim()}`);
-  return result.stdout;
-}
-function runWithCwd(command, args, cwd, label) {
-  const result = spawnSync(command, args, { cwd, encoding: "utf8", maxBuffer: 64 * 1024 * 1024 });
-  if (result.error || result.status !== 0) fail(`${label}: ${(result.stderr || result.error?.message || result.stdout).trim()}`);
-  return result.stdout;
-}
-const ZIP_UTF8 = new TextDecoder("utf-8", { fatal: true });
-function zipRange(buffer, offset, length, file, label) {
-  if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(length) || offset < 0 || length < 0 || offset > buffer.length - length) {
-    fail(`${file} has a truncated ZIP ${label}`);
-  }
-  return buffer.subarray(offset, offset + length);
-}
-function zipName(bytes, flags, file, label) {
-  if (bytes.length === 0) fail(`${file} has an empty ZIP ${label}`);
-  if ((flags & 0x0800) === 0 && bytes.some((value) => value >= 0x80)) {
-    fail(`${file} has a non-UTF-8 ZIP ${label}`);
-  }
-  try {
-    return ZIP_UTF8.decode(bytes);
-  } catch {
-    fail(`${file} has an invalid UTF-8 ZIP ${label}`);
-  }
-}
-function zipExtraFields(bytes, file, label) {
-  const seen = new Set();
-  let offset = 0;
-  while (offset < bytes.length) {
-    if (bytes.length - offset < 4) fail(`${file} has a truncated ZIP ${label}`);
-    const id = bytes.readUInt16LE(offset);
-    const size = bytes.readUInt16LE(offset + 2);
-    offset += 4;
-    if (size > bytes.length - offset) fail(`${file} has a truncated ZIP ${label} field 0x${id.toString(16)}`);
-    if (seen.has(id)) fail(`${file} repeats ZIP ${label} field 0x${id.toString(16)}`);
-    if (!ALLOWED_ZIP_EXTRA_FIELDS.has(id)) {
-      fail(`${file} uses unsupported ZIP ${label} field 0x${id.toString(16)}`);
-    }
-    seen.add(id);
-    offset += size;
-  }
-}
-function zipDirectory(buffer, file) {
-  if (buffer.length < 22) fail(`${file} is too short to contain a ZIP end record`);
-  const minimum = Math.max(0, buffer.length - 65_557);
-  let eocd = -1;
-  for (let offset = buffer.length - 22; offset >= minimum; offset -= 1) {
-    if (
-      buffer.readUInt32LE(offset) === 0x06054b50
-      && offset + 22 + buffer.readUInt16LE(offset + 20) === buffer.length
-    ) {
-      eocd = offset;
-      break;
-    }
-  }
-  if (eocd < 0) fail(`${file} has no well-formed ZIP end record`);
-  const disk = buffer.readUInt16LE(eocd + 4);
-  const centralDisk = buffer.readUInt16LE(eocd + 6);
-  const diskEntries = buffer.readUInt16LE(eocd + 8);
-  const entries = buffer.readUInt16LE(eocd + 10);
-  const centralSize = buffer.readUInt32LE(eocd + 12);
-  const centralOffset = buffer.readUInt32LE(eocd + 16);
-  if (
-    disk === 0xffff || centralDisk === 0xffff || diskEntries === 0xffff || entries === 0xffff
-    || centralSize === 0xffffffff || centralOffset === 0xffffffff
-  ) {
-    fail(`${file} uses unsupported ZIP64 metadata`);
-  }
-  if (disk !== 0 || centralDisk !== 0 || diskEntries !== entries) {
-    fail(`${file} uses unsupported multi-disk ZIP metadata`);
-  }
-  if (entries === 0 || centralOffset > eocd || centralSize !== eocd - centralOffset) {
-    fail(`${file} has an invalid or ambiguous ZIP central-directory extent`);
-  }
-  if (entries > MAX_ARCHIVE_ENTRIES) {
-    fail(`${file} exceeds the maximum supported ${MAX_ARCHIVE_ENTRIES} archive entries`);
-  }
-  return { centralEnd: eocd, centralOffset, entries };
-}
-function zipDescriptor(buffer, entry, offset, length, file) {
-  if (length !== 12 && length !== 16) {
-    fail(`${file} has an ambiguous ${length}-byte ZIP gap after ${JSON.stringify(entry.raw)}`);
-  }
-  const descriptor = zipRange(buffer, offset, length, file, `data descriptor for ${JSON.stringify(entry.raw)}`);
-  let cursor = 0;
-  if (length === 16) {
-    if (descriptor.readUInt32LE(0) !== 0x08074b50) {
-      fail(`${file} has an invalid ZIP data-descriptor signature for ${JSON.stringify(entry.raw)}`);
-    }
-    cursor = 4;
-  }
-  if (
-    descriptor.readUInt32LE(cursor) !== entry.crc32
-    || descriptor.readUInt32LE(cursor + 4) !== entry.compressedSize
-    || descriptor.readUInt32LE(cursor + 8) !== entry.size
-  ) {
-    fail(`${file} has a ZIP data descriptor that disagrees with ${JSON.stringify(entry.raw)}`);
-  }
-}
-function zipMemberType(versionMadeBy, externalAttributes, raw, file) {
-  const host = versionMadeBy >>> 8;
-  const unixType = (externalAttributes >>> 16) & 0o170000;
-  const pathDirectory = raw.endsWith("/");
-  const dosDirectory = (externalAttributes & 0x10) !== 0;
-  let type;
-
-  if (host === 3) {
-    if (unixType === 0o100000) {
-      type = "-";
-      if (dosDirectory) {
-        fail(`${file} Unix regular file also carries the DOS directory bit: ${raw}`);
-      }
-    } else if (unixType === 0o040000) {
-      type = "d";
-    } else if (unixType === 0) {
-      fail(`${file} has an ambiguous Unix member type: ${raw}`);
-    } else {
-      fail(`${file} contains a link or special entry: ${raw}`);
-    }
-  } else if (host === 0) {
-    if (unixType !== 0) {
-      fail(`${file} FAT-origin member carries conflicting Unix type metadata: ${raw}`);
-    }
-    if (dosDirectory !== pathDirectory) {
-      fail(`${file} FAT-origin member has inconsistent directory metadata: ${raw}`);
-    }
-    type = pathDirectory ? "d" : "-";
-  } else {
-    fail(`${file} uses unsupported ZIP creator host ${host} for ${raw}`);
-  }
-
-  if ((type === "d") !== pathDirectory) {
-    fail(`${file} member type/path marker mismatch: ${raw}`);
-  }
-  return type;
-}
-async function zipEntries(file) {
-  const buffer = await fs.readFile(file);
-  const { centralEnd, centralOffset, entries: entryCount } = zipDirectory(buffer, file);
-  const entries = [];
-  let expandedBytes = 0;
-  let offset = centralOffset;
-  for (let index = 0; index < entryCount; index += 1) {
-    const header = zipRange(buffer, offset, 46, file, `central header ${index + 1}`);
-    if (header.readUInt32LE(0) !== 0x02014b50) fail(`${file} has an invalid ZIP central header ${index + 1}`);
-    const versionMadeBy = header.readUInt16LE(4);
-    const flags = header.readUInt16LE(8);
-    const method = header.readUInt16LE(10);
-    if ((flags & 0x0001) !== 0 || (flags & 0x0040) !== 0) {
-      fail(`${file} contains an encrypted ZIP member`);
-    }
-    if ((flags & ~0x080e) !== 0) {
-      fail(`${file} uses unsupported ZIP general-purpose flags 0x${flags.toString(16)}`);
-    }
-    if (method !== 0 && method !== 8) fail(`${file} uses unsupported ZIP compression method ${method}`);
-    if (method !== 8 && (flags & 0x0006) !== 0) {
-      fail(`${file} uses deflate-only ZIP flags with compression method ${method}`);
-    }
-    const compressedSize = header.readUInt32LE(20);
-    const size = header.readUInt32LE(24);
-    const nameLength = header.readUInt16LE(28);
-    const extraLength = header.readUInt16LE(30);
-    const commentLength = header.readUInt16LE(32);
-    const diskStart = header.readUInt16LE(34);
-    const externalAttributes = header.readUInt32LE(38);
-    const localOffset = header.readUInt32LE(42);
-    if (compressedSize === 0xffffffff || size === 0xffffffff || localOffset === 0xffffffff || diskStart === 0xffff) {
-      fail(`${file} uses unsupported ZIP64 entry metadata`);
-    }
-    if (diskStart !== 0) fail(`${file} contains a multi-disk ZIP member`);
-    const recordLength = 46 + nameLength + extraLength + commentLength;
-    const record = zipRange(buffer, offset, recordLength, file, `central entry ${index + 1}`);
-    const rawName = Buffer.from(record.subarray(46, 46 + nameLength));
-    const raw = zipName(rawName, flags, file, `member name ${index + 1}`);
-    zipExtraFields(
-      record.subarray(46 + nameLength, 46 + nameLength + extraLength),
-      file,
-      `central extra metadata for ${JSON.stringify(raw)}`,
-    );
-    const type = zipMemberType(versionMadeBy, externalAttributes, raw, file);
-    if (type === "d" && (compressedSize !== 0 || size !== 0)) fail(`${file} has a non-empty directory entry: ${raw}`);
-    if (method === 0 && compressedSize !== size) fail(`${file} has an invalid stored ZIP size for ${raw}`);
-    if (size > MAX_ARCHIVE_MEMBER_BYTES) {
-      fail(`${file} member ${JSON.stringify(raw)} exceeds the maximum expanded member size of ${MAX_ARCHIVE_MEMBER_BYTES} bytes`);
-    }
-    expandedBytes += size;
-    if (!Number.isSafeInteger(expandedBytes) || expandedBytes > MAX_ARCHIVE_EXPANDED_BYTES) {
-      fail(`${file} exceeds the maximum supported expanded archive size`);
-    }
-
-    const local = zipRange(buffer, localOffset, 30, file, `local header for ${JSON.stringify(raw)}`);
-    if (local.readUInt32LE(0) !== 0x04034b50) fail(`${file} has an invalid ZIP local header for ${raw}`);
-    if (local.readUInt16LE(6) !== flags || local.readUInt16LE(8) !== method) {
-      fail(`${file} ZIP local metadata disagrees with ${raw}`);
-    }
-    const localNameLength = local.readUInt16LE(26);
-    const localExtraLength = local.readUInt16LE(28);
-    const localName = zipRange(buffer, localOffset + 30, localNameLength, file, `local name for ${JSON.stringify(raw)}`);
-    if (!localName.equals(rawName)) fail(`${file} ZIP local name disagrees with ${raw}`);
-    zipExtraFields(
-      zipRange(buffer, localOffset + 30 + localNameLength, localExtraLength, file, `local extra metadata for ${JSON.stringify(raw)}`),
-      file,
-      `local extra metadata for ${JSON.stringify(raw)}`,
-    );
-    const descriptor = (flags & 0x0008) !== 0;
-    const localCrc32 = local.readUInt32LE(14);
-    const localCompressedSize = local.readUInt32LE(18);
-    const localSize = local.readUInt32LE(22);
-    if (descriptor) {
-      if (
-        (localCrc32 !== 0 && localCrc32 !== header.readUInt32LE(16))
-        || (localCompressedSize !== 0 && localCompressedSize !== compressedSize)
-        || (localSize !== 0 && localSize !== size)
-      ) {
-        fail(`${file} ZIP local descriptor metadata disagrees with ${raw}`);
-      }
-    } else if (
-      localCrc32 !== header.readUInt32LE(16)
-      || localCompressedSize !== compressedSize
-      || localSize !== size
-    ) {
-      fail(`${file} ZIP local CRC or sizes disagree with ${raw}`);
-    }
-    const dataOffset = localOffset + 30 + localNameLength + localExtraLength;
-    if (dataOffset > centralOffset || compressedSize > centralOffset - dataOffset) {
-      fail(`${file} ZIP payload overlaps the central directory for ${raw}`);
-    }
-    entries.push({
-      compressedSize,
-      crc32: header.readUInt32LE(16),
-      dataEnd: dataOffset + compressedSize,
-      descriptor,
-      localOffset,
-      raw,
-      size,
-      type,
-    });
-    offset += recordLength;
-  }
-  if (offset !== centralEnd) fail(`${file} ZIP central directory contains trailing or missing records`);
-  const extents = [...entries].sort((left, right) => left.localOffset - right.localOffset || left.dataEnd - right.dataEnd);
-  if (extents[0]?.localOffset !== 0) fail(`${file} has unreferenced bytes before its first ZIP local record`);
-  for (let index = 0; index < extents.length; index += 1) {
-    const entry = extents[index];
-    const nextOffset = extents[index + 1]?.localOffset ?? centralOffset;
-    if (entry.dataEnd > nextOffset) fail(`${file} has overlapping ZIP local records`);
-    const gap = nextOffset - entry.dataEnd;
-    if (entry.descriptor) zipDescriptor(buffer, entry, entry.dataEnd, gap, file);
-    else if (gap !== 0) fail(`${file} has an ambiguous ${gap}-byte ZIP gap after ${JSON.stringify(entry.raw)}`);
-  }
-  return entries;
-}
-export function localTarArchiveBinding(archive, pathImplementation = path) {
-  if (typeof archive !== "string" || archive.length === 0) fail("tar archive path must be non-empty");
-  const archiveName = pathImplementation.basename(archive);
-  const cwd = pathImplementation.dirname(archive);
-  if (!archiveName || archiveName === "." || archiveName === pathImplementation.sep) {
-    fail("tar archive path must identify a file");
-  }
-  return { archiveName, cwd };
-}
-function safeMember(value, label) {
-  if (value === ".") return value;
-  if (
-    typeof value !== "string" || value.length === 0 || value.includes("\\") ||
-    value.startsWith("/") || /^[A-Za-z]:/u.test(value) || /[\u0000-\u001f\u007f]/u.test(value)
-  ) fail(`${label} is unsafe`);
-  const parts = value.replace(/^\.\//u, "").split("/");
-  if (parts.some((part) => !part || part === "." || part === "..")) fail(`${label} is unsafe`);
-  const relative = parts.join("/");
-  if (relative !== relative.normalize("NFC")) fail(`${label} must be canonical NFC`);
-  return relative;
-}
-function portableAssetName(value, label) {
-  if (
-    typeof value !== "string" || value.length === 0 || path.posix.basename(value) !== value ||
-    /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) || /[ .]$/u.test(value) ||
-    /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value)
-  ) fail(`${label} must be a portable release asset file name`);
-  return value;
-}
-function asset(value, label, allowFileUrls) {
-  const row = object(value, label);
-  exactKeys(row, ["bytes", "format", "member", "name", "role", "sha256", "url"], label);
-  const role = identifier(row.role, `${label}.role`);
-  portableAssetName(row.name, `${label}.name`);
-  if (
-    !Number.isSafeInteger(row.bytes) || row.bytes <= 0 || row.bytes > MAX_CARRIER_BYTES
-    || !/^[a-f0-9]{64}$/u.test(row.sha256)
-  ) fail(`${label} has invalid or unsupported size/checksum`);
-  if (!["zip", "tar.gz"].includes(row.format)) fail(`${label} has unsupported format`);
-  if ((row.format === "zip" && !row.name.endsWith(".zip")) || (row.format === "tar.gz" && !row.name.endsWith(".tar.gz"))) {
-    fail(`${label}.name does not match format ${row.format}`);
-  }
-  let url;
-  try { url = new URL(row.url); } catch { fail(`${label}.url must be an absolute URL`); }
-  if (url.protocol !== "https:" && !(allowFileUrls && url.protocol === "file:")) fail(`${label}.url must use HTTPS`);
-  let urlName;
-  try { urlName = decodeURIComponent(path.basename(url.pathname)); } catch { fail(`${label}.url contains invalid escaping`); }
-  if (urlName !== row.name) fail(`${label}.url must end with ${row.name}`);
-  return { bytes: row.bytes, format: row.format, member: safeMember(row.member, `${label}.member`), name: row.name, role, sha256: row.sha256, url: url.href };
-}
-function assets(value, label, allowFileUrls) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((row, index) => asset(row, `${label}[${index}]`, allowFileUrls));
-  for (const [description, keys] of [
-    ["asset name", rows.map(({ name }) => name)],
-    ["asset role/member identity", rows.map(({ role, member }) => `${role}\0${member}`)],
-  ]) {
-    if (new Set(keys).size !== keys.length) fail(`${label} repeats an ${description}`);
-  }
-  return rows.sort((left, right) => compareText(`${left.role}\0${left.member}`, `${right.role}\0${right.member}`));
-}
-function carrierEnvelope(value, label, allowFileUrls) {
-  const row = object(value, label);
-  exactKeys(row, ["bytes", "format", "name", "sha256", "url"], label);
-  portableAssetName(row.name, `${label}.name`);
-  if (
-    !Number.isSafeInteger(row.bytes) || row.bytes <= 0 || row.bytes > MAX_CARRIER_BYTES
-    || !/^[a-f0-9]{64}$/u.test(row.sha256)
-  ) {
-    fail(`${label} has invalid or unsupported size/checksum`);
-  }
-  if (!["zip", "tar.gz"].includes(row.format)) fail(`${label} has unsupported format`);
-  if ((row.format === "zip" && !row.name.endsWith(".zip")) || (row.format === "tar.gz" && !row.name.endsWith(".tar.gz"))) {
-    fail(`${label}.name does not match format ${row.format}`);
-  }
-  let url;
-  try { url = new URL(row.url); } catch { fail(`${label}.url must be an absolute URL`); }
-  if (url.protocol !== "https:" && !(allowFileUrls && url.protocol === "file:")) fail(`${label}.url must use HTTPS`);
-  let urlName;
-  try { urlName = decodeURIComponent(path.posix.basename(url.pathname)); } catch { fail(`${label}.url contains invalid escaping`); }
-  if (urlName !== row.name) fail(`${label}.url must end with ${row.name}`);
-  return { bytes: row.bytes, format: row.format, name: row.name, sha256: row.sha256, url: url.href };
-}
-function carrierEnvelopes(value, label, allowFileUrls) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((row, index) => carrierEnvelope(row, `${label}[${index}]`, allowFileUrls));
-  if (new Set(rows.map(({ name }) => name)).size !== rows.length) fail(`${label} repeats a carrier name`);
-  rows.sort((left, right) => compareText(left.name, right.name));
-  return new Map(rows.map((row) => [row.name, row]));
-}
-function assetLocator(value, label, carriers) {
-  const row = object(value, label);
-  exactKeys(row, ["bytes", "carrier", "format", "member", "path", "role", "sha256"], label);
-  const role = identifier(row.role, `${label}.role`);
-  const carrier = portableAssetName(row.carrier, `${label}.carrier`);
-  const envelope = carriers.get(carrier);
-  if (envelope === undefined) fail(`${label}.carrier references undeclared envelope ${carrier}`);
-  const memberPath = safeMember(row.path, `${label}.path`);
-  const member = safeMember(row.member, `${label}.member`);
-  if (
-    !Number.isSafeInteger(row.bytes) || row.bytes <= 0 || row.bytes > MAX_CARRIER_BYTES
-    || !/^[a-f0-9]{64}$/u.test(row.sha256)
-  ) {
-    fail(`${label} has invalid or unsupported logical payload size/checksum`);
-  }
-  if (!["zip", "tar.gz"].includes(row.format)) fail(`${label} has unsupported logical payload format`);
-  if (memberPath === ".") {
-    if (row.bytes !== envelope.bytes || row.sha256 !== envelope.sha256 || row.format !== envelope.format) {
-      fail(`${label} direct payload metadata must exactly match carrier ${carrier}`);
-    }
-  } else {
-    if (envelope.format !== "tar.gz") fail(`${label} nested payload carrier must be a tar.gz archive`);
-    const nestedName = path.posix.basename(memberPath);
-    portableAssetName(nestedName, `${label}.path basename`);
-    if ((row.format === "zip" && !nestedName.endsWith(".zip")) || (row.format === "tar.gz" && !nestedName.endsWith(".tar.gz"))) {
-      fail(`${label}.path does not match logical payload format ${row.format}`);
-    }
-  }
-  return { bytes: row.bytes, carrier, envelope, format: row.format, member, path: memberPath, role, sha256: row.sha256 };
-}
-function assetLocators(value, label, carriers) {
-  if (!Array.isArray(value)) fail(`${label} must be an array`);
-  const rows = value.map((row, index) => assetLocator(row, `${label}[${index}]`, carriers));
-  const identities = rows.map(({ carrier, member, path: memberPath, role }) => `${role}\0${member}\0${carrier}\0${memberPath}`);
-  if (new Set(identities).size !== rows.length) fail(`${label} repeats an asset locator identity`);
-  return rows.sort((left, right) => compareText(
-    `${left.role}\0${left.member}\0${left.carrier}\0${left.path}`,
-    `${right.role}\0${right.member}\0${right.carrier}\0${right.path}`,
-  ));
-}
-function oneRole(rows, role, label) {
-  const matches = rows.filter((row) => row.role === role);
-  if (matches.length !== 1) fail(`${label} must have exactly one ${role} asset`);
-  return matches[0];
-}
-function registration(value, label) {
-  const row = object(value, label);
-  exactKeys(row, ["initSymbol", "magicSymbol", "symbols"], label);
-  const initSymbol = row.initSymbol === null ? null : cIdentifier(row.initSymbol, `${label}.initSymbol`);
-  const magicSymbol = cIdentifier(row.magicSymbol, `${label}.magicSymbol`);
-  if (!Array.isArray(row.symbols)) fail(`${label}.symbols must be an array`);
-  const symbols = row.symbols.map((raw, index) => {
-    const symbol = object(raw, `${label}.symbols[${index}]`);
-    exactKeys(symbol, ["address", "name"], `${label}.symbols[${index}]`);
-    return {
-      address: cIdentifier(symbol.address, `${label}.symbols[${index}].address`),
-      name: cIdentifier(symbol.name, `${label}.symbols[${index}].name`),
-    };
-  }).sort((left, right) => compareText(`${left.name}\0${left.address}`, `${right.name}\0${right.address}`));
-  if (new Set(symbols.map(({ name }) => name)).size !== symbols.length) fail(`${label}.symbols repeats a SQL symbol`);
-  return { initSymbol, magicSymbol, symbols };
-}
-function validateBase(value, label, allowFileUrls) {
-  const row = object(value, label);
-  exactKeys(row, ["assets", "product", "tag", "version"], label);
-  if (row.product !== "liboliphaunt-native") fail(`${label}.product must be liboliphaunt-native`);
-  const version = stableVersion(row.version, `${label}.version`);
-  if (row.tag !== `${row.product}-v${version}`) fail(`${label}.tag must be ${row.product}-v${version}`);
-  const rows = assets(row.assets, `${label}.assets`, allowFileUrls);
-  const allowed = new Set(["base-xcframework", "icu-data", "runtime-resources"]);
-  const unsupported = [...new Set(rows.filter(({ role }) => !allowed.has(role)).map(({ role }) => role))].sort(compareText);
-  if (unsupported.length) fail(`${label}.assets has unsupported roles: ${unsupported.join(",")}`);
-  const framework = oneRole(rows, "base-xcframework", `${label}.assets`);
-  const runtime = oneRole(rows, "runtime-resources", `${label}.assets`);
-  oneRole(rows, "icu-data", `${label}.assets`);
-  const expectedRuntimeName =
-    `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`;
-  if (runtime.name !== expectedRuntimeName) {
-    fail(`${label} runtime-resources asset must be ${expectedRuntimeName}`);
-  }
-  if (!path.posix.basename(framework.member).endsWith(".xcframework")) fail(`${label} base framework member must be an XCFramework`);
-  return { assets: rows, product: row.product, tag: row.tag, version };
-}
-function validateBaseReference(value, label) {
-  const row = object(value, label);
-  exactKeys(row, ["product", "tag", "version"], label);
-  if (row.product !== "liboliphaunt-native") fail(`${label}.product must be liboliphaunt-native`);
-  const version = stableVersion(row.version, `${label}.version`);
-  if (row.tag !== `${row.product}-v${version}`) fail(`${label}.tag must be ${row.product}-v${version}`);
-  return { product: row.product, tag: row.tag, version };
-}
-function validateDependencyCarrierReference(value, label) {
-  const row = object(value, label);
-  exactKeys(row, ["product", "releaseProduct", "sqlName", "tag", "version"], label);
-  const sqlName = identifier(row.sqlName, `${label}.sqlName`);
-  const product = identifier(row.product, `${label}.product`);
-  if (!product.startsWith("oliphaunt-extension-")) fail(`${label}.product must be an extension artifact product`);
-  const releaseProduct = identifier(row.releaseProduct, `${label}.releaseProduct`);
-  const version = stableVersion(row.version, `${label}.version`);
-  if (row.tag !== `${releaseProduct}-v${version}`) fail(`${label}.tag must be ${releaseProduct}-v${version}`);
-  return { product, releaseProduct, sqlName, tag: row.tag, version };
-}
-function validateExtensionReleaseReference(value, label) {
-  const row = object(value, label);
-  exactKeys(row, ["product", "tag", "version"], label);
-  const product = identifier(row.product, `${label}.product`);
-  const version = stableVersion(row.version, `${label}.version`);
-  if (row.tag !== `${product}-v${version}`) fail(`${label}.tag must be ${product}-v${version}`);
-  return { product, tag: row.tag, version };
-}
-function validateExtension(value, label, carriers) {
-  const row = object(value, label);
-  exactKeys(row, [
-    "assets", "createsExtension", "dataFiles", "dependencies", "extensionSqlFileNames",
-    "extensionSqlFilePrefixes", "nativeDependencies", "nativeModuleStem", "product",
-    "registration", "releaseProduct", "sharedPreloadLibraries", "sqlName", "tag", "version",
-  ], label);
-  const sqlName = identifier(row.sqlName, `${label}.sqlName`);
-  const product = identifier(row.product, `${label}.product`);
-  if (!product.startsWith("oliphaunt-extension-")) fail(`${label}.product must be an extension artifact product`);
-  const releaseProduct = identifier(row.releaseProduct, `${label}.releaseProduct`);
-  const version = stableVersion(row.version, `${label}.version`);
-  if (row.tag !== `${releaseProduct}-v${version}`) fail(`${label}.tag must be ${releaseProduct}-v${version}`);
-  if (typeof row.createsExtension !== "boolean") fail(`${label}.createsExtension must be boolean`);
-  const nativeModuleStem = row.nativeModuleStem === null ? null : identifier(row.nativeModuleStem, `${label}.nativeModuleStem`);
-  const dependencies = canonicalIds(row.dependencies, `${label}.dependencies`);
-  if (dependencies.includes(sqlName)) fail(`${label}.dependencies must not include ${sqlName} itself`);
-  return {
-    assets: assetLocators(row.assets, `${label}.assets`, carriers),
-    createsExtension: row.createsExtension,
-    dataFiles: canonicalRelativeFiles(row.dataFiles, `${label}.dataFiles`),
-    dependencies,
-    extensionSqlFileNames: canonicalSqlFileNames(
-      row.extensionSqlFileNames,
-      `${label}.extensionSqlFileNames`,
-    ),
-    extensionSqlFilePrefixes: canonicalSqlFilePrefixes(
-      row.extensionSqlFilePrefixes,
-      `${label}.extensionSqlFilePrefixes`,
-    ),
-    nativeDependencies: canonicalIds(row.nativeDependencies, `${label}.nativeDependencies`),
-    nativeModuleStem,
-    product,
-    releaseProduct,
-    registration: row.registration === null ? null : registration(row.registration, `${label}.registration`),
-    sharedPreloadLibraries: canonicalIds(
-      row.sharedPreloadLibraries,
-      `${label}.sharedPreloadLibraries`,
-    ),
-    sqlName,
-    tag: row.tag,
-    version,
-  };
-}
-function assertExactCarrierCoverage(carriers, extensions, label) {
-  const referenced = new Set(extensions.flatMap((extension) => extension.assets.map(({ carrier }) => carrier)));
-  const declared = [...carriers.keys()].sort(compareText);
-  const used = [...referenced].sort(compareText);
-  if (JSON.stringify(declared) !== JSON.stringify(used)) {
-    fail(`${label} carrier envelopes must exactly cover referenced logical payloads; declared=${declared.join(",")}, used=${used.join(",")}`);
-  }
-}
-function byteLimitTransform(limit, label) {
-  let bytes = 0;
-  return new Transform({
-    transform(chunk, _encoding, callback) {
-      bytes += chunk.length;
-      if (bytes > limit) {
-        callback(new Error(`${PREFIX}: ${label} exceeds its frozen ${limit}-byte limit`));
-        return;
-      }
-      callback(null, chunk);
-    },
-  });
-}
-async function materialize(row, cacheDir, { offline }) {
-  const directory = path.join(cacheDir, "objects");
-  const output = path.join(directory, `${row.sha256}-${row.name}`);
-  await fs.mkdir(directory, { recursive: true });
-  const existing = await stat(output);
-  if (existing?.isFile() && existing.size === row.bytes && await digest(output) === row.sha256) return output;
-  await fs.rm(output, { force: true, recursive: true });
-  if (offline) fail(`offline cache miss for ${row.name}`);
-  const temporary = `${output}.tmp-${process.pid}-${Date.now()}`;
-  try {
-    const url = new URL(row.url);
-    if (url.protocol === "file:") {
-      const source = fileURLToPath(url);
-      const sourceStat = await stat(source);
-      if (sourceStat?.isFile() !== true || sourceStat.isSymbolicLink()) {
-        fail(`file URL is not a regular non-symlink file: ${row.url}`);
-      }
-      if (sourceStat.size !== row.bytes) {
-        fail(`size mismatch for ${row.name}; expected ${row.bytes}, got ${sourceStat.size}`);
-      }
-      await fs.copyFile(source, temporary, fsConstants.COPYFILE_EXCL);
-    } else {
-      const response = await fetch(url, { redirect: "follow" });
-      if (!response.ok || !response.body || new URL(response.url).protocol !== "https:") fail(`download failed for ${row.url}`);
-      await pipeline(
-        Readable.fromWeb(response.body),
-        byteLimitTransform(row.bytes, `download ${row.name}`),
-        createWriteStream(temporary, { flags: "wx", mode: 0o600 }),
-      );
-    }
-    const actual = await stat(temporary);
-    if (actual?.size !== row.bytes) fail(`size mismatch for ${row.name}`);
-    const actualDigest = await digest(temporary);
-    if (actualDigest !== row.sha256) fail(`checksum mismatch for ${row.name}; got ${actualDigest}`);
-    await fs.rename(temporary, output);
-    return output;
-  } finally { await fs.rm(temporary, { force: true }); }
-}
-
-async function materializeLogicalPayload(locator, carrierFile, cacheDir, carrierMemberCache) {
-  if (locator.path === ".") return carrierFile;
-  const directory = path.join(cacheDir, "payloads");
-  const output = path.join(directory, `${locator.sha256}-${path.posix.basename(locator.path)}`);
-  await fs.mkdir(directory, { recursive: true });
-  const existing = await stat(output);
-  if (
-    existing?.isFile()
-    && !existing.isSymbolicLink()
-    && existing.size === locator.bytes
-    && await digest(output) === locator.sha256
-  ) return output;
-  await fs.rm(output, { force: true, recursive: true });
-
-  let members = carrierMemberCache.get(locator.envelope.sha256);
-  if (members === undefined) {
-    members = await archiveMembers(carrierFile, locator.envelope.format);
-    carrierMemberCache.set(locator.envelope.sha256, members);
-  }
-  if (!members.has(locator.path)) {
-    fail(`${locator.envelope.name} lacks nested logical payload ${locator.path}`);
-  }
-  const temporaryRoot = path.join(directory, `.tmp-${process.pid}-${Date.now()}-${locator.sha256}`);
-  await fs.rm(temporaryRoot, { force: true, recursive: true });
-  await fs.mkdir(temporaryRoot, { recursive: true, mode: 0o700 });
-  try {
-    const outerBinding = localTarArchiveBinding(carrierFile);
-    runWithCwd(
-      "tar",
-      ["-xzf", outerBinding.archiveName, "-C", temporaryRoot, locator.path],
-      outerBinding.cwd,
-      `extract ${locator.path} from ${locator.envelope.name}`,
-    );
-    const selected = path.join(temporaryRoot, ...locator.path.split("/"));
-    const selectedStat = await stat(selected);
-    if (selectedStat?.isFile() !== true || selectedStat.isSymbolicLink()) {
-      fail(`${locator.envelope.name} nested payload ${locator.path} is not a regular file`);
-    }
-    if (selectedStat.size !== locator.bytes || await digest(selected) !== locator.sha256) {
-      fail(`${locator.envelope.name} nested payload ${locator.path} does not match its frozen size/checksum`);
-    }
-    await fs.rename(selected, output);
-    return output;
-  } finally {
-    await fs.rm(temporaryRoot, { force: true, recursive: true });
-  }
-}
-function tarString(header, offset, length, file) {
-  const field = header.subarray(offset, offset + length);
-  const end = field.indexOf(0);
-  try {
-    return new TextDecoder("utf-8", { fatal: true }).decode(field.subarray(0, end < 0 ? field.length : end));
-  } catch {
-    fail(`${file} contains a non-UTF-8 ustar header field`);
-  }
-}
-function tarOctal(header, offset, length, label, file) {
-  const value = header.subarray(offset, offset + length).toString("ascii").replaceAll("\0", "").trim();
-  if (value !== "" && !/^[0-7]+$/u.test(value)) fail(`${file} has invalid ustar ${label}`);
-  const parsed = value === "" ? 0 : Number.parseInt(value, 8);
-  if (!Number.isSafeInteger(parsed) || parsed < 0) fail(`${file} has unsafe ustar ${label}`);
-  return parsed;
-}
-async function tarEntries(file) {
-  const entries = [];
-  let currentEntry = "archive header";
-  let expandedBytes = 0;
-  let streamedBytes = 0;
-  let pending = Buffer.alloc(0);
-  let remainingPayload = 0;
-  let terminated = false;
-  let zeroBlocks = 0;
-  try {
-    const stream = createReadStream(file).pipe(createGunzip());
-    for await (const chunk of stream) {
-      streamedBytes += chunk.length;
-      if (
-        !Number.isSafeInteger(streamedBytes)
-        || streamedBytes > MAX_ARCHIVE_EXPANDED_BYTES + MAX_ARCHIVE_ENTRIES * 1024 + 1024
-      ) {
-        fail(`${file} exceeds the maximum supported expanded archive size`);
-      }
-      let offset = 0;
-      while (offset < chunk.length) {
-        if (terminated) {
-          if (!chunk.subarray(offset).every((value) => value === 0)) {
-            fail(`${file} has data after its ustar end marker`);
-          }
-          break;
-        }
-        if (remainingPayload > 0) {
-          const consumed = Math.min(remainingPayload, chunk.length - offset);
-          remainingPayload -= consumed;
-          offset += consumed;
-          continue;
-        }
-        const consumed = Math.min(512 - pending.length, chunk.length - offset);
-        pending = pending.length === 0
-          ? Buffer.from(chunk.subarray(offset, offset + consumed))
-          : Buffer.concat([pending, chunk.subarray(offset, offset + consumed)]);
-        offset += consumed;
-        if (pending.length < 512) continue;
-
-        const header = pending;
-        pending = Buffer.alloc(0);
-        if (header.every((value) => value === 0)) {
-          zeroBlocks += 1;
-          if (zeroBlocks >= 2) terminated = true;
-          continue;
-        }
-        if (zeroBlocks > 0) fail(`${file} has an incomplete ustar end marker`);
-
-        const posixUstar = header.subarray(257, 263).equals(Buffer.from("ustar\0"))
-          && header.subarray(263, 265).equals(Buffer.from("00"));
-        const gnuUstar = header.subarray(257, 263).equals(Buffer.from("ustar "))
-          && header[263] === 0x20 && header[264] === 0;
-        if (!posixUstar && !gnuUstar) fail(`${file} contains a non-ustar header`);
-
-        const expectedChecksum = tarOctal(header, 148, 8, "checksum", file);
-        let actualChecksum = 0;
-        for (let index = 0; index < 512; index += 1) {
-          actualChecksum += index >= 148 && index < 156 ? 0x20 : header[index];
-        }
-        if (expectedChecksum !== actualChecksum) fail(`${file} has an invalid ustar header checksum`);
-
-        const name = tarString(header, 0, 100, file);
-        const prefix = tarString(header, 345, 155, file);
-        const raw = prefix ? `${prefix}/${name}` : name;
-        currentEntry = JSON.stringify(raw);
-        const size = tarOctal(header, 124, 12, `size for ${currentEntry}`, file);
-        const typeFlag = header[156];
-        const type = typeFlag === 0 || typeFlag === 0x30 ? "-" : typeFlag === 0x35 ? "d" : null;
-        if (type === null) fail(`${file} contains a link or special entry: ${raw}`);
-        if (type === "d" && size !== 0) fail(`${file} has a non-empty directory entry: ${raw}`);
-        if (size > MAX_ARCHIVE_MEMBER_BYTES) {
-          fail(`${file} member ${currentEntry} exceeds the maximum supported member size`);
-        }
-        expandedBytes += size;
-        if (!Number.isSafeInteger(expandedBytes) || expandedBytes > MAX_ARCHIVE_EXPANDED_BYTES) {
-          fail(`${file} exceeds the maximum supported expanded archive size`);
-        }
-        remainingPayload = Math.ceil(size / 512) * 512;
-        if (!Number.isSafeInteger(remainingPayload)) fail(`${file} has unsafe padded size for ${currentEntry}`);
-        if (entries.length >= MAX_ARCHIVE_ENTRIES) {
-          fail(`${file} exceeds the maximum supported ${MAX_ARCHIVE_ENTRIES} archive entries`);
-        }
-        entries.push({ raw, type });
-      }
-    }
-  } catch (error) {
-    if (error instanceof Error && error.message.startsWith(`${PREFIX}:`)) throw error;
-    fail(`${file} is not a readable gzip tar archive: ${error.message}`);
-  }
-  if (remainingPayload > 0) fail(`${file} has a truncated entry: ${currentEntry}`);
-  if (pending.length > 0) fail(`${file} has a truncated ustar header`);
-  if (!terminated) fail(`${file} is missing its two-block ustar end marker`);
-  return entries;
-}
-async function archiveMembers(file, format) {
-  const archiveStat = await stat(file);
-  if (archiveStat?.isFile() !== true || archiveStat.isSymbolicLink()) {
-    fail(`${file} is not a regular archive file`);
-  }
-  if (archiveStat.size <= 0 || archiveStat.size > MAX_CARRIER_BYTES) {
-    fail(`${file} exceeds the maximum supported carrier size of ${MAX_CARRIER_BYTES} bytes`);
-  }
-  if (format === "zip" && archiveStat.size > MAX_ZIP_CARRIER_BYTES) {
-    fail(`${file} exceeds the maximum supported ZIP carrier size of ${MAX_ZIP_CARRIER_BYTES} bytes`);
-  }
-  let entries;
-  if (format === "tar.gz") {
-    entries = await tarEntries(file);
-  } else {
-    entries = await zipEntries(file);
-  }
-  if (entries.length === 0) fail(`${file} has no archive members`);
-  const normalizedEntries = entries.map(({ raw, type }) => {
-    if (!["-", "d"].includes(type)) fail(`${file} contains a link or special entry: ${raw}`);
-    const directoryMarker = raw.endsWith("/");
-    // A POSIX tar typeflag 5 is sufficient to identify a directory; the slash
-    // is a canonical producer convention, not a tar-format requirement. ZIP
-    // still requires its path marker and metadata type to agree.
-    const markerMismatch = format === "zip"
-      ? (type === "d") !== directoryMarker
-      : type !== "d" && directoryMarker;
-    if (markerMismatch && raw !== "." && raw !== "./") {
-      fail(`${file} member type/path marker mismatch: ${raw}`);
-    }
-    return {
-      name: safeMember(raw.replace(/\/$/u, "") || ".", `${file} member`),
-      type: type === "d" ? "directory" : "file",
-    };
-  });
-  const names = normalizedEntries.map(({ name }) => name);
-  if (new Set(names).size !== names.length) fail(`${file} repeats a normalized archive member`);
-  const trackPortablePath = createPortablePathCollisionTracker(`${PREFIX}: ${file}`);
-  for (const name of names) trackPortablePath(name);
-  const files = new Set(normalizedEntries.filter(({ type }) => type === "file").map(({ name }) => name));
-  for (const entry of normalizedEntries) {
-    let separator = entry.name.indexOf("/");
-    while (separator >= 0) {
-      const parent = entry.name.slice(0, separator);
-      if (files.has(parent)) fail(`${file} uses file ${parent} as an archive directory`);
-      separator = entry.name.indexOf("/", separator + 1);
-    }
-  }
-  return new Map(normalizedEntries.map(({ name, type }) => [name, type]));
-}
-function jsonDigest(value) {
-  return createHash("sha256").update(JSON.stringify(value)).digest("hex");
-}
-async function extractedTree(root) {
-  const entries = [];
-  const pending = [{ directory: root, relative: "" }];
-  let expandedBytes = 0;
-  while (pending.length) {
-    const { directory, relative } = pending.pop();
-    for (const name of (await fs.readdir(directory)).sort(compareText).reverse()) {
-      const child = path.join(directory, name);
-      const childRelative = relative ? `${relative}/${name}` : name;
-      safeMember(childRelative, `${root} extracted member`);
-      const info = await fs.lstat(child);
-      if (info.isSymbolicLink() || (!info.isFile() && !info.isDirectory())) fail(`unsafe extracted entry ${child}`);
-      if (info.isDirectory()) {
-        entries.push({ path: childRelative, type: "directory" });
-        pending.push({ directory: child, relative: childRelative });
-      } else {
-        if (info.size > MAX_ARCHIVE_MEMBER_BYTES) {
-          fail(`${root} extracted member ${childRelative} exceeds the maximum supported member size`);
-        }
-        expandedBytes += info.size;
-        if (!Number.isSafeInteger(expandedBytes) || expandedBytes > MAX_ARCHIVE_EXPANDED_BYTES) {
-          fail(`${root} extracted tree exceeds the maximum supported expanded size`);
-        }
-        entries.push({
-          bytes: info.size,
-          executable: (info.mode & 0o111) !== 0,
-          path: childRelative,
-          sha256: await digest(child),
-          type: "file",
-        });
-      }
-      if (entries.length > MAX_ARCHIVE_ENTRIES) {
-        fail(`${root} extracted tree exceeds the maximum supported ${MAX_ARCHIVE_ENTRIES} entries`);
-      }
-    }
-  }
-  entries.sort((left, right) => compareText(left.path, right.path));
-  return entries;
-}
-
-function assertArchiveTreeMatches(members, tree, file) {
-  const expected = [...members]
-    .filter(([name]) => name !== ".")
-    .sort(([left], [right]) => compareText(left, right));
-  const actual = tree
-    .map(({ path: name, type }) => [name, type])
-    .sort(([left], [right]) => compareText(left, right));
-  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
-    fail(`${file} extracted tree does not exactly match its validated archive member plan`);
-  }
-}
-
-export async function extractVerifiedZipArchive({ archive, destination }) {
-  const archivePath = path.resolve(archive);
-  const destinationPath = path.resolve(destination);
-  const archiveStat = await stat(archivePath);
-  if (archiveStat?.isFile() !== true || archiveStat.isSymbolicLink()) {
-    fail(`ZIP archive is not a regular file: ${archivePath}`);
-  }
-  if (await stat(destinationPath) !== undefined) {
-    fail(`verified ZIP destination already exists: ${destinationPath}`);
-  }
-  const members = await archiveMembers(archivePath, "zip");
-  const parent = path.dirname(destinationPath);
-  await fs.mkdir(parent, { recursive: true });
-  const parentStat = await stat(parent);
-  if (parentStat?.isDirectory() !== true || parentStat.isSymbolicLink()) {
-    fail(`verified ZIP destination parent is unsafe: ${parent}`);
-  }
-  const temporary = `${destinationPath}.tmp-${process.pid}-${Date.now()}`;
-  await fs.rm(temporary, { force: true, recursive: true });
-  await fs.mkdir(temporary, { mode: 0o700 });
-  try {
-    run("unzip", ["-q", archivePath, "-d", temporary], `extract ${archivePath}`);
-    const tree = await extractedTree(temporary);
-    assertArchiveTreeMatches(members, tree, archivePath);
-    if (!tree.some(({ type }) => type === "file")) {
-      fail(`${archivePath} contains no regular files`);
-    }
-    await fs.rename(temporary, destinationPath);
-    return tree;
-  } finally {
-    await fs.rm(temporary, { force: true, recursive: true });
-  }
-}
-
-async function extractedCacheValid(root, manifestFile, archiveSha256) {
-  if ((await stat(root))?.isDirectory() !== true || (await stat(manifestFile))?.isFile() !== true) return false;
-  try {
-    const manifest = object(JSON.parse(await fs.readFile(manifestFile, "utf8")), manifestFile);
-    exactKeys(manifest, ["archiveSha256", "entries", "schema", "treeSha256"], manifestFile);
-    if (manifest.schema !== EXTRACTED_CACHE_SCHEMA || manifest.archiveSha256 !== archiveSha256 || !Array.isArray(manifest.entries)) return false;
-    if (manifest.treeSha256 !== jsonDigest(manifest.entries)) return false;
-    const actual = await extractedTree(root);
-    return manifest.treeSha256 === jsonDigest(actual) && JSON.stringify(manifest.entries) === JSON.stringify(actual);
-  } catch {
-    return false;
-  }
-}
-async function extract(row, archive, cacheDir) {
-  const output = path.join(cacheDir, "extracted", row.sha256);
-  const cacheManifest = `${output}.tree.json`;
-  if (await extractedCacheValid(output, cacheManifest, row.sha256)) {
-    return row.member === "." ? output : path.join(output, row.member);
-  }
-  await fs.rm(output, { recursive: true, force: true });
-  await fs.rm(cacheManifest, { force: true });
-  const members = await archiveMembers(archive, row.format);
-  if (row.member !== "." && !members.has(row.member) && ![...members.keys()].some((entry) => entry.startsWith(`${row.member}/`))) fail(`${row.name} lacks ${row.member}`);
-  const temporary = `${output}.tmp-${process.pid}-${Date.now()}`;
-  const temporaryManifest = `${cacheManifest}.tmp-${process.pid}-${Date.now()}`;
-  await fs.rm(temporary, { recursive: true, force: true });
-  await fs.mkdir(temporary, { recursive: true });
-  try {
-    if (row.format === "zip") run("unzip", ["-q", archive, "-d", temporary], `extract ${row.name}`);
-    else {
-      const innerBinding = localTarArchiveBinding(archive);
-      runWithCwd(
-        "tar",
-        ["-xzf", innerBinding.archiveName, "-C", temporary],
-        innerBinding.cwd,
-        `extract ${row.envelope.name}`,
-      );
-    }
-    const tree = await extractedTree(temporary);
-    if (row.format === "zip") assertArchiveTreeMatches(members, tree, archive);
-    const manifest = {
-      archiveSha256: row.sha256,
-      entries: tree,
-      schema: EXTRACTED_CACHE_SCHEMA,
-      treeSha256: jsonDigest(tree),
-    };
-    const selected = row.member === "." ? temporary : path.join(temporary, row.member);
-    if ((await stat(selected))?.isDirectory() !== true) fail(`${row.name} member is not a directory: ${row.member}`);
-    await fs.writeFile(temporaryManifest, `${JSON.stringify(manifest, null, 2)}\n`, { flag: "wx" });
-    await fs.mkdir(path.dirname(output), { recursive: true });
-    await fs.rename(temporary, output);
-    await fs.rename(temporaryManifest, cacheManifest);
-    return row.member === "." ? output : path.join(output, row.member);
-  } catch (error) {
-    await fs.rm(temporary, { recursive: true, force: true });
-    await fs.rm(temporaryManifest, { force: true });
-    await fs.rm(output, { recursive: true, force: true });
-    await fs.rm(cacheManifest, { force: true });
-    throw error;
-  }
-}
-
-export async function resolveSwiftCarrierSelection({
-  carrierFile,
-  extensionCarrierFiles = [],
-  extensions,
-  cacheDir = path.join(os.homedir(), ".cache", "oliphaunt", "swift-extensions"),
-  allowFileUrls = false,
-  offline = false,
-  localBinaryTargets = false,
-  basePackageUrl = "https://github.com/f0rr0/oliphaunt.git",
-  basePackageVersion,
-  ownerCatalogFile = undefined,
-}) {
-  const canonicalOwners = await loadCanonicalOwners(ownerCatalogFile);
-  let document;
-  try { document = JSON.parse(await fs.readFile(carrierFile, "utf8")); } catch (error) { fail(`could not read carrier ${carrierFile}: ${error.message}`); }
-  const root = object(document, carrierFile);
-  exactKeys(root, ["base", "carriers", "extensions", "legal", "schema"], carrierFile);
-  if (root.schema !== SCHEMA) fail(`${carrierFile} has unsupported schema`);
-  const base = validateBase(root.base, `${carrierFile}.base`, allowFileUrls);
-  const rootCarriers = carrierEnvelopes(root.carriers, `${carrierFile}.carriers`, allowFileUrls);
-  if (!Array.isArray(root.extensions)) fail(`${carrierFile}.extensions must be an array`);
-  const validatedExtensions = root.extensions.map((row, index) =>
-    validateExtension(row, `${carrierFile}.extensions[${index}]`, rootCarriers));
-  for (const [index, extension] of validatedExtensions.entries()) {
-    assertCanonicalOwner(extension, canonicalOwners, `${carrierFile}.extensions[${index}]`);
-  }
-  assertOwnerReleaseConsistency(validatedExtensions, `${carrierFile}.extensions`);
-  assertExactCarrierCoverage(rootCarriers, validatedExtensions, carrierFile);
-  const byName = new Map(validatedExtensions.map((row) => [row.sqlName, row]));
-  if (byName.size !== root.extensions.length) fail("carrier repeats an extension row");
-  if (!Array.isArray(extensionCarrierFiles) || extensionCarrierFiles.some((file) => typeof file !== "string" || file.length === 0)) {
-    fail("extensionCarrierFiles must be an array of carrier paths");
-  }
-  const explicitNames = new Set();
-  const membersByCarrier = new Map();
-  const dependencyRequirements = new Map();
-  for (const carrier of extensionCarrierFiles) {
-    let overlayDocument;
-    try {
-      overlayDocument = JSON.parse(await fs.readFile(carrier, "utf8"));
-    } catch (error) {
-      fail(`could not read extension carrier ${carrier}: ${error.message}`);
-    }
-    const overlay = object(overlayDocument, carrier);
-    exactKeys(overlay, ["base", "carriers", "entries", "release", "schema"], carrier);
-    if (overlay.schema !== EXTENSION_CARRIER_SCHEMA) fail(`${carrier} has unsupported extension carrier schema`);
-    const overlayBase = validateBaseReference(overlay.base, `${carrier}.base`);
-    if (
-      overlayBase.product !== base.product
-      || overlayBase.version !== base.version
-      || overlayBase.tag !== base.tag
-    ) {
-      fail(`${carrier} requires ${overlayBase.tag}, but the base carrier provides ${base.tag}`);
-    }
-    const release = validateExtensionReleaseReference(overlay.release, `${carrier}.release`);
-    const overlayCarriers = carrierEnvelopes(overlay.carriers, `${carrier}.carriers`, allowFileUrls);
-    if (!Array.isArray(overlay.entries) || overlay.entries.length === 0) {
-      fail(`${carrier}.entries must be a non-empty array`);
-    }
-    const carrierMembers = new Set();
-    const carrierExtensions = [];
-    for (const [index, rawEntry] of overlay.entries.entries()) {
-      const entry = object(rawEntry, `${carrier}.entries[${index}]`);
-      exactKeys(entry, ["dependencyCarriers", "extension"], `${carrier}.entries[${index}]`);
-      const extension = validateExtension(entry.extension, `${carrier}.entries[${index}].extension`, overlayCarriers);
-      assertCanonicalOwner(extension, canonicalOwners, `${carrier}.entries[${index}].extension`);
-      if (
-        extension.releaseProduct !== release.product
-        || extension.version !== release.version
-        || extension.tag !== release.tag
-      ) {
-        fail(`${carrier}.entries[${index}].extension must be owned by ${release.tag}`);
-      }
-      if (explicitNames.has(extension.sqlName)) {
-        fail(`extension carriers repeat explicit row ${extension.sqlName}`);
-      }
-      if (!Array.isArray(entry.dependencyCarriers)) {
-        fail(`${carrier}.entries[${index}].dependencyCarriers must be an array`);
-      }
-      const requirements = entry.dependencyCarriers.map((row, dependencyIndex) =>
-        validateDependencyCarrierReference(
-          row,
-          `${carrier}.entries[${index}].dependencyCarriers[${dependencyIndex}]`,
-        ));
-      for (const [dependencyIndex, requirement] of requirements.entries()) {
-        const canonicalOwner = canonicalOwners.get(requirement.sqlName);
-        if (
-          canonicalOwner === undefined
-          || requirement.product !== canonicalOwner.product
-          || requirement.releaseProduct !== canonicalOwner.releaseProduct
-        ) {
-          fail(
-            `${carrier}.entries[${index}].dependencyCarriers[${dependencyIndex}] must use canonical artifact/release products `
-              + `${canonicalOwner?.product ?? ""}/${canonicalOwner?.releaseProduct ?? ""} for ${requirement.sqlName}`,
-          );
-        }
-      }
-      if (new Set(requirements.map(({ sqlName }) => sqlName)).size !== requirements.length) {
-        fail(`${carrier}.entries[${index}].dependencyCarriers repeats an extension dependency`);
-      }
-      const requiredNames = requirements.map(({ sqlName }) => sqlName).sort(compareText);
-      if (JSON.stringify(requiredNames) !== JSON.stringify(extension.dependencies)) {
-        fail(`${carrier}.entries[${index}].dependencyCarriers must exactly pin ${extension.sqlName} dependencies`);
-      }
-      explicitNames.add(extension.sqlName);
-      carrierMembers.add(extension.sqlName);
-      carrierExtensions.push(extension);
-      dependencyRequirements.set(extension.sqlName, requirements);
-      byName.set(extension.sqlName, extension);
-    }
-    assertOwnerReleaseConsistency(carrierExtensions, `${carrier}.entries`);
-    assertExactCarrierCoverage(overlayCarriers, carrierExtensions, carrier);
-    membersByCarrier.set(carrier, carrierMembers);
-  }
-  const ordered = [], visiting = new Set(), visited = new Set();
-  function visit(name, parent) {
-    if (visited.has(name)) return;
-    if (visiting.has(name)) fail(`dependency cycle includes ${name}`);
-    const row = byName.get(name);
-    if (!row) fail(`missing carrier for ${name}${parent ? ` required by ${parent}` : ""}`);
-    visiting.add(name);
-    for (const dependency of ids(row.dependencies, `${name}.dependencies`)) visit(dependency, name);
-    visiting.delete(name); visited.add(name); ordered.push(row);
-  }
-  for (const name of ids(extensions, "selected extensions")) visit(name);
-  assertOwnerReleaseConsistency(ordered, "resolved selected extensions");
-  const unusedCarriers = [...membersByCarrier]
-    .filter(([, members]) => ![...members].some((name) => visited.has(name)))
-    .map(([carrier]) => carrier)
-    .sort(compareText);
-  if (unusedCarriers.length > 0) {
-    fail(`extension carrier file(s) supplied no selected or required row: ${unusedCarriers.join(",")}`);
-  }
-  for (const [sqlName, requirements] of dependencyRequirements) {
-    for (const requirement of requirements) {
-      const selected = byName.get(requirement.sqlName);
-      if (
-        selected === undefined
-        || selected.product !== requirement.product
-        || selected.releaseProduct !== requirement.releaseProduct
-        || selected.version !== requirement.version
-        || selected.tag !== requirement.tag
-      ) {
-        fail(
-          `${sqlName} requires dependency carrier ${requirement.tag}, but resolved ` +
-            `${selected?.tag ?? "no carrier"}`,
-        );
-      }
-    }
-  }
-  const output = [];
-  const materializedCarriers = new Map();
-  const carrierMemberCache = new Map();
-  for (const row of ordered) {
-    const nativeDependencies = row.nativeDependencies;
-    const rows = row.assets;
-    const allowedRoles = new Set(["runtime-resources", "extension-xcframework", "dependency-xcframework"]);
-    const unsupportedRoles = [...new Set(rows.filter(({ role }) => !allowedRoles.has(role)).map(({ role }) => role))].sort(compareText);
-    if (unsupportedRoles.length) fail(`${row.sqlName} has unsupported asset roles: ${unsupportedRoles.join(",")}`);
-    const runtimeRows = rows.filter(({ role }) => role === "runtime-resources");
-    if (runtimeRows.length !== 1) fail(`${row.sqlName} must have one runtime-resources asset`);
-    const materialized = new Map();
-    for (const rowAsset of rows) {
-      const carrierKey = `${rowAsset.envelope.sha256}\0${rowAsset.envelope.name}`;
-      let carrierFile = materializedCarriers.get(carrierKey);
-      if (carrierFile === undefined) {
-        carrierFile = await materialize(rowAsset.envelope, cacheDir, { offline });
-        materializedCarriers.set(carrierKey, carrierFile);
-      }
-      materialized.set(
-        rowAsset,
-        await materializeLogicalPayload(rowAsset, carrierFile, cacheDir, carrierMemberCache),
-      );
-    }
-    const runtimeArchive = materialized.get(runtimeRows[0]);
-    const resourceRoot = await extract(runtimeRows[0], runtimeArchive, cacheDir);
-    const stem = row.nativeModuleStem === null ? null : row.nativeModuleStem;
-    const extensionAssets = rows.filter(({ role }) => role === "extension-xcframework");
-    const dependencyAssets = rows.filter(({ role }) => role === "dependency-xcframework").map((rowAsset) => {
-      const match = /^liboliphaunt_dependency_(.+)\.xcframework$/u.exec(path.posix.basename(rowAsset.member));
-      if (!match || !ID.test(match[1])) fail(`${row.sqlName} has malformed dependency framework member`);
-      return { name: match[1], rowAsset };
-    }).sort((left, right) => compareText(left.name, right.name));
-    if (new Set(dependencyAssets.map(({ name }) => name)).size !== dependencyAssets.length) {
-      fail(`${row.sqlName} repeats a dependency carrier identity`);
-    }
-    if (stem === null) {
-      if (extensionAssets.length || dependencyAssets.length || nativeDependencies.length || row.registration !== null) fail(`${row.sqlName} SQL-only carrier fabricates native roles`);
-    } else {
-      if (!ID.test(stem) || extensionAssets.length !== 1 || path.posix.basename(extensionAssets[0].member) !== `liboliphaunt_extension_${stem}.xcframework`) fail(`${row.sqlName} lacks its exact extension XCFramework`);
-      if (JSON.stringify(dependencyAssets.map(({ name }) => name)) !== JSON.stringify(nativeDependencies)) fail(`${row.sqlName} native dependency inventory mismatch`);
-      const prefix = `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`;
-      if (row.registration?.magicSymbol !== `${prefix}_Pg_magic_func` || ![null, `${prefix}__PG_init`].includes(row.registration?.initSymbol)) fail(`${row.sqlName} registration symbols do not match its native stem`);
-    }
-    const binaryAsset = async (rowAsset) => {
-      const requiresLocalPath = localBinaryTargets || rowAsset.path !== ".";
-      return {
-        name: rowAsset.envelope.name,
-        url: rowAsset.envelope.url,
-        checksum: rowAsset.envelope.sha256,
-        ...(requiresLocalPath
-          ? { localPath: await extract(rowAsset, materialized.get(rowAsset), cacheDir) }
-          : {}),
-      };
-    };
-    const resolvedNativeDependencies = [];
-    for (const { name, rowAsset } of dependencyAssets) {
-      resolvedNativeDependencies.push({
-        name,
-        asset: await binaryAsset(rowAsset),
-      });
-    }
-    const primaryAsset = stem === null ? null : await binaryAsset(extensionAssets[0]);
-    const resolvedExtension = {
-      product: row.product,
-      releaseProduct: row.releaseProduct,
-      version: row.version,
-      sqlName: row.sqlName,
-      createsExtension: row.createsExtension,
-      dataFiles: row.dataFiles,
-      dependencies: row.dependencies,
-      extensionSqlFileNames: row.extensionSqlFileNames,
-      extensionSqlFilePrefixes: row.extensionSqlFilePrefixes,
-      nativeModuleStem: stem,
-      nativeDependencies: resolvedNativeDependencies,
-      resourceRoot,
-      sharedPreloadLibraries: row.sharedPreloadLibraries,
-      asset: primaryAsset,
-      registration: stem === null ? null : { hasInit: row.registration.initSymbol !== null, symbols: row.registration.symbols },
-    };
-    await validateSwiftExtensionResourceArtifact({
-      extension: resolvedExtension,
-      canonical: canonicalOwners.get(row.sqlName),
-      nativeRuntime: { product: base.product, version: base.version },
-      label: `${row.sqlName} resolved runtime resource artifact`,
-      allowMobileCarrierArchives: true,
-    });
-    output.push(resolvedExtension);
-  }
-  stableVersion(basePackageVersion, "basePackageVersion");
-  let packageUrl;
-  try { packageUrl = new URL(basePackageUrl); } catch { fail("basePackageUrl must be an HTTPS Git URL"); }
-  if (packageUrl.protocol !== "https:" || !packageUrl.pathname.endsWith(".git")) fail("basePackageUrl must be an HTTPS Git URL ending in .git");
-  return {
-    schema: "oliphaunt-swiftpm-extension-selection-v1",
-    basePackage: { name: "Oliphaunt", url: packageUrl.href, version: basePackageVersion },
-    nativeRuntime: { product: base.product, version: base.version },
-    extensions: output,
-  };
-}
diff --git a/src/sdks/swift/tools/swift-carrier-resolver.mts b/src/sdks/swift/tools/swift-carrier-resolver.mts
new file mode 100644
index 000000000..f114de2ac
--- /dev/null
+++ b/src/sdks/swift/tools/swift-carrier-resolver.mts
@@ -0,0 +1,1067 @@
+import { createHash } from 'node:crypto';
+import { createReadStream, createWriteStream, constants as fsConstants } from 'node:fs';
+import fs from 'node:fs/promises';
+import os from 'node:os';
+import path from 'node:path';
+import { Readable, Transform } from 'node:stream';
+import { pipeline } from 'node:stream/promises';
+import { fileURLToPath } from 'node:url';
+import {
+  extractPortableArchiveTree,
+  extractPortableTarGzipTree,
+} from '../../../../tools/packaging/portable-archive.mts';
+import {
+  loadSwiftExtensionInventoryCatalog,
+  validateSwiftExtensionResourceArtifact,
+} from './extension-resource-inventory.mts';
+
+const PREFIX = 'swift-carrier-resolver';
+const SCHEMA = 'oliphaunt-react-native-ios-carrier-v1';
+const EXTENSION_CARRIER_SCHEMA = 'oliphaunt-swift-extension-carrier-v1';
+const ID = /^[A-Za-z0-9._-]{1,128}$/u;
+const C_ID = /^[A-Za-z_][A-Za-z0-9_]*$/u;
+const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u;
+const EXTRACTED_CACHE_SCHEMA = 'oliphaunt-extracted-carrier-tree-v1';
+const MAX_CARRIER_BYTES = 2 * 1024 * 1024 * 1024;
+const MAX_ZIP_CARRIER_BYTES = 512 * 1024 * 1024;
+// Match the release-side iOS carrier envelope. Current XCFrameworks contain
+// one runtime-resource tree per slice, so the consumer must accept the same
+// bounded archive shape that the producer validates.
+const MAX_ARCHIVE_ENTRIES = 32_768;
+const MAX_ARCHIVE_MEMBER_BYTES = 1024 * 1024 * 1024;
+const MAX_ARCHIVE_EXPANDED_BYTES = 4 * 1024 * 1024 * 1024;
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+function object(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object')
+    fail(`${label} must be an object`);
+  return value;
+}
+function exactKeys(value, allowed, label) {
+  const actual = Object.keys(value).sort(compareText);
+  const expected = [...allowed].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
+    fail(`${label} fields must be exactly ${expected.join(',')}; got ${actual.join(',')}`);
+  }
+}
+function identifier(value, label) {
+  if (typeof value !== 'string' || !ID.test(value)) fail(`${label} must be a portable identifier`);
+  return value;
+}
+function cIdentifier(value, label) {
+  if (typeof value !== 'string' || !C_ID.test(value)) fail(`${label} must be a C identifier`);
+  return value;
+}
+function stableVersion(value, label) {
+  if (typeof value !== 'string' || !STABLE_SEMVER.test(value))
+    fail(`${label} must be a stable SemVer X.Y.Z version`);
+  return value;
+}
+function ids(value, label) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((row, index) => identifier(row, `${label}[${index}]`)).sort(compareText);
+  if (new Set(rows).size !== rows.length) fail(`${label} repeats an identifier`);
+  return rows;
+}
+function canonicalIds(value, label) {
+  const rows = ids(value, label);
+  if (JSON.stringify(value) !== JSON.stringify(rows))
+    fail(`${label} must be sorted in ordinal order`);
+  return rows;
+}
+function canonicalRelativeFiles(value, label) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((row, index) => {
+    const relative = safeMember(row, `${label}[${index}]`);
+    if (relative === '.') fail(`${label}[${index}] must name a file`);
+    return relative;
+  });
+  const canonical = [...rows].sort(compareText);
+  if (new Set(rows).size !== rows.length) fail(`${label} repeats a path`);
+  if (JSON.stringify(rows) !== JSON.stringify(canonical))
+    fail(`${label} must be sorted in ordinal order`);
+  return rows;
+}
+function canonicalSqlFileNames(value, label) {
+  const rows = canonicalIds(value, label);
+  if (rows.some((name) => !name.endsWith('.sql'))) fail(`${label} must contain SQL basenames`);
+  return rows;
+}
+function canonicalSqlFilePrefixes(value, label) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((row, index) => {
+    if (typeof row !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/u.test(row)) {
+      fail(`${label}[${index}] must be a dot-free portable SQL basename prefix`);
+    }
+    return row;
+  });
+  const canonical = [...rows].sort(compareText);
+  if (new Set(rows).size !== rows.length) fail(`${label} repeats a prefix`);
+  if (JSON.stringify(rows) !== JSON.stringify(canonical))
+    fail(`${label} must be sorted in ordinal order`);
+  return rows;
+}
+async function loadCanonicalOwners(ownerCatalogFile) {
+  return loadSwiftExtensionInventoryCatalog(ownerCatalogFile);
+}
+function assertCanonicalOwner(extension, owners, label) {
+  const owner = owners.get(extension.sqlName);
+  if (owner === undefined)
+    fail(`${label} has no generated canonical release owner for ${extension.sqlName}`);
+  if (extension.product !== owner.product) {
+    fail(
+      `${label}.product must be canonical artifact product ${owner.product} for ${extension.sqlName}`,
+    );
+  }
+  if (extension.releaseProduct !== owner.releaseProduct) {
+    fail(
+      `${label}.releaseProduct must be canonical owner ${owner.releaseProduct} for ${extension.sqlName}`,
+    );
+  }
+}
+function assertOwnerReleaseConsistency(extensions, label) {
+  const releases = new Map();
+  for (const extension of extensions) {
+    const identity = `${extension.version}\0${extension.tag}`;
+    const existing = releases.get(extension.releaseProduct);
+    if (existing !== undefined && existing !== identity) {
+      fail(
+        `${label} assigns inconsistent version/tag identities to release owner ${extension.releaseProduct}`,
+      );
+    }
+    releases.set(extension.releaseProduct, identity);
+  }
+}
+async function digest(file) {
+  const hash = createHash('sha256');
+  await pipeline(createReadStream(file), hash);
+  return hash.digest('hex');
+}
+async function stat(file) {
+  return fs
+    .lstat(file)
+    .catch((error) => (error?.code === 'ENOENT' ? undefined : Promise.reject(error)));
+}
+const TAR_LIMITS = {
+  maxArchiveBytes: MAX_CARRIER_BYTES,
+  maxEntries: MAX_ARCHIVE_ENTRIES,
+  maxEntryBytes: MAX_ARCHIVE_MEMBER_BYTES,
+  maxExpandedBytes: MAX_ARCHIVE_EXPANDED_BYTES,
+};
+const ZIP_LIMITS = {
+  format: 'zip',
+  maxArchiveBytes: MAX_ZIP_CARRIER_BYTES,
+  maxEntries: MAX_ARCHIVE_ENTRIES,
+  maxEntryBytes: MAX_ARCHIVE_MEMBER_BYTES,
+  maxExpandedBytes: MAX_ARCHIVE_EXPANDED_BYTES,
+};
+
+function safeMember(value, label) {
+  if (value === '.') return value;
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    value.startsWith('/') ||
+    /^[A-Za-z]:/u.test(value) ||
+    /[\u0000-\u001f\u007f]/u.test(value)
+  )
+    fail(`${label} is unsafe`);
+  const parts = value.replace(/^\.\//u, '').split('/');
+  if (parts.some((part) => !part || part === '.' || part === '..')) fail(`${label} is unsafe`);
+  const relative = parts.join('/');
+  if (relative !== relative.normalize('NFC')) fail(`${label} must be canonical NFC`);
+  return relative;
+}
+function portableAssetName(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    path.posix.basename(value) !== value ||
+    /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) ||
+    /[ .]$/u.test(value) ||
+    /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value)
+  )
+    fail(`${label} must be a portable release asset file name`);
+  return value;
+}
+function asset(value, label, allowFileUrls) {
+  const row = object(value, label);
+  exactKeys(row, ['bytes', 'format', 'member', 'name', 'role', 'sha256', 'url'], label);
+  const role = identifier(row.role, `${label}.role`);
+  portableAssetName(row.name, `${label}.name`);
+  if (
+    !Number.isSafeInteger(row.bytes) ||
+    row.bytes <= 0 ||
+    row.bytes > MAX_CARRIER_BYTES ||
+    !/^[a-f0-9]{64}$/u.test(row.sha256)
+  )
+    fail(`${label} has invalid or unsupported size/checksum`);
+  if (!['zip', 'tar.gz'].includes(row.format)) fail(`${label} has unsupported format`);
+  if (
+    (row.format === 'zip' && !row.name.endsWith('.zip')) ||
+    (row.format === 'tar.gz' && !row.name.endsWith('.tar.gz'))
+  ) {
+    fail(`${label}.name does not match format ${row.format}`);
+  }
+  let url;
+  try {
+    url = new URL(row.url);
+  } catch {
+    fail(`${label}.url must be an absolute URL`);
+  }
+  if (url.protocol !== 'https:' && !(allowFileUrls && url.protocol === 'file:'))
+    fail(`${label}.url must use HTTPS`);
+  let urlName;
+  try {
+    urlName = decodeURIComponent(path.basename(url.pathname));
+  } catch {
+    fail(`${label}.url contains invalid escaping`);
+  }
+  if (urlName !== row.name) fail(`${label}.url must end with ${row.name}`);
+  return {
+    bytes: row.bytes,
+    format: row.format,
+    member: safeMember(row.member, `${label}.member`),
+    name: row.name,
+    role,
+    sha256: row.sha256,
+    url: url.href,
+  };
+}
+function assets(value, label, allowFileUrls) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((row, index) => asset(row, `${label}[${index}]`, allowFileUrls));
+  for (const [description, keys] of [
+    ['asset name', rows.map(({ name }) => name)],
+    ['asset role/member identity', rows.map(({ role, member }) => `${role}\0${member}`)],
+  ]) {
+    if (new Set(keys).size !== keys.length) fail(`${label} repeats an ${description}`);
+  }
+  return rows.sort((left, right) =>
+    compareText(`${left.role}\0${left.member}`, `${right.role}\0${right.member}`),
+  );
+}
+function carrierEnvelope(value, label, allowFileUrls) {
+  const row = object(value, label);
+  exactKeys(row, ['bytes', 'format', 'name', 'sha256', 'url'], label);
+  portableAssetName(row.name, `${label}.name`);
+  if (
+    !Number.isSafeInteger(row.bytes) ||
+    row.bytes <= 0 ||
+    row.bytes > MAX_CARRIER_BYTES ||
+    !/^[a-f0-9]{64}$/u.test(row.sha256)
+  ) {
+    fail(`${label} has invalid or unsupported size/checksum`);
+  }
+  if (!['zip', 'tar.gz'].includes(row.format)) fail(`${label} has unsupported format`);
+  if (
+    (row.format === 'zip' && !row.name.endsWith('.zip')) ||
+    (row.format === 'tar.gz' && !row.name.endsWith('.tar.gz'))
+  ) {
+    fail(`${label}.name does not match format ${row.format}`);
+  }
+  let url;
+  try {
+    url = new URL(row.url);
+  } catch {
+    fail(`${label}.url must be an absolute URL`);
+  }
+  if (url.protocol !== 'https:' && !(allowFileUrls && url.protocol === 'file:'))
+    fail(`${label}.url must use HTTPS`);
+  let urlName;
+  try {
+    urlName = decodeURIComponent(path.posix.basename(url.pathname));
+  } catch {
+    fail(`${label}.url contains invalid escaping`);
+  }
+  if (urlName !== row.name) fail(`${label}.url must end with ${row.name}`);
+  return {
+    bytes: row.bytes,
+    format: row.format,
+    name: row.name,
+    sha256: row.sha256,
+    url: url.href,
+  };
+}
+function carrierEnvelopes(value, label, allowFileUrls) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((row, index) => carrierEnvelope(row, `${label}[${index}]`, allowFileUrls));
+  if (new Set(rows.map(({ name }) => name)).size !== rows.length)
+    fail(`${label} repeats a carrier name`);
+  rows.sort((left, right) => compareText(left.name, right.name));
+  return new Map(rows.map((row) => [row.name, row]));
+}
+function assetLocator(value, label, carriers) {
+  const row = object(value, label);
+  exactKeys(row, ['bytes', 'carrier', 'format', 'member', 'path', 'role', 'sha256'], label);
+  const role = identifier(row.role, `${label}.role`);
+  const carrier = portableAssetName(row.carrier, `${label}.carrier`);
+  const envelope = carriers.get(carrier);
+  if (envelope === undefined) fail(`${label}.carrier references undeclared envelope ${carrier}`);
+  const memberPath = safeMember(row.path, `${label}.path`);
+  const member = safeMember(row.member, `${label}.member`);
+  if (
+    !Number.isSafeInteger(row.bytes) ||
+    row.bytes <= 0 ||
+    row.bytes > MAX_CARRIER_BYTES ||
+    !/^[a-f0-9]{64}$/u.test(row.sha256)
+  ) {
+    fail(`${label} has invalid or unsupported logical payload size/checksum`);
+  }
+  if (!['zip', 'tar.gz'].includes(row.format))
+    fail(`${label} has unsupported logical payload format`);
+  if (memberPath === '.') {
+    if (
+      row.bytes !== envelope.bytes ||
+      row.sha256 !== envelope.sha256 ||
+      row.format !== envelope.format
+    ) {
+      fail(`${label} direct payload metadata must exactly match carrier ${carrier}`);
+    }
+  } else {
+    if (envelope.format !== 'tar.gz')
+      fail(`${label} nested payload carrier must be a tar.gz archive`);
+    const nestedName = path.posix.basename(memberPath);
+    portableAssetName(nestedName, `${label}.path basename`);
+    if (
+      (row.format === 'zip' && !nestedName.endsWith('.zip')) ||
+      (row.format === 'tar.gz' && !nestedName.endsWith('.tar.gz'))
+    ) {
+      fail(`${label}.path does not match logical payload format ${row.format}`);
+    }
+  }
+  return {
+    bytes: row.bytes,
+    carrier,
+    envelope,
+    format: row.format,
+    member,
+    path: memberPath,
+    role,
+    sha256: row.sha256,
+  };
+}
+function assetLocators(value, label, carriers) {
+  if (!Array.isArray(value)) fail(`${label} must be an array`);
+  const rows = value.map((row, index) => assetLocator(row, `${label}[${index}]`, carriers));
+  const identities = rows.map(
+    ({ carrier, member, path: memberPath, role }) =>
+      `${role}\0${member}\0${carrier}\0${memberPath}`,
+  );
+  if (new Set(identities).size !== rows.length) fail(`${label} repeats an asset locator identity`);
+  return rows.sort((left, right) =>
+    compareText(
+      `${left.role}\0${left.member}\0${left.carrier}\0${left.path}`,
+      `${right.role}\0${right.member}\0${right.carrier}\0${right.path}`,
+    ),
+  );
+}
+function oneRole(rows, role, label) {
+  const matches = rows.filter((row) => row.role === role);
+  if (matches.length !== 1) fail(`${label} must have exactly one ${role} asset`);
+  return matches[0];
+}
+function registration(value, label) {
+  const row = object(value, label);
+  exactKeys(row, ['initSymbol', 'magicSymbol', 'symbols'], label);
+  const initSymbol =
+    row.initSymbol === null ? null : cIdentifier(row.initSymbol, `${label}.initSymbol`);
+  const magicSymbol = cIdentifier(row.magicSymbol, `${label}.magicSymbol`);
+  if (!Array.isArray(row.symbols)) fail(`${label}.symbols must be an array`);
+  const symbols = row.symbols
+    .map((raw, index) => {
+      const symbol = object(raw, `${label}.symbols[${index}]`);
+      exactKeys(symbol, ['address', 'name'], `${label}.symbols[${index}]`);
+      return {
+        address: cIdentifier(symbol.address, `${label}.symbols[${index}].address`),
+        name: cIdentifier(symbol.name, `${label}.symbols[${index}].name`),
+      };
+    })
+    .sort((left, right) =>
+      compareText(`${left.name}\0${left.address}`, `${right.name}\0${right.address}`),
+    );
+  if (new Set(symbols.map(({ name }) => name)).size !== symbols.length)
+    fail(`${label}.symbols repeats a SQL symbol`);
+  return { initSymbol, magicSymbol, symbols };
+}
+function validateBase(value, label, allowFileUrls) {
+  const row = object(value, label);
+  exactKeys(row, ['assets', 'product', 'tag', 'version'], label);
+  if (row.product !== 'liboliphaunt-native') fail(`${label}.product must be liboliphaunt-native`);
+  const version = stableVersion(row.version, `${label}.version`);
+  if (row.tag !== `${row.product}-v${version}`)
+    fail(`${label}.tag must be ${row.product}-v${version}`);
+  const rows = assets(row.assets, `${label}.assets`, allowFileUrls);
+  const allowed = new Set(['base-xcframework', 'runtime-resources']);
+  const unsupported = [
+    ...new Set(rows.filter(({ role }) => !allowed.has(role)).map(({ role }) => role)),
+  ].sort(compareText);
+  if (unsupported.length) fail(`${label}.assets has unsupported roles: ${unsupported.join(',')}`);
+  const framework = oneRole(rows, 'base-xcframework', `${label}.assets`);
+  const runtime = oneRole(rows, 'runtime-resources', `${label}.assets`);
+  const expectedRuntimeName = `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`;
+  if (runtime.name !== expectedRuntimeName) {
+    fail(`${label} runtime-resources asset must be ${expectedRuntimeName}`);
+  }
+  if (!path.posix.basename(framework.member).endsWith('.xcframework'))
+    fail(`${label} base framework member must be an XCFramework`);
+  return { assets: rows, product: row.product, tag: row.tag, version };
+}
+function validateBaseReference(value, label) {
+  const row = object(value, label);
+  exactKeys(row, ['product', 'tag', 'version'], label);
+  if (row.product !== 'liboliphaunt-native') fail(`${label}.product must be liboliphaunt-native`);
+  const version = stableVersion(row.version, `${label}.version`);
+  if (row.tag !== `${row.product}-v${version}`)
+    fail(`${label}.tag must be ${row.product}-v${version}`);
+  return { product: row.product, tag: row.tag, version };
+}
+function validateDependencyCarrierReference(value, label) {
+  const row = object(value, label);
+  exactKeys(row, ['product', 'releaseProduct', 'sqlName', 'tag', 'version'], label);
+  const sqlName = identifier(row.sqlName, `${label}.sqlName`);
+  const product = identifier(row.product, `${label}.product`);
+  if (!product.startsWith('oliphaunt-extension-'))
+    fail(`${label}.product must be an extension artifact product`);
+  const releaseProduct = identifier(row.releaseProduct, `${label}.releaseProduct`);
+  const version = stableVersion(row.version, `${label}.version`);
+  if (row.tag !== `${releaseProduct}-v${version}`)
+    fail(`${label}.tag must be ${releaseProduct}-v${version}`);
+  return { product, releaseProduct, sqlName, tag: row.tag, version };
+}
+function validateExtensionReleaseReference(value, label) {
+  const row = object(value, label);
+  exactKeys(row, ['product', 'tag', 'version'], label);
+  const product = identifier(row.product, `${label}.product`);
+  const version = stableVersion(row.version, `${label}.version`);
+  if (row.tag !== `${product}-v${version}`) fail(`${label}.tag must be ${product}-v${version}`);
+  return { product, tag: row.tag, version };
+}
+function validateExtension(value, label, carriers) {
+  const row = object(value, label);
+  exactKeys(
+    row,
+    [
+      'assets',
+      'createsExtension',
+      'dataFiles',
+      'dependencies',
+      'extensionSqlFileNames',
+      'extensionSqlFilePrefixes',
+      'nativeDependencies',
+      'nativeModuleStem',
+      'product',
+      'registration',
+      'releaseProduct',
+      'sharedPreloadLibraries',
+      'sqlName',
+      'tag',
+      'version',
+    ],
+    label,
+  );
+  const sqlName = identifier(row.sqlName, `${label}.sqlName`);
+  const product = identifier(row.product, `${label}.product`);
+  if (!product.startsWith('oliphaunt-extension-'))
+    fail(`${label}.product must be an extension artifact product`);
+  const releaseProduct = identifier(row.releaseProduct, `${label}.releaseProduct`);
+  const version = stableVersion(row.version, `${label}.version`);
+  if (row.tag !== `${releaseProduct}-v${version}`)
+    fail(`${label}.tag must be ${releaseProduct}-v${version}`);
+  if (typeof row.createsExtension !== 'boolean') fail(`${label}.createsExtension must be boolean`);
+  const nativeModuleStem =
+    row.nativeModuleStem === null
+      ? null
+      : identifier(row.nativeModuleStem, `${label}.nativeModuleStem`);
+  const dependencies = canonicalIds(row.dependencies, `${label}.dependencies`);
+  if (dependencies.includes(sqlName))
+    fail(`${label}.dependencies must not include ${sqlName} itself`);
+  return {
+    assets: assetLocators(row.assets, `${label}.assets`, carriers),
+    createsExtension: row.createsExtension,
+    dataFiles: canonicalRelativeFiles(row.dataFiles, `${label}.dataFiles`),
+    dependencies,
+    extensionSqlFileNames: canonicalSqlFileNames(
+      row.extensionSqlFileNames,
+      `${label}.extensionSqlFileNames`,
+    ),
+    extensionSqlFilePrefixes: canonicalSqlFilePrefixes(
+      row.extensionSqlFilePrefixes,
+      `${label}.extensionSqlFilePrefixes`,
+    ),
+    nativeDependencies: canonicalIds(row.nativeDependencies, `${label}.nativeDependencies`),
+    nativeModuleStem,
+    product,
+    releaseProduct,
+    registration:
+      row.registration === null ? null : registration(row.registration, `${label}.registration`),
+    sharedPreloadLibraries: canonicalIds(
+      row.sharedPreloadLibraries,
+      `${label}.sharedPreloadLibraries`,
+    ),
+    sqlName,
+    tag: row.tag,
+    version,
+  };
+}
+function assertExactCarrierCoverage(carriers, extensions, label) {
+  const referenced = new Set(
+    extensions.flatMap((extension) => extension.assets.map(({ carrier }) => carrier)),
+  );
+  const declared = [...carriers.keys()].sort(compareText);
+  const used = [...referenced].sort(compareText);
+  if (JSON.stringify(declared) !== JSON.stringify(used)) {
+    fail(
+      `${label} carrier envelopes must exactly cover referenced logical payloads; declared=${declared.join(',')}, used=${used.join(',')}`,
+    );
+  }
+}
+function byteLimitTransform(limit, label) {
+  let bytes = 0;
+  return new Transform({
+    transform(chunk, _encoding, callback) {
+      bytes += chunk.length;
+      if (bytes > limit) {
+        callback(new Error(`${PREFIX}: ${label} exceeds its frozen ${limit}-byte limit`));
+        return;
+      }
+      callback(null, chunk);
+    },
+  });
+}
+async function materialize(row, cacheDir, { offline }) {
+  const directory = path.join(cacheDir, 'objects');
+  const output = path.join(directory, `${row.sha256}-${row.name}`);
+  await fs.mkdir(directory, { recursive: true });
+  const existing = await stat(output);
+  if (existing?.isFile() && existing.size === row.bytes && (await digest(output)) === row.sha256)
+    return output;
+  if (offline) fail(`offline cache miss for ${row.name}`);
+  const temporary = `${output}.tmp-${process.pid}-${Date.now()}`;
+  try {
+    const url = new URL(row.url);
+    if (url.protocol === 'file:') {
+      const source = fileURLToPath(url);
+      const sourceStat = await stat(source);
+      if (sourceStat?.isFile() !== true || sourceStat.isSymbolicLink()) {
+        fail(`file URL is not a regular non-symlink file: ${row.url}`);
+      }
+      if (sourceStat.size !== row.bytes) {
+        fail(`size mismatch for ${row.name}; expected ${row.bytes}, got ${sourceStat.size}`);
+      }
+      await fs.copyFile(source, temporary, fsConstants.COPYFILE_EXCL);
+    } else {
+      const response = await fetch(url, { redirect: 'follow' });
+      if (!response.ok || !response.body || new URL(response.url).protocol !== 'https:')
+        fail(`download failed for ${row.url}`);
+      await pipeline(
+        Readable.fromWeb(response.body),
+        byteLimitTransform(row.bytes, `download ${row.name}`),
+        createWriteStream(temporary, { flags: 'wx', mode: 0o600 }),
+      );
+    }
+    const actual = await stat(temporary);
+    if (actual?.size !== row.bytes) fail(`size mismatch for ${row.name}`);
+    const actualDigest = await digest(temporary);
+    if (actualDigest !== row.sha256) fail(`checksum mismatch for ${row.name}; got ${actualDigest}`);
+    await fs.rm(output, { force: true, recursive: true });
+    await fs.rename(temporary, output);
+    return output;
+  } finally {
+    await fs.rm(temporary, { force: true });
+  }
+}
+
+async function materializeLogicalPayload(locator, carrierFile, cacheDir) {
+  if (locator.path === '.') return carrierFile;
+  const directory = path.join(cacheDir, 'payloads');
+  const output = path.join(directory, `${locator.sha256}-${path.posix.basename(locator.path)}`);
+  await fs.mkdir(directory, { recursive: true });
+  const existing = await stat(output);
+  if (
+    existing?.isFile() &&
+    !existing.isSymbolicLink() &&
+    existing.size === locator.bytes &&
+    (await digest(output)) === locator.sha256
+  )
+    return output;
+  const temporaryRoot = path.join(directory, `.tmp-${process.pid}-${Date.now()}-${locator.sha256}`);
+  await fs.rm(temporaryRoot, { force: true, recursive: true });
+  await fs.mkdir(temporaryRoot, { recursive: true, mode: 0o700 });
+  try {
+    await extractPortableTarGzipTree(carrierFile, temporaryRoot, TAR_LIMITS, locator.path);
+    const selected = path.join(temporaryRoot, ...locator.path.split('/'));
+    const selectedStat = await stat(selected);
+    if (selectedStat?.isFile() !== true || selectedStat.isSymbolicLink()) {
+      fail(`${locator.envelope.name} nested payload ${locator.path} is not a regular file`);
+    }
+    if (selectedStat.size !== locator.bytes || (await digest(selected)) !== locator.sha256) {
+      fail(
+        `${locator.envelope.name} nested payload ${locator.path} does not match its frozen size/checksum`,
+      );
+    }
+    await fs.rm(output, { force: true, recursive: true });
+    await fs.rename(selected, output);
+    return output;
+  } finally {
+    await fs.rm(temporaryRoot, { force: true, recursive: true });
+  }
+}
+function jsonDigest(value) {
+  return createHash('sha256').update(JSON.stringify(value)).digest('hex');
+}
+async function extractedTree(root) {
+  const entries = [];
+  const pending = [{ directory: root, relative: '' }];
+  let expandedBytes = 0;
+  while (pending.length) {
+    const { directory, relative } = pending.pop();
+    for (const name of (await fs.readdir(directory)).sort(compareText).reverse()) {
+      const child = path.join(directory, name);
+      const childRelative = relative ? `${relative}/${name}` : name;
+      safeMember(childRelative, `${root} extracted member`);
+      const info = await fs.lstat(child);
+      if (info.isSymbolicLink() || (!info.isFile() && !info.isDirectory()))
+        fail(`unsafe extracted entry ${child}`);
+      if (info.isDirectory()) {
+        entries.push({ path: childRelative, type: 'directory' });
+        pending.push({ directory: child, relative: childRelative });
+      } else {
+        if (info.size > MAX_ARCHIVE_MEMBER_BYTES) {
+          fail(
+            `${root} extracted member ${childRelative} exceeds the maximum supported member size`,
+          );
+        }
+        expandedBytes += info.size;
+        if (!Number.isSafeInteger(expandedBytes) || expandedBytes > MAX_ARCHIVE_EXPANDED_BYTES) {
+          fail(`${root} extracted tree exceeds the maximum supported expanded size`);
+        }
+        entries.push({
+          bytes: info.size,
+          executable: (info.mode & 0o111) !== 0,
+          path: childRelative,
+          sha256: await digest(child),
+          type: 'file',
+        });
+      }
+      if (entries.length > MAX_ARCHIVE_ENTRIES) {
+        fail(`${root} extracted tree exceeds the maximum supported ${MAX_ARCHIVE_ENTRIES} entries`);
+      }
+    }
+  }
+  entries.sort((left, right) => compareText(left.path, right.path));
+  return entries;
+}
+
+export async function extractVerifiedZipArchive({ archive, destination }) {
+  const archivePath = path.resolve(archive);
+  const destinationPath = path.resolve(destination);
+  const archiveStat = await stat(archivePath);
+  if (archiveStat?.isFile() !== true || archiveStat.isSymbolicLink()) {
+    fail(`ZIP archive is not a regular file: ${archivePath}`);
+  }
+  if ((await stat(destinationPath)) !== undefined) {
+    fail(`verified ZIP destination already exists: ${destinationPath}`);
+  }
+  const parent = path.dirname(destinationPath);
+  await fs.mkdir(parent, { recursive: true });
+  const parentStat = await stat(parent);
+  if (parentStat?.isDirectory() !== true || parentStat.isSymbolicLink()) {
+    fail(`verified ZIP destination parent is unsafe: ${parent}`);
+  }
+  const temporary = `${destinationPath}.tmp-${process.pid}-${Date.now()}`;
+  await fs.rm(temporary, { force: true, recursive: true });
+  await fs.mkdir(temporary, { mode: 0o700 });
+  try {
+    extractPortableArchiveTree(archivePath, temporary, '', ZIP_LIMITS);
+    const tree = await extractedTree(temporary);
+    if (!tree.some(({ type }) => type === 'file')) {
+      fail(`${archivePath} contains no regular files`);
+    }
+    await fs.rename(temporary, destinationPath);
+    return tree;
+  } finally {
+    await fs.rm(temporary, { force: true, recursive: true });
+  }
+}
+
+async function extractedCacheValid(root, manifestFile, archiveSha256) {
+  if ((await stat(root))?.isDirectory() !== true || (await stat(manifestFile))?.isFile() !== true)
+    return false;
+  try {
+    const manifest = object(JSON.parse(await fs.readFile(manifestFile, 'utf8')), manifestFile);
+    exactKeys(manifest, ['archiveSha256', 'entries', 'schema', 'treeSha256'], manifestFile);
+    if (
+      manifest.schema !== EXTRACTED_CACHE_SCHEMA ||
+      manifest.archiveSha256 !== archiveSha256 ||
+      !Array.isArray(manifest.entries)
+    )
+      return false;
+    if (manifest.treeSha256 !== jsonDigest(manifest.entries)) return false;
+    const actual = await extractedTree(root);
+    return (
+      manifest.treeSha256 === jsonDigest(actual) &&
+      JSON.stringify(manifest.entries) === JSON.stringify(actual)
+    );
+  } catch {
+    return false;
+  }
+}
+async function extract(row, archive, cacheDir) {
+  const output = path.join(cacheDir, 'extracted', row.sha256);
+  const cacheManifest = `${output}.tree.json`;
+  if (await extractedCacheValid(output, cacheManifest, row.sha256)) {
+    return row.member === '.' ? output : path.join(output, row.member);
+  }
+  const temporary = `${output}.tmp-${process.pid}-${Date.now()}`;
+  const temporaryManifest = `${cacheManifest}.tmp-${process.pid}-${Date.now()}`;
+  await fs.rm(temporary, { recursive: true, force: true });
+  await fs.mkdir(temporary, { recursive: true });
+  try {
+    if (row.format === 'zip') extractPortableArchiveTree(archive, temporary, '', ZIP_LIMITS);
+    else {
+      await extractPortableTarGzipTree(archive, temporary, TAR_LIMITS);
+    }
+    const tree = await extractedTree(temporary);
+    const manifest = {
+      archiveSha256: row.sha256,
+      entries: tree,
+      schema: EXTRACTED_CACHE_SCHEMA,
+      treeSha256: jsonDigest(tree),
+    };
+    const selected = row.member === '.' ? temporary : path.join(temporary, row.member);
+    if ((await stat(selected))?.isDirectory() !== true)
+      fail(`${row.name} member is not a directory: ${row.member}`);
+    await fs.writeFile(temporaryManifest, `${JSON.stringify(manifest, null, 2)}\n`, { flag: 'wx' });
+    await fs.mkdir(path.dirname(output), { recursive: true });
+    await fs.rm(output, { recursive: true, force: true });
+    await fs.rm(cacheManifest, { force: true });
+    await fs.rename(temporary, output);
+    await fs.rename(temporaryManifest, cacheManifest);
+    return row.member === '.' ? output : path.join(output, row.member);
+  } catch (error) {
+    await fs.rm(temporary, { recursive: true, force: true });
+    await fs.rm(temporaryManifest, { force: true });
+    throw error;
+  }
+}
+
+export async function resolveSwiftCarrierSelection({
+  carrierFile,
+  extensionCarrierFiles = [],
+  extensions,
+  cacheDir = path.join(os.homedir(), '.cache', 'oliphaunt', 'swift-extensions'),
+  allowFileUrls = false,
+  offline = false,
+  localBinaryTargets = false,
+  basePackageUrl = 'https://github.com/f0rr0/oliphaunt.git',
+  basePackageVersion,
+  ownerCatalogFile = undefined,
+}) {
+  const canonicalOwners = await loadCanonicalOwners(ownerCatalogFile);
+  let document;
+  try {
+    document = JSON.parse(await fs.readFile(carrierFile, 'utf8'));
+  } catch (error) {
+    fail(`could not read carrier ${carrierFile}: ${error.message}`);
+  }
+  const root = object(document, carrierFile);
+  exactKeys(root, ['base', 'carriers', 'extensions', 'legal', 'schema'], carrierFile);
+  if (root.schema !== SCHEMA) fail(`${carrierFile} has unsupported schema`);
+  const base = validateBase(root.base, `${carrierFile}.base`, allowFileUrls);
+  const rootCarriers = carrierEnvelopes(root.carriers, `${carrierFile}.carriers`, allowFileUrls);
+  if (!Array.isArray(root.extensions)) fail(`${carrierFile}.extensions must be an array`);
+  const validatedExtensions = root.extensions.map((row, index) =>
+    validateExtension(row, `${carrierFile}.extensions[${index}]`, rootCarriers),
+  );
+  for (const [index, extension] of validatedExtensions.entries()) {
+    assertCanonicalOwner(extension, canonicalOwners, `${carrierFile}.extensions[${index}]`);
+  }
+  assertOwnerReleaseConsistency(validatedExtensions, `${carrierFile}.extensions`);
+  assertExactCarrierCoverage(rootCarriers, validatedExtensions, carrierFile);
+  const byName = new Map(validatedExtensions.map((row) => [row.sqlName, row]));
+  if (byName.size !== root.extensions.length) fail('carrier repeats an extension row');
+  if (
+    !Array.isArray(extensionCarrierFiles) ||
+    extensionCarrierFiles.some((file) => typeof file !== 'string' || file.length === 0)
+  ) {
+    fail('extensionCarrierFiles must be an array of carrier paths');
+  }
+  const explicitNames = new Set();
+  const membersByCarrier = new Map();
+  const dependencyRequirements = new Map();
+  for (const carrier of extensionCarrierFiles) {
+    let overlayDocument;
+    try {
+      overlayDocument = JSON.parse(await fs.readFile(carrier, 'utf8'));
+    } catch (error) {
+      fail(`could not read extension carrier ${carrier}: ${error.message}`);
+    }
+    const overlay = object(overlayDocument, carrier);
+    exactKeys(overlay, ['base', 'carriers', 'entries', 'release', 'schema'], carrier);
+    if (overlay.schema !== EXTENSION_CARRIER_SCHEMA)
+      fail(`${carrier} has unsupported extension carrier schema`);
+    const overlayBase = validateBaseReference(overlay.base, `${carrier}.base`);
+    if (
+      overlayBase.product !== base.product ||
+      overlayBase.version !== base.version ||
+      overlayBase.tag !== base.tag
+    ) {
+      fail(`${carrier} requires ${overlayBase.tag}, but the base carrier provides ${base.tag}`);
+    }
+    const release = validateExtensionReleaseReference(overlay.release, `${carrier}.release`);
+    const overlayCarriers = carrierEnvelopes(
+      overlay.carriers,
+      `${carrier}.carriers`,
+      allowFileUrls,
+    );
+    if (!Array.isArray(overlay.entries) || overlay.entries.length === 0) {
+      fail(`${carrier}.entries must be a non-empty array`);
+    }
+    const carrierMembers = new Set();
+    const carrierExtensions = [];
+    for (const [index, rawEntry] of overlay.entries.entries()) {
+      const entry = object(rawEntry, `${carrier}.entries[${index}]`);
+      exactKeys(entry, ['dependencyCarriers', 'extension'], `${carrier}.entries[${index}]`);
+      const extension = validateExtension(
+        entry.extension,
+        `${carrier}.entries[${index}].extension`,
+        overlayCarriers,
+      );
+      assertCanonicalOwner(extension, canonicalOwners, `${carrier}.entries[${index}].extension`);
+      if (
+        extension.releaseProduct !== release.product ||
+        extension.version !== release.version ||
+        extension.tag !== release.tag
+      ) {
+        fail(`${carrier}.entries[${index}].extension must be owned by ${release.tag}`);
+      }
+      if (explicitNames.has(extension.sqlName)) {
+        fail(`extension carriers repeat explicit row ${extension.sqlName}`);
+      }
+      if (!Array.isArray(entry.dependencyCarriers)) {
+        fail(`${carrier}.entries[${index}].dependencyCarriers must be an array`);
+      }
+      const requirements = entry.dependencyCarriers.map((row, dependencyIndex) =>
+        validateDependencyCarrierReference(
+          row,
+          `${carrier}.entries[${index}].dependencyCarriers[${dependencyIndex}]`,
+        ),
+      );
+      for (const [dependencyIndex, requirement] of requirements.entries()) {
+        const canonicalOwner = canonicalOwners.get(requirement.sqlName);
+        if (
+          canonicalOwner === undefined ||
+          requirement.product !== canonicalOwner.product ||
+          requirement.releaseProduct !== canonicalOwner.releaseProduct
+        ) {
+          fail(
+            `${carrier}.entries[${index}].dependencyCarriers[${dependencyIndex}] must use canonical artifact/release products ` +
+              `${canonicalOwner?.product ?? ''}/${canonicalOwner?.releaseProduct ?? ''} for ${requirement.sqlName}`,
+          );
+        }
+      }
+      if (new Set(requirements.map(({ sqlName }) => sqlName)).size !== requirements.length) {
+        fail(`${carrier}.entries[${index}].dependencyCarriers repeats an extension dependency`);
+      }
+      const requiredNames = requirements.map(({ sqlName }) => sqlName).sort(compareText);
+      if (JSON.stringify(requiredNames) !== JSON.stringify(extension.dependencies)) {
+        fail(
+          `${carrier}.entries[${index}].dependencyCarriers must exactly pin ${extension.sqlName} dependencies`,
+        );
+      }
+      explicitNames.add(extension.sqlName);
+      carrierMembers.add(extension.sqlName);
+      carrierExtensions.push(extension);
+      dependencyRequirements.set(extension.sqlName, requirements);
+      byName.set(extension.sqlName, extension);
+    }
+    assertOwnerReleaseConsistency(carrierExtensions, `${carrier}.entries`);
+    assertExactCarrierCoverage(overlayCarriers, carrierExtensions, carrier);
+    membersByCarrier.set(carrier, carrierMembers);
+  }
+  const ordered = [],
+    visiting = new Set(),
+    visited = new Set();
+  function visit(name, parent) {
+    if (visited.has(name)) return;
+    if (visiting.has(name)) fail(`dependency cycle includes ${name}`);
+    const row = byName.get(name);
+    if (!row) fail(`missing carrier for ${name}${parent ? ` required by ${parent}` : ''}`);
+    visiting.add(name);
+    for (const dependency of ids(row.dependencies, `${name}.dependencies`)) visit(dependency, name);
+    visiting.delete(name);
+    visited.add(name);
+    ordered.push(row);
+  }
+  for (const name of ids(extensions, 'selected extensions')) visit(name);
+  assertOwnerReleaseConsistency(ordered, 'resolved selected extensions');
+  const unusedCarriers = [...membersByCarrier]
+    .filter(([, members]) => ![...members].some((name) => visited.has(name)))
+    .map(([carrier]) => carrier)
+    .sort(compareText);
+  if (unusedCarriers.length > 0) {
+    fail(
+      `extension carrier file(s) supplied no selected or required row: ${unusedCarriers.join(',')}`,
+    );
+  }
+  for (const [sqlName, requirements] of dependencyRequirements) {
+    for (const requirement of requirements) {
+      const selected = byName.get(requirement.sqlName);
+      if (
+        selected === undefined ||
+        selected.product !== requirement.product ||
+        selected.releaseProduct !== requirement.releaseProduct ||
+        selected.version !== requirement.version ||
+        selected.tag !== requirement.tag
+      ) {
+        fail(
+          `${sqlName} requires dependency carrier ${requirement.tag}, but resolved ` +
+            `${selected?.tag ?? 'no carrier'}`,
+        );
+      }
+    }
+  }
+  const output = [];
+  const materializedCarriers = new Map();
+  for (const row of ordered) {
+    const nativeDependencies = row.nativeDependencies;
+    const rows = row.assets;
+    const allowedRoles = new Set([
+      'runtime-resources',
+      'extension-xcframework',
+      'dependency-xcframework',
+    ]);
+    const unsupportedRoles = [
+      ...new Set(rows.filter(({ role }) => !allowedRoles.has(role)).map(({ role }) => role)),
+    ].sort(compareText);
+    if (unsupportedRoles.length)
+      fail(`${row.sqlName} has unsupported asset roles: ${unsupportedRoles.join(',')}`);
+    const runtimeRows = rows.filter(({ role }) => role === 'runtime-resources');
+    if (runtimeRows.length !== 1) fail(`${row.sqlName} must have one runtime-resources asset`);
+    const materialized = new Map();
+    for (const rowAsset of rows) {
+      const carrierKey = `${rowAsset.envelope.sha256}\0${rowAsset.envelope.name}`;
+      let carrierFile = materializedCarriers.get(carrierKey);
+      if (carrierFile === undefined) {
+        carrierFile = await materialize(rowAsset.envelope, cacheDir, { offline });
+        materializedCarriers.set(carrierKey, carrierFile);
+      }
+      materialized.set(rowAsset, await materializeLogicalPayload(rowAsset, carrierFile, cacheDir));
+    }
+    const runtimeArchive = materialized.get(runtimeRows[0]);
+    const resourceRoot = await extract(runtimeRows[0], runtimeArchive, cacheDir);
+    const stem = row.nativeModuleStem === null ? null : row.nativeModuleStem;
+    const extensionAssets = rows.filter(({ role }) => role === 'extension-xcframework');
+    const dependencyAssets = rows
+      .filter(({ role }) => role === 'dependency-xcframework')
+      .map((rowAsset) => {
+        const match = /^liboliphaunt_dependency_(.+)\.xcframework$/u.exec(
+          path.posix.basename(rowAsset.member),
+        );
+        if (!match || !ID.test(match[1]))
+          fail(`${row.sqlName} has malformed dependency framework member`);
+        return { name: match[1], rowAsset };
+      })
+      .sort((left, right) => compareText(left.name, right.name));
+    if (new Set(dependencyAssets.map(({ name }) => name)).size !== dependencyAssets.length) {
+      fail(`${row.sqlName} repeats a dependency carrier identity`);
+    }
+    if (stem === null) {
+      if (
+        extensionAssets.length ||
+        dependencyAssets.length ||
+        nativeDependencies.length ||
+        row.registration !== null
+      )
+        fail(`${row.sqlName} SQL-only carrier fabricates native roles`);
+    } else {
+      if (
+        !ID.test(stem) ||
+        extensionAssets.length !== 1 ||
+        path.posix.basename(extensionAssets[0].member) !==
+          `liboliphaunt_extension_${stem}.xcframework`
+      )
+        fail(`${row.sqlName} lacks its exact extension XCFramework`);
+      if (
+        JSON.stringify(dependencyAssets.map(({ name }) => name)) !==
+        JSON.stringify(nativeDependencies)
+      )
+        fail(`${row.sqlName} native dependency inventory mismatch`);
+      const prefix = `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`;
+      if (
+        row.registration?.magicSymbol !== `${prefix}_Pg_magic_func` ||
+        ![null, `${prefix}__PG_init`].includes(row.registration?.initSymbol)
+      )
+        fail(`${row.sqlName} registration symbols do not match its native stem`);
+    }
+    const binaryAsset = async (rowAsset) => {
+      const requiresLocalPath = localBinaryTargets || rowAsset.path !== '.';
+      return {
+        name: rowAsset.envelope.name,
+        url: rowAsset.envelope.url,
+        checksum: rowAsset.envelope.sha256,
+        ...(requiresLocalPath
+          ? { localPath: await extract(rowAsset, materialized.get(rowAsset), cacheDir) }
+          : {}),
+      };
+    };
+    const resolvedNativeDependencies = [];
+    for (const { name, rowAsset } of dependencyAssets) {
+      resolvedNativeDependencies.push({
+        name,
+        asset: await binaryAsset(rowAsset),
+      });
+    }
+    const primaryAsset = stem === null ? null : await binaryAsset(extensionAssets[0]);
+    const resolvedExtension = {
+      product: row.product,
+      releaseProduct: row.releaseProduct,
+      version: row.version,
+      sqlName: row.sqlName,
+      createsExtension: row.createsExtension,
+      dataFiles: row.dataFiles,
+      dependencies: row.dependencies,
+      extensionSqlFileNames: row.extensionSqlFileNames,
+      extensionSqlFilePrefixes: row.extensionSqlFilePrefixes,
+      nativeModuleStem: stem,
+      nativeDependencies: resolvedNativeDependencies,
+      resourceRoot,
+      sharedPreloadLibraries: row.sharedPreloadLibraries,
+      asset: primaryAsset,
+      registration:
+        stem === null
+          ? null
+          : { hasInit: row.registration.initSymbol !== null, symbols: row.registration.symbols },
+    };
+    await validateSwiftExtensionResourceArtifact({
+      extension: resolvedExtension,
+      canonical: canonicalOwners.get(row.sqlName),
+      nativeRuntime: { product: base.product, version: base.version },
+      label: `${row.sqlName} resolved runtime resource artifact`,
+      allowMobileCarrierArchives: true,
+    });
+    output.push(resolvedExtension);
+  }
+  stableVersion(basePackageVersion, 'basePackageVersion');
+  let packageUrl;
+  try {
+    packageUrl = new URL(basePackageUrl);
+  } catch {
+    fail('basePackageUrl must be an HTTPS Git URL');
+  }
+  if (packageUrl.protocol !== 'https:' || !packageUrl.pathname.endsWith('.git'))
+    fail('basePackageUrl must be an HTTPS Git URL ending in .git');
+  return {
+    schema: 'oliphaunt-swiftpm-extension-selection-v1',
+    basePackage: { name: 'Oliphaunt', url: packageUrl.href, version: basePackageVersion },
+    nativeRuntime: { product: base.product, version: base.version },
+    extensions: output,
+  };
+}
diff --git a/src/sdks/swift/tools/swift-carrier-resolver.test.mjs b/src/sdks/swift/tools/swift-carrier-resolver.test.mjs
deleted file mode 100755
index 9d01501aa..000000000
--- a/src/sdks/swift/tools/swift-carrier-resolver.test.mjs
+++ /dev/null
@@ -1,1229 +0,0 @@
-#!/usr/bin/env node
-
-import assert from "node:assert/strict";
-import { createHash } from "node:crypto";
-import fs from "node:fs/promises";
-import path from "node:path";
-import { pathToFileURL } from "node:url";
-import { spawnSync } from "node:child_process";
-import { gunzipSync, gzipSync } from "node:zlib";
-import {
-  extractVerifiedZipArchive,
-  localTarArchiveBinding,
-  resolveSwiftCarrierSelection,
-} from "./swift-carrier-resolver.mjs";
-
-const sdk = path.resolve(import.meta.dirname, "..");
-const root = path.resolve(process.argv[2] ?? path.join(sdk, ".build", "carrier-test"));
-const generator = path.join(import.meta.dirname, "render-extension-products.mjs");
-const schema = "oliphaunt-react-native-ios-carrier-v1";
-const extensionCarrierSchema = "oliphaunt-swift-extension-carrier-v1";
-const postgisNativeDependencies = [
-  ["geos", "OliphauntNativeDependencyGeos"],
-  ["geos-c", "OliphauntNativeDependencyGeosC"],
-  ["json-c", "OliphauntNativeDependencyJsonC"],
-  ["libxml2", "OliphauntNativeDependencyLibxml2"],
-  ["proj", "OliphauntNativeDependencyProj"],
-  ["sqlite", "OliphauntNativeDependencySqlite"],
-];
-const productionDependencyArchiveNames = new Map([
-  ["geos", "libgeos.a"],
-  ["geos-c", "libgeos_c.a"],
-  ["json-c", "libjson-c.a"],
-  ["libxml2", "libxml2.a"],
-  ["proj", "libproj.a"],
-  ["sqlite", "libsqlite3.a"],
-]);
-const frozenContent = new Map([
-  ["pgtap", {
-    dataFiles: [],
-    extensionSqlFileNames: ["uninstall_pgtap.sql"],
-    extensionSqlFilePrefixes: ["pgtap-core", "pgtap-schema"],
-  }],
-  ["postgis", {
-    dataFiles: [
-      "contrib/postgis-3.6/legacy.sql",
-      "contrib/postgis-3.6/legacy_gist.sql",
-      "contrib/postgis-3.6/legacy_minimal.sql",
-      "contrib/postgis-3.6/postgis.sql",
-      "contrib/postgis-3.6/postgis_upgrade.sql",
-      "contrib/postgis-3.6/spatial_ref_sys.sql",
-      "contrib/postgis-3.6/uninstall_legacy.sql",
-      "contrib/postgis-3.6/uninstall_postgis.sql",
-      "proj/proj.db",
-    ],
-    extensionSqlFileNames: ["uninstall_postgis.sql"],
-    extensionSqlFilePrefixes: [
-      "postgis_comments",
-      "postgis_proc_set_search_path",
-      "rtpostgis",
-    ],
-  }],
-]);
-
-function run(command, args, options = {}) {
-  const result = spawnSync(command, args, { encoding: "utf8", ...options });
-  if (options.expectFailure) {
-    assert.notEqual(result.status, 0, `${command} unexpectedly succeeded`);
-    return `${result.stderr}${result.stdout}`;
-  }
-  assert.equal(result.status, 0, `${command} failed:\n${result.stderr || result.stdout}`);
-  return result.stdout;
-}
-async function checksum(file) { return createHash("sha256").update(await fs.readFile(file)).digest("hex"); }
-async function asset(role, file, format, member) {
-  return { role, name: path.basename(file), url: pathToFileURL(file).href, sha256: await checksum(file), bytes: (await fs.stat(file)).size, format, member };
-}
-function carrierize(rawExtensions) {
-  const carriers = new Map();
-  const extensions = rawExtensions.map((extensionRow) => ({
-    ...extensionRow,
-    assets: extensionRow.assets.map((raw) => {
-      const envelope = {
-        name: raw.name,
-        url: raw.url,
-        sha256: raw.sha256,
-        bytes: raw.bytes,
-        format: raw.format,
-      };
-      const existing = carriers.get(envelope.name);
-      if (existing !== undefined) assert.deepEqual(existing, envelope);
-      carriers.set(envelope.name, envelope);
-      return {
-        role: raw.role,
-        carrier: envelope.name,
-        path: ".",
-        sha256: raw.sha256,
-        bytes: raw.bytes,
-        format: raw.format,
-        member: raw.member,
-      };
-    }),
-  }));
-  return { carriers: [...carriers.values()].sort((left, right) => left.name.localeCompare(right.name)), extensions };
-}
-function setDirectExtensionAssets(document, sqlName, rawAssets) {
-  const extensionRow = document.extensions.find((row) => row.sqlName === sqlName);
-  assert.ok(extensionRow, `missing ${sqlName} fixture row`);
-  const converted = carrierize([{ ...extensionRow, assets: rawAssets }]);
-  extensionRow.assets = converted.extensions[0].assets;
-  const referenced = new Set(document.extensions.flatMap((row) => row.assets.map(({ carrier }) => carrier)));
-  const byName = new Map(document.carriers.filter(({ name }) => referenced.has(name)).map((row) => [row.name, row]));
-  for (const row of converted.carriers) byName.set(row.name, row);
-  document.carriers = [...byName.values()].sort((left, right) => left.name.localeCompare(right.name));
-}
-async function maliciousZip(archive, entry, kind) {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  const script = [
-    "import stat, sys, zipfile",
-    "archive, entry, kind = sys.argv[1:]",
-    "info = zipfile.ZipInfo(entry)",
-    "info.create_system = 3",
-    "info.external_attr = ((stat.S_IFLNK | 0o777) if kind == 'symlink' else (stat.S_IFREG | 0o644)) << 16",
-    "with zipfile.ZipFile(archive, 'w') as output: output.writestr(info, '../outside' if kind == 'symlink' else 'malicious')",
-  ].join("\n");
-  run("python3", ["-c", script, archive, entry, kind]);
-}
-async function metadataZip(archive, creator) {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  const script = [
-    "import sys, zipfile",
-    "archive, creator = sys.argv[1:]",
-    "host = 0 if creator == 'fat' else 3",
-    "ambiguous = creator == 'ambiguous-unix'",
-    "root = zipfile.ZipInfo('liboliphaunt.xcframework/')",
-    "root.create_system = host",
-    "root.external_attr = (((0o755 if ambiguous else 0o40755) << 16) | 0x10) if host == 3 else 0x10",
-    "payload = zipfile.ZipInfo('liboliphaunt.xcframework/Info.plist')",
-    "payload.create_system = host",
-    "payload.external_attr = (((0o644 if ambiguous else 0o100644) << 16) | 0x20) if host == 3 else 0x20",
-    "if creator == 'unicode-extra': payload.extra = b'\\x75\\x70\\x05\\x00\\x01\\x00\\x00\\x00\\x00'",
-    "with zipfile.ZipFile(archive, 'w') as output:",
-    "  output.writestr(root, b'')",
-    "  output.writestr(payload, b'\\n')",
-  ].join("\n");
-  run("python3", ["-c", script, archive, creator]);
-}
-async function addUnsupportedZipFlag(archive) {
-  const buffer = await fs.readFile(archive);
-  const eocd = buffer.length - 22;
-  assert.equal(buffer.readUInt32LE(eocd), 0x06054b50);
-  const centralOffset = buffer.readUInt32LE(eocd + 16);
-  assert.equal(buffer.readUInt32LE(centralOffset), 0x02014b50);
-  const localOffset = buffer.readUInt32LE(centralOffset + 42);
-  assert.equal(buffer.readUInt32LE(localOffset), 0x04034b50);
-  buffer.writeUInt16LE(buffer.readUInt16LE(centralOffset + 8) | 0x20, centralOffset + 8);
-  buffer.writeUInt16LE(buffer.readUInt16LE(localOffset + 6) | 0x20, localOffset + 6);
-  await fs.writeFile(archive, buffer);
-}
-async function craftedTar(archive, entries) {
-  await fs.mkdir(path.dirname(archive), { recursive: true });
-  const script = [
-    "import io, json, sys, tarfile",
-    "archive, encoded = sys.argv[1:]",
-    "with tarfile.open(archive, 'w:gz', format=tarfile.USTAR_FORMAT) as output:",
-    "  for row in json.loads(encoded):",
-    "    info = tarfile.TarInfo(row['name'])",
-    "    info.mode = 0o755 if row['type'] == 'directory' else 0o644",
-    "    if row['type'] == 'directory': info.type = tarfile.DIRTYPE; output.addfile(info)",
-    "    elif row['type'] == 'symlink': info.type = tarfile.SYMTYPE; info.linkname = 'target'; output.addfile(info)",
-    "    else: data = b'fixture'; info.size = len(data); output.addfile(info, io.BytesIO(data))",
-  ].join("\n");
-  run("python3", ["-c", script, archive, JSON.stringify(entries)]);
-}
-async function removeTarDirectorySlash(archive, member) {
-  const tar = gunzipSync(await fs.readFile(archive));
-  let found = false;
-  for (let offset = 0; offset + 512 <= tar.length;) {
-    const header = tar.subarray(offset, offset + 512);
-    if (header.every((value) => value === 0)) break;
-    const field = (start, length) => {
-      const bytes = header.subarray(start, start + length);
-      const end = bytes.indexOf(0);
-      return bytes.subarray(0, end < 0 ? bytes.length : end).toString("utf8");
-    };
-    const name = field(0, 100);
-    const prefix = field(345, 155);
-    const fullName = prefix ? `${prefix}/${name}` : name;
-    const size = Number.parseInt(field(124, 12).trim() || "0", 8);
-    assert.ok(Number.isSafeInteger(size) && size >= 0, `invalid tar size for ${fullName}`);
-    if (fullName === member) {
-      assert.equal(String.fromCharCode(header[156]), "5", `${member} must be a directory header`);
-      assert.equal(prefix, "", `${member} test helper only supports the ustar name field`);
-      assert.ok(name.endsWith("/"), `${member} must initially use a canonical directory marker`);
-      header[name.length - 1] = 0;
-      header.fill(0x20, 148, 156);
-      const checksum = header.reduce((total, value) => total + value, 0);
-      Buffer.from(`${checksum.toString(8).padStart(6, "0")}\0 `, "ascii").copy(header, 148);
-      found = true;
-    }
-    offset += 512 + Math.ceil(size / 512) * 512;
-  }
-  assert.equal(found, true, `missing tar directory ${member}`);
-  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
-}
-async function addTarFileSlash(archive, member) {
-  const tar = gunzipSync(await fs.readFile(archive));
-  let found = false;
-  for (let offset = 0; offset + 512 <= tar.length;) {
-    const header = tar.subarray(offset, offset + 512);
-    if (header.every((value) => value === 0)) break;
-    const end = header.subarray(0, 100).indexOf(0);
-    const name = header.subarray(0, end < 0 ? 100 : end).toString("utf8");
-    const sizeEnd = header.subarray(124, 136).indexOf(0);
-    const size = Number.parseInt(
-      header.subarray(124, sizeEnd < 0 ? 136 : 124 + sizeEnd).toString("utf8").trim() || "0",
-      8,
-    );
-    if (name === member) {
-      assert.equal(String.fromCharCode(header[156]), "0", `${member} must be a regular file header`);
-      assert.ok(member.length < 99, `${member} must leave room for a slash`);
-      header[member.length] = "/".charCodeAt(0);
-      header[member.length + 1] = 0;
-      header.fill(0x20, 148, 156);
-      const checksum = header.reduce((total, value) => total + value, 0);
-      Buffer.from(`${checksum.toString(8).padStart(6, "0")}\0 `, "ascii").copy(header, 148);
-      found = true;
-    }
-    offset += 512 + Math.ceil(size / 512) * 512;
-  }
-  assert.equal(found, true, `missing tar file ${member}`);
-  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
-}
-async function zipFramework(name, archive) {
-  const parent = path.join(root, "frameworks");
-  await fs.mkdir(path.join(parent, name), { recursive: true });
-  await fs.writeFile(path.join(parent, name, "Info.plist"), "\n");
-  run("zip", ["-qry", archive, name], { cwd: parent });
-}
-async function base() {
-  const archives = path.join(root, "archives");
-  await fs.mkdir(archives, { recursive: true });
-  const framework = path.join(archives, "liboliphaunt-0.1.0-apple-spm-xcframework.zip");
-  await zipFramework("liboliphaunt.xcframework", framework);
-  const runtimeSource = path.join(root, "base", "runtime", "oliphaunt");
-  await fs.mkdir(runtimeSource, { recursive: true });
-  await fs.writeFile(path.join(runtimeSource, "fixture.txt"), "runtime\n");
-  const runtime = path.join(
-    archives,
-    "liboliphaunt-0.1.0-runtime-resources-ios-datum64.tar.gz",
-  );
-  run("tar", ["--no-xattrs", "-czf", runtime, "-C", path.dirname(runtimeSource), path.basename(runtimeSource)]);
-  const icuSource = path.join(root, "base", "icu", "share", "icu");
-  await fs.mkdir(icuSource, { recursive: true });
-  await fs.writeFile(path.join(icuSource, "icudt.dat"), "icu\n");
-  const icuDigest = createHash("sha256")
-    .update("icudt.dat\0" + Buffer.byteLength("icu\n") + "\0icu\n\n")
-    .digest("hex");
-  await fs.writeFile(
-    path.join(root, "base", "icu", "manifest.properties"),
-    "schema=oliphaunt-icu-data-v1\n"
-      + "artifactRole=icu-data\n"
-      + "icuDataVersion=76.1\n"
-      + "icuDataForm=files-le\n"
-      + `icuDataTreeSha256=${icuDigest}\n`,
-  );
-  const icu = path.join(archives, "liboliphaunt-0.1.0-icu-data.tar.gz");
-  run("tar", ["--no-xattrs", "-czf", icu, "-C", path.join(root, "base", "icu"), "."]);
-  return {
-    assets: [
-      await asset("base-xcframework", framework, "zip", "liboliphaunt.xcframework"),
-      await asset("runtime-resources", runtime, "tar.gz", "oliphaunt"),
-      await asset("icu-data", icu, "tar.gz", "."),
-    ],
-    product: "liboliphaunt-native",
-    tag: "liboliphaunt-native-v0.1.0",
-    version: "0.1.0",
-  };
-}
-
-async function productionExtensionResource(sqlName, stem, nativeDependencies) {
-  const source = path.join(sdk, "Tests", "Fixtures", "swiftpm-extension-resources", sqlName);
-  if (stem === null) return source;
-  const stage = path.join(root, "production-extension-resources", sqlName);
-  await fs.rm(stage, { recursive: true, force: true });
-  await fs.cp(source, stage, { recursive: true });
-  const targets = ["ios-device", "ios-simulator"];
-  const mobileStaticArchives = targets.map(
-    (target) =>
-      `${target}:mobile-static/${target}/extensions/${stem}/` +
-      `liboliphaunt_extension_${stem}.a`,
-  );
-  const mobileStaticDependencyArchives = targets.flatMap((target) =>
-    nativeDependencies.map((dependency) => {
-      const archiveName = productionDependencyArchiveNames.get(dependency) ?? `lib${dependency}.a`;
-      return `${target}:${dependency}:mobile-static/${target}/dependencies/${dependency}/${archiveName}`;
-    }));
-  if (nativeDependencies.includes("geos") && nativeDependencies.includes("geos-c")) {
-    assert.notDeepEqual(
-      mobileStaticDependencyArchives,
-      [...mobileStaticDependencyArchives].sort(),
-      "the production fixture must preserve structured order that differs from raw-string order",
-    );
-  }
-  const manifestFile = path.join(stage, "manifest.properties");
-  let manifest = await fs.readFile(manifestFile, "utf8");
-  assert.ok(manifest.includes("mobileStaticArchives=\n"));
-  assert.ok(manifest.includes("mobileStaticDependencyArchives=\n"));
-  manifest = manifest
-    .replace("mobileStaticArchives=\n", `mobileStaticArchives=${mobileStaticArchives.join(",")}\n`)
-    .replace(
-      "mobileStaticDependencyArchives=\n",
-      `mobileStaticDependencyArchives=${mobileStaticDependencyArchives.join(",")}\n`,
-    );
-  await fs.writeFile(manifestFile, manifest);
-  for (const row of [...mobileStaticArchives, ...mobileStaticDependencyArchives]) {
-    const relative = row.slice(row.lastIndexOf(":") + 1);
-    const archive = path.join(stage, ...relative.split("/"));
-    await fs.mkdir(path.dirname(archive), { recursive: true });
-    await fs.writeFile(archive, `static archive fixture for ${sqlName}\n`);
-  }
-  return stage;
-}
-
-async function extension(sqlName, stem, dependencies = [], nativeDependencies = []) {
-  const resource = await productionExtensionResource(sqlName, stem, nativeDependencies);
-  const runtime = path.join(root, "archives", `${sqlName}-runtime.tar.gz`);
-  await fs.mkdir(path.dirname(runtime), { recursive: true });
-  run("tar", ["--no-xattrs", "-czf", runtime, "-C", resource, "."]);
-  if (sqlName === "cube") {
-    // Reproduce the valid POSIX typeflag-5/no-trailing-slash carrier emitted by
-    // the previous archive producer and rejected by the failed CI run.
-    await removeTarDirectorySlash(runtime, "./files/");
-  }
-  const assets = [await asset("runtime-resources", runtime, "tar.gz", ".")];
-  if (stem !== null) {
-    const frameworkName = `liboliphaunt_extension_${stem}.xcframework`;
-    const archive = path.join(root, "archives", `${sqlName}-framework.zip`);
-    await zipFramework(frameworkName, archive);
-    assets.push(await asset("extension-xcframework", archive, "zip", frameworkName));
-    for (const dependency of nativeDependencies) {
-      const dependencyName = `liboliphaunt_dependency_${dependency}.xcframework`;
-      const dependencyArchive = path.join(root, "archives", `${sqlName}-${dependency}.zip`);
-      await zipFramework(dependencyName, dependencyArchive);
-      assets.push(await asset("dependency-xcframework", dependencyArchive, "zip", dependencyName));
-    }
-  }
-  const prefix = stem === null ? null : `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`;
-  const product = new Set(["cube", "earthdistance", "pg_trgm"]).has(sqlName)
-    ? "oliphaunt-extension-contrib-pg18"
-    : `oliphaunt-extension-${sqlName.replaceAll("_", "-")}`;
-  const releaseProduct = product === "oliphaunt-extension-contrib-pg18"
-    ? "liboliphaunt-native"
-    : product;
-  const version = sqlName === "postgis" ? "3.6.1" : "1.0.0";
-  const content = frozenContent.get(sqlName) ?? {
-    dataFiles: [],
-    extensionSqlFileNames: [],
-    extensionSqlFilePrefixes: [],
-  };
-  return {
-    product,
-    releaseProduct,
-    version,
-    tag: `${releaseProduct}-v${version}`,
-    sqlName,
-    createsExtension: true,
-    dataFiles: content.dataFiles,
-    dependencies,
-    extensionSqlFileNames: content.extensionSqlFileNames,
-    extensionSqlFilePrefixes: content.extensionSqlFilePrefixes,
-    nativeDependencies,
-    nativeModuleStem: stem,
-    sharedPreloadLibraries: [],
-    registration: stem === null ? null : {
-      magicSymbol: `${prefix}_Pg_magic_func`,
-      initSymbol: null,
-      symbols: sqlName === "postgis"
-        ? [
-            { name: "difference", address: `${prefix}_difference` },
-            { name: "pg_finfo_difference", address: `pg_finfo_${prefix}_difference` },
-          ]
-        : [],
-    },
-    assets,
-  };
-}
-
-async function rewrittenResourceArchive(sqlName, archiveName, replacements) {
-  const source = path.join(sdk, "Tests", "Fixtures", "swiftpm-extension-resources", sqlName);
-  const stage = path.join(root, "rewritten-resources", archiveName.replace(/\.tar\.gz$/u, ""));
-  await fs.rm(stage, { recursive: true, force: true });
-  await fs.cp(source, stage, { recursive: true });
-  const manifestFile = path.join(stage, "manifest.properties");
-  let manifest = await fs.readFile(manifestFile, "utf8");
-  for (const [expected, replacement] of replacements) {
-    assert.ok(manifest.includes(expected), `resource fixture is missing ${expected}`);
-    manifest = manifest.replace(expected, replacement);
-  }
-  await fs.writeFile(manifestFile, manifest);
-  const archive = path.join(root, "archives", archiveName);
-  run("tar", ["--no-xattrs", "-czf", archive, "-C", stage, "."]);
-  return archive;
-}
-
-async function contaminatedResourceArchive(sqlName, archiveName, relativePath) {
-  const source = path.join(sdk, "Tests", "Fixtures", "swiftpm-extension-resources", sqlName);
-  const stage = path.join(root, "contaminated-resources", archiveName.replace(/\.tar\.gz$/u, ""));
-  await fs.rm(stage, { recursive: true, force: true });
-  await fs.cp(source, stage, { recursive: true });
-  const injected = path.join(stage, ...relativePath.split("/"));
-  await fs.mkdir(path.dirname(injected), { recursive: true });
-  await fs.writeFile(injected, "undeclared carrier contamination\n");
-  const archive = path.join(root, "archives", archiveName);
-  run("tar", ["--no-xattrs", "-czf", archive, "-C", stage, "."]);
-  return archive;
-}
-
-function dependencyReference(row) {
-  return {
-    product: row.product,
-    releaseProduct: row.releaseProduct,
-    sqlName: row.sqlName,
-    tag: row.tag,
-    version: row.version,
-  };
-}
-
-function extensionReleaseCarrier(baseRow, release, extensionRows, availableExtensions, availableCarriers) {
-  const carrierNames = new Set(extensionRows.flatMap((row) => row.assets.map(({ carrier }) => carrier)));
-  return {
-    schema: extensionCarrierSchema,
-    release: {
-      product: release.releaseProduct,
-      tag: release.tag,
-      version: release.version,
-    },
-    base: {
-      product: baseRow.product,
-      tag: baseRow.tag,
-      version: baseRow.version,
-    },
-    carriers: availableCarriers.filter(({ name }) => carrierNames.has(name)),
-    entries: extensionRows.map((extensionRow) => ({
-      dependencyCarriers: extensionRow.dependencies.map((sqlName) => {
-        const dependency = availableExtensions.find((row) => row.sqlName === sqlName);
-        assert.ok(dependency, `missing test dependency ${sqlName}`);
-        return dependencyReference(dependency);
-      }),
-      extension: extensionRow,
-    })),
-  };
-}
-
-function extensionCarrier(baseRow, extensionRow, availableExtensions, availableCarriers) {
-  return extensionReleaseCarrier(baseRow, extensionRow, [extensionRow], availableExtensions, availableCarriers);
-}
-
-async function nestExtensionCarrierPayloads(document, archiveName) {
-  const stage = path.join(root, `aggregate-${archiveName}`);
-  const carrierRoot = archiveName.replace(/\.tar\.gz$/u, "");
-  await fs.rm(stage, { recursive: true, force: true });
-  const byName = new Map(document.carriers.map((row) => [row.name, row]));
-  for (const { extension: extensionRow } of document.entries) {
-    for (const locator of extensionRow.assets) {
-      assert.equal(locator.path, ".");
-      const envelope = byName.get(locator.carrier);
-      assert.ok(envelope, `missing envelope ${locator.carrier}`);
-      const memberPath = `${carrierRoot}/extensions/${extensionRow.sqlName}/${envelope.name}`;
-      const destination = path.join(stage, ...memberPath.split("/"));
-      await fs.mkdir(path.dirname(destination), { recursive: true });
-      await fs.copyFile(new URL(envelope.url), destination);
-      locator.carrier = archiveName;
-      locator.path = memberPath;
-    }
-  }
-  const output = path.join(root, "archives", archiveName);
-  await fs.mkdir(path.dirname(output), { recursive: true });
-  run("tar", ["--format=ustar", "-czf", output, "-C", stage, carrierRoot]);
-  document.carriers = [{
-    name: archiveName,
-    url: pathToFileURL(output).href,
-    sha256: await checksum(output),
-    bytes: (await fs.stat(output)).size,
-    format: "tar.gz",
-  }];
-  return document;
-}
-
-async function main() {
-  assert.deepEqual(
-    localTarArchiveBinding("D:\\release\\bundle.tar.gz", path.win32),
-    { archiveName: "bundle.tar.gz", cwd: "D:\\release" },
-  );
-  assert.ok(!localTarArchiveBinding("D:\\release\\bundle.tar.gz", path.win32).archiveName.includes(":"));
-  await fs.rm(root, { force: true, recursive: true });
-  await fs.mkdir(root, { recursive: true });
-  const carrierized = carrierize([
-    await extension("cube", "cube"),
-    await extension("earthdistance", "earthdistance", ["cube"]),
-    await extension("pgtap", null),
-    await extension(
-      "postgis",
-      "postgis-3",
-      [],
-      postgisNativeDependencies.map(([name]) => name),
-    ),
-  ]);
-  const manifest = {
-    schema,
-    base: await base(),
-    carriers: carrierized.carriers,
-    extensions: carrierized.extensions,
-    legal: { base: [], extensions: [] },
-  };
-  const carrier = path.join(root, "oliphaunt-react-native-ios-carriers.json");
-  await fs.writeFile(carrier, `${JSON.stringify(manifest, null, 2)}\n`);
-
-  // Independently versioned extension content is governed by its frozen
-  // carrier row. A newer SDK catalog may change content metadata, but retains
-  // authority only over the stable SQL-name -> release-product ownership.
-  const frozenOldCarrier = structuredClone(manifest);
-  frozenOldCarrier.extensions = frozenOldCarrier.extensions.filter(
-    ({ sqlName }) => sqlName === "pgtap",
-  );
-  frozenOldCarrier.extensions[0].version = "0.9.0";
-  frozenOldCarrier.extensions[0].tag = "oliphaunt-extension-pgtap-v0.9.0";
-  const frozenCarrierNames = new Set(
-    frozenOldCarrier.extensions[0].assets.map(({ carrier: name }) => name),
-  );
-  frozenOldCarrier.carriers = frozenOldCarrier.carriers.filter(
-    ({ name }) => frozenCarrierNames.has(name),
-  );
-  const frozenOldCarrierFile = path.join(root, "pgtap-frozen-old-carrier.json");
-  await fs.writeFile(frozenOldCarrierFile, `${JSON.stringify(frozenOldCarrier, null, 2)}\n`);
-  const mutableNewCatalogFile = path.join(root, "mutable-new-swift-catalog.json");
-  await fs.writeFile(mutableNewCatalogFile, `${JSON.stringify({
-    "format-version": 1,
-    extensions: [{
-      "sql-name": "pgtap",
-      "artifact-product": "oliphaunt-extension-pgtap",
-      "release-product": "oliphaunt-extension-pgtap",
-      "creates-extension": false,
-      "native-module-stem": "future_pgtap",
-      "selected-extension-dependencies": ["cube"],
-      "runtime-share-data-files": ["future/data.dat"],
-      "extension-sql-file-names": ["future.sql"],
-      "extension-sql-file-prefixes": ["future"],
-      "shared-preload-libraries": ["future_preload"],
-    }],
-  }, null, 2)}\n`);
-  const frozenOldSelection = await resolveSwiftCarrierSelection({
-    allowFileUrls: true,
-    basePackageVersion: "0.1.0",
-    cacheDir: path.join(root, "frozen-old-cache"),
-    carrierFile: frozenOldCarrierFile,
-    extensions: ["pgtap"],
-    ownerCatalogFile: mutableNewCatalogFile,
-  });
-  assert.equal(frozenOldSelection.extensions[0].version, "0.9.0");
-  assert.deepEqual(frozenOldSelection.extensions[0].extensionSqlFileNames, [
-    "uninstall_pgtap.sql",
-  ]);
-  const pgtapOverride = structuredClone(manifest.extensions.find(({ sqlName }) => sqlName === "pgtap"));
-  pgtapOverride.version = "1.1.0";
-  pgtapOverride.tag = `${pgtapOverride.releaseProduct}-v${pgtapOverride.version}`;
-  const pgtapCarrierDocument = extensionCarrier(
-    manifest.base,
-    pgtapOverride,
-    manifest.extensions,
-    manifest.carriers,
-  );
-  const pgtapCarrier = path.join(root, "pgtap-1.1.0-swift-ios-carrier.json");
-  await fs.writeFile(pgtapCarrier, `${JSON.stringify(pgtapCarrierDocument, null, 2)}\n`);
-  const verifiedBase = path.join(root, "verified-base-xcframework");
-  const fakeArchiveTools = path.join(root, "fake-archive-tools");
-  await fs.mkdir(fakeArchiveTools, { recursive: true });
-  const fakeZipinfo = path.join(fakeArchiveTools, "zipinfo");
-  await fs.writeFile(fakeZipinfo, "#!/bin/sh\n# Reproduce a successful child whose formatted stdout was truncated.\nexit 0\n");
-  await fs.chmod(fakeZipinfo, 0o755);
-  const originalPath = process.env.PATH;
-  let verifiedTree;
-  try {
-    process.env.PATH = `${fakeArchiveTools}${path.delimiter}${originalPath ?? ""}`;
-    verifiedTree = await extractVerifiedZipArchive({
-      archive: path.join(root, "archives", "liboliphaunt-0.1.0-apple-spm-xcframework.zip"),
-      destination: verifiedBase,
-    });
-  } finally {
-    if (originalPath === undefined) delete process.env.PATH;
-    else process.env.PATH = originalPath;
-  }
-  assert.ok(verifiedTree.some(({ path: entry }) => entry === "liboliphaunt.xcframework/Info.plist"));
-  const cache = path.join(root, "cache");
-  const output = path.join(root, "selected");
-  const common = [
-    generator, "--carrier", carrier, "--extension-carrier", pgtapCarrier,
-    "--extensions", "earthdistance,pgtap,postgis",
-    "--cache-dir", cache, "--allow-file-urls", "--base-package-version", "0.1.0",
-  ];
-  run(process.execPath, [...common, "--output-dir", output]);
-  assert.deepEqual(
-    (await fs.readdir(output, { recursive: true })).filter((entry) => entry.endsWith(".a")),
-    [],
-    "carrier-resolved mobile static archives must not enter the generated Swift package",
-  );
-  const products = JSON.parse(await fs.readFile(path.join(output, "extension-products.json"), "utf8"));
-  assert.deepEqual(products.nativeRuntime, {
-    product: "liboliphaunt-native",
-    version: "0.1.0",
-  });
-  assert.deepEqual(products.selected.map(({ sqlName }) => sqlName), ["cube", "earthdistance", "pgtap", "postgis"]);
-  assert.equal(products.selected.find(({ sqlName }) => sqlName === "pgtap").version, "1.1.0");
-  const selectedPostgis = products.selected.find(({ sqlName }) => sqlName === "postgis");
-  assert.deepEqual(
-    selectedPostgis.nativeDependencies.map(({ name, binaryTarget }) => [name, binaryTarget]),
-    postgisNativeDependencies,
-  );
-  for (const [name, targetName] of postgisNativeDependencies) {
-    assert.deepEqual(
-      products.targets.find(({ name: candidate }) => candidate === targetName),
-      {
-        checksum: await checksum(path.join(root, "archives", `postgis-${name}.zip`)),
-        kind: "binaryTarget",
-        name: targetName,
-        url: pathToFileURL(path.join(root, "archives", `postgis-${name}.zip`)).href,
-      },
-    );
-  }
-  assert.ok(products.targets.some(({ name }) => name === "OliphauntExtensionPostgisBinary"));
-  assert.ok(!products.targets.some(({ name }) => name === "OliphauntExtensionPgtapBinary"));
-  assert.deepEqual(
-    products.targets.find(({ name }) => name === "COliphauntExtensionPostgis").dependencies
-      .filter((dependency) => typeof dependency === "string"),
-    [
-      "OliphauntExtensionPostgisBinary",
-      ...postgisNativeDependencies.map(([, targetName]) => targetName),
-    ],
-  );
-  assert.match(await fs.readFile(path.join(output, "Package.swift"), "utf8"), /postgis-framework\.zip/u);
-
-  const localOutput = path.join(root, "selected-local-binaries");
-  run(process.execPath, [
-    ...common,
-    "--local-binary-targets",
-    "--base-package-path", sdk,
-    "--output-dir", localOutput,
-  ]);
-  const localPackage = await fs.readFile(path.join(localOutput, "Package.swift"), "utf8");
-  assert.match(localPackage, /\.binaryTarget\([\s\S]*path: "Artifacts\/OliphauntExtensionPostgisBinary\.xcframework"/u);
-  assert.match(
-    localPackage,
-    /name: "COliphauntExtensionPostgis"[\s\S]*linkerSettings: \[\.linkedLibrary\("c\+\+"\)\]/u,
-  );
-  assert.doesNotMatch(localPackage, /postgis-framework\.zip/u);
-  for (const target of [
-    "OliphauntExtensionCubeBinary",
-    "OliphauntExtensionEarthdistanceBinary",
-    "OliphauntExtensionPostgisBinary",
-    ...postgisNativeDependencies.map(([, targetName]) => targetName),
-  ]) {
-    const artifact = path.join(localOutput, "Artifacts", `${target}.xcframework`, "Info.plist");
-    assert.equal((await fs.stat(artifact)).isFile(), true, `missing copied local binary target ${target}`);
-  }
-  for (const [, targetName] of postgisNativeDependencies) {
-    assert.match(
-      localPackage,
-      new RegExp(`\\.binaryTarget\\(\\s*name: "${targetName}",[\\s\\S]*?path: "Artifacts/${targetName}\\.xcframework"`, "u"),
-    );
-  }
-
-  const pgtapRuntime = manifest.extensions.find(({ sqlName }) => sqlName === "pgtap").assets[0];
-  const cachedPgtap = path.join(cache, "extracted", pgtapRuntime.sha256);
-  await fs.writeFile(path.join(cachedPgtap, "manifest.properties"), "tampered-cache-entry\n");
-  assert.equal((await fs.stat(`${cachedPgtap}.tree.json`)).isFile(), true);
-  const offlineOutput = path.join(root, "offline");
-  run(process.execPath, [...common, "--offline", "--output-dir", offlineOutput]);
-  assert.doesNotMatch(await fs.readFile(path.join(cachedPgtap, "manifest.properties"), "utf8"), /tampered-cache-entry/u);
-  run("diff", ["-ru", output, offlineOutput]);
-
-  async function expectCarrierFailure(name, candidate, selected, pattern) {
-    const file = path.join(root, `${name}.json`);
-    await fs.writeFile(file, `${JSON.stringify(candidate, null, 2)}\n`);
-    const diagnostic = run(process.execPath, [
-      generator, "--carrier", file, "--extensions", selected,
-      "--cache-dir", path.join(root, `${name}-cache`), "--allow-file-urls",
-      "--base-package-version", "0.1.0", "--output-dir", path.join(root, `${name}-output`),
-    ], { expectFailure: true });
-    assert.match(diagnostic, pattern);
-  }
-
-  async function expectResourceManifestFailure(name, replacements, pattern, sqlName = "pgtap") {
-    const archive = await rewrittenResourceArchive(
-      sqlName,
-      `${sqlName}-${name}.tar.gz`,
-      replacements,
-    );
-    const candidate = structuredClone(manifest);
-    setDirectExtensionAssets(candidate, sqlName, [
-      await asset("runtime-resources", archive, "tar.gz", "."),
-    ]);
-    await expectCarrierFailure(name, candidate, sqlName, pattern);
-  }
-
-  async function expectExtensionCarrierFailure(name, candidates, selected, pattern) {
-    const args = [generator, "--carrier", carrier];
-    for (const [index, candidate] of candidates.entries()) {
-      const file = path.join(root, `${name}-${index}-extension-carrier.json`);
-      await fs.writeFile(file, `${JSON.stringify(candidate, null, 2)}\n`);
-      args.push("--extension-carrier", file);
-    }
-    args.push(
-      "--extensions", selected,
-      "--cache-dir", path.join(root, `${name}-cache`),
-      "--allow-file-urls",
-      "--base-package-version", "0.1.0",
-      "--output-dir", path.join(root, `${name}-output`),
-    );
-    assert.match(run(process.execPath, args, { expectFailure: true }), pattern);
-  }
-
-  const contaminatedPgtapArchive = await contaminatedResourceArchive(
-    "pgtap",
-    "pgtap-recomputed-contaminated.tar.gz",
-    "files/share/postgresql/extension/pgtap-core-evil.control",
-  );
-  const contaminatedPgtapCarrier = structuredClone(manifest);
-  setDirectExtensionAssets(contaminatedPgtapCarrier, "pgtap", [
-    await asset("runtime-resources", contaminatedPgtapArchive, "tar.gz", "."),
-  ]);
-  await expectCarrierFailure(
-    "recomputed-contaminated-resource",
-    contaminatedPgtapCarrier,
-    "pgtap",
-    /undeclared extension SQL\/control file.*pgtap-core-evil\.control/u,
-  );
-
-  const contribOverrideRelease = {
-    product: "oliphaunt-extension-contrib-pg18",
-    releaseProduct: "liboliphaunt-native",
-    tag: "liboliphaunt-native-v1.1.0",
-    version: "1.1.0",
-  };
-  const contribOverrideRows = ["cube", "earthdistance"].map((sqlName) => {
-    const row = structuredClone(
-      manifest.extensions.find((extensionRow) => extensionRow.sqlName === sqlName),
-    );
-    Object.assign(row, contribOverrideRelease);
-    return row;
-  });
-  const earthdistanceCarrierDocument = extensionReleaseCarrier(
-    manifest.base,
-    contribOverrideRelease,
-    contribOverrideRows,
-    contribOverrideRows,
-    manifest.carriers,
-  );
-  const earthdistanceCarrier = path.join(root, "earthdistance-1.1.0-swift-ios-carrier.json");
-  await fs.writeFile(earthdistanceCarrier, `${JSON.stringify(earthdistanceCarrierDocument, null, 2)}\n`);
-  const composedOutput = path.join(root, "dependency-composed");
-  run(process.execPath, [
-    generator, "--carrier", carrier, "--extension-carrier", earthdistanceCarrier,
-    "--extensions", "earthdistance", "--cache-dir", path.join(root, "dependency-composed-cache"),
-    "--allow-file-urls", "--base-package-version", "0.1.0", "--output-dir", composedOutput,
-  ]);
-  const composedProducts = JSON.parse(await fs.readFile(path.join(composedOutput, "extension-products.json"), "utf8"));
-  assert.deepEqual(composedProducts.selected.map(({ sqlName, version }) => [sqlName, version]), [
-    ["cube", "1.1.0"],
-    ["earthdistance", "1.1.0"],
-  ]);
-
-  const bundleRelease = {
-    product: "oliphaunt-extension-contrib-pg18",
-    releaseProduct: "liboliphaunt-native",
-    tag: "liboliphaunt-native-v1.2.0",
-    version: "1.2.0",
-  };
-  const bundleRows = ["cube", "earthdistance"].map((sqlName) => {
-    const row = structuredClone(manifest.extensions.find((extensionRow) => extensionRow.sqlName === sqlName));
-    Object.assign(row, bundleRelease);
-    return row;
-  });
-  const pgTrgmRow = structuredClone(bundleRows.find(({ sqlName }) => sqlName === "cube"));
-  pgTrgmRow.sqlName = "pg_trgm";
-  pgTrgmRow.dependencies = [];
-  bundleRows.push(pgTrgmRow);
-  // ios-carrier-manifest.test.mjs proves that an extension-ci-artifacts-v2
-  // aggregate becomes this checksum-bound carrier shape. This consumer-side
-  // case proves partial selection and dependency closure from that aggregate.
-  const bundleDocument = await nestExtensionCarrierPayloads(extensionReleaseCarrier(
-    manifest.base,
-    bundleRelease,
-    bundleRows,
-    bundleRows,
-    manifest.carriers,
-  ), "oliphaunt-extension-contrib-pg18-1.2.0-native-ios-xcframework-bundle.tar.gz");
-  const bundleCarrier = path.join(root, "contrib-pg18-swift-ios-carrier.json");
-  await fs.writeFile(bundleCarrier, `${JSON.stringify(bundleDocument, null, 2)}\n`);
-  assert.equal(bundleDocument.schema, extensionCarrierSchema);
-  assert.deepEqual(bundleDocument.entries.map(({ extension }) => extension.sqlName), [
-    "cube",
-    "earthdistance",
-    "pg_trgm",
-  ]);
-  assert.deepEqual(bundleDocument.carriers.map(({ name }) => name), [
-    "oliphaunt-extension-contrib-pg18-1.2.0-native-ios-xcframework-bundle.tar.gz",
-  ]);
-  assert.deepEqual(
-    bundleDocument.entries.filter(({ extension }) => ["cube", "pg_trgm"].includes(extension.sqlName))
-      .map(({ extension }) => [extension.product, extension.version, extension.tag]),
-    [
-      [bundleRelease.product, bundleRelease.version, bundleRelease.tag],
-      [bundleRelease.product, bundleRelease.version, bundleRelease.tag],
-    ],
-  );
-  const bundleOutput = path.join(root, "bundle-selected");
-  run(process.execPath, [
-    generator, "--carrier", carrier, "--extension-carrier", bundleCarrier,
-    "--extensions", "earthdistance", "--cache-dir", path.join(root, "bundle-selected-cache"),
-    "--allow-file-urls", "--base-package-version", "0.1.0", "--output-dir", bundleOutput,
-  ]);
-  const bundleProducts = JSON.parse(await fs.readFile(path.join(bundleOutput, "extension-products.json"), "utf8"));
-  assert.deepEqual(bundleProducts.selected.map(({ product, sqlName, version }) => [product, sqlName, version]), [
-    ["oliphaunt-extension-contrib-pg18", "cube", "1.2.0"],
-    ["oliphaunt-extension-contrib-pg18", "earthdistance", "1.2.0"],
-  ]);
-  assert.deepEqual(
-    bundleProducts.targets.filter(({ kind }) => kind === "binaryTarget"),
-    [
-      {
-        kind: "binaryTarget",
-        name: "OliphauntExtensionCubeBinary",
-        path: "Artifacts/OliphauntExtensionCubeBinary.xcframework",
-      },
-      {
-        kind: "binaryTarget",
-        name: "OliphauntExtensionEarthdistanceBinary",
-        path: "Artifacts/OliphauntExtensionEarthdistanceBinary.xcframework",
-      },
-    ],
-  );
-  const bundlePackage = await fs.readFile(path.join(bundleOutput, "Package.swift"), "utf8");
-  for (const sqlName of ["Cube", "Earthdistance"]) {
-    const targetName = `OliphauntExtension${sqlName}Binary`;
-    assert.match(
-      bundlePackage,
-      new RegExp(`path: "Artifacts/${targetName}\\.xcframework"`, "u"),
-    );
-    assert.equal(
-      (await fs.stat(path.join(bundleOutput, "Artifacts", `${targetName}.xcframework`, "Info.plist"))).isFile(),
-      true,
-      `missing aggregate-carrier artifact for ${targetName}`,
-    );
-  }
-  assert.doesNotMatch(
-    bundlePackage,
-    /url: .*contrib-pg18.*bundle/u,
-  );
-
-  const contribV1 = structuredClone(bundleDocument);
-  contribV1.entries = contribV1.entries.filter(
-    ({ extension }) => extension.sqlName === "cube",
-  );
-  const contribV2 = structuredClone(bundleDocument);
-  contribV2.entries = contribV2.entries.filter(
-    ({ extension }) => extension.sqlName === "pg_trgm",
-  );
-  contribV2.release.version = "1.3.0";
-  contribV2.release.tag = `${contribV2.release.product}-v1.3.0`;
-  contribV2.entries[0].extension.version = "1.3.0";
-  contribV2.entries[0].extension.tag = contribV2.release.tag;
-  await expectExtensionCarrierFailure(
-    "same-owner-release-skew",
-    [contribV1, contribV2],
-    "cube,pg_trgm",
-    /resolved selected extensions assigns inconsistent version\/tag identities to release owner liboliphaunt-native/u,
-  );
-
-  const incompatibleBase = structuredClone(pgtapCarrierDocument);
-  incompatibleBase.base.version = "2.0.0";
-  incompatibleBase.base.tag = "liboliphaunt-native-v2.0.0";
-  await expectExtensionCarrierFailure("incompatible-base", [incompatibleBase], "pgtap", /requires liboliphaunt-native-v2\.0\.0.*provides liboliphaunt-native-v0\.1\.0/u);
-
-  const fakeOwner = structuredClone(pgtapCarrierDocument);
-  fakeOwner.entries[0].extension.product = "oliphaunt-extension-contrib-pg18";
-  await expectExtensionCarrierFailure(
-    "fake-independent-owner",
-    [fakeOwner],
-    "pgtap",
-    /product must be canonical artifact product oliphaunt-extension-pgtap for pgtap/u,
-  );
-
-  const leadingZeroVersion = structuredClone(pgtapCarrierDocument);
-  leadingZeroVersion.release.version = "01.1.0";
-  leadingZeroVersion.release.tag = "oliphaunt-extension-pgtap-v01.1.0";
-  leadingZeroVersion.entries[0].extension.version = "01.1.0";
-  leadingZeroVersion.entries[0].extension.tag = "oliphaunt-extension-pgtap-v01.1.0";
-  await expectExtensionCarrierFailure(
-    "leading-zero-version",
-    [leadingZeroVersion],
-    "pgtap",
-    /stable SemVer/u,
-  );
-
-  await expectExtensionCarrierFailure(
-    "duplicate-explicit-row",
-    [pgtapCarrierDocument, pgtapCarrierDocument],
-    "pgtap",
-    /repeat explicit row pgtap/u,
-  );
-  await expectExtensionCarrierFailure(
-    "unused-explicit-row",
-    [pgtapCarrierDocument],
-    "postgis",
-    /supplied no selected or required row/u,
-  );
-
-  const incompleteDependencyPins = structuredClone(earthdistanceCarrierDocument);
-  incompleteDependencyPins.entries.find(
-    ({ extension }) => extension.sqlName === "earthdistance",
-  ).dependencyCarriers = [];
-  await expectExtensionCarrierFailure(
-    "incomplete-dependency-pins",
-    [incompleteDependencyPins],
-    "earthdistance",
-    /must exactly pin earthdistance dependencies/u,
-  );
-
-  const omittedCanonicalDependency = structuredClone(earthdistanceCarrierDocument);
-  const omittedEarthdistance = omittedCanonicalDependency.entries.find(
-    ({ extension }) => extension.sqlName === "earthdistance",
-  );
-  omittedEarthdistance.extension.dependencies = [];
-  omittedEarthdistance.dependencyCarriers = [];
-  await expectExtensionCarrierFailure(
-    "omitted-canonical-dependency",
-    [omittedCanonicalDependency],
-    "earthdistance",
-    /manifest dependencies must be ""/u,
-  );
-
-  const substitutedCanonicalDependency = structuredClone(earthdistanceCarrierDocument);
-  const substitutedEarthdistance = substitutedCanonicalDependency.entries.find(
-    ({ extension }) => extension.sqlName === "earthdistance",
-  );
-  substitutedEarthdistance.extension.dependencies = ["pg_trgm"];
-  substitutedEarthdistance.dependencyCarriers = [
-    {
-      product: "oliphaunt-extension-contrib-pg18",
-      releaseProduct: "liboliphaunt-native",
-      sqlName: "pg_trgm",
-      tag: "liboliphaunt-native-v1.1.0",
-      version: "1.1.0",
-    },
-  ];
-  await expectExtensionCarrierFailure(
-    "substituted-canonical-dependency",
-    [substitutedCanonicalDependency],
-    "earthdistance",
-    /missing carrier for pg_trgm required by earthdistance/u,
-  );
-
-  const dependencySkewRelease = {
-    product: "oliphaunt-extension-contrib-pg18",
-    releaseProduct: "liboliphaunt-native",
-    tag: "liboliphaunt-native-v2.0.0",
-    version: "2.0.0",
-  };
-  const dependencySkewRows = ["cube", "earthdistance"].map((sqlName) => {
-    const row = structuredClone(
-      manifest.extensions.find((extensionRow) => extensionRow.sqlName === sqlName),
-    );
-    Object.assign(row, dependencySkewRelease);
-    return row;
-  });
-  const dependencySkewEarthdistance = extensionReleaseCarrier(
-    manifest.base,
-    dependencySkewRelease,
-    dependencySkewRows.filter(({ sqlName }) => sqlName === "earthdistance"),
-    dependencySkewRows,
-    manifest.carriers,
-  );
-  dependencySkewEarthdistance.entries[0].dependencyCarriers[0].version = "1.0.0";
-  dependencySkewEarthdistance.entries[0].dependencyCarriers[0].tag =
-    "liboliphaunt-native-v1.0.0";
-  const dependencySkewCube = extensionReleaseCarrier(
-    manifest.base,
-    dependencySkewRelease,
-    dependencySkewRows.filter(({ sqlName }) => sqlName === "cube"),
-    dependencySkewRows,
-    manifest.carriers,
-  );
-  await expectExtensionCarrierFailure(
-    "dependency-version-skew",
-    [dependencySkewEarthdistance, dependencySkewCube],
-    "earthdistance",
-    /earthdistance requires dependency carrier liboliphaunt-native-v1\.0\.0.*resolved liboliphaunt-native-v2\.0\.0/u,
-  );
-
-  const traversalArchive = path.join(root, "archives", "malicious-traversal.zip");
-  await maliciousZip(traversalArchive, "../escaped-from-swift.txt", "file");
-  const traversal = structuredClone(manifest);
-  setDirectExtensionAssets(traversal, "pgtap", [
-    await asset("runtime-resources", traversalArchive, "zip", "."),
-  ]);
-  await expectCarrierFailure("malicious-traversal", traversal, "pgtap", /unsafe/u);
-  await assert.rejects(fs.access(path.join(root, "malicious-traversal-cache", "extracted", "escaped-from-swift.txt")));
-  await assert.rejects(
-    extractVerifiedZipArchive({
-      archive: traversalArchive,
-      destination: path.join(root, "direct-traversal-output"),
-    }),
-    /unsafe/u,
-  );
-
-  const symlinkArchive = path.join(root, "archives", "malicious-symlink.zip");
-  await maliciousZip(symlinkArchive, "runtime-link", "symlink");
-  const symlink = structuredClone(manifest);
-  setDirectExtensionAssets(symlink, "pgtap", [
-    await asset("runtime-resources", symlinkArchive, "zip", "."),
-  ]);
-  await expectCarrierFailure("malicious-symlink", symlink, "pgtap", /link or special entry/u);
-  await assert.rejects(
-    extractVerifiedZipArchive({
-      archive: symlinkArchive,
-      destination: path.join(root, "direct-symlink-output"),
-    }),
-    /link or special entry/u,
-  );
-
-  const ambiguousUnixArchive = path.join(root, "archives", "ambiguous-unix-types.zip");
-  await metadataZip(ambiguousUnixArchive, "ambiguous-unix");
-  await assert.rejects(
-    extractVerifiedZipArchive({
-      archive: ambiguousUnixArchive,
-      destination: path.join(root, "ambiguous-unix-output"),
-    }),
-    /ambiguous Unix member type/u,
-  );
-
-  const fatArchive = path.join(root, "archives", "fat-types.zip");
-  await metadataZip(fatArchive, "fat");
-  const fatTree = await extractVerifiedZipArchive({
-    archive: fatArchive,
-    destination: path.join(root, "fat-output"),
-  });
-  assert.ok(fatTree.some(({ path: entry }) => entry === "liboliphaunt.xcframework/Info.plist"));
-
-  const unicodeExtraArchive = path.join(root, "archives", "unicode-path-extra.zip");
-  await metadataZip(unicodeExtraArchive, "unicode-extra");
-  await assert.rejects(
-    extractVerifiedZipArchive({
-      archive: unicodeExtraArchive,
-      destination: path.join(root, "unicode-path-extra-output"),
-    }),
-    /unsupported ZIP .* extra metadata .* field 0x7075/u,
-  );
-
-  const unsupportedFlagsArchive = path.join(root, "archives", "unsupported-flags.zip");
-  await metadataZip(unsupportedFlagsArchive, "fat");
-  await addUnsupportedZipFlag(unsupportedFlagsArchive);
-  await assert.rejects(
-    extractVerifiedZipArchive({
-      archive: unsupportedFlagsArchive,
-      destination: path.join(root, "unsupported-flags-output"),
-    }),
-    /unsupported ZIP general-purpose flags 0x20/u,
-  );
-
-  for (const [name, entries, pattern] of [
-    ["tar-file-directory-marker", [{ name: "payload", type: "file" }], /member type\/path marker mismatch/u],
-    ["tar-traversal", [{ name: "../payload", type: "file" }], /member is unsafe/u],
-    ["tar-symlink", [{ name: "payload", type: "symlink" }], /link or special entry/u],
-    ["tar-duplicate", [{ name: "payload", type: "file" }, { name: "payload", type: "file" }], /repeats a normalized archive member/u],
-    ["tar-case-collision", [{ name: "Payload", type: "file" }, { name: "payload", type: "file" }], /case\/NFC-colliding paths/u],
-    ["tar-non-nfc", [{ name: "cafe\u0301", type: "file" }], /must be canonical NFC/u],
-    ["tar-file-as-parent", [{ name: "parent", type: "file" }, { name: "parent/child", type: "file" }], /uses file parent as an archive directory/u],
-  ]) {
-    const archive = path.join(root, "archives", `${name}.tar.gz`);
-    await craftedTar(archive, entries);
-    if (name === "tar-file-directory-marker") await addTarFileSlash(archive, "payload");
-    const candidate = structuredClone(manifest);
-    setDirectExtensionAssets(candidate, "pgtap", [
-      await asset("runtime-resources", archive, "tar.gz", "."),
-    ]);
-    await expectCarrierFailure(name, candidate, "pgtap", pattern);
-  }
-
-  const unstable = structuredClone(manifest);
-  unstable.base.version = "1.0.0-rc.1";
-  unstable.base.tag = "liboliphaunt-native-v1.0.0-rc.1";
-  await expectCarrierFailure("unstable-version", unstable, "pgtap", /stable SemVer/u);
-
-  const wrongTag = structuredClone(manifest);
-  wrongTag.extensions.find(({ sqlName }) => sqlName === "pgtap").tag = "unrelated-v1.0.0";
-  await expectCarrierFailure("wrong-tag", wrongTag, "pgtap", /\.tag must be oliphaunt-extension-pgtap-v1\.0\.0/u);
-
-  const malformedAssets = structuredClone(manifest);
-  malformedAssets.base.assets = {};
-  await expectCarrierFailure("malformed-assets", malformedAssets, "pgtap", /base\.assets must be an array/u);
-
-  const malformedRegistration = structuredClone(manifest);
-  malformedRegistration.extensions.find(({ sqlName }) => sqlName === "cube").registration.symbols = "not-an-array";
-  await expectCarrierFailure("malformed-registration", malformedRegistration, "cube", /registration\.symbols must be an array/u);
-
-  await expectResourceManifestFailure(
-    "wrong-resource-native-runtime-version",
-    [["nativeRuntimeVersion=0.1.0", "nativeRuntimeVersion=9.9.9"]],
-    /manifest nativeRuntimeVersion must be "0\.1\.0"/u,
-  );
-  await expectResourceManifestFailure(
-    "missing-resource-native-runtime-product",
-    [["nativeRuntimeProduct=liboliphaunt-native\n", ""]],
-    /exact canonical fields in canonical order/u,
-  );
-  await expectResourceManifestFailure(
-    "missing-resource-native-runtime-version",
-    [["nativeRuntimeVersion=0.1.0\n", ""]],
-    /exact canonical fields in canonical order/u,
-  );
-  await expectResourceManifestFailure(
-    "wrong-resource-native-runtime-product",
-    [["nativeRuntimeProduct=liboliphaunt-native", "nativeRuntimeProduct=other-runtime"]],
-    /manifest nativeRuntimeProduct must be "liboliphaunt-native"/u,
-  );
-  await expectResourceManifestFailure(
-    "unknown-resource-manifest-field",
-    [["nativeRuntimeVersion=0.1.0\n", "nativeRuntimeVersion=0.1.0\nunexpectedField=value\n"]],
-    /exact canonical fields in canonical order/u,
-  );
-  await expectResourceManifestFailure(
-    "missing-resource-canonical-field",
-    [["nativeModuleFile=\n", ""]],
-    /exact canonical fields in canonical order/u,
-  );
-  await expectResourceManifestFailure(
-    "wrong-resource-native-module-file",
-    [["nativeModuleFile=\n", "nativeModuleFile=other.dylib\n"]],
-    /manifest nativeModuleFile must be ""/u,
-  );
-  await expectResourceManifestFailure(
-    "wrong-resource-static-symbol-prefix",
-    [["staticSymbolPrefix=\n", "staticSymbolPrefix=oliphaunt_static_other\n"]],
-    /manifest staticSymbolPrefix must be ""/u,
-  );
-  await expectResourceManifestFailure(
-    "wrong-resource-static-symbol-alias",
-    [["staticSymbolAliases=\n", "staticSymbolAliases=sql_symbol:linked_symbol\n"]],
-    /manifest staticSymbolAliases do not match carrier registration metadata/u,
-  );
-
-  const mismatchedCreatesExtension = structuredClone(manifest);
-  mismatchedCreatesExtension.extensions.find(({ sqlName }) => sqlName === "pgtap").createsExtension = false;
-  await expectCarrierFailure(
-    "mismatched-creates-extension",
-    mismatchedCreatesExtension,
-    "pgtap",
-    /manifest createsExtension must be "no"/u,
-  );
-
-  const duplicateName = structuredClone(manifest);
-  duplicateName.carriers.push({ ...duplicateName.carriers[0], sha256: "0".repeat(64) });
-  await expectCarrierFailure("duplicate-asset-name", duplicateName, "postgis", /repeats a carrier name/u);
-
-  const duplicateIdentity = structuredClone(manifest);
-  const duplicateIdentityPostgis = duplicateIdentity.extensions.find(({ sqlName }) => sqlName === "postgis");
-  const geosAsset = duplicateIdentityPostgis.assets.find(({ role }) => role === "dependency-xcframework");
-  const geosEnvelope = duplicateIdentity.carriers.find(({ name }) => name === geosAsset.carrier);
-  const duplicateGeosArchive = path.join(root, "archives", "postgis-geos-duplicate.zip");
-  await fs.copyFile(new URL(geosEnvelope.url), duplicateGeosArchive);
-  const duplicateGeos = carrierize([{
-    ...duplicateIdentityPostgis,
-    assets: [await asset(
-      "dependency-xcframework",
-      duplicateGeosArchive,
-      "zip",
-      `nested/${path.posix.basename(geosAsset.member)}`,
-    )],
-  }]);
-  duplicateIdentityPostgis.assets.push(duplicateGeos.extensions[0].assets[0]);
-  duplicateIdentity.carriers.push(...duplicateGeos.carriers);
-  duplicateIdentity.carriers.sort((left, right) => left.name.localeCompare(right.name));
-  await expectCarrierFailure("duplicate-dependency-identity", duplicateIdentity, "postgis", /repeats a dependency carrier identity/u);
-
-  const missingFile = path.join(root, "missing-dependency.json");
-  const missingExtensions = manifest.extensions.filter(({ sqlName }) => sqlName === "earthdistance");
-  const missingCarrierNames = new Set(missingExtensions.flatMap((row) => row.assets.map(({ carrier }) => carrier)));
-  await fs.writeFile(missingFile, `${JSON.stringify({
-    ...manifest,
-    carriers: manifest.carriers.filter(({ name }) => missingCarrierNames.has(name)),
-    extensions: missingExtensions,
-  }, null, 2)}\n`);
-  assert.match(run(process.execPath, [
-    generator, "--carrier", missingFile, "--extensions", "earthdistance", "--cache-dir", path.join(root, "missing-cache"),
-    "--allow-file-urls", "--base-package-version", "0.1.0", "--output-dir", path.join(root, "missing-output"),
-  ], { expectFailure: true }), /missing carrier for cube required by earthdistance/u);
-
-  const tampered = structuredClone(manifest);
-  const tamperedAsset = tampered.extensions.find(({ sqlName }) => sqlName === "postgis").assets[0];
-  tamperedAsset.sha256 = "0".repeat(64);
-  tampered.carriers.find(({ name }) => name === tamperedAsset.carrier).sha256 = "0".repeat(64);
-  const tamperedFile = path.join(root, "tampered.json");
-  await fs.writeFile(tamperedFile, `${JSON.stringify(tampered, null, 2)}\n`);
-  const diagnostic = run(process.execPath, [
-    generator, "--carrier", tamperedFile, "--extensions", "postgis", "--cache-dir", path.join(root, "tampered-cache"),
-    "--allow-file-urls", "--base-package-version", "0.1.0", "--output-dir", path.join(root, "tampered-output"),
-  ], { expectFailure: true });
-  assert.match(diagnostic, /checksum mismatch/u);
-
-  // Recreate only the SQL-only archive and leave a buildable consumer package
-  // for check-sdk's clean Swift compile/link lane.
-  const pgtap = await extension("pgtap", null);
-  const sqlOnly = carrierize([pgtap]);
-  const sqlCarrier = path.join(root, "sql-only-carrier.json");
-  await fs.writeFile(sqlCarrier, `${JSON.stringify({
-    ...manifest,
-    carriers: sqlOnly.carriers,
-    extensions: sqlOnly.extensions,
-  }, null, 2)}\n`);
-  const sqlOutput = path.join(root, "sql-only");
-  run(process.execPath, [
-    generator, "--carrier", sqlCarrier, "--extensions", "pgtap", "--cache-dir", path.join(root, "sql-cache"),
-    "--allow-file-urls", "--base-package-version", "0.1.0", "--base-package-path", sdk, "--output-dir", sqlOutput,
-  ]);
-  const sqlPackage = await fs.readFile(path.join(sqlOutput, "Package.swift"), "utf8");
-  assert.doesNotMatch(sqlPackage, /binaryTarget/u);
-  console.log(`swift-carrier-resolver.test.mjs: metadata, malicious ZIP, cache-tamper, and consumer checks passed; sql-only-package=${sqlOutput}`);
-}
-
-main().catch((error) => { console.error(error.stack ?? String(error)); process.exit(1); });
diff --git a/src/sdks/swift/tools/swift-carrier-resolver.test.mts b/src/sdks/swift/tools/swift-carrier-resolver.test.mts
new file mode 100755
index 000000000..0ea9823a7
--- /dev/null
+++ b/src/sdks/swift/tools/swift-carrier-resolver.test.mts
@@ -0,0 +1,1467 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import { pathToFileURL } from 'node:url';
+import { gunzipSync, gzipSync } from 'node:zlib';
+import { archiveDirectory } from '../../../../tools/packaging/archive-directory.mts';
+import { craftedTar } from '../../../../tools/packaging/testdata/tar-fixture.mts';
+import {
+  fixtureFiles,
+  maliciousZip,
+  metadataZip,
+} from '../../../../tools/packaging/testdata/zip-fixture.mts';
+import { renderExtensionProducts } from './render-extension-products.mts';
+import {
+  extractVerifiedZipArchive,
+  resolveSwiftCarrierSelection,
+} from './swift-carrier-resolver.mts';
+
+const sdk = path.resolve(import.meta.dirname, '..');
+const root = path.resolve(
+  process.argv[2] ?? path.join(sdk, '../../../target/liboliphaunt-sdk-check/swift-carrier-test'),
+);
+const generator = path.join(import.meta.dirname, 'render-extension-products.mts');
+const schema = 'oliphaunt-react-native-ios-carrier-v1';
+const extensionCarrierSchema = 'oliphaunt-swift-extension-carrier-v1';
+const postgisNativeDependencies = [
+  ['geos', 'OliphauntNativeDependencyGeos'],
+  ['geos-c', 'OliphauntNativeDependencyGeosC'],
+  ['json-c', 'OliphauntNativeDependencyJsonC'],
+  ['libxml2', 'OliphauntNativeDependencyLibxml2'],
+  ['proj', 'OliphauntNativeDependencyProj'],
+  ['sqlite', 'OliphauntNativeDependencySqlite'],
+];
+const productionDependencyArchiveNames = new Map([
+  ['geos', 'libgeos.a'],
+  ['geos-c', 'libgeos_c.a'],
+  ['json-c', 'libjson-c.a'],
+  ['libxml2', 'libxml2.a'],
+  ['proj', 'libproj.a'],
+  ['sqlite', 'libsqlite3.a'],
+]);
+const frozenContent = new Map([
+  [
+    'pgtap',
+    {
+      dataFiles: [],
+      extensionSqlFileNames: ['uninstall_pgtap.sql'],
+      extensionSqlFilePrefixes: ['pgtap-core', 'pgtap-schema'],
+    },
+  ],
+  [
+    'postgis',
+    {
+      dataFiles: [
+        'contrib/postgis-3.6/legacy.sql',
+        'contrib/postgis-3.6/legacy_gist.sql',
+        'contrib/postgis-3.6/legacy_minimal.sql',
+        'contrib/postgis-3.6/postgis.sql',
+        'contrib/postgis-3.6/postgis_upgrade.sql',
+        'contrib/postgis-3.6/spatial_ref_sys.sql',
+        'contrib/postgis-3.6/uninstall_legacy.sql',
+        'contrib/postgis-3.6/uninstall_postgis.sql',
+        'proj/proj.db',
+      ],
+      extensionSqlFileNames: ['uninstall_postgis.sql'],
+      extensionSqlFilePrefixes: ['postgis_comments', 'postgis_proc_set_search_path', 'rtpostgis'],
+    },
+  ],
+]);
+
+async function render(args, options = {}) {
+  try {
+    await renderExtensionProducts(args.slice(1));
+  } catch (error) {
+    if (!options.expectFailure) throw error;
+    return String(error);
+  }
+  assert.ok(!options.expectFailure, 'invalid carrier unexpectedly rendered');
+}
+async function checksum(file) {
+  return createHash('sha256')
+    .update(await fs.readFile(file))
+    .digest('hex');
+}
+async function asset(role, file, format, member) {
+  return {
+    role,
+    name: path.basename(file),
+    url: pathToFileURL(file).href,
+    sha256: await checksum(file),
+    bytes: (await fs.stat(file)).size,
+    format,
+    member,
+  };
+}
+function carrierize(rawExtensions) {
+  const carriers = new Map();
+  const extensions = rawExtensions.map((extensionRow) => ({
+    ...extensionRow,
+    assets: extensionRow.assets.map((raw) => {
+      const envelope = {
+        name: raw.name,
+        url: raw.url,
+        sha256: raw.sha256,
+        bytes: raw.bytes,
+        format: raw.format,
+      };
+      const existing = carriers.get(envelope.name);
+      if (existing !== undefined) assert.deepEqual(existing, envelope);
+      carriers.set(envelope.name, envelope);
+      return {
+        role: raw.role,
+        carrier: envelope.name,
+        path: '.',
+        sha256: raw.sha256,
+        bytes: raw.bytes,
+        format: raw.format,
+        member: raw.member,
+      };
+    }),
+  }));
+  return {
+    carriers: [...carriers.values()].sort((left, right) => left.name.localeCompare(right.name)),
+    extensions,
+  };
+}
+function setDirectExtensionAssets(document, sqlName, rawAssets) {
+  const extensionRow = document.extensions.find((row) => row.sqlName === sqlName);
+  assert.ok(extensionRow, `missing ${sqlName} fixture row`);
+  const converted = carrierize([{ ...extensionRow, assets: rawAssets }]);
+  extensionRow.assets = converted.extensions[0].assets;
+  const referenced = new Set(
+    document.extensions.flatMap((row) => row.assets.map(({ carrier }) => carrier)),
+  );
+  const byName = new Map(
+    document.carriers.filter(({ name }) => referenced.has(name)).map((row) => [row.name, row]),
+  );
+  for (const row of converted.carriers) byName.set(row.name, row);
+  document.carriers = [...byName.values()].sort((left, right) =>
+    left.name.localeCompare(right.name),
+  );
+}
+
+async function addUnsupportedZipFlag(archive) {
+  const buffer = await fs.readFile(archive);
+  const eocd = buffer.length - 22;
+  assert.equal(buffer.readUInt32LE(eocd), 0x06054b50);
+  const centralOffset = buffer.readUInt32LE(eocd + 16);
+  assert.equal(buffer.readUInt32LE(centralOffset), 0x02014b50);
+  const localOffset = buffer.readUInt32LE(centralOffset + 42);
+  assert.equal(buffer.readUInt32LE(localOffset), 0x04034b50);
+  buffer.writeUInt16LE(buffer.readUInt16LE(centralOffset + 8) | 0x20, centralOffset + 8);
+  buffer.writeUInt16LE(buffer.readUInt16LE(localOffset + 6) | 0x20, localOffset + 6);
+  await fs.writeFile(archive, buffer);
+}
+
+async function removeTarDirectorySlash(archive, member) {
+  const tar = gunzipSync(await fs.readFile(archive));
+  let found = false;
+  for (let offset = 0; offset + 512 <= tar.length; ) {
+    const header = tar.subarray(offset, offset + 512);
+    if (header.every((value) => value === 0)) break;
+    const field = (start, length) => {
+      const bytes = header.subarray(start, start + length);
+      const end = bytes.indexOf(0);
+      return bytes.subarray(0, end < 0 ? bytes.length : end).toString('utf8');
+    };
+    const name = field(0, 100);
+    const prefix = field(345, 155);
+    const fullName = prefix ? `${prefix}/${name}` : name;
+    const size = Number.parseInt(field(124, 12).trim() || '0', 8);
+    assert.ok(Number.isSafeInteger(size) && size >= 0, `invalid tar size for ${fullName}`);
+    if (fullName === member) {
+      assert.equal(String.fromCharCode(header[156]), '5', `${member} must be a directory header`);
+      assert.equal(prefix, '', `${member} test helper only supports the ustar name field`);
+      assert.ok(name.endsWith('/'), `${member} must initially use a canonical directory marker`);
+      header[name.length - 1] = 0;
+      header.fill(0x20, 148, 156);
+      const checksum = header.reduce((total, value) => total + value, 0);
+      Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `, 'ascii').copy(header, 148);
+      found = true;
+    }
+    offset += 512 + Math.ceil(size / 512) * 512;
+  }
+  assert.equal(found, true, `missing tar directory ${member}`);
+  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
+}
+async function addTarFileSlash(archive, member) {
+  const tar = gunzipSync(await fs.readFile(archive));
+  let found = false;
+  for (let offset = 0; offset + 512 <= tar.length; ) {
+    const header = tar.subarray(offset, offset + 512);
+    if (header.every((value) => value === 0)) break;
+    const end = header.subarray(0, 100).indexOf(0);
+    const name = header.subarray(0, end < 0 ? 100 : end).toString('utf8');
+    const sizeEnd = header.subarray(124, 136).indexOf(0);
+    const size = Number.parseInt(
+      header
+        .subarray(124, sizeEnd < 0 ? 136 : 124 + sizeEnd)
+        .toString('utf8')
+        .trim() || '0',
+      8,
+    );
+    if (name === member) {
+      assert.equal(
+        String.fromCharCode(header[156]),
+        '0',
+        `${member} must be a regular file header`,
+      );
+      assert.ok(member.length < 99, `${member} must leave room for a slash`);
+      header[member.length] = '/'.charCodeAt(0);
+      header[member.length + 1] = 0;
+      header.fill(0x20, 148, 156);
+      const checksum = header.reduce((total, value) => total + value, 0);
+      Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `, 'ascii').copy(header, 148);
+      found = true;
+    }
+    offset += 512 + Math.ceil(size / 512) * 512;
+  }
+  assert.equal(found, true, `missing tar file ${member}`);
+  await fs.writeFile(archive, gzipSync(tar, { mtime: 0 }));
+}
+async function zipFramework(name, archive) {
+  const parent = path.join(root, 'frameworks');
+  await fs.mkdir(path.join(parent, name), { recursive: true });
+  await fs.writeFile(path.join(parent, name, 'Info.plist'), '\n');
+  await archiveDirectory(path.join(parent, name), archive, { keepParent: true });
+}
+async function base() {
+  const archives = path.join(root, 'archives');
+  await fs.mkdir(archives, { recursive: true });
+  const framework = path.join(archives, 'liboliphaunt-0.1.0-apple-spm-xcframework.zip');
+  await zipFramework('liboliphaunt.xcframework', framework);
+  const runtimeSource = path.join(root, 'base', 'runtime', 'oliphaunt');
+  await fs.mkdir(runtimeSource, { recursive: true });
+  await fs.writeFile(path.join(runtimeSource, 'fixture.txt'), 'runtime\n');
+  const runtime = path.join(archives, 'liboliphaunt-0.1.0-runtime-resources-ios-datum64.tar.gz');
+  await archiveDirectory(runtimeSource, runtime, { keepParent: true });
+  return {
+    assets: [
+      await asset('base-xcframework', framework, 'zip', 'liboliphaunt.xcframework'),
+      await asset('runtime-resources', runtime, 'tar.gz', 'oliphaunt'),
+    ],
+    product: 'liboliphaunt-native',
+    tag: 'liboliphaunt-native-v0.1.0',
+    version: '0.1.0',
+  };
+}
+
+async function productionExtensionResource(sqlName, stem, nativeDependencies) {
+  const source = path.join(sdk, 'Tests', 'Fixtures', 'swiftpm-extension-resources', sqlName);
+  if (stem === null) return source;
+  const stage = path.join(root, 'production-extension-resources', sqlName);
+  await fs.rm(stage, { recursive: true, force: true });
+  await fs.cp(source, stage, { recursive: true });
+  const targets = ['ios-device', 'ios-simulator'];
+  const mobileStaticArchives = targets.map(
+    (target) =>
+      `${target}:mobile-static/${target}/extensions/${stem}/` + `liboliphaunt_extension_${stem}.a`,
+  );
+  const mobileStaticDependencyArchives = targets.flatMap((target) =>
+    nativeDependencies.map((dependency) => {
+      const archiveName = productionDependencyArchiveNames.get(dependency) ?? `lib${dependency}.a`;
+      return `${target}:${dependency}:mobile-static/${target}/dependencies/${dependency}/${archiveName}`;
+    }),
+  );
+  if (nativeDependencies.includes('geos') && nativeDependencies.includes('geos-c')) {
+    assert.notDeepEqual(
+      mobileStaticDependencyArchives,
+      [...mobileStaticDependencyArchives].sort(),
+      'the production fixture must preserve structured order that differs from raw-string order',
+    );
+  }
+  const manifestFile = path.join(stage, 'manifest.properties');
+  let manifest = await fs.readFile(manifestFile, 'utf8');
+  assert.ok(manifest.includes('mobileStaticArchives=\n'));
+  assert.ok(manifest.includes('mobileStaticDependencyArchives=\n'));
+  manifest = manifest
+    .replace('mobileStaticArchives=\n', `mobileStaticArchives=${mobileStaticArchives.join(',')}\n`)
+    .replace(
+      'mobileStaticDependencyArchives=\n',
+      `mobileStaticDependencyArchives=${mobileStaticDependencyArchives.join(',')}\n`,
+    );
+  await fs.writeFile(manifestFile, manifest);
+  for (const row of [...mobileStaticArchives, ...mobileStaticDependencyArchives]) {
+    const relative = row.slice(row.lastIndexOf(':') + 1);
+    const archive = path.join(stage, ...relative.split('/'));
+    await fs.mkdir(path.dirname(archive), { recursive: true });
+    await fs.writeFile(archive, `static archive fixture for ${sqlName}\n`);
+  }
+  return stage;
+}
+
+async function extension(sqlName, stem, dependencies = [], nativeDependencies = []) {
+  const resource = await productionExtensionResource(sqlName, stem, nativeDependencies);
+  const runtime = path.join(root, 'archives', `${sqlName}-runtime.tar.gz`);
+  await fs.mkdir(path.dirname(runtime), { recursive: true });
+  await archiveDirectory(resource, runtime);
+  if (sqlName === 'cube') {
+    // Reproduce the valid POSIX typeflag-5/no-trailing-slash carrier emitted by
+    // the previous archive producer and rejected by the failed CI run.
+    await removeTarDirectorySlash(runtime, 'files/');
+  }
+  const assets = [await asset('runtime-resources', runtime, 'tar.gz', '.')];
+  if (stem !== null) {
+    const frameworkName = `liboliphaunt_extension_${stem}.xcframework`;
+    const archive = path.join(root, 'archives', `${sqlName}-framework.zip`);
+    await zipFramework(frameworkName, archive);
+    assets.push(await asset('extension-xcframework', archive, 'zip', frameworkName));
+    for (const dependency of nativeDependencies) {
+      const dependencyName = `liboliphaunt_dependency_${dependency}.xcframework`;
+      const dependencyArchive = path.join(root, 'archives', `${sqlName}-${dependency}.zip`);
+      await zipFramework(dependencyName, dependencyArchive);
+      assets.push(await asset('dependency-xcframework', dependencyArchive, 'zip', dependencyName));
+    }
+  }
+  const prefix =
+    stem === null ? null : `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`;
+  const product = new Set(['cube', 'earthdistance', 'pg_trgm']).has(sqlName)
+    ? 'oliphaunt-extension-contrib-pg18'
+    : `oliphaunt-extension-${sqlName.replaceAll('_', '-')}`;
+  const releaseProduct =
+    product === 'oliphaunt-extension-contrib-pg18' ? 'liboliphaunt-native' : product;
+  const version = sqlName === 'postgis' ? '3.6.1' : '1.0.0';
+  const content = frozenContent.get(sqlName) ?? {
+    dataFiles: [],
+    extensionSqlFileNames: [],
+    extensionSqlFilePrefixes: [],
+  };
+  return {
+    product,
+    releaseProduct,
+    version,
+    tag: `${releaseProduct}-v${version}`,
+    sqlName,
+    createsExtension: true,
+    dataFiles: content.dataFiles,
+    dependencies,
+    extensionSqlFileNames: content.extensionSqlFileNames,
+    extensionSqlFilePrefixes: content.extensionSqlFilePrefixes,
+    nativeDependencies,
+    nativeModuleStem: stem,
+    sharedPreloadLibraries: [],
+    registration:
+      stem === null
+        ? null
+        : {
+            magicSymbol: `${prefix}_Pg_magic_func`,
+            initSymbol: null,
+            symbols:
+              sqlName === 'postgis'
+                ? [
+                    { name: 'difference', address: `${prefix}_difference` },
+                    { name: 'pg_finfo_difference', address: `pg_finfo_${prefix}_difference` },
+                  ]
+                : [],
+          },
+    assets,
+  };
+}
+
+async function rewrittenResourceArchive(sqlName, archiveName, replacements) {
+  const source = path.join(sdk, 'Tests', 'Fixtures', 'swiftpm-extension-resources', sqlName);
+  const stage = path.join(root, 'rewritten-resources', archiveName.replace(/\.tar\.gz$/u, ''));
+  await fs.rm(stage, { recursive: true, force: true });
+  await fs.cp(source, stage, { recursive: true });
+  const manifestFile = path.join(stage, 'manifest.properties');
+  let manifest = await fs.readFile(manifestFile, 'utf8');
+  for (const [expected, replacement] of replacements) {
+    assert.ok(manifest.includes(expected), `resource fixture is missing ${expected}`);
+    manifest = manifest.replace(expected, replacement);
+  }
+  await fs.writeFile(manifestFile, manifest);
+  const archive = path.join(root, 'archives', archiveName);
+  await archiveDirectory(stage, archive);
+  return archive;
+}
+
+async function contaminatedResourceArchive(sqlName, archiveName, relativePath) {
+  const source = path.join(sdk, 'Tests', 'Fixtures', 'swiftpm-extension-resources', sqlName);
+  const stage = path.join(root, 'contaminated-resources', archiveName.replace(/\.tar\.gz$/u, ''));
+  await fs.rm(stage, { recursive: true, force: true });
+  await fs.cp(source, stage, { recursive: true });
+  const injected = path.join(stage, ...relativePath.split('/'));
+  await fs.mkdir(path.dirname(injected), { recursive: true });
+  await fs.writeFile(injected, 'undeclared carrier contamination\n');
+  const archive = path.join(root, 'archives', archiveName);
+  await archiveDirectory(stage, archive);
+  return archive;
+}
+
+function dependencyReference(row) {
+  return {
+    product: row.product,
+    releaseProduct: row.releaseProduct,
+    sqlName: row.sqlName,
+    tag: row.tag,
+    version: row.version,
+  };
+}
+
+function extensionReleaseCarrier(
+  baseRow,
+  release,
+  extensionRows,
+  availableExtensions,
+  availableCarriers,
+) {
+  const carrierNames = new Set(
+    extensionRows.flatMap((row) => row.assets.map(({ carrier }) => carrier)),
+  );
+  return {
+    schema: extensionCarrierSchema,
+    release: {
+      product: release.releaseProduct,
+      tag: release.tag,
+      version: release.version,
+    },
+    base: {
+      product: baseRow.product,
+      tag: baseRow.tag,
+      version: baseRow.version,
+    },
+    carriers: availableCarriers.filter(({ name }) => carrierNames.has(name)),
+    entries: extensionRows.map((extensionRow) => ({
+      dependencyCarriers: extensionRow.dependencies.map((sqlName) => {
+        const dependency = availableExtensions.find((row) => row.sqlName === sqlName);
+        assert.ok(dependency, `missing test dependency ${sqlName}`);
+        return dependencyReference(dependency);
+      }),
+      extension: extensionRow,
+    })),
+  };
+}
+
+function extensionCarrier(baseRow, extensionRow, availableExtensions, availableCarriers) {
+  return extensionReleaseCarrier(
+    baseRow,
+    extensionRow,
+    [extensionRow],
+    availableExtensions,
+    availableCarriers,
+  );
+}
+
+async function nestExtensionCarrierPayloads(document, archiveName) {
+  const stage = path.join(root, `aggregate-${archiveName}`);
+  const carrierRoot = archiveName.replace(/\.tar\.gz$/u, '');
+  await fs.rm(stage, { recursive: true, force: true });
+  const byName = new Map(document.carriers.map((row) => [row.name, row]));
+  for (const { extension: extensionRow } of document.entries) {
+    for (const locator of extensionRow.assets) {
+      assert.equal(locator.path, '.');
+      const envelope = byName.get(locator.carrier);
+      assert.ok(envelope, `missing envelope ${locator.carrier}`);
+      const memberPath = `${carrierRoot}/extensions/${extensionRow.sqlName}/${envelope.name}`;
+      const destination = path.join(stage, ...memberPath.split('/'));
+      await fs.mkdir(path.dirname(destination), { recursive: true });
+      await fs.copyFile(new URL(envelope.url), destination);
+      locator.carrier = archiveName;
+      locator.path = memberPath;
+    }
+  }
+  const output = path.join(root, 'archives', archiveName);
+  await fs.mkdir(path.dirname(output), { recursive: true });
+  await archiveDirectory(path.join(stage, carrierRoot), output, { keepParent: true });
+  document.carriers = [
+    {
+      name: archiveName,
+      url: pathToFileURL(output).href,
+      sha256: await checksum(output),
+      bytes: (await fs.stat(output)).size,
+      format: 'tar.gz',
+    },
+  ];
+  return document;
+}
+
+async function main() {
+  await fs.rm(root, { force: true, recursive: true });
+  await fs.mkdir(root, { recursive: true });
+  const carrierized = carrierize([
+    await extension('cube', 'cube'),
+    await extension('earthdistance', 'earthdistance', ['cube']),
+    await extension('pgtap', null),
+    await extension(
+      'postgis',
+      'postgis-3',
+      [],
+      postgisNativeDependencies.map(([name]) => name),
+    ),
+  ]);
+  const manifest = {
+    schema,
+    base: await base(),
+    carriers: carrierized.carriers,
+    extensions: carrierized.extensions,
+    legal: { base: [], extensions: [] },
+  };
+  const carrier = path.join(root, 'oliphaunt-react-native-ios-carriers.json');
+  await fs.writeFile(carrier, `${JSON.stringify(manifest, null, 2)}\n`);
+
+  // Independently versioned extension content is governed by its frozen
+  // carrier row. A newer SDK catalog may change content metadata, but retains
+  // authority only over the stable SQL-name -> release-product ownership.
+  const frozenOldCarrier = structuredClone(manifest);
+  frozenOldCarrier.extensions = frozenOldCarrier.extensions.filter(
+    ({ sqlName }) => sqlName === 'pgtap',
+  );
+  frozenOldCarrier.extensions[0].version = '0.9.0';
+  frozenOldCarrier.extensions[0].tag = 'oliphaunt-extension-pgtap-v0.9.0';
+  const frozenCarrierNames = new Set(
+    frozenOldCarrier.extensions[0].assets.map(({ carrier: name }) => name),
+  );
+  frozenOldCarrier.carriers = frozenOldCarrier.carriers.filter(({ name }) =>
+    frozenCarrierNames.has(name),
+  );
+  const frozenOldCarrierFile = path.join(root, 'pgtap-frozen-old-carrier.json');
+  await fs.writeFile(frozenOldCarrierFile, `${JSON.stringify(frozenOldCarrier, null, 2)}\n`);
+  const mutableNewCatalogFile = path.join(root, 'mutable-new-swift-catalog.json');
+  await fs.writeFile(
+    mutableNewCatalogFile,
+    `${JSON.stringify(
+      {
+        'format-version': 1,
+        extensions: [
+          {
+            'sql-name': 'pgtap',
+            'artifact-product': 'oliphaunt-extension-pgtap',
+            'release-product': 'oliphaunt-extension-pgtap',
+            'creates-extension': false,
+            'native-module-stem': 'future_pgtap',
+            'selected-extension-dependencies': ['cube'],
+            'runtime-share-data-files': ['future/data.dat'],
+            'extension-sql-file-names': ['future.sql'],
+            'extension-sql-file-prefixes': ['future'],
+            'shared-preload-libraries': ['future_preload'],
+          },
+        ],
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  const frozenOldSelection = await resolveSwiftCarrierSelection({
+    allowFileUrls: true,
+    basePackageVersion: '0.1.0',
+    cacheDir: path.join(root, 'frozen-old-cache'),
+    carrierFile: frozenOldCarrierFile,
+    extensions: ['pgtap'],
+    ownerCatalogFile: mutableNewCatalogFile,
+  });
+  assert.equal(frozenOldSelection.extensions[0].version, '0.9.0');
+  assert.deepEqual(frozenOldSelection.extensions[0].extensionSqlFileNames, ['uninstall_pgtap.sql']);
+  const pgtapOverride = structuredClone(
+    manifest.extensions.find(({ sqlName }) => sqlName === 'pgtap'),
+  );
+  pgtapOverride.version = '1.1.0';
+  pgtapOverride.tag = `${pgtapOverride.releaseProduct}-v${pgtapOverride.version}`;
+  const pgtapCarrierDocument = extensionCarrier(
+    manifest.base,
+    pgtapOverride,
+    manifest.extensions,
+    manifest.carriers,
+  );
+  const pgtapCarrier = path.join(root, 'pgtap-1.1.0-swift-ios-carrier.json');
+  await fs.writeFile(pgtapCarrier, `${JSON.stringify(pgtapCarrierDocument, null, 2)}\n`);
+  const verifiedBase = path.join(root, 'verified-base-xcframework');
+  const fakeArchiveTools = path.join(root, 'fake-archive-tools');
+  await fs.mkdir(fakeArchiveTools, { recursive: true });
+  const fakeZipinfo = path.join(fakeArchiveTools, 'zipinfo');
+  await fs.writeFile(
+    fakeZipinfo,
+    '#!/bin/sh\n# Reproduce a successful child whose formatted stdout was truncated.\nexit 0\n',
+  );
+  await fs.chmod(fakeZipinfo, 0o755);
+  const originalPath = process.env.PATH;
+  let verifiedTree;
+  try {
+    process.env.PATH = `${fakeArchiveTools}${path.delimiter}${originalPath ?? ''}`;
+    verifiedTree = await extractVerifiedZipArchive({
+      archive: path.join(root, 'archives', 'liboliphaunt-0.1.0-apple-spm-xcframework.zip'),
+      destination: verifiedBase,
+    });
+  } finally {
+    if (originalPath === undefined) delete process.env.PATH;
+    else process.env.PATH = originalPath;
+  }
+  assert.ok(
+    verifiedTree.some(({ path: entry }) => entry === 'liboliphaunt.xcframework/Info.plist'),
+  );
+  const cache = path.join(root, 'cache');
+  const output = path.join(root, 'selected');
+  const common = [
+    generator,
+    '--carrier',
+    carrier,
+    '--extension-carrier',
+    pgtapCarrier,
+    '--extensions',
+    'earthdistance,pgtap,postgis',
+    '--cache-dir',
+    cache,
+    '--allow-file-urls',
+    '--base-package-version',
+    '0.1.0',
+  ];
+  await render([...common, '--output-dir', output]);
+  assert.deepEqual(
+    (await fs.readdir(output, { recursive: true })).filter((entry) => entry.endsWith('.a')),
+    [],
+    'carrier-resolved mobile static archives must not enter the generated Swift package',
+  );
+  const products = JSON.parse(
+    await fs.readFile(path.join(output, 'extension-products.json'), 'utf8'),
+  );
+  assert.deepEqual(products.nativeRuntime, {
+    product: 'liboliphaunt-native',
+    version: '0.1.0',
+  });
+  assert.deepEqual(
+    products.selected.map(({ sqlName }) => sqlName),
+    ['cube', 'earthdistance', 'pgtap', 'postgis'],
+  );
+  assert.equal(products.selected.find(({ sqlName }) => sqlName === 'pgtap').version, '1.1.0');
+  const selectedPostgis = products.selected.find(({ sqlName }) => sqlName === 'postgis');
+  assert.deepEqual(
+    selectedPostgis.nativeDependencies.map(({ name, binaryTarget }) => [name, binaryTarget]),
+    postgisNativeDependencies,
+  );
+  for (const [name, targetName] of postgisNativeDependencies) {
+    assert.deepEqual(
+      products.targets.find(({ name: candidate }) => candidate === targetName),
+      {
+        checksum: await checksum(path.join(root, 'archives', `postgis-${name}.zip`)),
+        kind: 'binaryTarget',
+        name: targetName,
+        url: pathToFileURL(path.join(root, 'archives', `postgis-${name}.zip`)).href,
+      },
+    );
+  }
+  assert.ok(products.targets.some(({ name }) => name === 'OliphauntExtensionPostgisBinary'));
+  assert.ok(!products.targets.some(({ name }) => name === 'OliphauntExtensionPgtapBinary'));
+  assert.deepEqual(
+    products.targets
+      .find(({ name }) => name === 'COliphauntExtensionPostgis')
+      .dependencies.filter((dependency) => typeof dependency === 'string'),
+    [
+      'OliphauntExtensionPostgisBinary',
+      ...postgisNativeDependencies.map(([, targetName]) => targetName),
+    ],
+  );
+  assert.match(
+    await fs.readFile(path.join(output, 'Package.swift'), 'utf8'),
+    /postgis-framework\.zip/u,
+  );
+
+  const localOutput = path.join(root, 'selected-local-binaries');
+  await render([
+    ...common,
+    '--local-binary-targets',
+    '--base-package-path',
+    sdk,
+    '--output-dir',
+    localOutput,
+  ]);
+  const localPackage = await fs.readFile(path.join(localOutput, 'Package.swift'), 'utf8');
+  assert.match(
+    localPackage,
+    /\.binaryTarget\([\s\S]*path: "Artifacts\/OliphauntExtensionPostgisBinary\.xcframework"/u,
+  );
+  assert.match(
+    localPackage,
+    /name: "COliphauntExtensionPostgis"[\s\S]*linkerSettings: \[\.linkedLibrary\("c\+\+"\)\]/u,
+  );
+  assert.doesNotMatch(localPackage, /postgis-framework\.zip/u);
+  for (const target of [
+    'OliphauntExtensionCubeBinary',
+    'OliphauntExtensionEarthdistanceBinary',
+    'OliphauntExtensionPostgisBinary',
+    ...postgisNativeDependencies.map(([, targetName]) => targetName),
+  ]) {
+    const artifact = path.join(localOutput, 'Artifacts', `${target}.xcframework`, 'Info.plist');
+    assert.equal(
+      (await fs.stat(artifact)).isFile(),
+      true,
+      `missing copied local binary target ${target}`,
+    );
+  }
+  for (const [, targetName] of postgisNativeDependencies) {
+    assert.match(
+      localPackage,
+      new RegExp(
+        `\\.binaryTarget\\(\\s*name: "${targetName}",[\\s\\S]*?path: "Artifacts/${targetName}\\.xcframework"`,
+        'u',
+      ),
+    );
+  }
+
+  const pgtapRuntime = manifest.extensions.find(({ sqlName }) => sqlName === 'pgtap').assets[0];
+  const cachedPgtap = path.join(cache, 'extracted', pgtapRuntime.sha256);
+  await fs.writeFile(path.join(cachedPgtap, 'manifest.properties'), 'tampered-cache-entry\n');
+  assert.equal((await fs.stat(`${cachedPgtap}.tree.json`)).isFile(), true);
+  const offlineOutput = path.join(root, 'offline');
+  await render([...common, '--offline', '--output-dir', offlineOutput]);
+  assert.doesNotMatch(
+    await fs.readFile(path.join(cachedPgtap, 'manifest.properties'), 'utf8'),
+    /tampered-cache-entry/u,
+  );
+  assert.deepEqual(await fixtureFiles(output), await fixtureFiles(offlineOutput));
+
+  async function expectCarrierFailure(name, candidate, selected, pattern) {
+    const file = path.join(root, `${name}.json`);
+    await fs.writeFile(file, `${JSON.stringify(candidate, null, 2)}\n`);
+    const diagnostic = await render(
+      [
+        generator,
+        '--carrier',
+        file,
+        '--extensions',
+        selected,
+        '--cache-dir',
+        path.join(root, `${name}-cache`),
+        '--allow-file-urls',
+        '--base-package-version',
+        '0.1.0',
+        '--output-dir',
+        path.join(root, `${name}-output`),
+      ],
+      { expectFailure: true },
+    );
+    assert.match(diagnostic, pattern);
+  }
+
+  async function expectResourceManifestFailure(name, replacements, pattern, sqlName = 'pgtap') {
+    const archive = await rewrittenResourceArchive(
+      sqlName,
+      `${sqlName}-${name}.tar.gz`,
+      replacements,
+    );
+    const candidate = structuredClone(manifest);
+    setDirectExtensionAssets(candidate, sqlName, [
+      await asset('runtime-resources', archive, 'tar.gz', '.'),
+    ]);
+    await expectCarrierFailure(name, candidate, sqlName, pattern);
+  }
+
+  async function expectExtensionCarrierFailure(name, candidates, selected, pattern) {
+    const args = [generator, '--carrier', carrier];
+    for (const [index, candidate] of candidates.entries()) {
+      const file = path.join(root, `${name}-${index}-extension-carrier.json`);
+      await fs.writeFile(file, `${JSON.stringify(candidate, null, 2)}\n`);
+      args.push('--extension-carrier', file);
+    }
+    args.push(
+      '--extensions',
+      selected,
+      '--cache-dir',
+      path.join(root, `${name}-cache`),
+      '--allow-file-urls',
+      '--base-package-version',
+      '0.1.0',
+      '--output-dir',
+      path.join(root, `${name}-output`),
+    );
+    assert.match(await render(args, { expectFailure: true }), pattern);
+  }
+
+  const contaminatedPgtapArchive = await contaminatedResourceArchive(
+    'pgtap',
+    'pgtap-recomputed-contaminated.tar.gz',
+    'files/share/postgresql/extension/pgtap-core-evil.control',
+  );
+  const contaminatedPgtapCarrier = structuredClone(manifest);
+  setDirectExtensionAssets(contaminatedPgtapCarrier, 'pgtap', [
+    await asset('runtime-resources', contaminatedPgtapArchive, 'tar.gz', '.'),
+  ]);
+  await expectCarrierFailure(
+    'recomputed-contaminated-resource',
+    contaminatedPgtapCarrier,
+    'pgtap',
+    /undeclared extension SQL\/control file.*pgtap-core-evil\.control/u,
+  );
+
+  const contribOverrideRelease = {
+    product: 'oliphaunt-extension-contrib-pg18',
+    releaseProduct: 'liboliphaunt-native',
+    tag: 'liboliphaunt-native-v1.1.0',
+    version: '1.1.0',
+  };
+  const contribOverrideRows = ['cube', 'earthdistance'].map((sqlName) => {
+    const row = structuredClone(
+      manifest.extensions.find((extensionRow) => extensionRow.sqlName === sqlName),
+    );
+    Object.assign(row, contribOverrideRelease);
+    return row;
+  });
+  const earthdistanceCarrierDocument = extensionReleaseCarrier(
+    manifest.base,
+    contribOverrideRelease,
+    contribOverrideRows,
+    contribOverrideRows,
+    manifest.carriers,
+  );
+  const earthdistanceCarrier = path.join(root, 'earthdistance-1.1.0-swift-ios-carrier.json');
+  await fs.writeFile(
+    earthdistanceCarrier,
+    `${JSON.stringify(earthdistanceCarrierDocument, null, 2)}\n`,
+  );
+  const composedOutput = path.join(root, 'dependency-composed');
+  await render([
+    generator,
+    '--carrier',
+    carrier,
+    '--extension-carrier',
+    earthdistanceCarrier,
+    '--extensions',
+    'earthdistance',
+    '--cache-dir',
+    path.join(root, 'dependency-composed-cache'),
+    '--allow-file-urls',
+    '--base-package-version',
+    '0.1.0',
+    '--output-dir',
+    composedOutput,
+  ]);
+  const composedProducts = JSON.parse(
+    await fs.readFile(path.join(composedOutput, 'extension-products.json'), 'utf8'),
+  );
+  assert.deepEqual(
+    composedProducts.selected.map(({ sqlName, version }) => [sqlName, version]),
+    [
+      ['cube', '1.1.0'],
+      ['earthdistance', '1.1.0'],
+    ],
+  );
+
+  const bundleRelease = {
+    product: 'oliphaunt-extension-contrib-pg18',
+    releaseProduct: 'liboliphaunt-native',
+    tag: 'liboliphaunt-native-v1.2.0',
+    version: '1.2.0',
+  };
+  const bundleRows = ['cube', 'earthdistance'].map((sqlName) => {
+    const row = structuredClone(
+      manifest.extensions.find((extensionRow) => extensionRow.sqlName === sqlName),
+    );
+    Object.assign(row, bundleRelease);
+    return row;
+  });
+  const pgTrgmRow = structuredClone(bundleRows.find(({ sqlName }) => sqlName === 'cube'));
+  pgTrgmRow.sqlName = 'pg_trgm';
+  pgTrgmRow.dependencies = [];
+  bundleRows.push(pgTrgmRow);
+  // ios-carrier-manifest.test.mts proves that an extension-ci-artifacts-v2
+  // aggregate becomes this checksum-bound carrier shape. This consumer-side
+  // case proves partial selection and dependency closure from that aggregate.
+  const bundleDocument = await nestExtensionCarrierPayloads(
+    extensionReleaseCarrier(
+      manifest.base,
+      bundleRelease,
+      bundleRows,
+      bundleRows,
+      manifest.carriers,
+    ),
+    'oliphaunt-extension-contrib-pg18-1.2.0-native-ios-xcframework-bundle.tar.gz',
+  );
+  const bundleCarrier = path.join(root, 'contrib-pg18-swift-ios-carrier.json');
+  await fs.writeFile(bundleCarrier, `${JSON.stringify(bundleDocument, null, 2)}\n`);
+  assert.equal(bundleDocument.schema, extensionCarrierSchema);
+  assert.deepEqual(
+    bundleDocument.entries.map(({ extension }) => extension.sqlName),
+    ['cube', 'earthdistance', 'pg_trgm'],
+  );
+  assert.deepEqual(
+    bundleDocument.carriers.map(({ name }) => name),
+    ['oliphaunt-extension-contrib-pg18-1.2.0-native-ios-xcframework-bundle.tar.gz'],
+  );
+  assert.deepEqual(
+    bundleDocument.entries
+      .filter(({ extension }) => ['cube', 'pg_trgm'].includes(extension.sqlName))
+      .map(({ extension }) => [extension.product, extension.version, extension.tag]),
+    [
+      [bundleRelease.product, bundleRelease.version, bundleRelease.tag],
+      [bundleRelease.product, bundleRelease.version, bundleRelease.tag],
+    ],
+  );
+  const bundleOutput = path.join(root, 'bundle-selected');
+  await render([
+    generator,
+    '--carrier',
+    carrier,
+    '--extension-carrier',
+    bundleCarrier,
+    '--extensions',
+    'earthdistance',
+    '--cache-dir',
+    path.join(root, 'bundle-selected-cache'),
+    '--allow-file-urls',
+    '--base-package-version',
+    '0.1.0',
+    '--output-dir',
+    bundleOutput,
+  ]);
+  const bundleProducts = JSON.parse(
+    await fs.readFile(path.join(bundleOutput, 'extension-products.json'), 'utf8'),
+  );
+  assert.deepEqual(
+    bundleProducts.selected.map(({ product, sqlName, version }) => [product, sqlName, version]),
+    [
+      ['oliphaunt-extension-contrib-pg18', 'cube', '1.2.0'],
+      ['oliphaunt-extension-contrib-pg18', 'earthdistance', '1.2.0'],
+    ],
+  );
+  assert.deepEqual(
+    bundleProducts.targets.filter(({ kind }) => kind === 'binaryTarget'),
+    [
+      {
+        kind: 'binaryTarget',
+        name: 'OliphauntExtensionCubeBinary',
+        path: 'Artifacts/OliphauntExtensionCubeBinary.xcframework',
+      },
+      {
+        kind: 'binaryTarget',
+        name: 'OliphauntExtensionEarthdistanceBinary',
+        path: 'Artifacts/OliphauntExtensionEarthdistanceBinary.xcframework',
+      },
+    ],
+  );
+  const bundlePackage = await fs.readFile(path.join(bundleOutput, 'Package.swift'), 'utf8');
+  for (const sqlName of ['Cube', 'Earthdistance']) {
+    const targetName = `OliphauntExtension${sqlName}Binary`;
+    assert.match(bundlePackage, new RegExp(`path: "Artifacts/${targetName}\\.xcframework"`, 'u'));
+    assert.equal(
+      (
+        await fs.stat(
+          path.join(bundleOutput, 'Artifacts', `${targetName}.xcframework`, 'Info.plist'),
+        )
+      ).isFile(),
+      true,
+      `missing aggregate-carrier artifact for ${targetName}`,
+    );
+  }
+  assert.doesNotMatch(bundlePackage, /url: .*contrib-pg18.*bundle/u);
+
+  const contribV1 = structuredClone(bundleDocument);
+  contribV1.entries = contribV1.entries.filter(({ extension }) => extension.sqlName === 'cube');
+  const contribV2 = structuredClone(bundleDocument);
+  contribV2.entries = contribV2.entries.filter(({ extension }) => extension.sqlName === 'pg_trgm');
+  contribV2.release.version = '1.3.0';
+  contribV2.release.tag = `${contribV2.release.product}-v1.3.0`;
+  contribV2.entries[0].extension.version = '1.3.0';
+  contribV2.entries[0].extension.tag = contribV2.release.tag;
+  await expectExtensionCarrierFailure(
+    'same-owner-release-skew',
+    [contribV1, contribV2],
+    'cube,pg_trgm',
+    /resolved selected extensions assigns inconsistent version\/tag identities to release owner liboliphaunt-native/u,
+  );
+
+  const incompatibleBase = structuredClone(pgtapCarrierDocument);
+  incompatibleBase.base.version = '2.0.0';
+  incompatibleBase.base.tag = 'liboliphaunt-native-v2.0.0';
+  await expectExtensionCarrierFailure(
+    'incompatible-base',
+    [incompatibleBase],
+    'pgtap',
+    /requires liboliphaunt-native-v2\.0\.0.*provides liboliphaunt-native-v0\.1\.0/u,
+  );
+
+  const fakeOwner = structuredClone(pgtapCarrierDocument);
+  fakeOwner.entries[0].extension.product = 'oliphaunt-extension-contrib-pg18';
+  await expectExtensionCarrierFailure(
+    'fake-independent-owner',
+    [fakeOwner],
+    'pgtap',
+    /product must be canonical artifact product oliphaunt-extension-pgtap for pgtap/u,
+  );
+
+  const leadingZeroVersion = structuredClone(pgtapCarrierDocument);
+  leadingZeroVersion.release.version = '01.1.0';
+  leadingZeroVersion.release.tag = 'oliphaunt-extension-pgtap-v01.1.0';
+  leadingZeroVersion.entries[0].extension.version = '01.1.0';
+  leadingZeroVersion.entries[0].extension.tag = 'oliphaunt-extension-pgtap-v01.1.0';
+  await expectExtensionCarrierFailure(
+    'leading-zero-version',
+    [leadingZeroVersion],
+    'pgtap',
+    /stable SemVer/u,
+  );
+
+  await expectExtensionCarrierFailure(
+    'duplicate-explicit-row',
+    [pgtapCarrierDocument, pgtapCarrierDocument],
+    'pgtap',
+    /repeat explicit row pgtap/u,
+  );
+  await expectExtensionCarrierFailure(
+    'unused-explicit-row',
+    [pgtapCarrierDocument],
+    'postgis',
+    /supplied no selected or required row/u,
+  );
+
+  const incompleteDependencyPins = structuredClone(earthdistanceCarrierDocument);
+  incompleteDependencyPins.entries.find(
+    ({ extension }) => extension.sqlName === 'earthdistance',
+  ).dependencyCarriers = [];
+  await expectExtensionCarrierFailure(
+    'incomplete-dependency-pins',
+    [incompleteDependencyPins],
+    'earthdistance',
+    /must exactly pin earthdistance dependencies/u,
+  );
+
+  const omittedCanonicalDependency = structuredClone(earthdistanceCarrierDocument);
+  const omittedEarthdistance = omittedCanonicalDependency.entries.find(
+    ({ extension }) => extension.sqlName === 'earthdistance',
+  );
+  omittedEarthdistance.extension.dependencies = [];
+  omittedEarthdistance.dependencyCarriers = [];
+  await expectExtensionCarrierFailure(
+    'omitted-canonical-dependency',
+    [omittedCanonicalDependency],
+    'earthdistance',
+    /manifest dependencies must be ""/u,
+  );
+
+  const substitutedCanonicalDependency = structuredClone(earthdistanceCarrierDocument);
+  const substitutedEarthdistance = substitutedCanonicalDependency.entries.find(
+    ({ extension }) => extension.sqlName === 'earthdistance',
+  );
+  substitutedEarthdistance.extension.dependencies = ['pg_trgm'];
+  substitutedEarthdistance.dependencyCarriers = [
+    {
+      product: 'oliphaunt-extension-contrib-pg18',
+      releaseProduct: 'liboliphaunt-native',
+      sqlName: 'pg_trgm',
+      tag: 'liboliphaunt-native-v1.1.0',
+      version: '1.1.0',
+    },
+  ];
+  await expectExtensionCarrierFailure(
+    'substituted-canonical-dependency',
+    [substitutedCanonicalDependency],
+    'earthdistance',
+    /missing carrier for pg_trgm required by earthdistance/u,
+  );
+
+  const dependencySkewRelease = {
+    product: 'oliphaunt-extension-contrib-pg18',
+    releaseProduct: 'liboliphaunt-native',
+    tag: 'liboliphaunt-native-v2.0.0',
+    version: '2.0.0',
+  };
+  const dependencySkewRows = ['cube', 'earthdistance'].map((sqlName) => {
+    const row = structuredClone(
+      manifest.extensions.find((extensionRow) => extensionRow.sqlName === sqlName),
+    );
+    Object.assign(row, dependencySkewRelease);
+    return row;
+  });
+  const dependencySkewEarthdistance = extensionReleaseCarrier(
+    manifest.base,
+    dependencySkewRelease,
+    dependencySkewRows.filter(({ sqlName }) => sqlName === 'earthdistance'),
+    dependencySkewRows,
+    manifest.carriers,
+  );
+  dependencySkewEarthdistance.entries[0].dependencyCarriers[0].version = '1.0.0';
+  dependencySkewEarthdistance.entries[0].dependencyCarriers[0].tag = 'liboliphaunt-native-v1.0.0';
+  const dependencySkewCube = extensionReleaseCarrier(
+    manifest.base,
+    dependencySkewRelease,
+    dependencySkewRows.filter(({ sqlName }) => sqlName === 'cube'),
+    dependencySkewRows,
+    manifest.carriers,
+  );
+  await expectExtensionCarrierFailure(
+    'dependency-version-skew',
+    [dependencySkewEarthdistance, dependencySkewCube],
+    'earthdistance',
+    /earthdistance requires dependency carrier liboliphaunt-native-v1\.0\.0.*resolved liboliphaunt-native-v2\.0\.0/u,
+  );
+
+  const traversalArchive = path.join(root, 'archives', 'malicious-traversal.zip');
+  await maliciousZip(traversalArchive, '../escaped-from-swift.txt', 'file');
+  const traversal = structuredClone(manifest);
+  const traversalAsset = await asset('runtime-resources', traversalArchive, 'zip', '.');
+  setDirectExtensionAssets(traversal, 'pgtap', [traversalAsset]);
+  const previousTree = path.join(
+    root,
+    'malicious-traversal-cache',
+    'extracted',
+    traversalAsset.sha256,
+  );
+  await fs.mkdir(previousTree, { recursive: true });
+  await fs.writeFile(path.join(previousTree, 'existing.txt'), 'preserve existing content');
+  await fs.writeFile(`${previousTree}.tree.json`, 'preserve existing manifest');
+  await expectCarrierFailure('malicious-traversal', traversal, 'pgtap', /unsafe/u);
+  assert.equal(
+    await fs.readFile(path.join(previousTree, 'existing.txt'), 'utf8'),
+    'preserve existing content',
+  );
+  assert.equal(
+    await fs.readFile(`${previousTree}.tree.json`, 'utf8'),
+    'preserve existing manifest',
+  );
+  await assert.rejects(
+    fs.access(path.join(root, 'malicious-traversal-cache', 'extracted', 'escaped-from-swift.txt')),
+  );
+  await assert.rejects(
+    extractVerifiedZipArchive({
+      archive: traversalArchive,
+      destination: path.join(root, 'direct-traversal-output'),
+    }),
+    /unsafe/u,
+  );
+
+  const symlinkArchive = path.join(root, 'archives', 'malicious-symlink.zip');
+  await maliciousZip(symlinkArchive, 'runtime-link', 'symlink');
+  const symlink = structuredClone(manifest);
+  setDirectExtensionAssets(symlink, 'pgtap', [
+    await asset('runtime-resources', symlinkArchive, 'zip', '.'),
+  ]);
+  await expectCarrierFailure(
+    'malicious-symlink',
+    symlink,
+    'pgtap',
+    /link or special (?:ZIP )?entry/u,
+  );
+  await assert.rejects(
+    extractVerifiedZipArchive({
+      archive: symlinkArchive,
+      destination: path.join(root, 'direct-symlink-output'),
+    }),
+    /link or special (?:ZIP )?entry/u,
+  );
+
+  const ambiguousUnixArchive = path.join(root, 'archives', 'ambiguous-unix-types.zip');
+  await metadataZip(ambiguousUnixArchive, 'ambiguous-unix');
+  await assert.rejects(
+    extractVerifiedZipArchive({
+      archive: ambiguousUnixArchive,
+      destination: path.join(root, 'ambiguous-unix-output'),
+    }),
+    /ambiguous Unix creator type/u,
+  );
+
+  const fatArchive = path.join(root, 'archives', 'fat-types.zip');
+  await metadataZip(fatArchive, 'fat');
+  const fatTree = await extractVerifiedZipArchive({
+    archive: fatArchive,
+    destination: path.join(root, 'fat-output'),
+  });
+  assert.ok(fatTree.some(({ path: entry }) => entry === 'liboliphaunt.xcframework/Info.plist'));
+
+  const unicodeExtraArchive = path.join(root, 'archives', 'unicode-path-extra.zip');
+  await metadataZip(unicodeExtraArchive, 'unicode-extra');
+  await assert.rejects(
+    extractVerifiedZipArchive({
+      archive: unicodeExtraArchive,
+      destination: path.join(root, 'unicode-path-extra-output'),
+    }),
+    /unsupported ZIP .* extra field 0x7075/u,
+  );
+
+  const unsupportedFlagsArchive = path.join(root, 'archives', 'unsupported-flags.zip');
+  await metadataZip(unsupportedFlagsArchive, 'fat');
+  await addUnsupportedZipFlag(unsupportedFlagsArchive);
+  await assert.rejects(
+    extractVerifiedZipArchive({
+      archive: unsupportedFlagsArchive,
+      destination: path.join(root, 'unsupported-flags-output'),
+    }),
+    /unsupported or encrypted ZIP flags 0x20/u,
+  );
+
+  for (const [name, entries, pattern] of [
+    [
+      'tar-file-directory-marker',
+      [{ name: 'payload', type: 'file' }],
+      /member type\/path-marker mismatch/u,
+    ],
+    ['tar-traversal', [{ name: '../payload', type: 'file' }], /unsafe archive member/u],
+    ['tar-symlink', [{ name: 'payload', type: 'symlink' }], /link or special ustar entry/u],
+    [
+      'tar-duplicate',
+      [
+        { name: 'payload', type: 'file' },
+        { name: 'payload', type: 'file' },
+      ],
+      /repeats archive member|EEXIST/u,
+    ],
+    [
+      'tar-case-collision',
+      [
+        { name: 'Payload', type: 'file' },
+        { name: 'payload', type: 'file' },
+      ],
+      /case\/NFC-colliding archive members/u,
+    ],
+    ['tar-non-nfc', [{ name: 'cafe\u0301', type: 'file' }], /non-NFC archive member/u],
+    [
+      'tar-file-as-parent',
+      [
+        { name: 'parent', type: 'file' },
+        { name: 'parent/child', type: 'file' },
+      ],
+      /uses regular file parent as an archive directory|EEXIST|ENOTDIR/u,
+    ],
+  ]) {
+    const archive = path.join(root, 'archives', `${name}.tar.gz`);
+    await craftedTar(archive, entries);
+    if (name === 'tar-file-directory-marker') await addTarFileSlash(archive, 'payload');
+    const candidate = structuredClone(manifest);
+    setDirectExtensionAssets(candidate, 'pgtap', [
+      await asset('runtime-resources', archive, 'tar.gz', '.'),
+    ]);
+    await expectCarrierFailure(name, candidate, 'pgtap', pattern);
+  }
+
+  const unstable = structuredClone(manifest);
+  unstable.base.version = '1.0.0-rc.1';
+  unstable.base.tag = 'liboliphaunt-native-v1.0.0-rc.1';
+  await expectCarrierFailure('unstable-version', unstable, 'pgtap', /stable SemVer/u);
+
+  const wrongTag = structuredClone(manifest);
+  wrongTag.extensions.find(({ sqlName }) => sqlName === 'pgtap').tag = 'unrelated-v1.0.0';
+  await expectCarrierFailure(
+    'wrong-tag',
+    wrongTag,
+    'pgtap',
+    /\.tag must be oliphaunt-extension-pgtap-v1\.0\.0/u,
+  );
+
+  const malformedAssets = structuredClone(manifest);
+  malformedAssets.base.assets = {};
+  await expectCarrierFailure(
+    'malformed-assets',
+    malformedAssets,
+    'pgtap',
+    /base\.assets must be an array/u,
+  );
+
+  const malformedRegistration = structuredClone(manifest);
+  malformedRegistration.extensions.find(({ sqlName }) => sqlName === 'cube').registration.symbols =
+    'not-an-array';
+  await expectCarrierFailure(
+    'malformed-registration',
+    malformedRegistration,
+    'cube',
+    /registration\.symbols must be an array/u,
+  );
+
+  await expectResourceManifestFailure(
+    'wrong-resource-native-runtime-version',
+    [['nativeRuntimeVersion=0.1.0', 'nativeRuntimeVersion=9.9.9']],
+    /manifest nativeRuntimeVersion must be "0\.1\.0"/u,
+  );
+  await expectResourceManifestFailure(
+    'missing-resource-native-runtime-product',
+    [['nativeRuntimeProduct=liboliphaunt-native\n', '']],
+    /exact canonical fields in canonical order/u,
+  );
+  await expectResourceManifestFailure(
+    'missing-resource-native-runtime-version',
+    [['nativeRuntimeVersion=0.1.0\n', '']],
+    /exact canonical fields in canonical order/u,
+  );
+  await expectResourceManifestFailure(
+    'wrong-resource-native-runtime-product',
+    [['nativeRuntimeProduct=liboliphaunt-native', 'nativeRuntimeProduct=other-runtime']],
+    /manifest nativeRuntimeProduct must be "liboliphaunt-native"/u,
+  );
+  await expectResourceManifestFailure(
+    'unknown-resource-manifest-field',
+    [['nativeRuntimeVersion=0.1.0\n', 'nativeRuntimeVersion=0.1.0\nunexpectedField=value\n']],
+    /exact canonical fields in canonical order/u,
+  );
+  await expectResourceManifestFailure(
+    'missing-resource-canonical-field',
+    [['nativeModuleFile=\n', '']],
+    /exact canonical fields in canonical order/u,
+  );
+  await expectResourceManifestFailure(
+    'wrong-resource-native-module-file',
+    [['nativeModuleFile=\n', 'nativeModuleFile=other.dylib\n']],
+    /manifest nativeModuleFile must be ""/u,
+  );
+  await expectResourceManifestFailure(
+    'wrong-resource-static-symbol-prefix',
+    [['staticSymbolPrefix=\n', 'staticSymbolPrefix=oliphaunt_static_other\n']],
+    /manifest staticSymbolPrefix must be ""/u,
+  );
+  await expectResourceManifestFailure(
+    'wrong-resource-static-symbol-alias',
+    [['staticSymbolAliases=\n', 'staticSymbolAliases=sql_symbol:linked_symbol\n']],
+    /manifest staticSymbolAliases do not match carrier registration metadata/u,
+  );
+
+  const mismatchedCreatesExtension = structuredClone(manifest);
+  mismatchedCreatesExtension.extensions.find(
+    ({ sqlName }) => sqlName === 'pgtap',
+  ).createsExtension = false;
+  await expectCarrierFailure(
+    'mismatched-creates-extension',
+    mismatchedCreatesExtension,
+    'pgtap',
+    /manifest createsExtension must be "no"/u,
+  );
+
+  const duplicateName = structuredClone(manifest);
+  duplicateName.carriers.push({ ...duplicateName.carriers[0], sha256: '0'.repeat(64) });
+  await expectCarrierFailure(
+    'duplicate-asset-name',
+    duplicateName,
+    'postgis',
+    /repeats a carrier name/u,
+  );
+
+  const duplicateIdentity = structuredClone(manifest);
+  const duplicateIdentityPostgis = duplicateIdentity.extensions.find(
+    ({ sqlName }) => sqlName === 'postgis',
+  );
+  const geosAsset = duplicateIdentityPostgis.assets.find(
+    ({ role }) => role === 'dependency-xcframework',
+  );
+  const geosEnvelope = duplicateIdentity.carriers.find(({ name }) => name === geosAsset.carrier);
+  const duplicateGeosArchive = path.join(root, 'archives', 'postgis-geos-duplicate.zip');
+  await fs.copyFile(new URL(geosEnvelope.url), duplicateGeosArchive);
+  const duplicateGeos = carrierize([
+    {
+      ...duplicateIdentityPostgis,
+      assets: [
+        await asset(
+          'dependency-xcframework',
+          duplicateGeosArchive,
+          'zip',
+          `nested/${path.posix.basename(geosAsset.member)}`,
+        ),
+      ],
+    },
+  ]);
+  duplicateIdentityPostgis.assets.push(duplicateGeos.extensions[0].assets[0]);
+  duplicateIdentity.carriers.push(...duplicateGeos.carriers);
+  duplicateIdentity.carriers.sort((left, right) => left.name.localeCompare(right.name));
+  await expectCarrierFailure(
+    'duplicate-dependency-identity',
+    duplicateIdentity,
+    'postgis',
+    /repeats a dependency carrier identity/u,
+  );
+
+  const missingFile = path.join(root, 'missing-dependency.json');
+  const missingExtensions = manifest.extensions.filter(
+    ({ sqlName }) => sqlName === 'earthdistance',
+  );
+  const missingCarrierNames = new Set(
+    missingExtensions.flatMap((row) => row.assets.map(({ carrier }) => carrier)),
+  );
+  await fs.writeFile(
+    missingFile,
+    `${JSON.stringify(
+      {
+        ...manifest,
+        carriers: manifest.carriers.filter(({ name }) => missingCarrierNames.has(name)),
+        extensions: missingExtensions,
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  assert.match(
+    await render(
+      [
+        generator,
+        '--carrier',
+        missingFile,
+        '--extensions',
+        'earthdistance',
+        '--cache-dir',
+        path.join(root, 'missing-cache'),
+        '--allow-file-urls',
+        '--base-package-version',
+        '0.1.0',
+        '--output-dir',
+        path.join(root, 'missing-output'),
+      ],
+      { expectFailure: true },
+    ),
+    /missing carrier for cube required by earthdistance/u,
+  );
+
+  const tampered = structuredClone(manifest);
+  const tamperedAsset = tampered.extensions.find(({ sqlName }) => sqlName === 'postgis').assets[0];
+  tamperedAsset.sha256 = '0'.repeat(64);
+  tampered.carriers.find(({ name }) => name === tamperedAsset.carrier).sha256 = '0'.repeat(64);
+  const tamperedFile = path.join(root, 'tampered.json');
+  await fs.writeFile(tamperedFile, `${JSON.stringify(tampered, null, 2)}\n`);
+  const diagnostic = await render(
+    [
+      generator,
+      '--carrier',
+      tamperedFile,
+      '--extensions',
+      'postgis',
+      '--cache-dir',
+      path.join(root, 'tampered-cache'),
+      '--allow-file-urls',
+      '--base-package-version',
+      '0.1.0',
+      '--output-dir',
+      path.join(root, 'tampered-output'),
+    ],
+    { expectFailure: true },
+  );
+  assert.match(diagnostic, /checksum mismatch/u);
+
+  // Recreate only the SQL-only archive and leave a buildable consumer package
+  // for check-sdk's clean Swift compile/link lane.
+  const pgtap = await extension('pgtap', null);
+  const sqlOnly = carrierize([pgtap]);
+  const sqlCarrier = path.join(root, 'sql-only-carrier.json');
+  await fs.writeFile(
+    sqlCarrier,
+    `${JSON.stringify(
+      {
+        ...manifest,
+        carriers: sqlOnly.carriers,
+        extensions: sqlOnly.extensions,
+      },
+      null,
+      2,
+    )}\n`,
+  );
+  const sqlOutput = path.join(root, 'sql-only');
+  await render([
+    generator,
+    '--carrier',
+    sqlCarrier,
+    '--extensions',
+    'pgtap',
+    '--cache-dir',
+    path.join(root, 'sql-cache'),
+    '--allow-file-urls',
+    '--base-package-version',
+    '0.1.0',
+    '--base-package-path',
+    sdk,
+    '--output-dir',
+    sqlOutput,
+  ]);
+  const sqlPackage = await fs.readFile(path.join(sqlOutput, 'Package.swift'), 'utf8');
+  assert.doesNotMatch(sqlPackage, /binaryTarget/u);
+  console.log(
+    `swift-carrier-resolver.test.mts: metadata, malicious ZIP, cache-tamper, and consumer checks passed; sql-only-package=${sqlOutput}`,
+  );
+}
+
+main().catch((error) => {
+  console.error(error.stack ?? String(error));
+  process.exit(1);
+});
diff --git a/src/sdks/swift/tools/swift-carrier-resolver.test.sh b/src/sdks/swift/tools/swift-carrier-resolver.test.sh
new file mode 100644
index 000000000..6b6c96e9a
--- /dev/null
+++ b/src/sdks/swift/tools/swift-carrier-resolver.test.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+set -euo pipefail
+tools="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+bun "$tools/swift-carrier-resolver.test.mts" "$scratch"
+bun "$tools/render-extension-products.mts" --carrier "$scratch/sql-only-carrier.json" \
+  --extensions pgtap --cache-dir "$scratch/sql-cache" --allow-file-urls --offline \
+  --base-package-version 0.1.0 --base-package-path "$tools/.." --output-dir "$scratch/sql-cli"
+diff -ru "$scratch/sql-only" "$scratch/sql-cli"
+if bun "$tools/render-extension-products.mts" --carrier "$scratch/tampered.json" \
+  --extensions postgis --cache-dir "$scratch/tampered-cache" --allow-file-urls \
+  --base-package-version 0.1.0 --output-dir "$scratch/tampered-cli" > "$scratch/cli.log" 2>&1; then
+  echo 'tampered carrier unexpectedly rendered' >&2
+  exit 1
+fi
+grep -q 'checksum mismatch' "$scratch/cli.log"
diff --git a/src/sdks/swift/tools/swift-extension-release-consumer-inputs.mts b/src/sdks/swift/tools/swift-extension-release-consumer-inputs.mts
new file mode 100644
index 000000000..71da02f22
--- /dev/null
+++ b/src/sdks/swift/tools/swift-extension-release-consumer-inputs.mts
@@ -0,0 +1,243 @@
+#!/usr/bin/env bun
+
+import { readFileSync } from 'node:fs';
+
+import { contribCarrierDescriptor } from '../../../../tools/release/release-artifact-targets.mts';
+import { validateSelectionNeutralSwiftSourceCarrier } from './swift-source-carrier-contract.mts';
+
+const PREFIX = 'swift-extension-release-consumer-inputs.mts';
+const EXTENSION_CARRIER_SCHEMA = 'oliphaunt-swift-extension-carrier-v1';
+const PRODUCT = /^oliphaunt-extension-[A-Za-z0-9._-]+$/u;
+const PORTABLE_IDENTIFIER = /^[A-Za-z0-9._-]+$/u;
+const STABLE_SEMVER = /^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u;
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+
+function object(value, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    fail(`${label} must be an object`);
+  }
+  return value;
+}
+
+function exactKeys(value, expected, label) {
+  const actual = Object.keys(object(value, label)).sort(compareText);
+  const canonical = [...expected].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(canonical)) {
+    fail(`${label} fields must be exactly ${canonical.join(',')}; got ${actual.join(',')}`);
+  }
+  return value;
+}
+
+function stableVersion(value, label) {
+  if (typeof value !== 'string' || !STABLE_SEMVER.test(value)) {
+    fail(`${label} must be a stable SemVer X.Y.Z version`);
+  }
+  return value;
+}
+
+function releaseReference(value, label) {
+  const row = exactKeys(value, ['product', 'tag', 'version'], label);
+  const contrib = contribCarrierDescriptor(PREFIX);
+  if (
+    typeof row.product !== 'string' ||
+    (!PRODUCT.test(row.product) && row.product !== contrib.nativeOwner)
+  ) {
+    fail(`${label}.product must be an exact-extension product or the native contrib owner`);
+  }
+  stableVersion(row.version, `${label}.version`);
+  const expectedTag = `${row.product}-v${row.version}`;
+  if (row.tag !== expectedTag) {
+    fail(`${label}.tag must be ${expectedTag}`);
+  }
+  return row;
+}
+
+function baseReference(value, label) {
+  const row = exactKeys(value, ['product', 'tag', 'version'], label);
+  if (row.product !== 'liboliphaunt-native') {
+    fail(`${label}.product must be liboliphaunt-native`);
+  }
+  stableVersion(row.version, `${label}.version`);
+  const expectedTag = `${row.product}-v${row.version}`;
+  if (row.tag !== expectedTag) {
+    fail(`${label}.tag must be ${expectedTag}`);
+  }
+  return row;
+}
+
+function readJson(file, label) {
+  if (typeof file !== 'string' || file.length === 0) {
+    fail(`${label} path must be a non-empty string`);
+  }
+  try {
+    return JSON.parse(readFileSync(file, 'utf8'));
+  } catch (cause) {
+    fail(`cannot read ${label} ${file}: ${cause.message}`);
+  }
+}
+
+export function extensionReleaseConsumerInputs({ sourceCarrierFile, extensionCarrierFiles }) {
+  const sourceCarrier = readJson(sourceCarrierFile, 'source carrier');
+  try {
+    validateSelectionNeutralSwiftSourceCarrier(sourceCarrier, sourceCarrierFile);
+  } catch (cause) {
+    fail(cause instanceof Error ? cause.message : String(cause));
+  }
+  if (
+    !Array.isArray(extensionCarrierFiles) ||
+    extensionCarrierFiles.length === 0 ||
+    extensionCarrierFiles.some((file) => typeof file !== 'string' || file.length === 0)
+  ) {
+    fail('at least one independent extension carrier file is required');
+  }
+  if (new Set(extensionCarrierFiles).size !== extensionCarrierFiles.length) {
+    fail('independent extension carrier paths must not repeat');
+  }
+
+  const releaseProducts = new Set();
+  const extensions = [];
+  for (const file of extensionCarrierFiles) {
+    const carrier = exactKeys(
+      readJson(file, 'extension carrier'),
+      ['base', 'carriers', 'entries', 'release', 'schema'],
+      file,
+    );
+    if (carrier.schema !== EXTENSION_CARRIER_SCHEMA) {
+      fail(`${file}.schema must be ${EXTENSION_CARRIER_SCHEMA}`);
+    }
+    const base = baseReference(carrier.base, `${file}.base`);
+    if (
+      base.product !== sourceCarrier.base.product ||
+      base.version !== sourceCarrier.base.version ||
+      base.tag !== sourceCarrier.base.tag
+    ) {
+      fail(
+        `${file} requires ${base.tag}, but the selection-neutral source carrier provides ${sourceCarrier.base.tag}`,
+      );
+    }
+    const release = releaseReference(carrier.release, `${file}.release`);
+    if (releaseProducts.has(release.product)) {
+      fail(`independent extension carriers repeat release product ${release.product}`);
+    }
+    releaseProducts.add(release.product);
+    if (!Array.isArray(carrier.entries) || carrier.entries.length === 0) {
+      fail(`${file}.entries must be a non-empty array`);
+    }
+    for (const [index, rawEntry] of carrier.entries.entries()) {
+      const entry = exactKeys(
+        rawEntry,
+        ['dependencyCarriers', 'extension'],
+        `${file}.entries[${index}]`,
+      );
+      if (!Array.isArray(entry.dependencyCarriers)) {
+        fail(`${file}.entries[${index}].dependencyCarriers must be an array`);
+      }
+      const extension = object(entry.extension, `${file}.entries[${index}].extension`);
+      if (typeof extension.product !== 'string' || !PRODUCT.test(extension.product)) {
+        fail(`${file}.entries[${index}].extension.product must be an exact-extension product id`);
+      }
+      if (typeof extension.sqlName !== 'string' || !PORTABLE_IDENTIFIER.test(extension.sqlName)) {
+        fail(`${file}.entries[${index}].extension.sqlName must be a portable identifier`);
+      }
+      if (
+        extension.nativeModuleStem !== null &&
+        (typeof extension.nativeModuleStem !== 'string' ||
+          !PORTABLE_IDENTIFIER.test(extension.nativeModuleStem))
+      ) {
+        fail(
+          `${file}.entries[${index}].extension.nativeModuleStem must be null or a portable identifier`,
+        );
+      }
+      const releaseProduct = extension.releaseProduct ?? extension.product;
+      const contrib = contribCarrierDescriptor(PREFIX);
+      const validOwnership =
+        release.product === contrib.nativeOwner
+          ? extension.product === contrib.artifactProduct && releaseProduct === contrib.nativeOwner
+          : extension.product === release.product && releaseProduct === release.product;
+      if (
+        !validOwnership ||
+        extension.version !== release.version ||
+        extension.tag !== release.tag
+      ) {
+        fail(`${file}.entries[${index}].extension must be owned by ${release.tag}`);
+      }
+      extensions.push({
+        nativeModuleStem: extension.nativeModuleStem,
+        product: extension.product,
+        sqlName: extension.sqlName,
+      });
+    }
+  }
+
+  extensions.sort((left, right) => compareText(left.sqlName, right.sqlName));
+  if (new Set(extensions.map(({ sqlName }) => sqlName)).size !== extensions.length) {
+    fail('independent extension carriers repeat an extension SQL name');
+  }
+  const native = extensions.filter(({ nativeModuleStem }) => nativeModuleStem !== null);
+  const selectedNative =
+    native.find(({ sqlName }) => sqlName === 'postgis') ??
+    native.find(({ sqlName }) => sqlName === 'vector') ??
+    native[0];
+  return {
+    extensionCarrierCount: extensionCarrierFiles.length,
+    extensionProducts: [...new Set(extensions.map(({ product }) => product))].sort(compareText),
+    extensions: extensions.map(({ sqlName }) => sqlName),
+    extensionsCsv: extensions.map(({ sqlName }) => sqlName).join(','),
+    finalLink: {
+      kind: selectedNative === undefined ? 'base-runtime' : 'native-extension',
+      nativeExtension: selectedNative?.sqlName ?? null,
+      nativeModuleStem: selectedNative?.nativeModuleStem ?? null,
+      runtimeProduct: sourceCarrier.base.product,
+      runtimeVersion: sourceCarrier.base.version,
+    },
+    schema: 'oliphaunt-swift-extension-release-consumer-inputs-v1',
+  };
+}
+
+function parseArgs(argv) {
+  const args = { extensionCarrierFiles: [] };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--help' || arg === '-h') {
+      console.log(
+        `usage: ${PREFIX} --source-carrier FILE --extension-carrier FILE [--extension-carrier FILE ...]`,
+      );
+      process.exit(0);
+    }
+    if (arg !== '--source-carrier' && arg !== '--extension-carrier') {
+      fail(`unknown argument ${arg}`);
+    }
+    const value = argv[index + 1];
+    if (value === undefined || value.startsWith('--')) {
+      fail(`${arg} requires a value`);
+    }
+    index += 1;
+    if (arg === '--source-carrier') {
+      if (args.sourceCarrierFile !== undefined)
+        fail('--source-carrier must be passed exactly once');
+      args.sourceCarrierFile = value;
+    } else {
+      args.extensionCarrierFiles.push(value);
+    }
+  }
+  if (args.sourceCarrierFile === undefined) fail('--source-carrier is required');
+  return args;
+}
+
+if (import.meta.main) {
+  try {
+    process.stdout.write(
+      `${JSON.stringify(extensionReleaseConsumerInputs(parseArgs(Bun.argv.slice(2))))}\n`,
+    );
+  } catch (cause) {
+    console.error(cause instanceof Error ? cause.message : String(cause));
+    process.exit(1);
+  }
+}
diff --git a/src/sdks/swift/tools/swift-extension-release-consumer-inputs.test.mts b/src/sdks/swift/tools/swift-extension-release-consumer-inputs.test.mts
new file mode 100644
index 000000000..183bda8c9
--- /dev/null
+++ b/src/sdks/swift/tools/swift-extension-release-consumer-inputs.test.mts
@@ -0,0 +1,252 @@
+import assert from 'node:assert/strict';
+import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+
+import { iosBaseLegalMetadata } from './ios-carrier-manifest.mts';
+import { extensionReleaseConsumerInputs } from './swift-extension-release-consumer-inputs.mts';
+
+const VERSION = '1.2.3';
+const BASE_TAG = `liboliphaunt-native-v${VERSION}`;
+
+function sourceCarrier() {
+  const asset = (role, name, format, member, bytes) => ({
+    bytes,
+    format,
+    member,
+    name,
+    role,
+    sha256: String(bytes).padStart(64, '0'),
+    url: `https://github.com/f0rr0/oliphaunt/releases/download/${BASE_TAG}/${name}`,
+  });
+  return {
+    base: {
+      assets: [
+        asset(
+          'base-xcframework',
+          `liboliphaunt-${VERSION}-apple-spm-xcframework.zip`,
+          'zip',
+          'liboliphaunt.xcframework',
+          1,
+        ),
+        asset(
+          'runtime-resources',
+          `liboliphaunt-${VERSION}-runtime-resources-ios-datum64.tar.gz`,
+          'tar.gz',
+          'oliphaunt',
+          2,
+        ),
+      ],
+      product: 'liboliphaunt-native',
+      tag: BASE_TAG,
+      version: VERSION,
+    },
+    carriers: [],
+    extensions: [],
+    legal: { base: iosBaseLegalMetadata(), extensions: [] },
+    schema: 'oliphaunt-react-native-ios-carrier-v1',
+  };
+}
+
+function extensionCarrier(product, rows, { baseVersion = VERSION } = {}) {
+  const version = product.endsWith('pgtap') ? '2.0.0' : '3.0.0';
+  const tag = `${product}-v${version}`;
+  return {
+    base: {
+      product: 'liboliphaunt-native',
+      tag: `liboliphaunt-native-v${baseVersion}`,
+      version: baseVersion,
+    },
+    carriers: [],
+    entries: rows.map(({ nativeModuleStem, sqlName }) => ({
+      dependencyCarriers: [],
+      extension: {
+        nativeModuleStem,
+        product,
+        sqlName,
+        tag,
+        version,
+      },
+    })),
+    release: { product, tag, version },
+    schema: 'oliphaunt-swift-extension-carrier-v1',
+  };
+}
+
+function runtimeOwnedContribCarrier(rows) {
+  const product = 'oliphaunt-extension-contrib-pg18';
+  const carrier = extensionCarrier(product, rows);
+  carrier.release = { product: 'liboliphaunt-native', tag: BASE_TAG, version: VERSION };
+  for (const { extension } of carrier.entries) {
+    extension.releaseProduct = 'liboliphaunt-native';
+    extension.tag = BASE_TAG;
+    extension.version = VERSION;
+  }
+  return carrier;
+}
+
+function fixture(context, documents) {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-swift-consumer-carriers-'));
+  context.after(() => rmSync(root, { recursive: true, force: true }));
+  return documents.map((document, index) => {
+    const file = path.join(root, `carrier-${index}.json`);
+    writeFileSync(file, `${JSON.stringify(document, null, 2)}\n`);
+    return file;
+  });
+}
+
+test('plans every repeated independent carrier against a selection-neutral source carrier', (context) => {
+  const [source, pgtap, postgis, vector] = fixture(context, [
+    sourceCarrier(),
+    extensionCarrier('oliphaunt-extension-pgtap', [{ nativeModuleStem: null, sqlName: 'pgtap' }]),
+    extensionCarrier('oliphaunt-extension-postgis', [
+      { nativeModuleStem: 'postgis-3', sqlName: 'postgis' },
+    ]),
+    extensionCarrier('oliphaunt-extension-vector', [
+      { nativeModuleStem: 'vector', sqlName: 'vector' },
+    ]),
+  ]);
+  assert.deepEqual(
+    extensionReleaseConsumerInputs({
+      extensionCarrierFiles: [pgtap, postgis, vector],
+      sourceCarrierFile: source,
+    }),
+    {
+      extensionCarrierCount: 3,
+      extensionProducts: [
+        'oliphaunt-extension-pgtap',
+        'oliphaunt-extension-postgis',
+        'oliphaunt-extension-vector',
+      ],
+      extensions: ['pgtap', 'postgis', 'vector'],
+      extensionsCsv: 'pgtap,postgis,vector',
+      finalLink: {
+        kind: 'native-extension',
+        nativeExtension: 'postgis',
+        nativeModuleStem: 'postgis-3',
+        runtimeProduct: 'liboliphaunt-native',
+        runtimeVersion: VERSION,
+      },
+      schema: 'oliphaunt-swift-extension-release-consumer-inputs-v1',
+    },
+  );
+});
+
+test('rejects an aggregate or extension-bearing source carrier', (context) => {
+  const contaminated = sourceCarrier();
+  contaminated.extensions.push({ sqlName: 'vector' });
+  const [source, vector] = fixture(context, [
+    contaminated,
+    extensionCarrier('oliphaunt-extension-vector', [
+      { nativeModuleStem: 'vector', sqlName: 'vector' },
+    ]),
+  ]);
+  assert.throws(
+    () =>
+      extensionReleaseConsumerInputs({
+        sourceCarrierFile: source,
+        extensionCarrierFiles: [vector],
+      }),
+    /source tags are selection-neutral/u,
+  );
+
+  const [neutralSource, aggregate] = fixture(context, [sourceCarrier(), sourceCarrier()]);
+  assert.throws(
+    () =>
+      extensionReleaseConsumerInputs({
+        sourceCarrierFile: neutralSource,
+        extensionCarrierFiles: [aggregate],
+      }),
+    /fields must be exactly base,carriers,entries,release,schema/u,
+  );
+});
+
+test('rejects base skew and repeated owners', (context) => {
+  const [source, skewed] = fixture(context, [
+    sourceCarrier(),
+    extensionCarrier(
+      'oliphaunt-extension-vector',
+      [{ nativeModuleStem: 'vector', sqlName: 'vector' }],
+      { baseVersion: '1.2.4' },
+    ),
+  ]);
+  assert.throws(
+    () =>
+      extensionReleaseConsumerInputs({
+        sourceCarrierFile: source,
+        extensionCarrierFiles: [skewed],
+      }),
+    /requires liboliphaunt-native-v1\.2\.4.*provides liboliphaunt-native-v1\.2\.3/u,
+  );
+
+  const [neutral, first, second] = fixture(context, [
+    sourceCarrier(),
+    extensionCarrier('oliphaunt-extension-vector', [
+      { nativeModuleStem: 'vector', sqlName: 'vector' },
+    ]),
+    extensionCarrier('oliphaunt-extension-vector', [
+      { nativeModuleStem: 'vector', sqlName: 'vector2' },
+    ]),
+  ]);
+  assert.throws(
+    () =>
+      extensionReleaseConsumerInputs({
+        sourceCarrierFile: neutral,
+        extensionCarrierFiles: [first, second],
+      }),
+    /repeat release product oliphaunt-extension-vector/u,
+  );
+});
+
+test('plans an explicit base-runtime final-link proof for an SQL-only selection', (context) => {
+  const [sqlSource, sqlOnly] = fixture(context, [
+    sourceCarrier(),
+    extensionCarrier('oliphaunt-extension-pgtap', [{ nativeModuleStem: null, sqlName: 'pgtap' }]),
+  ]);
+  assert.deepEqual(
+    extensionReleaseConsumerInputs({
+      sourceCarrierFile: sqlSource,
+      extensionCarrierFiles: [sqlOnly],
+    }),
+    {
+      extensionCarrierCount: 1,
+      extensionProducts: ['oliphaunt-extension-pgtap'],
+      extensions: ['pgtap'],
+      extensionsCsv: 'pgtap',
+      finalLink: {
+        kind: 'base-runtime',
+        nativeExtension: null,
+        nativeModuleStem: null,
+        runtimeProduct: 'liboliphaunt-native',
+        runtimeVersion: VERSION,
+      },
+      schema: 'oliphaunt-swift-extension-release-consumer-inputs-v1',
+    },
+  );
+});
+
+test('plans native-owned contrib under its logical extension identity', (context) => {
+  const [source, contrib] = fixture(context, [
+    sourceCarrier(),
+    runtimeOwnedContribCarrier([{ nativeModuleStem: null, sqlName: 'amcheck' }]),
+  ]);
+  const plan = extensionReleaseConsumerInputs({
+    sourceCarrierFile: source,
+    extensionCarrierFiles: [contrib],
+  });
+  assert.deepEqual(plan.extensionProducts, ['oliphaunt-extension-contrib-pg18']);
+  assert.deepEqual(plan.extensions, ['amcheck']);
+
+  const forged = runtimeOwnedContribCarrier([{ nativeModuleStem: null, sqlName: 'amcheck' }]);
+  forged.entries[0].extension.releaseProduct = 'oliphaunt-extension-contrib-pg18';
+  const [forgedFile] = fixture(context, [forged]);
+  assert.throws(
+    () =>
+      extensionReleaseConsumerInputs({
+        sourceCarrierFile: source,
+        extensionCarrierFiles: [forgedFile],
+      }),
+    /must be owned by liboliphaunt-native-v1[.]2[.]3/u,
+  );
+});
diff --git a/src/sdks/swift/tools/swift-source-carrier-contract.mts b/src/sdks/swift/tools/swift-source-carrier-contract.mts
new file mode 100644
index 000000000..36a5fa99f
--- /dev/null
+++ b/src/sdks/swift/tools/swift-source-carrier-contract.mts
@@ -0,0 +1,271 @@
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+
+import { IOS_CARRIER_SCHEMA, iosBaseLegalMetadata } from './ios-carrier-manifest.mts';
+import { parseSwiftReleaseBinaryTarget } from './prepare-swift-release-consumer.mts';
+
+const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u;
+const CANONICAL_REPOSITORY = 'https://github.com/f0rr0/oliphaunt';
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function error(label, message) {
+  return new Error(`${label}: ${message}`);
+}
+
+function exactKeys(value, expected, label) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    throw error(label, 'must be an object');
+  }
+  const actual = Object.keys(value).sort(compareText);
+  const canonical = [...expected].sort(compareText);
+  if (JSON.stringify(actual) !== JSON.stringify(canonical)) {
+    throw error(label, `fields must be exactly ${canonical.join(',')}; got ${actual.join(',')}`);
+  }
+  return value;
+}
+
+function safeArchiveMember(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    value.startsWith('/') ||
+    /^[A-Za-z]:/u.test(value) ||
+    /[\u0000-\u001f\u007f]/u.test(value)
+  ) {
+    throw error(label, 'must be a safe POSIX archive path');
+  }
+  if (value === '.') return value;
+  const parts = value.split('/');
+  if (parts.some((part) => part.length === 0 || part === '.' || part === '..')) {
+    throw error(label, 'must be a safe POSIX archive path');
+  }
+  return value;
+}
+
+function portableFilename(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    path.posix.basename(value) !== value ||
+    /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) ||
+    /[ .]$/u.test(value) ||
+    /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value)
+  ) {
+    throw error(label, 'must be a portable release asset filename');
+  }
+  return value;
+}
+
+/**
+ * Validate the carrier embedded in an Oliphaunt Swift source tag.
+ *
+ * Source tags intentionally freeze only the compatible native base. Optional
+ * extensions are supplied by their independently versioned release carriers,
+ * so both carrier and extension inventories must remain empty here.
+ */
+export function validateSelectionNeutralSwiftSourceCarrier(
+  document,
+  label = 'oliphaunt-swift source-tag carrier',
+) {
+  const root = exactKeys(document, ['base', 'carriers', 'extensions', 'legal', 'schema'], label);
+  if (root.schema !== IOS_CARRIER_SCHEMA) {
+    throw error(label, `schema must be ${IOS_CARRIER_SCHEMA}`);
+  }
+  if (!Array.isArray(root.carriers) || root.carriers.length !== 0) {
+    throw error(
+      `${label}.carriers`,
+      'must be an empty array; source tags do not own extension payload carriers',
+    );
+  }
+  if (!Array.isArray(root.extensions) || root.extensions.length !== 0) {
+    throw error(`${label}.extensions`, 'must be an empty array; source tags are selection-neutral');
+  }
+  const legal = exactKeys(root.legal, ['base', 'extensions'], `${label}.legal`);
+  if (!Array.isArray(legal.extensions) || legal.extensions.length !== 0) {
+    throw error(
+      `${label}.legal.extensions`,
+      'must be empty for a selection-neutral source carrier',
+    );
+  }
+  if (JSON.stringify(legal.base) !== JSON.stringify(iosBaseLegalMetadata())) {
+    throw error(`${label}.legal.base`, 'must match the canonical native Apple legal locators');
+  }
+
+  const base = exactKeys(root.base, ['assets', 'product', 'tag', 'version'], `${label}.base`);
+  if (base.product !== 'liboliphaunt-native') {
+    throw error(`${label}.base.product`, 'must be liboliphaunt-native');
+  }
+  if (typeof base.version !== 'string' || !STABLE_SEMVER.test(base.version)) {
+    throw error(`${label}.base.version`, 'must be a stable SemVer X.Y.Z version');
+  }
+  const expectedTag = `${base.product}-v${base.version}`;
+  if (base.tag !== expectedTag) {
+    throw error(`${label}.base.tag`, `must be ${expectedTag}`);
+  }
+
+  const assetContracts = [
+    {
+      format: 'zip',
+      member: 'liboliphaunt.xcframework',
+      name: `liboliphaunt-${base.version}-apple-spm-xcframework.zip`,
+      role: 'base-xcframework',
+    },
+    {
+      format: 'tar.gz',
+      member: 'oliphaunt',
+      name: `liboliphaunt-${base.version}-runtime-resources-ios-datum64.tar.gz`,
+      role: 'runtime-resources',
+    },
+  ];
+  if (!Array.isArray(base.assets) || base.assets.length !== assetContracts.length) {
+    throw error(
+      `${label}.base.assets`,
+      `must contain exactly ${assetContracts.length} native base assets`,
+    );
+  }
+  for (const [index, contract] of assetContracts.entries()) {
+    const assetLabel = `${label}.base.assets[${index}]`;
+    const asset = exactKeys(
+      base.assets[index],
+      ['bytes', 'format', 'member', 'name', 'role', 'sha256', 'url'],
+      assetLabel,
+    );
+    portableFilename(asset.name, `${assetLabel}.name`);
+    safeArchiveMember(asset.member, `${assetLabel}.member`);
+    for (const key of ['format', 'member', 'name', 'role']) {
+      if (asset[key] !== contract[key]) {
+        throw error(`${assetLabel}.${key}`, `must be ${contract[key]}`);
+      }
+    }
+    if (!Number.isSafeInteger(asset.bytes) || asset.bytes <= 0) {
+      throw error(`${assetLabel}.bytes`, 'must be a positive safe integer');
+    }
+    if (typeof asset.sha256 !== 'string' || !/^[0-9a-f]{64}$/u.test(asset.sha256)) {
+      throw error(`${assetLabel}.sha256`, 'must be a lowercase SHA-256 digest');
+    }
+    let assetUrl;
+    try {
+      assetUrl = new URL(asset.url);
+    } catch {
+      throw error(`${assetLabel}.url`, 'must be an absolute HTTPS URL');
+    }
+    let urlName;
+    try {
+      urlName = decodeURIComponent(path.posix.basename(assetUrl.pathname));
+    } catch {
+      throw error(`${assetLabel}.url`, 'contains invalid percent encoding');
+    }
+    if (
+      assetUrl.protocol !== 'https:' ||
+      assetUrl.username !== '' ||
+      assetUrl.password !== '' ||
+      assetUrl.search !== '' ||
+      assetUrl.hash !== '' ||
+      urlName !== asset.name
+    ) {
+      throw error(
+        `${assetLabel}.url`,
+        `must be a credential-free HTTPS URL ending in ${asset.name}`,
+      );
+    }
+    const urlParts = assetUrl.pathname
+      .split('/')
+      .filter(Boolean)
+      .map((part) => {
+        try {
+          return decodeURIComponent(part);
+        } catch {
+          throw error(`${assetLabel}.url`, 'contains invalid percent encoding');
+        }
+      });
+    if (
+      urlParts.length < 4 ||
+      JSON.stringify(urlParts.slice(-4)) !==
+        JSON.stringify(['releases', 'download', expectedTag, asset.name])
+    ) {
+      throw error(
+        `${assetLabel}.url`,
+        `must address ${asset.name} under release tag ${expectedTag}`,
+      );
+    }
+  }
+  return root;
+}
+
+export function validateSelectionNeutralSwiftSourceCarrierFile(carrier, label = String(carrier)) {
+  let document;
+  try {
+    document = JSON.parse(readFileSync(carrier, 'utf8'));
+  } catch (cause) {
+    throw error(label, `is not valid JSON: ${cause.message}`);
+  }
+  return validateSelectionNeutralSwiftSourceCarrier(document, label);
+}
+
+/**
+ * Bind a selection-neutral Apple carrier to the public Oliphaunt release
+ * namespace and, when supplied, the exact native version selected by the
+ * release graph. This contract is shared by SwiftPM source tags and the
+ * carrier embedded in the React Native npm package.
+ */
+export function validateSelectionNeutralSwiftCarrierIdentity({
+  carrier,
+  expectedNativeVersion,
+  repository = CANONICAL_REPOSITORY,
+  label = 'selection-neutral Apple carrier',
+}) {
+  if (repository !== CANONICAL_REPOSITORY) {
+    throw error(`${label}.repository`, `must be ${CANONICAL_REPOSITORY}`);
+  }
+  const validated = validateSelectionNeutralSwiftSourceCarrier(carrier, `${label}.carrier`);
+  if (expectedNativeVersion !== undefined && validated.base.version !== expectedNativeVersion) {
+    throw error(
+      `${label}.carrier.base.version`,
+      `must match liboliphaunt-native ${expectedNativeVersion}`,
+    );
+  }
+  for (const asset of validated.base.assets) {
+    const expectedUrl = `${repository}/releases/download/${validated.base.tag}/${asset.name}`;
+    if (asset.url !== expectedUrl) {
+      throw error(`${label}.carrier.base.assets.${asset.role}.url`, `must be ${expectedUrl}`);
+    }
+  }
+  return validated;
+}
+
+export function validateSwiftSourceReleaseContract({
+  carrier,
+  manifestText,
+  expectedNativeVersion,
+  repository = CANONICAL_REPOSITORY,
+  label = 'oliphaunt-swift source release',
+}) {
+  const validated = validateSelectionNeutralSwiftCarrierIdentity({
+    carrier,
+    expectedNativeVersion,
+    repository,
+    label,
+  });
+  const binaryTarget = parseSwiftReleaseBinaryTarget(
+    manifestText,
+    `${label} Package.swift.release`,
+  );
+  const xcframework = validated.base.assets.find(({ role }) => role === 'base-xcframework');
+  if (binaryTarget.url !== xcframework.url) {
+    throw error(
+      `${label} Package.swift.release binary target URL`,
+      `must match ${xcframework.url}`,
+    );
+  }
+  if (binaryTarget.checksum !== xcframework.sha256) {
+    throw error(
+      `${label} Package.swift.release binary target checksum`,
+      `must match carrier SHA-256 ${xcframework.sha256}`,
+    );
+  }
+  return { binaryTarget, carrier: validated };
+}
diff --git a/src/sdks/swift/tools/swift.sh b/src/sdks/swift/tools/swift.sh
new file mode 100644
index 000000000..96e9469b2
--- /dev/null
+++ b/src/sdks/swift/tools/swift.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+bash "$root/src/sdks/swift/tools/prepare-bindings.sh"
+exec swift "$@" --package-path "$root/src/sdks/swift"
diff --git a/src/sdks/swift/tools/test-c-bridge.sh b/src/sdks/swift/tools/test-c-bridge.sh
deleted file mode 100755
index 4d0b8957f..000000000
--- a/src/sdks/swift/tools/test-c-bridge.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env sh
-set -eu
-
-root="$(git rev-parse --show-toplevel)"
-host_os="$(uname -s)"
-case "$host_os" in
-  MINGW*|MSYS*|CYGWIN*)
-    echo "Swift C bridge unit tests are covered by the Linux/macOS lanes"
-    exit 0
-    ;;
-esac
-
-scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-swift-c-bridge.XXXXXX")"
-trap 'rm -rf "$scratch"' EXIT
-
-set --
-if [ "$host_os" != "Darwin" ]; then
-  set -- -ldl
-fi
-
-"${CC:-cc}" \
-  -std=c11 \
-  -Wall \
-  -Wextra \
-  -Werror \
-  -D_POSIX_C_SOURCE=200809L \
-  -pthread \
-  -I "$root/src/sdks/swift/Sources/COliphaunt/include" \
-  "$root/src/sdks/swift/tools/bridge-mutex-init-failure.c" \
-  "$@" \
-  -o "$scratch/bridge-mutex-init-failure"
-
-"$scratch/bridge-mutex-init-failure"
diff --git a/src/shared/js-core/.gitignore b/src/sdks/ts-query/.gitignore
similarity index 100%
rename from src/shared/js-core/.gitignore
rename to src/sdks/ts-query/.gitignore
diff --git a/src/sdks/ts-query/CHANGELOG.md b/src/sdks/ts-query/CHANGELOG.md
new file mode 100644
index 000000000..daa365112
--- /dev/null
+++ b/src/sdks/ts-query/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## Unreleased
+
+- Extract shared PostgreSQL query encoding and decoding into a normal dependency of the TypeScript SDKs.
diff --git a/src/sdks/ts-query/LICENSE b/src/sdks/ts-query/LICENSE
new file mode 100644
index 000000000..ac7484ea4
--- /dev/null
+++ b/src/sdks/ts-query/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 oliphaunt-wasix Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/sdks/ts-query/README.md b/src/sdks/ts-query/README.md
new file mode 100644
index 000000000..f0288e1ce
--- /dev/null
+++ b/src/sdks/ts-query/README.md
@@ -0,0 +1,11 @@
+# @oliphaunt/ts-query
+
+PostgreSQL query encoding, decoding and result types shared by the native, WASIX and React Native TypeScript SDKs.
+
+Import from `@oliphaunt/ts-query/query` or `@oliphaunt/ts-query/protocol`. ESM and CommonJS builds include TypeScript declarations.
+
+Run `bun run build`, `bun run typecheck`, or `bun run test` from this directory.
+`bun run format` rewrites formatting; `bun run format-check` and `bun run lint`
+check sources. `moon run oliphaunt-query-ts:package` builds and packs the
+distributable; `bun run package` packs already built outputs. SDK packages depend
+on this independently versioned package instead of copying or bundling its source.
diff --git a/src/shared/js-core/module.package.json b/src/sdks/ts-query/module.package.json
similarity index 100%
rename from src/shared/js-core/module.package.json
rename to src/sdks/ts-query/module.package.json
diff --git a/src/sdks/ts-query/moon.yml b/src/sdks/ts-query/moon.yml
new file mode 100644
index 000000000..4f860edd6
--- /dev/null
+++ b/src/sdks/ts-query/moon.yml
@@ -0,0 +1,100 @@
+$schema: https://moonrepo.dev/schemas/project.json
+id: oliphaunt-query-ts
+language: typescript
+layer: library
+stack: frontend
+tags:
+  - javascript-quality
+  - shared
+  - typescript
+  - sdk
+  - release-product
+dependsOn:
+  - id: shared-test-fixtures
+    scope: development
+project:
+  title: TypeScript query
+  description: "PostgreSQL query encoding, decoding and result types."
+  owner: oliphaunt
+  release:
+    component: oliphaunt-query-ts
+    packagePath: src/sdks/ts-query
+owners:
+  defaultOwner: "@oliphaunt/sdk-js"
+  paths:
+    "**/*.ts":
+      - "@oliphaunt/sdk-js"
+      - "@oliphaunt/sdk-react-native"
+    tools/**:
+      - "@oliphaunt/sdk-js"
+      - "@oliphaunt/sdk-react-native"
+fileGroups:
+  package:
+    - README.md
+  sources:
+    - module.package.json
+    - package.json
+    - src/**/*.ts
+    - tsconfig*.json
+tasks:
+  build:
+    tags:
+      - build
+      - typescript
+    command: bun run build
+    inputs:
+      - /src/sdks/ts-query/package.json
+      - /src/sdks/ts-query/module.package.json
+      - /src/sdks/ts-query/src/**/*.ts
+      - /src/sdks/ts-query/tsconfig*.json
+      - /bun.lock
+    outputs:
+      - /src/sdks/ts-query/dist/module/*.d.ts
+      - /src/sdks/ts-query/dist/module/*.js
+      - /src/sdks/ts-query/dist/module/package.json
+      - /src/sdks/ts-query/dist/commonjs/*.d.ts
+      - /src/sdks/ts-query/dist/commonjs/*.js
+    options:
+      cache: true
+  test:
+    tags:
+      - quality
+      - unit
+    command: bun run test
+    inputs:
+      - /src/sdks/ts-query/src/**/*.ts
+      - test/**/*
+      - project: shared-test-fixtures
+        group: fixtures
+    options:
+      cache: true
+  typecheck:
+    tags:
+      - quality
+      - static
+      - typescript
+    command: bun run typecheck
+    inputs:
+      - "@group(sources)"
+      - /bun.lock
+  package:
+    tags:
+      - package
+      - release
+      - artifact-package
+      - ci-js-sdk-package
+    deps:
+      - oliphaunt-query-ts:build
+    inputs:
+      - "**/*"
+      - /bun.lock
+      - /LICENSE
+    outputs:
+      - /target/sdk-artifacts/oliphaunt-query-ts/**/*
+    command: bun run package
+workspace:
+  inheritedTasks:
+    rename:
+      js-format: format
+      js-format-check: format-check
+      js-lint: lint
diff --git a/src/sdks/ts-query/package.json b/src/sdks/ts-query/package.json
new file mode 100644
index 000000000..8d41e9c79
--- /dev/null
+++ b/src/sdks/ts-query/package.json
@@ -0,0 +1,55 @@
+{
+  "name": "@oliphaunt/ts-query",
+  "version": "0.1.0",
+  "exports": {
+    "./protocol": {
+      "import": {
+        "types": "./dist/module/protocol.d.ts",
+        "default": "./dist/module/protocol.js"
+      },
+      "require": {
+        "types": "./dist/commonjs/protocol.d.ts",
+        "default": "./dist/commonjs/protocol.js"
+      }
+    },
+    "./query": {
+      "import": {
+        "types": "./dist/module/query.d.ts",
+        "default": "./dist/module/query.js"
+      },
+      "require": {
+        "types": "./dist/commonjs/query.d.ts",
+        "default": "./dist/commonjs/query.js"
+      }
+    }
+  },
+  "files": [
+    "dist/module",
+    "dist/commonjs"
+  ],
+  "scripts": {
+    "build": "tsc -p tsconfig.build.module.json && tsc -p tsconfig.build.commonjs.json && cp module.package.json dist/module/package.json",
+    "test": "bun test ./test",
+    "typecheck": "tsc --noEmit",
+    "format": "bun x --no-install biome format --write --no-errors-on-unmatched .",
+    "format-check": "bun x --no-install biome format --no-errors-on-unmatched .",
+    "lint": "bun x --no-install biome lint --diagnostic-level=error --no-errors-on-unmatched .",
+    "package": "bash tools/package.sh"
+  },
+  "devDependencies": {
+    "@types/node": "^24.10.1",
+    "typescript": "catalog:"
+  },
+  "license": "MIT",
+  "description": "PostgreSQL query encoding, decoding and result types for Oliphaunt TypeScript SDKs.",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts-query"
+  },
+  "homepage": "https://oliphaunt.dev",
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  }
+}
diff --git a/src/sdks/ts-query/release.toml b/src/sdks/ts-query/release.toml
new file mode 100644
index 000000000..1f8e6ca8b
--- /dev/null
+++ b/src/sdks/ts-query/release.toml
@@ -0,0 +1,6 @@
+id = "oliphaunt-query-ts"
+owner = "@oliphaunt/sdk-js"
+kind = "sdk"
+publish_targets = ["npm"]
+registry_packages = ["npm:@oliphaunt/ts-query"]
+release_artifacts = ["npm-package"]
diff --git a/src/shared/js-core/src/protocol.ts b/src/sdks/ts-query/src/protocol.ts
similarity index 100%
rename from src/shared/js-core/src/protocol.ts
rename to src/sdks/ts-query/src/protocol.ts
diff --git a/src/sdks/ts-query/src/query.ts b/src/sdks/ts-query/src/query.ts
new file mode 100644
index 000000000..abefa9a80
--- /dev/null
+++ b/src/sdks/ts-query/src/query.ts
@@ -0,0 +1,2453 @@
+import { simpleQuery } from './protocol.js';
+
+const utf8Encoder = new TextEncoder();
+const utf8Decoder = new TextDecoder('utf-8', { fatal: true });
+
+export type QueryBinaryInput = ArrayBuffer | ArrayBufferView | Uint8Array;
+export type ByteInput = QueryBinaryInput | ReadonlyArray;
+
+/** Stable PostgreSQL OIDs used by the built-in JavaScript codecs. */
+export const postgresOids = Object.freeze({
+  bool: 16,
+  bytea: 17,
+  char: 18,
+  name: 19,
+  int8: 20,
+  int2: 21,
+  int4: 23,
+  text: 25,
+  oid: 26,
+  json: 114,
+  xml: 142,
+  float4: 700,
+  float8: 701,
+  unknown: 705,
+  bpchar: 1042,
+  varchar: 1043,
+  date: 1082,
+  time: 1083,
+  timestamp: 1114,
+  timestamptz: 1184,
+  interval: 1186,
+  timetz: 1266,
+  numeric: 1700,
+  uuid: 2950,
+  jsonb: 3802,
+  boolArray: 1000,
+  byteaArray: 1001,
+  charArray: 1002,
+  nameArray: 1003,
+  int2Array: 1005,
+  int4Array: 1007,
+  textArray: 1009,
+  bpcharArray: 1014,
+  varcharArray: 1015,
+  int8Array: 1016,
+  float4Array: 1021,
+  float8Array: 1022,
+  oidArray: 1028,
+  dateArray: 1182,
+  timeArray: 1183,
+  timestampArray: 1115,
+  timestamptzArray: 1185,
+  intervalArray: 1187,
+  numericArray: 1231,
+  timetzArray: 1270,
+  jsonArray: 199,
+  xmlArray: 143,
+  uuidArray: 2951,
+  jsonbArray: 3807,
+} as const);
+
+declare const encodedQueryParameterBrand: unique symbol;
+
+type EncodedQueryParameterBrand = {
+  readonly [encodedQueryParameterBrand]: true;
+};
+
+export type TextQueryParameter = Readonly<
+  EncodedQueryParameterBrand & {
+    format: 'text';
+    value: string;
+    typeOid?: number;
+  }
+>;
+
+export type BinaryQueryParameter = Readonly<
+  EncodedQueryParameterBrand & {
+    format: 'binary';
+    value: QueryBinaryInput;
+    typeOid?: number;
+  }
+>;
+
+export type NullQueryParameter = Readonly<
+  EncodedQueryParameterBrand & {
+    format: 'null';
+    typeOid: number;
+  }
+>;
+
+export type EncodedQueryParameter = TextQueryParameter | BinaryQueryParameter | NullQueryParameter;
+
+export type QueryParam =
+  | null
+  | string
+  | number
+  | bigint
+  | boolean
+  | Date
+  | QueryBinaryInput
+  | Readonly>
+  | ReadonlyArray
+  | EncodedQueryParameter;
+
+export type QueryParameterEncoder = (value: QueryParam, typeOid: number) => EncodedQueryParameter;
+
+export type QueryFormat = 'text' | 'binary' | { code: number; kind: 'other' };
+
+export type QueryField = {
+  name: string;
+  tableOid: number;
+  tableAttribute: number;
+  typeOid: number;
+  typeSize: number;
+  typeModifier: number;
+  format: QueryFormat;
+};
+
+export type RawQueryRow = {
+  values: Array;
+  text(column: number): string | null;
+};
+
+class ParsedRawQueryRow implements RawQueryRow {
+  constructor(readonly values: Array) {}
+
+  text(column: number): string | null {
+    if (column < 0 || column >= this.values.length) {
+      throw new Error(`query row has no column at index ${column}`);
+    }
+    const value = this.values[column]!;
+    return value === null ? null : decodeUtf8Strict(value, 'query value');
+  }
+}
+
+export type PostgresNotice = {
+  severity?: string;
+  localizedSeverity?: string;
+  nonlocalizedSeverity?: string;
+  sqlstate?: string;
+  message: string;
+  detail?: string;
+  hint?: string;
+  position?: string;
+  internalPosition?: string;
+  internalQuery?: string;
+  whereText?: string;
+  schemaName?: string;
+  tableName?: string;
+  columnName?: string;
+  dataTypeName?: string;
+  constraintName?: string;
+  file?: string;
+  line?: string;
+  routine?: string;
+  fields: PostgresErrorField[];
+};
+
+export type RawQueryResult = {
+  kind: 'command' | 'rows';
+  fields: QueryField[];
+  rows: RawQueryRow[];
+  commandTag?: string;
+  rowCount: number | null;
+  notices: PostgresNotice[];
+  getText(row: number, column: string): string | null;
+};
+
+export type QueryValue =
+  | null
+  | string
+  | number
+  | boolean
+  | Uint8Array
+  | QueryValue[]
+  | { [key: string]: unknown };
+
+export type QueryObjectRow = Record;
+export type QueryArrayRow = Value[];
+
+export type QueryResult = {
+  kind: 'command' | 'rows';
+  fields: QueryField[];
+  rows: Row[];
+  commandTag?: string;
+  rowCount: number | null;
+  notices: PostgresNotice[];
+};
+
+export type QueryValueDecoder = (value: string, field: QueryField) => Value;
+export type QueryDecoderMap = Readonly>;
+export type QueryRowMode = 'object' | 'array';
+
+export type QueryOptions<
+  RowMode extends QueryRowMode = QueryRowMode,
+  Decoders extends QueryDecoderMap | undefined = QueryDecoderMap | undefined,
+> = Readonly<{
+  rowMode?: RowMode;
+  valueMode?: 'decoded' | 'text';
+  decoders?: Decoders;
+  encoders?: Readonly>;
+}>;
+
+type QueryModeFromOptions = Options extends { readonly rowMode?: infer Mode }
+  ? Extract extends never
+    ? 'object'
+    : Extract
+  : 'object';
+
+type QueryDecoderOutput = Options extends { readonly decoders?: infer Decoders }
+  ? Decoders extends QueryDecoderMap
+    ? Decoders[keyof Decoders] extends QueryValueDecoder
+      ? Value
+      : never
+    : never
+  : never;
+
+type QueryRowForMode = Mode extends 'array'
+  ? QueryArrayRow
+  : QueryObjectRow;
+
+/** Infer the runtime row shape from `rowMode` and custom decoder return types. */
+export type InferQueryRow = [ExplicitRow] extends [never]
+  ? QueryRowForMode, QueryValue | QueryDecoderOutput>
+  : ExplicitRow;
+
+export type ParameterOptions = Readonly<{
+  encoders?: Readonly>;
+}>;
+
+export type CommandResult = {
+  commandTag?: string;
+  rowCount: number | null;
+  notices: PostgresNotice[];
+};
+
+export type ExecResult = {
+  statements: QueryResult[];
+  notices: PostgresNotice[];
+};
+
+export type DescribeResult = {
+  parameterTypeOids: number[];
+  fields?: QueryField[];
+  notices: PostgresNotice[];
+};
+
+export type TransactionStatus = 'idle' | 'transaction' | 'failed';
+
+export { simpleQuery };
+
+export type PostgresErrorField = {
+  code: number;
+  value: string;
+};
+
+export class PostgresError extends Error {
+  readonly severity?: string;
+  readonly localizedSeverity?: string;
+  readonly nonlocalizedSeverity?: string;
+  readonly sqlstate?: string;
+  readonly detail?: string;
+  readonly hint?: string;
+  readonly position?: string;
+  readonly internalPosition?: string;
+  readonly internalQuery?: string;
+  readonly whereText?: string;
+  readonly schemaName?: string;
+  readonly tableName?: string;
+  readonly columnName?: string;
+  readonly dataTypeName?: string;
+  readonly constraintName?: string;
+  readonly file?: string;
+  readonly line?: string;
+  readonly routine?: string;
+  readonly fields: PostgresErrorField[];
+  readonly notices: PostgresNotice[];
+
+  constructor(fields: PostgresErrorField[], notices: PostgresNotice[] = []) {
+    const severity = fieldValue(fields, 0x53) ?? fieldValue(fields, 0x56);
+    const sqlstate = fieldValue(fields, 0x43);
+    super(fieldValue(fields, 0x4d) ?? 'PostgreSQL ErrorResponse');
+    this.name = 'PostgresError';
+    this.severity = severity;
+    this.localizedSeverity = fieldValue(fields, 0x53);
+    this.nonlocalizedSeverity = fieldValue(fields, 0x56);
+    this.sqlstate = sqlstate;
+    this.detail = fieldValue(fields, 0x44);
+    this.hint = fieldValue(fields, 0x48);
+    this.position = fieldValue(fields, 0x50);
+    this.internalPosition = fieldValue(fields, 0x70);
+    this.internalQuery = fieldValue(fields, 0x71);
+    this.whereText = fieldValue(fields, 0x57);
+    this.schemaName = fieldValue(fields, 0x73);
+    this.tableName = fieldValue(fields, 0x74);
+    this.columnName = fieldValue(fields, 0x63);
+    this.dataTypeName = fieldValue(fields, 0x64);
+    this.constraintName = fieldValue(fields, 0x6e);
+    this.file = fieldValue(fields, 0x46);
+    this.line = fieldValue(fields, 0x4c);
+    this.routine = fieldValue(fields, 0x52);
+    this.fields = fields;
+    this.notices = notices;
+  }
+}
+
+/** @internal Preserve query-scoped notices on caller codec failures. */
+export function errorWithNotices(error: unknown, notices: ReadonlyArray): unknown {
+  if (notices.length === 0 && isObjectLike(error)) return error;
+  if (isObjectLike(error) && tryAttachNotices(error, notices)) return error;
+
+  const wrapped = withCause(new Error(codecFailureMessage(error)), error);
+  if (notices.length > 0) {
+    Object.defineProperty(wrapped, 'notices', {
+      value: [...notices],
+      configurable: true,
+      enumerable: true,
+    });
+  }
+  return wrapped;
+}
+
+function tryAttachNotices(error: object, notices: ReadonlyArray): boolean {
+  try {
+    const existing = (error as { notices?: unknown }).notices;
+    if (Array.isArray(existing)) {
+      try {
+        existing.unshift(...notices);
+        return true;
+      } catch {
+        // Fall through to replacing a configurable property.
+      }
+    }
+    if (!Object.isExtensible(error)) return false;
+    Object.defineProperty(error, 'notices', {
+      value: [...notices],
+      configurable: true,
+      enumerable: true,
+    });
+    return true;
+  } catch {
+    return false;
+  }
+}
+
+function codecFailureMessage(error: unknown): string {
+  if (error instanceof Error && error.message.length > 0) return error.message;
+  if (typeof error === 'string' && error.length > 0) return error;
+  if (isObjectLike(error)) {
+    try {
+      const message = (error as { message?: unknown }).message;
+      if (typeof message === 'string' && message.length > 0) return message;
+    } catch {
+      // Use the stable fallback for hostile thrown objects.
+    }
+  }
+  return 'query codec failed';
+}
+
+function isObjectLike(value: unknown): value is object {
+  return (typeof value === 'object' && value !== null) || typeof value === 'function';
+}
+
+type ParameterMetadata =
+  | { format: 'text'; value: string; typeOid?: number }
+  | { format: 'binary'; value: QueryBinaryInput; typeOid?: number }
+  | { format: 'null'; typeOid: number };
+
+const parameterMetadata = new WeakMap();
+
+export function text(
+  value: string | number | bigint | boolean | Date,
+  typeOid?: number,
+): TextQueryParameter {
+  const encoded = scalarText(value);
+  return parameterWrapper({
+    format: 'text',
+    value: encoded,
+    typeOid,
+  }) as TextQueryParameter;
+}
+
+export function binary(value: QueryBinaryInput, typeOid?: number): BinaryQueryParameter {
+  if (!isQueryBinaryInput(value)) {
+    throw new TypeError('binary() requires an ArrayBuffer or ArrayBuffer view');
+  }
+  return parameterWrapper({
+    format: 'binary',
+    value,
+    typeOid,
+  }) as BinaryQueryParameter;
+}
+
+export function typedNull(typeOid: number): NullQueryParameter {
+  validateTypeOid(typeOid, false);
+  return parameterWrapper({ format: 'null', typeOid }) as NullQueryParameter;
+}
+
+export function json(value: unknown, typeOid: number = postgresOids.jsonb): TextQueryParameter {
+  validateTypeOid(typeOid, false);
+  let encoded: string | undefined;
+  try {
+    encoded = JSON.stringify(value);
+  } catch (error) {
+    throw withCause(new TypeError('json() value must be acyclic and JSON-serializable'), error);
+  }
+  if (encoded === undefined) {
+    throw new TypeError('json() value must be JSON-serializable');
+  }
+  return parameterWrapper({
+    format: 'text',
+    value: encoded,
+    typeOid,
+  }) as TextQueryParameter;
+}
+
+export function array(values: ReadonlyArray, typeOid?: number): TextQueryParameter {
+  if (!Array.isArray(values)) {
+    throw new TypeError('array() requires a JavaScript array');
+  }
+  const elementTypeOid = typeOid === undefined ? undefined : arrayElementTypeOid(typeOid);
+  if (typeOid !== undefined && elementTypeOid === undefined) {
+    throw new TypeError('array() type OID ' + typeOid + ' is not a supported PostgreSQL array OID');
+  }
+  return parameterWrapper({
+    format: 'text',
+    value: encodeArrayLiteral(values, elementTypeOid),
+    typeOid,
+  }) as TextQueryParameter;
+}
+
+export type QueryPlan =
+  | Readonly<{ kind: 'complete'; input: Uint8Array }>
+  | Readonly<{
+      kind: 'describe';
+      input: Uint8Array;
+      bind(parameterTypeOids: ReadonlyArray): Uint8Array;
+    }>;
+
+export function planQuery(
+  sql: string,
+  parameters: ReadonlyArray = [],
+  options: ParameterOptions = {},
+): QueryPlan {
+  validateStatementInput(sql, parameters);
+  assertNoTopLevelCopy(sql);
+  const snapshot = Array.from(parameters, snapshotQueryParam);
+  const encoders =
+    options.encoders === undefined ? undefined : Object.freeze({ ...options.encoders });
+  const declaredTypeOids = snapshot.map(parameterDeclaredTypeOid);
+  if (declaredTypeOids.every((typeOid) => typeOid !== 0)) {
+    const normalized = snapshot.map((parameter, index) =>
+      normalizeQueryParam(parameter, declaredTypeOids[index]!, encoders),
+    );
+    return {
+      kind: 'complete',
+      input: encodeParseBindExecute(sql, declaredTypeOids, normalized),
+    };
+  }
+  return {
+    kind: 'describe',
+    input: describeQuery(sql, declaredTypeOids),
+    bind(parameterTypeOids: ReadonlyArray): Uint8Array {
+      if (parameterTypeOids.length !== snapshot.length) {
+        throw new Error(
+          'PostgreSQL described ' +
+            parameterTypeOids.length +
+            ' parameters, expected ' +
+            snapshot.length,
+        );
+      }
+      const normalized = snapshot.map((parameter, index) =>
+        normalizeQueryParam(parameter, parameterTypeOids[index]!, encoders),
+      );
+      return encodeParseBindExecute(sql, parameterTypeOids, normalized);
+    },
+  };
+}
+
+/** Encode a one-exchange query. Untyped values require planQuery() instead. */
+export function extendedQuery(
+  sql: string,
+  parameters: ReadonlyArray,
+  options: ParameterOptions = {},
+): Uint8Array {
+  const plan = planQuery(sql, parameters, options);
+  if (plan.kind === 'describe') {
+    throw new Error('extended query parameters require PostgreSQL type inference; use planQuery()');
+  }
+  return plan.input;
+}
+
+export function describeQuery(
+  sql: string,
+  parameterTypeOids: ReadonlyArray = [],
+): Uint8Array {
+  validateStatementInput(sql, parameterTypeOids);
+  for (const typeOid of parameterTypeOids) validateTypeOid(typeOid, true);
+  const sqlBytes = utf8Encoder.encode(sql);
+  const parseBodyLength = sqlBytes.length + 4 + parameterTypeOids.length * 4;
+  const packet = new ByteWriter(parseBodyLength + 17);
+  writeParse(packet, sqlBytes, parameterTypeOids);
+  packet.message(0x44, 2);
+  packet.u8(0x53);
+  packet.u8(0);
+  packet.message(0x53, 0);
+  return packet.finish();
+}
+
+function encodeParseBindExecute(
+  sql: string,
+  parameterTypeOids: ReadonlyArray,
+  parameters: ReadonlyArray,
+): Uint8Array {
+  const sqlBytes = utf8Encoder.encode(sql);
+  const parseBodyLength = sqlBytes.length + 4 + parameterTypeOids.length * 4;
+  const bindBodyLength = bindLength(parameters);
+  const packet = new ByteWriter(parseBodyLength + bindBodyLength + 32);
+  writeParse(packet, sqlBytes, parameterTypeOids);
+  writeBindExecute(packet, parameters);
+  return packet.finish();
+}
+
+function writeParse(
+  packet: ByteWriter,
+  sqlBytes: Uint8Array,
+  parameterTypeOids: ReadonlyArray,
+): void {
+  const parseBodyLength = sqlBytes.length + 4 + parameterTypeOids.length * 4;
+  packet.message(0x50, parseBodyLength);
+  packet.u8(0);
+  packet.bytes(sqlBytes);
+  packet.u8(0);
+  packet.i16(parameterTypeOids.length);
+  for (const typeOid of parameterTypeOids) packet.i32(typeOid);
+}
+
+function writeBindExecute(packet: ByteWriter, parameters: ReadonlyArray): void {
+  packet.message(0x42, bindLength(parameters));
+  packet.u8(0);
+  packet.u8(0);
+  packet.i16(parameters.length);
+  for (const parameter of parameters) packet.i16(parameter.kind === 'binary' ? 1 : 0);
+  packet.i16(parameters.length);
+  for (const parameter of parameters) {
+    if (parameter.kind === 'null') {
+      packet.i32(-1);
+    } else {
+      packet.i32(parameter.value.length);
+      packet.bytes(parameter.value);
+    }
+  }
+  packet.i16(1);
+  packet.i16(0);
+  packet.message(0x44, 2);
+  packet.u8(0x50);
+  packet.u8(0);
+  packet.message(0x45, 5);
+  packet.u8(0);
+  packet.i32(0);
+  packet.message(0x53, 0);
+}
+
+function bindLength(parameters: ReadonlyArray): number {
+  let length = 10 + parameters.length * 2;
+  for (const parameter of parameters) {
+    length += 4 + (parameter.kind === 'null' ? 0 : parameter.value.length);
+  }
+  return length;
+}
+
+const transactionStatuses = new WeakMap();
+
+type ParsedOperation = {
+  statements: Statement[];
+  notices: PostgresNotice[];
+  transactionStatus: TransactionStatus;
+};
+
+type RawOperation = ParsedOperation;
+type PendingExecResult = QueryResult;
+
+type OperationStatementFactory = (
+  kind: 'command' | 'rows',
+  fields: QueryField[],
+  rows: RawQueryRow[],
+  commandTag: string | undefined,
+  notices: PostgresNotice[],
+) => Statement;
+
+export function responseTransactionStatus(value: object): TransactionStatus | undefined {
+  return transactionStatuses.get(value);
+}
+
+/**
+ * Validate the complete backend framing and return the one terminal
+ * ReadyForQuery status without interpreting result values.
+ *
+ * Structured clients call this immediately after transport completion so a
+ * custom decoder or higher-level result assertion cannot obscure whether the
+ * physical PostgreSQL session reached a reusable boundary.
+ */
+export function inspectReadyForQuery(bytes: Uint8Array): TransactionStatus {
+  return inspectResponseBoundary(bytes, false).status;
+}
+
+/**
+ * Validate a structured callback-transaction response before high-level
+ * parsing can discard earlier command tags after a later ErrorResponse.
+ */
+export function inspectManagedTransactionResponse(bytes: Uint8Array): TransactionStatus {
+  const boundary = inspectResponseBoundary(bytes, true);
+  if (boundary.status === 'idle') {
+    throw new Error(
+      'structured callback transaction operation ended PostgreSQL transaction ownership; close the database',
+    );
+  }
+  for (const rawTag of boundary.commandTags) {
+    const tag = rawTag;
+    if (
+      tag === 'BEGIN' ||
+      tag === 'START TRANSACTION' ||
+      tag === 'COMMIT' ||
+      tag === 'PREPARE TRANSACTION' ||
+      tag === 'COMMIT PREPARED' ||
+      tag === 'ROLLBACK PREPARED'
+    ) {
+      throw new Error(
+        `PostgreSQL command tag ${tag} violated callback transaction ownership; close the database`,
+      );
+    }
+  }
+  return boundary.status;
+}
+
+function inspectResponseBoundary(
+  bytes: Uint8Array,
+  collectCommandTags: boolean,
+): Readonly<{ status: TransactionStatus; commandTags: string[] }> {
+  const cursor = new ByteCursor(bytes);
+  let status: TransactionStatus | undefined;
+  const commandTags: string[] = [];
+  while (!cursor.isAtEnd()) {
+    if (status !== undefined) {
+      throw new Error('backend returned bytes after ReadyForQuery');
+    }
+    const tag = cursor.readU8('backend message tag');
+    const length = cursor.readI32('backend message length');
+    if (length < 4) throw new Error('invalid backend message length ' + length);
+    const bodyBytes = cursor.readBytes(length - 4, 'backend message body');
+    if (tag === 0x43 && !collectCommandTags) {
+      validateCStringBody(bodyBytes, 'CommandComplete tag', 'CommandComplete');
+      continue;
+    }
+    const body = new ByteCursor(bodyBytes);
+    if (tag === 0x43) {
+      commandTags.push(body.readCString('CommandComplete tag'));
+      body.requireEnd('CommandComplete');
+    } else if (tag === 0x5a) {
+      status = parseReadyForQuery(body);
+    }
+  }
+  if (status === undefined) {
+    throw new Error('backend response ended before ReadyForQuery');
+  }
+  return { status, commandTags };
+}
+
+export function parseQueryRawResponse(bytes: Uint8Array): RawQueryResult {
+  return singleRawResult(parseRawOperation(bytes, 'extended-single'));
+}
+
+export function parseSimpleQueryRawResponse(bytes: Uint8Array): RawQueryResult {
+  return singleRawResult(parseRawOperation(bytes, 'simple-single'));
+}
+
+function singleRawResult(operation: RawOperation): RawQueryResult {
+  const result =
+    operation.statements[0] ?? rawResult('command', [], [], undefined, operation.notices);
+  if (operation.statements.length === 1) result.notices = operation.notices;
+  transactionStatuses.set(result, operation.transactionStatus);
+  return result;
+}
+
+export function decodeQueryResult(
+  raw: RawQueryResult,
+  options: Options & QueryOptions = {} as Options & QueryOptions,
+): QueryResult> {
+  let stableOptions: QueryOptions;
+  let rows: InferQueryRow[];
+  try {
+    stableOptions = stabilizeQueryOptions(options);
+    rows = decodeRows(raw.rows, raw.fields, stableOptions, false);
+  } catch (error) {
+    const failure = errorWithNotices(error, raw.notices);
+    const status = responseTransactionStatus(raw);
+    if (status !== undefined && isObjectLike(failure)) {
+      transactionStatuses.set(failure, status);
+    }
+    throw failure;
+  }
+  const result: QueryResult> = {
+    kind: raw.kind,
+    fields: raw.fields,
+    rows,
+    commandTag: raw.commandTag,
+    rowCount: raw.rowCount,
+    notices: raw.notices,
+  };
+  const status = responseTransactionStatus(raw);
+  if (status !== undefined) transactionStatuses.set(result, status);
+  return result;
+}
+
+export function parseExecResponse<
+  Row = never,
+  const Options extends Omit = {},
+>(
+  bytes: Uint8Array,
+  options: Options & Omit = {} as Options &
+    Omit,
+): ExecResult> {
+  const operation = parseOperation(bytes, 'simple-exec', pendingExecResult);
+  let result: ExecResult>;
+  try {
+    if (operation.statements.length > 0) {
+      const stableOptions = stabilizeQueryOptions(options);
+      for (const statement of operation.statements) {
+        materializePendingExecResult(statement, stableOptions);
+      }
+    }
+    result = {
+      statements: operation.statements as unknown as QueryResult>[],
+      notices: operation.notices,
+    };
+  } catch (error) {
+    const failure = errorWithNotices(error, operation.notices);
+    if (isObjectLike(failure)) {
+      transactionStatuses.set(failure, operation.transactionStatus);
+    }
+    throw failure;
+  }
+  transactionStatuses.set(result, operation.transactionStatus);
+  return result;
+}
+
+export function parseCommandResponse(bytes: Uint8Array): CommandResult {
+  const raw = parseQueryRawResponse(bytes);
+  const status = responseTransactionStatus(raw);
+  if (raw.kind === 'rows') {
+    throwWithStatus(new Error('execute() received rows; use query() for row results'), status);
+  }
+  const result: CommandResult = {
+    commandTag: raw.commandTag,
+    rowCount: raw.rowCount,
+    notices: raw.notices,
+  };
+  if (status !== undefined) transactionStatuses.set(result, status);
+  return result;
+}
+
+export function parseDescribeResponse(bytes: Uint8Array): DescribeResult {
+  const cursor = new ByteCursor(bytes);
+  const notices: PostgresNotice[] = [];
+  let parameterTypeOids: number[] | undefined;
+  let fields: QueryField[] | undefined;
+  let sawParseComplete = false;
+  let sawNoData = false;
+  let failure: Error | undefined;
+  let recoveryFailure: Error | undefined;
+  let sawErrorResponse = false;
+  let status: TransactionStatus | undefined;
+  while (!cursor.isAtEnd()) {
+    const tag = cursor.readU8('backend message tag');
+    const length = cursor.readI32('backend message length');
+    if (length < 4) throw new Error('invalid backend message length ' + length);
+    const body = new ByteCursor(cursor.readBytes(length - 4, 'backend message body'));
+    if (sawErrorResponse && tag !== 0x4e && tag !== 0x53 && tag !== 0x41 && tag !== 0x5a) {
+      recoveryFailure ??= withCause(
+        new Error('describe response contained ' + hexBackendTag(tag) + ' after ErrorResponse'),
+        failure,
+      );
+      continue;
+    }
+    try {
+      switch (tag) {
+        case 0x31:
+          if (sawParseComplete) throw new Error('duplicate ParseComplete');
+          body.requireEnd('ParseComplete');
+          sawParseComplete = true;
+          break;
+        case 0x74:
+          if (!sawParseComplete)
+            throw new Error('ParameterDescription arrived before ParseComplete');
+          if (parameterTypeOids !== undefined) throw new Error('duplicate ParameterDescription');
+          parameterTypeOids = parseParameterDescription(body);
+          body.requireEnd('ParameterDescription');
+          break;
+        case 0x54:
+          if (parameterTypeOids === undefined)
+            throw new Error('RowDescription arrived before ParameterDescription');
+          if (fields !== undefined || sawNoData) throw new Error('duplicate result description');
+          fields = parseRowDescription(body);
+          body.requireEnd('RowDescription');
+          break;
+        case 0x6e:
+          if (parameterTypeOids === undefined)
+            throw new Error('NoData arrived before ParameterDescription');
+          if (fields !== undefined || sawNoData) throw new Error('duplicate result description');
+          sawNoData = true;
+          body.requireEnd('NoData');
+          break;
+        case 0x45: {
+          const postgresFailure = parseErrorResponse(body, notices);
+          if (
+            sawParseComplete &&
+            parameterTypeOids !== undefined &&
+            (fields !== undefined || sawNoData)
+          ) {
+            failure ??= withCause(
+              new Error('ErrorResponse arrived after describe completion'),
+              postgresFailure,
+            );
+          } else {
+            failure ??= postgresFailure;
+          }
+          sawErrorResponse = true;
+          break;
+        }
+        case 0x4e:
+          notices.push(parseNoticeResponse(body));
+          break;
+        case 0x53:
+          validateParameterStatus(body);
+          break;
+        case 0x41:
+          validateNotificationResponse(body);
+          break;
+        case 0x5a:
+          status = parseReadyForQuery(body);
+          if (!cursor.isAtEnd()) {
+            failure ??= new Error('backend returned bytes after ReadyForQuery');
+            cursor.discardRemaining();
+          }
+          break;
+        default:
+          failure ??= new Error(
+            'describe() received unexpected backend message tag ' + hexBackendTag(tag),
+          );
+      }
+    } catch (error) {
+      failure ??= asError(error);
+    }
+  }
+  if (status === undefined) {
+    if (failure !== undefined) throw failure;
+    throw new Error('describe response ended before ReadyForQuery');
+  }
+  if (recoveryFailure !== undefined) throwWithStatus(recoveryFailure, status);
+  if (failure !== undefined) throwWithStatus(failure, status);
+  if (!sawParseComplete) {
+    throwWithStatus(new Error('describe response omitted ParseComplete'), status);
+  }
+  if (parameterTypeOids === undefined) {
+    throwWithStatus(new Error('describe response omitted ParameterDescription'), status);
+  }
+  if (fields === undefined && !sawNoData) {
+    throwWithStatus(new Error('describe response omitted RowDescription or NoData'), status);
+  }
+  const result: DescribeResult = {
+    parameterTypeOids,
+    ...(fields === undefined ? {} : { fields }),
+    notices,
+  };
+  transactionStatuses.set(result, status);
+  return result;
+}
+
+export function assertSuccessfulQueryResponse(bytes: Uint8Array): void {
+  const raw = singleRawResult(parseRawOperation(bytes, 'simple-single'));
+  if (raw.kind === 'rows') {
+    throwWithStatus(
+      new Error('command response unexpectedly contained rows'),
+      responseTransactionStatus(raw),
+    );
+  }
+}
+
+type RawOperationMode = 'extended-single' | 'simple-single' | 'simple-exec';
+
+function parseRawOperation(bytes: Uint8Array, mode: RawOperationMode): RawOperation {
+  return parseOperation(bytes, mode, rawResult);
+}
+
+function parseOperation(
+  bytes: Uint8Array,
+  mode: RawOperationMode,
+  statementFactory: OperationStatementFactory,
+): ParsedOperation {
+  const cursor = new ByteCursor(bytes);
+  const statements: Statement[] = [];
+  const notices: PostgresNotice[] = [];
+  let statementNotices: PostgresNotice[] = [];
+  let fields: QueryField[] | undefined;
+  let rows: RawQueryRow[] = [];
+  let failure: Error | undefined;
+  let recoveryFailure: Error | undefined;
+  let sawErrorResponse = false;
+  let completionCount = 0;
+  let extendedStage: 'start' | 'parsed' | 'bound' | 'described' | 'completed' = 'start';
+  let status: TransactionStatus | undefined;
+  while (!cursor.isAtEnd()) {
+    const tag = cursor.readU8('backend message tag');
+    const length = cursor.readI32('backend message length');
+    if (length < 4) throw new Error('invalid backend message length ' + length);
+    const body = new ByteCursor(cursor.readBytes(length - 4, 'backend message body'));
+    if (sawErrorResponse && tag !== 0x4e && tag !== 0x53 && tag !== 0x41 && tag !== 0x5a) {
+      recoveryFailure ??= withCause(
+        new Error('query response contained ' + hexBackendTag(tag) + ' after ErrorResponse'),
+        failure,
+      );
+      continue;
+    }
+    try {
+      switch (tag) {
+        case 0x54:
+          if (mode !== 'simple-exec' && completionCount > 0)
+            throw new Error('RowDescription arrived after statement completion');
+          if (mode === 'extended-single') {
+            if (extendedStage !== 'bound') {
+              throw new Error('RowDescription arrived before ParseComplete and BindComplete');
+            }
+            extendedStage = 'described';
+          }
+          if (fields !== undefined) failure ??= new Error('result received two RowDescriptions');
+          fields = parseRowDescription(body);
+          body.requireEnd('RowDescription');
+          break;
+        case 0x44:
+          if (completionCount > 0 && fields === undefined)
+            throw new Error('DataRow arrived after statement completion');
+          if (fields === undefined) throw new Error('DataRow arrived before RowDescription');
+          if (mode === 'extended-single' && extendedStage !== 'described') {
+            throw new Error('DataRow arrived before the result description');
+          }
+          rows.push(parseDataRow(body, fields.length));
+          body.requireEnd('DataRow');
+          break;
+        case 0x43: {
+          if (mode !== 'simple-exec' && completionCount > 0) {
+            throw new Error(
+              'queryRaw() received multiple result completions; use exec() for multi-statement SQL',
+            );
+          }
+          if (mode === 'extended-single' && extendedStage !== 'described') {
+            throw new Error('CommandComplete arrived before the extended-query result description');
+          }
+          const commandTag = body.readCString('CommandComplete tag');
+          body.requireEnd('CommandComplete');
+          statements.push(
+            statementFactory(
+              fields === undefined ? 'command' : 'rows',
+              fields ?? [],
+              rows,
+              commandTag,
+              statementNotices,
+            ),
+          );
+          fields = undefined;
+          rows = [];
+          statementNotices = [];
+          completionCount += 1;
+          if (mode === 'extended-single') {
+            extendedStage = 'completed';
+          }
+          break;
+        }
+        case 0x45: {
+          const postgresFailure = parseErrorResponse(body, notices);
+          if (mode !== 'simple-exec' && completionCount > 0) {
+            failure ??= withCause(
+              new Error('ErrorResponse arrived after statement completion'),
+              postgresFailure,
+            );
+          } else {
+            failure ??= postgresFailure;
+          }
+          sawErrorResponse = true;
+          break;
+        }
+        case 0x47:
+        case 0x48:
+        case 0x57:
+        case 0x64:
+        case 0x63:
+          failure ??= new Error(
+            'query() does not support COPY protocol responses; use a raw protocol API for COPY traffic',
+          );
+          break;
+        case 0x5a:
+          status = parseReadyForQuery(body);
+          if (!cursor.isAtEnd()) {
+            failure ??= new Error('backend returned bytes after ReadyForQuery');
+            cursor.discardRemaining();
+          }
+          break;
+        case 0x31:
+          if (mode !== 'extended-single') {
+            throw new Error('simple-query response contained ParseComplete');
+          }
+          if (extendedStage !== 'start') {
+            throw new Error('ParseComplete arrived out of order');
+          }
+          body.requireEnd('ParseComplete');
+          extendedStage = 'parsed';
+          break;
+        case 0x32:
+          if (mode !== 'extended-single') {
+            throw new Error('simple-query response contained BindComplete');
+          }
+          if (extendedStage !== 'parsed') {
+            throw new Error('BindComplete arrived before ParseComplete or out of order');
+          }
+          body.requireEnd('BindComplete');
+          extendedStage = 'bound';
+          break;
+        case 0x33:
+          throw new Error('unsolicited CloseComplete in query response');
+        case 0x49:
+          if (fields !== undefined || rows.length !== 0)
+            throw new Error('EmptyQueryResponse arrived during a row result');
+          if (mode !== 'simple-exec' && completionCount > 0) {
+            throw new Error(
+              'queryRaw() received multiple result completions; use exec() for multi-statement SQL',
+            );
+          }
+          if (mode === 'extended-single' && extendedStage !== 'described') {
+            throw new Error(
+              'EmptyQueryResponse arrived before the extended-query result description',
+            );
+          }
+          body.requireEnd('EmptyQueryResponse');
+          statementNotices = [];
+          completionCount += 1;
+          if (mode === 'extended-single') {
+            extendedStage = 'completed';
+          }
+          break;
+        case 0x6e:
+          if (mode !== 'extended-single') {
+            throw new Error('simple-query response contained NoData');
+          }
+          if (extendedStage !== 'bound') {
+            throw new Error('NoData arrived before ParseComplete and BindComplete');
+          }
+          body.requireEnd('NoData');
+          extendedStage = 'described';
+          break;
+        case 0x53:
+          validateParameterStatus(body);
+          break;
+        case 0x4e: {
+          const notice = parseNoticeResponse(body);
+          notices.push(notice);
+          statementNotices.push(notice);
+          break;
+        }
+        case 0x41:
+          validateNotificationResponse(body);
+          break;
+        default:
+          failure ??= new Error('unexpected backend message tag ' + hexBackendTag(tag));
+      }
+    } catch (error) {
+      failure ??= asError(error);
+    }
+  }
+  if (status === undefined) {
+    if (failure !== undefined) throw failure;
+    throw new Error('query response ended before ReadyForQuery');
+  }
+  if (recoveryFailure !== undefined) throwWithStatus(recoveryFailure, status);
+  if (fields !== undefined || rows.length !== 0) {
+    failure ??= new Error('query response ended before CommandComplete');
+  }
+  if (!sawErrorResponse && completionCount === 0) {
+    failure ??= new Error('query response omitted CommandComplete or EmptyQueryResponse');
+  }
+  if (!sawErrorResponse && mode === 'extended-single' && extendedStage !== 'completed') {
+    failure ??= new Error(
+      'extended-query response omitted ParseComplete, BindComplete, result description, or completion',
+    );
+  }
+  if (failure !== undefined) throwWithStatus(failure, status);
+  return { statements, notices, transactionStatus: status };
+}
+
+function pendingExecResult(
+  kind: 'command' | 'rows',
+  fields: QueryField[],
+  rows: RawQueryRow[],
+  commandTag: string | undefined,
+  notices: PostgresNotice[],
+): PendingExecResult {
+  return {
+    kind,
+    fields,
+    rows,
+    commandTag,
+    rowCount: commandTagRowCount(commandTag),
+    notices,
+  };
+}
+
+function rawResult(
+  kind: 'command' | 'rows',
+  fields: QueryField[],
+  rows: RawQueryRow[],
+  commandTag: string | undefined,
+  notices: PostgresNotice[],
+): RawQueryResult {
+  return {
+    kind,
+    fields,
+    rows,
+    commandTag,
+    rowCount: commandTagRowCount(commandTag),
+    notices,
+    getText(row: number, column: string): string | null {
+      const columnIndex = resolveFieldIndex(fields, column);
+      const queryRow = rows[row];
+      if (queryRow === undefined) throw new Error('query result has no row at index ' + row);
+      return queryRow.text(columnIndex);
+    },
+  };
+}
+
+function resolveFieldIndex(fields: QueryField[], name: string): number {
+  let match: number | undefined;
+  for (let index = 0; index < fields.length; index += 1) {
+    if (fields[index]!.name !== name) continue;
+    if (match !== undefined) {
+      throw new Error(
+        'query result has more than one column named ' +
+          JSON.stringify(name) +
+          '; use array row mode or a positional raw-row index',
+      );
+    }
+    match = index;
+  }
+  if (match === undefined) {
+    throw new Error('query result has no column named ' + JSON.stringify(name));
+  }
+  return match;
+}
+
+function stabilizeQueryOptions(options: QueryOptions): QueryOptions {
+  const rowMode = options.rowMode;
+  const valueMode = options.valueMode;
+  const decoders = options.decoders;
+  return {
+    rowMode,
+    valueMode,
+    decoders: decoders === undefined ? undefined : Object.freeze({ ...decoders }),
+  };
+}
+
+function decodeRows(
+  rawRows: RawQueryRow[],
+  fields: QueryField[],
+  options: QueryOptions,
+  reuseEmpty: boolean,
+): InferQueryRow[] {
+  if (options.rowMode !== 'array' && fields.length > 1) assertUniqueObjectRowFields(fields);
+  if (reuseEmpty && rawRows.length === 0) {
+    return rawRows as unknown as InferQueryRow[];
+  }
+  return rawRows.map((row) => materializeRow(row, fields, options)) as InferQueryRow<
+    Options,
+    Row
+  >[];
+}
+
+function materializePendingExecResult(
+  pending: PendingExecResult,
+  options: QueryOptions,
+): void {
+  const rows = decodeRows(pending.rows, pending.fields, options, true);
+  (pending as unknown as QueryResult>).rows = rows;
+}
+
+function assertUniqueObjectRowFields(fields: ReadonlyArray): void {
+  const names = new Set();
+  for (const field of fields) {
+    if (names.has(field.name)) {
+      throw new Error(
+        'decoded object rows cannot represent more than one column named ' +
+          JSON.stringify(field.name) +
+          "; use { rowMode: 'array' } or queryRaw()",
+      );
+    }
+    names.add(field.name);
+  }
+}
+
+function materializeRow(
+  row: RawQueryRow,
+  fields: QueryField[],
+  options: QueryOptions,
+): QueryObjectRow | QueryArrayRow {
+  const values = row.values.map((value, index) => decodeValue(value, fields[index]!, options));
+  if (options.rowMode === 'array') return values;
+  const object: QueryObjectRow = {};
+  for (let index = 0; index < fields.length; index += 1) {
+    Object.defineProperty(object, fields[index]!.name, {
+      value: values[index]!,
+      enumerable: true,
+      configurable: true,
+      writable: true,
+    });
+  }
+  return object;
+}
+
+function decodeValue(
+  value: Uint8Array | null,
+  field: QueryField,
+  options: QueryOptions,
+): QueryValue {
+  if (value === null) return null;
+  if (field.format !== 'text') return value;
+  const decodedText = decodeUtf8Strict(value, 'query value');
+  const decoder = options.decoders?.[field.typeOid];
+  if (decoder !== undefined) return decoder(decodedText, field) as QueryValue;
+  if (options.valueMode === 'text') return decodedText;
+  return decodeBuiltInText(decodedText, field.typeOid);
+}
+
+function commandTagRowCount(commandTag: string | undefined): number | null {
+  if (commandTag === undefined) {
+    return null;
+  }
+  let start = 0;
+  let end = commandTag.length;
+  while (start < end && isEcmaWhitespace(commandTag.charCodeAt(start))) start += 1;
+  while (end > start && isEcmaWhitespace(commandTag.charCodeAt(end - 1))) end -= 1;
+  if (start === end) return null;
+
+  let commandEnd = start;
+  while (commandEnd < end && !isEcmaWhitespace(commandTag.charCodeAt(commandEnd))) {
+    commandEnd += 1;
+  }
+  if (!hasRowCountCommand(commandTag, start, commandEnd)) return null;
+
+  let countStart = end;
+  while (countStart > start && !isEcmaWhitespace(commandTag.charCodeAt(countStart - 1))) {
+    countStart -= 1;
+  }
+  if (countStart === start) return null;
+
+  let value = 0;
+  for (let index = countStart; index < end; index += 1) {
+    const digit = commandTag.charCodeAt(index) - 0x30;
+    if (digit < 0 || digit > 9) return null;
+    value = value * 10 + digit;
+    if (!Number.isSafeInteger(value)) return null;
+  }
+  return value;
+}
+
+function hasRowCountCommand(value: string, start: number, end: number): boolean {
+  const length = end - start;
+  if (length === 4) {
+    return value.startsWith('MOVE', start) || value.startsWith('COPY', start);
+  }
+  if (length === 5) {
+    return value.startsWith('MERGE', start) || value.startsWith('FETCH', start);
+  }
+  if (length === 6) {
+    return (
+      value.startsWith('SELECT', start) ||
+      value.startsWith('INSERT', start) ||
+      value.startsWith('UPDATE', start) ||
+      value.startsWith('DELETE', start)
+    );
+  }
+  return false;
+}
+
+function isEcmaWhitespace(code: number): boolean {
+  if ((code >= 0x09 && code <= 0x0d) || code === 0x20 || code === 0xa0 || code === 0x1680) {
+    return true;
+  }
+  if (code >= 0x2000 && code <= 0x200a) return true;
+  switch (code) {
+    case 0x2028:
+    case 0x2029:
+    case 0x202f:
+    case 0x205f:
+    case 0x3000:
+    case 0xfeff:
+      return true;
+    default:
+      return false;
+  }
+}
+
+type NormalizedParam =
+  | { kind: 'null' }
+  | { kind: 'text'; value: Uint8Array }
+  | { kind: 'binary'; value: Uint8Array };
+
+function normalizeQueryParam(
+  parameter: QueryParam,
+  typeOid: number,
+  encoders: Readonly> | undefined,
+): NormalizedParam {
+  validateTypeOid(typeOid, false);
+  const wrapper =
+    parameter !== null && typeof parameter === 'object'
+      ? parameterMetadata.get(parameter)
+      : undefined;
+  if (wrapper !== undefined) return normalizeWrapper(wrapper, typeOid);
+
+  const custom = encoders?.[typeOid];
+  if (custom !== undefined) {
+    const encoded = custom(parameter, typeOid);
+    if (encoded === null || typeof encoded !== 'object') {
+      throw new TypeError('query encoder for OID ' + typeOid + ' must return a parameter helper');
+    }
+    const encodedMetadata = parameterMetadata.get(encoded);
+    if (encodedMetadata === undefined) {
+      throw new TypeError(
+        'query encoder for OID ' + typeOid + ' must use text(), binary(), or typedNull()',
+      );
+    }
+    return normalizeWrapper(encodedMetadata, typeOid);
+  }
+
+  if (parameter === null) return { kind: 'null' };
+  if (typeof parameter === 'string') {
+    return { kind: 'text', value: utf8Encoder.encode(parameter) };
+  }
+  if (typeof parameter === 'number') {
+    if (!isNumericOrTextOid(typeOid)) throw unsupportedParameter(parameter, typeOid);
+    return { kind: 'text', value: utf8Encoder.encode(scalarText(parameter)) };
+  }
+  if (typeof parameter === 'bigint') {
+    if (!isNumericOrTextOid(typeOid)) throw unsupportedParameter(parameter, typeOid);
+    return { kind: 'text', value: utf8Encoder.encode(parameter.toString()) };
+  }
+  if (typeof parameter === 'boolean') {
+    if (typeOid !== postgresOids.bool && !isTextOid(typeOid)) {
+      throw unsupportedParameter(parameter, typeOid);
+    }
+    return {
+      kind: 'text',
+      value: utf8Encoder.encode(parameter ? 'true' : 'false'),
+    };
+  }
+  if (parameter instanceof Date) {
+    return {
+      kind: 'text',
+      value: utf8Encoder.encode(dateText(parameter, typeOid)),
+    };
+  }
+  if (isQueryBinaryInput(parameter)) {
+    if (typeOid !== postgresOids.bytea) throw unsupportedParameter(parameter, typeOid);
+    return { kind: 'binary', value: toUint8Array(parameter) };
+  }
+  if (Array.isArray(parameter)) {
+    const elementTypeOid = arrayElementTypeOid(typeOid);
+    if (elementTypeOid === undefined) throw unsupportedParameter(parameter, typeOid);
+    return {
+      kind: 'text',
+      value: utf8Encoder.encode(encodeArrayLiteral(parameter, elementTypeOid)),
+    };
+  }
+  if (isPlainRecord(parameter)) {
+    if (typeOid !== postgresOids.json && typeOid !== postgresOids.jsonb) {
+      throw unsupportedParameter(parameter, typeOid);
+    }
+    return { kind: 'text', value: utf8Encoder.encode(json(parameter).value) };
+  }
+  throw new TypeError('query parameter is unsupported; use an explicit parameter helper');
+}
+
+function normalizeWrapper(wrapper: ParameterMetadata, typeOid: number): NormalizedParam {
+  if (wrapper.typeOid !== undefined && wrapper.typeOid !== typeOid) {
+    throw new Error(
+      'parameter declares PostgreSQL OID ' +
+        wrapper.typeOid +
+        ', but PostgreSQL described OID ' +
+        typeOid,
+    );
+  }
+  if (wrapper.format === 'null') return { kind: 'null' };
+  if (wrapper.format === 'text') {
+    return { kind: 'text', value: utf8Encoder.encode(wrapper.value) };
+  }
+  return { kind: 'binary', value: toUint8Array(wrapper.value) };
+}
+
+function parameterDeclaredTypeOid(parameter: QueryParam): number {
+  if (parameter !== null && typeof parameter === 'object') {
+    const wrapper = parameterMetadata.get(parameter);
+    if (wrapper?.typeOid !== undefined) {
+      validateTypeOid(wrapper.typeOid, false);
+      return wrapper.typeOid;
+    }
+  }
+  return 0;
+}
+
+function snapshotQueryParam(parameter: QueryParam): QueryParam {
+  if (
+    parameter === null ||
+    typeof parameter === 'string' ||
+    typeof parameter === 'number' ||
+    typeof parameter === 'bigint' ||
+    typeof parameter === 'boolean'
+  ) {
+    return parameter;
+  }
+  if (parameter === undefined) throw new TypeError('query parameters must not be undefined');
+  const wrapper = typeof parameter === 'object' ? parameterMetadata.get(parameter) : undefined;
+  if (wrapper !== undefined) {
+    if (wrapper.format === 'null') return typedNull(wrapper.typeOid);
+    if (wrapper.format === 'binary') {
+      return binary(toUint8Array(wrapper.value).slice(), wrapper.typeOid);
+    }
+    return text(wrapper.value, wrapper.typeOid);
+  }
+  if (parameter instanceof Date) return new Date(parameter.getTime());
+  if (isQueryBinaryInput(parameter)) return toUint8Array(parameter).slice();
+  if (Array.isArray(parameter))
+    return Array.from(parameter, (value) => snapshotQueryParam(value as QueryParam));
+  if (isPlainRecord(parameter)) {
+    let encoded: string | undefined;
+    try {
+      encoded = JSON.stringify(parameter);
+    } catch (error) {
+      throw withCause(
+        new TypeError('plain-object query parameters must be JSON-serializable'),
+        error,
+      );
+    }
+    if (encoded === undefined)
+      throw new TypeError('plain-object query parameters must be JSON-serializable');
+    return JSON.parse(encoded) as Readonly>;
+  }
+  throw new TypeError('query parameter is unsupported; use an explicit parameter helper');
+}
+
+function parameterWrapper(metadata: ParameterMetadata): EncodedQueryParameter {
+  if (metadata.typeOid !== undefined) validateTypeOid(metadata.typeOid, false);
+  const visible =
+    metadata.format === 'null'
+      ? { format: 'null' as const, typeOid: metadata.typeOid }
+      : {
+          format: metadata.format,
+          value: metadata.value,
+          ...(metadata.typeOid === undefined ? {} : { typeOid: metadata.typeOid }),
+        };
+  const wrapper = Object.freeze(visible) as EncodedQueryParameter;
+  parameterMetadata.set(wrapper, metadata);
+  return wrapper;
+}
+
+function isQueryBinaryInput(value: unknown): value is QueryBinaryInput {
+  return value instanceof ArrayBuffer || ArrayBuffer.isView(value);
+}
+
+function validateStatementInput(sql: string, parameters: { length: number }): void {
+  if (parameters.length > 0x7fff) {
+    throw new Error('extended query supports at most 32767 parameters, got ' + parameters.length);
+  }
+  if (sql.includes('\0')) throw new Error('extended query SQL must not contain NUL bytes');
+}
+
+function validateTypeOid(typeOid: number, allowZero: boolean): void {
+  if (!Number.isInteger(typeOid) || typeOid < (allowZero ? 0 : 1) || typeOid > 0xffffffff) {
+    throw new TypeError(
+      'PostgreSQL type OID must be ' + (allowZero ? 'zero or ' : '') + 'a positive uint32',
+    );
+  }
+}
+
+function scalarText(value: string | number | bigint | boolean | Date): string {
+  if (typeof value === 'number') {
+    if (!Number.isFinite(value)) throw new TypeError('number query parameters must be finite');
+    if (Number.isInteger(value) && !Number.isSafeInteger(value)) {
+      throw new TypeError('integer query parameters must be safe integers; use bigint instead');
+    }
+  }
+  if (value instanceof Date) {
+    if (Number.isNaN(value.getTime())) throw new TypeError('Date query parameters must be valid');
+    return value.toISOString();
+  }
+  return String(value);
+}
+
+function dateText(value: Date, typeOid: number): string {
+  const iso = scalarText(value);
+  if (typeOid === postgresOids.date) return iso.slice(0, 10);
+  if (typeOid === postgresOids.timestamp) return iso.slice(0, -1).replace('T', ' ');
+  if (typeOid === postgresOids.timestamptz || isTextOid(typeOid)) return iso;
+  throw unsupportedParameter(value, typeOid);
+}
+
+function isNumericOrTextOid(typeOid: number): boolean {
+  return (
+    (
+      [
+        postgresOids.int2,
+        postgresOids.int4,
+        postgresOids.int8,
+        postgresOids.oid,
+        postgresOids.float4,
+        postgresOids.float8,
+        postgresOids.numeric,
+      ] as number[]
+    ).includes(typeOid) || isTextOid(typeOid)
+  );
+}
+
+function isTextOid(typeOid: number): boolean {
+  return typeOid === postgresOids.text || typeOid === postgresOids.varchar;
+}
+
+function unsupportedParameter(value: unknown, typeOid: number): TypeError {
+  const kind = value === null ? 'null' : Array.isArray(value) ? 'array' : typeof value;
+  return new TypeError(
+    'cannot safely encode ' +
+      kind +
+      ' for PostgreSQL OID ' +
+      typeOid +
+      '; use a typed helper or encoder',
+  );
+}
+
+function isPlainRecord(value: unknown): value is Readonly> {
+  if (value === null || typeof value !== 'object') return false;
+  const prototype = Object.getPrototypeOf(value);
+  return prototype === Object.prototype || prototype === null;
+}
+
+function throwWithStatus(error: Error, status: TransactionStatus | undefined): never {
+  if (status !== undefined) transactionStatuses.set(error, status);
+  throw error;
+}
+
+function asError(error: unknown): Error {
+  return error instanceof Error
+    ? error
+    : withCause(new Error('PostgreSQL response parsing failed'), error);
+}
+
+function withCause(error: ErrorType, cause: unknown): ErrorType {
+  Object.defineProperty(error, 'cause', {
+    value: cause,
+    configurable: true,
+    writable: true,
+  });
+  return error;
+}
+
+function decodeBuiltInText(value: string, typeOid: number): QueryValue {
+  switch (typeOid) {
+    case postgresOids.bool:
+      if (value === 't') return true;
+      if (value === 'f') return false;
+      throw new Error('invalid PostgreSQL bool text ' + JSON.stringify(value));
+    case postgresOids.int2:
+    case postgresOids.int4:
+    case postgresOids.oid:
+      return decodeInteger(value, typeOid);
+    case postgresOids.float4:
+    case postgresOids.float8:
+      return decodeFloat(value, typeOid);
+    case postgresOids.json:
+    case postgresOids.jsonb:
+      return JSON.parse(value) as QueryValue;
+    case postgresOids.bytea:
+      return decodeBytea(value);
+    case postgresOids.int8:
+    case postgresOids.numeric:
+    case postgresOids.date:
+    case postgresOids.time:
+    case postgresOids.timestamp:
+    case postgresOids.timestamptz:
+    case postgresOids.interval:
+    case postgresOids.timetz:
+      return value;
+    default: {
+      const elementTypeOid = arrayElementTypeOid(typeOid);
+      if (elementTypeOid === undefined) return value;
+      return decodeArrayLiteral(value, elementTypeOid);
+    }
+  }
+}
+
+function decodeInteger(value: string, typeOid: number): number {
+  if (!/^-?[0-9]+$/.test(value)) {
+    throw new Error(
+      'invalid PostgreSQL integer text for OID ' + typeOid + ': ' + JSON.stringify(value),
+    );
+  }
+  const decoded = Number(value);
+  if (!Number.isSafeInteger(decoded)) {
+    throw new Error('PostgreSQL integer for OID ' + typeOid + ' exceeds JavaScript safe range');
+  }
+  return decoded;
+}
+
+function decodeFloat(value: string, typeOid: number): number {
+  if (value === 'NaN') return Number.NaN;
+  if (value === 'Infinity') return Number.POSITIVE_INFINITY;
+  if (value === '-Infinity') return Number.NEGATIVE_INFINITY;
+  if (!/^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/.test(value)) {
+    throw new Error(
+      'invalid PostgreSQL float text for OID ' + typeOid + ': ' + JSON.stringify(value),
+    );
+  }
+  const decoded = Number(value);
+  if (!Number.isFinite(decoded))
+    throw new Error('PostgreSQL float text is outside JavaScript range');
+  return decoded;
+}
+
+function decodeBytea(value: string): Uint8Array {
+  if (value.startsWith('\\x')) {
+    const hex = value.slice(2);
+    if (hex.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex)) {
+      throw new Error('invalid PostgreSQL hex bytea text');
+    }
+    const bytes = new Uint8Array(hex.length / 2);
+    for (let index = 0; index < bytes.length; index += 1) {
+      bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
+    }
+    return bytes;
+  }
+  const bytes: number[] = [];
+  for (let index = 0; index < value.length; index += 1) {
+    if (value[index] !== '\\') {
+      bytes.push(value.charCodeAt(index));
+      continue;
+    }
+    if (value[index + 1] === '\\') {
+      bytes.push(0x5c);
+      index += 1;
+      continue;
+    }
+    const octal = value.slice(index + 1, index + 4);
+    if (!/^[0-3][0-7]{2}$/.test(octal)) throw new Error('invalid PostgreSQL escape bytea text');
+    bytes.push(Number.parseInt(octal, 8));
+    index += 3;
+  }
+  return Uint8Array.from(bytes);
+}
+
+const arrayElementOids = new Map([
+  [postgresOids.boolArray, postgresOids.bool],
+  [postgresOids.byteaArray, postgresOids.bytea],
+  [postgresOids.charArray, postgresOids.char],
+  [postgresOids.nameArray, postgresOids.name],
+  [postgresOids.int2Array, postgresOids.int2],
+  [postgresOids.int4Array, postgresOids.int4],
+  [postgresOids.textArray, postgresOids.text],
+  [postgresOids.bpcharArray, postgresOids.bpchar],
+  [postgresOids.varcharArray, postgresOids.varchar],
+  [postgresOids.int8Array, postgresOids.int8],
+  [postgresOids.float4Array, postgresOids.float4],
+  [postgresOids.float8Array, postgresOids.float8],
+  [postgresOids.oidArray, postgresOids.oid],
+  [postgresOids.dateArray, postgresOids.date],
+  [postgresOids.timeArray, postgresOids.time],
+  [postgresOids.timestampArray, postgresOids.timestamp],
+  [postgresOids.timestamptzArray, postgresOids.timestamptz],
+  [postgresOids.intervalArray, postgresOids.interval],
+  [postgresOids.numericArray, postgresOids.numeric],
+  [postgresOids.timetzArray, postgresOids.timetz],
+  [postgresOids.jsonArray, postgresOids.json],
+  [postgresOids.xmlArray, postgresOids.xml],
+  [postgresOids.uuidArray, postgresOids.uuid],
+  [postgresOids.jsonbArray, postgresOids.jsonb],
+]);
+
+function arrayElementTypeOid(arrayTypeOid: number): number | undefined {
+  return arrayElementOids.get(arrayTypeOid);
+}
+
+function encodeArrayLiteral(values: ReadonlyArray, elementTypeOid?: number): string {
+  return (
+    '{' + Array.from(values, (value) => encodeArrayElement(value, elementTypeOid)).join(',') + '}'
+  );
+}
+
+function encodeArrayElement(value: unknown, elementTypeOid?: number): string {
+  if (value === null) return 'NULL';
+  if (value === undefined) throw new TypeError('PostgreSQL arrays cannot contain undefined');
+  if (Array.isArray(value)) return encodeArrayLiteral(value, elementTypeOid);
+  const wrapper =
+    typeof value === 'object' && value !== null ? parameterMetadata.get(value) : undefined;
+  if (wrapper !== undefined) {
+    if (
+      elementTypeOid !== undefined &&
+      wrapper.typeOid !== undefined &&
+      wrapper.typeOid !== elementTypeOid
+    ) {
+      throw new TypeError(
+        'array element declares PostgreSQL OID ' +
+          wrapper.typeOid +
+          ', but the array resolves element OID ' +
+          elementTypeOid,
+      );
+    }
+    if (wrapper.format === 'null') return 'NULL';
+    if (wrapper.format === 'binary') {
+      if (elementTypeOid !== undefined && elementTypeOid !== postgresOids.bytea) {
+        throw unsupportedParameter(value, elementTypeOid);
+      }
+      return quoteArrayElement('\\x' + bytesToHex(toUint8Array(wrapper.value)));
+    }
+    return quoteArrayElement(wrapper.value);
+  }
+  if (typeof value === 'string') return quoteArrayElement(value);
+  if (typeof value === 'number' || typeof value === 'bigint' || typeof value === 'boolean') {
+    if (elementTypeOid !== undefined) {
+      normalizeQueryParam(value as QueryParam, elementTypeOid, undefined);
+    }
+    return quoteArrayElement(scalarText(value));
+  }
+  if (value instanceof Date) {
+    return quoteArrayElement(
+      elementTypeOid === undefined ? scalarText(value) : dateText(value, elementTypeOid),
+    );
+  }
+  if (isQueryBinaryInput(value)) {
+    if (elementTypeOid !== undefined && elementTypeOid !== postgresOids.bytea) {
+      throw unsupportedParameter(value, elementTypeOid);
+    }
+    return quoteArrayElement('\\x' + bytesToHex(toUint8Array(value)));
+  }
+  if (
+    isPlainRecord(value) &&
+    (elementTypeOid === postgresOids.json || elementTypeOid === postgresOids.jsonb)
+  ) {
+    return quoteArrayElement(json(value, elementTypeOid).value);
+  }
+  throw new TypeError('PostgreSQL array element is unsupported; use an explicit helper');
+}
+
+function quoteArrayElement(value: string): string {
+  return '"' + value.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
+}
+
+function bytesToHex(bytes: Uint8Array): string {
+  let hex = '';
+  for (const byte of bytes) hex += byte.toString(16).padStart(2, '0');
+  return hex;
+}
+
+type ParsedArrayValue = string | null | ParsedArrayValue[];
+
+function decodeArrayLiteral(value: string, elementTypeOid: number): QueryValue[] {
+  const parsed = new ArrayTextParser(value).parse();
+  return decodeArrayValues(parsed, elementTypeOid);
+}
+
+function decodeArrayValues(values: ParsedArrayValue[], elementTypeOid: number): QueryValue[] {
+  return values.map((value) =>
+    Array.isArray(value)
+      ? decodeArrayValues(value, elementTypeOid)
+      : value === null
+        ? null
+        : decodeBuiltInText(value, elementTypeOid),
+  );
+}
+
+class ArrayTextParser {
+  readonly #input: string;
+  #offset = 0;
+
+  constructor(input: string) {
+    this.#input = input;
+  }
+
+  parse(): ParsedArrayValue[] {
+    if (this.#input.startsWith('[')) {
+      const separator = this.#input.indexOf('=');
+      if (separator < 0) throw new Error('invalid PostgreSQL array dimensions');
+      this.#offset = separator + 1;
+    }
+    const result = this.#level();
+    if (this.#offset !== this.#input.length)
+      throw new Error('PostgreSQL array text has trailing data');
+    return result;
+  }
+
+  #level(): ParsedArrayValue[] {
+    if (this.#input[this.#offset] !== '{')
+      throw new Error('PostgreSQL array text must start with {');
+    this.#offset += 1;
+    const result: ParsedArrayValue[] = [];
+    if (this.#input[this.#offset] === '}') {
+      this.#offset += 1;
+      return result;
+    }
+    for (;;) {
+      result.push(this.#input[this.#offset] === '{' ? this.#level() : this.#element());
+      const delimiter = this.#input[this.#offset];
+      if (delimiter === '}') {
+        this.#offset += 1;
+        return result;
+      }
+      if (delimiter !== ',') throw new Error('invalid PostgreSQL array delimiter');
+      this.#offset += 1;
+    }
+  }
+
+  #element(): string | null {
+    if (this.#input[this.#offset] === '"') {
+      this.#offset += 1;
+      let value = '';
+      for (;;) {
+        const character = this.#input[this.#offset];
+        if (character === undefined) throw new Error('unterminated quoted PostgreSQL array value');
+        this.#offset += 1;
+        if (character === '"') return value;
+        if (character === '\\') {
+          const escaped = this.#input[this.#offset];
+          if (escaped === undefined) throw new Error('unterminated PostgreSQL array escape');
+          value += escaped;
+          this.#offset += 1;
+        } else {
+          value += character;
+        }
+      }
+    }
+    let value = '';
+    while (this.#offset < this.#input.length) {
+      const character = this.#input[this.#offset]!;
+      if (character === ',' || character === '}') break;
+      this.#offset += 1;
+      if (character === '\\') {
+        const escaped = this.#input[this.#offset];
+        if (escaped === undefined) throw new Error('unterminated PostgreSQL array escape');
+        value += escaped;
+        this.#offset += 1;
+      } else {
+        value += character;
+      }
+    }
+    return value === 'NULL' ? null : value;
+  }
+}
+
+export function assertNoTopLevelCopy(sql: string): void {
+  if (containsTopLevelCopy(sql)) {
+    throw new Error(
+      'structured SQL does not support COPY; use a raw protocol API for COPY traffic',
+    );
+  }
+}
+
+/**
+ * Reject transaction commands whose response boundary cannot prove that the
+ * callback still owns the transaction it started. PostgreSQL reports both
+ * `ROLLBACK TO SAVEPOINT` and `ROLLBACK AND CHAIN` as command tag `ROLLBACK`
+ * with ReadyForQuery status `transaction`, so the latter must be rejected
+ * before execution rather than inferred from the backend response.
+ */
+export function assertNoTransactionChain(sql: string): void {
+  if (containsTransactionChain(sql)) {
+    throw new Error(
+      'callback transactions do not support ROLLBACK/ABORT ... AND CHAIN; return or throw from the callback instead',
+    );
+  }
+}
+
+export function structuredSimpleQuery(sql: string): Uint8Array {
+  assertNoTopLevelCopy(sql);
+  return simpleQuery(sql);
+}
+
+export function containsTopLevelCopy(sql: string): boolean {
+  return (
+    scanTopLevelTokens(sql, false, (word, first) => first && word === 'copy') ||
+    scanTopLevelTokens(sql, true, (word, first) => first && word === 'copy')
+  );
+}
+
+export function containsTransactionChain(sql: string): boolean {
+  return scanTransactionChain(sql, false) || scanTransactionChain(sql, true);
+}
+
+function scanTransactionChain(sql: string, plainStringsEscapeBackslashes: boolean): boolean {
+  let currentStatement = -1;
+  let state: 'afterControl' | 'afterQualifier' | 'afterAnd' | 'ineligible' = 'ineligible';
+  return scanTopLevelTokens(sql, plainStringsEscapeBackslashes, (word, first, statement) => {
+    if (statement !== currentStatement) {
+      currentStatement = statement;
+      state = first && (word === 'rollback' || word === 'abort') ? 'afterControl' : 'ineligible';
+      return false;
+    }
+    if (word === undefined) {
+      state = 'ineligible';
+      return false;
+    }
+    if (state === 'afterControl' && (word === 'work' || word === 'transaction')) {
+      state = 'afterQualifier';
+    } else if ((state === 'afterControl' || state === 'afterQualifier') && word === 'and') {
+      state = 'afterAnd';
+    } else if (state === 'afterAnd' && word === 'chain') {
+      return true;
+    } else {
+      // This also keeps ROLLBACK TO [SAVEPOINT] inside the managed transaction.
+      state = 'ineligible';
+    }
+    return false;
+  });
+}
+
+function scanTopLevelTokens(
+  sql: string,
+  plainStringsEscapeBackslashes: boolean,
+  visit: (word: string | undefined, first: boolean, statement: number) => boolean,
+): boolean {
+  let offset = 0;
+  let depth = 0;
+  let statementStart = true;
+  let statement = 0;
+  while (offset < sql.length) {
+    const character = sql[offset]!;
+    if (/\s/.test(character)) {
+      offset += 1;
+      continue;
+    }
+    if (character === '-' && sql[offset + 1] === '-') {
+      let end = offset + 2;
+      while (end < sql.length && sql[end] !== '\n' && sql[end] !== '\r') end += 1;
+      offset = end < sql.length ? end + 1 : sql.length;
+      continue;
+    }
+    if (character === '/' && sql[offset + 1] === '*') {
+      offset = skipBlockComment(sql, offset + 2);
+      continue;
+    }
+    if ((character === 'e' || character === 'E') && sql[offset + 1] === "'") {
+      if (depth === 0 && visit(undefined, statementStart, statement)) return true;
+      statementStart = false;
+      offset = skipSingleQuote(sql, offset + 1, true);
+      continue;
+    }
+    if (character === "'") {
+      if (depth === 0 && visit(undefined, statementStart, statement)) return true;
+      statementStart = false;
+      offset = skipSingleQuote(sql, offset, plainStringsEscapeBackslashes);
+      continue;
+    }
+    if (character === '"') {
+      if (depth === 0 && visit(undefined, statementStart, statement)) return true;
+      statementStart = false;
+      offset = skipDoubleQuote(sql, offset);
+      continue;
+    }
+    if (character === '$') {
+      const delimiter = dollarQuoteDelimiter(sql, offset);
+      if (delimiter !== undefined) {
+        if (depth === 0 && visit(undefined, statementStart, statement)) return true;
+        statementStart = false;
+        const end = sql.indexOf(delimiter, offset + delimiter.length);
+        offset = end < 0 ? sql.length : end + delimiter.length;
+        continue;
+      }
+    }
+    if (character === '(') {
+      if (depth === 0 && visit(undefined, statementStart, statement)) return true;
+      depth += 1;
+      statementStart = false;
+      offset += 1;
+      continue;
+    }
+    if (character === ')') {
+      if (depth > 0) depth -= 1;
+      offset += 1;
+      continue;
+    }
+    if (character === ';' && depth === 0) {
+      statementStart = true;
+      statement += 1;
+      offset += 1;
+      continue;
+    }
+    if (isPostgresIdentifierStart(character)) {
+      const start = offset;
+      offset += 1;
+      while (offset < sql.length && isPostgresIdentifierContinuation(sql[offset]!)) offset += 1;
+      if (depth === 0 && visit(sql.slice(start, offset).toLowerCase(), statementStart, statement)) {
+        return true;
+      }
+      statementStart = false;
+      continue;
+    }
+    if (depth === 0 && visit(undefined, statementStart, statement)) return true;
+    statementStart = false;
+    offset += 1;
+  }
+  return false;
+}
+
+function skipBlockComment(sql: string, start: number): number {
+  let depth = 1;
+  let offset = start;
+  while (offset < sql.length && depth > 0) {
+    if (sql[offset] === '/' && sql[offset + 1] === '*') {
+      depth += 1;
+      offset += 2;
+    } else if (sql[offset] === '*' && sql[offset + 1] === '/') {
+      depth -= 1;
+      offset += 2;
+    } else {
+      offset += 1;
+    }
+  }
+  return offset;
+}
+
+function skipSingleQuote(sql: string, quoteOffset: number, escapeBackslash: boolean): number {
+  let offset = quoteOffset + 1;
+  while (offset < sql.length) {
+    if (escapeBackslash && sql[offset] === '\\') {
+      offset += Math.min(2, sql.length - offset);
+    } else if (sql[offset] === "'" && sql[offset + 1] === "'") {
+      offset += 2;
+    } else if (sql[offset] === "'") {
+      return offset + 1;
+    } else {
+      offset += 1;
+    }
+  }
+  return offset;
+}
+
+function skipDoubleQuote(sql: string, quoteOffset: number): number {
+  let offset = quoteOffset + 1;
+  while (offset < sql.length) {
+    if (sql[offset] === '"' && sql[offset + 1] === '"') offset += 2;
+    else if (sql[offset] === '"') return offset + 1;
+    else offset += 1;
+  }
+  return offset;
+}
+
+function dollarQuoteDelimiter(sql: string, offset: number): string | undefined {
+  let end = offset + 1;
+  if (sql[end] === '$') return '$$';
+  if (end >= sql.length || !isPostgresIdentifierStart(sql[end]!)) return undefined;
+  end += 1;
+  while (end < sql.length && sql[end] !== '$' && isPostgresIdentifierContinuation(sql[end]!)) {
+    end += 1;
+  }
+  return sql[end] === '$' ? sql.slice(offset, end + 1) : undefined;
+}
+
+function isPostgresIdentifierStart(character: string): boolean {
+  const code = character.charCodeAt(0);
+  return (
+    character === '_' ||
+    (code >= 0x41 && code <= 0x5a) ||
+    (code >= 0x61 && code <= 0x7a) ||
+    code >= 0x80
+  );
+}
+
+function isPostgresIdentifierContinuation(character: string): boolean {
+  const code = character.charCodeAt(0);
+  return (
+    isPostgresIdentifierStart(character) || character === '$' || (code >= 0x30 && code <= 0x39)
+  );
+}
+
+class ByteWriter {
+  readonly #bytes: Uint8Array;
+  #offset = 0;
+
+  constructor(length: number) {
+    this.#bytes = new Uint8Array(length);
+  }
+
+  message(tag: number, bodyLength: number): void {
+    this.u8(tag);
+    this.i32(bodyLength + 4);
+  }
+
+  u8(value: number): void {
+    this.#bytes[this.#offset] = value;
+    this.#offset += 1;
+  }
+
+  i16(value: number): void {
+    this.#bytes[this.#offset] = (value >>> 8) & 0xff;
+    this.#bytes[this.#offset + 1] = value & 0xff;
+    this.#offset += 2;
+  }
+
+  i32(value: number): void {
+    this.#bytes[this.#offset] = (value >>> 24) & 0xff;
+    this.#bytes[this.#offset + 1] = (value >>> 16) & 0xff;
+    this.#bytes[this.#offset + 2] = (value >>> 8) & 0xff;
+    this.#bytes[this.#offset + 3] = value & 0xff;
+    this.#offset += 4;
+  }
+
+  bytes(value: Uint8Array): void {
+    this.#bytes.set(value, this.#offset);
+    this.#offset += value.length;
+  }
+
+  finish(): Uint8Array {
+    if (this.#offset !== this.#bytes.length) {
+      throw new Error('extended query packet length invariant failed');
+    }
+    return this.#bytes;
+  }
+}
+
+export function toUint8Array(input: ByteInput): Uint8Array {
+  if (ArrayBuffer.isView(input)) {
+    return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
+  }
+  if (input instanceof ArrayBuffer) {
+    return new Uint8Array(input);
+  }
+  return Uint8Array.from(input);
+}
+
+function parseRowDescription(cursor: ByteCursor): QueryField[] {
+  const count = cursor.readI16('RowDescription field count');
+  if (count < 0) {
+    throw new Error(`invalid RowDescription field count ${count}`);
+  }
+  const fields: QueryField[] = [];
+  for (let index = 0; index < count; index += 1) {
+    fields.push({
+      name: cursor.readCString('field name'),
+      tableOid: cursor.readU32('field table oid'),
+      tableAttribute: cursor.readI16('field table attribute'),
+      typeOid: cursor.readU32('field type oid'),
+      typeSize: cursor.readI16('field type size'),
+      typeModifier: cursor.readI32('field type modifier'),
+      format: queryFormat(cursor.readI16('field format')),
+    });
+  }
+  return fields;
+}
+
+function parseDataRow(cursor: ByteCursor, expectedColumns: number): RawQueryRow {
+  const count = cursor.readI16('DataRow column count');
+  if (count < 0) {
+    throw new Error(`invalid DataRow column count ${count}`);
+  }
+  if (count !== expectedColumns) {
+    throw new Error(
+      `DataRow column count ${count} does not match RowDescription count ${expectedColumns}`,
+    );
+  }
+  const values = new Array(count);
+  for (let index = 0; index < count; index += 1) {
+    const length = cursor.readI32('DataRow value length');
+    if (length === -1) {
+      values[index] = null;
+    } else if (length < 0) {
+      throw new Error(`invalid DataRow value length ${length}`);
+    } else {
+      values[index] = cursor.readBytes(length, 'DataRow value');
+    }
+  }
+  return new ParsedRawQueryRow(values);
+}
+
+function parseErrorResponse(cursor: ByteCursor, notices: PostgresNotice[] = []): PostgresError {
+  return new PostgresError(parseDiagnosticFields(cursor, 'ErrorResponse'), notices);
+}
+
+function fieldValue(fields: ReadonlyArray, code: number): string | undefined {
+  return fields.find((field) => field.code === code)?.value;
+}
+
+function queryFormat(code: number): QueryFormat {
+  if (code === 0) {
+    return 'text';
+  }
+  if (code === 1) {
+    return 'binary';
+  }
+  return { code, kind: 'other' };
+}
+
+function hexBackendTag(tag: number): string {
+  return `0x${tag.toString(16).padStart(2, '0')}`;
+}
+
+function parseReadyForQuery(body: ByteCursor): TransactionStatus {
+  const remaining = body.remainingBytes();
+  if (remaining !== 1) {
+    throw new Error(`ReadyForQuery contained ${remaining} bytes, expected 1`);
+  }
+  const status = body.readU8('ReadyForQuery transaction status');
+  if (status === 0x49) return 'idle';
+  if (status === 0x54) return 'transaction';
+  if (status === 0x45) return 'failed';
+  throw new Error(`ReadyForQuery contained invalid transaction status ${hexBackendTag(status)}`);
+}
+
+function parseParameterDescription(body: ByteCursor): number[] {
+  const count = body.readI16('ParameterDescription parameter count');
+  if (count < 0) throw new Error('invalid ParameterDescription parameter count ' + count);
+  const typeOids: number[] = [];
+  for (let index = 0; index < count; index += 1) {
+    typeOids.push(body.readU32('ParameterDescription type OID'));
+  }
+  return typeOids;
+}
+
+function parseNoticeResponse(body: ByteCursor): PostgresNotice {
+  const fields = parseDiagnosticFields(body, 'NoticeResponse');
+  return {
+    severity: fieldValue(fields, 0x53) ?? fieldValue(fields, 0x56),
+    localizedSeverity: fieldValue(fields, 0x53),
+    nonlocalizedSeverity: fieldValue(fields, 0x56),
+    sqlstate: fieldValue(fields, 0x43),
+    message: fieldValue(fields, 0x4d) ?? 'PostgreSQL notice',
+    detail: fieldValue(fields, 0x44),
+    hint: fieldValue(fields, 0x48),
+    position: fieldValue(fields, 0x50),
+    internalPosition: fieldValue(fields, 0x70),
+    internalQuery: fieldValue(fields, 0x71),
+    whereText: fieldValue(fields, 0x57),
+    schemaName: fieldValue(fields, 0x73),
+    tableName: fieldValue(fields, 0x74),
+    columnName: fieldValue(fields, 0x63),
+    dataTypeName: fieldValue(fields, 0x64),
+    constraintName: fieldValue(fields, 0x6e),
+    file: fieldValue(fields, 0x46),
+    line: fieldValue(fields, 0x4c),
+    routine: fieldValue(fields, 0x52),
+    fields,
+  };
+}
+
+function parseDiagnosticFields(body: ByteCursor, label: string): PostgresErrorField[] {
+  const fields: PostgresErrorField[] = [];
+  for (;;) {
+    if (body.isAtEnd()) throw new Error(label + ' is missing terminator');
+    const code = body.readU8(label + ' field code');
+    if (code === 0) {
+      body.requireEnd(label);
+      return fields;
+    }
+    fields.push({ code, value: body.readCString(label + ' field') });
+  }
+}
+
+function validateParameterStatus(body: ByteCursor): void {
+  body.readCString('ParameterStatus name');
+  body.readCString('ParameterStatus value');
+  body.requireEnd('ParameterStatus');
+}
+
+function validateNotificationResponse(body: ByteCursor): void {
+  body.readI32('NotificationResponse process id');
+  body.readCString('NotificationResponse channel');
+  body.readCString('NotificationResponse payload');
+  body.requireEnd('NotificationResponse');
+}
+
+class ByteCursor {
+  readonly #bytes: Uint8Array;
+  #offset = 0;
+
+  constructor(bytes: Uint8Array) {
+    this.#bytes = bytes;
+  }
+
+  isAtEnd(): boolean {
+    return this.#offset === this.#bytes.length;
+  }
+
+  remainingBytes(): number {
+    return this.#bytes.length - this.#offset;
+  }
+
+  discardRemaining(): void {
+    this.#offset = this.#bytes.length;
+  }
+
+  requireEnd(label: string): void {
+    if (!this.isAtEnd()) {
+      throw new Error(`${label} contained trailing bytes`);
+    }
+  }
+
+  readU8(label: string): number {
+    this.#require(1, label);
+    const value = this.#bytes[this.#offset]!;
+    this.#offset += 1;
+    return value;
+  }
+
+  readU32(label: string): number {
+    this.#require(4, label);
+    const offset = this.#offset;
+    this.#offset += 4;
+    return (
+      (this.#bytes[offset]! * 0x1000000 +
+        (this.#bytes[offset + 1]! << 16) +
+        (this.#bytes[offset + 2]! << 8) +
+        this.#bytes[offset + 3]!) >>>
+      0
+    );
+  }
+
+  readI32(label: string): number {
+    const value = this.readU32(label);
+    return value > 0x7fffffff ? value - 0x100000000 : value;
+  }
+
+  readI16(label: string): number {
+    this.#require(2, label);
+    const value = (this.#bytes[this.#offset]! << 8) | this.#bytes[this.#offset + 1]!;
+    this.#offset += 2;
+    return value > 0x7fff ? value - 0x10000 : value;
+  }
+
+  readCString(label: string): string {
+    const end = this.#bytes.indexOf(0, this.#offset);
+    if (end < 0) {
+      throw new Error(`${label} is missing null terminator`);
+    }
+    const value = decodeUtf8Strict(this.#bytes.subarray(this.#offset, end), label);
+    this.#offset = end + 1;
+    return value;
+  }
+
+  readBytes(count: number, label: string): Uint8Array {
+    this.#require(count, label);
+    const value = this.#bytes.subarray(this.#offset, this.#offset + count);
+    this.#offset += count;
+    return value;
+  }
+
+  #require(count: number, label: string): void {
+    if (count < 0 || count > this.#bytes.length - this.#offset) {
+      throw new Error(`truncated ${label}`);
+    }
+  }
+}
+
+function validateCStringBody(bytes: Uint8Array, valueLabel: string, bodyLabel: string): void {
+  const end = bytes.indexOf(0);
+  if (end < 0) {
+    throw new Error(`${valueLabel} is missing null terminator`);
+  }
+  for (let index = 0; index < end; index += 1) {
+    if (bytes[index]! < 0x80) continue;
+    validateUtf8(bytes.subarray(0, end), valueLabel);
+    break;
+  }
+  if (end !== bytes.length - 1) {
+    throw new Error(`${bodyLabel} contained trailing bytes`);
+  }
+}
+
+function decodeUtf8Strict(bytes: Uint8Array, label: string): string {
+  try {
+    return utf8Decoder.decode(bytes);
+  } catch {
+    // Keep the precise protocol diagnostic off the valid-data hot path. The
+    // platform decoder performs the usual validation in native code; this
+    // scanner only runs after it has already rejected malformed UTF-8.
+    validateUtf8(bytes, label);
+    throw new Error(`${label} is not valid UTF-8`);
+  }
+}
+
+function validateUtf8(bytes: Uint8Array, label: string): void {
+  let index = 0;
+  while (index < bytes.length) {
+    const first = bytes[index]!;
+    if (first <= 0x7f) {
+      index += 1;
+    } else if (first >= 0xc2 && first <= 0xdf) {
+      requireContinuation(bytes, index + 1, label);
+      index += 2;
+    } else if (first === 0xe0) {
+      requireRange(bytes, index + 1, 0xa0, 0xbf, label);
+      requireContinuation(bytes, index + 2, label);
+      index += 3;
+    } else if (first >= 0xe1 && first <= 0xec) {
+      requireContinuation(bytes, index + 1, label);
+      requireContinuation(bytes, index + 2, label);
+      index += 3;
+    } else if (first === 0xed) {
+      requireRange(bytes, index + 1, 0x80, 0x9f, label);
+      requireContinuation(bytes, index + 2, label);
+      index += 3;
+    } else if (first >= 0xee && first <= 0xef) {
+      requireContinuation(bytes, index + 1, label);
+      requireContinuation(bytes, index + 2, label);
+      index += 3;
+    } else if (first === 0xf0) {
+      requireRange(bytes, index + 1, 0x90, 0xbf, label);
+      requireContinuation(bytes, index + 2, label);
+      requireContinuation(bytes, index + 3, label);
+      index += 4;
+    } else if (first >= 0xf1 && first <= 0xf3) {
+      requireContinuation(bytes, index + 1, label);
+      requireContinuation(bytes, index + 2, label);
+      requireContinuation(bytes, index + 3, label);
+      index += 4;
+    } else if (first === 0xf4) {
+      requireRange(bytes, index + 1, 0x80, 0x8f, label);
+      requireContinuation(bytes, index + 2, label);
+      requireContinuation(bytes, index + 3, label);
+      index += 4;
+    } else {
+      throw invalidUtf8(label, index);
+    }
+  }
+}
+
+function requireContinuation(bytes: Uint8Array, index: number, label: string): void {
+  requireRange(bytes, index, 0x80, 0xbf, label);
+}
+
+function requireRange(
+  bytes: Uint8Array,
+  index: number,
+  min: number,
+  max: number,
+  label: string,
+): void {
+  const byte = bytes[index];
+  if (byte === undefined || byte < min || byte > max) {
+    throw invalidUtf8(label, index);
+  }
+}
+
+function invalidUtf8(label: string, index: number): Error {
+  return new Error(`${label} is not valid UTF-8 at byte ${index}`);
+}
diff --git a/src/shared/js-core/test/protocol-fixtures.d.mts b/src/sdks/ts-query/test/protocol-fixtures.d.mts
similarity index 100%
rename from src/shared/js-core/test/protocol-fixtures.d.mts
rename to src/sdks/ts-query/test/protocol-fixtures.d.mts
diff --git a/src/sdks/ts-query/test/protocol-fixtures.mts b/src/sdks/ts-query/test/protocol-fixtures.mts
new file mode 100644
index 000000000..58cf68606
--- /dev/null
+++ b/src/sdks/ts-query/test/protocol-fixtures.mts
@@ -0,0 +1,104 @@
+import assert from 'node:assert/strict';
+import { readFileSync } from 'node:fs';
+
+export function assertSharedProtocolFixtures(options) {
+  const fixtureUrl = new URL(
+    '../../../test-fixtures/protocol/query-response-cases.json',
+    import.meta.url,
+  );
+  const corpus = JSON.parse(readFileSync(fixtureUrl, 'utf8'));
+  assert.equal(corpus.schemaVersion, 1);
+  assert.equal(corpus.kind, 'postgres-backend-query-response');
+  assert.ok(corpus.cases.length > 0, 'shared protocol corpus is empty');
+
+  const names = new Set();
+  for (const fixture of corpus.cases) {
+    assert.equal(names.has(fixture.name), false, `duplicate fixture ${fixture.name}`);
+    names.add(fixture.name);
+    const expectation = fixture.queryExpectation;
+    if (expectation === undefined) continue;
+
+    const bytes = hexToBytes(fixture.responseHex);
+    const parseQueryResponse = parserForFixture(fixture, options);
+    if (expectation.ok !== undefined) {
+      assertOk(fixture.name, expectation.ok, parseQueryResponse(bytes));
+    } else if (expectation.postgresError !== undefined) {
+      const thrown = thrownBy(() => parseQueryResponse(bytes));
+      assert.ok(options.isPostgresError(thrown), `${fixture.name} should throw PostgresError`);
+      assert.equal(thrown.severity, expectation.postgresError.severity, `${fixture.name} severity`);
+      assert.equal(thrown.sqlstate, expectation.postgresError.sqlstate, `${fixture.name} SQLSTATE`);
+      assert.equal(
+        thrown.message,
+        expectation.postgresError.message,
+        `${fixture.name} PostgreSQL message`,
+      );
+    } else if (expectation.engineErrorContains !== undefined) {
+      const thrown = thrownBy(() => parseQueryResponse(bytes));
+      assert.ok(thrown instanceof Error, `${fixture.name} should throw Error`);
+      assert.ok(
+        thrown.message.includes(expectation.engineErrorContains),
+        `${fixture.name} error ${JSON.stringify(thrown.message)} did not contain ${JSON.stringify(expectation.engineErrorContains)}`,
+      );
+    } else {
+      assert.fail(`shared protocol fixture ${fixture.name} has no query expectation`);
+    }
+  }
+}
+
+function parserForFixture(fixture, options) {
+  const modes = fixture.protocolModeExpectation;
+  return modes?.extendedQuery?.outcome === 'ok' && modes?.simpleCommand?.outcome !== 'ok'
+    ? options.parseExtendedQueryResponse
+    : options.parseSimpleQueryResponse;
+}
+
+function assertOk(name, expected, actual) {
+  assert.equal(actual.rowCount, expected.rowCount, `${name} row count`);
+  assert.equal(actual.commandTag, expected.commandTag, `${name} command tag`);
+  assert.equal(actual.fields.length, expected.fields.length, `${name} field count`);
+  assert.equal(actual.rows.length, expected.rows.length, `${name} rows size`);
+
+  for (const [index, expectedField] of expected.fields.entries()) {
+    const actualField = actual.fields[index];
+    assert.ok(actualField, `${name} missing field ${index}`);
+    assert.equal(actualField.name, expectedField.name, `${name} field name`);
+    assert.equal(actualField.typeOid, expectedField.typeOid, `${name} type OID`);
+    if (expectedField.format === 'text') {
+      assert.equal(actualField.format, 'text', `${name} field format`);
+    }
+  }
+
+  for (const [rowIndex, expectedRow] of expected.rows.entries()) {
+    assert.equal(expectedRow.length, expected.fields.length, `${name} expected row width`);
+    for (const [columnIndex, expectedValue] of expectedRow.entries()) {
+      const field = expected.fields[columnIndex];
+      assert.ok(field, `${name} missing expected field ${columnIndex}`);
+      assert.equal(
+        actual.getText(rowIndex, field.name),
+        expectedValue,
+        `${name} row ${rowIndex} column ${field.name}`,
+      );
+    }
+  }
+}
+
+function hexToBytes(hex) {
+  const compact = hex.replace(/\s+/g, '');
+  assert.equal(compact.length % 2, 0, 'hex fixture must have an even digit count');
+  const bytes = new Uint8Array(compact.length / 2);
+  for (let index = 0; index < bytes.length; index += 1) {
+    const byte = Number.parseInt(compact.slice(index * 2, index * 2 + 2), 16);
+    assert.ok(Number.isInteger(byte), 'hex fixture contains invalid byte');
+    bytes[index] = byte;
+  }
+  return bytes;
+}
+
+function thrownBy(callback) {
+  try {
+    callback();
+  } catch (error) {
+    return error;
+  }
+  assert.fail('expected callback to throw');
+}
diff --git a/src/sdks/ts-query/test/protocol.test.ts b/src/sdks/ts-query/test/protocol.test.ts
new file mode 100644
index 000000000..c28e95a1d
--- /dev/null
+++ b/src/sdks/ts-query/test/protocol.test.ts
@@ -0,0 +1,156 @@
+import { describe, expect, it } from 'bun:test';
+
+import {
+  binary,
+  extendedQuery,
+  parseSimpleQueryRawResponse,
+  postgresOids,
+  toUint8Array,
+} from '../src/query.ts';
+
+describe('query protocol codec', () => {
+  it('rejects invalid frontend inputs and respects typed-array view boundaries', () => {
+    expect(() => extendedQuery('SELECT \0', [])).toThrow(/SQL must not contain NUL/);
+    expect(() => extendedQuery('SELECT 1', new Array(0x8000).fill(null))).toThrow(
+      /at most 32767 parameters/,
+    );
+    const view = new DataView(new Uint8Array([9, 8, 7, 6]).buffer, 1, 2);
+    expect([...toUint8Array(view)]).toEqual([8, 7]);
+  });
+
+  it('writes large binary parameters without argument spreading', () => {
+    const value = new Uint8Array(256 * 1024).fill(0xab);
+    const packet = extendedQuery('SELECT $1::bytea', [binary(value, postgresOids.bytea)]);
+    const messages = frontendMessages(packet);
+
+    expect(messages.map(({ tag }) => tag)).toEqual(['P', 'B', 'D', 'E', 'S']);
+    const bind = messages[1]?.body;
+    if (bind === undefined) throw new Error('extended query omitted Bind');
+    const parameterLengthOffset = 2 + 2 + 2 + 2;
+    expect(readU32(bind, parameterLengthOffset)).toBe(value.length);
+    expect(
+      bind.subarray(parameterLengthOffset + 4, parameterLengthOffset + 4 + value.length),
+    ).toEqual(value);
+  });
+
+  it('parses integers without copies and keeps row values as response views', () => {
+    const response = queryResponse(new TextEncoder().encode('λ-value'));
+    const result = parseSimpleQueryRawResponse(response);
+
+    expect(result.fields).toEqual([
+      {
+        name: 'value',
+        tableOid: 0x01020304,
+        tableAttribute: -2,
+        typeOid: 25,
+        typeSize: -1,
+        typeModifier: -1,
+        format: 'text',
+      },
+    ]);
+    expect(result.getText(0, 'value')).toBe('λ-value');
+    expect(result.rows[0]?.values[0]?.buffer).toBe(response.buffer);
+  });
+
+  it('retains exact invalid UTF-8 field-name byte-offset diagnostics', () => {
+    const malformedDescription = concatenate(Uint8Array.of(0, 1, 0xc0, 0), new Uint8Array(18));
+
+    expect(() => parseSimpleQueryRawResponse(backendMessage('T', malformedDescription))).toThrow(
+      'field name is not valid UTF-8 at byte 0',
+    );
+  });
+
+  it('retains exact invalid UTF-8 row-value byte-offset diagnostics', () => {
+    const result = parseSimpleQueryRawResponse(
+      queryResponse(Uint8Array.of(0x61, 0xe2, 0x28, 0xa1)),
+    );
+
+    expect(() => result.rows[0]?.text(0)).toThrow('query value is not valid UTF-8 at byte 2');
+  });
+
+  it('retains truncated integer and body diagnostics', () => {
+    expect(() => parseSimpleQueryRawResponse(Uint8Array.of(0x54, 0, 0))).toThrow(
+      'truncated backend message length',
+    );
+    expect(() => parseSimpleQueryRawResponse(Uint8Array.of(0x54, 0, 0, 0, 6, 0))).toThrow(
+      'truncated backend message body',
+    );
+  });
+});
+
+function frontendMessages(packet: Uint8Array): Array<{ tag: string; body: Uint8Array }> {
+  const messages: Array<{ tag: string; body: Uint8Array }> = [];
+  let offset = 0;
+  while (offset < packet.length) {
+    const length = readU32(packet, offset + 1);
+    messages.push({
+      tag: String.fromCharCode(packet[offset] ?? 0),
+      body: packet.subarray(offset + 5, offset + 1 + length),
+    });
+    offset += length + 1;
+  }
+  return messages;
+}
+
+function queryResponse(value: Uint8Array): Uint8Array {
+  const fieldName = new TextEncoder().encode('value');
+  const rowDescription = new Uint8Array(2 + fieldName.length + 1 + 4 + 2 + 4 + 2 + 4 + 2);
+  const rowView = new DataView(
+    rowDescription.buffer,
+    rowDescription.byteOffset,
+    rowDescription.byteLength,
+  );
+  let offset = 0;
+  rowView.setInt16(offset, 1);
+  offset += 2;
+  rowDescription.set(fieldName, offset);
+  offset += fieldName.length;
+  rowDescription[offset] = 0;
+  offset += 1;
+  rowView.setUint32(offset, 0x01020304);
+  offset += 4;
+  rowView.setInt16(offset, -2);
+  offset += 2;
+  rowView.setUint32(offset, 25);
+  offset += 4;
+  rowView.setInt16(offset, -1);
+  offset += 2;
+  rowView.setInt32(offset, -1);
+  offset += 4;
+  rowView.setInt16(offset, 0);
+
+  const dataRow = new Uint8Array(2 + 4 + value.length);
+  const dataView = new DataView(dataRow.buffer, dataRow.byteOffset, dataRow.byteLength);
+  dataView.setInt16(0, 1);
+  dataView.setInt32(2, value.length);
+  dataRow.set(value, 6);
+
+  return concatenate(
+    backendMessage('T', rowDescription),
+    backendMessage('D', dataRow),
+    backendMessage('C', new TextEncoder().encode('SELECT 1\0')),
+    backendMessage('Z', Uint8Array.of('I'.charCodeAt(0))),
+  );
+}
+
+function backendMessage(tag: string, body: Uint8Array): Uint8Array {
+  const message = new Uint8Array(body.length + 5);
+  message[0] = tag.charCodeAt(0);
+  new DataView(message.buffer).setUint32(1, body.length + 4);
+  message.set(body, 5);
+  return message;
+}
+
+function readU32(bytes: Uint8Array, offset: number): number {
+  return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(offset);
+}
+
+function concatenate(...parts: Uint8Array[]): Uint8Array {
+  const result = new Uint8Array(parts.reduce((length, part) => length + part.length, 0));
+  let offset = 0;
+  for (const part of parts) {
+    result.set(part, offset);
+    offset += part.length;
+  }
+  return result;
+}
diff --git a/src/sdks/ts-query/test/query.test.ts b/src/sdks/ts-query/test/query.test.ts
new file mode 100644
index 000000000..99b592403
--- /dev/null
+++ b/src/sdks/ts-query/test/query.test.ts
@@ -0,0 +1,1103 @@
+import assert from 'node:assert/strict';
+import { Buffer } from 'node:buffer';
+import { readFileSync } from 'node:fs';
+import { test } from 'bun:test';
+
+import {
+  PostgresError,
+  array,
+  binary,
+  containsTopLevelCopy,
+  containsTransactionChain,
+  decodeQueryResult,
+  describeQuery,
+  inspectManagedTransactionResponse,
+  inspectReadyForQuery,
+  json,
+  parseDescribeResponse,
+  parseExecResponse,
+  parseQueryRawResponse,
+  parseSimpleQueryRawResponse,
+  planQuery,
+  postgresOids,
+  responseTransactionStatus,
+  text,
+  typedNull,
+} from '../src/query.ts';
+import { assertSharedProtocolFixtures } from './protocol-fixtures.mts';
+
+test('protocol fixtures', () => {
+  assertSharedProtocolFixtures({
+    parseSimpleQueryResponse: parseSimpleQueryRawResponse,
+    parseExtendedQueryResponse: parseQueryRawResponse,
+    isPostgresError: (error): error is PostgresError => error instanceof PostgresError,
+  });
+});
+
+test('parameter plans infer OIDs without exposing mutable values across the await', () => {
+  const value = { stable: 1 };
+  const plan = planQuery('SELECT $1::jsonb', [value]);
+  assert.equal(plan.kind, 'describe');
+  value.stable = 2;
+  if (plan.kind !== 'describe') throw new Error('expected describe plan');
+  const bind = frontendMessages(plan.bind([postgresOids.jsonb]));
+  assert.deepEqual(
+    bind.map((message) => message.tag),
+    ['P', 'B', 'D', 'E', 'S'],
+  );
+  assert.match(new TextDecoder().decode(bind[1]!.body), /"stable":1/);
+
+  assert.throws(() => plan.bind([postgresOids.text]), /cannot safely encode object/);
+  assert.throws(() => planQuery('SELECT $1', [undefined as never]), /must not be undefined/);
+});
+
+test('deferred binding owns Buffer views with offsets', () => {
+  const bytes = Buffer.from([0, 1, 2, 3]);
+  const plan = planQuery('SELECT $1, $2', [bytes.subarray(1, 3), 'text']);
+  assert.equal(plan.kind, 'describe');
+  if (plan.kind !== 'describe') throw new Error('expected describe plan');
+  const expected = plan.bind([postgresOids.bytea, postgresOids.text]);
+  bytes.fill(9);
+  assert.deepEqual(plan.bind([postgresOids.bytea, postgresOids.text]), expected);
+});
+
+test('typed helpers make a one-exchange OID-aware plan', () => {
+  const plan = planQuery('SELECT $1, $2, $3, $4, $5', [
+    json({ ok: true }),
+    array([1, null, 2], postgresOids.int4Array),
+    text('550e8400-e29b-41d4-a716-446655440000', postgresOids.uuid),
+    binary(Uint8Array.of(0, 255), postgresOids.bytea),
+    typedNull(postgresOids.int8),
+  ]);
+  assert.equal(plan.kind, 'complete');
+  if (plan.kind !== 'complete') throw new Error('expected complete plan');
+  const messages = frontendMessages(plan.input);
+  assert.deepEqual(
+    messages.map((message) => message.tag),
+    ['P', 'B', 'D', 'E', 'S'],
+  );
+  assert.deepEqual(readParseTypeOids(messages[0]!.body), [
+    postgresOids.jsonb,
+    postgresOids.int4Array,
+    postgresOids.uuid,
+    postgresOids.bytea,
+    postgresOids.int8,
+  ]);
+  assert.equal(Object.isFrozen(postgresOids), true);
+});
+
+test('sparse parameter and PostgreSQL arrays reject their undefined holes', () => {
+  assert.throws(() => planQuery('SELECT $1', Array(1)), /query parameters must not be undefined/);
+  assert.throws(
+    () => array(Array(1), postgresOids.textArray),
+    /PostgreSQL arrays cannot contain undefined/,
+  );
+  assert.throws(() => planQuery('SELECT $1', [Array(1)]), /query parameters must not be undefined/);
+});
+
+test('array helpers reject explicit element OID mismatches', () => {
+  for (const value of [
+    text('1', postgresOids.int4),
+    typedNull(postgresOids.int4),
+    binary(Uint8Array.of(1), postgresOids.bytea),
+  ]) {
+    assert.throws(
+      () => array([value], postgresOids.textArray),
+      /array element declares PostgreSQL OID .* resolves element OID/,
+    );
+  }
+
+  assert.equal(array([text('raw')], postgresOids.textArray).value, '{"raw"}');
+  assert.equal(array([binary(Uint8Array.of(0xff))], postgresOids.byteaArray).value, '{"\\\\xff"}');
+});
+
+test('decoded rows reject ambiguous object fields and preserve them in array mode', () => {
+  const response = queryResponse(
+    [
+      field('__proto__', postgresOids.text),
+      field('constructor', postgresOids.int4),
+      field('constructor', postgresOids.int8),
+      field('payload', postgresOids.jsonb),
+      field('bytes', postgresOids.bytea),
+      field('dates', postgresOids.dateArray),
+    ],
+    [['safe', '7', '9007199254740993', '{"ok":true}', '\\x00ff', '{2026-01-01,NULL}']],
+    'SELECT 1',
+  );
+  const raw = parseQueryRawResponse(response);
+  assert.throws(() => raw.getText(0, 'constructor'), /more than one column/);
+  assert.throws(
+    () => decodeQueryResult(raw),
+    /cannot represent more than one column named "constructor"; use \{ rowMode: 'array' \}/,
+  );
+
+  const custom = decodeQueryResult(raw, {
+    rowMode: 'array',
+    valueMode: 'text',
+    decoders: { [postgresOids.int4]: (value) => 'int:' + value },
+  });
+  assert.deepEqual(custom.rows[0], [
+    'safe',
+    'int:7',
+    '9007199254740993',
+    '{"ok":true}',
+    '\\x00ff',
+    '{2026-01-01,NULL}',
+  ]);
+});
+
+test('decoded object rows remain prototype safe when field names are unique', () => {
+  const decoded = decodeQueryResult(
+    parseQueryRawResponse(
+      queryResponse(
+        [field('__proto__', postgresOids.text), field('constructor', postgresOids.int4)],
+        [['safe', '7']],
+        'SELECT 1',
+      ),
+    ),
+  );
+  const row = decoded.rows[0]!;
+  assert.equal(Object.prototype.hasOwnProperty.call(row, '__proto__'), true);
+  assert.equal(row.__proto__, 'safe');
+  assert.equal(row.constructor, 7);
+});
+
+test('decoded floating-point scalars and arrays preserve PostgreSQL non-finite values', () => {
+  const decoded = decodeQueryResult(
+    parseQueryRawResponse(
+      queryResponse(
+        [
+          field('nan', postgresOids.float4),
+          field('positive', postgresOids.float8),
+          field('negative', postgresOids.float8),
+          field('values', postgresOids.float8Array),
+        ],
+        [['NaN', 'Infinity', '-Infinity', '{NaN,Infinity,-Infinity,NULL}']],
+        'SELECT 1',
+      ),
+    ),
+  );
+
+  const row = decoded.rows[0]!;
+  assert.equal(Number.isNaN(row.nan), true);
+  assert.equal(row.positive, Number.POSITIVE_INFINITY);
+  assert.equal(row.negative, Number.NEGATIVE_INFINITY);
+  const values = row.values as unknown[];
+  assert.equal(Number.isNaN(values[0]), true);
+  assert.deepEqual(values.slice(1), [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, null]);
+});
+
+test('built-in ORM OIDs and text-fallback arrays stay portable', () => {
+  assert.deepEqual(
+    {
+      char: postgresOids.char,
+      name: postgresOids.name,
+      xml: postgresOids.xml,
+      unknown: postgresOids.unknown,
+      bpchar: postgresOids.bpchar,
+      charArray: postgresOids.charArray,
+      nameArray: postgresOids.nameArray,
+      bpcharArray: postgresOids.bpcharArray,
+      xmlArray: postgresOids.xmlArray,
+    },
+    {
+      char: 18,
+      name: 19,
+      xml: 142,
+      unknown: 705,
+      bpchar: 1042,
+      charArray: 1002,
+      nameArray: 1003,
+      bpcharArray: 1014,
+      xmlArray: 143,
+    },
+  );
+
+  const decoded = decodeQueryResult(
+    parseQueryRawResponse(
+      queryResponse(
+        [
+          field('chars', postgresOids.charArray),
+          field('names', postgresOids.nameArray),
+          field('fixed', postgresOids.bpcharArray),
+          field('xml', postgresOids.xmlArray),
+          field('literal', postgresOids.unknown),
+        ],
+        [['{a,b}', '{one,two}', '{fixed,padded}', '{,}', 'value']],
+        'SELECT 1',
+      ),
+    ),
+  );
+  assert.deepEqual(decoded.rows, [
+    {
+      chars: ['a', 'b'],
+      names: ['one', 'two'],
+      fixed: ['fixed', 'padded'],
+      xml: ['', ''],
+      literal: 'value',
+    },
+  ]);
+  assert.equal(array(['a'], postgresOids.charArray).typeOid, postgresOids.charArray);
+});
+
+test('exec attributes notices to each statement and retains aggregate operation notices', () => {
+  const response = backendResponse([
+    [0x4e, diagnostic('NOTICE', '00000', 'before create')],
+    [0x43, cstring('CREATE TABLE')],
+    [0x49, []],
+    [0x4e, diagnostic('NOTICE', '00000', 'before select')],
+    [0x54, rowDescription([field('value', postgresOids.int4)])],
+    [0x44, dataRow(['42'])],
+    [0x43, cstring('SELECT 1')],
+    [0x4e, diagnostic('NOTICE', '00000', 'after statements')],
+    [0x5a, [0x49]],
+  ]);
+  const result = parseExecResponse(response);
+  assert.equal(result.statements.length, 2);
+  assert.equal(result.statements[0]!.kind, 'command');
+  assert.equal(result.statements[1]!.kind, 'rows');
+  assert.deepEqual(result.statements[1]!.rows, [{ value: 42 }]);
+  assert.deepEqual(
+    result.statements.map((statement) => statement.notices.map((notice) => notice.message)),
+    [['before create'], ['before select']],
+  );
+  assert.deepEqual(
+    result.notices.map((notice) => notice.message),
+    ['before create', 'before select', 'after statements'],
+  );
+});
+
+test('exec validates the complete response before decoding and snapshots options once', () => {
+  const validResponse = backendResponse([
+    [0x54, rowDescription([field('value', postgresOids.int4)])],
+    [0x44, dataRow(['1'])],
+    [0x43, cstring('SELECT 1')],
+    [0x54, rowDescription([field('value', postgresOids.int4)])],
+    [0x44, dataRow(['2'])],
+    [0x43, cstring('SELECT 1')],
+    [0x5a, [0x49]],
+  ]);
+  let optionReads = 0;
+  let decoderCalls = 0;
+  const result = parseExecResponse(validResponse, {
+    get decoders() {
+      optionReads += 1;
+      return {
+        [postgresOids.int4]: (value: string) => {
+          decoderCalls += 1;
+          return Number(value);
+        },
+      };
+    },
+  });
+  assert.equal(optionReads, 1);
+  assert.equal(decoderCalls, 2);
+  assert.deepEqual(
+    result.statements.map((statement) => statement.rows),
+    [[{ value: 1 }], [{ value: 2 }]],
+  );
+
+  let emptyOptionReads = 0;
+  const empty = parseExecResponse(
+    backendResponse([
+      [0x49, []],
+      [0x5a, [0x49]],
+    ]),
+    {
+      get decoders() {
+        emptyOptionReads += 1;
+        return undefined;
+      },
+    },
+  );
+  assert.equal(empty.statements.length, 0);
+  assert.equal(emptyOptionReads, 0);
+
+  decoderCalls = 0;
+  assert.throws(
+    () =>
+      parseExecResponse(
+        backendResponse([
+          [0x54, rowDescription([field('value', postgresOids.int4)])],
+          [0x44, dataRow(['1'])],
+          [0x43, cstring('SELECT 1')],
+          [0x31, []],
+          [0x5a, [0x49]],
+        ]),
+        {
+          decoders: {
+            [postgresOids.int4]: (value) => {
+              decoderCalls += 1;
+              return Number(value);
+            },
+          },
+        },
+      ),
+    /simple-query response contained ParseComplete/,
+  );
+  assert.equal(decoderCalls, 0);
+});
+
+test('exec decoder failures stop later decoding but retain all operation notices', () => {
+  let decoderCalls = 0;
+  const failure = thrownBy(() =>
+    parseExecResponse(
+      backendResponse([
+        [0x4e, diagnostic('NOTICE', '00000', 'before first')],
+        [0x54, rowDescription([field('value', postgresOids.int4)])],
+        [0x44, dataRow(['1'])],
+        [0x43, cstring('SELECT 1')],
+        [0x4e, diagnostic('NOTICE', '00000', 'before second')],
+        [0x54, rowDescription([field('value', postgresOids.int4)])],
+        [0x44, dataRow(['2'])],
+        [0x43, cstring('SELECT 1')],
+        [0x4e, diagnostic('NOTICE', '00000', 'after statements')],
+        [0x5a, [0x49]],
+      ]),
+      {
+        decoders: {
+          [postgresOids.int4]: () => {
+            decoderCalls += 1;
+            throw new Error('decoder stopped');
+          },
+        },
+      },
+    ),
+  );
+  assert.equal(decoderCalls, 1);
+  assert.deepEqual(
+    (failure as Error & { notices: Array<{ message: string }> }).notices.map(
+      (notice) => notice.message,
+    ),
+    ['before first', 'before second', 'after statements'],
+  );
+  assert.equal(responseTransactionStatus(failure as object), 'idle');
+});
+
+test('exec extracts row counts without narrowing backend whitespace semantics', () => {
+  const commandTags = [
+    'SELECT 42',
+    ' INSERT 0 7 ',
+    '\u00a0UPDATE\t0003\u3000',
+    'FETCH FORWARD 9',
+    'COPY 10',
+    'CREATE TABLE',
+    'SELECT 9007199254740992',
+    'SELECT +1',
+    'SELECT',
+  ];
+  const result = parseExecResponse(
+    backendResponse([...commandTags.map((tag) => [0x43, cstring(tag)] as const), [0x5a, [0x49]]]),
+  );
+  assert.deepEqual(
+    result.statements.map((statement) => statement.rowCount),
+    [42, 7, 3, 9, 10, null, null, null, null],
+  );
+});
+
+test('describe is structured and errors drain through ReadyForQuery with notices', () => {
+  const described = parseDescribeResponse(
+    backendResponse([
+      [0x31, []],
+      [0x74, [...i16(1), ...i32(postgresOids.jsonb)]],
+      [0x54, rowDescription([field('payload', postgresOids.jsonb)])],
+      [0x5a, [0x49]],
+    ]),
+  );
+  assert.deepEqual(described.parameterTypeOids, [postgresOids.jsonb]);
+  assert.equal(described.fields?.[0]?.name, 'payload');
+  assert.deepEqual(
+    frontendMessages(describeQuery('SELECT $1', [0])).map((message) => message.tag),
+    ['P', 'D', 'S'],
+  );
+
+  const failure = thrownBy(() =>
+    parseQueryRawResponse(
+      backendResponse([
+        [0x4e, diagnostic('NOTICE', '00000', 'before error')],
+        [0x45, diagnostic('ERROR', '22023', 'bad value')],
+        [0x53, [...cstring('application_name'), ...cstring('test')]],
+        [0x5a, [0x45]],
+      ]),
+    ),
+  );
+  assert.ok(failure instanceof PostgresError);
+  assert.equal(failure.notices[0]!.message, 'before error');
+  assert.equal(responseTransactionStatus(failure), 'failed');
+  assert.equal(failure.sqlstate, '22023');
+  assert.equal(failure.message, 'bad value');
+});
+
+test('diagnostics promote standard PostgreSQL fields and preserve unknown fields', () => {
+  const noticeFields: Array = [
+    [0x53, 'AVERTISSEMENT'],
+    [0x56, 'WARNING'],
+    [0x43, '01000'],
+    [0x4d, 'notice message'],
+    [0x70, '3'],
+    [0x71, 'SELECT notice'],
+    [0x57, 'PL/pgSQL function notice_fn() line 1'],
+    [0x46, 'pl_exec.c'],
+    [0x4c, '100'],
+    [0x52, 'exec_stmt_raise'],
+  ];
+  const errorFields: Array = [
+    [0x53, 'ERREUR'],
+    [0x56, 'ERROR'],
+    [0x43, 'XX000'],
+    [0x4d, 'error message'],
+    [0x70, '7'],
+    [0x71, 'SELECT broken'],
+    [0x57, 'PL/pgSQL function broken_fn() line 2'],
+    [0x46, 'postgres.c'],
+    [0x4c, '200'],
+    [0x52, 'exec_simple_query'],
+    [0x58, 'future diagnostic'],
+  ];
+
+  const failure = thrownBy(() =>
+    parseQueryRawResponse(
+      backendResponse([
+        [0x4e, diagnosticFields(noticeFields)],
+        [0x45, diagnosticFields(errorFields)],
+        [0x5a, [0x49]],
+      ]),
+    ),
+  );
+  assert.ok(failure instanceof PostgresError);
+  assert.deepEqual(
+    {
+      severity: failure.severity,
+      localizedSeverity: failure.localizedSeverity,
+      nonlocalizedSeverity: failure.nonlocalizedSeverity,
+      internalPosition: failure.internalPosition,
+      internalQuery: failure.internalQuery,
+      whereText: failure.whereText,
+      file: failure.file,
+      line: failure.line,
+      routine: failure.routine,
+    },
+    {
+      severity: 'ERREUR',
+      localizedSeverity: 'ERREUR',
+      nonlocalizedSeverity: 'ERROR',
+      internalPosition: '7',
+      internalQuery: 'SELECT broken',
+      whereText: 'PL/pgSQL function broken_fn() line 2',
+      file: 'postgres.c',
+      line: '200',
+      routine: 'exec_simple_query',
+    },
+  );
+  assert.deepEqual(failure.fields.at(-1), {
+    code: 0x58,
+    value: 'future diagnostic',
+  });
+
+  const notice = failure.notices[0]!;
+  assert.deepEqual(
+    {
+      severity: notice.severity,
+      localizedSeverity: notice.localizedSeverity,
+      nonlocalizedSeverity: notice.nonlocalizedSeverity,
+      internalPosition: notice.internalPosition,
+      internalQuery: notice.internalQuery,
+      whereText: notice.whereText,
+      file: notice.file,
+      line: notice.line,
+      routine: notice.routine,
+    },
+    {
+      severity: 'AVERTISSEMENT',
+      localizedSeverity: 'AVERTISSEMENT',
+      nonlocalizedSeverity: 'WARNING',
+      internalPosition: '3',
+      internalQuery: 'SELECT notice',
+      whereText: 'PL/pgSQL function notice_fn() line 1',
+      file: 'pl_exec.c',
+      line: '100',
+      routine: 'exec_stmt_raise',
+    },
+  );
+});
+
+test('custom decoder failures retain query notices and normalize unattachable throws', () => {
+  const queryRaw = parseQueryRawResponse(
+    backendResponse([
+      [0x31, []],
+      [0x32, []],
+      [0x54, rowDescription([field('value', postgresOids.int4)])],
+      [0x4e, diagnostic('NOTICE', '00000', 'query notice')],
+      [0x44, dataRow(['42'])],
+      [0x43, cstring('SELECT 1')],
+      [0x5a, [0x49]],
+    ]),
+  );
+  const extensible = new Error('extensible decoder failure');
+  const queryFailure = thrownBy(() =>
+    decodeQueryResult(queryRaw, {
+      decoders: {
+        [postgresOids.int4]: () => {
+          throw extensible;
+        },
+      },
+    }),
+  );
+  assert.equal(queryFailure, extensible);
+  assert.deepEqual(
+    (queryFailure as { notices: Array<{ message: string }> }).notices.map(
+      (notice) => notice.message,
+    ),
+    ['query notice'],
+  );
+  assert.equal(responseTransactionStatus(queryFailure as object), 'idle');
+
+  const frozen = Object.freeze(new Error('frozen decoder failure'));
+  const execFailure = thrownBy(() =>
+    parseExecResponse(
+      backendResponse([
+        [0x54, rowDescription([field('value', postgresOids.int4)])],
+        [0x4e, diagnostic('NOTICE', '00000', 'exec notice')],
+        [0x44, dataRow(['42'])],
+        [0x43, cstring('SELECT 1')],
+        [0x5a, [0x49]],
+      ]),
+      {
+        decoders: {
+          [postgresOids.int4]: () => {
+            throw frozen;
+          },
+        },
+      },
+    ),
+  );
+  assert.ok(execFailure instanceof Error);
+  assert.notEqual(execFailure, frozen);
+  assert.equal(execFailure.cause, frozen);
+  assert.deepEqual(
+    (execFailure as Error & { notices: Array<{ message: string }> }).notices.map(
+      (notice) => notice.message,
+    ),
+    ['exec notice'],
+  );
+  assert.equal(responseTransactionStatus(execFailure), 'idle');
+
+  const primitiveFailure = thrownBy(() =>
+    decodeQueryResult(queryRaw, {
+      decoders: {
+        [postgresOids.int4]: () => {
+          throw 'primitive decoder failure';
+        },
+      },
+    }),
+  );
+  assert.ok(primitiveFailure instanceof Error);
+  assert.equal(primitiveFailure.message, 'primitive decoder failure');
+  assert.equal(primitiveFailure.cause, 'primitive decoder failure');
+  assert.deepEqual(
+    (primitiveFailure as Error & { notices: Array<{ message: string }> }).notices.map(
+      (notice) => notice.message,
+    ),
+    ['query notice'],
+  );
+
+  const frozenWithoutNotices = Object.freeze(new Error('frozen failure without notices'));
+  const noNoticeRaw = parseQueryRawResponse(
+    queryResponse([field('value', postgresOids.int4)], [['42']], 'SELECT 1'),
+  );
+  const noNoticeFailure = thrownBy(() =>
+    decodeQueryResult(noNoticeRaw, {
+      decoders: {
+        [postgresOids.int4]: () => {
+          throw frozenWithoutNotices;
+        },
+      },
+    }),
+  );
+  assert.equal(noNoticeFailure, frozenWithoutNotices);
+
+  const primitiveWithoutNotices = thrownBy(() =>
+    decodeQueryResult(noNoticeRaw, {
+      decoders: {
+        [postgresOids.int4]: () => {
+          throw 'primitive failure without notices';
+        },
+      },
+    }),
+  );
+  assert.ok(primitiveWithoutNotices instanceof Error);
+  assert.equal(primitiveWithoutNotices.cause, 'primitive failure without notices');
+  assert.equal(responseTransactionStatus(primitiveWithoutNotices), 'idle');
+});
+
+test('readiness inspection is decode-independent and malformed errors stay protocol errors', () => {
+  assert.equal(inspectReadyForQuery(backendResponse([[0x5a, [0x54]]])), 'transaction');
+  assert.throws(
+    () =>
+      inspectReadyForQuery(
+        backendResponse([
+          [0x5a, [0x49]],
+          [0x49, []],
+        ]),
+      ),
+    /bytes after ReadyForQuery/,
+  );
+  assert.throws(
+    () => inspectReadyForQuery(backendResponse([[0x43, cstring('SELECT 0')]])),
+    /before ReadyForQuery/,
+  );
+  assert.equal(
+    inspectReadyForQuery(
+      backendResponse([
+        [0x43, cstring('SÉLECT 0')],
+        [0x5a, [0x49]],
+      ]),
+    ),
+    'idle',
+  );
+  assert.throws(
+    () =>
+      inspectReadyForQuery(
+        backendResponse([
+          [0x43, [0xc0, 0]],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /CommandComplete tag is not valid UTF-8/,
+  );
+  assert.throws(
+    () =>
+      inspectReadyForQuery(
+        backendResponse([
+          [0x43, [0x53]],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /CommandComplete tag is missing null terminator/,
+  );
+  assert.throws(
+    () =>
+      inspectReadyForQuery(
+        backendResponse([
+          [0x43, [...cstring('SELECT 0'), 0x53]],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /CommandComplete contained trailing bytes/,
+  );
+  assert.throws(
+    () =>
+      inspectReadyForQuery(
+        backendResponse([
+          [0x43, [0xc0, 0, 0x53]],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /CommandComplete tag is not valid UTF-8/,
+  );
+
+  const malformed = thrownBy(() =>
+    parseQueryRawResponse(
+      backendResponse([
+        [0x45, [0x4d, 0xc0, 0, 0]],
+        [0x5a, [0x49]],
+      ]),
+    ),
+  );
+  assert.ok(malformed instanceof Error);
+  assert.equal(malformed instanceof PostgresError, false);
+  assert.match(malformed.message, /ErrorResponse field is not valid UTF-8/);
+  assert.equal(responseTransactionStatus(malformed), 'idle');
+});
+
+test('managed transaction inspection uses every protocol tag and final readiness boundary', () => {
+  for (const tag of [
+    'BEGIN',
+    'START TRANSACTION',
+    'COMMIT',
+    'PREPARE TRANSACTION',
+    'COMMIT PREPARED',
+    'ROLLBACK PREPARED',
+  ]) {
+    assert.throws(
+      () =>
+        inspectManagedTransactionResponse(
+          backendResponse([
+            [0x43, cstring(tag)],
+            [0x5a, [0x54]],
+          ]),
+        ),
+      /violated callback transaction ownership/,
+      tag,
+    );
+  }
+
+  assert.throws(
+    () =>
+      inspectManagedTransactionResponse(
+        backendResponse([
+          [0x43, cstring('COMMIT')],
+          [0x43, cstring('BEGIN')],
+          [0x45, diagnostic('ERROR', 'XX000', 'later failure')],
+          [0x5a, [0x54]],
+        ]),
+      ),
+    /command tag COMMIT/,
+  );
+  assert.throws(
+    () =>
+      inspectManagedTransactionResponse(
+        backendResponse([
+          [0x43, cstring('ROLLBACK')],
+          [0x43, cstring('BEGIN')],
+          [0x5a, [0x54]],
+        ]),
+      ),
+    /command tag BEGIN/,
+  );
+  assert.throws(
+    () =>
+      inspectManagedTransactionResponse(
+        backendResponse([
+          [0x43, cstring('ROLLBACK')],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /ended PostgreSQL transaction ownership/,
+  );
+
+  for (const [tag, status] of [
+    ['ROLLBACK', 0x54],
+    ['ROLLBACK', 0x45],
+    ['SAVEPOINT', 0x54],
+    ['RELEASE', 0x54],
+    ['SET', 0x54],
+    ['PREPARE', 0x54],
+    ['CREATE FUNCTION', 0x54],
+    ['CALL', 0x54],
+    ['DO', 0x54],
+  ] as const) {
+    assert.equal(
+      inspectManagedTransactionResponse(
+        backendResponse([
+          [0x43, cstring(tag)],
+          [0x5a, [status]],
+        ]),
+      ),
+      status === 0x45 ? 'failed' : 'transaction',
+      tag,
+    );
+  }
+});
+
+test('structured parsers require exact completion and reject post-completion rows', () => {
+  const readyOnly = backendResponse([[0x5a, [0x49]]]);
+  assert.throws(
+    () => parseQueryRawResponse(readyOnly),
+    /omitted CommandComplete or EmptyQueryResponse/,
+  );
+  assert.throws(
+    () => parseExecResponse(readyOnly),
+    /omitted CommandComplete or EmptyQueryResponse/,
+  );
+  assert.throws(
+    () =>
+      parseQueryRawResponse(
+        backendResponse([
+          [0x43, cstring('UPDATE 1')],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /before the extended-query result description/,
+  );
+  assert.throws(
+    () =>
+      parseQueryRawResponse(
+        backendResponse([
+          [0x49, []],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /before the extended-query result description/,
+  );
+
+  assert.throws(
+    () =>
+      parseQueryRawResponse(
+        backendResponse([
+          [0x31, []],
+          [0x32, []],
+          [0x6e, []],
+          [0x43, cstring('UPDATE 1')],
+          [0x43, cstring('UPDATE 1')],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /multiple result completions/,
+  );
+  assert.throws(
+    () =>
+      parseQueryRawResponse(
+        backendResponse([
+          [0x31, []],
+          [0x32, []],
+          [0x6e, []],
+          [0x43, cstring('SELECT 1')],
+          [0x44, dataRow(['late'])],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /DataRow arrived after statement completion/,
+  );
+
+  const empty = parseQueryRawResponse(
+    backendResponse([
+      [0x31, []],
+      [0x32, []],
+      [0x6e, []],
+      [0x49, []],
+      [0x5a, [0x49]],
+    ]),
+  );
+  assert.equal(empty.kind, 'command');
+  assert.equal(empty.commandTag, undefined);
+
+  const multi = parseExecResponse(
+    backendResponse([
+      [0x43, cstring('UPDATE 1')],
+      [0x49, []],
+      [0x43, cstring('DELETE 2')],
+      [0x5a, [0x49]],
+    ]),
+  );
+  assert.deepEqual(
+    multi.statements.map((statement) => statement.commandTag),
+    ['UPDATE 1', 'DELETE 2'],
+  );
+
+  assert.throws(
+    () =>
+      parseDescribeResponse(
+        backendResponse([
+          [0x74, [...i16(0)]],
+          [0x6e, []],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /before ParseComplete|omitted ParseComplete/,
+  );
+  assert.throws(
+    () =>
+      parseDescribeResponse(
+        backendResponse([
+          [0x31, []],
+          [0x74, [...i16(0)]],
+          [0x6e, []],
+          [0x45, diagnostic('ERROR', 'XX000', 'late describe error')],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /ErrorResponse arrived after describe completion/,
+  );
+
+  assert.throws(
+    () =>
+      parseQueryRawResponse(
+        backendResponse([
+          [0x32, []],
+          [0x6e, []],
+          [0x43, cstring('UPDATE 1')],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /BindComplete arrived before ParseComplete/,
+  );
+  assert.throws(
+    () =>
+      parseQueryRawResponse(
+        backendResponse([
+          [0x31, []],
+          [0x32, []],
+          [0x6e, []],
+          [0x43, cstring('UPDATE 1')],
+          [0x33, []],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /unsolicited CloseComplete/,
+  );
+  assert.throws(
+    () =>
+      parseExecResponse(
+        backendResponse([
+          [0x31, []],
+          [0x43, cstring('UPDATE 1')],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /simple-query response contained ParseComplete/,
+  );
+  assert.throws(
+    () =>
+      parseQueryRawResponse(
+        backendResponse([
+          [0x31, []],
+          [0x32, []],
+          [0x6e, []],
+          [0x43, cstring('UPDATE 1')],
+          [0x45, diagnostic('ERROR', 'XX000', 'late error')],
+          [0x5a, [0x49]],
+        ]),
+      ),
+    /ErrorResponse arrived after statement completion/,
+  );
+});
+
+test('structured SQL scanners match the shared lexical corpus', () => {
+  const fixture = JSON.parse(
+    readFileSync(
+      new URL('../../../test-fixtures/protocol/structured-sql-cases.json', import.meta.url),
+      'utf8',
+    ),
+  ) as {
+    schemaVersion: number;
+    cases: Array<{
+      name: string;
+      sql: string;
+      containsTopLevelCopy: boolean;
+      containsTransactionChain: boolean;
+    }>;
+  };
+  assert.equal(fixture.schemaVersion, 2);
+  for (const entry of fixture.cases) {
+    assert.equal(containsTopLevelCopy(entry.sql), entry.containsTopLevelCopy, entry.name);
+    assert.equal(containsTransactionChain(entry.sql), entry.containsTransactionChain, entry.name);
+  }
+});
+
+type FieldInput = { name: string; typeOid: number };
+
+function field(name: string, typeOid: number): FieldInput {
+  return { name, typeOid };
+}
+
+function queryResponse(fields: FieldInput[], rows: string[][], commandTag: string): Uint8Array {
+  return backendResponse([
+    [0x31, []],
+    [0x32, []],
+    [0x54, rowDescription(fields)],
+    ...rows.map((row) => [0x44, dataRow(row)] as const),
+    [0x43, cstring(commandTag)],
+    [0x5a, [0x49]],
+  ]);
+}
+
+function rowDescription(fields: FieldInput[]): number[] {
+  return [
+    ...i16(fields.length),
+    ...fields.flatMap((entry) => [
+      ...cstring(entry.name),
+      ...i32(0),
+      ...i16(0),
+      ...i32(entry.typeOid),
+      ...i16(-1),
+      ...i32(-1),
+      ...i16(0),
+    ]),
+  ];
+}
+
+function dataRow(values: string[]): number[] {
+  return [
+    ...i16(values.length),
+    ...values.flatMap((value) => {
+      const bytes = new TextEncoder().encode(value);
+      return [...i32(bytes.length), ...bytes];
+    }),
+  ];
+}
+
+function diagnostic(severity: string, sqlstate: string, message: string): number[] {
+  return diagnosticFields([
+    [0x53, severity],
+    [0x43, sqlstate],
+    [0x4d, message],
+  ]);
+}
+
+function diagnosticFields(fields: ReadonlyArray): number[] {
+  return [...fields.flatMap(([code, value]) => [code, ...cstring(value)]), 0];
+}
+
+function backendResponse(
+  messages: ReadonlyArray,
+): Uint8Array {
+  return Uint8Array.from(
+    messages.flatMap(([tag, body]) => [tag, ...i32(body.length + 4), ...body]),
+  );
+}
+
+function cstring(value: string): number[] {
+  return [...new TextEncoder().encode(value), 0];
+}
+
+function i16(value: number): number[] {
+  const bits = value & 0xffff;
+  return [(bits >>> 8) & 0xff, bits & 0xff];
+}
+
+function i32(value: number): number[] {
+  const bits = value >>> 0;
+  return [(bits >>> 24) & 0xff, (bits >>> 16) & 0xff, (bits >>> 8) & 0xff, bits & 0xff];
+}
+
+function frontendMessages(bytes: Uint8Array): Array<{ tag: string; body: Uint8Array }> {
+  const messages: Array<{ tag: string; body: Uint8Array }> = [];
+  let offset = 0;
+  while (offset < bytes.length) {
+    const length = readI32(bytes, offset + 1);
+    messages.push({
+      tag: String.fromCharCode(bytes[offset]!),
+      body: bytes.slice(offset + 5, offset + 1 + length),
+    });
+    offset += length + 1;
+  }
+  return messages;
+}
+
+function readParseTypeOids(body: Uint8Array): number[] {
+  let offset = 1;
+  while (body[offset] !== 0) offset += 1;
+  offset += 1;
+  const count = readI16(body, offset);
+  offset += 2;
+  const oids: number[] = [];
+  for (let index = 0; index < count; index += 1) {
+    oids.push(readI32(body, offset) >>> 0);
+    offset += 4;
+  }
+  return oids;
+}
+
+function readI16(bytes: Uint8Array, offset: number): number {
+  return (bytes[offset]! << 8) | bytes[offset + 1]!;
+}
+
+function readI32(bytes: Uint8Array, offset: number): number {
+  return (
+    (bytes[offset]! * 0x1000000 +
+      (bytes[offset + 1]! << 16) +
+      (bytes[offset + 2]! << 8) +
+      bytes[offset + 3]!) >>>
+    0
+  );
+}
+
+function thrownBy(callback: () => unknown): unknown {
+  try {
+    callback();
+  } catch (error) {
+    return error;
+  }
+  throw new Error('expected callback to throw');
+}
diff --git a/src/sdks/ts-query/tools/package.sh b/src/sdks/ts-query/tools/package.sh
new file mode 100644
index 000000000..a45fda2e2
--- /dev/null
+++ b/src/sdks/ts-query/tools/package.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
+version="$(bun ../../../tools/release/product-version.mts version oliphaunt-query-ts)"
+destination="$PWD/../../../target/sdk-artifacts/oliphaunt-query-ts"
+rm -rf "$destination"
+mkdir -p "$destination"
+bun pm pack --filename "$destination/oliphaunt-ts-query-$version.tgz"
+bun ../../../tools/packaging/staging.mts "$destination"
diff --git a/src/shared/js-core/tsconfig.build.commonjs.json b/src/sdks/ts-query/tsconfig.build.commonjs.json
similarity index 100%
rename from src/shared/js-core/tsconfig.build.commonjs.json
rename to src/sdks/ts-query/tsconfig.build.commonjs.json
diff --git a/src/shared/js-core/tsconfig.build.module.json b/src/sdks/ts-query/tsconfig.build.module.json
similarity index 100%
rename from src/shared/js-core/tsconfig.build.module.json
rename to src/sdks/ts-query/tsconfig.build.module.json
diff --git a/src/shared/js-core/tsconfig.json b/src/sdks/ts-query/tsconfig.json
similarity index 100%
rename from src/shared/js-core/tsconfig.json
rename to src/sdks/ts-query/tsconfig.json
diff --git a/src/runtimes/wasix-napi/CHANGELOG.md b/src/sdks/ts-wasix/node-addon/CHANGELOG.md
similarity index 100%
rename from src/runtimes/wasix-napi/CHANGELOG.md
rename to src/sdks/ts-wasix/node-addon/CHANGELOG.md
diff --git a/src/sdks/ts-wasix/node-addon/Cargo.toml b/src/sdks/ts-wasix/node-addon/Cargo.toml
new file mode 100644
index 000000000..12943db29
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/Cargo.toml
@@ -0,0 +1,114 @@
+[package]
+name = "oliphaunt-wasix-napi"
+version = "0.1.0"
+edition = "2024"
+rust-version = "1.93"
+description = "Node-API adapter for the Oliphaunt WASIX Rust runtime."
+repository = "https://github.com/f0rr0/oliphaunt"
+homepage = "https://oliphaunt.dev"
+license = "MIT"
+publish = false
+build = "build.rs"
+
+[lib]
+crate-type = ["cdylib"]
+
+[features]
+default = []
+extensions = ["oliphaunt-wasix/extensions", "oliphaunt-pgwire-server/extensions"]
+tools = ["oliphaunt-wasix/tools-execution"]
+test-noop = ["napi/noop"]
+release = [
+  "tools",
+  "extension-amcheck",
+  "extension-auto-explain",
+  "extension-bloom",
+  "extension-btree-gin",
+  "extension-btree-gist",
+  "extension-citext",
+  "extension-cube",
+  "extension-dict-int",
+  "extension-dict-xsyn",
+  "extension-earthdistance",
+  "extension-file-fdw",
+  "extension-fuzzystrmatch",
+  "extension-hstore",
+  "extension-intarray",
+  "extension-isn",
+  "extension-lo",
+  "extension-ltree",
+  "extension-pageinspect",
+  "extension-pg-buffercache",
+  "extension-pg-freespacemap",
+  "extension-pg-hashids",
+  "extension-pg-ivm",
+  "extension-pg-surgery",
+  "extension-pg-textsearch",
+  "extension-pg-trgm",
+  "extension-pg-uuidv7",
+  "extension-pg-visibility",
+  "extension-pg-walinspect",
+  "extension-pgcrypto",
+  "extension-pgtap",
+  "extension-postgis",
+  "extension-seg",
+  "extension-tablefunc",
+  "extension-tcn",
+  "extension-tsm-system-rows",
+  "extension-tsm-system-time",
+  "extension-unaccent",
+  "extension-uuid-ossp",
+  "extension-vector",
+]
+extension-amcheck = ["extensions", "oliphaunt-wasix/extension-amcheck"]
+extension-auto-explain = ["extensions", "oliphaunt-wasix/extension-auto-explain"]
+extension-bloom = ["extensions", "oliphaunt-wasix/extension-bloom"]
+extension-btree-gin = ["extensions", "oliphaunt-wasix/extension-btree-gin"]
+extension-btree-gist = ["extensions", "oliphaunt-wasix/extension-btree-gist"]
+extension-citext = ["extensions", "oliphaunt-wasix/extension-citext"]
+extension-cube = ["extensions", "oliphaunt-wasix/extension-cube"]
+extension-dict-int = ["extensions", "oliphaunt-wasix/extension-dict-int"]
+extension-dict-xsyn = ["extensions", "oliphaunt-wasix/extension-dict-xsyn"]
+extension-earthdistance = ["extensions", "oliphaunt-wasix/extension-earthdistance"]
+extension-file-fdw = ["extensions", "oliphaunt-wasix/extension-file-fdw"]
+extension-fuzzystrmatch = ["extensions", "oliphaunt-wasix/extension-fuzzystrmatch"]
+extension-hstore = ["extensions", "oliphaunt-wasix/extension-hstore"]
+extension-intarray = ["extensions", "oliphaunt-wasix/extension-intarray"]
+extension-isn = ["extensions", "oliphaunt-wasix/extension-isn"]
+extension-lo = ["extensions", "oliphaunt-wasix/extension-lo"]
+extension-ltree = ["extensions", "oliphaunt-wasix/extension-ltree"]
+extension-pageinspect = ["extensions", "oliphaunt-wasix/extension-pageinspect"]
+extension-pg-buffercache = ["extensions", "oliphaunt-wasix/extension-pg-buffercache"]
+extension-pg-freespacemap = ["extensions", "oliphaunt-wasix/extension-pg-freespacemap"]
+extension-pg-hashids = ["extensions", "oliphaunt-wasix/extension-pg-hashids"]
+extension-pg-ivm = ["extensions", "oliphaunt-wasix/extension-pg-ivm"]
+extension-pg-surgery = ["extensions", "oliphaunt-wasix/extension-pg-surgery"]
+extension-pg-textsearch = ["extensions", "oliphaunt-wasix/extension-pg-textsearch"]
+extension-pg-trgm = ["extensions", "oliphaunt-wasix/extension-pg-trgm"]
+extension-pg-uuidv7 = ["extensions", "oliphaunt-wasix/extension-pg-uuidv7"]
+extension-pg-visibility = ["extensions", "oliphaunt-wasix/extension-pg-visibility"]
+extension-pg-walinspect = ["extensions", "oliphaunt-wasix/extension-pg-walinspect"]
+extension-pgcrypto = ["extensions", "oliphaunt-wasix/extension-pgcrypto"]
+extension-pgtap = ["extensions", "oliphaunt-wasix/extension-pgtap"]
+extension-postgis = ["extensions", "oliphaunt-wasix/extension-postgis"]
+extension-seg = ["extensions", "oliphaunt-wasix/extension-seg"]
+extension-tablefunc = ["extensions", "oliphaunt-wasix/extension-tablefunc"]
+extension-tcn = ["extensions", "oliphaunt-wasix/extension-tcn"]
+extension-tsm-system-rows = ["extensions", "oliphaunt-wasix/extension-tsm-system-rows"]
+extension-tsm-system-time = ["extensions", "oliphaunt-wasix/extension-tsm-system-time"]
+extension-unaccent = ["extensions", "oliphaunt-wasix/extension-unaccent"]
+extension-uuid-ossp = ["extensions", "oliphaunt-wasix/extension-uuid-ossp"]
+extension-vector = ["extensions", "oliphaunt-wasix/extension-vector"]
+
+[dependencies]
+oliphaunt-pgwire-server = { path = "../../../pgwire-server" }
+napi = { version = "=3.12.2", default-features = false, features = ["napi8"] }
+napi-derive = { version = "=3.6.3", default-features = false, features = ["strict", "type-def"] }
+liboliphaunt-wasix-portable = { version = "*", path = "../../../runtimes/liboliphaunt-wasix/crates/assets" }
+oliphaunt-wasix = { version = "*", path = "../../rust-wasix", features = ["__internal-napi"] }
+
+[target.'cfg(unix)'.dependencies]
+rustix = { version = "=1.1.4", features = ["fs"] }
+
+[build-dependencies]
+napi-build = "=2.4.1"
diff --git a/src/sdks/ts-wasix/node-addon/README.md b/src/sdks/ts-wasix/node-addon/README.md
new file mode 100644
index 000000000..b923ac0dc
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/README.md
@@ -0,0 +1,160 @@
+# Oliphaunt WASIX Node-API Runtime
+
+This private product builds the Node-API boundary used by `@oliphaunt/wasix-ts`
+on Node.js, Bun, Deno, and Electron. Browser export conditions do not load this product;
+they continue to use the patched Wasmer JavaScript host.
+
+The addon supports four purpose-specific TypeScript placement paths:
+
+- the direct TypeScript entry point opens and runs the database on its caller's
+  JavaScript thread;
+- the default native-host entry point uses one Rust database-owner actor so
+  synchronous guest work does not block the importing event loop;
+- the `/worker` entry point loads the direct class inside a real package-owned
+  JavaScript Worker; and
+- `/server` wraps the Rust listener owner directly.
+
+Direct handles reject use from a thread other than their creator. The actor and
+server surfaces instead expose Promise-facing Rust owners and do not publish a
+movable native handle to JavaScript.
+
+This makes the lowest-hop path explicit without making it the event-loop-blocking
+default. Calls on `/direct` are synchronous at the native boundary; the root
+settles promises from the Rust actor, and `/worker` adds only its requested
+JavaScript Worker hop. The TypeScript facade retains one promise-shaped public
+API and serialization contract.
+
+## Binary boundary
+
+`execProtocolRaw`, `backup`, and tool output return ordinary V8-owned
+`Uint8Array` values. This keeps their lifetime and detach behavior predictable
+across Node-API implementations. Direct requests borrow JavaScript input only
+for the synchronous call; actor requests copy into Rust-owned admission data
+before the caller returns. The `/worker` transport transfers eligible V8-owned
+`ArrayBuffer` values instead of cloning them again.
+
+`execProtocolRawStream` uses the Rust runtime's synchronous protocol callback.
+It verifies that every callback remains on the creator thread before entering
+Node-API, copies each chunk into V8-owned memory, and returns
+`callbackAborted` only after PostgreSQL recovers to `ReadyForQuery`. An
+unexpected off-thread callback is stopped without touching the JavaScript
+environment.
+
+`pgDump` and `psql` return structured `{ status, stdout, stderr }` results
+whose output fields retain their exact bytes, including invalid UTF-8.
+Ordinary frontend nonzero exits therefore retain stdout and stderr. A
+`PostgresToolError` is still thrown with its structured diagnostics even if it
+reports exit code zero; unrelated runtime failures remain thrown errors.
+
+`extensionIdentity(sqlName)` exposes each embedded extension archive as
+canonical `sha256:size`. Tool calls instead receive portable module bytes and
+trusted target AOT bytes from the optional PostgreSQL tools package. The Rust
+executor validates the module digest, target, engine and runtime fingerprint
+before loading that native code; the default addon embeds no tool modules.
+
+`payloadIdentity("runtimeArchive")` exposes the same identity form for the embedded runtime. Seeds and ICU data arrive as explicit validated byte inputs.
+
+## Standard and ICU profiles
+
+Each platform carrier contains one stable addon subpath,
+`oliphaunt_wasix_napi.node`. The binary supports both profiles without embedding seed or ICU data.
+Database open options select the requested profile and supply optional resources. `supportedProfiles()` reports the exact `['standard', 'icu']` contract.
+
+The existing TypeScript `icu` option therefore changes the selected database
+profile, not the package or binary that gets loaded. The default remains the
+standard profile.
+
+Release builds enable the `release` Cargo feature, which enables tool execution and all extension features supported by the WASIX catalog.
+The TypeScript API continues to accept extension descriptors, but the addon
+receives the validated SQL names and resolves them against this compile-time
+catalog. It never loads arbitrary extension bytes from JavaScript. A new or
+updated server extension therefore needs a new N-API carrier release.
+Frontend tool payloads are released independently. This makes each carrier larger, but removes portable
+archive expansion, WebAssembly compilation, and dynamic side-module linking
+from server startup.
+
+Source-only `cargo check` intentionally leaves those payload features disabled.
+The artifact build validates every staged runtime, extension, and AOT payload before embedding it.
+
+`tools/build-native.sh` fails closed unless the same-run producer outputs are
+available through the dependency build-script contract:
+
+- `OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR` points at the portable runtime payload root;
+- `OLIPHAUNT_WASM_GENERATED_AOT_DIR` points at the root containing the current
+  Rust target triple's core AOT manifest;
+- `OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT` points at the exact portable and
+  per-target AOT extension inventory;
+- `OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD=1` prevents every dependency crate
+  from selecting its source-only fallback.
+
+The build records and rechecks a deterministic inventory before packaging.
+Its portable manifest, host AOT manifest, and every selected extension
+manifest/archive/AOT manifest are embedded under
+`artifact-provenance.json.buildInputs` in both distribution forms. Its `build`
+object also records the release Cargo profile, disabled incremental compilation,
+single codegen unit, thin LTO, symbol stripping, exact `release` feature, and
+Rust target triple.
+The addon's `runtimeVersion()` identity comes directly from the selected
+`liboliphaunt-wasix-portable` crate. Workspace builds therefore report the
+local runtime while released carriers retain exact product compatibility pins.
+Product metadata tracks the runtime and `oliphaunt-wasix` Rust binding as
+separate compatibility versions; they are not assumed to advance together.
+
+## Distribution
+
+The canonical build package is private. `@oliphaunt/wasix-ts` declares public
+platform carriers as optional dependencies, allowing npm-compatible package
+managers to install only the matching target:
+
+- `@oliphaunt/wasix-napi-darwin-arm64`
+- `@oliphaunt/wasix-napi-linux-arm64-gnu`
+- `@oliphaunt/wasix-napi-linux-x64-gnu`
+- `@oliphaunt/wasix-napi-win32-x64-msvc`
+
+Carrier packages have no install scripts and never download executable code.
+`tools/build-native.sh` creates the single profile-complete addon and
+`tools/package-platform.sh` stages the matching carrier and portable release
+archive with source/artifact provenance before `bun pm pack`. Per-target jobs do
+not write the shared checksum filename; the aggregate release-assets task
+writes one canonical checksum manifest after all four target outputs merge.
+
+The supported target set is intentionally closed: macOS arm64, Linux arm64 or
+x64 with glibc, and Windows x64 with MSVC. macOS x64, Linux musl, and Windows
+arm64 do not have carriers. The native builder detects its Linux libc and
+rejects musl or an unidentifiable libc before compiling a GNU carrier. The
+Linux release addons are then compiled inside the pinned Rust 1.93.1 Debian
+Bookworm image (glibc 2.36), with exact payload paths mounted read-only and the
+actual build run without network access. This keeps them below the published
+glibc 2.38 ceiling; release staging also validates their ELF shape and resolves
+their dynamic dependencies in the pinned Fedora 39 glibc 2.38 consumer
+fixture. The runtime loader performs the same libc check before resolving even
+an explicit addon override. An unsupported target or
+missing optional package fails explicitly; the server export never falls back
+to the browser Wasmer implementation.
+
+Release staging pins every carrier to the exact N-API product version. Before
+loading native code, the TypeScript adapter checks the package identity,
+version, target, WASIX runtime version, addon ABI, Node-API level, and presence
+of both profiles. It then checks the addon's self-reported runtime and supported
+profiles. Artifact provenance records the exact source and embedded input
+identities used for the binary.
+
+Deno requires a local `node_modules` directory plus `--allow-ffi`,
+`--allow-read`, and `--allow-env`; directory databases need the corresponding
+filesystem permissions. Its `/worker` path uses the Node-compatible Worker
+implementation and does not require process-spawn permission. Managed Deno
+Deploy is not a qualified distribution target. Node.js, Bun, Deno, and Electron
+load the same Node-API 8 binary for their platform.
+
+Electron applications should configure their packager to leave
+`**/prebuilds/**` unpacked and ship `app.asar.unpacked` beside `app.asar`. This
+keeps the addon and any platform loader companions, including the Windows
+app-local VC runtime, in one loadable directory. Electron can otherwise extract
+native modules to a temporary file, which adds startup work and can interact
+poorly with antivirus scanners. Each carrier job exercises the ASAR-unpacked
+layout and its missing-companion failure mode.
+
+Run the installed-carrier smoke locally with `bash tools/smoke-packaged-addon.sh
+--target linux-x64-gnu --runtime node` from this project. It requires the packed
+carrier and GNU coreutils (`brew install coreutils` on macOS); each command has
+a five-minute deadline. Other runtimes are `bun`, `deno`, and `electron`.
diff --git a/src/sdks/ts-wasix/node-addon/build.rs b/src/sdks/ts-wasix/node-addon/build.rs
new file mode 100644
index 000000000..ed2baf6be
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/build.rs
@@ -0,0 +1,121 @@
+use std::path::{Path, PathBuf};
+
+const RELEASE_INPUT_ENVS: &[&str] = &[
+    "OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD",
+    "OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR",
+    "OLIPHAUNT_WASM_GENERATED_AOT_DIR",
+    "OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT",
+    "OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS",
+];
+
+fn main() {
+    napi_build::setup();
+    for name in RELEASE_INPUT_ENVS {
+        println!("cargo::rerun-if-env-changed={name}");
+    }
+    println!("cargo::rustc-env=OLIPHAUNT_WASIX_NAPI_ABI_VERSION=1");
+    validate_release_inputs();
+}
+
+fn validate_release_inputs() {
+    if std::env::var_os("CARGO_FEATURE_RELEASE").is_none() {
+        return;
+    }
+    assert!(
+        matches!(
+            std::env::var("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").as_deref(),
+            Ok("1")
+        ),
+        "WASIX N-API release builds must set OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD=1",
+    );
+
+    let portable = required_directory("OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR");
+    for relative in [
+        "manifest.json",
+        "oliphaunt.wasix.tar.zst",
+        "bin/initdb.wasix.wasm",
+    ] {
+        required_file(&portable.join(relative), "portable WASIX release payload");
+    }
+
+    let target = std::env::var("TARGET").expect("Cargo provides TARGET");
+    let aot_root = required_directory("OLIPHAUNT_WASM_GENERATED_AOT_DIR");
+    let target_aot = if aot_root.ends_with(&target) {
+        aot_root
+    } else {
+        aot_root.join(&target)
+    };
+    required_file(
+        &target_aot.join("manifest.json"),
+        "target WASIX core/tools AOT manifest",
+    );
+
+    let extension_root = required_directory("OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT");
+    assert!(
+        std::fs::read_dir(&extension_root)
+            .expect("read exact WASIX extension artifact root")
+            .next()
+            .is_some(),
+        "exact WASIX extension artifact root {} must not be empty",
+        extension_root.display(),
+    );
+    let inventory = required_path("OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS");
+    required_file(&inventory, "validated WASIX N-API build-input inventory");
+    println!("cargo::rerun-if-changed={}", inventory.display());
+
+    // `oliphaunt-wasix` relays the manifests emitted by the exact payload
+    // crates it compiled. These prove Cargo selected the embedded
+    // portable/core-AOT inputs, not only that similarly named
+    // files happened to exist in the workspace.
+    let target_suffix = match target.as_str() {
+        "aarch64-apple-darwin" => "MACOS_ARM64",
+        "aarch64-unknown-linux-gnu" => "LINUX_ARM64_GNU",
+        "x86_64-unknown-linux-gnu" => "LINUX_X64_GNU",
+        "x86_64-pc-windows-msvc" => "WINDOWS_X64_MSVC",
+        other => panic!("unsupported WASIX N-API release target {other}"),
+    };
+    for name in [
+        "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_LIBOLIPHAUNT_WASIX_RUNTIME_MANIFEST".to_owned(),
+        format!(
+            "DEP_OLIPHAUNT_ARTIFACT_WASIX_RELAY_LIBOLIPHAUNT_WASIX_AOT_{target_suffix}_MANIFEST"
+        ),
+    ] {
+        required_env_file(&name, "relayed WASIX Cargo artifact manifest");
+    }
+}
+
+fn required_path(name: &str) -> PathBuf {
+    std::env::var_os(name)
+        .filter(|value| !value.is_empty())
+        .map(PathBuf::from)
+        .unwrap_or_else(|| panic!("WASIX N-API release builds require {name}"))
+}
+
+fn required_directory(name: &str) -> PathBuf {
+    let path = required_path(name);
+    let metadata = std::fs::symlink_metadata(&path)
+        .unwrap_or_else(|error| panic!("inspect {name} {}: {error}", path.display()));
+    assert!(
+        metadata.is_dir() && !metadata.file_type().is_symlink(),
+        "{name} must be a regular non-symlink directory: {}",
+        path.display(),
+    );
+    path
+}
+
+fn required_file(path: &Path, label: &str) {
+    let metadata = std::fs::symlink_metadata(path)
+        .unwrap_or_else(|error| panic!("inspect {label} {}: {error}", path.display()));
+    assert!(
+        metadata.is_file() && !metadata.file_type().is_symlink() && metadata.len() > 0,
+        "{label} must be a non-empty regular non-symlink file: {}",
+        path.display(),
+    );
+}
+
+fn required_env_file(name: &str, label: &str) {
+    println!("cargo::rerun-if-env-changed={name}");
+    let path = required_path(name);
+    required_file(&path, label);
+    println!("cargo::rerun-if-changed={}", path.display());
+}
diff --git a/src/sdks/ts-wasix/node-addon/moon.yml b/src/sdks/ts-wasix/node-addon/moon.yml
new file mode 100644
index 000000000..b717c4cfc
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/moon.yml
@@ -0,0 +1,218 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "oliphaunt-wasix-napi"
+language: "rust"
+layer: "library"
+stack: "systems"
+tags: ["cargo-package", "javascript-quality", "runtime", "wasix", "native", "node-api", "release-product"]
+dependsOn:
+  - id: "extension-runtime-contract"
+    scope: "build"
+  - id: "extensions"
+    scope: "build"
+  - id: "liboliphaunt-wasix"
+    scope: "production"
+  - id: "oliphaunt-wasix-rust"
+    scope: "production"
+
+project:
+  title: "Oliphaunt WASIX Node-API Runtime"
+  description: "Node-API adapter over the Oliphaunt WASIX Rust binding."
+  owner: "oliphaunt"
+  release:
+    component: "oliphaunt-wasix-napi"
+    packagePath: "src/sdks/ts-wasix/node-addon"
+    artifactTargets:
+      preset: "wasix-napi-addon"
+      targets:
+        - "linux-arm64-gnu"
+        - "linux-x64-gnu"
+        - "macos-arm64"
+        - "windows-x64-msvc"
+
+owners:
+  defaultOwner: "@oliphaunt/wasix-napi"
+
+fileGroups:
+  code:
+    - "**/*"
+    - "!**/*.md"
+    - "!moon.yml"
+    - "!release.toml"
+
+tasks:
+  typecheck:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "static", "requires-rust"]
+    script: |
+      set -e
+      node --check tools/smoke-packaged-addon.mts
+      bash -n tools/smoke-packaged-addon.sh
+      cargo check --manifest-path Cargo.toml --locked --no-default-features
+    env:
+      CARGO_TARGET_DIR: "../../../../target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - project: "liboliphaunt-wasix"
+        group: "crates"
+      - "Cargo.toml"
+      - "build.rs"
+      - "src/**/*"
+      - "tools/smoke-packaged-addon.mts"
+      - "tools/smoke-packaged-addon.sh"
+    options:
+      cache: true
+
+  test:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "unit", "requires-rust"]
+    script: |
+      set -e
+      bun test ./tools/detect-linux-libc.test.mts ./tools/package-contract.test.mts ../../../../tools/packaging/local-npm-tarball.test.mts
+      bash tools/package-platform.test.sh
+      cargo test --manifest-path Cargo.toml --locked --no-default-features --features test-noop --lib
+    env:
+      CARGO_TARGET_DIR: "../../../../target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - "@group(code)"
+      - "/tools/packaging/testdata/release-fixture-utils.mts"
+      - "/tools/packaging/**/*"
+      - "/tools/release/**/*"
+    options:
+      cache: true
+
+  rust-format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt -p oliphaunt-wasix-napi --check"
+    inputs: ["/src/sdks/ts-wasix/node-addon/**/*.rs","/src/sdks/ts-wasix/node-addon/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+  rust-lint:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy -p oliphaunt-wasix-napi --all-targets --locked -- -D warnings"
+    env:
+      CARGO_TARGET_DIR: "target"
+    inputs: ["/src/sdks/ts-wasix/node-addon/**/*.rs","/src/sdks/ts-wasix/node-addon/Cargo.toml","/clippy.toml","@group(cargo-workspace)"]
+    options:
+      runFromWorkspaceRoot: true
+
+  build-release-assets:
+    tags: ["release", "artifact", "in-place-finalizer-input", "ci-wasix-napi"]
+    command: "bash -c 'set -e; tools/dev/bun.sh src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts --all --family wasix --require-wasix; exec bash src/sdks/ts-wasix/node-addon/tools/build-native.sh'"
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+      - "liboliphaunt-wasix:runtime-aot"
+      - "extension-artifacts-wasix:build-aot"
+      - "extension-artifacts-wasix:build-target"
+    inputs:
+      - "@group(cargo-workspace)"
+      - "@group(legal-files)"
+      - project: "extensions"
+        group: "package"
+      - project: "liboliphaunt-wasix"
+        group: "release-metadata"
+      - project: "extension-runtime-contract"
+        group: "contract"
+      - "/src/sdks/ts-wasix/node-addon/Cargo.toml"
+      - "/src/sdks/ts-wasix/node-addon/build.rs"
+      - "/src/sdks/ts-wasix/node-addon/package.json"
+      - "/src/sdks/ts-wasix/node-addon/packages/**/*"
+      - "/src/sdks/ts-wasix/node-addon/src/**/*"
+      - "/src/sdks/ts-wasix/node-addon/tools/build-native.sh"
+      - "/src/sdks/ts-wasix/node-addon/tools/native-build-data.mts"
+      - "/src/sdks/ts-wasix/node-addon/tools/check-build-inputs.mts"
+      - "/src/sdks/ts-wasix/node-addon/tools/detect-linux-libc.mts"
+      - "/src/sdks/ts-wasix/node-addon/tools/package-platform.mts"
+      - "/src/sdks/ts-wasix/node-addon/tools/package-platform.sh"
+      - "/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.mts"
+      - "/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.sh"
+      - "/src/sdks/ts-wasix/sdk/tools/pgwire-client.mts"
+      - project: "liboliphaunt-wasix"
+        group: "crates"
+      - "/target/oliphaunt-wasix/assets/**/*"
+      - "/target/oliphaunt-wasix/aot/**/*"
+      - "/target/extensions/wasix/release-assets/**/*"
+      - "/target/extensions/wasix/aot-artifacts/**/*"
+      - "/target/extension-artifacts/**/*"
+      - "/src/runtimes/liboliphaunt-wasix/tools/xtask/**/*"
+      - "/.prototools"
+      - "/src/extensions/contrib/carriers.toml"
+      - "/src/extensions/generated/extensions.catalog.json"
+      - "/tools/dev/bun.toml"
+      - "/tools/dev/deno.toml"
+      - "/tools/dev/bun.sh"
+      - "/tools/dev/deno.sh"
+      - "/tools/dev/install-pinned-js-runtime.sh"
+      - "/tools/packaging/*.{mjs,mts}"
+      - "/src/sdks/ts-wasix/node-addon/tools/check-release-assets.mts"
+      - "/src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts"
+      - "/tools/packaging/cargo-source-package.mts"
+      - "/src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts"
+      - "/src/extensions/tools/extension-upstream-licenses.mts"
+      - "/tools/release/release-artifact-targets.mts"
+      - "/src/sdks/ts-wasix/node-addon/tools/build-linux-wasix-napi-baseline.sh"
+      - "/tools/packaging/check-linux-consumer-baseline.sh"
+      - "/src/extensions/artifacts/packages/tools/contrib-carriers.mts"
+      - "/src/extensions/artifacts/packages/tools/extension-registry-packages.mts"
+      - "/tools/packaging/platform-binary-contract.mts"
+      - "@group(release-target-contract)"
+      - "/tools/packaging/release-asset-validation.mts"
+      - "/tools/release/release-graph.mts"
+      - "@group(release-archive-contract)"
+      - "/src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json"
+      - "/src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts"
+      - "/tools/packaging/windows-vc-runtime-closure.mts"
+    outputs:
+      - "/target/oliphaunt-wasix-napi/release-assets/**/*"
+      - "/target/oliphaunt-wasix-napi/npm-packages/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+
+
+  finalize-release-assets:
+    tags: ["release", "artifact-package", "in-place-finalizer", "ci-wasix-napi-release-assets"]
+    command: "tools/dev/bun.sh src/sdks/ts-wasix/node-addon/tools/check-release-assets.mts --aggregate"
+    deps:
+      - "oliphaunt-wasix-napi:build-release-assets"
+    inputs:
+      - "@group(legal-files)"
+      - "/bunfig.toml"
+      - "/src/sdks/ts-wasix/node-addon/moon.yml"
+      - "/src/sdks/ts-wasix/node-addon/package.json"
+      - "/src/sdks/ts-wasix/node-addon/packages/**/*"
+      - "/src/sdks/ts-wasix/node-addon/release.toml"
+      - project: "oliphaunt-wasix-rust"
+        group: "code"
+      - project: "liboliphaunt-wasix"
+        group: "crates"
+      - "/tools/packaging/*.{mjs,mts}"
+      - "/tools/packaging/finalize-helper-assets.mts"
+      - "/src/sdks/ts-wasix/node-addon/tools/check-release-assets.mts"
+      - "/src/sdks/ts-wasix/node-addon/tools/build-linux-wasix-napi-baseline.sh"
+      - "/tools/packaging/check-linux-consumer-baseline.sh"
+      - "/tools/packaging/platform-binary-contract.mts"
+      - "/tools/release/platform-compatibility-policy.mts"
+      - "/tools/release/release-artifact-targets.mts"
+      - "/tools/packaging/release-asset-validation.mts"
+      - "@group(release-archive-contract)"
+      - "/tools/packaging/write-checksum-manifest.mts"
+      - "/src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json"
+      - "/tools/packaging/windows-vc-runtime-closure.mts"
+      - "/target/oliphaunt-wasix-napi/npm-packages/**/*"
+      - "/target/oliphaunt-wasix-napi/release-assets/**/*"
+    outputs:
+      - "/target/oliphaunt-wasix-napi/npm-packages/**/*"
+      - "/target/oliphaunt-wasix-napi/release-assets/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
diff --git a/src/sdks/ts-wasix/node-addon/package.json b/src/sdks/ts-wasix/node-addon/package.json
new file mode 100644
index 000000000..809f5c8f5
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/package.json
@@ -0,0 +1,45 @@
+{
+  "name": "@oliphaunt/wasix-napi",
+  "version": "0.1.0",
+  "description": "Private build package for the Oliphaunt WASIX Node-API runtime.",
+  "license": "MIT",
+  "private": true,
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts-wasix/node-addon"
+  },
+  "oliphaunt": {
+    "runtimeProduct": "liboliphaunt-wasix",
+    "runtimeVersion": "0.2.0",
+    "rustBindingProduct": "oliphaunt-wasix-rust",
+    "rustBindingVersion": "0.2.0",
+    "addonAbiVersion": 2,
+    "nodeApiVersion": 8,
+    "profiles": [
+      "standard",
+      "icu"
+    ]
+  },
+  "files": [
+    "src",
+    "packages",
+    "tools",
+    "Cargo.toml",
+    "build.rs",
+    "README.md",
+    "CHANGELOG.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md"
+  ],
+  "scripts": {
+    "build": "bash tools/build-native.sh",
+    "package": "bash tools/package-platform.sh"
+  },
+  "engines": {
+    "node": ">=22.13 <25",
+    "bun": ">=1.3.14",
+    "deno": ">=2.8.1"
+  }
+}
diff --git a/src/runtimes/wasix-napi/packages/darwin-arm64/README.md b/src/sdks/ts-wasix/node-addon/packages/darwin-arm64/README.md
similarity index 100%
rename from src/runtimes/wasix-napi/packages/darwin-arm64/README.md
rename to src/sdks/ts-wasix/node-addon/packages/darwin-arm64/README.md
diff --git a/src/sdks/ts-wasix/node-addon/packages/darwin-arm64/package.json b/src/sdks/ts-wasix/node-addon/packages/darwin-arm64/package.json
new file mode 100644
index 000000000..666b4ff5a
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/packages/darwin-arm64/package.json
@@ -0,0 +1,48 @@
+{
+  "name": "@oliphaunt/wasix-napi-darwin-arm64",
+  "version": "0.1.0",
+  "description": "macOS arm64 prebuilt Oliphaunt WASIX Node-API runtime.",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0",
+  "type": "commonjs",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts-wasix/node-addon/packages/darwin-arm64"
+  },
+  "os": [
+    "darwin"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "macos-arm64",
+    "runtimeProduct": "liboliphaunt-wasix",
+    "runtimeVersion": "0.2.0",
+    "addonAbiVersion": 2,
+    "nodeApiVersion": 8,
+    "profiles": [
+      "standard",
+      "icu"
+    ]
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "files": [
+    "prebuilds",
+    "artifact-provenance.json",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
+    "THIRD_PARTY_LICENSES"
+  ],
+  "exports": {
+    "./oliphaunt_wasix_napi.node": "./prebuilds/oliphaunt_wasix_napi.node",
+    "./artifact-provenance.json": "./artifact-provenance.json",
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/wasix-napi/packages/linux-arm64-gnu/README.md b/src/sdks/ts-wasix/node-addon/packages/linux-arm64-gnu/README.md
similarity index 100%
rename from src/runtimes/wasix-napi/packages/linux-arm64-gnu/README.md
rename to src/sdks/ts-wasix/node-addon/packages/linux-arm64-gnu/README.md
diff --git a/src/sdks/ts-wasix/node-addon/packages/linux-arm64-gnu/package.json b/src/sdks/ts-wasix/node-addon/packages/linux-arm64-gnu/package.json
new file mode 100644
index 000000000..7a2a7ec55
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/packages/linux-arm64-gnu/package.json
@@ -0,0 +1,51 @@
+{
+  "name": "@oliphaunt/wasix-napi-linux-arm64-gnu",
+  "version": "0.1.0",
+  "description": "Linux arm64 glibc prebuilt Oliphaunt WASIX Node-API runtime.",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0",
+  "type": "commonjs",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts-wasix/node-addon/packages/linux-arm64-gnu"
+  },
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "linux-arm64-gnu",
+    "runtimeProduct": "liboliphaunt-wasix",
+    "runtimeVersion": "0.2.0",
+    "addonAbiVersion": 2,
+    "nodeApiVersion": 8,
+    "profiles": [
+      "standard",
+      "icu"
+    ]
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "files": [
+    "prebuilds",
+    "artifact-provenance.json",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
+    "THIRD_PARTY_LICENSES"
+  ],
+  "exports": {
+    "./oliphaunt_wasix_napi.node": "./prebuilds/oliphaunt_wasix_napi.node",
+    "./artifact-provenance.json": "./artifact-provenance.json",
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/wasix-napi/packages/linux-x64-gnu/README.md b/src/sdks/ts-wasix/node-addon/packages/linux-x64-gnu/README.md
similarity index 100%
rename from src/runtimes/wasix-napi/packages/linux-x64-gnu/README.md
rename to src/sdks/ts-wasix/node-addon/packages/linux-x64-gnu/README.md
diff --git a/src/sdks/ts-wasix/node-addon/packages/linux-x64-gnu/package.json b/src/sdks/ts-wasix/node-addon/packages/linux-x64-gnu/package.json
new file mode 100644
index 000000000..243dd2e49
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/packages/linux-x64-gnu/package.json
@@ -0,0 +1,51 @@
+{
+  "name": "@oliphaunt/wasix-napi-linux-x64-gnu",
+  "version": "0.1.0",
+  "description": "Linux x64 glibc prebuilt Oliphaunt WASIX Node-API runtime.",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0",
+  "type": "commonjs",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts-wasix/node-addon/packages/linux-x64-gnu"
+  },
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "linux-x64-gnu",
+    "runtimeProduct": "liboliphaunt-wasix",
+    "runtimeVersion": "0.2.0",
+    "addonAbiVersion": 2,
+    "nodeApiVersion": 8,
+    "profiles": [
+      "standard",
+      "icu"
+    ]
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "files": [
+    "prebuilds",
+    "artifact-provenance.json",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
+    "THIRD_PARTY_LICENSES"
+  ],
+  "exports": {
+    "./oliphaunt_wasix_napi.node": "./prebuilds/oliphaunt_wasix_napi.node",
+    "./artifact-provenance.json": "./artifact-provenance.json",
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/wasix-napi/packages/win32-x64-msvc/README.md b/src/sdks/ts-wasix/node-addon/packages/win32-x64-msvc/README.md
similarity index 100%
rename from src/runtimes/wasix-napi/packages/win32-x64-msvc/README.md
rename to src/sdks/ts-wasix/node-addon/packages/win32-x64-msvc/README.md
diff --git a/src/sdks/ts-wasix/node-addon/packages/win32-x64-msvc/package.json b/src/sdks/ts-wasix/node-addon/packages/win32-x64-msvc/package.json
new file mode 100644
index 000000000..46abad627
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/packages/win32-x64-msvc/package.json
@@ -0,0 +1,48 @@
+{
+  "name": "@oliphaunt/wasix-napi-win32-x64-msvc",
+  "version": "0.1.0",
+  "description": "Windows x64 MSVC prebuilt Oliphaunt WASIX Node-API runtime.",
+  "license": "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0",
+  "type": "commonjs",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts-wasix/node-addon/packages/win32-x64-msvc"
+  },
+  "os": [
+    "win32"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "windows-x64-msvc",
+    "runtimeProduct": "liboliphaunt-wasix",
+    "runtimeVersion": "0.2.0",
+    "addonAbiVersion": 2,
+    "nodeApiVersion": 8,
+    "profiles": [
+      "standard",
+      "icu"
+    ]
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "files": [
+    "prebuilds",
+    "artifact-provenance.json",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_NOTICES.oliphaunt-wasix.md",
+    "THIRD_PARTY_LICENSES"
+  ],
+  "exports": {
+    "./oliphaunt_wasix_napi.node": "./prebuilds/oliphaunt_wasix_napi.node",
+    "./artifact-provenance.json": "./artifact-provenance.json",
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/sdks/ts-wasix/node-addon/release.toml b/src/sdks/ts-wasix/node-addon/release.toml
new file mode 100644
index 000000000..d5e16da91
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/release.toml
@@ -0,0 +1,41 @@
+id = "oliphaunt-wasix-napi"
+owner = "@oliphaunt/wasix-napi"
+kind = "runtime"
+publish_targets = ["npm", "github-release-assets"]
+registry_packages = [
+  "npm:@oliphaunt/wasix-napi-darwin-arm64",
+  "npm:@oliphaunt/wasix-napi-linux-arm64-gnu",
+  "npm:@oliphaunt/wasix-napi-linux-x64-gnu",
+  "npm:@oliphaunt/wasix-napi-win32-x64-msvc",
+]
+release_artifacts = ["node-api-prebuilds", "npm-optional-platform-packages"]
+
+[compatibility_versions.oliphaunt-wasix-napi-runtime]
+source_product = "liboliphaunt-wasix"
+path = "src/sdks/ts-wasix/node-addon/package.json"
+parser = "json:oliphaunt.runtimeVersion"
+
+[compatibility_versions.oliphaunt-wasix-napi-runtime-darwin-arm64]
+source_product = "liboliphaunt-wasix"
+path = "src/sdks/ts-wasix/node-addon/packages/darwin-arm64/package.json"
+parser = "json:oliphaunt.runtimeVersion"
+
+[compatibility_versions.oliphaunt-wasix-napi-runtime-linux-arm64-gnu]
+source_product = "liboliphaunt-wasix"
+path = "src/sdks/ts-wasix/node-addon/packages/linux-arm64-gnu/package.json"
+parser = "json:oliphaunt.runtimeVersion"
+
+[compatibility_versions.oliphaunt-wasix-napi-runtime-linux-x64-gnu]
+source_product = "liboliphaunt-wasix"
+path = "src/sdks/ts-wasix/node-addon/packages/linux-x64-gnu/package.json"
+parser = "json:oliphaunt.runtimeVersion"
+
+[compatibility_versions.oliphaunt-wasix-napi-runtime-win32-x64-msvc]
+source_product = "liboliphaunt-wasix"
+path = "src/sdks/ts-wasix/node-addon/packages/win32-x64-msvc/package.json"
+parser = "json:oliphaunt.runtimeVersion"
+
+[compatibility_versions.oliphaunt-wasix-napi-wasix-rust]
+source_product = "oliphaunt-wasix-rust"
+path = "src/sdks/ts-wasix/node-addon/package.json"
+parser = "json:oliphaunt.rustBindingVersion"
diff --git a/src/sdks/ts-wasix/node-addon/src/lib.rs b/src/sdks/ts-wasix/node-addon/src/lib.rs
new file mode 100644
index 000000000..c392f5d8a
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/src/lib.rs
@@ -0,0 +1,1456 @@
+//! Node-API boundary for the Oliphaunt WASIX Rust runtime.
+//!
+//! `NativeWasixActorDatabase` and `NativeWasixServer` reuse the Rust async
+//! owners directly. Promise settlement is the only owner-to-JavaScript hop;
+//! no Tokio runtime or Node async-work queue participates in database work.
+
+use std::collections::BTreeMap;
+use std::mem;
+use std::panic::{AssertUnwindSafe, catch_unwind};
+use std::path::PathBuf;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::{Arc, Condvar, Mutex, OnceLock};
+use std::thread::{self, ThreadId};
+
+use napi::Env;
+use napi::bindgen_prelude::{
+    Function, JsObjectValue, JsValue, Object, ObjectFinalize, ToNapiValue, Uint8Array,
+    Uint8ArraySlice,
+};
+use napi::threadsafe_function::{ThreadsafeCallContext, ThreadsafeFunctionCallMode};
+use napi::{Error, Result, Status};
+use napi_derive::napi;
+use oliphaunt_pgwire_server::{AsyncOliphauntServer, AsyncOliphauntServerBuilder, ServerListen};
+#[cfg(feature = "extensions")]
+use oliphaunt_wasix::Extension;
+#[cfg(feature = "tools")]
+use oliphaunt_wasix::tools::{PgDumpOptions, PostgresToolOutput, PsqlOptions, ToolAssets};
+use oliphaunt_wasix::{
+    AsyncOliphaunt, AsyncOliphauntBuilder, CatalogProfile, ClusterSeed, DatabaseStorage, ErrorKind,
+    IcuData, Oliphaunt, OliphauntBuilder, RawStreamError, StorageCommitState, StorageErrorCode,
+    StorageErrorPhase,
+};
+
+const ADDON_ABI_VERSION: u32 = 2;
+const NODE_API_VERSION: u32 = 8;
+const RUNTIME_VERSION: &str = liboliphaunt_wasix_portable::PACKAGE_VERSION;
+
+/// Keep the native image mapped after a JavaScript Worker environment exits.
+///
+/// The synchronous `/direct` placement can initialize Wasmer/WASIX's
+/// process-wide Tokio runtime without first creating a Node-API deferred or
+/// threadsafe function. Those napi-rs values normally request this same pin,
+/// but a direct-only Worker has neither. The runtime's native threads can
+/// outlive that Worker environment, so Windows must not `FreeLibrary` (and
+/// Unix hosts must not `dlclose`) the code containing their wakers. napi-rs
+/// implements this as a process-once loader reference and leaves the event
+/// loop unreferenced.
+#[inline]
+fn retain_addon_image_for_process_runtime() {
+    #[cfg(not(feature = "test-noop"))]
+    napi::bindgen_prelude::retain_current_module_for_unload_safety();
+}
+
+#[napi(object)]
+pub struct NativeStorageOptions {
+    pub kind: String,
+    pub path: Option,
+}
+
+#[napi(object)]
+pub struct NativeSeedInput {
+    pub archive: Uint8Array,
+    pub manifest: Uint8Array,
+}
+
+#[napi(object)]
+pub struct NativeIcuInput {
+    pub data: Uint8Array,
+    pub manifest: Uint8Array,
+}
+
+// Snapshot caller-owned views before resource preparation moves off the JS thread.
+fn snapshot_resources(seed: &mut Option, icu: &mut Option) {
+    if let Some(seed) = seed {
+        seed.archive = Uint8Array::new(seed.archive.to_vec());
+        seed.manifest = Uint8Array::new(seed.manifest.to_vec());
+    }
+    if let Some(icu) = icu {
+        icu.data = Uint8Array::new(icu.data.to_vec());
+        icu.manifest = Uint8Array::new(icu.manifest.to_vec());
+    }
+}
+
+#[napi(object)]
+pub struct NativeOpenOptions {
+    pub profile: String,
+    pub storage: NativeStorageOptions,
+    pub username: String,
+    pub database: String,
+    #[napi(js_name = "startupGucs")]
+    pub startup_gucs: BTreeMap,
+    pub extensions: Vec,
+    pub seed: Option,
+    #[napi(js_name = "icuData")]
+    pub icu_data: Option,
+}
+
+#[napi(object)]
+pub struct NativeListenOptions {
+    pub transport: String,
+    pub port: Option,
+    pub directory: Option,
+}
+
+#[napi(object)]
+pub struct NativeServerOpenOptions {
+    pub profile: String,
+    pub storage: NativeStorageOptions,
+    pub username: String,
+    pub database: String,
+    #[napi(js_name = "startupGucs")]
+    pub startup_gucs: BTreeMap,
+    pub extensions: Vec,
+    pub seed: Option,
+    #[napi(js_name = "icuData")]
+    pub icu_data: Option,
+    pub listen: NativeListenOptions,
+}
+
+#[napi(object)]
+pub struct NativeToolResult {
+    pub status: i32,
+    pub stdout: Uint8Array,
+    pub stderr: Uint8Array,
+}
+
+#[napi(object)]
+pub struct NativeToolAssets {
+    pub wasm: Uint8Array,
+    pub aot: Uint8Array,
+    pub manifest: String,
+}
+
+#[cfg(feature = "tools")]
+#[allow(unsafe_code)]
+fn tool_assets(assets: NativeToolAssets) -> ToolAssets {
+    // SAFETY: this API loads the caller's trusted native-code tool package.
+    // Rust validates its target, source identity and all content hashes before
+    // deserializing. Own both buffers before any asynchronous execution.
+    unsafe { ToolAssets::new(assets.wasm.to_vec(), assets.aot.to_vec(), assets.manifest) }
+}
+
+#[derive(Debug)]
+struct CreatorThread {
+    id: ThreadId,
+}
+
+impl CreatorThread {
+    fn current() -> Self {
+        Self {
+            id: thread::current().id(),
+        }
+    }
+
+    fn require(&self, owner: &'static str) -> Result<()> {
+        if thread::current().id() == self.id {
+            return Ok(());
+        }
+        Err(Error::new(
+            Status::GenericFailure,
+            format!(
+                "{owner} is bound to the JavaScript thread that created it; open and use it in the same Node.js, Bun, Deno, or Electron isolate"
+            ),
+        ))
+    }
+}
+
+/// Synchronous database owner for the `/direct` placement and for a real
+/// JavaScript Worker placement which loads `/direct` in its own isolate.
+#[napi(custom_finalize)]
+pub struct NativeWasixDatabase {
+    owner: CreatorThread,
+    database: Option,
+}
+
+impl NativeWasixDatabase {
+    fn invoke_result(
+        &mut self,
+        env: &Env,
+        operation: &'static str,
+        action: impl FnOnce(&mut Oliphaunt) -> std::result::Result,
+    ) -> Result> {
+        self.owner.require("WASIX direct database")?;
+        let Some(mut database) = self.database.take() else {
+            return Err(native_lifecycle_error(
+                env,
+                operation,
+                "WASIX direct database is closed",
+            ));
+        };
+        match catch_unwind(AssertUnwindSafe(|| action(&mut database))) {
+            Ok(result) => {
+                self.database = Some(database);
+                Ok(result)
+            }
+            Err(payload) => {
+                // The Wasmer store cannot be trusted after an unwind. Retire
+                // and quarantine it instead of allowing a second entry or Drop.
+                mem::forget(payload);
+                mem::forget(database);
+                Err(native_lifecycle_error(
+                    env,
+                    operation,
+                    "WASIX direct database panicked and was permanently retired",
+                ))
+            }
+        }
+    }
+
+    fn invoke_core(
+        &mut self,
+        env: &Env,
+        operation: &'static str,
+        action: impl FnOnce(&mut Oliphaunt) -> oliphaunt_wasix::Result,
+    ) -> Result> {
+        self.invoke_result(env, operation, action)
+    }
+
+    fn invoke(
+        &mut self,
+        env: &Env,
+        operation: &'static str,
+        action: impl FnOnce(&mut Oliphaunt) -> oliphaunt_wasix::Result,
+    ) -> Result {
+        self.invoke_core(env, operation, action)?
+            .map_err(|error| native_runtime_error(env, operation, error))
+    }
+}
+
+impl Drop for NativeWasixDatabase {
+    fn drop(&mut self) {
+        let Some(mut database) = self.database.take() else {
+            return;
+        };
+        if thread::current().id() != self.owner.id {
+            mem::forget(database);
+            return;
+        }
+        if let Err(payload) = catch_unwind(AssertUnwindSafe(|| {
+            let _ = database.close();
+        })) {
+            mem::forget(payload);
+            mem::forget(database);
+        }
+    }
+}
+
+impl ObjectFinalize for NativeWasixDatabase {
+    fn finalize(mut self, _env: Env) -> Result<()> {
+        // A V8/N-API finalizer is an environment-teardown callback, not an
+        // explicit lifecycle operation. Synchronous PostgreSQL shutdown could
+        // hang teardown indefinitely, so quarantine the still-open creator-
+        // thread-affine store. An already closed store is safe to drop and
+        // release normally; explicit `close()` therefore does not leak its
+        // Wasmer allocation. Drop sees `None` after this method.
+        drop_if_closed_or_quarantine(&mut self.database, Oliphaunt::is_closed);
+        Ok(())
+    }
+}
+
+fn drop_if_closed_or_quarantine(value: &mut Option, is_closed: impl FnOnce(&T) -> bool) {
+    if let Some(value) = value.take() {
+        if is_closed(&value) {
+            drop(value);
+        } else {
+            mem::forget(value);
+        }
+    }
+}
+
+#[napi]
+impl NativeWasixDatabase {
+    #[napi(factory, catch_unwind)]
+    pub fn open(env: Env, options: NativeOpenOptions) -> Result {
+        retain_addon_image_for_process_runtime();
+        let database = configure_direct_database(options)?
+            .open()
+            .map_err(|error| native_runtime_error(&env, "open WASIX direct database", error))?;
+        Ok(Self {
+            owner: CreatorThread::current(),
+            database: Some(database),
+        })
+    }
+
+    #[napi(getter, catch_unwind)]
+    pub fn closed(&self) -> Result {
+        self.owner.require("WASIX direct database")?;
+        Ok(self.database.as_ref().is_none_or(Oliphaunt::is_closed))
+    }
+
+    #[napi(js_name = "execProtocolRaw", catch_unwind)]
+    pub fn exec_protocol_raw(
+        &mut self,
+        env: Env,
+        request: Uint8ArraySlice<'_>,
+    ) -> Result {
+        let response = self.invoke(&env, "execute PostgreSQL protocol request", |database| {
+            database.exec_protocol_raw(request.as_ref())
+        })?;
+        v8_owned_bytes(&env, &response)
+    }
+
+    #[napi(js_name = "execProtocolRawStream", catch_unwind)]
+    pub fn exec_protocol_raw_stream(
+        &mut self,
+        env: Env,
+        request: Uint8ArraySlice<'_>,
+        on_chunk: Function<'_, Uint8Array, ()>,
+    ) -> Result<&'static str> {
+        let callback = on_chunk.create_ref()?;
+        let raw_env = env.raw() as usize;
+        let owner_thread = self.owner.id;
+        let result =
+            self.invoke_result(&env, "stream PostgreSQL protocol response", |database| {
+                database.exec_protocol_raw_stream(request.as_ref(), move |chunk| {
+                    if thread::current().id() != owner_thread {
+                        return Err(Error::new(
+                            Status::GenericFailure,
+                            "WASIX protocol callback left its JavaScript owner thread",
+                        ));
+                    }
+                    let callback_env = Env::from_raw(raw_env as napi::sys::napi_env);
+                    let output = v8_owned_bytes(&callback_env, chunk)?;
+                    callback.borrow_back(&callback_env)?.call(output)
+                })
+            })?;
+        match result {
+            Ok(()) => Ok("complete"),
+            Err(RawStreamError::Callback(_)) => Ok("callbackAborted"),
+            Err(RawStreamError::Database(error)) => Err(native_runtime_error(
+                &env,
+                "stream PostgreSQL protocol response",
+                error,
+            )),
+            Err(RawStreamError::CallbackPanicked(error)) => Err(native_runtime_error(
+                &env,
+                "stream PostgreSQL protocol callback",
+                error,
+            )),
+            Err(_) => Err(Error::new(
+                Status::GenericFailure,
+                "stream PostgreSQL protocol response: unknown stream error",
+            )),
+        }
+    }
+
+    #[napi(catch_unwind)]
+    pub fn backup(&mut self, env: Env) -> Result {
+        let backup = self.invoke(&env, "back up WASIX database", Oliphaunt::backup)?;
+        v8_owned_bytes(&env, &backup)
+    }
+
+    #[napi(js_name = "pgDump", catch_unwind)]
+    pub fn pg_dump(
+        &mut self,
+        env: Env,
+        args: Vec,
+        assets: NativeToolAssets,
+    ) -> Result {
+        #[cfg(feature = "tools")]
+        {
+            let output = self.invoke_core(&env, "run WASIX pg_dump", |database| {
+                database.pg_dump_output(PgDumpOptions::new().args(args).assets(tool_assets(assets)))
+            })?;
+            native_tool_result(&env, "run WASIX pg_dump", output)
+        }
+        #[cfg(not(feature = "tools"))]
+        {
+            let _ = (env, args, assets);
+            Err(missing_release_feature("tools", "pgDump"))
+        }
+    }
+
+    #[napi(catch_unwind)]
+    pub fn psql(
+        &mut self,
+        env: Env,
+        args: Vec,
+        assets: NativeToolAssets,
+        command: Option,
+        script: Option,
+    ) -> Result {
+        if command.is_some() && script.is_some() {
+            return Err(invalid_argument(
+                "psql accepts either command or script, not both",
+            ));
+        }
+        #[cfg(feature = "tools")]
+        {
+            let options = psql_options(args, command, script).assets(tool_assets(assets));
+            let output = self.invoke_core(&env, "run WASIX psql", |database| {
+                database.psql_output(options)
+            })?;
+            native_tool_result(&env, "run WASIX psql", output)
+        }
+        #[cfg(not(feature = "tools"))]
+        {
+            let _ = (env, args, assets, command, script);
+            Err(missing_release_feature("tools", "psql"))
+        }
+    }
+
+    #[napi(catch_unwind)]
+    pub fn close(&mut self, env: Env) -> Result<()> {
+        self.invoke(&env, "close WASIX direct database", Oliphaunt::close)
+    }
+}
+
+#[derive(Default)]
+struct StreamEnvironment {
+    alive: AtomicBool,
+    active: Mutex>>,
+}
+
+impl StreamEnvironment {
+    fn new() -> Self {
+        Self {
+            alive: AtomicBool::new(true),
+            active: Mutex::new(None),
+        }
+    }
+
+    fn activate(&self, ack: Arc) -> Result<()> {
+        let mut active = self
+            .active
+            .lock()
+            .map_err(|_| Error::new(Status::GenericFailure, "stream state lock poisoned"))?;
+        if !self.alive.load(Ordering::Acquire) {
+            return Err(Error::new(
+                Status::Closing,
+                "JavaScript environment is closing",
+            ));
+        }
+        *active = Some(ack);
+        Ok(())
+    }
+
+    fn deactivate(&self, ack: &Arc) {
+        let Ok(mut active) = self.active.lock() else {
+            return;
+        };
+        if active
+            .as_ref()
+            .is_some_and(|current| Arc::ptr_eq(current, ack))
+        {
+            active.take();
+        }
+    }
+
+    fn shutdown(&self) {
+        let active = {
+            let mut active = self
+                .active
+                .lock()
+                .unwrap_or_else(|error| error.into_inner());
+            self.alive.store(false, Ordering::Release);
+            active.take()
+        };
+        if let Some(active) = active {
+            active.complete(Err(Error::new(
+                Status::Closing,
+                "JavaScript environment closed during protocol streaming",
+            )));
+        }
+    }
+}
+
+#[derive(Default)]
+struct StreamAck {
+    result: Mutex>>,
+    ready: Condvar,
+}
+
+impl StreamAck {
+    fn complete(&self, result: Result<()>) {
+        let mut slot = self
+            .result
+            .lock()
+            .unwrap_or_else(|error| error.into_inner());
+        if slot.is_none() {
+            *slot = Some(result);
+            self.ready.notify_one();
+        }
+    }
+
+    fn wait(&self) -> Result<()> {
+        let mut slot = self.result.lock().map_err(|_| {
+            Error::new(
+                Status::GenericFailure,
+                "stream acknowledgement lock poisoned",
+            )
+        })?;
+        while slot.is_none() {
+            slot = self.ready.wait(slot).map_err(|_| {
+                Error::new(
+                    Status::GenericFailure,
+                    "stream acknowledgement lock poisoned",
+                )
+            })?;
+        }
+        slot.take().expect("stream acknowledgement is present")
+    }
+}
+
+/// Promise-facing database which directly owns one `AsyncOliphaunt` actor.
+#[napi(custom_finalize)]
+pub struct NativeWasixActorDatabase {
+    database: AsyncOliphaunt,
+    stream_environment: Arc,
+}
+
+impl NativeWasixActorDatabase {
+    fn attach(env: &Env, database: AsyncOliphaunt) -> Result {
+        let stream_environment = Arc::new(StreamEnvironment::new());
+        let cleanup_environment = Arc::clone(&stream_environment);
+        let _cleanup = env.add_env_cleanup_hook(cleanup_environment, |environment| {
+            environment.shutdown();
+        })?;
+        Ok(Self {
+            database,
+            stream_environment,
+        })
+    }
+}
+
+/// Promise-facing local wire server backed by the existing Rust server owner.
+#[napi(custom_finalize)]
+pub struct NativeWasixServer {
+    server: AsyncOliphauntServer,
+}
+
+impl ObjectFinalize for NativeWasixServer {}
+
+#[napi]
+impl NativeWasixServer {
+    #[napi(catch_unwind, ts_return_type = "Promise")]
+    pub fn open(env: Env, mut options: NativeServerOpenOptions) -> Result> {
+        snapshot_resources(&mut options.seed, &mut options.icu_data);
+        let (deferred, promise) = env.create_deferred()?;
+        AsyncOliphauntServerBuilder::start_configured_with_completion(
+            move || configure_async_server(options).map_err(|error| error.reason),
+            move |result| {
+                deferred.resolve(move |env| {
+                    result
+                        .map(|server| Self { server })
+                        .map_err(|error| native_runtime_error(&env, "open WASIX server", error))
+                });
+            },
+        );
+        Ok(static_object(&env, promise))
+    }
+
+    #[napi(getter, js_name = "connectionString", catch_unwind)]
+    pub fn connection_string(&self) -> String {
+        self.server.connection_string().to_owned()
+    }
+
+    #[napi(getter, catch_unwind)]
+    pub fn closed(&self) -> bool {
+        self.server.is_closed()
+    }
+
+    #[napi(catch_unwind, ts_return_type = "Promise")]
+    pub fn close(&self, env: Env) -> Result> {
+        let server = self.server.clone();
+        let (deferred, promise) = env.create_deferred()?;
+        server.close_with_completion(move |result| {
+            deferred.resolve(move |env| {
+                result.map_err(|error| native_runtime_error(&env, "close WASIX server", error))
+            });
+        });
+        Ok(static_object(&env, promise))
+    }
+}
+
+#[napi(js_name = "restore", catch_unwind, ts_return_type = "Promise")]
+pub fn restore_database(
+    env: Env,
+    destination: String,
+    backup: Uint8ArraySlice<'_>,
+) -> Result> {
+    let destination = PathBuf::from(destination);
+    let backup = backup.as_ref().to_vec();
+    let (deferred, promise) = env.create_deferred()?;
+    AsyncOliphaunt::restore_with_completion(destination, backup, move |result| {
+        deferred.resolve(move |env| {
+            result.map_err(|error| native_runtime_error(&env, "restore WASIX database", error))
+        });
+    });
+    Ok(static_object(&env, promise))
+}
+
+#[napi(js_name = "restoreDirect", catch_unwind)]
+pub fn restore_database_direct(
+    env: Env,
+    destination: String,
+    backup: Uint8ArraySlice<'_>,
+) -> Result<()> {
+    retain_addon_image_for_process_runtime();
+    Oliphaunt::restore(PathBuf::from(destination), backup.as_ref())
+        .map_err(|error| native_runtime_error(&env, "restore WASIX database", error))
+}
+
+#[napi(js_name = "addonAbiVersion", catch_unwind)]
+pub fn addon_abi_version() -> u32 {
+    ADDON_ABI_VERSION
+}
+
+#[napi(js_name = "nodeApiVersion", catch_unwind)]
+pub fn node_api_version() -> u32 {
+    NODE_API_VERSION
+}
+
+#[napi(js_name = "runtimeVersion", catch_unwind)]
+pub fn runtime_version() -> &'static str {
+    RUNTIME_VERSION
+}
+
+#[napi(js_name = "supportedProfiles", catch_unwind)]
+pub fn supported_profiles() -> Vec<&'static str> {
+    vec!["standard", "icu"]
+}
+
+#[napi(js_name = "payloadIdentity", catch_unwind)]
+pub fn payload_identity(component: String) -> Result {
+    let manifest = embedded_portable_manifest()?;
+    match component.as_str() {
+        "runtimeArchive" => embedded_identity(
+            "runtime archive",
+            liboliphaunt_wasix_portable::runtime_archive(),
+            &manifest.runtime.sha256,
+        ),
+        _ => Err(invalid_argument(format!(
+            "unsupported WASIX payload component {component:?}"
+        ))),
+    }
+}
+
+#[napi(js_name = "extensionIdentity", catch_unwind)]
+pub fn extension_identity(sql_name: String) -> Result {
+    #[cfg(feature = "extensions")]
+    {
+        let bytes = liboliphaunt_wasix_portable::extension_archive(&sql_name).ok_or_else(|| {
+            invalid_argument(format!(
+                "WASIX extension {sql_name:?} is not embedded in this addon"
+            ))
+        })?;
+        let sha256 = liboliphaunt_wasix_portable::expected_extension_archive_sha256(&sql_name)
+            .ok_or_else(|| {
+                Error::new(
+                    Status::GenericFailure,
+                    format!("WASIX extension {sql_name:?} has no embedded SHA-256 identity"),
+                )
+            })?;
+        Ok(format!("{sha256}:{}", bytes.len()))
+    }
+    #[cfg(not(feature = "extensions"))]
+    {
+        let _ = sql_name;
+        Err(missing_release_feature("extensions", "extensionIdentity"))
+    }
+}
+
+fn configure_direct_database(options: NativeOpenOptions) -> Result {
+    let NativeOpenOptions {
+        profile,
+        storage,
+        username,
+        database,
+        startup_gucs,
+        extensions,
+        seed,
+        icu_data,
+    } = options;
+    let mut builder = Oliphaunt::builder()
+        .storage(resolve_storage(storage)?)
+        .catalog_profile(resolve_profile(&profile)?)
+        .username(username)
+        .database(database)
+        .startup_gucs(startup_gucs);
+    if let Some(seed) = seed {
+        builder = builder.seed(ClusterSeed::new(
+            seed.archive.to_vec(),
+            seed.manifest.as_ref(),
+        ));
+    }
+    if let Some(icu) = icu_data {
+        let data = IcuData::new(icu.data.to_vec(), icu.manifest.as_ref())
+            .map_err(|error| invalid_argument(format!("invalid ICU data: {error}")))?;
+        builder = builder.icu_data(data);
+    }
+    builder = apply_direct_extensions(builder, extensions)?;
+    Ok(builder)
+}
+
+fn configure_actor_database(options: NativeOpenOptions) -> Result {
+    let NativeOpenOptions {
+        profile,
+        storage,
+        username,
+        database,
+        startup_gucs,
+        extensions,
+        seed,
+        icu_data,
+    } = options;
+    let mut builder = AsyncOliphaunt::builder()
+        .storage(resolve_storage(storage)?)
+        .catalog_profile(resolve_profile(&profile)?)
+        .username(username)
+        .database(database)
+        .startup_gucs(startup_gucs);
+    if let Some(seed) = seed {
+        builder = builder.seed(ClusterSeed::new(
+            seed.archive.to_vec(),
+            seed.manifest.as_ref(),
+        ));
+    }
+    if let Some(icu) = icu_data {
+        let data = IcuData::new(icu.data.to_vec(), icu.manifest.as_ref())
+            .map_err(|error| invalid_argument(format!("invalid ICU data: {error}")))?;
+        builder = builder.icu_data(data);
+    }
+    builder = apply_async_extensions(builder, extensions)?;
+    Ok(builder)
+}
+
+fn configure_async_server(options: NativeServerOpenOptions) -> Result {
+    let NativeServerOpenOptions {
+        profile,
+        storage,
+        username,
+        database,
+        startup_gucs,
+        extensions,
+        seed,
+        icu_data,
+        listen,
+    } = options;
+    let mut builder = AsyncOliphauntServer::builder()
+        .storage(resolve_storage(storage)?)
+        .catalog_profile(resolve_profile(&profile)?)
+        .username(username)
+        .database(database)
+        .startup_gucs(startup_gucs)
+        .listen(resolve_listen(listen)?);
+    if let Some(seed) = seed {
+        builder = builder.seed(ClusterSeed::new(
+            seed.archive.to_vec(),
+            seed.manifest.as_ref(),
+        ));
+    }
+    if let Some(icu) = icu_data {
+        let data = IcuData::new(icu.data.to_vec(), icu.manifest.as_ref())
+            .map_err(|error| invalid_argument(format!("invalid ICU data: {error}")))?;
+        builder = builder.icu_data(data);
+    }
+    builder = apply_server_extensions(builder, extensions)?;
+    Ok(builder)
+}
+
+fn resolve_profile(profile: &str) -> Result {
+    match profile {
+        "standard" => Ok(CatalogProfile::Standard),
+        "icu" => Ok(CatalogProfile::Icu),
+        value => Err(invalid_argument(format!(
+            "unsupported WASIX profile {value:?}; expected \"standard\" or \"icu\""
+        ))),
+    }
+}
+
+fn resolve_storage(storage: NativeStorageOptions) -> Result {
+    match storage.kind.as_str() {
+        "memory" => {
+            if storage.path.is_some() {
+                return Err(invalid_argument("memory storage must not include path"));
+            }
+            Ok(DatabaseStorage::Memory)
+        }
+        "directory" => {
+            let path = storage
+                .path
+                .filter(|path| !path.is_empty())
+                .ok_or_else(|| invalid_argument("directory storage requires a non-empty path"))?;
+            Ok(DatabaseStorage::Directory(PathBuf::from(path)))
+        }
+        kind => Err(invalid_argument(format!(
+            "unsupported WASIX storage kind {kind:?}; expected \"memory\" or \"directory\""
+        ))),
+    }
+}
+
+fn resolve_listen(listen: NativeListenOptions) -> Result {
+    let port = listen.port.map(resolve_port).transpose()?;
+    match listen.transport.as_str() {
+        "tcp" => {
+            if listen.directory.is_some() {
+                return Err(invalid_argument(
+                    "TCP listen options must not include directory",
+                ));
+            }
+            Ok(port.map_or_else(ServerListen::tcp, ServerListen::tcp_port))
+        }
+        "unix" => {
+            #[cfg(unix)]
+            {
+                let path = listen
+                    .directory
+                    .filter(|path| !path.is_empty())
+                    .ok_or_else(|| {
+                        invalid_argument("Unix listen options require a non-empty directory")
+                    })?;
+                Ok(match port {
+                    Some(port) => ServerListen::unix_port(path, port),
+                    None => ServerListen::unix(path),
+                })
+            }
+            #[cfg(not(unix))]
+            {
+                let _ = (listen.directory, port);
+                Err(invalid_argument(
+                    "Unix-domain WASIX server listeners are not supported on Windows",
+                ))
+            }
+        }
+        kind => Err(invalid_argument(format!(
+            "unsupported WASIX server transport {kind:?}; expected \"tcp\" or \"unix\""
+        ))),
+    }
+}
+
+fn resolve_port(port: u32) -> Result {
+    u16::try_from(port)
+        .ok()
+        .filter(|port| *port != 0)
+        .ok_or_else(|| invalid_argument("server port must be in the range 1..=65535"))
+}
+
+#[cfg(feature = "extensions")]
+fn resolve_extensions(names: Vec) -> Result> {
+    names
+        .into_iter()
+        .map(|name| {
+            Extension::by_sql_name(&name).ok_or_else(|| {
+                invalid_argument(format!(
+                    "WASIX extension {name:?} is unknown or unavailable in this runtime"
+                ))
+            })
+        })
+        .collect()
+}
+
+fn apply_direct_extensions(
+    builder: OliphauntBuilder,
+    names: Vec,
+) -> Result {
+    #[cfg(feature = "extensions")]
+    {
+        Ok(builder.extensions(resolve_extensions(names)?))
+    }
+    #[cfg(not(feature = "extensions"))]
+    {
+        if names.is_empty() {
+            Ok(builder)
+        } else {
+            Err(missing_release_feature("extensions", "open"))
+        }
+    }
+}
+
+fn apply_async_extensions(
+    builder: AsyncOliphauntBuilder,
+    names: Vec,
+) -> Result {
+    #[cfg(feature = "extensions")]
+    {
+        Ok(builder.extensions(resolve_extensions(names)?))
+    }
+    #[cfg(not(feature = "extensions"))]
+    {
+        if names.is_empty() {
+            Ok(builder)
+        } else {
+            Err(missing_release_feature("extensions", "open"))
+        }
+    }
+}
+
+fn apply_server_extensions(
+    builder: AsyncOliphauntServerBuilder,
+    names: Vec,
+) -> Result {
+    #[cfg(feature = "extensions")]
+    {
+        Ok(builder.extensions(resolve_extensions(names)?))
+    }
+    #[cfg(not(feature = "extensions"))]
+    {
+        if names.is_empty() {
+            Ok(builder)
+        } else {
+            Err(missing_release_feature("extensions", "server open"))
+        }
+    }
+}
+
+#[cfg(feature = "tools")]
+fn psql_options(args: Vec, command: Option, script: Option) -> PsqlOptions {
+    let mut options = PsqlOptions::new().args(args);
+    if let Some(command) = command {
+        options = options.command(command);
+    }
+    if let Some(script) = script {
+        options = options.script(script);
+    }
+    options
+}
+
+fn static_object(env: &Env, object: Object<'_>) -> Object<'static> {
+    // `Object` is a copyable local N-API handle; its Rust lifetime only ties it
+    // to the current handle scope. The value is returned immediately to N-API
+    // and is never retained in Rust under this widened marker lifetime.
+    Object::from_raw(env.raw(), object.raw())
+}
+
+fn v8_owned_bytes(env: &Env, bytes: &[u8]) -> Result {
+    // napi-rs 3.12.2 allocates here but does not initialize the new
+    // ArrayBuffer from `bytes`; fill the V8-owned allocation explicitly.
+    let mut output = Uint8ArraySlice::copy_from(env, bytes)?;
+    // SAFETY: the new ArrayBuffer is not observable by JavaScript until this
+    // function returns, and its allocation has exactly `bytes.len()` elements.
+    unsafe { output.as_mut() }.copy_from_slice(bytes);
+    output.into_typed_array(env)
+}
+
+#[cfg(feature = "tools")]
+fn native_tool_result(
+    env: &Env,
+    operation: &'static str,
+    result: oliphaunt_wasix::Result,
+) -> Result {
+    match result {
+        Ok(output) => {
+            let (stdout, stderr) = output.into_parts();
+            Ok(NativeToolResult {
+                status: 0,
+                stdout: v8_owned_bytes(env, &stdout)?,
+                stderr: v8_owned_bytes(env, &stderr)?,
+            })
+        }
+        Err(error) => {
+            if let Some(tool) = error.tool_error()
+                && let Some(status) = tool.exit_code()
+            {
+                if status == 0 {
+                    return Err(native_tool_error(env, operation, tool));
+                }
+                return Ok(NativeToolResult {
+                    status,
+                    stdout: v8_owned_bytes(env, tool.stdout_bytes())?,
+                    stderr: v8_owned_bytes(env, tool.stderr_bytes())?,
+                });
+            }
+            Err(native_runtime_error(env, operation, error))
+        }
+    }
+}
+
+fn invalid_argument(reason: impl Into) -> Error {
+    Error::new(Status::InvalidArg, reason.into())
+}
+
+#[cfg(any(not(feature = "tools"), not(feature = "extensions")))]
+fn missing_release_feature(feature: &str, operation: &str) -> Error {
+    Error::new(
+        Status::GenericFailure,
+        format!("WASIX N-API {operation} requires an addon built with the {feature} feature"),
+    )
+}
+
+fn native_runtime_error(
+    env: &Env,
+    operation: &'static str,
+    error: oliphaunt_wasix::Error,
+) -> Error {
+    if error.kind() == ErrorKind::Storage
+        && let Some(details) = error.storage_error()
+    {
+        return native_storage_error(
+            env,
+            operation,
+            &error,
+            details.code(),
+            details.commit_state(),
+            details.phase(),
+        );
+    }
+    let (marker, code) = match error.kind() {
+        ErrorKind::InvalidConfiguration => ("configuration", "invalid-configuration"),
+        ErrorKind::Lifecycle => ("lifecycle", "lifecycle"),
+        ErrorKind::TransactionActive => ("transaction", "transaction-active"),
+        ErrorKind::Postgres => ("postgres", "postgres-error"),
+        ErrorKind::Storage => ("runtime", "unclassified-storage-error"),
+        ErrorKind::Other => ("runtime", "runtime-error"),
+        _ => ("runtime", "runtime-error"),
+    };
+    native_tagged_error(
+        env,
+        "OliphauntWasixError",
+        marker,
+        code,
+        operation,
+        format!("{operation}: {error}"),
+    )
+}
+
+fn native_lifecycle_error(env: &Env, operation: &'static str, reason: &'static str) -> Error {
+    native_tagged_error(
+        env,
+        "OliphauntWasixError",
+        "lifecycle",
+        "lifecycle",
+        operation,
+        format!("{operation}: {reason}"),
+    )
+}
+
+fn native_tagged_error(
+    env: &Env,
+    name: &'static str,
+    marker: &'static str,
+    code: &'static str,
+    operation: &'static str,
+    reason: String,
+) -> Error {
+    let tagged = (|| -> Result {
+        let mut object = env.create_error(Error::new(Status::GenericFailure, reason.clone()))?;
+        object.set_named_property("name", name)?;
+        object.set_named_property("oliphauntWasixError", marker)?;
+        object.set_named_property("oliphauntWasixAddonAbi", ADDON_ABI_VERSION)?;
+        object.set_named_property("code", code)?;
+        object.set_named_property("operation", operation)?;
+        Ok(Error::from_unknown_without_coercion(
+            object.into_unknown(env)?,
+        ))
+    })();
+    tagged.unwrap_or_else(|tag_error| {
+        Error::new(
+            Status::GenericFailure,
+            format!("{reason}; construct structured native error: {tag_error}"),
+        )
+    })
+}
+
+fn native_storage_error(
+    env: &Env,
+    operation: &'static str,
+    error: &oliphaunt_wasix::Error,
+    code: StorageErrorCode,
+    commit_state: StorageCommitState,
+    phase: StorageErrorPhase,
+) -> Error {
+    let reason = format!("{operation}: {error}");
+    let tagged = (|| -> Result {
+        let mut object = env.create_error(Error::new(Status::GenericFailure, reason.clone()))?;
+        object.set_named_property("name", "OliphauntWasixStorageError")?;
+        object.set_named_property("oliphauntWasixError", "storage")?;
+        object.set_named_property("oliphauntWasixAddonAbi", ADDON_ABI_VERSION)?;
+        object.set_named_property("code", storage_code(code))?;
+        object.set_named_property("commitState", storage_commit_state(commit_state))?;
+        object.set_named_property("phase", storage_phase(phase))?;
+        object.set_named_property("operation", operation)?;
+        Ok(Error::from_unknown_without_coercion(
+            object.into_unknown(env)?,
+        ))
+    })();
+    tagged.unwrap_or_else(|tag_error| {
+        Error::new(
+            Status::GenericFailure,
+            format!("{reason}; construct structured storage error: {tag_error}"),
+        )
+    })
+}
+
+#[cfg(feature = "tools")]
+fn native_tool_error(
+    env: &Env,
+    operation: &'static str,
+    tool: &oliphaunt_wasix::tools::PostgresToolError,
+) -> Error {
+    let reason = format!("{operation}: {tool}");
+    let tagged = (|| -> Result {
+        let mut object = env.create_error(Error::new(Status::GenericFailure, reason.clone()))?;
+        object.set_named_property("name", "OliphauntWasixToolError")?;
+        object.set_named_property("oliphauntWasixError", "tool")?;
+        object.set_named_property("oliphauntWasixAddonAbi", ADDON_ABI_VERSION)?;
+        object.set_named_property("code", "tool-error")?;
+        object.set_named_property("operation", operation)?;
+        object.set_named_property("tool", tool.tool())?;
+        object.set_named_property("exitCode", tool.exit_code())?;
+        object.set_named_property("stdout", v8_owned_bytes(env, tool.stdout_bytes())?)?;
+        object.set_named_property("stderr", v8_owned_bytes(env, tool.stderr_bytes())?)?;
+        Ok(Error::from_unknown_without_coercion(
+            object.into_unknown(env)?,
+        ))
+    })();
+    tagged.unwrap_or_else(|tag_error| {
+        Error::new(
+            Status::GenericFailure,
+            format!("{reason}; construct structured tool error: {tag_error}"),
+        )
+    })
+}
+
+fn storage_code(code: StorageErrorCode) -> &'static str {
+    match code {
+        StorageErrorCode::Busy => "busy",
+        StorageErrorCode::Corrupt => "corrupt",
+        StorageErrorCode::Incomplete => "incomplete",
+        StorageErrorCode::Incompatible => "incompatible",
+        StorageErrorCode::PublicationFailed => "publication-failed",
+        StorageErrorCode::Unavailable => "unavailable",
+        _ => "unavailable",
+    }
+}
+
+fn storage_commit_state(state: StorageCommitState) -> &'static str {
+    match state {
+        StorageCommitState::NotPersisted => "not-persisted",
+        StorageCommitState::Persisted => "persisted",
+        StorageCommitState::Unchanged => "unchanged",
+        StorageCommitState::Unknown => "unknown",
+        _ => "unknown",
+    }
+}
+
+fn storage_phase(phase: StorageErrorPhase) -> &'static str {
+    match phase {
+        StorageErrorPhase::Ownership => "ownership",
+        StorageErrorPhase::Open => "open",
+        StorageErrorPhase::OpenPublication => "open-publication",
+        StorageErrorPhase::Operation => "operation",
+        StorageErrorPhase::Backup => "backup",
+        StorageErrorPhase::Close => "close",
+        StorageErrorPhase::RestoreValidation => "restore-validation",
+        StorageErrorPhase::RestoreStaging => "restore-staging",
+        StorageErrorPhase::RestorePublication => "restore-publication",
+        StorageErrorPhase::RestoreDurability => "restore-durability",
+        _ => "operation",
+    }
+}
+
+fn embedded_portable_manifest() -> Result<&'static liboliphaunt_wasix_portable::AssetManifest> {
+    static MANIFEST: OnceLock<
+        std::result::Result,
+    > = OnceLock::new();
+    match MANIFEST
+        .get_or_init(|| liboliphaunt_wasix_portable::manifest().map_err(|error| error.to_string()))
+    {
+        Ok(manifest) => Ok(manifest),
+        Err(error) => Err(Error::new(
+            Status::GenericFailure,
+            format!("parse embedded WASIX payload manifest: {error}"),
+        )),
+    }
+}
+
+fn embedded_identity(label: &str, bytes: Option<&[u8]>, sha256: &str) -> Result {
+    let bytes = bytes.ok_or_else(|| {
+        Error::new(
+            Status::GenericFailure,
+            format!("WASIX {label} is not embedded in this addon"),
+        )
+    })?;
+    Ok(format!("{sha256}:{}", bytes.len()))
+}
+
+#[cfg(test)]
+mod tests {
+    use std::sync::atomic::AtomicUsize;
+
+    use super::*;
+
+    struct DropCounter {
+        drops: Arc,
+        closed: bool,
+    }
+
+    impl Drop for DropCounter {
+        fn drop(&mut self) {
+            self.drops.fetch_add(1, Ordering::SeqCst);
+        }
+    }
+
+    #[test]
+    fn environment_finalizer_drops_closed_and_quarantines_open_owners() {
+        let drops = Arc::new(AtomicUsize::new(0));
+        let mut open = Some(DropCounter {
+            drops: Arc::clone(&drops),
+            closed: false,
+        });
+        drop_if_closed_or_quarantine(&mut open, |value| value.closed);
+        assert!(open.is_none());
+        assert_eq!(drops.load(Ordering::SeqCst), 0);
+
+        let mut closed = Some(DropCounter {
+            drops: Arc::clone(&drops),
+            closed: true,
+        });
+        drop_if_closed_or_quarantine(&mut closed, |value| value.closed);
+        assert!(closed.is_none());
+        assert_eq!(drops.load(Ordering::SeqCst), 1);
+    }
+
+    #[test]
+    fn profile_selection_is_explicit() {
+        assert_eq!(
+            resolve_profile("standard").unwrap(),
+            CatalogProfile::Standard
+        );
+        assert_eq!(resolve_profile("icu").unwrap(), CatalogProfile::Icu);
+        assert!(resolve_profile("default").is_err());
+    }
+
+    #[test]
+    fn directory_storage_requires_path() {
+        let error = resolve_storage(NativeStorageOptions {
+            kind: "directory".to_owned(),
+            path: None,
+        })
+        .unwrap_err();
+        assert!(error.reason.contains("requires a non-empty path"));
+    }
+
+    #[test]
+    fn explicit_zero_port_is_rejected() {
+        let error = resolve_port(0).unwrap_err();
+        assert!(error.reason.contains("1..=65535"));
+    }
+}
+
+// Dropping these fields never joins the owner thread. AsyncOliphaunt's final
+// Arc sends its existing best-effort Shutdown control and returns immediately.
+impl ObjectFinalize for NativeWasixActorDatabase {}
+
+#[napi]
+impl NativeWasixActorDatabase {
+    #[napi(catch_unwind, ts_return_type = "Promise")]
+    pub fn open(env: Env, mut options: NativeOpenOptions) -> Result> {
+        snapshot_resources(&mut options.seed, &mut options.icu_data);
+        let (deferred, promise) = env.create_deferred()?;
+        AsyncOliphauntBuilder::open_configured_with_completion(
+            move || configure_actor_database(options).map_err(|error| error.reason),
+            move |result| {
+                deferred.resolve(move |env| {
+                    let database = result.map_err(|error| {
+                        native_runtime_error(&env, "open WASIX actor database", error)
+                    })?;
+                    Self::attach(&env, database)
+                });
+            },
+        );
+        Ok(static_object(&env, promise))
+    }
+
+    #[napi(getter, catch_unwind)]
+    pub fn closed(&self) -> bool {
+        self.database.is_closed()
+    }
+
+    #[napi(
+        js_name = "execProtocolRaw",
+        catch_unwind,
+        ts_return_type = "Promise"
+    )]
+    pub fn exec_protocol_raw(
+        &self,
+        env: Env,
+        request: Uint8ArraySlice<'_>,
+    ) -> Result> {
+        let request = request.as_ref().to_vec();
+        let database = self.database.clone();
+        let (deferred, promise) = env.create_deferred()?;
+        database.exec_protocol_raw_with_completion(request, move |result| {
+            deferred.resolve(move |env| {
+                let response = result.map_err(|error| {
+                    native_runtime_error(&env, "execute PostgreSQL protocol request", error)
+                })?;
+                v8_owned_bytes(&env, &response)
+            });
+        });
+        Ok(static_object(&env, promise))
+    }
+
+    #[napi(
+        js_name = "execProtocolRawStream",
+        catch_unwind,
+        ts_return_type = "Promise<'complete' | 'callbackAborted'>"
+    )]
+    pub fn exec_protocol_raw_stream(
+        &self,
+        env: Env,
+        request: Uint8ArraySlice<'_>,
+        on_chunk: Function<'_, Uint8Array, ()>,
+    ) -> Result> {
+        let request = request.as_ref().to_vec();
+        let stream_environment = Arc::clone(&self.stream_environment);
+        let callback_environment = Arc::clone(&stream_environment);
+        let threadsafe = on_chunk
+            .build_threadsafe_function::>()
+            .max_queue_size::<1>()
+            .build_callback(|context: ThreadsafeCallContext>| {
+                v8_owned_bytes(&context.env, &context.value)
+            })?;
+        let database = self.database.clone();
+        let (deferred, promise) = env.create_deferred()?;
+        database.exec_protocol_raw_stream_with_completion(
+            request,
+            move |chunk| {
+                let ack = Arc::new(StreamAck::default());
+                callback_environment.activate(Arc::clone(&ack))?;
+                let callback_ack = Arc::clone(&ack);
+                let status = threadsafe.call_with_return_value(
+                    chunk.to_vec(),
+                    ThreadsafeFunctionCallMode::Blocking,
+                    move |result, _env| {
+                        callback_ack.complete(result.map(|_| ()));
+                        Ok(())
+                    },
+                );
+                if status != Status::Ok {
+                    ack.complete(Err(Error::new(
+                        status,
+                        "queue protocol chunk on the JavaScript thread",
+                    )));
+                }
+                let result = ack.wait();
+                callback_environment.deactivate(&ack);
+                result
+            },
+            move |result| {
+                deferred.resolve(move |env| match result {
+                    Ok(()) => Ok("complete"),
+                    Err(RawStreamError::Callback(_)) => Ok("callbackAborted"),
+                    Err(RawStreamError::Database(error)) => Err(native_runtime_error(
+                        &env,
+                        "stream PostgreSQL protocol response",
+                        error,
+                    )),
+                    Err(RawStreamError::CallbackPanicked(error)) => Err(native_runtime_error(
+                        &env,
+                        "stream PostgreSQL protocol callback",
+                        error,
+                    )),
+                    Err(_) => Err(Error::new(
+                        Status::GenericFailure,
+                        "stream PostgreSQL protocol response: unknown stream error",
+                    )),
+                });
+            },
+        );
+        Ok(static_object(&env, promise))
+    }
+
+    #[napi(catch_unwind, ts_return_type = "Promise")]
+    pub fn backup(&self, env: Env) -> Result> {
+        let database = self.database.clone();
+        let (deferred, promise) = env.create_deferred()?;
+        database.backup_with_completion(move |result| {
+            deferred.resolve(move |env| {
+                let backup = result
+                    .map_err(|error| native_runtime_error(&env, "back up WASIX database", error))?;
+                v8_owned_bytes(&env, &backup)
+            });
+        });
+        Ok(static_object(&env, promise))
+    }
+
+    #[napi(
+        js_name = "pgDump",
+        catch_unwind,
+        ts_return_type = "Promise"
+    )]
+    pub fn pg_dump(
+        &self,
+        env: Env,
+        args: Vec,
+        assets: NativeToolAssets,
+    ) -> Result> {
+        #[cfg(feature = "tools")]
+        {
+            let database = self.database.clone();
+            let (deferred, promise) = env.create_deferred()?;
+            database.pg_dump_output_with_completion(
+                PgDumpOptions::new().args(args).assets(tool_assets(assets)),
+                move |result| {
+                    deferred
+                        .resolve(move |env| native_tool_result(&env, "run WASIX pg_dump", result));
+                },
+            );
+            Ok(static_object(&env, promise))
+        }
+        #[cfg(not(feature = "tools"))]
+        {
+            let _ = (env, args, assets);
+            Err(missing_release_feature("tools", "pgDump"))
+        }
+    }
+
+    #[napi(catch_unwind, ts_return_type = "Promise")]
+    pub fn psql(
+        &self,
+        env: Env,
+        args: Vec,
+        assets: NativeToolAssets,
+        command: Option,
+        script: Option,
+    ) -> Result> {
+        if command.is_some() && script.is_some() {
+            return Err(invalid_argument(
+                "psql accepts either command or script, not both",
+            ));
+        }
+        #[cfg(feature = "tools")]
+        {
+            let database = self.database.clone();
+            let (deferred, promise) = env.create_deferred()?;
+            database.psql_output_with_completion(
+                psql_options(args, command, script).assets(tool_assets(assets)),
+                move |result| {
+                    deferred.resolve(move |env| native_tool_result(&env, "run WASIX psql", result));
+                },
+            );
+            Ok(static_object(&env, promise))
+        }
+        #[cfg(not(feature = "tools"))]
+        {
+            let _ = (env, args, assets, command, script);
+            Err(missing_release_feature("tools", "psql"))
+        }
+    }
+
+    #[napi(catch_unwind, ts_return_type = "Promise")]
+    pub fn close(&self, env: Env) -> Result> {
+        let database = self.database.clone();
+        let (deferred, promise) = env.create_deferred()?;
+        database.close_with_completion(move |result| {
+            deferred.resolve(move |env| {
+                result.map_err(|error| {
+                    native_runtime_error(&env, "close WASIX actor database", error)
+                })
+            });
+        });
+        Ok(static_object(&env, promise))
+    }
+}
diff --git a/src/sdks/ts-wasix/node-addon/tests/native.integration.mts b/src/sdks/ts-wasix/node-addon/tests/native.integration.mts
new file mode 100644
index 000000000..747a7af35
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tests/native.integration.mts
@@ -0,0 +1,252 @@
+import assert from 'node:assert/strict';
+import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
+import { createRequire } from 'node:module';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { Worker } from 'node:worker_threads';
+
+const addonPath = process.argv[2];
+if (addonPath === undefined) {
+  throw new Error('usage: node native.integration.mts /absolute/path/to/addon.node [--tools]');
+}
+
+const addon = createRequire(import.meta.url)(addonPath);
+const expectedExports = [
+  'NativeWasixActorDatabase',
+  'NativeWasixDatabase',
+  'NativeWasixServer',
+  'addonAbiVersion',
+  'extensionIdentity',
+  'nodeApiVersion',
+  'payloadIdentity',
+  'restore',
+  'restoreDirect',
+  'runtimeVersion',
+  'supportedProfiles',
+];
+assert.deepEqual(Object.keys(addon).sort(), expectedExports);
+assert.equal(addon.addonAbiVersion(), 2);
+assert.equal(addon.nodeApiVersion(), 8);
+assert.deepEqual(addon.supportedProfiles(), ['standard', 'icu']);
+
+const openOptions = (profile = 'standard', storage = { kind: 'memory' }) => ({
+  profile,
+  storage,
+  username: 'postgres',
+  database: 'postgres',
+  startupGucs: {},
+  extensions: [],
+});
+
+const queryMessage = (sql) => {
+  const text = Buffer.from(`${sql}\0`);
+  const request = Buffer.alloc(5 + text.length);
+  request[0] = 0x51;
+  request.writeUInt32BE(4 + text.length, 1);
+  text.copy(request, 5);
+  return request;
+};
+
+const assertResponse = (response, value) => {
+  assert(response instanceof Uint8Array);
+  assert(Buffer.from(response).includes(Buffer.from(String(value))));
+};
+
+const assertTransferable = (bytes) => {
+  assert(bytes instanceof Uint8Array);
+  const expected = Uint8Array.from(bytes);
+  const moved = structuredClone(bytes, { transfer: [bytes.buffer] });
+  assert.equal(bytes.byteLength, 0, 'V8 must detach the source ArrayBuffer');
+  assert.deepEqual(moved, expected, 'transfer must preserve every output byte');
+  return moved;
+};
+
+for (const server of [false, true]) {
+  const backing = Buffer.from('padding:invalid-manifest:padding');
+  const manifest = backing.subarray(8, 24);
+  const options = {
+    ...openOptions(),
+    icuData: { data: Uint8Array.from([1, 2, 3]), manifest },
+    ...(server ? { listen: { transport: 'tcp', port: 54321 } } : {}),
+  };
+  let opening;
+  assert.doesNotThrow(() => {
+    opening = server
+      ? addon.NativeWasixServer.open(options)
+      : addon.NativeWasixActorDatabase.open(options);
+  }, 'resource preparation errors must reject the asynchronous open');
+  manifest.fill(10);
+  await assert.rejects(opening, /invalid ICU manifest entry/u);
+}
+if (process.argv.includes('--resource-preparation-only')) process.exit(0);
+
+const direct = addon.NativeWasixDatabase.open(openOptions());
+const directResponse = direct.execProtocolRaw(queryMessage('select 4101'));
+assertResponse(directResponse, 4101);
+assertTransferable(directResponse);
+const directChunks = [];
+assert.equal(
+  direct.execProtocolRawStream(queryMessage('select 4102'), (chunk) => {
+    assertResponse(chunk, 4102);
+    directChunks.push(assertTransferable(chunk));
+  }),
+  'complete',
+);
+assert(Buffer.concat(directChunks.map(Buffer.from)).includes(Buffer.from('4102')));
+let directReentryError;
+assert.equal(
+  direct.execProtocolRawStream(queryMessage('select 4103'), () => {
+    try {
+      direct.close();
+    } catch (error) {
+      directReentryError = error;
+    }
+  }),
+  'complete',
+);
+assert(
+  directReentryError instanceof Error,
+  'napi-rs must reject a synchronous mutable reentry while the stream callback is active',
+);
+assert.match(directReentryError.message, /borrow(?:ed|ing)|mutabl/iu);
+assertResponse(direct.execProtocolRaw(queryMessage('select 4104')), 4104);
+const directBackup = direct.backup();
+const restoreBackup = Uint8Array.from(directBackup);
+assert(directBackup.byteLength > 0);
+assertTransferable(directBackup);
+direct.close();
+assert.equal(direct.closed, true);
+
+const actor = await addon.NativeWasixActorDatabase.open(openOptions());
+const actorResponse = await actor.execProtocolRaw(queryMessage('select 4201'));
+assertResponse(actorResponse, 4201);
+assertTransferable(actorResponse);
+const actorChunks = [];
+assert.equal(
+  await actor.execProtocolRawStream(queryMessage('select 4202'), (chunk) => {
+    actorChunks.push(assertTransferable(chunk));
+  }),
+  'complete',
+);
+assert(Buffer.concat(actorChunks.map(Buffer.from)).includes(Buffer.from('4202')));
+assert.equal(
+  await actor.execProtocolRawStream(queryMessage('select 4203'), () => {
+    throw new Error('intentional stream stop');
+  }),
+  'callbackAborted',
+);
+assertResponse(await actor.execProtocolRaw(queryMessage('select 4204')), 4204);
+
+if (process.argv.includes('--tools')) {
+  const portableRoot = process.env.OLIPHAUNT_WASIX_TOOLS_PORTABLE_ROOT;
+  const aotRoot = process.env.OLIPHAUNT_WASIX_TOOLS_AOT_ROOT;
+  assert(portableRoot && aotRoot, '--tools requires explicit portable and AOT tool asset roots');
+  const manifest = readFileSync(join(aotRoot, 'manifest.json'), 'utf8');
+  const artifact = JSON.parse(manifest).artifacts.find(({ name }) => name === 'tool:pg_dump');
+  assert(artifact, 'AOT manifest must contain pg_dump');
+  const dump = await actor.pgDump([], {
+    wasm: readFileSync(join(portableRoot, 'bin/pg_dump.wasix.wasm')),
+    aot: readFileSync(join(aotRoot, artifact.path)),
+    manifest,
+  });
+  assert.equal(dump.status, 0);
+  assert(dump.stdout.byteLength > 0);
+  assertTransferable(dump.stdout);
+  assertTransferable(dump.stderr);
+}
+
+await Promise.all([actor.close(), actor.close()]);
+assert.equal(actor.closed, true);
+await assert.rejects(actor.execProtocolRaw(queryMessage('select 1')), (error) => {
+  assert.equal(error.oliphauntWasixError, 'lifecycle');
+  assert.equal(error.oliphauntWasixAddonAbi, 2);
+  return true;
+});
+
+const server = await addon.NativeWasixServer.open({
+  ...openOptions(),
+  listen: { transport: 'tcp' },
+});
+assert.match(server.connectionString, /^postgresql:\/\//u);
+await Promise.all([server.close(), server.close()]);
+assert.equal(server.closed, true);
+
+const icuRoot = process.env.OLIPHAUNT_TEST_ICU_ROOT;
+assert.ok(icuRoot, 'OLIPHAUNT_TEST_ICU_ROOT must point to separately produced ICU data');
+const icu = await addon.NativeWasixActorDatabase.open({
+  ...openOptions('icu'),
+  icuData: {
+    data: readFileSync(join(icuRoot, 'share/icu/icudt76l.dat')),
+    manifest: readFileSync(join(icuRoot, 'manifest.properties')),
+  },
+});
+assertResponse(await icu.execProtocolRaw(queryMessage('select 4301')), 4301);
+await icu.close();
+
+const temporaryRoot = mkdtempSync(join(tmpdir(), 'oliphaunt-wasix-napi-'));
+try {
+  const restored = join(temporaryRoot, 'restored-actor');
+  await addon.restore(restored, restoreBackup);
+  const restoredActor = await addon.NativeWasixActorDatabase.open(
+    openOptions('standard', { kind: 'directory', path: restored }),
+  );
+  assertResponse(await restoredActor.execProtocolRaw(queryMessage('select 4401')), 4401);
+  await assert.rejects(
+    addon.NativeWasixActorDatabase.open(
+      openOptions('standard', { kind: 'directory', path: restored }),
+    ),
+    (error) => {
+      assert.equal(error.name, 'OliphauntWasixStorageError');
+      assert.equal(error.oliphauntWasixError, 'storage');
+      assert.equal(error.oliphauntWasixAddonAbi, 2);
+      assert.equal(error.code, 'busy');
+      assert.equal(error.commitState, 'unchanged');
+      assert.equal(error.phase, 'ownership');
+      return true;
+    },
+  );
+  await restoredActor.close();
+
+  const restoredDirectPath = join(temporaryRoot, 'restored-direct');
+  addon.restoreDirect(restoredDirectPath, restoreBackup);
+  const restoredDirect = addon.NativeWasixDatabase.open(
+    openOptions('standard', { kind: 'directory', path: restoredDirectPath }),
+  );
+  assertResponse(restoredDirect.execProtocolRaw(queryMessage('select 4402')), 4402);
+  restoredDirect.close();
+} finally {
+  rmSync(temporaryRoot, { recursive: true, force: true });
+}
+
+const worker = new Worker(
+  `
+    const { parentPort, workerData } = require('node:worker_threads');
+    const addon = require(workerData.addonPath);
+    const options = ${JSON.stringify(openOptions())};
+    addon.NativeWasixActorDatabase.open(options).then((database) => {
+      globalThis.database = database;
+      const text = Buffer.from('select 4501\\0');
+      const request = Buffer.alloc(5 + text.length);
+      request[0] = 0x51;
+      request.writeUInt32BE(4 + text.length, 1);
+      text.copy(request, 5);
+      void database.execProtocolRawStream(request, () => {
+        parentPort.postMessage('stream-entered');
+        Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 60_000);
+      }).catch(() => undefined);
+    }, (error) => { throw error; });
+  `,
+  { eval: true, workerData: { addonPath } },
+);
+await new Promise((resolve, reject) => {
+  worker.once('message', resolve);
+  worker.once('error', reject);
+});
+await Promise.race([
+  worker.terminate(),
+  new Promise((_, reject) => {
+    setTimeout(() => reject(new Error('worker teardown blocked on actor stream')), 10_000).unref();
+  }),
+]);
+
+console.log('WASIX N-API native integration passed');
diff --git a/tools/release/build-linux-wasix-napi-baseline.sh b/src/sdks/ts-wasix/node-addon/tools/build-linux-wasix-napi-baseline.sh
similarity index 96%
rename from tools/release/build-linux-wasix-napi-baseline.sh
rename to src/sdks/ts-wasix/node-addon/tools/build-linux-wasix-napi-baseline.sh
index b289592ef..6691e9163 100755
--- a/tools/release/build-linux-wasix-napi-baseline.sh
+++ b/src/sdks/ts-wasix/node-addon/tools/build-linux-wasix-napi-baseline.sh
@@ -16,7 +16,7 @@ require() {
 }
 
 if [ "$#" -ne 3 ]; then
-  fail "usage: tools/release/build-linux-wasix-napi-baseline.sh TARGET_DIR TARGET_TRIPLE FEATURES"
+  fail "usage: src/sdks/ts-wasix/node-addon/tools/build-linux-wasix-napi-baseline.sh TARGET_DIR TARGET_TRIPLE FEATURES"
 fi
 if [ "$(uname -s)" != "Linux" ]; then
   fail "the Linux WASIX Node-API baseline build must run on Linux"
@@ -46,7 +46,7 @@ readonly rust_release="1.93.1"
 readonly rust_commit="01f6ddf7588f42ae2d7eb0a2f21d44e8e96674cf"
 readonly rust_toolchain="${rust_release}-${rust_host}"
 readonly expected_builder_glibc="glibc 2.36"
-readonly manifest="/workspace/src/runtimes/wasix-napi/Cargo.toml"
+readonly manifest="/workspace/src/sdks/ts-wasix/node-addon/Cargo.toml"
 
 case "$target_dir" in
   /*) ;;
@@ -78,7 +78,6 @@ workspace_path() {
 generated_assets="$(workspace_path OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR)"
 generated_aot="$(workspace_path OLIPHAUNT_WASM_GENERATED_AOT_DIR)"
 extension_artifacts="$(workspace_path OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT)"
-icu_data="$(workspace_path OLIPHAUNT_ICU_DATA_DIR)"
 build_inputs="$(workspace_path OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS)"
 
 cargo_root="${CARGO_HOME:-$HOME/.cargo}"
@@ -144,7 +143,6 @@ docker_cargo() {
     --env "OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR=$generated_assets" \
     --env "OLIPHAUNT_WASM_GENERATED_AOT_DIR=$generated_aot" \
     --env "OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT=$extension_artifacts" \
-    --env "OLIPHAUNT_ICU_DATA_DIR=$icu_data" \
     --env "OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS=$build_inputs" \
     --env "EXPECTED_BUILDER_GLIBC=$expected_builder_glibc" \
     --env "EXPECTED_RUST_RELEASE=$rust_release" \
diff --git a/src/sdks/ts-wasix/node-addon/tools/build-native.sh b/src/sdks/ts-wasix/node-addon/tools/build-native.sh
new file mode 100755
index 000000000..6f0062687
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/build-native.sh
@@ -0,0 +1,200 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+workspace_root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$workspace_root"
+
+require_command() {
+  if ! command -v "$1" >/dev/null 2>&1; then
+    echo "missing required command: $1" >&2
+    exit 1
+  fi
+}
+
+require_command cargo
+require_command git
+require_command node
+require_command bun
+
+host_system="$(uname -s)"
+host_machine="$(uname -m)"
+if [[ "$host_system" == "Linux" ]]; then
+  linux_libc="$(node src/sdks/ts-wasix/node-addon/tools/detect-linux-libc.mts)"
+  case "$linux_libc" in
+    glibc) ;;
+    musl)
+      echo "WASIX N-API native addons do not support Linux musl; use a glibc build host" >&2
+      exit 2
+      ;;
+    *)
+      echo "WASIX N-API could not verify that this Linux build host uses glibc" >&2
+      exit 2
+      ;;
+  esac
+fi
+
+target_id="${1:-${OLIPHAUNT_WASIX_NAPI_TARGET:-}}"
+if [[ -z "$target_id" ]]; then
+  case "$host_system:$host_machine" in
+    Darwin:arm64 | Darwin:aarch64) target_id="macos-arm64" ;;
+    Linux:x86_64 | Linux:amd64) target_id="linux-x64-gnu" ;;
+    Linux:arm64 | Linux:aarch64) target_id="linux-arm64-gnu" ;;
+    MINGW*:x86_64 | MSYS*:x86_64 | CYGWIN*:x86_64) target_id="windows-x64-msvc" ;;
+    *)
+      echo "unsupported WASIX N-API host: $(uname -s)/$(uname -m)" >&2
+      exit 2
+      ;;
+  esac
+fi
+
+case "$target_id" in
+  macos-arm64)
+    cargo_target="aarch64-apple-darwin"
+    library_name="liboliphaunt_wasix_napi.dylib"
+    ;;
+  linux-arm64-gnu)
+    cargo_target="aarch64-unknown-linux-gnu"
+    library_name="liboliphaunt_wasix_napi.so"
+    ;;
+  linux-x64-gnu)
+    cargo_target="x86_64-unknown-linux-gnu"
+    library_name="liboliphaunt_wasix_napi.so"
+    ;;
+  windows-x64-msvc)
+    cargo_target="x86_64-pc-windows-msvc"
+    library_name="oliphaunt_wasix_napi.dll"
+    ;;
+  *)
+    echo "unsupported WASIX N-API target: $target_id" >&2
+    exit 2
+    ;;
+esac
+
+source_sha="$(git rev-parse HEAD)"
+artifact_source_sha="${OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA:-$source_sha}"
+if [[ ! "$artifact_source_sha" =~ ^[0-9a-f]{40}$ ]]; then
+  echo "OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA must be a lowercase 40-character Git SHA" >&2
+  exit 2
+fi
+
+manifest="src/sdks/ts-wasix/node-addon/Cargo.toml"
+package_manifest="src/sdks/ts-wasix/node-addon/package.json"
+metadata_contract="$(
+  bun "$workspace_root/src/sdks/ts-wasix/node-addon/tools/native-build-data.mts" metadata "$package_manifest"
+)"
+IFS=$'\t' read -r expected_runtime_version expected_addon_abi expected_node_api <<<"$metadata_contract"
+product_target_root="${OLIPHAUNT_WASIX_NAPI_BUILD_ROOT:-$workspace_root/target/oliphaunt-wasix-napi}"
+prebuild_dir="$product_target_root/prebuilds/$target_id"
+cargo_target_dir="$product_target_root/cargo-release"
+build_inputs_file="$product_target_root/build-inputs/$target_id.json"
+mkdir -p "$prebuild_dir"
+
+# Release addons must consume the exact portable runtime, target AOT, exact
+# extension, and ICU payloads staged by the same CI run. Export the canonical
+# dependency build-script variables explicitly so no source-only fallback can
+# be selected through a package-local or stale workspace probe.
+export OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR="${OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR:-$workspace_root/target/oliphaunt-wasix/assets}"
+export OLIPHAUNT_WASM_GENERATED_AOT_DIR="${OLIPHAUNT_WASM_GENERATED_AOT_DIR:-$workspace_root/target/oliphaunt-wasix/aot}"
+export OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="${OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT:-$workspace_root/target/extension-artifacts}"
+export OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD=1
+export OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS="$build_inputs_file"
+
+build_input_args=(
+  --target "$target_id"
+  --target-triple "$cargo_target"
+  --portable-root "$OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR"
+  --aot-root "$OLIPHAUNT_WASM_GENERATED_AOT_DIR"
+  --extension-root "$OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT"
+)
+tools/dev/bun.sh src/sdks/ts-wasix/node-addon/tools/check-build-inputs.mts \
+  "${build_input_args[@]}" \
+  --output "$build_inputs_file"
+
+# Release profile environment variables work whether the crate is built as a
+# workspace member or through its manifest directly.
+export CARGO_INCREMENTAL=0
+export CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1
+export CARGO_PROFILE_RELEASE_LTO=thin
+export CARGO_PROFILE_RELEASE_STRIP=symbols
+
+build_addon() {
+  local output="$1"
+
+  echo "building WASIX N-API addon for $target_id ($cargo_target)"
+  if [[ "$target_id" == linux-*-gnu ]]; then
+    src/sdks/ts-wasix/node-addon/tools/build-linux-wasix-napi-baseline.sh \
+      "$cargo_target_dir" \
+      "$cargo_target" \
+      release
+  else
+    CARGO_TARGET_DIR="$cargo_target_dir" cargo build \
+      --locked \
+      --manifest-path "$manifest" \
+      --target "$cargo_target" \
+      --release \
+      --no-default-features \
+      --features release
+  fi
+
+  local library="$cargo_target_dir/$cargo_target/release/$library_name"
+  if [[ ! -f "$library" ]]; then
+    echo "Cargo did not produce expected addon library: $library" >&2
+    exit 1
+  fi
+  cp "$library" "$output"
+}
+
+addon="$prebuild_dir/oliphaunt_wasix_napi.node"
+build_addon "$addon"
+
+# Recompute the complete input inventory after compilation so packaging
+# cannot attest to payloads that changed during compilation.
+tools/dev/bun.sh src/sdks/ts-wasix/node-addon/tools/check-build-inputs.mts \
+  "${build_input_args[@]}" \
+  --check "$build_inputs_file"
+
+# Loading a foreign-target addon is impossible. For a host build, validate the
+# complete stable N-API contract before it can be packaged.
+host_target=""
+case "$host_system:$host_machine" in
+  Darwin:arm64 | Darwin:aarch64) host_target="macos-arm64" ;;
+  Linux:x86_64 | Linux:amd64) host_target="linux-x64-gnu" ;;
+  Linux:arm64 | Linux:aarch64) host_target="linux-arm64-gnu" ;;
+  MINGW*:x86_64 | MSYS*:x86_64 | CYGWIN*:x86_64) host_target="windows-x64-msvc" ;;
+esac
+if [[ "$target_id" == "$host_target" ]]; then
+  node "$workspace_root/src/sdks/ts-wasix/node-addon/tools/native-build-data.mts" check-addon \
+    "$addon" \
+    "$expected_runtime_version" \
+    "$expected_addon_abi" \
+    "$expected_node_api" \
+    "$build_inputs_file"
+fi
+
+OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA="$artifact_source_sha" \
+  bash src/sdks/ts-wasix/node-addon/tools/package-platform.sh \
+  --target "$target_id" \
+  --prebuild-dir "$prebuild_dir" \
+  --build-inputs "$build_inputs_file"
+
+# Exercise the packed carrier, never the build directory. Node covers both
+# supported clean-install clients; every host then loads the same target addon
+# through its own Node-API implementation. Electron also exercises the
+# production ASAR-unpacked layout while remaining display-server-independent.
+for runtime_and_manager in \
+  "node npm" \
+  "node bun" \
+  "bun bun" \
+  "deno bun" \
+  "electron bun"; do
+  read -r smoke_runtime smoke_package_manager <<<"$runtime_and_manager"
+  bash src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.sh \
+    --target "$target_id" \
+    --runtime "$smoke_runtime" \
+    --package-manager "$smoke_package_manager"
+done
+
+printf 'WASIX N-API addon: %s\n' "$addon"
diff --git a/src/sdks/ts-wasix/node-addon/tools/check-build-inputs.mts b/src/sdks/ts-wasix/node-addon/tools/check-build-inputs.mts
new file mode 100755
index 000000000..c73de6fff
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/check-build-inputs.mts
@@ -0,0 +1,359 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { assertCanonicalWasixAotManifest } from '../../../../runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts';
+import {
+  compareText,
+  exactExtensionProducts,
+  extensionArtifactProductRoot,
+  extensionSqlNames,
+  extensionWasixAotMemberSqlNames,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+
+const PREFIX = 'check-wasix-napi-build-inputs.mjs';
+const WORKSPACE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../..');
+const SHA256 = /^[0-9a-f]{64}$/u;
+
+function fail(message) {
+  throw new Error(message);
+}
+
+function parseArguments(argv) {
+  const options = {};
+  for (let index = 0; index < argv.length; index += 1) {
+    const argument = argv[index];
+    if (!argument.startsWith('--')) fail(`unexpected argument ${argument}`);
+    const value = argv[index + 1];
+    if (!value || value.startsWith('--')) fail(`${argument} requires a value`);
+    options[argument.slice(2)] = value;
+    index += 1;
+  }
+  for (const required of [
+    'target',
+    'target-triple',
+    'portable-root',
+    'aot-root',
+    'extension-root',
+  ]) {
+    if (!options[required]) fail(`--${required} is required`);
+  }
+  if (Boolean(options.output) === Boolean(options.check)) {
+    fail('exactly one of --output or --check is required');
+  }
+  return options;
+}
+
+function repoPath(file, label) {
+  const resolved = path.resolve(file);
+  const relative = path.relative(WORKSPACE_ROOT, resolved);
+  if (
+    !relative ||
+    relative === '..' ||
+    relative.startsWith(`..${path.sep}`) ||
+    path.isAbsolute(relative)
+  ) {
+    fail(`${label} must be inside the repository: ${resolved}`);
+  }
+  return relative.split(path.sep).join('/');
+}
+
+function regularFile(file, label) {
+  let metadata;
+  try {
+    metadata = lstatSync(file);
+  } catch (error) {
+    fail(`${label} is missing: ${repoPath(file, label)} (${error.message})`);
+  }
+  if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) {
+    fail(`${label} must be a non-empty regular non-symlink file: ${repoPath(file, label)}`);
+  }
+  return metadata;
+}
+
+function directory(root, label) {
+  let metadata;
+  try {
+    metadata = lstatSync(root);
+  } catch (error) {
+    fail(`${label} is missing: ${repoPath(root, label)} (${error.message})`);
+  }
+  if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
+    fail(`${label} must be a regular non-symlink directory: ${repoPath(root, label)}`);
+  }
+}
+
+function readJson(file, label) {
+  regularFile(file, label);
+  try {
+    return JSON.parse(readFileSync(file, 'utf8'));
+  } catch (error) {
+    fail(`${label} is not valid JSON: ${error.message}`);
+  }
+}
+
+function sha256Bytes(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+function sha256(file) {
+  return sha256Bytes(readFileSync(file));
+}
+
+function safeMember(value, label) {
+  if (typeof value !== 'string' || value.length === 0 || path.isAbsolute(value)) {
+    fail(`${label} must be a non-empty relative path`);
+  }
+  const normalized = value.replaceAll('\\', '/');
+  if (
+    normalized !== value ||
+    normalized.split('/').some((part) => !part || part === '.' || part === '..')
+  ) {
+    fail(`${label} is not a canonical portable path: ${JSON.stringify(value)}`);
+  }
+  return value;
+}
+
+function validateDigestFile(file, expected, label) {
+  const metadata = regularFile(file, label);
+  if (!SHA256.test(expected ?? '')) fail(`${label} manifest digest is not lowercase SHA-256`);
+  const actual = sha256(file);
+  if (actual !== expected) fail(`${label} digest mismatch: expected ${expected}, got ${actual}`);
+  return metadata;
+}
+
+function portableInputs(portableRoot) {
+  directory(portableRoot, 'portable WASIX artifact root');
+  const manifestFile = path.join(portableRoot, 'manifest.json');
+  const manifest = readJson(manifestFile, 'portable WASIX manifest');
+  if (manifest?.['format-version'] !== 2) fail('portable WASIX manifest must use format-version 2');
+  if (typeof manifest['source-fingerprint'] !== 'string' || !manifest['source-fingerprint']) {
+    fail('portable WASIX manifest must contain a source-fingerprint');
+  }
+  const runtimeArchive = safeMember(manifest.runtime?.archive, 'portable runtime archive');
+  validateDigestFile(
+    path.join(portableRoot, runtimeArchive),
+    manifest.runtime?.sha256,
+    'portable WASIX runtime archive',
+  );
+  regularFile(path.join(portableRoot, 'bin/initdb.wasix.wasm'), 'portable WASIX initdb module');
+
+  return {
+    manifest,
+    provenance: {
+      portableManifest: {
+        path: repoPath(manifestFile, 'portable WASIX manifest'),
+        sha256: sha256(manifestFile),
+      },
+    },
+  };
+}
+
+function validateAotManifest(file, targetTriple, sourceFingerprint, label, namePredicate) {
+  const manifest = readJson(file, label);
+  try {
+    assertCanonicalWasixAotManifest(manifest, {
+      context: repoPath(file, label),
+      expectedTarget: targetTriple,
+    });
+  } catch (error) {
+    fail(error.message);
+  }
+  if (manifest['source-fingerprint'] !== sourceFingerprint) {
+    fail(`${label} source-fingerprint does not match the portable WASIX runtime`);
+  }
+  const names = new Set();
+  for (const [index, artifact] of manifest.artifacts.entries()) {
+    const name = artifact?.name;
+    if (typeof name !== 'string' || !namePredicate(name)) {
+      fail(`${label} artifact ${index} has an unexpected name ${JSON.stringify(name)}`);
+    }
+    if (names.has(name)) fail(`${label} repeats artifact ${name}`);
+    names.add(name);
+    const relative = safeMember(artifact.path, `${label} artifact ${name}`);
+    validateDigestFile(
+      path.join(path.dirname(file), relative),
+      artifact.sha256,
+      `${label} artifact ${name}`,
+    );
+  }
+  return { manifest, names };
+}
+
+function runtimeAotInputs(aotRoot, targetTriple, sourceFingerprint) {
+  directory(aotRoot, 'WASIX AOT artifact root');
+  const targetRoot =
+    path.basename(path.resolve(aotRoot)) === targetTriple
+      ? path.resolve(aotRoot)
+      : path.join(aotRoot, targetTriple);
+  const manifestFile = path.join(targetRoot, 'manifest.json');
+  const { names } = validateAotManifest(
+    manifestFile,
+    targetTriple,
+    sourceFingerprint,
+    'host WASIX AOT manifest',
+    (name) => !name.startsWith('extension:'),
+  );
+  if (![...names].some((name) => !name.startsWith('tool:'))) {
+    fail('host WASIX AOT manifest contains no core runtime artifacts');
+  }
+  return {
+    targetTriple,
+    path: repoPath(manifestFile, 'host WASIX AOT manifest'),
+    sha256: sha256(manifestFile),
+  };
+}
+
+function manifestMembers(manifest, product) {
+  if (manifest.schema === 'oliphaunt-extension-ci-artifacts-v1') return [manifest];
+  if (
+    manifest.schema === 'oliphaunt-extension-ci-artifacts-v2' &&
+    Array.isArray(manifest.extensions)
+  ) {
+    return manifest.extensions;
+  }
+  fail(
+    `${product} has an unsupported extension-artifacts schema ${JSON.stringify(manifest.schema)}`,
+  );
+}
+
+function extensionInputs(extensionRoot, target, targetTriple, sourceFingerprint) {
+  directory(extensionRoot, 'WASIX extension artifact root');
+  return exactExtensionProducts(PREFIX)
+    .map((product) => {
+      const productRoot = extensionArtifactProductRoot(product, 'wasix', extensionRoot, PREFIX);
+      const manifestFile = path.join(productRoot, 'extension-artifacts.json');
+      const manifest = readJson(manifestFile, `${product} extension artifact manifest`);
+      if (manifest.product !== product)
+        fail(`${repoPath(manifestFile, product)} identifies ${manifest.product}`);
+      const members = manifestMembers(manifest, product);
+      const expectedSqlNames = extensionSqlNames(product, PREFIX).sort(compareText);
+      const actualSqlNames = members.map((member) => member?.sqlName).sort(compareText);
+      if (JSON.stringify(actualSqlNames) !== JSON.stringify(expectedSqlNames)) {
+        fail(`${product} extension member inventory is not exact`);
+      }
+      const portableArchives = members
+        .map((member) => {
+          const matches = Array.isArray(member.assets)
+            ? member.assets.filter(
+                (asset) =>
+                  asset?.family === 'wasix' &&
+                  asset.target === 'wasix-portable' &&
+                  asset.kind === 'wasix-runtime',
+              )
+            : [];
+          if (matches.length !== 1)
+            fail(`${product}/${member.sqlName} must have one portable WASIX asset`);
+          const asset = matches[0];
+          const file =
+            manifest.schema === 'oliphaunt-extension-ci-artifacts-v2'
+              ? path.join(productRoot, 'member-assets', member.sqlName, asset.name)
+              : path.join(productRoot, 'release-assets', asset.name);
+          const metadata = validateDigestFile(
+            file,
+            asset.sha256,
+            `${product}/${member.sqlName} portable archive`,
+          );
+          if (metadata.size !== asset.bytes)
+            fail(`${product}/${member.sqlName} portable archive size changed`);
+          return {
+            sqlName: member.sqlName,
+            path: repoPath(file, `${product}/${member.sqlName} portable archive`),
+            sha256: asset.sha256,
+          };
+        })
+        .sort((left, right) => compareText(left.sqlName, right.sqlName));
+
+      const aotManifests = extensionWasixAotMemberSqlNames(product, PREFIX)
+        .map((sqlName) => {
+          const targetRoot = path.join(productRoot, 'wasix-aot', target);
+          const file =
+            manifest.schema === 'oliphaunt-extension-ci-artifacts-v2'
+              ? path.join(targetRoot, sqlName, 'manifest.json')
+              : path.join(targetRoot, 'manifest.json');
+          const { names } = validateAotManifest(
+            file,
+            targetTriple,
+            sourceFingerprint,
+            `${product}/${sqlName} AOT manifest`,
+            (name) => name === `extension:${sqlName}` || name.startsWith(`extension:${sqlName}:`),
+          );
+          if (names.size === 0) fail(`${product}/${sqlName} AOT manifest has no artifacts`);
+          return {
+            sqlName,
+            targetTriple,
+            path: repoPath(file, `${product}/${sqlName} AOT manifest`),
+            sha256: sha256(file),
+          };
+        })
+        .sort((left, right) => compareText(left.sqlName, right.sqlName));
+
+      return {
+        product,
+        manifest: {
+          path: repoPath(manifestFile, `${product} extension artifact manifest`),
+          sha256: sha256(manifestFile),
+        },
+        portableArchives,
+        aotManifests,
+      };
+    })
+    .sort((left, right) => compareText(left.product, right.product));
+}
+
+function buildInventory(options) {
+  const portableRoot = path.resolve(options['portable-root']);
+  const aotRoot = path.resolve(options['aot-root']);
+  const extensionRoot = path.resolve(options['extension-root']);
+  const portable = portableInputs(portableRoot);
+  return {
+    schema: 'oliphaunt-wasix-napi-build-inputs-v1',
+    target: options.target,
+    targetTriple: options['target-triple'],
+    inputs: {
+      ...portable.provenance,
+      runtimeAotManifest: runtimeAotInputs(
+        aotRoot,
+        options['target-triple'],
+        portable.manifest['source-fingerprint'],
+      ),
+      extensionArtifacts: extensionInputs(
+        extensionRoot,
+        options.target,
+        options['target-triple'],
+        portable.manifest['source-fingerprint'],
+      ),
+    },
+  };
+}
+
+function main() {
+  const options = parseArguments(Bun.argv.slice(2));
+  const rendered = `${JSON.stringify(buildInventory(options), null, 2)}\n`;
+  const destination = path.resolve(options.output ?? options.check);
+  repoPath(
+    destination,
+    options.output ? 'build input inventory output' : 'build input inventory check',
+  );
+  if (options.output) {
+    mkdirSync(path.dirname(destination), { recursive: true });
+    writeFileSync(destination, rendered, { encoding: 'utf8', mode: 0o600 });
+  } else {
+    regularFile(destination, 'recorded build input inventory');
+    if (readFileSync(destination, 'utf8') !== rendered) {
+      fail('WASIX build inputs changed while compiling the Node-API addon');
+    }
+  }
+  console.log(
+    `WASIX Node-API build inputs validated: ${repoPath(destination, 'build input inventory')}`,
+  );
+}
+
+try {
+  main();
+} catch (error) {
+  console.error(`${PREFIX}: ${error instanceof Error ? error.message : String(error)}`);
+  process.exitCode = 1;
+}
diff --git a/src/sdks/ts-wasix/node-addon/tools/check-carriers.mts b/src/sdks/ts-wasix/node-addon/tools/check-carriers.mts
new file mode 100644
index 000000000..e71448c01
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/check-carriers.mts
@@ -0,0 +1,113 @@
+#!/usr/bin/env bun
+import path from 'node:path';
+import {
+  ROOT,
+  artifactTargets,
+  compareText,
+  currentProductVersionSync,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  TOOL,
+  artifactNpmPackageTargets,
+  copyStagedRuntimeAssets,
+  fail,
+  isDirectory,
+  isFile,
+  rel,
+  safeNpmPackageFilenamePrefix,
+} from '../../../../../tools/packaging/release-carrier.mts';
+import { readdirSync } from 'node:fs';
+import { writeChecksumManifest } from '../../../../../tools/packaging/write-checksum-manifest.mts';
+import { assertWasixNapiNpmArchive, checkWasixNapiReleaseAssets } from './check-release-assets.mts';
+
+export const WASIX_NAPI_PRODUCT = 'oliphaunt-wasix-napi';
+
+const WASIX_NAPI_KIND = 'wasix-napi-addon';
+
+const WASIX_NAPI_PACKAGE_ROOT = path.join(ROOT, 'src/sdks/ts-wasix/node-addon/packages');
+
+function hasWasixNapiReleaseArchive(assetDir) {
+  if (!isDirectory(assetDir)) {
+    return false;
+  }
+  return readdirSync(assetDir).some(
+    (name) =>
+      name.startsWith('oliphaunt-wasix-napi-') &&
+      (name.endsWith('.tar.gz') || name.endsWith('.zip')),
+  );
+}
+
+async function ensureWasixNapiReleaseAssets() {
+  const assetDir = path.join(ROOT, 'target/oliphaunt-wasix-napi/release-assets');
+  if (!hasWasixNapiReleaseArchive(assetDir)) {
+    copyStagedRuntimeAssets({
+      product: WASIX_NAPI_PRODUCT,
+      destination: assetDir,
+      envName: 'OLIPHAUNT_WASIX_NAPI_ASSET_INPUT_DIRS',
+      patterns: ['oliphaunt-wasix-napi-*.tar.gz', 'oliphaunt-wasix-napi-*.zip'],
+    });
+  }
+  const version = currentProductVersionSync(WASIX_NAPI_PRODUCT, TOOL);
+  await writeChecksumManifest([
+    '--asset-dir',
+    rel(assetDir),
+    '--output',
+    `oliphaunt-wasix-napi-${version}-release-assets.sha256`,
+    '--pattern',
+    'oliphaunt-wasix-napi-*.tar.gz',
+    '--pattern',
+    'oliphaunt-wasix-napi-*.zip',
+  ]);
+  await checkWasixNapiReleaseAssets(['--asset-dir', rel(assetDir)]);
+}
+
+function wasixNapiOptionalPackageTargets(version) {
+  return artifactNpmPackageTargets({
+    product: WASIX_NAPI_PRODUCT,
+    kind: WASIX_NAPI_KIND,
+    surface: 'npm-optional',
+    packageRoot: WASIX_NAPI_PACKAGE_ROOT,
+    version,
+  });
+}
+
+export async function wasixNapiOptionalNpmTarballs(version) {
+  const targets = artifactTargets(WASIX_NAPI_PRODUCT, WASIX_NAPI_KIND, TOOL);
+  const tarballs = [];
+  const packageDir = path.join(ROOT, 'target/oliphaunt-wasix-napi/npm-packages');
+  for (const [packageName] of wasixNapiOptionalPackageTargets(version)) {
+    const tarball = path.join(
+      packageDir,
+      `${safeNpmPackageFilenamePrefix(packageName)}-${version}.tgz`,
+    );
+    if (!isFile(tarball)) {
+      fail(`missing WASIX Node-API optional npm package artifact: ${rel(tarball)}`);
+    }
+    try {
+      assertWasixNapiNpmArchive(tarball, targets, version);
+    } catch (error) {
+      fail(error instanceof Error ? error.message : String(error));
+    }
+    tarballs.push([packageName, tarball]);
+  }
+  const expected = new Set(tarballs.map(([, tarball]) => path.resolve(tarball)));
+  const unexpected = isDirectory(packageDir)
+    ? readdirSync(packageDir)
+        .filter((name) => name.endsWith('.tgz'))
+        .map((name) => path.join(packageDir, name))
+        .filter((file) => !expected.has(path.resolve(file)))
+        .map((file) => path.basename(file))
+        .sort(compareText)
+    : [];
+  if (unexpected.length > 0) {
+    fail(`unexpected WASIX Node-API optional npm package artifact(s): ${unexpected.join(', ')}`);
+  }
+  return tarballs;
+}
+
+export async function packageWasixNapiCarriers() {
+  await ensureWasixNapiReleaseAssets();
+  await wasixNapiOptionalNpmTarballs(currentProductVersionSync(WASIX_NAPI_PRODUCT, TOOL));
+}
+
+if (import.meta.main) await packageWasixNapiCarriers();
diff --git a/src/sdks/ts-wasix/node-addon/tools/check-release-assets.mts b/src/sdks/ts-wasix/node-addon/tools/check-release-assets.mts
new file mode 100644
index 000000000..059907369
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/check-release-assets.mts
@@ -0,0 +1,479 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { readFileSync } from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { finalizeHelperAssets } from '../../../../../tools/packaging/finalize-helper-assets.mts';
+import { inspectPlatformBinaryEntries } from '../../../../../tools/packaging/platform-binary-contract.mts';
+import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  assertFileExists,
+  checksumManifest,
+  readArchiveEntries,
+  sha256,
+} from '../../../../../tools/packaging/release-asset-validation.mts';
+import {
+  assertReleaseNoticesInEntries,
+  releaseProfilePackageLicense,
+} from '../../../../../tools/packaging/release-notices.mts';
+import {
+  WINDOWS_VC_RUNTIME_DLLS,
+  WINDOWS_VC_RUNTIME_RECEIPT,
+} from '../../../../../tools/packaging/windows-vc-runtime-closure.mts';
+import {
+  artifactTargets,
+  compareText,
+  currentProductVersion,
+  exactExtensionProducts,
+  expectedAssets,
+  extensionSqlNames,
+  extensionWasixAotMemberSqlNames,
+  fail,
+  ROOT,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+
+const PREFIX = 'check-wasix-napi-release-assets.mts';
+const PRODUCT = 'oliphaunt-wasix-napi';
+const KIND = 'wasix-napi-addon';
+const PROFILE = 'wasix-napi-addon';
+const PACKAGE_LICENSE = releaseProfilePackageLicense(PROFILE).spdx;
+const BINARY = 'oliphaunt_wasix_napi.node';
+const PRODUCT_MANIFEST = JSON.parse(
+  readFileSync(path.join(ROOT, 'src/sdks/ts-wasix/node-addon/package.json'), 'utf8'),
+);
+const SHA256 = /^[0-9a-f]{64}$/u;
+
+function parseArgs(argv) {
+  const args = {
+    assetDir: path.join(ROOT, 'target/oliphaunt-wasix-napi/release-assets'),
+    allowPartial: false,
+    npmPackages: [],
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--asset-dir') {
+      const value = argv[index + 1];
+      if (!value) fail(PREFIX, '--asset-dir requires a value');
+      args.assetDir = path.resolve(value);
+      index += 1;
+    } else if (arg === '--allow-partial') {
+      args.allowPartial = true;
+    } else if (arg === '--npm-package') {
+      const value = argv[index + 1];
+      if (!value) fail(PREFIX, '--npm-package requires a value');
+      args.npmPackages.push(path.resolve(value));
+      index += 1;
+    } else {
+      fail(PREFIX, `unknown argument ${arg}`);
+    }
+  }
+  return args;
+}
+
+function archiveJson(entries, member, label) {
+  const entry = entries.get(member);
+  if (!entry?.isFile || entry.isSymbolicLink) {
+    throw new Error(`${label} is missing regular member ${member}`);
+  }
+  try {
+    return JSON.parse(Buffer.from(entry.data()).toString('utf8'));
+  } catch (cause) {
+    throw new Error(`${label} member ${member} must contain valid JSON: ${cause.message}`);
+  }
+}
+
+function entrySha256(entry) {
+  return createHash('sha256').update(Buffer.from(entry.data())).digest('hex');
+}
+
+function assertSameStrings(actual, expected, label) {
+  const actualSorted = [...actual].sort(compareText);
+  const expectedSorted = [...expected].sort(compareText);
+  if (
+    actualSorted.length !== new Set(actualSorted).size ||
+    JSON.stringify(actualSorted) !== JSON.stringify(expectedSorted)
+  ) {
+    throw new Error(
+      `${label} must be exactly ${expectedSorted.join(', ')}; got ${actualSorted.join(', ')}`,
+    );
+  }
+}
+
+function canonicalRepoPath(value, label) {
+  if (
+    typeof value !== 'string' ||
+    value.length === 0 ||
+    value.includes('\\') ||
+    path.posix.isAbsolute(value) ||
+    path.posix.normalize(value) !== value ||
+    value.split('/').some((part) => !part || part === '.' || part === '..')
+  ) {
+    throw new Error(`${label} must be a canonical repository-relative path`);
+  }
+  return value;
+}
+
+function digestRecord(value, label, { expectedPath, pathPrefix, pathSuffix } = {}) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    throw new Error(`${label} must be an object`);
+  }
+  const recordPath = canonicalRepoPath(value.path, `${label} path`);
+  if (
+    (expectedPath !== undefined && recordPath !== expectedPath) ||
+    (pathPrefix !== undefined && !recordPath.startsWith(pathPrefix)) ||
+    (pathSuffix !== undefined && !recordPath.endsWith(pathSuffix))
+  ) {
+    throw new Error(`${label} has incompatible path ${recordPath}`);
+  }
+  if (!SHA256.test(value.sha256 ?? '')) {
+    throw new Error(`${label} must record a lowercase SHA-256 digest`);
+  }
+  return recordPath;
+}
+
+function assertBuildInputs(buildInputs, target, label) {
+  if (
+    buildInputs?.schema !== 'oliphaunt-wasix-napi-build-inputs-v1' ||
+    buildInputs.target !== target.target ||
+    buildInputs.targetTriple !== target.triple ||
+    buildInputs.inputs === null ||
+    Array.isArray(buildInputs.inputs) ||
+    typeof buildInputs.inputs !== 'object'
+  ) {
+    throw new Error(`${label} has incompatible embedded build-input provenance`);
+  }
+  const inputs = buildInputs.inputs;
+  digestRecord(inputs.portableManifest, `${label} portable WASIX manifest`, {
+    expectedPath: 'target/oliphaunt-wasix/assets/manifest.json',
+  });
+  if (inputs.runtimeAotManifest?.targetTriple !== target.triple) {
+    throw new Error(`${label} runtime AOT manifest must target ${target.triple}`);
+  }
+  digestRecord(inputs.runtimeAotManifest, `${label} runtime AOT manifest`, {
+    expectedPath: `target/oliphaunt-wasix/aot/${target.triple}/manifest.json`,
+  });
+  if (!Array.isArray(inputs.extensionArtifacts)) {
+    throw new Error(`${label} extension artifact inventory must be an array`);
+  }
+  const expectedProducts = exactExtensionProducts(PREFIX);
+  assertSameStrings(
+    inputs.extensionArtifacts.map((row) => row?.product),
+    expectedProducts,
+    `${label} extension product inventory`,
+  );
+  for (const extension of inputs.extensionArtifacts) {
+    const product = extension.product;
+    digestRecord(extension.manifest, `${label} ${product} extension manifest`, {
+      pathPrefix: 'target/extension-artifacts/',
+      pathSuffix: '/extension-artifacts.json',
+    });
+    if (!Array.isArray(extension.portableArchives)) {
+      throw new Error(`${label} ${product} portable extension inventory must be an array`);
+    }
+    assertSameStrings(
+      extension.portableArchives.map((row) => row?.sqlName),
+      extensionSqlNames(product, PREFIX),
+      `${label} ${product} portable extension inventory`,
+    );
+    for (const archive of extension.portableArchives) {
+      digestRecord(archive, `${label} ${product}/${archive.sqlName} portable extension`, {
+        pathPrefix: 'target/extension-artifacts/',
+        pathSuffix: '-wasix-portable.tar.zst',
+      });
+    }
+    if (!Array.isArray(extension.aotManifests)) {
+      throw new Error(`${label} ${product} extension AOT inventory must be an array`);
+    }
+    assertSameStrings(
+      extension.aotManifests.map((row) => row?.sqlName),
+      extensionWasixAotMemberSqlNames(product, PREFIX),
+      `${label} ${product} extension AOT inventory`,
+    );
+    for (const aot of extension.aotManifests) {
+      if (aot?.targetTriple !== target.triple) {
+        throw new Error(
+          `${label} ${product}/${aot?.sqlName} AOT manifest must target ${target.triple}`,
+        );
+      }
+      digestRecord(aot, `${label} ${product}/${aot.sqlName} AOT manifest`, {
+        pathPrefix: 'target/extension-artifacts/',
+        pathSuffix: '/manifest.json',
+      });
+    }
+  }
+}
+
+export function assertWasixNapiCarrierManifest(manifest, target, version, label = 'carrier') {
+  if (manifest.name !== target.npmPackage || manifest.version !== version) {
+    throw new Error(`${label} must identify ${target.npmPackage}@${version}`);
+  }
+  if (manifest.license !== PACKAGE_LICENSE) {
+    throw new Error(
+      `${label} package license must be ${PACKAGE_LICENSE}, got ${JSON.stringify(manifest.license)}`,
+    );
+  }
+  if (
+    manifest.oliphaunt?.target !== target.target ||
+    manifest.oliphaunt?.runtimeProduct !== PRODUCT_MANIFEST.oliphaunt.runtimeProduct ||
+    manifest.oliphaunt?.runtimeVersion !== PRODUCT_MANIFEST.oliphaunt.runtimeVersion ||
+    manifest.oliphaunt?.addonAbiVersion !== PRODUCT_MANIFEST.oliphaunt.addonAbiVersion ||
+    manifest.oliphaunt?.nodeApiVersion !== PRODUCT_MANIFEST.oliphaunt.nodeApiVersion ||
+    JSON.stringify(manifest.oliphaunt?.profiles) !== JSON.stringify(['standard', 'icu'])
+  ) {
+    throw new Error(`${label} has incompatible WASIX Node-API target/runtime/ABI/profile metadata`);
+  }
+  if (
+    JSON.stringify(manifest.os) !== JSON.stringify([target.npmOs]) ||
+    JSON.stringify(manifest.cpu) !== JSON.stringify([target.npmCpu]) ||
+    (target.npmLibc === undefined
+      ? Object.hasOwn(manifest, 'libc')
+      : JSON.stringify(manifest.libc) !== JSON.stringify([target.npmLibc])) ||
+    manifest.optional !== true ||
+    manifest.type !== 'commonjs' ||
+    Object.hasOwn(manifest, 'scripts')
+  ) {
+    throw new Error(`${label} has incompatible npm platform or lifecycle metadata`);
+  }
+  const expectedFiles = [
+    'prebuilds',
+    'artifact-provenance.json',
+    'README.md',
+    'LICENSE',
+    'THIRD_PARTY_NOTICES.md',
+    'THIRD_PARTY_NOTICES.oliphaunt-wasix.md',
+    'THIRD_PARTY_LICENSES',
+  ];
+  if (JSON.stringify(manifest.files) !== JSON.stringify(expectedFiles)) {
+    throw new Error(`${label} must declare the exact one-addon package file surface`);
+  }
+  if (
+    manifest.exports?.[`./${BINARY}`] !== `./prebuilds/${BINARY}` ||
+    JSON.stringify(Object.keys(manifest.exports ?? {})) !==
+      JSON.stringify([`./${BINARY}`, './artifact-provenance.json', './package.json'])
+  ) {
+    throw new Error(`${label} must expose exactly one stable addon binary subpath`);
+  }
+  return manifest;
+}
+
+export function assertSingleWasixNapiAddonMember(entries, binaryMember, label = 'carrier') {
+  const nativeMembers = [...entries.keys()].filter((name) => name.endsWith('.node'));
+  if (JSON.stringify(nativeMembers) !== JSON.stringify([binaryMember])) {
+    throw new Error(
+      `${label} must contain exactly one native addon member ${binaryMember}; got ${nativeMembers.join(', ')}`,
+    );
+  }
+}
+
+export function assertWasixNapiPlatformEntries(
+  entries,
+  { target, label = 'carrier', prefix = '', binaryDirectory = '' },
+) {
+  inspectPlatformBinaryEntries(
+    [...entries].map(([name, entry]) => ({ name, ...entry })),
+    { target, rootLabel: label },
+  );
+  if (target !== 'windows-x64-msvc') return;
+
+  const sibling = (name) => [prefix, binaryDirectory, name].filter(Boolean).join('/');
+  const runtimeNames = new Set(WINDOWS_VC_RUNTIME_DLLS);
+  const actualRuntimeMembers = [...entries]
+    .filter(
+      ([name, entry]) => entry?.isFile && runtimeNames.has(path.posix.basename(name).toLowerCase()),
+    )
+    .map(([name]) => name)
+    .sort(compareText);
+  const expectedRuntimeMembers = WINDOWS_VC_RUNTIME_DLLS.filter((name) =>
+    entries.has(sibling(name)),
+  )
+    .map((name) => sibling(name))
+    .sort(compareText);
+  if (JSON.stringify(actualRuntimeMembers) !== JSON.stringify(expectedRuntimeMembers)) {
+    throw new Error(
+      `${label} must place its exact app-local VC runtime closure beside ${sibling(BINARY)}`,
+    );
+  }
+
+  const expectedReceiptMember = sibling(WINDOWS_VC_RUNTIME_RECEIPT);
+  const actualReceiptMembers = [...entries.keys()]
+    .filter((name) => path.posix.basename(name).toLowerCase() === WINDOWS_VC_RUNTIME_RECEIPT)
+    .sort(compareText);
+  const expectedReceiptMembers = expectedRuntimeMembers.length > 0 ? [expectedReceiptMember] : [];
+  if (JSON.stringify(actualReceiptMembers) !== JSON.stringify(expectedReceiptMembers)) {
+    throw new Error(`${label} must carry one VC runtime receipt beside its app-local closure`);
+  }
+  if (expectedRuntimeMembers.length === 0) return;
+
+  const receipt = entries.get(expectedReceiptMember);
+  if (!receipt?.isFile || receipt.isSymbolicLink) {
+    throw new Error(`${label} is missing regular member ${expectedReceiptMember}`);
+  }
+  const expectedReceipt = expectedRuntimeMembers
+    .map((member) => `${entrySha256(entries.get(member))}  ${path.posix.basename(member)}\n`)
+    .join('');
+  if (Buffer.from(receipt.data()).toString('utf8') !== expectedReceipt) {
+    throw new Error(`${label} ${expectedReceiptMember} does not bind its exact VC runtime bytes`);
+  }
+}
+
+function assertPayload(entries, { prefix = '', label, target, version, npm = false }) {
+  assertReleaseNoticesInEntries(entries, { profile: PROFILE, prefix, label });
+  const member = (name) => (prefix ? `${prefix}/${name}` : name);
+  const provenance = archiveJson(entries, member('artifact-provenance.json'), label);
+  if (
+    provenance.schema !== 'oliphaunt-wasix-napi-provenance-v1' ||
+    provenance.product !== PRODUCT ||
+    provenance.target !== target.target ||
+    !/^[0-9a-f]{40}$/u.test(provenance.sourceSha ?? '') ||
+    !/^[0-9a-f]{40}$/u.test(provenance.artifactSourceSha ?? '')
+  ) {
+    throw new Error(`${label} has incompatible WASIX Node-API provenance`);
+  }
+  if (provenance.sourceSha !== provenance.artifactSourceSha) {
+    throw new Error(
+      `${label} provenance must bind addon source and embedded artifacts to one commit`,
+    );
+  }
+  const expectedBuild = {
+    cargoProfile: 'release',
+    incremental: false,
+    codegenUnits: 1,
+    lto: 'thin',
+    strip: 'symbols',
+    features: ['release'],
+    targetTriple: target.triple,
+  };
+  if (JSON.stringify(provenance.build) !== JSON.stringify(expectedBuild)) {
+    throw new Error(
+      `${label} provenance must record the exact optimized addon build: ${JSON.stringify(expectedBuild)}`,
+    );
+  }
+  assertBuildInputs(provenance.buildInputs, target, label);
+  const binaryMember = member(npm ? `prebuilds/${BINARY}` : BINARY);
+  const entry = entries.get(binaryMember);
+  if (!entry?.isFile || entry.isSymbolicLink || entry.size <= 0) {
+    throw new Error(`${label} is missing non-empty regular ${binaryMember}`);
+  }
+  const actual = entrySha256(entry);
+  if (
+    provenance.binary?.filename !== BINARY ||
+    provenance.binary?.sha256 !== actual ||
+    Object.hasOwn(provenance, 'binaries')
+  ) {
+    throw new Error(`${label} provenance must bind its sole ${BINARY} subject to ${actual}`);
+  }
+  if (!npm) return;
+  assertSingleWasixNapiAddonMember(entries, binaryMember, label);
+  const manifest = archiveJson(entries, member('package.json'), label);
+  assertWasixNapiCarrierManifest(manifest, target, version, label);
+}
+
+export function assertWasixNapiNpmArchive(file, targets, version) {
+  const label = path.basename(file);
+  let entries;
+  try {
+    entries = readPortableArchiveEntries(file);
+  } catch (error) {
+    throw new Error(`${label} is not a valid portable archive: ${error.message}`);
+  }
+  const manifest = archiveJson(entries, 'package/package.json', label);
+  const target = targets.find((candidate) => candidate.npmPackage === manifest.name);
+  if (!target) {
+    throw new Error(
+      `${label} package name is not a published WASIX Node-API carrier: ${JSON.stringify(manifest.name)}`,
+    );
+  }
+  assertPayload(entries, { prefix: 'package', label, target, version, npm: true });
+  assertWasixNapiPlatformEntries(entries, {
+    target: target.target,
+    label,
+    prefix: 'package',
+    binaryDirectory: 'prebuilds',
+  });
+  return manifest;
+}
+
+async function validateArchive(file, target, version) {
+  const entries = await readArchiveEntries(file, fail, PREFIX, 'WASIX Node-API');
+  try {
+    assertPayload(entries, { label: path.basename(file), target, version });
+  } catch (error) {
+    fail(PREFIX, error.message);
+  }
+  assertWasixNapiPlatformEntries(entries, {
+    target: target.target,
+    label: path.basename(file),
+  });
+}
+
+export async function checkWasixNapiReleaseAssets(argv) {
+  if (argv.includes('--aggregate'))
+    argv = await finalizeHelperAssets(PRODUCT, KIND, argv, {
+      assetDir:
+        process.env.OLIPHAUNT_WASIX_NAPI_ASSET_OUT_DIR ??
+        path.join(ROOT, 'target/oliphaunt-wasix-napi/release-assets'),
+      npmPackageDir:
+        process.env.OLIPHAUNT_WASIX_NAPI_NPM_PACKAGE_OUT_DIR ??
+        path.join(ROOT, 'target/oliphaunt-wasix-napi/npm-packages'),
+    });
+  const args = parseArgs(argv);
+  const version = await currentProductVersion(PRODUCT, PREFIX);
+  const requiredAssets = expectedAssets(PRODUCT, KIND, version, PREFIX);
+  const targets = artifactTargets(PRODUCT, KIND, PREFIX);
+  const targetsByAsset = new Map(
+    targets.map((target) => [target.asset.replaceAll('{version}', version), target]),
+  );
+  const missing = [];
+  for (const asset of requiredAssets) {
+    if (!(await assertFileExists(path.join(args.assetDir, asset)))) missing.push(asset);
+  }
+  if (missing.length > 0) {
+    if (!args.allowPartial) {
+      fail(PREFIX, `missing WASIX Node-API release asset(s): ${missing.join(', ')}`);
+    }
+    let present = 0;
+    for (const asset of targetsByAsset.keys()) {
+      if (await assertFileExists(path.join(args.assetDir, asset))) present += 1;
+    }
+    if (present === 0) {
+      fail(PREFIX, 'partial WASIX Node-API validation requires at least one addon asset');
+    }
+  }
+
+  const checksumAsset = `${PRODUCT}-${version}-release-assets.sha256`;
+  const checksumPath = path.join(args.assetDir, checksumAsset);
+  if (!(await assertFileExists(checksumPath))) {
+    fail(PREFIX, `missing checksum manifest: ${checksumAsset}`);
+  }
+  const checksums = await checksumManifest(checksumPath, fail, PREFIX);
+  for (const asset of requiredAssets.sort(compareText)) {
+    const assetPath = path.join(args.assetDir, asset);
+    if (args.allowPartial && !(await assertFileExists(assetPath))) continue;
+    if (asset === checksumAsset) continue;
+    const expected = checksums.get(asset);
+    if (!expected) fail(PREFIX, `${checksumAsset} does not cover ${asset}`);
+    const actual = await sha256(assetPath);
+    if (actual !== expected) {
+      fail(PREFIX, `checksum mismatch for ${asset}: expected ${expected}, got ${actual}`);
+    }
+  }
+  for (const [asset, target] of targetsByAsset) {
+    const assetPath = path.join(args.assetDir, asset);
+    if (args.allowPartial && !(await assertFileExists(assetPath))) continue;
+    await validateArchive(assetPath, target, version);
+  }
+  for (const npmPackage of args.npmPackages) {
+    try {
+      assertWasixNapiNpmArchive(npmPackage, targets, version);
+    } catch (error) {
+      fail(PREFIX, error.message);
+    }
+  }
+  console.log(`WASIX Node-API release assets validated: ${args.assetDir}`);
+}
+
+const invoked = process.argv[1] ? path.resolve(process.argv[1]) : '';
+if (invoked === fileURLToPath(import.meta.url)) {
+  await checkWasixNapiReleaseAssets(Bun.argv.slice(2));
+}
diff --git a/src/sdks/ts-wasix/node-addon/tools/detect-linux-libc.mts b/src/sdks/ts-wasix/node-addon/tools/detect-linux-libc.mts
new file mode 100644
index 000000000..b3a6166f8
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/detect-linux-libc.mts
@@ -0,0 +1,38 @@
+#!/usr/bin/env node
+
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+const MUSL_LOADER = /(?:^|[/\\])(?:ld-musl-[^/\\]+[.]so[.]1|libc[.]musl-[^/\\]+[.]so[.]1)$/iu;
+
+export function detectLinuxLibc({ report, versions } = {}) {
+  const runtimeVersions = versions ?? process.versions;
+  if (typeof runtimeVersions?.musl === 'string' && runtimeVersions.musl.length > 0) {
+    return 'musl';
+  }
+
+  const diagnostic = report ?? process.report?.getReport?.();
+  if (
+    Array.isArray(diagnostic?.sharedObjects) &&
+    diagnostic.sharedObjects.some(
+      (member) =>
+        typeof member === 'string' &&
+        (MUSL_LOADER.test(member) || /(?:^|[/\\])ld-musl-/iu.test(member)),
+    )
+  ) {
+    return 'musl';
+  }
+  if (
+    typeof diagnostic?.header?.glibcVersionRuntime === 'string' &&
+    diagnostic.header.glibcVersionRuntime.length > 0
+  ) {
+    return 'glibc';
+  }
+  return 'unknown';
+}
+
+function main() {
+  process.stdout.write(`${detectLinuxLibc()}\n`);
+}
+
+if (path.resolve(process.argv[1] ?? '') === fileURLToPath(import.meta.url)) main();
diff --git a/src/sdks/ts-wasix/node-addon/tools/detect-linux-libc.test.mts b/src/sdks/ts-wasix/node-addon/tools/detect-linux-libc.test.mts
new file mode 100644
index 000000000..f6b787156
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/detect-linux-libc.test.mts
@@ -0,0 +1,30 @@
+import { describe, expect, test } from 'bun:test';
+
+import { detectLinuxLibc } from './detect-linux-libc.mts';
+
+describe('WASIX Node-API Linux libc detection', () => {
+  test('recognizes glibc from the runtime diagnostic header', () => {
+    expect(
+      detectLinuxLibc({
+        report: { header: { glibcVersionRuntime: '2.38' }, sharedObjects: [] },
+        versions: {},
+      }),
+    ).toBe('glibc');
+  });
+
+  test('recognizes musl from an explicit runtime version or loader', () => {
+    expect(detectLinuxLibc({ report: {}, versions: { musl: '1.2.5' } })).toBe('musl');
+    expect(
+      detectLinuxLibc({
+        report: { header: {}, sharedObjects: ['/lib/ld-musl-x86_64.so.1'] },
+        versions: {},
+      }),
+    ).toBe('musl');
+  });
+
+  test('does not guess when diagnostics identify neither libc', () => {
+    expect(detectLinuxLibc({ report: { header: {}, sharedObjects: [] }, versions: {} })).toBe(
+      'unknown',
+    );
+  });
+});
diff --git a/src/sdks/ts-wasix/node-addon/tools/native-build-data.mts b/src/sdks/ts-wasix/node-addon/tools/native-build-data.mts
new file mode 100644
index 000000000..87cbfb4a2
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/native-build-data.mts
@@ -0,0 +1,124 @@
+import { createRequire } from 'node:module';
+
+const require = createRequire(import.meta.url);
+const [command, ...args] = process.argv.slice(2);
+switch (command) {
+  case 'metadata': {
+    const manifest = JSON.parse(require('node:fs').readFileSync(args[0], 'utf8'));
+    const values = [
+      manifest.oliphaunt?.runtimeVersion,
+      manifest.oliphaunt?.addonAbiVersion,
+      manifest.oliphaunt?.nodeApiVersion,
+    ];
+    if (
+      !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/.test(values[0] ?? '') ||
+      !Number.isSafeInteger(values[1]) ||
+      !Number.isSafeInteger(values[2])
+    ) {
+      throw new Error('WASIX N-API package metadata has an invalid runtime/ABI contract');
+    }
+    process.stdout.write(values.join('\t'));
+    break;
+  }
+  case 'check-addon': {
+    const { readFileSync, statSync } = require('node:fs');
+    const { resolve } = require('node:path');
+
+    const [addonPath, expectedRuntime, expectedAbiRaw, expectedNodeApiRaw, buildInputsPath] = args;
+    const expectedAbi = Number(expectedAbiRaw);
+    const expectedNodeApi = Number(expectedNodeApiRaw);
+    const buildInputs = JSON.parse(readFileSync(buildInputsPath, 'utf8'));
+    const expectedFunctions = [
+      'addonAbiVersion',
+      'extensionIdentity',
+      'nodeApiVersion',
+      'payloadIdentity',
+      'restore',
+      'restoreDirect',
+      'runtimeVersion',
+      'supportedProfiles',
+    ];
+    const expectedDatabaseMethods = [
+      'backup',
+      'close',
+      'execProtocolRaw',
+      'execProtocolRawStream',
+      'pgDump',
+      'psql',
+    ];
+    const expectedServerMethods = ['close'];
+    const addon = require(addonPath);
+    for (const name of expectedFunctions) {
+      if (typeof addon[name] !== 'function') {
+        throw new Error(`${addonPath} is missing function export ${name}`);
+      }
+    }
+    if (
+      addon.addonAbiVersion() !== expectedAbi ||
+      addon.nodeApiVersion() !== expectedNodeApi ||
+      addon.runtimeVersion() !== expectedRuntime ||
+      JSON.stringify(addon.supportedProfiles()) !== JSON.stringify(['standard', 'icu'])
+    ) {
+      throw new Error(`${addonPath} reports an incompatible ABI/runtime/profile contract`);
+    }
+
+    function expectedIdentity(record, kind) {
+      if (typeof record?.path !== 'string' || !/^[0-9a-f]{64}$/.test(record?.sha256 ?? '')) {
+        throw new Error(`${buildInputsPath} has an invalid ${kind} record`);
+      }
+      const size = statSync(resolve(record.path)).size;
+      if (!Number.isSafeInteger(size) || size < 1) {
+        throw new Error(`${record.path} has an invalid ${kind} size: ${size}`);
+      }
+      return `${record.sha256}:${size}`;
+    }
+
+    const portableExtensions = (buildInputs.inputs?.extensionArtifacts ?? []).flatMap(
+      ({ portableArchives = [] }) => portableArchives,
+    );
+    const extensionNames = portableExtensions.map(({ sqlName }) => sqlName);
+    if (
+      extensionNames.length === 0 ||
+      extensionNames.some((name) => typeof name !== 'string' || name.length === 0) ||
+      new Set(extensionNames).size !== extensionNames.length
+    ) {
+      throw new Error(`${buildInputsPath} has an invalid portable extension inventory`);
+    }
+    for (const extension of portableExtensions) {
+      const actual = addon.extensionIdentity(extension.sqlName);
+      const expected = expectedIdentity(extension, `${extension.sqlName} extension`);
+      if (actual !== expected) {
+        throw new Error(
+          `${addonPath} reports ${extension.sqlName} extension identity ${actual}; expected ${expected}`,
+        );
+      }
+    }
+    for (const component of ['runtimeArchive']) {
+      const identity = addon.payloadIdentity(component);
+      if (!/^[0-9a-f]{64}:[1-9][0-9]*$/.test(identity)) {
+        throw new Error(`${addonPath} reports an invalid ${component} identity: ${identity}`);
+      }
+    }
+    for (const constructorName of ['NativeWasixActorDatabase', 'NativeWasixDatabase']) {
+      if (typeof addon[constructorName]?.open !== 'function') {
+        throw new Error(`${addonPath} is missing ${constructorName}.open`);
+      }
+      for (const name of expectedDatabaseMethods) {
+        if (typeof addon[constructorName].prototype[name] !== 'function') {
+          throw new Error(`${addonPath} is missing ${constructorName}.prototype.${name}`);
+        }
+      }
+    }
+    if (typeof addon.NativeWasixServer?.open !== 'function') {
+      throw new Error(`${addonPath} is missing NativeWasixServer.open`);
+    }
+    for (const name of expectedServerMethods) {
+      if (typeof addon.NativeWasixServer.prototype[name] !== 'function') {
+        throw new Error(`${addonPath} is missing NativeWasixServer.prototype.${name}`);
+      }
+    }
+    break;
+  }
+  default:
+    throw Error(`unknown native build data command: ${command}`);
+}
diff --git a/src/sdks/ts-wasix/node-addon/tools/package-contract.test.mts b/src/sdks/ts-wasix/node-addon/tools/package-contract.test.mts
new file mode 100644
index 000000000..f422d04bf
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/package-contract.test.mts
@@ -0,0 +1,163 @@
+import { createHash } from 'node:crypto';
+
+import { describe, expect, test } from 'bun:test';
+import productManifest from '../package.json' with { type: 'json' };
+
+import {
+  assertSingleWasixNapiAddonMember,
+  assertWasixNapiCarrierManifest,
+  assertWasixNapiPlatformEntries,
+} from './check-release-assets.mts';
+import { windowsPeFixture } from '../../../../../tools/packaging/testdata/release-fixture-utils.mts';
+
+const target = Object.freeze({
+  npmPackage: '@oliphaunt/wasix-napi-linux-x64-gnu',
+  target: 'linux-x64-gnu',
+  npmOs: 'linux',
+  npmCpu: 'x64',
+  npmLibc: 'glibc',
+});
+function manifest() {
+  return {
+    name: target.npmPackage,
+    version: '1.2.3',
+    license: 'MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0',
+    type: 'commonjs',
+    os: ['linux'],
+    cpu: ['x64'],
+    libc: ['glibc'],
+    optional: true,
+    oliphaunt: {
+      target: target.target,
+      runtimeProduct: 'liboliphaunt-wasix',
+      runtimeVersion: productManifest.oliphaunt.runtimeVersion,
+      addonAbiVersion: 2,
+      nodeApiVersion: 8,
+      profiles: ['standard', 'icu'],
+    },
+    exports: {
+      './oliphaunt_wasix_napi.node': './prebuilds/oliphaunt_wasix_napi.node',
+      './artifact-provenance.json': './artifact-provenance.json',
+      './package.json': './package.json',
+    },
+    files: [
+      'prebuilds',
+      'artifact-provenance.json',
+      'README.md',
+      'LICENSE',
+      'THIRD_PARTY_NOTICES.md',
+      'THIRD_PARTY_NOTICES.oliphaunt-wasix.md',
+      'THIRD_PARTY_LICENSES',
+    ],
+  };
+}
+
+function archiveEntry(data) {
+  return {
+    data: () => data,
+    isFile: true,
+    isSymbolicLink: false,
+    size: data.length,
+  };
+}
+
+describe('WASIX Node-API carrier fail-closed package contract', () => {
+  test('accepts the one-binary, two-profile carrier', () => {
+    expect(() => assertWasixNapiCarrierManifest(manifest(), target, '1.2.3')).not.toThrow();
+  });
+
+  test('rejects a wrong target, addon ABI, or profile inventory', () => {
+    for (const mutate of [
+      (candidate) => {
+        candidate.oliphaunt.target = 'linux-arm64-gnu';
+      },
+      (candidate) => {
+        candidate.oliphaunt.addonAbiVersion = 3;
+      },
+      (candidate) => {
+        candidate.oliphaunt.profiles = ['standard'];
+      },
+    ]) {
+      const candidate = manifest();
+      mutate(candidate);
+      expect(() => assertWasixNapiCarrierManifest(candidate, target, '1.2.3')).toThrow(
+        'target/runtime/ABI/profile metadata',
+      );
+    }
+  });
+
+  test('rejects a second native binary export', () => {
+    const candidate = manifest();
+    candidate.exports['./oliphaunt_wasix_napi_icu.node'] =
+      './prebuilds/oliphaunt_wasix_napi_icu.node';
+    expect(() => assertWasixNapiCarrierManifest(candidate, target, '1.2.3')).toThrow(
+      'exactly one stable addon binary',
+    );
+  });
+
+  test('rejects a hidden second native binary archive member', () => {
+    const binary = 'package/prebuilds/oliphaunt_wasix_napi.node';
+    expect(() => assertSingleWasixNapiAddonMember(new Map([[binary, {}]]), binary)).not.toThrow();
+    expect(() =>
+      assertSingleWasixNapiAddonMember(
+        new Map([
+          [binary, {}],
+          ['package/prebuilds/oliphaunt_wasix_napi_icu.node', {}],
+        ]),
+        binary,
+      ),
+    ).toThrow('exactly one native addon member');
+  });
+
+  test('rejects incompatible npm platform, lifecycle, or file metadata', () => {
+    for (const mutate of [
+      (candidate) => {
+        candidate.cpu = ['arm64'];
+      },
+      (candidate) => {
+        candidate.libc = ['musl'];
+      },
+      (candidate) => {
+        candidate.scripts = { install: 'node install.js' };
+      },
+      (candidate) => {
+        candidate.files.push('install.js');
+      },
+    ]) {
+      const candidate = manifest();
+      mutate(candidate);
+      expect(() => assertWasixNapiCarrierManifest(candidate, target, '1.2.3')).toThrow();
+    }
+  });
+
+  test('requires the exact Windows VC runtime closure beside the npm addon', () => {
+    const binary = windowsPeFixture({ imports: ['VCRUNTIME140.dll'] });
+    const runtime = windowsPeFixture();
+    const digest = createHash('sha256').update(runtime).digest('hex');
+    const entries = new Map([
+      ['package/prebuilds/oliphaunt_wasix_napi.node', archiveEntry(binary)],
+      ['package/prebuilds/vcruntime140.dll', archiveEntry(runtime)],
+      [
+        'package/prebuilds/windows-vc-runtime.sha256',
+        archiveEntry(Buffer.from(`${digest}  vcruntime140.dll\n`)),
+      ],
+    ]);
+    const options = {
+      target: 'windows-x64-msvc',
+      prefix: 'package',
+      binaryDirectory: 'prebuilds',
+    };
+    expect(() => assertWasixNapiPlatformEntries(entries, options)).not.toThrow();
+
+    entries.delete('package/prebuilds/windows-vc-runtime.sha256');
+    expect(() => assertWasixNapiPlatformEntries(entries, options)).toThrow(/VC runtime receipt/u);
+
+    entries.set(
+      'package/prebuilds/windows-vc-runtime.sha256',
+      archiveEntry(Buffer.from(`${digest}  vcruntime140.dll\n`)),
+    );
+    entries.set('package/vcruntime140.dll', entries.get('package/prebuilds/vcruntime140.dll'));
+    entries.delete('package/prebuilds/vcruntime140.dll');
+    expect(() => assertWasixNapiPlatformEntries(entries, options)).toThrow(/beside/u);
+  });
+});
diff --git a/src/sdks/ts-wasix/node-addon/tools/package-platform.mts b/src/sdks/ts-wasix/node-addon/tools/package-platform.mts
new file mode 100755
index 000000000..bc4ae7f59
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/package-platform.mts
@@ -0,0 +1,231 @@
+#!/usr/bin/env bun
+
+import { createHash } from 'node:crypto';
+import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import { archiveDirectory } from '../../../../../tools/packaging/archive-directory.mts';
+import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts';
+import { stageReleaseNotices } from '../../../../../tools/packaging/release-notices.mts';
+import { inspectPlatformBinaryTree } from '../../../../../tools/packaging/platform-binary-contract.mts';
+import {
+  WINDOWS_VC_RUNTIME_RECEIPT,
+  stageWindowsVcRuntime,
+  verifyWindowsVcRuntimeClosure,
+} from '../../../../../tools/packaging/windows-vc-runtime-closure.mts';
+
+const WORKSPACE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../..');
+const PRODUCT_ROOT = path.join(WORKSPACE_ROOT, 'src/sdks/ts-wasix/node-addon');
+const TARGETS = Object.freeze({
+  'macos-arm64': 'darwin-arm64',
+  'linux-arm64-gnu': 'linux-arm64-gnu',
+  'linux-x64-gnu': 'linux-x64-gnu',
+  'windows-x64-msvc': 'win32-x64-msvc',
+});
+const BINARY = 'oliphaunt_wasix_napi.node';
+
+function parseArguments(argv) {
+  const options = {};
+  for (let index = 0; index < argv.length; index += 1) {
+    const argument = argv[index];
+    if (!argument.startsWith('--')) {
+      throw new Error(`unexpected argument ${argument}`);
+    }
+    const value = argv[index + 1];
+    if (!value || value.startsWith('--')) {
+      throw new Error(`${argument} requires a value`);
+    }
+    options[argument.slice(2)] = value;
+    index += 1;
+  }
+  return options;
+}
+
+function sha256(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function readJson(file) {
+  return JSON.parse(readFileSync(file, 'utf8'));
+}
+
+function requireFile(file) {
+  if (!existsSync(file)) {
+    throw new Error(`missing required file: ${path.relative(WORKSPACE_ROOT, file)}`);
+  }
+}
+
+async function main() {
+  const [mode, ...argv] = process.argv.slice(2);
+  if (!['stage', 'finish'].includes(mode)) throw new Error('expected stage or finish');
+  const options = parseArguments(argv);
+  const target = options.target;
+  const carrierDirectory = TARGETS[target];
+  if (!carrierDirectory) {
+    throw new Error(`--target must be one of ${Object.keys(TARGETS).join(', ')}`);
+  }
+  const sourcePackage = path.join(PRODUCT_ROOT, 'packages', carrierDirectory);
+  const packageWork = path.join(
+    WORKSPACE_ROOT,
+    'target/oliphaunt-wasix-napi/npm-package-work',
+    carrierDirectory,
+  );
+  const packageOutput = path.join(WORKSPACE_ROOT, 'target/oliphaunt-wasix-napi/npm-packages');
+  const rootManifest = readJson(path.join(PRODUCT_ROOT, 'package.json'));
+  const releaseStage = path.join(
+    WORKSPACE_ROOT,
+    'target/oliphaunt-wasix-napi/release-stage',
+    target,
+  );
+  const releaseAssets = path.join(WORKSPACE_ROOT, 'target/oliphaunt-wasix-napi/release-assets');
+  const archiveExtension = target === 'windows-x64-msvc' ? 'zip' : 'tar.gz';
+  const releaseArchive = path.join(
+    releaseAssets,
+    `oliphaunt-wasix-napi-${rootManifest.version}-${target}.${archiveExtension}`,
+  );
+  if (mode === 'stage') {
+    if (!options['build-inputs']) {
+      throw new Error('--build-inputs is required');
+    }
+    const buildInputsFile = path.resolve(options['build-inputs']);
+    requireFile(buildInputsFile);
+    const buildInputs = readJson(buildInputsFile);
+    if (
+      buildInputs.schema !== 'oliphaunt-wasix-napi-build-inputs-v1' ||
+      buildInputs.target !== target ||
+      typeof buildInputs.targetTriple !== 'string' ||
+      buildInputs.targetTriple.length === 0 ||
+      !Array.isArray(buildInputs.inputs?.extensionArtifacts) ||
+      buildInputs.inputs.extensionArtifacts.length === 0
+    ) {
+      throw new Error(
+        `${path.basename(buildInputsFile)} has incompatible WASIX N-API build inputs`,
+      );
+    }
+    const prebuildDirectory = path.resolve(
+      options['prebuild-dir'] ??
+        path.join(WORKSPACE_ROOT, 'target/oliphaunt-wasix-napi/prebuilds', target),
+    );
+    requireFile(path.join(prebuildDirectory, BINARY));
+
+    rmSync(packageWork, { recursive: true, force: true });
+    mkdirSync(path.join(packageWork, 'prebuilds'), { recursive: true });
+    mkdirSync(packageOutput, { recursive: true });
+    cpSync(sourcePackage, packageWork, { recursive: true });
+    const packagePrebuilds = path.join(packageWork, 'prebuilds');
+    mkdirSync(packagePrebuilds, { recursive: true });
+    cpSync(path.join(prebuildDirectory, BINARY), path.join(packagePrebuilds, BINARY));
+    stageReleaseNotices(packageWork, { profile: 'wasix-napi-addon' });
+    const windowsRuntimeNames =
+      target === 'windows-x64-msvc'
+        ? stageWindowsVcRuntime({
+            root: packageWork,
+            destinations: [packagePrebuilds],
+          }).required
+        : [];
+
+    const sourceSha = options['source-sha'];
+    if (!/^[0-9a-f]{40}$/u.test(sourceSha ?? ''))
+      throw new Error('--source-sha must be a lowercase Git SHA');
+    const artifactSourceSha = process.env.OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA ?? sourceSha;
+    if (!/^[0-9a-f]{40}$/.test(artifactSourceSha)) {
+      throw new Error('OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA must be a lowercase Git SHA');
+    }
+    const provenance = {
+      schema: 'oliphaunt-wasix-napi-provenance-v1',
+      product: 'oliphaunt-wasix-napi',
+      target,
+      sourceSha,
+      artifactSourceSha,
+      build: {
+        cargoProfile: 'release',
+        incremental: false,
+        codegenUnits: 1,
+        lto: 'thin',
+        strip: 'symbols',
+        features: ['release'],
+        targetTriple: buildInputs.targetTriple,
+      },
+      buildInputs,
+      binary: {
+        filename: BINARY,
+        sha256: sha256(path.join(packageWork, 'prebuilds', BINARY)),
+      },
+    };
+    writeFileSync(
+      path.join(packageWork, 'artifact-provenance.json'),
+      `${JSON.stringify(provenance, null, 2)}\n`,
+    );
+
+    rmSync(releaseStage, { recursive: true, force: true });
+    mkdirSync(releaseStage, { recursive: true });
+    mkdirSync(releaseAssets, { recursive: true });
+    cpSync(path.join(prebuildDirectory, BINARY), path.join(releaseStage, BINARY));
+    stageReleaseNotices(releaseStage, { profile: 'wasix-napi-addon' });
+    cpSync(
+      path.join(packageWork, 'artifact-provenance.json'),
+      path.join(releaseStage, 'artifact-provenance.json'),
+    );
+    if (target === 'windows-x64-msvc') {
+      const releaseRuntimeNames = stageWindowsVcRuntime({
+        root: releaseStage,
+        sourceDirectory: packagePrebuilds,
+        destinations: [releaseStage],
+      }).required;
+      if (JSON.stringify(releaseRuntimeNames) !== JSON.stringify(windowsRuntimeNames)) {
+        throw new Error('release and npm carriers derived different Windows VC runtime closures');
+      }
+    }
+    await inspectPlatformBinaryTree(releaseStage, { target });
+    console.log(
+      [releaseStage, packageWork, packageOutput]
+        .map((file) => path.relative(WORKSPACE_ROOT, file).split(path.sep).join('/'))
+        .join('\t'),
+    );
+    return;
+  }
+  const tarball = options.tarball;
+  requireFile(tarball);
+
+  const listing = readPortableArchiveEntries(tarball);
+  const windowsRuntimeNames =
+    target === 'windows-x64-msvc'
+      ? verifyWindowsVcRuntimeClosure({
+          root: packageWork,
+          searchRoots: [path.join(packageWork, 'prebuilds')],
+        }).required
+      : [];
+  const requiredMembers = [
+    `package/prebuilds/${BINARY}`,
+    'package/artifact-provenance.json',
+    'package/LICENSE',
+    'package/THIRD_PARTY_NOTICES.md',
+    'package/THIRD_PARTY_NOTICES.oliphaunt-wasix.md',
+    'package/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT',
+    'package/THIRD_PARTY_LICENSES/ICU-LICENSE',
+    'package/THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt',
+  ];
+  if (windowsRuntimeNames.length > 0) {
+    requiredMembers.push(
+      ...windowsRuntimeNames.map((name) => `package/prebuilds/${name}`),
+      `package/prebuilds/${WINDOWS_VC_RUNTIME_RECEIPT}`,
+    );
+  }
+  for (const member of requiredMembers) {
+    if (!listing.get(member)?.isFile || listing.get(member)?.isSymbolicLink) {
+      throw new Error(`${path.basename(tarball)} is missing ${member}`);
+    }
+  }
+  await archiveDirectory(releaseStage, releaseArchive);
+  process.stdout.write(`${tarball}\n${releaseArchive}\n`);
+}
+
+try {
+  await main();
+} catch (error) {
+  console.error(
+    `package-wasix-napi-platform: ${error instanceof Error ? error.message : String(error)}`,
+  );
+  process.exitCode = 1;
+}
diff --git a/src/sdks/ts-wasix/node-addon/tools/package-platform.sh b/src/sdks/ts-wasix/node-addon/tools/package-platform.sh
new file mode 100755
index 000000000..834192bde
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/package-platform.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+root="$(git -C "$script_dir" rev-parse --show-toplevel)"
+cd "$root"
+source_sha="$(git rev-parse HEAD)"
+plan="$(bun "$script_dir/package-platform.mts" stage "$@" --source-sha "$source_sha")"
+IFS=$'\t' read -r release_stage package_work package_output <<<"$plan"
+[ -d "$release_stage" ] && [ -d "$package_work" ] && [ -d "$package_output" ]
+case "$release_stage" in
+  */linux-*-gnu)
+    target="${release_stage##*/}"
+    bash tools/packaging/check-linux-consumer-baseline.sh --target "$target" --root "$release_stage"
+    ;;
+esac
+filename="$(bun tools/packaging/npm-package.mts "$package_work")"
+tarball="$root/$package_output/$filename"
+bun pm pack --cwd "$package_work" --filename "$tarball"
+bun "$script_dir/package-platform.mts" finish "$@" --tarball "$tarball"
diff --git a/src/sdks/ts-wasix/node-addon/tools/package-platform.test.sh b/src/sdks/ts-wasix/node-addon/tools/package-platform.test.sh
new file mode 100755
index 000000000..809ad2fdd
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/package-platform.test.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+set -euo pipefail
+# Exercise the Linux packaging route with a compiled binary, including a failed pack.
+[ "$(uname -s)" = Linux ] && [ "$(uname -m)" = x86_64 ] || exit 0
+root="$(git rev-parse --show-toplevel)"
+fixture="$(mktemp -d)"
+trap 'rm -rf "$fixture"' EXIT
+product="$fixture/src/sdks/ts-wasix/node-addon"
+mkdir -p "$product/tools" "$fixture/tools" "$fixture/prebuild"
+cp "$root/src/sdks/ts-wasix/node-addon/tools/package-platform."{sh,mts} "$product/tools/"
+cp "$root/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon."{sh,mts} "$product/tools/"
+cp "$root/src/sdks/ts-wasix/node-addon/package.json" "$product/"
+ln -s "$root/src/sdks/ts-wasix/node-addon/packages" "$product/packages"
+ln -s "$root/tools/packaging" "$fixture/tools/packaging"
+ln -s "$root/tools/dev" "$fixture/tools/dev"
+git -C "$fixture" init --quiet
+git -C "$fixture" -c user.name=Test -c user.email=test@example.invalid commit --quiet --allow-empty -m fixture
+printf 'int oliphaunt_packaging_fixture(void) { return 42; }\n' >"$fixture/binary.c"
+cc -shared -fPIC "$fixture/binary.c" -o "$fixture/prebuild/oliphaunt_wasix_napi.node"
+cat >"$fixture/inputs.json" <<'JSON'
+{"schema":"oliphaunt-wasix-napi-build-inputs-v1","target":"linux-x64-gnu","targetTriple":"x86_64-unknown-linux-gnu","inputs":{"extensionArtifacts":[{"fixture":true}]}}
+JSON
+bash "$product/tools/package-platform.sh" --target linux-x64-gnu \
+  --prebuild-dir "$fixture/prebuild" --build-inputs "$fixture/inputs.json"
+output="$fixture/target/oliphaunt-wasix-napi"
+tar -xOf "$output"/npm-packages/*.tgz package/prebuilds/oliphaunt_wasix_napi.node >"$fixture/npm.node"
+tar -xOf "$output"/release-assets/*.tar.gz oliphaunt_wasix_napi.node >"$fixture/release.node"
+cmp "$fixture/prebuild/oliphaunt_wasix_napi.node" "$fixture/npm.node"
+cmp "$fixture/npm.node" "$fixture/release.node"
+tar -xOf "$output"/npm-packages/*.tgz package/artifact-provenance.json >"$fixture/npm.json"
+tar -xOf "$output"/release-assets/*.tar.gz artifact-provenance.json >"$fixture/release.json"
+cmp "$fixture/npm.json" "$fixture/release.json"
+# This is a real ELF library, but not a Node addon: the clean-install smoke
+# must surface the native loader failure and remove its private consumer.
+mkdir "$fixture/smoke-temp"
+for manager in npm bun; do
+  if TMPDIR="$fixture/smoke-temp" bash "$product/tools/smoke-packaged-addon.sh" \
+    --target linux-x64-gnu --runtime node --package-manager "$manager" >"$fixture/smoke.log" 2>&1; then
+    echo 'smoke accepted a library without a Node-API registration' >&2
+    exit 1
+  fi
+  grep -F 'Module did not self-register' "$fixture/smoke.log" >/dev/null
+  [ -z "$(find "$fixture/smoke-temp" -maxdepth 1 -name 'tmp.*' -print -quit)" ]
+done
+rm -rf "$output/release-assets"
+mkdir "$fixture/bin"
+OLIPHAUNT_TEST_REAL_BUN="$(command -v bun)"
+export OLIPHAUNT_TEST_REAL_BUN
+cat >"$fixture/bin/bun" <<'SH'
+#!/bin/sh
+if [ "$1" = pm ] && [ "$2" = pack ]; then
+  exit 23
+fi
+exec "$OLIPHAUNT_TEST_REAL_BUN" "$@"
+SH
+chmod +x "$fixture/bin/bun"
+if PATH="$fixture/bin:$PATH" bash "$product/tools/package-platform.sh" --target linux-x64-gnu \
+  --prebuild-dir "$fixture/prebuild" --build-inputs "$fixture/inputs.json"; then
+  echo 'pack failure was ignored' >&2
+  exit 1
+fi
+[ -z "$(ls -A "$output/release-assets")" ]
+printf 'WASIX N-API package bytes, provenance, and failed-pack checks passed\n'
diff --git a/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.mts b/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.mts
new file mode 100644
index 000000000..0342a668b
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.mts
@@ -0,0 +1,441 @@
+#!/usr/bin/env node
+
+import { access, cp, mkdir, readdir, readFile, realpath, writeFile } from 'node:fs/promises';
+import { createRequire } from 'node:module';
+import path from 'node:path';
+import { fileURLToPath, pathToFileURL } from 'node:url';
+
+import { stageLocalNpmTarball } from '../../../../../tools/packaging/local-npm-tarball.mts';
+
+const WORKSPACE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../..');
+const PACKAGE_ROOT = path.join(WORKSPACE_ROOT, 'src/sdks/ts-wasix/node-addon');
+const PACKAGE_OUTPUT = path.join(WORKSPACE_ROOT, 'target/oliphaunt-wasix-napi/npm-packages');
+const BINARY = 'oliphaunt_wasix_napi.node';
+const PGWIRE_CLIENT = pathToFileURL(
+  path.join(WORKSPACE_ROOT, 'src/sdks/ts-wasix/sdk/tools/pgwire-client.mts'),
+).href;
+const ELECTRON_VERSION = '39.2.5';
+const TARGET_PACKAGES = Object.freeze({
+  'linux-arm64-gnu': 'linux-arm64-gnu',
+  'linux-x64-gnu': 'linux-x64-gnu',
+  'macos-arm64': 'darwin-arm64',
+  'windows-x64-msvc': 'win32-x64-msvc',
+});
+
+function parseArguments(argv) {
+  const options = { packageManager: 'bun' };
+  for (let index = 0; index < argv.length; index += 1) {
+    const argument = argv[index];
+    const value = argv[index + 1];
+    if (!['--package-manager', '--runtime', '--target'].includes(argument) || !value) {
+      throw new Error(
+        'usage: smoke-packaged-addon.mts --target TARGET --runtime node|bun|deno|electron [--package-manager npm|bun]',
+      );
+    }
+    options[argument.slice(2).replace(/-([a-z])/gu, (_match, letter) => letter.toUpperCase())] =
+      value;
+    index += 1;
+  }
+  if (!Object.hasOwn(TARGET_PACKAGES, options.target)) {
+    throw new Error(`unsupported WASIX Node-API smoke target ${options.target}`);
+  }
+  if (!['bun', 'deno', 'electron', 'node'].includes(options.runtime)) {
+    throw new Error(`unsupported WASIX Node-API smoke runtime ${options.runtime}`);
+  }
+  if (!['npm', 'bun'].includes(options.packageManager)) {
+    throw new Error(`unsupported WASIX Node-API smoke package manager ${options.packageManager}`);
+  }
+  return options;
+}
+
+function tarballName(manifest) {
+  return `${manifest.name.slice(1).replace('/', '-')}-${manifest.version}.tgz`;
+}
+
+async function stageElectronAsarSmoke(scratch, carrierManifest) {
+  const require = createRequire(path.join(scratch, 'package.json'));
+  const installedManifest = require.resolve(`${carrierManifest.name}/package.json`);
+  const installedCarrier = await realpath(path.dirname(installedManifest));
+  const source = path.join(scratch, 'asar-source');
+  const archive = path.join(scratch, 'app.asar');
+  const scopedDirectory = carrierManifest.name;
+  const archivedCarrier = path.join(source, 'node_modules', scopedDirectory);
+  await mkdir(path.dirname(archivedCarrier), { recursive: true });
+  await cp(installedCarrier, archivedCarrier, { recursive: true });
+  await writeFile(
+    path.join(source, 'package.json'),
+    `${JSON.stringify({ name: 'oliphaunt-wasix-napi-asar-smoke', main: 'main.cjs' }, null, 2)}\n`,
+  );
+  await writeFile(
+    path.join(source, 'main.cjs'),
+    `const addonPath = require.resolve(${JSON.stringify(`${carrierManifest.name}/${BINARY}`)});
+if (!addonPath.includes('app.asar')) {
+  throw new Error('ASAR smoke resolved the addon outside app.asar: ' + addonPath);
+}
+const addon = require(addonPath);
+if (
+  addon.addonAbiVersion() !== 2 ||
+  addon.nodeApiVersion() !== 8 ||
+  JSON.stringify(addon.supportedProfiles()) !== JSON.stringify(['standard', 'icu'])
+) {
+  throw new Error('ASAR-unpacked addon reports incompatible metadata');
+}
+console.log('oliphaunt-wasix-napi-asar-unpacked:PASS');
+`,
+  );
+  const unpackedBinary = path.join(
+    `${archive}.unpacked`,
+    'node_modules',
+    scopedDirectory,
+    'prebuilds',
+    BINARY,
+  );
+  const installedPrebuilds = path.join(installedCarrier, 'prebuilds');
+  const unpackedPrebuilds = path.dirname(unpackedBinary);
+  const packagedCompanions = await readdir(installedPrebuilds);
+  await writeFile(
+    path.join(scratch, 'asar-companions.json'),
+    JSON.stringify(packagedCompanions.map((name) => path.join(unpackedPrebuilds, name))),
+  );
+  await writeFile(path.join(scratch, 'asar-binary.txt'), unpackedBinary);
+}
+
+async function stageWorkerUnloadSmoke(scratch, carrierManifest, runtime) {
+  const verification = path.join(scratch, 'worker-unload.mjs');
+  await writeFile(
+    verification,
+    `import { createRequire } from 'node:module';
+import { Worker } from 'node:worker_threads';
+
+const require = createRequire(import.meta.url);
+const addonPath = require.resolve(${JSON.stringify(`${carrierManifest.name}/${BINARY}`)});
+const openOptions = ${JSON.stringify({
+      profile: 'standard',
+      storage: { kind: 'memory' },
+      username: 'postgres',
+      database: 'postgres',
+      startupGucs: {},
+      extensions: [],
+    })};
+const naturalExitSource = [
+  "import { createRequire } from 'node:module';",
+  "import { parentPort, workerData } from 'node:worker_threads';",
+  "const addon = createRequire(workerData.addonPath)(workerData.addonPath);",
+  "const database = addon.NativeWasixDatabase.open(workerData.openOptions);",
+  "try {",
+  "  const query = new TextEncoder().encode('SELECT 42::text\\0');",
+  "  const request = new Uint8Array(5 + query.length);",
+  "  request[0] = 0x51;",
+  "  new DataView(request.buffer).setUint32(1, 4 + query.length, false);",
+  "  request.set(query, 5);",
+  "  const response = database.execProtocolRaw(request);",
+  "  if (!new TextDecoder().decode(response).includes('42')) throw new Error('worker query omitted 42');",
+  "} finally {",
+  "  database.close();",
+  "}",
+  "if (!database.closed) throw new Error('worker direct database did not close');",
+  "parentPort.postMessage('closed');",
+  "if (workerData.runtime === 'bun') process.exit(0);",
+  "else {",
+  "  parentPort.close?.();",
+  "  parentPort.unref();",
+  "}",
+].join('\\n');
+const terminateSource = [
+  "import { createRequire } from 'node:module';",
+  "import { parentPort, workerData } from 'node:worker_threads';",
+  "const addon = createRequire(workerData.addonPath)(workerData.addonPath);",
+  "globalThis.database = addon.NativeWasixDatabase.open(workerData.openOptions);",
+  "parentPort.postMessage('opened');",
+  "setInterval(() => undefined, 60_000);",
+].join('\\n');
+
+function spawn(source, name) {
+  return new Worker(new URL('data:text/javascript,' + encodeURIComponent(source)), {
+    name,
+    workerData: { addonPath, openOptions, runtime: ${JSON.stringify(runtime)} },
+  });
+}
+
+async function awaitNaturalExit(iteration) {
+  const worker = spawn(naturalExitSource, 'oliphaunt-wasix-direct-unload-' + iteration);
+  let exitObserved = false;
+  try {
+    await new Promise((resolve, reject) => {
+      let message;
+      worker.once('message', (value) => {
+        message = value;
+      });
+      worker.once('error', reject);
+      worker.once('exit', (code) => {
+        exitObserved = true;
+        if (code !== 0) reject(new Error('direct worker exited with code ' + code));
+        else if (message !== 'closed') reject(new Error('direct worker omitted close acknowledgement'));
+        else resolve();
+      });
+    });
+  } finally {
+    // Forced termination is only failure cleanup. Bun does not settle a
+    // redundant terminate() after a Worker has emitted its exit event.
+    if (!exitObserved) await worker.terminate();
+  }
+}
+
+for (let iteration = 1; iteration <= 20; iteration += 1) {
+  await awaitNaturalExit(iteration);
+}
+
+const terminated = spawn(terminateSource, 'oliphaunt-wasix-direct-terminate-after-open');
+await new Promise((resolve, reject) => {
+  terminated.once('message', (message) => {
+    if (message !== 'opened') {
+      reject(new Error('terminate-after-open worker returned an unexpected message'));
+      return;
+    }
+    void terminated.terminate().then(resolve, reject);
+  });
+  terminated.once('error', reject);
+});
+
+console.log(${JSON.stringify(`oliphaunt-wasix-napi-worker-unload-${runtime}:PASS`)});
+`,
+  );
+}
+
+async function main() {
+  const [phase, scratch, ...args] = process.argv.slice(2);
+  if (!scratch || !['stage', 'asar', 'asar-check'].includes(phase)) {
+    throw new Error(
+      'usage: smoke-packaged-addon.mts stage|asar|asar-check SCRATCH --target TARGET --runtime RUNTIME [--package-manager MANAGER]',
+    );
+  }
+  const options = parseArguments(args);
+  const carrierDirectory = TARGET_PACKAGES[options.target];
+  const carrierManifest = JSON.parse(
+    await readFile(path.join(PACKAGE_ROOT, 'packages', carrierDirectory, 'package.json'), 'utf8'),
+  );
+  const tarball = path.join(PACKAGE_OUTPUT, tarballName(carrierManifest));
+  await access(tarball);
+
+  if (phase === 'asar-check') {
+    const companions = JSON.parse(
+      await readFile(path.join(scratch, 'asar-companions.json'), 'utf8'),
+    );
+    await Promise.all(companions.map((file) => access(file)));
+    return;
+  }
+  if (phase === 'asar') return stageElectronAsarSmoke(scratch, carrierManifest);
+  await writeFile(
+    path.join(scratch, 'package.json'),
+    `${JSON.stringify(
+      {
+        name: 'oliphaunt-wasix-napi-smoke',
+        version: '0.0.0',
+        private: true,
+        type: 'module',
+        dependencies: { [carrierManifest.name]: stageLocalNpmTarball(tarball, scratch) },
+      },
+      null,
+      2,
+    )}\n`,
+  );
+
+  await stageWorkerUnloadSmoke(scratch, carrierManifest, options.runtime);
+
+  const verification = path.join(scratch, 'verify.mjs');
+  await writeFile(
+    verification,
+    `import { readdirSync, readFileSync } from 'node:fs';
+import { createRequire } from 'node:module';
+import { dirname, join } from 'node:path';
+
+const {
+  connect,
+  onceClosed,
+  onceConnected,
+  readExchange,
+  simpleQuery: wireSimpleQuery,
+  startupPacket,
+} = await import(${JSON.stringify(PGWIRE_CLIENT)});
+
+const require = createRequire(import.meta.url);
+const packageName = ${JSON.stringify(carrierManifest.name)};
+const expectedTarget = ${JSON.stringify(options.target)};
+const expectedElectron = ${JSON.stringify(ELECTRON_VERSION)};
+const manifestPath = require.resolve(packageName + '/package.json');
+const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
+const prebuilds = join(dirname(manifestPath), 'prebuilds');
+const nativeFiles = readdirSync(prebuilds).filter((name) => name.endsWith('.node'));
+if (
+  manifest.name !== packageName ||
+  manifest.oliphaunt?.target !== expectedTarget ||
+  manifest.oliphaunt?.addonAbiVersion !== 2 ||
+  manifest.oliphaunt?.nodeApiVersion !== 8 ||
+  JSON.stringify(manifest.oliphaunt?.profiles) !== JSON.stringify(['standard', 'icu']) ||
+  JSON.stringify(nativeFiles) !== JSON.stringify([${JSON.stringify(BINARY)}])
+) {
+  throw new Error('installed WASIX Node-API carrier has incompatible metadata or binary inventory');
+}
+const addon = require(packageName + '/${BINARY}');
+for (const name of [
+  'addonAbiVersion',
+  'extensionIdentity',
+  'nodeApiVersion',
+  'payloadIdentity',
+  'restore',
+  'restoreDirect',
+  'runtimeVersion',
+  'supportedProfiles',
+]) {
+  if (typeof addon[name] !== 'function') throw new Error('addon is missing function ' + name);
+}
+if (
+  addon.addonAbiVersion() !== manifest.oliphaunt.addonAbiVersion ||
+  addon.nodeApiVersion() !== manifest.oliphaunt.nodeApiVersion ||
+  addon.runtimeVersion() !== manifest.oliphaunt.runtimeVersion ||
+  JSON.stringify(addon.supportedProfiles()) !== JSON.stringify(manifest.oliphaunt.profiles)
+) {
+  throw new Error('addon self-reported metadata differs from its carrier');
+}
+for (const constructor of ['NativeWasixActorDatabase', 'NativeWasixDatabase']) {
+  if (typeof addon[constructor]?.open !== 'function') {
+    throw new Error('addon is missing ' + constructor + '.open');
+  }
+  for (const method of ['backup', 'close', 'execProtocolRaw', 'execProtocolRawStream', 'pgDump', 'psql']) {
+    if (typeof addon[constructor].prototype[method] !== 'function') {
+      throw new Error('addon is missing ' + constructor + '.prototype.' + method);
+    }
+  }
+}
+if (typeof addon.NativeWasixServer?.open !== 'function' || typeof addon.NativeWasixServer.prototype.close !== 'function') {
+  throw new Error('addon is missing NativeWasixServer');
+}
+if (process.versions.electron !== undefined && process.versions.electron !== expectedElectron) {
+  throw new Error('unexpected Electron version ' + process.versions.electron);
+}
+
+const runtime = ${JSON.stringify(options.runtime)};
+const decoder = new TextDecoder();
+const openOptions = {
+  profile: 'standard',
+  storage: { kind: 'memory' },
+  username: 'postgres',
+  database: 'postgres',
+  startupGucs: {},
+  extensions: [],
+};
+
+function simpleQuery(sql) {
+  const query = new TextEncoder().encode(sql);
+  const message = new Uint8Array(1 + 4 + query.byteLength + 1);
+  message[0] = 'Q'.charCodeAt(0);
+  new DataView(message.buffer).setUint32(1, 4 + query.byteLength + 1, false);
+  message.set(query, 5);
+  return message;
+}
+
+function verifySimpleQuery(response, owner) {
+  let answer = false;
+  let ready = false;
+  for (let offset = 0; offset < response.byteLength;) {
+    if (offset + 5 > response.byteLength) throw new Error(owner + ' returned a truncated frame');
+    const tag = String.fromCharCode(response[offset]);
+    const length = new DataView(
+      response.buffer,
+      response.byteOffset + offset + 1,
+      4,
+    ).getUint32(0, false);
+    const end = offset + 1 + length;
+    if (length < 4 || end > response.byteLength) throw new Error(owner + ' returned an invalid frame');
+    if (tag === 'D') {
+      const view = new DataView(response.buffer, response.byteOffset + offset + 5, length - 4);
+      const fields = view.getUint16(0, false);
+      const valueLength = view.getInt32(2, false);
+      if (fields === 1 && valueLength === 2) {
+        const value = response.subarray(offset + 11, offset + 13);
+        answer = decoder.decode(value) === '42';
+      }
+    }
+    if (tag === 'Z') ready = true;
+    offset = end;
+  }
+  if (!answer || !ready) throw new Error(owner + ' failed the PostgreSQL Simple Query roundtrip');
+}
+
+function transferResponse(response, owner) {
+  if (!(response instanceof Uint8Array) || !(response.buffer instanceof ArrayBuffer)) {
+    throw new Error(owner + ' did not return a V8-owned Uint8Array');
+  }
+  const transferred = structuredClone(response, { transfer: [response.buffer] });
+  if (response.byteLength !== 0 || !(transferred instanceof Uint8Array)) {
+    throw new Error(owner + ' response ArrayBuffer was not transferable');
+  }
+  return transferred;
+}
+
+async function exerciseDatabase(constructor, owner) {
+  const database = await constructor.open(openOptions);
+  try {
+    const response = await database.execProtocolRaw(simpleQuery('SELECT 42::text AS answer'));
+    verifySimpleQuery(transferResponse(response, owner), owner);
+  } finally {
+    await database.close();
+  }
+  if (!database.closed) throw new Error(owner + ' did not reach its closed state');
+}
+
+await exerciseDatabase(addon.NativeWasixActorDatabase, runtime + '-actor');
+await exerciseDatabase(addon.NativeWasixDatabase, runtime + '-direct');
+
+async function exerciseServer() {
+  const server = await addon.NativeWasixServer.open({
+    ...openOptions,
+    listen: { transport: 'tcp' },
+  });
+  if (
+    server.closed ||
+    typeof server.connectionString !== 'string' ||
+    server.connectionString.length === 0
+  ) {
+    throw new Error(runtime + ' server did not expose a live connection string');
+  }
+  const socket = connect(server.connectionString);
+  let startup;
+  let query;
+  try {
+    await onceConnected(socket);
+    const startupResponse = readExchange(socket);
+    socket.write(startupPacket('postgres', 'postgres'));
+    startup = await startupResponse;
+    const queryResponse = readExchange(socket);
+    socket.write(wireSimpleQuery('SELECT 42::int AS answer'));
+    query = await queryResponse;
+  } finally {
+    socket.end();
+    await onceClosed(socket);
+    await server.close();
+  }
+  if (!server.closed || startup.messages < 1 || query.messages < 3 || query.totalBytes < 6) {
+    throw new Error(
+      runtime + ' server wire roundtrip failed: ' +
+        JSON.stringify({ closed: server.closed, startup, query }),
+    );
+  }
+}
+await exerciseServer();
+console.log(JSON.stringify({
+  addonAbiVersion: addon.addonAbiVersion(),
+  nodeApiVersion: addon.nodeApiVersion(),
+  profiles: addon.supportedProfiles(),
+  runtime,
+  roundtrip: 'actor+direct+server-wire',
+  target: expectedTarget,
+}));
+`,
+  );
+}
+
+main().catch((error) => {
+  console.error(`smoke-packaged-addon: ${error instanceof Error ? error.message : String(error)}`);
+  process.exitCode = 1;
+});
diff --git a/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.sh b/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.sh
new file mode 100644
index 000000000..3d83036f8
--- /dev/null
+++ b/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.sh
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../../.." && pwd)"
+stage="$root/src/sdks/ts-wasix/node-addon/tools/smoke-packaged-addon.mts"
+args=("$@")
+runtime=''
+manager=bun
+while [ "$#" -gt 0 ]; do
+  [ "$#" -ge 2 ] || {
+    echo 'smoke options require values' >&2
+    exit 1
+  }
+  case "$1" in
+    --runtime) runtime="$2" ;;
+    --package-manager) manager="$2" ;;
+    --target) ;;
+    *)
+      echo "unknown smoke option: $1" >&2
+      exit 1
+      ;;
+  esac
+  shift 2
+done
+
+# macOS installs GNU timeout as gtimeout; Windows uses Git Bash's coreutils.
+deadline="$(command -v gtimeout || command -v timeout)" || {
+  echo 'packaged addon smoke requires GNU coreutils (timeout or gtimeout)' >&2
+  exit 1
+}
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+bun "$stage" stage "$scratch" "${args[@]}"
+cd "$scratch"
+export NPM_CONFIG_AUDIT=false NPM_CONFIG_FUND=false
+export NPM_CONFIG_IGNORE_SCRIPTS=true
+if [ "$manager" = bun ]; then
+  "$deadline" --kill-after=3s 300s bun install --ignore-scripts
+else
+  "$deadline" --kill-after=3s 300s npm install --ignore-scripts --no-audit --no-fund --package-lock=false
+fi
+
+case "$runtime" in
+  node) host=(node) ;;
+  bun) host=(bash "$root/tools/dev/bun.sh") ;;
+  deno) host=(bash "$root/tools/dev/deno.sh" run --allow-env --allow-ffi --allow-net=127.0.0.1 --allow-read) ;;
+  electron)
+    host=(env ELECTRON_RUN_AS_NODE=1 NPM_CONFIG_IGNORE_SCRIPTS=false
+      npm exec --yes --package=electron@39.2.5 -- electron)
+    ;;
+esac
+"$deadline" --kill-after=3s 300s "${host[@]}" "$scratch/worker-unload.mjs" >worker.log
+cat worker.log
+grep -F "oliphaunt-wasix-napi-worker-unload-$runtime:PASS" worker.log >/dev/null
+"$deadline" --kill-after=3s 300s "${host[@]}" "$scratch/verify.mjs"
+
+if [ "$runtime" = electron ]; then
+  node "$stage" asar "$scratch" "${args[@]}"
+  "$deadline" --kill-after=3s 300s npm exec --yes --package=@electron/asar@3.4.1 -- \
+    asar pack asar-source app.asar --unpack '**/prebuilds/**'
+  node "$stage" asar-check "$scratch" "${args[@]}"
+  binary="$(cat asar-binary.txt)"
+  mv "$binary" "$binary.missing"
+  status=0
+  "$deadline" --kill-after=3s 300s "${host[@]}" ./app.asar/main.cjs >missing.log 2>&1 || status=$?
+  mv "$binary.missing" "$binary"
+  if [ "$status" = 0 ] || [ "$status" = 124 ] || [ "$status" = 137 ]; then
+    cat missing.log >&2
+    echo 'Electron must promptly reject a missing unpacked addon' >&2
+    exit 1
+  fi
+  grep -F 'oliphaunt_wasix_napi.node' missing.log >/dev/null || {
+    cat missing.log >&2
+    exit 1
+  }
+  "$deadline" --kill-after=3s 300s "${host[@]}" ./app.asar/main.cjs >asar.log
+  cat asar.log
+  grep -F 'oliphaunt-wasix-napi-asar-unpacked:PASS' asar.log >/dev/null
+fi
+printf 'WASIX Node-API packaged %s/%s smoke passed\n' "$runtime" "$manager"
diff --git a/src/bindings/wasix-ts/tools-package/.gitignore b/src/sdks/ts-wasix/sdk/.gitignore
similarity index 100%
rename from src/bindings/wasix-ts/tools-package/.gitignore
rename to src/sdks/ts-wasix/sdk/.gitignore
diff --git a/src/sdks/ts-wasix/sdk/ARCHITECTURE.md b/src/sdks/ts-wasix/sdk/ARCHITECTURE.md
new file mode 100644
index 000000000..a4bb93c7d
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/ARCHITECTURE.md
@@ -0,0 +1,658 @@
+# WASIX TypeScript binding architecture
+
+This describes the development checkout. New resource and tools carrier identities
+are not assumed to be available in a completed public release.
+
+## Boundary
+
+`src/sdks/ts-wasix/sdk` is one public TypeScript API over two host adapters.
+The package export conditions, not a runtime option, select the adapter:
+
+```text
+browser/default                  node/bun/deno/electron
+      |                                      |
+      v                                      v
+patched Wasmer JavaScript host       napi-rs, Node-API 8 addon
+      |                                      |
+portable liboliphaunt-wasix       Rust actor, direct, Worker, server
+      `---------------------+----------------'
+                            v
+                 shared TypeScript database API
+```
+
+The browser adapter owns the portable runtime/seed descriptors and dynamic
+extension carrier installation. The server adapter owns no Wasmer JavaScript
+fallback: it loads one exact, prebuilt platform carrier whose Rust dependency
+embeds the runtime, AOT objects, and supported extension catalog. Seeds, ICU
+data, and frontend tools are separate explicit inputs. Both execute the canonical WASIX guest and preserve its physical
+database and backup formats.
+
+This boundary deliberately does not depend on `src/sdks/ts/sdk`,
+`liboliphaunt-native`, `node-direct`, or the broker. The N-API product wraps the
+WASIX Rust binding; it is not a route into the native PostgreSQL SDK.
+
+Protocol and typed-query helpers come from the independently versioned
+`@oliphaunt/ts-query` package in `src/sdks/ts-query`. The native and React Native
+SDKs depend on the same package.
+
+The patched Wasmer host under `src/runtimes/wasix-browser-host` is the browser host
+implementation dependency. PostgreSQL binaries and the canonical runtime manifest
+are owned by `liboliphaunt-wasix`; seed archives and ICU data are owned by
+`database-resources`, and mutable PGDATA belongs to the application storage provider; each extension product owns its separately versioned
+portable carrier envelope. The N-API release embeds the corresponding frozen
+artifacts instead of resolving those bytes during application startup.
+
+The canonical guest also owns the backend-only single-backend spinlock and
+scalar-atomic specializations carried by PostgreSQL patches 0035 and 0036.
+They follow the guest into the Rust binding's AOT artifacts and the portable
+module used by the browser. They are not a TypeScript host optimization.
+Frontends, PGXS side modules, and concurrent PostgreSQL builds retain the normal
+atomic implementation. Each adapter asserts the shared
+`OLIPHAUNT_WASIX_SINGLE_BACKEND=1` concurrency invariant and denies guest
+process and thread creation under it. Browser root and `/worker` use the same
+Oliphaunt export driver. Native-host root, `/direct`, `/worker`, and `/server` use the
+same Rust WASIX semantics with different explicit owners. Placement changes
+ownership and hop count, not the PostgreSQL protocol contract.
+
+## Browser lifecycle
+
+`Oliphaunt.open()` from the root package uses the host driver in the importing
+realm: setup is asynchronous, but PostgreSQL lifecycle and protocol exports run
+in that realm and may monopolize its event loop while active. `Oliphaunt.open()` from
+`@oliphaunt/wasix-ts/worker` creates one package-owned module Worker around the
+same driver. There is no public placement option and neither entrypoint falls
+back to the other. Both share one database state machine, mount
+construction, PostgreSQL configuration, extension/role setup, and storage
+contract. Immutable preparation and compiled modules are cached by verified
+runtime identity, while writable `Directory` mounts and storage leases are
+recreated for every open. Each handle remains one serialized PostgreSQL
+session. Only the root entrypoint contends for its caller's event loop.
+
+The pinned host currently instantiates dynamically loaded native side modules
+synchronously. Chromium refuses Window-realm modules above 8 MiB, so the root
+entrypoint fails early there for a selected carrier above that threshold. The
+explicit `/worker` entrypoint and the root imported from a Dedicated Worker are
+outside that Window restriction and apply descriptor-declared native
+load order; a real Chrome canary loads PostGIS there and verifies recovery
+across its large dependency module. The core guest uses the asynchronous path;
+smaller qualified side modules remain supported in a direct Window.
+
+1. The root entrypoint imports the package-relative host lazily in the caller
+   realm and creates no Worker. `/worker` creates one module Web Worker per open
+   and a temporary Worker for restore.
+2. The binding resolves the default `@oliphaunt/liboliphaunt-wasix` descriptor
+   internally and verifies its manifest and runtime bytes. New browser storage
+   requires an explicit seed archive and manifest from `database-resources`;
+   existing storage can reopen without a seed. ICU selection supplies the raw
+   data file and its manifest. Each input retains its own integrity and runtime
+   compatibility checks rather than sharing one product version. Imported
+   extension descriptors add their exact carrier closure.
+3. The selected realm safely expands the core artifacts and overlays only each
+   extension carrier's install-contract files into separate `/bin`, `/lib`, `/share`,
+   writable `/base`, `/home`, and `/tmp` Wasmer memory mounts. Before `/base` is
+   materialized, a storage provider lease supplies either the packaged cluster
+   seed or an exact-compatible persistent PGDATA. The source-pinned
+   host adds ephemeral `/dev/shm` and a real Wasmer `RandomFile` at
+   `/dev/urandom`. Its narrow `Directory` mutation journal records successful
+   writes and truncates through already-open descriptors as well as file,
+   directory, remove, and rename paths for either execution surface and every provider.
+   Both execution surfaces pass the verified precompiled main module and its original
+   bytes to `instantiateOliphauntDirect`. The root keeps the resulting Store in
+   the caller realm; `/worker` keeps it in its package Worker.
+4. Both execution surfaces push protocol bytes through guest-owned reusable input
+   and output buffers. The host writes requests directly into canonical guest
+   memory and returns one owned JavaScript response copy, so PostgreSQL can
+   safely reuse or grow its memory after the call. Startup preserves an
+   `ErrorResponse` and its SQLSTATE even when startup terminates the guest.
+5. The direct export driver completes the exported startup transition before
+   exposing the session. Selected carriers contribute verified artifacts and
+   required startup/preload configuration only; database-local extension SQL is
+   application/ORM-owned. A requested non-default user is selected from existing
+   roles with `SET ROLE`; standalone bootstrap remains the fixed `postgres`
+   identity.
+6. The binding frames later responses through `ReadyForQuery` and exposes
+   serialized `query`, `execute`, buffered `execProtocolRaw`, callback
+   `execProtocolRawStream`, and callback-scoped `transaction` calls
+   through one database contract. The same contract supports explicit
+   `close()` and `await using` disposal.
+   Every successfully completed protocol operation reaches `ReadyForQuery`, then
+   asks a persistent provider to publish only journaled `/base` paths before the
+   Promise resolves. A callback transaction defers publication for `BEGIN`, its
+   body, and `COMMIT`/`ROLLBACK`, then publishes exactly once after the confirmed
+   final boundary. A new persistent synchronous-OPFS root uses a separate internal
+   full-publication boundary after initialization; it is not a public database
+   operation. PostgreSQL `CHECKPOINT` remains available through ordinary
+   `execute`. If a
+   PostgreSQL `ERROR` crosses the host boundary, the direct host
+   invokes `PostgresMainLongJmp`, sends and flushes readiness, and continues
+   through `PostgresMainLoopOnce`. Normal ErrorResponse returns receive the same
+   top-level cleanup as trapping errors.
+7. `close` establishes a terminal admission cutoff and lets already accepted
+   database work drain. The direct owner
+   sends PostgreSQL Terminate through the same direct bridge, deactivates the
+   embedded lifecycle, and runs its atexit exports synchronously in the owning
+   realm. A successful close completes the
+   provider's final persistence boundary. Every outcome attempts provider close,
+   exclusive-lease release, and entrypoint-owned host-resource release. The
+   browser `/worker` waits for that close reply and then terminates its already
+   quiescent Worker; a Node-compatible `/worker` closes its native handle, posts
+   the reply, and exits itself. The public
+   handle memoizes that single outcome and becomes closed after teardown settles;
+   a rejected close never advertises the destroyed owner or guest as reusable.
+   If the isolated owner terminates independently, shared session state makes the
+   public handle closed immediately and prevents later work from crossing the
+   dead transport. An explicit close still memoizes and reports that terminal
+   failure while completing package-owned resource cleanup.
+8. Each public database handle registers an opaque generation token for
+   best-effort forgotten-handle recovery. The finalizer holds no reference to
+   the public owner and only schedules work after returning. It atomically
+   claims the exact still-active generation, then schedules the same best-effort
+   close for that root, direct, or `/worker` generation. Explicit close
+   unregisters the generation before teardown, so queued stale finalizers are
+   harmless and cannot affect a later database.
+
+Stock Wasmer's public browser API exposes streams and process completion, but
+not arbitrary guest exports. The source-pinned host deliberately adds only the
+narrow Oliphaunt export driver needed to match the Rust WASIX lifecycle; it is
+not a general synchronous WASIX process API. Generic Wasmer process streams
+remain upstream behavior and are not part of the TypeScript database surface.
+
+## Node, Bun, Deno, and Electron lifecycle
+
+Native-host conditions load one Node-API 8 addon. The root constructs
+`NativeWasixActorDatabase`, which directly owns the Rust `AsyncOliphaunt`
+database actor. Bounded admission is synchronous, PostgreSQL runs on its one
+Rust owner thread, and completion settles the existing Promise on the importing
+JavaScript thread. This is the responsive default and adds one native queue hop.
+
+The conditional `/direct` export constructs `NativeWasixDatabase` around
+synchronous `oliphaunt_wasix::Oliphaunt` on the importing JavaScript thread. It
+has the fewest hops and can block that event loop. The conditional `/worker`
+export creates one real package-owned Node-compatible Worker, which loads the
+same `/direct` implementation inside that Worker. It adds the requested
+JavaScript RPC hop and realm isolation without a child process or a second Rust
+owner thread. Native direct handles remain creator-thread-affine.
+
+Close establishes one admission cutoff. The actor drains accepted work and
+settles its terminal completion. Direct close runs on its owning thread. A
+package Worker closes its native database at quiescence, posts the close reply,
+then closes its parent port and exits itself; the parent does not terminate a
+Worker across an active Node-API frame. An unexpected Worker exit rejects
+pending work and leaves the public handle terminal.
+
+Query serialization, close semantics, the memory default, storage identity,
+and public errors remain TypeScript-owned. Descriptor validation also remains
+shared, but native release addons resolve validated extension SQL names against
+their compile-time catalog instead of expanding portable extension archives at
+open.
+
+IndexedDB and OPFS remain browser-only and are rejected before a native-host
+actor, direct, or Worker session starts. Directory persistence is exposed through matching
+`storage/node`, `storage/bun`, and `storage/deno` entrypoints. They preserve the
+shared managed-root descriptor and exclusive path ownership while Rust owns
+the database bytes and durability. No host falls back to native
+`@oliphaunt/ts`. Direct and explicit `/worker` entrypoints may themselves
+be imported from an application-owned worker thread. Rust holds one OS advisory
+lock for the managed-root lifetime, shared with direct Rust owners. There is no
+JavaScript marker lock to recover. Callers should still close before externally
+terminating their own realm.
+
+## Protocol streams, tools, and local endpoints
+
+The public callback stream reuses the guest's COPY-aware synchronous transport
+and emits at most 64 KiB per callback. Browser root and native `/direct` invoke
+the callback in their owning JavaScript realm. Browser and native-host
+Workers block only their Worker with a shared-memory acknowledgement until the
+importing-realm callback returns. The native actor uses a napi-rs thread-safe
+function with queue size one and waits for each JavaScript acknowledgement.
+Every path therefore preserves bounded backpressure and callback ordering.
+
+Direct native requests borrow JavaScript input for the duration of their
+synchronous call. Actor requests copy into owned Rust admission data before the
+call returns. All native responses, backup archives, chunks, and tool output are
+ordinary V8-owned typed arrays with predictable detach and lifetime behavior.
+The Worker transport transfers eligible response `ArrayBuffer` values directly;
+there is no external-buffer finalizer crossing an isolate or environment exit.
+
+A callback returning a Promise or thenable is rejected: asynchronous
+completion cannot acknowledge this synchronous backpressure contract, and the
+PostgreSQL session is poisoned conservatively. The callback is also an
+ownership boundary: it cannot queue work through the same database or
+transaction while that database is waiting for the chunk acknowledgement. Such
+reentry fails immediately instead of creating a hidden post-stream operation.
+
+`@oliphaunt/wasix-tools` remains the optional public facade. In a browser it
+resolves the separately published `@oliphaunt/liboliphaunt-wasix-tools` asset
+carrier. `pg_dump` runs in the realm that already owns the database; `psql`
+uses a separate persistent browser tool worker because COPY input is genuinely
+full duplex. Its private pgwire connection has fixed, bounded shared-memory
+rings.
+
+Native hosts route `pg_dump` and `psql` through the existing Rust database owner
+on root, `/direct`, or `/worker`. The independently versioned tools product
+supplies portable or target-specific AOT inputs explicitly. Building or installing
+the core runtime does not compile or bundle those optional frontends.
+
+The package export `@oliphaunt/wasix-ts/internal/tools` exists only so the
+`@oliphaunt/wasix-tools` package can reach this bridge. It is not
+an application API or part of the stable SDK surface, is undocumented for app
+consumers, and is governed by the companion package's declared SDK dependency. Independent
+product versions need not be numerically equal. Package
+checks reject any other low-level query or protocol subpath exports.
+
+The database session is exclusively serialized. It resets PostgreSQL with
+`ROLLBACK`, `DISCARD ALL`, and the configured role before and after a tool, then
+publishes storage once after the final safe cleanup boundary. An uncertain tool
+transport outcome poisons the handle after making its stored state safe. The
+tools remain outside the core public database surface on both adapters.
+
+The host-only `/server` subpath uses conditions to export the same implementation
+for Node, Bun, Deno, and Electron. It has no browser or default condition. The implementation
+constructs the Rust `OliphauntServer` through the same addon rather than
+adapting a JavaScript socket relay. It binds one loopback TCP or
+PostgreSQL-named Unix listener and serves one active client. Another connection
+may wait in the operating-system backlog, so consumers configure pools with a
+maximum size of one. Each admitted connection receives a fresh embedded
+backend. Server state, listener lifetime, and storage publication are
+Rust-owned; the TypeScript facade retains the
+existing Promise-shaped open/close and `closed` contract. The concurrent WASIX
+postmaster remains a separate runtime product rather than a mode of this
+single-backend SDK.
+
+## Browser storage boundary
+
+Storage is a binding-owned provider/lease contract rather than runtime asset
+configuration:
+
+```text
+opaque storage descriptor
+          |
+          v
+ acquire provider lease ---- exact physical compatibility
+          |
+          +---- synchronous OPFS /base ---- exact-range file I/O
+          |
+          `---- portable /base ------ journaled publication
+                           |
+                           v
+              PostgreSQL boundary + release
+```
+
+The main package owns the fresh-memory descriptor and default. IndexedDB and
+OPFS are selective `./storage/indexed-db` and `./storage/opfs` entrypoints whose
+implementations load only when an opaque descriptor reaches the owning
+realm. Raw serialized descriptors are not accepted from consumers. The
+internal lease exposes `state`, one initial PGDATA mount,
+an optional synchronous PGDATA materializer, `sync(directory, boundary)`, and
+`close(directory, outcome)`; it does not own runtime or extension assets.
+
+The source-pinned Wasmer `Directory` exposes a compact current-state mutation
+journal. Write-capable files are wrapped so a PostgreSQL descriptor retained
+across multiple operations records every later write, not only its initial
+open. The shared portable delta layer drains the journal only at
+PostgreSQL-safe host boundaries, collapses overlapping paths, reads changed
+files and subtrees, and expresses removals explicitly. A provider without that
+host capability falls back to a full scan, so correctness does not depend on
+the optimization. Synchronous OPFS mounts bypass mutation tracking and serve the
+guest synchronously in its owning worker. Process-lifetime `postmaster.pid` and
+`postmaster.opts` never enter persistent storage.
+
+Each logical IndexedDB name owns a separate physical IndexedDB database with
+fixed metadata and one row per PGDATA path. Each boundary applies upserts and
+removals in one atomic read-write transaction using the browser's default
+commitState policy; an aborted write leaves the preceding generation intact,
+and distinct logical databases do not share an object-store transaction. OPFS
+stores a strict logical namespace and physical identity over flat backing files.
+`/worker`, and the root inside a Dedicated Worker, preopen synchronous access
+handles and perform exact-range guest I/O without a mailbox or nested worker. A
+direct Window uses the portable path. Guest file flushes are immediate;
+operation boundaries drain WAL; internal full-publication, close, and namespace publication
+flush WAL before ordinary files and `global/pg_control`. The portable path uses
+copy-on-write backing files and atomically replaces namespace state last. OPFS
+has PostgreSQL recovery ordering but no cross-file transaction, so a failed
+publication reports unknown state instead of claiming that nothing changed.
+The synchronous path keeps a bounded private reserve of preopened backing files for
+the synchronous hot path. Overflow is staged only until the mandatory host
+boundary, which allocates, writes, and flushes every staged file before
+publishing namespace state. A failure leaves the previous namespace
+authoritative and poisons the live handle. The reserve is replenished
+best-effort after successful boundaries, and hosts that cannot establish its
+initial capacity use the portable path. Its size is an implementation detail,
+not a public database-capacity limit.
+
+Compatibility uses the PostgreSQL major and versioned WASIX physical format.
+Runtime hashes and source fingerprints still reject mixed runtime, cluster-seed,
+AOT, and extension build outputs, while package and carrier changes do not
+rewrite the managed-root descriptor or reject an unchanged physical format.
+Safe extension upgrade or removal remains an explicit migration concern rather
+than a reason to reject every change in the available carrier set.
+Cross-binding root handoff is not a supported or qualified workflow.
+
+Persistent databases use an origin-scoped exclusive Web Lock. This preserves
+the single-owner invariant rather than suggesting that one single-user
+PostgreSQL backend represents independent connections. There is no leader
+proxy or multi-tab transaction ownership yet.
+
+Provider acquisition and PGDATA materialization happen before PostgreSQL
+starts. Provider boundaries happen only after pgwire recovery returns
+`ReadyForQuery`, so ordinary PostgreSQL errors retain their existing
+`PostgresError` identity. A host persistence failure is instead a typed storage
+error and poisons the live handle: guest state may be ahead of confirmed durable
+storage, so retrying the application operation is not known to be safe.
+
+## Selective extension descriptor contract
+
+The consumer API accepts exact structural values rather than SQL strings:
+
+```ts
+type WasixExtensionDescriptor = {
+  schema: 'oliphaunt-wasix-extension-v1';
+  runtime: 'wasix';
+  product: string;
+  version: string;
+  compatibility: {
+    extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1';
+    postgresMajor: string;
+    wasixRuntimeProduct: 'liboliphaunt-wasix';
+    wasixRuntimeVersion: string;
+  };
+  sqlName: string;
+  carriers: readonly {
+    product: string;
+    version: string;
+    sqlName: string;
+    archive: string;
+    sha256: string;
+    size: number;
+    source: string | URL | ArrayBuffer | Uint8Array;
+    install: {
+      schema: 'oliphaunt-wasix-extension-install-v1';
+      dependencies: readonly string[];
+      coreExportsRequired: readonly string[];
+      // exact native-module, lifecycle, and installed-file projections
+    };
+  }[];
+};
+```
+
+This is structural rather than nominal so a generated extension package can be
+dependency-free; it does not import the host binding merely to acquire a brand.
+The literal `runtime: 'wasix'` still makes native descriptors statically
+incompatible with non-WASIX extension descriptors, and the client
+runtime-validates the complete shape.
+The binding keeps an internal validation/freezing helper for fixtures. It is not
+part of the consumer entrypoint and generated packages do not depend on it.
+
+Generated leaf packages can point at their package-owned payload without any
+host conditional:
+
+```ts
+const carrier = {
+  source: new URL('./extensions/pgtap/extension.tar.zst', import.meta.url),
+  // product, version, SQL identity, archive key, hash, and size
+} as const;
+```
+
+The development Vite harness derives virtual package descriptors from the current
+canonical target outputs and uses development route strings while serving those
+exact artifacts directly.
+
+Each descriptor selects only its root `sqlName`. Its carrier array is a
+dependency-complete byte closure, not an alternate dependency declaration. The
+client validates each root's exact dependency closure, unions closures in
+deterministic SQL-name order, deduplicates shared rows only when their complete
+identity/install/compatibility metadata agrees, and rejects repeated rows,
+duplicate roots, or conflicts. The selected realm resolves dependencies solely from
+the imported install contracts, treating only the stripped core manifest's
+`runtime-support` entries as runtime-provided. Before reading extension bytes,
+it gates every carrier on the selected WASIX runtime version, PostgreSQL major,
+extension-runtime contract, and required names in `runtime.link.exports`. It
+then verifies each archive's declared size/hash and overlays exactly its
+carrier-owned installed-file inventory. The core manifest is required to have
+`extensions: []` so it cannot quietly reclaim optional extension ownership.
+
+That byte-closure processing is the browser implementation. Node.js, Bun, Deno,
+and Electron retain the same public descriptor and perform its structural/runtime
+validation, but pass only the validated, dependency-ordered SQL names across
+the N-API boundary. The Rust runtime resolves those names against the exact
+extension features compiled into the release carrier. Unknown names fail; the
+addon never treats arbitrary descriptor bytes as native code. A new or upgraded
+extension can ship independently for browsers, but it becomes available to
+native-host consumers only after the N-API product is rebuilt and released
+with that feature.
+
+## Host compatibility
+
+The host is rebuilt from source rather than maintained as hand-edited generated
+JavaScript/WASM. `src/runtimes/wasix-browser-host/source.toml` pins the Wasmer JS Git source and Cargo
+crates; the adjacent patches are the reviewable compatibility delta. The build
+lands first in `target/oliphaunt-wasix-ts/host`. Public package staging copies
+the exact JS module, worker module, WebAssembly module, license, and provenance
+into `lib/host`; the browser root imports the host in the caller realm, while
+the browser `/worker` imports it in its package Worker. Node.js, Bun, Deno, and Electron
+conditions do not import this module.
+
+This is not a general backport of WASIX 0.702 to Wasmer 0.601. The authoritative
+patch order is the `series` in `src/runtimes/wasix-browser-host/source.toml`; this document records the
+resulting invariants instead of duplicating that filename inventory. Together,
+the patches:
+
+- honor configured args, environment, mounts, cwd, and stdio; preserve original
+  module bytes where the generic blocking worker needs them; and repair the
+  pinned npm/toolchain inputs without mutating their lock;
+- provide only the 0.702 compatibility imports and runtime devices required by
+  the shipped guests, reject unavailable fork/context/thread/process behavior,
+  remove the retired Rust target, and recognize standard WebAssembly exception
+  reference types;
+- make oversized main-module construction asynchronous through the builder and
+  linker while keeping the returned database driver synchronous and rejecting
+  unsupported oversized side modules before open;
+- enforce the single-backend profile, use correct realtime and monotonic clocks,
+  amortize bounded pending-work checks, and avoid turning synchronous-file POSIX
+  close into an implicit fsync that bypasses PostgreSQL durability policy;
+- expose the current-state mutation journal and the narrow caller-realm
+  synchronous filesystem bridge used by synchronous OPFS, without reviving the old
+  mailbox transport;
+- provide the caller-realm PostgreSQL lifecycle and reusable-memory pgwire
+  driver, including COPY-aware callback streaming, top-level error recovery,
+  and a bounded 16 KiB failure-only stderr tail; and
+- run only the packaged PostgreSQL frontend tools through a fresh caller-realm
+  WASIX process with captured stdio and synchronous pgwire callbacks. This path
+  uses neither the generic Wasmer scheduler worker nor a Web Streams pump.
+
+The clock specialization is intentionally narrower than a general syscall
+shortcut. Realtime uses the JavaScript epoch clock, while monotonic reads
+calibrate the host's monotonic clock against the canonical Rust fallback epoch,
+so fast and fallback reads cannot jump between domains. Process and thread CPU
+clocks remain on the canonical fallback because wall time is not an equivalent
+clock. Synthetic clock offsets remain honored by declining the direct import
+for guests that import `clock_time_set`, and pending WASIX operations are
+checked on a real-time bound. Invalid clock IDs, pointers, or host values use
+the complete Rust syscall. Other WASIX programs retain the complete upstream
+per-call path.
+
+The exact pairing is qualified for the single-process direct Oliphaunt export
+path in both execution surfaces, including repeated PostgreSQL `ERROR` recovery. The
+direct driver treats every `PostgresMainLoopOnce` trap as the guest's exported
+top-level recovery boundary and also cleans up non-trapping ErrorResponses.
+Its JavaScript memory bridge is limited to the direct Oliphaunt driver: generic
+WASIX streams keep their normal ownership and scheduling semantics. Copy failures
+are caught before guest buffers are released, and protocol responses are copied
+once into owned JavaScript storage rather than exposed as mutable guest views.
+Browser qualification loads and calls PostGIS in a real worker and asserts that
+its dependency side module exceeds Chromium's 8 MiB main-thread compilation
+limit; the exemption is therefore attached to the worker realm, not to an
+extension name or a benchmark payload size.
+This remains an integration contract with the pinned Oliphaunt runtime rather
+than a generic Wasmer guarantee.
+Missing WASIX context switching is a broader compatibility gap, but is not part
+of this PostgreSQL recovery path. Ordinary package resolution never selects
+stock `@wasmer/sdk`; the published binding owns the source-pinned host. A larger
+current-Wasmer JS port is outside this host's compatibility contract.
+
+The version skew is upstream-owned rather than a loose Oliphaunt dependency.
+The commit referenced by the latest npm `@wasmer/sdk` 0.10.0 release identifies
+its checked-in source as 0.8.0 and embeds Wasmer 6.1 with the 0.601 Wasmer
+support family. `wasmer-wasix` 0.702.1 embeds Wasmer 7.2.1 and
+matching 0.702.1 virtual filesystem/network, package, configuration, backend,
+and types contracts. A coordinated compile probe exposed incompatible
+`FileSystem` mounting, `TaskWasm`, wasm-bindgen conversion, registry calls,
+module hashing, and binary-package construction before the Oliphaunt runner and
+recovery changes could be reapplied. Consequently 0.702.1 adoption is a full
+source-host port plus browser qualification, not an isolated crate bump.
+`src/runtimes/wasix-browser-host/source.toml` records the intentionally coherent 0.601 source family until
+that port exists.
+
+## PGlite reference, not product inheritance
+
+PGlite independently validates the recovery shape used here. Its Emscripten
+guest turns the active PostgreSQL top-level `longjmp` into a known exit status;
+the TypeScript host then calls `PostgresMainLongJmp`, sends readiness, flushes,
+and resumes `PostgresMainLoopOnce`. Its public database error is separately
+decoded from pgwire. See PGlite's
+[runtime loop](https://github.com/electric-sql/pglite/blob/67872123b637ba132cceb8dbb3f739a09685ee87/packages/pglite/src/pglite.ts#L932-L965)
+and [guest shim](https://github.com/electric-sql/postgres-pglite/blob/7b4ee5086055dc5e54ae1e13e487888249438e68/pglite/src/pglitec/pglitec.c#L52-L84).
+Oliphaunt deliberately uses an environment-gated Wasmer exception discriminator
+instead of Emscripten's numeric sentinel, but preserves the same separation
+between control-flow recovery and the pgwire `PostgresError` seen by callers.
+Lifecycle SQL for a selectively imported extension runs in the owning realm.
+Isolated-host errors are serialized by PostgreSQL field and rebuilt in the caller;
+direct errors retain the same `PostgresError` identity in place. Generic
+transport errors retain their name, message, and owner-side stack. Neither path
+collapses SQLSTATE and diagnostics into a generic error.
+
+PGlite is also a useful ordering reference: it stages extension archives and
+precompiles Emscripten side modules before PostgreSQL starts. Those
+`MAIN_MODULE`/`SIDE_MODULE` binaries are not WASIX carriers, however, and its
+filesystem persistence is coupled to Emscripten FS.
+
+The browser benchmark also exposed a preparation asymmetry: PGlite reused
+precompiled modules while each WASIX open recompiled the verified guest bytes.
+Caller-realm execution now bounds and keys immutable preparation and compiled-module
+caches by exact runtime/carrier/GUC identity. Mutable directories and storage
+leases never enter those caches. The checked-in insert benchmark compares WAL
+volume alongside timing; separate root-cause diagnostics compare buffer
+activity and relation sizes. Both keep host/runtime overhead visible without
+changing PostgreSQL work or commitState settings.
+
+This binding keeps the following deliberate divergences:
+
+- extension lifecycle and install metadata comes from each selectively imported
+  `-wasix` package; the stripped runtime manifest cannot override it;
+- runtime/PGDATA/manifest hashes, carrier hashes, required core exports, exact
+  installed-file inventories, dependencies, and collisions are checked before
+  startup;
+- selecting an extension stages its verified artifacts and startup configuration;
+  applications explicitly run ordinary `CREATE EXTENSION`, `LOAD`, schema, or
+  migration SQL, matching the ownership expected by ORMs; and
+- IndexedDB and OPFS now use source-pinned dirty-path synchronization at each
+  completed protocol operation, matching PGlite's useful commitState boundary
+  without importing Emscripten FS. Oliphaunt keeps explicit provider-specific
+  atomicity and exclusive ownership; multi-tab leadership remains unsupported.
+
+The host validates every native `load-order` entry against the carrier's exact
+installed-file inventory but does not execute it as SQL. Applications explicitly
+issue any required `LOAD`/`CREATE EXTENSION` lifecycle, after which PostgreSQL and
+Wasmer's dynamic linker remain responsible for each module's declared
+`dylink-needed` closure. `shared-memory-required` contracts remain rejected
+because the single-backend runtime has not qualified that capability.
+
+## Asset ownership
+
+The `@oliphaunt/wasix-ts` tarball does not contain PostgreSQL binaries. Browser
+conditions import `@oliphaunt/liboliphaunt-wasix`, whose generated descriptor
+points at package-owned runtime, PGDATA, and manifest assets. There is no public
+raw runtime-source override. Development reads
+`target/oliphaunt-wasix/assets`, produced by
+`liboliphaunt-wasix:runtime-portable`, through the browser example's Vite
+plugin, which models that generated carrier.
+
+Node.js, Bun, Deno, and Electron also receive one target-filtered optional dependency.
+The public carriers are
+`@oliphaunt/wasix-napi-darwin-arm64`,
+`@oliphaunt/wasix-napi-linux-arm64-gnu`,
+`@oliphaunt/wasix-napi-linux-x64-gnu`, and
+`@oliphaunt/wasix-napi-win32-x64-msvc`. Each has no install script and contains
+one `oliphaunt_wasix_napi.node` binary with both standard and ICU profiles. The private
+`@oliphaunt/wasix-napi` product coordinates the Rust build and carrier release;
+applications never import it.
+
+Linux carriers are GNU/glibc-only. The adapter identifies libc from the
+runtime diagnostic report before resolving package-adjacent, optional, or
+explicit addon paths; known musl and unknown libc identities fail closed.
+
+Native release builds embed the runtime, AOT objects, and complete currently
+supported extension feature set. Seeds, ICU data, and frontend tools remain
+separate selected resources. Optional extensions remain
+exact, separately imported `-wasix` packages at the public TypeScript boundary,
+but native hosts use their descriptor identity to select compiled-in artifacts
+instead of copying the carrier bytes. Their availability is consequently a
+release-time N-API contract.
+
+The source workspace manifest deliberately does not resolve that generated
+carrier from npm: the carrier exists only after same-candidate runtime assets
+are frozen. SDK release staging injects the exact dependency recorded by
+`oliphaunt.runtimeVersion`, validates it, and publishes only that staged
+manifest. This keeps fresh frozen workspace installs independent of an
+unpublished candidate while making the consumer tarball's browser runtime edge
+exact. The same staging step rewrites every native optional dependency to the
+exact N-API product version. The loader rejects a carrier whose package name,
+version, target, WASIX runtime, addon ABI, Node-API level, or profile inventory do
+not match the SDK metadata; the addon then self-reports its runtime and exact
+supported profile inventory before open.
+
+The release runtime carrier owns a stripped core manifest (`extensions: []`).
+The development Vite plugin projects the same core-only bytes from the build
+pipeline's qualification manifest and derives separate exact extension install
+contracts from its extension rows. The binding rejects a nonempty core manifest,
+so the runtime carrier cannot become the authority for independently versioned
+extensions.
+
+The first browser smoke selects the SQL-only `pgtap` carrier and explicitly runs
+`CREATE EXTENSION`. That isolates manifest verification, dependency ordering, archive overlay, and lifecycle SQL
+from dynamic linking. The separate `smoke-browser.sh --pg-uuidv7` profile selects the
+native carrier, calls `uuid_generate_v7()` before and after the two error
+recovery cases, verifies both results are UUIDv7 values, and checks clean
+process exit. That proves one exact `.so` against the pinned package-owned host; it
+does not add or widen a canonical extension target claim. Generic native-module
+support remains gated on a safer loader boundary and broader qualification.
+
+The example's virtual Vite modules model the intended
+`@oliphaunt/extension-pgtap-wasix` and
+`@oliphaunt/extension-pg-uuidv7-wasix` package roots from current target
+outputs. Its asset middleware and COOP/COEP headers are development-only.
+Production hosting, cache policy, and asset integrity are application/carrier
+concerns; the binding does not silently copy target-owned assets into its npm
+bundle.
+
+## Public package and qualification
+
+`@oliphaunt/wasix-ts` is a separately versioned public SDK product. It has its own
+release metadata and changelog, declares an exact browser dependency on the
+published `@oliphaunt/liboliphaunt-wasix` runtime carrier, and declares the four
+exact native packages as optional dependencies. It publishes the patched host
+under `lib/host` for browser/default conditions. Conditional package exports
+choose browser, Node.js, Bun, Deno, or Electron adapters. Browser root remains
+caller-owned; the native-host root uses the Rust actor, `/direct` is caller-owned, and
+the conditional `/worker` subpath is owned by its isolated Worker.
+
+The browser smoke proves the exact runtime/host pairing can start PostgreSQL,
+explicitly activate `pgtap`, retain SQLSTATE across repeated PostgreSQL error recovery,
+continue with `42` on the same handle, persist through IndexedDB operation
+boundaries, run an explicit `CHECKPOINT` through `execute`, and close with a
+successful zero exit status. Each Node.js, Bun, Deno, and Electron host smoke installs the
+packed SDK and matching packed platform carrier into a fresh external project,
+verifies conditional-export and profile selection, starts the embedded
+WASIX Rust runtime, activates a compiled extension, recovers from an error, and
+closes cleanly. Each carrier also runs a real actor Simple Query roundtrip and
+proves its V8-owned response buffer is transferable; Node additionally proves
+direct and local-server lifecycles. The Deno proof uses local `node_modules`
+with explicit read, environment, and FFI permissions and qualifies the declared
+Deno CLI range, not managed Deno Deploy. Electron additionally qualifies the
+ASAR-unpacked native-addon layout. The opt-in native browser profile
+additionally loads and calls the canonical `pg_uuidv7.so`; it remains a narrow
+canary rather than a generic dynamic-extension claim.
+
+The intentional host, persistence, extension, and Wasmer compatibility limits
+remain listed in [README.md](./README.md). They are explicit product boundaries,
+not compatibility aliases or fallbacks to a native SDK.
diff --git a/src/bindings/wasix-ts/CHANGELOG.md b/src/sdks/ts-wasix/sdk/CHANGELOG.md
similarity index 100%
rename from src/bindings/wasix-ts/CHANGELOG.md
rename to src/sdks/ts-wasix/sdk/CHANGELOG.md
diff --git a/src/sdks/ts-wasix/sdk/README.md b/src/sdks/ts-wasix/sdk/README.md
new file mode 100644
index 000000000..b717a2577
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/README.md
@@ -0,0 +1,429 @@
+# `@oliphaunt/wasix-ts`
+
+Portable PostgreSQL 18 for TypeScript. Browser conditions run the canonical
+`liboliphaunt-wasix` guest through the patched Wasmer JavaScript host. Node.js,
+Bun, Deno, and Electron conditions run the same WASIX runtime through a Rust
+Oliphaunt Node-API addon. The public TypeScript API is shared by both hosts.
+
+In browsers the root owns PostgreSQL in the importing JavaScript realm. On
+native hosts the root uses a dedicated Rust owner thread. The explicit
+`/direct` import runs synchronously in the importing realm, while `/worker`
+uses a separate JavaScript Worker on every runtime.
+
+Use `@oliphaunt/wasix-ts/browser` for explicit browser imports; it rejects native
+hosts. Browser open and restore accept memory (open only), IndexedDB, and OPFS.
+Native root, `/direct`, `/worker`, and `/server` accept memory and directory
+storage. Host-specific declarations enforce these storage choices even when
+storage descriptors pass through variables; JavaScript callers receive runtime
+errors for unsupported storage.
+
+
+## Install
+
+```sh
+bun add @oliphaunt/wasix-ts
+```
+
+The published SDK is one universal browser-and-server package. Its browser host
+files and exact `@oliphaunt/liboliphaunt-wasix` dependency are therefore
+installed on Node.js, Bun, Deno, and Electron too, although native export
+conditions never load them. The matching target-filtered optional platform
+package embeds the runtime, both cluster profiles, tools, and qualified
+extension catalog used on those hosts. Carrier packages have no install scripts
+and do not download a binary at install or first use. Applications do not
+configure raw runtime assets.
+
+Published Node-API 8 carriers currently cover:
+
+- macOS arm64;
+- Linux arm64 and x64 with glibc; and
+- Windows x64 with MSVC.
+
+There is no published carrier yet for macOS x64, Linux musl, or Windows arm64.
+The native loader detects Linux libc before resolving a carrier and explicitly
+rejects musl or an unidentifiable libc; it cannot load a `-gnu` carrier through
+an override on an unsupported host. Opening a database on another server target
+fails with an explicit unsupported-platform error rather than falling back to
+the browser Wasmer host.
+
+Deno must resolve the npm package through a local `node_modules` directory and
+must be granted `--allow-ffi`, `--allow-read`, and `--allow-env` in addition to any filesystem
+permissions the application needs. The `/worker` entrypoint uses Deno's
+Node-compatible Worker implementation and does not spawn a process. The package
+smoke uses explicit host permissions. The qualified Deno surface is
+the Deno CLI version declared by this package; managed Deno Deploy is not
+currently a qualified distribution target.
+
+Electron applications that use ASAR should leave `**/prebuilds/**` unpacked and
+ship the generated `app.asar.unpacked` directory beside `app.asar`. This keeps
+the addon and any platform loader companions, including the Windows app-local
+VC runtime, in one loadable directory. Electron can temporarily extract a
+packed native module, but the unpacked layout avoids that startup overhead and
+antivirus interaction. Carrier qualification loads the addon from this
+packaged layout and proves that a missing unpacked companion fails explicitly.
+
+Database resources are optional, separately installed packages. New browser storage
+requires a selected seed; existing browser storage reopens without one. Node, Bun,
+and Deno can also initialize a new database with the runtime's initdb when no seed
+is supplied.
+
+For a browser bundler, select the standard seed explicitly:
+
+```ts
+import Oliphaunt from '@oliphaunt/wasix-ts';
+import archive from '@oliphaunt/seed-wasix-standard/seed.tar.zst?url';
+import manifest from '@oliphaunt/seed-wasix-standard/manifest.json?url';
+
+await using database = await Oliphaunt.open({ seed: { archive, manifest } });
+```
+
+For ICU, select `@oliphaunt/seed-wasix-icu` instead and pass
+`icu: { data, manifest }`, loading `@oliphaunt/icu/data` and
+`@oliphaunt/icu/manifest`. Node/Bun/Deno may pass their file bytes instead of URLs.
+The SDK verifies seed integrity, runtime compatibility, and the ICU data tree
+before initialization. Each native platform addon supports both profiles without
+bundling either seed or ICU data.
+
+## Query PostgreSQL
+
+```ts
+import Oliphaunt from '@oliphaunt/wasix-ts';
+
+await using database = await Oliphaunt.open();
+
+await database.execute('create table todo (title text not null)');
+await database.execute('insert into todo values ($1)', ['ship it']);
+
+const result = await database.query(
+  'select title from todo where title = $1',
+  ['ship it'],
+);
+console.log(result.rows[0]?.title);
+```
+
+`execute` asserts one command with no rows. `query` accepts command-only or
+row-producing SQL and defaults to decoded object rows; array rows, text value
+mode, and immutable per-query OID codecs are available. Object mode rejects
+duplicate field names; use `rowMode: 'array'` to preserve them positionally.
+`queryRaw` retains ordered nullable bytes and complete field metadata. `exec` returns ordered
+simple-query results, while `describe` resolves parameter OIDs and optional
+result fields without executing. Structured operations preserve command
+metadata and ordered notices.
+
+Safe scalar parameters are resolved and encoded inside one owned operation.
+Use `text`, `binary`, `typedNull`, `json`, or `array` with `postgresOids` for a
+deterministic type, or an immutable per-query encoder for an extension OID.
+Unsupported and mismatched values fail rather than being guessed.
+
+`execProtocolRaw` is the buffered PostgreSQL frontend-protocol escape hatch.
+`execProtocolRawStream` delivers the same response through a synchronous
+callback. Every surface invokes it serially with at most 64 KiB per chunk and
+waits for it to return before producing the next chunk. Direct sessions invoke
+the callback inline; the native actor and Worker paths use bounded
+acknowledgements across their existing thread boundary. COPY-sized responses
+therefore need not be retained as one JavaScript value. A thrown callback, including
+the deterministic error for returning a Promise or thenable, is rethrown
+unchanged only after the guest confirms recovery to `ReadyForQuery`; the
+recovered database remains reusable. An asynchronous callback cannot provide
+this backpressure contract.
+The callback also cannot reenter the same database or transaction;
+fire-and-forget calls are rejected instead of being queued behind the stream.
+Neither method interprets responses for the caller. A buffered raw rejection,
+or a streamed execution, transport, or recovery failure, poisons the handle and
+takes precedence over a simultaneous callback error; close it and open a new
+database instead of assuming the physical session recovered.
+
+PostgreSQL `ErrorResponse` values reject with `PostgresError`, including the
+SQLSTATE and structured diagnostic fields.
+
+## Transactions
+
+```ts
+await database.transaction(async (transaction) => {
+  await transaction.execute('insert into todo values ($1)', ['inside transaction']);
+  return transaction.query('select count(*)::int4 as count from todo');
+});
+```
+
+The callback exclusively owns the session from `BEGIN` through its final
+boundary. It mirrors query/raw query, execute, exec, and describe; database-level
+operations reject while it is active. One-shot `rollback()` closes the
+transaction and lets the callback return without a later commit.
+
+Raw protocol is database-only and deliberately absent from the callback handle.
+Do not issue manual `BEGIN`, `START TRANSACTION`, `COMMIT`, `END`, `ABORT`,
+`PREPARE TRANSACTION`, or `AND CHAIN` inside the callback; return/throw or call
+`rollback()` instead. `SAVEPOINT` and `ROLLBACK TO` are supported. `ROLLBACK AND
+CHAIN` is unsupported contract misuse and has the same PostgreSQL wire
+tag/readiness state as `ROLLBACK TO`, so the SDK rejects `ROLLBACK`/`ABORT ...
+AND CHAIN` before dispatch and still validates every actual protocol boundary.
+A proven ownership escape makes the database close-only and never causes a
+speculative SDK `COMMIT` or `ROLLBACK`.
+
+Callback failures trigger a best-effort `ROLLBACK`. Once `COMMIT` has been
+sent, the binding never sends a second rollback. PostgreSQL's clean `ROLLBACK`
+response is a known aborted outcome; a transport failure or malformed response
+after `COMMIT` makes the outcome unknown and poisons the handle until close.
+Persistent publication completes before a successful transaction resolves.
+After rollback and its required publication succeed, the original callback
+failure is rethrown unchanged. If the callback and rollback both fail, an
+`AggregateError` preserves the callback failure followed by the rollback
+failure. If an earlier independent database or protocol failure has already
+poisoned or expired transaction ownership and the callback then throws a
+different value, an `AggregateError` preserves the callback failure followed by
+that database failure; the database is close-only. Ordinary PostgreSQL statement
+errors that remain safely rollbackable are not automatically aggregated.
+
+## Storage
+
+Omitting `storage` creates a fresh true-memory database. Persistent adapters
+are explicit, host-specific imports:
+
+```ts
+import Oliphaunt from '@oliphaunt/wasix-ts';
+import { directory } from '@oliphaunt/wasix-ts/storage/node';
+
+const storage = directory('./data/todos');
+let database = await Oliphaunt.open({ storage });
+await database.execute('create table if not exists todo (title text not null)');
+await database.close();
+
+database = await Oliphaunt.open({ storage });
+await database.close();
+```
+
+Use `storage/bun` or `storage/deno` for those runtimes, and
+`storage/indexed-db` or `storage/opfs` in browsers.
+
+A Node, Bun, Deno, or Electron directory is a managed root with exactly:
+
+```text
+.oliphaunt.json
+pgdata/
+```
+
+The descriptor records the shared database-root schema, PostgreSQL major, and
+WASIX physical format. Runtime source fingerprints and package hashes validate
+the asset graph; they are not physical-reopen identity. Native and WASIX roots
+are not rejected merely because of the originating family.
+
+Rust and WASIX TypeScript bindings use the same root and physical-archive
+contracts. On Node.js, Bun, Deno, and Electron the Rust runtime holds the managed
+root's OS advisory lock for the database lifetime. The same lock protects actor,
+direct, Worker, and Rust owners. Always close the current owner before handing a
+root to another process, Worker, or binding.
+
+The Rust host owns directory durability for Node.js, Bun, Deno, and Electron. IndexedDB
+publishes a delta in one transaction. OPFS uses synchronous backing files for
+`/worker` and when the root entrypoint is imported inside an application-owned
+Dedicated Worker.
+The root entrypoint in a browser Window uses the same opaque format through a
+copy-on-write portable path. Both OPFS paths flush or publish in
+PostgreSQL-safe order. A
+publication failure rejects with `WasixStorageError`; an uncertain state
+poisons the live database handle.
+
+All native-host entrypoints may be used inside an application-owned Worker,
+including with directory storage. Close the database before terminating that
+Worker. The lock is owned by the Rust runtime rather than a JavaScript marker
+directory, and an orderly package Worker close waits for native quiescence,
+posts its terminal reply, and then lets the Worker exit itself.
+
+`close()` is one terminal, idempotent teardown attempt. It stops admitting new
+work and lets work already accepted by the database FIFO finish. The root actor
+and `/server` await their Rust owner teardown. `/direct` closes synchronously at
+the native boundary. `/worker` closes its direct native session at quiescence,
+replies, and self-exits; it is never force-terminated across an active Node-API
+frame. Concurrent and later calls return the same promise. Provider, host, and
+Worker transport failures are preserved.
+If teardown rejects, `closed` still becomes `true`: cleanup was attempted and
+a destroyed isolated owner or guest is never treated as a retryable live session.
+An unexpected `/worker` crash also makes `closed` true as soon as the transport
+observes ownership loss. Later operations fail without posting more work;
+`close()` remains idempotent and reports that terminal transport failure while
+finishing any remaining package-owned cleanup.
+
+Forgetting a database handle schedules generation-guarded best-effort cleanup
+of only that handle's actor, direct session, or Worker generation. A stale
+finalizer cannot affect a later open. Finalizers are not prompt or observable,
+so applications must still use `close()` or `await using` when ownership release
+matters.
+
+## Backup and restore
+
+```ts
+const backup = await database.backup();
+await database.close();
+
+await Oliphaunt.restore(directory('./data/restored'), backup);
+```
+
+`backup()` performs PostgreSQL online physical backup without replacing the
+session. The archive is the shared strict ustar format containing
+`pgdata/**` and `.oliphaunt/backup-manifest.properties`. `restore` accepts only
+an absent or empty persistent destination, validates the complete archive
+before publication, and creates the receiving storage provider's outer
+identity. Browser root restores in its importing realm. On native hosts the
+root uses the Rust owner actor, `/direct` restores on the importing JavaScript
+thread, and `/worker` uses a temporary package-owned Worker.
+
+## Extensions
+
+Import package-authored WASIX extension descriptors and pass them at open:
+
+```ts
+import Oliphaunt from '@oliphaunt/wasix-ts';
+import pgtap from '@oliphaunt/extension-pgtap-wasix';
+
+await using database = await Oliphaunt.open({ extensions: [pgtap] });
+await database.execute('CREATE EXTENSION pgtap');
+const version = await database.query('select pgtap_version()');
+```
+
+The call shape and lifecycle ownership are host-independent. A browser verifies
+the selected carrier and its dependency closure, installs its artifacts before
+startup, and applies required startup/preload settings. Node.js, Bun, Deno, and Electron
+validate the same descriptor but resolve its SQL name against the extension
+catalog compiled into the platform addon. Release addons contain the complete
+currently supported extension catalog; they do not load arbitrary side-module
+bytes from npm at runtime. Adding or upgrading a server extension therefore
+requires a matching N-API carrier release. This increases the carrier size in
+exchange for eliminating runtime archive expansion and dynamic linking on the
+native path.
+
+Neither host runs database-local `CREATE EXTENSION`, `LOAD`, schema,
+post-create, upgrade, or migration SQL. Applications and ORM migrations own
+those ordinary PostgreSQL statements explicitly; selecting a descriptor makes
+its code available but leaves the extension uninstalled in the database.
+
+## Calling shape and execution placement
+
+The normal import keeps the public API consistent while selecting the safest
+default placement for the host:
+
+```ts
+import Oliphaunt from '@oliphaunt/wasix-ts';
+
+await using database = await Oliphaunt.open();
+```
+
+On Node.js, Bun, Deno, and Electron, use `/direct` only when the lowest-hop path
+is more important than keeping the importing event loop responsive:
+
+```ts
+import DirectOliphaunt from '@oliphaunt/wasix-ts/direct';
+
+await using database = await DirectOliphaunt.open();
+```
+
+Use the explicit Worker import when a separate JavaScript realm is part of the
+application's isolation or placement model:
+
+```ts
+import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker';
+
+await using database = await WorkerOliphaunt.open();
+```
+
+All imports expose the same PostgreSQL interface and retain the promise-shaped
+public API. A Promise does not itself imply off-thread execution. In a browser,
+the root steps the Wasmer guest in the importing realm. On native hosts, the
+root uses one Rust owner actor so PostgreSQL does not block the importing event
+loop. `/direct` calls the synchronous Rust database on the importing thread and
+removes that actor hop. `/worker` uses a real package-owned JavaScript Worker on
+every runtime and loads the direct implementation inside it.
+
+Importing the browser root or `/direct` from an application Worker blocks only
+that Worker; importing the browser root in a Window can block the page. Browser
+Worker use requires cross-origin isolation. Chromium Window compilation
+of native side modules larger than 8 MiB requires `/worker`.
+
+## Optional PostgreSQL tools
+
+Install `@oliphaunt/wasix-tools` when the application needs standard plain
+`pg_dump` or non-interactive `psql`:
+
+```ts
+import Oliphaunt from '@oliphaunt/wasix-ts';
+import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker';
+import { pgDump, psql } from '@oliphaunt/wasix-tools';
+
+await using source = await Oliphaunt.open();
+const sql = await pgDump(source, { args: ['--schema-only'] });
+await using target = await WorkerOliphaunt.open();
+await psql(target, { script: sql });
+```
+
+`pgDump()` runs with the database's existing owner, so it supports root,
+`/direct`, and `/worker` entrypoints where available. In browsers, `psql()` requires `/worker`
+because restoring COPY input is full duplex. Node.js, Bun, Deno, and Electron route both
+tools through the frontend binaries compiled into the native carrier, so
+`psql()` works with root, `/direct`, and `/worker` on those hosts. The optional
+`@oliphaunt/wasix-tools` package remains the public opt-in API even though the
+native carrier includes the tool code at build time. Adding or changing a tool
+requires a matching N-API carrier release.
+
+The package preserves PostgreSQL's normal plain SQL and COPY output. It does
+not support interactive psql, custom dump archives, parallel jobs, or
+pg_restore.
+
+## Optional local server
+
+Node, Bun, Deno, and Electron may import `openServer` from the shared host-only server
+subpath. Package export conditions select the runtime; browsers cannot resolve
+this entrypoint:
+
+```ts
+import { openServer } from '@oliphaunt/wasix-ts/server';
+
+await using server = await openServer({
+  listen: { transport: 'tcp' },
+});
+console.log(server.connectionString);
+```
+
+The lightweight compatibility endpoint binds IPv4 loopback with an automatic
+port when `port` is omitted. Unix hosts may instead pass
+`{ transport: 'unix', directory, port? }`; the socket follows PostgreSQL's
+`.s.PGSQL.` convention. One complete client connection owns the single
+embedded backend at a time; another connection may wait in the operating-system
+backlog, so configure client pools with a maximum size of one. The server
+entrypoint wraps the Rust `OliphauntServer` directly; it does not create a
+JavaScript socket relay or managed Worker. The listener and storage lease
+persist, while each admitted client receives a fresh backend.
+Use the separate WASIX postmaster product for concurrent PostgreSQL sessions.
+The server's read-only `closed` property remains `false` while terminal teardown
+is running and becomes `true` when that memoized attempt settles, including when
+cleanup rejects.
+
+## Scope
+
+The core database surface remains limited to open, execute/query/queryRaw,
+exec/describe, buffered and callback-streamed raw protocol, callback
+transaction, physical backup/restore, read-only `closed`, and close.
+Tools and local sockets stay in optional packages or host-only subpaths.
+Cancellation and a dedicated typed COPY reader/writer are not exposed today.
+
+## Working on this package
+
+After installing the workspace's pinned tools and workspace dependencies, run
+from this directory:
+
+```sh
+moon run oliphaunt-wasix-ts:build
+bun run format-check
+bun run lint
+bun run typecheck
+bun run test
+moon run oliphaunt-wasix-ts:package
+```
+
+Moon builds the independently versioned query dependency before the TypeScript SDK.
+Packaging additionally builds the Rust browser host through its Moon dependency.
+Runtime carrier and browser/Node/Bun/Deno/Electron host smokes are defined in the
+packages' Moon tasks. Native-host smokes install the packed SDK and matching
+packed optional carrier into a fresh external project. Use
+`moon run oliphaunt-wasix-ts:test-consumer` for Node/Bun/Deno/Electron and
+`moon run oliphaunt-wasix-ts:test-browser` for Chrome. These own their runtime
+prerequisites. `bun run package`, `bun run test-consumer`, and
+`bun run test-browser` run the same recipes against already built inputs.
diff --git a/src/sdks/ts-wasix/sdk/bunfig.toml b/src/sdks/ts-wasix/sdk/bunfig.toml
new file mode 100644
index 000000000..37ff1f948
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/bunfig.toml
@@ -0,0 +1,2 @@
+[test]
+preload = ["./src/__tests__/setup.ts"]
diff --git a/src/sdks/ts-wasix/sdk/moon.yml b/src/sdks/ts-wasix/sdk/moon.yml
new file mode 100644
index 000000000..05bba368c
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/moon.yml
@@ -0,0 +1,200 @@
+$schema: https://moonrepo.dev/schemas/project.json
+id: oliphaunt-wasix-ts
+language: typescript
+layer: library
+stack: frontend
+tags:
+  - javascript-quality
+  - binding
+  - wasix
+  - wasm
+  - typescript
+  - browser
+  - node
+  - bun
+  - deno
+  - sdk
+  - release-product
+dependsOn:
+  - id: wasix-browser-host
+    scope: build
+  - id: oliphaunt-query-ts
+    scope: build
+  - id: cluster-seed-contract
+    scope: development
+  - id: shared-test-fixtures
+    scope: development
+  - liboliphaunt-wasix
+  - oliphaunt-wasix-napi
+project:
+  title: Oliphaunt WASIX TypeScript binding
+  description: Universal WASIX TypeScript binding with browser and native host placements.
+  owner: oliphaunt
+  release:
+    component: oliphaunt-wasix-ts
+    packagePath: src/sdks/ts-wasix/sdk
+owners:
+  defaultOwner: "@oliphaunt/sdk-js"
+fileGroups:
+  code:
+    - "**/*"
+    - "!**/*.md"
+    - "!moon.yml"
+    - "!release.toml"
+tasks:
+  build:
+    tags:
+      - build
+    command: bun run --cwd src/sdks/ts-wasix/sdk build
+    deps:
+      - oliphaunt-query-ts:build
+    inputs:
+      - "@group(bun-workspace)"
+      - "@group(code)"
+      - project: oliphaunt-query-ts
+        group: sources
+    outputs:
+      - lib/**/*
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  typecheck:
+    tags:
+      - quality
+      - static
+    command: bun run --cwd src/sdks/ts-wasix/sdk typecheck
+    deps:
+      - oliphaunt-query-ts:build
+    inputs:
+      - "@group(bun-workspace)"
+      - project: oliphaunt-query-ts
+        group: sources
+      - "@group(code)"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  package:
+    tags:
+      - package
+      - release
+      - artifact-package
+      - ci-wasix-ts-sdk-package
+    script: bun run --cwd src/sdks/ts-wasix/sdk package
+    deps:
+      - wasix-browser-host:build
+      - oliphaunt-wasix-ts:build
+    inputs:
+      - "@group(legal-files)"
+      - "@group(bun-workspace)"
+      - "@group(release-archive-contract)"
+      - /src/sdks/ts-wasix/sdk/tools/check-package.mts
+      - /tools/packaging/npm-trusted-publishing.mts
+      - /tools/packaging/staging.mts
+      - /src/sdks/ts-wasix/sdk/tools/stage-release-artifacts.mts
+      - /src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.mts
+      - /tools/dev/bun.sh
+      - "@group(legal-files)"
+      - "@group(release-archive-contract)"
+      - "@group(bun-workspace)"
+      - project: oliphaunt-query-ts
+        group: sources
+      - "**/*"
+    outputs:
+      - /target/sdk-artifacts/oliphaunt-wasix-ts/**/*
+      - /target/oliphaunt-wasix-ts/package/**/*
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  coverage:
+    tags:
+      - coverage
+    command: bun run coverage
+    deps:
+      - oliphaunt-query-ts:build
+    inputs:
+      - "@group(code)"
+      - "@group(bun-workspace)"
+      - project: oliphaunt-query-ts
+        group: sources
+      - project: shared-test-fixtures
+        group: fixtures
+    outputs:
+      - /target/coverage/oliphaunt-wasix-ts/**/*
+    options:
+      cache: false
+      runInCI: false
+  test:
+    tags:
+      - quality
+      - unit
+    command: bun run --cwd src/sdks/ts-wasix/sdk test
+    deps:
+      - oliphaunt-query-ts:build
+    inputs:
+      - "@group(bun-workspace)"
+      - project: oliphaunt-query-ts
+        group: sources
+      - project: shared-test-fixtures
+        group: fixtures
+      - project: cluster-seed-contract
+        group: contract
+      - "@group(code)"
+      - "@group(release-target-contract)"
+      - "@group(package-test-metadata)"
+      - "**/*.{mjs,mts}"
+      - /tools/packaging/testdata/**/*
+      - /tools/dev/bun.sh
+      - "/tools/packaging/*.{mts,sh}"
+      - "/tools/release/*.{mjs,mts}"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  test-consumer:
+    tags:
+      - integration
+      - consumer
+      - ci-wasix-ts-sdk-package
+    deps:
+      - extension-artifacts-wasix:compiler-output
+      - liboliphaunt-wasix:runtime-portable
+      - oliphaunt-wasix-ts:package
+      - oliphaunt-wasix-napi:build-release-assets
+    inputs:
+      &inputs
+      - "@group(legal-files)"
+      - "@group(bun-workspace)"
+      - /src/examples/browser-wasix/**/*
+      - project: shared-test-fixtures
+        group: fixtures
+      - "**/*"
+      - /tools/dev/bun.sh
+      - /tools/dev/deno.sh
+      - /src/runtimes/liboliphaunt-wasix/tools/wasix-*.mts
+    options:
+      &options
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: true
+    command: bun run --cwd src/sdks/ts-wasix/sdk test-consumer
+  test-browser:
+    tags:
+      - integration
+      - browser
+      - ci-wasix-ts-sdk-package
+    deps:
+      - extension-artifacts-wasix:compiler-output
+      - database-resources:package-wasix
+      - database-resources:package-icu
+      - liboliphaunt-wasix:runtime-portable
+      - oliphaunt-wasix-ts:package
+    inputs:
+      *inputs
+    options:
+      *options
+    command: bun run --cwd src/sdks/ts-wasix/sdk test-browser
+workspace:
+  inheritedTasks:
+    rename:
+      js-format: format
+      js-format-check: format-check
+      js-lint: lint
diff --git a/src/sdks/ts-wasix/sdk/package.json b/src/sdks/ts-wasix/sdk/package.json
new file mode 100644
index 000000000..372fbcd87
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/package.json
@@ -0,0 +1,179 @@
+{
+  "name": "@oliphaunt/wasix-ts",
+  "version": "0.1.0",
+  "description": "Portable Oliphaunt WASIX TypeScript SDK for browsers, Node.js, Bun, Deno, and Electron.",
+  "license": "MIT",
+  "type": "module",
+  "sideEffects": [
+    "./lib/browser.js",
+    "./lib/native-only.js"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts-wasix/sdk"
+  },
+  "bugs": {
+    "url": "https://github.com/f0rr0/oliphaunt/issues"
+  },
+  "homepage": "https://oliphaunt.dev",
+  "oliphaunt": {
+    "runtimeProduct": "liboliphaunt-wasix",
+    "runtimeVersion": "0.2.0",
+    "wasixNapiProduct": "oliphaunt-wasix-napi",
+    "wasixNapiVersion": "0.1.0",
+    "wasixAddonAbiVersion": 2,
+    "nodeApiVersion": 8,
+    "browserHost": "wasmer-js-patched",
+    "serverHost": "wasix-rust-napi"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "exports": {
+    ".": {
+      "deno": {
+        "types": "./lib/index.deno.d.ts",
+        "default": "./lib/index.deno.js"
+      },
+      "bun": {
+        "types": "./lib/index.bun.d.ts",
+        "default": "./lib/index.bun.js"
+      },
+      "node": {
+        "types": "./lib/index.node.d.ts",
+        "default": "./lib/index.node.js"
+      },
+      "browser": {
+        "types": "./lib/index.d.ts",
+        "default": "./lib/index.js"
+      },
+      "default": {
+        "types": "./lib/index.d.ts",
+        "default": "./lib/index.js"
+      }
+    },
+    "./worker": {
+      "deno": {
+        "types": "./lib/worker-entry.deno.d.ts",
+        "default": "./lib/worker-entry.deno.js"
+      },
+      "bun": {
+        "types": "./lib/worker-entry.bun.d.ts",
+        "default": "./lib/worker-entry.bun.js"
+      },
+      "node": {
+        "types": "./lib/worker-entry.node.d.ts",
+        "default": "./lib/worker-entry.node.js"
+      },
+      "browser": {
+        "types": "./lib/worker-entry.d.ts",
+        "default": "./lib/worker-entry.js"
+      },
+      "default": {
+        "types": "./lib/worker-entry.d.ts",
+        "default": "./lib/worker-entry.js"
+      }
+    },
+    "./direct": {
+      "types": "./lib/direct.node.d.ts",
+      "deno": "./lib/direct.node.js",
+      "bun": "./lib/direct.node.js",
+      "node": "./lib/direct.node.js",
+      "browser": "./lib/native-only.js",
+      "default": "./lib/native-only.js"
+    },
+    "./internal/tools": {
+      "types": "./lib/internal.d.ts",
+      "deno": "./lib/internal.node.js",
+      "bun": "./lib/internal.node.js",
+      "node": "./lib/internal.node.js",
+      "browser": "./lib/internal.js",
+      "default": "./lib/internal.js"
+    },
+    "./server": {
+      "types": "./lib/server.node.d.ts",
+      "deno": "./lib/server.node.js",
+      "bun": "./lib/server.node.js",
+      "node": "./lib/server.node.js",
+      "browser": "./lib/native-only.js",
+      "default": "./lib/native-only.js"
+    },
+    "./storage/indexed-db": {
+      "types": "./lib/storage/indexed-db.d.ts",
+      "default": "./lib/storage/indexed-db.js"
+    },
+    "./storage/opfs": {
+      "types": "./lib/storage/opfs.d.ts",
+      "default": "./lib/storage/opfs.js"
+    },
+    "./storage/node": {
+      "types": "./lib/storage/node.d.ts",
+      "node": "./lib/storage/node.js"
+    },
+    "./storage/bun": {
+      "types": "./lib/storage/bun.d.ts",
+      "bun": "./lib/storage/bun.js"
+    },
+    "./storage/deno": {
+      "types": "./lib/storage/deno.d.ts",
+      "deno": "./lib/storage/deno.js"
+    },
+    "./package.json": {
+      "default": "./package.json"
+    },
+    "./browser": {
+      "types": "./lib/browser.d.ts",
+      "default": "./lib/browser.js"
+    }
+  },
+  "main": "lib/index.js",
+  "module": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "files": [
+    "lib",
+    "README.md",
+    "ARCHITECTURE.md",
+    "CHANGELOG.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md"
+  ],
+  "scripts": {
+    "build": "rm -rf lib && tsc -p tsconfig.build.json",
+    "dev": "bun run host:build && bun run build && bun tools/stage-host.mts && vite --config ../../../examples/browser-wasix/vite.config.ts",
+    "host:build": "bash ../../../runtimes/wasix-browser-host/build-sdk.sh",
+    "test": "bun test --isolate --timeout=30000 ./src/__tests__ ./tools/wasix-typescript-package.test.mts",
+    "typecheck": "tsc --noEmit",
+    "clean": "rm -rf lib",
+    "coverage": "bun test --isolate --timeout=30000 ./src/__tests__ --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=../../../../target/coverage/oliphaunt-wasix-ts",
+    "format": "bun x --no-install biome format --write --no-errors-on-unmatched .",
+    "format-check": "bun x --no-install biome format --no-errors-on-unmatched .",
+    "lint": "bun x --no-install biome lint --diagnostic-level=error --no-errors-on-unmatched .",
+    "test-consumer": "bash tools/integration/test-consumer.sh",
+    "test-browser": "bash tools/integration/test-browser.sh",
+    "package": "bash tools/package.sh"
+  },
+  "dependencies": {
+    "@oliphaunt/ts-query": "0.1.0",
+    "fzstd": "0.1.1"
+  },
+  "optionalDependencies": {
+    "@oliphaunt/wasix-napi-darwin-arm64": "workspace:*",
+    "@oliphaunt/wasix-napi-linux-arm64-gnu": "workspace:*",
+    "@oliphaunt/wasix-napi-linux-x64-gnu": "workspace:*",
+    "@oliphaunt/wasix-napi-win32-x64-msvc": "workspace:*"
+  },
+  "devDependencies": {
+    "@electric-sql/pglite": "0.5.4",
+    "@types/node": "^24.10.1",
+    "typescript": "catalog:",
+    "vite": "^6.0.3",
+    "@types/bun": "catalog:"
+  },
+  "engines": {
+    "node": ">=22.13 <25",
+    "bun": ">=1.3.14",
+    "deno": ">=2.8.1"
+  }
+}
diff --git a/src/sdks/ts-wasix/sdk/release.toml b/src/sdks/ts-wasix/sdk/release.toml
new file mode 100644
index 000000000..50b3ecf59
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/release.toml
@@ -0,0 +1,29 @@
+id = "oliphaunt-wasix-ts"
+owner = "@oliphaunt/sdk-js"
+kind = "sdk"
+publish_targets = ["npm"]
+registry_packages = [
+  "npm:@oliphaunt/wasix-ts",
+]
+release_artifacts = [
+  "npm-package",
+  "browser-worker",
+  "node-bun-deno-electron-node-api",
+  "node-bun-deno-electron-native-actor",
+  "node-bun-deno-electron-worker",
+]
+
+[compatibility_versions.oliphaunt-wasix-ts-runtime]
+source_product = "liboliphaunt-wasix"
+path = "src/sdks/ts-wasix/sdk/package.json"
+parser = "json:oliphaunt.runtimeVersion"
+
+[compatibility_versions.oliphaunt-wasix-ts-napi]
+source_product = "oliphaunt-wasix-napi"
+path = "src/sdks/ts-wasix/sdk/package.json"
+parser = "json:oliphaunt.wasixNapiVersion"
+
+[compatibility_versions.oliphaunt-wasix-ts-query]
+source_product = "oliphaunt-query-ts"
+path = "src/sdks/ts-wasix/sdk/package.json"
+parser = "json:dependencies.@oliphaunt/ts-query"
diff --git a/src/bindings/wasix-ts/src/__tests__/archive.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/archive.test.ts
similarity index 99%
rename from src/bindings/wasix-ts/src/__tests__/archive.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/archive.test.ts
index 7169d4977..153d3d7ff 100644
--- a/src/bindings/wasix-ts/src/__tests__/archive.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/archive.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
 
 import {
   clusterSeedMount,
diff --git a/src/bindings/wasix-ts/src/__tests__/asset-source.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/asset-source.test.ts
similarity index 90%
rename from src/bindings/wasix-ts/src/__tests__/asset-source.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/asset-source.test.ts
index f7467c333..5c7ea4138 100644
--- a/src/bindings/wasix-ts/src/__tests__/asset-source.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/asset-source.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it, vi } from 'vitest';
+import { describe, expect, it, vi } from 'bun:test';
 
 import { installPackageAssetReader, readPackageAsset } from '../asset-source.js';
 
@@ -13,7 +13,7 @@ describe('WASIX package asset reader', () => {
     await expect(readPackageAsset('file:///runtime.tar.zst', 'runtime archive')).resolves.toEqual(
       new TextEncoder().encode('/runtime.tar.zst'),
     );
-    expect(reader).toHaveBeenCalledOnce();
+    expect(reader).toHaveBeenCalledTimes(1);
     await expect(
       readPackageAsset('https://example.test/runtime', 'runtime archive'),
     ).rejects.toThrow('cannot read package-relative runtime archive URL');
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/browser-tool-arguments.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/browser-tool-arguments.test.ts
new file mode 100644
index 000000000..b09c53183
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/browser-tool-arguments.test.ts
@@ -0,0 +1,53 @@
+import { expect, it, vi } from 'bun:test';
+import type { OliphauntDatabase } from '../types.js';
+import type { WasixToolProcessOptions } from '../tool-runtime.js';
+
+const runTool = vi.fn(async (_database: OliphauntDatabase, _options: WasixToolProcessOptions) => ({
+  exitCode: 0,
+  stdout: new Uint8Array(),
+  stderr: new Uint8Array(),
+}));
+vi.mock('../internal-common.js', () => ({ runWasixToolProcess: runTool }));
+vi.mock('../database.js', () => ({
+  getWasixDatabaseIdentity: () => ({
+    username: '-application user',
+    database: '-application database',
+  }),
+}));
+const { runWasixToolProcess } = await import('../internal.js');
+
+it('adds browser connection and input arguments at the execution boundary', async () => {
+  for (const name of ['pg_dump', 'psql'] as const) {
+    for (const input of [
+      {},
+      { command: 'select 1' },
+      { stdin: new TextEncoder().encode('select 2') },
+    ]) {
+      if (name === 'pg_dump' && Object.keys(input).length !== 0) continue;
+      await runWasixToolProcess({} as OliphauntDatabase, {
+        runtimeVersion: '0.1.1',
+        tool: { name, sha256: 'a'.repeat(64), size: 1, source: Uint8Array.of(1) },
+        args: ['--verbose'],
+        ...input,
+      });
+      expect(runTool.mock.calls.at(-1)?.[1]).toMatchObject({
+        ...input,
+        args: [
+          '--verbose',
+          ...(name === 'pg_dump'
+            ? ['--encoding=UTF8', '--no-password']
+            : ['--no-psqlrc', '--no-password', '--set=ON_ERROR_STOP=1']),
+          '--username=-application user',
+          '--host=127.0.0.1',
+          '--port=65432',
+          '--dbname=-application database',
+          ...('command' in input
+            ? ['--command', input.command]
+            : 'stdin' in input
+              ? ['--file=-']
+              : []),
+        ],
+      });
+    }
+  }
+});
diff --git a/src/bindings/wasix-ts/src/__tests__/byte-channel.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/byte-channel.test.ts
similarity index 97%
rename from src/bindings/wasix-ts/src/__tests__/byte-channel.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/byte-channel.test.ts
index 3670f700f..15869b255 100644
--- a/src/bindings/wasix-ts/src/__tests__/byte-channel.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/byte-channel.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
 import {
   closeWasixByteChannel,
   createWasixByteChannel,
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/client-common.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/client-common.test.ts
new file mode 100644
index 000000000..3cc921a0a
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/client-common.test.ts
@@ -0,0 +1,192 @@
+import { describe, expect, it, vi } from 'bun:test';
+
+vi.mock('@oliphaunt/liboliphaunt-wasix', () => ({
+  POSTGRES_MAJOR: 18,
+  PHYSICAL_FORMAT: 'wasix-pg18-v1',
+  default: {
+    schema: 'oliphaunt-wasix-runtime-v2',
+    runtime: 'wasix',
+    product: 'liboliphaunt-wasix',
+    version: '0.1.1',
+    runtimeArchive: {
+      archive: 'oliphaunt.wasix.tar.zst',
+      sha256: '1'.repeat(64),
+      size: 1,
+      source: Uint8Array.of(1),
+    },
+    manifest: {
+      sha256: '3'.repeat(64),
+      size: 1,
+      source: Uint8Array.of(3),
+    },
+  },
+}));
+
+import { restoreWasix, serializeOpenConfig } from '../client-common.js';
+import { indexedDB } from '../storage/indexed-db.js';
+import type { WasixRuntimeDescriptor } from '../types.js';
+import { openWasixWithWorker, restoreWasixWithWorker } from '../worker-rpc.js';
+import { FakeWorkerPort, workerOpenOptions } from './worker-helpers.js';
+
+describe('WASIX shared client orchestration', () => {
+  it('serializes independent seed and ICU sources without retaining caller buffers', () => {
+    const data = Uint8Array.of(1);
+    const options = serializeOpenConfig(
+      {
+        icu: { data, manifest: new URL('https://example.test/icu.properties') },
+        seed: { archive: Uint8Array.of(2), manifest: Uint8Array.of(3) },
+      },
+      runtimeDescriptor(Uint8Array.of(1)),
+    );
+    data[0] = 9;
+    expect(options.icu).toEqual({
+      data: Uint8Array.of(1),
+      manifest: 'https://example.test/icu.properties',
+    });
+    expect(options.seed).toEqual({ archive: Uint8Array.of(2), manifest: Uint8Array.of(3) });
+  });
+
+  it('serializes caller configuration without retaining mutable asset buffers', () => {
+    const runtimeBytes = new Uint8Array(4).fill(1);
+    const options = serializeOpenConfig(
+      {
+        username: 'app',
+        database: 'todos',
+        startupGUCs: { search_path: 'app, public' },
+      },
+      runtimeDescriptor(runtimeBytes),
+    );
+
+    runtimeBytes[0] = 9;
+    expect(options).toMatchObject({
+      username: 'app',
+      database: 'todos',
+      startupGUCs: { search_path: 'app, public' },
+      storage: { schema: 'oliphaunt-wasix-storage-v1', kind: 'memory' },
+    });
+    expect(options.runtime.runtimeArchive.source).toEqual(Uint8Array.of(1, 1, 1, 1));
+  });
+
+  it('canonicalizes case-insensitive GUCs and rejects storage redirection before open', () => {
+    const options = serializeOpenConfig(
+      { startupGUCs: { work_mem: '1MB', WORK_MEM: '2MB' } },
+      runtimeDescriptor(Uint8Array.of(1)),
+    );
+    expect(options.startupGUCs).toEqual({ work_mem: '2MB' });
+
+    for (const name of ['CONFIG_FILE', 'data_directory']) {
+      expect(() =>
+        serializeOpenConfig(
+          { startupGUCs: { [name]: '/tmp/other' } },
+          runtimeDescriptor(Uint8Array.of(1)),
+        ),
+      ).toThrow('owns PostgreSQL startup GUC');
+    }
+  });
+
+  it('validates before opening and transfers each distinct runtime buffer once', async () => {
+    const port = new FakeWorkerPort();
+    const options = workerOpenOptions();
+    const shared = Uint8Array.of(1, 2);
+    const manifest = Uint8Array.of(3);
+    options.runtime.runtimeArchive.source = shared;
+    options.seed = { archive: shared, manifest };
+    options.runtime.manifest.source = manifest;
+    const validate = vi.fn();
+    const opening = openWasixWithWorker(
+      (received) => {
+        expect(received).toBe(options);
+        return port;
+      },
+      options,
+      validate,
+    );
+
+    expect(validate).toHaveBeenCalledWith(options);
+    const open = port.requests[0];
+    expect(open?.message.method).toBe('open');
+    expect(open?.transfer).toEqual([shared.buffer, manifest.buffer]);
+    if (open === undefined) throw new Error('open request was not posted');
+    port.respond({ id: open.message.id, ok: true });
+    const database = await opening;
+
+    const closing = database.close();
+    await Promise.resolve();
+    const close = port.requests[1]?.message;
+    if (close === undefined) throw new Error('close request was not posted');
+    port.respond({ id: close.id, ok: true });
+    await closing;
+  });
+
+  it('rejects restore without an explicit persistent storage target', async () => {
+    await expect(restoreWasix(undefined, Uint8Array.of())).rejects.toThrow(
+      'WASIX restore requires persistent storage',
+    );
+  });
+
+  it('runs Worker restore without detaching caller bytes', async () => {
+    const port = new FakeWorkerPort();
+    const bytes = Uint8Array.of(1, 2, 3);
+    const restoring = restoreWasixWithWorker(() => port, indexedDB('restore-target'), bytes);
+    const request = port.requests[0];
+    expect(request?.message).toMatchObject({ method: 'restore' });
+    if (request?.message.method !== 'restore') throw new Error('restore request was not posted');
+    expect(request.message.bytes).toEqual(bytes);
+    expect(request.message.bytes).not.toBe(bytes);
+    expect(request.transfer).toEqual([request.message.bytes.buffer]);
+    expect(bytes).toEqual(Uint8Array.of(1, 2, 3));
+    port.respond({ id: request.message.id, ok: true });
+
+    await expect(restoring).resolves.toBeUndefined();
+    expect(port.terminations).toBe(1);
+  });
+
+  it('preserves both Worker restore and termination failures', async () => {
+    const port = new FakeWorkerPort();
+    port.terminate = () => {
+      port.terminations += 1;
+      throw new Error('worker termination failed');
+    };
+    const restoring = restoreWasixWithWorker(
+      () => port,
+      indexedDB('restore-failure-target'),
+      Uint8Array.of(1),
+    );
+    const request = port.requests[0]?.message;
+    if (request === undefined) throw new Error('restore request was not posted');
+    port.respond({
+      id: request.id,
+      ok: false,
+      error: { name: 'Error', message: 'restore failed' },
+    });
+
+    const failure = await restoring.catch((error: unknown) => error);
+    expect(failure).toBeInstanceOf(AggregateError);
+    if (!(failure instanceof AggregateError)) throw new Error('expected aggregate restore failure');
+    expect(failure.errors).toEqual([
+      expect.objectContaining({ message: 'restore failed' }),
+      expect.objectContaining({ message: 'worker termination failed' }),
+    ]);
+    expect(port.terminations).toBe(1);
+  });
+});
+
+function runtimeDescriptor(runtimeBytes: Uint8Array): WasixRuntimeDescriptor {
+  return {
+    schema: 'oliphaunt-wasix-runtime-v2',
+    runtime: 'wasix',
+    product: 'liboliphaunt-wasix',
+    version: '0.1.1',
+    runtimeArchive: {
+      archive: 'oliphaunt.wasix.tar.zst',
+      sha256: '1'.repeat(64),
+      size: runtimeBytes.byteLength,
+      source: runtimeBytes,
+    },
+    manifest: {
+      sha256: '3'.repeat(64),
+      size: 1,
+      source: Uint8Array.of(3),
+    },
+  };
+}
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/client.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/client.test.ts
new file mode 100644
index 000000000..d397d779d
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/client.test.ts
@@ -0,0 +1,112 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from 'bun:test';
+
+const directMocks = {
+  openWasixDirect: vi.fn(),
+  openNodeActor: vi.fn(),
+  openNodeDirect: vi.fn(),
+};
+
+vi.mock('../direct-client-common.js', () => ({
+  openWasixDirect: directMocks.openWasixDirect,
+}));
+vi.mock('../node-direct.js', () => ({
+  openNodeDirect: directMocks.openNodeDirect,
+}));
+vi.mock('../node-actor.js', () => ({
+  openNodeActor: directMocks.openNodeActor,
+}));
+vi.mock('../worker-rpc.js', () => {
+  throw new Error('root entrypoint loaded Worker RPC machinery');
+});
+vi.mock('../native-session.js', () => ({
+  restoreNativeWasix: vi.fn(),
+  restoreNativeWasixDirect: vi.fn(),
+}));
+
+import { openWasixWithHost } from '../client.js';
+import { directory } from '../storage/node.js';
+import type { OliphauntDatabase } from '../types.js';
+
+let crossOriginDescriptor: PropertyDescriptor | undefined;
+let workerDescriptor: PropertyDescriptor | undefined;
+
+beforeEach(() => {
+  crossOriginDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'crossOriginIsolated');
+  workerDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'Worker');
+  Object.defineProperty(globalThis, 'crossOriginIsolated', {
+    configurable: true,
+    value: true,
+  });
+  Object.defineProperty(globalThis, 'Worker', {
+    configurable: true,
+    value: class ForbiddenWorker {
+      constructor() {
+        throw new Error('root entrypoint constructed a Worker');
+      }
+    },
+  });
+  directMocks.openWasixDirect.mockReset();
+  directMocks.openWasixDirect.mockResolvedValue({} as OliphauntDatabase);
+  directMocks.openNodeDirect.mockReset();
+  directMocks.openNodeDirect.mockResolvedValue({} as OliphauntDatabase);
+  directMocks.openNodeActor.mockReset();
+  directMocks.openNodeActor.mockResolvedValue({} as OliphauntDatabase);
+});
+
+describe('WASIX Node-compatible root execution surface', () => {
+  it('opens through the Rust actor without loading Worker RPC machinery', async () => {
+    const { openWasix } = await import('../node-client.js');
+
+    const database = await openWasix();
+
+    expect(database).toBe(await directMocks.openNodeActor.mock.results[0]?.value);
+    expect(directMocks.openNodeActor).toHaveBeenCalledTimes(1);
+    expect(directMocks.openNodeDirect).not.toHaveBeenCalled();
+  });
+
+  it('keeps the explicit direct placement in the importing realm', async () => {
+    const { openWasix } = await import('../direct-client.js');
+
+    const database = await openWasix();
+
+    expect(database).toBe(await directMocks.openNodeDirect.mock.results[0]?.value);
+    expect(directMocks.openNodeDirect).toHaveBeenCalledTimes(1);
+    expect(directMocks.openNodeActor).not.toHaveBeenCalled();
+  });
+});
+
+afterEach(() => {
+  restoreGlobal('crossOriginIsolated', crossOriginDescriptor);
+  restoreGlobal('Worker', workerDescriptor);
+});
+
+describe('WASIX browser root execution surface', () => {
+  it('rejects explicit browser entrypoint imports on native hosts', async () => {
+    await expect(import('../browser.js')).rejects.toThrow('requires a browser or browser worker');
+  });
+
+  it('rejects native storage before loading the browser host', async () => {
+    const loadHost = vi.fn();
+    // @ts-expect-error Exercise the JavaScript boundary with native-only storage.
+    await expect(openWasixWithHost({ storage: directory('/db') }, loadHost)).rejects.toThrow(
+      'directory storage is native-only',
+    );
+    expect(loadHost).not.toHaveBeenCalled();
+  });
+
+  it('opens through the caller-realm engine and never constructs a Worker', async () => {
+    const database = await openWasixWithHost(
+      { username: 'application' },
+      async () => ({}) as never,
+    );
+
+    expect(database).toBe(await directMocks.openWasixDirect.mock.results[0]?.value);
+    expect(directMocks.openWasixDirect).toHaveBeenCalledTimes(1);
+    expect(directMocks.openWasixDirect.mock.calls[0]?.[2]).toBe('browser-main');
+  });
+});
+
+function restoreGlobal(name: string, descriptor: PropertyDescriptor | undefined): void {
+  if (descriptor === undefined) Reflect.deleteProperty(globalThis, name);
+  else Object.defineProperty(globalThis, name, descriptor);
+}
diff --git a/src/bindings/wasix-ts/src/__tests__/database.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/database.test.ts
similarity index 97%
rename from src/bindings/wasix-ts/src/__tests__/database.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/database.test.ts
index 240aa5a25..c0578b88c 100644
--- a/src/bindings/wasix-ts/src/__tests__/database.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/database.test.ts
@@ -1,12 +1,12 @@
-import { describe, expect, it, vi } from 'vitest';
-
+import { describe, expect, it, vi } from 'bun:test';
+import { rejects } from 'node:assert/strict';
+import { createWasixByteChannel } from '../byte-channel.js';
 import {
   assertWasixProtocolConnectionTarget,
   normalizeWasixDatabaseIdentity,
   WasixDatabaseImpl,
   type WasixDatabaseSession,
 } from '../database.js';
-import { createWasixByteChannel } from '../byte-channel.js';
 import { WasixStorageError } from '../errors.js';
 import { PostgresError } from '../query.js';
 import type { OliphauntTransaction } from '../types.js';
@@ -104,7 +104,7 @@ describe('WASIX database recovery state', () => {
     const transaction = database.transaction(() => {
       bodyEntered = true;
     });
-    const transactionFailure = expect(transaction).rejects.toThrow(/database is closing/);
+    const transactionFailure = rejects(transaction, /database is closing/);
 
     await database.close();
     await transactionFailure;
@@ -1123,10 +1123,11 @@ describe('WASIX database recovery state', () => {
       await Promise.resolve();
 
       const closeAttempt = database.close();
-      const close = expect(closeAttempt).rejects.toThrow(
-        'close exceeded 120000ms; worker termination was requested',
+      const close = rejects(closeAttempt, (error: Error) =>
+        error.message.includes('close exceeded 120000ms; worker termination was requested'),
       );
-      await vi.advanceTimersByTimeAsync(120_000);
+      while (vi.getTimerCount() === 0) await Promise.resolve();
+      vi.advanceTimersByTime(120_000);
       await close;
       expect(aborts).toBe(1);
       expect(database.closed).toBe(true);
@@ -1176,10 +1177,11 @@ describe('WASIX database recovery state', () => {
       void closeAttempt.catch(() => {
         settled = true;
       });
-      const close = expect(closeAttempt).rejects.toThrow(
-        'close exceeded 120000ms; worker termination was requested',
+      const close = rejects(closeAttempt, (error: Error) =>
+        error.message.includes('close exceeded 120000ms; worker termination was requested'),
       );
-      await vi.advanceTimersByTimeAsync(120_000);
+      while (vi.getTimerCount() === 0) await Promise.resolve();
+      vi.advanceTimersByTime(120_000);
       expect(events).toEqual(['abort']);
       expect(settled).toBe(false);
       expect(database.closed).toBe(false);
@@ -1218,7 +1220,8 @@ describe('WASIX database recovery state', () => {
 
       const closing = database.close();
       const observedFailure = closing.catch((error: unknown) => error);
-      await vi.advanceTimersByTimeAsync(120_000);
+      while (vi.getTimerCount() === 0) await Promise.resolve();
+      vi.advanceTimersByTime(120_000);
       const failure = await observedFailure;
 
       expect(failure).toBeInstanceOf(AggregateError);
@@ -1275,13 +1278,19 @@ describe('WASIX database recovery state', () => {
       commitState: 'not-persisted',
     });
 
-    const checkpointExecution = expect(database.execute('CHECKPOINT')).rejects.toBe(storageFailure);
+    const checkpointExecution = rejects(
+      database.execute('CHECKPOINT'),
+      (error) => error === storageFailure,
+    );
     await started;
-    const queuedQuery = expect(database.query('select 42')).rejects.toMatchObject({
-      name: 'WasixStorageError',
-      code: 'publication-failed',
-      commitState: 'not-persisted',
-      message: expect.stringContaining('cannot be used after a persistence boundary failed'),
+    const queuedQuery = rejects(database.query('select 42'), (error) => {
+      expect(error).toMatchObject({
+        name: 'WasixStorageError',
+        code: 'publication-failed',
+        commitState: 'not-persisted',
+        message: expect.stringContaining('cannot be used after a persistence boundary failed'),
+      });
+      return true;
     });
     rejectPublication?.(storageFailure);
 
diff --git a/src/bindings/wasix-ts/src/__tests__/direct-client-common.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/direct-client-common.test.ts
similarity index 98%
rename from src/bindings/wasix-ts/src/__tests__/direct-client-common.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/direct-client-common.test.ts
index 9e50ac211..47642d466 100644
--- a/src/bindings/wasix-ts/src/__tests__/direct-client-common.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/direct-client-common.test.ts
@@ -1,16 +1,16 @@
-import { describe, expect, it, vi } from 'vitest';
-
+import { describe, expect, it, vi } from 'bun:test';
+import { rejects } from 'node:assert/strict';
+import {
+  closeWasixByteChannel,
+  createWasixByteChannel,
+  failWasixByteChannel,
+} from '../byte-channel.js';
 import {
   type DirectWasixDependencies,
   type DirectWasixHost,
   DirectWasixSession,
   prepareRuntimeCached,
 } from '../direct-client-common.js';
-import {
-  closeWasixByteChannel,
-  createWasixByteChannel,
-  failWasixByteChannel,
-} from '../byte-channel.js';
 import { WasixStorageError } from '../errors.js';
 import type { PreparedWasixRuntime } from '../extensions.js';
 import type {
@@ -421,7 +421,8 @@ describe('direct WASIX session lifecycle', () => {
     });
 
     const opening = DirectWasixSession.open(openOptions(), host, dependencies);
-    await vi.waitFor(() => expect(events).toEqual(['seed', 'host', 'compile']));
+    await new Promise(setImmediate);
+    expect(events).toEqual(['seed', 'host', 'compile']);
     seed.resolve(pgdataMount());
     compilation.resolve({} as WebAssembly.Module);
     const session = await opening;
@@ -840,8 +841,11 @@ describe('direct WASIX session lifecycle', () => {
         }),
         fakeDependencies(storage),
       );
-      const timedOut = expect(opening).rejects.toThrow('Oliphaunt WASIX startup exceeded 120000ms');
-      await vi.advanceTimersByTimeAsync(120_000);
+      const timedOut = rejects(opening, (error: Error) =>
+        error.message.includes('Oliphaunt WASIX startup exceeded 120000ms'),
+      );
+      while (vi.getTimerCount() === 0) await Promise.resolve();
+      vi.advanceTimersByTime(120_000);
 
       await timedOut;
       expect(events).toEqual(['storage:failed']);
@@ -1131,17 +1135,6 @@ function openOptions(): SerializedOpenOptions {
         size: 1,
         source: Uint8Array.of(1),
       },
-      standardSeedArchive: {
-        archive: 'pgdata.tar.zst',
-        sha256: '2'.repeat(64),
-        size: 1,
-        source: Uint8Array.of(2),
-      },
-      standardSeedManifest: {
-        sha256: '5'.repeat(64),
-        size: 1,
-        source: Uint8Array.of(5),
-      },
       manifest: { sha256: '3'.repeat(64), size: 1, source: Uint8Array.of(3) },
     },
     extensionCarriers: {},
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/entrypoint-types.ts b/src/sdks/ts-wasix/sdk/src/__tests__/entrypoint-types.ts
new file mode 100644
index 000000000..07e26b5e4
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/entrypoint-types.ts
@@ -0,0 +1,54 @@
+import type { Oliphaunt as browser } from '../browser.js';
+import type { Oliphaunt as native } from '../index.node.js';
+import type { Oliphaunt as direct } from '../direct.node.js';
+import type { Oliphaunt as browserWorker } from '../worker-entry.js';
+import type { Oliphaunt as nativeWorker } from '../worker-entry.node.js';
+import type { openServer } from '../server.node.js';
+import { memory } from '../storage.js';
+import { directory } from '../storage/node.js';
+import { indexedDB } from '../storage/indexed-db.js';
+import { opfs } from '../storage/opfs.js';
+
+// Compiled by the SDK typecheck; never executed against an engine.
+export function checkEntrypointTypes(
+  web: typeof browser,
+  node: typeof native,
+  sync: typeof direct,
+  webWorker: typeof browserWorker,
+  nodeWorker: typeof nativeWorker,
+  server: typeof openServer,
+): void {
+  const disk = directory('/database');
+  const idb = indexedDB('database');
+  const origin = opfs('database');
+  const bytes = new Uint8Array();
+  for (const client of [web, webWorker]) {
+    void client.open({ storage: memory() });
+    void client.open({ storage: idb });
+    void client.open({ storage: origin });
+    void client.restore(idb, bytes);
+    void client.restore(origin, bytes);
+    // @ts-expect-error A directory descriptor is native-only, including when passed through a variable.
+    void client.open({ storage: disk });
+    // @ts-expect-error Browser restore accepts the same persistent storage kinds as open.
+    void client.restore(disk, bytes);
+    // @ts-expect-error Memory cannot receive a persistent restore.
+    void client.restore(memory(), bytes);
+  }
+  for (const client of [node, sync, nodeWorker]) {
+    void client.open({ storage: memory() });
+    void client.open({ storage: disk });
+    void client.restore(disk, bytes);
+    // @ts-expect-error IndexedDB is browser-only.
+    void client.open({ storage: idb });
+    // @ts-expect-error OPFS is browser-only.
+    void client.open({ storage: origin });
+    // @ts-expect-error Native restore cannot write browser storage.
+    void client.restore(idb, bytes);
+    // @ts-expect-error Native restore cannot write browser storage.
+    void client.restore(origin, bytes);
+  }
+  void server({ storage: disk });
+  // @ts-expect-error The native server cannot use browser storage either.
+  void server({ storage: origin });
+}
diff --git a/src/bindings/wasix-ts/src/__tests__/extension-descriptor.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/extension-descriptor.test.ts
similarity index 99%
rename from src/bindings/wasix-ts/src/__tests__/extension-descriptor.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/extension-descriptor.test.ts
index aeecbedeb..7d970abbe 100644
--- a/src/bindings/wasix-ts/src/__tests__/extension-descriptor.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/extension-descriptor.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
 
 import {
   defineWasixExtension,
diff --git a/src/bindings/wasix-ts/src/__tests__/extensions.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/extensions.test.ts
similarity index 90%
rename from src/bindings/wasix-ts/src/__tests__/extensions.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/extensions.test.ts
index 51af6f87b..963c74d78 100644
--- a/src/bindings/wasix-ts/src/__tests__/extensions.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/extensions.test.ts
@@ -1,13 +1,14 @@
+import { describe, expect, it } from 'bun:test';
+import { createHash } from 'node:crypto';
 import { readFileSync } from 'node:fs';
 
-import { describe, expect, it } from 'vitest';
-
 import type { ExtractedArchive, WasixRuntimeLayout } from '../archive.js';
 import {
+  assertClusterSeedProfileContract,
   assertExactCarrierClosure,
   assertExtensionCarriersCompatible,
   assertRuntimeDescriptorMatchesManifest,
-  assertClusterSeedProfileContract,
+  loadIcuData,
   mergeExtensionStartupGUCs,
   overlayExtensionArchive,
   overlayIcuArchive,
@@ -21,6 +22,33 @@ type ProjectedExtension = ReturnType['extensions'
 type ProjectedLifecycle = ProjectedExtension['lifecycle'];
 
 describe('WASIX TypeScript extensions', () => {
+  it('binds separately supplied ICU bytes to their manifest and rejects corruption', async () => {
+    const data = Uint8Array.of(1, 2, 3);
+    const digest = createHash('sha256')
+      .update(`icudt76l.dat\0${data.length}\0`)
+      .update(data)
+      .update('\n')
+      .digest('hex');
+    const manifest = new TextEncoder().encode(
+      [
+        'schema=oliphaunt-icu-data-v1',
+        'artifactRole=icu-data',
+        'icuDataVersion=76.1',
+        'icuDataForm=files-le',
+        `icuDataTreeSha256=${digest}`,
+      ].join('\n'),
+    );
+    expect((await loadIcuData({ data, manifest })).treeSha256).toBe(digest);
+    await expect(loadIcuData({ data: Uint8Array.of(1, 2, 4), manifest })).rejects.toThrow(
+      'SHA-256',
+    );
+    const duplicate = new TextEncoder().encode(
+      `${new TextDecoder().decode(manifest)}\nicuDataVersion=76.1`,
+    );
+    await expect(loadIcuData({ data, manifest: duplicate })).rejects.toThrow(
+      'invalid ICU manifest',
+    );
+  });
   it('uses the shared cluster-seed profile fixtures', () => {
     const standard = sharedSeedFixture('standard.valid.json');
     const icu = sharedSeedFixture('icu.valid.json');
@@ -183,11 +211,11 @@ describe('WASIX TypeScript extensions', () => {
       assertRuntimeDescriptorMatchesManifest(
         {
           ...runtimeDescriptor(),
-          standardSeedArchive: { ...runtimeDescriptor().standardSeedArchive, size: 101 },
+          runtimeArchive: { ...runtimeDescriptor().runtimeArchive, sha256: 'f'.repeat(64) },
         },
         manifest(),
       ),
-    ).toThrow('standard cluster seed archive size does not match the canonical manifest');
+    ).toThrow('runtime archive SHA-256 does not match the canonical manifest');
   });
 
   it('materializes declared native load order and fails closed on shared-memory requirements', () => {
@@ -429,35 +457,6 @@ function manifest(): WasixAssetManifest {
         sha256: '3'.repeat(64),
       },
     ],
-    'cluster-seeds': {
-      standard: {
-        'artifact-role': 'cluster-seed-standard',
-        'catalog-profile': 'standard',
-        archive: 'cluster-seeds/standard.tar.zst',
-        manifest: 'cluster-seeds/standard.json',
-        sha256: '4'.repeat(64),
-        size: 100,
-        'runtime-module-sha256': '1'.repeat(64),
-        'source-fingerprint': 'postgres-source-fingerprint',
-        'postgres-version': '18',
-        'physical-format': 'wasix-pg18-v1',
-        'compatibility-key': 'wasix-pg18-datum32-v1',
-      },
-      icu: {
-        'artifact-role': 'cluster-seed-icu',
-        'catalog-profile': 'icu',
-        archive: 'cluster-seeds/icu.tar.zst',
-        manifest: 'cluster-seeds/icu.json',
-        sha256: '6'.repeat(64),
-        size: 101,
-        'runtime-module-sha256': '1'.repeat(64),
-        'source-fingerprint': 'postgres-source-fingerprint',
-        'postgres-version': '18',
-        'physical-format': 'wasix-pg18-v1',
-        'compatibility-key': 'wasix-pg18-datum32-v1',
-        'icu-data-tree-sha256': '7'.repeat(64),
-      },
-    },
     extensions: [],
   };
 }
@@ -474,17 +473,6 @@ function runtimeDescriptor(): SerializedRuntimeDescriptor {
       size: 100,
       source: '/runtime.tar.zst',
     },
-    standardSeedArchive: {
-      archive: 'cluster-seeds/standard.tar.zst',
-      sha256: '4'.repeat(64),
-      size: 100,
-      source: '/standard-seed.tar.zst',
-    },
-    standardSeedManifest: {
-      sha256: '8'.repeat(64),
-      size: 100,
-      source: '/standard-seed.json',
-    },
     manifest: {
       sha256: '5'.repeat(64),
       size: 100,
@@ -512,7 +500,7 @@ function runtimeLayout(): WasixRuntimeLayout {
 function sharedSeedFixture(name: string): unknown {
   return JSON.parse(
     readFileSync(
-      new URL(`../../../../shared/cluster-seed-contract/fixtures/${name}`, import.meta.url),
+      new URL(`../../../../../database-resources/contracts/fixtures/${name}`, import.meta.url),
       'utf8',
     ),
   );
diff --git a/src/bindings/wasix-ts/src/__tests__/forgotten-database.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/forgotten-database.test.ts
similarity index 94%
rename from src/bindings/wasix-ts/src/__tests__/forgotten-database.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/forgotten-database.test.ts
index ea98dec57..6e80b2cc2 100644
--- a/src/bindings/wasix-ts/src/__tests__/forgotten-database.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/forgotten-database.test.ts
@@ -1,9 +1,9 @@
-import { describe, expect, it, vi } from 'vitest';
+import { describe, expect, it, vi } from 'bun:test';
 
 import {
   WasixDatabaseImpl,
-  WasixForgottenDatabaseRegistry,
   type WasixDatabaseSession,
+  WasixForgottenDatabaseRegistry,
 } from '../database.js';
 
 describe('WASIX forgotten database cleanup', () => {
@@ -31,7 +31,7 @@ describe('WASIX forgotten database cleanup', () => {
     expect(work).toHaveLength(1);
 
     work.shift()?.();
-    expect(abort).toHaveBeenCalledOnce();
+    expect(abort).toHaveBeenCalledTimes(1);
     expect(close).not.toHaveBeenCalled();
     await Promise.resolve();
   });
@@ -51,7 +51,7 @@ describe('WASIX forgotten database cleanup', () => {
     harness.finalize(registration.generation);
     expect(close).not.toHaveBeenCalled();
     work.shift()?.();
-    expect(close).toHaveBeenCalledOnce();
+    expect(close).toHaveBeenCalledTimes(1);
     await Promise.resolve();
     await Promise.resolve();
   });
@@ -77,7 +77,7 @@ describe('WASIX forgotten database cleanup', () => {
     expect(work).toHaveLength(1);
     work.shift()?.();
     expect(firstClose).not.toHaveBeenCalled();
-    expect(secondClose).toHaveBeenCalledOnce();
+    expect(secondClose).toHaveBeenCalledTimes(1);
   });
 
   it('revokes forgotten cleanup when explicit close claims the public handle', async () => {
@@ -92,12 +92,12 @@ describe('WASIX forgotten database cleanup', () => {
     if (generation === undefined) throw new Error('database did not register finalizer cleanup');
 
     await database.close();
-    expect(close).toHaveBeenCalledOnce();
+    expect(close).toHaveBeenCalledTimes(1);
     expect(harness.unregistered).toEqual([generation]);
 
     harness.finalize(generation);
     expect(work).toEqual([]);
-    expect(close).toHaveBeenCalledOnce();
+    expect(close).toHaveBeenCalledTimes(1);
   });
 });
 
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/host-runtime.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/host-runtime.test.ts
new file mode 100644
index 000000000..ee2f2a768
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/host-runtime.test.ts
@@ -0,0 +1,9 @@
+import { expect, test } from 'bun:test';
+import { hostRuntime, hostRuntimeName } from '../host-runtime.js';
+
+test('identifies the actual host and gives stable diagnostic names', () => {
+  expect(hostRuntime()).toBe('bun');
+  expect(hostRuntimeName()).toBe('Bun');
+  expect(hostRuntimeName('node')).toBe('Node');
+  expect(hostRuntimeName('deno')).toBe('Deno');
+});
diff --git a/src/bindings/wasix-ts/src/__tests__/native-addon.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/native-addon.test.ts
similarity index 97%
rename from src/bindings/wasix-ts/src/__tests__/native-addon.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/native-addon.test.ts
index b367046d3..7696d37bf 100644
--- a/src/bindings/wasix-ts/src/__tests__/native-addon.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/native-addon.test.ts
@@ -1,13 +1,13 @@
+import { afterEach, describe, expect, it } from 'bun:test';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterEach, describe, expect, it } from 'vitest';
 
 import {
   detectLinuxLibc,
   loadNativeWasixAddon,
+  type NativeWasixAddon,
   nativeTarget,
   optionalEnvironmentValue,
-  type NativeWasixAddon,
   validateNativeWasixAddon,
 } from '../native-addon.js';
 
@@ -160,13 +160,12 @@ function addonFixture(): NativeWasixAddon {
     NativeWasixServer: Server,
     async restore() {},
     restoreDirect() {},
-    addonAbiVersion: () => 1,
+    addonAbiVersion: () => 2,
     nodeApiVersion: () => 8,
     runtimeVersion: () => '0.1.1',
     supportedProfiles: () => ['standard', 'icu'],
     payloadIdentity: () => `${'a'.repeat(64)}:1`,
     extensionIdentity: () => `${'a'.repeat(64)}:1`,
-    toolIdentity: () => `${'a'.repeat(64)}:1`,
   };
 }
 
@@ -178,7 +177,7 @@ function metadata() {
       runtimeVersion: '0.1.1',
       wasixNapiProduct: 'oliphaunt-wasix-napi',
       wasixNapiVersion: '0.1.1',
-      wasixAddonAbiVersion: 1,
+      wasixAddonAbiVersion: 2,
       nodeApiVersion: 8,
     },
   };
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/native-entrypoint-boundary.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/native-entrypoint-boundary.test.ts
new file mode 100644
index 000000000..57ad8fb1a
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/native-entrypoint-boundary.test.ts
@@ -0,0 +1,15 @@
+import { expect, it, vi } from 'bun:test';
+
+vi.mock('../physical-archive.js', () => {
+  throw new Error('native entrypoint loaded browser archive code');
+});
+vi.mock('../storage-provider.js', () => {
+  throw new Error('native entrypoint loaded browser storage providers');
+});
+
+it('loads native entrypoints without browser archive or storage providers', async () => {
+  for (const entry of ['../index.node.js', '../direct.node.js', '../worker-entry.node.js']) {
+    expect(typeof (await import(entry)).Oliphaunt.open).toBe('function');
+  }
+  expect(typeof (await import('../server.node.js')).openServer).toBe('function');
+});
diff --git a/src/bindings/wasix-ts/src/__tests__/native-session.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/native-session.test.ts
similarity index 85%
rename from src/bindings/wasix-ts/src/__tests__/native-session.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/native-session.test.ts
index 69b1374da..8beb760bc 100644
--- a/src/bindings/wasix-ts/src/__tests__/native-session.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/native-session.test.ts
@@ -1,16 +1,21 @@
-import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { beforeEach, describe, expect, it, vi } from 'bun:test';
+import { createHash } from 'node:crypto';
+import { rejects } from 'node:assert/strict';
+
+import { readFile } from 'node:fs/promises';
+import { readPackageAsset } from '../asset-source.js';
 
 import { WasixDatabaseImpl } from '../database.js';
 import { WasixStorageError } from '../errors.js';
 import type {
-  NativeWasixAddon,
   NativeWasixActorDatabaseHandle,
+  NativeWasixAddon,
   NativeWasixDatabaseHandle,
 } from '../native-addon.js';
 import type { SerializedExtensionCarrier } from '../rpc.js';
 import { workerOpenOptions } from './worker-helpers.js';
 
-const nativeMocks = vi.hoisted(() => ({
+const nativeMocks = {
   extensionIdentity: vi.fn(),
   actorOpen: vi.fn(),
   loadAddon: vi.fn(),
@@ -18,8 +23,7 @@ const nativeMocks = vi.hoisted(() => ({
   payloadIdentity: vi.fn(),
   pgDump: vi.fn(),
   psql: vi.fn(),
-  toolIdentity: vi.fn(),
-}));
+};
 
 vi.mock('../native-addon.js', () => ({
   loadNativeWasixAddon: nativeMocks.loadAddon,
@@ -32,12 +36,25 @@ import {
   requireCompatibleNativeWasixAddon,
 } from '../native-session.js';
 
+it('loads package-relative assets in the native host realm', async () => {
+  const source = new URL('./native-session.test.ts', import.meta.url);
+  expect(await readPackageAsset(source.href, 'tool AOT')).toEqual(await readFile(source));
+});
+
+const toolBytes = Uint8Array.of(0, 97, 115, 109);
+const toolDescriptor = {
+  name: 'pg_dump' as const,
+  sha256: createHash('sha256').update(toolBytes).digest('hex'),
+  size: toolBytes.length,
+  source: toolBytes,
+  aot: { source: Uint8Array.of(1), manifest: new TextEncoder().encode('{}') },
+};
+
 const digest = 'a'.repeat(64);
 
 beforeEach(() => {
   for (const mock of Object.values(nativeMocks)) mock.mockReset();
   nativeMocks.extensionIdentity.mockReturnValue(`${digest}:7`);
-  nativeMocks.toolIdentity.mockReturnValue(`${digest}:7`);
   nativeMocks.pgDump.mockReturnValue({
     status: 0,
     stdout: new TextEncoder().encode('ok'),
@@ -93,19 +110,16 @@ describe('WASIX native embedded payload compatibility', () => {
     );
   });
 
-  it('rejects a frontend tool descriptor whose bytes differ from the embedded module', async () => {
+  it('rejects a frontend tool descriptor whose digest differs from its supplied bytes', async () => {
     const session = await NativeWasixSession.open(workerOpenOptions());
-    nativeMocks.toolIdentity.mockReturnValue(`${'b'.repeat(64)}:7`);
 
     await expect(
       session.runTool({
         runtimeVersion: '0.1.1',
-        tool: { name: 'pg_dump', sha256: digest, size: 7, source: 'embedded' },
-        args: pgDumpArguments(),
+        tool: { ...toolDescriptor, sha256: 'b'.repeat(64) },
+        args: ['--schema-only'],
       }),
-    ).rejects.toThrow(
-      'WASIX pg_dump descriptor does not match the tool embedded in the native addon',
-    );
+    ).rejects.toThrow('SHA-256');
     expect(nativeMocks.pgDump).not.toHaveBeenCalled();
   });
 
@@ -122,7 +136,7 @@ describe('WASIX native embedded payload compatibility', () => {
     nativeMocks.open.mockImplementation(() => {
       throw Object.assign(new Error('this deliberately says corrupt and available'), {
         oliphauntWasixError: 'storage',
-        oliphauntWasixAddonAbi: 1,
+        oliphauntWasixAddonAbi: 2,
         code: 'busy',
         commitState: 'unchanged',
         phase: 'ownership',
@@ -165,8 +179,8 @@ describe('WASIX native embedded payload compatibility', () => {
 
     const result = await session.runTool({
       runtimeVersion: '0.1.1',
-      tool: { name: 'pg_dump', sha256: digest, size: 7, source: 'embedded' },
-      args: pgDumpArguments(),
+      tool: toolDescriptor,
+      args: ['--schema-only'],
     });
 
     expect(result).toEqual({
@@ -176,6 +190,44 @@ describe('WASIX native embedded payload compatibility', () => {
     });
   });
 
+  it('passes user arguments and explicit psql input directly to both native owners', async () => {
+    for (const owner of [NativeWasixSession, NativeWasixActorSession]) {
+      const session = await owner.open(workerOpenOptions());
+      await session.runTool({
+        runtimeVersion: '0.1.1',
+        tool: toolDescriptor,
+        args: ['--schema-only'],
+      });
+      expect(nativeMocks.pgDump.mock.calls.at(-1)?.[0]).toEqual(['--schema-only']);
+      const tool = { ...toolDescriptor, name: 'psql' as const };
+      await session.runTool({
+        runtimeVersion: '0.1.1',
+        tool,
+        args: ['--tuples-only'],
+        command: 'select 1',
+      });
+      expect(nativeMocks.psql.mock.calls.at(-1)).toEqual([
+        ['--tuples-only'],
+        expect.anything(),
+        'select 1',
+        undefined,
+      ]);
+      await session.runTool({
+        runtimeVersion: '0.1.1',
+        tool,
+        args: [],
+        stdin: new TextEncoder().encode('select 2'),
+      });
+      expect(nativeMocks.psql.mock.calls.at(-1)).toEqual([
+        [],
+        expect.anything(),
+        undefined,
+        'select 2',
+      ]);
+      await session.close();
+    }
+  });
+
   it('passes an immutable profile to direct and actor opens', async () => {
     const options = workerOpenOptions();
 
@@ -217,8 +269,8 @@ describe('WASIX native embedded payload compatibility', () => {
     expectTransferable(await actor.backup(), [9, 10]);
     const toolOptions = {
       runtimeVersion: '0.1.1',
-      tool: { name: 'pg_dump' as const, sha256: digest, size: 7, source: 'embedded' },
-      args: pgDumpArguments(),
+      tool: toolDescriptor,
+      args: ['--schema-only'],
     };
     const directTool = await direct.runTool(toolOptions);
     const actorTool = await actor.runTool(toolOptions);
@@ -242,8 +294,10 @@ describe('WASIX native embedded payload compatibility', () => {
     const first = database.execProtocolRaw(Uint8Array.of(1));
     const queued = database.execProtocolRaw(Uint8Array.of(2));
 
-    await expect(first).rejects.toBe(failure);
-    await expect(queued).rejects.toBe(failure);
+    await Promise.all([
+      rejects(first, (error) => error === failure),
+      rejects(queued, (error) => error === failure),
+    ]);
     expect(session.terminalState.failure).toBe(failure);
     expect(session.terminalState.failure).toBe(failure);
     expect(database.closed).toBe(true);
@@ -264,8 +318,10 @@ describe('WASIX native embedded payload compatibility', () => {
     const first = database.execProtocolRaw(Uint8Array.of(1));
     const queued = database.execProtocolRaw(Uint8Array.of(2));
 
-    await expect(first).rejects.toBe(failure);
-    await expect(queued).rejects.toBe(failure);
+    await Promise.all([
+      rejects(first, (error) => error === failure),
+      rejects(queued, (error) => error === failure),
+    ]);
     expect(session.terminalState.failure).toBe(failure);
     expect(session.terminalState.failure).toBe(failure);
     expect(database.closed).toBe(true);
@@ -345,13 +401,12 @@ function addon(): NativeWasixAddon {
     }) as unknown as NativeWasixAddon['NativeWasixServer'],
     async restore() {},
     restoreDirect() {},
-    addonAbiVersion: () => 1,
+    addonAbiVersion: () => 2,
     nodeApiVersion: () => 8,
     runtimeVersion: () => '0.1.1',
     supportedProfiles: () => ['standard', 'icu'],
     payloadIdentity: nativeMocks.payloadIdentity,
     extensionIdentity: nativeMocks.extensionIdentity,
-    toolIdentity: nativeMocks.toolIdentity,
   };
 }
 
@@ -475,14 +530,3 @@ function extensionCarrier(sqlName: string): SerializedExtensionCarrier {
     },
   };
 }
-
-function pgDumpArguments(): string[] {
-  return [
-    '--encoding=UTF8',
-    '--no-password',
-    '--username=postgres',
-    '--host=127.0.0.1',
-    '--port=65432',
-    '--dbname=postgres',
-  ];
-}
diff --git a/src/bindings/wasix-ts/src/__tests__/node-actor.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/node-actor.test.ts
similarity index 90%
rename from src/bindings/wasix-ts/src/__tests__/node-actor.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/node-actor.test.ts
index dd4758d82..741b3bb04 100644
--- a/src/bindings/wasix-ts/src/__tests__/node-actor.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/node-actor.test.ts
@@ -1,9 +1,9 @@
-import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { beforeEach, describe, expect, it, vi } from 'bun:test';
 
 import type { NativeWasixActorSession } from '../native-session.js';
 import { workerOpenOptions } from './worker-helpers.js';
 
-const nativeMocks = vi.hoisted(() => ({ open: vi.fn() }));
+const nativeMocks = { open: vi.fn() };
 
 vi.mock('../native-session.js', () => ({
   NativeWasixActorSession: { open: nativeMocks.open },
@@ -21,7 +21,7 @@ describe('WASIX Node actor routing', () => {
     nativeMocks.open.mockResolvedValueOnce(session);
 
     await expect(openNodeActorSession(options)).resolves.toBe(session);
-    expect(nativeMocks.open).toHaveBeenCalledOnce();
+    expect(nativeMocks.open).toHaveBeenCalledTimes(1);
     expect(nativeMocks.open).toHaveBeenCalledWith(options);
   });
 
diff --git a/src/bindings/wasix-ts/src/__tests__/node-direct.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/node-direct.test.ts
similarity index 82%
rename from src/bindings/wasix-ts/src/__tests__/node-direct.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/node-direct.test.ts
index d0fca68ed..6966bdc54 100644
--- a/src/bindings/wasix-ts/src/__tests__/node-direct.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/node-direct.test.ts
@@ -1,11 +1,11 @@
-import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { beforeEach, describe, expect, it, vi } from 'bun:test';
 
 import type { NativeWasixSession } from '../native-session.js';
 import { workerOpenOptions } from './worker-helpers.js';
 
-const nativeMocks = vi.hoisted(() => ({
+const nativeMocks = {
   open: vi.fn(),
-}));
+};
 
 vi.mock('../native-session.js', () => ({
   NativeWasixSession: { open: nativeMocks.open },
@@ -22,7 +22,7 @@ describe('WASIX Node direct native routing', () => {
     nativeMocks.open.mockResolvedValueOnce(session);
 
     await expect(openNodeDirectSession(options)).resolves.toBe(session);
-    expect(nativeMocks.open).toHaveBeenCalledOnce();
+    expect(nativeMocks.open).toHaveBeenCalledTimes(1);
     expect(nativeMocks.open).toHaveBeenCalledWith(options);
   });
 });
diff --git a/src/bindings/wasix-ts/src/__tests__/node-worker-options.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/node-worker-options.test.ts
similarity index 95%
rename from src/bindings/wasix-ts/src/__tests__/node-worker-options.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/node-worker-options.test.ts
index 6bf48346a..add804bac 100644
--- a/src/bindings/wasix-ts/src/__tests__/node-worker-options.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/node-worker-options.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
 
 import { nodeWorkerExecArgv } from '../node-worker-options.js';
 
diff --git a/src/bindings/wasix-ts/src/__tests__/node-worker-port.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/node-worker-port.test.ts
similarity index 98%
rename from src/bindings/wasix-ts/src/__tests__/node-worker-port.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/node-worker-port.test.ts
index a508527f4..8a62fac9e 100644
--- a/src/bindings/wasix-ts/src/__tests__/node-worker-port.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/node-worker-port.test.ts
@@ -1,8 +1,7 @@
+import { describe, expect, it } from 'bun:test';
 import { EventEmitter } from 'node:events';
 import type { Worker } from 'node:worker_threads';
 
-import { describe, expect, it } from 'vitest';
-
 import { nodeWorkerPort } from '../node-worker-port.js';
 import type { WorkerRequest, WorkerResponse } from '../rpc.js';
 
diff --git a/src/bindings/wasix-ts/src/__tests__/opfs-pool.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/opfs-pool.test.ts
similarity index 98%
rename from src/bindings/wasix-ts/src/__tests__/opfs-pool.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/opfs-pool.test.ts
index 48c855c91..8ae2eb9b0 100644
--- a/src/bindings/wasix-ts/src/__tests__/opfs-pool.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/opfs-pool.test.ts
@@ -1,5 +1,4 @@
-import { afterEach, describe, expect, it, vi } from 'vitest';
-
+import { afterEach, describe, expect, it, vi } from 'bun:test';
 import type { WasixDirectoryMount } from '../archive.js';
 import type { Directory } from '../host/index.mjs';
 import {
@@ -14,6 +13,7 @@ import {
   type WasixClusterSeedLoader,
   type WasixPhysicalIdentity,
 } from '../storage-provider.js';
+import { restoreGlobals, stubGlobal } from './test-globals.js';
 
 const OP = {
   metadata: 1,
@@ -34,7 +34,7 @@ const encoder = new TextEncoder();
 const decoder = new TextDecoder();
 
 describe('WASIX pooled OPFS storage', () => {
-  afterEach(() => vi.unstubAllGlobals());
+  afterEach(() => restoreGlobals());
 
   it('persists the opaque logical namespace across direct reopen', async () => {
     const root = installOpfs();
@@ -329,7 +329,7 @@ describe('WASIX pooled OPFS storage', () => {
 
   it('publishes an unchanged portable first-open generation as ready', async () => {
     const root = installOpfs();
-    vi.stubGlobal('document', {});
+    stubGlobal('document', {});
     const lease = await acquireOpfsStorage('portable-initialization', clusterSeed(), compatible());
     expect(lease.state).toBe('new');
     const clearChanges = vi.fn();
@@ -348,7 +348,7 @@ describe('WASIX pooled OPFS storage', () => {
     const database = await databaseDirectory(root, 'portable-initialization');
     const state = JSON.parse(await database.file('state.json').text()) as { phase: string };
     expect(state.phase).toBe('ready');
-    expect(clearChanges).toHaveBeenCalledOnce();
+    expect(clearChanges).toHaveBeenCalledTimes(1);
   });
 
   it('releases the direct host filesystem exactly once when its lease closes', async () => {
@@ -364,8 +364,8 @@ describe('WASIX pooled OPFS storage', () => {
     await lease.close(directory, 'failed');
     await lease.close(directory, 'failed');
 
-    expect(createSync).toHaveBeenCalledOnce();
-    expect(free).toHaveBeenCalledOnce();
+    expect(createSync).toHaveBeenCalledTimes(1);
+    expect(free).toHaveBeenCalledTimes(1);
   });
 
   it('releases a direct host filesystem when bridge validation fails', async () => {
@@ -391,7 +391,7 @@ describe('WASIX pooled OPFS storage', () => {
     ).rejects.toThrow('injected bridge read failure');
     await lease.close(undefined, 'failed');
 
-    expect(free).toHaveBeenCalledOnce();
+    expect(free).toHaveBeenCalledTimes(1);
   });
 
   it('reports persisted when access-handle cleanup fails after a clean close sync', async () => {
@@ -410,7 +410,7 @@ describe('WASIX pooled OPFS storage', () => {
       code: 'unavailable',
       commitState: 'persisted',
     });
-    expect(free).toHaveBeenCalledOnce();
+    expect(free).toHaveBeenCalledTimes(1);
   });
 
   it('does not publish setup completion when its final state commit fails', async () => {
@@ -770,7 +770,7 @@ type FakeIo = {
 
 function installOpfs(io: FakeIo = {}): FakeDirectory {
   const root = new FakeDirectory('', io);
-  vi.stubGlobal('navigator', {
+  stubGlobal('navigator', {
     locks: {
       request: async (
         _name: string,
diff --git a/src/bindings/wasix-ts/src/__tests__/pgwire-connection.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/pgwire-connection.test.ts
similarity index 99%
rename from src/bindings/wasix-ts/src/__tests__/pgwire-connection.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/pgwire-connection.test.ts
index fb02f93b4..8e24cacb2 100644
--- a/src/bindings/wasix-ts/src/__tests__/pgwire-connection.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/pgwire-connection.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
 import {
   closeWasixByteChannel,
   createWasixByteChannel,
@@ -9,8 +9,8 @@ import {
   classifyFrontendFrame,
   FrontendFrameReader,
   parseStartupIdentity,
-  serveWasixProtocolConnection,
   SynchronousPgDumpConnection,
+  serveWasixProtocolConnection,
 } from '../pgwire-connection.js';
 
 describe('WASIX PostgreSQL connection framing', () => {
diff --git a/src/bindings/wasix-ts/src/__tests__/pgwire.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/pgwire.test.ts
similarity index 98%
rename from src/bindings/wasix-ts/src/__tests__/pgwire.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/pgwire.test.ts
index c6a9d1b85..ffe672698 100644
--- a/src/bindings/wasix-ts/src/__tests__/pgwire.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/pgwire.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
 
 import { assertSuccessfulStartupResponse, startupPacket } from '../pgwire.js';
 import { PostgresError } from '../query.js';
diff --git a/src/bindings/wasix-ts/src/__tests__/physical-archive.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/physical-archive.test.ts
similarity index 99%
rename from src/bindings/wasix-ts/src/__tests__/physical-archive.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/physical-archive.test.ts
index 72c783de6..d050e398d 100644
--- a/src/bindings/wasix-ts/src/__tests__/physical-archive.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/physical-archive.test.ts
@@ -1,8 +1,7 @@
+import { describe, expect, it } from 'bun:test';
 import { readFileSync } from 'node:fs';
 import { fileURLToPath } from 'node:url';
 
-import { describe, expect, it } from 'vitest';
-
 import { extractTar } from '../archive.js';
 import {
   BackupModeExitUnconfirmedError,
@@ -217,7 +216,7 @@ describe('WASIX physical archives', () => {
     const expected = readFileSync(
       fileURLToPath(
         new URL(
-          '../../../../shared/fixtures/storage/physical-archive-wasix-v1.properties',
+          '../../../../../test-fixtures/storage/physical-archive-wasix-v1.properties',
           import.meta.url,
         ),
       ),
@@ -434,7 +433,7 @@ describe('WASIX physical archives', () => {
     const text = readFileSync(
       fileURLToPath(
         new URL(
-          '../../../../shared/fixtures/storage/physical-backup-wal-range-v1.properties',
+          '../../../../../test-fixtures/storage/physical-backup-wal-range-v1.properties',
           import.meta.url,
         ),
       ),
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/public-api.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/public-api.test.ts
new file mode 100644
index 000000000..b3893f653
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/public-api.test.ts
@@ -0,0 +1,129 @@
+import { describe, expect, it } from 'bun:test';
+
+import {
+  array,
+  type BinaryQueryParameter,
+  binary,
+  type DescribeResult,
+  type EncodedQueryParameter,
+  type ExecResult,
+  json,
+  type NullQueryParameter,
+  Oliphaunt,
+  type OliphauntDatabase,
+  type OliphauntTransaction,
+  type OpenConfig,
+  PostgresError,
+  postgresOids,
+  type QueryArrayRow,
+  type QueryObjectRow,
+  type QueryParam,
+  type QueryResult,
+  type QueryValue,
+  type RawQueryResult,
+  type TextQueryParameter,
+  text,
+  typedNull,
+} from '../index.js';
+import WorkerOliphaunt, { Oliphaunt as NamedWorkerOliphaunt } from '../worker-entry.js';
+
+describe('WASIX public ORM surface', () => {
+  it('publishes codecs and PostgreSQL metadata from the root entrypoint', () => {
+    expect(typeof Oliphaunt.open).toBe('function');
+    expect(WorkerOliphaunt).toBe(NamedWorkerOliphaunt);
+    expect(typeof WorkerOliphaunt.open).toBe('function');
+    expect(typeof PostgresError).toBe('function');
+    expect(postgresOids.jsonb).toBe(3802);
+    expect(text('value', postgresOids.text).format).toBe('text');
+    expect(binary(Uint8Array.of(1), postgresOids.bytea).format).toBe('binary');
+    expect(json({ ok: true }).typeOid).toBe(postgresOids.jsonb);
+    expect(array([1, 2], postgresOids.int4Array).typeOid).toBe(postgresOids.int4Array);
+    expect(typedNull(postgresOids.uuid).format).toBe('null');
+  });
+});
+
+const canonicalPostgresError = new PostgresError([
+  { code: 0x43, value: '22000' },
+  { code: 0x4d, value: 'invalid value' },
+]);
+const canonicalSqlstate: string | undefined = canonicalPostgresError.sqlstate;
+const canonicalMessage: string = canonicalPostgresError.message;
+void [canonicalSqlstate, canonicalMessage];
+
+function assertPublicDatabaseTypes(
+  database: OliphauntDatabase,
+  transaction: OliphauntTransaction,
+): void {
+  const decoded: Promise> = database.query<{
+    value: number;
+  }>('SELECT $1::int4 AS value', [1], { rowMode: 'object' });
+  const raw: Promise = database.queryRaw('SELECT $1::bytea', [
+    binary(Uint8Array.of(1), postgresOids.bytea),
+  ]);
+  const execResults: Promise> = database.exec(
+    'SELECT 1',
+    { rowMode: 'array' },
+  );
+  const inferredArrays: Promise> = transaction.query('SELECT 1', [], {
+    rowMode: 'array',
+  });
+  const inferredDecoder: Promise>> = database.query(
+    'SELECT now()',
+    [],
+    { decoders: { [postgresOids.timestamptz]: (value) => new Date(value) } },
+  );
+  const description: Promise = database.describe('SELECT $1', [postgresOids.int4]);
+  const streamed: Promise = database.execProtocolRawStream(Uint8Array.of(1), () => undefined);
+  // @ts-expect-error Stream callbacks are synchronous backpressure acknowledgements.
+  const asyncStreamed = database.execProtocolRawStream(Uint8Array.of(1), async () => {});
+  const widenedAsyncCallback: (chunk: Uint8Array) => unknown = async () => {};
+  const widenedAsyncStreamed = database.execProtocolRawStream(
+    Uint8Array.of(1),
+    // @ts-expect-error Widening an async callback must not bypass the synchronous contract.
+    widenedAsyncCallback,
+  );
+  // @ts-expect-error Raw protocol is root-only; it bypasses callback transaction ownership.
+  const transactionBuffered = transaction.execProtocolRaw(Uint8Array.of(1));
+  // @ts-expect-error Raw protocol is root-only; it bypasses callback transaction ownership.
+  const transactionStreamed = transaction.execProtocolRawStream(Uint8Array.of(1), () => undefined);
+  const rollback: Promise = transaction.rollback();
+  const closed: boolean = database.closed || transaction.closed;
+  void [
+    decoded,
+    raw,
+    execResults,
+    inferredArrays,
+    inferredDecoder,
+    description,
+    streamed,
+    asyncStreamed,
+    widenedAsyncStreamed,
+    transactionBuffered,
+    transactionStreamed,
+    rollback,
+    closed,
+  ];
+}
+
+void assertPublicDatabaseTypes;
+
+const publicHelperTypes: [TextQueryParameter, BinaryQueryParameter, NullQueryParameter] = [
+  text('value'),
+  binary(Uint8Array.of(1)),
+  typedNull(postgresOids.text),
+];
+void publicHelperTypes;
+
+const plainJsonParameter: QueryParam = {
+  format: 'text',
+  value: 'plain JSON data',
+};
+// @ts-expect-error Encoded parameters must be created by an exported helper.
+const forgedEncodedParameter: EncodedQueryParameter = {
+  format: 'text',
+  value: 'forged',
+};
+void [plainJsonParameter, forgedEncodedParameter];
+
+const openConfig: OpenConfig = { username: 'application' };
+void openConfig;
diff --git a/src/bindings/wasix-ts/src/__tests__/restore-cleanup.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/restore-cleanup.test.ts
similarity index 96%
rename from src/bindings/wasix-ts/src/__tests__/restore-cleanup.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/restore-cleanup.test.ts
index 0efcde4da..dd933ca89 100644
--- a/src/bindings/wasix-ts/src/__tests__/restore-cleanup.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/restore-cleanup.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
 
 import { WasixStorageError } from '../errors.js';
 import { releaseRestoreLock } from '../storage/restore-cleanup.js';
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/runtime-carrier.ts b/src/sdks/ts-wasix/sdk/src/__tests__/runtime-carrier.ts
new file mode 100644
index 000000000..80035d72e
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/runtime-carrier.ts
@@ -0,0 +1,23 @@
+import type { WasixRuntimeDescriptor } from '../types.js';
+
+export const POSTGRES_MAJOR = 18 as const;
+export const PHYSICAL_FORMAT = 'wasix-pg18-v1' as const;
+
+const runtime: WasixRuntimeDescriptor = {
+  schema: 'oliphaunt-wasix-runtime-v2',
+  runtime: 'wasix',
+  product: 'liboliphaunt-wasix',
+  version: '0.1.1',
+  runtimeArchive: {
+    archive: 'oliphaunt.wasix.tar.zst',
+    sha256: '1'.repeat(64),
+    size: 1,
+    source: Uint8Array.of(1),
+  },
+  manifest: {
+    sha256: '3'.repeat(64),
+    size: 1,
+    source: Uint8Array.of(3),
+  },
+};
+export default runtime;
diff --git a/src/bindings/wasix-ts/src/__tests__/runtime-descriptor.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/runtime-descriptor.test.ts
similarity index 82%
rename from src/bindings/wasix-ts/src/__tests__/runtime-descriptor.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/runtime-descriptor.test.ts
index d38eab1fc..985051eb1 100644
--- a/src/bindings/wasix-ts/src/__tests__/runtime-descriptor.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/runtime-descriptor.test.ts
@@ -1,9 +1,17 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
+import { Buffer } from 'node:buffer';
 
+import { serializeAssetSource } from '../descriptor-validation.js';
 import { serializeWasixRuntimeDescriptor } from '../runtime-descriptor.js';
 import type { WasixRuntimeDescriptor } from '../types.js';
 
 describe('WASIX runtime descriptors', () => {
+  it('owns Buffer snapshots including views with offsets', () => {
+    const bytes = Buffer.from([0, 1, 2, 3]);
+    const snapshot = serializeAssetSource(bytes.subarray(1, 3));
+    bytes.fill(9);
+    expect(snapshot).toEqual(Uint8Array.of(1, 2));
+  });
   it('serializes one exact runtime identity and preserves package-relative URLs', () => {
     const value = descriptor();
     const serialized = serializeWasixRuntimeDescriptor(value);
@@ -50,18 +58,6 @@ describe('WASIX runtime descriptors', () => {
     ).toThrow('byte length must match declared asset size 2');
   });
 
-  it('requires runtime and standard cluster seed archives to have distinct canonical paths', () => {
-    expect(() =>
-      serializeWasixRuntimeDescriptor({
-        ...descriptor(),
-        standardSeedArchive: {
-          ...descriptor().standardSeedArchive,
-          archive: descriptor().runtimeArchive.archive,
-        },
-      }),
-    ).toThrow('runtime and standard cluster seed archives must have distinct paths');
-  });
-
   it('rejects malformed scalar fields before loading package-owned assets', () => {
     expect(() => serializeWasixRuntimeDescriptor(null)).toThrow('must be an object');
     expect(() => serializeWasixRuntimeDescriptor({ ...descriptor(), version: 'latest' })).toThrow(
@@ -117,17 +113,6 @@ function descriptor(): WasixRuntimeDescriptor {
       size: 100,
       source: new URL('https://example.test/runtime.tar.zst'),
     },
-    standardSeedArchive: {
-      archive: 'cluster-seeds/standard.tar.zst',
-      sha256: '2'.repeat(64),
-      size: 200,
-      source: new URL('https://example.test/standard-seed.tar.zst'),
-    },
-    standardSeedManifest: {
-      sha256: '4'.repeat(64),
-      size: 250,
-      source: new URL('https://example.test/standard-seed.json'),
-    },
     manifest: {
       sha256: '3'.repeat(64),
       size: 300,
diff --git a/src/bindings/wasix-ts/src/__tests__/server.node.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/server.node.test.ts
similarity index 93%
rename from src/bindings/wasix-ts/src/__tests__/server.node.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/server.node.test.ts
index cf5b2f83e..964f2b622 100644
--- a/src/bindings/wasix-ts/src/__tests__/server.node.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/server.node.test.ts
@@ -1,7 +1,7 @@
+import { beforeEach, describe, expect, it, vi } from 'bun:test';
 import { resolve } from 'node:path';
-import { beforeEach, describe, expect, it, vi } from 'vitest';
 
-const nativeMocks = vi.hoisted(() => ({
+const nativeMocks = {
   close: vi.fn(),
   mapError: vi.fn(),
   nativeOpenOptions: vi.fn(),
@@ -9,9 +9,9 @@ const nativeMocks = vi.hoisted(() => ({
   requireAddon: vi.fn(),
   requireNodeStorage: vi.fn(),
   serialize: vi.fn(),
-}));
+};
 
-vi.mock('../client-common.js', () => ({
+vi.mock('../open-config.js', () => ({
   serializeOpenConfig: nativeMocks.serialize,
 }));
 vi.mock('../native-session.js', () => ({
@@ -79,7 +79,7 @@ describe('WASIX native local server surface', () => {
     expect(second).toBe(first);
     await expect(first).resolves.toBeUndefined();
     expect(server.closed).toBe(true);
-    expect(nativeMocks.close).toHaveBeenCalledOnce();
+    expect(nativeMocks.close).toHaveBeenCalledTimes(1);
   });
 
   it('passes an absolute Unix socket directory and PostgreSQL default port to Rust', async () => {
@@ -120,7 +120,7 @@ describe('WASIX native local server surface', () => {
     });
 
     await server.close();
-    expect(nativeMocks.close).toHaveBeenCalledOnce();
+    expect(nativeMocks.close).toHaveBeenCalledTimes(1);
   });
 
   it('maps a structured native server-open failure at the ABI boundary', async () => {
@@ -150,6 +150,6 @@ describe('WASIX native local server surface', () => {
     await first;
 
     expect(server.closed).toBe(true);
-    expect(nativeMocks.close).toHaveBeenCalledOnce();
+    expect(nativeMocks.close).toHaveBeenCalledTimes(1);
   });
 });
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/setup.ts b/src/sdks/ts-wasix/sdk/src/__tests__/setup.ts
new file mode 100644
index 000000000..c998127ec
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/setup.ts
@@ -0,0 +1,4 @@
+import { mock } from 'bun:test';
+import * as runtime from './runtime-carrier.js';
+
+mock.module('@oliphaunt/liboliphaunt-wasix', () => runtime);
diff --git a/src/bindings/wasix-ts/src/__tests__/storage-provider.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/storage-provider.test.ts
similarity index 98%
rename from src/bindings/wasix-ts/src/__tests__/storage-provider.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/storage-provider.test.ts
index 230b71e15..5db471efc 100644
--- a/src/bindings/wasix-ts/src/__tests__/storage-provider.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/storage-provider.test.ts
@@ -1,28 +1,28 @@
-import { afterEach, describe, expect, it, vi } from 'vitest';
-
+import { afterEach, describe, expect, it } from 'bun:test';
 import { WasixStorageError } from '../errors.js';
 import {
   acquireIndexedDbStorage,
   acquireIndexedDbStorageWithBackend,
   type IndexedDbStorageBackend,
   indexedDbDatabaseName,
+  restoreIndexedDbStorage,
   type StoredDatabase,
   type StoredDatabaseStore,
   validateStoredDatabase,
-  restoreIndexedDbStorage,
 } from '../storage/indexed-db-provider.js';
 import {
   acquireWasixStorage,
+  assertWasixPhysicalIdentity,
   canonicalJson,
   restoreWasixStorage,
-  assertWasixPhysicalIdentity,
-  WASIX_PHYSICAL_IDENTITY,
   type StorageDirectory,
+  WASIX_PHYSICAL_IDENTITY,
   type WasixPhysicalIdentity,
 } from '../storage-provider.js';
 import { snapshotStorageDelta, snapshotStorageDirectory } from '../storage-snapshot.js';
+import { restoreGlobals, stubGlobal } from './test-globals.js';
 
-afterEach(() => vi.unstubAllGlobals());
+afterEach(() => restoreGlobals());
 
 describe('WASIX incremental PGDATA storage', () => {
   it('reports a missing server directory integration without mislabeling the host', async () => {
@@ -245,8 +245,8 @@ describe('WASIX incremental PGDATA storage', () => {
   });
 
   it('preserves an IndexedDB restore failure when ownership release also fails', async () => {
-    vi.stubGlobal('indexedDB', undefined);
-    vi.stubGlobal('navigator', {
+    stubGlobal('indexedDB', undefined);
+    stubGlobal('navigator', {
       locks: {
         async request(
           _name: string,
@@ -432,8 +432,8 @@ describe('WASIX incremental PGDATA storage', () => {
 
   it('round-trips the browser IndexedDB adapter and rejects replacement restore', async () => {
     const factory = new FakeIndexedDbFactory();
-    vi.stubGlobal('indexedDB', factory.asFactory());
-    vi.stubGlobal('navigator', { locks: webLocks() });
+    stubGlobal('indexedDB', factory.asFactory());
+    stubGlobal('navigator', { locks: webLocks() });
 
     const snapshot = completeSnapshot();
     await restoreIndexedDbStorage('todos', snapshot, compatible());
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/storage.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/storage.test.ts
new file mode 100644
index 000000000..522368aac
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/storage.test.ts
@@ -0,0 +1,181 @@
+import { describe, expect, it } from 'bun:test';
+import { fileURLToPath } from 'node:url';
+
+import { WasixStorageError } from '../errors.js';
+import type { PersistentWasixStorage } from '../public.js';
+import { PostgresError } from '../query.js';
+import { deserializeWorkerError, serializeWorkerError } from '../rpc.js';
+import { indexedDB } from '../storage/indexed-db.js';
+import { directory } from '../storage/node.js';
+import { opfs } from '../storage/opfs.js';
+import { memory, serializeWasixStorage, type WasixStorage } from '../storage.js';
+
+const persistentStorageProof: PersistentWasixStorage[] = [
+  indexedDB('type-proof'),
+  opfs('type-proof'),
+  directory('/type-proof'),
+];
+// @ts-expect-error Memory storage cannot be a physical-restore destination.
+const memoryIsNotPersistent: PersistentWasixStorage = memory();
+void persistentStorageProof;
+void memoryIsNotPersistent;
+
+type MainPackage = typeof import('../index.js');
+const mainPackageOmitsIndexedDb: 'indexedDB' extends keyof MainPackage ? false : true = true;
+
+describe('WASIX storage descriptors', () => {
+  it('defaults to memory and keeps storage values opaque', () => {
+    expect(serializeWasixStorage(undefined)).toEqual({
+      schema: 'oliphaunt-wasix-storage-v1',
+      kind: 'memory',
+    });
+
+    const descriptor = memory();
+    expect(Object.isFrozen(descriptor)).toBe(true);
+    expect(Object.keys(descriptor)).toEqual([]);
+    expect(serializeWasixStorage(descriptor)).toEqual({
+      schema: 'oliphaunt-wasix-storage-v1',
+      kind: 'memory',
+    });
+  });
+
+  it('requires selective IndexedDB construction and validates its database name', () => {
+    expect(mainPackageOmitsIndexedDb).toBe(true);
+    const descriptor = indexedDB('todos');
+    expect(Object.keys(descriptor)).toEqual([]);
+    expect(serializeWasixStorage(descriptor)).toEqual({
+      schema: 'oliphaunt-wasix-storage-v1',
+      kind: 'indexed-db',
+      name: 'todos',
+    });
+
+    expect(() => indexedDB('')).toThrow('must be 1-200 characters');
+    expect(() => indexedDB('x'.repeat(201))).toThrow('must be 1-200 characters');
+    expect(() => indexedDB('bad\0name')).toThrow('without NUL bytes');
+  });
+
+  it('constructs an OPFS descriptor with a path-safe database name', () => {
+    const descriptor = opfs('todos-v2');
+    expect(Object.keys(descriptor)).toEqual([]);
+    expect(serializeWasixStorage(descriptor)).toEqual({
+      schema: 'oliphaunt-wasix-storage-v1',
+      kind: 'opfs',
+      name: 'todos-v2',
+    });
+
+    expect(() => opfs('')).toThrow('must be 1-100 ASCII');
+    expect(() => opfs('../escape')).toThrow('must be 1-100 ASCII');
+    expect(() => opfs('space name')).toThrow('must be 1-100 ASCII');
+  });
+
+  it('requires selective Node directory construction and validates its path', () => {
+    const descriptor = directory('./data/with spaces');
+    expect(Object.keys(descriptor)).toEqual([]);
+    expect(serializeWasixStorage(descriptor)).toEqual({
+      schema: 'oliphaunt-wasix-storage-v1',
+      kind: 'directory',
+      path: './data/with spaces',
+    });
+    const fileUrl = new URL('file:///tmp/data%20space');
+    expect(serializeWasixStorage(directory(fileUrl))).toEqual({
+      schema: 'oliphaunt-wasix-storage-v1',
+      kind: 'directory',
+      path: fileURLToPath(fileUrl),
+    });
+    expect(() => directory(new URL('https://example.com/data'))).toThrow(
+      'URL must be of scheme file',
+    );
+    expect(() => directory('')).toThrow('non-empty string');
+    expect(() => directory('bad\0path')).toThrow('without NUL bytes');
+  });
+
+  it('rejects user-authored and structured-cloned lookalikes', () => {
+    expect(() =>
+      serializeWasixStorage({
+        schema: 'oliphaunt-wasix-storage-v1',
+        kind: 'memory',
+      } as unknown as WasixStorage),
+    ).toThrow('must come from @oliphaunt/wasix-ts');
+
+    expect(() => serializeWasixStorage(structuredClone(memory()))).toThrow(
+      'must come from @oliphaunt/wasix-ts',
+    );
+  });
+
+  it('preserves typed storage failures across the worker boundary', () => {
+    const original = new WasixStorageError('the prior generation is still current', {
+      code: 'publication-failed',
+      commitState: 'not-persisted',
+      phase: 'open-publication',
+    });
+
+    const roundTrip = deserializeWorkerError(serializeWorkerError(original));
+
+    expect(roundTrip).toBeInstanceOf(WasixStorageError);
+    expect(roundTrip).toMatchObject({
+      name: 'WasixStorageError',
+      message: 'the prior generation is still current',
+      code: 'publication-failed',
+      commitState: 'not-persisted',
+      phase: 'open-publication',
+    });
+  });
+
+  it('preserves exact native tool diagnostics across the worker boundary', () => {
+    const original = Object.assign(new Error('pg_dump reported an impossible success error'), {
+      name: 'OliphauntWasixToolError',
+      oliphauntWasixError: 'tool' as const,
+      oliphauntWasixAddonAbi: 2 as const,
+      code: 'tool-error' as const,
+      tool: 'pg_dump',
+      exitCode: 0,
+      stdout: Uint8Array.of(0xff, 0),
+      stderr: Uint8Array.of(0x80, 0xfe),
+    });
+
+    const roundTrip = deserializeWorkerError(serializeWorkerError(original));
+
+    expect(roundTrip).toMatchObject({
+      name: 'OliphauntWasixToolError',
+      oliphauntWasixError: 'tool',
+      oliphauntWasixAddonAbi: 2,
+      code: 'tool-error',
+      tool: 'pg_dump',
+      exitCode: 0,
+      stdout: Uint8Array.of(0xff, 0),
+      stderr: Uint8Array.of(0x80, 0xfe),
+    });
+  });
+
+  it('preserves extension bootstrap PostgreSQL errors across the worker boundary', () => {
+    const original = new PostgresError([
+      { code: 0x53, value: 'ERROR' },
+      { code: 0x43, value: '42710' },
+      { code: 0x4d, value: 'extension already exists' },
+    ]);
+
+    const roundTrip = deserializeWorkerError(serializeWorkerError(original));
+
+    expect(roundTrip).toBeInstanceOf(PostgresError);
+    expect(roundTrip).toMatchObject({
+      name: 'PostgresError',
+      sqlstate: '42710',
+      message: 'extension already exists',
+      fields: original.fields,
+    });
+  });
+
+  it('preserves generic error identity and owner-side diagnostics across the worker boundary', () => {
+    const original = new TypeError('invalid owner request');
+    original.stack = 'TypeError: invalid owner request\n    at owner-worker.js:1:1';
+
+    const roundTrip = deserializeWorkerError(serializeWorkerError(original));
+
+    expect(roundTrip).toBeInstanceOf(Error);
+    expect(roundTrip).toMatchObject({
+      name: 'TypeError',
+      message: 'invalid owner request',
+      stack: original.stack,
+    });
+  });
+});
diff --git a/src/sdks/ts-wasix/sdk/src/__tests__/test-globals.ts b/src/sdks/ts-wasix/sdk/src/__tests__/test-globals.ts
new file mode 100644
index 000000000..332e8adfc
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/test-globals.ts
@@ -0,0 +1,12 @@
+const originals = new Map();
+export function stubGlobal(name: string, value: unknown): void {
+  if (!originals.has(name)) originals.set(name, Object.getOwnPropertyDescriptor(globalThis, name));
+  Object.defineProperty(globalThis, name, { configurable: true, writable: true, value });
+}
+export function restoreGlobals(): void {
+  for (const [name, descriptor] of originals) {
+    if (descriptor) Object.defineProperty(globalThis, name, descriptor);
+    else Reflect.deleteProperty(globalThis, name);
+  }
+  originals.clear();
+}
diff --git a/src/bindings/wasix-ts/src/__tests__/tool-runtime.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/tool-runtime.test.ts
similarity index 98%
rename from src/bindings/wasix-ts/src/__tests__/tool-runtime.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/tool-runtime.test.ts
index 19d5ce8a0..9a486a28e 100644
--- a/src/bindings/wasix-ts/src/__tests__/tool-runtime.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/tool-runtime.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
 
 import type { Directory } from '../host/index.mjs';
 import {
diff --git a/src/bindings/wasix-ts/src/__tests__/tool-worker-lifecycle.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/tool-worker-lifecycle.test.ts
similarity index 95%
rename from src/bindings/wasix-ts/src/__tests__/tool-worker-lifecycle.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/tool-worker-lifecycle.test.ts
index 169196bcd..71dafe6e0 100644
--- a/src/bindings/wasix-ts/src/__tests__/tool-worker-lifecycle.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/tool-worker-lifecycle.test.ts
@@ -1,4 +1,5 @@
-import { describe, expect, it, vi } from 'vitest';
+import { describe, expect, it, vi } from 'bun:test';
+import { rejects } from 'node:assert/strict';
 
 import {
   closeWasixByteChannel,
@@ -137,7 +138,7 @@ describe('persistent WASIX tool worker lifecycle', () => {
       ),
     ).resolves.toMatchObject({ stdout: Uint8Array.of(1, 2) });
 
-    expect(runPgDump).toHaveBeenCalledOnce();
+    expect(runPgDump).toHaveBeenCalledTimes(1);
     expect(createWorker).not.toHaveBeenCalled();
     await database.close();
   });
@@ -280,8 +281,12 @@ describe('persistent WASIX tool worker lifecycle', () => {
     const queued = run(database, () => port);
     await port.request(0);
 
-    const firstFailure = expect(first).rejects.toThrow('tool worker is closing');
-    const queuedFailure = expect(queued).rejects.toThrow('tool worker is closing');
+    const firstFailure = rejects(first, (error: Error) =>
+      error.message.includes('tool worker is closing'),
+    );
+    const queuedFailure = rejects(queued, (error: Error) =>
+      error.message.includes('tool worker is closing'),
+    );
     await database.close();
     await Promise.all([firstFailure, queuedFailure]);
 
@@ -321,11 +326,14 @@ describe('persistent WASIX tool worker lifecycle', () => {
       await port.request(1);
       await serving;
 
-      const toolFailure = expect(running).rejects.toThrow('tool worker is closing');
-      const closeFailure = expect(database.close()).rejects.toThrow(
-        'close exceeded 120000ms; worker termination was requested',
+      const toolFailure = rejects(running, (error: Error) =>
+        error.message.includes('tool worker is closing'),
+      );
+      const closeFailure = rejects(database.close(), (error: Error) =>
+        error.message.includes('close exceeded 120000ms; worker termination was requested'),
       );
-      await vi.advanceTimersByTimeAsync(120_000);
+      while (vi.getTimerCount() === 0) await Promise.resolve();
+      vi.advanceTimersByTime(120_000);
 
       await Promise.all([toolFailure, closeFailure]);
       expect(abortCount).toBe(1);
@@ -437,7 +445,7 @@ describe('persistent WASIX tool worker lifecycle', () => {
     secondPort.complete(invocation.id, 'recovered');
     await expect(second).resolves.toMatchObject({ stdout: new TextEncoder().encode('recovered') });
     expect(workerCount).toBe(2);
-    expect(serve).toHaveBeenCalledOnce();
+    expect(serve).toHaveBeenCalledTimes(1);
     await database.close();
   });
 
@@ -450,7 +458,9 @@ describe('persistent WASIX tool worker lifecycle', () => {
     const database = workerDatabase();
     const running = run(database, () => port);
     await port.request(0);
-    const failure = expect(running).rejects.toThrow('prepare worker crashed');
+    const failure = rejects(running, (error: Error) =>
+      error.message.includes('prepare worker crashed'),
+    );
     port.crash(new Error('prepare worker crashed'));
     await failure;
 
@@ -477,7 +487,9 @@ describe('persistent WASIX tool worker lifecycle', () => {
     const database = workerDatabase();
     const running = run(database, () => port);
     await port.request(0);
-    const runFailure = expect(running).rejects.toThrow('prepare worker crashed');
+    const runFailure = rejects(running, (error: Error) =>
+      error.message.includes('prepare worker crashed'),
+    );
     port.crash(new Error('prepare worker crashed'));
     await runFailure;
 
diff --git a/src/bindings/wasix-ts/src/__tests__/wasix-runtime.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/wasix-runtime.test.ts
similarity index 97%
rename from src/bindings/wasix-ts/src/__tests__/wasix-runtime.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/wasix-runtime.test.ts
index 5144dcddd..d117aa29f 100644
--- a/src/bindings/wasix-ts/src/__tests__/wasix-runtime.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/wasix-runtime.test.ts
@@ -1,4 +1,4 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
 
 import { WasixStorageError } from '../errors.js';
 import { PostgresError } from '../query.js';
@@ -46,7 +46,7 @@ describe('WASIX host runtime helpers', () => {
       },
     );
 
-    expect(result.baseDirectory).toBe(result.mounts['/base']);
+    expect(result.mounts['/base']).toBe(result.baseDirectory);
     expect(RecordingDirectory.created).toEqual([
       ['empty', 'nested/empty'],
       ['global', 'pg_wal'],
diff --git a/src/bindings/wasix-ts/src/__tests__/web-lock.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/web-lock.test.ts
similarity index 86%
rename from src/bindings/wasix-ts/src/__tests__/web-lock.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/web-lock.test.ts
index cc9a49b22..447dbbd10 100644
--- a/src/bindings/wasix-ts/src/__tests__/web-lock.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/web-lock.test.ts
@@ -1,18 +1,18 @@
-import { afterEach, describe, expect, it, vi } from 'vitest';
-
+import { afterEach, describe, expect, it } from 'bun:test';
 import { acquireExclusiveWebLock } from '../storage/web-lock.js';
+import { restoreGlobals, stubGlobal } from './test-globals.js';
 
-afterEach(() => vi.unstubAllGlobals());
+afterEach(() => restoreGlobals());
 
 describe('WASIX Web Lock ownership', () => {
   it('requires Web Locks and reports an unavailable lock without taking ownership', async () => {
-    vi.stubGlobal('navigator', {});
+    stubGlobal('navigator', {});
     await expect(acquireExclusiveWebLock('database', 'database storage')).rejects.toMatchObject({
       code: 'unavailable',
       commitState: 'unchanged',
     });
 
-    vi.stubGlobal('navigator', {
+    stubGlobal('navigator', {
       locks: {
         async request(
           _name: string,
@@ -30,7 +30,7 @@ describe('WASIX Web Lock ownership', () => {
   });
 
   it('normalizes request failures and releases an acquired lock exactly once', async () => {
-    vi.stubGlobal('navigator', {
+    stubGlobal('navigator', {
       locks: {
         async request() {
           throw 'request failed';
@@ -42,7 +42,7 @@ describe('WASIX Web Lock ownership', () => {
     );
 
     let releases = 0;
-    vi.stubGlobal('navigator', {
+    stubGlobal('navigator', {
       locks: {
         async request(
           name: string,
diff --git a/src/bindings/wasix-ts/src/__tests__/worker-client.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/worker-client.test.ts
similarity index 96%
rename from src/bindings/wasix-ts/src/__tests__/worker-client.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/worker-client.test.ts
index b69b69137..a7b3b17f6 100644
--- a/src/bindings/wasix-ts/src/__tests__/worker-client.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/worker-client.test.ts
@@ -1,8 +1,7 @@
-import { afterEach, beforeEach, describe, expect, it } from 'vitest';
-
-import { openWasix, Oliphaunt } from '../worker-client.js';
+import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
 import type { WorkerRequest, WorkerResponse } from '../rpc.js';
 import { indexedDB } from '../storage/indexed-db.js';
+import { Oliphaunt, openWasix } from '../worker-client.js';
 
 let crossOriginDescriptor: PropertyDescriptor | undefined;
 let workerDescriptor: PropertyDescriptor | undefined;
diff --git a/src/bindings/wasix-ts/src/__tests__/worker-helpers.ts b/src/sdks/ts-wasix/sdk/src/__tests__/worker-helpers.ts
similarity index 84%
rename from src/bindings/wasix-ts/src/__tests__/worker-helpers.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/worker-helpers.ts
index 285604760..174eba8ac 100644
--- a/src/bindings/wasix-ts/src/__tests__/worker-helpers.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/worker-helpers.ts
@@ -49,17 +49,6 @@ export function workerOpenOptions(): SerializedOpenOptions {
         size: 1,
         source: 'file:///runtime.tar.zst',
       },
-      standardSeedArchive: {
-        archive: 'cluster-seeds/standard.tar.zst',
-        sha256: '2'.repeat(64),
-        size: 1,
-        source: 'file:///standard-seed.tar.zst',
-      },
-      standardSeedManifest: {
-        sha256: '4'.repeat(64),
-        size: 1,
-        source: 'file:///standard-seed.json',
-      },
       manifest: {
         sha256: '3'.repeat(64),
         size: 1,
diff --git a/src/bindings/wasix-ts/src/__tests__/worker-rpc.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/worker-rpc.test.ts
similarity index 94%
rename from src/bindings/wasix-ts/src/__tests__/worker-rpc.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/worker-rpc.test.ts
index a5732d7f9..055c8b48b 100644
--- a/src/bindings/wasix-ts/src/__tests__/worker-rpc.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/worker-rpc.test.ts
@@ -1,5 +1,7 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
+import { rejects } from 'node:assert/strict';
 import { runWasixPgDumpProcess, WASIX_PROTOCOL_CALLBACK_CHUNK_BYTES } from '../database.js';
+import { runWasixToolProcess } from '../internal.node.js';
 import type { WorkerResponse } from '../rpc.js';
 import { createWorkerSessionDispatcher } from '../worker-dispatch.js';
 import { openWorkerDatabase, WorkerRpc } from '../worker-rpc.js';
@@ -59,6 +61,33 @@ describe('WASIX worker RPC', () => {
     await closing;
   });
 
+  it('preserves separately packaged tool sources across the worker boundary', async () => {
+    const port = new FakeWorkerPort();
+    const opening = openWorkerDatabase(port, workerOpenOptions());
+    const open = await postedRequest(port, 0);
+    port.respond({ id: open.id, ok: true });
+    const database = await opening;
+    const tool = {
+      name: 'psql' as const,
+      sha256: '4'.repeat(64),
+      size: 1,
+      source: 'file:///tools/psql.wasm',
+    };
+    const running = runWasixToolProcess(database, { runtimeVersion: '0.1.1', tool, args: [] });
+    const request = await postedRequest(port, 1);
+    expect(request).toMatchObject({ method: 'runTool', options: { tool } });
+    port.respond({
+      id: request.id,
+      ok: true,
+      value: { exitCode: 0, stdout: new Uint8Array(), stderr: new Uint8Array() },
+    });
+    await running;
+    const closing = database.close();
+    const close = await postedRequest(port, 2);
+    port.respond({ id: close.id, ok: true });
+    await closing;
+  });
+
   it('terminates the worker when opening returns an error', async () => {
     const port = new FakeWorkerPort();
     const opening = openWorkerDatabase(port, workerOpenOptions());
@@ -113,8 +142,8 @@ describe('WASIX worker RPC', () => {
     });
     const second = rpc.request({ method: 'sync', boundary: 'full' });
     const failure = new Error('worker exited unexpectedly');
-    const firstRejection = expect(first).rejects.toBe(failure);
-    const secondRejection = expect(second).rejects.toBe(failure);
+    const firstRejection = rejects(first, (error) => error === failure);
+    const secondRejection = rejects(second, (error) => error === failure);
 
     port.fail(failure);
 
@@ -273,7 +302,7 @@ describe('WASIX worker RPC', () => {
 
   it('preserves deferred execution and explicit sync boundaries across worker RPC', async () => {
     const events: string[] = [];
-    const responses: Array<{ id: number; ok: boolean }> = [];
+    const responses: Extract[] = [];
     const dispatch = createWorkerSessionDispatcher(
       async () => ({
         async exec(_input, persistence) {
@@ -362,7 +391,7 @@ describe('WASIX worker RPC', () => {
   it('retires the worker dispatcher before awaiting a failing session close', async () => {
     let closes = 0;
     let executions = 0;
-    const responses: Array<{ id: number; ok: boolean }> = [];
+    const responses: Extract[] = [];
     const dispatch = createWorkerSessionDispatcher(
       async () => ({
         async exec(input) {
@@ -428,7 +457,7 @@ describe('WASIX worker RPC', () => {
 
   it('rejects a malformed one-shot restore without opening a database session', async () => {
     let opened = false;
-    const responses: Array<{ id: number; ok: boolean }> = [];
+    const responses: Extract[] = [];
     const dispatch = createWorkerSessionDispatcher(
       async () => {
         opened = true;
@@ -578,7 +607,7 @@ describe('WASIX worker RPC', () => {
   });
 
   it('rejects backup when the opened worker session does not provide it', async () => {
-    const responses: Array<{ id: number; ok: boolean }> = [];
+    const responses: Extract[] = [];
     const dispatch = createWorkerSessionDispatcher(
       async () => ({
         async exec(input) {
diff --git a/src/bindings/wasix-ts/src/__tests__/worker-transfer.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/worker-transfer.test.ts
similarity index 89%
rename from src/bindings/wasix-ts/src/__tests__/worker-transfer.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/worker-transfer.test.ts
index 8f06583f5..26730d392 100644
--- a/src/bindings/wasix-ts/src/__tests__/worker-transfer.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/worker-transfer.test.ts
@@ -1,4 +1,5 @@
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it } from 'bun:test';
+import { deepEqual } from 'node:assert/strict';
 
 import { toolWorkerResponseTransfers } from '../tool-worker-common.js';
 import { prepareTransferableBytes } from '../worker-transfer.js';
@@ -12,7 +13,7 @@ describe('WASIX worker response transfer', () => {
     expect(response.value.byteOffset).toBe(0);
     expect(response.value.buffer.byteLength).toBe(2);
     expect(response.value.buffer).not.toBe(backing.buffer);
-    expect(response.transfer).toEqual([response.value.buffer]);
+    deepEqual(response.transfer, [response.value.buffer]);
   });
 
   it('reuses an already exact ArrayBuffer-backed view', () => {
diff --git a/src/bindings/wasix-ts/src/__tests__/zstd.test.ts b/src/sdks/ts-wasix/sdk/src/__tests__/zstd.test.ts
similarity index 81%
rename from src/bindings/wasix-ts/src/__tests__/zstd.test.ts
rename to src/sdks/ts-wasix/sdk/src/__tests__/zstd.test.ts
index 7dcd8e13a..9d48b6650 100644
--- a/src/bindings/wasix-ts/src/__tests__/zstd.test.ts
+++ b/src/sdks/ts-wasix/sdk/src/__tests__/zstd.test.ts
@@ -1,4 +1,4 @@
-import { afterEach, describe, expect, it, vi } from 'vitest';
+import { describe, expect, it, vi } from 'bun:test';
 
 const frame = Uint8Array.of(
   40,
@@ -31,17 +31,17 @@ const frame = Uint8Array.of(
   116,
 );
 
-afterEach(() => vi.resetModules());
-
 describe('WASIX zstd decompression', () => {
   it('uses the portable fallback by default', async () => {
-    const { decompressZstd } = await import('../zstd.js');
+    const { decompressZstd } = await import(`../zstd.ts?test=${crypto.randomUUID()}`);
 
     expect(new TextDecoder().decode(decompressZstd(frame))).toBe('oliphaunt-zstd-test');
   });
 
   it('selects one installed host decompressor', async () => {
-    const { decompressZstd, installZstdDecompressor } = await import('../zstd.js');
+    const { decompressZstd, installZstdDecompressor } = await import(
+      `../zstd.ts?test=${crypto.randomUUID()}`
+    );
     const output = Uint8Array.of(4, 2);
     const host = vi.fn(() => output);
 
@@ -53,7 +53,9 @@ describe('WASIX zstd decompression', () => {
   });
 
   it('propagates host decoding failures without retrying', async () => {
-    const { decompressZstd, installZstdDecompressor } = await import('../zstd.js');
+    const { decompressZstd, installZstdDecompressor } = await import(
+      `../zstd.ts?test=${crypto.randomUUID()}`
+    );
     const failure = new Error('invalid native frame');
     installZstdDecompressor(() => {
       throw failure;
diff --git a/src/bindings/wasix-ts/src/archive.ts b/src/sdks/ts-wasix/sdk/src/archive.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/archive.ts
rename to src/sdks/ts-wasix/sdk/src/archive.ts
diff --git a/src/bindings/wasix-ts/src/asset-source.ts b/src/sdks/ts-wasix/sdk/src/asset-source.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/asset-source.ts
rename to src/sdks/ts-wasix/sdk/src/asset-source.ts
diff --git a/src/sdks/ts-wasix/sdk/src/browser-public.ts b/src/sdks/ts-wasix/sdk/src/browser-public.ts
new file mode 100644
index 000000000..74ea5416e
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/browser-public.ts
@@ -0,0 +1,9 @@
+export * from './public.js';
+import type * as Types from './types.js';
+import type * as Storage from './storage.js';
+
+type StorageKind = 'memory' | 'indexed-db' | 'opfs';
+export type OpenConfig = Types.OpenConfig;
+export type OliphauntClient = Types.OliphauntClient;
+export type WasixStorage = Storage.WasixStorage;
+export type PersistentWasixStorage = Storage.PersistentWasixStorage>;
diff --git a/src/sdks/ts-wasix/sdk/src/browser.ts b/src/sdks/ts-wasix/sdk/src/browser.ts
new file mode 100644
index 000000000..721a01503
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/browser.ts
@@ -0,0 +1,12 @@
+const host = globalThis as typeof globalThis & {
+  process?: { versions?: { node?: string } };
+  Bun?: unknown;
+  Deno?: unknown;
+};
+if (host.process?.versions?.node || host.Bun !== undefined || host.Deno !== undefined) {
+  throw new Error(
+    '@oliphaunt/wasix-ts/browser requires a browser or browser worker; use @oliphaunt/wasix-ts on Node.js, Bun, or Deno',
+  );
+}
+export { Oliphaunt, Oliphaunt as default } from './client.js';
+export * from './browser-public.js';
diff --git a/src/bindings/wasix-ts/src/byte-channel.ts b/src/sdks/ts-wasix/sdk/src/byte-channel.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/byte-channel.ts
rename to src/sdks/ts-wasix/sdk/src/byte-channel.ts
diff --git a/src/sdks/ts-wasix/sdk/src/client-common.ts b/src/sdks/ts-wasix/sdk/src/client-common.ts
new file mode 100644
index 000000000..46b2a436b
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/client-common.ts
@@ -0,0 +1,27 @@
+import { decodePhysicalArchive } from './physical-archive.js';
+import { toUint8Array } from './query.js';
+import type { SerializedOpenOptions } from './rpc.js';
+import { restoreWasixStorage, WASIX_PHYSICAL_IDENTITY } from './storage-provider.js';
+import type { BinaryInput, OpenConfig } from './types.js';
+import { serializeOpenConfig } from './open-config.js';
+export { serializeOpenConfig } from './open-config.js';
+
+export async function restoreWasix(
+  storage: OpenConfig['storage'],
+  bytes: BinaryInput,
+  validate?: (options: SerializedOpenOptions) => void,
+): Promise {
+  if (storage === undefined) throw new TypeError('WASIX restore requires persistent storage');
+  const openOptions = serializeOpenConfig({ storage });
+  validate?.(openOptions);
+  await restoreWasixSerialized(openOptions.storage, toUint8Array(bytes).slice());
+}
+
+/** @internal Restore already-owned archive bytes inside the selected realm. */
+export async function restoreWasixSerialized(
+  storage: SerializedOpenOptions['storage'],
+  bytes: Uint8Array,
+): Promise {
+  const snapshot = decodePhysicalArchive(bytes);
+  await restoreWasixStorage(storage, snapshot, WASIX_PHYSICAL_IDENTITY);
+}
diff --git a/src/sdks/ts-wasix/sdk/src/client.ts b/src/sdks/ts-wasix/sdk/src/client.ts
new file mode 100644
index 000000000..b3d21a478
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/client.ts
@@ -0,0 +1,40 @@
+import { restoreWasix } from './client-common.js';
+import { requireBrowserStorage, serializeOpenConfig } from './open-config.js';
+import {
+  openWasixDirect,
+  type DirectWasixEnvironment,
+  type DirectWasixHost,
+} from './direct-client-common.js';
+import type { OliphauntClient, OliphauntDatabase, OpenConfig } from './browser-public.js';
+
+/** Open PostgreSQL in the importing browser realm. Guest execution may block that realm. */
+export async function openWasix(config: OpenConfig = {}): Promise {
+  return openWasixWithHost(config, () => import('./host/index.mjs'));
+}
+
+/** @internal Dependency seam for root-entrypoint contract qualification. */
+export async function openWasixWithHost(
+  config: OpenConfig,
+  loadHost: () => Promise,
+): Promise {
+  const openOptions = serializeOpenConfig(config);
+  requireBrowserStorage(openOptions);
+  if (globalThis.crossOriginIsolated !== true) {
+    throw new Error(
+      '@oliphaunt/wasix-ts requires COOP: same-origin and COEP: require-corp response headers',
+    );
+  }
+  const host = await loadHost();
+  return openWasixDirect(openOptions, host, browserRealm());
+}
+
+export const Oliphaunt: OliphauntClient = {
+  open: openWasix,
+  restore: (storage, bytes) => restoreWasix(storage, bytes, requireBrowserStorage),
+};
+
+function browserRealm(): DirectWasixEnvironment {
+  return typeof WorkerGlobalScope !== 'undefined' && globalThis instanceof WorkerGlobalScope
+    ? 'browser-worker'
+    : 'browser-main';
+}
diff --git a/src/bindings/wasix-ts/src/database-root.ts b/src/sdks/ts-wasix/sdk/src/database-root.ts
similarity index 91%
rename from src/bindings/wasix-ts/src/database-root.ts
rename to src/sdks/ts-wasix/sdk/src/database-root.ts
index 3abff50ae..b3006d821 100644
--- a/src/bindings/wasix-ts/src/database-root.ts
+++ b/src/sdks/ts-wasix/sdk/src/database-root.ts
@@ -8,6 +8,21 @@ export const DATABASE_ROOT_SCHEMA = 'oliphaunt-database-root-v1';
 export const DATABASE_ROOT_PGDATA = 'pgdata';
 export const DATABASE_ROOT_POSTGRES_MAJOR = CARRIER_POSTGRES_MAJOR;
 export const WASIX_PHYSICAL_FORMAT = CARRIER_PHYSICAL_FORMAT;
+/** Stable fields that determine whether a WASIX runtime may open stored PGDATA. */
+export type WasixPhysicalIdentity = Readonly<{
+  schema: 'oliphaunt-physical-format-v1';
+  engineFamily: 'wasix';
+  postgresMajor: number;
+  physicalFormat: string;
+}>;
+
+export const WASIX_PHYSICAL_IDENTITY: WasixPhysicalIdentity = Object.freeze({
+  schema: 'oliphaunt-physical-format-v1',
+  engineFamily: 'wasix',
+  postgresMajor: DATABASE_ROOT_POSTGRES_MAJOR,
+  physicalFormat: WASIX_PHYSICAL_FORMAT,
+});
+
 export const NATIVE_PHYSICAL_FORMAT = 'native-pg18-v1';
 
 export type DatabaseRootDescriptor = Readonly<{
diff --git a/src/bindings/wasix-ts/src/database.ts b/src/sdks/ts-wasix/sdk/src/database.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/database.ts
rename to src/sdks/ts-wasix/sdk/src/database.ts
diff --git a/src/bindings/wasix-ts/src/descriptor-validation.ts b/src/sdks/ts-wasix/sdk/src/descriptor-validation.ts
similarity index 98%
rename from src/bindings/wasix-ts/src/descriptor-validation.ts
rename to src/sdks/ts-wasix/sdk/src/descriptor-validation.ts
index 2080aabe5..74f9cf2cb 100644
--- a/src/bindings/wasix-ts/src/descriptor-validation.ts
+++ b/src/sdks/ts-wasix/sdk/src/descriptor-validation.ts
@@ -79,7 +79,7 @@ export function serializeAssetSource(source: WasixAssetSource): SerializedAssetS
     return source.href;
   }
   if (source instanceof Uint8Array) {
-    return source.slice();
+    return new Uint8Array(source);
   }
   return new Uint8Array(source.slice(0));
 }
diff --git a/src/bindings/wasix-ts/src/direct-client-common.ts b/src/sdks/ts-wasix/sdk/src/direct-client-common.ts
similarity index 97%
rename from src/bindings/wasix-ts/src/direct-client-common.ts
rename to src/sdks/ts-wasix/sdk/src/direct-client-common.ts
index 343bd56ed..fcfa56f6c 100644
--- a/src/bindings/wasix-ts/src/direct-client-common.ts
+++ b/src/sdks/ts-wasix/sdk/src/direct-client-common.ts
@@ -824,6 +824,8 @@ export function prepareRuntimeCached(
   options: SerializedOpenOptions,
   prepare: (options: SerializedOpenOptions) => Promise = prepareWasixRuntime,
 ): Promise {
+  // Explicit resource URLs/bytes can change independently of the runtime carrier.
+  if (options.seed !== undefined || options.icu !== undefined) return prepare(options);
   const identity = preparedRuntimeIdentity(options);
   let prepared = preparedRuntimes.get(identity);
   if (prepared === undefined) {
@@ -902,30 +904,11 @@ function preparedRuntimeIdentity(options: SerializedOpenOptions): string {
       product: runtime.product,
       version: runtime.version,
       runtimeArchive: assetIdentity(runtime.runtimeArchive),
-      standardSeedArchive: assetIdentity(runtime.standardSeedArchive),
-      standardSeedManifest: {
-        sha256: runtime.standardSeedManifest.sha256,
-        size: runtime.standardSeedManifest.size,
-      },
       manifest: {
         sha256: runtime.manifest.sha256,
         size: runtime.manifest.size,
       },
     },
-    icu:
-      options.icu === undefined
-        ? null
-        : {
-            product: options.icu.product,
-            version: options.icu.version,
-            compatibility: options.icu.compatibility,
-            dataArchive: assetIdentity(options.icu.dataArchive),
-            clusterSeedArchive: assetIdentity(options.icu.clusterSeedArchive),
-            clusterSeedManifest: {
-              sha256: options.icu.clusterSeedManifest.sha256,
-              size: options.icu.clusterSeedManifest.size,
-            },
-          },
     extensions: options.extensions,
     carriers: Object.values(options.extensionCarriers)
       .sort((left, right) => left.sqlName.localeCompare(right.sqlName))
diff --git a/src/bindings/wasix-ts/src/direct-client.ts b/src/sdks/ts-wasix/sdk/src/direct-client.ts
similarity index 88%
rename from src/bindings/wasix-ts/src/direct-client.ts
rename to src/sdks/ts-wasix/sdk/src/direct-client.ts
index d46c9ed4a..c1a0d9499 100644
--- a/src/bindings/wasix-ts/src/direct-client.ts
+++ b/src/sdks/ts-wasix/sdk/src/direct-client.ts
@@ -1,7 +1,7 @@
-import { serializeOpenConfig } from './client-common.js';
+import { serializeOpenConfig } from './open-config.js';
 import { requireNodeStorage, restoreNodeWasixDirect } from './node-client-common.js';
 import { openNodeDirect } from './node-direct.js';
-import type { OliphauntClient, OliphauntDatabase, OpenConfig } from './types.js';
+import type { OliphauntClient, OliphauntDatabase, OpenConfig } from './native-public.js';
 
 /** Open PostgreSQL in the importing realm, where native work blocks its event loop. */
 export async function openWasix(config: OpenConfig = {}): Promise {
diff --git a/src/sdks/ts-wasix/sdk/src/direct.node.ts b/src/sdks/ts-wasix/sdk/src/direct.node.ts
new file mode 100644
index 000000000..354e8ae25
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/direct.node.ts
@@ -0,0 +1,2 @@
+export { Oliphaunt, Oliphaunt as default } from './direct-client.js';
+export * from './native-public.js';
diff --git a/src/bindings/wasix-ts/src/errors.ts b/src/sdks/ts-wasix/sdk/src/errors.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/errors.ts
rename to src/sdks/ts-wasix/sdk/src/errors.ts
diff --git a/src/bindings/wasix-ts/src/extension-descriptor.ts b/src/sdks/ts-wasix/sdk/src/extension-descriptor.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/extension-descriptor.ts
rename to src/sdks/ts-wasix/sdk/src/extension-descriptor.ts
diff --git a/src/sdks/ts-wasix/sdk/src/extensions.ts b/src/sdks/ts-wasix/sdk/src/extensions.ts
new file mode 100644
index 000000000..fb87af9aa
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/extensions.ts
@@ -0,0 +1,1021 @@
+import {
+  clusterSeedMount,
+  decompressIfNeeded,
+  type ExtractedArchive,
+  extractTar,
+  layoutRuntimeSupport,
+  loadAsset,
+  type WasixDirectoryMount,
+  type WasixRuntimeLayout,
+} from './archive.js';
+import type {
+  SerializedOpenOptions,
+  SerializedRuntimeDescriptor,
+  SerializedToolRuntimeDescriptor,
+} from './rpc.js';
+import { WASIX_PHYSICAL_IDENTITY, type WasixPhysicalIdentity } from './database-root.js';
+import type { WasixAssetManifest } from './types.js';
+
+const decoder = new TextDecoder('utf-8', { fatal: true });
+const SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/;
+const SHA256 = /^[a-f0-9]{64}$/;
+const SHARED_PRELOAD_LIBRARIES = 'shared_preload_libraries';
+
+type CatalogProfile = 'standard' | 'icu';
+
+type ClusterSeedManifest = {
+  schema: 'oliphaunt-cluster-seed-v1';
+  artifactRole: 'cluster-seed-standard' | 'cluster-seed-icu';
+  catalogProfile: CatalogProfile;
+  runtime: {
+    product: string;
+    version: string;
+    engineFamily: string;
+    target: string;
+    physicalFormat: string;
+    postgresMajor: number;
+    compatibilityKey: string;
+    consumerSha256: string;
+    producerSha256: string;
+    initdbSha256: string;
+  };
+  source: {
+    producer: string;
+  };
+  archive: {
+    path: string;
+    sha256: string;
+    compressedBytes: number;
+    expandedBytes: number;
+    regularFiles: number;
+    directories: number;
+  };
+  requiredRuntimeFeatures: string[];
+  extensions: {
+    selected: string[];
+    startupConfiguration: string[];
+  };
+  icu: null | {
+    artifactRole: string;
+    dataTreeSha256: string;
+    dataVersion: string;
+    dataForm: string;
+  };
+};
+
+/** Internal kebab-case projection used while installing an imported carrier. */
+type ProjectedExtensionLifecycle = {
+  'create-extension': boolean;
+  'create-schema'?: string | null;
+  'load-sql': readonly string[];
+  'post-create-sql': readonly string[];
+  'startup-config': readonly string[];
+  'shared-memory-required': boolean;
+};
+
+/** Internal install shape projected solely from extension-owned carrier metadata. */
+type ProjectedExtensionInstall = {
+  name: string;
+  'sql-name': string;
+  archive: string;
+  sha256: string;
+  size: number;
+  'native-module'?: string | null;
+  'native-modules': readonly unknown[];
+  dependencies: readonly string[];
+  'load-order': readonly string[];
+  lifecycle: ProjectedExtensionLifecycle;
+  'installed-files': readonly string[];
+  'unresolved-imports': readonly unknown[];
+};
+
+export type ResolvedWasixExtensions = {
+  extensions: ProjectedExtensionInstall[];
+  runtimeDependencies: string[];
+};
+
+export type PreparedWasixRuntime = {
+  layout: WasixRuntimeLayout;
+  loadClusterSeed(): Promise;
+  moduleSha256: string;
+  catalogProfile: 'standard' | 'icu';
+  icuEnabled: boolean;
+  startupGUCs: Record;
+  physicalIdentity: WasixPhysicalIdentity;
+};
+
+/**
+ * Loads and verifies one exact runtime/ICU/extension closure. The matching
+ * cluster seed stays lazy until an exclusively leased storage provider reports
+ * a new root. Selection materializes exact artifacts and required startup
+ * configuration; database-local installation remains explicit application SQL.
+ */
+export async function prepareWasixRuntime(
+  options: SerializedOpenOptions,
+): Promise {
+  const descriptor = options.runtime;
+  const profile = options.icu === undefined ? 'standard' : 'icu';
+  const [manifestBytes, runtimeBytes, icuData] = await Promise.all([
+    loadAsset(descriptor.manifest.source, 'WASIX asset manifest'),
+    loadAsset(descriptor.runtimeArchive.source, 'WASIX runtime archive'),
+    options.icu === undefined ? Promise.resolve(undefined) : loadIcuData(options.icu),
+  ]);
+  await Promise.all([
+    assertDeclaredAssetBytes(
+      manifestBytes,
+      descriptor.manifest.size,
+      descriptor.manifest.sha256,
+      'WASIX asset manifest',
+    ),
+    assertDeclaredAssetBytes(
+      runtimeBytes,
+      descriptor.runtimeArchive.size,
+      descriptor.runtimeArchive.sha256,
+      'WASIX runtime archive',
+    ),
+  ]);
+  const manifest = parseWasixAssetManifest(manifestBytes);
+  assertRuntimeDescriptorMatchesManifest(descriptor, manifest);
+  const runtime = extractTar(decompressIfNeeded(runtimeBytes));
+  if (icuData !== undefined) {
+    overlayIcuArchive(runtime, {
+      files: new Map([['share/icu/icudt76l.dat', icuData.data]]),
+      directories: new Set(['share', 'share/icu']),
+    });
+  }
+  const layout = layoutRuntimeSupport(runtime);
+  assertExtensionCarriersCompatible(descriptor, manifest, options.extensionCarriers);
+
+  const resolved = resolveWasixExtensions(manifest, options.extensionCarriers, options.extensions);
+  assertExactCarrierClosure(resolved.extensions, options.extensionCarriers);
+  const loaded = await Promise.all(
+    resolved.extensions.map(async (extension) => {
+      if (extension['unresolved-imports'].length > 0) {
+        throw new Error(
+          `WASIX extension '${extension['sql-name']}' carrier has unresolved imports`,
+        );
+      }
+      const carrier = Object.hasOwn(options.extensionCarriers, extension['sql-name'])
+        ? options.extensionCarriers[extension['sql-name']]
+        : undefined;
+      if (carrier === undefined) {
+        throw new Error(
+          `selected WASIX extension '${extension['sql-name']}' requires exact carrier ${extension.archive}`,
+        );
+      }
+      const bytes = await loadAsset(
+        carrier.source,
+        `WASIX extension ${extension['sql-name']} from ${carrier.product}@${carrier.version}`,
+      );
+      if (bytes.length !== extension.size) {
+        throw new Error(
+          `WASIX extension '${extension['sql-name']}' carrier size mismatch: expected ${extension.size}, received ${bytes.length}`,
+        );
+      }
+      await assertSha256(
+        bytes,
+        extension.sha256,
+        `WASIX extension '${extension['sql-name']}' carrier`,
+      );
+      return [extension, extractTar(decompressIfNeeded(bytes))] as const;
+    }),
+  );
+  for (const [extension, archive] of loaded) {
+    overlayExtensionArchive(layout, archive, extension);
+  }
+
+  return {
+    layout,
+    loadClusterSeed: lazyClusterSeedLoader(options, manifest, profile, icuData?.treeSha256),
+    moduleSha256: manifest.runtime['module-sha256'],
+    catalogProfile: profile,
+    icuEnabled: options.icu !== undefined,
+    startupGUCs: mergeExtensionStartupGUCs(options.startupGUCs, resolved.extensions),
+    physicalIdentity: WASIX_PHYSICAL_IDENTITY,
+  };
+}
+
+function lazyClusterSeedLoader(
+  options: SerializedOpenOptions,
+  runtime: WasixAssetManifest,
+  profile: CatalogProfile,
+  icuTree?: string,
+): () => Promise {
+  let cached: Promise | undefined;
+  return () => {
+    if (cached === undefined) {
+      cached = loadClusterSeed(options, runtime, profile, icuTree);
+      void cached.catch(() => {
+        cached = undefined;
+      });
+    }
+    return cached;
+  };
+}
+
+export async function loadSeedBytes(seed: NonNullable) {
+  const [archive, manifest] = await Promise.all([
+    loadAsset(seed.archive, 'WASIX seed archive'),
+    loadAsset(seed.manifest, 'WASIX seed manifest'),
+  ]);
+  return { archive, manifest };
+}
+
+export async function loadIcuData(icu: NonNullable) {
+  const [data, manifest] = await Promise.all([
+    loadAsset(icu.data, 'ICU data'),
+    loadAsset(icu.manifest, 'ICU manifest'),
+  ]);
+  const fields = new Map();
+  for (const line of decodeUtf8(manifest).split(/\r?\n/)) {
+    if (!line.trim() || line.startsWith('#')) continue;
+    const at = line.indexOf('=');
+    if (at <= 0 || fields.has(line.slice(0, at))) throw new Error('invalid ICU manifest');
+    fields.set(line.slice(0, at), line.slice(at + 1));
+  }
+  if (
+    fields.get('schema') !== 'oliphaunt-icu-data-v1' ||
+    fields.get('artifactRole') !== 'icu-data' ||
+    fields.get('icuDataVersion') !== '76.1' ||
+    fields.get('icuDataForm') !== 'files-le'
+  ) {
+    throw new Error('incompatible ICU data manifest');
+  }
+  const treeSha256 = requireSha256(fields.get('icuDataTreeSha256'), 'ICU logical tree');
+  const prefix = new TextEncoder().encode('icudt76l.dat\0' + data.length + '\0');
+  const tree = new Uint8Array(prefix.length + data.length + 1);
+  tree.set(prefix);
+  tree.set(data, prefix.length);
+  tree[tree.length - 1] = 10;
+  await assertSha256(tree, treeSha256, 'ICU data tree');
+  return { data, manifest, treeSha256 };
+}
+
+async function loadClusterSeed(
+  options: SerializedOpenOptions,
+  runtime: WasixAssetManifest,
+  profile: CatalogProfile,
+  icuTree?: string,
+): Promise {
+  if (options.seed === undefined) throw new Error('new browser storage requires an explicit seed');
+  const { archive, manifest } = await loadSeedBytes(options.seed);
+  const seed = parseClusterSeedManifest(manifest, profile);
+  verifyClusterSeedIdentity(options, runtime, seed, icuTree);
+  await assertDeclaredAssetBytes(
+    archive,
+    seed.archive.compressedBytes,
+    seed.archive.sha256,
+    'WASIX seed',
+  );
+  const unpacked = extractTar(decompressIfNeeded(archive));
+  verifyPostgresIdentity(runtime, seed.runtime.postgresMajor, unpacked.files.get('PG_VERSION'));
+  if (!unpacked.files.has('global/pg_control'))
+    throw new Error('WASIX seed is missing global/pg_control');
+  return clusterSeedMount(unpacked);
+}
+
+/** Require the package-authored archive identities to match the canonical manifest. */
+export function assertRuntimeDescriptorMatchesManifest(
+  descriptor: SerializedRuntimeDescriptor,
+  manifest: WasixAssetManifest,
+): void {
+  assertToolRuntimeDescriptorMatchesManifest(descriptor, manifest);
+}
+
+/** Verify only the runtime assets consumed by PostgreSQL frontend tools. */
+export function assertToolRuntimeDescriptorMatchesManifest(
+  descriptor: SerializedToolRuntimeDescriptor,
+  manifest: WasixAssetManifest,
+): void {
+  assertRuntimeArchiveMatchesManifest(
+    descriptor.runtimeArchive,
+    manifest.runtime,
+    'WASIX runtime archive',
+  );
+}
+
+export function assertExactCarrierClosure(
+  resolved: readonly ProjectedExtensionInstall[],
+  carriers: SerializedOpenOptions['extensionCarriers'],
+): void {
+  const expected = new Set(resolved.map((extension) => extension['sql-name']));
+  const actual = new Set(Object.keys(carriers));
+  const missing = [...expected].filter((sqlName) => !actual.has(sqlName)).sort();
+  const unexpected = [...actual].filter((sqlName) => !expected.has(sqlName)).sort();
+  if (missing.length > 0 || unexpected.length > 0) {
+    throw new Error(
+      'WASIX extension carrier closure does not match imported dependency resolution' +
+        `${missing.length > 0 ? `; missing ${missing.join(', ')}` : ''}` +
+        `${unexpected.length > 0 ? `; unexpected ${unexpected.join(', ')}` : ''}`,
+    );
+  }
+}
+
+export function parseWasixAssetManifest(bytes: Uint8Array): WasixAssetManifest {
+  let parsed: unknown;
+  try {
+    parsed = JSON.parse(decodeUtf8(bytes));
+  } catch (error) {
+    throw new Error(`WASIX asset manifest is not valid UTF-8 JSON: ${describeError(error)}`);
+  }
+  const manifest = requireObject(parsed, 'WASIX asset manifest');
+  if (manifest['format-version'] !== 2) {
+    throw new Error('WASIX asset manifest must use format-version 2');
+  }
+
+  const runtime = requireObject(manifest.runtime, 'WASIX asset manifest runtime');
+  requireAssetPath(runtime.archive, 'WASIX runtime archive');
+  requireSha256(runtime.sha256, 'WASIX runtime archive');
+  if (runtime.size !== undefined) {
+    requireSafeInteger(runtime.size, 'WASIX runtime archive size');
+  }
+  requireSha256(runtime['module-sha256'], 'WASIX runtime module');
+  requireString(runtime['postgres-version'], 'WASIX runtime PostgreSQL version');
+  const link = requireObject(runtime.link, 'WASIX runtime link metadata');
+  const exports = requireArray(link.exports, 'WASIX runtime exports');
+  for (const [index, value] of exports.entries()) {
+    const entry = requireObject(value, `WASIX runtime export ${index}`);
+    requireString(entry.name, `WASIX runtime export ${index} name`);
+    requireString(entry.kind, `WASIX runtime export ${index} kind`);
+  }
+
+  requireString(manifest['source-fingerprint'], 'WASIX asset source fingerprint');
+
+  const runtimeSupport = requireArray(manifest['runtime-support'], 'WASIX runtime-support entries');
+  for (const [index, value] of runtimeSupport.entries()) {
+    const support = requireObject(value, `WASIX runtime-support entry ${index}`);
+    requireSqlName(support.name, `WASIX runtime-support entry ${index} name`);
+    requireInstallPath(support.path, `WASIX runtime-support entry ${index} path`);
+    requireSha256(support.sha256, `WASIX runtime-support entry ${index}`);
+  }
+
+  const extensions = requireArray(manifest.extensions, 'WASIX extension entries');
+  if (extensions.length !== 0) {
+    throw new Error(
+      'WASIX core asset manifest must not contain extension rows; import extension carriers explicitly',
+    );
+  }
+
+  return parsed as WasixAssetManifest;
+}
+
+export function resolveWasixExtensions(
+  manifest: WasixAssetManifest,
+  carriers: SerializedOpenOptions['extensionCarriers'],
+  requested: readonly string[],
+): ResolvedWasixExtensions {
+  const runtimeSupport = new Set(manifest['runtime-support'].map((entry) => entry.name));
+  const bySqlName = new Map(
+    Object.entries(carriers).map(([sqlName, carrier]) => {
+      if (carrier.sqlName !== sqlName) {
+        throw new Error(
+          `WASIX extension carrier map key '${sqlName}' does not match carrier SQL name '${carrier.sqlName}'`,
+        );
+      }
+      if (runtimeSupport.has(sqlName)) {
+        throw new Error(
+          `WASIX extension carrier '${sqlName}' cannot replace runtime-provided support`,
+        );
+      }
+      return [sqlName, extensionFromCarrier(carrier)] as const;
+    }),
+  );
+  const visiting = new Set();
+  const visited = new Set();
+  const runtimeDependencies = new Set();
+  const resolved: ProjectedExtensionInstall[] = [];
+
+  const visit = (extension: ProjectedExtensionInstall): void => {
+    const sqlName = extension['sql-name'];
+    if (visited.has(sqlName)) {
+      return;
+    }
+    if (extension.lifecycle['shared-memory-required']) {
+      throw new Error(
+        `selected WASIX extension '${sqlName}' requires shared-memory behavior that the @oliphaunt/wasix-ts host has not qualified`,
+      );
+    }
+    if (visiting.has(sqlName)) {
+      throw new Error(`cyclic WASIX extension dependency involving '${sqlName}'`);
+    }
+    visiting.add(sqlName);
+    for (const dependency of extension.dependencies) {
+      if (runtimeSupport.has(dependency)) {
+        runtimeDependencies.add(dependency);
+      } else {
+        const dependencyExtension = bySqlName.get(dependency);
+        if (dependencyExtension !== undefined) {
+          visit(dependencyExtension);
+          continue;
+        }
+        throw new Error(
+          `selected WASIX extension '${sqlName}' depends on unavailable extension '${dependency}'`,
+        );
+      }
+    }
+    visiting.delete(sqlName);
+    visited.add(sqlName);
+    resolved.push(extension);
+  };
+
+  for (const sqlName of [...new Set(requested)].sort()) {
+    requireSqlName(sqlName, 'selected WASIX extension');
+    const extension = bySqlName.get(sqlName);
+    if (extension === undefined) {
+      throw new Error(`selected WASIX extension '${sqlName}' has no imported carrier`);
+    }
+    visit(extension);
+  }
+  return {
+    extensions: resolved,
+    runtimeDependencies: [...runtimeDependencies].sort(),
+  };
+}
+
+function extensionFromCarrier(
+  carrier: SerializedOpenOptions['extensionCarriers'][string],
+): ProjectedExtensionInstall {
+  const lifecycle = carrier.install.lifecycle;
+  return {
+    name: carrier.install.name,
+    'sql-name': carrier.sqlName,
+    archive: carrier.archive,
+    sha256: carrier.sha256,
+    size: carrier.size,
+    'native-module': carrier.install.nativeModule,
+    'native-modules': carrier.install.nativeModules,
+    dependencies: carrier.install.dependencies,
+    'load-order': carrier.install.loadOrder,
+    lifecycle: {
+      'create-extension': lifecycle.createExtension,
+      ...(lifecycle.createSchema === undefined ? {} : { 'create-schema': lifecycle.createSchema }),
+      'load-sql': lifecycle.loadSql,
+      'post-create-sql': lifecycle.postCreateSql,
+      'startup-config': lifecycle.startupConfig,
+      'shared-memory-required': lifecycle.sharedMemoryRequired,
+    },
+    'installed-files': carrier.install.installedFiles,
+    'unresolved-imports': carrier.install.unresolvedImports,
+  };
+}
+
+export function assertExtensionCarriersCompatible(
+  runtime: SerializedRuntimeDescriptor,
+  manifest: WasixAssetManifest,
+  carriers: SerializedOpenOptions['extensionCarriers'],
+): void {
+  const postgresMajor = manifest.runtime['postgres-version'].split('.')[0];
+  for (const carrier of Object.values(carriers)) {
+    const compatibility = carrier.compatibility;
+    if (compatibility.extensionRuntimeContract !== 'oliphaunt-extension-runtime-contract-v1') {
+      throw new Error(
+        `WASIX extension '${carrier.sqlName}' has an unsupported extension runtime contract`,
+      );
+    }
+    if (
+      compatibility.wasixRuntimeProduct !== runtime.product ||
+      compatibility.wasixRuntimeVersion !== runtime.version
+    ) {
+      throw new Error(
+        `WASIX extension '${carrier.sqlName}' targets ${compatibility.wasixRuntimeProduct}@${compatibility.wasixRuntimeVersion}, not ${runtime.product}@${runtime.version}`,
+      );
+    }
+    if (compatibility.postgresMajor !== postgresMajor) {
+      throw new Error(
+        `WASIX extension '${carrier.sqlName}' targets PostgreSQL ${compatibility.postgresMajor}, not ${postgresMajor}`,
+      );
+    }
+  }
+  const coreExports = new Set(
+    manifest.runtime.link.exports
+      .filter((entry) => entry.kind === 'func' || entry.kind === 'global')
+      .map((entry) => entry.name),
+  );
+  for (const carrier of Object.values(carriers)) {
+    const missing = carrier.install.coreExportsRequired.filter((name) => !coreExports.has(name));
+    if (missing.length > 0) {
+      throw new Error(
+        `WASIX extension '${carrier.sqlName}' requires exports absent from the selected core runtime: ${missing.join(', ')}`,
+      );
+    }
+  }
+}
+
+export function overlayExtensionArchive(
+  layout: WasixRuntimeLayout,
+  archive: ExtractedArchive,
+  extension: ProjectedExtensionInstall,
+): void {
+  const sqlName = extension['sql-name'];
+  const expected = new Set(extension['installed-files']);
+  if (expected.size !== extension['installed-files'].length) {
+    throw new Error(`WASIX extension '${sqlName}' manifest repeats installed file paths`);
+  }
+  const actual = new Set(archive.files.keys());
+  const missing = [...expected].filter((path) => !actual.has(path));
+  const unexpected = [...actual].filter((path) => !expected.has(path));
+  if (missing.length > 0 || unexpected.length > 0) {
+    throw new Error(
+      `WASIX extension '${sqlName}' archive contents do not match installed-files` +
+        `${missing.length > 0 ? `; missing ${missing.join(', ')}` : ''}` +
+        `${unexpected.length > 0 ? `; unexpected ${unexpected.join(', ')}` : ''}`,
+    );
+  }
+
+  for (const [path, bytes] of archive.files) {
+    const { mountPath, relative } = extensionMountTarget(path, sqlName);
+    const mount = layout.mounts[mountPath];
+    if (mount === undefined) {
+      throw new Error(`WASIX runtime is missing extension mount ${mountPath}`);
+    }
+    if (Object.hasOwn(mount.files, relative)) {
+      throw new Error(`WASIX extension '${sqlName}' collides with installed file ${path}`);
+    }
+    mount.files[relative] = bytes;
+  }
+  for (const path of archive.directories) {
+    if (path === 'lib' || path === 'share') {
+      continue;
+    }
+    const { mountPath, relative } = extensionMountTarget(path, sqlName, true);
+    const mount = layout.mounts[mountPath];
+    if (mount === undefined) {
+      throw new Error(`WASIX runtime is missing extension mount ${mountPath}`);
+    }
+    if (!mount.directories.includes(relative)) {
+      mount.directories.push(relative);
+    }
+  }
+}
+
+export function mergeExtensionStartupGUCs(
+  configured: Readonly>,
+  extensions: readonly ProjectedExtensionInstall[],
+): Record {
+  const merged = { ...configured };
+  const sharedPreloads: string[] = [];
+  const seenSharedPreloads = new Set();
+  appendCsv(merged[SHARED_PRELOAD_LIBRARIES], sharedPreloads, seenSharedPreloads);
+
+  for (const extension of extensions) {
+    for (const assignment of extension.lifecycle['startup-config']) {
+      const equals = assignment.indexOf('=');
+      const name = assignment.slice(0, equals).trim();
+      const value = assignment.slice(equals + 1).trim();
+      if (equals <= 0 || !/^[A-Za-z][A-Za-z0-9_.]*$/.test(name) || value.length === 0) {
+        throw new Error(
+          `WASIX extension '${extension['sql-name']}' has invalid startup config '${assignment}'`,
+        );
+      }
+      if (name === SHARED_PRELOAD_LIBRARIES) {
+        appendCsv(value, sharedPreloads, seenSharedPreloads);
+        continue;
+      }
+      const existing = merged[name];
+      if (existing !== undefined && existing !== value) {
+        throw new Error(
+          `WASIX extension '${extension['sql-name']}' requires ${name}=${value}, but the caller configured ${name}=${existing}`,
+        );
+      }
+      merged[name] = value;
+    }
+  }
+  if (sharedPreloads.length > 0) {
+    merged[SHARED_PRELOAD_LIBRARIES] = sharedPreloads.join(',');
+  }
+  return merged;
+}
+
+function parseClusterSeedManifest(
+  bytes: Uint8Array,
+  expectedProfile: CatalogProfile,
+): ClusterSeedManifest {
+  let parsed: unknown;
+  try {
+    parsed = JSON.parse(decodeUtf8(bytes));
+  } catch (error) {
+    throw new Error(
+      `WASIX ${expectedProfile} cluster seed manifest is not valid UTF-8 JSON: ${describeError(error)}`,
+    );
+  }
+  const label = `WASIX ${expectedProfile} cluster seed manifest`;
+  const root = requireObject(parsed, label);
+  requireExactKeys(
+    root,
+    [
+      'archive',
+      'artifactRole',
+      'catalogProfile',
+      'extensions',
+      'icu',
+      'requiredRuntimeFeatures',
+      'runtime',
+      'schema',
+      'source',
+    ],
+    label,
+  );
+  assertClusterSeedProfileContract(root, expectedProfile);
+
+  const runtime = requireObject(root.runtime, `${label} runtime`);
+  requireExactKeys(
+    runtime,
+    [
+      'compatibilityKey',
+      'consumerSha256',
+      'engineFamily',
+      'target',
+      'initdbSha256',
+      'physicalFormat',
+      'postgresMajor',
+      'producerSha256',
+      'product',
+      'version',
+    ],
+    `${label} runtime`,
+  );
+  for (const field of [
+    'product',
+    'version',
+    'engineFamily',
+    'physicalFormat',
+    'compatibilityKey',
+  ] as const) {
+    requireString(runtime[field], `${label} runtime ${field}`);
+  }
+  requirePositiveInteger(runtime.postgresMajor, `${label} runtime PostgreSQL major`);
+  for (const field of ['consumerSha256', 'producerSha256', 'initdbSha256'] as const) {
+    requireSha256(runtime[field], `${label} runtime ${field}`);
+  }
+
+  const source = requireObject(root.source, `${label} source`);
+  requireExactKeys(source, ['producer'], `${label} source`);
+  for (const field of ['producer'] as const) {
+    requireString(source[field], `${label} source ${field}`);
+  }
+
+  const archive = requireObject(root.archive, `${label} archive`);
+  requireExactKeys(
+    archive,
+    ['compressedBytes', 'directories', 'expandedBytes', 'path', 'regularFiles', 'sha256'],
+    `${label} archive`,
+  );
+  requireAssetPath(archive.path, `${label} archive path`);
+  requireSha256(archive.sha256, `${label} archive`);
+  for (const field of [
+    'compressedBytes',
+    'directories',
+    'expandedBytes',
+    'regularFiles',
+  ] as const) {
+    requirePositiveInteger(archive[field], `${label} archive ${field}`);
+  }
+
+  const extensions = requireObject(root.extensions, `${label} extensions`);
+  requireExactKeys(extensions, ['selected', 'startupConfiguration'], `${label} extensions`);
+  const selected = requireStringArray(extensions.selected, `${label} selected extensions`);
+  const startupConfiguration = requireStringArray(
+    extensions.startupConfiguration,
+    `${label} startup configuration`,
+  );
+  if (selected.length !== 0 || startupConfiguration.length !== 0) {
+    throw new Error(`${label} must be extension-free`);
+  }
+
+  return parsed as ClusterSeedManifest;
+}
+
+/** @internal Validate the host-independent standard/ICU seed profile contract. */
+export function assertClusterSeedProfileContract(
+  value: unknown,
+  expectedProfile: CatalogProfile,
+): void {
+  const label = `WASIX ${expectedProfile} cluster seed manifest`;
+  const root = requireObject(value, label);
+  if (root.schema !== 'oliphaunt-cluster-seed-v1') {
+    throw new Error(`${label} has an unsupported schema`);
+  }
+  if (root.catalogProfile !== expectedProfile) {
+    throw new Error(
+      `${label} profile mismatch: expected ${expectedProfile}, got ${String(root.catalogProfile)}`,
+    );
+  }
+  const expectedRole =
+    expectedProfile === 'standard' ? 'cluster-seed-standard' : 'cluster-seed-icu';
+  if (root.artifactRole !== expectedRole) {
+    throw new Error(
+      `${label} profile mismatch: expected role ${expectedRole}, got ${String(root.artifactRole)}`,
+    );
+  }
+
+  const requiredFeatures = requireStringArray(
+    root.requiredRuntimeFeatures,
+    `${label} required features`,
+  );
+  if (expectedProfile === 'standard') {
+    if (requiredFeatures.length !== 0 || root.icu !== null) {
+      throw new Error(`${label} must not require or identify ICU data`);
+    }
+    return;
+  }
+  if (requiredFeatures.length !== 1 || requiredFeatures[0] !== 'icu') {
+    throw new Error(`${label} must require exactly the ICU runtime feature`);
+  }
+  const icu = requireObject(root.icu, `${label} ICU identity`);
+  for (const field of ['artifactRole', 'dataForm', 'dataVersion'] as const) {
+    requireString(icu[field], `${label} ICU ${field}`);
+  }
+  requireSha256(icu.dataTreeSha256, `${label} ICU data tree`);
+  if (
+    icu.artifactRole !== 'icu-data' ||
+    icu.dataVersion !== '76.1' ||
+    icu.dataForm !== 'files-le'
+  ) {
+    throw new Error(`${label} has an incompatible ICU identity`);
+  }
+}
+
+function verifyClusterSeedIdentity(
+  options: SerializedOpenOptions,
+  outer: WasixAssetManifest,
+  seed: ClusterSeedManifest,
+  icuTree?: string,
+): void {
+  if (
+    seed.runtime.product !== options.runtime.product ||
+    seed.runtime.version !== options.runtime.version ||
+    seed.runtime.engineFamily !== 'wasix' ||
+    seed.runtime.target !== 'portable' ||
+    seed.runtime.physicalFormat !== 'wasix-pg18-v1' ||
+    seed.runtime.compatibilityKey !== 'wasix-pg18-datum32-v1' ||
+    seed.runtime.postgresMajor !== 18 ||
+    seed.source.producer !== 'wasix-initdb'
+  )
+    throw new Error('WASIX seed has an incompatible runtime identity');
+  if (
+    seed.runtime.consumerSha256 !== seed.runtime.producerSha256 ||
+    seed.runtime.consumerSha256 !== outer.runtime['module-sha256']
+  ) {
+    throw new Error('WASIX seed was produced by a different runtime module');
+  }
+  if (seed.catalogProfile === 'icu' && seed.icu?.dataTreeSha256 !== icuTree) {
+    throw new Error('WASIX ICU seed does not match the selected ICU data');
+  }
+}
+
+/** @internal Validate and add exact-archive-verified ICU files to the runtime tree. */
+export function overlayIcuArchive(runtime: ExtractedArchive, icu: ExtractedArchive): void {
+  const prefix = 'share/icu/';
+  const rows: { path: string; bytes: Uint8Array }[] = [];
+  const directories: string[] = [];
+  let hasDataFile = false;
+  for (const [path, bytes] of icu.files) {
+    if (!path.startsWith(prefix) || path.length === prefix.length) {
+      throw new Error(`WASIX ICU data archive contains a file outside share/icu: ${path}`);
+    }
+    const relative = path.slice(prefix.length);
+    if (relative.split('/').some((segment) => segment.startsWith('icudt'))) hasDataFile = true;
+    rows.push({ path: relative, bytes });
+    const target = `oliphaunt/${path}`;
+    if (runtime.files.has(target) || runtime.directories.has(target)) {
+      throw new Error(`WASIX ICU data collides with runtime path ${target}`);
+    }
+  }
+  if (rows.length === 0 || !hasDataFile) {
+    throw new Error('WASIX ICU data archive contains no ICU data files under share/icu');
+  }
+  for (const path of icu.directories) {
+    if (path !== 'share' && path !== 'share/icu' && !path.startsWith(prefix)) {
+      throw new Error(`WASIX ICU data archive contains a directory outside share/icu: ${path}`);
+    }
+    if (path === 'share') continue;
+    const target = `oliphaunt/${path}`;
+    if (runtime.files.has(target)) {
+      throw new Error(`WASIX ICU data collides with runtime path ${target}`);
+    }
+    directories.push(target);
+  }
+  for (const { path, bytes } of rows) runtime.files.set(`oliphaunt/share/icu/${path}`, bytes);
+  for (const path of directories) runtime.directories.add(path);
+}
+
+function assertRuntimeArchiveMatchesManifest(
+  descriptor: SerializedRuntimeDescriptor['runtimeArchive'],
+  manifest: { archive: string; sha256: string; size?: number },
+  label: string,
+): void {
+  if (descriptor.archive !== manifest.archive) {
+    throw new Error(
+      `${label} path does not match the canonical manifest: expected ${manifest.archive}, received ${descriptor.archive}`,
+    );
+  }
+  if (descriptor.sha256 !== manifest.sha256) {
+    throw new Error(`${label} SHA-256 does not match the canonical manifest`);
+  }
+  if (manifest.size !== undefined && descriptor.size !== manifest.size) {
+    throw new Error(
+      `${label} size does not match the canonical manifest: expected ${manifest.size}, received ${descriptor.size}`,
+    );
+  }
+}
+
+async function assertDeclaredAssetBytes(
+  bytes: Uint8Array,
+  expectedSize: number,
+  expectedSha256: string,
+  label: string,
+): Promise {
+  if (bytes.length !== expectedSize) {
+    throw new Error(`${label} size mismatch: expected ${expectedSize}, received ${bytes.length}`);
+  }
+  await assertSha256(bytes, expectedSha256, label);
+}
+
+function verifyPostgresIdentity(
+  manifest: WasixAssetManifest,
+  seedMajor: number,
+  pgVersionBytes: Uint8Array | undefined,
+): void {
+  if (pgVersionBytes === undefined) {
+    throw new Error('WASIX cluster seed is missing PG_VERSION');
+  }
+  const pgVersion = decodeUtf8(pgVersionBytes).trim();
+  const runtimeMajor = manifest.runtime['postgres-version'].split('.')[0];
+  if (pgVersion !== runtimeMajor || pgVersion !== String(seedMajor)) {
+    throw new Error(
+      `WASIX runtime/cluster seed PostgreSQL major mismatch: runtime ${runtimeMajor}, seed ${seedMajor}, PG_VERSION ${pgVersion}`,
+    );
+  }
+}
+
+function decodeUtf8(bytes: Uint8Array): string {
+  const input =
+    typeof SharedArrayBuffer !== 'undefined' && bytes.buffer instanceof SharedArrayBuffer
+      ? Uint8Array.from(bytes)
+      : bytes;
+  return decoder.decode(input);
+}
+
+/** @internal Shared verification for separately carried WASIX tool modules. */
+export async function assertSha256(
+  bytes: Uint8Array,
+  expected: string,
+  label: string,
+): Promise {
+  if (globalThis.crypto?.subtle === undefined) {
+    throw new Error(`Web Crypto is required to verify ${label}`);
+  }
+  const actual = await sha256Hex(bytes);
+  if (actual !== expected) {
+    throw new Error(`${label} SHA-256 mismatch: expected ${expected}, received ${actual}`);
+  }
+}
+
+async function sha256Hex(bytes: Uint8Array): Promise {
+  if (globalThis.crypto?.subtle === undefined) {
+    throw new Error('Web Crypto is required to calculate SHA-256');
+  }
+  const source =
+    bytes.buffer instanceof ArrayBuffer
+      ? new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength)
+      : bytes.slice().buffer;
+  const digest = new Uint8Array(await globalThis.crypto.subtle.digest('SHA-256', source));
+  return [...digest].map((byte) => byte.toString(16).padStart(2, '0')).join('');
+}
+
+function extensionMountTarget(
+  path: string,
+  sqlName: string,
+  directory = false,
+): { mountPath: '/lib' | '/share'; relative: string } {
+  const allowed = [
+    'lib/postgresql/',
+    'share/proj/',
+    'share/postgresql/extension/',
+    'share/postgresql/tsearch_data/',
+  ];
+  const allowedDirectory = new Set([
+    'lib/postgresql',
+    'share/proj',
+    'share/postgresql',
+    'share/postgresql/extension',
+    'share/postgresql/tsearch_data',
+  ]);
+  if (
+    !allowed.some((prefix) => path.startsWith(prefix)) &&
+    !(directory && allowedDirectory.has(path))
+  ) {
+    throw new Error(`WASIX extension '${sqlName}' contains non-canonical install path ${path}`);
+  }
+  const slash = path.indexOf('/');
+  return {
+    mountPath: path.slice(0, slash) === 'lib' ? '/lib' : '/share',
+    relative: path.slice(slash + 1),
+  };
+}
+
+function appendCsv(value: string | undefined, ordered: string[], seen: Set): void {
+  for (const item of value?.split(',') ?? []) {
+    const trimmed = item.trim();
+    if (trimmed.length > 0 && !seen.has(trimmed)) {
+      seen.add(trimmed);
+      ordered.push(trimmed);
+    }
+  }
+}
+
+function requireObject(value: unknown, label: string): Record {
+  if (value === null || typeof value !== 'object' || Array.isArray(value)) {
+    throw new Error(`${label} must be an object`);
+  }
+  return value as Record;
+}
+
+function requireArray(value: unknown, label: string): unknown[] {
+  if (!Array.isArray(value)) {
+    throw new Error(`${label} must be an array`);
+  }
+  return value;
+}
+
+function requireExactKeys(
+  value: Record,
+  expected: readonly string[],
+  label: string,
+): void {
+  const actual = Object.keys(value).sort();
+  const canonical = [...expected].sort();
+  if (actual.length !== canonical.length || actual.some((key, index) => key !== canonical[index])) {
+    const missing = canonical.filter((key) => !Object.hasOwn(value, key));
+    const unexpected = actual.filter((key) => !canonical.includes(key));
+    throw new Error(
+      `${label} fields do not match the contract` +
+        `${missing.length > 0 ? `; missing ${missing.join(', ')}` : ''}` +
+        `${unexpected.length > 0 ? `; unexpected ${unexpected.join(', ')}` : ''}`,
+    );
+  }
+}
+
+function requireStringArray(value: unknown, label: string): string[] {
+  const values = requireArray(value, label);
+  return values.map((entry, index) => requireString(entry, `${label} entry ${index}`));
+}
+
+function requireString(value: unknown, label: string): string {
+  if (typeof value !== 'string' || value.length === 0 || value.includes('\0')) {
+    throw new Error(`${label} must be a non-empty string without NUL bytes`);
+  }
+  return value;
+}
+
+function requireSqlName(value: unknown, label: string): string {
+  const name = requireString(value, label);
+  if (!SQL_NAME.test(name)) {
+    throw new Error(`${label} must be a portable PostgreSQL extension name`);
+  }
+  return name;
+}
+
+function requireSha256(value: unknown, label: string): string {
+  const hash = requireString(value, `${label} SHA-256`);
+  if (!SHA256.test(hash)) {
+    throw new Error(`${label} SHA-256 must be 64 lowercase hexadecimal characters`);
+  }
+  return hash;
+}
+
+function requireSafeInteger(value: unknown, label: string): number {
+  if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
+    throw new Error(`${label} must be a non-negative safe integer`);
+  }
+  return value;
+}
+
+function requirePositiveInteger(value: unknown, label: string): number {
+  const integer = requireSafeInteger(value, label);
+  if (integer === 0) throw new Error(`${label} must be positive`);
+  return integer;
+}
+
+function requireAssetPath(value: unknown, label: string): string {
+  const path = requireString(value, label);
+  const segments = path.replaceAll('\\', '/').split('/');
+  if (
+    path.startsWith('/') ||
+    path.includes('\\') ||
+    segments.some((segment) => segment.length === 0 || segment === '.' || segment === '..')
+  ) {
+    throw new Error(`${label} must be a safe relative asset path`);
+  }
+  return path;
+}
+
+function requireInstallPath(value: unknown, label: string): string {
+  const path = requireAssetPath(value, label);
+  extensionMountTarget(path, label);
+  return path;
+}
+
+function describeError(error: unknown): string {
+  return error instanceof Error ? error.message : String(error);
+}
diff --git a/src/bindings/wasix-ts/src/host-runtime.ts b/src/sdks/ts-wasix/sdk/src/host-runtime.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/host-runtime.ts
rename to src/sdks/ts-wasix/sdk/src/host-runtime.ts
diff --git a/src/bindings/wasix-ts/src/host/index.d.mts b/src/sdks/ts-wasix/sdk/src/host/index.d.mts
similarity index 99%
rename from src/bindings/wasix-ts/src/host/index.d.mts
rename to src/sdks/ts-wasix/sdk/src/host/index.d.mts
index e198315e7..114cbecbc 100644
--- a/src/bindings/wasix-ts/src/host/index.d.mts
+++ b/src/sdks/ts-wasix/sdk/src/host/index.d.mts
@@ -14,7 +14,7 @@ export type OliphauntToolOutput = Readonly<{
 }>;
 
 export type DirectoryEntry = Readonly<{
-  type: "dir" | "file" | "unknown";
+  type: 'dir' | 'file' | 'unknown';
   name: string;
 }>;
 
diff --git a/src/sdks/ts-wasix/sdk/src/icu-descriptor.ts b/src/sdks/ts-wasix/sdk/src/icu-descriptor.ts
new file mode 100644
index 000000000..fd1947d93
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/icu-descriptor.ts
@@ -0,0 +1,24 @@
+import {
+  requireAssetSource,
+  requireExactObject,
+  serializeAssetSource,
+} from './descriptor-validation.js';
+import type { SerializedIcuDescriptor, SerializedSeed } from './rpc.js';
+
+function source(value: unknown, label: string) {
+  const size = value instanceof Uint8Array || value instanceof ArrayBuffer ? value.byteLength : 0;
+  return serializeAssetSource(requireAssetSource(value, label, size));
+}
+
+export function serializeWasixIcuDescriptor(value: unknown): SerializedIcuDescriptor {
+  const data = requireExactObject(value, ['data', 'manifest'], 'ICU data');
+  return { data: source(data.data, 'ICU data'), manifest: source(data.manifest, 'ICU manifest') };
+}
+
+export function serializeWasixSeed(value: unknown): SerializedSeed {
+  const seed = requireExactObject(value, ['archive', 'manifest'], 'WASIX seed');
+  return {
+    archive: source(seed.archive, 'seed archive'),
+    manifest: source(seed.manifest, 'seed manifest'),
+  };
+}
diff --git a/src/sdks/ts-wasix/sdk/src/index.bun.ts b/src/sdks/ts-wasix/sdk/src/index.bun.ts
new file mode 100644
index 000000000..cf96e1e49
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/index.bun.ts
@@ -0,0 +1,2 @@
+export { Oliphaunt, Oliphaunt as default } from './node-client.js';
+export * from './native-public.js';
diff --git a/src/sdks/ts-wasix/sdk/src/index.deno.ts b/src/sdks/ts-wasix/sdk/src/index.deno.ts
new file mode 100644
index 000000000..cf96e1e49
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/index.deno.ts
@@ -0,0 +1,2 @@
+export { Oliphaunt, Oliphaunt as default } from './node-client.js';
+export * from './native-public.js';
diff --git a/src/sdks/ts-wasix/sdk/src/index.node.ts b/src/sdks/ts-wasix/sdk/src/index.node.ts
new file mode 100644
index 000000000..cf96e1e49
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/index.node.ts
@@ -0,0 +1,2 @@
+export { Oliphaunt, Oliphaunt as default } from './node-client.js';
+export * from './native-public.js';
diff --git a/src/sdks/ts-wasix/sdk/src/index.ts b/src/sdks/ts-wasix/sdk/src/index.ts
new file mode 100644
index 000000000..7d46b25cf
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/index.ts
@@ -0,0 +1,2 @@
+export { Oliphaunt, Oliphaunt as default } from './client.js';
+export * from './browser-public.js';
diff --git a/src/bindings/wasix-ts/src/internal-common.ts b/src/sdks/ts-wasix/sdk/src/internal-common.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/internal-common.ts
rename to src/sdks/ts-wasix/sdk/src/internal-common.ts
diff --git a/src/bindings/wasix-ts/src/internal.node.ts b/src/sdks/ts-wasix/sdk/src/internal.node.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/internal.node.ts
rename to src/sdks/ts-wasix/sdk/src/internal.node.ts
diff --git a/src/sdks/ts-wasix/sdk/src/internal.ts b/src/sdks/ts-wasix/sdk/src/internal.ts
new file mode 100644
index 000000000..9aee650f4
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/internal.ts
@@ -0,0 +1,85 @@
+import type { OliphauntDatabase } from './types.js';
+import {
+  runWasixToolProcess as runTool,
+  type WasixToolProcessOptions,
+  type WasixToolProcessResult,
+  type WasixToolWorkerPort,
+} from './internal-common.js';
+import type { WasixToolWorkerRequest, WasixToolWorkerResponse } from './tool-worker-common.js';
+
+import { getWasixDatabaseIdentity } from './database.js';
+export { getWasixDatabaseIdentity } from './database.js';
+
+export type {
+  WasixToolDescriptor,
+  WasixToolProcessOptions,
+  WasixToolProcessResult,
+} from './internal-common.js';
+
+export function runWasixToolProcess(
+  database: OliphauntDatabase,
+  options: WasixToolProcessOptions,
+): Promise {
+  const identity = getWasixDatabaseIdentity(database);
+  const managed =
+    options.tool.name === 'pg_dump'
+      ? ['--encoding=UTF8', '--no-password']
+      : ['--no-psqlrc', '--no-password', '--set=ON_ERROR_STOP=1'];
+  return runTool(
+    database,
+    {
+      ...options,
+      args: [
+        ...options.args,
+        ...managed,
+        `--username=${identity.username}`,
+        '--host=127.0.0.1',
+        '--port=65432',
+        `--dbname=${identity.database}`,
+        ...(options.command !== undefined
+          ? ['--command', options.command]
+          : options.stdin !== undefined
+            ? ['--file=-']
+            : []),
+      ],
+    },
+    createBrowserToolWorker,
+  );
+}
+
+function createBrowserToolWorker(): WasixToolWorkerPort {
+  if (typeof Worker === 'undefined') {
+    throw new Error('WASIX tools require Web Workers');
+  }
+  const worker = new Worker(new URL('./tool-worker.js', import.meta.url), {
+    type: 'module',
+    name: 'oliphaunt-wasix-tool',
+  });
+  let messageListener: ((response: WasixToolWorkerResponse) => void) | undefined;
+  let fatalListener: ((error: Error) => void) | undefined;
+  let fatalDelivered = false;
+  worker.addEventListener('message', (event: MessageEvent) => {
+    messageListener?.(event.data);
+  });
+  worker.addEventListener('error', (event) => {
+    if (fatalDelivered) return;
+    fatalDelivered = true;
+    fatalListener?.(new Error(event.message || 'Oliphaunt WASIX tool worker crashed'));
+  });
+  worker.addEventListener('messageerror', () => {
+    if (fatalDelivered) return;
+    fatalDelivered = true;
+    fatalListener?.(new Error('Oliphaunt WASIX tool worker returned an unreadable response'));
+  });
+  return {
+    postMessage: (request: WasixToolWorkerRequest, transfer: ArrayBuffer[] = []) =>
+      worker.postMessage(request, transfer),
+    onMessage: (listener) => {
+      messageListener = listener;
+    },
+    onFatal: (listener) => {
+      fatalListener = listener;
+    },
+    terminate: () => worker.terminate(),
+  };
+}
diff --git a/src/bindings/wasix-ts/src/native-addon.ts b/src/sdks/ts-wasix/sdk/src/native-addon.ts
similarity index 94%
rename from src/bindings/wasix-ts/src/native-addon.ts
rename to src/sdks/ts-wasix/sdk/src/native-addon.ts
index e36f35b95..910ee812c 100644
--- a/src/bindings/wasix-ts/src/native-addon.ts
+++ b/src/sdks/ts-wasix/sdk/src/native-addon.ts
@@ -17,6 +17,8 @@ export type NativeWasixOpenOptions = Readonly<{
   database: string;
   startupGucs: Record;
   extensions: string[];
+  seed?: { archive: Uint8Array; manifest: Uint8Array };
+  icuData?: { data: Uint8Array; manifest: Uint8Array };
 }>;
 
 export type NativeWasixServerListen =
@@ -34,8 +36,13 @@ export type NativeWasixDatabaseHandle = {
     onChunk: (chunk: Uint8Array) => void,
   ): 'complete' | 'callbackAborted';
   backup(): Uint8Array;
-  pgDump(args: string[]): NativeWasixToolResult;
-  psql(args: string[], command?: string, script?: string): NativeWasixToolResult;
+  pgDump(args: readonly string[], assets: NativeWasixToolAssets): NativeWasixToolResult;
+  psql(
+    args: readonly string[],
+    assets: NativeWasixToolAssets,
+    command?: string,
+    script?: string,
+  ): NativeWasixToolResult;
   close(): void;
 };
 
@@ -47,8 +54,13 @@ export type NativeWasixActorDatabaseHandle = {
     onChunk: (chunk: Uint8Array) => void,
   ): Promise<'complete' | 'callbackAborted'>;
   backup(): Promise;
-  pgDump(args: string[]): Promise;
-  psql(args: string[], command?: string, script?: string): Promise;
+  pgDump(args: readonly string[], assets: NativeWasixToolAssets): Promise;
+  psql(
+    args: readonly string[],
+    assets: NativeWasixToolAssets,
+    command?: string,
+    script?: string,
+  ): Promise;
   close(): Promise;
 };
 
@@ -58,6 +70,12 @@ export type NativeWasixToolResult = Readonly<{
   stderr: Uint8Array;
 }>;
 
+export type NativeWasixToolAssets = Readonly<{
+  wasm: Uint8Array;
+  aot: Uint8Array;
+  manifest: string;
+}>;
+
 export type NativeWasixServerHandle = {
   readonly connectionString: string;
   readonly closed: boolean;
@@ -83,17 +101,8 @@ export type NativeWasixAddon = {
   nodeApiVersion(): number;
   runtimeVersion(): string;
   supportedProfiles(): readonly NativeProfile[];
-  payloadIdentity(
-    component:
-      | 'runtimeArchive'
-      | 'standardSeedArchive'
-      | 'standardSeedManifest'
-      | 'icuDataArchive'
-      | 'icuSeedArchive'
-      | 'icuSeedManifest',
-  ): string;
+  payloadIdentity(component: 'runtimeArchive'): string;
   extensionIdentity(sqlName: string): string;
-  toolIdentity(name: 'pg_dump' | 'psql'): string;
 };
 
 type WasixPackageMetadata = Readonly<{
@@ -361,13 +370,12 @@ export function validateNativeWasixAddon(
     typeof addon.runtimeVersion !== 'function' ||
     typeof addon.supportedProfiles !== 'function' ||
     typeof addon.payloadIdentity !== 'function' ||
-    typeof addon.extensionIdentity !== 'function' ||
-    typeof addon.toolIdentity !== 'function'
+    typeof addon.extensionIdentity !== 'function'
   ) {
     throw new Error(`Oliphaunt WASIX native addon ${path} has an invalid export surface`);
   }
   const expectedAbi = metadata.oliphaunt?.wasixAddonAbiVersion;
-  if (expectedAbi !== 1 || addon.addonAbiVersion() !== expectedAbi) {
+  if (expectedAbi !== 2 || addon.addonAbiVersion() !== expectedAbi) {
     throw new Error(`Oliphaunt WASIX native addon ${path} has an incompatible addon ABI`);
   }
   const expectedNodeApi = metadata.oliphaunt?.nodeApiVersion;
diff --git a/src/sdks/ts-wasix/sdk/src/native-only.ts b/src/sdks/ts-wasix/sdk/src/native-only.ts
new file mode 100644
index 000000000..1999c48b5
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/native-only.ts
@@ -0,0 +1,4 @@
+throw new Error(
+  'This @oliphaunt/wasix-ts entrypoint requires Node.js, Bun, or Deno; use @oliphaunt/wasix-ts/browser in a browser',
+);
+export {};
diff --git a/src/sdks/ts-wasix/sdk/src/native-public.ts b/src/sdks/ts-wasix/sdk/src/native-public.ts
new file mode 100644
index 000000000..1347acd3c
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/native-public.ts
@@ -0,0 +1,9 @@
+export * from './public.js';
+import type * as Types from './types.js';
+import type * as Storage from './storage.js';
+
+type StorageKind = 'memory' | 'directory';
+export type OpenConfig = Types.OpenConfig;
+export type OliphauntClient = Types.OliphauntClient;
+export type WasixStorage = Storage.WasixStorage;
+export type PersistentWasixStorage = Storage.PersistentWasixStorage>;
diff --git a/src/bindings/wasix-ts/src/native-server.ts b/src/sdks/ts-wasix/sdk/src/native-server.ts
similarity index 96%
rename from src/bindings/wasix-ts/src/native-server.ts
rename to src/sdks/ts-wasix/sdk/src/native-server.ts
index 03cc24d27..0a8ba7bbc 100644
--- a/src/bindings/wasix-ts/src/native-server.ts
+++ b/src/sdks/ts-wasix/sdk/src/native-server.ts
@@ -1,14 +1,15 @@
 import { resolve } from 'node:path';
 
-import { serializeOpenConfig } from './client-common.js';
+import { serializeOpenConfig } from './open-config.js';
 import type { NativeWasixServerHandle, NativeWasixServerListen } from './native-addon.js';
 import {
   mapNativeError,
   nativeWasixOpenOptions,
+  loadNativeResources,
   requireCompatibleNativeWasixAddon,
 } from './native-session.js';
 import { requireNodeStorage } from './node-client-common.js';
-import type { OpenConfig } from './types.js';
+import type { OpenConfig } from './native-public.js';
 
 export type ServerListen =
   | Readonly<{ transport: 'tcp'; port?: number }>
@@ -46,6 +47,7 @@ export async function openServer(config: ServerOpenConfig = {}): Promise | undefined;
 
   private constructor(
-    addon: NativeWasixAddon,
     handle: NativeWasixDatabaseHandle,
     identity: WasixDatabaseIdentity,
     runtimeVersion: string,
   ) {
-    this.#addon = addon;
     this.#handle = handle;
     this.identity = identity;
     this.#runtimeVersion = runtimeVersion;
@@ -71,10 +75,12 @@ export class NativeWasixSession implements WasixDatabaseSession {
     }
 
     try {
-      const handle = addon.NativeWasixDatabase.open(nativeOptions);
+      const handle = addon.NativeWasixDatabase.open({
+        ...nativeOptions,
+        ...(await loadNativeResources(options)),
+      });
       validateDatabaseHandle(handle);
       return new NativeWasixSession(
-        addon,
         handle,
         normalizeWasixDatabaseIdentity(options.username, options.database),
         options.runtime.version,
@@ -135,30 +141,20 @@ export class NativeWasixSession implements WasixDatabaseSession {
 
   async runTool(options: WasixToolProcessOptions): Promise {
     this.#assertOpen();
-    if (options.runtimeVersion !== '' && options.runtimeVersion !== this.#runtimeVersion) {
-      throw new Error(
-        `WASIX tools runtime ${options.runtimeVersion} is incompatible with database runtime ${this.#runtimeVersion}`,
-      );
-    }
-    validateWasixToolDescriptor(options.tool);
-    const expectedIdentity = `${options.tool.sha256}:${options.tool.size}`;
-    if (this.#addon.toolIdentity(options.tool.name) !== expectedIdentity) {
-      throw new Error(
-        `WASIX ${options.tool.name} descriptor does not match the tool embedded in the native addon`,
-      );
-    }
+    const assets = await loadNativeToolAssets(this.#runtimeVersion, options);
     if (options.tool.name === 'pg_dump') {
       try {
-        return toolProcessResult(
-          this.#handle.pgDump(userPgDumpArguments(options.args, this.identity)),
-        );
+        return toolProcessResult(this.#handle.pgDump(options.args, assets));
       } catch (error) {
         throw this.#mapFailure(error);
       }
     }
-    const parsed = userPsqlArguments(options.args, options.stdin, this.identity);
+    const script =
+      options.stdin === undefined
+        ? undefined
+        : new TextDecoder('utf-8', { fatal: true }).decode(options.stdin);
     try {
-      return toolProcessResult(this.#handle.psql(parsed.args, parsed.command, parsed.script));
+      return toolProcessResult(this.#handle.psql(options.args, assets, options.command, script));
     } catch (error) {
       throw this.#mapFailure(error);
     }
@@ -198,19 +194,16 @@ export class NativeWasixSession implements WasixDatabaseSession {
 export class NativeWasixActorSession implements WasixDatabaseSession {
   readonly identity: WasixDatabaseIdentity;
   readonly terminalState: NativeHandleTerminalState;
-  readonly #addon: NativeWasixAddon;
   readonly #handle: NativeWasixActorDatabaseHandle;
   readonly #runtimeVersion: string;
   #closed = false;
   #closeAttempt: Promise | undefined;
 
   private constructor(
-    addon: NativeWasixAddon,
     handle: NativeWasixActorDatabaseHandle,
     identity: WasixDatabaseIdentity,
     runtimeVersion: string,
   ) {
-    this.#addon = addon;
     this.#handle = handle;
     this.identity = identity;
     this.#runtimeVersion = runtimeVersion;
@@ -223,12 +216,12 @@ export class NativeWasixActorSession implements WasixDatabaseSession {
   static async open(options: SerializedOpenOptions): Promise {
     const addon = requireCompatibleNativeWasixAddon(options);
     try {
-      const handle = await addon.NativeWasixActorDatabase.open(
-        nativeWasixOpenOptions(options, nativeStorage(options)),
-      );
+      const handle = await addon.NativeWasixActorDatabase.open({
+        ...nativeWasixOpenOptions(options, nativeStorage(options)),
+        ...(await loadNativeResources(options)),
+      });
       validateActorDatabaseHandle(handle);
       return new NativeWasixActorSession(
-        addon,
         handle,
         normalizeWasixDatabaseIdentity(options.username, options.database),
         options.runtime.version,
@@ -285,15 +278,18 @@ export class NativeWasixActorSession implements WasixDatabaseSession {
 
   async runTool(options: WasixToolProcessOptions): Promise {
     this.#assertOpen();
-    validateNativeToolCall(this.#addon, this.#runtimeVersion, options);
+    const assets = await loadNativeToolAssets(this.#runtimeVersion, options);
     try {
       if (options.tool.name === 'pg_dump') {
-        return toolProcessResult(
-          await this.#handle.pgDump(userPgDumpArguments(options.args, this.identity)),
-        );
+        return toolProcessResult(await this.#handle.pgDump(options.args, assets));
       }
-      const parsed = userPsqlArguments(options.args, options.stdin, this.identity);
-      return toolProcessResult(await this.#handle.psql(parsed.args, parsed.command, parsed.script));
+      const script =
+        options.stdin === undefined
+          ? undefined
+          : new TextDecoder('utf-8', { fatal: true }).decode(options.stdin);
+      return toolProcessResult(
+        await this.#handle.psql(options.args, assets, options.command, script),
+      );
     } catch (error) {
       throw this.#mapFailure(error);
     }
@@ -447,50 +443,12 @@ export function requireCompatibleNativeWasixAddon(
       `WASIX runtime ${options.runtime.version} is incompatible with native runtime ${addon.runtimeVersion()}`,
     );
   }
-  if (
-    options.icu !== undefined &&
-    options.icu.compatibility.runtimeVersion !== options.runtime.version
-  ) {
-    throw new Error('WASIX ICU descriptor is incompatible with the selected native runtime');
-  }
   requireEmbeddedPayloadIdentity(
     addon,
     'runtimeArchive',
     options.runtime.runtimeArchive,
     'runtime archive',
   );
-  requireEmbeddedPayloadIdentity(
-    addon,
-    'standardSeedArchive',
-    options.runtime.standardSeedArchive,
-    'standard cluster seed archive',
-  );
-  requireEmbeddedPayloadIdentity(
-    addon,
-    'standardSeedManifest',
-    options.runtime.standardSeedManifest,
-    'standard cluster seed manifest',
-  );
-  if (options.icu !== undefined) {
-    requireEmbeddedPayloadIdentity(
-      addon,
-      'icuDataArchive',
-      options.icu.dataArchive,
-      'ICU data archive',
-    );
-    requireEmbeddedPayloadIdentity(
-      addon,
-      'icuSeedArchive',
-      options.icu.clusterSeedArchive,
-      'ICU cluster seed archive',
-    );
-    requireEmbeddedPayloadIdentity(
-      addon,
-      'icuSeedManifest',
-      options.icu.clusterSeedManifest,
-      'ICU cluster seed manifest',
-    );
-  }
   for (const [sqlName, carrier] of Object.entries(options.extensionCarriers)) {
     if (carrier.sqlName !== sqlName) {
       throw new Error(`WASIX extension carrier key ${sqlName} does not match ${carrier.sqlName}`);
@@ -516,6 +474,19 @@ function requireEmbeddedPayloadIdentity(
   }
 }
 
+export async function loadNativeResources(options: SerializedOpenOptions) {
+  const [seed, icuData] = await Promise.all([
+    options.seed === undefined ? undefined : loadSeedBytes(options.seed),
+    options.icu === undefined ? undefined : loadIcuData(options.icu),
+  ]);
+  return {
+    ...(seed === undefined ? {} : { seed }),
+    ...(icuData === undefined
+      ? {}
+      : { icuData: { data: icuData.data, manifest: icuData.manifest } }),
+  };
+}
+
 /** @internal Project already-validated TS config onto the narrow native ABI. */
 export function nativeWasixOpenOptions(
   options: SerializedOpenOptions,
@@ -541,23 +512,26 @@ function nativeStorage(options: SerializedOpenOptions): NativeWasixOpenOptions['
   throw new TypeError(`@oliphaunt/wasix-ts ${provider} storage is browser-only`);
 }
 
-function validateNativeToolCall(
-  addon: NativeWasixAddon,
+async function loadNativeToolAssets(
   runtimeVersion: string,
   options: WasixToolProcessOptions,
-): void {
+): Promise {
   if (options.runtimeVersion !== '' && options.runtimeVersion !== runtimeVersion) {
     throw new Error(
       `WASIX tools runtime ${options.runtimeVersion} is incompatible with database runtime ${runtimeVersion}`,
     );
   }
   validateWasixToolDescriptor(options.tool);
-  const expectedIdentity = `${options.tool.sha256}:${options.tool.size}`;
-  if (addon.toolIdentity(options.tool.name) !== expectedIdentity) {
-    throw new Error(
-      `WASIX ${options.tool.name} descriptor does not match the tool embedded in the native addon`,
-    );
-  }
+  if (!options.tool.aot)
+    throw new Error('WASIX native tools require the installed target AOT carrier');
+  const [wasm, aot, manifest] = await Promise.all([
+    loadAsset(options.tool.source, 'WASIX tool module'),
+    loadAsset(options.tool.aot.source, 'WASIX tool AOT'),
+    loadAsset(options.tool.aot.manifest, 'WASIX tools AOT manifest'),
+  ]);
+  if (wasm.length !== options.tool.size) throw new Error('WASIX tool module size mismatch');
+  await assertSha256(wasm, options.tool.sha256, 'WASIX tool module');
+  return { wasm, aot, manifest: new TextDecoder('utf-8', { fatal: true }).decode(manifest) };
 }
 
 function validateDatabaseHandle(handle: NativeWasixDatabaseHandle): void {
@@ -614,70 +588,6 @@ function toolProcessResult(result: NativeWasixToolResult): WasixToolProcessResul
   };
 }
 
-function userPgDumpArguments(args: readonly string[], identity: WasixDatabaseIdentity): string[] {
-  const suffix = [
-    '--encoding=UTF8',
-    '--no-password',
-    `--username=${identity.username}`,
-    '--host=127.0.0.1',
-    '--port=65432',
-    `--dbname=${identity.database}`,
-  ];
-  return stripManagedSuffix('pg_dump', args, suffix);
-}
-
-function userPsqlArguments(
-  args: readonly string[],
-  stdin: Uint8Array | undefined,
-  identity: WasixDatabaseIdentity,
-): Readonly<{ args: string[]; command?: string; script?: string }> {
-  const managed = [
-    '--no-psqlrc',
-    '--no-password',
-    '--set=ON_ERROR_STOP=1',
-    `--username=${identity.username}`,
-    '--host=127.0.0.1',
-    '--port=65432',
-    `--dbname=${identity.database}`,
-  ];
-  const start = findExactSequence(args, managed);
-  if (start < 0) throw new Error('Oliphaunt WASIX psql call has an invalid managed argument set');
-  const user = args.slice(0, start);
-  const input = args.slice(start + managed.length);
-  if (input.length === 0) return { args: user };
-  if (input.length === 2 && input[0] === '--command' && input[1] !== undefined) {
-    return { args: user, command: input[1] };
-  }
-  if (input.length === 1 && input[0] === '--file=-' && stdin !== undefined) {
-    return {
-      args: user,
-      script: new TextDecoder('utf-8', { fatal: true }).decode(stdin),
-    };
-  }
-  throw new Error('Oliphaunt WASIX psql call has invalid managed input arguments');
-}
-
-function stripManagedSuffix(
-  tool: string,
-  args: readonly string[],
-  suffix: readonly string[],
-): string[] {
-  if (
-    args.length < suffix.length ||
-    !suffix.every((argument, index) => args[args.length - suffix.length + index] === argument)
-  ) {
-    throw new Error(`Oliphaunt WASIX ${tool} call has an invalid managed argument set`);
-  }
-  return args.slice(0, -suffix.length);
-}
-
-function findExactSequence(values: readonly string[], expected: readonly string[]): number {
-  for (let start = values.length - expected.length; start >= 0; start -= 1) {
-    if (expected.every((value, offset) => values[start + offset] === value)) return start;
-  }
-  return -1;
-}
-
 /** @internal Translate only the exact tagged native storage contract. */
 export function mapNativeError(error: unknown): unknown {
   if (error instanceof WasixStorageError) return error;
@@ -724,7 +634,7 @@ function nativeStorageError(error: unknown): NativeStorageError | undefined {
   const candidate = error as Record;
   if (
     candidate.oliphauntWasixError !== 'storage' ||
-    candidate.oliphauntWasixAddonAbi !== 1 ||
+    candidate.oliphauntWasixAddonAbi !== 2 ||
     !memberOf(candidate.code, STORAGE_CODES) ||
     !memberOf(candidate.commitState, STORAGE_COMMIT_STATES) ||
     !memberOf(candidate.phase, STORAGE_PHASES)
diff --git a/src/bindings/wasix-ts/src/node-actor.ts b/src/sdks/ts-wasix/sdk/src/node-actor.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/node-actor.ts
rename to src/sdks/ts-wasix/sdk/src/node-actor.ts
diff --git a/src/bindings/wasix-ts/src/node-client-common.ts b/src/sdks/ts-wasix/sdk/src/node-client-common.ts
similarity index 90%
rename from src/bindings/wasix-ts/src/node-client-common.ts
rename to src/sdks/ts-wasix/sdk/src/node-client-common.ts
index 03c2a9fb4..e5da6dc8b 100644
--- a/src/bindings/wasix-ts/src/node-client-common.ts
+++ b/src/sdks/ts-wasix/sdk/src/node-client-common.ts
@@ -1,7 +1,7 @@
 import { isAbsolute, resolve } from 'node:path';
 import { fileURLToPath } from 'node:url';
 
-import { serializeOpenConfig } from './client-common.js';
+import { serializeOpenConfig } from './open-config.js';
 import { hostRuntime } from './host-runtime.js';
 import { restoreNativeWasix, restoreNativeWasixDirect } from './native-session.js';
 import { toUint8Array } from './query.js';
@@ -16,7 +16,7 @@ export async function restoreNodeWasix(
 ): Promise {
   const options = serializeOpenConfig({ storage });
   requireNodeStorage(options);
-  return restoreNativeWasix(options, toUint8Array(bytes).slice());
+  return restoreNativeWasix(options, toUint8Array(bytes));
 }
 
 /** @internal Restore synchronously in the importing realm for `/direct`. */
@@ -26,7 +26,7 @@ export async function restoreNodeWasixDirect(
 ): Promise {
   const options = serializeOpenConfig({ storage });
   requireNodeStorage(options);
-  return restoreNativeWasixDirect(options, toUint8Array(bytes).slice());
+  return restoreNativeWasixDirect(options, toUint8Array(bytes));
 }
 
 /** @internal Validate and normalize storage shared by direct and Worker entrypoints. */
diff --git a/src/bindings/wasix-ts/src/node-client.ts b/src/sdks/ts-wasix/sdk/src/node-client.ts
similarity index 87%
rename from src/bindings/wasix-ts/src/node-client.ts
rename to src/sdks/ts-wasix/sdk/src/node-client.ts
index 443092ac9..435987b3a 100644
--- a/src/bindings/wasix-ts/src/node-client.ts
+++ b/src/sdks/ts-wasix/sdk/src/node-client.ts
@@ -1,7 +1,7 @@
-import { serializeOpenConfig } from './client-common.js';
+import { serializeOpenConfig } from './open-config.js';
 import { requireNodeStorage, restoreNodeWasix } from './node-client-common.js';
 import { openNodeActor } from './node-actor.js';
-import type { OliphauntClient, OliphauntDatabase, OpenConfig } from './types.js';
+import type { OliphauntClient, OliphauntDatabase, OpenConfig } from './native-public.js';
 
 /** Open PostgreSQL on a dedicated Rust owner while keeping the caller event loop responsive. */
 export async function openWasix(config: OpenConfig = {}): Promise {
diff --git a/src/bindings/wasix-ts/src/node-direct.ts b/src/sdks/ts-wasix/sdk/src/node-direct.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/node-direct.ts
rename to src/sdks/ts-wasix/sdk/src/node-direct.ts
diff --git a/src/bindings/wasix-ts/src/node-worker-options.ts b/src/sdks/ts-wasix/sdk/src/node-worker-options.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/node-worker-options.ts
rename to src/sdks/ts-wasix/sdk/src/node-worker-options.ts
diff --git a/src/bindings/wasix-ts/src/node-worker-port.ts b/src/sdks/ts-wasix/sdk/src/node-worker-port.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/node-worker-port.ts
rename to src/sdks/ts-wasix/sdk/src/node-worker-port.ts
diff --git a/src/bindings/wasix-ts/src/node-worker.ts b/src/sdks/ts-wasix/sdk/src/node-worker.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/node-worker.ts
rename to src/sdks/ts-wasix/sdk/src/node-worker.ts
diff --git a/src/sdks/ts-wasix/sdk/src/open-config.ts b/src/sdks/ts-wasix/sdk/src/open-config.ts
new file mode 100644
index 000000000..ff207d02a
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/open-config.ts
@@ -0,0 +1,38 @@
+import defaultWasixRuntime from '@oliphaunt/liboliphaunt-wasix';
+
+import { serializeWasixExtensionDescriptors } from './extension-descriptor.js';
+import { serializeWasixIcuDescriptor, serializeWasixSeed } from './icu-descriptor.js';
+import type { SerializedOpenOptions } from './rpc.js';
+import { serializeWasixRuntimeDescriptor } from './runtime-descriptor.js';
+import { serializeWasixStorage } from './storage.js';
+import { normalizeWasixStartupGUCs } from './startup-config.js';
+import type { OpenConfig, WasixRuntimeDescriptor } from './types.js';
+
+export function serializeOpenConfig(
+  config: OpenConfig = {},
+  runtimeDescriptor: WasixRuntimeDescriptor = defaultWasixRuntime,
+): SerializedOpenOptions {
+  const extensions = serializeWasixExtensionDescriptors(config.extensions ?? []);
+  const runtime = serializeWasixRuntimeDescriptor(runtimeDescriptor);
+  const storage = serializeWasixStorage(config.storage);
+  return {
+    runtime,
+    ...(config.seed === undefined ? {} : { seed: serializeWasixSeed(config.seed) }),
+    ...(config.icu === undefined ? {} : { icu: serializeWasixIcuDescriptor(config.icu) }),
+    extensionCarriers: extensions.carriers,
+    extensions: extensions.selectedSqlNames,
+    username: config.username ?? 'postgres',
+    database: config.database ?? 'postgres',
+    startupGUCs: normalizeWasixStartupGUCs(config.startupGUCs ?? {}),
+    storage,
+  };
+}
+
+/** Reject unsupported browser storage before loading an engine or starting a worker. */
+export function requireBrowserStorage(options: SerializedOpenOptions): void {
+  if (options.storage.kind === 'directory') {
+    throw new TypeError(
+      '@oliphaunt/wasix-ts/browser directory storage is native-only; use memory, IndexedDB, or OPFS',
+    );
+  }
+}
diff --git a/src/bindings/wasix-ts/src/pgwire-connection.ts b/src/sdks/ts-wasix/sdk/src/pgwire-connection.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/pgwire-connection.ts
rename to src/sdks/ts-wasix/sdk/src/pgwire-connection.ts
diff --git a/src/bindings/wasix-ts/src/pgwire.ts b/src/sdks/ts-wasix/sdk/src/pgwire.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/pgwire.ts
rename to src/sdks/ts-wasix/sdk/src/pgwire.ts
diff --git a/src/bindings/wasix-ts/src/physical-archive.ts b/src/sdks/ts-wasix/sdk/src/physical-archive.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/physical-archive.ts
rename to src/sdks/ts-wasix/sdk/src/physical-archive.ts
diff --git a/src/sdks/ts-wasix/sdk/src/protocol.ts b/src/sdks/ts-wasix/sdk/src/protocol.ts
new file mode 100644
index 000000000..0fdfe840b
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/protocol.ts
@@ -0,0 +1 @@
+export * from '@oliphaunt/ts-query/protocol';
diff --git a/src/bindings/wasix-ts/src/public.ts b/src/sdks/ts-wasix/sdk/src/public.ts
similarity index 97%
rename from src/bindings/wasix-ts/src/public.ts
rename to src/sdks/ts-wasix/sdk/src/public.ts
index fc7607ec2..83a2aa0b4 100644
--- a/src/bindings/wasix-ts/src/public.ts
+++ b/src/sdks/ts-wasix/sdk/src/public.ts
@@ -53,4 +53,6 @@ export type {
   OpenConfig,
   WasixAssetSource,
   WasixExtensionDescriptor,
+  WasixSeed,
+  WasixIcuDescriptor,
 } from './types.js';
diff --git a/src/sdks/ts-wasix/sdk/src/query.ts b/src/sdks/ts-wasix/sdk/src/query.ts
new file mode 100644
index 000000000..d4b53542b
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/query.ts
@@ -0,0 +1 @@
+export * from '@oliphaunt/ts-query/query';
diff --git a/src/bindings/wasix-ts/src/rpc.ts b/src/sdks/ts-wasix/sdk/src/rpc.ts
similarity index 90%
rename from src/bindings/wasix-ts/src/rpc.ts
rename to src/sdks/ts-wasix/sdk/src/rpc.ts
index d892c2b48..34bc044f0 100644
--- a/src/bindings/wasix-ts/src/rpc.ts
+++ b/src/sdks/ts-wasix/sdk/src/rpc.ts
@@ -72,12 +72,6 @@ export type SerializedRuntimeDescriptor = {
   product: 'liboliphaunt-wasix';
   version: string;
   runtimeArchive: SerializedRuntimeArchive;
-  standardSeedArchive: SerializedRuntimeArchive;
-  standardSeedManifest: {
-    sha256: string;
-    size: number;
-    source: SerializedAssetSource;
-  };
   manifest: {
     sha256: string;
     size: number;
@@ -92,33 +86,16 @@ export type SerializedToolRuntimeDescriptor = Pick<
 >;
 
 export type SerializedIcuDescriptor = {
-  schema: 'oliphaunt-wasix-icu-v1';
-  runtime: 'wasix';
-  product: 'oliphaunt-icu';
-  version: string;
-  compatibility: {
-    runtimeProduct: 'liboliphaunt-wasix';
-    runtimeVersion: string;
-    postgresMajor: '18';
-    physicalFormat: 'wasix-pg18-v1';
-    compatibilityKey: 'wasix-pg18-datum32-v1';
-    dataVersion: '76.1';
-    dataForm: 'files-le';
-    dataTreeSha256: string;
-  };
-  dataArchive: SerializedRuntimeArchive;
-  clusterSeedArchive: SerializedRuntimeArchive;
-  clusterSeedManifest: {
-    sha256: string;
-    size: number;
-    source: SerializedAssetSource;
-  };
+  data: SerializedAssetSource;
+  manifest: SerializedAssetSource;
 };
+export type SerializedSeed = { archive: SerializedAssetSource; manifest: SerializedAssetSource };
 
 /** Host-ready open options shared by both public execution surfaces. */
 export type SerializedOpenOptions = {
   runtime: SerializedRuntimeDescriptor;
   icu?: SerializedIcuDescriptor;
+  seed?: SerializedSeed;
   /** Exact imported carrier closure, keyed by PostgreSQL SQL name. */
   extensionCarriers: Record;
   extensions: string[];
@@ -249,7 +226,7 @@ export function deserializeWorkerError(error: SerializedWorkerError): Error {
     restored.name = error.name;
     return Object.assign(restored, {
       oliphauntWasixError: 'tool' as const,
-      oliphauntWasixAddonAbi: 1 as const,
+      oliphauntWasixAddonAbi: 2 as const,
       code: error.code,
       tool: error.tool,
       exitCode: error.exitCode,
@@ -276,7 +253,7 @@ function nativeToolError(error: unknown): NativeToolError | undefined {
   const candidate = error as Record;
   if (
     candidate.oliphauntWasixError !== 'tool' ||
-    candidate.oliphauntWasixAddonAbi !== 1 ||
+    candidate.oliphauntWasixAddonAbi !== 2 ||
     candidate.code !== 'tool-error' ||
     typeof candidate.message !== 'string' ||
     typeof candidate.tool !== 'string' ||
diff --git a/src/bindings/wasix-ts/src/runtime-carrier-shim.d.ts b/src/sdks/ts-wasix/sdk/src/runtime-carrier-shim.d.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/runtime-carrier-shim.d.ts
rename to src/sdks/ts-wasix/sdk/src/runtime-carrier-shim.d.ts
diff --git a/src/bindings/wasix-ts/src/runtime-descriptor.ts b/src/sdks/ts-wasix/sdk/src/runtime-descriptor.ts
similarity index 75%
rename from src/bindings/wasix-ts/src/runtime-descriptor.ts
rename to src/sdks/ts-wasix/sdk/src/runtime-descriptor.ts
index d9a4a503d..37d931ba3 100644
--- a/src/bindings/wasix-ts/src/runtime-descriptor.ts
+++ b/src/sdks/ts-wasix/sdk/src/runtime-descriptor.ts
@@ -10,16 +10,7 @@ import {
 import type { SerializedRuntimeDescriptor } from './rpc.js';
 import type { WasixRuntimeArchive, WasixRuntimeDescriptor, WasixRuntimeManifest } from './types.js';
 
-const DESCRIPTOR_FIELDS = [
-  'manifest',
-  'product',
-  'runtime',
-  'runtimeArchive',
-  'schema',
-  'standardSeedArchive',
-  'standardSeedManifest',
-  'version',
-];
+const DESCRIPTOR_FIELDS = ['manifest', 'product', 'runtime', 'runtimeArchive', 'schema', 'version'];
 const ARCHIVE_FIELDS = ['archive', 'sha256', 'size', 'source'];
 const MANIFEST_FIELDS = ['sha256', 'size', 'source'];
 
@@ -32,8 +23,6 @@ export function serializeWasixRuntimeDescriptor(value: unknown): SerializedRunti
     product: value.product,
     version: value.version,
     runtimeArchive: serializeArchive(value.runtimeArchive),
-    standardSeedArchive: serializeArchive(value.standardSeedArchive),
-    standardSeedManifest: serializeManifest(value.standardSeedManifest),
     manifest: {
       sha256: value.manifest.sha256,
       size: value.manifest.size,
@@ -58,12 +47,7 @@ function validateRuntimeDescriptor(
   }
   requireVersion(descriptor.version, `${label} version`);
   validateArchive(descriptor.runtimeArchive, `${label} runtime archive`);
-  validateArchive(descriptor.standardSeedArchive, `${label} standard cluster seed archive`);
-  validateManifest(descriptor.standardSeedManifest, `${label} standard cluster seed manifest`);
   validateManifest(descriptor.manifest, `${label} manifest`);
-  if (descriptor.runtimeArchive.archive === descriptor.standardSeedArchive.archive) {
-    throw new Error(`${label} runtime and standard cluster seed archives must have distinct paths`);
-  }
 }
 
 function validateArchive(value: unknown, label: string): asserts value is WasixRuntimeArchive {
@@ -91,13 +75,3 @@ function serializeArchive(
     source: serializeAssetSource(archive.source),
   };
 }
-
-function serializeManifest(
-  manifest: WasixRuntimeManifest,
-): SerializedRuntimeDescriptor['manifest'] {
-  return {
-    sha256: manifest.sha256,
-    size: manifest.size,
-    source: serializeAssetSource(manifest.source),
-  };
-}
diff --git a/src/bindings/wasix-ts/src/server.node.ts b/src/sdks/ts-wasix/sdk/src/server.node.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/server.node.ts
rename to src/sdks/ts-wasix/sdk/src/server.node.ts
diff --git a/src/bindings/wasix-ts/src/startup-config.ts b/src/sdks/ts-wasix/sdk/src/startup-config.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/startup-config.ts
rename to src/sdks/ts-wasix/sdk/src/startup-config.ts
diff --git a/src/bindings/wasix-ts/src/storage-provider.ts b/src/sdks/ts-wasix/sdk/src/storage-provider.ts
similarity index 93%
rename from src/bindings/wasix-ts/src/storage-provider.ts
rename to src/sdks/ts-wasix/sdk/src/storage-provider.ts
index 7b3087d63..c640ebc45 100644
--- a/src/bindings/wasix-ts/src/storage-provider.ts
+++ b/src/sdks/ts-wasix/sdk/src/storage-provider.ts
@@ -1,26 +1,12 @@
 import type { WasixDirectoryMount } from './archive.js';
-import { DATABASE_ROOT_POSTGRES_MAJOR, WASIX_PHYSICAL_FORMAT } from './database-root.js';
+import { WASIX_PHYSICAL_IDENTITY, type WasixPhysicalIdentity } from './database-root.js';
+export { WASIX_PHYSICAL_IDENTITY, type WasixPhysicalIdentity } from './database-root.js';
 import { WasixStorageError } from './errors.js';
 import type { Directory } from './host/index.mjs';
 import type { SerializedWasixStorage } from './storage.js';
 import type { StoredSnapshot } from './storage-snapshot.js';
 import { validateIndexedDbDatabaseName, validateOpfsDatabaseName } from './storage.js';
 
-/** Stable fields that determine whether a WASIX runtime may open stored PGDATA. */
-export type WasixPhysicalIdentity = Readonly<{
-  schema: 'oliphaunt-physical-format-v1';
-  engineFamily: 'wasix';
-  postgresMajor: number;
-  physicalFormat: string;
-}>;
-
-export const WASIX_PHYSICAL_IDENTITY: WasixPhysicalIdentity = Object.freeze({
-  schema: 'oliphaunt-physical-format-v1',
-  engineFamily: 'wasix',
-  postgresMajor: DATABASE_ROOT_POSTGRES_MAJOR,
-  physicalFormat: WASIX_PHYSICAL_FORMAT,
-});
-
 export type StorageDirectoryEntry = Readonly<{
   type: 'dir' | 'file' | 'unknown';
   name: string;
diff --git a/src/bindings/wasix-ts/src/storage-snapshot.ts b/src/sdks/ts-wasix/sdk/src/storage-snapshot.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/storage-snapshot.ts
rename to src/sdks/ts-wasix/sdk/src/storage-snapshot.ts
diff --git a/src/sdks/ts-wasix/sdk/src/storage.ts b/src/sdks/ts-wasix/sdk/src/storage.ts
new file mode 100644
index 000000000..8a5569de2
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/storage.ts
@@ -0,0 +1,142 @@
+declare const storageDescriptorBrand: unique symbol;
+declare const persistentStorageDescriptorBrand: unique symbol;
+
+/**
+ * An opaque storage selection created by this package's storage factories.
+ * The descriptor is deliberately not a bag of user-authored paths or assets.
+ */
+export type WasixStorageKind = 'memory' | 'directory' | 'indexed-db' | 'opfs';
+
+export type WasixStorage = Readonly<{
+  [storageDescriptorBrand]: Kind;
+}>;
+
+/** Opaque persistent storage accepted by static physical restore. */
+export type PersistentWasixStorage<
+  Kind extends Exclude = Exclude,
+> = WasixStorage &
+  Readonly<{
+    [persistentStorageDescriptorBrand]: 'oliphaunt-wasix-persistent-storage';
+  }>;
+
+export type SerializedWasixStorage =
+  | Readonly<{
+      schema: 'oliphaunt-wasix-storage-v1';
+      kind: 'memory';
+    }>
+  | Readonly<{
+      schema: 'oliphaunt-wasix-storage-v1';
+      kind: 'indexed-db';
+      name: string;
+    }>
+  | Readonly<{
+      schema: 'oliphaunt-wasix-storage-v1';
+      kind: 'opfs';
+      name: string;
+    }>
+  | Readonly<{
+      schema: 'oliphaunt-wasix-storage-v1';
+      kind: 'directory';
+      path: string;
+    }>;
+
+const descriptorValues = new WeakMap();
+
+/**
+ * Select a fresh in-memory database. This is also the default when `storage`
+ * is omitted. Reusing the descriptor does not preserve data.
+ */
+export function memory(): WasixStorage<'memory'> {
+  return defineStorage({
+    schema: 'oliphaunt-wasix-storage-v1',
+    kind: 'memory',
+  });
+}
+
+/** @internal Used by the selectively imported IndexedDB adapter. */
+export function defineIndexedDbStorage(name: string): PersistentWasixStorage<'indexed-db'> {
+  validateIndexedDbDatabaseName(name);
+  return defineStorage({
+    schema: 'oliphaunt-wasix-storage-v1',
+    kind: 'indexed-db',
+    name,
+  }) as PersistentWasixStorage<'indexed-db'>;
+}
+
+/** @internal Used by the selectively imported OPFS adapter. */
+export function defineOpfsStorage(name: string): PersistentWasixStorage<'opfs'> {
+  validateOpfsDatabaseName(name);
+  return defineStorage({
+    schema: 'oliphaunt-wasix-storage-v1',
+    kind: 'opfs',
+    name,
+  }) as PersistentWasixStorage<'opfs'>;
+}
+
+/** @internal Used by the selectively imported Node directory adapter. */
+export function defineDirectoryStorage(path: string): PersistentWasixStorage<'directory'> {
+  validateHostDirectoryPath(path);
+  return defineStorage({
+    schema: 'oliphaunt-wasix-storage-v1',
+    kind: 'directory',
+    path,
+  }) as PersistentWasixStorage<'directory'>;
+}
+
+/** @internal Validate and project the opaque main-thread value for the worker. */
+export function serializeWasixStorage(storage: WasixStorage | undefined): SerializedWasixStorage {
+  if (storage === undefined) {
+    return { schema: 'oliphaunt-wasix-storage-v1', kind: 'memory' };
+  }
+  const value = descriptorValues.get(storage as object);
+  if (value === undefined) {
+    throw new TypeError(
+      'storage must come from @oliphaunt/wasix-ts or one of its storage adapter subpaths',
+    );
+  }
+  switch (value.kind) {
+    case 'memory':
+      return { ...value };
+    case 'indexed-db':
+      return { ...value, name: value.name };
+    case 'opfs':
+      return { ...value, name: value.name };
+    case 'directory':
+      return { ...value, path: value.path };
+  }
+}
+
+export function validateIndexedDbDatabaseName(name: unknown): asserts name is string {
+  if (typeof name !== 'string' || name.length === 0 || name.length > 200 || name.includes('\0')) {
+    throw new TypeError('IndexedDB storage name must be 1-200 characters without NUL bytes');
+  }
+}
+
+export function validateOpfsDatabaseName(name: unknown): asserts name is string {
+  if (
+    typeof name !== 'string' ||
+    name.length === 0 ||
+    name.length > 100 ||
+    name === '.' ||
+    name === '..' ||
+    !/^[A-Za-z0-9._-]+$/.test(name)
+  ) {
+    throw new TypeError(
+      'OPFS storage name must be 1-100 ASCII letters, digits, dot, dash, or underscore',
+    );
+  }
+}
+
+export function validateHostDirectoryPath(path: unknown): asserts path is string {
+  if (typeof path !== 'string' || path.length === 0 || path.includes('\0')) {
+    throw new TypeError('host directory storage path must be a non-empty string without NUL bytes');
+  }
+}
+
+function defineStorage(
+  value: Value,
+): WasixStorage {
+  const descriptor = Object.freeze({});
+  descriptorValues.set(descriptor, Object.freeze(value));
+  return descriptor as WasixStorage;
+}
diff --git a/src/bindings/wasix-ts/src/storage/bun.ts b/src/sdks/ts-wasix/sdk/src/storage/bun.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/storage/bun.ts
rename to src/sdks/ts-wasix/sdk/src/storage/bun.ts
diff --git a/src/bindings/wasix-ts/src/storage/deno.ts b/src/sdks/ts-wasix/sdk/src/storage/deno.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/storage/deno.ts
rename to src/sdks/ts-wasix/sdk/src/storage/deno.ts
diff --git a/src/bindings/wasix-ts/src/storage/incremental-storage.ts b/src/sdks/ts-wasix/sdk/src/storage/incremental-storage.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/storage/incremental-storage.ts
rename to src/sdks/ts-wasix/sdk/src/storage/incremental-storage.ts
diff --git a/src/bindings/wasix-ts/src/storage/indexed-db-provider.ts b/src/sdks/ts-wasix/sdk/src/storage/indexed-db-provider.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/storage/indexed-db-provider.ts
rename to src/sdks/ts-wasix/sdk/src/storage/indexed-db-provider.ts
diff --git a/src/bindings/wasix-ts/src/storage/indexed-db.ts b/src/sdks/ts-wasix/sdk/src/storage/indexed-db.ts
similarity index 82%
rename from src/bindings/wasix-ts/src/storage/indexed-db.ts
rename to src/sdks/ts-wasix/sdk/src/storage/indexed-db.ts
index b6ce2a195..928796c65 100644
--- a/src/bindings/wasix-ts/src/storage/indexed-db.ts
+++ b/src/sdks/ts-wasix/sdk/src/storage/indexed-db.ts
@@ -6,7 +6,7 @@ import { defineIndexedDbStorage, type PersistentWasixStorage } from '../storage.
  * Every completed protocol operation commits only journaled PGDATA path
  * changes in one atomic read-write IndexedDB transaction before its Promise resolves.
  */
-export function indexedDB(name: string): PersistentWasixStorage {
+export function indexedDB(name: string): PersistentWasixStorage<'indexed-db'> {
   return defineIndexedDbStorage(name);
 }
 
diff --git a/src/sdks/ts-wasix/sdk/src/storage/node.ts b/src/sdks/ts-wasix/sdk/src/storage/node.ts
new file mode 100644
index 000000000..8d27ebbd4
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/storage/node.ts
@@ -0,0 +1,16 @@
+import { fileURLToPath } from 'node:url';
+
+import { defineDirectoryStorage, type PersistentWasixStorage } from '../storage.js';
+
+/**
+ * Persist a managed database below a Node.js host directory.
+ *
+ * Rust opens the selected managed root directly, owns its OS advisory lock,
+ * and performs PostgreSQL-safe durable writes at each native operation
+ * boundary. Network and cross-host shared filesystems are unsupported.
+ */
+export function directory(path: string | URL): PersistentWasixStorage<'directory'> {
+  return defineDirectoryStorage(typeof path === 'string' ? path : fileURLToPath(path));
+}
+
+export default directory;
diff --git a/src/bindings/wasix-ts/src/storage/opfs-pool.ts b/src/sdks/ts-wasix/sdk/src/storage/opfs-pool.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/storage/opfs-pool.ts
rename to src/sdks/ts-wasix/sdk/src/storage/opfs-pool.ts
diff --git a/src/bindings/wasix-ts/src/storage/opfs-provider.ts b/src/sdks/ts-wasix/sdk/src/storage/opfs-provider.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/storage/opfs-provider.ts
rename to src/sdks/ts-wasix/sdk/src/storage/opfs-provider.ts
diff --git a/src/bindings/wasix-ts/src/storage/opfs.ts b/src/sdks/ts-wasix/sdk/src/storage/opfs.ts
similarity index 83%
rename from src/bindings/wasix-ts/src/storage/opfs.ts
rename to src/sdks/ts-wasix/sdk/src/storage/opfs.ts
index e86f23823..c52548fc3 100644
--- a/src/bindings/wasix-ts/src/storage/opfs.ts
+++ b/src/sdks/ts-wasix/sdk/src/storage/opfs.ts
@@ -5,7 +5,7 @@ import { defineOpfsStorage, type PersistentWasixStorage } from '../storage.js';
  * same-realm synchronous exact-range I/O; other placements publish to the
  * same format through the portable journaled path.
  */
-export function opfs(name: string): PersistentWasixStorage {
+export function opfs(name: string): PersistentWasixStorage<'opfs'> {
   return defineOpfsStorage(name);
 }
 
diff --git a/src/bindings/wasix-ts/src/storage/restore-cleanup.ts b/src/sdks/ts-wasix/sdk/src/storage/restore-cleanup.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/storage/restore-cleanup.ts
rename to src/sdks/ts-wasix/sdk/src/storage/restore-cleanup.ts
diff --git a/src/bindings/wasix-ts/src/storage/web-lock.ts b/src/sdks/ts-wasix/sdk/src/storage/web-lock.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/storage/web-lock.ts
rename to src/sdks/ts-wasix/sdk/src/storage/web-lock.ts
diff --git a/src/bindings/wasix-ts/src/tool-runtime.ts b/src/sdks/ts-wasix/sdk/src/tool-runtime.ts
similarity index 96%
rename from src/bindings/wasix-ts/src/tool-runtime.ts
rename to src/sdks/ts-wasix/sdk/src/tool-runtime.ts
index 8cecc1ac2..cee7c6774 100644
--- a/src/bindings/wasix-ts/src/tool-runtime.ts
+++ b/src/sdks/ts-wasix/sdk/src/tool-runtime.ts
@@ -8,6 +8,8 @@ export type WasixToolDescriptor = Readonly<{
   sha256: string;
   size: number;
   source: SerializedAssetSource;
+  /** Selected native target carrier; browser execution only needs source. */
+  aot?: Readonly<{ source: SerializedAssetSource; manifest: SerializedAssetSource }>;
 }>;
 
 export type WasixToolProcessOptions = Readonly<{
@@ -16,6 +18,7 @@ export type WasixToolProcessOptions = Readonly<{
   args: readonly string[];
   /** @internal An exact ArrayBuffer-backed view is transferred and consumed. */
   stdin?: Uint8Array;
+  command?: string;
 }>;
 
 export type WasixToolProcessResult = Readonly<{
diff --git a/src/bindings/wasix-ts/src/tool-worker-common.ts b/src/sdks/ts-wasix/sdk/src/tool-worker-common.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/tool-worker-common.ts
rename to src/sdks/ts-wasix/sdk/src/tool-worker-common.ts
diff --git a/src/bindings/wasix-ts/src/tool-worker.ts b/src/sdks/ts-wasix/sdk/src/tool-worker.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/tool-worker.ts
rename to src/sdks/ts-wasix/sdk/src/tool-worker.ts
diff --git a/src/sdks/ts-wasix/sdk/src/types.ts b/src/sdks/ts-wasix/sdk/src/types.ts
new file mode 100644
index 000000000..1ebee2515
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/types.ts
@@ -0,0 +1,263 @@
+import type {
+  CommandResult,
+  DescribeResult,
+  ExecResult,
+  InferQueryRow,
+  ParameterOptions,
+  QueryOptions,
+  QueryParam,
+  QueryResult,
+  RawQueryResult,
+} from './query.js';
+import type { PersistentWasixStorage, WasixStorage, WasixStorageKind } from './storage.js';
+
+type QueryReadOptions = Omit;
+
+export type BinaryInput = ArrayBuffer | ArrayBufferView | Uint8Array | ReadonlyArray;
+/** A synchronous, serial raw-protocol consumer used as the backpressure acknowledgement. */
+export type ProtocolChunkCallback = (chunk: Uint8Array) => undefined;
+
+/** A host-neutral asset reference accepted by the portable WASIX carrier contract. */
+export type WasixAssetSource = string | URL | ArrayBuffer | Uint8Array;
+
+/** One exact archive carried by the portable WASIX runtime package. */
+export type WasixRuntimeArchive = Readonly<{
+  /** Canonical path recorded by the generated runtime manifest. */
+  archive: string;
+  sha256: string;
+  size: number;
+  source: WasixAssetSource;
+}>;
+
+/** The canonical generated manifest carried alongside the runtime archives. */
+export type WasixRuntimeManifest = Readonly<{
+  sha256: string;
+  size: number;
+  source: WasixAssetSource;
+}>;
+
+/**
+ * A package-authored runtime identity. The default value comes from
+ * `@oliphaunt/liboliphaunt-wasix`; callers normally never handle it directly.
+ */
+export type WasixRuntimeDescriptor = Readonly<{
+  schema: 'oliphaunt-wasix-runtime-v2';
+  runtime: 'wasix';
+  product: 'liboliphaunt-wasix';
+  version: string;
+  runtimeArchive: WasixRuntimeArchive;
+  manifest: WasixRuntimeManifest;
+}>;
+
+/** Select one independently packaged seed for initialization of new storage. */
+export type WasixSeed = Readonly<{ archive: WasixAssetSource; manifest: WasixAssetSource }>;
+
+/** Canonical ICU data shared by native and WASIX seeds. */
+export type WasixIcuDescriptor = Readonly<{ data: WasixAssetSource; manifest: WasixAssetSource }>;
+
+export type WasixExtensionCarrier = Readonly<{
+  /** Owning Oliphaunt release product, not the PostgreSQL SQL name. */
+  product: string;
+  /** Oliphaunt product version; upstream provenance stays release/evidence metadata. */
+  version: string;
+  sqlName: string;
+  /** Exact canonical manifest archive key, for example `extensions/pgtap.tar.zst`. */
+  archive: string;
+  sha256: string;
+  size: number;
+  /** Portable archive URL or bytes. The same descriptor can be hosted by Node or a browser. */
+  source: WasixAssetSource;
+  /** Exact install contract owned by this independently versioned carrier. */
+  install: WasixExtensionInstall;
+}>;
+
+export type WasixExtensionCompatibility = Readonly<{
+  extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1';
+  postgresMajor: string;
+  wasixRuntimeProduct: 'liboliphaunt-wasix';
+  wasixRuntimeVersion: string;
+}>;
+
+export type WasixExtensionInstall = Readonly<{
+  schema: 'oliphaunt-wasix-extension-install-v1';
+  name: string;
+  nativeModule: string | null;
+  nativeModules: readonly WasixExtensionNativeModule[];
+  dependencies: readonly string[];
+  coreExportsRequired: readonly string[];
+  loadOrder: readonly string[];
+  lifecycle: WasixExtensionLifecycle;
+  installedFiles: readonly string[];
+  unresolvedImports: readonly WasixExtensionImport[];
+}>;
+
+export type WasixExtensionImport = Readonly<{
+  module: string;
+  name: string;
+  kind: string;
+}>;
+
+export type WasixExtensionNativeModule = Readonly<{
+  name: string;
+  path: string;
+  sha256: string;
+  moduleSha256: string;
+  size: number;
+}>;
+
+export type WasixExtensionDescriptorInput = Readonly<{
+  schema: 'oliphaunt-wasix-extension-v1';
+  runtime: 'wasix';
+  /** Product and version of the root carrier selected by `sqlName`. */
+  product: string;
+  version: string;
+  /** Exact WASIX runtime identity against which this descriptor was qualified. */
+  compatibility: WasixExtensionCompatibility;
+  sqlName: string;
+  /** Root carrier plus any extension carrier dependencies required by this import. */
+  carriers: readonly WasixExtensionCarrier[];
+}>;
+
+/**
+ * A package-authored, runtime-validated WASIX extension import. Applications
+ * obtain these from extension packages instead of constructing SQL strings.
+ * The schema and runtime literals discriminate it structurally, so generated
+ * carrier packages do not need a dependency on this binding.
+ */
+export type WasixExtensionDescriptor = WasixExtensionDescriptorInput;
+
+/** Lifecycle fields owned by an independently versioned extension carrier. */
+export type WasixExtensionLifecycle = {
+  createExtension: boolean;
+  createSchema: string | null;
+  loadSql: readonly string[];
+  postCreateSql: readonly string[];
+  startupConfig: readonly string[];
+  preloadRequired: boolean;
+  restartRequired: boolean;
+  sharedMemoryRequired: boolean;
+};
+
+/** Host-relevant subset of the generated liboliphaunt WASIX asset manifest. */
+export type WasixAssetManifest = {
+  'format-version': 2;
+  'source-fingerprint': string;
+  runtime: {
+    archive: string;
+    sha256: string;
+    /** Present when the canonical producer records the outer archive size. */
+    size?: number;
+    'module-sha256': string;
+    'postgres-version': string;
+    link: {
+      exports: readonly {
+        name: string;
+        kind: string;
+      }[];
+    };
+  };
+  'runtime-support': readonly {
+    name: string;
+    path: string;
+    sha256: string;
+  }[];
+  /** The core runtime carrier is intentionally extension-free. */
+  extensions: readonly [];
+};
+
+export type OpenConfig = {
+  /** Existing PostgreSQL role selected after the fixed superuser bootstrap. */
+  username?: string;
+  database?: string;
+  /** PostgreSQL `-c name=value` settings applied before the database opens. */
+  startupGUCs?: Readonly>;
+  /** Optional initializer seed. New browser storage requires an explicit seed. */
+  seed?: WasixSeed;
+  /** Optional canonical ICU data, independent of the selected seed. */
+  icu?: WasixIcuDescriptor;
+  /** Selectively imported WASIX carriers. SQL strings are intentionally not accepted. */
+  extensions?: readonly WasixExtensionDescriptor[];
+  /** Fresh memory by default, or an explicitly imported host storage adapter. */
+  storage?: WasixStorage;
+};
+
+export type OliphauntDatabase = {
+  /**
+   * True after the terminal close attempt settles, including when teardown
+   * rejects, or as soon as a package-owned isolated host terminates unexpectedly.
+   */
+  readonly closed: boolean;
+  execute(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: ParameterOptions,
+  ): Promise;
+  query(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: Options & QueryOptions,
+  ): Promise>>;
+  queryRaw(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: ParameterOptions,
+  ): Promise;
+  exec(
+    sql: string,
+    options?: Options & QueryReadOptions,
+  ): Promise>>;
+  describe(sql: string, parameterTypeOids?: ReadonlyArray): Promise;
+  execProtocolRaw(input: BinaryInput): Promise;
+  execProtocolRawStream(input: BinaryInput, onChunk: ProtocolChunkCallback): Promise;
+  /** Create a session-preserving PostgreSQL online physical backup. */
+  backup(): Promise;
+  /**
+   * Own the session for one callback. Use callback return/throw or rollback()
+   * for lifecycle; manual BEGIN/START/COMMIT/END/ABORT/PREPARE TRANSACTION and
+   * AND CHAIN are unsupported. SAVEPOINT and ROLLBACK TO are allowed.
+   */
+  transaction(body: (transaction: OliphauntTransaction) => Promise | T): Promise;
+  /**
+   * Stop admitting work and perform one terminal teardown attempt.
+   * Concurrent and later calls return the same promise. A rejection reports
+   * cleanup failure; it does not make the handle reusable. Calling from an
+   * active transaction callback rejects before teardown begins; close the
+   * database after that callback settles.
+   */
+  close(): Promise;
+  [Symbol.asyncDispose](): Promise;
+};
+
+/** A database session pinned to one callback-scoped PostgreSQL transaction. */
+export type OliphauntTransaction = {
+  readonly closed: boolean;
+  execute(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: ParameterOptions,
+  ): Promise;
+  query(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: Options & QueryOptions,
+  ): Promise>>;
+  queryRaw(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: ParameterOptions,
+  ): Promise;
+  exec(
+    sql: string,
+    options?: Options & QueryReadOptions,
+  ): Promise>>;
+  describe(sql: string, parameterTypeOids?: ReadonlyArray): Promise;
+  rollback(): Promise;
+};
+
+export type OliphauntClient = {
+  open(config?: OpenConfig): Promise;
+  restore(
+    storage: PersistentWasixStorage>,
+    bytes: BinaryInput,
+  ): Promise;
+};
diff --git a/src/bindings/wasix-ts/src/wasix-runtime.ts b/src/sdks/ts-wasix/sdk/src/wasix-runtime.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/wasix-runtime.ts
rename to src/sdks/ts-wasix/sdk/src/wasix-runtime.ts
diff --git a/src/bindings/wasix-ts/src/worker-client.ts b/src/sdks/ts-wasix/sdk/src/worker-client.ts
similarity index 81%
rename from src/bindings/wasix-ts/src/worker-client.ts
rename to src/sdks/ts-wasix/sdk/src/worker-client.ts
index 839965826..1c3927d76 100644
--- a/src/bindings/wasix-ts/src/worker-client.ts
+++ b/src/sdks/ts-wasix/sdk/src/worker-client.ts
@@ -1,13 +1,19 @@
-import { serializeOpenConfig } from './client-common.js';
-import type { PersistentWasixStorage } from './storage.js';
-import type { BinaryInput, OliphauntClient, OliphauntDatabase, OpenConfig } from './types.js';
+import { requireBrowserStorage, serializeOpenConfig } from './open-config.js';
+import type { PersistentWasixStorage } from './browser-public.js';
+import type {
+  BinaryInput,
+  OliphauntClient,
+  OliphauntDatabase,
+  OpenConfig,
+} from './browser-public.js';
 import { openWasixWithWorker, restoreWasixWithWorker, type WasixWorkerPort } from './worker-rpc.js';
 
 /** Open PostgreSQL in a package-owned browser Worker. */
 export async function openWasix(config: OpenConfig = {}): Promise {
   const openOptions = serializeOpenConfig(config);
+  requireBrowserStorage(openOptions);
   assertBrowserWorkerEnvironment();
-  return openWasixWithWorker(createBrowserWorker, openOptions);
+  return openWasixWithWorker(createBrowserWorker, openOptions, requireBrowserStorage);
 }
 
 async function restoreBrowserWasix(
@@ -15,7 +21,7 @@ async function restoreBrowserWasix(
   bytes: BinaryInput,
 ): Promise {
   assertBrowserWorkerEnvironment();
-  return restoreWasixWithWorker(createBrowserWorker, storage, bytes);
+  return restoreWasixWithWorker(createBrowserWorker, storage, bytes, requireBrowserStorage);
 }
 
 function assertBrowserWorkerEnvironment(): void {
diff --git a/src/bindings/wasix-ts/src/worker-dispatch.ts b/src/sdks/ts-wasix/sdk/src/worker-dispatch.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/worker-dispatch.ts
rename to src/sdks/ts-wasix/sdk/src/worker-dispatch.ts
diff --git a/src/sdks/ts-wasix/sdk/src/worker-entry.bun.ts b/src/sdks/ts-wasix/sdk/src/worker-entry.bun.ts
new file mode 100644
index 000000000..7c4c9bd8b
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/worker-entry.bun.ts
@@ -0,0 +1,2 @@
+export { Oliphaunt, Oliphaunt as default } from './worker-node-client.js';
+export * from './native-public.js';
diff --git a/src/sdks/ts-wasix/sdk/src/worker-entry.deno.ts b/src/sdks/ts-wasix/sdk/src/worker-entry.deno.ts
new file mode 100644
index 000000000..7c4c9bd8b
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/worker-entry.deno.ts
@@ -0,0 +1,2 @@
+export { Oliphaunt, Oliphaunt as default } from './worker-node-client.js';
+export * from './native-public.js';
diff --git a/src/sdks/ts-wasix/sdk/src/worker-entry.node.ts b/src/sdks/ts-wasix/sdk/src/worker-entry.node.ts
new file mode 100644
index 000000000..7c4c9bd8b
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/worker-entry.node.ts
@@ -0,0 +1,2 @@
+export { Oliphaunt, Oliphaunt as default } from './worker-node-client.js';
+export * from './native-public.js';
diff --git a/src/sdks/ts-wasix/sdk/src/worker-entry.ts b/src/sdks/ts-wasix/sdk/src/worker-entry.ts
new file mode 100644
index 000000000..95578ade4
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/worker-entry.ts
@@ -0,0 +1,2 @@
+export { Oliphaunt, Oliphaunt as default } from './worker-client.js';
+export * from './browser-public.js';
diff --git a/src/sdks/ts-wasix/sdk/src/worker-node-client.ts b/src/sdks/ts-wasix/sdk/src/worker-node-client.ts
new file mode 100644
index 000000000..e3e5a2e92
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/src/worker-node-client.ts
@@ -0,0 +1,65 @@
+import { Worker } from 'node:worker_threads';
+
+import { serializeOpenConfig } from './open-config.js';
+import { hostRuntimeName } from './host-runtime.js';
+import { requireNodeStorage } from './node-client-common.js';
+import { nodeWorkerExecArgv } from './node-worker-options.js';
+import { nodeWorkerPort } from './node-worker-port.js';
+import type { SerializedOpenOptions } from './rpc.js';
+import type { PersistentWasixStorage } from './native-public.js';
+import type {
+  BinaryInput,
+  OliphauntClient,
+  OliphauntDatabase,
+  OpenConfig,
+} from './native-public.js';
+import { openWasixWithWorker, restoreWasixWithWorker, type WasixWorkerPort } from './worker-rpc.js';
+
+/** Open PostgreSQL in a package-owned Node-compatible Worker realm. */
+export async function openWasix(config: OpenConfig = {}): Promise {
+  // The native Worker owns release-embedded runtime assets. Do not structured-
+  // clone caller-provided WebAssembly archives that the N-API path will never
+  // read; retain their exact identity metadata for compatibility validation.
+  const openOptions = withoutNativeAssetPayloads(serializeOpenConfig(config));
+  return openWasixWithWorker(createNodeWorker, openOptions, requireNodeStorage, false);
+}
+
+export const Oliphaunt: OliphauntClient = {
+  open: openWasix,
+  restore: restoreNodeWasixWithWorker,
+};
+
+async function restoreNodeWasixWithWorker(
+  storage: PersistentWasixStorage,
+  bytes: BinaryInput,
+): Promise {
+  return restoreWasixWithWorker(createNodeWorker, storage, bytes, requireNodeStorage);
+}
+
+function createNodeWorker(_options: SerializedOpenOptions): WasixWorkerPort {
+  return nodeWorkerPort(
+    new Worker(new URL('./node-worker.js', import.meta.url), {
+      execArgv: nodeWorkerExecArgv(),
+      name: 'oliphaunt-wasix',
+    }),
+    hostRuntimeName(),
+  );
+}
+
+function withoutNativeAssetPayloads(options: SerializedOpenOptions): SerializedOpenOptions {
+  const source = 'oliphaunt:wasix-napi-embedded';
+  return {
+    ...options,
+    runtime: {
+      ...options.runtime,
+      runtimeArchive: { ...options.runtime.runtimeArchive, source },
+      manifest: { ...options.runtime.manifest, source },
+    },
+    extensionCarriers: Object.fromEntries(
+      Object.entries(options.extensionCarriers).map(([sqlName, carrier]) => [
+        sqlName,
+        { ...carrier, source },
+      ]),
+    ),
+  };
+}
diff --git a/src/bindings/wasix-ts/src/worker-rpc.ts b/src/sdks/ts-wasix/sdk/src/worker-rpc.ts
similarity index 96%
rename from src/bindings/wasix-ts/src/worker-rpc.ts
rename to src/sdks/ts-wasix/sdk/src/worker-rpc.ts
index 8c607bb99..598b470e1 100644
--- a/src/bindings/wasix-ts/src/worker-rpc.ts
+++ b/src/sdks/ts-wasix/sdk/src/worker-rpc.ts
@@ -10,7 +10,7 @@ import {
   type WasixProtocolConnectionMode,
   type WasixProtocolStreamOutcome,
 } from './database.js';
-import { serializeOpenConfig } from './client-common.js';
+import { serializeOpenConfig } from './open-config.js';
 import { toUint8Array } from './query.js';
 import type {
   SerializedAssetSource,
@@ -315,12 +315,12 @@ function assetTransfers(options: SerializedOpenOptions): Transferable[] {
   appendAssetTransfer(options.runtime.runtimeArchive.source, transfer, seen);
   appendAssetTransfer(options.runtime.manifest.source, transfer, seen);
   if (options.icu !== undefined) {
-    appendAssetTransfer(options.icu.dataArchive.source, transfer, seen);
-    appendAssetTransfer(options.icu.clusterSeedArchive.source, transfer, seen);
-    appendAssetTransfer(options.icu.clusterSeedManifest.source, transfer, seen);
-  } else {
-    appendAssetTransfer(options.runtime.standardSeedArchive.source, transfer, seen);
-    appendAssetTransfer(options.runtime.standardSeedManifest.source, transfer, seen);
+    appendAssetTransfer(options.icu.data, transfer, seen);
+    appendAssetTransfer(options.icu.manifest, transfer, seen);
+  }
+  if (options.seed !== undefined) {
+    appendAssetTransfer(options.seed.archive, transfer, seen);
+    appendAssetTransfer(options.seed.manifest, transfer, seen);
   }
   for (const carrier of Object.values(options.extensionCarriers)) {
     appendAssetTransfer(carrier.source, transfer, seen);
@@ -442,9 +442,6 @@ class WorkerDatabaseSession implements WasixDatabaseSession {
         method: 'runTool',
         options: {
           ...options,
-          // The release addon owns the verified tool payload. Preserve only
-          // the descriptor identity across the Worker boundary.
-          tool: { ...options.tool, source: 'oliphaunt:wasix-napi-embedded' },
           args: [...options.args],
           ...(stdin === undefined ? {} : { stdin }),
         },
diff --git a/src/bindings/wasix-ts/src/worker-transfer.ts b/src/sdks/ts-wasix/sdk/src/worker-transfer.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/worker-transfer.ts
rename to src/sdks/ts-wasix/sdk/src/worker-transfer.ts
diff --git a/src/bindings/wasix-ts/src/worker.ts b/src/sdks/ts-wasix/sdk/src/worker.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/worker.ts
rename to src/sdks/ts-wasix/sdk/src/worker.ts
diff --git a/src/bindings/wasix-ts/src/zstd.ts b/src/sdks/ts-wasix/sdk/src/zstd.ts
similarity index 100%
rename from src/bindings/wasix-ts/src/zstd.ts
rename to src/sdks/ts-wasix/sdk/src/zstd.ts
diff --git a/src/sdks/ts-wasix/sdk/tools/check-package.mts b/src/sdks/ts-wasix/sdk/tools/check-package.mts
new file mode 100644
index 000000000..565618e8f
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/check-package.mts
@@ -0,0 +1,29 @@
+#!/usr/bin/env bun
+import { readdirSync } from 'node:fs';
+import path from 'node:path';
+import { compareText } from '../../../../../tools/release/release-artifact-targets.mts';
+import { fail, inspectSdkProduct, rel } from '../../../../../tools/packaging/release-carrier.mts';
+import { assertWasixTypescriptNpmArchive } from './wasix-typescript-package.mts';
+
+export async function checkWasixTypescriptPackage(root) {
+  const product = 'oliphaunt-wasix-ts';
+  let checked = false;
+
+  const tarballs = readdirSync(root)
+    .filter((name) => name.endsWith('.tgz'))
+    .map((name) => path.join(root, name))
+    .sort(compareText);
+  if (tarballs.length !== 1) {
+    fail(`${product} must stage one SDK npm tarball under ${rel(root)}`);
+  }
+  try {
+    assertWasixTypescriptNpmArchive(tarballs[0]);
+  } catch (error) {
+    fail(error instanceof Error ? error.message : String(error));
+  }
+  checked = true;
+
+  return checked;
+}
+
+if (import.meta.main) await inspectSdkProduct('oliphaunt-wasix-ts', checkWasixTypescriptPackage);
diff --git a/src/sdks/ts-wasix/sdk/tools/entrypoint-consumer.ts b/src/sdks/ts-wasix/sdk/tools/entrypoint-consumer.ts
new file mode 100644
index 000000000..61ccf4805
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/entrypoint-consumer.ts
@@ -0,0 +1,29 @@
+import Browser from '@oliphaunt/wasix-ts/browser';
+import Native from '@oliphaunt/wasix-ts';
+import Direct from '@oliphaunt/wasix-ts/direct';
+import Worker from '@oliphaunt/wasix-ts/worker';
+import { openServer } from '@oliphaunt/wasix-ts/server';
+import { directory } from '@oliphaunt/wasix-ts/storage/node';
+import { indexedDB } from '@oliphaunt/wasix-ts/storage/indexed-db';
+import { opfs } from '@oliphaunt/wasix-ts/storage/opfs';
+
+const disk = directory('/db');
+const origin = indexedDB('db');
+const bytes = new Uint8Array();
+void Browser.open({ storage: origin });
+void Browser.restore(opfs('restore'), bytes);
+// @ts-expect-error Browser open cannot use host directories.
+void Browser.open({ storage: disk });
+// @ts-expect-error Browser restore cannot use host directories.
+void Browser.restore(disk, bytes);
+for (const client of [Native, Direct, Worker]) {
+  void client.open({ storage: disk });
+  void client.restore(disk, bytes);
+  // @ts-expect-error Node conditions must select native declarations.
+  void client.open({ storage: origin });
+  // @ts-expect-error Native restore cannot use browser persistence.
+  void client.restore(origin, bytes);
+}
+void openServer({ storage: disk });
+// @ts-expect-error Servers are native-only.
+void openServer({ storage: origin });
diff --git a/src/sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts b/src/sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts
new file mode 100644
index 000000000..064da7f86
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/integration/packed-node-fixture.mts
@@ -0,0 +1,552 @@
+import { createHash } from 'node:crypto';
+import { cp, mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
+import { arch, platform } from 'node:os';
+import { dirname, isAbsolute, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { WASIX_RUNTIME_NPM_ASSET_PATHS } from '../../../../../runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-contract.mts';
+import {
+  renderWasixRuntimeDescriptorModule,
+  renderWasixRuntimeDescriptorTypes,
+} from '../../../../../runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-descriptor.mts';
+import { createDeterministicTar } from '../../../../../../tools/packaging/cargo-source-package.mts';
+import {
+  canonicalGzipSync,
+  readPortableArchiveEntries,
+} from '../../../../../../tools/packaging/portable-archive.mts';
+import { packWasixToolsNpmCarrier } from '../../../../../postgres-tools/wasix/tools/wasix-tools-npm-carrier.mts';
+import { packWasixToolsAotNpmCarriers } from '../../../../../postgres-tools/wasix/tools/wasix-tools-aot-npm.mts';
+import { artifactTargets } from '../../../../../../tools/release/release-artifact-targets.mts';
+import { assertWasixTypescriptNpmArchive } from '../wasix-typescript-package.mts';
+
+import { stageLocalNpmTarball } from '../../../../../../tools/packaging/local-npm-tarball.mts';
+
+const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../../..');
+const packageRoot = resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk');
+const assetRoot = resolve(repositoryRoot, 'target/oliphaunt-wasix/assets');
+const extensionAssetRoot = resolve(repositoryRoot, 'target/extensions/wasix/assets');
+const nativeCarrierRoot = resolve(repositoryRoot, 'target/oliphaunt-wasix-napi/npm-packages');
+const databaseRootContractFile = resolve(
+  repositoryRoot,
+  'src/test-fixtures/storage/database-root.json',
+);
+
+export async function stagePackedWasixConsumer({
+  scratch,
+  consumerName = 'oliphaunt-wasix-node-consumer',
+  includePgtap = false,
+  includeTools = false,
+  includeNative = true,
+  includeSeed = false,
+  includeResources = false,
+  useStubRuntime = false,
+}) {
+  if (typeof scratch !== 'string' || !isAbsolute(scratch)) {
+    throw new Error(
+      'packed WASIX Node/Bun/Deno/Electron host fixture requires an absolute scratch directory',
+    );
+  }
+  const releaseVersions = JSON.parse(
+    await readFile(resolve(repositoryRoot, '.release-please-manifest.json'), 'utf8'),
+  );
+  const runtimeVersion = releaseVersions['src/runtimes/liboliphaunt-wasix'];
+  const extensionVersion = releaseVersions['src/extensions/external/pgtap'];
+  const tarballs = resolve(scratch, 'tarballs');
+  await mkdir(tarballs, { recursive: true });
+
+  const binding = await packedBinding();
+  const queryFile = resolve(scratch, 'query.tgz');
+  const queryEntries = readPortableArchiveEntries(queryFile);
+  const queryManifest = queryEntries.get('package/package.json');
+  if (!queryManifest?.isFile)
+    throw new Error('Packed query dependency is missing its package manifest');
+  const query = {
+    ...JSON.parse(Buffer.from(queryManifest.data()).toString('utf8')),
+    file: queryFile,
+  };
+  const nativeCarrier = includeNative
+    ? await findNativeCarrier({
+        nativeVersion: binding.nativeVersion,
+        runtimeVersion,
+      })
+    : undefined;
+  const toolsVersion = releaseVersions['src/postgres-tools/wasix'];
+  const toolsCarrier = includeTools
+    ? await packToolsCarrier({ scratch, tarballs, toolsVersion })
+    : undefined;
+  const toolsFacade = includeTools ? await findToolsFacade() : undefined;
+  if (includePgtap && useStubRuntime) {
+    throw new Error('the packed WASIX stub runtime cannot carry extensions');
+  }
+  const runtime = useStubRuntime
+    ? await packStubRuntime({ scratch, tarballs, runtimeVersion })
+    : await packRuntime({ scratch, tarballs, runtimeVersion });
+  const extension = includePgtap
+    ? await packPgtap({ scratch, tarballs, runtimeVersion, extensionVersion })
+    : undefined;
+  const toolsAot =
+    includeTools && includeNative ? await packToolsAot({ scratch, toolsVersion }) : undefined;
+  const resources = [];
+  if (includeSeed || includeResources) {
+    const version = releaseVersions['src/database-resources'];
+    requireReleaseVersion(version, 'src/database-resources');
+    for (const profile of includeResources ? ['standard', 'icu'] : ['standard']) {
+      resources.push(
+        await archivePackage(
+          resolve(
+            repositoryRoot,
+            `target/database-resources/seed-carriers/npm/oliphaunt-seed-wasix-${profile}/oliphaunt-seed-wasix-${profile}-${version}.tgz`,
+          ),
+        ),
+      );
+    }
+    if (includeResources)
+      resources.push(
+        await archivePackage(
+          resolve(
+            repositoryRoot,
+            `target/release/npm-packages/oliphaunt-icu/oliphaunt-icu-${version}.tgz`,
+          ),
+        ),
+      );
+  }
+  const consumer = resolve(scratch, 'consumer');
+  await mkdir(consumer, { recursive: true });
+  const dependencies = {
+    [query.name]: stageLocalNpmTarball(query.file, consumer),
+    [runtime.name]: stageLocalNpmTarball(runtime.file, consumer),
+    [binding.name]: stageLocalNpmTarball(binding.file, consumer),
+  };
+  for (const resource of resources)
+    dependencies[resource.name] = stageLocalNpmTarball(resource.file, consumer);
+  if (nativeCarrier !== undefined) {
+    dependencies[nativeCarrier.name] = stageLocalNpmTarball(nativeCarrier.file, consumer);
+  }
+  if (extension !== undefined) {
+    dependencies[extension.name] = stageLocalNpmTarball(extension.file, consumer);
+  }
+  if (toolsCarrier !== undefined) {
+    dependencies[toolsCarrier.name] = stageLocalNpmTarball(toolsCarrier.file, consumer);
+  }
+  if (toolsAot !== undefined)
+    dependencies[toolsAot.name] = stageLocalNpmTarball(toolsAot.file, consumer);
+  if (toolsFacade !== undefined) {
+    dependencies[toolsFacade.name] = stageLocalNpmTarball(toolsFacade.file, consumer);
+  }
+  await writeJson(resolve(consumer, 'package.json'), {
+    name: consumerName,
+    version: '0.0.0',
+    private: true,
+    type: 'module',
+    dependencies,
+    overrides: dependencies,
+  });
+  return {
+    consumer,
+    packages: {
+      query,
+      resources,
+      binding,
+      runtime,
+      ...(nativeCarrier === undefined ? {} : { nativeCarrier }),
+      ...(extension === undefined ? {} : { extension }),
+      ...(toolsCarrier === undefined ? {} : { toolsCarrier }),
+      ...(toolsFacade === undefined ? {} : { toolsFacade }),
+    },
+  };
+}
+
+async function packStubRuntime({ scratch, tarballs, runtimeVersion }) {
+  requireReleaseVersion(runtimeVersion, 'src/runtimes/liboliphaunt-wasix');
+  const identity = await wasixPhysicalIdentity();
+  const staging = resolve(scratch, 'runtime');
+  await mkdir(staging);
+  const emptyByteSha256 = sha256(Buffer.of(0));
+  await writeFile(
+    resolve(staging, 'index.js'),
+    `export const POSTGRES_MAJOR = ${JSON.stringify(identity.postgresMajor)};
+export const PHYSICAL_FORMAT = ${JSON.stringify(identity.physicalFormat)};
+
+const byte = new URL('data:application/octet-stream;base64,AA==');
+export default Object.freeze({
+  schema: 'oliphaunt-wasix-runtime-v2',
+  runtime: 'wasix',
+  product: 'liboliphaunt-wasix',
+  version: ${JSON.stringify(runtimeVersion)},
+  runtimeArchive: {
+    archive: 'runtime.tar.zst',
+    sha256: ${JSON.stringify(emptyByteSha256)},
+    size: 1,
+    source: byte,
+  },
+  manifest: {
+    sha256: ${JSON.stringify(emptyByteSha256)},
+    size: 1,
+    source: byte,
+  },
+});
+`,
+  );
+  await writeJson(resolve(staging, 'package.json'), {
+    name: '@oliphaunt/liboliphaunt-wasix',
+    version: runtimeVersion,
+    type: 'module',
+    exports: { '.': './index.js' },
+  });
+  return pack(staging, tarballs);
+}
+
+async function packedBinding() {
+  const { version } = JSON.parse(await readFile(resolve(packageRoot, 'package.json'), 'utf8'));
+  const file = resolve(
+    repositoryRoot,
+    `target/oliphaunt-wasix-ts/package/packages/oliphaunt-wasix-ts-${version}.tgz`,
+  );
+  const manifest = assertWasixTypescriptNpmArchive(file);
+  const nativeVersion = manifest.oliphaunt?.wasixNapiVersion;
+  requireReleaseVersion(nativeVersion, 'oliphaunt-wasix-napi');
+  const bytes = await readFile(file);
+  return {
+    file,
+    name: manifest.name,
+    version: manifest.version,
+    sha256: sha256(bytes),
+    size: bytes.length,
+    nativeVersion,
+  };
+}
+
+async function findNativeCarrier({ nativeVersion, runtimeVersion }) {
+  const expected = nativeCarrierIdentity(platform(), arch());
+  let names;
+  try {
+    names = (await readdir(nativeCarrierRoot)).filter((name) => name.endsWith('.tgz')).sort();
+  } catch (error) {
+    if (error?.code !== 'ENOENT') throw error;
+    throw new Error(
+      `packed WASIX Node/Bun/Deno/Electron smoke requires ${expected.name} ${nativeVersion} under ${nativeCarrierRoot}`,
+    );
+  }
+
+  const matches = [];
+  for (const filename of names) {
+    const file = resolve(nativeCarrierRoot, filename);
+    const entries = readPortableArchiveEntries(file);
+    const manifestEntry = entries.get('package/package.json');
+    if (!manifestEntry?.isFile || manifestEntry.isSymbolicLink) continue;
+    const manifest = JSON.parse(Buffer.from(manifestEntry.data()).toString('utf8'));
+    if (manifest.name !== expected.name || manifest.version !== nativeVersion) continue;
+    const artifactProvenance = validateNativeCarrierArchive(
+      file,
+      entries,
+      manifest,
+      expected,
+      runtimeVersion,
+    );
+    const bytes = await readFile(file);
+    matches.push({
+      file,
+      name: manifest.name,
+      version: manifest.version,
+      target: expected.target,
+      sha256: sha256(bytes),
+      size: bytes.length,
+      manifest,
+      artifactProvenance,
+      artifactProvenanceMember: 'package/artifact-provenance.json',
+    });
+  }
+  if (matches.length !== 1) {
+    throw new Error(
+      `packed WASIX Node/Bun/Deno/Electron smoke requires exactly one ${expected.name} ${nativeVersion} tarball under ${nativeCarrierRoot}; found ${matches.length}`,
+    );
+  }
+  return matches[0];
+}
+
+function validateNativeCarrierArchive(file, entries, manifest, expected, runtimeVersion) {
+  const label = file.slice(file.lastIndexOf('/') + 1);
+  if (
+    manifest.oliphaunt?.target !== expected.target ||
+    manifest.oliphaunt?.runtimeProduct !== 'liboliphaunt-wasix' ||
+    manifest.oliphaunt?.runtimeVersion !== runtimeVersion ||
+    manifest.oliphaunt?.addonAbiVersion !== 2 ||
+    manifest.oliphaunt?.nodeApiVersion !== 8 ||
+    JSON.stringify(manifest.oliphaunt?.profiles) !== JSON.stringify(['standard', 'icu'])
+  ) {
+    throw new Error(`${label} has incompatible WASIX Node-API carrier metadata`);
+  }
+  const provenanceEntry = entries.get('package/artifact-provenance.json');
+  if (!provenanceEntry?.isFile || provenanceEntry.isSymbolicLink) {
+    throw new Error(`${label} omits native artifact provenance`);
+  }
+  const provenance = JSON.parse(Buffer.from(provenanceEntry.data()).toString('utf8'));
+  if (
+    provenance.schema !== 'oliphaunt-wasix-napi-provenance-v1' ||
+    provenance.product !== 'oliphaunt-wasix-napi' ||
+    provenance.target !== expected.target ||
+    !/^[0-9a-f]{40}$/.test(provenance.artifactSourceSha ?? '')
+  ) {
+    throw new Error(`${label} has invalid native artifact provenance`);
+  }
+  const binary = 'oliphaunt_wasix_napi.node';
+  const entry = entries.get(`package/prebuilds/${binary}`);
+  if (!entry?.isFile || entry.isSymbolicLink || entry.size <= 0) {
+    throw new Error(`${label} omits non-empty ${binary}`);
+  }
+  const digest = sha256(Buffer.from(entry.data()));
+  if (
+    provenance.binary?.filename !== binary ||
+    provenance.binary?.sha256 !== digest ||
+    Object.hasOwn(provenance, 'binaries')
+  ) {
+    throw new Error(`${label} ${binary} differs from native artifact provenance`);
+  }
+  return provenance;
+}
+
+function nativeCarrierIdentity(currentPlatform, currentArch) {
+  if (currentPlatform === 'darwin' && currentArch === 'arm64') {
+    return { name: '@oliphaunt/wasix-napi-darwin-arm64', target: 'macos-arm64' };
+  }
+  if (currentPlatform === 'linux' && currentArch === 'arm64') {
+    return { name: '@oliphaunt/wasix-napi-linux-arm64-gnu', target: 'linux-arm64-gnu' };
+  }
+  if (currentPlatform === 'linux' && currentArch === 'x64') {
+    return { name: '@oliphaunt/wasix-napi-linux-x64-gnu', target: 'linux-x64-gnu' };
+  }
+  if (currentPlatform === 'win32' && currentArch === 'x64') {
+    return { name: '@oliphaunt/wasix-napi-win32-x64-msvc', target: 'windows-x64-msvc' };
+  }
+  throw new Error(
+    `packed WASIX Node/Bun/Deno/Electron smoke has no native carrier for ${currentPlatform}/${currentArch}`,
+  );
+}
+
+async function archivePackage(file) {
+  const entries = readPortableArchiveEntries(file);
+  const row = entries.get('package/package.json');
+  if (!row?.isFile) throw new Error(`Missing package manifest in ${file}`);
+  const manifest = JSON.parse(Buffer.from(row.data()).toString('utf8'));
+  const bytes = await readFile(file);
+  return {
+    file,
+    name: manifest.name,
+    version: manifest.version,
+    sha256: sha256(bytes),
+    size: bytes.length,
+  };
+}
+async function packToolsCarrier({ scratch, tarballs, toolsVersion }) {
+  requireReleaseVersion(toolsVersion, 'src/postgres-tools/wasix');
+  const packed = packWasixToolsNpmCarrier({
+    version: toolsVersion,
+    portableReleaseArchive: resolve(
+      repositoryRoot,
+      `target/postgres-tools/wasix/release-assets/postgres-tools-wasix-${toolsVersion}-portable.tar.gz`,
+    ),
+    packageDir: resolve(scratch, 'tools-carrier'),
+    tarballRoot: resolve(tarballs, 'tools'),
+  });
+  return archivePackage(packed.tarball);
+}
+async function packToolsAot({ scratch, toolsVersion }) {
+  const target = artifactTargets('postgres-tools-wasix', 'wasix-tools-aot', 'packed-consumer').find(
+    (row) => row.npmOs === platform() && row.npmCpu === arch(),
+  );
+  if (!target) throw new Error('No PostgreSQL tools AOT carrier for this host');
+  const [file] = packWasixToolsAotNpmCarriers(
+    toolsVersion,
+    resolve(repositoryRoot, 'target/postgres-tools/wasix/release-assets'),
+    { targetIds: [target.target], workRoot: resolve(scratch, 'tools-aot') },
+  );
+  return archivePackage(file);
+}
+async function findToolsFacade() {
+  const root = resolve(repositoryRoot, 'target/sdk-artifacts/postgres-tools-wasix');
+  const files = (await readdir(root)).filter((name) => name.endsWith('.tgz'));
+  if (files.length !== 1) throw new Error('Expected one packaged PostgreSQL tools facade');
+  return archivePackage(resolve(root, files[0]));
+}
+
+async function packRuntime({ scratch, tarballs, runtimeVersion }) {
+  requireReleaseVersion(runtimeVersion, 'src/runtimes/liboliphaunt-wasix');
+  const identity = await wasixPhysicalIdentity();
+  const staging = resolve(scratch, 'runtime');
+  const assets = resolve(staging, 'assets');
+  await mkdir(assets, { recursive: true });
+  const manifest = JSON.parse(await readFile(resolve(assetRoot, 'manifest.json'), 'utf8'));
+  const manifestPostgresMajor = Number(manifest.runtime?.['postgres-version']?.split('.')[0]);
+  if (manifestPostgresMajor !== identity.postgresMajor) {
+    throw new Error('WASIX runtime manifest disagrees with the shared physical identity');
+  }
+  const { ['cluster-seeds']: _retiredSeeds, ...runtimeManifest } = manifest;
+  const coreManifest = Buffer.from(JSON.stringify({ ...runtimeManifest, extensions: [] }));
+  const runtimeSource = resolve(assetRoot, manifest.runtime.archive);
+  const runtimeBytes = await readFile(runtimeSource);
+  requireDigest(runtimeBytes, manifest.runtime.sha256, manifest.runtime.archive);
+  await cp(runtimeSource, resolve(staging, WASIX_RUNTIME_NPM_ASSET_PATHS.runtimeArchive));
+  await writeFile(resolve(staging, WASIX_RUNTIME_NPM_ASSET_PATHS.manifest), coreManifest);
+  const descriptor = {
+    schema: 'oliphaunt-wasix-runtime-v2',
+    runtime: 'wasix',
+    product: 'liboliphaunt-wasix',
+    version: runtimeVersion,
+    runtimeArchive: {
+      archive: manifest.runtime.archive,
+      sha256: sha256(runtimeBytes),
+      size: runtimeBytes.length,
+    },
+    manifest: { sha256: sha256(coreManifest), size: coreManifest.length },
+  };
+  await writeFile(resolve(staging, 'index.js'), renderWasixRuntimeDescriptorModule(descriptor));
+  await writeFile(resolve(staging, 'index.d.ts'), renderWasixRuntimeDescriptorTypes());
+  await writeJson(resolve(staging, 'package.json'), {
+    name: '@oliphaunt/liboliphaunt-wasix',
+    version: runtimeVersion,
+    type: 'module',
+    exports: {
+      '.': { types: './index.d.ts', import: './index.js', default: './index.js' },
+    },
+  });
+  return pack(staging, tarballs);
+}
+
+async function wasixPhysicalIdentity() {
+  const contract = JSON.parse(await readFile(databaseRootContractFile, 'utf8'));
+  const postgresMajor = contract.postgresMajor;
+  const physicalFormat = contract.families?.wasix?.physicalFormat;
+  if (!Number.isInteger(postgresMajor) || typeof physicalFormat !== 'string' || !physicalFormat) {
+    throw new Error('shared database-root fixture has no valid WASIX physical identity');
+  }
+  return { postgresMajor, physicalFormat };
+}
+
+async function packPgtap({ scratch, tarballs, runtimeVersion, extensionVersion }) {
+  requireReleaseVersion(extensionVersion, 'src/extensions/external/pgtap');
+  const staging = resolve(scratch, 'pgtap');
+  const assets = resolve(staging, 'assets');
+  await mkdir(assets, { recursive: true });
+  const manifest = JSON.parse(await readFile(resolve(extensionAssetRoot, 'manifest.json'), 'utf8'));
+  const row = manifest.extensions.find((candidate) => candidate['sql-name'] === 'pgtap');
+  if (row === undefined) throw new Error('WASIX manifest has no pgtap carrier');
+  await cp(resolve(extensionAssetRoot, row.archive), resolve(assets, 'pgtap.tar.zst'));
+  const lifecycle = row.lifecycle;
+  const carrier = {
+    product: 'oliphaunt-extension-pgtap',
+    version: extensionVersion,
+    sqlName: 'pgtap',
+    archive: row.archive,
+    sha256: row.sha256,
+    size: row.size,
+    install: {
+      schema: 'oliphaunt-wasix-extension-install-v1',
+      name: row.name,
+      nativeModule: null,
+      nativeModules: [],
+      dependencies: row.dependencies,
+      coreExportsRequired: row['core-exports-required'],
+      loadOrder: row['load-order'],
+      lifecycle: {
+        createExtension: lifecycle['create-extension'],
+        createSchema: lifecycle['create-schema'],
+        loadSql: lifecycle['load-sql'],
+        postCreateSql: lifecycle['post-create-sql'],
+        startupConfig: lifecycle['startup-config'],
+        preloadRequired: lifecycle['preload-required'],
+        restartRequired: lifecycle['restart-required'],
+        sharedMemoryRequired: lifecycle['shared-memory-required'],
+      },
+      installedFiles: row['installed-files'],
+      unresolvedImports: row['unresolved-imports'],
+    },
+  };
+  const descriptor = {
+    schema: 'oliphaunt-wasix-extension-v1',
+    runtime: 'wasix',
+    product: carrier.product,
+    version: carrier.version,
+    compatibility: {
+      extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1',
+      postgresMajor: manifest.runtime['postgres-version'].split('.')[0],
+      wasixRuntimeProduct: 'liboliphaunt-wasix',
+      wasixRuntimeVersion: runtimeVersion,
+    },
+    sqlName: 'pgtap',
+    carriers: [carrier],
+  };
+  await writeFile(
+    resolve(staging, 'index.js'),
+    `const descriptor = ${JSON.stringify(descriptor, null, 2)};
+descriptor.carriers[0].source = new URL('./assets/pgtap.tar.zst', import.meta.url);
+export default descriptor;
+`,
+  );
+  await writeJson(resolve(staging, 'package.json'), {
+    name: '@oliphaunt/extension-pgtap-wasix',
+    version: extensionVersion,
+    type: 'module',
+    exports: { '.': './index.js' },
+  });
+  return pack(staging, tarballs);
+}
+
+async function pack(directory, tarballs) {
+  const manifest = JSON.parse(await readFile(resolve(directory, 'package.json'), 'utf8'));
+  await cp(resolve(repositoryRoot, 'LICENSE'), resolve(directory, 'LICENSE'), { force: false });
+  const file = resolve(
+    tarballs,
+    `${manifest.name.replace(/^@/u, '').replaceAll('/', '-')}-${manifest.version}.tgz`,
+  );
+  const bytes = canonicalGzipSync(createDeterministicTar(directory, 'package', {}));
+  await writeFile(file, bytes, { flag: 'wx' });
+  return {
+    file,
+    name: manifest.name,
+    version: manifest.version,
+    sha256: sha256(bytes),
+    size: bytes.length,
+  };
+}
+
+async function writeJson(file, value) {
+  await writeFile(file, `${JSON.stringify(value, null, 2)}\n`);
+}
+
+function requireReleaseVersion(value, component) {
+  if (typeof value !== 'string' || !/^\d+\.\d+\.\d+$/u.test(value)) {
+    throw new Error(`release manifest has no exact version for ${component}`);
+  }
+}
+
+function requireDigest(bytes, expected, label) {
+  const actual = sha256(bytes);
+  if (actual !== expected) {
+    throw new Error(`${label} is ${actual}, expected ${expected}`);
+  }
+}
+
+function sha256(bytes) {
+  return createHash('sha256').update(bytes).digest('hex');
+}
+
+if (resolve(process.argv[1] ?? '') === fileURLToPath(import.meta.url)) {
+  const [scratch, ...flags] = process.argv.slice(2);
+  if (
+    !scratch ||
+    flags.some(
+      (flag) => !['--pgtap', '--tools', '--without-native', '--stub-runtime'].includes(flag),
+    )
+  ) {
+    throw new Error(
+      'usage: packed-node-fixture.mts SCRATCH [--pgtap] [--tools] [--without-native] [--stub-runtime]',
+    );
+  }
+  const fixture = await stagePackedWasixConsumer({
+    scratch: resolve(scratch),
+    includePgtap: flags.includes('--pgtap'),
+    includeTools: flags.includes('--tools'),
+    includeNative: !flags.includes('--without-native'),
+    useStubRuntime: flags.includes('--stub-runtime'),
+  });
+  await writeJson(resolve(scratch, 'packed-consumer.json'), fixture);
+}
diff --git a/src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.mts b/src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.mts
new file mode 100644
index 000000000..5a111d51c
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.mts
@@ -0,0 +1,358 @@
+import { access, cp, readFile, realpath, writeFile } from 'node:fs/promises';
+import { createServer } from 'node:net';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { stagePackedWasixConsumer } from './packed-node-fixture.mts';
+
+const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../../..');
+const bindingRoot = resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk');
+const [phase, scratch] = process.argv.slice(2);
+if (!scratch || !['--prepare', '--run'].includes(phase))
+  throw new Error('use bash src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh [options]');
+if (phase === '--prepare') {
+  const diagnosticOpfsBenchmark = process.argv.includes('--diagnostic-opfs');
+  const qualifyingBenchmark = process.argv.includes('--benchmark');
+  if (diagnosticOpfsBenchmark && qualifyingBenchmark) {
+    throw new Error('--diagnostic-opfs and --benchmark are mutually exclusive');
+  }
+  const benchmark = qualifyingBenchmark || diagnosticOpfsBenchmark;
+  const packageOnly = process.argv.includes('--package-only');
+  const quickBenchmark = benchmark && process.argv.includes('--quick');
+  if (
+    !qualifyingBenchmark &&
+    (argumentValue('--config') !== undefined || argumentValue('--output') !== undefined)
+  ) {
+    throw new Error('--config and --output require --benchmark');
+  }
+  if (
+    packageOnly &&
+    (benchmark || process.argv.includes('--pg-uuidv7') || process.argv.includes('--postgis-worker'))
+  ) {
+    throw new Error('--package-only cannot be combined with benchmark or extension-canary options');
+  }
+  const timeoutMs = Number(
+    process.env.OLIPHAUNT_BROWSER_SMOKE_TIMEOUT_MS ??
+      (diagnosticOpfsBenchmark && !quickBenchmark ? 1_800_000 : benchmark ? 900_000 : 300_000),
+  );
+  const pgUuidv7Canary = process.argv.includes('--pg-uuidv7');
+  const postgisWorkerCanary = process.argv.includes('--postgis-worker');
+  const requiredInputs = [
+    resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/oliphaunt.wasix.tar.zst'),
+    resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/manifest.json'),
+    ...(!packageOnly
+      ? [resolve(repositoryRoot, 'target/oliphaunt-wasix-ts/host/wasmer-sdk/dist/index.mjs')]
+      : []),
+  ];
+  if (!benchmark) {
+    requiredInputs.push(
+      resolve(repositoryRoot, 'target/extensions/wasix/assets/extensions/pgtap.tar.zst'),
+    );
+  }
+  if (pgUuidv7Canary) {
+    requiredInputs.push(
+      resolve(repositoryRoot, 'target/extensions/wasix/assets/extensions/pg_uuidv7.tar.zst'),
+    );
+  }
+  if (postgisWorkerCanary) {
+    requiredInputs.push(
+      resolve(repositoryRoot, 'target/extensions/wasix/assets/extensions/postgis.tar.zst'),
+    );
+  }
+  if (benchmark) {
+    requiredInputs.push(
+      resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist/pglite.data'),
+      resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist/pglite.wasm'),
+      resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist/initdb.wasm'),
+    );
+  }
+
+  for (const input of requiredInputs) {
+    try {
+      await access(input);
+    } catch {
+      throw new Error(`browser smoke input is missing: ${input}`);
+    }
+  }
+
+  const servers = [createServer(), createServer()];
+  let ports;
+  try {
+    await Promise.all(
+      servers.map(
+        (server) =>
+          new Promise((resolve, reject) => {
+            server.once('error', reject);
+            server.listen(0, '127.0.0.1', resolve);
+          }),
+      ),
+    );
+    ports = servers.map((server) => {
+      const address = server.address();
+      if (!address || typeof address === 'string') throw new Error('missing TCP address');
+      return address.port;
+    });
+  } finally {
+    for (const server of servers) server.close();
+  }
+  const [vitePort, chromePort] = ports;
+  let packedConsumer;
+  if (packageOnly) {
+    packedConsumer = await stagePackedBrowserConsumer(scratch, process.argv.includes('--tools'));
+  }
+  const smokeUrl = benchmark
+    ? `http://127.0.0.1:${vitePort}/benchmark.html?${new URLSearchParams({
+        ...(quickBenchmark ? { quick: '1' } : {}),
+        ...(diagnosticOpfsBenchmark ? { opfs: '1' } : {}),
+      })}`
+    : packageOnly
+      ? `http://127.0.0.1:${vitePort}/?package_smoke=1`
+      : `http://127.0.0.1:${vitePort}/?smoke=1${pgUuidv7Canary ? '&pg_uuidv7=1' : ''}${postgisWorkerCanary ? '&postgis_worker=1' : ''}`;
+
+  if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1)
+    throw new Error('browser timeout must be a positive number of milliseconds');
+  await writeFile(
+    resolve(scratch, 'browser.json'),
+    JSON.stringify({
+      vitePort,
+      chromePort,
+      smokeUrl,
+      timeoutMs,
+      packedConsumer,
+      packageOnly,
+      benchmark,
+      mode: qualifyingBenchmark ? 'benchmark' : diagnosticOpfsBenchmark ? 'diagnostic' : 'smoke',
+      config: argumentValue('--config'),
+      output: argumentValue('--output'),
+    }),
+  );
+} else {
+  const { chromePort, smokeUrl, timeoutMs, benchmark, packageOnly } = JSON.parse(
+    await readFile(resolve(scratch, 'browser.json'), 'utf8'),
+  );
+  // Cold Chrome startup shares the smoke budget instead of a separate 30-second cutoff.
+  const deadline = Date.now() + timeoutMs;
+  const chromePid = Number(await readFile(resolve(scratch, 'chrome.pid'), 'utf8'));
+  const targets = await waitForChrome(
+    `http://127.0.0.1:${chromePort}/json/list`,
+    chromePid,
+    deadline,
+  );
+  const page = targets.find((candidate) => candidate.type === 'page');
+  if (!page?.webSocketDebuggerUrl)
+    throw new Error('headless Chrome did not expose a page debugging target');
+  let socket;
+  try {
+    socket = new WebSocket(page.webSocketDebuggerUrl);
+    await new Promise((resolveOpen, rejectOpen) => {
+      socket.addEventListener('open', resolveOpen, { once: true });
+      socket.addEventListener('error', rejectOpen, { once: true });
+    });
+
+    const browserFailures = [];
+    const cdp = createCdpClient(socket, (failure) => browserFailures.push(failure), deadline);
+    await Promise.all([
+      cdp.send('Runtime.enable'),
+      cdp.send('Page.enable'),
+      cdp.send('Log.enable'),
+      cdp.send('Target.setAutoAttach', {
+        autoAttach: true,
+        waitForDebuggerOnStart: false,
+        flatten: true,
+      }),
+    ]);
+
+    await cdp.send('Page.navigate', { url: smokeUrl });
+    while (Date.now() < deadline) {
+      if (browserFailures.length > 0) {
+        throw new Error(
+          `browser smoke observed an unhandled exception:\n${browserFailures.at(-1)}`,
+        );
+      }
+      const evaluated = await cdp.send('Runtime.evaluate', {
+        expression:
+          "JSON.stringify({state:document.documentElement.dataset.oliphauntSmoke??'',status:document.querySelector('#status')?.textContent??'',output:document.querySelector('#output')?.textContent??''})",
+        returnByValue: true,
+      });
+      const snapshot = JSON.parse(evaluated.result.value ?? '{}');
+      if (snapshot.state === 'passed') {
+        if (benchmark) {
+          await writeFile(
+            resolve(scratch, 'browser-result.json'),
+            JSON.stringify(JSON.parse(snapshot.output)),
+          );
+        } else
+          console.log(
+            `wasix-ts ${packageOnly ? 'packed browser package' : 'browser'} smoke: PASS ${snapshot.output}`,
+          );
+        break;
+      }
+      if (snapshot.state === 'failed') {
+        throw new Error(`browser smoke failed: ${snapshot.status}\n${snapshot.output}`);
+      }
+      await delay(750);
+    }
+
+    const finalState = await cdp.send('Runtime.evaluate', {
+      expression: "document.documentElement.dataset.oliphauntSmoke ?? ''",
+      returnByValue: true,
+    });
+    if (finalState.result.value !== 'passed') {
+      throw new Error(`browser smoke timed out after ${timeoutMs}ms`);
+    }
+  } finally {
+    socket?.close();
+  }
+}
+
+async function stagePackedBrowserConsumer(scratch, includeTools) {
+  const fixture = await stagePackedWasixConsumer({
+    scratch,
+    consumerName: 'oliphaunt-wasix-browser-package-smoke-consumer',
+    includePgtap: true,
+    includeTools,
+    includeNative: false,
+    includeResources: true,
+  });
+  for (const [source, destination] of [
+    ['src/examples/browser-wasix/index.html', 'index.html'],
+    [
+      includeTools
+        ? 'src/postgres-tools/wasix/ts/tests/browser.ts'
+        : 'src/examples/browser-wasix/package-smoke.ts',
+      'main.ts',
+    ],
+    ...(includeTools
+      ? [['src/postgres-tools/wasix/ts/tests/direct-pg-dump-smoke.ts', 'direct-pg-dump-smoke.ts']]
+      : []),
+    ['src/examples/browser-wasix/structured-api-smoke.ts', 'structured-api-smoke.ts'],
+    ['src/test-fixtures/postgres/logical-tools.json', 'logical-tools.json'],
+    ['src/test-fixtures/postgres/logical-tools-seed.sql', 'logical-tools-seed.sql'],
+    ['src/test-fixtures/postgres/logical-tools-verify.sql', 'logical-tools-verify.sql'],
+  ]) {
+    await cp(resolve(repositoryRoot, source), resolve(fixture.consumer, destination));
+  }
+  return realpath(fixture.consumer);
+}
+
+function argumentValue(flag) {
+  const positions = process.argv
+    .map((value, index) => (value === flag ? index : -1))
+    .filter((index) => index >= 0);
+  if (positions.length > 1) throw new Error(`${flag} may be specified only once`);
+  if (positions.length === 0) return undefined;
+  const value = process.argv[positions[0] + 1];
+  if (value === undefined || value.startsWith('--')) throw new Error(`${flag} requires a value`);
+  return value;
+}
+
+function createCdpClient(webSocket, recordFailure, deadline) {
+  let nextId = 1;
+  const pending = new Map();
+
+  const rejectPending = (reason) => {
+    const error = new Error(`Chrome DevTools Protocol connection ${reason}`);
+    for (const request of pending.values()) request.reject(error);
+    pending.clear();
+  };
+  webSocket.addEventListener('close', () => rejectPending('closed'));
+  webSocket.addEventListener('error', () => rejectPending('failed'));
+
+  webSocket.addEventListener('message', (event) => {
+    const message = JSON.parse(event.data);
+    if (message.id !== undefined) {
+      const request = pending.get(message.id);
+      if (request !== undefined) {
+        pending.delete(message.id);
+        if (message.error === undefined) request.resolve(message.result);
+        else
+          request.reject(
+            new Error(`Chrome DevTools Protocol error: ${JSON.stringify(message.error)}`),
+          );
+      }
+      return;
+    }
+
+    if (message.method === 'Runtime.exceptionThrown') {
+      const failure = formatCdpException(message.params.exceptionDetails);
+      recordFailure(failure);
+      console.error(`browser exception: ${failure}`);
+    } else if (message.method === 'Runtime.consoleAPICalled') {
+      const values = message.params.args.map(
+        (argument) => argument.value ?? argument.description ?? argument.type,
+      );
+      console.error(`browser console ${message.params.type}: ${values.join(' ')}`);
+    } else if (message.method === 'Log.entryAdded') {
+      console.error(`browser log ${message.params.entry.level}: ${message.params.entry.text}`);
+    } else if (message.method === 'Target.attachedToTarget') {
+      const sessionId = message.params.sessionId;
+      void send('Runtime.enable', {}, sessionId).catch((error) => recordFailure(error.message));
+      void send('Log.enable', {}, sessionId).catch((error) => recordFailure(error.message));
+    }
+  });
+
+  function send(method, params = {}, sessionId = undefined) {
+    const id = nextId++;
+    return new Promise((resolveRequest, rejectRequest) => {
+      const timer = setTimeout(
+        () => {
+          pending.delete(id);
+          rejectRequest(new Error(`Chrome DevTools Protocol ${method} timed out`));
+        },
+        Math.max(1, Math.min(30_000, deadline - Date.now())),
+      );
+      pending.set(id, {
+        resolve(value) {
+          clearTimeout(timer);
+          resolveRequest(value);
+        },
+        reject(error) {
+          clearTimeout(timer);
+          rejectRequest(error);
+        },
+      });
+      webSocket.send(
+        JSON.stringify({ id, method, params, ...(sessionId === undefined ? {} : { sessionId }) }),
+      );
+    });
+  }
+
+  return { send };
+}
+
+function formatCdpException(details) {
+  const description = details.exception?.description ?? details.exception?.value ?? details.text;
+  const location = details.url
+    ? `${details.url}:${Number(details.lineNumber ?? 0) + 1}:${Number(details.columnNumber ?? 0) + 1}`
+    : undefined;
+  return [description, location].filter(Boolean).join('\n');
+}
+
+async function waitForChrome(url, chromePid, deadline) {
+  let lastFailure;
+  while (Date.now() < deadline) {
+    try {
+      process.kill(chromePid, 0);
+    } catch (cause) {
+      throw new Error('Chrome exited before its debugging endpoint became ready', { cause });
+    }
+    try {
+      const response = await fetch(url, {
+        signal: AbortSignal.timeout(Math.max(1, Math.min(5000, deadline - Date.now()))),
+      });
+      if (response.ok) {
+        return await response.json();
+      }
+      lastFailure = new Error(`Chrome debugging endpoint returned HTTP ${response.status}`);
+      await response.body?.cancel();
+    } catch (error) {
+      lastFailure = error;
+    }
+    await delay(200);
+  }
+  throw new Error(`browser endpoint did not become ready within the smoke budget: ${url}`, {
+    cause: lastFailure,
+  });
+}
+function delay(milliseconds) {
+  return new Promise((resolve) => setTimeout(resolve, milliseconds));
+}
diff --git a/src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh b/src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh
new file mode 100644
index 000000000..dc0fe6b51
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.sh
@@ -0,0 +1,91 @@
+#!/usr/bin/env bash
+set -euo pipefail
+# Separate process groups let the EXIT trap close Vite, Chrome and their workers.
+set -m
+# Match Node's child-process limit: OPFS needs more than the shell default of 1024.
+ulimit -Sn "$(ulimit -Hn)"
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../../../.." && pwd)"
+cd "$root"
+tool="$root/src/sdks/ts-wasix/sdk/tools/integration/smoke-browser.mts"
+report="$root/src/benchmarks/perf/wasix-browser/benchmark.mts"
+deadline="$(command -v gtimeout || command -v timeout)"
+command -v jq >/dev/null
+chrome=''
+for candidate in "${CHROME_BIN:-}" /usr/bin/google-chrome /usr/bin/chromium /usr/bin/chromium-browser; do
+  if [ -n "$candidate" ] && [ -x "$candidate" ]; then chrome="$candidate"; break; fi
+done
+[ -n "$chrome" ] || { echo 'browser smoke requires Chrome/Chromium; set CHROME_BIN' >&2; exit 1; }
+scratch="$(mktemp -d)"
+pids=()
+# Invoked by the EXIT trap, including failed launches and smoke assertions.
+# shellcheck disable=SC2317
+cleanup() {
+  status=$?
+  trap - EXIT
+  for pid in "${pids[@]}"; do kill -TERM -- "-$pid" 2>/dev/null || true; done
+  if [ "${#pids[@]}" -gt 0 ]; then sleep 2; fi
+  for pid in "${pids[@]}"; do
+    kill -KILL -- "-$pid" 2>/dev/null || true
+    wait "$pid" 2>/dev/null || true
+  done
+  if [ "$status" != 0 ]; then
+    for log in "$scratch/vite.log" "$scratch/chrome.log"; do
+      if [ -f "$log" ]; then tail -c 32768 "$log" >&2; fi
+    done
+  fi
+  rm -rf "$scratch"
+  exit "$status"
+}
+trap cleanup EXIT
+bun run --cwd "$root/src/sdks/ts-query" build
+bun pm --cwd "$root/src/sdks/ts-query" pack --filename "$scratch/query.tgz" --quiet
+bun "$tool" --prepare "$scratch" "$@"
+configuration="$scratch/browser.json"
+mode="$(jq -r '.mode' "$configuration")"
+snapshot_git() {
+  git rev-parse HEAD > "$scratch/git-commit${1:-}"
+  git rev-parse 'HEAD^{tree}' > "$scratch/git-tree${1:-}"
+  git status --porcelain=v1 --untracked-files=all > "$scratch/git-status${1:-}"
+}
+if [ "$mode" = benchmark ]; then
+  snapshot_git
+  bun "$report" --prepare "$scratch"
+fi
+packed_consumer="$(jq -r '.packedConsumer // empty' "$configuration")"
+if [ -n "$packed_consumer" ]; then
+  export OLIPHAUNT_WASIX_BROWSER_PACKAGE_ROOT="$packed_consumer"
+  (
+    cd "$OLIPHAUNT_WASIX_BROWSER_PACKAGE_ROOT"
+    NPM_CONFIG_IGNORE_SCRIPTS=true \
+      "$deadline" --kill-after=3s 120s bun install --ignore-scripts
+  )
+else
+  unset OLIPHAUNT_WASIX_BROWSER_PACKAGE_ROOT
+  bun "$root/src/sdks/ts-wasix/sdk/tools/stage-host.mts"
+fi
+vite_port="$(jq -r '.vitePort' "$configuration")"
+chrome_port="$(jq -r '.chromePort' "$configuration")"
+(cd "$root/src/sdks/ts-wasix/sdk" && OLIPHAUNT_WASIX_BROWSER_SMOKE=1 bun x --no-install vite \
+  --config "$root/src/examples/browser-wasix/vite.config.ts" --host 127.0.0.1 \
+  --port "$vite_port" --strictPort) > "$scratch/vite.log" 2>&1 &
+pids+=("$!")
+ready_deadline=$((SECONDS + 30))
+until curl --silent --fail --max-time 1 "http://127.0.0.1:$vite_port/" -o /dev/null; do
+  kill -0 "${pids[0]}"
+  [ "$SECONDS" -lt "$ready_deadline" ] || { echo 'Vite did not become ready' >&2; exit 1; }
+  sleep 0.2
+done
+"$chrome" --headless=new --no-sandbox --disable-gpu --disable-dev-shm-usage \
+  "--user-data-dir=$scratch/profile" "--remote-debugging-port=$chrome_port" \
+  about:blank > "$scratch/chrome.log" 2>&1 &
+pids+=("$!")
+printf '%s\n' "$!" > "$scratch/chrome.pid"
+seconds="$(jq -r '(.timeoutMs / 1000 | ceil) + 90' "$configuration")"
+"$deadline" --kill-after=3s "${seconds}s" bun "$tool" --run "$scratch"
+for pid in "${pids[@]}"; do kill -0 "$pid"; done
+if [ "$mode" = benchmark ]; then
+  snapshot_git -after
+  bun "$report" --report "$scratch"
+elif [ "$mode" = diagnostic ]; then
+  bun "$report" --diagnostic "$scratch"
+fi
diff --git a/src/sdks/ts-wasix/sdk/tools/integration/smoke-node.mts b/src/sdks/ts-wasix/sdk/tools/integration/smoke-node.mts
new file mode 100644
index 000000000..ab1a696b4
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/integration/smoke-node.mts
@@ -0,0 +1,80 @@
+import { readFile, writeFile } from 'node:fs/promises';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath, pathToFileURL } from 'node:url';
+
+import { stagePackedWasixConsumer } from './packed-node-fixture.mts';
+
+const { packageOnly, runtime } = readOptions(process.argv.slice(3));
+const runtimeName =
+  runtime === 'bun'
+    ? 'Bun'
+    : runtime === 'deno'
+      ? 'Deno'
+      : runtime === 'electron'
+        ? 'Electron'
+        : 'Node';
+const packageCondition = runtime === 'electron' ? 'node' : runtime;
+const storageCondition = runtime === 'electron' ? 'node' : runtime;
+const expectedEntrypoint = `index.${packageCondition}.js`;
+const expectedDirectEntrypoint = 'direct.node.js';
+const expectedWorkerEntrypoint = `worker-entry.${packageCondition}.js`;
+const expectedServerEntrypoint = 'server.node.js';
+const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../../..');
+const pgwireClientUrl = pathToFileURL(
+  resolve(repositoryRoot, 'src/sdks/ts-wasix/sdk/tools/pgwire-client.mts'),
+).href;
+if (!process.argv[2]) throw new Error('smoke-node.mts requires a scratch directory');
+const scratch = resolve(process.argv[2]);
+const fixture = await stagePackedWasixConsumer({
+  scratch,
+  consumerName: `oliphaunt-wasix-${runtime}-smoke-consumer`,
+  includePgtap: !packageOnly,
+  includeNative: !packageOnly,
+  useStubRuntime: packageOnly,
+});
+const candidate = fixture.packages.binding.name;
+const extension = fixture.packages.extension?.name;
+await writeFile(
+  resolve(fixture.consumer, 'fixture.json'),
+  JSON.stringify({
+    candidate,
+    extension,
+    runtime,
+    storageCondition,
+    runtimeName,
+    packageOnly,
+    expectedEntrypoint,
+    expectedDirectEntrypoint,
+    expectedWorkerEntrypoint,
+    expectedServerEntrypoint,
+    pgwireClientUrl,
+  }),
+);
+await writeFile(
+  resolve(fixture.consumer, 'verify.mjs'),
+  new Bun.Transpiler({ loader: 'ts' }).transformSync(
+    await readFile(new URL('./verify-host.mts', import.meta.url), 'utf8'),
+  ),
+);
+function readOptions(args) {
+  let packageOnly = false;
+  let runtime = 'node';
+  for (let index = 0; index < args.length; index += 1) {
+    const argument = args[index];
+    if (argument === '--package-only' && !packageOnly) {
+      packageOnly = true;
+      continue;
+    }
+    if (
+      argument === '--runtime' &&
+      index + 1 < args.length &&
+      ['bun', 'deno', 'electron', 'node'].includes(args[index + 1])
+    ) {
+      runtime = args[index + 1];
+      index += 1;
+      continue;
+    }
+    throw new Error('usage: smoke-node.mts [--runtime node|bun|deno|electron] [--package-only]');
+  }
+  return { packageOnly, runtime };
+}
diff --git a/src/sdks/ts-wasix/sdk/tools/integration/smoke-node.sh b/src/sdks/ts-wasix/sdk/tools/integration/smoke-node.sh
new file mode 100644
index 000000000..2fd18b1a4
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/integration/smoke-node.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../../../.." && pwd)"
+runtime=node
+args=("$@")
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --runtime) runtime="${2:?--runtime requires a value}"; shift 2 ;;
+    --package-only) shift ;;
+    *) echo "unknown smoke option: $1" >&2; exit 1 ;;
+  esac
+done
+deadline="$(command -v gtimeout || command -v timeout)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+bun run --cwd "$root/src/sdks/ts-query" build
+bun pm --cwd "$root/src/sdks/ts-query" pack --filename "$scratch/query.tgz" --quiet
+bun "$root/src/sdks/ts-wasix/sdk/tools/integration/smoke-node.mts" "$scratch" "${args[@]}"
+cd "$scratch/consumer"
+export NPM_CONFIG_IGNORE_SCRIPTS=true
+"$deadline" --kill-after=3s 120s bun install --ignore-scripts
+cp "$root/src/sdks/ts-wasix/sdk/tools/entrypoint-consumer.ts" "$scratch/consumer/entrypoint-consumer.mts"
+"$root/src/sdks/ts-wasix/sdk/node_modules/.bin/tsc" --noEmit --strict --skipLibCheck \
+  --target ES2022 --module NodeNext --moduleResolution NodeNext \
+  --customConditions "$runtime" "$scratch/consumer/entrypoint-consumer.mts"
+case "$runtime" in
+  node) host=(node) ;;
+  bun) host=(bash "$root/tools/dev/bun.sh") ;;
+  deno) host=(bash "$root/tools/dev/deno.sh" run --allow-env --allow-ffi --allow-net=127.0.0.1 --allow-read) ;;
+  electron)
+    host=(env ELECTRON_RUN_AS_NODE=1 NPM_CONFIG_IGNORE_SCRIPTS=false
+      npm exec --yes --package=electron@39.2.5 -- electron)
+    ;;
+esac
+"$deadline" --kill-after=3s 300s "${host[@]}" "$scratch/consumer/verify.mjs"
+printf 'WASIX TypeScript %s smoke passed\n' "$runtime"
diff --git a/src/sdks/ts-wasix/sdk/tools/integration/test-browser.sh b/src/sdks/ts-wasix/sdk/tools/integration/test-browser.sh
new file mode 100644
index 000000000..19cb32051
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/integration/test-browser.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")"
+bash smoke-browser.sh --postgis-worker
+bash smoke-browser.sh --package-only
diff --git a/src/sdks/ts-wasix/sdk/tools/integration/test-consumer.sh b/src/sdks/ts-wasix/sdk/tools/integration/test-consumer.sh
new file mode 100644
index 000000000..0b5381fbe
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/integration/test-consumer.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")"
+for runtime in node bun deno electron; do
+  bash smoke-node.sh --runtime "$runtime"
+done
diff --git a/src/sdks/ts-wasix/sdk/tools/integration/verify-host.mts b/src/sdks/ts-wasix/sdk/tools/integration/verify-host.mts
new file mode 100644
index 000000000..9b298f3db
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/integration/verify-host.mts
@@ -0,0 +1,527 @@
+import { rejects } from 'node:assert/strict';
+import { readFileSync } from 'node:fs';
+const fixture: {
+  candidate: string;
+  extension: string | undefined;
+  runtime: string;
+  storageCondition: string;
+  runtimeName: string;
+  packageOnly: boolean;
+  expectedEntrypoint: string;
+  expectedDirectEntrypoint: string;
+  expectedWorkerEntrypoint: string;
+  expectedServerEntrypoint: string;
+  pgwireClientUrl: string;
+} = JSON.parse(readFileSync(new URL('./fixture.json', import.meta.url), 'utf8'));
+
+import { Worker } from 'node:worker_threads';
+
+const candidate = fixture.candidate;
+await rejects(import(candidate + '/browser'), /requires a browser or browser worker/);
+const extension = fixture.extension;
+const runtime = fixture.runtime;
+const storageCondition = fixture.storageCondition;
+const runtimeName = fixture.runtimeName;
+const packageOnly = fixture.packageOnly;
+const pgtap = packageOnly ? undefined : (await import(extension)).default;
+const executionSurfaces = {
+  actor: {
+    entrypoint: candidate,
+    resolvedEntrypoint: fixture.expectedEntrypoint,
+    callingContract: 'async',
+    executionOwner: 'sdk-thread',
+  },
+  direct: {
+    entrypoint: candidate + '/direct',
+    resolvedEntrypoint: fixture.expectedDirectEntrypoint,
+    callingContract: 'async',
+    executionOwner: 'caller',
+  },
+  worker: {
+    entrypoint: candidate + '/worker',
+    resolvedEntrypoint: fixture.expectedWorkerEntrypoint,
+    callingContract: 'async',
+    executionOwner: 'sdk-worker',
+  },
+  server: {
+    entrypoint: candidate + '/server',
+    resolvedEntrypoint: fixture.expectedServerEntrypoint,
+    callingContract: 'async',
+    executionOwner: 'rust-listener',
+  },
+};
+const {
+  default: Oliphaunt,
+  PostgresError,
+  postgresOids,
+  WasixStorageError,
+} = await import(candidate);
+const { default: DirectOliphaunt } = await import(candidate + '/direct');
+const { default: WorkerOliphaunt } = await import(candidate + '/worker');
+const { openServer } = await import(candidate + '/server');
+const { directory } = await import(candidate + '/storage/' + storageCondition);
+const {
+  connect,
+  onceClosed,
+  onceConnected,
+  readExchange,
+  simpleQuery: wireSimpleQuery,
+  startupPacket,
+} = await import(fixture.pgwireClientUrl);
+const simpleQuery = (sql) => {
+  const body = new TextEncoder().encode(sql + '\0');
+  const message = new Uint8Array(body.length + 5);
+  message[0] = 0x51;
+  new DataView(message.buffer).setUint32(1, body.length + 4);
+  message.set(body, 5);
+  return message;
+};
+
+const resolved = import.meta.resolve(candidate);
+if (!resolved.endsWith('/lib/' + fixture.expectedEntrypoint + '')) {
+  throw new Error(runtimeName + ' did not select its actor entrypoint: ' + resolved);
+}
+const directResolved = import.meta.resolve(candidate + '/direct');
+if (!directResolved.endsWith('/lib/' + fixture.expectedDirectEntrypoint + '')) {
+  throw new Error(runtimeName + ' did not select its direct entrypoint: ' + directResolved);
+}
+const workerResolved = import.meta.resolve(candidate + '/worker');
+if (!workerResolved.endsWith('/lib/' + fixture.expectedWorkerEntrypoint + '')) {
+  throw new Error(runtimeName + ' did not select its Worker entrypoint: ' + workerResolved);
+}
+const serverResolved = import.meta.resolve(candidate + '/server');
+if (!serverResolved.endsWith('/lib/' + fixture.expectedServerEntrypoint + '')) {
+  throw new Error(runtimeName + ' did not select its server entrypoint: ' + serverResolved);
+}
+if (!packageOnly) {
+  const callerSource = [
+    "import { parentPort, workerData } from 'node:worker_threads';",
+    'const { default: DirectOliphaunt } = await import(' + JSON.stringify(directResolved) + ');',
+    'const { default: WorkerOliphaunt } = await import(' + JSON.stringify(workerResolved) + ');',
+    'const { directory } = await import(' +
+      JSON.stringify(import.meta.resolve(candidate + '/storage/' + storageCondition)) +
+      ');',
+    'const finishWorker = () => {',
+    "  if (workerData.runtime === 'bun') return process.exit(0);",
+    '  parentPort.close?.();',
+    '  parentPort.unref();',
+    '};',
+    'try {',
+    '  const direct = await DirectOliphaunt.open({ storage: directory(' +
+      JSON.stringify(new URL('./caller-worker-storage', import.meta.url).href) +
+      ') });',
+    "  const directAnswer = (await direct.queryRaw('SELECT 42::int AS answer')).getText(0, 'answer');",
+    '  await direct.close();',
+    '  const nestedWorker = await WorkerOliphaunt.open();',
+    "  const workerAnswer = (await nestedWorker.queryRaw('SELECT 43::int AS answer')).getText(0, 'answer');",
+    '  await nestedWorker.close();',
+    '  parentPort.postMessage({ directAnswer, workerAnswer });',
+    '  finishWorker();',
+    '} catch (error) {',
+    '  parentPort.postMessage({ name: error?.name, message: error?.message });',
+    '  finishWorker();',
+    '}',
+  ].join('\n');
+  const callerResults = [];
+  for (let iteration = 1; iteration <= 2; iteration += 1) {
+    const worker = new Worker(new URL('data:text/javascript,' + encodeURIComponent(callerSource)), {
+      name: 'oliphaunt-caller-worker-check-' + iteration,
+      workerData: { runtime },
+    });
+    let callerResult;
+    let exitObserved = false;
+    try {
+      callerResult = await new Promise((resolveResult, rejectResult) => {
+        let message;
+        worker.once('message', (value) => {
+          message = value;
+        });
+        worker.once('error', rejectResult);
+        worker.once('exit', (code) => {
+          exitObserved = true;
+          if (code !== 0) {
+            rejectResult(new Error('caller worker exited with code ' + code));
+          } else if (message === undefined) {
+            rejectResult(new Error('caller worker self-exited without a result'));
+          } else {
+            resolveResult(message);
+          }
+        });
+      });
+    } finally {
+      // Forced termination is only failure cleanup. Bun does not settle a
+      // redundant terminate() after a Worker has emitted its exit event.
+      if (!exitObserved) await worker.terminate();
+    }
+    if (callerResult?.directAnswer !== '42' || callerResult?.workerAnswer !== '43') {
+      throw new Error('caller-worker execution failed: ' + JSON.stringify(callerResult));
+    }
+    callerResults.push(callerResult);
+  }
+  if (callerResults.length !== 2) {
+    throw new Error('caller-worker repetition failed');
+  }
+}
+
+if (packageOnly) {
+  const storage = directory(new URL('./package-condition-storage', import.meta.url));
+  if (!Object.isFrozen(storage) || Reflect.ownKeys(storage).length !== 0) {
+    throw new Error(runtimeName + ' storage condition returned an invalid adapter');
+  }
+  console.log(
+    JSON.stringify({
+      host: runtime + '-package-condition-actor-direct-worker',
+      executionSurfaces,
+      storage: runtime + '-directory',
+    }),
+  );
+} else {
+  async function verifyMemory(client, executionSurface) {
+    // OLIPHAUNT_DOCS_SNIPPET wasix-typescript-quickstart
+    const db = await client.open({ extensions: [pgtap] });
+    await db.execute('CREATE EXTENSION pgtap');
+    const structuredApi = await verifyStructuredApi(db);
+    const version = (await db.queryRaw('SELECT pgtap_version()::text AS version')).getText(
+      0,
+      'version',
+    );
+    const retainedProtocol = await db.execProtocolRaw(
+      simpleQuery("SELECT repeat('a', 8192) AS retained_payload"),
+    );
+    const retainedSnapshot = retainedProtocol.slice();
+    await db.execProtocolRaw(simpleQuery("SELECT repeat('z', 8192) AS replacement_payload"));
+    const protocolResponseOwned =
+      retainedProtocol.length === retainedSnapshot.length &&
+      retainedProtocol.every((byte, index) => byte === retainedSnapshot[index]);
+    const wallClockMillis = Number(
+      (
+        await db.queryRaw('SELECT (extract(epoch FROM clock_timestamp()) * 1000)::bigint AS millis')
+      ).getText(0, 'millis'),
+    );
+    const wallClockDeltaMillis = Math.abs(Date.now() - wallClockMillis);
+    const explain = JSON.parse(
+      (await db.queryRaw('EXPLAIN (ANALYZE, FORMAT JSON) SELECT pg_sleep(0.05)')).getText(
+        0,
+        'QUERY PLAN',
+      ),
+    );
+    const monotonicElapsedMillis = explain[0]?.['Execution Time'];
+    await db.execute('CREATE TABLE smoke_transaction (value integer NOT NULL)');
+    const transactionValue = await db.transaction(async (tx) => {
+      await tx.execute('INSERT INTO smoke_transaction VALUES ($1)', [7]);
+      return (await tx.queryRaw('SELECT value::text AS value FROM smoke_transaction')).getText(
+        0,
+        'value',
+      );
+    });
+    const rollbackSentinel = new Error('packed transaction rollback sentinel');
+    try {
+      await db.transaction(async (tx) => {
+        await tx.execute('INSERT INTO smoke_transaction VALUES ($1)', [9]);
+        throw rollbackSentinel;
+      });
+      throw new Error('failed packed transaction unexpectedly committed');
+    } catch (error) {
+      if (error !== rollbackSentinel) throw error;
+    }
+    const transactionRows = (
+      await db.queryRaw('SELECT count(*)::int AS count FROM smoke_transaction')
+    ).getText(0, 'count');
+    let sqlstate;
+    try {
+      await db.queryRaw('SELEC 1');
+    } catch (error) {
+      if (!(error instanceof PostgresError)) throw error;
+      sqlstate = error.sqlstate;
+    }
+    const answer = (await db.queryRaw('SELECT 42::int AS answer')).getText(0, 'answer');
+    await db[Symbol.asyncDispose]();
+    const result = {
+      version,
+      protocolResponseOwned,
+      wallClockDeltaMillis,
+      monotonicElapsedMillis,
+      transactionValue,
+      transactionRows,
+      sqlstate,
+      answer,
+      structuredApi,
+    };
+    if (
+      !version ||
+      !protocolResponseOwned ||
+      wallClockDeltaMillis > 5_000 ||
+      !Number.isFinite(monotonicElapsedMillis) ||
+      monotonicElapsedMillis < 25 ||
+      monotonicElapsedMillis > 5_000 ||
+      transactionValue !== '7' ||
+      transactionRows !== '1' ||
+      sqlstate !== '42601' ||
+      answer !== '42' ||
+      structuredApi !== '42:9007199254740993:3:custom:42:42:2'
+    ) {
+      throw new Error(executionSurface + ': ' + JSON.stringify(result));
+    }
+    return result;
+  }
+
+  async function verifyStructuredApi(db) {
+    const decoded = await db.query(
+      'SELECT $1::int4 AS answer, $2::int8 AS wide, $3::jsonb AS document, $4::int4[] AS numbers',
+      [42, 9007199254740993n, { ok: true }, [1, 2, 3]],
+    );
+    const objectRow = decoded.rows[0];
+    if (
+      objectRow?.answer !== 42 ||
+      objectRow?.wide !== '9007199254740993' ||
+      objectRow?.document?.ok !== true ||
+      JSON.stringify(objectRow?.numbers) !== '[1,2,3]'
+    ) {
+      throw new Error('decoded object-row contract failed: ' + JSON.stringify(objectRow));
+    }
+
+    const positional = await db.query('SELECT 41::int4 AS left, 42::int4 AS right', [], {
+      rowMode: 'array',
+    });
+    if (JSON.stringify(positional.rows) !== '[[41,42]]') {
+      throw new Error('decoded array-row contract failed: ' + JSON.stringify(positional.rows));
+    }
+
+    const custom = await db.query('SELECT 42::int4 AS answer', [], {
+      decoders: {
+        [postgresOids.int4]: (value, field) => 'custom:' + value + ':' + field.typeOid,
+      },
+    });
+    if (custom.rows[0]?.answer !== 'custom:42:23') {
+      throw new Error('OID decoder contract failed: ' + JSON.stringify(custom.rows));
+    }
+
+    const description = await db.describe('SELECT $1::int4 AS answer');
+    if (
+      description.parameterTypeOids[0] !== postgresOids.int4 ||
+      description.fields?.[0]?.typeOid !== postgresOids.int4
+    ) {
+      throw new Error('describe contract failed: ' + JSON.stringify(description));
+    }
+
+    const execution = await db.exec('SELECT 1::int4 AS first; SELECT 2::int4 AS second');
+    if (
+      execution.statements.length !== 2 ||
+      execution.statements[0]?.rows[0]?.first !== 1 ||
+      execution.statements[1]?.rows[0]?.second !== 2
+    ) {
+      throw new Error('multi-statement exec contract failed: ' + JSON.stringify(execution));
+    }
+
+    return [
+      objectRow.answer,
+      objectRow.wide,
+      objectRow.numbers.length,
+      String(custom.rows[0].answer).split(':').slice(0, 2).join(':'),
+      positional.rows[0][1],
+      execution.statements.length,
+    ].join(':');
+  }
+
+  async function verifyServer() {
+    const server = await openServer();
+    const socket = connect(server.connectionString);
+    let startup;
+    let query;
+    try {
+      await onceConnected(socket);
+      const startupResponse = readExchange(socket);
+      socket.write(startupPacket('postgres', 'postgres'));
+      startup = await startupResponse;
+      const queryResponse = readExchange(socket);
+      socket.write(wireSimpleQuery('SELECT 42::int AS answer'));
+      query = await queryResponse;
+    } finally {
+      socket.end();
+      await onceClosed(socket);
+      await server.close();
+    }
+    if (!server.closed || startup.messages < 1 || query.messages < 3 || query.totalBytes < 6) {
+      throw new Error('server: ' + JSON.stringify({ closed: server.closed, startup, query }));
+    }
+    return { connection: 'tcp-loopback', startup, query };
+  }
+
+  const actor = await verifyMemory(Oliphaunt, 'actor');
+  const direct = await verifyMemory(DirectOliphaunt, 'direct');
+  const worker = await verifyMemory(WorkerOliphaunt, 'worker');
+  const server = await verifyServer();
+  if (actor.version !== direct.version || direct.version !== worker.version) {
+    throw new Error(
+      'entrypoint extension versions differ: ' + JSON.stringify({ actor, direct, worker }),
+    );
+  }
+
+  const storage = directory(new URL('./database space ü', import.meta.url));
+  let persistent = await Oliphaunt.open({ storage, extensions: [pgtap] });
+  await persistent.execute('CREATE EXTENSION pgtap');
+  await persistent.execute('CREATE SEQUENCE smoke_persistence_seq START WITH 10');
+  await persistent.execute(
+    'CREATE TABLE smoke_persistence (' +
+      "ordinal bigint PRIMARY KEY DEFAULT nextval('smoke_persistence_seq'), " +
+      'label text NOT NULL, payload bytea NOT NULL, optional_value text NULL)',
+  );
+  await persistent.execute(
+    'CREATE UNIQUE INDEX smoke_persistence_label_idx ON smoke_persistence(label)',
+  );
+  await persistent.execute(
+    'INSERT INTO smoke_persistence(label, payload, optional_value) VALUES ' +
+      "('café 🐘', decode('00ff10', 'hex'), NULL), " +
+      "('東京', decode('deadbeef', 'hex'), 'present'), " +
+      "('mañana', decode('', 'hex'), NULL)",
+  );
+  await persistent.execute('CREATE TEMP TABLE smoke_direct_session(value text NOT NULL)');
+  await persistent.execute("INSERT INTO smoke_direct_session VALUES ('direct-session')");
+  await persistent.execute("SET application_name = 'packed-direct-session'");
+  await persistent.execute('CHECKPOINT');
+  let busy;
+  try {
+    await WorkerOliphaunt.open({ storage, extensions: [pgtap] });
+  } catch (error) {
+    if (!(error instanceof WasixStorageError)) throw error;
+    busy = error.code;
+  }
+  const directArchive = await persistent.backup();
+  const directSessionState = (
+    await persistent.queryRaw(
+      "SELECT (SELECT value FROM smoke_direct_session) || ':' || current_setting('application_name') AS value",
+    )
+  ).getText(0, 'value');
+  await persistent.close();
+
+  persistent = await WorkerOliphaunt.open({ storage, extensions: [pgtap] });
+  const workerPersistedRows = (
+    await persistent.queryRaw('SELECT count(*)::int AS count FROM smoke_persistence')
+  ).getText(0, 'count');
+  const persistentExtension = (
+    await persistent.queryRaw('SELECT pgtap_version()::text AS version')
+  ).getText(0, 'version');
+  await persistent.execute(
+    'INSERT INTO smoke_persistence(label, payload, optional_value) ' +
+      "VALUES ('naïve', decode('010203', 'hex'), NULL)",
+  );
+  await persistent.execute('CREATE TEMP TABLE smoke_worker_session(value text NOT NULL)');
+  await persistent.execute("INSERT INTO smoke_worker_session VALUES ('worker-session')");
+  await persistent.execute("SET application_name = 'packed-worker-session'");
+  await persistent.execute('CHECKPOINT');
+  const workerArchive = await persistent.backup();
+  const workerSessionState = (
+    await persistent.queryRaw(
+      "SELECT (SELECT value FROM smoke_worker_session) || ':' || current_setting('application_name') AS value",
+    )
+  ).getText(0, 'value');
+  await persistent.close();
+
+  const directRestoreStorage = directory(new URL('./direct-backup-restore', import.meta.url));
+  await WorkerOliphaunt.restore(directRestoreStorage, directArchive);
+  let restored = await WorkerOliphaunt.open({
+    storage: directRestoreStorage,
+    extensions: [pgtap],
+  });
+  const directBackupRows = (
+    await restored.queryRaw('SELECT count(*)::int AS count FROM smoke_persistence')
+  ).getText(0, 'count');
+  const directBackupValues = await richBackupValues(restored);
+  const directBackupSequence = (
+    await restored.queryRaw("SELECT nextval('smoke_persistence_seq')::text AS value")
+  ).getText(0, 'value');
+  await restored.close();
+
+  const workerRestoreStorage = directory(new URL('./worker-backup-restore', import.meta.url));
+  await Oliphaunt.restore(workerRestoreStorage, workerArchive);
+  restored = await Oliphaunt.open({
+    storage: workerRestoreStorage,
+    extensions: [pgtap],
+  });
+  const workerBackupRows = (
+    await restored.queryRaw('SELECT count(*)::int AS count FROM smoke_persistence')
+  ).getText(0, 'count');
+  const workerBackupValues = await richBackupValues(restored);
+  const workerBackupSequence = (
+    await restored.queryRaw("SELECT nextval('smoke_persistence_seq')::text AS value")
+  ).getText(0, 'value');
+  await restored.close();
+  let corruptRestore;
+  try {
+    await WorkerOliphaunt.restore(
+      directory(new URL('./corrupt-backup-restore', import.meta.url)),
+      Uint8Array.of(1, 2, 3),
+    );
+  } catch (error) {
+    if (!(error instanceof WasixStorageError)) throw error;
+    corruptRestore = error.code + ':' + error.commitState;
+  }
+  if (
+    busy !== 'busy' ||
+    workerPersistedRows !== '3' ||
+    directBackupRows !== '3' ||
+    workerBackupRows !== '4' ||
+    directBackupValues !== 'café 🐘:00ff10:NULL|mañana::NULL|東京:deadbeef:present' ||
+    workerBackupValues !==
+      'café 🐘:00ff10:NULL|mañana::NULL|naïve:010203:NULL|東京:deadbeef:present' ||
+    directBackupSequence !== '13' ||
+    workerBackupSequence !== '14' ||
+    directSessionState !== 'direct-session:packed-direct-session' ||
+    workerSessionState !== 'worker-session:packed-worker-session' ||
+    corruptRestore !== 'corrupt:unchanged' ||
+    persistentExtension !== actor.version
+  ) {
+    throw new Error(
+      JSON.stringify({
+        busy,
+        workerPersistedRows,
+        directBackupRows,
+        workerBackupRows,
+        directBackupValues,
+        workerBackupValues,
+        directBackupSequence,
+        workerBackupSequence,
+        directSessionState,
+        workerSessionState,
+        corruptRestore,
+        persistentExtension,
+        version: actor.version,
+      }),
+    );
+  }
+  console.log(
+    JSON.stringify({
+      host: runtime + '-actor-direct-worker',
+      executionSurfaces,
+      surfaceResults: { actor, direct, worker, server },
+      extension: 'pgtap',
+      version: actor.version,
+      storage: runtime + '-raw-pgdata-delta',
+      busy,
+      workerPersistedRows,
+      backupRestore: {
+        directBackupRows,
+        workerBackupRows,
+        directBackupSequence,
+        workerBackupSequence,
+        corruptRestore,
+      },
+    }),
+  );
+
+  async function richBackupValues(db) {
+    const index = (
+      await db.queryRaw("SELECT to_regclass('smoke_persistence_label_idx')::text AS value")
+    ).getText(0, 'value');
+    if (index !== 'smoke_persistence_label_idx') {
+      throw new Error('restored physical backup omitted smoke_persistence_label_idx: ' + index);
+    }
+    return (
+      await db.queryRaw(
+        "SELECT string_agg(label || ':' || encode(payload, 'hex') || ':' || " +
+          "coalesce(optional_value, 'NULL'), '|' ORDER BY label COLLATE \"C\") AS value " +
+          'FROM smoke_persistence',
+      )
+    ).getText(0, 'value');
+  }
+}
diff --git a/src/sdks/ts-wasix/sdk/tools/package.mts b/src/sdks/ts-wasix/sdk/tools/package.mts
new file mode 100755
index 000000000..6148a2a27
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/package.mts
@@ -0,0 +1,67 @@
+#!/usr/bin/env bun
+import {
+  copyFileSync,
+  cpSync,
+  existsSync,
+  mkdirSync,
+  readFileSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { stageReleaseNotices } from '../../../../../tools/packaging/release-notices.mts';
+
+export const ROOT = path.resolve(import.meta.dirname, '../../../../..');
+const SOURCE = path.join(ROOT, 'src/sdks/ts-wasix/sdk');
+const RUNTIME = '@oliphaunt/liboliphaunt-wasix';
+const NATIVE = [
+  '@oliphaunt/wasix-napi-darwin-arm64',
+  '@oliphaunt/wasix-napi-linux-arm64-gnu',
+  '@oliphaunt/wasix-napi-linux-x64-gnu',
+  '@oliphaunt/wasix-napi-win32-x64-msvc',
+];
+
+export function prepareWasixTypescriptPackage(packageDir) {
+  const manifestFile = path.join(packageDir, 'package.json');
+  const manifest = JSON.parse(readFileSync(manifestFile, 'utf8'));
+  const runtimeVersion = manifest.oliphaunt?.runtimeVersion;
+  const nativeVersion = manifest.oliphaunt?.wasixNapiVersion;
+  if (![runtimeVersion, nativeVersion].every((version) => /^\d+\.\d+\.\d+$/u.test(version))) {
+    throw new Error('WASIX TypeScript package requires exact runtime and Node-API versions');
+  }
+
+  manifest.dependencies = Object.fromEntries(
+    Object.entries({
+      ...(manifest.dependencies ?? {}),
+      [RUNTIME]: runtimeVersion,
+    }).sort(),
+  );
+  manifest.optionalDependencies = Object.fromEntries(NATIVE.map((name) => [name, nativeVersion]));
+  delete manifest.devDependencies;
+  delete manifest.scripts;
+  writeFileSync(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`);
+  stageReleaseNotices(packageDir, { profile: 'source-sdk' });
+  return manifest;
+}
+
+export function stageWasixTypescriptPackage(outputDir) {
+  const destination = path.resolve(ROOT, outputDir);
+  const relative = path.relative(ROOT, destination);
+  if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
+    throw new Error(`WASIX TypeScript package stage must stay inside the repository: ${outputDir}`);
+  }
+  rmSync(destination, { recursive: true, force: true });
+  mkdirSync(destination, { recursive: true });
+  const manifest = JSON.parse(readFileSync(path.join(SOURCE, 'package.json'), 'utf8'));
+  copyFileSync(path.join(SOURCE, 'package.json'), path.join(destination, 'package.json'));
+  for (const name of manifest.files ?? []) {
+    const source = path.join(SOURCE, name);
+    if (existsSync(source)) cpSync(source, path.join(destination, name), { recursive: true });
+  }
+  return prepareWasixTypescriptPackage(destination);
+}
+
+if (import.meta.main) {
+  const output = process.argv[2] ?? 'target/oliphaunt-wasix-ts/package';
+  stageWasixTypescriptPackage(output);
+}
diff --git a/src/sdks/ts-wasix/sdk/tools/package.sh b/src/sdks/ts-wasix/sdk/tools/package.sh
new file mode 100644
index 000000000..d1ff8351b
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/package.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../../../../.."
+bun src/sdks/ts-wasix/sdk/tools/package.mts target/oliphaunt-wasix-ts/package
+bun src/sdks/ts-wasix/sdk/tools/stage-host.mts --package
+mkdir -p target/oliphaunt-wasix-ts/package/packages
+bun pm --cwd target/oliphaunt-wasix-ts/package pack --quiet --destination packages
+bun src/sdks/ts-wasix/sdk/tools/stage-release-artifacts.mts
+bun src/sdks/ts-wasix/sdk/tools/check-package.mts
diff --git a/src/bindings/wasix-ts/tools/pgwire-client.mjs b/src/sdks/ts-wasix/sdk/tools/pgwire-client.mts
similarity index 100%
rename from src/bindings/wasix-ts/tools/pgwire-client.mjs
rename to src/sdks/ts-wasix/sdk/tools/pgwire-client.mts
diff --git a/src/sdks/ts-wasix/sdk/tools/stage-host.mts b/src/sdks/ts-wasix/sdk/tools/stage-host.mts
new file mode 100644
index 000000000..686135bad
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/stage-host.mts
@@ -0,0 +1,79 @@
+import { copyFile, mkdir, rm } from 'node:fs/promises';
+import { dirname, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import ts from 'typescript';
+
+const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
+const repositoryRoot = resolve(packageRoot, '../../../..');
+const source = resolve(repositoryRoot, 'target/oliphaunt-wasix-ts/host/wasmer-sdk');
+const destination = process.argv.includes('--package')
+  ? resolve(repositoryRoot, 'target/oliphaunt-wasix-ts/package/lib/host')
+  : resolve(packageRoot, 'lib/host');
+
+assertHostDeclarationCompatibility();
+
+await rm(destination, { force: true, recursive: true });
+await mkdir(destination, { recursive: true });
+
+for (const [sourcePath, name] of [
+  [resolve(source, 'dist/index.mjs'), 'index.mjs'],
+  [resolve(source, 'dist/worker.mjs'), 'worker.mjs'],
+  [resolve(source, 'dist/wasmer_js_bg.wasm'), 'wasmer_js_bg.wasm'],
+  [resolve(packageRoot, 'src/host/index.d.mts'), 'index.d.mts'],
+  [resolve(source, 'LICENSE'), 'LICENSE'],
+  [resolve(source, 'provenance.json'), 'provenance.json'],
+]) {
+  await copyFile(sourcePath, resolve(destination, name));
+}
+
+console.log(`wasix-ts host stage: wrote package-relative host to ${destination}`);
+
+function assertHostDeclarationCompatibility() {
+  const virtualFile = resolve(packageRoot, '.host-abi-check.mts');
+  const sourceText = [
+    "import * as generated from '../../../../target/oliphaunt-wasix-ts/host/wasmer-sdk/dist/index.mjs';",
+    "import * as curated from './src/host/index.mjs';",
+    'const compatible: typeof curated = generated;',
+    'void compatible;',
+    '// @ts-expect-error Instance handles are created by runWasix.',
+    'new curated.Instance();',
+    '// @ts-expect-error Direct handles are created by instantiateOliphauntDirect.',
+    'new curated.OliphauntDirectInstance();',
+  ].join('\n');
+  const compilerOptions = {
+    noEmit: true,
+    strict: true,
+    skipLibCheck: true,
+    target: ts.ScriptTarget.ES2022,
+    module: ts.ModuleKind.NodeNext,
+    moduleResolution: ts.ModuleResolutionKind.NodeNext,
+    lib: ['lib.es2023.d.ts', 'lib.dom.d.ts', 'lib.dom.iterable.d.ts', 'lib.webworker.d.ts'],
+    types: [],
+  };
+  const defaultHost = ts.createCompilerHost(compilerOptions);
+  const isVirtual = (path) => resolve(path) === virtualFile;
+  const compilerHost = {
+    ...defaultHost,
+    fileExists: (path) => isVirtual(path) || defaultHost.fileExists(path),
+    readFile: (path) => (isVirtual(path) ? sourceText : defaultHost.readFile(path)),
+    getSourceFile: (path, languageVersion, onError, shouldCreateNewSourceFile) =>
+      isVirtual(path)
+        ? ts.createSourceFile(path, sourceText, languageVersion, true, ts.ScriptKind.TS)
+        : defaultHost.getSourceFile(path, languageVersion, onError, shouldCreateNewSourceFile),
+  };
+  const program = ts.createProgram([virtualFile], compilerOptions, compilerHost);
+  const diagnostics = ts.getPreEmitDiagnostics(program);
+  if (diagnostics.length > 0) {
+    throw new Error(
+      `curated WASIX host declaration is incompatible with generated host ABI:\n${ts.formatDiagnosticsWithColorAndContext(
+        diagnostics,
+        {
+          getCanonicalFileName: (path) => path,
+          getCurrentDirectory: () => packageRoot,
+          getNewLine: () => '\n',
+        },
+      )}`,
+    );
+  }
+}
diff --git a/src/sdks/ts-wasix/sdk/tools/stage-release-artifacts.mts b/src/sdks/ts-wasix/sdk/tools/stage-release-artifacts.mts
new file mode 100644
index 000000000..5f7452c85
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/stage-release-artifacts.mts
@@ -0,0 +1,17 @@
+import { copyFileSync } from 'node:fs';
+import path from 'node:path';
+
+import { ROOT, fail, filesUnder } from '../../../../../tools/packaging/staging.mts';
+
+export function stageArtifacts(artifactRoot) {
+  const archives = filesUnder(path.join(ROOT, 'target/oliphaunt-wasix-ts/package/packages')).filter(
+    (file) => file.endsWith('.tgz'),
+  );
+  if (archives.length !== 1)
+    fail(`expected one WASIX TypeScript package, found ${archives.length}`);
+  const archive = archives[0];
+  copyFileSync(archive, path.join(artifactRoot, path.basename(archive)));
+}
+
+import { stageSdkArtifacts } from '../../../../../tools/packaging/staging.mts';
+if (import.meta.main) await stageSdkArtifacts('oliphaunt-wasix-ts', stageArtifacts);
diff --git a/src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.mts b/src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.mts
new file mode 100644
index 000000000..da28d0f62
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.mts
@@ -0,0 +1,166 @@
+import path from 'node:path';
+
+import { prepareWasixTypescriptPackage as prepareProductPackage } from './package.mts';
+const QUERY_PACKAGE = '@oliphaunt/ts-query';
+
+import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  assertReleaseNoticesInArchive,
+  assertReleaseNoticesInDirectory,
+  releasePackageLicense,
+} from '../../../../../tools/packaging/release-notices.mts';
+
+const TOOL = 'wasix-typescript-package.mts';
+const PACKAGE_NAME = '@oliphaunt/wasix-ts';
+const RUNTIME_PACKAGE = '@oliphaunt/liboliphaunt-wasix';
+const FZSTD_PACKAGE = 'fzstd';
+const FZSTD_VERSION = '0.1.1';
+const NATIVE_PRODUCT = 'oliphaunt-wasix-napi';
+const NATIVE_PACKAGES = Object.freeze([
+  '@oliphaunt/wasix-napi-darwin-arm64',
+  '@oliphaunt/wasix-napi-linux-arm64-gnu',
+  '@oliphaunt/wasix-napi-linux-x64-gnu',
+  '@oliphaunt/wasix-napi-win32-x64-msvc',
+]);
+const NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' });
+
+function fail(message) {
+  throw new Error(`${TOOL}: ${message}`);
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function sortedKeys(value) {
+  return Object.keys(value ?? {}).sort(compareText);
+}
+
+export function assertWasixTypescriptManifest(manifest, label = `${PACKAGE_NAME} package.json`) {
+  if (
+    manifest.name !== PACKAGE_NAME ||
+    typeof manifest.version !== 'string' ||
+    !/^\d+\.\d+\.\d+$/u.test(manifest.version) ||
+    manifest.private === true ||
+    manifest.license !== releasePackageLicense().spdx ||
+    manifest.type !== 'module' ||
+    manifest.publishConfig?.access !== 'public' ||
+    manifest.publishConfig?.provenance !== true
+  ) {
+    fail(`${label} is not the stable-version public ESM ${PACKAGE_NAME} package`);
+  }
+  if (manifest.scripts !== undefined || manifest.devDependencies !== undefined) {
+    fail(`${label} must not publish development scripts or dependencies`);
+  }
+  const dependencies = manifest.dependencies ?? {};
+  const optionalDependencies = manifest.optionalDependencies ?? {};
+  const expectedDependencies = [FZSTD_PACKAGE, QUERY_PACKAGE, RUNTIME_PACKAGE].sort(compareText);
+  const nativeVersion = manifest.oliphaunt?.wasixNapiVersion;
+  if (
+    JSON.stringify(sortedKeys(dependencies)) !== JSON.stringify(expectedDependencies) ||
+    typeof dependencies[RUNTIME_PACKAGE] !== 'string' ||
+    !/^\d+\.\d+\.\d+$/u.test(dependencies[RUNTIME_PACKAGE]) ||
+    dependencies[FZSTD_PACKAGE] !== FZSTD_VERSION ||
+    !/^\d+\.\d+\.\d+$/u.test(dependencies[QUERY_PACKAGE]) ||
+    typeof nativeVersion !== 'string' ||
+    !/^\d+\.\d+\.\d+$/u.test(nativeVersion) ||
+    JSON.stringify(sortedKeys(optionalDependencies)) !==
+      JSON.stringify([...NATIVE_PACKAGES].sort(compareText)) ||
+    NATIVE_PACKAGES.some((name) => optionalDependencies[name] !== nativeVersion) ||
+    sortedKeys(manifest.peerDependencies).length !== 0 ||
+    manifest.peerDependenciesMeta !== undefined ||
+    manifest.bundledDependencies !== undefined ||
+    manifest.bundleDependencies !== undefined
+  ) {
+    fail(
+      `${label} must depend only on its query package, portable runtime, decompressor, and native platform carriers`,
+    );
+  }
+  if (
+    manifest.engines?.node !== '>=22.13 <25' ||
+    manifest.engines?.bun !== '>=1.3.14' ||
+    manifest.engines?.deno !== '>=2.8.1'
+  ) {
+    fail(`${label} must declare the qualified Node, Bun, and Deno runtime floors`);
+  }
+  if (
+    manifest.oliphaunt?.runtimeProduct !== 'liboliphaunt-wasix' ||
+    manifest.oliphaunt?.runtimeVersion !== dependencies[RUNTIME_PACKAGE] ||
+    manifest.oliphaunt?.wasixNapiProduct !== NATIVE_PRODUCT ||
+    manifest.oliphaunt?.wasixAddonAbiVersion !== 2 ||
+    manifest.oliphaunt?.nodeApiVersion !== 8 ||
+    manifest.oliphaunt?.browserHost !== 'wasmer-js-patched' ||
+    manifest.oliphaunt?.serverHost !== 'wasix-rust-napi'
+  ) {
+    fail(`${label} runtime compatibility metadata differs from its exact dependencies`);
+  }
+  return manifest;
+}
+
+export function prepareWasixTypescriptPackage(packageDir) {
+  const root = path.resolve(packageDir);
+  const manifest = prepareProductPackage(root);
+  assertReleaseNoticesInDirectory(root, NOTICE_OPTIONS);
+  assertWasixTypescriptManifest(manifest, `${PACKAGE_NAME} staged package.json`);
+  return manifest;
+}
+
+export function assertWasixTypescriptNpmArchive(archive) {
+  const file = path.resolve(archive);
+  assertReleaseNoticesInArchive(file, {
+    ...NOTICE_OPTIONS,
+    prefix: 'package',
+    label: path.basename(file),
+  });
+  const entries = readPortableArchiveEntries(file);
+  const requireFile = (name) => {
+    const entry = entries.get(`package/${name}`);
+    if (!entry?.isFile || entry.isSymbolicLink || entry.size <= 0) {
+      fail(`${path.basename(file)} is missing non-empty regular package/${name}`);
+    }
+    return Buffer.from(entry.data());
+  };
+  const manifest = assertWasixTypescriptManifest(
+    JSON.parse(requireFile('package.json').toString('utf8')),
+    `${path.basename(file)} package.json`,
+  );
+  const packageFiles = [
+    'ARCHITECTURE.md',
+    'CHANGELOG.md',
+    'LICENSE',
+    'README.md',
+    'THIRD_PARTY_NOTICES.md',
+    'lib',
+  ];
+  if (
+    JSON.stringify([...(manifest.files ?? [])].sort(compareText)) !== JSON.stringify(packageFiles)
+  ) {
+    fail(`${path.basename(file)} package.json files differ from the owned package roots`);
+  }
+  const allowedFiles = new Set([
+    'package.json',
+    ...manifest.files.filter((name) => name !== 'lib'),
+  ]);
+  for (const [name, entry] of entries) {
+    if (entry.isSymbolicLink) fail(`${path.basename(file)} contains symbolic link ${name}`);
+    const relative = name.replace(/^package\//u, '');
+    if (entry.isFile && !allowedFiles.has(relative) && !relative.startsWith('lib/')) {
+      fail(`${path.basename(file)} contains file outside package.json files: ${name}`);
+    }
+  }
+  for (const name of manifest.files) {
+    if (name === 'lib' || (name === 'CHANGELOG.md' && manifest.version === '0.0.0')) continue;
+    requireFile(name);
+  }
+  const exportedFiles = new Set();
+  const visit = (value) => {
+    if (typeof value === 'string' && value.startsWith('./')) exportedFiles.add(value.slice(2));
+    else if (value && typeof value === 'object') Object.values(value).forEach(visit);
+  };
+  visit(manifest.exports);
+  for (const name of exportedFiles) {
+    requireFile(name);
+  }
+  JSON.parse(requireFile('lib/host/provenance.json').toString('utf8'));
+  return manifest;
+}
diff --git a/src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.test.mts b/src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.test.mts
new file mode 100644
index 000000000..2d3b06006
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tools/wasix-typescript-package.test.mts
@@ -0,0 +1,100 @@
+import { describe, expect, test } from 'bun:test';
+
+import { assertWasixTypescriptManifest } from './wasix-typescript-package.mts';
+
+function manifest() {
+  return {
+    name: '@oliphaunt/wasix-ts',
+    version: '1.2.3',
+    license: 'MIT',
+    type: 'module',
+    sideEffects: ['./lib/browser.js', './lib/native-only.js'],
+    publishConfig: { access: 'public', provenance: true },
+    dependencies: {
+      '@oliphaunt/ts-query': '0.1.0',
+      '@oliphaunt/liboliphaunt-wasix': '1.2.3',
+      fzstd: '0.1.1',
+    },
+    optionalDependencies: {
+      '@oliphaunt/wasix-napi-darwin-arm64': '1.2.3',
+      '@oliphaunt/wasix-napi-linux-arm64-gnu': '1.2.3',
+      '@oliphaunt/wasix-napi-linux-x64-gnu': '1.2.3',
+      '@oliphaunt/wasix-napi-win32-x64-msvc': '1.2.3',
+    },
+    engines: {
+      node: '>=22.13 <25',
+      bun: '>=1.3.14',
+      deno: '>=2.8.1',
+    },
+    oliphaunt: {
+      runtimeProduct: 'liboliphaunt-wasix',
+      runtimeVersion: '1.2.3',
+      wasixNapiProduct: 'oliphaunt-wasix-napi',
+      wasixNapiVersion: '1.2.3',
+      wasixAddonAbiVersion: 2,
+      nodeApiVersion: 8,
+      browserHost: 'wasmer-js-patched',
+      serverHost: 'wasix-rust-napi',
+    },
+  };
+}
+
+describe('WASIX TypeScript package dependency contract', () => {
+  test('accepts the portable browser runtime and exact native platform carriers', () => {
+    expect(() => assertWasixTypescriptManifest(manifest())).not.toThrow();
+  });
+
+  test('rejects a missing native platform carrier', () => {
+    const candidate = manifest();
+    delete candidate.optionalDependencies['@oliphaunt/wasix-napi-linux-x64-gnu'];
+    expect(() => assertWasixTypescriptManifest(candidate)).toThrow(/must depend only/u);
+  });
+
+  test('rejects a native platform carrier outside the pinned N-API release', () => {
+    const candidate = manifest();
+    candidate.optionalDependencies['@oliphaunt/wasix-napi-linux-x64-gnu'] = '1.2.4';
+    expect(() => assertWasixTypescriptManifest(candidate)).toThrow(/must depend only/u);
+  });
+
+  test('rejects compatibility metadata that could route a server runtime back to Wasmer', () => {
+    const candidate = manifest();
+    candidate.oliphaunt.serverHost = 'wasmer-js-patched';
+    expect(() => assertWasixTypescriptManifest(candidate)).toThrow(
+      'runtime compatibility metadata differs from its exact dependencies',
+    );
+  });
+
+  test('rejects a carrier ABI outside the qualified Node-API contract', () => {
+    const candidate = manifest();
+    candidate.oliphaunt.nodeApiVersion = 9;
+    expect(() => assertWasixTypescriptManifest(candidate)).toThrow(
+      'runtime compatibility metadata differs from its exact dependencies',
+    );
+  });
+
+  test('rejects runtime floors outside the qualified envelope', () => {
+    const candidate = manifest();
+    candidate.engines.bun = '>=1';
+    expect(() => assertWasixTypescriptManifest(candidate)).toThrow(
+      'must declare the qualified Node, Bun, and Deno runtime floors',
+    );
+  });
+
+  for (const [family, dependency] of [
+    ['dependencies', 'unrelated'],
+    ['optionalDependencies', '@wasmer/sdk'],
+    ['peerDependencies', '@oliphaunt/native-host'],
+  ]) {
+    test(`rejects an extra ${family} entry`, () => {
+      const candidate = manifest();
+      candidate[family] = { ...candidate[family], [dependency]: '1.0.0' };
+      expect(() => assertWasixTypescriptManifest(candidate)).toThrow(/must depend only/u);
+    });
+  }
+
+  test('rejects bundled dependencies', () => {
+    const candidate = manifest();
+    candidate.bundledDependencies = ['fzstd'];
+    expect(() => assertWasixTypescriptManifest(candidate)).toThrow(/must depend only/u);
+  });
+});
diff --git a/src/bindings/wasix-ts/tsconfig.build.json b/src/sdks/ts-wasix/sdk/tsconfig.build.json
similarity index 100%
rename from src/bindings/wasix-ts/tsconfig.build.json
rename to src/sdks/ts-wasix/sdk/tsconfig.build.json
diff --git a/src/sdks/ts-wasix/sdk/tsconfig.json b/src/sdks/ts-wasix/sdk/tsconfig.json
new file mode 100644
index 000000000..853b6b9db
--- /dev/null
+++ b/src/sdks/ts-wasix/sdk/tsconfig.json
@@ -0,0 +1,24 @@
+{
+  "compilerOptions": {
+    "declaration": true,
+    "declarationMap": false,
+    "lib": ["ES2023", "ESNext.Disposable", "DOM", "DOM.Iterable", "WebWorker"],
+    "module": "NodeNext",
+    "moduleResolution": "NodeNext",
+    "noEmit": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "noUncheckedIndexedAccess": true,
+    "outDir": "lib",
+    "paths": {
+      "@oliphaunt/liboliphaunt-wasix": ["./src/runtime-carrier-shim.d.ts"]
+    },
+    "rootDir": "src",
+    "skipLibCheck": true,
+    "strict": true,
+    "target": "ES2022",
+    "types": ["node", "bun"]
+  },
+  "include": ["src/**/*"],
+  "exclude": ["lib", "node_modules"]
+}
diff --git a/src/sdks/ts/node-addon/CHANGELOG.md b/src/sdks/ts/node-addon/CHANGELOG.md
new file mode 100644
index 000000000..656f46822
--- /dev/null
+++ b/src/sdks/ts/node-addon/CHANGELOG.md
@@ -0,0 +1,35 @@
+# Changelog
+
+## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-node-direct-v0.1.1...oliphaunt-node-direct-v0.2.0) (2026-09-05)
+
+
+### ⚠ BREAKING CHANGES
+
+* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
+
+### Features
+
+* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))
+* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
+
+
+### Code Refactoring
+
+* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
+* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
+
+## 0.1.1
+
+### Dependencies
+
+* **dependencies:** align with `liboliphaunt-native` 0.1.1 (release compatibility field `oliphaunt-node-direct-liboliphaunt`)
+* **dependencies:** align with `liboliphaunt-native` 0.1.1 (Moon production dependency: `liboliphaunt-native` -> `oliphaunt-node-direct`)
+
+## 0.1.0 (2026-07-28)
+
+
+### Features
+
+* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/sdks/ts/node-addon/Cargo.toml b/src/sdks/ts/node-addon/Cargo.toml
new file mode 100644
index 000000000..bd7a6354c
--- /dev/null
+++ b/src/sdks/ts/node-addon/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "oliphaunt-node-direct"
+version = "0.0.0"
+edition.workspace = true
+rust-version.workspace = true
+license.workspace = true
+publish = false
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+liboliphaunt-native-bindings = { path = "../../rust/liboliphaunt-native" }
+napi = { version = "=3.12.2", default-features = false, features = ["napi8"] }
+napi-derive = { version = "=3.6.3", default-features = false, features = ["strict", "type-def"] }
+
+[build-dependencies]
+napi-build = "=2.4.1"
diff --git a/src/sdks/ts/node-addon/README.md b/src/sdks/ts/node-addon/README.md
new file mode 100644
index 000000000..a8e8f1b78
--- /dev/null
+++ b/src/sdks/ts/node-addon/README.md
@@ -0,0 +1,35 @@
+# Oliphaunt Node-API addon
+
+`oliphaunt-node-direct` owns the Node-API adapter that lets the TypeScript SDK
+call the native `liboliphaunt` runtime without compiling native code during a
+normal application install.
+
+Published consumer packages are platform-specific optional npm packages:
+
+- `@oliphaunt/node-direct-darwin-arm64`
+- `@oliphaunt/node-direct-linux-x64-gnu`
+- `@oliphaunt/node-direct-linux-arm64-gnu`
+- `@oliphaunt/node-direct-win32-x64-msvc`
+
+The TypeScript SDK selects the matching optional package. Missing packages fail
+with an install-time action instead of downloading runtime assets.
+
+Native database calls run on addon-owned background threads and return to
+JavaScript through bounded Node-API thread-safe-function bridges. Environment
+cleanup first aborts those JavaScript delivery bridges and waits only for a
+producer already inside Node-API to observe that abort. Cleanup then cancels the resident backend, drains registered native worker threads, and terminally closes only the generation owned by that environment. It does not wait for JavaScript promise completion or an asynchronous cleanup acknowledgement.
+
+The addon uses napi-rs and `liboliphaunt-native-bindings`, shared with the Rust SDK
+and broker. The native runtime
+remains a separately installed asset. Node and Bun use this addon; Deno retains
+its nonblocking FFI adapter because Deno worker cleanup is not compatible with
+the Node-API cleanup lifecycle. On Deno 2.8.1 the current addon passes normal SQL
+and backup/restore but fails Worker termination with queued stream delivery:
+the native producer is not drained and closed. Do not remove FFI based only on
+ordinary query success.
+
+From this directory, use `bun run typecheck`, `bun run lint`, `bun run test`,
+`bun run build`, and `bun run test-built`. Building uses Cargo and the platform
+Rust toolchain; application installs need no compiler or downloaded Node headers.
+
+The adapter source is MIT licensed. Shipped binaries also include Rust dependencies; each binary archive and npm carrier includes their exact license texts and target-specific inventory under `THIRD_PARTY_LICENSES/rust`. The package license expression covers MIT, ISC, Unicode-3.0, and BSD-3-Clause obligations. The dependency contract pins the locked Cargo graph and actual source license bytes; four napi-rs crates omit legal files from their registry archives, so their full upstream LICENSE is pinned to each crate’s recorded source commit.
diff --git a/src/sdks/ts/node-addon/build.rs b/src/sdks/ts/node-addon/build.rs
new file mode 100644
index 000000000..0f1b01002
--- /dev/null
+++ b/src/sdks/ts/node-addon/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+    napi_build::setup();
+}
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64
new file mode 100644
index 000000000..7c5335ec4
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f.base64
@@ -0,0 +1,3 @@
+VGhpcyBwcm9qZWN0IGlzIGR1YWwtbGljZW5zZWQgdW5kZXIgdGhlIFVubGljZW5zZSBhbmQgTUlU
+IGxpY2Vuc2VzLgoKWW91IG1heSB1c2UgdGhpcyBjb2RlIHVuZGVyIHRoZSB0ZXJtcyBvZiBlaXRo
+ZXIgbGljZW5zZS4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594.base64
new file mode 100644
index 000000000..3cea07385
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594.base64
@@ -0,0 +1,179 @@
+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAg
+ICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAg
+ICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5E
+IENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAx
+LiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24g
+YXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAg
+ICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1
+dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRo
+ZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2Yg
+dGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRy
+b2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wg
+d2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAg
+ICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRv
+IGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwg
+d2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlw
+IG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcg
+c2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAg
+ICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBF
+bnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5z
+ZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y
+IG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRv
+IHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNv
+bmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZv
+cm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFu
+c2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVk
+IHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAg
+YW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxs
+IG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAg
+T2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0
+ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0
+YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFw
+cGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3
+b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNl
+ZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBl
+ZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBt
+b2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29y
+ayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwg
+RGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAg
+ICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhl
+IGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJl
+b2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNo
+aXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg
+YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJp
+dmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0
+ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0
+IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6
+ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3Ig
+dGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMg
+YW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24g
+c2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVk
+aW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMg
+bWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNz
+dWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2Ys
+IHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1w
+cm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBp
+cyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3
+cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgog
+ICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFs
+IG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBo
+YXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29y
+cG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5z
+ZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNl
+bnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAog
+ICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBp
+cnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUg
+RGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy
+Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2gg
+RGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBv
+ZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YK
+ICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91
+IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwg
+cm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlz
+IHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBv
+ZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdv
+cmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50
+IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVj
+ZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBv
+ciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUg
+V29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UK
+ICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5j
+bHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkg
+YWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0
+ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRv
+cnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdy
+YW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1p
+bmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0
+LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVz
+IG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVk
+aXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv
+ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5n
+IGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50
+cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhp
+cyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmls
+ZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3Ug
+Y2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhl
+IFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBk
+aXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAg
+ICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAog
+ICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBh
+bnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQp
+IElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRz
+CiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZ
+b3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0
+aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5P
+VElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAg
+cGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qg
+b25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRl
+eHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBX
+b3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwg
+aWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAg
+ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg
+YW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkg
+YXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9y
+IGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkg
+dGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBu
+b3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25n
+c2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20g
+dGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1
+dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0
+aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1l
+bnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFs
+IG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IK
+ICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQg
+WW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29y
+ayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4g
+dGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3Mg
+WW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGlu
+dGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkg
+WW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlv
+bnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9y
+IGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVy
+ZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh
+cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBM
+aWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4g
+VGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQog
+ICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBv
+ZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBh
+bmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdv
+cmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcu
+IERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxh
+dyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdv
+cmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25z
+KSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElU
+SU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVk
+aW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAg
+ICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVT
+UyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNp
+YmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9y
+IHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29j
+aWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5z
+ZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIg
+bm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdl
+bmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFw
+cGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGln
+ZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3Ig
+YmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs
+IGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRh
+bWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMg
+TGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBX
+b3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29v
+ZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rp
+b24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3Nz
+ZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0
+aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5
+IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUg
+V29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVy
+LAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJy
+YW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5k
+L29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBp
+biBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZ
+b3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJl
+aGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3Jl
+ZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBo
+YXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFz
+c2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIg
+YWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAg
+RU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64
new file mode 100644
index 000000000..2f7b4a717
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f.base64
@@ -0,0 +1,19 @@
+VGhlIE1JVCBMaWNlbnNlIChNSVQpCgpDb3B5cmlnaHQgKGMpIDIwMTUgQW5kcmV3IEdhbGxhbnQK
+ClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVy
+c29uIG9idGFpbmluZyBhIGNvcHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1
+bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJl
+IHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJp
+Z2h0cwp0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1
+YmxpY2Vuc2UsIGFuZC9vciBzZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJt
+aXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1
+YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBu
+b3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4KYWxs
+IGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09G
+VFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwg
+RVhQUkVTUyBPUgpJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJS
+QU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBP
+U0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1Ig
+Q09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RI
+RVIKTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBP
+VEhFUldJU0UsIEFSSVNJTkcgRlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUg
+U09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTgpUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64
new file mode 100644
index 000000000..5093c7c30
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSBUaGUgUnVzdCBQcm9qZWN0IERldmVsb3BlcnMKClBlcm1pc3Npb24gaXMg
+aGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBh
+IGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVz
+ICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJp
+Y3Rpb24sIGluY2x1ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNv
+cHksIG1vZGlmeSwgbWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9v
+ciBzZWxsIGNvcGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3
+aG9tIHRoZSBTb2Z0d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZv
+bGxvd2luZwpjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMg
+cGVybWlzc2lvbiBub3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJz
+dGFudGlhbCBwb3J0aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklE
+RUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBM
+SUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNI
+QU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJ
+TkdFTUVOVC4gSU4gTk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERF
+UlMgQkUgTElBQkxFIEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBX
+SEVUSEVSIElOIEFOIEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJ
+TkcgRlJPTSwgT1VUIE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhF
+IFVTRSBPUiBPVEhFUgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8.base64
new file mode 100644
index 000000000..e11847ef7
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8.base64
@@ -0,0 +1,19 @@
+VGhlIE1JVCBMaWNlbnNlIChNSVQpCkNvcHlyaWdodCAoYykgMjAxNiBBbGV4YW5kcmUgQnVyeQoK
+UGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJz
+b24gb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3Vt
+ZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUg
+d2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmln
+aHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3Vi
+bGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1p
+dCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3Vi
+amVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5v
+dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwg
+Y29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZU
+V0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBF
+WFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJB
+TlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9T
+RSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBD
+T1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhF
+UiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9U
+SEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBT
+T0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d.base64
new file mode 100644
index 000000000..2a923dd69
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d.base64
@@ -0,0 +1,6 @@
+TGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMAo8TElDRU5TRS1B
+UEFDSEUgb3IKaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wPiBvciB0
+aGUgTUlUCmxpY2Vuc2UgPExJQ0VOU0UtTUlUIG9yIGh0dHA6Ly9vcGVuc291cmNlLm9yZy9saWNl
+bnNlcy9NSVQ+LAphdCB5b3VyIG9wdGlvbi4gQWxsIGZpbGVzIGluIHRoZSBwcm9qZWN0IGNhcnJ5
+aW5nIHN1Y2gKbm90aWNlIG1heSBub3QgYmUgY29waWVkLCBtb2RpZmllZCwgb3IgZGlzdHJpYnV0
+ZWQgZXhjZXB0CmFjY29yZGluZyB0byB0aG9zZSB0ZXJtcy4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64
new file mode 100644
index 000000000..0eb7839e0
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3.base64
@@ -0,0 +1,18 @@
+UGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJz
+b24gb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3Vt
+ZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUg
+d2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmln
+aHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3Vi
+bGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1p
+dCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3Vi
+amVjdCB0byB0aGUgZm9sbG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5v
+dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwg
+Y29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZU
+V0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBF
+WFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJB
+TlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9T
+RSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBD
+T1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhF
+UiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9U
+SEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBT
+T0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.base64
new file mode 100644
index 000000000..bc239132a
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5.base64
@@ -0,0 +1,215 @@
+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAg
+ICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAg
+ICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5E
+IENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAx
+LiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24g
+YXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAg
+ICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1
+dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRo
+ZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2Yg
+dGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRy
+b2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wg
+d2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAg
+ICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRv
+IGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwg
+d2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlw
+IG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcg
+c2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAg
+ICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBF
+bnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5z
+ZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y
+IG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRv
+IHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNv
+bmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZv
+cm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFu
+c2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVk
+IHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAg
+YW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxs
+IG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAg
+T2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0
+ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0
+YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFw
+cGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3
+b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNl
+ZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBl
+ZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBt
+b2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29y
+ayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwg
+RGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAg
+ICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhl
+IGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJl
+b2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNo
+aXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg
+YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJp
+dmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0
+ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0
+IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6
+ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3Ig
+dGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMg
+YW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24g
+c2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVk
+aW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMg
+bWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNz
+dWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2Ys
+IHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1w
+cm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBp
+cyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3
+cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgog
+ICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFs
+IG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBo
+YXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29y
+cG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5z
+ZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNl
+bnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAog
+ICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBp
+cnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUg
+RGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy
+Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2gg
+RGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBv
+ZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YK
+ICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91
+IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwg
+cm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlz
+IHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBv
+ZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdv
+cmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50
+IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVj
+ZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBv
+ciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUg
+V29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UK
+ICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5j
+bHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkg
+YWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0
+ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRv
+cnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdy
+YW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1p
+bmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0
+LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVz
+IG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVk
+aXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv
+ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5n
+IGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50
+cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhp
+cyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmls
+ZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3Ug
+Y2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhl
+IFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBk
+aXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAg
+ICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAog
+ICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBh
+bnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQp
+IElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRz
+CiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZ
+b3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0
+aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5P
+VElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAg
+cGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qg
+b25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRl
+eHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBX
+b3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwg
+aWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAg
+ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg
+YW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkg
+YXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9y
+IGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkg
+dGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBu
+b3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25n
+c2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20g
+dGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1
+dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0
+aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1l
+bnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFs
+IG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IK
+ICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQg
+WW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29y
+ayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4g
+dGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3Mg
+WW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGlu
+dGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkg
+WW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlv
+bnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9y
+IGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVy
+ZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh
+cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBM
+aWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4g
+VGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQog
+ICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBv
+ZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBh
+bmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdv
+cmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcu
+IERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxh
+dyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdv
+cmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25z
+KSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElU
+SU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVk
+aW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAg
+ICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVT
+UyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNp
+YmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9y
+IHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29j
+aWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5z
+ZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIg
+bm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdl
+bmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFw
+cGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGln
+ZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3Ig
+YmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs
+IGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRh
+bWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMg
+TGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBX
+b3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29v
+ZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rp
+b24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3Nz
+ZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0
+aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5
+IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUg
+V29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVy
+LAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJy
+YW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5k
+L29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBp
+biBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZ
+b3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJl
+aGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3Jl
+ZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBo
+YXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFz
+c2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIg
+YWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAg
+RU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRo
+ZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hl
+IExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJw
+bGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAg
+ICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24n
+dCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9z
+ZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBm
+b3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUg
+YW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUg
+InByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBp
+ZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQg
+W3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBB
+cGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5v
+dCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAg
+IFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93
+d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5
+IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0
+cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJB
+U0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0
+aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lm
+aWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRl
+ciB0aGUgTGljZW5zZS4KCgotLS0gTExWTSBFeGNlcHRpb25zIHRvIHRoZSBBcGFjaGUgMi4wIExp
+Y2Vuc2UgLS0tLQoKQXMgYW4gZXhjZXB0aW9uLCBpZiwgYXMgYSByZXN1bHQgb2YgeW91ciBjb21w
+aWxpbmcgeW91ciBzb3VyY2UgY29kZSwgcG9ydGlvbnMKb2YgdGhpcyBTb2Z0d2FyZSBhcmUgZW1i
+ZWRkZWQgaW50byBhbiBPYmplY3QgZm9ybSBvZiBzdWNoIHNvdXJjZSBjb2RlLCB5b3UKbWF5IHJl
+ZGlzdHJpYnV0ZSBzdWNoIGVtYmVkZGVkIHBvcnRpb25zIGluIHN1Y2ggT2JqZWN0IGZvcm0gd2l0
+aG91dCBjb21wbHlpbmcKd2l0aCB0aGUgY29uZGl0aW9ucyBvZiBTZWN0aW9ucyA0KGEpLCA0KGIp
+IGFuZCA0KGQpIG9mIHRoZSBMaWNlbnNlLgoKSW4gYWRkaXRpb24sIGlmIHlvdSBjb21iaW5lIG9y
+IGxpbmsgY29tcGlsZWQgZm9ybXMgb2YgdGhpcyBTb2Z0d2FyZSB3aXRoCnNvZnR3YXJlIHRoYXQg
+aXMgbGljZW5zZWQgdW5kZXIgdGhlIEdQTHYyICgiQ29tYmluZWQgU29mdHdhcmUiKSBhbmQgaWYg
+YQpjb3VydCBvZiBjb21wZXRlbnQganVyaXNkaWN0aW9uIGRldGVybWluZXMgdGhhdCB0aGUgcGF0
+ZW50IHByb3Zpc2lvbiAoU2VjdGlvbgozKSwgdGhlIGluZGVtbml0eSBwcm92aXNpb24gKFNlY3Rp
+b24gOSkgb3Igb3RoZXIgU2VjdGlvbiBvZiB0aGUgTGljZW5zZQpjb25mbGljdHMgd2l0aCB0aGUg
+Y29uZGl0aW9ucyBvZiB0aGUgR1BMdjIsIHlvdSBtYXkgcmV0cm9hY3RpdmVseSBhbmQKcHJvc3Bl
+Y3RpdmVseSBjaG9vc2UgdG8gZGVlbSB3YWl2ZWQgb3Igb3RoZXJ3aXNlIGV4Y2x1ZGUgc3VjaCBT
+ZWN0aW9uKHMpIG9mCnRoZSBMaWNlbnNlLCBidXQgb25seSBpbiB0aGVpciBlbnRpcmV0eSBhbmQg
+b25seSB3aXRoIHJlc3BlY3QgdG8gdGhlIENvbWJpbmVkClNvZnR3YXJlLgoK
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427.base64
new file mode 100644
index 000000000..772f2e430
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427.base64
@@ -0,0 +1,191 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCkFQUEVORElYOiBIb3cgdG8gYXBwbHkg
+dGhlIEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgIGJvaWxlcnBsYXRl
+IG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJbXSIKICAgcmVw
+bGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0IGluY2x1
+ZGUKICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3NlZCBpbiB0aGUg
+YXBwcm9wcmlhdGUKICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZvcm1hdC4gV2UgYWxz
+byByZWNvbW1lbmQgdGhhdCBhCiAgIGZpbGUgb3IgY2xhc3MgbmFtZSBhbmQgZGVzY3JpcHRpb24g
+b2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgc2FtZSAicHJpbnRlZCBwYWdlIiBhcyB0
+aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgIGlkZW50aWZpY2F0aW9uIHdpdGhpbiB0
+aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCkNvcHlyaWdodCAoYykgMjAxNiBBbGV4IENyaWNodG9uCkNv
+cHlyaWdodCAoYykgMjAxNyBUaGUgVG9raW8gQXV0aG9ycwoKTGljZW5zZWQgdW5kZXIgdGhlIEFw
+YWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CnlvdSBtYXkgbm90IHVz
+ZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KWW91IG1h
+eSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CgoJaHR0cDovL3d3dy5hcGFjaGUub3Jn
+L2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgpVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcg
+b3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBM
+aWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCldJVEhPVVQgV0FSUkFO
+VElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVk
+LgpTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVy
+bWlzc2lvbnMgYW5kCmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64
new file mode 100644
index 000000000..d977c9dbf
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4.base64
@@ -0,0 +1,20 @@
+Q29weXJpZ2h0IChjKSAyMDE4LTIwMjUgVGhlIHJ1c3QtcmFuZG9tIFByb2plY3QgRGV2ZWxvcGVy
+cwpDb3B5cmlnaHQgKGMpIDIwMTQgVGhlIFJ1c3QgUHJvamVjdCBEZXZlbG9wZXJzCgpQZXJtaXNz
+aW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRh
+aW5pbmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlv
+biBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0
+IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8g
+dXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNl
+LCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNv
+bnMgdG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRv
+IHRoZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFu
+ZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMg
+b3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElT
+IFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1Mg
+T1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBP
+RiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBO
+T05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdI
+VCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJ
+TElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNF
+LCBBUklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJF
+IE9SIFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652.base64
new file mode 100644
index 000000000..67dd8e9a9
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652.base64
@@ -0,0 +1,18 @@
+UGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJz
+b24gb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3Vt
+ZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUg
+d2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmln
+aHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3Vi
+bGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1p
+dCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3Vi
+amVjdCB0byB0aGUgZm9sbG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5v
+dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwg
+Y29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZU
+V0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBF
+WFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJB
+TlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9T
+RSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBD
+T1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhF
+UiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9U
+SEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBT
+T0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b.base64
new file mode 100644
index 000000000..41dcc5852
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b.base64
@@ -0,0 +1,16 @@
+U2hvcnQgdmVyc2lvbiBmb3Igbm9uLWxhd3llcnM6CgpgbGludXgtcmF3LXN5c2AgaXMgdHJpcGxl
+LWxpY2Vuc2VkIHVuZGVyIEFwYWNoZSAyLjAgd2l0aCB0aGUgTExWTSBFeGNlcHRpb24sCkFwYWNo
+ZSAyLjAsIGFuZCBNSVQgdGVybXMuCgoKTG9uZ2VyIHZlcnNpb246CgpDb3B5cmlnaHRzIGluIHRo
+ZSBgbGludXgtcmF3LXN5c2AgcHJvamVjdCBhcmUgcmV0YWluZWQgYnkgdGhlaXIgY29udHJpYnV0
+b3JzLgpObyBjb3B5cmlnaHQgYXNzaWdubWVudCBpcyByZXF1aXJlZCB0byBjb250cmlidXRlIHRv
+IHRoZSBgbGludXgtcmF3LXN5c2AKcHJvamVjdC4KClNvbWUgZmlsZXMgaW5jbHVkZSBjb2RlIGRl
+cml2ZWQgZnJvbSBSdXN0J3MgYGxpYnN0ZGA7IHNlZSB0aGUgY29tbWVudHMgaW4KdGhlIGNvZGUg
+Zm9yIGRldGFpbHMuCgpFeGNlcHQgYXMgb3RoZXJ3aXNlIG5vdGVkIChiZWxvdyBhbmQvb3IgaW4g
+aW5kaXZpZHVhbCBmaWxlcyksIGBsaW51eC1yYXctc3lzYAppcyBsaWNlbnNlZCB1bmRlcjoKCiAt
+IHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAsIHdpdGggdGhlIExMVk0gRXhjZXB0aW9u
+CiAgIDxMSUNFTlNFLUFwYWNoZS0yLjBfV0lUSF9MTFZNLWV4Y2VwdGlvbj4gb3IKICAgPGh0dHA6
+Ly9sbHZtLm9yZy9mb3VuZGF0aW9uL3JlbGljZW5zaW5nL0xJQ0VOU0UudHh0PgogLSB0aGUgQXBh
+Y2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wCiAgIDxMSUNFTlNFLUFQQUNIRT4gb3IKICAgPGh0dHA6
+Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMD4sCiAtIG9yIHRoZSBNSVQgbGlj
+ZW5zZQogICA8TElDRU5TRS1NSVQ+IG9yCiAgIDxodHRwOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5z
+ZXMvTUlUPiwKCmF0IHlvdXIgb3B0aW9uLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64
new file mode 100644
index 000000000..a44c99db0
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDIxIFJ1c3RDcnlwdG8gRGV2ZWxvcGVycwoKUGVybWlzc2lvbiBpcyBo
+ZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWluaW5nIGEg
+Y29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24gZmlsZXMg
+KHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCByZXN0cmlj
+dGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29w
+eSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29y
+IHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdo
+b20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9s
+bG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBw
+ZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0
+YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURF
+RCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9SIElNUExJ
+RUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hB
+TlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklO
+R0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVS
+UyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdI
+RVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lO
+RyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUg
+VVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9.base64
new file mode 100644
index 000000000..435dc2fa0
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9.base64
@@ -0,0 +1,15 @@
+U2hvcnQgdmVyc2lvbiBmb3Igbm9uLWxhd3llcnM6CgpgcnVzdGl4YCBpcyB0cmlwbGUtbGljZW5z
+ZWQgdW5kZXIgQXBhY2hlIDIuMCB3aXRoIHRoZSBMTFZNIEV4Y2VwdGlvbiwKQXBhY2hlIDIuMCwg
+YW5kIE1JVCB0ZXJtcy4KCgpMb25nZXIgdmVyc2lvbjoKCkNvcHlyaWdodHMgaW4gdGhlIGBydXN0
+aXhgIHByb2plY3QgYXJlIHJldGFpbmVkIGJ5IHRoZWlyIGNvbnRyaWJ1dG9ycy4KTm8gY29weXJp
+Z2h0IGFzc2lnbm1lbnQgaXMgcmVxdWlyZWQgdG8gY29udHJpYnV0ZSB0byB0aGUgYHJ1c3RpeGAK
+cHJvamVjdC4KClNvbWUgZmlsZXMgaW5jbHVkZSBjb2RlIGRlcml2ZWQgZnJvbSBSdXN0J3MgYGxp
+YnN0ZGA7IHNlZSB0aGUgY29tbWVudHMgaW4KdGhlIGNvZGUgZm9yIGRldGFpbHMuCgpFeGNlcHQg
+YXMgb3RoZXJ3aXNlIG5vdGVkIChiZWxvdyBhbmQvb3IgaW4gaW5kaXZpZHVhbCBmaWxlcyksIGBy
+dXN0aXhgCmlzIGxpY2Vuc2VkIHVuZGVyOgoKIC0gdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9u
+IDIuMCwgd2l0aCB0aGUgTExWTSBFeGNlcHRpb24KICAgPExJQ0VOU0UtQXBhY2hlLTIuMF9XSVRI
+X0xMVk0tZXhjZXB0aW9uPiBvcgogICA8aHR0cDovL2xsdm0ub3JnL2ZvdW5kYXRpb24vcmVsaWNl
+bnNpbmcvTElDRU5TRS50eHQ+CiAtIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAKICAg
+PExJQ0VOU0UtQVBBQ0hFPiBvcgogICA8aHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJ
+Q0VOU0UtMi4wPiwKIC0gb3IgdGhlIE1JVCBsaWNlbnNlCiAgIDxMSUNFTlNFLU1JVD4gb3IKICAg
+PGh0dHA6Ly9vcGVuc291cmNlLm9yZy9saWNlbnNlcy9NSVQ+LAoKYXQgeW91ciBvcHRpb24uCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64
new file mode 100644
index 000000000..b53aaa660
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE0IEFsZXggQ3JpY2h0b24KClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdy
+YW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2Yg
+dGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNv
+ZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGlu
+Y2x1ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlm
+eSwgbWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNv
+cGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBT
+b2Z0d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZwpj
+b25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lv
+biBub3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBw
+b3J0aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElT
+IiwgV0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNM
+VURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElU
+WSwgRklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4g
+SU4gTk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElB
+QkxFIEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElO
+IEFOIEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwg
+T1VUIE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBP
+VEhFUgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/3f1ce66533302df3a32edbfdfc0b78f0dd34659e4c1f5817162e5ea3c2297215.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/3f1ce66533302df3a32edbfdfc0b78f0dd34659e4c1f5817162e5ea3c2297215.base64
new file mode 100644
index 000000000..d8177421e
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/3f1ce66533302df3a32edbfdfc0b78f0dd34659e4c1f5817162e5ea3c2297215.base64
@@ -0,0 +1,38 @@
+TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAyMC1wcmVzZW50IExvbmdZaW5hbgoKUGVybWlz
+c2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0
+YWluaW5nIGEgY29weQpvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRp
+b24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbAppbiB0aGUgU29mdHdhcmUgd2l0aG91
+dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzCnRv
+IHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5z
+ZSwgYW5kL29yIHNlbGwKY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJz
+b25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzCmZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0
+byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBh
+bmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwKY29waWVz
+IG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJ
+UyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNT
+IE9SCklNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMg
+T0YgTUVSQ0hBTlRBQklMSVRZLApGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQg
+Tk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUKQVVUSE9SUyBPUiBDT1BZUklH
+SFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUgpMSUFC
+SUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lT
+RSwgQVJJU0lORyBGUk9NLApPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FS
+RSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRQpTT0ZUV0FSRS4KCk1JVCBMaWNl
+bnNlCgpDb3B5cmlnaHQgKGMpIDIwMTggR2l0SHViCgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFu
+dGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5Cm9mIHRo
+aXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0
+d2FyZSIpLCB0byBkZWFsCmluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNs
+dWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMKdG8gdXNlLCBjb3B5LCBtb2RpZnks
+IG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbApjb3Bp
+ZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29m
+dHdhcmUgaXMKZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24g
+bm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbApjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9y
+dGlvbnMgb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIs
+IFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1IKSU1QTElFRCwgSU5DTFVE
+SU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFks
+CkZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElO
+IE5PIEVWRU5UIFNIQUxMIFRIRQpBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJM
+RSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSCkxJQUJJTElUWSwgV0hFVEhFUiBJTiBB
+TiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sCk9V
+VCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RI
+RVIgREVBTElOR1MgSU4gVEhFClNPRlRXQVJFLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd.base64
new file mode 100644
index 000000000..d8a50af44
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd.base64
@@ -0,0 +1,28 @@
+VGhlIGF1dG8tZ2VuZXJhdGVkIGJpbmRpbmdzIGFyZSB1bmRlciB0aGUgMy1jbGF1c2UgQlNEIGxp
+Y2Vuc2U6CgpCU0QgTGljZW5zZQoKRm9yIFpzdGFuZGFyZCBzb2Z0d2FyZQoKQ29weXJpZ2h0IChj
+KSAyMDE2LXByZXNlbnQsIEZhY2Vib29rLCBJbmMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgpSZWRp
+c3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdp
+dGhvdXQgbW9kaWZpY2F0aW9uLAphcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxv
+d2luZyBjb25kaXRpb25zIGFyZSBtZXQ6CgogKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNv
+ZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsIHRoaXMKICAgbGlzdCBv
+ZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgogKiBSZWRpc3RyaWJ1
+dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodCBu
+b3RpY2UsCiAgIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2Ns
+YWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb24KICAgYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92
+aWRlZCB3aXRoIHRoZSBkaXN0cmlidXRpb24uCgogKiBOZWl0aGVyIHRoZSBuYW1lIEZhY2Vib29r
+IG5vciB0aGUgbmFtZXMgb2YgaXRzIGNvbnRyaWJ1dG9ycyBtYXkgYmUgdXNlZCB0bwogICBlbmRv
+cnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZCBmcm9tIHRoaXMgc29mdHdhcmUgd2l0aG91
+dCBzcGVjaWZpYwogICBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uCgpUSElTIFNPRlRXQVJFIElT
+IFBST1ZJREVEIEJZIFRIRSBDT1BZUklHSFQgSE9MREVSUyBBTkQgQ09OVFJJQlVUT1JTICJBUyBJ
+UyIgQU5ECkFOWSBFWFBSRVNTIE9SIElNUExJRUQgV0FSUkFOVElFUywgSU5DTFVESU5HLCBCVVQg
+Tk9UIExJTUlURUQgVE8sIFRIRSBJTVBMSUVECldBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZ
+IEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBUkUKRElTQ0xBSU1FRC4gSU4g
+Tk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVCBIT0xERVIgT1IgQ09OVFJJQlVUT1JTIEJFIExJ
+QUJMRSBGT1IKQU5ZIERJUkVDVCwgSU5ESVJFQ1QsIElOQ0lERU5UQUwsIFNQRUNJQUwsIEVYRU1Q
+TEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTCihJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRF
+RCBUTywgUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUzsKTE9TUyBP
+RiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7IE9SIEJVU0lORVNTIElOVEVSUlVQVElPTikgSE9XRVZF
+UiBDQVVTRUQgQU5EIE9OCkFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRS
+QUNULCBTVFJJQ1QgTElBQklMSVRZLCBPUiBUT1JUCihJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBP
+VEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRiBUSElTClNPRlRX
+QVJFLCBFVkVOIElGIEFEVklTRUQgT0YgVEhFIFBPU1NJQklMSVRZIE9GIFNVQ0ggREFNQUdFLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64
new file mode 100644
index 000000000..f8430850f
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406.base64
@@ -0,0 +1,191 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCkFQUEVORElYOiBIb3cgdG8gYXBwbHkg
+dGhlIEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgIGJvaWxlcnBsYXRl
+IG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJbXSIKICAgcmVw
+bGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0IGluY2x1
+ZGUKICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3NlZCBpbiB0aGUg
+YXBwcm9wcmlhdGUKICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZvcm1hdC4gV2UgYWxz
+byByZWNvbW1lbmQgdGhhdCBhCiAgIGZpbGUgb3IgY2xhc3MgbmFtZSBhbmQgZGVzY3JpcHRpb24g
+b2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgc2FtZSAicHJpbnRlZCBwYWdlIiBhcyB0
+aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgIGlkZW50aWZpY2F0aW9uIHdpdGhpbiB0
+aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCkNvcHlyaWdodCAyMDE0IFBhaG8gTHVyaWUtR3JlZ2cKCkxp
+Y2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5z
+ZSIpOwp5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGgg
+dGhlIExpY2Vuc2UuCllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKCWh0
+dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKVW5sZXNzIHJlcXVpcmVk
+IGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQpkaXN0
+cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJB
+U0lTLApXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVy
+IGV4cHJlc3Mgb3IgaW1wbGllZC4KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFu
+Z3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZApsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGlj
+ZW5zZS4=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64
new file mode 100644
index 000000000..f2778470e
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a.base64
@@ -0,0 +1,171 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMK
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.base64
new file mode 100644
index 000000000..63f5ccfa7
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE0IFRoZSBSdXN0IFByb2plY3QgRGV2ZWxvcGVycwoKUGVybWlzc2lv
+biBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWlu
+aW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24g
+ZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCBy
+ZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVz
+ZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwg
+YW5kL29yIHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25z
+IHRvIHdob20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0
+aGUgZm9sbG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQg
+dGhpcyBwZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9y
+IHN1YnN0YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQ
+Uk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9S
+IElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0Yg
+TUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9O
+SU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQg
+SE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJ
+VFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwg
+QVJJU0lORyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBP
+UiBUSEUgVVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd.base64
new file mode 100644
index 000000000..e9405be0a
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd.base64
@@ -0,0 +1,20 @@
+Q29weXJpZ2h0IChjKSAyMDE2IEFsZXggQ3JpY2h0b24KQ29weXJpZ2h0IChjKSAyMDE3IFRoZSBU
+b2tpbyBBdXRob3JzCgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJn
+ZSwgdG8gYW55CnBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFz
+c29jaWF0ZWQKZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGlu
+IHRoZQpTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1p
+dGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBk
+aXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJl
+LCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVk
+IHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92
+ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGlu
+Y2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3
+YXJlLgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkg
+T0YKQU5ZIEtJTkQsIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRF
+RApUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFS
+VElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRI
+RSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBE
+QU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJB
+Q1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNU
+SU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhF
+IFNPRlRXQVJFLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8.base64
new file mode 100644
index 000000000..3ea11f2c8
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8.base64
@@ -0,0 +1,28 @@
+QlNEIExpY2Vuc2UKCkZvciBac3RhbmRhcmQgc29mdHdhcmUKCkNvcHlyaWdodCAoYykgTWV0YSBQ
+bGF0Zm9ybXMsIEluYy4gYW5kIGFmZmlsaWF0ZXMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgpSZWRp
+c3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdp
+dGhvdXQgbW9kaWZpY2F0aW9uLAphcmUgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZvbGxv
+d2luZyBjb25kaXRpb25zIGFyZSBtZXQ6CgogKiBSZWRpc3RyaWJ1dGlvbnMgb2Ygc291cmNlIGNv
+ZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UsIHRoaXMKICAgbGlzdCBv
+ZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuCgogKiBSZWRpc3RyaWJ1
+dGlvbnMgaW4gYmluYXJ5IGZvcm0gbXVzdCByZXByb2R1Y2UgdGhlIGFib3ZlIGNvcHlyaWdodCBu
+b3RpY2UsCiAgIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2Ns
+YWltZXIgaW4gdGhlIGRvY3VtZW50YXRpb24KICAgYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92
+aWRlZCB3aXRoIHRoZSBkaXN0cmlidXRpb24uCgogKiBOZWl0aGVyIHRoZSBuYW1lIEZhY2Vib29r
+LCBub3IgTWV0YSwgbm9yIHRoZSBuYW1lcyBvZiBpdHMgY29udHJpYnV0b3JzIG1heQogICBiZSB1
+c2VkIHRvIGVuZG9yc2Ugb3IgcHJvbW90ZSBwcm9kdWN0cyBkZXJpdmVkIGZyb20gdGhpcyBzb2Z0
+d2FyZSB3aXRob3V0CiAgIHNwZWNpZmljIHByaW9yIHdyaXR0ZW4gcGVybWlzc2lvbi4KClRISVMg
+U09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTIEFORCBDT05UUklC
+VVRPUlMgIkFTIElTIiBBTkQKQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNM
+VURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFIElNUExJRUQKV0FSUkFOVElFUyBPRiBNRVJD
+SEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRQpESVND
+TEFJTUVELiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQ09QWVJJR0hUIEhPTERFUiBPUiBDT05UUklC
+VVRPUlMgQkUgTElBQkxFIEZPUgpBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BF
+Q0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMKKElOQ0xVRElORywgQlVU
+IE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJ
+Q0VTOwpMT1NTIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBU
+SU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT04KQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRI
+RVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQKKElOQ0xVRElORyBORUdM
+SUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgVVNFIE9G
+IFRISVMKU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VD
+SCBEQU1BR0UuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64
new file mode 100644
index 000000000..d3bb917f5
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE1IFRoZSBSdXN0IFByb2plY3QgRGV2ZWxvcGVycwoKUGVybWlzc2lv
+biBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWlu
+aW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24g
+ZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCBy
+ZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVz
+ZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwg
+YW5kL29yIHNlbGwgY29waWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25z
+IHRvIHdob20gdGhlIFNvZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0
+aGUgZm9sbG93aW5nCmNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQg
+dGhpcyBwZXJtaXNzaW9uIG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9y
+IHN1YnN0YW50aWFsIHBvcnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQ
+Uk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9S
+IElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0Yg
+TUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9O
+SU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQg
+SE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJ
+VFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwg
+QVJJU0lORyBGUk9NLCBPVVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBP
+UiBUSEUgVVNFIE9SIE9USEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64
new file mode 100644
index 000000000..36c0b0762
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c.base64
@@ -0,0 +1,22 @@
+VGhpcyBpcyBmcmVlIGFuZCB1bmVuY3VtYmVyZWQgc29mdHdhcmUgcmVsZWFzZWQgaW50byB0aGUg
+cHVibGljIGRvbWFpbi4KCkFueW9uZSBpcyBmcmVlIHRvIGNvcHksIG1vZGlmeSwgcHVibGlzaCwg
+dXNlLCBjb21waWxlLCBzZWxsLCBvcgpkaXN0cmlidXRlIHRoaXMgc29mdHdhcmUsIGVpdGhlciBp
+biBzb3VyY2UgY29kZSBmb3JtIG9yIGFzIGEgY29tcGlsZWQKYmluYXJ5LCBmb3IgYW55IHB1cnBv
+c2UsIGNvbW1lcmNpYWwgb3Igbm9uLWNvbW1lcmNpYWwsIGFuZCBieSBhbnkKbWVhbnMuCgpJbiBq
+dXJpc2RpY3Rpb25zIHRoYXQgcmVjb2duaXplIGNvcHlyaWdodCBsYXdzLCB0aGUgYXV0aG9yIG9y
+IGF1dGhvcnMKb2YgdGhpcyBzb2Z0d2FyZSBkZWRpY2F0ZSBhbnkgYW5kIGFsbCBjb3B5cmlnaHQg
+aW50ZXJlc3QgaW4gdGhlCnNvZnR3YXJlIHRvIHRoZSBwdWJsaWMgZG9tYWluLiBXZSBtYWtlIHRo
+aXMgZGVkaWNhdGlvbiBmb3IgdGhlIGJlbmVmaXQKb2YgdGhlIHB1YmxpYyBhdCBsYXJnZSBhbmQg
+dG8gdGhlIGRldHJpbWVudCBvZiBvdXIgaGVpcnMgYW5kCnN1Y2Nlc3NvcnMuIFdlIGludGVuZCB0
+aGlzIGRlZGljYXRpb24gdG8gYmUgYW4gb3ZlcnQgYWN0IG9mCnJlbGlucXVpc2htZW50IGluIHBl
+cnBldHVpdHkgb2YgYWxsIHByZXNlbnQgYW5kIGZ1dHVyZSByaWdodHMgdG8gdGhpcwpzb2Z0d2Fy
+ZSB1bmRlciBjb3B5cmlnaHQgbGF3LgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIs
+IFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsCkVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVE
+SU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRgpNRVJDSEFOVEFCSUxJVFks
+IEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuCklO
+IE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1B
+R0VTIE9SCk9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1Qs
+IFRPUlQgT1IgT1RIRVJXSVNFLApBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9O
+IFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IKT1RIRVIgREVBTElOR1MgSU4gVEhFIFNP
+RlRXQVJFLgoKRm9yIG1vcmUgaW5mb3JtYXRpb24sIHBsZWFzZSByZWZlciB0byA8aHR0cDovL3Vu
+bGljZW5zZS5vcmcvPgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2.base64
new file mode 100644
index 000000000..8ca7d5553
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE0IENocmlzIFdvbmcKClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50
+ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhp
+cyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3
+YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1
+ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwg
+bWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGll
+cyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0
+d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZwpjb25k
+aXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBu
+b3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0
+aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwg
+V0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJ
+TkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwg
+RklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4g
+Tk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxF
+IEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFO
+IEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VU
+IE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhF
+UgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36.base64
new file mode 100644
index 000000000..7744e2c5b
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE1IFN0ZXZlbiBBbGxlbgoKUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3Jh
+bnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueQpwZXJzb24gb2J0YWluaW5nIGEgY29weSBvZiB0
+aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkCmRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29m
+dHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUKU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5j
+bHVkaW5nIHdpdGhvdXQKbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5
+LCBtZXJnZSwKcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29w
+aWVzIG9mCnRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNv
+ZnR3YXJlCmlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nCmNv
+bmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9u
+IG5vdGljZQpzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBv
+cnRpb25zCm9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMi
+LCBXSVRIT1VUIFdBUlJBTlRZIE9GCkFOWSBLSU5ELCBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xV
+RElORyBCVVQgTk9UIExJTUlURUQKVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZ
+LCBGSVRORVNTIEZPUiBBClBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJ
+TiBOTyBFVkVOVApTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFC
+TEUgRk9SIEFOWQpDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4g
+QU4gQUNUSU9OCk9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBP
+VVQgT0YgT1IKSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9U
+SEVSCkRFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077.base64
new file mode 100644
index 000000000..66df04367
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSBUaGUgdGFyLXJzIFByb2plY3QgQ29udHJpYnV0b3JzCgpQZXJtaXNzaW9u
+IGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRhaW5p
+bmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlvbiBm
+aWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0IHJl
+c3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNl
+LCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBh
+bmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMg
+dG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRo
+ZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0
+aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Ig
+c3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElTIFBS
+T1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1MgT1Ig
+SU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBPRiBN
+RVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05J
+TkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBI
+T0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElU
+WSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBB
+UklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9S
+IFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/8ce0830173fdac609dfb4ea603fdc002c2f4af0dc9b1a005653f5da9cf534b18.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/8ce0830173fdac609dfb4ea603fdc002c2f4af0dc9b1a005653f5da9cf534b18.base64
new file mode 100644
index 000000000..1efc0c0c4
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/8ce0830173fdac609dfb4ea603fdc002c2f4af0dc9b1a005653f5da9cf534b18.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE5IENhcmwgTGVyY2hlCgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFu
+dGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRo
+aXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0
+d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNs
+dWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnks
+IG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3Bp
+ZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29m
+dHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcKY29u
+ZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24g
+bm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9y
+dGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIs
+IFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQsIEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVE
+SU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFks
+IEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElO
+IE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJM
+RSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBB
+TiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9V
+VCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RI
+RVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc.base64
new file mode 100644
index 000000000..2cd7026e4
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc.base64
@@ -0,0 +1,171 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlM=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64
new file mode 100644
index 000000000..c81079b6f
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE3IEFydHlvbSBQYXZsb3YKClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdy
+YW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVyc29uIG9idGFpbmluZyBhIGNvcHkgb2Yg
+dGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNv
+ZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGlu
+Y2x1ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlm
+eSwgbWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNv
+cGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBT
+b2Z0d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZwpj
+b25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lv
+biBub3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBw
+b3J0aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElT
+IiwgV0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwgRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNM
+VURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElU
+WSwgRklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4g
+SU4gTk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElB
+QkxFIEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElO
+IEFOIEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwg
+T1VUIE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBP
+VEhFUgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64
new file mode 100644
index 000000000..6ead32cec
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2.base64
@@ -0,0 +1,191 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCkFQUEVORElYOiBIb3cgdG8gYXBwbHkg
+dGhlIEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgIGJvaWxlcnBsYXRl
+IG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJbXSIKICAgcmVw
+bGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0IGluY2x1
+ZGUKICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3NlZCBpbiB0aGUg
+YXBwcm9wcmlhdGUKICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZvcm1hdC4gV2UgYWxz
+byByZWNvbW1lbmQgdGhhdCBhCiAgIGZpbGUgb3IgY2xhc3MgbmFtZSBhbmQgZGVzY3JpcHRpb24g
+b2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgc2FtZSAicHJpbnRlZCBwYWdlIiBhcyB0
+aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgIGlkZW50aWZpY2F0aW9uIHdpdGhpbiB0
+aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCkNvcHlyaWdodCBbeXl5eV0gW25hbWUgb2YgY29weXJpZ2h0
+IG93bmVyXQoKTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAo
+dGhlICJMaWNlbnNlIik7CnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBs
+aWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNl
+bnNlIGF0CgoJaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgpVbmxl
+c3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNv
+ZnR3YXJlCmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFu
+ICJBUyBJUyIgQkFTSVMsCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBL
+SU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgpTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBz
+cGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCmxpbWl0YXRpb25zIHVu
+ZGVyIHRoZSBMaWNlbnNlLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63.base64
new file mode 100644
index 000000000..078caa305
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63.base64
@@ -0,0 +1 @@
+TUlUIG9yIEFwYWNoZS0yLjAK
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64
new file mode 100644
index 000000000..10ff42af9
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f.base64
@@ -0,0 +1,19 @@
+VGhlIE1JVCBMaWNlbnNlIChNSVQpCgpDb3B5cmlnaHQgKGMpIDIwMTQgUGFobyBMdXJpZS1HcmVn
+ZwoKUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBw
+ZXJzb24gb2J0YWluaW5nIGEgY29weQpvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRv
+Y3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbAppbiB0aGUgU29mdHdh
+cmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUg
+cmlnaHRzCnRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwg
+c3VibGljZW5zZSwgYW5kL29yIHNlbGwKY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBl
+cm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzCmZ1cm5pc2hlZCB0byBkbyBzbywg
+c3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0
+IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBh
+bGwKY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBT
+T0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5E
+LCBFWFBSRVNTIE9SCklNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdB
+UlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLApGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVS
+UE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUKQVVUSE9SUyBP
+UiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBP
+VEhFUgpMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9S
+IE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLApPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRI
+RSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRQpTT0ZUV0FSRS4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/a8ad31b1c3f40dca5a84119351b8fa8ddc868edd77fad8a8ebf6d8f2d16fa4ae.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/a8ad31b1c3f40dca5a84119351b8fa8ddc868edd77fad8a8ebf6d8f2d16fa4ae.base64
new file mode 100644
index 000000000..d1443fb97
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/a8ad31b1c3f40dca5a84119351b8fa8ddc868edd77fad8a8ebf6d8f2d16fa4ae.base64
@@ -0,0 +1,199 @@
+QXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAgICAgICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEph
+bnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAgICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcv
+bGljZW5zZXMvCgogICBURVJNUyBBTkQgQ09ORElUSU9OUyBGT1IgVVNFLCBSRVBST0RVQ1RJT04s
+IEFORCBESVNUUklCVVRJT04KCiAgIDEuIERlZmluaXRpb25zLgoKICAgICAgIkxpY2Vuc2UiIHNo
+YWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwK
+ICAgICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25zIDEgdGhyb3VnaCA5
+IG9mIHRoaXMgZG9jdW1lbnQuCgogICAgICAiTGljZW5zb3IiIHNoYWxsIG1lYW4gdGhlIGNvcHly
+aWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICAgICB0aGUgY29weXJpZ2h0IG93
+bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAgICAiTGVnYWwgRW50aXR5IiBz
+aGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgICAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2Vz
+IG9mIHRoaXMgZGVmaW5pdGlvbiwKICAgICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIs
+IGRpcmVjdCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgICAgIGRpcmVjdGlvbiBvciBtYW5h
+Z2VtZW50IG9mIHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgICAgIG90aGVy
+d2lzZSwgb3IgKGlpKSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9m
+IHRoZQogICAgICBvdXRzdGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJz
+aGlwIG9mIHN1Y2ggZW50aXR5LgoKICAgICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBh
+biBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICAgICBleGVyY2lzaW5nIHBlcm1pc3Npb25z
+IGdyYW50ZWQgYnkgdGhpcyBMaWNlbnNlLgoKICAgICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFu
+IHRoZSBwcmVmZXJyZWQgZm9ybSBmb3IgbWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgICAgIGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29mdHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRp
+b24KICAgICAgc291cmNlLCBhbmQgY29uZmlndXJhdGlvbiBmaWxlcy4KCiAgICAgICJPYmplY3Qi
+IGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRpbmcgZnJvbSBtZWNoYW5pY2FsCiAgICAg
+IHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEgU291cmNlIGZvcm0sIGluY2x1ZGlu
+ZyBidXQKICAgICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2JqZWN0IGNvZGUsIGdlbmVyYXRl
+ZCBkb2N1bWVudGF0aW9uLAogICAgICBhbmQgY29udmVyc2lvbnMgdG8gb3RoZXIgbWVkaWEgdHlw
+ZXMuCgogICAgICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRob3JzaGlwLCB3aGV0
+aGVyIGluIFNvdXJjZSBvcgogICAgICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFibGUgdW5kZXIg
+dGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgICAgIGNvcHlyaWdodCBub3RpY2UgdGhh
+dCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAgICAoYW4gZXhhbXBs
+ZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICAgICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFu
+ZCBmb3Igd2hpY2ggdGhlCiAgICAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBl
+bGFib3JhdGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgICAgcmVwcmVzZW50LCBhcyBh
+IHdob2xlLCBhbiBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMK
+ICAgICAgb2YgdGhpcyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRl
+IHdvcmtzIHRoYXQgcmVtYWluCiAgICAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAo
+b3IgYmluZCBieSBuYW1lKSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgICAgdGhlIFdvcmsgYW5k
+IERlcml2YXRpdmUgV29ya3MgdGhlcmVvZi4KCiAgICAgICJDb250cmlidXRpb24iIHNoYWxsIG1l
+YW4gYW55IHdvcmsgb2YgYXV0aG9yc2hpcCwgaW5jbHVkaW5nCiAgICAgIHRoZSBvcmlnaW5hbCB2
+ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBhbnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAg
+ICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRl
+bnRpb25hbGx5CiAgICAgIHN1Ym1pdHRlZCB0byBMaWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRo
+ZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIKICAgICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBv
+ciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJtaXQgb24gYmVoYWxmIG9mCiAgICAgIHRo
+ZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBkZWZpbml0aW9uLCAi
+c3VibWl0dGVkIgogICAgICBtZWFucyBhbnkgZm9ybSBvZiBlbGVjdHJvbmljLCB2ZXJiYWwsIG9y
+IHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgICAgIHRvIHRoZSBMaWNlbnNvciBvciBpdHMg
+cmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvCiAgICAgIGNvbW11
+bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2UgY29kZSBjb250cm9s
+IHN5c3RlbXMsCiAgICAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQgYXJlIG1hbmFn
+ZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgICAgIExpY2Vuc29yIGZvciB0aGUgcHVycG9z
+ZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICAgICBleGNsdWRp
+bmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVyd2lz
+ZQogICAgICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNl
+bnNvciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgICAgIG9uIGJlaGFsZiBv
+ZiB3aG9tIGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAog
+ICAgICBzdWJzZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCiAgIDIuIEdy
+YW50IG9mIENvcHlyaWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0
+aW9ucyBvZgogICAgICB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50
+cyB0byBZb3UgYSBwZXJwZXR1YWwsCiAgICAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8t
+Y2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlCiAgICAgIGNvcHlyaWdodCBsaWNlbnNl
+IHRvIHJlcHJvZHVjZSwgcHJlcGFyZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICAgICBwdWJsaWNs
+eSBkaXNwbGF5LCBwdWJsaWNseSBwZXJmb3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0
+aGUKICAgICAgV29yayBhbmQgc3VjaCBEZXJpdmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmpl
+Y3QgZm9ybS4KCiAgIDMuIEdyYW50IG9mIFBhdGVudCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0
+ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICAgICB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0
+b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsCiAgICAgIHdvcmxkd2lkZSwgbm9u
+LWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlCiAgICAgIChl
+eGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50IGxpY2Vuc2UgdG8gbWFrZSwg
+aGF2ZSBtYWRlLAogICAgICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGwsIGltcG9ydCwgYW5kIG90
+aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgICAgd2hlcmUgc3VjaCBsaWNlbnNlIGFwcGxp
+ZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAgICAgYnkgc3VjaCBD
+b250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhlaXIKICAgICAg
+Q29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENvbnRyaWJ1
+dGlvbihzKQogICAgICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9uKHMp
+IHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICAgICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICAgICBjcm9zcy1jbGFpbSBvciBjb3Vu
+dGVyY2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgICAgIG9yIGEg
+Q29udHJpYnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGly
+ZWN0CiAgICAgIG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBw
+YXRlbnQgbGljZW5zZXMKICAgICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZv
+ciB0aGF0IFdvcmsgc2hhbGwgdGVybWluYXRlCiAgICAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0
+aWdhdGlvbiBpcyBmaWxlZC4KCiAgIDQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVj
+ZSBhbmQgZGlzdHJpYnV0ZSBjb3BpZXMgb2YgdGhlCiAgICAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBX
+b3JrcyB0aGVyZW9mIGluIGFueSBtZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICAgICBtb2RpZmlj
+YXRpb25zLCBhbmQgaW4gU291cmNlIG9yIE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQog
+ICAgICBtZWV0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKCiAgICAgIChhKSBZb3UgbXVzdCBn
+aXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRoZSBXb3JrIG9yCiAgICAgICAgICBEZXJpdmF0
+aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7IGFuZAoKICAgICAgKGIpIFlvdSBtdXN0
+IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcwogICAg
+ICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxlczsgYW5kCgogICAgICAoYykg
+WW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55IERlcml2YXRpdmUgV29y
+a3MKICAgICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmlnaHQsIHBhdGVudCwg
+dHJhZGVtYXJrLCBhbmQKICAgICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJvbSB0aGUgU291
+cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0
+aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICAgICB0aGUgRGVyaXZhdGl2
+ZSBXb3JrczsgYW5kCgogICAgICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkg
+RGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgICAgIGluY2x1
+ZGUgYSByZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAog
+ICAgICAgICAgd2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2Vz
+IHRoYXQgZG8gbm90CiAgICAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzLCBpbiBhdCBsZWFzdCBvbmUKICAgICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxh
+Y2VzOiB3aXRoaW4gYSBOT1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICAgICBhcyBw
+YXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAg
+ICAgICAgICBkb2N1bWVudGF0aW9uLCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyBvciwKICAgICAgICAgIHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRo
+ZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBhbmQKICAgICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQt
+cGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBlYXIuIFRoZSBjb250ZW50cwogICAgICAgICAgb2Yg
+dGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3JtYXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAog
+ICAgICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5zZS4gWW91IG1heSBhZGQgWW91ciBvd24g
+YXR0cmlidXRpb24KICAgICAgICAgIG5vdGljZXMgd2l0aGluIERlcml2YXRpdmUgV29ya3MgdGhh
+dCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICAgICBvciBhcyBhbiBhZGRlbmR1bSB0
+byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlkZWQKICAgICAgICAgIHRoYXQg
+c3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90IGJlIGNvbnN0cnVlZAog
+ICAgICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgICAgWW91IG1heSBhZGQgWW91
+ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMgYW5kCiAgICAg
+IG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMgYW5kIGNv
+bmRpdGlvbnMKICAgICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24gb2Yg
+WW91ciBtb2RpZmljYXRpb25zLCBvcgogICAgICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgICAgcmVwcm9kdWN0aW9uLCBhbmQg
+ZGlzdHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgICAgIHRo
+ZSBjb25kaXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgogICA1LiBTdWJtaXNzaW9uIG9m
+IENvbnRyaWJ1dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAg
+ICAgIGFueSBDb250cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lv
+biBpbiB0aGUgV29yawogICAgICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVy
+IHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICAgICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQg
+YW55IGFkZGl0aW9uYWwgdGVybXMgb3IgY29uZGl0aW9ucy4KICAgICAgTm90d2l0aHN0YW5kaW5n
+IHRoZSBhYm92ZSwgbm90aGluZyBoZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICAg
+ICB0aGUgdGVybXMgb2YgYW55IHNlcGFyYXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2
+ZSBleGVjdXRlZAogICAgICB3aXRoIExpY2Vuc29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlv
+bnMuCgogICA2LiBUcmFkZW1hcmtzLiBUaGlzIExpY2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlz
+c2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgICAgIG5hbWVzLCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1h
+cmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNlbnNvciwKICAgICAgZXhjZXB0IGFzIHJl
+cXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkgdXNlIGluIGRlc2NyaWJpbmcgdGhl
+CiAgICAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNpbmcgdGhlIGNvbnRlbnQgb2Yg
+dGhlIE5PVElDRSBmaWxlLgoKICAgNy4gRGlzY2xhaW1lciBvZiBXYXJyYW50eS4gVW5sZXNzIHJl
+cXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgICAgIGFncmVlZCB0byBpbiB3cml0aW5nLCBM
+aWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgICAgQ29udHJpYnV0b3IgcHJv
+dmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAgICAgIFdJVEhP
+VVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBv
+cgogICAgICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdhcnJh
+bnRpZXMgb3IgY29uZGl0aW9ucwogICAgICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgICAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4g
+WW91IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICAgICBhcHBy
+b3ByaWF0ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3Vt
+ZSBhbnkKICAgICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlz
+c2lvbnMgdW5kZXIgdGhpcyBMaWNlbnNlLgoKICAgOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHku
+IEluIG5vIGV2ZW50IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgICAgIHdoZXRoZXIgaW4g
+dG9ydCAoaW5jbHVkaW5nIG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICAg
+ICB1bmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBh
+bmQgZ3Jvc3NseQogICAgICBuZWdsaWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcs
+IHNoYWxsIGFueSBDb250cmlidXRvciBiZQogICAgICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2Vz
+LCBpbmNsdWRpbmcgYW55IGRpcmVjdCwgaW5kaXJlY3QsIHNwZWNpYWwsCiAgICAgIGluY2lkZW50
+YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdlcyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMg
+YQogICAgICByZXN1bHQgb2YgdGhpcyBMaWNlbnNlIG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJp
+bGl0eSB0byB1c2UgdGhlCiAgICAgIFdvcmsgKGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8g
+ZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAgICAgd29yayBzdG9wcGFnZSwgY29tcHV0
+ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFuZCBhbGwKICAgICAgb3RoZXIgY29t
+bWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3VjaCBDb250cmlidXRvcgogICAg
+ICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBzdWNoIGRhbWFnZXMuCgog
+ICA5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxpdHkuIFdoaWxlIHJl
+ZGlzdHJpYnV0aW5nCiAgICAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwg
+WW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgICAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9yLCBhY2Nl
+cHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgICAgIG9yIG90aGVyIGxp
+YWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlzCiAg
+ICAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgICAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJl
+c3BvbnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgICAgIG9mIGFueSBvdGhlciBDb250cmlidXRv
+ciwgYW5kIG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgICAgZGVmZW5kLCBhbmQg
+aG9sZCBlYWNoIENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgICAgIGlu
+Y3VycmVkIGJ5LCBvciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBi
+eSByZWFzb24KICAgICAgb2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRk
+aXRpb25hbCBsaWFiaWxpdHkuCgogICBFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCiAgIEFQ
+UEVORElYOiBIb3cgdG8gYXBwbHkgdGhlIEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAg
+ICAgIFRvIGFwcGx5IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUg
+Zm9sbG93aW5nCiAgICAgIGJvaWxlcnBsYXRlIG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xv
+c2VkIGJ5IGJyYWNrZXRzICJ7fSIKICAgICAgcmVwbGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlm
+eWluZyBpbmZvcm1hdGlvbi4gKERvbid0IGluY2x1ZGUKICAgICAgdGhlIGJyYWNrZXRzISkgIFRo
+ZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3NlZCBpbiB0aGUgYXBwcm9wcmlhdGUKICAgICAgY29tbWVu
+dCBzeW50YXggZm9yIHRoZSBmaWxlIGZvcm1hdC4gV2UgYWxzbyByZWNvbW1lbmQgdGhhdCBhCiAg
+ICAgIGZpbGUgb3IgY2xhc3MgbmFtZSBhbmQgZGVzY3JpcHRpb24gb2YgcHVycG9zZSBiZSBpbmNs
+dWRlZCBvbiB0aGUKICAgICAgc2FtZSAicHJpbnRlZCBwYWdlIiBhcyB0aGUgY29weXJpZ2h0IG5v
+dGljZSBmb3IgZWFzaWVyCiAgICAgIGlkZW50aWZpY2F0aW9uIHdpdGhpbiB0aGlyZC1wYXJ0eSBh
+cmNoaXZlcy4KCiAgIENvcHlyaWdodCB7eXl5eX0ge25hbWUgb2YgY29weXJpZ2h0IG93bmVyfQoK
+ICAgTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJM
+aWNlbnNlIik7CiAgIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFu
+Y2Ugd2l0aCB0aGUgTGljZW5zZS4KICAgWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNl
+bnNlIGF0CgogICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4w
+CgogICBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdy
+aXRpbmcsIHNvZnR3YXJlCiAgIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3Ry
+aWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAgIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05E
+SVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogICBTZWUgdGhl
+IExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMg
+YW5kCiAgIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64
new file mode 100644
index 000000000..266160f58
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5.base64
@@ -0,0 +1,191 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgpURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCjEuIERlZmluaXRpb25zLgoK
+ICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwKICAgYW5kIGRpc3RyaWJ1dGlvbiBhcyBkZWZpbmVkIGJ5IFNlY3Rpb25z
+IDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAiTGljZW5zb3IiIHNoYWxsIG1lYW4g
+dGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0aG9yaXplZCBieQogICB0aGUgY29weXJp
+Z2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhlIExpY2Vuc2UuCgogICAiTGVnYWwgRW50aXR5
+IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgIG90
+aGVyIGVudGl0aWVzIHRoYXQgY29udHJvbCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRl
+ciBjb21tb24KICAgY29udHJvbCB3aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9m
+IHRoaXMgZGVmaW5pdGlvbiwKICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVj
+dCBvciBpbmRpcmVjdCwgdG8gY2F1c2UgdGhlCiAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9m
+IHN1Y2ggZW50aXR5LCB3aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgIG90aGVyd2lzZSwgb3IgKGlp
+KSBvd25lcnNoaXAgb2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICBvdXRz
+dGFuZGluZyBzaGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50
+aXR5LgoKICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExl
+Z2FsIEVudGl0eQogICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNl
+bnNlLgoKICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gc29m
+dHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgc291cmNlLCBhbmQgY29uZmlndXJh
+dGlvbiBmaWxlcy4KCiAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9ybSByZXN1bHRp
+bmcgZnJvbSBtZWNoYW5pY2FsCiAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5zbGF0aW9uIG9mIGEg
+U291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgbm90IGxpbWl0ZWQgdG8gY29tcGlsZWQgb2Jq
+ZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICBhbmQgY29udmVyc2lvbnMgdG8g
+b3RoZXIgbWVkaWEgdHlwZXMuCgogICAiV29yayIgc2hhbGwgbWVhbiB0aGUgd29yayBvZiBhdXRo
+b3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICBPYmplY3QgZm9ybSwgbWFkZSBhdmFpbGFi
+bGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRlZCBieSBhCiAgIGNvcHlyaWdodCBub3Rp
+Y2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRhY2hlZCB0byB0aGUgd29yawogICAoYW4gZXhh
+bXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBwZW5kaXggYmVsb3cpLgoKICAgIkRlcml2YXRpdmUg
+V29ya3MiIHNoYWxsIG1lYW4gYW55IHdvcmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAog
+ICBmb3JtLCB0aGF0IGlzIGJhc2VkIG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBm
+b3Igd2hpY2ggdGhlCiAgIGVkaXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3Jh
+dGlvbnMsIG9yIG90aGVyIG1vZGlmaWNhdGlvbnMKICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBh
+biBvcmlnaW5hbCB3b3JrIG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgb2YgdGhp
+cyBMaWNlbnNlLCBEZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQg
+cmVtYWluCiAgIHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1l
+KSB0byB0aGUgaW50ZXJmYWNlcyBvZiwKICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZi4KCiAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9y
+c2hpcCwgaW5jbHVkaW5nCiAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgdG8gdGhhdCBXb3JrIG9yIERlcml2YXRp
+dmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgIHN1Ym1pdHRlZCB0byBM
+aWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIK
+ICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXplZCB0byBzdWJt
+aXQgb24gYmVoYWxmIG9mCiAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0aGUgcHVycG9zZXMg
+b2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICBtZWFucyBhbnkgZm9ybSBvZiBlbGVj
+dHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBzZW50CiAgIHRvIHRoZSBM
+aWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVk
+IHRvCiAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBtYWlsaW5nIGxpc3RzLCBzb3VyY2Ug
+Y29kZSBjb250cm9sIHN5c3RlbXMsCiAgIGFuZCBpc3N1ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQg
+YXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwgdGhlCiAgIExpY2Vuc29yIGZvciB0aGUg
+cHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXByb3ZpbmcgdGhlIFdvcmssIGJ1dAogICBleGNs
+dWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlzIGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVy
+d2lzZQogICBkZXNpZ25hdGVkIGluIHdyaXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAi
+Tm90IGEgQ29udHJpYnV0aW9uLiIKCiAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNv
+ciBhbmQgYW55IGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5CiAgIG9uIGJlaGFsZiBvZiB3aG9t
+IGEgQ29udHJpYnV0aW9uIGhhcyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICBzdWJz
+ZXF1ZW50bHkgaW5jb3Jwb3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCjIuIEdyYW50IG9mIENvcHly
+aWdodCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0
+aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJw
+ZXR1YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZy
+ZWUsIGlycmV2b2NhYmxlCiAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFy
+ZSBEZXJpdmF0aXZlIFdvcmtzIG9mLAogICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgV29yayBhbmQgc3VjaCBEZXJp
+dmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCjMuIEdyYW50IG9mIFBhdGVu
+dCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICB0aGlz
+IExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1
+YWwsCiAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUs
+IGlycmV2b2NhYmxlCiAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMgc2VjdGlvbikgcGF0ZW50
+IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICB1c2UsIG9mZmVyIHRvIHNlbGwsIHNlbGws
+IGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29yaywKICAgd2hlcmUgc3VjaCBs
+aWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQgY2xhaW1zIGxpY2Vuc2FibGUKICAg
+Ynkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNlc3NhcmlseSBpbmZyaW5nZWQgYnkgdGhl
+aXIKICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9yIGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENv
+bnRyaWJ1dGlvbihzKQogICB3aXRoIHRoZSBXb3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9u
+KHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQogICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24g
+YWdhaW5zdCBhbnkgZW50aXR5IChpbmNsdWRpbmcgYQogICBjcm9zcy1jbGFpbSBvciBjb3VudGVy
+Y2xhaW0gaW4gYSBsYXdzdWl0KSBhbGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgIG9yIGEgQ29udHJp
+YnV0aW9uIGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAg
+IG9yIGNvbnRyaWJ1dG9yeSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGlj
+ZW5zZXMKICAgZ3JhbnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsg
+c2hhbGwgdGVybWluYXRlCiAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxl
+ZC4KCjQuIFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBj
+b3BpZXMgb2YgdGhlCiAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBt
+ZWRpdW0sIHdpdGggb3Igd2l0aG91dAogICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICBtZWV0IHRoZSBmb2xsb3dpbmcgY29u
+ZGl0aW9uczoKCiAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRo
+ZSBXb3JrIG9yCiAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlzIExpY2Vuc2U7
+IGFuZAoKICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxlcyB0byBjYXJyeSBw
+cm9taW5lbnQgbm90aWNlcwogICAgICAgc3RhdGluZyB0aGF0IFlvdSBjaGFuZ2VkIHRoZSBmaWxl
+czsgYW5kCgogICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUgU291cmNlIGZvcm0gb2YgYW55
+IERlcml2YXRpdmUgV29ya3MKICAgICAgIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsbCBjb3B5cmln
+aHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgIGF0dHJpYnV0aW9uIG5vdGljZXMgZnJv
+bSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90
+aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mCiAgICAgICB0aGUgRGVyaXZh
+dGl2ZSBXb3JrczsgYW5kCgogICAoZCkgSWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0
+ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMKICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVy
+aXZhdGl2ZSBXb3JrcyB0aGF0IFlvdSBkaXN0cmlidXRlIG11c3QKICAgICAgIGluY2x1ZGUgYSBy
+ZWFkYWJsZSBjb3B5IG9mIHRoZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAg
+d2l0aGluIHN1Y2ggTk9USUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8g
+bm90CiAgICAgICBwZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBp
+biBhdCBsZWFzdCBvbmUKICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBO
+T1RJQ0UgdGV4dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0
+aXZlIFdvcmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICBkb2N1bWVudGF0aW9u
+LCBpZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBhcHBl
+YXIuIFRoZSBjb250ZW50cwogICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3IgaW5mb3Jt
+YXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgZG8gbm90IG1vZGlmeSB0aGUgTGljZW5z
+ZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgIG5vdGljZXMgd2l0aGlu
+IERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdzaWRlCiAgICAgICBv
+ciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0aGUgV29yaywgcHJvdmlk
+ZWQKICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0aW9uIG5vdGljZXMgY2Fubm90
+IGJlIGNvbnN0cnVlZAogICAgICAgYXMgbW9kaWZ5aW5nIHRoZSBMaWNlbnNlLgoKICAgWW91IG1h
+eSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVudCB0byBZb3VyIG1vZGlmaWNhdGlvbnMg
+YW5kCiAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwgb3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMg
+YW5kIGNvbmRpdGlvbnMKICAgZm9yIHVzZSwgcmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24g
+b2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgogICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3Jr
+cyBhcyBhIHdob2xlLCBwcm92aWRlZCBZb3VyIHVzZSwKICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlz
+dHJpYnV0aW9uIG9mIHRoZSBXb3JrIG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgIHRoZSBjb25k
+aXRpb25zIHN0YXRlZCBpbiB0aGlzIExpY2Vuc2UuCgo1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1
+dGlvbnMuIFVubGVzcyBZb3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgIGFueSBDb250
+cmlidXRpb24gaW50ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29y
+awogICBieSBZb3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBvZgogICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVy
+bXMgb3IgY29uZGl0aW9ucy4KICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBo
+ZXJlaW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICB3aXRoIExpY2Vu
+c29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgo2LiBUcmFkZW1hcmtzLiBUaGlzIExp
+Y2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAgIG5hbWVz
+LCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9mIHRoZSBMaWNl
+bnNvciwKICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFuZCBjdXN0b21hcnkg
+dXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgIG9yaWdpbiBvZiB0aGUgV29yayBhbmQgcmVwcm9kdWNp
+bmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKNy4gRGlzY2xhaW1lciBvZiBXYXJy
+YW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yCiAgIGFncmVlZCB0byBp
+biB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29yayAoYW5kIGVhY2gKICAgQ29udHJp
+YnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMpIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvcgogICBpbXBsaWVkLCBpbmNsdWRpbmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdh
+cnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVS
+Q0hBTlRBQklMSVRZLCBvciBGSVRORVNTIEZPUiBBCiAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91
+IGFyZSBzb2xlbHkgcmVzcG9uc2libGUgZm9yIGRldGVybWluaW5nIHRoZQogICBhcHByb3ByaWF0
+ZW5lc3Mgb2YgdXNpbmcgb3IgcmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkK
+ICAgcmlza3MgYXNzb2NpYXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5k
+ZXIgdGhpcyBMaWNlbnNlLgoKOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50
+IGFuZCB1bmRlciBubyBsZWdhbCB0aGVvcnksCiAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5n
+IG5lZ2xpZ2VuY2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICB1bmxlc3MgcmVxdWlyZWQg
+YnkgYXBwbGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICBuZWds
+aWdlbnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRv
+ciBiZQogICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFtYWdl
+cyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICByZXN1bHQgb2YgdGhpcyBMaWNlbnNl
+IG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgIFdvcmsgKGluY2x1
+ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29kd2lsbCwKICAg
+d29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlvbiwgb3IgYW55IGFu
+ZCBhbGwKICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3NlcyksIGV2ZW4gaWYgc3Vj
+aCBDb250cmlidXRvcgogICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRoZSBwb3NzaWJpbGl0eSBvZiBz
+dWNoIGRhbWFnZXMuCgo5LiBBY2NlcHRpbmcgV2FycmFudHkgb3IgQWRkaXRpb25hbCBMaWFiaWxp
+dHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgIHRoZSBXb3JrIG9yIERlcml2YXRpdmUgV29ya3Mg
+dGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIsCiAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9y
+LCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJhbnR5LCBpbmRlbW5pdHksCiAgIG9yIG90aGVy
+IGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQvb3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlz
+CiAgIExpY2Vuc2UuIEhvd2V2ZXIsIGluIGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3Ug
+bWF5IGFjdCBvbmx5CiAgIG9uIFlvdXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3Bv
+bnNpYmlsaXR5LCBub3Qgb24gYmVoYWxmCiAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5k
+IG9ubHkgaWYgWW91IGFncmVlIHRvIGluZGVtbmlmeSwKICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNo
+IENvbnRyaWJ1dG9yIGhhcm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgIGluY3VycmVkIGJ5LCBv
+ciBjbGFpbXMgYXNzZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAg
+b2YgeW91ciBhY2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxp
+dHkuCgpFTkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCkFQUEVORElYOiBIb3cgdG8gYXBwbHkg
+dGhlIEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgIGJvaWxlcnBsYXRl
+IG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJbXSIKICAgcmVw
+bGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0IGluY2x1
+ZGUKICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3NlZCBpbiB0aGUg
+YXBwcm9wcmlhdGUKICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZvcm1hdC4gV2UgYWxz
+byByZWNvbW1lbmQgdGhhdCBhCiAgIGZpbGUgb3IgY2xhc3MgbmFtZSBhbmQgZGVzY3JpcHRpb24g
+b2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgc2FtZSAicHJpbnRlZCBwYWdlIiBhcyB0
+aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgIGlkZW50aWZpY2F0aW9uIHdpdGhpbiB0
+aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCkNvcHlyaWdodCBbeXl5eV0gW25hbWUgb2YgY29weXJpZ2h0
+IG93bmVyXQoKTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAo
+dGhlICJMaWNlbnNlIik7CnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBs
+aWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNl
+bnNlIGF0CgogICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKClVu
+bGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywg
+c29mdHdhcmUKZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24g
+YW4gIkFTIElTIiBCQVNJUywKV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5Z
+IEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuClNlZSB0aGUgTGljZW5zZSBmb3IgdGhl
+IHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKbGltaXRhdGlvbnMg
+dW5kZXIgdGhlIExpY2Vuc2UuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64
new file mode 100644
index 000000000..611d21f96
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf.base64
@@ -0,0 +1,191 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAgICAg
+ICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAgICAgICAg
+ICBodHRwczovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKVEVSTVMgQU5EIENPTkRJVElPTlMg
+Rk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgoxLiBEZWZpbml0aW9ucy4K
+CiAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgdXNl
+LCByZXByb2R1Y3Rpb24sCiAgIGFuZCBkaXN0cmlidXRpb24gYXMgZGVmaW5lZCBieSBTZWN0aW9u
+cyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFu
+IHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1dGhvcml6ZWQgYnkKICAgdGhlIGNvcHly
+aWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRoZSBMaWNlbnNlLgoKICAgIkxlZ2FsIEVudGl0
+eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2YgdGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICBv
+dGhlciBlbnRpdGllcyB0aGF0IGNvbnRyb2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5k
+ZXIgY29tbW9uCiAgIGNvbnRyb2wgd2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBv
+ZiB0aGlzIGRlZmluaXRpb24sCiAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJl
+Y3Qgb3IgaW5kaXJlY3QsIHRvIGNhdXNlIHRoZQogICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBv
+ZiBzdWNoIGVudGl0eSwgd2hldGhlciBieSBjb250cmFjdCBvcgogICBvdGhlcndpc2UsIG9yIChp
+aSkgb3duZXJzaGlwIG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgb3V0
+c3RhbmRpbmcgc2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVu
+dGl0eS4KCiAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBM
+ZWdhbCBFbnRpdHkKICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGlj
+ZW5zZS4KCiAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y
+IG1ha2luZyBtb2RpZmljYXRpb25zLAogICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIHNv
+ZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgIHNvdXJjZSwgYW5kIGNvbmZpZ3Vy
+YXRpb24gZmlsZXMuCgogICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZvcm0gcmVzdWx0
+aW5nIGZyb20gbWVjaGFuaWNhbAogICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFuc2xhdGlvbiBvZiBh
+IFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgIG5vdCBsaW1pdGVkIHRvIGNvbXBpbGVkIG9i
+amVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgYW5kIGNvbnZlcnNpb25zIHRv
+IG90aGVyIG1lZGlhIHR5cGVzLgoKICAgIldvcmsiIHNoYWxsIG1lYW4gdGhlIHdvcmsgb2YgYXV0
+aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgT2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxh
+YmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0ZWQgYnkgYQogICBjb3B5cmlnaHQgbm90
+aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0YWNoZWQgdG8gdGhlIHdvcmsKICAgKGFuIGV4
+YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFwcGVuZGl4IGJlbG93KS4KCiAgICJEZXJpdmF0aXZl
+IFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QK
+ICAgZm9ybSwgdGhhdCBpcyBiYXNlZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQg
+Zm9yIHdoaWNoIHRoZQogICBlZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9y
+YXRpb25zLCBvciBvdGhlciBtb2RpZmljYXRpb25zCiAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwg
+YW4gb3JpZ2luYWwgd29yayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgIG9mIHRo
+aXMgTGljZW5zZSwgRGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0
+IHJlbWFpbgogICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFt
+ZSkgdG8gdGhlIGludGVyZmFjZXMgb2YsCiAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtz
+IHRoZXJlb2YuCgogICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhv
+cnNoaXAsIGluY2x1ZGluZwogICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg
+YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgIHRvIHRoYXQgV29yayBvciBEZXJpdmF0
+aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICBzdWJtaXR0ZWQgdG8g
+TGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0IG93bmVy
+CiAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6ZWQgdG8gc3Vi
+bWl0IG9uIGJlaGFsZiBvZgogICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3IgdGhlIHB1cnBvc2Vz
+IG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgbWVhbnMgYW55IGZvcm0gb2YgZWxl
+Y3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24gc2VudAogICB0byB0aGUg
+TGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVkaW5nIGJ1dCBub3QgbGltaXRl
+ZCB0bwogICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMgbWFpbGluZyBsaXN0cywgc291cmNl
+IGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICBhbmQgaXNzdWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0
+IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2YsIHRoZQogICBMaWNlbnNvciBmb3IgdGhl
+IHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1wcm92aW5nIHRoZSBXb3JrLCBidXQKICAgZXhj
+bHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBpcyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhl
+cndpc2UKICAgZGVzaWduYXRlZCBpbiB3cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMg
+Ik5vdCBhIENvbnRyaWJ1dGlvbi4iCgogICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5z
+b3IgYW5kIGFueSBpbmRpdmlkdWFsIG9yIExlZ2FsIEVudGl0eQogICBvbiBiZWhhbGYgb2Ygd2hv
+bSBhIENvbnRyaWJ1dGlvbiBoYXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgc3Vi
+c2VxdWVudGx5IGluY29ycG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgoyLiBHcmFudCBvZiBDb3B5
+cmlnaHQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAg
+dGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVy
+cGV0dWFsLAogICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1m
+cmVlLCBpcnJldm9jYWJsZQogICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBh
+cmUgRGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy
+Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgIFdvcmsgYW5kIHN1Y2ggRGVy
+aXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgozLiBHcmFudCBvZiBQYXRl
+bnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgdGhp
+cyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0
+dWFsLAogICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVl
+LCBpcnJldm9jYWJsZQogICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlzIHNlY3Rpb24pIHBhdGVu
+dCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgdXNlLCBvZmZlciB0byBzZWxsLCBzZWxs
+LCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdvcmssCiAgIHdoZXJlIHN1Y2gg
+bGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50IGNsYWltcyBsaWNlbnNhYmxlCiAg
+IGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVjZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRo
+ZWlyCiAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBvciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBD
+b250cmlidXRpb24ocykKICAgd2l0aCB0aGUgV29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlv
+bihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UKICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9u
+IGFnYWluc3QgYW55IGVudGl0eSAoaW5jbHVkaW5nIGEKICAgY3Jvc3MtY2xhaW0gb3IgY291bnRl
+cmNsYWltIGluIGEgbGF3c3VpdCkgYWxsZWdpbmcgdGhhdCB0aGUgV29yawogICBvciBhIENvbnRy
+aWJ1dGlvbiBpbmNvcnBvcmF0ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAog
+ICBvciBjb250cmlidXRvcnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxp
+Y2Vuc2VzCiAgIGdyYW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3Jr
+IHNoYWxsIHRlcm1pbmF0ZQogICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmls
+ZWQuCgo0LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUg
+Y29waWVzIG9mIHRoZQogICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkg
+bWVkaXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv
+ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgbWVldCB0aGUgZm9sbG93aW5nIGNv
+bmRpdGlvbnM6CgogICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50cyBvZiB0
+aGUgV29yayBvcgogICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhpcyBMaWNlbnNl
+OyBhbmQKCiAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmlsZXMgdG8gY2Fycnkg
+cHJvbWluZW50IG5vdGljZXMKICAgICAgIHN0YXRpbmcgdGhhdCBZb3UgY2hhbmdlZCB0aGUgZmls
+ZXM7IGFuZAoKICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhlIFNvdXJjZSBmb3JtIG9mIGFu
+eSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICB0aGF0IFlvdSBkaXN0cmlidXRlLCBhbGwgY29weXJp
+Z2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZy
+b20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAogICAgICAgZXhjbHVkaW5nIHRob3NlIG5v
+dGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBhbnkgcGFydCBvZgogICAgICAgdGhlIERlcml2
+YXRpdmUgV29ya3M7IGFuZAoKICAgKGQpIElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIg
+dGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRzCiAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERl
+cml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICBpbmNsdWRlIGEg
+cmVhZGFibGUgY29weSBvZiB0aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAg
+IHdpdGhpbiBzdWNoIE5PVElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRv
+IG5vdAogICAgICAgcGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3Jrcywg
+aW4gYXQgbGVhc3Qgb25lCiAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEg
+Tk9USUNFIHRleHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZh
+dGl2ZSBXb3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgZG9jdW1lbnRhdGlv
+biwgaWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAg
+ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg
+YW5kCiAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkgYXBw
+ZWFyLiBUaGUgY29udGVudHMKICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9yIGluZm9y
+bWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgIGRvIG5vdCBtb2RpZnkgdGhlIExpY2Vu
+c2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICBub3RpY2VzIHdpdGhp
+biBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25nc2lkZQogICAgICAg
+b3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20gdGhlIFdvcmssIHByb3Zp
+ZGVkCiAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1dGlvbiBub3RpY2VzIGNhbm5v
+dCBiZSBjb25zdHJ1ZWQKICAgICAgIGFzIG1vZGlmeWluZyB0aGUgTGljZW5zZS4KCiAgIFlvdSBt
+YXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1lbnQgdG8gWW91ciBtb2RpZmljYXRpb25z
+IGFuZAogICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFsIG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1z
+IGFuZCBjb25kaXRpb25zCiAgIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9u
+IG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IKICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29y
+a3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQgWW91ciB1c2UsCiAgIHJlcHJvZHVjdGlvbiwgYW5kIGRp
+c3RyaWJ1dGlvbiBvZiB0aGUgV29yayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICB0aGUgY29u
+ZGl0aW9ucyBzdGF0ZWQgaW4gdGhpcyBMaWNlbnNlLgoKNS4gU3VibWlzc2lvbiBvZiBDb250cmli
+dXRpb25zLiBVbmxlc3MgWW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICBhbnkgQ29u
+dHJpYnV0aW9uIGludGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdv
+cmsKICAgYnkgWW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5k
+IGNvbmRpdGlvbnMgb2YKICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRl
+cm1zIG9yIGNvbmRpdGlvbnMuCiAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcg
+aGVyZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh
+cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgd2l0aCBMaWNl
+bnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKNi4gVHJhZGVtYXJrcy4gVGhpcyBM
+aWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQogICBuYW1l
+cywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBvZiB0aGUgTGlj
+ZW5zb3IsCiAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBhbmQgY3VzdG9tYXJ5
+IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICBvcmlnaW4gb2YgdGhlIFdvcmsgYW5kIHJlcHJvZHVj
+aW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCjcuIERpc2NsYWltZXIgb2YgV2Fy
+cmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvcgogICBhZ3JlZWQgdG8g
+aW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdvcmsgKGFuZCBlYWNoCiAgIENvbnRy
+aWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25zKSBvbiBhbiAiQVMgSVMiIEJBU0lTLAog
+ICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4
+cHJlc3Mgb3IKICAgaW1wbGllZCwgaW5jbHVkaW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3
+YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1F
+UkNIQU5UQUJJTElUWSwgb3IgRklUTkVTUyBGT1IgQQogICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlv
+dSBhcmUgc29sZWx5IHJlc3BvbnNpYmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgYXBwcm9wcmlh
+dGVuZXNzIG9mIHVzaW5nIG9yIHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55
+CiAgIHJpc2tzIGFzc29jaWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVu
+ZGVyIHRoaXMgTGljZW5zZS4KCjguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVu
+dCBhbmQgdW5kZXIgbm8gbGVnYWwgdGhlb3J5LAogICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGlu
+ZyBuZWdsaWdlbmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgdW5sZXNzIHJlcXVpcmVk
+IGJ5IGFwcGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgbmVn
+bGlnZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0
+b3IgYmUKICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs
+IGluZGlyZWN0LCBzcGVjaWFsLAogICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRhbWFn
+ZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgcmVzdWx0IG9mIHRoaXMgTGljZW5z
+ZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICBXb3JrIChpbmNs
+dWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29vZHdpbGwsCiAg
+IHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rpb24sIG9yIGFueSBh
+bmQgYWxsCiAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3NzZXMpLCBldmVuIGlmIHN1
+Y2ggQ29udHJpYnV0b3IKICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0aGUgcG9zc2liaWxpdHkgb2Yg
+c3VjaCBkYW1hZ2VzLgoKOS4gQWNjZXB0aW5nIFdhcnJhbnR5IG9yIEFkZGl0aW9uYWwgTGlhYmls
+aXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICB0aGUgV29yayBvciBEZXJpdmF0aXZlIFdvcmtz
+IHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVyLAogICBhbmQgY2hhcmdlIGEgZmVlIGZv
+ciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJyYW50eSwgaW5kZW1uaXR5LAogICBvciBvdGhl
+ciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5kL29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhp
+cwogICBMaWNlbnNlLiBIb3dldmVyLCBpbiBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91
+IG1heSBhY3Qgb25seQogICBvbiBZb3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNw
+b25zaWJpbGl0eSwgbm90IG9uIGJlaGFsZgogICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFu
+ZCBvbmx5IGlmIFlvdSBhZ3JlZSB0byBpbmRlbW5pZnksCiAgIGRlZmVuZCwgYW5kIGhvbGQgZWFj
+aCBDb250cmlidXRvciBoYXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICBpbmN1cnJlZCBieSwg
+b3IgY2xhaW1zIGFzc2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAg
+IG9mIHlvdXIgYWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmls
+aXR5LgoKRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgpBUFBFTkRJWDogSG93IHRvIGFwcGx5
+IHRoZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICBUbyBhcHBseSB0aGUgQXBhY2hl
+IExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICBib2lsZXJwbGF0
+ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAgIHJl
+cGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24ndCBpbmNs
+dWRlCiAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9zZWQgaW4gdGhl
+IGFwcHJvcHJpYXRlCiAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBmb3JtYXQuIFdlIGFs
+c28gcmVjb21tZW5kIHRoYXQgYQogICBmaWxlIG9yIGNsYXNzIG5hbWUgYW5kIGRlc2NyaXB0aW9u
+IG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgIHNhbWUgInByaW50ZWQgcGFnZSIgYXMg
+dGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICBpZGVudGlmaWNhdGlvbiB3aXRoaW4g
+dGhpcmQtcGFydHkgYXJjaGl2ZXMuCgpDb3B5cmlnaHQgW3l5eXldIFtuYW1lIG9mIGNvcHlyaWdo
+dCBvd25lcl0KCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAg
+KHRoZSAiTGljZW5zZSIpOwp5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21w
+bGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGlj
+ZW5zZSBhdAoKCWh0dHBzOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjAKClVu
+bGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywg
+c29mdHdhcmUKZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24g
+YW4gIkFTIElTIiBCQVNJUywKV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5Z
+IEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuClNlZSB0aGUgTGljZW5zZSBmb3IgdGhl
+IHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmQKbGltaXRhdGlvbnMg
+dW5kZXIgdGhlIExpY2Vuc2UuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64
new file mode 100644
index 000000000..e731812cd
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDIwLTIwMjUgVGhlIFJ1c3RDcnlwdG8gUHJvamVjdCBEZXZlbG9wZXJz
+CgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBl
+cnNvbiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9j
+dW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2Fy
+ZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSBy
+aWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBz
+dWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVy
+bWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBz
+dWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQg
+bm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFs
+bCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNP
+RlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQs
+IEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FS
+UkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQ
+T1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9S
+IENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9U
+SEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1Ig
+T1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhF
+IFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/aed7b1758e35afa0cd0fde059d61950747ca11cd0e5e169cb21c11608daed772.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/aed7b1758e35afa0cd0fde059d61950747ca11cd0e5e169cb21c11608daed772.base64
new file mode 100644
index 000000000..aace13d47
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/aed7b1758e35afa0cd0fde059d61950747ca11cd0e5e169cb21c11608daed772.base64
@@ -0,0 +1,19 @@
+TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAyNSBydXRydW0KClBlcm1pc3Npb24gaXMgaGVy
+ZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNv
+cHkKb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0
+aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rp
+b24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cwp0byB1c2UsIGNvcHks
+IG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBz
+ZWxsCmNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9t
+IHRoZSBTb2Z0d2FyZSBpcwpmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxv
+d2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVy
+bWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBzdWJzdGFu
+dGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQg
+IkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJTVBMSUVE
+LCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5U
+QUJJTElUWSwKRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdF
+TUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMg
+QkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIKTElBQklMSVRZLCBXSEVU
+SEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcg
+RlJPTSwKT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVT
+RSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKU09GVFdBUkUu
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64
new file mode 100644
index 000000000..af13c8e66
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f.base64
@@ -0,0 +1,13 @@
+Q29weXJpZ2h0IMKpIDIwMTUsIFNpbW9uYXMgS2F6bGF1c2thcwoKUGVybWlzc2lvbiB0byB1c2Us
+IGNvcHksIG1vZGlmeSwgYW5kL29yIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBmb3IgYW55IHB1
+cnBvc2Ugd2l0aCBvciB3aXRob3V0CmZlZSBpcyBoZXJlYnkgZ3JhbnRlZCwgcHJvdmlkZWQgdGhh
+dCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBh
+cHBlYXIKaW4gYWxsIGNvcGllcy4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiIEFO
+RCBUSEUgQVVUSE9SIERJU0NMQUlNUyBBTEwgV0FSUkFOVElFUyBXSVRIIFJFR0FSRCBUTyBUSElT
+ClNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJ
+TElUWSBBTkQgRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCkFVVEhPUiBCRSBMSUFCTEUg
+Rk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsIElORElSRUNULCBPUiBDT05TRVFVRU5USUFMIERBTUFH
+RVMgT1IgQU5ZIERBTUFHRVMKV0hBVFNPRVZFUiBSRVNVTFRJTkcgRlJPTSBMT1NTIE9GIFVTRSwg
+REFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwKTkVHTElH
+RU5DRSBPUiBPVEhFUiBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5F
+Q1RJT04gV0lUSCBUSEUgVVNFIE9SIFBFUkZPUk1BTkNFIE9GClRISVMgU09GVFdBUkUuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1.base64
new file mode 100644
index 000000000..0bfd95fab
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1.base64
@@ -0,0 +1,200 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAg
+ICAgICAgICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgogICBURVJNUyBBTkQg
+Q09ORElUSU9OUyBGT1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCiAgIDEu
+IERlZmluaXRpb25zLgoKICAgICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBj
+b25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwKICAgICAgYW5kIGRpc3RyaWJ1dGlvbiBh
+cyBkZWZpbmVkIGJ5IFNlY3Rpb25zIDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAg
+ICAiTGljZW5zb3IiIHNoYWxsIG1lYW4gdGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0
+aG9yaXplZCBieQogICAgICB0aGUgY29weXJpZ2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhl
+IExpY2Vuc2UuCgogICAgICAiTGVnYWwgRW50aXR5IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0
+aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgICAgIG90aGVyIGVudGl0aWVzIHRoYXQgY29udHJv
+bCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRlciBjb21tb24KICAgICAgY29udHJvbCB3
+aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwKICAg
+ICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVjdCBvciBpbmRpcmVjdCwgdG8g
+Y2F1c2UgdGhlCiAgICAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9mIHN1Y2ggZW50aXR5LCB3
+aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgICAgIG90aGVyd2lzZSwgb3IgKGlpKSBvd25lcnNoaXAg
+b2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICAgICBvdXRzdGFuZGluZyBz
+aGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50aXR5LgoKICAg
+ICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExlZ2FsIEVu
+dGl0eQogICAgICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNlbnNl
+LgoKICAgICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgICAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8g
+c29mdHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgICAgc291cmNlLCBhbmQgY29u
+ZmlndXJhdGlvbiBmaWxlcy4KCiAgICAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9y
+bSByZXN1bHRpbmcgZnJvbSBtZWNoYW5pY2FsCiAgICAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5z
+bGF0aW9uIG9mIGEgU291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgICAgbm90IGxpbWl0ZWQg
+dG8gY29tcGlsZWQgb2JqZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICAgICBh
+bmQgY29udmVyc2lvbnMgdG8gb3RoZXIgbWVkaWEgdHlwZXMuCgogICAgICAiV29yayIgc2hhbGwg
+bWVhbiB0aGUgd29yayBvZiBhdXRob3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICAgICBP
+YmplY3QgZm9ybSwgbWFkZSBhdmFpbGFibGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRl
+ZCBieSBhCiAgICAgIGNvcHlyaWdodCBub3RpY2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRh
+Y2hlZCB0byB0aGUgd29yawogICAgICAoYW4gZXhhbXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBw
+ZW5kaXggYmVsb3cpLgoKICAgICAgIkRlcml2YXRpdmUgV29ya3MiIHNoYWxsIG1lYW4gYW55IHdv
+cmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAogICAgICBmb3JtLCB0aGF0IGlzIGJhc2Vk
+IG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBmb3Igd2hpY2ggdGhlCiAgICAgIGVk
+aXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3JhdGlvbnMsIG9yIG90aGVyIG1v
+ZGlmaWNhdGlvbnMKICAgICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBhbiBvcmlnaW5hbCB3b3Jr
+IG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgICAgb2YgdGhpcyBMaWNlbnNlLCBE
+ZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQgcmVtYWluCiAgICAg
+IHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1lKSB0byB0aGUg
+aW50ZXJmYWNlcyBvZiwKICAgICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3MgdGhlcmVv
+Zi4KCiAgICAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9yc2hp
+cCwgaW5jbHVkaW5nCiAgICAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgICAgdG8gdGhhdCBXb3JrIG9yIERlcml2
+YXRpdmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgICAgIHN1Ym1pdHRl
+ZCB0byBMaWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQg
+b3duZXIKICAgICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXpl
+ZCB0byBzdWJtaXQgb24gYmVoYWxmIG9mCiAgICAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0
+aGUgcHVycG9zZXMgb2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICAgICBtZWFucyBh
+bnkgZm9ybSBvZiBlbGVjdHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBz
+ZW50CiAgICAgIHRvIHRoZSBMaWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRp
+bmcgYnV0IG5vdCBsaW1pdGVkIHRvCiAgICAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBt
+YWlsaW5nIGxpc3RzLCBzb3VyY2UgY29kZSBjb250cm9sIHN5c3RlbXMsCiAgICAgIGFuZCBpc3N1
+ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQgYXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwg
+dGhlCiAgICAgIExpY2Vuc29yIGZvciB0aGUgcHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXBy
+b3ZpbmcgdGhlIFdvcmssIGJ1dAogICAgICBleGNsdWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlz
+IGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVyd2lzZQogICAgICBkZXNpZ25hdGVkIGluIHdy
+aXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAiTm90IGEgQ29udHJpYnV0aW9uLiIKCiAg
+ICAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNvciBhbmQgYW55IGluZGl2aWR1YWwg
+b3IgTGVnYWwgRW50aXR5CiAgICAgIG9uIGJlaGFsZiBvZiB3aG9tIGEgQ29udHJpYnV0aW9uIGhh
+cyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICAgICBzdWJzZXF1ZW50bHkgaW5jb3Jw
+b3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCiAgIDIuIEdyYW50IG9mIENvcHlyaWdodCBMaWNlbnNl
+LiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICAgICB0aGlzIExpY2Vu
+c2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsCiAg
+ICAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGly
+cmV2b2NhYmxlCiAgICAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFyZSBE
+ZXJpdmF0aXZlIFdvcmtzIG9mLAogICAgICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgICAgV29yayBhbmQgc3VjaCBE
+ZXJpdmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCiAgIDMuIEdyYW50IG9m
+IFBhdGVudCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgog
+ICAgICB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3Ug
+YSBwZXJwZXR1YWwsCiAgICAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCBy
+b3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlCiAgICAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMg
+c2VjdGlvbikgcGF0ZW50IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICAgICB1c2UsIG9m
+ZmVyIHRvIHNlbGwsIHNlbGwsIGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29y
+aywKICAgICAgd2hlcmUgc3VjaCBsaWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQg
+Y2xhaW1zIGxpY2Vuc2FibGUKICAgICAgYnkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNl
+c3NhcmlseSBpbmZyaW5nZWQgYnkgdGhlaXIKICAgICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9y
+IGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENvbnRyaWJ1dGlvbihzKQogICAgICB3aXRoIHRoZSBX
+b3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9uKHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQog
+ICAgICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24gYWdhaW5zdCBhbnkgZW50aXR5IChpbmNs
+dWRpbmcgYQogICAgICBjcm9zcy1jbGFpbSBvciBjb3VudGVyY2xhaW0gaW4gYSBsYXdzdWl0KSBh
+bGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgICAgIG9yIGEgQ29udHJpYnV0aW9uIGluY29ycG9yYXRl
+ZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAgICAgIG9yIGNvbnRyaWJ1dG9y
+eSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGljZW5zZXMKICAgICAgZ3Jh
+bnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsgc2hhbGwgdGVybWlu
+YXRlCiAgICAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxlZC4KCiAgIDQu
+IFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBjb3BpZXMg
+b2YgdGhlCiAgICAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBtZWRp
+dW0sIHdpdGggb3Igd2l0aG91dAogICAgICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICAgICBtZWV0IHRoZSBmb2xsb3dpbmcg
+Y29uZGl0aW9uczoKCiAgICAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRz
+IG9mIHRoZSBXb3JrIG9yCiAgICAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlz
+IExpY2Vuc2U7IGFuZAoKICAgICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxl
+cyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcwogICAgICAgICAgc3RhdGluZyB0aGF0IFlvdSBj
+aGFuZ2VkIHRoZSBmaWxlczsgYW5kCgogICAgICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUg
+U291cmNlIGZvcm0gb2YgYW55IERlcml2YXRpdmUgV29ya3MKICAgICAgICAgIHRoYXQgWW91IGRp
+c3RyaWJ1dGUsIGFsbCBjb3B5cmlnaHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgICAg
+IGF0dHJpYnV0aW9uIG5vdGljZXMgZnJvbSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAg
+ICAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFu
+eSBwYXJ0IG9mCiAgICAgICAgICB0aGUgRGVyaXZhdGl2ZSBXb3JrczsgYW5kCgogICAgICAoZCkg
+SWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMK
+ICAgICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlv
+dSBkaXN0cmlidXRlIG11c3QKICAgICAgICAgIGluY2x1ZGUgYSByZWFkYWJsZSBjb3B5IG9mIHRo
+ZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAgICAgd2l0aGluIHN1Y2ggTk9U
+SUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8gbm90CiAgICAgICAgICBw
+ZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpbiBhdCBsZWFzdCBv
+bmUKICAgICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBOT1RJQ0UgdGV4
+dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdv
+cmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICAgICBkb2N1bWVudGF0aW9uLCBp
+ZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBh
+cHBlYXIuIFRoZSBjb250ZW50cwogICAgICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3Ig
+aW5mb3JtYXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgICAgZG8gbm90IG1vZGlmeSB0
+aGUgTGljZW5zZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgICAgIG5v
+dGljZXMgd2l0aGluIERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdz
+aWRlCiAgICAgICAgICBvciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0
+aGUgV29yaywgcHJvdmlkZWQKICAgICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0
+aW9uIG5vdGljZXMgY2Fubm90IGJlIGNvbnN0cnVlZAogICAgICAgICAgYXMgbW9kaWZ5aW5nIHRo
+ZSBMaWNlbnNlLgoKICAgICAgWW91IG1heSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVu
+dCB0byBZb3VyIG1vZGlmaWNhdGlvbnMgYW5kCiAgICAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwg
+b3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMgYW5kIGNvbmRpdGlvbnMKICAgICAgZm9yIHVzZSwg
+cmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24gb2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgog
+ICAgICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBhcyBhIHdob2xlLCBwcm92aWRlZCBZ
+b3VyIHVzZSwKICAgICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlzdHJpYnV0aW9uIG9mIHRoZSBXb3Jr
+IG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgICAgIHRoZSBjb25kaXRpb25zIHN0YXRlZCBpbiB0
+aGlzIExpY2Vuc2UuCgogICA1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1dGlvbnMuIFVubGVzcyBZ
+b3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgICAgIGFueSBDb250cmlidXRpb24gaW50
+ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yawogICAgICBieSBZ
+b3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9u
+cyBvZgogICAgICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVybXMgb3Ig
+Y29uZGl0aW9ucy4KICAgICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBoZXJl
+aW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICAgICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICAgICB3aXRoIExp
+Y2Vuc29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgogICA2LiBUcmFkZW1hcmtzLiBU
+aGlzIExpY2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAg
+ICAgIG5hbWVzLCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9m
+IHRoZSBMaWNlbnNvciwKICAgICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFu
+ZCBjdXN0b21hcnkgdXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgICAgIG9yaWdpbiBvZiB0aGUgV29y
+ayBhbmQgcmVwcm9kdWNpbmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKICAgNy4g
+RGlzY2xhaW1lciBvZiBXYXJyYW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3
+IG9yCiAgICAgIGFncmVlZCB0byBpbiB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29y
+ayAoYW5kIGVhY2gKICAgICAgQ29udHJpYnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMp
+IG9uIGFuICJBUyBJUyIgQkFTSVMsCiAgICAgIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJ
+T05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvcgogICAgICBpbXBsaWVkLCBpbmNsdWRp
+bmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdhcnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICAg
+ICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVSQ0hBTlRBQklMSVRZLCBvciBGSVRORVNT
+IEZPUiBBCiAgICAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91IGFyZSBzb2xlbHkgcmVzcG9uc2li
+bGUgZm9yIGRldGVybWluaW5nIHRoZQogICAgICBhcHByb3ByaWF0ZW5lc3Mgb2YgdXNpbmcgb3Ig
+cmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkKICAgICAgcmlza3MgYXNzb2Np
+YXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5kZXIgdGhpcyBMaWNlbnNl
+LgoKICAgOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50IGFuZCB1bmRlciBu
+byBsZWdhbCB0aGVvcnksCiAgICAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5nIG5lZ2xpZ2Vu
+Y2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICAgICB1bmxlc3MgcmVxdWlyZWQgYnkgYXBw
+bGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICAgICBuZWdsaWdl
+bnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRvciBi
+ZQogICAgICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgICAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFt
+YWdlcyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICAgICByZXN1bHQgb2YgdGhpcyBM
+aWNlbnNlIG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgICAgIFdv
+cmsgKGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29k
+d2lsbCwKICAgICAgd29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlv
+biwgb3IgYW55IGFuZCBhbGwKICAgICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3Nl
+cyksIGV2ZW4gaWYgc3VjaCBDb250cmlidXRvcgogICAgICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRo
+ZSBwb3NzaWJpbGl0eSBvZiBzdWNoIGRhbWFnZXMuCgogICA5LiBBY2NlcHRpbmcgV2FycmFudHkg
+b3IgQWRkaXRpb25hbCBMaWFiaWxpdHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgICAgIHRoZSBX
+b3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIs
+CiAgICAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9yLCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJh
+bnR5LCBpbmRlbW5pdHksCiAgICAgIG9yIG90aGVyIGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQv
+b3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlzCiAgICAgIExpY2Vuc2UuIEhvd2V2ZXIsIGlu
+IGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3UgbWF5IGFjdCBvbmx5CiAgICAgIG9uIFlv
+dXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3BvbnNpYmlsaXR5LCBub3Qgb24gYmVo
+YWxmCiAgICAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5kIG9ubHkgaWYgWW91IGFncmVl
+IHRvIGluZGVtbmlmeSwKICAgICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNoIENvbnRyaWJ1dG9yIGhh
+cm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgICAgIGluY3VycmVkIGJ5LCBvciBjbGFpbXMgYXNz
+ZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAgICAgb2YgeW91ciBh
+Y2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxpdHkuCgogICBF
+TkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCiAgIEFQUEVORElYOiBIb3cgdG8gYXBwbHkgdGhl
+IEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgICAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgICAgIGJvaWxlcnBs
+YXRlIG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJ7fSIKICAg
+ICAgcmVwbGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0
+IGluY2x1ZGUKICAgICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3Nl
+ZCBpbiB0aGUgYXBwcm9wcmlhdGUKICAgICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZv
+cm1hdC4gV2UgYWxzbyByZWNvbW1lbmQgdGhhdCBhCiAgICAgIGZpbGUgb3IgY2xhc3MgbmFtZSBh
+bmQgZGVzY3JpcHRpb24gb2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgICAgc2FtZSAi
+cHJpbnRlZCBwYWdlIiBhcyB0aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgICAgIGlk
+ZW50aWZpY2F0aW9uIHdpdGhpbiB0aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCiAgIENvcHlyaWdodCB7
+eXl5eX0ge25hbWUgb2YgY29weXJpZ2h0IG93bmVyfQoKICAgTGljZW5zZWQgdW5kZXIgdGhlIEFw
+YWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiAgIHlvdSBtYXkgbm90
+IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICAg
+WW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CgogICAgICAgaHR0cDovL3d3
+dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgogICBVbmxlc3MgcmVxdWlyZWQgYnkg
+YXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAgIGRpc3Ry
+aWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFT
+SVMsCiAgIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRo
+ZXIgZXhwcmVzcyBvciBpbXBsaWVkLgogICBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZp
+YyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAgIGxpbWl0YXRpb25zIHVuZGVy
+IHRoZSBMaWNlbnNlLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64
new file mode 100644
index 000000000..7d7e9de8a
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1.base64
@@ -0,0 +1,20 @@
+Q29weXJpZ2h0IChjKSAyMDA2LTIwMDkgR3JheWRvbiBIb2FyZQpDb3B5cmlnaHQgKGMpIDIwMDkt
+MjAxMyBNb3ppbGxhIEZvdW5kYXRpb24KQ29weXJpZ2h0IChjKSAyMDE2IEFydHlvbSBQYXZsb3YK
+ClBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkKcGVy
+c29uIG9idGFpbmluZyBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZApkb2N1
+bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4gdGhlClNvZnR3YXJl
+IHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0CmxpbWl0YXRpb24gdGhlIHJp
+Z2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsCnB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1
+YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJt
+aXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZQppcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1
+YmplY3QgdG8gdGhlIGZvbGxvd2luZwpjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBu
+b3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2UKc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxs
+IGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucwpvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09G
+VFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRgpBTlkgS0lORCwg
+RVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIFRIRSBXQVJS
+QU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQQpQQVJUSUNVTEFSIFBVUlBP
+U0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQKU0hBTEwgVEhFIEFVVEhPUlMgT1Ig
+Q09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkKQ0xBSU0sIERBTUFHRVMgT1IgT1RI
+RVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTgpPRiBDT05UUkFDVCwgVE9SVCBPUiBP
+VEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SCklOIENPTk5FQ1RJT04gV0lUSCBUSEUg
+U09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUgpERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/bccaa8b6c09f94e81f06696e179dbe058464bbdfbc823b6d49cada1d71e84ac3.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/bccaa8b6c09f94e81f06696e179dbe058464bbdfbc823b6d49cada1d71e84ac3.base64
new file mode 100644
index 000000000..fe7259a73
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/bccaa8b6c09f94e81f06696e179dbe058464bbdfbc823b6d49cada1d71e84ac3.base64
@@ -0,0 +1,18 @@
+UGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJz
+b24gb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3Vt
+ZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUg
+d2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmln
+aHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3Vi
+bGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1p
+dCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3Vi
+amVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5v
+dGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwg
+Y29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZU
+V0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBF
+WFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJB
+TlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9T
+RSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBD
+T1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhF
+UiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9U
+SEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBT
+T0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64
new file mode 100644
index 000000000..bd0f672a5
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583.base64
@@ -0,0 +1,20 @@
+VGhlIE1JVCBMaWNlbnNlIChNSVQpDQoNCkNvcHlyaWdodCAoYykgMjAxNSBCYXJ0xYJvbWllaiBL
+YW1pxYRza2kNCg0KUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2Us
+IHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weQ0Kb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNz
+b2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwNCmlu
+IHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1p
+dGF0aW9uIHRoZSByaWdodHMNCnRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwg
+ZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwNCmNvcGllcyBvZiB0aGUgU29mdHdh
+cmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcw0KZnVybmlz
+aGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoNCg0KVGhl
+IGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwg
+YmUgaW5jbHVkZWQgaW4gYWxsDQpjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhl
+IFNvZnR3YXJlLg0KDQpUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiwgV0lUSE9VVCBX
+QVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUg0KSU1QTElFRCwgSU5DTFVESU5HIEJVVCBO
+T1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksDQpGSVRORVNT
+IEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVO
+VCBTSEFMTCBUSEUNCkFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBB
+TlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVINCkxJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJ
+T04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sDQpPVVQgT0Yg
+T1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERF
+QUxJTkdTIElOIFRIRQ0KU09GVFdBUkUu
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b.base64
new file mode 100644
index 000000000..24b4a9f3d
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b.base64
@@ -0,0 +1,200 @@
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQXBhY2hlIExpY2Vuc2UKICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgVmVyc2lvbiAyLjAsIEphbnVhcnkgMjAwNAogICAgICAgICAgICAg
+ICAgICAgICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvCgogICBURVJNUyBBTkQg
+Q09ORElUSU9OUyBGT1IgVVNFLCBSRVBST0RVQ1RJT04sIEFORCBESVNUUklCVVRJT04KCiAgIDEu
+IERlZmluaXRpb25zLgoKICAgICAgIkxpY2Vuc2UiIHNoYWxsIG1lYW4gdGhlIHRlcm1zIGFuZCBj
+b25kaXRpb25zIGZvciB1c2UsIHJlcHJvZHVjdGlvbiwKICAgICAgYW5kIGRpc3RyaWJ1dGlvbiBh
+cyBkZWZpbmVkIGJ5IFNlY3Rpb25zIDEgdGhyb3VnaCA5IG9mIHRoaXMgZG9jdW1lbnQuCgogICAg
+ICAiTGljZW5zb3IiIHNoYWxsIG1lYW4gdGhlIGNvcHlyaWdodCBvd25lciBvciBlbnRpdHkgYXV0
+aG9yaXplZCBieQogICAgICB0aGUgY29weXJpZ2h0IG93bmVyIHRoYXQgaXMgZ3JhbnRpbmcgdGhl
+IExpY2Vuc2UuCgogICAgICAiTGVnYWwgRW50aXR5IiBzaGFsbCBtZWFuIHRoZSB1bmlvbiBvZiB0
+aGUgYWN0aW5nIGVudGl0eSBhbmQgYWxsCiAgICAgIG90aGVyIGVudGl0aWVzIHRoYXQgY29udHJv
+bCwgYXJlIGNvbnRyb2xsZWQgYnksIG9yIGFyZSB1bmRlciBjb21tb24KICAgICAgY29udHJvbCB3
+aXRoIHRoYXQgZW50aXR5LiBGb3IgdGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwKICAg
+ICAgImNvbnRyb2wiIG1lYW5zIChpKSB0aGUgcG93ZXIsIGRpcmVjdCBvciBpbmRpcmVjdCwgdG8g
+Y2F1c2UgdGhlCiAgICAgIGRpcmVjdGlvbiBvciBtYW5hZ2VtZW50IG9mIHN1Y2ggZW50aXR5LCB3
+aGV0aGVyIGJ5IGNvbnRyYWN0IG9yCiAgICAgIG90aGVyd2lzZSwgb3IgKGlpKSBvd25lcnNoaXAg
+b2YgZmlmdHkgcGVyY2VudCAoNTAlKSBvciBtb3JlIG9mIHRoZQogICAgICBvdXRzdGFuZGluZyBz
+aGFyZXMsIG9yIChpaWkpIGJlbmVmaWNpYWwgb3duZXJzaGlwIG9mIHN1Y2ggZW50aXR5LgoKICAg
+ICAgIllvdSIgKG9yICJZb3VyIikgc2hhbGwgbWVhbiBhbiBpbmRpdmlkdWFsIG9yIExlZ2FsIEVu
+dGl0eQogICAgICBleGVyY2lzaW5nIHBlcm1pc3Npb25zIGdyYW50ZWQgYnkgdGhpcyBMaWNlbnNl
+LgoKICAgICAgIlNvdXJjZSIgZm9ybSBzaGFsbCBtZWFuIHRoZSBwcmVmZXJyZWQgZm9ybSBmb3Ig
+bWFraW5nIG1vZGlmaWNhdGlvbnMsCiAgICAgIGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8g
+c29mdHdhcmUgc291cmNlIGNvZGUsIGRvY3VtZW50YXRpb24KICAgICAgc291cmNlLCBhbmQgY29u
+ZmlndXJhdGlvbiBmaWxlcy4KCiAgICAgICJPYmplY3QiIGZvcm0gc2hhbGwgbWVhbiBhbnkgZm9y
+bSByZXN1bHRpbmcgZnJvbSBtZWNoYW5pY2FsCiAgICAgIHRyYW5zZm9ybWF0aW9uIG9yIHRyYW5z
+bGF0aW9uIG9mIGEgU291cmNlIGZvcm0sIGluY2x1ZGluZyBidXQKICAgICAgbm90IGxpbWl0ZWQg
+dG8gY29tcGlsZWQgb2JqZWN0IGNvZGUsIGdlbmVyYXRlZCBkb2N1bWVudGF0aW9uLAogICAgICBh
+bmQgY29udmVyc2lvbnMgdG8gb3RoZXIgbWVkaWEgdHlwZXMuCgogICAgICAiV29yayIgc2hhbGwg
+bWVhbiB0aGUgd29yayBvZiBhdXRob3JzaGlwLCB3aGV0aGVyIGluIFNvdXJjZSBvcgogICAgICBP
+YmplY3QgZm9ybSwgbWFkZSBhdmFpbGFibGUgdW5kZXIgdGhlIExpY2Vuc2UsIGFzIGluZGljYXRl
+ZCBieSBhCiAgICAgIGNvcHlyaWdodCBub3RpY2UgdGhhdCBpcyBpbmNsdWRlZCBpbiBvciBhdHRh
+Y2hlZCB0byB0aGUgd29yawogICAgICAoYW4gZXhhbXBsZSBpcyBwcm92aWRlZCBpbiB0aGUgQXBw
+ZW5kaXggYmVsb3cpLgoKICAgICAgIkRlcml2YXRpdmUgV29ya3MiIHNoYWxsIG1lYW4gYW55IHdv
+cmssIHdoZXRoZXIgaW4gU291cmNlIG9yIE9iamVjdAogICAgICBmb3JtLCB0aGF0IGlzIGJhc2Vk
+IG9uIChvciBkZXJpdmVkIGZyb20pIHRoZSBXb3JrIGFuZCBmb3Igd2hpY2ggdGhlCiAgICAgIGVk
+aXRvcmlhbCByZXZpc2lvbnMsIGFubm90YXRpb25zLCBlbGFib3JhdGlvbnMsIG9yIG90aGVyIG1v
+ZGlmaWNhdGlvbnMKICAgICAgcmVwcmVzZW50LCBhcyBhIHdob2xlLCBhbiBvcmlnaW5hbCB3b3Jr
+IG9mIGF1dGhvcnNoaXAuIEZvciB0aGUgcHVycG9zZXMKICAgICAgb2YgdGhpcyBMaWNlbnNlLCBE
+ZXJpdmF0aXZlIFdvcmtzIHNoYWxsIG5vdCBpbmNsdWRlIHdvcmtzIHRoYXQgcmVtYWluCiAgICAg
+IHNlcGFyYWJsZSBmcm9tLCBvciBtZXJlbHkgbGluayAob3IgYmluZCBieSBuYW1lKSB0byB0aGUg
+aW50ZXJmYWNlcyBvZiwKICAgICAgdGhlIFdvcmsgYW5kIERlcml2YXRpdmUgV29ya3MgdGhlcmVv
+Zi4KCiAgICAgICJDb250cmlidXRpb24iIHNoYWxsIG1lYW4gYW55IHdvcmsgb2YgYXV0aG9yc2hp
+cCwgaW5jbHVkaW5nCiAgICAgIHRoZSBvcmlnaW5hbCB2ZXJzaW9uIG9mIHRoZSBXb3JrIGFuZCBh
+bnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbnMKICAgICAgdG8gdGhhdCBXb3JrIG9yIERlcml2
+YXRpdmUgV29ya3MgdGhlcmVvZiwgdGhhdCBpcyBpbnRlbnRpb25hbGx5CiAgICAgIHN1Ym1pdHRl
+ZCB0byBMaWNlbnNvciBmb3IgaW5jbHVzaW9uIGluIHRoZSBXb3JrIGJ5IHRoZSBjb3B5cmlnaHQg
+b3duZXIKICAgICAgb3IgYnkgYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBFbnRpdHkgYXV0aG9yaXpl
+ZCB0byBzdWJtaXQgb24gYmVoYWxmIG9mCiAgICAgIHRoZSBjb3B5cmlnaHQgb3duZXIuIEZvciB0
+aGUgcHVycG9zZXMgb2YgdGhpcyBkZWZpbml0aW9uLCAic3VibWl0dGVkIgogICAgICBtZWFucyBh
+bnkgZm9ybSBvZiBlbGVjdHJvbmljLCB2ZXJiYWwsIG9yIHdyaXR0ZW4gY29tbXVuaWNhdGlvbiBz
+ZW50CiAgICAgIHRvIHRoZSBMaWNlbnNvciBvciBpdHMgcmVwcmVzZW50YXRpdmVzLCBpbmNsdWRp
+bmcgYnV0IG5vdCBsaW1pdGVkIHRvCiAgICAgIGNvbW11bmljYXRpb24gb24gZWxlY3Ryb25pYyBt
+YWlsaW5nIGxpc3RzLCBzb3VyY2UgY29kZSBjb250cm9sIHN5c3RlbXMsCiAgICAgIGFuZCBpc3N1
+ZSB0cmFja2luZyBzeXN0ZW1zIHRoYXQgYXJlIG1hbmFnZWQgYnksIG9yIG9uIGJlaGFsZiBvZiwg
+dGhlCiAgICAgIExpY2Vuc29yIGZvciB0aGUgcHVycG9zZSBvZiBkaXNjdXNzaW5nIGFuZCBpbXBy
+b3ZpbmcgdGhlIFdvcmssIGJ1dAogICAgICBleGNsdWRpbmcgY29tbXVuaWNhdGlvbiB0aGF0IGlz
+IGNvbnNwaWN1b3VzbHkgbWFya2VkIG9yIG90aGVyd2lzZQogICAgICBkZXNpZ25hdGVkIGluIHdy
+aXRpbmcgYnkgdGhlIGNvcHlyaWdodCBvd25lciBhcyAiTm90IGEgQ29udHJpYnV0aW9uLiIKCiAg
+ICAgICJDb250cmlidXRvciIgc2hhbGwgbWVhbiBMaWNlbnNvciBhbmQgYW55IGluZGl2aWR1YWwg
+b3IgTGVnYWwgRW50aXR5CiAgICAgIG9uIGJlaGFsZiBvZiB3aG9tIGEgQ29udHJpYnV0aW9uIGhh
+cyBiZWVuIHJlY2VpdmVkIGJ5IExpY2Vuc29yIGFuZAogICAgICBzdWJzZXF1ZW50bHkgaW5jb3Jw
+b3JhdGVkIHdpdGhpbiB0aGUgV29yay4KCiAgIDIuIEdyYW50IG9mIENvcHlyaWdodCBMaWNlbnNl
+LiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgogICAgICB0aGlzIExpY2Vu
+c2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3UgYSBwZXJwZXR1YWwsCiAg
+ICAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCByb3lhbHR5LWZyZWUsIGly
+cmV2b2NhYmxlCiAgICAgIGNvcHlyaWdodCBsaWNlbnNlIHRvIHJlcHJvZHVjZSwgcHJlcGFyZSBE
+ZXJpdmF0aXZlIFdvcmtzIG9mLAogICAgICBwdWJsaWNseSBkaXNwbGF5LCBwdWJsaWNseSBwZXJm
+b3JtLCBzdWJsaWNlbnNlLCBhbmQgZGlzdHJpYnV0ZSB0aGUKICAgICAgV29yayBhbmQgc3VjaCBE
+ZXJpdmF0aXZlIFdvcmtzIGluIFNvdXJjZSBvciBPYmplY3QgZm9ybS4KCiAgIDMuIEdyYW50IG9m
+IFBhdGVudCBMaWNlbnNlLiBTdWJqZWN0IHRvIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZgog
+ICAgICB0aGlzIExpY2Vuc2UsIGVhY2ggQ29udHJpYnV0b3IgaGVyZWJ5IGdyYW50cyB0byBZb3Ug
+YSBwZXJwZXR1YWwsCiAgICAgIHdvcmxkd2lkZSwgbm9uLWV4Y2x1c2l2ZSwgbm8tY2hhcmdlLCBy
+b3lhbHR5LWZyZWUsIGlycmV2b2NhYmxlCiAgICAgIChleGNlcHQgYXMgc3RhdGVkIGluIHRoaXMg
+c2VjdGlvbikgcGF0ZW50IGxpY2Vuc2UgdG8gbWFrZSwgaGF2ZSBtYWRlLAogICAgICB1c2UsIG9m
+ZmVyIHRvIHNlbGwsIHNlbGwsIGltcG9ydCwgYW5kIG90aGVyd2lzZSB0cmFuc2ZlciB0aGUgV29y
+aywKICAgICAgd2hlcmUgc3VjaCBsaWNlbnNlIGFwcGxpZXMgb25seSB0byB0aG9zZSBwYXRlbnQg
+Y2xhaW1zIGxpY2Vuc2FibGUKICAgICAgYnkgc3VjaCBDb250cmlidXRvciB0aGF0IGFyZSBuZWNl
+c3NhcmlseSBpbmZyaW5nZWQgYnkgdGhlaXIKICAgICAgQ29udHJpYnV0aW9uKHMpIGFsb25lIG9y
+IGJ5IGNvbWJpbmF0aW9uIG9mIHRoZWlyIENvbnRyaWJ1dGlvbihzKQogICAgICB3aXRoIHRoZSBX
+b3JrIHRvIHdoaWNoIHN1Y2ggQ29udHJpYnV0aW9uKHMpIHdhcyBzdWJtaXR0ZWQuIElmIFlvdQog
+ICAgICBpbnN0aXR1dGUgcGF0ZW50IGxpdGlnYXRpb24gYWdhaW5zdCBhbnkgZW50aXR5IChpbmNs
+dWRpbmcgYQogICAgICBjcm9zcy1jbGFpbSBvciBjb3VudGVyY2xhaW0gaW4gYSBsYXdzdWl0KSBh
+bGxlZ2luZyB0aGF0IHRoZSBXb3JrCiAgICAgIG9yIGEgQ29udHJpYnV0aW9uIGluY29ycG9yYXRl
+ZCB3aXRoaW4gdGhlIFdvcmsgY29uc3RpdHV0ZXMgZGlyZWN0CiAgICAgIG9yIGNvbnRyaWJ1dG9y
+eSBwYXRlbnQgaW5mcmluZ2VtZW50LCB0aGVuIGFueSBwYXRlbnQgbGljZW5zZXMKICAgICAgZ3Jh
+bnRlZCB0byBZb3UgdW5kZXIgdGhpcyBMaWNlbnNlIGZvciB0aGF0IFdvcmsgc2hhbGwgdGVybWlu
+YXRlCiAgICAgIGFzIG9mIHRoZSBkYXRlIHN1Y2ggbGl0aWdhdGlvbiBpcyBmaWxlZC4KCiAgIDQu
+IFJlZGlzdHJpYnV0aW9uLiBZb3UgbWF5IHJlcHJvZHVjZSBhbmQgZGlzdHJpYnV0ZSBjb3BpZXMg
+b2YgdGhlCiAgICAgIFdvcmsgb3IgRGVyaXZhdGl2ZSBXb3JrcyB0aGVyZW9mIGluIGFueSBtZWRp
+dW0sIHdpdGggb3Igd2l0aG91dAogICAgICBtb2RpZmljYXRpb25zLCBhbmQgaW4gU291cmNlIG9y
+IE9iamVjdCBmb3JtLCBwcm92aWRlZCB0aGF0IFlvdQogICAgICBtZWV0IHRoZSBmb2xsb3dpbmcg
+Y29uZGl0aW9uczoKCiAgICAgIChhKSBZb3UgbXVzdCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRz
+IG9mIHRoZSBXb3JrIG9yCiAgICAgICAgICBEZXJpdmF0aXZlIFdvcmtzIGEgY29weSBvZiB0aGlz
+IExpY2Vuc2U7IGFuZAoKICAgICAgKGIpIFlvdSBtdXN0IGNhdXNlIGFueSBtb2RpZmllZCBmaWxl
+cyB0byBjYXJyeSBwcm9taW5lbnQgbm90aWNlcwogICAgICAgICAgc3RhdGluZyB0aGF0IFlvdSBj
+aGFuZ2VkIHRoZSBmaWxlczsgYW5kCgogICAgICAoYykgWW91IG11c3QgcmV0YWluLCBpbiB0aGUg
+U291cmNlIGZvcm0gb2YgYW55IERlcml2YXRpdmUgV29ya3MKICAgICAgICAgIHRoYXQgWW91IGRp
+c3RyaWJ1dGUsIGFsbCBjb3B5cmlnaHQsIHBhdGVudCwgdHJhZGVtYXJrLCBhbmQKICAgICAgICAg
+IGF0dHJpYnV0aW9uIG5vdGljZXMgZnJvbSB0aGUgU291cmNlIGZvcm0gb2YgdGhlIFdvcmssCiAg
+ICAgICAgICBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdCBwZXJ0YWluIHRvIGFu
+eSBwYXJ0IG9mCiAgICAgICAgICB0aGUgRGVyaXZhdGl2ZSBXb3JrczsgYW5kCgogICAgICAoZCkg
+SWYgdGhlIFdvcmsgaW5jbHVkZXMgYSAiTk9USUNFIiB0ZXh0IGZpbGUgYXMgcGFydCBvZiBpdHMK
+ICAgICAgICAgIGRpc3RyaWJ1dGlvbiwgdGhlbiBhbnkgRGVyaXZhdGl2ZSBXb3JrcyB0aGF0IFlv
+dSBkaXN0cmlidXRlIG11c3QKICAgICAgICAgIGluY2x1ZGUgYSByZWFkYWJsZSBjb3B5IG9mIHRo
+ZSBhdHRyaWJ1dGlvbiBub3RpY2VzIGNvbnRhaW5lZAogICAgICAgICAgd2l0aGluIHN1Y2ggTk9U
+SUNFIGZpbGUsIGV4Y2x1ZGluZyB0aG9zZSBub3RpY2VzIHRoYXQgZG8gbm90CiAgICAgICAgICBw
+ZXJ0YWluIHRvIGFueSBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpbiBhdCBsZWFzdCBv
+bmUKICAgICAgICAgIG9mIHRoZSBmb2xsb3dpbmcgcGxhY2VzOiB3aXRoaW4gYSBOT1RJQ0UgdGV4
+dCBmaWxlIGRpc3RyaWJ1dGVkCiAgICAgICAgICBhcyBwYXJ0IG9mIHRoZSBEZXJpdmF0aXZlIFdv
+cmtzOyB3aXRoaW4gdGhlIFNvdXJjZSBmb3JtIG9yCiAgICAgICAgICBkb2N1bWVudGF0aW9uLCBp
+ZiBwcm92aWRlZCBhbG9uZyB3aXRoIHRoZSBEZXJpdmF0aXZlIFdvcmtzOyBvciwKICAgICAgICAg
+IHdpdGhpbiBhIGRpc3BsYXkgZ2VuZXJhdGVkIGJ5IHRoZSBEZXJpdmF0aXZlIFdvcmtzLCBpZiBh
+bmQKICAgICAgICAgIHdoZXJldmVyIHN1Y2ggdGhpcmQtcGFydHkgbm90aWNlcyBub3JtYWxseSBh
+cHBlYXIuIFRoZSBjb250ZW50cwogICAgICAgICAgb2YgdGhlIE5PVElDRSBmaWxlIGFyZSBmb3Ig
+aW5mb3JtYXRpb25hbCBwdXJwb3NlcyBvbmx5IGFuZAogICAgICAgICAgZG8gbm90IG1vZGlmeSB0
+aGUgTGljZW5zZS4gWW91IG1heSBhZGQgWW91ciBvd24gYXR0cmlidXRpb24KICAgICAgICAgIG5v
+dGljZXMgd2l0aGluIERlcml2YXRpdmUgV29ya3MgdGhhdCBZb3UgZGlzdHJpYnV0ZSwgYWxvbmdz
+aWRlCiAgICAgICAgICBvciBhcyBhbiBhZGRlbmR1bSB0byB0aGUgTk9USUNFIHRleHQgZnJvbSB0
+aGUgV29yaywgcHJvdmlkZWQKICAgICAgICAgIHRoYXQgc3VjaCBhZGRpdGlvbmFsIGF0dHJpYnV0
+aW9uIG5vdGljZXMgY2Fubm90IGJlIGNvbnN0cnVlZAogICAgICAgICAgYXMgbW9kaWZ5aW5nIHRo
+ZSBMaWNlbnNlLgoKICAgICAgWW91IG1heSBhZGQgWW91ciBvd24gY29weXJpZ2h0IHN0YXRlbWVu
+dCB0byBZb3VyIG1vZGlmaWNhdGlvbnMgYW5kCiAgICAgIG1heSBwcm92aWRlIGFkZGl0aW9uYWwg
+b3IgZGlmZmVyZW50IGxpY2Vuc2UgdGVybXMgYW5kIGNvbmRpdGlvbnMKICAgICAgZm9yIHVzZSwg
+cmVwcm9kdWN0aW9uLCBvciBkaXN0cmlidXRpb24gb2YgWW91ciBtb2RpZmljYXRpb25zLCBvcgog
+ICAgICBmb3IgYW55IHN1Y2ggRGVyaXZhdGl2ZSBXb3JrcyBhcyBhIHdob2xlLCBwcm92aWRlZCBZ
+b3VyIHVzZSwKICAgICAgcmVwcm9kdWN0aW9uLCBhbmQgZGlzdHJpYnV0aW9uIG9mIHRoZSBXb3Jr
+IG90aGVyd2lzZSBjb21wbGllcyB3aXRoCiAgICAgIHRoZSBjb25kaXRpb25zIHN0YXRlZCBpbiB0
+aGlzIExpY2Vuc2UuCgogICA1LiBTdWJtaXNzaW9uIG9mIENvbnRyaWJ1dGlvbnMuIFVubGVzcyBZ
+b3UgZXhwbGljaXRseSBzdGF0ZSBvdGhlcndpc2UsCiAgICAgIGFueSBDb250cmlidXRpb24gaW50
+ZW50aW9uYWxseSBzdWJtaXR0ZWQgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yawogICAgICBieSBZ
+b3UgdG8gdGhlIExpY2Vuc29yIHNoYWxsIGJlIHVuZGVyIHRoZSB0ZXJtcyBhbmQgY29uZGl0aW9u
+cyBvZgogICAgICB0aGlzIExpY2Vuc2UsIHdpdGhvdXQgYW55IGFkZGl0aW9uYWwgdGVybXMgb3Ig
+Y29uZGl0aW9ucy4KICAgICAgTm90d2l0aHN0YW5kaW5nIHRoZSBhYm92ZSwgbm90aGluZyBoZXJl
+aW4gc2hhbGwgc3VwZXJzZWRlIG9yIG1vZGlmeQogICAgICB0aGUgdGVybXMgb2YgYW55IHNlcGFy
+YXRlIGxpY2Vuc2UgYWdyZWVtZW50IHlvdSBtYXkgaGF2ZSBleGVjdXRlZAogICAgICB3aXRoIExp
+Y2Vuc29yIHJlZ2FyZGluZyBzdWNoIENvbnRyaWJ1dGlvbnMuCgogICA2LiBUcmFkZW1hcmtzLiBU
+aGlzIExpY2Vuc2UgZG9lcyBub3QgZ3JhbnQgcGVybWlzc2lvbiB0byB1c2UgdGhlIHRyYWRlCiAg
+ICAgIG5hbWVzLCB0cmFkZW1hcmtzLCBzZXJ2aWNlIG1hcmtzLCBvciBwcm9kdWN0IG5hbWVzIG9m
+IHRoZSBMaWNlbnNvciwKICAgICAgZXhjZXB0IGFzIHJlcXVpcmVkIGZvciByZWFzb25hYmxlIGFu
+ZCBjdXN0b21hcnkgdXNlIGluIGRlc2NyaWJpbmcgdGhlCiAgICAgIG9yaWdpbiBvZiB0aGUgV29y
+ayBhbmQgcmVwcm9kdWNpbmcgdGhlIGNvbnRlbnQgb2YgdGhlIE5PVElDRSBmaWxlLgoKICAgNy4g
+RGlzY2xhaW1lciBvZiBXYXJyYW50eS4gVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3
+IG9yCiAgICAgIGFncmVlZCB0byBpbiB3cml0aW5nLCBMaWNlbnNvciBwcm92aWRlcyB0aGUgV29y
+ayAoYW5kIGVhY2gKICAgICAgQ29udHJpYnV0b3IgcHJvdmlkZXMgaXRzIENvbnRyaWJ1dGlvbnMp
+IG9uIGFuICJBUyBJUyIgQkFTSVMsCiAgICAgIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJ
+T05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvcgogICAgICBpbXBsaWVkLCBpbmNsdWRp
+bmcsIHdpdGhvdXQgbGltaXRhdGlvbiwgYW55IHdhcnJhbnRpZXMgb3IgY29uZGl0aW9ucwogICAg
+ICBvZiBUSVRMRSwgTk9OLUlORlJJTkdFTUVOVCwgTUVSQ0hBTlRBQklMSVRZLCBvciBGSVRORVNT
+IEZPUiBBCiAgICAgIFBBUlRJQ1VMQVIgUFVSUE9TRS4gWW91IGFyZSBzb2xlbHkgcmVzcG9uc2li
+bGUgZm9yIGRldGVybWluaW5nIHRoZQogICAgICBhcHByb3ByaWF0ZW5lc3Mgb2YgdXNpbmcgb3Ig
+cmVkaXN0cmlidXRpbmcgdGhlIFdvcmsgYW5kIGFzc3VtZSBhbnkKICAgICAgcmlza3MgYXNzb2Np
+YXRlZCB3aXRoIFlvdXIgZXhlcmNpc2Ugb2YgcGVybWlzc2lvbnMgdW5kZXIgdGhpcyBMaWNlbnNl
+LgoKICAgOC4gTGltaXRhdGlvbiBvZiBMaWFiaWxpdHkuIEluIG5vIGV2ZW50IGFuZCB1bmRlciBu
+byBsZWdhbCB0aGVvcnksCiAgICAgIHdoZXRoZXIgaW4gdG9ydCAoaW5jbHVkaW5nIG5lZ2xpZ2Vu
+Y2UpLCBjb250cmFjdCwgb3Igb3RoZXJ3aXNlLAogICAgICB1bmxlc3MgcmVxdWlyZWQgYnkgYXBw
+bGljYWJsZSBsYXcgKHN1Y2ggYXMgZGVsaWJlcmF0ZSBhbmQgZ3Jvc3NseQogICAgICBuZWdsaWdl
+bnQgYWN0cykgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNoYWxsIGFueSBDb250cmlidXRvciBi
+ZQogICAgICBsaWFibGUgdG8gWW91IGZvciBkYW1hZ2VzLCBpbmNsdWRpbmcgYW55IGRpcmVjdCwg
+aW5kaXJlY3QsIHNwZWNpYWwsCiAgICAgIGluY2lkZW50YWwsIG9yIGNvbnNlcXVlbnRpYWwgZGFt
+YWdlcyBvZiBhbnkgY2hhcmFjdGVyIGFyaXNpbmcgYXMgYQogICAgICByZXN1bHQgb2YgdGhpcyBM
+aWNlbnNlIG9yIG91dCBvZiB0aGUgdXNlIG9yIGluYWJpbGl0eSB0byB1c2UgdGhlCiAgICAgIFdv
+cmsgKGluY2x1ZGluZyBidXQgbm90IGxpbWl0ZWQgdG8gZGFtYWdlcyBmb3IgbG9zcyBvZiBnb29k
+d2lsbCwKICAgICAgd29yayBzdG9wcGFnZSwgY29tcHV0ZXIgZmFpbHVyZSBvciBtYWxmdW5jdGlv
+biwgb3IgYW55IGFuZCBhbGwKICAgICAgb3RoZXIgY29tbWVyY2lhbCBkYW1hZ2VzIG9yIGxvc3Nl
+cyksIGV2ZW4gaWYgc3VjaCBDb250cmlidXRvcgogICAgICBoYXMgYmVlbiBhZHZpc2VkIG9mIHRo
+ZSBwb3NzaWJpbGl0eSBvZiBzdWNoIGRhbWFnZXMuCgogICA5LiBBY2NlcHRpbmcgV2FycmFudHkg
+b3IgQWRkaXRpb25hbCBMaWFiaWxpdHkuIFdoaWxlIHJlZGlzdHJpYnV0aW5nCiAgICAgIHRoZSBX
+b3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiwgWW91IG1heSBjaG9vc2UgdG8gb2ZmZXIs
+CiAgICAgIGFuZCBjaGFyZ2UgYSBmZWUgZm9yLCBhY2NlcHRhbmNlIG9mIHN1cHBvcnQsIHdhcnJh
+bnR5LCBpbmRlbW5pdHksCiAgICAgIG9yIG90aGVyIGxpYWJpbGl0eSBvYmxpZ2F0aW9ucyBhbmQv
+b3IgcmlnaHRzIGNvbnNpc3RlbnQgd2l0aCB0aGlzCiAgICAgIExpY2Vuc2UuIEhvd2V2ZXIsIGlu
+IGFjY2VwdGluZyBzdWNoIG9ibGlnYXRpb25zLCBZb3UgbWF5IGFjdCBvbmx5CiAgICAgIG9uIFlv
+dXIgb3duIGJlaGFsZiBhbmQgb24gWW91ciBzb2xlIHJlc3BvbnNpYmlsaXR5LCBub3Qgb24gYmVo
+YWxmCiAgICAgIG9mIGFueSBvdGhlciBDb250cmlidXRvciwgYW5kIG9ubHkgaWYgWW91IGFncmVl
+IHRvIGluZGVtbmlmeSwKICAgICAgZGVmZW5kLCBhbmQgaG9sZCBlYWNoIENvbnRyaWJ1dG9yIGhh
+cm1sZXNzIGZvciBhbnkgbGlhYmlsaXR5CiAgICAgIGluY3VycmVkIGJ5LCBvciBjbGFpbXMgYXNz
+ZXJ0ZWQgYWdhaW5zdCwgc3VjaCBDb250cmlidXRvciBieSByZWFzb24KICAgICAgb2YgeW91ciBh
+Y2NlcHRpbmcgYW55IHN1Y2ggd2FycmFudHkgb3IgYWRkaXRpb25hbCBsaWFiaWxpdHkuCgogICBF
+TkQgT0YgVEVSTVMgQU5EIENPTkRJVElPTlMKCiAgIEFQUEVORElYOiBIb3cgdG8gYXBwbHkgdGhl
+IEFwYWNoZSBMaWNlbnNlIHRvIHlvdXIgd29yay4KCiAgICAgIFRvIGFwcGx5IHRoZSBBcGFjaGUg
+TGljZW5zZSB0byB5b3VyIHdvcmssIGF0dGFjaCB0aGUgZm9sbG93aW5nCiAgICAgIGJvaWxlcnBs
+YXRlIG5vdGljZSwgd2l0aCB0aGUgZmllbGRzIGVuY2xvc2VkIGJ5IGJyYWNrZXRzICJbXSIKICAg
+ICAgcmVwbGFjZWQgd2l0aCB5b3VyIG93biBpZGVudGlmeWluZyBpbmZvcm1hdGlvbi4gKERvbid0
+IGluY2x1ZGUKICAgICAgdGhlIGJyYWNrZXRzISkgIFRoZSB0ZXh0IHNob3VsZCBiZSBlbmNsb3Nl
+ZCBpbiB0aGUgYXBwcm9wcmlhdGUKICAgICAgY29tbWVudCBzeW50YXggZm9yIHRoZSBmaWxlIGZv
+cm1hdC4gV2UgYWxzbyByZWNvbW1lbmQgdGhhdCBhCiAgICAgIGZpbGUgb3IgY2xhc3MgbmFtZSBh
+bmQgZGVzY3JpcHRpb24gb2YgcHVycG9zZSBiZSBpbmNsdWRlZCBvbiB0aGUKICAgICAgc2FtZSAi
+cHJpbnRlZCBwYWdlIiBhcyB0aGUgY29weXJpZ2h0IG5vdGljZSBmb3IgZWFzaWVyCiAgICAgIGlk
+ZW50aWZpY2F0aW9uIHdpdGhpbiB0aGlyZC1wYXJ0eSBhcmNoaXZlcy4KCiAgIENvcHlyaWdodCAo
+YykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLgoKICAgTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBM
+aWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlICJMaWNlbnNlIik7CiAgIHlvdSBtYXkgbm90IHVzZSB0
+aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS4KICAgWW91IG1h
+eSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0CgogICAgICAgaHR0cDovL3d3dy5hcGFj
+aGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wCgogICBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGlj
+YWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlCiAgIGRpc3RyaWJ1dGVk
+IHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuICJBUyBJUyIgQkFTSVMsCiAg
+IFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhw
+cmVzcyBvciBpbXBsaWVkLgogICBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5n
+dWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kCiAgIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBM
+aWNlbnNlLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383.base64
new file mode 100644
index 000000000..2f4e2364b
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383.base64
@@ -0,0 +1,21 @@
+ICAgIE1JVCBMaWNlbnNlCgogICAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24u
+CgogICAgUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFu
+eSBwZXJzb24gb2J0YWluaW5nIGEgY29weQogICAgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2Np
+YXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwKICAgIGlu
+IHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1p
+dGF0aW9uIHRoZSByaWdodHMKICAgIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlz
+aCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwKICAgIGNvcGllcyBvZiB0aGUg
+U29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcwog
+ICAgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9u
+czoKCiAgICBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5v
+dGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwKICAgIGNvcGllcyBvciBzdWJzdGFudGlhbCBw
+b3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgogICAgVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEICJB
+UyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1IKICAgIElNUExJ
+RUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hB
+TlRBQklMSVRZLAogICAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklO
+RlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFCiAgICBBVVRIT1JTIE9SIENPUFlSSUdI
+VCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSCiAgICBM
+SUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVS
+V0lTRSwgQVJJU0lORyBGUk9NLAogICAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUg
+U09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUKICAgIFNPRlRXQVJF
+Cg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b.base64
new file mode 100644
index 000000000..50436e625
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE1LTIwMTggVGhlIHdpbmFwaS1ycyBEZXZlbG9wZXJzCgpQZXJtaXNz
+aW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRh
+aW5pbmcgYSBjb3B5Cm9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlv
+biBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsCmluIHRoZSBTb2Z0d2FyZSB3aXRob3V0
+IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMKdG8g
+dXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNl
+LCBhbmQvb3Igc2VsbApjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNv
+bnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMKZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRv
+IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFu
+ZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbApjb3BpZXMg
+b3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNPRlRXQVJFIElT
+IFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1Mg
+T1IKSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBP
+RiBNRVJDSEFOVEFCSUxJVFksCkZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBO
+T05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRQpBVVRIT1JTIE9SIENPUFlSSUdI
+VCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSCkxJQUJJ
+TElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNF
+LCBBUklTSU5HIEZST00sCk9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJF
+IE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFClNPRlRXQVJFLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30.base64
new file mode 100644
index 000000000..95c577e82
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30.base64
@@ -0,0 +1,200 @@
+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFwYWNoZSBMaWNlbnNlCiAgICAgICAg
+ICAgICAgICAgICAgICAgICAgIFZlcnNpb24gMi4wLCBKYW51YXJ5IDIwMDQKICAgICAgICAgICAg
+ICAgICAgICAgICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLwoKICAgVEVSTVMgQU5E
+IENPTkRJVElPTlMgRk9SIFVTRSwgUkVQUk9EVUNUSU9OLCBBTkQgRElTVFJJQlVUSU9OCgogICAx
+LiBEZWZpbml0aW9ucy4KCiAgICAgICJMaWNlbnNlIiBzaGFsbCBtZWFuIHRoZSB0ZXJtcyBhbmQg
+Y29uZGl0aW9ucyBmb3IgdXNlLCByZXByb2R1Y3Rpb24sCiAgICAgIGFuZCBkaXN0cmlidXRpb24g
+YXMgZGVmaW5lZCBieSBTZWN0aW9ucyAxIHRocm91Z2ggOSBvZiB0aGlzIGRvY3VtZW50LgoKICAg
+ICAgIkxpY2Vuc29yIiBzaGFsbCBtZWFuIHRoZSBjb3B5cmlnaHQgb3duZXIgb3IgZW50aXR5IGF1
+dGhvcml6ZWQgYnkKICAgICAgdGhlIGNvcHlyaWdodCBvd25lciB0aGF0IGlzIGdyYW50aW5nIHRo
+ZSBMaWNlbnNlLgoKICAgICAgIkxlZ2FsIEVudGl0eSIgc2hhbGwgbWVhbiB0aGUgdW5pb24gb2Yg
+dGhlIGFjdGluZyBlbnRpdHkgYW5kIGFsbAogICAgICBvdGhlciBlbnRpdGllcyB0aGF0IGNvbnRy
+b2wsIGFyZSBjb250cm9sbGVkIGJ5LCBvciBhcmUgdW5kZXIgY29tbW9uCiAgICAgIGNvbnRyb2wg
+d2l0aCB0aGF0IGVudGl0eS4gRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGRlZmluaXRpb24sCiAg
+ICAgICJjb250cm9sIiBtZWFucyAoaSkgdGhlIHBvd2VyLCBkaXJlY3Qgb3IgaW5kaXJlY3QsIHRv
+IGNhdXNlIHRoZQogICAgICBkaXJlY3Rpb24gb3IgbWFuYWdlbWVudCBvZiBzdWNoIGVudGl0eSwg
+d2hldGhlciBieSBjb250cmFjdCBvcgogICAgICBvdGhlcndpc2UsIG9yIChpaSkgb3duZXJzaGlw
+IG9mIGZpZnR5IHBlcmNlbnQgKDUwJSkgb3IgbW9yZSBvZiB0aGUKICAgICAgb3V0c3RhbmRpbmcg
+c2hhcmVzLCBvciAoaWlpKSBiZW5lZmljaWFsIG93bmVyc2hpcCBvZiBzdWNoIGVudGl0eS4KCiAg
+ICAgICJZb3UiIChvciAiWW91ciIpIHNoYWxsIG1lYW4gYW4gaW5kaXZpZHVhbCBvciBMZWdhbCBF
+bnRpdHkKICAgICAgZXhlcmNpc2luZyBwZXJtaXNzaW9ucyBncmFudGVkIGJ5IHRoaXMgTGljZW5z
+ZS4KCiAgICAgICJTb3VyY2UiIGZvcm0gc2hhbGwgbWVhbiB0aGUgcHJlZmVycmVkIGZvcm0gZm9y
+IG1ha2luZyBtb2RpZmljYXRpb25zLAogICAgICBpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRv
+IHNvZnR3YXJlIHNvdXJjZSBjb2RlLCBkb2N1bWVudGF0aW9uCiAgICAgIHNvdXJjZSwgYW5kIGNv
+bmZpZ3VyYXRpb24gZmlsZXMuCgogICAgICAiT2JqZWN0IiBmb3JtIHNoYWxsIG1lYW4gYW55IGZv
+cm0gcmVzdWx0aW5nIGZyb20gbWVjaGFuaWNhbAogICAgICB0cmFuc2Zvcm1hdGlvbiBvciB0cmFu
+c2xhdGlvbiBvZiBhIFNvdXJjZSBmb3JtLCBpbmNsdWRpbmcgYnV0CiAgICAgIG5vdCBsaW1pdGVk
+IHRvIGNvbXBpbGVkIG9iamVjdCBjb2RlLCBnZW5lcmF0ZWQgZG9jdW1lbnRhdGlvbiwKICAgICAg
+YW5kIGNvbnZlcnNpb25zIHRvIG90aGVyIG1lZGlhIHR5cGVzLgoKICAgICAgIldvcmsiIHNoYWxs
+IG1lYW4gdGhlIHdvcmsgb2YgYXV0aG9yc2hpcCwgd2hldGhlciBpbiBTb3VyY2Ugb3IKICAgICAg
+T2JqZWN0IGZvcm0sIG1hZGUgYXZhaWxhYmxlIHVuZGVyIHRoZSBMaWNlbnNlLCBhcyBpbmRpY2F0
+ZWQgYnkgYQogICAgICBjb3B5cmlnaHQgbm90aWNlIHRoYXQgaXMgaW5jbHVkZWQgaW4gb3IgYXR0
+YWNoZWQgdG8gdGhlIHdvcmsKICAgICAgKGFuIGV4YW1wbGUgaXMgcHJvdmlkZWQgaW4gdGhlIEFw
+cGVuZGl4IGJlbG93KS4KCiAgICAgICJEZXJpdmF0aXZlIFdvcmtzIiBzaGFsbCBtZWFuIGFueSB3
+b3JrLCB3aGV0aGVyIGluIFNvdXJjZSBvciBPYmplY3QKICAgICAgZm9ybSwgdGhhdCBpcyBiYXNl
+ZCBvbiAob3IgZGVyaXZlZCBmcm9tKSB0aGUgV29yayBhbmQgZm9yIHdoaWNoIHRoZQogICAgICBl
+ZGl0b3JpYWwgcmV2aXNpb25zLCBhbm5vdGF0aW9ucywgZWxhYm9yYXRpb25zLCBvciBvdGhlciBt
+b2RpZmljYXRpb25zCiAgICAgIHJlcHJlc2VudCwgYXMgYSB3aG9sZSwgYW4gb3JpZ2luYWwgd29y
+ayBvZiBhdXRob3JzaGlwLiBGb3IgdGhlIHB1cnBvc2VzCiAgICAgIG9mIHRoaXMgTGljZW5zZSwg
+RGVyaXZhdGl2ZSBXb3JrcyBzaGFsbCBub3QgaW5jbHVkZSB3b3JrcyB0aGF0IHJlbWFpbgogICAg
+ICBzZXBhcmFibGUgZnJvbSwgb3IgbWVyZWx5IGxpbmsgKG9yIGJpbmQgYnkgbmFtZSkgdG8gdGhl
+IGludGVyZmFjZXMgb2YsCiAgICAgIHRoZSBXb3JrIGFuZCBEZXJpdmF0aXZlIFdvcmtzIHRoZXJl
+b2YuCgogICAgICAiQ29udHJpYnV0aW9uIiBzaGFsbCBtZWFuIGFueSB3b3JrIG9mIGF1dGhvcnNo
+aXAsIGluY2x1ZGluZwogICAgICB0aGUgb3JpZ2luYWwgdmVyc2lvbiBvZiB0aGUgV29yayBhbmQg
+YW55IG1vZGlmaWNhdGlvbnMgb3IgYWRkaXRpb25zCiAgICAgIHRvIHRoYXQgV29yayBvciBEZXJp
+dmF0aXZlIFdvcmtzIHRoZXJlb2YsIHRoYXQgaXMgaW50ZW50aW9uYWxseQogICAgICBzdWJtaXR0
+ZWQgdG8gTGljZW5zb3IgZm9yIGluY2x1c2lvbiBpbiB0aGUgV29yayBieSB0aGUgY29weXJpZ2h0
+IG93bmVyCiAgICAgIG9yIGJ5IGFuIGluZGl2aWR1YWwgb3IgTGVnYWwgRW50aXR5IGF1dGhvcml6
+ZWQgdG8gc3VibWl0IG9uIGJlaGFsZiBvZgogICAgICB0aGUgY29weXJpZ2h0IG93bmVyLiBGb3Ig
+dGhlIHB1cnBvc2VzIG9mIHRoaXMgZGVmaW5pdGlvbiwgInN1Ym1pdHRlZCIKICAgICAgbWVhbnMg
+YW55IGZvcm0gb2YgZWxlY3Ryb25pYywgdmVyYmFsLCBvciB3cml0dGVuIGNvbW11bmljYXRpb24g
+c2VudAogICAgICB0byB0aGUgTGljZW5zb3Igb3IgaXRzIHJlcHJlc2VudGF0aXZlcywgaW5jbHVk
+aW5nIGJ1dCBub3QgbGltaXRlZCB0bwogICAgICBjb21tdW5pY2F0aW9uIG9uIGVsZWN0cm9uaWMg
+bWFpbGluZyBsaXN0cywgc291cmNlIGNvZGUgY29udHJvbCBzeXN0ZW1zLAogICAgICBhbmQgaXNz
+dWUgdHJhY2tpbmcgc3lzdGVtcyB0aGF0IGFyZSBtYW5hZ2VkIGJ5LCBvciBvbiBiZWhhbGYgb2Ys
+IHRoZQogICAgICBMaWNlbnNvciBmb3IgdGhlIHB1cnBvc2Ugb2YgZGlzY3Vzc2luZyBhbmQgaW1w
+cm92aW5nIHRoZSBXb3JrLCBidXQKICAgICAgZXhjbHVkaW5nIGNvbW11bmljYXRpb24gdGhhdCBp
+cyBjb25zcGljdW91c2x5IG1hcmtlZCBvciBvdGhlcndpc2UKICAgICAgZGVzaWduYXRlZCBpbiB3
+cml0aW5nIGJ5IHRoZSBjb3B5cmlnaHQgb3duZXIgYXMgIk5vdCBhIENvbnRyaWJ1dGlvbi4iCgog
+ICAgICAiQ29udHJpYnV0b3IiIHNoYWxsIG1lYW4gTGljZW5zb3IgYW5kIGFueSBpbmRpdmlkdWFs
+IG9yIExlZ2FsIEVudGl0eQogICAgICBvbiBiZWhhbGYgb2Ygd2hvbSBhIENvbnRyaWJ1dGlvbiBo
+YXMgYmVlbiByZWNlaXZlZCBieSBMaWNlbnNvciBhbmQKICAgICAgc3Vic2VxdWVudGx5IGluY29y
+cG9yYXRlZCB3aXRoaW4gdGhlIFdvcmsuCgogICAyLiBHcmFudCBvZiBDb3B5cmlnaHQgTGljZW5z
+ZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YKICAgICAgdGhpcyBMaWNl
+bnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91IGEgcGVycGV0dWFsLAog
+ICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwgcm95YWx0eS1mcmVlLCBp
+cnJldm9jYWJsZQogICAgICBjb3B5cmlnaHQgbGljZW5zZSB0byByZXByb2R1Y2UsIHByZXBhcmUg
+RGVyaXZhdGl2ZSBXb3JrcyBvZiwKICAgICAgcHVibGljbHkgZGlzcGxheSwgcHVibGljbHkgcGVy
+Zm9ybSwgc3VibGljZW5zZSwgYW5kIGRpc3RyaWJ1dGUgdGhlCiAgICAgIFdvcmsgYW5kIHN1Y2gg
+RGVyaXZhdGl2ZSBXb3JrcyBpbiBTb3VyY2Ugb3IgT2JqZWN0IGZvcm0uCgogICAzLiBHcmFudCBv
+ZiBQYXRlbnQgTGljZW5zZS4gU3ViamVjdCB0byB0aGUgdGVybXMgYW5kIGNvbmRpdGlvbnMgb2YK
+ICAgICAgdGhpcyBMaWNlbnNlLCBlYWNoIENvbnRyaWJ1dG9yIGhlcmVieSBncmFudHMgdG8gWW91
+IGEgcGVycGV0dWFsLAogICAgICB3b3JsZHdpZGUsIG5vbi1leGNsdXNpdmUsIG5vLWNoYXJnZSwg
+cm95YWx0eS1mcmVlLCBpcnJldm9jYWJsZQogICAgICAoZXhjZXB0IGFzIHN0YXRlZCBpbiB0aGlz
+IHNlY3Rpb24pIHBhdGVudCBsaWNlbnNlIHRvIG1ha2UsIGhhdmUgbWFkZSwKICAgICAgdXNlLCBv
+ZmZlciB0byBzZWxsLCBzZWxsLCBpbXBvcnQsIGFuZCBvdGhlcndpc2UgdHJhbnNmZXIgdGhlIFdv
+cmssCiAgICAgIHdoZXJlIHN1Y2ggbGljZW5zZSBhcHBsaWVzIG9ubHkgdG8gdGhvc2UgcGF0ZW50
+IGNsYWltcyBsaWNlbnNhYmxlCiAgICAgIGJ5IHN1Y2ggQ29udHJpYnV0b3IgdGhhdCBhcmUgbmVj
+ZXNzYXJpbHkgaW5mcmluZ2VkIGJ5IHRoZWlyCiAgICAgIENvbnRyaWJ1dGlvbihzKSBhbG9uZSBv
+ciBieSBjb21iaW5hdGlvbiBvZiB0aGVpciBDb250cmlidXRpb24ocykKICAgICAgd2l0aCB0aGUg
+V29yayB0byB3aGljaCBzdWNoIENvbnRyaWJ1dGlvbihzKSB3YXMgc3VibWl0dGVkLiBJZiBZb3UK
+ICAgICAgaW5zdGl0dXRlIHBhdGVudCBsaXRpZ2F0aW9uIGFnYWluc3QgYW55IGVudGl0eSAoaW5j
+bHVkaW5nIGEKICAgICAgY3Jvc3MtY2xhaW0gb3IgY291bnRlcmNsYWltIGluIGEgbGF3c3VpdCkg
+YWxsZWdpbmcgdGhhdCB0aGUgV29yawogICAgICBvciBhIENvbnRyaWJ1dGlvbiBpbmNvcnBvcmF0
+ZWQgd2l0aGluIHRoZSBXb3JrIGNvbnN0aXR1dGVzIGRpcmVjdAogICAgICBvciBjb250cmlidXRv
+cnkgcGF0ZW50IGluZnJpbmdlbWVudCwgdGhlbiBhbnkgcGF0ZW50IGxpY2Vuc2VzCiAgICAgIGdy
+YW50ZWQgdG8gWW91IHVuZGVyIHRoaXMgTGljZW5zZSBmb3IgdGhhdCBXb3JrIHNoYWxsIHRlcm1p
+bmF0ZQogICAgICBhcyBvZiB0aGUgZGF0ZSBzdWNoIGxpdGlnYXRpb24gaXMgZmlsZWQuCgogICA0
+LiBSZWRpc3RyaWJ1dGlvbi4gWW91IG1heSByZXByb2R1Y2UgYW5kIGRpc3RyaWJ1dGUgY29waWVz
+IG9mIHRoZQogICAgICBXb3JrIG9yIERlcml2YXRpdmUgV29ya3MgdGhlcmVvZiBpbiBhbnkgbWVk
+aXVtLCB3aXRoIG9yIHdpdGhvdXQKICAgICAgbW9kaWZpY2F0aW9ucywgYW5kIGluIFNvdXJjZSBv
+ciBPYmplY3QgZm9ybSwgcHJvdmlkZWQgdGhhdCBZb3UKICAgICAgbWVldCB0aGUgZm9sbG93aW5n
+IGNvbmRpdGlvbnM6CgogICAgICAoYSkgWW91IG11c3QgZ2l2ZSBhbnkgb3RoZXIgcmVjaXBpZW50
+cyBvZiB0aGUgV29yayBvcgogICAgICAgICAgRGVyaXZhdGl2ZSBXb3JrcyBhIGNvcHkgb2YgdGhp
+cyBMaWNlbnNlOyBhbmQKCiAgICAgIChiKSBZb3UgbXVzdCBjYXVzZSBhbnkgbW9kaWZpZWQgZmls
+ZXMgdG8gY2FycnkgcHJvbWluZW50IG5vdGljZXMKICAgICAgICAgIHN0YXRpbmcgdGhhdCBZb3Ug
+Y2hhbmdlZCB0aGUgZmlsZXM7IGFuZAoKICAgICAgKGMpIFlvdSBtdXN0IHJldGFpbiwgaW4gdGhl
+IFNvdXJjZSBmb3JtIG9mIGFueSBEZXJpdmF0aXZlIFdvcmtzCiAgICAgICAgICB0aGF0IFlvdSBk
+aXN0cmlidXRlLCBhbGwgY29weXJpZ2h0LCBwYXRlbnQsIHRyYWRlbWFyaywgYW5kCiAgICAgICAg
+ICBhdHRyaWJ1dGlvbiBub3RpY2VzIGZyb20gdGhlIFNvdXJjZSBmb3JtIG9mIHRoZSBXb3JrLAog
+ICAgICAgICAgZXhjbHVkaW5nIHRob3NlIG5vdGljZXMgdGhhdCBkbyBub3QgcGVydGFpbiB0byBh
+bnkgcGFydCBvZgogICAgICAgICAgdGhlIERlcml2YXRpdmUgV29ya3M7IGFuZAoKICAgICAgKGQp
+IElmIHRoZSBXb3JrIGluY2x1ZGVzIGEgIk5PVElDRSIgdGV4dCBmaWxlIGFzIHBhcnQgb2YgaXRz
+CiAgICAgICAgICBkaXN0cmlidXRpb24sIHRoZW4gYW55IERlcml2YXRpdmUgV29ya3MgdGhhdCBZ
+b3UgZGlzdHJpYnV0ZSBtdXN0CiAgICAgICAgICBpbmNsdWRlIGEgcmVhZGFibGUgY29weSBvZiB0
+aGUgYXR0cmlidXRpb24gbm90aWNlcyBjb250YWluZWQKICAgICAgICAgIHdpdGhpbiBzdWNoIE5P
+VElDRSBmaWxlLCBleGNsdWRpbmcgdGhvc2Ugbm90aWNlcyB0aGF0IGRvIG5vdAogICAgICAgICAg
+cGVydGFpbiB0byBhbnkgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaW4gYXQgbGVhc3Qg
+b25lCiAgICAgICAgICBvZiB0aGUgZm9sbG93aW5nIHBsYWNlczogd2l0aGluIGEgTk9USUNFIHRl
+eHQgZmlsZSBkaXN0cmlidXRlZAogICAgICAgICAgYXMgcGFydCBvZiB0aGUgRGVyaXZhdGl2ZSBX
+b3Jrczsgd2l0aGluIHRoZSBTb3VyY2UgZm9ybSBvcgogICAgICAgICAgZG9jdW1lbnRhdGlvbiwg
+aWYgcHJvdmlkZWQgYWxvbmcgd2l0aCB0aGUgRGVyaXZhdGl2ZSBXb3Jrczsgb3IsCiAgICAgICAg
+ICB3aXRoaW4gYSBkaXNwbGF5IGdlbmVyYXRlZCBieSB0aGUgRGVyaXZhdGl2ZSBXb3JrcywgaWYg
+YW5kCiAgICAgICAgICB3aGVyZXZlciBzdWNoIHRoaXJkLXBhcnR5IG5vdGljZXMgbm9ybWFsbHkg
+YXBwZWFyLiBUaGUgY29udGVudHMKICAgICAgICAgIG9mIHRoZSBOT1RJQ0UgZmlsZSBhcmUgZm9y
+IGluZm9ybWF0aW9uYWwgcHVycG9zZXMgb25seSBhbmQKICAgICAgICAgIGRvIG5vdCBtb2RpZnkg
+dGhlIExpY2Vuc2UuIFlvdSBtYXkgYWRkIFlvdXIgb3duIGF0dHJpYnV0aW9uCiAgICAgICAgICBu
+b3RpY2VzIHdpdGhpbiBEZXJpdmF0aXZlIFdvcmtzIHRoYXQgWW91IGRpc3RyaWJ1dGUsIGFsb25n
+c2lkZQogICAgICAgICAgb3IgYXMgYW4gYWRkZW5kdW0gdG8gdGhlIE5PVElDRSB0ZXh0IGZyb20g
+dGhlIFdvcmssIHByb3ZpZGVkCiAgICAgICAgICB0aGF0IHN1Y2ggYWRkaXRpb25hbCBhdHRyaWJ1
+dGlvbiBub3RpY2VzIGNhbm5vdCBiZSBjb25zdHJ1ZWQKICAgICAgICAgIGFzIG1vZGlmeWluZyB0
+aGUgTGljZW5zZS4KCiAgICAgIFlvdSBtYXkgYWRkIFlvdXIgb3duIGNvcHlyaWdodCBzdGF0ZW1l
+bnQgdG8gWW91ciBtb2RpZmljYXRpb25zIGFuZAogICAgICBtYXkgcHJvdmlkZSBhZGRpdGlvbmFs
+IG9yIGRpZmZlcmVudCBsaWNlbnNlIHRlcm1zIGFuZCBjb25kaXRpb25zCiAgICAgIGZvciB1c2Us
+IHJlcHJvZHVjdGlvbiwgb3IgZGlzdHJpYnV0aW9uIG9mIFlvdXIgbW9kaWZpY2F0aW9ucywgb3IK
+ICAgICAgZm9yIGFueSBzdWNoIERlcml2YXRpdmUgV29ya3MgYXMgYSB3aG9sZSwgcHJvdmlkZWQg
+WW91ciB1c2UsCiAgICAgIHJlcHJvZHVjdGlvbiwgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0aGUgV29y
+ayBvdGhlcndpc2UgY29tcGxpZXMgd2l0aAogICAgICB0aGUgY29uZGl0aW9ucyBzdGF0ZWQgaW4g
+dGhpcyBMaWNlbnNlLgoKICAgNS4gU3VibWlzc2lvbiBvZiBDb250cmlidXRpb25zLiBVbmxlc3Mg
+WW91IGV4cGxpY2l0bHkgc3RhdGUgb3RoZXJ3aXNlLAogICAgICBhbnkgQ29udHJpYnV0aW9uIGlu
+dGVudGlvbmFsbHkgc3VibWl0dGVkIGZvciBpbmNsdXNpb24gaW4gdGhlIFdvcmsKICAgICAgYnkg
+WW91IHRvIHRoZSBMaWNlbnNvciBzaGFsbCBiZSB1bmRlciB0aGUgdGVybXMgYW5kIGNvbmRpdGlv
+bnMgb2YKICAgICAgdGhpcyBMaWNlbnNlLCB3aXRob3V0IGFueSBhZGRpdGlvbmFsIHRlcm1zIG9y
+IGNvbmRpdGlvbnMuCiAgICAgIE5vdHdpdGhzdGFuZGluZyB0aGUgYWJvdmUsIG5vdGhpbmcgaGVy
+ZWluIHNoYWxsIHN1cGVyc2VkZSBvciBtb2RpZnkKICAgICAgdGhlIHRlcm1zIG9mIGFueSBzZXBh
+cmF0ZSBsaWNlbnNlIGFncmVlbWVudCB5b3UgbWF5IGhhdmUgZXhlY3V0ZWQKICAgICAgd2l0aCBM
+aWNlbnNvciByZWdhcmRpbmcgc3VjaCBDb250cmlidXRpb25zLgoKICAgNi4gVHJhZGVtYXJrcy4g
+VGhpcyBMaWNlbnNlIGRvZXMgbm90IGdyYW50IHBlcm1pc3Npb24gdG8gdXNlIHRoZSB0cmFkZQog
+ICAgICBuYW1lcywgdHJhZGVtYXJrcywgc2VydmljZSBtYXJrcywgb3IgcHJvZHVjdCBuYW1lcyBv
+ZiB0aGUgTGljZW5zb3IsCiAgICAgIGV4Y2VwdCBhcyByZXF1aXJlZCBmb3IgcmVhc29uYWJsZSBh
+bmQgY3VzdG9tYXJ5IHVzZSBpbiBkZXNjcmliaW5nIHRoZQogICAgICBvcmlnaW4gb2YgdGhlIFdv
+cmsgYW5kIHJlcHJvZHVjaW5nIHRoZSBjb250ZW50IG9mIHRoZSBOT1RJQ0UgZmlsZS4KCiAgIDcu
+IERpc2NsYWltZXIgb2YgV2FycmFudHkuIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxh
+dyBvcgogICAgICBhZ3JlZWQgdG8gaW4gd3JpdGluZywgTGljZW5zb3IgcHJvdmlkZXMgdGhlIFdv
+cmsgKGFuZCBlYWNoCiAgICAgIENvbnRyaWJ1dG9yIHByb3ZpZGVzIGl0cyBDb250cmlidXRpb25z
+KSBvbiBhbiAiQVMgSVMiIEJBU0lTLAogICAgICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElU
+SU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IKICAgICAgaW1wbGllZCwgaW5jbHVk
+aW5nLCB3aXRob3V0IGxpbWl0YXRpb24sIGFueSB3YXJyYW50aWVzIG9yIGNvbmRpdGlvbnMKICAg
+ICAgb2YgVElUTEUsIE5PTi1JTkZSSU5HRU1FTlQsIE1FUkNIQU5UQUJJTElUWSwgb3IgRklUTkVT
+UyBGT1IgQQogICAgICBQQVJUSUNVTEFSIFBVUlBPU0UuIFlvdSBhcmUgc29sZWx5IHJlc3BvbnNp
+YmxlIGZvciBkZXRlcm1pbmluZyB0aGUKICAgICAgYXBwcm9wcmlhdGVuZXNzIG9mIHVzaW5nIG9y
+IHJlZGlzdHJpYnV0aW5nIHRoZSBXb3JrIGFuZCBhc3N1bWUgYW55CiAgICAgIHJpc2tzIGFzc29j
+aWF0ZWQgd2l0aCBZb3VyIGV4ZXJjaXNlIG9mIHBlcm1pc3Npb25zIHVuZGVyIHRoaXMgTGljZW5z
+ZS4KCiAgIDguIExpbWl0YXRpb24gb2YgTGlhYmlsaXR5LiBJbiBubyBldmVudCBhbmQgdW5kZXIg
+bm8gbGVnYWwgdGhlb3J5LAogICAgICB3aGV0aGVyIGluIHRvcnQgKGluY2x1ZGluZyBuZWdsaWdl
+bmNlKSwgY29udHJhY3QsIG9yIG90aGVyd2lzZSwKICAgICAgdW5sZXNzIHJlcXVpcmVkIGJ5IGFw
+cGxpY2FibGUgbGF3IChzdWNoIGFzIGRlbGliZXJhdGUgYW5kIGdyb3NzbHkKICAgICAgbmVnbGln
+ZW50IGFjdHMpIG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzaGFsbCBhbnkgQ29udHJpYnV0b3Ig
+YmUKICAgICAgbGlhYmxlIHRvIFlvdSBmb3IgZGFtYWdlcywgaW5jbHVkaW5nIGFueSBkaXJlY3Qs
+IGluZGlyZWN0LCBzcGVjaWFsLAogICAgICBpbmNpZGVudGFsLCBvciBjb25zZXF1ZW50aWFsIGRh
+bWFnZXMgb2YgYW55IGNoYXJhY3RlciBhcmlzaW5nIGFzIGEKICAgICAgcmVzdWx0IG9mIHRoaXMg
+TGljZW5zZSBvciBvdXQgb2YgdGhlIHVzZSBvciBpbmFiaWxpdHkgdG8gdXNlIHRoZQogICAgICBX
+b3JrIChpbmNsdWRpbmcgYnV0IG5vdCBsaW1pdGVkIHRvIGRhbWFnZXMgZm9yIGxvc3Mgb2YgZ29v
+ZHdpbGwsCiAgICAgIHdvcmsgc3RvcHBhZ2UsIGNvbXB1dGVyIGZhaWx1cmUgb3IgbWFsZnVuY3Rp
+b24sIG9yIGFueSBhbmQgYWxsCiAgICAgIG90aGVyIGNvbW1lcmNpYWwgZGFtYWdlcyBvciBsb3Nz
+ZXMpLCBldmVuIGlmIHN1Y2ggQ29udHJpYnV0b3IKICAgICAgaGFzIGJlZW4gYWR2aXNlZCBvZiB0
+aGUgcG9zc2liaWxpdHkgb2Ygc3VjaCBkYW1hZ2VzLgoKICAgOS4gQWNjZXB0aW5nIFdhcnJhbnR5
+IG9yIEFkZGl0aW9uYWwgTGlhYmlsaXR5LiBXaGlsZSByZWRpc3RyaWJ1dGluZwogICAgICB0aGUg
+V29yayBvciBEZXJpdmF0aXZlIFdvcmtzIHRoZXJlb2YsIFlvdSBtYXkgY2hvb3NlIHRvIG9mZmVy
+LAogICAgICBhbmQgY2hhcmdlIGEgZmVlIGZvciwgYWNjZXB0YW5jZSBvZiBzdXBwb3J0LCB3YXJy
+YW50eSwgaW5kZW1uaXR5LAogICAgICBvciBvdGhlciBsaWFiaWxpdHkgb2JsaWdhdGlvbnMgYW5k
+L29yIHJpZ2h0cyBjb25zaXN0ZW50IHdpdGggdGhpcwogICAgICBMaWNlbnNlLiBIb3dldmVyLCBp
+biBhY2NlcHRpbmcgc3VjaCBvYmxpZ2F0aW9ucywgWW91IG1heSBhY3Qgb25seQogICAgICBvbiBZ
+b3VyIG93biBiZWhhbGYgYW5kIG9uIFlvdXIgc29sZSByZXNwb25zaWJpbGl0eSwgbm90IG9uIGJl
+aGFsZgogICAgICBvZiBhbnkgb3RoZXIgQ29udHJpYnV0b3IsIGFuZCBvbmx5IGlmIFlvdSBhZ3Jl
+ZSB0byBpbmRlbW5pZnksCiAgICAgIGRlZmVuZCwgYW5kIGhvbGQgZWFjaCBDb250cmlidXRvciBo
+YXJtbGVzcyBmb3IgYW55IGxpYWJpbGl0eQogICAgICBpbmN1cnJlZCBieSwgb3IgY2xhaW1zIGFz
+c2VydGVkIGFnYWluc3QsIHN1Y2ggQ29udHJpYnV0b3IgYnkgcmVhc29uCiAgICAgIG9mIHlvdXIg
+YWNjZXB0aW5nIGFueSBzdWNoIHdhcnJhbnR5IG9yIGFkZGl0aW9uYWwgbGlhYmlsaXR5LgoKICAg
+RU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05TCgogICBBUFBFTkRJWDogSG93IHRvIGFwcGx5IHRo
+ZSBBcGFjaGUgTGljZW5zZSB0byB5b3VyIHdvcmsuCgogICAgICBUbyBhcHBseSB0aGUgQXBhY2hl
+IExpY2Vuc2UgdG8geW91ciB3b3JrLCBhdHRhY2ggdGhlIGZvbGxvd2luZwogICAgICBib2lsZXJw
+bGF0ZSBub3RpY2UsIHdpdGggdGhlIGZpZWxkcyBlbmNsb3NlZCBieSBicmFja2V0cyAiW10iCiAg
+ICAgIHJlcGxhY2VkIHdpdGggeW91ciBvd24gaWRlbnRpZnlpbmcgaW5mb3JtYXRpb24uIChEb24n
+dCBpbmNsdWRlCiAgICAgIHRoZSBicmFja2V0cyEpICBUaGUgdGV4dCBzaG91bGQgYmUgZW5jbG9z
+ZWQgaW4gdGhlIGFwcHJvcHJpYXRlCiAgICAgIGNvbW1lbnQgc3ludGF4IGZvciB0aGUgZmlsZSBm
+b3JtYXQuIFdlIGFsc28gcmVjb21tZW5kIHRoYXQgYQogICAgICBmaWxlIG9yIGNsYXNzIG5hbWUg
+YW5kIGRlc2NyaXB0aW9uIG9mIHB1cnBvc2UgYmUgaW5jbHVkZWQgb24gdGhlCiAgICAgIHNhbWUg
+InByaW50ZWQgcGFnZSIgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZm9yIGVhc2llcgogICAgICBp
+ZGVudGlmaWNhdGlvbiB3aXRoaW4gdGhpcmQtcGFydHkgYXJjaGl2ZXMuCgogICBDb3B5cmlnaHQg
+W3l5eXldIFtuYW1lIG9mIGNvcHlyaWdodCBvd25lcl0KCiAgIExpY2Vuc2VkIHVuZGVyIHRoZSBB
+cGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOwogICB5b3UgbWF5IG5v
+dCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuCiAg
+IFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdAoKICAgICAgIGh0dHA6Ly93
+d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMAoKICAgVW5sZXNzIHJlcXVpcmVkIGJ5
+IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQogICBkaXN0
+cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiAiQVMgSVMiIEJB
+U0lTLAogICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0
+aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC4KICAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lm
+aWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZAogICBsaW1pdGF0aW9ucyB1bmRl
+ciB0aGUgTGljZW5zZS4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64
new file mode 100644
index 000000000..bfc309f00
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IChjKSAyMDE4LTIwMTkgVGhlIFJ1c3RDcnlwdG8gUHJvamVjdCBEZXZlbG9wZXJz
+CgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55CnBl
+cnNvbiBvYnRhaW5pbmcgYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQKZG9j
+dW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsIGluIHRoZQpTb2Z0d2Fy
+ZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dApsaW1pdGF0aW9uIHRoZSBy
+aWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLApwdWJsaXNoLCBkaXN0cmlidXRlLCBz
+dWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YKdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVy
+bWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUKaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBz
+dWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcKY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmlnaHQg
+bm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlCnNoYWxsIGJlIGluY2x1ZGVkIGluIGFs
+bCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMKb2YgdGhlIFNvZnR3YXJlLgoKVEhFIFNP
+RlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YKQU5ZIEtJTkQs
+IEVYUFJFU1MgT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRApUTyBUSEUgV0FS
+UkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEKUEFSVElDVUxBUiBQVVJQ
+T1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UClNIQUxMIFRIRSBBVVRIT1JTIE9S
+IENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZCkNMQUlNLCBEQU1BR0VTIE9SIE9U
+SEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04KT0YgQ09OVFJBQ1QsIFRPUlQgT1Ig
+T1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUgpJTiBDT05ORUNUSU9OIFdJVEggVEhF
+IFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIKREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLgo=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64
new file mode 100644
index 000000000..5eb6ec8ad
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a.base64
@@ -0,0 +1 @@
+TUlUIE9SIEFwYWNoZS0yLjA=
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/ec353d4fecf7963b4c054384557e5dbc3c7a717997eb4a3815b315721a6aa75a.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/ec353d4fecf7963b4c054384557e5dbc3c7a717997eb4a3815b315721a6aa75a.base64
new file mode 100644
index 000000000..ef354903f
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/ec353d4fecf7963b4c054384557e5dbc3c7a717997eb4a3815b315721a6aa75a.base64
@@ -0,0 +1,19 @@
+Q29weXJpZ2h0IDIwMTggUGFyaXR5IFRlY2hub2xvZ2llcyAoVUspIEx0ZC4KClBlcm1pc3Npb24g
+aXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmlu
+ZyBhIGNvcHkgb2YKdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZp
+bGVzICh0aGUgIlNvZnR3YXJlIiksIHRvIGRlYWwgaW4KdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVz
+dHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0bwp1c2Us
+IGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFu
+ZC9vciBzZWxsIGNvcGllcyBvZgp0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0
+byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sCnN1YmplY3QgdG8gdGhl
+IGZvbGxvd2luZyBjb25kaXRpb25zOgoKVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRo
+aXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsCmNvcGllcyBvciBz
+dWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuCgpUSEUgU09GVFdBUkUgSVMgUFJP
+VklERUQgIkFTIElTIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUgpJ
+TVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1F
+UkNIQU5UQUJJTElUWSwgRklUTkVTUwpGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklO
+RlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMKT1IgQ09QWVJJR0hUIEhP
+TERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZ
+LApXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFS
+SVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOCkNPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1Ig
+VEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuCg==
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64
new file mode 100644
index 000000000..817bcfcf1
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1.base64
@@ -0,0 +1,35 @@
+VU5JQ09ERSBMSUNFTlNFIFYzCgpDT1BZUklHSFQgQU5EIFBFUk1JU1NJT04gTk9USUNFCgpDb3B5
+cmlnaHQgwqkgMTk5MS0yMDIzIFVuaWNvZGUsIEluYy4KCk5PVElDRSBUTyBVU0VSOiBDYXJlZnVs
+bHkgcmVhZCB0aGUgZm9sbG93aW5nIGxlZ2FsIGFncmVlbWVudC4gQlkKRE9XTkxPQURJTkcsIElO
+U1RBTExJTkcsIENPUFlJTkcgT1IgT1RIRVJXSVNFIFVTSU5HIERBVEEgRklMRVMsIEFORC9PUgpT
+T0ZUV0FSRSwgWU9VIFVORVFVSVZPQ0FMTFkgQUNDRVBULCBBTkQgQUdSRUUgVE8gQkUgQk9VTkQg
+QlksIEFMTCBPRiBUSEUKVEVSTVMgQU5EIENPTkRJVElPTlMgT0YgVEhJUyBBR1JFRU1FTlQuIElG
+IFlPVSBETyBOT1QgQUdSRUUsIERPIE5PVApET1dOTE9BRCwgSU5TVEFMTCwgQ09QWSwgRElTVFJJ
+QlVURSBPUiBVU0UgVEhFIERBVEEgRklMRVMgT1IgU09GVFdBUkUuCgpQZXJtaXNzaW9uIGlzIGhl
+cmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYQpj
+b3B5IG9mIGRhdGEgZmlsZXMgYW5kIGFueSBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gKHRoZSAi
+RGF0YSBGaWxlcyIpIG9yCnNvZnR3YXJlIGFuZCBhbnkgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9u
+ICh0aGUgIlNvZnR3YXJlIikgdG8gZGVhbCBpbiB0aGUKRGF0YSBGaWxlcyBvciBTb2Z0d2FyZSB3
+aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uCnRoZSByaWdo
+dHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBhbmQv
+b3Igc2VsbApjb3BpZXMgb2YgdGhlIERhdGEgRmlsZXMgb3IgU29mdHdhcmUsIGFuZCB0byBwZXJt
+aXQgcGVyc29ucyB0byB3aG9tIHRoZQpEYXRhIEZpbGVzIG9yIFNvZnR3YXJlIGFyZSBmdXJuaXNo
+ZWQgdG8gZG8gc28sIHByb3ZpZGVkIHRoYXQgZWl0aGVyIChhKQp0aGlzIGNvcHlyaWdodCBhbmQg
+cGVybWlzc2lvbiBub3RpY2UgYXBwZWFyIHdpdGggYWxsIGNvcGllcyBvZiB0aGUgRGF0YQpGaWxl
+cyBvciBTb2Z0d2FyZSwgb3IgKGIpIHRoaXMgY29weXJpZ2h0IGFuZCBwZXJtaXNzaW9uIG5vdGlj
+ZSBhcHBlYXIgaW4KYXNzb2NpYXRlZCBEb2N1bWVudGF0aW9uLgoKVEhFIERBVEEgRklMRVMgQU5E
+IFNPRlRXQVJFIEFSRSBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWQpL
+SU5ELCBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhF
+IFdBUlJBTlRJRVMgT0YKTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIg
+UFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5UIE9GClRISVJEIFBBUlRZIFJJR0hUUy4KCklOIE5P
+IEVWRU5UIFNIQUxMIFRIRSBDT1BZUklHSFQgSE9MREVSIE9SIEhPTERFUlMgSU5DTFVERUQgSU4g
+VEhJUyBOT1RJQ0UKQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIE9SIEFOWSBTUEVDSUFMIElORElS
+RUNUIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUywKT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUiBS
+RVNVTFRJTkcgRlJPTSBMT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLApXSEVUSEVSIElOIEFO
+IEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5DRSBPUiBPVEhFUiBUT1JUSU9VUyBBQ1RJT04s
+CkFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SIFBFUkZPUk1B
+TkNFIE9GIFRIRSBEQVRBCkZJTEVTIE9SIFNPRlRXQVJFLgoKRXhjZXB0IGFzIGNvbnRhaW5lZCBp
+biB0aGlzIG5vdGljZSwgdGhlIG5hbWUgb2YgYSBjb3B5cmlnaHQgaG9sZGVyIHNoYWxsCm5vdCBi
+ZSB1c2VkIGluIGFkdmVydGlzaW5nIG9yIG90aGVyd2lzZSB0byBwcm9tb3RlIHRoZSBzYWxlLCB1
+c2Ugb3Igb3RoZXIKZGVhbGluZ3MgaW4gdGhlc2UgRGF0YSBGaWxlcyBvciBTb2Z0d2FyZSB3aXRo
+b3V0IHByaW9yIHdyaXR0ZW4KYXV0aG9yaXphdGlvbiBvZiB0aGUgY29weXJpZ2h0IGhvbGRlci4K
diff --git a/src/sdks/ts/node-addon/dependency-license-blobs/f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505.base64 b/src/sdks/ts/node-addon/dependency-license-blobs/f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505.base64
new file mode 100644
index 000000000..f598c992e
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-license-blobs/f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505.base64
@@ -0,0 +1,318 @@
+ICAgICAgICAgICAgICAgICAgICBHTlUgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAgICAgICAg
+ICAgICAgICAgICAgIFZlcnNpb24gMiwgSnVuZSAxOTkxCgogQ29weXJpZ2h0IChDKSAxOTg5LCAx
+OTkxIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiwKIDUxIEZyYW5rbGluIFN0cmVldCwg
+RmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgMDIxMTAtMTMwMSBVU0EKIEV2ZXJ5b25lIGlzIHBlcm1p
+dHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNvcGllcwogb2YgdGhpcyBsaWNl
+bnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFsbG93ZWQuCgogICAgICAgICAg
+ICAgICAgICAgICAgICAgICAgUHJlYW1ibGUKCiAgVGhlIGxpY2Vuc2VzIGZvciBtb3N0IHNvZnR3
+YXJlIGFyZSBkZXNpZ25lZCB0byB0YWtlIGF3YXkgeW91cgpmcmVlZG9tIHRvIHNoYXJlIGFuZCBj
+aGFuZ2UgaXQuICBCeSBjb250cmFzdCwgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYwpMaWNlbnNlIGlz
+IGludGVuZGVkIHRvIGd1YXJhbnRlZSB5b3VyIGZyZWVkb20gdG8gc2hhcmUgYW5kIGNoYW5nZSBm
+cmVlCnNvZnR3YXJlLS10byBtYWtlIHN1cmUgdGhlIHNvZnR3YXJlIGlzIGZyZWUgZm9yIGFsbCBp
+dHMgdXNlcnMuICBUaGlzCkdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXBwbGllcyB0byBtb3N0IG9m
+IHRoZSBGcmVlIFNvZnR3YXJlCkZvdW5kYXRpb24ncyBzb2Z0d2FyZSBhbmQgdG8gYW55IG90aGVy
+IHByb2dyYW0gd2hvc2UgYXV0aG9ycyBjb21taXQgdG8KdXNpbmcgaXQuICAoU29tZSBvdGhlciBG
+cmVlIFNvZnR3YXJlIEZvdW5kYXRpb24gc29mdHdhcmUgaXMgY292ZXJlZCBieQp0aGUgR05VIExl
+c3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGluc3RlYWQuKSAgWW91IGNhbiBhcHBseSBpdCB0
+bwp5b3VyIHByb2dyYW1zLCB0b28uCgogIFdoZW4gd2Ugc3BlYWsgb2YgZnJlZSBzb2Z0d2FyZSwg
+d2UgYXJlIHJlZmVycmluZyB0byBmcmVlZG9tLCBub3QKcHJpY2UuICBPdXIgR2VuZXJhbCBQdWJs
+aWMgTGljZW5zZXMgYXJlIGRlc2lnbmVkIHRvIG1ha2Ugc3VyZSB0aGF0IHlvdQpoYXZlIHRoZSBm
+cmVlZG9tIHRvIGRpc3RyaWJ1dGUgY29waWVzIG9mIGZyZWUgc29mdHdhcmUgKGFuZCBjaGFyZ2Ug
+Zm9yCnRoaXMgc2VydmljZSBpZiB5b3Ugd2lzaCksIHRoYXQgeW91IHJlY2VpdmUgc291cmNlIGNv
+ZGUgb3IgY2FuIGdldCBpdAppZiB5b3Ugd2FudCBpdCwgdGhhdCB5b3UgY2FuIGNoYW5nZSB0aGUg
+c29mdHdhcmUgb3IgdXNlIHBpZWNlcyBvZiBpdAppbiBuZXcgZnJlZSBwcm9ncmFtczsgYW5kIHRo
+YXQgeW91IGtub3cgeW91IGNhbiBkbyB0aGVzZSB0aGluZ3MuCgogIFRvIHByb3RlY3QgeW91ciBy
+aWdodHMsIHdlIG5lZWQgdG8gbWFrZSByZXN0cmljdGlvbnMgdGhhdCBmb3JiaWQKYW55b25lIHRv
+IGRlbnkgeW91IHRoZXNlIHJpZ2h0cyBvciB0byBhc2sgeW91IHRvIHN1cnJlbmRlciB0aGUgcmln
+aHRzLgpUaGVzZSByZXN0cmljdGlvbnMgdHJhbnNsYXRlIHRvIGNlcnRhaW4gcmVzcG9uc2liaWxp
+dGllcyBmb3IgeW91IGlmIHlvdQpkaXN0cmlidXRlIGNvcGllcyBvZiB0aGUgc29mdHdhcmUsIG9y
+IGlmIHlvdSBtb2RpZnkgaXQuCgogIEZvciBleGFtcGxlLCBpZiB5b3UgZGlzdHJpYnV0ZSBjb3Bp
+ZXMgb2Ygc3VjaCBhIHByb2dyYW0sIHdoZXRoZXIKZ3JhdGlzIG9yIGZvciBhIGZlZSwgeW91IG11
+c3QgZ2l2ZSB0aGUgcmVjaXBpZW50cyBhbGwgdGhlIHJpZ2h0cyB0aGF0CnlvdSBoYXZlLiAgWW91
+IG11c3QgbWFrZSBzdXJlIHRoYXQgdGhleSwgdG9vLCByZWNlaXZlIG9yIGNhbiBnZXQgdGhlCnNv
+dXJjZSBjb2RlLiAgQW5kIHlvdSBtdXN0IHNob3cgdGhlbSB0aGVzZSB0ZXJtcyBzbyB0aGV5IGtu
+b3cgdGhlaXIKcmlnaHRzLgoKICBXZSBwcm90ZWN0IHlvdXIgcmlnaHRzIHdpdGggdHdvIHN0ZXBz
+OiAoMSkgY29weXJpZ2h0IHRoZSBzb2Z0d2FyZSwgYW5kCigyKSBvZmZlciB5b3UgdGhpcyBsaWNl
+bnNlIHdoaWNoIGdpdmVzIHlvdSBsZWdhbCBwZXJtaXNzaW9uIHRvIGNvcHksCmRpc3RyaWJ1dGUg
+YW5kL29yIG1vZGlmeSB0aGUgc29mdHdhcmUuCgogIEFsc28sIGZvciBlYWNoIGF1dGhvcidzIHBy
+b3RlY3Rpb24gYW5kIG91cnMsIHdlIHdhbnQgdG8gbWFrZSBjZXJ0YWluCnRoYXQgZXZlcnlvbmUg
+dW5kZXJzdGFuZHMgdGhhdCB0aGVyZSBpcyBubyB3YXJyYW50eSBmb3IgdGhpcyBmcmVlCnNvZnR3
+YXJlLiAgSWYgdGhlIHNvZnR3YXJlIGlzIG1vZGlmaWVkIGJ5IHNvbWVvbmUgZWxzZSBhbmQgcGFz
+c2VkIG9uLCB3ZQp3YW50IGl0cyByZWNpcGllbnRzIHRvIGtub3cgdGhhdCB3aGF0IHRoZXkgaGF2
+ZSBpcyBub3QgdGhlIG9yaWdpbmFsLCBzbwp0aGF0IGFueSBwcm9ibGVtcyBpbnRyb2R1Y2VkIGJ5
+IG90aGVycyB3aWxsIG5vdCByZWZsZWN0IG9uIHRoZSBvcmlnaW5hbAphdXRob3JzJyByZXB1dGF0
+aW9ucy4KCiAgRmluYWxseSwgYW55IGZyZWUgcHJvZ3JhbSBpcyB0aHJlYXRlbmVkIGNvbnN0YW50
+bHkgYnkgc29mdHdhcmUKcGF0ZW50cy4gIFdlIHdpc2ggdG8gYXZvaWQgdGhlIGRhbmdlciB0aGF0
+IHJlZGlzdHJpYnV0b3JzIG9mIGEgZnJlZQpwcm9ncmFtIHdpbGwgaW5kaXZpZHVhbGx5IG9idGFp
+biBwYXRlbnQgbGljZW5zZXMsIGluIGVmZmVjdCBtYWtpbmcgdGhlCnByb2dyYW0gcHJvcHJpZXRh
+cnkuICBUbyBwcmV2ZW50IHRoaXMsIHdlIGhhdmUgbWFkZSBpdCBjbGVhciB0aGF0IGFueQpwYXRl
+bnQgbXVzdCBiZSBsaWNlbnNlZCBmb3IgZXZlcnlvbmUncyBmcmVlIHVzZSBvciBub3QgbGljZW5z
+ZWQgYXQgYWxsLgoKICBUaGUgcHJlY2lzZSB0ZXJtcyBhbmQgY29uZGl0aW9ucyBmb3IgY29weWlu
+ZywgZGlzdHJpYnV0aW9uIGFuZAptb2RpZmljYXRpb24gZm9sbG93LgoKICAgICAgICAgICAgICAg
+ICAgICBHTlUgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICBURVJNUyBBTkQgQ09ORElUSU9OUyBG
+T1IgQ09QWUlORywgRElTVFJJQlVUSU9OIEFORCBNT0RJRklDQVRJT04KCiAgMC4gVGhpcyBMaWNl
+bnNlIGFwcGxpZXMgdG8gYW55IHByb2dyYW0gb3Igb3RoZXIgd29yayB3aGljaCBjb250YWlucwph
+IG5vdGljZSBwbGFjZWQgYnkgdGhlIGNvcHlyaWdodCBob2xkZXIgc2F5aW5nIGl0IG1heSBiZSBk
+aXN0cmlidXRlZAp1bmRlciB0aGUgdGVybXMgb2YgdGhpcyBHZW5lcmFsIFB1YmxpYyBMaWNlbnNl
+LiAgVGhlICJQcm9ncmFtIiwgYmVsb3csCnJlZmVycyB0byBhbnkgc3VjaCBwcm9ncmFtIG9yIHdv
+cmssIGFuZCBhICJ3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtIgptZWFucyBlaXRoZXIgdGhlIFBy
+b2dyYW0gb3IgYW55IGRlcml2YXRpdmUgd29yayB1bmRlciBjb3B5cmlnaHQgbGF3Ogp0aGF0IGlz
+IHRvIHNheSwgYSB3b3JrIGNvbnRhaW5pbmcgdGhlIFByb2dyYW0gb3IgYSBwb3J0aW9uIG9mIGl0
+LAplaXRoZXIgdmVyYmF0aW0gb3Igd2l0aCBtb2RpZmljYXRpb25zIGFuZC9vciB0cmFuc2xhdGVk
+IGludG8gYW5vdGhlcgpsYW5ndWFnZS4gIChIZXJlaW5hZnRlciwgdHJhbnNsYXRpb24gaXMgaW5j
+bHVkZWQgd2l0aG91dCBsaW1pdGF0aW9uIGluCnRoZSB0ZXJtICJtb2RpZmljYXRpb24iLikgIEVh
+Y2ggbGljZW5zZWUgaXMgYWRkcmVzc2VkIGFzICJ5b3UiLgoKQWN0aXZpdGllcyBvdGhlciB0aGFu
+IGNvcHlpbmcsIGRpc3RyaWJ1dGlvbiBhbmQgbW9kaWZpY2F0aW9uIGFyZSBub3QKY292ZXJlZCBi
+eSB0aGlzIExpY2Vuc2U7IHRoZXkgYXJlIG91dHNpZGUgaXRzIHNjb3BlLiAgVGhlIGFjdCBvZgpy
+dW5uaW5nIHRoZSBQcm9ncmFtIGlzIG5vdCByZXN0cmljdGVkLCBhbmQgdGhlIG91dHB1dCBmcm9t
+IHRoZSBQcm9ncmFtCmlzIGNvdmVyZWQgb25seSBpZiBpdHMgY29udGVudHMgY29uc3RpdHV0ZSBh
+IHdvcmsgYmFzZWQgb24gdGhlClByb2dyYW0gKGluZGVwZW5kZW50IG9mIGhhdmluZyBiZWVuIG1h
+ZGUgYnkgcnVubmluZyB0aGUgUHJvZ3JhbSkuCldoZXRoZXIgdGhhdCBpcyB0cnVlIGRlcGVuZHMg
+b24gd2hhdCB0aGUgUHJvZ3JhbSBkb2VzLgoKICAxLiBZb3UgbWF5IGNvcHkgYW5kIGRpc3RyaWJ1
+dGUgdmVyYmF0aW0gY29waWVzIG9mIHRoZSBQcm9ncmFtJ3MKc291cmNlIGNvZGUgYXMgeW91IHJl
+Y2VpdmUgaXQsIGluIGFueSBtZWRpdW0sIHByb3ZpZGVkIHRoYXQgeW91CmNvbnNwaWN1b3VzbHkg
+YW5kIGFwcHJvcHJpYXRlbHkgcHVibGlzaCBvbiBlYWNoIGNvcHkgYW4gYXBwcm9wcmlhdGUKY29w
+eXJpZ2h0IG5vdGljZSBhbmQgZGlzY2xhaW1lciBvZiB3YXJyYW50eTsga2VlcCBpbnRhY3QgYWxs
+IHRoZQpub3RpY2VzIHRoYXQgcmVmZXIgdG8gdGhpcyBMaWNlbnNlIGFuZCB0byB0aGUgYWJzZW5j
+ZSBvZiBhbnkgd2FycmFudHk7CmFuZCBnaXZlIGFueSBvdGhlciByZWNpcGllbnRzIG9mIHRoZSBQ
+cm9ncmFtIGEgY29weSBvZiB0aGlzIExpY2Vuc2UKYWxvbmcgd2l0aCB0aGUgUHJvZ3JhbS4KCllv
+dSBtYXkgY2hhcmdlIGEgZmVlIGZvciB0aGUgcGh5c2ljYWwgYWN0IG9mIHRyYW5zZmVycmluZyBh
+IGNvcHksIGFuZAp5b3UgbWF5IGF0IHlvdXIgb3B0aW9uIG9mZmVyIHdhcnJhbnR5IHByb3RlY3Rp
+b24gaW4gZXhjaGFuZ2UgZm9yIGEgZmVlLgoKICAyLiBZb3UgbWF5IG1vZGlmeSB5b3VyIGNvcHkg
+b3IgY29waWVzIG9mIHRoZSBQcm9ncmFtIG9yIGFueSBwb3J0aW9uCm9mIGl0LCB0aHVzIGZvcm1p
+bmcgYSB3b3JrIGJhc2VkIG9uIHRoZSBQcm9ncmFtLCBhbmQgY29weSBhbmQKZGlzdHJpYnV0ZSBz
+dWNoIG1vZGlmaWNhdGlvbnMgb3Igd29yayB1bmRlciB0aGUgdGVybXMgb2YgU2VjdGlvbiAxCmFi
+b3ZlLCBwcm92aWRlZCB0aGF0IHlvdSBhbHNvIG1lZXQgYWxsIG9mIHRoZXNlIGNvbmRpdGlvbnM6
+CgogICAgYSkgWW91IG11c3QgY2F1c2UgdGhlIG1vZGlmaWVkIGZpbGVzIHRvIGNhcnJ5IHByb21p
+bmVudCBub3RpY2VzCiAgICBzdGF0aW5nIHRoYXQgeW91IGNoYW5nZWQgdGhlIGZpbGVzIGFuZCB0
+aGUgZGF0ZSBvZiBhbnkgY2hhbmdlLgoKICAgIGIpIFlvdSBtdXN0IGNhdXNlIGFueSB3b3JrIHRo
+YXQgeW91IGRpc3RyaWJ1dGUgb3IgcHVibGlzaCwgdGhhdCBpbgogICAgd2hvbGUgb3IgaW4gcGFy
+dCBjb250YWlucyBvciBpcyBkZXJpdmVkIGZyb20gdGhlIFByb2dyYW0gb3IgYW55CiAgICBwYXJ0
+IHRoZXJlb2YsIHRvIGJlIGxpY2Vuc2VkIGFzIGEgd2hvbGUgYXQgbm8gY2hhcmdlIHRvIGFsbCB0
+aGlyZAogICAgcGFydGllcyB1bmRlciB0aGUgdGVybXMgb2YgdGhpcyBMaWNlbnNlLgoKICAgIGMp
+IElmIHRoZSBtb2RpZmllZCBwcm9ncmFtIG5vcm1hbGx5IHJlYWRzIGNvbW1hbmRzIGludGVyYWN0
+aXZlbHkKICAgIHdoZW4gcnVuLCB5b3UgbXVzdCBjYXVzZSBpdCwgd2hlbiBzdGFydGVkIHJ1bm5p
+bmcgZm9yIHN1Y2gKICAgIGludGVyYWN0aXZlIHVzZSBpbiB0aGUgbW9zdCBvcmRpbmFyeSB3YXks
+IHRvIHByaW50IG9yIGRpc3BsYXkgYW4KICAgIGFubm91bmNlbWVudCBpbmNsdWRpbmcgYW4gYXBw
+cm9wcmlhdGUgY29weXJpZ2h0IG5vdGljZSBhbmQgYQogICAgbm90aWNlIHRoYXQgdGhlcmUgaXMg
+bm8gd2FycmFudHkgKG9yIGVsc2UsIHNheWluZyB0aGF0IHlvdSBwcm92aWRlCiAgICBhIHdhcnJh
+bnR5KSBhbmQgdGhhdCB1c2VycyBtYXkgcmVkaXN0cmlidXRlIHRoZSBwcm9ncmFtIHVuZGVyCiAg
+ICB0aGVzZSBjb25kaXRpb25zLCBhbmQgdGVsbGluZyB0aGUgdXNlciBob3cgdG8gdmlldyBhIGNv
+cHkgb2YgdGhpcwogICAgTGljZW5zZS4gIChFeGNlcHRpb246IGlmIHRoZSBQcm9ncmFtIGl0c2Vs
+ZiBpcyBpbnRlcmFjdGl2ZSBidXQKICAgIGRvZXMgbm90IG5vcm1hbGx5IHByaW50IHN1Y2ggYW4g
+YW5ub3VuY2VtZW50LCB5b3VyIHdvcmsgYmFzZWQgb24KICAgIHRoZSBQcm9ncmFtIGlzIG5vdCBy
+ZXF1aXJlZCB0byBwcmludCBhbiBhbm5vdW5jZW1lbnQuKQoKVGhlc2UgcmVxdWlyZW1lbnRzIGFw
+cGx5IHRvIHRoZSBtb2RpZmllZCB3b3JrIGFzIGEgd2hvbGUuICBJZgppZGVudGlmaWFibGUgc2Vj
+dGlvbnMgb2YgdGhhdCB3b3JrIGFyZSBub3QgZGVyaXZlZCBmcm9tIHRoZSBQcm9ncmFtLAphbmQg
+Y2FuIGJlIHJlYXNvbmFibHkgY29uc2lkZXJlZCBpbmRlcGVuZGVudCBhbmQgc2VwYXJhdGUgd29y
+a3MgaW4KdGhlbXNlbHZlcywgdGhlbiB0aGlzIExpY2Vuc2UsIGFuZCBpdHMgdGVybXMsIGRvIG5v
+dCBhcHBseSB0byB0aG9zZQpzZWN0aW9ucyB3aGVuIHlvdSBkaXN0cmlidXRlIHRoZW0gYXMgc2Vw
+YXJhdGUgd29ya3MuICBCdXQgd2hlbiB5b3UKZGlzdHJpYnV0ZSB0aGUgc2FtZSBzZWN0aW9ucyBh
+cyBwYXJ0IG9mIGEgd2hvbGUgd2hpY2ggaXMgYSB3b3JrIGJhc2VkCm9uIHRoZSBQcm9ncmFtLCB0
+aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB3aG9sZSBtdXN0IGJlIG9uIHRoZSB0ZXJtcyBvZgp0aGlz
+IExpY2Vuc2UsIHdob3NlIHBlcm1pc3Npb25zIGZvciBvdGhlciBsaWNlbnNlZXMgZXh0ZW5kIHRv
+IHRoZQplbnRpcmUgd2hvbGUsIGFuZCB0aHVzIHRvIGVhY2ggYW5kIGV2ZXJ5IHBhcnQgcmVnYXJk
+bGVzcyBvZiB3aG8gd3JvdGUgaXQuCgpUaHVzLCBpdCBpcyBub3QgdGhlIGludGVudCBvZiB0aGlz
+IHNlY3Rpb24gdG8gY2xhaW0gcmlnaHRzIG9yIGNvbnRlc3QKeW91ciByaWdodHMgdG8gd29yayB3
+cml0dGVuIGVudGlyZWx5IGJ5IHlvdTsgcmF0aGVyLCB0aGUgaW50ZW50IGlzIHRvCmV4ZXJjaXNl
+IHRoZSByaWdodCB0byBjb250cm9sIHRoZSBkaXN0cmlidXRpb24gb2YgZGVyaXZhdGl2ZSBvcgpj
+b2xsZWN0aXZlIHdvcmtzIGJhc2VkIG9uIHRoZSBQcm9ncmFtLgoKSW4gYWRkaXRpb24sIG1lcmUg
+YWdncmVnYXRpb24gb2YgYW5vdGhlciB3b3JrIG5vdCBiYXNlZCBvbiB0aGUgUHJvZ3JhbQp3aXRo
+IHRoZSBQcm9ncmFtIChvciB3aXRoIGEgd29yayBiYXNlZCBvbiB0aGUgUHJvZ3JhbSkgb24gYSB2
+b2x1bWUgb2YKYSBzdG9yYWdlIG9yIGRpc3RyaWJ1dGlvbiBtZWRpdW0gZG9lcyBub3QgYnJpbmcg
+dGhlIG90aGVyIHdvcmsgdW5kZXIKdGhlIHNjb3BlIG9mIHRoaXMgTGljZW5zZS4KCiAgMy4gWW91
+IG1heSBjb3B5IGFuZCBkaXN0cmlidXRlIHRoZSBQcm9ncmFtIChvciBhIHdvcmsgYmFzZWQgb24g
+aXQsCnVuZGVyIFNlY3Rpb24gMikgaW4gb2JqZWN0IGNvZGUgb3IgZXhlY3V0YWJsZSBmb3JtIHVu
+ZGVyIHRoZSB0ZXJtcyBvZgpTZWN0aW9ucyAxIGFuZCAyIGFib3ZlIHByb3ZpZGVkIHRoYXQgeW91
+IGFsc28gZG8gb25lIG9mIHRoZSBmb2xsb3dpbmc6CgogICAgYSkgQWNjb21wYW55IGl0IHdpdGgg
+dGhlIGNvbXBsZXRlIGNvcnJlc3BvbmRpbmcgbWFjaGluZS1yZWFkYWJsZQogICAgc291cmNlIGNv
+ZGUsIHdoaWNoIG11c3QgYmUgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIHRlcm1zIG9mIFNlY3Rpb25z
+CiAgICAxIGFuZCAyIGFib3ZlIG9uIGEgbWVkaXVtIGN1c3RvbWFyaWx5IHVzZWQgZm9yIHNvZnR3
+YXJlIGludGVyY2hhbmdlOyBvciwKCiAgICBiKSBBY2NvbXBhbnkgaXQgd2l0aCBhIHdyaXR0ZW4g
+b2ZmZXIsIHZhbGlkIGZvciBhdCBsZWFzdCB0aHJlZQogICAgeWVhcnMsIHRvIGdpdmUgYW55IHRo
+aXJkIHBhcnR5LCBmb3IgYSBjaGFyZ2Ugbm8gbW9yZSB0aGFuIHlvdXIKICAgIGNvc3Qgb2YgcGh5
+c2ljYWxseSBwZXJmb3JtaW5nIHNvdXJjZSBkaXN0cmlidXRpb24sIGEgY29tcGxldGUKICAgIG1h
+Y2hpbmUtcmVhZGFibGUgY29weSBvZiB0aGUgY29ycmVzcG9uZGluZyBzb3VyY2UgY29kZSwgdG8g
+YmUKICAgIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSB0ZXJtcyBvZiBTZWN0aW9ucyAxIGFuZCAyIGFi
+b3ZlIG9uIGEgbWVkaXVtCiAgICBjdXN0b21hcmlseSB1c2VkIGZvciBzb2Z0d2FyZSBpbnRlcmNo
+YW5nZTsgb3IsCgogICAgYykgQWNjb21wYW55IGl0IHdpdGggdGhlIGluZm9ybWF0aW9uIHlvdSBy
+ZWNlaXZlZCBhcyB0byB0aGUgb2ZmZXIKICAgIHRvIGRpc3RyaWJ1dGUgY29ycmVzcG9uZGluZyBz
+b3VyY2UgY29kZS4gIChUaGlzIGFsdGVybmF0aXZlIGlzCiAgICBhbGxvd2VkIG9ubHkgZm9yIG5v
+bmNvbW1lcmNpYWwgZGlzdHJpYnV0aW9uIGFuZCBvbmx5IGlmIHlvdQogICAgcmVjZWl2ZWQgdGhl
+IHByb2dyYW0gaW4gb2JqZWN0IGNvZGUgb3IgZXhlY3V0YWJsZSBmb3JtIHdpdGggc3VjaAogICAg
+YW4gb2ZmZXIsIGluIGFjY29yZCB3aXRoIFN1YnNlY3Rpb24gYiBhYm92ZS4pCgpUaGUgc291cmNl
+IGNvZGUgZm9yIGEgd29yayBtZWFucyB0aGUgcHJlZmVycmVkIGZvcm0gb2YgdGhlIHdvcmsgZm9y
+Cm1ha2luZyBtb2RpZmljYXRpb25zIHRvIGl0LiAgRm9yIGFuIGV4ZWN1dGFibGUgd29yaywgY29t
+cGxldGUgc291cmNlCmNvZGUgbWVhbnMgYWxsIHRoZSBzb3VyY2UgY29kZSBmb3IgYWxsIG1vZHVs
+ZXMgaXQgY29udGFpbnMsIHBsdXMgYW55CmFzc29jaWF0ZWQgaW50ZXJmYWNlIGRlZmluaXRpb24g
+ZmlsZXMsIHBsdXMgdGhlIHNjcmlwdHMgdXNlZCB0bwpjb250cm9sIGNvbXBpbGF0aW9uIGFuZCBp
+bnN0YWxsYXRpb24gb2YgdGhlIGV4ZWN1dGFibGUuICBIb3dldmVyLCBhcyBhCnNwZWNpYWwgZXhj
+ZXB0aW9uLCB0aGUgc291cmNlIGNvZGUgZGlzdHJpYnV0ZWQgbmVlZCBub3QgaW5jbHVkZQphbnl0
+aGluZyB0aGF0IGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIChpbiBlaXRoZXIgc291cmNlIG9yIGJp
+bmFyeQpmb3JtKSB3aXRoIHRoZSBtYWpvciBjb21wb25lbnRzIChjb21waWxlciwga2VybmVsLCBh
+bmQgc28gb24pIG9mIHRoZQpvcGVyYXRpbmcgc3lzdGVtIG9uIHdoaWNoIHRoZSBleGVjdXRhYmxl
+IHJ1bnMsIHVubGVzcyB0aGF0IGNvbXBvbmVudAppdHNlbGYgYWNjb21wYW5pZXMgdGhlIGV4ZWN1
+dGFibGUuCgpJZiBkaXN0cmlidXRpb24gb2YgZXhlY3V0YWJsZSBvciBvYmplY3QgY29kZSBpcyBt
+YWRlIGJ5IG9mZmVyaW5nCmFjY2VzcyB0byBjb3B5IGZyb20gYSBkZXNpZ25hdGVkIHBsYWNlLCB0
+aGVuIG9mZmVyaW5nIGVxdWl2YWxlbnQKYWNjZXNzIHRvIGNvcHkgdGhlIHNvdXJjZSBjb2RlIGZy
+b20gdGhlIHNhbWUgcGxhY2UgY291bnRzIGFzCmRpc3RyaWJ1dGlvbiBvZiB0aGUgc291cmNlIGNv
+ZGUsIGV2ZW4gdGhvdWdoIHRoaXJkIHBhcnRpZXMgYXJlIG5vdApjb21wZWxsZWQgdG8gY29weSB0
+aGUgc291cmNlIGFsb25nIHdpdGggdGhlIG9iamVjdCBjb2RlLgoKICA0LiBZb3UgbWF5IG5vdCBj
+b3B5LCBtb2RpZnksIHN1YmxpY2Vuc2UsIG9yIGRpc3RyaWJ1dGUgdGhlIFByb2dyYW0KZXhjZXB0
+IGFzIGV4cHJlc3NseSBwcm92aWRlZCB1bmRlciB0aGlzIExpY2Vuc2UuICBBbnkgYXR0ZW1wdApv
+dGhlcndpc2UgdG8gY29weSwgbW9kaWZ5LCBzdWJsaWNlbnNlIG9yIGRpc3RyaWJ1dGUgdGhlIFBy
+b2dyYW0gaXMKdm9pZCwgYW5kIHdpbGwgYXV0b21hdGljYWxseSB0ZXJtaW5hdGUgeW91ciByaWdo
+dHMgdW5kZXIgdGhpcyBMaWNlbnNlLgpIb3dldmVyLCBwYXJ0aWVzIHdobyBoYXZlIHJlY2VpdmVk
+IGNvcGllcywgb3IgcmlnaHRzLCBmcm9tIHlvdSB1bmRlcgp0aGlzIExpY2Vuc2Ugd2lsbCBub3Qg
+aGF2ZSB0aGVpciBsaWNlbnNlcyB0ZXJtaW5hdGVkIHNvIGxvbmcgYXMgc3VjaApwYXJ0aWVzIHJl
+bWFpbiBpbiBmdWxsIGNvbXBsaWFuY2UuCgogIDUuIFlvdSBhcmUgbm90IHJlcXVpcmVkIHRvIGFj
+Y2VwdCB0aGlzIExpY2Vuc2UsIHNpbmNlIHlvdSBoYXZlIG5vdApzaWduZWQgaXQuICBIb3dldmVy
+LCBub3RoaW5nIGVsc2UgZ3JhbnRzIHlvdSBwZXJtaXNzaW9uIHRvIG1vZGlmeSBvcgpkaXN0cmli
+dXRlIHRoZSBQcm9ncmFtIG9yIGl0cyBkZXJpdmF0aXZlIHdvcmtzLiAgVGhlc2UgYWN0aW9ucyBh
+cmUKcHJvaGliaXRlZCBieSBsYXcgaWYgeW91IGRvIG5vdCBhY2NlcHQgdGhpcyBMaWNlbnNlLiAg
+VGhlcmVmb3JlLCBieQptb2RpZnlpbmcgb3IgZGlzdHJpYnV0aW5nIHRoZSBQcm9ncmFtIChvciBh
+bnkgd29yayBiYXNlZCBvbiB0aGUKUHJvZ3JhbSksIHlvdSBpbmRpY2F0ZSB5b3VyIGFjY2VwdGFu
+Y2Ugb2YgdGhpcyBMaWNlbnNlIHRvIGRvIHNvLCBhbmQKYWxsIGl0cyB0ZXJtcyBhbmQgY29uZGl0
+aW9ucyBmb3IgY29weWluZywgZGlzdHJpYnV0aW5nIG9yIG1vZGlmeWluZwp0aGUgUHJvZ3JhbSBv
+ciB3b3JrcyBiYXNlZCBvbiBpdC4KCiAgNi4gRWFjaCB0aW1lIHlvdSByZWRpc3RyaWJ1dGUgdGhl
+IFByb2dyYW0gKG9yIGFueSB3b3JrIGJhc2VkIG9uIHRoZQpQcm9ncmFtKSwgdGhlIHJlY2lwaWVu
+dCBhdXRvbWF0aWNhbGx5IHJlY2VpdmVzIGEgbGljZW5zZSBmcm9tIHRoZQpvcmlnaW5hbCBsaWNl
+bnNvciB0byBjb3B5LCBkaXN0cmlidXRlIG9yIG1vZGlmeSB0aGUgUHJvZ3JhbSBzdWJqZWN0IHRv
+CnRoZXNlIHRlcm1zIGFuZCBjb25kaXRpb25zLiAgWW91IG1heSBub3QgaW1wb3NlIGFueSBmdXJ0
+aGVyCnJlc3RyaWN0aW9ucyBvbiB0aGUgcmVjaXBpZW50cycgZXhlcmNpc2Ugb2YgdGhlIHJpZ2h0
+cyBncmFudGVkIGhlcmVpbi4KWW91IGFyZSBub3QgcmVzcG9uc2libGUgZm9yIGVuZm9yY2luZyBj
+b21wbGlhbmNlIGJ5IHRoaXJkIHBhcnRpZXMgdG8KdGhpcyBMaWNlbnNlLgoKICA3LiBJZiwgYXMg
+YSBjb25zZXF1ZW5jZSBvZiBhIGNvdXJ0IGp1ZGdtZW50IG9yIGFsbGVnYXRpb24gb2YgcGF0ZW50
+CmluZnJpbmdlbWVudCBvciBmb3IgYW55IG90aGVyIHJlYXNvbiAobm90IGxpbWl0ZWQgdG8gcGF0
+ZW50IGlzc3VlcyksCmNvbmRpdGlvbnMgYXJlIGltcG9zZWQgb24geW91ICh3aGV0aGVyIGJ5IGNv
+dXJ0IG9yZGVyLCBhZ3JlZW1lbnQgb3IKb3RoZXJ3aXNlKSB0aGF0IGNvbnRyYWRpY3QgdGhlIGNv
+bmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLCB0aGV5IGRvIG5vdApleGN1c2UgeW91IGZyb20gdGhl
+IGNvbmRpdGlvbnMgb2YgdGhpcyBMaWNlbnNlLiAgSWYgeW91IGNhbm5vdApkaXN0cmlidXRlIHNv
+IGFzIHRvIHNhdGlzZnkgc2ltdWx0YW5lb3VzbHkgeW91ciBvYmxpZ2F0aW9ucyB1bmRlciB0aGlz
+CkxpY2Vuc2UgYW5kIGFueSBvdGhlciBwZXJ0aW5lbnQgb2JsaWdhdGlvbnMsIHRoZW4gYXMgYSBj
+b25zZXF1ZW5jZSB5b3UKbWF5IG5vdCBkaXN0cmlidXRlIHRoZSBQcm9ncmFtIGF0IGFsbC4gIEZv
+ciBleGFtcGxlLCBpZiBhIHBhdGVudApsaWNlbnNlIHdvdWxkIG5vdCBwZXJtaXQgcm95YWx0eS1m
+cmVlIHJlZGlzdHJpYnV0aW9uIG9mIHRoZSBQcm9ncmFtIGJ5CmFsbCB0aG9zZSB3aG8gcmVjZWl2
+ZSBjb3BpZXMgZGlyZWN0bHkgb3IgaW5kaXJlY3RseSB0aHJvdWdoIHlvdSwgdGhlbgp0aGUgb25s
+eSB3YXkgeW91IGNvdWxkIHNhdGlzZnkgYm90aCBpdCBhbmQgdGhpcyBMaWNlbnNlIHdvdWxkIGJl
+IHRvCnJlZnJhaW4gZW50aXJlbHkgZnJvbSBkaXN0cmlidXRpb24gb2YgdGhlIFByb2dyYW0uCgpJ
+ZiBhbnkgcG9ydGlvbiBvZiB0aGlzIHNlY3Rpb24gaXMgaGVsZCBpbnZhbGlkIG9yIHVuZW5mb3Jj
+ZWFibGUgdW5kZXIKYW55IHBhcnRpY3VsYXIgY2lyY3Vtc3RhbmNlLCB0aGUgYmFsYW5jZSBvZiB0
+aGUgc2VjdGlvbiBpcyBpbnRlbmRlZCB0bwphcHBseSBhbmQgdGhlIHNlY3Rpb24gYXMgYSB3aG9s
+ZSBpcyBpbnRlbmRlZCB0byBhcHBseSBpbiBvdGhlcgpjaXJjdW1zdGFuY2VzLgoKSXQgaXMgbm90
+IHRoZSBwdXJwb3NlIG9mIHRoaXMgc2VjdGlvbiB0byBpbmR1Y2UgeW91IHRvIGluZnJpbmdlIGFu
+eQpwYXRlbnRzIG9yIG90aGVyIHByb3BlcnR5IHJpZ2h0IGNsYWltcyBvciB0byBjb250ZXN0IHZh
+bGlkaXR5IG9mIGFueQpzdWNoIGNsYWltczsgdGhpcyBzZWN0aW9uIGhhcyB0aGUgc29sZSBwdXJw
+b3NlIG9mIHByb3RlY3RpbmcgdGhlCmludGVncml0eSBvZiB0aGUgZnJlZSBzb2Z0d2FyZSBkaXN0
+cmlidXRpb24gc3lzdGVtLCB3aGljaCBpcwppbXBsZW1lbnRlZCBieSBwdWJsaWMgbGljZW5zZSBw
+cmFjdGljZXMuICBNYW55IHBlb3BsZSBoYXZlIG1hZGUKZ2VuZXJvdXMgY29udHJpYnV0aW9ucyB0
+byB0aGUgd2lkZSByYW5nZSBvZiBzb2Z0d2FyZSBkaXN0cmlidXRlZAp0aHJvdWdoIHRoYXQgc3lz
+dGVtIGluIHJlbGlhbmNlIG9uIGNvbnNpc3RlbnQgYXBwbGljYXRpb24gb2YgdGhhdApzeXN0ZW07
+IGl0IGlzIHVwIHRvIHRoZSBhdXRob3IvZG9ub3IgdG8gZGVjaWRlIGlmIGhlIG9yIHNoZSBpcyB3
+aWxsaW5nCnRvIGRpc3RyaWJ1dGUgc29mdHdhcmUgdGhyb3VnaCBhbnkgb3RoZXIgc3lzdGVtIGFu
+ZCBhIGxpY2Vuc2VlIGNhbm5vdAppbXBvc2UgdGhhdCBjaG9pY2UuCgpUaGlzIHNlY3Rpb24gaXMg
+aW50ZW5kZWQgdG8gbWFrZSB0aG9yb3VnaGx5IGNsZWFyIHdoYXQgaXMgYmVsaWV2ZWQgdG8KYmUg
+YSBjb25zZXF1ZW5jZSBvZiB0aGUgcmVzdCBvZiB0aGlzIExpY2Vuc2UuCgogIDguIElmIHRoZSBk
+aXN0cmlidXRpb24gYW5kL29yIHVzZSBvZiB0aGUgUHJvZ3JhbSBpcyByZXN0cmljdGVkIGluCmNl
+cnRhaW4gY291bnRyaWVzIGVpdGhlciBieSBwYXRlbnRzIG9yIGJ5IGNvcHlyaWdodGVkIGludGVy
+ZmFjZXMsIHRoZQpvcmlnaW5hbCBjb3B5cmlnaHQgaG9sZGVyIHdobyBwbGFjZXMgdGhlIFByb2dy
+YW0gdW5kZXIgdGhpcyBMaWNlbnNlCm1heSBhZGQgYW4gZXhwbGljaXQgZ2VvZ3JhcGhpY2FsIGRp
+c3RyaWJ1dGlvbiBsaW1pdGF0aW9uIGV4Y2x1ZGluZwp0aG9zZSBjb3VudHJpZXMsIHNvIHRoYXQg
+ZGlzdHJpYnV0aW9uIGlzIHBlcm1pdHRlZCBvbmx5IGluIG9yIGFtb25nCmNvdW50cmllcyBub3Qg
+dGh1cyBleGNsdWRlZC4gIEluIHN1Y2ggY2FzZSwgdGhpcyBMaWNlbnNlIGluY29ycG9yYXRlcwp0
+aGUgbGltaXRhdGlvbiBhcyBpZiB3cml0dGVuIGluIHRoZSBib2R5IG9mIHRoaXMgTGljZW5zZS4K
+CiAgOS4gVGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiBtYXkgcHVibGlzaCByZXZpc2VkIGFu
+ZC9vciBuZXcgdmVyc2lvbnMKb2YgdGhlIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZnJvbSB0aW1l
+IHRvIHRpbWUuICBTdWNoIG5ldyB2ZXJzaW9ucyB3aWxsCmJlIHNpbWlsYXIgaW4gc3Bpcml0IHRv
+IHRoZSBwcmVzZW50IHZlcnNpb24sIGJ1dCBtYXkgZGlmZmVyIGluIGRldGFpbCB0bwphZGRyZXNz
+IG5ldyBwcm9ibGVtcyBvciBjb25jZXJucy4KCkVhY2ggdmVyc2lvbiBpcyBnaXZlbiBhIGRpc3Rp
+bmd1aXNoaW5nIHZlcnNpb24gbnVtYmVyLiAgSWYgdGhlIFByb2dyYW0Kc3BlY2lmaWVzIGEgdmVy
+c2lvbiBudW1iZXIgb2YgdGhpcyBMaWNlbnNlIHdoaWNoIGFwcGxpZXMgdG8gaXQgYW5kICJhbnkK
+bGF0ZXIgdmVyc2lvbiIsIHlvdSBoYXZlIHRoZSBvcHRpb24gb2YgZm9sbG93aW5nIHRoZSB0ZXJt
+cyBhbmQgY29uZGl0aW9ucwplaXRoZXIgb2YgdGhhdCB2ZXJzaW9uIG9yIG9mIGFueSBsYXRlciB2
+ZXJzaW9uIHB1Ymxpc2hlZCBieSB0aGUgRnJlZQpTb2Z0d2FyZSBGb3VuZGF0aW9uLiAgSWYgdGhl
+IFByb2dyYW0gZG9lcyBub3Qgc3BlY2lmeSBhIHZlcnNpb24gbnVtYmVyIG9mCnRoaXMgTGljZW5z
+ZSwgeW91IG1heSBjaG9vc2UgYW55IHZlcnNpb24gZXZlciBwdWJsaXNoZWQgYnkgdGhlIEZyZWUg
+U29mdHdhcmUKRm91bmRhdGlvbi4KCiAgMTAuIElmIHlvdSB3aXNoIHRvIGluY29ycG9yYXRlIHBh
+cnRzIG9mIHRoZSBQcm9ncmFtIGludG8gb3RoZXIgZnJlZQpwcm9ncmFtcyB3aG9zZSBkaXN0cmli
+dXRpb24gY29uZGl0aW9ucyBhcmUgZGlmZmVyZW50LCB3cml0ZSB0byB0aGUgYXV0aG9yCnRvIGFz
+ayBmb3IgcGVybWlzc2lvbi4gIEZvciBzb2Z0d2FyZSB3aGljaCBpcyBjb3B5cmlnaHRlZCBieSB0
+aGUgRnJlZQpTb2Z0d2FyZSBGb3VuZGF0aW9uLCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZSBG
+b3VuZGF0aW9uOyB3ZSBzb21ldGltZXMKbWFrZSBleGNlcHRpb25zIGZvciB0aGlzLiAgT3VyIGRl
+Y2lzaW9uIHdpbGwgYmUgZ3VpZGVkIGJ5IHRoZSB0d28gZ29hbHMKb2YgcHJlc2VydmluZyB0aGUg
+ZnJlZSBzdGF0dXMgb2YgYWxsIGRlcml2YXRpdmVzIG9mIG91ciBmcmVlIHNvZnR3YXJlIGFuZApv
+ZiBwcm9tb3RpbmcgdGhlIHNoYXJpbmcgYW5kIHJldXNlIG9mIHNvZnR3YXJlIGdlbmVyYWxseS4K
+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBOTyBXQVJSQU5UWQoKICAxMS4gQkVDQVVTRSBU
+SEUgUFJPR1JBTSBJUyBMSUNFTlNFRCBGUkVFIE9GIENIQVJHRSwgVEhFUkUgSVMgTk8gV0FSUkFO
+VFkKRk9SIFRIRSBQUk9HUkFNLCBUTyBUSEUgRVhURU5UIFBFUk1JVFRFRCBCWSBBUFBMSUNBQkxF
+IExBVy4gIEVYQ0VQVCBXSEVOCk9USEVSV0lTRSBTVEFURUQgSU4gV1JJVElORyBUSEUgQ09QWVJJ
+R0hUIEhPTERFUlMgQU5EL09SIE9USEVSIFBBUlRJRVMKUFJPVklERSBUSEUgUFJPR1JBTSAiQVMg
+SVMiIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVJVEhFUiBFWFBSRVNTRUQKT1IgSU1Q
+TElFRCwgSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sIFRIRSBJTVBMSUVEIFdBUlJBTlRJ
+RVMgT0YKTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9T
+RS4gIFRIRSBFTlRJUkUgUklTSyBBUwpUTyBUSEUgUVVBTElUWSBBTkQgUEVSRk9STUFOQ0UgT0Yg
+VEhFIFBST0dSQU0gSVMgV0lUSCBZT1UuICBTSE9VTEQgVEhFClBST0dSQU0gUFJPVkUgREVGRUNU
+SVZFLCBZT1UgQVNTVU1FIFRIRSBDT1NUIE9GIEFMTCBORUNFU1NBUlkgU0VSVklDSU5HLApSRVBB
+SVIgT1IgQ09SUkVDVElPTi4KCiAgMTIuIElOIE5PIEVWRU5UIFVOTEVTUyBSRVFVSVJFRCBCWSBB
+UFBMSUNBQkxFIExBVyBPUiBBR1JFRUQgVE8gSU4gV1JJVElORwpXSUxMIEFOWSBDT1BZUklHSFQg
+SE9MREVSLCBPUiBBTlkgT1RIRVIgUEFSVFkgV0hPIE1BWSBNT0RJRlkgQU5EL09SClJFRElTVFJJ
+QlVURSBUSEUgUFJPR1JBTSBBUyBQRVJNSVRURUQgQUJPVkUsIEJFIExJQUJMRSBUTyBZT1UgRk9S
+IERBTUFHRVMsCklOQ0xVRElORyBBTlkgR0VORVJBTCwgU1BFQ0lBTCwgSU5DSURFTlRBTCBPUiBD
+T05TRVFVRU5USUFMIERBTUFHRVMgQVJJU0lORwpPVVQgT0YgVEhFIFVTRSBPUiBJTkFCSUxJVFkg
+VE8gVVNFIFRIRSBQUk9HUkFNIChJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEClRPIExPU1MgT0Yg
+REFUQSBPUiBEQVRBIEJFSU5HIFJFTkRFUkVEIElOQUNDVVJBVEUgT1IgTE9TU0VTIFNVU1RBSU5F
+RCBCWQpZT1UgT1IgVEhJUkQgUEFSVElFUyBPUiBBIEZBSUxVUkUgT0YgVEhFIFBST0dSQU0gVE8g
+T1BFUkFURSBXSVRIIEFOWSBPVEhFUgpQUk9HUkFNUyksIEVWRU4gSUYgU1VDSCBIT0xERVIgT1Ig
+T1RIRVIgUEFSVFkgSEFTIEJFRU4gQURWSVNFRCBPRiBUSEUKUE9TU0lCSUxJVFkgT0YgU1VDSCBE
+QU1BR0VTLgoKICAgICAgICAgICAgICAgICAgICAgRU5EIE9GIFRFUk1TIEFORCBDT05ESVRJT05T
+CgogICAgICAgICAgICBIb3cgdG8gQXBwbHkgVGhlc2UgVGVybXMgdG8gWW91ciBOZXcgUHJvZ3Jh
+bXMKCiAgSWYgeW91IGRldmVsb3AgYSBuZXcgcHJvZ3JhbSwgYW5kIHlvdSB3YW50IGl0IHRvIGJl
+IG9mIHRoZSBncmVhdGVzdApwb3NzaWJsZSB1c2UgdG8gdGhlIHB1YmxpYywgdGhlIGJlc3Qgd2F5
+IHRvIGFjaGlldmUgdGhpcyBpcyB0byBtYWtlIGl0CmZyZWUgc29mdHdhcmUgd2hpY2ggZXZlcnlv
+bmUgY2FuIHJlZGlzdHJpYnV0ZSBhbmQgY2hhbmdlIHVuZGVyIHRoZXNlIHRlcm1zLgoKICBUbyBk
+byBzbywgYXR0YWNoIHRoZSBmb2xsb3dpbmcgbm90aWNlcyB0byB0aGUgcHJvZ3JhbS4gIEl0IGlz
+IHNhZmVzdAp0byBhdHRhY2ggdGhlbSB0byB0aGUgc3RhcnQgb2YgZWFjaCBzb3VyY2UgZmlsZSB0
+byBtb3N0IGVmZmVjdGl2ZWx5CmNvbnZleSB0aGUgZXhjbHVzaW9uIG9mIHdhcnJhbnR5OyBhbmQg
+ZWFjaCBmaWxlIHNob3VsZCBoYXZlIGF0IGxlYXN0CnRoZSAiY29weXJpZ2h0IiBsaW5lIGFuZCBh
+IHBvaW50ZXIgdG8gd2hlcmUgdGhlIGZ1bGwgbm90aWNlIGlzIGZvdW5kLgoKICAgIDxvbmUgbGlu
+ZSB0byBnaXZlIHRoZSBwcm9ncmFtJ3MgbmFtZSBhbmQgYSBicmllZiBpZGVhIG9mIHdoYXQgaXQg
+ZG9lcy4+CiAgICBDb3B5cmlnaHQgKEMpIDx5ZWFyPiAgPG5hbWUgb2YgYXV0aG9yPgoKICAgIFRo
+aXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQv
+b3IgbW9kaWZ5CiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1Ymxp
+YyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieQogICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlv
+bjsgZWl0aGVyIHZlcnNpb24gMiBvZiB0aGUgTGljZW5zZSwgb3IKICAgIChhdCB5b3VyIG9wdGlv
+bikgYW55IGxhdGVyIHZlcnNpb24uCgogICAgVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGlu
+IHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsCiAgICBidXQgV0lUSE9VVCBBTlkgV0FS
+UkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZgogICAgTUVSQ0hBTlRB
+QklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQogICAg
+R05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy4KCiAgICBZb3Ugc2hv
+dWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5z
+ZSBhbG9uZwogICAgd2l0aCB0aGlzIHByb2dyYW07IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUg
+U29mdHdhcmUgRm91bmRhdGlvbiwgSW5jLiwKICAgIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGgg
+Rmxvb3IsIEJvc3RvbiwgTUEgMDIxMTAtMTMwMSBVU0EuCgpBbHNvIGFkZCBpbmZvcm1hdGlvbiBv
+biBob3cgdG8gY29udGFjdCB5b3UgYnkgZWxlY3Ryb25pYyBhbmQgcGFwZXIgbWFpbC4KCklmIHRo
+ZSBwcm9ncmFtIGlzIGludGVyYWN0aXZlLCBtYWtlIGl0IG91dHB1dCBhIHNob3J0IG5vdGljZSBs
+aWtlIHRoaXMKd2hlbiBpdCBzdGFydHMgaW4gYW4gaW50ZXJhY3RpdmUgbW9kZToKCiAgICBHbm9t
+b3Zpc2lvbiB2ZXJzaW9uIDY5LCBDb3B5cmlnaHQgKEMpIHllYXIgbmFtZSBvZiBhdXRob3IKICAg
+IEdub21vdmlzaW9uIGNvbWVzIHdpdGggQUJTT0xVVEVMWSBOTyBXQVJSQU5UWTsgZm9yIGRldGFp
+bHMgdHlwZSBgc2hvdyB3Jy4KICAgIFRoaXMgaXMgZnJlZSBzb2Z0d2FyZSwgYW5kIHlvdSBhcmUg
+d2VsY29tZSB0byByZWRpc3RyaWJ1dGUgaXQKICAgIHVuZGVyIGNlcnRhaW4gY29uZGl0aW9uczsg
+dHlwZSBgc2hvdyBjJyBmb3IgZGV0YWlscy4KClRoZSBoeXBvdGhldGljYWwgY29tbWFuZHMgYHNo
+b3cgdycgYW5kIGBzaG93IGMnIHNob3VsZCBzaG93IHRoZSBhcHByb3ByaWF0ZQpwYXJ0cyBvZiB0
+aGUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZS4gIE9mIGNvdXJzZSwgdGhlIGNvbW1hbmRzIHlvdSB1
+c2UgbWF5CmJlIGNhbGxlZCBzb21ldGhpbmcgb3RoZXIgdGhhbiBgc2hvdyB3JyBhbmQgYHNob3cg
+Yyc7IHRoZXkgY291bGQgZXZlbiBiZQptb3VzZS1jbGlja3Mgb3IgbWVudSBpdGVtcy0td2hhdGV2
+ZXIgc3VpdHMgeW91ciBwcm9ncmFtLgoKWW91IHNob3VsZCBhbHNvIGdldCB5b3VyIGVtcGxveWVy
+IChpZiB5b3Ugd29yayBhcyBhIHByb2dyYW1tZXIpIG9yIHlvdXIKc2Nob29sLCBpZiBhbnksIHRv
+IHNpZ24gYSAiY29weXJpZ2h0IGRpc2NsYWltZXIiIGZvciB0aGUgcHJvZ3JhbSwgaWYKbmVjZXNz
+YXJ5LiAgSGVyZSBpcyBhIHNhbXBsZTsgYWx0ZXIgdGhlIG5hbWVzOgoKICBZb3lvZHluZSwgSW5j
+LiwgaGVyZWJ5IGRpc2NsYWltcyBhbGwgY29weXJpZ2h0IGludGVyZXN0IGluIHRoZSBwcm9ncmFt
+CiAgYEdub21vdmlzaW9uJyAod2hpY2ggbWFrZXMgcGFzc2VzIGF0IGNvbXBpbGVycykgd3JpdHRl
+biBieSBKYW1lcyBIYWNrZXIuCgogIDxzaWduYXR1cmUgb2YgVHkgQ29vbj4sIDEgQXByaWwgMTk4
+OQogIFR5IENvb24sIFByZXNpZGVudCBvZiBWaWNlCgpUaGlzIEdlbmVyYWwgUHVibGljIExpY2Vu
+c2UgZG9lcyBub3QgcGVybWl0IGluY29ycG9yYXRpbmcgeW91ciBwcm9ncmFtIGludG8KcHJvcHJp
+ZXRhcnkgcHJvZ3JhbXMuICBJZiB5b3VyIHByb2dyYW0gaXMgYSBzdWJyb3V0aW5lIGxpYnJhcnks
+IHlvdSBtYXkKY29uc2lkZXIgaXQgbW9yZSB1c2VmdWwgdG8gcGVybWl0IGxpbmtpbmcgcHJvcHJp
+ZXRhcnkgYXBwbGljYXRpb25zIHdpdGggdGhlCmxpYnJhcnkuICBJZiB0aGlzIGlzIHdoYXQgeW91
+IHdhbnQgdG8gZG8sIHVzZSB0aGUgR05VIExlc3NlciBHZW5lcmFsClB1YmxpYyBMaWNlbnNlIGlu
+c3RlYWQgb2YgdGhpcyBMaWNlbnNlLg==
diff --git a/src/sdks/ts/node-addon/dependency-licenses.json b/src/sdks/ts/node-addon/dependency-licenses.json
new file mode 100644
index 000000000..6e3f4ecdb
--- /dev/null
+++ b/src/sdks/ts/node-addon/dependency-licenses.json
@@ -0,0 +1,1414 @@
+{
+  "schema": "oliphaunt-node-direct-dependency-license-contract-v1",
+  "product": "oliphaunt-node-direct",
+  "cargoSource": "registry+https://github.com/rust-lang/crates.io-index",
+  "payloadLicense": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause",
+  "targets": {
+    "linux-x64-gnu": {
+      "cargoTarget": "x86_64-unknown-linux-gnu",
+      "packages": [
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "cfg-if@1.0.4",
+        "convert_case@0.11.0",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "ctor@1.0.13",
+        "digest@0.10.7",
+        "filetime@0.2.29",
+        "fs2@0.4.3",
+        "futures-channel@0.3.32",
+        "futures-core@0.3.32",
+        "futures-executor@0.3.32",
+        "futures-io@0.3.32",
+        "futures-macro@0.3.32",
+        "futures-sink@0.3.32",
+        "futures-task@0.3.32",
+        "futures-util@0.3.32",
+        "futures@0.3.32",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "libloading@0.9.0",
+        "linux-raw-sys@0.12.1",
+        "memchr@2.8.1",
+        "napi-derive-backend@6.1.2",
+        "napi-derive@3.6.3",
+        "napi-sys@3.3.0",
+        "napi@3.12.2",
+        "nohash-hasher@0.2.0",
+        "pin-project-lite@0.2.17",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustc-hash@2.1.2",
+        "rustix@1.1.4",
+        "semver@1.0.28",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "sha2@0.10.9",
+        "slab@0.4.12",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "unicode-segmentation@1.13.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    },
+    "linux-arm64-gnu": {
+      "cargoTarget": "aarch64-unknown-linux-gnu",
+      "packages": [
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "cfg-if@1.0.4",
+        "convert_case@0.11.0",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "ctor@1.0.13",
+        "digest@0.10.7",
+        "filetime@0.2.29",
+        "fs2@0.4.3",
+        "futures-channel@0.3.32",
+        "futures-core@0.3.32",
+        "futures-executor@0.3.32",
+        "futures-io@0.3.32",
+        "futures-macro@0.3.32",
+        "futures-sink@0.3.32",
+        "futures-task@0.3.32",
+        "futures-util@0.3.32",
+        "futures@0.3.32",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "libloading@0.9.0",
+        "linux-raw-sys@0.12.1",
+        "memchr@2.8.1",
+        "napi-derive-backend@6.1.2",
+        "napi-derive@3.6.3",
+        "napi-sys@3.3.0",
+        "napi@3.12.2",
+        "nohash-hasher@0.2.0",
+        "pin-project-lite@0.2.17",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustc-hash@2.1.2",
+        "rustix@1.1.4",
+        "semver@1.0.28",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "sha2@0.10.9",
+        "slab@0.4.12",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "unicode-segmentation@1.13.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    },
+    "macos-arm64": {
+      "cargoTarget": "aarch64-apple-darwin",
+      "packages": [
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "cfg-if@1.0.4",
+        "convert_case@0.11.0",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "ctor@1.0.13",
+        "digest@0.10.7",
+        "errno@0.3.14",
+        "filetime@0.2.29",
+        "fs2@0.4.3",
+        "futures-channel@0.3.32",
+        "futures-core@0.3.32",
+        "futures-executor@0.3.32",
+        "futures-io@0.3.32",
+        "futures-macro@0.3.32",
+        "futures-sink@0.3.32",
+        "futures-task@0.3.32",
+        "futures-util@0.3.32",
+        "futures@0.3.32",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "itoa@1.0.18",
+        "libc@0.2.186",
+        "libloading@0.8.9",
+        "libloading@0.9.0",
+        "memchr@2.8.1",
+        "napi-derive-backend@6.1.2",
+        "napi-derive@3.6.3",
+        "napi-sys@3.3.0",
+        "napi@3.12.2",
+        "nohash-hasher@0.2.0",
+        "pin-project-lite@0.2.17",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustc-hash@2.1.2",
+        "rustix@1.1.4",
+        "semver@1.0.28",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "sha2@0.10.9",
+        "slab@0.4.12",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "unicode-segmentation@1.13.3",
+        "xattr@1.6.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    },
+    "windows-x64-msvc": {
+      "cargoTarget": "x86_64-pc-windows-msvc",
+      "packages": [
+        "bitflags@2.12.1",
+        "block-buffer@0.10.4",
+        "cfg-if@1.0.4",
+        "convert_case@0.11.0",
+        "cpufeatures@0.2.17",
+        "crypto-common@0.1.7",
+        "ctor@1.0.13",
+        "digest@0.10.7",
+        "filetime@0.2.29",
+        "fs2@0.4.3",
+        "futures-channel@0.3.32",
+        "futures-core@0.3.32",
+        "futures-executor@0.3.32",
+        "futures-io@0.3.32",
+        "futures-macro@0.3.32",
+        "futures-sink@0.3.32",
+        "futures-task@0.3.32",
+        "futures-util@0.3.32",
+        "futures@0.3.32",
+        "generic-array@0.14.7",
+        "getrandom@0.3.4",
+        "itoa@1.0.18",
+        "libloading@0.8.9",
+        "libloading@0.9.0",
+        "memchr@2.8.1",
+        "napi-derive-backend@6.1.2",
+        "napi-derive@3.6.3",
+        "napi-sys@3.3.0",
+        "napi@3.12.2",
+        "nohash-hasher@0.2.0",
+        "pin-project-lite@0.2.17",
+        "proc-macro2@1.0.106",
+        "quote@1.0.45",
+        "rustc-hash@2.1.2",
+        "semver@1.0.28",
+        "serde@1.0.228",
+        "serde_core@1.0.228",
+        "serde_derive@1.0.228",
+        "serde_json@1.0.150",
+        "sha2@0.10.9",
+        "slab@0.4.12",
+        "syn@2.0.117",
+        "tar@0.4.46",
+        "typenum@1.20.1",
+        "unicode-ident@1.0.24",
+        "unicode-segmentation@1.13.3",
+        "winapi@0.3.9",
+        "windows-link@0.2.1",
+        "zmij@1.0.21",
+        "zstd-safe@7.2.4",
+        "zstd-sys@2.0.16+zstd.1.5.7",
+        "zstd@0.13.3"
+      ]
+    }
+  },
+  "packages": [
+    {
+      "name": "bitflags",
+      "version": "2.12.1",
+      "checksum": "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb",
+          "bytes": 1071
+        }
+      ]
+    },
+    {
+      "name": "block-buffer",
+      "version": "0.10.4",
+      "checksum": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef",
+          "bytes": 1082
+        }
+      ]
+    },
+    {
+      "name": "cfg-if",
+      "version": "1.0.4",
+      "checksum": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
+          "bytes": 1057
+        }
+      ]
+    },
+    {
+      "name": "convert_case",
+      "version": "0.11.0",
+      "checksum": "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "aed7b1758e35afa0cd0fde059d61950747ca11cd0e5e169cb21c11608daed772",
+          "bytes": 1062
+        }
+      ]
+    },
+    {
+      "name": "cpufeatures",
+      "version": "0.2.17",
+      "checksum": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "ae9baa7beea910273c2f384c2a6b721fb7bd02bda3436074a1072e4ee689f985",
+          "bytes": 1082
+        }
+      ]
+    },
+    {
+      "name": "crypto-common",
+      "version": "0.1.7",
+      "checksum": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "3521672491a3479422d5fe1aca6645dd2984090f85da6e5205abfb18fb7a6897",
+          "bytes": 1065
+        }
+      ]
+    },
+    {
+      "name": "ctor",
+      "version": "1.0.13",
+      "checksum": "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d",
+      "declaredLicense": "Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a8ad31b1c3f40dca5a84119351b8fa8ddc868edd77fad8a8ebf6d8f2d16fa4ae",
+          "bytes": 11324
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "bccaa8b6c09f94e81f06696e179dbe058464bbdfbc823b6d49cada1d71e84ac3",
+          "bytes": 1022
+        }
+      ]
+    },
+    {
+      "name": "digest",
+      "version": "0.10.7",
+      "checksum": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba",
+          "bytes": 1057
+        }
+      ]
+    },
+    {
+      "name": "errno",
+      "version": "0.3.14",
+      "checksum": "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["macos-arm64"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "8764a597675778ddfd4e25f81b08a05dbcf089ac05662df7613fe67f150e3aa2",
+          "bytes": 1054
+        }
+      ]
+    },
+    {
+      "name": "filetime",
+      "version": "0.2.29",
+      "checksum": "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759",
+      "declaredLicense": "MIT/Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397",
+          "bytes": 1057
+        }
+      ]
+    },
+    {
+      "name": "fs2",
+      "version": "0.4.3",
+      "checksum": "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213",
+      "declaredLicense": "MIT/Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
+          "bytes": 1071
+        }
+      ]
+    },
+    {
+      "name": "futures-channel",
+      "version": "0.3.32",
+      "checksum": "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
+          "bytes": 10874
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
+          "bytes": 1094
+        }
+      ]
+    },
+    {
+      "name": "futures-core",
+      "version": "0.3.32",
+      "checksum": "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
+          "bytes": 10874
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
+          "bytes": 1094
+        }
+      ]
+    },
+    {
+      "name": "futures-executor",
+      "version": "0.3.32",
+      "checksum": "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
+          "bytes": 10874
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
+          "bytes": 1094
+        }
+      ]
+    },
+    {
+      "name": "futures-io",
+      "version": "0.3.32",
+      "checksum": "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
+          "bytes": 10874
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
+          "bytes": 1094
+        }
+      ]
+    },
+    {
+      "name": "futures-macro",
+      "version": "0.3.32",
+      "checksum": "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
+          "bytes": 10874
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
+          "bytes": 1094
+        }
+      ]
+    },
+    {
+      "name": "futures-sink",
+      "version": "0.3.32",
+      "checksum": "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
+          "bytes": 10874
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
+          "bytes": 1094
+        }
+      ]
+    },
+    {
+      "name": "futures-task",
+      "version": "0.3.32",
+      "checksum": "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
+          "bytes": 10874
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
+          "bytes": 1094
+        }
+      ]
+    },
+    {
+      "name": "futures-util",
+      "version": "0.3.32",
+      "checksum": "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
+          "bytes": 10874
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
+          "bytes": 1094
+        }
+      ]
+    },
+    {
+      "name": "futures",
+      "version": "0.3.32",
+      "checksum": "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "275c491d6d1160553c32fd6127061d7f9606c3ea25abfad6ca3f6ed088785427",
+          "bytes": 10874
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "6652c868f35dfe5e8ef636810a4e576b9d663f3a17fb0f5613ad73583e1b88fd",
+          "bytes": 1094
+        }
+      ]
+    },
+    {
+      "name": "generic-array",
+      "version": "0.14.7",
+      "checksum": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583",
+          "bytes": 1107
+        }
+      ]
+    },
+    {
+      "name": "getrandom",
+      "version": "0.3.4",
+      "checksum": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "29e9fe5074bd27e0e5d5d110394fbbcd841baee2651a3c4b4560a632702cede4",
+          "bytes": 1130
+        }
+      ]
+    },
+    {
+      "name": "itoa",
+      "version": "1.0.18",
+      "checksum": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "libc",
+      "version": "0.2.186",
+      "checksum": "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "123a331b5dbf04c30097fa43b8f858bc85df671fe776de498d01f3d6b7c1f69e",
+          "bytes": 1066
+        }
+      ]
+    },
+    {
+      "name": "libloading",
+      "version": "0.8.9",
+      "checksum": "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55",
+      "declaredLicense": "ISC",
+      "selectedLicense": "ISC",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f",
+          "bytes": 736
+        }
+      ]
+    },
+    {
+      "name": "libloading",
+      "version": "0.9.0",
+      "checksum": "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60",
+      "declaredLicense": "ISC",
+      "selectedLicense": "ISC",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f",
+          "bytes": 736
+        }
+      ]
+    },
+    {
+      "name": "linux-raw-sys",
+      "version": "0.12.1",
+      "checksum": "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53",
+      "declaredLicense": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu"],
+      "licenseFiles": [
+        {
+          "name": "COPYRIGHT",
+          "sha256": "3290ae0fbc9ddb77d2239121d710f0bb9d31b3b4744e6d97fe01e652b4c1870b",
+          "bytes": 881
+        },
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-Apache-2.0_WITH_LLVM-exception",
+          "sha256": "268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5",
+          "bytes": 12243
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "memchr",
+      "version": "2.8.1",
+      "checksum": "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8",
+      "declaredLicense": "Unlicense OR MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "COPYING",
+          "sha256": "01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f",
+          "bytes": 126
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "0f96a83840e146e43c0ec96a22ec1f392e0680e6c1226e6f3ba87e0740af850f",
+          "bytes": 1081
+        },
+        {
+          "name": "UNLICENSE",
+          "sha256": "7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c",
+          "bytes": 1211
+        }
+      ]
+    },
+    {
+      "name": "napi-derive-backend",
+      "version": "6.1.2",
+      "checksum": "df4056ac7c18e4438ccf0edaed4340ca0d269278c8ec19284f7b23cb039fd0ae",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "3f1ce66533302df3a32edbfdfc0b78f0dd34659e4c1f5817162e5ea3c2297215",
+          "bytes": 2138,
+          "upstream": {
+            "repository": "https://github.com/napi-rs/napi-rs",
+            "commit": "956e4525fea6a676ea3680b711382f167b899af9",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "napi-derive",
+      "version": "3.6.3",
+      "checksum": "0fa55ea69990c90b888e9e77044410e304ce7f35de599dc6d0b5c1923d2e59af",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "3f1ce66533302df3a32edbfdfc0b78f0dd34659e4c1f5817162e5ea3c2297215",
+          "bytes": 2138,
+          "upstream": {
+            "repository": "https://github.com/napi-rs/napi-rs",
+            "commit": "956e4525fea6a676ea3680b711382f167b899af9",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "napi-sys",
+      "version": "3.3.0",
+      "checksum": "85fbf1fa9f1babfe396d74bbbf52b3643770243e8f5b0b46715d4caf7f0dfc9a",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "3f1ce66533302df3a32edbfdfc0b78f0dd34659e4c1f5817162e5ea3c2297215",
+          "bytes": 2138,
+          "upstream": {
+            "repository": "https://github.com/napi-rs/napi-rs",
+            "commit": "679eb79f5cf3c7c6b2850f4ab46092126f23dc5c",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "napi",
+      "version": "3.12.2",
+      "checksum": "58c5f4d5375213fdb7be2655e152386e82f026f9a5ba36a75556e11359aafe09",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "3f1ce66533302df3a32edbfdfc0b78f0dd34659e4c1f5817162e5ea3c2297215",
+          "bytes": 2138,
+          "upstream": {
+            "repository": "https://github.com/napi-rs/napi-rs",
+            "commit": "444bf29b8534216dd1cec4695a71e5996a173e87",
+            "path": "LICENSE"
+          }
+        }
+      ]
+    },
+    {
+      "name": "nohash-hasher",
+      "version": "0.2.0",
+      "checksum": "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451",
+      "declaredLicense": "Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30",
+          "bytes": 11358
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "ec353d4fecf7963b4c054384557e5dbc3c7a717997eb4a3815b315721a6aa75a",
+          "bytes": 1069
+        }
+      ]
+    },
+    {
+      "name": "pin-project-lite",
+      "version": "0.2.17",
+      "checksum": "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd",
+      "declaredLicense": "Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
+          "bytes": 10174
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "proc-macro2",
+      "version": "1.0.106",
+      "checksum": "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "quote",
+      "version": "1.0.45",
+      "checksum": "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "rustc-hash",
+      "version": "2.1.2",
+      "checksum": "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe",
+      "declaredLicense": "Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "95bd3988beee069fa2848f648dab43cc6e0b2add2ad6bcb17360caf749802bcc",
+          "bytes": 9722
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652",
+          "bytes": 1022
+        }
+      ]
+    },
+    {
+      "name": "rustix",
+      "version": "1.1.4",
+      "checksum": "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190",
+      "declaredLicense": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64"],
+      "licenseFiles": [
+        {
+          "name": "COPYRIGHT",
+          "sha256": "377c2e7c53250cc5905c0b0532d35973392af16ffb9596a41d99d202cf3617c9",
+          "bytes": 853
+        },
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-Apache-2.0_WITH_LLVM-exception",
+          "sha256": "268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5",
+          "bytes": 12243
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "semver",
+      "version": "1.0.28",
+      "checksum": "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "serde",
+      "version": "1.0.228",
+      "checksum": "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "serde_core",
+      "version": "1.0.228",
+      "checksum": "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "serde_derive",
+      "version": "1.0.228",
+      "checksum": "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "serde_json",
+      "version": "1.0.150",
+      "checksum": "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "sha2",
+      "version": "0.10.9",
+      "checksum": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5",
+          "bytes": 10849
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1",
+          "bytes": 1138
+        }
+      ]
+    },
+    {
+      "name": "slab",
+      "version": "0.4.12",
+      "checksum": "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "8ce0830173fdac609dfb4ea603fdc002c2f4af0dc9b1a005653f5da9cf534b18",
+          "bytes": 1055
+        }
+      ]
+    },
+    {
+      "name": "syn",
+      "version": "2.0.117",
+      "checksum": "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "tar",
+      "version": "0.4.46",
+      "checksum": "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "8ca6b96cea9e67c6c5c63f452c31bd396db8bd2406231fdea5d48ef462b48077",
+          "bytes": 1070
+        }
+      ]
+    },
+    {
+      "name": "typenum",
+      "version": "1.20.1",
+      "checksum": "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "db11fec9946737df39ca3898d9cd8c10ec6f6c3a884a6802b0ad0b81b4e8f23a",
+          "bytes": 17
+        },
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "516b24e051bf5630880ebbd55c40a25ce9552ebaf8970a53e8976eb70e522406",
+          "bytes": 10835
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "a825bd853ab71619a4923d7b4311221427848070ff44d990da39b0b274c1683f",
+          "bytes": 1083
+        }
+      ]
+    },
+    {
+      "name": "unicode-ident",
+      "version": "1.0.24",
+      "checksum": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75",
+      "declaredLicense": "(MIT OR Apache-2.0) AND Unicode-3.0",
+      "selectedLicense": "MIT AND Unicode-3.0",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a",
+          "bytes": 9723
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        },
+        {
+          "name": "LICENSE-UNICODE",
+          "sha256": "f7db81051789b729fea528a63ec4c938fdcb93d9d61d97dc8cc2e9df6d47f2a1",
+          "bytes": 1995
+        }
+      ]
+    },
+    {
+      "name": "unicode-segmentation",
+      "version": "1.13.3",
+      "checksum": "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "COPYRIGHT",
+          "sha256": "23860c2a7b5d96b21569afedf033469bab9fe14a1b24a35068b8641c578ce24d",
+          "bytes": 321
+        },
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0",
+          "bytes": 1071
+        }
+      ]
+    },
+    {
+      "name": "winapi",
+      "version": "0.3.9",
+      "checksum": "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419",
+      "declaredLicense": "MIT/Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "b40930bbcf80744c86c46a12bc9da056641d722716c378f5659b9e555ef833e1",
+          "bytes": 11357
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "ce7bc3499fee93d5022ef430d5e4201e79a6d9154f3974e42f41349f0569e09b",
+          "bytes": 1073
+        }
+      ]
+    },
+    {
+      "name": "windows-link",
+      "version": "0.2.1",
+      "checksum": "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "license-apache-2.0",
+          "sha256": "c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b",
+          "bytes": 11351
+        },
+        {
+          "name": "license-mit",
+          "sha256": "c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383",
+          "bytes": 1141
+        }
+      ]
+    },
+    {
+      "name": "xattr",
+      "version": "1.6.1",
+      "checksum": "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-APACHE",
+          "sha256": "a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2",
+          "bytes": 10847
+        },
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "8b427f5bc501764575e52ba4f9d95673cf8f6d80a86d0d06599852e1a9a20a36",
+          "bytes": 1056
+        }
+      ]
+    },
+    {
+      "name": "zmij",
+      "version": "1.0.21",
+      "checksum": "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE-MIT",
+          "sha256": "23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3",
+          "bytes": 1023
+        }
+      ]
+    },
+    {
+      "name": "zstd-safe",
+      "version": "7.2.4",
+      "checksum": "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d",
+      "declaredLicense": "MIT OR Apache-2.0",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63",
+          "bytes": 18
+        },
+        {
+          "name": "LICENSE.Apache-2.0",
+          "sha256": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
+          "bytes": 10174
+        },
+        {
+          "name": "LICENSE.Mit",
+          "sha256": "129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8",
+          "bytes": 1080
+        }
+      ]
+    },
+    {
+      "name": "zstd-sys",
+      "version": "2.0.16+zstd.1.5.7",
+      "checksum": "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748",
+      "declaredLicense": "MIT/Apache-2.0",
+      "selectedLicense": "MIT AND BSD-3-Clause",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "a77b7cfeaf911ed410ffbe76f0cb2b24ad8a4d94e7ead5727e914425c416cc63",
+          "bytes": 18
+        },
+        {
+          "name": "LICENSE.Apache-2.0",
+          "sha256": "0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594",
+          "bytes": 10174
+        },
+        {
+          "name": "LICENSE.BSD-3-Clause",
+          "sha256": "48341f685c87304089aa099b23c386f8bacc519ef555aa7a13e239908907b3fd",
+          "bytes": 1595
+        },
+        {
+          "name": "LICENSE.Mit",
+          "sha256": "129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8",
+          "bytes": 1080
+        },
+        {
+          "name": "zstd/COPYING",
+          "sha256": "f9c375a1be4a41f7b70301dd83c91cb89e41567478859b77eef375a52d782505",
+          "bytes": 18091
+        },
+        {
+          "name": "zstd/LICENSE",
+          "sha256": "7055266497633c9025b777c78eb7235af13922117480ed5c674677adc381c9d8",
+          "bytes": 1549
+        }
+      ]
+    },
+    {
+      "name": "zstd",
+      "version": "0.13.3",
+      "checksum": "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a",
+      "declaredLicense": "MIT",
+      "selectedLicense": "MIT",
+      "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"],
+      "licenseFiles": [
+        {
+          "name": "LICENSE",
+          "sha256": "129e8edef29e9abcd2ebabe252f4ef1b1289cdca356bf0040284a2fbccfb96c8",
+          "bytes": 1080
+        }
+      ]
+    }
+  ]
+}
diff --git a/src/sdks/ts/node-addon/moon.yml b/src/sdks/ts/node-addon/moon.yml
new file mode 100644
index 000000000..674c0793f
--- /dev/null
+++ b/src/sdks/ts/node-addon/moon.yml
@@ -0,0 +1,181 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+
+id: "oliphaunt-node-direct"
+language: "rust"
+layer: "library"
+stack: "systems"
+tags: ["cargo-package", "rust", "runtime", "node", "native", "node-api", "release-product"]
+dependsOn:
+  - "liboliphaunt-native"
+  - "liboliphaunt-native-bindings"
+
+project:
+  title: "Oliphaunt Node Direct Runtime"
+  description: "Node-API native direct addon runtime consumed by the TypeScript SDK."
+  owner: "oliphaunt"
+  release:
+    component: "oliphaunt-node-direct"
+    packagePath: "src/sdks/ts/node-addon"
+    artifactTargets:
+      preset: "node-direct-addon"
+      targets:
+        - "linux-arm64-gnu"
+        - "linux-x64-gnu"
+        - "macos-arm64"
+        - "windows-x64-msvc"
+
+owners:
+  defaultOwner: "@oliphaunt/node-direct"
+
+fileGroups:
+  code:
+    - "src/**/*"
+    - "native/**/*"
+    - "Cargo.toml"
+    - "build.rs"
+    - "tools/**/*"
+    - "package.json"
+    - "packages/**/package.json"
+    - "dependency-licenses.json"
+    - "dependency-license-blobs/**/*"
+    - "/tools/packaging/rust-dependency-license-contract.mts"
+
+tasks:
+  dependency-license-audit:
+    tags: ["quality", "static", "requires-rust"]
+    command: "bash tools/packaging/audit-rust-dependency-licenses.sh src/sdks/ts/node-addon/tools/dependency-license-contract.mts oliphaunt-node-direct"
+    inputs:
+      - "@group(code)"
+      - "/Cargo.lock"
+      - "/**/Cargo.toml"
+      - "/tools/packaging/audit-rust-dependency-licenses.sh"
+      - "/tools/packaging/release-directory-safety.mts"
+    options:
+      runFromWorkspaceRoot: true
+
+  format:
+    command: "cargo fmt"
+    options:
+      cache: false
+      runInCI: false
+  format-check:
+    tags: ["quality", "static", "format", "requires-rust"]
+    command: "cargo fmt --check"
+    inputs: ["src/**/*", "build.rs"]
+  typecheck:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo check --locked"
+    inputs: ["@group(code)", "/Cargo.lock", "/Cargo.toml"]
+  lint:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["quality", "static", "requires-rust"]
+    command: "cargo clippy --all-targets --locked -- -D warnings"
+    inputs: ["@group(code)", "/Cargo.lock", "/Cargo.toml"]
+  test:
+    tags: ["quality", "unit"]
+    command: "bun test tools/check-release-assets.test.mts"
+    inputs:
+      - "@group(code)"
+      - "/tools/packaging/testdata/tar-fixture.mts"
+      - "@group(legal-files)"
+      - "@group(release-archive-contract)"
+  build:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["build", "requires-rust"]
+    command: "bash tools/build-native.sh"
+    inputs: ["@group(code)", "/Cargo.lock", "/Cargo.toml"]
+    outputs: ["/target/oliphaunt-node-direct/native/oliphaunt_node.node"]
+    options:
+      cache: false
+  test-built:
+    tags: ["quality", "integration", "requires-rust"]
+    command: "bash tools/test-node-addon-cleanup-lifecycle.sh target/oliphaunt-node-direct/native/oliphaunt_node.node"
+    deps: [{target: "cargo-sources", cacheStrategy: hash}, "build"]
+    inputs: ["@group(code)", "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"]
+    options:
+      cache: false
+
+  build-release-assets:
+    deps:
+      - target: cargo-sources
+        cacheStrategy: hash
+    tags: ["release", "artifact", "in-place-finalizer-input", "ci-node-direct"]
+    command: "bash src/sdks/ts/node-addon/tools/package-node-direct-runtime.sh"
+    inputs:
+      - "@group(code)"
+      - "/Cargo.lock"
+      - "/Cargo.toml"
+      - "/tools/dev/node-info.mts"
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
+      - "@group(legal-files)"
+      - "@group(release-archive-contract)"
+      - "/tools/release/artifact-target-matrix.mts"
+      - "/src/sdks/ts/node-addon/tools/check-release-assets.mts"
+      - "/tools/packaging/check-linux-consumer-baseline.sh"
+      - "/tools/packaging/linux-abi-baseline.test.sh"
+      - "/tools/release/platform-compatibility-policy.mts"
+      - "/tools/release/platform-compatibility-policy.test.mts"
+      - "/tools/packaging/platform-binary-contract.mts"
+      - "/tools/packaging/windows-vc-runtime-closure.mts"
+      - "/tools/packaging/strip-native-binaries.sh"
+      - "/tools/packaging/platform-binary-contract.test.mts"
+      - "/src/sdks/ts/node-addon/tools/package-node-direct-runtime.sh"
+      - "/tools/packaging/release-asset-validation.mts"
+      - "/src/extensions/contracts/extension-target-profiles.mts"
+      - "/tools/release/release-artifact-targets.mts"
+      - "/tools/release/query.mts"
+      - "/release-please-config.json"
+    outputs:
+      - "/target/oliphaunt-node-direct/release-assets/**/*"
+      - "/target/oliphaunt-node-direct/npm-packages/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+
+
+  finalize-release-assets:
+    tags: ["release", "artifact-package", "in-place-finalizer", "ci-node-direct-release-assets"]
+    command: "tools/dev/bun.sh src/sdks/ts/node-addon/tools/check-release-assets.mts --aggregate"
+    deps:
+      - "oliphaunt-node-direct:build-release-assets"
+    inputs:
+      - "@group(legal-files)"
+      - "/bunfig.toml"
+      - "@group(code)"
+      - "/src/runtimes/liboliphaunt-native/include/oliphaunt.h"
+      - "/tools/release/artifact-target-matrix.mts"
+      - "/tools/packaging/check-linux-consumer-baseline.sh"
+      - "/tools/packaging/finalize-helper-assets.mts"
+      - "/src/sdks/ts/node-addon/tools/check-release-assets.mts"
+      - "/tools/packaging/linux-abi-baseline.test.sh"
+      - "/tools/release/platform-compatibility-policy.mts"
+      - "/tools/release/platform-compatibility-policy.test.mts"
+      - "/tools/packaging/platform-binary-contract.mts"
+      - "/tools/packaging/strip-native-binaries.sh"
+      - "/tools/packaging/platform-binary-contract.test.mts"
+      - "/tools/packaging/release-asset-validation.mts"
+      - "/src/extensions/contracts/extension-target-profiles.mts"
+      - "/tools/release/release-artifact-targets.mts"
+      - "@group(release-archive-contract)"
+      - "/tools/release/query.mts"
+      - "/tools/packaging/write-checksum-manifest.mts"
+      - "/release-please-config.json"
+      - "/target/oliphaunt-node-direct/npm-packages/**/*"
+      - "/target/oliphaunt-node-direct/release-assets/**/*"
+    outputs:
+      - "/target/oliphaunt-node-direct/npm-packages/**/*"
+      - "/target/oliphaunt-node-direct/release-assets/**/*"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+
+  qualify:
+    tags: ["ci-node-direct"]
+    deps: ["build-release-assets", "test-built"]
diff --git a/src/runtimes/node-direct/native/node-addon/fixtures/fake_liboliphaunt.cc b/src/sdks/ts/node-addon/native/node-addon/fixtures/fake_liboliphaunt.cc
similarity index 80%
rename from src/runtimes/node-direct/native/node-addon/fixtures/fake_liboliphaunt.cc
rename to src/sdks/ts/node-addon/native/node-addon/fixtures/fake_liboliphaunt.cc
index 6534897ca..041aa6744 100644
--- a/src/runtimes/node-direct/native/node-addon/fixtures/fake_liboliphaunt.cc
+++ b/src/sdks/ts/node-addon/native/node-addon/fixtures/fake_liboliphaunt.cc
@@ -22,6 +22,7 @@ std::mutex g_log_mutex;
 std::condition_variable g_query_condition;
 OliphauntHandle g_handle;
 char g_last_error[256] = "";
+thread_local char g_operation_error[OLIPHAUNT_ERROR_CAPTURE_CAPACITY] = "";
 bool g_failed_detach_once = false;
 bool g_query_cancelled = false;
 bool g_query_active = false;
@@ -35,6 +36,18 @@ constexpr uint8_t kStreamUnknownWithoutCallback = 0xf6;
 
 void SetError(const char *message) {
   std::snprintf(g_last_error, sizeof(g_last_error), "%s", message);
+  std::snprintf(g_operation_error, sizeof(g_operation_error), "%s", message);
+}
+
+int32_t CaptureError(int32_t status, OliphauntErrorCapture *error) {
+  if (error != nullptr) {
+    std::memset(error, 0, sizeof(*error));
+    if (status != 0) {
+      error->length = static_cast(std::strlen(g_operation_error));
+      std::memcpy(error->message, g_operation_error, error->length);
+    }
+  }
+  return status;
 }
 
 void RecordEvent(const char *event) {
@@ -381,9 +394,25 @@ OLIPHAUNT_API int32_t oliphaunt_close_if_generation(uint64_t generation) {
   return 0;
 }
 
+OLIPHAUNT_API const OliphauntStaticExtension *liboliphaunt_selected_static_extensions(size_t *count) {
+  const char *mode = std::getenv("OLIPHAUNT_NODE_CLEANUP_TEST_REGISTRY");
+  static const OliphauntStaticExtension selected[] = {{}};
+  *count = mode == nullptr ? 0 : 1;
+  if (mode == nullptr) return nullptr;
+  RecordEvent("registry-selected");
+  return std::strcmp(mode, "null") == 0 ? nullptr : selected;
+}
+
 OLIPHAUNT_API int32_t oliphaunt_register_static_extensions(
     const OliphauntStaticExtension *,
     size_t) {
+  const char *mode = std::getenv("OLIPHAUNT_NODE_CLEANUP_TEST_REGISTRY");
+  if (mode != nullptr && std::strcmp(mode, "failure") == 0) {
+    RecordEvent("registry-rejected");
+    SetError("selected static registry rejected");
+    return -1;
+  }
+  RecordEvent("registry-registered");
   return 0;
 }
 
@@ -414,4 +443,51 @@ OLIPHAUNT_API void oliphaunt_free_response(OliphauntResponse *response) {
   response->len = 0;
 }
 
+// Match the current ABI consumed by the Rust bindings. Capture on the operation
+// thread, not later from the fixture's legacy process-wide last-error slot.
+OLIPHAUNT_API int32_t oliphaunt_init_with_error(
+    const OliphauntConfig *config, OliphauntHandle **out, OliphauntErrorCapture *error) {
+  g_operation_error[0] = '\0';
+  return CaptureError(oliphaunt_init(config, out), error);
+}
+
+OLIPHAUNT_API int32_t oliphaunt_exec_protocol_with_error(
+    OliphauntHandle *handle, const uint8_t *bytes, size_t length,
+    OliphauntResponse *out, OliphauntErrorCapture *error) {
+  g_operation_error[0] = '\0';
+  return CaptureError(oliphaunt_exec_protocol(handle, bytes, length, out), error);
+}
+
+OLIPHAUNT_API int32_t oliphaunt_exec_simple_query_with_error(
+    OliphauntHandle *handle, const char *sql, size_t length,
+    OliphauntResponse *out, OliphauntErrorCapture *error) {
+  g_operation_error[0] = '\0';
+  return CaptureError(oliphaunt_exec_simple_query(handle, sql, length, out), error);
+}
+
+OLIPHAUNT_API int32_t oliphaunt_exec_protocol_raw_stream_with_error(
+    OliphauntHandle *handle, const uint8_t *bytes, size_t length,
+    OliphauntStreamCallback callback, void *context, OliphauntErrorCapture *error) {
+  g_operation_error[0] = '\0';
+  return CaptureError(oliphaunt_exec_protocol_raw_stream(handle, bytes, length, callback, context), error);
+}
+
+OLIPHAUNT_API int32_t oliphaunt_backup_with_error(
+    OliphauntHandle *handle, OliphauntResponse *out, OliphauntErrorCapture *error) {
+  g_operation_error[0] = '\0';
+  return CaptureError(oliphaunt_backup(handle, out), error);
+}
+
+OLIPHAUNT_API int32_t oliphaunt_restore_with_error(
+    const OliphauntRestoreOptions *options, OliphauntErrorCapture *error) {
+  g_operation_error[0] = '\0';
+  return CaptureError(oliphaunt_restore(options), error);
+}
+
+OLIPHAUNT_API int32_t oliphaunt_detach_with_error(
+    OliphauntHandle *handle, OliphauntErrorCapture *error) {
+  g_operation_error[0] = '\0';
+  return CaptureError(oliphaunt_detach(handle), error);
+}
+
 }  // extern "C"
diff --git a/src/sdks/ts/node-addon/package.json b/src/sdks/ts/node-addon/package.json
new file mode 100644
index 000000000..55c44e94b
--- /dev/null
+++ b/src/sdks/ts/node-addon/package.json
@@ -0,0 +1,38 @@
+{
+  "name": "@oliphaunt/node-direct",
+  "version": "0.2.0",
+  "description": "Node-API native direct adapter for Oliphaunt.",
+  "license": "MIT",
+  "private": true,
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts/node-addon"
+  },
+  "oliphaunt": {
+    "liboliphauntVersion": "0.2.0"
+  },
+  "files": [
+    "native",
+    "packages",
+    "tools",
+    "README.md",
+    "CHANGELOG.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md"
+  ],
+  "engines": {
+    "node": ">=22.13 <25"
+  },
+  "scripts": {
+    "format": "cargo fmt",
+    "format-check": "cargo fmt --check",
+    "typecheck": "cargo check --locked",
+    "lint": "cargo clippy --all-targets --locked -- -D warnings",
+    "test": "bun test tools/check-release-assets.test.mts",
+    "build": "bash tools/build-native.sh",
+    "test-built": "bash tools/test-node-addon-cleanup-lifecycle.sh target/oliphaunt-node-direct/native/oliphaunt_node.node",
+    "dependency-license-audit": "bash ../../../../tools/packaging/audit-rust-dependency-licenses.sh src/sdks/ts/node-addon/tools/dependency-license-contract.mts oliphaunt-node-direct"
+  }
+}
diff --git a/src/runtimes/node-direct/packages/darwin-arm64/README.md b/src/sdks/ts/node-addon/packages/darwin-arm64/README.md
similarity index 100%
rename from src/runtimes/node-direct/packages/darwin-arm64/README.md
rename to src/sdks/ts/node-addon/packages/darwin-arm64/README.md
diff --git a/src/sdks/ts/node-addon/packages/darwin-arm64/package.json b/src/sdks/ts/node-addon/packages/darwin-arm64/package.json
new file mode 100644
index 000000000..443622b7e
--- /dev/null
+++ b/src/sdks/ts/node-addon/packages/darwin-arm64/package.json
@@ -0,0 +1,37 @@
+{
+  "name": "@oliphaunt/node-direct-darwin-arm64",
+  "version": "0.2.0",
+  "description": "macOS arm64 prebuilt Node-API native direct adapter for Oliphaunt.",
+  "license": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts/node-addon/packages/darwin-arm64"
+  },
+  "os": [
+    "darwin"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "macos-arm64"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "files": [
+    "prebuilds",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_LICENSES"
+  ],
+  "exports": {
+    "./oliphaunt_node.node": "./prebuilds/oliphaunt_node.node",
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/node-direct/packages/linux-arm64-gnu/README.md b/src/sdks/ts/node-addon/packages/linux-arm64-gnu/README.md
similarity index 100%
rename from src/runtimes/node-direct/packages/linux-arm64-gnu/README.md
rename to src/sdks/ts/node-addon/packages/linux-arm64-gnu/README.md
diff --git a/src/sdks/ts/node-addon/packages/linux-arm64-gnu/package.json b/src/sdks/ts/node-addon/packages/linux-arm64-gnu/package.json
new file mode 100644
index 000000000..18e827248
--- /dev/null
+++ b/src/sdks/ts/node-addon/packages/linux-arm64-gnu/package.json
@@ -0,0 +1,40 @@
+{
+  "name": "@oliphaunt/node-direct-linux-arm64-gnu",
+  "version": "0.2.0",
+  "description": "Linux arm64 glibc prebuilt Node-API native direct adapter for Oliphaunt.",
+  "license": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts/node-addon/packages/linux-arm64-gnu"
+  },
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "arm64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "linux-arm64-gnu"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "files": [
+    "prebuilds",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_LICENSES"
+  ],
+  "exports": {
+    "./oliphaunt_node.node": "./prebuilds/oliphaunt_node.node",
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/node-direct/packages/linux-x64-gnu/README.md b/src/sdks/ts/node-addon/packages/linux-x64-gnu/README.md
similarity index 100%
rename from src/runtimes/node-direct/packages/linux-x64-gnu/README.md
rename to src/sdks/ts/node-addon/packages/linux-x64-gnu/README.md
diff --git a/src/sdks/ts/node-addon/packages/linux-x64-gnu/package.json b/src/sdks/ts/node-addon/packages/linux-x64-gnu/package.json
new file mode 100644
index 000000000..553e93a92
--- /dev/null
+++ b/src/sdks/ts/node-addon/packages/linux-x64-gnu/package.json
@@ -0,0 +1,40 @@
+{
+  "name": "@oliphaunt/node-direct-linux-x64-gnu",
+  "version": "0.2.0",
+  "description": "Linux x64 glibc prebuilt Node-API native direct adapter for Oliphaunt.",
+  "license": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts/node-addon/packages/linux-x64-gnu"
+  },
+  "os": [
+    "linux"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "libc": [
+    "glibc"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "linux-x64-gnu"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "files": [
+    "prebuilds",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_LICENSES"
+  ],
+  "exports": {
+    "./oliphaunt_node.node": "./prebuilds/oliphaunt_node.node",
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/runtimes/node-direct/packages/win32-x64-msvc/README.md b/src/sdks/ts/node-addon/packages/win32-x64-msvc/README.md
similarity index 100%
rename from src/runtimes/node-direct/packages/win32-x64-msvc/README.md
rename to src/sdks/ts/node-addon/packages/win32-x64-msvc/README.md
diff --git a/src/sdks/ts/node-addon/packages/win32-x64-msvc/package.json b/src/sdks/ts/node-addon/packages/win32-x64-msvc/package.json
new file mode 100644
index 000000000..dbd6a0b19
--- /dev/null
+++ b/src/sdks/ts/node-addon/packages/win32-x64-msvc/package.json
@@ -0,0 +1,37 @@
+{
+  "name": "@oliphaunt/node-direct-win32-x64-msvc",
+  "version": "0.2.0",
+  "description": "Windows x64 MSVC prebuilt Node-API native direct adapter for Oliphaunt.",
+  "license": "MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts/node-addon/packages/win32-x64-msvc"
+  },
+  "os": [
+    "win32"
+  ],
+  "cpu": [
+    "x64"
+  ],
+  "optional": true,
+  "oliphaunt": {
+    "target": "windows-x64-msvc"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "files": [
+    "prebuilds",
+    "README.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "THIRD_PARTY_LICENSES"
+  ],
+  "exports": {
+    "./oliphaunt_node.node": "./prebuilds/oliphaunt_node.node",
+    "./package.json": "./package.json"
+  }
+}
diff --git a/src/sdks/ts/node-addon/release.toml b/src/sdks/ts/node-addon/release.toml
new file mode 100644
index 000000000..8889bb558
--- /dev/null
+++ b/src/sdks/ts/node-addon/release.toml
@@ -0,0 +1,16 @@
+id = "oliphaunt-node-direct"
+owner = "@oliphaunt/node-direct"
+kind = "runtime"
+publish_targets = ["npm", "github-release-assets"]
+registry_packages = [
+  "npm:@oliphaunt/node-direct-darwin-arm64",
+  "npm:@oliphaunt/node-direct-linux-x64-gnu",
+  "npm:@oliphaunt/node-direct-linux-arm64-gnu",
+  "npm:@oliphaunt/node-direct-win32-x64-msvc",
+]
+release_artifacts = ["node-api-prebuilds", "npm-optional-platform-packages"]
+
+[compatibility_versions.oliphaunt-node-direct-liboliphaunt]
+source_product = "liboliphaunt-native"
+path = "src/sdks/ts/node-addon/package.json"
+parser = "json:oliphaunt.liboliphauntVersion"
diff --git a/src/sdks/ts/node-addon/src/lib.rs b/src/sdks/ts/node-addon/src/lib.rs
new file mode 100644
index 000000000..d69e74851
--- /dev/null
+++ b/src/sdks/ts/node-addon/src/lib.rs
@@ -0,0 +1,627 @@
+use liboliphaunt_native_bindings::{
+    NativeCancel, NativeOpenOptions as PreparedOpenOptions, NativeSession, ProtocolStreamOutcome,
+};
+use napi::bindgen_prelude::*;
+use napi::threadsafe_function::{ThreadsafeCallContext, ThreadsafeFunctionCallMode};
+use napi::{Env, Error, Result, Status, Task};
+use napi_derive::napi;
+use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use std::sync::{Arc, Condvar, Mutex};
+
+fn native_error(error: impl std::fmt::Display) -> Error {
+    Error::from_reason(error.to_string())
+}
+fn validate_library_path(path: &str) -> Result<()> {
+    if path.is_empty() {
+        return Err(Error::from_reason("liboliphaunt path must not be empty"));
+    }
+    if path.contains('\0') {
+        return Err(Error::from_reason(
+            "liboliphaunt path must not contain a null byte",
+        ));
+    }
+    Ok(())
+}
+
+#[napi]
+pub struct NativeDatabase {
+    session: Arc>,
+    cancel: NativeCancel,
+    environment: Arc,
+    opening: Arc,
+}
+impl Drop for NativeDatabase {
+    fn drop(&mut self) {
+        // GC records recovery only; PostgreSQL detach belongs to the next
+        // asynchronous open, never to a JavaScript finalizer.
+        if self.opening.logical_active.load(Ordering::Acquire) {
+            self.opening.recovery_pending.store(true, Ordering::Release);
+        }
+    }
+}
+
+#[derive(Default)]
+struct StreamEnvironment {
+    closed: AtomicBool,
+    active: Mutex>>,
+}
+#[derive(Default)]
+struct Ack {
+    result: Mutex>>,
+    ready: Condvar,
+}
+impl Ack {
+    fn complete(&self, value: Result<()>) {
+        let mut slot = lock(&self.result);
+        if slot.is_none() {
+            *slot = Some(value);
+            self.ready.notify_one();
+        }
+    }
+    fn wait(&self) -> Result<()> {
+        let mut slot = lock(&self.result);
+        while slot.is_none() {
+            slot = self
+                .ready
+                .wait(slot)
+                .unwrap_or_else(|_| fatal("native callback synchronization failed"));
+        }
+        slot.take().unwrap()
+    }
+}
+
+#[napi(object)]
+pub struct OpenOptions {
+    pub library_path: String,
+    pub pgdata: String,
+    pub runtime_directory: Option,
+    pub module_directory: Option,
+    pub icu_data_directory: Option,
+    pub username: String,
+    pub database: String,
+    pub startup_args: Vec,
+}
+pub struct OpenTask {
+    options: OpenOptions,
+    opening: Arc,
+    recovery: Vec>,
+}
+impl Drop for OpenTask {
+    fn drop(&mut self) {
+        let mut state = lock(&self.opening.state);
+        if !state.0 {
+            state.0 = true;
+            self.opening.ready.notify_one();
+        }
+    }
+}
+#[derive(Clone)]
+pub struct Opened {
+    session: Arc>,
+    cancel: NativeCancel,
+}
+struct Opening {
+    state: Mutex<(bool, Option)>,
+    ready: Condvar,
+    environment: Arc,
+    recovery_pending: AtomicBool,
+    workers: Mutex>>,
+    owner: usize,
+    logical_active: AtomicBool,
+    pending: AtomicUsize,
+}
+thread_local! {static OPENINGS:std::cell::RefCell>>=Default::default();}
+#[napi]
+pub struct RecoveryToken {
+    opening: Arc,
+}
+#[napi]
+impl RecoveryToken {
+    #[napi]
+    pub fn queue(&self) -> bool {
+        if !self.opening.logical_active.load(Ordering::Acquire) {
+            return false;
+        }
+        self.opening.recovery_pending.store(true, Ordering::Release);
+        true
+    }
+}
+impl Task for OpenTask {
+    type Output = Opened;
+    type JsValue = NativeDatabase;
+    fn compute(&mut self) -> Result {
+        let result = (|| {
+            for opening in &self.recovery {
+                let opened = lock(&opening.state).1.clone();
+                if let Some(opened) = opened {
+                    opened
+                        .session
+                        .lock()
+                        .map_err(native_error)?
+                        .close()
+                        .map_err(|error| {
+                            native_error(format!(
+                                "could not recover the previous logical handle: {error}"
+                            ))
+                        })?;
+                }
+                opening.logical_active.store(false, Ordering::Release);
+                opening.recovery_pending.store(false, Ordering::Release);
+            }
+            NativeSession::open_prepared_inputs(PreparedOpenOptions {
+                library_path: Some(self.options.library_path.clone().into()),
+                pgdata: self.options.pgdata.clone().into(),
+                runtime_directory: self.options.runtime_directory.clone().map(Into::into),
+                module_directory: self.options.module_directory.clone().map(Into::into),
+                icu_data_directory: self.options.icu_data_directory.clone().map(Into::into),
+                username: self.options.username.clone(),
+                database: self.options.database.clone(),
+                startup_args: self.options.startup_args.clone(),
+            })
+            .map_err(native_error)
+            .map(|session| {
+                let cancel = session.cancel_handle();
+                Opened {
+                    session: Arc::new(Mutex::new(session)),
+                    cancel,
+                }
+            })
+        })();
+        self.opening
+            .logical_active
+            .store(result.is_ok(), Ordering::Release);
+        *lock(&self.opening.state) = (true, result.as_ref().ok().cloned());
+        self.opening.ready.notify_one();
+        result
+    }
+    fn resolve(&mut self, _env: Env, opened: Opened) -> Result {
+        Ok(NativeDatabase {
+            session: opened.session,
+            cancel: opened.cancel,
+            environment: self.opening.environment.clone(),
+            opening: self.opening.clone(),
+        })
+    }
+}
+
+enum StreamError {
+    Native(liboliphaunt_native_bindings::Error),
+    Js(Error),
+}
+impl From for StreamError {
+    fn from(value: liboliphaunt_native_bindings::Error) -> Self {
+        Self::Native(value)
+    }
+}
+impl StreamError {
+    fn into_napi(self) -> Error {
+        match self {
+            Self::Native(e) => native_error(e),
+            Self::Js(e) => e,
+        }
+    }
+}
+type Callback = Box std::result::Result<(), StreamError> + Send>;
+enum Operation {
+    Query(Vec),
+    SimpleQuery(String),
+    Backup,
+    Close,
+    Stream(Vec, Callback),
+}
+pub struct OperationTask {
+    session: Arc>,
+    operation: Operation,
+    environment: Arc,
+    opening: Arc,
+}
+impl Task for OperationTask {
+    type Output = Option>;
+    type JsValue = Either;
+    fn compute(&mut self) -> Result {
+        let mut session = self.session.lock().map_err(native_error)?;
+        if self.environment.closed.load(Ordering::Acquire) {
+            return Err(Error::new(Status::Closing, "JS environment closed"));
+        }
+        match &mut self.operation {
+            Operation::Query(bytes) => session
+                .exec_protocol_raw(bytes)
+                .map(Some)
+                .map_err(native_error),
+            Operation::Backup => session.backup().map(Some).map_err(native_error),
+            Operation::Close => {
+                let result = session.close().map(|_| None).map_err(native_error);
+                if result.is_err() {
+                    self.opening.logical_active.store(true, Ordering::Release);
+                }
+                result
+            }
+            Operation::SimpleQuery(sql) => session
+                .exec_simple_query(sql)
+                .map(Some)
+                .map_err(native_error),
+            Operation::Stream(bytes, callback) => {
+                match session.exec_protocol_raw_stream(bytes, callback.as_mut()) {
+                    ProtocolStreamOutcome::ReadyForQuery(result) => {
+                        result.map(|_| None).map_err(StreamError::into_napi)
+                    }
+                    ProtocolStreamOutcome::SessionStateUnknown(error) => Err(native_error(error)),
+                }
+            }
+        }
+    }
+    fn resolve(&mut self, env: Env, bytes: Self::Output) -> Result {
+        Ok(match bytes {
+            Some(bytes) => Either::A(js_bytes(&env, &bytes)?),
+            None => Either::B(()),
+        })
+    }
+}
+impl NativeDatabase {
+    fn task<'e>(&self, env: &'e Env, operation: Operation) -> Result> {
+        if !matches!(operation, Operation::Close)
+            && !self.opening.logical_active.load(Ordering::Acquire)
+        {
+            return Err(Error::from_reason("native session is closed"));
+        }
+        spawn(
+            env,
+            OperationTask {
+                session: self.session.clone(),
+                operation,
+                environment: self.environment.clone(),
+                opening: self.opening.clone(),
+            },
+            self.opening.clone(),
+        )
+    }
+}
+#[napi]
+impl NativeDatabase {
+    #[napi]
+    pub fn open(env: &Env, options: OpenOptions) -> Result> {
+        validate_library_path(&options.library_path)?;
+        let opening = register_cleanup(env, false)?;
+        let recovery = OPENINGS.with(|entries| {
+            let mut entries = entries.borrow_mut();
+            entries.retain(|entry| entry.strong_count() > 0);
+            let pending = entries
+                .iter()
+                .filter_map(std::sync::Weak::upgrade)
+                .filter(|entry| {
+                    entry.owner == opening.owner && entry.recovery_pending.load(Ordering::Acquire)
+                })
+                .collect();
+            entries.push(Arc::downgrade(&opening));
+            pending
+        });
+        spawn(
+            env,
+            OpenTask {
+                options,
+                opening: opening.clone(),
+                recovery,
+            },
+            opening,
+        )
+    }
+    #[napi]
+    pub fn query<'e>(&self, env: &'e Env, bytes: Uint8Array) -> Result> {
+        self.task(env, Operation::Query(bytes.to_vec()))
+    }
+    #[napi]
+    pub fn backup<'e>(&self, env: &'e Env) -> Result> {
+        self.task(env, Operation::Backup)
+    }
+    #[napi]
+    pub fn close<'e>(&self, env: &'e Env) -> Result> {
+        self.opening.logical_active.store(false, Ordering::Release);
+        let result = self.task(env, Operation::Close);
+        if result.is_err() {
+            self.opening.logical_active.store(true, Ordering::Release);
+        }
+        result
+    }
+    #[napi]
+    pub fn cancel(&self) -> Result<()> {
+        self.cancel.cancel().map_err(native_error)
+    }
+    #[napi]
+    pub fn recovery_token(&self) -> RecoveryToken {
+        RecoveryToken {
+            opening: self.opening.clone(),
+        }
+    }
+    #[napi]
+    pub fn stream<'e>(
+        &self,
+        env: &'e Env,
+        bytes: Uint8Array,
+        on_chunk: Function<'_, Uint8Array, Unknown<'static>>,
+    ) -> Result> {
+        let threadsafe = on_chunk
+            .build_threadsafe_function::>()
+            .max_queue_size::<1>()
+            .build_callback(|context: ThreadsafeCallContext>| {
+                js_bytes(&context.env, &context.value)
+            })?;
+        let environment = self.environment.clone();
+        let callback: Callback = Box::new(move |bytes| {
+            let ack = Arc::new(Ack::default());
+            {
+                let mut active = lock(&environment.active);
+                if environment.closed.load(Ordering::Acquire) {
+                    return Err(StreamError::Js(Error::new(
+                        Status::Closing,
+                        "JS environment closed",
+                    )));
+                }
+                *active = Some(ack.clone());
+            }
+            let callback_ack = ack.clone();
+            let status = threadsafe.call_with_return_value(
+                bytes.to_vec(), ThreadsafeFunctionCallMode::Blocking,
+                move |result, env| {
+                    let result=result.and_then(|value| {
+                        if matches!(value.get_type()?, napi::ValueType::Object | napi::ValueType::Function) {
+                            let object: Object = unsafe {value.cast()?};
+                            let then: Unknown=object.get_named_property("then")?;
+                            if then.get_type()? == napi::ValueType::Function {
+                                return Err(Error::from_reason("raw protocol stream callback must complete synchronously and must not return a Promise or thenable"));
+                            }
+                        }
+                        Ok(())
+                    });
+                    let result=result.map_err(|error| {
+                        if error.status == Status::PendingException {
+                            // The callback bridge may already have captured and
+                            // cleared its exception; preserve that retained value.
+                            let mut pending=false;
+                            unsafe {napi::sys::napi_is_exception_pending(env.raw(),&mut pending);}
+                            if !pending {return error;}
+                            let mut thrown=std::ptr::null_mut();
+                            let status=unsafe {napi::sys::napi_get_and_clear_last_exception(env.raw(), &mut thrown)};
+                            if status == napi::sys::Status::napi_ok && !thrown.is_null()
+                                && let Ok(value) = unsafe { Unknown::from_napi_value(env.raw(), thrown) } {
+                                return Error::from_unknown_without_coercion(value);
+                            }
+                        }
+                        error
+                    });
+                    callback_ack.complete(result);
+                    Ok(())
+                }
+            );
+            if status != Status::Ok {
+                ack.complete(Err(Error::new(status, "stream callback failed")));
+            }
+            let result = ack.wait();
+            lock(&environment.active).take();
+            result.map_err(StreamError::Js)
+        });
+        self.task(env, Operation::Stream(bytes.to_vec(), callback))
+    }
+}
+
+pub struct RestoreTask {
+    library: String,
+    destination: String,
+    bytes: Vec,
+}
+impl Task for RestoreTask {
+    type Output = ();
+    type JsValue = ();
+    fn compute(&mut self) -> Result<()> {
+        NativeSession::restore_from_library(
+            std::path::Path::new(&self.library),
+            std::path::Path::new(&self.destination),
+            &self.bytes,
+        )
+        .map_err(native_error)
+    }
+    fn resolve(&mut self, _env: Env, _: ()) -> Result<()> {
+        Ok(())
+    }
+}
+#[napi]
+pub fn restore(env: &Env, options: RestoreOptions) -> Result> {
+    validate_library_path(&options.library_path)?;
+    let opening = register_cleanup(env, true)?;
+    spawn(
+        env,
+        RestoreTask {
+            library: options.library_path,
+            destination: options.destination,
+            bytes: options.bytes.to_vec(),
+        },
+        opening,
+    )
+}
+
+fn js_bytes(env: &Env, bytes: &[u8]) -> Result {
+    // Reuse the current WASIX addon buffer contract, including napi 3.12.2 copy initialization.
+    let mut output = Uint8ArraySlice::copy_from(env, bytes)?;
+    unsafe { output.as_mut() }.copy_from_slice(bytes);
+    output.into_typed_array(env)
+}
+
+struct PendingWork(Arc);
+impl Drop for PendingWork {
+    fn drop(&mut self) {
+        let _state = lock(&self.0.state);
+        self.0.pending.fetch_sub(1, Ordering::AcqRel);
+        self.0.ready.notify_all();
+    }
+}
+fn spawn(env: &Env, mut task: T, opening: Arc) -> Result> {
+    let (deferred, promise) = env.create_deferred()?;
+    let failed = deferred.clone();
+    opening.pending.fetch_add(1, Ordering::AcqRel);
+    let pending = PendingWork(opening.clone());
+    let started = std::thread::Builder::new()
+        .name("oliphaunt-native".into())
+        .spawn(move || {
+            let result = task.compute();
+            deferred.resolve(move |env: Env| {
+                let resolved = match result {
+                    Ok(output) => task.resolve(env, output),
+                    Err(error) => task.reject(env, error),
+                };
+                task.finally(env)?;
+                resolved
+            });
+            drop(pending);
+        });
+    match started {
+        Ok(worker) => {
+            let mut workers = lock(&opening.workers);
+            let mut active = Vec::new();
+            for previous in workers.drain(..) {
+                if previous.is_finished() {
+                    previous
+                        .join()
+                        .unwrap_or_else(|_| fatal("native worker panicked"));
+                } else {
+                    active.push(previous);
+                }
+            }
+            active.push(worker);
+            *workers = active;
+        }
+        Err(error) => failed.reject(native_error(error)),
+    }
+    Ok(promise)
+}
+fn register_cleanup(env: &Env, initialized: bool) -> Result> {
+    let opening = Arc::new(Opening {
+        state: Mutex::new((initialized, None)),
+        ready: Condvar::new(),
+        environment: Arc::new(StreamEnvironment::default()),
+        recovery_pending: AtomicBool::new(false),
+        workers: Mutex::new(Vec::new()),
+        owner: env.raw() as usize,
+        logical_active: AtomicBool::new(false),
+        pending: AtomicUsize::new(0),
+    });
+    env.add_env_cleanup_hook(opening.clone(), cleanup_opening)?;
+    Ok(opening)
+}
+fn fatal(message: &str) -> ! {
+    unsafe {
+        napi::sys::napi_fatal_error(
+            c"oliphaunt".as_ptr(),
+            9,
+            message.as_ptr().cast(),
+            message.len() as isize,
+        );
+    }
+    std::process::abort()
+}
+fn lock(mutex: &Mutex) -> std::sync::MutexGuard<'_, T> {
+    mutex
+        .lock()
+        .unwrap_or_else(|_| fatal("native adapter synchronization failed"))
+}
+fn quiesce_opening(opening: Arc) {
+    opening.environment.closed.store(true, Ordering::Release);
+    if let Some(ack) = lock(&opening.environment.active).take() {
+        ack.complete(Err(Error::new(Status::Closing, "JS environment closed")));
+    }
+}
+
+// Cleanup runs on the terminating environment, after releasing callback waits.
+// Native operations need no JavaScript progress; competing opens fail immediately.
+// Join every worker before returning so no addon code outlives its environment.
+fn cleanup_opening(opening: Arc) {
+    quiesce_opening(opening.clone());
+    let mut state = lock(&opening.state);
+    while !state.0 || opening.pending.load(Ordering::Acquire) != 0 {
+        let cancel = state.1.as_ref().map(|opened| opened.cancel.clone());
+        drop(state);
+        if let Some(cancel) = cancel {
+            let _ = cancel.cancel();
+        }
+        state = lock(&opening.state);
+        if !state.0 || opening.pending.load(Ordering::Acquire) != 0 {
+            state = opening
+                .ready
+                .wait_timeout(state, std::time::Duration::from_millis(10))
+                .unwrap_or_else(|_| fatal("native cleanup synchronization failed"))
+                .0;
+        }
+    }
+    let opened = state.1.take();
+    drop(state);
+    for worker in lock(&opening.workers).drain(..) {
+        worker
+            .join()
+            .unwrap_or_else(|_| fatal("native worker panicked"));
+    }
+    if let Some(opened) = opened
+        && let Err(error) = lock(&opened.session).close_terminal_if_owned()
+    {
+        fatal(&error.to_string());
+    }
+}
+
+#[napi(object)]
+pub struct RestoreOptions {
+    pub library_path: String,
+    pub destination: String,
+    pub bytes: Uint8Array,
+}
+#[napi]
+pub fn open(env: &Env, options: OpenOptions) -> Result> {
+    NativeDatabase::open(env, options)
+}
+#[napi]
+pub fn exec_protocol_raw<'e>(
+    env: &'e Env,
+    handle: &NativeDatabase,
+    request: Uint8Array,
+) -> Result> {
+    handle.query(env, request)
+}
+#[napi]
+pub fn exec_simple_query<'e>(
+    env: &'e Env,
+    handle: &NativeDatabase,
+    sql: String,
+) -> Result> {
+    handle.task(env, Operation::SimpleQuery(sql))
+}
+#[napi]
+pub fn exec_protocol_raw_stream<'e>(
+    env: &'e Env,
+    handle: &NativeDatabase,
+    request: Uint8Array,
+    callback: Function<'_, Uint8Array, Unknown<'static>>,
+) -> Result> {
+    handle.stream(env, request, callback)
+}
+#[napi]
+pub fn backup<'e>(env: &'e Env, handle: &NativeDatabase) -> Result> {
+    handle.backup(env)
+}
+#[napi]
+pub fn cancel(handle: &NativeDatabase) -> Result<()> {
+    handle.cancel()
+}
+#[napi]
+pub fn detach<'e>(env: &'e Env, handle: &NativeDatabase) -> Result> {
+    handle.close(env)
+}
+#[napi]
+pub fn create_forgotten_handle_recovery_token(handle: &NativeDatabase) -> RecoveryToken {
+    handle.recovery_token()
+}
+#[napi]
+pub fn queue_forgotten_handle_recovery(token: &RecoveryToken) -> bool {
+    token.queue()
+}
+
+#[napi]
+pub fn version(library_path: String) -> Result {
+    validate_library_path(&library_path)?;
+    NativeSession::version_from_library(std::path::Path::new(&library_path)).map_err(native_error)
+}
diff --git a/src/sdks/ts/node-addon/tools/build-native.sh b/src/sdks/ts/node-addon/tools/build-native.sh
new file mode 100644
index 000000000..8bacce088
--- /dev/null
+++ b/src/sdks/ts/node-addon/tools/build-native.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+cd "$root"
+target="${CARGO_BUILD_TARGET:-$(rustc -vV | sed -n 's/^host: //p')}"
+profile="${OLIPHAUNT_NODE_ADDON_PROFILE:-release}"
+out="${1:-$root/target/oliphaunt-node-direct/native}"
+case "$target" in
+  *-apple-darwin) artifact=liboliphaunt_node_direct.dylib; export MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" ;;
+  *-windows-msvc) artifact=oliphaunt_node_direct.dll ;;
+  *-linux-gnu) artifact=liboliphaunt_node_direct.so ;;
+  *) echo "unsupported native addon target: $target" >&2; exit 2 ;;
+esac
+cargo build --locked -p oliphaunt-node-direct --target "$target" --profile "$profile"
+if [[ "$profile" == dev ]]; then profile=debug; fi
+mkdir -p "$out"
+cp "${CARGO_TARGET_DIR:-$root/target}/$target/$profile/$artifact" "$out/oliphaunt_node.node"
diff --git a/src/sdks/ts/node-addon/tools/check-carriers.mts b/src/sdks/ts/node-addon/tools/check-carriers.mts
new file mode 100644
index 000000000..6fe2fd368
--- /dev/null
+++ b/src/sdks/ts/node-addon/tools/check-carriers.mts
@@ -0,0 +1,153 @@
+#!/usr/bin/env bun
+import path from 'node:path';
+import {
+  ROOT,
+  compareText,
+  currentProductVersionSync,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  TOOL,
+  artifactNpmPackageTargets,
+  copyStagedRuntimeAssets,
+  fail,
+  isDirectory,
+  isFile,
+  rel,
+  safeNpmPackageFilenamePrefix,
+} from '../../../../../tools/packaging/release-carrier.mts';
+import { readdirSync } from 'node:fs';
+import { writeChecksumManifest } from '../../../../../tools/packaging/write-checksum-manifest.mts';
+import { checkNodeDirectReleaseAssets } from './check-release-assets.mts';
+import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts';
+
+export const NODE_DIRECT_PRODUCT = 'oliphaunt-node-direct';
+
+const NODE_DIRECT_KIND = 'node-direct-addon';
+
+const NODE_DIRECT_PACKAGE_ROOT = path.join(ROOT, 'src/sdks/ts/node-addon/packages');
+
+function hasNodeDirectReleaseArchive(assetDir) {
+  if (!isDirectory(assetDir)) {
+    return false;
+  }
+  return readdirSync(assetDir).some(
+    (name) =>
+      name.startsWith('oliphaunt-node-direct-') &&
+      (name.endsWith('.tar.gz') || name.endsWith('.zip')),
+  );
+}
+
+async function ensureNodeDirectReleaseAssets() {
+  const assetDir = path.join(ROOT, 'target/oliphaunt-node-direct/release-assets');
+  if (!hasNodeDirectReleaseArchive(assetDir)) {
+    copyStagedRuntimeAssets({
+      product: NODE_DIRECT_PRODUCT,
+      destination: assetDir,
+      envName: 'OLIPHAUNT_NODE_ADDON_ASSET_INPUT_DIRS',
+      patterns: ['oliphaunt-node-direct-*.tar.gz', 'oliphaunt-node-direct-*.zip'],
+    });
+  }
+  const version = currentProductVersionSync(NODE_DIRECT_PRODUCT, TOOL);
+  await writeChecksumManifest([
+    '--asset-dir',
+    rel(assetDir),
+    '--output',
+    `oliphaunt-node-direct-${version}-release-assets.sha256`,
+    '--pattern',
+    'oliphaunt-node-direct-*.tar.gz',
+    '--pattern',
+    'oliphaunt-node-direct-*.zip',
+  ]);
+  await checkNodeDirectReleaseAssets(['--asset-dir', rel(assetDir)]);
+}
+
+function nodeDirectOptionalPackageTargets(version) {
+  return artifactNpmPackageTargets({
+    product: NODE_DIRECT_PRODUCT,
+    kind: NODE_DIRECT_KIND,
+    surface: 'npm-optional',
+    packageRoot: NODE_DIRECT_PACKAGE_ROOT,
+    version,
+  });
+}
+
+function nodeDirectNpmPackageDir() {
+  return path.join(ROOT, 'target/oliphaunt-node-direct/npm-packages');
+}
+
+function expectedNodeDirectNpmTarball(packageName, version) {
+  return path.join(
+    nodeDirectNpmPackageDir(),
+    `${safeNpmPackageFilenamePrefix(packageName)}-${version}.tgz`,
+  );
+}
+
+async function validateNodeDirectOptionalTarball(packageName, version, tarball) {
+  if (!isFile(tarball)) {
+    fail(`missing Node direct optional npm package artifact: ${rel(tarball)}`);
+  }
+  let entries;
+  try {
+    entries = readPortableArchiveEntries(tarball);
+  } catch (error) {
+    fail(`${rel(tarball)} is not a valid Node direct optional npm tarball: ${error.message}`);
+  }
+  for (const required of ['package/package.json', 'package/prebuilds/oliphaunt_node.node']) {
+    if (!entries.has(required)) {
+      fail(`${rel(tarball)} is missing ${required}`);
+    }
+  }
+  const prebuild = entries.get('package/prebuilds/oliphaunt_node.node');
+  if (!prebuild.isFile || prebuild.size <= 0) {
+    fail(`${rel(tarball)} prebuilt addon must be a non-empty regular file`);
+  }
+  let packageJson;
+  try {
+    const packageData = entries.get('package/package.json')?.data() ?? null;
+    if (packageData === null) {
+      fail(`${rel(tarball)} package/package.json could not be read`);
+    }
+    packageJson = JSON.parse(packageData.toString('utf8'));
+  } catch (error) {
+    fail(`${rel(tarball)} package/package.json is not valid JSON: ${error.message}`);
+  }
+  if (packageJson.name !== packageName) {
+    fail(
+      `${rel(tarball)} package name must be ${packageName}, got ${JSON.stringify(packageJson.name)}`,
+    );
+  }
+  if (packageJson.version !== version) {
+    fail(
+      `${rel(tarball)} package version must be ${version}, got ${JSON.stringify(packageJson.version)}`,
+    );
+  }
+}
+
+export async function nodeDirectOptionalNpmTarballs(version) {
+  const tarballs = [];
+  for (const [packageName] of nodeDirectOptionalPackageTargets(version)) {
+    const tarball = expectedNodeDirectNpmTarball(packageName, version);
+    await validateNodeDirectOptionalTarball(packageName, version, tarball);
+    tarballs.push([packageName, tarball]);
+  }
+  const expected = new Set(tarballs.map(([, tarball]) => path.resolve(tarball)));
+  const unexpected = isDirectory(nodeDirectNpmPackageDir())
+    ? readdirSync(nodeDirectNpmPackageDir())
+        .filter((name) => name.endsWith('.tgz'))
+        .map((name) => path.join(nodeDirectNpmPackageDir(), name))
+        .filter((file) => !expected.has(path.resolve(file)))
+        .map((file) => path.basename(file))
+        .sort(compareText)
+    : [];
+  if (unexpected.length > 0) {
+    fail(`unexpected Node direct optional npm package artifact(s): ${unexpected.join(', ')}`);
+  }
+  return tarballs;
+}
+
+export async function packageNodeDirectCarriers() {
+  await ensureNodeDirectReleaseAssets();
+  await nodeDirectOptionalNpmTarballs(currentProductVersionSync(NODE_DIRECT_PRODUCT, TOOL));
+}
+
+if (import.meta.main) await packageNodeDirectCarriers();
diff --git a/src/sdks/ts/node-addon/tools/check-release-assets.mts b/src/sdks/ts/node-addon/tools/check-release-assets.mts
new file mode 100644
index 000000000..84b4b2774
--- /dev/null
+++ b/src/sdks/ts/node-addon/tools/check-release-assets.mts
@@ -0,0 +1,283 @@
+#!/usr/bin/env bun
+import {
+  RUST_PAYLOAD_LICENSE,
+  assertRustDependencyLicensesInEntries,
+} from './dependency-license-contract.mts';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { finalizeHelperAssets } from '../../../../../tools/packaging/finalize-helper-assets.mts';
+import { inspectPlatformBinaryEntries } from '../../../../../tools/packaging/platform-binary-contract.mts';
+import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  assertFileExists,
+  checksumManifest,
+  readArchiveEntries,
+  sha256,
+} from '../../../../../tools/packaging/release-asset-validation.mts';
+import { assertReleaseNoticesInEntries } from '../../../../../tools/packaging/release-notices.mts';
+import {
+  artifactTargets,
+  compareText,
+  currentProductVersion,
+  expectedAssets,
+  fail,
+  ROOT,
+} from '../../../../../tools/release/release-artifact-targets.mts';
+
+const PREFIX = 'check-node-direct-release-assets.mts';
+const PRODUCT = 'oliphaunt-node-direct';
+const KIND = 'node-direct-addon';
+const NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' });
+const NOTICE_MEMBERS = Object.freeze(['LICENSE', 'THIRD_PARTY_NOTICES.md', 'THIRD_PARTY_LICENSES']);
+const PACKAGE_LICENSE = RUST_PAYLOAD_LICENSE;
+
+function parseArgs(argv) {
+  const args = {
+    assetDir: path.join(ROOT, 'target/oliphaunt-node-direct/release-assets'),
+    allowPartial: false,
+    npmPackages: [],
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const arg = argv[index];
+    if (arg === '--asset-dir') {
+      const value = argv[index + 1];
+      if (!value) {
+        fail(PREFIX, '--asset-dir requires a value');
+      }
+      args.assetDir = path.resolve(value);
+      index += 1;
+    } else if (arg === '--allow-partial') {
+      args.allowPartial = true;
+    } else if (arg === '--npm-package') {
+      const value = argv[index + 1];
+      if (!value) {
+        fail(PREFIX, '--npm-package requires a value');
+      }
+      args.npmPackages.push(path.resolve(value));
+      index += 1;
+    } else {
+      fail(PREFIX, `unknown argument ${arg}`);
+    }
+  }
+  return args;
+}
+
+export function assertNodeDirectReleaseNoticeEntries(
+  entries,
+  { prefix = '', label = 'Node direct archive' } = {},
+) {
+  const rustRoot = `${prefix ? prefix + '/' : ''}THIRD_PARTY_LICENSES/rust`;
+  const sourceEntries = new Map(
+    [...entries].filter(([name]) => name !== rustRoot && !name.startsWith(rustRoot + '/')),
+  );
+  return assertReleaseNoticesInEntries(sourceEntries, {
+    ...NOTICE_OPTIONS,
+    prefix,
+    label,
+  });
+}
+
+function archiveJson(entries, member, label) {
+  const entry = entries.get(member);
+  if (!entry?.isFile || entry.isSymbolicLink) {
+    throw new Error(`${label} is missing regular member ${member}`);
+  }
+  if ((entry.mode & 0o444) !== 0o444 || (entry.mode & 0o7000) !== 0) {
+    throw new Error(
+      `${label} member ${member} must be readable by all users without special permission bits`,
+    );
+  }
+  try {
+    return JSON.parse(Buffer.from(entry.data()).toString('utf8'));
+  } catch (cause) {
+    throw new Error(`${label} member ${member} must contain valid JSON: ${cause.message}`);
+  }
+}
+
+export function assertNodeDirectNpmArchive(file, targets, version) {
+  const label = path.basename(file);
+  const entries = readArchiveEntriesForNotices(file, label);
+  assertNodeDirectReleaseNoticeEntries(entries, { prefix: 'package', label });
+  const manifest = archiveJson(entries, 'package/package.json', label);
+  const target = targets.find((candidate) => candidate.npmPackage === manifest.name);
+  if (!target) {
+    throw new Error(
+      `${label} package name is not a published Node direct carrier: ${JSON.stringify(manifest.name)}`,
+    );
+  }
+  assertRustDependencyLicensesInEntries(entries, {
+    target: target.target,
+    prefix: 'package',
+    label,
+  });
+  if (manifest.version !== version) {
+    throw new Error(
+      `${label} package version must be ${version}, got ${JSON.stringify(manifest.version)}`,
+    );
+  }
+  if (manifest.license !== PACKAGE_LICENSE) {
+    throw new Error(
+      `${label} package license must be ${PACKAGE_LICENSE}, got ${JSON.stringify(manifest.license)}`,
+    );
+  }
+  if (manifest.oliphaunt?.target !== target.target) {
+    throw new Error(
+      `${label} package target must be ${target.target}, got ${JSON.stringify(manifest.oliphaunt?.target)}`,
+    );
+  }
+  if (!Array.isArray(manifest.files)) {
+    throw new Error(`${label} package.json must declare an npm files allowlist`);
+  }
+  if (
+    manifest.files.some((member) => typeof member !== 'string' || member.length === 0) ||
+    new Set(manifest.files).size !== manifest.files.length
+  ) {
+    throw new Error(
+      `${label} package.json npm files allowlist must contain unique non-empty strings`,
+    );
+  }
+  for (const member of NOTICE_MEMBERS) {
+    if (!manifest.files.includes(member)) {
+      throw new Error(`${label} package.json npm files allowlist must include ${member}`);
+    }
+  }
+  const prebuild = entries.get('package/prebuilds/oliphaunt_node.node');
+  if (!prebuild?.isFile || prebuild.isSymbolicLink || prebuild.size === 0) {
+    throw new Error(
+      `${label} is missing a non-empty regular package/prebuilds/oliphaunt_node.node`,
+    );
+  }
+  if (target.target === 'windows-x64-msvc') {
+    inspectPlatformBinaryEntries(
+      [...entries].map(([name, entry]) => ({ name, ...entry })),
+      { target: target.target, rootLabel: label },
+    );
+  }
+  return manifest;
+}
+
+function readArchiveEntriesForNotices(file, label) {
+  try {
+    return readPortableArchiveEntries(file);
+  } catch (error) {
+    throw new Error(`${label} is not a valid portable archive: ${error.message}`);
+  }
+}
+
+async function validateArchive(file, target) {
+  const entries = await readArchiveEntries(file, fail, PREFIX, 'Node direct');
+  try {
+    assertNodeDirectReleaseNoticeEntries(entries, { label: path.basename(file) });
+    assertRustDependencyLicensesInEntries(entries, {
+      target: target.target,
+      label: path.basename(file),
+    });
+  } catch (error) {
+    fail(PREFIX, error.message);
+  }
+  const memberName = target.libraryRelativePath;
+  if (!entries.has(memberName)) {
+    fail(PREFIX, `${path.basename(file)} is missing ${memberName}`);
+  }
+  const member = entries.get(memberName);
+  if (!member.isFile) {
+    fail(PREFIX, `${path.basename(file)} ${memberName} is not a regular file`);
+  }
+  if (member.size === 0) {
+    fail(PREFIX, `${path.basename(file)} ${memberName} is empty`);
+  }
+  inspectPlatformBinaryEntries(
+    [...entries].map(([name, entry]) => ({ name, ...entry })),
+    { target: target.target, rootLabel: path.basename(file) },
+  );
+}
+
+export async function checkNodeDirectReleaseAssets(argv) {
+  if (argv.includes('--aggregate'))
+    argv = await finalizeHelperAssets(PRODUCT, KIND, argv, {
+      assetDir:
+        process.env.OLIPHAUNT_NODE_ADDON_ASSET_OUT_DIR ??
+        path.join(ROOT, 'target/oliphaunt-node-direct/release-assets'),
+      npmPackageDir:
+        process.env.OLIPHAUNT_NODE_ADDON_NPM_PACKAGE_OUT_DIR ??
+        path.join(ROOT, 'target/oliphaunt-node-direct/npm-packages'),
+    });
+  const args = parseArgs(argv);
+  const version = await currentProductVersion(PRODUCT, PREFIX);
+  const requiredAssets = expectedAssets(PRODUCT, KIND, version, PREFIX);
+  const targets = artifactTargets(PRODUCT, KIND, PREFIX);
+  const targetsByAsset = new Map(
+    targets.map((target) => [target.asset.replaceAll('{version}', version), target]),
+  );
+  const missing = [];
+  for (const asset of requiredAssets) {
+    if (!(await assertFileExists(path.join(args.assetDir, asset)))) {
+      missing.push(asset);
+    }
+  }
+  if (missing.length > 0) {
+    if (!args.allowPartial) {
+      fail(PREFIX, `missing oliphaunt-node-direct release asset(s): ${missing.join(', ')}`);
+    }
+    let presentAddons = 0;
+    for (const target of targets) {
+      if (
+        await assertFileExists(
+          path.join(args.assetDir, target.asset.replaceAll('{version}', version)),
+        )
+      ) {
+        presentAddons += 1;
+      }
+    }
+    if (presentAddons === 0) {
+      fail(
+        PREFIX,
+        'partial oliphaunt-node-direct release asset validation requires at least one addon asset',
+      );
+    }
+  }
+
+  const checksumAsset = `oliphaunt-node-direct-${version}-release-assets.sha256`;
+  const checksumPath = path.join(args.assetDir, checksumAsset);
+  if (!(await assertFileExists(checksumPath))) {
+    fail(PREFIX, `missing checksum manifest: ${checksumAsset}`);
+  }
+  const checksums = await checksumManifest(checksumPath, fail, PREFIX);
+  for (const asset of requiredAssets.sort(compareText)) {
+    const assetPath = path.join(args.assetDir, asset);
+    if (args.allowPartial && !(await assertFileExists(assetPath))) {
+      continue;
+    }
+    if (asset === checksumAsset) {
+      continue;
+    }
+    const expected = checksums.get(asset);
+    if (!expected) {
+      fail(PREFIX, `${checksumAsset} does not cover ${asset}`);
+    }
+    const actual = await sha256(assetPath);
+    if (actual !== expected) {
+      fail(PREFIX, `checksum mismatch for ${asset}: expected ${expected}, got ${actual}`);
+    }
+  }
+  for (const [asset, target] of targetsByAsset) {
+    const assetPath = path.join(args.assetDir, asset);
+    if (args.allowPartial && !(await assertFileExists(assetPath))) {
+      continue;
+    }
+    await validateArchive(assetPath, target);
+  }
+  for (const npmPackage of args.npmPackages) {
+    try {
+      assertNodeDirectNpmArchive(npmPackage, targets, version);
+    } catch (error) {
+      fail(PREFIX, error.message);
+    }
+  }
+  console.log(`oliphaunt-node-direct release assets validated: ${args.assetDir}`);
+}
+
+const invoked = process.argv[1] ? path.resolve(process.argv[1]) : '';
+if (invoked === fileURLToPath(import.meta.url)) {
+  await checkNodeDirectReleaseAssets(Bun.argv.slice(2));
+}
diff --git a/src/sdks/ts/node-addon/tools/check-release-assets.test.mts b/src/sdks/ts/node-addon/tools/check-release-assets.test.mts
new file mode 100644
index 000000000..fb603c96c
--- /dev/null
+++ b/src/sdks/ts/node-addon/tools/check-release-assets.test.mts
@@ -0,0 +1,165 @@
+import assert from 'node:assert/strict';
+import {
+  chmodSync,
+  mkdirSync,
+  mkdtempSync,
+  readFileSync,
+  realpathSync,
+  renameSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { gzipSync } from 'node:zlib';
+
+import { archiveDirectory as writeArchive } from '../../../../../tools/packaging/archive-directory.mts';
+import { createDeterministicTar } from '../../../../../tools/packaging/cargo-source-package.mts';
+import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts';
+import { stageReleaseNotices } from '../../../../../tools/packaging/release-notices.mts';
+import {
+  assertNodeDirectNpmArchive,
+  assertNodeDirectReleaseNoticeEntries,
+} from './check-release-assets.mts';
+import {
+  assertRustDependencyLicensesInEntries,
+  RUST_PAYLOAD_LICENSE,
+  rustDependencyLicenseMembers,
+  stageRustDependencyLicenses,
+} from './dependency-license-contract.mts';
+
+const ROOT = path.resolve(import.meta.dirname, '../../../../..');
+const TARGET = Object.freeze({
+  npmPackage: '@oliphaunt/node-direct-linux-x64-gnu',
+  target: 'linux-x64-gnu',
+});
+
+function fixture(t) {
+  const root = realpathSync(mkdtempSync(path.join(tmpdir(), 'node-direct-notices-test-')));
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+  return root;
+}
+
+async function archiveDirectory(source, output, { keepParent = false } = {}) {
+  const archive =
+    output.endsWith('.tar.gz') || output.endsWith('.zip') ? output : `${output}.tar.gz`;
+  await writeArchive(source, archive, { keepParent });
+  if (archive !== output) renameSync(archive, output);
+}
+
+function stageNpmPackage(root) {
+  const packageDir = path.join(root, 'package');
+  mkdirSync(path.join(packageDir, 'prebuilds'), { recursive: true });
+  const manifest = JSON.parse(
+    readFileSync(
+      path.join(ROOT, 'src/sdks/ts/node-addon/packages/linux-x64-gnu/package.json'),
+      'utf8',
+    ),
+  );
+  writeFileSync(path.join(packageDir, 'package.json'), `${JSON.stringify(manifest, null, 2)}\n`);
+  writeFileSync(path.join(packageDir, 'prebuilds/oliphaunt_node.node'), 'fixture-addon\n');
+  stageReleaseNotices(packageDir, { profile: 'source-sdk' });
+  stageRustDependencyLicenses(packageDir, TARGET.target);
+  return { manifest, packageDir };
+}
+
+test('Node direct addon and npm carriers preserve source and compiled dependency licenses', async (t) => {
+  const root = fixture(t);
+  const addonStage = path.join(root, 'addon');
+  mkdirSync(addonStage);
+  writeFileSync(path.join(addonStage, 'oliphaunt_node.node'), 'fixture-addon\n');
+  stageReleaseNotices(addonStage, { profile: 'source-sdk' });
+  stageRustDependencyLicenses(addonStage, TARGET.target);
+  const addonArchive = path.join(root, 'addon.tar.gz');
+  await archiveDirectory(addonStage, addonArchive);
+  assert.deepEqual(
+    assertNodeDirectReleaseNoticeEntries(readPortableArchiveEntries(addonArchive), {
+      label: path.basename(addonArchive),
+    }),
+    ['LICENSE', 'THIRD_PARTY_NOTICES.md'],
+  );
+  const addonZip = path.join(root, 'addon.zip');
+  await archiveDirectory(addonStage, addonZip);
+  assert.deepEqual(
+    assertNodeDirectReleaseNoticeEntries(readPortableArchiveEntries(addonZip), {
+      label: path.basename(addonZip),
+    }),
+    ['LICENSE', 'THIRD_PARTY_NOTICES.md'],
+  );
+
+  for (const file of [addonArchive, addonZip]) {
+    assertRustDependencyLicensesInEntries(readPortableArchiveEntries(file), {
+      target: TARGET.target,
+      label: file,
+    });
+  }
+  const { manifest: sourceManifest, packageDir } = stageNpmPackage(root);
+  const npmArchive = path.join(root, 'node-direct.tgz');
+  await archiveDirectory(packageDir, npmArchive, { keepParent: true });
+  const manifest = assertNodeDirectNpmArchive(npmArchive, [TARGET], sourceManifest.version);
+  assert.equal(manifest.license, RUST_PAYLOAD_LICENSE);
+});
+
+test('Node direct npm validation rejects notice drift and runtime-license carryover', async (t) => {
+  const root = fixture(t);
+  let staged = stageNpmPackage(path.join(root, 'byte-drift'));
+  writeFileSync(path.join(staged.packageDir, 'LICENSE'), 'not canonical\n');
+  let archive = path.join(root, 'byte-drift.tgz');
+  await archiveDirectory(staged.packageDir, archive, { keepParent: true });
+  assert.throws(
+    () => assertNodeDirectNpmArchive(archive, [TARGET], staged.manifest.version),
+    /differs byte-for-byte/u,
+  );
+
+  staged = stageNpmPackage(path.join(root, 'stale-runtime'));
+  writeFileSync(
+    path.join(staged.packageDir, 'package.json'),
+    `${JSON.stringify(staged.manifest, null, 2)}\n`,
+  );
+  rmSync(path.join(staged.packageDir, 'THIRD_PARTY_LICENSES/rust'), { recursive: true });
+  stageReleaseNotices(staged.packageDir, { profile: 'native-runtime' });
+  archive = path.join(root, 'stale-runtime.tgz');
+  await archiveDirectory(staged.packageDir, archive, { keepParent: true });
+  assert.throws(
+    () => assertNodeDirectNpmArchive(archive, [TARGET], staged.manifest.version),
+    /unexpected (?:product notice|release license)/u,
+  );
+
+  staged = stageNpmPackage(path.join(root, 'mode-drift'));
+  chmodSync(path.join(staged.packageDir, 'THIRD_PARTY_NOTICES.md'), 0o755);
+  archive = path.join(root, 'mode-drift.tgz');
+  await archiveDirectory(staged.packageDir, archive, { keepParent: true });
+  assertNodeDirectNpmArchive(archive, [TARGET], staged.manifest.version);
+  for (const mode of [0o666, 0o777]) {
+    writeFileSync(
+      archive,
+      gzipSync(
+        createDeterministicTar(staged.packageDir, 'package', {
+          fixedFileMode: mode,
+        }),
+      ),
+    );
+    assertNodeDirectNpmArchive(archive, [TARGET], staged.manifest.version);
+  }
+});
+
+test('Node direct npm rejects missing and modified compiled dependency licenses', async (t) => {
+  const root = fixture(t);
+  for (const mutation of ['missing', 'modified']) {
+    const { manifest, packageDir } = stageNpmPackage(path.join(root, mutation));
+    const member = rustDependencyLicenseMembers(TARGET.target).find((name) =>
+      name.includes('/licenses/'),
+    );
+    assert.ok(member);
+    const file = path.join(packageDir, member);
+    if (mutation === 'missing') rmSync(file);
+    else writeFileSync(file, 'wrong copyright holder\n');
+    const archive = path.join(root, mutation + '.tgz');
+    await archiveDirectory(packageDir, archive, { keepParent: true });
+    assert.throws(
+      () => assertNodeDirectNpmArchive(archive, [TARGET], manifest.version),
+      /(?:missing regular dependency license|differs from canonical bytes)/u,
+    );
+  }
+});
diff --git a/src/sdks/ts/node-addon/tools/dependency-license-contract.mts b/src/sdks/ts/node-addon/tools/dependency-license-contract.mts
new file mode 100644
index 000000000..e354e3f46
--- /dev/null
+++ b/src/sdks/ts/node-addon/tools/dependency-license-contract.mts
@@ -0,0 +1,21 @@
+#!/usr/bin/env bun
+import { createRustDependencyLicenseContract } from '../../../../../tools/packaging/rust-dependency-license-contract.mts';
+
+const contract = createRustDependencyLicenseContract({
+  owner: 'src/sdks/ts/node-addon',
+  product: 'oliphaunt-node-direct',
+  payloadLicense: 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause',
+});
+
+export const {
+  RUST_DEPENDENCY_LICENSE_ROOT,
+  RUST_PAYLOAD_LICENSE,
+  loadRustDependencyLicenseContract,
+  rustDependencyLicenseMembers,
+  stageRustDependencyLicenses,
+  assertRustDependencyLicensesInDirectory,
+  assertRustDependencyLicensesInEntries,
+  assertRustDependencyLicensesInArchive,
+} = contract;
+
+if (import.meta.main) contract.runCli();
diff --git a/src/sdks/ts/node-addon/tools/node-addon-cleanup-lifecycle.test.mts b/src/sdks/ts/node-addon/tools/node-addon-cleanup-lifecycle.test.mts
new file mode 100644
index 000000000..f9a401b94
--- /dev/null
+++ b/src/sdks/ts/node-addon/tools/node-addon-cleanup-lifecycle.test.mts
@@ -0,0 +1,1185 @@
+import assert from 'node:assert/strict';
+import { existsSync, readFileSync } from 'node:fs';
+import { copyFile, mkdir, mkdtemp, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import { createRequire } from 'node:module';
+import { fileURLToPath } from 'node:url';
+import { spawnSync } from 'node:child_process';
+import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads';
+
+const scriptPath = fileURLToPath(import.meta.url);
+const workspaceRoot = path.resolve(path.dirname(scriptPath), '../../../../..');
+const require = createRequire(import.meta.url);
+const streamFixtureRequest = Object.freeze({
+  normal: 0x01,
+  failRecovery: 0xf1,
+  unknownAfterCallback: 0xf2,
+  successAfterCallback: 0xf3,
+  abortWithoutCallback: 0xf4,
+  failureWithoutCallback: 0xf5,
+  unknownWithoutCallback: 0xf6,
+});
+
+function parseArgs(argv) {
+  const parsed = {};
+  for (let index = 0; index < argv.length; index += 2) {
+    const key = argv[index];
+    const value = argv[index + 1];
+    if (!key?.startsWith('--') || value === undefined) {
+      throw new Error(`invalid cleanup lifecycle argument: ${key ?? ''}`);
+    }
+    const name = key.slice(2).replace(/-([a-z])/gu, (_match, letter) => letter.toUpperCase());
+    parsed[name] = value;
+  }
+  return parsed;
+}
+
+function loadAddon(addonPath) {
+  return require(addonPath);
+}
+
+function releaseParentPort() {
+  // Deno's Node-compatible parent port exposes unref, but not close.
+  if (process.versions.deno) parentPort.unref();
+  else parentPort.close();
+}
+
+async function openFake(addon, libraryPath, root) {
+  return addon.open({
+    libraryPath,
+    pgdata: path.join(root, 'pgdata'),
+    runtimeDirectory: path.join(root, 'runtime'),
+    username: 'postgres',
+    database: 'postgres',
+    startupArgs: [],
+  });
+}
+
+function eventsFrom(logPath) {
+  if (!existsSync(logPath)) {
+    return [];
+  }
+  return readFileSync(logPath, 'utf8')
+    .split(/\r?\n/u)
+    .filter((entry) => entry.length > 0);
+}
+
+function waitForWorkerMessage(worker, expectedMessage) {
+  return new Promise((resolve, reject) => {
+    const cleanup = () => {
+      worker.off('message', onMessage);
+      worker.off('messageerror', onMessageError);
+      worker.off('error', onError);
+      worker.off('exit', onExit);
+    };
+    const fail = (error, terminate = true) => {
+      cleanup();
+      reject(error);
+      if (terminate) {
+        void worker.terminate();
+      }
+    };
+    const onMessage = (received) => {
+      try {
+        assert.equal(received, expectedMessage);
+        cleanup();
+        resolve(received);
+      } catch (error) {
+        fail(error);
+      }
+    };
+    const onMessageError = (error) => {
+      fail(error instanceof Error ? error : new Error('cleanup lifecycle worker message failed'));
+    };
+    const onError = (error) => {
+      fail(error);
+    };
+    const onExit = (code) => {
+      fail(
+        new Error(`cleanup lifecycle worker exited with status ${code} before ${expectedMessage}`),
+        false,
+      );
+    };
+    worker.once('message', onMessage);
+    worker.once('messageerror', onMessageError);
+    worker.once('error', onError);
+    worker.once('exit', onExit);
+  });
+}
+
+function observeWorkerExit(worker) {
+  return new Promise((resolve) => {
+    let workerError;
+    worker.once('error', (error) => {
+      workerError = error;
+    });
+    worker.once('exit', (code) => {
+      resolve({ code, error: workerError });
+    });
+  });
+}
+
+async function requireWorkerExit(exitObservation, expectedCode) {
+  const { code, error } = await exitObservation;
+  if (error !== undefined) {
+    throw error;
+  }
+  assert.equal(code, expectedCode, 'cleanup lifecycle worker exit status');
+}
+
+async function runWorker() {
+  const { role, addonPath, libraryPath, root } = workerData;
+  const addon = loadAddon(addonPath);
+  if (role === 'load-only') {
+    parentPort.postMessage('loaded');
+    releaseParentPort();
+    return;
+  }
+  if (role === 'open-and-detach') {
+    const handle = await openFake(addon, libraryPath, root);
+    await addon.detach(handle);
+    parentPort.postMessage('detached');
+    await new Promise((resolve) => {
+      parentPort.once('message', (message) => {
+        assert.equal(message, 'finish');
+        resolve();
+      });
+    });
+    releaseParentPort();
+    return;
+  }
+  if (role === 'open-and-wait') {
+    globalThis.__oliphauntCleanupLifecycleWorkerHandle = await openFake(addon, libraryPath, root);
+    parentPort.postMessage('opened');
+    await new Promise((resolve) => {
+      parentPort.once('message', resolve);
+    });
+    return;
+  }
+  if (role === 'open-with-active-query') {
+    const handle = await openFake(addon, libraryPath, root);
+    globalThis.__oliphauntCleanupRaceHandle = handle;
+    globalThis.__oliphauntCleanupRaceOperation = addon
+      .execProtocolRaw(handle, new Uint8Array([1]))
+      .catch(() => undefined);
+    parentPort.postMessage('queued');
+    return;
+  }
+  if (role === 'open-with-queued-query') {
+    const handle = await openFake(addon, libraryPath, root);
+    globalThis.__oliphauntCleanupRaceHandle = handle;
+    globalThis.__oliphauntCleanupRaceOperation = addon
+      .execProtocolRaw(handle, new Uint8Array([1]))
+      .catch(() => undefined);
+    globalThis.__oliphauntSecondQueuedQuery = addon
+      .execProtocolRaw(handle, new Uint8Array([2]))
+      .catch(() => undefined);
+    parentPort.postMessage('queued');
+    return;
+  }
+  if (role === 'open-with-active-stream') {
+    const handle = await openFake(addon, libraryPath, root);
+    globalThis.__oliphauntCleanupRaceHandle = handle;
+    globalThis.__oliphauntCleanupRaceOperation = addon
+      .execProtocolRawStream(handle, new Uint8Array([1]), () => undefined)
+      .catch(() => undefined);
+    parentPort.postMessage('queued');
+    return;
+  }
+  if (role === 'open-with-stream-delivery-wait') {
+    const handle = await openFake(addon, libraryPath, root);
+    globalThis.__oliphauntCleanupRaceHandle = handle;
+    globalThis.__oliphauntCleanupRaceOperation = addon
+      .execProtocolRawStream(handle, new Uint8Array([1]), () => {
+        assert.fail('the admitted callback must remain queued until Worker teardown');
+      })
+      .catch(() => undefined);
+    parentPort.postMessage('queued');
+    Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 60_000);
+    return;
+  }
+  if (role === 'open-with-active-backup') {
+    const handle = await openFake(addon, libraryPath, root);
+    globalThis.__oliphauntCleanupRaceHandle = handle;
+    globalThis.__oliphauntCleanupRaceOperation = addon.backup(handle).catch(() => undefined);
+    parentPort.postMessage('queued');
+    return;
+  }
+  throw new Error(`unknown cleanup lifecycle worker role: ${role}`);
+}
+
+async function collectGarbageUntilCollected(signal) {
+  assert.equal(typeof globalThis.gc, 'function', 'GC lifecycle child must run with --expose-gc');
+  for (let attempt = 0; attempt < 200; attempt += 1) {
+    globalThis.gc();
+    await new Promise((resolve) => setImmediate(resolve));
+    if (signal.collected) {
+      return;
+    }
+  }
+  throw new Error('Node did not collect the unreachable native handle after 200 forced GC cycles');
+}
+
+function observeCollection(value) {
+  const signal = { collected: false, registry: undefined };
+  signal.registry = new FinalizationRegistry(() => {
+    signal.collected = true;
+  });
+  signal.registry.register(value, undefined);
+  return signal;
+}
+
+async function waitForEvent(logPath, expectedEvent) {
+  const deadline = Date.now() + 5_000;
+  while (Date.now() < deadline) {
+    if (eventsFrom(logPath).includes(expectedEvent)) {
+      return;
+    }
+    await new Promise((resolve) => setTimeout(resolve, 1));
+  }
+  throw new Error(`native lifecycle event did not arrive: ${expectedEvent}`);
+}
+
+async function runChild(options) {
+  const copiedImageScenario = options.scenario.startsWith('copied-image-');
+  const addon = copiedImageScenario ? undefined : loadAddon(options.addon);
+  switch (options.scenario) {
+    case 'registry-null':
+      await assert.rejects(
+        openFake(addon, options.library, options.root),
+        /registry returned null/u,
+      );
+      return;
+    case 'registry-failure':
+      await assert.rejects(
+        openFake(addon, options.library, options.root),
+        /selected static registry rejected/u,
+      );
+      return;
+    case 'registry-valid': {
+      const handle = await openFake(addon, options.library, options.root);
+      await addon.detach(handle);
+      return;
+    }
+    case 'invalid-library-path': {
+      assert.throws(() => addon.version(''), /liboliphaunt path must not be empty/u);
+      assert.throws(
+        () => addon.version(`${options.library}\0ignored-suffix`),
+        /liboliphaunt path must not contain a null byte/u,
+      );
+      return;
+    }
+    case 'explicit-detach':
+    case 'unicode-library-path': {
+      const handle = await openFake(addon, options.library, options.root);
+      await addon.detach(handle);
+      return;
+    }
+    case 'active-exit': {
+      globalThis.__oliphauntCleanupLifecycleHandle = await openFake(
+        addon,
+        options.library,
+        options.root,
+      );
+      return;
+    }
+    case 'forced-process-exit-active': {
+      globalThis.__oliphauntCleanupLifecycleHandle = await openFake(
+        addon,
+        options.library,
+        options.root,
+      );
+      // Node intentionally bypasses N-API environment cleanup hooks here.
+      // The real liboliphaunt process-level atexit handler owns this abrupt
+      // process teardown; this addon fixture must not claim otherwise.
+      return process.exit(0);
+    }
+    case 'gc-finalizer': {
+      let handle = await openFake(addon, options.library, options.root);
+      const collection = observeCollection(handle);
+      handle = undefined;
+      assert.equal(handle, undefined);
+      await collectGarbageUntilCollected(collection);
+      const reopened = await openFake(addon, options.library, options.root);
+      await addon.detach(reopened);
+      return;
+    }
+    case 'gc-detach-recovery': {
+      let handle = await openFake(addon, options.library, options.root);
+      const collection = observeCollection(handle);
+      handle = undefined;
+      assert.equal(handle, undefined);
+      await collectGarbageUntilCollected(collection);
+      await assert.rejects(
+        openFake(addon, options.library, options.root),
+        /could not recover the previous logical handle/u,
+      );
+      const recovered = await openFake(addon, options.library, options.root);
+      await addon.detach(recovered);
+      assert.equal(
+        eventsFrom(options.log).includes('init-while-active'),
+        false,
+        'reopen must recover the retained failed-detach owner before init',
+      );
+      return;
+    }
+    case 'forgotten-token-generation-guard': {
+      const staleHandle = await openFake(addon, options.library, options.root);
+      const staleToken = addon.createForgottenHandleRecoveryToken(staleHandle);
+      await addon.detach(staleHandle);
+
+      let currentHandle = await openFake(addon, options.library, options.root);
+      const currentToken = addon.createForgottenHandleRecoveryToken(currentHandle);
+      assert.equal(
+        addon.queueForgottenHandleRecovery(staleToken),
+        false,
+        'a recovery token from an older logical generation must not mark the current owner',
+      );
+      assert.equal(
+        addon.queueForgottenHandleRecovery(currentToken),
+        true,
+        'the current logical generation must be marked for next-open recovery',
+      );
+      currentHandle = undefined;
+      const recovered = await openFake(addon, options.library, options.root);
+      await addon.detach(recovered);
+      return;
+    }
+    case 'async-query-cancel': {
+      const handle = await openFake(addon, options.library, options.root);
+      const query = addon.execProtocolRaw(handle, new Uint8Array([1]));
+      assert.equal(query instanceof Promise, true, 'native query must return a Promise');
+      await waitForEvent(options.log, 'query-started');
+      addon.cancel(handle);
+      await assert.rejects(query, /fake query was cancelled/u);
+      await addon.detach(handle);
+      return;
+    }
+    case 'async-archive-timers': {
+      const handle = await openFake(addon, options.library, options.root);
+      let backupSettled = false;
+      const backup = addon.backup(handle).finally(() => {
+        backupSettled = true;
+      });
+      await new Promise((resolve) => setTimeout(resolve, 0));
+      assert.equal(backupSettled, false, 'backup must not block the Node.js event loop');
+      assert.deepEqual([...(await backup)], [1, 2, 3]);
+
+      let restoreSettled = false;
+      const restore = addon
+        .restore({
+          libraryPath: options.library,
+          destination: path.join(options.root, 'restored'),
+          bytes: new Uint8Array([1, 2, 3]),
+        })
+        .finally(() => {
+          restoreSettled = true;
+        });
+      await new Promise((resolve) => setTimeout(resolve, 0));
+      assert.equal(restoreSettled, false, 'restore must not block the Node.js event loop');
+      await restore;
+      await addon.detach(handle);
+      return;
+    }
+    case 'async-open-stream-detach-timers': {
+      let openSettled = false;
+      const opening = openFake(addon, options.library, options.root).finally(() => {
+        openSettled = true;
+      });
+      assert.equal(opening instanceof Promise, true, 'native open must return a Promise');
+      await new Promise((resolve) => setTimeout(resolve, 0));
+      assert.equal(openSettled, false, 'open must not block the Node.js event loop');
+      const handle = await opening;
+
+      const chunks = [];
+      let streamSettled = false;
+      const streaming = addon
+        .execProtocolRawStream(handle, new Uint8Array([1]), (chunk) => {
+          chunks.push([...chunk]);
+        })
+        .finally(() => {
+          streamSettled = true;
+        });
+      assert.equal(streaming instanceof Promise, true, 'native stream must return a Promise');
+      await new Promise((resolve) => setTimeout(resolve, 0));
+      assert.equal(streamSettled, false, 'streaming must not block the Node.js event loop');
+      await streaming;
+      assert.deepEqual(chunks, [
+        [1, 2],
+        [3, 4],
+        [5, 6],
+      ]);
+
+      let detachSettled = false;
+      const detaching = addon.detach(handle).finally(() => {
+        detachSettled = true;
+      });
+      assert.equal(detaching instanceof Promise, true, 'native detach must return a Promise');
+      await new Promise((resolve) => setTimeout(resolve, 0));
+      assert.equal(detachSettled, false, 'detach must not block the Node.js event loop');
+      await detaching;
+      return;
+    }
+    case 'async-stream-callback-contract': {
+      const handle = await openFake(addon, options.library, options.root);
+      await assert.rejects(
+        addon.execProtocolRawStream(handle, new Uint8Array([streamFixtureRequest.normal]), () =>
+          Promise.resolve(),
+        ),
+        /must complete synchronously.*Promise or thenable/u,
+      );
+      await assert.rejects(
+        addon.execProtocolRawStream(handle, new Uint8Array([streamFixtureRequest.normal]), () => {
+          throw new Error('stream consumer failed');
+        }),
+        /stream consumer failed/u,
+      );
+      const callbackObject = { kind: 'stream callback object identity' };
+      for (const callbackFailure of [
+        'stream callback string',
+        73,
+        Number.NaN,
+        undefined,
+        callbackObject,
+      ]) {
+        const outcome = await addon
+          .execProtocolRawStream(handle, new Uint8Array([streamFixtureRequest.normal]), () => {
+            throw callbackFailure;
+          })
+          .then(
+            () => ({ rejected: false, error: undefined }),
+            (error) => ({ rejected: true, error }),
+          );
+        assert.equal(outcome.rejected, true, 'a failed stream callback must reject');
+        assert.equal(
+          Object.is(outcome.error, callbackFailure),
+          true,
+          'a recovered callback abort must preserve the exact JavaScript throw value',
+        );
+      }
+      await assert.rejects(
+        addon.execProtocolRawStream(
+          handle,
+          new Uint8Array([streamFixtureRequest.failRecovery]),
+          () => {
+            throw new Error('secondary stream consumer failure');
+          },
+        ),
+        /fake stream recovery failed/u,
+        'an unconfirmed native recovery must take precedence over the callback exception',
+      );
+      await assert.rejects(
+        addon.execProtocolRawStream(
+          handle,
+          new Uint8Array([streamFixtureRequest.unknownAfterCallback]),
+          () => {
+            throw new Error('tertiary stream consumer failure');
+          },
+        ),
+        /fake stream returned an unknown positive status/u,
+        'an unknown positive native status must take precedence over the callback exception',
+      );
+      const successMismatchCallback = new Error(
+        'a success mismatch must not escape as a recovered callback failure',
+      );
+      await assert.rejects(
+        addon.execProtocolRawStream(
+          handle,
+          new Uint8Array([streamFixtureRequest.successAfterCallback]),
+          () => {
+            throw successMismatchCallback;
+          },
+        ),
+        (error) => {
+          assert.notStrictEqual(
+            error,
+            successMismatchCallback,
+            'native success after callback failure is authoritative adapter failure',
+          );
+          assert.match(String(error), /reported .*success.*callback/u);
+          return true;
+        },
+      );
+      let callbackCalled = false;
+      await assert.rejects(
+        addon.execProtocolRawStream(
+          handle,
+          new Uint8Array([streamFixtureRequest.abortWithoutCallback]),
+          () => {
+            callbackCalled = true;
+          },
+        ),
+        /callback abort without.*callback/u,
+        'CALLBACK_ABORTED without a recorded callback failure is native/ABI failure',
+      );
+      assert.equal(callbackCalled, false);
+      await assert.rejects(
+        addon.execProtocolRawStream(
+          handle,
+          new Uint8Array([streamFixtureRequest.failureWithoutCallback]),
+          () => {
+            assert.fail('native failure before delivery must not call the stream callback');
+          },
+        ),
+        /fake stream failed before callback delivery/u,
+      );
+      await assert.rejects(
+        addon.execProtocolRawStream(
+          handle,
+          new Uint8Array([streamFixtureRequest.unknownWithoutCallback]),
+          () => {
+            assert.fail('unknown native status before delivery must not call the stream callback');
+          },
+        ),
+        /fake stream returned an unknown status before callback delivery/u,
+      );
+      await addon.detach(handle);
+      return;
+    }
+    case 'generation-acquisition-race': {
+      await assert.rejects(
+        () => openFake(addon, options.library, options.root),
+        /logical generation/u,
+        'open must fail closed when the resident handle closes before generation acquisition',
+      );
+      return;
+    }
+    case 'alias-path': {
+      const first = await openFake(addon, options.library, options.root);
+      await addon.detach(first);
+      const aliasPath = `${path.dirname(options.library)}${path.sep}.${path.sep}${path.basename(options.library)}`;
+      assert.notEqual(aliasPath, options.library);
+      const second = await openFake(addon, aliasPath, options.root);
+      await addon.detach(second);
+      return;
+    }
+    case 'load-only-worker': {
+      const handle = await openFake(addon, options.library, options.root);
+      const worker = new Worker(scriptPath, {
+        workerData: {
+          role: 'load-only',
+          addonPath: options.addon,
+          libraryPath: options.library,
+          root: path.join(options.root, 'worker'),
+        },
+      });
+      const workerExit = observeWorkerExit(worker);
+      await waitForWorkerMessage(worker, 'loaded');
+      await requireWorkerExit(workerExit, 0);
+      assert.deepEqual(
+        eventsFrom(options.log),
+        ['init'],
+        "an environment that only loads the addon must not close another environment's runtime",
+      );
+      await addon.detach(handle);
+      return;
+    }
+    case 'ownership-transfer': {
+      const worker = new Worker(scriptPath, {
+        workerData: {
+          role: 'open-and-detach',
+          addonPath: options.addon,
+          libraryPath: options.library,
+          root: path.join(options.root, 'worker'),
+        },
+      });
+      const workerExit = observeWorkerExit(worker);
+      await waitForWorkerMessage(worker, 'detached');
+      const handle = await openFake(addon, options.library, options.root);
+      worker.postMessage('finish');
+      await requireWorkerExit(workerExit, 0);
+      assert.deepEqual(
+        eventsFrom(options.log),
+        ['init', 'detach', 'init'],
+        'the previous owner environment must not close a runtime after ownership transfers',
+      );
+      await addon.detach(handle);
+      return;
+    }
+    case 'worker-terminate-active': {
+      const worker = new Worker(scriptPath, {
+        workerData: {
+          role: 'open-and-wait',
+          addonPath: options.addon,
+          libraryPath: options.library,
+          root: path.join(options.root, 'worker'),
+        },
+      });
+      const workerExit = observeWorkerExit(worker);
+      await waitForWorkerMessage(worker, 'opened');
+      assert.equal(await worker.terminate(), 1);
+      await requireWorkerExit(workerExit, 1);
+      assert.deepEqual(
+        eventsFrom(options.log),
+        ['init', 'close'],
+        'worker.terminate() must run the owning Node environment cleanup hook',
+      );
+      return;
+    }
+    case 'worker-terminate-query':
+    case 'worker-terminate-backup': {
+      const operation = options.scenario.slice('worker-terminate-'.length);
+      const worker = new Worker(scriptPath, {
+        workerData: {
+          role: `open-with-active-${operation}`,
+          addonPath: options.addon,
+          libraryPath: options.library,
+          root: path.join(options.root, 'worker'),
+        },
+      });
+      const workerExit = observeWorkerExit(worker);
+      await waitForWorkerMessage(worker, 'queued');
+      await waitForEvent(options.log, `${operation}-started`);
+      assert.equal(await worker.terminate(), 1);
+      await requireWorkerExit(workerExit, 1);
+      return;
+    }
+    case 'worker-terminate-query-alias': {
+      const aliasPath = `${path.dirname(options.library)}${path.sep}.${path.sep}${path.basename(options.library)}`;
+      addon.version(aliasPath);
+      const worker = new Worker(scriptPath, {
+        workerData: {
+          role: 'open-with-active-query',
+          addonPath: options.addon,
+          libraryPath: options.library,
+          root: path.join(options.root, 'worker'),
+        },
+      });
+      const workerExit = observeWorkerExit(worker);
+      await waitForWorkerMessage(worker, 'queued');
+      await waitForEvent(options.log, 'query-started');
+      assert.equal(await worker.terminate(), 1);
+      await requireWorkerExit(workerExit, 1);
+      return;
+    }
+    case 'worker-terminate-stream-delivery-wait': {
+      const worker = new Worker(scriptPath, {
+        workerData: {
+          role: 'open-with-stream-delivery-wait',
+          addonPath: options.addon,
+          libraryPath: options.library,
+          root: path.join(options.root, 'worker'),
+        },
+      });
+      const workerExit = observeWorkerExit(worker);
+      await waitForWorkerMessage(worker, 'queued');
+      // The queued callback cannot run while its owning event loop is blocked.
+      // Teardown must release the native producer without running user code.
+      await waitForEvent(options.log, 'stream-callback-blocked');
+      assert.equal(await worker.terminate(), 1);
+      await requireWorkerExit(workerExit, 1);
+      // Deno reports exit before native teardown; observe the native barrier.
+      await waitForEvent(options.log, 'close');
+      return;
+    }
+    case 'worker-terminate-queued-query': {
+      const worker = new Worker(scriptPath, {
+        workerData: {
+          role: 'open-with-queued-query',
+          addonPath: options.addon,
+          libraryPath: options.library,
+          root: path.join(options.root, 'worker'),
+        },
+      });
+      const workerExit = observeWorkerExit(worker);
+      await waitForWorkerMessage(worker, 'queued');
+      // The first native call blocks while the second waits for session ownership.
+      // Both must retire before terminal shutdown, without JS completion callbacks.
+      await waitForEvent(options.log, 'query-started');
+      assert.equal(await worker.terminate(), 1);
+      await requireWorkerExit(workerExit, 1);
+      return;
+    }
+    case 'copied-image-same-env-active':
+    case 'copied-image-same-env-detached': {
+      const firstAddon = loadAddon(options.addonCopyA);
+      const secondAddon = loadAddon(options.addonCopyB);
+      const firstHandle = await openFake(
+        firstAddon,
+        options.library,
+        path.join(options.root, 'first'),
+      );
+      await firstAddon.detach(firstHandle);
+      const secondHandle = await openFake(
+        secondAddon,
+        options.library,
+        path.join(options.root, 'second'),
+      );
+      if (options.scenario.endsWith('-detached')) {
+        await secondAddon.detach(secondHandle);
+      } else {
+        globalThis.__oliphauntCopiedImageCurrentHandle = secondHandle;
+      }
+      return;
+    }
+    case 'copied-image-worker-main-active':
+    case 'copied-image-worker-main-detached': {
+      const worker = new Worker(scriptPath, {
+        workerData: {
+          role: 'open-and-detach',
+          addonPath: options.addonCopyA,
+          libraryPath: options.library,
+          root: path.join(options.root, 'worker'),
+        },
+      });
+      const workerExit = observeWorkerExit(worker);
+      await waitForWorkerMessage(worker, 'detached');
+      const mainAddon = loadAddon(options.addonCopyB);
+      const mainHandle = await openFake(
+        mainAddon,
+        options.library,
+        path.join(options.root, 'main'),
+      );
+      const currentOwnerDetached = options.scenario.endsWith('-detached');
+      if (currentOwnerDetached) {
+        await mainAddon.detach(mainHandle);
+      } else {
+        globalThis.__oliphauntCopiedImageCurrentHandle = mainHandle;
+      }
+      worker.postMessage('finish');
+      await requireWorkerExit(workerExit, 0);
+      assert.deepEqual(
+        eventsFrom(options.log),
+        ['init', 'detach', 'init', ...(currentOwnerDetached ? ['detach'] : []), 'close-stale'],
+        "cleanup from the copied worker image must not close the main image's current generation",
+      );
+      return;
+    }
+    case 'copied-image-worker-terminate-stale': {
+      const worker = new Worker(scriptPath, {
+        workerData: {
+          role: 'open-and-detach',
+          addonPath: options.addonCopyA,
+          libraryPath: options.library,
+          root: path.join(options.root, 'worker'),
+        },
+      });
+      const workerExit = observeWorkerExit(worker);
+      await waitForWorkerMessage(worker, 'detached');
+      const mainAddon = loadAddon(options.addonCopyB);
+      globalThis.__oliphauntCopiedImageCurrentHandle = await openFake(
+        mainAddon,
+        options.library,
+        path.join(options.root, 'main'),
+      );
+      assert.equal(await worker.terminate(), 1);
+      await requireWorkerExit(workerExit, 1);
+      assert.deepEqual(
+        eventsFrom(options.log),
+        ['init', 'detach', 'init', 'close-stale'],
+        'terminated stale addon cleanup must not close the current copied-image generation',
+      );
+      return;
+    }
+    default:
+      throw new Error(`unknown cleanup lifecycle scenario: ${options.scenario}`);
+  }
+}
+
+function assertTerminalLifecycle(scenario, events, expectedBeforeClose) {
+  // Independent environment reapers may race: a refused stale generation is
+  // harmless. The current generation must still close exactly once.
+  assert.deepEqual(
+    events.filter((event) => event !== 'close-stale'),
+    [...expectedBeforeClose.filter((event) => event !== 'close-stale'), 'close'],
+    `${scenario} must terminally close exactly once during Node environment cleanup`,
+  );
+  assert.equal(events.includes('close-after-close'), false);
+  assert.equal(events.includes('detach-after-close'), false);
+  assert.equal(events.includes('close-unguarded'), false);
+  assert.equal(events.includes('close-guard-invalid'), false);
+}
+
+function assertCopiedImageLifecycle(scenario, events, expectedBeforeCleanup, expectStaleCleanup) {
+  assert.deepEqual(
+    events.slice(0, expectedBeforeCleanup.length),
+    expectedBeforeCleanup,
+    `${scenario} must complete its logical ownership transfer before cleanup`,
+  );
+  const cleanupEvents = events.slice(expectedBeforeCleanup.length).toSorted();
+  if (expectStaleCleanup) {
+    assert.deepEqual(
+      cleanupEvents,
+      ['close', 'close-stale'],
+      `${scenario} must close the current generation once and reject one stale cleanup`,
+    );
+  } else {
+    assert.deepEqual(
+      cleanupEvents,
+      cleanupEvents.includes('close-stale') ? ['close', 'close-stale'] : ['close'],
+      `${scenario} must close exactly once; an older token may observe the already-spent process`,
+    );
+  }
+  assert.equal(events.includes('close-unguarded'), false);
+  assert.equal(events.includes('close-guard-invalid'), false);
+  assert.equal(events.includes('close-after-close'), false);
+  assert.equal(events.includes('detach-after-close'), false);
+}
+
+function assertGenerationAcquisitionRace(scenario, events) {
+  assert.deepEqual(
+    events,
+    ['init', 'close-before-generation'],
+    `${scenario} must not dereference a handle after generation acquisition reports it stale`,
+  );
+  assert.equal(events.includes('close-unguarded'), false);
+  assert.equal(events.includes('close-guard-invalid'), false);
+  assert.equal(events.includes('close-after-close'), false);
+  assert.equal(events.includes('detach-after-close'), false);
+}
+
+async function runParent(options) {
+  for (const candidate of [options.addon, options.library]) {
+    assert.ok(path.isAbsolute(candidate), `cleanup lifecycle input must be absolute: ${candidate}`);
+    assert.ok(existsSync(candidate), `cleanup lifecycle input does not exist: ${candidate}`);
+  }
+
+  const temporaryRoot = await mkdtemp(path.join(tmpdir(), 'oliphaunt-node-cleanup-'));
+  let singleImageCases = 0;
+  let copiedImageCases = 0;
+  let staleAcquisitionCases = 0;
+  try {
+    const copiedAddonA = path.join(temporaryRoot, 'oliphaunt-node-copy-a.node');
+    const copiedAddonB = path.join(temporaryRoot, 'oliphaunt-node-copy-b.node');
+    const unicodeLibraryDirectory = path.join(temporaryRoot, 'unicode-λ-路径');
+    const unicodeLibrary = path.join(unicodeLibraryDirectory, path.basename(options.library));
+    await mkdir(unicodeLibraryDirectory, { recursive: true });
+    await Promise.all([
+      copyFile(options.addon, copiedAddonA),
+      copyFile(options.addon, copiedAddonB),
+      copyFile(options.library, unicodeLibrary),
+    ]);
+    const scenarios = [
+      { name: 'registry-null', registry: 'null', expectedEvents: ['registry-selected'] },
+      {
+        name: 'registry-failure',
+        registry: 'failure',
+        expectedEvents: ['registry-selected', 'registry-rejected'],
+      },
+      {
+        name: 'registry-valid',
+        registry: 'valid',
+        expectedBeforeClose: ['registry-selected', 'registry-registered', 'init', 'detach'],
+      },
+      {
+        name: 'explicit-detach',
+        expectedBeforeClose: ['init', 'detach'],
+        iterations: 12,
+      },
+      {
+        name: 'active-exit',
+        expectedBeforeClose: ['init'],
+        iterations: 12,
+      },
+      {
+        name: 'forced-process-exit-active',
+        expectedAbruptExit: ['init'],
+      },
+      {
+        name: 'unicode-library-path',
+        expectedBeforeClose: ['init', 'detach'],
+        library: unicodeLibrary,
+      },
+      {
+        name: 'invalid-library-path',
+        expectedNoEvents: true,
+      },
+      {
+        name: 'gc-finalizer',
+        expectedBeforeClose: ['init', 'detach', 'init', 'detach'],
+        exposeGc: true,
+      },
+      {
+        name: 'gc-detach-recovery',
+        expectedBeforeClose: ['init', 'detach-failed', 'detach', 'init', 'detach'],
+        exposeGc: true,
+        failDetachOnce: true,
+      },
+      {
+        name: 'forgotten-token-generation-guard',
+        expectedBeforeClose: ['init', 'detach', 'init', 'detach', 'init', 'detach'],
+      },
+      {
+        name: 'async-query-cancel',
+        expectedBeforeClose: ['init', 'query-started', 'cancel', 'query-cancelled', 'detach'],
+        blockQuery: true,
+      },
+      {
+        name: 'async-archive-timers',
+        expectedBeforeClose: [
+          'init',
+          'backup-started',
+          'backup-finished',
+          'restore-started',
+          'restore-finished',
+          'detach',
+        ],
+        blockArchive: true,
+      },
+      {
+        name: 'async-open-stream-detach-timers',
+        expectedBeforeClose: [
+          'open-started',
+          'open-finished',
+          'init',
+          'stream-started',
+          'stream-finished',
+          'detach-started',
+          'detach-finished',
+          'detach',
+        ],
+        blockOpen: true,
+        blockStream: true,
+        blockDetach: true,
+      },
+      {
+        name: 'async-stream-callback-contract',
+        expectedBeforeClose: [
+          'init',
+          ...Array.from({ length: 7 }, () => ['stream-started', 'stream-aborted']).flat(),
+          'stream-started',
+          'stream-aborted',
+          'stream-recovery-failed',
+          'stream-started',
+          'stream-aborted',
+          'stream-unknown-status',
+          'stream-started',
+          'stream-aborted',
+          'stream-success-after-callback-abort',
+          'stream-started',
+          'stream-abort-without-callback',
+          'stream-started',
+          'stream-failure-without-callback',
+          'stream-started',
+          'stream-unknown-without-callback',
+          'detach',
+        ],
+        blockStream: true,
+      },
+      {
+        name: 'generation-acquisition-race',
+        generationAcquisitionRace: true,
+      },
+      {
+        name: 'alias-path',
+        expectedBeforeClose: ['init', 'detach', 'init', 'detach'],
+      },
+      {
+        name: 'load-only-worker',
+        expectedBeforeClose: ['init', 'detach'],
+      },
+      {
+        name: 'ownership-transfer',
+        expectedBeforeClose: ['init', 'detach', 'init', 'detach'],
+      },
+      {
+        name: 'worker-terminate-active',
+        expectedBeforeClose: ['init'],
+      },
+      {
+        name: 'worker-terminate-query',
+        expectedBeforeClose: ['init', 'query-started', 'cancel', 'query-cancelled'],
+        blockQuery: true,
+        iterations: 3,
+      },
+      {
+        name: 'worker-terminate-query-alias',
+        expectedBeforeClose: ['init', 'query-started', 'cancel', 'query-cancelled'],
+        blockQuery: true,
+        recordRepeatCancel: true,
+      },
+      {
+        name: 'worker-terminate-queued-query',
+        expectedBeforeClose: ['init', 'query-started', 'cancel', 'query-cancelled'],
+        blockQuery: true,
+        iterations: 3,
+      },
+      {
+        name: 'worker-terminate-stream-delivery-wait',
+        expectedBeforeClose: [
+          'init',
+          'stream-started',
+          'stream-callback-blocked',
+          'stream-aborted',
+        ],
+        blockStream: true,
+        observeBlockedStreamCallback: true,
+        iterations: 3,
+      },
+      {
+        name: 'worker-terminate-backup',
+        expectedBeforeClose: ['init', 'backup-started', 'backup-finished'],
+        blockArchive: true,
+        iterations: 3,
+      },
+      {
+        name: 'copied-image-same-env-active',
+        expectedBeforeCleanup: ['init', 'detach', 'init'],
+      },
+      {
+        name: 'copied-image-same-env-detached',
+        expectedBeforeCleanup: ['init', 'detach', 'init', 'detach'],
+      },
+      {
+        name: 'copied-image-worker-main-active',
+        expectedBeforeCleanup: ['init', 'detach', 'init'],
+        expectStaleCleanup: true,
+      },
+      {
+        name: 'copied-image-worker-main-detached',
+        expectedBeforeCleanup: ['init', 'detach', 'init', 'detach'],
+        expectStaleCleanup: true,
+      },
+      {
+        name: 'copied-image-worker-terminate-stale',
+        expectedBeforeClose: ['init', 'detach', 'init', 'close-stale'],
+      },
+    ];
+
+    for (const scenario of scenarios) {
+      const iterations = scenario.iterations ?? 1;
+      for (let iteration = 1; iteration <= iterations; iteration += 1) {
+        if (scenario.generationAcquisitionRace) {
+          staleAcquisitionCases += 1;
+        } else if (scenario.name.startsWith('copied-image-')) {
+          copiedImageCases += 1;
+        } else {
+          singleImageCases += 1;
+        }
+        const executionName =
+          iterations === 1 ? scenario.name : `${scenario.name}-${iteration}-of-${iterations}`;
+        const scenarioAddon = options.addon;
+        const scenarioRoot = path.join(temporaryRoot, executionName);
+        const logPath = path.join(temporaryRoot, `${executionName}.log`);
+        const childArgs = [
+          ...(process.versions.deno
+            ? [
+                'run',
+                '--no-config',
+                '--node-modules-dir=manual',
+                '--allow-all',
+                ...(scenario.exposeGc ? ['--v8-flags=--expose-gc'] : []),
+              ]
+            : scenario.exposeGc
+              ? ['--expose-gc']
+              : []),
+          scriptPath,
+          '--scenario',
+          scenario.name,
+          '--addon',
+          scenarioAddon,
+          '--addon-copy-a',
+          copiedAddonA,
+          '--addon-copy-b',
+          copiedAddonB,
+          '--library',
+          scenario.library ?? options.library,
+          '--root',
+          scenarioRoot,
+          '--log',
+          logPath,
+        ];
+        const child = spawnSync(process.execPath, childArgs, {
+          encoding: 'utf8',
+          env: {
+            ...process.env,
+            OLIPHAUNT_NODE_CLEANUP_TEST_LOG: logPath,
+            ...(scenario.registry
+              ? { OLIPHAUNT_NODE_CLEANUP_TEST_REGISTRY: scenario.registry }
+              : {}),
+            ...(scenario.generationAcquisitionRace
+              ? { OLIPHAUNT_NODE_CLEANUP_TEST_CLOSE_BEFORE_GENERATION: '1' }
+              : {}),
+            ...(scenario.failDetachOnce
+              ? { OLIPHAUNT_NODE_CLEANUP_TEST_FAIL_DETACH_ONCE: '1' }
+              : {}),
+            ...(scenario.blockQuery ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_QUERY: '1' } : {}),
+            ...(scenario.blockArchive ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_ARCHIVE: '1' } : {}),
+            ...(scenario.blockOpen ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_OPEN: '1' } : {}),
+            ...(scenario.blockStream ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_STREAM: '1' } : {}),
+            ...(scenario.blockDetach ? { OLIPHAUNT_NODE_CLEANUP_TEST_BLOCK_DETACH: '1' } : {}),
+            ...(scenario.observeBlockedStreamCallback
+              ? { OLIPHAUNT_NODE_CLEANUP_TEST_OBSERVE_BLOCKED_STREAM_CALLBACK: '1' }
+              : {}),
+            ...(scenario.recordRepeatCancel
+              ? { OLIPHAUNT_NODE_CLEANUP_TEST_RECORD_REPEAT_CANCEL: '1' }
+              : {}),
+          },
+          timeout: 30_000,
+        });
+        assert.equal(
+          child.error,
+          undefined,
+          `${executionName} child could not run: ${child.error?.message ?? 'unknown error'}`,
+        );
+        assert.equal(
+          child.signal,
+          null,
+          `${executionName} child terminated by ${child.signal}\n${child.stderr}`,
+        );
+        assert.equal(
+          child.status,
+          0,
+          `${executionName} child failed\nstdout:\n${child.stdout}\nstderr:\n${child.stderr}`,
+        );
+        // Bun can exit zero while another thread is printing its fatal banner.
+        assert.doesNotMatch(
+          child.stderr,
+          /={20,}\r?\nBun v/u,
+          `${executionName} crashed during environment cleanup`,
+        );
+        const events = eventsFrom(logPath);
+        if (scenario.expectedEvents) {
+          assert.deepEqual(
+            events,
+            scenario.expectedEvents,
+            `${executionName} must fail before native initialization`,
+          );
+        } else if (scenario.expectedNoEvents) {
+          assert.deepEqual(events, [], `${executionName} must not load a library image`);
+        } else if (scenario.expectedAbruptExit !== undefined) {
+          assert.deepEqual(
+            events,
+            scenario.expectedAbruptExit,
+            `${executionName} must defer cleanup to process teardown`,
+          );
+        } else if (scenario.generationAcquisitionRace) {
+          assertGenerationAcquisitionRace(executionName, events);
+        } else if (scenario.expectedBeforeCleanup !== undefined) {
+          assertCopiedImageLifecycle(
+            executionName,
+            events,
+            scenario.expectedBeforeCleanup,
+            scenario.expectStaleCleanup ?? false,
+          );
+        } else {
+          const assertedEvents = scenario.ignoreEarlyCancel
+            ? events.filter(
+                (event, index) =>
+                  event !== 'cancel-early-ignored' || index === events.indexOf(event),
+              )
+            : events;
+          assertTerminalLifecycle(executionName, assertedEvents, scenario.expectedBeforeClose);
+        }
+      }
+    }
+  } finally {
+    await rm(temporaryRoot, { recursive: true, force: true });
+  }
+
+  console.log(
+    `${process.versions.deno ? 'Deno' : process.versions.bun ? 'Bun' : 'Node'} direct environment cleanup lifecycle passed (${singleImageCases} single-image + ${copiedImageCases} copied-image + ${staleAcquisitionCases} stale-acquisition cases)`,
+  );
+}
+
+if (!isMainThread) {
+  await runWorker();
+} else {
+  const options = parseArgs(process.argv.slice(2));
+  if (options.scenario !== undefined) {
+    await runChild(options);
+  } else {
+    await runParent(options);
+  }
+}
diff --git a/src/sdks/ts/node-addon/tools/package-node-direct-runtime.sh b/src/sdks/ts/node-addon/tools/package-node-direct-runtime.sh
new file mode 100644
index 000000000..a7f54655d
--- /dev/null
+++ b/src/sdks/ts/node-addon/tools/package-node-direct-runtime.sh
@@ -0,0 +1,202 @@
+#!/usr/bin/env sh
+set -eu
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+
+require() {
+  if ! command -v "$1" >/dev/null 2>&1; then
+    echo "missing required command: $1" >&2
+    exit 1
+  fi
+}
+
+require node
+require bun
+require cargo
+require tar
+
+case "$(uname -s)" in
+  Darwin) platform="macos" ;;
+  Linux) platform="linux" ;;
+  MINGW* | MSYS* | CYGWIN*) platform="windows" ;;
+  *)
+    echo "unsupported Node direct adapter platform: $(uname -s)" >&2
+    exit 2
+    ;;
+esac
+
+case "$(uname -m)" in
+  arm64 | aarch64) arch="arm64" ;;
+  x86_64 | amd64) arch="x64" ;;
+  *)
+    echo "unsupported Node direct adapter architecture: $(uname -m)" >&2
+    exit 2
+    ;;
+esac
+
+case "$platform:$arch" in
+  macos:arm64) target="macos-arm64" ;;
+  linux:x64) target="linux-x64-gnu" ;;
+  linux:arm64) target="linux-arm64-gnu" ;;
+  windows:x64) target="windows-x64-msvc" ;;
+  *)
+    echo "unsupported Node direct adapter target: $platform/$arch" >&2
+    exit 2
+    ;;
+esac
+
+if [ "$platform" = "macos" ]; then
+  MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}"
+  case "$MACOSX_DEPLOYMENT_TARGET" in
+    "" | *[!0-9.]*)
+      echo "MACOSX_DEPLOYMENT_TARGET must be a numeric dotted version" >&2
+      exit 2
+      ;;
+  esac
+  export MACOSX_DEPLOYMENT_TARGET
+fi
+
+to_shell_path() {
+  if [ "$platform" = "windows" ] && command -v cygpath >/dev/null 2>&1; then
+    cygpath -u "$1"
+  else
+    printf '%s\n' "$1"
+  fi
+}
+
+resolve_output_path() {
+  raw="$1"
+  case "$raw" in
+    /* | [A-Za-z]:/* | [A-Za-z]:\\* | \\\\*) ;;
+    *) raw="$root/$raw" ;;
+  esac
+  if [ "$platform" = "windows" ] && command -v cygpath >/dev/null 2>&1; then
+    cygpath -am "$raw"
+  else
+    printf '%s\n' "$raw"
+  fi
+}
+
+tar_list_gzip() {
+  if [ "$platform" = "windows" ]; then
+    tar --force-local -tzf "$1"
+  else
+    tar -tzf "$1"
+  fi
+}
+
+version="$(bun tools/dev/node-info.mts package-version src/sdks/ts/node-addon/package.json)"
+out_dir="$(resolve_output_path "${OLIPHAUNT_NODE_ADDON_OUT_DIR:-$root/target/oliphaunt-artifacts/node-direct/$target}")"
+asset_dir="$(resolve_output_path "${OLIPHAUNT_NODE_ADDON_ASSET_OUT_DIR:-$root/target/oliphaunt-node-direct/release-assets}")"
+npm_package_dir="$(resolve_output_path "${OLIPHAUNT_NODE_ADDON_NPM_PACKAGE_OUT_DIR:-$root/target/oliphaunt-node-direct/npm-packages}")"
+npm_package_work_root="$(resolve_output_path "${OLIPHAUNT_NODE_ADDON_NPM_PACKAGE_WORK_DIR:-$root/target/oliphaunt-node-direct/npm-package-work/$target}")"
+addon="$out_dir/oliphaunt_node.node"
+addon_file="$addon"
+mkdir -p "$out_dir" "$asset_dir" "$npm_package_dir"
+bash src/sdks/ts/node-addon/tools/build-native.sh "$out_dir"
+bash tools/packaging/strip-native-binaries.sh "$addon_file"
+
+if [ "$platform" = "windows" ]; then
+  asset="oliphaunt-node-direct-$version-$target.zip"
+else
+  asset="oliphaunt-node-direct-$version-$target.tar.gz"
+fi
+asset_stage="$root/target/oliphaunt-node-direct/release-stage/$target"
+rm -rf "$asset_stage"
+mkdir -p "$asset_stage"
+cp "$addon_file" "$asset_stage/oliphaunt_node.node"
+tools/dev/bun.sh tools/packaging/release-notices.mts stage "$asset_stage" --profile source-sdk
+tools/dev/bun.sh src/sdks/ts/node-addon/tools/dependency-license-contract.mts stage "$asset_stage" --target "$target"
+if [ "$platform" = "windows" ]; then
+  tools/dev/bun.sh tools/packaging/windows-vc-runtime-closure.mts stage \
+    --root "$asset_stage" --destination "$asset_stage"
+fi
+tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target" --root "$asset_stage"
+if [ "$platform" = "linux" ]; then
+  tools/packaging/check-linux-consumer-baseline.sh --target "$target" --root "$asset_stage"
+fi
+tools/packaging/archive-directory.mts "$asset_stage" "$asset_dir/$asset"
+
+input_dirs="${OLIPHAUNT_NODE_ADDON_ASSET_INPUT_DIRS:-${OLIPHAUNT_RELEASE_ASSET_INPUT_DIRS:-}}"
+if [ -n "$input_dirs" ]; then
+  old_ifs="$IFS"
+  if [ "$platform" = "windows" ]; then
+    input_delimiter=';'
+  else
+    input_delimiter=':'
+  fi
+  IFS="$input_delimiter"
+  for input_dir in $input_dirs; do
+    IFS="$old_ifs"
+    [ -n "$input_dir" ] || continue
+    input_dir="$(to_shell_path "$input_dir")"
+    [ -d "$input_dir" ] || {
+      echo "release asset input directory does not exist: $input_dir" >&2
+      exit 1
+    }
+    find "$input_dir" -maxdepth 1 -type f \( -name 'oliphaunt-node-direct-*.tar.gz' -o -name 'oliphaunt-node-direct-*.zip' \) -print |
+      sort |
+      while IFS= read -r input_asset; do
+        [ -n "$input_asset" ] || continue
+        cp -p "$input_asset" "$asset_dir/"
+      done
+    IFS="$input_delimiter"
+  done
+  IFS="$old_ifs"
+fi
+
+tools/packaging/write-checksum-manifest.mts \
+  --asset-dir "$asset_dir" \
+  --output "oliphaunt-node-direct-$version-release-assets.sha256" \
+  --pattern 'oliphaunt-node-direct-*.tar.gz' \
+  --pattern 'oliphaunt-node-direct-*.zip'
+
+printf 'Node direct addon built and validated: %s\n' "$addon"
+case "$target" in
+  macos-arm64) optional_package="darwin-arm64" ;;
+  linux-x64-gnu) optional_package="linux-x64-gnu" ;;
+  linux-arm64-gnu) optional_package="linux-arm64-gnu" ;;
+  windows-x64-msvc) optional_package="win32-x64-msvc" ;;
+  *)
+    echo "unsupported Node direct optional npm package target: $target" >&2
+    exit 2
+    ;;
+esac
+package_source="$root/src/sdks/ts/node-addon/packages/$optional_package"
+package_work="$npm_package_work_root/$optional_package"
+rm -rf "$package_work"
+mkdir -p "$package_work/prebuilds"
+cp -R "$package_source/." "$package_work/"
+rm -rf "$package_work/prebuilds"
+mkdir -p "$package_work/prebuilds"
+cp "$addon_file" "$package_work/prebuilds/oliphaunt_node.node"
+if [ "$platform" = "windows" ]; then
+  tools/dev/bun.sh tools/packaging/windows-vc-runtime-closure.mts stage \
+    --root "$package_work" --source-dir "$asset_stage" \
+    --destination "$package_work/prebuilds"
+fi
+tools/dev/bun.sh tools/packaging/release-notices.mts stage "$package_work" --profile source-sdk
+tools/dev/bun.sh src/sdks/ts/node-addon/tools/dependency-license-contract.mts stage "$package_work" --target "$target"
+find "$package_work" -type f -exec chmod 0644 {} +
+chmod 0755 "$package_work/prebuilds/oliphaunt_node.node"
+filename="$(bun "$root/tools/packaging/npm-package.mts" "$package_work")"
+tarball="$npm_package_dir/$filename"
+bun pm pack --cwd "$package_work" --filename "$tarball"
+[ -f "$tarball" ] || {
+  echo "bun pm pack did not create $tarball" >&2
+  exit 1
+}
+if ! tar_list_gzip "$tarball" | grep -Fxq "package/prebuilds/oliphaunt_node.node"; then
+  echo "Node direct optional npm package is missing prebuilds/oliphaunt_node.node: $tarball" >&2
+  exit 1
+fi
+tools/dev/bun.sh src/sdks/ts/node-addon/tools/check-release-assets.mts \
+  --asset-dir "$asset_dir" \
+  --allow-partial \
+  --npm-package "$tarball"
+printf 'Node direct optional npm package staged: %s\n' "$tarball"
+printf '%s\n' "$asset_dir/$asset"
diff --git a/src/sdks/ts/node-addon/tools/test-node-addon-cleanup-lifecycle.sh b/src/sdks/ts/node-addon/tools/test-node-addon-cleanup-lifecycle.sh
new file mode 100755
index 000000000..3d1d43237
--- /dev/null
+++ b/src/sdks/ts/node-addon/tools/test-node-addon-cleanup-lifecycle.sh
@@ -0,0 +1,118 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+is_absolute_path() {
+  case "$1" in
+    /*|[A-Za-z]:/*|[A-Za-z]:\\*|\\\\*) return 0 ;;
+    *) return 1 ;;
+  esac
+}
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+
+addon="${1:-}"
+if [[ -z "$addon" ]]; then
+  echo "usage: $0 " >&2
+  exit 2
+fi
+if ! is_absolute_path "$addon"; then
+  addon="$root/$addon"
+fi
+if [[ ! -f "$addon" ]]; then
+  echo "compiled production Node direct addon does not exist: $addon" >&2
+  exit 2
+fi
+case "$(uname -s)" in
+  Darwin)
+    platform="macos"
+    library_name="libfake_oliphaunt.dylib"
+    ;;
+  Linux)
+    platform="linux"
+    library_name="libfake_oliphaunt.so"
+    ;;
+  MINGW*|MSYS*|CYGWIN*)
+    platform="windows"
+    library_name="fake_oliphaunt.dll"
+    ;;
+  *)
+    echo "unsupported Node cleanup lifecycle platform: $(uname -s)" >&2
+    exit 2
+    ;;
+esac
+
+out_root="${OLIPHAUNT_NODE_CLEANUP_TEST_OUT_DIR:-$root/target/oliphaunt-node-direct/cleanup-lifecycle$platform}"
+if ! is_absolute_path "$out_root"; then
+  out_root="$root/$out_root"
+fi
+rm -rf "$out_root"
+mkdir -p "$out_root"
+
+source_path="$root/src/sdks/ts/node-addon/native/node-addon/fixtures/fake_liboliphaunt.cc"
+include_path="$root/src/runtimes/liboliphaunt-native/include"
+library_path="$out_root/$library_name"
+cxx="${CXX:-c++}"
+
+case "$platform" in
+  macos)
+    "$cxx" \
+      -std=c++17 \
+      -O2 \
+      -fPIC \
+      -dynamiclib \
+      -DOLIPHAUNT_BUILDING_DLL \
+      "-I$include_path" \
+      "$source_path" \
+      -o "$library_path"
+    ;;
+  linux)
+    "$cxx" \
+      -std=c++17 \
+      -O2 \
+      -fPIC \
+      -shared \
+      -DOLIPHAUNT_BUILDING_DLL \
+      "-I$include_path" \
+      "$source_path" \
+      -o "$library_path"
+    ;;
+  windows)
+    cxx="${CXX:-cl}"
+    object_path="$out_root/fake_liboliphaunt.obj"
+    import_library_path="$out_root/fake_liboliphaunt.lib"
+    if command -v cygpath >/dev/null 2>&1; then
+      source_path="$(cygpath -w "$source_path")"
+      include_path="$(cygpath -w "$include_path")"
+      library_path="$(cygpath -w "$library_path")"
+      object_path="$(cygpath -w "$object_path")"
+      import_library_path="$(cygpath -w "$import_library_path")"
+      addon="$(cygpath -w "$addon")"
+    fi
+    "$cxx" \
+      //nologo \
+      //std:c++17 \
+      //O2 \
+      //EHsc \
+      //LD \
+      //DOLIPHAUNT_BUILDING_DLL \
+      "-I$include_path" \
+      "$source_path" \
+      //Fo:"$object_path" \
+      //link \
+      //OUT:"$library_path" \
+      //IMPLIB:"$import_library_path"
+    ;;
+esac
+
+node \
+  src/sdks/ts/node-addon/tools/node-addon-cleanup-lifecycle.test.mts \
+  --addon "$addon" \
+  --library "$library_path"
+bash tools/dev/bun.sh \
+  src/sdks/ts/node-addon/tools/node-addon-cleanup-lifecycle.test.mts \
+  --addon "$addon" \
+  --library "$library_path"
diff --git a/src/sdks/js/.gitignore b/src/sdks/ts/sdk/.gitignore
similarity index 100%
rename from src/sdks/js/.gitignore
rename to src/sdks/ts/sdk/.gitignore
diff --git a/src/sdks/ts/sdk/ARCHITECTURE.md b/src/sdks/ts/sdk/ARCHITECTURE.md
new file mode 100644
index 000000000..24a19e97e
--- /dev/null
+++ b/src/sdks/ts/sdk/ARCHITECTURE.md
@@ -0,0 +1,141 @@
+# TypeScript SDK architecture
+
+The TypeScript SDK is a thin native binding with one public entrypoint. It keeps
+JavaScript ergonomics at the API boundary and delegates PostgreSQL lifecycle and
+physical backup to `liboliphaunt`.
+
+## Public shape
+
+The default `Oliphaunt` client exposes `open`, `openServer`, and static
+`restore`. `open` returns the direct/broker database interface. `openServer`
+returns a distinct handle with a required connection string and no backup
+or database-connection methods.
+
+Typed execute/query results, callback transactions, cancellation, buffered and
+callback-streamed raw protocol, and close are common where meaningful. Backup
+is one byte format and only belongs to direct/broker databases. Runtime modes,
+capability objects, archive formats, parsers, stream primitives, packaging
+reports, and resource profiles are internal or absent.
+
+## Adapter boundaries
+
+- Native direct uses the platform Rust napi-rs addon on Node/Bun. Deno retains
+  its nonblocking FFI adapter: the addon passes ordinary SQL/restore checks on
+  Deno 2.8.1 but fails to drain and close when a Worker terminates with a queued
+  stream callback. Shared-addon migration requires that lifecycle proof.
+- Native broker owns one authenticated helper process per database. Helper or
+  IPC failure permanently fails that database handle; recovery is an explicit
+  close plus new open, never transparent session replacement or request replay.
+  SQL, streaming and cancellation use PostgreSQL wire messages. A separate
+  authenticated management connection owns backup and process shutdown. A
+  failed stream callback drains through ReadyForQuery before the next query;
+  failure to drain retires the handle.
+- Native server starts PostgreSQL, closes its private readiness probe before
+  publication, and exposes a connection string for caller-owned ORMs, drivers,
+  and tools.
+
+All three adapters implement the internal runtime binding. Its server adapter
+uses only open/connection-string/close/finalizer slots; required database slots
+reject internally and never appear on the public server facade. The Node addon and C ABI
+may have lower-level symbols for other consumers; the SDK does not mirror unused
+symbols into its own interface.
+
+The private close boundary returns a discriminated `closed`, `retryable`, or
+`terminal` outcome. Direct adapters may report retryable only when logical
+deactivation did not occur. Broker and server adapters cross a destructive
+cutoff before fallible process/filesystem cleanup and therefore classify those
+failures as terminal without inspecting error text.
+
+The public database contract is promise-based in every JavaScript runtime, and
+PostgreSQL open, query, backup, restore, and detach work runs through async native
+work in the addon or Deno nonblocking FFI. Loading the native module is
+the narrow exception: `require()` on Node/Bun and `dlopen()` on Deno are synchronous
+platform operations during first adapter resolution. They do not run a database
+operation or create an alternate synchronous database surface.
+
+Direct and broker databases have the same public methods. Server differs
+structurally instead of returning runtime-dependent failures: it exposes only
+`connectionString`, `closed`, `close`, and async disposal. External connections
+own SQL, transactions, raw protocol, cancellation, and backup. Standard
+PostgreSQL tools own server backup and logical import/export; applications
+provide those tools through their ordinary environment.
+
+## Lifecycle and concurrency
+
+Direct runtime admission prevents two active direct owners in one process.
+Broker supervision prevents duplicate roots and opens a separate SQL socket
+for PostgreSQL cancellation, so cancellation is not queued behind query output. The server handle
+does not control independent external connections.
+
+The database handle tracks close and active transaction state. A transaction
+pins the one SDK connection. Body failure rolls back; failed rollback poisons.
+COMMIT transport/protocol uncertainty poisons without a later ROLLBACK. An
+explicit PostgreSQL `ROLLBACK` command tag returned for COMMIT is the known-idle
+exception. Close waits for admitted operations. A pre-teardown direct failure
+may be retried; after success or a destructive broker/server failure, the one
+terminal close attempt is retained and later calls replay its exact outcome.
+The read-only `closed` state becomes true for either terminal result.
+
+Managed transaction handles expose structured SQL only. They reject ownership
+escape based on exact `CommandComplete` tags and the terminal `ReadyForQuery`
+frame before high-level parsing, then make the database close-only without a
+speculative SDK control command. Manual transaction lifecycle SQL and `AND
+CHAIN` are unsupported; `SAVEPOINT` and `ROLLBACK TO` remain supported.
+Closing stops ordinary session admission immediately, but keeps out-of-band
+cancel admission open while already-admitted work drains. Runtime teardown
+closes that cancel gate only after every admitted cancellation request settles.
+
+Raw-stream callbacks provide synchronous backpressure. While a callback runs,
+same-handle database work, transaction work, backup, close, and nested streams
+are rejected at admission rather than silently queued. Out-of-band `cancel()`
+remains available.
+
+Explicit close unregisters forgotten-handle cleanup before releasing the
+JavaScript direct owner. Node/Bun register the public object with a
+`FinalizationRegistry` whose held record contains an opaque, exact-generation
+addon token. The registry only releases the matching JavaScript admission lease
+if the addon safely marks that generation for recovery by the next asynchronous
+open. Deno's finalizer instead starts a nonblocking, generation-guarded FFI
+close; it holds no public object or native pointer. This makes stale cleanup
+harmless without running PostgreSQL teardown
+on the JavaScript finalizer job. Broker and server registries likewise hold only
+an exact private runtime handle and private lease generation, never the public
+facade or its release callback. Their finalizers schedule asynchronous teardown;
+explicitly unregistered and superseded generations are no-ops. Registration is
+the last step of facade publication: if it throws, the opened handle is retired,
+any partial registration is unregistered, and the exact JavaScript ownership
+lease is released before `open()` rejects. None of these guards make garbage
+collection a supported replacement for explicit close.
+
+## Storage
+
+Storage resolution maps temporary or caller-owned roots to `pgdata/`. Root
+preparation and restore validate before mutation. Initialization creates PGDATA
+first and publishes the exact shared `.oliphaunt.json` descriptor last. Symlink
+roots and structural directories are rejected.
+
+Direct and broker share the native C sibling lease. The server provider prevents
+duplicate server ownership separately. Neither mechanism coordinates across
+providers, so simultaneous direct/broker/server mutation of one root is
+application error. The descriptor records the root schema, family/format pair,
+PGDATA directory name, and PostgreSQL major; it does not record JavaScript or
+Node ownership and does not reject another valid runtime family merely because
+cross-family reuse is undocumented.
+
+Direct/broker backup bytes contain the PostgreSQL physical initialization
+payload. Restore stages those bytes in a sibling directory, validates PGDATA,
+and creates the outer receiving identity. Existing nonempty destinations are
+rejected. No replacement mode exists.
+
+## Packaging
+
+Optional platform packages carry the native library/runtime, Node addon, broker
+helper, and ICU data. Resolution validates package versions and target identity
+before loading. Split native client-tool packages are independent products, not
+dependencies or locators of `@oliphaunt/ts`. Development path overrides are
+normalized internally but do not create alternate public runtime profiles.
+
+Extension selection uses the generated exact-name PostgreSQL 18 catalog. The
+adapter resolves only selected artifacts and required preload libraries. Package
+metadata, resource manifests, and materialization details remain outside the
+public SDK contract.
diff --git a/src/sdks/ts/sdk/CHANGELOG.md b/src/sdks/ts/sdk/CHANGELOG.md
new file mode 100644
index 000000000..38e4ed225
--- /dev/null
+++ b/src/sdks/ts/sdk/CHANGELOG.md
@@ -0,0 +1,46 @@
+# Changelog
+
+## Unreleased
+
+- Fail broker database objects permanently after helper or IPC failure. Close
+  and explicitly open a new object for PostgreSQL WAL recovery; the SDK never
+  substitutes a new session or replays uncertain work under the old object.
+
+## [0.2.0](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-js-v0.1.1...oliphaunt-js-v0.2.0) (2026-09-05)
+
+
+### ⚠ BREAKING CHANGES
+
+* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))
+
+### Features
+
+* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))
+* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))
+
+
+### Performance Improvements
+
+* **js:** streamline exec response handling ([#158](https://github.com/f0rr0/oliphaunt/issues/158)) ([5eaf05b](https://github.com/f0rr0/oliphaunt/commit/5eaf05b8a8d21bd974b9fcb6d618103be5689151))
+
+
+### Code Refactoring
+
+* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))
+* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))
+* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))
+
+## [0.1.1](https://github.com/f0rr0/oliphaunt/compare/oliphaunt-js-v0.1.0...oliphaunt-js-v0.1.1) (2026-08-08)
+
+
+### Bug Fixes
+
+* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))
+
+## 0.1.0 (2026-07-28)
+
+
+### Features
+
+* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))
diff --git a/src/sdks/ts/sdk/README.md b/src/sdks/ts/sdk/README.md
new file mode 100644
index 000000000..82e876501
--- /dev/null
+++ b/src/sdks/ts/sdk/README.md
@@ -0,0 +1,286 @@
+# Oliphaunt TypeScript SDK
+
+`@oliphaunt/ts` embeds PostgreSQL 18 on Node.js, Bun, and Deno through the native
+`liboliphaunt` runtime. It is the native TypeScript SDK; browser and WASIX hosts
+use the separate WASIX TypeScript package.
+
+## Open and query
+
+Import `@oliphaunt/ts/direct` or `@oliphaunt/ts/broker` to select execution mode
+through the import path. These entrypoints retain the default API and reject a
+`topology` option; `/direct` also rejects `brokerExecutable`.
+
+```ts
+import Oliphaunt from '@oliphaunt/ts';
+
+const db = await Oliphaunt.open({
+  storage: { kind: 'directory', path: '.oliphaunt' },
+  startupGUCs: { application_name: 'my-app' },
+});
+
+await db.execute('CREATE TABLE events(value text)');
+await db.execute('INSERT INTO events(value) VALUES ($1)', ['ready']);
+const result = await db.query('SELECT value FROM events');
+console.log(result.rows[0]?.value);
+await db.close();
+```
+
+Direct topology is the default. Set `topology: 'broker'` to place the embedded
+backend in a helper process while keeping the same database API. If that helper
+fails, the database object fails permanently; close it and explicitly open a new
+object on persistent storage for PostgreSQL WAL recovery. The SDK never swaps a
+new session under an existing object or replays uncertain work.
+
+Runtime packages contain neither cluster seeds nor ICU data. A new database
+uses the runtime's `initdb` unless you select a seed explicitly. Existing roots
+do not read the selected seed again. Native seed packages expose an unpacked
+directory; the SDK verifies its receipt and contents before initializing PGDATA:
+
+```ts
+import { createRequire } from 'node:module';
+import { dirname } from 'node:path';
+const require = createRequire(import.meta.url);
+const seedPackage = '@oliphaunt/seed-native-linux-x64-gnu-standard';
+const db = await Oliphaunt.open({
+  seed: {
+    directory: dirname(require.resolve(`${seedPackage}/pgdata/PG_VERSION`)),
+    manifestPath: require.resolve(`${seedPackage}/manifest.json`),
+  },
+});
+```
+
+Choose the seed package for the host target. For an ICU catalog, select its
+`-icu` seed and pass `icuData: { directory:
+dirname(require.resolve('@oliphaunt/icu/data')), manifestPath:
+require.resolve('@oliphaunt/icu/manifest') }`. The same ICU data may be selected
+without a seed. Both direct and broker topology accept these inputs. Server mode
+accepts ICU data and uses PostgreSQL `initdb`; embedded seeds are not server seeds.
+
+The database API is promise-based on Node.js, Bun, and Deno. Native PostgreSQL
+work runs in Rust addon jobs on Node/Bun and nonblocking FFI on Deno. Deno's
+addon path passes ordinary database operations but still fails Worker teardown
+with a queued stream callback, so its FFI adapter remains until that is fixed.
+First adapter resolution performs a synchronous native-module load
+(`require()` on Node/Bun, `dlopen()` on Deno); that narrow
+startup step is not a synchronous database execution mode.
+
+The deliberate public vocabulary is:
+
+- `Oliphaunt.open(config)` for direct or broker databases.
+- `execute`, decoded `query`, byte-preserving `queryRaw`, ordered `exec`,
+  non-executing `describe`, callback `transaction`, `cancel`, and `close`.
+- `execProtocolRaw` as the buffered escape hatch for protocol flows the typed
+  helpers cannot represent.
+- `execProtocolRawStream` for callback delivery of raw backend protocol chunks,
+  including COPY responses, without buffering the complete response.
+- `backup()` returning the one physical backup format as `Uint8Array`.
+- `Oliphaunt.restore(destination, bytes)` for an absent or empty destination.
+- `Oliphaunt.openServer(config)` for the distinct local-server handle.
+
+`execute` asserts one command with no rows. `query` accepts command-only or
+row-producing SQL and defaults to decoded object rows; use `rowMode: 'array'`
+for positional rows or duplicate column names, `valueMode: 'text'` for
+text-format strings, or per-query OID decoders. Object mode rejects duplicate
+names rather than discarding a value. `queryRaw` retains ordered nullable bytes
+and complete field metadata. `exec` returns each simple-query statement in wire order, and
+`describe` returns resolved parameter OIDs and optional result fields without
+executing. All structured results preserve notices and command metadata.
+
+Safe scalar parameters are inferred inside one owned Parse/Describe/Bind
+operation. Use the exported `text`, `binary`, `typedNull`, `json`, and `array`
+helpers with `postgresOids` when the type must be deterministic, and immutable
+per-query encoders for extension OIDs. Unsupported or mismatched values fail
+instead of being guessed or stringified; `undefined` is never a SQL null.
+PostgreSQL errors are structured `PostgresError` instances with query notices.
+
+The read-only `closed` property becomes true whenever the owner is terminally
+retired, including after a broker/server teardown error that occurs past its
+destructive cutoff. Transactions pin the session and mirror query/raw query, execute, exec,
+and describe. One-shot `rollback()` closes the transaction and lets the callback
+return without committing. Failed rollback or COMMIT uncertainty poisons the
+database and never triggers a misleading second control command.
+
+When a callback throws, Oliphaunt waits for a successful automatic rollback and
+then rethrows the original value unchanged. If the callback and rollback both
+fail, the transaction rejects with an `AggregateError` whose `errors` are the
+callback failure followed by the rollback failure. If an earlier independent
+database or protocol failure has already poisoned or expired transaction
+ownership and the callback then throws a different value, an `AggregateError`
+preserves the callback failure followed by that database failure; the database
+is close-only. An ordinary PostgreSQL statement error that remains safely
+rollbackable uses the first rule and is not automatically aggregated.
+
+Raw protocol is intentionally database-only and absent from callback transaction
+handles. Inside a transaction callback, do not issue manual `BEGIN`, `START
+TRANSACTION`, `COMMIT`, `END`, `ABORT`, `PREPARE TRANSACTION`, or `AND CHAIN`;
+return/throw from the callback or call `rollback()` instead. `SAVEPOINT` and
+`ROLLBACK TO` remain ordinary supported SQL. `ROLLBACK AND CHAIN` is unsupported
+contract misuse and cannot be distinguished from `ROLLBACK TO` by PostgreSQL's
+wire tag and readiness status, so Oliphaunt rejects `ROLLBACK`/`ABORT ... AND
+CHAIN` before dispatch and still validates every actual protocol boundary. A
+proven ownership escape makes the database close-only and the SDK sends no
+follow-up `COMMIT` or `ROLLBACK`.
+
+Always `await db.close()` or use `await using` for deterministic lifecycle.
+Garbage collection is only a best-effort leak guard: on Node/Bun a
+`FinalizationRegistry` gives the addon an opaque exact-generation token and only
+releases JavaScript admission after the addon queues recovery for the next
+asynchronous open. Deno's registry enqueues nonblocking generation-guarded
+terminal cleanup. Broker and server registries retain only their exact private
+runtime handle plus a private lease generation; finalizers schedule
+asynchronous teardown and an unregistered or superseded generation is a no-op.
+A stale cleanup
+cannot close a newer logical lease, but finalizer timing and errors are not
+observable and an executed fallback spends the native database process
+lifetime. Explicit close remains the path that resets the logical session for
+reuse and reports failures.
+
+In direct mode, that reuse is for the same database root and startup configuration:
+the physical backend remains bound to them until the host process exits. Open a
+restored database in a fresh host process, or use broker mode for independently
+owned database processes.
+
+A direct logical-detach failure is retryable only while the native owner proves
+it remains active. Broker/server teardown failures are terminal: later work is
+rejected and every repeated `close()` observes the same original outcome.
+Raw-stream callbacks are synchronous, cannot reenter database or transaction
+work on the same handle, and may only use `cancel()` out of band. Once `close()`
+stops ordinary admission, `cancel()` remains available while previously
+admitted work drains; runtime teardown begins only after admitted cancellation
+requests settle. A thrown callback is returned unchanged only after the runtime
+confirms that it recovered the PostgreSQL protocol boundary. An execution,
+transport, or recovery failure is authoritative instead and poisons the
+session when its state is unknown.
+
+## Backup and restore
+
+```ts
+const source = await Oliphaunt.open({
+  storage: { kind: 'directory', path: '.oliphaunt-source' },
+});
+const bytes = await source.backup();
+await source.close();
+
+await Oliphaunt.restore('.oliphaunt-restored', bytes);
+```
+
+Backup bytes are a PostgreSQL physical initialization payload containing PGDATA
+and backup metadata. They do not contain the outer `.oliphaunt.json` descriptor.
+Restore stages and validates PGDATA, then creates the receiving root identity.
+There is no archive selector and no replace-existing option.
+
+## Local server
+
+```ts
+const server = await Oliphaunt.openServer({
+  storage: { kind: 'directory', path: '.oliphaunt-server' },
+  listen: { transport: 'tcp' },
+});
+console.log(server.connectionString);
+await server.close();
+```
+
+The server handle owns only the PostgreSQL process/listener lifecycle and exposes
+its `connectionString`, `closed`, and `close`. Connect an ORM, PostgreSQL driver,
+or tool with that URI; the resulting connections own their own queries,
+transactions, raw protocol, and cancellation. The server handle cannot cancel
+or otherwise control work on external clients. TCP is fixed to IPv4 loopback;
+omit `port` for automatic assignment. Unix hosts may
+instead pass `{ transport: 'unix', directory, port? }`, which uses
+`.s.PGSQL.` and never removes the caller's directory.
+
+Use `pg_basebackup` for a standard server physical backup. Plain `pg_dump` and
+non-interactive `psql` are available from the optional endpoint-oriented
+`@oliphaunt/tools` package. `@oliphaunt/ts` does not depend on or install client
+tools.
+
+```js
+import { pgDump, psql } from '@oliphaunt/tools';
+
+const sql = await pgDump(server.connectionString, {
+  args: ['--schema-only'],
+});
+await psql(server.connectionString, { script: sql });
+```
+
+Pass the server's `connectionString` to the standard PostgreSQL tool:
+
+```sh
+pg_basebackup --dbname "$CONNECTION_STRING" --pgdata ./server-backup --wal-method=stream
+```
+
+## Storage contract
+
+A persistent managed root contains:
+
+```text
+.oliphaunt.json
+pgdata/
+```
+
+The descriptor's exact five fields record its schema, engine family, PGDATA
+directory name, PostgreSQL major, and physical format. It is shared contract
+vocabulary, not a TypeScript or Node marker. Root validation occurs before
+mutation, rejects symlink structural directories, requires complete PostgreSQL
+18 PGDATA, and publishes the descriptor last.
+
+Direct and broker coordinate through the same native sibling-lock identity. The
+server provider prevents duplicate server ownership separately. These are
+provider-local lifecycle safeguards, not a public cross-provider lock protocol.
+Simultaneous direct/broker/server mutation of one root is application error.
+
+If server open reports an existing sibling owner directory, first confirm that
+no native server owns the root. Only then remove the exact reported directory;
+the SDK deliberately does not guess that an owner is stale.
+
+## Runtime and extensions
+
+Platform native runtime, Node addon and broker packages are optional
+dependencies selected for the installed host. Seeds and ICU data are explicit,
+separate resource dependencies. Explicit library, runtime, addon,
+broker, or server paths exist for packaging and development scenarios. Native
+client-tool packages remain separate products and are not SDK dependencies.
+
+Extensions are selected by exact PostgreSQL SQL name through `extensions`.
+Runtime artifact discovery remains internal. The package intentionally does not
+publish capability profiles, supported-mode introspection, package-size reports,
+generic streams, protocol parsers, or backup format helpers.
+
+The package has one public code entrypoint, `@oliphaunt/ts`, plus
+`@oliphaunt/ts/package.json` for package metadata.
+
+## Working on this package
+
+After installing the workspace's pinned tools and running `bun install` at the
+repository root, these commands work from this directory:
+
+```sh
+moon run oliphaunt-js:build
+bun run format-check
+bun run lint
+bun run typecheck
+bun run test
+```
+
+The build compiles the shared query package first. It does not build
+PostgreSQL or the optional Node addon. `moon run oliphaunt-js:package`
+creates and checks the final archive directly from the built SDK.
+`bun run package` runs that recipe against already built inputs; `bun run format`
+rewrites formatting, while `format-check` only checks it.
+Installed-runtime tests are separate from these source and package checks.
+`moon run oliphaunt-js:test-native` builds its native dependencies and runs
+the built SDK on Node, Bun and Deno, including broker isolation, typed queries,
+backup/restore and persistent reopen. It also checks server connections with
+the PostgreSQL driver. `bun run test-native` uses already built dependencies.
+
+`src/__tests__/native-resources-smoke.mts` exercises selected resources through
+the public package API. Run it in a consumer that has the SDK, host seed package,
+and (for ICU) `@oliphaunt/icu` installed. Set `OLIPHAUNT_RESOURCE_PROFILE` to
+`none`, `standard`, or `icu`, `OLIPHAUNT_RESOURCE_SEED_PACKAGE` to the installed
+host seed identity, and `OLIPHAUNT_RESOURCE_TOPOLOGY` to `direct` or `broker`.
+Use a fresh `OLIPHAUNT_RESOURCE_SMOKE_ROOT` for each process and remove it after
+the host exits. Explicit `LIBOLIPHAUNT_PATH`, `OLIPHAUNT_INSTALL_DIR`,
+`OLIPHAUNT_NODE_ADDON`, and `OLIPHAUNT_BROKER` paths can select local built
+artifacts. The same test runs with Node TypeScript stripping, Bun, or Deno
+`run --allow-all`; it verifies queries, persisted reopen, and rejection of a
+corrupt seed without publishing PGDATA.
diff --git a/src/sdks/ts/sdk/moon.yml b/src/sdks/ts/sdk/moon.yml
new file mode 100644
index 000000000..6fbc4df24
--- /dev/null
+++ b/src/sdks/ts/sdk/moon.yml
@@ -0,0 +1,202 @@
+$schema: https://moonrepo.dev/schemas/project.json
+id: oliphaunt-js
+language: typescript
+layer: library
+stack: backend
+tags:
+  - javascript-quality
+  - sdk
+  - typescript
+  - node
+  - bun
+  - deno
+  - release-product
+dependsOn:
+  - id: oliphaunt-query-ts
+    scope: build
+  - id: cluster-seed-contract
+    scope: development
+  - id: shared-test-fixtures
+    scope: development
+  - liboliphaunt-native
+  - oliphaunt-broker
+  - oliphaunt-node-direct
+project:
+  title: Oliphaunt TypeScript SDK
+  description: "TypeScript SDK with native direct topology defaults for Node.js, Bun, and Deno."
+  owner: oliphaunt
+  release:
+    component: oliphaunt-js
+    packagePath: src/sdks/ts/sdk
+owners:
+  defaultOwner: "@oliphaunt/sdk-js"
+  paths:
+    "**/*.ts":
+      - "@oliphaunt/sdk-js"
+    tools/**:
+      - "@oliphaunt/sdk-js"
+fileGroups:
+  code:
+    - "**/*"
+    - "!**/*.md"
+    - "!moon.yml"
+    - "!release.toml"
+tasks:
+  build:
+    tags:
+      - build
+    command: bun run build
+    deps:
+      - oliphaunt-query-ts:build
+    inputs:
+      - project: oliphaunt-query-ts
+        group: sources
+      - "@group(bun-workspace)"
+      - "@group(code)"
+    outputs:
+      - lib/**/*
+    options:
+      cache: true
+  typecheck:
+    tags:
+      - quality
+      - static
+    command: bun run typecheck
+    deps:
+      - oliphaunt-query-ts:build
+    inputs:
+      - project: oliphaunt-query-ts
+        group: sources
+      - "@group(bun-workspace)"
+      - "@group(code)"
+    options:
+      cache: true
+  coverage:
+    tags:
+      - coverage
+    command: bun run coverage
+    deps:
+      - oliphaunt-query-ts:build
+    inputs:
+      - "@group(code)"
+      - "@group(bun-workspace)"
+      - project: oliphaunt-query-ts
+        group: sources
+      - project: shared-test-fixtures
+        group: fixtures
+    outputs:
+      - /target/coverage/oliphaunt-js/**/*
+    options:
+      cache: false
+      runInCI: false
+  test:
+    tags:
+      - quality
+      - unit
+    command: bun run test
+    deps:
+      - oliphaunt-query-ts:build
+    inputs:
+      - /tools/release/check_registry_publication.mts
+      - /tools/release/public-consumer-smoke.mts
+      - project: shared-test-fixtures
+        group: fixtures
+      - project: cluster-seed-contract
+        group: contract
+      - project: oliphaunt-query-ts
+        group: sources
+      - "@group(bun-workspace)"
+      - "@group(code)"
+    options:
+      cache: true
+  package:
+    tags:
+      - package
+      - release
+      - artifact-package
+      - ci-js-sdk-package
+    deps:
+      - oliphaunt-js:build
+    inputs:
+      - "@group(legal-files)"
+      - "@group(bun-workspace)"
+      - "@group(release-archive-contract)"
+      - "**/*"
+      - /src/sdks/ts/sdk/tools/check-package.mts
+      - /src/sdks/ts/sdk/tools/stage-release-artifacts.sh
+      - /tools/packaging/npm-package.mts
+      - /tools/packaging/staging.mts
+      - /tools/packaging/source-only-sdk-package.mts
+      - /tools/dev/bun.sh
+      - /src/third-party/tools/source-fetch-core.mts
+    outputs:
+      - /target/sdk-artifacts/oliphaunt-js/**/*
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+    command: bun run --cwd src/sdks/ts/sdk package
+  test-consumer:
+    tags: [consumer, integration, ci-native-consumers, platform-linux-x64-gnu]
+    command: bun run --cwd src/sdks/ts/sdk test-consumer
+    deps:
+      - package
+      - oliphaunt-query-ts:package
+      - liboliphaunt-native:package-runtime-desktop-target
+      - oliphaunt-broker:build-release-assets
+      - oliphaunt-node-direct:build-release-assets
+    inputs:
+      - tools/test-consumer.sh
+      - tools/prepare-consumer.mts
+      - tools/entrypoint-consumer.mts
+      - tools/test-native.sh
+      - src/__tests__/native-*.{ts,mts}
+      - /src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+      - /tools/packaging/portable-archive.mts
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  test-consumer-published:
+    tags: [consumer, integration, ci-native-consumers, platform-linux-x64-gnu, release-only]
+    command: bash src/sdks/ts/sdk/tools/test-consumer.sh --published-dependencies
+    deps:
+      - package
+    inputs:
+      - /tools/release/check_registry_publication.mts
+      - /tools/release/public-consumer-smoke.mts
+      - tools/test-consumer.sh
+      - tools/prepare-consumer.mts
+      - tools/published-consumer.mts
+      - tools/entrypoint-consumer.mts
+      - tools/test-native.sh
+      - src/__tests__/native-*.{ts,mts}
+      - /src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+      - /tools/packaging/portable-archive.mts
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  test-native:
+    tags:
+      - runtime
+      - smoke
+      - node
+      - bun
+      - deno
+    command: bun run --cwd src/sdks/ts/sdk test-native
+    deps:
+      - build
+      - liboliphaunt-native:build-runtime-desktop-target
+      - oliphaunt-broker:build
+      - oliphaunt-node-direct:build
+    inputs:
+      - "@group(code)"
+      - /src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+    options:
+      cache: local
+      runFromWorkspaceRoot: true
+      runInCI: false
+workspace:
+  inheritedTasks:
+    rename:
+      js-format: format
+      js-format-check: format-check
+      js-lint: lint
diff --git a/src/sdks/ts/sdk/package.json b/src/sdks/ts/sdk/package.json
new file mode 100644
index 000000000..86b550e46
--- /dev/null
+++ b/src/sdks/ts/sdk/package.json
@@ -0,0 +1,97 @@
+{
+  "name": "@oliphaunt/ts",
+  "version": "0.2.0",
+  "description": "TypeScript SDK for Oliphaunt on Node.js, Bun, and Deno.",
+  "license": "MIT",
+  "type": "module",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/f0rr0/oliphaunt.git",
+    "directory": "src/sdks/ts/sdk"
+  },
+  "bugs": {
+    "url": "https://github.com/f0rr0/oliphaunt/issues"
+  },
+  "homepage": "https://oliphaunt.dev",
+  "oliphaunt": {
+    "liboliphauntVersion": "0.2.0",
+    "brokerVersion": "0.2.0",
+    "nodeDirectAddonVersion": "0.2.0",
+    "nodeDirectAddon": "oliphaunt-node-direct",
+    "brokerHelper": "oliphaunt-broker"
+  },
+  "dependencies": {
+    "@oliphaunt/ts-query": "0.1.0"
+  },
+  "optionalDependencies": {
+    "@oliphaunt/broker-darwin-arm64": "workspace:*",
+    "@oliphaunt/broker-linux-arm64-gnu": "workspace:*",
+    "@oliphaunt/broker-linux-x64-gnu": "workspace:*",
+    "@oliphaunt/broker-win32-x64-msvc": "workspace:*",
+    "@oliphaunt/liboliphaunt-darwin-arm64": "workspace:*",
+    "@oliphaunt/liboliphaunt-linux-arm64-gnu": "workspace:*",
+    "@oliphaunt/liboliphaunt-linux-x64-gnu": "workspace:*",
+    "@oliphaunt/liboliphaunt-win32-x64-msvc": "workspace:*",
+    "@oliphaunt/node-direct-darwin-arm64": "workspace:*",
+    "@oliphaunt/node-direct-linux-arm64-gnu": "workspace:*",
+    "@oliphaunt/node-direct-linux-x64-gnu": "workspace:*",
+    "@oliphaunt/node-direct-win32-x64-msvc": "workspace:*"
+  },
+  "publishConfig": {
+    "access": "public",
+    "provenance": true
+  },
+  "exports": {
+    ".": {
+      "types": "./lib/index.d.ts",
+      "default": "./lib/index.js"
+    },
+    "./direct": {
+      "types": "./lib/direct.d.ts",
+      "default": "./lib/direct.js"
+    },
+    "./broker": {
+      "types": "./lib/broker.d.ts",
+      "default": "./lib/broker.js"
+    },
+    "./package.json": {
+      "default": "./package.json"
+    }
+  },
+  "main": "lib/index.js",
+  "module": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "files": [
+    "lib",
+    "src",
+    "README.md",
+    "ARCHITECTURE.md",
+    "CHANGELOG.md",
+    "LICENSE",
+    "THIRD_PARTY_NOTICES.md",
+    "!src/__tests__"
+  ],
+  "scripts": {
+    "build": "rm -rf lib && tsc -p tsconfig.build.json",
+    "test": "bun test --isolate --timeout=30000 ./src/__tests__ ./tools/published-consumer.test.mts",
+    "typecheck": "tsc --noEmit",
+    "clean": "rm -rf lib",
+    "coverage": "bun test --isolate --timeout=30000 ./src/__tests__ --coverage --coverage-reporter=text --coverage-reporter=lcov --coverage-dir=../../../../target/coverage/oliphaunt-js",
+    "format": "bun x --no-install biome format --write --no-errors-on-unmatched .",
+    "format-check": "bun x --no-install biome format --no-errors-on-unmatched .",
+    "lint": "bun x --no-install biome lint --diagnostic-level=error --no-errors-on-unmatched .",
+    "package": "bash tools/package.sh",
+    "test-native": "bash tools/test-native.sh",
+    "test-consumer": "bash tools/test-consumer.sh"
+  },
+  "engines": {
+    "node": ">=22.13 <25"
+  },
+  "devDependencies": {
+    "@types/node": "^24.10.1",
+    "typescript": "catalog:",
+    "pg": "^8.16.3",
+    "@types/pg": "^8.15.6",
+    "@types/bun": "catalog:"
+  }
+}
diff --git a/src/sdks/ts/sdk/release.toml b/src/sdks/ts/sdk/release.toml
new file mode 100644
index 000000000..a46054289
--- /dev/null
+++ b/src/sdks/ts/sdk/release.toml
@@ -0,0 +1,30 @@
+id = "oliphaunt-js"
+owner = "@oliphaunt/sdk-js"
+kind = "sdk"
+publish_targets = ["npm"]
+registry_packages = ["npm:@oliphaunt/ts"]
+release_artifacts = [
+  "npm-package",
+  "node-bun-deno-direct",
+  "rust-broker-helper-compatibility",
+]
+
+[compatibility_versions.oliphaunt-js-liboliphaunt]
+source_product = "liboliphaunt-native"
+path = "src/sdks/ts/sdk/package.json"
+parser = "json:oliphaunt.liboliphauntVersion"
+
+[compatibility_versions.oliphaunt-js-broker]
+source_product = "oliphaunt-broker"
+path = "src/sdks/ts/sdk/package.json"
+parser = "json:oliphaunt.brokerVersion"
+
+[compatibility_versions.oliphaunt-js-node-direct-runtime]
+source_product = "oliphaunt-node-direct"
+path = "src/sdks/ts/sdk/package.json"
+parser = "json:oliphaunt.nodeDirectAddonVersion"
+
+[compatibility_versions.oliphaunt-js-query]
+source_product = "oliphaunt-query-ts"
+path = "src/sdks/ts/sdk/package.json"
+parser = "json:dependencies.@oliphaunt/ts-query"
diff --git a/src/sdks/js/src/__tests__/asset-resolver.test.ts b/src/sdks/ts/sdk/src/__tests__/asset-resolver.test.ts
similarity index 78%
rename from src/sdks/js/src/__tests__/asset-resolver.test.ts
rename to src/sdks/ts/sdk/src/__tests__/asset-resolver.test.ts
index f344064f3..f721694ef 100644
--- a/src/sdks/js/src/__tests__/asset-resolver.test.ts
+++ b/src/sdks/ts/sdk/src/__tests__/asset-resolver.test.ts
@@ -1,48 +1,36 @@
+import { test } from 'bun:test';
 import assert from 'node:assert/strict';
 import { createHash } from 'node:crypto';
 import {
   chmod,
+  copyFile,
+  cp,
   mkdir,
   mkdtemp,
-  realpath,
   readdir,
   readFile,
   rename,
   rm,
   rmdir,
-  stat as fsStat,
   symlink,
   writeFile,
 } from 'node:fs/promises';
 import { createRequire } from 'node:module';
 import { arch, platform, tmpdir } from 'node:os';
 import { basename, dirname, join, resolve } from 'node:path';
-import { fileURLToPath } from 'node:url';
+import { fileURLToPath, pathToFileURL } from 'node:url';
 import { deflateRawSync, inflateRawSync } from 'node:zlib';
-import { test } from 'vitest';
 import { GENERATED_EXTENSION_METADATA } from '../generated/extensions.js';
-import {
-  type DenoRuntime,
-  resolvePackageRelativeUrl,
-  validatePreparedDenoRuntimeExtensions,
-} from '../native/assets-deno.js';
-import {
-  materializeNodeExtensionInstall,
-  prepareNodeExtensionInstall,
-  type ResolvedNativeInstall,
-  resolveNodeIcuDataDirectory,
-  resolveNodeNativeInstall,
-  resolvePackageRelativePath,
-  validatePreparedNodeRuntimeExtensions,
-} from '../native/assets-node.js';
+import type { ResolvedNativeInstall } from '../native/assets.js';
+import * as originalNodeAssets from '../native/assets.js';
+
+let nodeAssets = originalNodeAssets;
+let consumerRoot: string;
+
 import { liboliphauntPackageTarget } from '../native/common.js';
 import { extractTarArchive } from '../native/tar.js';
 import { extractZipArchive } from '../native/zip.js';
-import {
-  packageMetadataVersion,
-  readTypeScriptPackageJson,
-  readTypeScriptPackageVersions,
-} from './package-metadata.js';
+import { readTypeScriptPackageVersions } from './package-metadata.js';
 
 type FixtureExtensionContract = {
   sqlName: string;
@@ -108,21 +96,46 @@ function fixtureExtensionContractManifest(
   };
 }
 
+async function withConsumer(run: () => Promise): Promise {
+  consumerRoot = await mkdtemp(join(tmpdir(), 'oliphaunt-consumer-'));
+  const sdk = join(consumerRoot, 'node_modules', '@oliphaunt', 'ts');
+  try {
+    await mkdir(sdk, { recursive: true });
+    await cp(fileURLToPath(new URL('../', import.meta.url)), join(sdk, 'src'), {
+      recursive: true,
+      filter: (source) => !source.includes('__tests__') && !source.includes('node_modules'),
+    });
+    await copyFile(
+      fileURLToPath(new URL('../../package.json', import.meta.url)),
+      join(sdk, 'package.json'),
+    );
+    const target = liboliphauntPackageTarget(platform(), arch());
+    const carrier = join(consumerRoot, 'node_modules', target.packageName);
+    await mkdir(carrier, { recursive: true });
+    await copyFile(
+      require.resolve(target.packageName + '/package.json'),
+      join(carrier, 'package.json'),
+    );
+    nodeAssets = await import(pathToFileURL(join(sdk, 'src/native/assets.ts')).href);
+    await run();
+  } finally {
+    nodeAssets = originalNodeAssets;
+    await rm(consumerRoot, { recursive: true, force: true });
+  }
+}
+
 async function main(): Promise {
   packageTargetsMatchLiboliphauntPackages();
   await tarExtractionRejectsTraversal();
   await zipExtractionWritesFilesAndRejectsTraversal();
   packageMetadataPathsAreConfinedToPackageRoot();
-  await nodeResolverUsesInstalledPackages();
-  await nodeResolverUsesStandardCarrierRuntime();
-  await nodeIcuResolverAcceptsValidPortablePackage();
-  await nodeExtensionMaterializationValidatesSelections();
-  await nodeExtensionMaterializationAcceptsBuiltInPostgresDependency();
+  await withConsumer(nodeResolverUsesInstalledPackages);
+  await withConsumer(nodeResolverUsesStandardCarrierRuntime);
+  await withConsumer(nodeExtensionMaterializationValidatesSelections);
+  await withConsumer(nodeExtensionMaterializationAcceptsBuiltInPostgresDependency);
   await explicitRuntimeExtensionValidationUsesPreparedFiles();
-  await denoPreparedRuntimeRequiresSeparateEmbeddedModules();
-  await nodeExtensionMaterializationCopiesPackagePayloads();
-  await nodeExtensionMaterializationRejectsIncompletePackagePayloads();
-  await typeScriptPackageMetadataMatchesRuntimePackages();
+  await withConsumer(nodeExtensionMaterializationCopiesPackagePayloads);
+  await withConsumer(nodeExtensionMaterializationRejectsIncompletePackagePayloads);
 }
 
 async function zipExtractionWritesFilesAndRejectsTraversal(): Promise {
@@ -187,14 +200,13 @@ function packageTargetsMatchLiboliphauntPackages(): void {
 function packageMetadataPathsAreConfinedToPackageRoot(): void {
   const packageRoot = resolve('/tmp/oliphaunt-package-root');
   assert.equal(
-    resolvePackageRelativePath(packageRoot, 'runtime/bin/postgres', 'test package metadata'),
+    nodeAssets.resolvePackageRelativePath(
+      packageRoot,
+      'runtime/bin/postgres',
+      'test package metadata',
+    ),
     join(packageRoot, 'runtime/bin/postgres'),
   );
-  const packageRootUrl = new URL('file:///tmp/oliphaunt-package-root/');
-  assert.equal(
-    resolvePackageRelativeUrl(packageRootUrl, 'runtime/bin/postgres', 'test package metadata').href,
-    'file:///tmp/oliphaunt-package-root/runtime/bin/postgres',
-  );
   for (const unsafePath of [
     '',
     '../outside',
@@ -207,12 +219,7 @@ function packageMetadataPathsAreConfinedToPackageRoot(): void {
     'runtime\0outside',
   ]) {
     assert.throws(
-      () => resolvePackageRelativePath(packageRoot, unsafePath, 'test package metadata'),
-      /unsafe package metadata path/,
-      unsafePath,
-    );
-    assert.throws(
-      () => resolvePackageRelativeUrl(packageRootUrl, unsafePath, 'test package metadata'),
+      () => nodeAssets.resolvePackageRelativePath(packageRoot, unsafePath, 'test package metadata'),
       /unsafe package metadata path/,
       unsafePath,
     );
@@ -252,7 +259,7 @@ async function nodeResolverUsesInstalledPackages(): Promise {
   delete process.env.LIBOLIPHAUNT_PATH;
   delete process.env.OLIPHAUNT_RUNTIME_DIR;
   try {
-    await assert.rejects(() => resolveNodeNativeInstall(), /@oliphaunt\/liboliphaunt-/);
+    await assert.rejects(() => nodeAssets.resolveNativeInstall(), /@oliphaunt\/liboliphaunt-/);
   } finally {
     restoreEnv('LIBOLIPHAUNT_PATH', previousLibraryPath);
     restoreEnv('OLIPHAUNT_RUNTIME_DIR', previousRuntimeDir);
@@ -278,17 +285,11 @@ async function nodeResolverUsesStandardCarrierRuntime(): Promise {
     for (const tool of nativeRuntimeToolsForTarget(target.id)) {
       await writeFixtureFile(join(runtimeBin, tool), `runtime:${tool}`, createdFiles);
     }
-    await writeClusterSeedFixture(
-      join(runtimePackageRoot, 'cluster-seed'),
-      'standard',
-      target.id,
-      createdFiles,
-    );
-    const install = await resolveNodeNativeInstall();
+    const install = await nodeAssets.resolveNativeInstall();
     assert.equal(install.libraryPath, join(runtimePackageRoot, target.libraryRelativePath));
     assert.equal(install.runtimeDirectory, join(runtimePackageRoot, target.runtimeRelativePath));
     assert.equal(install.icuDataDirectory, undefined);
-    assert.equal(install.clusterSeedDirectory, join(runtimePackageRoot, 'cluster-seed'));
+    assert.equal(install.clusterSeedDirectory, undefined);
     assert.equal(install.catalogProfile, 'standard');
   } finally {
     restoreEnv('LIBOLIPHAUNT_PATH', previousLibraryPath);
@@ -297,54 +298,17 @@ async function nodeResolverUsesStandardCarrierRuntime(): Promise {
   }
 }
 
-async function nodeIcuResolverAcceptsValidPortablePackage(): Promise {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-icu-'));
-  try {
-    await writeFile(
-      join(root, 'package.json'),
-      JSON.stringify({
-        name: root,
-        version: '9.9.9',
-        oliphaunt: {
-          product: 'oliphaunt-icu',
-          kind: 'icu-data',
-          target: 'portable',
-          dataRelativePath: 'OliphauntICU.bundle/share/icu',
-          manifestRelativePath: 'OliphauntICU.bundle/manifest.properties',
-          icuDataTreeSha256: 'a'.repeat(64),
-        },
-      }),
-      'utf8',
-    );
-    const dataDirectory = join(root, 'OliphauntICU.bundle/share/icu');
-    await mkdir(dataDirectory, { recursive: true });
-    await writeFile(join(dataDirectory, 'icudt76l.dat'), 'icu');
-    await writeFile(
-      join(root, 'OliphauntICU.bundle/manifest.properties'),
-      `schema=oliphaunt-icu-data-v1\nartifactRole=icu-data\nicuDataVersion=76.1\nicuDataForm=files-le\nicuDataTreeSha256=${'a'.repeat(64)}\n`,
-      'utf8',
-    );
-    assert.equal(await resolveNodeIcuDataDirectory('9.9.9', root), await realpath(dataDirectory));
-    await assert.rejects(
-      () => resolveNodeIcuDataDirectory('9.9.8', root),
-      /does not match @oliphaunt\/ts icuVersion/,
-    );
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-}
-
 async function nodeExtensionMaterializationValidatesSelections(): Promise {
   const install: ResolvedNativeInstall = {
     libraryPath: '/tmp/liboliphaunt-test.so',
   };
-  assert.equal(await materializeNodeExtensionInstall(install, []), install);
+  assert.equal(await nodeAssets.materializeExtensionInstall(install, []), install);
   await assert.rejects(
-    () => materializeNodeExtensionInstall(install, ['not_a_real_extension']),
+    () => nodeAssets.materializeExtensionInstall(install, ['not_a_real_extension']),
     /unknown Oliphaunt extension id/,
   );
   await assert.rejects(
-    () => materializeNodeExtensionInstall(install, ['hstore']),
+    () => nodeAssets.materializeExtensionInstall(install, ['hstore']),
     /native extension packages require a package-managed runtime directory/,
   );
 }
@@ -405,7 +369,7 @@ async function nodeExtensionMaterializationAcceptsBuiltInPostgresDependency(): P
     await writeFile(join(extensionDirectory, 'pgtap-core--1.3.5.sql'), 'owned prefixed SQL');
     await mkdir(installRuntime, { recursive: true });
 
-    const installed = await materializeNodeExtensionInstall(
+    const installed = await nodeAssets.materializeExtensionInstall(
       { libraryPath, runtimeDirectory: installRuntime },
       ['pgtap'],
     );
@@ -428,7 +392,7 @@ async function nodeExtensionMaterializationAcceptsBuiltInPostgresDependency(): P
     );
     await assert.rejects(
       () =>
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'pgtap',
         ]),
       /member pgtap is incompatible with the SDK dependency contract/,
@@ -463,14 +427,14 @@ async function explicitRuntimeExtensionValidationUsesPreparedFiles(): Promise
-        validatePreparedNodeRuntimeExtensions({ libraryPath, runtimeDirectory: invalidRuntime }, [
-          'hstore',
-        ]),
+        nodeAssets.validatePreparedNativeRuntimeExtensions(
+          { libraryPath, runtimeDirectory: invalidRuntime },
+          ['hstore'],
+        ),
       /explicit native runtimeDirectory is missing hstore.control/,
     );
   } finally {
@@ -490,102 +455,6 @@ async function explicitRuntimeExtensionValidationUsesPreparedFiles(): Promise {
-  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-deno-prepared-runtime-'));
-  const runtime = join(root, 'runtime');
-  const embeddedModules = join(runtime, 'lib/modules');
-  const deno = fsBackedDenoValidationRuntime();
-  try {
-    await writePreparedHstoreRuntime(runtime, 'linux-x64-gnu');
-
-    const preferred = await validatePreparedDenoRuntimeExtensions({
-      deno,
-      runtimeDirectory: runtime,
-      extensions: ['hstore'],
-      source: 'Deno test runtime',
-    });
-    assert.equal(preferred.runtimeDirectory, runtime);
-    assert.equal(preferred.moduleDirectory, embeddedModules);
-
-    await rm(join(embeddedModules, 'hstore.so'));
-    await assert.rejects(
-      () =>
-        validatePreparedDenoRuntimeExtensions({
-          deno,
-          runtimeDirectory: runtime,
-          extensions: ['hstore'],
-          source: 'Deno test runtime',
-        }),
-      /module directory is missing required file hstore[.]so/,
-    );
-
-    await writeFile(join(embeddedModules, 'hstore.so'), 'embedded hstore');
-    await rm(join(embeddedModules, 'dict_snowball.so'));
-    await assert.rejects(
-      () =>
-        validatePreparedDenoRuntimeExtensions({
-          deno,
-          runtimeDirectory: runtime,
-          extensions: ['hstore'],
-          source: 'Deno test runtime',
-        }),
-      /module directory is missing required file dict_snowball[.]so/,
-    );
-
-    await writeFile(join(embeddedModules, 'dict_snowball.so'), 'embedded dict_snowball');
-    await rm(join(embeddedModules, 'plpgsql.so'));
-    await assert.rejects(
-      () =>
-        validatePreparedDenoRuntimeExtensions({
-          deno,
-          runtimeDirectory: runtime,
-          extensions: ['hstore'],
-          source: 'Deno test runtime',
-        }),
-      /module directory is missing required file plpgsql[.]so/,
-    );
-
-    await rm(embeddedModules, { recursive: true });
-    await assert.rejects(
-      () =>
-        validatePreparedDenoRuntimeExtensions({
-          deno,
-          runtimeDirectory: runtime,
-          extensions: ['hstore'],
-          source: 'Deno test runtime',
-        }),
-      /module directory is missing required file hstore[.]so/,
-    );
-  } finally {
-    await rm(root, { recursive: true, force: true });
-  }
-}
-
-function fsBackedDenoValidationRuntime(): DenoRuntime {
-  return {
-    build: { os: 'linux', arch: 'x86_64' },
-    async readTextFile(path: string | URL) {
-      return readFile(path, 'utf8');
-    },
-    async *readDir(path: string | URL) {
-      for (const entry of await readdir(path, { withFileTypes: true })) {
-        yield {
-          name: entry.name,
-          isFile: entry.isFile(),
-          isDirectory: entry.isDirectory(),
-        };
-      }
-    },
-    async stat(path: string | URL) {
-      const metadata = await fsStat(path);
-      return {
-        isFile: metadata.isFile(),
-        isDirectory: metadata.isDirectory(),
-      };
-    },
-  };
-}
-
 async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise {
   const target = liboliphauntPackageTarget(platform(), arch());
   const { liboliphauntVersion } = await readTypeScriptPackageVersions();
@@ -765,7 +634,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /missing declared data file\(s\).*oliphaunt-skew\/frozen\.dat/,
@@ -836,7 +705,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /extension contract fields must be exactly/,
@@ -856,7 +725,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /extension contract members\[.*\] fields must be exactly/,
@@ -872,7 +741,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /member hstore is incompatible with the SDK dependency contract/,
@@ -882,7 +751,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /undeclared extension SQL\/control file.*foreign\.control/,
@@ -934,9 +803,10 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-          materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
-            'hstore',
-          ]),
+          nodeAssets.materializeExtensionInstall(
+            { libraryPath, runtimeDirectory: installRuntime },
+            ['hstore'],
+          ),
         expected,
       );
       await rm(join(targetRoot, relativePath));
@@ -955,7 +825,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /hstore\.control and canonical base installation SQL/,
@@ -968,7 +838,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /hstore\.control and canonical base installation SQL/,
@@ -985,7 +855,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /uses the physical carrier schema; expected oliphaunt-npm-extension-bundle-v1/,
@@ -1002,7 +872,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /runtime member hstore must declare identity=null/,
@@ -1019,7 +889,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /runtime member hstore must declare identity=null/,
@@ -1036,7 +906,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /repeats a canonical member or archive path/,
@@ -1070,7 +940,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /must declare one runtime path for every exact member/,
@@ -1103,7 +973,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /invalid member module paths/,
@@ -1117,7 +987,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /bundle manifest does not point to an existing file/,
@@ -1131,7 +1001,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /extension contract does not point to an existing file/,
@@ -1145,7 +1015,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /bundle member hstore does not point to an existing file/,
@@ -1159,7 +1029,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /contains symbolic link lib\/postgresql/,
@@ -1171,7 +1041,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /bundle member pg_trgm does not match its exact bytes and sha256/,
@@ -1183,7 +1053,7 @@ async function nodeExtensionMaterializationCopiesPackagePayloads(): Promise
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'hstore',
         ]),
       /does not match its exact bytes and sha256/,
@@ -1319,7 +1189,7 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
     await chmod(vectorLicense, 0o644);
     await assert.rejects(
       () =>
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'vector',
         ]),
       /extension runtime path must be exactly runtime/,
@@ -1364,7 +1234,7 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
         },
       }),
     );
-    const independentlyVersionedInstall = await materializeNodeExtensionInstall(
+    const independentlyVersionedInstall = await nodeAssets.materializeExtensionInstall(
       { libraryPath, runtimeDirectory: installRuntime },
       ['vector'],
     );
@@ -1391,7 +1261,7 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
     await rm(skewData);
     await assert.rejects(
       () =>
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'vector',
         ]),
       /missing declared data file\(s\).*oliphaunt-skew\/new-version\.dat/,
@@ -1404,7 +1274,7 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
     await rm(canonicalLicense);
     await assert.rejects(
       () =>
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'vector',
         ]),
       /missing declared license file\(s\).*share\/licenses\/vector\/LICENSE/,
@@ -1415,7 +1285,7 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
     await writeFile(canonicalLicense, 'tampered vector license');
     await assert.rejects(
       () =>
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'vector',
         ]),
       /license file share\/licenses\/vector\/LICENSE does not match declared SHA-256/,
@@ -1423,20 +1293,24 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
     await writeFile(canonicalLicense, canonicalLicenseBytes);
 
     if (platform() !== 'win32') {
-      for (const unsafeMode of [0o664, 0o4644]) {
+      for (const unsafeMode of [0o666, 0o755, 0o4644]) {
         await chmod(canonicalLicense, unsafeMode);
         await assert.rejects(
           () =>
-            materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
-              'vector',
-            ]),
+            nodeAssets.materializeExtensionInstall(
+              { libraryPath, runtimeDirectory: installRuntime },
+              ['vector'],
+            ),
           /license file share\/licenses\/vector\/LICENSE mode is not a safe installed representation of declared 0644/,
         );
       }
-      await chmod(canonicalLicense, 0o600);
-      await materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
-        'vector',
-      ]);
+      for (const installedMode of [0o600, 0o644, 0o664]) {
+        await chmod(canonicalLicense, installedMode);
+        await nodeAssets.materializeExtensionInstall(
+          { libraryPath, runtimeDirectory: installRuntime },
+          ['vector'],
+        );
+      }
       await chmod(canonicalLicense, 0o644);
     }
 
@@ -1444,7 +1318,7 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
     await writeFile(extraLicense, 'undeclared legal material');
     await assert.rejects(
       () =>
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'vector',
         ]),
       /undeclared runtime file.*share\/licenses\/vector\/EXTRA/,
@@ -1540,9 +1414,10 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
       );
       await assert.rejects(
         () =>
-          materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
-            'vector',
-          ]),
+          nodeAssets.materializeExtensionInstall(
+            { libraryPath, runtimeDirectory: installRuntime },
+            ['vector'],
+          ),
         expected,
       );
     }
@@ -1582,7 +1457,7 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
     );
     await assert.rejects(
       () =>
-        materializeNodeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
+        nodeAssets.materializeExtensionInstall({ libraryPath, runtimeDirectory: installRuntime }, [
           'vector',
         ]),
       /contains symbolic link lib\/modules/,
@@ -1598,66 +1473,6 @@ async function nodeExtensionMaterializationRejectsIncompletePackagePayloads(): P
   }
 }
 
-async function typeScriptPackageMetadataMatchesRuntimePackages(): Promise {
-  const packageJson = await readTypeScriptPackageJson();
-  const liboliphauntVersion = packageMetadataVersion(packageJson, 'liboliphauntVersion');
-  const brokerVersion = packageMetadataVersion(packageJson, 'brokerVersion');
-  const nodeDirectVersion = packageMetadataVersion(packageJson, 'nodeDirectAddonVersion');
-  const icuVersion = packageMetadataVersion(packageJson, 'icuVersion');
-  assert.equal(packageJson.oliphaunt?.icuPackage, '@oliphaunt/icu');
-  assert.equal(icuVersion, liboliphauntVersion);
-  assert.equal(packageJson.oliphaunt?.nodeDirectAddon, 'oliphaunt-node-direct');
-  assert.equal(packageJson.oliphaunt?.brokerHelper, 'oliphaunt-broker');
-  assert.deepEqual(packageJson.dependencies, { '@oliphaunt/js-core': 'workspace:*' });
-  assert.deepEqual(packageJson.bundledDependencies, ['@oliphaunt/js-core']);
-  const optionalDependencyNames = [
-    '@oliphaunt/broker-darwin-arm64',
-    '@oliphaunt/broker-linux-arm64-gnu',
-    '@oliphaunt/broker-linux-x64-gnu',
-    '@oliphaunt/broker-win32-x64-msvc',
-    '@oliphaunt/liboliphaunt-darwin-arm64',
-    '@oliphaunt/liboliphaunt-linux-arm64-gnu',
-    '@oliphaunt/liboliphaunt-linux-x64-gnu',
-    '@oliphaunt/liboliphaunt-win32-x64-msvc',
-    '@oliphaunt/node-direct-darwin-arm64',
-    '@oliphaunt/node-direct-linux-arm64-gnu',
-    '@oliphaunt/node-direct-linux-x64-gnu',
-    '@oliphaunt/node-direct-win32-x64-msvc',
-  ];
-  assert.deepEqual(
-    Object.keys(packageJson.optionalDependencies ?? {}).sort(),
-    optionalDependencyNames,
-  );
-  for (const packageName of optionalDependencyNames.slice(0, 4)) {
-    assert.equal(packageJson.optionalDependencies?.[packageName], 'workspace:*');
-  }
-  for (const packageName of optionalDependencyNames.slice(4, 8)) {
-    assert.equal(packageJson.optionalDependencies?.[packageName], 'workspace:*');
-  }
-  for (const packageName of optionalDependencyNames.slice(8, 12)) {
-    assert.equal(packageJson.optionalDependencies?.[packageName], 'workspace:*');
-  }
-  await assertPlatformPackageTarget(
-    '../../../../runtimes/liboliphaunt/native/packages/linux-x64-gnu/package.json',
-    '@oliphaunt/liboliphaunt-linux-x64-gnu',
-    liboliphauntVersion,
-    'linux-x64-gnu',
-    'runtime',
-  );
-  await assertPlatformPackageTarget(
-    '../../../../runtimes/broker/packages/linux-x64-gnu/package.json',
-    '@oliphaunt/broker-linux-x64-gnu',
-    brokerVersion,
-    'linux-x64-gnu',
-  );
-  await assertPlatformPackageTarget(
-    '../../../../runtimes/node-direct/packages/linux-x64-gnu/package.json',
-    '@oliphaunt/node-direct-linux-x64-gnu',
-    nodeDirectVersion,
-    'linux-x64-gnu',
-  );
-}
-
 type TarEntry = {
   path: string;
   mode: number;
@@ -1824,7 +1639,7 @@ function restoreEnv(name: string, value: string | undefined): void {
 const require = createRequire(import.meta.url);
 
 function packageRoot(packageName: string): string {
-  return dirname(require.resolve(`${packageName}/package.json`));
+  return join(consumerRoot, 'node_modules', packageName);
 }
 
 function contribBundleMembers(): string[] {
@@ -1836,7 +1651,7 @@ function contribBundleMembers(): string[] {
 }
 
 function nativeResolverPackageScopeRoot(): string {
-  return fileURLToPath(new URL('../native/node_modules/@oliphaunt/', import.meta.url));
+  return join(consumerRoot, 'node_modules', '@oliphaunt');
 }
 
 function nativeResolverPackageRoot(packageName: string): string {
@@ -1874,44 +1689,6 @@ async function writeFixtureFile(
   createdFiles.push(path);
 }
 
-async function writeClusterSeedFixture(
-  root: string,
-  profile: 'standard' | 'icu',
-  target: string,
-  createdFiles: string[],
-): Promise {
-  if (profile === 'standard') {
-    await writeFixtureFile(
-      join(dirname(root), 'manifest.properties'),
-      `schema=oliphaunt-native-runtime-carrier-v1\nclusterSeedTarget=${target}\nclusterSeedRelativePath=cluster-seed\nicuClusterSeedRelativePath=cluster-seed-icu\n`,
-      createdFiles,
-    );
-  }
-  await writeFixtureFile(join(root, 'files', 'PG_VERSION'), '18\n', createdFiles);
-  await writeFixtureFile(join(root, 'files', 'global', 'pg_control'), 'control', createdFiles);
-  await writeFixtureFile(
-    join(root, 'manifest.properties'),
-    [
-      'schema=oliphaunt-runtime-resources-v1',
-      'layout=oliphaunt-cluster-seed-v1',
-      `artifactRole=cluster-seed-${profile}`,
-      `catalogProfile=${profile}`,
-      `target=${target}`,
-      'postgresMajor=18',
-      'physicalFormat=native-pg18-v1',
-      `compatibilityKey=native-pg18-${target}-v1`,
-      'initialSuperuser=postgres',
-      `icuDataVersion=${profile === 'icu' ? '76.1' : ''}`,
-      `icuDataForm=${profile === 'icu' ? 'files-le' : ''}`,
-      `icuDataTreeSha256=${profile === 'icu' ? 'a'.repeat(64) : ''}`,
-      `runtimeFeatures=${profile === 'icu' ? 'icu' : ''}`,
-      'cacheKey=fixture-seed',
-      '',
-    ].join('\n'),
-    createdFiles,
-  );
-}
-
 async function removeFixtureFiles(files: string[], stopRoots: string[]): Promise {
   for (const file of files.reverse()) {
     await rm(file, { force: true });
@@ -1965,28 +1742,6 @@ function nativeModuleSuffixForTarget(target: string): string {
   return '.so';
 }
 
-async function assertPlatformPackageTarget(
-  relativePath: string,
-  expectedName: string,
-  expectedVersion: string,
-  expectedTarget: string,
-  expectedRuntimeRelativePath?: string,
-): Promise {
-  const packageJson = JSON.parse(
-    await readFile(new URL(relativePath, import.meta.url), 'utf8'),
-  ) as {
-    name?: string;
-    version?: string;
-    oliphaunt?: { target?: string; runtimeRelativePath?: string };
-  };
-  assert.equal(packageJson.name, expectedName);
-  assert.equal(packageJson.version, expectedVersion);
-  assert.equal(packageJson.oliphaunt?.target, expectedTarget);
-  if (expectedRuntimeRelativePath !== undefined) {
-    assert.equal(packageJson.oliphaunt?.runtimeRelativePath, expectedRuntimeRelativePath);
-  }
-}
-
 test('asset resolver', async () => {
   await main();
 });
diff --git a/src/sdks/ts/sdk/src/__tests__/broker-frames.test.ts b/src/sdks/ts/sdk/src/__tests__/broker-frames.test.ts
new file mode 100644
index 000000000..631e19c56
--- /dev/null
+++ b/src/sdks/ts/sdk/src/__tests__/broker-frames.test.ts
@@ -0,0 +1,42 @@
+import assert from 'node:assert/strict';
+import { test } from 'bun:test';
+import {
+  decodeBrokerRequest,
+  decodeBrokerResponse,
+  encodeBrokerRequest,
+  encodeBrokerResponse,
+  readBrokerRequest,
+  readBrokerResponse,
+} from '../runtime/broker-frames.js';
+import { MemoryDuplexStream } from '../runtime/byte-stream.js';
+
+test('broker management carries authentication, backup and close; SQL uses PostgreSQL', async () => {
+  for (const request of [
+    { kind: 'authenticate', token: 'secret' },
+    { kind: 'backup' },
+    { kind: 'close' },
+  ] as const) {
+    assert.deepEqual(
+      await readBrokerRequest(new MemoryDuplexStream([encodeBrokerRequest(request)])),
+      request,
+    );
+  }
+  for (const response of [
+    { kind: 'ok', bytes: new Uint8Array([1, 2, 3]) },
+    { kind: 'error', message: 'backup failed' },
+  ] as const) {
+    assert.deepEqual(
+      await readBrokerResponse(new MemoryDuplexStream([encodeBrokerResponse(response)])),
+      response,
+    );
+  }
+  assert.throws(() => decodeBrokerRequest(1, new Uint8Array()), /unknown broker request/);
+  assert.throws(() => decodeBrokerResponse(104, new Uint8Array()), /unknown broker response/);
+  assert.throws(() => decodeBrokerRequest(5, new Uint8Array([1])), /unexpectedly had a payload/);
+  assert.throws(() => decodeBrokerResponse(102, new Uint8Array([0xff])), /not UTF-8/);
+  const header = encodeBrokerRequest({ kind: 'backup' });
+  new DataView(header.buffer).setBigUint64(5, 128n * 1024n * 1024n + 1n);
+  await assert.rejects(readBrokerRequest(new MemoryDuplexStream([header])), /exceeds limit/);
+  header[0] = 0;
+  await assert.rejects(readBrokerRequest(new MemoryDuplexStream([header])), /magic mismatch/);
+});
diff --git a/src/sdks/ts/sdk/src/__tests__/client.test.ts b/src/sdks/ts/sdk/src/__tests__/client.test.ts
new file mode 100644
index 000000000..65cbe975b
--- /dev/null
+++ b/src/sdks/ts/sdk/src/__tests__/client.test.ts
@@ -0,0 +1,1548 @@
+import assert from 'node:assert/strict';
+import { mkdtemp, rm, stat } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { test } from 'bun:test';
+
+import { createOliphauntClient } from '../client.js';
+import type {
+  NativeBinding,
+  NativeBindingOptions,
+  NativeHandle,
+  NativeOpenConfig,
+  NativeRestoreOptions,
+} from '../native/types.js';
+import type { CommandResult } from '../query.js';
+import type {
+  OliphauntDatabase,
+  OliphauntTransaction,
+  OpenConfig,
+  ServerOpenConfig,
+} from '../types.js';
+import type { RuntimeBinding } from '../runtime/types.js';
+
+// OLIPHAUNT_DOCS_SNIPPET typescript-quickstart
+test('exposes the minimal database lifecycle and byte backup contract', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-client-'));
+  const binding = new FakeBinding();
+  const bindingOptions: NativeBindingOptions[] = [];
+  const client = createOliphauntClient((options = {}) => {
+    bindingOptions.push(options);
+    return binding;
+  });
+  try {
+    const db = await client.open({
+      storage: { kind: 'directory', path: root },
+      startupGUCs: { work_mem: '16MB' },
+      username: 'app',
+      database: 'appdb',
+    });
+    assert.deepEqual(binding.openCalls[0], {
+      pgdata: join(root, 'pgdata'),
+      runtimeDirectory: undefined,
+      username: 'app',
+      database: 'appdb',
+      extensions: [],
+      startupArgs: ['-c', 'work_mem=16MB'],
+    });
+    assert.deepEqual(await db.execute('UPDATE things SET value = 1'), {
+      commandTag: 'UPDATE 3',
+      rowCount: 3,
+      notices: [],
+    });
+    assert.equal(binding.requestTags.at(-1), 'P');
+    const result = await db.query('SELECT value FROM things');
+    assert.equal(binding.requestTags.at(-1), 'P');
+    assert.equal(result.commandTag, 'SELECT 1');
+    assert.equal(result.rowCount, 1);
+    assert.deepEqual(result.rows, [{ value: 'ok' }]);
+    const streamed: Uint8Array[] = [];
+    await db.execProtocolRawStream(new Uint8Array([0x51]), (chunk) => {
+      streamed.push(chunk);
+    });
+    assert.equal(streamed.length, 1);
+    assert.deepEqual(await db.backup(), new Uint8Array([1, 2, 3]));
+    await db.execute('CHECKPOINT');
+    await db.cancel();
+    await db.close();
+    assert.equal(binding.cancelCalls, 1);
+    assert.equal(binding.detachCalls, 1);
+    await assert.rejects(() => db.execute('SELECT 1'), /closed/);
+
+    await client.restore(join(root, 'restored'), new Uint8Array([7, 8]), {
+      libraryPath: '/opt/oliphaunt/liboliphaunt.so',
+    });
+    assert.deepEqual(binding.restoreCalls, [
+      { destination: join(root, 'restored'), bytes: new Uint8Array([7, 8]) },
+    ]);
+    assert.deepEqual(bindingOptions, [
+      { libraryPath: undefined },
+      { libraryPath: '/opt/oliphaunt/liboliphaunt.so' },
+    ]);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('snapshots open configuration before asynchronous storage work', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-open-snapshot-'));
+  const direct = new FakeBinding();
+  const broker = new FakeBinding();
+  const brokerRuntime = broker as unknown as RuntimeBinding;
+  brokerRuntime.close = async (handle) => {
+    await broker.detach(handle);
+    return { state: 'closed' };
+  };
+  const startupGUCs: Record = { work_mem: '8MB' };
+  const extensions: string[] = [];
+  const config: OpenConfig = {
+    topology: 'broker',
+    storage: { kind: 'directory', path: root },
+    startupGUCs,
+    username: 'before',
+    database: 'before',
+    extensions,
+  };
+  const client = createOliphauntClient(() => direct, { broker: brokerRuntime });
+
+  try {
+    const opening = client.open(config);
+    config.topology = 'direct';
+    config.username = 'after';
+    config.database = 'after';
+    startupGUCs.work_mem = '64MB';
+    extensions.push('vector');
+
+    const database = await opening;
+    assert.equal(direct.openCalls.length, 0);
+    assert.equal(broker.openCalls.length, 1);
+    assert.deepEqual(broker.openCalls[0], {
+      topology: 'broker',
+      instanceDirectory: root,
+      pgdata: join(root, 'pgdata'),
+      temporaryDirectory: false,
+      startupArgs: ['-c', 'work_mem=8MB'],
+      username: 'before',
+      database: 'before',
+      extensions: [],
+      libraryPath: undefined,
+      runtimeDirectory: undefined,
+      brokerExecutable: undefined,
+      serverExecutable: undefined,
+      serverListen: undefined,
+    });
+    await database.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('rejects an unknown current topology before materializing storage', async () => {
+  const scratch = await mkdtemp(join(tmpdir(), 'oliphaunt-js-invalid-topology-'));
+  const instanceDirectory = join(scratch, 'must-not-exist');
+  const binding = new FakeBinding();
+  const client = createOliphauntClient(() => binding);
+
+  try {
+    await assert.rejects(
+      client.open({
+        topology: 'worker',
+        storage: { kind: 'directory', path: instanceDirectory },
+      } as unknown as OpenConfig),
+      /topology must be "direct" or "broker"/,
+    );
+    assert.equal(binding.openCalls.length, 0);
+    await assert.rejects(stat(instanceDirectory), { code: 'ENOENT' });
+  } finally {
+    await rm(scratch, { recursive: true, force: true });
+  }
+});
+
+test('rejects storage-owned startup GUCs before materializing storage', async () => {
+  const scratch = await mkdtemp(join(tmpdir(), 'oliphaunt-js-owned-guc-'));
+  const instanceDirectory = join(scratch, 'must-not-exist');
+  const binding = new FakeBinding();
+  const client = createOliphauntClient(() => binding);
+
+  try {
+    await assert.rejects(
+      client.open({
+        storage: { kind: 'directory', path: instanceDirectory },
+        startupGUCs: { CONFIG_FILE: '/tmp/redirect.conf' },
+      }),
+      /Oliphaunt owns PostgreSQL startup GUC 'config_file'/,
+    );
+    assert.equal(binding.openCalls.length, 0);
+    await assert.rejects(stat(instanceDirectory), { code: 'ENOENT' });
+  } finally {
+    await rm(scratch, { recursive: true, force: true });
+  }
+});
+
+test('snapshots server storage and nested configuration before asynchronous work', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-server-snapshot-'));
+  const movedRoot = join(root, 'mutated');
+  const server = new FakeBinding();
+  const serverRuntime = server as unknown as RuntimeBinding;
+  serverRuntime.close = async (handle) => {
+    await server.detach(handle);
+    return { state: 'closed' };
+  };
+  serverRuntime.connectionString = () => 'postgresql://postgres@127.0.0.1:15432/postgres';
+  const storage = { kind: 'directory' as const, path: root };
+  const listen = { transport: 'tcp' as const, port: 15432 };
+  const startupGUCs: Record = { work_mem: '8MB' };
+  const extensions: string[] = [];
+  const config: ServerOpenConfig = { storage, listen, startupGUCs, extensions };
+  const client = createOliphauntClient(() => new FakeBinding(), { server: serverRuntime });
+
+  try {
+    const opening = client.openServer(config);
+    storage.path = movedRoot;
+    listen.port = 25432;
+    startupGUCs.work_mem = '64MB';
+    extensions.push('vector');
+
+    const database = await opening;
+    assert.equal(database.connectionString, 'postgresql://postgres@127.0.0.1:15432/postgres');
+    for (const operation of [
+      'execute',
+      'query',
+      'queryRaw',
+      'exec',
+      'describe',
+      'execProtocolRaw',
+      'execProtocolRawStream',
+      'backup',
+      'cancel',
+      'transaction',
+    ]) {
+      assert.equal(operation in database, false, `${operation} must not leak from server facade`);
+    }
+    assert.equal(server.openCalls.length, 1);
+    assert.deepEqual(server.openCalls[0], {
+      topology: 'server',
+      instanceDirectory: root,
+      pgdata: join(root, 'pgdata'),
+      temporaryDirectory: false,
+      startupArgs: ['-c', 'work_mem=8MB'],
+      username: 'postgres',
+      database: 'postgres',
+      extensions: [],
+      libraryPath: undefined,
+      runtimeDirectory: undefined,
+      brokerExecutable: undefined,
+      serverExecutable: undefined,
+      serverListen: { transport: 'tcp', port: 15432 },
+    });
+    await database.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('server open preserves both a missing endpoint and handle cleanup failure', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-server-open-failure-'));
+  const binding = new FakeBinding();
+  const cleanupFailure = new Error('server handle cleanup failed');
+  let closeCalls = 0;
+  const runtime = binding as unknown as RuntimeBinding;
+  runtime.close = async () => {
+    closeCalls += 1;
+    return { state: 'terminal', error: cleanupFailure };
+  };
+  const client = createOliphauntClient(() => new FakeBinding(), { server: runtime });
+
+  try {
+    const failure = await client
+      .openServer({ storage: { kind: 'directory', path: root } })
+      .catch((error: unknown) => error);
+    assert.ok(failure instanceof AggregateError);
+    assert.equal(failure.errors[0]?.message, 'native server did not expose its connection string');
+    assert.equal(failure.errors[1], cleanupFailure);
+    assert.equal(closeCalls, 1);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('copies restore bytes before asynchronous binding resolution', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-restore-snapshot-'));
+  const binding = new FakeBinding();
+  const releaseBinding = deferred();
+  const client = createOliphauntClient(async () => {
+    await releaseBinding.promise;
+    return binding;
+  });
+  const backup = Buffer.from([0, 7, 8, 0]).subarray(1, 3);
+
+  try {
+    const restoring = client.restore(join(root, 'restored'), backup);
+    backup.fill(0);
+    releaseBinding.resolve();
+    await restoring;
+    assert.deepEqual(binding.restoreCalls, [
+      { destination: join(root, 'restored'), bytes: new Uint8Array([7, 8]) },
+    ]);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('transactions commit, roll back body failures, and never roll back a failed commit', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-transaction-'));
+  try {
+    const successful = new FakeBinding();
+    const db = await createOliphauntClient(() => successful).open({
+      storage: { kind: 'directory', path: join(root, 'success') },
+    });
+    const value = await db.transaction(async (transaction) => {
+      await transaction.execute('UPDATE things SET value = 2');
+      return 42;
+    });
+    assert.equal(value, 42);
+    assert.deepEqual(successful.sqlCalls.slice(-3), [
+      'BEGIN',
+      'UPDATE things SET value = 2',
+      'COMMIT',
+    ]);
+    await db.close();
+
+    const bodyFailure = new FakeBinding();
+    const rollingBack = await createOliphauntClient(() => bodyFailure).open({
+      storage: { kind: 'directory', path: join(root, 'rollback') },
+    });
+    await assert.rejects(
+      () =>
+        rollingBack.transaction(() => {
+          throw new Error('body failed');
+        }),
+      /body failed/,
+    );
+    assert.deepEqual(bodyFailure.sqlCalls.slice(-2), ['BEGIN', 'ROLLBACK']);
+    await rollingBack.close();
+
+    const commitFailure = new FakeBinding();
+    commitFailure.failSql = 'COMMIT';
+    const uncertain = await createOliphauntClient(() => commitFailure).open({
+      storage: { kind: 'directory', path: join(root, 'commit') },
+    });
+    await assert.rejects(() => uncertain.transaction(() => 'done'), /commit failed/);
+    assert.deepEqual(commitFailure.sqlCalls.slice(-2), ['BEGIN', 'COMMIT']);
+    assert.equal(commitFailure.sqlCalls.includes('ROLLBACK'), false);
+    await assert.rejects(() => uncertain.execute('SELECT 1'), /state is unknown/);
+    await uncertain.close();
+
+    const poisonedCallback = new FakeBinding();
+    poisonedCallback.failSql = 'UPDATE transport_unknown';
+    const poisonedCallbackDb = await createOliphauntClient(() => poisonedCallback).open({
+      storage: { kind: 'directory', path: join(root, 'poisoned-callback') },
+    });
+    const businessFailure = new Error('business callback failed');
+    let databaseFailure: unknown;
+    const combinedFailure = await poisonedCallbackDb
+      .transaction(async (transaction) => {
+        try {
+          await transaction.execute('UPDATE transport_unknown');
+        } catch (error) {
+          databaseFailure = error;
+        }
+        throw businessFailure;
+      })
+      .catch((error: unknown) => error);
+    assert.ok(combinedFailure instanceof AggregateError);
+    assert.deepEqual(combinedFailure.errors, [businessFailure, databaseFailure]);
+    assert.match(combinedFailure.message, /independent database failure/);
+    assert.deepEqual(poisonedCallback.sqlCalls.slice(-2), ['BEGIN', 'UPDATE transport_unknown']);
+    const poisonedRequestCount = poisonedCallback.requests.length;
+    await assert.rejects(() => poisonedCallbackDb.execute('SELECT 1'), /state is unknown/);
+    assert.equal(poisonedCallback.requests.length, poisonedRequestCount);
+    await poisonedCallbackDb.close();
+
+    const malformedCommit = new FakeBinding();
+    malformedCommit.responseForSql.set('COMMIT', Uint8Array.from(backendMessage(0x5a, [0x49])));
+    const malformed = await createOliphauntClient(() => malformedCommit).open({
+      storage: { kind: 'directory', path: join(root, 'malformed-commit') },
+    });
+    await assert.rejects(
+      () => malformed.transaction(() => 'done'),
+      /omitted CommandComplete or EmptyQueryResponse/,
+    );
+    assert.deepEqual(malformedCommit.sqlCalls.slice(-2), ['BEGIN', 'COMMIT']);
+    assert.equal(malformedCommit.sqlCalls.includes('ROLLBACK'), false);
+    await assert.rejects(() => malformed.execute('SELECT 1'), /state is unknown/);
+    await malformed.close();
+
+    const rollbackFailure = new FakeBinding();
+    rollbackFailure.failSql = 'ROLLBACK';
+    const rollbackUncertain = await createOliphauntClient(() => rollbackFailure).open({
+      storage: { kind: 'directory', path: join(root, 'rollback-failure') },
+    });
+    const bodyError = new Error('body and rollback failed');
+    const aggregate = await rollbackUncertain
+      .transaction(() => {
+        throw bodyError;
+      })
+      .catch((error: unknown) => error);
+    assert.ok(aggregate instanceof AggregateError);
+    assert.equal(aggregate.errors[0], bodyError);
+    assert.match(String(aggregate.errors[1]), /commit failed/);
+    assert.deepEqual(rollbackFailure.sqlCalls.slice(-2), ['BEGIN', 'ROLLBACK']);
+    await assert.rejects(() => rollbackUncertain.execute('SELECT 1'), /state is unknown/);
+    await rollbackUncertain.close();
+
+    const aborted = new FakeBinding();
+    aborted.responseForSql.set(
+      'UPDATE rejected',
+      Uint8Array.from([
+        ...backendMessage(0x45, diagnostic('ERROR', 'XX000', 'queued operation failed')),
+        ...backendMessage(0x5a, [0x45]),
+      ]),
+    );
+    aborted.tagForSql.set('COMMIT', 'ROLLBACK');
+    const abortedDb = await createOliphauntClient(() => aborted).open({
+      storage: { kind: 'directory', path: join(root, 'aborted-transaction') },
+    });
+    let ignored: Promise | undefined;
+    const originalFailure = await abortedDb
+      .transaction((transaction) => {
+        ignored = transaction.execute('UPDATE rejected');
+        void ignored.catch(() => undefined);
+        return 'done';
+      })
+      .catch((error: unknown) => error);
+    assert.equal((originalFailure as { sqlstate?: string }).sqlstate, 'XX000');
+    assert.equal((originalFailure as Error).message, 'queued operation failed');
+    assert.ok(ignored);
+    await assert.rejects(ignored, (error: unknown) => error === originalFailure);
+    assert.deepEqual(aborted.sqlCalls.slice(-3), ['BEGIN', 'UPDATE rejected', 'COMMIT']);
+    await abortedDb.close();
+
+    const postgresRollback = new FakeBinding();
+    postgresRollback.tagForSql.set('COMMIT', 'ROLLBACK');
+    const idle = await createOliphauntClient(() => postgresRollback).open({
+      storage: { kind: 'directory', path: join(root, 'postgres-rollback') },
+    });
+    await assert.rejects(() => idle.transaction(() => 'done'), /expected COMMIT, got ROLLBACK/);
+    assert.deepEqual(await idle.execute('UPDATE things SET value = 3'), {
+      commandTag: 'UPDATE 3',
+      rowCount: 3,
+      notices: [],
+    });
+    await idle.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('transaction Promise methods never leak admission or planning failures synchronously', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-transaction-promises-'));
+  const binding = new FakeBinding();
+  const db = await createOliphauntClient(() => binding).open({
+    storage: { kind: 'directory', path: root },
+  });
+  let expired!: OliphauntTransaction;
+  try {
+    await db.transaction(async (transaction) => {
+      expired = transaction;
+      for (const call of [
+        () => transaction.execute('SELECT\0invalid'),
+        () => transaction.query('SELECT\0invalid'),
+        () => transaction.queryRaw('SELECT\0invalid'),
+        () => transaction.exec('SELECT\0invalid'),
+        () => transaction.describe('SELECT\0invalid'),
+      ]) {
+        assert.match(String(await catchPromiseWithoutSynchronousThrow(call)), /NUL bytes/);
+      }
+      for (const call of [
+        () => transaction.execute('ROLLBACK AND CHAIN'),
+        () => transaction.query('ABORT WORK AND CHAIN'),
+        () => transaction.queryRaw('ROLLBACK TRANSACTION /* keep ownership */ AND CHAIN'),
+        () => transaction.exec('SELECT 1; RoLlBaCk AND /* nested /* comment */ */ CHAIN'),
+      ]) {
+        assert.match(
+          String(await catchPromiseWithoutSynchronousThrow(call)),
+          /do not support ROLLBACK\/ABORT .* AND CHAIN/,
+        );
+      }
+      assert.deepEqual(binding.sqlCalls, ['BEGIN']);
+      // Planning failures never enter the transaction queue or poison it.
+      assert.deepEqual(await transaction.execute('UPDATE things SET value = 22'), {
+        commandTag: 'UPDATE 3',
+        rowCount: 3,
+        notices: [],
+      });
+    });
+
+    assert.match(
+      String(
+        await catchPromiseWithoutSynchronousThrow(() =>
+          expired.execute('UPDATE things SET value = 23'),
+        ),
+      ),
+      /transaction is no longer active/,
+    );
+    assert.match(
+      String(await catchPromiseWithoutSynchronousThrow(() => expired.rollback())),
+      /transaction is no longer active/,
+    );
+  } finally {
+    await db.close();
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('serializes physical-session work in FIFO order and pins transactions', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-session-queue-'));
+  const binding = new FakeBinding();
+  const firstStarted = deferred();
+  const releaseFirst = deferred();
+  binding.protocolStarted = () => firstStarted.resolve();
+  binding.protocolGate = releaseFirst.promise;
+  const db = await createOliphauntClient(() => binding).open({
+    storage: { kind: 'directory', path: root },
+  });
+  try {
+    const first = db.execute('UPDATE things SET value = 10');
+    await firstStarted.promise;
+    const backup = db.backup();
+    const checkpoint = db.execute('CHECKPOINT');
+    await new Promise((resolve) => setImmediate(resolve));
+    assert.deepEqual(binding.operationEvents, ['raw:UPDATE things SET value = 10']);
+
+    binding.protocolGate = undefined;
+    releaseFirst.resolve();
+    await Promise.all([first, backup, checkpoint]);
+    assert.deepEqual(binding.operationEvents, [
+      'raw:UPDATE things SET value = 10',
+      'backup',
+      'raw:CHECKPOINT',
+    ]);
+
+    binding.queryValues.set("SELECT 'first'", 'first');
+    binding.queryValues.set("SELECT 'second'", 'second');
+    const [firstResult, secondResult] = await Promise.all([
+      db.query("SELECT 'first'"),
+      db.query("SELECT 'second'"),
+    ]);
+    assert.deepEqual(firstResult.rows, [{ value: 'first' }]);
+    assert.deepEqual(secondResult.rows, [{ value: 'second' }]);
+
+    const transactionBodyStarted = deferred();
+    const releaseTransactionBody = deferred();
+    let completedTransactionHandle!: OliphauntTransaction;
+    const transaction = db.transaction(async (owned) => {
+      completedTransactionHandle = owned;
+      await owned.execute('UPDATE things SET value = 11');
+      transactionBodyStarted.resolve();
+      await releaseTransactionBody.promise;
+      await Promise.all([
+        owned.execute('UPDATE things SET value = 12'),
+        owned.execute('UPDATE things SET value = 13'),
+      ]);
+    });
+    await transactionBodyStarted.promise;
+    await assert.rejects(() => db.query('SELECT 1'), /physical session is pinned/);
+    releaseTransactionBody.resolve();
+    await transaction;
+    assert.deepEqual(binding.sqlCalls.slice(-5), [
+      'BEGIN',
+      'UPDATE things SET value = 11',
+      'UPDATE things SET value = 12',
+      'UPDATE things SET value = 13',
+      'COMMIT',
+    ]);
+    assert.equal(binding.maxConcurrentProtocolOperations, 1);
+    await assert.rejects(
+      () => completedTransactionHandle.execute('SELECT 1'),
+      /transaction is no longer active/,
+    );
+
+    const acceptedOperationStarted = deferred();
+    const releaseAcceptedOperation = deferred();
+    let acceptedOperation!: Promise;
+    let sealedTransactionHandle!: OliphauntTransaction;
+    const drainingTransaction = db.transaction(async (owned) => {
+      sealedTransactionHandle = owned;
+      binding.protocolStarted = () => acceptedOperationStarted.resolve();
+      binding.protocolGate = releaseAcceptedOperation.promise;
+      acceptedOperation = owned.execute('UPDATE things SET value = 15');
+      await acceptedOperationStarted.promise;
+    });
+    await acceptedOperationStarted.promise;
+    await new Promise((resolve) => setImmediate(resolve));
+    assert.notEqual(binding.sqlCalls.at(-1), 'COMMIT');
+    await assert.rejects(
+      () => sealedTransactionHandle.execute('UPDATE things SET value = 16'),
+      /transaction is finishing|transaction is no longer active/,
+    );
+    binding.protocolGate = undefined;
+    releaseAcceptedOperation.resolve();
+    await acceptedOperation;
+    await drainingTransaction;
+    assert.deepEqual(binding.sqlCalls.slice(-3), [
+      'BEGIN',
+      'UPDATE things SET value = 15',
+      'COMMIT',
+    ]);
+
+    await assert.rejects(
+      () =>
+        db.execProtocolRawStream(new Uint8Array([0x51]), () => {
+          throw new Error('stream consumer failed');
+        }),
+      /stream consumer failed/,
+    );
+    const nanCallbackOutcome = await db
+      .execProtocolRawStream(new Uint8Array([0x51]), () => {
+        throw Number.NaN;
+      })
+      .then(
+        () => ({ fulfilled: true as const, error: undefined }),
+        (error: unknown) => ({ fulfilled: false as const, error }),
+      );
+    assert.equal(nanCallbackOutcome.fulfilled, false);
+    assert.ok(Object.is(nanCallbackOutcome.error, Number.NaN));
+    const dynamicallyTypedAsyncCallback: (chunk: Uint8Array) => unknown = async () => {};
+    await assert.rejects(
+      db.execProtocolRawStream(
+        new Uint8Array([0x51]),
+        dynamicallyTypedAsyncCallback as unknown as (chunk: Uint8Array) => undefined,
+      ),
+      /must complete synchronously.*Promise or thenable/,
+    );
+    assert.deepEqual(await db.execute('UPDATE things SET value = 14'), {
+      commandTag: 'UPDATE 3',
+      rowCount: 3,
+      notices: [],
+    });
+  } finally {
+    await db.close();
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('keeps cancellation out of band and close drains accepted work exactly once', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-session-close-'));
+  const binding = new FakeBinding();
+  const operationStarted = deferred();
+  const releaseOperation = deferred();
+  const cancellationStarted = deferred();
+  const releaseCancellation = deferred();
+  const teardownStarted = deferred();
+  const releaseTeardown = deferred();
+  binding.protocolStarted = () => operationStarted.resolve();
+  binding.protocolGate = releaseOperation.promise;
+  binding.cancelStarted = () => cancellationStarted.resolve();
+  binding.cancelGate = releaseCancellation.promise;
+  binding.detachStarted = () => teardownStarted.resolve();
+  binding.detachGate = releaseTeardown.promise;
+  const db = await createOliphauntClient(() => binding).open({
+    storage: { kind: 'directory', path: root },
+  });
+  try {
+    // Deterministic query->immediate close->cancel admission regression.
+    const operation = db.execute('UPDATE things SET value = 12');
+    const firstClose = db.close();
+    const secondClose = db.close();
+    const cancellation = db.cancel();
+    assert.equal(firstClose, secondClose);
+    await Promise.all([operationStarted.promise, cancellationStarted.promise]);
+    assert.deepEqual(binding.operationEvents, ['cancel', 'raw:UPDATE things SET value = 12']);
+    await assert.rejects(() => db.backup(), /closing/);
+    assert.equal(binding.detachCalls, 0);
+
+    binding.protocolGate = undefined;
+    releaseOperation.resolve();
+    await operation;
+    await new Promise((resolve) => setImmediate(resolve));
+    assert.equal(
+      binding.detachCalls,
+      0,
+      'close must wait for the out-of-band cancellation it admitted',
+    );
+    binding.cancelGate = undefined;
+    releaseCancellation.resolve();
+    await cancellation;
+    await teardownStarted.promise;
+    await assert.rejects(() => db.cancel(), /closing/);
+    binding.detachGate = undefined;
+    releaseTeardown.resolve();
+    await Promise.all([firstClose, secondClose]);
+    assert.equal(binding.detachCalls, 1);
+    assert.equal(db.close(), firstClose);
+    await db.close();
+    assert.equal(binding.detachCalls, 1);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('keeps direct pre-deactivation close failures retryable', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-retryable-close-'));
+  const binding = new FakeBinding();
+  const closeError = new Error('logical detach did not complete');
+  binding.detachFailures.push(closeError);
+  const db = await createOliphauntClient(() => binding).open({
+    storage: { kind: 'directory', path: root },
+  });
+  try {
+    const first = db.close();
+    assert.equal(await first.catch((error: unknown) => error), closeError);
+    assert.equal(db.closed, false);
+    assert.deepEqual(await db.execute('UPDATE things SET value = 18'), {
+      commandTag: 'UPDATE 3',
+      rowCount: 3,
+      notices: [],
+    });
+
+    const retry = db.close();
+    assert.notEqual(retry, first);
+    await retry;
+    assert.equal(db.closed, true);
+    assert.equal(db.close(), retry);
+    assert.equal(binding.detachCalls, 2);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('terminal broker and server close failures retire the facade and replay exactly', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-terminal-close-'));
+  try {
+    for (const topology of ['broker', 'server'] as const) {
+      const binding = new FakeBinding();
+      const closeError = new Error(`${topology} teardown failed`);
+      let closeCalls = 0;
+      const runtime = binding as unknown as RuntimeBinding;
+      runtime.close = async () => {
+        closeCalls += 1;
+        return { state: 'terminal', error: closeError };
+      };
+      runtime.connectionString = () => 'postgresql://postgres@127.0.0.1:5432/postgres';
+      const client = createOliphauntClient(() => binding, {
+        broker: runtime,
+        server: runtime,
+      });
+      const database =
+        topology === 'broker'
+          ? await client.open({
+              topology,
+              storage: { kind: 'directory', path: join(root, topology) },
+            })
+          : await client.openServer({
+              storage: { kind: 'directory', path: join(root, topology) },
+            });
+
+      const first = database.close();
+      const concurrent = database.close();
+      assert.equal(concurrent, first);
+      assert.equal(await first.catch((error: unknown) => error), closeError);
+      assert.equal(database.closed, true);
+      assert.equal(closeCalls, 1);
+      assert.equal(database.close(), first);
+      assert.equal(await database.close().catch((error: unknown) => error), closeError);
+      if (topology === 'broker') {
+        const brokerDatabase = database as OliphauntDatabase;
+        await assert.rejects(() => brokerDatabase.query('SELECT 1'), /closed/);
+        await assert.rejects(() => brokerDatabase.cancel(), /closed/);
+      } else {
+        assert.equal('query' in database, false);
+        assert.equal('cancel' in database, false);
+      }
+      assert.equal(closeCalls, 1);
+    }
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('database raw stream callbacks cannot queue same-handle work while cancel stays out of band', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-stream-reentry-'));
+  const binding = new FakeBinding();
+  const db = await createOliphauntClient(() => binding).open({
+    storage: { kind: 'directory', path: root },
+  });
+  try {
+    let databaseAttempts: Promise[] = [];
+    let cancellation!: Promise;
+    const beforeDatabaseStream = binding.requests.length;
+    await db.execProtocolRawStream(new Uint8Array([0x51]), () => {
+      databaseAttempts = [
+        db.query('SELECT callback_reentry'),
+        db.backup(),
+        db.close(),
+        db.execProtocolRawStream(new Uint8Array([0x51]), () => undefined),
+      ];
+      for (const attempt of databaseAttempts) void attempt.catch(() => undefined);
+      cancellation = db.cancel();
+      void cancellation.catch(() => undefined);
+    });
+    for (const attempt of databaseAttempts) {
+      await assert.rejects(attempt, /must not re-enter the same Oliphaunt handle/);
+    }
+    await cancellation;
+    assert.equal(binding.requests.length, beforeDatabaseStream + 1);
+    assert.equal(binding.detachCalls, 0);
+    assert.equal(binding.cancelCalls, 1);
+  } finally {
+    await db.close();
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('raw stream native recovery failure outranks an earlier callback failure', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-stream-error-precedence-'));
+  const binding = new FakeBinding();
+  const nativeFailure = new Error('native protocol stream recovery failed');
+  const callbackFailure = new Error('protocol stream callback failed');
+  binding.streamCompletionFailure = nativeFailure;
+  const db = await createOliphauntClient(() => binding).open({
+    storage: { kind: 'directory', path: root },
+  });
+  try {
+    await assert.rejects(
+      () =>
+        db.execProtocolRawStream(new Uint8Array([0x51]), () => {
+          throw callbackFailure;
+        }),
+      (error) => error === nativeFailure,
+    );
+    const requestsAfterFailure = binding.requests.length;
+    await assert.rejects(() => db.query('SELECT 1'), /session state is unknown/);
+    assert.equal(binding.requests.length, requestsAfterFailure);
+  } finally {
+    await db.close();
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('registers forgotten direct cleanup and releases only the collected owner', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-finalizer-'));
+  const binding = new FinalizingFakeBinding();
+  const client = createOliphauntClient(() => binding);
+  try {
+    const explicit = await client.open({
+      storage: { kind: 'directory', path: join(root, 'explicit') },
+    });
+    assert.equal(binding.registeredOwner, explicit);
+    await explicit.close();
+    assert.deepEqual(binding.unregisteredOwners, [explicit]);
+
+    const current = await client.open({
+      storage: { kind: 'directory', path: join(root, 'current') },
+    });
+    await binding.runStaleFinalizer(explicit);
+    await assert.rejects(
+      () =>
+        client.open({
+          storage: { kind: 'directory', path: join(root, 'stale-must-not-release-current') },
+        }),
+      /active process-wide instance/,
+    );
+    await current.close();
+
+    const forgotten = await client.open({
+      storage: { kind: 'directory', path: join(root, 'forgotten') },
+    });
+    assert.equal(binding.registeredOwner, forgotten);
+    await binding.finalizeRegisteredOwner();
+    assert.equal(binding.forgottenCleanupCalls, 1);
+
+    // The cleanup record carries the exact direct-owner release callback. The
+    // next open reaches the runtime instead of failing the stale JS ownership
+    // guard; Deno's generation cleanup is terminal for this process lifetime.
+    await assert.rejects(
+      () =>
+        client.open({
+          storage: { kind: 'directory', path: join(root, 'after-finalizer') },
+        }),
+      /process lifetime has already been used/,
+    );
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('cleans an opened owner before rejecting failed facade publication', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-publication-cleanup-'));
+  try {
+    for (const topology of ['direct', 'broker', 'server'] as const) {
+      const binding = new PublicationFailingFakeBinding();
+      const registrationError = new Error(`${topology} registry rejected owner`);
+      binding.registrationFailure = registrationError;
+      const runtime = binding as unknown as RuntimeBinding;
+      runtime.close = async (handle) => {
+        await binding.detach(handle);
+        return { state: 'closed' };
+      };
+      runtime.connectionString = () => 'postgresql://postgres@127.0.0.1:5432/postgres';
+      const client = createOliphauntClient(() => binding, {
+        broker: runtime,
+        server: runtime,
+      });
+      const config = {
+        storage: { kind: 'directory' as const, path: join(root, topology) },
+      };
+      const firstOpen =
+        topology === 'server'
+          ? client.openServer(config)
+          : client.open({
+              ...config,
+              topology,
+            });
+      assert.equal(await firstOpen.catch((error: unknown) => error), registrationError);
+      assert.equal(binding.detachCalls, 1);
+      assert.equal(binding.registeredOwners.length, 1);
+      assert.deepEqual(binding.unregisteredOwners, binding.registeredOwners);
+
+      // In particular, direct publication failure must release only its exact
+      // process-wide JavaScript admission lease so a later owner can open.
+      const database =
+        topology === 'server'
+          ? await client.openServer(config)
+          : await client.open({ ...config, topology });
+      await database.close();
+      assert.equal(binding.detachCalls, 2);
+      assert.equal(binding.registeredOwners.length, 2);
+      assert.deepEqual(binding.unregisteredOwners, binding.registeredOwners);
+    }
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('broker facade preserves FIFO session ownership', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-runtime-queue-'));
+  try {
+    const binding = new FakeBinding();
+    const started = deferred();
+    const release = deferred();
+    binding.protocolStarted = () => started.resolve();
+    binding.protocolGate = release.promise;
+    const runtime = binding as unknown as RuntimeBinding;
+    runtime.close = async (handle) => {
+      await binding.detach(handle);
+      return { state: 'closed' };
+    };
+    const client = createOliphauntClient(() => binding, { broker: runtime });
+    const database = await client.open({
+      topology: 'broker',
+      storage: { kind: 'directory', path: join(root, 'broker') },
+    });
+    const first = database.execute('UPDATE things SET value = 20');
+    await started.promise;
+    const second = database.execute('UPDATE things SET value = 21');
+    await new Promise((resolve) => setImmediate(resolve));
+    assert.deepEqual(binding.operationEvents, ['raw:UPDATE things SET value = 20']);
+    binding.protocolGate = undefined;
+    release.resolve();
+    await Promise.all([first, second]);
+    assert.deepEqual(binding.operationEvents, [
+      'raw:UPDATE things SET value = 20',
+      'raw:UPDATE things SET value = 21',
+    ]);
+    await database.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('exposes decoded, raw, exec, describe, and immutable inferred-codec operations', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-structured-api-'));
+  const binding = new FakeBinding();
+  const firstStarted = deferred();
+  const releaseFirst = deferred();
+  binding.protocolStarted = () => firstStarted.resolve();
+  binding.protocolGate = releaseFirst.promise;
+  const db = await createOliphauntClient(() => binding).open({
+    storage: { kind: 'directory', path: root },
+  });
+  try {
+    assert.equal(db.closed, false);
+    const object = { version: 1 };
+    const decoders: Record unknown> = {
+      3802: (value) => `first:${value}`,
+    };
+    const inferred = db.query<{ value: string }>('SELECT $1::jsonb AS value', [object], {
+      decoders,
+    });
+    await firstStarted.promise;
+    const queued = db.execute('UPDATE things SET value = 22');
+    object.version = 2;
+    decoders[3802] = (value) => `second:${value}`;
+    await new Promise((resolve) => setImmediate(resolve));
+    assert.deepEqual(binding.requestTags, ['P']);
+
+    binding.protocolGate = undefined;
+    releaseFirst.resolve();
+    const [decoded] = await Promise.all([inferred, queued]);
+    assert.deepEqual(decoded.rows, [{ value: 'first:{"version":1}' }]);
+    assert.deepEqual(binding.requestTags.slice(0, 3), ['P', 'P', 'P']);
+    const bindRequest = binding.requests.find((request) =>
+      frontendMessageTags(request).includes('B'),
+    );
+    assert.ok(bindRequest);
+    assert.equal(firstBindTextParameter(bindRequest), '{"version":1}');
+    assert.equal(binding.maxConcurrentProtocolOperations, 1);
+
+    const raw = await db.queryRaw('SELECT $1::text AS value', ['raw']);
+    assert.equal(raw.getText(0, 'value'), 'raw');
+    assert.equal(raw.kind, 'rows');
+
+    const description = await db.describe('SELECT $1::int4 AS value');
+    assert.deepEqual(description.parameterTypeOids, [23]);
+    assert.equal(description.fields?.[0]?.typeOid, 23);
+
+    const multiSql = 'UPDATE things SET value = 30; SELECT value FROM things';
+    binding.responseForSql.set(multiSql, multiExecResponse());
+    const execution = await db.exec(multiSql);
+    assert.deepEqual(
+      execution.statements.map((statement) => statement.kind),
+      ['command', 'rows'],
+    );
+    assert.deepEqual(execution.statements[1]?.rows, [{ value: 'multi' }]);
+
+    const requestCount = binding.requests.length;
+    await assert.rejects(() => db.exec('COPY things FROM STDIN'), /does not support COPY/);
+    assert.equal(binding.requests.length, requestCount);
+  } finally {
+    await db.close();
+    assert.equal(db.closed, true);
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('recovers database-level transaction leakage and poisons unknown wire boundaries', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-recovery-'));
+  try {
+    const recoverableBinding = new FakeBinding();
+    const recoverable = await createOliphauntClient(() => recoverableBinding).open({
+      storage: { kind: 'directory', path: join(root, 'recoverable') },
+    });
+    await assert.rejects(
+      () => recoverable.execute('BEGIN'),
+      /ended with PostgreSQL transaction status transaction/,
+    );
+    assert.deepEqual(recoverableBinding.sqlCalls.slice(-2), ['BEGIN', 'ROLLBACK']);
+    await assert.doesNotReject(() => recoverable.execute('UPDATE things SET value = 31'));
+    await recoverable.close();
+
+    const malformedBinding = new FakeBinding();
+    malformedBinding.responseForSql.set(
+      'SELECT malformed',
+      Uint8Array.from(backendMessage(0x43, cstring('SELECT 0'))),
+    );
+    const malformed = await createOliphauntClient(() => malformedBinding).open({
+      storage: { kind: 'directory', path: join(root, 'malformed') },
+    });
+    await assert.rejects(() => malformed.query('SELECT malformed'), /before ReadyForQuery/);
+    await assert.rejects(() => malformed.query('SELECT 1'), /session state is unknown/);
+    await malformed.close();
+
+    const rawFailureBinding = new FakeBinding();
+    const rawTransportFailure = new Error('raw transport failed');
+    rawFailureBinding.protocolFailure = rawTransportFailure;
+    const rawFailure = await createOliphauntClient(() => rawFailureBinding).open({
+      storage: { kind: 'directory', path: join(root, 'raw-failure') },
+    });
+    await assert.rejects(
+      () => rawFailure.execProtocolRaw(new Uint8Array([0x51])),
+      (error) => error === rawTransportFailure,
+    );
+    const requestsAfterFailure = rawFailureBinding.requests.length;
+    await assert.rejects(() => rawFailure.query('SELECT 1'), /session state is unknown/);
+    assert.equal(rawFailureBinding.requests.length, requestsAfterFailure);
+    await rawFailure.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('supports one-shot explicit transaction rollback and expires the handle', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-explicit-rollback-'));
+  const binding = new FakeBinding();
+  const db = await createOliphauntClient(() => binding).open({
+    storage: { kind: 'directory', path: root },
+  });
+  let completed!: OliphauntTransaction;
+  try {
+    const value = await db.transaction(async (transaction) => {
+      completed = transaction;
+      assert.equal(transaction.closed, false);
+      assert.equal('execProtocolRaw' in transaction, false);
+      assert.equal('execProtocolRawStream' in transaction, false);
+      await transaction.execute('UPDATE things SET value = 40');
+      await transaction.rollback();
+      assert.equal(transaction.closed, true);
+      await assert.rejects(() => transaction.rollback(), /no longer active/);
+      await assert.rejects(() => transaction.query('SELECT 1'), /no longer active/);
+      return 40;
+    });
+    assert.equal(value, 40);
+    assert.equal(completed.closed, true);
+    assert.deepEqual(binding.sqlCalls.slice(-3), [
+      'BEGIN',
+      'UPDATE things SET value = 40',
+      'ROLLBACK',
+    ]);
+    assert.equal(binding.sqlCalls.includes('COMMIT'), false);
+    await assert.doesNotReject(() => db.execute('UPDATE things SET value = 41'));
+  } finally {
+    await db.close();
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('transaction ownership is enforced from complete protocol responses before parsing', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-transaction-ownership-'));
+  try {
+    const escapedResponses = [
+      {
+        sql: 'SELECT hidden_commit_then_begin',
+        response: Uint8Array.from([
+          ...backendMessage(0x43, cstring('COMMIT')),
+          ...backendMessage(0x43, cstring('BEGIN')),
+          ...backendMessage(0x45, diagnostic('ERROR', 'XX000', 'later failure')),
+          ...backendMessage(0x5a, [0x54]),
+        ]),
+        expected: /command tag COMMIT/,
+      },
+      {
+        sql: 'SELECT hidden_rollback_then_begin',
+        response: Uint8Array.from([
+          ...backendMessage(0x43, cstring('ROLLBACK')),
+          ...backendMessage(0x43, cstring('BEGIN')),
+          ...backendMessage(0x5a, [0x54]),
+        ]),
+        expected: /command tag BEGIN/,
+      },
+    ];
+
+    for (const [index, escaped] of escapedResponses.entries()) {
+      const binding = new FakeBinding();
+      binding.responseForSql.set(escaped.sql, escaped.response);
+      const db = await createOliphauntClient(() => binding).open({
+        storage: { kind: 'directory', path: join(root, `escaped-${index}`) },
+      });
+      const failure = await db
+        .transaction((transaction) => {
+          const ignored = transaction.exec(escaped.sql);
+          void ignored.catch(() => undefined);
+        })
+        .catch((error: unknown) => error);
+      assert.match(String(failure), escaped.expected);
+      assert.deepEqual(binding.sqlCalls, ['BEGIN', escaped.sql]);
+      const requestCount = binding.requests.length;
+      await assert.rejects(() => db.query('SELECT 1'), /session state is unknown/);
+      assert.equal(binding.requests.length, requestCount);
+      await db.close();
+    }
+
+    const savepointBinding = new FakeBinding();
+    const rollbackToSavepoint = 'ROLLBACK TO SAVEPOINT nested';
+    savepointBinding.responseForSql.set(rollbackToSavepoint, commandResponse('ROLLBACK', 0x54));
+    const reusable = await createOliphauntClient(() => savepointBinding).open({
+      storage: { kind: 'directory', path: join(root, 'savepoint') },
+    });
+    await reusable.transaction(async (transaction) => {
+      await transaction.exec(rollbackToSavepoint);
+    });
+    assert.deepEqual(savepointBinding.sqlCalls.slice(-3), ['BEGIN', rollbackToSavepoint, 'COMMIT']);
+    await reusable.close();
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+class FakeBinding implements NativeBinding {
+  readonly openCalls: NativeOpenConfig[] = [];
+  readonly restoreCalls: NativeRestoreOptions[] = [];
+  readonly sqlCalls: string[] = [];
+  readonly requestTags: string[] = [];
+  readonly requests: Uint8Array[] = [];
+  readonly operationEvents: string[] = [];
+  cancelCalls = 0;
+  detachCalls = 0;
+  readonly detachFailures: unknown[] = [];
+  failSql?: string;
+  protocolGate?: Promise;
+  protocolStarted?: () => void;
+  protocolFailure?: unknown;
+  streamCompletionFailure?: unknown;
+  cancelGate?: Promise;
+  cancelStarted?: () => void;
+  detachGate?: Promise;
+  detachStarted?: () => void;
+  activeProtocolOperations = 0;
+  maxConcurrentProtocolOperations = 0;
+  readonly tagForSql = new Map();
+  readonly queryValues = new Map();
+  readonly responseForSql = new Map();
+  #transactionStatus = 0x49;
+  #pendingSql?: string;
+
+  async open(config: NativeOpenConfig): Promise {
+    this.openCalls.push(config);
+    return { id: 1 };
+  }
+
+  async execProtocolRaw(_handle: NativeHandle, request: Uint8Array): Promise {
+    this.requestTags.push(String.fromCharCode(request[0] ?? 0));
+    this.requests.push(request.slice());
+    const tags = frontendMessageTags(request);
+    const parsedSql = decodeSimpleQuery(request) ?? decodeExtendedQuery(request);
+    const describeOnly = tags.includes('P') && tags.includes('D') && !tags.includes('B');
+    if (describeOnly && parsedSql !== undefined) this.#pendingSql = parsedSql;
+    const sql =
+      parsedSql ?? (tags[0] === 'B' ? this.#pendingSql : undefined) ?? 'SELECT value FROM things';
+    this.operationEvents.push(`raw:${sql}`);
+    this.protocolStarted?.();
+    this.activeProtocolOperations += 1;
+    this.maxConcurrentProtocolOperations = Math.max(
+      this.maxConcurrentProtocolOperations,
+      this.activeProtocolOperations,
+    );
+    try {
+      await this.protocolGate;
+      if (this.protocolFailure !== undefined) throw this.protocolFailure;
+      if (describeOnly) {
+        return describeResponse(sql, inferredParameterOids(sql), this.#transactionStatus);
+      }
+      if (tags.includes('B')) this.#pendingSql = undefined;
+      return this.respond(
+        sql,
+        tags.includes('B') ? firstBindTextParameter(request) : undefined,
+        tags.includes('B'),
+      );
+    } finally {
+      this.activeProtocolOperations -= 1;
+    }
+  }
+
+  async execProtocolStream(
+    handle: NativeHandle,
+    request: Uint8Array,
+    onChunk: (chunk: Uint8Array) => void,
+  ): Promise {
+    try {
+      onChunk(await this.execProtocolRaw(handle, request));
+    } catch (callbackError) {
+      if (this.streamCompletionFailure !== undefined) {
+        throw this.streamCompletionFailure;
+      }
+      throw callbackError;
+    }
+    if (this.streamCompletionFailure !== undefined) {
+      throw this.streamCompletionFailure;
+    }
+  }
+
+  async execSimpleQuery(_handle: NativeHandle, sql: string): Promise {
+    this.operationEvents.push(`simple:${sql}`);
+    return this.respond(sql);
+  }
+
+  async backup(_handle: NativeHandle): Promise {
+    this.operationEvents.push('backup');
+    return new Uint8Array([1, 2, 3]);
+  }
+
+  async restore(options: NativeRestoreOptions): Promise {
+    this.restoreCalls.push(options);
+  }
+
+  async cancel(_handle: NativeHandle): Promise {
+    this.cancelCalls += 1;
+    this.operationEvents.push('cancel');
+    this.cancelStarted?.();
+    await this.cancelGate;
+  }
+
+  async detach(_handle: NativeHandle): Promise {
+    this.detachCalls += 1;
+    this.detachStarted?.();
+    await this.detachGate;
+    if (this.detachFailures.length > 0) {
+      throw this.detachFailures.shift();
+    }
+  }
+
+  private respond(sql: string, boundValue?: string, extended = false): Uint8Array {
+    this.sqlCalls.push(sql);
+    if (sql === this.failSql) throw new Error('commit failed');
+    const configured = this.responseForSql.get(sql);
+    if (configured !== undefined) return configured;
+    if (sql === 'BEGIN') {
+      this.#transactionStatus = 0x54;
+      return commandResponse(this.tagForSql.get(sql) ?? sql, this.#transactionStatus, extended);
+    }
+    if (sql === 'COMMIT' || sql === 'ROLLBACK') {
+      this.#transactionStatus = 0x49;
+      return commandResponse(this.tagForSql.get(sql) ?? sql, this.#transactionStatus, extended);
+    }
+    if (sql === 'CHECKPOINT') return commandResponse(sql, this.#transactionStatus, extended);
+    if (sql.startsWith('UPDATE'))
+      return commandResponse('UPDATE 3', this.#transactionStatus, extended);
+    return queryResponse(
+      this.queryValues.get(sql) ?? boundValue ?? 'ok',
+      this.#transactionStatus,
+      inferredResultOid(sql),
+      extended,
+    );
+  }
+}
+
+class FinalizingFakeBinding extends FakeBinding {
+  registeredOwner?: object;
+  readonly unregisteredOwners: object[] = [];
+  forgottenCleanupCalls = 0;
+  terminallyClosed = false;
+  #releaseOwnership?: () => void;
+  readonly #releaseByOwner = new WeakMap void>();
+
+  override async open(config: NativeOpenConfig): Promise {
+    if (this.terminallyClosed) {
+      throw new Error('native process lifetime has already been used');
+    }
+    return super.open(config);
+  }
+
+  registerForgottenHandleCleanup(
+    owner: object,
+    _handle: NativeHandle,
+    releaseOwnership: () => void,
+  ): void {
+    this.registeredOwner = owner;
+    this.#releaseOwnership = releaseOwnership;
+    this.#releaseByOwner.set(owner, releaseOwnership);
+  }
+
+  unregisterForgottenHandleCleanup(owner: object): void {
+    this.unregisteredOwners.push(owner);
+    if (this.registeredOwner === owner) {
+      this.registeredOwner = undefined;
+      this.#releaseOwnership = undefined;
+    }
+  }
+
+  async finalizeRegisteredOwner(): Promise {
+    const releaseOwnership = this.#releaseOwnership;
+    assert.ok(releaseOwnership);
+    this.forgottenCleanupCalls += 1;
+    await Promise.resolve();
+    this.terminallyClosed = true;
+    releaseOwnership();
+    this.registeredOwner = undefined;
+    this.#releaseOwnership = undefined;
+  }
+
+  async runStaleFinalizer(owner: object): Promise {
+    const releaseOwnership = this.#releaseByOwner.get(owner);
+    assert.ok(releaseOwnership);
+    await Promise.resolve();
+    releaseOwnership();
+  }
+}
+
+class PublicationFailingFakeBinding extends FakeBinding {
+  registrationFailure?: Error;
+  readonly registeredOwners: object[] = [];
+  readonly unregisteredOwners: object[] = [];
+
+  registerForgottenHandleCleanup(
+    owner: object,
+    _handle: NativeHandle,
+    _releaseOwnership: () => void,
+  ): void {
+    this.registeredOwners.push(owner);
+    const error = this.registrationFailure;
+    this.registrationFailure = undefined;
+    if (error !== undefined) throw error;
+  }
+
+  unregisterForgottenHandleCleanup(owner: object): void {
+    this.unregisteredOwners.push(owner);
+  }
+}
+
+async function catchPromiseWithoutSynchronousThrow(call: () => Promise): Promise {
+  let caught!: Promise;
+  assert.doesNotThrow(() => {
+    caught = call().catch((error: unknown) => error);
+  });
+  return caught;
+}
+
+function deferred(): {
+  promise: Promise;
+  resolve(value?: T): void;
+} {
+  let resolvePromise!: (value: T | PromiseLike) => void;
+  const promise = new Promise((resolve) => {
+    resolvePromise = resolve;
+  });
+  return {
+    promise,
+    resolve: (value) => resolvePromise(value as T),
+  };
+}
+
+function commandResponse(tag: string, status = 0x49, extended = false): Uint8Array {
+  return Uint8Array.from([
+    ...(extended
+      ? [...backendMessage(0x31, []), ...backendMessage(0x32, []), ...backendMessage(0x6e, [])]
+      : []),
+    ...backendMessage(0x43, cstring(tag)),
+    ...backendMessage(0x5a, [status]),
+  ]);
+}
+
+function queryResponse(value: string, status = 0x49, typeOid = 25, extended = false): Uint8Array {
+  const bytes = [...new TextEncoder().encode(value)];
+  return Uint8Array.from([
+    ...(extended ? [...backendMessage(0x31, []), ...backendMessage(0x32, [])] : []),
+    ...backendMessage(0x54, rowDescriptionBody(typeOid)),
+    ...backendMessage(0x44, [...i16(1), ...i32(bytes.length), ...bytes]),
+    ...backendMessage(0x43, cstring('SELECT 1')),
+    ...backendMessage(0x5a, [status]),
+  ]);
+}
+
+function multiExecResponse(): Uint8Array {
+  const value = [...new TextEncoder().encode('multi')];
+  return Uint8Array.from([
+    ...backendMessage(0x43, cstring('UPDATE 2')),
+    ...backendMessage(0x54, rowDescriptionBody(25)),
+    ...backendMessage(0x44, [...i16(1), ...i32(value.length), ...value]),
+    ...backendMessage(0x43, cstring('SELECT 1')),
+    ...backendMessage(0x5a, [0x49]),
+  ]);
+}
+
+function describeResponse(sql: string, parameterTypeOids: number[], status: number): Uint8Array {
+  return Uint8Array.from([
+    ...backendMessage(0x31, []),
+    ...backendMessage(0x74, [...i16(parameterTypeOids.length), ...parameterTypeOids.flatMap(i32)]),
+    ...(sql.trimStart().toUpperCase().startsWith('SELECT')
+      ? backendMessage(0x54, rowDescriptionBody(inferredResultOid(sql)))
+      : backendMessage(0x6e, [])),
+    ...backendMessage(0x5a, [status]),
+  ]);
+}
+
+function rowDescriptionBody(typeOid: number): number[] {
+  return [
+    ...i16(1),
+    ...cstring('value'),
+    ...i32(0),
+    ...i16(0),
+    ...i32(typeOid),
+    ...i16(-1),
+    ...i32(-1),
+    ...i16(0),
+  ];
+}
+
+function inferredParameterOids(sql: string): number[] {
+  const indexes = [...sql.matchAll(/\$([1-9][0-9]*)/g)].map((match) => Number(match[1]));
+  const count = Math.max(0, ...indexes);
+  return Array.from({ length: count }, (_, offset) => {
+    const index = offset + 1;
+    const cast = new RegExp(`\\$${index}\\s*::\\s*([a-z0-9_]+)`, 'i').exec(sql)?.[1]?.toLowerCase();
+    if (cast === 'jsonb') return 3802;
+    if (cast === 'json') return 114;
+    if (cast === 'int4' || cast === 'integer') return 23;
+    return 25;
+  });
+}
+
+function inferredResultOid(sql: string): number {
+  if (/::\s*jsonb\b/i.test(sql)) return 3802;
+  if (/::\s*json\b/i.test(sql)) return 114;
+  if (/::\s*(?:int4|integer)\b/i.test(sql)) return 23;
+  return 25;
+}
+
+function backendMessage(tag: number, body: number[]): number[] {
+  return [tag, ...i32(body.length + 4), ...body];
+}
+
+function cstring(value: string): number[] {
+  return [...new TextEncoder().encode(value), 0];
+}
+
+function diagnostic(severity: string, sqlstate: string, message: string): number[] {
+  return [0x53, ...cstring(severity), 0x43, ...cstring(sqlstate), 0x4d, ...cstring(message), 0];
+}
+
+function i16(value: number): number[] {
+  const bits = value & 0xffff;
+  return [(bits >>> 8) & 0xff, bits & 0xff];
+}
+
+function i32(value: number): number[] {
+  const bits = value >>> 0;
+  return [(bits >>> 24) & 0xff, (bits >>> 16) & 0xff, (bits >>> 8) & 0xff, bits & 0xff];
+}
+
+function decodeSimpleQuery(request: Uint8Array): string | undefined {
+  return request[0] === 0x51
+    ? new TextDecoder().decode(request.subarray(5, request.length - 1))
+    : undefined;
+}
+
+function decodeExtendedQuery(request: Uint8Array): string | undefined {
+  if (request[0] !== 0x50 || request[5] !== 0) return undefined;
+  const terminator = request.indexOf(0, 6);
+  return terminator < 0 ? undefined : new TextDecoder().decode(request.subarray(6, terminator));
+}
+
+function frontendMessageTags(request: Uint8Array): string[] {
+  const tags: string[] = [];
+  let offset = 0;
+  while (offset + 5 <= request.length) {
+    const length = readU32(request, offset + 1);
+    if (length < 4 || offset + length + 1 > request.length) break;
+    tags.push(String.fromCharCode(request[offset]!));
+    offset += length + 1;
+  }
+  if (tags.length === 0 && request.length > 0) tags.push(String.fromCharCode(request[0]!));
+  return tags;
+}
+
+function firstBindTextParameter(request: Uint8Array): string | undefined {
+  let messageOffset = 0;
+  while (messageOffset + 5 <= request.length && request[messageOffset] !== 0x42) {
+    messageOffset += readU32(request, messageOffset + 1) + 1;
+  }
+  if (request[messageOffset] !== 0x42) return undefined;
+  let offset = messageOffset + 5;
+  while (offset < request.length && request[offset] !== 0) offset += 1;
+  offset += 1;
+  while (offset < request.length && request[offset] !== 0) offset += 1;
+  offset += 1;
+  const formatCount = readU16(request, offset);
+  offset += 2 + formatCount * 2;
+  const parameterCount = readU16(request, offset);
+  offset += 2;
+  if (parameterCount === 0) return undefined;
+  const length = readU32(request, offset);
+  if (length === 0xffffffff) return undefined;
+  offset += 4;
+  return new TextDecoder().decode(request.subarray(offset, offset + length));
+}
+
+function readU16(bytes: Uint8Array, offset: number): number {
+  return ((bytes[offset] ?? 0) << 8) | (bytes[offset + 1] ?? 0);
+}
+
+function readU32(bytes: Uint8Array, offset: number): number {
+  return (
+    ((bytes[offset] ?? 0) * 0x1000000 +
+      ((bytes[offset + 1] ?? 0) << 16) +
+      ((bytes[offset + 2] ?? 0) << 8) +
+      (bytes[offset + 3] ?? 0)) >>>
+    0
+  );
+}
diff --git a/src/sdks/js/src/__tests__/config.test.ts b/src/sdks/ts/sdk/src/__tests__/config.test.ts
similarity index 97%
rename from src/sdks/js/src/__tests__/config.test.ts
rename to src/sdks/ts/sdk/src/__tests__/config.test.ts
index 9ec221b13..2dc635867 100644
--- a/src/sdks/js/src/__tests__/config.test.ts
+++ b/src/sdks/ts/sdk/src/__tests__/config.test.ts
@@ -1,6 +1,6 @@
 import assert from 'node:assert/strict';
 import { readFileSync } from 'node:fs';
-import { test } from 'vitest';
+import { test } from 'bun:test';
 
 import {
   buildStartupArgs,
@@ -100,7 +100,7 @@ test('validates the small public configuration vocabulary', () => {
 test('matches the shared server-listen port contract', () => {
   const fixture = JSON.parse(
     readFileSync(
-      new URL('../../../../shared/fixtures/postgres/server-listen.json', import.meta.url),
+      new URL('../../../../../test-fixtures/postgres/server-listen.json', import.meta.url),
       'utf8',
     ),
   ) as {
diff --git a/src/sdks/ts/sdk/src/__tests__/entrypoints.test.ts b/src/sdks/ts/sdk/src/__tests__/entrypoints.test.ts
new file mode 100644
index 000000000..eb3fa6da8
--- /dev/null
+++ b/src/sdks/ts/sdk/src/__tests__/entrypoints.test.ts
@@ -0,0 +1,15 @@
+import assert from 'node:assert/strict';
+import { test } from 'bun:test';
+import { Oliphaunt as direct } from '../direct.js';
+import { Oliphaunt as broker } from '../broker.js';
+
+test('native mode entrypoints reject contradictory configuration before opening', async () => {
+  const topology = { topology: 'broker' as const };
+  // @ts-expect-error mode-specific imports forbid topology even through a variable
+  await assert.rejects(direct.open(topology), /does not accept topology/);
+  // @ts-expect-error the broker import owns its topology
+  await assert.rejects(broker.open(topology), /does not accept topology/);
+  const helper = { brokerExecutable: '/unused/broker' };
+  // @ts-expect-error direct execution has no broker helper
+  await assert.rejects(direct.open(helper), /does not accept topology or brokerExecutable/);
+});
diff --git a/src/sdks/js/src/__tests__/filesystem-durability.test.ts b/src/sdks/ts/sdk/src/__tests__/filesystem-durability.test.ts
similarity index 90%
rename from src/sdks/js/src/__tests__/filesystem-durability.test.ts
rename to src/sdks/ts/sdk/src/__tests__/filesystem-durability.test.ts
index f35560d38..f7d6a5a32 100644
--- a/src/sdks/js/src/__tests__/filesystem-durability.test.ts
+++ b/src/sdks/ts/sdk/src/__tests__/filesystem-durability.test.ts
@@ -1,7 +1,7 @@
 import { mkdtemp, mkdir, rm, symlink, writeFile } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { afterEach, describe, expect, it } from 'vitest';
+import { afterEach, describe, expect, it } from 'bun:test';
 import { syncDirectoryTree, syncRuntimeDirectoryTree } from '../native/filesystem-durability.js';
 
 describe('filesystem durability', () => {
@@ -11,7 +11,7 @@ describe('filesystem durability', () => {
     await Promise.all(roots.splice(0).map((root) => rm(root, { force: true, recursive: true })));
   });
 
-  it.runIf(process.platform !== 'win32')(
+  it.if(process.platform !== 'win32')(
     'accepts packaged runtime symlinks without weakening PGDATA publication',
     async () => {
       const root = await mkdtemp(join(tmpdir(), 'oliphaunt-runtime-sync-'));
diff --git a/src/sdks/ts/sdk/src/__tests__/native-bindings.test.ts b/src/sdks/ts/sdk/src/__tests__/native-bindings.test.ts
new file mode 100644
index 000000000..14f265509
--- /dev/null
+++ b/src/sdks/ts/sdk/src/__tests__/native-bindings.test.ts
@@ -0,0 +1,917 @@
+import { test } from 'bun:test';
+import assert from 'node:assert/strict';
+import {
+  mkdir as fsMkdir,
+  stat as fsStat,
+  mkdtemp,
+  readdir,
+  readFile,
+  rm,
+  writeFile,
+} from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import * as publicEntrypoint from '../index.js';
+import Oliphaunt, { type OliphauntClient } from '../index.js';
+import {
+  ABI_VERSION,
+  liboliphauntPackageTarget,
+  nativeRuntimeLibraryEnvironment,
+} from '../native/common.js';
+import { createDenoNativeBinding } from '../native/deno.js';
+import { nativeModuleSuffixForTarget } from '../native/extension-runtime.js';
+import {
+  cString,
+  errorCaptureBuffer,
+  OLIPHAUNT_CONFIG_SIZE,
+  OLIPHAUNT_ERROR_CAPTURE_CAPACITY,
+  OLIPHAUNT_ERROR_CAPTURE_SIZE,
+  OLIPHAUNT_RESPONSE_SIZE,
+  packConfigPointers,
+  packPointerArray,
+  packRestoreOptionsPointers,
+  readErrorCapture,
+  readResponseLength,
+  readResponsePointer,
+  responseBuffer,
+  writePointer,
+} from '../native/ffi-layout.js';
+import { createNodeNativeBinding } from '../native/node.js';
+import { publishNativeDescriptor } from '../root-descriptor.js';
+import { directRuntimeBinding } from '../runtime/direct.js';
+
+async function main(): Promise {
+  testIndexExportsDefaultClient();
+  testFfiLayoutPackingAndBounds();
+  testPackagedRuntimeLibraryEnvironment();
+  await testNodeNativeBindingUsesExplicitAssetsAndAddon();
+  await testDenoNativeBindingUsesSeparateModuleDirectoryWithoutAmbientMutation();
+}
+
+function testPackagedRuntimeLibraryEnvironment(): void {
+  const previous = Object.fromEntries(
+    ['LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'PATH'].map((name) => [name, process.env[name]]),
+  );
+  try {
+    process.env.LD_LIBRARY_PATH = '/existing/lib';
+    assert.deepEqual(nativeRuntimeLibraryEnvironment('/candidate/runtime', 'linux'), {
+      LD_LIBRARY_PATH: '/candidate/runtime/lib:/existing/lib',
+    });
+    process.env.LD_LIBRARY_PATH = '/candidate/runtime/lib:/existing/lib';
+    assert.deepEqual(nativeRuntimeLibraryEnvironment('/candidate/runtime', 'linux'), {
+      LD_LIBRARY_PATH: '/candidate/runtime/lib:/existing/lib',
+    });
+
+    process.env.DYLD_LIBRARY_PATH = '/candidate/runtime/lib:/existing/macos/lib';
+    assert.deepEqual(nativeRuntimeLibraryEnvironment('/candidate/runtime', 'darwin'), {
+      DYLD_LIBRARY_PATH: '/candidate/runtime/lib:/existing/macos/lib',
+    });
+
+    process.env.PATH = 'C:\\candidate\\runtime\\lib;C:\\existing\\bin;C:\\candidate\\runtime\\bin';
+    assert.deepEqual(nativeRuntimeLibraryEnvironment('C:\\candidate\\runtime', 'win32'), {
+      PATH: 'C:\\candidate\\runtime\\bin;C:\\candidate\\runtime\\lib;C:\\existing\\bin',
+    });
+
+    assert.deepEqual(nativeRuntimeLibraryEnvironment('   ', 'linux'), {});
+    assert.throws(
+      () => nativeRuntimeLibraryEnvironment('/candidate\0runtime', 'linux'),
+      /NUL bytes/,
+    );
+  } finally {
+    for (const [name, value] of Object.entries(previous)) {
+      if (value === undefined) delete process.env[name];
+      else process.env[name] = value;
+    }
+  }
+}
+
+function testIndexExportsDefaultClient(): void {
+  assert.equal(typeof (Oliphaunt as OliphauntClient).open, 'function');
+  assert.equal(typeof (Oliphaunt as OliphauntClient).openServer, 'function');
+  assert.equal(typeof (Oliphaunt as OliphauntClient).restore, 'function');
+  for (const internalName of [
+    'createOliphauntClient',
+    'OliphauntDatabase',
+    'nativeDirectCapabilities',
+    'createDefaultNativeBinding',
+    'createNodeNativeBinding',
+    'createDenoNativeBinding',
+  ]) {
+    assert.equal(internalName in publicEntrypoint, false, `${internalName} must remain internal`);
+  }
+}
+
+function testFfiLayoutPackingAndBounds(): void {
+  assert.deepEqual([...cString('pgdata')], [112, 103, 100, 97, 116, 97, 0]);
+  assert.throws(() => cString('bad\0value'), /NUL bytes/);
+
+  const pointers = packPointerArray([1n, 2n, 3n]);
+  const pointerView = new DataView(pointers.buffer);
+  assert.equal(pointerView.getBigUint64(0, true), 1n);
+  assert.equal(pointerView.getBigUint64(8, true), 2n);
+  assert.equal(pointerView.getBigUint64(16, true), 3n);
+  assert.equal(packPointerArray([]).byteLength, 8);
+
+  const emptyCapture = errorCaptureBuffer();
+  assert.equal(emptyCapture.byteLength, OLIPHAUNT_ERROR_CAPTURE_SIZE);
+  assert.equal(OLIPHAUNT_ERROR_CAPTURE_CAPACITY, 1024);
+  assert.equal(readErrorCapture(emptyCapture), null);
+  const capturedText = new TextEncoder().encode('operation-local failure');
+  new DataView(emptyCapture.buffer).setUint32(0, capturedText.byteLength, true);
+  emptyCapture.set(capturedText, 4);
+  assert.equal(readErrorCapture(emptyCapture), 'operation-local failure');
+  emptyCapture[4 + capturedText.byteLength] = 1;
+  assert.match(readErrorCapture(emptyCapture) ?? '', /invalid error capture/);
+  const invalidLengthCapture = errorCaptureBuffer();
+  new DataView(invalidLengthCapture.buffer).setUint32(0, OLIPHAUNT_ERROR_CAPTURE_CAPACITY, true);
+  assert.match(readErrorCapture(invalidLengthCapture) ?? '', /invalid error capture/);
+  const embeddedNulCapture = errorCaptureBuffer();
+  new DataView(embeddedNulCapture.buffer).setUint32(0, 3, true);
+  embeddedNulCapture.set([0x61, 0, 0x62], 4);
+  assert.match(readErrorCapture(embeddedNulCapture) ?? '', /invalid error capture/);
+  assert.match(readErrorCapture(new Uint8Array(4)) ?? '', /invalid error capture/);
+
+  let nextPointer = 16n;
+  const seenStrings: string[] = [];
+  const pointerOf = (value: Uint8Array): bigint => {
+    const decoded = new TextDecoder().decode(value.slice(0, Math.max(0, value.byteLength - 1)));
+    seenStrings.push(decoded);
+    nextPointer += 16n;
+    return nextPointer;
+  };
+  const packed = packConfigPointers(
+    {
+      pgdata: '/tmp/pgdata',
+      runtimeDirectory: '/tmp/runtime',
+      moduleDirectory: '/tmp/modules',
+      icuDataDirectory: '/tmp/icu',
+      username: 'postgres',
+      database: 'app',
+      extensions: [],
+      startupArgs: ['-c', 'work_mem=8MB'],
+    },
+    pointerOf,
+  );
+  assert.equal(packed.config.byteLength, OLIPHAUNT_CONFIG_SIZE);
+  assert.ok(seenStrings.includes('/tmp/pgdata'));
+  assert.ok(seenStrings.includes('/tmp/runtime'));
+  assert.ok(seenStrings.includes('/tmp/modules'));
+  assert.ok(seenStrings.includes('work_mem=8MB'));
+  assert.ok(seenStrings.includes('/tmp/icu'));
+  assert.equal(packed.keepAlive.length, 9);
+  const configView = new DataView(packed.config.buffer);
+  assert.equal(configView.getUint32(0, true), ABI_VERSION);
+  assert.notEqual(configView.getBigUint64(24, true), 0n);
+  assert.notEqual(configView.getBigUint64(72, true), 0n);
+
+  const restore = packRestoreOptionsPointers(
+    {
+      destination: '/tmp/root',
+      bytes: new Uint8Array([1, 2, 3]),
+    },
+    pointerOf,
+  );
+  assert.equal(restore.options.byteLength, 32);
+  assert.equal(restore.keepAlive.length, 2);
+
+  const response = responseBuffer();
+  assert.equal(response.byteLength, OLIPHAUNT_RESPONSE_SIZE);
+  const responseView = new DataView(response.buffer);
+  writePointer(responseView, 0, 0x1234n);
+  writePointer(responseView, 8, 3n);
+  assert.equal(readResponsePointer(response), 0x1234n);
+  assert.equal(readResponseLength(response), 3);
+  writePointer(responseView, 8, BigInt(Number.MAX_SAFE_INTEGER) + 1n);
+  assert.throws(() => readResponseLength(response), /safe integer/);
+}
+
+async function testNodeNativeBindingUsesExplicitAssetsAndAddon(): Promise {
+  const previousFinalizationRegistry = globalThis.FinalizationRegistry;
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-node-binding-'));
+  const addonPath = join(root, 'mock-addon.cjs');
+  const databaseRoot = join(root, 'database');
+  const runtimeDirectory = join(root, 'runtime');
+  const moduleDirectory = join(runtimeDirectory, 'lib/modules');
+  const extensionDirectory = join(runtimeDirectory, 'share/postgresql/extension');
+  const target = liboliphauntPackageTarget(process.platform, process.arch);
+  await fsMkdir(moduleDirectory, { recursive: true });
+  await fsMkdir(extensionDirectory, { recursive: true });
+  await fsMkdir(join(databaseRoot, 'pgdata', 'global'), { recursive: true });
+  await fsMkdir(join(databaseRoot, 'pgdata', 'pg_wal'));
+  await writeFile(join(databaseRoot, 'pgdata', 'PG_VERSION'), '18\n');
+  await writeFile(join(databaseRoot, 'pgdata', 'global', 'pg_control'), 'control');
+  await publishNativeDescriptor(databaseRoot);
+  await writeFile(join(extensionDirectory, 'hstore.control'), "default_version = '1.0'\n");
+  await writeFile(join(extensionDirectory, 'hstore--1.0.sql'), 'SELECT 1;\n');
+  await writeFile(
+    join(moduleDirectory, `hstore${nativeModuleSuffixForTarget(target.id)}`),
+    'native-module',
+  );
+  await writeFile(
+    join(moduleDirectory, `dict_snowball${nativeModuleSuffixForTarget(target.id)}`),
+    'native-module',
+  );
+  await writeFile(
+    join(moduleDirectory, `plpgsql${nativeModuleSuffixForTarget(target.id)}`),
+    'native-module',
+  );
+  await writeFile(
+    addonPath,
+    `
+let nextHandle = 40n;
+module.exports = {
+  default: {
+    async open(config) {
+      globalThis.__oliphauntNodeAddonCalls.push(['open', config]);
+      nextHandle += 1n;
+      return nextHandle;
+    },
+    execProtocolRaw(handle, request) {
+      globalThis.__oliphauntNodeAddonCalls.push(['execProtocolRaw', handle, Array.from(request)]);
+      return request.buffer.slice(request.byteOffset, request.byteOffset + request.byteLength);
+    },
+    async execProtocolRawStream(handle, request, onChunk) {
+      globalThis.__oliphauntNodeAddonCalls.push(['execProtocolRawStream', handle, Array.from(request)]);
+      onChunk(request.slice());
+    },
+    execSimpleQuery(handle, sql) {
+      globalThis.__oliphauntNodeAddonCalls.push(['execSimpleQuery', handle, sql]);
+      return new Uint8Array([90, 0, 0, 0, 5, 73]);
+    },
+    async backup(handle) {
+      globalThis.__oliphauntNodeAddonCalls.push(['backup', handle]);
+      return new Uint8Array([4, 5, 6]).buffer;
+    },
+    async restore(options) {
+      globalThis.__oliphauntNodeAddonCalls.push(['restore', options]);
+    },
+    cancel(handle) {
+      globalThis.__oliphauntNodeAddonCalls.push(['cancel', handle]);
+    },
+    async detach(handle) {
+      globalThis.__oliphauntNodeAddonCalls.push(['detach', handle]);
+    },
+    createForgottenHandleRecoveryToken(handle) {
+      const token = 'recovery-token:' + handle;
+      globalThis.__oliphauntNodeAddonCalls.push(['createForgottenHandleRecoveryToken', handle, token]);
+      return token;
+    },
+    queueForgottenHandleRecovery(token) {
+      globalThis.__oliphauntNodeAddonCalls.push(['queueForgottenHandleRecovery', token]);
+      return token !== 'stale-recovery-token';
+    },
+  },
+};
+`,
+    'utf8',
+  );
+  const calls: unknown[][] = [];
+  (globalThis as { __oliphauntNodeAddonCalls?: unknown[][] }).__oliphauntNodeAddonCalls = calls;
+  const previousRuntime = process.env.OLIPHAUNT_RUNTIME_DIR;
+  const previousModuleDirectory = process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR;
+  const callerModuleDirectory = join(root, 'caller-owned-modules');
+  type NodeForgottenHandle = {
+    readonly recoveryToken: unknown;
+    readonly releaseOwnership: () => void;
+  };
+  let finalizer: ((held: NodeForgottenHandle) => void) | undefined;
+  let registered: { target: object; held: NodeForgottenHandle; token?: object } | undefined;
+  const unregistered: object[] = [];
+  process.env.OLIPHAUNT_RUNTIME_DIR = runtimeDirectory;
+  process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR = callerModuleDirectory;
+  try {
+    (globalThis as { FinalizationRegistry: unknown }).FinalizationRegistry = class {
+      constructor(callback: (held: NodeForgottenHandle) => void) {
+        finalizer = callback;
+      }
+
+      register(target: object, held: NodeForgottenHandle, token?: object): void {
+        registered = { target, held, token };
+      }
+
+      unregister(token: object): boolean {
+        unregistered.push(token);
+        return true;
+      }
+    };
+    const binding = await createNodeNativeBinding({
+      libraryPath: join(root, 'liboliphaunt.dylib'),
+      nodeAddonPath: addonPath,
+    });
+    const handle = await binding.open({
+      pgdata: join(databaseRoot, 'pgdata'),
+      username: 'postgres',
+      database: 'postgres',
+      extensions: ['hstore'],
+      startupArgs: [],
+    });
+    assert.equal(handle, 41n);
+    const openConfig = calls.find(([name]) => name === 'open')?.[1] as
+      | { moduleDirectory?: string; runtimeDirectory?: string }
+      | undefined;
+    assert.equal(openConfig?.runtimeDirectory, runtimeDirectory);
+    assert.equal(openConfig?.moduleDirectory, moduleDirectory);
+    assert.equal(process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR, callerModuleDirectory);
+    assert.deepEqual([...(await binding.execProtocolRaw(handle, new Uint8Array([7, 8])))], [7, 8]);
+    const chunks: Uint8Array[] = [];
+    await binding.execProtocolStream(handle, new Uint8Array([9, 10]), (chunk) =>
+      chunks.push(chunk),
+    );
+    assert.deepEqual(
+      chunks.map((chunk) => [...chunk]),
+      [[9, 10]],
+    );
+    const execSimpleQuery = binding.execSimpleQuery;
+    assert.ok(execSimpleQuery !== undefined);
+    assert.deepEqual([...(await execSimpleQuery(handle, 'SELECT 1'))], [90, 0, 0, 0, 5, 73]);
+    assert.deepEqual([...(await binding.backup(handle))], [4, 5, 6]);
+    await binding.restore({
+      destination: join(root, 'restore'),
+      bytes: new Uint8Array([1]),
+    });
+    await binding.cancel(handle);
+
+    const forgottenOwner = {};
+    let released = 0;
+    binding.registerForgottenHandleCleanup?.(forgottenOwner, handle, () => {
+      released += 1;
+    });
+    assert.equal(registered?.target, forgottenOwner);
+    assert.equal(registered?.token, forgottenOwner);
+    assert.equal(registered?.held.recoveryToken, 'recovery-token:41');
+    finalizer?.(registered!.held);
+    assert.equal(released, 1);
+    let unsafeRelease = 0;
+    finalizer?.({
+      recoveryToken: 'stale-recovery-token',
+      releaseOwnership: () => {
+        unsafeRelease += 1;
+      },
+    });
+    assert.equal(unsafeRelease, 0, 'native recovery rejection must keep admission closed');
+
+    const explicitlyClosedOwner = {};
+    binding.registerForgottenHandleCleanup?.(explicitlyClosedOwner, handle, () => {});
+    await binding.detach(handle);
+    binding.unregisterForgottenHandleCleanup?.(explicitlyClosedOwner);
+    assert.deepEqual(unregistered, [explicitlyClosedOwner]);
+    assert.deepEqual(
+      calls.map((entry) => entry[0]),
+      [
+        'open',
+        'execProtocolRaw',
+        'execProtocolRawStream',
+        'execSimpleQuery',
+        'backup',
+        'restore',
+        'cancel',
+        'createForgottenHandleRecoveryToken',
+        'queueForgottenHandleRecovery',
+        'queueForgottenHandleRecovery',
+        'createForgottenHandleRecoveryToken',
+        'detach',
+      ],
+    );
+  } finally {
+    if (previousRuntime === undefined) {
+      delete process.env.OLIPHAUNT_RUNTIME_DIR;
+    } else {
+      process.env.OLIPHAUNT_RUNTIME_DIR = previousRuntime;
+    }
+    (globalThis as { FinalizationRegistry: unknown }).FinalizationRegistry =
+      previousFinalizationRegistry;
+    restoreEnv('OLIPHAUNT_EMBEDDED_MODULE_DIR', previousModuleDirectory);
+    delete (globalThis as { __oliphauntNodeAddonCalls?: unknown[][] }).__oliphauntNodeAddonCalls;
+    await rm(root, { recursive: true, force: true });
+  }
+}
+
+async function testDenoNativeBindingUsesSeparateModuleDirectoryWithoutAmbientMutation(): Promise {
+  const previousDeno = (globalThis as { Deno?: unknown }).Deno;
+  const previousFinalizationRegistry = globalThis.FinalizationRegistry;
+  const previousModuleDirectory = process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR;
+  const previousRuntime = process.env.OLIPHAUNT_RUNTIME_DIR;
+  const previousLibraryPath = process.env.LIBOLIPHAUNT_PATH;
+  const previousLibrarySearchPath = process.env.LD_LIBRARY_PATH;
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-js-deno-config-'));
+  const databaseRoot = join(root, 'database');
+  const runtime = join(root, 'runtime');
+  const embeddedModules = join(runtime, 'lib/modules');
+  const pointerStrings = new Map();
+  let nextPointer = 0x1000n;
+  const calls: string[] = [];
+  let copyLastErrorCalls = 0;
+  let restoreCallsStartedResolve: (() => void) | undefined;
+  let releaseRestoreCalls: (() => void) | undefined;
+  let restoreCallCount = 0;
+  let rejectInit = false;
+  let initFailure: unknown;
+  let initStatus = 0;
+  let initHandleAddress = 0x99n;
+  let logicalGeneration = 23n;
+  let rejectDetach = false;
+  let detachFailure: unknown;
+  let generationCleanupStatus = 1;
+  const restoreCallsStarted = new Promise((resolve) => {
+    restoreCallsStartedResolve = resolve;
+  });
+  const restoreCallsMayFinish = new Promise((resolve) => {
+    releaseRestoreCalls = resolve;
+  });
+  let finalizer: ((held: { generation: bigint; releaseOwnership: () => void }) => void) | undefined;
+  let registered:
+    | {
+        target: object;
+        held: { generation: bigint; releaseOwnership: () => void };
+        token?: object;
+      }
+    | undefined;
+  const unregistered: object[] = [];
+  try {
+    (globalThis as { FinalizationRegistry: unknown }).FinalizationRegistry = class {
+      constructor(callback: (held: { generation: bigint; releaseOwnership: () => void }) => void) {
+        finalizer = callback;
+      }
+
+      register(
+        target: object,
+        held: { generation: bigint; releaseOwnership: () => void },
+        token?: object,
+      ): void {
+        registered = { target, held, token };
+      }
+
+      unregister(token: object): boolean {
+        unregistered.push(token);
+        return true;
+      }
+    };
+    delete process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR;
+    delete process.env.OLIPHAUNT_RUNTIME_DIR;
+    delete process.env.LIBOLIPHAUNT_PATH;
+    await fsMkdir(join(databaseRoot, 'pgdata', 'global'), { recursive: true });
+    await fsMkdir(join(databaseRoot, 'pgdata', 'pg_wal'));
+    await writeFile(join(databaseRoot, 'pgdata', 'PG_VERSION'), '18\n');
+    await writeFile(join(databaseRoot, 'pgdata', 'global', 'pg_control'), 'control');
+    await publishNativeDescriptor(databaseRoot);
+    await fsMkdir(join(runtime, 'share/postgresql/extension'), {
+      recursive: true,
+    });
+    await fsMkdir(join(runtime, 'lib/postgresql'), { recursive: true });
+    await fsMkdir(embeddedModules, { recursive: true });
+    await writeFile(join(runtime, 'share/postgresql/extension/hstore.control'), 'extension');
+    await writeFile(join(runtime, 'share/postgresql/extension/hstore--1.0.sql'), 'install');
+    await writeFile(join(runtime, 'lib/postgresql/hstore.so'), 'subprocess hstore');
+    await writeFile(join(runtime, 'lib/postgresql/dict_snowball.so'), 'subprocess dict_snowball');
+    await writeFile(join(runtime, 'lib/postgresql/plpgsql.so'), 'subprocess plpgsql');
+    await writeFile(join(embeddedModules, 'hstore.so'), 'embedded hstore');
+    await writeFile(join(embeddedModules, 'dict_snowball.so'), 'embedded dict_snowball');
+    await writeFile(join(embeddedModules, 'plpgsql.so'), 'embedded plpgsql');
+
+    const deno = fsBackedDenoRuntime(root) as Record;
+    (globalThis as { Deno?: unknown }).Deno = {
+      ...deno,
+      dlopen(_path: string, definitions: Record) {
+        assert.deepEqual(definitions.oliphaunt_init_with_error, {
+          parameters: ['buffer', 'buffer', 'buffer'],
+          result: 'i32',
+          nonblocking: true,
+        });
+        assert.deepEqual(definitions.oliphaunt_exec_protocol_raw_stream_with_error, {
+          parameters: ['pointer', 'buffer', 'usize', 'function', 'pointer', 'buffer'],
+          result: 'i32',
+          nonblocking: true,
+        });
+        assert.deepEqual(definitions.oliphaunt_detach_with_error, {
+          parameters: ['pointer', 'buffer'],
+          result: 'i32',
+          nonblocking: true,
+        });
+        assert.deepEqual(definitions.oliphaunt_logical_generation, {
+          parameters: ['pointer'],
+          result: 'u64',
+        });
+        assert.deepEqual(definitions.oliphaunt_close_if_generation, {
+          parameters: ['u64'],
+          result: 'i32',
+          nonblocking: true,
+        });
+        assert.deepEqual(definitions.oliphaunt_copy_last_error, {
+          parameters: ['pointer', 'buffer', 'usize'],
+          result: 'usize',
+        });
+        assert.deepEqual(definitions.oliphaunt_backup_with_error, {
+          parameters: ['pointer', 'buffer', 'buffer'],
+          result: 'i32',
+          nonblocking: true,
+        });
+        assert.deepEqual(definitions.oliphaunt_restore_with_error, {
+          parameters: ['buffer', 'buffer'],
+          result: 'i32',
+          nonblocking: true,
+        });
+        return {
+          symbols: {
+            async oliphaunt_init_with_error(config: Uint8Array, out: Uint8Array) {
+              calls.push('init');
+              if (rejectInit) throw initFailure;
+              assert.equal(process.env.OLIPHAUNT_EMBEDDED_MODULE_DIR, undefined);
+              const view = new DataView(config.buffer, config.byteOffset, config.byteLength);
+              assert.equal(view.getUint32(0, true), ABI_VERSION);
+              assert.equal(pointerStrings.get(view.getBigUint64(24, true)), embeddedModules);
+              new DataView(out.buffer, out.byteOffset, out.byteLength).setBigUint64(
+                0,
+                initHandleAddress,
+                true,
+              );
+              return initStatus;
+            },
+            oliphaunt_exec_protocol_with_error() {
+              return 0;
+            },
+            oliphaunt_exec_protocol_raw_stream_with_error(
+              _handle: unknown,
+              request: Uint8Array,
+              _requestLength: bigint,
+              callback: (context: unknown, bytes: unknown, length: bigint) => number,
+              context: unknown,
+              captured: Uint8Array,
+            ) {
+              const callbackStatus = callback(context, null, 0n);
+              if (request[0] === 4) {
+                assert.equal(callbackStatus, 0);
+                return 1;
+              }
+              assert.equal(callbackStatus, 1);
+              if (request[0] === 3) return 0;
+              if (request[0] === 1) {
+                writeErrorCapture(captured, 'stream callback aborted after confirmed recovery');
+                return 1;
+              }
+              writeErrorCapture(captured, 'stream transport recovery failed');
+              return -1;
+            },
+            oliphaunt_exec_simple_query_with_error() {
+              return 0;
+            },
+            oliphaunt_backup_with_error() {
+              return 0;
+            },
+            async oliphaunt_restore_with_error(options: Uint8Array, captured: Uint8Array) {
+              const view = new DataView(options.buffer, options.byteOffset, options.byteLength);
+              const destination = pointerStrings.get(view.getBigUint64(8, true));
+              assert.ok(destination);
+              restoreCallCount += 1;
+              if (restoreCallCount === 2) restoreCallsStartedResolve?.();
+              await restoreCallsMayFinish;
+              writeErrorCapture(captured, `${destination} failed on its native worker`);
+              return -1;
+            },
+            oliphaunt_cancel() {
+              return 0;
+            },
+            async oliphaunt_detach_with_error(_handle: unknown, _captured: Uint8Array) {
+              calls.push('detach');
+              if (rejectDetach) throw detachFailure;
+              return 0;
+            },
+            oliphaunt_logical_generation() {
+              calls.push('logical-generation');
+              return logicalGeneration;
+            },
+            oliphaunt_close_if_generation(generation: bigint) {
+              calls.push(`close-generation:${generation}`);
+              return generationCleanupStatus;
+            },
+            oliphaunt_copy_last_error(_handle: unknown, output: Uint8Array) {
+              copyLastErrorCalls += 1;
+              output.fill(0);
+              return 0n;
+            },
+            oliphaunt_free_response() {},
+          },
+        };
+      },
+      UnsafePointer: {
+        of(value: Uint8Array) {
+          nextPointer += 0x10n;
+          pointerStrings.set(
+            nextPointer,
+            new TextDecoder().decode(value.subarray(0, Math.max(0, value.byteLength - 1))),
+          );
+          return { address: nextPointer };
+        },
+        value(pointer: { address: bigint }) {
+          return pointer.address;
+        },
+        create(address: bigint) {
+          return { address };
+        },
+      },
+      UnsafePointerView: class {},
+      UnsafeCallback: {
+        threadSafe(_definition: unknown, callback: unknown) {
+          return {
+            pointer: callback,
+            close() {},
+          };
+        },
+      },
+    };
+
+    const binding = await createDenoNativeBinding({
+      libraryPath: join(root, 'liboliphaunt.so'),
+    });
+    const handle = await binding.open({
+      pgdata: join(databaseRoot, 'pgdata'),
+      runtimeDirectory: runtime,
+      username: 'postgres',
+      database: 'postgres',
+      extensions: ['hstore'],
+      startupArgs: [],
+    });
+    assert.deepEqual(handle, { address: 0x99n });
+    assert.deepEqual(calls, ['init', 'logical-generation']);
+
+    await assert.rejects(
+      () =>
+        binding.execProtocolStream(handle, new Uint8Array([1]), () => {
+          throw new Error('Deno stream callback failed');
+        }),
+      /Deno stream callback failed/,
+    );
+    const undefinedCallbackFailure = await binding
+      .execProtocolStream(handle, new Uint8Array([1]), () => {
+        throw undefined;
+      })
+      .then(
+        () => ({ fulfilled: true as const, error: undefined }),
+        (error: unknown) => ({ fulfilled: false as const, error }),
+      );
+    assert.equal(undefinedCallbackFailure.fulfilled, false);
+    assert.equal(
+      undefinedCallbackFailure.error,
+      undefined,
+      'a recovered Deno callback abort must preserve even an undefined rejection reason',
+    );
+    await assert.rejects(
+      () =>
+        binding.execProtocolStream(handle, new Uint8Array([3]), () => {
+          throw undefined;
+        }),
+      /reported success after the callback failed/,
+    );
+    await assert.rejects(
+      () => binding.execProtocolStream(handle, new Uint8Array([4]), () => undefined),
+      /reported a recovered callback abort without a callback failure/,
+    );
+    await assert.rejects(
+      () =>
+        binding.execProtocolStream(handle, new Uint8Array([2]), () => {
+          throw new Error('this callback failure must not mask native recovery');
+        }),
+      /stream transport recovery failed/,
+    );
+
+    const firstRestore = binding.restore({
+      destination: '/tmp/first-restore',
+      bytes: new Uint8Array([1]),
+    });
+    const secondRestore = binding.restore({
+      destination: '/tmp/second-restore',
+      bytes: new Uint8Array([2]),
+    });
+    await restoreCallsStarted;
+    releaseRestoreCalls?.();
+    const restoreResults = await Promise.allSettled([firstRestore, secondRestore]);
+    assert.equal(restoreResults[0]?.status, 'rejected');
+    assert.equal(restoreResults[1]?.status, 'rejected');
+    assert.match(
+      String((restoreResults[0] as PromiseRejectedResult).reason),
+      /\/tmp\/first-restore failed on its native worker/,
+    );
+    assert.match(
+      String((restoreResults[1] as PromiseRejectedResult).reason),
+      /\/tmp\/second-restore failed on its native worker/,
+    );
+    assert.equal(
+      copyLastErrorCalls,
+      0,
+      'nonblocking Deno failures must not read worker-local errors later on the JS thread',
+    );
+
+    const forgottenOwner = {};
+    let released = 0;
+    binding.registerForgottenHandleCleanup?.(forgottenOwner, handle, () => {
+      released += 1;
+    });
+    assert.equal(registered?.target, forgottenOwner);
+    assert.equal(registered?.token, forgottenOwner);
+    assert.equal(registered?.held.generation, 23n);
+    finalizer?.(registered!.held);
+    assert.equal(released, 0, 'the finalizer must return before native cleanup settles');
+    await new Promise((resolve) => setImmediate(resolve));
+    assert.equal(released, 1);
+    assert.deepEqual(calls, ['init', 'logical-generation', 'close-generation:23']);
+
+    const failedCleanupOwner = {};
+    let releasedAfterFailedCleanup = 0;
+    generationCleanupStatus = -1;
+    binding.registerForgottenHandleCleanup?.(failedCleanupOwner, handle, () => {
+      releasedAfterFailedCleanup += 1;
+    });
+    finalizer?.(registered!.held);
+    await new Promise((resolve) => setImmediate(resolve));
+    assert.equal(
+      releasedAfterFailedCleanup,
+      0,
+      'failed native generation cleanup must keep direct admission closed',
+    );
+    assert.equal(calls.at(-1), 'close-generation:23');
+
+    const explicitlyClosedOwner = {};
+    binding.registerForgottenHandleCleanup?.(explicitlyClosedOwner, handle, () => {});
+    await binding.detach(handle);
+    binding.unregisterForgottenHandleCleanup?.(explicitlyClosedOwner);
+    assert.deepEqual(unregistered, [explicitlyClosedOwner]);
+    assert.equal(calls.at(-1), 'detach');
+
+    calls.length = 0;
+    const openConfig = {
+      pgdata: join(databaseRoot, 'pgdata'),
+      runtimeDirectory: runtime,
+      username: 'postgres',
+      database: 'postgres',
+      extensions: ['hstore'],
+      startupArgs: [],
+    };
+
+    const uncertainHandle = await binding.open(openConfig);
+    rejectDetach = true;
+    detachFailure = new Error('Deno detach worker delivery rejected');
+    const uncertainClose = await directRuntimeBinding(binding).close(uncertainHandle);
+    assert.equal(uncertainClose.state, 'terminal');
+    assert.match(
+      String(uncertainClose.error),
+      /detach delivery failed after its outcome became unknown/,
+    );
+    assert.equal((uncertainClose.error as Error).cause, detachFailure);
+    await assert.rejects(
+      () => binding.detach(uncertainHandle),
+      (error: unknown) => error === uncertainClose.error,
+    );
+    await assert.rejects(
+      () => binding.open(openConfig),
+      /prior native lifecycle outcome left ownership unknown/,
+    );
+    assert.deepEqual(
+      calls,
+      ['init', 'logical-generation', 'detach'],
+      'an outcome-unknown detach is terminal, cannot be retried, and closes admission before another init',
+    );
+
+    const createFreshBinding = async () => {
+      const freshDeno = await import(`../native/deno.ts?test=${crypto.randomUUID()}`);
+      return freshDeno.createDenoNativeBinding({
+        libraryPath: join(root, 'liboliphaunt.so'),
+      });
+    };
+
+    calls.length = 0;
+    rejectInit = false;
+    initStatus = -1;
+    initHandleAddress = 0x99n;
+    logicalGeneration = 23n;
+    rejectDetach = false;
+    detachFailure = undefined;
+    let freshBinding = await createFreshBinding();
+    await assert.rejects(() => freshBinding.open(openConfig), /native liboliphaunt init failed/);
+    initStatus = 0;
+    const retryHandle = await freshBinding.open(openConfig);
+    await freshBinding.detach(retryHandle);
+    assert.deepEqual(
+      calls,
+      ['init', 'init', 'logical-generation', 'detach'],
+      'a confirmed nonzero init status remains retryable',
+    );
+
+    calls.length = 0;
+    rejectInit = true;
+    initStatus = 0;
+    initFailure = new Error('Deno init worker delivery rejected');
+    rejectDetach = false;
+    detachFailure = undefined;
+    initHandleAddress = 0x99n;
+    logicalGeneration = 23n;
+    freshBinding = await createFreshBinding();
+    await assert.rejects(
+      () => freshBinding.open(openConfig),
+      (error) => error === initFailure,
+    );
+    await assert.rejects(
+      () => freshBinding.open(openConfig),
+      /prior native lifecycle outcome left ownership unknown/,
+    );
+    assert.deepEqual(calls, ['init'], 'a rejected init worker must close admission immediately');
+
+    calls.length = 0;
+    rejectInit = false;
+    initHandleAddress = 0n;
+    freshBinding = await createFreshBinding();
+    await assert.rejects(() => freshBinding.open(openConfig), /init returned a null handle/);
+    await assert.rejects(
+      () => freshBinding.open(openConfig),
+      /prior native lifecycle outcome left ownership unknown/,
+    );
+    assert.deepEqual(calls, ['init'], 'a null successful init must close admission immediately');
+
+    calls.length = 0;
+    initHandleAddress = 0x99n;
+    logicalGeneration = 0n;
+    freshBinding = await createFreshBinding();
+    await assert.rejects(() => freshBinding.open(openConfig), /invalid logical generation/);
+    await assert.rejects(
+      () => freshBinding.open(openConfig),
+      /prior native lifecycle outcome left ownership unknown/,
+    );
+    assert.deepEqual(
+      calls,
+      ['init', 'logical-generation'],
+      'an invalid generation must close admission without dereferencing the handle',
+    );
+  } finally {
+    if (previousDeno === undefined) {
+      delete (globalThis as { Deno?: unknown }).Deno;
+    } else {
+      (globalThis as { Deno?: unknown }).Deno = previousDeno;
+    }
+    (globalThis as { FinalizationRegistry: unknown }).FinalizationRegistry =
+      previousFinalizationRegistry;
+    restoreEnv('OLIPHAUNT_EMBEDDED_MODULE_DIR', previousModuleDirectory);
+    restoreEnv('OLIPHAUNT_RUNTIME_DIR', previousRuntime);
+    restoreEnv('LIBOLIPHAUNT_PATH', previousLibraryPath);
+    restoreEnv('LD_LIBRARY_PATH', previousLibrarySearchPath);
+    await rm(root, { recursive: true, force: true });
+  }
+}
+
+function fsBackedDenoRuntime(tempRoot: string): unknown {
+  return {
+    build: { os: 'linux', arch: 'x86_64' },
+    env: {
+      get(name: string) {
+        return name === 'TMPDIR' ? tempRoot : undefined;
+      },
+    },
+    async readTextFile(path: string | URL) {
+      return readFile(fsPath(path), 'utf8');
+    },
+    async *readDir(path: string | URL) {
+      for (const entry of await readdir(fsPath(path), {
+        withFileTypes: true,
+      })) {
+        yield {
+          name: entry.name,
+          isFile: entry.isFile(),
+          isDirectory: entry.isDirectory(),
+        };
+      }
+    },
+    async stat(path: string | URL) {
+      const metadata = await fsStat(fsPath(path));
+      return {
+        isFile: metadata.isFile(),
+        isDirectory: metadata.isDirectory(),
+      };
+    },
+  };
+}
+
+function writeErrorCapture(capture: Uint8Array, message: string): void {
+  capture.fill(0);
+  const bytes = new TextEncoder().encode(message);
+  assert.ok(bytes.byteLength < OLIPHAUNT_ERROR_CAPTURE_CAPACITY);
+  new DataView(capture.buffer, capture.byteOffset, capture.byteLength).setUint32(
+    0,
+    bytes.byteLength,
+    true,
+  );
+  capture.set(bytes, 4);
+}
+
+function fsPath(path: string | URL): string {
+  return path instanceof URL ? fileURLToPath(path) : path;
+}
+
+function restoreEnv(name: string, value: string | undefined): void {
+  if (value === undefined) {
+    delete process.env[name];
+  } else {
+    process.env[name] = value;
+  }
+}
+
+test('native bindings', async () => {
+  await main();
+});
diff --git a/src/sdks/js/src/__tests__/native-direct-contract.d.mts b/src/sdks/ts/sdk/src/__tests__/native-direct-contract.d.mts
similarity index 100%
rename from src/sdks/js/src/__tests__/native-direct-contract.d.mts
rename to src/sdks/ts/sdk/src/__tests__/native-direct-contract.d.mts
diff --git a/src/sdks/ts/sdk/src/__tests__/native-direct-contract.mts b/src/sdks/ts/sdk/src/__tests__/native-direct-contract.mts
new file mode 100644
index 000000000..d71e0fff9
--- /dev/null
+++ b/src/sdks/ts/sdk/src/__tests__/native-direct-contract.mts
@@ -0,0 +1,119 @@
+import assert from 'node:assert/strict';
+import { join } from 'node:path';
+import { createRequire } from 'node:module';
+import { pathToFileURL } from 'node:url';
+import type { OliphauntClient, OliphauntDatabase, OpenConfig } from '../types.js';
+
+const { simpleQuery } = await import(
+  pathToFileURL(
+    createRequire(process.env.OLIPHAUNT_SMOKE_SDK ?? import.meta.url).resolve(
+      '@oliphaunt/ts-query/protocol',
+    ),
+  ).href
+);
+
+export async function assertNativeDatabaseContract(
+  Oliphaunt: OliphauntClient,
+  config: Omit,
+  label: string,
+) {
+  // Direct close detaches a logical session; only process exit releases its root.
+  // The Shell caller runs each phase in a fresh host and cleans up after exit.
+  const workspace = process.env.OLIPHAUNT_SMOKE_ROOT;
+  const phase = process.env.OLIPHAUNT_SMOKE_PHASE;
+  assert.ok(workspace, 'OLIPHAUNT_SMOKE_ROOT is required');
+  assert.ok(phase === 'source' || phase === 'restored', 'expected source or restored smoke phase');
+  const root = join(workspace, label);
+  const sourceRoot = join(root, 'source');
+  const restoredRoot = join(root, 'restored');
+  let database: OliphauntDatabase | undefined;
+  try {
+    database = await Oliphaunt.open({
+      ...config,
+      storage: { kind: 'directory', path: phase === 'source' ? sourceRoot : restoredRoot },
+    });
+    await assertStructuredQueryContract(database, label);
+    await assertOrmSurfaceContract(database, label);
+    if (phase === 'restored') {
+      const restored = await database.query('SELECT value FROM backup_probe');
+      assert.deepEqual(restored.rows, [{ value: label }]);
+      return;
+    }
+    const callbackError = new Error('stream consumer stopped');
+    let callbacks = 0;
+    await assert.rejects(
+      database.execProtocolRawStream(simpleQuery('SELECT generate_series(1, 1000)'), () => {
+        callbacks += 1;
+        throw callbackError;
+      }),
+      (error) => error === callbackError,
+    );
+    assert.equal(callbacks, 1);
+    assert.deepEqual((await database.query('SELECT 42 AS answer')).rows, [{ answer: 42 }]);
+    await database.exec('CREATE TABLE backup_probe (value text NOT NULL)');
+    await database.query('INSERT INTO backup_probe VALUES ($1)', [label]);
+    const backup = await database.backup();
+    assert.ok(backup.byteLength > 0);
+    await assertStructuredQueryContract(database, label);
+    await database.close();
+    database = undefined;
+
+    await Oliphaunt.restore(restoredRoot, backup);
+    database = await Oliphaunt.open({
+      ...config,
+      storage: { kind: 'directory', path: sourceRoot },
+    });
+    await assertStructuredQueryContract(database, label);
+    await database.close();
+    database = undefined;
+
+    await assert.rejects(
+      Oliphaunt.restore(join(root, 'invalid'), backup.subarray(0, 8)),
+      (error) => error instanceof Error && error.message.length > 0,
+    );
+  } finally {
+    await database?.close();
+  }
+}
+
+async function assertStructuredQueryContract(database: OliphauntDatabase, label: string) {
+  const sql = `SELECT '${label}'::text AS value`;
+  const decoded = await database.query(sql);
+  assert.deepEqual(decoded.rows, [{ value: label }]);
+
+  const positional = await database.query(sql, [], { rowMode: 'array' });
+  assert.deepEqual(positional.rows, [[label]]);
+
+  const raw = await database.queryRaw(sql);
+  assert.equal(raw.getText(0, 'value'), label);
+}
+
+async function assertOrmSurfaceContract(database: OliphauntDatabase, label: string) {
+  const decoded = await database.query(
+    'SELECT $1::text AS label, $2::int8 AS wide, $3::jsonb AS document, $4::int4[] AS numbers',
+    [label, 9007199254740993n, { ok: true }, [1, 2, 3]],
+  );
+  assert.deepEqual(decoded.rows, [
+    {
+      label,
+      wide: '9007199254740993',
+      document: { ok: true },
+      numbers: [1, 2, 3],
+    },
+  ]);
+
+  const custom = await database.query('SELECT 42::int4 AS answer', [], {
+    decoders: { 23: (value, field) => `custom:${value}:${field.typeOid}` },
+  });
+  assert.deepEqual(custom.rows, [{ answer: 'custom:42:23' }]);
+
+  const description = await database.describe('SELECT $1::int4 AS answer');
+  assert.deepEqual(description.parameterTypeOids, [23]);
+  assert.equal(description.fields?.[0]?.typeOid, 23);
+
+  const execution = await database.exec('SELECT 1::int4 AS first; SELECT 2::int4 AS second');
+  assert.deepEqual(
+    execution.statements.map((statement) => statement.rows),
+    [[{ first: 1 }], [{ second: 2 }]],
+  );
+}
diff --git a/src/sdks/js/src/__tests__/native-initialize.test.ts b/src/sdks/ts/sdk/src/__tests__/native-initialize.test.ts
similarity index 79%
rename from src/sdks/js/src/__tests__/native-initialize.test.ts
rename to src/sdks/ts/sdk/src/__tests__/native-initialize.test.ts
index 67758eb3a..539972911 100644
--- a/src/sdks/js/src/__tests__/native-initialize.test.ts
+++ b/src/sdks/ts/sdk/src/__tests__/native-initialize.test.ts
@@ -1,20 +1,48 @@
 import assert from 'node:assert/strict';
-import { mkdir, mkdtemp, readdir, rm, symlink, writeFile } from 'node:fs/promises';
+import { mkdir, mkdtemp, readdir, rm, stat, symlink, writeFile } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { test } from 'vitest';
+import { test } from 'bun:test';
 
 import {
-  requireNativeClusterSeedPath,
-  requireNativeClusterSeedTarget,
-} from '../native/cluster-seed.js';
-import {
+  copyNativeClusterSeed,
   initializeNativePgdata,
   nativeInitdbArgs,
   nativePostgresChildEnvironment,
 } from '../native/initialize.js';
 import { publishNativeDescriptor } from '../root-descriptor.js';
 
+test('native seed copy restores empty directories and makes PGDATA private', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-native-seed-'));
+  try {
+    const seed = join(root, 'seed');
+    const pgdata = join(root, 'pgdata');
+    await mkdir(seed, { mode: 0o755 });
+    await writeFile(join(seed, 'PG_VERSION'), '18\n');
+    await copyNativeClusterSeed(seed, pgdata, ['pg_wal/archive_status', 'pg_logical/snapshots']);
+    assert.ok((await stat(join(pgdata, 'pg_wal/archive_status'))).isDirectory());
+    assert.ok((await stat(join(pgdata, 'pg_logical/snapshots'))).isDirectory());
+    assert.deepEqual(await readdir(seed), ['PG_VERSION']);
+    if (process.platform !== 'win32') assert.equal((await stat(pgdata)).mode & 0o777, 0o700);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('native seed copy rejects symbolic links', async () => {
+  if (process.platform === 'win32') return;
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-native-seed-'));
+  try {
+    const seed = join(root, 'seed');
+    await mkdir(seed);
+    await writeFile(join(root, 'outside'), 'external');
+    await symlink(join(root, 'outside'), join(seed, 'linked'));
+    await assert.rejects(copyNativeClusterSeed(seed, join(root, 'pgdata')), /unsupported entry/);
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
 test('fresh native roots reject a non-bootstrap role before PGDATA mutation', async () => {
   const root = await mkdtemp(join(tmpdir(), 'oliphaunt-native-initialize-'));
   let populated = false;
@@ -181,25 +209,6 @@ test('native PostgreSQL child environments isolate internal seed controls', () =
   );
 });
 
-test('native runtime carrier metadata is host-bound and uses fixed seed siblings', () => {
-  assert.equal(
-    requireNativeClusterSeedTarget('linux-x64-gnu', 'linux-x64-gnu', 'fixture'),
-    'linux-x64-gnu',
-  );
-  assert.equal(
-    requireNativeClusterSeedPath('cluster-seed', 'cluster-seed', 'fixture'),
-    'cluster-seed',
-  );
-  assert.throws(
-    () => requireNativeClusterSeedTarget('other-target', 'linux-x64-gnu', 'fixture'),
-    /clusterSeedTarget/,
-  );
-  assert.throws(
-    () => requireNativeClusterSeedPath('nested/cluster-seed', 'cluster-seed', 'fixture'),
-    /must be cluster-seed/,
-  );
-});
-
 async function completeRoot(): Promise {
   const root = await mkdtemp(join(tmpdir(), 'oliphaunt-native-existing-'));
   await writeCompletePgdata(join(root, 'pgdata'));
diff --git a/src/sdks/ts/sdk/src/__tests__/native-resources-smoke.mts b/src/sdks/ts/sdk/src/__tests__/native-resources-smoke.mts
new file mode 100644
index 000000000..661ca4cef
--- /dev/null
+++ b/src/sdks/ts/sdk/src/__tests__/native-resources-smoke.mts
@@ -0,0 +1,78 @@
+import assert from 'node:assert/strict';
+import { createRequire } from 'node:module';
+import { mkdir, readFile, writeFile } from 'node:fs/promises';
+import { dirname, join } from 'node:path';
+import { Oliphaunt } from '@oliphaunt/ts';
+
+const require = createRequire(import.meta.url);
+const root = process.env.OLIPHAUNT_RESOURCE_SMOKE_ROOT;
+assert.ok(
+  root,
+  'OLIPHAUNT_RESOURCE_SMOKE_ROOT must be an isolated directory cleaned after host exit',
+);
+const profile = process.env.OLIPHAUNT_RESOURCE_PROFILE ?? 'standard';
+assert.ok(profile === 'standard' || profile === 'icu' || profile === 'none');
+const topology = process.env.OLIPHAUNT_RESOURCE_TOPOLOGY ?? 'direct';
+assert.ok(topology === 'direct' || topology === 'broker');
+const packageName = process.env.OLIPHAUNT_RESOURCE_SEED_PACKAGE;
+assert.ok(
+  profile === 'none' || packageName,
+  'OLIPHAUNT_RESOURCE_SEED_PACKAGE must name the installed host seed',
+);
+const seed =
+  profile === 'none'
+    ? undefined
+    : {
+        directory: dirname(require.resolve(`${packageName}/pgdata/PG_VERSION`)),
+        manifestPath: require.resolve(`${packageName}/manifest.json`),
+      };
+const icuData =
+  profile === 'icu'
+    ? {
+        directory: dirname(require.resolve('@oliphaunt/icu/data')),
+        manifestPath: require.resolve('@oliphaunt/icu/manifest'),
+      }
+    : undefined;
+const config = {
+  topology,
+  libraryPath: process.env.LIBOLIPHAUNT_PATH,
+  runtimeDirectory: process.env.OLIPHAUNT_INSTALL_DIR,
+  brokerExecutable: process.env.OLIPHAUNT_BROKER,
+  seed,
+  icuData,
+} as const;
+if (seed) {
+  const badManifest = join(root, 'corrupt-seed.json');
+  const manifest = JSON.parse(await readFile(seed.manifestPath, 'utf8'));
+  manifest.directory.treeSha256 = '0'.repeat(64);
+  manifest.directory.path = seed.directory;
+  await writeFile(badManifest, JSON.stringify(manifest));
+  await assert.rejects(
+    Oliphaunt.open({
+      ...config,
+      seed: { ...seed, manifestPath: badManifest },
+      storage: { kind: 'directory', path: join(root, 'rejected') },
+    }),
+  );
+  await assert.rejects(readFile(join(root, 'rejected', 'pgdata', 'PG_VERSION')), /ENOENT/);
+}
+const storage = { kind: 'directory', path: join(root, 'database') } as const;
+await mkdir(root, { recursive: true });
+let database = await Oliphaunt.open({ ...config, storage });
+assert.deepEqual((await database.query('SELECT 42 AS answer')).rows, [{ answer: 42 }]);
+if (icuData)
+  assert.deepEqual((await database.query(`SELECT 'a' < 'b' COLLATE "und-x-icu" AS ordered`)).rows, [
+    { ordered: true },
+  ]);
+await database.exec(
+  'CREATE TABLE resource_probe(value integer); INSERT INTO resource_probe VALUES (73)',
+);
+await database.close();
+database = await Oliphaunt.open({
+  ...config,
+  storage,
+  seed: { directory: '/missing-seed', manifestPath: '/missing-seed-manifest' },
+});
+assert.deepEqual((await database.query('SELECT value FROM resource_probe')).rows, [{ value: 73 }]);
+await database.close();
+console.log(`native resource ${profile}/${topology} passed`);
diff --git a/src/sdks/ts/sdk/src/__tests__/native-resources.test.ts b/src/sdks/ts/sdk/src/__tests__/native-resources.test.ts
new file mode 100644
index 000000000..c598fd740
--- /dev/null
+++ b/src/sdks/ts/sdk/src/__tests__/native-resources.test.ts
@@ -0,0 +1,101 @@
+import { test, expect } from 'bun:test';
+import { createHash } from 'node:crypto';
+import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import { validateSelectedIcuData, validateSelectedNativeSeed } from '../native/cluster-seed.js';
+
+// Producer wire format: UTF-8 path NUL byte-count NUL contents newline.
+function digest(files: Record): string {
+  const hash = createHash('sha256');
+  for (const [path, content] of Object.entries(files).sort(([a], [b]) =>
+    Buffer.compare(Buffer.from(a), Buffer.from(b)),
+  )) {
+    hash.update(`${path}\0${Buffer.byteLength(content)}\0${content}\n`);
+  }
+  return hash.digest('hex');
+}
+
+test('explicit native resources reject incompatible and altered bytes before initialization', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-selected-seed-'));
+  const seed = { directory: join(root, 'pgdata'), manifestPath: join(root, 'manifest.json') };
+  const files = { PG_VERSION: '18\n', 'global/pg_control': 'control' };
+  const manifest = {
+    schema: 'oliphaunt-cluster-seed-v1',
+    artifactRole: 'cluster-seed-standard',
+    catalogProfile: 'standard',
+    runtime: {
+      product: 'liboliphaunt-native',
+      version: '1.2.3',
+      engineFamily: 'native',
+      target: 'linux-x64-gnu',
+      postgresMajor: 18,
+      physicalFormat: 'native-pg18-v1',
+      compatibilityKey: 'native-pg18-linux-x64-gnu-v1',
+    },
+    directory: { path: 'pgdata', treeSha256: digest(files), emptyDirectories: ['pg_notify'] },
+    icu: null,
+  };
+  try {
+    await mkdir(join(seed.directory, 'global'), { recursive: true });
+    for (const [path, content] of Object.entries(files))
+      await writeFile(join(seed.directory, path), content);
+    await writeFile(seed.manifestPath, JSON.stringify(manifest));
+    expect(await validateSelectedNativeSeed(seed, 'linux-x64-gnu', '1.2.3')).toEqual({
+      catalogProfile: 'standard',
+      emptyDirectories: ['pg_notify'],
+    });
+    await expect(validateSelectedNativeSeed(seed, 'linux-arm64-gnu', '1.2.3')).rejects.toThrow(
+      'incompatible',
+    );
+    await expect(validateSelectedNativeSeed(seed, 'linux-x64-gnu', '1.2.4')).rejects.toThrow(
+      'incompatible',
+    );
+    manifest.directory.emptyDirectories = ['../escape'];
+    await writeFile(seed.manifestPath, JSON.stringify(manifest));
+    await expect(validateSelectedNativeSeed(seed, 'linux-x64-gnu', '1.2.3')).rejects.toThrow(
+      'unsafe',
+    );
+    manifest.directory.emptyDirectories = ['global/pg_control'];
+    await writeFile(seed.manifestPath, JSON.stringify(manifest));
+    await expect(validateSelectedNativeSeed(seed, 'linux-x64-gnu', '1.2.3')).rejects.toThrow(
+      'overlaps',
+    );
+    manifest.directory.emptyDirectories = ['pg_notify'];
+    await writeFile(seed.manifestPath, JSON.stringify(manifest));
+    await writeFile(join(seed.directory, 'global/pg_control'), 'corrupt');
+    await expect(validateSelectedNativeSeed(seed, 'linux-x64-gnu', '1.2.3')).rejects.toThrow(
+      'corrupted',
+    );
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
+
+test('ICU data identity covers the selected files and rejects symlinks and corruption', async () => {
+  const root = await mkdtemp(join(tmpdir(), 'oliphaunt-selected-icu-'));
+  const resource = {
+    directory: join(root, 'data'),
+    manifestPath: join(root, 'manifest.properties'),
+  };
+  const content = 'canonical ICU fixture';
+  const expected = digest({ 'icudt76l.dat': content });
+  try {
+    await mkdir(resource.directory);
+    await writeFile(join(resource.directory, 'icudt76l.dat'), content);
+    await writeFile(
+      resource.manifestPath,
+      `schema=oliphaunt-icu-data-v1\nartifactRole=icu-data\nicuDataVersion=76.1\nicuDataForm=files-le\nicuDataTreeSha256=${expected}\n`,
+    );
+    expect(await validateSelectedIcuData(resource)).toBe(expected);
+    await writeFile(join(resource.directory, 'icudt76l.dat'), 'changed');
+    await expect(validateSelectedIcuData(resource)).rejects.toThrow('does not match');
+    if (process.platform !== 'win32') {
+      await rm(join(resource.directory, 'icudt76l.dat'));
+      await symlink(resource.manifestPath, join(resource.directory, 'icudt76l.dat'));
+      await expect(validateSelectedIcuData(resource)).rejects.toThrow('symlink');
+    }
+  } finally {
+    await rm(root, { recursive: true, force: true });
+  }
+});
diff --git a/src/sdks/js/src/__tests__/native-runtime-profile.test.ts b/src/sdks/ts/sdk/src/__tests__/native-runtime-profile.test.ts
similarity index 97%
rename from src/sdks/js/src/__tests__/native-runtime-profile.test.ts
rename to src/sdks/ts/sdk/src/__tests__/native-runtime-profile.test.ts
index 0e8b1ae44..849a2e3f6 100644
--- a/src/sdks/js/src/__tests__/native-runtime-profile.test.ts
+++ b/src/sdks/ts/sdk/src/__tests__/native-runtime-profile.test.ts
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict';
 import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
-import { test } from 'vitest';
+import { test } from 'bun:test';
 
 import { resolveExactNativeRuntimeProfile } from '../native/runtime-profile.js';
 
diff --git a/src/sdks/ts/sdk/src/__tests__/native-server-smoke.ts b/src/sdks/ts/sdk/src/__tests__/native-server-smoke.ts
new file mode 100644
index 000000000..853c40a20
--- /dev/null
+++ b/src/sdks/ts/sdk/src/__tests__/native-server-smoke.ts
@@ -0,0 +1,67 @@
+import assert from 'node:assert/strict';
+import { mkdtemp, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { dirname, join } from 'node:path';
+import pg from 'pg';
+import { pathToFileURL } from 'node:url';
+
+const { Oliphaunt } = await import(
+  process.env.OLIPHAUNT_SMOKE_SDK
+    ? pathToFileURL(process.env.OLIPHAUNT_SMOKE_SDK).href
+    : new URL('../index.js', import.meta.url).href
+);
+
+export async function assertNativeServerContract(serverExecutable: string): Promise {
+  const roots = await Promise.all([
+    mkdtemp(join(tmpdir(), 'oliphaunt-js-native-server-first-')),
+    mkdtemp(join(tmpdir(), 'oliphaunt-js-native-server-second-')),
+  ]);
+  try {
+    const systemIdentifiers: string[] = [];
+    for (const [index, root] of roots.entries()) {
+      const server = await Oliphaunt.openServer({
+        storage: { kind: 'directory', path: root },
+        serverExecutable,
+        runtimeDirectory: process.env.OLIPHAUNT_POSTGRES_TOOL_DIR ?? dirname(serverExecutable),
+      });
+      try {
+        const connection = new pg.Client({
+          connectionString: server.connectionString,
+          connectionTimeoutMillis: 10_000,
+          query_timeout: 10_000,
+        });
+        let identifier: string;
+        try {
+          await connection.connect();
+          if (index === 0) {
+            const one = await connection.query('SELECT $1::integer AS value', [1]);
+            assert.equal(one.rows[0]?.value, 1);
+          }
+          const identity = await connection.query<{ system_identifier: string }>(
+            'SELECT system_identifier::text AS system_identifier FROM pg_control_system()',
+          );
+          identifier = identity.rows[0]?.system_identifier ?? '';
+        } finally {
+          await connection.end();
+        }
+        assert.match(identifier, /^\d+$/u);
+        systemIdentifiers.push(identifier);
+      } finally {
+        await server.close();
+      }
+    }
+    assert.notEqual(
+      systemIdentifiers[0],
+      systemIdentifiers[1],
+      'independent fresh server roots must not clone one PostgreSQL system identifier',
+    );
+  } finally {
+    await Promise.all(roots.map((root) => rm(root, { recursive: true, force: true })));
+  }
+}
+
+if (import.meta.main) {
+  const postgres = process.env.OLIPHAUNT_POSTGRES;
+  if (!postgres) throw new Error('OLIPHAUNT_POSTGRES is required for the native server smoke');
+  await assertNativeServerContract(postgres);
+}
diff --git a/src/sdks/ts/sdk/src/__tests__/native-smoke.mts b/src/sdks/ts/sdk/src/__tests__/native-smoke.mts
new file mode 100644
index 000000000..4efc8bf20
--- /dev/null
+++ b/src/sdks/ts/sdk/src/__tests__/native-smoke.mts
@@ -0,0 +1,33 @@
+import { pathToFileURL } from 'node:url';
+import { assertNativeDatabaseContract } from './native-direct-contract.mts';
+
+const { Oliphaunt } = await import(
+  process.env.OLIPHAUNT_SMOKE_SDK
+    ? pathToFileURL(process.env.OLIPHAUNT_SMOKE_SDK).href
+    : new URL('../../lib/index.js', import.meta.url).href
+);
+
+async function main(): Promise {
+  const libraryPath = requiredEnv('LIBOLIPHAUNT_PATH');
+  await assertNativeDatabaseContract(
+    Oliphaunt,
+    { topology: 'direct', libraryPath },
+    `${process.env.OLIPHAUNT_SMOKE_HOST}-direct`,
+  );
+  const brokerExecutable = process.env.OLIPHAUNT_BROKER;
+  if (brokerExecutable) {
+    await assertNativeDatabaseContract(
+      Oliphaunt,
+      { topology: 'broker', libraryPath, brokerExecutable },
+      `${process.env.OLIPHAUNT_SMOKE_HOST}-broker`,
+    );
+  }
+}
+
+function requiredEnv(name: string): string {
+  const value = process.env[name];
+  if (!value) throw new Error(`${name} is required for the TypeScript SDK native smoke check`);
+  return value;
+}
+
+await main();
diff --git a/src/sdks/js/src/__tests__/package-metadata.ts b/src/sdks/ts/sdk/src/__tests__/package-metadata.ts
similarity index 86%
rename from src/sdks/js/src/__tests__/package-metadata.ts
rename to src/sdks/ts/sdk/src/__tests__/package-metadata.ts
index d42da154d..cda5b3b91 100644
--- a/src/sdks/js/src/__tests__/package-metadata.ts
+++ b/src/sdks/ts/sdk/src/__tests__/package-metadata.ts
@@ -4,8 +4,6 @@ import { readFile } from 'node:fs/promises';
 export type TypeScriptPackageMetadata = {
   oliphaunt?: {
     liboliphauntVersion?: string;
-    icuPackage?: string;
-    icuVersion?: string;
     brokerVersion?: string;
     nodeDirectAddon?: string;
     nodeDirectAddonVersion?: string;
@@ -18,7 +16,6 @@ export type TypeScriptPackageMetadata = {
 
 export type TypeScriptPackageVersions = {
   liboliphauntVersion: string;
-  icuVersion: string;
   brokerVersion: string;
   nodeDirectAddonVersion: string;
 };
@@ -33,7 +30,6 @@ export async function readTypeScriptPackageVersions(): Promise {
+  assert.equal(typeof Oliphaunt.open, 'function');
+  assert.equal(typeof PostgresError, 'function');
+  assert.equal(postgresOids.jsonb, 3802);
+  assert.equal(text('value', postgresOids.text).format, 'text');
+  assert.equal(binary(Uint8Array.of(1), postgresOids.bytea).format, 'binary');
+  assert.equal(json({ ok: true }).typeOid, postgresOids.jsonb);
+  assert.equal(array([1, 2], postgresOids.int4Array).typeOid, postgresOids.int4Array);
+  assert.equal(typedNull(postgresOids.uuid).format, 'null');
+});
+
+const canonicalPostgresError = new PostgresError([
+  { code: 0x43, value: '22000' },
+  { code: 0x4d, value: 'invalid value' },
+]);
+const canonicalSqlstate: string | undefined = canonicalPostgresError.sqlstate;
+const canonicalMessage: string = canonicalPostgresError.message;
+void [canonicalSqlstate, canonicalMessage];
+
+// Compile-time proof from the external root surface. Keeping this function
+// uncalled verifies declarations without needing a native runtime in the test.
+function assertPublicDatabaseTypes(
+  database: OliphauntDatabase,
+  server: OliphauntServer,
+  transaction: OliphauntTransaction,
+): void {
+  const decoded: Promise> = database.query<{
+    value: number;
+  }>('SELECT $1::int4 AS value', [1], { rowMode: 'object' });
+  const raw: Promise = database.queryRaw('SELECT $1::bytea', [
+    binary(Uint8Array.of(1), postgresOids.bytea),
+  ]);
+  const execution: Promise> = database.exec(
+    'SELECT 1',
+    { rowMode: 'array' },
+  );
+  const inferredArrays: Promise> = database.query('SELECT 1', [], {
+    rowMode: 'array',
+  });
+  const inferredDecoder: Promise>> = database.query(
+    'SELECT now()',
+    [],
+    { decoders: { [postgresOids.timestamptz]: (value) => new Date(value) } },
+  );
+  const description: Promise = database.describe('SELECT $1', [postgresOids.int4]);
+  const streamed: Promise = database.execProtocolRawStream(
+    Uint8Array.of(0x51),
+    () => undefined,
+  );
+  // @ts-expect-error Stream callbacks are synchronous backpressure acknowledgements.
+  const asyncStreamed = database.execProtocolRawStream(Uint8Array.of(0x51), async () => {});
+  const widenedAsyncCallback: (chunk: Uint8Array) => unknown = async () => {};
+  const widenedAsyncStreamed = database.execProtocolRawStream(
+    Uint8Array.of(0x51),
+    // @ts-expect-error Widening an async callback must not bypass the synchronous contract.
+    widenedAsyncCallback,
+  );
+  // @ts-expect-error Raw protocol is database/root-only; it bypasses callback transaction ownership.
+  const transactionBuffered = transaction.execProtocolRaw(Uint8Array.of(0x51));
+  // @ts-expect-error Raw protocol is database/root-only; it bypasses callback transaction ownership.
+  const transactionStreamed = transaction.execProtocolRawStream(
+    Uint8Array.of(0x51),
+    () => undefined,
+  );
+  const rollback: Promise = transaction.rollback();
+  const serverConnectionString: string = server.connectionString;
+  const serverClose: Promise = server.close();
+  // @ts-expect-error Server handles own lifecycle, not a privileged database connection.
+  const serverQuery = server.query('SELECT 1');
+  // @ts-expect-error External driver connections own their own cancellation.
+  const serverCancel = server.cancel();
+  // @ts-expect-error Server handles do not expose the embedded database backup format.
+  const serverBackup = server.backup();
+  // @ts-expect-error Raw protocol belongs to database connections, not listener ownership.
+  const serverRaw = server.execProtocolRaw(Uint8Array.of(0x51));
+  // @ts-expect-error Transactions belong to caller-owned database connections.
+  const serverTransaction = server.transaction(() => undefined);
+  const closed: boolean = database.closed || server.closed || transaction.closed;
+  void [
+    decoded,
+    raw,
+    execution,
+    inferredArrays,
+    inferredDecoder,
+    description,
+    streamed,
+    asyncStreamed,
+    widenedAsyncStreamed,
+    transactionBuffered,
+    transactionStreamed,
+    rollback,
+    serverConnectionString,
+    serverClose,
+    serverQuery,
+    serverCancel,
+    serverBackup,
+    serverRaw,
+    serverTransaction,
+    closed,
+  ];
+}
+
+void assertPublicDatabaseTypes;
+
+const publicHelperTypes: [TextQueryParameter, BinaryQueryParameter, NullQueryParameter] = [
+  text('value'),
+  binary(Uint8Array.of(1)),
+  typedNull(postgresOids.text),
+];
+void publicHelperTypes;
+
+const publicRestoreOptions: RestoreOptions = { libraryPath: '/opt/liboliphaunt.so' };
+const publicTopology: OpenConfig = { topology: 'broker' };
+void [publicRestoreOptions, publicTopology];
+
+const plainJsonParameter: QueryParam = {
+  format: 'text',
+  value: 'plain JSON data',
+};
+// @ts-expect-error Encoded parameters must be created by an exported helper.
+const forgedEncodedParameter: EncodedQueryParameter = {
+  format: 'text',
+  value: 'forged',
+};
+void [plainJsonParameter, forgedEncodedParameter];
diff --git a/src/sdks/js/src/__tests__/root-descriptor.test.ts b/src/sdks/ts/sdk/src/__tests__/root-descriptor.test.ts
similarity index 91%
rename from src/sdks/js/src/__tests__/root-descriptor.test.ts
rename to src/sdks/ts/sdk/src/__tests__/root-descriptor.test.ts
index f05f56acd..a81e7f798 100644
--- a/src/sdks/js/src/__tests__/root-descriptor.test.ts
+++ b/src/sdks/ts/sdk/src/__tests__/root-descriptor.test.ts
@@ -1,19 +1,23 @@
+import { test } from 'bun:test';
 import assert from 'node:assert/strict';
 import { readFileSync } from 'node:fs';
 import { access, mkdir, mkdtemp, readdir, rm, symlink, writeFile } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
-import path, { join } from 'node:path';
-import { test } from 'vitest';
-
+import { join } from 'node:path';
+import { normalizeOpenConfig } from '../config.js';
 import {
   publishNativeDescriptor,
   validateDescriptor,
   validateManagedRoot,
 } from '../root-descriptor.js';
-import { normalizeOpenConfig } from '../config.js';
 import { createServerRuntimeBinding } from '../runtime/server.js';
 
-const fixture = JSON.parse(readFileSync(sharedStorageFixturePath(), 'utf8')) as {
+const fixture = JSON.parse(
+  readFileSync(
+    new URL('../../../../../test-fixtures/storage/database-root.json', import.meta.url),
+    'utf8',
+  ),
+) as {
   validDescriptors: Array>;
   invalidDescriptors: Array<{ case: string; value: Record }>;
   malformedJson: Array<{ case: string; value: string }>;
@@ -107,17 +111,3 @@ async function completeRoot(): Promise {
   await writeFile(join(root, 'pgdata', 'global', 'pg_control'), new Uint8Array([1]));
   return root;
 }
-
-function sharedStorageFixturePath(): string {
-  return path.resolve(
-    process.cwd(),
-    '..',
-    '..',
-    '..',
-    'src',
-    'shared',
-    'fixtures',
-    'storage',
-    'database-root.json',
-  );
-}
diff --git a/src/sdks/js/src/__tests__/runtime-adapters.test.ts b/src/sdks/ts/sdk/src/__tests__/runtime-adapters.test.ts
similarity index 79%
rename from src/sdks/js/src/__tests__/runtime-adapters.test.ts
rename to src/sdks/ts/sdk/src/__tests__/runtime-adapters.test.ts
index 26c9c3647..d1bcb7bf3 100644
--- a/src/sdks/js/src/__tests__/runtime-adapters.test.ts
+++ b/src/sdks/ts/sdk/src/__tests__/runtime-adapters.test.ts
@@ -1,13 +1,14 @@
 import assert from 'node:assert/strict';
 import { chmod, mkdir, mkdtemp, rm, stat } from 'node:fs/promises';
 import { tmpdir } from 'node:os';
+import { createServer, type Socket } from 'node:net';
 import { join } from 'node:path';
 import { Readable } from 'node:stream';
-import { test } from 'vitest';
+import { test } from 'bun:test';
 
 import { normalizeOpenConfig } from '../config.js';
 import { MemoryDuplexStream } from '../runtime/byte-stream.js';
-import { BrokerHandle, cancelBrokerStream, createBrokerRuntimeBinding } from '../runtime/broker.js';
+import { BrokerHandle, createBrokerRuntimeBinding } from '../runtime/broker.js';
 import { encodeBrokerResponse } from '../runtime/broker-frames.js';
 import { createForgottenRuntimeHandleCleanup } from '../runtime/forgotten-handle.js';
 import {
@@ -17,7 +18,11 @@ import {
   readReadyLine,
   unixSocketPathsFit,
 } from '../runtime/node-adapter.js';
-import { encodeStartupMessage, PostgresWireClient } from '../runtime/pgwire.js';
+import {
+  cancelPostgresStream,
+  encodeStartupMessage,
+  PostgresWireClient,
+} from '../runtime/pgwire.js';
 import {
   createServerRuntimeBinding,
   postgresServerArguments,
@@ -63,27 +68,30 @@ test('native server quotes one Unix socket directory as one PostgreSQL GUC-list
   assert.equal(args[index - 1], '-c');
 });
 
-test('broker cancellation preserves its protocol failure when control-stream close also fails', async () => {
-  const wire = new MemoryDuplexStream([
-    encodeBrokerResponse({ kind: 'ok', bytes: new Uint8Array() }),
-    encodeBrokerResponse({ kind: 'error', message: 'cancel rejected' }),
-  ]);
+test('PostgreSQL cancellation preserves write and cleanup failures without reading a reply', async () => {
   const stream = {
-    readExactly: (length: number) => wire.readExactly(length),
-    writeAll: (bytes: Uint8Array) => wire.writeAll(bytes),
+    async readExactly(): Promise {
+      throw new Error('CancelRequest has no response');
+    },
+    async writeAll(): Promise {
+      throw new Error('cancel write failed');
+    },
     async close(): Promise {
-      throw new Error('cancel stream close failed');
+      throw new Error('cancel close failed');
     },
   };
-
-  await assert.rejects(cancelBrokerStream(stream, 'fixture-token'), (error: unknown) => {
+  await assert.rejects(cancelPostgresStream(stream, new Uint8Array(8)), (error: unknown) => {
     assert.ok(error instanceof AggregateError);
     assert.deepEqual(error.errors.map(String), [
-      'Error: native broker cancel failed: cancel rejected',
-      'Error: cancel stream close failed',
+      'Error: cancel write failed',
+      'Error: cancel close failed',
     ]);
     return true;
   });
+  const wire = new MemoryDuplexStream();
+  const key = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
+  await cancelPostgresStream(wire, key);
+  assert.deepEqual(wire.output, [new Uint8Array([0, 0, 0, 16, 4, 210, 22, 46, ...key])]);
 });
 
 test('failed broker handles never relaunch and retain cleanup ownership for close', async () => {
@@ -125,11 +133,12 @@ test('failed broker handles never relaunch and retain cleanup ownership for clos
     { topology: 'broker' },
     { instanceDirectory: join(scratch, 'database'), temporaryDirectory: false },
   );
-  const handle = new BrokerHandle(
-    config,
-    { child, stream, cancelEndpoint: 'tcp:127.0.0.1:1', ipcDir },
-    'fixture-token',
-  );
+  const handle = new BrokerHandle(config, {
+    child,
+    stream,
+    client: new PostgresWireClient(new MemoryDuplexStream()),
+    ipcDir,
+  });
   const firstFailure = new Error('fixture broker transport failed');
 
   try {
@@ -187,8 +196,7 @@ test('broker failure and detach stay bounded when SIGKILL never produces a reap'
   );
   const handle = new BrokerHandle(
     config,
-    { child, stream, cancelEndpoint: 'tcp:127.0.0.1:1', ipcDir },
-    'fixture-token',
+    { child, stream, client: new PostgresWireClient(new MemoryDuplexStream()), ipcDir },
     1,
   );
 
@@ -255,11 +263,12 @@ test('terminal broker detach retains each cleanup owner until that resource is r
     { topology: 'broker' },
     { instanceDirectory: join(scratch, 'database'), temporaryDirectory: false },
   );
-  const handle = new BrokerHandle(
-    config,
-    { child, stream, cancelEndpoint: 'tcp:127.0.0.1:1', ipcDir },
-    'fixture-token',
-  );
+  const handle = new BrokerHandle(config, {
+    child,
+    stream,
+    client: new PostgresWireClient(new MemoryDuplexStream()),
+    ipcDir,
+  });
 
   try {
     await assert.rejects(handle.detach(), (error: unknown) => {
@@ -305,9 +314,7 @@ test('Postgres wire termination closes after a failed Terminate write and retain
       if (closeAttempts === 1) throw new Error('fixture client stream close failed');
     },
   };
-  type InternalWireClientConstructor = new (wireStream: typeof stream) => PostgresWireClient;
-  const InternalWireClient = PostgresWireClient as unknown as InternalWireClientConstructor;
-  const client = new InternalWireClient(stream);
+  const client = new PostgresWireClient(stream);
 
   await assert.rejects(client.terminate(), (error: unknown) => {
     assert.ok(error instanceof AggregateError);
@@ -685,6 +692,40 @@ test('server readiness wire uses a PostgreSQL v3 startup packet', () => {
   assert.match(startupText, /client_encoding\0UTF8\0/);
 });
 
+test('server readiness times out and closes a peer that never answers startup', async () => {
+  let accepted: Socket | undefined;
+  let release!: () => void;
+  const closed = new Promise((resolve) => {
+    release = resolve;
+  });
+  const server = createServer((socket) => {
+    accepted = socket;
+    socket.resume();
+    socket.once('close', release);
+  });
+  try {
+    await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
+    const address = server.address();
+    assert.ok(address && typeof address !== 'string');
+    await assert.rejects(
+      settleWithin(
+        PostgresWireClient.connect(
+          { kind: 'tcp', host: '127.0.0.1', port: address.port },
+          'postgres',
+          'postgres',
+          1_000,
+        ),
+        5_000,
+      ),
+      /abort/i,
+    );
+    await settleWithin(closed, 5_000);
+  } finally {
+    accepted?.destroy();
+    await new Promise((resolve) => server.close(() => resolve()));
+  }
+});
+
 function readI32(bytes: Uint8Array, offset: number): number {
   return new DataView(bytes.buffer, bytes.byteOffset + offset, 4).getInt32(0);
 }
@@ -722,3 +763,126 @@ async function waitForMissingPath(path: string, timeoutMs: number): Promise {
+  const ready = new Uint8Array([0x5a, 0, 0, 0, 5, 0x49]);
+  const complete = new Uint8Array([0x43, 0, 0, 0, 5, 0]);
+  const query = new Uint8Array([0x51, 0, 0, 0, 5, 0]);
+  const wire = new MemoryDuplexStream([
+    complete.subarray(0, 2),
+    complete.subarray(2),
+    ready,
+    ready,
+    complete,
+    ready,
+  ]);
+  const config = normalizeOpenConfig(
+    { topology: 'broker' },
+    { instanceDirectory: '/tmp/unused-broker-fixture', temporaryDirectory: false },
+  );
+  const child = {
+    stdout: Readable.from([]),
+    kill() {},
+    async wait() {
+      return 0;
+    },
+    async exited() {
+      return 0;
+    },
+  };
+  const handle = new BrokerHandle(config, {
+    child,
+    stream: new MemoryDuplexStream(),
+    client: new PostgresWireClient(wire),
+    ipcDir: undefined,
+  });
+  const callbackError = new Error('consumer stopped');
+  let callbacks = 0;
+  await assert.rejects(
+    handle.execProtocolStream(new Uint8Array([...query, ...query]), () => {
+      callbacks++;
+      throw callbackError;
+    }),
+    (error) => error === callbackError,
+  );
+  assert.equal(callbacks, 1);
+  assert.deepEqual(await handle.execProtocolRaw(query), new Uint8Array([...complete, ...ready]));
+  assert.equal(wire.output.length, 2, 'a failed callback never replays SQL');
+});
+
+test('broker transport failure overrides callback failure when recovery is unconfirmed', async () => {
+  const frame = new Uint8Array([0x43, 0, 0, 0, 5, 0]);
+  const config = normalizeOpenConfig(
+    { topology: 'broker' },
+    { instanceDirectory: '/tmp/unused-broker-fixture', temporaryDirectory: false },
+  );
+  const child = {
+    stdout: Readable.from([]),
+    kill() {},
+    async wait() {
+      return 0;
+    },
+    async exited() {
+      return 0;
+    },
+  };
+  const handle = new BrokerHandle(config, {
+    child,
+    stream: new MemoryDuplexStream(),
+    client: new PostgresWireClient(new MemoryDuplexStream([frame])),
+    ipcDir: undefined,
+  });
+  await assert.rejects(
+    handle.execProtocolStream(new Uint8Array([0x51, 0, 0, 0, 5, 0]), () => {
+      throw new Error('consumer stopped');
+    }),
+    /read stream ended/,
+  );
+  await assert.rejects(
+    handle.execProtocolRaw(new Uint8Array([0x51, 0, 0, 0, 5, 0])),
+    /close and reopen/,
+  );
+});
+
+test('buffered PostgreSQL rejects incomplete requests before writing and malformed readiness before reuse', async () => {
+  const wire = new MemoryDuplexStream([new Uint8Array([0x5a, 0, 0, 0, 5, 0])]);
+  const client = new PostgresWireClient(wire);
+  await assert.rejects(
+    client.execProtocolStream(new Uint8Array([0x48, 0, 0, 0, 4]), () => {}),
+    /query or COPY boundary/,
+  );
+  await assert.rejects(
+    client.execProtocolStream(new Uint8Array([0x51, 0, 0, 0, 6, 0]), () => {}),
+    /frontend frame length/,
+  );
+  assert.equal(wire.output.length, 0);
+  await assert.rejects(
+    client.execProtocolStream(new Uint8Array([0x51, 0, 0, 0, 5, 0]), () => {}),
+    /invalid PostgreSQL ReadyForQuery/,
+  );
+});
+
+test('PostgreSQL drains pipelined results while a socket write is backpressured', async () => {
+  const ready = new Uint8Array([0x5a, 0, 0, 0, 5, 0x49]);
+  const input = new MemoryDuplexStream([ready]);
+  let releaseWrite!: () => void;
+  const write = new Promise((resolve) => {
+    releaseWrite = resolve;
+  });
+  const client = new PostgresWireClient({
+    async writeAll() {
+      await write;
+    },
+    async readExactly(length) {
+      releaseWrite();
+      return input.readExactly(length);
+    },
+    async close() {
+      releaseWrite();
+    },
+  });
+  await settleWithin(
+    client.execProtocolStream(new Uint8Array([0x51, 0, 0, 0, 5, 0]), () => {}),
+    250,
+  );
+});
diff --git a/src/sdks/ts/sdk/src/broker.ts b/src/sdks/ts/sdk/src/broker.ts
new file mode 100644
index 000000000..735403e99
--- /dev/null
+++ b/src/sdks/ts/sdk/src/broker.ts
@@ -0,0 +1,20 @@
+import { Oliphaunt as client } from './index.js';
+import type * as Types from './types.js';
+export * from './index.js';
+
+export type OpenConfig = Omit & { topology?: never };
+export type OliphauntClient = Omit & {
+  open(config?: OpenConfig): Promise;
+};
+export const Oliphaunt: OliphauntClient = {
+  ...client,
+  async open(config = {}) {
+    if (config.topology !== undefined) {
+      throw new TypeError(
+        '@oliphaunt/ts/broker does not accept topology; select the execution mode through the import path',
+      );
+    }
+    return client.open({ ...config, topology: 'broker' });
+  },
+};
+export default Oliphaunt;
diff --git a/src/sdks/ts/sdk/src/client.ts b/src/sdks/ts/sdk/src/client.ts
new file mode 100644
index 000000000..d99b5f076
--- /dev/null
+++ b/src/sdks/ts/sdk/src/client.ts
@@ -0,0 +1,1281 @@
+import { mkdir, mkdtemp, rm } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+
+import {
+  normalizeDatabaseTopology,
+  normalizeOpenConfig,
+  validateDirectoryPath,
+  validateNativeStartupGUCs,
+} from './config.js';
+import { createDefaultNativeBinding } from './native/default.js';
+import type { NativeBinding, NativeBindingOptions } from './native/types.js';
+import {
+  assertNoTransactionChain,
+  decodeQueryResult,
+  describeQuery,
+  errorWithNotices,
+  extendedQuery,
+  inspectManagedTransactionResponse,
+  inspectReadyForQuery,
+  parseCommandResponse,
+  parseDescribeResponse,
+  parseExecResponse,
+  parseQueryRawResponse,
+  planQuery,
+  structuredSimpleQuery,
+  type CommandResult,
+  type DescribeResult,
+  type ExecResult,
+  type InferQueryRow,
+  type ParameterOptions,
+  type PostgresNotice,
+  type QueryParam,
+  type QueryOptions,
+  type QueryPlan,
+  type QueryResult,
+  type RawQueryResult,
+  type TransactionStatus,
+  toUint8Array,
+} from './query.js';
+import { createBrokerRuntimeBinding } from './runtime/broker.js';
+import { directRuntimeBinding } from './runtime/direct.js';
+import { createServerRuntimeBinding } from './runtime/server.js';
+import type { RuntimeBinding, RuntimeHandle } from './runtime/types.js';
+import type {
+  BinaryInput,
+  DatabaseStorage,
+  OliphauntClient,
+  OliphauntDatabase,
+  OliphauntTransaction,
+  OliphauntServer,
+  OpenConfig,
+  ServerListen,
+  ServerOpenConfig,
+  ProtocolChunkCallback,
+  RestoreOptions,
+} from './types.js';
+
+export type NativeBindingFactory = (
+  options?: NativeBindingOptions,
+) => NativeBinding | Promise;
+
+type RuntimeBindingOverrides = {
+  readonly broker?: RuntimeBinding;
+  readonly server?: RuntimeBinding;
+};
+
+type QueryReadOptions = Omit;
+
+class OliphauntDatabaseBase {
+  protected readonly binding: RuntimeBinding;
+  protected readonly handle: RuntimeHandle;
+  readonly #releaseOwnership?: () => void;
+  #closed = false;
+  #closing = false;
+  #closeAttempt?: Promise;
+  #operationTail = Promise.resolve();
+  readonly #cancellationOperations = new Set>();
+  #runtimeCloseActive = false;
+  #activeTransaction = false;
+  #streamCallbackActive = false;
+  #sessionFailure?: Error;
+
+  static async publish(
+    database: Database,
+  ): Promise {
+    try {
+      database.#initializeForgottenHandleCleanup();
+      return database;
+    } catch (publicationError) {
+      const cleanupFailure = await database.#discardUnpublishedOwner();
+      if (cleanupFailure === undefined) throw publicationError;
+      throw new AggregateError(
+        [publicationError, cleanupFailure],
+        'Oliphaunt opened a runtime owner but could not publish its JavaScript facade',
+      );
+    }
+  }
+
+  constructor(binding: RuntimeBinding, handle: RuntimeHandle, releaseOwnership?: () => void) {
+    this.binding = binding;
+    this.handle = handle;
+    if (releaseOwnership !== undefined) {
+      let released = false;
+      this.#releaseOwnership = () => {
+        if (released) return;
+        released = true;
+        releaseOwnership();
+      };
+    }
+  }
+
+  /** Complete owner publication after the facade itself is reachable locally. */
+  #initializeForgottenHandleCleanup(): void {
+    this.binding.registerForgottenHandleCleanup?.(
+      this,
+      this.handle,
+      this.#releaseOwnership ?? noop,
+    );
+  }
+
+  /**
+   * Retire an opened handle whose public facade could not be published.
+   * Registration is unregistered even when the registry threw after partially
+   * accepting it, and the exact JavaScript ownership lease is always released.
+   */
+  async #discardUnpublishedOwner(): Promise {
+    const failures: unknown[] = [];
+    const closeFailure = await closeRuntimeHandleFailure(this.binding, this.handle);
+    if (closeFailure !== undefined) failures.push(closeFailure);
+    const retirementFailure = this.#retire();
+    if (retirementFailure !== undefined) failures.push(retirementFailure);
+    return collapseFailures(failures, 'unpublished Oliphaunt owner cleanup failed');
+  }
+
+  get closed(): boolean {
+    return this.#closed;
+  }
+
+  async execute(
+    sql: string,
+    parameters: ReadonlyArray = [],
+    options: ParameterOptions = {},
+  ): Promise {
+    this.assertNoActiveTransaction();
+    const plan = planQuery(sql, parameters, snapshotParameterOptions(options));
+    return this.withSessionOperation(() =>
+      this.#runPlannedUnlocked(plan, 'database', parseCommandResponse),
+    );
+  }
+
+  async query(
+    sql: string,
+    parameters: ReadonlyArray = [],
+    options: Options & QueryOptions = {} as Options & QueryOptions,
+  ): Promise>> {
+    this.assertNoActiveTransaction();
+    const stableOptions = snapshotQueryOptions(options);
+    const plan = planQuery(sql, parameters, stableOptions);
+    return this.withSessionOperation(async () =>
+      decodeQueryResult(
+        await this.#runPlannedUnlocked(plan, 'database', parseQueryRawResponse),
+        stableOptions,
+      ),
+    );
+  }
+
+  async queryRaw(
+    sql: string,
+    parameters: ReadonlyArray = [],
+    options: ParameterOptions = {},
+  ): Promise {
+    this.assertNoActiveTransaction();
+    const plan = planQuery(sql, parameters, snapshotParameterOptions(options));
+    return this.withSessionOperation(() =>
+      this.#runPlannedUnlocked(plan, 'database', parseQueryRawResponse),
+    );
+  }
+
+  async exec(
+    sql: string,
+    options: Options & QueryReadOptions = {} as Options & QueryReadOptions,
+  ): Promise>> {
+    this.assertNoActiveTransaction();
+    const input = structuredSimpleQuery(sql);
+    const stableOptions = snapshotReadOptions(options);
+    return this.withSessionOperation(() =>
+      this.#runStructuredUnlocked(input, 'database', (response) =>
+        parseExecResponse(response, stableOptions),
+      ),
+    );
+  }
+
+  async describe(
+    sql: string,
+    parameterTypeOids: ReadonlyArray = [],
+  ): Promise {
+    this.assertNoActiveTransaction();
+    const input = describeQuery(sql, [...parameterTypeOids]);
+    return this.withSessionOperation(() =>
+      this.#runStructuredUnlocked(input, 'database', parseDescribeResponse),
+    );
+  }
+
+  async execProtocolRaw(input: BinaryInput): Promise {
+    this.assertNoActiveTransaction();
+    const bytes = toUint8Array(input).slice();
+    return this.withSessionOperation(() => this.#runRawProtocolUnlocked(bytes));
+  }
+
+  async execProtocolRawStream(input: BinaryInput, onChunk: ProtocolChunkCallback): Promise {
+    this.assertNoActiveTransaction();
+    if (typeof onChunk !== 'function') {
+      return Promise.reject(new TypeError('protocol stream callback must be a function'));
+    }
+    const bytes = toUint8Array(input).slice();
+    return this.withSessionOperation(() => this.#execProtocolStreamUnlocked(bytes, onChunk));
+  }
+
+  cancel(): Promise {
+    if (this.#closed) {
+      return Promise.reject(new Error('Oliphaunt database is closed'));
+    }
+    if (this.#runtimeCloseActive) {
+      return Promise.reject(new Error('Oliphaunt database is closing'));
+    }
+    // Cancellation must remain independent of the physical-session queue so
+    // it can interrupt an admitted operation even after close() has stopped
+    // ordinary admission. Runtime teardown waits for every admitted cancel.
+    const operation = this.#runNativeVoidOperation(() => this.binding.cancel(this.handle));
+    this.#cancellationOperations.add(operation);
+    void operation.then(
+      () => this.#cancellationOperations.delete(operation),
+      () => this.#cancellationOperations.delete(operation),
+    );
+    return operation;
+  }
+
+  async transaction(body: (transaction: OliphauntTransaction) => Promise | T): Promise {
+    this.assertNoActiveTransaction();
+    if (typeof body !== 'function') {
+      return Promise.reject(new TypeError('Oliphaunt transaction body must be a function'));
+    }
+    // Pin immediately at admission. Calls made after transaction() returns may
+    // not slip into the physical-session queue before BEGIN starts.
+    this.#activeTransaction = true;
+    let attempt: Promise;
+    try {
+      attempt = this.withSessionOperation(async () => {
+        const transaction = new OliphauntTransactionHandle(
+          (plan, decode) => this.#runPlannedUnlocked(plan, 'transaction', decode),
+          (input, decode) => this.#runStructuredUnlocked(input, 'transaction', decode),
+          () => this.#executeTransactionControlUnlocked('ROLLBACK').then(() => undefined),
+        );
+        try {
+          await this.#executeTransactionControlUnlocked('BEGIN');
+
+          let result: T;
+          try {
+            result = await body(transaction);
+            await transaction.sealAndDrain();
+          } catch (error) {
+            transaction.seal();
+            await transaction.drain().catch(() => undefined);
+            let rollbackFailure: unknown;
+            if (transaction.rollbackStarted) {
+              try {
+                await transaction.waitForRollback();
+              } catch (rollbackError) {
+                rollbackFailure = rollbackError;
+              }
+            } else if (this.#sessionFailure === undefined) {
+              try {
+                await this.#executeTransactionControlUnlocked('ROLLBACK');
+              } catch (rollbackError) {
+                rollbackFailure = rollbackError;
+              }
+            }
+            if (rollbackFailure !== undefined && rollbackFailure !== error) {
+              throw transactionCallbackAggregate(
+                error,
+                rollbackFailure,
+                'transaction callback and rollback both failed',
+              );
+            }
+            const databaseFailure =
+              this.#sessionFailure === undefined
+                ? undefined
+                : (transaction.firstFailure ?? this.#sessionFailure);
+            if (databaseFailure !== undefined && databaseFailure !== error) {
+              throw transactionCallbackAggregate(
+                error,
+                databaseFailure,
+                'transaction callback and an independent database failure both occurred',
+              );
+            }
+            throw error;
+          }
+
+          if (transaction.rolledBack) {
+            return result;
+          }
+          if (this.#sessionFailure !== undefined && transaction.firstFailure !== undefined) {
+            throw transaction.firstFailure;
+          }
+          const outcome = await this.#executeTransactionControlUnlocked('COMMIT');
+          if (outcome === 'rolledBack') {
+            throw transaction.firstFailure ?? transactionTagError('COMMIT', 'ROLLBACK');
+          }
+          return result;
+        } finally {
+          transaction.deactivate();
+        }
+      });
+    } catch (error) {
+      this.#activeTransaction = false;
+      throw error;
+    }
+    return attempt.finally(() => {
+      this.#activeTransaction = false;
+    });
+  }
+
+  close(): Promise {
+    if (this.#streamCallbackActive) {
+      return Promise.reject(streamCallbackReentryError());
+    }
+    if (this.#closeAttempt !== undefined) {
+      return this.#closeAttempt;
+    }
+    if (this.#closed) {
+      return Promise.resolve();
+    }
+    if (this.#activeTransaction) {
+      return Promise.reject(new Error('cannot close Oliphaunt while a transaction is active'));
+    }
+
+    this.#closing = true;
+    let terminal = false;
+    const attempt = this.#operationTail
+      .then(async () => {
+        // Cancellation remains out-of-band while admitted session work drains.
+        // Close the cancellation admission gate only in the same job that
+        // starts runtime teardown, after every already-admitted cancel settles.
+        while (this.#cancellationOperations.size > 0) {
+          await Promise.allSettled([...this.#cancellationOperations]);
+        }
+        this.#runtimeCloseActive = true;
+        let outcome: Awaited>;
+        try {
+          outcome = await this.binding.close(this.handle);
+        } catch (error) {
+          // A runtime adapter violated the private no-rejection contract. Its
+          // teardown state is unknowable, so retiring the public owner is the
+          // only safe result.
+          outcome = { state: 'terminal' as const, error };
+        }
+        if (outcome.state === 'retryable') {
+          throw outcome.error;
+        }
+
+        terminal = true;
+        const cleanupFailure = this.#retire();
+        if (outcome.state === 'terminal') {
+          throw outcome.error;
+        }
+        if (cleanupFailure !== undefined) {
+          throw cleanupFailure;
+        }
+      })
+      .finally(() => {
+        this.#closing = false;
+        if (!terminal && this.#closeAttempt === attempt) {
+          this.#runtimeCloseActive = false;
+          this.#closeAttempt = undefined;
+        }
+      });
+    this.#closeAttempt = attempt;
+    return attempt;
+  }
+
+  async [Symbol.asyncDispose](): Promise {
+    await this.close();
+  }
+
+  async #executeTransactionControlUnlocked(
+    sql: 'BEGIN' | 'COMMIT' | 'ROLLBACK',
+  ): Promise<'committed' | 'rolledBack' | undefined> {
+    this.#assertHealthy();
+    let response: Uint8Array;
+    try {
+      response = await this.#execProtocolRawUnlocked(extendedQuery(sql, []));
+    } catch (error) {
+      this.#poison(error, `${sql} transport outcome is unknown`);
+      throw error;
+    }
+
+    let status: TransactionStatus;
+    try {
+      status = inspectReadyForQuery(response);
+    } catch (error) {
+      this.#poison(error, `${sql} did not reach a valid ReadyForQuery boundary`);
+      throw error;
+    }
+
+    let result: CommandResult;
+    try {
+      result = parseCommandResponse(response);
+    } catch (error) {
+      if (sql === 'BEGIN' && status !== 'idle') {
+        await this.#recoverDatabaseBoundaryUnlocked().catch(() => undefined);
+      } else if (sql === 'ROLLBACK') {
+        this.#poison(error, 'ROLLBACK did not return its exact command boundary');
+      } else if (sql === 'COMMIT') {
+        this.#poison(error, 'COMMIT did not return its exact command boundary');
+      }
+      throw error;
+    }
+
+    if (sql === 'BEGIN') {
+      if (result.commandTag === 'BEGIN' && status === 'transaction') return undefined;
+      const error = transactionBoundaryError(sql, result.commandTag, status);
+      if (status !== 'idle') {
+        await this.#recoverDatabaseBoundaryUnlocked();
+      }
+      throw error;
+    }
+
+    if (sql === 'COMMIT' && result.commandTag === 'ROLLBACK' && status === 'idle') {
+      return 'rolledBack';
+    }
+    if (result.commandTag === sql && status === 'idle') {
+      return sql === 'COMMIT' ? 'committed' : undefined;
+    }
+
+    const error = transactionBoundaryError(sql, result.commandTag, status);
+    this.#poison(error, `${sql} returned an unrecognized transaction boundary`);
+    throw error;
+  }
+
+  async #runPlannedUnlocked(
+    plan: QueryPlan,
+    scope: StructuredScope,
+    decode: (response: Uint8Array) => Result,
+  ): Promise {
+    if (plan.kind === 'complete') {
+      return this.#runStructuredUnlocked(plan.input, scope, decode);
+    }
+    const description = await this.#runStructuredUnlocked(plan.input, scope, parseDescribeResponse);
+    // plan.bind() may invoke a caller codec. It runs only after a proven Ready
+    // boundary and therefore cannot poison the wire session if it throws.
+    let input: Uint8Array;
+    try {
+      input = plan.bind(description.parameterTypeOids);
+    } catch (error) {
+      throw errorWithNotices(error, description.notices);
+    }
+    try {
+      return prependNotices(
+        await this.#runStructuredUnlocked(input, scope, decode),
+        description.notices,
+      );
+    } catch (error) {
+      throw errorWithNotices(error, description.notices);
+    }
+  }
+
+  async #runStructuredUnlocked(
+    input: Uint8Array,
+    scope: StructuredScope,
+    decode: (response: Uint8Array) => Result,
+  ): Promise {
+    let response: Uint8Array;
+    try {
+      response = await this.#execProtocolRawUnlocked(input);
+    } catch (error) {
+      this.#poison(error, 'structured PostgreSQL transport outcome is unknown');
+      throw error;
+    }
+
+    let status: TransactionStatus;
+    try {
+      status =
+        scope === 'transaction'
+          ? inspectManagedTransactionResponse(response)
+          : inspectReadyForQuery(response);
+    } catch (error) {
+      this.#poison(
+        error,
+        scope === 'transaction'
+          ? 'callback transaction ownership escaped or its response boundary was invalid'
+          : 'structured PostgreSQL response has no valid readiness boundary',
+      );
+      throw error;
+    }
+
+    if (scope === 'database' && status !== 'idle') {
+      await this.#recoverDatabaseBoundaryUnlocked();
+      // Preserve a PostgreSQL/parser error after proven recovery, but never
+      // report a successful structured call whose transaction was discarded.
+      const result = decode(response);
+      const error = new Error(
+        `structured database operation ended with PostgreSQL transaction status ${status}; Oliphaunt rolled it back`,
+      );
+      throw isNoticeCarrier(result) ? errorWithNotices(error, result.notices) : error;
+    }
+    return decode(response);
+  }
+
+  async #recoverDatabaseBoundaryUnlocked(): Promise {
+    try {
+      await this.#executeTransactionControlUnlocked('ROLLBACK');
+    } catch (error) {
+      this.#poison(error, 'PostgreSQL automatic rollback did not prove recovery');
+      throw new Error('PostgreSQL session could not be recovered to idle; close the database', {
+        cause: error,
+      });
+    }
+  }
+
+  async #execProtocolRawUnlocked(input: BinaryInput): Promise {
+    const requestBytes = toUint8Array(input);
+    return this.runNativeOperation(() => this.binding.execProtocolRaw(this.handle, requestBytes));
+  }
+
+  async #runRawProtocolUnlocked(input: BinaryInput): Promise {
+    try {
+      return await this.#execProtocolRawUnlocked(input);
+    } catch (error) {
+      // Raw protocol bypasses Oliphaunt's response-boundary parser. If the
+      // adapter rejects, neither the caller nor this layer can prove where the
+      // physical PostgreSQL session stopped, so subsequent work is unsafe.
+      this.#poison(error, 'raw PostgreSQL transport outcome is unknown');
+      throw error;
+    }
+  }
+
+  async #execProtocolStreamUnlocked(
+    input: BinaryInput,
+    onChunk: ProtocolChunkCallback,
+  ): Promise {
+    if (typeof onChunk !== 'function') {
+      throw new TypeError('protocol stream callback must be a function');
+    }
+    const requestBytes = toUint8Array(input);
+    const consumer = synchronousProtocolChunkConsumer((chunk) => {
+      this.#streamCallbackActive = true;
+      try {
+        return (onChunk as (chunk: Uint8Array) => unknown)(chunk);
+      } finally {
+        this.#streamCallbackActive = false;
+      }
+    });
+    try {
+      await this.binding.execProtocolStream(this.handle, requestBytes, consumer.callback);
+    } catch (error) {
+      // Adapters only preserve callback identity when they have positively
+      // confirmed recovery (for example the broker SQL connection reaching ReadyForQuery). Any
+      // other rejection is the authoritative execution/recovery outcome.
+      if (consumer.failure === undefined || !Object.is(error, consumer.failure.error)) {
+        this.#poison(error, 'streaming raw PostgreSQL recovery was not proven');
+      }
+      throw error;
+    }
+    if (consumer.failure !== undefined) {
+      throw consumer.failure.error;
+    }
+  }
+
+  #assertOpen(): void {
+    this.#assertNoStreamCallbackReentry();
+    if (this.#closed) {
+      throw new Error('Oliphaunt database is closed');
+    }
+    if (this.#closing) {
+      throw new Error('Oliphaunt database is closing');
+    }
+    this.#assertHealthy();
+  }
+
+  #assertHealthy(): void {
+    if (this.#sessionFailure !== undefined) {
+      throw new Error('Oliphaunt session state is unknown; close the database', {
+        cause: this.#sessionFailure,
+      });
+    }
+  }
+
+  protected assertNoActiveTransaction(): void {
+    this.#assertNoStreamCallbackReentry();
+    if (this.#activeTransaction) {
+      throw new Error(transactionPinnedMessage);
+    }
+  }
+
+  #assertNoStreamCallbackReentry(): void {
+    if (this.#streamCallbackActive) {
+      throw streamCallbackReentryError();
+    }
+  }
+
+  #retire(): unknown | undefined {
+    this.#closed = true;
+    const failures: unknown[] = [];
+    try {
+      this.binding.unregisterForgottenHandleCleanup?.(this);
+    } catch (error) {
+      failures.push(error);
+    }
+    try {
+      this.#releaseOwnership?.();
+    } catch (error) {
+      failures.push(error);
+    }
+    if (failures.length === 0) return undefined;
+    if (failures.length === 1) return failures[0];
+    return new AggregateError(failures, 'Oliphaunt owner retirement failed');
+  }
+
+  protected withSessionOperation(body: () => T | Promise): Promise {
+    this.#assertOpen();
+    const operation = this.#operationTail.then(async () => {
+      this.#assertHealthy();
+      return await body();
+    });
+    this.#operationTail = operation.then(
+      () => undefined,
+      () => undefined,
+    );
+    return operation;
+  }
+
+  protected async runNativeOperation(
+    body: () => T | undefined | Promise,
+  ): Promise {
+    const result = await body();
+    if (result === undefined) {
+      throw new Error('native oliphaunt runtime operation returned no result');
+    }
+    return result;
+  }
+
+  async #runNativeVoidOperation(body: () => void | Promise): Promise {
+    await body();
+  }
+
+  #poison(error: unknown, message: string): void {
+    this.#sessionFailure ??= new Error(message, { cause: error });
+  }
+}
+
+class OliphauntDatabaseImpl extends OliphauntDatabaseBase implements OliphauntDatabase {
+  async backup(): Promise {
+    this.assertNoActiveTransaction();
+    return this.withSessionOperation(async () => {
+      const backup = this.binding.backup;
+      if (backup === undefined) {
+        throw new Error('database runtime binding does not implement backup');
+      }
+      return this.runNativeOperation(() => backup(this.handle));
+    });
+  }
+}
+
+class OliphauntServerOwner extends OliphauntDatabaseBase {}
+
+class OliphauntServerImpl implements OliphauntServer {
+  readonly #owner: OliphauntServerOwner;
+
+  constructor(
+    owner: OliphauntServerOwner,
+    readonly connectionString: string,
+  ) {
+    this.#owner = owner;
+  }
+
+  get closed(): boolean {
+    return this.#owner.closed;
+  }
+
+  close(): Promise {
+    return this.#owner.close();
+  }
+
+  async [Symbol.asyncDispose](): Promise {
+    await this.close();
+  }
+}
+
+class OliphauntTransactionHandle implements OliphauntTransaction {
+  readonly #runPlan: (
+    plan: QueryPlan,
+    decode: (response: Uint8Array) => Result,
+  ) => Promise;
+  readonly #runStructured: (
+    input: Uint8Array,
+    decode: (response: Uint8Array) => Result,
+  ) => Promise;
+  readonly #rollbackControl: () => Promise;
+  #state: 'active' | 'finishing' | 'closed' = 'active';
+  #tail = Promise.resolve();
+  #rollbackAttempt?: Promise;
+  #rolledBack = false;
+  #firstFailure: unknown;
+
+  constructor(
+    runPlan: (
+      plan: QueryPlan,
+      decode: (response: Uint8Array) => Result,
+    ) => Promise,
+    runStructured: (
+      input: Uint8Array,
+      decode: (response: Uint8Array) => Result,
+    ) => Promise,
+    rollbackControl: () => Promise,
+  ) {
+    this.#runPlan = runPlan;
+    this.#runStructured = runStructured;
+    this.#rollbackControl = rollbackControl;
+  }
+
+  get closed(): boolean {
+    return this.#state === 'closed';
+  }
+
+  get rollbackStarted(): boolean {
+    return this.#rollbackAttempt !== undefined;
+  }
+
+  get rolledBack(): boolean {
+    return this.#rolledBack;
+  }
+
+  get firstFailure(): unknown {
+    return this.#firstFailure;
+  }
+
+  execute(
+    sql: string,
+    parameters: ReadonlyArray = [],
+    options: ParameterOptions = {},
+  ): Promise {
+    return promiseFromSynchronousCall(() => {
+      assertNoTransactionChain(sql);
+      const plan = planQuery(sql, parameters, snapshotParameterOptions(options));
+      return this.#enqueue(() => this.#runPlan(plan, parseCommandResponse));
+    });
+  }
+
+  query(
+    sql: string,
+    parameters: ReadonlyArray = [],
+    options: Options & QueryOptions = {} as Options & QueryOptions,
+  ): Promise>> {
+    return promiseFromSynchronousCall(() => {
+      assertNoTransactionChain(sql);
+      const stableOptions = snapshotQueryOptions(options);
+      const plan = planQuery(sql, parameters, stableOptions);
+      return this.#enqueue(async () => {
+        return decodeQueryResult(
+          await this.#runPlan(plan, parseQueryRawResponse),
+          stableOptions,
+        );
+      });
+    });
+  }
+
+  queryRaw(
+    sql: string,
+    parameters: ReadonlyArray = [],
+    options: ParameterOptions = {},
+  ): Promise {
+    return promiseFromSynchronousCall(() => {
+      assertNoTransactionChain(sql);
+      const plan = planQuery(sql, parameters, snapshotParameterOptions(options));
+      return this.#enqueue(() => this.#runPlan(plan, parseQueryRawResponse));
+    });
+  }
+
+  exec(
+    sql: string,
+    options: Options & QueryReadOptions = {} as Options & QueryReadOptions,
+  ): Promise>> {
+    return promiseFromSynchronousCall(() => {
+      assertNoTransactionChain(sql);
+      const input = structuredSimpleQuery(sql);
+      const stableOptions = snapshotReadOptions(options);
+      return this.#enqueue(() =>
+        this.#runStructured(input, (response) =>
+          parseExecResponse(response, stableOptions),
+        ),
+      );
+    });
+  }
+
+  describe(sql: string, parameterTypeOids: ReadonlyArray = []): Promise {
+    return promiseFromSynchronousCall(() => {
+      const input = describeQuery(sql, [...parameterTypeOids]);
+      return this.#enqueue(() => this.#runStructured(input, parseDescribeResponse));
+    });
+  }
+
+  rollback(): Promise {
+    return promiseFromSynchronousCall(() => {
+      this.#assertActive();
+      this.#state = 'finishing';
+      const operation = this.#enqueueFinishing(this.#rollbackControl);
+      const attempt = operation.then(
+        () => {
+          this.#rolledBack = true;
+          this.#state = 'closed';
+        },
+        (error: unknown) => {
+          this.#state = 'closed';
+          throw error;
+        },
+      );
+      this.#rollbackAttempt = attempt;
+      return attempt;
+    });
+  }
+
+  deactivate(): void {
+    this.#state = 'closed';
+  }
+
+  seal(): void {
+    if (this.#state === 'active') this.#state = 'finishing';
+  }
+
+  async drain(): Promise {
+    await this.#tail;
+  }
+
+  async sealAndDrain(): Promise {
+    this.seal();
+    await this.#tail;
+    await this.#rollbackAttempt;
+  }
+
+  async waitForRollback(): Promise {
+    await this.#rollbackAttempt;
+  }
+
+  #assertActive(): void {
+    if (this.#state === 'finishing') throw new Error('transaction is finishing');
+    if (this.#state === 'closed') throw new Error('transaction is no longer active');
+  }
+
+  #enqueue(body: () => Promise): Promise {
+    try {
+      this.#assertActive();
+    } catch (error) {
+      return Promise.reject(error);
+    }
+    return this.#enqueueFinishing(body);
+  }
+
+  #enqueueFinishing(body: () => Promise): Promise {
+    const operation = this.#tail.then(body);
+    this.#tail = operation.then(
+      () => undefined,
+      (error: unknown) => {
+        this.#firstFailure ??= error;
+      },
+    );
+    return operation;
+  }
+}
+
+const transactionPinnedMessage = 'physical session is pinned; use the active OliphauntTransaction';
+
+type StructuredScope = 'database' | 'transaction';
+type NoticeCarrier = { notices: PostgresNotice[] };
+
+function promiseFromSynchronousCall(body: () => Promise): Promise {
+  try {
+    return body();
+  } catch (error) {
+    return Promise.reject(error);
+  }
+}
+
+function snapshotParameterOptions(options: ParameterOptions): ParameterOptions {
+  return Object.freeze({
+    ...(options.encoders === undefined ? {} : { encoders: Object.freeze({ ...options.encoders }) }),
+  });
+}
+
+function snapshotReadOptions(options: Options): Options {
+  return Object.freeze({
+    rowMode: options.rowMode,
+    valueMode: options.valueMode,
+    ...(options.decoders === undefined ? {} : { decoders: Object.freeze({ ...options.decoders }) }),
+  }) as Options;
+}
+
+function snapshotQueryOptions(options: Options): Options {
+  return Object.freeze({
+    ...snapshotReadOptions(options),
+    ...snapshotParameterOptions(options),
+  }) as Options;
+}
+
+function prependNotices(
+  result: Result,
+  notices: ReadonlyArray,
+): Result {
+  if (notices.length > 0) result.notices.unshift(...notices);
+  return result;
+}
+
+function isNoticeCarrier(value: unknown): value is NoticeCarrier {
+  return (
+    value !== null &&
+    typeof value === 'object' &&
+    Array.isArray((value as { notices?: unknown }).notices)
+  );
+}
+
+function transactionTagError(expected: string, actual: string | undefined): Error {
+  return new Error(
+    `PostgreSQL transaction command expected ${expected}, got ${actual ?? 'no command tag'}`,
+  );
+}
+
+function transactionBoundaryError(
+  expected: 'BEGIN' | 'COMMIT' | 'ROLLBACK',
+  actual: string | undefined,
+  status: TransactionStatus,
+): Error {
+  return new Error(
+    `PostgreSQL transaction command expected ${expected} with its matching readiness status, got ${actual ?? 'no command tag'} with ${status}`,
+  );
+}
+
+function collapseFailures(failures: readonly unknown[], message: string): unknown | undefined {
+  if (failures.length === 0) return undefined;
+  if (failures.length === 1) return failures[0];
+  return new AggregateError(failures, message);
+}
+
+function transactionCallbackAggregate(
+  callback: unknown,
+  secondary: unknown,
+  message: string,
+): AggregateError {
+  return new AggregateError([callback, secondary], message);
+}
+
+function noop(): void {}
+
+export function createOliphauntClient(
+  bindingFactory: NativeBindingFactory = createDefaultNativeBinding,
+  runtimeOverrides: RuntimeBindingOverrides = {},
+): OliphauntClient {
+  const bindings = new Map>();
+  const brokerBindings = new Map();
+  const serverBinding = runtimeOverrides.server ?? createServerRuntimeBinding();
+  const directResident = {
+    temporaryDirectory: undefined as string | undefined,
+    activeOwner: undefined as symbol | undefined,
+    openQueue: Promise.resolve() as Promise,
+  };
+
+  function bindingFor(options: NativeBindingOptions = {}): Promise {
+    const key = options.libraryPath ?? '';
+    const cached = bindings.get(key);
+    if (cached !== undefined) {
+      return cached;
+    }
+    const created = Promise.resolve()
+      .then(() => bindingFactory(options))
+      .catch((error) => {
+        bindings.delete(key);
+        throw error;
+      });
+    bindings.set(key, created);
+    return created;
+  }
+
+  function brokerBindingFor(config: { brokerExecutable?: string }): RuntimeBinding {
+    if (runtimeOverrides.broker !== undefined) {
+      return runtimeOverrides.broker;
+    }
+    const key = config.brokerExecutable ?? '';
+    const cached = brokerBindings.get(key);
+    if (cached !== undefined) {
+      return cached;
+    }
+    const created = createBrokerRuntimeBinding({
+      executable: config.brokerExecutable,
+    });
+    brokerBindings.set(key, created);
+    return created;
+  }
+
+  function serializeDirectOpen(body: () => Promise): Promise {
+    const result = directResident.openQueue.then(body, body);
+    directResident.openQueue = result.then(
+      () => {},
+      () => {},
+    );
+    return result;
+  }
+
+  async function openDatabase(
+    effectiveConfig: OpenConfig | (ServerOpenConfig & { topology: 'server' }),
+  ): Promise {
+    const direct = effectiveConfig.topology === 'direct';
+    if (direct && directResident.activeOwner !== undefined) {
+      throw new Error('native direct already has an active process-wide instance');
+    }
+
+    const reusableTemporaryDirectory = direct ? directResident.temporaryDirectory : undefined;
+    const resolvedStorage = await materializeStorage(
+      effectiveConfig.storage,
+      reusableTemporaryDirectory,
+    );
+    let runtimeOpenAttempted = false;
+    try {
+      const normalized = normalizeOpenConfig(effectiveConfig, resolvedStorage);
+      let binding: RuntimeBinding;
+      if (normalized.topology === 'direct') {
+        binding = directRuntimeBinding(await bindingFor({ libraryPath: normalized.libraryPath }));
+      } else if (normalized.topology === 'broker') {
+        binding = brokerBindingFor({
+          brokerExecutable: normalized.brokerExecutable,
+        });
+      } else {
+        binding = serverBinding;
+      }
+
+      runtimeOpenAttempted = true;
+      const handle = await binding.open(normalized);
+      if (normalized.topology === 'server') {
+        const connectionString = binding.connectionString?.(handle);
+        if (connectionString === undefined) {
+          const mismatch = new Error('native server did not expose its connection string');
+          const cleanupFailure = await closeRuntimeHandleFailure(binding, handle);
+          if (cleanupFailure !== undefined) {
+            throw new AggregateError(
+              [mismatch, cleanupFailure],
+              'native server omitted its connection string and cleanup also failed',
+            );
+          }
+          throw mismatch;
+        }
+        const owner = await OliphauntDatabaseBase.publish(
+          new OliphauntServerOwner(binding, handle),
+        );
+        return new OliphauntServerImpl(owner, connectionString);
+      }
+      if (!direct) {
+        return await OliphauntDatabaseBase.publish(new OliphauntDatabaseImpl(binding, handle));
+      }
+
+      if (resolvedStorage.temporaryDirectory) {
+        directResident.temporaryDirectory ??= resolvedStorage.instanceDirectory;
+      }
+      const owner = Symbol('native-direct-owner');
+      directResident.activeOwner = owner;
+      return await OliphauntDatabaseBase.publish(
+        new OliphauntDatabaseImpl(binding, handle, () => {
+          if (directResident.activeOwner === owner) {
+            directResident.activeOwner = undefined;
+          }
+        }),
+      );
+    } catch (error) {
+      if (resolvedStorage.createdTemporaryDirectory) {
+        if (direct && runtimeOpenAttempted) {
+          // A native adapter can surface an error after liboliphaunt has claimed
+          // its process-resident PGDATA. Retain the candidate for a coherent
+          // retry, but do not publish it before the native open is entered.
+          directResident.temporaryDirectory ??= resolvedStorage.instanceDirectory;
+        } else if (!runtimeOpenAttempted) {
+          await removeDirectory(resolvedStorage.instanceDirectory);
+        }
+      }
+      throw error;
+    }
+  }
+
+  return {
+    async open(config: OpenConfig = {}): Promise {
+      const effectiveConfig = snapshotOpenConfig(config);
+      const database = await (effectiveConfig.topology === 'direct'
+        ? serializeDirectOpen(() => openDatabase(effectiveConfig))
+        : openDatabase(effectiveConfig));
+      if (database instanceof OliphauntServerImpl) {
+        return rejectUnexpectedFacade(
+          database,
+          new Error('generic database opener returned a native server'),
+        );
+      }
+      return database;
+    },
+
+    async openServer(config: ServerOpenConfig = {}): Promise {
+      const database = await openDatabase(snapshotServerOpenConfig(config));
+      if (!(database instanceof OliphauntServerImpl)) {
+        return rejectUnexpectedFacade(
+          database,
+          new Error('native server opener returned a non-server database'),
+        );
+      }
+      return database;
+    },
+
+    async restore(
+      destination: string,
+      backup: BinaryInput,
+      options: RestoreOptions = {},
+    ): Promise {
+      validateDirectoryPath(destination, 'restore destination');
+      const bytes = toUint8Array(backup).slice();
+      const binding = await bindingFor({ libraryPath: options.libraryPath });
+      await binding.restore({
+        destination,
+        bytes,
+      });
+    },
+  };
+}
+
+function snapshotOpenConfig(config: OpenConfig): OpenConfig & { topology: 'direct' | 'broker' } {
+  const topology = normalizeDatabaseTopology(config.topology);
+  validateNativeStartupGUCs(topology, config.startupGUCs ?? {});
+  return {
+    ...snapshotCommonOpenConfig(config),
+    topology,
+    libraryPath: config.libraryPath,
+    brokerExecutable: config.brokerExecutable,
+  };
+}
+
+async function rejectUnexpectedFacade(
+  facade: OliphauntDatabaseImpl | OliphauntServerImpl,
+  mismatch: Error,
+): Promise {
+  try {
+    await facade.close();
+  } catch (cleanupFailure) {
+    throw new AggregateError(
+      [mismatch, cleanupFailure],
+      'native runtime returned the wrong facade and cleanup also failed',
+    );
+  }
+  throw mismatch;
+}
+
+async function closeRuntimeHandleFailure(
+  binding: RuntimeBinding,
+  handle: RuntimeHandle,
+): Promise {
+  try {
+    const outcome = await binding.close(handle);
+    return outcome.state === 'closed' ? undefined : outcome.error;
+  } catch (error) {
+    return error;
+  }
+}
+
+function snapshotServerOpenConfig(
+  config: ServerOpenConfig,
+): ServerOpenConfig & { topology: 'server' } {
+  validateNativeStartupGUCs('server', config.startupGUCs ?? {});
+  return {
+    ...snapshotCommonOpenConfig(config),
+    topology: 'server',
+    serverExecutable: config.serverExecutable,
+    listen: snapshotServerListen(config.listen),
+  };
+}
+
+function snapshotCommonOpenConfig(config: OpenConfig | ServerOpenConfig) {
+  return {
+    storage: snapshotStorage(config.storage),
+    startupGUCs: config.startupGUCs === undefined ? undefined : { ...config.startupGUCs },
+    username: config.username,
+    database: config.database,
+    extensions: config.extensions === undefined ? undefined : [...config.extensions],
+    runtimeDirectory: config.runtimeDirectory,
+    ...('seed' in config && config.seed !== undefined ? { seed: { ...config.seed } } : {}),
+    ...(config.icuData !== undefined ? { icuData: { ...config.icuData } } : {}),
+  };
+}
+
+function snapshotStorage(storage: DatabaseStorage | undefined): DatabaseStorage | undefined {
+  if (storage === undefined) return undefined;
+  return storage.kind === 'directory'
+    ? { kind: 'directory', path: storage.path }
+    : { kind: storage.kind };
+}
+
+function snapshotServerListen(listen: ServerListen | undefined): ServerListen | undefined {
+  if (listen === undefined) return undefined;
+  return listen.transport === 'tcp'
+    ? { transport: 'tcp', port: listen.port }
+    : { transport: 'unix', directory: listen.directory, port: listen.port };
+}
+
+async function materializeStorage(
+  storage: DatabaseStorage | undefined,
+  reusableTemporaryDirectory?: string,
+): Promise<{
+  instanceDirectory: string;
+  temporaryDirectory: boolean;
+  createdTemporaryDirectory: boolean;
+}> {
+  if (storage === undefined || storage.kind === 'temporaryDirectory') {
+    if (reusableTemporaryDirectory !== undefined) {
+      return {
+        instanceDirectory: reusableTemporaryDirectory,
+        temporaryDirectory: true,
+        createdTemporaryDirectory: false,
+      };
+    }
+    return {
+      instanceDirectory: await mkdtemp(join(tmpdir(), 'liboliphaunt-js-')),
+      temporaryDirectory: true,
+      createdTemporaryDirectory: true,
+    };
+  }
+  if (storage.kind === 'directory') {
+    await mkdir(storage.path, { recursive: true });
+    return {
+      instanceDirectory: storage.path,
+      temporaryDirectory: false,
+      createdTemporaryDirectory: false,
+    };
+  }
+  throw new Error(
+    `unknown native database storage kind '${String((storage as { kind?: unknown }).kind)}'`,
+  );
+}
+
+async function removeDirectory(path: string): Promise {
+  await rm(path, { recursive: true, force: true }).catch(() => {});
+}
+
+function synchronousProtocolChunkConsumer(callback: (chunk: Uint8Array) => unknown): {
+  callback: ProtocolChunkCallback;
+  failure?: { error: unknown };
+} {
+  const consumer: {
+    callback: ProtocolChunkCallback;
+    failure?: { error: unknown };
+  } = {
+    callback(chunk) {
+      try {
+        const result = (callback as (chunk: Uint8Array) => unknown)(chunk);
+        if (!isThenable(result)) return;
+        // A synchronous chunk boundary cannot await caller work. Observe any
+        // eventual rejection before reporting the contract violation.
+        void Promise.resolve(result).catch(() => undefined);
+        throw new TypeError(
+          'raw protocol stream callback must complete synchronously and must not return a Promise or thenable',
+        );
+      } catch (error) {
+        consumer.failure ??= { error };
+        throw error;
+      }
+    },
+  };
+  return consumer;
+}
+
+function streamCallbackReentryError(): Error {
+  return new Error(
+    'raw protocol stream callback must not re-enter the same Oliphaunt handle; cancel remains available',
+  );
+}
+
+function isThenable(value: unknown): value is PromiseLike {
+  return (
+    ((typeof value === 'object' && value !== null) || typeof value === 'function') &&
+    typeof (value as { then?: unknown }).then === 'function'
+  );
+}
diff --git a/src/sdks/js/src/config.ts b/src/sdks/ts/sdk/src/config.ts
similarity index 92%
rename from src/sdks/js/src/config.ts
rename to src/sdks/ts/sdk/src/config.ts
index 1cd1ed317..2e53f4ae0 100644
--- a/src/sdks/js/src/config.ts
+++ b/src/sdks/ts/sdk/src/config.ts
@@ -4,7 +4,12 @@ import {
   generatedExtensionBySqlName,
   generatedSharedPreloadLibraries,
 } from './generated/extensions.js';
-import type { OpenConfig, ServerListen, ServerOpenConfig } from './types.js';
+import type {
+  NativeResourceDirectory,
+  OpenConfig,
+  ServerListen,
+  ServerOpenConfig,
+} from './types.js';
 
 type RuntimeTopology = 'direct' | 'broker' | 'server';
 export type DatabaseTopology = Exclude;
@@ -27,6 +32,8 @@ export type NormalizedOpenConfig = {
   extensions: string[];
   libraryPath?: string;
   runtimeDirectory?: string;
+  seed?: NativeResourceDirectory;
+  icuData?: NativeResourceDirectory;
   brokerExecutable?: string;
   serverExecutable?: string;
   serverListen?: ServerListen;
@@ -79,12 +86,28 @@ export function normalizeOpenConfig(
     extensions,
     libraryPath,
     runtimeDirectory,
+    ...('seed' in config && config.seed !== undefined
+      ? { seed: validateResourceDirectory(config.seed, 'seed') }
+      : {}),
+    ...(config.icuData !== undefined
+      ? { icuData: validateResourceDirectory(config.icuData, 'icuData') }
+      : {}),
     brokerExecutable,
     serverExecutable,
     serverListen,
   };
 }
 
+function validateResourceDirectory(
+  value: NativeResourceDirectory | undefined,
+  label: string,
+): NativeResourceDirectory | undefined {
+  if (value === undefined) return undefined;
+  validateDirectoryPath(value.directory, `${label} directory`);
+  validateDirectoryPath(value.manifestPath, `${label} manifestPath`);
+  return { directory: value.directory, manifestPath: value.manifestPath };
+}
+
 export function normalizeDatabaseTopology(value: unknown): DatabaseTopology {
   if (value === undefined || value === 'direct') return 'direct';
   if (value === 'broker') return 'broker';
diff --git a/src/sdks/ts/sdk/src/direct.ts b/src/sdks/ts/sdk/src/direct.ts
new file mode 100644
index 000000000..03342ff81
--- /dev/null
+++ b/src/sdks/ts/sdk/src/direct.ts
@@ -0,0 +1,23 @@
+import { Oliphaunt as client } from './index.js';
+import type * as Types from './types.js';
+export * from './index.js';
+
+export type OpenConfig = Omit & {
+  topology?: never;
+  brokerExecutable?: never;
+};
+export type OliphauntClient = Omit & {
+  open(config?: OpenConfig): Promise;
+};
+export const Oliphaunt: OliphauntClient = {
+  ...client,
+  async open(config = {}) {
+    if (config.topology !== undefined || config.brokerExecutable !== undefined) {
+      throw new TypeError(
+        '@oliphaunt/ts/direct does not accept topology or brokerExecutable; select the execution mode through the import path',
+      );
+    }
+    return client.open({ ...config, topology: 'direct' });
+  },
+};
+export default Oliphaunt;
diff --git a/src/sdks/ts/sdk/src/generated/extensions.ts b/src/sdks/ts/sdk/src/generated/extensions.ts
new file mode 100644
index 000000000..c729ea666
--- /dev/null
+++ b/src/sdks/ts/sdk/src/generated/extensions.ts
@@ -0,0 +1,990 @@
+// This file is generated by src/extensions/tools/check-extension-model.sh.
+// Do not edit by hand.
+
+export type GeneratedExtensionMetadata = {
+  readonly id: string;
+  readonly sqlName: string;
+  readonly displayName: string;
+  readonly postgresMajor: number;
+  readonly artifactProduct: string;
+  readonly releaseProduct: string;
+  readonly cargoPackage: string;
+  readonly npmPackage: string;
+  readonly mavenGroup: string;
+  readonly mavenArtifact: string;
+  readonly runtimeBound: boolean;
+  readonly createsExtension: boolean;
+  readonly nativeModuleStem: string | null;
+  readonly dependencies: readonly string[];
+  readonly selectedExtensionDependencies: readonly string[];
+  readonly sharedPreloadLibraries: readonly string[];
+  readonly dataFiles: readonly string[];
+  readonly runtimeShareDataFiles: readonly string[];
+  readonly extensionSqlFilePrefixes: readonly string[];
+  readonly extensionSqlFileNames: readonly string[];
+  readonly sourceKind: string;
+};
+
+export const GENERATED_EXTENSION_METADATA_SHA256 = "c1d2e09905d7ecc0172173b34b9e4104dad58987503dd3dab7af4ae78890d9f3" as const;
+
+export const GENERATED_EXTENSION_METADATA = [
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "amcheck",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "amcheck",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "amcheck",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "amcheck"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": false,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "auto_explain",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "auto_explain",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "auto_explain",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "auto_explain"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "bloom",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "bloom",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "bloom",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "bloom"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "btree_gin",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "btree_gin",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "btree_gin",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "btree_gin"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "btree_gist",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "btree_gist",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "btree_gist",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "btree_gist"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "citext",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "citext",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "citext",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "citext"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "cube",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "cube",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "cube",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "cube"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "dict_int",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "dict_int",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "dict_int",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "dict_int"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [
+      "share/postgresql/tsearch_data/xsyn_sample.rules"
+    ],
+    "dependencies": [],
+    "displayName": "dict_xsyn",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "dict_xsyn",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "dict_xsyn",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [
+      "tsearch_data/xsyn_sample.rules"
+    ],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "dict_xsyn"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [
+      "cube"
+    ],
+    "displayName": "earthdistance",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "earthdistance",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "earthdistance",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [
+      "cube"
+    ],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "earthdistance"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "file_fdw",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "file_fdw",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "file_fdw",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "file_fdw"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "fuzzystrmatch",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "fuzzystrmatch",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "fuzzystrmatch",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "fuzzystrmatch"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "hstore",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "hstore",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "hstore",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "hstore"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "intarray",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "intarray",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "_int",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "intarray"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "isn",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "isn",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "isn",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "isn"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "lo",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "lo",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "lo",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "lo"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "ltree",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "ltree",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "ltree",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "ltree"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pageinspect",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pageinspect",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pageinspect",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pageinspect"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_buffercache",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_buffercache",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_buffercache",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_buffercache"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_freespacemap",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_freespacemap",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_freespacemap",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_freespacemap"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-pg-hashids",
+    "cargoPackage": "oliphaunt-extension-pg-hashids",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_hashids",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_hashids",
+    "mavenArtifact": "oliphaunt-extension-pg-hashids",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_hashids",
+    "npmPackage": "@oliphaunt/extension-pg-hashids",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pg-hashids",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pg_hashids"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-pg-ivm",
+    "cargoPackage": "oliphaunt-extension-pg-ivm",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_ivm",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_ivm",
+    "mavenArtifact": "oliphaunt-extension-pg-ivm",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_ivm",
+    "npmPackage": "@oliphaunt/extension-pg-ivm",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pg-ivm",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pg_ivm"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_surgery",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_surgery",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_surgery",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_surgery"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-pg-textsearch",
+    "cargoPackage": "oliphaunt-extension-pg-textsearch",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_textsearch",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_textsearch",
+    "mavenArtifact": "oliphaunt-extension-pg-textsearch",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_textsearch",
+    "npmPackage": "@oliphaunt/extension-pg-textsearch",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pg-textsearch",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [
+      "pg_textsearch"
+    ],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pg_textsearch"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_trgm",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_trgm",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_trgm",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_trgm"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-pg-uuidv7",
+    "cargoPackage": "oliphaunt-extension-pg-uuidv7",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_uuidv7",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_uuidv7",
+    "mavenArtifact": "oliphaunt-extension-pg-uuidv7",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_uuidv7",
+    "npmPackage": "@oliphaunt/extension-pg-uuidv7",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pg-uuidv7",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pg_uuidv7"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_visibility",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_visibility",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_visibility",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_visibility"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pg_walinspect",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pg_walinspect",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pg_walinspect",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pg_walinspect"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pgcrypto",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "pgcrypto",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "pgcrypto",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "pgcrypto"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-pgtap",
+    "cargoPackage": "oliphaunt-extension-pgtap",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [
+      "plpgsql"
+    ],
+    "displayName": "pgtap",
+    "extensionSqlFileNames": [
+      "uninstall_pgtap.sql"
+    ],
+    "extensionSqlFilePrefixes": [
+      "pgtap-core",
+      "pgtap-schema"
+    ],
+    "id": "pgtap",
+    "mavenArtifact": "oliphaunt-extension-pgtap",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": null,
+    "npmPackage": "@oliphaunt/extension-pgtap",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-pgtap",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "pgtap"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-postgis",
+    "cargoPackage": "oliphaunt-extension-postgis",
+    "createsExtension": true,
+    "dataFiles": [
+      "share/postgresql/contrib/postgis-3.6/legacy.sql",
+      "share/postgresql/contrib/postgis-3.6/legacy_gist.sql",
+      "share/postgresql/contrib/postgis-3.6/legacy_minimal.sql",
+      "share/postgresql/contrib/postgis-3.6/postgis.sql",
+      "share/postgresql/contrib/postgis-3.6/postgis_upgrade.sql",
+      "share/postgresql/contrib/postgis-3.6/spatial_ref_sys.sql",
+      "share/postgresql/contrib/postgis-3.6/uninstall_legacy.sql",
+      "share/postgresql/contrib/postgis-3.6/uninstall_postgis.sql",
+      "share/postgresql/proj/proj.db"
+    ],
+    "dependencies": [],
+    "displayName": "PostGIS",
+    "extensionSqlFileNames": [
+      "uninstall_postgis.sql"
+    ],
+    "extensionSqlFilePrefixes": [
+      "postgis_comments",
+      "postgis_proc_set_search_path",
+      "rtpostgis"
+    ],
+    "id": "postgis",
+    "mavenArtifact": "oliphaunt-extension-postgis",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "postgis-3",
+    "npmPackage": "@oliphaunt/extension-postgis",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-postgis",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [
+      "contrib/postgis-3.6/legacy.sql",
+      "contrib/postgis-3.6/legacy_gist.sql",
+      "contrib/postgis-3.6/legacy_minimal.sql",
+      "contrib/postgis-3.6/postgis.sql",
+      "contrib/postgis-3.6/postgis_upgrade.sql",
+      "contrib/postgis-3.6/spatial_ref_sys.sql",
+      "contrib/postgis-3.6/uninstall_legacy.sql",
+      "contrib/postgis-3.6/uninstall_postgis.sql",
+      "proj/proj.db"
+    ],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgis",
+    "sqlName": "postgis"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "seg",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "seg",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "seg",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "seg"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "tablefunc",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "tablefunc",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "tablefunc",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "tablefunc"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "tcn",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "tcn",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "tcn",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "tcn"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "tsm_system_rows",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "tsm_system_rows",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "tsm_system_rows",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "tsm_system_rows"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "tsm_system_time",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "tsm_system_time",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "tsm_system_time",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "tsm_system_time"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [
+      "share/postgresql/tsearch_data/unaccent.rules"
+    ],
+    "dependencies": [],
+    "displayName": "unaccent",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "unaccent",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "unaccent",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [
+      "tsearch_data/unaccent.rules"
+    ],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "unaccent"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-contrib-pg18",
+    "cargoPackage": "oliphaunt-extension-contrib-pg18",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "uuid-ossp",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "uuid_ossp",
+    "mavenArtifact": "oliphaunt-extension-contrib-pg18",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "uuid-ossp",
+    "npmPackage": "@oliphaunt/extension-contrib-pg18",
+    "postgresMajor": 18,
+    "releaseProduct": "liboliphaunt-native",
+    "runtimeBound": true,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "postgres-contrib",
+    "sqlName": "uuid-ossp"
+  },
+  {
+    "artifactProduct": "oliphaunt-extension-vector",
+    "cargoPackage": "oliphaunt-extension-vector",
+    "createsExtension": true,
+    "dataFiles": [],
+    "dependencies": [],
+    "displayName": "pgvector",
+    "extensionSqlFileNames": [],
+    "extensionSqlFilePrefixes": [],
+    "id": "vector",
+    "mavenArtifact": "oliphaunt-extension-vector",
+    "mavenGroup": "dev.oliphaunt.extensions",
+    "nativeModuleStem": "vector",
+    "npmPackage": "@oliphaunt/extension-vector",
+    "postgresMajor": 18,
+    "releaseProduct": "oliphaunt-extension-vector",
+    "runtimeBound": false,
+    "runtimeShareDataFiles": [],
+    "selectedExtensionDependencies": [],
+    "sharedPreloadLibraries": [],
+    "sourceKind": "oliphaunt-other-extension",
+    "sqlName": "vector"
+  }
+] as const satisfies readonly GeneratedExtensionMetadata[];
+
+export function generatedExtensionBySqlName(sqlName: string): GeneratedExtensionMetadata | undefined {
+  return GENERATED_EXTENSION_METADATA.find((extension) => extension.sqlName === sqlName);
+}
+
+export function generatedSharedPreloadLibraries(extensionSqlNames: readonly string[]): string[] {
+  const libraries = new Set();
+  for (const sqlName of extensionSqlNames) {
+    const extension = generatedExtensionBySqlName(sqlName);
+    for (const library of extension?.sharedPreloadLibraries ?? []) {
+      libraries.add(library);
+    }
+  }
+  return [...libraries].sort();
+}
diff --git a/src/sdks/ts/sdk/src/index.ts b/src/sdks/ts/sdk/src/index.ts
new file mode 100644
index 000000000..74f0f9f9d
--- /dev/null
+++ b/src/sdks/ts/sdk/src/index.ts
@@ -0,0 +1,56 @@
+export {
+  array,
+  binary,
+  json,
+  postgresOids,
+  text,
+  typedNull,
+  type BinaryQueryParameter,
+  type CommandResult,
+  type DescribeResult,
+  type EncodedQueryParameter,
+  type ExecResult,
+  type InferQueryRow,
+  type NullQueryParameter,
+  type ParameterOptions,
+  PostgresError,
+  type PostgresErrorField,
+  type PostgresNotice,
+  type QueryArrayRow,
+  type QueryBinaryInput,
+  type QueryDecoderMap,
+  type QueryField,
+  type QueryFormat,
+  type QueryObjectRow,
+  type QueryOptions,
+  type QueryParam,
+  type QueryParameterEncoder,
+  type QueryResult,
+  type QueryRowMode,
+  type QueryValue,
+  type QueryValueDecoder,
+  type RawQueryResult,
+  type RawQueryRow,
+  type TextQueryParameter,
+  type TransactionStatus,
+} from './query.js';
+export type {
+  BinaryInput,
+  DatabaseStorage,
+  OliphauntClient,
+  OliphauntDatabase,
+  OliphauntTransaction,
+  OliphauntServer,
+  OpenConfig,
+  NativeResourceDirectory,
+  RestoreOptions,
+  ServerListen,
+  ServerOpenConfig,
+} from './types.js';
+
+import { createOliphauntClient } from './client.js';
+import type { OliphauntClient } from './types.js';
+
+export const Oliphaunt: OliphauntClient = createOliphauntClient();
+
+export default Oliphaunt;
diff --git a/src/sdks/ts/sdk/src/native/assets.ts b/src/sdks/ts/sdk/src/native/assets.ts
new file mode 100644
index 000000000..d9191ecbb
--- /dev/null
+++ b/src/sdks/ts/sdk/src/native/assets.ts
@@ -0,0 +1,1596 @@
+import { createHash, randomUUID } from 'node:crypto';
+import { createReadStream } from 'node:fs';
+import { cp, lstat, mkdir, readdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
+import { createRequire } from 'node:module';
+import { arch, platform, tmpdir } from 'node:os';
+import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
+import { setTimeout as delay } from 'node:timers/promises';
+import {
+  GENERATED_EXTENSION_METADATA,
+  type GeneratedExtensionMetadata,
+  generatedExtensionBySqlName,
+} from '../generated/extensions.js';
+import {
+  type NativeCatalogProfile,
+  validateSelectedIcuData,
+  validateSelectedNativeSeed,
+} from './cluster-seed.js';
+import type { NativeResourceDirectory } from '../types.js';
+import { validateManagedRoot } from '../root-descriptor.js';
+import {
+  liboliphauntPackageTarget,
+  type NativePackageTarget,
+  resolveExplicitLibraryPath,
+  resolveExplicitRuntimeDirectory,
+} from './common.js';
+import {
+  type NpmExtensionLicenseFileContract,
+  parseNpmExtensionLicenseFiles,
+} from './extension-contract.js';
+import {
+  nativeModuleSuffixForTarget,
+  type RuntimeFileHost,
+  selectedExtensionClosure,
+  validatePreparedRuntimeExtensions,
+} from './extension-runtime.js';
+import { syncDirectory, syncRuntimeDirectoryTree } from './filesystem-durability.js';
+
+export type ResolvedNativeInstall = {
+  libraryPath: string;
+  runtimeDirectory?: string;
+  icuDataDirectory?: string;
+  clusterSeedDirectory?: string;
+  clusterSeedEmptyDirectories?: readonly string[];
+  catalogProfile?: NativeCatalogProfile;
+  moduleDirectory?: string;
+  packageManaged?: boolean;
+};
+
+type PackageMetadata = {
+  name: string;
+  oliphaunt?: {
+    liboliphauntVersion?: string;
+  };
+};
+
+type LiboliphauntPackageMetadata = {
+  name?: string;
+  version?: string;
+  oliphaunt?: {
+    target?: string;
+    libraryRelativePath?: string;
+    runtimeRelativePath?: string;
+  };
+};
+
+type ExtensionPackageMetadata = {
+  name?: string;
+  version?: string;
+  oliphaunt?: {
+    product?: string;
+    kind?: string;
+    sqlName?: string;
+    target?: string;
+    runtimeRelativePath?: string;
+    moduleRelativePath?: string;
+    liboliphauntVersion?: string;
+    bundleManifest?: string;
+    extensionContract?: string;
+    members?: string[];
+    memberRuntimeRelativePaths?: Record;
+    memberModuleRelativePaths?: Record;
+    targetPackageNames?: Record;
+  };
+};
+
+type NpmExtensionRuntimeBundleMember = {
+  sqlName: string;
+  kind: 'runtime';
+  identity: null;
+  path: string;
+  sha256: string;
+  bytes: number;
+  runtimeRelativePath: string;
+  moduleRelativePath?: string;
+};
+
+type NpmExtensionMemberContract = {
+  sqlName: string;
+  createsExtension: boolean;
+  nativeModuleStem: string | null;
+  dependencies: string[];
+  dataFiles: string[];
+  extensionSqlFileNames: string[];
+  extensionSqlFilePrefixes: string[];
+  licenseFiles: NpmExtensionLicenseFileContract[];
+  sharedPreloadLibraries: string[];
+};
+
+type NpmExtensionContractManifest = {
+  schema?: string;
+  product?: string;
+  version?: string;
+  family?: string;
+  target?: string;
+  members?: unknown[];
+};
+
+type NpmExtensionBundleManifest = {
+  schema?: string;
+  product?: string;
+  version?: string;
+  family?: string;
+  target?: string;
+  members?: unknown[];
+};
+
+const require = createRequire(import.meta.url);
+const CACHE_LOCK_POLL_MS = 25;
+const CACHE_LOCK_TIMEOUT_MS = 30_000;
+const CACHE_LOCK_STALE_MS = 5 * 60_000;
+const MAX_EXTENSION_RUNTIME_FILES = 4096;
+const MAX_EXTENSION_RUNTIME_FILE_BYTES = 48 * 1024 * 1024;
+const MAX_EXTENSION_RUNTIME_BYTES = 256 * 1024 * 1024;
+const NPM_EXTENSION_CONTRACT_SCHEMA = 'oliphaunt-npm-extension-contract-v1';
+const NPM_EXTENSION_CONTRACT_MEMBER_FIELDS = [
+  'createsExtension',
+  'dataFiles',
+  'dependencies',
+  'extensionSqlFileNames',
+  'extensionSqlFilePrefixes',
+  'licenseFiles',
+  'nativeModuleStem',
+  'sharedPreloadLibraries',
+  'sqlName',
+] as const;
+
+export async function resolveNativeInstall(libraryPath?: string): Promise {
+  const versions = await packageVersions();
+  const explicit = resolveExplicitLibraryPath(libraryPath);
+  if (explicit !== undefined)
+    return {
+      libraryPath: explicit,
+      runtimeDirectory: resolveExplicitRuntimeDirectory(),
+      catalogProfile: 'standard',
+      packageManaged: false,
+    };
+  const target = liboliphauntPackageTarget(platform(), arch());
+  return resolvePackageNativeInstall(target, versions.liboliphauntVersion);
+}
+
+export async function selectNativeResources(
+  install: ResolvedNativeInstall,
+  resources: { seed?: NativeResourceDirectory; icuData?: NativeResourceDirectory },
+  root?: string,
+): Promise {
+  const seed = root !== undefined && (await validateManagedRoot(root)) ? undefined : resources.seed;
+  const icuHash =
+    resources.icuData === undefined ? undefined : await validateSelectedIcuData(resources.icuData);
+  let catalogProfile: NativeCatalogProfile = icuHash === undefined ? 'standard' : 'icu';
+  let emptyDirectories: string[] = [];
+  if (seed !== undefined) {
+    const target = liboliphauntPackageTarget(platform(), arch());
+    const versions = await packageVersions();
+    const selected = await validateSelectedNativeSeed(
+      seed,
+      target.id,
+      versions.liboliphauntVersion,
+      icuHash,
+    );
+    catalogProfile = selected.catalogProfile;
+    emptyDirectories = selected.emptyDirectories;
+  }
+  return {
+    ...install,
+    catalogProfile,
+    icuDataDirectory: resources.icuData?.directory,
+    clusterSeedDirectory: seed?.directory,
+    clusterSeedEmptyDirectories: emptyDirectories,
+  };
+}
+
+export async function prepareExtensionInstall(
+  install: ResolvedNativeInstall,
+  extensions: ReadonlyArray = [],
+  options: { explicitRuntimeDirectory?: boolean } = {},
+): Promise {
+  if (options.explicitRuntimeDirectory === true && extensions.length > 0) {
+    return validatePreparedNativeRuntimeExtensions(install, extensions);
+  }
+  return materializeExtensionInstall(install, extensions);
+}
+
+export async function validatePreparedNativeRuntimeExtensions(
+  install: ResolvedNativeInstall,
+  extensions: ReadonlyArray = [],
+): Promise {
+  const target = liboliphauntPackageTarget(platform(), arch());
+  const validated = await validatePreparedRuntimeExtensions({
+    runtimeDirectory: install.runtimeDirectory,
+    extensions,
+    target: target.id,
+    source: 'explicit native runtimeDirectory',
+    host: runtimeFileHost,
+  });
+  return {
+    ...install,
+    runtimeDirectory: validated.runtimeDirectory,
+    moduleDirectory: validated.moduleDirectory,
+  };
+}
+
+export async function materializeExtensionInstall(
+  install: ResolvedNativeInstall,
+  extensions: ReadonlyArray = [],
+): Promise {
+  const selected = selectedExtensionClosure(extensions);
+  if (selected.length === 0) {
+    return install;
+  }
+  if (install.runtimeDirectory === undefined) {
+    throw new Error(
+      `native extension packages require a package-managed runtime directory; selected extensions: ${selected.join(', ')}`,
+    );
+  }
+  const installRuntimeDirectory = install.runtimeDirectory;
+
+  const versions = await packageVersions();
+  const target = liboliphauntPackageTarget(platform(), arch());
+  const packages = await Promise.all(
+    selected.map((sqlName) =>
+      resolveExtensionPackage(sqlName, target.id, versions.liboliphauntVersion),
+    ),
+  );
+  const cacheKey = runtimeCacheKey({
+    libraryPath: install.libraryPath,
+    runtimeDirectory: installRuntimeDirectory,
+    target: target.id,
+    packages: packages.map((entry) => ({
+      name: entry.name,
+      version: entry.version,
+      contract: entry.contract,
+      runtimeDirectories: entry.runtimeDirectories,
+      moduleDirectories: entry.moduleDirectories,
+    })),
+  });
+  const root = join(tmpdir(), 'oliphaunt-js-runtime-cache', cacheKey);
+  const runtimeDirectory = join(root, 'runtime');
+  const moduleDirectory = join(root, 'modules');
+  const marker = join(root, 'manifest.json');
+  const manifest = JSON.stringify(
+    {
+      runtimeDirectory: installRuntimeDirectory,
+      libraryPath: install.libraryPath,
+      target: target.id,
+      packages: packages.map((entry) => ({
+        name: entry.name,
+        version: entry.version,
+        sqlName: entry.sqlName,
+        contract: entry.contract,
+      })),
+    },
+    null,
+    2,
+  );
+  if ((await optionalRead(marker)) === manifest) {
+    return { ...install, runtimeDirectory, moduleDirectory };
+  }
+
+  await publishRuntimeCache(root, manifest, async (stageRoot) => {
+    const stageRuntimeDirectory = join(stageRoot, 'runtime');
+    const stageModuleDirectory = join(stageRoot, 'modules');
+    await cp(installRuntimeDirectory, stageRuntimeDirectory, {
+      recursive: true,
+    });
+    await mkdir(stageModuleDirectory, { recursive: true });
+    for (const source of nativeModuleDirectoryCandidates(install.libraryPath)) {
+      if (await isDirectory(source)) {
+        await cp(source, stageModuleDirectory, {
+          force: true,
+          recursive: true,
+        });
+      }
+    }
+    for (const entry of packages) {
+      for (const source of entry.runtimeDirectories) {
+        await cp(source, stageRuntimeDirectory, {
+          force: true,
+          recursive: true,
+        });
+      }
+      for (const source of entry.moduleDirectories) {
+        if (await isDirectory(source)) {
+          await cp(source, stageModuleDirectory, {
+            force: true,
+            recursive: true,
+          });
+        }
+      }
+    }
+  });
+  return { ...install, runtimeDirectory, moduleDirectory };
+}
+
+async function packageVersions(): Promise<{
+  liboliphauntVersion: string;
+}> {
+  const packageJson = JSON.parse(
+    await readFile(require.resolve('@oliphaunt/ts/package.json'), 'utf8'),
+  ) as PackageMetadata;
+  const liboliphauntVersion = packageJson.oliphaunt?.liboliphauntVersion;
+  if (
+    packageJson.name !== '@oliphaunt/ts' ||
+    liboliphauntVersion === undefined ||
+    liboliphauntVersion.length === 0
+  ) {
+    throw new Error('@oliphaunt/ts package metadata does not pin liboliphauntVersion');
+  }
+  return { liboliphauntVersion };
+}
+
+type ResolvedExtensionPackage = {
+  name: string;
+  version: string;
+  sqlName: string;
+  contract: NpmExtensionMemberContract;
+  runtimeDirectories: string[];
+  moduleDirectories: string[];
+};
+
+async function resolveExtensionPackage(
+  sqlName: string,
+  target: string,
+  liboliphauntVersion: string,
+): Promise {
+  const extension = generatedExtensionBySqlName(sqlName);
+  if (extension === undefined) {
+    throw new Error(`unknown Oliphaunt extension id '${sqlName}'`);
+  }
+  const packageName = extension.npmPackage;
+  const targetPackageName = extensionTargetPackageName(extension, target);
+  const resolvedTarget = await resolveExtensionTargetPackageJson(
+    extension,
+    targetPackageName,
+    target,
+  );
+  const packageJsonPath = resolvedTarget.packageJsonPath;
+  const packageRoot = dirname(packageJsonPath);
+  const packageJson = JSON.parse(
+    await readFile(packageJsonPath, 'utf8'),
+  ) as ExtensionPackageMetadata;
+  const expectedProduct = extension.artifactProduct;
+  const expectedMembers = extensionOwnerMembers(extension);
+  const isBundle = expectedMembers.length > 1;
+  if (packageJson.name !== targetPackageName) {
+    throw new Error(
+      `${targetPackageName} package metadata has name ${packageJson.name ?? ''}`,
+    );
+  }
+  const expectedKind = isBundle ? 'exact-extension-bundle-target' : 'exact-extension-target';
+  if (packageJson.oliphaunt?.kind !== expectedKind) {
+    throw new Error(`${targetPackageName} package metadata does not declare ${expectedKind}`);
+  }
+  if (packageJson.oliphaunt?.product !== expectedProduct) {
+    throw new Error(`${targetPackageName} package metadata does not declare ${expectedProduct}`);
+  }
+  requireExtensionPackageMembers(packageJson, expectedMembers, targetPackageName);
+  if (packageJson.oliphaunt?.target !== target) {
+    throw new Error(`${targetPackageName} package metadata does not target ${target}`);
+  }
+  if (packageJson.oliphaunt?.liboliphauntVersion !== liboliphauntVersion) {
+    throw new Error(
+      `${targetPackageName} liboliphauntVersion ${packageJson.oliphaunt?.liboliphauntVersion ?? ''} does not match @oliphaunt/ts liboliphauntVersion ${liboliphauntVersion}`,
+    );
+  }
+  if (packageJson.version === undefined || packageJson.version.length === 0) {
+    throw new Error(`${targetPackageName} package metadata is missing version`);
+  }
+  if (packageJson.version !== resolvedTarget.ownerVersion) {
+    throw new Error(
+      `${targetPackageName} version ${packageJson.version} does not match ${packageName} version ${resolvedTarget.ownerVersion}`,
+    );
+  }
+  const memberContracts = await loadExtensionPackageContract({
+    extension,
+    expectedMembers,
+    packageJson,
+    packageRoot,
+    packageName: targetPackageName,
+    target,
+  });
+  const selectedContract = memberContracts.get(sqlName);
+  if (selectedContract === undefined) {
+    throw new Error(
+      `${targetPackageName} extension contract is missing selected member ${sqlName}`,
+    );
+  }
+  const runtimeDirectories: string[] = [];
+  const moduleDirectories: string[] = [];
+  if (isBundle) {
+    const payload = await resolveExtensionBundleMember({
+      extension,
+      expectedMembers,
+      packageJson,
+      packageRoot,
+      packageName: targetPackageName,
+      target,
+      memberContracts,
+    });
+    runtimeDirectories.push(payload.runtimeDirectory);
+    if (payload.moduleDirectory !== undefined) {
+      moduleDirectories.push(payload.moduleDirectory);
+    }
+  } else {
+    const runtimeRelativePath = packageJson.oliphaunt.runtimeRelativePath;
+    if (runtimeRelativePath !== 'runtime') {
+      throw new Error(`${targetPackageName} extension runtime path must be exactly runtime`);
+    }
+    const runtimeDirectory = resolvePackageRelativePath(
+      packageRoot,
+      runtimeRelativePath,
+      `${targetPackageName} extension runtime directory metadata`,
+    );
+    await requireDirectory(runtimeDirectory, `${targetPackageName} extension runtime directory`);
+    await requireExactExtensionRuntimeInventory({
+      contract: selectedContract,
+      runtimeDirectory,
+      target,
+      source: `${targetPackageName} extension runtime directory`,
+    });
+    runtimeDirectories.push(runtimeDirectory);
+    const moduleRelativePath = packageJson.oliphaunt.moduleRelativePath;
+    const expectedModuleRelativePath =
+      selectedContract.nativeModuleStem === null ? undefined : 'runtime/lib/modules';
+    if (moduleRelativePath !== expectedModuleRelativePath) {
+      throw new Error(
+        `${targetPackageName} extension module path must be ${expectedModuleRelativePath ?? ''}`,
+      );
+    }
+    const moduleDirectory =
+      moduleRelativePath === undefined
+        ? undefined
+        : resolvePackageRelativePath(
+            packageRoot,
+            moduleRelativePath,
+            `${targetPackageName} extension module directory metadata`,
+          );
+    if (moduleDirectory !== undefined) {
+      await requireDirectory(moduleDirectory, `${targetPackageName} extension module directory`);
+      moduleDirectories.push(moduleDirectory);
+    }
+  }
+  return {
+    name: targetPackageName,
+    version: packageJson.version,
+    sqlName,
+    contract: selectedContract,
+    runtimeDirectories,
+    moduleDirectories,
+  };
+}
+
+function extensionOwnerMembers(extension: GeneratedExtensionMetadata): string[] {
+  const rows = GENERATED_EXTENSION_METADATA.filter(
+    (candidate) =>
+      candidate.artifactProduct === extension.artifactProduct &&
+      candidate.npmPackage === extension.npmPackage,
+  );
+  if (
+    rows.length === 0 ||
+    rows.some(
+      (candidate) =>
+        candidate.cargoPackage !== extension.cargoPackage ||
+        candidate.mavenGroup !== extension.mavenGroup ||
+        candidate.mavenArtifact !== extension.mavenArtifact ||
+        candidate.runtimeBound !== extension.runtimeBound,
+    )
+  ) {
+    throw new Error(
+      `generated extension metadata has inconsistent release ownership for ${extension.sqlName}`,
+    );
+  }
+  return rows.map((candidate) => candidate.sqlName).sort();
+}
+
+function requireExtensionPackageMembers(
+  packageJson: ExtensionPackageMetadata,
+  expectedMembers: readonly string[],
+  packageName: string,
+): void {
+  if (expectedMembers.length === 1) {
+    if (packageJson.oliphaunt?.sqlName !== expectedMembers[0]) {
+      throw new Error(
+        `${packageName} package metadata does not declare SQL extension ${expectedMembers[0]}`,
+      );
+    }
+    return;
+  }
+  const members = packageJson.oliphaunt?.members;
+  if (
+    !Array.isArray(members) ||
+    members.some((member) => typeof member !== 'string') ||
+    JSON.stringify(members) !== JSON.stringify(expectedMembers)
+  ) {
+    throw new Error(
+      `${packageName} package metadata members must exactly match ${expectedMembers.join(', ')}`,
+    );
+  }
+}
+
+function compareText(left: string, right: string): number {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function parseExtensionContractStringList(value: unknown, field: string, label: string): string[] {
+  if (
+    !Array.isArray(value) ||
+    value.some((item) => typeof item !== 'string' || item.length === 0)
+  ) {
+    throw new Error(`${label}.${field} must be a string array`);
+  }
+  const rows = value as string[];
+  const canonical = [...new Set(rows)].sort(compareText);
+  if (JSON.stringify(rows) !== JSON.stringify(canonical)) {
+    throw new Error(`${label}.${field} must be sorted and unique`);
+  }
+  return rows;
+}
+
+function requirePortableExtensionContractPath(value: string, field: string, label: string): void {
+  const parts = value.split('/');
+  let decoded: string;
+  try {
+    decoded = decodeURIComponent(value);
+  } catch {
+    throw new Error(`${label}.${field} contains unsafe relative path ${value}`);
+  }
+  if (
+    value.includes('\\') ||
+    value !== value.normalize('NFC') ||
+    decoded !== value ||
+    value.startsWith('/') ||
+    /^[A-Za-z]:/u.test(value) ||
+    // biome-ignore lint/suspicious/noControlCharactersInRegex: Control characters make archive paths unsafe.
+    /[\u0000-\u001f\u007f]/u.test(value) ||
+    Buffer.byteLength(value, 'utf8') > 4096 ||
+    parts.some(
+      (part) =>
+        part === '' ||
+        part === '.' ||
+        part === '..' ||
+        Buffer.byteLength(part, 'utf8') > 255 ||
+        /[<>:"|?*]/u.test(part) ||
+        /[ .]$/u.test(part) ||
+        /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(part),
+    )
+  ) {
+    throw new Error(`${label}.${field} contains unsafe relative path ${value}`);
+  }
+}
+
+function requirePortableExtensionContractPaths(
+  values: readonly string[],
+  field: string,
+  label: string,
+): void {
+  const portable = new Map();
+  for (const value of values) {
+    requirePortableExtensionContractPath(value, field, label);
+    const key = value.toLowerCase();
+    const prior = portable.get(key);
+    if (prior !== undefined && prior !== value) {
+      throw new Error(`${label}.${field} contains case/NFC-colliding paths ${prior} and ${value}`);
+    }
+    portable.set(key, value);
+  }
+}
+
+function parseExtensionMemberContract(value: unknown, label: string): NpmExtensionMemberContract {
+  if (value === null || typeof value !== 'object' || Array.isArray(value)) {
+    throw new Error(`${label} must be a JSON object`);
+  }
+  const row = value as Record;
+  if (
+    JSON.stringify(Object.keys(row).sort(compareText)) !==
+    JSON.stringify(NPM_EXTENSION_CONTRACT_MEMBER_FIELDS)
+  ) {
+    throw new Error(
+      `${label} fields must be exactly ${NPM_EXTENSION_CONTRACT_MEMBER_FIELDS.join(', ')}`,
+    );
+  }
+  if (typeof row.sqlName !== 'string' || !/^[A-Za-z0-9._-]{1,128}$/u.test(row.sqlName)) {
+    throw new Error(`${label}.sqlName must be a portable identifier`);
+  }
+  if (typeof row.createsExtension !== 'boolean') {
+    throw new Error(`${label}.createsExtension must be a boolean`);
+  }
+  if (
+    row.nativeModuleStem !== null &&
+    (typeof row.nativeModuleStem !== 'string' ||
+      !/^[A-Za-z0-9._-]{1,128}$/u.test(row.nativeModuleStem))
+  ) {
+    throw new Error(`${label}.nativeModuleStem must be null or a portable identifier`);
+  }
+  const dependencies = parseExtensionContractStringList(row.dependencies, 'dependencies', label);
+  if (
+    dependencies.includes(row.sqlName) ||
+    dependencies.some((item) => !/^[A-Za-z0-9._-]{1,128}$/u.test(item))
+  ) {
+    throw new Error(`${label}.dependencies contains an invalid or self dependency`);
+  }
+  const dataFiles = parseExtensionContractStringList(row.dataFiles, 'dataFiles', label);
+  requirePortableExtensionContractPaths(dataFiles, 'dataFiles', label);
+  const extensionSqlFileNames = parseExtensionContractStringList(
+    row.extensionSqlFileNames,
+    'extensionSqlFileNames',
+    label,
+  );
+  if (
+    extensionSqlFileNames.some(
+      (file) => !/^[A-Za-z0-9._-]+\.sql$/u.test(file) || file.includes('/') || file.includes('\\'),
+    )
+  ) {
+    throw new Error(`${label}.extensionSqlFileNames must contain portable .sql basenames`);
+  }
+  const extensionSqlFilePrefixes = parseExtensionContractStringList(
+    row.extensionSqlFilePrefixes,
+    'extensionSqlFilePrefixes',
+    label,
+  );
+  if (extensionSqlFilePrefixes.some((prefix) => !/^[A-Za-z0-9_-]{1,128}$/u.test(prefix))) {
+    throw new Error(`${label}.extensionSqlFilePrefixes must contain portable dot-free prefixes`);
+  }
+  const licenseFiles = parseNpmExtensionLicenseFiles(row.licenseFiles, `${label}.licenseFiles`);
+  const sharedPreloadLibraries = parseExtensionContractStringList(
+    row.sharedPreloadLibraries,
+    'sharedPreloadLibraries',
+    label,
+  );
+  if (sharedPreloadLibraries.some((library) => !/^[A-Za-z0-9._-]{1,128}$/u.test(library))) {
+    throw new Error(`${label}.sharedPreloadLibraries contains an invalid identifier`);
+  }
+  return {
+    sqlName: row.sqlName,
+    createsExtension: row.createsExtension,
+    nativeModuleStem: row.nativeModuleStem as string | null,
+    dependencies,
+    dataFiles,
+    extensionSqlFileNames,
+    extensionSqlFilePrefixes,
+    licenseFiles,
+    sharedPreloadLibraries,
+  };
+}
+
+async function loadExtensionPackageContract(config: {
+  extension: GeneratedExtensionMetadata;
+  expectedMembers: readonly string[];
+  packageJson: ExtensionPackageMetadata;
+  packageRoot: string;
+  packageName: string;
+  target: string;
+}): Promise> {
+  const pointer = config.packageJson.oliphaunt?.extensionContract;
+  if (pointer !== 'extension-contract.json') {
+    throw new Error(
+      `${config.packageName} target must declare oliphaunt.extensionContract=extension-contract.json`,
+    );
+  }
+  const contractPath = resolvePackageRelativePath(
+    config.packageRoot,
+    pointer,
+    `${config.packageName} extension contract metadata`,
+  );
+  await requireFile(contractPath, `${config.packageName} extension contract`);
+  let parsed: unknown;
+  try {
+    parsed = JSON.parse(await readFile(contractPath, 'utf8')) as unknown;
+  } catch (error) {
+    throw new Error(`${config.packageName} extension contract is not valid JSON`, { cause: error });
+  }
+  if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
+    throw new Error(`${config.packageName} extension contract must be a JSON object`);
+  }
+  const manifest = parsed as NpmExtensionContractManifest;
+  const expectedFields = ['family', 'members', 'product', 'schema', 'target', 'version'];
+  if (JSON.stringify(Object.keys(manifest).sort(compareText)) !== JSON.stringify(expectedFields)) {
+    throw new Error(
+      `${config.packageName} extension contract fields must be exactly ${expectedFields.join(', ')}`,
+    );
+  }
+  if (manifest.schema !== NPM_EXTENSION_CONTRACT_SCHEMA) {
+    throw new Error(`${config.packageName} extension contract has unsupported schema`);
+  }
+  if (
+    manifest.product !== config.extension.artifactProduct ||
+    manifest.version !== config.packageJson.version ||
+    manifest.family !== 'native' ||
+    manifest.target !== config.target
+  ) {
+    throw new Error(
+      `${config.packageName} extension contract does not match its product, version, family, and target`,
+    );
+  }
+  if (!Array.isArray(manifest.members)) {
+    throw new Error(`${config.packageName} extension contract is missing members`);
+  }
+  const members = manifest.members.map((member, index) =>
+    parseExtensionMemberContract(
+      member,
+      `${config.packageName} extension contract members[${index}]`,
+    ),
+  );
+  if (
+    JSON.stringify(members.map(({ sqlName }) => sqlName)) !== JSON.stringify(config.expectedMembers)
+  ) {
+    throw new Error(
+      `${config.packageName} extension contract members must exactly match ${config.expectedMembers.join(', ')}`,
+    );
+  }
+  for (const member of members) {
+    const current = generatedExtensionBySqlName(member.sqlName);
+    if (
+      current === undefined ||
+      current.artifactProduct !== config.extension.artifactProduct ||
+      JSON.stringify(current.selectedExtensionDependencies) !== JSON.stringify(member.dependencies)
+    ) {
+      throw new Error(
+        `${config.packageName} extension contract member ${member.sqlName} is incompatible with the SDK dependency contract`,
+      );
+    }
+  }
+  return new Map(members.map((member) => [member.sqlName, member]));
+}
+
+async function resolveExtensionBundleMember(config: {
+  extension: GeneratedExtensionMetadata;
+  expectedMembers: readonly string[];
+  packageJson: ExtensionPackageMetadata;
+  packageRoot: string;
+  packageName: string;
+  target: string;
+  memberContracts: ReadonlyMap;
+}): Promise<{ runtimeDirectory: string; moduleDirectory?: string }> {
+  const pointer = config.packageJson.oliphaunt?.bundleManifest;
+  if (pointer !== 'bundle-manifest.json') {
+    throw new Error(
+      `${config.packageName} bundle target must declare oliphaunt.bundleManifest=bundle-manifest.json`,
+    );
+  }
+  const manifestPath = resolvePackageRelativePath(
+    config.packageRoot,
+    pointer,
+    `${config.packageName} bundle manifest metadata`,
+  );
+  await requireFile(manifestPath, `${config.packageName} bundle manifest`);
+  let parsedManifest: unknown;
+  try {
+    parsedManifest = JSON.parse(await readFile(manifestPath, 'utf8')) as unknown;
+  } catch (error) {
+    throw new Error(`${config.packageName} bundle manifest is not valid JSON`, {
+      cause: error,
+    });
+  }
+  if (
+    parsedManifest === null ||
+    typeof parsedManifest !== 'object' ||
+    Array.isArray(parsedManifest)
+  ) {
+    throw new Error(`${config.packageName} bundle manifest must be a JSON object`);
+  }
+  const manifest = parsedManifest as NpmExtensionBundleManifest;
+  if (manifest.schema === 'oliphaunt-extension-bundle-v1') {
+    throw new Error(
+      `${config.packageName} bundle manifest uses the physical carrier schema; expected oliphaunt-npm-extension-bundle-v1`,
+    );
+  }
+  if (manifest.schema !== 'oliphaunt-npm-extension-bundle-v1') {
+    throw new Error(`${config.packageName} bundle manifest has unsupported schema`);
+  }
+  const manifestFields = Object.keys(manifest).sort();
+  const expectedManifestFields = ['family', 'members', 'product', 'schema', 'target', 'version'];
+  if (JSON.stringify(manifestFields) !== JSON.stringify(expectedManifestFields)) {
+    throw new Error(
+      `${config.packageName} npm bundle manifest fields must be exactly ${expectedManifestFields.join(', ')}`,
+    );
+  }
+  if (manifest.product !== config.extension.artifactProduct) {
+    throw new Error(
+      `${config.packageName} bundle manifest does not declare ${config.extension.artifactProduct}`,
+    );
+  }
+  if (manifest.version !== config.packageJson.version) {
+    throw new Error(
+      `${config.packageName} bundle manifest version ${manifest.version ?? ''} does not match package version ${config.packageJson.version ?? ''}`,
+    );
+  }
+  if (manifest.family !== 'native' || manifest.target !== config.target) {
+    throw new Error(
+      `${config.packageName} bundle manifest must declare native target ${config.target}`,
+    );
+  }
+  if (!Array.isArray(manifest.members)) {
+    throw new Error(`${config.packageName} bundle manifest is missing members`);
+  }
+  const expectedRuntimeRelativePaths = Object.fromEntries(
+    config.expectedMembers.map((sqlName) => [sqlName, `extensions/${sqlName}/runtime`]),
+  );
+  const memberRuntimeRelativePaths = config.packageJson.oliphaunt?.memberRuntimeRelativePaths;
+  if (
+    memberRuntimeRelativePaths === undefined ||
+    memberRuntimeRelativePaths === null ||
+    typeof memberRuntimeRelativePaths !== 'object' ||
+    Array.isArray(memberRuntimeRelativePaths) ||
+    Object.values(memberRuntimeRelativePaths).some(
+      (value) => typeof value !== 'string' || value.length === 0,
+    ) ||
+    JSON.stringify(Object.keys(memberRuntimeRelativePaths).sort()) !==
+      JSON.stringify([...config.expectedMembers].sort()) ||
+    JSON.stringify(memberRuntimeRelativePaths) !== JSON.stringify(expectedRuntimeRelativePaths)
+  ) {
+    throw new Error(
+      `${config.packageName} bundle target must declare one runtime path for every exact member`,
+    );
+  }
+  const rawMemberModuleRelativePaths = config.packageJson.oliphaunt?.memberModuleRelativePaths;
+  const expectedMemberModuleRelativePaths = Object.fromEntries(
+    config.expectedMembers.flatMap((sqlName) =>
+      config.memberContracts.get(sqlName)?.nativeModuleStem === null
+        ? []
+        : [[sqlName, `extensions/${sqlName}/runtime/lib/modules`]],
+    ),
+  );
+  if (
+    rawMemberModuleRelativePaths === undefined
+      ? Object.keys(expectedMemberModuleRelativePaths).length !== 0
+      : rawMemberModuleRelativePaths === null ||
+        typeof rawMemberModuleRelativePaths !== 'object' ||
+        Array.isArray(rawMemberModuleRelativePaths) ||
+        Object.values(rawMemberModuleRelativePaths).some(
+          (value) => typeof value !== 'string' || value.length === 0,
+        ) ||
+        JSON.stringify(rawMemberModuleRelativePaths) !==
+          JSON.stringify(expectedMemberModuleRelativePaths)
+  ) {
+    throw new Error(`${config.packageName} bundle target has invalid member module paths`);
+  }
+  const memberModuleRelativePaths = rawMemberModuleRelativePaths ?? {};
+  const validatedMembers: NpmExtensionRuntimeBundleMember[] = [];
+  const canonicalMembers = new Set();
+  const memberPaths = new Set();
+  const memberArchivePaths = new Map();
+  for (const [index, rawMember] of manifest.members.entries()) {
+    if (rawMember === null || typeof rawMember !== 'object' || Array.isArray(rawMember)) {
+      throw new Error(`${config.packageName} bundle manifest members[${index}] must be an object`);
+    }
+    const member = rawMember as Record;
+    if (typeof member.sqlName !== 'string' || !/^[A-Za-z0-9._-]{1,128}$/.test(member.sqlName)) {
+      throw new Error(
+        `${config.packageName} bundle manifest members[${index}] has invalid sqlName`,
+      );
+    }
+    if (member.kind !== 'runtime') {
+      throw new Error(
+        `${config.packageName} bundle manifest member ${member.sqlName} must declare kind=runtime`,
+      );
+    }
+    if (!Object.hasOwn(member, 'identity') || member.identity !== null) {
+      throw new Error(
+        `${config.packageName} bundle manifest runtime member ${member.sqlName} must declare identity=null`,
+      );
+    }
+    if (
+      typeof member.path !== 'string' ||
+      !new RegExp(
+        `^extensions/${member.sqlName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}/[A-Za-z0-9][A-Za-z0-9._-]*\\.(?:tar\\.gz|tgz)$`,
+      ).test(member.path) ||
+      member.path !== member.path.normalize('NFC') ||
+      decodeURIComponent(member.path) !== member.path
+    ) {
+      throw new Error(
+        `${config.packageName} bundle manifest member ${member.sqlName} has invalid archive path`,
+      );
+    }
+    const archive = resolvePackageRelativePath(
+      config.packageRoot,
+      member.path,
+      `${config.packageName} bundle member ${member.sqlName}`,
+    );
+    await requireFile(archive, `${config.packageName} bundle member ${member.sqlName}`);
+    if (typeof member.sha256 !== 'string' || !/^[0-9a-f]{64}$/.test(member.sha256)) {
+      throw new Error(
+        `${config.packageName} bundle manifest member ${member.sqlName} has invalid sha256`,
+      );
+    }
+    if (
+      typeof member.bytes !== 'number' ||
+      !Number.isSafeInteger(member.bytes) ||
+      member.bytes <= 0
+    ) {
+      throw new Error(
+        `${config.packageName} bundle manifest member ${member.sqlName} has invalid bytes`,
+      );
+    }
+    const archiveIdentity = await fileSha256AndBytes(archive);
+    if (archiveIdentity.bytes !== member.bytes || archiveIdentity.sha256 !== member.sha256) {
+      throw new Error(
+        `${config.packageName} bundle member ${member.sqlName} does not match its exact bytes and sha256`,
+      );
+    }
+    if (
+      typeof member.runtimeRelativePath !== 'string' ||
+      member.runtimeRelativePath.length === 0 ||
+      member.runtimeRelativePath !== memberRuntimeRelativePaths[member.sqlName] ||
+      member.runtimeRelativePath !== `extensions/${member.sqlName}/runtime`
+    ) {
+      throw new Error(
+        `${config.packageName} bundle manifest member ${member.sqlName} runtime path disagrees with package metadata`,
+      );
+    }
+    const runtimeDirectory = resolvePackageRelativePath(
+      config.packageRoot,
+      member.runtimeRelativePath,
+      `${config.packageName} bundle member ${member.sqlName} runtime directory metadata`,
+    );
+    await requireDirectory(
+      runtimeDirectory,
+      `${config.packageName} bundle member ${member.sqlName} runtime directory`,
+    );
+    const memberContract = config.memberContracts.get(member.sqlName);
+    if (memberContract === undefined) {
+      throw new Error(
+        `${config.packageName} bundle member ${member.sqlName} has no frozen package contract`,
+      );
+    }
+    await requireExactExtensionRuntimeInventory({
+      contract: memberContract,
+      runtimeDirectory,
+      target: config.target,
+      source: `${config.packageName} bundle member ${member.sqlName} runtime directory`,
+    });
+    if (
+      member.moduleRelativePath !== undefined &&
+      (typeof member.moduleRelativePath !== 'string' || member.moduleRelativePath.length === 0)
+    ) {
+      throw new Error(
+        `${config.packageName} bundle manifest member ${member.sqlName} has invalid moduleRelativePath`,
+      );
+    }
+    if (member.moduleRelativePath !== memberModuleRelativePaths[member.sqlName]) {
+      throw new Error(
+        `${config.packageName} bundle manifest member ${member.sqlName} module path disagrees with package metadata`,
+      );
+    }
+    const expectedModuleRelativePath =
+      memberContract.nativeModuleStem === null
+        ? undefined
+        : `extensions/${member.sqlName}/runtime/lib/modules`;
+    if (member.moduleRelativePath !== expectedModuleRelativePath) {
+      throw new Error(
+        `${config.packageName} bundle manifest member ${member.sqlName} module path is not canonical`,
+      );
+    }
+    if (member.moduleRelativePath !== undefined) {
+      const moduleDirectory = resolvePackageRelativePath(
+        config.packageRoot,
+        member.moduleRelativePath,
+        `${config.packageName} bundle member ${member.sqlName} module directory metadata`,
+      );
+      await requireDirectory(
+        moduleDirectory,
+        `${config.packageName} bundle member ${member.sqlName} module directory`,
+      );
+    }
+    const expectedMemberFields = [
+      'bytes',
+      'identity',
+      'kind',
+      ...(member.moduleRelativePath === undefined ? [] : ['moduleRelativePath']),
+      'path',
+      'runtimeRelativePath',
+      'sha256',
+      'sqlName',
+    ].sort();
+    if (JSON.stringify(Object.keys(member).sort()) !== JSON.stringify(expectedMemberFields)) {
+      throw new Error(
+        `${config.packageName} bundle manifest member ${member.sqlName} has unexpected or missing fields`,
+      );
+    }
+    const canonicalMember = `${member.sqlName}\u0000${member.kind}\u0000${member.path}`;
+    if (canonicalMembers.has(canonicalMember) || memberPaths.has(member.path)) {
+      throw new Error(
+        `${config.packageName} bundle manifest repeats a canonical member or archive path`,
+      );
+    }
+    canonicalMembers.add(canonicalMember);
+    memberPaths.add(member.path);
+    memberArchivePaths.set(member.sqlName, archive);
+    validatedMembers.push({
+      sqlName: member.sqlName,
+      kind: 'runtime',
+      identity: null,
+      path: member.path,
+      sha256: member.sha256,
+      bytes: member.bytes,
+      runtimeRelativePath: member.runtimeRelativePath,
+      ...(member.moduleRelativePath === undefined
+        ? {}
+        : { moduleRelativePath: member.moduleRelativePath }),
+    });
+  }
+  const sqlNames = validatedMembers.map((member) => member.sqlName);
+  if (JSON.stringify(sqlNames) !== JSON.stringify(config.expectedMembers)) {
+    throw new Error(
+      `${config.packageName} bundle manifest members must exactly match ${config.expectedMembers.join(', ')}`,
+    );
+  }
+  const member = validatedMembers.find(
+    (candidate) => candidate.sqlName === config.extension.sqlName,
+  );
+  if (member === undefined) {
+    throw new Error(
+      `${config.packageName} bundle manifest is missing selected member ${config.extension.sqlName}`,
+    );
+  }
+  const archive = memberArchivePaths.get(config.extension.sqlName);
+  if (archive === undefined) {
+    throw new Error(
+      `${config.packageName} bundle manifest did not resolve selected member ${config.extension.sqlName}`,
+    );
+  }
+
+  const runtimeRelativePath = member.runtimeRelativePath;
+  const runtimeDirectory = resolvePackageRelativePath(
+    config.packageRoot,
+    runtimeRelativePath,
+    `${config.packageName} bundle member ${config.extension.sqlName} runtime directory metadata`,
+  );
+  const moduleRelativePath = member.moduleRelativePath;
+  const moduleDirectory =
+    moduleRelativePath === undefined
+      ? undefined
+      : resolvePackageRelativePath(
+          config.packageRoot,
+          moduleRelativePath,
+          `${config.packageName} bundle member ${config.extension.sqlName} module directory metadata`,
+        );
+  return { runtimeDirectory, moduleDirectory };
+}
+
+function extensionRuntimeSqlFileOwned(
+  extension: NpmExtensionMemberContract,
+  fileName: string,
+): boolean {
+  return (
+    (extension.createsExtension && fileName === `${extension.sqlName}.control`) ||
+    (extension.createsExtension && fileName === `${extension.sqlName}.sql`) ||
+    (extension.createsExtension &&
+      fileName.startsWith(`${extension.sqlName}--`) &&
+      fileName.endsWith('.sql')) ||
+    extension.extensionSqlFileNames.includes(fileName) ||
+    (fileName.endsWith('.sql') &&
+      extension.extensionSqlFilePrefixes.some((prefix) => fileName.startsWith(prefix)))
+  );
+}
+
+function isCanonicalExtensionInstallSql(fileName: string, sqlName: string): boolean {
+  if (fileName === `${sqlName}.sql`) return true;
+  const prefix = `${sqlName}--`;
+  if (!fileName.startsWith(prefix) || !fileName.endsWith('.sql')) return false;
+  const version = fileName.slice(prefix.length, -'.sql'.length);
+  return /^[0-9][A-Za-z0-9._-]*$/u.test(version) && !version.includes('--');
+}
+
+async function exactRuntimeLeafPaths(root: string, source: string): Promise {
+  const rows: string[] = [];
+  const collisionPaths = new Map();
+  let totalBytes = 0;
+  const visit = async (current: string, relativePath: string): Promise => {
+    if (relativePath !== '') {
+      if (
+        relativePath.includes('\\') ||
+        relativePath !== relativePath.normalize('NFC') ||
+        // biome-ignore lint/suspicious/noControlCharactersInRegex: Control characters make archive paths unsafe.
+        /[\u0000-\u001f\u007f]/u.test(relativePath)
+      ) {
+        throw new Error(`${source} contains a noncanonical runtime path ${relativePath}`);
+      }
+      const collisionKey = relativePath.toLowerCase();
+      const collision = collisionPaths.get(collisionKey);
+      if (collision !== undefined && collision !== relativePath) {
+        throw new Error(
+          `${source} contains case/NFC-colliding paths ${collision} and ${relativePath}`,
+        );
+      }
+      collisionPaths.set(collisionKey, relativePath);
+    }
+    const metadata = await lstat(current);
+    if (metadata.isSymbolicLink()) {
+      throw new Error(`${source} contains symbolic link ${relativePath || '.'}`);
+    }
+    if (metadata.isDirectory()) {
+      const entries = (await readdir(current)).sort();
+      for (const entry of entries) {
+        await visit(join(current, entry), relativePath === '' ? entry : `${relativePath}/${entry}`);
+      }
+      return;
+    }
+    if (!metadata.isFile()) {
+      throw new Error(`${source} contains unsupported filesystem entry ${relativePath}`);
+    }
+    if (metadata.size > MAX_EXTENSION_RUNTIME_FILE_BYTES) {
+      throw new Error(`${source} runtime file ${relativePath} exceeds the bounded member size`);
+    }
+    totalBytes += metadata.size;
+    if (totalBytes > MAX_EXTENSION_RUNTIME_BYTES) {
+      throw new Error(`${source} exceeds the bounded expanded runtime size`);
+    }
+    rows.push(relativePath);
+    if (rows.length > MAX_EXTENSION_RUNTIME_FILES) {
+      throw new Error(`${source} contains too many runtime files`);
+    }
+  };
+  await visit(root, '');
+  return rows;
+}
+
+async function requireExactExtensionRuntimeInventory(config: {
+  contract: NpmExtensionMemberContract;
+  runtimeDirectory: string;
+  target: string;
+  source: string;
+}): Promise {
+  const files = await exactRuntimeLeafPaths(config.runtimeDirectory, config.source);
+  const dataFiles = new Set(config.contract.dataFiles.map((file) => `share/postgresql/${file}`));
+  const licenseFiles = new Map(config.contract.licenseFiles.map((file) => [file.path, file]));
+  const moduleFile =
+    config.contract.nativeModuleStem === null
+      ? undefined
+      : `lib/postgresql/${config.contract.nativeModuleStem}${nativeModuleSuffixForTarget(config.target)}`;
+  const embeddedModuleFile =
+    config.contract.nativeModuleStem === null
+      ? undefined
+      : `lib/modules/${config.contract.nativeModuleStem}${nativeModuleSuffixForTarget(config.target)}`;
+  let hasControl = false;
+  let hasSql = false;
+  for (const file of files) {
+    const extensionPrefix = 'share/postgresql/extension/';
+    if (file.startsWith(extensionPrefix)) {
+      const fileName = file.slice(extensionPrefix.length);
+      if (fileName.includes('/') || !extensionRuntimeSqlFileOwned(config.contract, fileName)) {
+        throw new Error(`${config.source} contains undeclared extension SQL/control file ${file}`);
+      }
+      if (fileName === `${config.contract.sqlName}.control`) hasControl = true;
+      if (isCanonicalExtensionInstallSql(fileName, config.contract.sqlName)) hasSql = true;
+      continue;
+    }
+    if (
+      dataFiles.has(file) ||
+      licenseFiles.has(file) ||
+      file === moduleFile ||
+      file === embeddedModuleFile
+    ) {
+      continue;
+    }
+    throw new Error(`${config.source} contains undeclared runtime file ${file}`);
+  }
+  const missingDataFiles = [...dataFiles].filter((file) => !files.includes(file));
+  if (missingDataFiles.length > 0) {
+    throw new Error(
+      `${config.source} is missing declared data file(s): ${missingDataFiles.join(', ')}`,
+    );
+  }
+  const missingLicenseFiles = [...licenseFiles.keys()].filter((file) => !files.includes(file));
+  if (missingLicenseFiles.length > 0) {
+    throw new Error(
+      `${config.source} is missing declared license file(s): ${missingLicenseFiles.join(', ')}`,
+    );
+  }
+  for (const licenseFile of licenseFiles.values()) {
+    const licensePath = resolvePackageRelativePath(
+      config.runtimeDirectory,
+      licenseFile.path,
+      `${config.source} declared license file`,
+    );
+    const metadata = await lstat(licensePath);
+    const observedMode = metadata.mode & 0o7777;
+    if (
+      (platform() === 'win32' && (observedMode & 0o111) !== 0) ||
+      (platform() !== 'win32' &&
+        // Package managers may recreate 0644 archive files as 0664 under umask
+        // 0002. Integrity is checked below; execution, special bits and public
+        // write access are never valid installed license representations.
+        ((observedMode & 0o7113) !== 0 || (observedMode & 0o400) === 0))
+    ) {
+      throw new Error(
+        `${config.source} license file ${licenseFile.path} mode is not a safe installed representation of declared ${licenseFile.mode}`,
+      );
+    }
+    const identity = await fileSha256AndBytes(licensePath);
+    if (identity.sha256 !== licenseFile.sha256) {
+      throw new Error(
+        `${config.source} license file ${licenseFile.path} does not match declared SHA-256 ${licenseFile.sha256}`,
+      );
+    }
+  }
+  if (moduleFile !== undefined && !files.includes(moduleFile)) {
+    throw new Error(`${config.source} is missing declared native module ${moduleFile}`);
+  }
+  if (embeddedModuleFile !== undefined && !files.includes(embeddedModuleFile)) {
+    throw new Error(
+      `${config.source} is missing declared embedded native module ${embeddedModuleFile}`,
+    );
+  }
+  if (config.contract.createsExtension && (!hasControl || !hasSql)) {
+    throw new Error(
+      `${config.source} must contain ${config.contract.sqlName}.control and canonical base installation SQL`,
+    );
+  }
+}
+
+async function resolvePackageNativeInstall(
+  target: NativePackageTarget,
+  expectedVersion: string,
+): Promise {
+  const packageJsonPath = resolvePackageJson(target.packageName);
+  const packageRoot = dirname(packageJsonPath);
+  const packageJson = JSON.parse(
+    await readFile(packageJsonPath, 'utf8'),
+  ) as LiboliphauntPackageMetadata;
+  if (packageJson.name !== target.packageName) {
+    throw new Error(
+      `${target.packageName} package metadata has name ${packageJson.name ?? ''}`,
+    );
+  }
+  if (packageJson.version !== expectedVersion) {
+    throw new Error(
+      `${target.packageName} version ${packageJson.version ?? ''} does not match @oliphaunt/ts liboliphauntVersion ${expectedVersion}`,
+    );
+  }
+  if (packageJson.oliphaunt?.target !== target.id) {
+    throw new Error(`${target.packageName} package metadata does not target ${target.id}`);
+  }
+  const libraryPath = resolvePackageRelativePath(
+    packageRoot,
+    packageJson.oliphaunt?.libraryRelativePath ?? target.libraryRelativePath,
+    `${target.packageName} liboliphaunt library metadata`,
+  );
+  await requireFile(libraryPath, `${target.packageName} liboliphaunt library`);
+  const runtimeDirectory = resolvePackageRelativePath(
+    packageRoot,
+    packageJson.oliphaunt?.runtimeRelativePath ?? target.runtimeRelativePath,
+    `${target.packageName} runtime directory metadata`,
+  );
+  await requireDirectory(runtimeDirectory, `${target.packageName} runtime directory`);
+  for (const tool of nativeRuntimeToolsForTarget(target.id)) {
+    await requireFile(
+      join(runtimeDirectory, 'bin', tool),
+      `${target.packageName} runtime tool bin/${tool}`,
+    );
+  }
+  return { libraryPath, runtimeDirectory, catalogProfile: 'standard', packageManaged: true };
+}
+
+async function publishRuntimeCache(
+  root: string,
+  manifest: string,
+  build: (stageRoot: string) => Promise,
+): Promise {
+  const marker = join(root, 'manifest.json');
+  if ((await optionalRead(marker)) === manifest) {
+    return;
+  }
+  await mkdir(dirname(root), { recursive: true });
+  await withRuntimeCacheLock(root, async () => {
+    if ((await optionalRead(marker)) === manifest) {
+      return;
+    }
+    const unique = `${process.pid}-${randomUUID()}`;
+    const stageRoot = `${root}.build-${unique}`;
+    const oldRoot = `${root}.old-${unique}`;
+    await rm(stageRoot, { force: true, recursive: true });
+    await rm(oldRoot, { force: true, recursive: true });
+    let movedExistingRoot = false;
+    let publishedRoot = false;
+    try {
+      await mkdir(stageRoot, { recursive: true });
+      await build(stageRoot);
+      await writeFile(join(stageRoot, 'manifest.json'), manifest, 'utf8');
+      await syncRuntimeDirectoryTree(stageRoot);
+      try {
+        await rename(root, oldRoot);
+        movedExistingRoot = true;
+      } catch (error) {
+        if (!isErrorCode(error, 'ENOENT')) {
+          throw error;
+        }
+      }
+      try {
+        await rename(stageRoot, root);
+        publishedRoot = true;
+      } catch (error) {
+        if (movedExistingRoot) {
+          await rename(oldRoot, root).catch(() => undefined);
+          movedExistingRoot = false;
+        }
+        throw error;
+      }
+      await syncDirectory(dirname(root));
+      if (movedExistingRoot) {
+        await rm(oldRoot, { force: true, recursive: true }).catch(() => undefined);
+      }
+    } catch (error) {
+      await rm(stageRoot, { force: true, recursive: true });
+      if (!publishedRoot) {
+        await rm(oldRoot, { force: true, recursive: true });
+      }
+      throw error;
+    }
+  });
+}
+
+async function withRuntimeCacheLock(root: string, callback: () => Promise): Promise {
+  const lock = `${root}.lock`;
+  const deadline = Date.now() + CACHE_LOCK_TIMEOUT_MS;
+  while (true) {
+    try {
+      await mkdir(lock);
+      break;
+    } catch (error) {
+      if (!isErrorCode(error, 'EEXIST')) {
+        throw error;
+      }
+      if (await runtimeCacheLockIsStale(lock)) {
+        await rm(lock, { force: true, recursive: true });
+        continue;
+      }
+      if (Date.now() >= deadline) {
+        throw new Error(`timed out waiting for Oliphaunt runtime cache lock: ${lock}`);
+      }
+      await delay(CACHE_LOCK_POLL_MS);
+    }
+  }
+
+  try {
+    return await callback();
+  } finally {
+    await rm(lock, { force: true, recursive: true });
+  }
+}
+
+async function runtimeCacheLockIsStale(lock: string): Promise {
+  try {
+    const metadata = await stat(lock);
+    return Date.now() - metadata.mtimeMs > CACHE_LOCK_STALE_MS;
+  } catch {
+    return true;
+  }
+}
+
+function resolvePackageJson(packageName: string): string {
+  try {
+    return require.resolve(`${packageName}/package.json`);
+  } catch (error) {
+    throw new Error(
+      `${packageName} is not installed; reinstall @oliphaunt/ts with optional dependencies enabled`,
+      { cause: error },
+    );
+  }
+}
+
+async function resolveExtensionTargetPackageJson(
+  extension: GeneratedExtensionMetadata,
+  targetPackageName: string,
+  target: string,
+): Promise<{ packageJsonPath: string; ownerVersion: string }> {
+  const packageName = extension.npmPackage;
+  const expectedMembers = extensionOwnerMembers(extension);
+  const isBundle = expectedMembers.length > 1;
+  const packageJsonPath = optionalResolvePackageJson(packageName);
+  if (packageJsonPath === undefined) {
+    if (isBundle) {
+      throw new Error(
+        `${packageName} is not installed; add it to the application dependencies for CREATE EXTENSION support`,
+      );
+    }
+    const targetPath = resolveExtensionPackageJson(targetPackageName, packageName);
+    const targetMetadata = JSON.parse(
+      await readFile(targetPath, 'utf8'),
+    ) as ExtensionPackageMetadata;
+    if (typeof targetMetadata.version !== 'string' || targetMetadata.version.length === 0) {
+      throw new Error(`${targetPackageName} package metadata is missing version`);
+    }
+    return {
+      packageJsonPath: targetPath,
+      ownerVersion: targetMetadata.version,
+    };
+  }
+
+  const packageJson = JSON.parse(
+    await readFile(packageJsonPath, 'utf8'),
+  ) as ExtensionPackageMetadata;
+  if (packageJson.name !== packageName) {
+    throw new Error(`${packageName} package metadata has name ${packageJson.name ?? ''}`);
+  }
+  const expectedKind = isBundle ? 'exact-extension-bundle' : 'exact-extension';
+  if (packageJson.oliphaunt?.kind !== expectedKind) {
+    throw new Error(`${packageName} package metadata does not declare ${expectedKind}`);
+  }
+  if (packageJson.oliphaunt?.product !== extension.artifactProduct) {
+    throw new Error(
+      `${packageName} package metadata does not declare ${extension.artifactProduct}`,
+    );
+  }
+  requireExtensionPackageMembers(packageJson, expectedMembers, packageName);
+  if (typeof packageJson.version !== 'string' || packageJson.version.length === 0) {
+    throw new Error(`${packageName} package metadata is missing version`);
+  }
+  const resolvedTargetPackageName =
+    packageJson.oliphaunt.targetPackageNames?.[target] ?? targetPackageName;
+  if (resolvedTargetPackageName !== targetPackageName) {
+    throw new Error(
+      `${packageName} target package for ${target} must be ${targetPackageName}, got ${resolvedTargetPackageName}`,
+    );
+  }
+  try {
+    return {
+      packageJsonPath: createRequire(packageJsonPath).resolve(
+        `${resolvedTargetPackageName}/package.json`,
+      ),
+      ownerVersion: packageJson.version,
+    };
+  } catch (error) {
+    throw new Error(
+      `${resolvedTargetPackageName} is not installed; reinstall ${packageName} with optional dependencies enabled`,
+      { cause: error },
+    );
+  }
+}
+
+function resolveExtensionPackageJson(packageName: string, installPackageName: string): string {
+  try {
+    return require.resolve(`${packageName}/package.json`);
+  } catch (error) {
+    throw new Error(
+      `${installPackageName} is not installed; add it to the application dependencies for CREATE EXTENSION support`,
+      { cause: error },
+    );
+  }
+}
+
+function optionalResolvePackageJson(packageName: string): string | undefined {
+  try {
+    return require.resolve(`${packageName}/package.json`);
+  } catch {
+    return undefined;
+  }
+}
+
+export function resolvePackageRelativePath(
+  packageRoot: string,
+  metadataPath: string,
+  source: string,
+): string {
+  const relativePath = safePackageRelativePath(metadataPath, source);
+  const root = resolve(packageRoot);
+  const resolved = resolve(root, relativePath);
+  const fromRoot = relative(root, resolved);
+  if (fromRoot.startsWith('..') || isAbsolute(fromRoot)) {
+    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
+  }
+  return resolved;
+}
+
+function safePackageRelativePath(metadataPath: string, source: string): string {
+  if (metadataPath.length === 0) {
+    throw new Error(`${source} contains unsafe package metadata path: `);
+  }
+  if (metadataPath.includes('\0')) {
+    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
+  }
+  let decoded: string;
+  try {
+    decoded = decodeURIComponent(metadataPath);
+  } catch {
+    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
+  }
+  const normalized = decoded.replaceAll('\\', '/');
+  if (
+    normalized.startsWith('/') ||
+    /^[A-Za-z][A-Za-z0-9+.-]*:/.test(normalized) ||
+    normalized.split('/').includes('..')
+  ) {
+    throw new Error(`${source} contains unsafe package metadata path: ${metadataPath}`);
+  }
+  return normalized;
+}
+
+async function requireFile(path: string, source: string): Promise {
+  try {
+    const metadata = await lstat(path);
+    if (metadata.isFile() && !metadata.isSymbolicLink()) {
+      return;
+    }
+  } catch {}
+  throw new Error(`${source} does not point to an existing file: ${path}`);
+}
+
+async function fileSha256AndBytes(path: string): Promise<{ sha256: string; bytes: number }> {
+  const digest = createHash('sha256');
+  let bytes = 0;
+  for await (const chunk of createReadStream(path)) {
+    const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
+    bytes += buffer.byteLength;
+    digest.update(buffer);
+  }
+  return { sha256: digest.digest('hex'), bytes };
+}
+
+async function requireDirectory(path: string, source: string): Promise {
+  try {
+    const metadata = await lstat(path);
+    if (metadata.isDirectory() && !metadata.isSymbolicLink()) {
+      return;
+    }
+  } catch {}
+  throw new Error(`${source} does not point to an existing directory: ${path}`);
+}
+
+async function isDirectory(path: string): Promise {
+  try {
+    return (await stat(path)).isDirectory();
+  } catch {
+    return false;
+  }
+}
+
+async function optionalRead(path: string): Promise {
+  try {
+    return await readFile(path, 'utf8');
+  } catch {
+    return undefined;
+  }
+}
+
+function isErrorCode(error: unknown, code: string): boolean {
+  return typeof error === 'object' && error !== null && 'code' in error && error.code === code;
+}
+
+function extensionTargetPackageName(extension: GeneratedExtensionMetadata, target: string): string {
+  return `${extension.npmPackage}-${target}`;
+}
+
+function nativeModuleDirectoryCandidates(libraryPath: string): string[] {
+  const libraryDir = dirname(libraryPath);
+  return [join(libraryDir, 'modules'), join(dirname(libraryDir), 'lib', 'modules')];
+}
+
+function nativeRuntimeToolsForTarget(target: string): string[] {
+  return target === 'windows-x64-msvc'
+    ? ['initdb.exe', 'pg_ctl.exe', 'postgres.exe']
+    : ['initdb', 'pg_ctl', 'postgres'];
+}
+
+function runtimeCacheKey(value: unknown): string {
+  return createHash('sha256').update(JSON.stringify(value)).digest('hex').slice(0, 32);
+}
+
+const runtimeFileHost: RuntimeFileHost = {
+  join,
+  async readDir(path: string) {
+    return (await readdir(path, { withFileTypes: true })).map((entry) => ({
+      name: entry.name,
+      isFile: entry.isFile(),
+    }));
+  },
+  async isDirectory(path: string) {
+    return isDirectory(path);
+  },
+  async isFile(path: string) {
+    try {
+      return (await stat(path)).isFile();
+    } catch {
+      return false;
+    }
+  },
+};
diff --git a/src/sdks/ts/sdk/src/native/cluster-seed.ts b/src/sdks/ts/sdk/src/native/cluster-seed.ts
new file mode 100644
index 000000000..406f898a3
--- /dev/null
+++ b/src/sdks/ts/sdk/src/native/cluster-seed.ts
@@ -0,0 +1,199 @@
+import { createHash } from 'node:crypto';
+import { createReadStream } from 'node:fs';
+import { lstat, readdir, readFile } from 'node:fs/promises';
+import { dirname, join, relative, resolve } from 'node:path';
+import type { NativeResourceDirectory } from '../types.js';
+
+export type NativeCatalogProfile = 'standard' | 'icu';
+
+/** Hash the actual selected immutable files, including unexpected or missing files. */
+async function resourceTreeSha256(root: string): Promise {
+  const paths: string[] = [];
+  let totalBytes = 0;
+  const walk = async (directory: string): Promise => {
+    const metadata = await lstat(directory);
+    if (!metadata.isDirectory() || metadata.isSymbolicLink())
+      throw new Error(`resource must be a real directory: ${directory}`);
+    for (const entry of await readdir(directory, { withFileTypes: true })) {
+      const path = join(directory, entry.name);
+      if (entry.isSymbolicLink()) throw new Error(`resource must not contain symlinks: ${path}`);
+      if (entry.isDirectory()) await walk(path);
+      else if (entry.isFile()) paths.push(path);
+      else throw new Error(`resource contains a special file: ${path}`);
+      if (paths.length > 8192) throw new Error('resource has too many files');
+    }
+  };
+  await walk(root);
+  paths.sort((left, right) =>
+    Buffer.compare(
+      Buffer.from(relative(root, left).replaceAll('\\', '/')),
+      Buffer.from(relative(root, right).replaceAll('\\', '/')),
+    ),
+  );
+  const hash = createHash('sha256');
+  for (const path of paths) {
+    const metadata = await lstat(path);
+    if (!metadata.isFile() || metadata.isSymbolicLink())
+      throw new Error(`resource file changed during validation: ${path}`);
+    totalBytes += metadata.size;
+    if (totalBytes > 1024 * 1024 * 1024) throw new Error('resource exceeds the 1 GiB limit');
+    hash.update(relative(root, path).replaceAll('\\', '/'));
+    hash.update(Buffer.of(0));
+    hash.update(String(metadata.size));
+    hash.update(Buffer.of(0));
+    for await (const chunk of createReadStream(path)) hash.update(chunk);
+    hash.update('\n');
+  }
+  return hash.digest('hex');
+}
+
+export async function validateSelectedIcuData(resource: NativeResourceDirectory): Promise {
+  const expected = validateNativeIcuDataReceipt(
+    await readFile(resource.manifestPath, 'utf8'),
+    resource.manifestPath,
+  );
+  const actual = await resourceTreeSha256(resource.directory);
+  if (actual !== expected) throw new Error('selected ICU data does not match its manifest');
+  return actual;
+}
+
+export async function validateSelectedNativeSeed(
+  resource: NativeResourceDirectory,
+  target: string,
+  runtimeVersion: string,
+  icuDataTreeSha256?: string,
+): Promise<{ catalogProfile: NativeCatalogProfile; emptyDirectories: string[] }> {
+  const manifest = JSON.parse(await readFile(resource.manifestPath, 'utf8'));
+  const profile = manifest.catalogProfile;
+  if (
+    manifest.schema !== 'oliphaunt-cluster-seed-v1' ||
+    !['standard', 'icu'].includes(profile) ||
+    manifest.artifactRole !== `cluster-seed-${profile}`
+  )
+    throw new Error('selected native seed has an invalid resource manifest');
+  const runtime = manifest.runtime;
+  if (
+    runtime?.product !== 'liboliphaunt-native' ||
+    runtime.engineFamily !== 'native' ||
+    runtime.version !== runtimeVersion ||
+    runtime.target !== target ||
+    runtime.postgresMajor !== 18 ||
+    runtime.physicalFormat !== 'native-pg18-v1' ||
+    runtime.compatibilityKey !== `native-pg18-${target}-v1`
+  )
+    throw new Error(
+      `selected seed is incompatible with native runtime ${runtimeVersion} for ${target}`,
+    );
+  if (profile === 'icu') {
+    if (
+      !icuDataTreeSha256 ||
+      manifest.icu?.dataVersion !== '76.1' ||
+      manifest.icu?.dataForm !== 'files-le' ||
+      manifest.icu?.dataTreeSha256 !== icuDataTreeSha256
+    )
+      throw new Error('selected ICU seed requires its matching explicit ICU data');
+  } else if (manifest.icu !== null || icuDataTreeSha256 !== undefined)
+    throw new Error('standard seed cannot initialize an ICU catalog');
+  const payload = manifest.directory;
+  if (
+    typeof payload?.path !== 'string' ||
+    !SHA256.test(payload.treeSha256 ?? '') ||
+    resolve(dirname(resource.manifestPath), payload.path) !== resolve(resource.directory)
+  )
+    throw new Error('selected seed directory does not match its manifest');
+  if ((await resourceTreeSha256(resource.directory)) !== payload.treeSha256)
+    throw new Error('selected native seed directory is corrupted');
+  if ((await readFile(join(resource.directory, 'PG_VERSION'), 'utf8')).trim() !== '18')
+    throw new Error('selected native seed has the wrong PostgreSQL major version');
+  const control = await lstat(join(resource.directory, 'global/pg_control'));
+  if (!control.isFile() || control.isSymbolicLink() || control.size === 0)
+    throw new Error('selected native seed is missing pg_control');
+  const emptyDirectories = payload.emptyDirectories;
+  if (
+    !Array.isArray(emptyDirectories) ||
+    emptyDirectories.length > 8192 ||
+    new Set(emptyDirectories).size !== emptyDirectories.length
+  )
+    throw new Error('selected seed has an invalid empty-directory inventory');
+  for (const path of emptyDirectories) {
+    if (
+      typeof path !== 'string' ||
+      !path ||
+      path.includes('\\') ||
+      path
+        .split('/')
+        .some(
+          (part) =>
+            !part || part === '.' || part === '..' || part.includes(':') || part.includes('\0'),
+        )
+    )
+      throw new Error('selected seed has an unsafe empty-directory path');
+    let parent = resource.directory;
+    for (const part of path.split('/')) {
+      parent = join(parent, part);
+      const metadata = await lstat(parent).catch((error) => {
+        if (error?.code === 'ENOENT') return undefined;
+        throw error;
+      });
+      if (metadata && (!metadata.isDirectory() || metadata.isSymbolicLink()))
+        throw new Error('seed empty-directory path overlaps a file or link');
+    }
+  }
+  return { catalogProfile: profile, emptyDirectories };
+}
+
+const SHA256 = /^[0-9a-f]{64}$/u;
+const ICU_DATA_FIELDS = [
+  'schema',
+  'artifactRole',
+  'icuDataVersion',
+  'icuDataForm',
+  'icuDataTreeSha256',
+] as const;
+function parseProperties(manifest: string, source: string): Map {
+  const fields = new Map();
+  for (const line of manifest.split(/\r?\n/u)) {
+    if (line.length === 0) continue;
+    const separator = line.indexOf('=');
+    if (separator <= 0) {
+      throw new Error(`${source} manifest contains a malformed property`);
+    }
+    const key = line.slice(0, separator);
+    if (fields.has(key)) {
+      throw new Error(`${source} manifest repeats property ${key}`);
+    }
+    fields.set(key, line.slice(separator + 1));
+  }
+  return fields;
+}
+
+function requireExactFields(
+  fields: ReadonlyMap,
+  expected: ReadonlyArray,
+  source: string,
+): void {
+  if (fields.size !== expected.length || expected.some((key) => !fields.has(key))) {
+    throw new Error(`${source} manifest fields must be exactly ${expected.join(',')}`);
+  }
+}
+
+export function requireIcuDataTreeSha256(value: string | undefined, source: string): string {
+  if (value === undefined || !SHA256.test(value)) {
+    throw new Error(`${source} does not declare canonical ICU data identity`);
+  }
+  return value;
+}
+
+export function validateNativeIcuDataReceipt(manifest: string, source: string): string {
+  const fields = parseProperties(manifest, source);
+  requireExactFields(fields, ICU_DATA_FIELDS, source);
+  if (
+    fields.get('schema') !== 'oliphaunt-icu-data-v1' ||
+    fields.get('artifactRole') !== 'icu-data' ||
+    fields.get('icuDataVersion') !== '76.1' ||
+    fields.get('icuDataForm') !== 'files-le'
+  ) {
+    throw new Error(`${source} manifest does not declare canonical ICU data`);
+  }
+  return requireIcuDataTreeSha256(fields.get('icuDataTreeSha256'), source);
+}
diff --git a/src/sdks/js/src/native/common.ts b/src/sdks/ts/sdk/src/native/common.ts
similarity index 80%
rename from src/sdks/js/src/native/common.ts
rename to src/sdks/ts/sdk/src/native/common.ts
index 9b25c5e3f..4fc3414c4 100644
--- a/src/sdks/js/src/native/common.ts
+++ b/src/sdks/ts/sdk/src/native/common.ts
@@ -1,4 +1,4 @@
-export const ABI_VERSION = 10;
+export const ABI_VERSION = 11;
 export const LIBOLIPHAUNT_RUNTIME_DIR_ENV = 'OLIPHAUNT_RUNTIME_DIR';
 export const OLIPHAUNT_ICU_DATA_DIR_ENV = 'OLIPHAUNT_ICU_DATA_DIR';
 export const ICU_DATA_ENV = 'ICU_DATA';
@@ -48,31 +48,6 @@ export function resolveExplicitRuntimeDirectory(): string | undefined {
   return resolved;
 }
 
-export function applyNativeIcuDataEnvironment(icuDataDirectory?: string): void {
-  if (icuDataDirectory === undefined || icuDataDirectory.trim().length === 0) {
-    return;
-  }
-  if (icuDataDirectory.includes('\0')) {
-    throw new Error(`${OLIPHAUNT_ICU_DATA_DIR_ENV} must not contain NUL bytes`);
-  }
-  setRuntimeEnvironment(OLIPHAUNT_ICU_DATA_DIR_ENV, icuDataDirectory);
-  setRuntimeEnvironment(ICU_DATA_ENV, icuDataDirectory);
-}
-
-/** Replace ambient ICU selection with one exact resolved runtime closure. */
-export function replaceNativeIcuDataEnvironment(icuDataDirectory?: string): void {
-  if (icuDataDirectory === undefined) {
-    unsetRuntimeEnvironment(OLIPHAUNT_ICU_DATA_DIR_ENV);
-    unsetRuntimeEnvironment(ICU_DATA_ENV);
-    return;
-  }
-  if (icuDataDirectory.trim().length === 0 || icuDataDirectory.includes('\0')) {
-    throw new Error(`${OLIPHAUNT_ICU_DATA_DIR_ENV} must be a nonempty path without NUL bytes`);
-  }
-  setRuntimeEnvironment(OLIPHAUNT_ICU_DATA_DIR_ENV, icuDataDirectory);
-  setRuntimeEnvironment(ICU_DATA_ENV, icuDataDirectory);
-}
-
 export function nativeRuntimeLibraryEnvironment(
   runtimeDirectory?: string,
   platformName: string = runtimePlatform(),
@@ -195,24 +170,6 @@ function setRuntimeEnvironment(name: string, value: string): void {
   }
 }
 
-function unsetRuntimeEnvironment(name: string): void {
-  const processEnv = globalThis.process?.env;
-  if (processEnv !== undefined) {
-    delete processEnv[name];
-    return;
-  }
-  const deno = (globalThis as { Deno?: { env?: { delete(name: string): void } } }).Deno;
-  if (deno?.env?.delete === undefined) return;
-  try {
-    deno.env.delete(name);
-  } catch (error) {
-    throw new Error(
-      `cannot clear ${name}; grant environment-write permission for native runtime data`,
-      { cause: error },
-    );
-  }
-}
-
 function normalizePlatform(platform: string): string {
   switch (platform) {
     case 'darwin':
diff --git a/src/sdks/ts/sdk/src/native/default.ts b/src/sdks/ts/sdk/src/native/default.ts
new file mode 100644
index 000000000..9d131fb67
--- /dev/null
+++ b/src/sdks/ts/sdk/src/native/default.ts
@@ -0,0 +1,17 @@
+import type { NativeBinding, NativeBindingOptions } from './types.js';
+
+export async function createDefaultNativeBinding(
+  options: NativeBindingOptions = {},
+): Promise {
+  if (
+    typeof (globalThis as { Deno?: { version?: { deno?: string } } }).Deno?.version?.deno ===
+    'string'
+  ) {
+    // Deno 2.8.1 skips native cleanup when terminating a Worker executing JS
+    // (even without a stream). Retire FFI after the blocked-worker proof passes.
+    const { createDenoNativeBinding } = await import('./deno.js');
+    return createDenoNativeBinding(options);
+  }
+  const { createNodeNativeBinding } = await import('./node.js');
+  return createNodeNativeBinding(options);
+}
diff --git a/src/sdks/js/src/native/deno.ts b/src/sdks/ts/sdk/src/native/deno.ts
similarity index 88%
rename from src/sdks/js/src/native/deno.ts
rename to src/sdks/ts/sdk/src/native/deno.ts
index e5838d6a2..0f869dce7 100644
--- a/src/sdks/js/src/native/deno.ts
+++ b/src/sdks/ts/sdk/src/native/deno.ts
@@ -1,17 +1,6 @@
-import {
-  applyNativeIcuDataEnvironment,
-  applyNativeRuntimeLibraryEnvironment,
-  errorMessage,
-  replaceNativeIcuDataEnvironment,
-} from './common.js';
-import { resolveDenoNativeInstall, validatePreparedDenoRuntimeExtensions } from './assets-deno.js';
 import { dirname, join } from 'node:path';
-import {
-  copyNativeClusterSeed,
-  initializeNativePgdata,
-  nativeInitdbArgs,
-  nativePostgresChildEnvironment,
-} from './initialize.js';
+import { prepareExtensionInstall, resolveNativeInstall, selectNativeResources } from './assets.js';
+import { applyNativeRuntimeLibraryEnvironment, errorMessage } from './common.js';
 import {
   errorCaptureBuffer,
   packConfigPointers,
@@ -22,14 +11,20 @@ import {
   responseBuffer,
 } from './ffi-layout.js';
 import {
-  NativeDetachOutcomeUnknownError,
+  copyNativeClusterSeed,
+  initializeNativePgdata,
+  nativeInitdbArgs,
+  nativePostgresChildEnvironment,
+} from './initialize.js';
+import { resolveExactNativeRuntimeProfile } from './runtime-profile.js';
+import {
   type NativeBinding,
   type NativeBindingOptions,
+  NativeDetachOutcomeUnknownError,
   type NativeHandle,
   type NativeOpenConfig,
   type NativeRestoreOptions,
 } from './types.js';
-import { resolveExactNativeRuntimeProfile } from './runtime-profile.js';
 
 type DenoPointer = object | null;
 const OLIPHAUNT_STREAM_CALLBACK_ABORTED = 1;
@@ -60,8 +55,7 @@ export async function createDenoNativeBinding(
   options: NativeBindingOptions = {},
 ): Promise {
   const deno = denoGlobal();
-  const install = await resolveDenoNativeInstall(options.libraryPath);
-  applyNativeIcuDataEnvironment(install.icuDataDirectory);
+  const install = await resolveNativeInstall(options.libraryPath);
   applyNativeRuntimeLibraryEnvironment(install.runtimeDirectory);
   const dylib = deno.dlopen(install.libraryPath, {
     oliphaunt_init_with_error: {
@@ -143,48 +137,32 @@ export async function createDenoNativeBinding(
 
   return {
     async open(config: NativeOpenConfig): Promise {
+      const selectedInstall = await selectNativeResources(install, config, dirname(config.pgdata));
       assertDenoDirectAdmissionOpen();
       const explicitRuntimeDirectory =
-        config.runtimeDirectory !== undefined || install.packageManaged === false;
+        config.runtimeDirectory !== undefined || selectedInstall.packageManaged === false;
       let openConfig = {
         ...config,
-        runtimeDirectory: config.runtimeDirectory ?? install.runtimeDirectory,
+        runtimeDirectory: config.runtimeDirectory ?? selectedInstall.runtimeDirectory,
       };
-      let moduleDirectory: string | undefined;
-      if (
-        openConfig.extensions.length > 0 &&
-        (openConfig.runtimeDirectory === undefined ||
-          (install.packageManaged && openConfig.runtimeDirectory === install.runtimeDirectory))
-      ) {
-        throw new Error(
-          `Deno direct execution does not automatically materialize extension packages; pass runtimeDirectory with the selected extension assets or use Node/Bun direct execution. Selected extensions: ${openConfig.extensions.join(', ')}`,
-        );
-      }
-      if (openConfig.extensions.length > 0) {
-        const validated = await validatePreparedDenoRuntimeExtensions({
-          deno,
-          runtimeDirectory: openConfig.runtimeDirectory,
-          extensions: openConfig.extensions,
-          source: 'Deno direct explicit runtimeDirectory',
-        });
-        openConfig = {
-          ...openConfig,
-          runtimeDirectory: validated.runtimeDirectory,
-        };
-        // Keep canonical lib/postgresql subprocess-owned during initdb. The
-        // separate lib/modules $libdir is carried in the native config.
-        moduleDirectory = validated.moduleDirectory;
-        applyNativeRuntimeLibraryEnvironment(validated.runtimeDirectory);
-      }
+      const prepared = await prepareExtensionInstall(
+        { ...selectedInstall, runtimeDirectory: openConfig.runtimeDirectory },
+        openConfig.extensions,
+        { explicitRuntimeDirectory },
+      );
+      openConfig = { ...openConfig, runtimeDirectory: prepared.runtimeDirectory };
+      const moduleDirectory = prepared.moduleDirectory;
+      applyNativeRuntimeLibraryEnvironment(prepared.runtimeDirectory);
       const runtimeProfile =
-        explicitRuntimeDirectory && openConfig.runtimeDirectory !== undefined
+        explicitRuntimeDirectory &&
+        config.icuData === undefined &&
+        openConfig.runtimeDirectory !== undefined
           ? await resolveExactNativeRuntimeProfile(openConfig.runtimeDirectory)
           : {
-              icuDataDirectory: install.icuDataDirectory,
-              catalogProfile: install.catalogProfile ?? ('standard' as const),
+              icuDataDirectory: selectedInstall.icuDataDirectory,
+              catalogProfile: selectedInstall.catalogProfile ?? ('standard' as const),
             };
       if (explicitRuntimeDirectory) {
-        replaceNativeIcuDataEnvironment(runtimeProfile.icuDataDirectory);
         applyNativeRuntimeLibraryEnvironment(openConfig.runtimeDirectory);
       }
       await prepareDenoPgdata(
@@ -192,12 +170,14 @@ export async function createDenoNativeBinding(
         openConfig.pgdata,
         openConfig.username,
         openConfig.runtimeDirectory,
-        config.runtimeDirectory === undefined ? install.clusterSeedDirectory : undefined,
+        selectedInstall.clusterSeedDirectory,
         runtimeProfile.icuDataDirectory,
         runtimeProfile.catalogProfile,
+        selectedInstall.clusterSeedEmptyDirectories,
       );
-      const packed = packConfigPointers({ ...openConfig, moduleDirectory }, (value) =>
-        pointerOf(deno, value),
+      const packed = packConfigPointers(
+        { ...openConfig, moduleDirectory, icuDataDirectory: runtimeProfile.icuDataDirectory },
+        (value) => pointerOf(deno, value),
       );
       const out = new Uint8Array(8);
       const captured = errorCaptureBuffer();
@@ -439,6 +419,7 @@ async function prepareDenoPgdata(
   clusterSeedDirectory?: string,
   icuDataDirectory?: string,
   catalogProfile: 'standard' | 'icu' = 'standard',
+  emptyDirectories: readonly string[] = [],
 ): Promise {
   await initializeNativePgdata({
     root: dirname(pgdata),
@@ -446,7 +427,7 @@ async function prepareDenoPgdata(
     username,
     populatePgdata: async (staging) => {
       if (clusterSeedDirectory !== undefined) {
-        await copyNativeClusterSeed(clusterSeedDirectory, staging);
+        await copyNativeClusterSeed(clusterSeedDirectory, staging, emptyDirectories);
         return;
       }
       if (runtimeDirectory === undefined || typeof deno.Command !== 'function') {
diff --git a/src/sdks/js/src/native/extension-contract.ts b/src/sdks/ts/sdk/src/native/extension-contract.ts
similarity index 100%
rename from src/sdks/js/src/native/extension-contract.ts
rename to src/sdks/ts/sdk/src/native/extension-contract.ts
diff --git a/src/sdks/js/src/native/extension-runtime.ts b/src/sdks/ts/sdk/src/native/extension-runtime.ts
similarity index 100%
rename from src/sdks/js/src/native/extension-runtime.ts
rename to src/sdks/ts/sdk/src/native/extension-runtime.ts
diff --git a/src/sdks/js/src/native/ffi-layout.ts b/src/sdks/ts/sdk/src/native/ffi-layout.ts
similarity index 93%
rename from src/sdks/js/src/native/ffi-layout.ts
rename to src/sdks/ts/sdk/src/native/ffi-layout.ts
index ffea656f3..1ca1db491 100644
--- a/src/sdks/js/src/native/ffi-layout.ts
+++ b/src/sdks/ts/sdk/src/native/ffi-layout.ts
@@ -2,7 +2,7 @@ import { ABI_VERSION } from './common.js';
 import type { NativeOpenConfig, NativeRestoreOptions } from './types.js';
 
 export const POINTER_SIZE = 8;
-export const OLIPHAUNT_CONFIG_SIZE = 72;
+export const OLIPHAUNT_CONFIG_SIZE = 80;
 export const OLIPHAUNT_RESPONSE_SIZE = 16;
 export const OLIPHAUNT_RESTORE_OPTIONS_SIZE = 32;
 export const OLIPHAUNT_ERROR_CAPTURE_CAPACITY = 1024;
@@ -32,12 +32,13 @@ export function packPointerArray(pointers: ReadonlyArray): Uint8Array {
 }
 
 export function packConfigPointers(
-  config: NativeOpenConfig & { moduleDirectory?: string },
+  config: NativeOpenConfig & { moduleDirectory?: string; icuDataDirectory?: string },
   pointerOf: PointerReader,
 ): { config: Uint8Array; keepAlive: Uint8Array[] } {
   const pgdata = cString(config.pgdata);
   const runtimeDirectory = config.runtimeDirectory ? cString(config.runtimeDirectory) : undefined;
   const moduleDirectory = config.moduleDirectory ? cString(config.moduleDirectory) : undefined;
+  const icuDataDirectory = config.icuDataDirectory ? cString(config.icuDataDirectory) : undefined;
   const username = cString(config.username);
   const database = cString(config.database);
   const startupStrings = config.startupArgs.map(cString);
@@ -54,6 +55,7 @@ export function packConfigPointers(
   view.setBigUint64(48, 0n, true);
   writePointer(view, 56, config.startupArgs.length > 0 ? pointerOf(startupPointerArray) : 0n);
   writeSize(view, 64, config.startupArgs.length);
+  writePointer(view, 72, icuDataDirectory ? pointerOf(icuDataDirectory) : 0n);
 
   return {
     config: out,
@@ -61,6 +63,7 @@ export function packConfigPointers(
       pgdata,
       ...(runtimeDirectory ? [runtimeDirectory] : []),
       ...(moduleDirectory ? [moduleDirectory] : []),
+      ...(icuDataDirectory ? [icuDataDirectory] : []),
       username,
       database,
       ...startupStrings,
diff --git a/src/sdks/js/src/native/filesystem-durability.ts b/src/sdks/ts/sdk/src/native/filesystem-durability.ts
similarity index 100%
rename from src/sdks/js/src/native/filesystem-durability.ts
rename to src/sdks/ts/sdk/src/native/filesystem-durability.ts
diff --git a/src/sdks/js/src/native/initialize.ts b/src/sdks/ts/sdk/src/native/initialize.ts
similarity index 88%
rename from src/sdks/js/src/native/initialize.ts
rename to src/sdks/ts/sdk/src/native/initialize.ts
index 7e2092120..925851adf 100644
--- a/src/sdks/js/src/native/initialize.ts
+++ b/src/sdks/ts/sdk/src/native/initialize.ts
@@ -1,5 +1,5 @@
 import { randomUUID } from 'node:crypto';
-import { cp, lstat, readFile, rename, rm, writeFile } from 'node:fs/promises';
+import { chmod, cp, lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
 import { platform } from 'node:os';
 import { basename, dirname, join } from 'node:path';
 
@@ -119,11 +119,22 @@ export function nativePostgresChildEnvironment(
 export async function copyNativeClusterSeed(
   clusterSeedDirectory: string,
   stagingPgdata: string,
+  emptyDirectories: readonly string[] = [],
 ): Promise {
-  await cp(join(clusterSeedDirectory, 'files'), stagingPgdata, {
+  await cp(clusterSeedDirectory, stagingPgdata, {
     errorOnExist: true,
     recursive: true,
+    filter: async (source) => {
+      const stat = await lstat(source);
+      if (!stat.isFile() && !stat.isDirectory()) {
+        throw new Error(`cluster seed contains unsupported entry: ${source}`);
+      }
+      return true;
+    },
   });
+  for (const path of emptyDirectories)
+    await mkdir(join(stagingPgdata, path), { recursive: true, mode: 0o700 });
+  if (platform() !== 'win32') await chmod(stagingPgdata, 0o700);
   await normalizeNativeClusterSeedForHost(stagingPgdata);
 }
 
diff --git a/src/sdks/js/src/native/node-addon.ts b/src/sdks/ts/sdk/src/native/node-addon.ts
similarity index 99%
rename from src/sdks/js/src/native/node-addon.ts
rename to src/sdks/ts/sdk/src/native/node-addon.ts
index 0069ffcf8..7b004dfde 100644
--- a/src/sdks/js/src/native/node-addon.ts
+++ b/src/sdks/ts/sdk/src/native/node-addon.ts
@@ -27,6 +27,7 @@ export type NodeDirectAddon = {
 export type NodeDirectOpenConfig = NativeOpenConfig & {
   libraryPath: string;
   moduleDirectory?: string;
+  icuDataDirectory?: string;
 };
 
 export type NodeDirectRestoreOptions = {
diff --git a/src/sdks/ts/sdk/src/native/node.ts b/src/sdks/ts/sdk/src/native/node.ts
new file mode 100644
index 000000000..bd68bb774
--- /dev/null
+++ b/src/sdks/ts/sdk/src/native/node.ts
@@ -0,0 +1,189 @@
+import { spawn } from 'node:child_process';
+import { dirname, join } from 'node:path';
+import { prepareExtensionInstall, resolveNativeInstall, selectNativeResources } from './assets.js';
+import { applyNativeRuntimeLibraryEnvironment } from './common.js';
+import {
+  copyNativeClusterSeed,
+  initializeNativePgdata,
+  nativeInitdbArgs,
+  nativePostgresChildEnvironment,
+} from './initialize.js';
+import { loadNodeDirectAddon } from './node-addon.js';
+import { resolveExactNativeRuntimeProfile } from './runtime-profile.js';
+import type {
+  NativeBinding,
+  NativeBindingOptions,
+  NativeHandle,
+  NativeOpenConfig,
+  NativeRestoreOptions,
+} from './types.js';
+
+export async function createNodeNativeBinding(
+  options: NativeBindingOptions = {},
+): Promise {
+  const install = await resolveNativeInstall(options.libraryPath);
+  applyNativeRuntimeLibraryEnvironment(install.runtimeDirectory);
+  const addon = await loadNodeDirectAddon(options.nodeAddonPath);
+  const forgottenHandles = new FinalizationRegistry<{
+    readonly recoveryToken: unknown;
+    readonly releaseOwnership: () => void;
+  }>(({ recoveryToken, releaseOwnership }) => {
+    try {
+      // The addon only marks this exact logical generation for recovery. The
+      // actual PostgreSQL detach remains on the next open's async worker.
+      if (addon.queueForgottenHandleRecovery(recoveryToken)) {
+        releaseOwnership();
+      }
+    } catch {
+      // Finalizer failures are unobservable. Keep the JavaScript admission
+      // lease closed if native recovery could not be queued safely.
+    }
+  });
+
+  return {
+    async open(config: NativeOpenConfig): Promise {
+      const selectedInstall = await selectNativeResources(install, config, dirname(config.pgdata));
+      const explicitRuntimeDirectory =
+        config.runtimeDirectory !== undefined || selectedInstall.packageManaged === false;
+      let extensionInstall = await prepareExtensionInstall(
+        {
+          ...selectedInstall,
+          runtimeDirectory: config.runtimeDirectory ?? selectedInstall.runtimeDirectory,
+          clusterSeedDirectory: selectedInstall.clusterSeedDirectory,
+        },
+        config.extensions,
+        {
+          explicitRuntimeDirectory,
+        },
+      );
+      if (
+        explicitRuntimeDirectory &&
+        config.icuData === undefined &&
+        extensionInstall.runtimeDirectory !== undefined
+      ) {
+        extensionInstall = {
+          ...extensionInstall,
+          ...(await resolveExactNativeRuntimeProfile(extensionInstall.runtimeDirectory)),
+        };
+      }
+      applyNativeRuntimeLibraryEnvironment(extensionInstall.runtimeDirectory);
+      await prepareNodePgdata(
+        config.pgdata,
+        config.username,
+        extensionInstall.runtimeDirectory,
+        extensionInstall.clusterSeedDirectory,
+        extensionInstall.icuDataDirectory,
+        extensionInstall.catalogProfile,
+        extensionInstall.clusterSeedEmptyDirectories,
+      );
+      return await addon.open({
+        ...config,
+        libraryPath: extensionInstall.libraryPath,
+        runtimeDirectory: extensionInstall.runtimeDirectory,
+        moduleDirectory: extensionInstall.moduleDirectory,
+        icuDataDirectory: extensionInstall.icuDataDirectory,
+      });
+    },
+    async execProtocolRaw(handle: NativeHandle, request: Uint8Array): Promise {
+      return toUint8Array(await addon.execProtocolRaw(handle, request));
+    },
+    async execProtocolStream(
+      handle: NativeHandle,
+      request: Uint8Array,
+      onChunk: (chunk: Uint8Array) => void,
+    ): Promise {
+      await addon.execProtocolRawStream(handle, request, onChunk);
+    },
+    async execSimpleQuery(handle: NativeHandle, sql: string): Promise {
+      return toUint8Array(await addon.execSimpleQuery(handle, sql));
+    },
+    async backup(handle: NativeHandle): Promise {
+      return toUint8Array(await addon.backup(handle));
+    },
+    async restore(options: NativeRestoreOptions): Promise {
+      await addon.restore({
+        libraryPath: install.libraryPath,
+        destination: options.destination,
+        bytes: options.bytes,
+      });
+    },
+    async cancel(handle: NativeHandle): Promise {
+      addon.cancel(handle);
+    },
+    async detach(handle: NativeHandle): Promise {
+      await addon.detach(handle);
+    },
+    registerForgottenHandleCleanup(
+      owner: object,
+      handle: NativeHandle,
+      releaseOwnership: () => void,
+    ): void {
+      forgottenHandles.register(
+        owner,
+        Object.freeze({
+          recoveryToken: addon.createForgottenHandleRecoveryToken(handle),
+          releaseOwnership,
+        }),
+        owner,
+      );
+    },
+    unregisterForgottenHandleCleanup(owner: object): void {
+      forgottenHandles.unregister(owner);
+    },
+  };
+}
+
+async function prepareNodePgdata(
+  pgdata: string,
+  username: string,
+  runtimeDirectory?: string,
+  clusterSeedDirectory?: string,
+  icuDataDirectory?: string,
+  catalogProfile: 'standard' | 'icu' = 'standard',
+  emptyDirectories: readonly string[] = [],
+): Promise {
+  await initializeNativePgdata({
+    root: dirname(pgdata),
+    pgdata,
+    username,
+    populatePgdata: (staging) => {
+      if (clusterSeedDirectory !== undefined) {
+        return copyNativeClusterSeed(clusterSeedDirectory, staging, emptyDirectories);
+      }
+      if (runtimeDirectory === undefined) {
+        throw new Error('initializing a native database requires runtimeDirectory with initdb');
+      }
+      const executable = join(
+        runtimeDirectory,
+        'bin',
+        process.platform === 'win32' ? 'initdb.exe' : 'initdb',
+      );
+      return new Promise((resolve, reject) => {
+        const env = nativePostgresChildEnvironment(process.env, {
+          icuDataDirectory,
+          initdbCatalogProfile: catalogProfile,
+        });
+        const child = spawn(executable, nativeInitdbArgs(staging), {
+          env,
+          stdio: ['ignore', 'ignore', 'pipe'],
+        });
+        const errors: Buffer[] = [];
+        child.stderr.on('data', (chunk: Buffer) => errors.push(chunk));
+        child.once('error', reject);
+        child.once('exit', (code) =>
+          code === 0
+            ? resolve()
+            : reject(
+                new Error(
+                  `initdb failed with exit code ${code ?? 'unknown'}: ${Buffer.concat(errors).toString('utf8').trim()}`,
+                ),
+              ),
+        );
+      });
+    },
+  });
+}
+
+function toUint8Array(value: Uint8Array | ArrayBuffer): Uint8Array {
+  return value instanceof Uint8Array ? value : new Uint8Array(value);
+}
diff --git a/src/sdks/js/src/native/runtime-profile.ts b/src/sdks/ts/sdk/src/native/runtime-profile.ts
similarity index 100%
rename from src/sdks/js/src/native/runtime-profile.ts
rename to src/sdks/ts/sdk/src/native/runtime-profile.ts
diff --git a/src/sdks/js/src/native/tar.ts b/src/sdks/ts/sdk/src/native/tar.ts
similarity index 100%
rename from src/sdks/js/src/native/tar.ts
rename to src/sdks/ts/sdk/src/native/tar.ts
diff --git a/src/sdks/ts/sdk/src/native/types.ts b/src/sdks/ts/sdk/src/native/types.ts
new file mode 100644
index 000000000..e20479f13
--- /dev/null
+++ b/src/sdks/ts/sdk/src/native/types.ts
@@ -0,0 +1,62 @@
+export type NativeBindingOptions = {
+  libraryPath?: string;
+  nodeAddonPath?: string;
+};
+
+export type NativeOpenConfig = {
+  pgdata: string;
+  runtimeDirectory?: string;
+  seed?: import('../types.js').NativeResourceDirectory;
+  icuData?: import('../types.js').NativeResourceDirectory;
+  username: string;
+  database: string;
+  extensions: string[];
+  startupArgs: string[];
+};
+
+export type NativeRestoreOptions = {
+  destination: string;
+  bytes: Uint8Array;
+};
+
+export type NativeHandle = unknown;
+
+/** @internal The adapter cannot prove whether a logical detach took effect. */
+export class NativeDetachOutcomeUnknownError extends Error {
+  constructor(message: string, options?: ErrorOptions) {
+    super(message, options);
+    this.name = 'NativeDetachOutcomeUnknownError';
+  }
+}
+
+export type NativeBinding = {
+  open(config: NativeOpenConfig): Promise;
+  execProtocolRaw(handle: NativeHandle, request: Uint8Array): Promise;
+  execProtocolStream(
+    handle: NativeHandle,
+    request: Uint8Array,
+    onChunk: (chunk: Uint8Array) => void,
+  ): Promise;
+  execSimpleQuery?(handle: NativeHandle, sql: string): Promise;
+  backup(handle: NativeHandle): Promise;
+  restore(options: NativeRestoreOptions): Promise;
+  cancel(handle: NativeHandle): Promise;
+  /**
+   * Deactivate the logical handle. An ordinary rejection guarantees that
+   * deactivation did not occur and the same handle remains valid for a later
+   * retry. NativeDetachOutcomeUnknownError is terminal. A handle that is
+   * already terminally unavailable is a successful detach.
+   */
+  detach(handle: NativeHandle): Promise;
+  /**
+   * Register a public owner for best-effort cleanup when that owner becomes
+   * unreachable. Native adapters omit this unless they can make stale cleanup
+   * ownership-safe and keep native teardown off the JavaScript thread.
+   */
+  registerForgottenHandleCleanup?(
+    owner: object,
+    handle: NativeHandle,
+    releaseOwnership: () => void,
+  ): void;
+  unregisterForgottenHandleCleanup?(owner: object): void;
+};
diff --git a/src/sdks/js/src/native/zip.ts b/src/sdks/ts/sdk/src/native/zip.ts
similarity index 100%
rename from src/sdks/js/src/native/zip.ts
rename to src/sdks/ts/sdk/src/native/zip.ts
diff --git a/src/sdks/ts/sdk/src/protocol.ts b/src/sdks/ts/sdk/src/protocol.ts
new file mode 100644
index 000000000..0fdfe840b
--- /dev/null
+++ b/src/sdks/ts/sdk/src/protocol.ts
@@ -0,0 +1 @@
+export * from '@oliphaunt/ts-query/protocol';
diff --git a/src/sdks/ts/sdk/src/query.ts b/src/sdks/ts/sdk/src/query.ts
new file mode 100644
index 000000000..d4b53542b
--- /dev/null
+++ b/src/sdks/ts/sdk/src/query.ts
@@ -0,0 +1 @@
+export * from '@oliphaunt/ts-query/query';
diff --git a/src/sdks/js/src/root-descriptor.ts b/src/sdks/ts/sdk/src/root-descriptor.ts
similarity index 100%
rename from src/sdks/js/src/root-descriptor.ts
rename to src/sdks/ts/sdk/src/root-descriptor.ts
diff --git a/src/sdks/js/src/runtime/broker-frames.ts b/src/sdks/ts/sdk/src/runtime/broker-frames.ts
similarity index 75%
rename from src/sdks/js/src/runtime/broker-frames.ts
rename to src/sdks/ts/sdk/src/runtime/broker-frames.ts
index 2ed918e07..b8d578777 100644
--- a/src/sdks/js/src/runtime/broker-frames.ts
+++ b/src/sdks/ts/sdk/src/runtime/broker-frames.ts
@@ -6,18 +6,12 @@ const MAX_FRAME_LEN = 128 * 1024 * 1024;
 
 export type BrokerRequestFrame =
   | { kind: 'authenticate'; token: string }
-  | { kind: 'execProtocol'; bytes: Uint8Array }
-  | { kind: 'execProtocolStream'; bytes: Uint8Array }
-  | { kind: 'execSimpleQuery'; sql: string }
   | { kind: 'close' }
-  | { kind: 'backup' }
-  | { kind: 'cancel' };
+  | { kind: 'backup' };
 
 export type BrokerResponseFrame =
   | { kind: 'ok'; bytes: Uint8Array }
-  | { kind: 'chunk'; bytes: Uint8Array }
-  | { kind: 'error'; message: string }
-  | { kind: 'streamCallbackAborted'; message: string };
+  | { kind: 'error'; message: string };
 
 export async function writeBrokerRequest(
   stream: ByteStream,
@@ -47,18 +41,10 @@ export function encodeBrokerRequest(frame: BrokerRequestFrame): Uint8Array {
   switch (frame.kind) {
     case 'authenticate':
       return encodeFrame(6, encodeUtf8(frame.token));
-    case 'execProtocol':
-      return encodeFrame(1, frame.bytes);
-    case 'execProtocolStream':
-      return encodeFrame(4, frame.bytes);
-    case 'execSimpleQuery':
-      return encodeFrame(8, encodeUtf8(frame.sql));
     case 'close':
       return encodeFrame(3, emptyPayload);
     case 'backup':
       return encodeFrame(5, emptyPayload);
-    case 'cancel':
-      return encodeFrame(7, emptyPayload);
   }
 }
 
@@ -66,12 +52,8 @@ export function encodeBrokerResponse(frame: BrokerResponseFrame): Uint8Array {
   switch (frame.kind) {
     case 'ok':
       return encodeFrame(101, frame.bytes);
-    case 'chunk':
-      return encodeFrame(103, frame.bytes);
     case 'error':
       return encodeFrame(102, encodeUtf8(frame.message));
-    case 'streamCallbackAborted':
-      return encodeFrame(104, encodeUtf8(frame.message));
   }
 }
 
@@ -82,24 +64,12 @@ export function decodeBrokerRequest(kind: number, payload: Uint8Array): BrokerRe
         kind: 'authenticate',
         token: decodeUtf8(payload, 'broker auth frame'),
       };
-    case 1:
-      return { kind: 'execProtocol', bytes: payload };
-    case 4:
-      return { kind: 'execProtocolStream', bytes: payload };
-    case 8:
-      return {
-        kind: 'execSimpleQuery',
-        sql: decodeUtf8(payload, 'broker simple-query frame'),
-      };
     case 3:
       assertEmptyPayload(payload);
       return { kind: 'close' };
     case 5:
       assertEmptyPayload(payload);
       return { kind: 'backup' };
-    case 7:
-      assertEmptyPayload(payload);
-      return { kind: 'cancel' };
     default:
       throw new Error(`unknown broker request frame ${kind}`);
   }
@@ -114,13 +84,6 @@ export function decodeBrokerResponse(kind: number, payload: Uint8Array): BrokerR
         kind: 'error',
         message: decodeUtf8(payload, 'broker error frame'),
       };
-    case 103:
-      return { kind: 'chunk', bytes: payload };
-    case 104:
-      return {
-        kind: 'streamCallbackAborted',
-        message: decodeUtf8(payload, 'broker stream callback-aborted frame'),
-      };
     default:
       throw new Error(`unknown broker response frame ${kind}`);
   }
diff --git a/src/sdks/ts/sdk/src/runtime/broker.ts b/src/sdks/ts/sdk/src/runtime/broker.ts
new file mode 100644
index 000000000..a7be0bc01
--- /dev/null
+++ b/src/sdks/ts/sdk/src/runtime/broker.ts
@@ -0,0 +1,847 @@
+import { readFile, stat } from 'node:fs/promises';
+import { createRequire } from 'node:module';
+import { arch, platform } from 'node:os';
+import { dirname, join, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+import type { NormalizedOpenConfig } from '../config.js';
+import { simpleQuery } from '../protocol.js';
+import {
+  envVar,
+  ICU_DATA_ENV,
+  LIBOLIPHAUNT_RUNTIME_DIR_ENV,
+  nativeRuntimeLibraryEnvironment,
+  OLIPHAUNT_EMBEDDED_MODULE_DIR_ENV,
+  OLIPHAUNT_ICU_DATA_DIR_ENV,
+} from '../native/common.js';
+import { resolveExactNativeRuntimeProfile } from '../native/runtime-profile.js';
+import {
+  type BrokerResponseFrame,
+  readBrokerResponse,
+  writeBrokerRequest,
+} from './broker-frames.js';
+import type { ByteStream } from './byte-stream.js';
+import { PostgresWireClient } from './pgwire.js';
+import { throwCollectedCloseFailures } from './close.js';
+import { createForgottenRuntimeHandleCleanup } from './forgotten-handle.js';
+import {
+  cleanupFailedManagedLaunch,
+  connectEndpoint,
+  createTempDir,
+  type FailedManagedLaunch,
+  type ManagedChild,
+  parseReadyEndpoint,
+  randomHexToken,
+  readReadyLine,
+  removeTree,
+  spawnManagedChild,
+  unixSocketPathsFit,
+  waitForManagedChild,
+} from './node-adapter.js';
+import type { RuntimeBinding, RuntimeHandle } from './types.js';
+
+const READY_PREFIX = 'OLIPHAUNT_BROKER_READY ';
+const ERROR_PREFIX = 'OLIPHAUNT_BROKER_ERROR ';
+const LIBOLIPHAUNT_PATH_ENV = 'LIBOLIPHAUNT_PATH';
+const OLIPHAUNT_INSTALL_DIR_ENV = 'OLIPHAUNT_INSTALL_DIR';
+const OLIPHAUNT_BROKER_ENV = 'OLIPHAUNT_BROKER';
+const OLIPHAUNT_BROKER_STARTUP_TIMEOUT_MS_ENV = 'OLIPHAUNT_BROKER_STARTUP_TIMEOUT_MS';
+const DEFAULT_STARTUP_TIMEOUT_MS = 60_000;
+const SHUTDOWN_TIMEOUT_MS = 5_000;
+const require = createRequire(import.meta.url);
+
+export type BrokerRuntimeBindingOptions = {
+  executable?: string;
+};
+
+export function createBrokerRuntimeBinding(
+  options: BrokerRuntimeBindingOptions = {},
+): RuntimeBinding {
+  const forgottenHandles = createForgottenRuntimeHandleCleanup((handle) =>
+    handle.detach(),
+  );
+  return {
+    async open(config: NormalizedOpenConfig): Promise {
+      return openBrokerHandle(config.brokerExecutable ?? options.executable, config);
+    },
+    execProtocolRaw(handle: RuntimeHandle, request: Uint8Array): Promise {
+      return asBrokerHandle(handle).execProtocolRaw(request);
+    },
+    execProtocolStream(
+      handle: RuntimeHandle,
+      request: Uint8Array,
+      onChunk: (chunk: Uint8Array) => void,
+    ): Promise {
+      return asBrokerHandle(handle).execProtocolStream(request, onChunk);
+    },
+    execSimpleQuery(handle: RuntimeHandle, sql: string): Promise {
+      return asBrokerHandle(handle).execProtocolRaw(simpleQuery(sql));
+    },
+    backup(handle: RuntimeHandle): Promise {
+      return asBrokerHandle(handle).requestOk({ kind: 'backup' });
+    },
+    cancel(handle: RuntimeHandle): Promise {
+      return asBrokerHandle(handle).cancel();
+    },
+    async close(handle: RuntimeHandle) {
+      try {
+        await asBrokerHandle(handle).detach();
+        return { state: 'closed' };
+      } catch (error) {
+        // BrokerHandle.detach() crosses its destructive cutoff before any
+        // fallible teardown. The public owner must be retired even when later
+        // process or filesystem cleanup reports an error.
+        return { state: 'terminal', error };
+      }
+    },
+    registerForgottenHandleCleanup(
+      owner: object,
+      handle: RuntimeHandle,
+      _releaseOwnership: () => void,
+    ): void {
+      forgottenHandles.register(owner, asBrokerHandle(handle));
+    },
+    unregisterForgottenHandleCleanup(owner: object): void {
+      forgottenHandles.unregister(owner);
+    },
+  };
+}
+
+/** @internal Runtime-owned handle; exported only for package-internal contract tests. */
+export class BrokerHandle {
+  #child: ManagedChild | undefined;
+  #stream: ByteStream | undefined;
+  #client: PostgresWireClient | undefined;
+  #ipcDir: string | undefined;
+  #temporaryInstanceDirectory: string | undefined;
+  #failed = false;
+  #failure: unknown;
+  #closed = false;
+
+  constructor(
+    readonly config: NormalizedOpenConfig,
+    launch: BrokerLaunch,
+    private readonly shutdownTimeoutMs = SHUTDOWN_TIMEOUT_MS,
+  ) {
+    this.#child = launch.child;
+    this.#stream = launch.stream;
+    this.#client = launch.client;
+    this.#ipcDir = launch.ipcDir;
+    this.#temporaryInstanceDirectory = config.temporaryDirectory
+      ? config.instanceDirectory
+      : undefined;
+  }
+
+  async requestOk(frame: Parameters[1]): Promise {
+    const response = await this.request(frame);
+    switch (response.kind) {
+      case 'ok':
+        return response.bytes;
+      case 'error':
+        throw new Error(response.message);
+    }
+  }
+
+  async execProtocolRaw(request: Uint8Array): Promise {
+    const chunks: Uint8Array[] = [];
+    let size = 0;
+    await this.execProtocolStream(request, (chunk) => {
+      size += chunk.length;
+      if (size > 128 * 1024 * 1024) throw new Error('native broker response exceeds 128 MiB');
+      chunks.push(chunk);
+    });
+    const result = new Uint8Array(size);
+    let offset = 0;
+    for (const chunk of chunks) {
+      result.set(chunk, offset);
+      offset += chunk.length;
+    }
+    return result;
+  }
+
+  async execProtocolStream(
+    request: Uint8Array,
+    onChunk: (chunk: Uint8Array) => void,
+  ): Promise {
+    await this.ensureStream();
+    const client = this.#client;
+    if (!client) throw new Error('native broker SQL connection is unavailable');
+    let callbackFailed = false;
+    let callbackError: unknown;
+    try {
+      await client.execProtocolStream(request, (chunk) => {
+        if (!callbackFailed) {
+          try {
+            onChunk(chunk);
+          } catch (error) {
+            callbackFailed = true;
+            callbackError = error;
+          }
+        }
+      });
+    } catch (error) {
+      await this.markFailed(error);
+      throw error;
+    }
+    if (callbackFailed) throw callbackError;
+  }
+
+  async cancel(): Promise {
+    await this.ensureStream();
+    if (!this.#client) throw new Error('native broker SQL connection is unavailable');
+    await this.#client.cancel();
+  }
+
+  async detach(): Promise {
+    const firstAttempt = !this.#closed;
+    this.#closed = true;
+    const failures: unknown[] = [];
+    const client = this.#client;
+    if (client) {
+      try {
+        if (firstAttempt && !this.#failed) await client.terminate();
+        else await client.close();
+        this.#client = undefined;
+      } catch (error) {
+        failures.push(error);
+      }
+    }
+    const stream = this.#stream;
+    if (stream !== undefined) {
+      if (firstAttempt && !this.#failed) {
+        try {
+          await writeBrokerRequest(stream, { kind: 'close' });
+          const response = await readBrokerResponse(stream);
+          if (response.kind === 'error') {
+            throw new Error(`native broker close failed: ${response.message}`);
+          }
+        } catch (error) {
+          failures.push(error);
+        }
+      }
+      try {
+        await stream.close();
+        if (this.#stream === stream) {
+          this.#stream = undefined;
+        }
+      } catch (error) {
+        // Retain the exact stream so a later internal cleanup attempt can
+        // retry releasing it. Public close still memoizes this first terminal
+        // result and never presents the handle as usable again.
+        failures.push(error);
+      }
+    }
+    const child = this.#child;
+    if (child !== undefined) {
+      try {
+        let exited = await waitForManagedChild(child, this.shutdownTimeoutMs);
+        if (!exited) {
+          failures.push(new Error(`native broker did not stop within ${this.shutdownTimeoutMs}ms`));
+          child.kill('SIGKILL');
+          exited = await waitForManagedChild(child, this.shutdownTimeoutMs);
+          if (!exited) {
+            failures.push(
+              new Error(
+                `native broker was not reaped within ${this.shutdownTimeoutMs}ms after SIGKILL`,
+              ),
+            );
+          }
+        }
+        if (exited && this.#child === child) {
+          this.#child = undefined;
+        }
+      } catch (error) {
+        // An unconfirmed reap remains owned by this terminal handle. Never
+        // discard the only child handle merely because wait/kill failed.
+        failures.push(error);
+      }
+    }
+    // A process whose reap is unconfirmed may still have its IPC endpoint and
+    // PGDATA open. Never remove either tree underneath it; retain the exact
+    // paths until a later internal cleanup attempt confirms the reap.
+    if (this.#child === undefined) {
+      const ipcDir = this.#ipcDir;
+      try {
+        await removeTree(ipcDir);
+        if (this.#ipcDir === ipcDir) {
+          this.#ipcDir = undefined;
+        }
+      } catch (error) {
+        // Retain the path so later best-effort cleanup can retry it.
+        failures.push(error);
+      }
+      const temporaryInstanceDirectory = this.#temporaryInstanceDirectory;
+      if (temporaryInstanceDirectory !== undefined) {
+        try {
+          await removeTree(temporaryInstanceDirectory);
+          if (this.#temporaryInstanceDirectory === temporaryInstanceDirectory) {
+            this.#temporaryInstanceDirectory = undefined;
+          }
+        } catch (error) {
+          // Retain the managed-root cleanup identity after a failed removal.
+          failures.push(error);
+        }
+      }
+    }
+    if (
+      this.#stream !== undefined ||
+      this.#client !== undefined ||
+      this.#child !== undefined ||
+      this.#ipcDir !== undefined ||
+      this.#temporaryInstanceDirectory !== undefined
+    ) {
+      // Public close is terminal after the first destructive attempt, so no
+      // later facade call is available to own these uncertain resources. Keep
+      // the exact private handle alive through process exit instead of letting
+      // GC discard the only stream/child/path cleanup identity.
+      retainedFailedBrokerHandles.add(this);
+    } else {
+      retainedFailedBrokerHandles.delete(this);
+    }
+    throwCollectedCloseFailures(failures, 'native broker teardown failed');
+  }
+
+  async request(frame: Parameters[1]): Promise {
+    const stream = await this.ensureStream();
+    try {
+      await writeBrokerRequest(stream, frame);
+      return await readBrokerResponse(stream);
+    } catch (error) {
+      await this.markFailed(error);
+      throw error;
+    }
+  }
+
+  async ensureStream(): Promise {
+    if (this.#closed) {
+      throw new Error('native broker session is closed');
+    }
+    if (this.#failed) {
+      throw new Error(
+        'native broker helper failed; close and reopen the database before running more work',
+        { cause: this.#failure },
+      );
+    }
+    if (this.#stream === undefined) {
+      throw new Error(
+        'native broker stream is unavailable; close and reopen the database before running more work',
+      );
+    }
+    return this.#stream;
+  }
+
+  async markFailed(error: unknown): Promise {
+    if (!this.#failed) {
+      this.#failed = true;
+      this.#failure = error;
+    }
+    const client = this.#client;
+    try {
+      await client?.close();
+      if (this.#client === client) this.#client = undefined;
+    } catch {
+      /* Explicit close retains ownership of an unreleased SQL stream. */
+    }
+    const stream = this.#stream;
+    try {
+      await stream?.close();
+      if (this.#stream === stream) {
+        this.#stream = undefined;
+      }
+    } catch {
+      // Preserve the operation/transport failure that made session state
+      // unknown. Keep cleanup ownership so explicit close can retry it.
+    }
+    const child = this.#child;
+    if (child !== undefined) {
+      try {
+        child.kill('SIGKILL');
+        const reaped = await waitForManagedChild(child, this.shutdownTimeoutMs);
+        if (reaped && this.#child === child) {
+          this.#child = undefined;
+        }
+      } catch {
+        // Retain the child handle so explicit close can retry reaping it.
+      }
+    }
+    if (this.#child === undefined) {
+      const ipcDir = this.#ipcDir;
+      try {
+        await removeTree(ipcDir);
+        if (this.#ipcDir === ipcDir) {
+          this.#ipcDir = undefined;
+        }
+      } catch {
+        // Retain the path so explicit close retries filesystem cleanup.
+      }
+    }
+  }
+}
+
+// Intentionally process-lifetime ownership for resources whose destructive
+// cleanup did not complete. Entries are removed only if a package-internal
+// best-effort retry later releases every exact resource.
+const retainedFailedBrokerHandles = new Set();
+
+async function openBrokerHandle(
+  executable: string | undefined,
+  config: NormalizedOpenConfig,
+): Promise {
+  const authToken = randomHexToken();
+  const launch = await launchBroker(executable, config, authToken);
+  return new BrokerHandle(config, launch);
+}
+
+type BrokerLaunch = {
+  child: ManagedChild;
+  stream: ByteStream;
+  client: PostgresWireClient;
+  ipcDir?: string;
+};
+
+async function launchBroker(
+  executable: string | undefined,
+  config: NormalizedOpenConfig,
+  authToken: string,
+): Promise {
+  const failedLaunch: FailedManagedLaunch = {
+    paths: [undefined, config.temporaryDirectory ? config.instanceDirectory : undefined],
+  };
+  try {
+    const startupTimeoutMs = brokerStartupTimeoutMs();
+    const resolvedExecutable = await resolveBrokerExecutable(executable);
+    const endpoint = await allocateBrokerEndpoint(config);
+    failedLaunch.paths[0] = endpoint.ipcDir;
+    const nativeInstall = await resolveBrokerNativeInstall(config);
+    const child = spawnManagedChild({
+      executable: resolvedExecutable,
+      args: brokerSpawnArgs(config, endpoint),
+      env: brokerSpawnEnv(authToken, nativeInstall),
+      replaceEnv: true,
+    });
+    failedLaunch.child = child;
+    const readiness = new AbortController();
+    const line = await Promise.race([
+      readReadyLine(child.stdout, startupTimeoutMs, 'native broker', readiness.signal),
+      child.exited().then((code) => {
+        throw new Error(`native broker exited before readiness with code ${code ?? 'signal'}`);
+      }),
+    ]).finally(() => readiness.abort());
+    const ready = parseBrokerReadyLine(line);
+    const stream = await connectEndpoint(parseReadyEndpoint(ready.control));
+    failedLaunch.stream = stream;
+    await authenticateBroker(stream, authToken);
+    const client = await PostgresWireClient.connect(
+      parseReadyEndpoint(ready.primary),
+      config.username,
+      config.database,
+      startupTimeoutMs,
+      authToken,
+    );
+    return {
+      child,
+      stream,
+      client,
+      ipcDir: endpoint.ipcDir,
+    };
+  } catch (error) {
+    const cleanupFailures = await cleanupFailedManagedLaunch(
+      failedLaunch,
+      SHUTDOWN_TIMEOUT_MS,
+      'native broker startup child',
+    );
+    throwCollectedCloseFailures(
+      [error, ...cleanupFailures],
+      'native broker startup and cleanup failed',
+    );
+    throw error;
+  }
+}
+
+function brokerStartupTimeoutMs(): number {
+  return positiveIntegerEnvMs(OLIPHAUNT_BROKER_STARTUP_TIMEOUT_MS_ENV, DEFAULT_STARTUP_TIMEOUT_MS);
+}
+
+function positiveIntegerEnvMs(name: string, fallback: number): number {
+  const value = envVar(name);
+  if (value === undefined || value.length === 0) {
+    return fallback;
+  }
+  const parsed = Number.parseInt(value, 10);
+  if (!Number.isFinite(parsed) || parsed <= 0 || parsed.toString() !== value.trim()) {
+    throw new Error(`${name} must be a positive integer number of milliseconds`);
+  }
+  return parsed;
+}
+
+type BrokerNativeInstall = {
+  libraryPath: string;
+  runtimeDirectory?: string;
+  icuDataDirectory?: string;
+  catalogProfile: 'standard' | 'icu';
+  moduleDirectory?: string;
+};
+
+async function resolveBrokerNativeInstall(config: {
+  instanceDirectory: string;
+  libraryPath?: string;
+  runtimeDirectory?: string;
+  extensions?: readonly string[];
+  seed?: import('../types.js').NativeResourceDirectory;
+  icuData?: import('../types.js').NativeResourceDirectory;
+}): Promise {
+  const extensions = config.extensions ?? [];
+  const assets = await import('../native/assets.js');
+  const install = await assets.selectNativeResources(
+    await assets.resolveNativeInstall(config.libraryPath),
+    config,
+    config.instanceDirectory,
+  );
+  const explicitRuntimeDirectory =
+    config.runtimeDirectory !== undefined || install.packageManaged === false;
+  const resolved = {
+    libraryPath: install.libraryPath,
+    runtimeDirectory: config.runtimeDirectory ?? install.runtimeDirectory,
+    icuDataDirectory: install.icuDataDirectory,
+    catalogProfile: install.catalogProfile ?? ('standard' as const),
+  };
+  const prepared = await assets.prepareExtensionInstall(resolved, extensions, {
+    explicitRuntimeDirectory,
+  });
+  if (
+    !explicitRuntimeDirectory ||
+    config.icuData !== undefined ||
+    prepared.runtimeDirectory === undefined
+  ) {
+    return {
+      ...prepared,
+      catalogProfile: prepared.catalogProfile ?? 'standard',
+    };
+  }
+  return {
+    ...prepared,
+    ...(await resolveExactNativeRuntimeProfile(prepared.runtimeDirectory)),
+  };
+}
+
+function brokerSpawnEnv(
+  authToken: string,
+  nativeInstall: BrokerNativeInstall,
+): Record {
+  const env = Object.fromEntries(
+    Object.entries(process.env).filter(
+      (entry): entry is [string, string] => entry[1] !== undefined,
+    ),
+  );
+  delete env[OLIPHAUNT_ICU_DATA_DIR_ENV];
+  delete env[ICU_DATA_ENV];
+  return {
+    ...env,
+    OLIPHAUNT_BROKER_AUTH_TOKEN: authToken,
+    ...brokerNativeInstallEnv(nativeInstall),
+  };
+}
+
+function brokerNativeInstallEnv(nativeInstall: BrokerNativeInstall): Record {
+  const env: Record = {
+    [LIBOLIPHAUNT_PATH_ENV]: nativeInstall.libraryPath,
+  };
+  if (nativeInstall.runtimeDirectory !== undefined) {
+    env[OLIPHAUNT_INSTALL_DIR_ENV] = nativeInstall.runtimeDirectory;
+    env[LIBOLIPHAUNT_RUNTIME_DIR_ENV] = nativeInstall.runtimeDirectory;
+    Object.assign(env, nativeRuntimeLibraryEnvironment(nativeInstall.runtimeDirectory, platform()));
+  }
+  if (nativeInstall.icuDataDirectory !== undefined) {
+    env[OLIPHAUNT_ICU_DATA_DIR_ENV] = nativeInstall.icuDataDirectory;
+    env[ICU_DATA_ENV] = nativeInstall.icuDataDirectory;
+  }
+  if (nativeInstall.moduleDirectory !== undefined) {
+    env[OLIPHAUNT_EMBEDDED_MODULE_DIR_ENV] = nativeInstall.moduleDirectory;
+  }
+  return env;
+}
+
+async function authenticateBroker(stream: ByteStream, authToken: string): Promise {
+  await writeBrokerRequest(stream, { kind: 'authenticate', token: authToken });
+  const response = await readBrokerResponse(stream);
+  if (response.kind === 'error') {
+    throw new Error(`native broker authentication failed: ${response.message}`);
+  }
+}
+
+type BrokerEndpointPlan =
+  | { kind: 'unix'; socket: string; controlSocket: string; ipcDir: string }
+  | { kind: 'tcp'; listen: string; controlListen: string; ipcDir?: undefined };
+
+async function allocateBrokerEndpoint(config: NormalizedOpenConfig): Promise {
+  const canUseUnix = process.platform !== 'win32';
+  if (canUseUnix) {
+    const ipcDir = await createTempDir('lpgo-');
+    const endpoint = {
+      kind: 'unix',
+      socket: join(ipcDir, 's'),
+      controlSocket: join(ipcDir, 'c'),
+      ipcDir,
+    } as const;
+    if (unixSocketPathsFit(endpoint.socket, endpoint.controlSocket)) return endpoint;
+    await removeTree(ipcDir);
+  }
+  return { kind: 'tcp', listen: '127.0.0.1:0', controlListen: '127.0.0.1:0' };
+}
+
+function brokerSpawnArgs(config: NormalizedOpenConfig, endpoint: BrokerEndpointPlan): string[] {
+  const args = [
+    '--root',
+    config.instanceDirectory,
+    '--username',
+    config.username,
+    '--database',
+    config.database,
+  ];
+  if (endpoint.kind === 'unix') {
+    args.push('--socket', endpoint.socket, '--control-socket', endpoint.controlSocket);
+  } else {
+    args.push('--listen', endpoint.listen, '--control-listen', endpoint.controlListen);
+  }
+  if (config.seed !== undefined)
+    args.push(
+      '--seed-directory',
+      config.seed.directory,
+      '--seed-manifest',
+      config.seed.manifestPath,
+    );
+  if (config.icuData !== undefined)
+    args.push(
+      '--icu-data-directory',
+      config.icuData.directory,
+      '--icu-data-manifest',
+      config.icuData.manifestPath,
+    );
+  for (const extension of config.extensions) {
+    args.push('--extension', extension);
+  }
+  for (const assignment of startupAssignments(config.startupArgs)) {
+    args.push('--startup-guc', assignment);
+  }
+  return args;
+}
+
+function parseBrokerReadyLine(line: string): {
+  primary: string;
+  control: string;
+} {
+  if (line.startsWith(ERROR_PREFIX)) {
+    throw new Error(`native broker failed to start: ${line.slice(ERROR_PREFIX.length)}`);
+  }
+  if (!line.startsWith(READY_PREFIX)) {
+    throw new Error(`native broker did not print a ready line: ${line}`);
+  }
+  const parts = line.slice(READY_PREFIX.length).trim().split(/\s+/);
+  const primary = parts[0];
+  const control = parts[1]?.startsWith('control=') ? parts[1].slice('control='.length) : undefined;
+  if (parts.length !== 2 || primary === undefined || control === undefined) {
+    throw new Error('native broker ready line did not include primary and control endpoints');
+  }
+  return { primary, control };
+}
+
+async function resolveBrokerExecutable(explicit: string | undefined): Promise {
+  if (explicit !== undefined) {
+    return requireExecutableFile(explicit, 'brokerExecutable');
+  }
+
+  const configured = envVar(OLIPHAUNT_BROKER_ENV);
+  if (configured !== undefined && configured.trim().length > 0) {
+    if (configured.includes('\0')) {
+      throw new Error(`${OLIPHAUNT_BROKER_ENV} must not contain NUL bytes`);
+    }
+    return requireExecutableFile(configured, OLIPHAUNT_BROKER_ENV);
+  }
+
+  for (const candidate of packageAdjacentExecutables('oliphaunt-broker')) {
+    if (await isFile(candidate)) {
+      return candidate;
+    }
+  }
+  const version = await packageBrokerVersion();
+  const target = brokerPackageTarget(platform(), arch());
+  const installed = await packageBrokerExecutable(target, version);
+  if (installed !== undefined) {
+    return installed;
+  }
+  throw new Error(
+    `${target.packageName} ${version} is not installed; reinstall @oliphaunt/ts with optional dependencies enabled`,
+  );
+}
+
+async function requireExecutableFile(path: string, source: string): Promise {
+  if (!(await isFile(path))) {
+    throw new Error(`${source} does not point to an existing file: ${path}`);
+  }
+  return path;
+}
+
+function packageAdjacentExecutables(base: string): string[] {
+  const here = dirname(fileURLToPath(import.meta.url));
+  return [
+    join(here, base),
+    join(here, `${base}.exe`),
+    join(here, '..', base),
+    join(here, '..', `${base}.exe`),
+    resolve(process.cwd(), base),
+    resolve(process.cwd(), `${base}.exe`),
+  ];
+}
+
+type BrokerPackageTarget = {
+  id: string;
+  packageName: string;
+  executableRelativePath: string;
+};
+
+async function packageBrokerVersion(): Promise {
+  type PackageMetadata = {
+    name?: string;
+    version?: string;
+    oliphaunt?: { brokerVersion?: string };
+  };
+  const packageJson = JSON.parse(
+    await readFile(new URL('../../package.json', import.meta.url), 'utf8'),
+  ) as PackageMetadata;
+  const version = packageJson.oliphaunt?.brokerVersion;
+  if (packageJson.name !== '@oliphaunt/ts' || version === undefined || version.length === 0) {
+    throw new Error('@oliphaunt/ts package metadata does not pin brokerVersion');
+  }
+  return version;
+}
+
+function brokerPackageTarget(currentPlatform: string, currentArch: string): BrokerPackageTarget {
+  const normalizedPlatform = normalizeBrokerPlatform(currentPlatform);
+  const normalizedArch = normalizeBrokerArchitecture(currentArch);
+  if (normalizedPlatform === 'darwin' && normalizedArch === 'arm64') {
+    return {
+      id: 'macos-arm64',
+      packageName: '@oliphaunt/broker-darwin-arm64',
+      executableRelativePath: 'bin/oliphaunt-broker',
+    };
+  }
+  if (normalizedPlatform === 'linux' && normalizedArch === 'x64') {
+    return {
+      id: 'linux-x64-gnu',
+      packageName: '@oliphaunt/broker-linux-x64-gnu',
+      executableRelativePath: 'bin/oliphaunt-broker',
+    };
+  }
+  if (normalizedPlatform === 'linux' && normalizedArch === 'arm64') {
+    return {
+      id: 'linux-arm64-gnu',
+      packageName: '@oliphaunt/broker-linux-arm64-gnu',
+      executableRelativePath: 'bin/oliphaunt-broker',
+    };
+  }
+  if (normalizedPlatform === 'windows' && normalizedArch === 'x64') {
+    return {
+      id: 'windows-x64-msvc',
+      packageName: '@oliphaunt/broker-win32-x64-msvc',
+      executableRelativePath: 'bin/oliphaunt-broker.exe',
+    };
+  }
+  throw new Error(
+    `no oliphaunt-broker package is defined for ${currentPlatform}/${currentArch}; pass brokerExecutable explicitly for this platform`,
+  );
+}
+
+async function packageBrokerExecutable(
+  target: BrokerPackageTarget,
+  expectedVersion: string,
+): Promise {
+  let packageJsonPath: string;
+  try {
+    packageJsonPath = require.resolve(`${target.packageName}/package.json`);
+  } catch {
+    return undefined;
+  }
+  type BrokerPackageMetadata = {
+    name?: string;
+    version?: string;
+    oliphaunt?: {
+      brokerHelper?: string;
+      target?: string;
+      executableRelativePath?: string;
+    };
+  };
+  const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8')) as BrokerPackageMetadata;
+  if (packageJson.name !== target.packageName) {
+    throw new Error(
+      `${target.packageName} package metadata has name ${packageJson.name ?? ''}`,
+    );
+  }
+  if (packageJson.version !== expectedVersion) {
+    throw new Error(
+      `${target.packageName} version ${packageJson.version ?? ''} does not match @oliphaunt/ts brokerVersion ${expectedVersion}`,
+    );
+  }
+  if (packageJson.oliphaunt?.brokerHelper !== 'oliphaunt-broker') {
+    throw new Error(`${target.packageName} package metadata does not declare oliphaunt-broker`);
+  }
+  if (packageJson.oliphaunt?.target !== target.id) {
+    throw new Error(`${target.packageName} package metadata does not target ${target.id}`);
+  }
+  const executable = join(
+    dirname(packageJsonPath),
+    packageJson.oliphaunt.executableRelativePath ?? target.executableRelativePath,
+  );
+  return requireExecutableFile(executable, `${target.packageName} broker helper`);
+}
+
+async function isFile(path: string): Promise {
+  try {
+    return (await stat(path)).isFile();
+  } catch {
+    return false;
+  }
+}
+
+function startupAssignments(startupArgs: string[]): string[] {
+  const assignments: string[] = [];
+  for (let i = 0; i < startupArgs.length; i += 2) {
+    const assignment = startupArgs[i + 1];
+    if (startupArgs[i] === '-c' && assignment !== undefined) {
+      assignments.push(assignment);
+    }
+  }
+  return assignments;
+}
+
+function asBrokerHandle(handle: RuntimeHandle): BrokerHandle {
+  if (handle instanceof BrokerHandle) {
+    return handle;
+  }
+  throw new Error('invalid native broker handle');
+}
+
+function normalizeBrokerPlatform(value: string): string {
+  switch (value) {
+    case 'darwin':
+    case 'macos':
+      return 'darwin';
+    case 'win32':
+    case 'windows':
+      return 'windows';
+    default:
+      return value;
+  }
+}
+
+function normalizeBrokerArchitecture(value: string): string {
+  switch (value) {
+    case 'arm64':
+    case 'aarch64':
+      return 'arm64';
+    case 'x64':
+    case 'x86_64':
+      return 'x64';
+    default:
+      return value;
+  }
+}
diff --git a/src/sdks/js/src/runtime/byte-stream.ts b/src/sdks/ts/sdk/src/runtime/byte-stream.ts
similarity index 100%
rename from src/sdks/js/src/runtime/byte-stream.ts
rename to src/sdks/ts/sdk/src/runtime/byte-stream.ts
diff --git a/src/sdks/js/src/runtime/close.ts b/src/sdks/ts/sdk/src/runtime/close.ts
similarity index 100%
rename from src/sdks/js/src/runtime/close.ts
rename to src/sdks/ts/sdk/src/runtime/close.ts
diff --git a/src/sdks/ts/sdk/src/runtime/direct.ts b/src/sdks/ts/sdk/src/runtime/direct.ts
new file mode 100644
index 000000000..e208c1311
--- /dev/null
+++ b/src/sdks/ts/sdk/src/runtime/direct.ts
@@ -0,0 +1,77 @@
+import type { NormalizedOpenConfig } from '../config.js';
+import {
+  NativeDetachOutcomeUnknownError,
+  type NativeBinding,
+  type NativeHandle,
+} from '../native/types.js';
+import type { RuntimeBinding, RuntimeHandle } from './types.js';
+
+export function directRuntimeBinding(binding: NativeBinding): RuntimeBinding {
+  const runtimeBinding: RuntimeBinding = {
+    open(config: NormalizedOpenConfig): Promise {
+      return binding.open({
+        pgdata: config.pgdata,
+        // Undefined is provenance: Node and Bun may materialize package-managed
+        // extension assets, while a caller-supplied directory must be validated as-is.
+        runtimeDirectory: config.runtimeDirectory,
+        ...(config.seed !== undefined ? { seed: config.seed } : {}),
+        ...(config.icuData !== undefined ? { icuData: config.icuData } : {}),
+        username: config.username,
+        database: config.database,
+        extensions: config.extensions,
+        startupArgs: config.startupArgs,
+      });
+    },
+    execProtocolRaw(handle: RuntimeHandle, request: Uint8Array): Promise {
+      return binding.execProtocolRaw(handle, request);
+    },
+    execProtocolStream(
+      handle: RuntimeHandle,
+      request: Uint8Array,
+      onChunk: (chunk: Uint8Array) => void,
+    ): Promise {
+      return binding.execProtocolStream(handle, request, onChunk);
+    },
+    backup(handle: RuntimeHandle): Promise {
+      return binding.backup(handle);
+    },
+    cancel(handle: RuntimeHandle): Promise {
+      return binding.cancel(handle);
+    },
+    async close(handle: RuntimeHandle) {
+      try {
+        await binding.detach(handle);
+        return { state: 'closed' };
+      } catch (error) {
+        if (error instanceof NativeDetachOutcomeUnknownError) {
+          return { state: 'terminal', error };
+        }
+        // Every other NativeBinding.detach() rejection is required to precede
+        // logical deactivation. Keeping this owner live is therefore safe and
+        // lets a caller retry an interrupted DISCARD ALL / ROLLBACK boundary.
+        return { state: 'retryable', error };
+      }
+    },
+  };
+  if (binding.registerForgottenHandleCleanup !== undefined) {
+    runtimeBinding.registerForgottenHandleCleanup = (
+      owner: object,
+      handle: RuntimeHandle,
+      releaseOwnership: () => void,
+    ) => binding.registerForgottenHandleCleanup?.(owner, handle, releaseOwnership);
+  }
+  if (binding.unregisterForgottenHandleCleanup !== undefined) {
+    runtimeBinding.unregisterForgottenHandleCleanup = (owner: object) =>
+      binding.unregisterForgottenHandleCleanup?.(owner);
+  }
+  if (binding.execSimpleQuery !== undefined) {
+    runtimeBinding.execSimpleQuery = (handle: RuntimeHandle, sql: string) =>
+      binding.execSimpleQuery?.(handle, sql).then(assertDefined) ??
+      Promise.reject(new Error('direct simple query operation is unavailable'));
+  }
+  return runtimeBinding;
+}
+
+function assertDefined(value: T): T {
+  return value;
+}
diff --git a/src/sdks/js/src/runtime/forgotten-handle.ts b/src/sdks/ts/sdk/src/runtime/forgotten-handle.ts
similarity index 100%
rename from src/sdks/js/src/runtime/forgotten-handle.ts
rename to src/sdks/ts/sdk/src/runtime/forgotten-handle.ts
diff --git a/src/sdks/js/src/runtime/node-adapter.ts b/src/sdks/ts/sdk/src/runtime/node-adapter.ts
similarity index 98%
rename from src/sdks/js/src/runtime/node-adapter.ts
rename to src/sdks/ts/sdk/src/runtime/node-adapter.ts
index 740a0ae0d..c736b49aa 100644
--- a/src/sdks/js/src/runtime/node-adapter.ts
+++ b/src/sdks/ts/sdk/src/runtime/node-adapter.ts
@@ -231,11 +231,14 @@ export async function readReadyLine(
   });
 }
 
-export async function connectEndpoint(endpoint: LocalEndpoint): Promise {
+export async function connectEndpoint(
+  endpoint: LocalEndpoint,
+  signal?: AbortSignal,
+): Promise {
   const socket =
     endpoint.kind === 'unix'
-      ? createConnection(endpoint.path)
-      : createConnection({ host: endpoint.host, port: endpoint.port });
+      ? createConnection({ path: endpoint.path, signal })
+      : createConnection({ host: endpoint.host, port: endpoint.port, signal });
   if (endpoint.kind === 'tcp') {
     socket.setNoDelay(true);
   }
diff --git a/src/sdks/ts/sdk/src/runtime/pgwire.ts b/src/sdks/ts/sdk/src/runtime/pgwire.ts
new file mode 100644
index 000000000..baffc639c
--- /dev/null
+++ b/src/sdks/ts/sdk/src/runtime/pgwire.ts
@@ -0,0 +1,272 @@
+import type { ByteStream } from './byte-stream.js';
+import { connectEndpoint, type LocalEndpoint } from './node-adapter.js';
+import { throwCollectedCloseFailures } from './close.js';
+
+const PROTOCOL_VERSION_3 = 196_608;
+const MAX_FRAME_LEN = 128 * 1024 * 1024;
+
+export class PostgresWireClient {
+  readonly #stream: ByteStream;
+  #terminateRequested = false;
+  #streamClosed = false;
+
+  constructor(
+    stream: ByteStream,
+    private readonly endpoint?: LocalEndpoint,
+    private readonly cancelKey?: Uint8Array,
+  ) {
+    this.#stream = stream;
+  }
+
+  static async connect(
+    endpoint: LocalEndpoint,
+    username: string,
+    database: string,
+    timeoutMs: number,
+    password?: string,
+  ): Promise {
+    const controller = new AbortController();
+    const timeout = setTimeout(() => controller.abort(), timeoutMs);
+    let stream: ByteStream | undefined;
+    try {
+      stream = await connectEndpoint(endpoint, controller.signal);
+      await stream.writeAll(encodeStartupMessage(username, database));
+      const key = await readUntilReady(stream, password);
+      return new PostgresWireClient(stream, endpoint, key);
+    } catch (error) {
+      const failures: unknown[] = [error];
+      try {
+        await stream?.close();
+      } catch (closeError) {
+        failures.push(closeError);
+      }
+      throwCollectedCloseFailures(failures, 'native server startup connection cleanup failed');
+      throw error;
+    } finally {
+      clearTimeout(timeout);
+    }
+  }
+
+  async execProtocolStream(
+    request: Uint8Array,
+    onChunk: (chunk: Uint8Array) => void,
+  ): Promise {
+    let remaining = requestReadyBoundaries(request);
+    const read = async () => {
+      while (remaining > 0) {
+        const frame = await readBackendFrame(this.#stream);
+        onChunk(frame);
+        if (frame[0] === 0x5a) remaining--;
+      }
+    };
+    try {
+      // Pipelined queries can fill both socket buffers; drain while writing.
+      await Promise.all([this.#stream.writeAll(request), read()]);
+    } catch (error) {
+      const failures: unknown[] = [error];
+      try {
+        await this.close();
+      } catch (closeError) {
+        failures.push(closeError);
+      }
+      throwCollectedCloseFailures(failures, 'PostgreSQL exchange cleanup failed');
+    }
+  }
+
+  async cancel(): Promise {
+    if (!this.endpoint || !this.cancelKey)
+      throw new Error('PostgreSQL cancellation key is unavailable');
+    await cancelPostgresStream(await connectEndpoint(this.endpoint), this.cancelKey);
+  }
+
+  async close(): Promise {
+    if (!this.#streamClosed) {
+      await this.#stream.close();
+      this.#streamClosed = true;
+    }
+  }
+
+  async terminate(): Promise {
+    const failures: unknown[] = [];
+    if (!this.#terminateRequested) {
+      this.#terminateRequested = true;
+      try {
+        await this.#stream.writeAll(new Uint8Array([0x58, 0, 0, 0, 4]));
+      } catch (error) {
+        failures.push(error);
+      }
+    }
+    if (!this.#streamClosed) {
+      try {
+        await this.close();
+      } catch (error) {
+        failures.push(error);
+      }
+    }
+    throwCollectedCloseFailures(failures, 'native server client termination failed');
+  }
+
+  /** @internal Whether the exact client stream has been released. */
+  get isTerminated(): boolean {
+    return this.#streamClosed;
+  }
+}
+
+export function encodeStartupMessage(username: string, database: string): Uint8Array {
+  const body: number[] = [];
+  pushI32(body, PROTOCOL_VERSION_3);
+  pushCString(body, 'user');
+  pushCString(body, username);
+  pushCString(body, 'database');
+  pushCString(body, database);
+  pushCString(body, 'client_encoding');
+  pushCString(body, 'UTF8');
+  body.push(0);
+  const out: number[] = [];
+  pushI32(out, body.length + 4);
+  out.push(...body);
+  return Uint8Array.from(out);
+}
+
+async function readUntilReady(
+  stream: ByteStream,
+  password?: string,
+): Promise {
+  let authenticated = false;
+  let passwordSent = false;
+  let cancelKey: Uint8Array | undefined;
+  for (;;) {
+    const frame = await readBackendFrame(stream);
+    const tag = frame[0];
+    const body = frame.subarray(5);
+    switch (tag) {
+      case 0x52: {
+        if (body.length !== 4 || authenticated)
+          throw new Error('invalid PostgreSQL authentication response');
+        const method = readI32(body, 0);
+        if (method === 0) authenticated = true;
+        else if (method === 3 && password !== undefined && !passwordSent) {
+          if (password.includes('\0'))
+            throw new Error('PostgreSQL password must not contain NUL bytes');
+          const payload = new TextEncoder().encode(password);
+          const message = new Uint8Array(payload.length + 6);
+          message[0] = 0x70;
+          new DataView(message.buffer).setUint32(1, payload.length + 5);
+          message.set(payload, 5);
+          await stream.writeAll(message);
+          passwordSent = true;
+        } else
+          throw new Error(`native server requested unsupported authentication method ${method}`);
+        break;
+      }
+      case 0x4b:
+        if (!authenticated || body.length !== 8 || cancelKey)
+          throw new Error('invalid PostgreSQL cancellation key');
+        cancelKey = body.slice();
+        break;
+      case 0x45:
+        throw new Error(parseErrorResponse(body));
+      case 0x5a:
+        if (!authenticated || (password !== undefined && !cancelKey))
+          throw new Error('PostgreSQL startup was not authenticated');
+        return cancelKey;
+      default:
+        break;
+    }
+  }
+}
+
+async function readBackendFrame(stream: ByteStream): Promise {
+  const header = await stream.readExactly(5);
+  const length = readI32(header, 1);
+  if (length < 4 || length > MAX_FRAME_LEN)
+    throw new Error(`invalid PostgreSQL message length ${length}`);
+  const frame = new Uint8Array(length + 1);
+  frame.set(header);
+  frame.set(await stream.readExactly(length - 4), 5);
+  if (frame[0] === 0x5a && (length !== 5 || ![0x49, 0x54, 0x45].includes(frame[5]!)))
+    throw new Error('invalid PostgreSQL ReadyForQuery frame');
+  return frame;
+}
+
+function requestReadyBoundaries(request: Uint8Array): number {
+  if (request.length === 0 || request.length > MAX_FRAME_LEN)
+    throw new Error('invalid PostgreSQL request length');
+  let count = 0;
+  let lastTag = 0;
+  for (let offset = 0; offset < request.length; ) {
+    if (request.length - offset < 5) throw new Error('truncated PostgreSQL frontend header');
+    const length = readI32(request, offset + 1);
+    if (length < 4 || length + 1 > request.length - offset)
+      throw new Error('invalid PostgreSQL frontend frame length');
+    lastTag = request[offset]!;
+    if (lastTag === 0x58 || lastTag === 0x70)
+      throw new Error('PostgreSQL connection control is not a query request');
+    if (lastTag === 0x51 || lastTag === 0x53) count++;
+    offset += length + 1;
+  }
+  if (!count || ![0x51, 0x53, 0x63, 0x66].includes(lastTag))
+    throw new Error(
+      'buffered PostgreSQL request must include Query or Sync and end at a query or COPY boundary',
+    );
+  return count;
+}
+
+/** Send PostgreSQL CancelRequest; the server intentionally sends no response. */
+export async function cancelPostgresStream(stream: ByteStream, key: Uint8Array): Promise {
+  try {
+    if (key.length !== 8) throw new Error('invalid PostgreSQL cancellation key');
+    const packet = new Uint8Array(16);
+    const view = new DataView(packet.buffer);
+    view.setUint32(0, 16);
+    view.setUint32(4, 80_877_102);
+    packet.set(key, 8);
+    await stream.writeAll(packet);
+  } catch (failure) {
+    try {
+      await stream.close();
+    } catch (closeFailure) {
+      throw new AggregateError(
+        [failure, closeFailure],
+        'PostgreSQL cancel and stream close both failed',
+      );
+    }
+    throw failure;
+  }
+  await stream.close();
+}
+
+function parseErrorResponse(body: Uint8Array): string {
+  let offset = 0;
+  while (offset < body.length && body[offset] !== 0) {
+    const code = body[offset];
+    offset += 1;
+    const end = body.indexOf(0, offset);
+    if (end < 0) {
+      break;
+    }
+    if (code === 0x4d) {
+      return strictUtf8.decode(body.subarray(offset, end));
+    }
+    offset = end + 1;
+  }
+  return 'native server returned an error response';
+}
+
+function pushCString(out: number[], value: string): void {
+  if (value.includes('\0')) {
+    throw new Error('PostgreSQL startup string must not contain NUL bytes');
+  }
+  out.push(...new TextEncoder().encode(value), 0);
+}
+
+function pushI32(out: number[], value: number): void {
+  const bits = value >>> 0;
+  out.push((bits >>> 24) & 0xff, (bits >>> 16) & 0xff, (bits >>> 8) & 0xff, bits & 0xff);
+}
+
+function readI32(bytes: Uint8Array, offset: number): number {
+  return new DataView(bytes.buffer, bytes.byteOffset + offset, 4).getInt32(0);
+}
+
+const strictUtf8 = new TextDecoder('utf-8', { fatal: true });
diff --git a/src/sdks/js/src/runtime/server.ts b/src/sdks/ts/sdk/src/runtime/server.ts
similarity index 94%
rename from src/sdks/js/src/runtime/server.ts
rename to src/sdks/ts/sdk/src/runtime/server.ts
index be9d6a42a..3d1e5de09 100644
--- a/src/sdks/js/src/runtime/server.ts
+++ b/src/sdks/ts/sdk/src/runtime/server.ts
@@ -1,37 +1,37 @@
+import { validateSelectedIcuData } from '../native/cluster-seed.js';
 import { spawn } from 'node:child_process';
-import { chmod, lstat, mkdir, mkdtemp, readdir, stat } from 'node:fs/promises';
+import { chmod, lstat, mkdir, mkdtemp, stat } from 'node:fs/promises';
+import { createServer } from 'node:net';
 import { tmpdir } from 'node:os';
 import { delimiter, dirname, join, resolve } from 'node:path';
-import { createServer } from 'node:net';
 
 import type { NormalizedOpenConfig } from '../config.js';
-import type { ServerListen } from '../types.js';
+import {
+  materializeExtensionInstall,
+  resolveNativeInstall,
+  selectNativeResources,
+} from '../native/assets.js';
 import { envVar } from '../native/common.js';
 import {
-  connectEndpoint,
+  initializeNativePgdata,
+  nativeInitdbArgs,
+  nativePostgresChildEnvironment,
+} from '../native/initialize.js';
+import { resolveExactNativeRuntimeProfile } from '../native/runtime-profile.js';
+import type { ServerListen } from '../types.js';
+import { throwCollectedCloseFailures } from './close.js';
+import { createForgottenRuntimeHandleCleanup } from './forgotten-handle.js';
+import {
   cleanupFailedManagedLaunch,
+  type LocalEndpoint,
+  type ManagedChild,
   removeTree,
   spawnManagedChild,
   unixSocketPathsFit,
   waitForManagedChild,
-  type LocalEndpoint,
-  type FailedManagedLaunch,
-  type ManagedChild,
 } from './node-adapter.js';
 import { PostgresWireClient } from './pgwire.js';
-import {
-  initializeNativePgdata,
-  nativeInitdbArgs,
-  nativePostgresChildEnvironment,
-} from '../native/initialize.js';
 import type { RuntimeBinding, RuntimeHandle } from './types.js';
-import { throwCollectedCloseFailures } from './close.js';
-import { createForgottenRuntimeHandleCleanup } from './forgotten-handle.js';
-import {
-  materializeNodeExtensionInstall,
-  resolveNodeNativeInstall,
-} from '../native/assets-node.js';
-import { resolveExactNativeRuntimeProfile } from '../native/runtime-profile.js';
 
 const SERVER_HOST = '127.0.0.1';
 const SERVER_STARTUP_TIMEOUT_MS_ENV = 'OLIPHAUNT_SERVER_STARTUP_TIMEOUT_MS';
@@ -285,6 +285,7 @@ async function openServer(config: NormalizedOpenConfig): Promise {
   try {
     const startupTimeoutMs = serverStartupTimeoutMs();
     const tools = await resolveServerTools({
+      icuData: config.icuData,
       serverExecutable: config.serverExecutable,
       runtimeDirectory: config.runtimeDirectory,
       extensions: config.extensions,
@@ -423,10 +424,15 @@ async function waitForServer(
       throw new Error(`native server exited before accepting connections with code ${exited.code}`);
     }
     try {
-      return await PostgresWireClient.connect(endpoint, username, database);
+      return await PostgresWireClient.connect(
+        endpoint,
+        username,
+        database,
+        Math.max(1, deadline - Date.now()),
+      );
     } catch (error) {
       lastError = error;
-      await sleep(CONNECT_RETRY_MS);
+      await sleep(Math.min(CONNECT_RETRY_MS, Math.max(0, deadline - Date.now())));
     }
   }
   throw new Error(`native server did not accept SDK connections: ${errorString(lastError)}`);
@@ -543,6 +549,7 @@ export async function resolveServerTools(options: {
   serverExecutable?: string;
   runtimeDirectory?: string;
   extensions?: readonly string[];
+  icuData?: import('../types.js').NativeResourceDirectory;
 }): Promise {
   const candidates = [
     options.serverExecutable,
@@ -554,7 +561,11 @@ export async function resolveServerTools(options: {
   for (const candidate of candidates) {
     if (await isFile(candidate)) {
       const toolDirectory = options.runtimeDirectory ?? dirname(candidate);
-      const profile = await resolveExactNativeRuntimeProfile(dirname(toolDirectory));
+      const profile =
+        options.icuData === undefined
+          ? await resolveExactNativeRuntimeProfile(dirname(toolDirectory))
+          : (await validateSelectedIcuData(options.icuData),
+            { catalogProfile: 'icu' as const, icuDataDirectory: options.icuData.directory });
       return {
         executable: candidate,
         toolDirectory,
@@ -565,7 +576,10 @@ export async function resolveServerTools(options: {
   if (options.serverExecutable !== undefined || options.runtimeDirectory !== undefined) {
     throw new Error(`set serverExecutable, runtimeDirectory, or ${OLIPHAUNT_POSTGRES_ENV}`);
   }
-  const install = await resolvePackageManagedServerInstall(options.extensions ?? []);
+  const install = await resolvePackageManagedServerInstall(
+    options.extensions ?? [],
+    options.icuData,
+  );
   if (install.runtimeDirectory !== undefined) {
     const toolDirectory = join(install.runtimeDirectory, 'bin');
     const executable = join(toolDirectory, executableName('postgres'));
@@ -587,28 +601,18 @@ export async function resolveServerTools(options: {
   );
 }
 
-async function resolvePackageManagedServerInstall(extensions: readonly string[]): Promise<{
+async function resolvePackageManagedServerInstall(
+  extensions: readonly string[],
+  icuData?: import('../types.js').NativeResourceDirectory,
+): Promise<{
   runtimeDirectory?: string;
   icuDataDirectory?: string;
   catalogProfile?: 'standard' | 'icu';
 }> {
-  if (runtimeName() === 'deno') {
-    if (extensions.length > 0) {
-      throw new Error(
-        `Deno server execution does not automatically materialize extension packages; pass runtimeDirectory with the selected extension assets or use Node/Bun openServer(). Selected extensions: ${extensions.join(', ')}`,
-      );
-    }
-    const install = await import('../native/assets-deno.js').then((module) =>
-      module.resolveDenoNativeInstall(),
-    );
-    return {
-      runtimeDirectory: install.runtimeDirectory,
-      icuDataDirectory: install.icuDataDirectory,
-      catalogProfile: install.catalogProfile,
-    };
-  }
-
-  return materializeNodeExtensionInstall(await resolveNodeNativeInstall(), extensions);
+  return materializeExtensionInstall(
+    await selectNativeResources(await resolveNativeInstall(), { icuData }),
+    extensions,
+  );
 }
 
 async function optionalTool(
@@ -864,16 +868,6 @@ function asServerHandle(handle: RuntimeHandle): ServerHandle {
   throw new Error('invalid native server handle');
 }
 
-function runtimeName(): 'node' | 'bun' | 'deno' {
-  if (typeof (globalThis as { Deno?: unknown }).Deno !== 'undefined') {
-    return 'deno';
-  }
-  if (typeof (globalThis as { Bun?: unknown }).Bun !== 'undefined') {
-    return 'bun';
-  }
-  return 'node';
-}
-
 function errorString(error: unknown): string {
   return error instanceof Error ? error.message : String(error);
 }
diff --git a/src/sdks/js/src/runtime/types.ts b/src/sdks/ts/sdk/src/runtime/types.ts
similarity index 100%
rename from src/sdks/js/src/runtime/types.ts
rename to src/sdks/ts/sdk/src/runtime/types.ts
diff --git a/src/sdks/ts/sdk/src/types.ts b/src/sdks/ts/sdk/src/types.ts
new file mode 100644
index 000000000..7d2ed5ace
--- /dev/null
+++ b/src/sdks/ts/sdk/src/types.ts
@@ -0,0 +1,137 @@
+export type DatabaseStorage =
+  | { readonly kind: 'temporaryDirectory' }
+  | { readonly kind: 'directory'; readonly path: string };
+
+export type BinaryInput = ArrayBuffer | ArrayBufferView | Uint8Array | ReadonlyArray;
+
+/** An explicitly selected, immutable resource directory and its producer receipt. */
+export type NativeResourceDirectory = {
+  readonly directory: string;
+  readonly manifestPath: string;
+};
+
+type QueryReadOptions = Omit;
+/** A synchronous, serial raw-protocol consumer used as the backpressure acknowledgement. */
+export type ProtocolChunkCallback = (chunk: Uint8Array) => undefined;
+
+export type OpenConfig = {
+  /**
+   * Runtime placement topology. `direct` is in-process; it does not mean that
+   * PostgreSQL work runs synchronously on the JavaScript caller thread.
+   * Server ownership is selected explicitly with `Oliphaunt.openServer()`.
+   */
+  topology?: 'direct' | 'broker';
+  storage?: DatabaseStorage;
+  startupGUCs?: Readonly>;
+  username?: string;
+  database?: string;
+  extensions?: ReadonlyArray;
+  libraryPath?: string;
+  runtimeDirectory?: string;
+  /** Optional preinitialized cluster. Without one, desktop initialization uses initdb. */
+  seed?: NativeResourceDirectory;
+  /** Canonical ICU data, selected independently of the runtime and seed. */
+  icuData?: NativeResourceDirectory;
+  brokerExecutable?: string;
+};
+
+export type ServerOpenConfig = Omit<
+  OpenConfig,
+  'topology' | 'brokerExecutable' | 'libraryPath' | 'seed'
+> & {
+  serverExecutable?: string;
+  listen?: ServerListen;
+};
+
+export type ServerListen =
+  | { readonly transport: 'tcp'; readonly port?: number }
+  | {
+      readonly transport: 'unix';
+      readonly directory: string;
+      readonly port?: number;
+    };
+
+export type OliphauntTransaction = {
+  readonly closed: boolean;
+  execute(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: import('./query.js').ParameterOptions,
+  ): Promise;
+  query(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: Options & import('./query.js').QueryOptions,
+  ): Promise>>;
+  queryRaw(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: import('./query.js').ParameterOptions,
+  ): Promise;
+  exec(
+    sql: string,
+    options?: Options & QueryReadOptions,
+  ): Promise>>;
+  describe(
+    sql: string,
+    parameterTypeOids?: ReadonlyArray,
+  ): Promise;
+  rollback(): Promise;
+};
+
+export type OliphauntDatabase = {
+  readonly closed: boolean;
+  execute(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: import('./query.js').ParameterOptions,
+  ): Promise;
+  query(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: Options & import('./query.js').QueryOptions,
+  ): Promise>>;
+  queryRaw(
+    sql: string,
+    parameters?: ReadonlyArray,
+    options?: import('./query.js').ParameterOptions,
+  ): Promise;
+  exec(
+    sql: string,
+    options?: Options & QueryReadOptions,
+  ): Promise>>;
+  describe(
+    sql: string,
+    parameterTypeOids?: ReadonlyArray,
+  ): Promise;
+  execProtocolRaw(input: BinaryInput): Promise;
+  execProtocolRawStream(input: BinaryInput, onChunk: ProtocolChunkCallback): Promise;
+  backup(): Promise;
+  cancel(): Promise;
+  /**
+   * Own the session for one callback. Use callback return/throw or rollback()
+   * for lifecycle; manual BEGIN/START/COMMIT/END/ABORT/PREPARE TRANSACTION and
+   * AND CHAIN are unsupported. SAVEPOINT and ROLLBACK TO are allowed.
+   */
+  transaction(body: (transaction: OliphauntTransaction) => Promise | T): Promise;
+  close(): Promise;
+  [Symbol.asyncDispose](): Promise;
+};
+
+export type OliphauntServer = {
+  readonly closed: boolean;
+  /** Endpoint for caller-owned ORM, driver, or tool connections. */
+  readonly connectionString: string;
+  close(): Promise;
+  [Symbol.asyncDispose](): Promise;
+};
+
+export type RestoreOptions = {
+  libraryPath?: string;
+};
+
+export type OliphauntClient = {
+  open(config?: OpenConfig): Promise;
+  openServer(config?: ServerOpenConfig): Promise;
+  restore(destination: string, backup: BinaryInput, options?: RestoreOptions): Promise;
+};
diff --git a/src/sdks/ts/sdk/tools/check-package.mts b/src/sdks/ts/sdk/tools/check-package.mts
new file mode 100644
index 000000000..73f5fe307
--- /dev/null
+++ b/src/sdks/ts/sdk/tools/check-package.mts
@@ -0,0 +1,43 @@
+#!/usr/bin/env bun
+import { readdirSync } from 'node:fs';
+import path from 'node:path';
+import { compareText } from '../../../../../tools/release/release-artifact-targets.mts';
+import {
+  archiveTarNames,
+  fail,
+  inspectSdkProduct,
+  rejectSdkRuntimePayload,
+  rel,
+} from '../../../../../tools/packaging/release-carrier.mts';
+import {
+  SOURCE_ONLY_NPM_PROFILES,
+  assertSourceOnlyNpmArchive,
+} from '../../../../../tools/packaging/source-only-sdk-package.mts';
+
+export async function checkJavascriptPackage(root) {
+  const product = 'oliphaunt-js';
+  let checked = false;
+
+  const tarballs = readdirSync(root)
+    .filter((name) => name.endsWith('.tgz'))
+    .map((name) => path.join(root, name))
+    .sort(compareText);
+  if (tarballs.length === 0) {
+    fail(`${product} must stage an npm tarball under ${rel(root)}`);
+  }
+  for (const tarball of tarballs) {
+    const names = archiveTarNames(tarball);
+    rejectSdkRuntimePayload(product, tarball, names);
+    try {
+      assertSourceOnlyNpmArchive(tarball, SOURCE_ONLY_NPM_PROFILES.js);
+    } catch (error) {
+      fail(error instanceof Error ? error.message : String(error));
+    }
+
+    checked = true;
+  }
+
+  return checked;
+}
+
+if (import.meta.main) await inspectSdkProduct('oliphaunt-js', checkJavascriptPackage);
diff --git a/src/sdks/ts/sdk/tools/entrypoint-consumer.mts b/src/sdks/ts/sdk/tools/entrypoint-consumer.mts
new file mode 100644
index 000000000..254d03d00
--- /dev/null
+++ b/src/sdks/ts/sdk/tools/entrypoint-consumer.mts
@@ -0,0 +1,27 @@
+import assert from 'node:assert/strict';
+import broker, {
+  type OpenConfig as BrokerConfig,
+  Oliphaunt as namedBroker,
+} from '@oliphaunt/ts/broker';
+import direct, {
+  type OpenConfig as DirectConfig,
+  Oliphaunt as namedDirect,
+} from '@oliphaunt/ts/direct';
+
+const directConfig: DirectConfig = { storage: { kind: 'temporaryDirectory' } };
+const brokerConfig: BrokerConfig = { brokerExecutable: '/unused/broker' };
+void [directConfig, brokerConfig];
+assert.equal(direct, namedDirect);
+assert.equal(broker, namedBroker);
+
+const conflictingTopology = { topology: 'broker' as const };
+// @ts-expect-error direct mode is selected by the import, including widened variables
+await assert.rejects(direct.open(conflictingTopology), /does not accept topology/);
+// @ts-expect-error broker mode is selected by the import
+await assert.rejects(broker.open(conflictingTopology), /does not accept topology/);
+const conflictingHelper = { brokerExecutable: '/unused/broker' };
+await assert.rejects(
+  // @ts-expect-error a direct database does not accept a broker helper
+  direct.open(conflictingHelper),
+  /does not accept topology or brokerExecutable/,
+);
diff --git a/src/sdks/ts/sdk/tools/package.sh b/src/sdks/ts/sdk/tools/package.sh
new file mode 100644
index 000000000..df9e24e41
--- /dev/null
+++ b/src/sdks/ts/sdk/tools/package.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")"
+bash stage-release-artifacts.sh
+bun check-package.mts
diff --git a/src/sdks/ts/sdk/tools/prepare-consumer.mts b/src/sdks/ts/sdk/tools/prepare-consumer.mts
new file mode 100644
index 000000000..f32e73910
--- /dev/null
+++ b/src/sdks/ts/sdk/tools/prepare-consumer.mts
@@ -0,0 +1,64 @@
+import { mkdirSync, readdirSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { extractPortableTarGzipTree } from '../../../../../tools/packaging/portable-archive.mts';
+import {
+  preparePublishedConsumerEnvironment,
+  validPublishedConsumerInventory,
+} from './published-consumer.mts';
+
+const destination = path.resolve(process.argv[2]);
+const artifact = (directory: string, pattern: RegExp) => {
+  const files = readdirSync(directory).filter((name) => pattern.test(name));
+  if (files.length !== 1)
+    throw new Error(`expected one ${pattern} in ${directory}, found ${files.length}`);
+  return path.resolve(directory, files[0]);
+};
+mkdirSync(destination, { recursive: true });
+const sdk = artifact('target/sdk-artifacts/oliphaunt-js', /\.tgz$/u);
+const published = process.argv[3] === '--published-dependencies';
+if (published) {
+  const inventory = JSON.parse(process.env.OLIPHAUNT_PUBLISHED_DEPENDENCIES ?? 'null');
+  if (!validPublishedConsumerInventory(inventory))
+    throw new Error('missing or invalid verified published dependency inventory');
+  preparePublishedConsumerEnvironment(destination);
+  writeFileSync(
+    path.join(destination, 'package.json'),
+    JSON.stringify({
+      private: true,
+      type: 'module',
+      dependencies: {
+        '@oliphaunt/ts': `file:${sdk}`,
+        ...Object.fromEntries(inventory.map((row) => [row.name, row.version])),
+      },
+    }),
+  );
+  process.exit(0);
+}
+const query = artifact('target/sdk-artifacts/oliphaunt-query-ts', /\.tgz$/u);
+writeFileSync(
+  path.join(destination, 'package.json'),
+  JSON.stringify({
+    private: true,
+    type: 'module',
+    dependencies: { '@oliphaunt/ts': `file:${sdk}`, '@oliphaunt/ts-query': `file:${query}` },
+    overrides: { '@oliphaunt/ts-query': `file:${query}` },
+  }),
+);
+for (const [name, directory, pattern] of [
+  [
+    'runtime',
+    'target/liboliphaunt/desktop-release-assets/linux-x64-gnu',
+    /^liboliphaunt-.*-linux-x64-gnu\.tar\.gz$/u,
+  ],
+  [
+    'broker',
+    'target/oliphaunt-broker/release-assets',
+    /^oliphaunt-broker-.*-linux-x64-gnu\.tar\.gz$/u,
+  ],
+  [
+    'addon',
+    'target/oliphaunt-node-direct/release-assets',
+    /^oliphaunt-node-direct-.*-linux-x64-gnu\.tar\.gz$/u,
+  ],
+] as const)
+  await extractPortableTarGzipTree(artifact(directory, pattern), path.join(destination, name));
diff --git a/src/sdks/ts/sdk/tools/published-consumer.mts b/src/sdks/ts/sdk/tools/published-consumer.mts
new file mode 100644
index 000000000..a20a1e857
--- /dev/null
+++ b/src/sdks/ts/sdk/tools/published-consumer.mts
@@ -0,0 +1,118 @@
+import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { npmPublishedVersion } from '../../../../../tools/release/check_registry_publication.mts';
+import { sanitizedPublicEnvironment } from '../../../../../tools/release/public-consumer-smoke.mts';
+
+const root = path.resolve(import.meta.dir, '../../../../..');
+export function publishedConsumerDependencies(
+  manifest = JSON.parse(readFileSync(path.join(root, 'src/sdks/ts/sdk/package.json'), 'utf8')),
+) {
+  return {
+    '@oliphaunt/ts-query': manifest.dependencies['@oliphaunt/ts-query'],
+    '@oliphaunt/liboliphaunt-linux-x64-gnu': manifest.oliphaunt.liboliphauntVersion,
+    '@oliphaunt/broker-linux-x64-gnu': manifest.oliphaunt.brokerVersion,
+    '@oliphaunt/node-direct-linux-x64-gnu': manifest.oliphaunt.nodeDirectAddonVersion,
+  };
+}
+
+// Only a release of this SDK alone can replace all four candidate dependencies.
+// Mixed releases continue to exercise their newly produced dependency artifacts.
+export async function publishedConsumerInventory(products) {
+  if (products.length !== 1 || products[0] !== 'oliphaunt-js') return null;
+  const rows = await Promise.all(
+    Object.entries(publishedConsumerDependencies()).map(async ([name, version]) => {
+      const metadata = await npmPublishedVersion(name, version);
+      if (metadata === undefined) return null;
+      const integrity = metadata?.dist?.integrity;
+      const tarball = metadata?.dist?.tarball;
+      if (
+        metadata?.name !== name ||
+        metadata?.version !== version ||
+        !/^sha512-[A-Za-z0-9+/]{86}==$/.test(integrity ?? '') ||
+        typeof tarball !== 'string' ||
+        !tarball.startsWith('https://registry.npmjs.org/')
+      )
+        throw new Error(`invalid published npm dependency metadata: ${name}@${version}`);
+      return { name, version, integrity, tarball };
+    }),
+  );
+  return rows.every(Boolean) ? rows : null;
+}
+
+export function validPublishedConsumerInventory(inventory, manifest = undefined) {
+  const dependencies = publishedConsumerDependencies(manifest);
+  return (
+    Array.isArray(inventory) &&
+    inventory.length === Object.keys(dependencies).length &&
+    Object.entries(dependencies).every(
+      ([name, version]) =>
+        inventory.filter(
+          (row) =>
+            row !== null &&
+            typeof row === 'object' &&
+            row.name === name &&
+            row.version === version &&
+            /^sha512-[A-Za-z0-9+/]{86}==$/.test(row.integrity ?? '') &&
+            typeof row.tarball === 'string' &&
+            row.tarball.startsWith('https://registry.npmjs.org/'),
+        ).length === 1,
+    )
+  );
+}
+
+export function verifyPublishedConsumerInstall(destination, inventory) {
+  const manifest = JSON.parse(
+    readFileSync(path.join(destination, 'node_modules/@oliphaunt/ts/package.json'), 'utf8'),
+  );
+  if (!validPublishedConsumerInventory(inventory, manifest))
+    throw new Error('published dependency inventory does not match the candidate SDK');
+  const lock = Bun.JSONC.parse(readFileSync(path.join(destination, 'bun.lock'), 'utf8'));
+  for (const row of inventory) {
+    const installed = JSON.parse(
+      readFileSync(path.join(destination, 'node_modules', row.name, 'package.json'), 'utf8'),
+    );
+    const entry = lock.packages?.[row.name];
+    if (
+      installed.name !== row.name ||
+      installed.version !== row.version ||
+      entry?.[0] !== `${row.name}@${row.version}` ||
+      entry?.[1] !== '' ||
+      entry?.[3] !== row.integrity
+    )
+      throw new Error(`published dependency identity/integrity mismatch: ${row.name}`);
+  }
+}
+
+export function preparePublishedConsumerEnvironment(destination, inherited = process.env) {
+  const home = path.join(destination, 'install-home');
+  mkdirSync(home, { recursive: true });
+  const userConfig = path.join(home, '.npmrc');
+  const globalConfig = path.join(home, 'global.npmrc');
+  for (const file of [userConfig, globalConfig])
+    writeFileSync(file, 'registry=https://registry.npmjs.org/\nalways-auth=false\n');
+  const env = sanitizedPublicEnvironment(
+    {
+      HOME: home,
+      XDG_CONFIG_HOME: home,
+      NPM_CONFIG_USERCONFIG: userConfig,
+      NPM_CONFIG_GLOBALCONFIG: globalConfig,
+      NPM_CONFIG_REGISTRY: 'https://registry.npmjs.org/',
+    },
+    inherited,
+  );
+  for (const name of Object.keys(env)) if (/^BUN_|^NODE_OPTIONS$/i.test(name)) delete env[name];
+  writeFileSync(
+    path.join(destination, 'install-environment'),
+    Object.entries(env)
+      .map(([name, value]) => `${name}=${value}\0`)
+      .join(''),
+    { mode: 0o600 },
+  );
+  return env;
+}
+
+if (import.meta.main)
+  verifyPublishedConsumerInstall(
+    process.argv[2],
+    JSON.parse(process.env.OLIPHAUNT_PUBLISHED_DEPENDENCIES ?? 'null'),
+  );
diff --git a/src/sdks/ts/sdk/tools/published-consumer.test.mts b/src/sdks/ts/sdk/tools/published-consumer.test.mts
new file mode 100644
index 000000000..72a5359f3
--- /dev/null
+++ b/src/sdks/ts/sdk/tools/published-consumer.test.mts
@@ -0,0 +1,155 @@
+import assert from 'node:assert/strict';
+import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { test } from 'node:test';
+import {
+  publishedConsumerDependencies,
+  publishedConsumerInventory,
+  preparePublishedConsumerEnvironment,
+  verifyPublishedConsumerInstall,
+} from './published-consumer.mts';
+
+test('published lookup falls back only for absent versions and rejects invalid public metadata', async () => {
+  const originalFetch = globalThis.fetch;
+  const dependencies = publishedConsumerDependencies();
+  try {
+    globalThis.fetch = async () => new Response('', { status: 404 });
+    assert.equal(await publishedConsumerInventory(['oliphaunt-js']), null);
+    for (const mutation of [
+      { name: 'wrong-package' },
+      { version: '999.0.0' },
+      { dist: { integrity: 'bad', tarball: 'https://registry.npmjs.org/package.tgz' } },
+      {
+        dist: {
+          integrity: `sha512-${Buffer.alloc(64).toString('base64')}`,
+          tarball: 'https://private.example/package.tgz',
+        },
+      },
+    ]) {
+      globalThis.fetch = async (url) => {
+        const name = decodeURIComponent(new URL(url).pathname.slice(1));
+        const version = dependencies[name];
+        return Response.json({
+          versions: {
+            [version]: {
+              name,
+              version,
+              dist: {
+                integrity: `sha512-${Buffer.alloc(64).toString('base64')}`,
+                tarball: 'https://registry.npmjs.org/package.tgz',
+              },
+              ...mutation,
+            },
+          },
+        });
+      };
+      await assert.rejects(
+        publishedConsumerInventory(['oliphaunt-js']),
+        /invalid published npm dependency metadata/,
+      );
+    }
+  } finally {
+    globalThis.fetch = originalFetch;
+  }
+});
+
+test('published install isolates credentials, scoped configuration and injected runtime options', () => {
+  const destination = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-published-environment-'));
+  try {
+    const env = preparePublishedConsumerEnvironment(destination, {
+      PATH: '/bin',
+      HOME: '/private-home',
+      XDG_CONFIG_HOME: '/private-config',
+      NPM_TOKEN: 'secret',
+      NODE_AUTH_TOKEN: 'secret',
+      npm_config_userconfig: '/private-npmrc',
+      NPM_CONFIG_REGISTRY: 'https://private.example',
+      BUN_CONFIG: '/private-bunfig',
+      BUN_INSTALL: '/private-bun',
+      NODE_OPTIONS: '--require /private-hook.js',
+    });
+    assert.equal(env.PATH, '/bin');
+    for (const name of [
+      'NPM_TOKEN',
+      'NODE_AUTH_TOKEN',
+      'npm_config_userconfig',
+      'BUN_CONFIG',
+      'BUN_INSTALL',
+      'NODE_OPTIONS',
+    ])
+      assert.equal(env[name], undefined);
+    assert.equal(env.HOME, path.join(destination, 'install-home'));
+    assert.equal(env.XDG_CONFIG_HOME, env.HOME);
+    assert.equal(
+      readFileSync(env.NPM_CONFIG_USERCONFIG, 'utf8'),
+      'registry=https://registry.npmjs.org/\nalways-auth=false\n',
+    );
+    assert.equal(
+      readFileSync(env.NPM_CONFIG_GLOBALCONFIG, 'utf8'),
+      readFileSync(env.NPM_CONFIG_USERCONFIG, 'utf8'),
+    );
+    assert(!readFileSync(path.join(destination, 'install-environment'), 'utf8').includes('secret'));
+  } finally {
+    rmSync(destination, { recursive: true, force: true });
+  }
+});
+
+test('installed published dependencies must retain the candidate pins and registry integrity', () => {
+  const destination = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-published-consumer-'));
+  try {
+    const manifest = JSON.parse(
+      readFileSync(path.join(import.meta.dir, '../package.json'), 'utf8'),
+    );
+    const writePackage = (name, data) => {
+      const directory = path.join(destination, 'node_modules', name);
+      mkdirSync(directory, { recursive: true });
+      writeFileSync(path.join(directory, 'package.json'), JSON.stringify(data));
+    };
+    writePackage('@oliphaunt/ts', manifest);
+    const inventory = Object.entries(publishedConsumerDependencies(manifest)).map(
+      ([name, version]) => ({
+        name,
+        version,
+        integrity: `sha512-${Buffer.alloc(64, 7).toString('base64')}`,
+        tarball: `https://registry.npmjs.org/${name}/-/package.tgz`,
+      }),
+    );
+    const lock = {
+      packages: Object.fromEntries(
+        inventory.map((row) => [row.name, [`${row.name}@${row.version}`, '', {}, row.integrity]]),
+      ),
+    };
+    for (const row of inventory) writePackage(row.name, { name: row.name, version: row.version });
+    const writeLock = () => writeFileSync(path.join(destination, 'bun.lock'), JSON.stringify(lock));
+    writeLock();
+    verifyPublishedConsumerInstall(destination, inventory);
+    const first = inventory[0];
+    lock.packages[first.name][3] = `sha512-${Buffer.alloc(64, 8).toString('base64')}`;
+    writeLock();
+    assert.throws(
+      () => verifyPublishedConsumerInstall(destination, inventory),
+      /integrity mismatch/,
+    );
+    lock.packages[first.name][3] = first.integrity;
+    lock.packages[first.name][1] = 'https://private.example/package.tgz';
+    writeLock();
+    assert.throws(
+      () => verifyPublishedConsumerInstall(destination, inventory),
+      /integrity mismatch/,
+    );
+    lock.packages[first.name][1] = '';
+    writeLock();
+    writePackage(first.name, { name: first.name, version: '999.0.0' });
+    assert.throws(
+      () => verifyPublishedConsumerInstall(destination, inventory),
+      /identity\/integrity mismatch/,
+    );
+    assert.throws(
+      () => verifyPublishedConsumerInstall(destination, inventory.slice(1)),
+      /does not match the candidate SDK/,
+    );
+  } finally {
+    rmSync(destination, { recursive: true, force: true });
+  }
+});
diff --git a/src/sdks/ts/sdk/tools/stage-release-artifacts.sh b/src/sdks/ts/sdk/tools/stage-release-artifacts.sh
new file mode 100644
index 000000000..d58afb71a
--- /dev/null
+++ b/src/sdks/ts/sdk/tools/stage-release-artifacts.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+artifact_root="$PWD/target/sdk-artifacts/oliphaunt-js"
+work_root="$PWD/target/sdk-artifacts-work/oliphaunt-js"
+rm -rf "$artifact_root" "$work_root"
+mkdir -p "$artifact_root" "$work_root/package"
+rsync -a --exclude node_modules src/sdks/ts/sdk/ "$work_root/package/"
+cp LICENSE THIRD_PARTY_NOTICES.md "$work_root/package/"
+bun tools/packaging/source-only-sdk-package.mts prepare-npm js "$work_root/package"
+filename="$(bun tools/packaging/npm-package.mts "$work_root/package")"
+archive="$artifact_root/$filename"
+bun pm pack --cwd "$work_root/package" --filename "$archive"
+
+bun tools/packaging/staging.mts "$artifact_root"
diff --git a/src/sdks/ts/sdk/tools/test-consumer.sh b/src/sdks/ts/sdk/tools/test-consumer.sh
new file mode 100644
index 000000000..372be4e48
--- /dev/null
+++ b/src/sdks/ts/sdk/tools/test-consumer.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(git rev-parse --show-toplevel)"
+cd "$root"
+[[ "$(uname -s):$(uname -m)" == Linux:x86_64 ]] || {
+  echo 'the packed SDK consumer uses Linux x64 artifacts; run test-native for host source behavior' >&2
+  exit 2
+}
+consumer="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-ts-consumer.XXXXXX")"
+trap 'rm -rf "$consumer"' EXIT HUP INT TERM
+bun src/sdks/ts/sdk/tools/prepare-consumer.mts "$consumer" "${1:-}"
+if [[ "${1:-}" == --published-dependencies ]]; then
+  clean=(env -i)
+  while IFS= read -r -d '' entry; do clean+=("$entry"); done < "$consumer/install-environment"
+  "${clean[@]}" bun install --cwd "$consumer" --ignore-scripts --omit optional --registry https://registry.npmjs.org --cache-dir "$consumer/cache"
+else
+  bun install --cwd "$consumer" --ignore-scripts --omit optional
+fi
+cp src/sdks/ts/sdk/tools/entrypoint-consumer.mts "$consumer/entrypoints.mts"
+bun src/sdks/ts/sdk/node_modules/typescript/bin/tsc --ignoreConfig --noEmit --strict --skipLibCheck \
+  --target ES2022 --module NodeNext --types node \
+  --typeRoots "$root/src/sdks/ts/sdk/node_modules/@types" "$consumer/entrypoints.mts"
+bun "$consumer/entrypoints.mts"
+export OLIPHAUNT_SMOKE_SDK="$consumer/node_modules/@oliphaunt/ts/lib/index.js"
+if [[ "${1:-}" == --published-dependencies ]]; then
+  bun src/sdks/ts/sdk/tools/published-consumer.mts "$consumer"
+  export LIBOLIPHAUNT_PATH="$consumer/node_modules/@oliphaunt/liboliphaunt-linux-x64-gnu/lib/liboliphaunt.so"
+  export OLIPHAUNT_INSTALL_DIR="$consumer/node_modules/@oliphaunt/liboliphaunt-linux-x64-gnu/runtime"
+  export OLIPHAUNT_BROKER="$consumer/node_modules/@oliphaunt/broker-linux-x64-gnu/bin/oliphaunt-broker"
+  export OLIPHAUNT_NODE_ADDON="$consumer/node_modules/@oliphaunt/node-direct-linux-x64-gnu/prebuilds/oliphaunt_node.node"
+else
+export LIBOLIPHAUNT_PATH="$consumer/runtime/lib/liboliphaunt.so"
+export OLIPHAUNT_INSTALL_DIR="$consumer/runtime/runtime"
+export OLIPHAUNT_BROKER="$consumer/broker/bin/oliphaunt-broker"
+export OLIPHAUNT_NODE_ADDON="$consumer/addon/oliphaunt_node.node"
+fi
+export OLIPHAUNT_RUNTIME_DIR="$OLIPHAUNT_INSTALL_DIR"
+bash src/sdks/ts/sdk/tools/test-native.sh
diff --git a/src/sdks/ts/sdk/tools/test-native.sh b/src/sdks/ts/sdk/tools/test-native.sh
new file mode 100755
index 000000000..3acc60476
--- /dev/null
+++ b/src/sdks/ts/sdk/tools/test-native.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel)"
+cd "$root"
+
+. src/runtimes/liboliphaunt-native/tools/runtime-preflight.sh
+oliphaunt_runtime_native_host_export_defaults
+
+case "$(uname -s)" in
+  MINGW* | MSYS* | CYGWIN*) broker_name="oliphaunt-broker.exe" ;;
+  *) broker_name="oliphaunt-broker" ;;
+esac
+export OLIPHAUNT_BROKER="${OLIPHAUNT_BROKER:-$root/target/debug/$broker_name}"
+export OLIPHAUNT_NODE_ADDON="${OLIPHAUNT_NODE_ADDON:-$root/target/oliphaunt-node-direct/native/oliphaunt_node.node}"
+export OLIPHAUNT_RUNTIME_DIR="${OLIPHAUNT_RUNTIME_DIR:-$OLIPHAUNT_INSTALL_DIR}"
+
+test -x "$OLIPHAUNT_BROKER"
+test -f "$OLIPHAUNT_NODE_ADDON"
+OLIPHAUNT_SMOKE_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-js-smoke.XXXXXX")"
+export OLIPHAUNT_SMOKE_ROOT
+trap 'rm -rf "$OLIPHAUNT_SMOKE_ROOT"' EXIT HUP INT TERM
+# A direct backend remains bound to its root until the host process exits.
+for host in node bun deno; do
+  export OLIPHAUNT_SMOKE_HOST="$host"
+  for OLIPHAUNT_SMOKE_PHASE in source restored; do
+    export OLIPHAUNT_SMOKE_PHASE
+    printf 'Checking %s native SDK (%s)\n' "$host" "$OLIPHAUNT_SMOKE_PHASE"
+    case "$host" in
+      node) node --experimental-strip-types src/sdks/ts/sdk/src/__tests__/native-smoke.mts ;;
+      bun) bun src/sdks/ts/sdk/src/__tests__/native-smoke.mts ;;
+      deno) deno run --no-config --node-modules-dir=manual --allow-all src/sdks/ts/sdk/src/__tests__/native-smoke.mts ;;
+    esac
+  done
+done
+bun src/sdks/ts/sdk/src/__tests__/native-server-smoke.ts
diff --git a/src/sdks/js/tsconfig.build.json b/src/sdks/ts/sdk/tsconfig.build.json
similarity index 100%
rename from src/sdks/js/tsconfig.build.json
rename to src/sdks/ts/sdk/tsconfig.build.json
diff --git a/src/sdks/ts/sdk/tsconfig.json b/src/sdks/ts/sdk/tsconfig.json
new file mode 100644
index 000000000..3683686dc
--- /dev/null
+++ b/src/sdks/ts/sdk/tsconfig.json
@@ -0,0 +1,20 @@
+{
+  "compilerOptions": {
+    "declaration": true,
+    "declarationMap": true,
+    "lib": ["ES2023", "DOM"],
+    "module": "NodeNext",
+    "moduleResolution": "NodeNext",
+    "noEmit": true,
+    "noUncheckedIndexedAccess": true,
+    "outDir": "lib",
+    "rewriteRelativeImportExtensions": true,
+    "rootDir": "src",
+    "skipLibCheck": true,
+    "strict": true,
+    "target": "ES2022",
+    "types": ["node", "bun"]
+  },
+  "include": ["src/**/*.ts"],
+  "exclude": ["lib", "node_modules"]
+}
diff --git a/src/shared/artifact-packaging/archive-directory.mjs b/src/shared/artifact-packaging/archive-directory.mjs
deleted file mode 100755
index 390646291..000000000
--- a/src/shared/artifact-packaging/archive-directory.mjs
+++ /dev/null
@@ -1,341 +0,0 @@
-#!/usr/bin/env node
-import { deflateRawSync } from 'node:zlib';
-import fs from 'node:fs/promises';
-import path from 'node:path';
-import process from 'node:process';
-import { fileURLToPath } from 'node:url';
-
-import {
-  canonicalGzipSync,
-  releaseZstdCompressSync,
-} from './portable-archive.mjs';
-
-function fail(message) {
-  throw new Error(`archive-directory.mjs: ${message}`);
-}
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function normalizedMode(stat, isDirectory) {
-  if (isDirectory) {
-    return 0o755;
-  }
-  return stat.mode & 0o100 ? 0o755 : 0o644;
-}
-
-function posixRelative(root, item) {
-  const relative = path.relative(root, item).split(path.sep).join('/');
-  return relative === '' ? '.' : relative;
-}
-
-function archiveEntryName(root, item, keepParent) {
-  const relative = posixRelative(root, item);
-  if (!keepParent) {
-    return relative;
-  }
-  const parent = path.basename(root);
-  if (!parent || parent === '.' || parent === '..' || parent.includes('/') || parent.includes('\\')) {
-    fail(`source directory has an unsafe archive parent name: ${root}`);
-  }
-  return relative === '.' ? parent : `${parent}/${relative}`;
-}
-
-async function archiveEntries(root, { keepParent = false } = {}) {
-  const rootStat = await fs.lstat(root);
-  if (!rootStat.isDirectory()) {
-    fail(`source is not a real directory: ${root}`);
-  }
-  const entries = [{
-    fullPath: root,
-    name: archiveEntryName(root, root, keepParent),
-    isDirectory: true,
-    stat: rootStat,
-  }];
-
-  async function walk(directory) {
-    const dirents = await fs.readdir(directory, { withFileTypes: true });
-    const directories = [];
-    const files = [];
-    for (const entry of dirents) {
-      const fullPath = path.join(directory, entry.name);
-      const stat = await fs.lstat(fullPath);
-      if (stat.isSymbolicLink()) {
-        fail(`source tree contains a symbolic link: ${fullPath}`);
-      }
-      if (stat.isDirectory()) {
-        directories.push({ entry, fullPath, stat });
-      } else if (stat.isFile()) {
-        files.push({ entry, fullPath, stat });
-      } else {
-        fail(`source tree contains an unsupported special entry: ${fullPath}`);
-      }
-    }
-    directories.sort((left, right) => compareText(left.entry.name, right.entry.name));
-    files.sort((left, right) => compareText(left.entry.name, right.entry.name));
-    for (const entry of directories) {
-      entries.push({
-        fullPath: entry.fullPath,
-        name: archiveEntryName(root, entry.fullPath, keepParent),
-        isDirectory: true,
-        stat: entry.stat,
-      });
-    }
-    for (const entry of files) {
-      entries.push({
-        fullPath: entry.fullPath,
-        name: archiveEntryName(root, entry.fullPath, keepParent),
-        isDirectory: false,
-        stat: entry.stat,
-      });
-    }
-    for (const entry of directories) {
-      await walk(entry.fullPath);
-    }
-  }
-
-  await walk(root);
-  return entries;
-}
-
-function tarPathParts(relativePath) {
-  if (Buffer.byteLength(relativePath) <= 100) {
-    return { name: relativePath, prefix: '' };
-  }
-  const parts = relativePath.split('/');
-  for (let index = 1; index < parts.length; index += 1) {
-    const prefix = parts.slice(0, index).join('/');
-    const name = parts.slice(index).join('/');
-    if (name.length > 0 && Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) {
-      return { name, prefix };
-    }
-  }
-  fail(`archive path is too long for ustar: ${relativePath}`);
-}
-
-function writeString(buffer, offset, length, value) {
-  const bytes = Buffer.from(value);
-  if (bytes.length > length) {
-    fail(`tar header field overflow for '${value}'`);
-  }
-  bytes.copy(buffer, offset);
-}
-
-function writeOctal(buffer, offset, length, value) {
-  const text = value.toString(8);
-  if (text.length > length - 1) {
-    fail(`tar header octal field overflow for '${value}'`);
-  }
-  writeString(buffer, offset, length, `${text.padStart(length - 1, '0')}\0`);
-}
-
-function tarHeader(entry, size, mode) {
-  const header = Buffer.alloc(512, 0);
-  // POSIX identifies directories with typeflag `5`, but a trailing slash is
-  // the portable path spelling expected by archive listing tools and package
-  // consumers. Keep the root marker as `.` and canonicalize every other
-  // directory entry at the producer boundary.
-  const archiveName = entry.isDirectory && entry.name !== '.' ? `${entry.name}/` : entry.name;
-  const { name, prefix } = tarPathParts(archiveName);
-  writeString(header, 0, 100, name);
-  writeOctal(header, 100, 8, mode);
-  writeOctal(header, 108, 8, 0);
-  writeOctal(header, 116, 8, 0);
-  writeOctal(header, 124, 12, size);
-  writeOctal(header, 136, 12, 0);
-  header.fill(0x20, 148, 156);
-  writeString(header, 156, 1, entry.isDirectory ? '5' : '0');
-  writeString(header, 257, 6, 'ustar\0');
-  writeString(header, 263, 2, '00');
-  writeString(header, 345, 155, prefix);
-  let checksum = 0;
-  for (const byte of header) {
-    checksum += byte;
-  }
-  const checksumText = checksum.toString(8);
-  if (checksumText.length > 6) {
-    fail(`tar header checksum overflow for ${entry.name}`);
-  }
-  writeString(header, 148, 8, `${checksumText.padStart(6, '0')}\0 `);
-  return header;
-}
-
-export async function createDeterministicTar(root, options = {}) {
-  const chunks = [];
-  for (const entry of await archiveEntries(root, options)) {
-    const stat = entry.stat;
-    const mode = normalizedMode(stat, entry.isDirectory);
-    const data = entry.isDirectory ? Buffer.alloc(0) : await fs.readFile(entry.fullPath);
-    chunks.push(tarHeader(entry, data.length, mode));
-    if (data.length > 0) {
-      chunks.push(data);
-      const remainder = data.length % 512;
-      if (remainder !== 0) {
-        chunks.push(Buffer.alloc(512 - remainder, 0));
-      }
-    }
-  }
-  chunks.push(Buffer.alloc(1024, 0));
-  return Buffer.concat(chunks);
-}
-
-const crcTable = new Uint32Array(256);
-for (let index = 0; index < crcTable.length; index += 1) {
-  let value = index;
-  for (let bit = 0; bit < 8; bit += 1) {
-    value = value & 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1;
-  }
-  crcTable[index] = value >>> 0;
-}
-
-function crc32(data) {
-  let crc = 0xffffffff;
-  for (const byte of data) {
-    crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8);
-  }
-  return (crc ^ 0xffffffff) >>> 0;
-}
-
-function dosDateTime() {
-  return {
-    time: 0,
-    date: ((1980 - 1980) << 9) | (1 << 5) | 1,
-  };
-}
-
-function writeUInt16(value) {
-  const buffer = Buffer.alloc(2);
-  buffer.writeUInt16LE(value);
-  return buffer;
-}
-
-function writeUInt32(value) {
-  const buffer = Buffer.alloc(4);
-  buffer.writeUInt32LE(value >>> 0);
-  return buffer;
-}
-
-function zipName(entry) {
-  return entry.isDirectory && entry.name !== '.' ? `${entry.name}/` : entry.name;
-}
-
-export async function createDeterministicZip(root, options = {}) {
-  const localChunks = [];
-  const centralChunks = [];
-  let offset = 0;
-  const { time, date } = dosDateTime();
-
-  for (const entry of await archiveEntries(root, options)) {
-    if (entry.name === '.') {
-      continue;
-    }
-    const stat = entry.stat;
-    const mode = normalizedMode(stat, entry.isDirectory);
-    const name = Buffer.from(zipName(entry));
-    const data = entry.isDirectory ? Buffer.alloc(0) : await fs.readFile(entry.fullPath);
-    const compressed = entry.isDirectory ? Buffer.alloc(0) : deflateRawSync(data, { level: 9 });
-    const method = entry.isDirectory ? 0 : 8;
-    const crc = crc32(data);
-    // A Unix-origin ZIP must include the POSIX file type as well as permission
-    // bits. Omitting S_IFREG/S_IFDIR makes the central directory ambiguous to
-    // strict consumers and causes platform-dependent `zipinfo` rendering.
-    const unixMode = (entry.isDirectory ? 0o040000 : 0o100000) | (mode & 0o777);
-    const externalAttributes = (unixMode << 16) | (entry.isDirectory ? 0x10 : 0);
-    const localHeader = Buffer.concat([
-      writeUInt32(0x04034b50),
-      writeUInt16(20),
-      writeUInt16(0),
-      writeUInt16(method),
-      writeUInt16(time),
-      writeUInt16(date),
-      writeUInt32(crc),
-      writeUInt32(compressed.length),
-      writeUInt32(data.length),
-      writeUInt16(name.length),
-      writeUInt16(0),
-      name,
-    ]);
-    localChunks.push(localHeader, compressed);
-    centralChunks.push(
-      Buffer.concat([
-        writeUInt32(0x02014b50),
-        writeUInt16((3 << 8) | 20),
-        writeUInt16(20),
-        writeUInt16(0),
-        writeUInt16(method),
-        writeUInt16(time),
-        writeUInt16(date),
-        writeUInt32(crc),
-        writeUInt32(compressed.length),
-        writeUInt32(data.length),
-        writeUInt16(name.length),
-        writeUInt16(0),
-        writeUInt16(0),
-        writeUInt16(0),
-        writeUInt16(0),
-        writeUInt32(externalAttributes),
-        writeUInt32(offset),
-        name,
-      ]),
-    );
-    offset += localHeader.length + compressed.length;
-  }
-
-  const centralDirectory = Buffer.concat(centralChunks);
-  const end = Buffer.concat([
-    writeUInt32(0x06054b50),
-    writeUInt16(0),
-    writeUInt16(0),
-    writeUInt16(centralChunks.length),
-    writeUInt16(centralChunks.length),
-    writeUInt32(centralDirectory.length),
-    writeUInt32(offset),
-    writeUInt16(0),
-  ]);
-  return Buffer.concat([...localChunks, centralDirectory, end]);
-}
-
-function parseArgs(argv) {
-  const values = [...argv];
-  let keepParent = false;
-  if (values[0] === '--keep-parent') {
-    keepParent = true;
-    values.shift();
-  }
-  if (values.length !== 2) {
-    fail('usage: src/shared/artifact-packaging/archive-directory.mjs [--keep-parent]  ');
-  }
-  return {
-    keepParent,
-    source: path.resolve(values[0]),
-    output: path.resolve(values[1]),
-  };
-}
-
-async function main(argv) {
-  const { keepParent, source, output } = parseArgs(argv);
-  const sourceStat = await fs.lstat(source).catch(() => null);
-  if (!sourceStat?.isDirectory()) {
-    fail(`source is not a directory: ${source}`);
-  }
-  await fs.mkdir(path.dirname(output), { recursive: true });
-  if (output.endsWith('.tar.gz')) {
-    await fs.writeFile(output, canonicalGzipSync(await createDeterministicTar(source, { keepParent })));
-  } else if (output.endsWith('.tar.zst')) {
-    await fs.writeFile(output, releaseZstdCompressSync(await createDeterministicTar(source, { keepParent })));
-  } else if (path.extname(output) === '.zip') {
-    await fs.writeFile(output, await createDeterministicZip(source, { keepParent }));
-  } else {
-    fail(`unsupported archive extension: ${output}`);
-  }
-}
-
-if (process.argv[1] !== undefined && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
-  try {
-    await main(process.argv.slice(2));
-  } catch (cause) {
-    console.error(cause instanceof Error ? cause.message : String(cause));
-    process.exit(2);
-  }
-}
diff --git a/src/shared/artifact-packaging/archive-directory.test.mjs b/src/shared/artifact-packaging/archive-directory.test.mjs
deleted file mode 100644
index 980219c77..000000000
--- a/src/shared/artifact-packaging/archive-directory.test.mjs
+++ /dev/null
@@ -1,259 +0,0 @@
-#!/usr/bin/env node
-
-import assert from "node:assert/strict";
-import { spawnSync } from "node:child_process";
-import { createHash } from "node:crypto";
-import {
-  chmodSync,
-  mkdirSync,
-  mkdtempSync,
-  readFileSync,
-  rmSync,
-  symlinkSync,
-  writeFileSync,
-} from "node:fs";
-import { tmpdir } from "node:os";
-import path from "node:path";
-import test from "node:test";
-import { gunzipSync, zstdDecompressSync } from "node:zlib";
-
-const ARCHIVER = path.resolve(import.meta.dirname, "archive-directory.mjs");
-
-function run(command, args) {
-  const result = spawnSync(command, args, { encoding: "utf8" });
-  assert.equal(result.status, 0, `${command} ${args.join(" ")} failed:\n${result.stderr || result.stdout}`);
-}
-
-function runFailure(command, args) {
-  const result = spawnSync(command, args, { encoding: "utf8" });
-  assert.notEqual(result.status, 0, `${command} ${args.join(" ")} unexpectedly succeeded`);
-  return `${result.stderr}${result.stdout}`;
-}
-
-function tarString(buffer, offset, length) {
-  const end = buffer.indexOf(0, offset);
-  return buffer.subarray(offset, end >= offset && end < offset + length ? end : offset + length).toString("utf8");
-}
-
-function tarOctal(buffer, offset, length) {
-  const value = tarString(buffer, offset, length).trim();
-  return value ? Number.parseInt(value, 8) : 0;
-}
-
-function entries(archive) {
-  const compressed = readFileSync(archive);
-  const buffer = archive.endsWith(".tar.zst")
-    ? zstdDecompressSync(compressed)
-    : gunzipSync(compressed);
-  const rows = [];
-  for (let offset = 0; offset + 512 <= buffer.length;) {
-    const header = buffer.subarray(offset, offset + 512);
-    if (header.every((byte) => byte === 0)) break;
-    const name = tarString(header, 0, 100);
-    const prefix = tarString(header, 345, 155);
-    const size = tarOctal(header, 124, 12);
-    rows.push({
-      headerName: name,
-      name: prefix ? `${prefix}/${name}` : name,
-      prefix,
-      type: tarString(header, 156, 1),
-    });
-    offset += 512 + Math.ceil(size / 512) * 512;
-  }
-  return rows;
-}
-
-function digest(file) {
-  return createHash("sha256").update(readFileSync(file)).digest("hex");
-}
-
-function zipEntries(archive) {
-  const buffer = readFileSync(archive);
-  let eocd = -1;
-  for (let offset = buffer.length - 22; offset >= Math.max(0, buffer.length - 65_557); offset -= 1) {
-    if (
-      buffer.readUInt32LE(offset) === 0x06054b50
-      && offset + 22 + buffer.readUInt16LE(offset + 20) === buffer.length
-    ) {
-      eocd = offset;
-      break;
-    }
-  }
-  assert.notEqual(eocd, -1, "ZIP must have an exact end-of-central-directory record");
-  const count = buffer.readUInt16LE(eocd + 10);
-  const size = buffer.readUInt32LE(eocd + 12);
-  const start = buffer.readUInt32LE(eocd + 16);
-  assert.equal(start + size, eocd, "ZIP central directory must end at the EOCD");
-  const rows = [];
-  let offset = start;
-  for (let index = 0; index < count; index += 1) {
-    assert.equal(buffer.readUInt32LE(offset), 0x02014b50, `missing central entry ${index}`);
-    const versionMadeBy = buffer.readUInt16LE(offset + 4);
-    const nameLength = buffer.readUInt16LE(offset + 28);
-    const extraLength = buffer.readUInt16LE(offset + 30);
-    const commentLength = buffer.readUInt16LE(offset + 32);
-    const externalAttributes = buffer.readUInt32LE(offset + 38);
-    const nameStart = offset + 46;
-    rows.push({
-      commentLength,
-      date: buffer.readUInt16LE(offset + 14),
-      dosDirectory: (externalAttributes & 0x10) !== 0,
-      extraLength,
-      host: versionMadeBy >>> 8,
-      mode: externalAttributes >>> 16,
-      name: buffer.subarray(nameStart, nameStart + nameLength).toString("utf8"),
-      time: buffer.readUInt16LE(offset + 12),
-    });
-    offset = nameStart + nameLength + extraLength + commentLength;
-  }
-  assert.equal(offset, eocd, "ZIP central directory must contain only declared entries");
-  return rows;
-}
-
-test("writes deterministic canonical ustar directory markers", () => {
-  const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-archive-dir-"));
-  try {
-    const source = path.join(root, "source");
-    mkdirSync(path.join(source, "nested", "child"), { recursive: true });
-    const longParent = "parent".repeat(14);
-    const longChild = "child".repeat(7);
-    mkdirSync(path.join(source, longParent, longChild), { recursive: true });
-    writeFileSync(path.join(source, "nested", "child", "payload.txt"), "payload\n");
-    writeFileSync(path.join(source, "top.txt"), "top\n");
-    const first = path.join(root, "first.tar.gz");
-    const second = path.join(root, "second.tar.gz");
-    const firstZstd = path.join(root, "first.tar.zst");
-    const secondZstd = path.join(root, "second.tar.zst");
-    run(process.execPath, [ARCHIVER, source, first]);
-    run(process.execPath, [ARCHIVER, source, second]);
-    run(process.execPath, [ARCHIVER, source, firstZstd]);
-    run(process.execPath, [ARCHIVER, source, secondZstd]);
-
-    assert.equal(digest(first), digest(second), "archive output must be byte-for-byte deterministic");
-    assert.equal(
-      digest(firstZstd),
-      digest(secondZstd),
-      "Zstandard archive output must be byte-for-byte deterministic",
-    );
-    assert.equal(
-      readFileSync(first).subarray(0, 10).toString("hex"),
-      "1f8b0800000000000003",
-      "tar.gz output must use the canonical cross-platform gzip header",
-    );
-    const expectedEntries = [
-      { headerName: ".", name: ".", prefix: "", type: "5" },
-      { headerName: "nested/", name: "nested/", prefix: "", type: "5" },
-      { headerName: `${longParent}/`, name: `${longParent}/`, prefix: "", type: "5" },
-      { headerName: "top.txt", name: "top.txt", prefix: "", type: "0" },
-      { headerName: "nested/child/", name: "nested/child/", prefix: "", type: "5" },
-      { headerName: "nested/child/payload.txt", name: "nested/child/payload.txt", prefix: "", type: "0" },
-      { headerName: `${longChild}/`, name: `${longParent}/${longChild}/`, prefix: longParent, type: "5" },
-    ];
-    assert.deepEqual(entries(first), expectedEntries);
-    assert.deepEqual(entries(firstZstd), expectedEntries);
-    assert.equal(
-      readFileSync(firstZstd).subarray(0, 4).toString("hex"),
-      "28b52ffd",
-      "tar.zst output must be a Zstandard frame",
-    );
-
-    const extracted = path.join(root, "extracted");
-    mkdirSync(extracted);
-    run("tar", ["-xzf", first, "-C", extracted]);
-    assert.equal(readFileSync(path.join(extracted, "nested", "child", "payload.txt"), "utf8"), "payload\n");
-
-    const unsplittable = path.join(root, "unsplittable");
-    mkdirSync(path.join(unsplittable, "x".repeat(100)), { recursive: true });
-    assert.match(
-      runFailure(process.execPath, [ARCHIVER, unsplittable, path.join(root, "unsplittable.tar.gz")]),
-      /archive path is too long for ustar/u,
-    );
-  } finally {
-    rmSync(root, { force: true, recursive: true });
-  }
-});
-
-test("writes deterministic keep-parent ZIPs with unambiguous Unix member types", () => {
-  const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-archive-dir-zip-"));
-  try {
-    const source = path.join(root, "Fixture.xcframework");
-    mkdirSync(path.join(source, "ios-arm64"), { recursive: true });
-    writeFileSync(path.join(source, "Info.plist"), "\n");
-    const library = path.join(source, "ios-arm64", "libFixture");
-    writeFileSync(library, "library\n");
-    chmodSync(library, 0o755);
-    const first = path.join(root, "first.zip");
-    const second = path.join(root, "second.zip");
-    run(process.execPath, [ARCHIVER, "--keep-parent", source, first]);
-    run(process.execPath, [ARCHIVER, "--keep-parent", source, second]);
-
-    assert.equal(digest(first), digest(second), "ZIP output must be byte-for-byte deterministic");
-    assert.deepEqual(zipEntries(first), [
-      {
-        commentLength: 0,
-        date: 33,
-        dosDirectory: true,
-        extraLength: 0,
-        host: 3,
-        mode: 0o040755,
-        name: "Fixture.xcframework/",
-        time: 0,
-      },
-      {
-        commentLength: 0,
-        date: 33,
-        dosDirectory: true,
-        extraLength: 0,
-        host: 3,
-        mode: 0o040755,
-        name: "Fixture.xcframework/ios-arm64/",
-        time: 0,
-      },
-      {
-        commentLength: 0,
-        date: 33,
-        dosDirectory: false,
-        extraLength: 0,
-        host: 3,
-        mode: 0o100644,
-        name: "Fixture.xcframework/Info.plist",
-        time: 0,
-      },
-      {
-        commentLength: 0,
-        date: 33,
-        dosDirectory: false,
-        extraLength: 0,
-        host: 3,
-        mode: 0o100755,
-        name: "Fixture.xcframework/ios-arm64/libFixture",
-        time: 0,
-      },
-    ]);
-  } finally {
-    rmSync(root, { force: true, recursive: true });
-  }
-});
-
-test("rejects symbolic links instead of silently dereferencing release inputs", () => {
-  const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-archive-dir-link-"));
-  try {
-    const source = path.join(root, "source");
-    mkdirSync(source);
-    writeFileSync(path.join(source, "payload"), "payload\n");
-    symlinkSync("payload", path.join(source, "payload-link"));
-
-    for (const output of [
-      path.join(root, "output.tar.gz"),
-      path.join(root, "output.tar.zst"),
-      path.join(root, "output.zip"),
-    ]) {
-      assert.match(
-        runFailure(process.execPath, [ARCHIVER, source, output]),
-        /source tree contains a symbolic link/u,
-      );
-    }
-  } finally {
-    rmSync(root, { force: true, recursive: true });
-  }
-});
diff --git a/src/shared/artifact-packaging/materialize-release-symlinks.mjs b/src/shared/artifact-packaging/materialize-release-symlinks.mjs
deleted file mode 100644
index 99cbf91e0..000000000
--- a/src/shared/artifact-packaging/materialize-release-symlinks.mjs
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/env node
-
-import { randomUUID } from "node:crypto";
-import { constants } from "node:fs";
-import {
-  chmod,
-  copyFile,
-  lstat,
-  readlink,
-  readdir,
-  rename,
-  rm,
-  symlink,
-  utimes,
-} from "node:fs/promises";
-import path from "node:path";
-import process from "node:process";
-import { fileURLToPath } from "node:url";
-
-const TOOL = "materialize-release-symlinks.mjs";
-
-function fail(message) {
-  throw new Error(`${TOOL}: ${message}`);
-}
-
-function compareText(left, right) {
-  return left < right ? -1 : left > right ? 1 : 0;
-}
-
-function isInside(root, candidate) {
-  const relative = path.relative(root, candidate);
-  return relative === ""
-    || (!path.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path.sep}`));
-}
-
-async function requiredLstat(file, context) {
-  try {
-    return await lstat(file);
-  } catch (error) {
-    fail(`${context}: ${error.message}`);
-  }
-}
-
-async function collectSymlinks(root, directory = root, links = []) {
-  const entries = (await readdir(directory)).sort(compareText);
-  for (const name of entries) {
-    const file = path.join(directory, name);
-    const stat = await requiredLstat(file, `cannot inspect ${file}`);
-    if (stat.isSymbolicLink()) {
-      links.push(file);
-    } else if (stat.isDirectory()) {
-      await collectSymlinks(root, file, links);
-    }
-  }
-  return links;
-}
-
-async function resolveRegularTarget(root, link) {
-  let current = link;
-  const visited = new Set([current]);
-
-  while (true) {
-    const target = await readlink(current);
-    if (target.length === 0 || path.isAbsolute(target) || path.win32.isAbsolute(target)) {
-      fail(`${link} must use only relative symbolic-link targets`);
-    }
-    const next = path.resolve(path.dirname(current), target);
-    if (!isInside(root, next)) {
-      fail(`${link} escapes the staged release tree through ${JSON.stringify(target)}`);
-    }
-    const stat = await requiredLstat(next, `${link} has a broken symbolic-link target`);
-    if (stat.isSymbolicLink()) {
-      if (visited.has(next)) {
-        fail(`${link} contains a symbolic-link cycle`);
-      }
-      visited.add(next);
-      current = next;
-      continue;
-    }
-    if (!stat.isFile()) {
-      fail(`${link} must resolve to a regular file, not a directory or special file`);
-    }
-    return { file: next, stat };
-  }
-}
-
-async function cleanupTemps(plans) {
-  await Promise.all(plans.map(({ temp }) => rm(temp, { force: true }).catch(() => {})));
-}
-
-export async function materializeReleaseSymlinks(rootInput) {
-  if (typeof rootInput !== "string" || rootInput.length === 0 || rootInput.includes("\0")) {
-    fail("a staged release root is required");
-  }
-  const root = path.resolve(rootInput);
-  const rootStat = await requiredLstat(root, `cannot inspect staged release root ${root}`);
-  if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
-    fail(`staged release root must be a real directory: ${root}`);
-  }
-
-  const links = await collectSymlinks(root);
-  const plans = [];
-  for (const link of links) {
-    const originalTarget = await readlink(link);
-    const resolved = await resolveRegularTarget(root, link);
-    plans.push({
-      link,
-      originalTarget,
-      source: resolved.file,
-      sourceStat: resolved.stat,
-      temp: path.join(path.dirname(link), `.${path.basename(link)}.materialize-${randomUUID()}.tmp`),
-    });
-  }
-
-  try {
-    for (const plan of plans) {
-      await copyFile(plan.source, plan.temp, constants.COPYFILE_EXCL);
-      await chmod(plan.temp, plan.sourceStat.mode & 0o777);
-      await utimes(plan.temp, plan.sourceStat.atime, plan.sourceStat.mtime);
-    }
-  } catch (error) {
-    await cleanupTemps(plans);
-    fail(`could not stage verified symbolic-link replacements: ${error.message}`);
-  }
-
-  const committed = [];
-  try {
-    for (const plan of plans) {
-      const currentStat = await requiredLstat(plan.link, `cannot revalidate ${plan.link}`);
-      const currentTarget = currentStat.isSymbolicLink() ? await readlink(plan.link) : "";
-      if (!currentStat.isSymbolicLink() || currentTarget !== plan.originalTarget) {
-        fail(`${plan.link} changed while its replacement was staged`);
-      }
-      await rename(plan.temp, plan.link);
-      committed.push(plan);
-    }
-  } catch (error) {
-    for (const plan of committed.reverse()) {
-      await rm(plan.link, { force: true }).catch(() => {});
-      await symlink(plan.originalTarget, plan.link).catch(() => {});
-    }
-    await cleanupTemps(plans);
-    throw error;
-  }
-
-  await cleanupTemps(plans);
-  const remaining = await collectSymlinks(root);
-  if (remaining.length !== 0) {
-    fail(`staged release tree still contains symbolic links: ${remaining.join(", ")}`);
-  }
-  return plans.length;
-}
-
-async function main(argv) {
-  if (argv.length !== 1) {
-    fail("usage: src/shared/artifact-packaging/materialize-release-symlinks.mjs ROOT");
-  }
-  const count = await materializeReleaseSymlinks(argv[0]);
-  console.log(`materializedReleaseSymlinks=${count}`);
-}
-
-if (process.argv[1] !== undefined && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
-  main(process.argv.slice(2)).catch((error) => {
-    console.error(error instanceof Error ? error.message : String(error));
-    process.exit(1);
-  });
-}
diff --git a/src/shared/artifact-packaging/materialize-release-symlinks.test.mjs b/src/shared/artifact-packaging/materialize-release-symlinks.test.mjs
deleted file mode 100644
index fbffd8ed4..000000000
--- a/src/shared/artifact-packaging/materialize-release-symlinks.test.mjs
+++ /dev/null
@@ -1,85 +0,0 @@
-import { afterEach, describe, expect, test } from "bun:test";
-import { chmod, lstat, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from "node:fs/promises";
-import { tmpdir } from "node:os";
-import path from "node:path";
-
-import { materializeReleaseSymlinks } from "./materialize-release-symlinks.mjs";
-
-const roots = [];
-
-async function fixture(name) {
-  const root = await mkdtemp(path.join(tmpdir(), `oliphaunt-materialize-${name}-`));
-  roots.push(root);
-  return root;
-}
-
-afterEach(async () => {
-  await Promise.all(roots.splice(0).map((root) => rm(root, { force: true, recursive: true })));
-});
-
-describe("release symlink materialization", () => {
-  test("materializes contained versioned library aliases as regular files", async () => {
-    const root = await fixture("aliases");
-    const lib = path.join(root, "runtime", "lib");
-    await mkdir(lib, { recursive: true });
-    const versioned = path.join(lib, "libexample.so.3.1");
-    await writeFile(versioned, "verified-library-bytes\n");
-    await chmod(versioned, 0o555);
-    await symlink("libexample.so.3.1", path.join(lib, "libexample.so.3"));
-    await symlink("libexample.so.3", path.join(lib, "libexample.so"));
-    await symlink("libexample.so.3.1", path.join(lib, "libexample.dylib"));
-
-    expect(await materializeReleaseSymlinks(root)).toBe(3);
-    for (const name of ["libexample.so.3", "libexample.so", "libexample.dylib"]) {
-      const file = path.join(lib, name);
-      const stat = await lstat(file);
-      expect(stat.isFile()).toBe(true);
-      expect(stat.isSymbolicLink()).toBe(false);
-      expect(stat.mode & 0o777).toBe(0o555);
-      expect(await readFile(file, "utf8")).toBe("verified-library-bytes\n");
-    }
-  });
-
-  test("validates the complete tree before replacing any link", async () => {
-    const root = await fixture("transaction");
-    const outside = await fixture("outside");
-    await writeFile(path.join(root, "library.so.1"), "library\n");
-    await writeFile(path.join(outside, "escape.so"), "escape\n");
-    const valid = path.join(root, "library.so");
-    const escape = path.join(root, "escape.so");
-    await symlink("library.so.1", valid);
-    await symlink(path.relative(root, path.join(outside, "escape.so")), escape);
-
-    await expect(materializeReleaseSymlinks(root)).rejects.toThrow(/escapes the staged release tree/u);
-    expect((await lstat(valid)).isSymbolicLink()).toBe(true);
-    expect((await lstat(escape)).isSymbolicLink()).toBe(true);
-  });
-
-  test("rejects absolute, broken, directory, cyclic, and symlink-root inputs", async () => {
-    const absoluteRoot = await fixture("absolute");
-    await writeFile(path.join(absoluteRoot, "real.so"), "library\n");
-    await symlink(path.join(absoluteRoot, "real.so"), path.join(absoluteRoot, "absolute.so"));
-    await expect(materializeReleaseSymlinks(absoluteRoot)).rejects.toThrow(/only relative/u);
-
-    const brokenRoot = await fixture("broken");
-    await symlink("missing.so", path.join(brokenRoot, "broken.so"));
-    await expect(materializeReleaseSymlinks(brokenRoot)).rejects.toThrow(/broken symbolic-link target/u);
-
-    const directoryRoot = await fixture("directory");
-    await mkdir(path.join(directoryRoot, "real-directory"));
-    await symlink("real-directory", path.join(directoryRoot, "directory-link"));
-    await expect(materializeReleaseSymlinks(directoryRoot)).rejects.toThrow(/regular file/u);
-
-    const cycleRoot = await fixture("cycle");
-    await symlink("second.so", path.join(cycleRoot, "first.so"));
-    await symlink("first.so", path.join(cycleRoot, "second.so"));
-    await expect(materializeReleaseSymlinks(cycleRoot)).rejects.toThrow(/cycle/u);
-
-    const targetRoot = await fixture("root-target");
-    const linkedRoot = `${targetRoot}-link`;
-    roots.push(linkedRoot);
-    await symlink(targetRoot, linkedRoot);
-    await expect(materializeReleaseSymlinks(linkedRoot)).rejects.toThrow(/root must be a real directory/u);
-  });
-
-});
diff --git a/src/shared/artifact-packaging/moon.yml b/src/shared/artifact-packaging/moon.yml
deleted file mode 100644
index 938d7d6a5..000000000
--- a/src/shared/artifact-packaging/moon.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "artifact-packaging"
-language: "javascript"
-layer: "library"
-stack: "systems"
-tags: ["shared", "artifacts", "packaging"]
-
-project:
-  title: "Artifact Packaging"
-  description: "Deterministic archive creation, reading, and safe staging shared by product packagers."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "**/*": ["@oliphaunt/core"]
-
-fileGroups:
-  source:
-    - "*.mjs"
-    - "!*.test.mjs"
-
-tasks:
-  test:
-    tags: ["quality", "unit"]
-    script: |
-      set -e
-      node --test src/shared/artifact-packaging/archive-directory.test.mjs src/shared/artifact-packaging/portable-archive.test.mjs
-      bun test src/shared/artifact-packaging/materialize-release-symlinks.test.mjs
-    inputs:
-      - "*.mjs"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
diff --git a/src/shared/artifact-packaging/portable-archive.mjs b/src/shared/artifact-packaging/portable-archive.mjs
deleted file mode 100644
index c42bc9d68..000000000
--- a/src/shared/artifact-packaging/portable-archive.mjs
+++ /dev/null
@@ -1,1324 +0,0 @@
-import { lstatSync, readFileSync } from "node:fs";
-import path from "node:path";
-import {
-  constants as zlibConstants,
-  gzipSync,
-  inflateRawSync,
-  zstdCompressSync,
-  zstdDecompressSync,
-} from "node:zlib";
-
-export const RELEASE_ZSTD_COMPRESSION_LEVEL = 19;
-
-export const DEFAULT_PORTABLE_ARCHIVE_LIMITS = Object.freeze({
-  maxArchiveBytes: 512 * 1024 * 1024,
-  maxEntries: 32_768,
-  maxEntryBytes: 512 * 1024 * 1024,
-  maxExpandedBytes: 1024 * 1024 * 1024,
-});
-
-const UTF8 = new TextDecoder("utf-8", { fatal: true });
-const ZIP_ALLOWED_FLAGS = 0x080e;
-const ZIP_ALLOWED_EXTRA_FIELDS = new Set([0x5455, 0x5855, 0x7875]);
-const ANDROID_ALIGNMENT_EXTRA_FIELD_ID = 0xd935;
-const APK_SIGNING_BLOCK_MAGIC = Buffer.from("APK Sig Block 42", "ascii");
-const APK_SIGNATURE_SCHEME_BLOCK_IDS = new Set([0x7109871a, 0xf05368c0, 0x1b93ad61]);
-const CANONICAL_GZIP_HEADER = Buffer.from([
-  0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-]);
-
-function archiveError(file, message) {
-  return new Error(`portable-archive: ${path.basename(file)} ${message}`);
-}
-
-/**
- * Normalize only the gzip metadata bytes that are outside the compressed
- * payload and trailer. zlib derives the OS byte from its build host, so an
- * otherwise identical archive is not byte-for-byte portable without this
- * explicit producer boundary.
- */
-export function normalizeCanonicalGzipHeader(compressed) {
-  if (!Buffer.isBuffer(compressed) && !(compressed instanceof Uint8Array)) {
-    throw new TypeError("portable-archive: canonical gzip input must be a Buffer or Uint8Array");
-  }
-  const normalized = Buffer.from(compressed);
-  if (
-    normalized.length < 18
-    || normalized[0] !== 0x1f
-    || normalized[1] !== 0x8b
-    || normalized[2] !== 0x08
-    || normalized[3] !== 0x00
-  ) {
-    throw new Error("portable-archive: canonical gzip input must be a flag-free gzip stream");
-  }
-  normalized.fill(0, 4, 9);
-  normalized[9] = 0x03;
-  return normalized;
-}
-
-export function canonicalGzipSync(input) {
-  return normalizeCanonicalGzipHeader(gzipSync(input, { mtime: 0 }));
-}
-
-export function releaseZstdCompressSync(input) {
-  return zstdCompressSync(input, {
-    params: {
-      [zlibConstants.ZSTD_c_compressionLevel]: RELEASE_ZSTD_COMPRESSION_LEVEL,
-    },
-  });
-}
-
-function positiveLimit(value, fallback, label) {
-  const result = value ?? fallback;
-  if (!Number.isSafeInteger(result) || result <= 0) {
-    throw new Error(`portable-archive: ${label} must be a positive safe integer`);
-  }
-  return result;
-}
-
-function limits(options) {
-  return {
-    maxArchiveBytes: positiveLimit(
-      options.maxArchiveBytes,
-      DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxArchiveBytes,
-      "maxArchiveBytes",
-    ),
-    maxEntries: positiveLimit(
-      options.maxEntries,
-      DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntries,
-      "maxEntries",
-    ),
-    maxEntryBytes: positiveLimit(
-      options.maxEntryBytes,
-      DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntryBytes,
-      "maxEntryBytes",
-    ),
-    maxExpandedBytes: positiveLimit(
-      options.maxExpandedBytes,
-      DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxExpandedBytes,
-      "maxExpandedBytes",
-    ),
-  };
-}
-
-function requireRegularArchive(file, maxArchiveBytes) {
-  let stat;
-  try {
-    stat = lstatSync(file);
-  } catch (cause) {
-    throw archiveError(file, `cannot be inspected: ${cause.message}`);
-  }
-  if (!stat.isFile()) {
-    throw archiveError(file, "must be a regular, non-symlink archive file");
-  }
-  if (stat.size <= 0 || stat.size > maxArchiveBytes) {
-    throw archiveError(
-      file,
-      `must be non-empty and no larger than ${maxArchiveBytes} bytes; got ${stat.size}`,
-    );
-  }
-  return stat;
-}
-
-function boundedSlice(buffer, offset, length, file, label) {
-  if (
-    !Number.isSafeInteger(offset)
-    || !Number.isSafeInteger(length)
-    || offset < 0
-    || length < 0
-    || offset > buffer.length
-    || length > buffer.length - offset
-  ) {
-    throw archiveError(file, `has a truncated or unsafe ${label}`);
-  }
-  return buffer.subarray(offset, offset + length);
-}
-
-function decodeUtf8(bytes, file, label, { requireAscii = false } = {}) {
-  if (bytes.length === 0) {
-    throw archiveError(file, `has an empty ${label}`);
-  }
-  if (requireAscii && bytes.some((byte) => byte >= 0x80)) {
-    throw archiveError(file, `has a non-ASCII ${label} without the ZIP UTF-8 flag`);
-  }
-  try {
-    return UTF8.decode(bytes);
-  } catch {
-    throw archiveError(file, `has invalid UTF-8 in ${label}`);
-  }
-}
-
-export function portableMemberName(raw, type, file, { allowRoot = false } = {}) {
-  if (allowRoot && type === "directory" && (raw === "." || raw === "./")) return null;
-  const directoryMarker = raw.endsWith("/");
-  if ((type === "directory") !== directoryMarker) {
-    throw archiveError(file, `has a member type/path-marker mismatch: ${JSON.stringify(raw)}`);
-  }
-  if (
-    raw.includes("\\")
-    || raw.startsWith("/")
-    || /^[A-Za-z]:/u.test(raw)
-    || /[\u0000-\u001f\u007f]/u.test(raw)
-  ) {
-    throw archiveError(file, `has an unsafe archive member: ${JSON.stringify(raw)}`);
-  }
-  let value = directoryMarker ? raw.slice(0, -1) : raw;
-  if (value === "." || value === "./") {
-    throw archiveError(file, `has an ambiguous root archive member: ${JSON.stringify(raw)}`);
-  }
-  if (value.startsWith("./")) value = value.slice(2);
-  const parts = value.split("/");
-  if (parts.length === 0 || parts.some((part) => !part || part === "." || part === "..")) {
-    throw archiveError(file, `has an unsafe archive member: ${JSON.stringify(raw)}`);
-  }
-  if (value !== value.normalize("NFC")) {
-    throw archiveError(file, `has a non-NFC archive member: ${JSON.stringify(raw)}`);
-  }
-  if (Buffer.byteLength(value, "utf8") > 4096) {
-    throw archiveError(file, `has an overlong archive member: ${JSON.stringify(raw)}`);
-  }
-  for (const segment of parts) {
-    if (
-      Buffer.byteLength(segment, "utf8") > 255
-      ||
-      /[<>:"|?*]/u.test(segment)
-      || /[ .]$/u.test(segment)
-      || /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(segment)
-    ) {
-      throw archiveError(file, `has a non-portable archive member: ${JSON.stringify(raw)}`);
-    }
-  }
-  return value;
-}
-
-function checkedEntries(entries, file, archiveLimits, { caseSensitive = false } = {}) {
-  if (entries.length === 0) throw archiveError(file, "contains no archive members");
-  if (entries.length > archiveLimits.maxEntries) {
-    throw archiveError(file, `exceeds the ${archiveLimits.maxEntries}-entry limit`);
-  }
-  const exact = new Set();
-  const portable = new Map();
-  const files = new Set();
-  let expandedBytes = 0;
-  for (const entry of entries) {
-    if (!Number.isSafeInteger(entry.size) || entry.size < 0) {
-      throw archiveError(file, `declares an unsafe size for ${entry.name}`);
-    }
-    if (entry.size > archiveLimits.maxEntryBytes) {
-      throw archiveError(
-        file,
-        `member ${entry.name} exceeds the ${archiveLimits.maxEntryBytes}-byte entry limit`,
-      );
-    }
-    expandedBytes += entry.size;
-    if (!Number.isSafeInteger(expandedBytes) || expandedBytes > archiveLimits.maxExpandedBytes) {
-      throw archiveError(
-        file,
-        `exceeds the ${archiveLimits.maxExpandedBytes}-byte expanded-data limit`,
-      );
-    }
-    if (exact.has(entry.name)) {
-      throw archiveError(file, `repeats archive member ${entry.name}`);
-    }
-    exact.add(entry.name);
-    // Android resource names are case-sensitive and aapt2 legitimately emits
-    // distinct hashed paths such as res/2F.xml and res/2f.xml. Other carrier
-    // formats retain the cross-filesystem case-folding collision check.
-    const portableKey = caseSensitive
-      ? entry.name.normalize("NFC")
-      : entry.name.normalize("NFC").toLowerCase();
-    const prior = portable.get(portableKey);
-    if (prior !== undefined && prior !== entry.name) {
-      throw archiveError(
-        file,
-        `contains case/NFC-colliding archive members ${prior} and ${entry.name}`,
-      );
-    }
-    portable.set(portableKey, entry.name);
-    if (entry.type === "file") files.add(entry.name);
-  }
-  for (const entry of entries) {
-    let separator = entry.name.indexOf("/");
-    while (separator >= 0) {
-      const parent = entry.name.slice(0, separator);
-      if (files.has(parent)) {
-        throw archiveError(file, `uses regular file ${parent} as an archive directory`);
-      }
-      separator = entry.name.indexOf("/", separator + 1);
-    }
-  }
-  return new Map(entries.map((entry) => [entry.name, Object.freeze(entry)]));
-}
-
-let crcTable;
-
-function crc32(buffer) {
-  if (crcTable === undefined) {
-    crcTable = new Uint32Array(256);
-    for (let value = 0; value < 256; value += 1) {
-      let crc = value;
-      for (let bit = 0; bit < 8; bit += 1) {
-        crc = (crc & 1) !== 0 ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1;
-      }
-      crcTable[value] = crc >>> 0;
-    }
-  }
-  let crc = 0xffffffff;
-  for (const byte of buffer) crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8);
-  return (crc ^ 0xffffffff) >>> 0;
-}
-
-function androidApkEntryAlignment(name) {
-  return name.endsWith(".so") ? 16 * 1024 : 4;
-}
-
-function validateAndroidAlignmentExtra(value, file, label, { dataOffset, method, name }) {
-  if (method !== 0) {
-    throw archiveError(file, `uses APK alignment metadata on compressed ZIP member ${label}`);
-  }
-  if (value.length < 2) {
-    throw archiveError(file, `has malformed APK alignment ZIP metadata for ${label}`);
-  }
-  const alignment = value.readUInt16LE(0);
-  const padding = value.subarray(2);
-  const expectedAlignment = androidApkEntryAlignment(name);
-  const unpaddedDataOffset = dataOffset - padding.length;
-  const expectedPadding = (
-    expectedAlignment - (unpaddedDataOffset % expectedAlignment)
-  ) % expectedAlignment;
-  if (
-    alignment !== expectedAlignment
-    || (alignment & (alignment - 1)) !== 0
-    || padding.length !== expectedPadding
-    || padding.some((byte) => byte !== 0)
-    || dataOffset % alignment !== 0
-  ) {
-    throw archiveError(file, `has malformed APK alignment ZIP metadata for ${label}`);
-  }
-}
-
-function validateZipExtra(
-  extra,
-  file,
-  label,
-  { androidApkLocal = false, dataOffset = 0, method = -1, name = "" } = {},
-) {
-  const seen = new Set();
-  for (let offset = 0; offset < extra.length;) {
-    if (androidApkLocal && extra.subarray(offset).every((byte) => byte === 0)) {
-      const paddingLength = extra.length - offset;
-      const alignment = androidApkEntryAlignment(name);
-      const unpaddedDataOffset = dataOffset - paddingLength;
-      const expectedPadding = (alignment - (unpaddedDataOffset % alignment)) % alignment;
-      if (
-        method !== 0
-        || paddingLength !== expectedPadding
-        || dataOffset % alignment !== 0
-      ) {
-        throw archiveError(file, `has malformed legacy APK alignment padding for ${label}`);
-      }
-      return;
-    }
-    if (extra.length - offset < 4) {
-      throw archiveError(file, `has a truncated ZIP ${label} extra field`);
-    }
-    const id = extra.readUInt16LE(offset);
-    const size = extra.readUInt16LE(offset + 2);
-    offset += 4;
-    if (size > extra.length - offset) {
-      throw archiveError(file, `has a truncated ZIP ${label} extra field`);
-    }
-    if (seen.has(id)) {
-      throw archiveError(
-        file,
-        `repeats ZIP ${label} extra field 0x${id.toString(16).padStart(4, "0")}`,
-      );
-    }
-    seen.add(id);
-    if (!ZIP_ALLOWED_EXTRA_FIELDS.has(id) && !(androidApkLocal && id === ANDROID_ALIGNMENT_EXTRA_FIELD_ID)) {
-      throw archiveError(
-        file,
-        `uses unsupported ZIP ${label} extra field 0x${id.toString(16).padStart(4, "0")}`,
-      );
-    }
-    const value = extra.subarray(offset, offset + size);
-    if (id === ANDROID_ALIGNMENT_EXTRA_FIELD_ID) {
-      if (offset + size !== extra.length) {
-        throw archiveError(file, `does not place APK alignment ZIP metadata last for ${label}`);
-      }
-      validateAndroidAlignmentExtra(value, file, label, { dataOffset, method, name });
-    } else if (id === 0x5455) {
-      if (![5, 9, 13].includes(size) || (value[0] & ~0x07) !== 0 || (value[0] & 0x01) === 0) {
-        throw archiveError(file, "has malformed extended-timestamp ZIP metadata");
-      }
-    } else if (id === 0x5855) {
-      if (size !== 8 && size !== 12) {
-        throw archiveError(file, "has malformed legacy Unix ZIP metadata");
-      }
-    } else if (id === 0x7875) {
-      if (size < 5 || value[0] !== 1) {
-        throw archiveError(file, "has malformed Unix UID/GID ZIP metadata");
-      }
-      const uidBytes = value[1];
-      const gidOffset = 2 + uidBytes;
-      if (uidBytes < 1 || uidBytes > 8 || gidOffset >= value.length) {
-        throw archiveError(file, "has malformed Unix UID/GID ZIP metadata");
-      }
-      const gidBytes = value[gidOffset];
-      if (gidBytes < 1 || gidBytes > 8 || gidOffset + 1 + gidBytes !== value.length) {
-        throw archiveError(file, "has malformed Unix UID/GID ZIP metadata");
-      }
-    }
-    offset += size;
-  }
-}
-
-function safeZipUInt64(buffer, offset, file, label) {
-  const bytes = boundedSlice(buffer, offset, 8, file, label);
-  const value = bytes.readBigUInt64LE(0);
-  if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
-    throw archiveError(file, `has an unsafe ${label}`);
-  }
-  return Number(value);
-}
-
-function zipDescriptorMatches(buffer, entry, offset, length) {
-  if (length === 16) {
-    return buffer.readUInt32LE(offset) === 0x08074b50
-      && buffer.readUInt32LE(offset + 4) === entry.crc32
-      && buffer.readUInt32LE(offset + 8) === entry.compressedSize
-      && buffer.readUInt32LE(offset + 12) === entry.size;
-  }
-  return buffer.readUInt32LE(offset) === entry.crc32
-    && buffer.readUInt32LE(offset + 4) === entry.compressedSize
-    && buffer.readUInt32LE(offset + 8) === entry.size;
-}
-
-function apkZipDescriptorLength(buffer, entry, available, file) {
-  const candidates = [];
-  for (const length of [12, 16]) {
-    if (available >= length && zipDescriptorMatches(buffer, entry, entry.dataEnd, length)) {
-      candidates.push(length);
-    }
-  }
-  if (candidates.length !== 1) {
-    throw archiveError(file, `has an invalid or ambiguous ZIP descriptor before APK metadata for ${entry.name}`);
-  }
-  return candidates[0];
-}
-
-function validateApkSigningBlock(buffer, recordsEnd, centralOffset, file) {
-  const gap = centralOffset - recordsEnd;
-  if (gap === 0) return;
-  if (gap < 32) {
-    throw archiveError(file, `has an unrecognized ${gap}-byte gap before its APK central directory`);
-  }
-  const footerOffset = centralOffset - 24;
-  const magic = boundedSlice(buffer, centralOffset - 16, 16, file, "APK Signing Block magic");
-  if (!magic.equals(APK_SIGNING_BLOCK_MAGIC)) {
-    throw archiveError(file, "has an unrecognized gap before its APK central directory");
-  }
-  const size = safeZipUInt64(buffer, footerOffset, file, "APK Signing Block footer size");
-  if (size < 24 || size > centralOffset - recordsEnd - 8) {
-    throw archiveError(file, "has an invalid APK Signing Block size");
-  }
-  const blockOffset = centralOffset - size - 8;
-  const firstSize = safeZipUInt64(buffer, blockOffset, file, "APK Signing Block header size");
-  if (firstSize !== size) {
-    throw archiveError(file, "has disagreeing APK Signing Block sizes");
-  }
-  if (buffer.subarray(recordsEnd, blockOffset).some((byte) => byte !== 0)) {
-    throw archiveError(file, "has non-zero padding before its APK Signing Block");
-  }
-  const signingPadding = blockOffset - recordsEnd;
-  if (
-    signingPadding !== 0
-    && (
-      signingPadding >= 4096
-      || blockOffset % 4096 !== 0
-      || signingPadding !== (4096 - (recordsEnd % 4096)) % 4096
-    )
-  ) {
-    throw archiveError(file, "has non-canonical zero padding before its APK Signing Block");
-  }
-  const pairsEnd = footerOffset;
-  let offset = blockOffset + 8;
-  let pairCount = 0;
-  let hasSignatureScheme = false;
-  const pairIds = new Set();
-  while (offset < pairsEnd) {
-    if (pairsEnd - offset < 12) {
-      throw archiveError(file, "has a truncated APK Signing Block pair");
-    }
-    const pairSize = safeZipUInt64(buffer, offset, file, "APK Signing Block pair size");
-    offset += 8;
-    if (pairSize < 4 || pairSize > pairsEnd - offset) {
-      throw archiveError(file, "has an invalid APK Signing Block pair size");
-    }
-    const pairId = buffer.readUInt32LE(offset);
-    if (pairIds.has(pairId)) {
-      throw archiveError(
-        file,
-        `repeats APK Signing Block pair ID 0x${pairId.toString(16).padStart(8, "0")}`,
-      );
-    }
-    pairIds.add(pairId);
-    if (APK_SIGNATURE_SCHEME_BLOCK_IDS.has(pairId)) hasSignatureScheme = true;
-    // Unknown IDs are intentionally accepted. Android makes the signing-block
-    // container extensible; exact framing plus at least one known whole-file
-    // signature scheme is the archive-safety boundary here.
-    offset += pairSize;
-    pairCount += 1;
-  }
-  if (offset !== pairsEnd || pairCount === 0) {
-    throw archiveError(file, "has an empty or truncated APK Signing Block pair sequence");
-  }
-  if (!hasSignatureScheme) {
-    throw archiveError(file, "has an APK Signing Block without a v2, v3, or v3.1 signature pair");
-  }
-}
-
-function zipEntryType(versionMadeBy, externalAttributes, rawName, file) {
-  const host = versionMadeBy >>> 8;
-  const unixMode = externalAttributes >>> 16;
-  const unixType = unixMode & 0o170000;
-  const pathDirectory = rawName.endsWith("/");
-  const dosDirectory = (externalAttributes & 0x10) !== 0;
-  let type;
-  if (host === 3) {
-    if (unixType === 0o100000) {
-      if (dosDirectory) {
-        throw archiveError(file, `marks Unix regular file ${rawName} as a DOS directory`);
-      }
-      type = "file";
-    } else if (unixType === 0o040000) {
-      type = "directory";
-    } else if (unixType === 0) {
-      throw archiveError(file, `has an ambiguous Unix creator type for ${rawName}`);
-    } else {
-      throw archiveError(file, `contains a link or special ZIP entry: ${rawName}`);
-    }
-  } else if (host === 0) {
-    if (unixType !== 0) {
-      throw archiveError(file, `has conflicting FAT/Unix type metadata for ${rawName}`);
-    }
-    if (pathDirectory !== dosDirectory) {
-      throw archiveError(file, `has inconsistent FAT directory metadata for ${rawName}`);
-    }
-    type = pathDirectory ? "directory" : "file";
-  } else {
-    throw archiveError(file, `uses unsupported ZIP creator host ${host} for ${rawName}`);
-  }
-  if ((type === "directory") !== pathDirectory) {
-    throw archiveError(file, `has a member type/path-marker mismatch: ${rawName}`);
-  }
-  if (host === 3) validatePortableMode(unixMode & 0o7777, type, rawName, file);
-  return { mode: unixMode, type };
-}
-
-function validatePortableMode(mode, type, name, file) {
-  if ((mode & 0o7000) !== 0) {
-    throw archiveError(file, `uses set-id or sticky permission bits for ${name}`);
-  }
-  if (type === "file" && (mode & 0o400) === 0) {
-    throw archiveError(file, `has an owner-unreadable regular file ${name}`);
-  }
-  if (type === "directory" && (mode & 0o500) !== 0o500) {
-    throw archiveError(file, `has an owner-unreadable or untraversable directory ${name}`);
-  }
-}
-
-function findZipEnd(buffer, file) {
-  if (buffer.length < 22) throw archiveError(file, "is too short to be a ZIP archive");
-  const minimum = Math.max(0, buffer.length - 65_557);
-  for (let offset = buffer.length - 22; offset >= minimum; offset -= 1) {
-    if (
-      buffer.readUInt32LE(offset) === 0x06054b50
-      && offset + 22 + buffer.readUInt16LE(offset + 20) === buffer.length
-    ) {
-      return offset;
-    }
-  }
-  throw archiveError(file, "has no well-formed ZIP end record");
-}
-
-function validateZipDescriptor(buffer, entry, offset, length, file) {
-  if (length !== 12 && length !== 16) {
-    throw archiveError(file, `has an ambiguous ${length}-byte gap after ZIP member ${entry.name}`);
-  }
-  const descriptor = boundedSlice(buffer, offset, length, file, `ZIP descriptor for ${entry.name}`);
-  let cursor = 0;
-  if (length === 16) {
-    if (descriptor.readUInt32LE(0) !== 0x08074b50) {
-      throw archiveError(file, `has an invalid ZIP descriptor signature for ${entry.name}`);
-    }
-    cursor = 4;
-  }
-  if (
-    descriptor.readUInt32LE(cursor) !== entry.crc32
-    || descriptor.readUInt32LE(cursor + 4) !== entry.compressedSize
-    || descriptor.readUInt32LE(cursor + 8) !== entry.size
-  ) {
-    throw archiveError(file, `has a ZIP descriptor that disagrees with ${entry.name}`);
-  }
-}
-
-function inflateZipEntry(buffer, entry, file, maxEntryBytes) {
-  const compressed = boundedSlice(
-    buffer,
-    entry.dataOffset,
-    entry.compressedSize,
-    file,
-    `ZIP payload for ${entry.name}`,
-  );
-  let data;
-  if (entry.method === 0) {
-    data = compressed;
-  } else {
-    let inflated;
-    try {
-      inflated = inflateRawSync(compressed, {
-        info: true,
-        maxOutputLength: Math.min(maxEntryBytes, entry.size) + 1,
-      });
-    } catch (cause) {
-      throw archiveError(file, `has invalid or oversized deflate data for ${entry.name}: ${cause.message}`);
-    }
-    if (inflated.engine.bytesWritten !== compressed.length) {
-      throw archiveError(file, `has trailing compressed bytes in ZIP member ${entry.name}`);
-    }
-    data = inflated.buffer;
-  }
-  if (data.length !== entry.size) {
-    throw archiveError(
-      file,
-      `expanded ZIP size for ${entry.name} is ${data.length}, expected ${entry.size}`,
-    );
-  }
-  const actualCrc = crc32(data);
-  if (actualCrc !== entry.crc32) {
-    throw archiveError(
-      file,
-      `CRC-32 mismatch for ZIP member ${entry.name}: expected ${entry.crc32.toString(16).padStart(8, "0")}, got ${actualCrc.toString(16).padStart(8, "0")}`,
-    );
-  }
-  return data;
-}
-
-function readZipEntries(file, archiveLimits, { androidApk = false } = {}) {
-  const buffer = readFileSync(file);
-  const eocdOffset = findZipEnd(buffer, file);
-  const eocd = boundedSlice(buffer, eocdOffset, 22, file, "ZIP end record");
-  const disk = eocd.readUInt16LE(4);
-  const centralDisk = eocd.readUInt16LE(6);
-  const diskEntries = eocd.readUInt16LE(8);
-  const entryCount = eocd.readUInt16LE(10);
-  const centralSize = eocd.readUInt32LE(12);
-  const centralOffset = eocd.readUInt32LE(16);
-  const commentLength = eocd.readUInt16LE(20);
-  if (
-    disk === 0xffff
-    || centralDisk === 0xffff
-    || diskEntries === 0xffff
-    || entryCount === 0xffff
-    || centralSize === 0xffffffff
-    || centralOffset === 0xffffffff
-  ) {
-    throw archiveError(file, "uses unsupported ZIP64 metadata");
-  }
-  if (disk !== 0 || centralDisk !== 0 || diskEntries !== entryCount) {
-    throw archiveError(file, "uses unsupported multi-disk ZIP metadata");
-  }
-  if (commentLength !== 0) throw archiveError(file, "has an unsupported ZIP archive comment");
-  if (entryCount === 0 || entryCount > archiveLimits.maxEntries) {
-    throw archiveError(file, `has an invalid ZIP entry count ${entryCount}`);
-  }
-  if (centralOffset + centralSize !== eocdOffset) {
-    throw archiveError(file, "has an invalid or ambiguous ZIP central-directory extent");
-  }
-
-  const entries = [];
-  let offset = centralOffset;
-  let expandedBytes = 0;
-  for (let index = 0; index < entryCount; index += 1) {
-    const header = boundedSlice(buffer, offset, 46, file, `ZIP central header ${index + 1}`);
-    if (header.readUInt32LE(0) !== 0x02014b50) {
-      throw archiveError(file, `has an invalid ZIP central header ${index + 1}`);
-    }
-    const versionMadeBy = header.readUInt16LE(4);
-    const versionNeeded = header.readUInt16LE(6);
-    const flags = header.readUInt16LE(8);
-    const method = header.readUInt16LE(10);
-    const modTime = header.readUInt16LE(12);
-    const modDate = header.readUInt16LE(14);
-    const expectedCrc = header.readUInt32LE(16);
-    const compressedSize = header.readUInt32LE(20);
-    const size = header.readUInt32LE(24);
-    const nameLength = header.readUInt16LE(28);
-    const extraLength = header.readUInt16LE(30);
-    const memberCommentLength = header.readUInt16LE(32);
-    const diskStart = header.readUInt16LE(34);
-    const externalAttributes = header.readUInt32LE(38);
-    const localOffset = header.readUInt32LE(42);
-    if (versionNeeded > 20) {
-      throw archiveError(file, `requires unsupported ZIP version ${versionNeeded}`);
-    }
-    if ((flags & ~ZIP_ALLOWED_FLAGS) !== 0 || (flags & 0x0001) !== 0) {
-      throw archiveError(file, `uses unsupported or encrypted ZIP flags 0x${flags.toString(16)}`);
-    }
-    if (method !== 0 && method !== 8) {
-      throw archiveError(file, `uses unsupported ZIP compression method ${method}`);
-    }
-    if (method === 0 && (flags & 0x0006) !== 0) {
-      throw archiveError(file, "uses deflate-only flags on a stored ZIP member");
-    }
-    if (
-      compressedSize === 0xffffffff
-      || size === 0xffffffff
-      || localOffset === 0xffffffff
-      || diskStart === 0xffff
-    ) {
-      throw archiveError(file, "uses unsupported ZIP64 entry metadata");
-    }
-    if (diskStart !== 0) throw archiveError(file, "contains a multi-disk ZIP member");
-    if (memberCommentLength !== 0) throw archiveError(file, "contains a ZIP member comment");
-    if (size > archiveLimits.maxEntryBytes) {
-      throw archiveError(file, `ZIP member ${index + 1} exceeds the entry-size limit`);
-    }
-    expandedBytes += size;
-    if (!Number.isSafeInteger(expandedBytes) || expandedBytes > archiveLimits.maxExpandedBytes) {
-      throw archiveError(file, "exceeds the expanded ZIP data limit");
-    }
-    const recordLength = 46 + nameLength + extraLength;
-    if (offset > eocdOffset - recordLength) {
-      throw archiveError(file, `has a truncated ZIP central member ${index + 1}`);
-    }
-    const variable = boundedSlice(
-      buffer,
-      offset + 46,
-      nameLength + extraLength,
-      file,
-      `ZIP central member ${index + 1}`,
-    );
-    const rawNameBytes = variable.subarray(0, nameLength);
-    const rawName = decodeUtf8(rawNameBytes, file, `ZIP member name ${index + 1}`, {
-      requireAscii: (flags & 0x0800) === 0,
-    });
-    validateZipExtra(variable.subarray(nameLength), file, `central ${JSON.stringify(rawName)}`);
-    const { mode, type } = zipEntryType(versionMadeBy, externalAttributes, rawName, file);
-    const name = portableMemberName(rawName, type, file);
-    if (type === "directory" && (size !== 0 || expectedCrc !== 0)) {
-      throw archiveError(file, `has a non-empty ZIP directory member ${rawName}`);
-    }
-    if (method === 0 && compressedSize !== size) {
-      throw archiveError(file, `has inconsistent stored ZIP sizes for ${rawName}`);
-    }
-
-    const local = boundedSlice(buffer, localOffset, 30, file, `ZIP local header for ${name}`);
-    if (local.readUInt32LE(0) !== 0x04034b50) {
-      throw archiveError(file, `has an invalid ZIP local header for ${name}`);
-    }
-    if (
-      local.readUInt16LE(4) !== versionNeeded
-      || local.readUInt16LE(6) !== flags
-      || local.readUInt16LE(8) !== method
-      || local.readUInt16LE(10) !== modTime
-      || local.readUInt16LE(12) !== modDate
-    ) {
-      throw archiveError(file, `has local/central ZIP metadata disagreement for ${name}`);
-    }
-    const localNameLength = local.readUInt16LE(26);
-    const localExtraLength = local.readUInt16LE(28);
-    const localVariable = boundedSlice(
-      buffer,
-      localOffset + 30,
-      localNameLength + localExtraLength,
-      file,
-      `ZIP local variable fields for ${name}`,
-    );
-    if (!localVariable.subarray(0, localNameLength).equals(rawNameBytes)) {
-      throw archiveError(file, `has a local/central ZIP name disagreement for ${name}`);
-    }
-    const dataOffset = localOffset + 30 + localNameLength + localExtraLength;
-    validateZipExtra(
-      localVariable.subarray(localNameLength),
-      file,
-      `local ${JSON.stringify(rawName)}`,
-      { androidApkLocal: androidApk, dataOffset, method, name },
-    );
-    const descriptor = (flags & 0x0008) !== 0;
-    const localCrc = local.readUInt32LE(14);
-    const localCompressedSize = local.readUInt32LE(18);
-    const localSize = local.readUInt32LE(22);
-    if (descriptor) {
-      if (
-        (localCrc !== 0 && localCrc !== expectedCrc)
-        || (localCompressedSize !== 0 && localCompressedSize !== compressedSize)
-        || (localSize !== 0 && localSize !== size)
-      ) {
-        throw archiveError(file, `has local/descriptor ZIP disagreement for ${name}`);
-      }
-    } else if (
-      localCrc !== expectedCrc
-      || localCompressedSize !== compressedSize
-      || localSize !== size
-    ) {
-      throw archiveError(file, `has local/central ZIP CRC or size disagreement for ${name}`);
-    }
-    if (dataOffset > centralOffset || compressedSize > centralOffset - dataOffset) {
-      throw archiveError(file, `has ZIP payload outside local-record bounds for ${name}`);
-    }
-    entries.push({
-      compressedSize,
-      crc32: expectedCrc,
-      dataEnd: dataOffset + compressedSize,
-      dataOffset,
-      descriptor,
-      isDirectory: type === "directory",
-      isFile: type === "file",
-      isSymbolicLink: false,
-      localOffset,
-      method,
-      mode,
-      name,
-      size,
-      type,
-    });
-    offset += recordLength;
-  }
-  if (offset !== eocdOffset) {
-    throw archiveError(file, "has trailing or missing ZIP central-directory records");
-  }
-  const extents = [...entries].sort(
-    (left, right) => left.localOffset - right.localOffset || left.dataEnd - right.dataEnd,
-  );
-  if (extents[0]?.localOffset !== 0) {
-    throw archiveError(file, "has unreferenced bytes before its first ZIP local record");
-  }
-  for (let index = 0; index < extents.length; index += 1) {
-    const entry = extents[index];
-    const nextOffset = extents[index + 1]?.localOffset ?? centralOffset;
-    if (entry.dataEnd > nextOffset) throw archiveError(file, "has overlapping ZIP local records");
-    const gap = nextOffset - entry.dataEnd;
-    const finalEntry = index === extents.length - 1;
-    if (entry.descriptor && androidApk && finalEntry) {
-      const descriptorLength = apkZipDescriptorLength(buffer, entry, gap, file);
-      validateApkSigningBlock(buffer, entry.dataEnd + descriptorLength, centralOffset, file);
-    } else if (entry.descriptor) {
-      validateZipDescriptor(buffer, entry, entry.dataEnd, gap, file);
-    } else if (androidApk && finalEntry) {
-      validateApkSigningBlock(buffer, entry.dataEnd, centralOffset, file);
-    } else if (gap !== 0) {
-      throw archiveError(file, `has an ambiguous ${gap}-byte gap after ZIP member ${entry.name}`);
-    }
-  }
-
-  for (const entry of entries) {
-    const payload = {
-      compressedSize: entry.compressedSize,
-      crc32: entry.crc32,
-      dataOffset: entry.dataOffset,
-      method: entry.method,
-      name: entry.name,
-      size: entry.size,
-    };
-    inflateZipEntry(buffer, payload, file, archiveLimits.maxEntryBytes);
-    entry.data = () => inflateZipEntry(buffer, payload, file, archiveLimits.maxEntryBytes);
-    delete entry.compressedSize;
-    delete entry.crc32;
-    delete entry.dataEnd;
-    delete entry.dataOffset;
-    delete entry.descriptor;
-    delete entry.localOffset;
-    delete entry.method;
-  }
-  return checkedEntries(entries, file, archiveLimits, { caseSensitive: androidApk });
-}
-
-function tarString(header, offset, length, file, label, { allowEmpty = false } = {}) {
-  const field = header.subarray(offset, offset + length);
-  const zero = field.indexOf(0);
-  const value = zero < 0 ? field : field.subarray(0, zero);
-  if (zero >= 0 && field.subarray(zero).some((byte) => byte !== 0)) {
-    throw archiveError(file, `has malformed ustar ${label}`);
-  }
-  if (value.length === 0) {
-    if (allowEmpty) return "";
-    throw archiveError(file, `has an empty ustar ${label}`);
-  }
-  try {
-    return UTF8.decode(value);
-  } catch {
-    throw archiveError(file, `has invalid UTF-8 in ustar ${label}`);
-  }
-}
-
-function tarOctal(header, offset, length, file, label, { allowEmpty = false } = {}) {
-  const field = header.subarray(offset, offset + length);
-  if ((field[0] & 0x80) !== 0) {
-    throw archiveError(file, `uses unsupported base-256 ustar ${label}`);
-  }
-  const zero = field.indexOf(0);
-  const value = zero < 0 ? field : field.subarray(0, zero);
-  if (zero >= 0 && field.subarray(zero + 1).some((byte) => byte !== 0 && byte !== 0x20)) {
-    throw archiveError(file, `has non-padding bytes after the ustar ${label} terminator`);
-  }
-  if (value.some((byte) => byte !== 0x20 && (byte < 0x30 || byte > 0x37))) {
-    throw archiveError(file, `has invalid ustar ${label}`);
-  }
-  const text = value.toString("ascii").trim();
-  if (text.length === 0 && allowEmpty) return 0;
-  if (!/^[0-7]+$/u.test(text)) throw archiveError(file, `has invalid ustar ${label}`);
-  const parsed = Number.parseInt(text, 8);
-  if (!Number.isSafeInteger(parsed) || parsed < 0) {
-    throw archiveError(file, `has unsafe ustar ${label}`);
-  }
-  return parsed;
-}
-
-function gzipPortableText(compressed, start, end, file, label) {
-  const bytes = compressed.subarray(start, end);
-  if (
-    bytes.some((byte) => byte < 0x20 || byte > 0x7e)
-    || bytes.length === 0
-  ) {
-    throw archiveError(file, `has a non-portable gzip ${label}`);
-  }
-}
-
-function gzipZeroTerminatedEnd(compressed, offset, trailerOffset, file, label) {
-  const end = compressed.indexOf(0, offset);
-  if (end < offset || end >= trailerOffset) {
-    throw archiveError(file, `has a truncated gzip ${label}`);
-  }
-  gzipPortableText(compressed, offset, end, file, label);
-  return end + 1;
-}
-
-function strictGunzip(compressed, file, maxOutputLength) {
-  if (
-    compressed.length < 18
-    || compressed[0] !== 0x1f
-    || compressed[1] !== 0x8b
-    || compressed[2] !== 8
-  ) {
-    throw archiveError(file, "is not a gzip-compressed deflate stream");
-  }
-  const flags = compressed[3];
-  if ((flags & 0xe0) !== 0) throw archiveError(file, "uses reserved gzip flags");
-  const trailerOffset = compressed.length - 8;
-  let offset = 10;
-  if ((flags & 0x04) !== 0) {
-    if (offset > trailerOffset - 2) throw archiveError(file, "has a truncated gzip extra length");
-    const extraLength = compressed.readUInt16LE(offset);
-    offset += 2;
-    if (extraLength > trailerOffset - offset) throw archiveError(file, "has truncated gzip extra data");
-    offset += extraLength;
-  }
-  if ((flags & 0x08) !== 0) {
-    offset = gzipZeroTerminatedEnd(compressed, offset, trailerOffset, file, "filename");
-  }
-  if ((flags & 0x10) !== 0) {
-    offset = gzipZeroTerminatedEnd(compressed, offset, trailerOffset, file, "comment");
-  }
-  if ((flags & 0x02) !== 0) {
-    if (offset > trailerOffset - 2) throw archiveError(file, "has a truncated gzip header CRC");
-    const expectedHeaderCrc = compressed.readUInt16LE(offset);
-    const actualHeaderCrc = crc32(compressed.subarray(0, offset)) & 0xffff;
-    if (expectedHeaderCrc !== actualHeaderCrc) throw archiveError(file, "has an invalid gzip header CRC");
-    offset += 2;
-  }
-  if (offset >= trailerOffset) throw archiveError(file, "has no gzip deflate payload");
-  const deflate = compressed.subarray(offset, trailerOffset);
-  let inflated;
-  try {
-    inflated = inflateRawSync(deflate, { info: true, maxOutputLength });
-  } catch (cause) {
-    throw archiveError(file, `is not a bounded readable gzip stream: ${cause.message}`);
-  }
-  if (inflated.engine.bytesWritten !== deflate.length) {
-    throw archiveError(file, "contains trailing data or multiple gzip members");
-  }
-  const expectedCrc = compressed.readUInt32LE(trailerOffset);
-  const expectedSize = compressed.readUInt32LE(trailerOffset + 4);
-  const actualCrc = crc32(inflated.buffer);
-  if (actualCrc !== expectedCrc) throw archiveError(file, "has an invalid gzip payload CRC-32");
-  if (inflated.buffer.length !== expectedSize) throw archiveError(file, "has an invalid gzip payload size");
-  return inflated.buffer;
-}
-
-export function decompressSingleZstdFrame(
-  input,
-  {
-    label = "Zstandard payload",
-    maxInputBytes = DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxArchiveBytes,
-    maxOutputBytes = DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxExpandedBytes,
-  } = {},
-) {
-  const checkedMaxInputBytes = positiveLimit(
-    maxInputBytes,
-    DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxArchiveBytes,
-    "maxInputBytes",
-  );
-  const checkedMaxOutputBytes = positiveLimit(
-    maxOutputBytes,
-    DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxExpandedBytes,
-    "maxOutputBytes",
-  );
-  if (!Buffer.isBuffer(input) && !(input instanceof Uint8Array)) {
-    throw archiveError(label, "must be provided as a Buffer or Uint8Array");
-  }
-  const compressed = Buffer.isBuffer(input)
-    ? input
-    : Buffer.from(input.buffer, input.byteOffset, input.byteLength);
-  if (compressed.length === 0 || compressed.length > checkedMaxInputBytes) {
-    throw archiveError(
-      label,
-      `must be non-empty and no larger than ${checkedMaxInputBytes} bytes; got ${compressed.length}`,
-    );
-  }
-  if (
-    compressed.length < 4
-    || compressed[0] !== 0x28
-    || compressed[1] !== 0xb5
-    || compressed[2] !== 0x2f
-    || compressed[3] !== 0xfd
-  ) {
-    throw archiveError(label, "is not a Zstandard frame");
-  }
-  let decompressed;
-  try {
-    decompressed = zstdDecompressSync(compressed, {
-      info: true,
-      maxOutputLength: checkedMaxOutputBytes,
-    });
-  } catch (cause) {
-    throw archiveError(label, `is not a bounded readable Zstandard stream: ${cause.message}`);
-  }
-  if (decompressed.engine.bytesWritten !== compressed.length) {
-    throw archiveError(label, "contains trailing data or multiple Zstandard frames");
-  }
-  return decompressed.buffer;
-}
-
-function parseTarEntries(tar, file, archiveLimits) {
-  if (tar.length === 0 || tar.length % 512 !== 0) {
-    throw archiveError(file, "has a truncated or non-block-aligned ustar stream");
-  }
-  const entries = [];
-  let offset = 0;
-  let memberCount = 0;
-  let zeroBlocks = 0;
-  while (offset < tar.length) {
-    const header = tar.subarray(offset, offset + 512);
-    if (header.every((byte) => byte === 0)) {
-      zeroBlocks += 1;
-      offset += 512;
-      if (zeroBlocks >= 2) {
-        if (tar.subarray(offset).some((byte) => byte !== 0)) {
-          throw archiveError(file, "has data after its two-block ustar end marker");
-        }
-        break;
-      }
-      continue;
-    }
-    if (zeroBlocks !== 0) throw archiveError(file, "has an incomplete ustar end marker");
-    memberCount += 1;
-    if (memberCount > archiveLimits.maxEntries) {
-      throw archiveError(file, `exceeds the ${archiveLimits.maxEntries}-entry limit`);
-    }
-    const posixUstar = header.subarray(257, 263).equals(Buffer.from("ustar\0"))
-      && header.subarray(263, 265).equals(Buffer.from("00"));
-    const gnuUstar = header.subarray(257, 263).equals(Buffer.from("ustar "))
-      && header[263] === 0x20
-      && header[264] === 0;
-    if (!posixUstar && !gnuUstar) throw archiveError(file, "contains a non-ustar header");
-    const storedChecksum = tarOctal(header, 148, 8, file, "checksum");
-    let actualChecksum = 0;
-    for (let index = 0; index < 512; index += 1) {
-      actualChecksum += index >= 148 && index < 156 ? 0x20 : header[index];
-    }
-    if (storedChecksum !== actualChecksum) {
-      throw archiveError(file, "has an invalid ustar header checksum");
-    }
-    const rawName = tarString(header, 0, 100, file, "name");
-    const prefix = tarString(header, 345, 155, file, "prefix", { allowEmpty: true });
-    const raw = prefix ? `${prefix}/${rawName}` : rawName;
-    const mode = tarOctal(header, 100, 8, file, `mode for ${raw}`);
-    const uid = tarOctal(header, 108, 8, file, `uid for ${raw}`, { allowEmpty: true });
-    const gid = tarOctal(header, 116, 8, file, `gid for ${raw}`, { allowEmpty: true });
-    const size = tarOctal(header, 124, 12, file, `size for ${raw}`);
-    const mtime = tarOctal(header, 136, 12, file, `mtime for ${raw}`, { allowEmpty: true });
-    const typeFlag = header[156];
-    const type = typeFlag === 0 || typeFlag === 0x30
-      ? "file"
-      : typeFlag === 0x35
-        ? "directory"
-        : null;
-    if (type === null) throw archiveError(file, `contains a link or special ustar entry: ${raw}`);
-    if (type === "directory" && size !== 0) {
-      throw archiveError(file, `has a non-empty ustar directory member ${raw}`);
-    }
-    if (tarString(header, 157, 100, file, `link name for ${raw}`, { allowEmpty: true }) !== "") {
-      throw archiveError(file, `sets a link target on non-link ustar member ${raw}`);
-    }
-    tarString(header, 265, 32, file, `owner name for ${raw}`, { allowEmpty: true });
-    tarString(header, 297, 32, file, `group name for ${raw}`, { allowEmpty: true });
-    const deviceMajor = tarOctal(header, 329, 8, file, `device major for ${raw}`, { allowEmpty: true });
-    const deviceMinor = tarOctal(header, 337, 8, file, `device minor for ${raw}`, { allowEmpty: true });
-    if (deviceMajor !== 0 || deviceMinor !== 0) {
-      throw archiveError(file, `sets device numbers on non-device ustar member ${raw}`);
-    }
-    if (posixUstar && header.subarray(500, 512).some((byte) => byte !== 0)) {
-      throw archiveError(file, `has non-zero reserved ustar header bytes for ${raw}`);
-    }
-    if (gnuUstar && header.subarray(345, 512).some((byte) => byte !== 0)) {
-      throw archiveError(file, `uses unsupported extended GNU ustar metadata for ${raw}`);
-    }
-    if (mode > 0o7777) throw archiveError(file, `has invalid ustar permission bits for ${raw}`);
-    validatePortableMode(mode, type, raw, file);
-    if (size > archiveLimits.maxEntryBytes) {
-      throw archiveError(file, `ustar member ${raw} exceeds the entry-size limit`);
-    }
-    const name = portableMemberName(raw, type, file, { allowRoot: true });
-    const dataOffset = offset + 512;
-    const paddedSize = Math.ceil(size / 512) * 512;
-    if (
-      !Number.isSafeInteger(paddedSize)
-      || dataOffset > tar.length
-      || paddedSize > tar.length - dataOffset
-    ) {
-      throw archiveError(file, `has a truncated ustar payload for ${raw}`);
-    }
-    if (tar.subarray(dataOffset + size, dataOffset + paddedSize).some((byte) => byte !== 0)) {
-      throw archiveError(file, `has non-zero ustar padding for ${raw}`);
-    }
-    if (name !== null) {
-      const data = tar.subarray(dataOffset, dataOffset + size);
-      entries.push({
-        data: () => data,
-        gid,
-        isDirectory: type === "directory",
-        isFile: type === "file",
-        isSymbolicLink: false,
-        mode,
-        mtime,
-        name,
-        size,
-        type,
-        uid,
-      });
-    }
-    offset = dataOffset + paddedSize;
-  }
-  if (zeroBlocks < 2) throw archiveError(file, "is missing its two-block ustar end marker");
-  return checkedEntries(entries, file, archiveLimits);
-}
-
-function decompressedTarBuffer(compressed, file, archiveLimits, compression) {
-  try {
-    if (compression === "gzip") {
-      return strictGunzip(compressed, file, archiveLimits.maxExpandedBytes);
-    }
-    return decompressSingleZstdFrame(compressed, {
-      label: file,
-      maxInputBytes: archiveLimits.maxArchiveBytes,
-      maxOutputBytes: archiveLimits.maxExpandedBytes,
-    });
-  } catch (cause) {
-    if (cause instanceof Error && cause.message.startsWith("portable-archive:")) throw cause;
-    throw archiveError(file, `is not a bounded readable ${compression} stream: ${cause.message}`);
-  }
-}
-
-function readTarBufferEntries(compressed, file, archiveLimits, compression = "gzip") {
-  return parseTarEntries(
-    decompressedTarBuffer(compressed, file, archiveLimits, compression),
-    file,
-    archiveLimits,
-  );
-}
-
-function canonicalTarPathParts(name, file) {
-  if (Buffer.byteLength(name) <= 100) return { name, prefix: "" };
-  const parts = name.split("/");
-  for (let index = 1; index < parts.length; index += 1) {
-    const prefix = parts.slice(0, index).join("/");
-    const suffix = parts.slice(index).join("/");
-    if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(suffix) <= 100) {
-      return { name: suffix, prefix };
-    }
-  }
-  throw archiveError(file, `has a path that cannot use canonical POSIX ustar fields: ${name}`);
-}
-
-function writeCanonicalTarString(header, offset, length, value, file, label) {
-  const bytes = Buffer.from(value);
-  if (bytes.length > length) {
-    throw archiveError(file, `has an overlong canonical ustar ${label}`);
-  }
-  bytes.copy(header, offset);
-}
-
-function writeCanonicalTarOctal(header, offset, length, value, file, label) {
-  const text = value.toString(8);
-  if (text.length > length - 1) {
-    throw archiveError(file, `has a canonical ustar ${label} overflow`);
-  }
-  writeCanonicalTarString(
-    header,
-    offset,
-    length,
-    `${text.padStart(length - 1, "0")}\0`,
-    file,
-    label,
-  );
-}
-
-function canonicalTarHeader(name, size, mode, file) {
-  const header = Buffer.alloc(512);
-  const fields = canonicalTarPathParts(name, file);
-  writeCanonicalTarString(header, 0, 100, fields.name, file, `name for ${name}`);
-  writeCanonicalTarOctal(header, 100, 8, mode, file, `mode for ${name}`);
-  writeCanonicalTarOctal(header, 108, 8, 0, file, `uid for ${name}`);
-  writeCanonicalTarOctal(header, 116, 8, 0, file, `gid for ${name}`);
-  writeCanonicalTarOctal(header, 124, 12, size, file, `size for ${name}`);
-  writeCanonicalTarOctal(header, 136, 12, 0, file, `mtime for ${name}`);
-  header.fill(0x20, 148, 156);
-  writeCanonicalTarString(header, 156, 1, "0", file, `type for ${name}`);
-  writeCanonicalTarString(header, 257, 6, "ustar\0", file, `magic for ${name}`);
-  writeCanonicalTarString(header, 263, 2, "00", file, `version for ${name}`);
-  writeCanonicalTarString(header, 345, 155, fields.prefix, file, `prefix for ${name}`);
-  const checksum = header.reduce((total, byte) => total + byte, 0);
-  const checksumText = checksum.toString(8);
-  if (checksumText.length > 6) {
-    throw archiveError(file, `has a canonical ustar checksum overflow for ${name}`);
-  }
-  writeCanonicalTarString(
-    header,
-    148,
-    8,
-    `${checksumText.padStart(6, "0")}\0 `,
-    file,
-    `checksum for ${name}`,
-  );
-  return header;
-}
-
-function canonicalFileTar(entries, file, mode) {
-  const names = [...entries.keys()];
-  const sorted = [...names].sort();
-  if (JSON.stringify(names) !== JSON.stringify(sorted)) {
-    throw archiveError(file, "must list canonical file members in bytewise sorted order");
-  }
-  const chunks = [];
-  for (const [name, entry] of entries) {
-    if (
-      !entry.isFile
-      || entry.isDirectory
-      || entry.isSymbolicLink
-      || entry.mode !== mode
-      || entry.uid !== 0
-      || entry.gid !== 0
-      || entry.mtime !== 0
-    ) {
-      throw archiveError(
-        file,
-        `member ${name} must be a canonical regular mode=${mode.toString(8).padStart(4, "0")} uid=0 gid=0 mtime=0 file`,
-      );
-    }
-    const data = Buffer.from(entry.data());
-    if (data.length !== entry.size) {
-      throw archiveError(file, `member ${name} changed while reconstructing its canonical ustar bytes`);
-    }
-    chunks.push(canonicalTarHeader(name, data.length, mode, file), data);
-    const remainder = data.length % 512;
-    if (remainder !== 0) chunks.push(Buffer.alloc(512 - remainder));
-  }
-  chunks.push(Buffer.alloc(1024));
-  return Buffer.concat(chunks);
-}
-
-function readTarEntries(file, archiveLimits, compression = "gzip") {
-  return readTarBufferEntries(readFileSync(file), file, archiveLimits, compression);
-}
-
-function inferredFormat(file) {
-  const lower = file.toLowerCase();
-  if (lower.endsWith(".zip") || lower.endsWith(".jar") || lower.endsWith(".aar") || lower.endsWith(".apk")) {
-    return "zip";
-  }
-  if (lower.endsWith(".tar.gz") || lower.endsWith(".tgz") || lower.endsWith(".crate")) {
-    return "tar.gz";
-  }
-  if (lower.endsWith(".tar.zst")) return "tar.zst";
-  return undefined;
-}
-
-export function readPortableArchiveEntries(file, options = {}) {
-  const archiveLimits = limits(options);
-  requireRegularArchive(file, archiveLimits.maxArchiveBytes);
-  const format = options.format ?? inferredFormat(file);
-  if (format === "zip") return readZipEntries(file, archiveLimits);
-  if (format === "tar.gz") return readTarEntries(file, archiveLimits);
-  if (format === "tar.zst") return readTarEntries(file, archiveLimits, "zstd");
-  throw archiveError(file, `has an unsupported archive format ${JSON.stringify(format)}`);
-}
-
-/**
- * Read an Android application package while retaining the portable ZIP safety
- * contract. APKs additionally permit Android's local-header alignment padding
- * and a structurally framed APK Signing Block immediately before the central
- * directory; ordinary ZIP/JAR/AAR readers deliberately do not accept either.
- */
-export function readAndroidApkEntries(file, options = {}) {
-  const archiveLimits = limits(options);
-  requireRegularArchive(file, archiveLimits.maxArchiveBytes);
-  return readZipEntries(file, archiveLimits, { androidApk: true });
-}
-
-/**
- * Read a deterministic file-only tar.gz emitted by Oliphaunt's canonical
- * carrier producer. In addition to the portable archive safety contract, this
- * binds the exact gzip header and POSIX ustar byte encoding used by consumers.
- */
-export function readCanonicalTarGzipEntries(file, options = {}) {
-  const archiveLimits = limits(options);
-  requireRegularArchive(file, archiveLimits.maxArchiveBytes);
-  const mode = options.fileMode ?? 0o644;
-  if (!Number.isInteger(mode) || mode < 0 || mode > 0o777) {
-    throw archiveError(file, "canonical tar.gz fileMode must be an integer between 0000 and 0777");
-  }
-  const compressed = readFileSync(file);
-  if (
-    compressed.length < 18
-    || !compressed.subarray(0, CANONICAL_GZIP_HEADER.length).equals(CANONICAL_GZIP_HEADER)
-  ) {
-    throw archiveError(file, "must use the canonical gzip method, flags, mtime, XFL, and OS header");
-  }
-  const tar = decompressedTarBuffer(compressed, file, archiveLimits, "gzip");
-  const entries = parseTarEntries(tar, file, archiveLimits);
-  const canonical = canonicalFileTar(entries, file, mode);
-  if (!tar.equals(canonical)) {
-    throw archiveError(file, "must use the exact deterministic POSIX ustar file encoding");
-  }
-  return entries;
-}
-
-export function readPortableTarZstdBufferEntries(input, options = {}) {
-  const archiveLimits = limits(options);
-  if (!Buffer.isBuffer(input) && !(input instanceof Uint8Array)) {
-    throw archiveError(options.label ?? "nested.tar.zst", "must be provided as a Buffer or Uint8Array");
-  }
-  const buffer = Buffer.isBuffer(input)
-    ? input
-    : Buffer.from(input.buffer, input.byteOffset, input.byteLength);
-  const label = options.label ?? "nested.tar.zst";
-  if (buffer.length === 0 || buffer.length > archiveLimits.maxArchiveBytes) {
-    throw archiveError(
-      label,
-      `must be non-empty and no larger than ${archiveLimits.maxArchiveBytes} bytes; got ${buffer.length}`,
-    );
-  }
-  return readTarBufferEntries(buffer, label, archiveLimits, "zstd");
-}
diff --git a/src/shared/artifact-packaging/portable-archive.test.mjs b/src/shared/artifact-packaging/portable-archive.test.mjs
deleted file mode 100644
index e52695468..000000000
--- a/src/shared/artifact-packaging/portable-archive.test.mjs
+++ /dev/null
@@ -1,833 +0,0 @@
-import assert from "node:assert/strict";
-import { mkdtempSync, mkdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
-import { tmpdir } from "node:os";
-import path from "node:path";
-import { spawnSync } from "node:child_process";
-import test from "node:test";
-import {
-  constants as zlibConstants,
-  deflateRawSync,
-  gunzipSync,
-  gzipSync,
-  zstdCompressSync,
-} from "node:zlib";
-
-import {
-  canonicalGzipSync,
-  DEFAULT_PORTABLE_ARCHIVE_LIMITS,
-  decompressSingleZstdFrame,
-  normalizeCanonicalGzipHeader,
-  portableMemberName,
-  readAndroidApkEntries,
-  readCanonicalTarGzipEntries,
-  readPortableArchiveEntries,
-  readPortableTarZstdBufferEntries,
-  RELEASE_ZSTD_COMPRESSION_LEVEL,
-  releaseZstdCompressSync,
-} from "./portable-archive.mjs";
-
-const ROOT = path.resolve(import.meta.dirname, "../../..");
-
-test("exposes the same portable member contract to nested carrier consumers", () => {
-  const archive = "/tmp/carrier.tar.gz";
-  const member = "carrier/extensions/postgis/postgis-ios-xcframework.tar.gz";
-  assert.equal(portableMemberName(member, "file", archive), member);
-  assert.throws(
-    () => portableMemberName("carrier/extensions/postgis/../escape", "file", archive),
-    /unsafe archive member/u,
-  );
-  assert.throws(
-    () => portableMemberName("carrier/extensions/postgis/file/", "file", archive),
-    /type\/path-marker mismatch/u,
-  );
-});
-
-let crcTable;
-function crc32(buffer) {
-  if (crcTable === undefined) {
-    crcTable = new Uint32Array(256);
-    for (let value = 0; value < 256; value += 1) {
-      let crc = value;
-      for (let bit = 0; bit < 8; bit += 1) {
-        crc = (crc & 1) !== 0 ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1;
-      }
-      crcTable[value] = crc >>> 0;
-    }
-  }
-  let crc = 0xffffffff;
-  for (const byte of buffer) crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8);
-  return (crc ^ 0xffffffff) >>> 0;
-}
-
-function zipArchive(rows, { beforeCentral = Buffer.alloc(0) } = {}) {
-  const locals = [];
-  const centrals = [];
-  let localOffset = 0;
-  for (const row of rows) {
-    const name = Buffer.from(row.localName ?? row.name, "utf8");
-    const centralName = Buffer.from(row.name, "utf8");
-    const data = Buffer.from(row.data ?? "payload");
-    const method = row.method ?? 0;
-    const compressed = method === 8 ? deflateRawSync(data) : data;
-    const flags = (row.flags ?? 0) | (row.descriptor ? 0x0008 : 0);
-    const actualCrc = crc32(data);
-    const storedCrc = row.crc ?? actualCrc;
-    const localExtra = row.localExtra ?? Buffer.alloc(0);
-    const centralExtra = row.centralExtra ?? Buffer.alloc(0);
-    const local = Buffer.alloc(30);
-    local.writeUInt32LE(0x04034b50, 0);
-    local.writeUInt16LE(20, 4);
-    local.writeUInt16LE(flags, 6);
-    local.writeUInt16LE(method, 8);
-    local.writeUInt32LE(storedCrc, 14);
-    local.writeUInt32LE(compressed.length, 18);
-    local.writeUInt32LE(data.length, 22);
-    local.writeUInt16LE(name.length, 26);
-    local.writeUInt16LE(localExtra.length, 28);
-    let descriptor = Buffer.alloc(0);
-    if (row.descriptor) {
-      descriptor = Buffer.alloc(row.descriptor === "signed" ? 16 : 12);
-      let descriptorOffset = 0;
-      if (row.descriptor === "signed") {
-        descriptor.writeUInt32LE(0x08074b50, 0);
-        descriptorOffset = 4;
-      }
-      descriptor.writeUInt32LE(row.descriptorCrc ?? storedCrc, descriptorOffset);
-      descriptor.writeUInt32LE(compressed.length, descriptorOffset + 4);
-      descriptor.writeUInt32LE(data.length, descriptorOffset + 8);
-    }
-    const localRecord = Buffer.concat([
-      local,
-      name,
-      localExtra,
-      compressed,
-      descriptor,
-      row.afterData ?? Buffer.alloc(0),
-    ]);
-    locals.push(localRecord);
-
-    const central = Buffer.alloc(46);
-    central.writeUInt32LE(0x02014b50, 0);
-    central.writeUInt16LE(row.versionMadeBy ?? 0x0314, 4);
-    central.writeUInt16LE(20, 6);
-    central.writeUInt16LE(flags, 8);
-    central.writeUInt16LE(method, 10);
-    central.writeUInt32LE(storedCrc, 16);
-    central.writeUInt32LE(compressed.length, 20);
-    central.writeUInt32LE(row.declaredSize ?? data.length, 24);
-    central.writeUInt16LE(centralName.length, 28);
-    central.writeUInt16LE(centralExtra.length, 30);
-    central.writeUInt32LE((row.externalAttributes ?? (0o100644 << 16)) >>> 0, 38);
-    central.writeUInt32LE(localOffset, 42);
-    centrals.push(Buffer.concat([central, centralName, centralExtra]));
-    localOffset += localRecord.length;
-  }
-  const centralDirectory = Buffer.concat(centrals);
-  const eocd = Buffer.alloc(22);
-  eocd.writeUInt32LE(0x06054b50, 0);
-  eocd.writeUInt16LE(rows.length, 8);
-  eocd.writeUInt16LE(rows.length, 10);
-  eocd.writeUInt32LE(centralDirectory.length, 12);
-  eocd.writeUInt32LE(localOffset + beforeCentral.length, 16);
-  return Buffer.concat([...locals, beforeCentral, centralDirectory, eocd]);
-}
-
-function androidAlignmentExtra(alignment, paddingLength, paddingByte = 0) {
-  const extra = Buffer.alloc(6 + paddingLength, paddingByte);
-  extra.writeUInt16LE(0xd935, 0);
-  extra.writeUInt16LE(2 + paddingLength, 2);
-  extra.writeUInt16LE(alignment, 4);
-  return extra;
-}
-
-function apkSigningBlock(pairs = [{ id: 0x7109871a, data: "signature" }]) {
-  const pairBuffers = pairs.map(({ id, data }) => {
-    const value = Buffer.from(data);
-    const pair = Buffer.alloc(12 + value.length);
-    pair.writeBigUInt64LE(BigInt(4 + value.length), 0);
-    pair.writeUInt32LE(id, 8);
-    value.copy(pair, 12);
-    return pair;
-  });
-  const pairBytes = Buffer.concat(pairBuffers);
-  const size = 24 + pairBytes.length;
-  const header = Buffer.alloc(8);
-  const footer = Buffer.alloc(8);
-  header.writeBigUInt64LE(BigInt(size), 0);
-  footer.writeBigUInt64LE(BigInt(size), 0);
-  return Buffer.concat([header, pairBytes, footer, Buffer.from("APK Sig Block 42", "ascii")]);
-}
-
-function tarOctal(value, length) {
-  return Buffer.from(`${value.toString(8).padStart(length - 1, "0")}\0`, "ascii");
-}
-
-function tarArchive(rows) {
-  const records = [];
-  for (const row of rows) {
-    const header = Buffer.alloc(512);
-    Buffer.from(row.name).copy(header, 0);
-    tarOctal(row.mode ?? 0o644, 8).copy(header, 100);
-    tarOctal(0, 8).copy(header, 108);
-    tarOctal(0, 8).copy(header, 116);
-    const data = Buffer.from(row.data ?? "");
-    tarOctal(data.length, 12).copy(header, 124);
-    tarOctal(0, 12).copy(header, 136);
-    header.fill(0x20, 148, 156);
-    header[156] = (row.type ?? "0").charCodeAt(0);
-    Buffer.from("ustar\0", "binary").copy(header, 257);
-    Buffer.from("00").copy(header, 263);
-    const checksum = header.reduce((sum, byte) => sum + byte, 0);
-    Buffer.from(`${checksum.toString(8).padStart(6, "0")}\0 `, "ascii").copy(header, 148);
-    records.push(header, data, Buffer.alloc((512 - (data.length % 512)) % 512));
-  }
-  return canonicalGzipSync(Buffer.concat([...records, Buffer.alloc(1024)]));
-}
-
-function refreshFirstTarChecksum(tar) {
-  tar.fill(0x20, 148, 156);
-  const checksum = tar.subarray(0, 512).reduce((sum, byte) => sum + byte, 0);
-  Buffer.from(`${checksum.toString(8).padStart(6, "0")}\0 `, "ascii").copy(tar, 148);
-}
-
-function fixtureFile(t, name, bytes) {
-  const root = mkdtempSync(path.join(tmpdir(), "portable-archive-test-"));
-  t.after(() => rmSync(root, { force: true, recursive: true }));
-  const file = path.join(root, name);
-  writeFileSync(file, bytes);
-  return { file, root };
-}
-
-test("uses a runner-safe default archive memory envelope", () => {
-  assert.deepEqual(DEFAULT_PORTABLE_ARCHIVE_LIMITS, {
-    maxArchiveBytes: 512 * 1024 * 1024,
-    maxEntries: 32_768,
-    maxEntryBytes: 512 * 1024 * 1024,
-    maxExpandedBytes: 1024 * 1024 * 1024,
-  });
-});
-
-test("canonicalizes host-derived gzip metadata without changing payload or caller bytes", () => {
-  const payload = Buffer.from("portable gzip payload\n");
-  const hostArchive = Buffer.from(gzipSync(payload, { mtime: 0 }));
-  hostArchive.fill(0x7f, 4, 9);
-  hostArchive[9] = 0x07;
-  const original = Buffer.from(hostArchive);
-
-  const canonical = normalizeCanonicalGzipHeader(hostArchive);
-  assert.deepEqual(
-    canonical.subarray(0, 10),
-    Buffer.from([0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03]),
-  );
-  assert.deepEqual(gunzipSync(canonical), payload);
-  assert.deepEqual(hostArchive, original);
-  assert.throws(
-    () => normalizeCanonicalGzipHeader(Buffer.from("not gzip")),
-    /flag-free gzip stream/u,
-  );
-});
-
-test("uses the shared level-19 Zstandard release setting", () => {
-  const payload = Buffer.from("portable Zstandard payload\n");
-  assert.equal(RELEASE_ZSTD_COMPRESSION_LEVEL, 19);
-  assert.deepEqual(
-    releaseZstdCompressSync(payload),
-    zstdCompressSync(payload, {
-      params: {
-        [zlibConstants.ZSTD_c_compressionLevel]: 19,
-      },
-    }),
-  );
-});
-
-test("reads a strict ZIP and validates payload bytes", (t) => {
-  const { file } = fixtureFile(t, "valid.zip", zipArchive([{ name: "root/file.txt", data: "ok" }]));
-  const entries = readPortableArchiveEntries(file);
-  assert.deepEqual([...entries.keys()], ["root/file.txt"]);
-  assert.equal(entries.get("root/file.txt").data().toString(), "ok");
-});
-
-test("accepts an unambiguous FAT-origin ZIP member", (t) => {
-  const { file } = fixtureFile(
-    t,
-    "fat.zip",
-    zipArchive([{ name: "file.txt", versionMadeBy: 0x0014, externalAttributes: 0 }]),
-  );
-  assert.equal(readPortableArchiveEntries(file).get("file.txt").isFile, true);
-});
-
-test("accepts Android legacy and 0xd935 alignment only in the APK profile", (t) => {
-  // This reproduces the exact two zero bytes on the AGP-produced
-  // assets/dexopt/baseline.prof that exposed the release failure. The leading
-  // record puts its data at a four-byte-aligned offset.
-  const legacy = fixtureFile(
-    t,
-    "legacy-aligned.apk",
-    zipArchive([
-      { name: "aaaa" },
-      { name: "assets/dexopt/baseline.prof", data: "profile", localExtra: Buffer.alloc(2) },
-    ]),
-  ).file;
-  assert.throws(() => readPortableArchiveEntries(legacy), /truncated ZIP local/u);
-  assert.equal(
-    readAndroidApkEntries(legacy).get("assets/dexopt/baseline.prof").data().toString(),
-    "profile",
-  );
-
-  // Official apksigner rewrites the same member to d935,size=3,alignment=4,
-  // one zero byte; with this path the payload begins at byte offset 64.
-  const structured = fixtureFile(
-    t,
-    "structured-aligned.apk",
-    zipArchive([{
-      name: "assets/dexopt/baseline.prof",
-      data: "profile",
-      localExtra: androidAlignmentExtra(4, 1),
-    }]),
-  ).file;
-  assert.throws(() => readPortableArchiveEntries(structured), /unsupported ZIP local/u);
-  assert.equal(
-    readAndroidApkEntries(structured).get("assets/dexopt/baseline.prof").data().toString(),
-    "profile",
-  );
-
-  const sharedLibraryName = "lib/arm64-v8a/liboliphaunt.so";
-  const unpaddedSharedLibraryOffset = 30 + Buffer.byteLength(sharedLibraryName) + 6;
-  const sharedLibraryPadding = (
-    16 * 1024 - (unpaddedSharedLibraryOffset % (16 * 1024))
-  ) % (16 * 1024);
-  const sharedLibrary = fixtureFile(
-    t,
-    "structured-shared-library.apk",
-    zipArchive([{
-      name: sharedLibraryName,
-      data: "ELF",
-      localExtra: androidAlignmentExtra(16 * 1024, sharedLibraryPadding),
-    }]),
-  ).file;
-  assert.equal(
-    readAndroidApkEntries(sharedLibrary).get(sharedLibraryName).data().toString(),
-    "ELF",
-  );
-});
-
-test("rejects malformed or misplaced Android alignment metadata", (t) => {
-  const cases = [
-    [
-      "legacy-unaligned.apk",
-      { name: "assets/dexopt/baseline.prof", localExtra: Buffer.alloc(2) },
-      /malformed legacy APK alignment/u,
-    ],
-    [
-      "legacy-nonzero.apk",
-      { name: "assets/dexopt/baseline.prof", localExtra: Buffer.from([0, 1]) },
-      /truncated ZIP local/u,
-    ],
-    [
-      "alignment-too-short.apk",
-      { name: "assets/dexopt/baseline.prof", localExtra: Buffer.from([0x35, 0xd9, 1, 0, 4]) },
-      /malformed APK alignment/u,
-    ],
-    [
-      "alignment-nonzero.apk",
-      { name: "assets/dexopt/baseline.prof", localExtra: androidAlignmentExtra(4, 1, 1) },
-      /malformed APK alignment/u,
-    ],
-    [
-      "alignment-unaligned.apk",
-      { name: "assets/dexopt/baseline.prof", localExtra: androidAlignmentExtra(4, 0) },
-      /malformed APK alignment/u,
-    ],
-    [
-      "alignment-wrong-multiple.apk",
-      { name: "assets/dexopt/baseline.prof", localExtra: androidAlignmentExtra(8, 5) },
-      /malformed APK alignment/u,
-    ],
-    [
-      "alignment-redundant.apk",
-      { name: "assets/dexopt/baseline.prof", localExtra: androidAlignmentExtra(4, 5) },
-      /malformed APK alignment/u,
-    ],
-    [
-      "alignment-compressed.apk",
-      {
-        name: "assets/dexopt/baseline.prof",
-        method: 8,
-        localExtra: androidAlignmentExtra(4, 1),
-      },
-      /alignment metadata on compressed/u,
-    ],
-    [
-      "alignment-central.apk",
-      { name: "assets/dexopt/baseline.prof", centralExtra: androidAlignmentExtra(4, 1) },
-      /unsupported ZIP central/u,
-    ],
-    [
-      "alignment-not-last.apk",
-      {
-        name: "assets/dexopt/baseline.prof",
-        localExtra: Buffer.concat([
-          androidAlignmentExtra(4, 1),
-          Buffer.from([0x55, 0x54, 5, 0, 1, 0, 0, 0, 0]),
-        ]),
-      },
-      /does not place APK alignment ZIP metadata last/u,
-    ],
-  ];
-  for (const [name, row, pattern] of cases) {
-    const file = fixtureFile(t, name, zipArchive([row])).file;
-    assert.throws(() => readAndroidApkEntries(file), pattern);
-  }
-});
-
-test("accepts a framed APK Signing Block and unknown extension pairs", (t) => {
-  const block = apkSigningBlock([
-    { id: 0x504b4453, data: "unknown-but-framed" },
-    { id: 0x7109871a, data: "v2-signature-container" },
-  ]);
-  for (const descriptor of [undefined, "unsigned", "signed"]) {
-    const file = fixtureFile(
-      t,
-      `signed-${descriptor ?? "none"}.apk`,
-      zipArchive(
-        [{ name: "AndroidManifest.xml", data: "manifest", descriptor }],
-        { beforeCentral: block },
-      ),
-    ).file;
-    assert.throws(() => readPortableArchiveEntries(file), /ambiguous .*gap/u);
-    assert.equal(
-      readAndroidApkEntries(file).get("AndroidManifest.xml").data().toString(),
-      "manifest",
-    );
-  }
-
-  const manifestRecordBytes = 30
-    + Buffer.byteLength("AndroidManifest.xml")
-    + Buffer.byteLength("manifest");
-  const canonicalPadding = 4096 - manifestRecordBytes;
-  const padded = fixtureFile(
-    t,
-    "signed-canonical-padding.apk",
-    zipArchive(
-      [{ name: "AndroidManifest.xml", data: "manifest" }],
-      { beforeCentral: Buffer.concat([Buffer.alloc(canonicalPadding), block]) },
-    ),
-  ).file;
-  assert.equal(
-    readAndroidApkEntries(padded).get("AndroidManifest.xml").data().toString(),
-    "manifest",
-  );
-});
-
-test("rejects malformed APK Signing Block gaps and descriptors", (t) => {
-  const valid = apkSigningBlock();
-  const badHeaderSize = Buffer.from(valid);
-  badHeaderSize.writeBigUInt64LE(badHeaderSize.readBigUInt64LE(0) + 1n, 0);
-  const badPairSize = Buffer.from(valid);
-  badPairSize.writeBigUInt64LE(3n, 8);
-  const unknownOnly = apkSigningBlock([{ id: 0x504b4453, data: "extension" }]);
-  const duplicatePair = apkSigningBlock([
-    { id: 0x7109871a, data: "first" },
-    { id: 0x7109871a, data: "second" },
-  ]);
-  const cases = [
-    ["opaque-gap.apk", Buffer.alloc(32, 1), /unrecognized gap/u],
-    ["nonzero-padding.apk", Buffer.concat([Buffer.from([1]), valid]), /non-zero padding/u],
-    [
-      "noncanonical-zero-padding.apk",
-      Buffer.concat([Buffer.alloc(17), valid]),
-      /non-canonical zero padding/u,
-    ],
-    ["size-mismatch.apk", badHeaderSize, /disagreeing APK Signing Block sizes/u],
-    ["bad-pair.apk", badPairSize, /invalid APK Signing Block pair size/u],
-    ["no-signature-scheme.apk", unknownOnly, /without a v2, v3, or v3[.]1/u],
-    ["duplicate-pair.apk", duplicatePair, /repeats APK Signing Block pair ID/u],
-  ];
-  for (const [name, beforeCentral, pattern] of cases) {
-    const file = fixtureFile(
-      t,
-      name,
-      zipArchive([{ name: "AndroidManifest.xml", data: "manifest" }], { beforeCentral }),
-    ).file;
-    assert.throws(() => readAndroidApkEntries(file), pattern);
-  }
-
-  const invalidDescriptor = fixtureFile(
-    t,
-    "invalid-descriptor.apk",
-    zipArchive(
-      [{ name: "AndroidManifest.xml", descriptor: "signed", descriptorCrc: 0x12345678 }],
-      { beforeCentral: valid },
-    ),
-  ).file;
-  assert.throws(
-    () => readAndroidApkEntries(invalidDescriptor),
-    /invalid or ambiguous ZIP descriptor/u,
-  );
-
-  const internalGap = fixtureFile(
-    t,
-    "internal-gap.apk",
-    zipArchive([
-      { name: "first", afterData: Buffer.alloc(4) },
-      { name: "second" },
-    ]),
-  ).file;
-  assert.throws(() => readAndroidApkEntries(internalGap), /ambiguous 4-byte gap/u);
-});
-
-test("retains entry safety and integrity checks in the Android APK profile", (t) => {
-  const cases = [
-    ["traversal.apk", [{ name: "../escape" }], /unsafe archive member/u],
-    ["duplicate.apk", [{ name: "same" }, { name: "same" }], /repeats archive member/u],
-    ["link.apk", [{ name: "link", externalAttributes: 0o120777 << 16 }], /link or special/u],
-    ["setid.apk", [{ name: "file", externalAttributes: 0o104644 << 16 }], /set-id or sticky/u],
-    ["crc.apk", [{ name: "file", crc: 0x12345678 }], /CRC-32 mismatch/u],
-  ];
-  for (const [name, rows, pattern] of cases) {
-    const file = fixtureFile(t, name, zipArchive(rows)).file;
-    assert.throws(() => readAndroidApkEntries(file), pattern);
-  }
-
-  const caseSensitive = fixtureFile(
-    t,
-    "aapt-case-sensitive.apk",
-    zipArchive([{ name: "res/2F.xml" }, { name: "res/2f.xml" }]),
-  ).file;
-  assert.deepEqual(
-    [...readAndroidApkEntries(caseSensitive).keys()],
-    ["res/2F.xml", "res/2f.xml"],
-  );
-  assert.throws(() => readPortableArchiveEntries(caseSensitive), /case\/NFC-colliding/u);
-});
-
-test("requires ZIP directory type flags and trailing path markers to agree", (t) => {
-  const valid = fixtureFile(
-    t,
-    "directory.zip",
-    zipArchive([
-      {
-        name: "root/",
-        data: "",
-        externalAttributes: ((0o040755 << 16) | 0x10) >>> 0,
-      },
-      { name: "root/file.txt", data: "ok" },
-    ]),
-  ).file;
-  const entries = readPortableArchiveEntries(valid);
-  assert.equal(entries.get("root").isDirectory, true);
-  assert.equal(entries.get("root/file.txt").isFile, true);
-
-  for (const [name, row] of [
-    ["missing-marker.zip", { name: "root", data: "", externalAttributes: ((0o040755 << 16) | 0x10) >>> 0 }],
-    ["file-with-marker.zip", { name: "root/", externalAttributes: 0o100644 << 16 }],
-  ]) {
-    const file = fixtureFile(t, name, zipArchive([row])).file;
-    assert.throws(() => readPortableArchiveEntries(file), /type\/path-marker|directory metadata/u);
-  }
-});
-
-test("rejects truncated ZIPs, duplicates, case collisions, and file-parent collisions", (t) => {
-  const valid = zipArchive([{ name: "root/file.txt" }]);
-  const truncated = fixtureFile(t, "truncated.zip", valid.subarray(0, valid.length - 1)).file;
-  assert.throws(() => readPortableArchiveEntries(truncated), /well-formed ZIP end record/u);
-
-  for (const [name, rows, pattern] of [
-    ["duplicate.zip", [{ name: "same" }, { name: "same" }], /repeats archive member/u],
-    ["case.zip", [{ name: "Name" }, { name: "name" }], /case\/NFC-colliding/u],
-    ["parent.zip", [{ name: "parent" }, { name: "parent/child" }], /as an archive directory/u],
-  ]) {
-    const file = fixtureFile(t, name, zipArchive(rows)).file;
-    assert.throws(() => readPortableArchiveEntries(file), pattern);
-  }
-});
-
-test("rejects ZIP links, special entries, unsafe paths, and ambiguous creator types", (t) => {
-  const cases = [
-    ["symlink.zip", { name: "link", externalAttributes: 0o120777 << 16 }, /link or special/u],
-    ["special.zip", { name: "device", externalAttributes: 0o020666 << 16 }, /link or special/u],
-    ["unsafe.zip", { name: "../escape", externalAttributes: 0o100644 << 16 }, /unsafe archive member/u],
-    ["ambiguous.zip", { name: "file", externalAttributes: 0 }, /ambiguous Unix creator type/u],
-  ];
-  for (const [name, row, pattern] of cases) {
-    const file = fixtureFile(t, name, zipArchive([row])).file;
-    assert.throws(() => readPortableArchiveEntries(file), pattern);
-  }
-});
-
-test("rejects ZIP local-central mismatch, unsupported flags/extras, size bombs, and CRC errors", (t) => {
-  const unknownExtra = Buffer.from([0xef, 0xbe, 0x00, 0x00]);
-  const cases = [
-    ["mismatch.zip", { name: "central", localName: "local__" }, /name disagreement/u, {}],
-    ["flags.zip", { name: "file", flags: 0x2000 }, /unsupported or encrypted ZIP flags/u, {}],
-    ["extra.zip", { name: "file", centralExtra: unknownExtra }, /unsupported ZIP central/u, {}],
-    ["bomb.zip", { name: "file", data: "0123456789", method: 8 }, /entry-size limit/u, { maxEntryBytes: 5 }],
-    ["crc.zip", { name: "file", crc: 0x12345678 }, /CRC-32 mismatch/u, {}],
-    ["setid.zip", { name: "file", externalAttributes: 0o104644 << 16 }, /set-id or sticky/u, {}],
-  ];
-  for (const [name, row, pattern, options] of cases) {
-    const file = fixtureFile(t, name, zipArchive([row])).file;
-    assert.throws(() => readPortableArchiveEntries(file, options), pattern);
-  }
-
-  const overlappingBytes = zipArchive([
-    { name: "first", data: "a" },
-    { name: "second", data: "b" },
-  ]);
-  const overlapEocd = overlappingBytes.length - 22;
-  const overlapCentral = overlappingBytes.readUInt32LE(overlapEocd + 16);
-  overlappingBytes.writeUInt32LE(2, 18);
-  overlappingBytes.writeUInt32LE(2, 22);
-  overlappingBytes.writeUInt32LE(2, overlapCentral + 20);
-  overlappingBytes.writeUInt32LE(2, overlapCentral + 24);
-  const overlapping = fixtureFile(t, "overlap.zip", overlappingBytes).file;
-  assert.throws(() => readPortableArchiveEntries(overlapping), /overlapping ZIP local records/u);
-
-  const aggregate = fixtureFile(
-    t,
-    "aggregate.zip",
-    zipArchive([{ name: "one", data: "1234" }, { name: "two", data: "5678" }]),
-  ).file;
-  assert.throws(
-    () => readPortableArchiveEntries(aggregate, { maxEntryBytes: 5, maxExpandedBytes: 7 }),
-    /expanded ZIP data limit/u,
-  );
-  assert.throws(
-    () => readPortableArchiveEntries(aggregate, { maxArchiveBytes: 10 }),
-    /no larger than 10 bytes/u,
-  );
-});
-
-test("reads strict ustar and rejects links, bad checksums, padding, and end markers", (t) => {
-  const validBytes = tarArchive([{ name: "root/file", data: "ok" }]);
-  const valid = fixtureFile(t, "valid.tar.gz", validBytes).file;
-  assert.equal(readPortableArchiveEntries(valid).get("root/file").data().toString(), "ok");
-
-  const linked = fixtureFile(t, "link.tar.gz", tarArchive([{ name: "link", type: "2" }])).file;
-  assert.throws(() => readPortableArchiveEntries(linked), /link or special ustar entry/u);
-  const device = fixtureFile(t, "device.tar.gz", tarArchive([{ name: "device", type: "3" }])).file;
-  assert.throws(() => readPortableArchiveEntries(device), /link or special ustar entry/u);
-
-  const setid = fixtureFile(t, "setid.tar.gz", tarArchive([{ name: "file", mode: 0o4644 }])).file;
-  assert.throws(() => readPortableArchiveEntries(setid), /set-id or sticky permission bits/u);
-
-  const tar = gunzipForTest(validBytes);
-  tar[0] ^= 1;
-  const badChecksum = fixtureFile(t, "checksum.tar.gz", gzipSync(tar, { mtime: 0 })).file;
-  assert.throws(() => readPortableArchiveEntries(badChecksum), /header checksum/u);
-
-  const withoutEnd = gunzipForTest(validBytes).subarray(0, 1024);
-  const badEnd = fixtureFile(t, "end.tar.gz", gzipSync(withoutEnd, { mtime: 0 })).file;
-  assert.throws(() => readPortableArchiveEntries(badEnd), /two-block ustar end marker/u);
-
-  const paddedTar = gunzipForTest(validBytes);
-  paddedTar[512 + 2] = 1;
-  const badPadding = fixtureFile(t, "padding.tar.gz", gzipSync(paddedTar, { mtime: 0 })).file;
-  assert.throws(() => readPortableArchiveEntries(badPadding), /non-zero ustar padding/u);
-
-  assert.throws(
-    () => readPortableArchiveEntries(valid, { maxExpandedBytes: 1024 }),
-    /bounded readable gzip stream/u,
-  );
-
-  const numericJunkTar = gunzipForTest(validBytes);
-  numericJunkTar[155] = "X".charCodeAt(0);
-  const numericJunk = fixtureFile(t, "numeric-junk.tar.gz", gzipSync(numericJunkTar)).file;
-  assert.throws(() => readPortableArchiveEntries(numericJunk), /non-padding bytes after the ustar checksum terminator/u);
-
-  const deviceFieldTar = gunzipForTest(validBytes);
-  tarOctal(1, 8).copy(deviceFieldTar, 329);
-  refreshFirstTarChecksum(deviceFieldTar);
-  const deviceField = fixtureFile(t, "device-field.tar.gz", gzipSync(deviceFieldTar)).file;
-  assert.throws(() => readPortableArchiveEntries(deviceField), /sets device numbers on non-device/u);
-
-  const linkFieldTar = gunzipForTest(validBytes);
-  Buffer.from("unexpected-target\0").copy(linkFieldTar, 157);
-  refreshFirstTarChecksum(linkFieldTar);
-  const linkField = fixtureFile(t, "link-field.tar.gz", gzipSync(linkFieldTar)).file;
-  assert.throws(() => readPortableArchiveEntries(linkField), /sets a link target on non-link/u);
-});
-
-test("binds the exact deterministic tar-gzip encoding used by release consumers", (t) => {
-  const validBytes = tarArchive([
-    { name: "root/LICENSE", data: "license\n" },
-    { name: "root/bundle-manifest.json", data: "{}\n" },
-  ]);
-  const valid = fixtureFile(t, "canonical.tar.gz", validBytes).file;
-  assert.deepEqual([...readCanonicalTarGzipEntries(valid).keys()], [
-    "root/LICENSE",
-    "root/bundle-manifest.json",
-  ]);
-
-  const wrongGzipHeader = Buffer.from(validBytes);
-  wrongGzipHeader[9] = 0;
-  const wrongGzip = fixtureFile(t, "wrong-gzip-header.tar.gz", wrongGzipHeader).file;
-  assert.throws(
-    () => readCanonicalTarGzipEntries(wrongGzip),
-    /canonical gzip method, flags, mtime, XFL, and OS header/u,
-  );
-
-  const ownerTar = gunzipForTest(validBytes);
-  Buffer.from("builder\0", "ascii").copy(ownerTar, 265);
-  refreshFirstTarChecksum(ownerTar);
-  const owner = fixtureFile(t, "owner.tar.gz", canonicalGzipSync(ownerTar)).file;
-  assert.doesNotThrow(() => readPortableArchiveEntries(owner));
-  assert.throws(
-    () => readCanonicalTarGzipEntries(owner),
-    /exact deterministic POSIX ustar file encoding/u,
-  );
-
-  const unsorted = fixtureFile(
-    t,
-    "unsorted.tar.gz",
-    tarArchive([
-      { name: "root/z", data: "last" },
-      { name: "root/a", data: "first" },
-    ]),
-  ).file;
-  assert.doesNotThrow(() => readPortableArchiveEntries(unsorted));
-  assert.throws(
-    () => readCanonicalTarGzipEntries(unsorted),
-    /canonical file members.*sorted order/u,
-  );
-});
-
-test("requires ustar directory type flags and trailing path markers to agree", (t) => {
-  const valid = fixtureFile(
-    t,
-    "directory.tar.gz",
-    tarArchive([
-      { name: "root/", type: "5", mode: 0o755 },
-      { name: "root/file", data: "ok" },
-    ]),
-  ).file;
-  const entries = readPortableArchiveEntries(valid);
-  assert.equal(entries.get("root").isDirectory, true);
-  assert.equal(entries.get("root/file").isFile, true);
-
-  for (const [name, row] of [
-    ["missing-marker.tar.gz", { name: "root", type: "5", mode: 0o755 }],
-    ["file-with-marker.tar.gz", { name: "root/", type: "0", mode: 0o644 }],
-  ]) {
-    const file = fixtureFile(t, name, tarArchive([row])).file;
-    assert.throws(() => readPortableArchiveEntries(file), /type\/path-marker mismatch/u);
-  }
-});
-
-test("rejects trailing bytes, concatenated gzip members, and corrupt gzip trailers", (t) => {
-  const valid = tarArchive([{ name: "file", data: "payload" }]);
-  const concatenated = fixtureFile(t, "concatenated.tar.gz", Buffer.concat([valid, valid])).file;
-  assert.throws(() => readPortableArchiveEntries(concatenated), /trailing data or multiple gzip members/u);
-
-  const trailing = fixtureFile(t, "trailing.tar.gz", Buffer.concat([valid, Buffer.from("trailing")])).file;
-  assert.throws(() => readPortableArchiveEntries(trailing), /gzip/u);
-
-  const corrupt = Buffer.from(valid);
-  corrupt[corrupt.length - 8] ^= 1;
-  const corruptTrailer = fixtureFile(t, "corrupt-trailer.tar.gz", corrupt).file;
-  assert.throws(() => readPortableArchiveEntries(corruptTrailer), /gzip payload CRC-32/u);
-});
-
-test("reads one Zstandard frame and rejects trailing bytes or concatenated frames", (t) => {
-  const tar = gunzipForTest(tarArchive([{ name: "root/file", data: "payload" }]));
-  const valid = zstdCompressSync(tar);
-  const archive = fixtureFile(t, "valid.tar.zst", valid).file;
-  assert.equal(readPortableArchiveEntries(archive).get("root/file").data().toString(), "payload");
-
-  const trailing = fixtureFile(
-    t,
-    "trailing.tar.zst",
-    Buffer.concat([valid, Buffer.from("trailing")]),
-  ).file;
-  assert.throws(
-    () => readPortableArchiveEntries(trailing),
-    /trailing data or multiple Zstandard frames/u,
-  );
-
-  const concatenated = fixtureFile(
-    t,
-    "concatenated.tar.zst",
-    Buffer.concat([valid, valid]),
-  ).file;
-  assert.throws(
-    () => readPortableArchiveEntries(concatenated),
-    /trailing data or multiple Zstandard frames/u,
-  );
-});
-
-test("strictly parses an in-memory tar.zst with the same bounded portable contract", () => {
-  const tar = gunzipForTest(tarArchive([
-    { name: "oliphaunt/", type: "5", mode: 0o755 },
-    { name: "oliphaunt/bin/", type: "5", mode: 0o755 },
-    { name: "oliphaunt/bin/postgres", data: "runtime" },
-  ]));
-  const compressed = zstdCompressSync(tar);
-  const entries = readPortableTarZstdBufferEntries(compressed, {
-    label: "nested oliphaunt.wasix.tar.zst",
-  });
-  assert.deepEqual([...entries.keys()], [
-    "oliphaunt",
-    "oliphaunt/bin",
-    "oliphaunt/bin/postgres",
-  ]);
-  assert.equal(entries.get("oliphaunt/bin/postgres").data().toString(), "runtime");
-  assert.equal(
-    decompressSingleZstdFrame(compressed, { label: "nested frame" }).equals(tar),
-    true,
-  );
-
-  for (const [label, rows, pattern] of [
-    ["duplicate", [{ name: "same", data: "one" }, { name: "same", data: "two" }], /repeats archive member/u],
-    ["traversal", [{ name: "../escape", data: "bad" }], /unsafe archive member/u],
-    ["symlink", [{ name: "link", type: "2" }], /link or special ustar entry/u],
-    ["special", [{ name: "device", type: "3" }], /link or special ustar entry/u],
-  ]) {
-    const candidate = zstdCompressSync(gunzipForTest(tarArchive(rows)));
-    assert.throws(
-      () => readPortableTarZstdBufferEntries(candidate, { label }),
-      pattern,
-      label,
-    );
-  }
-
-  assert.throws(
-    () => readPortableTarZstdBufferEntries(Buffer.concat([compressed, compressed])),
-    /trailing data or multiple Zstandard frames/u,
-  );
-  assert.throws(
-    () => readPortableTarZstdBufferEntries(compressed, { maxArchiveBytes: compressed.length - 1 }),
-    /no larger than/u,
-  );
-  assert.throws(
-    () => decompressSingleZstdFrame(compressed, { maxOutputBytes: tar.length - 1 }),
-    /bounded readable Zstandard stream/u,
-  );
-});
-
-test("rejects symlink archive inputs before parsing", (t) => {
-  const { file, root } = fixtureFile(t, "real.zip", zipArchive([{ name: "file" }]));
-  const linked = path.join(root, "linked.zip");
-  symlinkSync(file, linked);
-  assert.throws(() => readPortableArchiveEntries(linked), /regular, non-symlink/u);
-});
-
-test("accepts ZIPs emitted by the canonical archive-directory producer", (t) => {
-  const root = mkdtempSync(path.join(tmpdir(), "portable-producer-test-"));
-  t.after(() => rmSync(root, { force: true, recursive: true }));
-  const source = path.join(root, "Fixture.xcframework");
-  mkdirSync(source);
-  writeFileSync(path.join(source, "Info.plist"), "fixture");
-  const output = path.join(root, "fixture.zip");
-  const result = spawnSync(
-    path.join(ROOT, "tools/dev/bun.sh"),
-    ["src/shared/artifact-packaging/archive-directory.mjs", "--keep-parent", source, output],
-    { cwd: ROOT, encoding: "utf8" },
-  );
-  assert.equal(result.status, 0, result.stderr);
-  const entries = readPortableArchiveEntries(output);
-  assert.equal(entries.get("Fixture.xcframework/Info.plist").data().toString(), "fixture");
-});
-
-function gunzipForTest(buffer) {
-  return gunzipSync(buffer);
-}
diff --git a/src/shared/cluster-seed-contract/contract.json b/src/shared/cluster-seed-contract/contract.json
deleted file mode 100644
index 437d51942..000000000
--- a/src/shared/cluster-seed-contract/contract.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
-  "schema": "oliphaunt-cluster-seed-contract-v1",
-  "icuDataSchema": "oliphaunt-icu-data-v1",
-  "manifests": {
-    "native": {
-      "schema": "oliphaunt-runtime-resources-v1",
-      "layout": "oliphaunt-cluster-seed-v1",
-      "cacheKeyPattern": "^[A-Za-z0-9._-]{1,128}$",
-      "cacheKeyDisallowedValues": [
-        ".",
-        ".."
-      ]
-    },
-    "wasix": {
-      "schema": "oliphaunt-cluster-seed-v1"
-    }
-  },
-  "profiles": {
-    "standard": {
-      "artifactRole": "cluster-seed-standard",
-      "requiredRuntimeFeatures": []
-    },
-    "icu": {
-      "artifactRole": "cluster-seed-icu",
-      "requiredRuntimeFeatures": [
-        "icu"
-      ]
-    }
-  },
-  "icu": {
-    "artifactRole": "icu-data",
-    "dataForm": "files-le",
-    "dataVersion": "76.1",
-    "internalReadinessEnvironment": "OLIPHAUNT_INTERNAL_ICU_READY",
-    "internalReadinessValue": "1",
-    "logicalTreeDigest": "sha256(path-nul-size-nul-bytes-lf)",
-    "runtimePath": "share/icu"
-  },
-  "compatibilityKeys": {
-    "native": {
-      "android-datum64": "native-pg18-android-datum64-v1",
-      "ios-datum64": "native-pg18-ios-datum64-v1",
-      "linux-arm64-gnu": "native-pg18-linux-arm64-gnu-v1",
-      "linux-x64-gnu": "native-pg18-linux-x64-gnu-v1",
-      "macos-arm64": "native-pg18-macos-arm64-v1",
-      "windows-x64-msvc": "native-pg18-windows-x64-msvc-v1"
-    },
-    "wasixDatum32": "wasix-pg18-datum32-v1"
-  },
-  "physicalFormats": {
-    "native": "native-pg18-v1",
-    "wasix": "wasix-pg18-v1"
-  }
-}
diff --git a/src/shared/cluster-seed-contract/moon.yml b/src/shared/cluster-seed-contract/moon.yml
deleted file mode 100644
index 853b8f06c..000000000
--- a/src/shared/cluster-seed-contract/moon.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "cluster-seed-contract"
-language: "javascript"
-layer: "configuration"
-stack: "systems"
-tags: ["postgres", "contract", "runtime"]
-
-project:
-  title: "Cluster Seed Contract"
-  description: "Canonical standard/ICU seed and portable ICU-data identity contract."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "**/*": ["@oliphaunt/core"]
-
-fileGroups:
-  contract:
-    - "**/*"
-    - "!moon.yml"
diff --git a/src/shared/extension-runtime-contract/extension-target-profiles.mjs b/src/shared/extension-runtime-contract/extension-target-profiles.mjs
deleted file mode 100644
index 7bdda37de..000000000
--- a/src/shared/extension-runtime-contract/extension-target-profiles.mjs
+++ /dev/null
@@ -1,88 +0,0 @@
-import { readFileSync } from "node:fs";
-import path from "node:path";
-
-export const EXTENSION_TARGET_PROFILES_RELATIVE_PATH =
-  "src/shared/extension-runtime-contract/extension-target-profiles.toml";
-const ROOT = path.resolve(import.meta.dir, "../../..");
-const ID = /^[a-z][a-z0-9_-]*$/u;
-
-function fail(message) {
-  throw new Error(`extension target profiles: ${message}`);
-}
-
-function table(value, label) {
-  if (value === null || Array.isArray(value) || typeof value !== "object") {
-    fail(`${label} must be a table`);
-  }
-  return value;
-}
-
-function exactKeys(value, expected, label) {
-  const actual = Object.keys(value).sort();
-  const wanted = [...expected].sort();
-  if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
-    fail(`${label} fields must be exactly ${wanted.join(", ")}; got ${actual.join(", ")}`);
-  }
-}
-
-function id(value, label) {
-  if (typeof value !== "string" || !ID.test(value)) {
-    fail(`${label} must match ${ID}`);
-  }
-  return value;
-}
-
-export function validateExtensionTargetProfiles(raw) {
-  table(raw, "root");
-  exactKeys(raw, ["profiles", "schema"], "root");
-  if (raw.schema !== "oliphaunt-extension-artifact-target-profiles-v1") {
-    fail("schema must be oliphaunt-extension-artifact-target-profiles-v1");
-  }
-  if (!Array.isArray(raw.profiles) || raw.profiles.length === 0) {
-    fail("profiles must be a non-empty array");
-  }
-
-  const profileIds = new Set();
-  const targets = new Set();
-  const profiles = raw.profiles.map((rawProfile, profileIndex) => {
-    const profile = table(rawProfile, `profiles[${profileIndex}]`);
-    exactKeys(profile, ["id", "targets"], `profiles[${profileIndex}]`);
-    const profileId = id(profile.id, `profiles[${profileIndex}].id`);
-    if (profileIds.has(profileId)) fail(`duplicate profile ${profileId}`);
-    profileIds.add(profileId);
-    if (!Array.isArray(profile.targets) || profile.targets.length === 0) {
-      fail(`profile ${profileId} must define a non-empty targets array`);
-    }
-    const rows = profile.targets.map((rawTarget, targetIndex) => {
-      const target = table(rawTarget, `profile ${profileId} targets[${targetIndex}]`);
-      exactKeys(target, ["family", "kind", "target"], `profile ${profileId} targets[${targetIndex}]`);
-      const targetId = id(target.target, `profile ${profileId} targets[${targetIndex}].target`);
-      if (targets.has(targetId)) fail(`duplicate target ${targetId}`);
-      targets.add(targetId);
-      return Object.freeze({
-        profileId,
-        target: targetId,
-        family: id(target.family, `target ${targetId}.family`),
-        kind: id(target.kind, `target ${targetId}.kind`),
-      });
-    });
-    return Object.freeze({ id: profileId, targets: Object.freeze(rows) });
-  });
-
-  return Object.freeze({
-    schema: raw.schema,
-    profiles: Object.freeze(profiles),
-    targets: Object.freeze(profiles.flatMap((profile) => profile.targets)),
-  });
-}
-
-export function loadExtensionTargetProfiles({
-  file = path.join(ROOT, EXTENSION_TARGET_PROFILES_RELATIVE_PATH),
-} = {}) {
-  try {
-    return validateExtensionTargetProfiles(Bun.TOML.parse(readFileSync(file, "utf8")));
-  } catch (error) {
-    if (error instanceof Error && error.message.startsWith("extension target profiles:")) throw error;
-    fail(`cannot read ${file}: ${error instanceof Error ? error.message : String(error)}`);
-  }
-}
diff --git a/src/shared/extension-runtime-contract/extension-target-profiles.test.mjs b/src/shared/extension-runtime-contract/extension-target-profiles.test.mjs
deleted file mode 100644
index 97ae73586..000000000
--- a/src/shared/extension-runtime-contract/extension-target-profiles.test.mjs
+++ /dev/null
@@ -1,34 +0,0 @@
-import { expect, test } from "bun:test";
-
-import { validateExtensionTargetProfiles } from "./extension-target-profiles.mjs";
-
-function fixture() {
-  return {
-    schema: "oliphaunt-extension-artifact-target-profiles-v1",
-    profiles: [{
-      id: "native-v1",
-      targets: [{ target: "linux-x64-gnu", family: "native", kind: "native-dynamic" }],
-    }],
-  };
-}
-
-test("normalizes the minimal target identity contract", () => {
-  expect(validateExtensionTargetProfiles(fixture()).targets).toEqual([{
-    profileId: "native-v1",
-    target: "linux-x64-gnu",
-    family: "native",
-    kind: "native-dynamic",
-  }]);
-});
-
-test("rejects intermediate state fields", () => {
-  const raw = fixture();
-  raw.profiles[0].targets[0].status = "supported";
-  expect(() => validateExtensionTargetProfiles(raw)).toThrow(/fields must be exactly family, kind, target/u);
-});
-
-test("rejects a target declared by more than one profile", () => {
-  const raw = fixture();
-  raw.profiles.push({ ...raw.profiles[0], id: "duplicate-v1" });
-  expect(() => validateExtensionTargetProfiles(raw)).toThrow(/duplicate target linux-x64-gnu/u);
-});
diff --git a/src/shared/extension-runtime-contract/moon.yml b/src/shared/extension-runtime-contract/moon.yml
deleted file mode 100644
index e27a927bd..000000000
--- a/src/shared/extension-runtime-contract/moon.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "extension-runtime-contract"
-language: "javascript"
-layer: "configuration"
-stack: "systems"
-tags: ["extensions", "contract", "runtime"]
-dependsOn:
-  - id: "artifact-packaging"
-    scope: "build"
-
-project:
-  title: "Extension Runtime Contract"
-  description: "Shared contract between base runtimes and exact extension artifacts."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "**/*": ["@oliphaunt/core"]
-
-fileGroups:
-  contract:
-    - "contract.toml"
-    - "extension-artifact-archive-policy.properties"
-    - "extension-target-profiles.mjs"
-    - "extension-target-profiles.toml"
-    - "wasix-extension-install.mjs"
-
-tasks:
-  test:
-    tags: ["quality", "unit"]
-    command: "bun test src/shared/extension-runtime-contract/*.test.mjs"
-    inputs:
-      - "@group(contract)"
-      - "*.test.mjs"
-      - project: "artifact-packaging"
-        group: "source"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
diff --git a/src/shared/extension-runtime-contract/wasix-extension-install.mjs b/src/shared/extension-runtime-contract/wasix-extension-install.mjs
deleted file mode 100644
index 3c75ed6ca..000000000
--- a/src/shared/extension-runtime-contract/wasix-extension-install.mjs
+++ /dev/null
@@ -1,473 +0,0 @@
-import { createHash } from "node:crypto";
-
-import { readPortableTarZstdBufferEntries } from "../artifact-packaging/portable-archive.mjs";
-
-export const WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA =
-  "oliphaunt-wasix-extension-install-sidecar-v1";
-export const WASIX_EXTENSION_INSTALL_SCHEMA = "oliphaunt-wasix-extension-install-v1";
-export const EXTENSION_RUNTIME_CONTRACT_PATH =
-  "src/shared/extension-runtime-contract/contract.toml";
-export const EXTENSION_RUNTIME_CONTRACT_SCHEMA =
-  "oliphaunt-extension-runtime-contract-v1";
-
-const LOWER_SHA256 = /^[0-9a-f]{64}$/u;
-const SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/u;
-const SIDECAR_FIELDS = Object.freeze([
-  "archive",
-  "install",
-  "schema",
-  "sha256",
-  "size",
-  "sqlName",
-]);
-const INSTALL_FIELDS = Object.freeze([
-  "coreExportsRequired",
-  "dependencies",
-  "installedFiles",
-  "lifecycle",
-  "loadOrder",
-  "name",
-  "nativeModule",
-  "nativeModules",
-  "schema",
-  "unresolvedImports",
-]);
-const LIFECYCLE_FIELDS = Object.freeze([
-  "createExtension",
-  "createSchema",
-  "loadSql",
-  "postCreateSql",
-  "preloadRequired",
-  "restartRequired",
-  "sharedMemoryRequired",
-  "startupConfig",
-]);
-const NATIVE_MODULE_FIELDS = Object.freeze([
-  "moduleSha256",
-  "name",
-  "path",
-  "sha256",
-  "size",
-]);
-const UNRESOLVED_IMPORT_FIELDS = Object.freeze(["kind", "module", "name"]);
-
-function error(label, message) {
-  return new Error(`wasix-extension-install-contract: ${label} ${message}`);
-}
-
-function object(value, label) {
-  if (value === null || Array.isArray(value) || typeof value !== "object") {
-    throw error(label, "must be an object");
-  }
-  return value;
-}
-
-function exactObject(value, fields, label) {
-  const result = object(value, label);
-  const actual = Object.keys(result).sort();
-  const expected = [...fields].sort();
-  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
-    throw error(label, `must contain exactly ${expected.join(", ")}`);
-  }
-  return result;
-}
-
-function nonEmptyString(value, label) {
-  if (typeof value !== "string" || value.length === 0) {
-    throw error(label, "must be a non-empty string");
-  }
-  return value;
-}
-
-function safeRelativePath(value, label) {
-  const result = nonEmptyString(value, label);
-  const normalized = result.replaceAll("\\", "/");
-  const segments = normalized.split("/");
-  if (
-    result !== normalized
-    || result.startsWith("/")
-    || segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")
-  ) {
-    throw error(label, "must be a canonical safe relative path");
-  }
-  return result;
-}
-
-function sha256(value, label) {
-  if (typeof value !== "string" || !LOWER_SHA256.test(value)) {
-    throw error(label, "must be a lowercase SHA-256 digest");
-  }
-  return value;
-}
-
-function positiveSize(value, label) {
-  if (!Number.isSafeInteger(value) || value <= 0) {
-    throw error(label, "must be a positive safe integer");
-  }
-  return value;
-}
-
-function stringList(value, label, { paths = false } = {}) {
-  if (!Array.isArray(value)) throw error(label, "must be an array");
-  const result = value.map((entry, index) => {
-    const entryLabel = `${label}[${index}]`;
-    return paths ? safeRelativePath(entry, entryLabel) : nonEmptyString(entry, entryLabel);
-  });
-  if (new Set(result).size !== result.length) {
-    throw error(label, "must not contain duplicates");
-  }
-  return result;
-}
-
-function uniqueValues(values, label) {
-  if (new Set(values).size !== values.length) {
-    throw error(label, "must not contain duplicates");
-  }
-}
-
-function sqlName(value, label) {
-  const result = nonEmptyString(value, label);
-  if (!SQL_NAME.test(result)) throw error(label, "must be a portable PostgreSQL extension name");
-  return result;
-}
-
-function sameValue(left, right) {
-  return JSON.stringify(left) === JSON.stringify(right);
-}
-
-function lifecycleFromManifest(value, label) {
-  const row = object(value, label);
-  const result = {
-    createExtension: row["create-extension"],
-    createSchema: row["create-schema"] ?? null,
-    loadSql: row["load-sql"],
-    postCreateSql: row["post-create-sql"],
-    startupConfig: row["startup-config"],
-    preloadRequired: row["preload-required"],
-    restartRequired: row["restart-required"],
-    sharedMemoryRequired: row["shared-memory-required"],
-  };
-  return checkedLifecycle(result, label);
-}
-
-function checkedLifecycle(value, label) {
-  const row = exactObject(value, LIFECYCLE_FIELDS, label);
-  for (const field of [
-    "createExtension",
-    "preloadRequired",
-    "restartRequired",
-    "sharedMemoryRequired",
-  ]) {
-    if (typeof row[field] !== "boolean") throw error(`${label}.${field}`, "must be a boolean");
-  }
-  if (row.createSchema !== null) nonEmptyString(row.createSchema, `${label}.createSchema`);
-  return {
-    createExtension: row.createExtension,
-    createSchema: row.createSchema,
-    loadSql: stringList(row.loadSql, `${label}.loadSql`),
-    postCreateSql: stringList(row.postCreateSql, `${label}.postCreateSql`),
-    startupConfig: stringList(row.startupConfig, `${label}.startupConfig`),
-    preloadRequired: row.preloadRequired,
-    restartRequired: row.restartRequired,
-    sharedMemoryRequired: row.sharedMemoryRequired,
-  };
-}
-
-function compactNativeModule(value, label) {
-  const row = object(value, label);
-  return checkedNativeModule({
-    name: row.name,
-    path: row.path,
-    sha256: row.sha256,
-    moduleSha256: row["module-sha256"],
-    size: row.size,
-  }, label);
-}
-
-function checkedNativeModule(value, label) {
-  const row = exactObject(value, NATIVE_MODULE_FIELDS, label);
-  return {
-    name: nonEmptyString(row.name, `${label}.name`),
-    path: safeRelativePath(row.path, `${label}.path`),
-    sha256: sha256(row.sha256, `${label}.sha256`),
-    moduleSha256: sha256(row.moduleSha256, `${label}.moduleSha256`),
-    size: positiveSize(row.size, `${label}.size`),
-  };
-}
-
-function checkedUnresolvedImport(value, label) {
-  const row = exactObject(value, UNRESOLVED_IMPORT_FIELDS, label);
-  return {
-    module: nonEmptyString(row.module, `${label}.module`),
-    name: nonEmptyString(row.name, `${label}.name`),
-    kind: nonEmptyString(row.kind, `${label}.kind`),
-  };
-}
-
-function checkedInstall(value, label, { expectedSqlName } = {}) {
-  const row = exactObject(value, INSTALL_FIELDS, label);
-  if (row.schema !== WASIX_EXTENSION_INSTALL_SCHEMA) {
-    throw error(`${label}.schema`, `must be ${WASIX_EXTENSION_INSTALL_SCHEMA}`);
-  }
-  const nativeModule = row.nativeModule === null
-    ? null
-    : safeRelativePath(row.nativeModule, `${label}.nativeModule`);
-  if (!Array.isArray(row.nativeModules)) throw error(`${label}.nativeModules`, "must be an array");
-  if (!Array.isArray(row.unresolvedImports)) {
-    throw error(`${label}.unresolvedImports`, "must be an array");
-  }
-  const nativeModules = row.nativeModules.map((entry, index) =>
-    checkedNativeModule(entry, `${label}.nativeModules[${index}]`));
-  uniqueValues(nativeModules.map((entry) => entry.name), `${label}.nativeModules names`);
-  uniqueValues(nativeModules.map((entry) => entry.path), `${label}.nativeModules paths`);
-  if ((nativeModule === null) !== (nativeModules.length === 0)) {
-    throw error(
-      `${label}.nativeModule`,
-      "must be null exactly when nativeModules is empty",
-    );
-  }
-  const dependencies = stringList(row.dependencies, `${label}.dependencies`)
-    .map((dependency, index) => sqlName(dependency, `${label}.dependencies[${index}]`));
-  if (expectedSqlName !== undefined) {
-    const rootSqlName = sqlName(expectedSqlName, `${label} expected SQL name`);
-    if (dependencies.includes(rootSqlName)) {
-      throw error(`${label}.dependencies`, `must not include its own SQL name ${rootSqlName}`);
-    }
-  }
-  const installedFiles = stringList(
-    row.installedFiles,
-    `${label}.installedFiles`,
-    { paths: true },
-  );
-  for (const module of nativeModules) {
-    if (!installedFiles.includes(module.path)) {
-      throw error(
-        `${label}.nativeModules`,
-        `path ${module.path} must appear in installedFiles`,
-      );
-    }
-  }
-  return {
-    schema: WASIX_EXTENSION_INSTALL_SCHEMA,
-    name: nonEmptyString(row.name, `${label}.name`),
-    nativeModule,
-    nativeModules,
-    coreExportsRequired: stringList(
-      row.coreExportsRequired,
-      `${label}.coreExportsRequired`,
-    ),
-    dependencies,
-    loadOrder: stringList(row.loadOrder, `${label}.loadOrder`, { paths: true }),
-    lifecycle: checkedLifecycle(row.lifecycle, `${label}.lifecycle`),
-    installedFiles,
-    unresolvedImports: row.unresolvedImports.map((entry, index) =>
-      checkedUnresolvedImport(entry, `${label}.unresolvedImports[${index}]`)),
-  };
-}
-
-export function assertWasixExtensionInstall(value, {
-  expectedSqlName,
-  label = "WASIX extension install",
-} = {}) {
-  return deepFreeze(checkedInstall(value, label, { expectedSqlName }));
-}
-
-export function assertWasixExtensionMemberInstall(value, {
-  label = "extension member",
-} = {}) {
-  const member = object(value, label);
-  if (!Array.isArray(member.assets)) throw error(`${label}.assets`, "must be an array");
-  const portableAssets = member.assets.filter((asset) =>
-    asset?.family === "wasix"
-    && asset?.target === "wasix-portable"
-    && asset?.kind === "wasix-runtime");
-  if (portableAssets.length === 0) {
-    if (member.wasixInstall !== null) {
-      throw error(`${label}.wasixInstall`, "must be null without a portable WASIX asset");
-    }
-    return null;
-  }
-  if (portableAssets.length !== 1) {
-    throw error(label, "must declare exactly one portable WASIX asset");
-  }
-  return assertWasixExtensionInstall(member.wasixInstall, {
-    expectedSqlName: member.sqlName,
-    label: `${label}.wasixInstall`,
-  });
-}
-
-export function assertWasixExtensionInstallSidecar(value, {
-  expectedArchive,
-  expectedSha256,
-  expectedSize,
-  expectedSqlName,
-  label = "install sidecar",
-} = {}) {
-  const row = exactObject(value, SIDECAR_FIELDS, label);
-  if (row.schema !== WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA) {
-    throw error(`${label}.schema`, `must be ${WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA}`);
-  }
-  const sqlName = nonEmptyString(row.sqlName, `${label}.sqlName`);
-  if (!SQL_NAME.test(sqlName)) throw error(`${label}.sqlName`, "is not portable");
-  const archive = safeRelativePath(row.archive, `${label}.archive`);
-  const digest = sha256(row.sha256, `${label}.sha256`);
-  const size = positiveSize(row.size, `${label}.size`);
-  if (expectedSqlName !== undefined && sqlName !== expectedSqlName) {
-    throw error(`${label}.sqlName`, `must be ${expectedSqlName}`);
-  }
-  if (archive !== `extensions/${sqlName}.tar.zst`) {
-    throw error(`${label}.archive`, `must be extensions/${sqlName}.tar.zst`);
-  }
-  if (expectedArchive !== undefined && archive !== expectedArchive) {
-    throw error(`${label}.archive`, `must be ${expectedArchive}`);
-  }
-  if (expectedSha256 !== undefined && digest !== expectedSha256) {
-    throw error(`${label}.sha256`, "does not match the frozen archive digest");
-  }
-  if (expectedSize !== undefined && size !== expectedSize) {
-    throw error(`${label}.size`, "does not match the frozen archive size");
-  }
-  return deepFreeze({
-    schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA,
-    sqlName,
-    archive,
-    sha256: digest,
-    size,
-    install: checkedInstall(row.install, `${label}.install`, { expectedSqlName: sqlName }),
-  });
-}
-
-function assertStaticModelMatchesBuilt(model, built, label) {
-  const modelSqlName = nonEmptyString(model["sql-name"], `${label} model.sql-name`);
-  const builtSqlName = nonEmptyString(built["sql-name"], `${label} manifest.sql-name`);
-  if (modelSqlName !== builtSqlName) throw error(label, "static and built SQL names differ");
-  for (const [modelField, builtField] of [
-    ["archive", "archive"],
-    ["dependencies", "dependencies"],
-    ["load-order", "load-order"],
-  ]) {
-    if (!sameValue(model[modelField], built[builtField])) {
-      throw error(label, `static ${modelField} differs from the built manifest`);
-    }
-  }
-  const modelNativeModule = model["native-module-file"] ?? null;
-  const builtNativeModule = built["native-module"] ?? null;
-  if (modelNativeModule !== builtNativeModule) {
-    throw error(label, "static native-module-file differs from the built manifest");
-  }
-  if (!sameValue(
-    lifecycleFromManifest(model.lifecycle, `${label} model.lifecycle`),
-    lifecycleFromManifest(built.lifecycle, `${label} manifest.lifecycle`),
-  )) {
-    throw error(label, "static lifecycle differs from the built manifest");
-  }
-
-  const nativeModules = Array.isArray(built["native-modules"])
-    ? built["native-modules"].map((entry, index) => compactNativeModule(
-      entry,
-      `${label} manifest.native-modules[${index}]`,
-    ))
-    : null;
-  if (nativeModules === null) throw error(label, "built native-modules must be an array");
-  if (!Array.isArray(model["native-support-modules"])) {
-    throw error(label, "static native-support-modules must be an array");
-  }
-  const expectedModulePaths = [
-    ...model["native-support-modules"].map((entry, index) =>
-      safeRelativePath(entry?.["runtime-path"], `${label} model.native-support-modules[${index}]`)),
-    ...(modelNativeModule === null ? [] : [`lib/postgresql/${modelNativeModule}`]),
-  ];
-  const actualModulePaths = nativeModules.map((entry) => entry.path);
-  if (
-    expectedModulePaths.length !== actualModulePaths.length
-    || expectedModulePaths.some((modulePath) => !actualModulePaths.includes(modulePath))
-  ) {
-    throw error(label, "static native module inventory differs from the built manifest");
-  }
-}
-
-export function projectWasixExtensionInstallSidecar({ modelRow, manifestRow }, {
-  archiveBytes,
-  label = "WASIX extension",
-} = {}) {
-  const model = object(modelRow, `${label} static model row`);
-  const built = object(manifestRow, `${label} built manifest row`);
-  assertStaticModelMatchesBuilt(model, built, label);
-  const sidecar = assertWasixExtensionInstallSidecar({
-    schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA,
-    sqlName: built["sql-name"],
-    archive: built.archive,
-    sha256: built.sha256,
-    size: built.size,
-    install: {
-      schema: WASIX_EXTENSION_INSTALL_SCHEMA,
-      name: built.name,
-      nativeModule: built["native-module"] ?? null,
-      nativeModules: built["native-modules"].map((entry, index) => compactNativeModule(
-        entry,
-        `${label} manifest.native-modules[${index}]`,
-      )),
-      coreExportsRequired: built["core-exports-required"],
-      dependencies: built.dependencies,
-      loadOrder: built["load-order"],
-      lifecycle: lifecycleFromManifest(built.lifecycle, `${label} manifest.lifecycle`),
-      installedFiles: built["installed-files"],
-      unresolvedImports: built["unresolved-imports"],
-    },
-  }, { label });
-  if (archiveBytes !== undefined) assertWasixExtensionArchiveInstall(archiveBytes, sidecar, { label });
-  return sidecar;
-}
-
-export function assertWasixExtensionArchiveInstall(archiveBytes, sidecarValue, {
-  label = "WASIX extension archive",
-} = {}) {
-  if (!Buffer.isBuffer(archiveBytes) && !(archiveBytes instanceof Uint8Array)) {
-    throw error(label, "bytes must be a Buffer or Uint8Array");
-  }
-  const bytes = Buffer.from(archiveBytes);
-  const sidecar = assertWasixExtensionInstallSidecar(sidecarValue, { label: `${label} sidecar` });
-  if (bytes.length !== sidecar.size) throw error(label, "size differs from its install sidecar");
-  if (createHash("sha256").update(bytes).digest("hex") !== sidecar.sha256) {
-    throw error(label, "digest differs from its install sidecar");
-  }
-  let entries;
-  try {
-    entries = readPortableTarZstdBufferEntries(bytes, { label });
-  } catch (cause) {
-    throw error(label, cause.message);
-  }
-  const files = [...entries]
-    .filter(([, entry]) => entry.isFile)
-    .map(([member]) => member);
-  if (!sameValue(files, sidecar.install.installedFiles)) {
-    throw error(label, "regular file inventory differs from install.installedFiles");
-  }
-  for (const [member, entry] of entries) {
-    if (entry.isSymbolicLink) throw error(label, `must not contain symbolic link ${member}`);
-  }
-  for (const module of sidecar.install.nativeModules) {
-    const entry = entries.get(module.path);
-    if (entry === undefined || !entry.isFile || entry.isSymbolicLink) {
-      throw error(label, `must contain native module ${module.path} as a regular file`);
-    }
-    const moduleBytes = Buffer.from(entry.data());
-    const digest = createHash("sha256").update(moduleBytes).digest("hex");
-    if (
-      moduleBytes.length !== module.size
-      || digest !== module.sha256
-      || digest !== module.moduleSha256
-    ) {
-      throw error(label, `native module ${module.path} differs from its compact identity`);
-    }
-  }
-  return sidecar;
-}
-
-export function deepFreeze(value) {
-  if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
-    for (const child of Object.values(value)) deepFreeze(child);
-    Object.freeze(value);
-  }
-  return value;
-}
diff --git a/src/shared/extension-runtime-contract/wasix-extension-install.test.mjs b/src/shared/extension-runtime-contract/wasix-extension-install.test.mjs
deleted file mode 100644
index c3b90a76d..000000000
--- a/src/shared/extension-runtime-contract/wasix-extension-install.test.mjs
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/usr/bin/env bun
-import { createHash } from "node:crypto";
-import {
-  mkdirSync,
-  mkdtempSync,
-  rmSync,
-  writeFileSync,
-} from "node:fs";
-import os from "node:os";
-import path from "node:path";
-import { zstdCompressSync } from "node:zlib";
-import { afterAll, expect, test } from "bun:test";
-
-import { createDeterministicTar } from "../artifact-packaging/archive-directory.mjs";
-import {
-  assertWasixExtensionInstall,
-  assertWasixExtensionMemberInstall,
-  projectWasixExtensionInstallSidecar,
-} from "./wasix-extension-install.mjs";
-
-const directories = [];
-
-afterAll(() => {
-  for (const directory of directories) rmSync(directory, { recursive: true, force: true });
-});
-
-function sha256(bytes) {
-  return createHash("sha256").update(bytes).digest("hex");
-}
-
-async function fixture() {
-  const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-wasix-install-contract-"));
-  directories.push(root);
-  const moduleBytes = Buffer.from("wasix-side-module");
-  const modulePath = "lib/postgresql/example.so";
-  const controlPath = "share/postgresql/extension/example.control";
-  for (const [member, bytes] of [
-    [modulePath, moduleBytes],
-    [controlPath, Buffer.from("default_version = '1.0'\n")],
-  ]) {
-    const output = path.join(root, ...member.split("/"));
-    mkdirSync(path.dirname(output), { recursive: true });
-    writeFileSync(output, bytes);
-  }
-  const archiveBytes = zstdCompressSync(await createDeterministicTar(root));
-  const lifecycle = {
-    "create-extension": true,
-    "create-schema": "pg_catalog",
-    "load-sql": [],
-    "post-create-sql": [],
-    "startup-config": [],
-    "preload-required": false,
-    "restart-required": false,
-    "shared-memory-required": false,
-  };
-  const modelRow = {
-    id: "example",
-    "sql-name": "example",
-    archive: "extensions/example.tar.zst",
-    dependencies: ["plpgsql"],
-    "load-order": [modulePath],
-    lifecycle,
-    "native-module-file": "example.so",
-    "native-support-modules": [],
-  };
-  const manifestRow = {
-    name: "Example",
-    "sql-name": "example",
-    archive: "extensions/example.tar.zst",
-    sha256: sha256(archiveBytes),
-    size: archiveBytes.length,
-    "native-module": "example.so",
-    "native-modules": [{
-      name: "example",
-      path: modulePath,
-      sha256: sha256(moduleBytes),
-      "module-sha256": sha256(moduleBytes),
-      size: moduleBytes.length,
-      link: { deliberately: "not public" },
-    }],
-    "core-exports-required": ["palloc"],
-    dependencies: ["plpgsql"],
-    "load-order": [modulePath],
-    lifecycle,
-    "installed-files": [modulePath, controlPath],
-    "unresolved-imports": [],
-  };
-  return { archiveBytes, manifestRow, modelRow };
-}
-
-test("projects and deeply freezes only the compact extension-owned install authority", async () => {
-  const value = await fixture();
-  const sidecar = projectWasixExtensionInstallSidecar(value, {
-    archiveBytes: value.archiveBytes,
-    label: "example fixture",
-  });
-  expect(sidecar).toMatchObject({
-    schema: "oliphaunt-wasix-extension-install-sidecar-v1",
-    sqlName: "example",
-    archive: "extensions/example.tar.zst",
-    install: {
-      schema: "oliphaunt-wasix-extension-install-v1",
-      dependencies: ["plpgsql"],
-      coreExportsRequired: ["palloc"],
-    },
-  });
-  expect(sidecar.install.nativeModules[0]).toEqual({
-    name: "example",
-    path: "lib/postgresql/example.so",
-    sha256: value.manifestRow["native-modules"][0].sha256,
-    moduleSha256: value.manifestRow["native-modules"][0]["module-sha256"],
-    size: value.manifestRow["native-modules"][0].size,
-  });
-  expect(Object.isFrozen(sidecar.install.nativeModules[0])).toBe(true);
-  expect(Object.isFrozen(sidecar.install.lifecycle.loadSql)).toBe(true);
-});
-
-test("rejects installed-file and compact module hash drift against the archive", async () => {
-  const missingFile = await fixture();
-  missingFile.manifestRow["installed-files"] = ["lib/postgresql/example.so"];
-  expect(() => projectWasixExtensionInstallSidecar(missingFile, {
-    archiveBytes: missingFile.archiveBytes,
-    label: "missing file fixture",
-  })).toThrow(/regular file inventory differs from install[.]installedFiles/u);
-
-  const badModule = await fixture();
-  badModule.manifestRow["native-modules"][0]["module-sha256"] = "a".repeat(64);
-  expect(() => projectWasixExtensionInstallSidecar(badModule, {
-    archiveBytes: badModule.archiveBytes,
-    label: "bad module fixture",
-  })).toThrow(/differs from its compact identity/u);
-});
-
-test("rejects install contracts that the consumer descriptor cannot accept", async () => {
-  const value = await fixture();
-  const install = structuredClone(projectWasixExtensionInstallSidecar(value, {
-    archiveBytes: value.archiveBytes,
-    label: "consumer parity fixture",
-  }).install);
-
-  const duplicateModule = structuredClone(install);
-  duplicateModule.nativeModules.push({ ...duplicateModule.nativeModules[0] });
-  expect(() => assertWasixExtensionInstall(duplicateModule, {
-    expectedSqlName: "example",
-  })).toThrow(/nativeModules names must not contain duplicates/u);
-
-  const missingModuleIdentity = structuredClone(install);
-  missingModuleIdentity.nativeModule = null;
-  expect(() => assertWasixExtensionInstall(missingModuleIdentity, {
-    expectedSqlName: "example",
-  })).toThrow(/must be null exactly when nativeModules is empty/u);
-
-  const selfDependency = structuredClone(install);
-  selfDependency.dependencies = ["example"];
-  expect(() => assertWasixExtensionInstall(selfDependency, {
-    expectedSqlName: "example",
-  })).toThrow(/must not include its own SQL name example/u);
-
-  const missingInstalledModule = structuredClone(install);
-  missingInstalledModule.installedFiles = missingInstalledModule.installedFiles.filter(
-    (file) => file !== missingInstalledModule.nativeModules[0].path,
-  );
-  expect(() => assertWasixExtensionInstall(missingInstalledModule, {
-    expectedSqlName: "example",
-  })).toThrow(/must appear in installedFiles/u);
-});
-
-test("binds one install contract to exactly one portable member asset", async () => {
-  const value = await fixture();
-  const install = projectWasixExtensionInstallSidecar(value, {
-    archiveBytes: value.archiveBytes,
-    label: "member fixture",
-  }).install;
-  const portableAsset = {
-    family: "wasix",
-    kind: "wasix-runtime",
-    target: "wasix-portable",
-  };
-  expect(assertWasixExtensionMemberInstall({
-    sqlName: "example",
-    assets: [portableAsset],
-    wasixInstall: install,
-  })).toEqual(install);
-  expect(assertWasixExtensionMemberInstall({
-    sqlName: "example",
-    assets: [{ family: "native", kind: "runtime", target: "linux-x64-gnu" }],
-    wasixInstall: null,
-  })).toBeNull();
-  expect(() => assertWasixExtensionMemberInstall({
-    sqlName: "example",
-    assets: [],
-    wasixInstall: install,
-  })).toThrow(/must be null without a portable WASIX asset/u);
-  expect(() => assertWasixExtensionMemberInstall({
-    sqlName: "example",
-    assets: [portableAsset, portableAsset],
-    wasixInstall: install,
-  })).toThrow(/must declare exactly one portable WASIX asset/u);
-});
diff --git a/src/shared/fixtures/extensions/file_fdw.sql b/src/shared/fixtures/extensions/file_fdw.sql
deleted file mode 100644
index 288c56b4e..000000000
--- a/src/shared/fixtures/extensions/file_fdw.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-DROP SERVER IF EXISTS oliphaunt_file_server;
--- oliphaunt-statement
-CREATE SERVER oliphaunt_file_server FOREIGN DATA WRAPPER file_fdw;
--- oliphaunt-statement
-DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_foreign_data_wrapper WHERE fdwname = 'file_fdw') THEN RAISE EXCEPTION 'file_fdw wrapper missing'; END IF; END $$;
diff --git a/src/shared/fixtures/extensions/pg_ivm.sql b/src/shared/fixtures/extensions/pg_ivm.sql
deleted file mode 100644
index 02e3b3af4..000000000
--- a/src/shared/fixtures/extensions/pg_ivm.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-DROP TABLE IF EXISTS oliphaunt_ivm_summary;
--- oliphaunt-statement
-DROP TABLE IF EXISTS oliphaunt_ivm_orders;
--- oliphaunt-statement
-CREATE TABLE oliphaunt_ivm_orders (id int, amount int);
--- oliphaunt-statement
-INSERT INTO oliphaunt_ivm_orders VALUES (1, 10), (2, 20);
--- oliphaunt-statement
-SELECT pgivm.create_immv('oliphaunt_ivm_summary', $$ SELECT id, amount FROM oliphaunt_ivm_orders $$);
--- oliphaunt-statement
-DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_ivm_summary; IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm initial count failed: %', n; END IF; END $$;
diff --git a/src/shared/fixtures/extensions/vector.sql b/src/shared/fixtures/extensions/vector.sql
deleted file mode 100644
index a0211e73c..000000000
--- a/src/shared/fixtures/extensions/vector.sql
+++ /dev/null
@@ -1,7 +0,0 @@
-DROP TABLE IF EXISTS oliphaunt_vector;
--- oliphaunt-statement
-CREATE TABLE oliphaunt_vector (id int PRIMARY KEY, embedding vector(3));
--- oliphaunt-statement
-INSERT INTO oliphaunt_vector VALUES (1, '[1,2,3]');
--- oliphaunt-statement
-DO $$ DECLARE d float8; BEGIN SELECT embedding <-> '[1,2,4]'::vector INTO d FROM oliphaunt_vector WHERE id = 1; IF d <> 1 THEN RAISE EXCEPTION 'vector distance failed: %', d; END IF; END $$;
diff --git a/src/shared/fixtures/manifest.toml b/src/shared/fixtures/manifest.toml
deleted file mode 100644
index 27693a75f..000000000
--- a/src/shared/fixtures/manifest.toml
+++ /dev/null
@@ -1,51 +0,0 @@
-schema_version = 1
-
-[[fixtures]]
-id = "postgres-18-core-behavior"
-path = "postgres/behavior-contract.json"
-owner = "postgres-engine-runners"
-
-[[fixtures]]
-id = "postgres-logical-tools-v1"
-path = "postgres/logical-tools.json"
-owner = "native-and-wasix-tools"
-
-[[fixtures]]
-id = "postgres-logical-tools-seed-v1"
-path = "postgres/logical-tools-seed.sql"
-owner = "native-and-wasix-tools"
-
-[[fixtures]]
-id = "postgres-logical-tools-verify-v1"
-path = "postgres/logical-tools-verify.sql"
-owner = "native-and-wasix-tools"
-
-[[fixtures]]
-id = "postgres-server-listen-v1"
-path = "postgres/server-listen.json"
-owner = "desktop-native-and-wasix-servers"
-
-[[fixtures]]
-id = "database-root-v1"
-path = "storage/database-root.json"
-owner = "native-and-wasix-storage"
-
-[[fixtures]]
-id = "physical-archive-native-v1"
-path = "storage/physical-archive-native-v1.properties"
-owner = "liboliphaunt-native"
-
-[[fixtures]]
-id = "physical-archive-wasix-v1"
-path = "storage/physical-archive-wasix-v1.properties"
-owner = "liboliphaunt-wasix"
-
-[[fixtures]]
-id = "physical-backup-wal-range-v1"
-path = "storage/physical-backup-wal-range-v1.properties"
-owner = "native-and-wasix-physical-backup"
-
-[[fixtures]]
-id = "postgres-query-response-cases"
-path = "protocol/query-response-cases.json"
-owner = "sdk-query-parsers"
diff --git a/src/shared/js-core/README.md b/src/shared/js-core/README.md
deleted file mode 100644
index db076a3fc..000000000
--- a/src/shared/js-core/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Shared JavaScript Core
-
-Canonical TypeScript helpers shared by the JavaScript, React Native, and WASIX
-TypeScript SDKs through the private `@oliphaunt/js-core` workspace package.
-
-Moon builds its ESM and CommonJS exports once. Published SDKs bundle that
-minimal private package so registry consumers do not need another dependency.
diff --git a/src/shared/js-core/moon.yml b/src/shared/js-core/moon.yml
deleted file mode 100644
index 8ba6948ea..000000000
--- a/src/shared/js-core/moon.yml
+++ /dev/null
@@ -1,81 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "shared-js-core"
-language: "typescript"
-layer: "library"
-stack: "frontend"
-tags: ["shared", "typescript", "sdk"]
-dependsOn:
-  - id: "shared-test-fixtures"
-    scope: "development"
-
-project:
-  title: "Shared JavaScript Core"
-  description: "Private workspace package for canonical TypeScript query and protocol helpers."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/sdk-js"
-  paths:
-    "**/*.ts": ["@oliphaunt/sdk-js", "@oliphaunt/sdk-react-native"]
-    "tools/**": ["@oliphaunt/sdk-js", "@oliphaunt/sdk-react-native"]
-
-fileGroups:
-  sources:
-    - "module.package.json"
-    - "package.json"
-    - "src/**/*.ts"
-    - "tsconfig*.json"
-
-tasks:
-  build-module:
-    tags: ["build", "static", "typescript"]
-    script: |
-      set -e
-      pnpm --dir src/shared/js-core exec tsc -p tsconfig.build.module.json
-      cp src/shared/js-core/module.package.json src/shared/js-core/dist/module/package.json
-    inputs:
-      - "/src/shared/js-core/package.json"
-      - "/src/shared/js-core/module.package.json"
-      - "/src/shared/js-core/src/**/*.ts"
-      - "/src/shared/js-core/tsconfig*.json"
-      - "/pnpm-lock.yaml"
-    outputs:
-      - "/src/shared/js-core/dist/module/*.d.ts"
-      - "/src/shared/js-core/dist/module/*.js"
-      - "/src/shared/js-core/dist/module/package.json"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  build-commonjs:
-    tags: ["build", "static", "typescript"]
-    command: "pnpm --dir src/shared/js-core exec tsc -p tsconfig.build.commonjs.json"
-    inputs:
-      - "/src/shared/js-core/package.json"
-      - "/src/shared/js-core/src/**/*.ts"
-      - "/src/shared/js-core/tsconfig*.json"
-      - "/pnpm-lock.yaml"
-    outputs:
-      - "/src/shared/js-core/dist/commonjs/*.d.ts"
-      - "/src/shared/js-core/dist/commonjs/*.js"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  build:
-    tags: ["build", "typescript", "aggregate"]
-    command: "true"
-    deps:
-      - "shared-js-core:build-module"
-      - "shared-js-core:build-commonjs"
-    inputs: []
-  test:
-    tags: ["quality", "unit"]
-    command: "tools/dev/bun.sh test src/shared/js-core/test/query.test.ts"
-    inputs:
-      - "/src/shared/js-core/src/**/*.ts"
-      - "test/**/*"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
diff --git a/src/shared/js-core/package.json b/src/shared/js-core/package.json
deleted file mode 100644
index b9d051afe..000000000
--- a/src/shared/js-core/package.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "name": "@oliphaunt/js-core",
-  "version": "0.0.0",
-  "private": true,
-  "exports": {
-    "./protocol": {
-      "import": { "types": "./dist/module/protocol.d.ts", "default": "./dist/module/protocol.js" },
-      "require": { "types": "./dist/commonjs/protocol.d.ts", "default": "./dist/commonjs/protocol.js" }
-    },
-    "./query": {
-      "import": { "types": "./dist/module/query.d.ts", "default": "./dist/module/query.js" },
-      "require": { "types": "./dist/commonjs/query.d.ts", "default": "./dist/commonjs/query.js" }
-    }
-  },
-  "files": ["dist/module", "dist/commonjs"],
-  "scripts": { "typecheck": "tsc --noEmit" },
-  "devDependencies": {
-    "@types/node": "^24.10.1",
-    "typescript": "catalog:"
-  }
-}
diff --git a/src/shared/js-core/src/query.ts b/src/shared/js-core/src/query.ts
deleted file mode 100644
index e2db8b4a9..000000000
--- a/src/shared/js-core/src/query.ts
+++ /dev/null
@@ -1,2456 +0,0 @@
-import { simpleQuery } from './protocol.js';
-
-const utf8Encoder = new TextEncoder();
-const utf8Decoder = new TextDecoder('utf-8', { fatal: true });
-
-export type QueryBinaryInput = ArrayBuffer | ArrayBufferView | Uint8Array;
-export type ByteInput = QueryBinaryInput | ReadonlyArray;
-
-/** Stable PostgreSQL OIDs used by the built-in JavaScript codecs. */
-export const postgresOids = Object.freeze({
-  bool: 16,
-  bytea: 17,
-  char: 18,
-  name: 19,
-  int8: 20,
-  int2: 21,
-  int4: 23,
-  text: 25,
-  oid: 26,
-  json: 114,
-  xml: 142,
-  float4: 700,
-  float8: 701,
-  unknown: 705,
-  bpchar: 1042,
-  varchar: 1043,
-  date: 1082,
-  time: 1083,
-  timestamp: 1114,
-  timestamptz: 1184,
-  interval: 1186,
-  timetz: 1266,
-  numeric: 1700,
-  uuid: 2950,
-  jsonb: 3802,
-  boolArray: 1000,
-  byteaArray: 1001,
-  charArray: 1002,
-  nameArray: 1003,
-  int2Array: 1005,
-  int4Array: 1007,
-  textArray: 1009,
-  bpcharArray: 1014,
-  varcharArray: 1015,
-  int8Array: 1016,
-  float4Array: 1021,
-  float8Array: 1022,
-  oidArray: 1028,
-  dateArray: 1182,
-  timeArray: 1183,
-  timestampArray: 1115,
-  timestamptzArray: 1185,
-  intervalArray: 1187,
-  numericArray: 1231,
-  timetzArray: 1270,
-  jsonArray: 199,
-  xmlArray: 143,
-  uuidArray: 2951,
-  jsonbArray: 3807,
-} as const);
-
-declare const encodedQueryParameterBrand: unique symbol;
-
-type EncodedQueryParameterBrand = {
-  readonly [encodedQueryParameterBrand]: true;
-};
-
-export type TextQueryParameter = Readonly<
-  EncodedQueryParameterBrand & {
-    format: 'text';
-    value: string;
-    typeOid?: number;
-  }
->;
-
-export type BinaryQueryParameter = Readonly<
-  EncodedQueryParameterBrand & {
-    format: 'binary';
-    value: QueryBinaryInput;
-    typeOid?: number;
-  }
->;
-
-export type NullQueryParameter = Readonly<
-  EncodedQueryParameterBrand & {
-    format: 'null';
-    typeOid: number;
-  }
->;
-
-export type EncodedQueryParameter = TextQueryParameter | BinaryQueryParameter | NullQueryParameter;
-
-export type QueryParam =
-  | null
-  | string
-  | number
-  | bigint
-  | boolean
-  | Date
-  | QueryBinaryInput
-  | Readonly>
-  | ReadonlyArray
-  | EncodedQueryParameter;
-
-export type QueryParameterEncoder = (value: QueryParam, typeOid: number) => EncodedQueryParameter;
-
-export type QueryFormat = 'text' | 'binary' | { code: number; kind: 'other' };
-
-export type QueryField = {
-  name: string;
-  tableOid: number;
-  tableAttribute: number;
-  typeOid: number;
-  typeSize: number;
-  typeModifier: number;
-  format: QueryFormat;
-};
-
-export type RawQueryRow = {
-  values: Array;
-  text(column: number): string | null;
-};
-
-class ParsedRawQueryRow implements RawQueryRow {
-  constructor(readonly values: Array) {}
-
-  text(column: number): string | null {
-    if (column < 0 || column >= this.values.length) {
-      throw new Error(`query row has no column at index ${column}`);
-    }
-    const value = this.values[column]!;
-    return value === null ? null : decodeUtf8Strict(value, 'query value');
-  }
-}
-
-export type PostgresNotice = {
-  severity?: string;
-  localizedSeverity?: string;
-  nonlocalizedSeverity?: string;
-  sqlstate?: string;
-  message: string;
-  detail?: string;
-  hint?: string;
-  position?: string;
-  internalPosition?: string;
-  internalQuery?: string;
-  whereText?: string;
-  schemaName?: string;
-  tableName?: string;
-  columnName?: string;
-  dataTypeName?: string;
-  constraintName?: string;
-  file?: string;
-  line?: string;
-  routine?: string;
-  fields: PostgresErrorField[];
-};
-
-export type RawQueryResult = {
-  kind: 'command' | 'rows';
-  fields: QueryField[];
-  rows: RawQueryRow[];
-  commandTag?: string;
-  rowCount: number | null;
-  notices: PostgresNotice[];
-  getText(row: number, column: string): string | null;
-};
-
-export type QueryValue =
-  | null
-  | string
-  | number
-  | boolean
-  | Uint8Array
-  | QueryValue[]
-  | { [key: string]: unknown };
-
-export type QueryObjectRow = Record;
-export type QueryArrayRow = Value[];
-
-export type QueryResult = {
-  kind: 'command' | 'rows';
-  fields: QueryField[];
-  rows: Row[];
-  commandTag?: string;
-  rowCount: number | null;
-  notices: PostgresNotice[];
-};
-
-export type QueryValueDecoder = (value: string, field: QueryField) => Value;
-export type QueryDecoderMap = Readonly>;
-export type QueryRowMode = 'object' | 'array';
-
-export type QueryOptions<
-  RowMode extends QueryRowMode = QueryRowMode,
-  Decoders extends QueryDecoderMap | undefined = QueryDecoderMap | undefined,
-> = Readonly<{
-  rowMode?: RowMode;
-  valueMode?: 'decoded' | 'text';
-  decoders?: Decoders;
-  encoders?: Readonly>;
-}>;
-
-type QueryModeFromOptions = Options extends { readonly rowMode?: infer Mode }
-  ? Extract extends never
-    ? 'object'
-    : Extract
-  : 'object';
-
-type QueryDecoderOutput = Options extends { readonly decoders?: infer Decoders }
-  ? Decoders extends QueryDecoderMap
-    ? Decoders[keyof Decoders] extends QueryValueDecoder
-      ? Value
-      : never
-    : never
-  : never;
-
-type QueryRowForMode = Mode extends 'array'
-  ? QueryArrayRow
-  : QueryObjectRow;
-
-/** Infer the runtime row shape from `rowMode` and custom decoder return types. */
-export type InferQueryRow = [ExplicitRow] extends [never]
-  ? QueryRowForMode, QueryValue | QueryDecoderOutput>
-  : ExplicitRow;
-
-export type ParameterOptions = Readonly<{
-  encoders?: Readonly>;
-}>;
-
-export type CommandResult = {
-  commandTag?: string;
-  rowCount: number | null;
-  notices: PostgresNotice[];
-};
-
-export type ExecResult = {
-  statements: QueryResult[];
-  notices: PostgresNotice[];
-};
-
-export type DescribeResult = {
-  parameterTypeOids: number[];
-  fields?: QueryField[];
-  notices: PostgresNotice[];
-};
-
-export type TransactionStatus = 'idle' | 'transaction' | 'failed';
-
-export { simpleQuery };
-
-export type PostgresErrorField = {
-  code: number;
-  value: string;
-};
-
-export class PostgresError extends Error {
-  readonly severity?: string;
-  readonly localizedSeverity?: string;
-  readonly nonlocalizedSeverity?: string;
-  readonly sqlstate?: string;
-  readonly detail?: string;
-  readonly hint?: string;
-  readonly position?: string;
-  readonly internalPosition?: string;
-  readonly internalQuery?: string;
-  readonly whereText?: string;
-  readonly schemaName?: string;
-  readonly tableName?: string;
-  readonly columnName?: string;
-  readonly dataTypeName?: string;
-  readonly constraintName?: string;
-  readonly file?: string;
-  readonly line?: string;
-  readonly routine?: string;
-  readonly fields: PostgresErrorField[];
-  readonly notices: PostgresNotice[];
-
-  constructor(fields: PostgresErrorField[], notices: PostgresNotice[] = []) {
-    const severity = fieldValue(fields, 0x53) ?? fieldValue(fields, 0x56);
-    const sqlstate = fieldValue(fields, 0x43);
-    super(fieldValue(fields, 0x4d) ?? 'PostgreSQL ErrorResponse');
-    this.name = 'PostgresError';
-    this.severity = severity;
-    this.localizedSeverity = fieldValue(fields, 0x53);
-    this.nonlocalizedSeverity = fieldValue(fields, 0x56);
-    this.sqlstate = sqlstate;
-    this.detail = fieldValue(fields, 0x44);
-    this.hint = fieldValue(fields, 0x48);
-    this.position = fieldValue(fields, 0x50);
-    this.internalPosition = fieldValue(fields, 0x70);
-    this.internalQuery = fieldValue(fields, 0x71);
-    this.whereText = fieldValue(fields, 0x57);
-    this.schemaName = fieldValue(fields, 0x73);
-    this.tableName = fieldValue(fields, 0x74);
-    this.columnName = fieldValue(fields, 0x63);
-    this.dataTypeName = fieldValue(fields, 0x64);
-    this.constraintName = fieldValue(fields, 0x6e);
-    this.file = fieldValue(fields, 0x46);
-    this.line = fieldValue(fields, 0x4c);
-    this.routine = fieldValue(fields, 0x52);
-    this.fields = fields;
-    this.notices = notices;
-  }
-}
-
-/** @internal Preserve query-scoped notices on caller codec failures. */
-export function errorWithNotices(error: unknown, notices: ReadonlyArray): unknown {
-  if (notices.length === 0 && isObjectLike(error)) return error;
-  if (isObjectLike(error) && tryAttachNotices(error, notices)) return error;
-
-  const wrapped = withCause(new Error(codecFailureMessage(error)), error);
-  if (notices.length > 0) {
-    Object.defineProperty(wrapped, 'notices', {
-      value: [...notices],
-      configurable: true,
-      enumerable: true,
-    });
-  }
-  return wrapped;
-}
-
-function tryAttachNotices(error: object, notices: ReadonlyArray): boolean {
-  try {
-    const existing = (error as { notices?: unknown }).notices;
-    if (Array.isArray(existing)) {
-      try {
-        existing.unshift(...notices);
-        return true;
-      } catch {
-        // Fall through to replacing a configurable property.
-      }
-    }
-    if (!Object.isExtensible(error)) return false;
-    Object.defineProperty(error, 'notices', {
-      value: [...notices],
-      configurable: true,
-      enumerable: true,
-    });
-    return true;
-  } catch {
-    return false;
-  }
-}
-
-function codecFailureMessage(error: unknown): string {
-  if (error instanceof Error && error.message.length > 0) return error.message;
-  if (typeof error === 'string' && error.length > 0) return error;
-  if (isObjectLike(error)) {
-    try {
-      const message = (error as { message?: unknown }).message;
-      if (typeof message === 'string' && message.length > 0) return message;
-    } catch {
-      // Use the stable fallback for hostile thrown objects.
-    }
-  }
-  return 'query codec failed';
-}
-
-function isObjectLike(value: unknown): value is object {
-  return (typeof value === 'object' && value !== null) || typeof value === 'function';
-}
-
-type ParameterMetadata =
-  | { format: 'text'; value: string; typeOid?: number }
-  | { format: 'binary'; value: QueryBinaryInput; typeOid?: number }
-  | { format: 'null'; typeOid: number };
-
-const parameterMetadata = new WeakMap();
-
-export function text(
-  value: string | number | bigint | boolean | Date,
-  typeOid?: number,
-): TextQueryParameter {
-  const encoded = scalarText(value);
-  return parameterWrapper({
-    format: 'text',
-    value: encoded,
-    typeOid,
-  }) as TextQueryParameter;
-}
-
-export function binary(value: QueryBinaryInput, typeOid?: number): BinaryQueryParameter {
-  if (!isQueryBinaryInput(value)) {
-    throw new TypeError('binary() requires an ArrayBuffer or ArrayBuffer view');
-  }
-  return parameterWrapper({
-    format: 'binary',
-    value,
-    typeOid,
-  }) as BinaryQueryParameter;
-}
-
-export function typedNull(typeOid: number): NullQueryParameter {
-  validateTypeOid(typeOid, false);
-  return parameterWrapper({ format: 'null', typeOid }) as NullQueryParameter;
-}
-
-export function json(value: unknown, typeOid: number = postgresOids.jsonb): TextQueryParameter {
-  validateTypeOid(typeOid, false);
-  let encoded: string | undefined;
-  try {
-    encoded = JSON.stringify(value);
-  } catch (error) {
-    throw withCause(new TypeError('json() value must be acyclic and JSON-serializable'), error);
-  }
-  if (encoded === undefined) {
-    throw new TypeError('json() value must be JSON-serializable');
-  }
-  return parameterWrapper({
-    format: 'text',
-    value: encoded,
-    typeOid,
-  }) as TextQueryParameter;
-}
-
-export function array(values: ReadonlyArray, typeOid?: number): TextQueryParameter {
-  if (!Array.isArray(values)) {
-    throw new TypeError('array() requires a JavaScript array');
-  }
-  const elementTypeOid = typeOid === undefined ? undefined : arrayElementTypeOid(typeOid);
-  if (typeOid !== undefined && elementTypeOid === undefined) {
-    throw new TypeError('array() type OID ' + typeOid + ' is not a supported PostgreSQL array OID');
-  }
-  return parameterWrapper({
-    format: 'text',
-    value: encodeArrayLiteral(values, elementTypeOid),
-    typeOid,
-  }) as TextQueryParameter;
-}
-
-export type QueryPlan =
-  | Readonly<{ kind: 'complete'; input: Uint8Array }>
-  | Readonly<{
-      kind: 'describe';
-      input: Uint8Array;
-      bind(parameterTypeOids: ReadonlyArray): Uint8Array;
-    }>;
-
-export function planQuery(
-  sql: string,
-  parameters: ReadonlyArray = [],
-  options: ParameterOptions = {},
-): QueryPlan {
-  validateStatementInput(sql, parameters);
-  assertNoTopLevelCopy(sql);
-  const snapshot = Array.from(parameters, snapshotQueryParam);
-  const encoders =
-    options.encoders === undefined ? undefined : Object.freeze({ ...options.encoders });
-  const declaredTypeOids = snapshot.map(parameterDeclaredTypeOid);
-  if (declaredTypeOids.every((typeOid) => typeOid !== 0)) {
-    const normalized = snapshot.map((parameter, index) =>
-      normalizeQueryParam(parameter, declaredTypeOids[index]!, encoders),
-    );
-    return {
-      kind: 'complete',
-      input: encodeParseBindExecute(sql, declaredTypeOids, normalized),
-    };
-  }
-  return {
-    kind: 'describe',
-    input: describeQuery(sql, declaredTypeOids),
-    bind(parameterTypeOids: ReadonlyArray): Uint8Array {
-      if (parameterTypeOids.length !== snapshot.length) {
-        throw new Error(
-          'PostgreSQL described ' +
-            parameterTypeOids.length +
-            ' parameters, expected ' +
-            snapshot.length,
-        );
-      }
-      const normalized = snapshot.map((parameter, index) =>
-        normalizeQueryParam(parameter, parameterTypeOids[index]!, encoders),
-      );
-      return encodeParseBindExecute(sql, parameterTypeOids, normalized);
-    },
-  };
-}
-
-/** Encode a one-exchange query. Untyped values require planQuery() instead. */
-export function extendedQuery(
-  sql: string,
-  parameters: ReadonlyArray,
-  options: ParameterOptions = {},
-): Uint8Array {
-  const plan = planQuery(sql, parameters, options);
-  if (plan.kind === 'describe') {
-    throw new Error('extended query parameters require PostgreSQL type inference; use planQuery()');
-  }
-  return plan.input;
-}
-
-export function describeQuery(
-  sql: string,
-  parameterTypeOids: ReadonlyArray = [],
-): Uint8Array {
-  validateStatementInput(sql, parameterTypeOids);
-  for (const typeOid of parameterTypeOids) validateTypeOid(typeOid, true);
-  const sqlBytes = utf8Encoder.encode(sql);
-  const parseBodyLength = sqlBytes.length + 4 + parameterTypeOids.length * 4;
-  const packet = new ByteWriter(parseBodyLength + 17);
-  writeParse(packet, sqlBytes, parameterTypeOids);
-  packet.message(0x44, 2);
-  packet.u8(0x53);
-  packet.u8(0);
-  packet.message(0x53, 0);
-  return packet.finish();
-}
-
-function encodeParseBindExecute(
-  sql: string,
-  parameterTypeOids: ReadonlyArray,
-  parameters: ReadonlyArray,
-): Uint8Array {
-  const sqlBytes = utf8Encoder.encode(sql);
-  const parseBodyLength = sqlBytes.length + 4 + parameterTypeOids.length * 4;
-  const bindBodyLength = bindLength(parameters);
-  const packet = new ByteWriter(parseBodyLength + bindBodyLength + 32);
-  writeParse(packet, sqlBytes, parameterTypeOids);
-  writeBindExecute(packet, parameters);
-  return packet.finish();
-}
-
-function writeParse(
-  packet: ByteWriter,
-  sqlBytes: Uint8Array,
-  parameterTypeOids: ReadonlyArray,
-): void {
-  const parseBodyLength = sqlBytes.length + 4 + parameterTypeOids.length * 4;
-  packet.message(0x50, parseBodyLength);
-  packet.u8(0);
-  packet.bytes(sqlBytes);
-  packet.u8(0);
-  packet.i16(parameterTypeOids.length);
-  for (const typeOid of parameterTypeOids) packet.i32(typeOid);
-}
-
-function writeBindExecute(packet: ByteWriter, parameters: ReadonlyArray): void {
-  packet.message(0x42, bindLength(parameters));
-  packet.u8(0);
-  packet.u8(0);
-  packet.i16(parameters.length);
-  for (const parameter of parameters) packet.i16(parameter.kind === 'binary' ? 1 : 0);
-  packet.i16(parameters.length);
-  for (const parameter of parameters) {
-    if (parameter.kind === 'null') {
-      packet.i32(-1);
-    } else {
-      packet.i32(parameter.value.length);
-      packet.bytes(parameter.value);
-    }
-  }
-  packet.i16(1);
-  packet.i16(0);
-  packet.message(0x44, 2);
-  packet.u8(0x50);
-  packet.u8(0);
-  packet.message(0x45, 5);
-  packet.u8(0);
-  packet.i32(0);
-  packet.message(0x53, 0);
-}
-
-function bindLength(parameters: ReadonlyArray): number {
-  let length = 10 + parameters.length * 2;
-  for (const parameter of parameters) {
-    length += 4 + (parameter.kind === 'null' ? 0 : parameter.value.length);
-  }
-  return length;
-}
-
-const transactionStatuses = new WeakMap();
-
-type ParsedOperation = {
-  statements: Statement[];
-  notices: PostgresNotice[];
-  transactionStatus: TransactionStatus;
-};
-
-type RawOperation = ParsedOperation;
-type PendingExecResult = QueryResult;
-
-type OperationStatementFactory = (
-  kind: 'command' | 'rows',
-  fields: QueryField[],
-  rows: RawQueryRow[],
-  commandTag: string | undefined,
-  notices: PostgresNotice[],
-) => Statement;
-
-export function responseTransactionStatus(value: object): TransactionStatus | undefined {
-  return transactionStatuses.get(value);
-}
-
-/**
- * Validate the complete backend framing and return the one terminal
- * ReadyForQuery status without interpreting result values.
- *
- * Structured clients call this immediately after transport completion so a
- * custom decoder or higher-level result assertion cannot obscure whether the
- * physical PostgreSQL session reached a reusable boundary.
- */
-export function inspectReadyForQuery(bytes: Uint8Array): TransactionStatus {
-  return inspectResponseBoundary(bytes, false).status;
-}
-
-/**
- * Validate a structured callback-transaction response before high-level
- * parsing can discard earlier command tags after a later ErrorResponse.
- */
-export function inspectManagedTransactionResponse(bytes: Uint8Array): TransactionStatus {
-  const boundary = inspectResponseBoundary(bytes, true);
-  if (boundary.status === 'idle') {
-    throw new Error(
-      'structured callback transaction operation ended PostgreSQL transaction ownership; close the database',
-    );
-  }
-  for (const rawTag of boundary.commandTags) {
-    const tag = rawTag;
-    if (
-      tag === 'BEGIN' ||
-      tag === 'START TRANSACTION' ||
-      tag === 'COMMIT' ||
-      tag === 'PREPARE TRANSACTION' ||
-      tag === 'COMMIT PREPARED' ||
-      tag === 'ROLLBACK PREPARED'
-    ) {
-      throw new Error(
-        `PostgreSQL command tag ${tag} violated callback transaction ownership; close the database`,
-      );
-    }
-  }
-  return boundary.status;
-}
-
-function inspectResponseBoundary(
-  bytes: Uint8Array,
-  collectCommandTags: boolean,
-): Readonly<{ status: TransactionStatus; commandTags: string[] }> {
-  const cursor = new ByteCursor(bytes);
-  let status: TransactionStatus | undefined;
-  const commandTags: string[] = [];
-  while (!cursor.isAtEnd()) {
-    if (status !== undefined) {
-      throw new Error('backend returned bytes after ReadyForQuery');
-    }
-    const tag = cursor.readU8('backend message tag');
-    const length = cursor.readI32('backend message length');
-    if (length < 4) throw new Error('invalid backend message length ' + length);
-    const bodyBytes = cursor.readBytes(length - 4, 'backend message body');
-    if (tag === 0x43 && !collectCommandTags) {
-      validateCStringBody(bodyBytes, 'CommandComplete tag', 'CommandComplete');
-      continue;
-    }
-    const body = new ByteCursor(bodyBytes);
-    if (tag === 0x43) {
-      commandTags.push(body.readCString('CommandComplete tag'));
-      body.requireEnd('CommandComplete');
-    } else if (tag === 0x5a) {
-      status = parseReadyForQuery(body);
-    }
-  }
-  if (status === undefined) {
-    throw new Error('backend response ended before ReadyForQuery');
-  }
-  return { status, commandTags };
-}
-
-export function parseQueryRawResponse(bytes: Uint8Array): RawQueryResult {
-  return singleRawResult(parseRawOperation(bytes, 'extended-single'));
-}
-
-export function parseSimpleQueryRawResponse(bytes: Uint8Array): RawQueryResult {
-  return singleRawResult(parseRawOperation(bytes, 'simple-single'));
-}
-
-function singleRawResult(operation: RawOperation): RawQueryResult {
-  const result =
-    operation.statements[0] ?? rawResult('command', [], [], undefined, operation.notices);
-  if (operation.statements.length === 1) result.notices = operation.notices;
-  transactionStatuses.set(result, operation.transactionStatus);
-  return result;
-}
-
-export function decodeQueryResult(
-  raw: RawQueryResult,
-  options: Options & QueryOptions = {} as Options & QueryOptions,
-): QueryResult> {
-  let stableOptions: QueryOptions;
-  let rows: InferQueryRow[];
-  try {
-    stableOptions = stabilizeQueryOptions(options);
-    rows = decodeRows(raw.rows, raw.fields, stableOptions, false);
-  } catch (error) {
-    const failure = errorWithNotices(error, raw.notices);
-    const status = responseTransactionStatus(raw);
-    if (status !== undefined && isObjectLike(failure)) {
-      transactionStatuses.set(failure, status);
-    }
-    throw failure;
-  }
-  const result: QueryResult> = {
-    kind: raw.kind,
-    fields: raw.fields,
-    rows,
-    commandTag: raw.commandTag,
-    rowCount: raw.rowCount,
-    notices: raw.notices,
-  };
-  const status = responseTransactionStatus(raw);
-  if (status !== undefined) transactionStatuses.set(result, status);
-  return result;
-}
-
-export function parseExecResponse<
-  Row = never,
-  const Options extends Omit = {},
->(
-  bytes: Uint8Array,
-  options: Options & Omit = {} as Options &
-    Omit,
-): ExecResult> {
-  const operation = parseOperation(bytes, 'simple-exec', pendingExecResult);
-  let result: ExecResult>;
-  try {
-    if (operation.statements.length > 0) {
-      const stableOptions = stabilizeQueryOptions(options);
-      for (const statement of operation.statements) {
-        materializePendingExecResult(statement, stableOptions);
-      }
-    }
-    result = {
-      statements: operation.statements as unknown as QueryResult>[],
-      notices: operation.notices,
-    };
-  } catch (error) {
-    const failure = errorWithNotices(error, operation.notices);
-    if (isObjectLike(failure)) {
-      transactionStatuses.set(failure, operation.transactionStatus);
-    }
-    throw failure;
-  }
-  transactionStatuses.set(result, operation.transactionStatus);
-  return result;
-}
-
-export function parseCommandResponse(bytes: Uint8Array): CommandResult {
-  const raw = parseQueryRawResponse(bytes);
-  const status = responseTransactionStatus(raw);
-  if (raw.kind === 'rows') {
-    throwWithStatus(new Error('execute() received rows; use query() for row results'), status);
-  }
-  const result: CommandResult = {
-    commandTag: raw.commandTag,
-    rowCount: raw.rowCount,
-    notices: raw.notices,
-  };
-  if (status !== undefined) transactionStatuses.set(result, status);
-  return result;
-}
-
-export function parseDescribeResponse(bytes: Uint8Array): DescribeResult {
-  const cursor = new ByteCursor(bytes);
-  const notices: PostgresNotice[] = [];
-  let parameterTypeOids: number[] | undefined;
-  let fields: QueryField[] | undefined;
-  let sawParseComplete = false;
-  let sawNoData = false;
-  let failure: Error | undefined;
-  let recoveryFailure: Error | undefined;
-  let sawErrorResponse = false;
-  let status: TransactionStatus | undefined;
-  while (!cursor.isAtEnd()) {
-    const tag = cursor.readU8('backend message tag');
-    const length = cursor.readI32('backend message length');
-    if (length < 4) throw new Error('invalid backend message length ' + length);
-    const body = new ByteCursor(cursor.readBytes(length - 4, 'backend message body'));
-    if (sawErrorResponse && tag !== 0x4e && tag !== 0x53 && tag !== 0x41 && tag !== 0x5a) {
-      recoveryFailure ??= withCause(
-        new Error('describe response contained ' + hexBackendTag(tag) + ' after ErrorResponse'),
-        failure,
-      );
-      continue;
-    }
-    try {
-      switch (tag) {
-        case 0x31:
-          if (sawParseComplete) throw new Error('duplicate ParseComplete');
-          body.requireEnd('ParseComplete');
-          sawParseComplete = true;
-          break;
-        case 0x74:
-          if (!sawParseComplete)
-            throw new Error('ParameterDescription arrived before ParseComplete');
-          if (parameterTypeOids !== undefined) throw new Error('duplicate ParameterDescription');
-          parameterTypeOids = parseParameterDescription(body);
-          body.requireEnd('ParameterDescription');
-          break;
-        case 0x54:
-          if (parameterTypeOids === undefined)
-            throw new Error('RowDescription arrived before ParameterDescription');
-          if (fields !== undefined || sawNoData) throw new Error('duplicate result description');
-          fields = parseRowDescription(body);
-          body.requireEnd('RowDescription');
-          break;
-        case 0x6e:
-          if (parameterTypeOids === undefined)
-            throw new Error('NoData arrived before ParameterDescription');
-          if (fields !== undefined || sawNoData) throw new Error('duplicate result description');
-          sawNoData = true;
-          body.requireEnd('NoData');
-          break;
-        case 0x45: {
-          const postgresFailure = parseErrorResponse(body, notices);
-          if (
-            sawParseComplete &&
-            parameterTypeOids !== undefined &&
-            (fields !== undefined || sawNoData)
-          ) {
-            failure ??= withCause(
-              new Error('ErrorResponse arrived after describe completion'),
-              postgresFailure,
-            );
-          } else {
-            failure ??= postgresFailure;
-          }
-          sawErrorResponse = true;
-          break;
-        }
-        case 0x4e:
-          notices.push(parseNoticeResponse(body));
-          break;
-        case 0x53:
-          validateParameterStatus(body);
-          break;
-        case 0x41:
-          validateNotificationResponse(body);
-          break;
-        case 0x5a:
-          status = parseReadyForQuery(body);
-          if (!cursor.isAtEnd()) {
-            failure ??= new Error('backend returned bytes after ReadyForQuery');
-            cursor.discardRemaining();
-          }
-          break;
-        default:
-          failure ??= new Error(
-            'describe() received unexpected backend message tag ' + hexBackendTag(tag),
-          );
-      }
-    } catch (error) {
-      failure ??= asError(error);
-    }
-  }
-  if (status === undefined) {
-    if (failure !== undefined) throw failure;
-    throw new Error('describe response ended before ReadyForQuery');
-  }
-  if (recoveryFailure !== undefined) throwWithStatus(recoveryFailure, status);
-  if (failure !== undefined) throwWithStatus(failure, status);
-  if (!sawParseComplete) {
-    throwWithStatus(new Error('describe response omitted ParseComplete'), status);
-  }
-  if (parameterTypeOids === undefined) {
-    throwWithStatus(new Error('describe response omitted ParameterDescription'), status);
-  }
-  if (fields === undefined && !sawNoData) {
-    throwWithStatus(new Error('describe response omitted RowDescription or NoData'), status);
-  }
-  const result: DescribeResult = {
-    parameterTypeOids,
-    ...(fields === undefined ? {} : { fields }),
-    notices,
-  };
-  transactionStatuses.set(result, status);
-  return result;
-}
-
-export function assertSuccessfulQueryResponse(bytes: Uint8Array): void {
-  const raw = singleRawResult(parseRawOperation(bytes, 'simple-single'));
-  if (raw.kind === 'rows') {
-    throwWithStatus(
-      new Error('command response unexpectedly contained rows'),
-      responseTransactionStatus(raw),
-    );
-  }
-}
-
-type RawOperationMode = 'extended-single' | 'simple-single' | 'simple-exec';
-
-function parseRawOperation(bytes: Uint8Array, mode: RawOperationMode): RawOperation {
-  return parseOperation(bytes, mode, rawResult);
-}
-
-function parseOperation(
-  bytes: Uint8Array,
-  mode: RawOperationMode,
-  statementFactory: OperationStatementFactory,
-): ParsedOperation {
-  const cursor = new ByteCursor(bytes);
-  const statements: Statement[] = [];
-  const notices: PostgresNotice[] = [];
-  let statementNotices: PostgresNotice[] = [];
-  let fields: QueryField[] | undefined;
-  let rows: RawQueryRow[] = [];
-  let failure: Error | undefined;
-  let recoveryFailure: Error | undefined;
-  let sawErrorResponse = false;
-  let completionCount = 0;
-  let extendedStage: 'start' | 'parsed' | 'bound' | 'described' | 'completed' = 'start';
-  let status: TransactionStatus | undefined;
-  while (!cursor.isAtEnd()) {
-    const tag = cursor.readU8('backend message tag');
-    const length = cursor.readI32('backend message length');
-    if (length < 4) throw new Error('invalid backend message length ' + length);
-    const body = new ByteCursor(cursor.readBytes(length - 4, 'backend message body'));
-    if (sawErrorResponse && tag !== 0x4e && tag !== 0x53 && tag !== 0x41 && tag !== 0x5a) {
-      recoveryFailure ??= withCause(
-        new Error('query response contained ' + hexBackendTag(tag) + ' after ErrorResponse'),
-        failure,
-      );
-      continue;
-    }
-    try {
-      switch (tag) {
-        case 0x54:
-          if (mode !== 'simple-exec' && completionCount > 0)
-            throw new Error('RowDescription arrived after statement completion');
-          if (mode === 'extended-single') {
-            if (extendedStage !== 'bound') {
-              throw new Error('RowDescription arrived before ParseComplete and BindComplete');
-            }
-            extendedStage = 'described';
-          }
-          if (fields !== undefined) failure ??= new Error('result received two RowDescriptions');
-          fields = parseRowDescription(body);
-          body.requireEnd('RowDescription');
-          break;
-        case 0x44:
-          if (completionCount > 0 && fields === undefined)
-            throw new Error('DataRow arrived after statement completion');
-          if (fields === undefined) throw new Error('DataRow arrived before RowDescription');
-          if (mode === 'extended-single' && extendedStage !== 'described') {
-            throw new Error('DataRow arrived before the result description');
-          }
-          rows.push(parseDataRow(body, fields.length));
-          body.requireEnd('DataRow');
-          break;
-        case 0x43: {
-          if (mode !== 'simple-exec' && completionCount > 0) {
-            throw new Error(
-              'queryRaw() received multiple result completions; use exec() for multi-statement SQL',
-            );
-          }
-          if (mode === 'extended-single' && extendedStage !== 'described') {
-            throw new Error('CommandComplete arrived before the extended-query result description');
-          }
-          const commandTag = body.readCString('CommandComplete tag');
-          body.requireEnd('CommandComplete');
-          statements.push(
-            statementFactory(
-              fields === undefined ? 'command' : 'rows',
-              fields ?? [],
-              rows,
-              commandTag,
-              statementNotices,
-            ),
-          );
-          fields = undefined;
-          rows = [];
-          statementNotices = [];
-          completionCount += 1;
-          if (mode === 'extended-single') {
-            extendedStage = 'completed';
-          }
-          break;
-        }
-        case 0x45: {
-          const postgresFailure = parseErrorResponse(body, notices);
-          if (mode !== 'simple-exec' && completionCount > 0) {
-            failure ??= withCause(
-              new Error('ErrorResponse arrived after statement completion'),
-              postgresFailure,
-            );
-          } else {
-            failure ??= postgresFailure;
-          }
-          sawErrorResponse = true;
-          break;
-        }
-        case 0x47:
-        case 0x48:
-        case 0x57:
-        case 0x64:
-        case 0x63:
-          failure ??= new Error(
-            'query() does not support COPY protocol responses; use a raw protocol API for COPY traffic',
-          );
-          break;
-        case 0x5a:
-          status = parseReadyForQuery(body);
-          if (!cursor.isAtEnd()) {
-            failure ??= new Error('backend returned bytes after ReadyForQuery');
-            cursor.discardRemaining();
-          }
-          break;
-        case 0x31:
-          if (mode !== 'extended-single') {
-            throw new Error('simple-query response contained ParseComplete');
-          }
-          if (extendedStage !== 'start') {
-            throw new Error('ParseComplete arrived out of order');
-          }
-          body.requireEnd('ParseComplete');
-          extendedStage = 'parsed';
-          break;
-        case 0x32:
-          if (mode !== 'extended-single') {
-            throw new Error('simple-query response contained BindComplete');
-          }
-          if (extendedStage !== 'parsed') {
-            throw new Error('BindComplete arrived before ParseComplete or out of order');
-          }
-          body.requireEnd('BindComplete');
-          extendedStage = 'bound';
-          break;
-        case 0x33:
-          throw new Error('unsolicited CloseComplete in query response');
-        case 0x49:
-          if (fields !== undefined || rows.length !== 0)
-            throw new Error('EmptyQueryResponse arrived during a row result');
-          if (mode !== 'simple-exec' && completionCount > 0) {
-            throw new Error(
-              'queryRaw() received multiple result completions; use exec() for multi-statement SQL',
-            );
-          }
-          if (mode === 'extended-single' && extendedStage !== 'described') {
-            throw new Error(
-              'EmptyQueryResponse arrived before the extended-query result description',
-            );
-          }
-          body.requireEnd('EmptyQueryResponse');
-          statementNotices = [];
-          completionCount += 1;
-          if (mode === 'extended-single') {
-            extendedStage = 'completed';
-          }
-          break;
-        case 0x6e:
-          if (mode !== 'extended-single') {
-            throw new Error('simple-query response contained NoData');
-          }
-          if (extendedStage !== 'bound') {
-            throw new Error('NoData arrived before ParseComplete and BindComplete');
-          }
-          body.requireEnd('NoData');
-          extendedStage = 'described';
-          break;
-        case 0x53:
-          validateParameterStatus(body);
-          break;
-        case 0x4e: {
-          const notice = parseNoticeResponse(body);
-          notices.push(notice);
-          statementNotices.push(notice);
-          break;
-        }
-        case 0x41:
-          validateNotificationResponse(body);
-          break;
-        default:
-          failure ??= new Error('unexpected backend message tag ' + hexBackendTag(tag));
-      }
-    } catch (error) {
-      failure ??= asError(error);
-    }
-  }
-  if (status === undefined) {
-    if (failure !== undefined) throw failure;
-    throw new Error('query response ended before ReadyForQuery');
-  }
-  if (recoveryFailure !== undefined) throwWithStatus(recoveryFailure, status);
-  if (fields !== undefined || rows.length !== 0) {
-    failure ??= new Error('query response ended before CommandComplete');
-  }
-  if (!sawErrorResponse && completionCount === 0) {
-    failure ??= new Error('query response omitted CommandComplete or EmptyQueryResponse');
-  }
-  if (!sawErrorResponse && mode === 'extended-single' && extendedStage !== 'completed') {
-    failure ??= new Error(
-      'extended-query response omitted ParseComplete, BindComplete, result description, or completion',
-    );
-  }
-  if (failure !== undefined) throwWithStatus(failure, status);
-  return { statements, notices, transactionStatus: status };
-}
-
-function pendingExecResult(
-  kind: 'command' | 'rows',
-  fields: QueryField[],
-  rows: RawQueryRow[],
-  commandTag: string | undefined,
-  notices: PostgresNotice[],
-): PendingExecResult {
-  return {
-    kind,
-    fields,
-    rows,
-    commandTag,
-    rowCount: commandTagRowCount(commandTag),
-    notices,
-  };
-}
-
-function rawResult(
-  kind: 'command' | 'rows',
-  fields: QueryField[],
-  rows: RawQueryRow[],
-  commandTag: string | undefined,
-  notices: PostgresNotice[],
-): RawQueryResult {
-  return {
-    kind,
-    fields,
-    rows,
-    commandTag,
-    rowCount: commandTagRowCount(commandTag),
-    notices,
-    getText(row: number, column: string): string | null {
-      const columnIndex = resolveFieldIndex(fields, column);
-      const queryRow = rows[row];
-      if (queryRow === undefined) throw new Error('query result has no row at index ' + row);
-      return queryRow.text(columnIndex);
-    },
-  };
-}
-
-function resolveFieldIndex(fields: QueryField[], name: string): number {
-  let match: number | undefined;
-  for (let index = 0; index < fields.length; index += 1) {
-    if (fields[index]!.name !== name) continue;
-    if (match !== undefined) {
-      throw new Error(
-        'query result has more than one column named ' +
-          JSON.stringify(name) +
-          '; use array row mode or a positional raw-row index',
-      );
-    }
-    match = index;
-  }
-  if (match === undefined) {
-    throw new Error('query result has no column named ' + JSON.stringify(name));
-  }
-  return match;
-}
-
-function stabilizeQueryOptions(options: QueryOptions): QueryOptions {
-  const rowMode = options.rowMode;
-  const valueMode = options.valueMode;
-  const decoders = options.decoders;
-  return {
-    rowMode,
-    valueMode,
-    decoders: decoders === undefined ? undefined : Object.freeze({ ...decoders }),
-  };
-}
-
-function decodeRows(
-  rawRows: RawQueryRow[],
-  fields: QueryField[],
-  options: QueryOptions,
-  reuseEmpty: boolean,
-): InferQueryRow[] {
-  if (options.rowMode !== 'array' && fields.length > 1) assertUniqueObjectRowFields(fields);
-  if (reuseEmpty && rawRows.length === 0) {
-    return rawRows as unknown as InferQueryRow[];
-  }
-  return rawRows.map((row) => materializeRow(row, fields, options)) as InferQueryRow<
-    Options,
-    Row
-  >[];
-}
-
-function materializePendingExecResult(
-  pending: PendingExecResult,
-  options: QueryOptions,
-): void {
-  const rows = decodeRows(pending.rows, pending.fields, options, true);
-  (pending as unknown as QueryResult>).rows = rows;
-}
-
-function assertUniqueObjectRowFields(fields: ReadonlyArray): void {
-  const names = new Set();
-  for (const field of fields) {
-    if (names.has(field.name)) {
-      throw new Error(
-        'decoded object rows cannot represent more than one column named ' +
-          JSON.stringify(field.name) +
-          "; use { rowMode: 'array' } or queryRaw()",
-      );
-    }
-    names.add(field.name);
-  }
-}
-
-function materializeRow(
-  row: RawQueryRow,
-  fields: QueryField[],
-  options: QueryOptions,
-): QueryObjectRow | QueryArrayRow {
-  const values = row.values.map((value, index) => decodeValue(value, fields[index]!, options));
-  if (options.rowMode === 'array') return values;
-  const object: QueryObjectRow = {};
-  for (let index = 0; index < fields.length; index += 1) {
-    Object.defineProperty(object, fields[index]!.name, {
-      value: values[index]!,
-      enumerable: true,
-      configurable: true,
-      writable: true,
-    });
-  }
-  return object;
-}
-
-function decodeValue(
-  value: Uint8Array | null,
-  field: QueryField,
-  options: QueryOptions,
-): QueryValue {
-  if (value === null) return null;
-  if (field.format !== 'text') return value;
-  const decodedText = decodeUtf8Strict(value, 'query value');
-  const decoder = options.decoders?.[field.typeOid];
-  if (decoder !== undefined) return decoder(decodedText, field) as QueryValue;
-  if (options.valueMode === 'text') return decodedText;
-  return decodeBuiltInText(decodedText, field.typeOid);
-}
-
-function commandTagRowCount(commandTag: string | undefined): number | null {
-  if (commandTag === undefined) {
-    return null;
-  }
-  let start = 0;
-  let end = commandTag.length;
-  while (start < end && isEcmaWhitespace(commandTag.charCodeAt(start))) start += 1;
-  while (end > start && isEcmaWhitespace(commandTag.charCodeAt(end - 1))) end -= 1;
-  if (start === end) return null;
-
-  let commandEnd = start;
-  while (commandEnd < end && !isEcmaWhitespace(commandTag.charCodeAt(commandEnd))) {
-    commandEnd += 1;
-  }
-  if (!hasRowCountCommand(commandTag, start, commandEnd)) return null;
-
-  let countStart = end;
-  while (countStart > start && !isEcmaWhitespace(commandTag.charCodeAt(countStart - 1))) {
-    countStart -= 1;
-  }
-  if (countStart === start) return null;
-
-  let value = 0;
-  for (let index = countStart; index < end; index += 1) {
-    const digit = commandTag.charCodeAt(index) - 0x30;
-    if (digit < 0 || digit > 9) return null;
-    value = value * 10 + digit;
-    if (!Number.isSafeInteger(value)) return null;
-  }
-  return value;
-}
-
-function hasRowCountCommand(value: string, start: number, end: number): boolean {
-  const length = end - start;
-  if (length === 4) {
-    return value.startsWith('MOVE', start) || value.startsWith('COPY', start);
-  }
-  if (length === 5) {
-    return value.startsWith('MERGE', start) || value.startsWith('FETCH', start);
-  }
-  if (length === 6) {
-    return (
-      value.startsWith('SELECT', start) ||
-      value.startsWith('INSERT', start) ||
-      value.startsWith('UPDATE', start) ||
-      value.startsWith('DELETE', start)
-    );
-  }
-  return false;
-}
-
-function isEcmaWhitespace(code: number): boolean {
-  if ((code >= 0x09 && code <= 0x0d) || code === 0x20 || code === 0xa0 || code === 0x1680) {
-    return true;
-  }
-  if (code >= 0x2000 && code <= 0x200a) return true;
-  switch (code) {
-    case 0x2028:
-    case 0x2029:
-    case 0x202f:
-    case 0x205f:
-    case 0x3000:
-    case 0xfeff:
-      return true;
-    default:
-      return false;
-  }
-}
-
-type NormalizedParam =
-  | { kind: 'null' }
-  | { kind: 'text'; value: Uint8Array }
-  | { kind: 'binary'; value: Uint8Array };
-
-function normalizeQueryParam(
-  parameter: QueryParam,
-  typeOid: number,
-  encoders: Readonly> | undefined,
-): NormalizedParam {
-  validateTypeOid(typeOid, false);
-  const wrapper =
-    parameter !== null && typeof parameter === 'object'
-      ? parameterMetadata.get(parameter)
-      : undefined;
-  if (wrapper !== undefined) return normalizeWrapper(wrapper, typeOid);
-
-  const custom = encoders?.[typeOid];
-  if (custom !== undefined) {
-    const encoded = custom(parameter, typeOid);
-    if (encoded === null || typeof encoded !== 'object') {
-      throw new TypeError('query encoder for OID ' + typeOid + ' must return a parameter helper');
-    }
-    const encodedMetadata = parameterMetadata.get(encoded);
-    if (encodedMetadata === undefined) {
-      throw new TypeError(
-        'query encoder for OID ' + typeOid + ' must use text(), binary(), or typedNull()',
-      );
-    }
-    return normalizeWrapper(encodedMetadata, typeOid);
-  }
-
-  if (parameter === null) return { kind: 'null' };
-  if (typeof parameter === 'string') {
-    return { kind: 'text', value: utf8Encoder.encode(parameter) };
-  }
-  if (typeof parameter === 'number') {
-    if (!isNumericOrTextOid(typeOid)) throw unsupportedParameter(parameter, typeOid);
-    return { kind: 'text', value: utf8Encoder.encode(scalarText(parameter)) };
-  }
-  if (typeof parameter === 'bigint') {
-    if (!isNumericOrTextOid(typeOid)) throw unsupportedParameter(parameter, typeOid);
-    return { kind: 'text', value: utf8Encoder.encode(parameter.toString()) };
-  }
-  if (typeof parameter === 'boolean') {
-    if (typeOid !== postgresOids.bool && !isTextOid(typeOid)) {
-      throw unsupportedParameter(parameter, typeOid);
-    }
-    return {
-      kind: 'text',
-      value: utf8Encoder.encode(parameter ? 'true' : 'false'),
-    };
-  }
-  if (parameter instanceof Date) {
-    return {
-      kind: 'text',
-      value: utf8Encoder.encode(dateText(parameter, typeOid)),
-    };
-  }
-  if (isQueryBinaryInput(parameter)) {
-    if (typeOid !== postgresOids.bytea) throw unsupportedParameter(parameter, typeOid);
-    return { kind: 'binary', value: toUint8Array(parameter) };
-  }
-  if (Array.isArray(parameter)) {
-    const elementTypeOid = arrayElementTypeOid(typeOid);
-    if (elementTypeOid === undefined) throw unsupportedParameter(parameter, typeOid);
-    return {
-      kind: 'text',
-      value: utf8Encoder.encode(encodeArrayLiteral(parameter, elementTypeOid)),
-    };
-  }
-  if (isPlainRecord(parameter)) {
-    if (typeOid !== postgresOids.json && typeOid !== postgresOids.jsonb) {
-      throw unsupportedParameter(parameter, typeOid);
-    }
-    return { kind: 'text', value: utf8Encoder.encode(json(parameter).value) };
-  }
-  throw new TypeError('query parameter is unsupported; use an explicit parameter helper');
-}
-
-function normalizeWrapper(wrapper: ParameterMetadata, typeOid: number): NormalizedParam {
-  if (wrapper.typeOid !== undefined && wrapper.typeOid !== typeOid) {
-    throw new Error(
-      'parameter declares PostgreSQL OID ' +
-        wrapper.typeOid +
-        ', but PostgreSQL described OID ' +
-        typeOid,
-    );
-  }
-  if (wrapper.format === 'null') return { kind: 'null' };
-  if (wrapper.format === 'text') {
-    return { kind: 'text', value: utf8Encoder.encode(wrapper.value) };
-  }
-  return { kind: 'binary', value: toUint8Array(wrapper.value) };
-}
-
-function parameterDeclaredTypeOid(parameter: QueryParam): number {
-  if (parameter !== null && typeof parameter === 'object') {
-    const wrapper = parameterMetadata.get(parameter);
-    if (wrapper?.typeOid !== undefined) {
-      validateTypeOid(wrapper.typeOid, false);
-      return wrapper.typeOid;
-    }
-  }
-  return 0;
-}
-
-function snapshotQueryParam(parameter: QueryParam): QueryParam {
-  if (
-    parameter === null ||
-    typeof parameter === 'string' ||
-    typeof parameter === 'number' ||
-    typeof parameter === 'bigint' ||
-    typeof parameter === 'boolean'
-  ) {
-    return parameter;
-  }
-  if (parameter === undefined) throw new TypeError('query parameters must not be undefined');
-  const wrapper = typeof parameter === 'object' ? parameterMetadata.get(parameter) : undefined;
-  if (wrapper !== undefined) {
-    if (wrapper.format === 'null') return typedNull(wrapper.typeOid);
-    if (wrapper.format === 'binary') {
-      return binary(toUint8Array(wrapper.value).slice(), wrapper.typeOid);
-    }
-    return text(wrapper.value, wrapper.typeOid);
-  }
-  if (parameter instanceof Date) return new Date(parameter.getTime());
-  if (isQueryBinaryInput(parameter)) return toUint8Array(parameter).slice();
-  if (Array.isArray(parameter))
-    return Array.from(parameter, (value) => snapshotQueryParam(value as QueryParam));
-  if (isPlainRecord(parameter)) {
-    let encoded: string | undefined;
-    try {
-      encoded = JSON.stringify(parameter);
-    } catch (error) {
-      throw withCause(
-        new TypeError('plain-object query parameters must be JSON-serializable'),
-        error,
-      );
-    }
-    if (encoded === undefined)
-      throw new TypeError('plain-object query parameters must be JSON-serializable');
-    return JSON.parse(encoded) as Readonly>;
-  }
-  throw new TypeError('query parameter is unsupported; use an explicit parameter helper');
-}
-
-function parameterWrapper(metadata: ParameterMetadata): EncodedQueryParameter {
-  if (metadata.typeOid !== undefined) validateTypeOid(metadata.typeOid, false);
-  const visible =
-    metadata.format === 'null'
-      ? { format: 'null' as const, typeOid: metadata.typeOid }
-      : {
-          format: metadata.format,
-          value: metadata.value,
-          ...(metadata.typeOid === undefined ? {} : { typeOid: metadata.typeOid }),
-        };
-  const wrapper = Object.freeze(visible) as EncodedQueryParameter;
-  parameterMetadata.set(wrapper, metadata);
-  return wrapper;
-}
-
-function isQueryBinaryInput(value: unknown): value is QueryBinaryInput {
-  return value instanceof ArrayBuffer || ArrayBuffer.isView(value);
-}
-
-function validateStatementInput(sql: string, parameters: { length: number }): void {
-  if (parameters.length > 0x7fff) {
-    throw new Error('extended query supports at most 32767 parameters, got ' + parameters.length);
-  }
-  if (sql.includes('\0')) throw new Error('extended query SQL must not contain NUL bytes');
-}
-
-function validateTypeOid(typeOid: number, allowZero: boolean): void {
-  if (!Number.isInteger(typeOid) || typeOid < (allowZero ? 0 : 1) || typeOid > 0xffffffff) {
-    throw new TypeError(
-      'PostgreSQL type OID must be ' + (allowZero ? 'zero or ' : '') + 'a positive uint32',
-    );
-  }
-}
-
-function scalarText(value: string | number | bigint | boolean | Date): string {
-  if (typeof value === 'number') {
-    if (!Number.isFinite(value)) throw new TypeError('number query parameters must be finite');
-    if (Number.isInteger(value) && !Number.isSafeInteger(value)) {
-      throw new TypeError('integer query parameters must be safe integers; use bigint instead');
-    }
-  }
-  if (value instanceof Date) {
-    if (Number.isNaN(value.getTime())) throw new TypeError('Date query parameters must be valid');
-    return value.toISOString();
-  }
-  return String(value);
-}
-
-function dateText(value: Date, typeOid: number): string {
-  const iso = scalarText(value);
-  if (typeOid === postgresOids.date) return iso.slice(0, 10);
-  if (typeOid === postgresOids.timestamp) return iso.slice(0, -1).replace('T', ' ');
-  if (typeOid === postgresOids.timestamptz || isTextOid(typeOid)) return iso;
-  throw unsupportedParameter(value, typeOid);
-}
-
-function isNumericOrTextOid(typeOid: number): boolean {
-  return (
-    (
-      [
-        postgresOids.int2,
-        postgresOids.int4,
-        postgresOids.int8,
-        postgresOids.oid,
-        postgresOids.float4,
-        postgresOids.float8,
-        postgresOids.numeric,
-      ] as number[]
-    ).includes(typeOid) || isTextOid(typeOid)
-  );
-}
-
-function isTextOid(typeOid: number): boolean {
-  return typeOid === postgresOids.text || typeOid === postgresOids.varchar;
-}
-
-function unsupportedParameter(value: unknown, typeOid: number): TypeError {
-  const kind = value === null ? 'null' : Array.isArray(value) ? 'array' : typeof value;
-  return new TypeError(
-    'cannot safely encode ' +
-      kind +
-      ' for PostgreSQL OID ' +
-      typeOid +
-      '; use a typed helper or encoder',
-  );
-}
-
-function isPlainRecord(value: unknown): value is Readonly> {
-  if (value === null || typeof value !== 'object') return false;
-  const prototype = Object.getPrototypeOf(value);
-  return prototype === Object.prototype || prototype === null;
-}
-
-function throwWithStatus(error: Error, status: TransactionStatus | undefined): never {
-  if (status !== undefined) transactionStatuses.set(error, status);
-  throw error;
-}
-
-function asError(error: unknown): Error {
-  return error instanceof Error
-    ? error
-    : withCause(new Error('PostgreSQL response parsing failed'), error);
-}
-
-function withCause(error: ErrorType, cause: unknown): ErrorType {
-  Object.defineProperty(error, 'cause', {
-    value: cause,
-    configurable: true,
-    writable: true,
-  });
-  return error;
-}
-
-function decodeBuiltInText(value: string, typeOid: number): QueryValue {
-  switch (typeOid) {
-    case postgresOids.bool:
-      if (value === 't') return true;
-      if (value === 'f') return false;
-      throw new Error('invalid PostgreSQL bool text ' + JSON.stringify(value));
-    case postgresOids.int2:
-    case postgresOids.int4:
-    case postgresOids.oid:
-      return decodeInteger(value, typeOid);
-    case postgresOids.float4:
-    case postgresOids.float8:
-      return decodeFloat(value, typeOid);
-    case postgresOids.json:
-    case postgresOids.jsonb:
-      return JSON.parse(value) as QueryValue;
-    case postgresOids.bytea:
-      return decodeBytea(value);
-    case postgresOids.int8:
-    case postgresOids.numeric:
-    case postgresOids.date:
-    case postgresOids.time:
-    case postgresOids.timestamp:
-    case postgresOids.timestamptz:
-    case postgresOids.interval:
-    case postgresOids.timetz:
-      return value;
-    default: {
-      const elementTypeOid = arrayElementTypeOid(typeOid);
-      if (elementTypeOid === undefined) return value;
-      return decodeArrayLiteral(value, elementTypeOid);
-    }
-  }
-}
-
-function decodeInteger(value: string, typeOid: number): number {
-  if (!/^-?[0-9]+$/.test(value)) {
-    throw new Error(
-      'invalid PostgreSQL integer text for OID ' + typeOid + ': ' + JSON.stringify(value),
-    );
-  }
-  const decoded = Number(value);
-  if (!Number.isSafeInteger(decoded)) {
-    throw new Error('PostgreSQL integer for OID ' + typeOid + ' exceeds JavaScript safe range');
-  }
-  return decoded;
-}
-
-function decodeFloat(value: string, typeOid: number): number {
-  if (value === 'NaN') return Number.NaN;
-  if (value === 'Infinity') return Number.POSITIVE_INFINITY;
-  if (value === '-Infinity') return Number.NEGATIVE_INFINITY;
-  if (!/^[+-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/.test(value)) {
-    throw new Error(
-      'invalid PostgreSQL float text for OID ' + typeOid + ': ' + JSON.stringify(value),
-    );
-  }
-  const decoded = Number(value);
-  if (!Number.isFinite(decoded))
-    throw new Error('PostgreSQL float text is outside JavaScript range');
-  return decoded;
-}
-
-function decodeBytea(value: string): Uint8Array {
-  if (value.startsWith('\\x')) {
-    const hex = value.slice(2);
-    if (hex.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex)) {
-      throw new Error('invalid PostgreSQL hex bytea text');
-    }
-    const bytes = new Uint8Array(hex.length / 2);
-    for (let index = 0; index < bytes.length; index += 1) {
-      bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
-    }
-    return bytes;
-  }
-  const bytes: number[] = [];
-  for (let index = 0; index < value.length; index += 1) {
-    if (value[index] !== '\\') {
-      bytes.push(value.charCodeAt(index));
-      continue;
-    }
-    if (value[index + 1] === '\\') {
-      bytes.push(0x5c);
-      index += 1;
-      continue;
-    }
-    const octal = value.slice(index + 1, index + 4);
-    if (!/^[0-3][0-7]{2}$/.test(octal)) throw new Error('invalid PostgreSQL escape bytea text');
-    bytes.push(Number.parseInt(octal, 8));
-    index += 3;
-  }
-  return Uint8Array.from(bytes);
-}
-
-const arrayElementOids = new Map([
-  [postgresOids.boolArray, postgresOids.bool],
-  [postgresOids.byteaArray, postgresOids.bytea],
-  [postgresOids.charArray, postgresOids.char],
-  [postgresOids.nameArray, postgresOids.name],
-  [postgresOids.int2Array, postgresOids.int2],
-  [postgresOids.int4Array, postgresOids.int4],
-  [postgresOids.textArray, postgresOids.text],
-  [postgresOids.bpcharArray, postgresOids.bpchar],
-  [postgresOids.varcharArray, postgresOids.varchar],
-  [postgresOids.int8Array, postgresOids.int8],
-  [postgresOids.float4Array, postgresOids.float4],
-  [postgresOids.float8Array, postgresOids.float8],
-  [postgresOids.oidArray, postgresOids.oid],
-  [postgresOids.dateArray, postgresOids.date],
-  [postgresOids.timeArray, postgresOids.time],
-  [postgresOids.timestampArray, postgresOids.timestamp],
-  [postgresOids.timestamptzArray, postgresOids.timestamptz],
-  [postgresOids.intervalArray, postgresOids.interval],
-  [postgresOids.numericArray, postgresOids.numeric],
-  [postgresOids.timetzArray, postgresOids.timetz],
-  [postgresOids.jsonArray, postgresOids.json],
-  [postgresOids.xmlArray, postgresOids.xml],
-  [postgresOids.uuidArray, postgresOids.uuid],
-  [postgresOids.jsonbArray, postgresOids.jsonb],
-]);
-
-function arrayElementTypeOid(arrayTypeOid: number): number | undefined {
-  return arrayElementOids.get(arrayTypeOid);
-}
-
-function encodeArrayLiteral(values: ReadonlyArray, elementTypeOid?: number): string {
-  return (
-    '{' + Array.from(values, (value) => encodeArrayElement(value, elementTypeOid)).join(',') + '}'
-  );
-}
-
-function encodeArrayElement(value: unknown, elementTypeOid?: number): string {
-  if (value === null) return 'NULL';
-  if (value === undefined) throw new TypeError('PostgreSQL arrays cannot contain undefined');
-  if (Array.isArray(value)) return encodeArrayLiteral(value, elementTypeOid);
-  const wrapper =
-    typeof value === 'object' && value !== null ? parameterMetadata.get(value) : undefined;
-  if (wrapper !== undefined) {
-    if (
-      elementTypeOid !== undefined &&
-      wrapper.typeOid !== undefined &&
-      wrapper.typeOid !== elementTypeOid
-    ) {
-      throw new TypeError(
-        'array element declares PostgreSQL OID ' +
-          wrapper.typeOid +
-          ', but the array resolves element OID ' +
-          elementTypeOid,
-      );
-    }
-    if (wrapper.format === 'null') return 'NULL';
-    if (wrapper.format === 'binary') {
-      if (elementTypeOid !== undefined && elementTypeOid !== postgresOids.bytea) {
-        throw unsupportedParameter(value, elementTypeOid);
-      }
-      return quoteArrayElement('\\x' + bytesToHex(toUint8Array(wrapper.value)));
-    }
-    return quoteArrayElement(wrapper.value);
-  }
-  if (typeof value === 'string') return quoteArrayElement(value);
-  if (typeof value === 'number' || typeof value === 'bigint' || typeof value === 'boolean') {
-    if (elementTypeOid !== undefined) {
-      normalizeQueryParam(value as QueryParam, elementTypeOid, undefined);
-    }
-    return quoteArrayElement(scalarText(value));
-  }
-  if (value instanceof Date) {
-    return quoteArrayElement(
-      elementTypeOid === undefined ? scalarText(value) : dateText(value, elementTypeOid),
-    );
-  }
-  if (isQueryBinaryInput(value)) {
-    if (elementTypeOid !== undefined && elementTypeOid !== postgresOids.bytea) {
-      throw unsupportedParameter(value, elementTypeOid);
-    }
-    return quoteArrayElement('\\x' + bytesToHex(toUint8Array(value)));
-  }
-  if (
-    isPlainRecord(value) &&
-    (elementTypeOid === postgresOids.json || elementTypeOid === postgresOids.jsonb)
-  ) {
-    return quoteArrayElement(json(value, elementTypeOid).value);
-  }
-  throw new TypeError('PostgreSQL array element is unsupported; use an explicit helper');
-}
-
-function quoteArrayElement(value: string): string {
-  return '"' + value.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"';
-}
-
-function bytesToHex(bytes: Uint8Array): string {
-  let hex = '';
-  for (const byte of bytes) hex += byte.toString(16).padStart(2, '0');
-  return hex;
-}
-
-type ParsedArrayValue = string | null | ParsedArrayValue[];
-
-function decodeArrayLiteral(value: string, elementTypeOid: number): QueryValue[] {
-  const parsed = new ArrayTextParser(value).parse();
-  return decodeArrayValues(parsed, elementTypeOid);
-}
-
-function decodeArrayValues(values: ParsedArrayValue[], elementTypeOid: number): QueryValue[] {
-  return values.map((value) =>
-    Array.isArray(value)
-      ? decodeArrayValues(value, elementTypeOid)
-      : value === null
-        ? null
-        : decodeBuiltInText(value, elementTypeOid),
-  );
-}
-
-class ArrayTextParser {
-  readonly #input: string;
-  #offset = 0;
-
-  constructor(input: string) {
-    this.#input = input;
-  }
-
-  parse(): ParsedArrayValue[] {
-    if (this.#input.startsWith('[')) {
-      const separator = this.#input.indexOf('=');
-      if (separator < 0) throw new Error('invalid PostgreSQL array dimensions');
-      this.#offset = separator + 1;
-    }
-    const result = this.#level();
-    if (this.#offset !== this.#input.length)
-      throw new Error('PostgreSQL array text has trailing data');
-    return result;
-  }
-
-  #level(): ParsedArrayValue[] {
-    if (this.#input[this.#offset] !== '{')
-      throw new Error('PostgreSQL array text must start with {');
-    this.#offset += 1;
-    const result: ParsedArrayValue[] = [];
-    if (this.#input[this.#offset] === '}') {
-      this.#offset += 1;
-      return result;
-    }
-    for (;;) {
-      result.push(this.#input[this.#offset] === '{' ? this.#level() : this.#element());
-      const delimiter = this.#input[this.#offset];
-      if (delimiter === '}') {
-        this.#offset += 1;
-        return result;
-      }
-      if (delimiter !== ',') throw new Error('invalid PostgreSQL array delimiter');
-      this.#offset += 1;
-    }
-  }
-
-  #element(): string | null {
-    if (this.#input[this.#offset] === '"') {
-      this.#offset += 1;
-      let value = '';
-      for (;;) {
-        const character = this.#input[this.#offset];
-        if (character === undefined) throw new Error('unterminated quoted PostgreSQL array value');
-        this.#offset += 1;
-        if (character === '"') return value;
-        if (character === '\\') {
-          const escaped = this.#input[this.#offset];
-          if (escaped === undefined) throw new Error('unterminated PostgreSQL array escape');
-          value += escaped;
-          this.#offset += 1;
-        } else {
-          value += character;
-        }
-      }
-    }
-    let value = '';
-    while (this.#offset < this.#input.length) {
-      const character = this.#input[this.#offset]!;
-      if (character === ',' || character === '}') break;
-      this.#offset += 1;
-      if (character === '\\') {
-        const escaped = this.#input[this.#offset];
-        if (escaped === undefined) throw new Error('unterminated PostgreSQL array escape');
-        value += escaped;
-        this.#offset += 1;
-      } else {
-        value += character;
-      }
-    }
-    return value === 'NULL' ? null : value;
-  }
-}
-
-export function assertNoTopLevelCopy(sql: string): void {
-  if (containsTopLevelCopy(sql)) {
-    throw new Error(
-      'structured SQL does not support COPY; use a raw protocol API for COPY traffic',
-    );
-  }
-}
-
-/**
- * Reject transaction commands whose response boundary cannot prove that the
- * callback still owns the transaction it started. PostgreSQL reports both
- * `ROLLBACK TO SAVEPOINT` and `ROLLBACK AND CHAIN` as command tag `ROLLBACK`
- * with ReadyForQuery status `transaction`, so the latter must be rejected
- * before execution rather than inferred from the backend response.
- */
-export function assertNoTransactionChain(sql: string): void {
-  if (containsTransactionChain(sql)) {
-    throw new Error(
-      'callback transactions do not support ROLLBACK/ABORT ... AND CHAIN; return or throw from the callback instead',
-    );
-  }
-}
-
-export function structuredSimpleQuery(sql: string): Uint8Array {
-  assertNoTopLevelCopy(sql);
-  return simpleQuery(sql);
-}
-
-export function containsTopLevelCopy(sql: string): boolean {
-  return (
-    scanTopLevelTokens(sql, false, (word, first) => first && word === 'copy') ||
-    scanTopLevelTokens(sql, true, (word, first) => first && word === 'copy')
-  );
-}
-
-export function containsTransactionChain(sql: string): boolean {
-  return scanTransactionChain(sql, false) || scanTransactionChain(sql, true);
-}
-
-function scanTransactionChain(sql: string, plainStringsEscapeBackslashes: boolean): boolean {
-  let currentStatement = -1;
-  let state: 'afterControl' | 'afterQualifier' | 'afterAnd' | 'ineligible' = 'ineligible';
-  return scanTopLevelTokens(sql, plainStringsEscapeBackslashes, (word, first, statement) => {
-    if (statement !== currentStatement) {
-      currentStatement = statement;
-      state = first && (word === 'rollback' || word === 'abort') ? 'afterControl' : 'ineligible';
-      return false;
-    }
-    if (word === undefined) {
-      state = 'ineligible';
-      return false;
-    }
-    if (state === 'afterControl' && (word === 'work' || word === 'transaction')) {
-      state = 'afterQualifier';
-    } else if ((state === 'afterControl' || state === 'afterQualifier') && word === 'and') {
-      state = 'afterAnd';
-    } else if (state === 'afterAnd' && word === 'chain') {
-      return true;
-    } else {
-      // This also keeps ROLLBACK TO [SAVEPOINT] inside the managed transaction.
-      state = 'ineligible';
-    }
-    return false;
-  });
-}
-
-function scanTopLevelTokens(
-  sql: string,
-  plainStringsEscapeBackslashes: boolean,
-  visit: (word: string | undefined, first: boolean, statement: number) => boolean,
-): boolean {
-  let offset = 0;
-  let depth = 0;
-  let statementStart = true;
-  let statement = 0;
-  while (offset < sql.length) {
-    const character = sql[offset]!;
-    if (/\s/.test(character)) {
-      offset += 1;
-      continue;
-    }
-    if (character === '-' && sql[offset + 1] === '-') {
-      let end = offset + 2;
-      while (end < sql.length && sql[end] !== '\n' && sql[end] !== '\r') end += 1;
-      offset = end < sql.length ? end + 1 : sql.length;
-      continue;
-    }
-    if (character === '/' && sql[offset + 1] === '*') {
-      offset = skipBlockComment(sql, offset + 2);
-      continue;
-    }
-    if ((character === 'e' || character === 'E') && sql[offset + 1] === "'") {
-      if (depth === 0 && visit(undefined, statementStart, statement)) return true;
-      statementStart = false;
-      offset = skipSingleQuote(sql, offset + 1, true);
-      continue;
-    }
-    if (character === "'") {
-      if (depth === 0 && visit(undefined, statementStart, statement)) return true;
-      statementStart = false;
-      offset = skipSingleQuote(sql, offset, plainStringsEscapeBackslashes);
-      continue;
-    }
-    if (character === '"') {
-      if (depth === 0 && visit(undefined, statementStart, statement)) return true;
-      statementStart = false;
-      offset = skipDoubleQuote(sql, offset);
-      continue;
-    }
-    if (character === '$') {
-      const delimiter = dollarQuoteDelimiter(sql, offset);
-      if (delimiter !== undefined) {
-        if (depth === 0 && visit(undefined, statementStart, statement)) return true;
-        statementStart = false;
-        const end = sql.indexOf(delimiter, offset + delimiter.length);
-        offset = end < 0 ? sql.length : end + delimiter.length;
-        continue;
-      }
-    }
-    if (character === '(') {
-      if (depth === 0 && visit(undefined, statementStart, statement)) return true;
-      depth += 1;
-      statementStart = false;
-      offset += 1;
-      continue;
-    }
-    if (character === ')') {
-      if (depth > 0) depth -= 1;
-      offset += 1;
-      continue;
-    }
-    if (character === ';' && depth === 0) {
-      statementStart = true;
-      statement += 1;
-      offset += 1;
-      continue;
-    }
-    if (isPostgresIdentifierStart(character)) {
-      const start = offset;
-      offset += 1;
-      while (offset < sql.length && isPostgresIdentifierContinuation(sql[offset]!)) offset += 1;
-      if (depth === 0 && visit(sql.slice(start, offset).toLowerCase(), statementStart, statement)) {
-        return true;
-      }
-      statementStart = false;
-      continue;
-    }
-    if (depth === 0 && visit(undefined, statementStart, statement)) return true;
-    statementStart = false;
-    offset += 1;
-  }
-  return false;
-}
-
-function skipBlockComment(sql: string, start: number): number {
-  let depth = 1;
-  let offset = start;
-  while (offset < sql.length && depth > 0) {
-    if (sql[offset] === '/' && sql[offset + 1] === '*') {
-      depth += 1;
-      offset += 2;
-    } else if (sql[offset] === '*' && sql[offset + 1] === '/') {
-      depth -= 1;
-      offset += 2;
-    } else {
-      offset += 1;
-    }
-  }
-  return offset;
-}
-
-function skipSingleQuote(sql: string, quoteOffset: number, escapeBackslash: boolean): number {
-  let offset = quoteOffset + 1;
-  while (offset < sql.length) {
-    if (escapeBackslash && sql[offset] === '\\') {
-      offset += Math.min(2, sql.length - offset);
-    } else if (sql[offset] === "'" && sql[offset + 1] === "'") {
-      offset += 2;
-    } else if (sql[offset] === "'") {
-      return offset + 1;
-    } else {
-      offset += 1;
-    }
-  }
-  return offset;
-}
-
-function skipDoubleQuote(sql: string, quoteOffset: number): number {
-  let offset = quoteOffset + 1;
-  while (offset < sql.length) {
-    if (sql[offset] === '"' && sql[offset + 1] === '"') offset += 2;
-    else if (sql[offset] === '"') return offset + 1;
-    else offset += 1;
-  }
-  return offset;
-}
-
-function dollarQuoteDelimiter(sql: string, offset: number): string | undefined {
-  let end = offset + 1;
-  if (sql[end] === '$') return '$$';
-  if (end >= sql.length || !isPostgresIdentifierStart(sql[end]!)) return undefined;
-  end += 1;
-  while (end < sql.length && sql[end] !== '$' && isPostgresIdentifierContinuation(sql[end]!)) {
-    end += 1;
-  }
-  return sql[end] === '$' ? sql.slice(offset, end + 1) : undefined;
-}
-
-function isPostgresIdentifierStart(character: string): boolean {
-  const code = character.charCodeAt(0);
-  return (
-    character === '_' ||
-    (code >= 0x41 && code <= 0x5a) ||
-    (code >= 0x61 && code <= 0x7a) ||
-    code >= 0x80
-  );
-}
-
-function isPostgresIdentifierContinuation(character: string): boolean {
-  const code = character.charCodeAt(0);
-  return (
-    isPostgresIdentifierStart(character) || character === '$' || (code >= 0x30 && code <= 0x39)
-  );
-}
-
-class ByteWriter {
-  readonly #bytes: Uint8Array;
-  #offset = 0;
-
-  constructor(length: number) {
-    this.#bytes = new Uint8Array(length);
-  }
-
-  message(tag: number, bodyLength: number): void {
-    this.u8(tag);
-    this.i32(bodyLength + 4);
-  }
-
-  u8(value: number): void {
-    this.#bytes[this.#offset] = value;
-    this.#offset += 1;
-  }
-
-  i16(value: number): void {
-    this.#bytes[this.#offset] = (value >>> 8) & 0xff;
-    this.#bytes[this.#offset + 1] = value & 0xff;
-    this.#offset += 2;
-  }
-
-  i32(value: number): void {
-    this.#bytes[this.#offset] = (value >>> 24) & 0xff;
-    this.#bytes[this.#offset + 1] = (value >>> 16) & 0xff;
-    this.#bytes[this.#offset + 2] = (value >>> 8) & 0xff;
-    this.#bytes[this.#offset + 3] = value & 0xff;
-    this.#offset += 4;
-  }
-
-  bytes(value: Uint8Array): void {
-    this.#bytes.set(value, this.#offset);
-    this.#offset += value.length;
-  }
-
-  finish(): Uint8Array {
-    if (this.#offset !== this.#bytes.length) {
-      throw new Error('extended query packet length invariant failed');
-    }
-    return this.#bytes;
-  }
-}
-
-export function toUint8Array(input: ByteInput): Uint8Array {
-  if (input instanceof Uint8Array) {
-    return input;
-  }
-  if (ArrayBuffer.isView(input)) {
-    return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
-  }
-  if (input instanceof ArrayBuffer) {
-    return new Uint8Array(input);
-  }
-  return Uint8Array.from(input);
-}
-
-function parseRowDescription(cursor: ByteCursor): QueryField[] {
-  const count = cursor.readI16('RowDescription field count');
-  if (count < 0) {
-    throw new Error(`invalid RowDescription field count ${count}`);
-  }
-  const fields: QueryField[] = [];
-  for (let index = 0; index < count; index += 1) {
-    fields.push({
-      name: cursor.readCString('field name'),
-      tableOid: cursor.readU32('field table oid'),
-      tableAttribute: cursor.readI16('field table attribute'),
-      typeOid: cursor.readU32('field type oid'),
-      typeSize: cursor.readI16('field type size'),
-      typeModifier: cursor.readI32('field type modifier'),
-      format: queryFormat(cursor.readI16('field format')),
-    });
-  }
-  return fields;
-}
-
-function parseDataRow(cursor: ByteCursor, expectedColumns: number): RawQueryRow {
-  const count = cursor.readI16('DataRow column count');
-  if (count < 0) {
-    throw new Error(`invalid DataRow column count ${count}`);
-  }
-  if (count !== expectedColumns) {
-    throw new Error(
-      `DataRow column count ${count} does not match RowDescription count ${expectedColumns}`,
-    );
-  }
-  const values = new Array(count);
-  for (let index = 0; index < count; index += 1) {
-    const length = cursor.readI32('DataRow value length');
-    if (length === -1) {
-      values[index] = null;
-    } else if (length < 0) {
-      throw new Error(`invalid DataRow value length ${length}`);
-    } else {
-      values[index] = cursor.readBytes(length, 'DataRow value');
-    }
-  }
-  return new ParsedRawQueryRow(values);
-}
-
-function parseErrorResponse(cursor: ByteCursor, notices: PostgresNotice[] = []): PostgresError {
-  return new PostgresError(parseDiagnosticFields(cursor, 'ErrorResponse'), notices);
-}
-
-function fieldValue(fields: ReadonlyArray, code: number): string | undefined {
-  return fields.find((field) => field.code === code)?.value;
-}
-
-function queryFormat(code: number): QueryFormat {
-  if (code === 0) {
-    return 'text';
-  }
-  if (code === 1) {
-    return 'binary';
-  }
-  return { code, kind: 'other' };
-}
-
-function hexBackendTag(tag: number): string {
-  return `0x${tag.toString(16).padStart(2, '0')}`;
-}
-
-function parseReadyForQuery(body: ByteCursor): TransactionStatus {
-  const remaining = body.remainingBytes();
-  if (remaining !== 1) {
-    throw new Error(`ReadyForQuery contained ${remaining} bytes, expected 1`);
-  }
-  const status = body.readU8('ReadyForQuery transaction status');
-  if (status === 0x49) return 'idle';
-  if (status === 0x54) return 'transaction';
-  if (status === 0x45) return 'failed';
-  throw new Error(`ReadyForQuery contained invalid transaction status ${hexBackendTag(status)}`);
-}
-
-function parseParameterDescription(body: ByteCursor): number[] {
-  const count = body.readI16('ParameterDescription parameter count');
-  if (count < 0) throw new Error('invalid ParameterDescription parameter count ' + count);
-  const typeOids: number[] = [];
-  for (let index = 0; index < count; index += 1) {
-    typeOids.push(body.readU32('ParameterDescription type OID'));
-  }
-  return typeOids;
-}
-
-function parseNoticeResponse(body: ByteCursor): PostgresNotice {
-  const fields = parseDiagnosticFields(body, 'NoticeResponse');
-  return {
-    severity: fieldValue(fields, 0x53) ?? fieldValue(fields, 0x56),
-    localizedSeverity: fieldValue(fields, 0x53),
-    nonlocalizedSeverity: fieldValue(fields, 0x56),
-    sqlstate: fieldValue(fields, 0x43),
-    message: fieldValue(fields, 0x4d) ?? 'PostgreSQL notice',
-    detail: fieldValue(fields, 0x44),
-    hint: fieldValue(fields, 0x48),
-    position: fieldValue(fields, 0x50),
-    internalPosition: fieldValue(fields, 0x70),
-    internalQuery: fieldValue(fields, 0x71),
-    whereText: fieldValue(fields, 0x57),
-    schemaName: fieldValue(fields, 0x73),
-    tableName: fieldValue(fields, 0x74),
-    columnName: fieldValue(fields, 0x63),
-    dataTypeName: fieldValue(fields, 0x64),
-    constraintName: fieldValue(fields, 0x6e),
-    file: fieldValue(fields, 0x46),
-    line: fieldValue(fields, 0x4c),
-    routine: fieldValue(fields, 0x52),
-    fields,
-  };
-}
-
-function parseDiagnosticFields(body: ByteCursor, label: string): PostgresErrorField[] {
-  const fields: PostgresErrorField[] = [];
-  for (;;) {
-    if (body.isAtEnd()) throw new Error(label + ' is missing terminator');
-    const code = body.readU8(label + ' field code');
-    if (code === 0) {
-      body.requireEnd(label);
-      return fields;
-    }
-    fields.push({ code, value: body.readCString(label + ' field') });
-  }
-}
-
-function validateParameterStatus(body: ByteCursor): void {
-  body.readCString('ParameterStatus name');
-  body.readCString('ParameterStatus value');
-  body.requireEnd('ParameterStatus');
-}
-
-function validateNotificationResponse(body: ByteCursor): void {
-  body.readI32('NotificationResponse process id');
-  body.readCString('NotificationResponse channel');
-  body.readCString('NotificationResponse payload');
-  body.requireEnd('NotificationResponse');
-}
-
-class ByteCursor {
-  readonly #bytes: Uint8Array;
-  #offset = 0;
-
-  constructor(bytes: Uint8Array) {
-    this.#bytes = bytes;
-  }
-
-  isAtEnd(): boolean {
-    return this.#offset === this.#bytes.length;
-  }
-
-  remainingBytes(): number {
-    return this.#bytes.length - this.#offset;
-  }
-
-  discardRemaining(): void {
-    this.#offset = this.#bytes.length;
-  }
-
-  requireEnd(label: string): void {
-    if (!this.isAtEnd()) {
-      throw new Error(`${label} contained trailing bytes`);
-    }
-  }
-
-  readU8(label: string): number {
-    this.#require(1, label);
-    const value = this.#bytes[this.#offset]!;
-    this.#offset += 1;
-    return value;
-  }
-
-  readU32(label: string): number {
-    this.#require(4, label);
-    const offset = this.#offset;
-    this.#offset += 4;
-    return (
-      (this.#bytes[offset]! * 0x1000000 +
-        (this.#bytes[offset + 1]! << 16) +
-        (this.#bytes[offset + 2]! << 8) +
-        this.#bytes[offset + 3]!) >>>
-      0
-    );
-  }
-
-  readI32(label: string): number {
-    const value = this.readU32(label);
-    return value > 0x7fffffff ? value - 0x100000000 : value;
-  }
-
-  readI16(label: string): number {
-    this.#require(2, label);
-    const value = (this.#bytes[this.#offset]! << 8) | this.#bytes[this.#offset + 1]!;
-    this.#offset += 2;
-    return value > 0x7fff ? value - 0x10000 : value;
-  }
-
-  readCString(label: string): string {
-    const end = this.#bytes.indexOf(0, this.#offset);
-    if (end < 0) {
-      throw new Error(`${label} is missing null terminator`);
-    }
-    const value = decodeUtf8Strict(this.#bytes.subarray(this.#offset, end), label);
-    this.#offset = end + 1;
-    return value;
-  }
-
-  readBytes(count: number, label: string): Uint8Array {
-    this.#require(count, label);
-    const value = this.#bytes.subarray(this.#offset, this.#offset + count);
-    this.#offset += count;
-    return value;
-  }
-
-  #require(count: number, label: string): void {
-    if (count < 0 || count > this.#bytes.length - this.#offset) {
-      throw new Error(`truncated ${label}`);
-    }
-  }
-}
-
-function validateCStringBody(bytes: Uint8Array, valueLabel: string, bodyLabel: string): void {
-  const end = bytes.indexOf(0);
-  if (end < 0) {
-    throw new Error(`${valueLabel} is missing null terminator`);
-  }
-  for (let index = 0; index < end; index += 1) {
-    if (bytes[index]! < 0x80) continue;
-    validateUtf8(bytes.subarray(0, end), valueLabel);
-    break;
-  }
-  if (end !== bytes.length - 1) {
-    throw new Error(`${bodyLabel} contained trailing bytes`);
-  }
-}
-
-function decodeUtf8Strict(bytes: Uint8Array, label: string): string {
-  try {
-    return utf8Decoder.decode(bytes);
-  } catch {
-    // Keep the precise protocol diagnostic off the valid-data hot path. The
-    // platform decoder performs the usual validation in native code; this
-    // scanner only runs after it has already rejected malformed UTF-8.
-    validateUtf8(bytes, label);
-    throw new Error(`${label} is not valid UTF-8`);
-  }
-}
-
-function validateUtf8(bytes: Uint8Array, label: string): void {
-  let index = 0;
-  while (index < bytes.length) {
-    const first = bytes[index]!;
-    if (first <= 0x7f) {
-      index += 1;
-    } else if (first >= 0xc2 && first <= 0xdf) {
-      requireContinuation(bytes, index + 1, label);
-      index += 2;
-    } else if (first === 0xe0) {
-      requireRange(bytes, index + 1, 0xa0, 0xbf, label);
-      requireContinuation(bytes, index + 2, label);
-      index += 3;
-    } else if (first >= 0xe1 && first <= 0xec) {
-      requireContinuation(bytes, index + 1, label);
-      requireContinuation(bytes, index + 2, label);
-      index += 3;
-    } else if (first === 0xed) {
-      requireRange(bytes, index + 1, 0x80, 0x9f, label);
-      requireContinuation(bytes, index + 2, label);
-      index += 3;
-    } else if (first >= 0xee && first <= 0xef) {
-      requireContinuation(bytes, index + 1, label);
-      requireContinuation(bytes, index + 2, label);
-      index += 3;
-    } else if (first === 0xf0) {
-      requireRange(bytes, index + 1, 0x90, 0xbf, label);
-      requireContinuation(bytes, index + 2, label);
-      requireContinuation(bytes, index + 3, label);
-      index += 4;
-    } else if (first >= 0xf1 && first <= 0xf3) {
-      requireContinuation(bytes, index + 1, label);
-      requireContinuation(bytes, index + 2, label);
-      requireContinuation(bytes, index + 3, label);
-      index += 4;
-    } else if (first === 0xf4) {
-      requireRange(bytes, index + 1, 0x80, 0x8f, label);
-      requireContinuation(bytes, index + 2, label);
-      requireContinuation(bytes, index + 3, label);
-      index += 4;
-    } else {
-      throw invalidUtf8(label, index);
-    }
-  }
-}
-
-function requireContinuation(bytes: Uint8Array, index: number, label: string): void {
-  requireRange(bytes, index, 0x80, 0xbf, label);
-}
-
-function requireRange(
-  bytes: Uint8Array,
-  index: number,
-  min: number,
-  max: number,
-  label: string,
-): void {
-  const byte = bytes[index];
-  if (byte === undefined || byte < min || byte > max) {
-    throw invalidUtf8(label, index);
-  }
-}
-
-function invalidUtf8(label: string, index: number): Error {
-  return new Error(`${label} is not valid UTF-8 at byte ${index}`);
-}
diff --git a/src/shared/js-core/test/protocol-fixtures.mjs b/src/shared/js-core/test/protocol-fixtures.mjs
deleted file mode 100644
index 76bdf019f..000000000
--- a/src/shared/js-core/test/protocol-fixtures.mjs
+++ /dev/null
@@ -1,101 +0,0 @@
-import assert from 'node:assert/strict';
-import { readFileSync } from 'node:fs';
-
-export function assertSharedProtocolFixtures(options) {
-  const fixtureUrl = new URL('../../fixtures/protocol/query-response-cases.json', import.meta.url);
-  const corpus = JSON.parse(readFileSync(fixtureUrl, 'utf8'));
-  assert.equal(corpus.schemaVersion, 1);
-  assert.equal(corpus.kind, 'postgres-backend-query-response');
-  assert.ok(corpus.cases.length > 0, 'shared protocol corpus is empty');
-
-  const names = new Set();
-  for (const fixture of corpus.cases) {
-    assert.equal(names.has(fixture.name), false, `duplicate fixture ${fixture.name}`);
-    names.add(fixture.name);
-    const expectation = fixture.queryExpectation;
-    if (expectation === undefined) continue;
-
-    const bytes = hexToBytes(fixture.responseHex);
-    const parseQueryResponse = parserForFixture(fixture, options);
-    if (expectation.ok !== undefined) {
-      assertOk(fixture.name, expectation.ok, parseQueryResponse(bytes));
-    } else if (expectation.postgresError !== undefined) {
-      const thrown = thrownBy(() => parseQueryResponse(bytes));
-      assert.ok(options.isPostgresError(thrown), `${fixture.name} should throw PostgresError`);
-      assert.equal(thrown.severity, expectation.postgresError.severity, `${fixture.name} severity`);
-      assert.equal(thrown.sqlstate, expectation.postgresError.sqlstate, `${fixture.name} SQLSTATE`);
-      assert.equal(
-        thrown.message,
-        expectation.postgresError.message,
-        `${fixture.name} PostgreSQL message`,
-      );
-    } else if (expectation.engineErrorContains !== undefined) {
-      const thrown = thrownBy(() => parseQueryResponse(bytes));
-      assert.ok(thrown instanceof Error, `${fixture.name} should throw Error`);
-      assert.ok(
-        thrown.message.includes(expectation.engineErrorContains),
-        `${fixture.name} error ${JSON.stringify(thrown.message)} did not contain ${JSON.stringify(expectation.engineErrorContains)}`,
-      );
-    } else {
-      assert.fail(`shared protocol fixture ${fixture.name} has no query expectation`);
-    }
-  }
-}
-
-function parserForFixture(fixture, options) {
-  const modes = fixture.protocolModeExpectation;
-  return modes?.extendedQuery?.outcome === 'ok' && modes?.simpleCommand?.outcome !== 'ok'
-    ? options.parseExtendedQueryResponse
-    : options.parseSimpleQueryResponse;
-}
-
-function assertOk(name, expected, actual) {
-  assert.equal(actual.rowCount, expected.rowCount, `${name} row count`);
-  assert.equal(actual.commandTag, expected.commandTag, `${name} command tag`);
-  assert.equal(actual.fields.length, expected.fields.length, `${name} field count`);
-  assert.equal(actual.rows.length, expected.rows.length, `${name} rows size`);
-
-  for (const [index, expectedField] of expected.fields.entries()) {
-    const actualField = actual.fields[index];
-    assert.ok(actualField, `${name} missing field ${index}`);
-    assert.equal(actualField.name, expectedField.name, `${name} field name`);
-    assert.equal(actualField.typeOid, expectedField.typeOid, `${name} type OID`);
-    if (expectedField.format === 'text') {
-      assert.equal(actualField.format, 'text', `${name} field format`);
-    }
-  }
-
-  for (const [rowIndex, expectedRow] of expected.rows.entries()) {
-    assert.equal(expectedRow.length, expected.fields.length, `${name} expected row width`);
-    for (const [columnIndex, expectedValue] of expectedRow.entries()) {
-      const field = expected.fields[columnIndex];
-      assert.ok(field, `${name} missing expected field ${columnIndex}`);
-      assert.equal(
-        actual.getText(rowIndex, field.name),
-        expectedValue,
-        `${name} row ${rowIndex} column ${field.name}`,
-      );
-    }
-  }
-}
-
-function hexToBytes(hex) {
-  const compact = hex.replace(/\s+/g, '');
-  assert.equal(compact.length % 2, 0, 'hex fixture must have an even digit count');
-  const bytes = new Uint8Array(compact.length / 2);
-  for (let index = 0; index < bytes.length; index += 1) {
-    const byte = Number.parseInt(compact.slice(index * 2, index * 2 + 2), 16);
-    assert.ok(Number.isInteger(byte), 'hex fixture contains invalid byte');
-    bytes[index] = byte;
-  }
-  return bytes;
-}
-
-function thrownBy(callback) {
-  try {
-    callback();
-  } catch (error) {
-    return error;
-  }
-  assert.fail('expected callback to throw');
-}
diff --git a/src/shared/js-core/test/query.test.ts b/src/shared/js-core/test/query.test.ts
deleted file mode 100644
index 58c08d7f3..000000000
--- a/src/shared/js-core/test/query.test.ts
+++ /dev/null
@@ -1,1162 +0,0 @@
-import assert from "node:assert/strict";
-import { readFileSync } from "node:fs";
-import { test } from "node:test";
-
-import {
-  PostgresError,
-  array,
-  binary,
-  containsTopLevelCopy,
-  containsTransactionChain,
-  decodeQueryResult,
-  describeQuery,
-  inspectManagedTransactionResponse,
-  inspectReadyForQuery,
-  json,
-  parseDescribeResponse,
-  parseExecResponse,
-  parseQueryRawResponse,
-  parseSimpleQueryRawResponse,
-  planQuery,
-  postgresOids,
-  responseTransactionStatus,
-  text,
-  typedNull,
-} from "../src/query.ts";
-import { assertSharedProtocolFixtures } from "./protocol-fixtures.mjs";
-
-test("protocol fixtures", () => {
-  assertSharedProtocolFixtures({
-    parseSimpleQueryResponse: parseSimpleQueryRawResponse,
-    parseExtendedQueryResponse: parseQueryRawResponse,
-    isPostgresError: (error): error is PostgresError => error instanceof PostgresError,
-  });
-});
-
-test("parameter plans infer OIDs without exposing mutable values across the await", () => {
-  const value = { stable: 1 };
-  const plan = planQuery("SELECT $1::jsonb", [value]);
-  assert.equal(plan.kind, "describe");
-  value.stable = 2;
-  if (plan.kind !== "describe") throw new Error("expected describe plan");
-  const bind = frontendMessages(plan.bind([postgresOids.jsonb]));
-  assert.deepEqual(
-    bind.map((message) => message.tag),
-    ["P", "B", "D", "E", "S"],
-  );
-  assert.match(new TextDecoder().decode(bind[1]!.body), /"stable":1/);
-
-  assert.throws(
-    () => plan.bind([postgresOids.text]),
-    /cannot safely encode object/,
-  );
-  assert.throws(
-    () => planQuery("SELECT $1", [undefined as never]),
-    /must not be undefined/,
-  );
-});
-
-test("typed helpers make a one-exchange OID-aware plan", () => {
-  const plan = planQuery("SELECT $1, $2, $3, $4, $5", [
-    json({ ok: true }),
-    array([1, null, 2], postgresOids.int4Array),
-    text("550e8400-e29b-41d4-a716-446655440000", postgresOids.uuid),
-    binary(Uint8Array.of(0, 255), postgresOids.bytea),
-    typedNull(postgresOids.int8),
-  ]);
-  assert.equal(plan.kind, "complete");
-  if (plan.kind !== "complete") throw new Error("expected complete plan");
-  const messages = frontendMessages(plan.input);
-  assert.deepEqual(
-    messages.map((message) => message.tag),
-    ["P", "B", "D", "E", "S"],
-  );
-  assert.deepEqual(readParseTypeOids(messages[0]!.body), [
-    postgresOids.jsonb,
-    postgresOids.int4Array,
-    postgresOids.uuid,
-    postgresOids.bytea,
-    postgresOids.int8,
-  ]);
-  assert.equal(Object.isFrozen(postgresOids), true);
-});
-
-test("sparse parameter and PostgreSQL arrays reject their undefined holes", () => {
-  assert.throws(
-    () => planQuery("SELECT $1", Array(1)),
-    /query parameters must not be undefined/,
-  );
-  assert.throws(
-    () => array(Array(1), postgresOids.textArray),
-    /PostgreSQL arrays cannot contain undefined/,
-  );
-  assert.throws(
-    () => planQuery("SELECT $1", [Array(1)]),
-    /query parameters must not be undefined/,
-  );
-});
-
-test("array helpers reject explicit element OID mismatches", () => {
-  for (const value of [
-    text("1", postgresOids.int4),
-    typedNull(postgresOids.int4),
-    binary(Uint8Array.of(1), postgresOids.bytea),
-  ]) {
-    assert.throws(
-      () => array([value], postgresOids.textArray),
-      /array element declares PostgreSQL OID .* resolves element OID/,
-    );
-  }
-
-  assert.equal(array([text("raw")], postgresOids.textArray).value, '{"raw"}');
-  assert.equal(
-    array([binary(Uint8Array.of(0xff))], postgresOids.byteaArray).value,
-    '{"\\\\xff"}',
-  );
-});
-
-test("decoded rows reject ambiguous object fields and preserve them in array mode", () => {
-  const response = queryResponse(
-    [
-      field("__proto__", postgresOids.text),
-      field("constructor", postgresOids.int4),
-      field("constructor", postgresOids.int8),
-      field("payload", postgresOids.jsonb),
-      field("bytes", postgresOids.bytea),
-      field("dates", postgresOids.dateArray),
-    ],
-    [
-      [
-        "safe",
-        "7",
-        "9007199254740993",
-        '{"ok":true}',
-        "\\x00ff",
-        "{2026-01-01,NULL}",
-      ],
-    ],
-    "SELECT 1",
-  );
-  const raw = parseQueryRawResponse(response);
-  assert.throws(() => raw.getText(0, "constructor"), /more than one column/);
-  assert.throws(
-    () => decodeQueryResult(raw),
-    /cannot represent more than one column named "constructor"; use \{ rowMode: 'array' \}/,
-  );
-
-  const custom = decodeQueryResult(raw, {
-    rowMode: "array",
-    valueMode: "text",
-    decoders: { [postgresOids.int4]: (value) => "int:" + value },
-  });
-  assert.deepEqual(custom.rows[0], [
-    "safe",
-    "int:7",
-    "9007199254740993",
-    '{"ok":true}',
-    "\\x00ff",
-    "{2026-01-01,NULL}",
-  ]);
-});
-
-test("decoded object rows remain prototype safe when field names are unique", () => {
-  const decoded = decodeQueryResult(
-    parseQueryRawResponse(
-      queryResponse(
-        [field("__proto__", postgresOids.text), field("constructor", postgresOids.int4)],
-        [["safe", "7"]],
-        "SELECT 1",
-      ),
-    ),
-  );
-  const row = decoded.rows[0]!;
-  assert.equal(Object.prototype.hasOwnProperty.call(row, "__proto__"), true);
-  assert.equal(row.__proto__, "safe");
-  assert.equal(row.constructor, 7);
-});
-
-test("decoded floating-point scalars and arrays preserve PostgreSQL non-finite values", () => {
-  const decoded = decodeQueryResult(
-    parseQueryRawResponse(
-      queryResponse(
-        [
-          field("nan", postgresOids.float4),
-          field("positive", postgresOids.float8),
-          field("negative", postgresOids.float8),
-          field("values", postgresOids.float8Array),
-        ],
-        [["NaN", "Infinity", "-Infinity", "{NaN,Infinity,-Infinity,NULL}"]],
-        "SELECT 1",
-      ),
-    ),
-  );
-
-  const row = decoded.rows[0]!;
-  assert.equal(Number.isNaN(row.nan), true);
-  assert.equal(row.positive, Number.POSITIVE_INFINITY);
-  assert.equal(row.negative, Number.NEGATIVE_INFINITY);
-  const values = row.values as unknown[];
-  assert.equal(Number.isNaN(values[0]), true);
-  assert.deepEqual(values.slice(1), [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, null]);
-});
-
-test("built-in ORM OIDs and text-fallback arrays stay portable", () => {
-  assert.deepEqual(
-    {
-      char: postgresOids.char,
-      name: postgresOids.name,
-      xml: postgresOids.xml,
-      unknown: postgresOids.unknown,
-      bpchar: postgresOids.bpchar,
-      charArray: postgresOids.charArray,
-      nameArray: postgresOids.nameArray,
-      bpcharArray: postgresOids.bpcharArray,
-      xmlArray: postgresOids.xmlArray,
-    },
-    {
-      char: 18,
-      name: 19,
-      xml: 142,
-      unknown: 705,
-      bpchar: 1042,
-      charArray: 1002,
-      nameArray: 1003,
-      bpcharArray: 1014,
-      xmlArray: 143,
-    },
-  );
-
-  const decoded = decodeQueryResult(
-    parseQueryRawResponse(
-      queryResponse(
-        [
-          field("chars", postgresOids.charArray),
-          field("names", postgresOids.nameArray),
-          field("fixed", postgresOids.bpcharArray),
-          field("xml", postgresOids.xmlArray),
-          field("literal", postgresOids.unknown),
-        ],
-        [["{a,b}", "{one,two}", "{fixed,padded}", "{,}", "value"]],
-        "SELECT 1",
-      ),
-    ),
-  );
-  assert.deepEqual(decoded.rows, [
-    {
-      chars: ["a", "b"],
-      names: ["one", "two"],
-      fixed: ["fixed", "padded"],
-      xml: ["", ""],
-      literal: "value",
-    },
-  ]);
-  assert.equal(
-    array(["a"], postgresOids.charArray).typeOid,
-    postgresOids.charArray,
-  );
-});
-
-test("exec attributes notices to each statement and retains aggregate operation notices", () => {
-  const response = backendResponse([
-    [0x4e, diagnostic("NOTICE", "00000", "before create")],
-    [0x43, cstring("CREATE TABLE")],
-    [0x49, []],
-    [0x4e, diagnostic("NOTICE", "00000", "before select")],
-    [0x54, rowDescription([field("value", postgresOids.int4)])],
-    [0x44, dataRow(["42"])],
-    [0x43, cstring("SELECT 1")],
-    [0x4e, diagnostic("NOTICE", "00000", "after statements")],
-    [0x5a, [0x49]],
-  ]);
-  const result = parseExecResponse(response);
-  assert.equal(result.statements.length, 2);
-  assert.equal(result.statements[0]!.kind, "command");
-  assert.equal(result.statements[1]!.kind, "rows");
-  assert.deepEqual(result.statements[1]!.rows, [{ value: 42 }]);
-  assert.deepEqual(
-    result.statements.map((statement) =>
-      statement.notices.map((notice) => notice.message),
-    ),
-    [["before create"], ["before select"]],
-  );
-  assert.deepEqual(
-    result.notices.map((notice) => notice.message),
-    ["before create", "before select", "after statements"],
-  );
-});
-
-test("exec validates the complete response before decoding and snapshots options once", () => {
-  const validResponse = backendResponse([
-    [0x54, rowDescription([field("value", postgresOids.int4)])],
-    [0x44, dataRow(["1"])],
-    [0x43, cstring("SELECT 1")],
-    [0x54, rowDescription([field("value", postgresOids.int4)])],
-    [0x44, dataRow(["2"])],
-    [0x43, cstring("SELECT 1")],
-    [0x5a, [0x49]],
-  ]);
-  let optionReads = 0;
-  let decoderCalls = 0;
-  const result = parseExecResponse(validResponse, {
-    get decoders() {
-      optionReads += 1;
-      return {
-        [postgresOids.int4]: (value: string) => {
-          decoderCalls += 1;
-          return Number(value);
-        },
-      };
-    },
-  });
-  assert.equal(optionReads, 1);
-  assert.equal(decoderCalls, 2);
-  assert.deepEqual(
-    result.statements.map((statement) => statement.rows),
-    [[{ value: 1 }], [{ value: 2 }]],
-  );
-
-  let emptyOptionReads = 0;
-  const empty = parseExecResponse(
-    backendResponse([
-      [0x49, []],
-      [0x5a, [0x49]],
-    ]),
-    {
-      get decoders() {
-        emptyOptionReads += 1;
-        return undefined;
-      },
-    },
-  );
-  assert.equal(empty.statements.length, 0);
-  assert.equal(emptyOptionReads, 0);
-
-  decoderCalls = 0;
-  assert.throws(
-    () =>
-      parseExecResponse(
-        backendResponse([
-          [0x54, rowDescription([field("value", postgresOids.int4)])],
-          [0x44, dataRow(["1"])],
-          [0x43, cstring("SELECT 1")],
-          [0x31, []],
-          [0x5a, [0x49]],
-        ]),
-        {
-          decoders: {
-            [postgresOids.int4]: (value) => {
-              decoderCalls += 1;
-              return Number(value);
-            },
-          },
-        },
-      ),
-    /simple-query response contained ParseComplete/,
-  );
-  assert.equal(decoderCalls, 0);
-});
-
-test("exec decoder failures stop later decoding but retain all operation notices", () => {
-  let decoderCalls = 0;
-  const failure = thrownBy(() =>
-    parseExecResponse(
-      backendResponse([
-        [0x4e, diagnostic("NOTICE", "00000", "before first")],
-        [0x54, rowDescription([field("value", postgresOids.int4)])],
-        [0x44, dataRow(["1"])],
-        [0x43, cstring("SELECT 1")],
-        [0x4e, diagnostic("NOTICE", "00000", "before second")],
-        [0x54, rowDescription([field("value", postgresOids.int4)])],
-        [0x44, dataRow(["2"])],
-        [0x43, cstring("SELECT 1")],
-        [0x4e, diagnostic("NOTICE", "00000", "after statements")],
-        [0x5a, [0x49]],
-      ]),
-      {
-        decoders: {
-          [postgresOids.int4]: () => {
-            decoderCalls += 1;
-            throw new Error("decoder stopped");
-          },
-        },
-      },
-    ),
-  );
-  assert.equal(decoderCalls, 1);
-  assert.deepEqual(
-    (failure as Error & { notices: Array<{ message: string }> }).notices.map(
-      (notice) => notice.message,
-    ),
-    ["before first", "before second", "after statements"],
-  );
-  assert.equal(responseTransactionStatus(failure as object), "idle");
-});
-
-test("exec extracts row counts without narrowing backend whitespace semantics", () => {
-  const commandTags = [
-    "SELECT 42",
-    " INSERT 0 7 ",
-    "\u00a0UPDATE\t0003\u3000",
-    "FETCH FORWARD 9",
-    "COPY 10",
-    "CREATE TABLE",
-    "SELECT 9007199254740992",
-    "SELECT +1",
-    "SELECT",
-  ];
-  const result = parseExecResponse(
-    backendResponse([
-      ...commandTags.map((tag) => [0x43, cstring(tag)] as const),
-      [0x5a, [0x49]],
-    ]),
-  );
-  assert.deepEqual(
-    result.statements.map((statement) => statement.rowCount),
-    [42, 7, 3, 9, 10, null, null, null, null],
-  );
-});
-
-test("describe is structured and errors drain through ReadyForQuery with notices", () => {
-  const described = parseDescribeResponse(
-    backendResponse([
-      [0x31, []],
-      [0x74, [...i16(1), ...i32(postgresOids.jsonb)]],
-      [0x54, rowDescription([field("payload", postgresOids.jsonb)])],
-      [0x5a, [0x49]],
-    ]),
-  );
-  assert.deepEqual(described.parameterTypeOids, [postgresOids.jsonb]);
-  assert.equal(described.fields?.[0]?.name, "payload");
-  assert.deepEqual(
-    frontendMessages(describeQuery("SELECT $1", [0])).map(
-      (message) => message.tag,
-    ),
-    ["P", "D", "S"],
-  );
-
-  const failure = thrownBy(() =>
-    parseQueryRawResponse(
-      backendResponse([
-        [0x4e, diagnostic("NOTICE", "00000", "before error")],
-        [0x45, diagnostic("ERROR", "22023", "bad value")],
-        [0x53, [...cstring("application_name"), ...cstring("test")]],
-        [0x5a, [0x45]],
-      ]),
-    ),
-  );
-  assert.ok(failure instanceof PostgresError);
-  assert.equal(failure.notices[0]!.message, "before error");
-  assert.equal(responseTransactionStatus(failure), "failed");
-  assert.equal(failure.sqlstate, "22023");
-  assert.equal(failure.message, "bad value");
-});
-
-test("diagnostics promote standard PostgreSQL fields and preserve unknown fields", () => {
-  const noticeFields: Array = [
-    [0x53, "AVERTISSEMENT"],
-    [0x56, "WARNING"],
-    [0x43, "01000"],
-    [0x4d, "notice message"],
-    [0x70, "3"],
-    [0x71, "SELECT notice"],
-    [0x57, "PL/pgSQL function notice_fn() line 1"],
-    [0x46, "pl_exec.c"],
-    [0x4c, "100"],
-    [0x52, "exec_stmt_raise"],
-  ];
-  const errorFields: Array = [
-    [0x53, "ERREUR"],
-    [0x56, "ERROR"],
-    [0x43, "XX000"],
-    [0x4d, "error message"],
-    [0x70, "7"],
-    [0x71, "SELECT broken"],
-    [0x57, "PL/pgSQL function broken_fn() line 2"],
-    [0x46, "postgres.c"],
-    [0x4c, "200"],
-    [0x52, "exec_simple_query"],
-    [0x58, "future diagnostic"],
-  ];
-
-  const failure = thrownBy(() =>
-    parseQueryRawResponse(
-      backendResponse([
-        [0x4e, diagnosticFields(noticeFields)],
-        [0x45, diagnosticFields(errorFields)],
-        [0x5a, [0x49]],
-      ]),
-    ),
-  );
-  assert.ok(failure instanceof PostgresError);
-  assert.deepEqual(
-    {
-      severity: failure.severity,
-      localizedSeverity: failure.localizedSeverity,
-      nonlocalizedSeverity: failure.nonlocalizedSeverity,
-      internalPosition: failure.internalPosition,
-      internalQuery: failure.internalQuery,
-      whereText: failure.whereText,
-      file: failure.file,
-      line: failure.line,
-      routine: failure.routine,
-    },
-    {
-      severity: "ERREUR",
-      localizedSeverity: "ERREUR",
-      nonlocalizedSeverity: "ERROR",
-      internalPosition: "7",
-      internalQuery: "SELECT broken",
-      whereText: "PL/pgSQL function broken_fn() line 2",
-      file: "postgres.c",
-      line: "200",
-      routine: "exec_simple_query",
-    },
-  );
-  assert.deepEqual(failure.fields.at(-1), {
-    code: 0x58,
-    value: "future diagnostic",
-  });
-
-  const notice = failure.notices[0]!;
-  assert.deepEqual(
-    {
-      severity: notice.severity,
-      localizedSeverity: notice.localizedSeverity,
-      nonlocalizedSeverity: notice.nonlocalizedSeverity,
-      internalPosition: notice.internalPosition,
-      internalQuery: notice.internalQuery,
-      whereText: notice.whereText,
-      file: notice.file,
-      line: notice.line,
-      routine: notice.routine,
-    },
-    {
-      severity: "AVERTISSEMENT",
-      localizedSeverity: "AVERTISSEMENT",
-      nonlocalizedSeverity: "WARNING",
-      internalPosition: "3",
-      internalQuery: "SELECT notice",
-      whereText: "PL/pgSQL function notice_fn() line 1",
-      file: "pl_exec.c",
-      line: "100",
-      routine: "exec_stmt_raise",
-    },
-  );
-});
-
-test("custom decoder failures retain query notices and normalize unattachable throws", () => {
-  const queryRaw = parseQueryRawResponse(
-    backendResponse([
-      [0x31, []],
-      [0x32, []],
-      [0x54, rowDescription([field("value", postgresOids.int4)])],
-      [0x4e, diagnostic("NOTICE", "00000", "query notice")],
-      [0x44, dataRow(["42"])],
-      [0x43, cstring("SELECT 1")],
-      [0x5a, [0x49]],
-    ]),
-  );
-  const extensible = new Error("extensible decoder failure");
-  const queryFailure = thrownBy(() =>
-    decodeQueryResult(queryRaw, {
-      decoders: {
-        [postgresOids.int4]: () => {
-          throw extensible;
-        },
-      },
-    }),
-  );
-  assert.equal(queryFailure, extensible);
-  assert.deepEqual(
-    (queryFailure as { notices: Array<{ message: string }> }).notices.map(
-      (notice) => notice.message,
-    ),
-    ["query notice"],
-  );
-  assert.equal(responseTransactionStatus(queryFailure as object), "idle");
-
-  const frozen = Object.freeze(new Error("frozen decoder failure"));
-  const execFailure = thrownBy(() =>
-    parseExecResponse(
-      backendResponse([
-        [0x54, rowDescription([field("value", postgresOids.int4)])],
-        [0x4e, diagnostic("NOTICE", "00000", "exec notice")],
-        [0x44, dataRow(["42"])],
-        [0x43, cstring("SELECT 1")],
-        [0x5a, [0x49]],
-      ]),
-      {
-        decoders: {
-          [postgresOids.int4]: () => {
-            throw frozen;
-          },
-        },
-      },
-    ),
-  );
-  assert.ok(execFailure instanceof Error);
-  assert.notEqual(execFailure, frozen);
-  assert.equal(execFailure.cause, frozen);
-  assert.deepEqual(
-    (
-      execFailure as Error & { notices: Array<{ message: string }> }
-    ).notices.map((notice) => notice.message),
-    ["exec notice"],
-  );
-  assert.equal(responseTransactionStatus(execFailure), "idle");
-
-  const primitiveFailure = thrownBy(() =>
-    decodeQueryResult(queryRaw, {
-      decoders: {
-        [postgresOids.int4]: () => {
-          throw "primitive decoder failure";
-        },
-      },
-    }),
-  );
-  assert.ok(primitiveFailure instanceof Error);
-  assert.equal(primitiveFailure.message, "primitive decoder failure");
-  assert.equal(primitiveFailure.cause, "primitive decoder failure");
-  assert.deepEqual(
-    (
-      primitiveFailure as Error & { notices: Array<{ message: string }> }
-    ).notices.map((notice) => notice.message),
-    ["query notice"],
-  );
-
-  const frozenWithoutNotices = Object.freeze(
-    new Error("frozen failure without notices"),
-  );
-  const noNoticeRaw = parseQueryRawResponse(
-    queryResponse([field("value", postgresOids.int4)], [["42"]], "SELECT 1"),
-  );
-  const noNoticeFailure = thrownBy(() =>
-    decodeQueryResult(noNoticeRaw, {
-      decoders: {
-        [postgresOids.int4]: () => {
-          throw frozenWithoutNotices;
-        },
-      },
-    }),
-  );
-  assert.equal(noNoticeFailure, frozenWithoutNotices);
-
-  const primitiveWithoutNotices = thrownBy(() =>
-    decodeQueryResult(noNoticeRaw, {
-      decoders: {
-        [postgresOids.int4]: () => {
-          throw "primitive failure without notices";
-        },
-      },
-    }),
-  );
-  assert.ok(primitiveWithoutNotices instanceof Error);
-  assert.equal(
-    primitiveWithoutNotices.cause,
-    "primitive failure without notices",
-  );
-  assert.equal(responseTransactionStatus(primitiveWithoutNotices), "idle");
-});
-
-test("readiness inspection is decode-independent and malformed errors stay protocol errors", () => {
-  assert.equal(
-    inspectReadyForQuery(backendResponse([[0x5a, [0x54]]])),
-    "transaction",
-  );
-  assert.throws(
-    () =>
-      inspectReadyForQuery(
-        backendResponse([
-          [0x5a, [0x49]],
-          [0x49, []],
-        ]),
-      ),
-    /bytes after ReadyForQuery/,
-  );
-  assert.throws(
-    () => inspectReadyForQuery(backendResponse([[0x43, cstring("SELECT 0")]])),
-    /before ReadyForQuery/,
-  );
-  assert.equal(
-    inspectReadyForQuery(
-      backendResponse([
-        [0x43, cstring("SÉLECT 0")],
-        [0x5a, [0x49]],
-      ]),
-    ),
-    "idle",
-  );
-  assert.throws(
-    () =>
-      inspectReadyForQuery(
-        backendResponse([
-          [0x43, [0xc0, 0]],
-          [0x5a, [0x49]],
-        ]),
-    ),
-    /CommandComplete tag is not valid UTF-8/,
-  );
-  assert.throws(
-    () =>
-      inspectReadyForQuery(
-        backendResponse([
-          [0x43, [0x53]],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /CommandComplete tag is missing null terminator/,
-  );
-  assert.throws(
-    () =>
-      inspectReadyForQuery(
-        backendResponse([
-          [0x43, [...cstring("SELECT 0"), 0x53]],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /CommandComplete contained trailing bytes/,
-  );
-  assert.throws(
-    () =>
-      inspectReadyForQuery(
-        backendResponse([
-          [0x43, [0xc0, 0, 0x53]],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /CommandComplete tag is not valid UTF-8/,
-  );
-
-  const malformed = thrownBy(() =>
-    parseQueryRawResponse(
-      backendResponse([
-        [0x45, [0x4d, 0xc0, 0, 0]],
-        [0x5a, [0x49]],
-      ]),
-    ),
-  );
-  assert.ok(malformed instanceof Error);
-  assert.equal(malformed instanceof PostgresError, false);
-  assert.match(malformed.message, /ErrorResponse field is not valid UTF-8/);
-  assert.equal(responseTransactionStatus(malformed), "idle");
-});
-
-test("managed transaction inspection uses every protocol tag and final readiness boundary", () => {
-  for (const tag of [
-    "BEGIN",
-    "START TRANSACTION",
-    "COMMIT",
-    "PREPARE TRANSACTION",
-    "COMMIT PREPARED",
-    "ROLLBACK PREPARED",
-  ]) {
-    assert.throws(
-      () =>
-        inspectManagedTransactionResponse(
-          backendResponse([
-            [0x43, cstring(tag)],
-            [0x5a, [0x54]],
-          ]),
-        ),
-      /violated callback transaction ownership/,
-      tag,
-    );
-  }
-
-  assert.throws(
-    () =>
-      inspectManagedTransactionResponse(
-        backendResponse([
-          [0x43, cstring("COMMIT")],
-          [0x43, cstring("BEGIN")],
-          [0x45, diagnostic("ERROR", "XX000", "later failure")],
-          [0x5a, [0x54]],
-        ]),
-      ),
-    /command tag COMMIT/,
-  );
-  assert.throws(
-    () =>
-      inspectManagedTransactionResponse(
-        backendResponse([
-          [0x43, cstring("ROLLBACK")],
-          [0x43, cstring("BEGIN")],
-          [0x5a, [0x54]],
-        ]),
-      ),
-    /command tag BEGIN/,
-  );
-  assert.throws(
-    () =>
-      inspectManagedTransactionResponse(
-        backendResponse([
-          [0x43, cstring("ROLLBACK")],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /ended PostgreSQL transaction ownership/,
-  );
-
-  for (const [tag, status] of [
-    ["ROLLBACK", 0x54],
-    ["ROLLBACK", 0x45],
-    ["SAVEPOINT", 0x54],
-    ["RELEASE", 0x54],
-    ["SET", 0x54],
-    ["PREPARE", 0x54],
-    ["CREATE FUNCTION", 0x54],
-    ["CALL", 0x54],
-    ["DO", 0x54],
-  ] as const) {
-    assert.equal(
-      inspectManagedTransactionResponse(
-        backendResponse([
-          [0x43, cstring(tag)],
-          [0x5a, [status]],
-        ]),
-      ),
-      status === 0x45 ? "failed" : "transaction",
-      tag,
-    );
-  }
-});
-
-test("structured parsers require exact completion and reject post-completion rows", () => {
-  const readyOnly = backendResponse([[0x5a, [0x49]]]);
-  assert.throws(
-    () => parseQueryRawResponse(readyOnly),
-    /omitted CommandComplete or EmptyQueryResponse/,
-  );
-  assert.throws(
-    () => parseExecResponse(readyOnly),
-    /omitted CommandComplete or EmptyQueryResponse/,
-  );
-  assert.throws(
-    () =>
-      parseQueryRawResponse(
-        backendResponse([
-          [0x43, cstring("UPDATE 1")],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /before the extended-query result description/,
-  );
-  assert.throws(
-    () =>
-      parseQueryRawResponse(
-        backendResponse([
-          [0x49, []],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /before the extended-query result description/,
-  );
-
-  assert.throws(
-    () =>
-      parseQueryRawResponse(
-        backendResponse([
-          [0x31, []],
-          [0x32, []],
-          [0x6e, []],
-          [0x43, cstring("UPDATE 1")],
-          [0x43, cstring("UPDATE 1")],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /multiple result completions/,
-  );
-  assert.throws(
-    () =>
-      parseQueryRawResponse(
-        backendResponse([
-          [0x31, []],
-          [0x32, []],
-          [0x6e, []],
-          [0x43, cstring("SELECT 1")],
-          [0x44, dataRow(["late"])],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /DataRow arrived after statement completion/,
-  );
-
-  const empty = parseQueryRawResponse(
-    backendResponse([
-      [0x31, []],
-      [0x32, []],
-      [0x6e, []],
-      [0x49, []],
-      [0x5a, [0x49]],
-    ]),
-  );
-  assert.equal(empty.kind, "command");
-  assert.equal(empty.commandTag, undefined);
-
-  const multi = parseExecResponse(
-    backendResponse([
-      [0x43, cstring("UPDATE 1")],
-      [0x49, []],
-      [0x43, cstring("DELETE 2")],
-      [0x5a, [0x49]],
-    ]),
-  );
-  assert.deepEqual(
-    multi.statements.map((statement) => statement.commandTag),
-    ["UPDATE 1", "DELETE 2"],
-  );
-
-  assert.throws(
-    () =>
-      parseDescribeResponse(
-        backendResponse([
-          [0x74, [...i16(0)]],
-          [0x6e, []],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /before ParseComplete|omitted ParseComplete/,
-  );
-  assert.throws(
-    () =>
-      parseDescribeResponse(
-        backendResponse([
-          [0x31, []],
-          [0x74, [...i16(0)]],
-          [0x6e, []],
-          [0x45, diagnostic("ERROR", "XX000", "late describe error")],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /ErrorResponse arrived after describe completion/,
-  );
-
-  assert.throws(
-    () =>
-      parseQueryRawResponse(
-        backendResponse([
-          [0x32, []],
-          [0x6e, []],
-          [0x43, cstring("UPDATE 1")],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /BindComplete arrived before ParseComplete/,
-  );
-  assert.throws(
-    () =>
-      parseQueryRawResponse(
-        backendResponse([
-          [0x31, []],
-          [0x32, []],
-          [0x6e, []],
-          [0x43, cstring("UPDATE 1")],
-          [0x33, []],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /unsolicited CloseComplete/,
-  );
-  assert.throws(
-    () =>
-      parseExecResponse(
-        backendResponse([
-          [0x31, []],
-          [0x43, cstring("UPDATE 1")],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /simple-query response contained ParseComplete/,
-  );
-  assert.throws(
-    () =>
-      parseQueryRawResponse(
-        backendResponse([
-          [0x31, []],
-          [0x32, []],
-          [0x6e, []],
-          [0x43, cstring("UPDATE 1")],
-          [0x45, diagnostic("ERROR", "XX000", "late error")],
-          [0x5a, [0x49]],
-        ]),
-      ),
-    /ErrorResponse arrived after statement completion/,
-  );
-});
-
-test("structured SQL scanners match the shared lexical corpus", () => {
-  const fixture = JSON.parse(
-    readFileSync(
-      new URL(
-        "../../fixtures/protocol/structured-sql-cases.json",
-        import.meta.url,
-      ),
-      "utf8",
-    ),
-  ) as {
-    schemaVersion: number;
-    cases: Array<{
-      name: string;
-      sql: string;
-      containsTopLevelCopy: boolean;
-      containsTransactionChain: boolean;
-    }>;
-  };
-  assert.equal(fixture.schemaVersion, 2);
-  for (const entry of fixture.cases) {
-    assert.equal(
-      containsTopLevelCopy(entry.sql),
-      entry.containsTopLevelCopy,
-      entry.name,
-    );
-    assert.equal(
-      containsTransactionChain(entry.sql),
-      entry.containsTransactionChain,
-      entry.name,
-    );
-  }
-});
-
-type FieldInput = { name: string; typeOid: number };
-
-function field(name: string, typeOid: number): FieldInput {
-  return { name, typeOid };
-}
-
-function queryResponse(
-  fields: FieldInput[],
-  rows: string[][],
-  commandTag: string,
-): Uint8Array {
-  return backendResponse([
-    [0x31, []],
-    [0x32, []],
-    [0x54, rowDescription(fields)],
-    ...rows.map((row) => [0x44, dataRow(row)] as const),
-    [0x43, cstring(commandTag)],
-    [0x5a, [0x49]],
-  ]);
-}
-
-function rowDescription(fields: FieldInput[]): number[] {
-  return [
-    ...i16(fields.length),
-    ...fields.flatMap((entry) => [
-      ...cstring(entry.name),
-      ...i32(0),
-      ...i16(0),
-      ...i32(entry.typeOid),
-      ...i16(-1),
-      ...i32(-1),
-      ...i16(0),
-    ]),
-  ];
-}
-
-function dataRow(values: string[]): number[] {
-  return [
-    ...i16(values.length),
-    ...values.flatMap((value) => {
-      const bytes = new TextEncoder().encode(value);
-      return [...i32(bytes.length), ...bytes];
-    }),
-  ];
-}
-
-function diagnostic(
-  severity: string,
-  sqlstate: string,
-  message: string,
-): number[] {
-  return diagnosticFields([
-    [0x53, severity],
-    [0x43, sqlstate],
-    [0x4d, message],
-  ]);
-}
-
-function diagnosticFields(
-  fields: ReadonlyArray,
-): number[] {
-  return [...fields.flatMap(([code, value]) => [code, ...cstring(value)]), 0];
-}
-
-function backendResponse(
-  messages: ReadonlyArray,
-): Uint8Array {
-  return Uint8Array.from(
-    messages.flatMap(([tag, body]) => [tag, ...i32(body.length + 4), ...body]),
-  );
-}
-
-function cstring(value: string): number[] {
-  return [...new TextEncoder().encode(value), 0];
-}
-
-function i16(value: number): number[] {
-  const bits = value & 0xffff;
-  return [(bits >>> 8) & 0xff, bits & 0xff];
-}
-
-function i32(value: number): number[] {
-  const bits = value >>> 0;
-  return [
-    (bits >>> 24) & 0xff,
-    (bits >>> 16) & 0xff,
-    (bits >>> 8) & 0xff,
-    bits & 0xff,
-  ];
-}
-
-function frontendMessages(
-  bytes: Uint8Array,
-): Array<{ tag: string; body: Uint8Array }> {
-  const messages: Array<{ tag: string; body: Uint8Array }> = [];
-  let offset = 0;
-  while (offset < bytes.length) {
-    const length = readI32(bytes, offset + 1);
-    messages.push({
-      tag: String.fromCharCode(bytes[offset]!),
-      body: bytes.slice(offset + 5, offset + 1 + length),
-    });
-    offset += length + 1;
-  }
-  return messages;
-}
-
-function readParseTypeOids(body: Uint8Array): number[] {
-  let offset = 1;
-  while (body[offset] !== 0) offset += 1;
-  offset += 1;
-  const count = readI16(body, offset);
-  offset += 2;
-  const oids: number[] = [];
-  for (let index = 0; index < count; index += 1) {
-    oids.push(readI32(body, offset) >>> 0);
-    offset += 4;
-  }
-  return oids;
-}
-
-function readI16(bytes: Uint8Array, offset: number): number {
-  return (bytes[offset]! << 8) | bytes[offset + 1]!;
-}
-
-function readI32(bytes: Uint8Array, offset: number): number {
-  return (
-    (bytes[offset]! * 0x1000000 +
-      (bytes[offset + 1]! << 16) +
-      (bytes[offset + 2]! << 8) +
-      bytes[offset + 3]!) >>>
-    0
-  );
-}
-
-function thrownBy(callback: () => unknown): unknown {
-  try {
-    callback();
-  } catch (error) {
-    return error;
-  }
-  throw new Error("expected callback to throw");
-}
diff --git a/src/shared/js-core/tools/stage-package.mjs b/src/shared/js-core/tools/stage-package.mjs
deleted file mode 100644
index 5b043e0dd..000000000
--- a/src/shared/js-core/tools/stage-package.mjs
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env node
-
-import { cpSync, lstatSync, mkdirSync, readFileSync } from "node:fs";
-import path from "node:path";
-import { fileURLToPath } from "node:url";
-
-export const JS_CORE_PACKAGE = "@oliphaunt/js-core";
-export const JS_CORE_BUNDLE_FILES = Object.freeze([
-  "README.md",
-  "dist/commonjs/protocol.d.ts",
-  "dist/commonjs/protocol.js",
-  "dist/commonjs/query.d.ts",
-  "dist/commonjs/query.js",
-  "dist/module/package.json",
-  "dist/module/protocol.d.ts",
-  "dist/module/protocol.js",
-  "dist/module/query.d.ts",
-  "dist/module/query.js",
-  "package.json",
-]);
-
-export function stageJsCoreBundle(packageDir, coreDir) {
-  const packageRoot = requireDirectory(packageDir, "consumer package");
-  const coreRoot = requireDirectory(coreDir, "shared JavaScript core package");
-  const manifest = JSON.parse(readFileSync(path.join(coreRoot, "package.json"), "utf8"));
-  if (
-    manifest.name !== JS_CORE_PACKAGE
-    || manifest.private !== true
-    || manifest.version !== "0.0.0"
-    || JSON.stringify(manifest.files) !== JSON.stringify(["dist/module", "dist/commonjs"])
-  ) {
-    throw new Error("shared JavaScript core must be the private, minimal 0.0.0 workspace package");
-  }
-  const destination = path.join(packageRoot, "node_modules", "@oliphaunt", "js-core");
-  mkdirSync(destination, { recursive: true });
-  for (const relative of JS_CORE_BUNDLE_FILES) {
-    const source = path.join(coreRoot, relative);
-    requireFile(source, `shared JavaScript core bundle member ${relative}`);
-    const output = path.join(destination, relative);
-    mkdirSync(path.dirname(output), { recursive: true });
-    cpSync(source, output, { errorOnExist: true, force: false });
-  }
-  return { destination, manifest };
-}
-
-export function assertJsCoreBundleInventory(paths, prefix = "node_modules/@oliphaunt/js-core/") {
-  const actual = [...paths]
-    .filter((entry) => entry.startsWith(prefix))
-    .map((entry) => entry.slice(prefix.length))
-    .sort();
-  const expected = [...JS_CORE_BUNDLE_FILES].sort();
-  if (JSON.stringify(actual) !== JSON.stringify(expected)) {
-    throw new Error(`bundled ${JS_CORE_PACKAGE} inventory mismatch`);
-  }
-}
-
-function requireDirectory(value, label) {
-  const resolved = path.resolve(value);
-  const stat = lstatSync(resolved);
-  if (!stat.isDirectory() || stat.isSymbolicLink()) {
-    throw new Error(`${label} must be a real directory: ${resolved}`);
-  }
-  return resolved;
-}
-
-function requireFile(file, label) {
-  const stat = lstatSync(file);
-  if (!stat.isFile() || stat.isSymbolicLink()) {
-    throw new Error(`${label} must be a real file: ${file}`);
-  }
-}
-
-if (path.resolve(process.argv[1] ?? "") === fileURLToPath(import.meta.url)) {
-  const [packageDir, coreDir, ...extra] = process.argv.slice(2);
-  if (!packageDir || !coreDir || extra.length > 0) {
-    throw new Error("usage: stage-package.mjs PACKAGE_DIR CORE_DIR");
-  }
-  stageJsCoreBundle(packageDir, coreDir);
-}
diff --git a/src/shared/rust-query-core/moon.yml b/src/shared/rust-query-core/moon.yml
deleted file mode 100644
index ca2139b30..000000000
--- a/src/shared/rust-query-core/moon.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "shared-rust-query-core"
-language: "rust"
-layer: "library"
-stack: "systems"
-tags: ["shared", "rust", "sdk"]
-
-project:
-  title: "Shared Rust Query Core"
-  description: "Canonical dependency-free PostgreSQL query protocol core included by both Rust SDKs."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "query_core.rs": ["@oliphaunt/sdk-rust", "@oliphaunt/wasix-rust"]
-    "tools/**": ["@oliphaunt/core"]
-
-fileGroups:
-  sources:
-    - "query_core.rs"
-
-tasks:
-  check:
-    tags: ["quality", "static"]
-    command: "node src/shared/rust-query-core/tools/check-rust-query-core.mjs"
-    inputs:
-      - "@group(sources)"
-      - "tools/check-rust-query-core.mjs"
-      - "/src/sdks/rust/src/query_core*"
-      - "/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/query_core*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
diff --git a/src/shared/rust-query-core/query_core.rs b/src/shared/rust-query-core/query_core.rs
deleted file mode 100644
index 88bf99caa..000000000
--- a/src/shared/rust-query-core/query_core.rs
+++ /dev/null
@@ -1,2750 +0,0 @@
-// Runtime-neutral PostgreSQL query protocol core shared by the Rust SDKs.
-//
-// This module deliberately has no dependencies outside `std`. It owns the
-// public query data model and diagnostics re-exported by both Rust facades;
-// runtime-specific request transport and outer error mapping stay at the
-// facade boundary.
-
-use std::sync::Arc;
-use std::{fmt, str};
-
-/// PostgreSQL object identifier used for parameter and result types.
-#[repr(transparent)]
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct TypeOid(u32);
-
-impl TypeOid {
-    /// PostgreSQL bool.
-    pub const BOOL: Self = Self(16);
-    /// PostgreSQL bytea.
-    pub const BYTEA: Self = Self(17);
-    /// PostgreSQL internal single-byte char.
-    pub const CHAR: Self = Self(18);
-    /// PostgreSQL name.
-    pub const NAME: Self = Self(19);
-    /// PostgreSQL int8.
-    pub const INT8: Self = Self(20);
-    /// PostgreSQL int2.
-    pub const INT2: Self = Self(21);
-    /// PostgreSQL int4.
-    pub const INT4: Self = Self(23);
-    /// PostgreSQL text.
-    pub const TEXT: Self = Self(25);
-    /// PostgreSQL oid.
-    pub const OID: Self = Self(26);
-    /// PostgreSQL json.
-    pub const JSON: Self = Self(114);
-    /// PostgreSQL xml.
-    pub const XML: Self = Self(142);
-    /// PostgreSQL xml array.
-    pub const XML_ARRAY: Self = Self(143);
-    /// PostgreSQL json array.
-    pub const JSON_ARRAY: Self = Self(199);
-    /// PostgreSQL float4.
-    pub const FLOAT4: Self = Self(700);
-    /// PostgreSQL float8.
-    pub const FLOAT8: Self = Self(701);
-    /// PostgreSQL pseudo-type unknown.
-    pub const UNKNOWN: Self = Self(705);
-    /// PostgreSQL bool array.
-    pub const BOOL_ARRAY: Self = Self(1000);
-    /// PostgreSQL bytea array.
-    pub const BYTEA_ARRAY: Self = Self(1001);
-    /// PostgreSQL internal single-byte char array.
-    pub const CHAR_ARRAY: Self = Self(1002);
-    /// PostgreSQL name array.
-    pub const NAME_ARRAY: Self = Self(1003);
-    /// PostgreSQL int2 array.
-    pub const INT2_ARRAY: Self = Self(1005);
-    /// PostgreSQL int4 array.
-    pub const INT4_ARRAY: Self = Self(1007);
-    /// PostgreSQL text array.
-    pub const TEXT_ARRAY: Self = Self(1009);
-    /// PostgreSQL bpchar array.
-    pub const BPCHAR_ARRAY: Self = Self(1014);
-    /// PostgreSQL varchar array.
-    pub const VARCHAR_ARRAY: Self = Self(1015);
-    /// PostgreSQL int8 array.
-    pub const INT8_ARRAY: Self = Self(1016);
-    /// PostgreSQL float4 array.
-    pub const FLOAT4_ARRAY: Self = Self(1021);
-    /// PostgreSQL float8 array.
-    pub const FLOAT8_ARRAY: Self = Self(1022);
-    /// PostgreSQL oid array.
-    pub const OID_ARRAY: Self = Self(1028);
-    /// PostgreSQL bpchar.
-    pub const BPCHAR: Self = Self(1042);
-    /// PostgreSQL varchar.
-    pub const VARCHAR: Self = Self(1043);
-    /// PostgreSQL date.
-    pub const DATE: Self = Self(1082);
-    /// PostgreSQL time without time zone.
-    pub const TIME: Self = Self(1083);
-    /// PostgreSQL timestamp without time zone.
-    pub const TIMESTAMP: Self = Self(1114);
-    /// PostgreSQL timestamp array.
-    pub const TIMESTAMP_ARRAY: Self = Self(1115);
-    /// PostgreSQL date array.
-    pub const DATE_ARRAY: Self = Self(1182);
-    /// PostgreSQL time array.
-    pub const TIME_ARRAY: Self = Self(1183);
-    /// PostgreSQL timestamp with time zone.
-    pub const TIMESTAMPTZ: Self = Self(1184);
-    /// PostgreSQL timestamptz array.
-    pub const TIMESTAMPTZ_ARRAY: Self = Self(1185);
-    /// PostgreSQL interval.
-    pub const INTERVAL: Self = Self(1186);
-    /// PostgreSQL interval array.
-    pub const INTERVAL_ARRAY: Self = Self(1187);
-    /// PostgreSQL numeric array.
-    pub const NUMERIC_ARRAY: Self = Self(1231);
-    /// PostgreSQL time with time zone.
-    pub const TIMETZ: Self = Self(1266);
-    /// PostgreSQL timetz array.
-    pub const TIMETZ_ARRAY: Self = Self(1270);
-    /// PostgreSQL numeric.
-    pub const NUMERIC: Self = Self(1700);
-    /// PostgreSQL uuid.
-    pub const UUID: Self = Self(2950);
-    /// PostgreSQL uuid array.
-    pub const UUID_ARRAY: Self = Self(2951);
-    /// PostgreSQL jsonb.
-    pub const JSONB: Self = Self(3802);
-    /// PostgreSQL jsonb array.
-    pub const JSONB_ARRAY: Self = Self(3807);
-
-    /// Construct an OID, including an extension or application-defined type OID.
-    pub const fn new(oid: u32) -> Self {
-        Self(oid)
-    }
-
-    /// Return the numeric PostgreSQL OID.
-    pub const fn get(self) -> u32 {
-        self.0
-    }
-}
-
-impl From for TypeOid {
-    fn from(value: u32) -> Self {
-        Self::new(value)
-    }
-}
-
-impl From for u32 {
-    fn from(value: TypeOid) -> Self {
-        value.get()
-    }
-}
-
-/// PostgreSQL text or binary value format.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum ValueFormat {
-    /// PostgreSQL text representation.
-    Text,
-    /// PostgreSQL binary representation.
-    Binary,
-}
-
-impl ValueFormat {
-    pub(crate) fn code(self) -> i16 {
-        match self {
-            Self::Text => 0,
-            Self::Binary => 1,
-        }
-    }
-}
-
-/// Owned, optionally typed PostgreSQL bind parameter.
-///
-/// An absent type OID asks PostgreSQL to infer the parameter type. A None
-/// value is SQL NULL; it is independent of the parameter format and type hint.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Parameter {
-    type_oid: Option,
-    format: ValueFormat,
-    value: Option>,
-}
-
-impl Parameter {
-    /// Construct an untyped SQL NULL whose type PostgreSQL will infer.
-    pub fn null() -> Self {
-        Self {
-            type_oid: None,
-            format: ValueFormat::Text,
-            value: None,
-        }
-    }
-
-    /// Construct an untyped text-format value.
-    pub fn text(value: impl Into) -> Self {
-        Self {
-            type_oid: None,
-            format: ValueFormat::Text,
-            value: Some(value.into().into_bytes()),
-        }
-    }
-
-    /// Construct an untyped binary-format value.
-    pub fn binary(value: impl Into>) -> Self {
-        Self {
-            type_oid: None,
-            format: ValueFormat::Binary,
-            value: Some(value.into()),
-        }
-    }
-
-    /// Attach an explicit PostgreSQL type OID.
-    ///
-    /// OID 0 is PostgreSQL's inference sentinel. It is accepted when describing
-    /// a statement, but execution rejects an explicitly attached zero; leave
-    /// the OID unset to request execution-time inference.
-    pub fn with_type_oid(mut self, type_oid: TypeOid) -> Self {
-        self.type_oid = Some(type_oid);
-        self
-    }
-
-    /// Construct a typed SQL NULL.
-    pub fn typed_null(type_oid: TypeOid) -> Self {
-        Self::null().with_type_oid(type_oid)
-    }
-
-    /// Construct a typed text-format value.
-    pub fn typed_text(type_oid: TypeOid, value: impl Into) -> Self {
-        Self::text(value).with_type_oid(type_oid)
-    }
-
-    /// Construct a typed binary-format value.
-    pub fn typed_binary(type_oid: TypeOid, value: impl Into>) -> Self {
-        Self::binary(value).with_type_oid(type_oid)
-    }
-
-    /// Return the declared PostgreSQL type, or None for server inference.
-    pub fn type_oid(&self) -> Option {
-        self.type_oid
-    }
-
-    /// Return the frontend parameter format.
-    pub fn format(&self) -> ValueFormat {
-        self.format
-    }
-
-    /// Return the encoded bytes, or None for SQL NULL.
-    pub fn value(&self) -> Option<&[u8]> {
-        self.value.as_deref()
-    }
-}
-
-/// Conversion into an owned, typed PostgreSQL bind parameter.
-pub trait IntoParameter: Sized {
-    /// Type OID retained when `Option` is bound as SQL NULL.
-    const TYPE_OID: Option;
-
-    /// Encode this value as one PostgreSQL parameter.
-    fn into_parameter(self) -> Parameter;
-}
-
-impl IntoParameter for Parameter {
-    const TYPE_OID: Option = None;
-
-    fn into_parameter(self) -> Parameter {
-        self
-    }
-}
-
-impl IntoParameter for &str {
-    const TYPE_OID: Option = Some(TypeOid::TEXT);
-
-    fn into_parameter(self) -> Parameter {
-        Parameter::typed_text(TypeOid::TEXT, self)
-    }
-}
-
-impl IntoParameter for String {
-    const TYPE_OID: Option = Some(TypeOid::TEXT);
-
-    fn into_parameter(self) -> Parameter {
-        Parameter::typed_text(TypeOid::TEXT, self)
-    }
-}
-
-impl IntoParameter for &String {
-    const TYPE_OID: Option = Some(TypeOid::TEXT);
-
-    fn into_parameter(self) -> Parameter {
-        Parameter::typed_text(TypeOid::TEXT, self)
-    }
-}
-
-macro_rules! binary_parameter {
-    ($type:ty, $oid:expr, $encode:expr) => {
-        impl IntoParameter for $type {
-            const TYPE_OID: Option = Some($oid);
-
-            fn into_parameter(self) -> Parameter {
-                Parameter::typed_binary($oid, $encode(self))
-            }
-        }
-    };
-}
-
-binary_parameter!(i16, TypeOid::INT2, i16::to_be_bytes);
-binary_parameter!(i32, TypeOid::INT4, i32::to_be_bytes);
-binary_parameter!(i64, TypeOid::INT8, i64::to_be_bytes);
-binary_parameter!(f32, TypeOid::FLOAT4, |value: f32| value
-    .to_bits()
-    .to_be_bytes());
-binary_parameter!(f64, TypeOid::FLOAT8, |value: f64| value
-    .to_bits()
-    .to_be_bytes());
-
-impl IntoParameter for bool {
-    const TYPE_OID: Option = Some(TypeOid::BOOL);
-
-    fn into_parameter(self) -> Parameter {
-        Parameter::typed_binary(TypeOid::BOOL, [u8::from(self)])
-    }
-}
-
-impl IntoParameter for &[u8] {
-    const TYPE_OID: Option = Some(TypeOid::BYTEA);
-
-    fn into_parameter(self) -> Parameter {
-        Parameter::typed_binary(TypeOid::BYTEA, self)
-    }
-}
-
-impl IntoParameter for Vec {
-    const TYPE_OID: Option = Some(TypeOid::BYTEA);
-
-    fn into_parameter(self) -> Parameter {
-        Parameter::typed_binary(TypeOid::BYTEA, self)
-    }
-}
-
-impl IntoParameter for Option
-where
-    T: IntoParameter,
-{
-    const TYPE_OID: Option = T::TYPE_OID;
-
-    fn into_parameter(self) -> Parameter {
-        self.map(IntoParameter::into_parameter)
-            .unwrap_or_else(|| match Self::TYPE_OID {
-                Some(type_oid) => Parameter::typed_null(type_oid),
-                None => Parameter::null(),
-            })
-    }
-}
-
-/// Metadata for one PostgreSQL result column.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct QueryField {
-    /// Column name.
-    pub name: String,
-    /// Table OID reported by PostgreSQL, or 0 when not tied to a table.
-    pub table_oid: u32,
-    /// Table attribute number reported by PostgreSQL.
-    pub table_attribute: i16,
-    /// PostgreSQL type OID.
-    pub type_oid: u32,
-    /// PostgreSQL type size.
-    pub type_size: i16,
-    /// PostgreSQL type modifier.
-    pub type_modifier: i32,
-    /// Format used for values in this column.
-    pub format: QueryFormat,
-}
-
-impl QueryField {
-    /// PostgreSQL type OID as the typed API value.
-    pub fn type_oid_value(&self) -> TypeOid {
-        TypeOid::new(self.type_oid)
-    }
-}
-
-/// PostgreSQL result-column value format.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum QueryFormat {
-    /// Text format.
-    Text,
-    /// Binary format.
-    Binary,
-    /// Unknown or extension format code.
-    Other(i16),
-}
-
-impl QueryFormat {
-    fn value_format(self) -> Option {
-        match self {
-            Self::Text => Some(ValueFormat::Text),
-            Self::Binary => Some(ValueFormat::Binary),
-            Self::Other(_) => None,
-        }
-    }
-}
-
-impl From for QueryFormat {
-    fn from(value: i16) -> Self {
-        match value {
-            0 => Self::Text,
-            1 => Self::Binary,
-            other => Self::Other(other),
-        }
-    }
-}
-
-/// Fallible row-column index accepted by row decoding APIs.
-pub trait RowIndex {
-    /// Resolve this index against result field metadata.
-    fn resolve(&self, fields: &[QueryField]) -> std::result::Result;
-}
-
-impl RowIndex for usize {
-    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
-        if *self < fields.len() {
-            Ok(*self)
-        } else {
-            Err(DecodeError::ColumnOutOfBounds {
-                index: *self,
-                len: fields.len(),
-            })
-        }
-    }
-}
-
-impl RowIndex for str {
-    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
-        let mut matches = fields
-            .iter()
-            .enumerate()
-            .filter_map(|(index, field)| (field.name == self).then_some(index));
-        let first = matches
-            .next()
-            .ok_or_else(|| DecodeError::ColumnNotFound(self.to_owned()))?;
-        if matches.next().is_some() {
-            Err(DecodeError::AmbiguousColumn(self.to_owned()))
-        } else {
-            Ok(first)
-        }
-    }
-}
-
-impl RowIndex for &str {
-    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
-        ::resolve(self, fields)
-    }
-}
-
-impl RowIndex for String {
-    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
-        ::resolve(self.as_str(), fields)
-    }
-}
-
-impl RowIndex for &String {
-    fn resolve(&self, fields: &[QueryField]) -> std::result::Result {
-        ::resolve(self.as_str(), fields)
-    }
-}
-
-/// Borrowed PostgreSQL value with its column metadata.
-#[derive(Debug, Clone, Copy)]
-pub struct ValueRef<'a> {
-    column: usize,
-    field: &'a QueryField,
-    value: Option<&'a [u8]>,
-}
-
-impl<'a> ValueRef<'a> {
-    pub(crate) fn new(column: usize, field: &'a QueryField, value: Option<&'a [u8]>) -> Self {
-        Self {
-            column,
-            field,
-            value,
-        }
-    }
-
-    /// Zero-based column position.
-    pub fn column(&self) -> usize {
-        self.column
-    }
-
-    /// Column metadata.
-    pub fn field(&self) -> &'a QueryField {
-        self.field
-    }
-
-    /// PostgreSQL type OID.
-    pub fn type_oid(&self) -> TypeOid {
-        TypeOid::new(self.field.type_oid)
-    }
-
-    /// PostgreSQL result format, when recognized.
-    pub fn format(&self) -> Option {
-        self.field.format.value_format()
-    }
-
-    /// Whether this value is SQL NULL.
-    pub fn is_null(&self) -> bool {
-        self.value.is_none()
-    }
-
-    /// Borrow encoded value bytes, or None for SQL NULL.
-    pub fn as_bytes(&self) -> Option<&'a [u8]> {
-        self.value
-    }
-
-    fn require_bytes(self, target: &'static str) -> std::result::Result<&'a [u8], DecodeError> {
-        self.value.ok_or(DecodeError::UnexpectedNull {
-            column: self.column,
-            target,
-        })
-    }
-}
-
-/// Decode one PostgreSQL value into a Rust type.
-pub trait FromSql<'a>: Sized {
-    /// Validate column metadata before decoding, including for SQL NULL.
-    ///
-    /// Custom decoders may leave the default when they accept arbitrary
-    /// PostgreSQL types. Built-in decoders use this hook so `Option` does
-    /// not silently accept a null value of the wrong database type.
-    fn check_type(_value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
-        Ok(())
-    }
-
-    /// Decode a possibly-null text or binary value.
-    fn from_sql(value: ValueRef<'a>) -> std::result::Result;
-}
-
-/// Error produced while locating or decoding a row value.
-#[non_exhaustive]
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum DecodeError {
-    /// No result column had the requested name.
-    ColumnNotFound(String),
-    /// More than one result column had the requested name.
-    AmbiguousColumn(String),
-    /// A positional index exceeded the row width.
-    ColumnOutOfBounds {
-        /// Requested index.
-        index: usize,
-        /// Number of result columns.
-        len: usize,
-    },
-    /// SQL NULL cannot be decoded into the requested non-optional type.
-    UnexpectedNull {
-        /// Column index.
-        column: usize,
-        /// Requested Rust target.
-        target: &'static str,
-    },
-    /// PostgreSQL returned a type incompatible with the requested Rust target.
-    TypeMismatch {
-        /// Column index.
-        column: usize,
-        /// Actual PostgreSQL type OID.
-        type_oid: TypeOid,
-        /// Requested Rust target.
-        target: &'static str,
-    },
-    /// PostgreSQL returned an unsupported value format.
-    UnsupportedFormat {
-        /// Column index.
-        column: usize,
-        /// Raw PostgreSQL format code.
-        format: i16,
-    },
-    /// Encoded bytes were not a valid value for the requested Rust target.
-    InvalidValue {
-        /// Column index.
-        column: usize,
-        /// Requested Rust target.
-        target: &'static str,
-        /// Decoder detail.
-        message: String,
-    },
-}
-
-impl fmt::Display for DecodeError {
-    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::ColumnNotFound(name) => {
-                write!(formatter, "query result has no column named {name:?}")
-            }
-            Self::AmbiguousColumn(name) => write!(
-                formatter,
-                "query result has more than one column named {name:?}; use a positional index"
-            ),
-            Self::ColumnOutOfBounds { index, len } => write!(
-                formatter,
-                "query row has no column at index {index}; row has {len} columns"
-            ),
-            Self::UnexpectedNull { column, target } => {
-                write!(
-                    formatter,
-                    "column {column} is NULL and cannot decode as {target}"
-                )
-            }
-            Self::TypeMismatch {
-                column,
-                type_oid,
-                target,
-            } => write!(
-                formatter,
-                "column {column} has PostgreSQL type OID {} and cannot decode as {target}",
-                type_oid.get()
-            ),
-            Self::UnsupportedFormat { column, format } => write!(
-                formatter,
-                "column {column} uses unsupported PostgreSQL format code {format}"
-            ),
-            Self::InvalidValue {
-                column,
-                target,
-                message,
-            } => write!(
-                formatter,
-                "column {column} could not decode as {target}: {message}"
-            ),
-        }
-    }
-}
-
-impl std::error::Error for DecodeError {}
-
-impl<'a> FromSql<'a> for &'a str {
-    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
-        require_text_compatible(value, "&str")
-    }
-
-    fn from_sql(value: ValueRef<'a>) -> std::result::Result {
-        Self::check_type(value)?;
-        let raw = value.require_bytes("&str")?;
-        str::from_utf8(raw).map_err(|error| DecodeError::InvalidValue {
-            column: value.column,
-            target: "&str",
-            message: error.to_string(),
-        })
-    }
-}
-
-impl FromSql<'_> for String {
-    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
-        <&str as FromSql>::check_type(value)
-    }
-
-    fn from_sql(value: ValueRef<'_>) -> std::result::Result {
-        <&str as FromSql>::from_sql(value).map(str::to_owned)
-    }
-}
-
-impl<'a> FromSql<'a> for &'a [u8] {
-    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
-        require_type(value, TypeOid::BYTEA, "&[u8]")?;
-        if value.format() == Some(ValueFormat::Binary) {
-            Ok(())
-        } else {
-            invalid_value(
-                value,
-                "&[u8]",
-                "borrowed bytea requires binary result format; use Vec for text bytea",
-            )
-        }
-    }
-
-    fn from_sql(value: ValueRef<'a>) -> std::result::Result {
-        Self::check_type(value)?;
-        value.require_bytes("&[u8]")
-    }
-}
-
-impl FromSql<'_> for Vec {
-    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
-        require_type(value, TypeOid::BYTEA, "Vec")
-    }
-
-    fn from_sql(value: ValueRef<'_>) -> std::result::Result {
-        Self::check_type(value)?;
-        let raw = value.require_bytes("Vec")?;
-        match value.format() {
-            Some(ValueFormat::Binary) => Ok(raw.to_vec()),
-            Some(ValueFormat::Text) => decode_text_bytea(value, raw),
-            None => unsupported_format(value),
-        }
-    }
-}
-
-impl FromSql<'_> for bool {
-    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
-        require_type(value, TypeOid::BOOL, "bool")
-    }
-
-    fn from_sql(value: ValueRef<'_>) -> std::result::Result {
-        Self::check_type(value)?;
-        let raw = value.require_bytes("bool")?;
-        match value.format() {
-            Some(ValueFormat::Text) => match raw {
-                b"t" | b"true" => Ok(true),
-                b"f" | b"false" => Ok(false),
-                _ => invalid_value(value, "bool", "expected t or f"),
-            },
-            Some(ValueFormat::Binary) => match raw {
-                [0] => Ok(false),
-                [1] => Ok(true),
-                _ => invalid_value(value, "bool", "expected one binary byte containing 0 or 1"),
-            },
-            None => unsupported_format(value),
-        }
-    }
-}
-
-macro_rules! integer_from_sql {
-    ($type:ty, $oid:expr, $width:literal) => {
-        impl FromSql<'_> for $type {
-            fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
-                require_type(value, $oid, stringify!($type))
-            }
-
-            fn from_sql(value: ValueRef<'_>) -> std::result::Result {
-                Self::check_type(value)?;
-                let raw = value.require_bytes(stringify!($type))?;
-                match value.format() {
-                    Some(ValueFormat::Text) => {
-                        let text =
-                            str::from_utf8(raw).map_err(|error| DecodeError::InvalidValue {
-                                column: value.column,
-                                target: stringify!($type),
-                                message: error.to_string(),
-                            })?;
-                        text.parse::<$type>()
-                            .map_err(|error| DecodeError::InvalidValue {
-                                column: value.column,
-                                target: stringify!($type),
-                                message: error.to_string(),
-                            })
-                    }
-                    Some(ValueFormat::Binary) => {
-                        let bytes: [u8; $width] =
-                            raw.try_into().map_err(|_| DecodeError::InvalidValue {
-                                column: value.column,
-                                target: stringify!($type),
-                                message: format!(
-                                    "expected {} binary bytes, got {}",
-                                    $width,
-                                    raw.len()
-                                ),
-                            })?;
-                        Ok(<$type>::from_be_bytes(bytes))
-                    }
-                    None => unsupported_format(value),
-                }
-            }
-        }
-    };
-}
-
-integer_from_sql!(i16, TypeOid::INT2, 2);
-integer_from_sql!(i32, TypeOid::INT4, 4);
-integer_from_sql!(i64, TypeOid::INT8, 8);
-
-macro_rules! float_from_sql {
-    ($type:ty, $bits:ty, $oid:expr, $width:literal) => {
-        impl FromSql<'_> for $type {
-            fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
-                require_type(value, $oid, stringify!($type))
-            }
-
-            fn from_sql(value: ValueRef<'_>) -> std::result::Result {
-                Self::check_type(value)?;
-                let raw = value.require_bytes(stringify!($type))?;
-                match value.format() {
-                    Some(ValueFormat::Text) => {
-                        let text =
-                            str::from_utf8(raw).map_err(|error| DecodeError::InvalidValue {
-                                column: value.column,
-                                target: stringify!($type),
-                                message: error.to_string(),
-                            })?;
-                        text.parse::<$type>()
-                            .map_err(|error| DecodeError::InvalidValue {
-                                column: value.column,
-                                target: stringify!($type),
-                                message: error.to_string(),
-                            })
-                    }
-                    Some(ValueFormat::Binary) => {
-                        let bytes: [u8; $width] =
-                            raw.try_into().map_err(|_| DecodeError::InvalidValue {
-                                column: value.column,
-                                target: stringify!($type),
-                                message: format!(
-                                    "expected {} binary bytes, got {}",
-                                    $width,
-                                    raw.len()
-                                ),
-                            })?;
-                        Ok(<$type>::from_bits(<$bits>::from_be_bytes(bytes)))
-                    }
-                    None => unsupported_format(value),
-                }
-            }
-        }
-    };
-}
-
-float_from_sql!(f32, u32, TypeOid::FLOAT4, 4);
-float_from_sql!(f64, u64, TypeOid::FLOAT8, 8);
-
-impl<'a, T> FromSql<'a> for Option
-where
-    T: FromSql<'a>,
-{
-    fn check_type(value: ValueRef<'_>) -> std::result::Result<(), DecodeError> {
-        T::check_type(value)
-    }
-
-    fn from_sql(value: ValueRef<'a>) -> std::result::Result {
-        T::check_type(value)?;
-        if value.is_null() {
-            Ok(None)
-        } else {
-            T::from_sql(value).map(Some)
-        }
-    }
-}
-
-fn require_type(
-    value: ValueRef<'_>,
-    expected: TypeOid,
-    target: &'static str,
-) -> std::result::Result<(), DecodeError> {
-    if value.type_oid() == expected {
-        Ok(())
-    } else {
-        Err(DecodeError::TypeMismatch {
-            column: value.column,
-            type_oid: value.type_oid(),
-            target,
-        })
-    }
-}
-
-fn require_text_compatible(
-    value: ValueRef<'_>,
-    target: &'static str,
-) -> std::result::Result<(), DecodeError> {
-    if value.format() != Some(ValueFormat::Text) {
-        return invalid_value(
-            value,
-            target,
-            "string decoding requires PostgreSQL text format",
-        );
-    }
-    let oid = value.type_oid();
-    if matches!(
-        oid,
-        TypeOid::CHAR
-            | TypeOid::NAME
-            | TypeOid::TEXT
-            | TypeOid::UNKNOWN
-            | TypeOid::BPCHAR
-            | TypeOid::VARCHAR
-            | TypeOid::JSON
-            | TypeOid::JSONB
-            | TypeOid::XML
-            | TypeOid::NUMERIC
-            | TypeOid::DATE
-            | TypeOid::TIME
-            | TypeOid::TIMETZ
-            | TypeOid::TIMESTAMP
-            | TypeOid::TIMESTAMPTZ
-            | TypeOid::INTERVAL
-            | TypeOid::UUID
-    ) || oid.get() >= 16_384
-    {
-        Ok(())
-    } else {
-        Err(DecodeError::TypeMismatch {
-            column: value.column,
-            type_oid: oid,
-            target,
-        })
-    }
-}
-
-fn decode_text_bytea(value: ValueRef<'_>, raw: &[u8]) -> std::result::Result, DecodeError> {
-    if let Some(hex) = raw.strip_prefix(b"\\x") {
-        if hex.len() % 2 != 0 {
-            return invalid_value(value, "Vec", "hex bytea has odd length");
-        }
-        return hex
-            .chunks_exact(2)
-            .map(|pair| {
-                let digit = |byte: u8| match byte {
-                    b'0'..=b'9' => Some(byte - b'0'),
-                    b'a'..=b'f' => Some(byte - b'a' + 10),
-                    b'A'..=b'F' => Some(byte - b'A' + 10),
-                    _ => None,
-                };
-                let high = digit(pair[0]).ok_or_else(|| DecodeError::InvalidValue {
-                    column: value.column,
-                    target: "Vec",
-                    message: "hex bytea contains a non-hex digit".to_owned(),
-                })?;
-                let low = digit(pair[1]).ok_or_else(|| DecodeError::InvalidValue {
-                    column: value.column,
-                    target: "Vec",
-                    message: "hex bytea contains a non-hex digit".to_owned(),
-                })?;
-                Ok((high << 4) | low)
-            })
-            .collect();
-    }
-
-    let mut decoded = Vec::with_capacity(raw.len());
-    let mut index = 0;
-    while index < raw.len() {
-        if raw[index] != b'\\' {
-            decoded.push(raw[index]);
-            index += 1;
-            continue;
-        }
-        match raw.get(index + 1..) {
-            Some([b'\\', ..]) => {
-                decoded.push(b'\\');
-                index += 2;
-            }
-            Some([a @ b'0'..=b'3', b @ b'0'..=b'7', c @ b'0'..=b'7', ..]) => {
-                decoded.push((a - b'0') * 64 + (b - b'0') * 8 + (c - b'0'));
-                index += 4;
-            }
-            _ => return invalid_value(value, "Vec", "invalid escaped bytea sequence"),
-        }
-    }
-    Ok(decoded)
-}
-
-fn invalid_value(
-    value: ValueRef<'_>,
-    target: &'static str,
-    message: impl Into,
-) -> std::result::Result {
-    Err(DecodeError::InvalidValue {
-        column: value.column,
-        target,
-        message: message.into(),
-    })
-}
-
-fn unsupported_format(value: ValueRef<'_>) -> std::result::Result {
-    let QueryFormat::Other(format) = value.field.format else {
-        unreachable!("known formats are handled before unsupported_format")
-    };
-    Err(DecodeError::UnsupportedFormat {
-        column: value.column,
-        format,
-    })
-}
-
-/// One raw field from a PostgreSQL ErrorResponse.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct PostgresErrorField {
-    /// Single-byte PostgreSQL field code.
-    pub code: u8,
-    /// Field value decoded as UTF-8.
-    pub value: String,
-}
-
-/// Structured PostgreSQL NoticeResponse diagnostic.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct PostgresNotice {
-    /// Backend severity, such as NOTICE or WARNING.
-    pub severity: Option,
-    /// Localized severity reported in PostgreSQL field S.
-    pub localized_severity: Option,
-    /// Locale-independent severity reported in PostgreSQL field V.
-    pub nonlocalized_severity: Option,
-    /// SQLSTATE code when PostgreSQL supplied one.
-    pub sqlstate: Option,
-    /// Primary human-readable notice message.
-    pub message: String,
-    /// Optional detailed explanation.
-    pub detail: Option,
-    /// Optional hint.
-    pub hint: Option,
-    /// Optional source statement position.
-    pub position: Option,
-    /// Optional position within an internally generated query.
-    pub internal_position: Option,
-    /// Optional text of an internally generated query.
-    pub internal_query: Option,
-    /// Optional context stack.
-    pub where_: Option,
-    /// Optional schema name.
-    pub schema_name: Option,
-    /// Optional table name.
-    pub table_name: Option,
-    /// Optional column name.
-    pub column_name: Option,
-    /// Optional data type name.
-    pub data_type_name: Option,
-    /// Optional constraint name.
-    pub constraint_name: Option,
-    /// PostgreSQL source file that emitted the diagnostic.
-    pub file: Option,
-    /// PostgreSQL source line that emitted the diagnostic.
-    pub line: Option,
-    /// PostgreSQL source routine that emitted the diagnostic.
-    pub routine: Option,
-    /// Raw diagnostic fields in backend order.
-    pub fields: Vec,
-}
-
-/// Structured PostgreSQL ErrorResponse decoded from backend protocol bytes.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct PostgresError {
-    /// Backend severity, such as ERROR or FATAL.
-    pub severity: Option,
-    /// Localized severity reported in PostgreSQL field S.
-    pub localized_severity: Option,
-    /// Locale-independent severity reported in PostgreSQL field V.
-    pub nonlocalized_severity: Option,
-    /// SQLSTATE code, such as 23505 for unique violations.
-    pub sqlstate: Option,
-    /// Primary human-readable PostgreSQL error message.
-    pub message: String,
-    /// Optional detailed explanation from PostgreSQL.
-    pub detail: Option,
-    /// Optional hint from PostgreSQL.
-    pub hint: Option,
-    /// Optional source statement position.
-    pub position: Option,
-    /// Optional position within an internally generated query.
-    pub internal_position: Option,
-    /// Optional text of an internally generated query.
-    pub internal_query: Option,
-    /// Optional context stack, exposed as where by PostgreSQL.
-    pub where_: Option,
-    /// Optional schema name reported by PostgreSQL.
-    pub schema_name: Option,
-    /// Optional table name reported by PostgreSQL.
-    pub table_name: Option,
-    /// Optional column name reported by PostgreSQL.
-    pub column_name: Option,
-    /// Optional data type name reported by PostgreSQL.
-    pub data_type_name: Option,
-    /// Optional constraint name reported by PostgreSQL.
-    pub constraint_name: Option,
-    /// PostgreSQL source file that emitted the diagnostic.
-    pub file: Option,
-    /// PostgreSQL source line that emitted the diagnostic.
-    pub line: Option,
-    /// PostgreSQL source routine that emitted the diagnostic.
-    pub routine: Option,
-    /// Raw ErrorResponse fields in backend order.
-    pub fields: Vec,
-    /// Notices emitted earlier in the same structured operation.
-    pub notices: Vec,
-}
-
-impl fmt::Display for PostgresError {
-    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match (&self.severity, &self.sqlstate) {
-            (Some(severity), Some(sqlstate)) => {
-                write!(formatter, "{severity} [{sqlstate}]: {}", self.message)
-            }
-            (Some(severity), None) => write!(formatter, "{severity}: {}", self.message),
-            (None, Some(sqlstate)) => write!(formatter, "[{sqlstate}]: {}", self.message),
-            (None, None) => formatter.write_str(&self.message),
-        }
-    }
-}
-
-impl std::error::Error for PostgresError {}
-
-/// One PostgreSQL query row.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct QueryRow {
-    pub(crate) fields: Arc<[QueryField]>,
-    pub(crate) values: Vec>>,
-}
-
-impl QueryRow {
-    pub(crate) fn new(fields: Arc<[QueryField]>, values: Vec>>) -> Self {
-        Self { fields, values }
-    }
-
-    /// Field metadata in column order.
-    pub fn fields(&self) -> &[QueryField] {
-        &self.fields
-    }
-
-    /// Raw column values in result-column order.
-    pub fn values(&self) -> &[Option>] {
-        &self.values
-    }
-
-    /// Number of columns in the row.
-    pub fn len(&self) -> usize {
-        self.values.len()
-    }
-
-    /// Whether the row contains no columns.
-    pub fn is_empty(&self) -> bool {
-        self.values.is_empty()
-    }
-
-    /// Read nullable raw wire bytes by column index or name.
-    pub fn try_get_raw(&self, index: I) -> std::result::Result, DecodeError>
-    where
-        I: RowIndex,
-    {
-        let index = index.resolve(&self.fields)?;
-        Ok(self.values[index].as_deref())
-    }
-
-    /// Decode a value by column index or name.
-    pub fn try_get<'a, T, I>(&'a self, index: I) -> std::result::Result
-    where
-        T: FromSql<'a>,
-        I: RowIndex,
-    {
-        let index = index.resolve(&self.fields)?;
-        T::from_sql(ValueRef::new(
-            index,
-            &self.fields[index],
-            self.values[index].as_deref(),
-        ))
-    }
-
-    pub(crate) fn value(&self, column: usize) -> Option<&Option>> {
-        self.values.get(column)
-    }
-}
-
-/// Result of a PostgreSQL command that does not expose rows.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct CommandResult {
-    pub(crate) command_tag: Option,
-    pub(crate) row_count: Option,
-    pub(crate) notices: Vec,
-    pub(crate) ready_status: ReadyStatus,
-}
-
-impl CommandResult {
-    /// PostgreSQL command tag returned by the command.
-    pub fn command_tag(&self) -> Option<&str> {
-        self.command_tag.as_deref()
-    }
-
-    /// Affected-row count encoded by PostgreSQL in the command tag.
-    pub fn row_count(&self) -> Option {
-        self.row_count
-    }
-
-    /// Notices emitted while PostgreSQL processed this command.
-    pub fn notices(&self) -> &[PostgresNotice] {
-        &self.notices
-    }
-
-    pub(crate) fn ready_status(&self) -> ReadyStatus {
-        self.ready_status
-    }
-}
-
-/// Result of one PostgreSQL row-producing execution.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct QueryResult {
-    pub(crate) fields: Arc<[QueryField]>,
-    pub(crate) rows: Vec,
-    pub(crate) command_tag: Option,
-    pub(crate) row_count: Option,
-    pub(crate) notices: Vec,
-    pub(crate) ready_status: ReadyStatus,
-}
-
-impl QueryResult {
-    /// Field metadata in result-column order.
-    pub fn fields(&self) -> &[QueryField] {
-        &self.fields
-    }
-
-    /// Rows returned by the query.
-    pub fn rows(&self) -> &[QueryRow] {
-        &self.rows
-    }
-
-    /// PostgreSQL command tag returned by the query.
-    pub fn command_tag(&self) -> Option<&str> {
-        self.command_tag.as_deref()
-    }
-
-    /// Row count encoded by PostgreSQL in the command tag.
-    pub fn row_count(&self) -> Option {
-        self.row_count
-    }
-
-    /// Notices emitted while PostgreSQL processed this query.
-    pub fn notices(&self) -> &[PostgresNotice] {
-        &self.notices
-    }
-
-    pub(crate) fn ready_status(&self) -> ReadyStatus {
-        self.ready_status
-    }
-
-    pub(crate) fn row(&self, index: usize) -> Option<&QueryRow> {
-        self.rows.get(index)
-    }
-}
-
-/// Metadata returned by PostgreSQL for a parsed statement.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct StatementDescription {
-    pub(crate) parameter_types: Vec,
-    pub(crate) fields: Option>,
-    pub(crate) notices: Vec,
-    pub(crate) ready_status: ReadyStatus,
-}
-
-impl StatementDescription {
-    /// Server-resolved parameter type OIDs in placeholder order.
-    pub fn parameter_types(&self) -> &[TypeOid] {
-        &self.parameter_types
-    }
-
-    /// Result fields, or None when PostgreSQL returned NoData.
-    pub fn fields(&self) -> Option<&[QueryField]> {
-        self.fields.as_deref()
-    }
-
-    /// Notices emitted while PostgreSQL parsed and described the statement.
-    pub fn notices(&self) -> &[PostgresNotice] {
-        &self.notices
-    }
-
-    pub(crate) fn ready_status(&self) -> ReadyStatus {
-        self.ready_status
-    }
-}
-
-/// One ordered result from PostgreSQL simple-query execution.
-#[non_exhaustive]
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum StatementResult {
-    /// A command that did not return rows.
-    Command(CommandResult),
-    /// A row-producing statement.
-    Rows(QueryResult),
-}
-
-/// Ordered results from PostgreSQL simple-query execution.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct ExecResult {
-    pub(crate) statements: Vec,
-    pub(crate) notices: Vec,
-    pub(crate) ready_status: ReadyStatus,
-}
-
-impl ExecResult {
-    /// Results in source-statement order.
-    pub fn statements(&self) -> &[StatementResult] {
-        &self.statements
-    }
-
-    /// Notices emitted while PostgreSQL executed the input.
-    pub fn notices(&self) -> &[PostgresNotice] {
-        &self.notices
-    }
-
-    pub(crate) fn ready_status(&self) -> ReadyStatus {
-        self.ready_status
-    }
-}
-
-pub(crate) type Result = std::result::Result;
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) enum Error {
-    Protocol(String),
-    Postgres {
-        diagnostic: Box,
-        notices: Vec,
-    },
-}
-
-fn protocol(message: impl Into) -> Error {
-    Error::Protocol(message.into())
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) struct DiagnosticField {
-    pub code: u8,
-    pub value: String,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) struct Diagnostic {
-    pub severity: Option,
-    pub localized_severity: Option,
-    pub nonlocalized_severity: Option,
-    pub sqlstate: Option,
-    pub message: String,
-    pub detail: Option,
-    pub hint: Option,
-    pub position: Option,
-    pub internal_position: Option,
-    pub internal_query: Option,
-    pub where_: Option,
-    pub schema_name: Option,
-    pub table_name: Option,
-    pub column_name: Option,
-    pub data_type_name: Option,
-    pub constraint_name: Option,
-    pub file: Option,
-    pub line: Option,
-    pub routine: Option,
-    pub fields: Vec,
-}
-
-pub(crate) fn diagnostic(fields: Vec, fallback_message: &str) -> Diagnostic {
-    let localized_severity = diagnostic_field_value(&fields, b'S');
-    let nonlocalized_severity = diagnostic_field_value(&fields, b'V');
-    Diagnostic {
-        severity: localized_severity
-            .clone()
-            .or_else(|| nonlocalized_severity.clone()),
-        localized_severity,
-        nonlocalized_severity,
-        sqlstate: diagnostic_field_value(&fields, b'C'),
-        message: diagnostic_field_value(&fields, b'M')
-            .unwrap_or_else(|| fallback_message.to_owned()),
-        detail: diagnostic_field_value(&fields, b'D'),
-        hint: diagnostic_field_value(&fields, b'H'),
-        position: diagnostic_field_value(&fields, b'P'),
-        internal_position: diagnostic_field_value(&fields, b'p'),
-        internal_query: diagnostic_field_value(&fields, b'q'),
-        where_: diagnostic_field_value(&fields, b'W'),
-        schema_name: diagnostic_field_value(&fields, b's'),
-        table_name: diagnostic_field_value(&fields, b't'),
-        column_name: diagnostic_field_value(&fields, b'c'),
-        data_type_name: diagnostic_field_value(&fields, b'd'),
-        constraint_name: diagnostic_field_value(&fields, b'n'),
-        file: diagnostic_field_value(&fields, b'F'),
-        line: diagnostic_field_value(&fields, b'L'),
-        routine: diagnostic_field_value(&fields, b'R'),
-        fields,
-    }
-}
-
-fn diagnostic_field_value(fields: &[DiagnosticField], code: u8) -> Option {
-    fields
-        .iter()
-        .find(|field| field.code == code)
-        .map(|field| field.value.clone())
-}
-
-impl PostgresError {
-    pub(crate) fn from_core(diagnostic: Diagnostic) -> Self {
-        Self {
-            severity: diagnostic.severity,
-            localized_severity: diagnostic.localized_severity,
-            nonlocalized_severity: diagnostic.nonlocalized_severity,
-            sqlstate: diagnostic.sqlstate,
-            message: diagnostic.message,
-            detail: diagnostic.detail,
-            hint: diagnostic.hint,
-            position: diagnostic.position,
-            internal_position: diagnostic.internal_position,
-            internal_query: diagnostic.internal_query,
-            where_: diagnostic.where_,
-            schema_name: diagnostic.schema_name,
-            table_name: diagnostic.table_name,
-            column_name: diagnostic.column_name,
-            data_type_name: diagnostic.data_type_name,
-            constraint_name: diagnostic.constraint_name,
-            file: diagnostic.file,
-            line: diagnostic.line,
-            routine: diagnostic.routine,
-            fields: diagnostic_fields_from_core(diagnostic.fields),
-            notices: Vec::new(),
-        }
-    }
-}
-
-impl PostgresNotice {
-    pub(crate) fn from_core(diagnostic: Diagnostic) -> Self {
-        Self {
-            severity: diagnostic.severity,
-            localized_severity: diagnostic.localized_severity,
-            nonlocalized_severity: diagnostic.nonlocalized_severity,
-            sqlstate: diagnostic.sqlstate,
-            message: diagnostic.message,
-            detail: diagnostic.detail,
-            hint: diagnostic.hint,
-            position: diagnostic.position,
-            internal_position: diagnostic.internal_position,
-            internal_query: diagnostic.internal_query,
-            where_: diagnostic.where_,
-            schema_name: diagnostic.schema_name,
-            table_name: diagnostic.table_name,
-            column_name: diagnostic.column_name,
-            data_type_name: diagnostic.data_type_name,
-            constraint_name: diagnostic.constraint_name,
-            file: diagnostic.file,
-            line: diagnostic.line,
-            routine: diagnostic.routine,
-            fields: diagnostic_fields_from_core(diagnostic.fields),
-        }
-    }
-}
-
-fn diagnostic_fields_from_core(fields: Vec) -> Vec {
-    fields
-        .into_iter()
-        .map(|field| PostgresErrorField {
-            code: field.code,
-            value: field.value,
-        })
-        .collect()
-}
-
-pub(crate) fn parse_diagnostic_fields(
-    mut body: &[u8],
-    label: &str,
-) -> Result> {
-    let mut fields = Vec::new();
-    loop {
-        let Some((&code, rest)) = body.split_first() else {
-            return Err(protocol(format!("{label} is missing terminator")));
-        };
-        body = rest;
-        if code == 0 {
-            if body.is_empty() {
-                return Ok(fields);
-            }
-            return Err(protocol(format!("{label} contained trailing bytes")));
-        }
-        fields.push(DiagnosticField {
-            code,
-            value: read_cstring(&mut body, &format!("{label} field"))?.to_owned(),
-        });
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum ReadyStatus {
-    Idle,
-    InTransaction,
-    FailedTransaction,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub(crate) enum ExpectedProtocol {
-    #[cfg(test)]
-    Either,
-    Simple,
-    Extended,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) struct Row {
-    pub values: Vec>>,
-}
-
-pub(crate) fn simple_query(sql: &str) -> Result> {
-    if sql.as_bytes().contains(&0) {
-        return Err(protocol("simple query SQL must not contain NUL bytes"));
-    }
-    let mut body = Vec::with_capacity(sql.len() + 1);
-    body.extend_from_slice(sql.as_bytes());
-    body.push(0);
-    let mut packet = Vec::with_capacity(body.len() + 5);
-    push_frontend_message(&mut packet, b'Q', &body)?;
-    Ok(packet)
-}
-
-pub(crate) fn extended_statement(
-    sql: &str,
-    params: &[Parameter],
-    result_format_code: i16,
-) -> Result> {
-    reject_copy_statements(sql)?;
-    validate_statement_input(sql, params.len())?;
-    validate_execution_parameters(params)?;
-    let mut packet = Vec::new();
-    push_parse(&mut packet, sql, params)?;
-    push_bind(&mut packet, params, result_format_code)?;
-    push_frontend_message(&mut packet, b'D', &[b'P', 0])?;
-    push_frontend_message(&mut packet, b'E', &[0, 0, 0, 0, 0])?;
-    push_frontend_message(&mut packet, b'S', &[])?;
-    Ok(packet)
-}
-
-pub(crate) fn describe_statement(sql: &str, params: &[Parameter]) -> Result> {
-    validate_statement_input(sql, params.len())?;
-    let mut packet = Vec::new();
-    push_parse(&mut packet, sql, params)?;
-    push_frontend_message(&mut packet, b'D', &[b'S', 0])?;
-    push_frontend_message(&mut packet, b'S', &[])?;
-    Ok(packet)
-}
-
-fn validate_statement_input(sql: &str, parameter_count: usize) -> Result<()> {
-    if sql.as_bytes().contains(&0) {
-        return Err(protocol("extended query SQL must not contain NUL bytes"));
-    }
-    if parameter_count > i16::MAX as usize {
-        return Err(protocol(format!(
-            "extended query supports at most {} parameters, got {parameter_count}",
-            i16::MAX
-        )));
-    }
-    Ok(())
-}
-
-fn validate_execution_parameters(params: &[Parameter]) -> Result<()> {
-    if let Some(index) = params
-        .iter()
-        .position(|parameter| parameter.type_oid().is_some_and(|oid| oid.get() == 0))
-    {
-        return Err(protocol(format!(
-            "execution parameter {index} explicitly declares PostgreSQL type OID 0; omit the type OID to request server inference"
-        )));
-    }
-    Ok(())
-}
-
-fn push_parse(out: &mut Vec, sql: &str, params: &[Parameter]) -> Result<()> {
-    let mut body = Vec::new();
-    push_cstring(&mut body, "")?;
-    push_cstring(&mut body, sql)?;
-    body.extend_from_slice(&(params.len() as i16).to_be_bytes());
-    for parameter in params {
-        body.extend_from_slice(
-            ¶meter
-                .type_oid()
-                .map(TypeOid::get)
-                .unwrap_or_default()
-                .to_be_bytes(),
-        );
-    }
-    push_frontend_message(out, b'P', &body)
-}
-
-fn push_bind(out: &mut Vec, params: &[Parameter], result_format_code: i16) -> Result<()> {
-    let mut body = Vec::new();
-    push_cstring(&mut body, "")?;
-    push_cstring(&mut body, "")?;
-    body.extend_from_slice(&(params.len() as i16).to_be_bytes());
-    for parameter in params {
-        body.extend_from_slice(¶meter.format().code().to_be_bytes());
-    }
-    body.extend_from_slice(&(params.len() as i16).to_be_bytes());
-    for parameter in params {
-        match parameter.value() {
-            None => body.extend_from_slice(&(-1_i32).to_be_bytes()),
-            Some(value) => push_sized_value(&mut body, value)?,
-        }
-    }
-    body.extend_from_slice(&1_i16.to_be_bytes());
-    body.extend_from_slice(&result_format_code.to_be_bytes());
-    push_frontend_message(out, b'B', &body)
-}
-
-fn push_frontend_message(out: &mut Vec, tag: u8, body: &[u8]) -> Result<()> {
-    let len = i32::try_from(body.len() + 4)
-        .map_err(|_| protocol("frontend protocol message is too large"))?;
-    out.push(tag);
-    out.extend_from_slice(&len.to_be_bytes());
-    out.extend_from_slice(body);
-    Ok(())
-}
-
-fn push_cstring(out: &mut Vec, value: &str) -> Result<()> {
-    if value.as_bytes().contains(&0) {
-        return Err(protocol(
-            "frontend protocol string must not contain NUL bytes",
-        ));
-    }
-    out.extend_from_slice(value.as_bytes());
-    out.push(0);
-    Ok(())
-}
-
-fn push_sized_value(out: &mut Vec, value: &[u8]) -> Result<()> {
-    let len = i32::try_from(value.len()).map_err(|_| protocol("query parameter is too large"))?;
-    out.extend_from_slice(&len.to_be_bytes());
-    out.extend_from_slice(value);
-    Ok(())
-}
-
-pub(crate) fn reject_copy_statements(sql: &str) -> Result<()> {
-    if contains_top_level_copy(sql, false) || contains_top_level_copy(sql, true) {
-        return Err(protocol(
-            "COPY is not supported by buffered SQL APIs; use exec_protocol_raw or exec_protocol_raw_stream with a complete COPY protocol flow",
-        ));
-    }
-    Ok(())
-}
-
-pub(crate) fn reject_transaction_chain(sql: &str) -> Result<()> {
-    if contains_transaction_chain(sql, false) || contains_transaction_chain(sql, true) {
-        return Err(protocol(
-            "ROLLBACK ... AND CHAIN and ABORT ... AND CHAIN are not allowed inside an SDK-managed callback transaction; roll back through the transaction handle and start a new transaction explicitly",
-        ));
-    }
-    Ok(())
-}
-
-fn contains_top_level_copy(sql: &str, ordinary_backslash_escapes: bool) -> bool {
-    let mut statement_start = true;
-    for token in TopLevelSqlTokens::new(sql, ordinary_backslash_escapes) {
-        match token {
-            TopLevelSqlToken::StatementBoundary => statement_start = true,
-            TopLevelSqlToken::Word(word) => {
-                if statement_start && word.eq_ignore_ascii_case(b"COPY") {
-                    return true;
-                }
-                statement_start = false;
-            }
-            TopLevelSqlToken::Other => statement_start = false,
-        }
-    }
-    false
-}
-
-#[derive(Clone, Copy)]
-enum TransactionChainState {
-    StatementStart,
-    AfterControl,
-    AfterQualifier,
-    AfterAnd,
-    Ineligible,
-}
-
-fn contains_transaction_chain(sql: &str, ordinary_backslash_escapes: bool) -> bool {
-    let mut state = TransactionChainState::StatementStart;
-    for token in TopLevelSqlTokens::new(sql, ordinary_backslash_escapes) {
-        state = match token {
-            TopLevelSqlToken::StatementBoundary => TransactionChainState::StatementStart,
-            TopLevelSqlToken::Other => TransactionChainState::Ineligible,
-            TopLevelSqlToken::Word(word) => match state {
-                TransactionChainState::StatementStart
-                    if word.eq_ignore_ascii_case(b"ROLLBACK")
-                        || word.eq_ignore_ascii_case(b"ABORT") =>
-                {
-                    TransactionChainState::AfterControl
-                }
-                TransactionChainState::AfterControl
-                    if word.eq_ignore_ascii_case(b"WORK")
-                        || word.eq_ignore_ascii_case(b"TRANSACTION") =>
-                {
-                    TransactionChainState::AfterQualifier
-                }
-                TransactionChainState::AfterControl | TransactionChainState::AfterQualifier
-                    if word.eq_ignore_ascii_case(b"AND") =>
-                {
-                    TransactionChainState::AfterAnd
-                }
-                TransactionChainState::AfterAnd if word.eq_ignore_ascii_case(b"CHAIN") => {
-                    return true;
-                }
-                _ => TransactionChainState::Ineligible,
-            },
-        };
-    }
-    false
-}
-
-#[derive(Clone, Copy)]
-enum TopLevelSqlToken<'a> {
-    StatementBoundary,
-    Word(&'a [u8]),
-    Other,
-}
-
-struct TopLevelSqlTokens<'a> {
-    bytes: &'a [u8],
-    index: usize,
-    depth: usize,
-    ordinary_backslash_escapes: bool,
-}
-
-impl<'a> TopLevelSqlTokens<'a> {
-    fn new(sql: &'a str, ordinary_backslash_escapes: bool) -> Self {
-        Self {
-            bytes: sql.as_bytes(),
-            index: 0,
-            depth: 0,
-            ordinary_backslash_escapes,
-        }
-    }
-}
-
-impl<'a> Iterator for TopLevelSqlTokens<'a> {
-    type Item = TopLevelSqlToken<'a>;
-
-    fn next(&mut self) -> Option {
-        while self.index < self.bytes.len() {
-            match self.bytes[self.index] {
-                byte if byte.is_ascii_whitespace() => self.index += 1,
-                b'-' if self.bytes.get(self.index + 1) == Some(&b'-') => {
-                    self.index += 2;
-                    while self.index < self.bytes.len()
-                        && !matches!(self.bytes[self.index], b'\n' | b'\r')
-                    {
-                        self.index += 1;
-                    }
-                }
-                b'/' if self.bytes.get(self.index + 1) == Some(&b'*') => {
-                    self.index = skip_block_comment(self.bytes, self.index);
-                }
-                b'\'' => {
-                    let top_level = self.depth == 0;
-                    self.index = skip_quoted(
-                        self.bytes,
-                        self.index,
-                        b'\'',
-                        self.ordinary_backslash_escapes,
-                    );
-                    if top_level {
-                        return Some(TopLevelSqlToken::Other);
-                    }
-                }
-                b'"' => {
-                    let top_level = self.depth == 0;
-                    self.index = skip_quoted(self.bytes, self.index, b'"', false);
-                    if top_level {
-                        return Some(TopLevelSqlToken::Other);
-                    }
-                }
-                b'$' if dollar_quote_delimiter(self.bytes, self.index).is_some() => {
-                    let top_level = self.depth == 0;
-                    self.index = skip_dollar_quote(self.bytes, self.index);
-                    if top_level {
-                        return Some(TopLevelSqlToken::Other);
-                    }
-                }
-                b'(' => {
-                    let top_level = self.depth == 0;
-                    self.depth += 1;
-                    self.index += 1;
-                    if top_level {
-                        return Some(TopLevelSqlToken::Other);
-                    }
-                }
-                b')' if self.depth > 0 => {
-                    self.depth -= 1;
-                    self.index += 1;
-                }
-                b';' if self.depth == 0 => {
-                    self.index += 1;
-                    return Some(TopLevelSqlToken::StatementBoundary);
-                }
-                byte if is_postgres_identifier_start(byte) => {
-                    let start = self.index;
-                    self.index += 1;
-                    while self
-                        .bytes
-                        .get(self.index)
-                        .is_some_and(|byte| is_postgres_identifier_continuation(*byte))
-                    {
-                        self.index += 1;
-                    }
-                    let word = &self.bytes[start..self.index];
-                    if word.eq_ignore_ascii_case(b"E") && self.bytes.get(self.index) == Some(&b'\'')
-                    {
-                        self.index = skip_quoted(self.bytes, self.index, b'\'', true);
-                        if self.depth == 0 {
-                            return Some(TopLevelSqlToken::Other);
-                        }
-                    } else if self.depth == 0 {
-                        return Some(TopLevelSqlToken::Word(word));
-                    }
-                }
-                _ => {
-                    self.index += 1;
-                    if self.depth == 0 {
-                        return Some(TopLevelSqlToken::Other);
-                    }
-                }
-            }
-        }
-        None
-    }
-}
-
-fn skip_quoted(bytes: &[u8], mut index: usize, quote: u8, backslash_escapes: bool) -> usize {
-    index += 1;
-    while index < bytes.len() {
-        if bytes[index] == quote {
-            if bytes.get(index + 1) == Some("e) {
-                index += 2;
-                continue;
-            }
-            return index + 1;
-        }
-        if backslash_escapes && bytes[index] == b'\\' && index + 1 < bytes.len() {
-            index += 2;
-        } else {
-            index += 1;
-        }
-    }
-    index
-}
-
-fn skip_block_comment(bytes: &[u8], mut index: usize) -> usize {
-    index += 2;
-    let mut depth = 1_usize;
-    while index < bytes.len() && depth > 0 {
-        if bytes.get(index..index + 2) == Some(b"/*") {
-            depth += 1;
-            index += 2;
-        } else if bytes.get(index..index + 2) == Some(b"*/") {
-            depth -= 1;
-            index += 2;
-        } else {
-            index += 1;
-        }
-    }
-    index
-}
-
-fn dollar_quote_delimiter(bytes: &[u8], index: usize) -> Option<&[u8]> {
-    if bytes.get(index) != Some(&b'$') {
-        return None;
-    }
-    let tail = &bytes[index + 1..];
-    let end = tail.iter().position(|byte| *byte == b'$')?;
-    let tag = &tail[..end];
-    (tag.is_empty()
-        || (is_postgres_identifier_start(tag[0])
-            && tag[1..]
-                .iter()
-                .all(|byte| is_postgres_identifier_continuation(*byte) && *byte != b'$')))
-    .then_some(&bytes[index..index + end + 2])
-}
-
-fn is_postgres_identifier_start(byte: u8) -> bool {
-    byte.is_ascii_alphabetic() || byte == b'_' || byte >= 0x80
-}
-
-fn is_postgres_identifier_continuation(byte: u8) -> bool {
-    is_postgres_identifier_start(byte) || byte.is_ascii_digit() || byte == b'$'
-}
-
-fn skip_dollar_quote(bytes: &[u8], index: usize) -> usize {
-    let Some(delimiter) = dollar_quote_delimiter(bytes, index) else {
-        return index + 1;
-    };
-    let content = index + delimiter.len();
-    bytes[content..]
-        .windows(delimiter.len())
-        .position(|window| window == delimiter)
-        .map_or(bytes.len(), |offset| content + offset + delimiter.len())
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum SingleStatementCompletion {
-    Command,
-    Empty,
-}
-
-pub(crate) fn parse_command_response(
-    bytes: &[u8],
-    expected_protocol: ExpectedProtocol,
-) -> Result {
-    let mut input = bytes;
-    let mut ready_status = None;
-    let mut command_tag = None;
-    let mut completion = None;
-    let mut saw_parse_complete = false;
-    let mut saw_bind_complete = false;
-    let mut saw_no_data = false;
-    let mut notices = Vec::new();
-    let mut postgres_error = None;
-
-    while !input.is_empty() {
-        let (tag, body, rest) = read_backend_message(input)?;
-        input = rest;
-        if expected_protocol == ExpectedProtocol::Simple && matches!(tag, b'1' | b'2' | b'n') {
-            return Err(protocol(format!(
-                "execute() simple-query response received extended-protocol message tag 0x{tag:02x}"
-            )));
-        }
-        if postgres_error.is_some() && !matches!(tag, b'N' | b'S' | b'A' | b'Z') {
-            return Err(protocol(format!(
-                "execute() received backend message 0x{tag:02x} after ErrorResponse"
-            )));
-        }
-        match tag {
-            b'E' => {
-                if completion.is_some() {
-                    return Err(protocol(
-                        "execute() received ErrorResponse after statement completion",
-                    ));
-                }
-                postgres_error = Some(parse_error_response(body)?);
-            }
-            b'C' => {
-                match completion {
-                    Some(SingleStatementCompletion::Command) => {
-                        return Err(protocol(
-                            "execute() received multiple CommandComplete messages",
-                        ));
-                    }
-                    Some(SingleStatementCompletion::Empty) => {
-                        return Err(protocol(
-                            "execute() received CommandComplete after EmptyQueryResponse",
-                        ));
-                    }
-                    None => {}
-                }
-                if saw_parse_complete != saw_bind_complete {
-                    return Err(protocol(
-                        "execute() received CommandComplete before the extended-query controls completed",
-                    ));
-                }
-                if saw_bind_complete && !saw_no_data {
-                    return Err(protocol("execute() received CommandComplete before NoData"));
-                }
-                command_tag = Some(parse_command_complete(body)?);
-                completion = Some(SingleStatementCompletion::Command);
-            }
-            b'Z' => {
-                ready_status = Some(parse_ready_for_query(body)?);
-                if !input.is_empty() {
-                    return Err(protocol("backend returned bytes after ReadyForQuery"));
-                }
-            }
-            b'1' => {
-                require_empty_backend_message(body, "ParseComplete")?;
-                if completion.is_some() || saw_parse_complete || saw_bind_complete || saw_no_data {
-                    return Err(protocol("execute() received ParseComplete out of order"));
-                }
-                saw_parse_complete = true;
-            }
-            b'2' => {
-                require_empty_backend_message(body, "BindComplete")?;
-                if completion.is_some() || !saw_parse_complete || saw_bind_complete || saw_no_data {
-                    return Err(protocol("execute() received BindComplete out of order"));
-                }
-                saw_bind_complete = true;
-            }
-            b'I' => {
-                require_empty_backend_message(body, "EmptyQueryResponse")?;
-                match completion {
-                    Some(SingleStatementCompletion::Command) => {
-                        return Err(protocol(
-                            "execute() received EmptyQueryResponse after CommandComplete",
-                        ));
-                    }
-                    Some(SingleStatementCompletion::Empty) => {
-                        return Err(protocol(
-                            "execute() received multiple EmptyQueryResponse messages",
-                        ));
-                    }
-                    None => {}
-                }
-                if saw_parse_complete != saw_bind_complete {
-                    return Err(protocol(
-                        "execute() received EmptyQueryResponse before the extended-query controls completed",
-                    ));
-                }
-                if saw_bind_complete && !saw_no_data {
-                    return Err(protocol(
-                        "execute() received EmptyQueryResponse before NoData",
-                    ));
-                }
-                completion = Some(SingleStatementCompletion::Empty);
-            }
-            b'n' => {
-                require_empty_backend_message(body, "NoData")?;
-                if completion.is_some() || !saw_bind_complete || saw_no_data {
-                    return Err(protocol("execute() received NoData out of order"));
-                }
-                saw_no_data = true;
-            }
-            b'S' => validate_parameter_status(body)?,
-            b'N' => notices.push(parse_notice_response(body)?),
-            b'A' => validate_notification_response(body)?,
-            b'T' | b'D' => {
-                return Err(protocol(
-                    "execute() received rows; use query() for row results",
-                ));
-            }
-            b'G' | b'H' | b'W' | b'd' | b'c' => {
-                return Err(protocol(
-                    "execute() does not support COPY protocol responses; use exec_protocol_raw or exec_protocol_raw_stream for COPY traffic",
-                ));
-            }
-            _ => {
-                return Err(protocol(format!(
-                    "execute() received unexpected backend message tag 0x{tag:02x}"
-                )));
-            }
-        }
-    }
-
-    let ready_status =
-        ready_status.ok_or_else(|| protocol("execute response ended before ReadyForQuery"))?;
-    if postgres_error.is_none()
-        && expected_protocol == ExpectedProtocol::Extended
-        && (!saw_parse_complete || !saw_bind_complete)
-    {
-        return Err(protocol(
-            "execute() extended-query response omitted ParseComplete or BindComplete",
-        ));
-    }
-    if let Some(diagnostic) = postgres_error {
-        return Err(Error::Postgres {
-            diagnostic: Box::new(diagnostic),
-            notices,
-        });
-    }
-    if completion.is_none() {
-        return Err(protocol(
-            "execute response ended before CommandComplete or EmptyQueryResponse",
-        ));
-    }
-
-    let row_count = command_tag.as_deref().and_then(command_tag_row_count);
-    Ok(CommandResult {
-        command_tag,
-        row_count,
-        notices: notices.into_iter().map(PostgresNotice::from_core).collect(),
-        ready_status,
-    })
-}
-
-pub(crate) fn parse_query_response(
-    bytes: &[u8],
-    expected_protocol: ExpectedProtocol,
-) -> Result {
-    let mut input = bytes;
-    let mut fields = None;
-    let mut rows = Vec::new();
-    let mut command_tag = None;
-    let mut completion = None;
-    let mut saw_parse_complete = false;
-    let mut saw_bind_complete = false;
-    let mut saw_no_data = false;
-    let mut ready_status = None;
-    let mut notices = Vec::new();
-    let mut postgres_error = None;
-
-    while !input.is_empty() {
-        let (tag, body, rest) = read_backend_message(input)?;
-        input = rest;
-        if expected_protocol == ExpectedProtocol::Simple && matches!(tag, b'1' | b'2' | b'n') {
-            return Err(protocol(format!(
-                "query() simple-query response received extended-protocol message tag 0x{tag:02x}"
-            )));
-        }
-        if postgres_error.is_some() && !matches!(tag, b'N' | b'S' | b'A' | b'Z') {
-            return Err(protocol(format!(
-                "query() received backend message 0x{tag:02x} after ErrorResponse"
-            )));
-        }
-        match tag {
-            b'T' => {
-                if fields.is_some() {
-                    return Err(protocol(
-                        "query() received multiple result sets; use exec_protocol_raw for multi-statement row results",
-                    ));
-                }
-                if completion.is_some() {
-                    return Err(protocol(
-                        "query() received a result after statement completion",
-                    ));
-                }
-                if saw_no_data || (saw_parse_complete && !saw_bind_complete) {
-                    return Err(protocol("query() received RowDescription out of order"));
-                }
-                fields = Some(parse_row_description(body)?);
-            }
-            b'D' => {
-                if completion.is_some() {
-                    return Err(protocol(
-                        "query() received DataRow after statement completion",
-                    ));
-                }
-                let field_count = fields
-                    .as_ref()
-                    .ok_or_else(|| protocol("DataRow arrived before RowDescription"))?
-                    .len();
-                rows.push(parse_data_row(body, field_count)?);
-            }
-            b'C' => {
-                match completion {
-                    Some(SingleStatementCompletion::Command) => {
-                        return Err(protocol(
-                            "query() received multiple CommandComplete messages",
-                        ));
-                    }
-                    Some(SingleStatementCompletion::Empty) => {
-                        return Err(protocol(
-                            "query() received CommandComplete after EmptyQueryResponse",
-                        ));
-                    }
-                    None => {}
-                }
-                if saw_parse_complete != saw_bind_complete {
-                    return Err(protocol(
-                        "query() received CommandComplete before the extended-query controls completed",
-                    ));
-                }
-                if saw_bind_complete && fields.is_none() && !saw_no_data {
-                    return Err(protocol(
-                        "query() received CommandComplete before RowDescription or NoData",
-                    ));
-                }
-                command_tag = Some(parse_command_complete(body)?);
-                completion = Some(SingleStatementCompletion::Command);
-            }
-            b'E' => {
-                if completion.is_some() {
-                    return Err(protocol(
-                        "query() received ErrorResponse after statement completion",
-                    ));
-                }
-                postgres_error = Some(parse_error_response(body)?);
-            }
-            b'G' | b'H' | b'W' | b'd' | b'c' => {
-                return Err(protocol(
-                    "query() does not support COPY protocol responses; use exec_protocol_raw or exec_protocol_raw_stream",
-                ));
-            }
-            b'Z' => {
-                ready_status = Some(parse_ready_for_query(body)?);
-                if !input.is_empty() {
-                    return Err(protocol("backend returned bytes after ReadyForQuery"));
-                }
-            }
-            b'1' => {
-                require_empty_backend_message(body, "ParseComplete")?;
-                if completion.is_some()
-                    || saw_parse_complete
-                    || saw_bind_complete
-                    || fields.is_some()
-                    || saw_no_data
-                {
-                    return Err(protocol("query() received ParseComplete out of order"));
-                }
-                saw_parse_complete = true;
-            }
-            b'2' => {
-                require_empty_backend_message(body, "BindComplete")?;
-                if completion.is_some()
-                    || !saw_parse_complete
-                    || saw_bind_complete
-                    || fields.is_some()
-                    || saw_no_data
-                {
-                    return Err(protocol("query() received BindComplete out of order"));
-                }
-                saw_bind_complete = true;
-            }
-            b'I' => {
-                require_empty_backend_message(body, "EmptyQueryResponse")?;
-                match completion {
-                    Some(SingleStatementCompletion::Command) => {
-                        return Err(protocol(
-                            "query() received EmptyQueryResponse after CommandComplete",
-                        ));
-                    }
-                    Some(SingleStatementCompletion::Empty) => {
-                        return Err(protocol(
-                            "query() received multiple EmptyQueryResponse messages",
-                        ));
-                    }
-                    None => {}
-                }
-                if fields.is_some() || !rows.is_empty() {
-                    return Err(protocol(
-                        "query() received EmptyQueryResponse after a row result",
-                    ));
-                }
-                if saw_parse_complete != saw_bind_complete {
-                    return Err(protocol(
-                        "query() received EmptyQueryResponse before the extended-query controls completed",
-                    ));
-                }
-                if saw_bind_complete && !saw_no_data {
-                    return Err(protocol(
-                        "query() received EmptyQueryResponse before RowDescription or NoData",
-                    ));
-                }
-                completion = Some(SingleStatementCompletion::Empty);
-            }
-            b'n' => {
-                require_empty_backend_message(body, "NoData")?;
-                if completion.is_some() || !saw_bind_complete || fields.is_some() || saw_no_data {
-                    return Err(protocol("query() received NoData out of order"));
-                }
-                saw_no_data = true;
-            }
-            b'S' => validate_parameter_status(body)?,
-            b'N' => notices.push(parse_notice_response(body)?),
-            b'A' => validate_notification_response(body)?,
-            _ => {
-                return Err(protocol(format!(
-                    "query() received unexpected backend message tag 0x{tag:02x}"
-                )));
-            }
-        }
-    }
-
-    let ready_status =
-        ready_status.ok_or_else(|| protocol("query response ended before ReadyForQuery"))?;
-    if postgres_error.is_none()
-        && expected_protocol == ExpectedProtocol::Extended
-        && (!saw_parse_complete || !saw_bind_complete)
-    {
-        return Err(protocol(
-            "query() extended-query response omitted ParseComplete or BindComplete",
-        ));
-    }
-    if let Some(diagnostic) = postgres_error {
-        return Err(Error::Postgres {
-            diagnostic: Box::new(diagnostic),
-            notices,
-        });
-    }
-    if completion.is_none() {
-        return Err(protocol(
-            "query response ended before CommandComplete or EmptyQueryResponse",
-        ));
-    }
-
-    let row_count = command_tag.as_deref().and_then(command_tag_row_count);
-    let fields: Arc<[QueryField]> = fields.unwrap_or_default().into();
-    let rows = rows
-        .into_iter()
-        .map(|row| QueryRow::new(Arc::clone(&fields), row.values))
-        .collect();
-    Ok(QueryResult {
-        fields,
-        rows,
-        command_tag,
-        row_count,
-        notices: notices.into_iter().map(PostgresNotice::from_core).collect(),
-        ready_status,
-    })
-}
-
-pub(crate) fn parse_exec_response(bytes: &[u8]) -> Result {
-    let mut input = bytes;
-    let mut fields = None;
-    let mut rows = Vec::new();
-    let mut statements = Vec::new();
-    let mut saw_completion = false;
-    let mut notices = Vec::new();
-    let mut statement_notices = Vec::new();
-    let mut ready_status = None;
-    let mut postgres_error = None;
-
-    while !input.is_empty() {
-        let (tag, body, rest) = read_backend_message(input)?;
-        input = rest;
-        if postgres_error.is_some() && !matches!(tag, b'N' | b'S' | b'A' | b'Z') {
-            return Err(protocol(format!(
-                "exec() received backend message 0x{tag:02x} after ErrorResponse"
-            )));
-        }
-        match tag {
-            b'T' => {
-                if fields.is_some() {
-                    return Err(protocol(
-                        "exec() received RowDescription before the prior result completed",
-                    ));
-                }
-                fields = Some(parse_row_description(body)?);
-            }
-            b'D' => {
-                let expected = fields
-                    .as_ref()
-                    .ok_or_else(|| protocol("DataRow arrived before RowDescription"))?
-                    .len();
-                rows.push(parse_data_row(body, expected)?);
-            }
-            b'C' => {
-                let command_tag = parse_command_complete(body)?;
-                let row_count = command_tag_row_count(&command_tag);
-                if let Some(result_fields) = fields.take() {
-                    let fields: Arc<[QueryField]> = result_fields.into();
-                    let rows = std::mem::take(&mut rows)
-                        .into_iter()
-                        .map(|row| QueryRow::new(Arc::clone(&fields), row.values))
-                        .collect();
-                    statements.push(StatementResult::Rows(QueryResult {
-                        fields,
-                        rows,
-                        command_tag: Some(command_tag),
-                        row_count,
-                        notices: take_notices(&mut statement_notices),
-                        ready_status: ReadyStatus::Idle,
-                    }));
-                } else {
-                    if !rows.is_empty() {
-                        return Err(protocol("exec() retained rows without field metadata"));
-                    }
-                    statements.push(StatementResult::Command(CommandResult {
-                        command_tag: Some(command_tag),
-                        row_count,
-                        notices: take_notices(&mut statement_notices),
-                        ready_status: ReadyStatus::Idle,
-                    }));
-                }
-                saw_completion = true;
-            }
-            b'I' => {
-                require_empty_backend_message(body, "EmptyQueryResponse")?;
-                if fields.is_some() || !rows.is_empty() {
-                    return Err(protocol(
-                        "exec() received EmptyQueryResponse before the prior row result completed",
-                    ));
-                }
-                statement_notices.clear();
-                saw_completion = true;
-            }
-            b'E' => postgres_error = Some(parse_error_response(body)?),
-            b'N' => {
-                let notice = parse_notice_response(body)?;
-                statement_notices.push(notice.clone());
-                notices.push(notice);
-            }
-            b'S' => validate_parameter_status(body)?,
-            b'A' => validate_notification_response(body)?,
-            b'Z' => {
-                ready_status = Some(parse_ready_for_query(body)?);
-                if !input.is_empty() {
-                    return Err(protocol("backend returned bytes after ReadyForQuery"));
-                }
-            }
-            b'G' | b'H' | b'W' | b'd' | b'c' => {
-                return Err(protocol(
-                    "exec() does not support COPY protocol responses; use exec_protocol_raw or exec_protocol_raw_stream",
-                ));
-            }
-            _ => {
-                return Err(protocol(format!(
-                    "exec() received unexpected backend message tag 0x{tag:02x}"
-                )));
-            }
-        }
-    }
-
-    let ready_status =
-        ready_status.ok_or_else(|| protocol("exec response ended before ReadyForQuery"))?;
-    if let Some(diagnostic) = postgres_error {
-        return Err(Error::Postgres {
-            diagnostic: Box::new(diagnostic),
-            notices,
-        });
-    }
-    if fields.is_some() || !rows.is_empty() {
-        return Err(protocol("exec response ended before CommandComplete"));
-    }
-    if !saw_completion {
-        return Err(protocol(
-            "exec response ended before CommandComplete or EmptyQueryResponse",
-        ));
-    }
-
-    Ok(ExecResult {
-        statements,
-        notices: notices.into_iter().map(PostgresNotice::from_core).collect(),
-        ready_status,
-    })
-}
-
-fn take_notices(notices: &mut Vec) -> Vec {
-    std::mem::take(notices)
-        .into_iter()
-        .map(PostgresNotice::from_core)
-        .collect()
-}
-
-pub(crate) fn parse_statement_description(bytes: &[u8]) -> Result {
-    let mut input = bytes;
-    let mut parameter_types = None;
-    let mut fields = None;
-    let mut saw_no_data = false;
-    let mut saw_parse_complete = false;
-    let mut ready_status = None;
-    let mut notices = Vec::new();
-    let mut postgres_error = None;
-
-    while !input.is_empty() {
-        let (tag, body, rest) = read_backend_message(input)?;
-        input = rest;
-        if postgres_error.is_some() && !matches!(tag, b'N' | b'S' | b'A' | b'Z') {
-            return Err(protocol(format!(
-                "describe() received backend message 0x{tag:02x} after ErrorResponse"
-            )));
-        }
-        match tag {
-            b'1' => {
-                require_empty_backend_message(body, "ParseComplete")?;
-                if saw_parse_complete
-                    || parameter_types.is_some()
-                    || fields.is_some()
-                    || saw_no_data
-                {
-                    return Err(protocol("describe() received ParseComplete out of order"));
-                }
-                saw_parse_complete = true;
-            }
-            b't' => {
-                if !saw_parse_complete
-                    || parameter_types.is_some()
-                    || fields.is_some()
-                    || saw_no_data
-                {
-                    return Err(protocol(
-                        "describe() received ParameterDescription out of order",
-                    ));
-                }
-                parameter_types = Some(parse_parameter_description(body)?);
-            }
-            b'T' => {
-                if parameter_types.is_none() || fields.is_some() || saw_no_data {
-                    return Err(protocol("describe() received RowDescription out of order"));
-                }
-                fields = Some(parse_row_description(body)?);
-            }
-            b'n' => {
-                require_empty_backend_message(body, "NoData")?;
-                if parameter_types.is_none() || fields.is_some() || saw_no_data {
-                    return Err(protocol("describe() received NoData out of order"));
-                }
-                saw_no_data = true;
-            }
-            b'E' => {
-                if fields.is_some() || saw_no_data {
-                    return Err(protocol(
-                        "describe() received ErrorResponse after result description",
-                    ));
-                }
-                postgres_error = Some(parse_error_response(body)?);
-            }
-            b'N' => notices.push(parse_notice_response(body)?),
-            b'S' => validate_parameter_status(body)?,
-            b'A' => validate_notification_response(body)?,
-            b'Z' => {
-                ready_status = Some(parse_ready_for_query(body)?);
-                if !input.is_empty() {
-                    return Err(protocol("backend returned bytes after ReadyForQuery"));
-                }
-            }
-            _ => {
-                return Err(protocol(format!(
-                    "describe() received unexpected backend message tag 0x{tag:02x}"
-                )));
-            }
-        }
-    }
-
-    let ready_status =
-        ready_status.ok_or_else(|| protocol("describe response ended before ReadyForQuery"))?;
-    if let Some(diagnostic) = postgres_error {
-        return Err(Error::Postgres {
-            diagnostic: Box::new(diagnostic),
-            notices,
-        });
-    }
-    if !saw_parse_complete {
-        return Err(protocol("describe response omitted ParseComplete"));
-    }
-    let parameter_types = parameter_types
-        .ok_or_else(|| protocol("describe response omitted ParameterDescription"))?;
-    if fields.is_none() && !saw_no_data {
-        return Err(protocol(
-            "describe response omitted RowDescription or NoData",
-        ));
-    }
-
-    Ok(StatementDescription {
-        parameter_types: parameter_types.into_iter().map(TypeOid::new).collect(),
-        fields,
-        notices: notices.into_iter().map(PostgresNotice::from_core).collect(),
-        ready_status,
-    })
-}
-
-pub(crate) fn response_ready_status(bytes: &[u8]) -> Result {
-    let mut input = bytes;
-    let mut ready = None;
-    while !input.is_empty() {
-        let (tag, body, rest) = read_backend_message(input)?;
-        input = rest;
-        if tag == b'Z' {
-            if ready.is_some() {
-                return Err(protocol("backend returned multiple ReadyForQuery messages"));
-            }
-            ready = Some(parse_ready_for_query(body)?);
-            if !input.is_empty() {
-                return Err(protocol("backend returned bytes after ReadyForQuery"));
-            }
-        }
-    }
-    ready.ok_or_else(|| protocol("response ended before ReadyForQuery"))
-}
-
-/// Validate that a structured operation kept ownership of a callback-scoped
-/// transaction. This works from raw backend frames so an earlier
-/// CommandComplete cannot be hidden by a later ErrorResponse.
-pub(crate) fn validate_managed_transaction_response(bytes: &[u8]) -> Result {
-    let mut input = bytes;
-    let mut ready = None;
-    let mut escaped_command = None;
-    while !input.is_empty() {
-        let (message, body, rest) = read_backend_message(input)?;
-        input = rest;
-        match message {
-            b'C' => {
-                let mut command = body;
-                let tag = read_cstring(&mut command, "CommandComplete tag")?;
-                if !command.is_empty() {
-                    return Err(protocol("CommandComplete contained trailing bytes"));
-                }
-                if matches!(
-                    tag,
-                    "BEGIN"
-                        | "START TRANSACTION"
-                        | "COMMIT"
-                        | "PREPARE TRANSACTION"
-                        | "COMMIT PREPARED"
-                        | "ROLLBACK PREPARED"
-                ) {
-                    escaped_command.get_or_insert_with(|| tag.to_owned());
-                }
-            }
-            b'Z' => {
-                if ready.is_some() {
-                    return Err(protocol("backend returned multiple ReadyForQuery messages"));
-                }
-                ready = Some(parse_ready_for_query(body)?);
-                if !input.is_empty() {
-                    return Err(protocol("backend returned bytes after ReadyForQuery"));
-                }
-            }
-            _ => {}
-        }
-    }
-    let ready = ready.ok_or_else(|| protocol("response ended before ReadyForQuery"))?;
-    if let Some(command) = escaped_command {
-        return Err(protocol(format!(
-            "PostgreSQL completed {command}, which changed the SDK-managed transaction lifecycle"
-        )));
-    }
-    if ready == ReadyStatus::Idle {
-        return Err(protocol(
-            "PostgreSQL returned idle readiness after SDK-managed transaction work",
-        ));
-    }
-    Ok(ready)
-}
-
-fn parse_parameter_description(mut body: &[u8]) -> Result> {
-    let count = read_i16(&mut body, "ParameterDescription parameter count")?;
-    if count < 0 {
-        return Err(protocol(format!(
-            "invalid ParameterDescription parameter count {count}"
-        )));
-    }
-    let mut types = Vec::with_capacity(count as usize);
-    for _ in 0..count {
-        types.push(read_u32(&mut body, "ParameterDescription type OID")?);
-    }
-    if !body.is_empty() {
-        return Err(protocol("ParameterDescription contained trailing bytes"));
-    }
-    Ok(types)
-}
-
-fn command_tag_row_count(tag: &str) -> Option {
-    let mut parts = tag.split_ascii_whitespace();
-    let command = parts.next()?;
-    if !matches!(
-        command,
-        "SELECT" | "INSERT" | "UPDATE" | "DELETE" | "MERGE" | "MOVE" | "FETCH" | "COPY"
-    ) {
-        return None;
-    }
-    parts.last().or(Some(command))?.parse().ok()
-}
-
-fn read_backend_message(bytes: &[u8]) -> Result<(u8, &[u8], &[u8])> {
-    if bytes.len() < 5 {
-        return Err(protocol("truncated backend message header"));
-    }
-    let tag = bytes[0];
-    let len = i32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]);
-    if len < 4 {
-        return Err(protocol(format!("invalid backend message length {len}")));
-    }
-    let total = 1usize
-        .checked_add(len as usize)
-        .ok_or_else(|| protocol("backend message length overflow"))?;
-    if bytes.len() < total {
-        return Err(protocol("truncated backend message body"));
-    }
-    Ok((tag, &bytes[5..total], &bytes[total..]))
-}
-
-fn parse_row_description(mut body: &[u8]) -> Result> {
-    let count = read_i16(&mut body, "RowDescription field count")?;
-    if count < 0 {
-        return Err(protocol(format!(
-            "invalid RowDescription field count {count}"
-        )));
-    }
-    let mut fields = Vec::with_capacity(count as usize);
-    for _ in 0..count {
-        fields.push(QueryField {
-            name: read_cstring(&mut body, "field name")?.to_owned(),
-            table_oid: read_u32(&mut body, "field table oid")?,
-            table_attribute: read_i16(&mut body, "field table attribute")?,
-            type_oid: read_u32(&mut body, "field type oid")?,
-            type_size: read_i16(&mut body, "field type size")?,
-            type_modifier: read_i32(&mut body, "field type modifier")?,
-            format: QueryFormat::from(read_i16(&mut body, "field format")?),
-        });
-    }
-    if !body.is_empty() {
-        return Err(protocol("RowDescription contained trailing bytes"));
-    }
-    Ok(fields)
-}
-
-fn parse_data_row(mut body: &[u8], expected_columns: usize) -> Result {
-    let count = read_i16(&mut body, "DataRow column count")?;
-    if count < 0 {
-        return Err(protocol(format!("invalid DataRow column count {count}")));
-    }
-    if count as usize != expected_columns {
-        return Err(protocol(format!(
-            "DataRow column count {count} does not match RowDescription count {expected_columns}"
-        )));
-    }
-    let mut values = Vec::with_capacity(count as usize);
-    for _ in 0..count {
-        let len = read_i32(&mut body, "DataRow value length")?;
-        if len == -1 {
-            values.push(None);
-            continue;
-        }
-        if len < 0 {
-            return Err(protocol(format!("invalid DataRow value length {len}")));
-        }
-        let len = len as usize;
-        if body.len() < len {
-            return Err(protocol("truncated DataRow value"));
-        }
-        values.push(Some(body[..len].to_vec()));
-        body = &body[len..];
-    }
-    if !body.is_empty() {
-        return Err(protocol("DataRow contained trailing bytes"));
-    }
-    Ok(Row { values })
-}
-
-fn parse_command_complete(mut body: &[u8]) -> Result {
-    let tag = read_cstring(&mut body, "CommandComplete tag")?.to_owned();
-    if !body.is_empty() {
-        return Err(protocol("CommandComplete contained trailing bytes"));
-    }
-    Ok(tag)
-}
-
-fn parse_error_response(body: &[u8]) -> Result {
-    parse_diagnostic_fields(body, "ErrorResponse")
-        .map(|fields| diagnostic(fields, "PostgreSQL ErrorResponse"))
-}
-
-fn parse_notice_response(body: &[u8]) -> Result {
-    parse_diagnostic_fields(body, "NoticeResponse")
-        .map(|fields| diagnostic(fields, "PostgreSQL NoticeResponse"))
-}
-
-fn require_empty_backend_message(body: &[u8], label: &str) -> Result<()> {
-    if body.is_empty() {
-        return Ok(());
-    }
-    Err(protocol(format!("{label} contained trailing bytes")))
-}
-
-fn parse_ready_for_query(body: &[u8]) -> Result {
-    match body {
-        [b'I'] => Ok(ReadyStatus::Idle),
-        [b'T'] => Ok(ReadyStatus::InTransaction),
-        [b'E'] => Ok(ReadyStatus::FailedTransaction),
-        [status] => Err(protocol(format!(
-            "ReadyForQuery contained invalid transaction status 0x{status:02x}"
-        ))),
-        _ => Err(protocol(format!(
-            "ReadyForQuery contained {} bytes, expected 1",
-            body.len()
-        ))),
-    }
-}
-
-fn validate_parameter_status(mut body: &[u8]) -> Result<()> {
-    read_cstring(&mut body, "ParameterStatus name")?;
-    read_cstring(&mut body, "ParameterStatus value")?;
-    if !body.is_empty() {
-        return Err(protocol("ParameterStatus contained trailing bytes"));
-    }
-    Ok(())
-}
-
-fn validate_notification_response(mut body: &[u8]) -> Result<()> {
-    read_i32(&mut body, "NotificationResponse process id")?;
-    read_cstring(&mut body, "NotificationResponse channel")?;
-    read_cstring(&mut body, "NotificationResponse payload")?;
-    if !body.is_empty() {
-        return Err(protocol("NotificationResponse contained trailing bytes"));
-    }
-    Ok(())
-}
-
-fn read_u32(input: &mut &[u8], label: &str) -> Result {
-    let bytes = take(input, 4, label)?;
-    Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
-}
-
-fn read_i32(input: &mut &[u8], label: &str) -> Result {
-    let bytes = take(input, 4, label)?;
-    Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
-}
-
-fn read_i16(input: &mut &[u8], label: &str) -> Result {
-    let bytes = take(input, 2, label)?;
-    Ok(i16::from_be_bytes([bytes[0], bytes[1]]))
-}
-
-fn read_cstring<'a>(input: &mut &'a [u8], label: &str) -> Result<&'a str> {
-    let nul = input
-        .iter()
-        .position(|byte| *byte == 0)
-        .ok_or_else(|| protocol(format!("{label} is missing null terminator")))?;
-    let raw = &input[..nul];
-    let value = str::from_utf8(raw)
-        .map_err(|error| protocol(format!("{label} is not valid UTF-8: {error}")))?;
-    *input = &input[nul + 1..];
-    Ok(value)
-}
-
-fn take<'a>(input: &mut &'a [u8], len: usize, label: &str) -> Result<&'a [u8]> {
-    if input.len() < len {
-        return Err(protocol(format!("truncated {label}")));
-    }
-    let (head, tail) = input.split_at(len);
-    *input = tail;
-    Ok(head)
-}
diff --git a/src/shared/rust-query-core/tools/check-rust-query-core.mjs b/src/shared/rust-query-core/tools/check-rust-query-core.mjs
deleted file mode 100644
index 203793ea0..000000000
--- a/src/shared/rust-query-core/tools/check-rust-query-core.mjs
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env node
-
-import { existsSync, readFileSync } from 'node:fs';
-
-function fail(message) {
-  throw new Error(message);
-}
-
-const canonicalPath = 'src/shared/rust-query-core/query_core.rs';
-const canonical = readFileSync(canonicalPath, 'utf8');
-if (!canonical.trim()) {
-  fail(`${canonicalPath} must not be empty`);
-}
-
-for (const mirror of [
-  'src/sdks/rust/src/query_core.rs',
-  'src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/query_core.rs',
-]) {
-  if (existsSync(mirror)) {
-    fail(`${mirror} must be release-staged, not committed beside ${canonicalPath}`);
-  }
-}
-
-console.log('shared Rust query core source is canonical and has no committed mirrors');
diff --git a/src/sources/moon.yml b/src/sources/moon.yml
deleted file mode 100644
index 6c95c0c5b..000000000
--- a/src/sources/moon.yml
+++ /dev/null
@@ -1,133 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "source-inputs"
-language: "unknown"
-layer: "configuration"
-stack: "systems"
-tags: ["sources"]
-
-project:
-  title: "Source Inputs"
-  description: "Neutral source checkout materialization for PostgreSQL, runtime dependencies, toolchains, and extension-owned sources."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "**/*": ["@oliphaunt/core"]
-
-tasks:
-  unit:
-    tags: ["quality", "unit"]
-    script: |
-      set -e
-      bun src/sources/tools/fetch-sources.mjs production-all --validate-only
-      bun test src/sources/tools/source-fetch-core.test.mjs src/sources/tools/source-fetch-scopes.test.mjs
-      bash src/postgres/versions/18/fetch-source.test.sh
-    inputs:
-      - "/src/postgres/versions/18/**/*"
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/sources/third-party/**/*.toml"
-      - "/src/extensions/external/**/source.toml"
-      - "/src/extensions/external/**/dependencies/**/source.toml"
-      - "/src/extensions/external/*/upstream-license-data.json"
-      - "tools/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  fetch-all:
-    tags: ["source", "fetch"]
-    command: "bun src/sources/tools/fetch-sources.mjs production-all --force"
-    inputs:
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/sources/third-party/**/*.toml"
-      - "/src/extensions/external/**/source.toml"
-      - "/src/extensions/external/**/dependencies/**/source.toml"
-      - "/src/extensions/external/*/upstream-license-data.json"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/Dockerfile"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/isrg-root-x1.pem"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.sh"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-wasixcc.sh"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv"
-      - "tools/**/*"
-      - "!tools/**/*.test.*"
-      - "!tools/verify-source-tree.py"
-      - "/tools/dev/capture-command-output.mjs"
-      - "/tools/release/extension-upstream-licenses.mjs"
-      - "@group(release-archive-contract)"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: false
-  source-fetch-native-runtime:
-    tags: ["source", "fetch"]
-    command: "bun src/sources/tools/fetch-sources.mjs native-runtime --force"
-    inputs:
-      - "/src/sources/third-party/shared/*.toml"
-      - "/src/sources/third-party/native/*.toml"
-      - "/src/extensions/external/**/source.toml"
-      - "/src/extensions/external/**/dependencies/**/source.toml"
-      - "/src/extensions/external/*/upstream-license-data.json"
-      - "tools/**/*"
-      - "!tools/**/*.test.*"
-      - "!tools/verify-source-tree.py"
-      - "/tools/dev/capture-command-output.mjs"
-      - "@group(release-archive-contract)"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-  source-fetch-wasix-runtime:
-    tags: ["source", "fetch"]
-    command: "bun src/sources/tools/fetch-sources.mjs wasix-runtime --force"
-    inputs:
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/sources/third-party/shared/*.toml"
-      - "/src/extensions/external/**/source.toml"
-      - "/src/extensions/external/**/dependencies/**/source.toml"
-      - "/src/extensions/external/*/upstream-license-data.json"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/Dockerfile"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/isrg-root-x1.pem"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.sh"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-wasixcc.sh"
-      - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv"
-      - "tools/**/*"
-      - "!tools/**/*.test.*"
-      - "!tools/verify-source-tree.py"
-      - "/tools/dev/capture-command-output.mjs"
-      - "@group(release-archive-contract)"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-  source-fetch-wasix-postmaster-runtime:
-    tags: ["source", "fetch"]
-    command: "bun src/sources/tools/fetch-sources.mjs wasix-postmaster-runtime --force"
-    inputs:
-      - "/src/sources/toolchains/wasix.toml"
-      - "/src/sources/third-party/shared/*.toml"
-      - "/src/sources/third-party/wasix-postmaster/*.toml"
-      - "tools/**/*"
-      - "!tools/**/*.test.*"
-      - "!tools/verify-source-tree.py"
-      - "/tools/dev/capture-command-output.mjs"
-    options:
-      cache: false
-      internal: true
-      runFromWorkspaceRoot: true
-  source-fetch-extensions:
-    tags: ["source", "fetch"]
-    command: "bun src/sources/tools/fetch-sources.mjs extensions --force"
-    inputs:
-      - "/src/extensions/external/**/source.toml"
-      - "/src/extensions/external/**/dependencies/**/source.toml"
-      - "/src/extensions/external/*/upstream-license-data.json"
-      - "tools/**/*"
-      - "!tools/**/*.test.*"
-      - "!tools/verify-source-tree.py"
-      - "/tools/dev/capture-command-output.mjs"
-      - "/tools/release/extension-upstream-licenses.mjs"
-      - "@group(release-archive-contract)"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
diff --git a/src/sources/third-party/native/README.md b/src/sources/third-party/native/README.md
deleted file mode 100644
index 846e141bb..000000000
--- a/src/sources/third-party/native/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Native Third-Party Sources
-
-Native-only third-party source pins live here when an upstream dependency is not shared with WASIX.
diff --git a/src/sources/third-party/native/moon.yml b/src/sources/third-party/native/moon.yml
deleted file mode 100644
index 0b843781e..000000000
--- a/src/sources/third-party/native/moon.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "third-party-native"
-language: "unknown"
-layer: "configuration"
-stack: "systems"
-tags: ["third-party", "sources", "native"]
-
-project:
-  title: "Native Third-Party Sources"
-  description: "Pinned native-only third-party source metadata."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "**/*": ["@oliphaunt/core"]
-
-fileGroups:
-  sources:
-    - "*.toml"
diff --git a/src/sources/third-party/shared/moon.yml b/src/sources/third-party/shared/moon.yml
deleted file mode 100644
index 894247b82..000000000
--- a/src/sources/third-party/shared/moon.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "third-party-shared"
-language: "unknown"
-layer: "configuration"
-stack: "systems"
-tags: ["third-party", "sources"]
-
-project:
-  title: "Shared Third-Party Sources"
-  description: "Pinned third-party source metadata shared by native and WASIX runtimes."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "**/*": ["@oliphaunt/core"]
-
-fileGroups:
-  sources:
-    - "*.toml"
diff --git a/src/sources/third-party/wasix-postmaster/README.md b/src/sources/third-party/wasix-postmaster/README.md
deleted file mode 100644
index e719a3fc4..000000000
--- a/src/sources/third-party/wasix-postmaster/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# WASIX Postmaster Third-Party Sources
-
-These are the production source pins for the concurrent PostgreSQL/WASIX
-postmaster runtime. They are separate from the single-backend WASIX source
-domain because applying the postmaster concurrency patches must not alter the
-existing `liboliphaunt-wasix` product.
-
-The hardened source fetcher materializes clean, immutable checkouts under
-`target/oliphaunt-sources/checkouts/`. Project scripts copy those inputs into
-disposable worktrees under `target/oliphaunt-wasix-postmaster/` before applying
-patches. The durable source checkouts are never patched in place.
-
-Wasmer's `lib/napi`, `wasmer-test-files`, and `tests/wast/spec` gitlinks are
-pinned independently because the repository source fetcher deliberately does
-not recurse into submodules.
diff --git a/src/sources/third-party/wasix-postmaster/moon.yml b/src/sources/third-party/wasix-postmaster/moon.yml
deleted file mode 100644
index 2eba1fdaf..000000000
--- a/src/sources/third-party/wasix-postmaster/moon.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "third-party-wasix-postmaster"
-language: "unknown"
-layer: "configuration"
-stack: "systems"
-tags: ["third-party", "sources", "wasix", "postmaster"]
-
-project:
-  title: "WASIX Postmaster Third-Party Sources"
-  description: "Pinned Wasmer and wasix-libc source metadata for the concurrent postmaster runtime."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/wasix"
-  paths:
-    "**/*": ["@oliphaunt/wasix"]
-
-fileGroups:
-  sources:
-    - "*.toml"
diff --git a/src/sources/toolchains/android-emulator-runner.toml b/src/sources/toolchains/android-emulator-runner.toml
deleted file mode 100644
index af0d61d30..000000000
--- a/src/sources/toolchains/android-emulator-runner.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[toolchain]
-name = "ReactiveCircus Android Emulator Runner"
-kind = "github-action"
-repository = "ReactiveCircus/android-emulator-runner"
-ref = "v2"
-sha = "70f4dee990796918b78d040e3278474bdbd348a7"
-license = "Apache-2.0"
-cloud_required = false
-
-[usage]
-scope = "React Native Android installed-app E2E on GitHub-hosted Ubuntu runners"
-reason = "Creates, boots, waits for, and tears down the Android emulator around the product-owned Maestro flow."
diff --git a/src/sources/toolchains/bun.toml b/src/sources/toolchains/bun.toml
deleted file mode 100644
index a09e8395d..000000000
--- a/src/sources/toolchains/bun.toml
+++ /dev/null
@@ -1,37 +0,0 @@
-[toolchain]
-version = "1.3.14"
-
-[assets.darwin-aarch64]
-url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-darwin-aarch64.zip"
-sha256 = "d8b96221828ad6f97ac7ac0ab7e95872341af763001e8803e8267652c2652620"
-binary_path = "bun-darwin-aarch64/bun"
-binary_sha256 = "e0c90ec15d33363e6b70713d56bc3b2c7585c17f40a0fe0f8fd9305901d4e233"
-entry_count = "2"
-
-[assets.darwin-x64]
-url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-darwin-x64.zip"
-sha256 = "4183df3374623e5bab315c547cfa0974533cd457d86b73b639f7a87974cd6633"
-binary_path = "bun-darwin-x64/bun"
-binary_sha256 = "ea2f223e94bb2f4bf3050895113c3cf346438f6fa0501c8532284e063f72f7a0"
-entry_count = "2"
-
-[assets.linux-aarch64]
-url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-aarch64.zip"
-sha256 = "a27ffb63a8310375836e0d6f668ae17fa8d8d18b88c37c821c65331973a19a3b"
-binary_path = "bun-linux-aarch64/bun"
-binary_sha256 = "37141662ebed915a2ab89313156e455e2a1374395f5f6760d06407f49406f086"
-entry_count = "2"
-
-[assets.linux-x64]
-url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-x64.zip"
-sha256 = "951ee2aee855f08595aeec6225226a298d3fea83a3dcd6465c09cbccdf7e848f"
-binary_path = "bun-linux-x64/bun"
-binary_sha256 = "9fd36f87e4b90b07632b987a2e4ec81ca15a62c81bf983190cea6d715be2ad74"
-entry_count = "2"
-
-[assets.windows-x64]
-url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-windows-x64.zip"
-sha256 = "0a0620930b6675d7ba440e81f4e0e00d3cfbe096c4b140d3fff02205e9e18922"
-binary_path = "bun-windows-x64/bun.exe"
-binary_sha256 = "0187f68d843f825a72ada4a7eca60db896ed753759a7f8252edcd31ac1bf1b9c"
-entry_count = "2"
diff --git a/src/sources/toolchains/moon-plugins.toml b/src/sources/toolchains/moon-plugins.toml
deleted file mode 100644
index 07366f6be..000000000
--- a/src/sources/toolchains/moon-plugins.toml
+++ /dev/null
@@ -1,35 +0,0 @@
-[plugins.javascript]
-locator = "registry://ghcr.io/moonrepo/javascript_toolchain@sha256:81c26ebeae43fb130ad3ce0411cbdfd3bc4aa9d5e488e25b43a08fda5e790176"
-repository = "moonrepo/javascript_toolchain"
-manifest_sha256 = "81c26ebeae43fb130ad3ce0411cbdfd3bc4aa9d5e488e25b43a08fda5e790176"
-manifest_bytes = "1538"
-blob_sha256 = "ef177cc41b6a0f5ded27c5c8db22fe790e6855ec6623d3089bf0170ae45e38ac"
-bytes = "2697259"
-cache_file = "javascript-b20b528033f296e32c44c64032920820e365f623e7d7a28566cacf1593fe7466.wasm"
-
-[plugins.node]
-locator = "registry://ghcr.io/moonrepo/node_toolchain@sha256:1ac2fab8bf5297bea9361132612b0dd70c63a9482606d06c15e48704643934ec"
-repository = "moonrepo/node_toolchain"
-manifest_sha256 = "1ac2fab8bf5297bea9361132612b0dd70c63a9482606d06c15e48704643934ec"
-manifest_bytes = "1510"
-blob_sha256 = "32f52daa73eaf736c02570856dc851ca3d75c8f43b62b53ff24e5b5a068f92ef"
-bytes = "1949761"
-cache_file = "node-0d616ca34b325e12df839c8bfbb0499c961a166416ea3d14fce1a78856fa8e8e.wasm"
-
-[plugins.pnpm]
-locator = "registry://ghcr.io/moonrepo/node_depman_toolchain@sha256:9337febf5b59f5a789a252179a7c2b1dd7c05be79905e311366a016d9f6f8677"
-repository = "moonrepo/node_depman_toolchain"
-manifest_sha256 = "9337febf5b59f5a789a252179a7c2b1dd7c05be79905e311366a016d9f6f8677"
-manifest_bytes = "1581"
-blob_sha256 = "f745403db21fba82f6f95eff7a92be69e71df0ba7a674af2b0d401488f58a43a"
-bytes = "2505324"
-cache_file = "pnpm-1c4d213db0c60ad63913ebc905b5a2da1356a321cdf98c3ddc2687996690f260.wasm"
-
-[plugins.rust]
-locator = "registry://ghcr.io/moonrepo/rust_toolchain@sha256:477b97a7c5f1c98321c43c8a63b4921fa54ee884d49b1b25b9644de5c0e6209e"
-repository = "moonrepo/rust_toolchain"
-manifest_sha256 = "477b97a7c5f1c98321c43c8a63b4921fa54ee884d49b1b25b9644de5c0e6209e"
-manifest_bytes = "1508"
-blob_sha256 = "29ae28f8191c6dabea0ece7d08fa0b142037aaa82a8f51902a044a9237598eae"
-bytes = "2907144"
-cache_file = "rust-a38daa0f782261e4a1ab262f4b39185346b459447e426b89e2c109de71574521.wasm"
diff --git a/src/sources/toolchains/moon.yml b/src/sources/toolchains/moon.yml
deleted file mode 100644
index 5ae4696ad..000000000
--- a/src/sources/toolchains/moon.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "source-toolchains"
-language: "unknown"
-layer: "configuration"
-stack: "systems"
-tags: ["sources", "toolchain"]
-
-project:
-  title: "Source Toolchains"
-  description: "Pinned compiler, runtime, and container metadata for source builds."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "**/*": ["@oliphaunt/core"]
-
-fileGroups:
-  wasix:
-    - "wasix.toml"
diff --git a/src/sources/toolchains/node.toml b/src/sources/toolchains/node.toml
deleted file mode 100644
index 0c55a3dca..000000000
--- a/src/sources/toolchains/node.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[toolchain]
-version = "22.22.3"
-
-[headers]
-url = "https://nodejs.org/download/release/v22.22.3/node-v22.22.3-headers.tar.gz"
-sha256 = "723b896d68a288e9877ea929538494afe8b5808f6fedc3358d2ad77307d1b393"
-
-[windows.x64]
-url = "https://nodejs.org/download/release/v22.22.3/win-x64/node.lib"
-sha256 = "0d8d8bcc11daea60f5dd4da414e72ccb785718345ec8fbec52cfc7d1a2326293"
diff --git a/src/sources/toolchains/pnpm.toml b/src/sources/toolchains/pnpm.toml
deleted file mode 100644
index c2e8404a9..000000000
--- a/src/sources/toolchains/pnpm.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-[toolchain]
-version = "11.5.0"
-
-[package]
-url = "https://registry.npmjs.org/pnpm/-/pnpm-11.5.0.tgz"
-sha256 = "a282871708f87a47b9cd72182dfdf9ee251c69100b8bac862a3d4f5e2145d8ff"
-sha512 = "dbfcc4f81cf48597afd4bc391ffdf12c11f1a9fb83a395bfa6b0a2d9cc2fd8ffebafdb1ccbd529632153f793904c2615b7f09fe1a345473fd1c35845172a8eb1"
-bytes = "4281185"
-expanded_bytes = "17589456"
-format = "tar.gz"
-prefix = "package"
-entry_count = "449"
-file_count = "449"
-tree_sha256 = "bc4c36f336fecec19bb14777cb4897bae42d7c9227ac8cc4737d03ec61c0d8c5"
-executable_paths = "bin/pnpm.mjs,bin/pnpx.mjs,dist/node-gyp-bin/node-gyp,dist/node-gyp-bin/node-gyp.cmd,dist/node_modules/node-gyp/bin/node-gyp.js"
-binary_path = "bin/pnpm.mjs"
-binary_sha256 = "ff3224d46b47fbb24a7e9fe15fededef7e00892d07d4e376b6762d4899906bfd"
-companion_path = "bin/pnpx.mjs"
-companion_sha256 = "7e2a61f1636e6d85fbd894b7062b1837e175c673c3dc9ba9bc7538fe1ce66502"
-payload_path = "dist/pnpm.mjs"
-payload_sha256 = "1d1078d8c01e422c1a334fe145ccb34f18035fc4d053f48e561aa5ab0e46b078"
diff --git a/src/sources/toolchains/wasix.toml b/src/sources/toolchains/wasix.toml
deleted file mode 100644
index 1dc976bff..000000000
--- a/src/sources/toolchains/wasix.toml
+++ /dev/null
@@ -1,52 +0,0 @@
-[toolchain]
-wasmer = "7.2.1"
-wasmer-wasix = "0.702.1"
-webc = "12.0.0"
-wasmer_llvm = "22.1"
-assets_manifest = "src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv"
-assets_manifest_sha256 = "9b0ee1aabcfecda1be72c94a9f14a16c9d8a2fc020f3dc471394d5335766c519"
-
-[toolchain.wasixcc]
-version = "0.4.3"
-target = "x86_64-unknown-linux-gnu"
-asset = "wasixcc-x86_64-unknown-linux-gnu.tar.gz"
-sha256 = "3c55abbe0490d0a4736dfe0caaf0763597ae3e50e587c447bf6397b841a0b096"
-
-[toolchain.sysroots]
-version = "2026-03-02.1"
-sysroot_sha256 = "ec1c4286fae0c70d4ac4e71acfa2d28d439b1270fe65b4ee266df48dc10076a7"
-sysroot_eh_sha256 = "0714ee07316d9a0bf9e1b1ec66acc15fee302b7bd23254680298554e75c2a74b"
-sysroot_ehpic_sha256 = "2ddbdc145ca8278c0599afdfe10218d1cf88571bf1a8d5dfe95e05becb6a0429"
-sysroot_exnref_eh_sha256 = "612f5c94c8d5972279b8f5728342f238b9da7a2ecc8ce5fb86090295f7a87026"
-sysroot_exnref_ehpic_sha256 = "bff94209738358f50f18c85b9446d84a65282690826ad88cc6b67d1795d9ce2f"
-
-[toolchain.llvm]
-release = "21.1.204"
-reported_version = "21.1.2"
-asset = "LLVM-Linux-x86_64.tar.gz"
-sha256 = "a94a2e550aea0081b31005e9fe18cacda4606c4cb98bc557b12f13cb0c06f6e2"
-
-[toolchain.binaryen]
-release = "version_130"
-reported_version = "130"
-asset = "binaryen-version_130-x86_64-linux.tar.gz"
-sha256 = "0a18362361ad05465118cd8eeb72edaeec89de6894bc283576ef4e07aa3babcc"
-
-[builder]
-base_image = "ubuntu:24.04"
-base_image_digest = "sha256:c4a8d5503dfb2a3eb8ab5f807da5bc69a85730fb49b5cfca2330194ebcc41c7b"
-dockerfile_frontend = "docker/dockerfile:1.7@sha256:a57df69d0ea827fb7266491f2813635de6f17269be881f696fbfdf2d83dda33e"
-apt_snapshot = "20260715T000000Z"
-apt_snapshot_retention = "Ubuntu documents archive snapshots as available for at least two years. Preserve or advance this pin through an explicitly qualified toolchain update before that retention window expires."
-snapshot_tls_root = "src/runtimes/liboliphaunt/wasix/assets/build/docker/isrg-root-x1.pem"
-snapshot_tls_root_sha256 = "22b557a27055b33606b6559f37703928d3e4ad79f110b407d04986e1843543d1"
-snapshot_tls_root_not_after = "2035-06-04T11:04:38Z"
-
-[build]
-postgres_prefix = "/"
-postgres_pkglibdir = "/lib/postgresql"
-postgres_sharedir = "/share/postgresql"
-main_flags = ["-fwasm-exceptions"]
-extension_flags = ["-fwasm-exceptions", "-fPIC", "-Wl,-shared"]
-archive_format = "tar.zst"
-deterministic_archives = true
diff --git a/src/sources/tools/fetch-sources.mjs b/src/sources/tools/fetch-sources.mjs
deleted file mode 100755
index feb458469..000000000
--- a/src/sources/tools/fetch-sources.mjs
+++ /dev/null
@@ -1,545 +0,0 @@
-#!/usr/bin/env bun
-import {X509Certificate, createHash} from 'node:crypto';
-import {existsSync, readdirSync, readFileSync} from 'node:fs';
-import {dirname, join, resolve} from 'node:path';
-import {fileURLToPath} from 'node:url';
-
-import {assertHttpsUrl, createSourceFetcher} from './source-fetch-core.mjs';
-import {
-  defaultSourceScope,
-  scopeIncludes,
-  scopeIncludesExtensions,
-  scopeIncludesWasix,
-  sourceDomainsForScope,
-  sourceOrigins,
-  sourceScopes,
-} from './source-fetch-scopes.mjs';
-import {auditExtensionUpstreamLicenseSources} from '../../../tools/release/extension-upstream-licenses.mjs';
-
-const workspaceRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
-process.chdir(workspaceRoot);
-
-const sourceCheckoutRoot = join(workspaceRoot, 'target', 'oliphaunt-sources', 'checkouts');
-const sourceArchiveRoot = join(workspaceRoot, 'target', 'oliphaunt-sources', 'archives');
-const sourceFetcher = createSourceFetcher({
-  workspaceRoot,
-  checkoutRoot: sourceCheckoutRoot,
-  archiveRoot: sourceArchiveRoot,
-});
-const allowedScopes = new Set(sourceScopes);
-
-const {scope, force, validateOnly, verifyOnly} = parseArgs(process.argv.slice(2));
-if (!allowedScopes.has(scope)) {
-  fail(`unsupported source fetch scope '${scope}'; expected one of: ${[...allowedScopes].join(', ')}`, 2);
-}
-
-if (
-  !validateOnly &&
-  !verifyOnly &&
-  !force &&
-  process.env.CI !== 'true' &&
-  process.env.OLIPHAUNT_FETCH_SOURCES !== '1'
-) {
-  console.log(
-    `source checkout fetch skipped outside CI for scope '${scope}'; set OLIPHAUNT_FETCH_SOURCES=1 or pass --force to refresh pinned checkouts with Bun`,
-  );
-  process.exit(0);
-}
-
-try {
-  const manifest = loadSourcesManifest(scope);
-  validateSourcesManifest(manifest, scope);
-  if (!validateOnly) {
-    await fetchManifestSources(manifest, scope, verifyOnly);
-  }
-} catch (error) {
-  fail(error instanceof Error ? error.message : String(error));
-}
-
-function parseArgs(args) {
-  let selectedScope = defaultSourceScope;
-  let sawScope = false;
-  let forceFetch = false;
-  let validateOnly = false;
-  let verifyOnly = false;
-  for (const arg of args) {
-    if (arg === '--force') {
-      forceFetch = true;
-      continue;
-    }
-    if (arg === '--verify-only') {
-      verifyOnly = true;
-      continue;
-    }
-    if (arg === '--validate-only') {
-      validateOnly = true;
-      continue;
-    }
-    if (arg === '--help' || arg === '-h') {
-      console.log(
-        `usage: bun src/sources/tools/fetch-sources.mjs [${sourceScopes.join('|')}] [--force|--validate-only|--verify-only]`,
-      );
-      process.exit(0);
-    }
-    if (sawScope) {
-      fail(`unexpected argument '${arg}'`, 2);
-    }
-    selectedScope = arg;
-    sawScope = true;
-  }
-  if (Number(forceFetch) + Number(validateOnly) + Number(verifyOnly) > 1) {
-    fail('--force, --validate-only, and --verify-only are mutually exclusive', 2);
-  }
-  return {scope: selectedScope, force: forceFetch, validateOnly, verifyOnly};
-}
-
-function loadSourcesManifest(selectedScope) {
-  const sources = [];
-  const names = new Set();
-  const thirdPartyRoot = join(workspaceRoot, 'src', 'sources', 'third-party');
-  for (const [domain, origin] of sourceDomainsForScope(selectedScope)) {
-    const domainDir = join(thirdPartyRoot, domain);
-    if (!existsSync(domainDir)) {
-      continue;
-    }
-    for (const file of readdirSync(domainDir).sort()) {
-      if (!file.endsWith('.toml')) {
-        continue;
-      }
-      pushSourcePin(sources, names, join(domainDir, file), origin);
-    }
-  }
-  if (scopeIncludesExtensions(selectedScope)) {
-    for (const sourcePath of extensionSourcePinPaths()) {
-      pushSourcePin(sources, names, sourcePath, sourceOrigins.extension);
-    }
-  }
-  return {sources, ...(scopeIncludesWasix(selectedScope) ? readToml('src/sources/toolchains/wasix.toml') : {})};
-}
-
-function extensionSourcePinPaths() {
-  const root = join(workspaceRoot, 'src', 'extensions', 'external');
-  const paths = [];
-  collectSourcePins(root, paths);
-  return paths.sort();
-}
-
-function collectSourcePins(dir, paths) {
-  if (!existsSync(dir)) {
-    return;
-  }
-  for (const entry of readdirSync(dir, {withFileTypes: true}).sort((left, right) =>
-    left.name < right.name ? -1 : left.name > right.name ? 1 : 0,
-  )) {
-    const path = join(dir, entry.name);
-    if (entry.isDirectory()) {
-      collectSourcePins(path, paths);
-    } else if (entry.name === 'source.toml') {
-      paths.push(path);
-    }
-  }
-}
-
-function pushSourcePin(sources, names, path, origin) {
-  const raw = readToml(path);
-  const source = {
-    name: stringField(raw, 'name', path),
-    kind: raw.kind ?? 'git',
-    url: stringField(raw, 'url', path),
-    mirrorUrl: optionalStringField(raw, 'mirror_url', path),
-    branch: stringField(raw, 'branch', path),
-    commit: stringField(raw, 'commit', path),
-    sha256: optionalStringField(raw, 'sha256', path),
-    stripPrefix: optionalStringField(raw, 'strip_prefix', path) ?? optionalStringField(raw, 'strip-prefix', path),
-    origin,
-  };
-  if (names.has(source.name)) {
-    throw new Error(`duplicate source pin '${source.name}' in source metadata`);
-  }
-  names.add(source.name);
-  sources.push(source);
-}
-
-function readToml(path) {
-  const text = readFileSync(path, 'utf8');
-  try {
-    return Bun.TOML.parse(text);
-  } catch (error) {
-    throw new Error(`parse ${path}: ${error instanceof Error ? error.message : String(error)}`);
-  }
-}
-
-function stringField(object, field, path) {
-  const value = object[field];
-  if (typeof value !== 'string' || value.trim() === '') {
-    throw new Error(`${path} must set non-empty string field '${field}'`);
-  }
-  return value;
-}
-
-function optionalStringField(object, field, path) {
-  const value = object[field];
-  if (value === undefined) {
-    return undefined;
-  }
-  if (typeof value !== 'string') {
-    throw new Error(`${path} field '${field}' must be a string`);
-  }
-  return value;
-}
-
-function validateSourcesManifest(manifest, selectedScope) {
-  if (!Array.isArray(manifest.sources) || manifest.sources.length === 0) {
-    throw new Error('source metadata must contain at least one source pin');
-  }
-  if (scopeIncludesWasix(selectedScope)) {
-    validateWasixToolchain(manifest);
-  }
-  for (const source of manifest.sources) {
-    validateSourcePin(source);
-  }
-}
-
-function validateWasixToolchain(manifest) {
-  assertEquals(manifest.toolchain?.wasmer, '7.2.1', 'toolchain.wasmer');
-  assertEquals(manifest.toolchain?.['wasmer-wasix'], '0.702.1', 'toolchain.wasmer-wasix');
-  assertEquals(manifest.toolchain?.webc, '12.0.0', 'toolchain.webc');
-  assertEquals(manifest.toolchain?.wasmer_llvm, '22.1', 'toolchain.wasmer_llvm');
-  assertEquals(manifest.toolchain?.wasixcc?.version, '0.4.3', 'toolchain.wasixcc.version');
-  assertEquals(
-    manifest.toolchain?.wasixcc?.target,
-    'x86_64-unknown-linux-gnu',
-    'toolchain.wasixcc.target',
-  );
-  assertEquals(manifest.toolchain?.sysroots?.version, '2026-03-02.1', 'toolchain.sysroots.version');
-  assertEquals(manifest.toolchain?.llvm?.release, '21.1.204', 'toolchain.llvm.release');
-  assertEquals(manifest.toolchain?.llvm?.reported_version, '21.1.2', 'toolchain.llvm.reported_version');
-  assertEquals(manifest.toolchain?.binaryen?.release, 'version_130', 'toolchain.binaryen.release');
-  assertEquals(manifest.toolchain?.binaryen?.reported_version, '130', 'toolchain.binaryen.reported_version');
-
-  const assetsManifest = manifest.toolchain?.assets_manifest;
-  assertEquals(
-    assetsManifest,
-    'src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv',
-    'toolchain.assets_manifest',
-  );
-  const assetsManifestSha256 = manifest.toolchain?.assets_manifest_sha256;
-  if (typeof assetsManifestSha256 !== 'string' || !/^[0-9a-f]{64}$/.test(assetsManifestSha256)) {
-    throw new Error(
-      `toolchain.assets_manifest_sha256 must pin a lowercase sha256 digest, got ${assetsManifestSha256}`,
-    );
-  }
-  const assetsManifestPath = join(workspaceRoot, ...assetsManifest.split('/'));
-  assertEquals(sha256File(assetsManifestPath), assetsManifestSha256, 'toolchain assets manifest SHA-256');
-  const assetRows = new Map(
-    readFileSync(assetsManifestPath, 'utf8')
-      .split(/\r?\n/u)
-      .filter((line) => line !== '' && !line.startsWith('#'))
-      .map((line) => {
-        const fields = line.split('\t');
-        if (fields.length !== 5) {
-          throw new Error(`invalid WASIX toolchain asset row: ${line}`);
-        }
-        return [fields[1], fields[3]];
-      }),
-  );
-  const expectedAssets = [
-    [manifest.toolchain?.wasixcc?.asset, manifest.toolchain?.wasixcc?.sha256],
-    ['sysroot.tar.gz', manifest.toolchain?.sysroots?.sysroot_sha256],
-    ['sysroot-eh.tar.gz', manifest.toolchain?.sysroots?.sysroot_eh_sha256],
-    ['sysroot-ehpic.tar.gz', manifest.toolchain?.sysroots?.sysroot_ehpic_sha256],
-    ['sysroot-exnref-eh.tar.gz', manifest.toolchain?.sysroots?.sysroot_exnref_eh_sha256],
-    ['sysroot-exnref-ehpic.tar.gz', manifest.toolchain?.sysroots?.sysroot_exnref_ehpic_sha256],
-    [manifest.toolchain?.llvm?.asset, manifest.toolchain?.llvm?.sha256],
-    [manifest.toolchain?.binaryen?.asset, manifest.toolchain?.binaryen?.sha256],
-  ];
-  for (const [asset, expectedSha256] of expectedAssets) {
-    if (typeof expectedSha256 !== 'string' || !/^[0-9a-f]{64}$/.test(expectedSha256)) {
-      throw new Error(`${asset ?? ''} metadata must pin a lowercase sha256 digest`);
-    }
-    assertEquals(assetRows.get(asset), expectedSha256, `toolchain asset ${asset}`);
-  }
-
-  assertEquals(manifest.builder?.base_image, 'ubuntu:24.04', 'builder.base_image');
-  const baseDigest = manifest.builder?.base_image_digest;
-  if (typeof baseDigest !== 'string' || !/^sha256:[0-9a-f]{64}$/.test(baseDigest)) {
-    throw new Error(`builder.base_image_digest must pin a concrete sha256 digest, got ${baseDigest}`);
-  }
-  const aptSnapshot = manifest.builder?.apt_snapshot;
-  if (typeof aptSnapshot !== 'string' || !/^\d{8}T\d{6}Z$/u.test(aptSnapshot)) {
-    throw new Error(`builder.apt_snapshot must be a fixed YYYYMMDDTHHMMSSZ timestamp, got ${aptSnapshot}`);
-  }
-  if (typeof manifest.builder?.apt_snapshot_retention !== 'string' || manifest.builder.apt_snapshot_retention === '') {
-    throw new Error('builder.apt_snapshot_retention must document the snapshot retention boundary');
-  }
-  const dockerfileFrontend = manifest.builder?.dockerfile_frontend;
-  if (
-    typeof dockerfileFrontend !== 'string' ||
-    !/^docker\/dockerfile:[0-9]+(?:\.[0-9]+){1,2}@sha256:[0-9a-f]{64}$/u.test(dockerfileFrontend)
-  ) {
-    throw new Error(
-      `builder.dockerfile_frontend must pin a versioned Dockerfile frontend by lowercase sha256 digest, got ${dockerfileFrontend}`,
-    );
-  }
-  const snapshotTlsRoot = manifest.builder?.snapshot_tls_root;
-  if (
-    typeof snapshotTlsRoot !== 'string' ||
-    !/^src\/runtimes\/liboliphaunt\/wasix\/assets\/build\/docker\/[A-Za-z0-9._-]+\.pem$/u.test(
-      snapshotTlsRoot,
-    )
-  ) {
-    throw new Error(
-      `builder.snapshot_tls_root must name a PEM file in the WASIX Docker build inputs, got ${snapshotTlsRoot}`,
-    );
-  }
-  const snapshotTlsRootSha256 = manifest.builder?.snapshot_tls_root_sha256;
-  if (typeof snapshotTlsRootSha256 !== 'string' || !/^[0-9a-f]{64}$/u.test(snapshotTlsRootSha256)) {
-    throw new Error(
-      `builder.snapshot_tls_root_sha256 must pin a lowercase sha256 digest, got ${snapshotTlsRootSha256}`,
-    );
-  }
-  const snapshotTlsRootNotAfter = manifest.builder?.snapshot_tls_root_not_after;
-  if (
-    typeof snapshotTlsRootNotAfter !== 'string' ||
-    !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/u.test(snapshotTlsRootNotAfter)
-  ) {
-    throw new Error(
-      `builder.snapshot_tls_root_not_after must be an exact UTC timestamp, got ${snapshotTlsRootNotAfter}`,
-    );
-  }
-  const snapshotTlsRootPath = join(workspaceRoot, ...snapshotTlsRoot.split('/'));
-  assertEquals(
-    sha256File(snapshotTlsRootPath),
-    snapshotTlsRootSha256,
-    'builder snapshot TLS root SHA-256',
-  );
-  let snapshotTlsCertificate;
-  try {
-    snapshotTlsCertificate = new X509Certificate(readFileSync(snapshotTlsRootPath));
-  } catch (error) {
-    throw new Error(
-      `builder.snapshot_tls_root must contain a valid X.509 certificate: ${error instanceof Error ? error.message : String(error)}`,
-    );
-  }
-  if (!snapshotTlsCertificate.ca) {
-    throw new Error('builder.snapshot_tls_root must contain a CA certificate');
-  }
-  if (
-    snapshotTlsCertificate.issuer !== snapshotTlsCertificate.subject ||
-    !snapshotTlsCertificate.verify(snapshotTlsCertificate.publicKey)
-  ) {
-    throw new Error('builder.snapshot_tls_root must contain a self-signed trust root');
-  }
-  const certificateNotAfter = snapshotTlsCertificate.validToDate;
-  if (!(certificateNotAfter instanceof Date) || Number.isNaN(certificateNotAfter.getTime())) {
-    throw new Error('builder.snapshot_tls_root certificate must expose a valid notAfter timestamp');
-  }
-  assertEquals(
-    certificateNotAfter.toISOString().replace(/\.000Z$/u, 'Z'),
-    snapshotTlsRootNotAfter,
-    'builder.snapshot_tls_root_not_after',
-  );
-  const dockerfile = readFileSync(
-    join(workspaceRoot, 'src', 'runtimes', 'liboliphaunt', 'wasix', 'assets', 'build', 'docker', 'Dockerfile'),
-    'utf8',
-  );
-  const aptInstaller = readFileSync(
-    join(workspaceRoot, 'src', 'runtimes', 'liboliphaunt', 'wasix', 'assets', 'build', 'docker', 'install-pinned-apt-packages.sh'),
-    'utf8',
-  );
-  if (!dockerfile.includes(`FROM ${manifest.builder.base_image}@${baseDigest}`)) {
-    throw new Error(
-      'WASIX build Dockerfile must pin the same builder base image digest as src/sources/toolchains/wasix.toml',
-    );
-  }
-  if (dockerfile.split(/\r?\n/u, 1)[0] !== `# syntax=${dockerfileFrontend}`) {
-    throw new Error('WASIX build Dockerfile must pin the declared Dockerfile frontend digest');
-  }
-  if (!dockerfile.includes(`OLIPHAUNT_WASIXCC_ASSET_MANIFEST_SHA256=${assetsManifestSha256}`)) {
-    throw new Error('WASIX build Dockerfile must pin the toolchain asset manifest SHA-256');
-  }
-  if (
-    !dockerfile.includes(`OLIPHAUNT_UBUNTU_APT_SNAPSHOT=${aptSnapshot}`) ||
-    !dockerfile.includes('COPY --chmod=0555 install-pinned-apt-packages.sh') ||
-    !dockerfile.includes('--snapshot "$OLIPHAUNT_UBUNTU_APT_SNAPSHOT"') ||
-    !aptInstaller.includes('https://snapshot.ubuntu.com/ubuntu/$snapshot') ||
-    !aptInstaller.includes('APT::Update::Error-Mode=any') ||
-    !aptInstaller.includes('Acquire::https::CaInfo="$ca_bundle"') ||
-    !aptInstaller.includes('install_transaction "builder package" ca-certificates')
-  ) {
-    throw new Error(
-      'WASIX builder must use the declared minimal Ubuntu snapshot through its fail-closed pinned APT installer',
-    );
-  }
-  if (
-    !dockerfile.includes(`OLIPHAUNT_UBUNTU_SNAPSHOT_TLS_ROOT_SHA256=${snapshotTlsRootSha256}`) ||
-    !dockerfile.includes(
-      'COPY --chmod=0444 isrg-root-x1.pem /usr/local/share/oliphaunt/isrg-root-x1.pem',
-    ) ||
-    !dockerfile.includes('/etc/ssl/certs/ca-certificates.crt') ||
-    !dockerfile.includes('sha256sum --check --strict')
-  ) {
-    throw new Error('WASIX build Dockerfile must verify and install the declared snapshot TLS root');
-  }
-  if (dockerfile.includes('Verify-Peer=false') || aptInstaller.includes('Verify-Peer=false')) {
-    throw new Error('WASIX snapshot acquisition must not disable TLS peer verification');
-  }
-  for (const forbidden of ['raw.githubusercontent.com/wasix-org/wasixcc', 'latest']) {
-    if (dockerfile.includes(forbidden)) {
-      throw new Error(`WASIX build Dockerfile contains forbidden mutable installer input ${forbidden}`);
-    }
-  }
-  assertEquals(manifest.build?.postgres_prefix, '/', 'build.postgres_prefix');
-  assertEquals(manifest.build?.postgres_pkglibdir, '/lib/postgresql', 'build.postgres_pkglibdir');
-  assertEquals(manifest.build?.postgres_sharedir, '/share/postgresql', 'build.postgres_sharedir');
-  assertIncludes(manifest.build?.main_flags, '-fwasm-exceptions', 'build.main_flags');
-  assertNoFlagContains(manifest.build?.main_flags, 'asyncify', 'build.main_flags');
-  assertIncludes(manifest.build?.extension_flags, '-fwasm-exceptions', 'build.extension_flags');
-  assertNoFlagContains(manifest.build?.extension_flags, 'asyncify', 'build.extension_flags');
-  assertIncludes(manifest.build?.extension_flags, '-fPIC', 'build.extension_flags');
-  assertIncludes(manifest.build?.extension_flags, '-Wl,-shared', 'build.extension_flags');
-  assertEquals(manifest.build?.archive_format, 'tar.zst', 'build.archive_format');
-  if (manifest.build?.deterministic_archives !== true) {
-    throw new Error('build.deterministic_archives must be true');
-  }
-}
-
-function validateSourcePin(source) {
-  if (!validSourceNameComponent(source.name) || source.branch.trim() === '') {
-    throw new Error(`invalid source pin in source metadata: ${JSON.stringify(source)}`);
-  }
-  const parsedUrl = assertHttpsUrl(source.url, `source '${source.name}' URL`);
-  const parsedMirrorUrl = source.mirrorUrl === undefined
-    ? undefined
-    : assertHttpsUrl(source.mirrorUrl, `source '${source.name}' mirror URL`);
-  if (!['git', 'archive'].includes(source.kind)) {
-    throw new Error(`source '${source.name}' has unsupported kind '${source.kind}'`);
-  }
-  if (source.kind === 'git') {
-    if (!/^[0-9a-f]{40}$/u.test(source.commit)) {
-      throw new Error(`git source '${source.name}' commit must be an exact lowercase 40-hex revision`);
-    }
-    if (source.sha256 !== undefined || source.stripPrefix !== undefined) {
-      throw new Error(`git source '${source.name}' must not set sha256 or strip-prefix`);
-    }
-    if (parsedMirrorUrl?.href === parsedUrl.href) {
-      throw new Error(`git source '${source.name}' mirror URL must differ from its primary URL`);
-    }
-    return;
-  }
-  if (parsedMirrorUrl !== undefined) {
-    throw new Error(`archive source '${source.name}' must not set mirror_url`);
-  }
-  const sha256 = archiveSha256(source);
-  archiveStripPrefix(source);
-  assertEquals(source.commit, sha256, `${source.name} archive commit must equal archive sha256`);
-  if (
-    !parsedUrl.pathname.endsWith('.tar.gz') &&
-    !parsedUrl.pathname.endsWith('.tgz') &&
-    !parsedUrl.pathname.endsWith('.zip')
-  ) {
-    throw new Error(`archive source '${source.name}' must point at a .tar.gz, .tgz, or .zip URL`);
-  }
-  if (source.stripPrefix === '.' && !parsedUrl.pathname.endsWith('.zip')) {
-    throw new Error(`archive source '${source.name}' may use a rootless strip prefix only for ZIP releases`);
-  }
-}
-
-async function fetchManifestSources(manifest, selectedScope, verifyOnly) {
-  let selectedExtensionSources = 0;
-  for (const source of manifest.sources) {
-    if (!scopeIncludes(selectedScope, source.origin)) {
-      console.error(`skipping source '${source.name}' for selected source lane`);
-      continue;
-    }
-    const checkoutPath = sourceCheckoutPath(source.name);
-    if (checkoutPath === undefined) {
-      console.error(`warning: source '${source.name}' has no configured checkout path; skipping fetch`);
-      continue;
-    }
-    if (verifyOnly) {
-      sourceFetcher.verify(source, checkoutPath);
-    } else {
-      await sourceFetcher.materialize(source, checkoutPath);
-    }
-    if (source.origin === sourceOrigins.extension) {
-      selectedExtensionSources += 1;
-    }
-  }
-  if (selectedExtensionSources > 0) {
-    const auditedFiles = auditExtensionUpstreamLicenseSources();
-    if (!Number.isSafeInteger(auditedFiles) || auditedFiles < 1) {
-      throw new Error('extension upstream legal source audit did not inspect any pinned files');
-    }
-    console.error(
-      `audited ${auditedFiles} pinned extension legal source files after qualifying ${selectedExtensionSources} extension source checkouts`,
-    );
-  }
-}
-
-function archiveSha256(source) {
-  if (source.sha256 === undefined || !/^[0-9a-f]{64}$/u.test(source.sha256)) {
-    throw new Error(`archive source '${source.name}' has invalid sha256 ${source.sha256}`);
-  }
-  return source.sha256;
-}
-
-function archiveStripPrefix(source) {
-  if (
-    source.stripPrefix === undefined ||
-    (source.stripPrefix !== '.' &&
-      (!/^[A-Za-z0-9][A-Za-z0-9._+-]*$/u.test(source.stripPrefix) ||
-        source.stripPrefix.includes('..'))) ||
-    source.stripPrefix.startsWith('/')
-  ) {
-    throw new Error(`archive source '${source.name}' has invalid strip-prefix`);
-  }
-  return source.stripPrefix;
-}
-
-function sourceCheckoutPath(name) {
-  return validSourceNameComponent(name) ? join(sourceCheckoutRoot, name) : undefined;
-}
-
-function validSourceNameComponent(name) {
-  return (
-    typeof name === 'string' &&
-    name !== '' &&
-    !name.includes('..') &&
-    !name.includes('/') &&
-    !name.includes('\\') &&
-    /^[A-Za-z0-9._-]+$/.test(name)
-  );
-}
-
-function sha256File(path) {
-  const hash = createHash('sha256');
-  hash.update(readFileSync(path));
-  return hash.digest('hex');
-}
-
-function assertEquals(actual, expected, name) {
-  if (actual !== expected) {
-    throw new Error(`${name}: expected ${expected}, got ${actual}`);
-  }
-}
-
-function assertIncludes(values, expected, name) {
-  if (!Array.isArray(values) || !values.includes(expected)) {
-    throw new Error(`${name} must contain ${expected}`);
-  }
-}
-
-function assertNoFlagContains(values, needle, name) {
-  if (!Array.isArray(values)) {
-    throw new Error(`${name} must be an array`);
-  }
-  if (values.some((value) => typeof value === 'string' && value.includes(needle))) {
-    throw new Error(`${name} must not contain ${needle}`);
-  }
-}
-
-function fail(message, code = 1) {
-  console.error(message);
-  process.exit(code);
-}
diff --git a/src/sources/tools/source-archive.py b/src/sources/tools/source-archive.py
deleted file mode 100755
index d7afbf2ab..000000000
--- a/src/sources/tools/source-archive.py
+++ /dev/null
@@ -1,334 +0,0 @@
-#!/usr/bin/env python3
-"""Validate and extract a pinned .tar.gz source archive safely.
-
-The standard tar CLI intentionally accepts archive features that are unsafe for
-an unattended source bootstrap.  This helper implements the much smaller
-archive format Oliphaunt needs: one explicitly pinned root containing regular
-files, directories, and links that remain inside that root.
-"""
-
-from __future__ import annotations
-
-import argparse
-import os
-import posixpath
-import shutil
-import stat
-import sys
-import tarfile
-import unicodedata
-from dataclasses import dataclass
-from pathlib import Path, PurePosixPath
-
-
-MAX_MEMBERS = 200_000
-MAX_MEMBER_BYTES = 2 * 1024 * 1024 * 1024
-MAX_EXPANDED_BYTES = 4 * 1024 * 1024 * 1024
-MAX_EXPANSION_RATIO = 200
-MIN_EXPANSION_ALLOWANCE = 64 * 1024 * 1024
-COPY_CHUNK_BYTES = 1024 * 1024
-RESERVED_ROOT_ENTRIES = {".git", ".oliphaunt-source-pin"}
-WINDOWS_RESERVED_NAMES = {
-    "con",
-    "prn",
-    "aux",
-    "nul",
-    *(f"com{index}" for index in range(1, 10)),
-    *(f"lpt{index}" for index in range(1, 10)),
-}
-
-
-class UnsafeArchive(ValueError):
-    pass
-
-
-@dataclass(frozen=True)
-class CheckedMember:
-    info: tarfile.TarInfo
-    relative: str
-    link_target: str | None = None
-
-
-def _reject_control_characters(value: str, label: str) -> None:
-    if any(ord(character) < 32 or ord(character) == 127 for character in value):
-        raise UnsafeArchive(f"{label} contains a control character")
-
-
-def _validate_prefix(prefix: str) -> None:
-    _validate_member_name(prefix, "strip prefix")
-    if "/" in prefix:
-        raise UnsafeArchive("strip prefix must be one portable top-level directory name")
-
-
-def _validate_member_name(name: str, label: str) -> tuple[str, ...]:
-    if not name:
-        raise UnsafeArchive(f"{label} is empty")
-    _reject_control_characters(name, label)
-    if "\\" in name:
-        raise UnsafeArchive(f"{label} contains a backslash")
-    if name.startswith("/") or (len(name) >= 2 and name[1] == ":"):
-        raise UnsafeArchive(f"{label} is absolute")
-
-    normalized = name[:-1] if name.endswith("/") else name
-    parts = tuple(normalized.split("/"))
-    if not normalized or any(part in {"", ".", ".."} for part in parts):
-        raise UnsafeArchive(f"{label} contains an empty, dot, or traversal component")
-    if len(normalized.encode("utf-8")) > 4096:
-        raise UnsafeArchive(f"{label} exceeds the portable path-length limit")
-    for part in parts:
-        if len(part.encode("utf-8")) > 255:
-            raise UnsafeArchive(f"{label} has an oversized path component")
-        if ":" in part or part.endswith((" ", ".")):
-            raise UnsafeArchive(f"{label} is not portable to Windows filesystems")
-        if part.split(".", 1)[0].casefold() in WINDOWS_RESERVED_NAMES:
-            raise UnsafeArchive(f"{label} uses a reserved Windows device name")
-    return parts
-
-
-def _member_relative_path(name: str, prefix: str) -> str:
-    parts = _validate_member_name(name, f"archive member {name!r}")
-    if parts[0] != prefix:
-        raise UnsafeArchive(
-            f"archive member {name!r} is outside required root {prefix!r}"
-        )
-    return "/".join(parts[1:])
-
-
-def _resolve_link_target(info: tarfile.TarInfo, prefix: str) -> str:
-    target = info.linkname
-    if not target:
-        raise UnsafeArchive(f"archive link {info.name!r} has an empty target")
-    _reject_control_characters(target, f"archive link target for {info.name!r}")
-    if "\\" in target:
-        raise UnsafeArchive(f"archive link {info.name!r} has a backslash target")
-    if target.startswith("/") or (len(target) >= 2 and target[1] == ":"):
-        raise UnsafeArchive(f"archive link {info.name!r} has an absolute target")
-
-    if info.issym():
-        combined = posixpath.join(posixpath.dirname(info.name), target)
-    else:
-        combined = target
-    normalized = posixpath.normpath(combined)
-    if normalized in {"", ".", ".."} or normalized.startswith("../"):
-        raise UnsafeArchive(f"archive link {info.name!r} escapes the archive root")
-    relative = _member_relative_path(normalized, prefix)
-    if relative == "":
-        raise UnsafeArchive(f"archive link {info.name!r} targets the archive root")
-    return relative
-
-
-def checked_members(archive: Path, prefix: str) -> list[CheckedMember]:
-    _validate_prefix(prefix)
-    if not archive.is_file():
-        raise UnsafeArchive(f"archive does not exist: {archive}")
-
-    compressed_bytes = archive.stat().st_size
-    expanded_limit = min(
-        MAX_EXPANDED_BYTES,
-        max(MIN_EXPANSION_ALLOWANCE, compressed_bytes * MAX_EXPANSION_RATIO),
-    )
-    checked: list[CheckedMember] = []
-    by_path: dict[str, tarfile.TarInfo] = {}
-    portable_paths: dict[str, str] = {}
-    expanded_bytes = 0
-
-    try:
-        stream = tarfile.open(archive, mode="r:gz")
-    except (OSError, tarfile.TarError) as error:
-        raise UnsafeArchive(f"cannot open gzip tar archive: {error}") from error
-
-    with stream:
-        try:
-            for index, info in enumerate(stream, start=1):
-                if index > MAX_MEMBERS:
-                    raise UnsafeArchive(
-                        f"archive contains more than {MAX_MEMBERS} members"
-                    )
-                relative = _member_relative_path(info.name, prefix)
-                if relative.split("/", 1)[0] in RESERVED_ROOT_ENTRIES:
-                    raise UnsafeArchive(
-                        f"archive member {info.name!r} uses a reserved source-spine path"
-                    )
-                if relative in by_path:
-                    raise UnsafeArchive(f"archive contains duplicate path {info.name!r}")
-                portable_key = unicodedata.normalize("NFC", relative).casefold()
-                if portable_key in portable_paths:
-                    raise UnsafeArchive(
-                        f"archive paths {portable_paths[portable_key]!r} and {info.name!r} collide on a portable filesystem"
-                    )
-                portable_paths[portable_key] = info.name
-                if info.mode & (stat.S_ISUID | stat.S_ISGID):
-                    raise UnsafeArchive(f"archive member {info.name!r} has set-id mode bits")
-                if not (info.isdir() or info.isreg() or info.issym() or info.islnk()):
-                    raise UnsafeArchive(
-                        f"archive member {info.name!r} has unsupported type {info.type!r}"
-                    )
-                if info.isreg():
-                    if info.size < 0 or info.size > MAX_MEMBER_BYTES:
-                        raise UnsafeArchive(
-                            f"archive member {info.name!r} exceeds the per-file size limit"
-                        )
-                    expanded_bytes += info.size
-                    if expanded_bytes > expanded_limit:
-                        raise UnsafeArchive(
-                            "archive exceeds the bounded expanded-size allowance "
-                            f"({expanded_limit} bytes)"
-                        )
-
-                link_target = (
-                    _resolve_link_target(info, prefix)
-                    if info.issym() or info.islnk()
-                    else None
-                )
-                by_path[relative] = info
-                checked.append(CheckedMember(info, relative, link_target))
-        except (OSError, tarfile.TarError) as error:
-            raise UnsafeArchive(f"cannot read gzip tar archive: {error}") from error
-
-    if not checked:
-        raise UnsafeArchive("archive is empty")
-
-    for member in checked:
-        relative = member.relative
-        if relative:
-            parts = PurePosixPath(relative).parts
-            for depth in range(1, len(parts)):
-                ancestor = "/".join(parts[:depth])
-                ancestor_info = by_path.get(ancestor)
-                if ancestor_info is not None and not ancestor_info.isdir():
-                    raise UnsafeArchive(
-                        f"archive path {member.info.name!r} descends through non-directory {ancestor!r}"
-                    )
-        if member.link_target is not None:
-            target = by_path.get(member.link_target)
-            if target is None:
-                raise UnsafeArchive(
-                    f"archive link {member.info.name!r} has missing target {member.info.linkname!r}"
-                )
-            if member.info.islnk() and not target.isreg():
-                raise UnsafeArchive(
-                    f"archive hard link {member.info.name!r} does not target a regular file"
-                )
-
-    return checked
-
-
-def _safe_parent(destination: Path, relative: str) -> Path:
-    parent = destination.joinpath(*PurePosixPath(relative).parts).parent
-    current = destination
-    for part in parent.relative_to(destination).parts:
-        current = current / part
-        if current.exists() or current.is_symlink():
-            mode = current.lstat().st_mode
-            if not stat.S_ISDIR(mode) or stat.S_ISLNK(mode):
-                raise UnsafeArchive(f"extraction ancestor is not a real directory: {current}")
-        else:
-            current.mkdir(mode=0o755)
-    return parent
-
-
-def extract_archive(archive: Path, destination: Path, prefix: str) -> None:
-    members = checked_members(archive, prefix)
-    if destination.exists() or destination.is_symlink():
-        raise UnsafeArchive(f"extraction destination already exists: {destination}")
-    destination.parent.mkdir(parents=True, exist_ok=True)
-    destination.mkdir(mode=0o755)
-
-    try:
-        with tarfile.open(archive, mode="r:gz") as stream:
-            by_name = {member.info.name: member.info for member in members}
-            for member in members:
-                relative = member.relative
-                if relative == "" or member.info.issym() or member.info.islnk():
-                    continue
-                output = destination.joinpath(*PurePosixPath(relative).parts)
-                _safe_parent(destination, relative)
-                if member.info.isdir():
-                    if output.exists() or output.is_symlink():
-                        if not output.is_dir() or output.is_symlink():
-                            raise UnsafeArchive(f"cannot create archive directory {relative!r}")
-                    else:
-                        output.mkdir(mode=(member.info.mode & 0o755) | 0o700)
-                    continue
-
-                source_info = by_name[member.info.name]
-                source = stream.extractfile(source_info)
-                if source is None:
-                    raise UnsafeArchive(f"cannot read archive file {member.info.name!r}")
-                flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
-                if hasattr(os, "O_NOFOLLOW"):
-                    flags |= os.O_NOFOLLOW
-                descriptor = os.open(output, flags, (member.info.mode & 0o755) | 0o600)
-                copied = 0
-                try:
-                    with source, os.fdopen(descriptor, "wb") as sink:
-                        descriptor = -1
-                        while True:
-                            block = source.read(COPY_CHUNK_BYTES)
-                            if not block:
-                                break
-                            copied += len(block)
-                            if copied > member.info.size:
-                                raise UnsafeArchive(
-                                    f"archive file {member.info.name!r} exceeded declared size"
-                                )
-                            sink.write(block)
-                finally:
-                    if descriptor >= 0:
-                        os.close(descriptor)
-                if copied != member.info.size:
-                    raise UnsafeArchive(
-                        f"archive file {member.info.name!r} was truncated during extraction"
-                    )
-
-            # Hard links first, then symlinks. Validation guarantees that link
-            # targets are members and no later member can descend through them.
-            for member in members:
-                if not member.info.islnk():
-                    continue
-                output = destination.joinpath(*PurePosixPath(member.relative).parts)
-                target = destination.joinpath(*PurePosixPath(member.link_target or "").parts)
-                _safe_parent(destination, member.relative)
-                os.link(target, output, follow_symlinks=False)
-            for member in members:
-                if not member.info.issym():
-                    continue
-                output = destination.joinpath(*PurePosixPath(member.relative).parts)
-                _safe_parent(destination, member.relative)
-                # Use the validated original relative spelling so symlink
-                # semantics are preserved without ever dereferencing it here.
-                os.symlink(member.info.linkname, output)
-    except BaseException:
-        shutil.rmtree(destination, ignore_errors=True)
-        raise
-
-
-def parse_args() -> argparse.Namespace:
-    parser = argparse.ArgumentParser()
-    parser.add_argument("mode", choices=("validate", "extract"))
-    parser.add_argument("archive", type=Path)
-    parser.add_argument("prefix")
-    parser.add_argument("destination", type=Path, nargs="?")
-    args = parser.parse_args()
-    if args.mode == "extract" and args.destination is None:
-        parser.error("extract requires a destination")
-    if args.mode == "validate" and args.destination is not None:
-        parser.error("validate does not accept a destination")
-    return args
-
-
-def main() -> int:
-    args = parse_args()
-    try:
-        if args.mode == "validate":
-            checked_members(args.archive, args.prefix)
-        else:
-            extract_archive(args.archive, args.destination, args.prefix)
-    except (OSError, UnsafeArchive, tarfile.TarError) as error:
-        print(f"unsafe source archive: {error}", file=sys.stderr)
-        return 1
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/sources/tools/source-fetch-core.mjs b/src/sources/tools/source-fetch-core.mjs
deleted file mode 100644
index b0f8c3f28..000000000
--- a/src/sources/tools/source-fetch-core.mjs
+++ /dev/null
@@ -1,1063 +0,0 @@
-import {createHash, randomUUID} from 'node:crypto';
-import {
-  closeSync,
-  lstatSync,
-  mkdirSync,
-  mkdtempSync,
-  openSync,
-  readFileSync,
-  readSync,
-  readdirSync,
-  readlinkSync,
-  realpathSync,
-  renameSync,
-  rmSync,
-  statSync,
-  writeFileSync,
-} from 'node:fs';
-import {dirname, isAbsolute, join, relative, resolve, sep} from 'node:path';
-
-import {captureCommandOutput} from '../../../tools/dev/capture-command-output.mjs';
-
-const ARCHIVE_SAFETY_VERSION = 'source-archive-v2';
-const ARCHIVE_DOWNLOAD_TIMEOUT_MS = 620_000;
-const ARCHIVE_VALIDATE_TIMEOUT_MS = 120_000;
-const ARCHIVE_EXTRACT_TIMEOUT_MS = 300_000;
-const GIT_FETCH_TIMEOUT_MS = 300_000;
-const COMMAND_MAX_BUFFER = 16 * 1024 * 1024;
-const DOWNLOAD_MAX_BYTES = 1024 * 1024 * 1024;
-const CHECKOUT_MAX_ENTRIES = 500_000;
-const CHECKOUT_MAX_BYTES = 8 * 1024 * 1024 * 1024;
-const GNU_MIRROR_ORIGIN = 'https://ftpmirror.gnu.org';
-const GNU_CANONICAL_ARCHIVE_ORIGIN = 'https://ftp.gnu.org/gnu';
-const GNU_ARCHIVE_PATH_COMPONENT = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/u;
-
-const temporaryPaths = new Set();
-const activePromotions = [];
-let signalHandlersInstalled = false;
-
-export function assertHttpsUrl(value, label = 'source URL') {
-  if (
-    typeof value !== 'string' ||
-    value === '' ||
-    value.trim() !== value ||
-    value.includes('\\') ||
-    /[\u0000-\u001f\u007f]/u.test(value)
-  ) {
-    throw new Error(`${label} must be one canonical absolute HTTPS URL`);
-  }
-  let parsed;
-  try {
-    parsed = new URL(value);
-  } catch (error) {
-    throw new Error(`${label} must be an absolute HTTPS URL: ${error instanceof Error ? error.message : error}`);
-  }
-  if (parsed.protocol !== 'https:') {
-    throw new Error(`${label} must use HTTPS, got ${parsed.protocol || ''}`);
-  }
-  if (parsed.username !== '' || parsed.password !== '') {
-    throw new Error(`${label} must not contain embedded credentials`);
-  }
-  if (parsed.hash !== '') {
-    throw new Error(`${label} must not contain a URL fragment`);
-  }
-  if (parsed.hostname === '') {
-    throw new Error(`${label} must contain a hostname`);
-  }
-  return parsed;
-}
-
-export function curlPlatformTlsArgs(platform = process.platform) {
-  return platform === 'win32' ? ['--ssl-revoke-best-effort'] : [];
-}
-
-export function curlDownloadArgs(url, output, {platform = process.platform} = {}) {
-  assertHttpsUrl(url);
-  return [
-    '--disable',
-    '--fail',
-    '--location',
-    '--silent',
-    '--show-error',
-    '--retry',
-    '8',
-    '--retry-all-errors',
-    '--retry-connrefused',
-    '--retry-delay',
-    '5',
-    '--retry-max-time',
-    '600',
-    '--connect-timeout',
-    '20',
-    '--max-time',
-    '600',
-    '--speed-limit',
-    '1024',
-    '--speed-time',
-    '120',
-    '--max-filesize',
-    String(DOWNLOAD_MAX_BYTES),
-    '--max-redirs',
-    '5',
-    '--proto-default',
-    'https',
-    '--proto',
-    '=https',
-    '--proto-redir',
-    '=https',
-    '--tlsv1.2',
-    ...curlPlatformTlsArgs(platform),
-    '--remove-on-error',
-    '--url',
-    url,
-    '--output',
-    output,
-  ];
-}
-
-export function canonicalGnuArchiveFallbackUrl(pinnedUrl) {
-  let parsed;
-  try {
-    parsed = assertHttpsUrl(pinnedUrl);
-  } catch {
-    return undefined;
-  }
-  if (
-    parsed.origin !== GNU_MIRROR_ORIGIN ||
-    parsed.search !== '' ||
-    parsed.href !== pinnedUrl
-  ) {
-    return undefined;
-  }
-  const [, project, file, ...extra] = parsed.pathname.split('/');
-  if (
-    extra.length !== 0 ||
-    !GNU_ARCHIVE_PATH_COMPONENT.test(project ?? '') ||
-    !GNU_ARCHIVE_PATH_COMPONENT.test(file ?? '') ||
-    (!file.endsWith('.tar.gz') && !file.endsWith('.tgz'))
-  ) {
-    return undefined;
-  }
-  return `${GNU_CANONICAL_ARCHIVE_ORIGIN}/${project}/${file}`;
-}
-
-export function defaultRunProcess({command, args, cwd, env = process.env, label, timeoutMs}) {
-  const result = captureCommandOutput(command, args, {
-    cwd,
-    env,
-    label: label ?? `${command} ${args.join(' ')}`,
-    maxOutputBytes: COMMAND_MAX_BUFFER,
-    timeout: timeoutMs,
-    killSignal: 'SIGTERM',
-  });
-  const description = label ?? `${command} ${args.join(' ')}`;
-  if (result.error !== undefined) {
-    const timeout = result.error.code === 'ETIMEDOUT' ? ` after ${timeoutMs}ms` : '';
-    throw new Error(`${description} failed${timeout}: ${result.error.message}`);
-  }
-  if (result.status !== 0) {
-    const detail = result.stderr.trim() || result.stdout.trim() || `exit code ${result.status}`;
-    throw new Error(`${description}: ${detail}`);
-  }
-  return result.stdout;
-}
-
-function pathExists(path) {
-  try {
-    lstatSync(path);
-    return true;
-  } catch (error) {
-    if (error?.code === 'ENOENT') {
-      return false;
-    }
-    throw error;
-  }
-}
-
-function removePath(path) {
-  rmSync(path, {recursive: true, force: true, maxRetries: 3, retryDelay: 50});
-}
-
-function installSignalHandlers() {
-  if (signalHandlersInstalled) {
-    return;
-  }
-  signalHandlersInstalled = true;
-  for (const [signal, exitCode] of [
-    ['SIGINT', 130],
-    ['SIGTERM', 143],
-    ['SIGHUP', 129],
-  ]) {
-    process.once(signal, () => {
-      restoreActivePromotions();
-      cleanupTemporaryPaths();
-      process.exit(exitCode);
-    });
-  }
-}
-
-function restorePromotion(promotion) {
-  if (pathExists(promotion.destination)) {
-    removePath(promotion.destination);
-  }
-  if (promotion.hadPrevious && pathExists(promotion.backup)) {
-    renameSync(promotion.backup, promotion.destination);
-  }
-}
-
-function restoreActivePromotions() {
-  for (const promotion of [...activePromotions].reverse()) {
-    try {
-      restorePromotion(promotion);
-    } catch (error) {
-      // There is no safe logging dependency in a signal cleanup path.  Preserve
-      // all remaining backups and continue attempting the other rollbacks.
-      process.stderr.write(`warning: could not roll back ${promotion.destination}: ${error}\n`);
-    }
-  }
-}
-
-function cleanupTemporaryPaths() {
-  for (const path of [...temporaryPaths].reverse()) {
-    try {
-      removePath(path);
-    } catch (error) {
-      process.stderr.write(`warning: could not remove source-fetch staging path ${path}: ${error}\n`);
-    }
-  }
-}
-
-function makeStageDirectory(parent, name) {
-  mkdirSync(parent, {recursive: true});
-  installSignalHandlers();
-  const stage = mkdtempSync(join(parent, `.${name}-stage-`));
-  temporaryPaths.add(stage);
-  return stage;
-}
-
-function forgetStageDirectory(stage) {
-  temporaryPaths.delete(stage);
-  removePath(stage);
-}
-
-export function promotePathTransactional(candidate, destination, {afterBackup} = {}) {
-  if (!pathExists(candidate)) {
-    throw new Error(`transaction candidate does not exist: ${candidate}`);
-  }
-  mkdirSync(dirname(destination), {recursive: true});
-  installSignalHandlers();
-  const hadPrevious = pathExists(destination);
-  const backup = join(dirname(destination), `.${destination.split(sep).at(-1)}-backup-${process.pid}-${randomUUID()}`);
-  const promotion = {destination, backup, hadPrevious};
-  activePromotions.push(promotion);
-  let candidateMoved = false;
-  try {
-    if (hadPrevious) {
-      renameSync(destination, backup);
-    }
-    afterBackup?.();
-    renameSync(candidate, destination);
-    candidateMoved = true;
-    if (hadPrevious) {
-      removePath(backup);
-    }
-  } catch (error) {
-    try {
-      if (candidateMoved && pathExists(destination)) {
-        removePath(destination);
-      }
-      if (hadPrevious && pathExists(backup)) {
-        renameSync(backup, destination);
-      }
-    } catch (rollbackError) {
-      throw new AggregateError(
-        [error, rollbackError],
-        `promotion of ${candidate} to ${destination} failed and rollback was incomplete`,
-      );
-    }
-    throw error;
-  } finally {
-    const index = activePromotions.indexOf(promotion);
-    if (index >= 0) {
-      activePromotions.splice(index, 1);
-    }
-  }
-}
-
-export function sha256File(path) {
-  const hash = createHash('sha256');
-  const buffer = Buffer.allocUnsafe(1024 * 1024);
-  const descriptor = openSync(path, 'r');
-  try {
-    while (true) {
-      const count = readSync(descriptor, buffer, 0, buffer.length, null);
-      if (count === 0) {
-        break;
-      }
-      hash.update(buffer.subarray(0, count));
-    }
-  } finally {
-    closeSync(descriptor);
-  }
-  return hash.digest('hex');
-}
-
-function isRealDirectory(path) {
-  try {
-    const metadata = lstatSync(path);
-    return metadata.isDirectory() && !metadata.isSymbolicLink();
-  } catch {
-    return false;
-  }
-}
-
-function isRegularFile(path, maximumBytes = Number.POSITIVE_INFINITY) {
-  try {
-    const metadata = lstatSync(path);
-    return metadata.isFile() && !metadata.isSymbolicLink() && metadata.size <= maximumBytes;
-  } catch {
-    return false;
-  }
-}
-
-function hasGitMetadata(path) {
-  return pathExists(join(path, '.git'));
-}
-
-function assertSupportedGitMetadata(source, path) {
-  if (hasGitMetadata(path) && !isRealDirectory(join(path, '.git'))) {
-    throw new Error(
-      `source checkout ${path} (${source.name}) has unsupported non-directory .git metadata; preserve it before fetching pins`,
-    );
-  }
-}
-
-function validateSourceName(name) {
-  if (
-    typeof name !== 'string' ||
-    name === '' ||
-    name.includes('..') ||
-    name.includes('/') ||
-    name.includes('\\') ||
-    !/^[A-Za-z0-9._-]+$/u.test(name)
-  ) {
-    throw new Error(`unsafe source name ${JSON.stringify(name)}`);
-  }
-}
-
-function validateBranchName(branch) {
-  if (
-    typeof branch !== 'string' ||
-    branch === '' ||
-    branch.startsWith('-') ||
-    branch.startsWith('/') ||
-    branch.endsWith('/') ||
-    branch.endsWith('.') ||
-    branch.includes('..') ||
-    branch.includes('@{') ||
-    /[\u0000-\u0020\u007f~^:?*[\\]/u.test(branch) ||
-    branch.split('/').some((part) => part === '' || part.endsWith('.lock'))
-  ) {
-    throw new Error(`unsafe Git branch name ${JSON.stringify(branch)}`);
-  }
-}
-
-function validateSource(source) {
-  validateSourceName(source.name);
-  const parsedUrl = assertHttpsUrl(source.url, `source '${source.name}' URL`);
-  const parsedMirrorUrl = source.mirrorUrl === undefined
-    ? undefined
-    : assertHttpsUrl(source.mirrorUrl, `source '${source.name}' mirror URL`);
-  validateBranchName(source.branch);
-  if (source.kind === 'git') {
-    if (!/^[0-9a-f]{40}$/u.test(source.commit)) {
-      throw new Error(`git source '${source.name}' must pin an exact lowercase 40-hex commit`);
-    }
-    if (parsedMirrorUrl?.href === parsedUrl.href) {
-      throw new Error(`git source '${source.name}' mirror URL must differ from its primary URL`);
-    }
-  } else if (source.kind === 'archive') {
-    if (parsedMirrorUrl !== undefined) {
-      throw new Error(`archive source '${source.name}' must not set mirror_url`);
-    }
-    if (!/^[0-9a-f]{64}$/u.test(source.sha256 ?? '') || source.commit !== source.sha256) {
-      throw new Error(`archive source '${source.name}' must pin one lowercase SHA-256 as sha256 and commit`);
-    }
-    if (
-      typeof source.stripPrefix !== 'string' ||
-      (source.stripPrefix !== '.' &&
-        (!/^[A-Za-z0-9][A-Za-z0-9._+-]*$/u.test(source.stripPrefix) ||
-          source.stripPrefix.includes('..')))
-    ) {
-      throw new Error(`archive source '${source.name}' has an unsafe strip prefix`);
-    }
-    if (
-      !parsedUrl.pathname.endsWith('.tar.gz') &&
-      !parsedUrl.pathname.endsWith('.tgz') &&
-      !parsedUrl.pathname.endsWith('.zip')
-    ) {
-      throw new Error(`archive source '${source.name}' URL must identify a .tar.gz, .tgz, or .zip file`);
-    }
-    if (source.stripPrefix === '.' && !parsedUrl.pathname.endsWith('.zip')) {
-      throw new Error(`archive source '${source.name}' may use a rootless strip prefix only for ZIP releases`);
-    }
-  } else {
-    throw new Error(`source '${source.name}' has unsupported kind '${source.kind}'`);
-  }
-}
-
-function archiveStampMetadata(source) {
-  return `safety=${ARCHIVE_SAFETY_VERSION}\nname=${source.name}\nkind=archive\nurl=${source.url}\nbranch=${source.branch}\ncommit=${source.commit}\nsha256=${source.sha256}\nstrip-prefix=${source.stripPrefix}\n`;
-}
-
-function archiveStamp(source, treeSha256) {
-  return `${archiveStampMetadata(source)}tree-sha256=${treeSha256}\n`;
-}
-
-function isolatedGitEnvironment(globalConfig) {
-  const env = {...process.env};
-  for (const name of [
-    'GIT_DIR',
-    'GIT_WORK_TREE',
-    'GIT_INDEX_FILE',
-    'GIT_OBJECT_DIRECTORY',
-    'GIT_ALTERNATE_OBJECT_DIRECTORIES',
-    'GIT_COMMON_DIR',
-    'GIT_SSH',
-    'GIT_SSH_COMMAND',
-    'GIT_ASKPASS',
-    'GIT_TEMPLATE_DIR',
-    'GIT_CONFIG_COUNT',
-  ]) {
-    delete env[name];
-  }
-  env.GIT_CONFIG_NOSYSTEM = '1';
-  env.GIT_CONFIG_GLOBAL = globalConfig;
-  env.GIT_TERMINAL_PROMPT = '0';
-  env.GCM_INTERACTIVE = 'Never';
-  return env;
-}
-
-function stagedGitEnvironment(stage) {
-  const globalConfig = join(stage, 'empty.gitconfig');
-  writeFileSync(globalConfig, '', {mode: 0o600});
-  return isolatedGitEnvironment(globalConfig);
-}
-
-function durableGitEnvironment() {
-  return isolatedGitEnvironment(process.platform === 'win32' ? 'NUL' : '/dev/null');
-}
-
-function hasUsableDirectoryIdentity(metadata) {
-  // Path strings cannot prove identity: Windows may spell one directory with
-  // either an 8.3 alias or its long name.  Require both the volume and file ID
-  // so filesystems without a complete stable identity fail closed.
-  return (
-    metadata.isDirectory() &&
-    typeof metadata.dev === 'bigint' &&
-    metadata.dev > 0n &&
-    typeof metadata.ino === 'bigint' &&
-    metadata.ino > 0n
-  );
-}
-
-export function sameDirectoryIdentity(left, right, {stat = statSync} = {}) {
-  const leftMetadata = stat(left, {bigint: true});
-  const rightMetadata = stat(right, {bigint: true});
-  if (!hasUsableDirectoryIdentity(leftMetadata) || !hasUsableDirectoryIdentity(rightMetadata)) {
-    return false;
-  }
-
-  return leftMetadata.dev === rightMetadata.dev && leftMetadata.ino === rightMetadata.ino;
-}
-
-function assertSafeCheckoutTree(root) {
-  const realRoot = realpathSync(root);
-  const pending = [root];
-  while (pending.length > 0) {
-    const directory = pending.pop();
-    for (const entry of readdirSync(directory, {withFileTypes: true})) {
-      if (directory === root && entry.name === '.git') {
-        continue;
-      }
-      const path = join(directory, entry.name);
-      const metadata = lstatSync(path);
-      if (metadata.isDirectory()) {
-        pending.push(path);
-        continue;
-      }
-      if (metadata.isFile()) {
-        continue;
-      }
-      if (!metadata.isSymbolicLink()) {
-        throw new Error(`Git source checkout contains unsupported filesystem object ${path}`);
-      }
-      const target = readlinkSync(path);
-      if (isAbsolute(target)) {
-        throw new Error(`Git source checkout contains absolute symlink ${path} -> ${target}`);
-      }
-      const resolvedTarget = resolve(dirname(path), target);
-      const relativeTarget = relative(root, resolvedTarget);
-      if (relativeTarget === '..' || relativeTarget.startsWith(`..${sep}`) || isAbsolute(relativeTarget)) {
-        throw new Error(`Git source checkout contains escaping symlink ${path} -> ${target}`);
-      }
-      if (!pathExists(resolvedTarget)) {
-        // Source repositories may intentionally track dangling relative links
-        // as filesystem fixtures. They are safe only when both the lexical
-        // destination and its deepest existing ancestor remain in the staged
-        // checkout. The ancestor check catches paths that cross an existing
-        // symlink before reaching the missing leaf.
-        let existingAncestor = dirname(resolvedTarget);
-        while (existingAncestor !== root && !pathExists(existingAncestor)) {
-          existingAncestor = dirname(existingAncestor);
-        }
-        let realAncestor;
-        try {
-          realAncestor = realpathSync(existingAncestor);
-        } catch (error) {
-          throw new Error(
-            `Git source checkout contains unresolved dangling symlink ${path} -> ${target}: ${error}`,
-          );
-        }
-        const relativeRealAncestor = relative(realRoot, realAncestor);
-        if (
-          relativeRealAncestor === '..'
-          || relativeRealAncestor.startsWith(`..${sep}`)
-          || isAbsolute(relativeRealAncestor)
-        ) {
-          throw new Error(
-            `Git source checkout contains transitively escaping dangling symlink ${path} -> ${target}`,
-          );
-        }
-        continue;
-      }
-      let realTarget;
-      try {
-        realTarget = realpathSync(resolvedTarget);
-      } catch (error) {
-        throw new Error(`Git source checkout contains unresolved symlink ${path} -> ${target}: ${error}`);
-      }
-      const relativeRealTarget = relative(realRoot, realTarget);
-      if (
-        relativeRealTarget === '..' ||
-        relativeRealTarget.startsWith(`..${sep}`) ||
-        isAbsolute(relativeRealTarget)
-      ) {
-        throw new Error(`Git source checkout contains transitively escaping symlink ${path} -> ${target}`);
-      }
-    }
-  }
-}
-
-function updateDigestField(hash, value) {
-  hash.update(String(value), 'utf8');
-  hash.update(Buffer.from([0]));
-}
-
-export function archiveTreeDigest(root) {
-  if (!isRealDirectory(root)) {
-    throw new Error(`archive source tree is not a real directory: ${root}`);
-  }
-  const entries = [];
-  const pending = [root];
-  let totalBytes = 0;
-  while (pending.length > 0) {
-    const directory = pending.pop();
-    const children = readdirSync(directory, {withFileTypes: true}).sort((left, right) =>
-      Buffer.compare(Buffer.from(left.name), Buffer.from(right.name)),
-    );
-    for (const child of children) {
-      if (directory === root && child.name === '.oliphaunt-source-pin') {
-        continue;
-      }
-      const path = join(directory, child.name);
-      const relativePath = relative(root, path).split(sep).join('/');
-      const metadata = lstatSync(path);
-      let type;
-      let detail = '';
-      if (metadata.isDirectory()) {
-        type = 'directory';
-        pending.push(path);
-      } else if (metadata.isFile()) {
-        type = 'file';
-        totalBytes += metadata.size;
-        if (totalBytes > CHECKOUT_MAX_BYTES) {
-          throw new Error(`archive source tree ${root} exceeds ${CHECKOUT_MAX_BYTES} bytes`);
-        }
-        detail = `${metadata.size}:${sha256File(path)}`;
-      } else if (metadata.isSymbolicLink()) {
-        type = 'symlink';
-        detail = readlinkSync(path);
-      } else {
-        throw new Error(`archive source tree contains unsupported filesystem object ${path}`);
-      }
-      entries.push({relativePath, type, detail});
-      if (entries.length > CHECKOUT_MAX_ENTRIES) {
-        throw new Error(`archive source tree ${root} exceeds ${CHECKOUT_MAX_ENTRIES} entries`);
-      }
-    }
-  }
-  entries.sort((left, right) =>
-    Buffer.compare(Buffer.from(left.relativePath), Buffer.from(right.relativePath)),
-  );
-  const hash = createHash('sha256');
-  for (const entry of entries) {
-    updateDigestField(hash, entry.type);
-    updateDigestField(hash, entry.relativePath);
-    updateDigestField(hash, entry.detail);
-  }
-  return hash.digest('hex');
-}
-
-function parseArchiveStamp(path) {
-  if (!isRegularFile(path, 64 * 1024)) {
-    throw new Error(`archive source marker is missing, non-regular, or oversized: ${path}`);
-  }
-  const fields = new Map();
-  const text = readFileSync(path, 'utf8');
-  for (const line of text.split('\n')) {
-    if (line === '') {
-      continue;
-    }
-    const separator = line.indexOf('=');
-    if (separator <= 0) {
-      throw new Error(`archive source marker ${path} contains a malformed line`);
-    }
-    const key = line.slice(0, separator);
-    if (fields.has(key)) {
-      throw new Error(`archive source marker ${path} repeats ${key}`);
-    }
-    fields.set(key, line.slice(separator + 1));
-  }
-  const required = [
-    'safety',
-    'name',
-    'kind',
-    'url',
-    'branch',
-    'commit',
-    'sha256',
-    'strip-prefix',
-    'tree-sha256',
-  ];
-  if (fields.size !== required.length || required.some((key) => !fields.has(key))) {
-    throw new Error(`archive source marker ${path} does not carry complete integrity state`);
-  }
-  if (fields.get('safety') !== ARCHIVE_SAFETY_VERSION) {
-    throw new Error(
-      `archive source marker ${path} predates ${ARCHIVE_SAFETY_VERSION}; move or remove the checkout before rematerializing it`,
-    );
-  }
-  if (!/^[0-9a-f]{64}$/u.test(fields.get('tree-sha256'))) {
-    throw new Error(`archive source marker ${path} has an invalid tree digest`);
-  }
-  return fields;
-}
-
-function defaultSleep(milliseconds) {
-  return new Promise((resolveSleep) => setTimeout(resolveSleep, milliseconds));
-}
-
-export function createSourceFetcher({
-  workspaceRoot,
-  checkoutRoot,
-  archiveRoot,
-  archiveTool = join(workspaceRoot, 'src', 'sources', 'tools', 'source-archive.py'),
-  zipArchiveTool = join(workspaceRoot, 'src', 'sources', 'tools', 'source-zip.py'),
-  runProcess = defaultRunProcess,
-  sleep = defaultSleep,
-  gitAttempts = 5,
-  downloadFile,
-  validateArchive,
-  extractArchive,
-} = {}) {
-  if (!workspaceRoot || !checkoutRoot || !archiveRoot) {
-    throw new Error('source fetcher requires workspaceRoot, checkoutRoot, and archiveRoot');
-  }
-
-  const run = (command, args, options = {}) =>
-    runProcess({
-      command,
-      args,
-      cwd: options.cwd ?? workspaceRoot,
-      env: options.env ?? process.env,
-      label: options.label,
-      timeoutMs: options.timeoutMs ?? 60_000,
-    });
-  const validate =
-    validateArchive ??
-    ((archive, source) =>
-      run('python3', [source.url.endsWith('.zip') ? zipArchiveTool : archiveTool, 'validate', archive, source.stripPrefix], {
-        label: `validate archive structure for ${source.name}`,
-        timeoutMs: ARCHIVE_VALIDATE_TIMEOUT_MS,
-      }));
-  const extract =
-    extractArchive ??
-    ((archive, destination, source) =>
-      run('python3', [source.url.endsWith('.zip') ? zipArchiveTool : archiveTool, 'extract', archive, source.stripPrefix, destination], {
-        label: `safely extract ${source.name}`,
-        timeoutMs: ARCHIVE_EXTRACT_TIMEOUT_MS,
-      }));
-  const download =
-    downloadFile ??
-    ((source, output) => {
-      try {
-        return run('curl', curlDownloadArgs(source.url, output), {
-          label: `download ${source.name} from pinned HTTPS URL`,
-          timeoutMs: ARCHIVE_DOWNLOAD_TIMEOUT_MS,
-        });
-      } catch (primaryError) {
-        const fallbackUrl = canonicalGnuArchiveFallbackUrl(source.url);
-        if (fallbackUrl === undefined) {
-          throw primaryError;
-        }
-        removePath(output);
-        try {
-          return run('curl', curlDownloadArgs(fallbackUrl, output), {
-            label: `download ${source.name} from canonical GNU HTTPS archive`,
-            timeoutMs: ARCHIVE_DOWNLOAD_TIMEOUT_MS,
-          });
-        } catch (fallbackError) {
-          const primaryDiagnostic =
-            primaryError instanceof Error ? primaryError.message : String(primaryError);
-          const fallbackDiagnostic =
-            fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
-          throw new AggregateError(
-            [primaryError, fallbackError],
-            `download ${source.name} failed from pinned GNU mirror: ${primaryDiagnostic}; ` +
-              `canonical GNU fallback also failed: ${fallbackDiagnostic}`,
-          );
-        }
-      }
-    });
-
-  function git(source, args, cwd, env, options = {}) {
-    // Pinned source bytes are part of release fingerprints and legal-data
-    // checks. Force one worktree representation even when an upstream marks a
-    // file `text=auto` and the host's native checkout convention is CRLF.
-    return run('git', [
-      '-c',
-      'core.fsmonitor=false',
-      '-c',
-      'submodule.recurse=false',
-      '-c',
-      'core.autocrlf=false',
-      '-c',
-      'core.eol=lf',
-      ...args,
-    ], {
-      cwd,
-      env,
-      label: options.label ?? `git ${args.join(' ')} for ${source.name}`,
-      timeoutMs: options.timeoutMs ?? 60_000,
-    });
-  }
-
-  function cleanGitStatus(source, path, env = durableGitEnvironment()) {
-    const status = git(source, ['status', '--porcelain=v1', '--untracked-files=all'], path, env, {
-      label: `read dirty state for ${source.name} at ${path}`,
-    });
-    if (status.trim() !== '') {
-      throw new Error(`source checkout ${path} (${source.name}) has uncommitted changes; preserve them before fetching pins`);
-    }
-  }
-
-  function gitCheckoutIsReady(source, path) {
-    const env = durableGitEnvironment();
-    cleanGitStatus(source, path, env);
-    try {
-      const head = git(source, ['rev-parse', '--verify', 'HEAD'], path, env).trim();
-      const branch = git(source, ['branch', '--show-current'], path, env).trim();
-      const remote = git(source, ['remote', 'get-url', 'origin'], path, env).trim();
-      const autocrlf = git(source, ['config', '--local', '--get', 'core.autocrlf'], path, env).trim();
-      const eol = git(source, ['config', '--local', '--get', 'core.eol'], path, env).trim();
-      return (
-        head === source.commit
-        && branch === source.branch
-        && remote === source.url
-        && autocrlf === 'false'
-        && eol === 'lf'
-      );
-    } catch {
-      return false;
-    }
-  }
-
-  function inspectDurablePath(source, path) {
-    if (!pathExists(path)) {
-      return {kind: 'missing', matchesArchivePin: false};
-    }
-    if (!isRealDirectory(path)) {
-      throw new Error(`durable source path ${path} (${source.name}) is not a real directory; preserve it before fetching pins`);
-    }
-    assertSupportedGitMetadata(source, path);
-    if (hasGitMetadata(path)) {
-      const env = durableGitEnvironment();
-      const worktree = git(source, ['rev-parse', '--show-toplevel'], path, env).trim();
-      const gitDirectory = git(source, ['rev-parse', '--absolute-git-dir'], path, env).trim();
-      if (!sameDirectoryIdentity(worktree, path) || !sameDirectoryIdentity(gitDirectory, join(path, '.git'))) {
-        throw new Error(`source checkout ${path} (${source.name}) has Git metadata outside its durable directory`);
-      }
-      if (isRegularFile(join(path, '.git', 'objects', 'info', 'alternates'))) {
-        throw new Error(`source checkout ${path} (${source.name}) uses external Git object storage`);
-      }
-      cleanGitStatus(source, path, env);
-      return {kind: 'git', matchesArchivePin: false};
-    }
-
-    const markerPath = join(path, '.oliphaunt-source-pin');
-    if (!pathExists(markerPath)) {
-      throw new Error(
-        `durable source path ${path} (${source.name}) is unmanaged; move or remove it before materializing a pinned source`,
-      );
-    }
-    let fields;
-    try {
-      fields = parseArchiveStamp(markerPath);
-    } catch (error) {
-      throw new Error(
-        `durable archive source ${path} (${source.name}) has unverifiable integrity state; preserve it before fetching pins: ${error}`,
-      );
-    }
-    const actualTreeSha256 = archiveTreeDigest(path);
-    const recordedTreeSha256 = fields.get('tree-sha256');
-    if (actualTreeSha256 !== recordedTreeSha256) {
-      throw new Error(
-        `durable archive source ${path} (${source.name}) was modified: expected tree ${recordedTreeSha256}, got ${actualTreeSha256}; preserve it before fetching pins`,
-      );
-    }
-    const matchesArchivePin =
-      source.kind === 'archive' &&
-      fields.get('name') === source.name &&
-      fields.get('kind') === 'archive' &&
-      fields.get('url') === source.url &&
-      fields.get('branch') === source.branch &&
-      fields.get('commit') === source.commit &&
-      fields.get('sha256') === source.sha256 &&
-      fields.get('strip-prefix') === source.stripPrefix;
-    return {kind: 'archive', matchesArchivePin};
-  }
-
-  async function fetchGit(source, path) {
-    const durable = inspectDurablePath(source, path);
-    if (durable.kind === 'git' && gitCheckoutIsReady(source, path)) {
-      return;
-    }
-
-    const stage = makeStageDirectory(dirname(path), `${source.name}-git`);
-    const candidate = join(stage, 'checkout');
-    try {
-      const env = stagedGitEnvironment(stage);
-      git(source, ['init', '--quiet', '--template=', candidate], workspaceRoot, env, {
-        label: `initialize staged checkout for ${source.name}`,
-      });
-      git(source, ['config', '--local', 'core.autocrlf', 'false'], candidate, env, {
-        label: `pin LF checkout conversion for ${source.name}`,
-      });
-      git(source, ['config', '--local', 'core.eol', 'lf'], candidate, env, {
-        label: `pin LF checkout line endings for ${source.name}`,
-      });
-      git(source, ['remote', 'add', 'origin', source.url], candidate, env, {
-        label: `configure staged HTTPS origin for ${source.name}`,
-      });
-
-      const transports = [
-        {name: 'primary', url: source.url},
-        ...(source.mirrorUrl === undefined ? [] : [{name: 'mirror', url: source.mirrorUrl}]),
-      ];
-      let lastError;
-      for (let attempt = 1; attempt <= gitAttempts; attempt += 1) {
-        const transport = transports[(attempt - 1) % transports.length];
-        try {
-          git(
-            source,
-            [
-              '-c',
-              'protocol.allow=never',
-              '-c',
-              'protocol.https.allow=always',
-              '-c',
-              'credential.helper=',
-              '-c',
-              'http.followRedirects=false',
-              '-c',
-              'http.lowSpeedLimit=1024',
-              '-c',
-              'http.lowSpeedTime=120',
-              'fetch',
-              '--no-tags',
-              '--depth=1',
-              transport.url,
-              source.commit,
-            ],
-            candidate,
-            env,
-            {
-              label: `fetch exact commit for ${source.name} from ${transport.name} transport`,
-              timeoutMs: GIT_FETCH_TIMEOUT_MS,
-            },
-          );
-          lastError = undefined;
-          break;
-        } catch (error) {
-          lastError = error;
-          if (attempt < gitAttempts) {
-            const completedTransportCycle = attempt % transports.length === 0;
-            if (completedTransportCycle) {
-              const completedCycles = attempt / transports.length;
-              const delaySeconds = completedCycles * 5;
-              process.stderr.write(
-                `fetch ${source.name} from ${transport.name} transport failed on attempt ${attempt}/${gitAttempts}: ${error}; retrying in ${delaySeconds}s\n`,
-              );
-              await sleep(delaySeconds * 1000);
-            } else {
-              const nextTransport = transports[attempt % transports.length];
-              process.stderr.write(
-                `fetch ${source.name} from ${transport.name} transport failed on attempt ${attempt}/${gitAttempts}: ${error}; trying ${nextTransport.name} transport without delay\n`,
-              );
-            }
-          }
-        }
-      }
-      if (lastError !== undefined) {
-        throw lastError;
-      }
-
-      const fetched = git(source, ['rev-parse', '--verify', 'FETCH_HEAD^{commit}'], candidate, env).trim();
-      if (fetched !== source.commit) {
-        throw new Error(`fetch for ${source.name} returned ${fetched}, expected exact commit ${source.commit}`);
-      }
-      git(source, ['checkout', '--quiet', '-B', source.branch, source.commit], candidate, env, {
-        label: `checkout exact staged commit for ${source.name}`,
-      });
-      cleanGitStatus(source, candidate, env);
-      const head = git(source, ['rev-parse', '--verify', 'HEAD'], candidate, env).trim();
-      const branch = git(source, ['branch', '--show-current'], candidate, env).trim();
-      const remote = git(source, ['remote', 'get-url', 'origin'], candidate, env).trim();
-      if (head !== source.commit || branch !== source.branch || remote !== source.url) {
-        throw new Error(`staged Git checkout for ${source.name} did not preserve its exact pin, branch, and HTTPS origin`);
-      }
-      // Gitlinks remain opaque pinned entries. This fetcher globally disables
-      // recursion, so no secondary URL or unpinned submodule transport can run.
-      assertSafeCheckoutTree(candidate);
-
-      inspectDurablePath(source, path);
-      promotePathTransactional(candidate, path);
-    } finally {
-      forgetStageDirectory(stage);
-    }
-  }
-
-  function cachedArchiveIsValid(archive, source) {
-    if (!pathExists(archive)) {
-      return false;
-    }
-    if (!isRegularFile(archive, DOWNLOAD_MAX_BYTES)) {
-      process.stderr.write(`warning: repairing non-regular or oversized archive cache ${archive}\n`);
-      return false;
-    }
-    const actual = sha256File(archive);
-    if (actual !== source.sha256) {
-      process.stderr.write(
-        `warning: repairing corrupt archive cache ${archive}: expected ${source.sha256}, got ${actual}\n`,
-      );
-      return false;
-    }
-    try {
-      validate(archive, source);
-      return true;
-    } catch (error) {
-      process.stderr.write(`warning: repairing structurally unsafe archive cache ${archive}: ${error}\n`);
-      return false;
-    }
-  }
-
-  async function ensureArchive(source) {
-    mkdirSync(archiveRoot, {recursive: true});
-    const extension = source.url.endsWith('.zip') ? '.zip' : '.tar.gz';
-    const archive = join(archiveRoot, `${source.name}-${source.sha256}${extension}`);
-    if (cachedArchiveIsValid(archive, source)) {
-      return archive;
-    }
-
-    const stage = makeStageDirectory(archiveRoot, `${source.name}-download`);
-    const candidate = join(stage, source.url.endsWith('.zip') ? 'download.zip' : 'download.tar.gz');
-    try {
-      await download(source, candidate);
-      if (!isRegularFile(candidate, DOWNLOAD_MAX_BYTES)) {
-        throw new Error(`download for ${source.name} did not create one bounded regular file at ${candidate}`);
-      }
-      const actual = sha256File(candidate);
-      if (actual !== source.sha256) {
-        throw new Error(`${source.name} archive sha256: expected ${source.sha256}, got ${actual}`);
-      }
-      validate(candidate, source);
-      promotePathTransactional(candidate, archive);
-      return archive;
-    } finally {
-      forgetStageDirectory(stage);
-    }
-  }
-
-  async function fetchArchive(source, path) {
-    const durable = inspectDurablePath(source, path);
-    if (durable.kind === 'archive' && durable.matchesArchivePin) {
-      return;
-    }
-
-    const archive = await ensureArchive(source);
-    const stage = makeStageDirectory(dirname(path), `${source.name}-extract`);
-    const candidate = join(stage, 'checkout');
-    try {
-      extract(archive, candidate, source);
-      if (!isRealDirectory(candidate)) {
-        throw new Error(`safe extractor did not create the staged source directory ${candidate}`);
-      }
-      const treeSha256 = archiveTreeDigest(candidate);
-      writeFileSync(join(candidate, '.oliphaunt-source-pin'), archiveStamp(source, treeSha256), {
-        encoding: 'utf8',
-        mode: 0o644,
-        flag: 'wx',
-      });
-      inspectDurablePath(source, path);
-      promotePathTransactional(candidate, path);
-    } finally {
-      forgetStageDirectory(stage);
-    }
-  }
-
-  async function materialize(source, explicitPath) {
-    validateSource(source);
-    const path = explicitPath ?? join(checkoutRoot, source.name);
-    const expectedPath = resolve(checkoutRoot, source.name);
-    if (resolve(path) !== expectedPath) {
-      throw new Error(`source checkout path must be the named child ${expectedPath}, got ${path}`);
-    }
-    if (source.kind === 'archive') {
-      await fetchArchive(source, path);
-    } else {
-      await fetchGit(source, path);
-    }
-  }
-
-  function verify(source, explicitPath) {
-    validateSource(source);
-    const path = explicitPath ?? join(checkoutRoot, source.name);
-    const expectedPath = resolve(checkoutRoot, source.name);
-    if (resolve(path) !== expectedPath) {
-      throw new Error(`source checkout path must be the named child ${expectedPath}, got ${path}`);
-    }
-    const durable = inspectDurablePath(source, path);
-    if (source.kind === 'archive') {
-      if (durable.kind !== 'archive' || !durable.matchesArchivePin) {
-        throw new Error(`archive source checkout ${path} (${source.name}) is missing or stale`);
-      }
-      return;
-    }
-    if (durable.kind !== 'git' || !gitCheckoutIsReady(source, path)) {
-      throw new Error(`Git source checkout ${path} (${source.name}) is missing or stale`);
-    }
-  }
-
-  return {materialize, verify, ensureArchive};
-}
diff --git a/src/sources/tools/source-fetch-core.test.mjs b/src/sources/tools/source-fetch-core.test.mjs
deleted file mode 100644
index 72e3cf776..000000000
--- a/src/sources/tools/source-fetch-core.test.mjs
+++ /dev/null
@@ -1,1410 +0,0 @@
-import assert from 'node:assert/strict';
-import {spawnSync} from '../../../tools/test/fd-backed-spawn-sync.mjs';
-import {
-  copyFileSync,
-  existsSync,
-  mkdirSync,
-  mkdtempSync,
-  readFileSync,
-  readdirSync,
-  rmSync,
-  symlinkSync,
-  writeFileSync,
-} from 'node:fs';
-import os from 'node:os';
-import path from 'node:path';
-import {test} from 'node:test';
-
-import {
-  assertHttpsUrl,
-  canonicalGnuArchiveFallbackUrl,
-  createSourceFetcher,
-  curlDownloadArgs,
-  curlPlatformTlsArgs,
-  defaultRunProcess,
-  promotePathTransactional,
-  sameDirectoryIdentity,
-  sha256File,
-} from './source-fetch-core.mjs';
-
-const archiveTool = path.join(import.meta.dirname, 'source-archive.py');
-const zipArchiveTool = path.join(import.meta.dirname, 'source-zip.py');
-const treeVerifier = path.join(import.meta.dirname, 'verify-source-tree.py');
-
-function command(commandName, args, options = {}) {
-  const result = spawnSync(commandName, args, {encoding: 'utf8', ...options});
-  assert.equal(result.status, 0, result.stderr || result.stdout);
-  return result.stdout.trim();
-}
-
-function makeRoot(label) {
-  return mkdtempSync(path.join(os.tmpdir(), `oliphaunt-${label}-`));
-}
-
-function directoryMetadata(dev, ino, isDirectory = true) {
-  return {dev, ino, isDirectory: () => isDirectory};
-}
-
-test('directory identity accepts Windows short and long aliases for the same filesystem object', () => {
-  const shortPath = String.raw`C:\Users\RUNNER~1\AppData\Local\Temp\checkout`;
-  const longPath = String.raw`C:\Users\runneradmin\AppData\Local\Temp\checkout`;
-  const metadata = new Map([
-    [shortPath, directoryMetadata(17n, 42n)],
-    [longPath, directoryMetadata(17n, 42n)],
-  ]);
-
-  assert.equal(
-    sameDirectoryIdentity(shortPath, longPath, {
-      stat: (candidate) => metadata.get(candidate),
-    }),
-    true,
-  );
-});
-
-test('directory identity rejects different filesystem objects', () => {
-  assert.equal(
-    sameDirectoryIdentity('/expected', '/external', {
-      stat: (candidate) =>
-        candidate === '/expected' ? directoryMetadata(17n, 42n) : directoryMetadata(17n, 43n),
-    }),
-    false,
-  );
-});
-
-test('directory identity rejects unavailable or partial filesystem identifiers', () => {
-  const identities = [
-    [directoryMetadata(0n, 0n), directoryMetadata(0n, 0n)],
-    [directoryMetadata(17n, 0n), directoryMetadata(17n, 0n)],
-    [directoryMetadata(0n, 42n), directoryMetadata(0n, 42n)],
-    [directoryMetadata(17n, 42n), directoryMetadata(0n, 42n)],
-  ];
-  for (const [left, right] of identities) {
-    assert.equal(
-      sameDirectoryIdentity('/left', '/right', {
-        stat: (candidate) => (candidate === '/left' ? left : right),
-      }),
-      false,
-    );
-  }
-});
-
-test('directory identity rejects a matching inode on a different device', () => {
-  assert.equal(
-    sameDirectoryIdentity('/left', '/right', {
-      stat: (candidate) =>
-        candidate === '/left' ? directoryMetadata(17n, 42n) : directoryMetadata(18n, 42n),
-    }),
-    false,
-  );
-});
-
-test('directory identity rejects non-directories and propagates stat errors', () => {
-  assert.equal(
-    sameDirectoryIdentity('/directory', '/file', {
-      stat: (candidate) => directoryMetadata(17n, candidate === '/directory' ? 42n : 43n, candidate === '/directory'),
-    }),
-    false,
-  );
-  assert.throws(
-    () =>
-      sameDirectoryIdentity('/missing', '/expected', {
-        stat: () => {
-          throw new Error('stat failed');
-        },
-      }),
-    /stat failed/u,
-  );
-});
-
-function createTarFixtures(root) {
-  const program = String.raw`
-import gzip
-import io
-import pathlib
-import tarfile
-import sys
-
-root = pathlib.Path(sys.argv[1])
-
-def member(name, data=b"bytes", *, kind=tarfile.REGTYPE, link="", size=None):
-    info = tarfile.TarInfo(name)
-    info.type = kind
-    info.mode = 0o755 if kind == tarfile.DIRTYPE else 0o644
-    info.linkname = link
-    info.size = len(data) if size is None else size
-    return info, io.BytesIO(data) if kind == tarfile.REGTYPE and size is None else None
-
-def write(name, entries):
-    with tarfile.open(root / name, "w:gz") as archive:
-        for info, contents in entries:
-            archive.addfile(info, contents)
-
-directory = member("pkg/", b"", kind=tarfile.DIRTYPE)
-file_entry = member("pkg/file.txt", b"trusted bytes")
-valid_link = member("pkg/link.txt", b"", kind=tarfile.SYMTYPE, link="file.txt")
-valid_hardlink = member("pkg/hard.txt", b"", kind=tarfile.LNKTYPE, link="pkg/file.txt")
-write("valid.tar.gz", [directory, file_entry, valid_link, valid_hardlink])
-write("updated.tar.gz", [
-    member("pkg/", b"", kind=tarfile.DIRTYPE),
-    member("pkg/file.txt", b"updated trusted bytes"),
-])
-write("traversal.tar.gz", [member("pkg/../../escape")])
-write("absolute.tar.gz", [member("/tmp/escape")])
-write("outside-prefix.tar.gz", [member("other/file")])
-write("backslash.tar.gz", [member(r"pkg\\escape")])
-write("duplicate.tar.gz", [member("pkg/file"), member("pkg/file", b"second")])
-write("case-collision.tar.gz", [member("pkg/File"), member("pkg/file", b"second")])
-write("windows-ads.tar.gz", [member("pkg/file:stream")])
-write("windows-device.tar.gz", [member("pkg/CON.txt")])
-write("escaping-symlink.tar.gz", [member("pkg/link", b"", kind=tarfile.SYMTYPE, link="../../escape")])
-write("dangling-symlink.tar.gz", [member("pkg/link", b"", kind=tarfile.SYMTYPE, link="missing")])
-write("escaping-hardlink.tar.gz", [member("pkg/link", b"", kind=tarfile.LNKTYPE, link="../../escape")])
-write("fifo.tar.gz", [member("pkg/fifo", b"", kind=tarfile.FIFOTYPE)])
-write("reserved-git.tar.gz", [member("pkg/.git/config")])
-write("reserved-stamp.tar.gz", [member("pkg/.oliphaunt-source-pin")])
-write("symlink-ancestor.tar.gz", [
-    member("pkg/dir/", b"", kind=tarfile.DIRTYPE),
-    member("pkg/link", b"", kind=tarfile.SYMTYPE, link="dir"),
-    member("pkg/link/child"),
-])
-
-huge = tarfile.TarInfo("pkg/huge")
-huge.type = tarfile.REGTYPE
-huge.mode = 0o644
-huge.size = 3 * 1024 * 1024 * 1024
-with gzip.open(root / "huge.tar.gz", "wb") as stream:
-    stream.write(huge.tobuf())
-`;
-  command('python3', ['-c', program, root]);
-}
-
-function validateArchive(archive) {
-  return spawnSync('python3', [archiveTool, 'validate', archive, 'pkg'], {encoding: 'utf8'});
-}
-
-function createZipFixtures(root) {
-  const program = String.raw`
-import pathlib
-import stat
-import sys
-import zipfile
-
-root = pathlib.Path(sys.argv[1])
-with zipfile.ZipFile(root / "valid.zip", "w", zipfile.ZIP_DEFLATED) as archive:
-    archive.writestr("LICENSE", "license\n")
-    archive.writestr("payload/data.bin", b"trusted bytes")
-with zipfile.ZipFile(root / "traversal.zip", "w", zipfile.ZIP_DEFLATED) as archive:
-    archive.writestr("../escape", b"bad")
-with zipfile.ZipFile(root / "symlink.zip", "w", zipfile.ZIP_DEFLATED) as archive:
-    info = zipfile.ZipInfo("link")
-    info.create_system = 3
-    info.external_attr = (stat.S_IFLNK | 0o777) << 16
-    archive.writestr(info, "payload/data.bin")
-`;
-  command('python3', ['-c', program, root]);
-}
-
-function validateZipArchive(archive) {
-  return spawnSync('python3', [zipArchiveTool, 'validate', archive, '.'], {encoding: 'utf8'});
-}
-
-function archiveSource(fixture, name = 'fixture') {
-  const sha256 = sha256File(fixture);
-  return {
-    name,
-    kind: 'archive',
-    url: `https://example.invalid/${name}.tar.gz`,
-    branch: 'archive-1.0',
-    commit: sha256,
-    sha256,
-    stripPrefix: 'pkg',
-  };
-}
-
-function gnuArchiveSource(fixture) {
-  return {
-    ...archiveSource(fixture, 'libiconv'),
-    url: 'https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz',
-  };
-}
-
-function archiveTransport(fixture, requests, responseForUrl) {
-  return (specification) => {
-    if (specification.command !== 'curl') {
-      return defaultRunProcess(specification);
-    }
-    const url = specification.args.at(specification.args.indexOf('--url') + 1);
-    const output = specification.args.at(specification.args.indexOf('--output') + 1);
-    requests.push(url);
-    const response = responseForUrl(url);
-    if (response instanceof Error) {
-      throw response;
-    }
-    copyFileSync(fixture, output);
-    return '';
-  };
-}
-
-function writeArchiveManifest(manifestPath, source) {
-  writeFileSync(
-    manifestPath,
-    `name = "${source.name}"\nkind = "archive"\nurl = "${source.url}"\nbranch = "${source.branch}"\ncommit = "${source.commit}"\nsha256 = "${source.sha256}"\nstrip_prefix = "${source.stripPrefix}"\n`,
-  );
-}
-
-function sourceFetcher(root, overrides = {}) {
-  return createSourceFetcher({
-    workspaceRoot: path.resolve(import.meta.dirname, '..', '..', '..'),
-    checkoutRoot: path.join(root, 'checkouts'),
-    archiveRoot: path.join(root, 'archives'),
-    archiveTool,
-    zipArchiveTool,
-    gitAttempts: 1,
-    sleep: async () => {},
-    ...overrides,
-  });
-}
-
-function initializeGitRepository(repository, contents, branch = 'old') {
-  mkdirSync(repository, {recursive: true});
-  command('git', ['init', '--quiet', `--initial-branch=${branch}`], {cwd: repository});
-  command('git', ['config', 'user.name', 'Source Fetch Test'], {cwd: repository});
-  command('git', ['config', 'user.email', 'source-fetch@example.invalid'], {cwd: repository});
-  writeFileSync(path.join(repository, 'source.txt'), contents);
-  command('git', ['add', 'source.txt'], {cwd: repository});
-  command('git', ['commit', '--quiet', '-m', 'test source'], {cwd: repository});
-  return command('git', ['rev-parse', 'HEAD'], {cwd: repository});
-}
-
-test('archive validator extracts only the declared safe root', () => {
-  const root = makeRoot('source-archive-valid');
-  try {
-    createTarFixtures(root);
-    const archive = path.join(root, 'valid.tar.gz');
-    assert.equal(validateArchive(archive).status, 0);
-    const destination = path.join(root, 'out');
-    const extraction = spawnSync('python3', [archiveTool, 'extract', archive, 'pkg', destination], {
-      encoding: 'utf8',
-    });
-    assert.equal(extraction.status, 0, extraction.stderr);
-    assert.equal(readFileSync(path.join(destination, 'file.txt'), 'utf8'), 'trusted bytes');
-    assert.equal(readFileSync(path.join(destination, 'link.txt'), 'utf8'), 'trusted bytes');
-    assert.equal(readFileSync(path.join(destination, 'hard.txt'), 'utf8'), 'trusted bytes');
-    assert.equal(existsSync(path.join(destination, 'pkg')), false);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('ZIP source validator extracts a safe rootless release and rejects unsafe members', () => {
-  const root = makeRoot('source-zip-valid');
-  try {
-    createZipFixtures(root);
-    const archive = path.join(root, 'valid.zip');
-    assert.equal(validateZipArchive(archive).status, 0);
-    const destination = path.join(root, 'out');
-    const extraction = spawnSync(
-      'python3',
-      [zipArchiveTool, 'extract', archive, '.', destination],
-      {encoding: 'utf8'},
-    );
-    assert.equal(extraction.status, 0, extraction.stderr);
-    assert.equal(readFileSync(path.join(destination, 'payload/data.bin'), 'utf8'), 'trusted bytes');
-    assert.notEqual(validateZipArchive(path.join(root, 'traversal.zip')).status, 0);
-    assert.notEqual(validateZipArchive(path.join(root, 'symlink.zip')).status, 0);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('source fetcher materializes a pinned rootless ZIP release', async () => {
-  const root = makeRoot('source-zip-materialize');
-  try {
-    createZipFixtures(root);
-    const fixture = path.join(root, 'valid.zip');
-    const sha256 = sha256File(fixture);
-    const source = {
-      name: 'zip-fixture',
-      kind: 'archive',
-      url: 'https://example.invalid/zip-fixture.zip',
-      branch: 'archive-1.0',
-      commit: sha256,
-      sha256,
-      stripPrefix: '.',
-    };
-    const fetcher = sourceFetcher(root, {
-      downloadFile: (_source, output) => copyFileSync(fixture, output),
-    });
-    const checkout = path.join(root, 'checkouts', source.name);
-    await fetcher.materialize(source, checkout);
-    assert.equal(readFileSync(path.join(checkout, 'payload/data.bin'), 'utf8'), 'trusted bytes');
-    fetcher.verify(source, checkout);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test(
-  'archive validator rejects traversal, unsafe links and types, duplicates, reserved paths, and expansion abuse',
-  {timeout: 30_000},
-  () => {
-    const root = makeRoot('source-archive-adversarial');
-    try {
-      createTarFixtures(root);
-      for (const name of [
-        'traversal',
-        'absolute',
-        'outside-prefix',
-        'backslash',
-        'duplicate',
-        'case-collision',
-        'windows-ads',
-        'windows-device',
-        'escaping-symlink',
-        'dangling-symlink',
-        'escaping-hardlink',
-        'fifo',
-        'reserved-git',
-        'reserved-stamp',
-        'symlink-ancestor',
-        'huge',
-      ]) {
-        const archive = path.join(root, `${name}.tar.gz`);
-        const validation = validateArchive(archive);
-        assert.notEqual(validation.status, 0, `${name} unexpectedly passed validation`);
-        const destination = path.join(root, `out-${name}`);
-        const extraction = spawnSync('python3', [archiveTool, 'extract', archive, 'pkg', destination], {
-          encoding: 'utf8',
-        });
-        assert.notEqual(extraction.status, 0, `${name} unexpectedly extracted`);
-        assert.equal(existsSync(destination), false, `${name} left a partial destination`);
-      }
-    } finally {
-      rmSync(root, {recursive: true, force: true});
-    }
-  },
-);
-
-test('archive transport is HTTPS-only and bounded', () => {
-  assert.throws(() => assertHttpsUrl('http://example.test/source.tar.gz'), /must use HTTPS/u);
-  assert.throws(() => assertHttpsUrl('https://user:secret@example.test/source.tar.gz'), /credentials/u);
-  assert.throws(() => assertHttpsUrl('https://example.test\\source.tar.gz'), /canonical/u);
-  const args = curlDownloadArgs('https://example.test/source.tar.gz', '/tmp/candidate');
-  assert.equal(args[0], '--disable');
-  for (const token of [
-    '--retry-max-time',
-    '--connect-timeout',
-    '--max-time',
-    '--speed-limit',
-    '--speed-time',
-    '--max-filesize',
-    '--proto',
-    '--proto-redir',
-    '=https',
-    '--tlsv1.2',
-    '--remove-on-error',
-  ]) {
-    assert.ok(args.includes(token), `missing bounded transport argument ${token}`);
-  }
-});
-
-test('GNU archive transport keeps a healthy pinned mirror as the sole request', async () => {
-  const root = makeRoot('source-gnu-primary');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const source = gnuArchiveSource(fixture);
-    const requests = [];
-    await sourceFetcher(root, {
-      runProcess: archiveTransport(fixture, requests, () => undefined),
-    }).materialize(source);
-
-    assert.deepEqual(requests, [source.url]);
-    const marker = readFileSync(
-      path.join(root, 'checkouts', source.name, '.oliphaunt-source-pin'),
-      'utf8',
-    );
-    assert.equal(marker.split('\n').includes(`url=${source.url}`), true);
-    assert.doesNotMatch(marker, /ftp\.gnu\.org/u);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('GNU archive transport retries the canonical host after a bounded pinned-mirror failure', async () => {
-  const root = makeRoot('source-gnu-fallback');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const source = gnuArchiveSource(fixture);
-    const fallback = 'https://ftp.gnu.org/gnu/libiconv/libiconv-1.19.tar.gz';
-    const requests = [];
-    await sourceFetcher(root, {
-      runProcess: archiveTransport(fixture, requests, (url) =>
-        url === source.url ? new Error('injected bounded primary transport failure') : undefined),
-    }).materialize(source);
-
-    assert.deepEqual(requests, [source.url, fallback]);
-    const marker = readFileSync(
-      path.join(root, 'checkouts', source.name, '.oliphaunt-source-pin'),
-      'utf8',
-    );
-    assert.equal(marker.split('\n').includes(`url=${source.url}`), true);
-    assert.doesNotMatch(marker, /ftp\.gnu\.org/u);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('GNU archive fallback bytes must still satisfy the pinned checksum before promotion', async () => {
-  const root = makeRoot('source-gnu-fallback-checksum');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const wrongFixture = path.join(root, 'updated.tar.gz');
-    const source = gnuArchiveSource(fixture);
-    const fallback = 'https://ftp.gnu.org/gnu/libiconv/libiconv-1.19.tar.gz';
-    const requests = [];
-    await assert.rejects(
-      sourceFetcher(root, {
-        runProcess: archiveTransport(wrongFixture, requests, (url) =>
-          url === source.url ? new Error('injected bounded primary transport failure') : undefined),
-      }).materialize(source),
-      new RegExp(`libiconv archive sha256: expected ${source.sha256}, got [0-9a-f]{64}`, 'u'),
-    );
-
-    assert.deepEqual(requests, [source.url, fallback]);
-    assert.deepEqual(readdirSync(path.join(root, 'archives')), []);
-    assert.equal(existsSync(path.join(root, 'checkouts', source.name)), false);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('GNU archive transport preserves both diagnostics when both bounded endpoints fail', async () => {
-  const root = makeRoot('source-gnu-both-fail');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const source = gnuArchiveSource(fixture);
-    const fallback = 'https://ftp.gnu.org/gnu/libiconv/libiconv-1.19.tar.gz';
-    const archiveRoot = path.join(root, 'archives');
-    const cached = path.join(archiveRoot, `${source.name}-${source.sha256}.tar.gz`);
-    mkdirSync(archiveRoot);
-    writeFileSync(cached, 'prior corrupt archive bytes');
-    const requests = [];
-    let failure;
-    try {
-      await sourceFetcher(root, {
-        runProcess: archiveTransport(fixture, requests, (url) =>
-          new Error(url === source.url ? 'primary diagnostic' : 'fallback diagnostic')),
-      }).materialize(source);
-    } catch (error) {
-      failure = error;
-    }
-
-    assert.ok(failure instanceof AggregateError);
-    assert.match(failure.message, /primary diagnostic/u);
-    assert.match(failure.message, /fallback diagnostic/u);
-    assert.deepEqual(failure.errors.map((error) => error.message), [
-      'primary diagnostic',
-      'fallback diagnostic',
-    ]);
-    assert.deepEqual(requests, [source.url, fallback]);
-    assert.equal(readFileSync(cached, 'utf8'), 'prior corrupt archive bytes');
-    assert.deepEqual(readdirSync(archiveRoot), [`${source.name}-${source.sha256}.tar.gz`]);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('GNU archive fallback is unavailable to other hosts and noncanonical or unsafe paths', async () => {
-  const root = makeRoot('source-gnu-fallback-scope');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const urls = [
-      'https://example.invalid/libiconv/libiconv-1.19.tar.gz',
-      'https://ftpmirror.gnu.org/libiconv/nested/libiconv-1.19.tar.gz',
-      'https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz?mutable=1',
-      'https://ftpmirror.gnu.org/libiconv/%6cibiconv-1.19.tar.gz',
-      'https://ftpmirror.gnu.org/libiconv/../libiconv-1.19.tar.gz',
-    ];
-    assert.equal(
-      canonicalGnuArchiveFallbackUrl(
-        'https://ftpmirror.gnu.org/libiconv/libiconv-1.19.zip',
-      ),
-      undefined,
-    );
-    for (const [index, url] of urls.entries()) {
-      assert.equal(canonicalGnuArchiveFallbackUrl(url), undefined);
-      const source = {...archiveSource(fixture, `fixture-${index}`), url};
-      const requests = [];
-      await assert.rejects(
-        sourceFetcher(path.join(root, String(index)), {
-          runProcess: archiveTransport(fixture, requests, () =>
-            new Error(`injected primary-only failure ${index}`)),
-        }).materialize(source),
-        new RegExp(`injected primary-only failure ${index}`, 'u'),
-      );
-      assert.deepEqual(requests, [url]);
-    }
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('Windows transport tolerates only an unavailable Schannel revocation service', () => {
-  assert.deepEqual(curlPlatformTlsArgs('win32'), ['--ssl-revoke-best-effort']);
-  assert.deepEqual(curlPlatformTlsArgs('linux'), []);
-  assert.deepEqual(curlPlatformTlsArgs('darwin'), []);
-
-  const windows = curlDownloadArgs(
-    'https://example.test/source.tar.gz',
-    'C:/candidate',
-    {platform: 'win32'},
-  );
-  assert.equal(windows.includes('--ssl-revoke-best-effort'), true);
-  assert.equal(windows.includes('--insecure'), false);
-  assert.equal(windows.includes('-k'), false);
-
-  const linux = curlDownloadArgs(
-    'https://example.test/source.tar.gz',
-    '/tmp/candidate',
-    {platform: 'linux'},
-  );
-  assert.equal(linux.includes('--ssl-revoke-best-effort'), false);
-});
-
-test('transactional promotion restores the prior destination on a normal failure', () => {
-  const root = makeRoot('source-promotion');
-  try {
-    const destination = path.join(root, 'live');
-    const candidate = path.join(root, 'candidate');
-    mkdirSync(destination);
-    mkdirSync(candidate);
-    writeFileSync(path.join(destination, 'value'), 'old');
-    writeFileSync(path.join(candidate, 'value'), 'new');
-    assert.throws(
-      () => promotePathTransactional(candidate, destination, {afterBackup: () => { throw new Error('fault'); }}),
-      /fault/u,
-    );
-    assert.equal(readFileSync(path.join(destination, 'value'), 'utf8'), 'old');
-    assert.equal(readFileSync(path.join(candidate, 'value'), 'utf8'), 'new');
-    assert.deepEqual(readdirSync(root).sort(), ['candidate', 'live']);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('a corrupt archive cache is retained on download failure and replaced only by a verified candidate', async () => {
-  const root = makeRoot('source-cache-repair');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const source = archiveSource(fixture);
-    const archiveRoot = path.join(root, 'archives');
-    mkdirSync(archiveRoot);
-    const cached = path.join(archiveRoot, `${source.name}-${source.sha256}.tar.gz`);
-    writeFileSync(cached, 'corrupt previous bytes');
-
-    const failing = sourceFetcher(root, {downloadFile: () => { throw new Error('network fault'); }});
-    await assert.rejects(failing.ensureArchive(source), /network fault/u);
-    assert.equal(readFileSync(cached, 'utf8'), 'corrupt previous bytes');
-
-    const repairing = sourceFetcher(root, {downloadFile: (_source, output) => copyFileSync(fixture, output)});
-    assert.equal(await repairing.ensureArchive(source), cached);
-    assert.equal(sha256File(cached), source.sha256);
-    assert.deepEqual(readdirSync(archiveRoot), [`${source.name}-${source.sha256}.tar.gz`]);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('archive extraction failure preserves the prior checkout', async () => {
-  const root = makeRoot('source-extract-rollback');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const source = archiveSource(fixture);
-    const checkout = path.join(root, 'checkouts', source.name);
-    await sourceFetcher(root, {downloadFile: (_source, output) => copyFileSync(fixture, output)}).materialize(source);
-    const updatedFixture = path.join(root, 'updated.tar.gz');
-    const updatedSource = archiveSource(updatedFixture);
-    const fetcher = sourceFetcher(root, {
-      downloadFile: (_source, output) => copyFileSync(updatedFixture, output),
-      extractArchive: () => { throw new Error('extract fault'); },
-    });
-    await assert.rejects(fetcher.materialize(updatedSource), /extract fault/u);
-    assert.equal(readFileSync(path.join(checkout, 'file.txt'), 'utf8'), 'trusted bytes');
-    assert.deepEqual(readdirSync(path.dirname(checkout)), [source.name]);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('modified stamped archive checkout is rejected and preserved', async () => {
-  const root = makeRoot('source-archive-dirty');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const source = archiveSource(fixture);
-    const checkout = path.join(root, 'checkouts', source.name);
-    const fetcher = sourceFetcher(root, {downloadFile: (_source, output) => copyFileSync(fixture, output)});
-    await fetcher.materialize(source);
-    writeFileSync(path.join(checkout, 'file.txt'), 'local modification');
-    await assert.rejects(fetcher.materialize(source), /was modified/u);
-    assert.equal(readFileSync(path.join(checkout, 'file.txt'), 'utf8'), 'local modification');
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('offline checkout verifier agrees with the source fetcher and detects modification', async () => {
-  const root = makeRoot('source-archive-offline-verify');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const source = archiveSource(fixture);
-    const checkout = path.join(root, 'checkouts', source.name);
-    const manifest = path.join(root, 'source.toml');
-    writeArchiveManifest(manifest, source);
-    await sourceFetcher(root, {downloadFile: (_source, output) => copyFileSync(fixture, output)}).materialize(source);
-    const verified = spawnSync(
-      'python3',
-      [treeVerifier, '--checkout', checkout, '--manifest', manifest],
-      {encoding: 'utf8'},
-    );
-    assert.equal(verified.status, 0, verified.stderr);
-    assert.match(verified.stdout, /^[0-9a-f]{64}\r?\n$/u);
-    writeFileSync(path.join(checkout, 'file.txt'), 'modified after verification');
-    const modified = spawnSync(
-      'python3',
-      [treeVerifier, '--checkout', checkout, '--manifest', manifest],
-      {encoding: 'utf8'},
-    );
-    assert.notEqual(modified.status, 0);
-    assert.match(modified.stderr, /was modified/u);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('unmanaged durable directory is rejected without download or replacement', async () => {
-  const root = makeRoot('source-archive-unmanaged');
-  try {
-    createTarFixtures(root);
-    const fixture = path.join(root, 'valid.tar.gz');
-    const source = archiveSource(fixture);
-    const checkout = path.join(root, 'checkouts', source.name);
-    mkdirSync(checkout, {recursive: true});
-    writeFileSync(path.join(checkout, 'prior'), 'unmanaged bytes');
-    let downloaded = false;
-    const fetcher = sourceFetcher(root, {
-      downloadFile: () => {
-        downloaded = true;
-        throw new Error('must not download');
-      },
-    });
-    await assert.rejects(fetcher.materialize(source), /is unmanaged/u);
-    assert.equal(downloaded, false);
-    assert.equal(readFileSync(path.join(checkout, 'prior'), 'utf8'), 'unmanaged bytes');
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('stale clean managed archive pin updates transactionally', async () => {
-  const root = makeRoot('source-archive-stale');
-  try {
-    createTarFixtures(root);
-    const firstFixture = path.join(root, 'valid.tar.gz');
-    const secondFixture = path.join(root, 'updated.tar.gz');
-    const first = archiveSource(firstFixture);
-    const second = archiveSource(secondFixture);
-    const checkout = path.join(root, 'checkouts', first.name);
-    await sourceFetcher(root, {
-      downloadFile: (_source, output) => copyFileSync(firstFixture, output),
-    }).materialize(first);
-    await sourceFetcher(root, {
-      downloadFile: (_source, output) => copyFileSync(secondFixture, output),
-    }).materialize(second);
-    assert.equal(readFileSync(path.join(checkout, 'file.txt'), 'utf8'), 'updated trusted bytes');
-    assert.equal(existsSync(path.join(checkout, 'link.txt')), false);
-    assert.deepEqual(readdirSync(path.dirname(checkout)), [first.name]);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('source mirror transport is HTTPS-only, distinct, and Git-only', async () => {
-  const root = makeRoot('source-mirror-validation');
-  try {
-    const gitSource = {
-      name: 'source',
-      kind: 'git',
-      url: 'https://example.invalid/source.git',
-      branch: 'pinned',
-      commit: '1111111111111111111111111111111111111111',
-    };
-    for (const [mirrorUrl, pattern] of [
-      ['http://example.invalid/source.git', /must use HTTPS/u],
-      ['https://user:secret@example.invalid/source.git', /credentials/u],
-      ['https://example.invalid/source.git#mutable', /fragment/u],
-      ['https://example.invalid\\source.git', /canonical/u],
-      [gitSource.url, /must differ from its primary URL/u],
-    ]) {
-      await assert.rejects(
-        sourceFetcher(root).materialize({...gitSource, mirrorUrl}),
-        pattern,
-      );
-    }
-
-    const sha256 = '2'.repeat(64);
-    await assert.rejects(
-      sourceFetcher(root).materialize({
-        name: 'archive',
-        kind: 'archive',
-        url: 'https://example.invalid/archive.tar.gz',
-        mirrorUrl: 'https://mirror.invalid/archive.tar.gz',
-        branch: 'archive-1.0',
-        commit: sha256,
-        sha256,
-        stripPrefix: 'archive',
-      }),
-      /must not set mirror_url/u,
-    );
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('Git fetch uses a healthy primary without contacting or delaying for its mirror', async () => {
-  const root = makeRoot('source-git-primary');
-  try {
-    const upstream = path.join(root, 'upstream');
-    const commit = initializeGitRepository(upstream, 'exact primary bytes', 'upstream');
-    const source = {
-      name: 'source',
-      kind: 'git',
-      url: 'https://primary.example.invalid/source.git',
-      mirrorUrl: 'https://mirror.example.invalid/source.git',
-      branch: 'pinned',
-      commit,
-    };
-    const fetchedUrls = [];
-    const sleeps = [];
-    const runProcess = (specification) => {
-      if (specification.command === 'git' && specification.args.includes('fetch')) {
-        const requestedUrl = specification.args.at(-2);
-        fetchedUrls.push(requestedUrl);
-        assert.equal(requestedUrl, source.url);
-        return defaultRunProcess({
-          ...specification,
-          args: [
-            '-c',
-            'protocol.file.allow=always',
-            'fetch',
-            '--no-tags',
-            '--depth=1',
-            upstream,
-            commit,
-          ],
-        });
-      }
-      return defaultRunProcess(specification);
-    };
-
-    await sourceFetcher(root, {
-      gitAttempts: 5,
-      runProcess,
-      sleep: async (milliseconds) => sleeps.push(milliseconds),
-    }).materialize(source);
-
-    const checkout = path.join(root, 'checkouts', source.name);
-    assert.deepEqual(fetchedUrls, [source.url]);
-    assert.deepEqual(sleeps, []);
-    assert.equal(command('git', ['rev-parse', 'HEAD'], {cwd: checkout}), commit);
-    assert.equal(command('git', ['branch', '--show-current'], {cwd: checkout}), source.branch);
-    assert.equal(command('git', ['remote', 'get-url', 'origin'], {cwd: checkout}), source.url);
-    assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'exact primary bytes');
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('Git fetch fails over immediately to an exact mirror commit and retains the canonical origin', async () => {
-  const root = makeRoot('source-git-mirror');
-  try {
-    const upstream = path.join(root, 'upstream');
-    const commit = initializeGitRepository(upstream, 'exact mirror bytes', 'upstream');
-    const checkout = path.join(root, 'checkouts', 'source');
-    const priorCommit = initializeGitRepository(checkout, 'prior durable bytes');
-    const source = {
-      name: 'source',
-      kind: 'git',
-      url: 'https://primary.example.invalid/source.git',
-      mirrorUrl: 'https://mirror.example.invalid/source.git',
-      branch: 'pinned',
-      commit,
-    };
-    const fetchedUrls = [];
-    const sleeps = [];
-    const runProcess = (specification) => {
-      if (specification.command === 'git' && specification.args.includes('fetch')) {
-        const requestedUrl = specification.args.at(-2);
-        fetchedUrls.push(requestedUrl);
-        if (requestedUrl === source.url) {
-          throw new Error('injected primary transport fault');
-        }
-        assert.equal(requestedUrl, source.mirrorUrl);
-        return defaultRunProcess({
-          ...specification,
-          args: [
-            '-c',
-            'protocol.file.allow=always',
-            'fetch',
-            '--no-tags',
-            '--depth=1',
-            upstream,
-            commit,
-          ],
-        });
-      }
-      return defaultRunProcess(specification);
-    };
-
-    await sourceFetcher(root, {
-      gitAttempts: 5,
-      runProcess,
-      sleep: async (milliseconds) => sleeps.push(milliseconds),
-    }).materialize(source);
-
-    assert.notEqual(priorCommit, commit);
-    assert.deepEqual(fetchedUrls, [source.url, source.mirrorUrl]);
-    assert.deepEqual(sleeps, []);
-    assert.equal(command('git', ['rev-parse', 'HEAD'], {cwd: checkout}), commit);
-    assert.equal(command('git', ['branch', '--show-current'], {cwd: checkout}), source.branch);
-    assert.equal(command('git', ['remote', 'get-url', 'origin'], {cwd: checkout}), source.url);
-    assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'exact mirror bytes');
-    assert.deepEqual(readdirSync(path.dirname(checkout)), [source.name]);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('Git fetch bounds alternating transport failures and preserves durable state', async () => {
-  const root = makeRoot('source-git-mirror-fault');
-  try {
-    const checkout = path.join(root, 'checkouts', 'source');
-    const priorCommit = initializeGitRepository(checkout, 'prior durable bytes');
-    const source = {
-      name: 'source',
-      kind: 'git',
-      url: 'https://primary.example.invalid/source.git',
-      mirrorUrl: 'https://mirror.example.invalid/source.git',
-      branch: 'pinned',
-      commit: '1111111111111111111111111111111111111111',
-    };
-    const fetchedUrls = [];
-    const sleeps = [];
-    const runProcess = (specification) => {
-      if (specification.command === 'git' && specification.args.includes('fetch')) {
-        fetchedUrls.push(specification.args.at(-2));
-        throw new Error('injected transport fault');
-      }
-      return defaultRunProcess(specification);
-    };
-
-    await assert.rejects(
-      sourceFetcher(root, {
-        gitAttempts: 5,
-        runProcess,
-        sleep: async (milliseconds) => sleeps.push(milliseconds),
-      }).materialize(source),
-      /injected transport fault/u,
-    );
-
-    assert.deepEqual(fetchedUrls, [
-      source.url,
-      source.mirrorUrl,
-      source.url,
-      source.mirrorUrl,
-      source.url,
-    ]);
-    assert.deepEqual(sleeps, [5_000, 10_000]);
-    assert.equal(command('git', ['rev-parse', 'HEAD'], {cwd: checkout}), priorCommit);
-    assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'prior durable bytes');
-    assert.deepEqual(readdirSync(path.dirname(checkout)), [source.name]);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('Git mirror cannot promote a different commit than the exact pin', async () => {
-  const root = makeRoot('source-git-mirror-wrong-commit');
-  try {
-    const upstream = path.join(root, 'upstream');
-    const mirrorCommit = initializeGitRepository(upstream, 'wrong mirror bytes', 'upstream');
-    const checkout = path.join(root, 'checkouts', 'source');
-    const priorCommit = initializeGitRepository(checkout, 'prior durable bytes');
-    const source = {
-      name: 'source',
-      kind: 'git',
-      url: 'https://primary.example.invalid/source.git',
-      mirrorUrl: 'https://mirror.example.invalid/source.git',
-      branch: 'pinned',
-      commit: '1111111111111111111111111111111111111111',
-    };
-    const fetchedUrls = [];
-    const runProcess = (specification) => {
-      if (specification.command === 'git' && specification.args.includes('fetch')) {
-        const requestedUrl = specification.args.at(-2);
-        fetchedUrls.push(requestedUrl);
-        if (requestedUrl === source.url) {
-          throw new Error('injected primary transport fault');
-        }
-        return defaultRunProcess({
-          ...specification,
-          args: [
-            '-c',
-            'protocol.file.allow=always',
-            'fetch',
-            '--no-tags',
-            '--depth=1',
-            upstream,
-            mirrorCommit,
-          ],
-        });
-      }
-      return defaultRunProcess(specification);
-    };
-
-    await assert.rejects(
-      sourceFetcher(root, {gitAttempts: 2, runProcess, sleep: async () => {}}).materialize(source),
-      /expected exact commit/u,
-    );
-
-    assert.deepEqual(fetchedUrls, [source.url, source.mirrorUrl]);
-    assert.equal(command('git', ['rev-parse', 'HEAD'], {cwd: checkout}), priorCommit);
-    assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'prior durable bytes');
-    assert.deepEqual(readdirSync(path.dirname(checkout)), [source.name]);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('dirty durable Git checkout is rejected before staging', async () => {
-  const root = makeRoot('source-git-dirty');
-  try {
-    const checkout = path.join(root, 'checkouts', 'source');
-    const commit = initializeGitRepository(checkout, 'committed');
-    command('git', ['remote', 'add', 'origin', 'https://example.invalid/source.git'], {cwd: checkout});
-    writeFileSync(path.join(checkout, 'source.txt'), 'dirty');
-    const source = {
-      name: 'source',
-      kind: 'git',
-      url: 'https://example.invalid/source.git',
-      branch: 'old',
-      commit,
-    };
-    await assert.rejects(sourceFetcher(root).materialize(source), /uncommitted changes/u);
-    assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'dirty');
-    assert.deepEqual(readdirSync(path.join(root, 'checkouts')), ['source']);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test(
-  'durable Git checkout accepts a canonical alias in an ancestor path',
-  {skip: process.platform === 'win32'},
-  async () => {
-    const root = makeRoot('source-git-ancestor-alias');
-    try {
-      const durableRoot = path.join(root, 'durable');
-      const aliasRoot = path.join(root, 'alias');
-      mkdirSync(durableRoot);
-      symlinkSync(durableRoot, aliasRoot, 'dir');
-      const checkout = path.join(aliasRoot, 'checkouts', 'source');
-      const commit = initializeGitRepository(checkout, 'committed');
-      const source = {
-        name: 'source',
-        kind: 'git',
-        url: 'https://example.invalid/source.git',
-        branch: 'old',
-        commit,
-      };
-      command('git', ['remote', 'add', 'origin', source.url], {cwd: checkout});
-      command('git', ['config', '--local', 'core.autocrlf', 'false'], {cwd: checkout});
-      command('git', ['config', '--local', 'core.eol', 'lf'], {cwd: checkout});
-      let fetched = false;
-      const runProcess = (specification) => {
-        if (specification.command === 'git' && specification.args.includes('fetch')) {
-          fetched = true;
-          throw new Error('an exact durable checkout must not be fetched again');
-        }
-        return defaultRunProcess(specification);
-      };
-
-      await sourceFetcher(aliasRoot, {runProcess}).materialize(source);
-
-      assert.equal(fetched, false);
-      assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'committed');
-    } finally {
-      rmSync(root, {recursive: true, force: true});
-    }
-  },
-);
-
-test(
-  'durable Git checkout rejects linked metadata even when it resolves to a real repository',
-  {skip: process.platform === 'win32'},
-  async () => {
-    const root = makeRoot('source-git-linked-metadata');
-    try {
-      const external = path.join(root, 'external');
-      const commit = initializeGitRepository(external, 'external');
-      const checkout = path.join(root, 'checkouts', 'source');
-      mkdirSync(checkout, {recursive: true});
-      symlinkSync(path.join(external, '.git'), path.join(checkout, '.git'), 'dir');
-      const source = {
-        name: 'source',
-        kind: 'git',
-        url: 'https://example.invalid/source.git',
-        branch: 'old',
-        commit,
-      };
-
-      await assert.rejects(sourceFetcher(root).materialize(source), /unsupported non-directory \.git metadata/u);
-    } finally {
-      rmSync(root, {recursive: true, force: true});
-    }
-  },
-);
-
-test('failed staged Git fetch leaves a stale clean durable checkout unchanged', async () => {
-  const root = makeRoot('source-git-fetch-fault');
-  try {
-    const checkout = path.join(root, 'checkouts', 'source');
-    const priorCommit = initializeGitRepository(checkout, 'prior');
-    const source = {
-      name: 'source',
-      kind: 'git',
-      url: 'https://example.invalid/source.git',
-      branch: 'pinned',
-      commit: '1111111111111111111111111111111111111111',
-    };
-    const runProcess = (specification) => {
-      if (specification.command === 'git' && specification.args.includes('fetch')) {
-        throw new Error('injected fetch fault');
-      }
-      return defaultRunProcess(specification);
-    };
-    await assert.rejects(sourceFetcher(root, {runProcess}).materialize(source), /injected fetch fault/u);
-    assert.equal(command('git', ['rev-parse', 'HEAD'], {cwd: checkout}), priorCommit);
-    assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'prior');
-    assert.deepEqual(readdirSync(path.join(root, 'checkouts')), ['source']);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('Git fetch stages and verifies the exact commit before replacing a clean checkout', {timeout: 15_000}, async () => {
-  const root = makeRoot('source-git-exact');
-  try {
-    const upstream = path.join(root, 'upstream');
-    const commit = initializeGitRepository(upstream, 'exact upstream bytes', 'upstream');
-    const checkout = path.join(root, 'checkouts', 'source');
-    initializeGitRepository(checkout, 'prior durable bytes');
-    const source = {
-      name: 'source',
-      kind: 'git',
-      url: 'https://example.invalid/source.git',
-      branch: 'pinned',
-      commit,
-    };
-    const runProcess = (specification) => {
-      if (specification.command === 'git' && specification.args.includes('fetch')) {
-        return defaultRunProcess({
-          ...specification,
-          args: [
-            '-c',
-            'protocol.file.allow=always',
-            'fetch',
-            '--no-tags',
-            '--depth=1',
-            upstream,
-            commit,
-          ],
-        });
-      }
-      return defaultRunProcess(specification);
-    };
-    await sourceFetcher(root, {runProcess}).materialize(source);
-    assert.equal(command('git', ['rev-parse', 'HEAD'], {cwd: checkout}), commit);
-    assert.equal(command('git', ['branch', '--show-current'], {cwd: checkout}), 'pinned');
-    assert.equal(command('git', ['remote', 'get-url', 'origin'], {cwd: checkout}), source.url);
-    assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'exact upstream bytes');
-    assert.deepEqual(readdirSync(path.join(root, 'checkouts')), ['source']);
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test('Git fetch materializes text bytes independently of host line-ending configuration', {timeout: 15_000}, async () => {
-  const root = makeRoot('source-git-line-endings');
-  try {
-    const upstream = path.join(root, 'upstream');
-    mkdirSync(upstream, {recursive: true});
-    command('git', ['init', '--quiet', '--initial-branch=upstream'], {cwd: upstream});
-    command('git', ['config', 'user.name', 'Source Fetch Test'], {cwd: upstream});
-    command('git', ['config', 'user.email', 'source-fetch@example.invalid'], {cwd: upstream});
-    writeFileSync(path.join(upstream, '.gitattributes'), '* text=auto\n');
-    writeFileSync(path.join(upstream, 'source.txt'), 'first line\nsecond line\n');
-    command('git', ['add', '.gitattributes', 'source.txt'], {cwd: upstream});
-    command('git', ['commit', '--quiet', '-m', 'test source'], {cwd: upstream});
-    const commit = command('git', ['rev-parse', 'HEAD'], {cwd: upstream});
-    const source = {
-      name: 'source',
-      kind: 'git',
-      url: 'https://example.invalid/source.git',
-      branch: 'pinned',
-      commit,
-    };
-    let fetches = 0;
-    const runProcess = (specification) => {
-      const hostileLineEndingConfig = [
-        '-c',
-        'core.autocrlf=true',
-        '-c',
-        'core.eol=crlf',
-      ];
-      if (specification.command === 'git' && specification.args.includes('fetch')) {
-        fetches += 1;
-        const args = [...specification.args];
-        args.splice(args.length - 2, 1, upstream);
-        return defaultRunProcess({
-          ...specification,
-          args: [...hostileLineEndingConfig, '-c', 'protocol.file.allow=always', ...args],
-        });
-      }
-      if (specification.command === 'git') {
-        return defaultRunProcess({
-          ...specification,
-          args: [...hostileLineEndingConfig, ...specification.args],
-        });
-      }
-      return defaultRunProcess(specification);
-    };
-
-    const fetcher = sourceFetcher(root, {runProcess});
-    await fetcher.materialize(source);
-
-    const checkout = path.join(root, 'checkouts', source.name);
-    assert.equal(fetches, 1);
-    assert.equal(command('git', ['config', '--local', '--get', 'core.autocrlf'], {cwd: checkout}), 'false');
-    assert.equal(command('git', ['config', '--local', '--get', 'core.eol'], {cwd: checkout}), 'lf');
-    assert.deepEqual(
-      readFileSync(path.join(checkout, 'source.txt')),
-      Buffer.from('first line\nsecond line\n'),
-    );
-
-    // A checkout created under the old policy can contain CRLF bytes yet still
-    // appear clean to Git because `text=auto` normalizes them for comparison.
-    // Poison only the local checkout policy, then prove materialization does
-    // not reuse that exact-pin cache entry.
-    command('git', ['config', '--local', 'core.autocrlf', 'true'], {cwd: checkout});
-    command('git', ['config', '--local', 'core.eol', 'crlf'], {cwd: checkout});
-    rmSync(path.join(checkout, 'source.txt'));
-    command('git', ['checkout', '--', 'source.txt'], {cwd: checkout});
-    assert.deepEqual(
-      readFileSync(path.join(checkout, 'source.txt')),
-      Buffer.from('first line\r\nsecond line\r\n'),
-    );
-    assert.equal(
-      command('git', [
-        '-c',
-        'core.autocrlf=false',
-        '-c',
-        'core.eol=lf',
-        'status',
-        '--porcelain=v1',
-        '--untracked-files=all',
-      ], {cwd: checkout}),
-      '',
-    );
-
-    await fetcher.materialize(source);
-
-    assert.equal(fetches, 2);
-    assert.equal(command('git', ['config', '--local', '--get', 'core.autocrlf'], {cwd: checkout}), 'false');
-    assert.equal(command('git', ['config', '--local', '--get', 'core.eol'], {cwd: checkout}), 'lf');
-    assert.deepEqual(
-      readFileSync(path.join(checkout, 'source.txt')),
-      Buffer.from('first line\nsecond line\n'),
-    );
-  } finally {
-    rmSync(root, {recursive: true, force: true});
-  }
-});
-
-test(
-  'staged Git checkout rejects an escaping symlink without replacing durable state',
-  {skip: process.platform === 'win32'},
-  async () => {
-    const root = makeRoot('source-git-unsafe-link');
-    try {
-      const upstream = path.join(root, 'upstream');
-      initializeGitRepository(upstream, 'upstream bytes', 'upstream');
-      symlinkSync('../outside', path.join(upstream, 'escape'));
-      command('git', ['add', 'escape'], {cwd: upstream});
-      command('git', ['commit', '--quiet', '-m', 'unsafe link'], {cwd: upstream});
-      const commit = command('git', ['rev-parse', 'HEAD'], {cwd: upstream});
-      const checkout = path.join(root, 'checkouts', 'source');
-      const priorCommit = initializeGitRepository(checkout, 'prior durable bytes');
-      const source = {
-        name: 'source',
-        kind: 'git',
-        url: 'https://example.invalid/source.git',
-        branch: 'pinned',
-        commit,
-      };
-      const runProcess = (specification) => {
-        if (specification.command === 'git' && specification.args.includes('fetch')) {
-          return defaultRunProcess({
-            ...specification,
-            args: [
-              '-c',
-              'protocol.file.allow=always',
-              'fetch',
-              '--no-tags',
-              '--depth=1',
-              upstream,
-              commit,
-            ],
-          });
-        }
-        return defaultRunProcess(specification);
-      };
-      await assert.rejects(sourceFetcher(root, {runProcess}).materialize(source), /escaping symlink/u);
-      assert.equal(command('git', ['rev-parse', 'HEAD'], {cwd: checkout}), priorCommit);
-      assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'prior durable bytes');
-      assert.deepEqual(readdirSync(path.join(root, 'checkouts')), ['source']);
-    } finally {
-      rmSync(root, {recursive: true, force: true});
-    }
-  },
-);
-
-test(
-  'staged Git checkout accepts a dangling relative symlink confined to the checkout',
-  {skip: process.platform === 'win32'},
-  async () => {
-    const root = makeRoot('source-git-contained-dangling-link');
-    try {
-      const upstream = path.join(root, 'upstream');
-      initializeGitRepository(upstream, 'upstream bytes', 'upstream');
-      const fixtures = path.join(upstream, 'fixtures');
-      mkdirSync(fixtures);
-      symlinkSync('../missing-fixture', path.join(fixtures, 'dangling'));
-      command('git', ['add', 'fixtures/dangling'], {cwd: upstream});
-      command('git', ['commit', '--quiet', '-m', 'contained dangling link'], {cwd: upstream});
-      const commit = command('git', ['rev-parse', 'HEAD'], {cwd: upstream});
-      const source = {
-        name: 'source',
-        kind: 'git',
-        url: 'https://example.invalid/source.git',
-        branch: 'pinned',
-        commit,
-      };
-      const runProcess = (specification) => {
-        if (specification.command === 'git' && specification.args.includes('fetch')) {
-          return defaultRunProcess({
-            ...specification,
-            args: [
-              '-c',
-              'protocol.file.allow=always',
-              'fetch',
-              '--no-tags',
-              '--depth=1',
-              upstream,
-              commit,
-            ],
-          });
-        }
-        return defaultRunProcess(specification);
-      };
-
-      await sourceFetcher(root, {runProcess}).materialize(source);
-
-      const checkout = path.join(root, 'checkouts', source.name);
-      assert.equal(existsSync(path.join(checkout, 'source.txt')), true);
-      assert.equal(
-        command('git', ['status', '--porcelain=v1', '--untracked-files=all'], {cwd: checkout}),
-        '',
-      );
-    } finally {
-      rmSync(root, {recursive: true, force: true});
-    }
-  },
-);
-
-test(
-  'staged Git checkout rejects a dangling target through an escaping symlink ancestor',
-  {skip: process.platform === 'win32'},
-  async () => {
-    const root = makeRoot('source-git-transitive-dangling-link');
-    try {
-      const upstream = path.join(root, 'upstream');
-      initializeGitRepository(upstream, 'upstream bytes', 'upstream');
-      const fixtures = path.join(upstream, 'fixtures');
-      mkdirSync(fixtures);
-      mkdirSync(path.join(root, 'outside'));
-      // In the staged checkout, ../../../../outside resolves beside the
-      // checkout root. The first link is lexically contained, but its deepest
-      // existing ancestor is the second link and resolves outside the stage.
-      symlinkSync('z-escape/missing', path.join(fixtures, 'a-dangling'));
-      symlinkSync('../../../../outside', path.join(fixtures, 'z-escape'));
-      command('git', ['add', 'fixtures/a-dangling', 'fixtures/z-escape'], {cwd: upstream});
-      command('git', ['commit', '--quiet', '-m', 'transitive dangling escape'], {cwd: upstream});
-      const commit = command('git', ['rev-parse', 'HEAD'], {cwd: upstream});
-      const checkout = path.join(root, 'checkouts', 'source');
-      const priorCommit = initializeGitRepository(checkout, 'prior durable bytes');
-      const source = {
-        name: 'source',
-        kind: 'git',
-        url: 'https://example.invalid/source.git',
-        branch: 'pinned',
-        commit,
-      };
-      const runProcess = (specification) => {
-        if (specification.command === 'git' && specification.args.includes('fetch')) {
-          return defaultRunProcess({
-            ...specification,
-            args: [
-              '-c',
-              'protocol.file.allow=always',
-              'fetch',
-              '--no-tags',
-              '--depth=1',
-              upstream,
-              commit,
-            ],
-          });
-        }
-        return defaultRunProcess(specification);
-      };
-
-      await assert.rejects(
-        sourceFetcher(root, {runProcess}).materialize(source),
-        /escaping .*symlink/u,
-      );
-      assert.equal(command('git', ['rev-parse', 'HEAD'], {cwd: checkout}), priorCommit);
-      assert.equal(readFileSync(path.join(checkout, 'source.txt'), 'utf8'), 'prior durable bytes');
-      assert.deepEqual(readdirSync(path.join(root, 'checkouts')), ['source']);
-    } finally {
-      rmSync(root, {recursive: true, force: true});
-    }
-  },
-);
diff --git a/src/sources/tools/source-fetch-scopes.mjs b/src/sources/tools/source-fetch-scopes.mjs
deleted file mode 100644
index 01da40a73..000000000
--- a/src/sources/tools/source-fetch-scopes.mjs
+++ /dev/null
@@ -1,57 +0,0 @@
-export const sourceOrigins = Object.freeze({
-  sharedThirdParty: 'shared-third-party',
-  nativeThirdParty: 'native-third-party',
-  wasixPostmasterThirdParty: 'wasix-postmaster-third-party',
-  extension: 'extension',
-});
-
-export const defaultSourceScope = 'production-all';
-
-const SOURCE_ORIGINS_BY_SCOPE = Object.freeze({
-  'production-all': Object.freeze([
-    sourceOrigins.sharedThirdParty,
-    sourceOrigins.nativeThirdParty,
-    sourceOrigins.wasixPostmasterThirdParty,
-    sourceOrigins.extension,
-  ]),
-  all: Object.freeze(Object.values(sourceOrigins)),
-  'native-runtime': Object.freeze([
-    sourceOrigins.sharedThirdParty,
-    sourceOrigins.nativeThirdParty,
-    sourceOrigins.extension,
-  ]),
-  'wasix-runtime': Object.freeze([
-    sourceOrigins.sharedThirdParty,
-    sourceOrigins.extension,
-  ]),
-  'wasix-postmaster-runtime': Object.freeze([
-    sourceOrigins.sharedThirdParty,
-    sourceOrigins.wasixPostmasterThirdParty,
-  ]),
-  extensions: Object.freeze([sourceOrigins.extension]),
-});
-
-export const sourceScopes = Object.freeze(Object.keys(SOURCE_ORIGINS_BY_SCOPE));
-
-const domainEntries = Object.freeze([
-  Object.freeze(['shared', sourceOrigins.sharedThirdParty]),
-  Object.freeze(['native', sourceOrigins.nativeThirdParty]),
-  Object.freeze(['wasix-postmaster', sourceOrigins.wasixPostmasterThirdParty]),
-]);
-
-export function sourceDomainsForScope(selectedScope) {
-  const origins = new Set(SOURCE_ORIGINS_BY_SCOPE[selectedScope] ?? []);
-  return domainEntries.filter(([, origin]) => origins.has(origin));
-}
-
-export function scopeIncludesWasix(selectedScope) {
-  return ['production-all', 'all', 'wasix-runtime', 'wasix-postmaster-runtime'].includes(selectedScope);
-}
-
-export function scopeIncludesExtensions(selectedScope) {
-  return scopeIncludes(selectedScope, sourceOrigins.extension);
-}
-
-export function scopeIncludes(selectedScope, origin) {
-  return (SOURCE_ORIGINS_BY_SCOPE[selectedScope] ?? []).includes(origin);
-}
diff --git a/src/sources/tools/source-fetch-scopes.test.mjs b/src/sources/tools/source-fetch-scopes.test.mjs
deleted file mode 100644
index 446f167cf..000000000
--- a/src/sources/tools/source-fetch-scopes.test.mjs
+++ /dev/null
@@ -1,110 +0,0 @@
-import assert from 'node:assert/strict';
-import {test} from 'node:test';
-
-import {
-  defaultSourceScope,
-  scopeIncludes,
-  scopeIncludesExtensions,
-  scopeIncludesWasix,
-  sourceDomainsForScope,
-  sourceOrigins,
-  sourceScopes,
-} from './source-fetch-scopes.mjs';
-
-const productionDomains = [
-  ['shared', sourceOrigins.sharedThirdParty],
-  ['native', sourceOrigins.nativeThirdParty],
-  ['wasix-postmaster', sourceOrigins.wasixPostmasterThirdParty],
-];
-
-test('production-all is the default release scope and includes every product pin', () => {
-  assert.equal(defaultSourceScope, 'production-all');
-  assert.equal(sourceScopes.includes(defaultSourceScope), true);
-  assert.deepEqual(sourceDomainsForScope('production-all'), productionDomains);
-  assert.equal(scopeIncludesWasix('production-all'), true);
-  assert.equal(scopeIncludesExtensions('production-all'), true);
-  assert.equal(scopeIncludes('production-all', sourceOrigins.sharedThirdParty), true);
-  assert.equal(scopeIncludes('production-all', sourceOrigins.nativeThirdParty), true);
-  assert.equal(scopeIncludes('production-all', sourceOrigins.extension), true);
-  assert.equal(
-    scopeIncludes('production-all', sourceOrigins.wasixPostmasterThirdParty),
-    true,
-  );
-});
-
-test('all honestly spans every repository source domain', () => {
-  assert.deepEqual(sourceDomainsForScope('all'), [
-    ['shared', sourceOrigins.sharedThirdParty],
-    ['native', sourceOrigins.nativeThirdParty],
-    ['wasix-postmaster', sourceOrigins.wasixPostmasterThirdParty],
-  ]);
-  assert.equal(scopeIncludesWasix('all'), true);
-  assert.equal(scopeIncludesExtensions('all'), true);
-  assert.equal(scopeIncludes('all', sourceOrigins.sharedThirdParty), true);
-  assert.equal(scopeIncludes('all', sourceOrigins.nativeThirdParty), true);
-  assert.equal(scopeIncludes('all', sourceOrigins.extension), true);
-  assert.equal(scopeIncludes('all', sourceOrigins.wasixPostmasterThirdParty), true);
-});
-
-test('postmaster scope includes only its runtime dependencies and private pins', () => {
-  assert.deepEqual(sourceDomainsForScope('wasix-postmaster-runtime'), [
-    ['shared', sourceOrigins.sharedThirdParty],
-    ['wasix-postmaster', sourceOrigins.wasixPostmasterThirdParty],
-  ]);
-  assert.equal(scopeIncludesWasix('wasix-postmaster-runtime'), true);
-  assert.equal(scopeIncludesExtensions('wasix-postmaster-runtime'), false);
-  assert.equal(
-    scopeIncludes('wasix-postmaster-runtime', sourceOrigins.sharedThirdParty),
-    true,
-  );
-  assert.equal(
-    scopeIncludes('wasix-postmaster-runtime', sourceOrigins.wasixPostmasterThirdParty),
-    true,
-  );
-  assert.equal(
-    scopeIncludes('wasix-postmaster-runtime', sourceOrigins.nativeThirdParty),
-    false,
-  );
-  assert.equal(scopeIncludes('wasix-postmaster-runtime', sourceOrigins.extension), false);
-});
-
-test('focused runtime scopes include the extension sources they package', () => {
-  assert.deepEqual(sourceDomainsForScope('native-runtime'), productionDomains.slice(0, 2));
-  assert.equal(scopeIncludesWasix('native-runtime'), false);
-  assert.equal(scopeIncludesExtensions('native-runtime'), true);
-  assert.equal(scopeIncludes('native-runtime', sourceOrigins.sharedThirdParty), true);
-  assert.equal(scopeIncludes('native-runtime', sourceOrigins.nativeThirdParty), true);
-  assert.equal(
-    scopeIncludes('native-runtime', sourceOrigins.wasixPostmasterThirdParty),
-    false,
-  );
-  assert.equal(scopeIncludes('native-runtime', sourceOrigins.extension), true);
-
-  assert.deepEqual(sourceDomainsForScope('wasix-runtime'), [
-    productionDomains[0],
-  ]);
-  assert.equal(scopeIncludesWasix('wasix-runtime'), true);
-  assert.equal(scopeIncludesExtensions('wasix-runtime'), true);
-  assert.equal(scopeIncludes('wasix-runtime', sourceOrigins.sharedThirdParty), true);
-  assert.equal(scopeIncludes('wasix-runtime', sourceOrigins.nativeThirdParty), false);
-  assert.equal(
-    scopeIncludes('wasix-runtime', sourceOrigins.wasixPostmasterThirdParty),
-    false,
-  );
-  assert.equal(scopeIncludes('wasix-runtime', sourceOrigins.extension), true);
-
-  assert.deepEqual(sourceDomainsForScope('extensions'), []);
-  assert.equal(scopeIncludesWasix('extensions'), false);
-  assert.equal(scopeIncludesExtensions('extensions'), true);
-  assert.equal(scopeIncludes('extensions', sourceOrigins.sharedThirdParty), false);
-  assert.equal(scopeIncludes('extensions', sourceOrigins.extension), true);
-});
-
-test('unknown scopes include no sources', () => {
-  assert.deepEqual(sourceDomainsForScope('unknown'), []);
-  assert.equal(scopeIncludesWasix('unknown'), false);
-  assert.equal(scopeIncludesExtensions('unknown'), false);
-  for (const origin of Object.values(sourceOrigins)) {
-    assert.equal(scopeIncludes('unknown', origin), false);
-  }
-});
diff --git a/src/sources/tools/source-zip.py b/src/sources/tools/source-zip.py
deleted file mode 100644
index 5b8188b04..000000000
--- a/src/sources/tools/source-zip.py
+++ /dev/null
@@ -1,260 +0,0 @@
-#!/usr/bin/env python3
-"""Validate and extract a pinned ZIP source archive safely.
-
-This is the ZIP counterpart to source-archive.py.  It intentionally accepts
-only the small portable subset needed by pinned upstream binary/data releases:
-real directories and regular files, with no links or platform-special entries.
-"""
-
-from __future__ import annotations
-
-import argparse
-import os
-import shutil
-import stat
-import sys
-import unicodedata
-import zipfile
-from dataclasses import dataclass
-from pathlib import Path, PurePosixPath
-
-
-MAX_MEMBERS = 200_000
-MAX_MEMBER_BYTES = 2 * 1024 * 1024 * 1024
-MAX_EXPANDED_BYTES = 4 * 1024 * 1024 * 1024
-MAX_EXPANSION_RATIO = 200
-MIN_EXPANSION_ALLOWANCE = 64 * 1024 * 1024
-COPY_CHUNK_BYTES = 1024 * 1024
-RESERVED_ROOT_ENTRIES = {".git", ".oliphaunt-source-pin"}
-WINDOWS_RESERVED_NAMES = {
-    "con",
-    "prn",
-    "aux",
-    "nul",
-    *(f"com{index}" for index in range(1, 10)),
-    *(f"lpt{index}" for index in range(1, 10)),
-}
-
-
-class UnsafeArchive(ValueError):
-    pass
-
-
-@dataclass(frozen=True)
-class CheckedMember:
-    info: zipfile.ZipInfo
-    relative: str
-    directory: bool
-
-
-def _reject_control_characters(value: str, label: str) -> None:
-    if any(ord(character) < 32 or ord(character) == 127 for character in value):
-        raise UnsafeArchive(f"{label} contains a control character")
-
-
-def _validate_member_name(name: str, label: str) -> tuple[str, ...]:
-    if not name:
-        raise UnsafeArchive(f"{label} is empty")
-    _reject_control_characters(name, label)
-    if "\\" in name:
-        raise UnsafeArchive(f"{label} contains a backslash")
-    if name.startswith("/") or (len(name) >= 2 and name[1] == ":"):
-        raise UnsafeArchive(f"{label} is absolute")
-
-    normalized = name[:-1] if name.endswith("/") else name
-    parts = tuple(normalized.split("/"))
-    if not normalized or any(part in {"", ".", ".."} for part in parts):
-        raise UnsafeArchive(f"{label} contains an empty, dot, or traversal component")
-    if len(normalized.encode("utf-8")) > 4096:
-        raise UnsafeArchive(f"{label} exceeds the portable path-length limit")
-    for part in parts:
-        if len(part.encode("utf-8")) > 255:
-            raise UnsafeArchive(f"{label} has an oversized path component")
-        if ":" in part or part.endswith((" ", ".")):
-            raise UnsafeArchive(f"{label} is not portable to Windows filesystems")
-        if part.split(".", 1)[0].casefold() in WINDOWS_RESERVED_NAMES:
-            raise UnsafeArchive(f"{label} uses a reserved Windows device name")
-    return parts
-
-
-def _member_relative_path(name: str, prefix: str) -> str:
-    parts = _validate_member_name(name, f"archive member {name!r}")
-    if prefix == ".":
-        return "/".join(parts)
-    if parts[0] != prefix:
-        raise UnsafeArchive(
-            f"archive member {name!r} is outside required root {prefix!r}"
-        )
-    return "/".join(parts[1:])
-
-
-def _member_kind(info: zipfile.ZipInfo) -> bool:
-    directory = info.is_dir()
-    unix_mode = info.external_attr >> 16
-    file_type = stat.S_IFMT(unix_mode)
-    if file_type not in {0, stat.S_IFREG, stat.S_IFDIR}:
-        raise UnsafeArchive(f"archive member {info.filename!r} has unsupported type")
-    if directory and file_type == stat.S_IFREG:
-        raise UnsafeArchive(f"archive directory {info.filename!r} has a regular-file mode")
-    if not directory and file_type == stat.S_IFDIR:
-        raise UnsafeArchive(f"archive file {info.filename!r} has a directory mode")
-    return directory
-
-
-def checked_members(archive: Path, prefix: str) -> list[CheckedMember]:
-    if prefix != ".":
-        prefix_parts = _validate_member_name(prefix, "strip prefix")
-        if len(prefix_parts) != 1:
-            raise UnsafeArchive("strip prefix must be one portable top-level directory name")
-    if not archive.is_file():
-        raise UnsafeArchive(f"archive does not exist: {archive}")
-
-    compressed_bytes = archive.stat().st_size
-    expanded_limit = min(
-        MAX_EXPANDED_BYTES,
-        max(MIN_EXPANSION_ALLOWANCE, compressed_bytes * MAX_EXPANSION_RATIO),
-    )
-    checked: list[CheckedMember] = []
-    by_path: dict[str, CheckedMember] = {}
-    portable_paths: dict[str, str] = {}
-    expanded_bytes = 0
-
-    try:
-        stream = zipfile.ZipFile(archive, mode="r")
-    except (OSError, zipfile.BadZipFile) as error:
-        raise UnsafeArchive(f"cannot open ZIP archive: {error}") from error
-
-    with stream:
-        for index, info in enumerate(stream.infolist(), start=1):
-            if index > MAX_MEMBERS:
-                raise UnsafeArchive(f"archive contains more than {MAX_MEMBERS} members")
-            if info.flag_bits & 0x1:
-                raise UnsafeArchive(f"archive member {info.filename!r} is encrypted")
-            if info.compress_type not in {zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED}:
-                raise UnsafeArchive(
-                    f"archive member {info.filename!r} uses unsupported compression"
-                )
-            relative = _member_relative_path(info.filename, prefix)
-            if relative == "":
-                continue
-            if relative.split("/", 1)[0] in RESERVED_ROOT_ENTRIES:
-                raise UnsafeArchive(
-                    f"archive member {info.filename!r} uses a reserved source-spine path"
-                )
-            if relative in by_path:
-                raise UnsafeArchive(f"archive contains duplicate path {info.filename!r}")
-            portable_key = unicodedata.normalize("NFC", relative).casefold()
-            if portable_key in portable_paths:
-                raise UnsafeArchive(
-                    f"archive paths {portable_paths[portable_key]!r} and {info.filename!r} collide on a portable filesystem"
-                )
-            portable_paths[portable_key] = info.filename
-            directory = _member_kind(info)
-            if not directory:
-                if info.file_size < 0 or info.file_size > MAX_MEMBER_BYTES:
-                    raise UnsafeArchive(
-                        f"archive member {info.filename!r} exceeds the per-file size limit"
-                    )
-                expanded_bytes += info.file_size
-                if expanded_bytes > expanded_limit:
-                    raise UnsafeArchive(
-                        "archive exceeds the bounded expanded-size allowance "
-                        f"({expanded_limit} bytes)"
-                    )
-            member = CheckedMember(info, relative, directory)
-            by_path[relative] = member
-            checked.append(member)
-
-    if not checked:
-        raise UnsafeArchive("archive is empty")
-    for member in checked:
-        parts = PurePosixPath(member.relative).parts
-        for depth in range(1, len(parts)):
-            ancestor = by_path.get("/".join(parts[:depth]))
-            if ancestor is not None and not ancestor.directory:
-                raise UnsafeArchive(
-                    f"archive path {member.info.filename!r} descends through a file"
-                )
-    return checked
-
-
-def _safe_parent(destination: Path, relative: str) -> Path:
-    parent = destination.joinpath(*PurePosixPath(relative).parts).parent
-    current = destination
-    for part in parent.relative_to(destination).parts:
-        current = current / part
-        if current.exists() or current.is_symlink():
-            mode = current.lstat().st_mode
-            if not stat.S_ISDIR(mode) or stat.S_ISLNK(mode):
-                raise UnsafeArchive(f"extraction ancestor is not a real directory: {current}")
-        else:
-            current.mkdir(mode=0o755)
-    return parent
-
-
-def extract_archive(archive: Path, destination: Path, prefix: str) -> None:
-    members = checked_members(archive, prefix)
-    if destination.exists() or destination.is_symlink():
-        raise UnsafeArchive(f"extraction destination already exists: {destination}")
-    destination.parent.mkdir(parents=True, exist_ok=True)
-    destination.mkdir(mode=0o755)
-    try:
-        with zipfile.ZipFile(archive, mode="r") as stream:
-            for member in members:
-                output = destination.joinpath(*PurePosixPath(member.relative).parts)
-                _safe_parent(destination, member.relative)
-                if member.directory:
-                    if output.exists() or output.is_symlink():
-                        if not output.is_dir() or output.is_symlink():
-                            raise UnsafeArchive(
-                                f"cannot create archive directory {member.relative!r}"
-                            )
-                    else:
-                        output.mkdir(mode=0o755)
-                    continue
-                flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
-                if hasattr(os, "O_NOFOLLOW"):
-                    flags |= os.O_NOFOLLOW
-                descriptor = os.open(output, flags, 0o600)
-                try:
-                    with os.fdopen(descriptor, "wb") as target:
-                        descriptor = -1
-                        with stream.open(member.info, mode="r") as source:
-                            shutil.copyfileobj(source, target, COPY_CHUNK_BYTES)
-                finally:
-                    if descriptor >= 0:
-                        os.close(descriptor)
-                if output.stat().st_size != member.info.file_size:
-                    raise UnsafeArchive(
-                        f"archive member {member.info.filename!r} extracted with the wrong size"
-                    )
-                output.chmod(0o644)
-    except Exception:
-        shutil.rmtree(destination, ignore_errors=True)
-        raise
-
-
-def main() -> int:
-    parser = argparse.ArgumentParser()
-    parser.add_argument("command", choices=("validate", "extract"))
-    parser.add_argument("archive", type=Path)
-    parser.add_argument("strip_prefix")
-    parser.add_argument("destination", type=Path, nargs="?")
-    args = parser.parse_args()
-    if args.command == "validate":
-        if args.destination is not None:
-            parser.error("validate does not accept a destination")
-        checked_members(args.archive, args.strip_prefix)
-    else:
-        if args.destination is None:
-            parser.error("extract requires a destination")
-        extract_archive(args.archive, args.destination, args.strip_prefix)
-    return 0
-
-
-if __name__ == "__main__":
-    try:
-        raise SystemExit(main())
-    except (OSError, UnsafeArchive, zipfile.BadZipFile) as error:
-        print(f"source-zip.py: {error}", file=sys.stderr)
-        raise SystemExit(1) from error
diff --git a/src/sources/tools/verify-source-tree.py b/src/sources/tools/verify-source-tree.py
deleted file mode 100755
index b8cdda40b..000000000
--- a/src/sources/tools/verify-source-tree.py
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/usr/bin/env python3
-"""Verify a managed archive source checkout offline."""
-
-from __future__ import annotations
-
-import argparse
-import hashlib
-import os
-import stat
-import sys
-import tomllib
-from pathlib import Path
-
-
-SAFETY_VERSION = "source-archive-v2"
-MARKER_NAME = ".oliphaunt-source-pin"
-MAX_MARKER_BYTES = 64 * 1024
-MAX_ENTRIES = 500_000
-MAX_BYTES = 8 * 1024 * 1024 * 1024
-
-
-class VerificationError(ValueError):
-    pass
-
-
-def parse_marker(path: Path) -> dict[str, str]:
-    metadata = path.lstat()
-    if not stat.S_ISREG(metadata.st_mode) or stat.S_ISLNK(metadata.st_mode):
-        raise VerificationError(f"source marker is not a regular file: {path}")
-    if metadata.st_size > MAX_MARKER_BYTES:
-        raise VerificationError(f"source marker is oversized: {path}")
-    fields: dict[str, str] = {}
-    for line in path.read_text(encoding="utf-8").splitlines():
-        if not line:
-            continue
-        key, separator, value = line.partition("=")
-        if not separator or not key or key in fields:
-            raise VerificationError(f"source marker contains a malformed or duplicate field: {path}")
-        fields[key] = value
-    required = {
-        "safety",
-        "name",
-        "kind",
-        "url",
-        "branch",
-        "commit",
-        "sha256",
-        "strip-prefix",
-        "tree-sha256",
-    }
-    if set(fields) != required:
-        raise VerificationError(f"source marker does not carry complete integrity state: {path}")
-    if fields["safety"] != SAFETY_VERSION:
-        raise VerificationError(
-            f"source marker uses {fields['safety']!r}, expected {SAFETY_VERSION!r}"
-        )
-    if len(fields["tree-sha256"]) != 64 or any(
-        character not in "0123456789abcdef" for character in fields["tree-sha256"]
-    ):
-        raise VerificationError("source marker has an invalid tree-sha256")
-    return fields
-
-
-def file_sha256(path: Path) -> str:
-    digest = hashlib.sha256()
-    with path.open("rb") as source:
-        while block := source.read(1024 * 1024):
-            digest.update(block)
-    return digest.hexdigest()
-
-
-def source_tree_digest(root: Path) -> str:
-    root_metadata = root.lstat()
-    if not stat.S_ISDIR(root_metadata.st_mode) or stat.S_ISLNK(root_metadata.st_mode):
-        raise VerificationError(f"source checkout is not a real directory: {root}")
-
-    entries: list[tuple[bytes, str, str]] = []
-    pending = [root]
-    total_bytes = 0
-    while pending:
-        directory = pending.pop()
-        with os.scandir(directory) as scan:
-            children = sorted(scan, key=lambda entry: os.fsencode(entry.name))
-        for child in children:
-            path = Path(child.path)
-            relative = path.relative_to(root).as_posix()
-            if relative == MARKER_NAME:
-                continue
-            metadata = path.lstat()
-            if stat.S_ISDIR(metadata.st_mode):
-                kind = "directory"
-                detail = ""
-                pending.append(path)
-            elif stat.S_ISREG(metadata.st_mode):
-                kind = "file"
-                total_bytes += metadata.st_size
-                if total_bytes > MAX_BYTES:
-                    raise VerificationError(f"source checkout exceeds {MAX_BYTES} bytes")
-                detail = f"{metadata.st_size}:{file_sha256(path)}"
-            elif stat.S_ISLNK(metadata.st_mode):
-                kind = "symlink"
-                detail = os.readlink(path)
-            else:
-                raise VerificationError(f"unsupported filesystem object in source checkout: {path}")
-            entries.append((relative.encode("utf-8"), kind, detail))
-            if len(entries) > MAX_ENTRIES:
-                raise VerificationError(f"source checkout exceeds {MAX_ENTRIES} entries")
-
-    digest = hashlib.sha256()
-    for relative, kind, detail in sorted(entries, key=lambda entry: entry[0]):
-        for field in (kind.encode("utf-8"), relative, detail.encode("utf-8")):
-            digest.update(field)
-            digest.update(b"\0")
-    return digest.hexdigest()
-
-
-def expected_fields(manifest_path: Path) -> dict[str, str]:
-    with manifest_path.open("rb") as source:
-        manifest = tomllib.load(source)
-    required = ("name", "url", "branch", "commit", "sha256", "strip_prefix")
-    for field in required:
-        if not isinstance(manifest.get(field), str) or not manifest[field]:
-            raise VerificationError(f"source manifest {manifest_path} has invalid {field}")
-    if manifest.get("kind") != "archive":
-        raise VerificationError(f"source manifest {manifest_path} is not an archive source")
-    return {
-        "name": manifest["name"],
-        "kind": "archive",
-        "url": manifest["url"],
-        "branch": manifest["branch"],
-        "commit": manifest["commit"],
-        "sha256": manifest["sha256"],
-        "strip-prefix": manifest["strip_prefix"],
-    }
-
-
-def verify(checkout: Path, manifest_path: Path) -> str:
-    marker = parse_marker(checkout / MARKER_NAME)
-    expected = expected_fields(manifest_path)
-    for key, value in expected.items():
-        if marker[key] != value:
-            raise VerificationError(
-                f"source checkout marker {key} is {marker[key]!r}, expected {value!r}"
-            )
-    actual = source_tree_digest(checkout)
-    if actual != marker["tree-sha256"]:
-        raise VerificationError(
-            f"source checkout was modified: expected tree {marker['tree-sha256']}, got {actual}"
-        )
-    return actual
-
-
-def main() -> int:
-    parser = argparse.ArgumentParser()
-    parser.add_argument("--checkout", required=True, type=Path)
-    parser.add_argument("--manifest", required=True, type=Path)
-    args = parser.parse_args()
-    try:
-        print(verify(args.checkout, args.manifest))
-    except (OSError, UnicodeError, VerificationError, tomllib.TOMLDecodeError) as error:
-        print(f"source checkout verification failed: {error}", file=sys.stderr)
-        return 1
-    return 0
-
-
-if __name__ == "__main__":
-    raise SystemExit(main())
diff --git a/src/shared/fixtures/extensions/amcheck.sql b/src/test-fixtures/extensions/amcheck.sql
similarity index 100%
rename from src/shared/fixtures/extensions/amcheck.sql
rename to src/test-fixtures/extensions/amcheck.sql
diff --git a/src/shared/fixtures/extensions/auto_explain.sql b/src/test-fixtures/extensions/auto_explain.sql
similarity index 100%
rename from src/shared/fixtures/extensions/auto_explain.sql
rename to src/test-fixtures/extensions/auto_explain.sql
diff --git a/src/shared/fixtures/extensions/bloom.sql b/src/test-fixtures/extensions/bloom.sql
similarity index 100%
rename from src/shared/fixtures/extensions/bloom.sql
rename to src/test-fixtures/extensions/bloom.sql
diff --git a/src/shared/fixtures/extensions/btree_gin.sql b/src/test-fixtures/extensions/btree_gin.sql
similarity index 100%
rename from src/shared/fixtures/extensions/btree_gin.sql
rename to src/test-fixtures/extensions/btree_gin.sql
diff --git a/src/shared/fixtures/extensions/btree_gist.sql b/src/test-fixtures/extensions/btree_gist.sql
similarity index 100%
rename from src/shared/fixtures/extensions/btree_gist.sql
rename to src/test-fixtures/extensions/btree_gist.sql
diff --git a/src/shared/fixtures/extensions/citext.sql b/src/test-fixtures/extensions/citext.sql
similarity index 100%
rename from src/shared/fixtures/extensions/citext.sql
rename to src/test-fixtures/extensions/citext.sql
diff --git a/src/shared/fixtures/extensions/cube.sql b/src/test-fixtures/extensions/cube.sql
similarity index 100%
rename from src/shared/fixtures/extensions/cube.sql
rename to src/test-fixtures/extensions/cube.sql
diff --git a/src/shared/fixtures/extensions/dict_int.sql b/src/test-fixtures/extensions/dict_int.sql
similarity index 100%
rename from src/shared/fixtures/extensions/dict_int.sql
rename to src/test-fixtures/extensions/dict_int.sql
diff --git a/src/shared/fixtures/extensions/dict_xsyn.sql b/src/test-fixtures/extensions/dict_xsyn.sql
similarity index 100%
rename from src/shared/fixtures/extensions/dict_xsyn.sql
rename to src/test-fixtures/extensions/dict_xsyn.sql
diff --git a/src/shared/fixtures/extensions/earthdistance.sql b/src/test-fixtures/extensions/earthdistance.sql
similarity index 100%
rename from src/shared/fixtures/extensions/earthdistance.sql
rename to src/test-fixtures/extensions/earthdistance.sql
diff --git a/src/test-fixtures/extensions/file_fdw.sql b/src/test-fixtures/extensions/file_fdw.sql
new file mode 100644
index 000000000..6b7e81d30
--- /dev/null
+++ b/src/test-fixtures/extensions/file_fdw.sql
@@ -0,0 +1,6 @@
+DROP SERVER IF EXISTS oliphaunt_file_server;
+-- oliphaunt-statement
+CREATE SERVER oliphaunt_file_server FOREIGN DATA WRAPPER file_fdw;
+-- oliphaunt-statement
+-- oliphaunt-verify
+DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname = 'oliphaunt_file_server') THEN RAISE EXCEPTION 'file_fdw server missing'; END IF; END $$;
diff --git a/src/shared/fixtures/extensions/fuzzystrmatch.sql b/src/test-fixtures/extensions/fuzzystrmatch.sql
similarity index 100%
rename from src/shared/fixtures/extensions/fuzzystrmatch.sql
rename to src/test-fixtures/extensions/fuzzystrmatch.sql
diff --git a/src/shared/fixtures/extensions/hstore.sql b/src/test-fixtures/extensions/hstore.sql
similarity index 100%
rename from src/shared/fixtures/extensions/hstore.sql
rename to src/test-fixtures/extensions/hstore.sql
diff --git a/src/shared/fixtures/extensions/intarray.sql b/src/test-fixtures/extensions/intarray.sql
similarity index 100%
rename from src/shared/fixtures/extensions/intarray.sql
rename to src/test-fixtures/extensions/intarray.sql
diff --git a/src/shared/fixtures/extensions/isn.sql b/src/test-fixtures/extensions/isn.sql
similarity index 100%
rename from src/shared/fixtures/extensions/isn.sql
rename to src/test-fixtures/extensions/isn.sql
diff --git a/src/shared/fixtures/extensions/lo.sql b/src/test-fixtures/extensions/lo.sql
similarity index 100%
rename from src/shared/fixtures/extensions/lo.sql
rename to src/test-fixtures/extensions/lo.sql
diff --git a/src/shared/fixtures/extensions/ltree.sql b/src/test-fixtures/extensions/ltree.sql
similarity index 100%
rename from src/shared/fixtures/extensions/ltree.sql
rename to src/test-fixtures/extensions/ltree.sql
diff --git a/src/shared/fixtures/extensions/manifest.json b/src/test-fixtures/extensions/manifest.json
similarity index 100%
rename from src/shared/fixtures/extensions/manifest.json
rename to src/test-fixtures/extensions/manifest.json
diff --git a/src/shared/fixtures/extensions/pageinspect.sql b/src/test-fixtures/extensions/pageinspect.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pageinspect.sql
rename to src/test-fixtures/extensions/pageinspect.sql
diff --git a/src/shared/fixtures/extensions/pg_buffercache.sql b/src/test-fixtures/extensions/pg_buffercache.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pg_buffercache.sql
rename to src/test-fixtures/extensions/pg_buffercache.sql
diff --git a/src/shared/fixtures/extensions/pg_freespacemap.sql b/src/test-fixtures/extensions/pg_freespacemap.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pg_freespacemap.sql
rename to src/test-fixtures/extensions/pg_freespacemap.sql
diff --git a/src/shared/fixtures/extensions/pg_hashids.sql b/src/test-fixtures/extensions/pg_hashids.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pg_hashids.sql
rename to src/test-fixtures/extensions/pg_hashids.sql
diff --git a/src/test-fixtures/extensions/pg_ivm.sql b/src/test-fixtures/extensions/pg_ivm.sql
new file mode 100644
index 000000000..6fa633545
--- /dev/null
+++ b/src/test-fixtures/extensions/pg_ivm.sql
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS oliphaunt_ivm_summary;
+-- oliphaunt-statement
+DROP TABLE IF EXISTS oliphaunt_ivm_orders;
+-- oliphaunt-statement
+CREATE TABLE oliphaunt_ivm_orders (id int, amount int);
+-- oliphaunt-statement
+INSERT INTO oliphaunt_ivm_orders VALUES (1, 10), (2, 20);
+-- oliphaunt-statement
+SELECT pgivm.create_immv('oliphaunt_ivm_summary', $$ SELECT id, amount FROM oliphaunt_ivm_orders $$);
+-- oliphaunt-statement
+-- oliphaunt-verify
+DO $$
+DECLARE n int;
+BEGIN
+  SELECT count(*) INTO n FROM oliphaunt_ivm_summary;
+  IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF;
+  UPDATE oliphaunt_ivm_orders SET amount = 11 WHERE id = 1;
+  SELECT amount INTO n FROM oliphaunt_ivm_summary WHERE id = 1;
+  IF n IS DISTINCT FROM 11 THEN RAISE EXCEPTION 'pg_ivm maintenance failed: %', n; END IF;
+  UPDATE oliphaunt_ivm_orders SET amount = 10 WHERE id = 1;
+END $$;
diff --git a/src/shared/fixtures/extensions/pg_surgery.sql b/src/test-fixtures/extensions/pg_surgery.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pg_surgery.sql
rename to src/test-fixtures/extensions/pg_surgery.sql
diff --git a/src/shared/fixtures/extensions/pg_textsearch.sql b/src/test-fixtures/extensions/pg_textsearch.sql
similarity index 98%
rename from src/shared/fixtures/extensions/pg_textsearch.sql
rename to src/test-fixtures/extensions/pg_textsearch.sql
index 9ca1ebd5f..ee1bbd30c 100644
--- a/src/shared/fixtures/extensions/pg_textsearch.sql
+++ b/src/test-fixtures/extensions/pg_textsearch.sql
@@ -17,6 +17,7 @@ CREATE INDEX oliphaunt_pg_textsearch_english_bm25
   USING bm25 (body)
   WITH (text_config = 'pg_catalog.english');
 -- oliphaunt-statement
+-- oliphaunt-verify
 DO $oliphaunt$
 DECLARE
   hit bigint;
diff --git a/src/shared/fixtures/extensions/pg_trgm.sql b/src/test-fixtures/extensions/pg_trgm.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pg_trgm.sql
rename to src/test-fixtures/extensions/pg_trgm.sql
diff --git a/src/shared/fixtures/extensions/pg_uuidv7.sql b/src/test-fixtures/extensions/pg_uuidv7.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pg_uuidv7.sql
rename to src/test-fixtures/extensions/pg_uuidv7.sql
diff --git a/src/shared/fixtures/extensions/pg_visibility.sql b/src/test-fixtures/extensions/pg_visibility.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pg_visibility.sql
rename to src/test-fixtures/extensions/pg_visibility.sql
diff --git a/src/shared/fixtures/extensions/pg_walinspect.sql b/src/test-fixtures/extensions/pg_walinspect.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pg_walinspect.sql
rename to src/test-fixtures/extensions/pg_walinspect.sql
diff --git a/src/shared/fixtures/extensions/pgcrypto.sql b/src/test-fixtures/extensions/pgcrypto.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pgcrypto.sql
rename to src/test-fixtures/extensions/pgcrypto.sql
diff --git a/src/shared/fixtures/extensions/pgtap.sql b/src/test-fixtures/extensions/pgtap.sql
similarity index 100%
rename from src/shared/fixtures/extensions/pgtap.sql
rename to src/test-fixtures/extensions/pgtap.sql
diff --git a/src/shared/fixtures/extensions/postgis.sql b/src/test-fixtures/extensions/postgis.sql
similarity index 95%
rename from src/shared/fixtures/extensions/postgis.sql
rename to src/test-fixtures/extensions/postgis.sql
index 632f9aec1..dc5dafeac 100644
--- a/src/shared/fixtures/extensions/postgis.sql
+++ b/src/test-fixtures/extensions/postgis.sql
@@ -1,6 +1,6 @@
 DROP TABLE IF EXISTS oliphaunt_postgis_points;
 -- oliphaunt-statement
-CREATE TEMP TABLE oliphaunt_postgis_points(id int PRIMARY KEY, geom geometry(Point, 4326));
+CREATE TABLE oliphaunt_postgis_points(id int PRIMARY KEY, geom geometry(Point, 4326));
 -- oliphaunt-statement
 INSERT INTO oliphaunt_postgis_points VALUES
   (1, ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)),
@@ -8,6 +8,7 @@ INSERT INTO oliphaunt_postgis_points VALUES
 -- oliphaunt-statement
 CREATE INDEX oliphaunt_postgis_points_gix ON oliphaunt_postgis_points USING GIST (geom);
 -- oliphaunt-statement
+-- oliphaunt-verify
 DO $$
 DECLARE
   distance float8;
diff --git a/src/shared/fixtures/extensions/seg.sql b/src/test-fixtures/extensions/seg.sql
similarity index 100%
rename from src/shared/fixtures/extensions/seg.sql
rename to src/test-fixtures/extensions/seg.sql
diff --git a/src/shared/fixtures/extensions/tablefunc.sql b/src/test-fixtures/extensions/tablefunc.sql
similarity index 100%
rename from src/shared/fixtures/extensions/tablefunc.sql
rename to src/test-fixtures/extensions/tablefunc.sql
diff --git a/src/shared/fixtures/extensions/tcn.sql b/src/test-fixtures/extensions/tcn.sql
similarity index 100%
rename from src/shared/fixtures/extensions/tcn.sql
rename to src/test-fixtures/extensions/tcn.sql
diff --git a/src/shared/fixtures/extensions/tsm_system_rows.sql b/src/test-fixtures/extensions/tsm_system_rows.sql
similarity index 100%
rename from src/shared/fixtures/extensions/tsm_system_rows.sql
rename to src/test-fixtures/extensions/tsm_system_rows.sql
diff --git a/src/shared/fixtures/extensions/tsm_system_time.sql b/src/test-fixtures/extensions/tsm_system_time.sql
similarity index 100%
rename from src/shared/fixtures/extensions/tsm_system_time.sql
rename to src/test-fixtures/extensions/tsm_system_time.sql
diff --git a/src/shared/fixtures/extensions/unaccent.sql b/src/test-fixtures/extensions/unaccent.sql
similarity index 100%
rename from src/shared/fixtures/extensions/unaccent.sql
rename to src/test-fixtures/extensions/unaccent.sql
diff --git a/src/shared/fixtures/extensions/uuid-ossp.sql b/src/test-fixtures/extensions/uuid-ossp.sql
similarity index 100%
rename from src/shared/fixtures/extensions/uuid-ossp.sql
rename to src/test-fixtures/extensions/uuid-ossp.sql
diff --git a/src/test-fixtures/extensions/vector.sql b/src/test-fixtures/extensions/vector.sql
new file mode 100644
index 000000000..8e6f86da0
--- /dev/null
+++ b/src/test-fixtures/extensions/vector.sql
@@ -0,0 +1,8 @@
+DROP TABLE IF EXISTS oliphaunt_vector;
+-- oliphaunt-statement
+CREATE TABLE oliphaunt_vector (id int PRIMARY KEY, embedding vector(3));
+-- oliphaunt-statement
+INSERT INTO oliphaunt_vector VALUES (1, '[1,2,3]');
+-- oliphaunt-statement
+-- oliphaunt-verify
+DO $$ DECLARE d float8; BEGIN SELECT embedding <-> '[1,2,4]'::vector INTO d FROM oliphaunt_vector WHERE id = 1; IF d IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'vector distance failed: %', d; END IF; END $$;
diff --git a/src/shared/fixtures/moon.yml b/src/test-fixtures/moon.yml
similarity index 100%
rename from src/shared/fixtures/moon.yml
rename to src/test-fixtures/moon.yml
diff --git a/src/shared/fixtures/postgres/behavior-contract.json b/src/test-fixtures/postgres/behavior-contract.json
similarity index 97%
rename from src/shared/fixtures/postgres/behavior-contract.json
rename to src/test-fixtures/postgres/behavior-contract.json
index 49a6078f8..a8a42f8d6 100644
--- a/src/shared/fixtures/postgres/behavior-contract.json
+++ b/src/test-fixtures/postgres/behavior-contract.json
@@ -25,7 +25,5 @@
     "column": "contract",
     "expected": "oliphaunt-postgres-contract-v1"
   },
-  "cleanupStatements": [
-    "DROP SCHEMA oliphaunt_contract CASCADE"
-  ]
+  "cleanupStatements": ["DROP SCHEMA oliphaunt_contract CASCADE"]
 }
diff --git a/src/shared/fixtures/postgres/logical-tools-seed.sql b/src/test-fixtures/postgres/logical-tools-seed.sql
similarity index 100%
rename from src/shared/fixtures/postgres/logical-tools-seed.sql
rename to src/test-fixtures/postgres/logical-tools-seed.sql
diff --git a/src/shared/fixtures/postgres/logical-tools-verify.sql b/src/test-fixtures/postgres/logical-tools-verify.sql
similarity index 100%
rename from src/shared/fixtures/postgres/logical-tools-verify.sql
rename to src/test-fixtures/postgres/logical-tools-verify.sql
diff --git a/src/shared/fixtures/postgres/logical-tools.json b/src/test-fixtures/postgres/logical-tools.json
similarity index 95%
rename from src/shared/fixtures/postgres/logical-tools.json
rename to src/test-fixtures/postgres/logical-tools.json
index 5eb733a6a..105aacc2e 100644
--- a/src/shared/fixtures/postgres/logical-tools.json
+++ b/src/test-fixtures/postgres/logical-tools.json
@@ -58,12 +58,7 @@
     ]
   },
   "psql": {
-    "acceptedArgs": [
-      "--echo-errors",
-      "--no-psqlrc",
-      "--set=ON_ERROR_STOP=1",
-      "-vAPP_MODE=test"
-    ],
+    "acceptedArgs": ["--echo-errors", "--no-psqlrc", "--set=ON_ERROR_STOP=1", "-vAPP_MODE=test"],
     "acceptedArgv": [
       ["--set", "APP_MODE=test"],
       ["-Av", "APP_MODE=test"],
diff --git a/src/shared/fixtures/postgres/server-listen.json b/src/test-fixtures/postgres/server-listen.json
similarity index 100%
rename from src/shared/fixtures/postgres/server-listen.json
rename to src/test-fixtures/postgres/server-listen.json
diff --git a/src/shared/fixtures/protocol/query-response-cases.json b/src/test-fixtures/protocol/query-response-cases.json
similarity index 91%
rename from src/shared/fixtures/protocol/query-response-cases.json
rename to src/test-fixtures/protocol/query-response-cases.json
index 1dd10e696..dfbb63c93 100644
--- a/src/shared/fixtures/protocol/query-response-cases.json
+++ b/src/test-fixtures/protocol/query-response-cases.json
@@ -27,23 +27,13 @@
               "format": "text"
             }
           ],
-          "rows": [
-            [
-              "1",
-              null
-            ]
-          ],
+          "rows": [["1", null]],
           "commandTag": "SELECT 1",
           "rowCount": 1
         }
       },
       "wireExpectation": {
-        "messageNames": [
-          "rowDescription",
-          "dataRow",
-          "commandComplete",
-          "readyForQuery"
-        ]
+        "messageNames": ["rowDescription", "dataRow", "commandComplete", "readyForQuery"]
       }
     },
     {
@@ -101,10 +91,7 @@
         }
       },
       "wireExpectation": {
-        "messageNames": [
-          "emptyQueryResponse",
-          "readyForQuery"
-        ]
+        "messageNames": ["emptyQueryResponse", "readyForQuery"]
       }
     },
     {
@@ -133,11 +120,7 @@
         }
       },
       "wireExpectation": {
-        "messageNames": [
-          "notice",
-          "commandComplete",
-          "readyForQuery"
-        ]
+        "messageNames": ["notice", "commandComplete", "readyForQuery"]
       }
     },
     {
@@ -189,10 +172,7 @@
         }
       },
       "wireExpectation": {
-        "messageNames": [
-          "error",
-          "readyForQuery"
-        ]
+        "messageNames": ["error", "readyForQuery"]
       }
     },
     {
@@ -214,10 +194,7 @@
         }
       },
       "wireExpectation": {
-        "messageNames": [
-          "error",
-          "readyForQuery"
-        ]
+        "messageNames": ["error", "readyForQuery"]
       }
     },
     {
@@ -236,9 +213,7 @@
         "engineErrorContains": "does not support COPY protocol responses"
       },
       "wireExpectation": {
-        "messageNames": [
-          "copyInResponse"
-        ]
+        "messageNames": ["copyInResponse"]
       }
     },
     {
diff --git a/src/shared/fixtures/protocol/structured-sql-cases.json b/src/test-fixtures/protocol/structured-sql-cases.json
similarity index 100%
rename from src/shared/fixtures/protocol/structured-sql-cases.json
rename to src/test-fixtures/protocol/structured-sql-cases.json
diff --git a/src/shared/fixtures/storage/database-root.json b/src/test-fixtures/storage/database-root.json
similarity index 100%
rename from src/shared/fixtures/storage/database-root.json
rename to src/test-fixtures/storage/database-root.json
diff --git a/src/shared/fixtures/storage/physical-archive-wasix-v1.properties b/src/test-fixtures/storage/physical-archive-wasix-v1.properties
similarity index 100%
rename from src/shared/fixtures/storage/physical-archive-wasix-v1.properties
rename to src/test-fixtures/storage/physical-archive-wasix-v1.properties
diff --git a/src/shared/fixtures/storage/physical-backup-wal-range-v1.properties b/src/test-fixtures/storage/physical-backup-wal-range-v1.properties
similarity index 100%
rename from src/shared/fixtures/storage/physical-backup-wal-range-v1.properties
rename to src/test-fixtures/storage/physical-backup-wal-range-v1.properties
diff --git a/src/runtimes/liboliphaunt/licenses/icu-76.1-LICENSE b/src/third-party/icu/LICENSE
similarity index 100%
rename from src/runtimes/liboliphaunt/licenses/icu-76.1-LICENSE
rename to src/third-party/icu/LICENSE
diff --git a/src/third-party/icu/moon.yml b/src/third-party/icu/moon.yml
new file mode 100644
index 000000000..b1d9324bf
--- /dev/null
+++ b/src/third-party/icu/moon.yml
@@ -0,0 +1,22 @@
+id: third-party-icu
+language: unknown
+layer: configuration
+tags:
+  - third-party
+  - sources
+fileGroups:
+  sources:
+    - source.toml
+    - tools/build.sh
+    - /src/database-resources/icu/tools/data.sh
+  legal:
+    - LICENSE*
+tasks:
+  test:
+    command: bash src/third-party/icu/tools/build.test.sh
+    tags: [quality, unit]
+    inputs:
+      - "@group(sources)"
+      - tools/build.test.sh
+    options:
+      runFromWorkspaceRoot: true
diff --git a/src/sources/third-party/shared/icu.toml b/src/third-party/icu/source.toml
similarity index 100%
rename from src/sources/third-party/shared/icu.toml
rename to src/third-party/icu/source.toml
diff --git a/src/third-party/icu/tools/build.sh b/src/third-party/icu/tools/build.sh
new file mode 100755
index 000000000..0bbeba189
--- /dev/null
+++ b/src/third-party/icu/tools/build.sh
@@ -0,0 +1,330 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+source "$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)/src/database-resources/icu/tools/data.sh"
+
+oliphaunt_icu_source_dir() {
+  local repo_root="${1:?repo root is required}"
+  printf '%s\n' "${OLIPHAUNT_ICU_SOURCE_DIR:-$repo_root/target/oliphaunt-sources/checkouts/icu/icu4c/source}"
+}
+
+oliphaunt_icu_source_commit() {
+  local source_dir="${1:?ICU source dir is required}"
+  git -C "$source_dir/../../" rev-parse HEAD
+}
+
+oliphaunt_icu_script_sha256() {
+  cat "${BASH_SOURCE[0]}" "$(dirname "${BASH_SOURCE[0]}")/../../../database-resources/icu/tools/data.sh" | oliphaunt_icu_sha256
+}
+
+oliphaunt_icu_native_tools_stamp() {
+  local source_dir="$1"
+  {
+    printf 'schema=oliphaunt-icu-native-tools-v4\n'
+    printf 'source=%s\n' "$(oliphaunt_icu_source_commit "$source_dir")"
+    printf 'script=%s\n' "$(oliphaunt_icu_script_sha256)"
+    printf 'configure=static-no-tests-no-samples-no-extras-no-icuio-no-layoutex-tools-only\n'
+  } | oliphaunt_icu_sha256
+}
+
+oliphaunt_icu_target_stamp() {
+  local source_dir="$1"
+  local target_label="$2"
+  local host="$3"
+  local cc="$4"
+  local cxx="$5"
+  local ar="$6"
+  local ranlib="$7"
+  local cflags="$8"
+  local cxxflags="${9}"
+  local ldflags="${10}"
+  {
+    printf 'schema=oliphaunt-icu-target-v8\n'
+    printf 'source=%s\n' "$(oliphaunt_icu_source_commit "$source_dir")"
+    printf 'script=%s\n' "$(oliphaunt_icu_script_sha256)"
+    printf 'target=%s\n' "$target_label"
+    printf 'host=%s\n' "$host"
+    printf 'cc=%s\n' "$cc"
+    printf 'cxx=%s\n' "$cxx"
+    printf 'ar=%s\n' "$ar"
+    printf 'ranlib=%s\n' "$ranlib"
+    printf 'cflags=%s\n' "$cflags"
+    printf 'cxxflags=%s\n' "$cxxflags"
+    printf 'ldflags=%s\n' "$ldflags"
+    printf 'canonical-data-sha256=%s\n' "$(oliphaunt_icu_canonical_data_sha256)"
+    printf 'configure=files-data-static-libs-static-consumer-no-extra-target-tools-stub-data-archive-pinned-upstream-data\n'
+  } | oliphaunt_icu_sha256
+}
+
+oliphaunt_icu_require_source() {
+  local source_dir="${1:?ICU source dir is required}"
+  if [ ! -x "$source_dir/configure" ]; then
+    echo "missing ICU source checkout at $source_dir; run \`bash src/third-party/tools/fetch-sources.sh native-runtime --force\` first" >&2
+    return 1
+  fi
+}
+
+oliphaunt_icu_native_tool_names() {
+  printf '%s\n' \
+    makeconv \
+    gencnval \
+    gencfu \
+    genbrk \
+    gendict \
+    genrb \
+    gensprep \
+    icupkg \
+    pkgdata \
+    genccode \
+    gencmn
+}
+
+oliphaunt_icu_native_tools_ready() {
+  local native_build_dir="${1:?native build dir is required}"
+  [ -f "$native_build_dir/icudefs.mk" ] || return 1
+  [ -f "$native_build_dir/config/icucross.mk" ] || return 1
+  [ -f "$native_build_dir/config/icucross.inc" ] || return 1
+  [ -f "$native_build_dir/lib/libicui18n.a" ] || return 1
+  [ -f "$native_build_dir/lib/libicuuc.a" ] || return 1
+  [ -f "$native_build_dir/stubdata/libicudata.a" ] || return 1
+  [ -f "$native_build_dir/lib/libicutu.a" ] || return 1
+  local tool
+  while IFS= read -r tool; do
+    [ -x "$native_build_dir/bin/$tool" ] || return 1
+  done < <(oliphaunt_icu_native_tool_names)
+}
+
+oliphaunt_icu_stub_data_archive_ready() {
+  local archive="${1:?ICU data archive is required}"
+  [ -f "$archive" ] || return 1
+  local members
+  members="$(ar -t "$archive")" || return 1
+  grep -Eq '^stubdata\.ao/?$' <<< "$members" || return 1
+  ! grep -Eq '^icudt[0-9]+[a-z]*_dat\.o/?$' <<< "$members"
+}
+
+oliphaunt_icu_artifacts_ready() {
+  local prefix="${1:?ICU prefix is required}"
+  [ -f "$prefix/.oliphaunt-icu-build" ] || return 1
+  [ -f "$prefix/include/unicode/ucol.h" ] || return 1
+  [ -f "$prefix/lib/libicui18n.a" ] || return 1
+  [ -f "$prefix/lib/libicuuc.a" ] || return 1
+  oliphaunt_icu_stub_data_archive_ready "$prefix/lib/libicudata.a" || return 1
+  oliphaunt_icu_files_data_ready "$prefix/share/icu"
+}
+
+oliphaunt_icu_linked_symbols_ready() {
+  local symbols="${1-}"
+  local data_symbol_re
+  data_symbol_re='(^|[[:space:]])_?icudt[0-9]+[a-z]*_dat($|[[:space:]])'
+  [ -n "$symbols" ] || return 1
+  grep -Eq '(^|[[:space:]])_?ucol_open(_[0-9]+)?($|[[:space:]])' <<< "$symbols" || return 1
+  ! grep -Eq '(^|[[:space:]])_?pg_register_static_icu_data($|[[:space:]])' <<< "$symbols" || return 1
+
+  local line address size_or_type type_or_symbol symbol_name
+  while IFS= read -r line; do
+    [[ "$line" =~ $data_symbol_re ]] || continue
+    read -r address size_or_type type_or_symbol symbol_name _ <<< "$line"
+    if [[ "$size_or_type" =~ ^[[:xdigit:]]+$ ]] && [[ "$type_or_symbol" =~ ^[A-Za-z]$ ]]; then
+      [ "$((16#$size_or_type))" -le 4096 ] || return 1
+    fi
+  done <<< "$symbols"
+}
+
+oliphaunt_icu_install_stub_data_archive() {
+  local target_build_dir="${1:?target ICU build dir is required}"
+  local prefix="${2:?ICU prefix is required}"
+  local built_archive="$target_build_dir/stubdata/libicudata.a"
+  local installed_archive="$prefix/lib/libicudata.a"
+  local tmp_archive="$installed_archive.tmp"
+
+  oliphaunt_icu_stub_data_archive_ready "$built_archive"
+  mkdir -p "$prefix/lib"
+  rm -f "$tmp_archive"
+  cp "$built_archive" "$tmp_archive"
+  chmod 0644 "$tmp_archive"
+  mv "$tmp_archive" "$installed_archive"
+}
+
+oliphaunt_icu_prepare_files_data_install_dirs() {
+  local target_build_dir="${1:?target ICU build dir is required}"
+  local prefix="${2:?ICU prefix is required}"
+  local build_data_root="$target_build_dir/data/out/build"
+  [ -d "$build_data_root" ] || return 0
+
+  local version
+  version="$(
+    awk -F' = ' '$1 == "VERSION" { print $2; exit }' "$target_build_dir/config/Makefile.inc"
+  )"
+  [ -n "$version" ] || {
+    echo "unable to determine ICU version from $target_build_dir/config/Makefile.inc" >&2
+    return 1
+  }
+
+  local install_data_root="$prefix/share/icu/$version"
+  mkdir -p "$install_data_root"
+  while IFS= read -r dir; do
+    local relative="${dir#"$build_data_root"/}"
+    [ "$relative" != "$dir" ] || continue
+    mkdir -p "$install_data_root/$relative"
+  done < <(find "$build_data_root" -type d -print)
+}
+
+oliphaunt_icu_build_native_tools() (
+  set -e
+  local source_dir="${1:?ICU source dir is required}"
+  local native_build_dir="${2:?native build dir is required}"
+  local jobs="${3:?jobs is required}"
+
+  oliphaunt_icu_require_source "$source_dir"
+
+  local stamp_file="$native_build_dir/.oliphaunt-icu-native-tools"
+  local stamp
+  stamp="$(oliphaunt_icu_native_tools_stamp "$source_dir")"
+  if [ -f "$stamp_file" ] &&
+     [ "$(cat "$stamp_file")" = "$stamp" ] &&
+     oliphaunt_icu_native_tools_ready "$native_build_dir"; then
+    return 0
+  fi
+
+  # ICU records this absolute build directory in its cross-build makefiles.
+  # Restore the previous complete build at the same path if rebuilding fails.
+  local backup rebuilding=0
+  mkdir -p "$(dirname "$native_build_dir")"
+  backup="$(mktemp -d "$native_build_dir.previous.XXXXXX")"
+  trap 'status=$?; if [ "$status" -ne 0 ] && [ "$rebuilding" = 1 ]; then rm -rf "$native_build_dir"; if [ -d "$backup/build" ]; then mv "$backup/build" "$native_build_dir" || exit "$status"; fi; fi; rm -rf "$backup"' EXIT
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
+  if [ -e "$native_build_dir" ]; then mv "$native_build_dir" "$backup/build"; fi
+  rebuilding=1
+  mkdir -p "$native_build_dir"
+  (
+    cd "$native_build_dir"
+    "$source_dir/configure" \
+      --disable-shared \
+      --enable-static \
+      --disable-tests \
+      --disable-samples \
+      --disable-extras \
+      --disable-icuio \
+      --disable-layoutex
+    make all-local
+    mkdir -p lib bin
+    make -j"$jobs" -C stubdata
+    make -j"$jobs" -C common
+    make -j"$jobs" -C i18n
+    make -j"$jobs" -C tools/toolutil
+    local tool
+    while IFS= read -r tool; do
+      make -j"$jobs" -C "tools/$tool"
+    done < <(oliphaunt_icu_native_tool_names)
+  )
+  oliphaunt_icu_native_tools_ready "$native_build_dir"
+  printf '%s\n' "$stamp" > "$stamp_file"
+)
+
+oliphaunt_icu_publish_prefix() (
+  set -e
+  local staged="$1" prefix="$2" backup
+  backup="$(mktemp -d "$prefix.previous.XXXXXX")"
+  trap 'status=$?; if [ "$status" -ne 0 ] && [ ! -e "$prefix" ] && [ -d "$backup/prefix" ]; then mv "$backup/prefix" "$prefix" || exit "$status"; fi; rm -rf "$backup"' EXIT
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
+  if [ -e "$prefix" ]; then mv "$prefix" "$backup/prefix"; fi
+  mv "$staged" "$prefix"
+)
+
+oliphaunt_icu_build_target() (
+  set -e
+  local source_dir="${1:?ICU source dir is required}"
+  local native_build_dir="${2:?native build dir is required}"
+  local target_build_dir="${3:?target build dir is required}"
+  local prefix="${4:?prefix is required}"
+  local jobs="${5:?jobs is required}"
+  local target_label="${6:?target label is required}"
+  local host="${7:?host is required}"
+  local cc="${8:?cc is required}"
+  local cxx="${9:?cxx is required}"
+  local ar="${10:?ar is required}"
+  local ranlib="${11:?ranlib is required}"
+  local cflags="${12:-}"
+  local cxxflags="${13:-}"
+  local ldflags="${14:-}"
+
+  oliphaunt_icu_require_canonical_data "$(oliphaunt_icu_canonical_data_archive "$source_dir")"
+  oliphaunt_icu_build_native_tools "$source_dir" "$native_build_dir" "$jobs"
+
+  local stamp_file="$prefix/.oliphaunt-icu-build"
+  local stamp
+  stamp="$(oliphaunt_icu_target_stamp "$source_dir" "$target_label" "$host" "$cc" "$cxx" "$ar" "$ranlib" "$cflags" "$cxxflags" "$ldflags")"
+  if [ -f "$stamp_file" ] &&
+     [ "$(cat "$stamp_file")" = "$stamp" ] &&
+     oliphaunt_icu_artifacts_ready "$prefix"; then
+    return 0
+  fi
+
+  rm -rf "$target_build_dir"
+  mkdir -p "$target_build_dir" "$(dirname "$prefix")"
+  local install_stage staged_prefix
+  install_stage="$(mktemp -d "$prefix.install.XXXXXX")"
+  staged_prefix="$install_stage$prefix"
+  trap 'rm -rf "$install_stage"' EXIT
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
+  (
+    cd "$target_build_dir"
+    CC="$cc" \
+    CXX="$cxx" \
+    AR="$ar" \
+    RANLIB="$ranlib" \
+    CFLAGS="$cflags" \
+    CXXFLAGS="$cxxflags" \
+    LDFLAGS="$ldflags" \
+      "$source_dir/configure" \
+        --host="$host" \
+        --with-cross-build="$native_build_dir" \
+        --with-data-packaging=files \
+        --disable-shared \
+        --enable-static \
+        --disable-tests \
+        --disable-samples \
+        --disable-tools \
+        --disable-extras \
+        --disable-icuio \
+        --disable-layoutex \
+        --prefix="$prefix"
+    local icu_pkgdata_opts="-O $target_build_dir/data/icupkg.inc -w"
+    local icu_data_name
+    icu_data_name="$(
+      awk -F' = ' '$1 == "ICUDATA_NAME" { print $2; exit }' \
+        "$target_build_dir/config/Makefile.inc"
+    )"
+    if [[ ! "$icu_data_name" =~ ^icudt[0-9]+[a-z]+$ ]]; then
+      echo "invalid ICU data name in $target_build_dir/config/Makefile.inc: $icu_data_name" >&2
+      return 1
+    fi
+    # ICU 76.1 does not order genrb after cnvalias.icu. Complete the alias
+    # file before parallel data generators can map a partially written file.
+    make -j1 -C data "out/build/$icu_data_name/cnvalias.icu" PKGDATA_OPTS="$icu_pkgdata_opts"
+    make -j"$jobs" PKGDATA_OPTS="$icu_pkgdata_opts"
+    oliphaunt_icu_prepare_files_data_install_dirs "$target_build_dir" "$staged_prefix"
+    make install DESTDIR="$install_stage" PKGDATA_OPTS="$icu_pkgdata_opts"
+    make -j"$jobs" -C data packagedata PKGDATA_OPTS="$icu_pkgdata_opts"
+    oliphaunt_icu_install_canonical_data "$(oliphaunt_icu_canonical_data_archive "$source_dir")" "$staged_prefix/share/icu"
+    oliphaunt_icu_install_stub_data_archive "$target_build_dir" "$staged_prefix"
+  )
+
+  printf '%s\n' "$stamp" > "$staged_prefix/.oliphaunt-icu-build"
+  oliphaunt_icu_artifacts_ready "$staged_prefix"
+  oliphaunt_icu_publish_prefix "$staged_prefix" "$prefix"
+)
+
+oliphaunt_icu_cflags() {
+  local prefix="${1:?prefix is required}"
+  printf '%s\n' "-DU_STATIC_IMPLEMENTATION -I$prefix/include"
+}
+
+oliphaunt_icu_static_libs() {
+  local prefix="${1:?prefix is required}"
+  printf '%s\n' "$prefix/lib/libicui18n.a $prefix/lib/libicuuc.a $prefix/lib/libicudata.a"
+}
diff --git a/src/third-party/icu/tools/build.test.sh b/src/third-party/icu/tools/build.test.sh
new file mode 100644
index 000000000..78bab9bc5
--- /dev/null
+++ b/src/third-party/icu/tools/build.test.sh
@@ -0,0 +1,86 @@
+#!/usr/bin/env bash
+set -euo pipefail
+source "$(dirname "$0")/build.sh"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+mkdir -p "$scratch/source" "$scratch/bin"
+export ICU_TEST_LOG="$scratch/commands" ICU_TEST_INPUT=one
+export PATH="$scratch/bin:$PATH"
+cat > "$scratch/source/configure" <<'SH'
+#!/usr/bin/env bash
+set -eu
+echo configure >> "$ICU_TEST_LOG"
+[[ ${ICU_TEST_FAIL:-} != configure ]]
+mkdir -p config lib stubdata bin data
+printf 'ICUDATA_NAME = icudt76l\n' > config/Makefile.inc
+touch icudefs.mk config/icucross.mk config/icucross.inc
+for name in icui18n icuuc icutu; do printf '%s' "$ICU_TEST_INPUT" > "lib/lib$name.a"; done
+printf stub > stubdata/stubdata.ao
+ar cr stubdata/libicudata.a stubdata/stubdata.ao
+for name in makeconv gencnval gencfu genbrk gendict genrb gensprep icupkg pkgdata genccode gencmn; do
+  printf '#!/bin/sh\nexit 0\n' > "bin/$name"
+  chmod +x "bin/$name"
+done
+for arg; do case "$arg" in --prefix=*) printf '%s' "${arg#--prefix=}" > configured-prefix;; esac; done
+SH
+cat > "$scratch/bin/make" <<'SH'
+#!/usr/bin/env bash
+set -eu
+echo "$*" >> "$ICU_TEST_LOG"
+[[ ${ICU_TEST_FAIL:-} != make ]]
+if [[ $1 == install ]]; then
+  stage=
+  for arg; do case "$arg" in DESTDIR=*) stage=${arg#DESTDIR=};; esac; done
+  [[ -n $stage ]]
+  prefix="$stage$(cat configured-prefix)"
+  mkdir -p "$prefix/include/unicode" "$prefix/lib"
+  touch "$prefix/include/unicode/ucol.h"
+  cp lib/libicui18n.a lib/libicuuc.a "$prefix/lib/"
+  [[ ${ICU_TEST_FAIL:-} != install ]]
+fi
+SH
+chmod +x "$scratch/source/configure" "$scratch/bin/make"
+# Replace only source/data acquisition; execute the real cache, configure,
+# install, archive validation and publication paths against a tiny build.
+oliphaunt_icu_source_commit() { printf '%s\n' "$ICU_TEST_INPUT"; }
+oliphaunt_icu_canonical_data_sha256() { printf data; }
+oliphaunt_icu_canonical_data_archive() { printf data; }
+oliphaunt_icu_require_canonical_data() { :; }
+oliphaunt_icu_install_canonical_data() { mkdir -p "$2"; printf data > "$2/data"; }
+oliphaunt_icu_files_data_ready() { test -f "$1/data"; }
+build() {
+  oliphaunt_icu_build_target "$scratch/source" "$scratch/native" \
+    "$scratch/build" "$scratch/install" 1 test test cc c++ ar ranlib '' '' ''
+}
+build
+first_stamp=$(cat "$scratch/install/.oliphaunt-icu-build")
+first_commands=$(wc -l < "$ICU_TEST_LOG")
+build
+[[ $(wc -l < "$ICU_TEST_LOG") == "$first_commands" ]]
+export ICU_TEST_INPUT=two ICU_TEST_FAIL=configure
+# A failed native-tools rebuild must restore the original absolute-path tree.
+set +e
+(set -e; build)
+status=$?
+set -e
+[[ $status != 0 && $(cat "$scratch/native/lib/libicuuc.a") == one ]]
+[[ $(cat "$scratch/install/.oliphaunt-icu-build") == "$first_stamp" ]]
+unset ICU_TEST_FAIL
+oliphaunt_icu_build_native_tools "$scratch/source" "$scratch/native" 1
+for phase in make install; do
+  export ICU_TEST_FAIL=$phase
+  set +e
+  (set -e; build)
+  status=$?
+  set -e
+  [[ $status != 0 && $(cat "$scratch/install/lib/libicuuc.a") == one ]]
+  [[ $(cat "$scratch/install/.oliphaunt-icu-build") == "$first_stamp" ]]
+done
+unset ICU_TEST_FAIL
+build
+[[ $(cat "$scratch/install/lib/libicuuc.a") == two ]]
+[[ $(cat "$scratch/install/.oliphaunt-icu-build") != "$first_stamp" ]]
+last_commands=$(wc -l < "$ICU_TEST_LOG")
+build
+[[ $(wc -l < "$ICU_TEST_LOG") == "$last_commands" ]]
+printf 'ICU repeated builds, changed inputs and failed rebuild preservation passed\n'
diff --git a/src/runtimes/liboliphaunt/licenses/openssl-3.5.6-LICENSE.txt b/src/third-party/openssl/LICENSE.txt
similarity index 100%
rename from src/runtimes/liboliphaunt/licenses/openssl-3.5.6-LICENSE.txt
rename to src/third-party/openssl/LICENSE.txt
diff --git a/src/third-party/openssl/moon.yml b/src/third-party/openssl/moon.yml
new file mode 100644
index 000000000..573680054
--- /dev/null
+++ b/src/third-party/openssl/moon.yml
@@ -0,0 +1,11 @@
+id: third-party-openssl
+language: unknown
+layer: configuration
+tags:
+  - third-party
+  - sources
+fileGroups:
+  sources:
+    - source.toml
+  legal:
+    - LICENSE*
\ No newline at end of file
diff --git a/src/sources/third-party/shared/openssl.toml b/src/third-party/openssl/source.toml
similarity index 100%
rename from src/sources/third-party/shared/openssl.toml
rename to src/third-party/openssl/source.toml
diff --git a/src/runtimes/liboliphaunt/licenses/postgresql-18.4-COPYRIGHT b/src/third-party/postgres/COPYRIGHT
similarity index 100%
rename from src/runtimes/liboliphaunt/licenses/postgresql-18.4-COPYRIGHT
rename to src/third-party/postgres/COPYRIGHT
diff --git a/src/third-party/postgres/apply-series.sh b/src/third-party/postgres/apply-series.sh
new file mode 100644
index 000000000..8b518777c
--- /dev/null
+++ b/src/third-party/postgres/apply-series.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -euo pipefail
+repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
+source_dir="${1:?PostgreSQL source directory required}"
+series="${2:?ordered patch series required}"
+while IFS= read -r entry || [ -n "$entry" ]; do
+  case "$entry" in
+    ''|'#'*) continue ;;
+    /*|*..*|*\\*) echo "unsafe PostgreSQL patch path: $entry" >&2; exit 2 ;;
+  esac
+  patch="$repo_root/$entry"
+  [ -f "$patch" ] && [ ! -L "$patch" ] || {
+    echo "missing regular PostgreSQL patch: $patch" >&2; exit 2;
+  }
+  if [ "${3:-}" = "--context-fuzz" ]; then
+    # The existing embedded WASIX series contains upstream-context offsets.
+    (cd "$source_dir" && patch --batch --forward --no-backup-if-mismatch -p1 < "$patch")
+  else
+    git -C "$source_dir" apply --whitespace=error-all "$patch"
+  fi
+done < "$series"
diff --git a/src/postgres/versions/18/fetch-source.sh b/src/third-party/postgres/fetch-source.sh
similarity index 100%
rename from src/postgres/versions/18/fetch-source.sh
rename to src/third-party/postgres/fetch-source.sh
diff --git a/src/postgres/versions/18/fetch-source.test.sh b/src/third-party/postgres/fetch-source.test.sh
similarity index 100%
rename from src/postgres/versions/18/fetch-source.test.sh
rename to src/third-party/postgres/fetch-source.test.sh
diff --git a/src/postgres/versions/18/moon.yml b/src/third-party/postgres/moon.yml
similarity index 100%
rename from src/postgres/versions/18/moon.yml
rename to src/third-party/postgres/moon.yml
diff --git a/src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0016-liboliphaunt-control-initdb-collation-discovery.patch b/src/third-party/postgres/patches/common/control-initdb-collation-discovery.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/native/patches/postgresql-18.4/0016-liboliphaunt-control-initdb-collation-discovery.patch
rename to src/third-party/postgres/patches/common/control-initdb-collation-discovery.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch b/src/third-party/postgres/patches/wasix/0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch
rename to src/third-party/postgres/patches/wasix/0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch b/src/third-party/postgres/patches/wasix/0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch
rename to src/third-party/postgres/patches/wasix/0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch b/src/third-party/postgres/patches/wasix/0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch
rename to src/third-party/postgres/patches/wasix/0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch b/src/third-party/postgres/patches/wasix/0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch
rename to src/third-party/postgres/patches/wasix/0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch b/src/third-party/postgres/patches/wasix/0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch
rename to src/third-party/postgres/patches/wasix/0024-oliphaunt-wasix-add-like-literal-substring-fast-path.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch b/src/third-party/postgres/patches/wasix/0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch
rename to src/third-party/postgres/patches/wasix/0026-oliphaunt-wasix-add-first-int4-leaf-compare-fast-path.patch
diff --git a/src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0037-oliphaunt-wasix-buffer-strong-random.patch b/src/third-party/postgres/patches/wasix/0037-oliphaunt-wasix-buffer-strong-random.patch
similarity index 100%
rename from src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/0037-oliphaunt-wasix-buffer-strong-random.patch
rename to src/third-party/postgres/patches/wasix/0037-oliphaunt-wasix-buffer-strong-random.patch
diff --git a/src/third-party/postgres/source.mts b/src/third-party/postgres/source.mts
new file mode 100644
index 000000000..fed800367
--- /dev/null
+++ b/src/third-party/postgres/source.mts
@@ -0,0 +1,15 @@
+import assert from 'node:assert/strict';
+import { readFileSync } from 'node:fs';
+
+const source = Bun.TOML.parse(
+  readFileSync(new URL('./source.toml', import.meta.url), 'utf8'),
+).postgresql;
+const fields = ['version', 'sha256', 'url'].map((key) => {
+  const value = source[key];
+  assert(
+    typeof value === 'string' && value && !/[\t\r\n]/.test(value),
+    `invalid PostgreSQL ${key}`,
+  );
+  return value;
+});
+console.log(fields.join('\t'));
diff --git a/src/postgres/versions/18/source.toml b/src/third-party/postgres/source.toml
similarity index 100%
rename from src/postgres/versions/18/source.toml
rename to src/third-party/postgres/source.toml
diff --git a/src/postgres/versions/18/testdata/curl b/src/third-party/postgres/testdata/curl
similarity index 100%
rename from src/postgres/versions/18/testdata/curl
rename to src/third-party/postgres/testdata/curl
diff --git a/src/third-party/tools/fetch-sources.mts b/src/third-party/tools/fetch-sources.mts
new file mode 100755
index 000000000..b7f19a800
--- /dev/null
+++ b/src/third-party/tools/fetch-sources.mts
@@ -0,0 +1,227 @@
+#!/usr/bin/env bun
+import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
+import { dirname, join, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { auditExtensionUpstreamLicenseSources } from '../../extensions/tools/extension-upstream-licenses.mts';
+import { validateSource } from './source-fetch-core.mts';
+import {
+  defaultSourceScope,
+  scopeIncludes,
+  scopeIncludesExtensions,
+  sourceDomainsForScope,
+  sourceOrigins,
+  sourceScopes,
+} from './source-fetch-scopes.mts';
+
+const workspaceRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
+process.chdir(workspaceRoot);
+
+const allowedScopes = new Set(sourceScopes);
+try {
+  const [operation, output, ...args] = process.argv.slice(2);
+  if (operation === 'audit') {
+    const count = Number(output);
+    if (count > 0) {
+      const audited = auditExtensionUpstreamLicenseSources();
+      if (!Number.isSafeInteger(audited) || audited < 1)
+        throw new Error('extension legal audit inspected no pinned files');
+      console.error(
+        `audited ${audited} pinned extension legal source files after qualifying ${count} extension source checkouts`,
+      );
+    }
+  } else if (operation === 'plan' && output) {
+    writeFileSync(join(output, 'mode'), 'skip');
+    const { scope, force, validateOnly, verifyOnly } = parseArgs(args);
+    if (!allowedScopes.has(scope)) throw new Error('unsupported source fetch scope: ' + scope);
+    let mode = verifyOnly ? 'verify' : 'fetch';
+    if (
+      !validateOnly &&
+      !verifyOnly &&
+      !force &&
+      process.env.CI !== 'true' &&
+      process.env.OLIPHAUNT_FETCH_SOURCES !== '1'
+    ) {
+      console.log(
+        `source checkout fetch skipped outside CI for scope '${scope}'; set OLIPHAUNT_FETCH_SOURCES=1 or pass --force`,
+      );
+      mode = 'skip';
+    }
+    const sources = loadSourcesManifest(scope).sources.filter((source) =>
+      scopeIncludes(scope, source.origin),
+    );
+    if (sources.length === 0)
+      throw new Error('source metadata must contain at least one source pin');
+    for (const source of sources) validateSource(source);
+    if (validateOnly) mode = 'skip';
+    writeFileSync(join(output, 'mode'), mode);
+    writeFileSync(
+      join(output, 'extension-count'),
+      String(sources.filter((source) => source.origin === sourceOrigins.extension).length),
+    );
+    const pins = [];
+    if (mode !== 'skip')
+      for (const source of sources) {
+        const file = join(output, source.name + '.json');
+        writeFileSync(file, JSON.stringify(source));
+        pins.push(file);
+      }
+    writeFileSync(join(output, 'pins'), pins.length ? pins.join('\0') + '\0' : '');
+  } else
+    throw new Error('source planning is internal; use bash src/third-party/tools/fetch-sources.sh');
+} catch (error) {
+  fail(error.message);
+}
+
+function parseArgs(args) {
+  let selectedScope = defaultSourceScope;
+  let sawScope = false;
+  let forceFetch = false;
+  let validateOnly = false;
+  let verifyOnly = false;
+  for (const arg of args) {
+    if (arg === '--force') {
+      forceFetch = true;
+      continue;
+    }
+    if (arg === '--verify-only') {
+      verifyOnly = true;
+      continue;
+    }
+    if (arg === '--validate-only') {
+      validateOnly = true;
+      continue;
+    }
+    if (arg === '--help' || arg === '-h') {
+      console.log(
+        `usage: bash src/third-party/tools/fetch-sources.sh [${sourceScopes.join('|')}] [--force|--validate-only|--verify-only]`,
+      );
+      process.exit(0);
+    }
+    if (sawScope) {
+      fail(`unexpected argument '${arg}'`, 2);
+    }
+    selectedScope = arg;
+    sawScope = true;
+  }
+  if (Number(forceFetch) + Number(validateOnly) + Number(verifyOnly) > 1) {
+    fail('--force, --validate-only, and --verify-only are mutually exclusive', 2);
+  }
+  return { scope: selectedScope, force: forceFetch, validateOnly, verifyOnly };
+}
+
+function loadSourcesManifest(selectedScope) {
+  const sources = [];
+  const names = new Set();
+  if (selectedScope === 'icu') {
+    pushSourcePin(
+      sources,
+      names,
+      join(workspaceRoot, 'src/database-resources/icu/source.toml'),
+      sourceOrigins.sharedThirdParty,
+    );
+    return { sources };
+  }
+  if (scopeIncludes(selectedScope, sourceOrigins.sharedThirdParty)) {
+    // ICU compilation consumes the data even when runtime packages omit it.
+    pushSourcePin(
+      sources,
+      names,
+      join(workspaceRoot, 'src/database-resources/icu/source.toml'),
+      sourceOrigins.sharedThirdParty,
+    );
+  }
+  for (const [domain, origin] of sourceDomainsForScope(selectedScope)) {
+    const domainDir = join(workspaceRoot, domain);
+    if (!existsSync(domainDir)) throw new Error(`missing source directory: ${domainDir}`);
+    for (const file of readdirSync(domainDir).sort()) {
+      if (!file.endsWith('.toml')) {
+        continue;
+      }
+      pushSourcePin(sources, names, join(domainDir, file), origin);
+    }
+  }
+  if (scopeIncludesExtensions(selectedScope)) {
+    for (const sourcePath of extensionSourcePinPaths()) {
+      pushSourcePin(sources, names, sourcePath, sourceOrigins.extension);
+    }
+  }
+  return { sources };
+}
+
+function extensionSourcePinPaths() {
+  const root = join(workspaceRoot, 'src/extensions', 'external');
+  const paths = [];
+  collectSourcePins(root, paths);
+  return paths.sort();
+}
+
+function collectSourcePins(dir, paths) {
+  if (!existsSync(dir)) {
+    return;
+  }
+  for (const entry of readdirSync(dir, { withFileTypes: true }).sort((left, right) =>
+    left.name < right.name ? -1 : left.name > right.name ? 1 : 0,
+  )) {
+    const path = join(dir, entry.name);
+    if (entry.isDirectory()) {
+      collectSourcePins(path, paths);
+    } else if (entry.name === 'source.toml') {
+      paths.push(path);
+    }
+  }
+}
+
+function pushSourcePin(sources, names, path, origin) {
+  const raw = readToml(path);
+  const source = {
+    name: stringField(raw, 'name', path),
+    kind: raw.kind ?? 'git',
+    url: stringField(raw, 'url', path),
+    mirrorUrl: optionalStringField(raw, 'mirror_url', path),
+    branch: stringField(raw, 'branch', path),
+    commit: stringField(raw, 'commit', path),
+    sha256: optionalStringField(raw, 'sha256', path),
+    stripPrefix:
+      optionalStringField(raw, 'strip_prefix', path) ??
+      optionalStringField(raw, 'strip-prefix', path),
+    origin,
+  };
+  if (names.has(source.name)) {
+    throw new Error(`duplicate source pin '${source.name}' in source metadata`);
+  }
+  names.add(source.name);
+  sources.push(source);
+}
+
+function readToml(path) {
+  const text = readFileSync(path, 'utf8');
+  try {
+    return Bun.TOML.parse(text);
+  } catch (error) {
+    throw new Error(`parse ${path}: ${error instanceof Error ? error.message : String(error)}`);
+  }
+}
+
+function stringField(object, field, path) {
+  const value = object[field];
+  if (typeof value !== 'string' || value.trim() === '') {
+    throw new Error(`${path} must set non-empty string field '${field}'`);
+  }
+  return value;
+}
+
+function optionalStringField(object, field, path) {
+  const value = object[field];
+  if (value === undefined) {
+    return undefined;
+  }
+  if (typeof value !== 'string') {
+    throw new Error(`${path} field '${field}' must be a string`);
+  }
+  return value;
+}
+
+function fail(message, code = 1) {
+  console.error(message);
+  process.exit(code);
+}
diff --git a/src/third-party/tools/fetch-sources.sh b/src/third-party/tools/fetch-sources.sh
new file mode 100644
index 000000000..1c59728cd
--- /dev/null
+++ b/src/third-party/tools/fetch-sources.sh
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+set -euo pipefail
+source_tools=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+source_core="$source_tools/source-fetch-core.mts"
+# shellcheck source=tools/dev/curl-platform-flags.sh
+source "$source_tools/../../../tools/dev/curl-platform-flags.sh"
+
+source_git() {
+  local seconds=$1 directory=$2 status=0
+  shift 2
+  # Bound both streams, including diagnostics, without holding them in memory.
+  # pipefail rejects a producer killed by SIGPIPE; the byte count also catches
+  # a producer that completed its last write before head closed the pipe.
+  "$source_timeout" --kill-after=5 "$seconds" git -C "$directory" \
+    -c core.fsmonitor=false -c submodule.recurse=false \
+    -c core.autocrlf=false -c core.eol=lf "$@" \
+    2> >(head -c 16777217 > "$source_stage/git-error") |
+    head -c 16777217 > "$source_stage/git-output" || status=$?
+  if (( $(wc -c < "$source_stage/git-output") > 16777216 )); then status=1; fi
+  # Process substitution is asynchronous: wait for its reader before inspection.
+  wait
+  if (( $(wc -c < "$source_stage/git-error") > 16777216 )); then status=1; fi
+  cat "$source_stage/git-error" >&2
+  cat "$source_stage/git-output"
+  return "$status"
+}
+
+source_snapshot() {
+  local checkout=$1 snapshot=$2
+  mkdir -p "$snapshot"
+  if [[ -d "$checkout" && ! -L "$checkout" && -d "$checkout/.git" && ! -L "$checkout/.git" ]]; then
+    source_git 60 "$checkout" rev-parse --show-toplevel > "$snapshot/worktree"
+    source_git 60 "$checkout" rev-parse --absolute-git-dir > "$snapshot/git-directory"
+    bun "$source_core" git-identity "$pin" "$checkout" "$snapshot"
+    source_git 60 "$checkout" status --porcelain=v1 --untracked-files=all > "$snapshot/status"
+    # Missing pin fields make a clean checkout stale; repository errors above
+    # remain fatal. The data validator compares the complete snapshot.
+    source_git 60 "$checkout" rev-parse --verify HEAD > "$snapshot/head" || : > "$snapshot/head"
+    source_git 60 "$checkout" branch --show-current > "$snapshot/branch" || : > "$snapshot/branch"
+    source_git 60 "$checkout" remote get-url origin > "$snapshot/origin" || : > "$snapshot/origin"
+    source_git 60 "$checkout" config --local --get core.autocrlf > "$snapshot/autocrlf" || : > "$snapshot/autocrlf"
+    source_git 60 "$checkout" config --local --get core.eol > "$snapshot/eol" || : > "$snapshot/eol"
+  fi
+}
+
+fetch_source() (
+  set -euo pipefail
+  local pin=$1 checkout_root=$2 archive_root=$3 mode=$4
+  local name kind url mirror branch commit archive_name canonical checkout readiness fetched
+  local source_lock='' lock_deadline
+  mkdir -p "$checkout_root" "$archive_root"
+  source_stage=$(mktemp -d "$checkout_root/.source-stage-XXXXXX")
+  trap 'rm -rf "$source_stage"; if [[ -n "$source_lock" ]]; then rmdir "$source_lock"; fi' EXIT
+  trap 'exit 129' HUP
+  trap 'exit 130' INT
+  trap 'exit 143' TERM
+  bun "$source_core" fields "$pin" > "$source_stage/fields"
+  { IFS= read -r -d '' name; IFS= read -r -d '' kind; IFS= read -r -d '' url
+    IFS= read -r -d '' mirror; IFS= read -r -d '' branch; IFS= read -r -d '' commit
+    IFS= read -r -d '' archive_name; IFS= read -r -d '' canonical
+  } < "$source_stage/fields"
+  checkout="$checkout_root/$name"
+  # Scopes overlap (notably ICU data). Serialize inspection through promotion,
+  # so a waiter reuses the complete checkout instead of replacing it concurrently.
+  lock_deadline=$((SECONDS + 3600))
+  until mkdir "$checkout.lock" 2>/dev/null; do
+    if (( SECONDS >= lock_deadline )); then
+      echo "timed out waiting for source checkout lock: $checkout.lock" >&2; exit 1
+    fi
+    sleep 0.1
+  done
+  source_lock="$checkout.lock"
+  # Ignore ambient Git configuration, hooks, credentials, and alternate stores.
+  while IFS= read -r variable; do
+    case "$variable" in GIT_*) unset "$variable" ;; esac
+  done < <(compgen -e)
+  : > "$source_stage/empty.gitconfig"
+  export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL="$source_stage/empty.gitconfig"
+  export GIT_TERMINAL_PROMPT=0 GCM_INTERACTIVE=Never
+  source_timeout=$(command -v timeout || command -v gtimeout) || {
+    echo 'source fetching requires GNU timeout (brew install coreutils on macOS)' >&2; exit 1;
+  }
+  source_snapshot "$checkout" "$source_stage/durable"
+  readiness=$(bun "$source_core" inspect "$pin" "$checkout" "$source_stage/durable")
+  if [[ "$readiness" == ready ]]; then exit 0; fi
+  if [[ "$mode" == verify ]]; then echo "source checkout $checkout is missing or stale" >&2; exit 1; fi
+
+  local candidate="$source_stage/checkout"
+  if [[ "$kind" == git ]]; then
+    source_git 60 "$checkout_root" init --quiet --template= "$candidate"
+    source_git 60 "$candidate" config --local core.autocrlf false
+    source_git 60 "$candidate" config --local core.eol lf
+    source_git 60 "$candidate" remote add origin "$url"
+    local transports=("$url") attempt transport success=false
+    if [[ -n "$mirror" ]]; then transports+=("$mirror"); fi
+    for attempt in 1 2 3 4 5; do
+      transport=${transports[$(((attempt - 1) % ${#transports[@]}))]}
+      if source_git 300 "$candidate" \
+        -c protocol.allow=never -c protocol.https.allow=always -c credential.helper= \
+        -c http.followRedirects=false -c http.lowSpeedLimit=1024 -c http.lowSpeedTime=120 \
+        fetch --no-tags --depth=1 "$transport" "$commit"; then success=true; break; fi
+      echo "fetch $name from $transport failed on attempt $attempt/5" >&2
+      if (( attempt < 5 && attempt % ${#transports[@]} == 0 )); then
+        sleep "$((attempt * 5 / ${#transports[@]}))"
+      fi
+    done
+    "$success" || exit 1
+    fetched=$(source_git 60 "$candidate" rev-parse --verify 'FETCH_HEAD^{commit}')
+    if [[ "$fetched" != "$commit" ]]; then
+      echo "fetch for $name returned $fetched, expected exact commit $commit" >&2; exit 1
+    fi
+    source_git 60 "$candidate" checkout --quiet -B "$branch" "$commit"
+    source_snapshot "$candidate" "$source_stage/candidate"
+    bun "$source_core" git-candidate "$pin" "$candidate" "$source_stage/candidate"
+  else
+    local archive="$archive_root/$archive_name" download="$source_stage/$archive_name"
+    if [[ "$(bun "$source_core" archive-valid "$pin" "$archive")" != valid ]]; then
+      local urls=() endpoint success=false
+      if [[ -n "$canonical" ]]; then urls+=("$canonical"); fi
+      urls+=("$url")
+      if [[ -n "$mirror" ]]; then urls+=("$mirror"); fi
+      local tls_flag
+      tls_flag=$(oliphaunt_curl_platform_tls_flag)
+      for endpoint in "${urls[@]}"; do
+        if "$source_timeout" --kill-after=5 620 curl --disable --fail --location --silent --show-error \
+          --retry 2 --retry-all-errors --retry-connrefused --retry-delay 5 --retry-max-time 600 \
+          --connect-timeout 20 --max-time 600 --speed-limit 1024 --speed-time 120 \
+          --max-filesize 1073741824 --max-redirs 5 --proto-default https \
+          --proto '=https' --proto-redir '=https' --tlsv1.2 ${tls_flag:+"$tls_flag"} \
+          --remove-on-error --url "$endpoint" --output "$download"; then success=true; break; fi
+        echo "download $name from $endpoint failed" >&2
+        rm -f "$download"
+      done
+      "$success" || exit 1
+      # An invalid candidate never replaces even a corrupt existing cache.
+      [[ "$(bun "$source_core" archive-valid "$pin" "$download")" == valid ]] || exit 1
+      bun "$source_core" promote "$download" "$archive"
+    fi
+    bun "$source_core" unpack "$pin" "$archive" "$candidate"
+  fi
+  # Reinspect immediately before replacing an existing checkout, including a
+  # source that changed kind. The promotion helper restores a prior tree on error.
+  source_snapshot "$checkout" "$source_stage/durable"
+  bun "$source_core" inspect "$pin" "$checkout" "$source_stage/durable" > /dev/null
+  bun "$source_core" promote "$candidate" "$checkout"
+)
+
+if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
+  cd "$source_tools/../../.."
+  source_work=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-source-plan-XXXXXX")
+  source_work=$(cd "$source_work" && pwd -P)
+  trap 'rm -rf "$source_work"' EXIT
+  bun "$source_tools/fetch-sources.mts" plan "$source_work" "$@"
+  mode=$(cat "$source_work/mode")
+  if [[ "$mode" != skip ]]; then
+    while IFS= read -r -d '' pin; do
+      fetch_source "$pin" "$PWD/target/oliphaunt-sources/checkouts" "$PWD/target/oliphaunt-sources/archives" "$mode"
+      # Bash 3.2 does not propagate a failed subshell function through this loop.
+      status=$?
+      [[ "$status" == 0 ]] || exit "$status"
+    done < "$source_work/pins"
+    bun "$source_tools/fetch-sources.mts" audit "$(cat "$source_work/extension-count")"
+  fi
+fi
diff --git a/src/third-party/tools/moon.yml b/src/third-party/tools/moon.yml
new file mode 100644
index 000000000..0193fa472
--- /dev/null
+++ b/src/third-party/tools/moon.yml
@@ -0,0 +1,144 @@
+$schema: https://moonrepo.dev/schemas/project.json
+id: source-inputs
+language: unknown
+layer: configuration
+stack: systems
+tags:
+  - javascript-quality
+  - sources
+project:
+  title: Source Inputs
+  description: "Neutral source checkout materialization for PostgreSQL, runtime dependencies, toolchains, and extension-owned sources."
+  owner: oliphaunt
+owners:
+  defaultOwner: "@oliphaunt/core"
+  paths:
+    "**/*":
+      - "@oliphaunt/core"
+tasks:
+  source-fetch-icu-data:
+    command: bash src/third-party/tools/fetch-sources.sh icu --force
+    inputs:
+      - /src/database-resources/icu/source.toml
+      - "**/*"
+      - "!**/*.test.*"
+      - /tools/dev/curl-platform-flags.sh
+      - "@group(release-archive-contract)"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+  test:
+    tags:
+      - quality
+      - unit
+    script: "set -e\nbash src/third-party/tools/fetch-sources.sh production-all --validate-only\nbash src/third-party/tools/source-fetch-core.test.sh\nbun test ./src/third-party/tools/source-fetch-scopes.test.mts\nbash src/third-party/postgres/fetch-source.test.sh\n"
+    inputs:
+      - /src/third-party/postgres/**/*
+      - "/src/third-party/{icu,openssl}/source.toml"
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - /src/runtimes/liboliphaunt-wasix-postmaster/sources/*.toml
+      - /src/extensions/external/**/source.toml
+      - /src/extensions/external/**/dependencies/**/source.toml
+      - /src/extensions/external/*/upstream-license-data.json
+      - "**/*"
+      - /tools/packaging/portable-archive.mts
+      - "/tools/packaging/testdata/{zip,tar}-fixture.mts"
+    options:
+      cache: true
+      runFromWorkspaceRoot: true
+  fetch-all:
+    tags:
+      - source
+      - fetch
+    command: bash src/third-party/tools/fetch-sources.sh production-all --force
+    inputs:
+      - /src/database-resources/icu/source.toml
+      - "/src/third-party/{icu,openssl}/source.toml"
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - /src/runtimes/liboliphaunt-wasix-postmaster/sources/*.toml
+      - /src/extensions/external/**/source.toml
+      - /src/extensions/external/**/dependencies/**/source.toml
+      - /src/extensions/external/*/upstream-license-data.json
+      - "**/*"
+      - "!**/*.test.*"
+      - "!verify-source-tree.mts"
+      - /tools/dev/curl-platform-flags.sh
+      - /src/extensions/tools/extension-upstream-licenses.mts
+      - "@group(release-archive-contract)"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
+      runInCI: false
+  source-fetch-native-runtime:
+    tags:
+      - source
+      - fetch
+    command: bash src/third-party/tools/fetch-sources.sh native-runtime --force
+    inputs:
+      - /src/database-resources/icu/source.toml
+      - "/src/third-party/{icu,openssl}/source.toml"
+      - /src/runtimes/liboliphaunt-native/sources/*.toml
+      - "**/*"
+      - "!**/*.test.*"
+      - "!verify-source-tree.mts"
+      - /tools/dev/curl-platform-flags.sh
+      - "@group(release-archive-contract)"
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+  source-fetch-wasix-runtime:
+    tags:
+      - source
+      - fetch
+    command: bash src/third-party/tools/fetch-sources.sh wasix-runtime --force
+    inputs:
+      - /src/database-resources/icu/source.toml
+      - "/src/third-party/{icu,openssl}/source.toml"
+      - /src/extensions/external/**/source.toml
+      - /src/extensions/external/**/dependencies/**/source.toml
+      - /src/extensions/external/*/upstream-license-data.json
+      - "**/*"
+      - "!**/*.test.*"
+      - "!verify-source-tree.mts"
+      - /tools/dev/curl-platform-flags.sh
+      - "@group(release-archive-contract)"
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+  source-fetch-wasix-postmaster-runtime:
+    tags:
+      - source
+      - fetch
+    command: bash src/third-party/tools/fetch-sources.sh wasix-postmaster-runtime --force
+    inputs:
+      - /src/database-resources/icu/source.toml
+      - "/src/third-party/{icu,openssl}/source.toml"
+      - /src/runtimes/liboliphaunt-wasix-postmaster/sources/*.toml
+      - "**/*"
+      - "!**/*.test.*"
+      - "!verify-source-tree.mts"
+      - /tools/dev/curl-platform-flags.sh
+    options:
+      cache: false
+      internal: true
+      runFromWorkspaceRoot: true
+  source-fetch-extensions:
+    tags:
+      - source
+      - fetch
+    command: bash src/third-party/tools/fetch-sources.sh extensions --force
+    inputs:
+      - /src/extensions/external/**/source.toml
+      - /src/extensions/external/**/dependencies/**/source.toml
+      - /src/extensions/external/*/upstream-license-data.json
+      - "**/*"
+      - "!**/*.test.*"
+      - "!verify-source-tree.mts"
+      - /tools/dev/curl-platform-flags.sh
+      - /src/extensions/tools/extension-upstream-licenses.mts
+      - "@group(release-archive-contract)"
+    options:
+      cache: false
+      runFromWorkspaceRoot: true
diff --git a/src/third-party/tools/source-archive.mts b/src/third-party/tools/source-archive.mts
new file mode 100644
index 000000000..9cacf93ec
--- /dev/null
+++ b/src/third-party/tools/source-archive.mts
@@ -0,0 +1,127 @@
+import assert from 'node:assert/strict';
+import {
+  chmodSync,
+  linkSync,
+  lstatSync,
+  mkdirSync,
+  rmSync,
+  symlinkSync,
+  writeFileSync,
+} from 'node:fs';
+import { dirname, join, posix } from 'node:path';
+import {
+  portableMemberName,
+  readSourceArchiveEntries,
+} from '../../../tools/packaging/portable-archive.mts';
+
+export function sourceArchiveEntries(archive: string, prefix: string) {
+  const size = lstatSync(archive).size;
+  const limits = {
+    maxEntries: 200_000,
+    maxArchiveBytes: 1024 ** 3,
+    maxEntryBytes: 2 * 1024 ** 3,
+    maxExpandedBytes: Math.min(4 * 1024 ** 3, Math.max(64 * 1024 ** 2, size * 200)),
+  };
+  const zip = archive.endsWith('.zip');
+  assert(
+    (zip && prefix === '.') ||
+      (portableMemberName(prefix, 'file', archive) === prefix && !prefix.includes('/')),
+    'strip prefix must be one portable top-level directory',
+  );
+  // ponytail: pinned source tarballs use V7/ustar; add PAX only when a source pin needs it.
+  const entries = readSourceArchiveEntries(archive, limits);
+  const relative = (name: string) => {
+    if (prefix === '.') return name;
+    assert(
+      name === prefix || name.startsWith(`${prefix}/`),
+      `source member ${name} is outside required root ${prefix}`,
+    );
+    return name === prefix ? '' : name.slice(prefix.length + 1);
+  };
+  const portable = new Set();
+  const members = [...entries.values()].map((entry) => {
+    const name = relative(entry.name);
+    assert(
+      !['.git', '.oliphaunt-source-pin'].includes(name.split('/')[0]),
+      'reserved source-spine path',
+    );
+    const key = name.normalize('NFC').toUpperCase().toLowerCase();
+    assert(!portable.has(key), `source paths collide on a portable filesystem: ${name}`);
+    portable.add(key);
+    if (name === '') assert(entry.isDirectory, 'archive root must be a directory');
+    let target: string | undefined;
+    if (entry.type === 'symlink' || entry.type === 'hardlink') {
+      const link = entry.linkTarget;
+      assert(
+        typeof link === 'string' &&
+          link &&
+          !/[\\\u0000-\u001f\u007f]/.test(link) &&
+          !posix.isAbsolute(link) &&
+          !/^[A-Za-z]:/.test(link),
+        `unsafe source link ${entry.name}`,
+      );
+      const resolved = posix.normalize(
+        entry.type === 'symlink' ? posix.join(posix.dirname(entry.name), link) : link,
+      );
+      portableMemberName(resolved, 'file', archive);
+      target = relative(resolved);
+      assert(
+        target && entries.has(resolved),
+        `source link ${entry.name} has a missing or escaping target`,
+      );
+      if (entry.type === 'hardlink')
+        assert(entries.get(resolved)?.isFile, `hard link ${entry.name} must target a regular file`);
+    }
+    return { ...entry, relative: name, target };
+  });
+  return members;
+}
+
+export function extractSourceArchive(archive: string, prefix: string, destination: string) {
+  const members = sourceArchiveEntries(archive, prefix);
+  mkdirSync(dirname(destination), { recursive: true });
+  mkdirSync(destination, { mode: 0o755 }); // Exclusive: never remove or overwrite a caller's existing checkout.
+  try {
+    const parent = (name: string) => {
+      const directory = dirname(join(destination, name));
+      mkdirSync(directory, { recursive: true, mode: 0o755 });
+      return join(destination, name);
+    };
+    // Create links last, so no archive path can be written through a link.
+    for (const entry of members) {
+      if (!entry.relative || !['file', 'directory'].includes(entry.type)) continue;
+      const output = parent(entry.relative);
+      if (entry.isDirectory) mkdirSync(output, { recursive: true, mode: 0o755 });
+      else {
+        writeFileSync(output, entry.data(), { flag: 'wx', mode: (entry.mode & 0o755) | 0o600 });
+        chmodSync(output, (entry.mode & 0o755) | 0o600);
+      }
+    }
+    for (const entry of members)
+      if (entry.type === 'hardlink')
+        linkSync(join(destination, entry.target!), parent(entry.relative));
+    for (const entry of members)
+      if (entry.type === 'symlink') symlinkSync(entry.linkTarget, parent(entry.relative));
+  } catch (error) {
+    rmSync(destination, { recursive: true, force: true });
+    throw error;
+  }
+}
+
+if (import.meta.main) {
+  try {
+    const [mode, archive, prefix, destination, extra] = Bun.argv.slice(2);
+    assert(
+      archive &&
+        prefix &&
+        !extra &&
+        ((mode === 'validate' && !destination) || (mode === 'extract' && destination)),
+      'usage: source-archive.mts validate|extract ARCHIVE PREFIX [DESTINATION]',
+    );
+    if (mode === 'validate') sourceArchiveEntries(archive, prefix);
+    else extractSourceArchive(archive, prefix, destination);
+  } catch (error) {
+    console.error(`unsafe source archive: ${error.message}`);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/third-party/tools/source-fetch-core.mts b/src/third-party/tools/source-fetch-core.mts
new file mode 100644
index 000000000..f0323f0dc
--- /dev/null
+++ b/src/third-party/tools/source-fetch-core.mts
@@ -0,0 +1,705 @@
+import { createHash, randomUUID } from 'node:crypto';
+import {
+  closeSync,
+  lstatSync,
+  mkdirSync,
+  openSync,
+  readdirSync,
+  readFileSync,
+  readlinkSync,
+  readSync,
+  realpathSync,
+  renameSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
+
+import { extractSourceArchive, sourceArchiveEntries } from './source-archive.mts';
+
+const ARCHIVE_SAFETY_VERSION = 'source-archive-v2';
+const DOWNLOAD_MAX_BYTES = 1024 * 1024 * 1024;
+const CHECKOUT_MAX_ENTRIES = 500_000;
+const CHECKOUT_MAX_BYTES = 8 * 1024 * 1024 * 1024;
+const GNU_MIRROR_ORIGIN = 'https://ftpmirror.gnu.org';
+const GNU_CANONICAL_ARCHIVE_ORIGIN = 'https://ftp.gnu.org/gnu';
+const GNU_ARCHIVE_PATH_COMPONENT = /^[A-Za-z0-9][A-Za-z0-9._+-]*$/u;
+
+const activePromotions = [];
+let signalHandlersInstalled = false;
+
+export function assertHttpsUrl(value, label = 'source URL') {
+  if (
+    typeof value !== 'string' ||
+    value === '' ||
+    value.trim() !== value ||
+    value.includes('\\') ||
+    /[\u0000-\u001f\u007f]/u.test(value)
+  ) {
+    throw new Error(`${label} must be one canonical absolute HTTPS URL`);
+  }
+  let parsed;
+  try {
+    parsed = new URL(value);
+  } catch (error) {
+    throw new Error(
+      `${label} must be an absolute HTTPS URL: ${error instanceof Error ? error.message : error}`,
+    );
+  }
+  if (parsed.protocol !== 'https:') {
+    throw new Error(`${label} must use HTTPS, got ${parsed.protocol || ''}`);
+  }
+  if (parsed.username !== '' || parsed.password !== '') {
+    throw new Error(`${label} must not contain embedded credentials`);
+  }
+  if (parsed.hash !== '') {
+    throw new Error(`${label} must not contain a URL fragment`);
+  }
+  if (parsed.hostname === '') {
+    throw new Error(`${label} must contain a hostname`);
+  }
+  return parsed;
+}
+
+export function canonicalGnuArchiveFallbackUrl(pinnedUrl) {
+  let parsed;
+  try {
+    parsed = assertHttpsUrl(pinnedUrl);
+  } catch {
+    return undefined;
+  }
+  if (parsed.origin !== GNU_MIRROR_ORIGIN || parsed.search !== '' || parsed.href !== pinnedUrl) {
+    return undefined;
+  }
+  const [, project, file, ...extra] = parsed.pathname.split('/');
+  if (
+    extra.length !== 0 ||
+    !GNU_ARCHIVE_PATH_COMPONENT.test(project ?? '') ||
+    !GNU_ARCHIVE_PATH_COMPONENT.test(file ?? '') ||
+    (!file.endsWith('.tar.gz') && !file.endsWith('.tgz'))
+  ) {
+    return undefined;
+  }
+  return `${GNU_CANONICAL_ARCHIVE_ORIGIN}/${project}/${file}`;
+}
+
+function pathExists(path) {
+  try {
+    lstatSync(path);
+    return true;
+  } catch (error) {
+    if (error?.code === 'ENOENT') {
+      return false;
+    }
+    throw error;
+  }
+}
+
+function removePath(path) {
+  rmSync(path, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
+}
+
+function installSignalHandlers() {
+  if (signalHandlersInstalled) {
+    return;
+  }
+  signalHandlersInstalled = true;
+  for (const [signal, exitCode] of [
+    ['SIGINT', 130],
+    ['SIGTERM', 143],
+    ['SIGHUP', 129],
+  ]) {
+    process.once(signal, () => {
+      restoreActivePromotions();
+      process.exit(exitCode);
+    });
+  }
+}
+
+function restorePromotion(promotion) {
+  if (pathExists(promotion.destination)) {
+    removePath(promotion.destination);
+  }
+  if (promotion.hadPrevious && pathExists(promotion.backup)) {
+    renameSync(promotion.backup, promotion.destination);
+  }
+}
+
+function restoreActivePromotions() {
+  for (const promotion of [...activePromotions].reverse()) {
+    try {
+      restorePromotion(promotion);
+    } catch (error) {
+      // There is no safe logging dependency in a signal cleanup path.  Preserve
+      // all remaining backups and continue attempting the other rollbacks.
+      process.stderr.write(`warning: could not roll back ${promotion.destination}: ${error}\n`);
+    }
+  }
+}
+
+export function promotePathTransactional(candidate, destination, { afterBackup } = {}) {
+  if (!pathExists(candidate)) {
+    throw new Error(`transaction candidate does not exist: ${candidate}`);
+  }
+  mkdirSync(dirname(destination), { recursive: true });
+  installSignalHandlers();
+  const hadPrevious = pathExists(destination);
+  const backup = join(
+    dirname(destination),
+    `.${basename(destination)}-backup-${process.pid}-${randomUUID()}`,
+  );
+  const promotion = { destination, backup, hadPrevious };
+  activePromotions.push(promotion);
+  let candidateMoved = false;
+  try {
+    if (hadPrevious) {
+      renameSync(destination, backup);
+    }
+    afterBackup?.();
+    renameSync(candidate, destination);
+    candidateMoved = true;
+    if (hadPrevious) {
+      removePath(backup);
+    }
+  } catch (error) {
+    try {
+      if (candidateMoved && pathExists(destination)) {
+        removePath(destination);
+      }
+      if (hadPrevious && pathExists(backup)) {
+        renameSync(backup, destination);
+      }
+    } catch (rollbackError) {
+      throw new AggregateError(
+        [error, rollbackError],
+        `promotion of ${candidate} to ${destination} failed and rollback was incomplete`,
+      );
+    }
+    throw error;
+  } finally {
+    const index = activePromotions.indexOf(promotion);
+    if (index >= 0) {
+      activePromotions.splice(index, 1);
+    }
+  }
+}
+
+export function sha256File(path) {
+  const hash = createHash('sha256');
+  const buffer = Buffer.allocUnsafe(1024 * 1024);
+  const descriptor = openSync(path, 'r');
+  try {
+    while (true) {
+      const count = readSync(descriptor, buffer, 0, buffer.length, null);
+      if (count === 0) {
+        break;
+      }
+      hash.update(buffer.subarray(0, count));
+    }
+  } finally {
+    closeSync(descriptor);
+  }
+  return hash.digest('hex');
+}
+
+function isRealDirectory(path) {
+  try {
+    const metadata = lstatSync(path);
+    return metadata.isDirectory() && !metadata.isSymbolicLink();
+  } catch {
+    return false;
+  }
+}
+
+function isRegularFile(path, maximumBytes = Number.POSITIVE_INFINITY) {
+  try {
+    const metadata = lstatSync(path);
+    return metadata.isFile() && !metadata.isSymbolicLink() && metadata.size <= maximumBytes;
+  } catch {
+    return false;
+  }
+}
+
+function hasGitMetadata(path) {
+  return pathExists(join(path, '.git'));
+}
+
+function assertSupportedGitMetadata(source, path) {
+  if (hasGitMetadata(path) && !isRealDirectory(join(path, '.git'))) {
+    throw new Error(
+      `source checkout ${path} (${source.name}) has unsupported non-directory .git metadata; preserve it before fetching pins`,
+    );
+  }
+}
+
+function validateSourceName(name) {
+  if (
+    typeof name !== 'string' ||
+    name === '' ||
+    name.includes('..') ||
+    name.includes('/') ||
+    name.includes('\\') ||
+    !/^[A-Za-z0-9._-]+$/u.test(name)
+  ) {
+    throw new Error(`unsafe source name ${JSON.stringify(name)}`);
+  }
+}
+
+function validateBranchName(branch) {
+  if (
+    typeof branch !== 'string' ||
+    branch === '' ||
+    branch.startsWith('-') ||
+    branch.startsWith('/') ||
+    branch.endsWith('/') ||
+    branch.endsWith('.') ||
+    branch.includes('..') ||
+    branch.includes('@{') ||
+    /[\u0000-\u0020\u007f~^:?*[\\]/u.test(branch) ||
+    branch.split('/').some((part) => part === '' || part.endsWith('.lock'))
+  ) {
+    throw new Error(`unsafe Git branch name ${JSON.stringify(branch)}`);
+  }
+}
+
+export function validateSource(source) {
+  validateSourceName(source.name);
+  const parsedUrl = assertHttpsUrl(source.url, `source '${source.name}' URL`);
+  const parsedMirrorUrl =
+    source.mirrorUrl === undefined
+      ? undefined
+      : assertHttpsUrl(source.mirrorUrl, `source '${source.name}' mirror URL`);
+  validateBranchName(source.branch);
+  if (parsedMirrorUrl?.href === parsedUrl.href) {
+    throw new Error(`source '${source.name}' mirror URL must differ from its primary URL`);
+  }
+  if (source.kind === 'git') {
+    if (source.sha256 !== undefined || source.stripPrefix !== undefined)
+      throw new Error(`git source '${source.name}' must not set sha256 or strip-prefix`);
+    if (!/^[0-9a-f]{40}$/u.test(source.commit)) {
+      throw new Error(`git source '${source.name}' must pin an exact lowercase 40-hex commit`);
+    }
+  } else if (source.kind === 'archive') {
+    if (!/^[0-9a-f]{64}$/u.test(source.sha256 ?? '') || source.commit !== source.sha256) {
+      throw new Error(
+        `archive source '${source.name}' must pin one lowercase SHA-256 as sha256 and commit`,
+      );
+    }
+    if (
+      typeof source.stripPrefix !== 'string' ||
+      (source.stripPrefix !== '.' &&
+        (!/^[A-Za-z0-9][A-Za-z0-9._+-]*$/u.test(source.stripPrefix) ||
+          source.stripPrefix.includes('..')))
+    ) {
+      throw new Error(`archive source '${source.name}' has an unsafe strip prefix`);
+    }
+    if (
+      !parsedUrl.pathname.endsWith('.tar.gz') &&
+      !parsedUrl.pathname.endsWith('.tgz') &&
+      !parsedUrl.pathname.endsWith('.zip')
+    ) {
+      throw new Error(
+        `archive source '${source.name}' URL must identify a .tar.gz, .tgz, or .zip file`,
+      );
+    }
+    if (source.stripPrefix === '.' && !parsedUrl.pathname.endsWith('.zip')) {
+      throw new Error(
+        `archive source '${source.name}' may use a rootless strip prefix only for ZIP releases`,
+      );
+    }
+  } else {
+    throw new Error(`source '${source.name}' has unsupported kind '${source.kind}'`);
+  }
+}
+
+function archiveStampMetadata(source) {
+  return `safety=${ARCHIVE_SAFETY_VERSION}\nname=${source.name}\nkind=archive\nurl=${source.url}\nbranch=${source.branch}\ncommit=${source.commit}\nsha256=${source.sha256}\nstrip-prefix=${source.stripPrefix}\n`;
+}
+
+function archiveStamp(source, treeSha256) {
+  return `${archiveStampMetadata(source)}tree-sha256=${treeSha256}\n`;
+}
+
+function hasUsableDirectoryIdentity(metadata) {
+  // Path strings cannot prove identity: Windows may spell one directory with
+  // either an 8.3 alias or its long name.  Require both the volume and file ID
+  // so filesystems without a complete stable identity fail closed.
+  return (
+    metadata.isDirectory() &&
+    typeof metadata.dev === 'bigint' &&
+    metadata.dev > 0n &&
+    typeof metadata.ino === 'bigint' &&
+    metadata.ino > 0n
+  );
+}
+
+export function sameDirectoryIdentity(left, right, { stat = statSync } = {}) {
+  const leftMetadata = stat(left, { bigint: true });
+  const rightMetadata = stat(right, { bigint: true });
+  if (!hasUsableDirectoryIdentity(leftMetadata) || !hasUsableDirectoryIdentity(rightMetadata)) {
+    return false;
+  }
+
+  return leftMetadata.dev === rightMetadata.dev && leftMetadata.ino === rightMetadata.ino;
+}
+
+function assertSafeCheckoutTree(root) {
+  const realRoot = realpathSync(root);
+  const pending = [root];
+  while (pending.length > 0) {
+    const directory = pending.pop();
+    for (const entry of readdirSync(directory, { withFileTypes: true })) {
+      if (directory === root && entry.name === '.git') {
+        continue;
+      }
+      const path = join(directory, entry.name);
+      const metadata = lstatSync(path);
+      if (metadata.isDirectory()) {
+        pending.push(path);
+        continue;
+      }
+      if (metadata.isFile()) {
+        continue;
+      }
+      if (!metadata.isSymbolicLink()) {
+        throw new Error(`Git source checkout contains unsupported filesystem object ${path}`);
+      }
+      const target = readlinkSync(path);
+      if (isAbsolute(target)) {
+        throw new Error(`Git source checkout contains absolute symlink ${path} -> ${target}`);
+      }
+      const resolvedTarget = resolve(dirname(path), target);
+      const relativeTarget = relative(root, resolvedTarget);
+      if (
+        relativeTarget === '..' ||
+        relativeTarget.startsWith(`..${sep}`) ||
+        isAbsolute(relativeTarget)
+      ) {
+        throw new Error(`Git source checkout contains escaping symlink ${path} -> ${target}`);
+      }
+      if (!pathExists(resolvedTarget)) {
+        // Source repositories may intentionally track dangling relative links
+        // as filesystem fixtures. They are safe only when both the lexical
+        // destination and its deepest existing ancestor remain in the staged
+        // checkout. The ancestor check catches paths that cross an existing
+        // symlink before reaching the missing leaf.
+        let existingAncestor = dirname(resolvedTarget);
+        while (existingAncestor !== root && !pathExists(existingAncestor)) {
+          existingAncestor = dirname(existingAncestor);
+        }
+        let realAncestor;
+        try {
+          realAncestor = realpathSync(existingAncestor);
+        } catch (error) {
+          throw new Error(
+            `Git source checkout contains unresolved dangling symlink ${path} -> ${target}: ${error}`,
+          );
+        }
+        const relativeRealAncestor = relative(realRoot, realAncestor);
+        if (
+          relativeRealAncestor === '..' ||
+          relativeRealAncestor.startsWith(`..${sep}`) ||
+          isAbsolute(relativeRealAncestor)
+        ) {
+          throw new Error(
+            `Git source checkout contains transitively escaping dangling symlink ${path} -> ${target}`,
+          );
+        }
+        continue;
+      }
+      let realTarget;
+      try {
+        realTarget = realpathSync(resolvedTarget);
+      } catch (error) {
+        throw new Error(
+          `Git source checkout contains unresolved symlink ${path} -> ${target}: ${error}`,
+        );
+      }
+      const relativeRealTarget = relative(realRoot, realTarget);
+      if (
+        relativeRealTarget === '..' ||
+        relativeRealTarget.startsWith(`..${sep}`) ||
+        isAbsolute(relativeRealTarget)
+      ) {
+        throw new Error(
+          `Git source checkout contains transitively escaping symlink ${path} -> ${target}`,
+        );
+      }
+    }
+  }
+}
+
+function updateDigestField(hash, value) {
+  hash.update(String(value), 'utf8');
+  hash.update(Buffer.from([0]));
+}
+
+export function archiveTreeDigest(root) {
+  if (!isRealDirectory(root)) {
+    throw new Error(`archive source tree is not a real directory: ${root}`);
+  }
+  const entries = [];
+  const pending = [root];
+  let totalBytes = 0;
+  while (pending.length > 0) {
+    const directory = pending.pop();
+    const children = readdirSync(directory, { withFileTypes: true }).sort((left, right) =>
+      Buffer.compare(Buffer.from(left.name), Buffer.from(right.name)),
+    );
+    for (const child of children) {
+      if (directory === root && child.name === '.oliphaunt-source-pin') {
+        continue;
+      }
+      const path = join(directory, child.name);
+      const relativePath = relative(root, path).split(sep).join('/');
+      const metadata = lstatSync(path);
+      let type;
+      let detail = '';
+      if (metadata.isDirectory()) {
+        type = 'directory';
+        pending.push(path);
+      } else if (metadata.isFile()) {
+        type = 'file';
+        totalBytes += metadata.size;
+        if (totalBytes > CHECKOUT_MAX_BYTES) {
+          throw new Error(`archive source tree ${root} exceeds ${CHECKOUT_MAX_BYTES} bytes`);
+        }
+        detail = `${metadata.size}:${sha256File(path)}`;
+      } else if (metadata.isSymbolicLink()) {
+        type = 'symlink';
+        detail = readlinkSync(path);
+      } else {
+        throw new Error(`archive source tree contains unsupported filesystem object ${path}`);
+      }
+      entries.push({ relativePath, type, detail });
+      if (entries.length > CHECKOUT_MAX_ENTRIES) {
+        throw new Error(`archive source tree ${root} exceeds ${CHECKOUT_MAX_ENTRIES} entries`);
+      }
+    }
+  }
+  entries.sort((left, right) =>
+    Buffer.compare(Buffer.from(left.relativePath), Buffer.from(right.relativePath)),
+  );
+  const hash = createHash('sha256');
+  for (const entry of entries) {
+    updateDigestField(hash, entry.type);
+    updateDigestField(hash, entry.relativePath);
+    updateDigestField(hash, entry.detail);
+  }
+  return hash.digest('hex');
+}
+
+export function parseArchiveStamp(path) {
+  if (!isRegularFile(path, 64 * 1024)) {
+    throw new Error(`archive source marker is missing, non-regular, or oversized: ${path}`);
+  }
+  const fields = new Map();
+  const text = readFileSync(path, 'utf8');
+  for (const line of text.split('\n')) {
+    if (line === '') {
+      continue;
+    }
+    const separator = line.indexOf('=');
+    if (separator <= 0) {
+      throw new Error(`archive source marker ${path} contains a malformed line`);
+    }
+    const key = line.slice(0, separator);
+    if (fields.has(key)) {
+      throw new Error(`archive source marker ${path} repeats ${key}`);
+    }
+    fields.set(key, line.slice(separator + 1));
+  }
+  const required = [
+    'safety',
+    'name',
+    'kind',
+    'url',
+    'branch',
+    'commit',
+    'sha256',
+    'strip-prefix',
+    'tree-sha256',
+  ];
+  if (fields.size !== required.length || required.some((key) => !fields.has(key))) {
+    throw new Error(`archive source marker ${path} does not carry complete integrity state`);
+  }
+  if (fields.get('safety') !== ARCHIVE_SAFETY_VERSION) {
+    throw new Error(
+      `archive source marker ${path} predates ${ARCHIVE_SAFETY_VERSION}; move or remove the checkout before rematerializing it`,
+    );
+  }
+  if (!/^[0-9a-f]{64}$/u.test(fields.get('tree-sha256'))) {
+    throw new Error(`archive source marker ${path} has an invalid tree digest`);
+  }
+  return fields;
+}
+
+function assertGitIdentity(source, path, snapshot) {
+  const worktree = readGitSnapshot(snapshot, 'worktree');
+  const gitDirectory = readGitSnapshot(snapshot, 'git-directory');
+  if (
+    !sameDirectoryIdentity(worktree, path) ||
+    !sameDirectoryIdentity(gitDirectory, join(path, '.git'))
+  ) {
+    throw new Error(
+      `source checkout ${path} (${source.name}) has Git metadata outside its durable directory`,
+    );
+  }
+  if (isRegularFile(join(path, '.git', 'objects', 'info', 'alternates'))) {
+    throw new Error(`source checkout ${path} (${source.name}) uses external Git object storage`);
+  }
+}
+
+export function inspectDurablePath(source, path, snapshot) {
+  if (!pathExists(path)) {
+    return { kind: 'missing', matchesArchivePin: false };
+  }
+  if (!isRealDirectory(path)) {
+    throw new Error(
+      `durable source path ${path} (${source.name}) is not a real directory; preserve it before fetching pins`,
+    );
+  }
+  assertSupportedGitMetadata(source, path);
+  if (hasGitMetadata(path)) {
+    assertGitIdentity(source, path, snapshot);
+    if (readGitSnapshot(snapshot, 'status') !== '') {
+      throw new Error(
+        `source checkout ${path} (${source.name}) has uncommitted changes; preserve them before fetching pins`,
+      );
+    }
+    return { kind: 'git', matchesArchivePin: false };
+  }
+
+  const markerPath = join(path, '.oliphaunt-source-pin');
+  if (!pathExists(markerPath)) {
+    throw new Error(
+      `durable source path ${path} (${source.name}) is unmanaged; move or remove it before materializing a pinned source`,
+    );
+  }
+  let fields;
+  try {
+    fields = parseArchiveStamp(markerPath);
+  } catch (error) {
+    throw new Error(
+      `durable archive source ${path} (${source.name}) has unverifiable integrity state; preserve it before fetching pins: ${error}`,
+    );
+  }
+  const actualTreeSha256 = archiveTreeDigest(path);
+  const recordedTreeSha256 = fields.get('tree-sha256');
+  if (actualTreeSha256 !== recordedTreeSha256) {
+    throw new Error(
+      `durable archive source ${path} (${source.name}) was modified: expected tree ${recordedTreeSha256}, got ${actualTreeSha256}; preserve it before fetching pins`,
+    );
+  }
+  const matchesArchivePin =
+    source.kind === 'archive' &&
+    fields.get('name') === source.name &&
+    fields.get('kind') === 'archive' &&
+    fields.get('url') === source.url &&
+    fields.get('branch') === source.branch &&
+    fields.get('commit') === source.commit &&
+    fields.get('sha256') === source.sha256 &&
+    fields.get('strip-prefix') === source.stripPrefix;
+  return { kind: 'archive', matchesArchivePin };
+}
+
+function readGitSnapshot(snapshot, field) {
+  const file = join(snapshot, field);
+  if (!isRegularFile(file, 16 * 1024 * 1024))
+    throw new Error('missing or oversized Git snapshot: ' + file);
+  return new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(file)).trim();
+}
+
+export function sourceCheckoutIsReady(source, path, snapshot) {
+  const durable = inspectDurablePath(source, path, snapshot);
+  if (source.kind === 'archive') return durable.matchesArchivePin;
+  return (
+    durable.kind === 'git' &&
+    readGitSnapshot(snapshot, 'head') === source.commit &&
+    readGitSnapshot(snapshot, 'branch') === source.branch &&
+    readGitSnapshot(snapshot, 'origin') === source.url &&
+    readGitSnapshot(snapshot, 'autocrlf') === 'false' &&
+    readGitSnapshot(snapshot, 'eol') === 'lf'
+  );
+}
+
+export function validateCachedArchive(archive, source) {
+  if (!isRegularFile(archive, DOWNLOAD_MAX_BYTES))
+    throw new Error('archive is missing, non-regular, or oversized: ' + archive);
+  const actual = sha256File(archive);
+  if (actual !== source.sha256)
+    throw new Error(`${source.name} archive sha256: expected ${source.sha256}, got ${actual}`);
+  sourceArchiveEntries(archive, source.stripPrefix);
+}
+
+export function prepareSourceArchive(source, archive, candidate) {
+  validateCachedArchive(archive, source);
+  extractSourceArchive(archive, source.stripPrefix, candidate);
+  const treeSha256 = archiveTreeDigest(candidate);
+  writeFileSync(join(candidate, '.oliphaunt-source-pin'), archiveStamp(source, treeSha256), {
+    encoding: 'utf8',
+    mode: 0o644,
+    flag: 'wx',
+  });
+}
+
+if (import.meta.main) {
+  try {
+    const [operation, sourceFile, path, snapshot] = process.argv.slice(2);
+    if (operation === 'promote') {
+      promotePathTransactional(sourceFile, path);
+    } else {
+      const source = JSON.parse(readFileSync(sourceFile, 'utf8'));
+      validateSource(source);
+      switch (operation) {
+        case 'fields': {
+          const suffix = new URL(source.url).pathname.endsWith('.zip') ? '.zip' : '.tar.gz';
+          process.stdout.write(
+            [
+              source.name,
+              source.kind,
+              source.url,
+              source.mirrorUrl ?? '',
+              source.branch,
+              source.commit,
+              source.name + '-' + source.sha256 + suffix,
+              canonicalGnuArchiveFallbackUrl(source.url) ?? '',
+            ].join('\0') + '\0',
+          );
+          break;
+        }
+        case 'git-identity':
+          assertGitIdentity(source, path, snapshot);
+          break;
+        case 'inspect':
+          console.log(sourceCheckoutIsReady(source, path, snapshot) ? 'ready' : 'stale');
+          break;
+        case 'git-candidate':
+          if (!sourceCheckoutIsReady(source, path, snapshot))
+            throw new Error(
+              'staged Git checkout did not preserve its exact pin, branch, and HTTPS origin',
+            );
+          assertSafeCheckoutTree(path);
+          break;
+        case 'archive-valid':
+          try {
+            validateCachedArchive(path, source);
+            console.log('valid');
+          } catch (error) {
+            console.error(error.message);
+            console.log('invalid');
+          }
+          break;
+        case 'unpack':
+          prepareSourceArchive(source, path, snapshot);
+          break;
+        default:
+          throw new Error('unknown source data operation: ' + operation);
+      }
+    }
+  } catch (error) {
+    console.error(error.message);
+    process.exitCode = 1;
+  }
+}
diff --git a/src/third-party/tools/source-fetch-core.test.mts b/src/third-party/tools/source-fetch-core.test.mts
new file mode 100644
index 000000000..d5682199b
--- /dev/null
+++ b/src/third-party/tools/source-fetch-core.test.mts
@@ -0,0 +1,285 @@
+import assert from 'node:assert/strict';
+import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { test } from 'node:test';
+import { tarArchive } from '../../../tools/packaging/testdata/tar-fixture.mts';
+import { zipArchive } from '../../../tools/packaging/testdata/zip-fixture.mts';
+
+import {
+  assertHttpsUrl,
+  canonicalGnuArchiveFallbackUrl,
+  promotePathTransactional,
+  sameDirectoryIdentity,
+  sha256File,
+  validateSource,
+} from './source-fetch-core.mts';
+
+function makeRoot(label) {
+  return mkdtempSync(path.join(os.tmpdir(), `oliphaunt-${label}-`));
+}
+
+function directoryMetadata(dev, ino, isDirectory = true) {
+  return { dev, ino, isDirectory: () => isDirectory };
+}
+
+const [mode, root] = process.argv.slice(2);
+if (mode) {
+  if (mode === 'prepare') {
+    createTarFixtures(root);
+    createZipFixtures(root);
+    const valid = gnuArchiveSource(path.join(root, 'valid.tar.gz'));
+    const pins = {
+      valid,
+      updated: archiveSource(path.join(root, 'updated.tar.gz'), valid.name),
+      unsafe: archiveSource(path.join(root, 'traversal.tar.gz'), valid.name),
+      zip: {
+        ...archiveSource(path.join(root, 'valid.zip')),
+        url: 'https://example.invalid/release.zip',
+        stripPrefix: '.',
+      },
+    };
+    for (const [name, pin] of Object.entries(pins))
+      writeFileSync(path.join(root, name + '.json'), JSON.stringify(pin));
+    writeArchiveManifest(path.join(root, 'source.toml'), valid);
+  } else if (mode === 'git-pin') {
+    writeFileSync(path.join(root, 'pin.json'), JSON.stringify(gitSource(process.argv[4])));
+  } else throw Error('unknown source test mode: ' + mode);
+  process.exit(0);
+}
+
+test('directory identity accepts Windows short and long aliases for the same filesystem object', () => {
+  const shortPath = String.raw`C:\Users\RUNNER~1\AppData\Local\Temp\checkout`;
+  const longPath = String.raw`C:\Users\runneradmin\AppData\Local\Temp\checkout`;
+  const metadata = new Map([
+    [shortPath, directoryMetadata(17n, 42n)],
+    [longPath, directoryMetadata(17n, 42n)],
+  ]);
+
+  assert.equal(
+    sameDirectoryIdentity(shortPath, longPath, {
+      stat: (candidate) => metadata.get(candidate),
+    }),
+    true,
+  );
+});
+
+test('directory identity rejects different filesystem objects', () => {
+  assert.equal(
+    sameDirectoryIdentity('/expected', '/external', {
+      stat: (candidate) =>
+        candidate === '/expected' ? directoryMetadata(17n, 42n) : directoryMetadata(17n, 43n),
+    }),
+    false,
+  );
+});
+
+test('directory identity rejects unavailable or partial filesystem identifiers', () => {
+  const identities = [
+    [directoryMetadata(0n, 0n), directoryMetadata(0n, 0n)],
+    [directoryMetadata(17n, 0n), directoryMetadata(17n, 0n)],
+    [directoryMetadata(0n, 42n), directoryMetadata(0n, 42n)],
+    [directoryMetadata(17n, 42n), directoryMetadata(0n, 42n)],
+  ];
+  for (const [left, right] of identities) {
+    assert.equal(
+      sameDirectoryIdentity('/left', '/right', {
+        stat: (candidate) => (candidate === '/left' ? left : right),
+      }),
+      false,
+    );
+  }
+});
+
+test('directory identity rejects a matching inode on a different device', () => {
+  assert.equal(
+    sameDirectoryIdentity('/left', '/right', {
+      stat: (candidate) =>
+        candidate === '/left' ? directoryMetadata(17n, 42n) : directoryMetadata(18n, 42n),
+    }),
+    false,
+  );
+});
+
+test('directory identity rejects non-directories and propagates stat errors', () => {
+  assert.equal(
+    sameDirectoryIdentity('/directory', '/file', {
+      stat: (candidate) =>
+        directoryMetadata(17n, candidate === '/directory' ? 42n : 43n, candidate === '/directory'),
+    }),
+    false,
+  );
+  assert.throws(
+    () =>
+      sameDirectoryIdentity('/missing', '/expected', {
+        stat: () => {
+          throw new Error('stat failed');
+        },
+      }),
+    /stat failed/u,
+  );
+});
+
+function createTarFixtures(root) {
+  const directory = { name: 'pkg/', type: '5', mode: 0o755, data: '' };
+  const file = { name: 'pkg/file.txt', data: 'trusted bytes', v7: true };
+  const link = (name, linkTarget, type = '2') => ({ name, linkTarget, type, data: '' });
+  const fixtures = {
+    valid: [
+      directory,
+      file,
+      link('pkg/link.txt', 'file.txt'),
+      link('pkg/hard.txt', 'pkg/file.txt', '1'),
+    ],
+    updated: [directory, { name: 'pkg/file.txt', data: 'updated trusted bytes' }],
+    traversal: [{ name: 'pkg/../../../escape' }],
+    absolute: [{ name: '/tmp/escape' }],
+    'outside-prefix': [{ name: 'other/file' }],
+    backslash: [{ name: 'pkg\\escape' }],
+    duplicate: [{ name: 'pkg/file' }, { name: 'pkg/file', data: 'second' }],
+    'case-collision': [{ name: 'pkg/File' }, { name: 'pkg/file', data: 'second' }],
+    'windows-ads': [{ name: 'pkg/file:stream' }],
+    'windows-device': [{ name: 'pkg/CON.txt' }],
+    'escaping-symlink': [link('pkg/link', '../../../escape')],
+    'dangling-symlink': [link('pkg/link', 'missing')],
+    'escaping-hardlink': [link('pkg/link', '../../../escape', '1')],
+    fifo: [{ name: 'pkg/fifo', type: '6', data: '' }],
+    'reserved-git': [{ name: 'pkg/.git/config' }],
+    'reserved-stamp': [{ name: 'pkg/.oliphaunt-source-pin' }],
+    'symlink-ancestor': [
+      { name: 'pkg/dir/', type: '5', mode: 0o755, data: '' },
+      link('pkg/link', 'dir'),
+      { name: 'pkg/link/child' },
+    ],
+    huge: [{ name: 'pkg/huge', size: 3 * 1024 ** 3 }],
+  };
+  for (const [name, entries] of Object.entries(fixtures))
+    writeFileSync(path.join(root, name + '.tar.gz'), tarArchive(entries));
+}
+
+function createZipFixtures(root) {
+  const ntfs = Buffer.alloc(36);
+  ntfs.writeUInt16LE(0x000a, 0);
+  ntfs.writeUInt16LE(32, 2);
+  ntfs.writeUInt16LE(1, 8);
+  ntfs.writeUInt16LE(24, 10);
+  writeFileSync(
+    path.join(root, 'valid.zip'),
+    zipArchive([
+      { name: 'LICENSE', data: 'license\n', centralExtra: ntfs, localExtra: ntfs },
+      { name: 'payload/data.bin', data: 'trusted bytes' },
+    ]),
+  );
+  writeFileSync(path.join(root, 'traversal.zip'), zipArchive([{ name: '../escape' }]));
+  writeFileSync(
+    path.join(root, 'symlink.zip'),
+    zipArchive([{ name: 'link', externalAttributes: 0o120777 << 16, data: 'payload/data.bin' }]),
+  );
+}
+
+function archiveSource(fixture, name = 'fixture') {
+  const sha256 = sha256File(fixture);
+  return {
+    name,
+    kind: 'archive',
+    url: `https://example.invalid/${name}.tar.gz`,
+    branch: 'archive-1.0',
+    commit: sha256,
+    sha256,
+    stripPrefix: 'pkg',
+  };
+}
+
+function gnuArchiveSource(fixture) {
+  return {
+    ...archiveSource(fixture, 'libiconv'),
+    url: 'https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz',
+  };
+}
+
+function writeArchiveManifest(manifestPath, source) {
+  writeFileSync(
+    manifestPath,
+    `name = "${source.name}"\nkind = "archive"\nurl = "${source.url}"\nbranch = "${source.branch}"\ncommit = "${source.commit}"\nsha256 = "${source.sha256}"\nstrip_prefix = "${source.stripPrefix}"\n`,
+  );
+}
+
+test('transactional promotion restores the prior destination on a normal failure', () => {
+  const root = makeRoot('source-promotion');
+  try {
+    // Git Bash passes forward slashes to Bun even when node:path.sep is '\\'.
+    const destination = path.join(root, 'live').replaceAll('\\', '/');
+    const candidate = path.join(root, 'candidate');
+    mkdirSync(destination);
+    mkdirSync(candidate);
+    writeFileSync(path.join(destination, 'value'), 'old');
+    writeFileSync(path.join(candidate, 'value'), 'new');
+    assert.throws(
+      () =>
+        promotePathTransactional(candidate, destination, {
+          afterBackup: () => {
+            throw new Error('fault');
+          },
+        }),
+      /fault/u,
+    );
+    assert.equal(readFileSync(path.join(destination, 'value'), 'utf8'), 'old');
+    assert.equal(readFileSync(path.join(candidate, 'value'), 'utf8'), 'new');
+    assert.deepEqual(readdirSync(root).sort(), ['candidate', 'live']);
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
+
+function gitSource(commit) {
+  return {
+    name: 'source',
+    kind: 'git',
+    url: 'https://primary.example.invalid/source.git',
+    mirrorUrl: 'https://mirror.example.invalid/source.git',
+    branch: 'pinned',
+    commit,
+  };
+}
+
+test('source pins reject unsafe URLs, branches, names, and unpinned archives', () => {
+  const source = gitSource('1'.repeat(40));
+  for (const url of [
+    'http://example.test/source',
+    'https://user:secret@example.test/source',
+    'https://example.test\\source',
+    'https://example.test/source#fragment',
+  ]) {
+    assert.throws(() => assertHttpsUrl(url));
+    assert.throws(() => validateSource({ ...source, mirrorUrl: url }));
+  }
+  assert.throws(() => validateSource({ ...source, mirrorUrl: source.url }));
+  for (const branch of ['--config', 'a..b', 'a.lock', 'a\nb', '/a'])
+    assert.throws(() => validateSource({ ...source, branch }));
+  for (const name of ['../outside', '/absolute', 'bad\\name'])
+    assert.throws(() => validateSource({ ...source, name }));
+  assert.throws(() =>
+    validateSource({ ...source, kind: 'archive', sha256: '1'.repeat(64), stripPrefix: 'pkg' }),
+  );
+  const archive = {
+    ...source,
+    kind: 'archive',
+    url: 'https://primary.example.invalid/source.tar.gz',
+    mirrorUrl: 'https://mirror.example.invalid/source.tar.gz',
+    commit: '1'.repeat(64),
+    sha256: '1'.repeat(64),
+    stripPrefix: 'pkg',
+  };
+  assert.doesNotThrow(() => validateSource(archive));
+  assert.throws(() => validateSource({ ...archive, mirrorUrl: archive.url }));
+  for (const url of [
+    'https://example.invalid/libiconv/libiconv-1.19.tar.gz',
+    'https://ftpmirror.gnu.org/libiconv/nested/libiconv-1.19.tar.gz',
+    'https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz?mutable=1',
+    'https://ftpmirror.gnu.org/libiconv/%6cibiconv-1.19.tar.gz',
+    'https://ftpmirror.gnu.org/libiconv/../libiconv-1.19.tar.gz',
+    'https://ftpmirror.gnu.org/libiconv/libiconv-1.19.zip',
+  ]) {
+    assert.equal(canonicalGnuArchiveFallbackUrl(url), undefined);
+  }
+});
diff --git a/src/third-party/tools/source-fetch-core.test.sh b/src/third-party/tools/source-fetch-core.test.sh
new file mode 100644
index 000000000..963eadf92
--- /dev/null
+++ b/src/third-party/tools/source-fetch-core.test.sh
@@ -0,0 +1,257 @@
+#!/usr/bin/env bash
+set -euo pipefail
+tools="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+root_dir="$(cd "$tools/../../.." && pwd)"
+scratch="$(mktemp -d)"
+trap 'rm -rf "$scratch"' EXIT
+test_data="$tools/source-fetch-core.test.mts"
+archive_tool="$tools/source-archive.mts"
+export FETCH_TEST_GIT="$(command -v git)"
+export FETCH_TEST_SLEEP="$(command -v sleep)"
+base_path="$PATH"
+for scope in icu native-runtime wasix-runtime wasix-postmaster-runtime production-all; do
+  plan="$scratch/plan-$scope"
+  mkdir "$plan"
+  bun "$tools/fetch-sources.mts" plan "$plan" "$scope" --force
+  [[ -f "$plan/icu-data.json" ]]
+  if [[ "$scope" != icu ]]; then [[ -f "$plan/icu.json" ]]; fi
+  if [[ "$scope" == native-runtime ]]; then
+    [[ ! -e "$plan/postgis.json" && ! -e "$plan/libiconv.json" ]]
+  fi
+done
+bun test "$test_data"
+mkdir "$scratch/fixtures" "$scratch/bin"
+bun "$test_data" prepare "$scratch/fixtures"
+for name in git curl sleep; do
+  cp "$tools/source-fetch-transport.test.sh" "$scratch/bin/$name"
+  chmod +x "$scratch/bin/$name"
+done
+fail_command() {
+  local expected="$1"
+  shift
+  if "$@" > "$scratch/failure.log" 2>&1; then
+    printf 'unexpected success: %s\n' "$*" >&2
+    exit 1
+  fi
+  grep -Eq "$expected" "$scratch/failure.log" || { cat "$scratch/failure.log" >&2; exit 1; }
+}
+fixtures="$scratch/fixtures"
+bun "$archive_tool" validate "$fixtures/valid.tar.gz" pkg
+bun "$archive_tool" extract "$fixtures/valid.tar.gz" pkg "$scratch/tar-out"
+printf 'trusted bytes' > "$scratch/trusted"
+for file in file.txt link.txt hard.txt; do cmp "$scratch/trusted" "$scratch/tar-out/$file"; done
+[[ ! -e "$scratch/tar-out/pkg" ]]
+bun "$archive_tool" validate "$fixtures/valid.zip" .
+bun "$archive_tool" extract "$fixtures/valid.zip" . "$scratch/zip-out"
+cmp "$scratch/trusted" "$scratch/zip-out/payload/data.bin"
+for archive in "$fixtures"/*.tar.gz "$fixtures"/*.zip; do
+  case "${archive##*/}" in valid.*|updated.tar.gz) continue;; esac
+  prefix=pkg
+  [[ "$archive" != *.zip ]] || prefix=.
+  for operation in validate extract; do
+    destination="$scratch/invalid-${archive##*/}"
+    arguments=("$operation" "$archive" "$prefix")
+    [[ "$operation" != extract ]] || arguments+=("$destination")
+    if bun "$archive_tool" "${arguments[@]}" > "$scratch/failure.log" 2>&1; then
+      printf 'unsafe archive accepted: %s %s\n' "$operation" "$archive" >&2
+      exit 1
+    fi
+    ! grep -q 'usage: source-archive' "$scratch/failure.log"
+    [[ ! -e "$destination" ]]
+  done
+done
+
+# Only transport and retry delays are substituted. The source owner still runs
+# its real Git checkout, archive verification, extraction and atomic promotion.
+fetch() {
+  local root="$1" pin="$2" mode="${3:-fetch}"
+  PATH="$scratch/bin:$base_path" FETCH_TEST_ROOT="$root" FETCH_TEST_UPSTREAM="$root/upstream" \
+    bash -c 'source "$1"; fetch_source "$2" "$3" "$4" "$5"' \
+    source-fetch-test "$tools/fetch-sources.sh" "$pin" "$root/checkouts" "$root/archives" "$mode"
+}
+# Hold the first transport open until the second fetch is actually waiting on
+# the shared checkout. Both must succeed with one verified download/promotion.
+wait_for_file() {
+  local attempt
+  for attempt in {1..100}; do
+    [[ ! -e "$1" ]] || return 0
+    "$FETCH_TEST_SLEEP" 0.1
+  done
+  echo "timed out waiting for test barrier: $1" >&2; return 1
+}
+root="$scratch/concurrent"
+mkdir -p "$root"
+FETCH_TEST_BARRIER=1 FETCH_TEST_ARCHIVE="$fixtures/valid.tar.gz" fetch "$root" "$fixtures/valid.json" > "$root/first.log" 2>&1 &
+first_fetch=$!
+wait_for_file "$root/downloading"
+FETCH_TEST_ARCHIVE="$fixtures/valid.tar.gz" fetch "$root" "$fixtures/valid.json" > "$root/second.log" 2>&1 &
+second_fetch=$!
+wait_for_file "$root/lock-waiting"
+touch "$root/release-download"
+wait "$first_fetch" || { cat "$root/first.log" >&2; exit 1; }
+wait "$second_fetch" || { cat "$root/second.log" >&2; exit 1; }
+[[ "$(wc -l < "$root/requests")" -eq 1 ]]
+[[ "$(ls -A "$root/checkouts")" == libiconv ]]
+cmp "$scratch/trusted" "$root/checkouts/libiconv/file.txt"
+root="$scratch/archive"
+mkdir -p "$root/archives"
+sha="$(jq -r .sha256 "$fixtures/valid.json")"
+cache="$root/archives/libiconv-$sha.tar.gz"
+checkout="$root/checkouts/libiconv"
+printf 'prior cache' > "$cache"
+export FETCH_TEST_FAULT=all FETCH_TEST_ARCHIVE=''
+fail_command 'transport fault:' fetch "$root" "$fixtures/valid.json"
+grep -q 'https://ftp.gnu.org' "$scratch/failure.log"
+grep -q 'https://ftpmirror.gnu.org' "$scratch/failure.log"
+[[ "$(cat "$cache")" == 'prior cache' && ! -e "$checkout" ]]
+export FETCH_TEST_FAULT=primary FETCH_TEST_ARCHIVE="$fixtures/updated.tar.gz"
+fail_command 'archive sha256: expected' fetch "$root" "$fixtures/valid.json"
+[[ "$(cat "$cache")" == 'prior cache' ]]
+: > "$root/requests"
+export FETCH_TEST_ARCHIVE="$fixtures/valid.tar.gz"
+RUNNER_OS=Windows fetch "$root" "$fixtures/valid.json"
+printf '%s\n' 'https://ftp.gnu.org/gnu/libiconv/libiconv-1.19.tar.gz' 'https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz' > "$scratch/expected"
+cmp "$scratch/expected" "$root/requests"
+cmp "$cache" "$fixtures/valid.tar.gz"
+cmp "$scratch/trusted" "$checkout/file.txt"
+grep -q 'url=https://ftpmirror.gnu.org/' "$checkout/.oliphaunt-source-pin"
+FETCH_TEST_FAULT=all fetch "$root" "$fixtures/valid.json" verify
+bun "$root_dir/src/runtimes/liboliphaunt-wasix/tools/verify-source-tree.mts" --checkout "$checkout" --manifest "$fixtures/source.toml"
+export FETCH_TEST_FAULT='' FETCH_TEST_ARCHIVE="$fixtures/traversal.tar.gz"
+fail_command 'traversal|unsafe|escape' fetch "$root" "$fixtures/unsafe.json"
+cmp "$scratch/trusted" "$checkout/file.txt"
+export FETCH_TEST_ARCHIVE="$fixtures/updated.tar.gz"
+fetch "$root" "$fixtures/updated.json"
+[[ "$(cat "$checkout/file.txt")" == 'updated trusted bytes' ]]
+printf 'local edit' > "$checkout/file.txt"
+fail_command 'was modified' fetch "$root" "$fixtures/updated.json" verify
+FETCH_TEST_ARCHIVE="$fixtures/valid.tar.gz" fail_command 'was modified' fetch "$root" "$fixtures/valid.json"
+[[ "$(cat "$checkout/file.txt")" == 'local edit' ]]
+[[ "$(ls -A "$root/checkouts")" == libiconv ]]
+
+root="$scratch/archive-mirror"
+mkdir "$root"
+jq '.mirrorUrl = "https://mirror.example.invalid/libiconv.tar.gz"' "$fixtures/valid.json" > "$root/pin.json"
+FETCH_TEST_FAULT=gnu FETCH_TEST_ARCHIVE="$fixtures/updated.tar.gz" \
+  fail_command 'archive sha256: expected' fetch "$root" "$root/pin.json"
+[[ ! -e "$root/checkouts/libiconv" ]]
+: > "$root/requests"
+FETCH_TEST_FAULT=gnu FETCH_TEST_ARCHIVE="$fixtures/valid.tar.gz" fetch "$root" "$root/pin.json"
+printf '%s\n' 'https://ftp.gnu.org/gnu/libiconv/libiconv-1.19.tar.gz' \
+  'https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz' \
+  'https://mirror.example.invalid/libiconv.tar.gz' > "$scratch/expected"
+cmp "$scratch/expected" "$root/requests"
+cmp "$scratch/trusted" "$root/checkouts/libiconv/file.txt"
+
+root="$scratch/zip"
+checkout="$root/checkouts/fixture"
+mkdir -p "$checkout"
+printf keep > "$checkout/local"
+export FETCH_TEST_ARCHIVE="$fixtures/valid.zip"
+fail_command 'is unmanaged' fetch "$root" "$fixtures/zip.json"
+[[ ! -s "$root/requests" && "$(cat "$checkout/local")" == keep ]]
+rm -r "$checkout"
+fetch "$root" "$fixtures/zip.json"
+cmp "$scratch/trusted" "$checkout/payload/data.bin"
+fetch "$root" "$fixtures/zip.json" verify
+
+init_repo() {
+  local repository="$1" contents="$2" branch="${3:-old}"
+  mkdir -p "$repository"
+  git -C "$repository" init --quiet --initial-branch="$branch"
+  git -C "$repository" config user.name 'Source Fetch Test'
+  git -C "$repository" config user.email source-fetch@example.invalid
+  printf '%s' "$contents" > "$repository/source.txt"
+  git -C "$repository" add source.txt
+  git -C "$repository" commit --quiet -m 'test source'
+}
+root="$scratch/git"
+init_repo "$root/upstream" 'new bytes' upstream
+commit="$(git -C "$root/upstream" rev-parse HEAD)"
+bun "$test_data" git-pin "$root" "$commit"
+checkout="$root/checkouts/source"
+init_repo "$checkout" prior
+prior="$(git -C "$checkout" rev-parse HEAD)"
+FETCH_TEST_FAULT=all fail_command 'transport fault' fetch "$root" "$root/pin.json"
+primary=https://primary.example.invalid/source.git
+mirror=https://mirror.example.invalid/source.git
+printf '%s\n' "$primary" "$mirror" "$primary" "$mirror" "$primary" > "$scratch/expected"
+cmp "$scratch/expected" "$root/requests"
+printf '%s\n' 5 10 > "$scratch/expected"
+cmp "$scratch/expected" "$root/sleeps"
+[[ "$(git -C "$checkout" rev-parse HEAD)" == "$prior" ]]
+jq '.commit = "1111111111111111111111111111111111111111"' "$root/pin.json" > "$root/wrong.json"
+FETCH_TEST_FAULT=primary FETCH_TEST_COMMIT="$commit" fail_command 'expected exact commit' fetch "$root" "$root/wrong.json"
+[[ "$(git -C "$checkout" rev-parse HEAD)" == "$prior" ]]
+: > "$root/requests"
+: > "$root/sleeps"
+FETCH_TEST_FAULT=primary fetch "$root" "$root/pin.json"
+printf '%s\n' "$primary" "$mirror" > "$scratch/expected"
+cmp "$scratch/expected" "$root/requests"
+[[ ! -s "$root/sleeps" ]]
+[[ "$(git -C "$checkout" rev-parse HEAD)" == "$commit" ]]
+[[ "$(git -C "$checkout" remote get-url origin)" == "$primary" ]]
+[[ "$(git -C "$checkout" branch --show-current)" == pinned ]]
+: > "$root/requests"
+FETCH_TEST_FAULT=all fetch "$root" "$root/pin.json" verify
+FETCH_TEST_FAULT=all fetch "$root" "$root/pin.json"
+[[ ! -s "$root/requests" ]]
+printf 'local edit' > "$checkout/source.txt"
+fail_command 'uncommitted changes' fetch "$root" "$root/pin.json"
+[[ "$(cat "$checkout/source.txt")" == 'local edit' ]]
+[[ "$(ls -A "$root/checkouts")" == source ]]
+
+root="$scratch/git-lf"
+init_repo "$root/upstream" $'first line\nsecond line\n' upstream
+printf '* text=auto\n' > "$root/upstream/.gitattributes"
+git -C "$root/upstream" add .gitattributes
+git -C "$root/upstream" commit --quiet -m text
+bun "$test_data" git-pin "$root" "$(git -C "$root/upstream" rev-parse HEAD)"
+fetch "$root" "$root/pin.json"
+checkout="$root/checkouts/source"
+printf 'first line\nsecond line\n' > "$scratch/lf"
+cmp "$scratch/lf" "$checkout/source.txt"
+git -C "$checkout" config --local core.autocrlf true
+git -C "$checkout" config --local core.eol crlf
+rm "$checkout/source.txt"
+git -C "$checkout" checkout -- source.txt
+printf 'first line\r\nsecond line\r\n' > "$scratch/crlf"
+cmp "$scratch/crlf" "$checkout/source.txt"
+fetch "$root" "$root/pin.json"
+cmp "$scratch/lf" "$checkout/source.txt"
+printf '%s\n' "$primary" "$primary" > "$scratch/expected"
+cmp "$scratch/expected" "$root/requests"
+
+case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) echo 'Git symlink creation proof requires a Unix host'; exit 0;; esac
+root="$scratch/git-links"
+init_repo "$root/upstream" trusted upstream
+mkdir "$root/outside" "$root/upstream/fixtures"
+ln -s ../missing "$root/upstream/fixtures/dangling"
+git -C "$root/upstream" add .
+git -C "$root/upstream" commit --quiet -m dangling
+commit="$(git -C "$root/upstream" rev-parse HEAD)"
+bun "$test_data" git-pin "$root" "$commit"
+fetch "$root" "$root/pin.json"
+checkout="$root/checkouts/source"
+ln -s "$root" "$scratch/git-alias"
+FETCH_TEST_FAULT=all fetch "$scratch/git-alias" "$root/pin.json"
+rm "$scratch/git-alias"
+for transitive in false true; do
+  if [[ "$transitive" == false ]]; then
+    ln -s ../outside "$root/upstream/escape"
+  else
+    rm "$root/upstream/escape"
+    ln -s z-escape/missing "$root/upstream/fixtures/a-dangling"
+    ln -s ../../../../outside "$root/upstream/fixtures/z-escape"
+  fi
+  git -C "$root/upstream" add -A
+  git -C "$root/upstream" commit --quiet -m escape
+  bun "$test_data" git-pin "$root" "$(git -C "$root/upstream" rev-parse HEAD)"
+  fail_command 'escaping.*symlink' fetch "$root" "$root/pin.json"
+  [[ "$(git -C "$checkout" rev-parse HEAD)" == "$commit" ]]
+done
+rm -r "$checkout/.git"
+ln -s "$root/upstream/.git" "$checkout/.git"
+bun "$test_data" git-pin "$root" "$commit"
+fail_command 'unsupported non-directory \.git metadata' fetch "$root" "$root/pin.json"
+echo 'Source fetch: verified archives, fallback/retries, exact Git pins, LF repair, symlink containment and local-edit preservation passed'
diff --git a/src/third-party/tools/source-fetch-scopes.mts b/src/third-party/tools/source-fetch-scopes.mts
new file mode 100644
index 000000000..c59d39c1f
--- /dev/null
+++ b/src/third-party/tools/source-fetch-scopes.mts
@@ -0,0 +1,59 @@
+export const sourceOrigins = Object.freeze({
+  sharedThirdParty: 'shared-third-party',
+  nativeThirdParty: 'native-third-party',
+  wasixPostmasterThirdParty: 'wasix-postmaster-third-party',
+  extension: 'extension',
+});
+
+export const defaultSourceScope = 'production-all';
+
+const SOURCE_ORIGINS_BY_SCOPE = Object.freeze({
+  icu: Object.freeze([sourceOrigins.sharedThirdParty]),
+  'production-all': Object.freeze([
+    sourceOrigins.sharedThirdParty,
+    sourceOrigins.nativeThirdParty,
+    sourceOrigins.wasixPostmasterThirdParty,
+    sourceOrigins.extension,
+  ]),
+  all: Object.freeze(Object.values(sourceOrigins)),
+  'native-runtime': Object.freeze([sourceOrigins.sharedThirdParty, sourceOrigins.nativeThirdParty]),
+  'wasix-runtime': Object.freeze([sourceOrigins.sharedThirdParty, sourceOrigins.extension]),
+  'wasix-postmaster-runtime': Object.freeze([
+    sourceOrigins.sharedThirdParty,
+    sourceOrigins.wasixPostmasterThirdParty,
+  ]),
+  extensions: Object.freeze([sourceOrigins.extension]),
+});
+
+export const sourceScopes = Object.freeze(Object.keys(SOURCE_ORIGINS_BY_SCOPE));
+
+const domainEntries = Object.freeze([
+  Object.freeze(['src/third-party/icu', sourceOrigins.sharedThirdParty]),
+  Object.freeze(['src/third-party/openssl', sourceOrigins.sharedThirdParty]),
+  Object.freeze(['src/runtimes/liboliphaunt-native/sources', sourceOrigins.nativeThirdParty]),
+  Object.freeze([
+    'src/runtimes/liboliphaunt-wasix-postmaster/sources',
+    sourceOrigins.wasixPostmasterThirdParty,
+  ]),
+]);
+
+export function sourceDomainsForScope(selectedScope, platform = process.platform) {
+  const origins = new Set(SOURCE_ORIGINS_BY_SCOPE[selectedScope] ?? []);
+  return domainEntries.filter(
+    ([, origin]) =>
+      origins.has(origin) &&
+      !(
+        selectedScope === 'native-runtime' &&
+        origin === sourceOrigins.nativeThirdParty &&
+        platform !== 'win32'
+      ),
+  );
+}
+
+export function scopeIncludesExtensions(selectedScope) {
+  return scopeIncludes(selectedScope, sourceOrigins.extension);
+}
+
+export function scopeIncludes(selectedScope, origin) {
+  return (SOURCE_ORIGINS_BY_SCOPE[selectedScope] ?? []).includes(origin);
+}
diff --git a/src/third-party/tools/source-fetch-scopes.test.mts b/src/third-party/tools/source-fetch-scopes.test.mts
new file mode 100644
index 000000000..c4baf468c
--- /dev/null
+++ b/src/third-party/tools/source-fetch-scopes.test.mts
@@ -0,0 +1,95 @@
+import assert from 'node:assert/strict';
+import { test } from 'node:test';
+
+import {
+  defaultSourceScope,
+  scopeIncludes,
+  scopeIncludesExtensions,
+  sourceDomainsForScope,
+  sourceOrigins,
+  sourceScopes,
+} from './source-fetch-scopes.mts';
+
+const productionDomains = [
+  ['src/third-party/icu', sourceOrigins.sharedThirdParty],
+  ['src/third-party/openssl', sourceOrigins.sharedThirdParty],
+  ['src/runtimes/liboliphaunt-native/sources', sourceOrigins.nativeThirdParty],
+  ['src/runtimes/liboliphaunt-wasix-postmaster/sources', sourceOrigins.wasixPostmasterThirdParty],
+];
+
+test('production-all is the default release scope and includes every product pin', () => {
+  assert.equal(defaultSourceScope, 'production-all');
+  assert.equal(sourceScopes.includes(defaultSourceScope), true);
+  assert.deepEqual(sourceDomainsForScope('production-all'), productionDomains);
+  assert.equal(scopeIncludesExtensions('production-all'), true);
+  assert.equal(scopeIncludes('production-all', sourceOrigins.sharedThirdParty), true);
+  assert.equal(scopeIncludes('production-all', sourceOrigins.nativeThirdParty), true);
+  assert.equal(scopeIncludes('production-all', sourceOrigins.extension), true);
+  assert.equal(scopeIncludes('production-all', sourceOrigins.wasixPostmasterThirdParty), true);
+});
+
+test('all honestly spans every repository source domain', () => {
+  assert.deepEqual(sourceDomainsForScope('all'), [
+    ['src/third-party/icu', sourceOrigins.sharedThirdParty],
+    ['src/third-party/openssl', sourceOrigins.sharedThirdParty],
+    ['src/runtimes/liboliphaunt-native/sources', sourceOrigins.nativeThirdParty],
+    ['src/runtimes/liboliphaunt-wasix-postmaster/sources', sourceOrigins.wasixPostmasterThirdParty],
+  ]);
+  assert.equal(scopeIncludesExtensions('all'), true);
+  assert.equal(scopeIncludes('all', sourceOrigins.sharedThirdParty), true);
+  assert.equal(scopeIncludes('all', sourceOrigins.nativeThirdParty), true);
+  assert.equal(scopeIncludes('all', sourceOrigins.extension), true);
+  assert.equal(scopeIncludes('all', sourceOrigins.wasixPostmasterThirdParty), true);
+});
+
+test('postmaster scope includes only its runtime dependencies and private pins', () => {
+  assert.deepEqual(sourceDomainsForScope('wasix-postmaster-runtime'), [
+    ['src/third-party/icu', sourceOrigins.sharedThirdParty],
+    ['src/third-party/openssl', sourceOrigins.sharedThirdParty],
+    ['src/runtimes/liboliphaunt-wasix-postmaster/sources', sourceOrigins.wasixPostmasterThirdParty],
+  ]);
+  assert.equal(scopeIncludesExtensions('wasix-postmaster-runtime'), false);
+  assert.equal(scopeIncludes('wasix-postmaster-runtime', sourceOrigins.sharedThirdParty), true);
+  assert.equal(
+    scopeIncludes('wasix-postmaster-runtime', sourceOrigins.wasixPostmasterThirdParty),
+    true,
+  );
+  assert.equal(scopeIncludes('wasix-postmaster-runtime', sourceOrigins.nativeThirdParty), false);
+  assert.equal(scopeIncludes('wasix-postmaster-runtime', sourceOrigins.extension), false);
+});
+
+test('native runtime fetches only runtime dependencies for its host platform', () => {
+  assert.deepEqual(sourceDomainsForScope('native-runtime', 'win32'), productionDomains.slice(0, 3));
+  for (const platform of ['linux', 'darwin'])
+    assert.deepEqual(
+      sourceDomainsForScope('native-runtime', platform),
+      productionDomains.slice(0, 2),
+    );
+  assert.equal(scopeIncludesExtensions('native-runtime'), false);
+  assert.equal(scopeIncludes('native-runtime', sourceOrigins.sharedThirdParty), true);
+  assert.equal(scopeIncludes('native-runtime', sourceOrigins.nativeThirdParty), true);
+  assert.equal(scopeIncludes('native-runtime', sourceOrigins.wasixPostmasterThirdParty), false);
+  assert.equal(scopeIncludes('native-runtime', sourceOrigins.extension), false);
+});
+
+test('WASIX and extension scopes retain the external sources they compile', () => {
+  assert.deepEqual(sourceDomainsForScope('wasix-runtime'), productionDomains.slice(0, 2));
+  assert.equal(scopeIncludesExtensions('wasix-runtime'), true);
+  assert.equal(scopeIncludes('wasix-runtime', sourceOrigins.sharedThirdParty), true);
+  assert.equal(scopeIncludes('wasix-runtime', sourceOrigins.nativeThirdParty), false);
+  assert.equal(scopeIncludes('wasix-runtime', sourceOrigins.wasixPostmasterThirdParty), false);
+  assert.equal(scopeIncludes('wasix-runtime', sourceOrigins.extension), true);
+
+  assert.deepEqual(sourceDomainsForScope('extensions'), []);
+  assert.equal(scopeIncludesExtensions('extensions'), true);
+  assert.equal(scopeIncludes('extensions', sourceOrigins.sharedThirdParty), false);
+  assert.equal(scopeIncludes('extensions', sourceOrigins.extension), true);
+});
+
+test('unknown scopes include no sources', () => {
+  assert.deepEqual(sourceDomainsForScope('unknown'), []);
+  assert.equal(scopeIncludesExtensions('unknown'), false);
+  for (const origin of Object.values(sourceOrigins)) {
+    assert.equal(scopeIncludes('unknown', origin), false);
+  }
+});
diff --git a/src/third-party/tools/source-fetch-transport.test.sh b/src/third-party/tools/source-fetch-transport.test.sh
new file mode 100644
index 000000000..8355d8bbc
--- /dev/null
+++ b/src/third-party/tools/source-fetch-transport.test.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+set -euo pipefail
+case "${0##*/}" in
+  sleep)
+    printf '%s\n' "$1" >> "$FETCH_TEST_ROOT/sleeps"
+    if [[ "$1" == 0.1 ]]; then
+      touch "$FETCH_TEST_ROOT/lock-waiting"
+      exec "$FETCH_TEST_SLEEP" "$1"
+    fi
+    ;;
+  git)
+    args=("$@")
+    if [[ " $* " == *' fetch '* ]]; then
+      count=${#args[@]}
+      url=${args[$((count-2))]}
+      printf '%s\n' "$url" >> "$FETCH_TEST_ROOT/requests"
+      if [[ ${FETCH_TEST_FAULT:-} == all || (${FETCH_TEST_FAULT:-} == primary && "$url" != https://mirror.example.invalid/source.git) ]]; then
+        echo "transport fault: $url" >&2; exit 1
+      fi
+      # Only substitute the transport. Real Git owns object storage, checkout,
+      # pin verification, status, line endings, and symlinks in these checks.
+      exec "$FETCH_TEST_GIT" -C "${args[1]}" -c protocol.file.allow=always \
+        fetch --no-tags --depth=1 "$FETCH_TEST_UPSTREAM" "${FETCH_TEST_COMMIT:-${args[$((count-1))]}}"
+    fi
+    exec "$FETCH_TEST_GIT" -c core.autocrlf=true -c core.eol=crlf "$@"
+    ;;
+  curl)
+    [[ "$1" == --disable ]]
+    case " $* " in *' --insecure '*|*' -k '*) exit 90 ;; esac
+    for required in '--proto =https' '--proto-redir =https' '--max-filesize 1073741824' '--max-time 600' '--tlsv1.2' '--retry 2'; do
+      [[ " $* " == *" $required "* ]] || exit 91
+    done
+    if [[ ${RUNNER_OS:-} == Windows ]]; then [[ " $* " == *' --ssl-revoke-best-effort '* ]]; fi
+    url='' output=''
+    while (( $# )); do
+      case "$1" in --url) url=$2; shift ;; --output) output=$2; shift ;; esac
+      shift
+    done
+    printf '%s\n' "$url" >> "$FETCH_TEST_ROOT/requests"
+    if [[ ${FETCH_TEST_BARRIER:-} == 1 ]]; then
+      touch "$FETCH_TEST_ROOT/downloading"
+      while [[ ! -e "$FETCH_TEST_ROOT/release-download" ]]; do "$FETCH_TEST_SLEEP" 0.1; done
+    fi
+    if [[ ${FETCH_TEST_FAULT:-} == all || (${FETCH_TEST_FAULT:-} == primary && "$url" == https://ftp.gnu.org/*) || (${FETCH_TEST_FAULT:-} == gnu && "$url" != https://mirror.example.invalid/libiconv.tar.gz) ]]; then
+      echo "transport fault: $url" >&2; exit 1
+    fi
+    cp "$FETCH_TEST_ARCHIVE" "$output"
+    ;;
+  *) exit 92 ;;
+esac
diff --git a/tools/ci/affected.mts b/tools/ci/affected.mts
new file mode 100644
index 000000000..10870e5e2
--- /dev/null
+++ b/tools/ci/affected.mts
@@ -0,0 +1,28 @@
+export function affectedNames(value = {}) {
+  if (value === null || Array.isArray(value) || typeof value !== 'object') {
+    throw new TypeError('Moon affected query must return an object');
+  }
+  return Object.keys(value).sort();
+}
+
+export function triggeringProjectNames(value = {}) {
+  affectedNames(value);
+  return Object.entries(value)
+    .filter(([, detail]) => {
+      if (detail === null || Array.isArray(detail) || typeof detail !== 'object') return false;
+      return detail.other === true || (Array.isArray(detail.tasks) && detail.tasks.length > 0);
+    })
+    .map(([project]) => project)
+    .sort();
+}
+
+export function triggeringTaskNames(value = {}) {
+  affectedNames(value);
+  return Object.entries(value)
+    .filter(([, detail]) => {
+      if (detail === null || Array.isArray(detail) || typeof detail !== 'object') return false;
+      return detail.other === true || (Array.isArray(detail.files) && detail.files.length > 0);
+    })
+    .map(([task]) => task)
+    .sort();
+}
diff --git a/tools/ci/capture-ci-test-observations.sh b/tools/ci/capture-ci-test-observations.sh
new file mode 100644
index 000000000..6cb9ae224
--- /dev/null
+++ b/tools/ci/capture-ci-test-observations.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+cd "$root"
+directory="${1:?expected observation directory}"
+bash tools/dev/bun.sh tools/ci/ci-plan-test-observations.mts "$directory"
+unset MOON_BASE MOON_HEAD
+export MOON_CACHE=off
+while IFS=$'\t' read -r kind id target; do
+  case "$kind" in
+    affected)
+      "${MOON_BIN:-moon}" query affected stdin --upstream none --downstream deep \
+        < "$directory/affected-$id.input" > "$directory/affected-$id.json" ;;
+    task) "${MOON_BIN:-moon}" task-graph "$target" --json > "$directory/task-$id.json" ;;
+    *) echo "unexpected test observation kind: $kind" >&2; exit 1 ;;
+  esac
+done < "$directory/requests.tsv"
diff --git a/tools/ci/check-workflows.sh b/tools/ci/check-workflows.sh
new file mode 100755
index 000000000..0c84a9462
--- /dev/null
+++ b/tools/ci/check-workflows.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
+  echo "must run inside the Oliphaunt git checkout" >&2
+  exit 1
+}
+cd "$root"
+PATH="$PATH:${CARGO_HOME:-$HOME/.cargo}/bin"
+export PATH
+
+require() {
+  if ! command -v "$1" >/dev/null 2>&1; then
+    echo "missing required command: $1" >&2
+    echo "run tools/dev/bootstrap-tools.sh to install pinned maintainer tools" >&2
+    exit 1
+  fi
+}
+
+run() {
+  printf '\n==> %s\n' "$*"
+  "$@"
+}
+
+require actionlint
+require zizmor
+# actionlint 1.7.12 predates GitHub's `concurrency.queue: max` schema addition.
+run actionlint -ignore 'unexpected key "queue" for "concurrency" section'
+run zizmor --config .github/zizmor.yml --min-severity medium --persona auditor .github/workflows .github/actions
+run tools/dev/bun.sh test ./tools/ci/workflow-security.test.mts
+run tools/dev/bun.sh tools/ci/workflow-security.mts
+run bash .github/scripts/check-ci-gate.test.sh
+run tools/dev/bun.sh test ./.github/scripts/resolve-mobile-e2e.test.mts
+run bash .github/scripts/run-moon-targets.test.sh
+graph_file="$(mktemp)"
+observations="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-ci-observations.XXXXXX")"
+trap 'rm -f "$graph_file"; rm -rf "$observations"' EXIT
+"${MOON_BIN:-moon}" task-graph --json >"$graph_file"
+export OLIPHAUNT_MOON_TASK_GRAPH_FILE="$graph_file"
+export OLIPHAUNT_CI_TEST_OBSERVATIONS="$observations"
+run tools/dev/bun.sh test ./.github/scripts/moon-task-capabilities.test.mts
+run bash .github/scripts/write-affected-moon-target-matrices.test.sh
+run bash .github/scripts/resolve-planned-moon-execution.test.sh
+run bash tools/ci/with-projects.sh --exec bash tools/ci/capture-ci-test-observations.sh "$observations"
+run bash tools/ci/ci-release-scope.test.sh
+run bash tools/ci/with-projects.sh test \
+  ./tools/ci/ci-plan-node-products.test.mts \
+  ./tools/ci/ci-plan-wasix-postmaster-release.test.mts
+run bash tools/ci/with-projects.sh --exec bash tools/ci/workflow-moon-transfers.test.sh
diff --git a/tools/ci/ci-plan-node-products.test.mts b/tools/ci/ci-plan-node-products.test.mts
new file mode 100644
index 000000000..ad2699791
--- /dev/null
+++ b/tools/ci/ci-plan-node-products.test.mts
@@ -0,0 +1,854 @@
+import assert from 'node:assert/strict';
+import { test } from 'node:test';
+import { buildPlan, loadGraph, normalizeFiles } from '../release/release-graph.mts';
+import { affectedNames, triggeringProjectNames, triggeringTaskNames } from './affected.mts';
+import {
+  dependencyPlatformTargets,
+  jobTargetsForJobs,
+  planForReleaseProducts,
+  planJobsForAffected,
+  requiredTasksForAffected,
+} from './ci_plan.mts';
+import { combinedNativeWasix, paths, taskRoots } from './ci-plan-test-inputs.mts';
+import { affectedObservation, taskObservation } from './ci-plan-test-observations.mts';
+import { loadExtensionTargetProfiles } from '../../src/extensions/contracts/extension-target-profiles.mts';
+import {
+  contribCarrierDescriptor,
+  extensionProductForSqlName,
+} from '../release/release-artifact-targets.mts';
+import { publishedConsumerDependencies } from '../../src/sdks/ts/sdk/tools/published-consumer.mts';
+
+const GRAPH = loadGraph('ci-plan-node-products.test.mts');
+const NATIVE_TS_CONSUMER_JOBS = [
+  'affected',
+  'broker-runtime',
+  'js-sdk-package',
+  'liboliphaunt-native-desktop',
+  'native-consumers',
+  'node-direct',
+];
+
+test('SDK-only release reuses a complete published dependency inventory, while missing or selected dependencies retain producers', () => {
+  const inventory = Object.entries(publishedConsumerDependencies()).map(([name, version]) => ({
+    name,
+    version,
+    integrity: `sha512-${Buffer.alloc(64).toString('base64')}`,
+    tarball: `https://registry.npmjs.org/${name}/-/${name.split('/')[1]}-${version}.tgz`,
+  }));
+  const published = planForReleaseProducts(['oliphaunt-js'], 'a'.repeat(40), inventory);
+  assert.deepEqual(published.jobs, ['affected', 'js-sdk-package', 'native-consumers']);
+  assert.deepEqual(published.job_targets['native-consumers'], [
+    'oliphaunt-js:test-consumer-published',
+  ]);
+  assert.deepEqual(published.job_targets['js-sdk-package'], ['oliphaunt-js:package']);
+  assert(!published.tasks.includes('liboliphaunt-native:package-runtime-desktop-target'));
+  for (const rows of [
+    null,
+    inventory.slice(1),
+    inventory.map((row, index) => (index === 0 ? { ...row, version: '999.0.0' } : row)),
+  ]) {
+    const plan = planForReleaseProducts(['oliphaunt-js'], 'a'.repeat(40), rows);
+    assert(plan.jobs.includes('liboliphaunt-native-desktop'));
+    assert.deepEqual(plan.job_targets['native-consumers'], ['oliphaunt-js:test-consumer']);
+  }
+  const mixed = planForReleaseProducts(
+    ['oliphaunt-js', 'oliphaunt-query-ts'],
+    'a'.repeat(40),
+    inventory,
+  );
+  assert(mixed.job_targets['js-sdk-package'].includes('oliphaunt-query-ts:package'));
+  assert(mixed.jobs.includes('node-direct'));
+  assert(
+    !requiredTasksForAffected(new Set(['oliphaunt-js:test-consumer-published'])).has(
+      'oliphaunt-js:test-consumer-published',
+    ),
+  );
+  assert(
+    !jobTargetsForJobs(new Set(['native-consumers']))['native-consumers'].includes(
+      'oliphaunt-js:test-consumer-published',
+    ),
+  );
+});
+
+test('selected TypeScript SDK qualification includes shipped native consumption without mobile or WASIX producers', () => {
+  const plan = planForReleaseProducts(['oliphaunt-js'], 'a'.repeat(40));
+  assert.deepEqual(plan.qualification_products, ['oliphaunt-js']);
+  assert.equal(plan.qualification_mode, 'selected-products');
+  assert(plan.job_targets['js-sdk-package'].includes('oliphaunt-js:package'));
+  assert(plan.job_targets['js-sdk-package'].includes('oliphaunt-query-ts:package'));
+  assert(plan.job_targets['native-consumers'].includes('oliphaunt-js:test-consumer'));
+  assert(plan.jobs.includes('liboliphaunt-native-desktop'));
+  for (const matrix of [
+    plan.liboliphaunt_native_desktop_runtime_matrix,
+    plan.broker_runtime_matrix,
+    plan.node_direct_runtime_matrix,
+  ]) {
+    assert.deepEqual(
+      matrix.include.map((row) => row.target),
+      ['linux-x64-gnu'],
+    );
+  }
+  assert(!plan.jobs.some((job) => job.includes('wasix') || job.startsWith('mobile-')));
+  assert.throws(
+    () => planForReleaseProducts(['unknown-product'], 'a'.repeat(40)),
+    /known product IDs/,
+  );
+  assert.throws(
+    () => planForReleaseProducts(['oliphaunt-js', 'oliphaunt-js'], 'a'.repeat(40)),
+    /unique list/,
+  );
+});
+
+function effects(paths) {
+  const relativePaths = Array.isArray(paths) ? paths : [paths];
+  const affected = affectedObservation(relativePaths);
+  const projects = triggeringProjectNames(affected.projects);
+  const directTasks = triggeringTaskNames(affected.tasks);
+  const tasks = affectedNames(affected.tasks);
+  const jobs = planJobsForAffected(new Set(directTasks));
+  return {
+    directTasks,
+    jobs: [...jobs].sort(),
+    jobTargets: jobTargetsForJobs(jobs, requiredTasksForAffected(new Set(directTasks))),
+    projects,
+    releaseProducts: buildPlan(
+      GRAPH,
+      normalizeFiles(relativePaths),
+      'ci-plan-node-products.test.mts',
+    ).releaseProducts,
+    tasks,
+  };
+}
+
+test('Rust release qualification executes the compiled consumer against shipped Linux dependencies', () => {
+  const consumer = 'oliphaunt-rust:test-consumer-runtime';
+  const plan = planForReleaseProducts(['oliphaunt-rust'], 'd'.repeat(40));
+  assert(plan.job_targets['native-consumers'].includes(consumer));
+  assert(plan.job_targets['rust-sdk-package'].includes('oliphaunt-rust:test-consumer'));
+  for (const target of [
+    'liboliphaunt-native:package-runtime-desktop-target',
+    'postgres-tools-native:package-assets',
+    'oliphaunt-broker:build-release-assets',
+  ])
+    assert(plan.tasks.includes(target), `missing shipped consumer input ${target}`);
+  const roots = new Set([consumer]);
+  assert.deepEqual(
+    [...dependencyPlatformTargets('liboliphaunt-native-desktop', roots)],
+    ['linux-x64-gnu'],
+  );
+  assert.deepEqual([...dependencyPlatformTargets('broker-runtime', roots)], ['linux-x64-gnu']);
+  assert(!requiredTasksForAffected(roots).has('native-extension-lifecycle:lifecycle'));
+});
+
+test('an empty Moon selection requires no product tasks or releases', () => {
+  const tasks = new Set();
+  assert.deepEqual([...requiredTasksForAffected(tasks)], []);
+  assert.deepEqual([...planJobsForAffected(tasks)], ['affected']);
+  assert.deepEqual(buildPlan(GRAPH, [], 'ci-plan-node-products.test.mts').releaseProducts, []);
+});
+
+test('shared Rust query changes stage the native and WASIX consumer artifacts', () => {
+  const result = effects(paths.sdksRustQuerySrcLibRs);
+  for (const consumer of ['oliphaunt-wasix-ts:package', 'oliphaunt-wasix-ts:test-consumer']) {
+    assert(result.jobTargets['wasix-ts-sdk-package'].includes(consumer), consumer);
+  }
+  for (const producer of [
+    'oliphaunt-rust:package',
+    'oliphaunt-query:package',
+    'liboliphaunt-native-bindings:package',
+    'oliphaunt-broker:package',
+  ]) {
+    assert(result.jobTargets['rust-sdk-package'].includes(producer), producer);
+  }
+});
+
+test('compiled WASIX carrier sources reach SDK and addon checks without rebuilding runtime bytes', () => {
+  for (const file of [
+    paths.wasixRuntimeCarrierSource,
+    paths.wasixToolsCarrierSource,
+    paths.icuCarrierSource,
+  ]) {
+    const result = effects(file);
+    for (const target of [
+      'oliphaunt-wasix-rust:build',
+      'oliphaunt-wasix-rust:test',
+      'oliphaunt-wasix-napi:test',
+      'oliphaunt-wasix-napi:rust-lint',
+    ]) {
+      assert(result.tasks.includes(target), `${file} must affect ${target}`);
+    }
+    for (const target of [
+      'liboliphaunt-wasix:compiler-output',
+      'liboliphaunt-wasix:runtime-portable',
+      'liboliphaunt-wasix:runtime-aot',
+    ]) {
+      assert(!result.tasks.includes(target), `${file} must not rebuild ${target}`);
+    }
+  }
+});
+
+test('WASIX SDK changes select artifact consumption without invalidating AOT compilation', () => {
+  for (const file of [paths.sdksRustQuerySrcLibRs, paths.sdksRustWasixSrcLibRs]) {
+    const result = effects(file);
+    assert.equal(result.directTasks.includes('oliphaunt-wasix-rust:test-aot'), true);
+    assert.equal(result.directTasks.includes('liboliphaunt-wasix:runtime-aot'), false);
+    assert.equal(result.directTasks.includes('liboliphaunt-wasix:runtime-portable'), false);
+    assert.equal(
+      result.jobTargets['liboliphaunt-wasix-aot'].includes('oliphaunt-wasix-rust:test-aot'),
+      true,
+    );
+  }
+  const consumer = actionTargets(taskRoots.oliphauntWasixRustTestAot);
+  assert.equal(consumer.has('liboliphaunt-wasix:runtime-aot'), true);
+  assert.equal(consumer.has('liboliphaunt-wasix:runtime-portable'), true);
+  assert.equal(
+    actionTargets(taskRoots.liboliphauntWasixRuntimeAot).has('oliphaunt-wasix-rust:test-aot'),
+    false,
+  );
+});
+
+test('pgwire runtime consumers execute in the AOT job with their required producers', () => {
+  for (const target of [
+    'oliphaunt-pgwire-server:test-integration',
+    'oliphaunt-pgwire-server:test-aot',
+  ]) {
+    const selected = new Set([target]);
+    const tasks = requiredTasksForAffected(selected);
+    const jobs = jobTargetsForJobs(planJobsForAffected(selected), tasks);
+    assert(jobs['liboliphaunt-wasix-aot'].includes(target));
+    assert(!jobs['liboliphaunt-wasix-runtime']?.includes(target));
+    assert(tasks.has('liboliphaunt-wasix:runtime-aot'));
+    if (target.endsWith(':test-aot')) {
+      assert(tasks.has('extension-artifacts-wasix:build-aot'));
+    }
+  }
+});
+
+test('optional WASIX compiler changes select their owner handoffs without invalidating core compilation', () => {
+  for (const [file, owner] of [
+    [paths.postgresToolsWasixToolsBuildPortableSh, 'postgres-tools-wasix'],
+    [paths.extensionsArtifactsWasixToolsBuildPortableSh, 'extension-artifacts-wasix'],
+  ]) {
+    const result = effects(file);
+    assert(result.directTasks.includes(`${owner}:compiler-output`));
+    assert(!result.directTasks.includes('liboliphaunt-wasix:runtime-portable'));
+    assert(!result.directTasks.includes('liboliphaunt-wasix:runtime-aot'));
+    assert(result.jobTargets['liboliphaunt-wasix-runtime'].includes(`${owner}:compiler-output`));
+    assert(result.jobTargets['liboliphaunt-wasix-aot'].includes(`${owner}:build-aot`));
+    assert(actionTargets(`${owner}:build-aot`).has(`${owner}:compiler-output`));
+  }
+});
+
+test('affected mobile consumers retain native ABI proofs and selected resources', () => {
+  const result = effects(paths.sdksTsQuerySrcQueryTs);
+  assert.deepEqual(result.jobTargets['liboliphaunt-native-android'], [
+    'liboliphaunt-native:build-runtime-android-arm64-v8a',
+    'liboliphaunt-native:build-runtime-android-x86_64',
+    'liboliphaunt-native:package-runtime-android-arm64-v8a',
+    'liboliphaunt-native:package-runtime-android-x86_64',
+  ]);
+  assert.deepEqual(result.jobTargets['liboliphaunt-native-android-abi'], [
+    'database-resources:build-native-android-icu',
+    'liboliphaunt-native:finalize-runtime-android-abi',
+  ]);
+  assert(
+    result.jobTargets['liboliphaunt-native-ios-abi'].includes(
+      'database-resources:build-native-ios-icu',
+    ),
+  );
+  assert(result.jobTargets['js-sdk-package'].includes('database-resources:package-icu'));
+});
+
+test('mobile seed production transfers native builds without selecting runtime packages', () => {
+  for (const platform of ['android', 'ios']) {
+    const roots = new Set([`database-resources:build-native-${platform}-standard`]);
+    const jobs = planJobsForAffected(roots);
+    const targets = jobTargetsForJobs(jobs, requiredTasksForAffected(roots));
+    const native = targets[`liboliphaunt-native-${platform}`];
+    assert.deepEqual(
+      native,
+      platform === 'android'
+        ? [
+            'liboliphaunt-native:build-runtime-android-arm64-v8a',
+            'liboliphaunt-native:build-runtime-android-x86_64',
+          ]
+        : ['liboliphaunt-native:build-runtime-ios-xcframework'],
+    );
+    assert.deepEqual(targets[`liboliphaunt-native-${platform}-abi`], [...roots]);
+    assert.equal(jobs.has('liboliphaunt-native-release-assets'), false);
+  }
+});
+
+test('native binding changes retain all source artifacts needed by the Rust consumer', () => {
+  const result = effects(paths.sdksRustLiboliphauntNativeSrcLibRs);
+  assert.deepEqual(result.jobTargets['rust-sdk-package'], [
+    'liboliphaunt-native-bindings:package',
+    'oliphaunt-broker:package',
+    'oliphaunt-query:package',
+    'oliphaunt-rust:package',
+    'oliphaunt-rust:test-consumer',
+  ]);
+});
+
+test('Rust dependency sources invalidate consumer checks while dependency tests and formatting stay local', () => {
+  for (const file of [paths.sdksRustLiboliphauntNativeSrcLibRs, paths.sdksRustQuerySrcLibRs]) {
+    const { tasks } = effects(file);
+    for (const task of ['build', 'test', 'lint']) {
+      assert(tasks.includes(`oliphaunt-rust:${task}`), `${file} must invalidate SDK ${task}`);
+    }
+    assert.equal(tasks.includes('oliphaunt-rust:format-check'), false);
+  }
+  const dependencyTests = effects(paths.nativeBindingProtocolTest);
+  assert.equal(dependencyTests.tasks.includes('oliphaunt-rust:test'), false);
+  assert.equal(dependencyTests.tasks.includes('oliphaunt-rust:build'), false);
+});
+
+function actionTargets(target) {
+  return new Set(taskObservation(target).map((task) => task.target));
+}
+function taskRecord(target) {
+  return taskObservation(target).find((task) => task.target === target);
+}
+
+test('mobile binding source selects Kotlin consumers while native test-only changes do not', () => {
+  const implementation = effects(paths.mobileBindingSource);
+  assert(implementation.jobTargets['kotlin-sdk-package'].includes('oliphaunt-kotlin:package'));
+  assert.equal(implementation.tasks.includes('oliphaunt-kotlin:format-check'), false);
+  const nativeTest = effects(paths.nativeBindingProtocolTest);
+  assert.equal(nativeTest.jobTargets['kotlin-sdk-package'], undefined);
+});
+
+test('Swift native bindings retain their Apple producer before Linux package assembly', () => {
+  const plan = planForReleaseProducts(['oliphaunt-swift'], 'b'.repeat(40));
+  assert.deepEqual(plan.job_targets['swift-bindings'], ['oliphaunt-swift:package-bindings']);
+  assert.deepEqual(plan.job_targets['swift-sdk-package'], ['oliphaunt-swift:package']);
+  const producer = taskRecord(taskRoots.oliphauntSwiftPackageBindings);
+  assert(producer.tags.includes('requires-apple'));
+  assert(actionTargets(taskRoots.oliphauntSwiftPackage).has('oliphaunt-swift:package-bindings'));
+});
+
+test('JavaScript SDK source consumes shipped native artifacts without invalidating their compilation', () => {
+  const result = effects(paths.sdksTsSdkSrcClientTs);
+  assert.deepEqual(result.jobs, NATIVE_TS_CONSUMER_JOBS);
+  assert.deepEqual(result.releaseProducts, ['oliphaunt-js']);
+  assert.equal(result.tasks.includes('oliphaunt-js:build'), true);
+  assert.equal(result.tasks.includes('oliphaunt-js:test'), true);
+  assert.equal(result.tasks.includes('oliphaunt-node-direct:build-release-assets'), false);
+  assert.equal(result.tasks.includes('release-tools:metadata'), false);
+  assert.equal(result.tasks.includes('release-tools:test'), false);
+});
+
+test('product prose selects packaging and the cold action graph includes required compilation', () => {
+  const javascript = effects(paths.sdksTsSdkREADMEMd);
+  assert.deepEqual(javascript.jobs, NATIVE_TS_CONSUMER_JOBS);
+  assert.equal(javascript.tasks.includes('oliphaunt-js:package'), true);
+  for (const target of [
+    'oliphaunt-js:test',
+    'oliphaunt-js:test-native',
+    'oliphaunt-js:build',
+    'oliphaunt-js:test',
+    'sdk-contracts:native-boundaries',
+  ]) {
+    assert.equal(javascript.tasks.includes(target), false, `${target} does not consume SDK prose`);
+  }
+  const actions = actionTargets(taskRoots.oliphauntJsPackage);
+  assert.equal(actions.has('oliphaunt-js:build'), true);
+  assert.equal(actions.has('oliphaunt-js:test'), false);
+
+  const napi = effects(paths.sdksTsWasixNodeAddonREADMEMd);
+  assert.deepEqual(napi.jobs, ['affected']);
+  assert.equal(napi.tasks.includes('oliphaunt-wasix-napi:test'), false);
+});
+
+test('query package prose affects its archive without rebuilding SDK consumers', () => {
+  const result = effects(paths.sdksTsQueryREADMEMd);
+  assert.equal(result.directTasks.includes('oliphaunt-query-ts:package'), true);
+  for (const target of [
+    'oliphaunt-js:package',
+    'oliphaunt-wasix-ts:package',
+    'oliphaunt-react-native:package',
+  ])
+    assert.equal(
+      result.directTasks.includes(target),
+      false,
+      `${target} consumes a published dependency`,
+    );
+  for (const target of [
+    'oliphaunt-query-ts:build',
+    'oliphaunt-query-ts:test',
+    'oliphaunt-js:build',
+    'oliphaunt-js:typecheck',
+    'oliphaunt-js:test',
+    'oliphaunt-react-native:build',
+    'oliphaunt-react-native:typecheck',
+    'oliphaunt-wasix-ts:typecheck',
+    'oliphaunt-wasix-ts:test',
+    'oliphaunt-wasix-rust:test-regression',
+  ])
+    assert.equal(result.directTasks.includes(target), false, `${target} does not read the README`);
+});
+
+test('extension evidence validates evidence without rebuilding products', () => {
+  const result = effects(paths.extensionsEvidenceRuns20260607TransitionalCatalogSmokeJson);
+  assert.equal(result.tasks.includes('extensions:lint'), true);
+  assert.equal(result.tasks.includes('docs:check'), false);
+  assert.equal(result.tasks.includes('sdk-contracts:fixtures'), false);
+  for (const job of [
+    'extension-artifacts-native',
+    'extension-artifacts-wasix',
+    'native-extension-lifecycle',
+  ]) {
+    assert.equal(result.jobs.includes(job), false, `${job} does not consume evidence records`);
+  }
+});
+
+test('Node Direct source does not rebuild the independently versioned JavaScript SDK', () => {
+  const result = effects(paths.sdksTsNodeAddonSrcLibRs);
+  assert.deepEqual(result.jobs, [...NATIVE_TS_CONSUMER_JOBS, 'node-direct-release-assets'].sort());
+  assert.deepEqual(result.releaseProducts, ['oliphaunt-node-direct']);
+  assert.equal(result.tasks.includes('oliphaunt-node-direct:typecheck'), true);
+  assert.equal(result.tasks.includes('oliphaunt-js:test'), false);
+});
+
+test('native implementation does not compile the version-decoupled broker', () => {
+  const result = effects(paths.runtimesLiboliphauntNativeSrcLiboliphauntProcessC);
+  assert.equal(result.tasks.includes('oliphaunt-broker:build'), false);
+  assert.equal(result.tasks.includes('liboliphaunt-native:lint'), false);
+  assert.equal(result.tasks.includes('oliphaunt-rust:test-integration'), true);
+  assert.equal(result.tasks.includes('oliphaunt-swift:test-native'), true);
+});
+
+test('combined JavaScript SDK and WASIX N-API changes release only changed products', () => {
+  const result = effects(combinedNativeWasix);
+  assert.deepEqual(result.jobs, [
+    'affected',
+    'broker-runtime',
+    'extension-artifacts-wasix',
+    'js-sdk-package',
+    'liboliphaunt-native-desktop',
+    'liboliphaunt-wasix-aot',
+    'liboliphaunt-wasix-runtime',
+    'native-consumers',
+    'node-direct',
+    'wasix-napi',
+    'wasix-napi-release-assets',
+    'wasix-ts-sdk-package',
+  ]);
+  assert.deepEqual(result.releaseProducts, ['oliphaunt-js', 'oliphaunt-wasix-napi']);
+});
+
+test('shared contrib source releases only its two runtime owners', () => {
+  const release = buildPlan(
+    GRAPH,
+    ['src/extensions/contrib/postgres18.toml'],
+    'ci-plan-node-products.test.mts',
+  );
+  assert.deepEqual(release.directProducts, ['liboliphaunt-native', 'liboliphaunt-wasix']);
+  assert.deepEqual(release.releaseProducts, ['liboliphaunt-native', 'liboliphaunt-wasix']);
+  const plan = planForReleaseProducts(release.releaseProducts, 'c'.repeat(40));
+  const contrib = contribCarrierDescriptor();
+  assert(plan.extension_package_products.includes(contrib.artifactProduct));
+  assert(plan.tasks.includes('native-extension-lifecycle:lifecycle'));
+  assert(plan.tasks.includes('extension-artifacts-wasix:build-target'));
+  for (const sql of ['hstore', 'pg_trgm']) {
+    assert(plan.native_extension_lifecycle_sql_names.includes(sql));
+    assert(
+      plan.extension_artifacts_wasix_matrix.include.some((row) =>
+        row.sql_names_csv.split(',').includes(sql),
+      ),
+    );
+  }
+  assert.throws(
+    () => planForReleaseProducts([contrib.artifactProduct], 'c'.repeat(40)),
+    /known product IDs/,
+  );
+});
+
+test('external extension release selects shared producers and same-run lifecycle evidence', () => {
+  const product = extensionProductForSqlName('pgtap');
+  const plan = planForReleaseProducts([product], 'c'.repeat(40));
+  assert.deepEqual(plan.qualification_products, [product]);
+  for (const target of [
+    'extension-artifacts-native:build-target',
+    'extension-artifacts-wasix:build-target',
+    'native-extension-lifecycle:lifecycle',
+  ])
+    assert(plan.tasks.includes(target), `missing ${target}`);
+  assert(
+    plan.job_targets['native-extension-lifecycle'].includes('native-extension-lifecycle:lifecycle'),
+  );
+  assert(plan.native_extension_lifecycle_sql_names.includes('pgtap'));
+  assert(plan.jobs.includes('liboliphaunt-wasix-runtime'));
+  assert(plan.jobs.includes('liboliphaunt-wasix-aot'));
+  const profiles = loadExtensionTargetProfiles({
+    file: new URL('../../src/extensions/contracts/extension-target-profiles.toml', import.meta.url),
+  });
+  for (const { family, target } of profiles.targets) {
+    const rows =
+      family === 'native'
+        ? plan.extension_artifacts_native_matrix.include
+        : plan.extension_artifacts_wasix_matrix.include;
+    assert(
+      rows.some((row) => row.target === target && row.sql_names_csv.split(',').includes('pgtap')),
+      `missing pgtap ${target}`,
+    );
+  }
+});
+
+test('WASIX N-API source selects only its real WASIX artifact inputs', () => {
+  const result = effects(paths.sdksTsWasixNodeAddonSrcLibRs);
+  assert.deepEqual(result.jobs, [
+    'affected',
+    'extension-artifacts-wasix',
+    'js-sdk-package',
+    'liboliphaunt-wasix-aot',
+    'liboliphaunt-wasix-runtime',
+    'wasix-napi',
+    'wasix-napi-release-assets',
+    'wasix-ts-sdk-package',
+  ]);
+  assert.deepEqual(result.releaseProducts, ['oliphaunt-wasix-napi']);
+  assert(result.jobTargets['wasix-ts-sdk-package'].includes('postgres-tools-wasix:test-consumer'));
+  assert(result.jobTargets['js-sdk-package'].includes('oliphaunt-wasix-tools-ts:package'));
+  assert.equal(result.tasks.includes('oliphaunt-wasix-napi:rust-format-check'), true);
+  assert.equal(result.tasks.includes('oliphaunt-wasix-napi:test'), true);
+});
+
+test('packaging fixtures select their owner tests without artifact builders', () => {
+  for (const [file, task] of [
+    [paths.sdksTsWasixNodeAddonToolsPackageContractTestMts, 'oliphaunt-wasix-napi:test'],
+    [paths.brokerToolsCreateReleaseFixtureMts, 'oliphaunt-broker:packaging-unit'],
+    [paths.brokerToolsBrokerDependencyLicenseContractTestMts, 'oliphaunt-broker:packaging-unit'],
+  ]) {
+    const result = effects(file);
+    assert.deepEqual(result.jobs, ['affected'], file);
+    assert.equal(result.tasks.includes(task), true, file);
+  }
+});
+
+test('WASIX test helpers invalidate only tasks that execute them', () => {
+  const result = effects(paths.runtimesLiboliphauntWasixToolsCargoTestFilterSh);
+  for (const target of [
+    'oliphaunt-wasix-rust:test-aot',
+    'liboliphaunt-wasix:smoke',
+    'oliphaunt-wasix-rust:test-regression',
+  ]) {
+    assert.equal(result.directTasks.includes(target), true, `${target} executes the helper`);
+  }
+  for (const target of [
+    'liboliphaunt-wasix:runtime-aot',
+    'oliphaunt-wasix-rust:test',
+    'extension-artifacts-wasix:build-target',
+    'liboliphaunt-wasix:assets-verify',
+    'liboliphaunt-wasix:release-assets',
+    'liboliphaunt-wasix:runtime-portable',
+    'perf-tools:wasix-browser-measure',
+    'perf-tools:wasix-node-measure',
+  ]) {
+    assert.equal(
+      result.directTasks.includes(target),
+      false,
+      `${target} does not execute the helper`,
+    );
+  }
+});
+
+test('WASIX extension staging follows its own code and produced runtime artifact', () => {
+  const packager = effects(paths.extensionsArtifactsWasixToolsPackageReleaseAssetsMts);
+  assert.equal(packager.directTasks.includes('extension-artifacts-wasix:build-target'), true);
+
+  const runtimeVersion = effects(paths.runtimesLiboliphauntWasixVERSION);
+  assert.equal(runtimeVersion.directTasks.includes('extension-artifacts-wasix:build-target'), true);
+
+  const releaseMetadata = effects(paths.runtimesLiboliphauntWasixReleaseToml);
+  assert.equal(
+    releaseMetadata.directTasks.includes('extension-artifacts-wasix:build-target'),
+    false,
+  );
+  assert.equal(
+    releaseMetadata.directTasks.includes('oliphaunt-wasix-napi:build-release-assets'),
+    true,
+  );
+});
+
+test('extension artifact builders materialize their runtime and extension sources', () => {
+  const native = actionTargets(taskRoots.extensionArtifactsNativeBuildTarget);
+  assert.equal(native.has('source-inputs:source-fetch-native-runtime'), true);
+  assert.equal(native.has('source-inputs:source-fetch-extensions'), true);
+
+  const wasix = actionTargets(taskRoots.extensionArtifactsWasixBuildTarget);
+  assert.equal(wasix.has('source-inputs:source-fetch-wasix-runtime'), true);
+  assert.equal(wasix.has('source-inputs:source-fetch-extensions'), false);
+});
+
+test('executable packagers and Rust test configuration select their real owners', () => {
+  const nativeExtensions = effects(paths.extensionsArtifactsNativeToolsPackageReleaseAssetsSh);
+  assert.equal(
+    nativeExtensions.directTasks.includes('extension-artifacts-native:build-target'),
+    true,
+  );
+  assert.equal(nativeExtensions.jobs.includes('extension-artifacts-native'), true);
+
+  const mobile = effects(paths.runtimesLiboliphauntNativeToolsPackageLiboliphauntMobileAssetsSh);
+  for (const target of [
+    'liboliphaunt-native:package-runtime-android-arm64-v8a',
+    'liboliphaunt-native:package-runtime-android-x86_64',
+    'liboliphaunt-native:package-runtime-ios-xcframework',
+  ]) {
+    assert.equal(
+      mobile.directTasks.includes(target),
+      true,
+      `${target} executes the mobile packager`,
+    );
+  }
+  assert.equal(
+    mobile.directTasks.some((target) => target.includes(':build-runtime-android-')),
+    false,
+  );
+  assert.equal(
+    mobile.directTasks.includes('liboliphaunt-native:build-runtime-ios-xcframework'),
+    false,
+  );
+
+  const desktop = effects(paths.runtimesLiboliphauntNativeToolsPackageLiboliphauntLinuxAssetsSh);
+  assert.equal(
+    desktop.directTasks.includes('liboliphaunt-native:package-runtime-desktop-target'),
+    true,
+  );
+  assert.equal(
+    desktop.directTasks.includes('liboliphaunt-native:build-runtime-desktop-target'),
+    false,
+  );
+
+  const smoke = effects(paths.runtimesLiboliphauntNativeSmokeLiboliphauntSmokeC);
+  assert(smoke.directTasks.includes('liboliphaunt-native:test-artifacts-desktop-target'));
+  assert.equal(
+    smoke.directTasks.includes('liboliphaunt-native:package-runtime-desktop-target'),
+    false,
+  );
+  assert.equal(
+    smoke.directTasks.includes('liboliphaunt-native:build-runtime-desktop-target'),
+    false,
+  );
+  assert(
+    smoke.jobTargets['liboliphaunt-native-desktop'].includes(
+      'liboliphaunt-native:package-runtime-desktop-target',
+    ),
+  );
+
+  const nextest = effects(paths.configNextestToml);
+  assert.equal(nextest.directTasks.includes('oliphaunt-rust:test'), true);
+  assert.equal(nextest.directTasks.includes('oliphaunt-wasix-rust:test'), true);
+});
+
+test('product unit suites remain selected without central coverage', () => {
+  const reactNative = effects(paths.sdksReactNativeSrcIndexTs);
+  assert.equal(reactNative.directTasks.includes('oliphaunt-react-native:test'), true);
+  assert.equal(taskRecord(taskRoots.oliphauntReactNativeTest).options.runInCI, true);
+
+  const wasixRust = effects(paths.sdksRustWasixSrcLibRs);
+  assert.equal(wasixRust.directTasks.includes('oliphaunt-wasix-rust:test'), true);
+});
+
+test('source acquisition and WASIX browser-host ownership stay narrow', () => {
+  const extensionPin = effects(paths.extensionsExternalVectorSourceToml);
+  assert.equal(extensionPin.directTasks.includes('source-inputs:source-fetch-extensions'), true);
+  assert.equal(
+    extensionPin.directTasks.includes('source-inputs:source-fetch-native-runtime'),
+    false,
+  );
+  assert.equal(extensionPin.directTasks.includes('source-inputs:source-fetch-wasix-runtime'), true);
+
+  const browserHost = effects(paths.runtimesWasixBrowserHostSourceToml);
+  assert.equal(browserHost.directTasks.includes('wasix-browser-host:build'), true);
+  assert.equal(browserHost.tasks.includes('oliphaunt-wasix-ts:package'), true);
+  assert.equal(browserHost.jobs.includes('wasix-ts-sdk-package'), true);
+
+  const cargoLock = effects(paths.CargoLock);
+  assert.equal(cargoLock.directTasks.includes('wasix-browser-host:build'), true);
+});
+
+test('docs changes select the production artifact and built-site smoke', () => {
+  const result = effects(paths.docsSrcAppDocsLayoutTsx);
+  assert.equal(result.directTasks.includes('docs:build'), true);
+  assert.equal(result.tasks.includes('docs:test-package'), true);
+});
+
+test('WASIX N-API production helpers keep the release builder affected', () => {
+  for (const relativePath of [
+    paths.sdksTsWasixSdkToolsPgwireClientMts,
+    paths.sdksTsWasixNodeAddonToolsPackagePlatformSh,
+    paths.toolsDevDenoSh,
+    paths.runtimesLiboliphauntWasixToolsWasixAotManifestMts,
+  ]) {
+    const result = effects(relativePath);
+    assert.equal(
+      result.tasks.includes('oliphaunt-wasix-napi:build-release-assets'),
+      true,
+      `${relativePath} must invalidate the WASIX N-API release builder`,
+    );
+    assert.equal(result.jobs.includes('wasix-napi-release-assets'), true);
+  }
+});
+
+test('CI planner changes select the focused graph proof', () => {
+  const result = effects(paths.toolsGraphCiPlanMts);
+  assert.equal(result.tasks.includes('release-tools:graph-unit'), true);
+  assert.equal(result.tasks.includes('release-tools:test'), false);
+});
+
+test('release mutation tests follow release helpers, not policy or workflow files', () => {
+  for (const relativePath of [paths.moonTasksJavascriptQualityYml, paths.githubWorkflowsCiYml]) {
+    const result = effects(relativePath);
+    assert.equal(result.tasks.includes('release-tools:test'), false);
+  }
+  const result = effects(paths.githubScriptsReleaseCandidateLibMts);
+  assert.equal(result.tasks.includes('release-tools:test'), true);
+  assert.equal(result.tasks.includes('release-tools:graph-unit'), false);
+});
+
+test('workflow changes run workflow checks without rebuilding product artifacts', () => {
+  const result = effects(paths.githubWorkflowsCiYml);
+  assert.deepEqual(result.jobs, ['affected']);
+  assert.equal(result.tasks.includes('ci-workflows:check'), true);
+  assert.equal(result.tasks.includes('release-tools:metadata'), true);
+});
+
+test('release helper changes invalidate only their product artifacts', () => {
+  const kotlin = effects(paths.sdksKotlinToolsStageReleaseArtifactsMts);
+  assert.deepEqual(kotlin.jobs, [
+    'affected',
+    'extension-artifacts-native',
+    'js-sdk-package',
+    'kotlin-maven-staging',
+    'kotlin-sdk-package',
+    'liboliphaunt-native-android',
+    'liboliphaunt-native-android-abi',
+    'liboliphaunt-native-ios',
+    'liboliphaunt-native-ios-abi',
+    'mobile-build-android',
+    'mobile-extension-packages',
+    'react-native-sdk-package',
+  ]);
+  // The selected Expo build installs RN with its packed query dependency.
+  assert.deepEqual(kotlin.jobTargets['js-sdk-package'], [
+    'database-resources:package-icu',
+    'oliphaunt-query-ts:package',
+  ]);
+
+  const nodeDirect = effects(paths.sdksTsNodeAddonToolsCheckReleaseAssetsMts);
+  assert.deepEqual(
+    nodeDirect.jobs,
+    [...NATIVE_TS_CONSUMER_JOBS, 'node-direct-release-assets'].sort(),
+  );
+});
+
+test('product Moon topology selects the focused release graph proof', () => {
+  const result = effects(paths.sdksTsSdkMoonYml);
+  assert.deepEqual(result.jobs, NATIVE_TS_CONSUMER_JOBS);
+  assert.equal(result.tasks.includes('release-tools:graph-unit'), true);
+  assert.equal(result.tasks.includes('release-tools:test'), false);
+});
+
+test('JavaScript release metadata does not rebuild unrelated products', () => {
+  const result = effects(paths.sdksTsSdkReleaseToml);
+  assert.deepEqual(result.jobs, NATIVE_TS_CONSUMER_JOBS);
+  assert.deepEqual(result.releaseProducts, ['oliphaunt-js']);
+  assert.equal(result.tasks.includes('release-tools:graph-unit'), true);
+  assert.equal(result.tasks.includes('release-tools:metadata'), true);
+  assert.equal(result.tasks.includes('release-tools:test'), false);
+  for (const target of [
+    'oliphaunt-broker:build-release-assets',
+    'oliphaunt-react-native:package',
+    'oliphaunt-swift:package',
+    'oliphaunt-wasix-napi:build-release-assets',
+  ]) {
+    assert.equal(
+      result.tasks.includes(target),
+      false,
+      `${target} is unrelated to the JavaScript SDK`,
+    );
+  }
+});
+
+test('release-please bookkeeping does not rebuild product artifacts', () => {
+  const result = effects(paths.releasePleaseManifestJson);
+  assert.deepEqual(result.jobs, ['affected']);
+  assert.equal(result.tasks.includes('release-tools:graph-unit'), true);
+  assert.equal(result.tasks.includes('release-tools:metadata'), true);
+  assert.equal(result.tasks.includes('release-tools:test'), false);
+  assert.equal(
+    result.tasks.some((target) =>
+      /:(aggregate-release-assets|package-artifacts|release-assets|[a-z-]+-sdk-package)$/u.test(
+        target,
+      ),
+    ),
+    false,
+  );
+});
+
+test('extension sources select shared builders without leaf package wrappers', () => {
+  for (const relativePath of [
+    paths.extensionsExternalPgUuidv7SourceToml,
+    paths.extensionsContribCarriersToml,
+  ]) {
+    const result = effects(relativePath);
+    for (const job of [
+      'extension-artifacts-native',
+      'extension-artifacts-wasix',
+      'extension-packages',
+    ]) {
+      assert.equal(result.jobs.includes(job), true, `${relativePath} must select ${job}`);
+    }
+    assert.equal(
+      result.tasks.some((target) => /^oliphaunt-extension-[^:]+:package$/u.test(target)),
+      false,
+      `${relativePath} must not need a duplicate leaf package task`,
+    );
+  }
+});
+
+test('extension package tooling invalidates packaging without changing builders', () => {
+  const result = effects(paths.extensionsArtifactsPackagesToolsPackageReleaseAssetsSh);
+  assert.equal(result.tasks.includes('extension-packages:package'), true);
+  assert.equal(result.tasks.includes('extension-packages:package-mobile'), false);
+  for (const target of [
+    'extension-artifacts-native:build-target',
+    'extension-artifacts-wasix:build-target',
+    'liboliphaunt-wasix:runtime-portable',
+    'oliphaunt-rust:test-extensions',
+  ]) {
+    assert.equal(
+      result.tasks.includes(target),
+      false,
+      `${target} does not consume package tooling`,
+    );
+  }
+});
+
+test('native producer host coverage is narrowed only for explicitly bounded dependency consumers', () => {
+  const sdk = effects(paths.sdksTsSdkSrcClientTs);
+  for (const job of ['liboliphaunt-native-desktop', 'broker-runtime', 'node-direct']) {
+    assert.deepEqual(
+      [...dependencyPlatformTargets(job, new Set(sdk.directTasks))],
+      ['linux-x64-gnu'],
+    );
+  }
+  for (const [source, job] of [
+    [paths.runtimesLiboliphauntNativeSrcLiboliphauntProcessC, 'liboliphaunt-native-desktop'],
+    [paths.brokerSrcMainRs, 'broker-runtime'],
+    [paths.sdksTsNodeAddonSrcLibRs, 'node-direct'],
+  ]) {
+    assert.equal(dependencyPlatformTargets(job, new Set(effects(source).directTasks)), null);
+  }
+});
+
+test('mixed SDK and query releases retain the Linux native consumer alongside mobile targets', () => {
+  const plan = planForReleaseProducts(['oliphaunt-js', 'oliphaunt-query-ts'], 'a'.repeat(40));
+  assert(plan.jobs.includes('native-consumers'));
+  assert(
+    plan.liboliphaunt_native_desktop_runtime_matrix.include.some(
+      (row) => row.target === 'linux-x64-gnu',
+    ),
+  );
+});
diff --git a/tools/ci/ci-plan-test-inputs.mts b/tools/ci/ci-plan-test-inputs.mts
new file mode 100644
index 000000000..7f9f73eb3
--- /dev/null
+++ b/tools/ci/ci-plan-test-inputs.mts
@@ -0,0 +1,116 @@
+// Sample changes exercised by CI planning tests; never used for production affectedness.
+export const paths = {
+  wasixRuntimeCarrierSource: 'src/runtimes/liboliphaunt-wasix/crates/assets/src/lib.rs',
+  wasixToolsCarrierSource: 'src/postgres-tools/wasix/crates/tools/src/lib.rs',
+  icuCarrierSource: 'src/database-resources/icu/cargo/src/lib.rs',
+  mobileBindingSource: 'src/sdks/rust/mobile-bindings/src/lib.rs',
+  nativeBindingProtocolTest: 'src/sdks/rust/liboliphaunt-native/tests/protocol_input.rs',
+  sdksRustQuerySrcLibRs: 'src/sdks/rust-query/src/lib.rs',
+  sdksRustWasixSrcLibRs: 'src/sdks/rust-wasix/src/lib.rs',
+  postgresToolsWasixToolsBuildPortableSh: 'src/postgres-tools/wasix/tools/build-portable.sh',
+  extensionsArtifactsWasixToolsBuildPortableSh:
+    'src/extensions/artifacts/wasix/tools/build-portable.sh',
+  sdksTsQuerySrcQueryTs: 'src/sdks/ts-query/src/query.ts',
+  sdksRustLiboliphauntNativeSrcLibRs: 'src/sdks/rust/liboliphaunt-native/src/lib.rs',
+  sdksTsSdkSrcClientTs: 'src/sdks/ts/sdk/src/client.ts',
+  sdksTsSdkREADMEMd: 'src/sdks/ts/sdk/README.md',
+  sdksTsWasixNodeAddonREADMEMd: 'src/sdks/ts-wasix/node-addon/README.md',
+  sdksTsQueryREADMEMd: 'src/sdks/ts-query/README.md',
+  extensionsEvidenceRuns20260607TransitionalCatalogSmokeJson:
+    'src/extensions/evidence/runs/2026-06-07-transitional-catalog-smoke.json',
+  sdksTsNodeAddonSrcLibRs: 'src/sdks/ts/node-addon/src/lib.rs',
+  runtimesLiboliphauntNativeSrcLiboliphauntProcessC:
+    'src/runtimes/liboliphaunt-native/src/liboliphaunt_process.c',
+  sdksTsWasixNodeAddonSrcLibRs: 'src/sdks/ts-wasix/node-addon/src/lib.rs',
+  sdksTsWasixNodeAddonToolsPackageContractTestMts:
+    'src/sdks/ts-wasix/node-addon/tools/package-contract.test.mts',
+  brokerToolsCreateReleaseFixtureMts: 'src/broker/tools/create-release-fixture.mts',
+  brokerToolsBrokerDependencyLicenseContractTestMts:
+    'src/broker/tools/broker-dependency-license-contract.test.mts',
+  runtimesLiboliphauntWasixToolsCargoTestFilterSh:
+    'src/runtimes/liboliphaunt-wasix/tools/cargo-test-filter.sh',
+  extensionsArtifactsWasixToolsPackageReleaseAssetsMts:
+    'src/extensions/artifacts/wasix/tools/package-release-assets.mts',
+  runtimesLiboliphauntWasixVERSION: 'src/runtimes/liboliphaunt-wasix/VERSION',
+  runtimesLiboliphauntWasixReleaseToml: 'src/runtimes/liboliphaunt-wasix/release.toml',
+  extensionsArtifactsNativeToolsPackageReleaseAssetsSh:
+    'src/extensions/artifacts/native/tools/package-release-assets.sh',
+  runtimesLiboliphauntNativeToolsPackageLiboliphauntMobileAssetsSh:
+    'src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-mobile-assets.sh',
+  runtimesLiboliphauntNativeToolsPackageLiboliphauntLinuxAssetsSh:
+    'src/runtimes/liboliphaunt-native/tools/package-liboliphaunt-linux-assets.sh',
+  runtimesLiboliphauntNativeSmokeLiboliphauntSmokeC:
+    'src/runtimes/liboliphaunt-native/smoke/liboliphaunt_smoke.c',
+  configNextestToml: '.config/nextest.toml',
+  sdksReactNativeSrcIndexTs: 'src/sdks/react-native/src/index.ts',
+  extensionsExternalVectorSourceToml: 'src/extensions/external/vector/source.toml',
+  runtimesWasixBrowserHostSourceToml: 'src/runtimes/wasix-browser-host/source.toml',
+  CargoLock: 'Cargo.lock',
+  docsSrcAppDocsLayoutTsx: 'src/docs/src/app/docs/layout.tsx',
+  sdksTsWasixSdkToolsPgwireClientMts: 'src/sdks/ts-wasix/sdk/tools/pgwire-client.mts',
+  sdksTsWasixNodeAddonToolsPackagePlatformSh:
+    'src/sdks/ts-wasix/node-addon/tools/package-platform.sh',
+  toolsDevDenoSh: 'tools/dev/deno.sh',
+  runtimesLiboliphauntWasixToolsWasixAotManifestMts:
+    'src/runtimes/liboliphaunt-wasix/tools/wasix-aot-manifest.mts',
+  toolsGraphCiPlanMts: 'tools/ci/ci_plan.mts',
+  moonTasksJavascriptQualityYml: '.moon/tasks/javascript-quality.yml',
+  githubWorkflowsCiYml: '.github/workflows/ci.yml',
+  githubScriptsReleaseCandidateLibMts: '.github/scripts/release-candidate-lib.mts',
+  sdksKotlinToolsStageReleaseArtifactsMts: 'src/sdks/kotlin/tools/stage-release-artifacts.mts',
+  sdksTsNodeAddonToolsCheckReleaseAssetsMts:
+    'src/sdks/ts/node-addon/tools/check-release-assets.mts',
+  sdksTsSdkMoonYml: 'src/sdks/ts/sdk/moon.yml',
+  sdksTsSdkReleaseToml: 'src/sdks/ts/sdk/release.toml',
+  releasePleaseManifestJson: '.release-please-manifest.json',
+  extensionsExternalPgUuidv7SourceToml: 'src/extensions/external/pg_uuidv7/source.toml',
+  extensionsContribCarriersToml: 'src/extensions/contrib/carriers.toml',
+  extensionsArtifactsPackagesToolsPackageReleaseAssetsSh:
+    'src/extensions/artifacts/packages/tools/package-release-assets.sh',
+  brokerSrcMainRs: 'src/broker/src/main.rs',
+  runtimesLiboliphauntWasixPostmasterSourcesWasmerToml:
+    'src/runtimes/liboliphaunt-wasix-postmaster/sources/wasmer.toml',
+  thirdPartyToolsSourceFetchCoreTestMts: 'src/third-party/tools/source-fetch-core.test.mts',
+  thirdPartyToolsSourceFetchCoreMts: 'src/third-party/tools/source-fetch-core.mts',
+  thirdPartyPostgresFetchSourceTestSh: 'src/third-party/postgres/fetch-source.test.sh',
+  runtimesLiboliphauntWasixPostmasterWasmerREADMEMd:
+    'src/runtimes/liboliphaunt-wasix-postmaster/wasmer/README.md',
+  runtimesLiboliphauntWasixPostmasterWasmerCapabilitiesTsv:
+    'src/runtimes/liboliphaunt-wasix-postmaster/wasmer/capabilities.tsv',
+  runtimesLiboliphauntWasixPostmasterWasmerBinVerifyPostmasterConcurrencyContractTestMts:
+    'src/runtimes/liboliphaunt-wasix-postmaster/wasmer/bin/verify-postmaster-concurrency-contract.test.mts',
+  srcSourcesThirdPartyNativeREADMEMd: 'src/sources/third-party/native/README.md',
+  toolsDevMaestroToml: 'tools/dev/maestro.toml',
+  postgresToolsWasixCratesToolsSrcLibRs: 'src/postgres-tools/wasix/crates/tools/src/lib.rs',
+  runtimesLiboliphauntWasixToolsXtaskSrcMainRs:
+    'src/runtimes/liboliphaunt-wasix/tools/xtask/src/main.rs',
+  runtimesLiboliphauntWasixAssetsBuildDockerInstallPinnedWasixccSh:
+    'src/runtimes/liboliphaunt-wasix/assets/build/docker/install-pinned-wasixcc.sh',
+  docsInternalOLIPHAUNTPATCHSTACKMd: 'src/docs/internal/OLIPHAUNT_PATCH_STACK.md',
+  runtimesLiboliphauntWasixPostmasterExecutorSrcExecuteRs:
+    'src/runtimes/liboliphaunt-wasix-postmaster/executor/src/execute.rs',
+  runtimesLiboliphauntWasixPostmasterToolsMergeProductReleaseAssetsMts:
+    'src/runtimes/liboliphaunt-wasix-postmaster/tools/merge-product-release-assets.mts',
+  extensionsTestsNativeToolsRunNativeExtensionLifecycleProofSh:
+    'src/extensions/tests/native/tools/run-native-extension-lifecycle-proof.sh',
+  extensionsTestsNativeSrcMainRs: 'src/extensions/tests/native/src/main.rs',
+  runtimesLiboliphauntWasixPostmasterLibProcessSupervisionSh:
+    'src/runtimes/liboliphaunt-wasix-postmaster/lib/process-supervision.sh',
+};
+export const taskRoots = {
+  oliphauntWasixRustTestAot: 'oliphaunt-wasix-rust:test-aot',
+  liboliphauntWasixRuntimeAot: 'liboliphaunt-wasix:runtime-aot',
+  oliphauntSwiftPackageBindings: 'oliphaunt-swift:package-bindings',
+  oliphauntSwiftPackage: 'oliphaunt-swift:package',
+  oliphauntJsPackage: 'oliphaunt-js:package',
+  extensionArtifactsNativeBuildTarget: 'extension-artifacts-native:build-target',
+  extensionArtifactsWasixBuildTarget: 'extension-artifacts-wasix:build-target',
+  oliphauntReactNativeTest: 'oliphaunt-react-native:test',
+  liboliphauntWasixPostmasterPreparePostgres: 'liboliphaunt-wasix-postmaster:prepare-postgres',
+  liboliphauntWasixPostmasterPortableInputs: 'liboliphaunt-wasix-postmaster:portable-inputs',
+  liboliphauntWasixPostmasterReleaseAssets: 'liboliphaunt-wasix-postmaster:release-assets',
+  postgresToolsWasixBuildAot: 'postgres-tools-wasix:build-aot',
+  extensionArtifactsWasixBuildAot: 'extension-artifacts-wasix:build-aot',
+};
+export const combinedNativeWasix = [paths.sdksTsWasixNodeAddonSrcLibRs, paths.sdksTsSdkSrcClientTs];
+export const affectedInputs = [...Object.values(paths).map((file) => [file]), combinedNativeWasix];
diff --git a/tools/ci/ci-plan-test-observations.mts b/tools/ci/ci-plan-test-observations.mts
new file mode 100644
index 000000000..8238d6b34
--- /dev/null
+++ b/tools/ci/ci-plan-test-observations.mts
@@ -0,0 +1,33 @@
+import { createHash } from 'node:crypto';
+import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { affectedInputs, taskRoots } from './ci-plan-test-inputs.mts';
+
+function key(value) {
+  return createHash('sha256').update(JSON.stringify(value)).digest('hex');
+}
+function observation(kind, input) {
+  const directory = process.env.OLIPHAUNT_CI_TEST_OBSERVATIONS;
+  if (!directory) throw new Error('run through tools/ci/check-workflows.sh');
+  return JSON.parse(readFileSync(path.join(directory, `${kind}-${key(input)}.json`), 'utf8'));
+}
+export function affectedObservation(input) {
+  return observation('affected', Array.isArray(input) ? input : [input]);
+}
+export function taskObservation(target) {
+  return Object.values(observation('task', target).data);
+}
+
+if (import.meta.main) {
+  const directory = process.argv[2];
+  if (!directory) throw new Error('expected observation directory');
+  mkdirSync(directory, { recursive: true });
+  const requests = [];
+  for (const input of affectedInputs) {
+    const id = key(input);
+    writeFileSync(path.join(directory, `affected-${id}.input`), input.join('\n') + '\n');
+    requests.push(`affected\t${id}`);
+  }
+  for (const target of Object.values(taskRoots)) requests.push(`task\t${key(target)}\t${target}`);
+  writeFileSync(path.join(directory, 'requests.tsv'), requests.join('\n') + '\n');
+}
diff --git a/tools/ci/ci-plan-wasix-postmaster-release.test.mts b/tools/ci/ci-plan-wasix-postmaster-release.test.mts
new file mode 100644
index 000000000..533e6d777
--- /dev/null
+++ b/tools/ci/ci-plan-wasix-postmaster-release.test.mts
@@ -0,0 +1,246 @@
+import { affectedObservation, taskObservation } from './ci-plan-test-observations.mts';
+import { paths, taskRoots } from './ci-plan-test-inputs.mts';
+import assert from 'node:assert/strict';
+import { test } from 'node:test';
+import { buildPlan, loadGraph, normalizeFiles } from '../release/release-graph.mts';
+import { affectedNames, triggeringProjectNames, triggeringTaskNames } from './affected.mts';
+import {
+  CI_JOB_TARGETS,
+  planJobsForAffected,
+  renderPlanWithSelection,
+  selectedExtensionProductsForPlan,
+} from './ci_plan.mts';
+
+const taskGraph = taskObservation;
+
+test('postmaster CI selects only terminal product roots', () => {
+  assert.deepEqual(CI_JOB_TARGETS['wasix-postmaster'], [
+    'liboliphaunt-wasix-postmaster:finalize-release-assets',
+    'liboliphaunt-wasix-postmaster:portable-inputs',
+    'liboliphaunt-wasix-postmaster:release-assets',
+  ]);
+});
+
+test('postmaster planner renders every supported release target', () => {
+  const plan = renderPlanWithSelection({
+    jobs: new Set(['affected', 'wasix-postmaster']),
+    projects: new Set(),
+    tasks: new Set(CI_JOB_TARGETS['wasix-postmaster']),
+    reason: 'postmaster planner fixture',
+    selectedTargets: null,
+    selectedExtensionProducts: new Set(),
+    qualificationMode: 'affected',
+    qualificationBaseSha: 'base-sha',
+    qualificationHeadSha: 'head-sha',
+  });
+  assert.equal(plan.qualification_mode, 'affected');
+  assert.equal(plan.qualification_base_sha, 'base-sha');
+  assert.equal(plan.qualification_head_sha, 'head-sha');
+  assert.deepEqual(
+    plan.liboliphaunt_wasix_postmaster_runtime_matrix.include.map(({ target_id }) => target_id),
+    ['linux-arm64-gnu', 'linux-x64-gnu', 'macos-arm64'],
+  );
+
+  const planWithoutPostmaster = renderPlanWithSelection({
+    jobs: new Set(['affected']),
+    projects: new Set(),
+    tasks: new Set(),
+    reason: 'non-postmaster planner fixture',
+    selectedTargets: null,
+    selectedExtensionProducts: new Set(),
+  });
+  assert.deepEqual(planWithoutPostmaster.liboliphaunt_wasix_postmaster_runtime_matrix, {
+    include: [],
+  });
+  assert.equal(planWithoutPostmaster.qualification_mode, 'full-payload');
+  assert.equal(planWithoutPostmaster.qualification_base_sha, null);
+  assert.equal(planWithoutPostmaster.qualification_head_sha, null);
+});
+
+test('postmaster source preparation waits for the shared source fetch', () => {
+  const task = taskGraph(taskRoots.liboliphauntWasixPostmasterPreparePostgres).find(
+    ({ target }) => target === 'liboliphaunt-wasix-postmaster:prepare-postgres',
+  );
+  assert.ok(task);
+  assert.equal(
+    task.deps.some(
+      ({ target }) => target === 'source-inputs:source-fetch-wasix-postmaster-runtime',
+    ),
+    true,
+  );
+});
+
+test('postmaster production and qualification roots stay separate', () => {
+  const patchTests = 'liboliphaunt-wasix-postmaster:runtime-patch-tests';
+  const targets = (root) => new Set(taskGraph(root).map(({ target }) => target));
+  const portableProduction = targets(taskRoots.liboliphauntWasixPostmasterPortableInputs);
+  const targetProduction = targets(taskRoots.liboliphauntWasixPostmasterReleaseAssets);
+  assert.equal(portableProduction.has(patchTests), false);
+  assert.equal(targetProduction.has(patchTests), false);
+  for (const behavior of [
+    'liboliphaunt-wasix-postmaster:backend-wave-stress',
+    'liboliphaunt-wasix-postmaster:immediate-recovery',
+    'liboliphaunt-wasix-postmaster:linear-memory-integration',
+  ]) {
+    assert.equal(targetProduction.has(behavior), false);
+  }
+});
+
+function directEffects(relativePath) {
+  const affected = affectedObservation(relativePath);
+  const projects = triggeringProjectNames(affected.projects);
+  const directTasks = triggeringTaskNames(affected.tasks);
+  const tasks = affectedNames(affected.tasks);
+  const jobs = [...planJobsForAffected(new Set(directTasks))].sort();
+  return { projects, directTasks, tasks, jobs };
+}
+
+function assertReleaseSelection(relativePath) {
+  const effects = directEffects(relativePath);
+  assert.equal(effects.projects.includes('liboliphaunt-wasix-postmaster'), true);
+  assert.equal(effects.jobs.includes('wasix-postmaster'), true);
+
+  const releasePlan = buildPlan(
+    loadGraph('ci-plan-wasix-postmaster-release.test.mts'),
+    normalizeFiles([relativePath]),
+    'ci-plan-wasix-postmaster-release.test.mts',
+  );
+  assert.equal(releasePlan.hasReleaseChanges, true);
+  assert.equal(releasePlan.releaseProducts.includes('liboliphaunt-wasix-postmaster'), true);
+}
+
+function assertNativeExtensionLifecycleSelection(relativePath) {
+  const effects = directEffects(relativePath);
+  assert.equal(effects.tasks.includes('native-extension-lifecycle:lifecycle'), true);
+  assert.equal(effects.jobs.includes('native-extension-lifecycle'), true);
+  const jobs = new Set(effects.jobs);
+  const projects = new Set(effects.projects);
+  const tasks = new Set(effects.directTasks);
+  const plan = renderPlanWithSelection({
+    jobs,
+    projects,
+    tasks,
+    reason: relativePath,
+    selectedTargets: null,
+    selectedExtensionProducts: selectedExtensionProductsForPlan(projects, tasks, jobs),
+  });
+  assert.ok(plan.native_extension_lifecycle_sql_names.includes('vector'));
+  const producer = plan.extension_artifacts_native_matrix.include.find(
+    (row) => row.target === 'linux-x64-gnu',
+  );
+  assert.ok(producer, 'the lifecycle runner needs a Linux extension producer');
+  for (const name of plan.native_extension_lifecycle_sql_names) {
+    assert.ok(producer.sql_names_csv.split(',').includes(name), `${name} needs a producer`);
+  }
+}
+
+test('postmaster build-input pins select its builder and release', () => {
+  assertReleaseSelection(paths.runtimesLiboliphauntWasixPostmasterSourcesWasmerToml);
+});
+
+test('source fetch unit fixtures do not rebuild product artifacts', () => {
+  const effects = directEffects(paths.thirdPartyToolsSourceFetchCoreTestMts);
+  assert.deepEqual(effects.jobs, ['affected']);
+  assert.equal(effects.tasks.includes('source-inputs:test'), true);
+  assert.equal(
+    effects.tasks.some((target) => target.startsWith('source-inputs:source-fetch-')),
+    false,
+  );
+});
+
+test('source fetch implementation changes retain their real consumers', () => {
+  const effects = directEffects(paths.thirdPartyToolsSourceFetchCoreMts);
+  for (const target of [
+    'extension-artifacts-native:build-target',
+    'liboliphaunt-native:build-runtime-desktop-target',
+    'liboliphaunt-wasix-postmaster:prepare-runtime',
+    'liboliphaunt-wasix:compiler-output',
+  ]) {
+    assert.equal(effects.tasks.includes(target), true, `${target} must consume source fetching`);
+  }
+});
+
+test('source prose, transport tests, and unrelated toolchains do not rebuild runtimes', () => {
+  const cases = [
+    [paths.thirdPartyPostgresFetchSourceTestSh, 'source-inputs:test'],
+    [paths.runtimesLiboliphauntWasixPostmasterWasmerREADMEMd, null],
+    [paths.runtimesLiboliphauntWasixPostmasterWasmerCapabilitiesTsv, null],
+    [
+      paths.runtimesLiboliphauntWasixPostmasterWasmerBinVerifyPostmasterConcurrencyContractTestMts,
+      'liboliphaunt-wasix-postmaster:test',
+    ],
+    [paths.srcSourcesThirdPartyNativeREADMEMd, null],
+    [paths.toolsDevMaestroToml, 'ci-workflows:check'],
+  ];
+  for (const [relativePath, expectedTask] of cases) {
+    const effects = directEffects(relativePath);
+    if (expectedTask !== null) assert.equal(effects.tasks.includes(expectedTask), true);
+    for (const target of [
+      'liboliphaunt-native:package-runtime-desktop-target',
+      'liboliphaunt-wasix-postmaster:prepare-runtime',
+      'liboliphaunt-wasix:runtime-portable',
+    ]) {
+      assert.equal(
+        effects.tasks.includes(target),
+        false,
+        `${target} does not consume ${relativePath}`,
+      );
+    }
+  }
+});
+
+test('runtime shell lint follows executable inputs without documentation gates', () => {
+  for (const relativePath of [
+    paths.extensionsExternalVectorSourceToml,
+    paths.postgresToolsWasixCratesToolsSrcLibRs,
+    paths.runtimesLiboliphauntWasixToolsXtaskSrcMainRs,
+  ]) {
+    const effects = directEffects(relativePath);
+    assert.equal(effects.tasks.includes('liboliphaunt-wasix:lint'), false);
+  }
+  assert.equal(
+    directEffects(
+      paths.runtimesLiboliphauntWasixAssetsBuildDockerInstallPinnedWasixccSh,
+    ).tasks.includes('liboliphaunt-wasix:lint'),
+    true,
+  );
+  assert.equal(
+    directEffects(paths.docsInternalOLIPHAUNTPATCHSTACKMd).tasks.includes(
+      'liboliphaunt-native:lint',
+    ),
+    false,
+  );
+});
+
+test('postmaster runtime changes select its production builder and release', () => {
+  assertReleaseSelection(paths.runtimesLiboliphauntWasixPostmasterExecutorSrcExecuteRs);
+});
+
+test('postmaster aggregate helper invalidates the product finalizer', () => {
+  const effects = directEffects(
+    paths.runtimesLiboliphauntWasixPostmasterToolsMergeProductReleaseAssetsMts,
+  );
+  assert.equal(effects.projects.includes('release-tools'), false);
+  assert.equal(effects.projects.includes('liboliphaunt-wasix-postmaster'), true);
+  assert.equal(
+    effects.tasks.includes('liboliphaunt-wasix-postmaster:finalize-release-assets'),
+    true,
+  );
+  assert.equal(effects.jobs.includes('wasix-postmaster'), true);
+});
+
+test('native lifecycle runner changes select its exact hosted proof', () => {
+  assertNativeExtensionLifecycleSelection(
+    paths.extensionsTestsNativeToolsRunNativeExtensionLifecycleProofSh,
+  );
+});
+
+test('native lifecycle proof source selects its exact hosted proof', () => {
+  assertNativeExtensionLifecycleSelection(paths.extensionsTestsNativeSrcMainRs);
+});
+
+test('native lifecycle supervisor changes select its exact hosted proof', () => {
+  assertNativeExtensionLifecycleSelection(
+    paths.runtimesLiboliphauntWasixPostmasterLibProcessSupervisionSh,
+  );
+});
diff --git a/tools/ci/ci-plan.sh b/tools/ci/ci-plan.sh
new file mode 100644
index 000000000..f285b1faf
--- /dev/null
+++ b/tools/ci/ci-plan.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+while IFS= read -r name; do
+  case "$name" in PROTO_*) unset "$name" ;; esac
+done < <(compgen -e)
+moon_bin="${MOON_BIN:-moon}"
+expected=$(sed -n 's/^moon *= *"\([^"]*\)".*/\1/p' .prototools)
+if [[ -z "$expected" || "$("$moon_bin" --version)" != "moon $expected" ]]; then
+  echo "Moon $expected is required" >&2
+  exit 1
+fi
+plan_dir=$(mktemp -d)
+trap 'rm -rf "$plan_dir"' EXIT
+export OLIPHAUNT_MOON_TASK_GRAPH_FILE="$plan_dir/graph.json"
+export OLIPHAUNT_MOON_AFFECTED_FILE="$plan_dir/affected.json"
+if [[ $# == 0 && (${CI_GENERATED_RELEASE_PR:-false} == true || (${GITHUB_EVENT_NAME:-} == push && ${GITHUB_REF:-} == refs/heads/main)) ]]; then
+  : "${MOON_HEAD:?MOON_HEAD is required for automatic release qualification}"
+  subject="$(git show -s --format=%s "$MOON_HEAD")"
+  if [[ ${CI_GENERATED_RELEASE_PR:-false} == true || "$subject" == 'chore(release): '* ]]; then
+    read -r _ parent extra <<<"$(git rev-list --parents -n 1 "$MOON_HEAD")"
+    [[ -n "$parent" && -z "$extra" ]] || {
+      echo 'release qualification requires a one-parent candidate' >&2
+      exit 1
+    }
+    git show "$MOON_HEAD:release-please-config.json" >"$plan_dir/config.json"
+    git show "$parent:.release-please-manifest.json" >"$plan_dir/before.json"
+    git show "$MOON_HEAD:.release-please-manifest.json" >"$plan_dir/after.json"
+    CI_RELEASE_PRODUCTS_JSON="$(bash tools/dev/bun.sh tools/release/verify-release-commit.mts --manifest-transition "$plan_dir/config.json" "$plan_dir/before.json" "$plan_dir/after.json")"
+    export CI_RELEASE_PRODUCTS_JSON
+  fi
+fi
+"$moon_bin" task-graph --json >"$OLIPHAUNT_MOON_TASK_GRAPH_FILE"
+if [[ $# == 0 && ${GITHUB_EVENT_NAME:-} != workflow_dispatch && (-z ${CI_RELEASE_PRODUCTS_JSON:-} || ${CI_RELEASE_PRODUCTS_JSON:-} == '[]') ]]; then
+  : "${MOON_BASE:?MOON_BASE is required for affected CI planning}"
+  : "${MOON_HEAD:?MOON_HEAD is required for affected CI planning}"
+  "$moon_bin" query affected --upstream none --downstream deep "$OLIPHAUNT_MOON_AFFECTED_FILE"
+fi
+bash tools/dev/bun.sh tools/ci/ci_plan.mts "$@"
diff --git a/tools/ci/ci-release-scope.test.mts b/tools/ci/ci-release-scope.test.mts
new file mode 100644
index 000000000..e7e0069a2
--- /dev/null
+++ b/tools/ci/ci-release-scope.test.mts
@@ -0,0 +1,34 @@
+import assert from 'node:assert/strict';
+import { readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+const [phase, directory, head] = process.argv.slice(2);
+if (phase === 'bump' || phase === 'invalid') {
+  const file = path.join(directory, '.release-please-manifest.json');
+  const manifest = JSON.parse(readFileSync(file, 'utf8'));
+  if (phase === 'invalid') manifest['unowned-product'] = '1.0.0';
+  else {
+    const config = JSON.parse(
+      readFileSync(path.join(directory, 'release-please-config.json'), 'utf8'),
+    );
+    const owner = Object.entries(config.packages).find(
+      ([, value]) => value.component === 'oliphaunt-js',
+    )?.[0];
+    assert.ok(owner, 'native TypeScript release owner must exist');
+    manifest[owner] = '99.0.0';
+  }
+  writeFileSync(file, JSON.stringify(manifest));
+} else if (phase === 'assert') {
+  for (const event of ['pull_request', 'push']) {
+    const output = readFileSync(path.join(directory, `${event}.out`), 'utf8');
+    assert.match(output, /qualification_mode=selected-products/);
+    assert(output.includes(`qualification_head_sha=${head}`));
+    assert.match(output, /qualification_products=\["oliphaunt-js"\]/);
+  }
+  assert.match(
+    readFileSync(path.join(directory, 'invalid.err'), 'utf8'),
+    /changed unknown package path/,
+  );
+  console.log(
+    'release PR and main select the same Git-derived product scope; unknown owner rejected',
+  );
+} else throw new Error('run through ci-release-scope.test.sh');
diff --git a/tools/ci/ci-release-scope.test.sh b/tools/ci/ci-release-scope.test.sh
new file mode 100644
index 000000000..2702b6e81
--- /dev/null
+++ b/tools/ci/ci-release-scope.test.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+set -euo pipefail
+root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-release-ci-scope.XXXXXX")"
+trap 'rm -rf "$scratch"' EXIT
+repo="$scratch/repo"
+git init -q "$repo"
+git -C "$repo" config user.name Fixture
+git -C "$repo" config user.email fixture@example.invalid
+cp "$root/release-please-config.json" "$root/.release-please-manifest.json" "$root/.prototools" "$repo/"
+git -C "$repo" add .
+git -C "$repo" commit -qm 'feat: initial products'
+before="$(git -C "$repo" rev-parse HEAD)"
+bash "$root/tools/dev/bun.sh" "$root/tools/ci/ci-release-scope.test.mts" bump "$repo"
+git -C "$repo" add .
+git -C "$repo" commit -qm 'chore(release): prepare products'
+head="$(git -C "$repo" rev-parse HEAD)"
+ln -s "$root/tools" "$repo/tools"
+cat > "$repo/moon" <<'SH'
+#!/usr/bin/env bash
+set -eu
+case "$1" in
+  --version) echo "moon $FIXTURE_MOON_VERSION" ;;
+  task-graph) cat "$FIXTURE_TASK_GRAPH" ;;
+  *) echo 'unexpected affected query' >&2; exit 82 ;;
+esac
+SH
+chmod +x "$repo/moon"
+export MOON_BIN="$repo/moon"
+FIXTURE_MOON_VERSION="$(sed -n 's/^moon *= *"\([^"]*\)".*/\1/p' "$root/.prototools")"
+export FIXTURE_MOON_VERSION
+export FIXTURE_TASK_GRAPH="${OLIPHAUNT_MOON_TASK_GRAPH_FILE:?expected captured Moon graph}"
+export MOON_BASE="$before" MOON_HEAD="$head" GITHUB_REF=refs/heads/main
+export CI_RELEASE_PRODUCTS_JSON='[]' GITHUB_OUTPUT='' WASM_TARGET=all NATIVE_TARGET=all MOBILE_TARGET=all
+cd "$repo"
+for event in pull_request push; do
+  export GITHUB_EVENT_NAME="$event"
+  if [[ "$event" == pull_request ]]; then export CI_GENERATED_RELEASE_PR=true;
+  else export CI_GENERATED_RELEASE_PR=false; fi
+  bash "$root/tools/ci/ci-plan.sh" > "$scratch/$event.out"
+done
+bash "$root/tools/dev/bun.sh" "$root/tools/ci/ci-release-scope.test.mts" invalid "$repo"
+git add .release-please-manifest.json
+git commit -qm 'chore(release): invalid product'
+export MOON_BASE="$head"
+MOON_HEAD="$(git rev-parse HEAD)"; export MOON_HEAD
+if bash "$root/tools/ci/ci-plan.sh" > "$scratch/invalid.out" 2> "$scratch/invalid.err"; then
+  echo 'unknown release owner was accepted' >&2; exit 1
+fi
+bash "$root/tools/dev/bun.sh" "$root/tools/ci/ci-release-scope.test.mts" assert "$scratch" "$head"
diff --git a/tools/ci/ci_plan.mts b/tools/ci/ci_plan.mts
new file mode 100644
index 000000000..b3df74807
--- /dev/null
+++ b/tools/ci/ci_plan.mts
@@ -0,0 +1,1247 @@
+#!/usr/bin/env bun
+// Map Moon affected tasks onto stable GitHub Actions jobs.
+//
+// Moon is the only project/task graph. Stable GitHub job names are selected
+// from Moon task tags named `ci-`. GitHub Actions still owns platform
+// matrix fan-out because runner OS, native target triples, and simulator/device
+// targets are CI execution details, not source projects.
+import { appendFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import {
+  brokerRuntimeMatrix,
+  extensionArtifactsNativeMatrix,
+  extensionArtifactsWasixMatrix,
+  liboliphauntNativeAndroidRuntimeMatrix,
+  liboliphauntNativeDesktopRuntimeMatrix,
+  liboliphauntNativeIosRuntimeMatrix,
+  liboliphauntNativeRuntimeTargetsForSurface,
+  liboliphauntWasixAotRuntimeMatrix,
+  liboliphauntWasixPostmasterRuntimeMatrix,
+  nodeDirectRuntimeMatrix,
+  reactNativeAndroidMobileAppMatrix,
+  wasixNapiRuntimeMatrix,
+} from '../release/artifact-target-matrix.mts';
+import {
+  compareText,
+  exactExtensionProducts,
+  exactExtensionReleaseProducts,
+  extensionPublicDependencySqlNames,
+  extensionSqlNames,
+  extensionSqlNamesForProducts,
+} from '../release/release-artifact-targets.mts';
+import { affectedNames, triggeringProjectNames, triggeringTaskNames } from './affected.mts';
+import { loadProducts, moonProjectsById } from '../release/release-graph.mts';
+import { qualificationRequestKey } from '../../.github/scripts/release-candidate-lib.mts';
+import {
+  publishedConsumerInventory,
+  validPublishedConsumerInventory,
+} from '../../src/sdks/ts/sdk/tools/published-consumer.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../..');
+const PREFIX = 'ci_plan.mts';
+
+export const BASE_JOBS = new Set(['affected']);
+export const ALWAYS_JOBS = new Set(BASE_JOBS);
+export const FULL_PAYLOAD_QUALIFICATION_MODE = 'full-payload';
+export const AFFECTED_QUALIFICATION_MODE = 'affected';
+export const PRODUCT_QUALIFICATION_MODE = 'selected-products';
+const NATIVE_RUNTIME_JOBS = new Set([
+  'liboliphaunt-native-android',
+  'liboliphaunt-native-desktop',
+  'liboliphaunt-native-ios',
+]);
+const NATIVE_RUNTIME_TASKS = new Set([
+  'liboliphaunt-native:package-runtime-desktop-target',
+  'liboliphaunt-native:package-runtime-android-arm64-v8a',
+  'liboliphaunt-native:package-runtime-android-x86_64',
+  'liboliphaunt-native:package-runtime-ios-xcframework',
+]);
+export const WASM_RUNTIME_JOBS = new Set([
+  'liboliphaunt-wasix-runtime',
+  'liboliphaunt-wasix-aot',
+  'liboliphaunt-wasix-release-assets',
+]);
+const MOBILE_JOB_SURFACES = {
+  'mobile-build-android': 'react-native-android',
+  'mobile-build-ios': 'react-native-ios',
+};
+const MOBILE_E2E_JOBS = {
+  'mobile-build-android': 'mobile-e2e-android',
+  'mobile-build-ios': 'mobile-e2e-ios',
+};
+const REACT_NATIVE_ANDROID_REPRESENTATIVE_TARGETS = new Set(['android-x86_64']);
+export const NATIVE_EXTENSION_LIFECYCLE_JOB = 'native-extension-lifecycle';
+export const NATIVE_EXTENSION_LIFECYCLE_AGGREGATE_JOB = 'native-extension-lifecycle-aggregate';
+export const NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT = 3;
+export const BROAD_EXTENSION_INPUT_PROJECTS = new Set([
+  'extension-artifacts-native',
+  'extension-artifacts-wasix',
+  'oliphaunt-extension-contrib-pg18',
+  'extension-packages',
+  'liboliphaunt-native',
+  'liboliphaunt-wasix',
+  'postgres18',
+  'third-party-native',
+  'third-party-shared',
+]);
+function fail(message) {
+  console.error(`${PREFIX}: ${message}`);
+  process.exit(2);
+}
+
+function affectedProjectsAndTasks() {
+  const affected = JSON.parse(readFileSync(process.env.OLIPHAUNT_MOON_AFFECTED_FILE, 'utf8'));
+  affectedNames(affected); // Reject malformed envelopes before defaulting omitted maps to empty.
+  return {
+    directProjects: new Set(triggeringProjectNames(affected.projects)),
+    projects: new Set(affectedNames(affected.projects)),
+    directTasks: new Set(triggeringTaskNames(affected.tasks)),
+  };
+}
+
+function stringList(value) {
+  if (!Array.isArray(value)) {
+    fail('expected a JSON string list');
+  }
+  return value.map((item) => String(item)).sort(compareText);
+}
+
+function setUnion(...sets) {
+  const result = new Set();
+  for (const set of sets) {
+    for (const item of set) {
+      result.add(item);
+    }
+  }
+  return result;
+}
+
+function intersects(left, right) {
+  for (const item of left) {
+    if (right.has(item)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+function sorted(set) {
+  return [...set].sort(compareText);
+}
+
+const TASKS_BY_TARGET = (() => {
+  if (!process.env.OLIPHAUNT_MOON_TASK_GRAPH_FILE)
+    fail('Moon task snapshot is required; use bash tools/ci/ci-plan.sh');
+  const graph = JSON.parse(readFileSync(process.env.OLIPHAUNT_MOON_TASK_GRAPH_FILE, 'utf8'));
+  if (graph.data === null || Array.isArray(graph.data) || typeof graph.data !== 'object') {
+    fail('moon task-graph did not return task data');
+  }
+  return new Map(Object.values(graph.data).map((task) => [task.target, task]));
+})();
+
+export function moonCiJobTargets() {
+  const jobs = new Map();
+  for (const task of TASKS_BY_TARGET.values()) {
+    for (const tag of task.tags ?? []) {
+      if (typeof tag === 'string' && tag.startsWith('ci-')) {
+        const job = tag.slice('ci-'.length);
+        if (!jobs.has(job)) {
+          jobs.set(job, new Set());
+        }
+        jobs.get(job).add(task.target);
+      }
+    }
+  }
+  return Object.fromEntries(
+    [...jobs.entries()]
+      .sort(([left], [right]) => compareText(left, right))
+      .map(([job, targets]) => [job, sorted(targets)]),
+  );
+}
+
+export const CI_JOB_TARGETS = moonCiJobTargets();
+const RELEASE_ONLY_TARGETS = new Set(
+  [...TASKS_BY_TARGET.values()]
+    .filter((task) => task.tags?.includes('release-only'))
+    .map((task) => task.target),
+);
+export const BUILDER_JOBS = new Set(
+  Object.keys(CI_JOB_TARGETS).filter((job) => job !== NATIVE_EXTENSION_LIFECYCLE_JOB),
+);
+const JOBS_BY_TARGET = (() => {
+  const jobs = new Map();
+  for (const [job, targets] of Object.entries(CI_JOB_TARGETS)) {
+    for (const target of targets) jobs.set(target, [...(jobs.get(target) ?? []), job]);
+  }
+  return jobs;
+})();
+const DEPENDENTS_BY_TARGET = (() => {
+  const dependents = new Map();
+  for (const task of TASKS_BY_TARGET.values()) {
+    for (const dependency of task.deps ?? []) {
+      const target = typeof dependency === 'string' ? dependency : dependency.target;
+      if (typeof target === 'string') {
+        dependents.set(target, [...(dependents.get(target) ?? []), task.target]);
+      }
+    }
+  }
+  return dependents;
+})();
+export const ALL_BUILDER_JOBS = new Set(Object.keys(CI_JOB_TARGETS));
+export const CI_JOBS_CONFIG = {
+  always_jobs: sorted(ALWAYS_JOBS),
+  ci_job_targets: CI_JOB_TARGETS,
+  wasm_runtime_jobs: sorted(WASM_RUNTIME_JOBS),
+};
+
+export function jobTargetsForJobs(jobs, selectedTasks = undefined) {
+  return Object.fromEntries(
+    sorted(jobs)
+      .filter((job) => CI_JOB_TARGETS[job] !== undefined)
+      .map((job) => [
+        job,
+        CI_JOB_TARGETS[job].filter((target) =>
+          selectedTasks === undefined
+            ? !RELEASE_ONLY_TARGETS.has(target)
+            : selectedTasks.has(target),
+        ),
+      ]),
+  );
+}
+
+function emptyMatrix() {
+  return { include: [] };
+}
+
+export function jobsForTargets(targets, { allowedJobs = undefined } = {}) {
+  const jobs = new Set();
+  for (const [job, jobTargets] of Object.entries(CI_JOB_TARGETS)) {
+    if (allowedJobs !== undefined && !allowedJobs.has(job)) {
+      continue;
+    }
+    if (intersects(targets, new Set(jobTargets))) {
+      jobs.add(job);
+    }
+  }
+  return jobs;
+}
+
+function taskDependencyTargets(task) {
+  return (task?.deps ?? [])
+    .map((dependency) => (typeof dependency === 'string' ? dependency : dependency.target))
+    .filter((target) => typeof target === 'string');
+}
+
+function downstreamTaskClosure(tasks, excludedTargets = RELEASE_ONLY_TARGETS) {
+  const closure = new Set([...tasks].filter((target) => !excludedTargets.has(target)));
+  const pending = [...closure];
+  while (pending.length > 0) {
+    for (const dependent of DEPENDENTS_BY_TARGET.get(pending.pop()) ?? []) {
+      if (!closure.has(dependent) && !excludedTargets.has(dependent)) {
+        closure.add(dependent);
+        pending.push(dependent);
+      }
+    }
+  }
+  return closure;
+}
+
+export function addRequiredJobs(jobs) {
+  const pendingJobs = [...jobs];
+  const visitedTasks = new Set();
+  while (pendingJobs.length > 0) {
+    const job = pendingJobs.pop();
+    const pendingTasks = [...(CI_JOB_TARGETS[job] ?? [])];
+    while (pendingTasks.length > 0) {
+      const target = pendingTasks.pop();
+      if (visitedTasks.has(target)) continue;
+      visitedTasks.add(target);
+      const task = TASKS_BY_TARGET.get(target);
+      if (!task) fail(`CI job ${job} references missing Moon target ${target}`);
+      for (const dependency of taskDependencyTargets(task)) {
+        pendingTasks.push(dependency);
+        for (const dependencyJob of JOBS_BY_TARGET.get(dependency) ?? []) {
+          if (!jobs.has(dependencyJob)) {
+            jobs.add(dependencyJob);
+            pendingJobs.push(dependencyJob);
+          }
+        }
+      }
+    }
+  }
+  return jobs;
+}
+
+export function planJobsForAffected(tasks, excludedTargets = RELEASE_ONLY_TARGETS) {
+  const jobs = new Set(ALWAYS_JOBS);
+  const directlySelectedJobs = jobsForTargets(requiredTasksForAffected(tasks, excludedTargets), {
+    allowedJobs: ALL_BUILDER_JOBS,
+  });
+  for (const job of directlySelectedJobs) {
+    jobs.add(job);
+  }
+  return jobs;
+}
+
+export function requiredTasksForAffected(tasks, excludedTargets = RELEASE_ONLY_TARGETS) {
+  const selected = new Set(
+    [...downstreamTaskClosure(tasks, excludedTargets)].filter((target) =>
+      JOBS_BY_TARGET.has(target),
+    ),
+  );
+  const pending = [...selected];
+  while (pending.length > 0) {
+    const target = pending.pop();
+    const task = TASKS_BY_TARGET.get(target);
+    if (!task) fail(`affected Moon selection references missing target ${target}`);
+    for (const dependency of taskDependencyTargets(task)) {
+      if (!selected.has(dependency)) {
+        selected.add(dependency);
+        pending.push(dependency);
+      }
+    }
+  }
+  return selected;
+}
+
+export function nativeTargetSubsetForJobs(jobs, tasks) {
+  if (!intersects(jobs, NATIVE_RUNTIME_JOBS)) {
+    return null;
+  }
+  if (jobs.has('liboliphaunt-native-release-assets')) {
+    return null;
+  }
+  if (intersects(tasks, NATIVE_RUNTIME_TASKS)) {
+    return null;
+  }
+
+  const targets = mobileNativeTargetsForJobs(jobs);
+  if (jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB) || jobs.has('native-consumers')) {
+    targets.add('linux-x64-gnu');
+  }
+  if (jobs.has('swift-sdk-package')) {
+    targets.add('ios-xcframework');
+  }
+  if (jobs.has('kotlin-sdk-package')) {
+    for (const target of liboliphauntNativeRuntimeTargetsForSurface('maven')) {
+      targets.add(target);
+    }
+  }
+  return targets.size > 0 ? targets : null;
+}
+
+export function mobileNativeTargetsForJobs(jobs) {
+  const targets = new Set();
+  for (const [job, surface] of Object.entries(MOBILE_JOB_SURFACES)) {
+    if (jobs.has(job)) {
+      for (const target of liboliphauntNativeRuntimeTargetsForSurface(surface)) {
+        targets.add(target);
+      }
+    }
+  }
+  return targets;
+}
+
+export function mobileExtensionPackageNativeTargets(jobs, selectedTargets) {
+  if (!jobs.has('mobile-extension-packages')) {
+    return [];
+  }
+  if (selectedTargets !== null && selectedTargets !== undefined) {
+    return sorted(selectedTargets);
+  }
+  return sorted(mobileNativeTargetsForJobs(jobs));
+}
+
+export function mobileE2eJobsForPlan(jobs) {
+  const selected = Object.entries(MOBILE_E2E_JOBS)
+    .filter(([builder]) => jobs.has(builder))
+    .map(([, e2e]) => e2e);
+  if (jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)) {
+    selected.push(NATIVE_EXTENSION_LIFECYCLE_AGGREGATE_JOB);
+  }
+  return selected.sort(compareText);
+}
+
+export function liboliphauntNativeIosRuntimeMatrixForPlan(
+  jobs,
+  selectedTargets,
+  nativeTarget = process.env.NATIVE_TARGET || 'all',
+) {
+  if (!jobs.has('liboliphaunt-native-ios')) return emptyMatrix();
+  if (jobs.has('react-native-sdk-package')) {
+    return liboliphauntNativeIosRuntimeMatrix('all', new Set(['ios-xcframework']));
+  }
+  return liboliphauntNativeIosRuntimeMatrix(nativeTarget, selectedTargets ?? undefined);
+}
+
+export function liboliphauntNativeDesktopRuntimeMatrixForPlan(
+  jobs,
+  selectedTargets,
+  nativeTarget = process.env.NATIVE_TARGET || 'all',
+) {
+  if (!jobs.has('liboliphaunt-native-desktop')) return emptyMatrix();
+  return liboliphauntNativeDesktopRuntimeMatrix(nativeTarget, selectedTargets ?? undefined);
+}
+
+function focusedMobileNativeTargets(mobileTarget, nativeTarget, focusedMobileJobs) {
+  const targets = mobileNativeTargetsForJobs(focusedMobileJobs);
+  if (nativeTarget !== 'all') {
+    if (mobileTarget === 'both') {
+      throw new Error('focused mobile_target=both requires native_target=all');
+    }
+    if (!targets.has(nativeTarget)) {
+      throw new Error(
+        `native_target=${nativeTarget} is not valid for mobile_target=${mobileTarget}; expected one of: all, ${sorted(targets).join(', ')}`,
+      );
+    }
+  }
+  // Mobile qualification admits one physical compatibility domain. A focused
+  // target may select that domain, but must not silently omit one of its ABI
+  // receipts or the representative emulator app that consumes the closure.
+  return targets;
+}
+
+export function planForAffectedRange() {
+  const base = process.env.MOON_BASE;
+  const head = process.env.MOON_HEAD;
+  if (!base || !head) {
+    throw new Error('MOON_BASE and MOON_HEAD are required for affected CI planning');
+  }
+
+  const { directProjects, projects, directTasks } = affectedProjectsAndTasks();
+  const jobs = planJobsForAffected(directTasks);
+  const selectedNativeTargets = nativeTargetSubsetForJobs(jobs, directTasks);
+  const reason =
+    `direct affected projects: ${sorted(directProjects).join(', ') || '(none)'}; ` +
+    `downstream affected projects: ${sorted(projects).join(', ') || '(none)'}; ` +
+    `direct affected tasks: ${sorted(directTasks).join(', ') || '(none)'}`;
+  return {
+    jobs,
+    directProjects,
+    projects,
+    tasks: directTasks,
+    reason,
+    selectedTargets: selectedNativeTargets,
+  };
+}
+
+export function planForReleaseProducts(
+  products,
+  headSha = process.env.MOON_HEAD,
+  publishedDependencies = null,
+) {
+  if (
+    process.env.CI_QUALIFICATION_REQUEST &&
+    process.env.CI_QUALIFICATION_REQUEST !== qualificationRequestKey(headSha, products)
+  )
+    throw new Error(
+      'qualification request no longer matches the dispatched source and product scope',
+    );
+  if (!/^[0-9a-f]{40}$/.test(headSha ?? ''))
+    throw new Error('product qualification requires the exact candidate SHA');
+  const catalog = loadProducts();
+  if (
+    !Array.isArray(products) ||
+    products.length === 0 ||
+    new Set(products).size !== products.length ||
+    products.some((product) => typeof product !== 'string' || !Object.hasOwn(catalog, product))
+  ) {
+    throw new Error('release qualification requires a non-empty unique list of known product IDs');
+  }
+  const projects = new Set(products);
+  const roots = new Set(
+    [...TASKS_BY_TARGET.values()]
+      .filter(
+        (task) =>
+          projects.has(task.target.split(':')[0]) &&
+          !RELEASE_ONLY_TARGETS.has(task.target) &&
+          task.options?.runInCI !== false &&
+          task.options?.runInCI !== 'skip',
+      )
+      .map((task) => task.target),
+  );
+  // External extensions own release metadata; their actual producers are shared
+  // native/WASIX artifact projects. Keep the normal graph closure so their
+  // package consumers and same-run lifecycle evidence remain required.
+  const externalProducts = new Set(exactExtensionReleaseProducts());
+  const selectedExternalProducts = products.filter((product) => externalProducts.has(product));
+  if (selectedExternalProducts.length > 0) {
+    const artifactProjects = new Set(
+      [...moonProjectsById(PREFIX).values()]
+        .filter(
+          (project) =>
+            project.config.tags.includes('extensions') && project.config.tags.includes('artifacts'),
+        )
+        .map((project) => project.id),
+    );
+    const producers = [...TASKS_BY_TARGET.values()].filter(
+      (task) =>
+        artifactProjects.has(task.target.split(':')[0]) &&
+        task.tags?.includes('artifact-builder') &&
+        task.options?.runInCI !== false &&
+        task.options?.runInCI !== 'skip',
+    );
+    if (producers.length === 0)
+      throw new Error('external extension release has no qualifying Moon artifact producers');
+    for (const task of producers) roots.add(task.target);
+  }
+  for (const product of products) {
+    if (
+      !externalProducts.has(product) &&
+      ![...roots].some((target) => target.startsWith(`${product}:`))
+    )
+      throw new Error(`release product ${product} has no qualifying Moon tasks`);
+  }
+  const excludedTargets = new Set(RELEASE_ONLY_TARGETS);
+  const reusePublished =
+    products.length === 1 &&
+    products[0] === 'oliphaunt-js' &&
+    validPublishedConsumerInventory(publishedDependencies);
+  if (reusePublished) {
+    roots.delete('oliphaunt-js:test-consumer');
+    excludedTargets.add('oliphaunt-js:test-consumer');
+    excludedTargets.delete('oliphaunt-js:test-consumer-published');
+    roots.add('oliphaunt-js:test-consumer-published');
+  }
+  const tasks = requiredTasksForAffected(roots, excludedTargets);
+  for (const target of downstreamTaskClosure(roots, excludedTargets)) {
+    const task = TASKS_BY_TARGET.get(target);
+    if (
+      task?.tags?.includes('quality') &&
+      task.options?.runInCI !== false &&
+      task.options?.runInCI !== 'skip'
+    )
+      tasks.add(target);
+  }
+  const pending = [...tasks];
+  while (pending.length > 0) {
+    for (const dependency of taskDependencyTargets(TASKS_BY_TARGET.get(pending.pop()))) {
+      if (!tasks.has(dependency)) {
+        tasks.add(dependency);
+        pending.push(dependency);
+      }
+    }
+  }
+  const jobs = planJobsForAffected(roots, excludedTargets);
+  const selectedExtensionProducts = selectedExtensionProductsForPlan(projects, roots, jobs);
+  const plan = renderPlanWithSelection({
+    jobs,
+    projects,
+    tasks,
+    selectedExtensionProducts,
+    selectedTargets: nativeTargetSubsetForJobs(jobs, roots),
+    platformRoots: roots,
+    qualificationMode: PRODUCT_QUALIFICATION_MODE,
+    qualificationProducts: [...products].sort(compareText),
+    qualificationHeadSha: headSha,
+    excludedTargets,
+    reason: `release qualification for products: ${[...products].sort(compareText).join(', ')}`,
+  });
+  return { ...plan, published_dependencies: reusePublished ? publishedDependencies : [] };
+}
+
+export function selectedExtensionProductsForPlan(directProjects, tasks, jobs) {
+  const extensionJobs = new Set([
+    'extension-artifacts-native',
+    'extension-artifacts-wasix',
+    'extension-packages',
+    NATIVE_EXTENSION_LIFECYCLE_JOB,
+    ...Object.keys(MOBILE_JOB_SURFACES),
+  ]);
+  if (!intersects(jobs, extensionJobs)) {
+    return null;
+  }
+
+  const exactProducts = new Set(exactExtensionProducts());
+  if (intersects(jobs, new Set(Object.keys(MOBILE_JOB_SURFACES)))) {
+    return exactProducts;
+  }
+  const selected = new Set([...directProjects].filter((project) => exactProducts.has(project)));
+  for (const target of tasks) {
+    const project = target.split(':', 1)[0];
+    if (exactProducts.has(project)) {
+      selected.add(project);
+    }
+  }
+  if (intersects(directProjects, BROAD_EXTENSION_INPUT_PROJECTS)) {
+    return exactProducts;
+  }
+  if (tasks.has('extension-packages:package') && selected.size === 0) {
+    return exactProducts;
+  }
+  if (jobs.has('extension-packages') && selected.size === 0) {
+    return exactProducts;
+  }
+  if (
+    intersects(jobs, new Set(['extension-artifacts-native', 'extension-artifacts-wasix'])) &&
+    selected.size === 0
+  ) {
+    return exactProducts;
+  }
+  if (tasks.has('extension-packages:package-mobile') && selected.size === 0) {
+    return exactProducts;
+  }
+  return selected.size > 0 ? selected : null;
+}
+
+export function extensionProductDependencyClosure(products) {
+  const exactProducts = new Set(exactExtensionProducts());
+  const productBySqlName = new Map(
+    [...exactProducts].flatMap((product) =>
+      extensionSqlNames(product, PREFIX).map((sqlName) => [sqlName, product]),
+    ),
+  );
+  const closure = new Set();
+  const pending = [...products];
+  while (pending.length > 0) {
+    const product = pending.pop();
+    if (!exactProducts.has(product)) throw new Error(`unknown exact extension product ${product}`);
+    if (closure.has(product)) continue;
+    closure.add(product);
+    for (const sqlName of extensionSqlNames(product, PREFIX)) {
+      for (const dependencySqlName of extensionPublicDependencySqlNames(sqlName, PREFIX)) {
+        const dependencyProduct = productBySqlName.get(dependencySqlName);
+        if (!dependencyProduct) {
+          throw new Error(
+            `${sqlName} has unknown public extension dependency ${dependencySqlName}`,
+          );
+        }
+        pending.push(dependencyProduct);
+      }
+    }
+  }
+  return closure;
+}
+
+export function planForFullRun({
+  wasmTarget = 'all',
+  nativeTarget = 'all',
+  mobileTarget = 'all',
+} = {}) {
+  if (wasmTarget !== 'all' && (nativeTarget !== 'all' || mobileTarget !== 'all')) {
+    throw new Error(
+      'wasm_target focus cannot be combined with native_target or mobile_target focus; run the WASIX and native/mobile diagnostics separately',
+    );
+  }
+  if (mobileTarget !== 'all') {
+    const mobileJobsByTarget = {
+      android: new Set(['mobile-build-android']),
+      ios: new Set(['mobile-build-ios']),
+      both: new Set(['mobile-build-android', 'mobile-build-ios']),
+    };
+    const focusedMobileJobs = mobileJobsByTarget[mobileTarget];
+    if (focusedMobileJobs === undefined) {
+      throw new Error(
+        `unknown mobile target ${mobileTarget}; expected one of: all, android, ios, both`,
+      );
+    }
+    const focusedJobs = setUnion(BASE_JOBS, focusedMobileJobs);
+    addRequiredJobs(focusedJobs);
+    const focusedNativeTargets = focusedMobileNativeTargets(
+      mobileTarget,
+      nativeTarget,
+      focusedMobileJobs,
+    );
+    return {
+      jobs: focusedJobs,
+      projects: new Set(['liboliphaunt-native', 'oliphaunt-react-native']),
+      tasks: targetsForJobs(focusedMobileJobs),
+      reason: `manual focused mobile CI run for ${mobileTarget}`,
+      selectedTargets: focusedNativeTargets,
+    };
+  }
+
+  if (nativeTarget !== 'all') {
+    let focusedJobs;
+    let focusedProjects;
+    if (nativeTarget.startsWith('android-') || nativeTarget === 'ios-xcframework') {
+      focusedJobs = setUnion(
+        BASE_JOBS,
+        new Set([
+          nativeTarget.startsWith('android-')
+            ? 'liboliphaunt-native-android'
+            : 'liboliphaunt-native-ios',
+        ]),
+      );
+      focusedProjects = new Set(['liboliphaunt-native']);
+    } else {
+      focusedJobs = setUnion(BASE_JOBS, new Set(['liboliphaunt-native-desktop']));
+      focusedProjects = new Set(['liboliphaunt-native']);
+      if (nativeTarget === 'linux-x64-gnu') {
+        focusedJobs.add(NATIVE_EXTENSION_LIFECYCLE_JOB);
+      }
+    }
+    addRequiredJobs(focusedJobs);
+    return {
+      jobs: focusedJobs,
+      projects: focusedProjects,
+      tasks: targetsForJobs(focusedJobs),
+      reason: `manual focused native runtime CI run for ${nativeTarget}`,
+      selectedTargets: focusedJobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)
+        ? new Set(['linux-x64-gnu'])
+        : null,
+    };
+  }
+
+  if (wasmTarget !== 'all') {
+    const focusedJobs = setUnion(
+      BASE_JOBS,
+      new Set(['liboliphaunt-wasix-runtime', 'liboliphaunt-wasix-aot']),
+    );
+    if (wasmTarget === 'linux-x64-gnu') {
+      // The workflow selects release regression for the Linux host target.
+      focusedJobs.add('extension-artifacts-wasix');
+    }
+    return {
+      jobs: focusedJobs,
+      projects: new Set(['liboliphaunt-wasix']),
+      tasks: targetsForJobs(focusedJobs),
+      reason: `manual focused WASIX runtime CI run for ${wasmTarget}`,
+      selectedTargets: null,
+    };
+  }
+
+  const jobs = setUnion(
+    BASE_JOBS,
+    BUILDER_JOBS,
+    WASM_RUNTIME_JOBS,
+    new Set([NATIVE_EXTENSION_LIFECYCLE_JOB]),
+  );
+  addRequiredJobs(jobs);
+  return {
+    jobs,
+    projects: new Set(),
+    tasks: targetsForJobs(jobs),
+    reason: 'manual full CI/runtime run',
+    selectedTargets: null,
+  };
+}
+
+function targetsForJobs(jobs) {
+  const targets = new Set();
+  for (const job of jobs) {
+    for (const target of CI_JOB_TARGETS[job] ?? []) {
+      if (!RELEASE_ONLY_TARGETS.has(target)) targets.add(target);
+    }
+  }
+  return targets;
+}
+
+function renderPlan(
+  { jobs, projects, tasks, reason, selectedTargets },
+  {
+    nativeTarget = process.env.NATIVE_TARGET || 'all',
+    wasmTarget = process.env.WASM_TARGET || 'all',
+  } = {},
+) {
+  const selectedExtensionProducts = selectedExtensionProductsForPlan(new Set(), tasks, jobs);
+  return renderPlanWithSelection({
+    jobs,
+    projects,
+    tasks,
+    reason,
+    selectedTargets,
+    selectedExtensionProducts,
+    nativeTarget,
+    wasmTarget,
+  });
+}
+
+export function renderPlanForFullRun({
+  wasmTarget = 'all',
+  nativeTarget = 'all',
+  mobileTarget = 'all',
+} = {}) {
+  return renderPlan(planForFullRun({ wasmTarget, nativeTarget, mobileTarget }), {
+    nativeTarget: mobileTarget === 'all' ? nativeTarget : 'all',
+    wasmTarget,
+  });
+}
+
+export function extensionArtifactsWasixMatrixForPlan(jobs, selectedExtensionProducts) {
+  // Release regression exercises every public extension. Its portable
+  // carrier producer must therefore be complete even when the release/package
+  // selection is intentionally narrowed to one independently versioned
+  // extension. Non-regression callers retain that focused selection.
+  const products = jobs.has('liboliphaunt-wasix-runtime')
+    ? undefined
+    : (selectedExtensionProducts ?? undefined);
+  return extensionArtifactsWasixMatrix('all', products);
+}
+
+export function extensionArtifactsNativeMatrixForPlan(
+  jobs,
+  selectedTargets,
+  selectedExtensionProducts,
+  nativeTarget = process.env.NATIVE_TARGET || 'all',
+) {
+  const matrix = extensionArtifactsNativeMatrix(
+    nativeTarget,
+    jobs.has('extension-packages') ? undefined : (selectedTargets ?? undefined),
+    selectedExtensionProducts ?? undefined,
+  );
+  if (!jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)) {
+    return matrix;
+  }
+
+  const exactProducts = new Set(exactExtensionProducts());
+  const requiredTargets = new Set(['linux-x64-gnu']);
+  const proofProducts = extensionProductDependencyClosure(
+    selectedExtensionProducts ?? exactProducts,
+  );
+  const proofRows = extensionArtifactsNativeMatrix('all', requiredTargets, proofProducts).include;
+  if (proofRows.length !== requiredTargets.size) {
+    throw new Error('native extension lifecycle does not have a complete Linux producer row');
+  }
+  const include = matrix.include.filter((row) => !requiredTargets.has(row.target));
+  include.push(...proofRows);
+  include.sort((left, right) => compareText(left.target, right.target));
+  return { include };
+}
+
+export function nativeExtensionLifecycleShardPlan(products) {
+  const selected = new Set(products);
+  if (selected.size === 0) return { matrix: emptyMatrix(), shardCount: 0 };
+  const exact = new Set(exactExtensionProducts());
+  const exhaustive =
+    selected.size === exact.size && [...selected].every((product) => exact.has(product));
+  const shardCount = exhaustive ? NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT : 1;
+  const sqlNames = extensionSqlNamesForProducts(selected);
+  return {
+    matrix: {
+      include: Array.from({ length: shardCount }, (_, shard) => {
+        const names = sqlNames.filter((_, index) => index % shardCount === shard);
+        const shown = names.slice(0, 4).join(', ');
+        return {
+          shard,
+          shard_count: shardCount,
+          label: `${names.length} Extensions (${shown}${names.length > 4 ? ` + ${names.length - 4} More` : ''})`,
+        };
+      }),
+    },
+    shardCount,
+  };
+}
+
+// A dependency-only producer inherits explicit host requirements from its selected
+// consumers. Unbounded consumers and directly selected producers retain all hosts.
+export function dependencyPlatformTargets(job, roots, excludedTargets = RELEASE_ONLY_TARGETS) {
+  if (!roots) return null;
+  const selected = downstreamTaskClosure(roots, excludedTargets);
+  const producers = new Set(CI_JOB_TARGETS[job] ?? []);
+  if (intersects(selected, producers)) return null;
+  const platforms = new Set();
+  for (const target of selected) {
+    if (!JOBS_BY_TARGET.has(target)) continue;
+    const seen = new Set();
+    const pending = taskDependencyTargets(TASKS_BY_TARGET.get(target));
+    while (pending.length) {
+      const dependency = pending.pop();
+      if (seen.has(dependency)) continue;
+      seen.add(dependency);
+      pending.push(...taskDependencyTargets(TASKS_BY_TARGET.get(dependency)));
+    }
+    if (!intersects(seen, producers)) continue;
+    const declared = (TASKS_BY_TARGET.get(target)?.tags ?? [])
+      .filter((tag) => tag.startsWith('platform-'))
+      .map((tag) => tag.slice(9));
+    if (!declared.length) return null;
+    for (const platform of declared) platforms.add(platform);
+  }
+  return platforms.size ? platforms : null;
+}
+
+export function renderPlanWithSelection({
+  jobs,
+  projects,
+  tasks,
+  reason,
+  selectedTargets,
+  selectedExtensionProducts,
+  nativeTarget = process.env.NATIVE_TARGET || 'all',
+  wasmTarget = process.env.WASM_TARGET || 'all',
+  qualificationMode = FULL_PAYLOAD_QUALIFICATION_MODE,
+  qualificationBaseSha = null,
+  qualificationHeadSha = null,
+  qualificationProducts = [],
+  platformRoots = qualificationMode === AFFECTED_QUALIFICATION_MODE ? tasks : null,
+  excludedTargets = RELEASE_ONLY_TARGETS,
+}) {
+  const extensionProducts = sorted(selectedExtensionProducts ?? new Set());
+  const extensionSqlNames = extensionSqlNamesForProducts(extensionProducts);
+  const nativeLifecycleProducts = jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)
+    ? extensionProductDependencyClosure(
+        selectedExtensionProducts ?? new Set(exactExtensionProducts()),
+      )
+    : new Set();
+  const nativeLifecycleSqlNames = extensionSqlNamesForProducts(nativeLifecycleProducts);
+  const nativeLifecycleShards = nativeExtensionLifecycleShardPlan(nativeLifecycleProducts);
+  const plan = {
+    qualification_mode: qualificationMode,
+    qualification_base_sha: qualificationBaseSha,
+    qualification_head_sha: qualificationHeadSha,
+    ...(qualificationMode === PRODUCT_QUALIFICATION_MODE
+      ? { qualification_products: qualificationProducts }
+      : {}),
+    jobs: sorted(jobs),
+    builder_jobs: sorted(new Set([...jobs].filter((job) => BUILDER_JOBS.has(job)))),
+    e2e_jobs: mobileE2eJobsForPlan(jobs),
+    job_targets: jobTargetsForJobs(
+      jobs,
+      qualificationMode === PRODUCT_QUALIFICATION_MODE
+        ? tasks
+        : qualificationMode === AFFECTED_QUALIFICATION_MODE
+          ? requiredTasksForAffected(tasks)
+          : undefined,
+    ),
+    projects: sorted(projects),
+    tasks: sorted(tasks),
+    liboliphaunt_native_desktop_runtime_matrix: liboliphauntNativeDesktopRuntimeMatrixForPlan(
+      jobs,
+      selectedTargets,
+      nativeTarget,
+    ),
+    liboliphaunt_native_android_runtime_matrix: jobs.has('liboliphaunt-native-android')
+      ? liboliphauntNativeAndroidRuntimeMatrix(nativeTarget, selectedTargets ?? undefined)
+      : emptyMatrix(),
+    liboliphaunt_native_ios_runtime_matrix: liboliphauntNativeIosRuntimeMatrixForPlan(
+      jobs,
+      selectedTargets,
+      nativeTarget,
+    ),
+    extension_artifacts_native_matrix: jobs.has('extension-artifacts-native')
+      ? extensionArtifactsNativeMatrixForPlan(
+          jobs,
+          selectedTargets,
+          selectedExtensionProducts,
+          nativeTarget,
+        )
+      : emptyMatrix(),
+    extension_artifacts_wasix_matrix: jobs.has('extension-artifacts-wasix')
+      ? extensionArtifactsWasixMatrixForPlan(jobs, selectedExtensionProducts)
+      : emptyMatrix(),
+    liboliphaunt_wasix_aot_runtime_matrix: jobs.has('liboliphaunt-wasix-aot')
+      ? liboliphauntWasixAotRuntimeMatrix(wasmTarget)
+      : emptyMatrix(),
+    liboliphaunt_wasix_postmaster_runtime_matrix: jobs.has('wasix-postmaster')
+      ? liboliphauntWasixPostmasterRuntimeMatrix()
+      : emptyMatrix(),
+    extension_package_products: extensionProducts,
+    extension_package_products_csv: extensionProducts.join(','),
+    extension_package_sql_names: extensionSqlNames,
+    extension_package_sql_names_csv: extensionSqlNames.join(','),
+    native_extension_lifecycle_sql_names: nativeLifecycleSqlNames,
+    native_extension_lifecycle_sql_names_csv: nativeLifecycleSqlNames.join(','),
+    native_extension_lifecycle_matrix: nativeLifecycleShards.matrix,
+    native_extension_lifecycle_shard_count: nativeLifecycleShards.shardCount,
+    mobile_extension_package_native_targets: mobileExtensionPackageNativeTargets(
+      jobs,
+      selectedTargets,
+    ),
+    mobile_extension_package_native_targets_csv: mobileExtensionPackageNativeTargets(
+      jobs,
+      selectedTargets,
+    ).join(','),
+    react_native_android_mobile_app_matrix: jobs.has('mobile-build-android')
+      ? reactNativeAndroidMobileAppMatrix('all', REACT_NATIVE_ANDROID_REPRESENTATIVE_TARGETS)
+      : emptyMatrix(),
+    broker_runtime_matrix: jobs.has('broker-runtime')
+      ? brokerRuntimeMatrix(
+          !jobs.has('broker-release-assets') &&
+            jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB) &&
+            selectedTargets?.size === 1 &&
+            selectedTargets.has('linux-x64-gnu')
+            ? 'linux-x64-gnu'
+            : nativeTarget,
+        )
+      : emptyMatrix(),
+    node_direct_runtime_matrix: jobs.has('node-direct')
+      ? nodeDirectRuntimeMatrix(nativeTarget)
+      : emptyMatrix(),
+    wasix_napi_runtime_matrix: jobs.has('wasix-napi')
+      ? wasixNapiRuntimeMatrix(
+          jobs.has('wasix-napi-release-assets') ? nativeTarget : 'linux-x64-gnu',
+        )
+      : emptyMatrix(),
+    reason,
+  };
+  if (nativeTarget === 'all') {
+    for (const [job, matrix] of [
+      ['liboliphaunt-native-desktop', 'liboliphaunt_native_desktop_runtime_matrix'],
+      ['broker-runtime', 'broker_runtime_matrix'],
+      ['node-direct', 'node_direct_runtime_matrix'],
+    ]) {
+      const required = dependencyPlatformTargets(job, platformRoots, excludedTargets);
+      if (required) {
+        const available = new Set(plan[matrix].include.map((row) => row.target));
+        for (const target of required) {
+          if (!available.has(target))
+            throw new Error(`CI producer ${job} cannot satisfy consumer platform ${target}`);
+        }
+        plan[matrix].include = plan[matrix].include.filter((row) => required.has(row.target));
+      }
+    }
+  }
+  for (const [matrix, groups] of [
+    ['extension_artifacts_native_matrix', ['linux', 'android', 'ios', 'other']],
+    ['liboliphaunt_native_desktop_runtime_matrix', ['linux', 'other']],
+    ['broker_runtime_matrix', ['linux', 'other']],
+  ]) {
+    for (const group of groups) {
+      plan[`${matrix}_${group}`] = {
+        include: plan[matrix].include.filter((row) => {
+          const family =
+            row.target === 'linux-x64-gnu'
+              ? 'linux'
+              : groups.includes('android') && row.target.startsWith('android-')
+                ? 'android'
+                : groups.includes('ios') && row.target === 'ios-xcframework'
+                  ? 'ios'
+                  : 'other';
+          return family === group;
+        }),
+      };
+    }
+  }
+
+  for (const family of ['android', 'ios']) {
+    plan[`mobile_extension_package_native_targets_${family}_csv`] =
+      plan.mobile_extension_package_native_targets
+        .filter((target) => target.startsWith(`${family}-`))
+        .join(',');
+  }
+
+  return plan;
+}
+
+function sortedValue(value) {
+  if (Array.isArray(value)) {
+    return value.map(sortedValue);
+  }
+  if (value instanceof Set) {
+    return sorted(value);
+  }
+  if (value !== null && typeof value === 'object') {
+    return Object.fromEntries(
+      Object.keys(value)
+        .sort(compareText)
+        .map((key) => [key, sortedValue(value[key])]),
+    );
+  }
+  return value;
+}
+
+function output(name, value) {
+  const rendered = typeof value === 'string' ? value : JSON.stringify(sortedValue(value));
+  const outputPath = process.env.GITHUB_OUTPUT;
+  if (outputPath) {
+    appendFileSync(outputPath, `${name}=${rendered}\n`, 'utf8');
+  }
+  console.log(`${name}=${rendered}`);
+}
+
+function writePlanArtifact(plan) {
+  const file = path.join(ROOT, 'target/graph/ci-plan.json');
+  mkdirSync(path.dirname(file), { recursive: true });
+  writeFileSync(file, `${JSON.stringify(sortedValue(plan), null, 2)}\n`, 'utf8');
+}
+
+export async function emitGithubOutputs() {
+  let planned;
+  try {
+    if (process.env.CI_RELEASE_PRODUCTS_JSON && process.env.CI_RELEASE_PRODUCTS_JSON !== '[]') {
+      if (
+        [process.env.WASM_TARGET, process.env.NATIVE_TARGET, process.env.MOBILE_TARGET].some(
+          (target) => target && target !== 'all',
+        )
+      )
+        throw new Error('product qualification cannot use focused platform targets');
+      const products = JSON.parse(process.env.CI_RELEASE_PRODUCTS_JSON);
+      planned = planForReleaseProducts(
+        products,
+        process.env.MOON_HEAD,
+        await publishedConsumerInventory(products),
+      );
+    } else if (process.env.GITHUB_EVENT_NAME !== 'workflow_dispatch') {
+      const affectedPlan = planForAffectedRange();
+      const selectedExtensionProducts = selectedExtensionProductsForPlan(
+        affectedPlan.directProjects,
+        affectedPlan.tasks,
+        affectedPlan.jobs,
+      );
+      planned = renderPlanWithSelection({
+        ...affectedPlan,
+        selectedExtensionProducts,
+        qualificationMode: AFFECTED_QUALIFICATION_MODE,
+        qualificationBaseSha: process.env.MOON_BASE,
+        qualificationHeadSha: process.env.MOON_HEAD,
+      });
+    } else {
+      planned = renderPlanForFullRun({
+        wasmTarget: process.env.WASM_TARGET || 'all',
+        nativeTarget: process.env.NATIVE_TARGET || 'all',
+        mobileTarget: process.env.MOBILE_TARGET || 'all',
+      });
+    }
+  } catch (error) {
+    console.error(`affected planning failed: ${error.message}`);
+    return 2;
+  }
+  writePlanArtifact(planned);
+  for (const [name, value] of Object.entries(planned)) {
+    output(name, value);
+  }
+  return 0;
+}
+
+function parseJsonFlag(argv, name, { defaultValue = undefined } = {}) {
+  const flag = `--${name}`;
+  for (let index = 0; index < argv.length; index += 1) {
+    const value = argv[index];
+    if (value === flag) {
+      if (index + 1 >= argv.length) {
+        fail(`${flag} requires a value`);
+      }
+      return JSON.parse(argv[index + 1]);
+    }
+    if (value.startsWith(`${flag}=`)) {
+      return JSON.parse(value.slice(flag.length + 1));
+    }
+  }
+  return defaultValue;
+}
+
+function stringFlag(argv, name, defaultValue = 'all') {
+  const flag = `--${name}`;
+  for (let index = 0; index < argv.length; index += 1) {
+    const value = argv[index];
+    if (value === flag) {
+      if (index + 1 >= argv.length) {
+        fail(`${flag} requires a value`);
+      }
+      return argv[index + 1];
+    }
+    if (value.startsWith(`${flag}=`)) {
+      return value.slice(flag.length + 1);
+    }
+  }
+  return defaultValue;
+}
+
+function setFlag(argv, name) {
+  const value = parseJsonFlag(argv, name, { defaultValue: [] });
+  return new Set(stringList(value));
+}
+
+function nullableSetFlag(argv, name) {
+  const value = parseJsonFlag(argv, name, { defaultValue: null });
+  if (value === null) {
+    return null;
+  }
+  return new Set(stringList(value));
+}
+
+function printJson(value) {
+  console.log(JSON.stringify(sortedValue(value), null, 2));
+}
+
+function printPlanForFullRun(argv) {
+  const plan = planForFullRun({
+    wasmTarget: stringFlag(argv, 'wasm-target'),
+    nativeTarget: stringFlag(argv, 'native-target'),
+    mobileTarget: stringFlag(argv, 'mobile-target'),
+  });
+  printJson({
+    jobs: sorted(plan.jobs),
+    projects: sorted(plan.projects),
+    tasks: sorted(plan.tasks),
+    reason: plan.reason,
+    selectedTargets: plan.selectedTargets === null ? null : sorted(plan.selectedTargets),
+  });
+}
+
+function printMatrix(argv, matrix) {
+  const nativeTarget = stringFlag(argv, 'native-target');
+  const wasmTarget = stringFlag(argv, 'wasm-target');
+  const selectedTargets = nullableSetFlag(argv, 'selected-targets-json');
+  const selectedProducts = nullableSetFlag(argv, 'selected-products-json');
+  if (matrix === 'extension-artifacts-native') {
+    printJson(
+      extensionArtifactsNativeMatrix(
+        nativeTarget,
+        selectedTargets ?? undefined,
+        selectedProducts ?? undefined,
+      ),
+    );
+  } else if (matrix === 'extension-artifacts-wasix') {
+    printJson(extensionArtifactsWasixMatrix(wasmTarget, selectedProducts ?? undefined));
+  } else {
+    fail(`unsupported matrix query ${matrix}`);
+  }
+}
+
+function usage() {
+  return `usage: bash tools/ci/ci-plan.sh [command]
+
+Default command emits GitHub Actions outputs and target/graph/ci-plan.json.
+
+Commands:
+  config
+  jobs-for-affected --tasks-json JSON
+  native-target-subset --jobs-json JSON --tasks-json JSON
+  selected-extension-products --direct-projects-json JSON --tasks-json JSON --jobs-json JSON
+  plan-full [--wasm-target TARGET] [--native-target TARGET] [--mobile-target TARGET]
+  mobile-extension-package-native-targets --jobs-json JSON --selected-targets-json JSON|null
+  matrix extension-artifacts-native|extension-artifacts-wasix [selection flags]
+`;
+}
+
+async function main(argv) {
+  const [command, ...rest] = argv;
+  if (command === undefined) {
+    process.exit(await emitGithubOutputs());
+  }
+  if (command === '--help' || command === '-h') {
+    console.log(usage());
+  } else if (command === 'config') {
+    printJson({
+      baseJobs: sorted(BASE_JOBS),
+      builderJobs: sorted(BUILDER_JOBS),
+      ciJobTargets: CI_JOB_TARGETS,
+      ciJobsConfig: CI_JOBS_CONFIG,
+    });
+  } else if (command === 'jobs-for-affected') {
+    printJson(sorted(planJobsForAffected(setFlag(rest, 'tasks-json'))));
+  } else if (command === 'native-target-subset') {
+    const targets = nativeTargetSubsetForJobs(
+      setFlag(rest, 'jobs-json'),
+      setFlag(rest, 'tasks-json'),
+    );
+    printJson(targets === null ? null : sorted(targets));
+  } else if (command === 'selected-extension-products') {
+    const selected = selectedExtensionProductsForPlan(
+      setFlag(rest, 'direct-projects-json'),
+      setFlag(rest, 'tasks-json'),
+      setFlag(rest, 'jobs-json'),
+    );
+    printJson(selected === null ? null : sorted(selected));
+  } else if (command === 'plan-full') {
+    printPlanForFullRun(rest);
+  } else if (command === 'mobile-extension-package-native-targets') {
+    printJson(
+      mobileExtensionPackageNativeTargets(
+        setFlag(rest, 'jobs-json'),
+        nullableSetFlag(rest, 'selected-targets-json'),
+      ),
+    );
+  } else if (command === 'matrix') {
+    const [matrix, ...matrixRest] = rest;
+    printMatrix(matrixRest, matrix);
+  } else {
+    fail(`unknown command ${command}`);
+  }
+}
+
+if (import.meta.main) {
+  await main(Bun.argv.slice(2));
+}
diff --git a/tools/ci/moon.yml b/tools/ci/moon.yml
new file mode 100644
index 000000000..2a3a7d10f
--- /dev/null
+++ b/tools/ci/moon.yml
@@ -0,0 +1,16 @@
+$schema: "https://moonrepo.dev/schemas/project.json"
+id: "ci-tools"
+language: "bash"
+layer: "tool"
+stack: "infrastructure"
+tags: ["javascript-quality", "tools", "ci"]
+project:
+  title: "CI adapters"
+  description: "Map Moon tasks to hosted jobs and transfer their prepared outputs."
+tasks:
+  test:
+    tags: ["quality", "unit"]
+    command: "bash tools/ci/start-android-emulator-ci.test.sh"
+    inputs: ["start-android-emulator-ci.sh", "start-android-emulator-ci.test.sh"]
+    options:
+      runFromWorkspaceRoot: true
diff --git a/tools/dev/start-android-emulator-ci.sh b/tools/ci/start-android-emulator-ci.sh
similarity index 94%
rename from tools/dev/start-android-emulator-ci.sh
rename to tools/ci/start-android-emulator-ci.sh
index 6d71b95ae..cdb84dc38 100755
--- a/tools/dev/start-android-emulator-ci.sh
+++ b/tools/ci/start-android-emulator-ci.sh
@@ -13,13 +13,8 @@ need_cmd() {
 ensure_kvm_access() {
   [ "$abi" = "x86_64" ] || return 0
   [ -e /dev/kvm ] || fail "x86_64 Android emulator requires /dev/kvm on Linux CI"
-  [ -r /dev/kvm ] && [ -w /dev/kvm ] && return 0
-  need_cmd sudo
-  sudo chmod a+rw /dev/kvm ||
-    fail "failed to make /dev/kvm readable and writable for Android emulator"
-  if [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then
-    fail "x86_64 Android emulator still cannot access /dev/kvm after permission fix"
-  fi
+  [ -r /dev/kvm ] && [ -w /dev/kvm ] ||
+    fail "runner setup must grant read/write access to /dev/kvm before starting the emulator"
 }
 
 [ -n "${ANDROID_HOME:-}" ] || fail "ANDROID_HOME is not set"
diff --git a/tools/dev/start-android-emulator-ci.test.sh b/tools/ci/start-android-emulator-ci.test.sh
similarity index 98%
rename from tools/dev/start-android-emulator-ci.test.sh
rename to tools/ci/start-android-emulator-ci.test.sh
index 01275b960..395c254fc 100755
--- a/tools/dev/start-android-emulator-ci.test.sh
+++ b/tools/ci/start-android-emulator-ci.test.sh
@@ -5,7 +5,7 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
   echo "must run inside the Oliphaunt git checkout" >&2
   exit 1
 }
-launcher="$root/tools/dev/start-android-emulator-ci.sh"
+launcher="$root/tools/ci/start-android-emulator-ci.sh"
 tmp="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-android-emulator-test.XXXXXX")"
 trap 'rm -rf "$tmp"' EXIT HUP INT TERM
 
diff --git a/tools/ci/with-projects.sh b/tools/ci/with-projects.sh
new file mode 100644
index 000000000..41d8a8327
--- /dev/null
+++ b/tools/ci/with-projects.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+while IFS= read -r name; do
+  case "$name" in PROTO_*) unset "$name" ;; esac
+done < <(compgen -e)
+moon_bin="${MOON_BIN:-moon}"
+expected=$(sed -n 's/^moon *= *"\([^"]*\)".*/\1/p' .prototools)
+if [[ -z "$expected" || "$("$moon_bin" --version)" != "moon $expected" ]]; then
+  echo "Moon $expected is required" >&2; exit 1
+fi
+projects="$(mktemp)"
+trap 'rm -f "$projects"' EXIT
+export OLIPHAUNT_MOON_PROJECTS_FILE="$projects"
+"$moon_bin" query projects > "$projects"
+if [[ "${1:-}" == --exec ]]; then
+  shift
+  "$@"
+else
+  bash tools/dev/bun.sh "$@"
+fi
diff --git a/tools/ci/workflow-moon-transfers.test.mts b/tools/ci/workflow-moon-transfers.test.mts
new file mode 100644
index 000000000..742dd29fe
--- /dev/null
+++ b/tools/ci/workflow-moon-transfers.test.mts
@@ -0,0 +1,273 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import {
+  chmodSync,
+  existsSync,
+  mkdirSync,
+  readFileSync,
+  readlinkSync,
+  statSync,
+  symlinkSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import test from 'node:test';
+import { CI_JOB_TARGETS } from './ci_plan.mts';
+import { resolveExecution } from '../../.github/scripts/resolve-planned-moon-execution.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../..');
+const workflow = Bun.YAML.parse(readFileSync(path.join(ROOT, '.github/workflows/ci.yml'), 'utf8'));
+const graphFile = process.env.OLIPHAUNT_MOON_TASK_GRAPH_FILE;
+assert.ok(graphFile, 'run through tools/ci/check-workflows.sh');
+const tasks = new Map(
+  Object.values(JSON.parse(readFileSync(graphFile, 'utf8')).data).map((task) => [
+    task.target,
+    task,
+  ]),
+);
+
+if (!process.env.OLIPHAUNT_TRANSFER_FIXTURE_PHASE)
+  test('artifact production waits for source check and test results without a dependency cycle', () => {
+    const jobs = workflow.jobs;
+    const sourceJobs = new Set([
+      'affected',
+      'release-intent',
+      'check-targets',
+      'policy-targets',
+      'test-targets',
+      'checks',
+      'tests',
+    ]);
+    const ancestors = (id, visiting = new Set()) => {
+      assert(!visiting.has(id), `workflow dependency cycle at ${id}`);
+      const chain = new Set([...visiting, id]);
+      const result = new Set();
+      for (const dependency of [jobs[id].needs ?? []].flat()) {
+        assert(jobs[dependency], `${id} requires unknown job ${dependency}`);
+        result.add(dependency);
+        for (const ancestor of ancestors(dependency, chain)) result.add(ancestor);
+      }
+      return result;
+    };
+    for (const [id, job] of Object.entries(jobs)) {
+      const dependencies = ancestors(id);
+      if (sourceJobs.has(id) || !dependencies.has('affected')) continue;
+      assert(dependencies.has('checks'), `${id} can start before source checks`);
+      assert(dependencies.has('tests'), `${id} can start before source tests`);
+      const direct = [job.needs ?? []].flat();
+      if (direct.includes('checks') && direct.includes('tests') && direct.length === 3)
+        assert(
+          !/always\(|!cancelled\(/u.test(job.if ?? ''),
+          `${id} must require successful source gates`,
+        );
+    }
+  });
+
+if (!process.env.OLIPHAUNT_TRANSFER_FIXTURE_PHASE)
+  test('cross-workflow artifact gates reference existing producer job names', () => {
+    const jobNames = Object.values(workflow.jobs).map((job) => job.name);
+    for (const file of ['release.yml', 'mobile-e2e.yml']) {
+      const consumer = Bun.YAML.parse(
+        readFileSync(path.join(ROOT, '.github/workflows', file), 'utf8'),
+      );
+      for (const job of Object.values(consumer.jobs)) {
+        for (const step of job.steps ?? []) {
+          const run = String(step.run ?? '');
+          if (!/download-build-artifacts[.]sh|require-workflow-success[.]sh/u.test(run)) continue;
+          for (const match of run.matchAll(/--job\s+(?:"([^"]+)"|'([^']+)'|([^\s\\]+))/gu)) {
+            const name = match[1] ?? match[2] ?? match[3];
+            assert.equal(
+              jobNames.filter((candidate) => candidate === name).length,
+              1,
+              `${file}: ${step.name} requires exactly one CI job named ${name}`,
+            );
+          }
+        }
+      }
+    }
+  });
+
+if (!process.env.OLIPHAUNT_TRANSFER_FIXTURE_PHASE)
+  test('extension package assembly consumes transferred artifacts without compiler prerequisites', () => {
+    const step = workflow.jobs['extension-packages'].steps.find(
+      (step) => step.name === 'Assemble exact-extension product packages',
+    );
+    const execution = resolveExecution(
+      ['extension-packages:package'],
+      JSON.parse(step.env.OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON),
+      tasks,
+    );
+    assert.deepEqual(execution.localDependencies, []);
+    assert.deepEqual(execution.targets, ['extension-packages:package']);
+  });
+
+function dependencies(target) {
+  const task = tasks.get(target);
+  assert.ok(task, `workflow root ${target} must exist in Moon`);
+  return (task.deps ?? [])
+    .map((dependency) => (typeof dependency === 'string' ? dependency : dependency.target))
+    .filter((target) => {
+      const dependency = tasks.get(target);
+      return !(
+        dependency?.options?.internal &&
+        dependency.command === 'noop' &&
+        !dependency.script
+      );
+    });
+}
+
+if (!process.env.OLIPHAUNT_TRANSFER_FIXTURE_PHASE)
+  test('downloaded Moon dependencies are explicit reachable handoffs', () => {
+    for (const [workflowJob, job] of Object.entries(workflow.jobs)) {
+      const steps = job.steps ?? [];
+      for (const [index, step] of steps.entries()) {
+        const run = String(step.run ?? '');
+        assert.doesNotMatch(
+          run,
+          /OLIPHAUNT_MOON_UPSTREAM=none|run-moon-targets[.]sh --upstream none/u,
+        );
+
+        const rawTransfers = step.env?.OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON;
+        if (rawTransfers === undefined) continue;
+        const plannedJob = run.match(/run-planned-moon-job[.]sh ([a-z0-9-]+)/u)?.[1];
+        assert.ok(plannedJob, `${workflowJob} transferred handoff must use the planned-job runner`);
+        const transfers = JSON.parse(rawTransfers);
+        assert.ok(Array.isArray(transfers) && transfers.length > 0);
+
+        let roots = CI_JOB_TARGETS[plannedJob];
+        const inlinePlan = step.env?.OLIPHAUNT_CI_JOB_TARGETS_JSON;
+        if (typeof inlinePlan === 'string' && inlinePlan.startsWith('{')) {
+          roots = JSON.parse(inlinePlan)[plannedJob];
+        }
+        assert.ok(
+          Array.isArray(roots) && roots.length > 0,
+          `${plannedJob} must resolve Moon roots`,
+        );
+        const direct = new Set(roots.flatMap(dependencies));
+        const reachable = new Set(direct);
+        for (const dependency of reachable) {
+          for (const upstream of dependencies(dependency)) reachable.add(upstream);
+        }
+        for (const transfer of transfers) {
+          assert.ok(
+            reachable.has(transfer),
+            `${workflowJob} transfers unrelated dependency ${transfer}`,
+          );
+        }
+        for (const dependency of direct) {
+          if (!transfers.includes(dependency)) {
+            assert.notEqual(
+              tasks.get(dependency)?.options?.internal,
+              true,
+              `${workflowJob} cannot directly run internal dependency ${dependency}`,
+            );
+          }
+        }
+
+        assert.ok(
+          steps
+            .slice(0, index)
+            .some(({ uses }) => String(uses ?? '').startsWith('actions/download-artifact@')),
+          `${workflowJob} declares transferred dependencies without downloading artifacts`,
+        );
+        const needs = Array.isArray(job.needs) ? job.needs : [job.needs];
+        assert.ok(
+          needs.some((need) => need && need !== 'affected'),
+          `${workflowJob} has no producer job`,
+        );
+      }
+    }
+  });
+
+const phase = process.env.OLIPHAUNT_TRANSFER_FIXTURE_PHASE;
+const scratch = process.argv[2];
+if (phase) {
+  assert.ok(scratch);
+  const postmasterRoot = 'target/oliphaunt-wasix-postmaster';
+  const nativeFiles = [
+    'runtime/build/wasmer-build.receipt',
+    'runtime/build/postmaster-executor-build.receipt',
+    'runtime/wasmer/target/release/wasmer',
+    'runtime/wasmer/target/release/wasmer-headless',
+    'runtime/postmaster-executor-target/release/oliphaunt-wasix-postmaster-executor',
+    'runtime/postmaster-executor-target/release/oliphaunt-wasix-start-proof',
+    'runtime/postmaster-executor-target/release/oliphaunt-wasix-memory-profile',
+    'runtime/postmaster-compiler-target/release/oliphaunt-wasix-postmaster-compiler',
+  ];
+  if (phase === 'prepare') {
+    for (const file of nativeFiles) {
+      const destination = path.join(scratch, 'postmaster-producer', postmasterRoot, file);
+      mkdirSync(path.dirname(destination), { recursive: true });
+      writeFileSync(destination, file);
+      chmodSync(destination, file.endsWith('.receipt') ? 0o644 : 0o755);
+    }
+    mkdirSync(path.join(scratch, 'postmaster-temp'));
+    mkdirSync(path.join(scratch, 'postmaster-consumer', postmasterRoot, 'native-input-download'), {
+      recursive: true,
+    });
+    for (const [job, name, script] of [
+      [
+        'wasix-postmaster-portable',
+        'Pack qualified Linux x64 postmaster runtime',
+        'postmaster-produce.sh',
+      ],
+      [
+        'wasix-postmaster-target',
+        'Restore qualified Linux x64 postmaster runtime',
+        'postmaster-restore.sh',
+      ],
+    ]) {
+      writeFileSync(
+        path.join(scratch, script),
+        workflow.jobs[job].steps.find((step) => step.name === name).run,
+      );
+    }
+  } else {
+    for (const file of nativeFiles) {
+      const restored = path.join(scratch, 'postmaster-consumer', postmasterRoot, file);
+      assert.equal(readFileSync(restored, 'utf8'), file);
+      assert.equal(statSync(restored).mode & 0o777, file.endsWith('.receipt') ? 0o644 : 0o755);
+    }
+  }
+  for (const [platform, title, target] of [
+    ['android', 'Android', 'android-x86_64'],
+    ['ios', 'iOS', 'ios-xcframework'],
+  ]) {
+    const staged = path.join(scratch, platform, 'staged');
+    const temporary = path.join(scratch, platform, 'temp');
+    const host = `target/liboliphaunt-mobile-host/${target}/install/bin`;
+    if (phase === 'prepare') {
+      mkdirSync(path.join(staged, host), { recursive: true });
+      mkdirSync(temporary, { recursive: true });
+      writeFileSync(path.join(staged, host, 'initdb'), '#!/bin/sh\necho executable-host-tool\n');
+      chmodSync(path.join(staged, host, 'initdb'), 0o755);
+      symlinkSync('initdb', path.join(staged, host, 'postgres'));
+      writeFileSync(path.join(staged, 'abi-receipt.json'), '{}\n');
+      const producer = workflow.jobs[`liboliphaunt-native-${platform}`].steps.find(
+        (step) => step.name === 'Preserve native build file modes and symlinks',
+      );
+      writeFileSync(path.join(scratch, platform, 'produce.sh'), producer.run);
+    }
+    for (const consumer of [`mobile-build-${platform}`, `liboliphaunt-native-${platform}-abi`]) {
+      const cwd = path.join(scratch, consumer);
+      const abi = consumer.endsWith('-abi');
+      const download = abi ? `target/liboliphaunt-native-ci/${target}` : '.';
+      if (phase === 'prepare') {
+        mkdirSync(path.join(cwd, download), { recursive: true });
+        const restore = workflow.jobs[consumer].steps.find(
+          (step) =>
+            step.name ===
+            (abi ? `Restore ${target} build outputs` : `Restore ${title} native build outputs`),
+        );
+        assert.ok(restore, consumer);
+        writeFileSync(path.join(cwd, 'restore.sh'), restore.run);
+      } else if (phase === 'verify') {
+        assert.equal(readlinkSync(path.join(cwd, host, 'postgres')), 'initdb');
+        assert.ok(existsSync(path.join(cwd, download, 'abi-receipt.json')));
+      } else {
+        throw new Error('unknown phase');
+      }
+    }
+  }
+}
diff --git a/tools/ci/workflow-moon-transfers.test.sh b/tools/ci/workflow-moon-transfers.test.sh
new file mode 100644
index 000000000..1b8dd163b
--- /dev/null
+++ b/tools/ci/workflow-moon-transfers.test.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "$0")/../.."
+: "${OLIPHAUNT_MOON_TASK_GRAPH_FILE:?run through tools/ci/check-workflows.sh}"
+scratch=$(mktemp -d)
+trap 'rm -rf "$scratch"' EXIT
+fixture=tools/ci/workflow-moon-transfers.test.mts
+bash tools/dev/bun.sh test "./$fixture"
+OLIPHAUNT_TRANSFER_FIXTURE_PHASE=prepare bash tools/dev/bun.sh "$fixture" "$scratch"
+(
+  cd "$scratch/postmaster-producer"
+  RUNNER_TEMP="$scratch/postmaster-temp" bash -euo pipefail "$scratch/postmaster-produce.sh"
+)
+cp "$scratch/postmaster-temp/postmaster-native-linux-x64.tar.gz" \
+  "$scratch/postmaster-consumer/target/oliphaunt-wasix-postmaster/native-input-download/"
+(
+  cd "$scratch/postmaster-consumer"
+  bash -euo pipefail "$scratch/postmaster-restore.sh"
+)
+(
+  cd "$scratch/postmaster-producer"
+  rm target/oliphaunt-wasix-postmaster/runtime/build/wasmer-build.receipt
+  if RUNNER_TEMP="$scratch/postmaster-temp" bash -euo pipefail "$scratch/postmaster-produce.sh" >/dev/null 2>&1; then
+    echo 'native transfer must reject missing build receipts' >&2
+    exit 1
+  fi
+)
+for platform in android ios; do
+  target=ios-xcframework
+  [[ "$platform" != android ]] || target=android-x86_64
+  (
+    cd "$scratch/$platform/staged"
+    NATIVE_ARTIFACT_ROOT="$PWD" RUNNER_TEMP="$scratch/$platform/temp" bash -euo pipefail "$scratch/$platform/produce.sh"
+  )
+  # GitHub normalizes the uploaded archive mode; its payload must retain original modes.
+  chmod 644 "$scratch/$platform/temp/native-target.tar.gz"
+  for consumer in "mobile-build-$platform" "liboliphaunt-native-$platform-abi"; do
+    download=.
+    [[ "$consumer" != *-abi ]] || download="target/liboliphaunt-native-ci/$target"
+    cp "$scratch/$platform/temp/native-target.tar.gz" "$scratch/$consumer/$download/"
+    (
+      cd "$scratch/$consumer"
+      bash -euo pipefail restore.sh
+      [[ $("./target/liboliphaunt-mobile-host/$target/install/bin/postgres") == executable-host-tool ]]
+    )
+  done
+done
+OLIPHAUNT_TRANSFER_FIXTURE_PHASE=verify bash tools/dev/bun.sh "$fixture" "$scratch"
diff --git a/tools/ci/workflow-security.mts b/tools/ci/workflow-security.mts
new file mode 100644
index 000000000..80e905889
--- /dev/null
+++ b/tools/ci/workflow-security.mts
@@ -0,0 +1,209 @@
+#!/usr/bin/env bun
+
+import { readFileSync, readdirSync } from 'node:fs';
+import path from 'node:path';
+
+const ROOT = path.resolve(import.meta.dir, '../..');
+const FULL_COMMIT_SHA = /^[0-9a-f]{40}$/u;
+const FULL_DIGEST = /^[0-9a-f]{64}$/u;
+
+function invariant(condition, message) {
+  if (!condition) throw new Error(`workflow security: ${message}`);
+}
+
+function object(value) {
+  return value !== null && typeof value === 'object' && !Array.isArray(value);
+}
+
+function yamlFiles(root, relativeRoot) {
+  const files = [];
+  const visit = (relative) => {
+    for (const entry of readdirSync(path.join(root, relative), { withFileTypes: true })) {
+      const child = path.join(relative, entry.name);
+      if (entry.isDirectory()) visit(child);
+      else if (entry.isFile() && /[.]ya?ml$/u.test(entry.name)) files.push(child);
+    }
+  };
+  visit(relativeRoot);
+  return files.sort();
+}
+
+function parseYaml(root, relativePath) {
+  try {
+    const value = Bun.YAML.parse(readFileSync(path.join(root, relativePath), 'utf8'));
+    invariant(object(value), `${relativePath} must contain a YAML object`);
+    return value;
+  } catch (cause) {
+    if (cause instanceof Error && cause.message.startsWith('workflow security:')) throw cause;
+    throw new Error(`workflow security: cannot parse ${relativePath}: ${cause.message}`);
+  }
+}
+
+function remoteUse(value) {
+  const uses = String(value ?? '');
+  if (!uses || uses.startsWith('./')) return undefined;
+  if (uses.startsWith('docker://')) {
+    const revision = uses.match(/@sha256:([0-9a-f]+)$/u)?.[1];
+    return { immutable: revision !== undefined && FULL_DIGEST.test(revision), uses };
+  }
+  const separator = uses.lastIndexOf('@');
+  const revision = separator === -1 ? '' : uses.slice(separator + 1);
+  return { immutable: FULL_COMMIT_SHA.test(revision), uses };
+}
+
+export function assertPinnedRemoteUses(document, label) {
+  const visit = (value, location) => {
+    if (Array.isArray(value)) {
+      value.forEach((entry, index) => {
+        visit(entry, `${location}[${index}]`);
+      });
+      return;
+    }
+    if (!object(value)) return;
+    for (const [key, child] of Object.entries(value)) {
+      const childLocation = `${location}.${key}`;
+      if (key === 'uses') {
+        const remote = remoteUse(child);
+        invariant(
+          remote === undefined || remote.immutable,
+          `${childLocation} must pin ${remote?.uses ?? child} by commit or digest`,
+        );
+      } else {
+        visit(child, childLocation);
+      }
+    }
+  };
+  visit(document, label);
+}
+
+function assertPermissions(workflow, label) {
+  invariant(object(workflow.permissions), `${label} must declare top-level permissions`);
+  invariant(Object.keys(workflow.permissions).length > 0, `${label} permissions cannot be empty`);
+  for (const [scope, access] of Object.entries(workflow.permissions)) {
+    invariant(
+      access === 'read' || access === 'none',
+      `${label} top-level ${scope} permission must be read-only`,
+    );
+  }
+
+  for (const [jobId, job] of Object.entries(workflow.jobs)) {
+    if (job.permissions === undefined) continue;
+    invariant(object(job.permissions), `${label} ${jobId} permissions must be explicit`);
+    for (const [scope, access] of Object.entries(job.permissions)) {
+      invariant(
+        access === 'read' || access === 'write' || access === 'none',
+        `${label} ${jobId} has invalid ${scope} permission ${String(access)}`,
+      );
+    }
+    if (job.permissions['id-token'] === 'write') {
+      invariant(
+        typeof job.environment === 'string' && job.environment.length > 0,
+        `${label} ${jobId} must use a protected environment before requesting an OIDC token`,
+      );
+    }
+  }
+}
+
+function actionName(step) {
+  return String(step.uses ?? '').split('@')[0];
+}
+
+function assertArtifactsAndCheckouts(workflow, label) {
+  for (const [jobId, job] of Object.entries(workflow.jobs)) {
+    const canWrite = object(job.permissions) && Object.values(job.permissions).includes('write');
+    for (const [index, step] of (job.steps ?? []).entries()) {
+      const location = `${label} ${jobId}.steps[${index}]`;
+      const action = actionName(step);
+      if (action === 'actions/checkout') {
+        invariant(
+          step.with?.['persist-credentials'] === false,
+          `${location} checkout must disable persisted credentials`,
+        );
+        const ref = step.with?.ref;
+        invariant(
+          ref === undefined || FULL_COMMIT_SHA.test(String(ref)) || String(ref).startsWith('${{'),
+          `${location} checkout must use the triggering commit or an explicit SHA expression`,
+        );
+      }
+
+      if (action === 'actions/upload-artifact') {
+        invariant(
+          typeof step.with?.name === 'string' && step.with.name.length > 0,
+          `${location} upload must name its artifact`,
+        );
+        invariant(
+          typeof step.with?.path === 'string' && step.with.path.length > 0,
+          `${location} upload must declare its source path`,
+        );
+      }
+
+      if (action === 'actions/download-artifact') {
+        const selectors = ['name', 'pattern', 'artifact-ids'].filter(
+          (key) => typeof step.with?.[key] === 'string' && step.with[key].length > 0,
+        );
+        invariant(
+          selectors.length === 1,
+          `${location} download must select artifacts by one name, pattern, or ID`,
+        );
+        invariant(
+          typeof step.with?.path === 'string' && step.with.path.length > 0,
+          `${location} download must use an explicit destination`,
+        );
+        invariant(
+          step.with?.repository === undefined,
+          `${location} cannot download artifacts from another repository`,
+        );
+        if (step.with?.['run-id'] !== undefined || step.with?.['github-token'] !== undefined) {
+          invariant(
+            !canWrite &&
+              selectors[0] === 'artifact-ids' &&
+              typeof step.with?.['run-id'] === 'string',
+            `${location} downloads from another run require exact artifact IDs in a read-only job`,
+          );
+        }
+        invariant(
+          !canWrite || selectors[0] === 'artifact-ids',
+          `${location} in a write-capable job must select an exact artifact ID`,
+        );
+      }
+    }
+  }
+}
+
+export function assertWorkflowSecurity(workflow, label = 'workflow') {
+  invariant(
+    object(workflow.jobs) && Object.keys(workflow.jobs).length > 0,
+    `${label} must declare jobs`,
+  );
+  assertPinnedRemoteUses(workflow, label);
+  assertPermissions(workflow, label);
+  assertArtifactsAndCheckouts(workflow, label);
+}
+
+export function checkRepositoryWorkflowSecurity(root = ROOT) {
+  const workflows = yamlFiles(root, '.github/workflows');
+  const actions = yamlFiles(root, '.github/actions');
+  for (const relativePath of workflows) {
+    assertWorkflowSecurity(parseYaml(root, relativePath), relativePath);
+  }
+  for (const relativePath of actions) {
+    assertPinnedRemoteUses(parseYaml(root, relativePath), relativePath);
+  }
+  return { actions: actions.length, workflows: workflows.length };
+}
+
+if (import.meta.main) {
+  if (process.argv.includes('--help')) {
+    console.log('usage: workflow-security.mts');
+  } else {
+    try {
+      const summary = checkRepositoryWorkflowSecurity();
+      console.log(
+        `workflow security checks passed (${summary.workflows} workflows, ${summary.actions} actions)`,
+      );
+    } catch (cause) {
+      console.error(cause instanceof Error ? cause.message : String(cause));
+      process.exitCode = 1;
+    }
+  }
+}
diff --git a/tools/ci/workflow-security.test.mts b/tools/ci/workflow-security.test.mts
new file mode 100644
index 000000000..e881a247c
--- /dev/null
+++ b/tools/ci/workflow-security.test.mts
@@ -0,0 +1,124 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import test from 'node:test';
+
+import { assertPinnedRemoteUses, assertWorkflowSecurity } from './workflow-security.mts';
+
+const SHA = 'de0fac2e4500dabe0009e67214ff5f5447ce83dd';
+
+function workflow(steps = [], extra = {}) {
+  return {
+    on: { workflow_dispatch: {} },
+    permissions: { contents: 'read' },
+    jobs: {
+      check: {
+        'runs-on': 'ubuntu-24.04',
+        steps,
+      },
+    },
+    ...extra,
+  };
+}
+
+test('remote actions require immutable revisions', () => {
+  assert.doesNotThrow(() =>
+    assertPinnedRemoteUses(
+      {
+        steps: [
+          { uses: `actions/checkout@${SHA}` },
+          { uses: './.github/actions/setup-bun' },
+          { uses: `docker://example/image@sha256:${'a'.repeat(64)}` },
+        ],
+      },
+      'fixture',
+    ),
+  );
+
+  for (const uses of ['actions/checkout@v4', 'docker://example/image:latest']) {
+    assert.throws(() => assertPinnedRemoteUses({ steps: [{ uses }] }, 'fixture'), /must pin/u);
+  }
+});
+
+test('workflow-wide permissions stay read-only', () => {
+  const candidate = workflow();
+  candidate.permissions.contents = 'write';
+  assert.throws(() => assertWorkflowSecurity(candidate), /top-level contents permission/u);
+});
+
+test('OIDC tokens require a protected environment', () => {
+  const candidate = workflow();
+  candidate.jobs.check.permissions = { contents: 'read', 'id-token': 'write' };
+  assert.throws(() => assertWorkflowSecurity(candidate), /protected environment/u);
+  candidate.jobs.check.environment = 'release';
+  assert.doesNotThrow(() => assertWorkflowSecurity(candidate));
+});
+
+test('checkouts do not retain credentials or use mutable literal refs', () => {
+  const candidate = workflow([
+    {
+      uses: `actions/checkout@${SHA}`,
+      with: { ref: 'main', 'persist-credentials': false },
+    },
+  ]);
+  assert.throws(() => assertWorkflowSecurity(candidate), /explicit SHA expression/u);
+  candidate.jobs.check.steps[0].with.ref = '${{ github.sha }}';
+  assert.doesNotThrow(() => assertWorkflowSecurity(candidate));
+  candidate.jobs.check.steps[0].with['persist-credentials'] = true;
+  assert.throws(() => assertWorkflowSecurity(candidate), /disable persisted credentials/u);
+});
+
+test('cross-run recovery downloads require immutable IDs and read-only permissions', () => {
+  const candidate = workflow([
+    {
+      uses: `actions/download-artifact@${SHA}`,
+      with: { name: 'candidate', path: 'target/candidate' },
+    },
+  ]);
+  assert.doesNotThrow(() => assertWorkflowSecurity(candidate));
+
+  candidate.jobs.check.steps[0].with['run-id'] = '123';
+  assert.throws(() => assertWorkflowSecurity(candidate), /another run require exact artifact IDs/u);
+  candidate.jobs.check.steps[0].with = {
+    'run-id': '123',
+    'artifact-ids': '901,902',
+    path: 'target/candidate',
+  };
+  assert.doesNotThrow(() => assertWorkflowSecurity(candidate));
+  candidate.jobs.check.permissions = { contents: 'write' };
+  assert.throws(() => assertWorkflowSecurity(candidate), /read-only job/u);
+  candidate.jobs.check.permissions = { contents: 'read' };
+  candidate.jobs.check.steps[0].with = { name: 'candidate', path: 'target/candidate' };
+  delete candidate.jobs.check.steps[0].with.name;
+  assert.throws(() => assertWorkflowSecurity(candidate), /must select artifacts/u);
+  candidate.jobs.check.steps[0].with = { name: 'candidate' };
+  assert.throws(() => assertWorkflowSecurity(candidate), /explicit destination/u);
+});
+
+test('write-capable jobs consume artifacts only by exact ID', () => {
+  const candidate = workflow([
+    {
+      uses: `actions/download-artifact@${SHA}`,
+      with: { name: 'candidate', path: 'target/candidate' },
+    },
+  ]);
+  candidate.jobs.check.permissions = { contents: 'write' };
+  assert.throws(() => assertWorkflowSecurity(candidate), /exact artifact ID/u);
+  candidate.jobs.check.steps[0].with = {
+    'artifact-ids': '${{ needs.build.outputs.artifact_id }}',
+    path: 'target/candidate',
+  };
+  assert.doesNotThrow(() => assertWorkflowSecurity(candidate));
+});
+
+test('artifact uploads have an identity and source', () => {
+  const candidate = workflow([
+    {
+      uses: `actions/upload-artifact@${SHA}`,
+      with: { name: 'proof', path: 'target/proof' },
+    },
+  ]);
+  assert.doesNotThrow(() => assertWorkflowSecurity(candidate));
+  delete candidate.jobs.check.steps[0].with.path;
+  assert.throws(() => assertWorkflowSecurity(candidate), /source path/u);
+});
diff --git a/tools/coverage/check-product b/tools/coverage/check-product
deleted file mode 100755
index 45817dd72..000000000
--- a/tools/coverage/check-product
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env sh
-set -eu
-root="$(git rev-parse --show-toplevel 2>/dev/null)"
-exec "$root/tools/dev/bun.sh" "$root/tools/coverage/coverage.mjs" check-product "$@"
diff --git a/tools/coverage/coverage-policy.test.mjs b/tools/coverage/coverage-policy.test.mjs
deleted file mode 100644
index f3cb16a9e..000000000
--- a/tools/coverage/coverage-policy.test.mjs
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env bun
-
-import assert from 'node:assert/strict';
-import test from 'node:test';
-
-import { coveragePolicyWarnings } from './coverage.mjs';
-
-const config = { line_threshold: 80, per_file_line_warning: 50 };
-const summary = {
-  covered_lines: 80,
-  total_lines: 100,
-  line_coverage: 80,
-  files: [
-    { path: 'src/healthy.rs', covered_lines: 76, total_lines: 80 },
-    { path: 'src/storage.rs', covered_lines: 4, total_lines: 20 },
-  ],
-};
-
-test('low per-file coverage warns while low overall and missing evidence fail', () => {
-  assert.deepEqual(coveragePolicyWarnings('sdk', summary, config), [
-    'sdk: src/storage.rs line coverage 20.00% is below advisory 50.00%',
-  ]);
-  assert.throws(
-    () => coveragePolicyWarnings('sdk', { ...summary, covered_lines: 79, line_coverage: 79 }, config),
-    /below threshold/u,
-  );
-  assert.throws(
-    () => coveragePolicyWarnings('sdk', { ...summary, files: [] }, config),
-    /no measured source files/u,
-  );
-});
diff --git a/tools/coverage/coverage.mjs b/tools/coverage/coverage.mjs
deleted file mode 100755
index ceceda55f..000000000
--- a/tools/coverage/coverage.mjs
+++ /dev/null
@@ -1,1058 +0,0 @@
-#!/usr/bin/env bun
-import { spawnSync } from 'node:child_process';
-import {
-  constants,
-  copyFileSync,
-  existsSync,
-  mkdirSync,
-  readFileSync,
-  readdirSync,
-  rmSync,
-  statSync,
-  accessSync,
-  writeFileSync,
-} from 'node:fs';
-import path from 'node:path';
-
-import { captureCommandOutput } from '../dev/capture-command-output.mjs';
-
-const PRODUCTS = [
-  'oliphaunt-rust',
-  'oliphaunt-swift',
-  'oliphaunt-kotlin',
-  'oliphaunt-js',
-  'oliphaunt-react-native',
-  'oliphaunt-wasix-rust',
-  'oliphaunt-wasix-ts',
-];
-
-const PRODUCT_SOURCE_ROOTS = new Map([
-  ['oliphaunt-rust', 'src/sdks/rust'],
-  ['oliphaunt-swift', 'src/sdks/swift'],
-  ['oliphaunt-kotlin', 'src/sdks/kotlin'],
-  ['oliphaunt-js', 'src/sdks/js'],
-  ['oliphaunt-react-native', 'src/sdks/react-native'],
-  ['oliphaunt-wasix-rust', 'src/bindings/wasix-rust/crates/oliphaunt-wasix'],
-  ['oliphaunt-wasix-ts', 'src/bindings/wasix-ts'],
-]);
-
-const FORBIDDEN_PATH_PARTS = [
-  '/node_modules/',
-  '/target/',
-  '/.build/',
-  '/DerivedData/',
-  '/build/',
-  '/.cxx/',
-  '/generated/',
-  '/vendor/',
-];
-
-const ROOT = path.resolve(import.meta.dir, '..', '..');
-const BASELINE = path.join(ROOT, 'coverage/baseline.toml');
-const COVERAGE_ROOT = path.join(ROOT, 'target/coverage');
-const globRegexCache = new Map();
-
-function fail(message) {
-  console.error(`coverage.mjs: ${message}`);
-  process.exit(1);
-}
-
-function posixPath(value) {
-  return value.split(path.sep).join('/');
-}
-
-function relPath(value) {
-  const raw = String(value);
-  const resolved = path.isAbsolute(raw) ? path.resolve(raw) : path.resolve(ROOT, raw);
-  const relative = path.relative(ROOT, resolved);
-  if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
-    return posixPath(relative);
-  }
-  return posixPath(raw);
-}
-
-function run(command, { cwd = ROOT, env = process.env } = {}) {
-  console.log(`\n==> ${command.join(' ')}`);
-  const result = spawnSync(command[0], command.slice(1), {
-    cwd,
-    env,
-    stdio: 'inherit',
-  });
-  if (result.error) {
-    throw result.error;
-  }
-  if (result.status !== 0) {
-    process.exit(result.status ?? 1);
-  }
-}
-
-function capture(command, { cwd = ROOT, env = process.env } = {}) {
-  console.log(`\n==> ${command.join(' ')}`);
-  const result = captureCommandOutput(command[0], command.slice(1), {
-    cwd,
-    env,
-    label: command.join(' '),
-  });
-  if (result.error) {
-    throw result.error;
-  }
-  const output = `${result.stdout ?? ''}${result.stderr ?? ''}`;
-  process.stdout.write(output);
-  if (result.status !== 0) {
-    process.exit(result.status ?? 1);
-  }
-  return output;
-}
-
-function optionalCapture(command, { cwd = ROOT } = {}) {
-  const result = captureCommandOutput(command[0], command.slice(1), {
-    cwd,
-    label: command.join(' '),
-  });
-  if (result.error || result.status !== 0) {
-    return null;
-  }
-  const value = result.stdout.trim();
-  return value || null;
-}
-
-function isExecutable(file) {
-  try {
-    accessSync(file, constants.X_OK);
-    return true;
-  } catch {
-    return false;
-  }
-}
-
-function which(name) {
-  const pathValue = process.env.PATH ?? '';
-  const extensions = process.platform === 'win32'
-    ? (process.env.PATHEXT ?? '.EXE;.CMD;.BAT;.COM').split(';')
-    : [''];
-  for (const directory of pathValue.split(path.delimiter)) {
-    if (!directory) {
-      continue;
-    }
-    for (const extension of extensions) {
-      const candidate = path.join(directory, `${name}${extension}`);
-      if (existsSync(candidate) && statSync(candidate).isFile() && isExecutable(candidate)) {
-        return candidate;
-      }
-    }
-  }
-  return null;
-}
-
-function requireTool(name, installHint) {
-  if (which(name) === null) {
-    fail(`missing required coverage tool: ${name}\n\nInstall with:\n  ${installHint}`);
-  }
-}
-
-function commandOk(command) {
-  const result = spawnSync(command[0], command.slice(1), {
-    cwd: ROOT,
-    stdio: 'ignore',
-  });
-  return !result.error && result.status === 0;
-}
-
-function loadBaseline() {
-  if (!existsSync(BASELINE) || !statSync(BASELINE).isFile()) {
-    fail(`missing coverage baseline: ${relPath(BASELINE)}`);
-  }
-  const data = Bun.TOML.parse(readFileSync(BASELINE, 'utf8'));
-  if (!data.products || typeof data.products !== 'object' || Array.isArray(data.products)) {
-    fail('coverage baseline must define [products.] tables');
-  }
-  return data;
-}
-
-function productConfig(product) {
-  const data = loadBaseline();
-  const config = data.products[product];
-  if (!config || typeof config !== 'object' || Array.isArray(config)) {
-    fail(`coverage baseline does not define product ${JSON.stringify(product)}`);
-  }
-  return config;
-}
-
-function outputDir(product) {
-  return path.join(COVERAGE_ROOT, product);
-}
-
-function productSourceRoot(product) {
-  const source = PRODUCT_SOURCE_ROOTS.get(product);
-  if (source === undefined) {
-    fail(`missing source root mapping for coverage product ${product}`);
-  }
-  return path.join(ROOT, source);
-}
-
-function productSourcePrefix(product) {
-  return relPath(productSourceRoot(product));
-}
-
-function resetOutput(product) {
-  const out = outputDir(product);
-  rmSync(out, { recursive: true, force: true });
-  mkdirSync(out, { recursive: true });
-  return out;
-}
-
-function escapeRegExp(value) {
-  return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
-}
-
-function repoGlobRegex(pattern) {
-  const normalized = pattern.replaceAll(path.sep, '/');
-  const cached = globRegexCache.get(normalized);
-  if (cached !== undefined) {
-    return cached;
-  }
-  const parts = ['^'];
-  let index = 0;
-  while (index < normalized.length) {
-    const char = normalized[index];
-    if (char === '*') {
-      if (index + 1 < normalized.length && normalized[index + 1] === '*') {
-        index += 2;
-        if (index < normalized.length && normalized[index] === '/') {
-          index += 1;
-          parts.push('(?:.*/)?');
-        } else {
-          parts.push('.*');
-        }
-        continue;
-      }
-      parts.push('[^/]*');
-    } else if (char === '?') {
-      parts.push('[^/]');
-    } else {
-      parts.push(escapeRegExp(char));
-    }
-    index += 1;
-  }
-  parts.push('$');
-  const regex = new RegExp(parts.join(''), 'u');
-  globRegexCache.set(normalized, regex);
-  return regex;
-}
-
-function matchesAny(file, patterns) {
-  const normalized = file.replaceAll(path.sep, '/');
-  return patterns.some((pattern) => repoGlobRegex(pattern).test(normalized));
-}
-
-function sourceGlobs(config) {
-  const globs = config.source_globs;
-  if (!Array.isArray(globs) || globs.length === 0 || !globs.every((item) => typeof item === 'string')) {
-    fail('coverage product config must define non-empty source_globs');
-  }
-  return globs;
-}
-
-function excludeGlobs(config) {
-  const globs = config.exclude_globs ?? [];
-  if (!Array.isArray(globs) || !globs.every((item) => typeof item === 'string')) {
-    fail('coverage product config exclude_globs must be a list of strings');
-  }
-  return globs;
-}
-
-function waiverEntries(config) {
-  const entries = config.waivers ?? [];
-  if (!Array.isArray(entries)) {
-    fail('coverage waivers must be an array of tables');
-  }
-  return entries.map((entry) => {
-    if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
-      fail('coverage waiver entries must be tables');
-    }
-    const exact = entry.path;
-    const pattern = entry.glob;
-    if ((exact === undefined) === (pattern === undefined)) {
-      fail('coverage waiver must define exactly one of path or glob');
-    }
-    for (const [key, value] of [
-      ['path/glob', exact ?? pattern],
-      ['reason', entry.reason],
-      ['evidence', entry.evidence],
-      ['owner', entry.owner],
-      ['expires', entry.expires],
-    ]) {
-      if (typeof value !== 'string') {
-        fail(`coverage waiver ${key}, reason, evidence, owner, and expires must be strings`);
-      }
-      if (key !== 'path/glob' && value.trim() === '') {
-        fail('coverage waiver reason, evidence, owner, and expires must be non-empty');
-      }
-    }
-    return {
-      path: exact ?? '',
-      glob: pattern ?? '',
-      reason: entry.reason,
-      evidence: entry.evidence,
-      owner: entry.owner,
-      expires: entry.expires,
-    };
-  });
-}
-
-function waiverPatterns(config) {
-  return waiverEntries(config).map((waiver) => waiver.path || waiver.glob);
-}
-
-function isWaived(file, config) {
-  const relative = relPath(file);
-  for (const waiver of waiverEntries(config)) {
-    if (waiver.path && relative === waiver.path) {
-      return true;
-    }
-    if (waiver.glob && matchesAny(relative, [waiver.glob])) {
-      return true;
-    }
-  }
-  return false;
-}
-
-function allowedFile(file, config) {
-  const relative = relPath(file);
-  const normalized = `/${relative}`;
-  if (!matchesAny(relative, sourceGlobs(config))) {
-    return false;
-  }
-  if (matchesAny(relative, excludeGlobs(config))) {
-    return false;
-  }
-  if (isWaived(relative, config)) {
-    return false;
-  }
-  return !FORBIDDEN_PATH_PARTS.some((part) => normalized.includes(part));
-}
-
-function staticGlobPrefix(pattern) {
-  const wildcardIndex = pattern.search(/[*?]/u);
-  if (wildcardIndex === -1) {
-    return pattern;
-  }
-  const slashIndex = pattern.lastIndexOf('/', wildcardIndex);
-  return slashIndex === -1 ? '.' : pattern.slice(0, slashIndex);
-}
-
-function walkFiles(root) {
-  if (!existsSync(root)) {
-    return [];
-  }
-  const files = [];
-  const stack = [root];
-  while (stack.length > 0) {
-    const current = stack.pop();
-    let entries;
-    try {
-      entries = readdirSync(current, { withFileTypes: true });
-    } catch {
-      continue;
-    }
-    for (const entry of entries) {
-      const child = path.join(current, entry.name);
-      if (entry.isDirectory()) {
-        stack.push(child);
-      } else if (entry.isFile()) {
-        files.push(child);
-      }
-    }
-  }
-  return files.sort();
-}
-
-function trackedOrLocalSourceFiles(config) {
-  const files = new Set();
-  for (const pattern of sourceGlobs(config)) {
-    const prefix = staticGlobPrefix(pattern);
-    for (const candidate of walkFiles(path.join(ROOT, prefix))) {
-      const relative = relPath(candidate);
-      if (matchesAny(relative, [pattern])) {
-        files.add(relative);
-      }
-    }
-  }
-  return [...files].sort();
-}
-
-function validateWaivers(config) {
-  const files = trackedOrLocalSourceFiles(config);
-  for (const waiver of waiverEntries(config)) {
-    const matched = files.filter((file) =>
-      (waiver.path && file === waiver.path) ||
-      (waiver.glob && matchesAny(file, [waiver.glob]))
-    );
-    if (matched.length === 0) {
-      fail(`coverage waiver does not match an owned source file: ${waiver.path || waiver.glob}`);
-    }
-  }
-  return waiverEntries(config);
-}
-
-function ownedUnwaivedSourceFiles(config) {
-  validateWaivers(config);
-  const owned = [];
-  for (const file of trackedOrLocalSourceFiles(config)) {
-    const normalized = `/${file}`;
-    if (matchesAny(file, excludeGlobs(config))) {
-      continue;
-    }
-    if (isWaived(file, config)) {
-      continue;
-    }
-    if (FORBIDDEN_PATH_PARTS.some((part) => normalized.includes(part))) {
-      continue;
-    }
-    owned.push(file);
-  }
-  return owned.sort();
-}
-
-function percent(covered, total) {
-  if (total <= 0) {
-    return 0.0;
-  }
-  return Math.round((covered / total) * 10000) / 100;
-}
-
-function parseLcov(reportPath, config) {
-  const files = [];
-  let currentFile = null;
-  let currentLines = new Map();
-  const flush = () => {
-    if (currentFile === null) {
-      return;
-    }
-    if (allowedFile(currentFile, config)) {
-      const total = currentLines.size;
-      const covered = [...currentLines.values()].filter((count) => count > 0).length;
-      if (total > 0) {
-        files.push({ path: relPath(currentFile), covered_lines: covered, total_lines: total });
-      }
-    }
-    currentFile = null;
-    currentLines = new Map();
-  };
-  for (const rawLine of readFileSync(reportPath, 'utf8').split(/\r?\n/u)) {
-    const line = rawLine.trimEnd();
-    if (line.startsWith('SF:')) {
-      flush();
-      currentFile = line.slice(3);
-    } else if (line.startsWith('DA:') && currentFile !== null) {
-      const [lineNo, count] = line.slice(3).split(',');
-      currentLines.set(Number.parseInt(lineNo, 10), Number.parseInt(count, 10));
-    } else if (line === 'end_of_record') {
-      flush();
-    }
-  }
-  flush();
-  const covered = files.reduce((sum, file) => sum + file.covered_lines, 0);
-  const total = files.reduce((sum, file) => sum + file.total_lines, 0);
-  return { covered, total, files };
-}
-
-function normalizeJavascriptReportPath(product, rawPath) {
-  if (path.isAbsolute(rawPath)) {
-    return rawPath;
-  }
-  const sourcePrefix = productSourcePrefix(product);
-  if (rawPath.startsWith(`${sourcePrefix}/`)) {
-    return rawPath;
-  }
-  return `${sourcePrefix}/${rawPath}`;
-}
-
-function parseJavascriptSummary(reportPath, product, config) {
-  const data = JSON.parse(readFileSync(reportPath, 'utf8'));
-  const files = [];
-  for (const [rawPath, entry] of Object.entries(data)) {
-    const sourcePath = normalizeJavascriptReportPath(product, rawPath);
-    if (rawPath === 'total' || !allowedFile(sourcePath, config)) {
-      continue;
-    }
-    const lines = entry.lines ?? {};
-    const total = Number.parseInt(lines.total ?? 0, 10);
-    const covered = Number.parseInt(lines.covered ?? 0, 10);
-    if (total > 0) {
-      files.push({ path: relPath(sourcePath), covered_lines: covered, total_lines: total });
-    }
-  }
-  return {
-    covered: files.reduce((sum, file) => sum + file.covered_lines, 0),
-    total: files.reduce((sum, file) => sum + file.total_lines, 0),
-    files,
-  };
-}
-
-function xmlUnescape(value) {
-  return value
-    .replaceAll('"', '"')
-    .replaceAll(''', "'")
-    .replaceAll('<', '<')
-    .replaceAll('>', '>')
-    .replaceAll('&', '&');
-}
-
-function parseXmlAttributes(raw) {
-  const attributes = new Map();
-  for (const match of raw.matchAll(/([A-Za-z_:][\w:.-]*)\s*=\s*"([^"]*)"/gu)) {
-    attributes.set(match[1], xmlUnescape(match[2]));
-  }
-  return attributes;
-}
-
-function resolveKoverSourcePath(packageName, sourceFileName) {
-  const packagePath = packageName.replaceAll('.', '/');
-  const sourceRoot = path.join(productSourceRoot('oliphaunt-kotlin'), 'oliphaunt/src');
-  const candidates = walkFiles(sourceRoot)
-    .filter((candidate) => posixPath(candidate).endsWith(`${packagePath}/${sourceFileName}`))
-    .sort();
-  const sourceCandidates = candidates.filter((candidate) => !candidate.split(path.sep).includes('Test'));
-  if (sourceCandidates.length > 0) {
-    return relPath(sourceCandidates[0]);
-  }
-  if (candidates.length > 0) {
-    return relPath(candidates[0]);
-  }
-  return `src/sdks/kotlin/oliphaunt/src/${packagePath}/${sourceFileName}`;
-}
-
-function parseKoverXml(reportPath, config) {
-  const xml = readFileSync(reportPath, 'utf8');
-  const files = [];
-  for (const packageMatch of xml.matchAll(/]*)>([\s\S]*?)<\/package>/gu)) {
-    const packageName = parseXmlAttributes(packageMatch[1]).get('name') ?? '';
-    for (const sourceMatch of packageMatch[2].matchAll(/]*)>([\s\S]*?)<\/sourcefile>/gu)) {
-      const sourceFileName = parseXmlAttributes(sourceMatch[1]).get('name') ?? '';
-      const sourcePath = resolveKoverSourcePath(packageName, sourceFileName);
-      if (!allowedFile(sourcePath, config)) {
-        continue;
-      }
-      const lines = [...sourceMatch[2].matchAll(/]*)\/?>/gu)];
-      const total = lines.length;
-      const covered = lines.filter((line) => {
-        const attributes = parseXmlAttributes(line[1]);
-        return Number.parseInt(attributes.get('ci') ?? '0', 10) > 0;
-      }).length;
-      if (total > 0) {
-        files.push({ path: sourcePath, covered_lines: covered, total_lines: total });
-      }
-    }
-  }
-  return {
-    covered: files.reduce((sum, file) => sum + file.covered_lines, 0),
-    total: files.reduce((sum, file) => sum + file.total_lines, 0),
-    files,
-  };
-}
-
-function parseSwiftJson(reportPath, config) {
-  const data = JSON.parse(readFileSync(reportPath, 'utf8'));
-  const files = [];
-  for (const report of data.data ?? []) {
-    for (const fileEntry of report.files ?? []) {
-      const filename = fileEntry.filename ?? fileEntry.name;
-      if (!filename || !allowedFile(filename, config)) {
-        continue;
-      }
-      const lines = fileEntry.summary?.lines ?? {};
-      const total = Number.parseInt(lines.count ?? lines.total ?? 0, 10);
-      const covered = Number.parseInt(lines.covered ?? 0, 10);
-      if (total > 0) {
-        files.push({ path: relPath(filename), covered_lines: covered, total_lines: total });
-      }
-    }
-  }
-  return {
-    covered: files.reduce((sum, file) => sum + file.covered_lines, 0),
-    total: files.reduce((sum, file) => sum + file.total_lines, 0),
-    files,
-  };
-}
-
-function sortForJson(value) {
-  if (Array.isArray(value)) {
-    return value.map(sortForJson);
-  }
-  if (value && typeof value === 'object') {
-    return Object.fromEntries(
-      Object.entries(value)
-        .sort(([left], [right]) => left.localeCompare(right))
-        .map(([key, item]) => [key, sortForJson(item)]),
-    );
-  }
-  return value;
-}
-
-function writeJson(file, value) {
-  writeFileSync(file, `${JSON.stringify(sortForJson(value), null, 2)}\n`);
-}
-
-function writeSummary(product, tool, coveredLines, totalLines, files, reports) {
-  const out = outputDir(product);
-  const config = productConfig(product);
-  files.sort((left, right) => left.path.localeCompare(right.path));
-  const summary = {
-    schema: 'oliphaunt-coverage-summary-v1',
-    product,
-    tool,
-    line_coverage: percent(coveredLines, totalLines),
-    line_threshold: Number.parseFloat(config.line_threshold),
-    covered_lines: coveredLines,
-    total_lines: totalLines,
-    files,
-    reports: reports.map(relPath),
-    source_globs: sourceGlobs(config),
-    exclude_globs: excludeGlobs(config),
-    waived_files: waiverEntries(config).map((waiver) => ({
-      path: waiver.path || waiver.glob,
-      reason: waiver.reason,
-      evidence: waiver.evidence,
-      owner: waiver.owner,
-      expires: waiver.expires,
-    })),
-  };
-  const summaryPath = path.join(out, 'summary.json');
-  writeJson(summaryPath, summary);
-  return summaryPath;
-}
-
-export function coveragePolicyWarnings(product, summary, config) {
-  const total = Number.parseInt(summary.total_lines ?? 0, 10);
-  const covered = Number.parseInt(summary.covered_lines ?? 0, 10);
-  if (total <= 0 || covered <= 0 || covered > total) {
-    throw new Error(`${product}: coverage summary is unmeasured: covered=${covered} total=${total}`);
-  }
-  if (!Array.isArray(summary.files) || summary.files.length === 0) {
-    throw new Error(`${product}: coverage summary contains no measured source files`);
-  }
-  const measured = Number.parseFloat(summary.line_coverage);
-  const threshold = Number.parseFloat(config.line_threshold);
-  if (!Number.isFinite(measured) || !Number.isFinite(threshold)) {
-    throw new Error(`${product}: coverage summary or aggregate threshold is malformed`);
-  }
-  if (Math.abs(measured - percent(covered, total)) >= 0.005) {
-    throw new Error(`${product}: coverage summary percentage does not match its measured lines`);
-  }
-  if (measured + 0.005 < threshold) {
-    throw new Error(`${product}: line coverage ${measured.toFixed(2)}% is below threshold ${threshold.toFixed(2)}%`);
-  }
-  const perFileWarning = Number.parseFloat(config.per_file_line_warning ?? 0.0);
-  if (!Number.isFinite(perFileWarning) || perFileWarning < 0 || perFileWarning > 100) {
-    throw new Error(`${product}: per-file coverage warning threshold is malformed`);
-  }
-  const warnings = [];
-  for (const file of summary.files) {
-    const totalLines = Number.parseInt(file.total_lines ?? 0, 10);
-    const coveredLines = Number.parseInt(file.covered_lines ?? -1, 10);
-    if (typeof file.path !== 'string' || file.path.length === 0 || totalLines <= 0 || coveredLines < 0 || coveredLines > totalLines) {
-      throw new Error(`${product}: coverage summary contains malformed per-file evidence`);
-    }
-    const measuredFile = percent(coveredLines, totalLines);
-    if (perFileWarning > 0 && measuredFile + 0.005 < perFileWarning) {
-      warnings.push(`${product}: ${file.path} line coverage ${measuredFile.toFixed(2)}% is below advisory ${perFileWarning.toFixed(2)}%`);
-    }
-  }
-  return warnings;
-}
-
-function checkSummary(product) {
-  const config = productConfig(product);
-  const summaryPath = path.join(ROOT, config.summary);
-  if (!existsSync(summaryPath) || !statSync(summaryPath).isFile()) {
-    fail(`${product}: missing measured coverage summary ${relPath(summaryPath)}`);
-  }
-  const summary = JSON.parse(readFileSync(summaryPath, 'utf8'));
-  if (summary.product !== product) {
-    fail(`${product}: coverage summary product mismatch`);
-  }
-  const files = summary.files;
-  let warnings;
-  try {
-    warnings = coveragePolicyWarnings(product, summary, config);
-  } catch (cause) {
-    fail(cause instanceof Error ? cause.message : String(cause));
-  }
-  for (const warning of warnings) {
-    const sourcePath = warning.slice(warning.indexOf(': ') + 2, warning.indexOf(' line coverage'));
-    console.warn(process.env.GITHUB_ACTIONS === 'true' ? `::warning file=${sourcePath}::${warning}` : `warning: ${warning}`);
-  }
-  const summaryReports = new Set(summary.reports ?? []);
-  for (const report of config.reports ?? []) {
-    if (!summaryReports.has(report)) {
-      fail(`${product}: coverage summary is missing expected report ${report}`);
-    }
-  }
-  for (const report of summaryReports) {
-    const reportPath = path.join(ROOT, report);
-    if (!existsSync(reportPath) || !statSync(reportPath).isFile() || statSync(reportPath).size === 0) {
-      fail(`${product}: missing or empty coverage report ${report}`);
-    }
-  }
-  for (const file of files) {
-    const sourcePath = file.path ?? '';
-    const normalized = `/${sourcePath}`;
-    if (FORBIDDEN_PATH_PARTS.some((part) => normalized.includes(part))) {
-      fail(`${product}: coverage includes generated/vendor/build path ${sourcePath}`);
-    }
-    if (!allowedFile(sourcePath, config)) {
-      fail(`${product}: coverage includes a source path outside the baseline scope: ${sourcePath}`);
-    }
-  }
-  const measuredPaths = new Set(files.map((file) => file.path ?? ''));
-  const missingOwned = ownedUnwaivedSourceFiles(config).filter((file) => !measuredPaths.has(file));
-  if (missingOwned.length > 0) {
-    fail(
-      `${product}: owned source files are neither measured nor waived: ` +
-      missingOwned.slice(0, 20).join(', ') +
-      (missingOwned.length > 20 ? ' ...' : ''),
-    );
-  }
-  return summary;
-}
-
-function runRust(product) {
-  const packageName = product === 'oliphaunt-rust' ? 'oliphaunt' : 'oliphaunt-wasix';
-  const out = resetOutput(product);
-  const lcov = path.join(out, 'lcov.info');
-  requireTool('cargo', 'rustup toolchain install 1.93.1');
-  if (!commandOk(['cargo', 'llvm-cov', '--version'])) {
-    fail('missing required coverage tool: cargo-llvm-cov\n\nInstall with:\n  cargo install cargo-llvm-cov --version 0.8.7 --locked');
-  }
-  if (!commandOk(['cargo', 'nextest', '--version'])) {
-    fail('missing required coverage tool: cargo-nextest\n\nInstall with:\n  cargo install cargo-nextest --version 0.9.137 --locked');
-  }
-  const env = { ...process.env };
-  if (env.LLVM_COV === undefined) {
-    const llvmCov = which('llvm-cov') ?? optionalCapture(['xcrun', '--find', 'llvm-cov']);
-    if (llvmCov) {
-      env.LLVM_COV = llvmCov;
-    }
-  }
-  if (env.LLVM_PROFDATA === undefined) {
-    const llvmProfdata = which('llvm-profdata') ?? optionalCapture(['xcrun', '--find', 'llvm-profdata']);
-    if (llvmProfdata) {
-      env.LLVM_PROFDATA = llvmProfdata;
-    }
-  }
-  const featureArgs = product === 'oliphaunt-wasix-rust' ? ['--no-default-features'] : [];
-  const targetArgs = product === 'oliphaunt-wasix-rust' ? ['--lib'] : [];
-  run(['cargo', 'llvm-cov', 'clean', '--profraw-only'], { env });
-  run(
-    [
-      'cargo',
-      'llvm-cov',
-      'nextest',
-      '--package',
-      packageName,
-      ...targetArgs,
-      ...featureArgs,
-      '--locked',
-      '--profile',
-      'ci',
-      '--no-tests=fail',
-      '--test-threads=1',
-      '--no-report',
-    ],
-    { env },
-  );
-  run(['cargo', 'llvm-cov', 'report', '--lcov', '--output-path', lcov], { env });
-  const parsed = parseLcov(lcov, productConfig(product));
-  writeSummary(product, 'cargo-llvm-cov', parsed.covered, parsed.total, parsed.files, [lcov]);
-  checkSummary(product);
-}
-
-function runSwift() {
-  const out = resetOutput('oliphaunt-swift');
-  const scratch = path.join(ROOT, 'target/coverage-build/oliphaunt-swift');
-  rmSync(scratch, { recursive: true, force: true });
-  requireTool('swift', 'Install Xcode or the Swift toolchain');
-  run([
-    'swift',
-    'test',
-    '--package-path',
-    ROOT,
-    '--scratch-path',
-    scratch,
-    '--enable-code-coverage',
-  ]);
-  const output = capture([
-    'swift',
-    'test',
-    '--package-path',
-    ROOT,
-    '--scratch-path',
-    scratch,
-    '--show-codecov-path',
-  ]);
-  let candidates = output
-    .split(/\r?\n/u)
-    .map((line) => line.trim())
-    .filter((line) => line.endsWith('.json') && existsSync(line) && statSync(line).isFile());
-  if (candidates.length === 0) {
-    candidates = walkFiles(scratch).filter((candidate) => candidate.endsWith('.json'));
-  }
-  if (candidates.length === 0) {
-    fail('oliphaunt-swift: swift test did not emit a code coverage JSON path');
-  }
-  const report = path.join(out, 'swift-coverage.json');
-  copyFileSync(candidates.at(-1), report);
-  const parsed = parseSwiftJson(report, productConfig('oliphaunt-swift'));
-  writeSummary('oliphaunt-swift', 'swift test --enable-code-coverage', parsed.covered, parsed.total, parsed.files, [report]);
-  checkSummary('oliphaunt-swift');
-}
-
-function runKotlin() {
-  const out = resetOutput('oliphaunt-kotlin');
-  requireTool('java', 'Install JDK 17');
-  const packageDir = productSourceRoot('oliphaunt-kotlin');
-  const gradle = path.join(packageDir, 'gradlew');
-  const buildRoot = path.join(ROOT, 'target/coverage-build/oliphaunt-kotlin/gradle');
-  const cxxBuildRoot = path.join(ROOT, 'target/coverage-build/oliphaunt-kotlin/cxx');
-  const projectCache = path.join(ROOT, 'target/coverage-build/oliphaunt-kotlin/gradle-cache');
-  rmSync(buildRoot, { recursive: true, force: true });
-  rmSync(cxxBuildRoot, { recursive: true, force: true });
-  run([
-    gradle,
-    '-p',
-    relPath(packageDir),
-    ':oliphaunt:koverXmlReport',
-    '--no-daemon',
-    `-PoliphauntBuildRoot=${buildRoot}`,
-    `-PoliphauntCxxBuildRoot=${cxxBuildRoot}`,
-    '--project-cache-dir',
-    projectCache,
-  ]);
-  let reports = walkFiles(buildRoot)
-    .filter((candidate) => posixPath(candidate).includes('/reports/kover/') && candidate.endsWith('.xml'))
-    .sort();
-  if (reports.length === 0) {
-    reports = walkFiles(packageDir)
-      .filter((candidate) => posixPath(candidate).includes('/build/reports/kover/') && candidate.endsWith('.xml'))
-      .sort();
-  }
-  if (reports.length === 0) {
-    fail('oliphaunt-kotlin: Kover did not emit an XML report');
-  }
-  const report = path.join(out, 'kover.xml');
-  copyFileSync(reports.at(-1), report);
-  const parsed = parseKoverXml(report, productConfig('oliphaunt-kotlin'));
-  writeSummary('oliphaunt-kotlin', 'kover', parsed.covered, parsed.total, parsed.files, [report]);
-  checkSummary('oliphaunt-kotlin');
-}
-
-function runJavascript(product) {
-  const out = resetOutput(product);
-  const packageDir = productSourceRoot(product);
-  requireTool(
-    'pnpm',
-    'export PATH="$(bash .github/actions/setup-node-pnpm/install-pinned-pnpm.sh)/bin:$PATH"',
-  );
-  const config = productConfig(product);
-  const threshold = String(Math.trunc(Number.parseFloat(config.line_threshold)));
-  const sourcePrefix = `${productSourcePrefix(product)}/`;
-  const includePatterns = sourceGlobs(config).map((pattern) =>
-    pattern.startsWith(sourcePrefix) ? pattern.slice(sourcePrefix.length) : pattern
-  );
-  const excludePatterns = [...excludeGlobs(config), ...waiverPatterns(config)].map((pattern) =>
-    pattern.startsWith(sourcePrefix) ? pattern.slice(sourcePrefix.length) : pattern
-  );
-  run([
-    'pnpm',
-    '--dir',
-    packageDir,
-    'exec',
-    'vitest',
-    'run',
-    '--pool=forks',
-    '--fileParallelism=false',
-    '--coverage.enabled=true',
-    '--coverage.provider=v8',
-    `--coverage.reportsDirectory=${out}`,
-    '--coverage.reporter=text',
-    '--coverage.reporter=lcov',
-    '--coverage.reporter=json-summary',
-    '--coverage.thresholds.branches=0',
-    '--coverage.thresholds.functions=0',
-    '--coverage.thresholds.statements=0',
-    `--coverage.thresholds.lines=${threshold}`,
-    ...includePatterns.map((pattern) => `--coverage.include=${pattern}`),
-    ...excludePatterns.map((pattern) => `--coverage.exclude=${pattern}`),
-    '--dir=src/__tests__',
-  ]);
-  const summaryReport = path.join(out, 'coverage-summary.json');
-  if (!existsSync(summaryReport) || !statSync(summaryReport).isFile()) {
-    fail(`${product}: Vitest did not emit ${relPath(summaryReport)}`);
-  }
-  const parsed = parseJavascriptSummary(summaryReport, product, config);
-  const reports = [summaryReport];
-  const lcov = path.join(out, 'lcov.info');
-  if (existsSync(lcov) && statSync(lcov).isFile()) {
-    reports.push(lcov);
-  }
-  writeSummary(product, 'vitest-v8', parsed.covered, parsed.total, parsed.files, reports);
-  checkSummary(product);
-}
-
-function runProduct(product) {
-  if (!PRODUCTS.includes(product)) {
-    fail(`unknown product ${JSON.stringify(product)}; expected one of ${PRODUCTS.join(', ')}`);
-  }
-  if (product === 'oliphaunt-rust' || product === 'oliphaunt-wasix-rust') {
-    runRust(product);
-  } else if (product === 'oliphaunt-swift') {
-    runSwift();
-  } else if (product === 'oliphaunt-kotlin') {
-    runKotlin();
-  } else if (
-    product === 'oliphaunt-js' ||
-    product === 'oliphaunt-react-native' ||
-    product === 'oliphaunt-wasix-ts'
-  ) {
-    runJavascript(product);
-  } else {
-    fail(`unhandled coverage product ${product}`);
-  }
-}
-
-function parseProductsJson(value) {
-  if (value === undefined || value.trim() === '') {
-    return [...PRODUCTS];
-  }
-  let parsed;
-  try {
-    parsed = JSON.parse(value);
-  } catch (error) {
-    fail(`coverage products JSON is invalid: ${error.message}`);
-  }
-  if (!Array.isArray(parsed) || !parsed.every((item) => typeof item === 'string')) {
-    fail('coverage products JSON must be a string array');
-  }
-  const unknown = [...new Set(parsed.filter((item) => !PRODUCTS.includes(item)))].sort();
-  if (unknown.length > 0) {
-    fail(`unknown coverage product(s): ${unknown.join(', ')}`);
-  }
-  return [...new Set(parsed)].sort((left, right) => PRODUCTS.indexOf(left) - PRODUCTS.indexOf(right));
-}
-
-function summarize({ allowMissing = false, productsJson } = {}) {
-  const data = loadBaseline();
-  const products = data.products;
-  const selectedProducts = parseProductsJson(productsJson);
-  const rows = [];
-  const allSummaries = [];
-  for (const product of selectedProducts) {
-    if (!Object.hasOwn(products, product)) {
-      if (data.policy?.fail_on_unmeasured_product ?? true) {
-        fail(`missing coverage baseline for ${product}`);
-      }
-      continue;
-    }
-    const summaryPath = path.join(ROOT, products[product].summary);
-    if (allowMissing && (!existsSync(summaryPath) || !statSync(summaryPath).isFile())) {
-      continue;
-    }
-    if (!existsSync(summaryPath) || !statSync(summaryPath).isFile()) {
-      fail(`missing required coverage summary: ${relPath(summaryPath)}`);
-    }
-    const summary = checkSummary(product);
-    allSummaries.push(summary);
-    rows.push(
-      `| ${summary.product} | ${summary.tool} | ${summary.line_coverage.toFixed(2)}% | ` +
-      `${summary.line_threshold.toFixed(2)}% | ${summary.covered_lines}/${summary.total_lines} |`,
-    );
-  }
-  mkdirSync(COVERAGE_ROOT, { recursive: true });
-  writeJson(path.join(COVERAGE_ROOT, 'summary.json'), {
-    schema: 'oliphaunt-coverage-aggregate-v1',
-    products: allSummaries,
-  });
-  const markdown = [
-    '| Product | Tool | Lines | Threshold | Covered |',
-    '| --- | --- | ---: | ---: | ---: |',
-    ...rows,
-    '',
-  ].join('\n');
-  writeFileSync(path.join(COVERAGE_ROOT, 'summary.md'), markdown);
-  console.log(markdown);
-}
-
-function checkTools() {
-  const data = loadBaseline();
-  for (const product of PRODUCTS) {
-    if (!data.products[product]) {
-      fail(`missing coverage baseline for ${product}`);
-    }
-    validateWaivers(data.products[product]);
-    sourceGlobs(data.products[product]);
-    excludeGlobs(data.products[product]);
-  }
-  console.log('coverage tooling checks passed');
-}
-
-function usage() {
-  return `usage:
-  tools/coverage/coverage.mjs run-product 
-  tools/coverage/coverage.mjs check-product 
-  tools/coverage/coverage.mjs summarize [--allow-missing] [--products-json JSON]
-  tools/coverage/coverage.mjs check-tools`;
-}
-
-function parseArgs(argv) {
-  const [command, ...rest] = argv;
-  if (command === undefined || command === '-h' || command === '--help') {
-    console.log(usage());
-    process.exit(0);
-  }
-  if (command === 'run-product' || command === 'check-product') {
-    if (rest.length !== 1 || !PRODUCTS.includes(rest[0])) {
-      fail(`${command} requires one product: ${PRODUCTS.join(', ')}`);
-    }
-    return { command, product: rest[0] };
-  }
-  if (command === 'summarize') {
-    const options = { command, allowMissing: false, productsJson: undefined };
-    for (let index = 0; index < rest.length; index += 1) {
-      const arg = rest[index];
-      if (arg === '--allow-missing') {
-        options.allowMissing = true;
-      } else if (arg === '--products-json') {
-        index += 1;
-        if (index >= rest.length) {
-          fail('--products-json requires a value');
-        }
-        options.productsJson = rest[index];
-      } else {
-        fail(`unknown summarize argument: ${arg}`);
-      }
-    }
-    return options;
-  }
-  if (command === 'check-tools') {
-    if (rest.length !== 0) {
-      fail('check-tools does not take arguments');
-    }
-    return { command };
-  }
-  fail(`unknown command: ${command}\n${usage()}`);
-}
-
-if (import.meta.main) {
-  const args = parseArgs(Bun.argv.slice(2));
-  if (args.command === 'run-product') {
-    runProduct(args.product);
-  } else if (args.command === 'check-product') {
-    const summary = checkSummary(args.product);
-    console.log(`${args.product}: ${summary.line_coverage.toFixed(2)}% line coverage`);
-  } else if (args.command === 'summarize') {
-    summarize({ allowMissing: args.allowMissing, productsJson: args.productsJson });
-  } else if (args.command === 'check-tools') {
-    checkTools();
-  }
-}
diff --git a/tools/coverage/moon.yml b/tools/coverage/moon.yml
deleted file mode 100644
index 9dab524d7..000000000
--- a/tools/coverage/moon.yml
+++ /dev/null
@@ -1,180 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "coverage-tools"
-language: "javascript"
-layer: "tool"
-stack: "infrastructure"
-tags: ["tools", "coverage", "repo-hygiene"]
-
-dependsOn:
-  - id: "shared-test-fixtures"
-    scope: "development"
-  - id: "extension-runtime-contract"
-    scope: "build"
-  - id: "liboliphaunt-wasix"
-    scope: "build"
-  - id: "oliphaunt-js"
-    scope: "build"
-  - id: "oliphaunt-kotlin"
-    scope: "build"
-  - id: "oliphaunt-react-native"
-    scope: "build"
-  - id: "oliphaunt-rust"
-    scope: "build"
-  - id: "oliphaunt-swift"
-    scope: "build"
-  - id: "oliphaunt-wasix-rust"
-    scope: "build"
-  - id: "oliphaunt-wasix-ts"
-    scope: "build"
-  - id: "shared-rust-query-core"
-    scope: "build"
-
-project:
-  title: "Coverage Tools"
-  description: "Measured polyglot coverage runners, parsers, thresholds, and aggregate summaries."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-  paths:
-    "**/*": ["@oliphaunt/core"]
-
-tasks:
-  check:
-    tags: ["quality", "static"]
-    command: "bash tools/dev/bun.sh tools/coverage/coverage.mjs check-tools"
-    inputs:
-      - "**/*"
-      - "/coverage/baseline.toml"
-      - "/tools/dev/capture-command-output.mjs"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  rust:
-    tags: ["coverage", "quality", "requires-rust"]
-    command: "tools/coverage/run-product oliphaunt-rust"
-    inputs:
-      - "/.config/nextest.toml"
-      - "@group(cargo-workspace)"
-      - "/coverage/baseline.toml"
-      - project: "oliphaunt-rust"
-        group: "code"
-      - project: "shared-rust-query-core"
-        group: "sources"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - "**/*"
-    outputs:
-      - "/target/coverage/oliphaunt-rust/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  swift:
-    tags: ["coverage", "quality", "requires-apple"]
-    command: "tools/coverage/run-product oliphaunt-swift"
-    inputs:
-      - "/Package.swift"
-      - "/coverage/baseline.toml"
-      - project: "oliphaunt-swift"
-        group: "code"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - "**/*"
-    outputs:
-      - "/target/coverage/oliphaunt-swift/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  kotlin:
-    tags: ["coverage", "quality", "requires-android-sdk"]
-    command: "tools/coverage/run-product oliphaunt-kotlin"
-    inputs:
-      - "/coverage/baseline.toml"
-      - project: "oliphaunt-kotlin"
-        group: "code"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - "**/*"
-    outputs:
-      - "/target/coverage/oliphaunt-kotlin/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  js:
-    tags: ["coverage", "quality"]
-    command: "tools/coverage/run-product oliphaunt-js"
-    deps:
-      - "shared-js-core:build"
-    inputs:
-      - "@group(pnpm-workspace)"
-      - "/coverage/baseline.toml"
-      - project: "oliphaunt-js"
-        group: "code"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - "**/*"
-    outputs:
-      - "/target/coverage/oliphaunt-js/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  react-native:
-    tags: ["coverage", "quality"]
-    command: "tools/coverage/run-product oliphaunt-react-native"
-    deps:
-      - "shared-js-core:build"
-    inputs:
-      - "@group(pnpm-workspace)"
-      - "/coverage/baseline.toml"
-      - project: "oliphaunt-react-native"
-        group: "code"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - "**/*"
-    outputs:
-      - "/target/coverage/oliphaunt-react-native/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  wasix-rust:
-    tags: ["coverage", "quality", "requires-rust"]
-    command: "tools/coverage/run-product oliphaunt-wasix-rust"
-    inputs:
-      - "/.config/nextest.toml"
-      - "@group(cargo-workspace)"
-      - "/coverage/baseline.toml"
-      - project: "oliphaunt-wasix-rust"
-        group: "code"
-      - project: "liboliphaunt-wasix"
-        group: "crates"
-      - project: "shared-rust-query-core"
-        group: "sources"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - "**/*"
-    outputs:
-      - "/target/coverage/oliphaunt-wasix-rust/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  wasix-ts:
-    tags: ["coverage", "quality"]
-    command: "tools/coverage/run-product oliphaunt-wasix-ts"
-    deps:
-      - "shared-js-core:build"
-    inputs:
-      - "@group(pnpm-workspace)"
-      - "/coverage/baseline.toml"
-      - project: "oliphaunt-wasix-ts"
-        group: "code"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - "**/*"
-    outputs:
-      - "/target/coverage/oliphaunt-wasix-ts/**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
diff --git a/tools/coverage/run-product b/tools/coverage/run-product
deleted file mode 100755
index 008a0cfd0..000000000
--- a/tools/coverage/run-product
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env sh
-set -eu
-root="$(git rev-parse --show-toplevel 2>/dev/null)"
-exec "$root/tools/dev/bun.sh" "$root/tools/coverage/coverage.mjs" run-product "$@"
diff --git a/tools/coverage/summarize b/tools/coverage/summarize
deleted file mode 100755
index c2c2f05f5..000000000
--- a/tools/coverage/summarize
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env sh
-set -eu
-root="$(git rev-parse --show-toplevel 2>/dev/null)"
-exec "$root/tools/dev/bun.sh" "$root/tools/coverage/coverage.mjs" summarize "$@"
diff --git a/src/sources/toolchains/android-sdk.toml b/tools/dev/android-sdk.toml
similarity index 100%
rename from src/sources/toolchains/android-sdk.toml
rename to tools/dev/android-sdk.toml
diff --git a/tools/dev/bootstrap-tools.sh b/tools/dev/bootstrap-tools.sh
index d1abd372d..06c1d1419 100755
--- a/tools/dev/bootstrap-tools.sh
+++ b/tools/dev/bootstrap-tools.sh
@@ -2,16 +2,14 @@
 set -euo pipefail
 
 PREK_VERSION="${PREK_VERSION:-0.4.3}"
-CARGO_DENY_VERSION="${CARGO_DENY_VERSION:-0.19.8}"
-CARGO_HACK_VERSION="${CARGO_HACK_VERSION:-0.6.44}"
 CARGO_NEXTEST_VERSION="${CARGO_NEXTEST_VERSION:-0.9.137}"
-CARGO_SEMVER_CHECKS_VERSION="${CARGO_SEMVER_CHECKS_VERSION:-0.47.0}"
-DPRINT_VERSION="${DPRINT_VERSION:-0.54.0}"
-LYCHEE_VERSION="${LYCHEE_VERSION:-0.24.2}"
-TAPLO_VERSION="${TAPLO_VERSION:-0.10.0}"
-TYPOS_VERSION="${TYPOS_VERSION:-1.47.0}"
 ZIZMOR_VERSION="${ZIZMOR_VERSION:-1.25.2}"
-RIPGREP_VERSION="${RIPGREP_VERSION:-15.1.0}"
+
+case "${1:-}" in
+  ""|--workflows) ;;
+  *) echo "usage: bootstrap-tools.sh [--workflows]" >&2; exit 2 ;;
+esac
+[ "$#" -le 1 ] || { echo "usage: bootstrap-tools.sh [--workflows]" >&2; exit 2; }
 
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 cargo_bin_dir="${CARGO_HOME:-$HOME/.cargo}/bin"
@@ -19,16 +17,10 @@ mkdir -p "$cargo_bin_dir"
 PATH="$cargo_bin_dir:$PATH"
 export PATH
 
-has_command() {
-  command -v "$1" >/dev/null 2>&1
-}
-
 installed_tool_version() {
   binary="$1"
   case "$(basename "$binary")" in
     cargo-binstall) "$binary" -V 2>/dev/null || true ;;
-    cargo-hack) PATH="$(dirname "$binary"):$PATH" cargo hack --version 2>/dev/null || true ;;
-    cargo-semver-checks) PATH="$(dirname "$binary"):$PATH" cargo semver-checks --version 2>/dev/null || true ;;
     *) "$binary" --version 2>/dev/null || true ;;
   esac
 }
@@ -71,11 +63,6 @@ install_cargo_tool() {
   package="$1"
   binary="$2"
   version="$3"
-  install_mode="${4:-binary-first}"
-  case "$install_mode" in
-    binary-first | source-only) ;;
-    *) echo "unsupported Cargo tool install mode: $install_mode" >&2; return 2 ;;
-  esac
   local_binary="$cargo_bin_dir/$binary"
   if [ -x "$local_binary" ]; then
     output="$(installed_tool_version "$local_binary")"
@@ -84,24 +71,15 @@ install_cargo_tool() {
       return
     fi
     printf '%s\n' "replacing $local_binary with pinned $package@$version (found: $output)"
-  elif has_command "$binary"; then
+  elif command -v "$binary" >/dev/null 2>&1; then
     printf '%s\n' "installing pinned $package@$version; ignoring non-local $binary at $(command -v "$binary")"
   fi
 
-  if [ "$install_mode" = binary-first ] && has_command cargo-binstall; then
-    binstall_args="--no-confirm --disable-telemetry --force --strategies crate-meta-data,quick-install"
-    if ! cargo binstall --help 2>/dev/null | grep -q -- '--force'; then
-      binstall_args="--no-confirm --disable-telemetry --strategies crate-meta-data,quick-install"
-    fi
-    # shellcheck disable=SC2086
-    if cargo binstall $binstall_args "$package@$version"; then
-      installed_pinned_tool_version "$local_binary" "$version" >/dev/null
-      return
-    fi
-    echo "cargo-binstall could not install $package@$version from a binary; falling back to cargo install" >&2
-  elif [ "$install_mode" = source-only ]; then
-    echo "installing pinned $package@$version from its locked crate source (no declared binary asset)"
+  if cargo binstall --no-confirm --disable-telemetry --force --strategies crate-meta-data,quick-install "$package@$version"; then
+    installed_pinned_tool_version "$local_binary" "$version" >/dev/null
+    return
   fi
+  echo "cargo-binstall could not install $package@$version from a binary; falling back to cargo install" >&2
   cargo install "$package" --version "$version" --locked --force
   installed_pinned_tool_version "$local_binary" "$version" >/dev/null
 }
@@ -136,20 +114,11 @@ install_cargo_binstall
 if [ "${OLIPHAUNT_BOOTSTRAP_CARGO_BINSTALL_ONLY:-0}" = 1 ]; then
   exit 0
 fi
-install_cargo_tool prek prek "$PREK_VERSION"
-install_cargo_tool cargo-deny cargo-deny "$CARGO_DENY_VERSION"
-install_cargo_tool cargo-hack cargo-hack "$CARGO_HACK_VERSION"
-install_cargo_tool cargo-nextest cargo-nextest "$CARGO_NEXTEST_VERSION"
-install_cargo_tool cargo-semver-checks cargo-semver-checks "$CARGO_SEMVER_CHECKS_VERSION"
-install_cargo_tool dprint dprint "$DPRINT_VERSION"
-install_cargo_tool lychee lychee "$LYCHEE_VERSION"
-# taplo-cli 0.10.0 has no cargo-quickinstall asset. Its binary-first path is a
-# guaranteed 404 followed by this same locked source build, so skip the probe.
-install_cargo_tool taplo-cli taplo "$TAPLO_VERSION" source-only
-install_cargo_tool typos-cli typos "$TYPOS_VERSION"
+if [ "${1:-}" != --workflows ]; then
+  install_cargo_tool prek prek "$PREK_VERSION"
+  install_cargo_tool cargo-nextest cargo-nextest "$CARGO_NEXTEST_VERSION"
+fi
 install_cargo_tool zizmor zizmor "$ZIZMOR_VERSION"
-install_cargo_tool ripgrep rg "$RIPGREP_VERSION"
 "$script_dir/install-actionlint.sh"
 
-echo
 echo "Tool bootstrap complete. Ensure $cargo_bin_dir is on PATH."
diff --git a/tools/dev/bun.toml b/tools/dev/bun.toml
new file mode 100644
index 000000000..42e62a9fd
--- /dev/null
+++ b/tools/dev/bun.toml
@@ -0,0 +1,34 @@
+[assets.darwin-aarch64]
+url = "https://github.com/oven-sh/bun/releases/download/bun-v1.4.2/bun-darwin-aarch64.zip"
+sha256 = "90987a3a16d7db556d886ac3d551e7b6d3edf0a1cf43acaed622e8676be1d12f"
+binary_path = "bun-darwin-aarch64/bun"
+binary_sha256 = "35d20dd0263e5c950194434b925454fdfa9ba6e4467da960410fa05b08a7a5b5"
+entry_count = "2"
+
+[assets.darwin-x64]
+url = "https://github.com/oven-sh/bun/releases/download/bun-v1.4.2/bun-darwin-x64.zip"
+sha256 = "80520d7e17526308c9185d261679ac6d27798d3803a0e9f7ff9121ab8affb012"
+binary_path = "bun-darwin-x64/bun"
+binary_sha256 = "2fa513af22ac59e03aae640cad302e73cb1ddb0f6398501e2ddccf7dcd613596"
+entry_count = "2"
+
+[assets.linux-aarch64]
+url = "https://github.com/oven-sh/bun/releases/download/bun-v1.4.2/bun-linux-aarch64.zip"
+sha256 = "54328bbc2d9c8e0c9f892c544d66c57a83b84139e34909e5ee81758f1ac8fda7"
+binary_path = "bun-linux-aarch64/bun"
+binary_sha256 = "616f267a34278ff5ac282df37ffdfba1d7141f4f6926bca99af2cd6ef3ad32b1"
+entry_count = "2"
+
+[assets.linux-x64]
+url = "https://github.com/oven-sh/bun/releases/download/bun-v1.4.2/bun-linux-x64.zip"
+sha256 = "36368faef7527875d5ffa52e53cd48021741f2a83eb6208a8dd64068d422a913"
+binary_path = "bun-linux-x64/bun"
+binary_sha256 = "a83d263767d839e4d2649ca8e35d07159c7afc99afdc96d731ced29e056dda0c"
+entry_count = "2"
+
+[assets.windows-x64]
+url = "https://github.com/oven-sh/bun/releases/download/bun-v1.4.2/bun-windows-x64.zip"
+sha256 = "ce4c17497b2f29712a99d3d53f028de28cd42e3bacb8589599e7f000e49b6405"
+binary_path = "bun-windows-x64/bun.exe"
+binary_sha256 = "15277c59ccd6c6c20f8dc9716c2b59c1776320d606b6a8658f70be8799519ca4"
+entry_count = "2"
diff --git a/tools/dev/capture-command-output.mjs b/tools/dev/capture-command-output.mjs
deleted file mode 100644
index 54584f762..000000000
--- a/tools/dev/capture-command-output.mjs
+++ /dev/null
@@ -1,177 +0,0 @@
-import { spawnSync } from "node:child_process";
-import {
-  closeSync,
-  fstatSync,
-  mkdtempSync,
-  openSync,
-  readFileSync,
-  rmSync,
-  statSync,
-  writeFileSync,
-} from "node:fs";
-import os from "node:os";
-import path from "node:path";
-
-const DEFAULT_MAX_OUTPUT_BYTES = 64 * 1024 * 1024;
-const UTF8 = new TextDecoder("utf-8", { fatal: true });
-
-function decode(bytes, label) {
-  try {
-    return UTF8.decode(bytes);
-  } catch {
-    throw new Error(`${label} is not valid UTF-8`);
-  }
-}
-
-function readBounded(file, maximum, label) {
-  const size = statSync(file).size;
-  if (size > maximum) {
-    throw new Error(`${label} exceeded the ${maximum}-byte capture limit`);
-  }
-  return readFileSync(file);
-}
-
-/**
- * Capture a synchronous child's streams through regular files, never pipes.
- *
- * Bun 1.3.14 may report a successful spawnSync child before its piped stdout
- * has been completely drained. A child-owned regular file is complete when
- * waitpid returns, so inventory callers can safely inspect every emitted byte.
- * `stdoutDescriptor` is a redirection-only escape hatch for large binary
- * output: it must identify a caller-owned regular file, is never read or
- * closed here, and is intentionally outside `maxOutputBytes`.
- */
-export function captureCommandBytes(
-  command,
-  args,
-  {
-    allowEmptyOutput = false,
-    argv0 = undefined,
-    cwd = undefined,
-    env = undefined,
-    gid = undefined,
-    input = undefined,
-    killSignal = undefined,
-    label = command,
-    maxOutputBytes = DEFAULT_MAX_OUTPUT_BYTES,
-    shell = undefined,
-    stdoutDescriptor = undefined,
-    stdoutTerminator = undefined,
-    timeout = undefined,
-    uid = undefined,
-    windowsHide = undefined,
-    windowsVerbatimArguments = undefined,
-  } = {},
-) {
-  if (typeof command !== "string" || command.length === 0 || !Array.isArray(args)) {
-    throw new Error("command capture requires a command and argument list");
-  }
-  if (!Number.isSafeInteger(maxOutputBytes) || maxOutputBytes < 1) {
-    throw new Error("command capture requires a positive output limit");
-  }
-  if (typeof allowEmptyOutput !== "boolean") {
-    throw new Error("command capture allowEmptyOutput must be a Boolean");
-  }
-  const terminator = stdoutTerminator === undefined ? undefined : Buffer.from(stdoutTerminator);
-  if (terminator !== undefined && terminator.length === 0) {
-    throw new Error("command capture requires a non-empty stdout terminator");
-  }
-  if (allowEmptyOutput && terminator === undefined) {
-    throw new Error("command capture allowEmptyOutput requires a stdout terminator");
-  }
-  if (
-    stdoutDescriptor !== undefined
-    && (!Number.isSafeInteger(stdoutDescriptor) || stdoutDescriptor < 0)
-  ) {
-    throw new Error("command capture stdoutDescriptor must be a non-negative file descriptor");
-  }
-  if (stdoutDescriptor !== undefined && terminator !== undefined) {
-    throw new Error("command capture cannot frame externally redirected stdout");
-  }
-  if (stdoutDescriptor !== undefined && !fstatSync(stdoutDescriptor).isFile()) {
-    throw new Error("command capture stdoutDescriptor must identify a regular file");
-  }
-  const directory = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-command-output-"));
-  const stdoutFile = path.join(directory, "stdout");
-  const stderrFile = path.join(directory, "stderr");
-  const stdinFile = path.join(directory, "stdin");
-  let stdinDescriptor;
-  let capturedStdoutDescriptor;
-  let stderrDescriptor;
-  try {
-    if (input !== undefined) {
-      writeFileSync(stdinFile, input, { flag: "wx", mode: 0o600 });
-      stdinDescriptor = openSync(stdinFile, "r");
-    }
-    if (stdoutDescriptor === undefined) {
-      capturedStdoutDescriptor = openSync(stdoutFile, "wx", 0o600);
-    }
-    stderrDescriptor = openSync(stderrFile, "wx", 0o600);
-    const result = spawnSync(command, args, {
-      argv0,
-      cwd,
-      env,
-      gid,
-      killSignal,
-      shell,
-      stdio: [
-        stdinDescriptor ?? "ignore",
-        stdoutDescriptor ?? capturedStdoutDescriptor,
-        stderrDescriptor,
-      ],
-      timeout,
-      uid,
-      windowsHide,
-      windowsVerbatimArguments,
-    });
-    if (stdinDescriptor !== undefined) {
-      closeSync(stdinDescriptor);
-      stdinDescriptor = undefined;
-    }
-    if (capturedStdoutDescriptor !== undefined) {
-      closeSync(capturedStdoutDescriptor);
-      capturedStdoutDescriptor = undefined;
-    }
-    closeSync(stderrDescriptor);
-    stderrDescriptor = undefined;
-    // A caller-owned redirection is intentionally not captured, read, closed,
-    // or bounded by maxOutputBytes. Its caller owns the regular file envelope.
-    const stdoutBytes = stdoutDescriptor === undefined
-      ? readBounded(stdoutFile, maxOutputBytes, `${label} stdout`)
-      : Buffer.alloc(0);
-    const stderrBytes = readBounded(stderrFile, maxOutputBytes, `${label} stderr`);
-    if (
-      terminator !== undefined
-      && result.error === undefined
-      && result.status === 0
-      && (stdoutBytes.length === 0
-        ? !allowEmptyOutput
-        : !stdoutBytes.subarray(-terminator.length).equals(terminator))
-    ) {
-      throw new Error(`${label} stdout is missing its required terminal ${JSON.stringify(stdoutTerminator)}`);
-    }
-    return {
-      error: result.error,
-      pid: result.pid,
-      signal: result.signal,
-      status: result.status,
-      stderr: stderrBytes,
-      stdout: stdoutBytes,
-    };
-  } finally {
-    if (stdinDescriptor !== undefined) closeSync(stdinDescriptor);
-    if (capturedStdoutDescriptor !== undefined) closeSync(capturedStdoutDescriptor);
-    if (stderrDescriptor !== undefined) closeSync(stderrDescriptor);
-    rmSync(directory, { force: true, recursive: true });
-  }
-}
-
-export function captureCommandOutput(command, args, options = {}) {
-  const label = options.label ?? command;
-  const result = captureCommandBytes(command, args, options);
-  return {
-    ...result,
-    stderr: decode(result.stderr, `${label} stderr`),
-    stdout: decode(result.stdout, `${label} stdout`),
-  };
-}
diff --git a/tools/policy/check-prek.sh b/tools/dev/check-prek.sh
similarity index 100%
rename from tools/policy/check-prek.sh
rename to tools/dev/check-prek.sh
diff --git a/src/sources/toolchains/deno.toml b/tools/dev/deno.toml
similarity index 98%
rename from src/sources/toolchains/deno.toml
rename to tools/dev/deno.toml
index f1d0f16b8..516171df1 100644
--- a/src/sources/toolchains/deno.toml
+++ b/tools/dev/deno.toml
@@ -1,6 +1,3 @@
-[toolchain]
-version = "2.8.1"
-
 [assets.aarch64-apple-darwin]
 url = "https://github.com/denoland/deno/releases/download/v2.8.1/deno-aarch64-apple-darwin.zip"
 mirror_url = "https://dl.deno.land/release/v2.8.1/deno-aarch64-apple-darwin.zip"
diff --git a/tools/dev/doctor.sh b/tools/dev/doctor.sh
deleted file mode 100755
index 119585481..000000000
--- a/tools/dev/doctor.sh
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "must run inside the Oliphaunt git checkout" >&2
-  exit 1
-}
-cd "$root"
-
-strict=0
-if [[ "${1:-}" == "--strict" ]]; then
-  strict=1
-fi
-
-failures=0
-warnings=0
-
-expected() {
-  local tool="$1"
-  awk -F '"' -v tool="$tool" '$1 ~ "^" tool " = " { print $2 }' .prototools
-}
-
-check_command() {
-  local command="$1"
-  local message="$2"
-  if ! command -v "$command" >/dev/null 2>&1; then
-    echo "missing $command: $message" >&2
-    failures=$((failures + 1))
-    return 1
-  fi
-}
-
-check_version() {
-  local command="$1"
-  local expected_version="$2"
-  local actual="$3"
-  local severity="${4:-error}"
-  if [[ "$actual" != *"$expected_version"* ]]; then
-    echo "$command version mismatch: expected $expected_version, got $actual" >&2
-    if [[ "$severity" == "warning" ]]; then
-      warnings=$((warnings + 1))
-    else
-      failures=$((failures + 1))
-    fi
-  else
-    echo "$command ok: $actual"
-  fi
-}
-
-proto_version="$(awk -F '"' '/^[[:space:]]+version: / { print $2; exit }' .moon/toolchains.yml)"
-moon_version="$(expected moon)"
-node_version="$(expected node)"
-pnpm_version="$(expected pnpm)"
-bun_version="$(expected bun)"
-deno_version="$(expected deno)"
-proto_bin="$(command -v proto 2>/dev/null || true)"
-if [[ -z "$proto_bin" && -x "$HOME/.proto/bin/proto" ]]; then
-  proto_bin="$HOME/.proto/bin/proto"
-fi
-
-check_command git "required for workspace root and affected checks" || true
-check_command cargo "install Rust from rustup; CI uses Rust 1.93.1" || true
-check_command node "run 'export PATH=\"\$(dirname \"\$(bash .github/actions/setup-moon/install-pinned-node.sh)\"):\$PATH\"'" || true
-check_command pnpm "after installing pinned Node, run 'export PATH=\"\$(bash .github/actions/setup-node-pnpm/install-pinned-pnpm.sh)/bin:\$PATH\"'" || true
-if [[ ! -x tools/dev/bun.sh ]]; then
-  echo "missing tools/dev/bun.sh: TypeScript SDK checks need the pinned Bun launcher" >&2
-  failures=$((failures + 1))
-fi
-
-if command -v pnpm >/dev/null 2>&1; then
-  check_version pnpm "$pnpm_version" "$(pnpm --version 2>/dev/null || true)"
-fi
-if command -v bun >/dev/null 2>&1; then
-  check_version bun "$bun_version" "$(bun --version 2>/dev/null || true)" warning
-else
-  echo "missing optional bun: TypeScript package checks will use tools/dev/bun.sh to download pinned Bun $bun_version on demand" >&2
-fi
-if command -v node >/dev/null 2>&1; then
-  proto_node="$HOME/.proto/tools/node/$node_version/bin/node"
-  if [[ -x "$proto_node" ]]; then
-    echo "node ok: $node_version via proto toolchain"
-    shell_node="$(node --version 2>/dev/null | sed 's/^v//')"
-    if [[ "$shell_node" != "$node_version" ]]; then
-      echo "node shell version differs from pinned toolchain: shell $shell_node, proto $node_version"
-    fi
-  else
-    check_version node "$node_version" "$(node --version 2>/dev/null | sed 's/^v//')" warning
-  fi
-fi
-
-if [[ -n "$proto_bin" ]]; then
-  check_version proto "$proto_version" "$("$proto_bin" --version 2>/dev/null || true)"
-else
-  echo "proto is not on PATH; moon will manage proto $proto_version through its pinned setup"
-fi
-
-if command -v moon >/dev/null 2>&1; then
-  check_version moon "$moon_version" "$(moon --version 2>/dev/null || true)"
-else
-  echo "missing moon: run 'export PATH=\"\$(bash .github/actions/setup-moon/install-pinned-toolchain.sh)/bin:\$PATH\"'" >&2
-  failures=$((failures + 1))
-fi
-
-if command -v deno >/dev/null 2>&1; then
-  check_version deno "$deno_version" "$(deno --version 2>/dev/null | head -n 1)" warning
-else
-  echo "missing optional deno: TypeScript package checks will use tools/dev/deno.sh to download pinned Deno $deno_version on demand" >&2
-  [[ "$strict" -eq 0 ]] || failures=$((failures + 1))
-fi
-
-for optional in \
-  actionlint \
-  autoconf \
-  aclocal \
-  cargo-deny \
-  cargo-hack \
-  cargo-nextest \
-  cargo-semver-checks \
-  ccache \
-  dprint \
-  glibtoolize \
-  lychee \
-  prek \
-  rg \
-  taplo \
-  typos \
-  zizmor
-do
-  if command -v "$optional" >/dev/null 2>&1; then
-    echo "$optional ok: $(command -v "$optional")"
-  else
-    echo "missing optional $optional: run tools/dev/bootstrap-tools.sh for maintainer gates" >&2
-    [[ "$strict" -eq 0 ]] || failures=$((failures + 1))
-  fi
-done
-
-if [[ "$failures" -ne 0 ]]; then
-  echo "doctor found $failures tooling issue(s)" >&2
-  exit 1
-fi
-
-if [[ "$warnings" -ne 0 ]]; then
-  echo "doctor completed with $warnings advisory warning(s)" >&2
-fi
-
-echo "doctor passed"
diff --git a/tools/dev/extract-maestro.mts b/tools/dev/extract-maestro.mts
new file mode 100644
index 000000000..50f6a4456
--- /dev/null
+++ b/tools/dev/extract-maestro.mts
@@ -0,0 +1,27 @@
+import { mkdirSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+import { readPortableArchiveEntries } from '../packaging/portable-archive.mts';
+const [archive, destination, version] = process.argv.slice(2);
+try {
+  const entries = readPortableArchiveEntries(archive, {
+    maxArchiveBytes: 400_000_000,
+    maxExpandedBytes: 800_000_000,
+    maxEntries: 4096,
+  });
+  for (const name of ['maestro/bin/maestro', 'maestro/lib/maestro-cli-' + version + '.jar']) {
+    if (!entries.get(name)?.isFile || !entries.get(name)?.size)
+      throw new Error('missing expected archive entry: ' + name);
+  }
+  for (const entry of entries.values()) {
+    if (entry.name !== 'maestro' && !entry.name.startsWith('maestro/'))
+      throw new Error('unsafe Maestro archive path: ' + entry.name);
+  }
+  for (const entry of entries.values()) {
+    const output = path.join(destination, entry.name);
+    mkdirSync(entry.isDirectory ? output : path.dirname(output), { recursive: true });
+    if (entry.isFile) writeFileSync(output, entry.data(), { flag: 'wx', mode: 0o644 });
+  }
+} catch (error) {
+  console.error(`invalid Maestro archive: ${error.message}`);
+  process.exitCode = 1;
+}
diff --git a/tools/dev/extract-pinned-binary.sh b/tools/dev/extract-pinned-binary.sh
new file mode 100644
index 000000000..5bdebbcad
--- /dev/null
+++ b/tools/dev/extract-pinned-binary.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+set -euo pipefail
+# The caller verifies the whole archive digest first and owns a private staging
+# directory. Archive paths never become filesystem destinations here.
+[ "$#" -ge 5 ] && [ "$#" -le 6 ] || { echo 'usage: extract-pinned-binary.sh FORMAT ARCHIVE MEMBER OUTPUT SHA256 [BYTES]' >&2; exit 2; }
+format="$1" archive="$2" member="$3" output="$4" digest="$5" expected_bytes="${6:-}"
+case "$member" in ''|/*|*'..'*|*'['*|*']'*|*'?'*|*'*'*|*'\'*) echo 'unsafe pinned member name' >&2; exit 2 ;; esac
+[[ "$digest" =~ ^[0-9a-f]{64}$ ]] || exit 2
+[[ "$expected_bytes" =~ ^[1-9][0-9]*$ || -z "$expected_bytes" ]] || exit 2
+[ -f "$archive" ] && [ ! -L "$archive" ] || exit 2
+[ ! -e "$output" ] && [ ! -L "$output" ] || exit 2
+[ -d "$(dirname "$output")" ] && [ ! -L "$(dirname "$output")" ] || exit 2
+limit="${expected_bytes:-150000000}"
+[ "$limit" -le 250000000 ] || exit 2
+success=0
+trap '[ "$success" = 1 ] || rm -f "$output"' EXIT
+set -C
+read_member() {
+  case "$format:$(uname -s)" in
+    zip:MINGW*|zip:MSYS*|zip:CYGWIN*)
+      env -u TAR_OPTIONS "$(cygpath -u "${SYSTEMROOT:-${SystemRoot:?Windows system directory is required}}")/System32/tar.exe" -xOf "$archive" -- "$member" ;;
+    zip:*) env -u UNZIP -u UNZIPOPT unzip -p "$archive" "$member" ;;
+    tar.xz:*|tar.gz:*) env -u TAR_OPTIONS tar -xOf "$archive" -- "$member" ;;
+    *) echo "unsupported pinned archive format: $format" >&2; return 2 ;;
+  esac
+}
+read_member | head -c "$((limit + 1))" > "$output"
+bytes="$(wc -c < "$output" | tr -d '[:space:]')"
+[ "$bytes" -gt 0 ] && [ "$bytes" -le "$limit" ] || exit 1
+[ -z "$expected_bytes" ] || [ "$bytes" = "$expected_bytes" ] || exit 1
+if command -v sha256sum >/dev/null 2>&1; then
+  actual="$(sha256sum "$output" | awk '{print $1}')"
+else
+  actual="$(shasum -a 256 "$output" | awk '{print $1}')"
+fi
+[ "$actual" = "$digest" ] || { echo 'pinned executable checksum mismatch' >&2; exit 1; }
+chmod 0555 "$output"
+success=1
diff --git a/tools/dev/extract-pinned-zip.mts b/tools/dev/extract-pinned-zip.mts
new file mode 100644
index 000000000..c82db8844
--- /dev/null
+++ b/tools/dev/extract-pinned-zip.mts
@@ -0,0 +1,86 @@
+import { mkdirSync, writeFileSync, chmodSync, rmSync } from 'node:fs';
+import path from 'node:path';
+import { parseArgs } from 'node:util';
+import { readPortableArchiveEntries } from '../packaging/portable-archive.mts';
+
+export function extractPinnedZip(argv: string[]) {
+  const { values } = parseArgs({
+    args: argv,
+    options: {
+      archive: { type: 'string' },
+      destination: { type: 'string' },
+      prefix: { type: 'string', default: '' },
+      'entry-count': { type: 'string' },
+      required: { type: 'string', multiple: true },
+      executable: { type: 'string', multiple: true },
+    },
+  });
+  const { archive, destination, prefix, required = [], executable = [] } = values;
+  const count = Number(values['entry-count']);
+  if (
+    !archive ||
+    !destination ||
+    !Number.isSafeInteger(count) ||
+    count < 1 ||
+    count > 4096 ||
+    !required.length ||
+    !executable.length
+  ) {
+    throw new Error(
+      'archive, destination, entry-count (1..4096), required and executable are required',
+    );
+  }
+  const entries = [
+    ...readPortableArchiveEntries(archive, {
+      format: 'zip',
+      maxArchiveBytes: 220_000_000,
+      maxExpandedBytes: 400_000_000,
+      maxEntryBytes: 150_000_000,
+      maxEntries: 4096,
+    }).values(),
+  ];
+  if (entries.length !== count)
+    throw new Error(`archive entry count mismatch: expected ${count}, got ${entries.length}`);
+  for (const entry of entries) {
+    if (
+      /[^\x20-\x7e]/u.test(entry.name) ||
+      (prefix && entry.name !== prefix && !entry.name.startsWith(`${prefix}/`))
+    ) {
+      throw new Error(`archive path is outside the pinned layout: ${entry.name}`);
+    }
+  }
+  for (const name of new Set([...required, ...executable])) {
+    const entry = entries.find((entry) => entry.name === name);
+    if (!entry?.isFile || !entry.size)
+      throw new Error(`required archive path is not a non-empty regular file: ${name}`);
+  }
+  // Create exclusively: a rejected existing destination must never be removed.
+  mkdirSync(path.dirname(path.resolve(destination)), { recursive: true });
+  mkdirSync(destination, { mode: 0o700 });
+  try {
+    for (const entry of entries) {
+      const target = path.join(destination, entry.name);
+      mkdirSync(entry.isDirectory ? target : path.dirname(target), {
+        recursive: true,
+        mode: 0o755,
+      });
+      if (entry.isFile) {
+        const mode = executable.includes(entry.name) ? 0o755 : 0o644;
+        writeFileSync(target, entry.data(), { flag: 'wx', mode });
+        chmodSync(target, mode);
+      }
+    }
+  } catch (error) {
+    rmSync(destination, { recursive: true, force: true });
+    throw error;
+  }
+}
+
+if (import.meta.main) {
+  try {
+    extractPinnedZip(process.argv.slice(2));
+  } catch (error) {
+    console.error(`pinned ZIP validation failed: ${error.message}`);
+    process.exitCode = 1;
+  }
+}
diff --git a/tools/dev/extract-pinned-zip.sh b/tools/dev/extract-pinned-zip.sh
index 2aff8141d..3b52de0cd 100755
--- a/tools/dev/extract-pinned-zip.sh
+++ b/tools/dev/extract-pinned-zip.sh
@@ -1,193 +1,4 @@
 #!/usr/bin/env bash
 set -euo pipefail
-
-fail() {
-  echo "extract-pinned-zip.sh: $*" >&2
-  exit 1
-}
-
-archive=""
-destination=""
-prefix=""
-entry_count=""
-required=()
-executables=()
-while [ "$#" -gt 0 ]; do
-  case "$1" in
-    --archive) archive="${2:-}"; shift 2 ;;
-    --destination) destination="${2:-}"; shift 2 ;;
-    --prefix) prefix="${2:-}"; shift 2 ;;
-    --entry-count) entry_count="${2:-}"; shift 2 ;;
-    --required) required+=("${2:-}"); shift 2 ;;
-    --executable) executables+=("${2:-}"); shift 2 ;;
-    *) fail "unknown or incomplete option: $1" ;;
-  esac
-done
-
-[ -f "$archive" ] || fail "archive is not a regular file: $archive"
-[ -n "$destination" ] || fail "--destination is required"
-case "$entry_count" in
-  ''|*[!0-9]*) fail "--entry-count must be a positive integer" ;;
-esac
-[ "$entry_count" -ge 1 ] && [ "$entry_count" -le 4096 ] ||
-  fail "--entry-count must be between 1 and 4096"
-[ "${#required[@]}" -ge 1 ] || fail "at least one --required file is required"
-[ "${#executables[@]}" -ge 1 ] || fail "at least one --executable file is required"
-python_bin="${OLIPHAUNT_PINNED_ZIP_PYTHON:-}"
-if [ -z "$python_bin" ]; then
-  for candidate in python3 python; do
-    if command -v "$candidate" >/dev/null 2>&1; then
-      python_bin="$candidate"
-      break
-    fi
-  done
-fi
-[ -n "$python_bin" ] && command -v "$python_bin" >/dev/null 2>&1 ||
-  fail "Python 3 is required for bounded ZIP validation"
-"$python_bin" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 8) else 1)' ||
-  fail "Python 3.8 or newer is required for bounded ZIP validation"
-
-required_file="$(mktemp "${TMPDIR:-/tmp}/oliphaunt-zip-required.XXXXXX")"
-executable_file="$(mktemp "${TMPDIR:-/tmp}/oliphaunt-zip-executables.XXXXXX")"
-cleanup() {
-  rm -f "$required_file" "$executable_file"
-}
-trap cleanup EXIT HUP INT TERM
-printf '%s\n' "${required[@]}" >"$required_file"
-printf '%s\n' "${executables[@]}" >"$executable_file"
-
-"$python_bin" - "$archive" "$destination" "$prefix" "$entry_count" "$required_file" "$executable_file" <<'PY'
-import os
-import shutil
-import stat
-import sys
-import zipfile
-from pathlib import Path, PurePosixPath
-
-archive_path = Path(sys.argv[1])
-destination = Path(sys.argv[2])
-prefix = sys.argv[3]
-expected_entries = int(sys.argv[4])
-required = set(Path(sys.argv[5]).read_text(encoding="utf-8").splitlines())
-executables = set(Path(sys.argv[6]).read_text(encoding="utf-8").splitlines())
-max_archive = 220_000_000
-max_expanded = 400_000_000
-max_file = 150_000_000
-
-def reject(message):
-    raise ValueError(message)
-
-def safe_name(info):
-    name = info.filename
-    try:
-        name.encode("ascii")
-    except UnicodeEncodeError:
-        reject(f"non-ASCII archive path: {name!r}")
-    if (
-        not name
-        or name.startswith("/")
-        or "\\" in name
-        or "\x00" in name
-        or any(ord(character) < 0x20 or ord(character) == 0x7F for character in name)
-    ):
-        reject(f"unsafe archive path: {name!r}")
-    directory_hint = name.endswith("/")
-    trimmed = name[:-1] if directory_hint else name
-    parts = trimmed.split("/")
-    if (
-        not trimmed
-        or any(part in {"", ".", ".."} for part in parts)
-        or any(len(part.encode("ascii")) > 255 for part in parts)
-        or (parts and len(parts[0]) >= 2 and parts[0][1] == ":")
-    ):
-        reject(f"unsafe archive path: {name!r}")
-    canonical = "/".join(parts)
-    if prefix and canonical != prefix and not canonical.startswith(prefix + "/"):
-        reject(f"archive path is outside required {prefix}/ root: {name!r}")
-
-    mode = (info.external_attr >> 16) & 0xFFFF
-    file_type = stat.S_IFMT(mode)
-    if file_type not in {0, stat.S_IFREG, stat.S_IFDIR}:
-        reject(f"unsupported archive entry type for {name!r}")
-    directory = directory_hint or file_type == stat.S_IFDIR or bool(info.external_attr & 0x10)
-    if directory != directory_hint:
-        reject(f"inconsistent directory metadata for {name!r}")
-    if directory and (info.file_size != 0 or info.compress_size != 0):
-        reject(f"directory archive entry is not empty: {name!r}")
-    return canonical, directory
-
-try:
-    archive_size = archive_path.stat().st_size
-    if archive_size <= 0 or archive_size > max_archive:
-        reject(f"archive size must be between 1 and {max_archive} bytes")
-    if destination.exists() or destination.is_symlink():
-        reject(f"private extraction destination must not already exist: {destination}")
-    destination.mkdir(parents=True, mode=0o700)
-
-    with zipfile.ZipFile(archive_path) as archive:
-        entries = archive.infolist()
-        if len(entries) != expected_entries:
-            reject(f"archive entry count mismatch: expected {expected_entries}, got {len(entries)}")
-        seen = {}
-        total = 0
-        validated = []
-        for info in entries:
-            canonical, directory = safe_name(info)
-            folded = canonical.casefold()
-            if folded in seen:
-                reject(f"duplicate or case-colliding archive paths: {seen[folded]!r} and {canonical!r}")
-            seen[folded] = canonical
-            if info.flag_bits & 0x1:
-                reject(f"encrypted archive entry: {canonical}")
-            if info.compress_type not in {zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED}:
-                reject(f"unsupported compression method for {canonical}")
-            if info.file_size < 0 or info.file_size > max_file:
-                reject(f"archive entry exceeds the {max_file}-byte per-file limit: {canonical}")
-            total += info.file_size
-            if total > max_expanded:
-                reject(f"expanded archive exceeds the {max_expanded}-byte limit")
-            validated.append((info, canonical, directory))
-
-        missing = sorted(required - set(seen.values()))
-        if missing:
-            reject(f"archive is missing required files: {', '.join(missing)}")
-        for path in required | executables:
-            match = next((item for item in validated if item[1] == path), None)
-            if match is None or match[2] or match[0].file_size == 0:
-                reject(f"required archive path is not a non-empty regular file: {path}")
-        for _, canonical, _ in validated:
-            parent = PurePosixPath(canonical).parent
-            while str(parent) != ".":
-                parent_entry = next((item for item in validated if item[1].casefold() == str(parent).casefold()), None)
-                if parent_entry is not None and not parent_entry[2]:
-                    reject(f"archive path descends through a regular file: {canonical}")
-                parent = parent.parent
-
-        for info, canonical, directory in validated:
-            target = destination.joinpath(*canonical.split("/"))
-            resolved_parent = target.parent.resolve()
-            destination_resolved = destination.resolve()
-            if resolved_parent != destination_resolved and destination_resolved not in resolved_parent.parents:
-                reject(f"resolved archive path escapes extraction root: {canonical}")
-            if directory:
-                target.mkdir(parents=True, exist_ok=True, mode=0o755)
-                os.chmod(target, 0o755)
-                continue
-            target.parent.mkdir(parents=True, exist_ok=True, mode=0o755)
-            with archive.open(info, "r") as source, target.open("xb") as output:
-                copied = 0
-                while True:
-                    chunk = source.read(1024 * 1024)
-                    if not chunk:
-                        break
-                    copied += len(chunk)
-                    if copied > info.file_size or copied > max_file:
-                        reject(f"archive entry expanded beyond its declared bound: {canonical}")
-                    output.write(chunk)
-                if copied != info.file_size:
-                    reject(f"archive entry size mismatch: {canonical}")
-            os.chmod(target, 0o755 if canonical in executables else 0o644)
-except (OSError, ValueError, zipfile.BadZipFile, zipfile.LargeZipFile) as error:
-    shutil.rmtree(destination, ignore_errors=True)
-    raise SystemExit(f"pinned ZIP validation failed: {error}")
-PY
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+exec bash "$script_dir/bun.sh" "$script_dir/extract-pinned-zip.mts" "$@"
diff --git a/tools/dev/extract-pinned-zip.test.mts b/tools/dev/extract-pinned-zip.test.mts
new file mode 100644
index 000000000..c261f010f
--- /dev/null
+++ b/tools/dev/extract-pinned-zip.test.mts
@@ -0,0 +1,67 @@
+import assert from 'node:assert/strict';
+import {
+  mkdtempSync,
+  mkdirSync,
+  writeFileSync,
+  readFileSync,
+  statSync,
+  existsSync,
+  rmSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import { zipArchive } from '../packaging/testdata/zip-fixture.mts';
+import { extractPinnedZip } from './extract-pinned-zip.mts';
+
+const root = mkdtempSync(path.join(tmpdir(), 'pinned-zip-'));
+const tool = {
+  name: 'tool/bin/tool',
+  data: '#!/bin/sh\necho ok\n',
+  externalAttributes: 0o100755 << 16,
+};
+const archive = path.join(root, 'tool.zip');
+const destination = path.join(root, 'out');
+function extract(bytes, count = 1) {
+  writeFileSync(archive, bytes);
+  extractPinnedZip([
+    '--archive',
+    archive,
+    '--destination',
+    destination,
+    '--prefix',
+    'tool',
+    '--entry-count',
+    String(count),
+    '--required',
+    tool.name,
+    '--executable',
+    tool.name,
+  ]);
+}
+try {
+  const valid = zipArchive([tool]);
+  extract(valid);
+  assert.equal(readFileSync(path.join(destination, tool.name), 'utf8'), tool.data);
+  if (process.platform !== 'win32')
+    assert.equal(statSync(path.join(destination, tool.name)).mode & 0o777, 0o755);
+  // A rejected destination belongs to its caller; preserve it even on failure.
+  assert.throws(() => extract(valid));
+  assert.equal(readFileSync(path.join(destination, tool.name), 'utf8'), tool.data);
+  rmSync(destination, { recursive: true });
+  for (const [bytes, count] of [
+    [zipArchive([{ ...tool, name: 'tool/../escape' }]), 1],
+    [zipArchive([{ ...tool, externalAttributes: 0o120777 << 16 }]), 1],
+    [zipArchive([tool, tool]), 2],
+    [zipArchive([tool, { ...tool, name: 'tool/bin/Tool' }]), 2],
+    [zipArchive([{ ...tool, declaredSize: 150_000_001 }]), 1],
+    [valid.subarray(0, -7), 1],
+    [zipArchive([{ ...tool, name: 'other/bin/tool' }]), 1],
+    [valid, 2],
+  ]) {
+    assert.throws(() => extract(bytes, count));
+    assert.equal(existsSync(destination), false, 'failed extraction left a partial destination');
+  }
+  console.log('pinned ZIP adversarial tests passed');
+} finally {
+  rmSync(root, { recursive: true, force: true });
+}
diff --git a/tools/dev/extract-pinned-zip.test.sh b/tools/dev/extract-pinned-zip.test.sh
index 81d7bbba3..7c5cfc027 100755
--- a/tools/dev/extract-pinned-zip.test.sh
+++ b/tools/dev/extract-pinned-zip.test.sh
@@ -1,115 +1,4 @@
 #!/usr/bin/env bash
 set -euo pipefail
-
-root="$(git rev-parse --show-toplevel)"
-extractor="$root/tools/dev/extract-pinned-zip.sh"
-tmp="$(mktemp -d)"
-trap 'rm -rf "$tmp"' EXIT HUP INT TERM
-
-python_bin=""
-for candidate in python3 python; do
-  if command -v "$candidate" >/dev/null 2>&1 &&
-    "$candidate" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 8) else 1)'; then
-    python_bin="$candidate"
-    break
-  fi
-done
-[ -n "$python_bin" ] || {
-  echo "Python 3.8 or newer is required" >&2
-  exit 1
-}
-
-"$python_bin" - "$tmp" <<'PY'
-import os
-import stat
-import struct
-import sys
-import warnings
-import zipfile
-from pathlib import Path
-
-root = Path(sys.argv[1])
-
-def write_zip(name, entries):
-    with zipfile.ZipFile(root / name, "w", zipfile.ZIP_DEFLATED) as archive:
-        for path, contents, mode in entries:
-            info = zipfile.ZipInfo(path)
-            info.compress_type = zipfile.ZIP_DEFLATED
-            info.external_attr = mode << 16
-            archive.writestr(info, contents)
-
-write_zip("valid.zip", [("tool/bin/tool", b"#!/bin/sh\necho ok\n", stat.S_IFREG | 0o755)])
-write_zip("traversal.zip", [("tool/../escape", b"no", stat.S_IFREG | 0o644)])
-write_zip("symlink.zip", [("tool/bin/tool", b"/tmp/escape", stat.S_IFLNK | 0o777)])
-write_zip("wrong-layout.zip", [("other/bin/tool", b"no", stat.S_IFREG | 0o755)])
-write_zip("case-collision.zip", [
-    ("tool/bin/tool", b"one", stat.S_IFREG | 0o755),
-    ("tool/bin/Tool", b"two", stat.S_IFREG | 0o755),
-])
-
-with warnings.catch_warnings():
-    warnings.simplefilter("ignore", UserWarning)
-    with zipfile.ZipFile(root / "duplicate.zip", "w", zipfile.ZIP_STORED) as archive:
-        archive.writestr("tool/bin/tool", b"one")
-        archive.writestr("tool/bin/tool", b"two")
-
-valid = (root / "valid.zip").read_bytes()
-(root / "truncated.zip").write_bytes(valid[:-7])
-
-oversized = bytearray(valid)
-central = oversized.find(b"PK\x01\x02")
-if central < 0:
-    raise SystemExit("could not locate ZIP central directory")
-struct.pack_into(""$tmp/$name.stdout" 2>"$tmp/$name.stderr"; then
-    echo "expected $name archive rejection" >&2
-    exit 1
-  fi
-  [ ! -e "$destination" ] || {
-    echo "$name left a partial extraction destination" >&2
-    exit 1
-  }
-}
-
-valid_destination="$tmp/valid-out"
-"$extractor" \
-  --archive "$tmp/valid.zip" \
-  --destination "$valid_destination" \
-  --prefix tool \
-  --entry-count 1 \
-  --required tool/bin/tool \
-  --executable tool/bin/tool
-"$valid_destination/tool/bin/tool" | grep -qx ok
-"$python_bin" - "$valid_destination/tool/bin/tool" <<'PY'
-import os
-import stat
-import sys
-mode = stat.S_IMODE(os.stat(sys.argv[1]).st_mode)
-raise SystemExit(0 if mode == 0o755 else f"unexpected extracted mode: {mode:o}")
-PY
-
-expect_failure traversal "$tmp/traversal.zip" 1
-expect_failure symlink "$tmp/symlink.zip" 1
-expect_failure duplicate "$tmp/duplicate.zip" 2
-expect_failure case-collision "$tmp/case-collision.zip" 2
-expect_failure oversized "$tmp/oversized.zip" 1
-expect_failure truncated "$tmp/truncated.zip" 1
-expect_failure wrong-layout "$tmp/wrong-layout.zip" 1
-expect_failure wrong-entry-count "$tmp/valid.zip" 2
-
-echo "pinned ZIP adversarial tests passed"
+script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+exec bash "$script_dir/bun.sh" "$script_dir/extract-pinned-zip.test.mts" "$@"
diff --git a/tools/dev/install-hooks.mjs b/tools/dev/install-hooks.mjs
deleted file mode 100755
index 105d1ff4d..000000000
--- a/tools/dev/install-hooks.mjs
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env bun
-import { spawnSync } from "node:child_process";
-import { accessSync, constants } from "node:fs";
-import path from "node:path";
-import process from "node:process";
-
-import { captureCommandOutput } from "./capture-command-output.mjs";
-
-function fail(message) {
-  console.error(message);
-  process.exit(1);
-}
-
-function run(command, args, options = {}) {
-  const result = spawnSync(command, args, {
-    stdio: "inherit",
-    ...options,
-  });
-  if (result.error) {
-    fail(result.error.message);
-  }
-  if (result.status !== 0) {
-    process.exit(result.status ?? 1);
-  }
-}
-
-function output(command, args) {
-  const result = captureCommandOutput(command, args, {
-    label: `${command} ${args.join(" ")}`,
-  });
-  if (result.error) {
-    fail(result.error.message);
-  }
-  if (result.status !== 0) {
-    fail(result.stderr.trim() || `${command} ${args.join(" ")} failed`);
-  }
-  return result.stdout.trim();
-}
-
-function hasCommand(command) {
-  const pathValue = process.env.PATH ?? "";
-  const extensions =
-    process.platform === "win32"
-      ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";")
-      : [""];
-  for (const directory of pathValue.split(path.delimiter).filter(Boolean)) {
-    for (const extension of extensions) {
-      const candidate = path.join(directory, `${command}${extension}`);
-      try {
-        accessSync(candidate, constants.X_OK);
-        return true;
-      } catch {
-        // Keep scanning PATH.
-      }
-    }
-  }
-  return false;
-}
-
-const root = output("git", ["rev-parse", "--show-toplevel"]);
-process.chdir(root);
-
-if (!hasCommand("prek")) {
-  fail(`missing required command: prek
-
-Install prek first, then rerun this script:
-  brew install prek
-
-Other installation methods are documented at https://prek.j178.dev/installation/`);
-}
-
-const hooksPath = captureCommandOutput(
-  "git",
-  ["config", "--local", "--get", "core.hooksPath"],
-  { label: "git config --local --get core.hooksPath" },
-);
-if (hooksPath.status === 0 && hooksPath.stdout.trim() === ".githooks") {
-  run("git", ["config", "--local", "--unset", "core.hooksPath"]);
-}
-
-run("prek", ["install", "--prepare-hooks", "--overwrite"]);
-console.log("Installed prek hooks from prek.toml");
diff --git a/tools/dev/install-hooks.sh b/tools/dev/install-hooks.sh
new file mode 100755
index 000000000..525fc59e7
--- /dev/null
+++ b/tools/dev/install-hooks.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(git rev-parse --show-toplevel)"
+command -v prek >/dev/null || { echo 'Install prek first: https://prek.j178.dev/installation/' >&2; exit 1; }
+if [ "$(git config --local --get core.hooksPath || true)" = .githooks ]; then
+  git config --local --unset core.hooksPath
+fi
+prek install --prepare-hooks --overwrite
diff --git a/tools/dev/install-pinned-js-runtime.sh b/tools/dev/install-pinned-js-runtime.sh
index a48c4f7a0..3be389cf7 100755
--- a/tools/dev/install-pinned-js-runtime.sh
+++ b/tools/dev/install-pinned-js-runtime.sh
@@ -26,11 +26,11 @@ case "$tool" in
 esac
 
 case "$tool" in
-  bun) manifest="${OLIPHAUNT_BUN_TOOLCHAIN_MANIFEST:-$root/src/sources/toolchains/bun.toml}" ;;
-  deno) manifest="${OLIPHAUNT_DENO_TOOLCHAIN_MANIFEST:-$root/src/sources/toolchains/deno.toml}" ;;
+  bun) manifest="${OLIPHAUNT_BUN_TOOLCHAIN_MANIFEST:-$root/tools/dev/bun.toml}" ;;
+  deno) manifest="${OLIPHAUNT_DENO_TOOLCHAIN_MANIFEST:-$root/tools/dev/deno.toml}" ;;
 esac
 proto_file="${OLIPHAUNT_PINNED_TOOL_PROTO_FILE:-$root/.prototools}"
-extractor="${OLIPHAUNT_PINNED_ZIP_EXTRACTOR:-$root/tools/dev/extract-pinned-zip.sh}"
+extractor="$script_dir/extract-pinned-binary.sh"
 curl_platform_flags="$script_dir/curl-platform-flags.sh"
 cache_root="${OLIPHAUNT_PINNED_TOOL_CACHE_ROOT:-$root/target/oliphaunt-tools}"
 case "$(uname -s)" in
@@ -42,7 +42,7 @@ case "$(uname -s)" in
 esac
 [ -f "$manifest" ] || fail "missing $tool manifest: $manifest"
 [ -f "$proto_file" ] || fail "missing tool version file: $proto_file"
-[ -x "$extractor" ] || fail "missing executable pinned ZIP extractor: $extractor"
+[ -f "$extractor" ] && [ ! -L "$extractor" ] || fail "missing regular pinned binary extractor: $extractor"
 if [ ! -f "$curl_platform_flags" ] || [ -L "$curl_platform_flags" ]; then
   fail "missing regular curl platform policy: $curl_platform_flags"
 fi
@@ -83,16 +83,13 @@ proto_version() {
   ' "$proto_file"
 }
 
-version="$(manifest_value toolchain version)" || fail "$manifest must contain exactly one quoted toolchain.version"
+version="$(proto_version)" || fail "$proto_file must contain exactly one $tool version"
+version="${version#v}"
 case "$version" in
   ''|.*|*.|*..*|*[!0-9.]*) fail "invalid $tool version in $manifest: $version" ;;
 esac
 [ "$(awk -F. 'NF == 3 { print "valid" }' <<<"$version")" = "valid" ] ||
   fail "invalid $tool version in $manifest: $version"
-configured_version="$(proto_version)" || fail "$proto_file must contain exactly one $tool version"
-configured_version="${configured_version#v}"
-[ "$configured_version" = "$version" ] ||
-  fail "$proto_file $tool version $configured_version does not match $manifest version $version"
 if [ -n "$expected_input" ]; then
   expected_input="${expected_input#v}"
   [ "$expected_input" = "$version" ] ||
@@ -287,7 +284,7 @@ for candidate_url in "$url" ${mirror_url:+"$mirror_url"}; do
   curl_args=(
     --fail --location --silent --show-error
     --proto '=https' --proto-redir '=https'
-    --retry 5 --retry-all-errors --retry-delay 2 --retry-max-time 120
+    --retry 6 --retry-all-errors --retry-max-time 120
     --connect-timeout 20 --max-time 180 --max-filesize 200000000
   )
   if [ -n "$curl_platform_tls_flag" ]; then
@@ -305,20 +302,8 @@ for candidate_url in "$url" ${mirror_url:+"$mirror_url"}; do
 done
 [ "$downloaded" = "1" ] || fail "could not download the verified $tool $version $target archive"
 
-extract_args=(
-  --archive "$archive"
-  --destination "$stage/extracted"
-  --entry-count "$entry_count"
-  --required "$binary_path"
-  --executable "$binary_path"
-)
-case "$binary_path" in
-  */*) extract_args+=(--prefix "${binary_path%%/*}") ;;
-esac
-"$extractor" "${extract_args[@]}"
 mkdir -p "$stage/bin"
-mv "$stage/extracted/$binary_path" "$stage/bin/$exe_name"
-rm -rf "$stage/extracted"
+bash "$extractor" zip "$archive" "$binary_path" "$stage/bin/$exe_name" "$binary_sha256"
 chmod 0700 "$stage" "$stage/bin"
 chmod 0555 "$stage/bin/$exe_name"
 printf '%s\n' "$receipt_text" >"$stage/receipt"
diff --git a/tools/dev/install-pinned-js-runtime.test.sh b/tools/dev/install-pinned-js-runtime.test.sh
index b1b3848a9..a91a6839b 100755
--- a/tools/dev/install-pinned-js-runtime.test.sh
+++ b/tools/dev/install-pinned-js-runtime.test.sh
@@ -3,120 +3,45 @@ set -euo pipefail
 
 root="$(git rev-parse --show-toplevel)"
 installer="$root/tools/dev/install-pinned-js-runtime.sh"
-extractor="$root/tools/dev/extract-pinned-zip.sh"
 tmp="$(mktemp -d)"
 trap 'rm -rf "$tmp"' EXIT HUP INT TERM
 
-# These are literal workflow expressions, not shell expansions.
-# shellcheck disable=SC2016
-for action in .github/actions/setup-bun/action.yml .github/actions/setup-deno/action.yml; do
-  grep -Fq '[[ "${RUNNER_OS:-}" == "Windows" ]]' "$action"
-  grep -Fq 'binary_dir="$(cygpath -w "$binary_dir")"' "$action"
-  grep -Fq 'echo "$binary_dir" >> "$GITHUB_PATH"' "$action"
-done
-
-python_bin=""
-for candidate in python3 python; do
-  if command -v "$candidate" >/dev/null 2>&1 &&
-    "$candidate" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 8) else 1)'; then
-    python_bin="$candidate"
-    break
-  fi
-done
-[ -n "$python_bin" ] || {
-  echo "Python 3.8 or newer is required" >&2
-  exit 1
-}
 
-# macOS still ships Bash 3.2, whose command-substitution parser can terminate
-# early on an inline case pattern. Keep platform selection out of nested case
-# so a Linux Bash 5 syntax check cannot certify a script that macOS rejects.
-"$python_bin" - "$installer" <<'PY'
-import re
-import sys
-from pathlib import Path
 
-source = Path(sys.argv[1]).read_text(encoding="utf-8")
-if re.search(r"\$\(\s*case\b", source):
-    raise SystemExit("pinned JS runtime installer must not nest case inside command substitution")
-PY
 
 mkdir -p "$tmp/fixtures" "$tmp/config" "$tmp/bin"
-"$python_bin" - "$tmp" <<'PY'
-import hashlib
-import stat
-import sys
-import zipfile
-from pathlib import Path
-
-root = Path(sys.argv[1])
-fixtures = root / "fixtures"
-config = root / "config"
-
-def archive(name, path, contents):
-    target = fixtures / name
-    info = zipfile.ZipInfo(path)
-    info.external_attr = (stat.S_IFREG | 0o755) << 16
-    info.compress_type = zipfile.ZIP_DEFLATED
-    with zipfile.ZipFile(target, "w") as output:
-        output.writestr(info, contents)
-    return target, hashlib.sha256(contents).hexdigest(), hashlib.sha256(target.read_bytes()).hexdigest()
-
-bun, bun_binary_sha, bun_archive_sha = archive(
-    "bun.zip", "bun-linux-x64/bun", b"#!/bin/sh\nprintf '1.2.3\\n'\n"
-)
-bad_bun, bad_bun_binary_sha, bad_bun_archive_sha = archive(
-    "bun-wrong-version.zip", "bun-linux-x64/bun", b"#!/bin/sh\nprintf '9.9.9\\n'\n"
-)
-deno, deno_binary_sha, deno_archive_sha = archive(
-    "deno.zip", "deno", b"#!/bin/sh\nprintf 'deno 1.2.3 (stable, release, x86_64-unknown-linux-gnu)\\n'\n"
-)
-
-def bun_manifest(name, archive_sha, binary_sha):
-    (config / name).write_text(f'''[toolchain]
-version = "1.2.3"
-
-[assets.linux-x64]
-url = "https://github.com/oven-sh/bun/releases/download/bun-v1.2.3/bun-linux-x64.zip"
-sha256 = "{archive_sha}"
-binary_path = "bun-linux-x64/bun"
-binary_sha256 = "{binary_sha}"
-entry_count = "1"
-''', encoding="utf-8")
-
-bun_manifest("bun.toml", bun_archive_sha, bun_binary_sha)
-bun_manifest("bun-bad-sha.toml", "0" * 64, bun_binary_sha)
-bun_manifest("bun-wrong-version.toml", bad_bun_archive_sha, bad_bun_binary_sha)
-(config / "bun-receipt").write_text(
-    f"tool=bun\nversion=1.2.3\ntarget=linux-x64\narchive_sha256={bun_archive_sha}\nbinary_sha256={bun_binary_sha}\n",
-    encoding="utf-8",
-)
-(config / "deno.toml").write_text(f'''[toolchain]
-version = "1.2.3"
-
-[assets.x86_64-unknown-linux-gnu]
-url = "https://github.com/denoland/deno/releases/download/v1.2.3/deno-x86_64-unknown-linux-gnu.zip"
-mirror_url = "https://dl.deno.land/release/v1.2.3/deno-x86_64-unknown-linux-gnu.zip"
-sha256 = "{deno_archive_sha}"
-binary_path = "deno"
-binary_sha256 = "{deno_binary_sha}"
-entry_count = "1"
-''', encoding="utf-8")
-(config / "deno-receipt").write_text(
-    f"tool=deno\nversion=1.2.3\ntarget=x86_64-unknown-linux-gnu\narchive_sha256={deno_archive_sha}\nbinary_sha256={deno_binary_sha}\n",
-    encoding="utf-8",
-)
-(config / "prototools").write_text('bun = "1.2.3"\ndeno = "1.2.3"\n', encoding="utf-8")
-PY
+bash "$root/tools/dev/bun.sh" - "$tmp" <<'TS'
+import {createHash} from 'node:crypto';
+import {writeFileSync} from 'node:fs';
+import {zipArchive} from './tools/packaging/testdata/zip-fixture.mts';
+const root = process.argv[2];
+const sha = data => createHash('sha256').update(data).digest('hex');
+const write = (name, data) => writeFileSync(root + '/' + name, data);
+
+function archive(name, member, data) {
+  const bytes = zipArchive([{name: member, data, method: 8, externalAttributes: 0o100755 << 16}]);
+  write('fixtures/' + name, bytes);
+  return {archive: sha(bytes), binary: sha(data)};
+}
+const bun = archive('bun.zip', 'bun-linux-x64/bun', "#!/bin/sh\nprintf '1.2.3\\n'\n");
+const wrong = archive('bun-wrong-version.zip', 'bun-linux-x64/bun', "#!/bin/sh\nprintf '9.9.9\\n'\n");
+const deno = archive('deno.zip', 'deno', "#!/bin/sh\nprintf 'deno 1.2.3 (stable, release, x86_64-unknown-linux-gnu)\\n'\n");
+function bunManifest(name, pin) {
+  write('config/' + name, "[assets.linux-x64]\nurl = \"https://github.com/oven-sh/bun/releases/download/bun-v1.2.3/bun-linux-x64.zip\"\nsha256 = \"{archive_sha}\"\nbinary_path = \"bun-linux-x64/bun\"\nbinary_sha256 = \"{binary_sha}\"\nentry_count = \"1\"\n".replace('{archive_sha}', pin.archive).replace('{binary_sha}', pin.binary));
+}
+bunManifest('bun.toml', bun);
+bunManifest('bun-bad-sha.toml', {...bun, archive: '0'.repeat(64)});
+bunManifest('bun-wrong-version.toml', wrong);
+write('config/deno.toml', "[assets.x86_64-unknown-linux-gnu]\nurl = \"https://github.com/denoland/deno/releases/download/v1.2.3/deno-x86_64-unknown-linux-gnu.zip\"\nmirror_url = \"https://dl.deno.land/release/v1.2.3/deno-x86_64-unknown-linux-gnu.zip\"\nsha256 = \"{deno_archive_sha}\"\nbinary_path = \"deno\"\nbinary_sha256 = \"{deno_binary_sha}\"\nentry_count = \"1\"\n".replace('{deno_archive_sha}', deno.archive).replace('{deno_binary_sha}', deno.binary));
+for (const [tool, target, pin] of [['bun','linux-x64',bun],['deno','x86_64-unknown-linux-gnu',deno]]) {
+  write('config/' + tool + '-receipt', 'tool=' + tool + '\nversion=1.2.3\ntarget=' + target + '\narchive_sha256=' + pin.archive + '\nbinary_sha256=' + pin.binary + '\n');
+}
+write('config/prototools', 'bun = "1.2.3"\ndeno = "1.2.3"\n');
 
-"$python_bin" - "$tmp/bin/curl" <<'PY'
-import os
-import stat
-import sys
-from pathlib import Path
+TS
 
-path = Path(sys.argv[1])
-path.write_text(r'''#!/usr/bin/env bash
+cat >"$tmp/bin/curl" <<'SH'
+#!/usr/bin/env bash
 set -euo pipefail
 printf '%s\n' "$@" >> "$CURL_ARGS_LOG"
 output=""
@@ -157,14 +82,12 @@ case "$CURL_MODE" in
     exit 2
     ;;
 esac
-''', encoding="utf-8")
-path.chmod(stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
-PY
+SH
+chmod 0700 "$tmp/bin/curl"
 
 common_env=(
   "OLIPHAUNT_PINNED_TOOL_ROOT=$tmp"
   "OLIPHAUNT_PINNED_TOOL_PROTO_FILE=$tmp/config/prototools"
-  "OLIPHAUNT_PINNED_ZIP_EXTRACTOR=$extractor"
   "OLIPHAUNT_PINNED_TOOL_CURL=$tmp/bin/curl"
   "OLIPHAUNT_PINNED_TOOL_TARGET=linux-x64"
   "BUN_ARCHIVE=$tmp/fixtures/bun.zip"
diff --git a/tools/dev/install-pinned-maintainer-tool.sh b/tools/dev/install-pinned-maintainer-tool.sh
index eb49ae7f6..ac899f21a 100755
--- a/tools/dev/install-pinned-maintainer-tool.sh
+++ b/tools/dev/install-pinned-maintainer-tool.sh
@@ -13,7 +13,7 @@ if [ -z "$root" ]; then
   root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
 fi
 [ -n "$root" ] || { echo "could not determine repository root" >&2; exit 1; }
-manifest="${OLIPHAUNT_MAINTAINER_TOOLS_MANIFEST:-$root/src/sources/toolchains/maintainer-tools.toml}"
+manifest="${OLIPHAUNT_MAINTAINER_TOOLS_MANIFEST:-$root/tools/dev/maintainer-tools.toml}"
 if [ ! -f "$manifest" ] || [ -L "$manifest" ]; then
   echo "missing regular maintainer tool manifest: $manifest" >&2
   exit 1
@@ -235,7 +235,6 @@ archive_sha="$(manifest_value "$section" sha256 || true)"
 binary_sha="$(manifest_value "$section" binary_sha256 || true)"
 archive_format="$(manifest_value "$section" format || true)"
 binary_path="$(manifest_value "$section" binary_path || true)"
-entry_count="$(manifest_value "$section" entry_count || true)"
 max_archive_bytes="$(manifest_value "$section" max_archive_bytes || true)"
 max_binary_bytes="$(manifest_value "$section" max_binary_bytes || true)"
 for digest in "$archive_sha" "$binary_sha"; do
@@ -244,7 +243,7 @@ for digest in "$archive_sha" "$binary_sha"; do
     exit 1
   fi
 done
-for number in "$entry_count" "$max_archive_bytes" "$max_binary_bytes"; do
+for number in "$max_archive_bytes" "$max_binary_bytes"; do
   [[ "$number" =~ ^[1-9][0-9]*$ ]] || { echo "$manifest has invalid bounds in $section" >&2; exit 1; }
 done
 [ "$binary_path" = "$tool" ] || { echo "$section.binary_path must be $tool" >&2; exit 1; }
@@ -325,7 +324,7 @@ actual_archive_sha="$(sha256_file "$archive")"
 case "$tool:$archive_format" in
   cargo-binstall:zip)
     members="$(unzip -Z1 "$archive")" || { echo "invalid cargo-binstall ZIP archive" >&2; exit 1; }
-    if [ "$members" != cargo-binstall ] || [ "$(printf '%s\n' "$members" | awk 'NF { count++ } END { print count + 0 }')" != "$entry_count" ]; then
+    if [ "$members" != cargo-binstall ]; then
       echo "cargo-binstall ZIP archive has an unexpected member layout" >&2
       exit 1
     fi
@@ -337,7 +336,7 @@ case "$tool:$archive_format" in
     ;;
   cargo-binstall:tgz)
     members="$(tar -tzf "$archive")" || { echo "invalid cargo-binstall tar archive" >&2; exit 1; }
-    if [ "$members" != cargo-binstall ] || [ "$(printf '%s\n' "$members" | awk 'NF { count++ } END { print count + 0 }')" != "$entry_count" ]; then
+    if [ "$members" != cargo-binstall ]; then
       echo "cargo-binstall tar archive has an unexpected member layout" >&2
       exit 1
     fi
@@ -347,15 +346,10 @@ case "$tool:$archive_format" in
     tar -xzf "$archive" -C "$extract_root" cargo-binstall
     ;;
   actionlint:tgz)
-    members="$(tar -tzf "$archive")" || { echo "invalid actionlint tar archive" >&2; exit 1; }
-    expected_members="$(printf '%s\n' LICENSE.txt README.md actionlint docs/README.md docs/api.md docs/checks.md docs/config.md docs/install.md docs/reference.md docs/usage.md man/actionlint.1 | LC_ALL=C sort)"
-    if [ "$(printf '%s\n' "$members" | LC_ALL=C sort)" != "$expected_members" ] || \
-      [ "$(printf '%s\n' "$members" | awk 'NF { count++ } END { print count + 0 }')" != "$entry_count" ]; then
-      echo "actionlint tar archive has an unexpected member layout" >&2
-      exit 1
-    fi
-    [ "$(tar -tvzf "$archive" | awk '{ print substr($1, 1, 1) }' | LC_ALL=C sort -u)" = - ] || {
-      echo "actionlint tar archive contains a non-regular member" >&2; exit 1;
+    # The archive is pinned; documentation names are not an installation contract.
+    # Select only this exact top-level member and reject duplicates or links.
+    [ "$(tar -tvzf "$archive" actionlint | awk '{ print substr($1, 1, 1) }')" = - ] || {
+      echo "actionlint tar archive must contain one regular actionlint binary" >&2; exit 1;
     }
     tar -xzf "$archive" -C "$extract_root" actionlint
     ;;
diff --git a/tools/dev/install-pinned-winflexbison.sh b/tools/dev/install-pinned-winflexbison.sh
index e47e58fab..fe1c39460 100755
--- a/tools/dev/install-pinned-winflexbison.sh
+++ b/tools/dev/install-pinned-winflexbison.sh
@@ -11,7 +11,7 @@ if [ -z "$root" ]; then
   root="$(git rev-parse --show-toplevel 2>/dev/null)" || fail "must run inside the Oliphaunt checkout"
 fi
 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-manifest="${OLIPHAUNT_WINFLEXBISON_MANIFEST:-$root/src/sources/toolchains/winflexbison.toml}"
+manifest="${OLIPHAUNT_WINFLEXBISON_MANIFEST:-$root/tools/dev/winflexbison.toml}"
 extractor="${OLIPHAUNT_PINNED_ZIP_EXTRACTOR:-$root/tools/dev/extract-pinned-zip.sh}"
 curl_platform_flags="$script_dir/curl-platform-flags.sh"
 cache_root="${OLIPHAUNT_PINNED_NATIVE_TOOL_CACHE_ROOT:-$root/target/oliphaunt-native-tools}"
@@ -90,18 +90,6 @@ done
 [ "$expanded_bytes" -ge 1 ] && [ "$expanded_bytes" -le 10000000 ] ||
   fail "expanded byte bound is invalid"
 
-python_bin="${OLIPHAUNT_WINFLEXBISON_PYTHON:-}"
-if [ -z "$python_bin" ]; then
-  for candidate in python3 python; do
-    if command -v "$candidate" >/dev/null 2>&1 &&
-      "$candidate" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 8) else 1)'; then
-      python_bin="$candidate"
-      break
-    fi
-  done
-fi
-[ -n "$python_bin" ] || fail "Python 3.8 or newer is required"
-
 sha256_file() {
   if command -v sha256sum >/dev/null 2>&1; then
     sha256sum "$1" | awk '{print tolower($1)}'
@@ -113,47 +101,7 @@ sha256_file() {
 }
 
 payload_identity() {
-  "$python_bin" - "$1" <<'PY'
-import hashlib
-import os
-import stat
-import sys
-from pathlib import Path
-
-root = Path(sys.argv[1])
-if not root.is_dir() or root.is_symlink():
-    raise SystemExit(1)
-files = []
-for current, directories, names in os.walk(root, topdown=True, followlinks=False):
-    current_path = Path(current)
-    for name in directories:
-        path = current_path / name
-        mode = os.lstat(path).st_mode
-        if not stat.S_ISDIR(mode) or stat.S_ISLNK(mode):
-            raise SystemExit(1)
-    for name in names:
-        path = current_path / name
-        mode = os.lstat(path).st_mode
-        if not stat.S_ISREG(mode) or stat.S_ISLNK(mode):
-            raise SystemExit(1)
-        relative = path.relative_to(root).as_posix()
-        if any(ord(character) < 0x20 or ord(character) == 0x7F for character in relative):
-            raise SystemExit(1)
-        files.append((relative, path))
-digest = hashlib.sha256()
-expanded = 0
-for relative, path in sorted(files, key=lambda item: item[0].encode("utf-8")):
-    file_digest = hashlib.sha256()
-    size = 0
-    with path.open("rb") as source:
-        while chunk := source.read(1024 * 1024):
-            size += len(chunk)
-            file_digest.update(chunk)
-    expanded += size
-    row = f"{relative}\0{size}\0{file_digest.hexdigest()}\n".encode("utf-8")
-    digest.update(row)
-print(f"{digest.hexdigest()}\t{len(files)}\t{expanded}")
-PY
+  bash "$script_dir/bun.sh" "$script_dir/winflexbison-identity.mts" "$1"
 }
 
 receipt_text="$(printf 'tool=winflexbison\nversion=%s\narchive_sha256=%s\ntree_sha256=%s\nflex_sha256=%s\nbison_sha256=%s' \
diff --git a/tools/dev/install-pinned-winflexbison.test.sh b/tools/dev/install-pinned-winflexbison.test.sh
index d0bc2bcb7..7aef06433 100755
--- a/tools/dev/install-pinned-winflexbison.test.sh
+++ b/tools/dev/install-pinned-winflexbison.test.sh
@@ -8,77 +8,28 @@ tmp="$(mktemp -d)"
 trap 'rm -rf "$tmp"' EXIT HUP INT TERM
 mkdir -p "$tmp/fixtures" "$tmp/config" "$tmp/bin"
 
-python_bin=""
-for candidate in python3 python; do
-  if command -v "$candidate" >/dev/null 2>&1 &&
-    "$candidate" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 8) else 1)'; then
-    python_bin="$candidate"
-    break
-  fi
-done
-[ -n "$python_bin" ] || { echo "Python 3.8 or newer is required" >&2; exit 1; }
 
-"$python_bin" - "$tmp" <<'PY'
-import hashlib
-import stat
-import sys
-import zipfile
-from pathlib import Path
+bash "$root/tools/dev/bun.sh" - "$tmp" <<'TS'
+import {createHash} from 'node:crypto';
+import {writeFileSync} from 'node:fs';
+import {zipArchive} from './tools/packaging/testdata/zip-fixture.mts';
+const root = process.argv[2];
+const sha = data => createHash('sha256').update(data).digest('hex');
+const write = (name, data) => writeFileSync(root + '/' + name, data);
 
-root = Path(sys.argv[1])
-files = {
-    "win_flex.exe": b"fixture-flex\n",
-    "win_bison.exe": b"fixture-bison\n",
-    "data/README.md": b"fixture-data\n",
-}
-archive = root / "fixtures" / "winflex.zip"
-with zipfile.ZipFile(archive, "w") as output:
-    for name, contents in files.items():
-        info = zipfile.ZipInfo(name)
-        info.external_attr = (stat.S_IFREG | (0o755 if name.endswith(".exe") else 0o644)) << 16
-        info.compress_type = zipfile.ZIP_DEFLATED
-        output.writestr(info, contents)
-tree = hashlib.sha256()
-for name, contents in sorted(files.items(), key=lambda item: item[0].encode("utf-8")):
-    digest = hashlib.sha256(contents).hexdigest()
-    tree.update(f"{name}\0{len(contents)}\0{digest}\n".encode("utf-8"))
-values = {
-    "archive_sha": hashlib.sha256(archive.read_bytes()).hexdigest(),
-    "archive_bytes": archive.stat().st_size,
-    "expanded_bytes": sum(map(len, files.values())),
-    "tree_sha": tree.hexdigest(),
-    "flex_sha": hashlib.sha256(files["win_flex.exe"]).hexdigest(),
-    "bison_sha": hashlib.sha256(files["win_bison.exe"]).hexdigest(),
-}
-manifest = f'''[toolchain]
-version = "1.2.3"
-repository = "lexxmark/winflexbison"
+const files = {'win_flex.exe':'fixture-flex\n','win_bison.exe':'fixture-bison\n','data/README.md':'fixture-data\n'};
+const bytes = zipArchive(Object.entries(files).map(([name,data]) => ({name,data,method:8,externalAttributes:(name.endsWith('.exe') ? 0o100755 : 0o100644) << 16})));
+write('fixtures/winflex.zip',bytes);
+const tree = createHash('sha256');
+for (const [name, data] of Object.entries(files).sort(([a],[b]) => Buffer.compare(Buffer.from(a),Buffer.from(b)))) tree.update(name + '\0' + Buffer.byteLength(data) + '\0' + sha(data) + '\n');
+const values = {archive_sha:sha(bytes), archive_bytes:bytes.length, expanded_bytes:Object.values(files).reduce((sum,data)=>sum+Buffer.byteLength(data),0), tree_sha:tree.digest('hex'), flex_sha:sha(files['win_flex.exe']), bison_sha:sha(files['win_bison.exe'])};
+const manifest = "[toolchain]\nversion = \"1.2.3\"\nrepository = \"lexxmark/winflexbison\"\n\n[assets.windows-x64]\nurl = \"https://github.com/lexxmark/winflexbison/releases/download/v1.2.3/win_flex_bison-1.2.3.zip\"\nsha256 = \"{values['archive_sha']}\"\nbytes = \"{values['archive_bytes']}\"\nentry_count = \"3\"\nfile_count = \"3\"\nexpanded_bytes = \"{values['expanded_bytes']}\"\ntree_sha256 = \"{values['tree_sha']}\"\nflex_path = \"win_flex.exe\"\nflex_sha256 = \"{values['flex_sha']}\"\nbison_path = \"win_bison.exe\"\nbison_sha256 = \"{values['bison_sha']}\"\n".replace(/\{values\['([^']+)'\]\}/g, (_,key)=>String(values[key]));
+write('config/winflexbison.toml',manifest);
+write('config/bad-sha.toml',manifest.replace(values.archive_sha,'0'.repeat(64)));
+write('config/bad-tree.toml',manifest.replace(values.tree_sha,'0'.repeat(64)));
+write('config/bad-url.toml',manifest.replace('https://github.com/lexxmark/winflexbison/','https://example.invalid/'));
 
-[assets.windows-x64]
-url = "https://github.com/lexxmark/winflexbison/releases/download/v1.2.3/win_flex_bison-1.2.3.zip"
-sha256 = "{values['archive_sha']}"
-bytes = "{values['archive_bytes']}"
-entry_count = "3"
-file_count = "3"
-expanded_bytes = "{values['expanded_bytes']}"
-tree_sha256 = "{values['tree_sha']}"
-flex_path = "win_flex.exe"
-flex_sha256 = "{values['flex_sha']}"
-bison_path = "win_bison.exe"
-bison_sha256 = "{values['bison_sha']}"
-'''
-(root / "config" / "winflexbison.toml").write_text(manifest, encoding="utf-8")
-(root / "config" / "bad-sha.toml").write_text(
-    manifest.replace(values["archive_sha"], "0" * 64), encoding="utf-8"
-)
-(root / "config" / "bad-tree.toml").write_text(
-    manifest.replace(values["tree_sha"], "0" * 64), encoding="utf-8"
-)
-(root / "config" / "bad-url.toml").write_text(
-    manifest.replace("https://github.com/lexxmark/winflexbison/", "https://example.invalid/"),
-    encoding="utf-8",
-)
-PY
+TS
 
 cat >"$tmp/bin/curl" <<'SH'
 #!/usr/bin/env bash
@@ -107,7 +58,6 @@ run_installer() {
     "OLIPHAUNT_PINNED_ZIP_EXTRACTOR=$extractor" \
     "OLIPHAUNT_PINNED_NATIVE_TOOL_CACHE_ROOT=${CACHE_ROOT:-$tmp/cache}" \
     "OLIPHAUNT_WINFLEXBISON_CURL=$tmp/bin/curl" \
-    "OLIPHAUNT_WINFLEXBISON_PYTHON=$python_bin" \
     "WINFLEX_ARCHIVE=$tmp/fixtures/winflex.zip" \
     "CURL_ARGS_LOG=$tmp/curl-args.log" \
     "CURL_MODE=${CURL_MODE:-good}" \
diff --git a/src/sources/toolchains/maestro.toml b/tools/dev/maestro.toml
similarity index 100%
rename from src/sources/toolchains/maestro.toml
rename to tools/dev/maestro.toml
diff --git a/tools/dev/maintainer-tool-install.test.sh b/tools/dev/maintainer-tool-install.test.sh
new file mode 100644
index 000000000..8d998f70e
--- /dev/null
+++ b/tools/dev/maintainer-tool-install.test.sh
@@ -0,0 +1,223 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../.."
+repo="$PWD"
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-maintainer-tools-XXXXXX")
+trap 'rm -rf "$scratch"' EXIT
+FAKE_REAL_MV="$(command -v mv)"
+export FAKE_REAL_MV
+mkdir -p "$scratch/fakes" "$scratch/source" "$scratch/action/docs"
+cat > "$scratch/source/cargo-binstall" <<'BIN'
+#!/usr/bin/env bash
+echo 'cargo-binstall 1.19.1'
+BIN
+cat > "$scratch/action/actionlint" <<'BIN'
+#!/usr/bin/env bash
+echo 'actionlint version 1.7.12'
+BIN
+chmod +x "$scratch/source/cargo-binstall" "$scratch/action/actionlint"
+printf 'upstream documentation\n' > "$scratch/action/docs/README.md"
+tar -czf "$scratch/cargo.tgz" -C "$scratch/source" cargo-binstall
+tar -czf "$scratch/action.tgz" -C "$scratch/action" actionlint docs/README.md
+printf extra > "$scratch/source/extra"
+tar -czf "$scratch/extra.tgz" -C "$scratch/source" cargo-binstall extra
+mkdir "$scratch/link"
+ln -s "$scratch/not-to-be-read" "$scratch/link/cargo-binstall"
+tar -czf "$scratch/link.tgz" -C "$scratch/link" cargo-binstall
+ln -s "$scratch/not-to-be-read" "$scratch/link/actionlint"
+tar -czf "$scratch/action-link.tgz" -C "$scratch/link" actionlint
+tar -czf "$scratch/action-duplicate.tgz" -C "$scratch/action" actionlint actionlint
+cat > "$scratch/fakes/uname" <<'FAKE'
+#!/usr/bin/env bash
+case "$1" in -s) echo "${FAKE_UNAME_OS:-Linux}";; -m) echo x86_64;; esac
+FAKE
+cat > "$scratch/fakes/curl" <<'FAKE'
+#!/usr/bin/env bash
+set -eu
+printf '%s\n' "$@" >> "$FAKE_CURL_LOG"
+output=
+while [ "$#" -gt 0 ]; do
+  if [ "$1" = --output ]; then output="$2"; shift; fi
+  shift
+done
+case "${FAKE_CURL_MODE:-success}" in
+  success) cp "$FAKE_CURL_SOURCE" "$output";;
+  transport) printf partial > "$output"; exit 28;;
+  http) exit 22;;
+  oversized) printf partial > "$output"; exit 63;;
+  interrupt) printf partial > "$output"; kill -TERM "$PPID"; exit 143;;
+esac
+FAKE
+cat > "$scratch/fakes/cargo" <<'FAKE'
+#!/usr/bin/env bash
+set -eu
+printf '%s\n' "$*" >> "$FAKE_CARGO_LOG"
+[ "${FAKE_CARGO_MODE:-success}" = success ] || exit 42
+while [ "$1" != --root ]; do shift; done
+mkdir -p "$2/bin"
+cp "$FAKE_SOURCE_BINARY" "$2/bin/cargo-binstall"
+FAKE
+cat > "$scratch/fakes/go" <<'FAKE'
+#!/usr/bin/env bash
+touch "$FAKE_GO_LOG"
+exit 99
+FAKE
+cat > "$scratch/fakes/mv" <<'FAKE'
+#!/usr/bin/env bash
+set -eu
+if [ "${!#}" = "${FAKE_MV_FAIL_TARGET:-}" ] && [ ! -f "$FAKE_MV_FAILURE_MARKER" ]; then
+  touch "$FAKE_MV_FAILURE_MARKER"
+  exit 91
+fi
+exec "$FAKE_REAL_MV" "$@"
+FAKE
+chmod +x "$scratch/fakes/"*
+export PATH="$scratch/fakes:$PATH"
+export FAKE_SOURCE_BINARY="$scratch/source/cargo-binstall"
+sha() { shasum -a 256 "$1" | awk '{print $1}'; }
+manifest() {
+  cat > "$OLIPHAUNT_MAINTAINER_TOOLS_MANIFEST" < "$case_root/failure.log" 2>&1 || status=$?
+  [ "$status" -ne 0 ] || { echo "unexpected success: $*" >&2; exit 1; }
+  if [ "$expected" != any ]; then test "$status" -eq "$expected"; fi
+}
+no_debris() {
+  local file
+  for file in "$OLIPHAUNT_MAINTAINER_BIN_DIR"/.*.download.* "$OLIPHAUNT_MAINTAINER_BIN_DIR"/.*.install.*; do
+    [ ! -e "$file" ] || { echo "installer left $file" >&2; exit 1; }
+  done
+}
+fixture cache
+install_tool cargo-binstall
+final="$OLIPHAUNT_MAINTAINER_BIN_DIR/cargo-binstall"
+marker="$OLIPHAUNT_MAINTAINER_BIN_DIR/.cargo-binstall.oliphaunt-source"
+cmp "$final" "$scratch/source/cargo-binstall"
+cp "$FAKE_CURL_LOG" "$case_root/first.log"
+install_tool cargo-binstall
+cmp "$FAKE_CURL_LOG" "$case_root/first.log"
+printf '# corrupted\n' >> "$final"
+install_tool cargo-binstall
+cmp "$final" "$scratch/source/cargo-binstall"
+printf '# force refresh\n' >> "$final"
+cp "$final" "$case_root/previous"
+cp "$marker" "$case_root/previous-marker"
+for archive in checksum extra link oversized; do
+  fixture_archive="$scratch/$archive.tgz"
+  case "$archive" in
+    checksum) printf wrong > "$fixture_archive";;
+    extra|link) cargo_archive="$fixture_archive";;
+    oversized) unset cargo_archive; max_archive=1; fixture_archive="$scratch/cargo.tgz";;
+  esac
+  manifest
+  export FAKE_CURL_SOURCE="$fixture_archive"
+  reject any install_tool cargo-binstall
+  cmp "$final" "$case_root/previous"
+  cmp "$marker" "$case_root/previous-marker"
+  no_debris
+done
+unset cargo_archive max_archive
+manifest
+export FAKE_CURL_SOURCE="$scratch/cargo.tgz" FAKE_MV_FAIL_TARGET="$marker"
+reject any install_tool cargo-binstall
+cmp "$final" "$case_root/previous"
+cmp "$marker" "$case_root/previous-marker"
+no_debris
+fixture transport
+export FAKE_CURL_MODE=transport
+reject 75 install_tool cargo-binstall
+export FAKE_CURL_MODE=interrupt
+reject any install_tool cargo-binstall
+test ! -e "$OLIPHAUNT_MAINTAINER_BIN_DIR/cargo-binstall"
+no_debris
+fixture fallback
+export FAKE_CURL_MODE=transport OLIPHAUNT_BOOTSTRAP_CARGO_BINSTALL_ONLY=1
+bash tools/dev/bootstrap-tools.sh
+grep -Eq '^install cargo-binstall --version 1.19.1 --locked --root /' "$FAKE_CARGO_LOG"
+cmp "$OLIPHAUNT_MAINTAINER_BIN_DIR/cargo-binstall" "$scratch/source/cargo-binstall"
+grep -q 'source=locked-cargo-install' "$OLIPHAUNT_MAINTAINER_BIN_DIR/.cargo-binstall.oliphaunt-source"
+cp "$FAKE_CURL_LOG" "$case_root/first.log"
+install_tool cargo-binstall
+cmp "$FAKE_CURL_LOG" "$case_root/first.log"
+no_debris
+for mode in http oversized checksum; do
+  fixture "fallback-$mode"
+  export FAKE_CURL_MODE="$mode"
+  if [ "$mode" = checksum ]; then export FAKE_CURL_MODE=success FAKE_CURL_SOURCE="$scratch/checksum.tgz"; fi
+  reject any bash tools/dev/bootstrap-tools.sh
+  test ! -e "$FAKE_CARGO_LOG"
+  no_debris
+done
+fixture fallback-failure
+printf old > "$OLIPHAUNT_MAINTAINER_BIN_DIR/cargo-binstall"
+printf marker > "$OLIPHAUNT_MAINTAINER_BIN_DIR/.cargo-binstall.oliphaunt-source"
+export FAKE_CURL_MODE=transport FAKE_CARGO_MODE=fail
+reject any bash tools/dev/bootstrap-tools.sh
+test "$(cat "$OLIPHAUNT_MAINTAINER_BIN_DIR/cargo-binstall")" = old
+test "$(cat "$OLIPHAUNT_MAINTAINER_BIN_DIR/.cargo-binstall.oliphaunt-source")" = marker
+no_debris
+fixture action
+export FAKE_CURL_SOURCE="$scratch/action.tgz"
+install_tool actionlint
+cmp "$OLIPHAUNT_MAINTAINER_BIN_DIR/actionlint" "$scratch/action/actionlint"
+printf '# refresh\n' >> "$OLIPHAUNT_MAINTAINER_BIN_DIR/actionlint"
+cp "$OLIPHAUNT_MAINTAINER_BIN_DIR/actionlint" "$case_root/previous"
+for action_archive in "$scratch/action-link.tgz" "$scratch/action-duplicate.tgz"; do
+  manifest
+  export FAKE_CURL_SOURCE="$action_archive"
+  reject any install_tool actionlint
+  cmp "$OLIPHAUNT_MAINTAINER_BIN_DIR/actionlint" "$case_root/previous"
+  no_debris
+done
+fixture action-transport
+export FAKE_CURL_MODE=transport
+reject 75 bash tools/dev/install-actionlint.sh
+test ! -e "$FAKE_GO_LOG"
+no_debris
+fixture unsupported
+export FAKE_UNAME_OS=FreeBSD
+reject 69 install_tool cargo-binstall
+test ! -e "$FAKE_CURL_LOG"
+no_debris
+echo 'Maintainer tool integrity, cache repair, rollback and pinned fallback checks passed'
diff --git a/src/sources/toolchains/maintainer-tools.toml b/tools/dev/maintainer-tools.toml
similarity index 96%
rename from src/sources/toolchains/maintainer-tools.toml
rename to tools/dev/maintainer-tools.toml
index 72fe73c1d..60a2301fc 100644
--- a/src/sources/toolchains/maintainer-tools.toml
+++ b/tools/dev/maintainer-tools.toml
@@ -10,7 +10,6 @@ sha256 = "bf9da6a27e432784f361cfbc70a6d04e548abc548470ae9a7587c3cffb8fb0a7"
 binary_sha256 = "5ef3a5d5287bb89c6158ea11b87ae51463d2c3a001d8f0c3d558fc46a8a396ce"
 format = "zip"
 binary_path = "cargo-binstall"
-entry_count = "1"
 max_archive_bytes = "16777216"
 max_binary_bytes = "33554432"
 
@@ -20,7 +19,6 @@ sha256 = "39257851fe4fd8cc9dd81fb318f15d589b7178b74165879eddeda8062bd9fcf2"
 binary_sha256 = "7af1e1ce18848e9d7b8a4306836964b3f65717f32b090e384f20fec8e808d6eb"
 format = "zip"
 binary_path = "cargo-binstall"
-entry_count = "1"
 max_archive_bytes = "16777216"
 max_binary_bytes = "33554432"
 
@@ -30,7 +28,6 @@ sha256 = "2001eee8da26705ad9627e57a25c23eb4639647521205f3e4a7b4e09d067d199"
 binary_sha256 = "c257882fc98d2af05d063c8335f0c95cd17c0617d2ca705d9e3c235b65b54ed0"
 format = "tgz"
 binary_path = "cargo-binstall"
-entry_count = "1"
 max_archive_bytes = "16777216"
 max_binary_bytes = "33554432"
 
@@ -40,7 +37,6 @@ sha256 = "4a50fcf01418862e2fa8e4076cb6cb80ff4061b0c0b1464e71a63ce01ee29bde"
 binary_sha256 = "e231f8fefaa40c70ae5d0236babb9a36d10c2c9e62de65a1d87e2fd56ceb55c7"
 format = "tgz"
 binary_path = "cargo-binstall"
-entry_count = "1"
 max_archive_bytes = "16777216"
 max_binary_bytes = "33554432"
 
@@ -56,7 +52,6 @@ sha256 = "5b44c3bc2255115c9b69e30efc0fecdf498fdb63c5d58e17084fd5f16324c644"
 binary_sha256 = "d1f7cee75ae2873609bd9567b4600bebc5315a5e733e73202987a44fafdd53b2"
 format = "tgz"
 binary_path = "actionlint"
-entry_count = "11"
 max_archive_bytes = "8388608"
 max_binary_bytes = "16777216"
 
@@ -66,7 +61,6 @@ sha256 = "aba9ced2dee8d27fecca3dc7feb1a7f9a52caefa1eb46f3271ea66b6e0e6953f"
 binary_sha256 = "8db11704dc296f096216db4db65d86cd7f0ebfdf4c38453a1da276b137b88388"
 format = "tgz"
 binary_path = "actionlint"
-entry_count = "11"
 max_archive_bytes = "8388608"
 max_binary_bytes = "16777216"
 
@@ -76,7 +70,6 @@ sha256 = "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8"
 binary_sha256 = "c872d6db8c6bf83a8eaa704fc93999f027d55dffbc63b8a6abdccb47df5f4cd4"
 format = "tgz"
 binary_path = "actionlint"
-entry_count = "11"
 max_archive_bytes = "8388608"
 max_binary_bytes = "16777216"
 
@@ -86,6 +79,5 @@ sha256 = "325e971b6ba9bfa504672e29be93c24981eeb1c07576d730e9f7c8805afff0c6"
 binary_sha256 = "ac0323433c2853ec3fb978c611430c5b3dc5d43c58d1a1ec031b00ab572beb60"
 format = "tgz"
 binary_path = "actionlint"
-entry_count = "11"
 max_archive_bytes = "8388608"
 max_binary_bytes = "16777216"
diff --git a/src/sources/toolchains/moon-cli.toml b/tools/dev/moon-cli.toml
similarity index 98%
rename from src/sources/toolchains/moon-cli.toml
rename to tools/dev/moon-cli.toml
index 108182be5..7196e5657 100644
--- a/src/sources/toolchains/moon-cli.toml
+++ b/tools/dev/moon-cli.toml
@@ -1,6 +1,3 @@
-[toolchain]
-version = "2.5.4"
-
 [assets.aarch64-apple-darwin]
 url = "https://github.com/moonrepo/moon/releases/download/v2.5.4/moon_cli-aarch64-apple-darwin.tar.xz"
 sha256 = "c4e0f41f43f80533be4120917858ca68e1d65063375de0088882342e45366867"
diff --git a/tools/dev/moon-command.mjs b/tools/dev/moon-command.mjs
deleted file mode 100644
index 55a5ac43f..000000000
--- a/tools/dev/moon-command.mjs
+++ /dev/null
@@ -1,41 +0,0 @@
-import { spawnSync } from "node:child_process";
-import { readFileSync } from "node:fs";
-
-const PROTOTOOLS = new URL("../../.prototools", import.meta.url);
-const PINNED_VERSION = readFileSync(PROTOTOOLS, "utf8").match(/^moon\s*=\s*"([^"]+)"/mu)?.[1];
-const VERIFIED = new Set();
-
-if (!PINNED_VERSION) throw new Error(".prototools does not pin Moon");
-
-function cleanEnvironment(environment) {
-  const clean = { ...environment };
-  for (const name of Object.keys(clean)) {
-    if (name.startsWith("PROTO_")) delete clean[name];
-  }
-  return clean;
-}
-
-/** Resolve and verify the repository-pinned Moon executable once per process. */
-export function moonCommand(environment = process.env) {
-  const command = environment.MOON_BIN || "moon";
-  const key = `${command}\0${environment.PATH ?? ""}`;
-  if (VERIFIED.has(key)) return command;
-
-  const result = spawnSync(command, ["--version"], {
-    encoding: "utf8",
-    env: cleanEnvironment(environment),
-  });
-  if (result.error) {
-    throw new Error(`Moon ${PINNED_VERSION} is required, but ${command} failed to start: ${result.error.message}`);
-  }
-  const actual = result.stdout.trim().match(/^moon\s+([^\s]+)$/u)?.[1];
-  if (result.status !== 0 || actual !== PINNED_VERSION) {
-    throw new Error(`Moon ${PINNED_VERSION} is required, but ${command} reported ${actual ?? "an invalid version"}`);
-  }
-  VERIFIED.add(key);
-  return command;
-}
-
-export function moonEnvironment(environment = process.env) {
-  return cleanEnvironment(environment);
-}
diff --git a/tools/dev/moon-plugins.toml b/tools/dev/moon-plugins.toml
new file mode 100644
index 000000000..ba32e48b5
--- /dev/null
+++ b/tools/dev/moon-plugins.toml
@@ -0,0 +1,35 @@
+[plugins.javascript]
+locator = "registry://ghcr.io/moonrepo/javascript_toolchain@sha256:81c26ebeae43fb130ad3ce0411cbdfd3bc4aa9d5e488e25b43a08fda5e790176"
+repository = "moonrepo/javascript_toolchain"
+manifest_sha256 = "81c26ebeae43fb130ad3ce0411cbdfd3bc4aa9d5e488e25b43a08fda5e790176"
+manifest_bytes = "1538"
+blob_sha256 = "ef177cc41b6a0f5ded27c5c8db22fe790e6855ec6623d3089bf0170ae45e38ac"
+bytes = "2697259"
+cache_file = "javascript-b20b528033f296e32c44c64032920820e365f623e7d7a28566cacf1593fe7466.wasm"
+
+[plugins.node]
+locator = "registry://ghcr.io/moonrepo/node_toolchain@sha256:1ac2fab8bf5297bea9361132612b0dd70c63a9482606d06c15e48704643934ec"
+repository = "moonrepo/node_toolchain"
+manifest_sha256 = "1ac2fab8bf5297bea9361132612b0dd70c63a9482606d06c15e48704643934ec"
+manifest_bytes = "1510"
+blob_sha256 = "32f52daa73eaf736c02570856dc851ca3d75c8f43b62b53ff24e5b5a068f92ef"
+bytes = "1949761"
+cache_file = "node-0d616ca34b325e12df839c8bfbb0499c961a166416ea3d14fce1a78856fa8e8e.wasm"
+
+[plugins.bun]
+locator = "registry://ghcr.io/moonrepo/bun_toolchain@sha256:d19bd0a3c223c8dcbcb7db71492761bc55fa799120f935289a788cb4c3c2128b"
+repository = "moonrepo/bun_toolchain"
+manifest_sha256 = "d19bd0a3c223c8dcbcb7db71492761bc55fa799120f935289a788cb4c3c2128b"
+manifest_bytes = "1503"
+blob_sha256 = "693b40a32a2c0f1d29bc1e19687bd3c16e0f900f5acb0704705ffcc6f0f399e1"
+bytes = "1892172"
+cache_file = "bun-6db71c2c6ffc9107da02083dfc21caae0fbbb29fb40d419bed15f945caec6471.wasm"
+
+[plugins.rust]
+locator = "registry://ghcr.io/moonrepo/rust_toolchain@sha256:477b97a7c5f1c98321c43c8a63b4921fa54ee884d49b1b25b9644de5c0e6209e"
+repository = "moonrepo/rust_toolchain"
+manifest_sha256 = "477b97a7c5f1c98321c43c8a63b4921fa54ee884d49b1b25b9644de5c0e6209e"
+manifest_bytes = "1508"
+blob_sha256 = "29ae28f8191c6dabea0ece7d08fa0b142037aaa82a8f51902a044a9237598eae"
+bytes = "2907144"
+cache_file = "rust-a38daa0f782261e4a1ab262f4b39185346b459447e426b89e2c109de71574521.wasm"
diff --git a/tools/dev/moon.yml b/tools/dev/moon.yml
index 2ce423b06..a15558536 100644
--- a/tools/dev/moon.yml
+++ b/tools/dev/moon.yml
@@ -1,32 +1,66 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "dev-tools"
-language: "bash"
-layer: "tool"
-stack: "infrastructure"
-tags: ["tools", "developer-experience"]
-
+$schema: https://moonrepo.dev/schemas/project.json
+id: dev-tools
+language: bash
+layer: tool
+stack: infrastructure
+tags:
+  - javascript-quality
+  - tools
+  - developer-experience
 project:
-  title: "Developer Tools"
-  description: "Local bootstrap, doctor, hook installation, and smoke helpers."
-  owner: "oliphaunt"
-
+  title: Developer Tools
+  description: "Local bootstrap, hook installation, and smoke helpers."
+  owner: oliphaunt
 owners:
   defaultOwner: "@oliphaunt/core"
   paths:
-    "**/*": ["@oliphaunt/core"]
-
+    "**/*":
+      - "@oliphaunt/core"
 tasks:
-  doctor:
-    tags: ["diagnostics", "developer-experience"]
-    command: "bash tools/dev/doctor.sh"
+  test-mobile-setup:
+    tags:
+      - quality
+      - unit
+    script: "set -e\nbash tools/dev/setup-android-sdk.test.sh\nbash tools/dev/setup-maestro.test.sh\n"
     inputs:
-      - "/.moon/workspace.yml"
-      - "/.moon/toolchains.yml"
-      - "/.prototools"
-      - "/package.json"
-      - "/pnpm-lock.yaml"
-      - "**/*"
+      - setup-android-sdk*
+      - setup-maestro*
+      - extract-maestro.mts
+      - bun.sh
+      - node-info.mts
+      - extract-pinned-zip.*
+      - /tools/packaging/testdata/zip-fixture.mts
+      - /tools/packaging/portable-archive.mts
+      - "/tools/dev/{android-sdk,maestro}.toml"
+    options:
+      runFromWorkspaceRoot: true
+  test:
+    tags:
+      - quality
+      - unit
+    script: "set -eu\nfor test in tools/dev/extract-pinned-zip.test.sh tools/dev/install-pinned-js-runtime.test.sh tools/dev/install-pinned-winflexbison.test.sh .github/actions/setup-moon/install-pinned-node.test.sh .github/actions/setup-moon/install-pinned-toolchain.test.sh .github/actions/setup-npm-publisher/install.test.sh .github/scripts/setup-native-build-tools.test.sh; do\n  bash \"$test\"\ndone\nbash tools/dev/maintainer-tool-install.test.sh\n"
+    inputs:
+      - install-pinned*
+      - install-actionlint.sh
+      - bootstrap-tools.sh
+      - maintainer-tool-install.test.sh
+      - extract-pinned*
+      - winflexbison-identity.mts
+      - bun.sh
+      - node-info.mts
+      - curl-platform-flags.sh
+      - /.prototools
+      - /.moon/toolchains.yml
+      - /.github/actions/setup-moon/**
+      - /.github/actions/setup-node-bun/**
+      - /.github/actions/setup-node-runtime/**
+      - /.github/actions/setup-npm-publisher/**
+      - /.github/scripts/setup-native-build-tools*
+      - "/tools/dev/{bun,deno,moon-cli,moon-plugins,node-runtime,proto,winflexbison}.toml"
+      - /tools/release/npm-publisher.toml
+      - /tools/dev/maintainer-tools.toml
+      - /tools/packaging/portable-archive.mts
+      - "/tools/packaging/testdata/{zip,tar}-fixture.mts"
+      - /.github/actions/setup-npm-publisher/testdata/package-manager-fixture.mts
     options:
-      cache: false
       runFromWorkspaceRoot: true
diff --git a/tools/dev/node-info.mts b/tools/dev/node-info.mts
new file mode 100644
index 000000000..ffb77847a
--- /dev/null
+++ b/tools/dev/node-info.mts
@@ -0,0 +1,9 @@
+import { readFileSync } from 'node:fs';
+
+const [field, file] = process.argv.slice(2);
+const value =
+  field === 'package-version'
+    ? JSON.parse(readFileSync(file, 'utf8')).version
+    : { executable: process.execPath, platform: process.platform, arch: process.arch }[field];
+if (typeof value !== 'string' || value.length === 0) throw new Error(`missing Node info: ${field}`);
+process.stdout.write(value);
diff --git a/src/sources/toolchains/node-runtime.toml b/tools/dev/node-runtime.toml
similarity index 98%
rename from src/sources/toolchains/node-runtime.toml
rename to tools/dev/node-runtime.toml
index 74395b5d1..7252c1a2f 100644
--- a/src/sources/toolchains/node-runtime.toml
+++ b/tools/dev/node-runtime.toml
@@ -1,6 +1,3 @@
-[toolchain]
-version = "22.22.3"
-
 [assets.aarch64-apple-darwin]
 url = "https://nodejs.org/download/release/v22.22.3/node-v22.22.3-darwin-arm64.tar.gz"
 sha256 = "0da7ff74ef8611328c8212f17943368713a2ad953fb7d89a8c8a0eae87c23207"
diff --git a/src/sources/toolchains/proto.toml b/tools/dev/proto.toml
similarity index 100%
rename from src/sources/toolchains/proto.toml
rename to tools/dev/proto.toml
diff --git a/tools/dev/setup-android-sdk.sh b/tools/dev/setup-android-sdk.sh
index b3f6173b3..e83ecec7e 100755
--- a/tools/dev/setup-android-sdk.sh
+++ b/tools/dev/setup-android-sdk.sh
@@ -25,7 +25,7 @@ Options:
   -h, --help                 Show this help.
 
 The command-line-tools URLs and SHA-256 checksums are intentionally not
-overridable. Update src/sources/toolchains/android-sdk.toml to change them.
+overridable. Update tools/dev/android-sdk.toml to change them.
 EOF
 }
 
@@ -33,7 +33,7 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)" ||
   fail "must run inside the Oliphaunt git checkout"
 cd "$root"
 
-manifest="${OLIPHAUNT_ANDROID_TOOLCHAIN_MANIFEST:-$root/src/sources/toolchains/android-sdk.toml}"
+manifest="${OLIPHAUNT_ANDROID_TOOLCHAIN_MANIFEST:-$root/tools/dev/android-sdk.toml}"
 extractor="${OLIPHAUNT_ANDROID_ZIP_EXTRACTOR:-$root/tools/dev/extract-pinned-zip.sh}"
 curl_bin="${OLIPHAUNT_ANDROID_CURL:-curl}"
 [ -f "$manifest" ] || fail "missing Android toolchain manifest: $manifest"
diff --git a/tools/dev/setup-android-sdk.test.sh b/tools/dev/setup-android-sdk.test.sh
index 80c84ed73..f89784513 100755
--- a/tools/dev/setup-android-sdk.test.sh
+++ b/tools/dev/setup-android-sdk.test.sh
@@ -7,171 +7,39 @@ extractor="$root/tools/dev/extract-pinned-zip.sh"
 tmp="$(mktemp -d)"
 trap 'rm -rf "$tmp"' EXIT HUP INT TERM
 
-python_bin=""
-for candidate in python3 python; do
-  if command -v "$candidate" >/dev/null 2>&1 &&
-    "$candidate" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 8) else 1)'; then
-    python_bin="$candidate"
-    break
-  fi
-done
-[ -n "$python_bin" ] || {
-  echo "Python 3.8 or newer is required" >&2
-  exit 1
-}
 
 mkdir -p "$tmp/fixtures" "$tmp/config" "$tmp/bin" "$tmp/home"
-"$python_bin" - "$tmp" <<'PY'
-import hashlib
-import stat
-import sys
-import zipfile
-from pathlib import Path
-
-root = Path(sys.argv[1])
-fixtures = root / "fixtures"
-config = root / "config"
-
-def sdkmanager(version):
-    return f'''#!/usr/bin/env bash
-set -euo pipefail
-sdk_root=""
-operation=""
-packages=()
-for argument in "$@"; do
-  case "$argument" in
-    --sdk_root=*) sdk_root="${{argument#--sdk_root=}}" ;;
-    --version) operation=version ;;
-    --licenses) operation=licenses ;;
-    --install) operation=install ;;
-    *) packages+=("$argument") ;;
-  esac
-done
-[ -n "$sdk_root" ]
-case "$operation" in
-  version)
-    printf '{version}\\n'
-    ;;
-  licenses)
-    exit 0
-    ;;
-  install)
-    expected=(
-      platform-tools
-      'platforms;android-36'
-      'build-tools;36.0.0'
-      'cmake;3.22.1'
-      'ndk;27.0.12077973'
-    )
-    [ "${{#packages[@]}}" = "${{#expected[@]}}" ]
-    for index in "${{!expected[@]}}"; do
-      [ "${{packages[$index]}}" = "${{expected[$index]}}" ]
-    done
-    mkdir -p \
-      "$sdk_root/platform-tools" \
-      "$sdk_root/platforms/android-36" \
-      "$sdk_root/build-tools/36.0.0" \
-      "$sdk_root/cmake/3.22.1/bin" \
-      "$sdk_root/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin"
-    printf '%s\\n' '#!/bin/sh' 'exit 0' > "$sdk_root/platform-tools/adb"
-    chmod +x "$sdk_root/platform-tools/adb"
-    printf 'AndroidVersion.ApiLevel=36\\n' > "$sdk_root/platforms/android-36/source.properties"
-    printf 'fake-android-jar\\n' > "$sdk_root/platforms/android-36/android.jar"
-    printf 'Pkg.Revision=36.0.0\\n' > "$sdk_root/build-tools/36.0.0/source.properties"
-    printf '%s\\n' '#!/bin/sh' 'exit 0' > "$sdk_root/build-tools/36.0.0/aapt2"
-    printf '%s\\n' '#!/bin/sh' 'exit 0' > "$sdk_root/build-tools/36.0.0/zipalign"
-    printf '%s\\n' '#!/bin/sh' 'exit 0' > "$sdk_root/build-tools/36.0.0/apksigner"
-    chmod +x \
-      "$sdk_root/build-tools/36.0.0/aapt2" \
-      "$sdk_root/build-tools/36.0.0/zipalign" \
-      "$sdk_root/build-tools/36.0.0/apksigner"
-    printf 'Pkg.Revision = 3.22.1\\n' > "$sdk_root/cmake/3.22.1/source.properties"
-    printf '%s\\n' '#!/bin/sh' 'exit 0' > "$sdk_root/cmake/3.22.1/bin/cmake"
-    chmod +x "$sdk_root/cmake/3.22.1/bin/cmake"
-    printf 'Pkg.Revision = 27.0.12077973\\n' > "$sdk_root/ndk/27.0.12077973/source.properties"
-    printf '%s\\n' '#!/bin/sh' 'exit 0' > "$sdk_root/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/clang"
-    chmod +x "$sdk_root/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/clang"
-    count=0
-    [ ! -f "$sdk_root/fake-install-count" ] || count="$(cat "$sdk_root/fake-install-count")"
-    printf '%s\\n' "$((count + 1))" > "$sdk_root/fake-install-count"
-    ;;
-  *)
-    exit 2
-    ;;
-esac
-'''.encode()
-
-def avdmanager():
-    return b'''#!/usr/bin/env bash
-set -euo pipefail
-exit 0
-'''
-
-def apkanalyzer():
-    return b'''#!/usr/bin/env bash
-set -euo pipefail
-exit 0
-'''
-
-def write_archive(name, version, layout="cmdline-tools"):
-    path = fixtures / name
-    entries = {
-        f"{layout}/bin/sdkmanager": sdkmanager(version),
-        f"{layout}/bin/avdmanager": avdmanager(),
-        f"{layout}/bin/apkanalyzer": apkanalyzer(),
-        f"{layout}/source.properties": b"Pkg.Revision=20.0\n",
-        f"{layout}/lib/sdkmanager-classpath.jar": b"fake-classpath\n",
-    }
-    with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as archive:
-        for member, contents in entries.items():
-            info = zipfile.ZipInfo(member)
-            info.compress_type = zipfile.ZIP_DEFLATED
-            info.external_attr = (
-                stat.S_IFREG
-                | (0o755 if member.endswith(("sdkmanager", "avdmanager", "apkanalyzer")) else 0o644)
-            ) << 16
-            archive.writestr(info, contents)
-    return hashlib.sha256(path.read_bytes()).hexdigest()
-
-good_sha = write_archive("android.zip", "20.0")
-wrong_version_sha = write_archive("android-wrong-version.zip", "19.0")
-wrong_layout_sha = write_archive("android-wrong-layout.zip", "20.0", "not-cmdline-tools")
-
-def manifest(name, digest):
-    (config / name).write_text(f'''[packages]
-command_line_tools_build = "14742923"
-command_line_tools_revision = "20.0"
-ndk = "27.0.12077973"
-cmake = "3.22.1"
-compile_sdk = "36"
-build_tools = "36.0.0"
-
-[command_line_tools.linux]
-url = "https://dl.google.com/android/repository/commandlinetools-linux-14742923_latest.zip"
-mirror_url = "https://edgedl.me.gvt1.com/edgedl/android/repository/commandlinetools-linux-14742923_latest.zip"
-sha256 = "{digest}"
-entry_count = "5"
-
-[command_line_tools.mac]
-url = "https://dl.google.com/android/repository/commandlinetools-mac-14742923_latest.zip"
-mirror_url = "https://edgedl.me.gvt1.com/edgedl/android/repository/commandlinetools-mac-14742923_latest.zip"
-sha256 = "{digest}"
-entry_count = "5"
-''', encoding="utf-8")
-
-manifest("android.toml", good_sha)
-manifest("android-bad-sha.toml", "0" * 64)
-manifest("android-wrong-version.toml", wrong_version_sha)
-manifest("android-wrong-layout.toml", wrong_layout_sha)
-PY
+bash "$root/tools/dev/bun.sh" - "$tmp" <<'TS'
+import {createHash} from 'node:crypto';
+import {writeFileSync} from 'node:fs';
+import {zipArchive} from './tools/packaging/testdata/zip-fixture.mts';
+const root = process.argv[2];
+const sha = data => createHash('sha256').update(data).digest('hex');
+const write = (name, data) => writeFileSync(root + '/' + name, data);
+
+function archive(name, version, layout = 'cmdline-tools') {
+  const entries = {
+    [layout + '/bin/sdkmanager']: "#!/usr/bin/env bash\nset -euo pipefail\nsdk_root=\"\"\noperation=\"\"\npackages=()\nfor argument in \"$@\"; do\n  case \"$argument\" in\n    --sdk_root=*) sdk_root=\"${argument#--sdk_root=}\" ;;\n    --version) operation=version ;;\n    --licenses) operation=licenses ;;\n    --install) operation=install ;;\n    *) packages+=(\"$argument\") ;;\n  esac\ndone\n[ -n \"$sdk_root\" ]\ncase \"$operation\" in\n  version)\n    printf '{version}\\n'\n    ;;\n  licenses)\n    exit 0\n    ;;\n  install)\n    expected=(\n      platform-tools\n      'platforms;android-36'\n      'build-tools;36.0.0'\n      'cmake;3.22.1'\n      'ndk;27.0.12077973'\n    )\n    [ \"${#packages[@]}\" = \"${#expected[@]}\" ]\n    for index in \"${!expected[@]}\"; do\n      [ \"${packages[$index]}\" = \"${expected[$index]}\" ]\n    done\n    mkdir -p \\\n      \"$sdk_root/platform-tools\" \\\n      \"$sdk_root/platforms/android-36\" \\\n      \"$sdk_root/build-tools/36.0.0\" \\\n      \"$sdk_root/cmake/3.22.1/bin\" \\\n      \"$sdk_root/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin\"\n    printf '%s\\n' '#!/bin/sh' 'exit 0' > \"$sdk_root/platform-tools/adb\"\n    chmod +x \"$sdk_root/platform-tools/adb\"\n    printf 'AndroidVersion.ApiLevel=36\\n' > \"$sdk_root/platforms/android-36/source.properties\"\n    printf 'fake-android-jar\\n' > \"$sdk_root/platforms/android-36/android.jar\"\n    printf 'Pkg.Revision=36.0.0\\n' > \"$sdk_root/build-tools/36.0.0/source.properties\"\n    printf '%s\\n' '#!/bin/sh' 'exit 0' > \"$sdk_root/build-tools/36.0.0/aapt2\"\n    printf '%s\\n' '#!/bin/sh' 'exit 0' > \"$sdk_root/build-tools/36.0.0/zipalign\"\n    printf '%s\\n' '#!/bin/sh' 'exit 0' > \"$sdk_root/build-tools/36.0.0/apksigner\"\n    chmod +x \\\n      \"$sdk_root/build-tools/36.0.0/aapt2\" \\\n      \"$sdk_root/build-tools/36.0.0/zipalign\" \\\n      \"$sdk_root/build-tools/36.0.0/apksigner\"\n    printf 'Pkg.Revision = 3.22.1\\n' > \"$sdk_root/cmake/3.22.1/source.properties\"\n    printf '%s\\n' '#!/bin/sh' 'exit 0' > \"$sdk_root/cmake/3.22.1/bin/cmake\"\n    chmod +x \"$sdk_root/cmake/3.22.1/bin/cmake\"\n    printf 'Pkg.Revision = 27.0.12077973\\n' > \"$sdk_root/ndk/27.0.12077973/source.properties\"\n    printf '%s\\n' '#!/bin/sh' 'exit 0' > \"$sdk_root/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/clang\"\n    chmod +x \"$sdk_root/ndk/27.0.12077973/toolchains/llvm/prebuilt/linux-x86_64/bin/clang\"\n    count=0\n    [ ! -f \"$sdk_root/fake-install-count\" ] || count=\"$(cat \"$sdk_root/fake-install-count\")\"\n    printf '%s\\n' \"$((count + 1))\" > \"$sdk_root/fake-install-count\"\n    ;;\n  *)\n    exit 2\n    ;;\nesac\n".replace('{version}', version),
+    [layout + '/bin/avdmanager']: '#!/usr/bin/env bash\nset -euo pipefail\nexit 0\n',
+    [layout + '/bin/apkanalyzer']: '#!/usr/bin/env bash\nset -euo pipefail\nexit 0\n',
+    [layout + '/source.properties']: 'Pkg.Revision=20.0\n',
+    [layout + '/lib/sdkmanager-classpath.jar']: 'fake-classpath\n',
+  };
+  const bytes = zipArchive(Object.entries(entries).map(([name,data]) => ({name,data,method: 8,externalAttributes: (name.includes('/bin/') ? 0o100755 : 0o100644) << 16})));
+  write('fixtures/' + name, bytes);
+  return sha(bytes);
+}
+for (const [name, digest] of [
+  ['android.toml', archive('android.zip','20.0')],
+  ['android-bad-sha.toml','0'.repeat(64)],
+  ['android-wrong-version.toml',archive('android-wrong-version.zip','19.0')],
+  ['android-wrong-layout.toml',archive('android-wrong-layout.zip','20.0','not-cmdline-tools')],
+]) write('config/' + name, "[packages]\ncommand_line_tools_build = \"14742923\"\ncommand_line_tools_revision = \"20.0\"\nndk = \"27.0.12077973\"\ncmake = \"3.22.1\"\ncompile_sdk = \"36\"\nbuild_tools = \"36.0.0\"\n\n[command_line_tools.linux]\nurl = \"https://dl.google.com/android/repository/commandlinetools-linux-14742923_latest.zip\"\nmirror_url = \"https://edgedl.me.gvt1.com/edgedl/android/repository/commandlinetools-linux-14742923_latest.zip\"\nsha256 = \"{digest}\"\nentry_count = \"5\"\n\n[command_line_tools.mac]\nurl = \"https://dl.google.com/android/repository/commandlinetools-mac-14742923_latest.zip\"\nmirror_url = \"https://edgedl.me.gvt1.com/edgedl/android/repository/commandlinetools-mac-14742923_latest.zip\"\nsha256 = \"{digest}\"\nentry_count = \"5\"\n".replaceAll('{digest}', digest));
 
-"$python_bin" - "$tmp/bin/curl" <<'PY'
-import stat
-import sys
-from pathlib import Path
+TS
 
-path = Path(sys.argv[1])
-path.write_text(r'''#!/usr/bin/env bash
+cat >"$tmp/bin/curl" <<'SH'
+#!/usr/bin/env bash
 set -euo pipefail
 output=""
 url=""
@@ -205,9 +73,8 @@ case "$CURL_MODE" in
     exit 2
     ;;
 esac
-''', encoding="utf-8")
-path.chmod(stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
-PY
+SH
+chmod 0700 "$tmp/bin/curl"
 
 common_env=(
   "HOME=$tmp/home"
diff --git a/tools/dev/setup-maestro.sh b/tools/dev/setup-maestro.sh
index e3996c99a..c722e0ab9 100755
--- a/tools/dev/setup-maestro.sh
+++ b/tools/dev/setup-maestro.sh
@@ -17,12 +17,11 @@ need_cmd() {
 need_cmd curl
 need_cmd java
 need_cmd mktemp
-need_cmd python3
 
 export MAESTRO_CLI_NO_ANALYTICS=true
 export MAESTRO_CLI_ANALYSIS_NOTIFICATION_DISABLED=true
 maestro_bin="$HOME/.maestro/bin/maestro"
-maestro_manifest="src/sources/toolchains/maestro.toml"
+maestro_manifest="tools/dev/maestro.toml"
 
 manifest_value() {
   local key="$1"
@@ -145,64 +144,7 @@ if [ "$actual_sha256" != "$maestro_sha256" ]; then
   exit 1
 fi
 
-python3 - "$archive" "$extract_root" "$normalized_version" <<'PY'
-import stat
-import sys
-import zipfile
-from pathlib import Path
-
-archive_path = Path(sys.argv[1])
-extract_root = Path(sys.argv[2])
-version = sys.argv[3]
-required = {
-    "maestro/bin/maestro",
-    f"maestro/lib/maestro-cli-{version}.jar",
-}
-seen = set()
-
-try:
-    with zipfile.ZipFile(archive_path) as archive:
-        entries = archive.infolist()
-        if not entries or len(entries) > 4096:
-            raise ValueError(f"unexpected entry count: {len(entries)}")
-        expanded_size = sum(entry.file_size for entry in entries)
-        if expanded_size > 800_000_000:
-            raise ValueError(f"expanded archive is too large: {expanded_size} bytes")
-
-        for entry in entries:
-            name = entry.filename
-            if not name or "\\" in name or "\x00" in name:
-                raise ValueError(f"unsafe archive path: {name!r}")
-            trimmed = name[:-1] if name.endswith("/") else name
-            parts = trimmed.split("/")
-            if (
-                not trimmed
-                or name.startswith("/")
-                or any(part in {"", ".", ".."} for part in parts)
-                or parts[0] != "maestro"
-            ):
-                raise ValueError(f"unsafe archive path: {name!r}")
-            canonical = "/".join(parts)
-            if canonical in seen:
-                raise ValueError(f"duplicate archive path: {canonical}")
-            seen.add(canonical)
-            if entry.flag_bits & 0x1:
-                raise ValueError(f"encrypted archive entry: {name}")
-            mode = (entry.external_attr >> 16) & 0xFFFF
-            file_type = stat.S_IFMT(mode)
-            if file_type not in {0, stat.S_IFREG, stat.S_IFDIR}:
-                raise ValueError(f"unsupported archive entry type: {name}")
-
-        missing = sorted(required - seen)
-        if missing:
-            raise ValueError(f"missing expected archive entries: {', '.join(missing)}")
-        corrupt = archive.testzip()
-        if corrupt is not None:
-            raise ValueError(f"archive CRC validation failed at {corrupt}")
-        archive.extractall(extract_root)
-except (OSError, ValueError, zipfile.BadZipFile) as error:
-    raise SystemExit(f"invalid Maestro archive: {error}")
-PY
+bash tools/dev/bun.sh tools/dev/extract-maestro.mts "$archive" "$extract_root" "$normalized_version"
 
 candidate_root="$extract_root/maestro"
 candidate_bin="$candidate_root/bin/maestro"
diff --git a/tools/dev/setup-maestro.test.sh b/tools/dev/setup-maestro.test.sh
index aef7659d4..0ec1e810c 100755
--- a/tools/dev/setup-maestro.test.sh
+++ b/tools/dev/setup-maestro.test.sh
@@ -3,7 +3,7 @@ set -euo pipefail
 
 root="$(git rev-parse --show-toplevel)"
 installer="$root/tools/dev/setup-maestro.sh"
-manifest="$root/src/sources/toolchains/maestro.toml"
+manifest="$root/tools/dev/maestro.toml"
 configured_version="$(sed -n 's/^[[:space:]]*maestro[[:space:]]*=[[:space:]]*"\([^"]*\)"[[:space:]]*$/\1/p' "$manifest")"
 expected_version="${configured_version#cli-}"
 expected_sha256="$(sed -n 's/^[[:space:]]*sha256[[:space:]]*=[[:space:]]*"\([^"]*\)"[[:space:]]*$/\1/p' "$manifest")"
@@ -88,17 +88,19 @@ fi
 exec /bin/mv "$@"
 SH
 
+pinned_bun="$(bash "$root/tools/dev/bun.sh" "$root/tools/dev/node-info.mts" executable)"
+ln -s "$pinned_bun" "$fake_bin/bun"
 chmod 0755 "$fake_bin"/*
 
 fallback_bin="$test_root/fallback-bin"
 no_hash_bin="$test_root/no-hash-bin"
 mkdir -p "$fallback_bin" "$no_hash_bin"
-for command_name in bash git grep sed tr awk mkdir mktemp python3 chmod rm cp cat; do
+for command_name in bash git grep sed tr awk mkdir mktemp dirname chmod rm cp cat; do
   command_path="$(command -v "$command_name")"
   ln -s "$command_path" "$fallback_bin/$command_name"
   ln -s "$command_path" "$no_hash_bin/$command_name"
 done
-for helper in curl java maestro mv; do
+for helper in bun curl java maestro mv; do
   cp "$fake_bin/$helper" "$fallback_bin/$helper"
   cp "$fake_bin/$helper" "$no_hash_bin/$helper"
 done
@@ -108,40 +110,15 @@ make_archive() {
   local output="$1"
   local launcher_version="$2"
   local shape="$3"
-  python3 - "$output" "$launcher_version" "$shape" "$expected_version" <<'PY'
-import stat
-import sys
-import zipfile
-from pathlib import Path
-
-output = Path(sys.argv[1])
-version = sys.argv[2]
-shape = sys.argv[3]
-archive_version = sys.argv[4]
-
-def entry(name, contents, mode):
-    info = zipfile.ZipInfo(name)
-    info.external_attr = mode << 16
-    archive.writestr(info, contents)
-
-with zipfile.ZipFile(output, "w", compression=zipfile.ZIP_DEFLATED) as archive:
-    entry("maestro/", b"", stat.S_IFDIR | 0o755)
-    entry("maestro/bin/", b"", stat.S_IFDIR | 0o755)
-    entry(
-        "maestro/bin/maestro",
-        f"#!/usr/bin/env bash\nprintf '{version}\\n'\n".encode(),
-        stat.S_IFREG | 0o755,
-    )
-    entry("maestro/lib/", b"", stat.S_IFDIR | 0o755)
-    if shape != "missing-jar":
-        entry(
-            f"maestro/lib/maestro-cli-{archive_version}.jar",
-            b"mock jar",
-            stat.S_IFREG | 0o644,
-        )
-    if shape == "traversal":
-        entry("maestro/../escape", b"escape", stat.S_IFREG | 0o644)
-PY
+  bash "$root/tools/dev/bun.sh" - "$output" "$launcher_version" "$shape" "$expected_version" <<'TS'
+import {writeFileSync} from 'node:fs';
+import {zipArchive} from './tools/packaging/testdata/zip-fixture.mts';
+const [output,version,shape,archiveVersion] = process.argv.slice(2);
+const rows = [{name:'maestro/bin/maestro',data:"#!/usr/bin/env bash\nprintf '" + version + "\\n'\n",externalAttributes:0o100755<<16}];
+if (shape !== 'missing-jar') rows.push({name:'maestro/lib/maestro-cli-'+archiveVersion+'.jar',data:'mock jar'});
+if (shape === 'traversal') rows.push({name:'maestro/../escape',data:'escape'});
+writeFileSync(output,zipArchive(rows));
+TS
 }
 
 valid_archive="$test_root/valid.zip"
@@ -179,27 +156,32 @@ run_case() {
   CASE_LOG="$CASE_ROOT/setup.log"
   CASE_CURL_ARGS="$CASE_ROOT/curl-args"
   CASE_GITHUB_PATH="$CASE_ROOT/github-path"
-  mkdir -p "$CASE_REPO/tools/dev" "$CASE_REPO/src/sources/toolchains" "$CASE_HOME/.maestro"
+  mkdir -p "$CASE_REPO/tools/dev" "$CASE_REPO/tools/dev" "$CASE_HOME/.maestro"
   cp "$installer" "$CASE_REPO/tools/dev/setup-maestro.sh"
+  cp "$root/tools/dev/extract-maestro.mts" "$CASE_REPO/tools/dev/extract-maestro.mts"
+  cp "$root/tools/dev/bun.sh" "$CASE_REPO/tools/dev/bun.sh"
+  cp "$root/.prototools" "$CASE_REPO/.prototools"
+  mkdir -p "$CASE_REPO/tools/packaging"
+  cp "$root/tools/packaging/portable-archive.mts" "$CASE_REPO/tools/packaging/portable-archive.mts"
   case "$manifest_mode" in
     pinned)
       printf '[toolchain]\nmaestro = "%s"\ninstall_url = "%s"\nsha256 = "%s"\n' \
         "$configured_version" "$expected_url" "$expected_sha256" \
-        >"$CASE_REPO/src/sources/toolchains/maestro.toml"
+        >"$CASE_REPO/tools/dev/maestro.toml"
       ;;
     unpinned)
       printf '[toolchain]\nmaestro = "%s"\n' \
-        "$configured_version" >"$CASE_REPO/src/sources/toolchains/maestro.toml"
+        "$configured_version" >"$CASE_REPO/tools/dev/maestro.toml"
       ;;
     wrong-url)
       printf '[toolchain]\nmaestro = "%s"\ninstall_url = "https://example.invalid/maestro.zip"\nsha256 = "%s"\n' \
         "$configured_version" "$expected_sha256" \
-        >"$CASE_REPO/src/sources/toolchains/maestro.toml"
+        >"$CASE_REPO/tools/dev/maestro.toml"
       ;;
     invalid-sha)
       printf '[toolchain]\nmaestro = "%s"\ninstall_url = "%s"\nsha256 = "not-a-sha256"\n' \
         "$configured_version" "$expected_url" \
-        >"$CASE_REPO/src/sources/toolchains/maestro.toml"
+        >"$CASE_REPO/tools/dev/maestro.toml"
       ;;
     *) fail "unknown manifest mode: $manifest_mode" ;;
   esac
@@ -295,7 +277,7 @@ assert_no_staging_dirs
 
 run_case missing-layout "$expected_version" "$missing_jar_archive" "$expected_sha256"
 [ "$CASE_STATUS" != "0" ] || fail "archive with a missing CLI jar unexpectedly succeeded"
-assert_contains "$CASE_LOG" "missing expected archive entries"
+assert_contains "$CASE_LOG" "missing expected archive entry"
 assert_previous_preserved
 assert_no_staging_dirs
 
@@ -307,7 +289,7 @@ assert_no_staging_dirs
 
 run_case traversal "$expected_version" "$traversal_archive" "$expected_sha256"
 [ "$CASE_STATUS" != "0" ] || fail "archive with path traversal unexpectedly succeeded"
-assert_contains "$CASE_LOG" "unsafe archive path"
+assert_contains "$CASE_LOG" "unsafe archive member"
 assert_previous_preserved
 assert_no_staging_dirs
 
diff --git a/tools/dev/winflexbison-identity.mts b/tools/dev/winflexbison-identity.mts
new file mode 100644
index 000000000..916aa2514
--- /dev/null
+++ b/tools/dev/winflexbison-identity.mts
@@ -0,0 +1,39 @@
+import { createHash } from 'node:crypto';
+import { lstatSync, readdirSync, readFileSync } from 'node:fs';
+import path from 'node:path';
+
+const root = process.argv[2];
+try {
+  if (!lstatSync(root).isDirectory()) throw new Error('payload must be a real directory');
+  const files = [];
+  let expanded = 0;
+  let count = 0;
+  function walk(relative = '') {
+    for (const name of readdirSync(path.join(root, relative))) {
+      const member = relative ? `${relative}/${name}` : name;
+      if (++count > 512 || /[\x00-\x1f\x7f]/u.test(member))
+        throw new Error('invalid payload inventory');
+      const file = path.join(root, member);
+      const stat = lstatSync(file);
+      if (stat.isDirectory()) {
+        walk(member);
+        continue;
+      }
+      if (!stat.isFile()) throw new Error(`payload contains a link or special file: ${member}`);
+      expanded += stat.size;
+      if (expanded > 10_000_000) throw new Error('payload exceeds its byte bound');
+      files.push({ member, file, size: stat.size });
+    }
+  }
+  walk();
+  files.sort((a, b) => Buffer.compare(Buffer.from(a.member), Buffer.from(b.member)));
+  const digest = createHash('sha256');
+  for (const { member, file, size } of files) {
+    const hash = createHash('sha256').update(readFileSync(file)).digest('hex');
+    digest.update(`${member}\0${size}\0${hash}\n`);
+  }
+  console.log(`${digest.digest('hex')}\t${files.length}\t${expanded}`);
+} catch (error) {
+  console.error(error.message);
+  process.exitCode = 1;
+}
diff --git a/src/sources/toolchains/winflexbison.toml b/tools/dev/winflexbison.toml
similarity index 100%
rename from src/sources/toolchains/winflexbison.toml
rename to tools/dev/winflexbison.toml
diff --git a/tools/dev/write-scoped-pnpm-workspace.mjs b/tools/dev/write-scoped-pnpm-workspace.mjs
deleted file mode 100644
index de5d93f74..000000000
--- a/tools/dev/write-scoped-pnpm-workspace.mjs
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/bin/env node
-
-import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
-import path from "node:path";
-import process from "node:process";
-import { fileURLToPath } from "node:url";
-
-function usage(message) {
-  if (message) {
-    console.error(message);
-  }
-  console.error(
-    "usage: write-scoped-pnpm-workspace.mjs --source FILE --output FILE --package GLOB [--package GLOB ...]",
-  );
-  process.exit(2);
-}
-
-export function renderScopedWorkspace(source, packageGlobs) {
-  if (!Array.isArray(packageGlobs) || packageGlobs.length === 0) {
-    throw new Error("at least one package glob is required");
-  }
-  for (const packageGlob of packageGlobs) {
-    if (
-      typeof packageGlob !== "string" ||
-      packageGlob.trim() !== packageGlob ||
-      packageGlob.length === 0 ||
-      /[\r\n\0]/u.test(packageGlob)
-    ) {
-      throw new Error(`invalid package glob: ${JSON.stringify(packageGlob)}`);
-    }
-  }
-
-  const normalized = source.replaceAll("\r\n", "\n");
-  const lines = normalized.split("\n");
-  if (lines[0] !== "packages:") {
-    throw new Error("source workspace must begin with the packages mapping");
-  }
-
-  let remainderIndex = 1;
-  while (remainderIndex < lines.length) {
-    const line = lines[remainderIndex];
-    if (line.length > 0 && !/^\s/u.test(line) && !line.startsWith("#")) {
-      break;
-    }
-    remainderIndex += 1;
-  }
-  if (remainderIndex >= lines.length) {
-    throw new Error("source workspace has no shared configuration after packages");
-  }
-
-  const remainder = lines.slice(remainderIndex).join("\n").replace(/^\n+/u, "");
-  const packageLines = packageGlobs.map((packageGlob) => `  - ${JSON.stringify(packageGlob)}`);
-  return `packages:\n${packageLines.join("\n")}\n\n${remainder}`;
-}
-
-export async function writeScopedWorkspace({ sourcePath, outputPath, packageGlobs }) {
-  const source = path.resolve(sourcePath);
-  const output = path.resolve(outputPath);
-  if (source === output) {
-    throw new Error("refusing to overwrite the source workspace");
-  }
-
-  const rendered = renderScopedWorkspace(await readFile(source, "utf8"), packageGlobs);
-  await mkdir(path.dirname(output), { recursive: true });
-  const temporary = `${output}.${process.pid}.tmp`;
-  try {
-    await writeFile(temporary, rendered, { encoding: "utf8", mode: 0o600 });
-    await rename(temporary, output);
-  } finally {
-    await rm(temporary, { force: true });
-  }
-}
-
-async function main(argv) {
-  let sourcePath;
-  let outputPath;
-  const packageGlobs = [];
-  for (let index = 0; index < argv.length; index += 1) {
-    const argument = argv[index];
-    const value = argv[index + 1];
-    switch (argument) {
-      case "--source":
-        if (!value) usage("--source requires a file");
-        sourcePath = value;
-        index += 1;
-        break;
-      case "--output":
-        if (!value) usage("--output requires a file");
-        outputPath = value;
-        index += 1;
-        break;
-      case "--package":
-        if (!value) usage("--package requires a glob");
-        packageGlobs.push(value);
-        index += 1;
-        break;
-      default:
-        usage(`unknown argument: ${argument}`);
-    }
-  }
-  if (!sourcePath || !outputPath || packageGlobs.length === 0) {
-    usage();
-  }
-  await writeScopedWorkspace({ sourcePath, outputPath, packageGlobs });
-}
-
-if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
-  main(process.argv.slice(2)).catch((error) => {
-    console.error(error instanceof Error ? error.message : String(error));
-    process.exitCode = 1;
-  });
-}
diff --git a/tools/graph/affected.mjs b/tools/graph/affected.mjs
deleted file mode 100644
index 641b76768..000000000
--- a/tools/graph/affected.mjs
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env bun
-import path from "node:path";
-
-import { captureCommandOutput } from "../dev/capture-command-output.mjs";
-import { moonCommand, moonEnvironment } from "../dev/moon-command.mjs";
-
-const ROOT = path.resolve(import.meta.dir, "../..");
-
-function fail(message) {
-  console.error(`affected.mjs: ${message}`);
-  process.exit(2);
-}
-
-function moon(args) {
-  const result = captureCommandOutput(moonCommand(), args, {
-    cwd: ROOT,
-    env: moonEnvironment(),
-    label: `moon ${args.join(" ")}`,
-    maxOutputBytes: 100 * 1024 * 1024,
-  });
-  if (result.error !== undefined) {
-    fail(`failed to run moon: ${result.error.message}`);
-  }
-  if (result.status !== 0) {
-    if (result.stderr) process.stderr.write(result.stderr);
-    process.exit(result.status ?? 1);
-  }
-  try {
-    return JSON.parse(result.stdout);
-  } catch (error) {
-    fail(`moon query did not return JSON: ${error.message}`);
-  }
-}
-
-export function affectedNames(value) {
-  if (value === null || Array.isArray(value) || typeof value !== "object") {
-    throw new TypeError("Moon affected query must return an object");
-  }
-  return Object.keys(value).sort();
-}
-
-export function triggeringProjectNames(value) {
-  affectedNames(value);
-  return Object.entries(value)
-    .filter(([, detail]) => {
-      if (detail === null || Array.isArray(detail) || typeof detail !== "object") return false;
-      return detail.other === true || (Array.isArray(detail.tasks) && detail.tasks.length > 0);
-    })
-    .map(([project]) => project)
-    .sort();
-}
-
-export function triggeringTaskNames(value) {
-  affectedNames(value);
-  return Object.entries(value)
-    .filter(([, detail]) => {
-      if (detail === null || Array.isArray(detail) || typeof detail !== "object") return false;
-      return detail.other === true || (Array.isArray(detail.files) && detail.files.length > 0);
-    })
-    .map(([task]) => task)
-    .sort();
-}
-
-function affectedSummary() {
-  const affected = moon(["query", "affected", "--upstream", "none", "--downstream", "direct"]);
-  return {
-    directProjects: triggeringProjectNames(affected.projects),
-    projects: affectedNames(affected.projects),
-    tasks: triggeringTaskNames(affected.tasks),
-  };
-}
-
-function usage() {
-  fail("usage: tools/graph/affected.mjs summary");
-}
-
-if (import.meta.main) {
-  const [command] = Bun.argv.slice(2);
-  if (command !== "summary") {
-    usage();
-  }
-  console.log(JSON.stringify(affectedSummary()));
-}
diff --git a/tools/graph/ci_plan.mjs b/tools/graph/ci_plan.mjs
deleted file mode 100644
index 2d87b84e1..000000000
--- a/tools/graph/ci_plan.mjs
+++ /dev/null
@@ -1,997 +0,0 @@
-#!/usr/bin/env bun
-// Map Moon affected tasks onto stable GitHub Actions jobs.
-//
-// Moon is the only project/task graph. Stable GitHub job names are selected
-// from Moon task tags named `ci-`. GitHub Actions still owns platform
-// matrix fan-out because runner OS, native target triples, and simulator/device
-// targets are CI execution details, not source projects.
-import { appendFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
-import path from "node:path";
-
-import { moonCommand, moonEnvironment } from "../dev/moon-command.mjs";
-import { captureCommandOutput } from "../dev/capture-command-output.mjs";
-
-import {
-  brokerRuntimeMatrix,
-  extensionArtifactsNativeMatrix,
-  extensionArtifactsWasixMatrix,
-  liboliphauntNativeAndroidRuntimeMatrix,
-  liboliphauntNativeDesktopRuntimeMatrix,
-  liboliphauntNativeIosRuntimeMatrix,
-  liboliphauntNativeRuntimeTargetsForSurface,
-  liboliphauntWasixAotRuntimeMatrix,
-  liboliphauntWasixPostmasterRuntimeMatrix,
-  nodeDirectRuntimeMatrix,
-  reactNativeAndroidMobileAppMatrix,
-  wasixNapiRuntimeMatrix,
-} from "../release/artifact_target_matrix.mjs";
-import {
-  compareText,
-  exactExtensionProducts,
-  extensionPublicDependencySqlNames,
-  extensionSqlNames,
-} from "../release/release-artifact-targets.mjs";
-
-const ROOT = path.resolve(import.meta.dir, "../..");
-const PREFIX = "ci_plan.mjs";
-
-export const BASE_JOBS = new Set(["affected"]);
-export const ALWAYS_JOBS = new Set(BASE_JOBS);
-export const FULL_PAYLOAD_QUALIFICATION_MODE = "full-payload";
-export const AFFECTED_QUALIFICATION_MODE = "affected";
-const NATIVE_RUNTIME_JOBS = new Set([
-  "liboliphaunt-native-android",
-  "liboliphaunt-native-desktop",
-  "liboliphaunt-native-ios",
-]);
-const NATIVE_RUNTIME_TASKS = new Set([
-  "liboliphaunt-native:package-runtime-desktop-target",
-  "liboliphaunt-native:package-runtime-android-arm64-v8a",
-  "liboliphaunt-native:package-runtime-android-x86_64",
-  "liboliphaunt-native:package-runtime-ios-xcframework",
-]);
-export const WASM_RUNTIME_JOBS = new Set([
-  "liboliphaunt-wasix-runtime",
-  "liboliphaunt-wasix-aot",
-  "liboliphaunt-wasix-release-assets",
-]);
-const MOBILE_JOB_SURFACES = {
-  "mobile-build-android": "react-native-android",
-  "mobile-build-ios": "react-native-ios",
-};
-const MOBILE_E2E_JOBS = {
-  "mobile-build-android": "mobile-e2e-android",
-  "mobile-build-ios": "mobile-e2e-ios",
-};
-const REACT_NATIVE_ANDROID_REPRESENTATIVE_TARGETS = new Set(["android-x86_64"]);
-export const NATIVE_EXTENSION_LIFECYCLE_JOB = "native-extension-lifecycle";
-export const NATIVE_EXTENSION_LIFECYCLE_AGGREGATE_JOB =
-  "native-extension-lifecycle-aggregate";
-export const NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT = 3;
-export const BROAD_EXTENSION_INPUT_PROJECTS = new Set([
-  "extension-artifacts-native",
-  "extension-artifacts-wasix",
-  "oliphaunt-extension-contrib-pg18",
-  "extension-packages",
-  "liboliphaunt-native",
-  "liboliphaunt-wasix",
-  "postgres18",
-  "third-party-native",
-  "third-party-shared",
-]);
-function fail(message) {
-  console.error(`${PREFIX}: ${message}`);
-  process.exit(2);
-}
-
-function commandJson(command, args, options = {}) {
-  const result = captureCommandOutput(command, args, {
-    cwd: ROOT,
-    env: process.env,
-    label: `${command} ${args.join(" ")}`,
-    maxOutputBytes: 100 * 1024 * 1024,
-    ...options,
-  });
-  if (result.error !== undefined || result.status !== 0) {
-    const detail = result.error?.message || result.stderr.trim() || `exit ${result.status}`;
-    fail(`${command} failed: ${detail}`);
-  }
-  return JSON.parse(result.stdout);
-}
-
-function moon(args) {
-  return commandJson(moonCommand(), args, { env: moonEnvironment() });
-}
-
-function affectedProjectsAndTasks() {
-  const summary = commandJson(process.execPath, ["tools/graph/affected.mjs", "summary"]);
-  return {
-    directProjects: new Set(stringList(summary.directProjects ?? [])),
-    projects: new Set(stringList(summary.projects ?? [])),
-    directTasks: new Set(stringList(summary.tasks ?? [])),
-  };
-}
-
-function stringList(value) {
-  if (!Array.isArray(value)) {
-    fail("expected a JSON string list");
-  }
-  return value.map((item) => String(item)).sort(compareText);
-}
-
-function setUnion(...sets) {
-  const result = new Set();
-  for (const set of sets) {
-    for (const item of set) {
-      result.add(item);
-    }
-  }
-  return result;
-}
-
-function intersects(left, right) {
-  for (const item of left) {
-    if (right.has(item)) {
-      return true;
-    }
-  }
-  return false;
-}
-
-function sorted(set) {
-  return [...set].sort(compareText);
-}
-
-const TASKS_BY_TARGET = (() => {
-  const graph = moon(["task-graph", "--json"]);
-  if (graph.data === null || Array.isArray(graph.data) || typeof graph.data !== "object") {
-    fail("moon task-graph did not return task data");
-  }
-  return new Map(Object.values(graph.data).map((task) => [task.target, task]));
-})();
-
-export function moonCiJobTargets() {
-  const jobs = new Map();
-  for (const task of TASKS_BY_TARGET.values()) {
-    for (const tag of task.tags ?? []) {
-      if (typeof tag === "string" && tag.startsWith("ci-")) {
-        const job = tag.slice("ci-".length);
-        if (!jobs.has(job)) {
-          jobs.set(job, new Set());
-        }
-        jobs.get(job).add(task.target);
-      }
-    }
-  }
-  return Object.fromEntries(
-    [...jobs.entries()]
-      .sort(([left], [right]) => compareText(left, right))
-      .map(([job, targets]) => [job, sorted(targets)]),
-  );
-}
-
-export const CI_JOB_TARGETS = moonCiJobTargets();
-export const BUILDER_JOBS = new Set(
-  Object.keys(CI_JOB_TARGETS).filter((job) => job !== NATIVE_EXTENSION_LIFECYCLE_JOB),
-);
-const JOBS_BY_TARGET = (() => {
-  const jobs = new Map();
-  for (const [job, targets] of Object.entries(CI_JOB_TARGETS)) {
-    for (const target of targets) jobs.set(target, [...(jobs.get(target) ?? []), job]);
-  }
-  return jobs;
-})();
-const DEPENDENTS_BY_TARGET = (() => {
-  const dependents = new Map();
-  for (const task of TASKS_BY_TARGET.values()) {
-    for (const dependency of task.deps ?? []) {
-      const target = typeof dependency === "string" ? dependency : dependency.target;
-      if (typeof target === "string") {
-        dependents.set(target, [...(dependents.get(target) ?? []), task.target]);
-      }
-    }
-  }
-  return dependents;
-})();
-export const ALL_BUILDER_JOBS = new Set(Object.keys(CI_JOB_TARGETS));
-export const CI_JOBS_CONFIG = {
-  always_jobs: sorted(ALWAYS_JOBS),
-  ci_job_targets: CI_JOB_TARGETS,
-  wasm_runtime_jobs: sorted(WASM_RUNTIME_JOBS),
-};
-
-export function jobTargetsForJobs(jobs) {
-  return Object.fromEntries(
-    sorted(jobs)
-      .filter((job) => CI_JOB_TARGETS[job] !== undefined)
-      .map((job) => [job, CI_JOB_TARGETS[job]]),
-  );
-}
-
-function emptyMatrix() {
-  return { include: [] };
-}
-
-export function jobsForTargets(targets, { allowedJobs = undefined } = {}) {
-  const jobs = new Set();
-  for (const [job, jobTargets] of Object.entries(CI_JOB_TARGETS)) {
-    if (allowedJobs !== undefined && !allowedJobs.has(job)) {
-      continue;
-    }
-    if (intersects(targets, new Set(jobTargets))) {
-      jobs.add(job);
-    }
-  }
-  return jobs;
-}
-
-function taskDependencyTargets(task) {
-  return (task?.deps ?? [])
-    .map((dependency) => typeof dependency === "string" ? dependency : dependency.target)
-    .filter((target) => typeof target === "string");
-}
-
-function downstreamTaskClosure(tasks) {
-  const closure = new Set(tasks);
-  const pending = [...closure];
-  while (pending.length > 0) {
-    for (const dependent of DEPENDENTS_BY_TARGET.get(pending.pop()) ?? []) {
-      if (!closure.has(dependent)) {
-        closure.add(dependent);
-        pending.push(dependent);
-      }
-    }
-  }
-  return closure;
-}
-
-export function addRequiredJobs(jobs) {
-  const pendingJobs = [...jobs];
-  const visitedTasks = new Set();
-  while (pendingJobs.length > 0) {
-    const job = pendingJobs.pop();
-    const pendingTasks = [...(CI_JOB_TARGETS[job] ?? [])];
-    while (pendingTasks.length > 0) {
-      const target = pendingTasks.pop();
-      if (visitedTasks.has(target)) continue;
-      visitedTasks.add(target);
-      const task = TASKS_BY_TARGET.get(target);
-      if (!task) fail(`CI job ${job} references missing Moon target ${target}`);
-      for (const dependency of taskDependencyTargets(task)) {
-        pendingTasks.push(dependency);
-        for (const dependencyJob of JOBS_BY_TARGET.get(dependency) ?? []) {
-          if (!jobs.has(dependencyJob)) {
-            jobs.add(dependencyJob);
-            pendingJobs.push(dependencyJob);
-          }
-        }
-      }
-    }
-  }
-  return jobs;
-}
-
-export function planJobsForAffected(tasks) {
-  const jobs = new Set(ALWAYS_JOBS);
-  const directlySelectedJobs = jobsForTargets(
-    downstreamTaskClosure(tasks),
-    { allowedJobs: ALL_BUILDER_JOBS },
-  );
-  for (const job of directlySelectedJobs) {
-    jobs.add(job);
-  }
-  return addRequiredJobs(jobs);
-}
-
-export function nativeTargetSubsetForJobs(jobs, tasks) {
-  if (!intersects(jobs, NATIVE_RUNTIME_JOBS)) {
-    return null;
-  }
-  if (jobs.has("liboliphaunt-native-release-assets")) {
-    return null;
-  }
-  if (intersects(tasks, NATIVE_RUNTIME_TASKS)) {
-    return null;
-  }
-
-  const targets = mobileNativeTargetsForJobs(jobs);
-  if (
-    jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)
-  ) {
-    targets.add("linux-x64-gnu");
-  }
-  if (jobs.has("swift-sdk-package")) {
-    targets.add("ios-xcframework");
-  }
-  if (jobs.has("kotlin-sdk-package")) {
-    for (const target of liboliphauntNativeRuntimeTargetsForSurface("maven")) {
-      targets.add(target);
-    }
-  }
-  return targets.size > 0 ? targets : null;
-}
-
-export function mobileNativeTargetsForJobs(jobs) {
-  const targets = new Set();
-  for (const [job, surface] of Object.entries(MOBILE_JOB_SURFACES)) {
-    if (jobs.has(job)) {
-      for (const target of liboliphauntNativeRuntimeTargetsForSurface(surface)) {
-        targets.add(target);
-      }
-    }
-  }
-  return targets;
-}
-
-export function mobileExtensionPackageNativeTargets(jobs, selectedTargets) {
-  if (!jobs.has("mobile-extension-packages")) {
-    return [];
-  }
-  if (selectedTargets !== null && selectedTargets !== undefined) {
-    return sorted(selectedTargets);
-  }
-  return sorted(mobileNativeTargetsForJobs(jobs));
-}
-
-export function mobileE2eJobsForPlan(jobs) {
-  const selected = Object.entries(MOBILE_E2E_JOBS)
-    .filter(([builder]) => jobs.has(builder))
-    .map(([, e2e]) => e2e)
-  if (jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)) {
-    selected.push(NATIVE_EXTENSION_LIFECYCLE_AGGREGATE_JOB);
-  }
-  return selected.sort(compareText);
-}
-
-export function liboliphauntNativeIosRuntimeMatrixForPlan(
-  jobs,
-  selectedTargets,
-  nativeTarget = process.env.NATIVE_TARGET || "all",
-) {
-  if (!jobs.has("liboliphaunt-native-ios")) return emptyMatrix();
-  if (jobs.has("react-native-sdk-package")) {
-    return liboliphauntNativeIosRuntimeMatrix("all", new Set(["ios-xcframework"]));
-  }
-  return liboliphauntNativeIosRuntimeMatrix(nativeTarget, selectedTargets ?? undefined);
-}
-
-export function liboliphauntNativeDesktopRuntimeMatrixForPlan(
-  jobs,
-  selectedTargets,
-  nativeTarget = process.env.NATIVE_TARGET || "all",
-) {
-  if (!jobs.has("liboliphaunt-native-desktop")) return emptyMatrix();
-  return liboliphauntNativeDesktopRuntimeMatrix(nativeTarget, selectedTargets ?? undefined);
-}
-
-function focusedMobileNativeTargets(mobileTarget, nativeTarget, focusedMobileJobs) {
-  const targets = mobileNativeTargetsForJobs(focusedMobileJobs);
-  if (nativeTarget !== "all") {
-    if (mobileTarget === "both") {
-      throw new Error("focused mobile_target=both requires native_target=all");
-    }
-    if (!targets.has(nativeTarget)) {
-      throw new Error(
-        `native_target=${nativeTarget} is not valid for mobile_target=${mobileTarget}; expected one of: all, ${sorted(targets).join(", ")}`,
-      );
-    }
-  }
-  // Mobile qualification admits one physical compatibility domain. A focused
-  // target may select that domain, but must not silently omit one of its ABI
-  // receipts or the representative emulator app that consumes the closure.
-  return targets;
-}
-
-export function planForAffectedRange() {
-  const base = process.env.MOON_BASE;
-  const head = process.env.MOON_HEAD;
-  if (!base || !head) {
-    throw new Error("MOON_BASE and MOON_HEAD are required for affected CI planning");
-  }
-
-  const { directProjects, projects, directTasks } = affectedProjectsAndTasks();
-  const jobs = planJobsForAffected(directTasks);
-  const selectedNativeTargets = nativeTargetSubsetForJobs(jobs, directTasks);
-  const reason =
-    `direct affected projects: ${sorted(directProjects).join(", ") || "(none)"}; ` +
-    `downstream affected projects: ${sorted(projects).join(", ") || "(none)"}; ` +
-    `direct affected tasks: ${sorted(directTasks).join(", ") || "(none)"}`;
-  return {
-    jobs,
-    directProjects,
-    projects,
-    tasks: directTasks,
-    reason,
-    selectedTargets: selectedNativeTargets,
-  };
-}
-
-export function selectedExtensionProductsForPlan(directProjects, tasks, jobs) {
-  const extensionJobs = new Set([
-    "extension-artifacts-native",
-    "extension-artifacts-wasix",
-    "extension-packages",
-    NATIVE_EXTENSION_LIFECYCLE_JOB,
-    ...Object.keys(MOBILE_JOB_SURFACES),
-  ]);
-  if (!intersects(jobs, extensionJobs)) {
-    return null;
-  }
-
-  const exactProducts = new Set(exactExtensionProducts());
-  if (intersects(jobs, new Set(Object.keys(MOBILE_JOB_SURFACES)))) {
-    return exactProducts;
-  }
-  const selected = new Set([...directProjects].filter((project) => exactProducts.has(project)));
-  for (const target of tasks) {
-    const project = target.split(":", 1)[0];
-    if (exactProducts.has(project)) {
-      selected.add(project);
-    }
-  }
-  if (intersects(directProjects, BROAD_EXTENSION_INPUT_PROJECTS)) {
-    return exactProducts;
-  }
-  if (tasks.has("extension-packages:package") && selected.size === 0) {
-    return exactProducts;
-  }
-  if (jobs.has("extension-packages") && selected.size === 0) {
-    return exactProducts;
-  }
-  if (intersects(jobs, new Set(["extension-artifacts-native", "extension-artifacts-wasix"])) && selected.size === 0) {
-    return exactProducts;
-  }
-  if (tasks.has("extension-packages:package-mobile") && selected.size === 0) {
-    return exactProducts;
-  }
-  return selected.size > 0 ? selected : null;
-}
-
-export function extensionProductDependencyClosure(products) {
-  const exactProducts = new Set(exactExtensionProducts());
-  const productBySqlName = new Map(
-    [...exactProducts].flatMap((product) => extensionSqlNames(product, PREFIX).map((sqlName) => [sqlName, product])),
-  );
-  const closure = new Set();
-  const pending = [...products];
-  while (pending.length > 0) {
-    const product = pending.pop();
-    if (!exactProducts.has(product)) throw new Error(`unknown exact extension product ${product}`);
-    if (closure.has(product)) continue;
-    closure.add(product);
-    for (const sqlName of extensionSqlNames(product, PREFIX)) {
-      for (const dependencySqlName of extensionPublicDependencySqlNames(sqlName, PREFIX)) {
-        const dependencyProduct = productBySqlName.get(dependencySqlName);
-        if (!dependencyProduct) {
-          throw new Error(`${sqlName} has unknown public extension dependency ${dependencySqlName}`);
-        }
-        pending.push(dependencyProduct);
-      }
-    }
-  }
-  return closure;
-}
-
-export function planForFullRun({
-  wasmTarget = "all",
-  nativeTarget = "all",
-  mobileTarget = "all",
-} = {}) {
-  if (wasmTarget !== "all" && (nativeTarget !== "all" || mobileTarget !== "all")) {
-    throw new Error(
-      "wasm_target focus cannot be combined with native_target or mobile_target focus; run the WASIX and native/mobile diagnostics separately",
-    );
-  }
-  if (mobileTarget !== "all") {
-    const mobileJobsByTarget = {
-      android: new Set(["mobile-build-android"]),
-      ios: new Set(["mobile-build-ios"]),
-      both: new Set(["mobile-build-android", "mobile-build-ios"]),
-    };
-    const focusedMobileJobs = mobileJobsByTarget[mobileTarget];
-    if (focusedMobileJobs === undefined) {
-      throw new Error(`unknown mobile target ${mobileTarget}; expected one of: all, android, ios, both`);
-    }
-    const focusedJobs = setUnion(BASE_JOBS, focusedMobileJobs);
-    addRequiredJobs(focusedJobs);
-    const focusedNativeTargets = focusedMobileNativeTargets(mobileTarget, nativeTarget, focusedMobileJobs);
-    return {
-      jobs: focusedJobs,
-      projects: new Set(["liboliphaunt-native", "oliphaunt-react-native"]),
-      tasks: targetsForJobs(focusedMobileJobs),
-      reason: `manual focused mobile CI run for ${mobileTarget}`,
-      selectedTargets: focusedNativeTargets,
-    };
-  }
-
-  if (nativeTarget !== "all") {
-    let focusedJobs;
-    let focusedProjects;
-    if (nativeTarget.startsWith("android-") || nativeTarget === "ios-xcframework") {
-      focusedJobs = setUnion(
-        BASE_JOBS,
-        new Set([nativeTarget.startsWith("android-") ? "liboliphaunt-native-android" : "liboliphaunt-native-ios"]),
-      );
-      focusedProjects = new Set(["liboliphaunt-native"]);
-    } else {
-      focusedJobs = setUnion(BASE_JOBS, new Set([
-        "liboliphaunt-native-desktop",
-      ]));
-      focusedProjects = new Set(["liboliphaunt-native"]);
-      if (nativeTarget === "linux-x64-gnu") {
-        focusedJobs.add(NATIVE_EXTENSION_LIFECYCLE_JOB);
-      }
-    }
-    addRequiredJobs(focusedJobs);
-    return {
-      jobs: focusedJobs,
-      projects: focusedProjects,
-      tasks: targetsForJobs(focusedJobs),
-      reason: `manual focused native runtime CI run for ${nativeTarget}`,
-      selectedTargets: focusedJobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)
-        ? new Set(["linux-x64-gnu"])
-        : null,
-    };
-  }
-
-  if (wasmTarget !== "all") {
-    const focusedJobs = setUnion(BASE_JOBS, new Set(["liboliphaunt-wasix-runtime", "liboliphaunt-wasix-aot"]));
-    if (wasmTarget === "linux-x64-gnu") {
-      // The workflow selects release regression for the Linux host target.
-      focusedJobs.add("extension-artifacts-wasix");
-    }
-    return {
-      jobs: focusedJobs,
-      projects: new Set(["liboliphaunt-wasix"]),
-      tasks: targetsForJobs(focusedJobs),
-      reason: `manual focused WASIX runtime CI run for ${wasmTarget}`,
-      selectedTargets: null,
-    };
-  }
-
-  const jobs = setUnion(
-    BASE_JOBS,
-    BUILDER_JOBS,
-    WASM_RUNTIME_JOBS,
-    new Set([NATIVE_EXTENSION_LIFECYCLE_JOB]),
-  );
-  addRequiredJobs(jobs);
-  return {
-    jobs,
-    projects: new Set(),
-    tasks: targetsForJobs(jobs),
-    reason: "manual full CI/runtime run",
-    selectedTargets: null,
-  };
-}
-
-function targetsForJobs(jobs) {
-  const targets = new Set();
-  for (const job of jobs) {
-    for (const target of CI_JOB_TARGETS[job] ?? []) {
-      targets.add(target);
-    }
-  }
-  return targets;
-}
-
-function renderPlan(
-  {
-    jobs,
-    projects,
-    tasks,
-    reason,
-    selectedTargets,
-  },
-  {
-    nativeTarget = process.env.NATIVE_TARGET || "all",
-    wasmTarget = process.env.WASM_TARGET || "all",
-  } = {},
-) {
-  const selectedExtensionProducts = selectedExtensionProductsForPlan(new Set(), tasks, jobs);
-  return renderPlanWithSelection({
-    jobs,
-    projects,
-    tasks,
-    reason,
-    selectedTargets,
-    selectedExtensionProducts,
-    nativeTarget,
-    wasmTarget,
-  });
-}
-
-export function renderPlanForFullRun({
-  wasmTarget = "all",
-  nativeTarget = "all",
-  mobileTarget = "all",
-} = {}) {
-  return renderPlan(
-    planForFullRun({ wasmTarget, nativeTarget, mobileTarget }),
-    { nativeTarget: mobileTarget === "all" ? nativeTarget : "all", wasmTarget },
-  );
-}
-
-export function extensionArtifactsWasixMatrixForPlan(jobs, selectedExtensionProducts) {
-  // Release regression exercises every public extension. Its portable
-  // carrier producer must therefore be complete even when the release/package
-  // selection is intentionally narrowed to one independently versioned
-  // extension. Non-regression callers retain that focused selection.
-  const products = jobs.has("liboliphaunt-wasix-runtime")
-    ? undefined
-    : selectedExtensionProducts ?? undefined;
-  return extensionArtifactsWasixMatrix("all", products);
-}
-
-export function extensionArtifactsNativeMatrixForPlan(
-  jobs,
-  selectedTargets,
-  selectedExtensionProducts,
-  nativeTarget = process.env.NATIVE_TARGET || "all",
-) {
-  const matrix = extensionArtifactsNativeMatrix(
-    nativeTarget,
-    jobs.has("extension-packages") ? undefined : selectedTargets ?? undefined,
-    selectedExtensionProducts ?? undefined,
-  );
-  if (!jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)) {
-    return matrix;
-  }
-
-  const exactProducts = new Set(exactExtensionProducts());
-  const requiredTargets = new Set(["linux-x64-gnu"]);
-  const proofProducts = extensionProductDependencyClosure(selectedExtensionProducts ?? exactProducts);
-  const proofRows = extensionArtifactsNativeMatrix(
-    "all",
-    requiredTargets,
-    proofProducts,
-  ).include;
-  if (proofRows.length !== requiredTargets.size) {
-    throw new Error("native extension lifecycle does not have a complete Linux producer row");
-  }
-  const include = matrix.include.filter((row) => !requiredTargets.has(row.target));
-  include.push(...proofRows);
-  include.sort((left, right) => compareText(left.target, right.target));
-  return { include };
-}
-
-export function extensionSqlNamesForProducts(products) {
-  const rows = [...products].flatMap((product) => extensionSqlNames(product, PREFIX).map((sqlName) => ({ product, sqlName })));
-  const productsBySqlName = new Map();
-  for (const { product, sqlName } of rows) {
-    const existing = productsBySqlName.get(sqlName);
-    if (existing !== undefined) {
-      throw new Error(
-        `exact extension products ${existing} and ${product} share SQL name ${sqlName}`,
-      );
-    }
-    productsBySqlName.set(sqlName, product);
-  }
-  return rows.map(({ sqlName }) => sqlName).sort(compareText);
-}
-
-export function nativeExtensionLifecycleShardPlan(products) {
-  const selected = new Set(products);
-  if (selected.size === 0) return { matrix: emptyMatrix(), shardCount: 0 };
-  const exact = new Set(exactExtensionProducts());
-  const exhaustive = selected.size === exact.size && [...selected].every((product) => exact.has(product));
-  const shardCount = exhaustive ? NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT : 1;
-  const sqlNames = extensionSqlNamesForProducts(selected);
-  return {
-    matrix: {
-      include: Array.from({ length: shardCount }, (_, shard) => {
-        const names = sqlNames.filter((_, index) => index % shardCount === shard);
-        const shown = names.slice(0, 4).join(", ");
-        return {
-          shard,
-          shard_count: shardCount,
-          label: `${names.length} Extensions (${shown}${names.length > 4 ? ` + ${names.length - 4} More` : ""})`,
-        };
-      }),
-    },
-    shardCount,
-  };
-}
-
-export function renderPlanWithSelection({
-  jobs,
-  projects,
-  tasks,
-  reason,
-  selectedTargets,
-  selectedExtensionProducts,
-  nativeTarget = process.env.NATIVE_TARGET || "all",
-  wasmTarget = process.env.WASM_TARGET || "all",
-  qualificationMode = FULL_PAYLOAD_QUALIFICATION_MODE,
-  qualificationBaseSha = null,
-  qualificationHeadSha = null,
-}) {
-  const extensionProducts = sorted(selectedExtensionProducts ?? new Set());
-  const extensionSqlNames = extensionSqlNamesForProducts(extensionProducts);
-  const nativeLifecycleProducts = jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)
-    ? extensionProductDependencyClosure(
-        selectedExtensionProducts ?? new Set(exactExtensionProducts()),
-      )
-    : new Set();
-  const nativeLifecycleSqlNames = extensionSqlNamesForProducts(nativeLifecycleProducts);
-  const nativeLifecycleShards = nativeExtensionLifecycleShardPlan(nativeLifecycleProducts);
-  const plan = {
-    qualification_mode: qualificationMode,
-    qualification_base_sha: qualificationBaseSha,
-    qualification_head_sha: qualificationHeadSha,
-    jobs: sorted(jobs),
-    builder_jobs: sorted(new Set([...jobs].filter((job) => BUILDER_JOBS.has(job)))),
-    e2e_jobs: mobileE2eJobsForPlan(jobs),
-    job_targets: jobTargetsForJobs(jobs),
-    projects: sorted(projects),
-    tasks: sorted(tasks),
-    liboliphaunt_native_desktop_runtime_matrix: liboliphauntNativeDesktopRuntimeMatrixForPlan(
-      jobs,
-      selectedTargets,
-      nativeTarget,
-    ),
-    liboliphaunt_native_android_runtime_matrix: jobs.has("liboliphaunt-native-android")
-      ? liboliphauntNativeAndroidRuntimeMatrix(nativeTarget, selectedTargets ?? undefined)
-      : emptyMatrix(),
-    liboliphaunt_native_ios_runtime_matrix: liboliphauntNativeIosRuntimeMatrixForPlan(
-      jobs,
-      selectedTargets,
-      nativeTarget,
-    ),
-    extension_artifacts_native_matrix: jobs.has("extension-artifacts-native")
-      ? extensionArtifactsNativeMatrixForPlan(
-          jobs,
-          selectedTargets,
-          selectedExtensionProducts,
-          nativeTarget,
-        )
-      : emptyMatrix(),
-    extension_artifacts_wasix_matrix: jobs.has("extension-artifacts-wasix")
-      ? extensionArtifactsWasixMatrixForPlan(jobs, selectedExtensionProducts)
-      : emptyMatrix(),
-    liboliphaunt_wasix_aot_runtime_matrix: jobs.has("liboliphaunt-wasix-aot")
-      ? liboliphauntWasixAotRuntimeMatrix(wasmTarget)
-      : emptyMatrix(),
-    liboliphaunt_wasix_postmaster_runtime_matrix: jobs.has("wasix-postmaster")
-      ? liboliphauntWasixPostmasterRuntimeMatrix()
-      : emptyMatrix(),
-    extension_package_products: extensionProducts,
-    extension_package_products_csv: extensionProducts.join(","),
-    extension_package_sql_names: extensionSqlNames,
-    extension_package_sql_names_csv: extensionSqlNames.join(","),
-    native_extension_lifecycle_sql_names: nativeLifecycleSqlNames,
-    native_extension_lifecycle_sql_names_csv: nativeLifecycleSqlNames.join(","),
-    native_extension_lifecycle_matrix: nativeLifecycleShards.matrix,
-    native_extension_lifecycle_shard_count: nativeLifecycleShards.shardCount,
-    mobile_extension_package_native_targets: mobileExtensionPackageNativeTargets(jobs, selectedTargets),
-    mobile_extension_package_native_targets_csv: mobileExtensionPackageNativeTargets(jobs, selectedTargets).join(","),
-    react_native_android_mobile_app_matrix: jobs.has("mobile-build-android")
-      ? reactNativeAndroidMobileAppMatrix("all", REACT_NATIVE_ANDROID_REPRESENTATIVE_TARGETS)
-      : emptyMatrix(),
-    broker_runtime_matrix: jobs.has("broker-runtime")
-      ? brokerRuntimeMatrix(
-          !jobs.has("broker-release-assets")
-            && jobs.has(NATIVE_EXTENSION_LIFECYCLE_JOB)
-            && selectedTargets?.size === 1
-            && selectedTargets.has("linux-x64-gnu")
-            ? "linux-x64-gnu"
-            : nativeTarget,
-        )
-      : emptyMatrix(),
-    node_direct_runtime_matrix: jobs.has("node-direct")
-      ? nodeDirectRuntimeMatrix(nativeTarget)
-      : emptyMatrix(),
-    wasix_napi_runtime_matrix: jobs.has("wasix-napi")
-      ? wasixNapiRuntimeMatrix(
-          jobs.has("wasix-napi-release-assets") ? nativeTarget : "linux-x64-gnu",
-        )
-      : emptyMatrix(),
-    reason,
-  };
-  return plan;
-}
-
-function sortedValue(value) {
-  if (Array.isArray(value)) {
-    return value.map(sortedValue);
-  }
-  if (value instanceof Set) {
-    return sorted(value);
-  }
-  if (value !== null && typeof value === "object") {
-    return Object.fromEntries(
-      Object.keys(value)
-        .sort(compareText)
-        .map((key) => [key, sortedValue(value[key])]),
-    );
-  }
-  return value;
-}
-
-function output(name, value) {
-  const rendered = typeof value === "string" ? value : JSON.stringify(sortedValue(value));
-  const outputPath = process.env.GITHUB_OUTPUT;
-  if (outputPath) {
-    appendFileSync(outputPath, `${name}=${rendered}\n`, "utf8");
-  }
-  console.log(`${name}=${rendered}`);
-}
-
-function writePlanArtifact(plan) {
-  const file = path.join(ROOT, "target/graph/ci-plan.json");
-  mkdirSync(path.dirname(file), { recursive: true });
-  writeFileSync(file, `${JSON.stringify(sortedValue(plan), null, 2)}\n`, "utf8");
-}
-
-export function emitGithubOutputs() {
-  let planned;
-  try {
-    if (process.env.GITHUB_EVENT_NAME !== "workflow_dispatch") {
-      const affectedPlan = planForAffectedRange();
-      const selectedExtensionProducts = selectedExtensionProductsForPlan(
-        affectedPlan.directProjects,
-        affectedPlan.tasks,
-        affectedPlan.jobs,
-      );
-      planned = renderPlanWithSelection({
-        ...affectedPlan,
-        selectedExtensionProducts,
-        qualificationMode: AFFECTED_QUALIFICATION_MODE,
-        qualificationBaseSha: process.env.MOON_BASE,
-        qualificationHeadSha: process.env.MOON_HEAD,
-      });
-    } else {
-      planned = renderPlanForFullRun({
-        wasmTarget: process.env.WASM_TARGET || "all",
-        nativeTarget: process.env.NATIVE_TARGET || "all",
-        mobileTarget: process.env.MOBILE_TARGET || "all",
-      });
-    }
-  } catch (error) {
-    console.error(`affected planning failed: ${error.message}`);
-    return 2;
-  }
-  writePlanArtifact(planned);
-  for (const [name, value] of Object.entries(planned)) {
-    output(name, value);
-  }
-  return 0;
-}
-
-function parseJsonFlag(argv, name, { defaultValue = undefined } = {}) {
-  const flag = `--${name}`;
-  for (let index = 0; index < argv.length; index += 1) {
-    const value = argv[index];
-    if (value === flag) {
-      if (index + 1 >= argv.length) {
-        fail(`${flag} requires a value`);
-      }
-      return JSON.parse(argv[index + 1]);
-    }
-    if (value.startsWith(`${flag}=`)) {
-      return JSON.parse(value.slice(flag.length + 1));
-    }
-  }
-  return defaultValue;
-}
-
-function stringFlag(argv, name, defaultValue = "all") {
-  const flag = `--${name}`;
-  for (let index = 0; index < argv.length; index += 1) {
-    const value = argv[index];
-    if (value === flag) {
-      if (index + 1 >= argv.length) {
-        fail(`${flag} requires a value`);
-      }
-      return argv[index + 1];
-    }
-    if (value.startsWith(`${flag}=`)) {
-      return value.slice(flag.length + 1);
-    }
-  }
-  return defaultValue;
-}
-
-function setFlag(argv, name) {
-  const value = parseJsonFlag(argv, name, { defaultValue: [] });
-  return new Set(stringList(value));
-}
-
-function nullableSetFlag(argv, name) {
-  const value = parseJsonFlag(argv, name, { defaultValue: null });
-  if (value === null) {
-    return null;
-  }
-  return new Set(stringList(value));
-}
-
-function printJson(value) {
-  console.log(JSON.stringify(sortedValue(value), null, 2));
-}
-
-function printPlanForFullRun(argv) {
-  const plan = planForFullRun({
-    wasmTarget: stringFlag(argv, "wasm-target"),
-    nativeTarget: stringFlag(argv, "native-target"),
-    mobileTarget: stringFlag(argv, "mobile-target"),
-  });
-  printJson({
-    jobs: sorted(plan.jobs),
-    projects: sorted(plan.projects),
-    tasks: sorted(plan.tasks),
-    reason: plan.reason,
-    selectedTargets: plan.selectedTargets === null ? null : sorted(plan.selectedTargets),
-  });
-}
-
-function printMatrix(argv, matrix) {
-  const nativeTarget = stringFlag(argv, "native-target");
-  const wasmTarget = stringFlag(argv, "wasm-target");
-  const selectedTargets = nullableSetFlag(argv, "selected-targets-json");
-  const selectedProducts = nullableSetFlag(argv, "selected-products-json");
-  if (matrix === "extension-artifacts-native") {
-    printJson(extensionArtifactsNativeMatrix(nativeTarget, selectedTargets ?? undefined, selectedProducts ?? undefined));
-  } else if (matrix === "extension-artifacts-wasix") {
-    printJson(extensionArtifactsWasixMatrix(wasmTarget, selectedProducts ?? undefined));
-  } else {
-    fail(`unsupported matrix query ${matrix}`);
-  }
-}
-
-function usage() {
-  return `usage: tools/graph/ci_plan.mjs [command]
-
-Default command emits GitHub Actions outputs and target/graph/ci-plan.json.
-
-Commands:
-  config
-  jobs-for-affected --tasks-json JSON
-  native-target-subset --jobs-json JSON --tasks-json JSON
-  selected-extension-products --direct-projects-json JSON --tasks-json JSON --jobs-json JSON
-  plan-full [--wasm-target TARGET] [--native-target TARGET] [--mobile-target TARGET]
-  mobile-extension-package-native-targets --jobs-json JSON --selected-targets-json JSON|null
-  matrix extension-artifacts-native|extension-artifacts-wasix [selection flags]
-`;
-}
-
-function main(argv) {
-  const [command, ...rest] = argv;
-  if (command === undefined) {
-    process.exit(emitGithubOutputs());
-  }
-  if (command === "--help" || command === "-h") {
-    console.log(usage());
-  } else if (command === "config") {
-    printJson({
-      baseJobs: sorted(BASE_JOBS),
-      builderJobs: sorted(BUILDER_JOBS),
-      ciJobTargets: CI_JOB_TARGETS,
-      ciJobsConfig: CI_JOBS_CONFIG,
-    });
-  } else if (command === "jobs-for-affected") {
-    printJson(sorted(planJobsForAffected(setFlag(rest, "tasks-json"))));
-  } else if (command === "native-target-subset") {
-    const targets = nativeTargetSubsetForJobs(setFlag(rest, "jobs-json"), setFlag(rest, "tasks-json"));
-    printJson(targets === null ? null : sorted(targets));
-  } else if (command === "selected-extension-products") {
-    const selected = selectedExtensionProductsForPlan(
-      setFlag(rest, "direct-projects-json"),
-      setFlag(rest, "tasks-json"),
-      setFlag(rest, "jobs-json"),
-    );
-    printJson(selected === null ? null : sorted(selected));
-  } else if (command === "plan-full") {
-    printPlanForFullRun(rest);
-  } else if (command === "mobile-extension-package-native-targets") {
-    printJson(mobileExtensionPackageNativeTargets(setFlag(rest, "jobs-json"), nullableSetFlag(rest, "selected-targets-json")));
-  } else if (command === "matrix") {
-    const [matrix, ...matrixRest] = rest;
-    printMatrix(matrixRest, matrix);
-  } else {
-    fail(`unknown command ${command}`);
-  }
-}
-
-if (import.meta.main) {
-  main(Bun.argv.slice(2));
-}
diff --git a/tools/integration/react-native/expo-runner-ios-installed-app.test.sh b/tools/integration/react-native/expo-runner-ios-installed-app.test.sh
deleted file mode 100644
index fb5c41891..000000000
--- a/tools/integration/react-native/expo-runner-ios-installed-app.test.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "must run inside the Oliphaunt git checkout" >&2
-  exit 1
-}
-. "$root/src/sdks/react-native/tools/expo-runner-ios-installed-app.sh"
-. "$root/src/sdks/react-native/tools/expo-runner-reporting.sh"
-
-test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-ios-runner-test.XXXXXX")"
-trap 'rm -rf "$test_root"' EXIT
-scratch_root="$test_root/scratch"
-maestro_flow="$test_root/installed-smoke.yaml"
-app_id="dev.oliphaunt.test"
-runner="smoke"
-mobile_platform="ios"
-timeout_seconds=600
-success_tag="OLIPHAUNT_EXPO_SMOKE_PASS"
-failure_tag="OLIPHAUNT_EXPO_SMOKE_FAIL"
-ios_simulator_log_pid=""
-ios_simulator_log_file="$test_root/simulator.log"
-export CI_HEAD_SHA="$(git rev-parse HEAD)"
-export OLIPHAUNT_MOBILE_E2E_EXPECT_ICU=0
-export OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE=standard
-export FAKE_MAESTRO_STARTED="$test_root/maestro-started"
-export FAKE_MAESTRO_TERMINATED="$test_root/maestro-terminated"
-
-mkdir -p "$scratch_root/reports"
-printf 'appId: dev.oliphaunt.test\n---\n- assertVisible: smoke\n' >"$maestro_flow"
-fake_maestro="$test_root/maestro"
-cat >"$fake_maestro" <<'SH'
-#!/usr/bin/env bash
-trap 'printf "terminated\n" >"$FAKE_MAESTRO_TERMINATED"; exit 143' TERM INT
-printf 'started\n' >"$FAKE_MAESTRO_STARTED"
-while :; do sleep 0.1; done
-SH
-chmod +x "$fake_maestro"
-
-maestro_binary() { printf '%s\n' "$fake_maestro"; }
-ios_simulator_log_capture_is_alive() { return 0; }
-latest_ios_simulator_capture_tag() {
-  [ "$1" = "$failure_tag" ] || return 0
-  local attempts=100
-  while [ "$attempts" -gt 0 ] && [ ! -f "$FAKE_MAESTRO_STARTED" ]; do
-    command sleep 0.01
-    attempts=$((attempts - 1))
-  done
-  printf '%s fixture\n' "$failure_tag"
-}
-
-set +e
-run_maestro_installed_smoke simulator-1 >"$test_root/fail.stdout" 2>"$test_root/fail.stderr"
-status=$?
-set -e
-[ "$status" -eq 2 ]
-[ -f "$FAKE_MAESTRO_TERMINATED" ]
-grep -Fq "$failure_tag" "$scratch_root/reports/maestro-authoritative-failure.txt"
-
-receipt_json="$(node - "$root/src/extensions/generated/sdk/extensions.json" <<'NODE'
-const fs = require('node:fs');
-const metadata = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
-const extensions = (metadata.extensions ?? []).map(row => row['sql-name']).sort();
-process.stdout.write(JSON.stringify({
-  schema: 'oliphaunt-expo-smoke-pass-v4',
-  runner: 'smoke',
-  platform: 'ios',
-  extensionCount: extensions.length,
-  allExtensionsActivated: true,
-  extensionCatalogComplete: true,
-  pgTextsearchEnglishBm25: extensions.includes('pg_textsearch'),
-  extensionCatalogSha256: metadata['extension-catalog-sha256'],
-  catalogProfile: 'standard',
-  icuRuntimeProof: false,
-}));
-NODE
-)"
-write_runner_report "$success_tag $receipt_json"
-verify_mobile_e2e_smoke_receipt ios "$scratch_root"
-
-node - "$scratch_root/reports/smoke-extension-receipt.json" <<'NODE'
-const fs = require('node:fs');
-const file = process.argv[2];
-const receipt = JSON.parse(fs.readFileSync(file, 'utf8'));
-receipt.candidateTree = '0'.repeat(40);
-fs.writeFileSync(file, `${JSON.stringify(receipt)}\n`);
-NODE
-if verify_mobile_e2e_smoke_receipt ios "$scratch_root" >/dev/null 2>&1; then
-  echo "tampered mobile receipt was accepted" >&2
-  exit 1
-fi
-
-echo "iOS runner failure and receipt checks passed"
diff --git a/tools/integration/react-native/expo-runner-workspace.test.sh b/tools/integration/react-native/expo-runner-workspace.test.sh
deleted file mode 100644
index 6ecb5297c..000000000
--- a/tools/integration/react-native/expo-runner-workspace.test.sh
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-root="$(git rev-parse --show-toplevel 2>/dev/null)" || {
-  echo "must run inside the Oliphaunt git checkout" >&2
-  exit 1
-}
-product_tools="$root/src/sdks/react-native/tools"
-fixture="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-rn-package-inputs.XXXXXX")"
-trap 'rm -rf "$fixture"' EXIT
-
-fixture_root="$fixture/repo"
-rn_dir="$fixture_root/src/sdks/react-native"
-source_example_dir="$fixture_root/examples/react-native-expo"
-scratch_root="$fixture/scratch"
-package_work="$scratch_root/src/sdks/react-native"
-mkdir -p \
-  "$rn_dir/src" \
-  "$rn_dir/node_modules" \
-  "$source_example_dir" \
-  "$fixture_root/src/extensions/generated/sdk"
-printf '{"name":"fixture"}\n' >"$rn_dir/package.json"
-printf 'export const fixture = 1;\n' >"$rn_dir/src/index.ts"
-printf '{"name":"example"}\n' >"$source_example_dir/package.json"
-printf '{"extensions":[]}\n' >"$fixture_root/src/extensions/generated/sdk/extensions.json"
-printf '{"extensions":[]}\n' >"$fixture_root/src/extensions/generated/sdk/ios-static-dependencies.json"
-
-# shellcheck source=src/sdks/react-native/tools/expo-runner-workspace.sh
-. "$product_tools/expo-runner-workspace.sh"
-root="$fixture_root"
-need_cmd() { command -v "$1" >/dev/null; }
-write_scratch_pnpm_workspace() { mkdir -p "$scratch_root"; }
-
-prepare_react_native_package_worktree
-cmp "$root/src/extensions/generated/sdk/extensions.json" "$package_work/src/generated/extensions.json"
-cmp "$root/src/extensions/generated/sdk/ios-static-dependencies.json" "$package_work/src/generated/ios-static-dependencies.json"
-[ -L "$package_work/node_modules" ]
-
-fingerprint() {
-  node "$product_tools/react-native-package-inputs.mjs" \
-    --root "$root" \
-    --rn-dir "$rn_dir" \
-    --example-package "$source_example_dir/package.json"
-}
-
-assert_fingerprint_changes() {
-  local file="$1"
-  local before after
-  before="$(fingerprint)"
-  printf '\nmutation\n' >>"$file"
-  touch -t 200001010000 "$file"
-  after="$(fingerprint)"
-  [ "$before" != "$after" ] || {
-    echo "package fingerprint ignored changed input: $file" >&2
-    exit 1
-  }
-}
-
-assert_fingerprint_changes "$rn_dir/src/index.ts"
-assert_fingerprint_changes "$root/src/extensions/generated/sdk/extensions.json"
-assert_fingerprint_changes "$root/src/extensions/generated/sdk/ios-static-dependencies.json"
-assert_fingerprint_changes "$source_example_dir/package.json"
-
-first="$(fingerprint)"
-second="$(fingerprint)"
-[ "$first" = "$second" ] || {
-  echo "package fingerprint is nondeterministic" >&2
-  exit 1
-}
-
-echo "React Native source-package staging and content fingerprint tests passed"
diff --git a/tools/integration/react-native/moon.yml b/tools/integration/react-native/moon.yml
deleted file mode 100644
index c1dbeb252..000000000
--- a/tools/integration/react-native/moon.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "react-native-runner-integration"
-language: "bash"
-layer: "tool"
-stack: "infrastructure"
-tags: ["integration", "react-native"]
-dependsOn:
-  - id: "extensions"
-    scope: "build"
-  - "oliphaunt-react-native"
-
-project:
-  title: "React Native Runner Integration"
-  description: "Failure, receipt, Gradle-limit, and package-staging checks for the mobile runners."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-
-tasks:
-  unit:
-    tags: ["quality", "unit"]
-    script: |
-      set -e
-      bash tools/integration/react-native/expo-android-gradle-limits.test.sh
-      bash tools/integration/react-native/expo-runner-android-device.test.sh
-      bash tools/integration/react-native/expo-runner-ios-installed-app.test.sh
-      bash tools/integration/react-native/expo-runner-workspace.test.sh
-    inputs:
-      - project: "extensions"
-        group: "sdk-metadata"
-      - "/src/sdks/react-native/tools/**/*"
-      - "**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
diff --git a/tools/integration/wasix-ts/moon.yml b/tools/integration/wasix-ts/moon.yml
deleted file mode 100644
index c0fb23bb4..000000000
--- a/tools/integration/wasix-ts/moon.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "wasix-ts-integration"
-language: "typescript"
-layer: "tool"
-stack: "infrastructure"
-tags: ["integration", "wasix", "typescript"]
-dependsOn:
-  - id: "shared-test-fixtures"
-    scope: "development"
-  - "liboliphaunt-wasix"
-  - "oliphaunt-wasix-napi"
-  - "oliphaunt-wasix-tools-ts"
-  - "oliphaunt-wasix-ts"
-
-project:
-  title: "WASIX TypeScript Integration"
-  description: "Installed-package runtime checks across the WASIX TypeScript packages and runtime carriers."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/core"
-
-tasks:
-  runtime:
-    tags: ["integration", "runtime", "ci-wasix-ts-sdk-package"]
-    script: |
-      set -e
-      node tools/integration/wasix-ts/smoke-node.mjs --runtime node
-      node tools/integration/wasix-ts/smoke-node.mjs --runtime bun
-      node tools/integration/wasix-ts/smoke-node.mjs --runtime deno
-      node tools/integration/wasix-ts/smoke-node.mjs --runtime electron
-      node tools/integration/wasix-ts/smoke-browser.mjs --postgis-worker
-      node tools/integration/wasix-ts/smoke-tools-host.mjs --runtime node
-      tools/dev/bun.sh tools/integration/wasix-ts/smoke-tools-host.mjs --runtime bun
-      tools/dev/deno.sh run --allow-all tools/integration/wasix-ts/smoke-tools-host.mjs --runtime deno
-      node tools/integration/wasix-ts/smoke-browser.mjs --package-only
-    deps:
-      - "liboliphaunt-wasix:runtime-portable"
-      - "oliphaunt-wasix-tools-ts:package"
-      - "oliphaunt-wasix-ts:package"
-      - "release-tools:wasix-napi-runtime"
-    inputs:
-      - "@group(legal-files)"
-      - "@group(pnpm-workspace)"
-      - "/benchmarks/wasix/**/*"
-      - "/examples/browser-wasix/**/*"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - "**/*"
-      - "/tools/dev/bun.sh"
-      - "/tools/dev/deno.sh"
-      - "/tools/perf/wasix-browser/*.mjs"
-      - "/tools/perf/wasix-node/installed-closure.mjs"
-      - "/tools/perf/wasix-node/plan.mjs"
-      - "/tools/release/wasix-*.mjs"
-    options:
-      cache: false
-      runFromWorkspaceRoot: true
-      runInCI: true
diff --git a/tools/integration/wasix-ts/packed-node-fixture.mjs b/tools/integration/wasix-ts/packed-node-fixture.mjs
deleted file mode 100644
index 262f8c404..000000000
--- a/tools/integration/wasix-ts/packed-node-fixture.mjs
+++ /dev/null
@@ -1,659 +0,0 @@
-import { execFile } from 'node:child_process';
-import { createHash } from 'node:crypto';
-import { cp, mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
-import { arch, platform } from 'node:os';
-import { dirname, isAbsolute, resolve } from 'node:path';
-import { fileURLToPath, pathToFileURL } from 'node:url';
-import { promisify } from 'node:util';
-import { readPortableArchiveEntries } from '../../../src/shared/artifact-packaging/portable-archive.mjs';
-import { WASIX_RUNTIME_NPM_ASSET_PATHS } from '../../release/wasix-runtime-npm-contract.mjs';
-import {
-  renderWasixRuntimeDescriptorModule,
-  renderWasixRuntimeDescriptorTypes,
-} from '../../release/wasix-runtime-npm-descriptor.mjs';
-import { prepareWasixToolsTypescriptPackage } from '../../release/wasix-tools-typescript-package.mjs';
-import { prepareWasixTypescriptPackage } from '../../release/wasix-typescript-package.mjs';
-import { portableCommand } from '../../../src/runtimes/wasix-napi/tools/portable-command.mjs';
-
-const execFileAsync = promisify(execFile);
-const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
-const packageRoot = resolve(repositoryRoot, 'src/bindings/wasix-ts');
-const assetRoot = resolve(repositoryRoot, 'target/oliphaunt-wasix/assets');
-const buildOutputsFile = resolve(
-  repositoryRoot,
-  'target/oliphaunt-wasix/wasix-build/build/outputs.json',
-);
-const nativeCarrierRoot = resolve(repositoryRoot, 'target/oliphaunt-wasix-napi/npm-packages');
-const databaseRootContractFile = resolve(
-  repositoryRoot,
-  'src/shared/fixtures/storage/database-root.json',
-);
-
-export async function createPackedWasixConsumer({
-  scratch,
-  consumerName = 'oliphaunt-wasix-node-consumer',
-  includePgtap = false,
-  includeTools = false,
-  includeNative = true,
-  useStubRuntime = false,
-  packageManager = 'pnpm',
-}) {
-  if (typeof scratch !== 'string' || !isAbsolute(scratch)) {
-    throw new Error(
-      'packed WASIX Node/Bun/Deno/Electron host fixture requires an absolute scratch directory',
-    );
-  }
-  if (!['npm', 'pnpm'].includes(packageManager)) {
-    throw new Error(`packed WASIX host fixture does not support package manager ${packageManager}`);
-  }
-  const releaseVersions = JSON.parse(
-    await readFile(resolve(repositoryRoot, '.release-please-manifest.json'), 'utf8'),
-  );
-  const runtimeVersion = releaseVersions['src/runtimes/liboliphaunt/wasix'];
-  const extensionVersion = releaseVersions['src/extensions/external/pgtap'];
-  const tarballs = resolve(scratch, 'tarballs');
-  await mkdir(tarballs, { recursive: true });
-
-  const binding = await packBinding({ scratch, tarballs });
-  const nativeCarrier = includeNative
-    ? await findNativeCarrier({
-        nativeVersion: binding.nativeVersion,
-        runtimeVersion,
-      })
-    : undefined;
-  const toolsCarrier = includeTools
-    ? await packToolsCarrier({ scratch, tarballs, runtimeVersion })
-    : undefined;
-  const toolsFacade = includeTools
-    ? await packToolsFacade({ scratch, tarballs, bindingVersion: binding.version })
-    : undefined;
-  if (includePgtap && useStubRuntime) {
-    throw new Error('the packed WASIX stub runtime cannot carry extensions');
-  }
-  const runtime = useStubRuntime
-    ? await packStubRuntime({ scratch, tarballs, runtimeVersion })
-    : await packRuntime({ scratch, tarballs, runtimeVersion });
-  const extension = includePgtap
-    ? await packPgtap({ scratch, tarballs, runtimeVersion, extensionVersion })
-    : undefined;
-  const consumer = resolve(scratch, 'consumer');
-  await mkdir(consumer, { recursive: true });
-  const dependencies = {
-    [runtime.name]: pathToFileURL(runtime.file).href,
-    [binding.name]: pathToFileURL(binding.file).href,
-  };
-  if (nativeCarrier !== undefined) {
-    dependencies[nativeCarrier.name] = pathToFileURL(nativeCarrier.file).href;
-  }
-  if (extension !== undefined) {
-    dependencies[extension.name] = pathToFileURL(extension.file).href;
-  }
-  if (toolsCarrier !== undefined) {
-    dependencies[toolsCarrier.name] = pathToFileURL(toolsCarrier.file).href;
-  }
-  if (toolsFacade !== undefined) {
-    dependencies[toolsFacade.name] = pathToFileURL(toolsFacade.file).href;
-  }
-  await writeJson(resolve(consumer, 'package.json'), {
-    name: consumerName,
-    version: '0.0.0',
-    private: true,
-    type: 'module',
-    dependencies,
-  });
-  const localPackages = [
-    runtime,
-    binding,
-    nativeCarrier,
-    extension,
-    toolsCarrier,
-    toolsFacade,
-  ].filter(Boolean);
-  await writeFile(
-    resolve(consumer, 'pnpm-workspace.yaml'),
-    `packages:\n  - .\noverrides:\n${localPackages
-      .map((candidate) => `  '${candidate.name}': ${pathToFileURL(candidate.file).href}`)
-      .join('\n')}\n`,
-  );
-  if (packageManager === 'pnpm') {
-    await runFixtureCommand(
-      'pnpm',
-      ['install', '--ignore-scripts', '--no-frozen-lockfile'],
-      consumer,
-    );
-  } else {
-    await runFixtureCommand(
-      'npm',
-      ['install', '--ignore-scripts', '--no-audit', '--no-fund', '--package-lock=false'],
-      consumer,
-    );
-  }
-  return {
-    consumer,
-    packages: {
-      binding,
-      runtime,
-      ...(nativeCarrier === undefined ? {} : { nativeCarrier }),
-      ...(extension === undefined ? {} : { extension }),
-      ...(toolsCarrier === undefined ? {} : { toolsCarrier }),
-      ...(toolsFacade === undefined ? {} : { toolsFacade }),
-    },
-    packageManager,
-  };
-}
-
-async function packStubRuntime({ scratch, tarballs, runtimeVersion }) {
-  requireReleaseVersion(runtimeVersion, 'src/runtimes/liboliphaunt/wasix');
-  const identity = await wasixPhysicalIdentity();
-  const staging = resolve(scratch, 'runtime');
-  await mkdir(staging);
-  const emptyByteSha256 = sha256(Buffer.of(0));
-  await writeFile(
-    resolve(staging, 'index.js'),
-    `export const POSTGRES_MAJOR = ${JSON.stringify(identity.postgresMajor)};
-export const PHYSICAL_FORMAT = ${JSON.stringify(identity.physicalFormat)};
-
-const byte = new URL('data:application/octet-stream;base64,AA==');
-export default Object.freeze({
-  schema: 'oliphaunt-wasix-runtime-v2',
-  runtime: 'wasix',
-  product: 'liboliphaunt-wasix',
-  version: ${JSON.stringify(runtimeVersion)},
-  runtimeArchive: {
-    archive: 'runtime.tar.zst',
-    sha256: ${JSON.stringify(emptyByteSha256)},
-    size: 1,
-    source: byte,
-  },
-  standardSeedArchive: {
-    archive: 'cluster-seeds/standard.tar.zst',
-    sha256: ${JSON.stringify(emptyByteSha256)},
-    size: 1,
-    source: byte,
-  },
-  standardSeedManifest: {
-    sha256: ${JSON.stringify(emptyByteSha256)},
-    size: 1,
-    source: byte,
-  },
-  manifest: {
-    sha256: ${JSON.stringify(emptyByteSha256)},
-    size: 1,
-    source: byte,
-  },
-});
-`,
-  );
-  await writeJson(resolve(staging, 'package.json'), {
-    name: '@oliphaunt/liboliphaunt-wasix',
-    version: runtimeVersion,
-    type: 'module',
-    exports: { '.': './index.js' },
-  });
-  return pack(staging, tarballs);
-}
-
-export async function runFixtureCommand(command, args, cwd, timeout = 120_000, extraEnv = {}) {
-  const invocation = portableCommand(command, args);
-  return execFileAsync(invocation.command, invocation.args, {
-    cwd,
-    env: {
-      ...process.env,
-      NPM_CONFIG_IGNORE_SCRIPTS: 'true',
-      PNPM_CONFIG_IGNORE_SCRIPTS: 'true',
-      ...extraEnv,
-    },
-    maxBuffer: 64 * 1024 * 1024,
-    timeout,
-  });
-}
-
-async function packBinding({ scratch, tarballs }) {
-  const staging = resolve(scratch, 'binding');
-  await mkdir(staging);
-  for (const name of ['package.json', 'README.md', 'ARCHITECTURE.md', 'CHANGELOG.md', 'lib']) {
-    await cp(resolve(packageRoot, name), resolve(staging, name), { recursive: true });
-  }
-  prepareWasixTypescriptPackage(staging);
-  const manifest = JSON.parse(await readFile(resolve(staging, 'package.json'), 'utf8'));
-  const nativeVersion = manifest.oliphaunt?.wasixNapiVersion;
-  requireReleaseVersion(nativeVersion, 'oliphaunt-wasix-napi');
-  return { ...(await pack(staging, tarballs)), nativeVersion };
-}
-
-async function findNativeCarrier({ nativeVersion, runtimeVersion }) {
-  const expected = nativeCarrierIdentity(platform(), arch());
-  let names;
-  try {
-    names = (await readdir(nativeCarrierRoot)).filter((name) => name.endsWith('.tgz')).sort();
-  } catch (error) {
-    if (error?.code !== 'ENOENT') throw error;
-    throw new Error(
-      `packed WASIX Node/Bun/Deno/Electron smoke requires ${expected.name} ${nativeVersion} under ${nativeCarrierRoot}`,
-    );
-  }
-
-  const matches = [];
-  for (const filename of names) {
-    const file = resolve(nativeCarrierRoot, filename);
-    const entries = readPortableArchiveEntries(file);
-    const manifestEntry = entries.get('package/package.json');
-    if (!manifestEntry?.isFile || manifestEntry.isSymbolicLink) continue;
-    const manifest = JSON.parse(Buffer.from(manifestEntry.data()).toString('utf8'));
-    if (manifest.name !== expected.name || manifest.version !== nativeVersion) continue;
-    const artifactProvenance = validateNativeCarrierArchive(
-      file,
-      entries,
-      manifest,
-      expected,
-      runtimeVersion,
-    );
-    const bytes = await readFile(file);
-    matches.push({
-      file,
-      name: manifest.name,
-      version: manifest.version,
-      target: expected.target,
-      sha256: sha256(bytes),
-      size: bytes.length,
-      manifest,
-      artifactProvenance,
-      artifactProvenanceMember: 'package/artifact-provenance.json',
-    });
-  }
-  if (matches.length !== 1) {
-    throw new Error(
-      `packed WASIX Node/Bun/Deno/Electron smoke requires exactly one ${expected.name} ${nativeVersion} tarball under ${nativeCarrierRoot}; found ${matches.length}`,
-    );
-  }
-  return matches[0];
-}
-
-function validateNativeCarrierArchive(file, entries, manifest, expected, runtimeVersion) {
-  const label = file.slice(file.lastIndexOf('/') + 1);
-  if (
-    manifest.oliphaunt?.target !== expected.target ||
-    manifest.oliphaunt?.runtimeProduct !== 'liboliphaunt-wasix' ||
-    manifest.oliphaunt?.runtimeVersion !== runtimeVersion ||
-    manifest.oliphaunt?.addonAbiVersion !== 1 ||
-    manifest.oliphaunt?.nodeApiVersion !== 8 ||
-    JSON.stringify(manifest.oliphaunt?.profiles) !== JSON.stringify(['standard', 'icu'])
-  ) {
-    throw new Error(`${label} has incompatible WASIX Node-API carrier metadata`);
-  }
-  const provenanceEntry = entries.get('package/artifact-provenance.json');
-  if (!provenanceEntry?.isFile || provenanceEntry.isSymbolicLink) {
-    throw new Error(`${label} omits native artifact provenance`);
-  }
-  const provenance = JSON.parse(Buffer.from(provenanceEntry.data()).toString('utf8'));
-  if (
-    provenance.schema !== 'oliphaunt-wasix-napi-provenance-v1' ||
-    provenance.product !== 'oliphaunt-wasix-napi' ||
-    provenance.target !== expected.target ||
-    !/^[0-9a-f]{40}$/.test(provenance.artifactSourceSha ?? '')
-  ) {
-    throw new Error(`${label} has invalid native artifact provenance`);
-  }
-  if (
-    provenance.build?.cargoProfile !== 'release' ||
-    provenance.build?.incremental !== false ||
-    provenance.build?.codegenUnits !== 1 ||
-    provenance.build?.lto !== 'thin' ||
-    provenance.build?.strip !== 'symbols' ||
-    JSON.stringify(provenance.build?.features) !== JSON.stringify(['release']) ||
-    provenance.build?.targetTriple !== provenance.buildInputs?.targetTriple
-  ) {
-    throw new Error(`${label} has incompatible optimized native build provenance`);
-  }
-  const binary = 'oliphaunt_wasix_napi.node';
-  const entry = entries.get(`package/prebuilds/${binary}`);
-  if (!entry?.isFile || entry.isSymbolicLink || entry.size <= 0) {
-    throw new Error(`${label} omits non-empty ${binary}`);
-  }
-  const digest = sha256(Buffer.from(entry.data()));
-  if (
-    provenance.binary?.filename !== binary ||
-    provenance.binary?.sha256 !== digest ||
-    Object.hasOwn(provenance, 'binaries')
-  ) {
-    throw new Error(`${label} ${binary} differs from native artifact provenance`);
-  }
-  return provenance;
-}
-
-function nativeCarrierIdentity(currentPlatform, currentArch) {
-  if (currentPlatform === 'darwin' && currentArch === 'arm64') {
-    return { name: '@oliphaunt/wasix-napi-darwin-arm64', target: 'macos-arm64' };
-  }
-  if (currentPlatform === 'linux' && currentArch === 'arm64') {
-    return { name: '@oliphaunt/wasix-napi-linux-arm64-gnu', target: 'linux-arm64-gnu' };
-  }
-  if (currentPlatform === 'linux' && currentArch === 'x64') {
-    return { name: '@oliphaunt/wasix-napi-linux-x64-gnu', target: 'linux-x64-gnu' };
-  }
-  if (currentPlatform === 'win32' && currentArch === 'x64') {
-    return { name: '@oliphaunt/wasix-napi-win32-x64-msvc', target: 'windows-x64-msvc' };
-  }
-  throw new Error(
-    `packed WASIX Node/Bun/Deno/Electron smoke has no native carrier for ${currentPlatform}/${currentArch}`,
-  );
-}
-
-async function packToolsCarrier({ scratch, tarballs, runtimeVersion }) {
-  requireReleaseVersion(runtimeVersion, 'src/runtimes/liboliphaunt/wasix');
-  const staging = resolve(scratch, 'tools-carrier');
-  const assets = resolve(staging, 'assets');
-  await mkdir(assets, { recursive: true });
-  const manifest = JSON.parse(await readFile(resolve(assetRoot, 'manifest.json'), 'utf8'));
-  const descriptors = {};
-  for (const [field, key, filename] of [
-    ['pgDump', 'pg-dump', 'pg_dump.wasix.wasm'],
-    ['psql', 'psql', 'psql.wasix.wasm'],
-  ]) {
-    const row = manifest[key];
-    const bytes = await readFile(resolve(assetRoot, row.path));
-    requireDigest(bytes, row.sha256, row.path);
-    if (bytes.length !== row.size) throw new Error(`${row.path} size differs from its manifest`);
-    await writeFile(resolve(assets, filename), bytes);
-    descriptors[field] = {
-      name: row.name,
-      sha256: row.sha256,
-      size: row.size,
-      filename,
-    };
-  }
-  const tool = ({ name, sha256: digest, size, filename }) =>
-    `Object.freeze({ name: ${JSON.stringify(name)}, sha256: ${JSON.stringify(digest)}, size: ${size}, source: new URL('./assets/${filename}', import.meta.url).href })`;
-  await writeFile(
-    resolve(staging, 'index.js'),
-    `export default Object.freeze({\n  schema: 'oliphaunt-wasix-tools-v1',\n  product: 'oliphaunt-wasix-tools',\n  version: ${JSON.stringify(runtimeVersion)},\n  runtimeProduct: 'liboliphaunt-wasix',\n  runtimeVersion: ${JSON.stringify(runtimeVersion)},\n  pgDump: ${tool(descriptors.pgDump)},\n  psql: ${tool(descriptors.psql)},\n});\n`,
-  );
-  await writeJson(resolve(staging, 'package.json'), {
-    name: '@oliphaunt/liboliphaunt-wasix-tools',
-    version: runtimeVersion,
-    type: 'module',
-    exports: { '.': './index.js' },
-  });
-  return pack(staging, tarballs);
-}
-
-async function packToolsFacade({ scratch, tarballs, bindingVersion }) {
-  const source = resolve(packageRoot, 'tools-package');
-  const staging = resolve(scratch, 'tools-facade');
-  await mkdir(staging);
-  for (const name of ['package.json', 'README.md', 'lib']) {
-    await cp(resolve(source, name), resolve(staging, name), { recursive: true });
-  }
-  await cp(resolve(packageRoot, 'CHANGELOG.md'), resolve(staging, 'CHANGELOG.md'));
-  prepareWasixToolsTypescriptPackage(staging, bindingVersion);
-  return pack(staging, tarballs);
-}
-
-async function packRuntime({ scratch, tarballs, runtimeVersion }) {
-  requireReleaseVersion(runtimeVersion, 'src/runtimes/liboliphaunt/wasix');
-  const identity = await wasixPhysicalIdentity();
-  const staging = resolve(scratch, 'runtime');
-  const assets = resolve(staging, 'assets');
-  await mkdir(assets, { recursive: true });
-  const manifest = JSON.parse(await readFile(resolve(assetRoot, 'manifest.json'), 'utf8'));
-  const manifestPostgresMajor = Number(manifest.runtime?.['postgres-version']?.split('.')[0]);
-  if (manifestPostgresMajor !== identity.postgresMajor) {
-    throw new Error('WASIX runtime manifest disagrees with the shared physical identity');
-  }
-  const coreManifest = Buffer.from(JSON.stringify({ ...manifest, extensions: [] }));
-  const runtimeSource = resolve(assetRoot, manifest.runtime.archive);
-  const standardSeed = manifest['cluster-seeds'].standard;
-  const seedSource = resolve(assetRoot, standardSeed.archive);
-  const seedManifestSource = resolve(assetRoot, standardSeed.manifest);
-  const runtimeBytes = await readFile(runtimeSource);
-  const seedBytes = await readFile(seedSource);
-  const seedManifestBytes = await readFile(seedManifestSource);
-  requireDigest(runtimeBytes, manifest.runtime.sha256, manifest.runtime.archive);
-  requireDigest(seedBytes, standardSeed.sha256, standardSeed.archive);
-  const build = await runtimeBuildProvenance(manifest);
-  await cp(runtimeSource, resolve(staging, WASIX_RUNTIME_NPM_ASSET_PATHS.runtimeArchive));
-  await cp(seedSource, resolve(staging, WASIX_RUNTIME_NPM_ASSET_PATHS.standardSeedArchive));
-  await cp(
-    seedManifestSource,
-    resolve(staging, WASIX_RUNTIME_NPM_ASSET_PATHS.standardSeedManifest),
-  );
-  await writeFile(resolve(staging, WASIX_RUNTIME_NPM_ASSET_PATHS.manifest), coreManifest);
-  const descriptor = {
-    schema: 'oliphaunt-wasix-runtime-v2',
-    runtime: 'wasix',
-    product: 'liboliphaunt-wasix',
-    version: runtimeVersion,
-    runtimeArchive: {
-      archive: manifest.runtime.archive,
-      sha256: sha256(runtimeBytes),
-      size: runtimeBytes.length,
-    },
-    standardSeedArchive: {
-      archive: standardSeed.archive,
-      sha256: sha256(seedBytes),
-      size: seedBytes.length,
-    },
-    standardSeedManifest: {
-      sha256: sha256(seedManifestBytes),
-      size: seedManifestBytes.length,
-    },
-    manifest: { sha256: sha256(coreManifest), size: coreManifest.length },
-  };
-  await writeFile(resolve(staging, 'index.js'), renderWasixRuntimeDescriptorModule(descriptor));
-  await writeFile(resolve(staging, 'index.d.ts'), renderWasixRuntimeDescriptorTypes());
-  await writeJson(resolve(staging, 'package.json'), {
-    name: '@oliphaunt/liboliphaunt-wasix',
-    version: runtimeVersion,
-    type: 'module',
-    exports: {
-      '.': { types: './index.d.ts', import: './index.js', default: './index.js' },
-    },
-  });
-  return { ...(await pack(staging, tarballs)), build };
-}
-
-async function wasixPhysicalIdentity() {
-  const contract = JSON.parse(await readFile(databaseRootContractFile, 'utf8'));
-  const postgresMajor = contract.postgresMajor;
-  const physicalFormat = contract.families?.wasix?.physicalFormat;
-  if (!Number.isInteger(postgresMajor) || typeof physicalFormat !== 'string' || !physicalFormat) {
-    throw new Error('shared database-root fixture has no valid WASIX physical identity');
-  }
-  return { postgresMajor, physicalFormat };
-}
-
-export async function runtimeBuildProvenance(manifest) {
-  const bytes = await readFile(buildOutputsFile);
-  let outputs;
-  try {
-    outputs = JSON.parse(bytes.toString('utf8'));
-  } catch (error) {
-    throw new Error(`WASIX build outputs are invalid JSON: ${describeError(error)}`);
-  }
-  const runtimeRows = Array.isArray(outputs.modules)
-    ? outputs.modules.filter((row) => row?.kind === 'runtime' && row?.name === 'runtime:oliphaunt')
-    : [];
-  const runtime = runtimeRows.length === 1 ? runtimeRows[0] : undefined;
-  const profileText = outputs['build-profile'];
-  const profile = parseBuildProfile(profileText);
-  if (
-    outputs['format-version'] !== 1 ||
-    outputs['source-fingerprint'] !== manifest['source-fingerprint'] ||
-    outputs['source-lane'] !== manifest['source-lane'] ||
-    outputs['postgres-version'] !== manifest.runtime?.['postgres-version'] ||
-    runtime?.sha256 !== manifest.runtime?.['module-sha256'] ||
-    manifest['cluster-seeds']?.standard?.['runtime-module-sha256'] !== runtime?.sha256
-  ) {
-    throw new Error('WASIX build outputs do not describe the packaged runtime assets');
-  }
-  return {
-    schema: 'oliphaunt-wasix-build-provenance-v1',
-    outputs: { sha256: sha256(bytes), size: bytes.length },
-    formatVersion: outputs['format-version'],
-    postgresVersion: outputs['postgres-version'],
-    sourceLane: outputs['source-lane'],
-    sourceFingerprint: outputs['source-fingerprint'],
-    runtimeModuleSha256: runtime.sha256,
-    configuration: profile,
-    buildProfile: {
-      text: profileText,
-      sha256: sha256(Buffer.from(profileText)),
-      size: Buffer.byteLength(profileText),
-    },
-  };
-}
-
-export function parseBuildProfile(value) {
-  if (typeof value !== 'string' || value.length === 0) {
-    throw new Error('WASIX build outputs have no build-profile signature');
-  }
-  const fields = new Map();
-  for (const line of value.split('\n')) {
-    if (line.length === 0) continue;
-    const separator = line.indexOf('=');
-    if (separator < 1) throw new Error('WASIX build-profile signature is malformed');
-    const key = line.slice(0, separator);
-    if (fields.has(key)) throw new Error(`WASIX build-profile repeats ${key}`);
-    fields.set(key, line.slice(separator + 1));
-  }
-  const configuration = {};
-  for (const [field, key] of Object.entries({
-    profile: 'profile',
-    cflags: 'cflags',
-    ldflags: 'ldflags',
-    configureWasmOpt: 'configure_wasm_opt',
-    buildWasmOpt: 'build_wasm_opt',
-    wasmOptFlags: 'wasm_opt_flags',
-    wasmOptSuppressDefault: 'wasm_opt_suppress_default',
-    wasmOptPreserveUnoptimized: 'wasm_opt_preserve_unoptimized',
-    compilerFlags: 'compiler_flags',
-    linkerFlags: 'linker_flags',
-  })) {
-    if (!fields.has(key)) throw new Error(`WASIX build-profile omits ${key}`);
-    configuration[field] = fields.get(key);
-  }
-  return configuration;
-}
-
-async function packPgtap({ scratch, tarballs, runtimeVersion, extensionVersion }) {
-  requireReleaseVersion(extensionVersion, 'src/extensions/external/pgtap');
-  const staging = resolve(scratch, 'pgtap');
-  const assets = resolve(staging, 'assets');
-  await mkdir(assets, { recursive: true });
-  const manifest = JSON.parse(await readFile(resolve(assetRoot, 'manifest.json'), 'utf8'));
-  const row = manifest.extensions.find((candidate) => candidate['sql-name'] === 'pgtap');
-  if (row === undefined) throw new Error('WASIX manifest has no pgtap carrier');
-  await cp(resolve(assetRoot, row.archive), resolve(assets, 'pgtap.tar.zst'));
-  const lifecycle = row.lifecycle;
-  const carrier = {
-    product: 'oliphaunt-extension-pgtap',
-    version: extensionVersion,
-    sqlName: 'pgtap',
-    archive: row.archive,
-    sha256: row.sha256,
-    size: row.size,
-    install: {
-      schema: 'oliphaunt-wasix-extension-install-v1',
-      name: row.name,
-      nativeModule: null,
-      nativeModules: [],
-      dependencies: row.dependencies,
-      coreExportsRequired: row['core-exports-required'],
-      loadOrder: row['load-order'],
-      lifecycle: {
-        createExtension: lifecycle['create-extension'],
-        createSchema: lifecycle['create-schema'],
-        loadSql: lifecycle['load-sql'],
-        postCreateSql: lifecycle['post-create-sql'],
-        startupConfig: lifecycle['startup-config'],
-        preloadRequired: lifecycle['preload-required'],
-        restartRequired: lifecycle['restart-required'],
-        sharedMemoryRequired: lifecycle['shared-memory-required'],
-      },
-      installedFiles: row['installed-files'],
-      unresolvedImports: row['unresolved-imports'],
-    },
-  };
-  const descriptor = {
-    schema: 'oliphaunt-wasix-extension-v1',
-    runtime: 'wasix',
-    product: carrier.product,
-    version: carrier.version,
-    compatibility: {
-      extensionRuntimeContract: 'oliphaunt-extension-runtime-contract-v1',
-      postgresMajor: manifest.runtime['postgres-version'].split('.')[0],
-      wasixRuntimeProduct: 'liboliphaunt-wasix',
-      wasixRuntimeVersion: runtimeVersion,
-    },
-    sqlName: 'pgtap',
-    carriers: [carrier],
-  };
-  await writeFile(
-    resolve(staging, 'index.js'),
-    `const descriptor = ${JSON.stringify(descriptor, null, 2)};
-descriptor.carriers[0].source = new URL('./assets/pgtap.tar.zst', import.meta.url);
-export default descriptor;
-`,
-  );
-  await writeJson(resolve(staging, 'package.json'), {
-    name: '@oliphaunt/extension-pgtap-wasix',
-    version: extensionVersion,
-    type: 'module',
-    exports: { '.': './index.js' },
-  });
-  return pack(staging, tarballs);
-}
-
-async function pack(directory, tarballs) {
-  const manifest = JSON.parse(await readFile(resolve(directory, 'package.json'), 'utf8'));
-  const { stdout } = await runFixtureCommand(
-    'pnpm',
-    ['pack', '--pack-destination', tarballs, '--json'],
-    directory,
-    120_000,
-    { PNPM_CONFIG_NODE_LINKER: 'hoisted' },
-  );
-  const result = stdout.trim() === '' ? undefined : JSON.parse(stdout);
-  const reportedFilename = Array.isArray(result) ? result[0]?.filename : result?.filename;
-  const filename =
-    typeof reportedFilename === 'string'
-      ? reportedFilename
-      : resolve(
-          tarballs,
-          `${manifest.name.replace(/^@/u, '').replaceAll('/', '-')}-${manifest.version}.tgz`,
-        );
-  const file = resolve(directory, filename);
-  const bytes = await readFile(file);
-  return {
-    file,
-    name: manifest.name,
-    version: manifest.version,
-    sha256: sha256(bytes),
-    size: bytes.length,
-  };
-}
-
-async function writeJson(file, value) {
-  await writeFile(file, `${JSON.stringify(value, null, 2)}\n`);
-}
-
-function requireReleaseVersion(value, component) {
-  if (typeof value !== 'string' || !/^\d+\.\d+\.\d+$/u.test(value)) {
-    throw new Error(`release manifest has no exact version for ${component}`);
-  }
-}
-
-function requireDigest(bytes, expected, label) {
-  const actual = sha256(bytes);
-  if (actual !== expected) {
-    throw new Error(`${label} is ${actual}, expected ${expected}`);
-  }
-}
-
-function describeError(error) {
-  return error instanceof Error ? error.message : String(error);
-}
-
-function sha256(bytes) {
-  return createHash('sha256').update(bytes).digest('hex');
-}
diff --git a/tools/integration/wasix-ts/smoke-browser.mjs b/tools/integration/wasix-ts/smoke-browser.mjs
deleted file mode 100644
index 006eda2fc..000000000
--- a/tools/integration/wasix-ts/smoke-browser.mjs
+++ /dev/null
@@ -1,758 +0,0 @@
-import { execFile, spawn } from 'node:child_process';
-import { createHash } from 'node:crypto';
-import {
-  access,
-  cp,
-  lstat,
-  mkdir,
-  mkdtemp,
-  readFile,
-  realpath,
-  rm,
-  writeFile,
-} from 'node:fs/promises';
-import { createRequire } from 'node:module';
-import { createServer } from 'node:net';
-import { arch, cpus, hostname, platform, release, tmpdir, totalmem } from 'node:os';
-import { dirname, join, relative, resolve } from 'node:path';
-import { fileURLToPath } from 'node:url';
-import { isDeepStrictEqual, promisify } from 'node:util';
-
-import {
-  browserMarkdownReport,
-  browserPlanSummary,
-  defaultBrowserPlanFile,
-  loadBrowserPlan,
-  qualifyingGitProvenance,
-  summarizeBrowserResult,
-} from '../../perf/wasix-browser/plan.mjs';
-import {
-  directoryTreeSha256,
-  installedPackageClosure,
-} from '../../perf/wasix-node/installed-closure.mjs';
-import { assertRuntimeBuildConfiguration } from '../../perf/wasix-node/plan.mjs';
-import { loadHostBuildContract } from '../../../src/bindings/wasix-ts/host/build-provenance.mjs';
-import { createPackedWasixConsumer, runtimeBuildProvenance } from './packed-node-fixture.mjs';
-
-const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
-const bindingRoot = resolve(repositoryRoot, 'src/bindings/wasix-ts');
-const execFileAsync = promisify(execFile);
-const diagnosticOpfsBenchmark = process.argv.includes('--diagnostic-opfs');
-const qualifyingBenchmark = process.argv.includes('--benchmark');
-if (diagnosticOpfsBenchmark && qualifyingBenchmark) {
-  throw new Error('--diagnostic-opfs and --benchmark are mutually exclusive');
-}
-const benchmark = qualifyingBenchmark || diagnosticOpfsBenchmark;
-const packageOnly = process.argv.includes('--package-only');
-const quickBenchmark = benchmark && process.argv.includes('--quick');
-const planFile = resolve(argumentValue('--config') ?? defaultBrowserPlanFile);
-const planSource = qualifyingBenchmark ? await loadBrowserPlan(planFile) : undefined;
-const git = qualifyingBenchmark ? await gitProvenance() : undefined;
-const benchmarkOutput = qualifyingBenchmark
-  ? resolve(argumentValue('--output') ?? defaultBenchmarkOutput(git.commit))
-  : undefined;
-if (
-  !qualifyingBenchmark &&
-  (argumentValue('--config') !== undefined || argumentValue('--output') !== undefined)
-) {
-  throw new Error('--config and --output require --benchmark');
-}
-if (
-  packageOnly &&
-  (benchmark || process.argv.includes('--pg-uuidv7') || process.argv.includes('--postgis-worker'))
-) {
-  throw new Error('--package-only cannot be combined with benchmark or extension-canary options');
-}
-if (benchmarkOutput !== undefined) await requireAbsent(benchmarkOutput, 'benchmark output');
-const timeoutMs = Number(
-  process.env.OLIPHAUNT_BROWSER_SMOKE_TIMEOUT_MS ??
-    (diagnosticOpfsBenchmark && !quickBenchmark ? 1_800_000 : benchmark ? 900_000 : 300_000),
-);
-const pgUuidv7Canary = process.argv.includes('--pg-uuidv7');
-const postgisWorkerCanary = process.argv.includes('--postgis-worker');
-const requiredInputs = [
-  resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/oliphaunt.wasix.tar.zst'),
-  resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/cluster-seeds/standard.tar.zst'),
-  resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/cluster-seeds/standard.json'),
-  resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/manifest.json'),
-  resolve(
-    repositoryRoot,
-    packageOnly
-      ? 'src/bindings/wasix-ts/lib/host/index.mjs'
-      : 'target/oliphaunt-wasix-ts/host/wasmer-sdk/dist/index.mjs',
-  ),
-];
-if (!benchmark) {
-  requiredInputs.push(
-    resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/extensions/pgtap.tar.zst'),
-  );
-}
-if (pgUuidv7Canary) {
-  requiredInputs.push(
-    resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/extensions/pg_uuidv7.tar.zst'),
-  );
-}
-if (postgisWorkerCanary) {
-  requiredInputs.push(
-    resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/extensions/postgis.tar.zst'),
-  );
-}
-if (benchmark) {
-  requiredInputs.push(
-    resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist/pglite.data'),
-    resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist/pglite.wasm'),
-    resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist/initdb.wasm'),
-  );
-}
-
-for (const input of requiredInputs) {
-  try {
-    await access(input);
-  } catch {
-    throw new Error(`browser smoke input is missing: ${input}`);
-  }
-}
-
-const chrome = await findChrome();
-const vitePort = await freePort();
-const chromePort = await freePort();
-const profile = await mkdtemp(join(tmpdir(), 'oliphaunt-wasix-chrome-'));
-const children = [];
-let socket;
-let packageScratch;
-
-try {
-  packageScratch = packageOnly
-    ? await realpath(await mkdtemp(join(tmpdir(), 'oliphaunt-wasix-browser-package-')))
-    : undefined;
-  const packedConsumer =
-    packageScratch === undefined ? undefined : await stagePackedBrowserConsumer(packageScratch);
-  const vite = startChild(
-    'pnpm',
-    [
-      '--dir',
-      bindingRoot,
-      'exec',
-      'vite',
-      '--config',
-      resolve(repositoryRoot, 'examples/browser-wasix/vite.config.ts'),
-      '--host',
-      '127.0.0.1',
-      '--port',
-      String(vitePort),
-      '--strictPort',
-    ],
-    'Vite',
-    packedConsumer === undefined
-      ? undefined
-      : {
-          env: {
-            ...process.env,
-            OLIPHAUNT_WASIX_BROWSER_PACKAGE_ROOT: packedConsumer,
-          },
-        },
-  );
-  children.push(vite);
-  await waitForHttp(`http://127.0.0.1:${vitePort}/`, vite, 30_000);
-
-  const browser = startChild(
-    chrome,
-    [
-      '--headless=new',
-      '--no-sandbox',
-      '--disable-gpu',
-      '--disable-dev-shm-usage',
-      `--user-data-dir=${profile}`,
-      `--remote-debugging-port=${chromePort}`,
-      'about:blank',
-    ],
-    'Chrome',
-  );
-  children.push(browser);
-
-  const targets = await waitForJson(`http://127.0.0.1:${chromePort}/json/list`, browser, 30_000);
-  const page = targets.find((candidate) => candidate.type === 'page');
-  if (page?.webSocketDebuggerUrl === undefined) {
-    throw new Error('headless Chrome did not expose a page debugging target');
-  }
-
-  socket = new WebSocket(page.webSocketDebuggerUrl);
-  await new Promise((resolveOpen, rejectOpen) => {
-    socket.addEventListener('open', resolveOpen, { once: true });
-    socket.addEventListener('error', rejectOpen, { once: true });
-  });
-
-  const browserFailures = [];
-  const cdp = createCdpClient(socket, (failure) => browserFailures.push(failure));
-  await Promise.all([
-    cdp.send('Runtime.enable'),
-    cdp.send('Page.enable'),
-    cdp.send('Log.enable'),
-    cdp.send('Target.setAutoAttach', {
-      autoAttach: true,
-      waitForDebuggerOnStart: false,
-      flatten: true,
-    }),
-  ]);
-
-  const smokeUrl = benchmark
-    ? `http://127.0.0.1:${vitePort}/benchmark.html?${new URLSearchParams({
-        ...(quickBenchmark ? { quick: '1' } : {}),
-        ...(diagnosticOpfsBenchmark ? { opfs: '1' } : {}),
-      })}`
-    : packageOnly
-      ? `http://127.0.0.1:${vitePort}/?package_smoke=1`
-      : `http://127.0.0.1:${vitePort}/?smoke=1${pgUuidv7Canary ? '&pg_uuidv7=1' : ''}${postgisWorkerCanary ? '&postgis_worker=1' : ''}`;
-  await cdp.send('Page.navigate', { url: smokeUrl });
-  const deadline = Date.now() + timeoutMs;
-  while (Date.now() < deadline) {
-    assertRunning(vite);
-    assertRunning(browser);
-    if (browserFailures.length > 0) {
-      throw new Error(`browser smoke observed an unhandled exception:\n${browserFailures.at(-1)}`);
-    }
-    const evaluated = await cdp.send('Runtime.evaluate', {
-      expression:
-        "JSON.stringify({state:document.documentElement.dataset.oliphauntSmoke??'',status:document.querySelector('#status')?.textContent??'',output:document.querySelector('#output')?.textContent??''})",
-      returnByValue: true,
-    });
-    const snapshot = JSON.parse(evaluated.result.value ?? '{}');
-    if (snapshot.state === 'passed') {
-      if (benchmark) {
-        const result = parseBenchmarkResult(snapshot.output);
-        if (diagnosticOpfsBenchmark) {
-          console.log(
-            `wasix-ts OPFS diagnostic benchmark: PASS\n${JSON.stringify(
-              {
-                configuration: result.configuration,
-                postgresProfiles: result.postgresProfiles,
-                worker: Object.fromEntries(
-                  Object.entries(result.summary.workload).map(([metric, value]) => [
-                    metric,
-                    value.worker,
-                  ]),
-                ),
-                insertDiagnostic: result.insertDiagnostic.summary,
-              },
-              null,
-              2,
-            )}`,
-          );
-          break;
-        }
-        const finalGit = await gitProvenance();
-        if (finalGit.commit !== git.commit || finalGit.tree !== git.tree) {
-          throw new Error('Git commit or tree changed while the browser benchmark was running');
-        }
-        const summary = summarizeBrowserResult(planSource, result);
-        const report = {
-          schema: 'oliphaunt-wasix-browser-benchmark-report-v2',
-          createdAt: new Date().toISOString(),
-          plan: browserPlanSummary(planSource),
-          provenance: {
-            git,
-            machine: machineProvenance(),
-            candidate: await candidateProvenance(planSource.plan),
-            comparison: await comparisonProvenance(planSource.plan),
-            tools: await toolProvenance(planSource.file),
-          },
-          result,
-          summary,
-        };
-        await writeBenchmarkReport(benchmarkOutput, report);
-        const direct = summary.comparisons.direct;
-        const worker = summary.comparisons.worker;
-        console.log(
-          `wasix-ts browser benchmark: ${summary.passed ? 'PASS' : 'FAIL'} ` +
-            `direct=${direct.geomeanRatio.toFixed(4)} worker=${worker.geomeanRatio.toFixed(4)} ` +
-            `gate<=${summary.gate.maxGeomeanRatio.toFixed(2)} ` +
-            `report=${relative(repositoryRoot, benchmarkOutput)}`,
-        );
-        if (!summary.passed) {
-          throw new Error(`browser benchmark failed qualification: ${snapshot.status}`);
-        }
-      } else {
-        console.log(
-          `wasix-ts ${packageOnly ? 'packed browser package' : 'browser'} smoke: PASS ${snapshot.output}`,
-        );
-      }
-      break;
-    }
-    if (snapshot.state === 'failed') {
-      throw new Error(`browser smoke failed: ${snapshot.status}\n${snapshot.output}`);
-    }
-    await delay(750);
-  }
-
-  const finalState = await cdp.send('Runtime.evaluate', {
-    expression: "document.documentElement.dataset.oliphauntSmoke ?? ''",
-    returnByValue: true,
-  });
-  if (finalState.result.value !== 'passed') {
-    throw new Error(
-      `browser smoke timed out after ${timeoutMs}ms\nVite output:\n${vite.output}\nChrome output:\n${browser.output}`,
-    );
-  }
-} finally {
-  socket?.close();
-  await Promise.all(children.reverse().map(stopChild));
-  await rm(profile, { recursive: true, force: true });
-  if (packageScratch !== undefined) {
-    await rm(packageScratch, { recursive: true, force: true });
-  }
-}
-
-async function stagePackedBrowserConsumer(scratch) {
-  const fixture = await createPackedWasixConsumer({
-    scratch,
-    consumerName: 'oliphaunt-wasix-browser-package-smoke-consumer',
-    includePgtap: true,
-    includeTools: true,
-    includeNative: false,
-  });
-  for (const [source, destination] of [
-    ['examples/browser-wasix/index.html', 'index.html'],
-    ['examples/browser-wasix/package-smoke.ts', 'main.ts'],
-    ['examples/browser-wasix/direct-pg-dump-smoke.ts', 'direct-pg-dump-smoke.ts'],
-    ['examples/browser-wasix/structured-api-smoke.ts', 'structured-api-smoke.ts'],
-    ['src/shared/fixtures/postgres/logical-tools.json', 'logical-tools.json'],
-    ['src/shared/fixtures/postgres/logical-tools-seed.sql', 'logical-tools-seed.sql'],
-    ['src/shared/fixtures/postgres/logical-tools-verify.sql', 'logical-tools-verify.sql'],
-  ]) {
-    await cp(resolve(repositoryRoot, source), resolve(fixture.consumer, destination));
-  }
-  return realpath(fixture.consumer);
-}
-
-function parseBenchmarkResult(value) {
-  try {
-    return JSON.parse(value);
-  } catch (error) {
-    throw new Error('browser benchmark did not return valid JSON', { cause: error });
-  }
-}
-
-async function writeBenchmarkReport(outputDirectory, report) {
-  await mkdir(dirname(outputDirectory), { recursive: true });
-  await mkdir(outputDirectory);
-  await writeFile(resolve(outputDirectory, 'report.json'), `${JSON.stringify(report, null, 2)}\n`, {
-    flag: 'wx',
-  });
-  await writeFile(resolve(outputDirectory, 'report.md'), browserMarkdownReport(report), {
-    flag: 'wx',
-  });
-}
-
-async function gitProvenance() {
-  const [{ stdout: commitOutput }, { stdout: treeOutput }, { stdout: statusOutput }] =
-    await Promise.all([
-      execFileAsync('git', ['rev-parse', 'HEAD'], { cwd: repositoryRoot }),
-      execFileAsync('git', ['rev-parse', 'HEAD^{tree}'], { cwd: repositoryRoot }),
-      execFileAsync('git', ['status', '--porcelain=v1', '--untracked-files=all'], {
-        cwd: repositoryRoot,
-        maxBuffer: 16 * 1024 * 1024,
-      }),
-    ]);
-  return qualifyingGitProvenance({
-    commit: commitOutput.trim(),
-    tree: treeOutput.trim(),
-    status: statusOutput.trimEnd(),
-  });
-}
-
-async function candidateProvenance(plan) {
-  const packageFile = resolve(bindingRoot, 'package.json');
-  const packageBytes = await readFile(packageFile);
-  const packageJson = JSON.parse(packageBytes.toString('utf8'));
-  if (packageJson.name !== '@oliphaunt/wasix-ts') {
-    throw new Error(`browser benchmark loaded unexpected candidate ${packageJson.name}`);
-  }
-  if (packageJson.dependencies?.fzstd !== plan.engines.candidate.dependencies.fzstd) {
-    throw new Error(
-      `browser benchmark loaded unexpected fzstd specifier ${packageJson.dependencies?.fzstd}`,
-    );
-  }
-  const manifestBytes = await readFile(
-    resolve(repositoryRoot, 'target/oliphaunt-wasix/assets/manifest.json'),
-  );
-  const manifest = JSON.parse(manifestBytes.toString('utf8'));
-  const runtime = manifest.runtime;
-  if (runtime === null || typeof runtime !== 'object') {
-    throw new Error('canonical WASIX manifest has no runtime entry');
-  }
-  const clusterSeed = manifest['cluster-seeds']?.standard;
-  if (clusterSeed === null || typeof clusterSeed !== 'object') {
-    throw new Error('canonical WASIX manifest has no standard cluster seed entry');
-  }
-  const archiveBytes = await readFile(
-    resolve(repositoryRoot, 'target/oliphaunt-wasix/assets', runtime.archive),
-  );
-  const archiveSha256 = sha256(archiveBytes);
-  if (archiveSha256 !== runtime.sha256) {
-    throw new Error('canonical WASIX runtime archive does not match its manifest');
-  }
-  const clusterSeedBytes = await readFile(
-    resolve(repositoryRoot, 'target/oliphaunt-wasix/assets', clusterSeed.archive),
-  );
-  const clusterSeedSha256 = sha256(clusterSeedBytes);
-  if (clusterSeedSha256 !== clusterSeed.sha256) {
-    throw new Error('canonical WASIX standard cluster seed does not match its manifest');
-  }
-  const hostBuild = await installedHostBuildProvenance(
-    packageFile,
-    (await loadHostBuildContract()).provenance,
-  );
-  const runtimeBuild = await runtimeBuildProvenance(manifest);
-  assertRuntimeBuildConfiguration(
-    runtimeBuild.configuration,
-    plan.engines.candidate.runtimeBuild,
-    'browser candidate runtime build',
-  );
-  const require = createRequire(packageFile);
-  const fzstdClosure = await installedPackageClosure(require.resolve('fzstd'), 'fzstd');
-  const libDirectory = resolve(bindingRoot, 'lib');
-  return {
-    package: packageJson.name,
-    version: packageJson.version,
-    packageJsonSha256: sha256(packageBytes),
-    build: {
-      treeHashSchema: 'oliphaunt-path-size-content-sha256-v1',
-      libTreeSha256: await directoryTreeSha256(libDirectory),
-      hostBuild,
-      hostArtifacts: await fileProvenance([
-        resolve(libDirectory, 'host/index.mjs'),
-        resolve(libDirectory, 'host/worker.mjs'),
-        resolve(libDirectory, 'host/wasmer_js_bg.wasm'),
-        resolve(libDirectory, 'host/provenance.json'),
-      ]),
-      runtimeBuild,
-    },
-    dependencies: { fzstd: fzstdClosure },
-    runtime: {
-      manifestSha256: sha256(manifestBytes),
-      archive: runtime.archive,
-      archiveSha256,
-      archiveSize: archiveBytes.length,
-      moduleSha256: runtime['module-sha256'],
-      postgresVersion: runtime['postgres-version'],
-      sourceFingerprint: manifest['source-fingerprint'],
-      sourceLane: manifest['source-lane'],
-    },
-    clusterSeed: {
-      profile: 'standard',
-      archive: clusterSeed.archive,
-      archiveSha256: clusterSeedSha256,
-      archiveSize: clusterSeedBytes.length,
-    },
-  };
-}
-
-async function installedHostBuildProvenance(packageManifestFile, expected) {
-  const file = resolve(dirname(packageManifestFile), 'lib/host/provenance.json');
-  let provenance;
-  try {
-    provenance = JSON.parse(await readFile(file, 'utf8'));
-  } catch (error) {
-    throw new Error('installed @oliphaunt/wasix-ts host provenance is unreadable', {
-      cause: error,
-    });
-  }
-  if (!isDeepStrictEqual(provenance, expected)) {
-    throw new Error(
-      'installed @oliphaunt/wasix-ts host provenance does not match the source build contract',
-    );
-  }
-  return provenance;
-}
-
-async function toolProvenance(plan) {
-  return fileProvenance([
-    plan,
-    resolve(repositoryRoot, 'tools/perf/wasix-browser/plan.mjs'),
-    resolve(repositoryRoot, 'tools/perf/wasix-node/installed-closure.mjs'),
-    resolve(repositoryRoot, 'tools/perf/wasix-node/plan.mjs'),
-    resolve(repositoryRoot, 'tools/integration/wasix-ts/smoke-browser.mjs'),
-    resolve(repositoryRoot, 'tools/integration/wasix-ts/packed-node-fixture.mjs'),
-    resolve(repositoryRoot, 'examples/browser-wasix/benchmark.html'),
-    resolve(repositoryRoot, 'examples/browser-wasix/benchmark.ts'),
-    resolve(repositoryRoot, 'examples/browser-wasix/pglite-worker.ts'),
-    resolve(repositoryRoot, 'examples/browser-wasix/vite.config.ts'),
-  ]);
-}
-
-async function fileProvenance(files) {
-  const records = [];
-  for (const file of [...new Set(files.map((entry) => resolve(entry)))].sort()) {
-    const bytes = await readFile(file);
-    records.push({
-      path: relative(repositoryRoot, file).split('\\').join('/'),
-      sha256: sha256(bytes),
-      size: bytes.length,
-    });
-  }
-  return records;
-}
-
-async function comparisonProvenance(plan) {
-  const entry = resolve(bindingRoot, 'node_modules/@electric-sql/pglite/dist/index.js');
-  const installedClosure = await installedPackageClosure(entry, plan.engines.comparison.package);
-  const root = installedClosure.packages.find(
-    (candidate) => candidate.id === installedClosure.root,
-  );
-  if (root === undefined) throw new Error('installed PGlite closure lost its root package');
-  if (
-    root.version !== plan.engines.comparison.version ||
-    root.installedTreeSha256 !== plan.engines.comparison.installedTreeSha256
-  ) {
-    throw new Error(
-      `installed PGlite is ${root.version}#${root.installedTreeSha256}, expected ` +
-        `${plan.engines.comparison.version}#${plan.engines.comparison.installedTreeSha256}`,
-    );
-  }
-  return { ...plan.engines.comparison, installedClosure };
-}
-
-function machineProvenance() {
-  const processors = cpus();
-  return {
-    hostname: hostname(),
-    platform: platform(),
-    release: release(),
-    arch: arch(),
-    node: process.version,
-    v8: process.versions.v8,
-    cpuModel: processors[0]?.model ?? 'unknown',
-    logicalCpus: processors.length,
-    totalMemoryBytes: totalmem(),
-  };
-}
-
-async function requireAbsent(path, label) {
-  try {
-    await lstat(path);
-  } catch (error) {
-    if (error?.code === 'ENOENT') return;
-    throw error;
-  }
-  throw new Error(`${label} already exists: ${path}`);
-}
-
-function defaultBenchmarkOutput(commit) {
-  const timestamp = new Date()
-    .toISOString()
-    .replaceAll(':', '')
-    .replaceAll('-', '')
-    .replace(/\.\d{3}Z$/u, 'Z');
-  return resolve(
-    repositoryRoot,
-    'target/perf',
-    `wasix-browser-${timestamp}-${commit.slice(0, 12)}`,
-  );
-}
-
-function argumentValue(flag) {
-  const positions = process.argv
-    .map((value, index) => (value === flag ? index : -1))
-    .filter((index) => index >= 0);
-  if (positions.length > 1) throw new Error(`${flag} may be specified only once`);
-  if (positions.length === 0) return undefined;
-  const value = process.argv[positions[0] + 1];
-  if (value === undefined || value.startsWith('--')) throw new Error(`${flag} requires a value`);
-  return value;
-}
-
-function sha256(value) {
-  return createHash('sha256').update(value).digest('hex');
-}
-
-function createCdpClient(webSocket, recordFailure) {
-  let nextId = 1;
-  const pending = new Map();
-
-  const rejectPending = (reason) => {
-    const error = new Error(`Chrome DevTools Protocol connection ${reason}`);
-    for (const request of pending.values()) request.reject(error);
-    pending.clear();
-  };
-  webSocket.addEventListener('close', () => rejectPending('closed'));
-  webSocket.addEventListener('error', () => rejectPending('failed'));
-
-  webSocket.addEventListener('message', (event) => {
-    const message = JSON.parse(event.data);
-    if (message.id !== undefined) {
-      const request = pending.get(message.id);
-      if (request !== undefined) {
-        pending.delete(message.id);
-        if (message.error === undefined) request.resolve(message.result);
-        else
-          request.reject(
-            new Error(`Chrome DevTools Protocol error: ${JSON.stringify(message.error)}`),
-          );
-      }
-      return;
-    }
-
-    if (message.method === 'Runtime.exceptionThrown') {
-      const failure = formatCdpException(message.params.exceptionDetails);
-      recordFailure(failure);
-      console.error(`browser exception: ${failure}`);
-    } else if (message.method === 'Runtime.consoleAPICalled') {
-      const values = message.params.args.map(
-        (argument) => argument.value ?? argument.description ?? argument.type,
-      );
-      console.error(`browser console ${message.params.type}: ${values.join(' ')}`);
-    } else if (message.method === 'Log.entryAdded') {
-      console.error(`browser log ${message.params.entry.level}: ${message.params.entry.text}`);
-    } else if (message.method === 'Target.attachedToTarget') {
-      const sessionId = message.params.sessionId;
-      void send('Runtime.enable', {}, sessionId);
-      void send('Log.enable', {}, sessionId);
-    }
-  });
-
-  function send(method, params = {}, sessionId = undefined) {
-    const id = nextId++;
-    return new Promise((resolveRequest, rejectRequest) => {
-      const timer = setTimeout(() => {
-        pending.delete(id);
-        rejectRequest(new Error(`Chrome DevTools Protocol ${method} timed out after 30000ms`));
-      }, 30_000);
-      pending.set(id, {
-        resolve(value) {
-          clearTimeout(timer);
-          resolveRequest(value);
-        },
-        reject(error) {
-          clearTimeout(timer);
-          rejectRequest(error);
-        },
-      });
-      webSocket.send(
-        JSON.stringify({ id, method, params, ...(sessionId === undefined ? {} : { sessionId }) }),
-      );
-    });
-  }
-
-  return { send };
-}
-
-function formatCdpException(details) {
-  const description = details.exception?.description ?? details.exception?.value ?? details.text;
-  const location = details.url
-    ? `${details.url}:${Number(details.lineNumber ?? 0) + 1}:${Number(details.columnNumber ?? 0) + 1}`
-    : undefined;
-  return [description, location].filter(Boolean).join('\n');
-}
-
-function startChild(command, args, label, options = {}) {
-  const child = spawn(command, args, {
-    cwd: options.cwd ?? bindingRoot,
-    detached: process.platform !== 'win32',
-    env: options.env ?? process.env,
-    stdio: ['ignore', 'pipe', 'pipe'],
-  });
-  child.label = label;
-  child.output = '';
-  for (const stream of [child.stdout, child.stderr]) {
-    stream.on('data', (chunk) => {
-      child.output = `${child.output}${chunk}`.slice(-32_768);
-    });
-  }
-  return child;
-}
-
-async function stopChild(child) {
-  if (child.exitCode !== null || child.signalCode !== null) return;
-  try {
-    if (process.platform === 'win32') child.kill('SIGTERM');
-    else process.kill(-child.pid, 'SIGTERM');
-  } catch {
-    return;
-  }
-  await Promise.race([new Promise((resolveExit) => child.once('exit', resolveExit)), delay(2_000)]);
-  if (child.exitCode === null && child.signalCode === null) {
-    try {
-      if (process.platform === 'win32') child.kill('SIGKILL');
-      else process.kill(-child.pid, 'SIGKILL');
-    } catch {
-      // The process exited between the state check and signal.
-    }
-  }
-}
-
-function assertRunning(child) {
-  if (child.exitCode !== null || child.signalCode !== null) {
-    throw new Error(
-      `${child.label} exited before the browser smoke completed (${child.exitCode ?? child.signalCode})\n${child.output}`,
-    );
-  }
-}
-
-async function waitForHttp(url, child, limitMs) {
-  const deadline = Date.now() + limitMs;
-  while (Date.now() < deadline) {
-    assertRunning(child);
-    try {
-      const response = await fetch(url);
-      if (response.ok) return;
-    } catch {
-      // The server is still starting.
-    }
-    await delay(200);
-  }
-  throw new Error(`${child.label} did not become ready\n${child.output}`);
-}
-
-async function waitForJson(url, child, limitMs) {
-  const deadline = Date.now() + limitMs;
-  while (Date.now() < deadline) {
-    assertRunning(child);
-    try {
-      const response = await fetch(url);
-      if (response.ok) return await response.json();
-    } catch {
-      // Chrome is still starting.
-    }
-    await delay(200);
-  }
-  throw new Error(`${child.label} did not expose its debugging endpoint\n${child.output}`);
-}
-
-async function findChrome() {
-  const candidates = [
-    process.env.CHROME_BIN,
-    '/usr/bin/google-chrome',
-    '/usr/bin/chromium',
-    '/usr/bin/chromium-browser',
-  ].filter(Boolean);
-  for (const candidate of candidates) {
-    try {
-      await access(candidate);
-      return candidate;
-    } catch {
-      // Try the next conventional browser path.
-    }
-  }
-  throw new Error('browser smoke requires Chrome/Chromium; set CHROME_BIN to its executable');
-}
-
-async function freePort() {
-  const server = createServer();
-  await new Promise((resolveListen, rejectListen) => {
-    server.once('error', rejectListen);
-    server.listen(0, '127.0.0.1', resolveListen);
-  });
-  const address = server.address();
-  if (address === null || typeof address === 'string') {
-    server.close();
-    throw new Error('failed to allocate a local TCP port');
-  }
-  await new Promise((resolveClose, rejectClose) =>
-    server.close((error) => (error ? rejectClose(error) : resolveClose())),
-  );
-  return address.port;
-}
-
-function delay(milliseconds) {
-  return new Promise((resolveDelay) => setTimeout(resolveDelay, milliseconds));
-}
diff --git a/tools/integration/wasix-ts/smoke-node.mjs b/tools/integration/wasix-ts/smoke-node.mjs
deleted file mode 100644
index 0d3b89470..000000000
--- a/tools/integration/wasix-ts/smoke-node.mjs
+++ /dev/null
@@ -1,612 +0,0 @@
-import { mkdtemp, rm, writeFile } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { dirname, resolve } from 'node:path';
-import { fileURLToPath, pathToFileURL } from 'node:url';
-
-import { createPackedWasixConsumer, runFixtureCommand } from './packed-node-fixture.mjs';
-
-const { packageOnly, runtime } = readOptions(process.argv.slice(2));
-const runtimeName =
-  runtime === 'bun'
-    ? 'Bun'
-    : runtime === 'deno'
-      ? 'Deno'
-      : runtime === 'electron'
-        ? 'Electron'
-        : 'Node';
-const packageCondition = runtime === 'electron' ? 'node' : runtime;
-const storageCondition = runtime === 'electron' ? 'node' : runtime;
-const expectedEntrypoint = `index.${packageCondition}.js`;
-const expectedDirectEntrypoint = 'direct.node.js';
-const expectedWorkerEntrypoint = `worker-entry.${packageCondition}.js`;
-const expectedServerEntrypoint = 'server.node.js';
-const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
-const pgwireClientUrl = pathToFileURL(
-  resolve(repositoryRoot, 'src/bindings/wasix-ts/tools/pgwire-client.mjs'),
-).href;
-const scratch = await mkdtemp(resolve(tmpdir(), `oliphaunt-wasix-${runtime}-smoke-`));
-
-try {
-  const fixture = await createPackedWasixConsumer({
-    scratch,
-    consumerName: `oliphaunt-wasix-${runtime}-smoke-consumer`,
-    includePgtap: !packageOnly,
-    useStubRuntime: packageOnly,
-  });
-  const candidate = fixture.packages.binding.name;
-  const extension = fixture.packages.extension?.name;
-  await writeFile(
-    resolve(fixture.consumer, 'verify.mjs'),
-    `import { Worker } from 'node:worker_threads';
-
-const candidate = ${JSON.stringify(candidate)};
-const extension = ${JSON.stringify(extension)};
-const runtime = ${JSON.stringify(runtime)};
-const storageCondition = ${JSON.stringify(storageCondition)};
-const runtimeName = ${JSON.stringify(runtimeName)};
-const packageOnly = ${JSON.stringify(packageOnly)};
-const pgtap = packageOnly ? undefined : (await import(extension)).default;
-const executionSurfaces = {
-  actor: {
-    entrypoint: candidate,
-    resolvedEntrypoint: ${JSON.stringify(expectedEntrypoint)},
-    callingContract: 'async',
-    executionOwner: 'sdk-thread',
-  },
-  direct: {
-    entrypoint: candidate + '/direct',
-    resolvedEntrypoint: ${JSON.stringify(expectedDirectEntrypoint)},
-    callingContract: 'async',
-    executionOwner: 'caller',
-  },
-  worker: {
-    entrypoint: candidate + '/worker',
-    resolvedEntrypoint: ${JSON.stringify(expectedWorkerEntrypoint)},
-    callingContract: 'async',
-    executionOwner: 'sdk-worker',
-  },
-  server: {
-    entrypoint: candidate + '/server',
-    resolvedEntrypoint: ${JSON.stringify(expectedServerEntrypoint)},
-    callingContract: 'async',
-    executionOwner: 'rust-listener',
-  },
-};
-const { default: Oliphaunt, PostgresError, postgresOids, WasixStorageError } = await import(candidate);
-const { default: DirectOliphaunt } = await import(candidate + '/direct');
-const { default: WorkerOliphaunt } = await import(candidate + '/worker');
-const { openServer } = await import(candidate + '/server');
-const { directory } = await import(candidate + '/storage/' + storageCondition);
-const {
-  connect,
-  onceClosed,
-  onceConnected,
-  readExchange,
-  simpleQuery: wireSimpleQuery,
-  startupPacket,
-} = await import(${JSON.stringify(pgwireClientUrl)});
-const simpleQuery = (sql) => {
-  const body = new TextEncoder().encode(sql + '\\0');
-  const message = new Uint8Array(body.length + 5);
-  message[0] = 0x51;
-  new DataView(message.buffer).setUint32(1, body.length + 4);
-  message.set(body, 5);
-  return message;
-};
-
-const resolved = import.meta.resolve(candidate);
-if (!resolved.endsWith('/lib/${expectedEntrypoint}')) {
-  throw new Error(runtimeName + ' did not select its actor entrypoint: ' + resolved);
-}
-const directResolved = import.meta.resolve(candidate + '/direct');
-if (!directResolved.endsWith('/lib/${expectedDirectEntrypoint}')) {
-  throw new Error(runtimeName + ' did not select its direct entrypoint: ' + directResolved);
-}
-const workerResolved = import.meta.resolve(candidate + '/worker');
-if (!workerResolved.endsWith('/lib/${expectedWorkerEntrypoint}')) {
-  throw new Error(
-    runtimeName + ' did not select its Worker entrypoint: ' + workerResolved,
-  );
-}
-const serverResolved = import.meta.resolve(candidate + '/server');
-if (!serverResolved.endsWith('/lib/${expectedServerEntrypoint}')) {
-  throw new Error(
-    runtimeName + ' did not select its server entrypoint: ' + serverResolved,
-  );
-}
-if (!packageOnly) {
-  const callerSource = [
-    "import { parentPort, workerData } from 'node:worker_threads';",
-    'const { default: DirectOliphaunt } = await import(' + JSON.stringify(directResolved) + ');',
-    'const { default: WorkerOliphaunt } = await import(' + JSON.stringify(workerResolved) + ');',
-    'const { directory } = await import(' +
-      JSON.stringify(import.meta.resolve(candidate + '/storage/' + storageCondition)) +
-      ');',
-    'const finishWorker = () => {',
-    "  if (workerData.runtime === 'bun') return process.exit(0);",
-    '  parentPort.close?.();',
-    '  parentPort.unref();',
-    '};',
-    'try {',
-    '  const direct = await DirectOliphaunt.open({ storage: directory(' +
-      JSON.stringify(new URL('./caller-worker-storage', import.meta.url).href) +
-      ') });',
-    "  const directAnswer = (await direct.queryRaw('SELECT 42::int AS answer')).getText(0, 'answer');",
-    '  await direct.close();',
-    '  const nestedWorker = await WorkerOliphaunt.open();',
-    "  const workerAnswer = (await nestedWorker.queryRaw('SELECT 43::int AS answer')).getText(0, 'answer');",
-    '  await nestedWorker.close();',
-    '  parentPort.postMessage({ directAnswer, workerAnswer });',
-    '  finishWorker();',
-    '} catch (error) {',
-    '  parentPort.postMessage({ name: error?.name, message: error?.message });',
-    '  finishWorker();',
-    '}',
-  ].join('\\n');
-  const callerResults = [];
-  for (let iteration = 1; iteration <= 2; iteration += 1) {
-    const worker = new Worker(
-      new URL('data:text/javascript,' + encodeURIComponent(callerSource)),
-      { name: 'oliphaunt-caller-worker-check-' + iteration, workerData: { runtime } },
-    );
-    let callerResult;
-    let exitObserved = false;
-    try {
-      callerResult = await new Promise((resolveResult, rejectResult) => {
-        let message;
-        worker.once('message', (value) => {
-          message = value;
-        });
-        worker.once('error', rejectResult);
-        worker.once('exit', (code) => {
-          exitObserved = true;
-          if (code !== 0) {
-            rejectResult(new Error('caller worker exited with code ' + code));
-          } else if (message === undefined) {
-            rejectResult(new Error('caller worker self-exited without a result'));
-          } else {
-            resolveResult(message);
-          }
-        });
-      });
-    } finally {
-      // Forced termination is only failure cleanup. Bun does not settle a
-      // redundant terminate() after a Worker has emitted its exit event.
-      if (!exitObserved) await worker.terminate();
-    }
-    if (callerResult?.directAnswer !== '42' || callerResult?.workerAnswer !== '43') {
-      throw new Error('caller-worker execution failed: ' + JSON.stringify(callerResult));
-    }
-    callerResults.push(callerResult);
-  }
-  if (callerResults.length !== 2) {
-    throw new Error('caller-worker repetition failed');
-  }
-}
-
-if (packageOnly) {
-  const storage = directory(new URL('./package-condition-storage', import.meta.url));
-  if (!Object.isFrozen(storage) || Reflect.ownKeys(storage).length !== 0) {
-    throw new Error(runtimeName + ' storage condition returned an invalid adapter');
-  }
-  console.log(JSON.stringify({
-    host: runtime + '-package-condition-actor-direct-worker',
-    executionSurfaces,
-    storage: runtime + '-directory',
-  }));
-} else {
-async function verifyMemory(client, executionSurface) {
-  // OLIPHAUNT_DOCS_SNIPPET wasix-typescript-quickstart
-  const db = await client.open({ extensions: [pgtap] });
-  await db.execute('CREATE EXTENSION pgtap');
-  const structuredApi = await verifyStructuredApi(db);
-  const version = (await db.queryRaw('SELECT pgtap_version()::text AS version')).getText(0, 'version');
-  const retainedProtocol = await db.execProtocolRaw(
-    simpleQuery("SELECT repeat('a', 8192) AS retained_payload"),
-  );
-  const retainedSnapshot = retainedProtocol.slice();
-  await db.execProtocolRaw(simpleQuery("SELECT repeat('z', 8192) AS replacement_payload"));
-  const protocolResponseOwned =
-    retainedProtocol.length === retainedSnapshot.length &&
-    retainedProtocol.every((byte, index) => byte === retainedSnapshot[index]);
-  const wallClockMillis = Number((await db.queryRaw(
-    'SELECT (extract(epoch FROM clock_timestamp()) * 1000)::bigint AS millis',
-  )).getText(0, 'millis'));
-  const wallClockDeltaMillis = Math.abs(Date.now() - wallClockMillis);
-  const explain = JSON.parse((await db.queryRaw(
-    'EXPLAIN (ANALYZE, FORMAT JSON) SELECT pg_sleep(0.05)',
-  )).getText(0, 'QUERY PLAN'));
-  const monotonicElapsedMillis = explain[0]?.['Execution Time'];
-  await db.execute('CREATE TABLE smoke_transaction (value integer NOT NULL)');
-  const transactionValue = await db.transaction(async (tx) => {
-    await tx.execute('INSERT INTO smoke_transaction VALUES ($1)', [7]);
-    return (await tx.queryRaw('SELECT value::text AS value FROM smoke_transaction')).getText(0, 'value');
-  });
-  const rollbackSentinel = new Error('packed transaction rollback sentinel');
-  try {
-    await db.transaction(async (tx) => {
-      await tx.execute('INSERT INTO smoke_transaction VALUES ($1)', [9]);
-      throw rollbackSentinel;
-    });
-    throw new Error('failed packed transaction unexpectedly committed');
-  } catch (error) {
-    if (error !== rollbackSentinel) throw error;
-  }
-  const transactionRows = (await db.queryRaw(
-    'SELECT count(*)::int AS count FROM smoke_transaction',
-  )).getText(0, 'count');
-  let sqlstate;
-  try {
-    await db.queryRaw('SELEC 1');
-  } catch (error) {
-    if (!(error instanceof PostgresError)) throw error;
-    sqlstate = error.sqlstate;
-  }
-  const answer = (await db.queryRaw('SELECT 42::int AS answer')).getText(0, 'answer');
-  await db[Symbol.asyncDispose]();
-  const result = {
-    version,
-    protocolResponseOwned,
-    wallClockDeltaMillis,
-    monotonicElapsedMillis,
-    transactionValue,
-    transactionRows,
-    sqlstate,
-    answer,
-    structuredApi,
-  };
-  if (
-    !version ||
-    !protocolResponseOwned ||
-    wallClockDeltaMillis > 5_000 ||
-    !Number.isFinite(monotonicElapsedMillis) ||
-    monotonicElapsedMillis < 25 ||
-    monotonicElapsedMillis > 5_000 ||
-    transactionValue !== '7' ||
-    transactionRows !== '1' ||
-    sqlstate !== '42601' ||
-    answer !== '42' ||
-    structuredApi !== '42:9007199254740993:3:custom:42:42:2'
-  ) {
-    throw new Error(executionSurface + ': ' + JSON.stringify(result));
-  }
-  return result;
-}
-
-async function verifyStructuredApi(db) {
-  const decoded = await db.query(
-    'SELECT $1::int4 AS answer, $2::int8 AS wide, $3::jsonb AS document, $4::int4[] AS numbers',
-    [42, 9007199254740993n, { ok: true }, [1, 2, 3]],
-  );
-  const objectRow = decoded.rows[0];
-  if (
-    objectRow?.answer !== 42 ||
-    objectRow?.wide !== '9007199254740993' ||
-    objectRow?.document?.ok !== true ||
-    JSON.stringify(objectRow?.numbers) !== '[1,2,3]'
-  ) {
-    throw new Error('decoded object-row contract failed: ' + JSON.stringify(objectRow));
-  }
-
-  const positional = await db.query('SELECT 41::int4 AS left, 42::int4 AS right', [], {
-    rowMode: 'array',
-  });
-  if (JSON.stringify(positional.rows) !== '[[41,42]]') {
-    throw new Error('decoded array-row contract failed: ' + JSON.stringify(positional.rows));
-  }
-
-  const custom = await db.query('SELECT 42::int4 AS answer', [], {
-    decoders: {
-      [postgresOids.int4]: (value, field) => 'custom:' + value + ':' + field.typeOid,
-    },
-  });
-  if (custom.rows[0]?.answer !== 'custom:42:23') {
-    throw new Error('OID decoder contract failed: ' + JSON.stringify(custom.rows));
-  }
-
-  const description = await db.describe('SELECT $1::int4 AS answer');
-  if (
-    description.parameterTypeOids[0] !== postgresOids.int4 ||
-    description.fields?.[0]?.typeOid !== postgresOids.int4
-  ) {
-    throw new Error('describe contract failed: ' + JSON.stringify(description));
-  }
-
-  const execution = await db.exec('SELECT 1::int4 AS first; SELECT 2::int4 AS second');
-  if (
-    execution.statements.length !== 2 ||
-    execution.statements[0]?.rows[0]?.first !== 1 ||
-    execution.statements[1]?.rows[0]?.second !== 2
-  ) {
-    throw new Error('multi-statement exec contract failed: ' + JSON.stringify(execution));
-  }
-
-  return [
-    objectRow.answer,
-    objectRow.wide,
-    objectRow.numbers.length,
-    String(custom.rows[0].answer).split(':').slice(0, 2).join(':'),
-    positional.rows[0][1],
-    execution.statements.length,
-  ].join(':');
-}
-
-async function verifyServer() {
-  const server = await openServer();
-  const socket = connect(server.connectionString);
-  let startup;
-  let query;
-  try {
-    await onceConnected(socket);
-    const startupResponse = readExchange(socket);
-    socket.write(startupPacket('postgres', 'postgres'));
-    startup = await startupResponse;
-    const queryResponse = readExchange(socket);
-    socket.write(wireSimpleQuery('SELECT 42::int AS answer'));
-    query = await queryResponse;
-  } finally {
-    socket.end();
-    await onceClosed(socket);
-    await server.close();
-  }
-  if (
-    !server.closed ||
-    startup.messages < 1 ||
-    query.messages < 3 ||
-    query.totalBytes < 6
-  ) {
-    throw new Error('server: ' + JSON.stringify({ closed: server.closed, startup, query }));
-  }
-  return { connection: 'tcp-loopback', startup, query };
-}
-
-const actor = await verifyMemory(Oliphaunt, 'actor');
-const direct = await verifyMemory(DirectOliphaunt, 'direct');
-const worker = await verifyMemory(WorkerOliphaunt, 'worker');
-const server = await verifyServer();
-if (actor.version !== direct.version || direct.version !== worker.version) {
-  throw new Error('entrypoint extension versions differ: ' + JSON.stringify({ actor, direct, worker }));
-}
-
-const storage = directory(new URL('./database space ü', import.meta.url));
-let persistent = await Oliphaunt.open({ storage, extensions: [pgtap] });
-await persistent.execute('CREATE EXTENSION pgtap');
-await persistent.execute('CREATE SEQUENCE smoke_persistence_seq START WITH 10');
-await persistent.execute(
-  'CREATE TABLE smoke_persistence (' +
-    ${JSON.stringify("ordinal bigint PRIMARY KEY DEFAULT nextval('smoke_persistence_seq'), ")} +
-    'label text NOT NULL, payload bytea NOT NULL, optional_value text NULL)'
-);
-await persistent.execute('CREATE UNIQUE INDEX smoke_persistence_label_idx ON smoke_persistence(label)');
-await persistent.execute(
-  "INSERT INTO smoke_persistence(label, payload, optional_value) VALUES " +
-    "('café 🐘', decode('00ff10', 'hex'), NULL), " +
-    "('東京', decode('deadbeef', 'hex'), 'present'), " +
-    "('mañana', decode('', 'hex'), NULL)"
-);
-await persistent.execute('CREATE TEMP TABLE smoke_direct_session(value text NOT NULL)');
-await persistent.execute("INSERT INTO smoke_direct_session VALUES ('direct-session')");
-await persistent.execute("SET application_name = 'packed-direct-session'");
-await persistent.execute('CHECKPOINT');
-let busy;
-try {
-  await WorkerOliphaunt.open({ storage, extensions: [pgtap] });
-} catch (error) {
-  if (!(error instanceof WasixStorageError)) throw error;
-  busy = error.code;
-}
-const directArchive = await persistent.backup();
-const directSessionState = (await persistent.queryRaw(
-  "SELECT (SELECT value FROM smoke_direct_session) || ':' || current_setting('application_name') AS value",
-)).getText(0, 'value');
-await persistent.close();
-
-persistent = await WorkerOliphaunt.open({ storage, extensions: [pgtap] });
-const workerPersistedRows = (await persistent.queryRaw(
-  'SELECT count(*)::int AS count FROM smoke_persistence',
-)).getText(0, 'count');
-const persistentExtension = (await persistent.queryRaw(
-  'SELECT pgtap_version()::text AS version',
-)).getText(0, 'version');
-await persistent.execute(
-  "INSERT INTO smoke_persistence(label, payload, optional_value) " +
-    "VALUES ('naïve', decode('010203', 'hex'), NULL)"
-);
-await persistent.execute('CREATE TEMP TABLE smoke_worker_session(value text NOT NULL)');
-await persistent.execute("INSERT INTO smoke_worker_session VALUES ('worker-session')");
-await persistent.execute("SET application_name = 'packed-worker-session'");
-await persistent.execute('CHECKPOINT');
-const workerArchive = await persistent.backup();
-const workerSessionState = (await persistent.queryRaw(
-  "SELECT (SELECT value FROM smoke_worker_session) || ':' || current_setting('application_name') AS value",
-)).getText(0, 'value');
-await persistent.close();
-
-const directRestoreStorage = directory(new URL('./direct-backup-restore', import.meta.url));
-await WorkerOliphaunt.restore(directRestoreStorage, directArchive);
-let restored = await WorkerOliphaunt.open({
-  storage: directRestoreStorage,
-  extensions: [pgtap],
-});
-const directBackupRows = (await restored.queryRaw(
-  'SELECT count(*)::int AS count FROM smoke_persistence',
-)).getText(0, 'count');
-const directBackupValues = await richBackupValues(restored);
-const directBackupSequence = (await restored.queryRaw(
-  "SELECT nextval('smoke_persistence_seq')::text AS value",
-)).getText(0, 'value');
-await restored.close();
-
-const workerRestoreStorage = directory(new URL('./worker-backup-restore', import.meta.url));
-await Oliphaunt.restore(workerRestoreStorage, workerArchive);
-restored = await Oliphaunt.open({
-  storage: workerRestoreStorage,
-  extensions: [pgtap],
-});
-const workerBackupRows = (await restored.queryRaw(
-  'SELECT count(*)::int AS count FROM smoke_persistence',
-)).getText(0, 'count');
-const workerBackupValues = await richBackupValues(restored);
-const workerBackupSequence = (await restored.queryRaw(
-  "SELECT nextval('smoke_persistence_seq')::text AS value",
-)).getText(0, 'value');
-await restored.close();
-let corruptRestore;
-try {
-  await WorkerOliphaunt.restore(
-    directory(new URL('./corrupt-backup-restore', import.meta.url)),
-    Uint8Array.of(1, 2, 3),
-  );
-} catch (error) {
-  if (!(error instanceof WasixStorageError)) throw error;
-  corruptRestore = error.code + ':' + error.commitState;
-}
-if (
-  busy !== 'busy' ||
-  workerPersistedRows !== '3' ||
-  directBackupRows !== '3' ||
-  workerBackupRows !== '4' ||
-  directBackupValues !== 'café 🐘:00ff10:NULL|mañana::NULL|東京:deadbeef:present' ||
-  workerBackupValues !== 'café 🐘:00ff10:NULL|mañana::NULL|naïve:010203:NULL|東京:deadbeef:present' ||
-  directBackupSequence !== '13' ||
-  workerBackupSequence !== '14' ||
-  directSessionState !== 'direct-session:packed-direct-session' ||
-  workerSessionState !== 'worker-session:packed-worker-session' ||
-  corruptRestore !== 'corrupt:unchanged' ||
-  persistentExtension !== actor.version
-) {
-  throw new Error(JSON.stringify({
-    busy,
-    workerPersistedRows,
-    directBackupRows,
-    workerBackupRows,
-    directBackupValues,
-    workerBackupValues,
-    directBackupSequence,
-    workerBackupSequence,
-    directSessionState,
-    workerSessionState,
-    corruptRestore,
-    persistentExtension,
-    version: actor.version,
-  }));
-}
-console.log(JSON.stringify({
-  host: runtime + '-actor-direct-worker',
-  executionSurfaces,
-  surfaceResults: { actor, direct, worker, server },
-  extension: 'pgtap',
-  version: actor.version,
-  storage: runtime + '-raw-pgdata-delta',
-  busy,
-  workerPersistedRows,
-  backupRestore: {
-    directBackupRows,
-    workerBackupRows,
-    directBackupSequence,
-    workerBackupSequence,
-    corruptRestore,
-  },
-}));
-
-async function richBackupValues(db) {
-  const index = (await db.queryRaw(
-    "SELECT to_regclass('smoke_persistence_label_idx')::text AS value",
-  )).getText(0, 'value');
-  if (index !== 'smoke_persistence_label_idx') {
-    throw new Error('restored physical backup omitted smoke_persistence_label_idx: ' + index);
-  }
-  return (await db.queryRaw(
-    ${JSON.stringify(
-      "SELECT string_agg(label || ':' || encode(payload, 'hex') || ':' || " +
-        "coalesce(optional_value, 'NULL'), '|' ORDER BY label COLLATE \"C\") AS value " +
-        'FROM smoke_persistence',
-    )}
-  )).getText(0, 'value');
-}
-}
-`,
-  );
-  const verification = runtimeVerificationCommand(
-    runtime,
-    pathToFileURL(resolve(fixture.consumer, 'verify.mjs')).href,
-  );
-  const { stdout } = await runFixtureCommand(
-    verification.command,
-    verification.args,
-    fixture.consumer,
-    300_000,
-    verification.env,
-  );
-  console.log(`wasix-ts ${runtimeName} smoke: PASS ${stdout.trim()}`);
-} finally {
-  await rm(scratch, { force: true, recursive: true });
-}
-
-function readOptions(args) {
-  let packageOnly = false;
-  let runtime = 'node';
-  for (let index = 0; index < args.length; index += 1) {
-    const argument = args[index];
-    if (argument === '--package-only' && !packageOnly) {
-      packageOnly = true;
-      continue;
-    }
-    if (
-      argument === '--runtime' &&
-      index + 1 < args.length &&
-      ['bun', 'deno', 'electron', 'node'].includes(args[index + 1])
-    ) {
-      runtime = args[index + 1];
-      index += 1;
-      continue;
-    }
-    throw new Error('usage: smoke-node.mjs [--runtime node|bun|deno|electron] [--package-only]');
-  }
-  return { packageOnly, runtime };
-}
-
-function runtimeVerificationCommand(runtime, verificationUrl) {
-  const expression = `await import(${JSON.stringify(verificationUrl)})`;
-  switch (runtime) {
-    case 'node':
-      return {
-        command: process.execPath,
-        args: ['--input-type=module', '--eval', expression],
-      };
-    case 'bun':
-      return {
-        command: resolve(repositoryRoot, 'tools/dev/bun.sh'),
-        args: ['--eval', expression],
-      };
-    case 'deno':
-      return {
-        command: resolve(repositoryRoot, 'tools/dev/deno.sh'),
-        args: [
-          'run',
-          '--allow-env',
-          '--allow-ffi',
-          '--allow-net=127.0.0.1',
-          '--allow-read',
-          verificationUrl,
-        ],
-      };
-    case 'electron':
-      return {
-        command: 'npm',
-        args: [
-          'exec',
-          '--yes',
-          '--package=electron@39.2.5',
-          '--',
-          'electron',
-          fileURLToPath(verificationUrl),
-        ],
-        env: {
-          ELECTRON_RUN_AS_NODE: '1',
-          NPM_CONFIG_IGNORE_SCRIPTS: 'false',
-          PNPM_CONFIG_IGNORE_SCRIPTS: 'false',
-        },
-      };
-  }
-}
diff --git a/tools/integration/wasix-ts/smoke-tools-host.mjs b/tools/integration/wasix-ts/smoke-tools-host.mjs
deleted file mode 100644
index 3bca02a73..000000000
--- a/tools/integration/wasix-ts/smoke-tools-host.mjs
+++ /dev/null
@@ -1,301 +0,0 @@
-import { mkdtemp, readFile, rm } from 'node:fs/promises';
-import { tmpdir } from 'node:os';
-import { dirname, join, resolve } from 'node:path';
-import { fileURLToPath, pathToFileURL } from 'node:url';
-
-import { createPackedWasixConsumer } from './packed-node-fixture.mjs';
-import {
-  connect,
-  controlPacket,
-  onceClosed,
-  onceConnected,
-  readExchange,
-  readSingleByte,
-  simpleQuery,
-  startupPacket,
-} from '../../../src/bindings/wasix-ts/tools/pgwire-client.mjs';
-
-const root = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');
-const runtimeName = readRuntime(process.argv.slice(2));
-const seed = await readFile(
-  resolve(root, 'src/shared/fixtures/postgres/logical-tools-seed.sql'),
-  'utf8',
-);
-const verify = await readFile(
-  resolve(root, 'src/shared/fixtures/postgres/logical-tools-verify.sql'),
-  'utf8',
-);
-const fixture = JSON.parse(
-  await readFile(resolve(root, 'src/shared/fixtures/postgres/logical-tools.json'), 'utf8'),
-);
-const socketOperationTimeoutMs = 30_000;
-const queuedClientObservationMs = 100;
-const scratch = await mkdtemp(join(tmpdir(), `oliphaunt-wasix-${runtimeName}-tools-`));
-
-try {
-  const packed = await createPackedWasixConsumer({
-    scratch,
-    consumerName: `oliphaunt-wasix-${runtimeName}-tools-consumer`,
-    includePgtap: true,
-    includeTools: true,
-  });
-  const packageRoot = (name) => resolve(packed.consumer, 'node_modules', ...name.split('/'));
-  const runtime = (
-    await import(pathToFileURL(resolve(packageRoot(packed.packages.runtime.name), 'index.js')).href)
-  ).default;
-  const { default: Oliphaunt } = await import(
-    pathToFileURL(resolve(packageRoot(packed.packages.binding.name), `lib/index.${runtimeName}.js`))
-      .href
-  );
-  const { default: WorkerOliphaunt } = await import(
-    pathToFileURL(
-      resolve(packageRoot(packed.packages.binding.name), `lib/worker-entry.${runtimeName}.js`),
-    ).href
-  );
-  const { PostgresToolError, pgDump, psql } = await import(
-    pathToFileURL(resolve(packageRoot(packed.packages.toolsFacade.name), 'lib/index.js')).href
-  );
-  const { openServer } = await import(
-    pathToFileURL(resolve(packageRoot(packed.packages.binding.name), 'lib/server.node.js')).href
-  );
-  const { default: extension } = await import(
-    pathToFileURL(resolve(packageRoot(packed.packages.extension.name), 'index.js')).href
-  );
-
-  console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: logical tools`);
-  await verifyLogicalTools({
-    Oliphaunt,
-    WorkerOliphaunt,
-    PostgresToolError,
-    pgDump,
-    psql,
-    extension,
-  });
-  console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: TCP server`);
-  await verifyServer(openServer, { transport: 'tcp' });
-  if (process.platform !== 'win32') {
-    const directory = await mkdtemp(join(tmpdir(), `oliphaunt-wasix-${runtimeName}-socket-`));
-    try {
-      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: Unix server`);
-      await verifyServer(openServer, { transport: 'unix', directory, port: 6543 });
-    } finally {
-      await rm(directory, { force: true, recursive: true });
-    }
-  }
-} finally {
-  await rm(scratch, { force: true, recursive: true });
-}
-
-console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: PASS`);
-
-async function verifyLogicalTools({
-  Oliphaunt,
-  WorkerOliphaunt,
-  PostgresToolError,
-  pgDump,
-  psql,
-  extension,
-}) {
-  const source = await WorkerOliphaunt.open({ extensions: [extension] });
-  let sql;
-  try {
-    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: psql seed`);
-    await psql(source, { script: seed });
-    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: pg_dump`);
-    sql = await pgDump(source);
-    if (!sql.includes('COPY public.logical_items') || sql.includes('--inserts')) {
-      throw new Error('pg_dump did not preserve standard plain COPY output');
-    }
-    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: pg_dump schema`);
-    const schema = await pgDump(source, { args: ['--schema-only'] });
-    if (!schema.includes('CREATE TABLE') || schema.includes('COPY public.logical_items')) {
-      throw new Error('pg_dump --schema-only returned an invalid logical dump');
-    }
-    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: psql error`);
-    try {
-      await psql(source, { command: 'SELEC 1' });
-      throw new Error('invalid psql command unexpectedly succeeded');
-    } catch (error) {
-      if (!(error instanceof PostgresToolError) || error.exitCode === null || error.stderr === '') {
-        throw error;
-      }
-    }
-  } finally {
-    await source.close();
-  }
-
-  if (runtimeName === 'node') {
-    await verifyDirectPgDump(Oliphaunt, pgDump);
-  }
-
-  const target = await WorkerOliphaunt.open({ extensions: [extension] });
-  try {
-    console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: psql restore`);
-    await psql(target, { script: sql });
-    const result = await target.queryRaw(verify);
-    const expected = fixture.expected;
-    const actual = {
-      rows: Number(result.getText(0, 'rows')),
-      sum: Number(result.getText(0, 'sum')),
-      sequenceLastValue: Number(result.getText(0, 'sequence_last_value')),
-      quotedValue: result.getText(0, 'quoted_value'),
-      normalizedMatches: Number(result.getText(0, 'normalized_matches')),
-      extensionLoaded: result.getText(0, 'extension_loaded') === 't',
-    };
-    if (JSON.stringify(actual) !== JSON.stringify(expected)) {
-      throw new Error(
-        `logical tool round trip differed from the shared fixture: ${JSON.stringify(actual)}`,
-      );
-    }
-  } finally {
-    await target.close();
-  }
-}
-
-async function verifyDirectPgDump(Oliphaunt, pgDump) {
-  console.log('WASIX TypeScript node tools/server smoke: direct pg_dump');
-  const database = await Oliphaunt.open();
-  try {
-    await database.execute(
-      'CREATE TABLE direct_dump_probe (id integer PRIMARY KEY, value text NOT NULL)',
-    );
-    await database.execute("INSERT INTO direct_dump_probe VALUES (1, 'same-realm')");
-    const sql = await pgDump(database);
-    if (!sql.includes('COPY public.direct_dump_probe') || !sql.includes('same-realm')) {
-      throw new Error('direct pg_dump did not preserve standard plain COPY output');
-    }
-    const result = await database.queryRaw('SELECT count(*)::int AS rows FROM direct_dump_probe');
-    if (result.getText(0, 'rows') !== '1') {
-      throw new Error('direct database was not usable after pg_dump');
-    }
-  } finally {
-    await database.close();
-  }
-}
-
-async function verifyServer(openServer, listen) {
-  const server = await openServer({ listen });
-  try {
-    const socket = connect(server.connectionString);
-    let queued;
-    let queuedStartup;
-    try {
-      await withSocketDeadline(socket, onceConnected(socket), 'first client connect');
-      for (const code of [80_877_103, 80_877_104]) {
-        const negotiation = withSocketDeadline(
-          socket,
-          readSingleByte(socket),
-          `PostgreSQL negotiation ${code}`,
-        );
-        socket.write(controlPacket(code));
-        const response = await negotiation;
-        if (response !== 'N'.charCodeAt(0)) {
-          throw new Error(
-            `local server returned ${response} for PostgreSQL negotiation request ${code}`,
-          );
-        }
-      }
-      const firstStartup = withSocketDeadline(socket, readExchange(socket), 'first client startup');
-      socket.write(startupPacket('postgres', 'postgres'));
-      await firstStartup;
-      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: first startup`);
-
-      // The Rust listener deliberately owns one complete client at a time. A
-      // second TCP/Unix connection can finish its host handshake in the OS
-      // backlog, but its PostgreSQL startup must wait for the active backend.
-      queued = connect(server.connectionString);
-      await withSocketDeadline(queued, onceConnected(queued), 'queued client connect');
-      queuedStartup = readExchange(queued);
-      queued.write(startupPacket('postgres', 'postgres'));
-      await expectStillPending(queuedStartup, queuedClientObservationMs, 'queued client startup');
-      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: second client queued`);
-
-      const copy = withSocketDeadline(socket, readExchange(socket), 'first client COPY');
-      socket.write(simpleQuery('COPY (SELECT generate_series(1, 100000)) TO STDOUT'));
-      const copied = await copy;
-      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: first COPY`);
-      if (copied.copyBytes < 500_000) {
-        throw new Error(`local server truncated COPY output at ${copied.copyBytes} bytes`);
-      }
-      const begin = withSocketDeadline(socket, readExchange(socket), 'first client BEGIN');
-      socket.write(simpleQuery('BEGIN'));
-      await begin;
-      const create = withSocketDeadline(
-        socket,
-        readExchange(socket),
-        'first client transaction query',
-      );
-      socket.write(simpleQuery('CREATE TABLE disconnect_must_rollback(value integer)'));
-      await create;
-      const firstClosed = withSocketDeadline(socket, onceClosed(socket), 'first client disconnect');
-      socket.destroy();
-      await firstClosed;
-      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: disconnect recovered`);
-
-      await withSocketDeadline(queued, queuedStartup, 'queued client startup after handoff');
-      const queuedQuery = withSocketDeadline(queued, readExchange(queued), 'queued client query');
-      queued.write(simpleQuery('CREATE TABLE disconnect_must_rollback(value integer)'));
-      await queuedQuery;
-      const queuedClosed = withSocketDeadline(queued, onceClosed(queued), 'queued client close');
-      queued.end(Uint8Array.of('X'.charCodeAt(0), 0, 0, 0, 4));
-      await queuedClosed;
-      console.log(`WASIX TypeScript ${runtimeName} tools/server smoke: queued client accepted`);
-    } finally {
-      socket.destroy();
-      queued?.destroy();
-      await queuedStartup?.catch(() => undefined);
-    }
-  } finally {
-    await server.close();
-  }
-}
-
-function withSocketDeadline(socket, operation, label) {
-  return new Promise((resolveOperation, rejectOperation) => {
-    let settled = false;
-    const finish = (settle, value) => {
-      if (settled) return;
-      settled = true;
-      clearTimeout(timeout);
-      settle(value);
-    };
-    const timeout = setTimeout(() => {
-      if (settled) return;
-      settled = true;
-      socket.destroy();
-      rejectOperation(new Error(`${label} timed out after ${socketOperationTimeoutMs}ms`));
-    }, socketOperationTimeoutMs);
-    operation.then(
-      (value) => finish(resolveOperation, value),
-      (error) => finish(rejectOperation, error),
-    );
-  });
-}
-
-async function expectStillPending(operation, observationMs, label) {
-  let timeout;
-  const observed = await Promise.race([
-    operation.then(
-      () => ({ status: 'resolved' }),
-      (error) => ({ status: 'rejected', error }),
-    ),
-    new Promise((resolveObservation) => {
-      timeout = setTimeout(() => resolveObservation({ status: 'pending' }), observationMs);
-    }),
-  ]);
-  clearTimeout(timeout);
-  if (observed.status === 'pending') return;
-  if (observed.status === 'rejected') {
-    throw new Error(`${label} was rejected instead of waiting behind the active client`, {
-      cause: observed.error,
-    });
-  }
-  throw new Error(`${label} completed while the first client still owned the embedded backend`);
-}
-
-function readRuntime(args) {
-  if (args.length !== 2 || args[0] !== '--runtime' || !['node', 'bun', 'deno'].includes(args[1])) {
-    throw new Error('usage: smoke-host.mjs --runtime node|bun|deno');
-  }
-  return args[1];
-}
diff --git a/tools/native-extension-proof/Cargo.toml b/tools/native-extension-proof/Cargo.toml
deleted file mode 100644
index 8feb880df..000000000
--- a/tools/native-extension-proof/Cargo.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[package]
-name = "oliphaunt-native-extension-proof"
-version = "0.0.0"
-edition.workspace = true
-rust-version.workspace = true
-license.workspace = true
-publish = false
-
-[features]
-default = []
-
-[dependencies]
-oliphaunt = { path = "../../src/sdks/rust" }
-tar = "0.4"
diff --git a/tools/native-extension-proof/src/main.rs b/tools/native-extension-proof/src/main.rs
deleted file mode 100644
index 4ed168a39..000000000
--- a/tools/native-extension-proof/src/main.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-#![allow(dead_code)]
-
-include!("../../../src/sdks/rust/tests/native_extensions.rs");
-
-fn parse_usize_flag(arguments: &[String], name: &str, default: usize) -> usize {
-    let flag = format!("--{name}");
-    for (index, argument) in arguments.iter().enumerate() {
-        if argument == &flag {
-            return arguments
-                .get(index + 1)
-                .unwrap_or_else(|| panic!("{flag} requires a value"))
-                .parse::()
-                .unwrap_or_else(|_| panic!("{flag} must be an unsigned integer"));
-        }
-        if let Some(value) = argument.strip_prefix(&format!("{flag}=")) {
-            return value
-                .parse::()
-                .unwrap_or_else(|_| panic!("{flag} must be an unsigned integer"));
-        }
-    }
-    default
-}
-
-fn main() {
-    if let Some(result) = run_direct_extension_child_from_env() {
-        result.expect("native extension proof direct child failed");
-        return;
-    }
-    unsafe {
-        std::env::set_var(RELEASE_PROOF_RUNNER_ENV, "1");
-    }
-    let arguments = std::env::args().skip(1).collect::>();
-    if arguments.first().map(String::as_str) == Some("--native-tools-npm-smoke") {
-        let command = arguments
-            .get(1..)
-            .filter(|arguments| arguments.first().map(String::as_str) == Some("--"))
-            .and_then(|arguments| arguments.get(1..))
-            .filter(|command| !command.is_empty())
-            .expect("usage: oliphaunt-native-extension-proof --native-tools-npm-smoke -- COMMAND [ARG ...]");
-        run_native_tools_npm_smoke(command).expect("packed native npm tools smoke failed");
-        return;
-    }
-    let shard_index = parse_usize_flag(&arguments, "shard-index", 0);
-    let shard_count = parse_usize_flag(&arguments, "shard-count", 1);
-    run_native_extension_release_proof(shard_index, shard_count);
-}
-
-fn run_native_tools_npm_smoke(
-    command: &[String],
-) -> std::result::Result<(), Box> {
-    let root = unique_temp_root("native-tools-npm-smoke");
-    let server = block_on(
-        OliphauntServer::builder()
-            .storage(DatabaseStorage::Directory(root.clone()))
-            .extension(Extension::PGTAP)
-            .start(),
-    )?;
-    let child = Command::new(&command[0])
-        .args(&command[1..])
-        .env(
-            "OLIPHAUNT_NATIVE_TOOLS_CONNECTION_STRING",
-            server.connection_string(),
-        )
-        .status();
-    let close = block_on(server.close());
-    let _ = fs::remove_dir_all(&root);
-    let status = child?;
-    close?;
-    if !status.success() {
-        return Err(std::io::Error::other(format!(
-            "packed native npm tools smoke command exited with {status}"
-        ))
-        .into());
-    }
-    println!("OLIPHAUNT_NATIVE_TOOLS_NPM_SMOKE_PASS engines=node,bun,deno");
-    Ok(())
-}
diff --git a/tools/native-packaging/Cargo.toml b/tools/native-packaging/Cargo.toml
deleted file mode 100644
index 0886d3999..000000000
--- a/tools/native-packaging/Cargo.toml
+++ /dev/null
@@ -1,40 +0,0 @@
-[package]
-name = "oliphaunt-native-packaging"
-version = "0.0.0"
-edition.workspace = true
-rust-version.workspace = true
-license.workspace = true
-publish = false
-
-[features]
-default = []
-extension-download = ["dep:ureq"]
-extension-signing = ["dep:ed25519-dalek"]
-
-[dependencies]
-ed25519-dalek = { version = "2.2", default-features = false, features = ["alloc"], optional = true }
-flate2 = "1"
-oliphaunt = { path = "../../src/sdks/rust", features = ["internal-native-packaging"] }
-serde = { version = "1", features = ["derive"] }
-serde_json = "1"
-sha2 = "0.10"
-tar = "0.4"
-toml = "0.9"
-ureq = { version = "2.12", default-features = false, features = ["tls"], optional = true }
-zip = { version = "2", default-features = false, features = ["deflate"] }
-zstd = { version = "0.13", default-features = false }
-
-[dev-dependencies]
-tempfile = "3"
-
-[[bin]]
-name = "oliphaunt-resources"
-path = "src/bin/package_resources.rs"
-
-[[bin]]
-name = "oliphaunt-extension-artifact"
-path = "src/bin/extension_artifact.rs"
-
-[[bin]]
-name = "oliphaunt-extension-index"
-path = "src/bin/extension_index.rs"
diff --git a/tools/native-packaging/README.md b/tools/native-packaging/README.md
deleted file mode 100644
index 4b9e15c81..000000000
--- a/tools/native-packaging/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Native packaging tools
-
-This unpublished workspace crate owns maintainer-only native runtime-resource,
-extension-artifact, and extension-index packaging. It is used by release and
-platform-package automation; application code must use the published
-`oliphaunt` and `oliphaunt-build` crates instead.
-
-The three binaries retain their established command names:
-
-- `oliphaunt-resources`
-- `oliphaunt-extension-artifact`
-- `oliphaunt-extension-index`
-
-The crate reads the generated extension catalog and does not maintain a second
-extension inventory.
diff --git a/tools/native-packaging/moon.yml b/tools/native-packaging/moon.yml
deleted file mode 100644
index f31bc0780..000000000
--- a/tools/native-packaging/moon.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "native-packaging"
-language: "rust"
-layer: "tool"
-stack: "systems"
-tags: ["maintainer-tool", "native", "rust"]
-dependsOn:
-  - id: "extensions"
-    scope: "build"
-  - id: "extension-runtime-contract"
-    scope: "build"
-
-project:
-  title: "Native packaging tools"
-  description: "Unpublished maintainer tooling for native runtime and extension packages."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/sdk-rust"
-
-tasks:
-  check:
-    tags: ["quality", "static", "requires-rust"]
-    command: "cargo check -p oliphaunt-native-packaging --locked --all-targets"
-    env:
-      CARGO_TARGET_DIR: "target/moon/native-packaging/check"
-    inputs:
-      - "@group(cargo-workspace)"
-      - project: "extensions"
-        group: "sdk-metadata"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - project: "oliphaunt-rust"
-        group: "code"
-      - "**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
-  unit:
-    tags: ["quality", "unit", "requires-rust"]
-    command: "cargo test -p oliphaunt-native-packaging --locked"
-    env:
-      CARGO_TARGET_DIR: "target/moon/native-packaging/unit"
-    inputs:
-      - "@group(cargo-workspace)"
-      - project: "extensions"
-        group: "sdk-metadata"
-      - project: "extension-runtime-contract"
-        group: "contract"
-      - project: "oliphaunt-rust"
-        group: "code"
-      - "**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
diff --git a/tools/native-packaging/src/bin/extension_artifact.rs b/tools/native-packaging/src/bin/extension_artifact.rs
deleted file mode 100644
index 3c5b5cde9..000000000
--- a/tools/native-packaging/src/bin/extension_artifact.rs
+++ /dev/null
@@ -1,705 +0,0 @@
-use std::env;
-use std::path::PathBuf;
-use std::process;
-
-use oliphaunt_native_packaging::{
-    Error, NativeExtensionArtifactFormat, NativeExtensionArtifactLegalContract,
-    NativeExtensionArtifactLicenseProfile, NativeExtensionArtifactOptions,
-    NativeExtensionMobileStaticArchive, NativeExtensionMobileStaticDependencyArchive,
-    NativeExtensionStaticSymbolAlias, Result, create_prebuilt_extension_artifact,
-};
-
-fn main() {
-    match run() {
-        Ok(()) => {}
-        Err(error) => {
-            eprintln!("oliphaunt-extension-artifact: {error}");
-            process::exit(2);
-        }
-    }
-}
-
-fn run() -> Result<()> {
-    let args = ArtifactArgs::parse(env::args().skip(1))?;
-    if args.help {
-        print_help();
-        return Ok(());
-    }
-    let output = args
-        .output
-        .ok_or_else(|| Error::InvalidConfig("missing required --output ".to_owned()))?;
-    let runtime = args
-        .runtime
-        .ok_or_else(|| Error::InvalidConfig("missing required --runtime ".to_owned()))?;
-    let sql_name = args.sql_name.ok_or_else(|| {
-        Error::InvalidConfig("missing required --sql-name ".to_owned())
-    })?;
-    let native_runtime_version = args.native_runtime_version.ok_or_else(|| {
-        Error::InvalidConfig(
-            "missing required --native-runtime-version  (or OLIPHAUNT_LIBOLIPHAUNT_VERSION)"
-                .to_owned(),
-        )
-    })?;
-    let license_profile = args.license_profile.ok_or_else(|| {
-        Error::InvalidConfig("missing required --license-profile ".to_owned())
-    })?;
-    let legal_files_root = args.legal_files_root.ok_or_else(|| {
-        Error::InvalidConfig("missing required --legal-files-root ".to_owned())
-    })?;
-    let legal_contract =
-        NativeExtensionArtifactLegalContract::new(license_profile, legal_files_root)
-            .license_files(args.license_files);
-
-    let mut options =
-        NativeExtensionArtifactOptions::new(output, runtime, sql_name, native_runtime_version)
-            .creates_extension(args.creates_extension)
-            .format(args.format)
-            .replace_existing(args.force)
-            .dependencies(args.dependencies)
-            .data_files(args.data_files)
-            .extension_sql_file_names(args.extension_sql_file_names)
-            .extension_sql_file_prefixes(args.extension_sql_file_prefixes)
-            .shared_preload_libraries(args.shared_preload_libraries)
-            .mobile_prebuilt(args.mobile_prebuilt)
-            .mobile_static_archives(args.mobile_static_archives)
-            .mobile_static_dependency_archives(args.mobile_static_dependency_archives)
-            .static_symbol_aliases(args.static_symbol_aliases)
-            .legal_contract(legal_contract);
-    if let Some(stem) = args.native_module_stem {
-        options = options.native_module_stem(stem);
-    }
-    if let Some(file) = args.native_module_file {
-        options = options.native_module_file(file);
-    }
-    if let Some(target) = args.native_target {
-        options = options.native_target(target);
-    }
-    if let Some(root) = args.embedded_module_root {
-        options = options.embedded_module_root(root);
-    }
-    if let Some(prefix) = args.static_symbol_prefix {
-        options = options.static_symbol_prefix(prefix);
-    }
-
-    let artifact = create_prebuilt_extension_artifact(options)?;
-    println!("path={}", artifact.path.display());
-    println!("sqlName={}", artifact.sql_name);
-    println!("format={}", artifact_format_label(artifact.format));
-    println!(
-        "manifest={}",
-        artifact
-            .manifest_path
-            .as_ref()
-            .map(|path| path.display().to_string())
-            .unwrap_or_default()
-    );
-    Ok(())
-}
-
-struct ArtifactArgs {
-    output: Option,
-    runtime: Option,
-    sql_name: Option,
-    native_runtime_version: Option,
-    license_profile: Option,
-    legal_files_root: Option,
-    license_files: Vec,
-    creates_extension: bool,
-    native_module_stem: Option,
-    native_module_file: Option,
-    native_target: Option,
-    embedded_module_root: Option,
-    dependencies: Vec,
-    data_files: Vec,
-    extension_sql_file_names: Vec,
-    extension_sql_file_prefixes: Vec,
-    shared_preload_libraries: Vec,
-    mobile_prebuilt: bool,
-    mobile_static_archives: Vec,
-    mobile_static_dependency_archives: Vec,
-    static_symbol_prefix: Option,
-    static_symbol_aliases: Vec,
-    format: NativeExtensionArtifactFormat,
-    force: bool,
-    help: bool,
-}
-
-impl ArtifactArgs {
-    fn parse(args: impl IntoIterator) -> Result {
-        let mut parsed = Self {
-            output: None,
-            runtime: None,
-            sql_name: None,
-            native_runtime_version: env::var("OLIPHAUNT_LIBOLIPHAUNT_VERSION")
-                .ok()
-                .filter(|value| !value.trim().is_empty()),
-            license_profile: None,
-            legal_files_root: None,
-            license_files: Vec::new(),
-            creates_extension: true,
-            native_module_stem: None,
-            native_module_file: None,
-            native_target: None,
-            embedded_module_root: None,
-            dependencies: Vec::new(),
-            data_files: Vec::new(),
-            extension_sql_file_names: Vec::new(),
-            extension_sql_file_prefixes: Vec::new(),
-            shared_preload_libraries: Vec::new(),
-            mobile_prebuilt: false,
-            mobile_static_archives: Vec::new(),
-            mobile_static_dependency_archives: Vec::new(),
-            static_symbol_prefix: None,
-            static_symbol_aliases: Vec::new(),
-            format: NativeExtensionArtifactFormat::Directory,
-            force: false,
-            help: false,
-        };
-
-        let mut args = args.into_iter();
-        while let Some(arg) = args.next() {
-            match arg.as_str() {
-                "-h" | "--help" => parsed.help = true,
-                "--force" => parsed.force = true,
-                "--no-create-extension" => parsed.creates_extension = false,
-                "--mobile-prebuilt" => parsed.mobile_prebuilt = true,
-                "--no-mobile-prebuilt" => parsed.mobile_prebuilt = false,
-                "--output" | "-o" => {
-                    parsed.output = Some(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                "--runtime" => {
-                    parsed.runtime = Some(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                "--sql-name" => {
-                    parsed.sql_name = Some(next_value(&mut args, &arg)?);
-                }
-                "--native-runtime-version" | "--liboliphaunt-native-version" => {
-                    parsed.native_runtime_version = Some(next_value(&mut args, &arg)?);
-                }
-                "--license-profile" => {
-                    parsed.license_profile = Some(NativeExtensionArtifactLicenseProfile::parse(
-                        &next_value(&mut args, &arg)?,
-                    )?);
-                }
-                "--legal-files-root" => {
-                    parsed.legal_files_root = Some(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                "--license-file" | "--license-files" => {
-                    push_paths(&mut parsed.license_files, &next_value(&mut args, &arg)?);
-                }
-                "--format" => {
-                    parsed.format = parse_format(&next_value(&mut args, &arg)?)?;
-                }
-                "--creates-extension" => {
-                    parsed.creates_extension = parse_bool(&next_value(&mut args, &arg)?)?;
-                }
-                "--native-module-stem" => {
-                    parsed.native_module_stem = Some(next_value(&mut args, &arg)?);
-                }
-                "--native-module-file" => {
-                    parsed.native_module_file = Some(next_value(&mut args, &arg)?);
-                }
-                "--native-target" | "--target" => {
-                    parsed.native_target = Some(next_value(&mut args, &arg)?);
-                }
-                "--embedded-module-root" => {
-                    parsed.embedded_module_root = Some(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                "--dependency" | "--dependencies" => {
-                    push_strings(&mut parsed.dependencies, &next_value(&mut args, &arg)?);
-                }
-                "--data-file" | "--data-files" => {
-                    push_paths(&mut parsed.data_files, &next_value(&mut args, &arg)?);
-                }
-                "--extension-sql-file-name" | "--extension-sql-file-names" => {
-                    push_strings(
-                        &mut parsed.extension_sql_file_names,
-                        &next_value(&mut args, &arg)?,
-                    );
-                }
-                "--extension-sql-file-prefix" | "--extension-sql-file-prefixes" => {
-                    push_strings(
-                        &mut parsed.extension_sql_file_prefixes,
-                        &next_value(&mut args, &arg)?,
-                    );
-                }
-                "--shared-preload-library" | "--shared-preload-libraries" => {
-                    push_strings(
-                        &mut parsed.shared_preload_libraries,
-                        &next_value(&mut args, &arg)?,
-                    );
-                }
-                "--mobile-static-archive" | "--mobile-static-archives" => {
-                    push_mobile_static_archives(
-                        &mut parsed.mobile_static_archives,
-                        &next_value(&mut args, &arg)?,
-                    )?;
-                }
-                "--mobile-static-dependency-archive" | "--mobile-static-dependency-archives" => {
-                    push_mobile_static_dependency_archives(
-                        &mut parsed.mobile_static_dependency_archives,
-                        &next_value(&mut args, &arg)?,
-                    )?;
-                }
-                "--static-symbol-prefix" => {
-                    parsed.static_symbol_prefix = Some(next_value(&mut args, &arg)?);
-                }
-                "--static-symbol-alias" | "--static-symbol-aliases" => {
-                    push_static_symbol_aliases(
-                        &mut parsed.static_symbol_aliases,
-                        &next_value(&mut args, &arg)?,
-                    )?;
-                }
-                value if value.starts_with("--output=") => {
-                    parsed.output = Some(PathBuf::from(value_without_prefix(value, "--output=")));
-                }
-                value if value.starts_with("--runtime=") => {
-                    parsed.runtime = Some(PathBuf::from(value_without_prefix(value, "--runtime=")));
-                }
-                value if value.starts_with("--sql-name=") => {
-                    parsed.sql_name = Some(value_without_prefix(value, "--sql-name=").to_owned());
-                }
-                value if value.starts_with("--native-runtime-version=") => {
-                    parsed.native_runtime_version =
-                        Some(value_without_prefix(value, "--native-runtime-version=").to_owned());
-                }
-                value if value.starts_with("--liboliphaunt-native-version=") => {
-                    parsed.native_runtime_version = Some(
-                        value_without_prefix(value, "--liboliphaunt-native-version=").to_owned(),
-                    );
-                }
-                value if value.starts_with("--license-profile=") => {
-                    parsed.license_profile = Some(NativeExtensionArtifactLicenseProfile::parse(
-                        value_without_prefix(value, "--license-profile="),
-                    )?);
-                }
-                value if value.starts_with("--legal-files-root=") => {
-                    parsed.legal_files_root = Some(PathBuf::from(value_without_prefix(
-                        value,
-                        "--legal-files-root=",
-                    )));
-                }
-                value if value.starts_with("--license-file=") => {
-                    push_paths(
-                        &mut parsed.license_files,
-                        value_without_prefix(value, "--license-file="),
-                    );
-                }
-                value if value.starts_with("--license-files=") => {
-                    push_paths(
-                        &mut parsed.license_files,
-                        value_without_prefix(value, "--license-files="),
-                    );
-                }
-                value if value.starts_with("--format=") => {
-                    parsed.format = parse_format(value_without_prefix(value, "--format="))?;
-                }
-                value if value.starts_with("--creates-extension=") => {
-                    parsed.creates_extension =
-                        parse_bool(value_without_prefix(value, "--creates-extension="))?;
-                }
-                value if value.starts_with("--native-module-stem=") => {
-                    parsed.native_module_stem =
-                        Some(value_without_prefix(value, "--native-module-stem=").to_owned());
-                }
-                value if value.starts_with("--native-module-file=") => {
-                    parsed.native_module_file =
-                        Some(value_without_prefix(value, "--native-module-file=").to_owned());
-                }
-                value if value.starts_with("--native-target=") => {
-                    parsed.native_target =
-                        Some(value_without_prefix(value, "--native-target=").to_owned());
-                }
-                value if value.starts_with("--target=") => {
-                    parsed.native_target =
-                        Some(value_without_prefix(value, "--target=").to_owned());
-                }
-                value if value.starts_with("--embedded-module-root=") => {
-                    parsed.embedded_module_root = Some(PathBuf::from(value_without_prefix(
-                        value,
-                        "--embedded-module-root=",
-                    )));
-                }
-                value if value.starts_with("--dependency=") => {
-                    push_strings(
-                        &mut parsed.dependencies,
-                        value_without_prefix(value, "--dependency="),
-                    );
-                }
-                value if value.starts_with("--dependencies=") => {
-                    push_strings(
-                        &mut parsed.dependencies,
-                        value_without_prefix(value, "--dependencies="),
-                    );
-                }
-                value if value.starts_with("--data-file=") => {
-                    push_paths(
-                        &mut parsed.data_files,
-                        value_without_prefix(value, "--data-file="),
-                    );
-                }
-                value if value.starts_with("--data-files=") => {
-                    push_paths(
-                        &mut parsed.data_files,
-                        value_without_prefix(value, "--data-files="),
-                    );
-                }
-                value if value.starts_with("--extension-sql-file-name=") => {
-                    push_strings(
-                        &mut parsed.extension_sql_file_names,
-                        value_without_prefix(value, "--extension-sql-file-name="),
-                    );
-                }
-                value if value.starts_with("--extension-sql-file-names=") => {
-                    push_strings(
-                        &mut parsed.extension_sql_file_names,
-                        value_without_prefix(value, "--extension-sql-file-names="),
-                    );
-                }
-                value if value.starts_with("--extension-sql-file-prefix=") => {
-                    push_strings(
-                        &mut parsed.extension_sql_file_prefixes,
-                        value_without_prefix(value, "--extension-sql-file-prefix="),
-                    );
-                }
-                value if value.starts_with("--extension-sql-file-prefixes=") => {
-                    push_strings(
-                        &mut parsed.extension_sql_file_prefixes,
-                        value_without_prefix(value, "--extension-sql-file-prefixes="),
-                    );
-                }
-                value if value.starts_with("--shared-preload-library=") => {
-                    push_strings(
-                        &mut parsed.shared_preload_libraries,
-                        value_without_prefix(value, "--shared-preload-library="),
-                    );
-                }
-                value if value.starts_with("--shared-preload-libraries=") => {
-                    push_strings(
-                        &mut parsed.shared_preload_libraries,
-                        value_without_prefix(value, "--shared-preload-libraries="),
-                    );
-                }
-                value if value.starts_with("--mobile-prebuilt=") => {
-                    parsed.mobile_prebuilt =
-                        parse_bool(value_without_prefix(value, "--mobile-prebuilt="))?;
-                }
-                value if value.starts_with("--mobile-static-archive=") => {
-                    push_mobile_static_archives(
-                        &mut parsed.mobile_static_archives,
-                        value_without_prefix(value, "--mobile-static-archive="),
-                    )?;
-                }
-                value if value.starts_with("--mobile-static-archives=") => {
-                    push_mobile_static_archives(
-                        &mut parsed.mobile_static_archives,
-                        value_without_prefix(value, "--mobile-static-archives="),
-                    )?;
-                }
-                value if value.starts_with("--mobile-static-dependency-archive=") => {
-                    push_mobile_static_dependency_archives(
-                        &mut parsed.mobile_static_dependency_archives,
-                        value_without_prefix(value, "--mobile-static-dependency-archive="),
-                    )?;
-                }
-                value if value.starts_with("--mobile-static-dependency-archives=") => {
-                    push_mobile_static_dependency_archives(
-                        &mut parsed.mobile_static_dependency_archives,
-                        value_without_prefix(value, "--mobile-static-dependency-archives="),
-                    )?;
-                }
-                value if value.starts_with("--static-symbol-prefix=") => {
-                    parsed.static_symbol_prefix =
-                        Some(value_without_prefix(value, "--static-symbol-prefix=").to_owned());
-                }
-                value if value.starts_with("--static-symbol-alias=") => {
-                    push_static_symbol_aliases(
-                        &mut parsed.static_symbol_aliases,
-                        value_without_prefix(value, "--static-symbol-alias="),
-                    )?;
-                }
-                value if value.starts_with("--static-symbol-aliases=") => {
-                    push_static_symbol_aliases(
-                        &mut parsed.static_symbol_aliases,
-                        value_without_prefix(value, "--static-symbol-aliases="),
-                    )?;
-                }
-                _ => {
-                    return Err(Error::InvalidConfig(format!("unknown argument '{arg}'")));
-                }
-            }
-        }
-        Ok(parsed)
-    }
-}
-
-fn next_value(args: &mut impl Iterator, flag: &str) -> Result {
-    args.next()
-        .ok_or_else(|| Error::InvalidConfig(format!("{flag} requires a value")))
-}
-
-fn value_without_prefix<'a>(value: &'a str, prefix: &str) -> &'a str {
-    value.strip_prefix(prefix).expect("prefix was checked")
-}
-
-fn parse_format(value: &str) -> Result {
-    match value {
-        "directory" | "dir" => Ok(NativeExtensionArtifactFormat::Directory),
-        "tar" => Ok(NativeExtensionArtifactFormat::Tar),
-        "tar-gz" | "tar.gz" | "tgz" | "gz" => Ok(NativeExtensionArtifactFormat::TarGz),
-        "tar-zst" | "tar.zst" | "zst" => Ok(NativeExtensionArtifactFormat::TarZst),
-        _ => Err(Error::InvalidConfig(format!(
-            "unknown extension artifact format '{value}'"
-        ))),
-    }
-}
-
-fn parse_bool(value: &str) -> Result {
-    match value {
-        "true" | "yes" | "1" => Ok(true),
-        "false" | "no" | "0" => Ok(false),
-        _ => Err(Error::InvalidConfig(format!(
-            "expected true/false, got '{value}'"
-        ))),
-    }
-}
-
-fn push_strings(target: &mut Vec, value: &str) {
-    for item in split_csv(value) {
-        target.push(item.to_owned());
-    }
-}
-
-fn push_paths(target: &mut Vec, value: &str) {
-    for item in split_csv(value) {
-        target.push(PathBuf::from(item));
-    }
-}
-
-fn push_mobile_static_archives(
-    target: &mut Vec,
-    value: &str,
-) -> Result<()> {
-    for item in split_csv(value) {
-        target.push(parse_mobile_static_archive(item)?);
-    }
-    Ok(())
-}
-
-fn parse_mobile_static_archive(value: &str) -> Result {
-    let separator = value.find('=').or_else(|| value.find(':')).ok_or_else(|| {
-        Error::InvalidConfig(
-            "--mobile-static-archive values must use : or ="
-                .to_owned(),
-        )
-    })?;
-    let (target, archive) = value.split_at(separator);
-    let archive = &archive[1..];
-    if target.trim().is_empty() || archive.trim().is_empty() {
-        return Err(Error::InvalidConfig(
-            "--mobile-static-archive values must include both target and archive path".to_owned(),
-        ));
-    }
-    Ok(NativeExtensionMobileStaticArchive::new(
-        target.trim(),
-        PathBuf::from(archive.trim()),
-    ))
-}
-
-fn push_mobile_static_dependency_archives(
-    target: &mut Vec,
-    value: &str,
-) -> Result<()> {
-    for item in split_csv(value) {
-        target.push(parse_mobile_static_dependency_archive(item)?);
-    }
-    Ok(())
-}
-
-fn parse_mobile_static_dependency_archive(
-    value: &str,
-) -> Result {
-    let (target_and_name, archive) = if let Some(separator) = value.find('=') {
-        let (left, right) = value.split_at(separator);
-        (left, &right[1..])
-    } else {
-        let mut parts = value.splitn(3, ':');
-        let target = parts.next().unwrap_or_default();
-        let name = parts.next().unwrap_or_default();
-        let archive = parts.next().unwrap_or_default();
-        if target.trim().is_empty() || name.trim().is_empty() || archive.trim().is_empty() {
-            return Err(Error::InvalidConfig(
-                "--mobile-static-dependency-archive values must use :: or :=".to_owned(),
-            ));
-        }
-        return Ok(NativeExtensionMobileStaticDependencyArchive::new(
-            target.trim(),
-            name.trim(),
-            PathBuf::from(archive.trim()),
-        ));
-    };
-    let Some((target, name)) = target_and_name.split_once(':') else {
-        return Err(Error::InvalidConfig(
-            "--mobile-static-dependency-archive values must use :: or :=".to_owned(),
-        ));
-    };
-    if target.trim().is_empty() || name.trim().is_empty() || archive.trim().is_empty() {
-        return Err(Error::InvalidConfig(
-            "--mobile-static-dependency-archive values must include target, name, and archive path"
-                .to_owned(),
-        ));
-    }
-    Ok(NativeExtensionMobileStaticDependencyArchive::new(
-        target.trim(),
-        name.trim(),
-        PathBuf::from(archive.trim()),
-    ))
-}
-
-fn push_static_symbol_aliases(
-    target: &mut Vec,
-    value: &str,
-) -> Result<()> {
-    for item in split_csv(value) {
-        target.push(parse_static_symbol_alias(item)?);
-    }
-    Ok(())
-}
-
-fn parse_static_symbol_alias(value: &str) -> Result {
-    let separator = value.find('=').or_else(|| value.find(':')).ok_or_else(|| {
-        Error::InvalidConfig(
-            "--static-symbol-alias values must use : or =".to_owned(),
-        )
-    })?;
-    let (sql_symbol, linked_symbol) = value.split_at(separator);
-    let linked_symbol = &linked_symbol[1..];
-    if sql_symbol.trim().is_empty() || linked_symbol.trim().is_empty() {
-        return Err(Error::InvalidConfig(
-            "--static-symbol-alias values must include both SQL and linked C symbols".to_owned(),
-        ));
-    }
-    Ok(NativeExtensionStaticSymbolAlias::new(
-        sql_symbol.trim(),
-        linked_symbol.trim(),
-    ))
-}
-
-fn split_csv(value: &str) -> impl Iterator {
-    value
-        .split(',')
-        .map(str::trim)
-        .filter(|value| !value.is_empty())
-}
-
-fn artifact_format_label(format: NativeExtensionArtifactFormat) -> &'static str {
-    match format {
-        NativeExtensionArtifactFormat::Directory => "directory",
-        NativeExtensionArtifactFormat::Tar => "tar",
-        NativeExtensionArtifactFormat::TarGz => "tar-gz",
-        NativeExtensionArtifactFormat::TarZst => "tar-zst",
-    }
-}
-
-fn print_help() {
-    println!(
-        "\
-Create one exact prebuilt Oliphaunt extension artifact from already-built PostgreSQL runtime files.
-
-Usage:
-  oliphaunt-extension-artifact --runtime  --sql-name  --native-runtime-version  --license-profile  --legal-files-root  --output  [--format directory|tar|tar-gz|tar-zst] [options]
-
-Options:
-  --native-runtime-version  Exact stable liboliphaunt-native version
-  --license-profile       contrib-native, contrib-native-openssl,
-                                    or external-native
-  --legal-files-root          Exact profile notices and license sources
-  --license-file      External license leaves below share/licenses
-  --native-module-stem        Native module stem used by extension SQL
-  --native-module-file        Target-specific file under lib/postgresql
-  --target                  Public target id that built the module
-  --embedded-module-root       Native-direct desktop modules directory
-  --dependency         Exact extension dependencies
-  --data-file          Extra files relative to share/postgresql
-  --extension-sql-file-name   Exact ancillary extension SQL basename
-  --extension-sql-file-prefix  Exact ancillary extension SQL prefix
-  --shared-preload-library    Required shared_preload_libraries entry
-  --mobile-static-archive :
-                                    Include a selected prebuilt iOS/Android .a
-  --mobile-static-dependency-archive ::
-                                    Include a static dependency archive linked
-                                    with selected mobile extension archives
-  --mobile-prebuilt[=yes|no]        Require carried mobile static archives
-  --static-symbol-prefix    C symbol prefix for mobile static artifacts
-  --static-symbol-alias :
-                                    Map a SQL C symbol to a linked archive symbol
-  --creates-extension       Whether control/SQL files are required
-  --no-create-extension             Alias for --creates-extension no
-  --force                           Replace an existing output path
-
-The command copies only files declared by the exact SQL extension name and the
-explicit metadata above. It never builds PostgreSQL or extension source in an
-app project. The resulting directory, .tar, .tar.gz, or .tar.zst can be passed
-to oliphaunt-resources --prebuilt-extension. Passing --mobile-static-archive
-marks the artifact mobile-prebuilt and stores the static archive inside the artifact.
-Dependency archives are copied alongside selected mobile static archives and
-linked by SDK builds when present. Native-module artifacts must declare a
-target so consumers cannot install a module built for a different platform.
-Every v1 manifest records nativeRuntimeProduct=liboliphaunt-native, the
-selected stable nativeRuntimeVersion, and the exact ancillary SQL
-names/prefixes copied into the carrier. The manifest also freezes the exact
-licenseProfile and sorted licenseFiles inventory; missing, extra, unsafe, or
-profile-inconsistent legal leaves are rejected by both producer and consumer.
-OLIPHAUNT_LIBOLIPHAUNT_VERSION is the environment equivalent of
---native-runtime-version.
-"
-    );
-}
-
-#[cfg(test)]
-mod tests {
-    use super::ArtifactArgs;
-
-    #[test]
-    fn ancillary_sql_flags_accept_repeated_and_csv_forms() {
-        let parsed = ArtifactArgs::parse([
-            "--extension-sql-file-name".to_owned(),
-            "uninstall_acme.sql".to_owned(),
-            "--extension-sql-file-names=acme_aux.sql,acme_data.sql".to_owned(),
-            "--extension-sql-file-prefix".to_owned(),
-            "acme_aux--".to_owned(),
-            "--extension-sql-file-prefixes=acme_data--,acme_geo--".to_owned(),
-        ])
-        .unwrap();
-
-        assert_eq!(
-            parsed.extension_sql_file_names,
-            ["uninstall_acme.sql", "acme_aux.sql", "acme_data.sql"]
-        );
-        assert_eq!(
-            parsed.extension_sql_file_prefixes,
-            ["acme_aux--", "acme_data--", "acme_geo--"]
-        );
-    }
-
-    #[test]
-    fn embedded_module_root_accepts_separate_and_equals_forms() {
-        let separate = ArtifactArgs::parse([
-            "--embedded-module-root".to_owned(),
-            "/tmp/embedded-modules".to_owned(),
-        ])
-        .unwrap();
-        assert_eq!(
-            separate.embedded_module_root,
-            Some("/tmp/embedded-modules".into())
-        );
-
-        let equals =
-            ArtifactArgs::parse(["--embedded-module-root=/tmp/embedded-modules-equals".to_owned()])
-                .unwrap();
-        assert_eq!(
-            equals.embedded_module_root,
-            Some("/tmp/embedded-modules-equals".into())
-        );
-    }
-}
diff --git a/tools/native-packaging/src/bin/extension_index.rs b/tools/native-packaging/src/bin/extension_index.rs
deleted file mode 100644
index a10889f68..000000000
--- a/tools/native-packaging/src/bin/extension_index.rs
+++ /dev/null
@@ -1,243 +0,0 @@
-use std::env;
-use std::fs;
-use std::path::PathBuf;
-use std::process;
-
-use oliphaunt_native_packaging::{
-    Error, NativeExtensionArtifactIndexCreateOptions, NativeExtensionArtifactIndexSigningOptions,
-    Result, create_prebuilt_extension_artifact_index, sign_prebuilt_extension_artifact_index,
-};
-
-fn main() {
-    match run() {
-        Ok(()) => {}
-        Err(error) => {
-            eprintln!("oliphaunt-extension-index: {error}");
-            process::exit(2);
-        }
-    }
-}
-
-fn run() -> Result<()> {
-    let args = IndexArgs::parse(env::args().skip(1))?;
-    if args.help {
-        print_help();
-        return Ok(());
-    }
-    let output = args
-        .output
-        .ok_or_else(|| Error::InvalidConfig("missing required --output ".to_owned()))?;
-    let target = args.target.ok_or_else(|| {
-        Error::InvalidConfig("missing required --target ".to_owned())
-    })?;
-    let index = create_prebuilt_extension_artifact_index(
-        NativeExtensionArtifactIndexCreateOptions::new(output, target)
-            .artifacts(args.artifacts)
-            .maybe_artifact_base_url(args.base_url)
-            .replace_existing(args.force),
-    )?;
-    println!("path={}", index.path.display());
-    println!("target={}", index.target);
-    println!(
-        "extensions={}",
-        index
-            .artifacts
-            .iter()
-            .map(|artifact| artifact.sql_name.as_str())
-            .collect::>()
-            .join(",")
-    );
-    println!(
-        "artifacts={}",
-        index
-            .artifacts
-            .iter()
-            .map(|artifact| format!(
-                "{}:{}:{}",
-                artifact.sql_name,
-                artifact.path.display(),
-                artifact.sha256
-            ))
-            .collect::>()
-            .join(",")
-    );
-    if let Some((key_id, signing_key_hex)) = args.signing_key {
-        let signature = sign_prebuilt_extension_artifact_index(
-            NativeExtensionArtifactIndexSigningOptions::new(&index.path, key_id, signing_key_hex)
-                .maybe_signature_path(args.signature)
-                .replace_existing(args.force),
-        )?;
-        println!("signature={}", signature.path.display());
-        println!("signatureKeyId={}", signature.key_id);
-        println!("signaturePublicKey={}", signature.public_key_hex);
-    }
-    Ok(())
-}
-
-struct IndexArgs {
-    output: Option,
-    target: Option,
-    artifacts: Vec,
-    base_url: Option,
-    signing_key: Option<(String, String)>,
-    signature: Option,
-    force: bool,
-    help: bool,
-}
-
-impl IndexArgs {
-    fn parse(args: impl IntoIterator) -> Result {
-        let mut parsed = Self {
-            output: None,
-            target: None,
-            artifacts: Vec::new(),
-            base_url: None,
-            signing_key: None,
-            signature: None,
-            force: false,
-            help: false,
-        };
-        let mut args = args.into_iter();
-        while let Some(arg) = args.next() {
-            match arg.as_str() {
-                "-h" | "--help" => parsed.help = true,
-                "--force" => parsed.force = true,
-                "--output" | "-o" => {
-                    parsed.output = Some(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                "--target" | "--extension-target" | "--artifact-target" => {
-                    parsed.target = Some(next_value(&mut args, &arg)?);
-                }
-                "--artifact" | "--extension-artifact" => {
-                    parsed
-                        .artifacts
-                        .push(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                "--base-url" | "--artifact-base-url" => {
-                    parsed.base_url = Some(next_value(&mut args, &arg)?);
-                }
-                "--signing-key" => {
-                    parsed.signing_key = Some(parse_key_value(&next_value(&mut args, &arg)?)?);
-                }
-                "--signing-key-file" => {
-                    parsed.signing_key = Some(read_key_file_value(&next_value(&mut args, &arg)?)?);
-                }
-                "--signature" | "--signature-output" => {
-                    parsed.signature = Some(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                value if value.starts_with("--output=") => {
-                    parsed.output = Some(PathBuf::from(value_without_prefix(value, "--output=")));
-                }
-                value if value.starts_with("--target=") => {
-                    parsed.target = Some(value_without_prefix(value, "--target=").to_owned());
-                }
-                value if value.starts_with("--extension-target=") => {
-                    parsed.target =
-                        Some(value_without_prefix(value, "--extension-target=").to_owned());
-                }
-                value if value.starts_with("--artifact-target=") => {
-                    parsed.target =
-                        Some(value_without_prefix(value, "--artifact-target=").to_owned());
-                }
-                value if value.starts_with("--artifact=") => {
-                    parsed
-                        .artifacts
-                        .push(PathBuf::from(value_without_prefix(value, "--artifact=")));
-                }
-                value if value.starts_with("--extension-artifact=") => {
-                    parsed.artifacts.push(PathBuf::from(value_without_prefix(
-                        value,
-                        "--extension-artifact=",
-                    )));
-                }
-                value if value.starts_with("--base-url=") => {
-                    parsed.base_url = Some(value_without_prefix(value, "--base-url=").to_owned());
-                }
-                value if value.starts_with("--artifact-base-url=") => {
-                    parsed.base_url =
-                        Some(value_without_prefix(value, "--artifact-base-url=").to_owned());
-                }
-                value if value.starts_with("--signing-key=") => {
-                    parsed.signing_key = Some(parse_key_value(value_without_prefix(
-                        value,
-                        "--signing-key=",
-                    ))?);
-                }
-                value if value.starts_with("--signing-key-file=") => {
-                    parsed.signing_key = Some(read_key_file_value(value_without_prefix(
-                        value,
-                        "--signing-key-file=",
-                    ))?);
-                }
-                value if value.starts_with("--signature=") => {
-                    parsed.signature =
-                        Some(PathBuf::from(value_without_prefix(value, "--signature=")));
-                }
-                value if value.starts_with("--signature-output=") => {
-                    parsed.signature = Some(PathBuf::from(value_without_prefix(
-                        value,
-                        "--signature-output=",
-                    )));
-                }
-                _ => {
-                    return Err(Error::InvalidConfig(format!("unknown argument '{arg}'")));
-                }
-            }
-        }
-        Ok(parsed)
-    }
-}
-
-fn next_value(args: &mut impl Iterator, flag: &str) -> Result {
-    args.next()
-        .ok_or_else(|| Error::InvalidConfig(format!("{flag} requires a value")))
-}
-
-fn value_without_prefix<'a>(value: &'a str, prefix: &str) -> &'a str {
-    value.strip_prefix(prefix).expect("prefix was checked")
-}
-
-fn parse_key_value(value: &str) -> Result<(String, String)> {
-    let Some((key_id, hex)) = value.split_once(':') else {
-        return Err(Error::InvalidConfig(
-            "key values must use :".to_owned(),
-        ));
-    };
-    Ok((key_id.to_owned(), hex.trim().to_owned()))
-}
-
-fn read_key_file_value(value: &str) -> Result<(String, String)> {
-    let Some((key_id, path)) = value.split_once(':') else {
-        return Err(Error::InvalidConfig(
-            "key file values must use :".to_owned(),
-        ));
-    };
-    let text = fs::read_to_string(path)
-        .map_err(|err| Error::InvalidConfig(format!("read signing key file {path}: {err}")))?;
-    Ok((key_id.to_owned(), text.trim().to_owned()))
-}
-
-fn print_help() {
-    println!(
-        "\
-Create a verified Oliphaunt extension artifact index for one target.
-
-Usage:
-  oliphaunt-extension-index --output  --target  --artifact  [--artifact  ...] [--base-url ] [--signing-key-file :] [--signature ] [--force]
-
-The index writer validates every artifact manifest, rejects built-in extension
-name overrides, computes byte counts and SHA-256 digests, and records relative
-artifact paths plus dependency, preload, native-module, and mobile-prebuilt
-metadata for catalog discovery. Artifact archives may use .tar, .tar.gz, or
-.tar.zst. Put the index next to the artifact archives,
-then use oliphaunt-resources --extension  --extension-index .
-Pass --base-url when publishing artifacts through an HTTPS release URL;
-consumers can then use oliphaunt-resources --extension-cache  to download
-and verify missing sidecar artifacts without building extension source.
-Pass --signing-key-file to write an Ed25519 detached signature sidecar for the
-exact index bytes. The file must contain a hex-encoded 32-byte Ed25519 signing
-key. For local automation only, --signing-key : is also
-accepted.
-"
-    );
-}
diff --git a/tools/native-packaging/src/bin/package_resources.rs b/tools/native-packaging/src/bin/package_resources.rs
deleted file mode 100644
index 4e8fbb952..000000000
--- a/tools/native-packaging/src/bin/package_resources.rs
+++ /dev/null
@@ -1,1724 +0,0 @@
-use std::env;
-use std::fs::{self, File};
-use std::io::Read;
-use std::path::{Path, PathBuf};
-use std::process;
-use std::time::{SystemTime, UNIX_EPOCH};
-
-use flate2::read::GzDecoder;
-use oliphaunt::Extension;
-use oliphaunt_native_packaging::{
-    Error, MobileStaticRegistryState, NativeExtensionArtifactIndexOptions,
-    NativeExtensionArtifactIndexTrustRoot, NativePackagingMode, NativePrebuiltExtensionArtifact,
-    NativeRuntimeFeature, NativeRuntimeResourceOptions, Result, build_native_runtime_resources,
-    built_in_extension_catalog, list_prebuilt_extension_artifact_index_catalog,
-    resolve_prebuilt_extension_artifacts_from_indexes,
-};
-use sha2::{Digest, Sha256};
-
-fn main() {
-    match run() {
-        Ok(()) => {}
-        Err(error) => {
-            eprintln!("oliphaunt-resources: {error}");
-            process::exit(2);
-        }
-    }
-}
-
-fn run() -> Result<()> {
-    let args = PackageArgs::parse(env::args().skip(1))?;
-    run_with_package_args(args)
-}
-
-fn run_with_package_args(args: PackageArgs) -> Result<()> {
-    if args.help {
-        print_help();
-        return Ok(());
-    }
-    if args.list_extensions {
-        print_extension_catalog(&args)?;
-        return Ok(());
-    }
-    if args.resolve_broker_release_assets {
-        resolve_broker_release_assets(&args)?;
-        return Ok(());
-    }
-    if args.resolve_release_assets {
-        resolve_release_assets(&args)?;
-        return Ok(());
-    }
-    let output_dir = args
-        .output_dir
-        .ok_or_else(|| Error::InvalidConfig("missing required --output ".to_owned()))?;
-    let extension_target = args
-        .extension_target
-        .clone()
-        .unwrap_or_else(default_extension_artifact_target);
-
-    let mut built_in_extensions = Vec::new();
-    let mut indexed_extensions = Vec::new();
-    for extension in args.extensions {
-        if let Some(extension) = Extension::by_sql_name(&extension) {
-            built_in_extensions.push(extension);
-        } else {
-            indexed_extensions.push(extension);
-        }
-    }
-    let mut prebuilt_extensions = args.prebuilt_extensions;
-    if !indexed_extensions.is_empty() {
-        let resolution = resolve_prebuilt_extension_artifacts_from_indexes(
-            NativeExtensionArtifactIndexOptions::new(extension_target.clone())
-                .indexes(args.extension_indexes)
-                .maybe_artifact_cache_dir(args.extension_cache_dir)
-                .trusted_signing_keys(args.trusted_extension_index_keys)
-                .require_signatures(args.require_signed_extension_indexes)
-                .extensions(indexed_extensions),
-        )?;
-        prebuilt_extensions.extend(resolution.artifacts);
-    }
-
-    let mut options = NativeRuntimeResourceOptions::new(output_dir)
-        .mode(args.mode)
-        .runtime_features(args.runtime_features)
-        .replace_existing(args.force)
-        .require_mobile_static_registry(args.require_mobile_static_registry)
-        .mobile_static_module_stems(args.mobile_static_module_stems)
-        .extension_target(extension_target);
-    if let Some(version) = args.liboliphaunt_version {
-        options = options.native_runtime_version(version);
-    }
-    for extension in built_in_extensions {
-        options = options.extension(extension);
-    }
-    for artifact in prebuilt_extensions {
-        options = options.prebuilt_extension(artifact.root);
-    }
-
-    let package = build_native_runtime_resources(options)?;
-    println!("root={}", package.root.display());
-    println!("runtimeFiles={}", package.runtime_files.display());
-    println!("clusterSeedFiles={}", package.cluster_seed_files.display());
-    println!("runtimeCacheKey={}", package.runtime_cache_key);
-    println!("clusterSeedCacheKey={}", package.cluster_seed_cache_key);
-    println!("extensions={}", package.extension_names.join(","));
-    println!(
-        "runtimeFeatures={}",
-        package
-            .runtime_features
-            .iter()
-            .map(|feature| feature.as_str())
-            .collect::>()
-            .join(",")
-    );
-    println!(
-        "mobileStaticRegistryState={}",
-        match package.mobile_static_registry.state {
-            MobileStaticRegistryState::NotRequired => "not-required",
-            MobileStaticRegistryState::Complete => "complete",
-            MobileStaticRegistryState::Pending => "pending",
-        }
-    );
-    println!(
-        "mobileStaticRegistryPending={}",
-        package.mobile_static_registry.pending_extensions.join(",")
-    );
-    println!(
-        "mobileStaticRegistryRegistered={}",
-        package
-            .mobile_static_registry
-            .registered_extensions
-            .join(",")
-    );
-    println!(
-        "sharedPreloadLibraries={}",
-        package.shared_preload_libraries.join(",")
-    );
-    println!(
-        "nativeModuleStems={}",
-        package.mobile_static_registry.native_module_stems.join(",")
-    );
-    println!(
-        "staticRegistryManifest={}",
-        package.static_registry_manifest.display()
-    );
-    println!(
-        "staticRegistrySource={}",
-        package
-            .static_registry_source
-            .as_ref()
-            .map(|path| path.display().to_string())
-            .unwrap_or_default()
-    );
-    println!("packageSizeReport={}", package.size_report.path.display());
-    println!("packageBytes={}", package.size_report.package_bytes);
-    println!("runtimeBytes={}", package.size_report.runtime_bytes);
-    println!(
-        "clusterSeedBytes={}",
-        package.size_report.cluster_seed_bytes
-    );
-    println!(
-        "staticRegistryBytes={}",
-        package.size_report.static_registry_bytes
-    );
-    println!(
-        "selectedExtensionBytes={}",
-        package.size_report.selected_extension_bytes
-    );
-    println!(
-        "extensionBytes={}",
-        package
-            .size_report
-            .extensions
-            .iter()
-            .map(|extension| format!("{}:{}", extension.name, extension.bytes))
-            .collect::>()
-            .join(",")
-    );
-    Ok(())
-}
-
-struct PackageArgs {
-    output_dir: Option,
-    mode: NativePackagingMode,
-    extensions: Vec,
-    runtime_features: Vec,
-    extension_indexes: Vec,
-    extension_target: Option,
-    extension_cache_dir: Option,
-    trusted_extension_index_keys: Vec,
-    require_signed_extension_indexes: bool,
-    prebuilt_extensions: Vec,
-    mobile_static_module_stems: Vec,
-    force: bool,
-    require_mobile_static_registry: bool,
-    resolve_release_assets: bool,
-    liboliphaunt_version: Option,
-    release_asset_base_url: Option,
-    release_asset_cache_dir: Option,
-    release_asset_target: Option,
-    release_assets: Vec,
-    resolve_broker_release_assets: bool,
-    broker_version: Option,
-    broker_release_asset_base_url: Option,
-    broker_release_asset_cache_dir: Option,
-    broker_release_asset_target: Option,
-    list_extensions: bool,
-    help: bool,
-}
-
-impl PackageArgs {
-    fn parse(args: impl IntoIterator) -> Result {
-        Self::parse_with_native_runtime_version(
-            args,
-            env::var("OLIPHAUNT_LIBOLIPHAUNT_VERSION")
-                .ok()
-                .filter(|value| !value.trim().is_empty()),
-        )
-    }
-
-    fn parse_with_native_runtime_version(
-        args: impl IntoIterator,
-        native_runtime_version: Option,
-    ) -> Result {
-        let mut parsed = Self {
-            output_dir: None,
-            mode: NativePackagingMode::NativeDirect,
-            extensions: Vec::new(),
-            runtime_features: Vec::new(),
-            extension_indexes: Vec::new(),
-            extension_target: None,
-            extension_cache_dir: None,
-            trusted_extension_index_keys: Vec::new(),
-            require_signed_extension_indexes: false,
-            prebuilt_extensions: Vec::new(),
-            mobile_static_module_stems: Vec::new(),
-            force: false,
-            require_mobile_static_registry: false,
-            resolve_release_assets: false,
-            liboliphaunt_version: native_runtime_version,
-            release_asset_base_url: env::var("OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSET_BASE_URL")
-                .ok()
-                .filter(|value| !value.trim().is_empty()),
-            release_asset_cache_dir: env::var("OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSET_CACHE")
-                .ok()
-                .filter(|value| !value.trim().is_empty())
-                .map(PathBuf::from),
-            release_asset_target: env::var("OLIPHAUNT_LIBOLIPHAUNT_RELEASE_TARGET")
-                .ok()
-                .filter(|value| !value.trim().is_empty()),
-            release_assets: Vec::new(),
-            resolve_broker_release_assets: false,
-            broker_version: env::var("OLIPHAUNT_BROKER_VERSION")
-                .ok()
-                .filter(|value| !value.trim().is_empty()),
-            broker_release_asset_base_url: env::var("OLIPHAUNT_BROKER_RELEASE_ASSET_BASE_URL")
-                .ok()
-                .filter(|value| !value.trim().is_empty()),
-            broker_release_asset_cache_dir: env::var("OLIPHAUNT_BROKER_RELEASE_ASSET_CACHE")
-                .ok()
-                .filter(|value| !value.trim().is_empty())
-                .map(PathBuf::from),
-            broker_release_asset_target: env::var("OLIPHAUNT_BROKER_RELEASE_TARGET")
-                .ok()
-                .filter(|value| !value.trim().is_empty()),
-            list_extensions: false,
-            help: false,
-        };
-        let mut args = args.into_iter();
-        while let Some(arg) = args.next() {
-            match arg.as_str() {
-                "-h" | "--help" => parsed.help = true,
-                "--list-extensions" => parsed.list_extensions = true,
-                "--resolve-release-assets" | "--resolve-liboliphaunt-release" => {
-                    parsed.resolve_release_assets = true;
-                }
-                "--resolve-broker-release-assets" | "--resolve-oliphaunt-broker-release" => {
-                    parsed.resolve_broker_release_assets = true;
-                }
-                "--force" => parsed.force = true,
-                "--require-mobile-static-registry" => {
-                    parsed.require_mobile_static_registry = true;
-                }
-                "--mobile-static-module" | "--mobile-static-registry-module" => {
-                    let value = next_value(&mut args, &arg)?;
-                    push_mobile_static_module_stems(&mut parsed.mobile_static_module_stems, &value);
-                }
-                "--output" | "-o" => {
-                    let value = next_value(&mut args, &arg)?;
-                    parsed.output_dir = Some(PathBuf::from(value));
-                }
-                "--liboliphaunt-native-version" => {
-                    parsed.liboliphaunt_version = Some(next_value(&mut args, &arg)?);
-                }
-                "--broker-version" | "--oliphaunt-broker-version" => {
-                    parsed.broker_version = Some(next_value(&mut args, &arg)?);
-                }
-                "--release-asset-base-url" => {
-                    parsed.release_asset_base_url = Some(next_value(&mut args, &arg)?);
-                }
-                "--broker-release-asset-base-url" => {
-                    parsed.broker_release_asset_base_url = Some(next_value(&mut args, &arg)?);
-                }
-                "--release-asset-cache" | "--release-asset-cache-dir" => {
-                    parsed.release_asset_cache_dir =
-                        Some(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                "--broker-release-asset-cache" | "--broker-release-asset-cache-dir" => {
-                    parsed.broker_release_asset_cache_dir =
-                        Some(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                "--release-asset-target" | "--release-target" => {
-                    parsed.release_asset_target = Some(next_value(&mut args, &arg)?);
-                }
-                "--broker-release-target" | "--broker-release-asset-target" => {
-                    parsed.broker_release_asset_target = Some(next_value(&mut args, &arg)?);
-                }
-                "--release-asset" => {
-                    parsed.release_assets.push(next_value(&mut args, &arg)?);
-                    parsed.resolve_release_assets = true;
-                }
-                "--mode" => {
-                    let value = next_value(&mut args, &arg)?;
-                    parsed.mode = parse_mode(&value)?;
-                }
-                "--extension" => {
-                    let value = next_value(&mut args, &arg)?;
-                    push_extension_names(&mut parsed.extensions, &value);
-                }
-                "--runtime-feature" | "--runtime-features" => {
-                    let value = next_value(&mut args, &arg)?;
-                    push_runtime_feature_names(&mut parsed.runtime_features, &value)?;
-                }
-                "--extension-index" | "--external-extension-index" => {
-                    let value = next_value(&mut args, &arg)?;
-                    parsed.extension_indexes.push(PathBuf::from(value));
-                }
-                "--extension-target" | "--artifact-target" => {
-                    parsed.extension_target = Some(next_value(&mut args, &arg)?);
-                }
-                "--extension-cache" | "--extension-artifact-cache" => {
-                    parsed.extension_cache_dir = Some(PathBuf::from(next_value(&mut args, &arg)?));
-                }
-                "--trusted-extension-index-key" => {
-                    let (key_id, key) = parse_key_value(&next_value(&mut args, &arg)?)?;
-                    parsed
-                        .trusted_extension_index_keys
-                        .push(NativeExtensionArtifactIndexTrustRoot::new(key_id, key));
-                    parsed.require_signed_extension_indexes = true;
-                }
-                "--trusted-extension-index-key-file" => {
-                    let (key_id, key) = read_key_file_value(&next_value(&mut args, &arg)?)?;
-                    parsed
-                        .trusted_extension_index_keys
-                        .push(NativeExtensionArtifactIndexTrustRoot::new(key_id, key));
-                    parsed.require_signed_extension_indexes = true;
-                }
-                "--require-signed-extension-index" | "--require-signed-extension-indexes" => {
-                    parsed.require_signed_extension_indexes = true;
-                }
-                "--prebuilt-extension" | "--prebuilt-extension-artifact" => {
-                    let value = next_value(&mut args, &arg)?;
-                    parsed
-                        .prebuilt_extensions
-                        .push(NativePrebuiltExtensionArtifact::new(PathBuf::from(value)));
-                }
-                value if value.starts_with("--output=") => {
-                    parsed.output_dir =
-                        Some(PathBuf::from(value_without_prefix(value, "--output=")));
-                }
-                value if value.starts_with("--liboliphaunt-native-version=") => {
-                    parsed.liboliphaunt_version = Some(
-                        value_without_prefix(value, "--liboliphaunt-native-version=").to_owned(),
-                    );
-                }
-                value if value.starts_with("--broker-version=") => {
-                    parsed.broker_version =
-                        Some(value_without_prefix(value, "--broker-version=").to_owned());
-                }
-                value if value.starts_with("--oliphaunt-broker-version=") => {
-                    parsed.broker_version =
-                        Some(value_without_prefix(value, "--oliphaunt-broker-version=").to_owned());
-                }
-                value if value.starts_with("--release-asset-base-url=") => {
-                    parsed.release_asset_base_url =
-                        Some(value_without_prefix(value, "--release-asset-base-url=").to_owned());
-                }
-                value if value.starts_with("--broker-release-asset-base-url=") => {
-                    parsed.broker_release_asset_base_url = Some(
-                        value_without_prefix(value, "--broker-release-asset-base-url=").to_owned(),
-                    );
-                }
-                value if value.starts_with("--release-asset-cache=") => {
-                    parsed.release_asset_cache_dir = Some(PathBuf::from(value_without_prefix(
-                        value,
-                        "--release-asset-cache=",
-                    )));
-                }
-                value if value.starts_with("--release-asset-cache-dir=") => {
-                    parsed.release_asset_cache_dir = Some(PathBuf::from(value_without_prefix(
-                        value,
-                        "--release-asset-cache-dir=",
-                    )));
-                }
-                value if value.starts_with("--broker-release-asset-cache=") => {
-                    parsed.broker_release_asset_cache_dir = Some(PathBuf::from(
-                        value_without_prefix(value, "--broker-release-asset-cache="),
-                    ));
-                }
-                value if value.starts_with("--broker-release-asset-cache-dir=") => {
-                    parsed.broker_release_asset_cache_dir = Some(PathBuf::from(
-                        value_without_prefix(value, "--broker-release-asset-cache-dir="),
-                    ));
-                }
-                value if value.starts_with("--release-asset-target=") => {
-                    parsed.release_asset_target =
-                        Some(value_without_prefix(value, "--release-asset-target=").to_owned());
-                }
-                value if value.starts_with("--release-target=") => {
-                    parsed.release_asset_target =
-                        Some(value_without_prefix(value, "--release-target=").to_owned());
-                }
-                value if value.starts_with("--broker-release-target=") => {
-                    parsed.broker_release_asset_target =
-                        Some(value_without_prefix(value, "--broker-release-target=").to_owned());
-                }
-                value if value.starts_with("--broker-release-asset-target=") => {
-                    parsed.broker_release_asset_target = Some(
-                        value_without_prefix(value, "--broker-release-asset-target=").to_owned(),
-                    );
-                }
-                value if value.starts_with("--release-asset=") => {
-                    parsed
-                        .release_assets
-                        .push(value_without_prefix(value, "--release-asset=").to_owned());
-                    parsed.resolve_release_assets = true;
-                }
-                value if value.starts_with("--mode=") => {
-                    parsed.mode = parse_mode(value_without_prefix(value, "--mode="))?;
-                }
-                value if value.starts_with("--extension=") => {
-                    push_extension_names(
-                        &mut parsed.extensions,
-                        value_without_prefix(value, "--extension="),
-                    );
-                }
-                value if value.starts_with("--runtime-feature=") => {
-                    push_runtime_feature_names(
-                        &mut parsed.runtime_features,
-                        value_without_prefix(value, "--runtime-feature="),
-                    )?;
-                }
-                value if value.starts_with("--runtime-features=") => {
-                    push_runtime_feature_names(
-                        &mut parsed.runtime_features,
-                        value_without_prefix(value, "--runtime-features="),
-                    )?;
-                }
-                value if value.starts_with("--extension-index=") => {
-                    parsed
-                        .extension_indexes
-                        .push(PathBuf::from(value_without_prefix(
-                            value,
-                            "--extension-index=",
-                        )));
-                }
-                value if value.starts_with("--external-extension-index=") => {
-                    parsed
-                        .extension_indexes
-                        .push(PathBuf::from(value_without_prefix(
-                            value,
-                            "--external-extension-index=",
-                        )));
-                }
-                value if value.starts_with("--extension-target=") => {
-                    parsed.extension_target =
-                        Some(value_without_prefix(value, "--extension-target=").to_owned());
-                }
-                value if value.starts_with("--artifact-target=") => {
-                    parsed.extension_target =
-                        Some(value_without_prefix(value, "--artifact-target=").to_owned());
-                }
-                value if value.starts_with("--extension-cache=") => {
-                    parsed.extension_cache_dir = Some(PathBuf::from(value_without_prefix(
-                        value,
-                        "--extension-cache=",
-                    )));
-                }
-                value if value.starts_with("--extension-artifact-cache=") => {
-                    parsed.extension_cache_dir = Some(PathBuf::from(value_without_prefix(
-                        value,
-                        "--extension-artifact-cache=",
-                    )));
-                }
-                value if value.starts_with("--trusted-extension-index-key=") => {
-                    let (key_id, key) = parse_key_value(value_without_prefix(
-                        value,
-                        "--trusted-extension-index-key=",
-                    ))?;
-                    parsed
-                        .trusted_extension_index_keys
-                        .push(NativeExtensionArtifactIndexTrustRoot::new(key_id, key));
-                    parsed.require_signed_extension_indexes = true;
-                }
-                value if value.starts_with("--trusted-extension-index-key-file=") => {
-                    let (key_id, key) = read_key_file_value(value_without_prefix(
-                        value,
-                        "--trusted-extension-index-key-file=",
-                    ))?;
-                    parsed
-                        .trusted_extension_index_keys
-                        .push(NativeExtensionArtifactIndexTrustRoot::new(key_id, key));
-                    parsed.require_signed_extension_indexes = true;
-                }
-                value if value.starts_with("--prebuilt-extension=") => {
-                    parsed
-                        .prebuilt_extensions
-                        .push(NativePrebuiltExtensionArtifact::new(PathBuf::from(
-                            value_without_prefix(value, "--prebuilt-extension="),
-                        )));
-                }
-                value if value.starts_with("--prebuilt-extension-artifact=") => {
-                    parsed
-                        .prebuilt_extensions
-                        .push(NativePrebuiltExtensionArtifact::new(PathBuf::from(
-                            value_without_prefix(value, "--prebuilt-extension-artifact="),
-                        )));
-                }
-                value if value.starts_with("--mobile-static-module=") => {
-                    push_mobile_static_module_stems(
-                        &mut parsed.mobile_static_module_stems,
-                        value_without_prefix(value, "--mobile-static-module="),
-                    );
-                }
-                value if value.starts_with("--mobile-static-registry-module=") => {
-                    push_mobile_static_module_stems(
-                        &mut parsed.mobile_static_module_stems,
-                        value_without_prefix(value, "--mobile-static-registry-module="),
-                    );
-                }
-                _ => {
-                    return Err(Error::InvalidConfig(format!("unknown argument '{arg}'")));
-                }
-            }
-        }
-        Ok(parsed)
-    }
-}
-
-fn resolve_release_assets(args: &PackageArgs) -> Result<()> {
-    let version = args.liboliphaunt_version.as_deref().ok_or_else(|| {
-        Error::InvalidConfig(
-            "--resolve-release-assets requires --liboliphaunt-native-version ".to_owned(),
-        )
-    })?;
-    validate_release_version(version, "liboliphaunt")?;
-    let base_url = args.release_asset_base_url.clone().unwrap_or_else(|| {
-        format!(
-            "https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v{version}"
-        )
-    });
-    let cache_dir = args
-        .release_asset_cache_dir
-        .clone()
-        .unwrap_or_else(default_release_asset_cache_dir)
-        .join(version);
-    fs::create_dir_all(&cache_dir).map_err(|err| {
-        Error::Engine(format!(
-            "create liboliphaunt release asset cache {}: {err}",
-            cache_dir.display()
-        ))
-    })?;
-
-    let checksum_name = format!("liboliphaunt-{version}-release-assets.sha256");
-    let checksum_path =
-        download_release_asset(&base_url, &checksum_name, &cache_dir, "liboliphaunt")?;
-    let checksums = parse_release_checksum_file(&checksum_path, "liboliphaunt")?;
-    let release_target = args
-        .release_asset_target
-        .clone()
-        .unwrap_or_else(|| default_release_asset_target().to_owned());
-    let mut assets = release_asset_names_for_target(version, &release_target)?;
-    assets.extend(args.release_assets.iter().cloned());
-    assets.sort();
-    assets.dedup();
-    for asset in &assets {
-        let path = download_release_asset(&base_url, asset, &cache_dir, "liboliphaunt")?;
-        verify_release_asset_checksum(&checksums, asset, &path, "liboliphaunt")?;
-    }
-    verify_release_asset_checksum(&checksums, &checksum_name, &checksum_path, "liboliphaunt").ok();
-
-    if let Some(output_dir) = &args.output_dir {
-        let runtime_asset = runtime_carrier_asset_name(version, &release_target)?;
-        let runtime_path = cache_dir.join(&runtime_asset);
-        if release_target.ends_with("datum64")
-            || release_target.starts_with("android-")
-            || release_target == "ios-xcframework"
-        {
-            extract_runtime_resources_archive(&runtime_path, output_dir, args.force)?;
-        } else {
-            extract_native_runtime_archive(&runtime_path, output_dir, args.force)?;
-        }
-    }
-
-    println!("liboliphauntReleaseVersion={version}");
-    println!("liboliphauntReleaseAssetBaseUrl={base_url}");
-    println!("liboliphauntReleaseAssetCache={}", cache_dir.display());
-    println!("liboliphauntReleaseAssets={}", assets.join(","));
-    Ok(())
-}
-
-fn resolve_broker_release_assets(args: &PackageArgs) -> Result<()> {
-    let version = args.broker_version.as_deref().ok_or_else(|| {
-        Error::InvalidConfig(
-            "--resolve-broker-release-assets requires --broker-version ".to_owned(),
-        )
-    })?;
-    validate_release_version(version, "oliphaunt-broker")?;
-    let base_url = args
-        .broker_release_asset_base_url
-        .clone()
-        .or_else(|| args.release_asset_base_url.clone())
-        .unwrap_or_else(|| {
-            format!(
-                "https://github.com/f0rr0/oliphaunt/releases/download/oliphaunt-broker-v{version}"
-            )
-        });
-    let cache_dir = args
-        .broker_release_asset_cache_dir
-        .clone()
-        .or_else(|| args.release_asset_cache_dir.clone())
-        .unwrap_or_else(default_broker_release_asset_cache_dir)
-        .join(version);
-    fs::create_dir_all(&cache_dir).map_err(|err| {
-        Error::Engine(format!(
-            "create oliphaunt-broker release asset cache {}: {err}",
-            cache_dir.display()
-        ))
-    })?;
-
-    let checksum_name = format!("oliphaunt-broker-{version}-release-assets.sha256");
-    let checksum_path =
-        download_release_asset(&base_url, &checksum_name, &cache_dir, "oliphaunt-broker")?;
-    let checksums = parse_release_checksum_file(&checksum_path, "oliphaunt-broker")?;
-    let release_target = args
-        .broker_release_asset_target
-        .clone()
-        .or_else(|| args.release_asset_target.clone())
-        .unwrap_or_else(default_broker_release_asset_target);
-    let asset = broker_release_asset_name_for_target(version, &release_target)?;
-    let asset_path = download_release_asset(&base_url, &asset, &cache_dir, "oliphaunt-broker")?;
-    verify_release_asset_checksum(&checksums, &asset, &asset_path, "oliphaunt-broker")?;
-
-    if let Some(output_dir) = &args.output_dir {
-        extract_broker_release_archive(&asset_path, output_dir, args.force)?;
-    }
-
-    println!("oliphauntBrokerReleaseVersion={version}");
-    println!("oliphauntBrokerReleaseAssetBaseUrl={base_url}");
-    println!("oliphauntBrokerReleaseAssetCache={}", cache_dir.display());
-    println!("oliphauntBrokerReleaseAssets={asset}");
-    Ok(())
-}
-
-fn validate_release_version(version: &str, product_label: &str) -> Result<()> {
-    let valid = version
-        .bytes()
-        .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'-' | b'_'));
-    if !valid || version.is_empty() {
-        return Err(Error::InvalidConfig(format!(
-            "invalid {product_label} release version '{version}'"
-        )));
-    }
-    Ok(())
-}
-
-fn default_release_asset_cache_dir() -> PathBuf {
-    if let Ok(value) = env::var("XDG_CACHE_HOME")
-        && !value.trim().is_empty()
-    {
-        return PathBuf::from(value).join("oliphaunt/release-assets/liboliphaunt");
-    }
-    if let Ok(value) = env::var("HOME")
-        && !value.trim().is_empty()
-    {
-        return PathBuf::from(value).join(".cache/oliphaunt/release-assets/liboliphaunt");
-    }
-    env::temp_dir().join("oliphaunt/release-assets/liboliphaunt")
-}
-
-fn default_broker_release_asset_cache_dir() -> PathBuf {
-    if let Ok(value) = env::var("XDG_CACHE_HOME")
-        && !value.trim().is_empty()
-    {
-        return PathBuf::from(value).join("oliphaunt/release-assets/oliphaunt-broker");
-    }
-    if let Ok(value) = env::var("HOME")
-        && !value.trim().is_empty()
-    {
-        return PathBuf::from(value).join(".cache/oliphaunt/release-assets/oliphaunt-broker");
-    }
-    env::temp_dir().join("oliphaunt/release-assets/oliphaunt-broker")
-}
-
-fn default_release_asset_target() -> &'static str {
-    match (env::consts::OS, env::consts::ARCH) {
-        ("macos", "aarch64") => "macos-arm64",
-        ("linux", "x86_64") => "linux-x64-gnu",
-        ("linux", "aarch64") => "linux-arm64-gnu",
-        ("windows", "x86_64") => "windows-x64-msvc",
-        ("ios", _) => "ios-xcframework",
-        ("android", "aarch64") => "android-arm64-v8a",
-        ("android", "x86_64") => "android-x86_64",
-        _ => "unsupported",
-    }
-}
-
-fn default_broker_release_asset_target() -> String {
-    match (env::consts::OS, env::consts::ARCH) {
-        ("macos", "aarch64") => "macos-arm64",
-        ("linux", "x86_64") => "linux-x64-gnu",
-        ("linux", "aarch64") => "linux-arm64-gnu",
-        ("windows", "x86_64") => "windows-x64-msvc",
-        _ => "unsupported",
-    }
-    .to_owned()
-}
-
-fn release_asset_names_for_target(version: &str, target: &str) -> Result> {
-    let mut assets = Vec::new();
-    match target {
-        "macos-arm64" => {
-            assets.push(format!("liboliphaunt-{version}-macos-arm64.tar.gz"));
-            assets.push(format!("oliphaunt-tools-{version}-macos-arm64.tar.gz"));
-        }
-        "linux-x64-gnu" => {
-            assets.push(format!("liboliphaunt-{version}-linux-x64-gnu.tar.gz"));
-            assets.push(format!("oliphaunt-tools-{version}-linux-x64-gnu.tar.gz"));
-        }
-        "linux-arm64-gnu" => {
-            assets.push(format!("liboliphaunt-{version}-linux-arm64-gnu.tar.gz"));
-            assets.push(format!("oliphaunt-tools-{version}-linux-arm64-gnu.tar.gz"));
-        }
-        "windows-x64-msvc" => {
-            assets.push(format!("liboliphaunt-{version}-windows-x64-msvc.zip"));
-            assets.push(format!("oliphaunt-tools-{version}-windows-x64-msvc.zip"));
-        }
-        "ios-xcframework" => {
-            assets.push(format!("liboliphaunt-{version}-ios-xcframework.tar.gz"));
-            assets.push(format!(
-                "liboliphaunt-{version}-runtime-resources-ios-datum64.tar.gz"
-            ));
-        }
-        "android-arm64-v8a" => {
-            assets.push(format!("liboliphaunt-{version}-android-arm64-v8a.tar.gz"));
-            assets.push(format!(
-                "liboliphaunt-{version}-runtime-resources-android-datum64.tar.gz"
-            ));
-        }
-        "android-x86_64" => {
-            assets.push(format!("liboliphaunt-{version}-android-x86_64.tar.gz"));
-            assets.push(format!(
-                "liboliphaunt-{version}-runtime-resources-android-datum64.tar.gz"
-            ));
-        }
-        "ios-datum64" => {
-            assets.push(format!(
-                "liboliphaunt-{version}-runtime-resources-ios-datum64.tar.gz"
-            ));
-        }
-        "android-datum64" => {
-            assets.push(format!(
-                "liboliphaunt-{version}-runtime-resources-android-datum64.tar.gz"
-            ));
-        }
-        value => {
-            return Err(Error::InvalidConfig(format!(
-                "unsupported liboliphaunt release asset target '{value}'"
-            )));
-        }
-    }
-    Ok(assets)
-}
-
-fn runtime_carrier_asset_name(version: &str, target: &str) -> Result {
-    let name = match target {
-        "macos-arm64" => format!("liboliphaunt-{version}-macos-arm64.tar.gz"),
-        "linux-x64-gnu" => format!("liboliphaunt-{version}-linux-x64-gnu.tar.gz"),
-        "linux-arm64-gnu" => format!("liboliphaunt-{version}-linux-arm64-gnu.tar.gz"),
-        "windows-x64-msvc" => format!("liboliphaunt-{version}-windows-x64-msvc.zip"),
-        "ios-xcframework" | "ios-datum64" => {
-            format!("liboliphaunt-{version}-runtime-resources-ios-datum64.tar.gz")
-        }
-        "android-arm64-v8a" | "android-x86_64" | "android-datum64" => {
-            format!("liboliphaunt-{version}-runtime-resources-android-datum64.tar.gz")
-        }
-        value => {
-            return Err(Error::InvalidConfig(format!(
-                "unsupported liboliphaunt release asset target '{value}'"
-            )));
-        }
-    };
-    Ok(name)
-}
-
-fn broker_release_asset_name_for_target(version: &str, target: &str) -> Result {
-    match target {
-        "macos-arm64" => Ok(format!("oliphaunt-broker-{version}-macos-arm64.tar.gz")),
-        "linux-x64-gnu" => Ok(format!("oliphaunt-broker-{version}-linux-x64-gnu.tar.gz")),
-        "linux-arm64-gnu" => Ok(format!("oliphaunt-broker-{version}-linux-arm64-gnu.tar.gz")),
-        "windows-x64-msvc" => Ok(format!("oliphaunt-broker-{version}-windows-x64-msvc.zip")),
-        value => Err(Error::InvalidConfig(format!(
-            "unsupported oliphaunt-broker release asset target '{value}'"
-        ))),
-    }
-}
-
-fn download_release_asset(
-    base_url: &str,
-    asset: &str,
-    cache_dir: &Path,
-    product_label: &str,
-) -> Result {
-    if asset.contains('/') || asset.contains('\\') || asset == "." || asset == ".." {
-        return Err(Error::InvalidConfig(format!(
-            "release asset name must be a plain file name: {asset}"
-        )));
-    }
-    let output = cache_dir.join(asset);
-    if output.is_file() {
-        return Ok(output);
-    }
-    let tmp_path = cache_dir.join(format!(".{asset}.{}.tmp", unique_timestamp_suffix()));
-    let url = format!("{}/{}", base_url.trim_end_matches('/'), asset);
-    let result = download_release_asset_url(&url, &tmp_path);
-    if let Err(error) = result {
-        let _ = fs::remove_file(&tmp_path);
-        return Err(error);
-    }
-    fs::rename(&tmp_path, &output).map_err(|err| {
-        Error::Engine(format!(
-            "publish downloaded {product_label} release asset {} to {}: {err}",
-            url,
-            output.display()
-        ))
-    })?;
-    Ok(output)
-}
-
-fn download_release_asset_url(url: &str, output: &Path) -> Result<()> {
-    if let Some(path) = url.strip_prefix("file://") {
-        let source = PathBuf::from(path);
-        fs::copy(&source, output).map_err(|err| {
-            Error::InvalidConfig(format!(
-                "copy release asset URL {} to {}: {err}",
-                url,
-                output.display()
-            ))
-        })?;
-        return Ok(());
-    }
-    download_release_asset_https_url(url, output)
-}
-
-#[cfg(feature = "extension-download")]
-fn download_release_asset_https_url(url: &str, output: &Path) -> Result<()> {
-    let response = ureq::get(url).call().map_err(|err| {
-        Error::InvalidConfig(format!(
-            "download liboliphaunt release asset URL {url}: {err}"
-        ))
-    })?;
-    let mut reader = response.into_reader();
-    let mut file = File::create(output)
-        .map_err(|err| Error::Engine(format!("create {}: {err}", output.display())))?;
-    std::io::copy(&mut reader, &mut file).map_err(|err| {
-        Error::Engine(format!(
-            "write downloaded liboliphaunt release asset URL {} to {}: {err}",
-            url,
-            output.display()
-        ))
-    })?;
-    Ok(())
-}
-
-#[cfg(not(feature = "extension-download"))]
-fn download_release_asset_https_url(url: &str, _output: &Path) -> Result<()> {
-    Err(Error::InvalidConfig(format!(
-        "liboliphaunt release asset URL {url} requires an oliphaunt-resources binary built with the extension-download feature"
-    )))
-}
-
-fn parse_release_checksum_file(path: &Path, product_label: &str) -> Result> {
-    let text = fs::read_to_string(path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "read {product_label} release checksum file {}: {err}",
-            path.display()
-        ))
-    })?;
-    let mut checksums = Vec::new();
-    for (index, line) in text.lines().enumerate() {
-        if line.trim().is_empty() {
-            continue;
-        }
-        let mut parts = line.split_whitespace();
-        let digest = parts.next().unwrap_or_default();
-        let filename = parts.next().unwrap_or_default();
-        if parts.next().is_some() || !filename.starts_with("./") {
-            return Err(Error::InvalidConfig(format!(
-                "malformed {product_label} release checksum line {} in {}: {line}",
-                index + 1,
-                path.display()
-            )));
-        }
-        checksums.push((filename[2..].to_owned(), digest.to_owned()));
-    }
-    Ok(checksums)
-}
-
-fn verify_release_asset_checksum(
-    checksums: &[(String, String)],
-    asset: &str,
-    path: &Path,
-    product_label: &str,
-) -> Result<()> {
-    let expected = checksums
-        .iter()
-        .find_map(|(name, digest)| (name == asset).then_some(digest))
-        .ok_or_else(|| {
-            Error::InvalidConfig(format!(
-                "{product_label} release checksum manifest does not cover {asset}"
-            ))
-        })?;
-    let actual = sha256_file(path)?;
-    if expected != &actual {
-        return Err(Error::InvalidConfig(format!(
-            "{product_label} release asset checksum mismatch for {asset}: expected {expected}, got {actual}"
-        )));
-    }
-    Ok(())
-}
-
-fn sha256_file(path: &Path) -> Result {
-    let mut file = File::open(path)
-        .map_err(|err| Error::InvalidConfig(format!("open {}: {err}", path.display())))?;
-    let mut digest = Sha256::new();
-    let mut buffer = [0; 8192];
-    loop {
-        let read = file
-            .read(&mut buffer)
-            .map_err(|err| Error::InvalidConfig(format!("hash {}: {err}", path.display())))?;
-        if read == 0 {
-            break;
-        }
-        digest.update(&buffer[..read]);
-    }
-    Ok(format!("{:x}", digest.finalize()))
-}
-
-fn extract_runtime_resources_archive(
-    archive_path: &Path,
-    output_dir: &Path,
-    replace_existing: bool,
-) -> Result<()> {
-    let resource_root = output_dir.join("oliphaunt");
-    if resource_root.exists() {
-        if !replace_existing {
-            return Err(Error::InvalidConfig(format!(
-                "runtime-resource output already exists at {}; pass --force to replace it",
-                resource_root.display()
-            )));
-        }
-        fs::remove_dir_all(&resource_root)
-            .map_err(|err| Error::Engine(format!("remove {}: {err}", resource_root.display())))?;
-    }
-    fs::create_dir_all(output_dir)
-        .map_err(|err| Error::Engine(format!("create {}: {err}", output_dir.display())))?;
-    let file = File::open(archive_path)
-        .map_err(|err| Error::InvalidConfig(format!("open {}: {err}", archive_path.display())))?;
-    let decoder = GzDecoder::new(file);
-    let mut archive = tar::Archive::new(decoder);
-    archive.unpack(output_dir).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "extract liboliphaunt runtime resources {} into {}: {err}",
-            archive_path.display(),
-            output_dir.display()
-        ))
-    })?;
-    Ok(())
-}
-
-fn extract_native_runtime_archive(
-    archive_path: &Path,
-    output_dir: &Path,
-    replace_existing: bool,
-) -> Result<()> {
-    prepare_archive_output_dir(output_dir, replace_existing, "liboliphaunt")?;
-    if archive_path
-        .file_name()
-        .and_then(|name| name.to_str())
-        .is_some_and(|name| name.ends_with(".tar.gz"))
-    {
-        extract_tar_gz_archive(archive_path, output_dir, "liboliphaunt")
-    } else if archive_path.extension().and_then(|value| value.to_str()) == Some("zip") {
-        extract_zip_archive(archive_path, output_dir, "liboliphaunt")
-    } else {
-        Err(Error::InvalidConfig(format!(
-            "unsupported liboliphaunt runtime archive {}",
-            archive_path.display()
-        )))
-    }
-}
-
-fn extract_broker_release_archive(
-    archive_path: &Path,
-    output_dir: &Path,
-    replace_existing: bool,
-) -> Result<()> {
-    prepare_archive_output_dir(output_dir, replace_existing, "oliphaunt-broker")?;
-    if archive_path
-        .file_name()
-        .and_then(|name| name.to_str())
-        .is_some_and(|name| name.ends_with(".tar.gz"))
-    {
-        extract_tar_gz_archive(archive_path, output_dir, "oliphaunt-broker")?;
-    } else if archive_path.extension().and_then(|value| value.to_str()) == Some("zip") {
-        extract_zip_archive(archive_path, output_dir, "oliphaunt-broker")?;
-    } else {
-        return Err(Error::InvalidConfig(format!(
-            "unsupported oliphaunt-broker release archive {}",
-            archive_path.display()
-        )));
-    }
-    Ok(())
-}
-
-fn prepare_archive_output_dir(
-    output_dir: &Path,
-    replace_existing: bool,
-    product_label: &str,
-) -> Result<()> {
-    if output_dir.exists() {
-        let has_entries = fs::read_dir(output_dir)
-            .map_err(|err| Error::Engine(format!("read {}: {err}", output_dir.display())))?
-            .next()
-            .transpose()
-            .map_err(|err| Error::Engine(format!("read {}: {err}", output_dir.display())))?
-            .is_some();
-        if has_entries {
-            if !replace_existing {
-                return Err(Error::InvalidConfig(format!(
-                    "{product_label} release output already exists at {}; pass --force to replace it",
-                    output_dir.display()
-                )));
-            }
-            fs::remove_dir_all(output_dir)
-                .map_err(|err| Error::Engine(format!("remove {}: {err}", output_dir.display())))?;
-        }
-    }
-    fs::create_dir_all(output_dir)
-        .map_err(|err| Error::Engine(format!("create {}: {err}", output_dir.display())))
-}
-
-fn extract_tar_gz_archive(
-    archive_path: &Path,
-    output_dir: &Path,
-    product_label: &str,
-) -> Result<()> {
-    let file = File::open(archive_path)
-        .map_err(|err| Error::InvalidConfig(format!("open {}: {err}", archive_path.display())))?;
-    let decoder = GzDecoder::new(file);
-    let mut archive = tar::Archive::new(decoder);
-    archive.unpack(output_dir).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "extract {product_label} release archive {} into {}: {err}",
-            archive_path.display(),
-            output_dir.display()
-        ))
-    })
-}
-
-fn extract_zip_archive(archive_path: &Path, output_dir: &Path, product_label: &str) -> Result<()> {
-    let file = File::open(archive_path)
-        .map_err(|err| Error::InvalidConfig(format!("open {}: {err}", archive_path.display())))?;
-    let mut archive = zip::ZipArchive::new(file).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "open {product_label} release zip archive {}: {err}",
-            archive_path.display()
-        ))
-    })?;
-    for index in 0..archive.len() {
-        let mut entry = archive.by_index(index).map_err(|err| {
-            Error::InvalidConfig(format!(
-                "read {product_label} release zip entry {index} from {}: {err}",
-                archive_path.display()
-            ))
-        })?;
-        let enclosed = entry.enclosed_name().ok_or_else(|| {
-            Error::InvalidConfig(format!(
-                "{product_label} release zip entry {} is not safely relative",
-                entry.name()
-            ))
-        })?;
-        let output_path = output_dir.join(enclosed);
-        if entry.is_dir() {
-            fs::create_dir_all(&output_path)
-                .map_err(|err| Error::Engine(format!("create {}: {err}", output_path.display())))?;
-            continue;
-        }
-        if let Some(parent) = output_path.parent() {
-            fs::create_dir_all(parent)
-                .map_err(|err| Error::Engine(format!("create {}: {err}", parent.display())))?;
-        }
-        let mut output = File::create(&output_path)
-            .map_err(|err| Error::Engine(format!("create {}: {err}", output_path.display())))?;
-        std::io::copy(&mut entry, &mut output)
-            .map_err(|err| Error::Engine(format!("extract {}: {err}", output_path.display())))?;
-    }
-    Ok(())
-}
-
-fn unique_timestamp_suffix() -> String {
-    SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .map(|duration| duration.as_nanos().to_string())
-        .unwrap_or_else(|_| "0".to_owned())
-}
-
-fn print_extension_catalog(args: &PackageArgs) -> Result<()> {
-    println!(
-        "sql_name\tpg_major\tcreates_extension\tnative_module_stem\tdependencies\tshared_preload\tdesktop_prebuilt\tmobile_prebuilt\tmobile_static_registry_required\tmobile_static_archive_targets\tdata_files\tartifact"
-    );
-    for entry in built_in_extension_catalog() {
-        let dependencies = entry.dependencies.join(",");
-        let shared_preload = entry.shared_preload_libraries.join(",");
-        println!(
-            "{}\t{}\t{}\t{}\t{}\t{}\tyes\tyes\t{}\t-\t{}\tfirst-party",
-            entry.sql_name,
-            entry.postgres_major,
-            yes_no(entry.creates_extension),
-            entry.native_module_stem.as_deref().unwrap_or("-"),
-            empty_as_dash(&dependencies),
-            empty_as_dash(&shared_preload),
-            yes_no(entry.native_module_stem.is_some()),
-            empty_as_dash(&entry.data_files.join(",")),
-        );
-    }
-    if !args.extension_indexes.is_empty() {
-        let catalog = list_prebuilt_extension_artifact_index_catalog(
-            NativeExtensionArtifactIndexOptions::new(
-                args.extension_target
-                    .clone()
-                    .unwrap_or_else(default_extension_artifact_target),
-            )
-            .indexes(args.extension_indexes.clone())
-            .trusted_signing_keys(args.trusted_extension_index_keys.clone())
-            .require_signatures(args.require_signed_extension_indexes),
-        )?;
-        for entry in catalog.extensions {
-            println!(
-                "{}\t18\t{}\t{}\t{}\t{}\tyes\t{}\t{}\t{}\t-\texternal-index:{}",
-                entry.sql_name,
-                yes_no(entry.creates_extension),
-                empty_as_dash(entry.native_module_stem.as_deref().unwrap_or("-")),
-                empty_as_dash(&entry.dependencies.join(",")),
-                empty_as_dash(&entry.shared_preload_libraries.join(",")),
-                yes_no(entry.mobile_prebuilt),
-                yes_no(entry.native_module_stem.is_some()),
-                empty_as_dash(&entry.mobile_static_archive_targets.join(",")),
-                entry.target,
-            );
-        }
-    }
-    Ok(())
-}
-
-fn yes_no(value: bool) -> &'static str {
-    if value { "yes" } else { "no" }
-}
-
-fn empty_as_dash(value: &str) -> &str {
-    if value.is_empty() { "-" } else { value }
-}
-
-fn next_value(args: &mut impl Iterator, flag: &str) -> Result {
-    args.next()
-        .ok_or_else(|| Error::InvalidConfig(format!("{flag} requires a value")))
-}
-
-fn value_without_prefix<'a>(value: &'a str, prefix: &str) -> &'a str {
-    value.strip_prefix(prefix).expect("prefix was checked")
-}
-
-fn parse_key_value(value: &str) -> Result<(String, String)> {
-    let Some((key_id, hex)) = value.split_once(':') else {
-        return Err(Error::InvalidConfig(
-            "key values must use :".to_owned(),
-        ));
-    };
-    Ok((key_id.to_owned(), hex.trim().to_owned()))
-}
-
-fn read_key_file_value(value: &str) -> Result<(String, String)> {
-    let Some((key_id, path)) = value.split_once(':') else {
-        return Err(Error::InvalidConfig(
-            "key file values must use :".to_owned(),
-        ));
-    };
-    let text = fs::read_to_string(path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "read trusted extension index key file {path}: {err}"
-        ))
-    })?;
-    Ok((key_id.to_owned(), text.trim().to_owned()))
-}
-
-fn parse_mode(value: &str) -> Result {
-    match value {
-        "native-direct" => Ok(NativePackagingMode::NativeDirect),
-        "native-broker" => Ok(NativePackagingMode::NativeBroker),
-        "native-server" => Ok(NativePackagingMode::NativeServer),
-        _ => Err(Error::InvalidConfig(format!(
-            "unknown native runtime-resource mode '{value}'"
-        ))),
-    }
-}
-
-fn push_extension_names(target: &mut Vec, value: &str) {
-    for extension in split_csv(value) {
-        target.push(extension.to_owned());
-    }
-}
-
-fn push_runtime_feature_names(target: &mut Vec, value: &str) -> Result<()> {
-    for feature in split_csv(value) {
-        target.push(parse_runtime_feature(feature)?);
-    }
-    Ok(())
-}
-
-fn parse_runtime_feature(value: &str) -> Result {
-    match value {
-        "icu" => Ok(NativeRuntimeFeature::Icu),
-        _ => Err(Error::InvalidConfig(format!(
-            "unknown native runtime feature '{value}'; supported values: icu"
-        ))),
-    }
-}
-
-fn push_mobile_static_module_stems(target: &mut Vec, value: &str) {
-    for stem in split_csv(value) {
-        target.push(stem.to_owned());
-    }
-}
-
-fn split_csv(value: &str) -> impl Iterator {
-    value
-        .split(',')
-        .map(str::trim)
-        .filter(|value| !value.is_empty())
-}
-
-fn default_extension_artifact_target() -> String {
-    if let Ok(target) = env::var("OLIPHAUNT_EXTENSION_TARGET")
-        && !target.trim().is_empty()
-    {
-        return target;
-    }
-    match (env::consts::ARCH, env::consts::OS) {
-        ("aarch64", "macos") => "macos-arm64",
-        ("x86_64", "macos") => "macos-x64",
-        ("aarch64", "linux") => "linux-arm64-gnu",
-        ("x86_64", "linux") => "linux-x64-gnu",
-        ("x86_64", "windows") => "windows-x64-msvc",
-        _ => "host",
-    }
-    .to_owned()
-}
-
-fn print_help() {
-    println!(
-        "\
-Build portable Oliphaunt runtime resources from the Rust SDK for Swift, Kotlin, and React Native.
-
-Usage:
-  oliphaunt-resources --output  [--mode native-direct|native-broker|native-server] [--runtime-feature icu] [--extension hstore,vector] [--extension-index ] [--extension-target ] [--extension-cache ] [--trusted-extension-index-key-file :] [--prebuilt-extension  --liboliphaunt-native-version ] [--mobile-static-module vector] [--force] [--require-mobile-static-registry]
-  oliphaunt-resources --resolve-release-assets --liboliphaunt-native-version  [--output ] [--release-target macos-arm64|linux-x64-gnu|linux-arm64-gnu|windows-x64-msvc|ios-xcframework|ios-datum64|android-arm64-v8a|android-x86_64|android-datum64] [--release-asset-cache ] [--release-asset-base-url ] [--force]
-  oliphaunt-resources --resolve-broker-release-assets --broker-version  [--output ] [--broker-release-target macos-arm64|linux-x64-gnu|linux-arm64-gnu|windows-x64-msvc] [--broker-release-asset-cache ] [--broker-release-asset-base-url ] [--force]
-  oliphaunt-resources --list-extensions [--extension-index ] [--extension-target ] [--trusted-extension-index-key-file :]
-
-The output directory receives:
-  oliphaunt/runtime/manifest.properties
-  oliphaunt/runtime/files/...
-  oliphaunt/cluster-seed/manifest.properties
-  oliphaunt/cluster-seed/files/...
-  oliphaunt/static-registry/manifest.properties
-  oliphaunt/static-registry/oliphaunt_static_registry.c when mobile-ready
-  oliphaunt/package-size.tsv
-
-Use --require-mobile-static-registry for iOS/Android release resources. It
-fails when selected native-module extensions still need static registry rows.
-Pass --mobile-static-module  only from platform packaging that has
-actually linked that module for static loading. Mobile-ready packages emit a
-C registry source that platform builds compile and call before oliphaunt_init.
-Extensions are selected by exact PostgreSQL SQL name. App bundles receive only
-the selected extension files plus mandatory extension dependencies.
-Runtime features are selected separately from SQL extensions. Use
---runtime-feature icu to include ICU collation/locale data from the installed
-oliphaunt-icu package or OLIPHAUNT_ICU_DATA_DIR.
-Use --prebuilt-extension  for exact third-party extensions that were
-built outside the app project. The artifact can be an unpacked directory, .tar,
-.tar.gz, or .tar.zst. It must contain manifest.properties with
-packageLayout=oliphaunt-extension-artifact-v1 and a files/ runtime tree; the app
-build consumes binary artifacts only. Every v1 manifest has exactly the
-canonical field set and declares nativeRuntimeProduct=liboliphaunt-native plus
-a stable nativeRuntimeVersion. Any prebuilt artifact, including one resolved
-from an index, requires --liboliphaunt-native-version  (or
-OLIPHAUNT_LIBOLIPHAUNT_VERSION); packaging rejects every missing or mismatched
-runtime identity before writing the output resource tree.
-Use --extension-index  to resolve external --extension names through
-a local oliphaunt-extension-artifact-index-v1 file. The command verifies
-artifact byte counts and sha256 digests before consuming each artifact. The
-target defaults to OLIPHAUNT_EXTENSION_TARGET or the current host target; pass
---extension-target for iOS, Android, or cross-compiled artifact indexes.
-If an index row has a URL and the sidecar artifact file is missing, pass
---extension-cache  to download the artifact into a deterministic cache
-location before byte-count, sha256, and manifest verification. HTTPS downloads
-require an oliphaunt-resources binary built with the extension-download feature.
-For release consumption, pass --trusted-extension-index-key-file :
-to require and verify an Ed25519 detached signature sidecar at .sig
-before any indexed artifact is used. The key file must contain a hex-encoded
-32-byte Ed25519 public key. For local automation only,
---trusted-extension-index-key : is also accepted.
-package-size.tsv records the runtime/cluster-seed/static-registry byte footprint,
-the de-duplicated selected extension asset bytes, and each selected extension's
-asset bytes.
-
-Use --list-extensions to print the exact public extension catalog
-without requiring a local PostgreSQL build. When --extension-index is also
-provided, signed external index metadata is listed for --extension-target
-without downloading artifacts or building extension source. desktop_prebuilt=yes
-means the extension is available to Rust/Tauri and desktop SDK resource
-artifacts. mobile_prebuilt=yes means iOS/Android app bundles can include it from
-Oliphaunt prebuilt mobile artifacts without compiling extension source; the
-mobile_static_archive_targets column lists carried static archive targets for
-external native-module artifacts. data_files lists extra files relative to
-share/postgresql that are shipped only when the exact extension is selected.
-
-Use --resolve-release-assets for app-developer installs from a published
-liboliphaunt-native-v GitHub release. The resolver downloads
-liboliphaunt--release-assets.sha256, verifies each selected asset
-against it, caches the exact artifacts, and unpacks the selected desktop
-target carrier or target-qualified iOS/Android datum64 closure into --output.
-The default base URL is
-https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v.
-HTTPS downloads require the extension-download feature; file:// release asset
-URLs are supported for clean local release verification without network access.
-Use --resolve-broker-release-assets for broker-mode Rust installs from a
-published oliphaunt-broker-v GitHub release. The resolver downloads
-and verifies oliphaunt-broker--release-assets.sha256, selects the
-current or requested desktop helper target, and unpacks it into --output. Point
-OLIPHAUNT_BROKER_ASSET_DIR at that output directory when using NativeBroker
-without placing oliphaunt-broker next to the application executable.
-"
-    );
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    #[cfg(unix)]
-    use std::os::unix::fs::PermissionsExt;
-    #[cfg(unix)]
-    use std::sync::{Mutex, OnceLock};
-
-    #[cfg(unix)]
-    static ENV_LOCK: OnceLock> = OnceLock::new();
-
-    #[test]
-    fn release_asset_selection_uses_only_target_owned_runtime_closures() {
-        assert_eq!(
-            release_asset_names_for_target("1.2.3", "linux-x64-gnu").unwrap(),
-            vec![
-                "liboliphaunt-1.2.3-linux-x64-gnu.tar.gz",
-                "oliphaunt-tools-1.2.3-linux-x64-gnu.tar.gz",
-            ]
-        );
-        assert_eq!(
-            release_asset_names_for_target("1.2.3", "android-x86_64").unwrap(),
-            vec![
-                "liboliphaunt-1.2.3-android-x86_64.tar.gz",
-                "liboliphaunt-1.2.3-runtime-resources-android-datum64.tar.gz",
-            ]
-        );
-        assert_eq!(
-            runtime_carrier_asset_name("1.2.3", "ios-xcframework").unwrap(),
-            "liboliphaunt-1.2.3-runtime-resources-ios-datum64.tar.gz"
-        );
-        assert!(release_asset_names_for_target("1.2.3", "runtime-resources").is_err());
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn direct_prebuilt_cli_packages_matching_native_runtime_version() {
-        let _lock = ENV_LOCK.get_or_init(|| Mutex::new(())).lock().unwrap();
-        let temp = test_temp_root("direct-positive-version-binding");
-        let install = temp.join("install");
-        let artifact = temp.join("acme_ext");
-        let output = temp.join("output");
-        write_test_native_install(&install);
-        write_test_extension_artifact(&artifact, "1.2.3");
-        let _env = TestEnvironment::replace([
-            ("OLIPHAUNT_INSTALL_DIR", Some(install.as_os_str())),
-            (
-                "OLIPHAUNT_RUNTIME_CACHE_DIR",
-                Some(temp.join("runtime-cache").as_os_str()),
-            ),
-            ("OLIPHAUNT_RESOURCES_DIR", None),
-            ("OLIPHAUNT_POSTGRES", None),
-            ("OLIPHAUNT_INITDB", None),
-        ]);
-
-        let args = PackageArgs::parse_with_native_runtime_version(
-            strings([
-                "--output",
-                output.to_str().unwrap(),
-                "--mode",
-                "native-server",
-                "--prebuilt-extension",
-                artifact.to_str().unwrap(),
-                "--extension-target",
-                "test-target",
-                "--liboliphaunt-native-version",
-                "1.2.3",
-            ]),
-            None,
-        )
-        .unwrap();
-        run_with_package_args(args).unwrap();
-
-        let manifest =
-            fs::read_to_string(output.join("oliphaunt/runtime/manifest.properties")).unwrap();
-        assert!(
-            manifest
-                .lines()
-                .any(|line| line == "selectedExtensions=acme_ext"),
-            "selected prebuilt extension missing from selectedExtensions domain:\n{manifest}"
-        );
-        assert!(
-            manifest.lines().any(|line| line == "extensions="),
-            "non-createable prebuilt extension leaked into createable extensions domain:\n{manifest}"
-        );
-        assert!(
-            output
-                .join("oliphaunt/cluster-seed/files/PG_VERSION")
-                .is_file()
-        );
-        for executable in ["postgres", "pg_ctl"] {
-            assert!(
-                output
-                    .join("oliphaunt/runtime/files/bin")
-                    .join(executable)
-                    .is_file(),
-                "packaged native server runtime is missing {executable}"
-            );
-        }
-        for tool in ["pg_basebackup", "pg_dump", "psql"] {
-            assert!(
-                !output
-                    .join("oliphaunt/runtime/files/bin")
-                    .join(tool)
-                    .exists(),
-                "optional PostgreSQL tool leaked into the core runtime: {tool}"
-            );
-        }
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn direct_prebuilt_cli_requires_and_binds_selected_native_runtime_version() {
-        let temp = test_temp_root("direct-version-binding");
-        let artifact = temp.join("acme_ext");
-        let output = temp.join("missing-version-output");
-        write_test_extension_artifact(&artifact, "1.2.3");
-
-        let args = PackageArgs::parse_with_native_runtime_version(
-            strings([
-                "--output",
-                output.to_str().unwrap(),
-                "--prebuilt-extension",
-                artifact.to_str().unwrap(),
-                "--extension-target",
-                "test-target",
-            ]),
-            None,
-        )
-        .unwrap();
-        let error = run_with_package_args(args).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("requires an exact stable liboliphaunt-native version"),
-            "unexpected missing-version error: {error}"
-        );
-        assert!(!output.exists(), "validation must precede materialization");
-
-        let output = temp.join("wrong-version-output");
-        let args = PackageArgs::parse_with_native_runtime_version(
-            strings([
-                "--output",
-                output.to_str().unwrap(),
-                "--prebuilt-extension",
-                artifact.to_str().unwrap(),
-                "--extension-target",
-                "test-target",
-                "--liboliphaunt-native-version",
-                "1.2.4",
-            ]),
-            None,
-        )
-        .unwrap();
-        let error = run_with_package_args(args).unwrap_err();
-        assert!(
-            error.to_string().contains(
-                "requires liboliphaunt-native version '1.2.3', but runtime packaging selected '1.2.4'"
-            ),
-            "unexpected bound-version error: {error}"
-        );
-        assert!(!output.exists(), "validation must precede materialization");
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn indexed_prebuilt_cli_requires_and_binds_selected_native_runtime_version() {
-        let temp = test_temp_root("indexed-version-binding");
-        let artifact_root = temp.join("artifact-root");
-        write_test_extension_artifact(&artifact_root, "1.2.3");
-        let archive = temp.join("acme_ext.tar");
-        let archive_file = File::create(&archive).unwrap();
-        let mut builder = tar::Builder::new(archive_file);
-        builder.mode(tar::HeaderMode::Deterministic);
-        builder.append_dir_all("acme_ext", &artifact_root).unwrap();
-        builder.finish().unwrap();
-        drop(builder);
-        let index = temp.join("extensions.toml");
-        fs::write(
-            &index,
-            format!(
-                "schema = \"oliphaunt-extension-artifact-index-v1\"\npg_major = 18\n\n[[artifacts]]\nsql_name = \"acme_ext\"\ntarget = \"test-target\"\npath = \"acme_ext.tar\"\nsha256 = \"{}\"\nbytes = {}\n",
-                sha256_file(&archive).unwrap(),
-                fs::metadata(&archive).unwrap().len()
-            ),
-        )
-        .unwrap();
-
-        let output = temp.join("missing-version-output");
-        let args = PackageArgs::parse_with_native_runtime_version(
-            strings([
-                "--output",
-                output.to_str().unwrap(),
-                "--extension",
-                "acme_ext",
-                "--extension-index",
-                index.to_str().unwrap(),
-                "--extension-target",
-                "test-target",
-            ]),
-            None,
-        )
-        .unwrap();
-        let error = run_with_package_args(args).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("requires an exact stable liboliphaunt-native version"),
-            "unexpected indexed missing-version error: {error}"
-        );
-        assert!(!output.exists(), "validation must precede materialization");
-
-        let output = temp.join("wrong-version-output");
-        let args = PackageArgs::parse_with_native_runtime_version(
-            strings([
-                "--output",
-                output.to_str().unwrap(),
-                "--extension",
-                "acme_ext",
-                "--extension-index",
-                index.to_str().unwrap(),
-                "--extension-target",
-                "test-target",
-                "--liboliphaunt-native-version=1.2.4",
-            ]),
-            None,
-        )
-        .unwrap();
-        let error = run_with_package_args(args).unwrap_err();
-        assert!(
-            error.to_string().contains(
-                "requires liboliphaunt-native version '1.2.3', but runtime packaging selected '1.2.4'"
-            ),
-            "unexpected indexed bound-version error: {error}"
-        );
-        assert!(!output.exists(), "validation must precede materialization");
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    fn write_test_extension_artifact(root: &Path, native_runtime_version: &str) {
-        fs::create_dir_all(root.join("files/share/licenses/acme_ext")).unwrap();
-        fs::write(
-            root.join("manifest.properties"),
-            format!(
-                "packageLayout=oliphaunt-extension-artifact-v1\npgMajor=18\nsqlName=acme_ext\ncreatesExtension=no\nnativeModuleStem=\nnativeModuleFile=\nnativeTarget=\nnativeRuntimeProduct=liboliphaunt-native\nnativeRuntimeVersion={native_runtime_version}\ndependencies=\ndataFiles=\nextensionSqlFileNames=\nextensionSqlFilePrefixes=\nsharedPreloadLibraries=\nmobilePrebuilt=no\nmobileStaticArchives=\nmobileStaticDependencyArchives=\nstaticSymbolPrefix=\nstaticSymbolAliases=\nlicenseFiles=share/licenses/acme_ext/LICENSE\nlicenseProfile=external-native\nfiles=files\n"
-            ),
-        )
-        .unwrap();
-        fs::write(root.join("LICENSE"), "fixture license\n").unwrap();
-        fs::write(
-            root.join("THIRD_PARTY_NOTICES.md"),
-            "fixture third-party notices\n",
-        )
-        .unwrap();
-        fs::write(
-            root.join("files/share/licenses/acme_ext/LICENSE"),
-            "fixture upstream license\n",
-        )
-        .unwrap();
-        #[cfg(unix)]
-        for legal in [
-            root.join("LICENSE"),
-            root.join("THIRD_PARTY_NOTICES.md"),
-            root.join("files/share/licenses/acme_ext/LICENSE"),
-        ] {
-            fs::set_permissions(legal, fs::Permissions::from_mode(0o644)).unwrap();
-        }
-    }
-
-    #[cfg(unix)]
-    fn write_test_native_install(root: &Path) {
-        for tool in ["postgres", "pg_ctl", "pg_basebackup", "pg_dump", "psql"] {
-            write_test_file(&root.join("bin").join(tool), tool.as_bytes());
-        }
-        let initdb = root.join("bin/initdb");
-        write_test_file(
-            &initdb,
-            b"#!/bin/sh\nset -eu\npgdata=\nwhile [ \"$#\" -gt 0 ]; do\n  if [ \"$1\" = -D ]; then pgdata=$2; shift 2; else shift; fi\ndone\n[ -n \"$pgdata\" ]\nmkdir -p \"$pgdata/global\"\nprintf '18\\n' >\"$pgdata/PG_VERSION\"\nprintf 'control\\n' >\"$pgdata/global/pg_control\"\nprintf \"dynamic_shared_memory_type = posix\\n\" >\"$pgdata/postgresql.conf\"\n",
-        );
-        fs::set_permissions(&initdb, fs::Permissions::from_mode(0o755)).unwrap();
-        write_test_file(
-            &root.join("share/postgresql/postgresql.conf.sample"),
-            b"# sample\n",
-        );
-        write_test_file(
-            &root.join("share/postgresql/extension/plpgsql.control"),
-            b"comment = 'PL/pgSQL'\n",
-        );
-        write_test_file(
-            &root.join("share/postgresql/extension/plpgsql--1.0.sql"),
-            b"select 'plpgsql install';\n",
-        );
-        fs::create_dir_all(root.join("lib/postgresql")).unwrap();
-    }
-
-    #[cfg(unix)]
-    fn write_test_file(path: &Path, contents: &[u8]) {
-        if let Some(parent) = path.parent() {
-            fs::create_dir_all(parent).unwrap();
-        }
-        fs::write(path, contents).unwrap();
-    }
-
-    #[cfg(unix)]
-    struct TestEnvironment {
-        previous: Vec<(&'static str, Option)>,
-    }
-
-    #[cfg(unix)]
-    impl TestEnvironment {
-        fn replace(values: [(&'static str, Option<&std::ffi::OsStr>); N]) -> Self {
-            let previous = values
-                .iter()
-                .map(|(name, _)| (*name, env::var_os(name)))
-                .collect();
-            for (name, value) in values {
-                unsafe {
-                    match value {
-                        Some(value) => env::set_var(name, value),
-                        None => env::remove_var(name),
-                    }
-                }
-            }
-            Self { previous }
-        }
-    }
-
-    #[cfg(unix)]
-    impl Drop for TestEnvironment {
-        fn drop(&mut self) {
-            for (name, value) in self.previous.drain(..).rev() {
-                unsafe {
-                    match value {
-                        Some(value) => env::set_var(name, value),
-                        None => env::remove_var(name),
-                    }
-                }
-            }
-        }
-    }
-
-    fn strings(values: [&str; N]) -> Vec {
-        values.into_iter().map(str::to_owned).collect()
-    }
-
-    fn test_temp_root(label: &str) -> PathBuf {
-        let nanos = SystemTime::now()
-            .duration_since(UNIX_EPOCH)
-            .map(|duration| duration.as_nanos())
-            .unwrap_or(0);
-        env::temp_dir().join(format!(
-            "oliphaunt-package-resources-{label}-{}-{nanos}",
-            process::id()
-        ))
-    }
-}
diff --git a/tools/native-packaging/src/catalog.rs b/tools/native-packaging/src/catalog.rs
deleted file mode 100644
index 61ea17a6b..000000000
--- a/tools/native-packaging/src/catalog.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use std::collections::BTreeMap;
-use std::sync::OnceLock;
-
-use serde::Deserialize;
-
-use oliphaunt::Extension;
-
-const GENERATED_EXTENSION_CATALOG: &str =
-    include_str!("../../../src/extensions/generated/sdk/extensions.json");
-
-#[derive(Debug, Deserialize)]
-struct CatalogDocument {
-    extensions: Vec,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "kebab-case")]
-pub(crate) struct CatalogExtension {
-    pub(crate) sql_name: String,
-    pub(crate) postgres_major: u16,
-    pub(crate) creates_extension: bool,
-    pub(crate) native_module_stem: Option,
-    pub(crate) dependencies: Vec,
-    pub(crate) runtime_share_data_files: Vec,
-    pub(crate) extension_sql_file_names: Vec,
-    pub(crate) extension_sql_file_prefixes: Vec,
-    pub(crate) shared_preload_libraries: Vec,
-    pub(crate) artifact_product: Option,
-}
-
-fn catalog() -> &'static BTreeMap {
-    static CATALOG: OnceLock> = OnceLock::new();
-    CATALOG.get_or_init(|| {
-        let document: CatalogDocument = serde_json::from_str(GENERATED_EXTENSION_CATALOG)
-            .expect("generated extension catalog must remain valid JSON");
-        document
-            .extensions
-            .into_iter()
-            .map(|entry| (entry.sql_name.clone(), entry))
-            .collect()
-    })
-}
-
-pub(crate) fn all() -> impl Iterator {
-    catalog().values()
-}
-
-pub(crate) fn by_sql_name(sql_name: &str) -> Option<&'static CatalogExtension> {
-    catalog().get(sql_name)
-}
-
-pub(crate) fn for_extension(extension: Extension) -> &'static CatalogExtension {
-    by_sql_name(extension.sql_name())
-        .expect("every generated Rust extension must exist in the generated extension catalog")
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn generated_catalog_matches_the_rust_extension_domain() {
-        assert_eq!(catalog().len(), Extension::ALL.len());
-        for extension in Extension::ALL {
-            let entry = for_extension(*extension);
-            assert_eq!(entry.sql_name, extension.sql_name());
-            assert_eq!(entry.postgres_major, 18);
-        }
-    }
-}
diff --git a/tools/native-packaging/src/extension_artifact.rs b/tools/native-packaging/src/extension_artifact.rs
deleted file mode 100644
index b9f9c70c8..000000000
--- a/tools/native-packaging/src/extension_artifact.rs
+++ /dev/null
@@ -1,2098 +0,0 @@
-use super::*;
-use std::path::Component;
-
-const EXTENSION_ARTIFACT_ARCHIVE_POLICY: &str = include_str!(
-    "../../../src/shared/extension-runtime-contract/extension-artifact-archive-policy.properties"
-);
-const EXTENSION_ARTIFACT_ARCHIVE_POLICY_SCHEMA: &str =
-    "oliphaunt-extension-artifact-archive-policy-v1";
-const DESKTOP_NATIVE_TARGETS: [&str; 4] = [
-    "linux-x64-gnu",
-    "linux-arm64-gnu",
-    "macos-arm64",
-    "windows-x64-msvc",
-];
-const EXTENSION_ARTIFACT_BASE_LEGAL_MEMBERS: [&str; 2] = ["LICENSE", "THIRD_PARTY_NOTICES.md"];
-pub(super) const EXTENSION_ARTIFACT_POSTGRESQL_LICENSE: &str =
-    "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT";
-pub(super) const EXTENSION_ARTIFACT_OPENSSL_LICENSE: &str =
-    "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt";
-
-fn extension_artifact_legal_members(
-    profile: NativeExtensionArtifactLicenseProfile,
-) -> Vec {
-    let mut members = EXTENSION_ARTIFACT_BASE_LEGAL_MEMBERS
-        .iter()
-        .map(PathBuf::from)
-        .collect::>();
-    match profile {
-        NativeExtensionArtifactLicenseProfile::ContribNative => {
-            members.push(PathBuf::from(EXTENSION_ARTIFACT_POSTGRESQL_LICENSE));
-        }
-        NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl => {
-            members.push(PathBuf::from(EXTENSION_ARTIFACT_POSTGRESQL_LICENSE));
-            members.push(PathBuf::from(EXTENSION_ARTIFACT_OPENSSL_LICENSE));
-        }
-        NativeExtensionArtifactLicenseProfile::ExternalNative => {}
-    }
-    members.sort();
-    members
-}
-
-pub(super) fn validate_extension_artifact_license_paths(
-    manifest_path: &Path,
-    license_files: &[PathBuf],
-) -> Result<()> {
-    for relative in license_files {
-        let mut components = relative.components();
-        let in_license_namespace = matches!(components.next(), Some(Component::Normal(value)) if value == "share")
-            && matches!(components.next(), Some(Component::Normal(value)) if value == "licenses")
-            && components.next().is_some();
-        if !in_license_namespace {
-            return Err(Error::InvalidConfig(format!(
-                "manifest {} licenseFiles entry '{}' must be an exact leaf below share/licenses/",
-                manifest_path.display(),
-                relative.display()
-            )));
-        }
-    }
-    Ok(())
-}
-
-pub(super) fn validate_extension_artifact_license_profile(
-    manifest_path: &Path,
-    sql_name: &str,
-    native_target: Option<&str>,
-    mobile_static_dependency_archives: &[MobileStaticDependencyArchive],
-    profile: NativeExtensionArtifactLicenseProfile,
-    license_files: &[PathBuf],
-) -> Result<()> {
-    let external = catalog::by_sql_name(sql_name)
-        .and_then(|extension| extension.artifact_product.as_deref())
-        .is_none_or(|product| product != "oliphaunt-extension-contrib-pg18");
-    let embeds_openssl = !external
-        && sql_name == "pgcrypto"
-        && (matches!(native_target, Some("macos-arm64" | "windows-x64-msvc"))
-            || mobile_static_dependency_archives
-                .iter()
-                .any(|archive| archive.name == "openssl"));
-    let expected = if external {
-        NativeExtensionArtifactLicenseProfile::ExternalNative
-    } else if embeds_openssl {
-        NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl
-    } else {
-        NativeExtensionArtifactLicenseProfile::ContribNative
-    };
-    if profile != expected {
-        return Err(Error::InvalidConfig(format!(
-            "manifest {} has licenseProfile='{}' for extension '{}' and target '{}', expected '{}'",
-            manifest_path.display(),
-            profile.as_str(),
-            sql_name,
-            native_target.unwrap_or(""),
-            expected.as_str()
-        )));
-    }
-    if external && license_files.is_empty() {
-        return Err(Error::InvalidConfig(format!(
-            "manifest {} external-native profile must declare at least one exact licenseFiles leaf",
-            manifest_path.display()
-        )));
-    }
-    if !external && !license_files.is_empty() {
-        return Err(Error::InvalidConfig(format!(
-            "manifest {} contrib profile must not declare upstream licenseFiles leaves",
-            manifest_path.display()
-        )));
-    }
-    Ok(())
-}
-
-pub(super) fn validate_prebuilt_extension_leaf_inventory(
-    root: &Path,
-    manifest_path: &Path,
-    extension: &RuntimeResourceExtension,
-) -> Result<()> {
-    let profile = extension.license_profile.ok_or_else(|| {
-        Error::Engine(format!(
-            "internal error: prebuilt extension {} has no legal profile",
-            manifest_path.display()
-        ))
-    })?;
-    let actual = extension_artifact_leaf_inventory(root)?;
-    let mut expected = BTreeSet::from([PathBuf::from("manifest.properties")]);
-    let mut legal_members = BTreeSet::new();
-    for member in extension_artifact_legal_members(profile) {
-        legal_members.insert(member.clone());
-        expected.insert(member);
-    }
-    for relative in &extension.license_files {
-        let member = PathBuf::from("files").join(relative);
-        legal_members.insert(member.clone());
-        expected.insert(member);
-    }
-
-    let extension_prefix = Path::new("files/share/postgresql/extension");
-    let mut has_control = false;
-    let mut has_install_sql = false;
-    for relative in &actual {
-        let Ok(file_name) = relative.strip_prefix(extension_prefix) else {
-            continue;
-        };
-        if file_name.components().count() != 1 {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact {} contains undeclared extension SQL/control file {}",
-                root.display(),
-                relative.display()
-            )));
-        }
-        let file_name = file_name.to_str().ok_or_else(|| {
-            Error::InvalidConfig(format!(
-                "prebuilt extension artifact {} has a non-UTF-8 extension SQL/control file {}",
-                root.display(),
-                relative.display()
-            ))
-        })?;
-        if !runtime_extension_sql_file_belongs(extension, file_name) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact {} contains undeclared extension SQL/control file {}",
-                root.display(),
-                relative.display()
-            )));
-        }
-        expected.insert(relative.clone());
-        has_control |= file_name == format!("{}.control", extension.sql_name);
-        has_install_sql |= extension_install_sql_file_belongs(&extension.sql_name, file_name);
-    }
-    if extension.creates_extension && (!has_control || !has_install_sql) {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact {} for '{}' must include its control file and at least one canonical base install SQL file",
-            root.display(),
-            extension.sql_name
-        )));
-    }
-    for relative in &extension.data_files {
-        expected.insert(PathBuf::from("files/share/postgresql").join(relative));
-    }
-    if let Some(module) = &extension.native_module_file {
-        expected.insert(PathBuf::from("files/lib/postgresql").join(module));
-        let embedded = PathBuf::from("files/lib/modules").join(module);
-        if extension
-            .native_target
-            .as_deref()
-            .is_some_and(|target| DESKTOP_NATIVE_TARGETS.contains(&target))
-            || actual.contains(&embedded)
-        {
-            expected.insert(embedded);
-        }
-    }
-    for archive in &extension.mobile_static_archives {
-        expected.insert(archive.relative_path.clone());
-    }
-    for archive in &extension.mobile_static_dependency_archives {
-        expected.insert(archive.relative_path.clone());
-    }
-
-    if actual != expected {
-        let undeclared = actual
-            .difference(&expected)
-            .map(|path| path.display().to_string());
-        let missing = expected
-            .difference(&actual)
-            .map(|path| path.display().to_string());
-        let undeclared = undeclared.collect::>();
-        let missing = missing.collect::>();
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact {} leaf inventory mismatch{}{}",
-            root.display(),
-            if undeclared.is_empty() {
-                String::new()
-            } else {
-                format!("; undeclared: {}", undeclared.join(","))
-            },
-            if missing.is_empty() {
-                String::new()
-            } else {
-                format!("; missing: {}", missing.join(","))
-            }
-        )));
-    }
-    for relative in legal_members {
-        validate_extension_artifact_legal_leaf(root, &relative)?;
-    }
-    Ok(())
-}
-
-fn extension_artifact_leaf_inventory(root: &Path) -> Result> {
-    fn walk(root: &Path, current: &Path, out: &mut BTreeSet) -> Result<()> {
-        let mut entries = fs::read_dir(current)
-            .map_err(|err| Error::InvalidConfig(format!("read {}: {err}", current.display())))?
-            .collect::, _>>()
-            .map_err(|err| {
-                Error::InvalidConfig(format!("read entry in {}: {err}", current.display()))
-            })?;
-        entries.sort_by_key(|entry| entry.file_name());
-        for entry in entries {
-            let path = entry.path();
-            let metadata = fs::symlink_metadata(&path).map_err(|err| {
-                Error::InvalidConfig(format!("inspect artifact member {}: {err}", path.display()))
-            })?;
-            if metadata.file_type().is_symlink() {
-                return Err(Error::InvalidConfig(format!(
-                    "prebuilt extension artifact {} contains unsafe symlink {}",
-                    root.display(),
-                    path.display()
-                )));
-            }
-            if metadata.is_dir() {
-                walk(root, &path, out)?;
-                continue;
-            }
-            if !metadata.is_file() {
-                return Err(Error::InvalidConfig(format!(
-                    "prebuilt extension artifact {} contains non-file member {}",
-                    root.display(),
-                    path.display()
-                )));
-            }
-            let relative = path.strip_prefix(root).map_err(|err| {
-                Error::Engine(format!(
-                    "derive artifact member path {}: {err}",
-                    path.display()
-                ))
-            })?;
-            validate_relative_artifact_path(root, "artifact member", relative)?;
-            for component in relative.components() {
-                let Component::Normal(component) = component else {
-                    continue;
-                };
-                let component = component.to_str().ok_or_else(|| {
-                    Error::InvalidConfig(format!(
-                        "prebuilt extension artifact {} member {} must use UTF-8 path text",
-                        root.display(),
-                        relative.display()
-                    ))
-                })?;
-                if component.contains('\\') {
-                    return Err(Error::InvalidConfig(format!(
-                        "prebuilt extension artifact {} member {} contains a literal backslash",
-                        root.display(),
-                        relative.display()
-                    )));
-                }
-            }
-            if !out.insert(relative.to_path_buf()) {
-                return Err(Error::InvalidConfig(format!(
-                    "prebuilt extension artifact {} repeats leaf {}",
-                    root.display(),
-                    relative.display()
-                )));
-            }
-        }
-        Ok(())
-    }
-
-    let metadata = fs::symlink_metadata(root).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "inspect prebuilt extension artifact {}: {err}",
-            root.display()
-        ))
-    })?;
-    if metadata.file_type().is_symlink() || !metadata.is_dir() {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact {} must be a real directory after extraction",
-            root.display()
-        )));
-    }
-    let mut out = BTreeSet::new();
-    walk(root, root, &mut out)?;
-    Ok(out)
-}
-
-fn validate_extension_artifact_legal_leaf(root: &Path, relative: &Path) -> Result<()> {
-    let path = root.join(relative);
-    let metadata = fs::symlink_metadata(&path).map_err(|err| {
-        Error::InvalidConfig(format!("inspect legal member {}: {err}", path.display()))
-    })?;
-    if metadata.file_type().is_symlink() || !metadata.is_file() || metadata.len() == 0 {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact legal member {} must be a non-empty regular non-symlink file",
-            relative.display()
-        )));
-    }
-    #[cfg(unix)]
-    {
-        use std::os::unix::fs::PermissionsExt;
-        if metadata.permissions().mode() & 0o777 != 0o644 {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact legal member {} must have mode 0644",
-                relative.display()
-            )));
-        }
-    }
-    Ok(())
-}
-
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub(super) struct ExtensionArtifactArchivePolicy {
-    pub(super) max_compressed_bytes: u64,
-    pub(super) max_expanded_bytes: u64,
-    pub(super) max_member_bytes: u64,
-    pub(super) max_members: usize,
-}
-
-pub(super) fn extension_artifact_archive_policy() -> Result {
-    if EXTENSION_ARTIFACT_ARCHIVE_POLICY.contains('\r')
-        || !EXTENSION_ARTIFACT_ARCHIVE_POLICY.ends_with('\n')
-        || EXTENSION_ARTIFACT_ARCHIVE_POLICY.ends_with("\n\n")
-    {
-        return Err(Error::Engine(
-            "embedded extension artifact archive policy must use LF lines and one final newline"
-                .to_owned(),
-        ));
-    }
-    let expected_keys = [
-        "schema",
-        "maxCompressedBytes",
-        "maxExpandedBytes",
-        "maxMemberBytes",
-        "maxMembers",
-    ];
-    let lines = EXTENSION_ARTIFACT_ARCHIVE_POLICY
-        .trim_end_matches('\n')
-        .lines()
-        .collect::>();
-    if lines.len() != expected_keys.len() {
-        return Err(Error::Engine(
-            "embedded extension artifact archive policy has the wrong property count".to_owned(),
-        ));
-    }
-    let mut values = BTreeMap::new();
-    for (index, line) in lines.iter().enumerate() {
-        let (key, value) = line.split_once('=').ok_or_else(|| {
-            Error::Engine(format!(
-                "embedded extension artifact archive policy line {} is not key=value",
-                index + 1
-            ))
-        })?;
-        if key != expected_keys[index] || value.is_empty() || values.insert(key, value).is_some() {
-            return Err(Error::Engine(format!(
-                "embedded extension artifact archive policy property {} must be {}",
-                index + 1,
-                expected_keys[index]
-            )));
-        }
-    }
-    if values.get("schema").copied() != Some(EXTENSION_ARTIFACT_ARCHIVE_POLICY_SCHEMA) {
-        return Err(Error::Engine(format!(
-            "embedded extension artifact archive policy schema must be {EXTENSION_ARTIFACT_ARCHIVE_POLICY_SCHEMA}"
-        )));
-    }
-    let positive_u64 = |key: &str| -> Result {
-        let raw = values.get(key).copied().unwrap_or_default();
-        let value = raw.parse::().map_err(|err| {
-            Error::Engine(format!(
-                "embedded extension artifact archive policy {key} is invalid: {err}"
-            ))
-        })?;
-        if value == 0 || value.to_string() != raw {
-            return Err(Error::Engine(format!(
-                "embedded extension artifact archive policy {key} must be a canonical positive integer"
-            )));
-        }
-        Ok(value)
-    };
-    let max_members_u64 = positive_u64("maxMembers")?;
-    let max_members = usize::try_from(max_members_u64).map_err(|err| {
-        Error::Engine(format!(
-            "embedded extension artifact archive policy maxMembers does not fit usize: {err}"
-        ))
-    })?;
-    let policy = ExtensionArtifactArchivePolicy {
-        max_compressed_bytes: positive_u64("maxCompressedBytes")?,
-        max_expanded_bytes: positive_u64("maxExpandedBytes")?,
-        max_member_bytes: positive_u64("maxMemberBytes")?,
-        max_members,
-    };
-    if policy.max_member_bytes > policy.max_expanded_bytes {
-        return Err(Error::Engine(
-            "embedded extension artifact archive policy maxMemberBytes must not exceed maxExpandedBytes"
-                .to_owned(),
-        ));
-    }
-    Ok(policy)
-}
-
-/// Create one exact prebuilt extension artifact from already-built PostgreSQL
-/// runtime files.
-///
-/// This is the producer-side companion to `--prebuilt-extension`: it copies
-/// only the selected extension's declared control, SQL, data, and native module
-/// files into the portable artifact schema. It never builds PostgreSQL or
-/// extension source.
-pub fn create_prebuilt_extension_artifact(
-    options: NativeExtensionArtifactOptions,
-) -> Result {
-    validate_extension_artifact_options(&options)?;
-    let legal_contract = options
-        .legal_contract
-        .as_ref()
-        .expect("validated artifact options require a legal contract");
-    let license_profile = legal_contract.profile;
-    let license_files = sorted_deduped_paths(&legal_contract.license_files);
-
-    let output = options.output.clone();
-    let mut staging_root = None;
-    let artifact_root = match options.format {
-        NativeExtensionArtifactFormat::Directory => {
-            prepare_output_root(&output, options.replace_existing)?;
-            output.clone()
-        }
-        NativeExtensionArtifactFormat::Tar
-        | NativeExtensionArtifactFormat::TarGz
-        | NativeExtensionArtifactFormat::TarZst => {
-            prepare_output_file(&output, options.replace_existing)?;
-            let staging = RemoveOnDrop::create(unique_extension_artifact_staging_root())?;
-            let path = staging.path.clone();
-            staging_root = Some(staging);
-            path
-        }
-    };
-
-    write_prebuilt_extension_artifact_directory(&artifact_root, &options)?;
-    let loaded = load_prebuilt_extension_artifact(&artifact_root)?;
-    if loaded.sql_name != options.sql_name
-        || loaded.native_runtime_version.as_deref() != Some(options.native_runtime_version.as_str())
-    {
-        return Err(Error::Engine(format!(
-            "created prebuilt extension artifact for '{}'/liboliphaunt-native {}, expected '{}'/liboliphaunt-native {}",
-            loaded.sql_name,
-            loaded
-                .native_runtime_version
-                .as_deref()
-                .unwrap_or(""),
-            options.sql_name,
-            options.native_runtime_version
-        )));
-    }
-
-    if options.format != NativeExtensionArtifactFormat::Directory {
-        write_prebuilt_extension_artifact_archive(&artifact_root, &output, options.format)?;
-        if let Some(mut staging) = staging_root {
-            staging.remove()?;
-        }
-    }
-
-    Ok(NativeExtensionArtifact {
-        path: output.clone(),
-        manifest_path: (options.format == NativeExtensionArtifactFormat::Directory)
-            .then(|| output.join("manifest.properties")),
-        sql_name: options.sql_name,
-        license_profile,
-        license_files,
-        format: options.format,
-    })
-}
-
-pub(super) fn unique_timestamp_suffix() -> String {
-    let nanos = SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .map(|duration| duration.as_nanos())
-        .unwrap_or(0);
-    format!("{}-{nanos}", std::process::id())
-}
-
-pub(super) fn sha256_file_hex(path: &Path) -> Result {
-    let mut file = File::open(path).map_err(|err| {
-        Error::InvalidConfig(format!("open {} for sha256: {err}", path.display()))
-    })?;
-    let mut hasher = Sha256::new();
-    io::copy(&mut file, &mut hasher)
-        .map_err(|err| Error::Engine(format!("hash {}: {err}", path.display())))?;
-    Ok(format!("{:x}", hasher.finalize()))
-}
-
-#[derive(Debug)]
-struct RemoveOnDrop {
-    path: PathBuf,
-    removed: bool,
-}
-
-impl RemoveOnDrop {
-    fn create(path: PathBuf) -> Result {
-        fs::create_dir_all(&path).map_err(|err| {
-            Error::Engine(format!(
-                "create prebuilt extension artifact staging root {}: {err}",
-                path.display()
-            ))
-        })?;
-        Ok(Self {
-            path,
-            removed: false,
-        })
-    }
-
-    fn remove(&mut self) -> Result<()> {
-        if self.removed {
-            return Ok(());
-        }
-        fs::remove_dir_all(&self.path).map_err(|err| {
-            Error::Engine(format!(
-                "remove prebuilt extension artifact staging root {}: {err}",
-                self.path.display()
-            ))
-        })?;
-        self.removed = true;
-        Ok(())
-    }
-}
-
-impl Drop for RemoveOnDrop {
-    fn drop(&mut self) {
-        if !self.removed {
-            let _ = fs::remove_dir_all(&self.path);
-        }
-    }
-}
-
-fn validate_extension_artifact_options(options: &NativeExtensionArtifactOptions) -> Result<()> {
-    if options.output.as_os_str().is_empty() {
-        return Err(Error::InvalidConfig(
-            "prebuilt extension artifact output path must not be empty".to_owned(),
-        ));
-    }
-    if options.runtime_files.as_os_str().is_empty() {
-        return Err(Error::InvalidConfig(
-            "prebuilt extension artifact runtime root must not be empty".to_owned(),
-        ));
-    }
-    if !options.runtime_files.is_dir() {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact runtime root {} must be an existing directory",
-            options.runtime_files.display()
-        )));
-    }
-    validate_portable_id(&options.sql_name, "prebuilt extension sqlName")?;
-    validate_stable_semver(
-        &options.native_runtime_version,
-        "prebuilt extension nativeRuntimeVersion",
-    )?;
-    for dependency in &options.dependencies {
-        validate_portable_id(dependency, "prebuilt extension dependency")?;
-    }
-    for file_name in &options.extension_sql_file_names {
-        validate_portable_id(file_name, "prebuilt extension ancillary SQL filename")?;
-        if !file_name.ends_with(".sql") {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension ancillary SQL filename '{file_name}' must be a SQL basename"
-            )));
-        }
-    }
-    for prefix in &options.extension_sql_file_prefixes {
-        validate_portable_id(prefix, "prebuilt extension ancillary SQL prefix")?;
-        if prefix.contains('.') {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension ancillary SQL prefix '{prefix}' must not contain '.'"
-            )));
-        }
-    }
-    for library in &options.shared_preload_libraries {
-        validate_portable_id(library, "prebuilt extension shared preload library")?;
-    }
-    if let Some(stem) = &options.native_module_stem {
-        validate_portable_id(stem, "prebuilt extension native module stem")?;
-    }
-    if let Some(file_name) = &options.native_module_file {
-        validate_portable_id(file_name, "prebuilt extension native module file")?;
-        if options.native_module_stem.is_none() {
-            return Err(Error::InvalidConfig(
-                "prebuilt extension nativeModuleFile requires nativeModuleStem".to_owned(),
-            ));
-        }
-    }
-    if let Some(target) = &options.native_target {
-        validate_portable_id(target, "prebuilt extension native target")?;
-    }
-    if options.native_module_stem.is_some() && options.native_target.is_none() {
-        return Err(Error::InvalidConfig(
-            "prebuilt extension artifacts with nativeModuleStem must declare nativeTarget"
-                .to_owned(),
-        ));
-    }
-    let desktop_native_target = options
-        .native_target
-        .as_deref()
-        .is_some_and(|target| DESKTOP_NATIVE_TARGETS.contains(&target));
-    if options.native_module_stem.is_some()
-        && desktop_native_target
-        && options.embedded_module_root.is_none()
-    {
-        return Err(Error::InvalidConfig(
-            "desktop prebuilt extension artifacts with nativeModuleStem must declare an embedded module root"
-                .to_owned(),
-        ));
-    }
-    if let Some(root) = &options.embedded_module_root {
-        if options.native_module_stem.is_none() || !desktop_native_target {
-            return Err(Error::InvalidConfig(
-                "an embedded module root is only valid for desktop native extension artifacts"
-                    .to_owned(),
-            ));
-        }
-        if root.as_os_str().is_empty() || !root.is_dir() {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension embedded module root {} must be an existing directory",
-                root.display()
-            )));
-        }
-    }
-    if let Some(prefix) = &options.static_symbol_prefix
-        && !is_c_identifier(prefix)
-    {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension static symbol prefix '{prefix}' must be a portable C identifier"
-        )));
-    }
-    let mut alias_sql_symbols = BTreeSet::new();
-    for alias in &options.static_symbol_aliases {
-        if !is_c_identifier(&alias.sql_symbol) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension static symbol alias '{}' must use a portable C identifier",
-                alias.sql_symbol
-            )));
-        }
-        if !is_c_identifier(&alias.linked_symbol) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension static symbol alias target '{}' must use a portable C identifier",
-                alias.linked_symbol
-            )));
-        }
-        if !alias_sql_symbols.insert(alias.sql_symbol.clone()) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension repeats static symbol alias for '{}'",
-                alias.sql_symbol
-            )));
-        }
-    }
-    if !options.mobile_static_archives.is_empty() && options.native_module_stem.is_none() {
-        return Err(Error::InvalidConfig(
-            "prebuilt extension mobile static archives require nativeModuleStem".to_owned(),
-        ));
-    }
-    let mobile_prebuilt = artifact_mobile_prebuilt(options);
-    if mobile_prebuilt
-        && options.native_module_stem.is_some()
-        && options.mobile_static_archives.is_empty()
-    {
-        return Err(Error::InvalidConfig(
-            "mobilePrebuilt native-module artifacts must carry at least one mobile static archive"
-                .to_owned(),
-        ));
-    }
-    let mut mobile_targets = BTreeSet::new();
-    for archive in &options.mobile_static_archives {
-        validate_portable_id(
-            &archive.target,
-            "prebuilt extension mobile static archive target",
-        )?;
-        if !mobile_targets.insert(archive.target.clone()) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension mobile static archives repeat target '{}'",
-                archive.target
-            )));
-        }
-        if !archive.archive.is_file() {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension mobile static archive for target '{}' must be a file: {}",
-                archive.target,
-                archive.archive.display()
-            )));
-        }
-    }
-    let mut mobile_dependency_keys = BTreeSet::new();
-    for archive in &options.mobile_static_dependency_archives {
-        validate_portable_id(
-            &archive.target,
-            "prebuilt extension mobile static dependency archive target",
-        )?;
-        validate_portable_id(
-            &archive.name,
-            "prebuilt extension mobile static dependency archive name",
-        )?;
-        if !mobile_targets.contains(&archive.target) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension mobile static dependency archive '{}' for target '{}' requires a matching mobile static archive target",
-                archive.name, archive.target
-            )));
-        }
-        if !mobile_dependency_keys.insert((archive.target.clone(), archive.name.clone())) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension mobile static dependency archives repeat '{}' for target '{}'",
-                archive.name, archive.target
-            )));
-        }
-        validate_mobile_static_dependency_archive_file_name(&archive.archive)?;
-        if !archive.archive.is_file() {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension mobile static dependency archive '{}' for target '{}' must be a file: {}",
-                archive.name,
-                archive.target,
-                archive.archive.display()
-            )));
-        }
-    }
-    for data_file in &options.data_files {
-        validate_relative_artifact_path(&options.output, "data file", data_file)?;
-        if data_file
-            .components()
-            .next()
-            .and_then(|component| match component {
-                Component::Normal(value) => value.to_str(),
-                _ => None,
-            })
-            == Some("extension")
-        {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension data file '{}' must not be under share/postgresql/extension; control and SQL files are selected from sqlName",
-                data_file.display()
-            )));
-        }
-    }
-    let legal_contract = options.legal_contract.as_ref().ok_or_else(|| {
-        Error::InvalidConfig(
-            "prebuilt extension artifact creation requires an exact legal contract".to_owned(),
-        )
-    })?;
-    let legal_root_metadata = fs::symlink_metadata(&legal_contract.source_root).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "inspect prebuilt extension artifact legal source root {}: {err}",
-            legal_contract.source_root.display()
-        ))
-    })?;
-    if legal_root_metadata.file_type().is_symlink() || !legal_root_metadata.is_dir() {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact legal source root {} must be a real directory",
-            legal_contract.source_root.display()
-        )));
-    }
-    let canonical_license_files = sorted_deduped_paths(&legal_contract.license_files);
-    if canonical_license_files.len() != legal_contract.license_files.len() {
-        return Err(Error::InvalidConfig(
-            "prebuilt extension artifact legal contract repeats a license file".to_owned(),
-        ));
-    }
-    validate_extension_artifact_license_paths(&options.output, &canonical_license_files)?;
-    validate_extension_artifact_license_profile(
-        &options.output,
-        &options.sql_name,
-        options.native_target.as_deref(),
-        &mobile_static_dependency_archives_for_artifact_options(options)?,
-        legal_contract.profile,
-        &canonical_license_files,
-    )?;
-    for relative in extension_artifact_legal_members(legal_contract.profile)
-        .into_iter()
-        .chain(canonical_license_files.iter().cloned())
-    {
-        validate_extension_artifact_legal_source(&legal_contract.source_root, &relative)?;
-    }
-    Ok(())
-}
-
-pub(super) fn prepare_output_file(path: &Path, replace_existing: bool) -> Result<()> {
-    if path.exists() {
-        if !replace_existing {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact output {} already exists; pass --force or replace_existing(true)",
-                path.display()
-            )));
-        }
-        if path.is_dir() {
-            fs::remove_dir_all(path)
-        } else {
-            fs::remove_file(path)
-        }
-        .map_err(|err| Error::Engine(format!("remove {}: {err}", path.display())))?;
-    }
-    if let Some(parent) = path
-        .parent()
-        .filter(|parent| !parent.as_os_str().is_empty())
-    {
-        fs::create_dir_all(parent)
-            .map_err(|err| Error::Engine(format!("create {}: {err}", parent.display())))?;
-    }
-    Ok(())
-}
-
-fn write_prebuilt_extension_artifact_directory(
-    artifact_root: &Path,
-    options: &NativeExtensionArtifactOptions,
-) -> Result<()> {
-    let extension = artifact_options_runtime_resource_extension(options, artifact_root)?;
-    copy_extension_artifact_sql_files(
-        artifact_root,
-        &options.runtime_files,
-        &artifact_root.join("files"),
-        &extension,
-    )?;
-    for relative in &extension.data_files {
-        copy_artifact_source_file(
-            &options.runtime_files,
-            &artifact_root.join("files"),
-            &PathBuf::from("share/postgresql").join(relative),
-        )?;
-    }
-    if let Some(module_file) = &extension.native_module_file {
-        copy_artifact_source_file(
-            &options.runtime_files,
-            &artifact_root.join("files"),
-            &PathBuf::from("lib/postgresql").join(module_file),
-        )?;
-        if let Some(embedded_module_root) = &options.embedded_module_root {
-            copy_artifact_source_file(
-                embedded_module_root,
-                &artifact_root.join("files/lib/modules"),
-                Path::new(module_file),
-            )?;
-        }
-    }
-    copy_mobile_static_archives_to_artifact(artifact_root, options, &extension)?;
-    copy_mobile_static_dependency_archives_to_artifact(artifact_root, options, &extension)?;
-    copy_extension_artifact_legal_files(artifact_root, options)?;
-    write_prebuilt_extension_artifact_manifest(artifact_root, options, &extension)?;
-    Ok(())
-}
-
-fn artifact_options_runtime_resource_extension(
-    options: &NativeExtensionArtifactOptions,
-    artifact_root: &Path,
-) -> Result {
-    let native_module_file = options.native_module_stem.as_ref().map(|stem| {
-        options
-            .native_module_file
-            .clone()
-            .unwrap_or_else(|| format!("{}{}", stem, std::env::consts::DLL_SUFFIX))
-    });
-    Ok(RuntimeResourceExtension {
-        sql_name: options.sql_name.clone(),
-        native_runtime_version: Some(options.native_runtime_version.clone()),
-        creates_extension: options.creates_extension,
-        native_module_stem: options.native_module_stem.clone(),
-        native_module_file,
-        native_target: options.native_target.clone(),
-        dependencies: sorted_deduped_strings(&options.dependencies),
-        data_files: sorted_deduped_paths(&options.data_files),
-        extension_sql_file_names: sorted_deduped_strings(&options.extension_sql_file_names),
-        extension_sql_file_prefixes: sorted_deduped_strings(&options.extension_sql_file_prefixes),
-        shared_preload_libraries: sorted_deduped_strings(&options.shared_preload_libraries),
-        mobile_prebuilt: artifact_mobile_prebuilt(options),
-        mobile_static_archives: mobile_static_archives_for_artifact_options(options),
-        mobile_static_dependency_archives: mobile_static_dependency_archives_for_artifact_options(
-            options,
-        )?,
-        static_symbol_prefix: options.static_symbol_prefix.clone(),
-        static_symbol_aliases: sorted_static_symbol_aliases(&options.static_symbol_aliases),
-        license_profile: options
-            .legal_contract
-            .as_ref()
-            .map(|contract| contract.profile),
-        license_files: options
-            .legal_contract
-            .as_ref()
-            .map(|contract| sorted_deduped_paths(&contract.license_files))
-            .unwrap_or_default(),
-        source: RuntimeResourceExtensionSource::Prebuilt {
-            root: artifact_root.to_path_buf(),
-            files_root: artifact_root.join("files"),
-        },
-    })
-}
-
-fn artifact_mobile_prebuilt(options: &NativeExtensionArtifactOptions) -> bool {
-    options.mobile_prebuilt || !options.mobile_static_archives.is_empty()
-}
-
-fn mobile_static_archives_for_artifact_options(
-    options: &NativeExtensionArtifactOptions,
-) -> Vec {
-    let Some(stem) = options.native_module_stem.as_deref() else {
-        return Vec::new();
-    };
-    let mut archives = options
-        .mobile_static_archives
-        .iter()
-        .map(|archive| MobileStaticArchive {
-            target: archive.target.clone(),
-            relative_path: mobile_static_archive_artifact_relative_path(&archive.target, stem),
-        })
-        .collect::>();
-    archives.sort_by(|left, right| left.target.cmp(&right.target));
-    archives
-}
-
-pub(super) fn mobile_static_archive_artifact_relative_path(target: &str, stem: &str) -> PathBuf {
-    PathBuf::from("mobile-static")
-        .join(target)
-        .join("extensions")
-        .join(stem)
-        .join(format!("liboliphaunt_extension_{stem}.a"))
-}
-
-fn mobile_static_dependency_archives_for_artifact_options(
-    options: &NativeExtensionArtifactOptions,
-) -> Result> {
-    let mut archives = Vec::new();
-    for archive in &options.mobile_static_dependency_archives {
-        let file_name = validate_mobile_static_dependency_archive_file_name(&archive.archive)?;
-        archives.push(MobileStaticDependencyArchive {
-            target: archive.target.clone(),
-            name: archive.name.clone(),
-            relative_path: mobile_static_dependency_archive_artifact_relative_path(
-                &archive.target,
-                &archive.name,
-                &file_name,
-            ),
-        });
-    }
-    archives.sort_by(|left, right| {
-        left.target
-            .cmp(&right.target)
-            .then_with(|| left.name.cmp(&right.name))
-    });
-    Ok(archives)
-}
-
-fn sorted_static_symbol_aliases(
-    aliases: &[NativeExtensionStaticSymbolAlias],
-) -> Vec {
-    let mut aliases = aliases.to_vec();
-    aliases.sort_by(|left, right| {
-        left.sql_symbol
-            .cmp(&right.sql_symbol)
-            .then_with(|| left.linked_symbol.cmp(&right.linked_symbol))
-    });
-    aliases.dedup();
-    aliases
-}
-
-pub(super) fn mobile_static_dependency_archive_artifact_relative_path(
-    target: &str,
-    name: &str,
-    file_name: &str,
-) -> PathBuf {
-    PathBuf::from("mobile-static")
-        .join(target)
-        .join("dependencies")
-        .join(name)
-        .join(file_name)
-}
-
-fn validate_mobile_static_dependency_archive_file_name(path: &Path) -> Result {
-    let file_name = path.file_name().and_then(|name| name.to_str()).ok_or_else(|| {
-        Error::InvalidConfig(format!(
-            "prebuilt extension mobile static dependency archive path {} must include a portable file name",
-            path.display()
-        ))
-    })?;
-    validate_portable_id(
-        file_name,
-        "prebuilt extension mobile static dependency archive file",
-    )?;
-    Ok(file_name.to_owned())
-}
-
-fn copy_mobile_static_archives_to_artifact(
-    artifact_root: &Path,
-    options: &NativeExtensionArtifactOptions,
-    extension: &RuntimeResourceExtension,
-) -> Result<()> {
-    if options.mobile_static_archives.is_empty() {
-        return Ok(());
-    }
-    let archive_by_target = options
-        .mobile_static_archives
-        .iter()
-        .map(|archive| (archive.target.as_str(), archive.archive.as_path()))
-        .collect::>();
-    for archive in &extension.mobile_static_archives {
-        let Some(source) = archive_by_target.get(archive.target.as_str()) else {
-            return Err(Error::Engine(format!(
-                "internal error: missing mobile static archive source for target '{}'",
-                archive.target
-            )));
-        };
-        copy_portable_tree(source, &artifact_root.join(&archive.relative_path))?;
-    }
-    Ok(())
-}
-
-fn copy_mobile_static_dependency_archives_to_artifact(
-    artifact_root: &Path,
-    options: &NativeExtensionArtifactOptions,
-    extension: &RuntimeResourceExtension,
-) -> Result<()> {
-    if options.mobile_static_dependency_archives.is_empty() {
-        return Ok(());
-    }
-    let archive_by_key = options
-        .mobile_static_dependency_archives
-        .iter()
-        .map(|archive| {
-            (
-                (archive.target.as_str(), archive.name.as_str()),
-                archive.archive.as_path(),
-            )
-        })
-        .collect::>();
-    for archive in &extension.mobile_static_dependency_archives {
-        let Some(source) = archive_by_key.get(&(archive.target.as_str(), archive.name.as_str()))
-        else {
-            return Err(Error::Engine(format!(
-                "internal error: missing mobile static dependency archive source for target '{}' dependency '{}'",
-                archive.target, archive.name
-            )));
-        };
-        copy_portable_tree(source, &artifact_root.join(&archive.relative_path))?;
-    }
-    Ok(())
-}
-
-fn copy_extension_artifact_legal_files(
-    artifact_root: &Path,
-    options: &NativeExtensionArtifactOptions,
-) -> Result<()> {
-    let contract = options
-        .legal_contract
-        .as_ref()
-        .expect("validated artifact options require a legal contract");
-    for relative in extension_artifact_legal_members(contract.profile) {
-        copy_extension_artifact_legal_file(
-            &contract.source_root,
-            &relative,
-            &artifact_root.join(&relative),
-        )?;
-    }
-    for relative in sorted_deduped_paths(&contract.license_files) {
-        copy_extension_artifact_legal_file(
-            &contract.source_root,
-            &relative,
-            &artifact_root.join("files").join(&relative),
-        )?;
-    }
-    Ok(())
-}
-
-fn copy_extension_artifact_legal_file(
-    source_root: &Path,
-    relative: &Path,
-    destination: &Path,
-) -> Result<()> {
-    validate_relative_artifact_path(source_root, "legal file", relative)?;
-    let source = source_root.join(relative);
-    validate_extension_artifact_legal_source(source_root, relative)?;
-    if let Some(parent) = destination.parent() {
-        fs::create_dir_all(parent)
-            .map_err(|err| Error::Engine(format!("create {}: {err}", parent.display())))?;
-    }
-    fs::copy(&source, destination).map_err(|err| {
-        Error::Engine(format!(
-            "copy legal file {} -> {}: {err}",
-            source.display(),
-            destination.display()
-        ))
-    })?;
-    set_extension_artifact_legal_mode(destination)
-}
-
-fn validate_extension_artifact_legal_source(source_root: &Path, relative: &Path) -> Result<()> {
-    validate_relative_artifact_path(source_root, "legal file", relative)?;
-    let mut cursor = source_root.to_path_buf();
-    let component_count = relative.components().count();
-    for (index, component) in relative.components().enumerate() {
-        let Component::Normal(component) = component else {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact legal source path {} is unsafe",
-                relative.display()
-            )));
-        };
-        cursor.push(component);
-        let metadata = fs::symlink_metadata(&cursor).map_err(|err| {
-            Error::InvalidConfig(format!(
-                "inspect prebuilt extension artifact legal source path {}: {err}",
-                cursor.display()
-            ))
-        })?;
-        if metadata.file_type().is_symlink() {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact legal source path {} must not traverse a symlink",
-                cursor.display()
-            )));
-        }
-        if index + 1 == component_count {
-            if !metadata.is_file() || metadata.len() == 0 {
-                return Err(Error::InvalidConfig(format!(
-                    "prebuilt extension artifact legal source file {} must be a non-empty regular non-symlink file",
-                    cursor.display()
-                )));
-            }
-        } else if !metadata.is_dir() {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact legal source parent {} must be a real directory",
-                cursor.display()
-            )));
-        }
-    }
-    Ok(())
-}
-
-fn set_extension_artifact_legal_mode(path: &Path) -> Result<()> {
-    #[cfg(unix)]
-    {
-        use std::os::unix::fs::PermissionsExt;
-        fs::set_permissions(path, fs::Permissions::from_mode(0o644)).map_err(|err| {
-            Error::Engine(format!(
-                "set canonical legal file permissions on {}: {err}",
-                path.display()
-            ))
-        })?;
-    }
-    #[cfg(not(unix))]
-    {
-        let mut permissions = fs::metadata(path)
-            .map_err(|err| Error::Engine(format!("stat {}: {err}", path.display())))?
-            .permissions();
-        permissions.set_readonly(false);
-        fs::set_permissions(path, permissions).map_err(|err| {
-            Error::Engine(format!(
-                "set portable legal file permissions on {}: {err}",
-                path.display()
-            ))
-        })?;
-    }
-    Ok(())
-}
-
-pub(super) fn sorted_deduped_strings(values: &[String]) -> Vec {
-    values
-        .iter()
-        .cloned()
-        .collect::>()
-        .into_iter()
-        .collect()
-}
-
-fn sorted_deduped_paths(values: &[PathBuf]) -> Vec {
-    values
-        .iter()
-        .cloned()
-        .collect::>()
-        .into_iter()
-        .collect()
-}
-
-fn copy_extension_artifact_sql_files(
-    artifact_root: &Path,
-    runtime_files: &Path,
-    artifact_files: &Path,
-    extension: &RuntimeResourceExtension,
-) -> Result<()> {
-    let source_dir = runtime_files.join("share/postgresql/extension");
-    let target_dir = artifact_files.join("share/postgresql/extension");
-    if !source_dir.is_dir() {
-        if extension.creates_extension {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact source runtime {} is missing share/postgresql/extension for '{}'",
-                runtime_files.display(),
-                extension.sql_name
-            )));
-        }
-        return Ok(());
-    }
-
-    let mut copied_control = false;
-    let mut copied_sql = false;
-    let mut copied = 0usize;
-    let mut entries = fs::read_dir(&source_dir)
-        .map_err(|err| Error::Engine(format!("read {}: {err}", source_dir.display())))?
-        .collect::, _>>()
-        .map_err(|err| Error::Engine(format!("read entry in {}: {err}", source_dir.display())))?;
-    entries.sort_by_key(|entry| entry.file_name());
-    for entry in entries {
-        let file_name = entry.file_name().to_string_lossy().into_owned();
-        if !runtime_extension_sql_file_belongs(extension, &file_name) {
-            continue;
-        }
-        copied += 1;
-        if file_name == format!("{}.control", extension.sql_name) {
-            copied_control = true;
-        } else if extension_install_sql_file_belongs(&extension.sql_name, &file_name) {
-            copied_sql = true;
-        }
-        copy_extension_runtime_file(runtime_files, &entry.path(), &target_dir.join(file_name))?;
-    }
-
-    if extension.creates_extension && (!copied_control || !copied_sql) {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact {} for '{}' must include a control file and at least one SQL install file",
-            artifact_root.display(),
-            extension.sql_name
-        )));
-    }
-    if !extension.creates_extension && copied == 0 {
-        return Ok(());
-    }
-    Ok(())
-}
-
-fn copy_artifact_source_file(
-    source_root: &Path,
-    artifact_files: &Path,
-    relative: &Path,
-) -> Result<()> {
-    validate_relative_artifact_path(source_root, "runtime file", relative)?;
-    let source = source_root.join(relative);
-    if !source.is_file() {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact source runtime is missing declared file {}",
-            source.display()
-        )));
-    }
-    copy_extension_runtime_file(source_root, &source, &artifact_files.join(relative))
-}
-
-fn copy_extension_runtime_file(
-    runtime_root: &Path,
-    source: &Path,
-    destination: &Path,
-) -> Result<()> {
-    let symlink_metadata = fs::symlink_metadata(source)
-        .map_err(|err| Error::Engine(format!("stat {}: {err}", source.display())))?;
-    let file_metadata = if symlink_metadata.file_type().is_symlink() {
-        let canonical_root = runtime_root.canonicalize().map_err(|err| {
-            Error::Engine(format!(
-                "canonicalize runtime root {}: {err}",
-                runtime_root.display()
-            ))
-        })?;
-        let canonical_source = source.canonicalize().map_err(|err| {
-            Error::Engine(format!(
-                "canonicalize selected extension runtime symlink {}: {err}",
-                source.display()
-            ))
-        })?;
-        if !canonical_source.starts_with(&canonical_root) {
-            return Err(Error::InvalidConfig(format!(
-                "selected extension runtime symlink {} resolves outside runtime root {}",
-                source.display(),
-                runtime_root.display()
-            )));
-        }
-        fs::metadata(source).map_err(|err| {
-            Error::Engine(format!(
-                "stat selected extension runtime symlink target {}: {err}",
-                source.display()
-            ))
-        })?
-    } else {
-        symlink_metadata
-    };
-    if !file_metadata.is_file() {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact source runtime file {} must be a regular file",
-            source.display()
-        )));
-    }
-    copy_portable_file(source, destination, &file_metadata)
-}
-
-fn write_prebuilt_extension_artifact_manifest(
-    artifact_root: &Path,
-    options: &NativeExtensionArtifactOptions,
-    extension: &RuntimeResourceExtension,
-) -> Result<()> {
-    fs::create_dir_all(artifact_root)
-        .map_err(|err| Error::Engine(format!("create {}: {err}", artifact_root.display())))?;
-    let legal_contract = options
-        .legal_contract
-        .as_ref()
-        .expect("validated artifact options require a legal contract");
-    let license_files = sorted_deduped_paths(&legal_contract.license_files)
-        .iter()
-        .map(|path| render_portable_artifact_path(path, "prebuilt extension license file"))
-        .collect::>>()?
-        .join(",");
-    let data_files = extension
-        .data_files
-        .iter()
-        .map(|path| render_portable_artifact_path(path, "prebuilt extension data file"))
-        .collect::>>()?
-        .join(",");
-    let mobile_static_archives =
-        mobile_static_archive_manifest_value(&extension.mobile_static_archives)?;
-    let mobile_static_dependency_archives = mobile_static_dependency_archive_manifest_value(
-        &extension.mobile_static_dependency_archives,
-    )?;
-    let text = format!(
-        "packageLayout={EXTENSION_ARTIFACT_LAYOUT}\npgMajor=18\nsqlName={}\ncreatesExtension={}\nnativeModuleStem={}\nnativeModuleFile={}\nnativeTarget={}\nnativeRuntimeProduct={EXTENSION_ARTIFACT_NATIVE_RUNTIME_PRODUCT}\nnativeRuntimeVersion={}\ndependencies={}\ndataFiles={}\nextensionSqlFileNames={}\nextensionSqlFilePrefixes={}\nsharedPreloadLibraries={}\nmobilePrebuilt={}\nmobileStaticArchives={}\nmobileStaticDependencyArchives={}\nstaticSymbolPrefix={}\nstaticSymbolAliases={}\nlicenseFiles={}\nlicenseProfile={}\nfiles=files\n",
-        extension.sql_name,
-        yes_no_manifest(options.creates_extension),
-        extension.native_module_stem.as_deref().unwrap_or(""),
-        extension.native_module_file.as_deref().unwrap_or(""),
-        extension.native_target.as_deref().unwrap_or(""),
-        options.native_runtime_version,
-        extension.dependencies.join(","),
-        data_files,
-        extension.extension_sql_file_names.join(","),
-        extension.extension_sql_file_prefixes.join(","),
-        extension.shared_preload_libraries.join(","),
-        yes_no_manifest(extension.mobile_prebuilt),
-        mobile_static_archives,
-        mobile_static_dependency_archives,
-        extension.static_symbol_prefix.as_deref().unwrap_or(""),
-        static_symbol_alias_manifest_value(&extension.static_symbol_aliases),
-        license_files,
-        legal_contract.profile.as_str(),
-    );
-    fs::write(artifact_root.join("manifest.properties"), text).map_err(|err| {
-        Error::Engine(format!(
-            "write prebuilt extension artifact manifest {}: {err}",
-            artifact_root.join("manifest.properties").display()
-        ))
-    })
-}
-
-fn static_symbol_alias_manifest_value(aliases: &[NativeExtensionStaticSymbolAlias]) -> String {
-    aliases
-        .iter()
-        .map(|alias| format!("{}:{}", alias.sql_symbol, alias.linked_symbol))
-        .collect::>()
-        .join(",")
-}
-
-fn mobile_static_archive_manifest_value(archives: &[MobileStaticArchive]) -> Result {
-    Ok(archives
-        .iter()
-        .map(|archive| {
-            Ok(format!(
-                "{}:{}",
-                archive.target,
-                render_portable_artifact_path(
-                    &archive.relative_path,
-                    "prebuilt extension mobile static archive",
-                )?
-            ))
-        })
-        .collect::>>()?
-        .join(","))
-}
-
-fn mobile_static_dependency_archive_manifest_value(
-    archives: &[MobileStaticDependencyArchive],
-) -> Result {
-    Ok(archives
-        .iter()
-        .map(|archive| {
-            Ok(format!(
-                "{}:{}:{}",
-                archive.target,
-                archive.name,
-                render_portable_artifact_path(
-                    &archive.relative_path,
-                    "prebuilt extension mobile static dependency archive",
-                )?
-            ))
-        })
-        .collect::>>()?
-        .join(","))
-}
-
-fn yes_no_manifest(value: bool) -> &'static str {
-    if value { "yes" } else { "no" }
-}
-
-fn write_prebuilt_extension_artifact_archive(
-    artifact_root: &Path,
-    output: &Path,
-    format: NativeExtensionArtifactFormat,
-) -> Result<()> {
-    let policy = extension_artifact_archive_policy()?;
-    let file = File::create(output)
-        .map_err(|err| Error::Engine(format!("create {}: {err}", output.display())))?;
-    match format {
-        NativeExtensionArtifactFormat::Directory => Ok(()),
-        NativeExtensionArtifactFormat::Tar => {
-            write_prebuilt_extension_artifact_tar(file, artifact_root).map(|_| ())
-        }
-        NativeExtensionArtifactFormat::TarGz => {
-            let encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
-            let encoder = write_prebuilt_extension_artifact_tar(encoder, artifact_root)?;
-            encoder.finish().map_err(|err| {
-                Error::Engine(format!(
-                    "finish gzip prebuilt extension artifact archive {}: {err}",
-                    output.display()
-                ))
-            })?;
-            Ok(())
-        }
-        NativeExtensionArtifactFormat::TarZst => {
-            let encoder = zstd::stream::write::Encoder::new(file, 0).map_err(|err| {
-                Error::Engine(format!(
-                    "create zstd prebuilt extension artifact archive {}: {err}",
-                    output.display()
-                ))
-            })?;
-            let encoder = write_prebuilt_extension_artifact_tar(encoder, artifact_root)?;
-            encoder.finish().map_err(|err| {
-                Error::Engine(format!(
-                    "finish zstd prebuilt extension artifact archive {}: {err}",
-                    output.display()
-                ))
-            })?;
-            Ok(())
-        }
-    }?;
-    let output_bytes = fs::metadata(output)
-        .map_err(|err| Error::Engine(format!("stat {}: {err}", output.display())))?
-        .len();
-    let output_limit = if matches!(format, NativeExtensionArtifactFormat::Tar) {
-        policy.max_expanded_bytes
-    } else {
-        policy.max_compressed_bytes
-    };
-    if output_bytes == 0 || output_bytes > output_limit {
-        return Err(Error::Engine(format!(
-            "created prebuilt extension artifact archive {} must contain between 1 and {output_limit} bytes",
-            output.display()
-        )));
-    }
-    Ok(())
-}
-
-fn write_prebuilt_extension_artifact_tar(
-    writer: W,
-    artifact_root: &Path,
-) -> Result {
-    let policy = extension_artifact_archive_policy()?;
-    let mut shape = ExtensionArtifactArchiveShape {
-        member_count: 0,
-        expanded_bytes: 1024,
-    };
-    let mut archive = tar::Builder::new(writer);
-    append_artifact_files_to_tar(
-        &mut archive,
-        artifact_root,
-        artifact_root,
-        policy,
-        &mut shape,
-    )?;
-    archive.finish().map_err(|err| {
-        Error::Engine(format!(
-            "finish prebuilt extension artifact tar from {}: {err}",
-            artifact_root.display()
-        ))
-    })?;
-    archive.into_inner().map_err(|err| {
-        Error::Engine(format!(
-            "finish prebuilt extension artifact tar writer from {}: {err}",
-            artifact_root.display()
-        ))
-    })
-}
-
-#[derive(Debug)]
-pub(super) struct ExtensionArtifactArchiveShape {
-    pub(super) member_count: usize,
-    pub(super) expanded_bytes: u64,
-}
-
-pub(super) fn record_extension_artifact_archive_member(
-    artifact_root: &Path,
-    relative: &Path,
-    member_bytes: u64,
-    policy: ExtensionArtifactArchivePolicy,
-    shape: &mut ExtensionArtifactArchiveShape,
-) -> Result<()> {
-    shape.member_count = shape.member_count.checked_add(1).ok_or_else(|| {
-        Error::Engine(format!(
-            "prebuilt extension artifact {} member count overflows",
-            artifact_root.display()
-        ))
-    })?;
-    if shape.member_count > policy.max_members {
-        return Err(Error::Engine(format!(
-            "prebuilt extension artifact {} contains more than {} members",
-            artifact_root.display(),
-            policy.max_members
-        )));
-    }
-    if member_bytes > policy.max_member_bytes {
-        return Err(Error::Engine(format!(
-            "prebuilt extension artifact {} member {} exceeds {} bytes",
-            artifact_root.display(),
-            relative.display(),
-            policy.max_member_bytes
-        )));
-    }
-    let padded_member_bytes = member_bytes
-        .checked_add(511)
-        .map(|value| value / 512 * 512)
-        .ok_or_else(|| {
-            Error::Engine(format!(
-                "prebuilt extension artifact {} member {} size overflows",
-                artifact_root.display(),
-                relative.display()
-            ))
-        })?;
-    shape.expanded_bytes = shape
-        .expanded_bytes
-        .checked_add(512)
-        .and_then(|value| value.checked_add(padded_member_bytes))
-        .ok_or_else(|| {
-            Error::Engine(format!(
-                "prebuilt extension artifact {} expanded size overflows",
-                artifact_root.display()
-            ))
-        })?;
-    if shape.expanded_bytes > policy.max_expanded_bytes {
-        return Err(Error::Engine(format!(
-            "prebuilt extension artifact {} expands beyond {} bytes",
-            artifact_root.display(),
-            policy.max_expanded_bytes
-        )));
-    }
-    Ok(())
-}
-
-fn append_artifact_files_to_tar(
-    archive: &mut tar::Builder,
-    artifact_root: &Path,
-    current: &Path,
-    policy: ExtensionArtifactArchivePolicy,
-    shape: &mut ExtensionArtifactArchiveShape,
-) -> Result<()> {
-    let mut entries = fs::read_dir(current)
-        .map_err(|err| Error::Engine(format!("read {}: {err}", current.display())))?
-        .collect::, _>>()
-        .map_err(|err| Error::Engine(format!("read entry in {}: {err}", current.display())))?;
-    entries.sort_by_key(|entry| entry.file_name());
-    for entry in entries {
-        let path = entry.path();
-        let metadata = fs::symlink_metadata(&path)
-            .map_err(|err| Error::Engine(format!("stat {}: {err}", path.display())))?;
-        if metadata.file_type().is_symlink() {
-            return Err(Error::Engine(format!(
-                "prebuilt extension artifact archives do not support symlinks: {}",
-                path.display()
-            )));
-        }
-        if metadata.is_dir() {
-            append_artifact_files_to_tar(archive, artifact_root, &path, policy, shape)?;
-            continue;
-        }
-        if !metadata.is_file() {
-            return Err(Error::Engine(format!(
-                "prebuilt extension artifact archives only support files and directories: {}",
-                path.display()
-            )));
-        }
-        let relative = path.strip_prefix(artifact_root).map_err(|err| {
-            Error::Engine(format!(
-                "derive prebuilt extension artifact archive path for {}: {err}",
-                path.display()
-            ))
-        })?;
-        validate_relative_artifact_path(artifact_root, "archive file", relative)?;
-        let portable_relative =
-            render_portable_artifact_path(relative, "prebuilt extension archive file")?;
-        record_extension_artifact_archive_member(
-            artifact_root,
-            relative,
-            metadata.len(),
-            policy,
-            shape,
-        )?;
-        let mut header = tar::Header::new_gnu();
-        header.set_size(metadata.len());
-        header.set_mode(portable_tar_mode(&metadata));
-        header.set_mtime(0);
-        header.set_cksum();
-        let mut file = File::open(&path)
-            .map_err(|err| Error::Engine(format!("open {}: {err}", path.display())))?;
-        archive
-            .append_data(&mut header, portable_relative, &mut file)
-            .map_err(|err| {
-                Error::Engine(format!(
-                    "append {} to prebuilt extension artifact archive: {err}",
-                    relative.display()
-                ))
-            })?;
-    }
-    Ok(())
-}
-
-fn portable_tar_mode(metadata: &fs::Metadata) -> u32 {
-    if metadata.is_dir() {
-        return 0o755;
-    }
-    #[cfg(unix)]
-    {
-        use std::os::unix::fs::PermissionsExt;
-        if metadata.permissions().mode() & 0o111 != 0 {
-            0o755
-        } else {
-            0o644
-        }
-    }
-    #[cfg(not(unix))]
-    {
-        0o644
-    }
-}
-
-fn unique_extension_artifact_staging_root() -> PathBuf {
-    let nanos = SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .map(|duration| duration.as_nanos())
-        .unwrap_or(0);
-    std::env::temp_dir().join(format!(
-        "oliphaunt-extension-artifact-create-{}-{nanos}",
-        std::process::id()
-    ))
-}
-
-pub(super) fn unique_extension_extraction_root() -> PathBuf {
-    let nanos = SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .map(|duration| duration.as_nanos())
-        .unwrap_or(0);
-    std::env::temp_dir().join(format!(
-        "oliphaunt-extension-artifacts-{}-{nanos}",
-        std::process::id()
-    ))
-}
-
-pub(super) fn extract_prebuilt_extension_archive(
-    archive_path: &Path,
-    destination: &Path,
-) -> Result {
-    let policy = extension_artifact_archive_policy()?;
-    let archive_metadata = fs::symlink_metadata(archive_path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "inspect prebuilt extension artifact archive {}: {err}",
-            archive_path.display()
-        ))
-    })?;
-    if archive_metadata.file_type().is_symlink() || !archive_metadata.is_file() {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact archive {} must be a regular non-symlink file",
-            archive_path.display()
-        )));
-    }
-    let compressed = archive_is_tar_zst(archive_path) || archive_is_tar_gz(archive_path);
-    let archive_limit = if compressed {
-        policy.max_compressed_bytes
-    } else {
-        policy.max_expanded_bytes
-    };
-    if archive_metadata.len() == 0 || archive_metadata.len() > archive_limit {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact archive {} must contain between 1 and {archive_limit} bytes",
-            archive_path.display()
-        )));
-    }
-    fs::create_dir_all(destination).map_err(|err| {
-        Error::Engine(format!(
-            "create prebuilt extension artifact extraction dir {}: {err}",
-            destination.display()
-        ))
-    })?;
-    let file = File::open(archive_path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "open prebuilt extension artifact archive {}: {err}",
-            archive_path.display()
-        ))
-    })?;
-    let file_modes = if archive_is_tar_zst(archive_path) {
-        let decoder = zstd::stream::read::Decoder::new(file).map_err(|err| {
-            Error::InvalidConfig(format!(
-                "open zstd prebuilt extension artifact archive {}: {err}",
-                archive_path.display()
-            ))
-        })?;
-        extract_prebuilt_extension_tar(archive_path, decoder, destination, policy)?
-    } else if archive_is_tar_gz(archive_path) {
-        let decoder = flate2::read::GzDecoder::new(file);
-        extract_prebuilt_extension_tar(archive_path, decoder, destination, policy)?
-    } else if archive_is_tar(archive_path) {
-        extract_prebuilt_extension_tar(archive_path, file, destination, policy)?
-    } else {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact archive {} must end in .tar, .tar.gz, or .tar.zst",
-            archive_path.display()
-        )));
-    };
-    let root = extracted_extension_artifact_root(destination)?;
-    validate_extension_artifact_archive_legal_modes(archive_path, destination, &root, &file_modes)?;
-    Ok(root)
-}
-
-fn archive_is_tar(path: &Path) -> bool {
-    path.file_name()
-        .and_then(|name| name.to_str())
-        .is_some_and(|name| name.ends_with(".tar"))
-}
-
-fn archive_is_tar_zst(path: &Path) -> bool {
-    path.file_name()
-        .and_then(|name| name.to_str())
-        .is_some_and(|name| name.ends_with(".tar.zst"))
-}
-
-fn archive_is_tar_gz(path: &Path) -> bool {
-    path.file_name()
-        .and_then(|name| name.to_str())
-        .is_some_and(|name| name.ends_with(".tar.gz") || name.ends_with(".tgz"))
-}
-
-fn extract_prebuilt_extension_tar(
-    archive_path: &Path,
-    reader: impl io::Read,
-    destination: &Path,
-    policy: ExtensionArtifactArchivePolicy,
-) -> Result> {
-    let mut archive = tar::Archive::new(reader);
-    let entries = archive.entries().map_err(|err| {
-        Error::InvalidConfig(format!(
-            "read prebuilt extension artifact archive {}: {err}",
-            archive_path.display()
-        ))
-    })?;
-    let mut seen_files = BTreeSet::new();
-    let mut seen_dirs = BTreeSet::new();
-    let mut file_modes = BTreeMap::new();
-    let mut member_count = 0usize;
-    // The canonical archive policy includes the two 512-byte tar end-marker
-    // blocks in the expanded byte budget. `tar::Archive::entries` stops before
-    // those blocks, so account for them up front just as the JS producer,
-    // release inventory, and Android consumer do.
-    let mut expanded_bytes = 1024u64;
-    for entry in entries {
-        let mut entry = entry.map_err(|err| {
-            Error::InvalidConfig(format!(
-                "read prebuilt extension artifact archive entry in {}: {err}",
-                archive_path.display()
-            ))
-        })?;
-        member_count += 1;
-        if member_count > policy.max_members {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive {} contains more than {} members",
-                archive_path.display(),
-                policy.max_members
-            )));
-        }
-        let member_bytes = entry.size();
-        if member_bytes > policy.max_member_bytes {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive {} contains a member larger than {} bytes",
-                archive_path.display(),
-                policy.max_member_bytes
-            )));
-        }
-        let padded_member_bytes = member_bytes
-            .checked_add(511)
-            .map(|value| value / 512 * 512)
-            .ok_or_else(|| {
-                Error::InvalidConfig(format!(
-                    "prebuilt extension artifact archive {} has an overflowing member size",
-                    archive_path.display()
-                ))
-            })?;
-        expanded_bytes = expanded_bytes
-            .checked_add(512)
-            .and_then(|value| value.checked_add(padded_member_bytes))
-            .ok_or_else(|| {
-                Error::InvalidConfig(format!(
-                    "prebuilt extension artifact archive {} has an overflowing expanded size",
-                    archive_path.display()
-                ))
-            })?;
-        if expanded_bytes > policy.max_expanded_bytes {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive {} expands beyond {} bytes",
-                archive_path.display(),
-                policy.max_expanded_bytes
-            )));
-        }
-        let entry_type = entry.header().entry_type();
-        let raw_relative = entry.path_bytes();
-        let raw_relative = std::str::from_utf8(raw_relative.as_ref()).map_err(|err| {
-            Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive {} contains a non-UTF-8 path: {err}",
-                archive_path.display()
-            ))
-        })?;
-        let raw_relative = if entry_type.is_dir() {
-            raw_relative.strip_suffix('/').unwrap_or(raw_relative)
-        } else {
-            raw_relative
-        };
-        let relative =
-            parse_portable_artifact_path_text(archive_path, "archive entry", raw_relative)?;
-        if entry_type.is_dir() {
-            if member_bytes != 0 {
-                return Err(Error::InvalidConfig(format!(
-                    "prebuilt extension artifact archive {} directory {} must have size zero",
-                    archive_path.display(),
-                    relative.display()
-                )));
-            }
-            validate_archive_entry_plan(&relative, true, &mut seen_files, &mut seen_dirs)?;
-            fs::create_dir_all(destination.join(&relative)).map_err(|err| {
-                Error::Engine(format!(
-                    "create prebuilt extension artifact archive dir {}: {err}",
-                    destination.join(&relative).display()
-                ))
-            })?;
-        } else if entry_type.is_file() {
-            validate_archive_entry_plan(&relative, false, &mut seen_files, &mut seen_dirs)?;
-            let mode = entry.header().mode().map_err(|err| {
-                Error::InvalidConfig(format!(
-                    "read prebuilt extension artifact archive mode for {} in {}: {err}",
-                    relative.display(),
-                    archive_path.display()
-                ))
-            })?;
-            file_modes.insert(relative.clone(), mode);
-            if let Some(parent) = destination.join(&relative).parent() {
-                fs::create_dir_all(parent).map_err(|err| {
-                    Error::Engine(format!(
-                        "create prebuilt extension artifact archive parent {}: {err}",
-                        parent.display()
-                    ))
-                })?;
-            }
-            entry.unpack(destination.join(&relative)).map_err(|err| {
-                Error::Engine(format!(
-                    "extract prebuilt extension artifact archive entry {} from {}: {err}",
-                    relative.display(),
-                    archive_path.display()
-                ))
-            })?;
-        } else {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive {} entry {} must be a regular file or directory, not {:?}",
-                archive_path.display(),
-                relative.display(),
-                entry_type
-            )));
-        }
-    }
-    Ok(file_modes)
-}
-
-fn validate_extension_artifact_archive_legal_modes(
-    archive_path: &Path,
-    destination: &Path,
-    artifact_root: &Path,
-    file_modes: &BTreeMap,
-) -> Result<()> {
-    let wrapper = artifact_root.strip_prefix(destination).map_err(|err| {
-        Error::Engine(format!(
-            "derive prebuilt extension artifact wrapper path for {}: {err}",
-            artifact_root.display()
-        ))
-    })?;
-    for (archive_member, mode) in file_modes {
-        let relative = if wrapper.as_os_str().is_empty() {
-            archive_member.as_path()
-        } else {
-            archive_member.strip_prefix(wrapper).map_err(|_| {
-                Error::InvalidConfig(format!(
-                    "prebuilt extension artifact archive {} contains top-level member {} outside wrapper {}",
-                    archive_path.display(),
-                    archive_member.display(),
-                    wrapper.display()
-                ))
-            })?
-        };
-        if extension_artifact_archive_member_is_legal(relative) && *mode != 0o644 {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive {} legal member {} must have exact tar header mode 0644, got {:04o}",
-                archive_path.display(),
-                archive_member.display(),
-                mode
-            )));
-        }
-    }
-    Ok(())
-}
-
-fn extension_artifact_archive_member_is_legal(relative: &Path) -> bool {
-    relative == Path::new("LICENSE")
-        || relative == Path::new("THIRD_PARTY_NOTICES.md")
-        || relative.starts_with("THIRD_PARTY_LICENSES")
-        || relative.starts_with("files/share/licenses")
-}
-
-fn validate_archive_entry_plan(
-    relative: &Path,
-    is_dir: bool,
-    seen_files: &mut BTreeSet,
-    seen_dirs: &mut BTreeSet,
-) -> Result<()> {
-    let mut ancestors = relative.ancestors();
-    let _ = ancestors.next();
-    for ancestor in ancestors {
-        if ancestor.as_os_str().is_empty() {
-            continue;
-        }
-        if seen_files.contains(ancestor) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive entry {} is nested under file entry {}",
-                relative.display(),
-                ancestor.display()
-            )));
-        }
-    }
-    if is_dir {
-        if seen_files.contains(relative) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive has both file and directory entries for {}",
-                relative.display()
-            )));
-        }
-        if !seen_dirs.insert(relative.to_path_buf()) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive repeats directory entry {}",
-                relative.display()
-            )));
-        }
-    } else {
-        if seen_dirs.contains(relative) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive has both directory and file entries for {}",
-                relative.display()
-            )));
-        }
-        if !seen_files.insert(relative.to_path_buf()) {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact archive repeats file entry {}",
-                relative.display()
-            )));
-        }
-    }
-    Ok(())
-}
-
-fn extracted_extension_artifact_root(destination: &Path) -> Result {
-    if destination.join("manifest.properties").is_file() {
-        return Ok(destination.to_path_buf());
-    }
-    let mut children = fs::read_dir(destination)
-        .map_err(|err| {
-            Error::Engine(format!(
-                "read prebuilt extension artifact extraction dir {}: {err}",
-                destination.display()
-            ))
-        })?
-        .collect::, _>>()
-        .map_err(|err| {
-            Error::Engine(format!(
-                "read entry in prebuilt extension artifact extraction dir {}: {err}",
-                destination.display()
-            ))
-        })?;
-    children.sort_by_key(|entry| entry.file_name());
-    if let [nested] = children.as_slice() {
-        let file_type = nested.file_type().map_err(|err| {
-            Error::Engine(format!(
-                "inspect top-level prebuilt extension artifact archive entry {}: {err}",
-                nested.path().display()
-            ))
-        })?;
-        if file_type.is_dir() && nested.path().join("manifest.properties").is_file() {
-            return Ok(nested.path());
-        }
-    }
-    Err(Error::InvalidConfig(format!(
-        "prebuilt extension artifact archive extracted to {} but did not contain manifest.properties at archive root or under exactly one top-level directory with no sibling entries",
-        destination.display()
-    )))
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn artifact_manifest_path_fields_use_portable_component_separators() {
-        let data_file = ["data", "nested", "acme.rules"]
-            .into_iter()
-            .collect::();
-        assert_eq!(
-            render_portable_artifact_path(&data_file, "test data file").unwrap(),
-            "data/nested/acme.rules"
-        );
-
-        let mobile_archive = MobileStaticArchive {
-            target: "ios-simulator".to_owned(),
-            relative_path: [
-                "mobile-static",
-                "ios-simulator",
-                "extensions",
-                "acme",
-                "liboliphaunt_extension_acme.a",
-            ]
-            .into_iter()
-            .collect(),
-        };
-        assert_eq!(
-            mobile_static_archive_manifest_value(&[mobile_archive]).unwrap(),
-            "ios-simulator:mobile-static/ios-simulator/extensions/acme/liboliphaunt_extension_acme.a"
-        );
-
-        let dependency_archive = MobileStaticDependencyArchive {
-            target: "android-arm64-v8a".to_owned(),
-            name: "openssl".to_owned(),
-            relative_path: [
-                "mobile-static",
-                "android-arm64-v8a",
-                "dependencies",
-                "openssl",
-                "libcrypto.a",
-            ]
-            .into_iter()
-            .collect(),
-        };
-        assert_eq!(
-            mobile_static_dependency_archive_manifest_value(&[dependency_archive]).unwrap(),
-            "android-arm64-v8a:openssl:mobile-static/android-arm64-v8a/dependencies/openssl/libcrypto.a"
-        );
-
-        assert!(render_portable_artifact_path(Path::new("../escape"), "test escape").is_err());
-        assert_eq!(
-            render_portable_artifact_path(
-                Path::new("licenses/donn\u{e9}es/\u{8bb8}\u{53ef}\u{8bc1}.txt"),
-                "test Unicode path",
-            )
-            .unwrap(),
-            "licenses/donn\u{e9}es/\u{8bb8}\u{53ef}\u{8bc1}.txt"
-        );
-        for path in [
-            "C:/payload.bin",
-            "payload:name.bin",
-            "CON.txt",
-            "com1.dll",
-            "trailing.",
-            "trailing ",
-            "control-\u{1f}",
-            "forbidden|name",
-        ] {
-            assert!(
-                render_portable_artifact_path(Path::new(path), "test unsafe path").is_err(),
-                "producer accepted non-portable manifest path {path:?}"
-            );
-        }
-    }
-}
diff --git a/tools/native-packaging/src/extension_index.rs b/tools/native-packaging/src/extension_index.rs
deleted file mode 100644
index 431892484..000000000
--- a/tools/native-packaging/src/extension_index.rs
+++ /dev/null
@@ -1,1068 +0,0 @@
-use super::*;
-
-/// Resolve exact prebuilt extension artifacts from local release index files.
-///
-/// The index is only a locator and integrity manifest. Every referenced
-/// artifact is checksum-verified, loaded through the same
-/// `oliphaunt-extension-artifact-v1` parser used by the package consumer, and
-/// resolved transitively by exact dependency names.
-pub fn resolve_prebuilt_extension_artifacts_from_indexes(
-    options: NativeExtensionArtifactIndexOptions,
-) -> Result {
-    if options.target.trim().is_empty() {
-        return Err(Error::InvalidConfig(
-            "extension artifact index target must not be empty".to_owned(),
-        ));
-    }
-    validate_portable_id(&options.target, "extension artifact index target")?;
-    if options.extensions.is_empty() {
-        return Ok(NativeExtensionArtifactIndexResolution {
-            artifacts: Vec::new(),
-            extension_names: Vec::new(),
-        });
-    }
-    if options.indexes.is_empty() {
-        return Err(Error::InvalidConfig(
-            "external extension selection requires at least one --extension-index "
-                .to_owned(),
-        ));
-    }
-
-    validate_extension_artifact_index_trust_options(&options)?;
-    let entries = load_extension_artifact_indexes(
-        &options.indexes,
-        &options.trusted_signing_keys,
-        options.require_signatures,
-    )?;
-    let mut artifacts = Vec::new();
-    let mut extension_names = Vec::new();
-    let mut visiting = BTreeSet::new();
-    let mut visited = BTreeSet::new();
-    let artifact_cache_dir = options.artifact_cache_dir.as_deref();
-    for extension in options.extensions {
-        validate_portable_id(&extension, "extension artifact index selection")?;
-        visit_extension_artifact_index_entry(
-            &extension,
-            &options.target,
-            &entries,
-            artifact_cache_dir,
-            &mut visiting,
-            &mut visited,
-            &mut artifacts,
-            &mut extension_names,
-        )?;
-    }
-    extension_names.sort();
-    extension_names.dedup();
-    Ok(NativeExtensionArtifactIndexResolution {
-        artifacts,
-        extension_names,
-    })
-}
-
-/// List exact external extensions advertised by prebuilt artifact indexes.
-///
-/// This is a discovery path for app/release tooling: it verifies signed indexes
-/// when trust roots are configured, then returns the target-specific metadata
-/// the publisher recorded for each external extension. Artifact bytes are still
-/// verified when a selected extension is resolved for packaging.
-pub fn list_prebuilt_extension_artifact_index_catalog(
-    options: NativeExtensionArtifactIndexOptions,
-) -> Result {
-    if options.target.trim().is_empty() {
-        return Err(Error::InvalidConfig(
-            "extension artifact index target must not be empty".to_owned(),
-        ));
-    }
-    validate_portable_id(&options.target, "extension artifact index target")?;
-    validate_extension_artifact_index_trust_options(&options)?;
-    if options.indexes.is_empty() {
-        return Ok(NativeExtensionArtifactIndexCatalog {
-            extensions: Vec::new(),
-        });
-    }
-    let entries = load_extension_artifact_indexes(
-        &options.indexes,
-        &options.trusted_signing_keys,
-        options.require_signatures,
-    )?;
-    let mut extensions = entries
-        .values()
-        .filter(|entry| entry.target == options.target)
-        .map(|entry| NativeExtensionArtifactIndexCatalogEntry {
-            sql_name: entry.sql_name.clone(),
-            target: entry.target.clone(),
-            creates_extension: entry.creates_extension,
-            native_module_stem: entry.native_module_stem.clone(),
-            dependencies: entry.dependencies.clone(),
-            shared_preload_libraries: entry.shared_preload_libraries.clone(),
-            mobile_prebuilt: entry.native_module_stem.is_none() || entry.mobile_prebuilt,
-            mobile_static_archive_targets: entry.mobile_static_archive_targets.clone(),
-            url: entry.url.clone(),
-        })
-        .collect::>();
-    extensions.sort_by(|left, right| left.sql_name.cmp(&right.sql_name));
-    Ok(NativeExtensionArtifactIndexCatalog { extensions })
-}
-
-/// Create a local exact prebuilt extension artifact index from validated
-/// archive artifacts.
-///
-/// The index producer verifies every artifact through the same schema parser
-/// used by package consumption, rejects built-in public extension names,
-/// computes byte counts and SHA-256 digests, and writes relative paths only.
-pub fn create_prebuilt_extension_artifact_index(
-    options: NativeExtensionArtifactIndexCreateOptions,
-) -> Result {
-    validate_extension_artifact_index_create_options(&options)?;
-    prepare_output_file(&options.output, options.replace_existing)?;
-    let index_parent = options.output.parent().unwrap_or_else(|| Path::new(""));
-    let mut seen = BTreeSet::new();
-    let mut rows = Vec::new();
-    for artifact_path in &options.artifacts {
-        let mut row =
-            create_extension_artifact_index_row(index_parent, &options.target, artifact_path)?;
-        if let Some(base_url) = &options.artifact_base_url {
-            row.url = Some(join_extension_artifact_base_url(base_url, &row.path)?);
-        }
-        if !seen.insert(row.sql_name.clone()) {
-            return Err(Error::InvalidConfig(format!(
-                "extension artifact index cannot contain duplicate extension '{}'",
-                row.sql_name
-            )));
-        }
-        rows.push(row);
-    }
-    rows.sort_by(|left, right| left.sql_name.cmp(&right.sql_name));
-    let text = extension_artifact_index_toml(&rows)?;
-    fs::write(&options.output, text).map_err(|err| {
-        Error::Engine(format!(
-            "write extension artifact index {}: {err}",
-            options.output.display()
-        ))
-    })?;
-    Ok(NativeExtensionArtifactIndex {
-        path: options.output,
-        target: options.target,
-        artifacts: rows,
-    })
-}
-
-/// Sign an exact prebuilt extension artifact index with Ed25519.
-///
-/// The detached signature covers the exact index bytes on disk. The signature
-/// file is a small TOML sidecar at `.sig` unless an explicit path is
-/// supplied.
-pub fn sign_prebuilt_extension_artifact_index(
-    options: NativeExtensionArtifactIndexSigningOptions,
-) -> Result {
-    validate_extension_artifact_index_signing_options(&options)?;
-    let index_bytes = fs::read(&options.index).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "read extension artifact index {} for signing: {err}",
-            options.index.display()
-        ))
-    })?;
-    let signature_path = options
-        .signature_path
-        .clone()
-        .unwrap_or_else(|| default_extension_artifact_index_signature_path(&options.index));
-    prepare_output_file(&signature_path, options.replace_existing)?;
-    let signed = sign_extension_artifact_index_bytes(
-        &options.key_id,
-        &options.signing_key_hex,
-        &index_bytes,
-    )?;
-    let text = extension_artifact_index_signature_toml(&signed);
-    fs::write(&signature_path, text).map_err(|err| {
-        Error::Engine(format!(
-            "write extension artifact index signature {}: {err}",
-            signature_path.display()
-        ))
-    })?;
-    Ok(NativeExtensionArtifactIndexSignature {
-        path: signature_path,
-        index: options.index,
-        key_id: signed.key_id,
-        public_key_hex: signed.public_key_hex,
-        signature_hex: signed.signature_hex,
-    })
-}
-
-fn validate_extension_artifact_index_create_options(
-    options: &NativeExtensionArtifactIndexCreateOptions,
-) -> Result<()> {
-    if options.output.as_os_str().is_empty() {
-        return Err(Error::InvalidConfig(
-            "extension artifact index output path must not be empty".to_owned(),
-        ));
-    }
-    if options.target.trim().is_empty() {
-        return Err(Error::InvalidConfig(
-            "extension artifact index target must not be empty".to_owned(),
-        ));
-    }
-    validate_portable_id(&options.target, "extension artifact index target")?;
-    if options.artifacts.is_empty() {
-        return Err(Error::InvalidConfig(
-            "extension artifact index requires at least one artifact archive".to_owned(),
-        ));
-    }
-    if let Some(base_url) = &options.artifact_base_url {
-        validate_extension_artifact_url(&options.output, base_url)?;
-        if !base_url.starts_with("https://") && !base_url.starts_with("file://") {
-            return Err(Error::InvalidConfig(format!(
-                "extension artifact index base URL '{}' must start with https://",
-                base_url
-            )));
-        }
-    }
-    Ok(())
-}
-
-fn validate_extension_artifact_index_trust_options(
-    options: &NativeExtensionArtifactIndexOptions,
-) -> Result<()> {
-    let mut keys = BTreeMap::new();
-    for key in &options.trusted_signing_keys {
-        validate_portable_id(&key.key_id, "extension artifact index trusted key id")?;
-        let normalized = normalize_hex(&key.public_key_hex);
-        decode_hex_fixed::<32>(
-            "extension artifact index trusted Ed25519 public key",
-            &normalized,
-        )?;
-        if let Some(previous) = keys.insert(key.key_id.clone(), normalized.clone())
-            && previous != normalized
-        {
-            return Err(Error::InvalidConfig(format!(
-                "extension artifact index trusted key '{}' was provided with multiple public keys",
-                key.key_id
-            )));
-        }
-    }
-    if options.require_signatures && options.trusted_signing_keys.is_empty() {
-        return Err(Error::InvalidConfig(
-            "signed extension artifact indexes require at least one trusted publisher key"
-                .to_owned(),
-        ));
-    }
-    Ok(())
-}
-
-fn validate_extension_artifact_index_signing_options(
-    options: &NativeExtensionArtifactIndexSigningOptions,
-) -> Result<()> {
-    if options.index.as_os_str().is_empty() {
-        return Err(Error::InvalidConfig(
-            "extension artifact index signing path must not be empty".to_owned(),
-        ));
-    }
-    if !options.index.is_file() {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index {} must be an existing file before signing",
-            options.index.display()
-        )));
-    }
-    validate_portable_id(&options.key_id, "extension artifact index signing key id")?;
-    decode_hex_fixed::<32>(
-        "extension artifact index Ed25519 signing key",
-        &options.signing_key_hex,
-    )?;
-    Ok(())
-}
-
-fn create_extension_artifact_index_row(
-    index_parent: &Path,
-    target: &str,
-    artifact_path: &Path,
-) -> Result {
-    let metadata = fs::metadata(artifact_path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "stat extension artifact {} for index: {err}",
-            artifact_path.display()
-        ))
-    })?;
-    if !metadata.is_file() {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index can only reference archive files, got {}",
-            artifact_path.display()
-        )));
-    }
-    let prepared =
-        PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-            artifact_path,
-        )])?;
-    let loaded = load_prebuilt_extension_artifact(&prepared.artifacts()[0].root)?;
-    if let Some(native_target) = &loaded.native_target
-        && native_target != target
-    {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact {} declares nativeTarget='{}' but index target is '{}'",
-            artifact_path.display(),
-            native_target,
-            target
-        )));
-    }
-    if Extension::by_sql_name(&loaded.sql_name).is_some() {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index cannot override built-in public extension '{}'",
-            loaded.sql_name
-        )));
-    }
-    let relative = artifact_path.strip_prefix(index_parent).map_err(|_| {
-        Error::InvalidConfig(format!(
-            "extension artifact {} must be inside index directory {} so the index can record a relative path",
-            artifact_path.display(),
-            index_parent.display()
-        ))
-    })?;
-    validate_relative_artifact_path(index_parent, "artifact path", relative)?;
-    let mobile_static_archive_targets =
-        mobile_static_archive_targets(&loaded.mobile_static_archives);
-    Ok(NativeExtensionArtifactIndexArtifact {
-        sql_name: loaded.sql_name,
-        target: target.to_owned(),
-        creates_extension: loaded.creates_extension,
-        native_module_stem: loaded.native_module_stem,
-        dependencies: loaded.dependencies,
-        shared_preload_libraries: loaded.shared_preload_libraries,
-        mobile_prebuilt: loaded.mobile_prebuilt,
-        mobile_static_archive_targets,
-        path: relative.to_path_buf(),
-        url: None,
-        sha256: sha256_file_hex(artifact_path)?,
-        bytes: metadata.len(),
-    })
-}
-
-fn extension_artifact_index_toml(rows: &[NativeExtensionArtifactIndexArtifact]) -> Result {
-    let mut text = format!(
-        "schema = {schema}\npg_major = 18\n",
-        schema = toml_string(EXTENSION_ARTIFACT_INDEX_LAYOUT)
-    );
-    for row in rows {
-        let artifact_path =
-            render_portable_artifact_path(&row.path, "extension artifact index path")?;
-        text.push_str(&format!(
-            "\n[[artifacts]]\nsql_name = {}\ntarget = {}\ncreates_extension = {}\n",
-            toml_string(&row.sql_name),
-            toml_string(&row.target),
-            row.creates_extension,
-        ));
-        if let Some(stem) = &row.native_module_stem {
-            text.push_str(&format!("native_module_stem = {}\n", toml_string(stem)));
-        }
-        text.push_str(&format!(
-            "dependencies = {}\nshared_preload_libraries = {}\nmobile_prebuilt = {}\nmobile_static_archive_targets = {}\npath = {}\n",
-            toml_string_array(&row.dependencies),
-            toml_string_array(&row.shared_preload_libraries),
-            row.mobile_prebuilt,
-            toml_string_array(&row.mobile_static_archive_targets),
-            toml_string(&artifact_path),
-        ));
-        if let Some(url) = &row.url {
-            text.push_str(&format!("url = {}\n", toml_string(url)));
-        }
-        text.push_str(&format!(
-            "sha256 = {}\nbytes = {}\n",
-            toml_string(&row.sha256),
-            row.bytes,
-        ));
-    }
-    Ok(text)
-}
-
-fn toml_string(value: &str) -> String {
-    let mut out = String::from("\"");
-    for ch in value.chars() {
-        match ch {
-            '\\' => out.push_str("\\\\"),
-            '"' => out.push_str("\\\""),
-            '\n' => out.push_str("\\n"),
-            '\r' => out.push_str("\\r"),
-            '\t' => out.push_str("\\t"),
-            ch if ch.is_control() => out.push_str(&format!("\\u{:04x}", ch as u32)),
-            _ => out.push(ch),
-        }
-    }
-    out.push('"');
-    out
-}
-
-fn toml_string_array(values: &[String]) -> String {
-    format!(
-        "[{}]",
-        values
-            .iter()
-            .map(|value| toml_string(value))
-            .collect::>()
-            .join(", ")
-    )
-}
-
-fn validate_extension_artifact_url(index_path: &Path, url: &str) -> Result<()> {
-    if url.trim() != url || url.is_empty() || url.chars().any(char::is_control) {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index {} has invalid artifact URL '{}'",
-            index_path.display(),
-            url
-        )));
-    }
-    if url.starts_with("https://") || url.starts_with("file://") {
-        return Ok(());
-    }
-    Err(Error::InvalidConfig(format!(
-        "extension artifact index {} artifact URL '{}' must start with https:// or file://",
-        index_path.display(),
-        url
-    )))
-}
-
-fn join_extension_artifact_base_url(base_url: &str, relative: &Path) -> Result {
-    let relative = render_portable_artifact_path(relative, "extension artifact URL path")?
-        .split('/')
-        .map(percent_encode_url_path_segment)
-        .collect::>()
-        .join("/");
-    let separator = if base_url.ends_with('/') { "" } else { "/" };
-    Ok(format!("{base_url}{separator}{relative}"))
-}
-
-fn percent_encode_url_path_segment(segment: &str) -> String {
-    let mut out = String::new();
-    for byte in segment.bytes() {
-        match byte {
-            b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
-                out.push(byte as char)
-            }
-            _ => out.push_str(&format!("%{byte:02X}")),
-        }
-    }
-    out
-}
-
-fn load_extension_artifact_indexes(
-    index_paths: &[PathBuf],
-    trusted_signing_keys: &[NativeExtensionArtifactIndexTrustRoot],
-    require_signatures: bool,
-) -> Result> {
-    let mut entries = BTreeMap::new();
-    for index_path in index_paths {
-        let index =
-            load_extension_artifact_index(index_path, trusted_signing_keys, require_signatures)?;
-        for entry in index {
-            let key = (entry.target.clone(), entry.sql_name.clone());
-            if entries.insert(key.clone(), entry).is_some() {
-                return Err(Error::InvalidConfig(format!(
-                    "extension artifact indexes define duplicate artifact for target '{}' extension '{}'",
-                    key.0, key.1
-                )));
-            }
-        }
-    }
-    Ok(entries)
-}
-
-fn load_extension_artifact_index(
-    index_path: &Path,
-    trusted_signing_keys: &[NativeExtensionArtifactIndexTrustRoot],
-    require_signatures: bool,
-) -> Result> {
-    verify_extension_artifact_index_signature_if_required(
-        index_path,
-        trusted_signing_keys,
-        require_signatures,
-    )?;
-    let text = fs::read_to_string(index_path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "read extension artifact index {}: {err}",
-            index_path.display()
-        ))
-    })?;
-    let parsed = toml::from_str::(&text).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "parse extension artifact index {}: {err}",
-            index_path.display()
-        ))
-    })?;
-    if parsed.schema != EXTENSION_ARTIFACT_INDEX_LAYOUT {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index {} has schema='{}', expected '{}'",
-            index_path.display(),
-            parsed.schema,
-            EXTENSION_ARTIFACT_INDEX_LAYOUT
-        )));
-    }
-    if parsed.pg_major != 18 {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index {} targets PostgreSQL {}; Oliphaunt native packages require PostgreSQL 18",
-            index_path.display(),
-            parsed.pg_major
-        )));
-    }
-    if parsed.artifacts.is_empty() {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index {} must contain at least one [[artifacts]] entry",
-            index_path.display()
-        )));
-    }
-    let base = index_path.parent().unwrap_or_else(|| Path::new(""));
-    let mut out = Vec::new();
-    for artifact in parsed.artifacts {
-        validate_portable_id(&artifact.sql_name, "extension artifact index sql_name")?;
-        validate_portable_id(&artifact.target, "extension artifact index target")?;
-        if let Some(stem) = &artifact.native_module_stem {
-            validate_portable_id(stem, "extension artifact index native_module_stem")?;
-        }
-        for dependency in &artifact.dependencies {
-            validate_portable_id(dependency, "extension artifact index dependency")?;
-        }
-        for library in &artifact.shared_preload_libraries {
-            validate_portable_id(library, "extension artifact index shared_preload_libraries")?;
-        }
-        for target in &artifact.mobile_static_archive_targets {
-            validate_portable_id(
-                target,
-                "extension artifact index mobile_static_archive_targets",
-            )?;
-        }
-        validate_sha256_hex(index_path, &artifact.sha256)?;
-        if Extension::by_sql_name(&artifact.sql_name).is_some() {
-            return Err(Error::InvalidConfig(format!(
-                "extension artifact index {} cannot override built-in public extension '{}'",
-                index_path.display(),
-                artifact.sql_name
-            )));
-        }
-        let relative =
-            parse_portable_artifact_path_text(index_path, "artifact path", &artifact.path)?;
-        if let Some(url) = &artifact.url {
-            validate_extension_artifact_url(index_path, url)?;
-        }
-        out.push(ExtensionArtifactIndexEntry {
-            index_path: index_path.to_path_buf(),
-            sql_name: artifact.sql_name,
-            target: artifact.target,
-            creates_extension: artifact.creates_extension,
-            native_module_stem: artifact.native_module_stem,
-            dependencies: sorted_deduped_strings(&artifact.dependencies),
-            shared_preload_libraries: sorted_deduped_strings(&artifact.shared_preload_libraries),
-            mobile_prebuilt: artifact.mobile_prebuilt,
-            mobile_static_archive_targets: sorted_deduped_strings(
-                &artifact.mobile_static_archive_targets,
-            ),
-            relative_path: relative.clone(),
-            path: base.join(relative),
-            url: artifact.url,
-            sha256: artifact.sha256.to_ascii_lowercase(),
-            bytes: artifact.bytes,
-        });
-    }
-    Ok(out)
-}
-
-fn validate_sha256_hex(index_path: &Path, value: &str) -> Result<()> {
-    if value.len() == 64 && value.bytes().all(|byte| byte.is_ascii_hexdigit()) {
-        return Ok(());
-    }
-    Err(Error::InvalidConfig(format!(
-        "extension artifact index {} has invalid sha256 '{}'",
-        index_path.display(),
-        value
-    )))
-}
-
-fn verify_extension_artifact_index_signature_if_required(
-    index_path: &Path,
-    trusted_signing_keys: &[NativeExtensionArtifactIndexTrustRoot],
-    require_signatures: bool,
-) -> Result<()> {
-    if trusted_signing_keys.is_empty() && !require_signatures {
-        return Ok(());
-    }
-    if trusted_signing_keys.is_empty() {
-        return Err(Error::InvalidConfig(
-            "signed extension artifact index verification requires at least one trusted publisher key"
-                .to_owned(),
-        ));
-    }
-    let signature_path = default_extension_artifact_index_signature_path(index_path);
-    let signature_text = fs::read_to_string(&signature_path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "read extension artifact index signature {} for {}: {err}",
-            signature_path.display(),
-            index_path.display()
-        ))
-    })?;
-    let signature = toml::from_str::(&signature_text)
-        .map_err(|err| {
-            Error::InvalidConfig(format!(
-                "parse extension artifact index signature {}: {err}",
-                signature_path.display()
-            ))
-        })?;
-    if signature.schema != EXTENSION_ARTIFACT_INDEX_SIGNATURE_LAYOUT {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index signature {} has schema='{}', expected '{}'",
-            signature_path.display(),
-            signature.schema,
-            EXTENSION_ARTIFACT_INDEX_SIGNATURE_LAYOUT
-        )));
-    }
-    if signature.algorithm != "ed25519" {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index signature {} has algorithm='{}', expected 'ed25519'",
-            signature_path.display(),
-            signature.algorithm
-        )));
-    }
-    validate_portable_id(
-        &signature.key_id,
-        "extension artifact index signature key id",
-    )?;
-    validate_sha256_hex_like(
-        &signature_path,
-        "extension artifact index signature",
-        &signature.signature,
-        128,
-    )?;
-    let trusted = trusted_signing_keys
-        .iter()
-        .find(|key| key.key_id == signature.key_id)
-        .ok_or_else(|| {
-            Error::InvalidConfig(format!(
-                "extension artifact index signature {} uses untrusted key '{}'",
-                signature_path.display(),
-                signature.key_id
-            ))
-        })?;
-    let trusted_public_key = normalize_hex(&trusted.public_key_hex);
-    if let Some(public_key) = &signature.public_key {
-        let signature_public_key = normalize_hex(public_key);
-        decode_hex_fixed::<32>(
-            "extension artifact index signature public key",
-            &signature_public_key,
-        )?;
-        if signature_public_key != trusted_public_key {
-            return Err(Error::InvalidConfig(format!(
-                "extension artifact index signature {} public key does not match trusted key '{}'",
-                signature_path.display(),
-                signature.key_id
-            )));
-        }
-    }
-    let index_bytes = fs::read(index_path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "read extension artifact index {} for signature verification: {err}",
-            index_path.display()
-        ))
-    })?;
-    verify_extension_artifact_index_signature_bytes(
-        &trusted_public_key,
-        &signature.signature,
-        &index_bytes,
-        &signature_path,
-    )
-}
-
-fn default_extension_artifact_index_signature_path(index_path: &Path) -> PathBuf {
-    let mut value = index_path.as_os_str().to_os_string();
-    value.push(".sig");
-    PathBuf::from(value)
-}
-
-fn validate_sha256_hex_like(
-    path: &Path,
-    label: &str,
-    value: &str,
-    expected_len: usize,
-) -> Result<()> {
-    if value.len() == expected_len && value.bytes().all(|byte| byte.is_ascii_hexdigit()) {
-        return Ok(());
-    }
-    Err(Error::InvalidConfig(format!(
-        "{} {} has invalid {} '{}'",
-        label,
-        path.display(),
-        if expected_len == 64 { "sha256" } else { "hex" },
-        value
-    )))
-}
-
-#[derive(Debug)]
-struct SignedExtensionArtifactIndex {
-    key_id: String,
-    public_key_hex: String,
-    signature_hex: String,
-}
-
-#[cfg(feature = "extension-signing")]
-fn sign_extension_artifact_index_bytes(
-    key_id: &str,
-    signing_key_hex: &str,
-    index_bytes: &[u8],
-) -> Result {
-    use ed25519_dalek::{Signer, SigningKey};
-
-    let signing_key_bytes = decode_hex_fixed::<32>(
-        "extension artifact index Ed25519 signing key",
-        signing_key_hex,
-    )?;
-    let signing_key = SigningKey::from_bytes(&signing_key_bytes);
-    let public_key = signing_key.verifying_key().to_bytes();
-    let signature = signing_key.sign(index_bytes).to_bytes();
-    Ok(SignedExtensionArtifactIndex {
-        key_id: key_id.to_owned(),
-        public_key_hex: hex_bytes(&public_key),
-        signature_hex: hex_bytes(&signature),
-    })
-}
-
-#[cfg(not(feature = "extension-signing"))]
-fn sign_extension_artifact_index_bytes(
-    _key_id: &str,
-    _signing_key_hex: &str,
-    _index_bytes: &[u8],
-) -> Result {
-    Err(Error::InvalidConfig(
-        "signing extension artifact indexes requires an oliphaunt-extension-index binary built with the extension-signing feature"
-            .to_owned(),
-    ))
-}
-
-#[cfg(feature = "extension-signing")]
-fn verify_extension_artifact_index_signature_bytes(
-    public_key_hex: &str,
-    signature_hex: &str,
-    index_bytes: &[u8],
-    signature_path: &Path,
-) -> Result<()> {
-    use ed25519_dalek::{Signature, Verifier, VerifyingKey};
-
-    let public_key = decode_hex_fixed::<32>(
-        "extension artifact index trusted Ed25519 public key",
-        public_key_hex,
-    )?;
-    let signature =
-        decode_hex_fixed::<64>("extension artifact index Ed25519 signature", signature_hex)?;
-    let public_key = VerifyingKey::from_bytes(&public_key).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "extension artifact index signature {} has invalid Ed25519 public key: {err}",
-            signature_path.display()
-        ))
-    })?;
-    let signature = Signature::from_bytes(&signature);
-    public_key.verify(index_bytes, &signature).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "extension artifact index signature {} failed verification: {err}",
-            signature_path.display()
-        ))
-    })
-}
-
-#[cfg(not(feature = "extension-signing"))]
-fn verify_extension_artifact_index_signature_bytes(
-    _public_key_hex: &str,
-    _signature_hex: &str,
-    _index_bytes: &[u8],
-    _signature_path: &Path,
-) -> Result<()> {
-    Err(Error::InvalidConfig(
-        "verifying signed extension artifact indexes requires an oliphaunt-resources binary built with the extension-signing feature"
-            .to_owned(),
-    ))
-}
-
-fn extension_artifact_index_signature_toml(signature: &SignedExtensionArtifactIndex) -> String {
-    format!(
-        "schema = {}\nalgorithm = \"ed25519\"\nkey_id = {}\npublic_key = {}\nsignature = {}\n",
-        toml_string(EXTENSION_ARTIFACT_INDEX_SIGNATURE_LAYOUT),
-        toml_string(&signature.key_id),
-        toml_string(&signature.public_key_hex),
-        toml_string(&signature.signature_hex),
-    )
-}
-
-fn normalize_hex(value: &str) -> String {
-    value
-        .bytes()
-        .filter(|byte| !byte.is_ascii_whitespace())
-        .map(|byte| (byte as char).to_ascii_lowercase())
-        .collect()
-}
-
-fn decode_hex_fixed(label: &str, value: &str) -> Result<[u8; N]> {
-    let value = normalize_hex(value);
-    if value.len() != N * 2 {
-        return Err(Error::InvalidConfig(format!(
-            "{label} must be {} hex characters",
-            N * 2
-        )));
-    }
-    let mut out = [0u8; N];
-    let bytes = value.as_bytes();
-    for index in 0..N {
-        let high = hex_nibble(bytes[index * 2])
-            .ok_or_else(|| Error::InvalidConfig(format!("{label} contains a non-hex character")))?;
-        let low = hex_nibble(bytes[index * 2 + 1])
-            .ok_or_else(|| Error::InvalidConfig(format!("{label} contains a non-hex character")))?;
-        out[index] = (high << 4) | low;
-    }
-    Ok(out)
-}
-
-fn hex_nibble(byte: u8) -> Option {
-    match byte {
-        b'0'..=b'9' => Some(byte - b'0'),
-        b'a'..=b'f' => Some(byte - b'a' + 10),
-        b'A'..=b'F' => Some(byte - b'A' + 10),
-        _ => None,
-    }
-}
-
-#[cfg(feature = "extension-signing")]
-pub(super) fn hex_bytes(bytes: &[u8]) -> String {
-    let mut out = String::with_capacity(bytes.len() * 2);
-    for byte in bytes {
-        out.push_str(&format!("{byte:02x}"));
-    }
-    out
-}
-
-#[allow(clippy::too_many_arguments)] // DFS state is intentionally explicit and independently mutable.
-fn visit_extension_artifact_index_entry(
-    sql_name: &str,
-    target: &str,
-    entries: &BTreeMap<(String, String), ExtensionArtifactIndexEntry>,
-    artifact_cache_dir: Option<&Path>,
-    visiting: &mut BTreeSet,
-    visited: &mut BTreeSet,
-    artifacts: &mut Vec,
-    extension_names: &mut Vec,
-) -> Result<()> {
-    if Extension::by_sql_name(sql_name).is_some() {
-        return Ok(());
-    }
-    if visited.contains(sql_name) {
-        return Ok(());
-    }
-    if !visiting.insert(sql_name.to_owned()) {
-        return Err(Error::InvalidConfig(format!(
-            "cyclic extension artifact index dependency involving '{sql_name}'"
-        )));
-    }
-    let entry = entries
-        .get(&(target.to_owned(), sql_name.to_owned()))
-        .ok_or_else(|| missing_extension_artifact_index_entry(sql_name, target, entries))?;
-    let artifact_path = verify_extension_artifact_index_entry(entry, artifact_cache_dir)?;
-    let prepared =
-        PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-            &artifact_path,
-        )])?;
-    let loaded = load_prebuilt_extension_artifact(&prepared.artifacts()[0].root)?;
-    if loaded.sql_name != entry.sql_name {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact index {} maps '{}' to {}, but artifact manifest declares '{}'",
-            entry.index_path.display(),
-            entry.sql_name,
-            entry.path.display(),
-            loaded.sql_name
-        )));
-    }
-    for dependency in loaded.dependencies() {
-        visit_extension_artifact_index_entry(
-            dependency,
-            target,
-            entries,
-            artifact_cache_dir,
-            visiting,
-            visited,
-            artifacts,
-            extension_names,
-        )?;
-    }
-    visiting.remove(sql_name);
-    visited.insert(sql_name.to_owned());
-    artifacts.push(NativePrebuiltExtensionArtifact::new(artifact_path));
-    extension_names.push(sql_name.to_owned());
-    Ok(())
-}
-
-fn missing_extension_artifact_index_entry(
-    sql_name: &str,
-    target: &str,
-    entries: &BTreeMap<(String, String), ExtensionArtifactIndexEntry>,
-) -> Error {
-    let available_targets = entries
-        .keys()
-        .filter_map(|(entry_target, entry_sql_name)| {
-            (entry_sql_name == sql_name).then_some(entry_target.as_str())
-        })
-        .collect::>();
-    let target_hint = if available_targets.is_empty() {
-        "no targets are available".to_owned()
-    } else {
-        format!(
-            "available target(s): {}",
-            available_targets.into_iter().collect::>().join(",")
-        )
-    };
-    Error::InvalidConfig(format!(
-        "extension artifact index has no artifact for extension '{sql_name}' target '{target}' ({target_hint})"
-    ))
-}
-
-fn verify_extension_artifact_index_entry(
-    entry: &ExtensionArtifactIndexEntry,
-    artifact_cache_dir: Option<&Path>,
-) -> Result {
-    if entry.path.is_file() {
-        verify_extension_artifact_index_file(entry, &entry.path)?;
-        return Ok(entry.path.clone());
-    }
-
-    let Some(url) = &entry.url else {
-        return Err(Error::InvalidConfig(format!(
-            "stat extension artifact {} from index {}: file is missing and the index row has no url",
-            entry.path.display(),
-            entry.index_path.display()
-        )));
-    };
-    let Some(cache_dir) = artifact_cache_dir else {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact {} from index {} is URL-backed; pass --extension-cache  so '{}' can be downloaded and verified",
-            entry.sql_name,
-            entry.index_path.display(),
-            url
-        )));
-    };
-    let cache_path = extension_artifact_cache_path(cache_dir, entry)?;
-    if cache_path.is_file() {
-        verify_extension_artifact_index_file(entry, &cache_path)?;
-        return Ok(cache_path);
-    }
-    download_extension_artifact_to_cache(entry, url, &cache_path)?;
-    verify_extension_artifact_index_file(entry, &cache_path)?;
-    Ok(cache_path)
-}
-
-fn verify_extension_artifact_index_file(
-    entry: &ExtensionArtifactIndexEntry,
-    path: &Path,
-) -> Result<()> {
-    let metadata = fs::metadata(path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "stat extension artifact {} from index {}: {err}",
-            path.display(),
-            entry.index_path.display()
-        ))
-    })?;
-    if !metadata.is_file() {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact {} from index {} must be a file",
-            path.display(),
-            entry.index_path.display()
-        )));
-    }
-    if metadata.len() != entry.bytes {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact {} from index {} has {} bytes, expected {}",
-            path.display(),
-            entry.index_path.display(),
-            metadata.len(),
-            entry.bytes
-        )));
-    }
-    let sha256 = sha256_file_hex(path)?;
-    if sha256 != entry.sha256 {
-        return Err(Error::InvalidConfig(format!(
-            "extension artifact {} from index {} has sha256 {}, expected {}",
-            path.display(),
-            entry.index_path.display(),
-            sha256,
-            entry.sha256
-        )));
-    }
-    Ok(())
-}
-
-fn extension_artifact_cache_path(
-    cache_dir: &Path,
-    entry: &ExtensionArtifactIndexEntry,
-) -> Result {
-    validate_relative_artifact_path(cache_dir, "cached artifact path", &entry.relative_path)?;
-    Ok(cache_dir.join(&entry.target).join(&entry.relative_path))
-}
-
-fn download_extension_artifact_to_cache(
-    entry: &ExtensionArtifactIndexEntry,
-    url: &str,
-    cache_path: &Path,
-) -> Result<()> {
-    if let Some(parent) = cache_path.parent() {
-        fs::create_dir_all(parent)
-            .map_err(|err| Error::Engine(format!("create {}: {err}", parent.display())))?;
-    }
-    let tmp_path = cache_path.with_file_name(format!(
-        ".{}.{}.tmp",
-        cache_path
-            .file_name()
-            .and_then(|name| name.to_str())
-            .unwrap_or("artifact"),
-        unique_timestamp_suffix()
-    ));
-    let download_result = download_extension_artifact_url(url, &tmp_path);
-    if let Err(error) = download_result {
-        let _ = fs::remove_file(&tmp_path);
-        return Err(error);
-    }
-    verify_extension_artifact_index_file(entry, &tmp_path)?;
-    fs::rename(&tmp_path, cache_path).map_err(|err| {
-        Error::Engine(format!(
-            "publish downloaded extension artifact {} to cache {}: {err}",
-            url,
-            cache_path.display()
-        ))
-    })?;
-    Ok(())
-}
-
-fn download_extension_artifact_url(url: &str, output: &Path) -> Result<()> {
-    if let Some(path) = url.strip_prefix("file://") {
-        let source = PathBuf::from(path);
-        fs::copy(&source, output).map_err(|err| {
-            Error::InvalidConfig(format!(
-                "copy extension artifact URL {} to {}: {err}",
-                url,
-                output.display()
-            ))
-        })?;
-        return Ok(());
-    }
-    download_extension_artifact_https_url(url, output)
-}
-
-#[cfg(feature = "extension-download")]
-fn download_extension_artifact_https_url(url: &str, output: &Path) -> Result<()> {
-    let response = ureq::get(url).call().map_err(|err| {
-        Error::InvalidConfig(format!("download extension artifact URL {url}: {err}"))
-    })?;
-    let mut reader = response.into_reader();
-    let mut file = File::create(output)
-        .map_err(|err| Error::Engine(format!("create {}: {err}", output.display())))?;
-    io::copy(&mut reader, &mut file).map_err(|err| {
-        Error::Engine(format!(
-            "write downloaded extension artifact URL {} to {}: {err}",
-            url,
-            output.display()
-        ))
-    })?;
-    Ok(())
-}
-
-#[cfg(not(feature = "extension-download"))]
-fn download_extension_artifact_https_url(url: &str, _output: &Path) -> Result<()> {
-    Err(Error::InvalidConfig(format!(
-        "extension artifact URL {url} requires an oliphaunt-resources binary built with the extension-download feature"
-    )))
-}
diff --git a/tools/native-packaging/src/lib.rs b/tools/native-packaging/src/lib.rs
deleted file mode 100644
index 23d3358c0..000000000
--- a/tools/native-packaging/src/lib.rs
+++ /dev/null
@@ -1,5191 +0,0 @@
-use std::collections::{BTreeMap, BTreeSet};
-use std::fs::{self, File};
-use std::io;
-use std::path::{Path, PathBuf};
-use std::time::{SystemTime, UNIX_EPOCH};
-
-use serde::Deserialize;
-use sha2::{Digest, Sha256};
-
-use oliphaunt::__private::packaging::{
-    NativePackagingCatalogProfile, NativePackagingResources as MaterializedNativeResources,
-    NativePackagingRuntime, materialize_native_packaging_resources,
-};
-use oliphaunt::Extension;
-
-/// Error returned by native packaging tooling.
-///
-/// Packaging validation and filesystem failures are intentionally owned by
-/// this unpublished tooling crate rather than constructed through the SDK's
-/// opaque public error type. SDK failures retain their original source.
-#[derive(Debug)]
-pub enum Error {
-    /// A packaging option, manifest, artifact, or command-line value is invalid.
-    InvalidConfig(String),
-    /// A packaging filesystem, archive, or subprocess operation failed.
-    Engine(String),
-    /// The native SDK failed while materializing runtime resources.
-    Oliphaunt(oliphaunt::Error),
-}
-
-impl std::fmt::Display for Error {
-    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::InvalidConfig(message) | Self::Engine(message) => formatter.write_str(message),
-            Self::Oliphaunt(error) => error.fmt(formatter),
-        }
-    }
-}
-
-impl std::error::Error for Error {
-    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-        match self {
-            Self::Oliphaunt(error) => Some(error),
-            Self::InvalidConfig(_) | Self::Engine(_) => None,
-        }
-    }
-}
-
-impl From for Error {
-    fn from(error: oliphaunt::Error) -> Self {
-        Self::Oliphaunt(error)
-    }
-}
-
-/// Result returned by native packaging tooling.
-pub type Result = std::result::Result;
-
-/// Native product whose resources are being assembled.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum NativePackagingMode {
-    /// In-process embedded PostgreSQL.
-    NativeDirect,
-    /// Process-isolated embedded PostgreSQL.
-    NativeBroker,
-    /// Local PostgreSQL server.
-    NativeServer,
-}
-
-impl NativePackagingMode {
-    fn as_manifest_value(self) -> &'static str {
-        match self {
-            Self::NativeDirect => "native-direct",
-            Self::NativeBroker => "native-broker",
-            Self::NativeServer => "native-server",
-        }
-    }
-}
-
-mod catalog;
-mod extension_artifact;
-mod extension_index;
-mod manifest;
-mod package;
-mod static_registry;
-
-pub use extension_artifact::create_prebuilt_extension_artifact;
-use extension_artifact::*;
-pub use extension_index::{
-    create_prebuilt_extension_artifact_index, list_prebuilt_extension_artifact_index_catalog,
-    resolve_prebuilt_extension_artifacts_from_indexes, sign_prebuilt_extension_artifact_index,
-};
-use manifest::*;
-use package::*;
-use static_registry::*;
-
-/// One built-in extension row used by maintainer catalog output.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct BuiltInExtensionCatalogEntry {
-    pub sql_name: String,
-    pub postgres_major: u16,
-    pub creates_extension: bool,
-    pub native_module_stem: Option,
-    pub dependencies: Vec,
-    pub shared_preload_libraries: Vec,
-    pub data_files: Vec,
-}
-
-/// Return the generated built-in extension inventory for maintainer tooling.
-pub fn built_in_extension_catalog() -> Vec {
-    catalog::all()
-        .map(|entry| BuiltInExtensionCatalogEntry {
-            sql_name: entry.sql_name.clone(),
-            postgres_major: entry.postgres_major,
-            creates_extension: entry.creates_extension,
-            native_module_stem: entry.native_module_stem.clone(),
-            dependencies: entry.dependencies.clone(),
-            shared_preload_libraries: entry.shared_preload_libraries.clone(),
-            data_files: entry.runtime_share_data_files.clone(),
-        })
-        .collect()
-}
-
-const RUNTIME_RESOURCES_SCHEMA: &str = "oliphaunt-runtime-resources-v1";
-const EXTENSION_ARTIFACT_LAYOUT: &str = "oliphaunt-extension-artifact-v1";
-const EXTENSION_ARTIFACT_NATIVE_RUNTIME_PRODUCT: &str = "liboliphaunt-native";
-const EXTENSION_ARTIFACT_MANIFEST_KEYS: [&str; 22] = [
-    "packageLayout",
-    "pgMajor",
-    "sqlName",
-    "createsExtension",
-    "nativeModuleStem",
-    "nativeModuleFile",
-    "nativeTarget",
-    "nativeRuntimeProduct",
-    "nativeRuntimeVersion",
-    "dependencies",
-    "dataFiles",
-    "extensionSqlFileNames",
-    "extensionSqlFilePrefixes",
-    "sharedPreloadLibraries",
-    "mobilePrebuilt",
-    "mobileStaticArchives",
-    "mobileStaticDependencyArchives",
-    "staticSymbolPrefix",
-    "staticSymbolAliases",
-    "licenseFiles",
-    "licenseProfile",
-    "files",
-];
-const EXTENSION_ARTIFACT_INDEX_LAYOUT: &str = "oliphaunt-extension-artifact-index-v1";
-const EXTENSION_ARTIFACT_INDEX_SIGNATURE_LAYOUT: &str =
-    "oliphaunt-extension-artifact-index-signature-v1";
-const RUNTIME_FILES_LAYOUT: &str = "postgres-runtime-files-v1";
-const CLUSTER_SEED_LAYOUT: &str = "oliphaunt-cluster-seed-v1";
-const STATIC_REGISTRY_PACKAGE_LAYOUT: &str = "oliphaunt-static-registry-v1";
-const STATIC_REGISTRY_SOURCE_FILE: &str = "oliphaunt_static_registry.c";
-const STATIC_REGISTRY_SOURCE_MANIFEST_VALUE: &str = "static-registry/oliphaunt_static_registry.c";
-// Resource-relative directory under the runtime path `static-registry/archives`.
-const STATIC_REGISTRY_ARCHIVES_DIR: &str = "archives";
-
-fn extension_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
-    file_name == format!("{sql_name}.control")
-        || file_name == format!("{sql_name}.sql")
-        || extension_install_sql_file_belongs(sql_name, file_name)
-        || extension_versioned_sql_file_belongs(sql_name, file_name)
-        || catalog::by_sql_name(sql_name).is_some_and(|extension| {
-            extension
-                .extension_sql_file_names
-                .iter()
-                .any(|name| name == file_name)
-                || (file_name.ends_with(".sql")
-                    && extension
-                        .extension_sql_file_prefixes
-                        .iter()
-                        .any(|prefix| file_name.starts_with(prefix)))
-        })
-}
-
-fn extension_versioned_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
-    file_name
-        .strip_prefix(&format!("{sql_name}--"))
-        .and_then(|value| value.strip_suffix(".sql"))
-        .is_some_and(|version_path| {
-            !version_path.is_empty()
-                && version_path
-                    .bytes()
-                    .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
-        })
-}
-
-fn extension_install_sql_file_belongs(sql_name: &str, file_name: &str) -> bool {
-    let Some(version) = file_name
-        .strip_prefix(&format!("{sql_name}--"))
-        .and_then(|value| value.strip_suffix(".sql"))
-    else {
-        return false;
-    };
-    !version.is_empty()
-        && !version.contains("--")
-        && version.as_bytes()[0].is_ascii_digit()
-        && version
-            .bytes()
-            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'))
-}
-
-/// Options for building platform SDK runtime resources.
-#[derive(Debug, Clone)]
-pub struct NativeRuntimeResourceOptions {
-    /// Directory that receives the generated `oliphaunt/...` resource tree.
-    pub output_dir: PathBuf,
-    /// Native engine mode whose runtime resources should be generated for.
-    pub mode: NativePackagingMode,
-    /// Exact PostgreSQL extensions made available by these runtime resources.
-    pub extensions: Vec,
-    /// Optional runtime data/features made available by these resources.
-    pub runtime_features: Vec,
-    /// Replace an existing `liboliphaunt` resource tree under `output_dir`.
-    pub replace_existing: bool,
-    /// Fail packaging when selected native-module extensions do not have a
-    /// mobile static-registry entry.
-    pub require_mobile_static_registry: bool,
-    /// Native module stems that the platform build has registered for static
-    /// mobile loading.
-    pub mobile_static_module_stems: Vec,
-    /// Exact third-party extension artifacts that are already built for the
-    /// target PostgreSQL runtime.
-    pub prebuilt_extensions: Vec,
-    /// Exact stable `liboliphaunt-native` version selected by the package.
-    ///
-    /// This is required whenever `prebuilt_extensions` is non-empty. Every
-    /// artifact must declare the same version in `nativeRuntimeVersion`.
-    pub native_runtime_version: Option,
-    /// Public artifact target the runtime resources are being packaged for.
-    ///
-    /// This is required for every prebuilt artifact that declares a native
-    /// module, including iOS and Android artifacts whose modules are linked
-    /// through `mobile-static` archives instead of copied as dynamic modules.
-    pub extension_target: Option,
-}
-
-impl NativeRuntimeResourceOptions {
-    /// Create options for native-direct runtime resources.
-    pub fn new(output_dir: impl Into) -> Self {
-        Self {
-            output_dir: output_dir.into(),
-            mode: NativePackagingMode::NativeDirect,
-            extensions: Vec::new(),
-            runtime_features: Vec::new(),
-            replace_existing: false,
-            require_mobile_static_registry: false,
-            mobile_static_module_stems: Vec::new(),
-            prebuilt_extensions: Vec::new(),
-            native_runtime_version: None,
-            extension_target: None,
-        }
-    }
-
-    /// Select the engine mode whose resources should be packaged.
-    pub fn mode(mut self, mode: NativePackagingMode) -> Self {
-        self.mode = mode;
-        self
-    }
-
-    /// Add one exact PostgreSQL extension to the runtime resources.
-    pub fn extension(mut self, extension: Extension) -> Self {
-        self.extensions.push(extension);
-        self
-    }
-
-    /// Add exact PostgreSQL extensions to the runtime resources.
-    pub fn extensions(mut self, extensions: impl IntoIterator) -> Self {
-        self.extensions.extend(extensions);
-        self
-    }
-
-    /// Add one optional runtime feature to the resource bundle.
-    pub fn runtime_feature(mut self, feature: NativeRuntimeFeature) -> Self {
-        self.runtime_features.push(feature);
-        self
-    }
-
-    /// Add optional runtime features to the resource bundle.
-    pub fn runtime_features(
-        mut self,
-        features: impl IntoIterator,
-    ) -> Self {
-        self.runtime_features.extend(features);
-        self
-    }
-
-    /// Allow replacement of an existing generated `liboliphaunt` resource tree.
-    pub fn replace_existing(mut self, replace_existing: bool) -> Self {
-        self.replace_existing = replace_existing;
-        self
-    }
-
-    /// Require every selected native-module extension to be mobile static-ready.
-    pub fn require_mobile_static_registry(mut self, required: bool) -> Self {
-        self.require_mobile_static_registry = required;
-        self
-    }
-
-    /// Declare one native module stem as present in the platform static
-    /// registry.
-    pub fn mobile_static_module_stem(mut self, stem: impl Into) -> Self {
-        self.mobile_static_module_stems.push(stem.into());
-        self
-    }
-
-    /// Declare native module stems as present in the platform static registry.
-    pub fn mobile_static_module_stems(mut self, stems: Vec) -> Self {
-        self.mobile_static_module_stems.extend(stems);
-        self
-    }
-
-    /// Add one exact prebuilt extension artifact directory.
-    pub fn prebuilt_extension(mut self, root: impl Into) -> Self {
-        self.prebuilt_extensions
-            .push(NativePrebuiltExtensionArtifact::new(root));
-        self
-    }
-
-    /// Add exact prebuilt extension artifact directories.
-    pub fn prebuilt_extensions(mut self, roots: impl IntoIterator) -> Self {
-        self.prebuilt_extensions
-            .extend(roots.into_iter().map(NativePrebuiltExtensionArtifact::new));
-        self
-    }
-
-    /// Select the exact stable `liboliphaunt-native` version for prebuilt
-    /// extension compatibility checks.
-    pub fn native_runtime_version(mut self, version: impl Into) -> Self {
-        self.native_runtime_version = Some(version.into());
-        self
-    }
-
-    /// Set the public artifact target these runtime resources are packaged for.
-    pub fn extension_target(mut self, target: impl Into) -> Self {
-        self.extension_target = Some(target.into());
-        self
-    }
-}
-
-/// Optional runtime data/features selected independently from PostgreSQL
-/// extensions.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum NativeRuntimeFeature {
-    /// ICU locale/collation data under `share/icu`.
-    Icu,
-}
-
-impl NativeRuntimeFeature {
-    /// Stable manifest/CLI spelling for this runtime feature.
-    pub fn as_str(self) -> &'static str {
-        match self {
-            Self::Icu => "icu",
-        }
-    }
-}
-
-/// One exact third-party extension artifact that has already been built.
-///
-/// The artifact may be an unpacked directory, `.tar`, `.tar.gz` (or `.tgz`),
-/// or `.tar.zst`. Its root must contain `manifest.properties` with
-/// `packageLayout=oliphaunt-extension-artifact-v1` and a `files/` tree whose
-/// paths mirror PostgreSQL runtime paths, such as
-/// `files/share/postgresql/extension/.control`.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativePrebuiltExtensionArtifact {
-    /// Artifact root directory or archive file.
-    pub root: PathBuf,
-}
-
-impl NativePrebuiltExtensionArtifact {
-    /// Create a prebuilt extension artifact reference.
-    pub fn new(root: impl Into) -> Self {
-        Self { root: root.into() }
-    }
-}
-
-/// One target-specific mobile static archive for an exact prebuilt extension.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionMobileStaticArchive {
-    /// Mobile target key, for example `ios-simulator`, `ios-device`, or
-    /// `arm64-v8a`.
-    pub target: String,
-    /// Already-built static archive file for the extension module.
-    pub archive: PathBuf,
-}
-
-impl NativeExtensionMobileStaticArchive {
-    /// Create a mobile static archive reference.
-    pub fn new(target: impl Into, archive: impl Into) -> Self {
-        Self {
-            target: target.into(),
-            archive: archive.into(),
-        }
-    }
-}
-
-/// One target-specific dependency archive needed by mobile static extension
-/// archives in an exact prebuilt extension artifact.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionMobileStaticDependencyArchive {
-    /// Mobile target key, for example `ios-simulator`, `ios-device`, or
-    /// `arm64-v8a`.
-    pub target: String,
-    /// Portable dependency name, for example `openssl`, `geos`, or `proj`.
-    pub name: String,
-    /// Already-built static archive file for this dependency.
-    pub archive: PathBuf,
-}
-
-impl NativeExtensionMobileStaticDependencyArchive {
-    /// Create a mobile static dependency archive reference.
-    pub fn new(
-        target: impl Into,
-        name: impl Into,
-        archive: impl Into,
-    ) -> Self {
-        Self {
-            target: target.into(),
-            name: name.into(),
-            archive: archive.into(),
-        }
-    }
-}
-
-/// One mobile static-registry symbol alias for an exact prebuilt extension.
-///
-/// `sql_symbol` is the C symbol name referenced by extension SQL. `linked_symbol`
-/// is the actual C identifier exported by the carried mobile static archive.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionStaticSymbolAlias {
-    /// SQL-visible C symbol name.
-    pub sql_symbol: String,
-    /// Link-time C identifier in the mobile static archive.
-    pub linked_symbol: String,
-}
-
-impl NativeExtensionStaticSymbolAlias {
-    /// Create a static-registry symbol alias.
-    pub fn new(sql_symbol: impl Into, linked_symbol: impl Into) -> Self {
-        Self {
-            sql_symbol: sql_symbol.into(),
-            linked_symbol: linked_symbol.into(),
-        }
-    }
-}
-
-/// Output format for an exact prebuilt extension artifact.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum NativeExtensionArtifactFormat {
-    /// Write an unpacked artifact directory.
-    Directory,
-    /// Write an uncompressed tar archive.
-    Tar,
-    /// Write a gzip-compressed tar archive.
-    TarGz,
-    /// Write a zstd-compressed tar archive.
-    TarZst,
-}
-
-/// Legal payload profile carried by one native prebuilt extension artifact.
-///
-/// The profile determines the exact release-notice leaves at the artifact
-/// root. External artifacts additionally declare their exact PostgreSQL-
-/// relative upstream license paths through
-/// [`NativeExtensionArtifactLegalContract::license_file`].
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum NativeExtensionArtifactLicenseProfile {
-    /// Contrib payload carrying PostgreSQL notices.
-    ContribNative,
-    /// Contrib payload carrying PostgreSQL and embedded OpenSSL notices.
-    ContribNativeOpenSsl,
-    /// Independently versioned external-extension payload.
-    ExternalNative,
-}
-
-impl NativeExtensionArtifactLicenseProfile {
-    /// Stable `manifest.properties` spelling.
-    pub fn as_str(self) -> &'static str {
-        match self {
-            Self::ContribNative => "contrib-native",
-            Self::ContribNativeOpenSsl => "contrib-native-openssl",
-            Self::ExternalNative => "external-native",
-        }
-    }
-
-    /// Parse the stable `manifest.properties` spelling.
-    pub fn parse(value: &str) -> Result {
-        match value {
-            "contrib-native" => Ok(Self::ContribNative),
-            "contrib-native-openssl" => Ok(Self::ContribNativeOpenSsl),
-            "external-native" => Ok(Self::ExternalNative),
-            _ => Err(Error::InvalidConfig(format!(
-                "unsupported native extension artifact license profile '{value}'; expected contrib-native, contrib-native-openssl, or external-native"
-            ))),
-        }
-    }
-}
-
-/// Exact legal source contract for a produced extension artifact.
-///
-/// `source_root` contains the profile's root notice files and every declared
-/// PostgreSQL-relative upstream license file. For example, an external file
-/// declared as `share/licenses/acme/LICENSE` is read from that path beneath
-/// `source_root` and written beneath the artifact's `files/` tree.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionArtifactLegalContract {
-    /// Payload-specific release-notice profile.
-    pub profile: NativeExtensionArtifactLicenseProfile,
-    /// Directory containing the exact legal source leaves.
-    pub source_root: PathBuf,
-    /// Sorted by the producer into exact PostgreSQL-relative license paths.
-    pub license_files: Vec,
-}
-
-impl NativeExtensionArtifactLegalContract {
-    /// Create a legal contract with no external upstream license files.
-    pub fn new(
-        profile: NativeExtensionArtifactLicenseProfile,
-        source_root: impl Into,
-    ) -> Self {
-        Self {
-            profile,
-            source_root: source_root.into(),
-            license_files: Vec::new(),
-        }
-    }
-
-    /// Add one exact PostgreSQL-relative upstream license file.
-    pub fn license_file(mut self, path: impl Into) -> Self {
-        self.license_files.push(path.into());
-        self
-    }
-
-    /// Add exact PostgreSQL-relative upstream license files.
-    pub fn license_files(mut self, paths: impl IntoIterator) -> Self {
-        self.license_files.extend(paths);
-        self
-    }
-}
-
-/// Options for creating one exact prebuilt extension artifact from built
-/// PostgreSQL runtime files.
-#[derive(Debug, Clone)]
-pub struct NativeExtensionArtifactOptions {
-    /// Artifact directory or archive path to write.
-    pub output: PathBuf,
-    /// Built PostgreSQL runtime root containing `share/postgresql` and
-    /// `lib/postgresql`.
-    pub runtime_files: PathBuf,
-    /// Exact SQL extension name used by `CREATE EXTENSION`.
-    pub sql_name: String,
-    /// Exact stable `liboliphaunt-native` version this artifact was built for.
-    pub native_runtime_version: String,
-    /// Whether the artifact represents a SQL extension with control/SQL files.
-    pub creates_extension: bool,
-    /// Native module stem used by PostgreSQL extension SQL.
-    pub native_module_stem: Option,
-    /// Target-specific native module filename under `lib/postgresql`.
-    pub native_module_file: Option,
-    /// Public target id that produced the dynamic native module payload.
-    pub native_target: Option,
-    /// Directory containing the native-direct module built for the same
-    /// desktop target. Desktop artifacts carry this module under
-    /// `files/lib/modules` alongside the server module under
-    /// `files/lib/postgresql`.
-    pub embedded_module_root: Option,
-    /// Exact extension dependencies.
-    pub dependencies: Vec,
-    /// Additional files under `share/postgresql` required by the extension.
-    pub data_files: Vec,
-    /// Exact ancillary SQL basenames under `share/postgresql/extension` that
-    /// do not follow the extension's canonical install/update naming.
-    pub extension_sql_file_names: Vec,
-    /// Exact ancillary SQL basename prefixes under
-    /// `share/postgresql/extension`.
-    pub extension_sql_file_prefixes: Vec,
-    /// PostgreSQL shared-preload libraries required when this extension is
-    /// selected.
-    pub shared_preload_libraries: Vec,
-    /// Whether matching iOS/Android static artifacts are available.
-    pub mobile_prebuilt: bool,
-    /// Target-specific mobile static archives carried by this artifact.
-    pub mobile_static_archives: Vec,
-    /// Target-specific static dependency archives needed by carried mobile
-    /// extension archives.
-    pub mobile_static_dependency_archives: Vec,
-    /// Static registry C symbol prefix for mobile artifacts.
-    pub static_symbol_prefix: Option,
-    /// SQL-visible to link-time C symbol aliases for mobile static artifacts.
-    pub static_symbol_aliases: Vec,
-    /// Exact legal profile, source root, and upstream-license leaf inventory.
-    ///
-    /// Artifact creation fails closed when this is absent.
-    pub legal_contract: Option,
-    /// Artifact output format.
-    pub format: NativeExtensionArtifactFormat,
-    /// Replace an existing output path.
-    pub replace_existing: bool,
-}
-
-impl NativeExtensionArtifactOptions {
-    /// Create artifact options for one exact SQL extension.
-    pub fn new(
-        output: impl Into,
-        runtime_files: impl Into,
-        sql_name: impl Into,
-        native_runtime_version: impl Into,
-    ) -> Self {
-        Self {
-            output: output.into(),
-            runtime_files: runtime_files.into(),
-            sql_name: sql_name.into(),
-            native_runtime_version: native_runtime_version.into(),
-            creates_extension: true,
-            native_module_stem: None,
-            native_module_file: None,
-            native_target: None,
-            embedded_module_root: None,
-            dependencies: Vec::new(),
-            data_files: Vec::new(),
-            extension_sql_file_names: Vec::new(),
-            extension_sql_file_prefixes: Vec::new(),
-            shared_preload_libraries: Vec::new(),
-            mobile_prebuilt: false,
-            mobile_static_archives: Vec::new(),
-            mobile_static_dependency_archives: Vec::new(),
-            static_symbol_prefix: None,
-            static_symbol_aliases: Vec::new(),
-            legal_contract: None,
-            format: NativeExtensionArtifactFormat::Directory,
-            replace_existing: false,
-        }
-    }
-
-    /// Set whether control/SQL extension files are required.
-    pub fn creates_extension(mut self, creates_extension: bool) -> Self {
-        self.creates_extension = creates_extension;
-        self
-    }
-
-    /// Set the native module stem.
-    pub fn native_module_stem(mut self, stem: impl Into) -> Self {
-        self.native_module_stem = Some(stem.into());
-        self
-    }
-
-    /// Set the target-specific native module filename under `lib/postgresql`.
-    pub fn native_module_file(mut self, file_name: impl Into) -> Self {
-        self.native_module_file = Some(file_name.into());
-        self
-    }
-
-    /// Set the public target id that produced the dynamic native module.
-    pub fn native_target(mut self, target: impl Into) -> Self {
-        self.native_target = Some(target.into());
-        self
-    }
-
-    /// Set the directory containing the native-direct desktop module.
-    pub fn embedded_module_root(mut self, root: impl Into) -> Self {
-        self.embedded_module_root = Some(root.into());
-        self
-    }
-
-    /// Add one exact dependency.
-    pub fn dependency(mut self, dependency: impl Into) -> Self {
-        self.dependencies.push(dependency.into());
-        self
-    }
-
-    /// Add exact dependencies.
-    pub fn dependencies(mut self, dependencies: impl IntoIterator) -> Self {
-        self.dependencies.extend(dependencies);
-        self
-    }
-
-    /// Add one data file path relative to `share/postgresql`.
-    pub fn data_file(mut self, data_file: impl Into) -> Self {
-        self.data_files.push(data_file.into());
-        self
-    }
-
-    /// Add data file paths relative to `share/postgresql`.
-    pub fn data_files(mut self, data_files: impl IntoIterator) -> Self {
-        self.data_files.extend(data_files);
-        self
-    }
-
-    /// Add one exact ancillary SQL basename.
-    pub fn extension_sql_file_name(mut self, file_name: impl Into) -> Self {
-        self.extension_sql_file_names.push(file_name.into());
-        self
-    }
-
-    /// Add exact ancillary SQL basenames.
-    pub fn extension_sql_file_names(
-        mut self,
-        file_names: impl IntoIterator,
-    ) -> Self {
-        self.extension_sql_file_names.extend(file_names);
-        self
-    }
-
-    /// Add one exact ancillary SQL basename prefix.
-    pub fn extension_sql_file_prefix(mut self, prefix: impl Into) -> Self {
-        self.extension_sql_file_prefixes.push(prefix.into());
-        self
-    }
-
-    /// Add exact ancillary SQL basename prefixes.
-    pub fn extension_sql_file_prefixes(
-        mut self,
-        prefixes: impl IntoIterator,
-    ) -> Self {
-        self.extension_sql_file_prefixes.extend(prefixes);
-        self
-    }
-
-    /// Add one required shared-preload library.
-    pub fn shared_preload_library(mut self, library: impl Into) -> Self {
-        self.shared_preload_libraries.push(library.into());
-        self
-    }
-
-    /// Add required shared-preload libraries.
-    pub fn shared_preload_libraries(mut self, libraries: impl IntoIterator) -> Self {
-        self.shared_preload_libraries.extend(libraries);
-        self
-    }
-
-    /// Mark whether matching mobile static artifacts exist.
-    pub fn mobile_prebuilt(mut self, mobile_prebuilt: bool) -> Self {
-        self.mobile_prebuilt = mobile_prebuilt;
-        self
-    }
-
-    /// Add one target-specific mobile static archive.
-    pub fn mobile_static_archive(
-        mut self,
-        target: impl Into,
-        archive: impl Into,
-    ) -> Self {
-        self.mobile_static_archives
-            .push(NativeExtensionMobileStaticArchive::new(target, archive));
-        self.mobile_prebuilt = true;
-        self
-    }
-
-    /// Add target-specific mobile static archives.
-    pub fn mobile_static_archives(
-        mut self,
-        archives: impl IntoIterator,
-    ) -> Self {
-        let mut any = false;
-        for archive in archives {
-            any = true;
-            self.mobile_static_archives.push(archive);
-        }
-        if any {
-            self.mobile_prebuilt = true;
-        }
-        self
-    }
-
-    /// Add one target-specific mobile static dependency archive.
-    pub fn mobile_static_dependency_archive(
-        mut self,
-        target: impl Into,
-        name: impl Into,
-        archive: impl Into,
-    ) -> Self {
-        self.mobile_static_dependency_archives.push(
-            NativeExtensionMobileStaticDependencyArchive::new(target, name, archive),
-        );
-        self
-    }
-
-    /// Add target-specific mobile static dependency archives.
-    pub fn mobile_static_dependency_archives(
-        mut self,
-        archives: impl IntoIterator,
-    ) -> Self {
-        self.mobile_static_dependency_archives.extend(archives);
-        self
-    }
-
-    /// Set the generated mobile static registry symbol prefix.
-    pub fn static_symbol_prefix(mut self, prefix: impl Into) -> Self {
-        self.static_symbol_prefix = Some(prefix.into());
-        self
-    }
-
-    /// Add one static-registry symbol alias.
-    pub fn static_symbol_alias(
-        mut self,
-        sql_symbol: impl Into,
-        linked_symbol: impl Into,
-    ) -> Self {
-        self.static_symbol_aliases
-            .push(NativeExtensionStaticSymbolAlias::new(
-                sql_symbol,
-                linked_symbol,
-            ));
-        self
-    }
-
-    /// Add static-registry symbol aliases.
-    pub fn static_symbol_aliases(
-        mut self,
-        aliases: impl IntoIterator,
-    ) -> Self {
-        self.static_symbol_aliases.extend(aliases);
-        self
-    }
-
-    /// Set the exact legal payload contract for this artifact.
-    pub fn legal_contract(mut self, contract: NativeExtensionArtifactLegalContract) -> Self {
-        self.legal_contract = Some(contract);
-        self
-    }
-
-    /// Select the artifact output format.
-    pub fn format(mut self, format: NativeExtensionArtifactFormat) -> Self {
-        self.format = format;
-        self
-    }
-
-    /// Allow replacement of an existing artifact path.
-    pub fn replace_existing(mut self, replace_existing: bool) -> Self {
-        self.replace_existing = replace_existing;
-        self
-    }
-}
-
-/// Prebuilt extension artifact created by the Rust SDK tooling.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionArtifact {
-    /// Artifact directory or archive path.
-    pub path: PathBuf,
-    /// Manifest path when the artifact is an unpacked directory.
-    pub manifest_path: Option,
-    /// Exact SQL extension name.
-    pub sql_name: String,
-    /// Exact legal payload profile recorded in the manifest.
-    pub license_profile: NativeExtensionArtifactLicenseProfile,
-    /// Exact PostgreSQL-relative upstream license paths carried under `files/`.
-    pub license_files: Vec,
-    /// Artifact output format.
-    pub format: NativeExtensionArtifactFormat,
-}
-
-/// Options for resolving exact prebuilt extension artifacts from release
-/// indexes.
-#[derive(Debug, Clone)]
-pub struct NativeExtensionArtifactIndexOptions {
-    /// Index TOML files to read. Later indexes may not redefine the same
-    /// `(target, sql_name)` pair.
-    pub indexes: Vec,
-    /// Target artifact key, such as `aarch64-apple-darwin`.
-    pub target: String,
-    /// Exact SQL extension names to resolve from indexes. Dependencies are
-    /// resolved transitively.
-    pub extensions: Vec,
-    /// Optional cache directory for URL-backed artifact rows. Local sidecar
-    /// artifacts next to an index are preferred; missing URL-backed artifacts
-    /// are downloaded here and then verified before use.
-    pub artifact_cache_dir: Option,
-    /// Trusted publisher keys for signed artifact indexes.
-    pub trusted_signing_keys: Vec,
-    /// Require every artifact index to have a valid sidecar signature.
-    pub require_signatures: bool,
-}
-
-impl NativeExtensionArtifactIndexOptions {
-    /// Create artifact-index resolution options for one target.
-    pub fn new(target: impl Into) -> Self {
-        Self {
-            indexes: Vec::new(),
-            target: target.into(),
-            extensions: Vec::new(),
-            artifact_cache_dir: None,
-            trusted_signing_keys: Vec::new(),
-            require_signatures: false,
-        }
-    }
-
-    /// Add one index file.
-    pub fn index(mut self, index: impl Into) -> Self {
-        self.indexes.push(index.into());
-        self
-    }
-
-    /// Add index files.
-    pub fn indexes(mut self, indexes: impl IntoIterator) -> Self {
-        self.indexes.extend(indexes);
-        self
-    }
-
-    /// Select one exact SQL extension name.
-    pub fn extension(mut self, extension: impl Into) -> Self {
-        self.extensions.push(extension.into());
-        self
-    }
-
-    /// Select exact SQL extension names.
-    pub fn extensions(mut self, extensions: impl IntoIterator) -> Self {
-        self.extensions.extend(extensions);
-        self
-    }
-
-    /// Cache directory for URL-backed artifact index rows.
-    pub fn artifact_cache_dir(mut self, cache_dir: impl Into) -> Self {
-        self.artifact_cache_dir = Some(cache_dir.into());
-        self
-    }
-
-    /// Set an optional cache directory for URL-backed artifact index rows.
-    pub fn maybe_artifact_cache_dir(mut self, cache_dir: Option) -> Self {
-        self.artifact_cache_dir = cache_dir;
-        self
-    }
-
-    /// Trust one Ed25519 publisher key for artifact index signatures.
-    pub fn trusted_signing_key(mut self, key: NativeExtensionArtifactIndexTrustRoot) -> Self {
-        self.trusted_signing_keys.push(key);
-        self
-    }
-
-    /// Trust Ed25519 publisher keys for artifact index signatures.
-    pub fn trusted_signing_keys(
-        mut self,
-        keys: impl IntoIterator,
-    ) -> Self {
-        self.trusted_signing_keys.extend(keys);
-        self
-    }
-
-    /// Require signed artifact indexes.
-    pub fn require_signatures(mut self, required: bool) -> Self {
-        self.require_signatures = required;
-        self
-    }
-}
-
-/// Resolution result for exact extension artifact indexes.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionArtifactIndexResolution {
-    /// Verified artifact paths in dependency order.
-    pub artifacts: Vec,
-    /// Exact external extension names resolved from indexes.
-    pub extension_names: Vec,
-}
-
-/// Catalog entries advertised by exact prebuilt extension artifact indexes.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionArtifactIndexCatalog {
-    /// Exact external extension rows available for the selected target.
-    pub extensions: Vec,
-}
-
-/// One exact external extension advertised by an artifact index.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionArtifactIndexCatalogEntry {
-    /// Exact SQL extension name.
-    pub sql_name: String,
-    /// Target artifact key.
-    pub target: String,
-    /// Whether `CREATE EXTENSION` control/SQL files are present.
-    pub creates_extension: bool,
-    /// Native module stem required by the extension, if any.
-    pub native_module_stem: Option,
-    /// Exact extension dependencies advertised by the index.
-    pub dependencies: Vec,
-    /// Required `shared_preload_libraries` entries advertised by the index.
-    pub shared_preload_libraries: Vec,
-    /// Whether iOS/Android app bundles can consume this artifact without
-    /// building extension source.
-    pub mobile_prebuilt: bool,
-    /// Mobile targets whose static archives are carried by the artifact.
-    pub mobile_static_archive_targets: Vec,
-    /// Optional artifact URL advertised by the index.
-    pub url: Option,
-}
-
-/// Options for creating an exact prebuilt extension artifact index.
-#[derive(Debug, Clone)]
-pub struct NativeExtensionArtifactIndexCreateOptions {
-    /// Index TOML path to write.
-    pub output: PathBuf,
-    /// Target artifact key shared by every indexed artifact.
-    pub target: String,
-    /// Archive artifact files to index.
-    pub artifacts: Vec,
-    /// Optional HTTPS base URL used to publish each relative artifact path.
-    pub artifact_base_url: Option,
-    /// Replace an existing output path.
-    pub replace_existing: bool,
-}
-
-/// Trusted Ed25519 publisher key for exact extension artifact indexes.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionArtifactIndexTrustRoot {
-    /// Stable publisher key identifier.
-    pub key_id: String,
-    /// Hex-encoded 32-byte Ed25519 public key.
-    pub public_key_hex: String,
-}
-
-impl NativeExtensionArtifactIndexTrustRoot {
-    /// Create a trusted artifact-index publisher key.
-    pub fn new(key_id: impl Into, public_key_hex: impl Into) -> Self {
-        Self {
-            key_id: key_id.into(),
-            public_key_hex: public_key_hex.into(),
-        }
-    }
-}
-
-/// Options for signing one exact extension artifact index.
-#[derive(Debug, Clone)]
-pub struct NativeExtensionArtifactIndexSigningOptions {
-    /// Index TOML path whose exact bytes will be signed.
-    pub index: PathBuf,
-    /// Stable publisher key identifier.
-    pub key_id: String,
-    /// Hex-encoded 32-byte Ed25519 signing key.
-    pub signing_key_hex: String,
-    /// Detached signature path. Defaults to `.sig`.
-    pub signature_path: Option,
-    /// Replace an existing signature file.
-    pub replace_existing: bool,
-}
-
-impl NativeExtensionArtifactIndexSigningOptions {
-    /// Create signing options for one artifact index.
-    pub fn new(
-        index: impl Into,
-        key_id: impl Into,
-        signing_key_hex: impl Into,
-    ) -> Self {
-        Self {
-            index: index.into(),
-            key_id: key_id.into(),
-            signing_key_hex: signing_key_hex.into(),
-            signature_path: None,
-            replace_existing: false,
-        }
-    }
-
-    /// Write the detached signature to a specific path.
-    pub fn signature_path(mut self, path: impl Into) -> Self {
-        self.signature_path = Some(path.into());
-        self
-    }
-
-    /// Set an optional detached signature path.
-    pub fn maybe_signature_path(mut self, path: Option) -> Self {
-        self.signature_path = path;
-        self
-    }
-
-    /// Allow replacement of an existing detached signature file.
-    pub fn replace_existing(mut self, replace_existing: bool) -> Self {
-        self.replace_existing = replace_existing;
-        self
-    }
-}
-
-/// Detached signature created for one exact extension artifact index.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionArtifactIndexSignature {
-    /// Signature sidecar path.
-    pub path: PathBuf,
-    /// Signed artifact index path.
-    pub index: PathBuf,
-    /// Stable publisher key identifier.
-    pub key_id: String,
-    /// Hex-encoded Ed25519 public key derived from the signing key.
-    pub public_key_hex: String,
-    /// Hex-encoded Ed25519 signature.
-    pub signature_hex: String,
-}
-
-impl NativeExtensionArtifactIndexCreateOptions {
-    /// Create options for one target artifact index.
-    pub fn new(output: impl Into, target: impl Into) -> Self {
-        Self {
-            output: output.into(),
-            target: target.into(),
-            artifacts: Vec::new(),
-            artifact_base_url: None,
-            replace_existing: false,
-        }
-    }
-
-    /// Add one artifact archive file.
-    pub fn artifact(mut self, artifact: impl Into) -> Self {
-        self.artifacts.push(artifact.into());
-        self
-    }
-
-    /// Add artifact archive files.
-    pub fn artifacts(mut self, artifacts: impl IntoIterator) -> Self {
-        self.artifacts.extend(artifacts);
-        self
-    }
-
-    /// Set an HTTPS base URL for artifact rows in the generated index.
-    pub fn artifact_base_url(mut self, base_url: impl Into) -> Self {
-        self.artifact_base_url = Some(base_url.into());
-        self
-    }
-
-    /// Set an optional base URL for artifact rows in the generated index.
-    pub fn maybe_artifact_base_url(mut self, base_url: Option) -> Self {
-        self.artifact_base_url = base_url;
-        self
-    }
-
-    /// Allow replacement of an existing index path.
-    pub fn replace_existing(mut self, replace_existing: bool) -> Self {
-        self.replace_existing = replace_existing;
-        self
-    }
-}
-
-/// Exact prebuilt extension artifact index created by the Rust SDK tooling.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionArtifactIndex {
-    /// Index TOML path.
-    pub path: PathBuf,
-    /// Target artifact key.
-    pub target: String,
-    /// Indexed artifacts.
-    pub artifacts: Vec,
-}
-
-/// One artifact row in an exact prebuilt extension artifact index.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeExtensionArtifactIndexArtifact {
-    /// Exact SQL extension name.
-    pub sql_name: String,
-    /// Target artifact key.
-    pub target: String,
-    /// Whether `CREATE EXTENSION` control/SQL files are present.
-    pub creates_extension: bool,
-    /// Native module stem required by the extension, if any.
-    pub native_module_stem: Option,
-    /// Exact extension dependencies.
-    pub dependencies: Vec,
-    /// Required `shared_preload_libraries` entries.
-    pub shared_preload_libraries: Vec,
-    /// Whether iOS/Android app bundles can consume this artifact without
-    /// building extension source.
-    pub mobile_prebuilt: bool,
-    /// Mobile targets whose static archives are carried by the artifact.
-    pub mobile_static_archive_targets: Vec,
-    /// Relative artifact path recorded in the index.
-    pub path: PathBuf,
-    /// Optional HTTPS artifact URL recorded in the index.
-    pub url: Option,
-    /// Hex-encoded SHA-256 digest of the artifact archive file.
-    pub sha256: String,
-    /// Artifact archive byte length.
-    pub bytes: u64,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-struct ExtensionArtifactIndexEntry {
-    index_path: PathBuf,
-    sql_name: String,
-    target: String,
-    creates_extension: bool,
-    native_module_stem: Option,
-    dependencies: Vec,
-    shared_preload_libraries: Vec,
-    mobile_prebuilt: bool,
-    mobile_static_archive_targets: Vec,
-    relative_path: PathBuf,
-    path: PathBuf,
-    url: Option,
-    sha256: String,
-    bytes: u64,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct ExtensionArtifactIndexToml {
-    schema: String,
-    pg_major: u16,
-    artifacts: Vec,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct ExtensionArtifactIndexEntryToml {
-    sql_name: String,
-    target: String,
-    #[serde(default = "default_true")]
-    creates_extension: bool,
-    native_module_stem: Option,
-    #[serde(default)]
-    dependencies: Vec,
-    #[serde(default)]
-    shared_preload_libraries: Vec,
-    #[serde(default)]
-    mobile_prebuilt: bool,
-    #[serde(default)]
-    mobile_static_archive_targets: Vec,
-    path: String,
-    url: Option,
-    sha256: String,
-    bytes: u64,
-}
-
-#[derive(Debug, Deserialize)]
-#[serde(deny_unknown_fields)]
-struct ExtensionArtifactIndexSignatureToml {
-    schema: String,
-    algorithm: String,
-    key_id: String,
-    public_key: Option,
-    signature: String,
-}
-
-fn default_true() -> bool {
-    true
-}
-
-/// Mobile static-registry readiness of generated runtime resources.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum MobileStaticRegistryState {
-    /// The selected extensions do not require native modules.
-    NotRequired,
-    /// Every selected native-module extension has a mobile static-registry row.
-    Complete,
-    /// At least one selected native-module extension still needs registry work.
-    Pending,
-}
-
-impl MobileStaticRegistryState {
-    fn as_manifest_value(self) -> &'static str {
-        match self {
-            Self::NotRequired => "not-required",
-            Self::Complete => "complete",
-            Self::Pending => "pending",
-        }
-    }
-}
-
-/// Mobile static-registry metadata recorded in generated runtime resources.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct MobileStaticRegistryMetadata {
-    /// Runtime-resource readiness state.
-    pub state: MobileStaticRegistryState,
-    /// Selected SQL extension names that are registered for mobile static use.
-    pub registered_extensions: Vec,
-    /// Selected SQL extension names that still need mobile static registry rows.
-    pub pending_extensions: Vec,
-    /// Native module stems required by the selected extensions.
-    pub native_module_stems: Vec,
-}
-
-/// Size report for generated runtime resources.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeRuntimeResourceSizeReport {
-    /// Stable TSV report path under the resource root.
-    pub path: PathBuf,
-    /// Bytes in runtime, cluster-seed, and static-registry resource trees. This
-    /// intentionally excludes the report file itself to avoid circular output.
-    pub package_bytes: u64,
-    /// Bytes in `runtime/files`.
-    pub runtime_bytes: u64,
-    /// Bytes in `cluster-seed/files`.
-    pub cluster_seed_bytes: u64,
-    /// Bytes in `static-registry`.
-    pub static_registry_bytes: u64,
-    /// De-duplicated bytes for all selected extension assets present in the
-    /// runtime tree.
-    pub selected_extension_bytes: u64,
-    /// Per-extension asset footprints.
-    pub extensions: Vec,
-}
-
-/// Size report row for one selected extension.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct ExtensionSizeReport {
-    /// SQL extension name.
-    pub name: String,
-    /// Number of runtime files counted for this extension.
-    pub file_count: usize,
-    /// Runtime bytes counted for this extension.
-    pub bytes: u64,
-}
-
-/// Runtime resources generated by the Rust SDK and consumed by Swift, Kotlin,
-/// and React Native SDKs.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct NativeRuntimeResources {
-    /// Root directory containing `runtime` and `cluster-seed` resources.
-    pub root: PathBuf,
-    /// Runtime files directory copied into app storage before opening.
-    pub runtime_files: PathBuf,
-    /// Cluster-seed PGDATA files copied for first open on mobile.
-    pub cluster_seed_files: PathBuf,
-    /// Content key of the source runtime cache.
-    pub runtime_cache_key: String,
-    /// Content key of the source cluster-seed PGDATA cache.
-    pub cluster_seed_cache_key: String,
-    /// Built-in extensions materialized into the runtime resources.
-    pub extensions: Vec,
-    /// Optional runtime features materialized into the runtime resources.
-    pub runtime_features: Vec,
-    /// Exact extension names materialized into the runtime resources, including
-    /// built-in and concrete prebuilt extension artifacts.
-    pub extension_names: Vec,
-    /// Mobile static-registry metadata for the materialized runtime resources.
-    pub mobile_static_registry: MobileStaticRegistryMetadata,
-    /// PostgreSQL shared-preload libraries required by the selected extensions.
-    pub shared_preload_libraries: Vec,
-    /// Static registry manifest generated for platform SDK resources.
-    pub static_registry_manifest: PathBuf,
-    /// Generated static registry source when the runtime resources are
-    /// mobile-ready.
-    pub static_registry_source: Option,
-    /// Package and extension size report.
-    pub size_report: NativeRuntimeResourceSizeReport,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-struct RuntimeResourceExtension {
-    sql_name: String,
-    native_runtime_version: Option,
-    creates_extension: bool,
-    native_module_stem: Option,
-    native_module_file: Option,
-    native_target: Option,
-    dependencies: Vec,
-    data_files: Vec,
-    extension_sql_file_names: Vec,
-    extension_sql_file_prefixes: Vec,
-    shared_preload_libraries: Vec,
-    mobile_prebuilt: bool,
-    mobile_static_archives: Vec,
-    mobile_static_dependency_archives: Vec,
-    static_symbol_prefix: Option,
-    static_symbol_aliases: Vec,
-    license_profile: Option,
-    license_files: Vec,
-    source: RuntimeResourceExtensionSource,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-enum RuntimeResourceExtensionSource {
-    BuiltIn(Extension),
-    Prebuilt { root: PathBuf, files_root: PathBuf },
-}
-
-#[derive(Debug)]
-struct PreparedPrebuiltExtensionArtifacts {
-    artifacts: Vec,
-    extraction_root: Option,
-}
-
-impl PreparedPrebuiltExtensionArtifacts {
-    fn prepare(artifacts: &[NativePrebuiltExtensionArtifact]) -> Result {
-        let mut prepared = Vec::new();
-        let mut extraction_root = None;
-        for (index, artifact) in artifacts.iter().enumerate() {
-            if artifact.root.is_dir() {
-                prepared.push(artifact.clone());
-            } else if artifact.root.is_file() {
-                let root = extraction_root.get_or_insert_with(unique_extension_extraction_root);
-                fs::create_dir_all(&root).map_err(|err| {
-                    Error::Engine(format!(
-                        "create prebuilt extension artifact extraction root {}: {err}",
-                        root.display()
-                    ))
-                })?;
-                let destination = root.join(format!("artifact-{index}"));
-                let extracted_root =
-                    extract_prebuilt_extension_archive(&artifact.root, &destination)?;
-                prepared.push(NativePrebuiltExtensionArtifact::new(extracted_root));
-            } else {
-                return Err(Error::InvalidConfig(format!(
-                    "prebuilt extension artifact {} must be an unpacked directory, .tar archive, .tar.gz/.tgz archive, or .tar.zst archive",
-                    artifact.root.display()
-                )));
-            }
-        }
-        Ok(Self {
-            artifacts: prepared,
-            extraction_root,
-        })
-    }
-
-    fn artifacts(&self) -> &[NativePrebuiltExtensionArtifact] {
-        &self.artifacts
-    }
-}
-
-impl Drop for PreparedPrebuiltExtensionArtifacts {
-    fn drop(&mut self) {
-        if let Some(root) = &self.extraction_root {
-            let _ = fs::remove_dir_all(root);
-        }
-    }
-}
-
-/// Build the portable runtime-resource layout consumed by platform SDK
-/// packaging.
-pub fn build_native_runtime_resources(
-    options: NativeRuntimeResourceOptions,
-) -> Result {
-    if options.output_dir.as_os_str().is_empty() {
-        return Err(Error::InvalidConfig(
-            "native runtime-resource output directory must not be empty".to_owned(),
-        ));
-    }
-
-    let expected_native_runtime_version = expected_prebuilt_native_runtime_version(&options)?;
-    let prebuilt_artifacts =
-        PreparedPrebuiltExtensionArtifacts::prepare(&options.prebuilt_extensions)?;
-    let selected_extensions =
-        resolve_runtime_resource_extensions(&options.extensions, prebuilt_artifacts.artifacts())?;
-    validate_prebuilt_native_runtime_versions(
-        &selected_extensions,
-        expected_native_runtime_version,
-    )?;
-    validate_prebuilt_extension_targets(&selected_extensions, options.extension_target.as_deref())?;
-    let runtime_features = normalize_runtime_features(&options.runtime_features);
-    let extensions = built_in_extensions(&selected_extensions);
-    let extension_names = selected_extension_names(&selected_extensions);
-    let shared_preload_libraries = shared_preload_libraries(&selected_extensions);
-    let mobile_static_registry =
-        mobile_static_registry_metadata(&selected_extensions, &options.mobile_static_module_stems)?;
-    if options.require_mobile_static_registry {
-        require_mobile_static_registry_ready(&mobile_static_registry)?;
-    }
-    let runtime = match options.mode {
-        NativePackagingMode::NativeDirect | NativePackagingMode::NativeBroker => {
-            NativePackagingRuntime::Embedded
-        }
-        NativePackagingMode::NativeServer => NativePackagingRuntime::PostgresServer,
-    };
-    let catalog_profile = if runtime_features.contains(&NativeRuntimeFeature::Icu) {
-        NativePackagingCatalogProfile::Icu
-    } else {
-        NativePackagingCatalogProfile::Standard
-    };
-    let materialized =
-        materialize_native_packaging_resources(runtime, &extensions, catalog_profile)?;
-    let root = options.output_dir.join("oliphaunt");
-    prepare_output_root(&root, options.replace_existing)?;
-
-    write_runtime_resource_tree(
-        &root,
-        options.mode,
-        &materialized,
-        &selected_extensions,
-        &runtime_features,
-        &shared_preload_libraries,
-        &mobile_static_registry,
-        options.extension_target.as_deref(),
-    )?;
-    let size_report = runtime_resource_size_report(
-        &root,
-        &selected_extensions,
-        options.extension_target.as_deref(),
-        &mobile_static_registry,
-    )?;
-    write_runtime_resource_size_report(&size_report)?;
-
-    Ok(NativeRuntimeResources {
-        runtime_files: root.join("runtime/files"),
-        cluster_seed_files: root.join("cluster-seed/files"),
-        static_registry_manifest: root.join("static-registry/manifest.properties"),
-        static_registry_source: (mobile_static_registry.state
-            == MobileStaticRegistryState::Complete)
-            .then(|| root.join(format!("static-registry/{STATIC_REGISTRY_SOURCE_FILE}"))),
-        root,
-        runtime_cache_key: materialized.runtime_cache_key,
-        cluster_seed_cache_key: materialized.cluster_seed_cache_key,
-        extensions,
-        runtime_features,
-        extension_names,
-        mobile_static_registry,
-        shared_preload_libraries,
-        size_report,
-    })
-}
-
-fn expected_prebuilt_native_runtime_version(
-    options: &NativeRuntimeResourceOptions,
-) -> Result> {
-    let version = options.native_runtime_version.as_deref();
-    if let Some(version) = version {
-        validate_stable_semver(
-            version,
-            "selected liboliphaunt-native version for prebuilt extension packaging",
-        )?;
-    }
-    if !options.prebuilt_extensions.is_empty() && version.is_none() {
-        return Err(Error::InvalidConfig(
-            "prebuilt extension packaging requires an exact stable liboliphaunt-native version; set NativeRuntimeResourceOptions::native_runtime_version(...) or pass --liboliphaunt-native-version "
-                .to_owned(),
-        ));
-    }
-    Ok(version)
-}
-
-fn validate_prebuilt_native_runtime_versions(
-    extensions: &[RuntimeResourceExtension],
-    expected: Option<&str>,
-) -> Result<()> {
-    for extension in extensions {
-        if !matches!(
-            extension.source,
-            RuntimeResourceExtensionSource::Prebuilt { .. }
-        ) {
-            continue;
-        }
-        let expected = expected.ok_or_else(|| {
-            Error::InvalidConfig(
-                "prebuilt extension packaging requires an exact stable liboliphaunt-native version"
-                    .to_owned(),
-            )
-        })?;
-        let actual = extension
-            .native_runtime_version
-            .as_deref()
-            .expect("validated v1 prebuilt extension manifests carry nativeRuntimeVersion");
-        if actual != expected {
-            return Err(Error::InvalidConfig(format!(
-                "prebuilt extension artifact for '{}' requires liboliphaunt-native version '{}', but runtime packaging selected '{}'",
-                extension.sql_name, actual, expected
-            )));
-        }
-    }
-    Ok(())
-}
-
-fn validate_prebuilt_extension_targets(
-    extensions: &[RuntimeResourceExtension],
-    extension_target: Option<&str>,
-) -> Result<()> {
-    for extension in extensions {
-        if !matches!(
-            extension.source,
-            RuntimeResourceExtensionSource::Prebuilt { .. }
-        ) || extension.native_module_stem.is_none()
-        {
-            continue;
-        }
-        validate_prebuilt_extension_target(extension, extension_target)?;
-    }
-    Ok(())
-}
-
-fn normalize_runtime_features(features: &[NativeRuntimeFeature]) -> Vec {
-    let normalized = features.iter().copied().collect::>();
-    normalized.into_iter().collect()
-}
-
-fn runtime_feature_names(features: &[NativeRuntimeFeature]) -> Vec<&'static str> {
-    features.iter().map(|feature| feature.as_str()).collect()
-}
-
-fn resolve_runtime_resource_extensions(
-    built_in: &[Extension],
-    prebuilt_artifacts: &[NativePrebuiltExtensionArtifact],
-) -> Result> {
-    let mut prebuilt = BTreeMap::new();
-    for artifact in prebuilt_artifacts {
-        let extension = load_prebuilt_extension_artifact(&artifact.root)?;
-        if prebuilt
-            .insert(extension.sql_name.clone(), extension)
-            .is_some()
-        {
-            return Err(Error::InvalidConfig(
-                "prebuilt extension artifacts must not repeat the same SQL extension name"
-                    .to_owned(),
-            ));
-        }
-    }
-
-    let mut requested = built_in
-        .iter()
-        .map(|extension| extension.sql_name().to_owned())
-        .collect::>();
-    requested.extend(prebuilt.keys().cloned());
-
-    let mut resolved = Vec::new();
-    let mut visiting = BTreeSet::new();
-    let mut visited = BTreeSet::new();
-    for sql_name in requested {
-        visit_runtime_resource_extension(
-            &sql_name,
-            &prebuilt,
-            &mut visiting,
-            &mut visited,
-            &mut resolved,
-        )?;
-    }
-    Ok(resolved)
-}
-
-fn visit_runtime_resource_extension(
-    sql_name: &str,
-    prebuilt: &BTreeMap,
-    visiting: &mut BTreeSet,
-    visited: &mut BTreeSet,
-    resolved: &mut Vec,
-) -> Result<()> {
-    if visited.contains(sql_name) {
-        return Ok(());
-    }
-    if !visiting.insert(sql_name.to_owned()) {
-        return Err(Error::InvalidConfig(format!(
-            "cyclic native extension dependency involving '{sql_name}'"
-        )));
-    }
-
-    let (extension, dependencies) = if let Some(extension) = prebuilt.get(sql_name) {
-        (
-            extension.clone(),
-            extension
-                .dependencies()
-                .into_iter()
-                .map(str::to_owned)
-                .collect::>(),
-        )
-    } else {
-        let Some(extension) = Extension::by_sql_name(sql_name) else {
-            return Err(Error::InvalidConfig(format!(
-                "selected extension '{sql_name}' is neither built into this Oliphaunt release nor provided as a prebuilt extension artifact"
-            )));
-        };
-        let selected_extension = built_in_runtime_resource_extension(extension);
-        (
-            selected_extension,
-            catalog::for_extension(extension).dependencies.clone(),
-        )
-    };
-
-    for dependency in dependencies {
-        visit_runtime_resource_extension(&dependency, prebuilt, visiting, visited, resolved)?;
-    }
-    visiting.remove(sql_name);
-    visited.insert(sql_name.to_owned());
-    resolved.push(extension);
-    Ok(())
-}
-
-fn built_in_runtime_resource_extension(extension: Extension) -> RuntimeResourceExtension {
-    let catalog = catalog::for_extension(extension);
-    RuntimeResourceExtension {
-        sql_name: catalog.sql_name.clone(),
-        native_runtime_version: None,
-        creates_extension: catalog.creates_extension,
-        native_module_stem: catalog.native_module_stem.clone(),
-        native_module_file: catalog
-            .native_module_stem
-            .as_deref()
-            .map(|stem| format!("{stem}{}", std::env::consts::DLL_SUFFIX)),
-        native_target: None,
-        dependencies: catalog.dependencies.clone(),
-        data_files: catalog
-            .runtime_share_data_files
-            .iter()
-            .map(PathBuf::from)
-            .collect(),
-        extension_sql_file_names: catalog.extension_sql_file_names.clone(),
-        extension_sql_file_prefixes: catalog.extension_sql_file_prefixes.clone(),
-        shared_preload_libraries: catalog.shared_preload_libraries.clone(),
-        mobile_prebuilt: true,
-        mobile_static_archives: Vec::new(),
-        mobile_static_dependency_archives: Vec::new(),
-        static_symbol_prefix: None,
-        static_symbol_aliases: Vec::new(),
-        license_profile: None,
-        license_files: Vec::new(),
-        source: RuntimeResourceExtensionSource::BuiltIn(extension),
-    }
-}
-
-fn built_in_extensions(extensions: &[RuntimeResourceExtension]) -> Vec {
-    extensions
-        .iter()
-        .filter_map(|extension| match extension.source {
-            RuntimeResourceExtensionSource::BuiltIn(extension) => Some(extension),
-            RuntimeResourceExtensionSource::Prebuilt { .. } => None,
-        })
-        .collect()
-}
-
-fn selected_extension_names(extensions: &[RuntimeResourceExtension]) -> Vec {
-    let mut names = extensions
-        .iter()
-        .map(|extension| extension.sql_name.clone())
-        .collect::>();
-    names.sort();
-    names.dedup();
-    names
-}
-
-fn createable_extension_names(extensions: &[RuntimeResourceExtension]) -> Vec {
-    let mut names = extensions
-        .iter()
-        .filter(|extension| extension.creates_extension)
-        .map(|extension| extension.sql_name.clone())
-        .collect::>();
-    names.sort();
-    names.dedup();
-    names
-}
-
-fn mobile_static_archive_targets(archives: &[MobileStaticArchive]) -> Vec {
-    archives
-        .iter()
-        .map(|archive| archive.target.clone())
-        .collect::>()
-        .into_iter()
-        .collect()
-}
-
-fn load_prebuilt_extension_artifact(root: &Path) -> Result {
-    let manifest_path = root.join("manifest.properties");
-    let manifest_text = fs::read_to_string(&manifest_path).map_err(|err| {
-        Error::InvalidConfig(format!(
-            "read prebuilt extension artifact manifest {}: {err}",
-            manifest_path.display()
-        ))
-    })?;
-    let manifest = parse_canonical_properties_manifest(
-        &manifest_path,
-        &manifest_text,
-        &EXTENSION_ARTIFACT_MANIFEST_KEYS,
-    )?;
-    require_property(
-        &manifest_path,
-        &manifest,
-        "packageLayout",
-        EXTENSION_ARTIFACT_LAYOUT,
-    )?;
-    require_exact_manifest_keys(&manifest_path, &manifest, &EXTENSION_ARTIFACT_MANIFEST_KEYS)?;
-    let pg_major = required_manifest_value(&manifest_path, &manifest, "pgMajor")?;
-    if pg_major != "18" {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact {} targets PostgreSQL {pg_major}; Oliphaunt native packages require PostgreSQL 18",
-            manifest_path.display()
-        )));
-    }
-    let files_value = manifest
-        .get("files")
-        .map(String::as_str)
-        .unwrap_or("files")
-        .trim();
-    if files_value != "files" {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact {} must use files=files",
-            manifest_path.display()
-        )));
-    }
-    let files_root = root.join("files");
-    if !files_root.is_dir() {
-        return Err(Error::InvalidConfig(format!(
-            "prebuilt extension artifact {} is missing files/ runtime tree",
-            root.display()
-        )));
-    }
-
-    let sql_name = required_manifest_value(&manifest_path, &manifest, "sqlName")?.to_owned();
-    validate_portable_id(&sql_name, "prebuilt extension sqlName")?;
-    require_property(
-        &manifest_path,
-        &manifest,
-        "nativeRuntimeProduct",
-        EXTENSION_ARTIFACT_NATIVE_RUNTIME_PRODUCT,
-    )?;
-    let native_runtime_version =
-        required_manifest_value(&manifest_path, &manifest, "nativeRuntimeVersion")?.to_owned();
-    validate_stable_semver(
-        &native_runtime_version,
-        "prebuilt extension nativeRuntimeVersion",
-    )?;
-    let creates_extension = parse_manifest_yes_no(&manifest_path, &manifest, "createsExtension")?;
-    let native_module_stem = optional_manifest_id(&manifest_path, &manifest, "nativeModuleStem")?;
-    let native_module_file = optional_manifest_id(&manifest_path, &manifest, "nativeModuleFile")?;
-    if native_module_file.is_some() && native_module_stem.is_none() {
-        return Err(Error::InvalidConfig(format!(
-            "manifest {} uses nativeModuleFile without nativeModuleStem",
-            manifest_path.display()
-        )));
-    }
-    let native_module_file = native_module_stem.as_ref().map(|stem| {
-        native_module_file
-            .clone()
-            .unwrap_or_else(|| format!("{}{}", stem, std::env::consts::DLL_SUFFIX))
-    });
-    let native_target = optional_manifest_id(&manifest_path, &manifest, "nativeTarget")?;
-    if native_module_stem.is_some() && native_target.is_none() {
-        return Err(Error::InvalidConfig(format!(
-            "manifest {} declares nativeModuleStem but is missing nativeTarget",
-            manifest_path.display()
-        )));
-    }
-    let dependencies = parse_manifest_id_list(&manifest_path, &manifest, "dependencies")?;
-    let data_files = parse_manifest_relative_path_list(&manifest_path, &manifest, "dataFiles")?;
-    let extension_sql_file_names =
-        parse_manifest_id_list(&manifest_path, &manifest, "extensionSqlFileNames")?;
-    for file_name in &extension_sql_file_names {
-        if !file_name.ends_with(".sql") {
-            return Err(Error::InvalidConfig(format!(
-                "manifest {} extensionSqlFileNames entry '{}' must be a SQL basename",
-                manifest_path.display(),
-                file_name
-            )));
-        }
-    }
-    let extension_sql_file_prefixes =
-        parse_manifest_id_list(&manifest_path, &manifest, "extensionSqlFilePrefixes")?;
-    for prefix in &extension_sql_file_prefixes {
-        if prefix.contains('.') {
-            return Err(Error::InvalidConfig(format!(
-                "manifest {} extensionSqlFilePrefixes entry '{}' must be a basename prefix without '.'",
-                manifest_path.display(),
-                prefix
-            )));
-        }
-    }
-    let shared_preload_libraries =
-        parse_manifest_id_list(&manifest_path, &manifest, "sharedPreloadLibraries")?;
-    let mobile_prebuilt = parse_manifest_yes_no(&manifest_path, &manifest, "mobilePrebuilt")?;
-    let mobile_static_archives =
-        parse_manifest_mobile_static_archives(&manifest_path, &manifest, "mobileStaticArchives")?;
-    let mobile_static_dependency_archives = parse_manifest_mobile_static_dependency_archives(
-        &manifest_path,
-        &manifest,
-        "mobileStaticDependencyArchives",
-    )?;
-    let static_symbol_prefix =
-        optional_manifest_c_identifier(&manifest_path, &manifest, "staticSymbolPrefix")?;
-    let static_symbol_aliases =
-        parse_manifest_static_symbol_aliases(&manifest_path, &manifest, "staticSymbolAliases")?;
-    let license_files =
-        parse_manifest_relative_path_list(&manifest_path, &manifest, "licenseFiles")?;
-    validate_extension_artifact_license_paths(&manifest_path, &license_files)?;
-    let license_profile = NativeExtensionArtifactLicenseProfile::parse(required_manifest_value(
-        &manifest_path,
-        &manifest,
-        "licenseProfile",
-    )?)?;
-    validate_extension_artifact_license_profile(
-        &manifest_path,
-        &sql_name,
-        native_target.as_deref(),
-        &mobile_static_dependency_archives,
-        license_profile,
-        &license_files,
-    )?;
-    validate_prebuilt_extension_mobile_static_archives(
-        root,
-        &manifest_path,
-        native_module_stem.as_deref(),
-        mobile_prebuilt,
-        &mobile_static_archives,
-    )?;
-    validate_prebuilt_extension_mobile_static_dependency_archives(
-        root,
-        &manifest_path,
-        &mobile_static_archives,
-        &mobile_static_dependency_archives,
-    )?;
-
-    let extension = RuntimeResourceExtension {
-        sql_name,
-        native_runtime_version: Some(native_runtime_version),
-        creates_extension,
-        native_module_stem,
-        native_module_file,
-        native_target,
-        dependencies,
-        data_files,
-        extension_sql_file_names,
-        extension_sql_file_prefixes,
-        shared_preload_libraries,
-        mobile_prebuilt,
-        mobile_static_archives,
-        mobile_static_dependency_archives,
-        static_symbol_prefix,
-        static_symbol_aliases,
-        license_profile: Some(license_profile),
-        license_files,
-        source: RuntimeResourceExtensionSource::Prebuilt {
-            root: root.to_path_buf(),
-            files_root,
-        },
-    };
-    validate_prebuilt_extension_leaf_inventory(root, &manifest_path, &extension)?;
-    Ok(extension)
-}
-
-impl RuntimeResourceExtension {
-    fn dependencies(&self) -> Vec<&str> {
-        self.dependencies.iter().map(String::as_str).collect()
-    }
-}
-
-fn runtime_extension_sql_file_belongs(
-    extension: &RuntimeResourceExtension,
-    file_name: &str,
-) -> bool {
-    (extension.creates_extension
-        && (file_name == format!("{}.control", extension.sql_name)
-            || file_name == format!("{}.sql", extension.sql_name)
-            || (file_name.starts_with(&format!("{}--", extension.sql_name))
-                && file_name.ends_with(".sql"))))
-        || extension
-            .extension_sql_file_names
-            .iter()
-            .any(|name| name == file_name)
-        || (file_name.ends_with(".sql")
-            && extension
-                .extension_sql_file_prefixes
-                .iter()
-                .any(|prefix| file_name.starts_with(prefix)))
-}
-
-fn require_mobile_static_registry_ready(metadata: &MobileStaticRegistryMetadata) -> Result<()> {
-    if metadata.state != MobileStaticRegistryState::Pending {
-        return Ok(());
-    }
-    Err(Error::InvalidConfig(format!(
-        "selected extension(s) require mobile static registry entries before iOS/Android packaging: {}",
-        metadata.pending_extensions.join(",")
-    )))
-}
-
-#[cfg(test)]
-mod tests {
-    #[cfg(feature = "extension-signing")]
-    use super::extension_index::hex_bytes;
-    use super::*;
-    use std::time::{SystemTime, UNIX_EPOCH};
-    use tar::EntryType;
-
-    #[test]
-    fn logical_tree_digest_uses_portable_path_order() {
-        let root = tempfile::tempdir().unwrap();
-        fs::create_dir(root.path().join("a")).unwrap();
-        write_file(&root.path().join("a/b"), b"nested");
-        write_file(&root.path().join("a0"), b"flat");
-
-        let windows_native_order = vec![
-            ("a0".to_string(), root.path().join("a0")),
-            ("a/b".to_string(), root.path().join("a/b")),
-        ];
-        let expected = "33fcdf990b4a606acc4d5cdda3ab275513c3a2fa87ae72bafc5f4e1278a2faa3";
-        assert_eq!(
-            logical_tree_sha256_files(windows_native_order).unwrap(),
-            expected
-        );
-        assert_eq!(logical_tree_sha256(root.path()).unwrap(), expected);
-    }
-
-    #[test]
-    fn mobile_static_registry_metadata_marks_sql_only_packages_not_required() {
-        let extensions = runtime_resource_extensions(&[Extension::PGTAP]);
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        assert_eq!(metadata.state, MobileStaticRegistryState::NotRequired);
-        assert!(metadata.registered_extensions.is_empty());
-        assert!(metadata.pending_extensions.is_empty());
-        assert!(metadata.native_module_stems.is_empty());
-    }
-
-    #[test]
-    fn mobile_static_registry_metadata_marks_module_extensions_pending() {
-        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        assert_eq!(metadata.state, MobileStaticRegistryState::Pending);
-        assert_eq!(metadata.pending_extensions, vec!["vector"]);
-        assert_eq!(metadata.native_module_stems, vec!["vector"]);
-        assert!(metadata.registered_extensions.is_empty());
-    }
-
-    #[test]
-    fn mobile_static_registry_requirement_rejects_pending_modules() {
-        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        let error = require_mobile_static_registry_ready(&metadata).unwrap_err();
-        assert!(matches!(
-            error,
-            Error::InvalidConfig(message)
-                if message
-                    == "selected extension(s) require mobile static registry entries before iOS/Android packaging: vector"
-        ));
-    }
-
-    #[test]
-    fn mobile_static_registry_metadata_marks_declared_modules_complete() {
-        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
-        let metadata =
-            mobile_static_registry_metadata(&extensions, &["vector".to_owned()]).unwrap();
-        assert_eq!(metadata.state, MobileStaticRegistryState::Complete);
-        assert_eq!(metadata.registered_extensions, vec!["vector"]);
-        assert!(metadata.pending_extensions.is_empty());
-        assert_eq!(metadata.native_module_stems, vec!["vector"]);
-        require_mobile_static_registry_ready(&metadata).unwrap();
-    }
-
-    #[test]
-    fn mobile_static_registry_metadata_marks_hstore_complete_after_prebuilt_artifact_support() {
-        let extensions = runtime_resource_extensions(&[Extension::HSTORE]);
-        let metadata =
-            mobile_static_registry_metadata(&extensions, &["hstore".to_owned()]).unwrap();
-        assert_eq!(metadata.state, MobileStaticRegistryState::Complete);
-        assert_eq!(metadata.registered_extensions, vec!["hstore"]);
-        assert!(metadata.pending_extensions.is_empty());
-        assert_eq!(metadata.native_module_stems, vec!["hstore"]);
-        require_mobile_static_registry_ready(&metadata).unwrap();
-    }
-
-    #[test]
-    fn mobile_static_registry_metadata_rejects_unknown_registered_modules() {
-        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
-        let error =
-            mobile_static_registry_metadata(&extensions, &["hstore".to_owned()]).unwrap_err();
-        assert!(matches!(
-            error,
-            Error::InvalidConfig(message)
-                if message
-                    == "mobile static registry module stem(s) were not selected by these runtime resources: hstore"
-        ));
-    }
-
-    #[test]
-    fn manifest_records_mobile_static_registry_metadata() {
-        let extensions = runtime_resource_extensions(&[Extension::VECTOR]);
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        let manifest = RuntimeResourceManifest {
-            cache_key: "runtime-smoke",
-            layout: RUNTIME_FILES_LAYOUT,
-            artifact_role: "runtime",
-            catalog_profile: "",
-            icu_data_tree_sha256: "",
-            mode: NativePackagingMode::NativeDirect,
-            extensions: &extensions,
-            runtime_features: &[],
-            shared_preload_libraries: &[],
-            mobile_static_registry: &metadata,
-        };
-        let text = manifest_text(&manifest);
-        assert!(text.contains("selectedExtensions=vector\n"));
-        assert!(text.contains("extensions=vector\n"));
-        assert!(text.contains("sharedPreloadLibraries=\n"));
-        assert!(text.contains("mobileStaticRegistryState=pending\n"));
-        assert!(text.contains("mobileStaticRegistryPending=vector\n"));
-        assert!(text.contains("nativeModuleStems=vector\n"));
-        assert!(text.contains("mobileStaticRegistrySource=\n"));
-        assert_eq!(
-            text.lines()
-                .map(|line| line.split_once('=').unwrap().0)
-                .collect::>(),
-            vec![
-                "schema",
-                "layout",
-                "artifactRole",
-                "catalogProfile",
-                "clusterSeedTarget",
-                "icuDataTreeSha256",
-                "mode",
-                "cacheKey",
-                "selectedExtensions",
-                "extensions",
-                "runtimeFeatures",
-                "sharedPreloadLibraries",
-                "mobileStaticRegistryState",
-                "mobileStaticRegistryRegistered",
-                "mobileStaticRegistryPending",
-                "nativeModuleStems",
-                "mobileStaticRegistrySource",
-            ]
-        );
-    }
-
-    #[test]
-    fn cluster_seed_manifest_omits_runtime_only_fields() {
-        let metadata = mobile_static_registry_metadata(&[], &[]).unwrap();
-        let manifest = RuntimeResourceManifest {
-            cache_key: "seed-smoke",
-            layout: CLUSTER_SEED_LAYOUT,
-            artifact_role: "cluster-seed-standard",
-            catalog_profile: "standard",
-            icu_data_tree_sha256: "",
-            mode: NativePackagingMode::NativeDirect,
-            extensions: &[],
-            runtime_features: &[],
-            shared_preload_libraries: &[],
-            mobile_static_registry: &metadata,
-        };
-        let text = manifest_text(&manifest);
-        assert_eq!(
-            text.lines()
-                .map(|line| line.split_once('=').unwrap().0)
-                .collect::>(),
-            vec![
-                "schema",
-                "layout",
-                "artifactRole",
-                "catalogProfile",
-                "postgresMajor",
-                "physicalFormat",
-                "initialSuperuser",
-                "icuDataVersion",
-                "icuDataForm",
-                "icuDataTreeSha256",
-                "runtimeFeatures",
-                "cacheKey",
-            ]
-        );
-    }
-
-    #[test]
-    fn manifest_records_required_shared_preload_libraries() {
-        let extensions =
-            runtime_resource_extensions(&[Extension::PG_TEXTSEARCH, Extension::PG_TEXTSEARCH]);
-        let preload = shared_preload_libraries(&extensions);
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        let manifest = RuntimeResourceManifest {
-            cache_key: "runtime-smoke",
-            layout: RUNTIME_FILES_LAYOUT,
-            artifact_role: "runtime",
-            catalog_profile: "",
-            icu_data_tree_sha256: "",
-            mode: NativePackagingMode::NativeDirect,
-            extensions: &extensions,
-            runtime_features: &[],
-            shared_preload_libraries: &preload,
-            mobile_static_registry: &metadata,
-        };
-        let text = manifest_text(&manifest);
-        assert!(text.contains("selectedExtensions=pg_textsearch\n"));
-        assert!(text.contains("extensions=pg_textsearch\n"));
-        assert!(text.contains("sharedPreloadLibraries=pg_textsearch\n"));
-    }
-
-    #[test]
-    fn manifest_separates_selected_and_createable_extension_domains() {
-        let extensions = runtime_resource_extensions(&[Extension::HSTORE, Extension::AUTO_EXPLAIN]);
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        let manifest = RuntimeResourceManifest {
-            cache_key: "runtime-domain-smoke",
-            layout: RUNTIME_FILES_LAYOUT,
-            artifact_role: "runtime",
-            catalog_profile: "",
-            icu_data_tree_sha256: "",
-            mode: NativePackagingMode::NativeDirect,
-            extensions: &extensions,
-            runtime_features: &[],
-            shared_preload_libraries: &[],
-            mobile_static_registry: &metadata,
-        };
-        let text = manifest_text(&manifest);
-        assert!(text.contains("selectedExtensions=auto_explain,hstore\n"));
-        assert!(text.contains("extensions=hstore\n"));
-        assert!(!text.contains("extensions=auto_explain"));
-    }
-
-    #[test]
-    fn runtime_resource_package_omits_native_icu_files_data() {
-        let temp = unique_temp_root("oliphaunt-runtime-resources-icu-data");
-        let root = temp.join("oliphaunt");
-        let materialized = MaterializedNativeResources {
-            runtime_dir: temp.join("materialized/runtime"),
-            cluster_seed: temp.join("materialized/cluster-seed"),
-            runtime_cache_key: "runtime-icu".to_owned(),
-            cluster_seed_cache_key: "template".to_owned(),
-        };
-        write_file(
-            &materialized
-                .runtime_dir
-                .join("share/postgresql/postgresql.conf.sample"),
-            b"core-runtime",
-        );
-        write_file(
-            &materialized.runtime_dir.join("share/icu/icudt76l.dat"),
-            b"icu-data",
-        );
-        write_file(&materialized.cluster_seed.join("PG_VERSION"), b"18\n");
-        fs::create_dir_all(&root).unwrap();
-
-        let metadata = mobile_static_registry_metadata(&[], &[]).unwrap();
-        write_runtime_resource_tree(
-            &root,
-            NativePackagingMode::NativeDirect,
-            &materialized,
-            &[],
-            &[],
-            &[],
-            &metadata,
-            None,
-        )
-        .unwrap();
-
-        assert!(
-            !root.join("runtime/files/share/icu").exists(),
-            "base runtime-resource packages must not carry ICU data; apps opt in through the ICU package"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn runtime_resource_package_copies_native_icu_data_when_feature_selected() {
-        let temp = unique_temp_root("oliphaunt-runtime-resources-selected-icu-data");
-        let root = temp.join("oliphaunt");
-        let materialized = MaterializedNativeResources {
-            runtime_dir: temp.join("materialized/runtime"),
-            cluster_seed: temp.join("materialized/cluster-seed"),
-            runtime_cache_key: "runtime-icu".to_owned(),
-            cluster_seed_cache_key: "template".to_owned(),
-        };
-        write_file(
-            &materialized
-                .runtime_dir
-                .join("share/postgresql/postgresql.conf.sample"),
-            b"core-runtime",
-        );
-        write_file(
-            &materialized.runtime_dir.join("share/icu/icudt76l.dat"),
-            b"icu-data",
-        );
-        write_file(&materialized.cluster_seed.join("PG_VERSION"), b"18\n");
-        fs::create_dir_all(&root).unwrap();
-
-        let metadata = mobile_static_registry_metadata(&[], &[]).unwrap();
-        write_runtime_resource_tree(
-            &root,
-            NativePackagingMode::NativeDirect,
-            &materialized,
-            &[],
-            &[NativeRuntimeFeature::Icu],
-            &[],
-            &metadata,
-            None,
-        )
-        .unwrap();
-
-        assert!(root.join("runtime/files/share/icu/icudt76l.dat").is_file());
-        let manifest = fs::read_to_string(root.join("runtime/manifest.properties")).unwrap();
-        assert!(manifest.contains("runtimeFeatures=icu\n"));
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn package_size_report_counts_selected_extension_assets() {
-        let temp = unique_temp_root("oliphaunt-runtime-resources-size-report");
-        let root = temp.join("oliphaunt");
-        write_file(
-            &root.join("runtime/files/share/postgresql/extension/vector.control"),
-            b"vector-control",
-        );
-        write_file(
-            &root.join("runtime/files/share/postgresql/extension/vector--1.0.sql"),
-            b"vector-sql",
-        );
-        write_file(
-            &root
-                .join("runtime/files/lib/postgresql")
-                .join(format!("vector{}", std::env::consts::DLL_SUFFIX)),
-            b"vector-module",
-        );
-        write_file(
-            &root.join("runtime/files/share/postgresql/postgresql.conf.sample"),
-            b"core-runtime",
-        );
-        write_file(&root.join("cluster-seed/files/PG_VERSION"), b"18\n");
-        write_file(
-            &root.join("static-registry/manifest.properties"),
-            b"state=pending\n",
-        );
-
-        let selected_extensions = runtime_resource_extensions(&[Extension::VECTOR]);
-        let metadata = mobile_static_registry_metadata(&selected_extensions, &[]).unwrap();
-        let report = runtime_resource_size_report(
-            &root,
-            &selected_extensions,
-            Some("test-target"),
-            &metadata,
-        )
-        .unwrap();
-        write_runtime_resource_size_report(&report).unwrap();
-
-        let vector_bytes = b"vector-control".len() as u64
-            + b"vector-sql".len() as u64
-            + b"vector-module".len() as u64;
-        assert_eq!(report.selected_extension_bytes, vector_bytes);
-        assert_eq!(report.extensions.len(), 1);
-        assert_eq!(report.extensions[0].name, "vector");
-        assert_eq!(report.extensions[0].file_count, 3);
-        assert_eq!(report.extensions[0].bytes, vector_bytes);
-
-        let text = fs::read_to_string(root.join("package-size.tsv")).unwrap();
-        assert!(text.contains("kind\tid\textensions\tfiles\tbytes\n"));
-        assert!(text.contains(&format!("extensions\tselected\t-\t-\t{vector_bytes}\n")));
-        assert!(text.contains(&format!("extension\tvector\t-\t3\t{vector_bytes}\n")));
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn package_size_report_counts_selected_extension_data_files_under_share() {
-        let temp = unique_temp_root("oliphaunt-runtime-resources-data-file-report");
-        let root = temp.join("oliphaunt");
-        write_file(
-            &root.join("runtime/files/share/postgresql/extension/unaccent.control"),
-            b"unaccent-control",
-        );
-        write_file(
-            &root.join("runtime/files/share/postgresql/extension/unaccent--1.1.sql"),
-            b"unaccent-sql",
-        );
-        write_file(
-            &root.join("runtime/files/share/postgresql/tsearch_data/unaccent.rules"),
-            b"unaccent-rules",
-        );
-        write_file(
-            &root
-                .join("runtime/files/lib/postgresql")
-                .join(format!("unaccent{}", std::env::consts::DLL_SUFFIX)),
-            b"unaccent-module",
-        );
-        write_file(
-            &root.join("runtime/files/share/postgresql/postgresql.conf.sample"),
-            b"core-runtime",
-        );
-        write_file(&root.join("cluster-seed/files/PG_VERSION"), b"18\n");
-        write_file(
-            &root.join("static-registry/manifest.properties"),
-            b"state=pending\n",
-        );
-
-        let selected_extensions = runtime_resource_extensions(&[Extension::UNACCENT]);
-        let metadata = mobile_static_registry_metadata(&selected_extensions, &[]).unwrap();
-        let report = runtime_resource_size_report(
-            &root,
-            &selected_extensions,
-            Some("test-target"),
-            &metadata,
-        )
-        .unwrap();
-
-        let unaccent_bytes = b"unaccent-control".len() as u64
-            + b"unaccent-sql".len() as u64
-            + b"unaccent-rules".len() as u64
-            + b"unaccent-module".len() as u64;
-        assert_eq!(report.selected_extension_bytes, unaccent_bytes);
-        assert_eq!(report.extensions.len(), 1);
-        assert_eq!(report.extensions[0].name, "unaccent");
-        assert_eq!(report.extensions[0].file_count, 4);
-        assert_eq!(report.extensions[0].bytes, unaccent_bytes);
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn module_symbol_parser_finds_module_pathname_and_exact_libdir_symbols() {
-        let symbols = module_c_symbols(
-            r#"
--- Commented AS 'MODULE_PATHNAME', 'ignored_symbol' LANGUAGE C;
-CREATE FUNCTION public.implicit_symbol(integer) RETURNS integer
-  AS 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT;
-CREATE OR REPLACE FUNCTION public.explicit_sql_name(integer) RETURNS integer
-  AS 'MODULE_PATHNAME', 'explicit_c_symbol'
-  LANGUAGE C STRICT;
-CREATE OR REPLACE FUNCTION public.spheroid_in(cstring) RETURNS spheroid
-  AS '$libdir/postgis-3', 'ellipsoid_in'
-  LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE;
-CREATE FUNCTION public.default_literal_decoy(text DEFAULT '$libdir/postgis-3') RETURNS integer
-  AS '$libdir/not-postgis-3', 'default_literal_must_not_be_registered' LANGUAGE C;
-CREATE FUNCTION public.as_keyword_decoy(text DEFAULT 'AS ''$libdir/postgis-3'', ''also_not_registered''') RETURNS integer
-  AS '$libdir/not-postgis-3', 'as_literal_must_not_be_registered' LANGUAGE C;
-CREATE FUNCTION public.foreign_module(integer) RETURNS integer
-  AS '$libdir/not-postgis-3', 'must_not_be_registered' LANGUAGE C;
-CREATE FUNCTION sql_only(integer) RETURNS integer
-  LANGUAGE sql AS 'SELECT $1';
-"#,
-            "postgis-3",
-        )
-        .unwrap();
-        assert_eq!(
-            symbols,
-            vec!["ellipsoid_in", "explicit_c_symbol", "implicit_symbol"]
-        );
-    }
-
-    #[test]
-    fn static_registry_source_declares_magic_init_and_sql_symbols() {
-        let modules = vec![StaticRegistryModule {
-            extension_sql_name: "vector".to_owned(),
-            module_stem: "vector".to_owned(),
-            symbol_prefix: "oliphaunt_static_vector".to_owned(),
-            sql_symbols: vec!["vector_in".to_owned(), "vector_out".to_owned()],
-            symbol_aliases: BTreeMap::new(),
-        }];
-        let source = static_registry_source_text(&modules);
-        assert!(source.contains("liboliphaunt_selected_static_extensions"));
-        assert!(source.contains("oliphaunt_static_vector_Pg_magic_func"));
-        assert!(source.contains("oliphaunt_static_vector__PG_init"));
-        assert!(source.contains("OLIPHAUNT_STATIC_OPTIONAL"));
-        assert!(source.contains("extern const void *oliphaunt_static_vector_Pg_magic_func(void);"));
-        assert!(source.contains(
-            "extern void oliphaunt_static_vector__PG_init(void) OLIPHAUNT_STATIC_OPTIONAL;"
-        ));
-        assert!(source.contains("extern void vector_in(void);"));
-        assert!(!source.contains(&format!("OLIPHAUNT_STATIC_{}", "WEAK")));
-        assert!(!source.contains("extern void vector_in(void) OLIPHAUNT_STATIC_OPTIONAL"));
-        assert!(source.contains("{ .name = \"vector_in\", .address = (void *)vector_in }"));
-        assert!(
-            source.contains(
-                "{ .name = \"pg_finfo_vector_in\", .address = (void *)pg_finfo_vector_in }"
-            )
-        );
-        let manifest = static_registry_manifest_text(
-            &MobileStaticRegistryMetadata {
-                state: MobileStaticRegistryState::Complete,
-                registered_extensions: vec!["vector".to_owned()],
-                pending_extensions: vec![],
-                native_module_stems: vec!["vector".to_owned()],
-            },
-            &modules,
-            &[],
-            &[],
-        );
-        assert!(manifest.contains("packageLayout=oliphaunt-static-registry-v1\n"));
-        assert!(manifest.contains("source=oliphaunt_static_registry.c\n"));
-        assert!(manifest.contains("module.vector.sqlSymbols=vector_in,vector_out\n"));
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_is_exact_and_mobile_registry_ready() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-artifact");
-        let artifact = temp.join("acme_ext");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            true,
-        );
-        write_file(
-            &artifact.join("files/share/postgresql/extension/hstore.control"),
-            b"comment = 'should not leak'\n",
-        );
-
-        let error = resolve_runtime_resource_extensions(
-            &[],
-            &[NativePrebuiltExtensionArtifact::new(&artifact)],
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains("contains undeclared extension SQL/control file files/share/postgresql/extension/hstore.control"),
-            "unexpected extra-leaf error: {error}"
-        );
-        fs::remove_file(artifact.join("files/share/postgresql/extension/hstore.control")).unwrap();
-
-        let extensions = resolve_runtime_resource_extensions(
-            &[],
-            &[NativePrebuiltExtensionArtifact::new(&artifact)],
-        )
-        .unwrap();
-        assert_eq!(selected_extension_names(&extensions), vec!["acme_ext"]);
-
-        let runtime_files = temp.join("runtime/files");
-        write_file(
-            &runtime_files.join("share/postgresql/postgresql.conf.sample"),
-            b"core-runtime",
-        );
-        write_file(&temp.join("cluster-seed/files/PG_VERSION"), b"18\n");
-        let pending_metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        copy_prebuilt_extension_artifacts(
-            &runtime_files,
-            &extensions,
-            NativePackagingMode::NativeServer,
-            Some("test-target"),
-            &pending_metadata,
-        )
-        .unwrap();
-
-        assert!(
-            runtime_files
-                .join("share/postgresql/extension/acme_ext.control")
-                .is_file()
-        );
-        assert!(
-            runtime_files
-                .join("share/postgresql/extension/acme_ext--1.0.sql")
-                .is_file()
-        );
-        assert!(
-            runtime_files
-                .join("share/postgresql/data/acme_ext.rules")
-                .is_file()
-        );
-        assert!(
-            runtime_files
-                .join("lib/postgresql")
-                .join(format!("acme_ext{}", std::env::consts::DLL_SUFFIX))
-                .is_file()
-        );
-        assert!(
-            !runtime_files
-                .join("share/postgresql/extension/hstore.control")
-                .exists(),
-            "unselected files inside a prebuilt extension artifact must not leak"
-        );
-
-        let metadata =
-            mobile_static_registry_metadata(&extensions, &["acme_ext".to_owned()]).unwrap();
-        assert_eq!(metadata.state, MobileStaticRegistryState::Complete);
-        assert_eq!(metadata.registered_extensions, vec!["acme_ext"]);
-        assert_eq!(metadata.native_module_stems, vec!["acme_ext"]);
-
-        let modules = static_registry_modules(&runtime_files, &extensions, &metadata).unwrap();
-        assert_eq!(modules.len(), 1);
-        assert_eq!(modules[0].extension_sql_name, "acme_ext");
-        assert_eq!(modules[0].symbol_prefix, "acme_static");
-        assert_eq!(modules[0].sql_symbols, vec!["acme_ext_echo"]);
-        let static_registry_dir = temp.join("oliphaunt/static-registry");
-        let archives = copy_prebuilt_mobile_static_archives(&static_registry_dir, &extensions)
-            .expect("copy selected mobile static archives");
-        assert_eq!(archives.len(), 1);
-        assert_eq!(archives[0].target, "ios-simulator");
-        assert!(
-            static_registry_dir
-                .join(
-                    "archives/ios-simulator/extensions/acme_ext/liboliphaunt_extension_acme_ext.a"
-                )
-                .is_file(),
-            "selected external mobile static archive must be copied into runtime resources"
-        );
-        let dependency_archives =
-            copy_prebuilt_mobile_static_dependency_archives(&static_registry_dir, &extensions)
-                .expect("copy selected mobile static dependency archives");
-        assert_eq!(dependency_archives.len(), 1);
-        assert_eq!(dependency_archives[0].target, "ios-simulator");
-        assert_eq!(dependency_archives[0].name, "openssl");
-        assert!(
-            static_registry_dir
-                .join("archives/ios-simulator/dependencies/openssl/libcrypto.a")
-                .is_file(),
-            "selected external mobile static dependency archive must be copied into runtime resources"
-        );
-        let static_manifest =
-            static_registry_manifest_text(&metadata, &modules, &archives, &dependency_archives);
-        assert!(static_manifest.contains("archiveTargets=ios-simulator\n"));
-        assert!(static_manifest.contains("dependencyArchiveTargets=ios-simulator\n"));
-        assert!(static_manifest.contains("dependencyArchives=openssl\n"));
-        assert!(static_manifest.contains("module.acme_ext.archiveTargets=ios-simulator\n"));
-        assert!(static_manifest.contains(
-            "module.acme_ext.archive.ios-simulator=archives/ios-simulator/extensions/acme_ext/liboliphaunt_extension_acme_ext.a\n"
-        ));
-        assert!(static_manifest.contains("dependency.openssl.archiveTargets=ios-simulator\n"));
-        assert!(static_manifest.contains(
-            "dependency.openssl.archive.ios-simulator=archives/ios-simulator/dependencies/openssl/libcrypto.a\n"
-        ));
-
-        write_file(
-            &temp.join("oliphaunt/static-registry/manifest.properties"),
-            b"state=complete\n",
-        );
-        copy_portable_tree(&runtime_files, &temp.join("oliphaunt/runtime/files")).unwrap();
-        copy_portable_tree(
-            &temp.join("cluster-seed"),
-            &temp.join("oliphaunt/cluster-seed"),
-        )
-        .unwrap();
-        let report = runtime_resource_size_report(
-            &temp.join("oliphaunt"),
-            &extensions,
-            Some("test-target"),
-            &pending_metadata,
-        )
-        .unwrap();
-        assert_eq!(report.extensions.len(), 1);
-        assert_eq!(report.extensions[0].name, "acme_ext");
-        assert_eq!(report.extensions[0].file_count, 5);
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn runtime_resource_packaging_selects_the_engine_module_profile() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-engine-profiles");
-        let artifact = temp.join("acme_ext");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let extensions = resolve_runtime_resource_extensions(
-            &[],
-            &[NativePrebuiltExtensionArtifact::new(&artifact)],
-        )
-        .unwrap();
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        let module = format!("acme_ext{}", std::env::consts::DLL_SUFFIX);
-        let server_runtime = temp.join("server-runtime");
-        let direct_runtime = temp.join("direct-runtime");
-        let broker_runtime = temp.join("broker-runtime");
-
-        copy_prebuilt_extension_artifacts(
-            &server_runtime,
-            &extensions,
-            NativePackagingMode::NativeServer,
-            Some("test-target"),
-            &metadata,
-        )
-        .unwrap();
-        copy_prebuilt_extension_artifacts(
-            &direct_runtime,
-            &extensions,
-            NativePackagingMode::NativeDirect,
-            Some("test-target"),
-            &metadata,
-        )
-        .unwrap();
-        copy_prebuilt_extension_artifacts(
-            &broker_runtime,
-            &extensions,
-            NativePackagingMode::NativeBroker,
-            Some("test-target"),
-            &metadata,
-        )
-        .unwrap();
-
-        assert_eq!(
-            fs::read(server_runtime.join("lib/postgresql").join(&module)).unwrap(),
-            b"acme-module\n"
-        );
-        assert_eq!(
-            fs::read(direct_runtime.join("lib/postgresql").join(&module)).unwrap(),
-            b"acme-embedded-module\n"
-        );
-        assert_eq!(
-            fs::read(broker_runtime.join("lib/postgresql").join(&module)).unwrap(),
-            b"acme-embedded-module\n"
-        );
-
-        fs::remove_file(artifact.join("files/lib/modules").join(&module)).unwrap();
-        let error = copy_prebuilt_extension_artifacts(
-            &temp.join("missing-direct-runtime"),
-            &extensions,
-            NativePackagingMode::NativeDirect,
-            Some("test-target"),
-            &metadata,
-        )
-        .unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains(&format!("files/lib/modules/{module}")),
-            "unexpected missing native-direct profile error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_mobile_static_registry_skips_desktop_dynamic_module() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-mobile-static");
-        let artifact = temp.join("acme_ext");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            true,
-        );
-        let extensions = resolve_runtime_resource_extensions(
-            &[],
-            &[NativePrebuiltExtensionArtifact::new(&artifact)],
-        )
-        .unwrap();
-        let metadata =
-            mobile_static_registry_metadata(&extensions, &["acme_ext".to_owned()]).unwrap();
-        let runtime_files = temp.join("runtime/files");
-        copy_prebuilt_extension_artifacts(
-            &runtime_files,
-            &extensions,
-            NativePackagingMode::NativeDirect,
-            Some("ios-xcframework"),
-            &metadata,
-        )
-        .unwrap();
-
-        assert!(
-            runtime_files
-                .join("share/postgresql/extension/acme_ext.control")
-                .is_file()
-        );
-        assert!(
-            !runtime_files
-                .join("lib/postgresql")
-                .join(format!("acme_ext{}", std::env::consts::DLL_SUFFIX))
-                .exists(),
-            "mobile-static extension packaging must not copy a desktop dynamic module"
-        );
-        let root = temp.join("oliphaunt");
-        write_file(
-            &root.join("static-registry/manifest.properties"),
-            b"state=complete\n",
-        );
-        copy_portable_tree(&runtime_files, &root.join("runtime/files")).unwrap();
-        write_file(&root.join("cluster-seed/files/PG_VERSION"), b"18\n");
-        let report =
-            runtime_resource_size_report(&root, &extensions, Some("ios-xcframework"), &metadata)
-                .unwrap();
-        assert_eq!(report.extensions[0].file_count, 4);
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn runtime_resource_tree_generates_static_registry_from_packaged_prebuilt_sql() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-packaged-static-registry");
-        let base_runtime = temp.join("base-runtime");
-        let cluster_seed = temp.join("cluster-seed");
-        write_file(
-            &base_runtime.join("share/postgresql/postgresql.conf.sample"),
-            b"core-runtime\n",
-        );
-        write_file(
-            &base_runtime.join("share/postgresql/extension/plpgsql.control"),
-            b"comment = 'must not leak'\n",
-        );
-        write_file(
-            &base_runtime.join("share/postgresql/extension/plpgsql--1.0.sql"),
-            b"select 'must not leak';\n",
-        );
-        write_file(
-            &base_runtime.join("share/postgresql/extension/acme_ext--base.sql"),
-            b"select 'base acme must not shadow prebuilt';\n",
-        );
-        write_file(
-            &base_runtime
-                .join("lib/postgresql")
-                .join(format!("acme_ext{}", std::env::consts::DLL_SUFFIX)),
-            b"base-acme-module\n",
-        );
-        write_file(&cluster_seed.join("PG_VERSION"), b"18\n");
-
-        let artifact = temp.join("acme_ext");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            true,
-        );
-        let manifest = artifact.join("manifest.properties");
-        let alias_line = "staticSymbolAliases=acme_ext_echo:acme_static_acme_ext_echo,pg_finfo_acme_ext_echo:acme_static_pg_finfo_acme_ext_echo,helper_symbol:acme_static_helper_symbol\n";
-        let mut manifest_text = fs::read_to_string(&manifest).unwrap();
-        if manifest_text.contains("staticSymbolAliases=\n") {
-            manifest_text = manifest_text.replace("staticSymbolAliases=\n", alias_line);
-        } else {
-            manifest_text.push_str(alias_line);
-        }
-        write_file(&manifest, manifest_text.as_bytes());
-        let extensions = resolve_runtime_resource_extensions(
-            &[],
-            &[NativePrebuiltExtensionArtifact::new(&artifact)],
-        )
-        .unwrap();
-        let metadata =
-            mobile_static_registry_metadata(&extensions, &["acme_ext".to_owned()]).unwrap();
-
-        let root = temp.join("oliphaunt");
-        write_runtime_resource_tree(
-            &root,
-            NativePackagingMode::NativeServer,
-            &MaterializedNativeResources {
-                runtime_dir: base_runtime,
-                cluster_seed,
-                runtime_cache_key: "runtime-cache".to_owned(),
-                cluster_seed_cache_key: "template-cache".to_owned(),
-            },
-            &extensions,
-            &[],
-            &[],
-            &metadata,
-            Some("test-target"),
-        )
-        .unwrap();
-
-        let registry_source =
-            fs::read_to_string(root.join("static-registry/oliphaunt_static_registry.c")).unwrap();
-        assert!(registry_source.contains("liboliphaunt_selected_static_extensions"));
-        assert!(
-            registry_source.contains("acme_ext_echo"),
-            "static registry must parse SQL copied from the prebuilt extension artifact"
-        );
-        assert!(
-            registry_source.contains("extern void acme_static_acme_ext_echo(void);"),
-            "static registry must reference aliased link-time symbols"
-        );
-        assert!(
-            registry_source.contains(
-                "{ .name = \"acme_ext_echo\", .address = (void *)acme_static_acme_ext_echo }"
-            ),
-            "static registry must keep SQL symbol names while pointing at aliased symbols"
-        );
-        assert!(
-            registry_source.contains(
-                "{ .name = \"helper_symbol\", .address = (void *)acme_static_helper_symbol }"
-            ),
-            "static registry must include explicit aliases outside main extension SQL"
-        );
-        assert!(
-            root.join("runtime/files/share/postgresql/extension/acme_ext--1.0.sql")
-                .is_file(),
-            "prebuilt SQL must be part of the final runtime package"
-        );
-        assert!(
-            root.join("runtime/files/share/postgresql/extension/plpgsql.control")
-                .is_file(),
-            "PL/pgSQL control metadata is mandatory baseline runtime metadata"
-        );
-        assert!(
-            root.join("runtime/files/share/postgresql/extension/plpgsql--1.0.sql")
-                .is_file(),
-            "PL/pgSQL SQL metadata is mandatory baseline runtime metadata"
-        );
-        assert!(
-            !root
-                .join("runtime/files/share/postgresql/extension/acme_ext--base.sql")
-                .exists(),
-            "base runtime files for a prebuilt-selected extension must not shadow the exact artifact"
-        );
-        assert!(
-            !root
-                .join("runtime/files/lib/postgresql")
-                .join(format!("acme_ext{}", std::env::consts::DLL_SUFFIX))
-                .exists(),
-            "mobile-static prebuilt extensions must not retain base dynamic modules"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_rejects_missing_native_target() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-missing-target");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let manifest = artifact.join("manifest.properties");
-        let text = fs::read_to_string(&manifest).unwrap();
-        fs::write(
-            &manifest,
-            text.replace("nativeTarget=test-target\n", "nativeTarget=\n"),
-        )
-        .unwrap();
-
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error.to_string().contains("missing nativeTarget"),
-            "unexpected missing-target error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_requires_canonical_native_runtime_product() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-native-product");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let manifest = artifact.join("manifest.properties");
-        let canonical = fs::read_to_string(&manifest).unwrap();
-
-        fs::write(
-            &manifest,
-            canonical.replace(
-                "nativeRuntimeProduct=liboliphaunt-native\n",
-                "nativeRuntimeProduct=another-runtime\n",
-            ),
-        )
-        .unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("nativeRuntimeProduct='another-runtime', expected 'liboliphaunt-native'"),
-            "unexpected wrong-product error: {error}"
-        );
-
-        fs::write(
-            &manifest,
-            canonical.replace("nativeRuntimeProduct=liboliphaunt-native\n", ""),
-        )
-        .unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error.to_string().contains("missing=[nativeRuntimeProduct]"),
-            "unexpected missing-product error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_requires_stable_native_runtime_version() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-native-version");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let manifest = artifact.join("manifest.properties");
-        let canonical = fs::read_to_string(&manifest).unwrap();
-
-        fs::write(
-            &manifest,
-            canonical.replace(
-                "nativeRuntimeVersion=1.2.3\n",
-                "nativeRuntimeVersion=1.2.3-rc.1\n",
-            ),
-        )
-        .unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error.to_string().contains("stable semantic version"),
-            "unexpected prerelease-version error: {error}"
-        );
-
-        fs::write(
-            &manifest,
-            canonical.replace("nativeRuntimeVersion=1.2.3\n", ""),
-        )
-        .unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error.to_string().contains("missing=[nativeRuntimeVersion]"),
-            "unexpected missing-version error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_rejects_unknown_manifest_key() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-unknown-key");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let manifest = artifact.join("manifest.properties");
-        let mut text = fs::read_to_string(&manifest).unwrap();
-        text.push_str("futureCompatibilityGuess=yes\n");
-        fs::write(&manifest, text).unwrap();
-
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("unknown=[futureCompatibilityGuess]"),
-            "unexpected unknown-key error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_requires_canonical_ancillary_sql_fields() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-ancillary-sql-fields");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let manifest = artifact.join("manifest.properties");
-        let canonical = fs::read_to_string(&manifest).unwrap();
-
-        fs::write(
-            &manifest,
-            canonical.replace(
-                "extensionSqlFileNames=\n",
-                "extensionSqlFileNames=z.sql,a.sql\n",
-            ),
-        )
-        .unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("extensionSqlFileNames must be sorted and unique"),
-            "unexpected unsorted ancillary-SQL error: {error}"
-        );
-
-        fs::write(
-            &manifest,
-            canonical.replace(
-                "extensionSqlFilePrefixes=\n",
-                "extensionSqlFilePrefixes=acme_,acme_\n",
-            ),
-        )
-        .unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("extensionSqlFilePrefixes must be sorted and unique"),
-            "unexpected duplicate ancillary-SQL-prefix error: {error}"
-        );
-
-        let reordered = canonical.replace(
-            "extensionSqlFileNames=\nextensionSqlFilePrefixes=\n",
-            "extensionSqlFilePrefixes=\nextensionSqlFileNames=\n",
-        );
-        fs::write(&manifest, reordered).unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("line 12 must be canonical field extensionSqlFileNames"),
-            "unexpected reordered-field error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_rejects_noncanonical_boolean_values() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-noncanonical-bool");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let manifest = artifact.join("manifest.properties");
-        let canonical = fs::read_to_string(&manifest).unwrap();
-
-        fs::write(
-            &manifest,
-            canonical.replace("createsExtension=yes\n", "createsExtension=true\n"),
-        )
-        .unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("createsExtension='true', expected canonical yes/no"),
-            "unexpected createsExtension boolean error: {error}"
-        );
-
-        fs::write(
-            &manifest,
-            canonical.replace("mobilePrebuilt=no\n", "mobilePrebuilt=false\n"),
-        )
-        .unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("mobilePrebuilt='false', expected canonical yes/no"),
-            "unexpected mobilePrebuilt boolean error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_packaging_requires_selected_native_runtime_version() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-selected-version-required");
-        let artifact = temp.join("artifact-root");
-        let output = temp.join("output");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-
-        let error = build_native_runtime_resources(
-            NativeRuntimeResourceOptions::new(&output).prebuilt_extension(&artifact),
-        )
-        .unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("requires an exact stable liboliphaunt-native version"),
-            "unexpected missing selected-version error: {error}"
-        );
-        assert!(!output.exists(), "validation must precede materialization");
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_packaging_rejects_wrong_native_runtime_version_before_materialization() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-wrong-native-version");
-        let artifact = temp.join("artifact-root");
-        let output = temp.join("output");
-        write_prebuilt_extension_artifact_for_runtime(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-            "1.2.4",
-        );
-
-        let error = build_native_runtime_resources(
-            NativeRuntimeResourceOptions::new(&output)
-                .prebuilt_extension(&artifact)
-                .native_runtime_version("1.2.3"),
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains(
-                "requires liboliphaunt-native version '1.2.4', but runtime packaging selected '1.2.3'"
-            ),
-            "unexpected mismatched-version error: {error}"
-        );
-        assert!(!output.exists(), "validation must precede materialization");
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_packaging_rejects_mixed_native_runtime_versions() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-mixed-native-versions");
-        let first = temp.join("first");
-        let second = temp.join("second");
-        let output = temp.join("output");
-        write_prebuilt_extension_artifact_for_runtime(
-            &first,
-            "acme_a",
-            "acme_a",
-            "acme_static_a",
-            "data/acme_a.rules",
-            false,
-            "1.2.3",
-        );
-        write_prebuilt_extension_artifact_for_runtime(
-            &second,
-            "acme_b",
-            "acme_b",
-            "acme_static_b",
-            "data/acme_b.rules",
-            false,
-            "1.2.4",
-        );
-
-        let error = build_native_runtime_resources(
-            NativeRuntimeResourceOptions::new(&output)
-                .prebuilt_extensions(vec![first, second])
-                .native_runtime_version("1.2.3"),
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains("artifact for 'acme_b'")
-                && error.to_string().contains("version '1.2.4'")
-                && error.to_string().contains("selected '1.2.3'"),
-            "unexpected mixed-version error: {error}"
-        );
-        assert!(!output.exists(), "validation must precede materialization");
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_rejects_wrong_runtime_target() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-wrong-target");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let extensions = resolve_runtime_resource_extensions(
-            &[],
-            &[NativePrebuiltExtensionArtifact::new(&artifact)],
-        )
-        .unwrap();
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        let error = copy_prebuilt_extension_artifacts(
-            &temp.join("runtime/files"),
-            &extensions,
-            NativePackagingMode::NativeServer,
-            Some("linux-x64-gnu"),
-            &metadata,
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains(
-                "prebuilt extension artifact for 'acme_ext' targets 'test-target', but runtime packaging target is 'linux-x64-gnu'"
-            ),
-            "unexpected wrong-target error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn mobile_static_prebuilt_extension_rejects_wrong_runtime_target_before_materialization() {
-        let temp = unique_temp_root("oliphaunt-mobile-static-prebuilt-wrong-target");
-        let artifact = temp.join("artifact-root");
-        let output = temp.join("output");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            true,
-        );
-
-        let error = build_native_runtime_resources(
-            NativeRuntimeResourceOptions::new(&output)
-                .prebuilt_extension(&artifact)
-                .native_runtime_version("1.2.3")
-                .extension_target("ios-simulator")
-                .mobile_static_module_stems(vec!["acme_ext".to_owned()]),
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains(
-                "prebuilt extension artifact for 'acme_ext' targets 'test-target', but runtime packaging target is 'ios-simulator'"
-            ),
-            "unexpected mobile-static wrong-target error: {error}"
-        );
-        assert!(!output.exists(), "validation must precede materialization");
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_tar_archive_is_validated_and_consumed() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext.tar");
-        write_tar_archive_from_dir(&archive, &artifact, "acme_ext");
-
-        let prepared =
-            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-                &archive,
-            )])
-            .unwrap();
-        let extensions = resolve_runtime_resource_extensions(&[], prepared.artifacts()).unwrap();
-        assert_eq!(selected_extension_names(&extensions), vec!["acme_ext"]);
-        assert_eq!(
-            extensions[0].native_module_stem.as_deref(),
-            Some("acme_ext")
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_nested_archive_rejects_top_level_file_sibling() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-file-sibling");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext-with-file-sibling.tar");
-        write_tar_archive_from_dir_with_top_level_sibling(
-            &archive,
-            &artifact,
-            "acme_ext",
-            "undeclared.txt",
-            false,
-        );
-
-        let error =
-            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-                &archive,
-            )])
-            .unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("exactly one top-level directory with no sibling entries"),
-            "unexpected top-level file sibling error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_nested_archive_rejects_top_level_directory_sibling() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-directory-sibling");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext-with-directory-sibling.tar");
-        write_tar_archive_from_dir_with_top_level_sibling(
-            &archive,
-            &artifact,
-            "acme_ext",
-            "undeclared",
-            true,
-        );
-
-        let error =
-            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-                &archive,
-            )])
-            .unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("exactly one top-level directory with no sibling entries"),
-            "unexpected top-level directory sibling error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_archive_rejects_noncanonical_legal_header_modes() {
-        for (case, member) in [
-            ("root-license", "acme_ext/LICENSE"),
-            (
-                "declared-upstream-license",
-                "acme_ext/files/share/licenses/acme_ext/LICENSE",
-            ),
-        ] {
-            let temp = unique_temp_root(&format!(
-                "oliphaunt-prebuilt-extension-tar-legal-mode-{case}"
-            ));
-            let artifact = temp.join("artifact-root");
-            write_prebuilt_extension_artifact(
-                &artifact,
-                "acme_ext",
-                "acme_ext",
-                "acme_static",
-                "data/acme_ext.rules",
-                false,
-            );
-            let archive = temp.join(format!("acme_ext-{case}.tar"));
-            write_tar_archive_from_dir(&archive, &artifact, "acme_ext");
-            rewrite_tar_archive_member_mode(&archive, Path::new(member), 0o600);
-
-            let error = PreparedPrebuiltExtensionArtifacts::prepare(&[
-                NativePrebuiltExtensionArtifact::new(&archive),
-            ])
-            .unwrap_err();
-            assert!(
-                error.to_string().contains(&format!(
-                    "legal member {member} must have exact tar header mode 0644, got 0600"
-                )),
-                "unexpected {case} legal header-mode error: {error}"
-            );
-
-            let _ = fs::remove_dir_all(temp);
-        }
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_rejects_mobile_archive_path_escape() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-mobile-path");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            true,
-        );
-        let wrong_relative = "files/lib/postgresql/liboliphaunt_extension_acme_ext.a";
-        write_file(&artifact.join(wrong_relative), b"wrong-place-static\n");
-        let manifest = artifact.join("manifest.properties");
-        let text = fs::read_to_string(&manifest).unwrap();
-        fs::write(
-            &manifest,
-            text.replace(
-                "mobileStaticArchives=ios-simulator:mobile-static/ios-simulator/extensions/acme_ext/liboliphaunt_extension_acme_ext.a\n",
-                &format!("mobileStaticArchives=ios-simulator:{wrong_relative}\n"),
-            ),
-        )
-        .unwrap();
-
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error.to_string().contains("must use mobile-static"),
-            "unexpected mobile archive path error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_tar_zst_archive_is_validated_and_consumed() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-zst");
-        let artifact = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext.tar.zst");
-        write_tar_zst_archive_from_dir(&archive, &artifact, "acme_ext");
-
-        let prepared =
-            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-                &archive,
-            )])
-            .unwrap();
-        let extensions = resolve_runtime_resource_extensions(&[], prepared.artifacts()).unwrap();
-        assert_eq!(selected_extension_names(&extensions), vec!["acme_ext"]);
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_archive_rejects_non_file_entries() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-symlink");
-        let archive_path = temp.join("malicious.tar");
-        let mut bytes = Vec::new();
-        {
-            let mut archive = tar::Builder::new(&mut bytes);
-            let mut header = tar::Header::new_gnu();
-            header.set_entry_type(EntryType::symlink());
-            header.set_path("manifest.properties").unwrap();
-            header.set_link_name("/tmp/not-allowed").unwrap();
-            header.set_mode(0o777);
-            header.set_size(0);
-            header.set_cksum();
-            archive.append(&header, std::io::empty()).unwrap();
-            archive.finish().unwrap();
-        }
-        write_file(&archive_path, &bytes);
-
-        let error =
-            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-                &archive_path,
-            )])
-            .unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("must be a regular file or directory"),
-            "unexpected symlink-entry error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn extension_artifact_archive_policy_covers_observed_android_postgis_shape() {
-        let policy = extension_artifact_archive_policy().unwrap();
-        assert_eq!(policy.max_compressed_bytes, 128 * 1024 * 1024);
-        assert_eq!(policy.max_expanded_bytes, 512 * 1024 * 1024);
-        assert_eq!(policy.max_member_bytes, 256 * 1024 * 1024);
-        assert_eq!(policy.max_members, 4096);
-
-        // Exact high-water marks from the qualified Android ARM64 PostGIS leaf
-        // artifact that exposed the former 48/256 MiB consumer-only limits.
-        assert!(64_676_748 <= policy.max_compressed_bytes);
-        assert!(345_621_694 <= policy.max_expanded_bytes);
-        assert!(154_827_564 <= policy.max_member_bytes);
-        assert!(27 <= policy.max_members);
-
-        let root = Path::new("android-arm64-v8a/postgis");
-        let mut shape = ExtensionArtifactArchiveShape {
-            member_count: 0,
-            expanded_bytes: 1024,
-        };
-        let mut observed_member_sizes = vec![154_827_564, 110_259_522, 80_534_608];
-        observed_member_sizes.resize(27, 0);
-        for (index, bytes) in observed_member_sizes.into_iter().enumerate() {
-            record_extension_artifact_archive_member(
-                root,
-                Path::new(&format!("member-{index}.bin")),
-                bytes,
-                policy,
-                &mut shape,
-            )
-            .unwrap();
-        }
-        assert_eq!(shape.member_count, 27);
-        assert!(shape.expanded_bytes <= policy.max_expanded_bytes);
-
-        let error = record_extension_artifact_archive_member(
-            root,
-            Path::new("too-large.bin"),
-            policy.max_member_bytes + 1,
-            policy,
-            &mut ExtensionArtifactArchiveShape {
-                member_count: 0,
-                expanded_bytes: 1024,
-            },
-        )
-        .unwrap_err();
-        assert!(error.to_string().contains("exceeds 268435456 bytes"));
-    }
-
-    #[test]
-    fn prebuilt_extension_archive_rejects_oversized_members_before_extraction() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-oversized-member");
-        let archive_path = temp.join("oversized.tar");
-        fs::create_dir_all(&temp).unwrap();
-        let policy = extension_artifact_archive_policy().unwrap();
-        let mut header = tar::Header::new_ustar();
-        header.set_entry_type(EntryType::Regular);
-        header.set_path("files/oversized.bin").unwrap();
-        header.set_mode(0o644);
-        header.set_size(policy.max_member_bytes + 1);
-        header.set_cksum();
-        let mut bytes = header.as_bytes().to_vec();
-        bytes.extend_from_slice(&[0u8; 1024]);
-        write_file(&archive_path, &bytes);
-
-        let error =
-            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-                &archive_path,
-            )])
-            .unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("member larger than 268435456 bytes"),
-            "unexpected oversized-member error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_archive_rejects_oversized_compressed_carriers_before_decoding() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-tar-oversized-compressed");
-        let archive_path = temp.join("oversized.tar.gz");
-        fs::create_dir_all(&temp).unwrap();
-        let file = File::create(&archive_path).unwrap();
-        let policy = extension_artifact_archive_policy().unwrap();
-        file.set_len(policy.max_compressed_bytes + 1).unwrap();
-
-        let error =
-            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-                &archive_path,
-            )])
-            .unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("must contain between 1 and 134217728 bytes"),
-            "unexpected oversized-carrier error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn production_extension_legal_profiles_load_with_exact_leaf_inventories() {
-        let temp = unique_temp_root("oliphaunt-extension-legal-profiles");
-        let cube = temp.join("cube");
-        write_profiled_extension_artifact(
-            &cube,
-            "cube",
-            "cube",
-            "linux-x64-gnu",
-            NativeExtensionArtifactLicenseProfile::ContribNative,
-            &[],
-        );
-        let loaded = load_prebuilt_extension_artifact(&cube).unwrap();
-        assert_eq!(
-            loaded.license_profile,
-            Some(NativeExtensionArtifactLicenseProfile::ContribNative)
-        );
-        assert!(loaded.license_files.is_empty());
-
-        let pgcrypto = temp.join("pgcrypto");
-        write_profiled_extension_artifact(
-            &pgcrypto,
-            "pgcrypto",
-            "pgcrypto",
-            "macos-arm64",
-            NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl,
-            &[],
-        );
-        let loaded = load_prebuilt_extension_artifact(&pgcrypto).unwrap();
-        assert_eq!(
-            loaded.license_profile,
-            Some(NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl)
-        );
-
-        let postgis = temp.join("postgis");
-        let postgis_licenses = [
-            "share/licenses/geos/COPYING",
-            "share/licenses/postgis/COPYING",
-        ];
-        write_profiled_extension_artifact(
-            &postgis,
-            "postgis",
-            "postgis-3",
-            "linux-x64-gnu",
-            NativeExtensionArtifactLicenseProfile::ExternalNative,
-            &postgis_licenses,
-        );
-        let loaded = load_prebuilt_extension_artifact(&postgis).unwrap();
-        assert_eq!(
-            loaded.license_profile,
-            Some(NativeExtensionArtifactLicenseProfile::ExternalNative)
-        );
-        assert_eq!(
-            loaded.license_files,
-            postgis_licenses.map(PathBuf::from).to_vec()
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_rejects_missing_extra_unsafe_and_wrong_profile_legal_files() {
-        let temp = unique_temp_root("oliphaunt-extension-legal-adversarial");
-
-        let missing = temp.join("missing");
-        write_profiled_extension_artifact(
-            &missing,
-            "postgis",
-            "postgis-3",
-            "linux-x64-gnu",
-            NativeExtensionArtifactLicenseProfile::ExternalNative,
-            &["share/licenses/postgis/COPYING"],
-        );
-        fs::remove_file(missing.join("files/share/licenses/postgis/COPYING")).unwrap();
-        let error = load_prebuilt_extension_artifact(&missing).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("leaf inventory mismatch; missing: files/share/licenses/postgis/COPYING"),
-            "unexpected missing legal leaf error: {error}"
-        );
-
-        let extra = temp.join("extra");
-        write_profiled_extension_artifact(
-            &extra,
-            "cube",
-            "cube",
-            "linux-x64-gnu",
-            NativeExtensionArtifactLicenseProfile::ContribNative,
-            &[],
-        );
-        write_file(
-            &extra.join("THIRD_PARTY_LICENSES/undeclared.txt"),
-            b"undeclared\n",
-        );
-        let error = load_prebuilt_extension_artifact(&extra).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("undeclared: THIRD_PARTY_LICENSES/undeclared.txt"),
-            "unexpected extra legal leaf error: {error}"
-        );
-
-        let unsafe_path = temp.join("unsafe");
-        write_profiled_extension_artifact(
-            &unsafe_path,
-            "postgis",
-            "postgis-3",
-            "linux-x64-gnu",
-            NativeExtensionArtifactLicenseProfile::ExternalNative,
-            &["share/licenses/postgis/COPYING"],
-        );
-        let manifest = unsafe_path.join("manifest.properties");
-        let text = fs::read_to_string(&manifest).unwrap().replace(
-            "licenseFiles=share/licenses/postgis/COPYING\n",
-            "licenseFiles=../outside-license\n",
-        );
-        fs::write(&manifest, text).unwrap();
-        let error = load_prebuilt_extension_artifact(&unsafe_path).unwrap_err();
-        assert!(
-            error
-                .to_string()
-                .contains("contains path component \"..\" that is unsafe on supported build hosts"),
-            "unexpected unsafe legal path error: {error}"
-        );
-
-        let wrong_profile = temp.join("wrong-profile");
-        write_profiled_extension_artifact(
-            &wrong_profile,
-            "cube",
-            "cube",
-            "linux-x64-gnu",
-            NativeExtensionArtifactLicenseProfile::ContribNative,
-            &[],
-        );
-        let manifest = wrong_profile.join("manifest.properties");
-        let text = fs::read_to_string(&manifest).unwrap().replace(
-            "licenseProfile=contrib-native\n",
-            "licenseProfile=external-native\n",
-        );
-        fs::write(&manifest, text).unwrap();
-        let error = load_prebuilt_extension_artifact(&wrong_profile).unwrap_err();
-        assert!(
-            error.to_string().contains("expected 'contrib-native'"),
-            "unexpected wrong legal profile error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[cfg(unix)]
-    #[test]
-    fn prebuilt_extension_rejects_noncanonical_legal_file_mode() {
-        use std::os::unix::fs::PermissionsExt;
-
-        let temp = unique_temp_root("oliphaunt-extension-legal-mode");
-        let artifact = temp.join("cube");
-        write_profiled_extension_artifact(
-            &artifact,
-            "cube",
-            "cube",
-            "linux-x64-gnu",
-            NativeExtensionArtifactLicenseProfile::ContribNative,
-            &[],
-        );
-        fs::set_permissions(artifact.join("LICENSE"), fs::Permissions::from_mode(0o600)).unwrap();
-        let error = load_prebuilt_extension_artifact(&artifact).unwrap_err();
-        assert!(
-            error.to_string().contains("LICENSE must have mode 0644"),
-            "unexpected legal mode error: {error}"
-        );
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn create_prebuilt_extension_artifact_copies_only_exact_declared_runtime_files() {
-        let temp = unique_temp_root("oliphaunt-create-prebuilt-extension-artifact");
-        let runtime = temp.join("runtime");
-        write_extension_source_runtime(&runtime, "acme_ext", "acme_ext.so");
-        write_file(
-            &runtime.join("share/postgresql/extension/hstore.control"),
-            b"comment = 'should not leak'\n",
-        );
-        write_file(
-            &runtime.join("share/postgresql/extension/uninstall_acme_ext.sql"),
-            b"-- carrier-declared ancillary SQL\n",
-        );
-        write_file(
-            &runtime.join("share/postgresql/extension/acme_aux--1.0.sql"),
-            b"-- carrier-declared ancillary SQL family\n",
-        );
-        write_file(
-            &runtime.join("share/postgresql/data/unused.rules"),
-            b"unused\n",
-        );
-        let ios_archive = temp.join("liboliphaunt_extension_acme_ext_ios_simulator.a");
-        write_file(&ios_archive, b"acme-ios-simulator-static\n");
-        let ios_dependency_archive = temp.join("libcrypto.a");
-        write_file(&ios_dependency_archive, b"acme-ios-simulator-libcrypto\n");
-        let artifact_root = temp.join("artifact");
-
-        let created = create_prebuilt_extension_artifact(
-            NativeExtensionArtifactOptions::new(&artifact_root, &runtime, "acme_ext", "1.2.3")
-                .native_module_stem("acme_ext")
-                .native_module_file("acme_ext.so")
-                .native_target("test-target")
-                .dependency("cube")
-                .data_file("data/acme_ext.rules")
-                .extension_sql_file_name("uninstall_acme_ext.sql")
-                .extension_sql_file_prefix("acme_aux--")
-                .shared_preload_library("acme_preload")
-                .mobile_prebuilt(true)
-                .mobile_static_archive("ios-simulator", &ios_archive)
-                .mobile_static_dependency_archive(
-                    "ios-simulator",
-                    "openssl",
-                    &ios_dependency_archive,
-                )
-                .static_symbol_prefix("acme_static")
-                .legal_contract(write_external_legal_contract(&temp, "acme_ext")),
-        )
-        .unwrap();
-
-        assert_eq!(created.path, artifact_root);
-        assert_eq!(created.sql_name, "acme_ext");
-        assert_eq!(
-            created.license_profile,
-            NativeExtensionArtifactLicenseProfile::ExternalNative
-        );
-        assert_eq!(
-            created.license_files,
-            vec![PathBuf::from("share/licenses/acme_ext/LICENSE")]
-        );
-        assert_eq!(created.format, NativeExtensionArtifactFormat::Directory);
-        assert!(created.manifest_path.unwrap().is_file());
-        let manifest = fs::read_to_string(artifact_root.join("manifest.properties")).unwrap();
-        assert!(manifest.contains("packageLayout=oliphaunt-extension-artifact-v1\n"));
-        assert!(manifest.contains("sqlName=acme_ext\n"));
-        assert!(manifest.contains("nativeModuleStem=acme_ext\n"));
-        assert!(manifest.contains("nativeModuleFile=acme_ext.so\n"));
-        assert!(manifest.contains("nativeTarget=test-target\n"));
-        assert!(manifest.contains("nativeRuntimeProduct=liboliphaunt-native\n"));
-        assert!(manifest.contains("nativeRuntimeVersion=1.2.3\n"));
-        assert!(manifest.contains("dependencies=cube\n"));
-        assert!(manifest.contains("dataFiles=data/acme_ext.rules\n"));
-        assert!(manifest.contains("extensionSqlFileNames=uninstall_acme_ext.sql\n"));
-        assert!(manifest.contains("extensionSqlFilePrefixes=acme_aux--\n"));
-        assert!(manifest.contains("sharedPreloadLibraries=acme_preload\n"));
-        assert!(manifest.contains("mobilePrebuilt=yes\n"));
-        assert!(manifest.contains(
-            "mobileStaticArchives=ios-simulator:mobile-static/ios-simulator/extensions/acme_ext/liboliphaunt_extension_acme_ext.a\n"
-        ));
-        assert!(manifest.contains(
-            "mobileStaticDependencyArchives=ios-simulator:openssl:mobile-static/ios-simulator/dependencies/openssl/libcrypto.a\n"
-        ));
-        assert!(manifest.contains("staticSymbolPrefix=acme_static\n"));
-        assert!(manifest.contains("licenseFiles=share/licenses/acme_ext/LICENSE\n"));
-        assert!(manifest.contains("licenseProfile=external-native\n"));
-        let parsed_manifest = parse_canonical_properties_manifest(
-            &artifact_root.join("manifest.properties"),
-            &manifest,
-            &EXTENSION_ARTIFACT_MANIFEST_KEYS,
-        )
-        .unwrap();
-        assert_eq!(
-            parsed_manifest
-                .keys()
-                .map(String::as_str)
-                .collect::>(),
-            EXTENSION_ARTIFACT_MANIFEST_KEYS
-                .iter()
-                .copied()
-                .collect::>()
-        );
-        assert!(
-            artifact_root
-                .join("files/share/postgresql/extension/acme_ext.control")
-                .is_file()
-        );
-        assert!(
-            artifact_root
-                .join("files/share/postgresql/extension/acme_ext--1.0.sql")
-                .is_file()
-        );
-        assert!(
-            artifact_root
-                .join("files/share/postgresql/extension/uninstall_acme_ext.sql")
-                .is_file()
-        );
-        assert!(
-            artifact_root
-                .join("files/share/postgresql/extension/acme_aux--1.0.sql")
-                .is_file()
-        );
-        assert!(
-            artifact_root
-                .join("files/lib/postgresql/acme_ext.so")
-                .is_file()
-        );
-        assert!(
-            artifact_root
-                .join("mobile-static/ios-simulator/extensions/acme_ext/liboliphaunt_extension_acme_ext.a")
-                .is_file()
-        );
-        assert!(
-            artifact_root
-                .join("mobile-static/ios-simulator/dependencies/openssl/libcrypto.a")
-                .is_file()
-        );
-        assert!(artifact_root.join("LICENSE").is_file());
-        assert!(artifact_root.join("THIRD_PARTY_NOTICES.md").is_file());
-        assert!(
-            artifact_root
-                .join("files/share/licenses/acme_ext/LICENSE")
-                .is_file()
-        );
-        assert!(
-            !artifact_root
-                .join("files/share/postgresql/extension/hstore.control")
-                .exists()
-        );
-        assert!(
-            !artifact_root
-                .join("files/share/postgresql/data/unused.rules")
-                .exists()
-        );
-
-        let loaded = load_prebuilt_extension_artifact(&artifact_root).unwrap();
-        assert_eq!(loaded.sql_name, "acme_ext");
-        assert_eq!(loaded.native_module_file.as_deref(), Some("acme_ext.so"));
-        assert_eq!(loaded.native_target.as_deref(), Some("test-target"));
-        assert_eq!(loaded.native_runtime_version.as_deref(), Some("1.2.3"));
-        assert_eq!(loaded.dependencies, vec!["cube"]);
-        assert_eq!(
-            loaded.extension_sql_file_names,
-            vec!["uninstall_acme_ext.sql"]
-        );
-        assert_eq!(loaded.extension_sql_file_prefixes, vec!["acme_aux--"]);
-        assert_eq!(loaded.shared_preload_libraries, vec!["acme_preload"]);
-        assert!(loaded.mobile_prebuilt);
-        assert_eq!(
-            mobile_static_archive_targets(&loaded.mobile_static_archives),
-            vec!["ios-simulator"]
-        );
-        assert_eq!(loaded.mobile_static_dependency_archives.len(), 1);
-        assert_eq!(
-            loaded.license_profile,
-            Some(NativeExtensionArtifactLicenseProfile::ExternalNative)
-        );
-        assert_eq!(
-            loaded.license_files,
-            vec![PathBuf::from("share/licenses/acme_ext/LICENSE")]
-        );
-        assert_eq!(
-            loaded.mobile_static_dependency_archives[0].relative_path,
-            PathBuf::from("mobile-static/ios-simulator/dependencies/openssl/libcrypto.a")
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn desktop_extension_artifact_carries_distinct_server_and_embedded_modules() {
-        let temp = unique_temp_root("oliphaunt-create-desktop-extension-profiles");
-        let runtime = temp.join("runtime");
-        let embedded_modules = temp.join("embedded-modules");
-        write_extension_source_runtime(&runtime, "acme_ext", "acme_ext.so");
-        write_file(
-            &runtime.join("lib/postgresql/acme_ext.so"),
-            b"server-profile-module\n",
-        );
-        write_file(
-            &embedded_modules.join("acme_ext.so"),
-            b"embedded-profile-module\n",
-        );
-        let artifact_root = temp.join("artifact");
-
-        create_prebuilt_extension_artifact(
-            NativeExtensionArtifactOptions::new(&artifact_root, &runtime, "acme_ext", "1.2.3")
-                .native_module_stem("acme_ext")
-                .native_module_file("acme_ext.so")
-                .native_target("linux-x64-gnu")
-                .embedded_module_root(&embedded_modules)
-                .legal_contract(write_external_legal_contract(&temp, "acme_ext")),
-        )
-        .unwrap();
-
-        assert_eq!(
-            fs::read(artifact_root.join("files/lib/postgresql/acme_ext.so")).unwrap(),
-            b"server-profile-module\n"
-        );
-        assert_eq!(
-            fs::read(artifact_root.join("files/lib/modules/acme_ext.so")).unwrap(),
-            b"embedded-profile-module\n"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn desktop_extension_artifact_rejects_a_missing_embedded_module_profile() {
-        let temp = unique_temp_root("oliphaunt-create-desktop-extension-missing-profile");
-        let runtime = temp.join("runtime");
-        write_extension_source_runtime(&runtime, "acme_ext", "acme_ext.so");
-
-        let error = create_prebuilt_extension_artifact(
-            NativeExtensionArtifactOptions::new(
-                temp.join("artifact"),
-                &runtime,
-                "acme_ext",
-                "1.2.3",
-            )
-            .native_module_stem("acme_ext")
-            .native_module_file("acme_ext.so")
-            .native_target("macos-arm64"),
-        )
-        .unwrap_err();
-
-        assert!(
-            error
-                .to_string()
-                .contains("desktop prebuilt extension artifacts with nativeModuleStem must declare an embedded module root"),
-            "unexpected missing embedded profile error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn create_prebuilt_extension_tar_zst_artifact_roundtrips_through_consumer() {
-        let temp = unique_temp_root("oliphaunt-create-prebuilt-extension-tar-zst");
-        let runtime = temp.join("runtime");
-        write_extension_source_runtime(
-            &runtime,
-            "acme_ext",
-            &format!("acme_ext{}", std::env::consts::DLL_SUFFIX),
-        );
-        write_file(
-            &runtime.join("share/postgresql/extension/hstore.control"),
-            b"comment = 'should not leak'\n",
-        );
-        let archive = temp.join("acme_ext.tar.zst");
-
-        let created = create_prebuilt_extension_artifact(
-            NativeExtensionArtifactOptions::new(&archive, &runtime, "acme_ext", "1.2.3")
-                .native_module_stem("acme_ext")
-                .native_target("test-target")
-                .data_file("data/acme_ext.rules")
-                .format(NativeExtensionArtifactFormat::TarZst)
-                .legal_contract(write_external_legal_contract(&temp, "acme_ext")),
-        )
-        .unwrap();
-        assert_eq!(created.path, archive);
-        assert_eq!(created.format, NativeExtensionArtifactFormat::TarZst);
-        assert!(created.manifest_path.is_none());
-
-        let prepared =
-            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-                &created.path,
-            )])
-            .unwrap();
-        let extensions = resolve_runtime_resource_extensions(&[], prepared.artifacts()).unwrap();
-        assert_eq!(selected_extension_names(&extensions), vec!["acme_ext"]);
-
-        let runtime_files = temp.join("packaged-runtime");
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        copy_prebuilt_extension_artifacts(
-            &runtime_files,
-            &extensions,
-            NativePackagingMode::NativeServer,
-            Some("test-target"),
-            &metadata,
-        )
-        .unwrap();
-        assert!(
-            runtime_files
-                .join("share/postgresql/extension/acme_ext.control")
-                .is_file()
-        );
-        assert!(
-            !runtime_files
-                .join("share/postgresql/extension/hstore.control")
-                .exists(),
-            "producer archives must preserve selected-only consumer behavior"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn create_prebuilt_extension_tar_gz_artifact_roundtrips_through_consumer() {
-        let temp = unique_temp_root("oliphaunt-create-prebuilt-extension-tar-gz");
-        let runtime = temp.join("runtime");
-        write_extension_source_runtime(
-            &runtime,
-            "acme_ext",
-            &format!("acme_ext{}", std::env::consts::DLL_SUFFIX),
-        );
-        write_file(
-            &runtime.join("share/postgresql/extension/hstore.control"),
-            b"comment = 'should not leak'\n",
-        );
-        let archive = temp.join("acme_ext.tar.gz");
-
-        let created = create_prebuilt_extension_artifact(
-            NativeExtensionArtifactOptions::new(&archive, &runtime, "acme_ext", "1.2.3")
-                .native_module_stem("acme_ext")
-                .native_target("test-target")
-                .data_file("data/acme_ext.rules")
-                .format(NativeExtensionArtifactFormat::TarGz)
-                .legal_contract(write_external_legal_contract(&temp, "acme_ext")),
-        )
-        .unwrap();
-        assert_eq!(created.path, archive);
-        assert_eq!(created.format, NativeExtensionArtifactFormat::TarGz);
-        assert!(created.manifest_path.is_none());
-
-        let prepared =
-            PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new(
-                &created.path,
-            )])
-            .unwrap();
-        let extensions = resolve_runtime_resource_extensions(&[], prepared.artifacts()).unwrap();
-        assert_eq!(selected_extension_names(&extensions), vec!["acme_ext"]);
-
-        let runtime_files = temp.join("packaged-runtime");
-        let metadata = mobile_static_registry_metadata(&extensions, &[]).unwrap();
-        copy_prebuilt_extension_artifacts(
-            &runtime_files,
-            &extensions,
-            NativePackagingMode::NativeServer,
-            Some("test-target"),
-            &metadata,
-        )
-        .unwrap();
-        assert!(
-            runtime_files
-                .join("share/postgresql/extension/acme_ext.control")
-                .is_file()
-        );
-        assert!(
-            !runtime_files
-                .join("share/postgresql/extension/hstore.control")
-                .exists(),
-            "gzip producer archives must preserve selected-only consumer behavior"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn extension_artifact_index_resolves_verified_dependency_closure() {
-        let temp = unique_temp_root("oliphaunt-extension-artifact-index");
-        let dep_artifact_root = temp.join("dep-root");
-        write_prebuilt_extension_artifact(
-            &dep_artifact_root,
-            "acme_dep",
-            "acme_dep",
-            "acme_dep_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let dep_archive = temp.join("acme_dep.tar.zst");
-        write_tar_zst_archive_from_dir(&dep_archive, &dep_artifact_root, "acme_dep");
-
-        let ext_artifact_root = temp.join("ext-root");
-        write_prebuilt_extension_artifact(
-            &ext_artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let manifest = ext_artifact_root.join("manifest.properties");
-        let text = fs::read_to_string(&manifest).unwrap();
-        fs::write(
-            &manifest,
-            text.replace("dependencies=\n", "dependencies=acme_dep\n"),
-        )
-        .unwrap();
-        let ext_archive = temp.join("acme_ext.tar.zst");
-        write_tar_zst_archive_from_dir(&ext_archive, &ext_artifact_root, "acme_ext");
-
-        let index = temp.join("extensions.toml");
-        write_extension_artifact_index(
-            &index,
-            "test-target",
-            &[("acme_dep", &dep_archive), ("acme_ext", &ext_archive)],
-        );
-
-        let resolution = resolve_prebuilt_extension_artifacts_from_indexes(
-            NativeExtensionArtifactIndexOptions::new("test-target")
-                .index(&index)
-                .extension("acme_ext"),
-        )
-        .unwrap();
-        assert_eq!(resolution.extension_names, vec!["acme_dep", "acme_ext"]);
-        assert_eq!(resolution.artifacts.len(), 2);
-        assert_eq!(resolution.artifacts[0].root, dep_archive);
-        assert_eq!(resolution.artifacts[1].root, ext_archive);
-
-        let prepared = PreparedPrebuiltExtensionArtifacts::prepare(&resolution.artifacts).unwrap();
-        let extensions = resolve_runtime_resource_extensions(&[], prepared.artifacts()).unwrap();
-        assert_eq!(
-            selected_extension_names(&extensions),
-            vec!["acme_dep", "acme_ext"]
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn create_extension_artifact_index_writes_canonical_verified_toml() {
-        let temp = unique_temp_root("oliphaunt-create-extension-artifact-index");
-        let artifact_root = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext.tar.zst");
-        write_tar_zst_archive_from_dir(&archive, &artifact_root, "acme_ext");
-        let index = temp.join("extensions.toml");
-
-        let created = create_prebuilt_extension_artifact_index(
-            NativeExtensionArtifactIndexCreateOptions::new(&index, "test-target")
-                .artifact(&archive),
-        )
-        .unwrap();
-        assert_eq!(created.path, index);
-        assert_eq!(created.target, "test-target");
-        assert_eq!(created.artifacts.len(), 1);
-        assert_eq!(created.artifacts[0].sql_name, "acme_ext");
-        assert!(created.artifacts[0].creates_extension);
-        assert_eq!(
-            created.artifacts[0].native_module_stem.as_deref(),
-            Some("acme_ext")
-        );
-        assert_eq!(created.artifacts[0].dependencies, Vec::::new());
-        assert_eq!(
-            created.artifacts[0].shared_preload_libraries,
-            Vec::::new()
-        );
-        assert!(!created.artifacts[0].mobile_prebuilt);
-        assert_eq!(created.artifacts[0].path, PathBuf::from("acme_ext.tar.zst"));
-        assert_eq!(
-            created.artifacts[0].bytes,
-            fs::metadata(&archive).unwrap().len()
-        );
-        assert_eq!(
-            created.artifacts[0].sha256,
-            sha256_file_hex(&archive).unwrap()
-        );
-
-        let text = fs::read_to_string(&created.path).unwrap();
-        assert!(text.contains("schema = \"oliphaunt-extension-artifact-index-v1\"\n"));
-        assert!(text.contains("pg_major = 18\n"));
-        assert!(text.contains("sql_name = \"acme_ext\"\n"));
-        assert!(text.contains("target = \"test-target\"\n"));
-        assert!(text.contains("creates_extension = true\n"));
-        assert!(text.contains("native_module_stem = \"acme_ext\"\n"));
-        assert!(text.contains("dependencies = []\n"));
-        assert!(text.contains("shared_preload_libraries = []\n"));
-        assert!(text.contains("mobile_prebuilt = false\n"));
-        assert!(text.contains("path = \"acme_ext.tar.zst\"\n"));
-        assert!(text.contains("sha256 = \""));
-        assert!(text.contains("bytes = "));
-
-        let resolved = resolve_prebuilt_extension_artifacts_from_indexes(
-            NativeExtensionArtifactIndexOptions::new("test-target")
-                .index(&created.path)
-                .extension("acme_ext"),
-        )
-        .unwrap();
-        assert_eq!(resolved.extension_names, vec!["acme_ext"]);
-        assert_eq!(resolved.artifacts[0].root, archive);
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn extension_artifact_index_catalog_lists_external_metadata_without_native_env() {
-        let temp = unique_temp_root("oliphaunt-extension-artifact-index-catalog");
-        let runtime = temp.join("runtime");
-        write_extension_source_runtime(&runtime, "acme_ext", "acme_ext.so");
-        let ios_archive = temp.join("liboliphaunt_extension_acme_ext_ios_simulator.a");
-        write_file(&ios_archive, b"acme-ios-simulator-static\n");
-        let archive = temp.join("acme_ext.tar.zst");
-
-        create_prebuilt_extension_artifact(
-            NativeExtensionArtifactOptions::new(&archive, &runtime, "acme_ext", "1.2.3")
-                .native_module_stem("acme_ext")
-                .native_module_file("acme_ext.so")
-                .native_target("test-target")
-                .dependency("cube")
-                .shared_preload_library("acme_preload")
-                .mobile_prebuilt(true)
-                .mobile_static_archive("ios-simulator", &ios_archive)
-                .static_symbol_prefix("acme_static")
-                .format(NativeExtensionArtifactFormat::TarZst)
-                .legal_contract(write_external_legal_contract(&temp, "acme_ext")),
-        )
-        .unwrap();
-
-        let index = temp.join("extensions.toml");
-        create_prebuilt_extension_artifact_index(
-            NativeExtensionArtifactIndexCreateOptions::new(&index, "test-target")
-                .artifact(&archive),
-        )
-        .unwrap();
-
-        let catalog = list_prebuilt_extension_artifact_index_catalog(
-            NativeExtensionArtifactIndexOptions::new("test-target").index(&index),
-        )
-        .unwrap();
-
-        assert_eq!(catalog.extensions.len(), 1);
-        let entry = &catalog.extensions[0];
-        assert_eq!(entry.sql_name, "acme_ext");
-        assert_eq!(entry.target, "test-target");
-        assert!(entry.creates_extension);
-        assert_eq!(entry.native_module_stem.as_deref(), Some("acme_ext"));
-        assert_eq!(entry.dependencies, vec!["cube"]);
-        assert_eq!(entry.shared_preload_libraries, vec!["acme_preload"]);
-        assert!(entry.mobile_prebuilt);
-        assert_eq!(entry.mobile_static_archive_targets, vec!["ios-simulator"]);
-
-        let other_target = list_prebuilt_extension_artifact_index_catalog(
-            NativeExtensionArtifactIndexOptions::new("other-target").index(&index),
-        )
-        .unwrap();
-        assert!(other_target.extensions.is_empty());
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn extension_artifact_index_downloads_url_backed_artifacts_to_verified_cache() {
-        let temp = unique_temp_root("oliphaunt-extension-artifact-index-download");
-        let artifact_root = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("published/acme_ext.tar.zst");
-        fs::create_dir_all(archive.parent().unwrap()).unwrap();
-        write_tar_zst_archive_from_dir(&archive, &artifact_root, "acme_ext");
-        let bytes = fs::metadata(&archive).unwrap().len();
-        let sha256 = sha256_file_hex(&archive).unwrap();
-
-        let index = temp.join("index/extensions.toml");
-        fs::create_dir_all(index.parent().unwrap()).unwrap();
-        fs::write(
-            &index,
-            format!(
-                "\
-schema = \"oliphaunt-extension-artifact-index-v1\"
-pg_major = 18
-
-[[artifacts]]
-sql_name = \"acme_ext\"
-target = \"test-target\"
-path = \"downloads/acme_ext.tar.zst\"
-url = \"file://{}\"
-sha256 = \"{sha256}\"
-bytes = {bytes}
-",
-                archive.display()
-            ),
-        )
-        .unwrap();
-        let cache = temp.join("cache");
-
-        let resolution = resolve_prebuilt_extension_artifacts_from_indexes(
-            NativeExtensionArtifactIndexOptions::new("test-target")
-                .index(&index)
-                .extension("acme_ext")
-                .artifact_cache_dir(&cache),
-        )
-        .unwrap();
-
-        let cached = cache.join("test-target/downloads/acme_ext.tar.zst");
-        assert!(cached.is_file());
-        assert_eq!(resolution.extension_names, vec!["acme_ext"]);
-        assert_eq!(resolution.artifacts[0].root, cached);
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn extension_artifact_index_requires_cache_for_url_backed_missing_artifacts() {
-        let temp = unique_temp_root("oliphaunt-extension-artifact-index-download-cache");
-        let artifact_root = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("published/acme_ext.tar.zst");
-        fs::create_dir_all(archive.parent().unwrap()).unwrap();
-        write_tar_zst_archive_from_dir(&archive, &artifact_root, "acme_ext");
-        let index = temp.join("extensions.toml");
-        fs::write(
-            &index,
-            format!(
-                "\
-schema = \"oliphaunt-extension-artifact-index-v1\"
-pg_major = 18
-
-[[artifacts]]
-sql_name = \"acme_ext\"
-target = \"test-target\"
-path = \"missing/acme_ext.tar.zst\"
-url = \"file://{}\"
-sha256 = \"{}\"
-bytes = {}
-",
-                archive.display(),
-                sha256_file_hex(&archive).unwrap(),
-                fs::metadata(&archive).unwrap().len()
-            ),
-        )
-        .unwrap();
-
-        let error = resolve_prebuilt_extension_artifacts_from_indexes(
-            NativeExtensionArtifactIndexOptions::new("test-target")
-                .index(&index)
-                .extension("acme_ext"),
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains("--extension-cache"),
-            "unexpected missing cache error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn create_extension_artifact_index_can_publish_url_rows() {
-        let temp = unique_temp_root("oliphaunt-create-extension-artifact-index-url");
-        let artifact_root = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext.tar.zst");
-        write_tar_zst_archive_from_dir(&archive, &artifact_root, "acme_ext");
-        let index = temp.join("extensions.toml");
-
-        let created = create_prebuilt_extension_artifact_index(
-            NativeExtensionArtifactIndexCreateOptions::new(&index, "test-target")
-                .artifact(&archive)
-                .artifact_base_url("https://example.invalid/oliphaunt/extensions"),
-        )
-        .unwrap();
-
-        assert_eq!(
-            created.artifacts[0].url.as_deref(),
-            Some("https://example.invalid/oliphaunt/extensions/acme_ext.tar.zst")
-        );
-        let text = fs::read_to_string(&created.path).unwrap();
-        assert!(
-            text.contains(
-                "url = \"https://example.invalid/oliphaunt/extensions/acme_ext.tar.zst\"\n"
-            )
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[cfg(feature = "extension-signing")]
-    #[test]
-    fn extension_artifact_index_signature_verifies_trusted_publisher_key() {
-        let temp = unique_temp_root("oliphaunt-extension-artifact-index-signature");
-        let artifact_root = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext.tar.zst");
-        write_tar_zst_archive_from_dir(&archive, &artifact_root, "acme_ext");
-        let index = temp.join("extensions.toml");
-        create_prebuilt_extension_artifact_index(
-            NativeExtensionArtifactIndexCreateOptions::new(&index, "test-target")
-                .artifact(&archive),
-        )
-        .unwrap();
-        let (signing_key, public_key) = test_extension_index_key_pair();
-        let signature = sign_prebuilt_extension_artifact_index(
-            NativeExtensionArtifactIndexSigningOptions::new(&index, "test-publisher", signing_key),
-        )
-        .unwrap();
-        assert!(signature.path.is_file());
-        assert_eq!(signature.public_key_hex, public_key);
-
-        let resolution = resolve_prebuilt_extension_artifacts_from_indexes(
-            NativeExtensionArtifactIndexOptions::new("test-target")
-                .index(&index)
-                .extension("acme_ext")
-                .trusted_signing_key(NativeExtensionArtifactIndexTrustRoot::new(
-                    "test-publisher",
-                    public_key,
-                ))
-                .require_signatures(true),
-        )
-        .unwrap();
-        assert_eq!(resolution.extension_names, vec!["acme_ext"]);
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[cfg(feature = "extension-signing")]
-    #[test]
-    fn extension_artifact_index_signature_rejects_modified_index() {
-        let temp = unique_temp_root("oliphaunt-extension-artifact-index-signature-modified");
-        let artifact_root = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext.tar.zst");
-        write_tar_zst_archive_from_dir(&archive, &artifact_root, "acme_ext");
-        let index = temp.join("extensions.toml");
-        create_prebuilt_extension_artifact_index(
-            NativeExtensionArtifactIndexCreateOptions::new(&index, "test-target")
-                .artifact(&archive),
-        )
-        .unwrap();
-        let (signing_key, public_key) = test_extension_index_key_pair();
-        sign_prebuilt_extension_artifact_index(NativeExtensionArtifactIndexSigningOptions::new(
-            &index,
-            "test-publisher",
-            signing_key,
-        ))
-        .unwrap();
-        let mut index_text = fs::read_to_string(&index).unwrap();
-        index_text.push('\n');
-        fs::write(&index, index_text).unwrap();
-
-        let error = resolve_prebuilt_extension_artifacts_from_indexes(
-            NativeExtensionArtifactIndexOptions::new("test-target")
-                .index(&index)
-                .extension("acme_ext")
-                .trusted_signing_key(NativeExtensionArtifactIndexTrustRoot::new(
-                    "test-publisher",
-                    public_key,
-                ))
-                .require_signatures(true),
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains("failed verification"),
-            "unexpected modified signature error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[cfg(feature = "extension-signing")]
-    #[test]
-    fn extension_artifact_index_requires_signature_when_trust_is_required() {
-        let temp = unique_temp_root("oliphaunt-extension-artifact-index-signature-required");
-        let artifact_root = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext.tar.zst");
-        write_tar_zst_archive_from_dir(&archive, &artifact_root, "acme_ext");
-        let index = temp.join("extensions.toml");
-        create_prebuilt_extension_artifact_index(
-            NativeExtensionArtifactIndexCreateOptions::new(&index, "test-target")
-                .artifact(&archive),
-        )
-        .unwrap();
-        let (_, public_key) = test_extension_index_key_pair();
-
-        let error = resolve_prebuilt_extension_artifacts_from_indexes(
-            NativeExtensionArtifactIndexOptions::new("test-target")
-                .index(&index)
-                .extension("acme_ext")
-                .trusted_signing_key(NativeExtensionArtifactIndexTrustRoot::new(
-                    "test-publisher",
-                    public_key,
-                ))
-                .require_signatures(true),
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains(".sig"),
-            "unexpected missing signature error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn create_extension_artifact_index_rejects_artifacts_outside_index_dir() {
-        let temp = unique_temp_root("oliphaunt-create-extension-artifact-index-outside");
-        let outside = unique_temp_root("oliphaunt-extension-artifact-outside");
-        let artifact_root = outside.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = outside.join("acme_ext.tar.zst");
-        write_tar_zst_archive_from_dir(&archive, &artifact_root, "acme_ext");
-        let index = temp.join("extensions.toml");
-
-        let error = create_prebuilt_extension_artifact_index(
-            NativeExtensionArtifactIndexCreateOptions::new(&index, "test-target")
-                .artifact(&archive),
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains("must be inside index directory"),
-            "unexpected outside-index error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-        let _ = fs::remove_dir_all(outside);
-    }
-
-    #[test]
-    fn extension_artifact_index_rejects_checksum_mismatch() {
-        let temp = unique_temp_root("oliphaunt-extension-artifact-index-checksum");
-        let artifact_root = temp.join("artifact-root");
-        write_prebuilt_extension_artifact(
-            &artifact_root,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            false,
-        );
-        let archive = temp.join("acme_ext.tar.zst");
-        write_tar_zst_archive_from_dir(&archive, &artifact_root, "acme_ext");
-        let index = temp.join("extensions.toml");
-        let bytes = fs::metadata(&archive).unwrap().len();
-        fs::write(
-            &index,
-            format!(
-                "\
-schema = \"oliphaunt-extension-artifact-index-v1\"
-pg_major = 18
-
-[[artifacts]]
-sql_name = \"acme_ext\"
-target = \"test-target\"
-path = \"acme_ext.tar.zst\"
-sha256 = \"{}\"
-bytes = {bytes}
-",
-                "0".repeat(64)
-            ),
-        )
-        .unwrap();
-
-        let error = resolve_prebuilt_extension_artifacts_from_indexes(
-            NativeExtensionArtifactIndexOptions::new("test-target")
-                .index(&index)
-                .extension("acme_ext"),
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains("has sha256"),
-            "unexpected checksum error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_can_override_builtin_artifact_payload() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-override");
-        let artifact = temp.join("vector");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "vector",
-            "vector",
-            "oliphaunt_static_vector",
-            "data/vector.rules",
-            true,
-        );
-
-        let resolved = resolve_runtime_resource_extensions(
-            &[],
-            &[NativePrebuiltExtensionArtifact::new(&artifact)],
-        )
-        .unwrap();
-        assert_eq!(resolved.len(), 1);
-        assert_eq!(resolved[0].sql_name, "vector");
-        assert!(matches!(
-            resolved[0].source,
-            RuntimeResourceExtensionSource::Prebuilt { .. }
-        ));
-        assert_eq!(resolved[0].mobile_static_archives.len(), 1);
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    #[test]
-    fn prebuilt_extension_artifact_dependencies_must_be_available() {
-        let temp = unique_temp_root("oliphaunt-prebuilt-extension-missing-dependency");
-        let artifact = temp.join("acme_ext");
-        write_prebuilt_extension_artifact(
-            &artifact,
-            "acme_ext",
-            "acme_ext",
-            "acme_static",
-            "data/acme_ext.rules",
-            true,
-        );
-        let manifest = artifact.join("manifest.properties");
-        let text = fs::read_to_string(&manifest).unwrap();
-        fs::write(
-            &manifest,
-            text.replace("dependencies=\n", "dependencies=missing_ext\n"),
-        )
-        .unwrap();
-
-        let error = resolve_runtime_resource_extensions(
-            &[],
-            &[NativePrebuiltExtensionArtifact::new(&artifact)],
-        )
-        .unwrap_err();
-        assert!(
-            error.to_string().contains(
-                "selected extension 'missing_ext' is neither built into this Oliphaunt release nor provided as a prebuilt extension artifact"
-            ),
-            "unexpected missing-dependency error: {error}"
-        );
-
-        let _ = fs::remove_dir_all(temp);
-    }
-
-    fn write_file(path: &Path, contents: &[u8]) {
-        if let Some(parent) = path.parent() {
-            fs::create_dir_all(parent).expect("create parent directory");
-        }
-        fs::write(path, contents).expect("write fixture file");
-    }
-
-    fn write_legal_fixture_file(path: &Path, contents: &[u8]) {
-        write_file(path, contents);
-        #[cfg(unix)]
-        {
-            use std::os::unix::fs::PermissionsExt;
-            fs::set_permissions(path, fs::Permissions::from_mode(0o644))
-                .expect("set canonical fixture legal mode");
-        }
-    }
-
-    fn write_prebuilt_extension_artifact(
-        root: &Path,
-        sql_name: &str,
-        module_stem: &str,
-        static_symbol_prefix: &str,
-        data_file: &str,
-        mobile_prebuilt: bool,
-    ) {
-        write_prebuilt_extension_artifact_for_runtime(
-            root,
-            sql_name,
-            module_stem,
-            static_symbol_prefix,
-            data_file,
-            mobile_prebuilt,
-            "1.2.3",
-        );
-    }
-
-    fn write_prebuilt_extension_artifact_for_runtime(
-        root: &Path,
-        sql_name: &str,
-        module_stem: &str,
-        static_symbol_prefix: &str,
-        data_file: &str,
-        mobile_prebuilt: bool,
-        native_runtime_version: &str,
-    ) {
-        let mobile_static_archives = if mobile_prebuilt {
-            format!(
-                "ios-simulator:mobile-static/ios-simulator/extensions/{module_stem}/liboliphaunt_extension_{module_stem}.a"
-            )
-        } else {
-            String::new()
-        };
-        let mobile_static_dependency_archives = if mobile_prebuilt {
-            "ios-simulator:openssl:mobile-static/ios-simulator/dependencies/openssl/libcrypto.a"
-                .to_owned()
-        } else {
-            String::new()
-        };
-        write_file(
-            &root.join("manifest.properties"),
-            format!(
-                "\
-packageLayout=oliphaunt-extension-artifact-v1
-pgMajor=18
-sqlName={sql_name}
-createsExtension=yes
-nativeModuleStem={module_stem}
-nativeModuleFile=
-nativeTarget=test-target
-nativeRuntimeProduct=liboliphaunt-native
-nativeRuntimeVersion={native_runtime_version}
-dependencies=
-dataFiles={data_file}
-extensionSqlFileNames=
-extensionSqlFilePrefixes=
-sharedPreloadLibraries=
-mobilePrebuilt={}
-mobileStaticArchives={mobile_static_archives}
-mobileStaticDependencyArchives={mobile_static_dependency_archives}
-staticSymbolPrefix={static_symbol_prefix}
-staticSymbolAliases=
-licenseFiles=share/licenses/{sql_name}/LICENSE
-licenseProfile=external-native
-files=files
-",
-                if mobile_prebuilt { "yes" } else { "no" }
-            )
-            .as_bytes(),
-        );
-        write_file(
-            &root
-                .join("files/share/postgresql/extension")
-                .join(format!("{sql_name}.control")),
-            b"comment = 'acme extension'\n",
-        );
-        write_file(
-            &root
-                .join("files/share/postgresql/extension")
-                .join(format!("{sql_name}--1.0.sql")),
-            b"CREATE FUNCTION acme_ext_echo(integer) RETURNS integer AS 'MODULE_PATHNAME' LANGUAGE C STRICT;\n",
-        );
-        write_file(
-            &root.join("files/share/postgresql").join(data_file),
-            b"acme-data\n",
-        );
-        write_legal_fixture_file(&root.join("LICENSE"), b"fixture Oliphaunt license\n");
-        write_legal_fixture_file(
-            &root.join("THIRD_PARTY_NOTICES.md"),
-            b"fixture third-party notices\n",
-        );
-        write_legal_fixture_file(
-            &root
-                .join("files/share/licenses")
-                .join(sql_name)
-                .join("LICENSE"),
-            b"fixture upstream license\n",
-        );
-        write_file(
-            &root
-                .join("files/lib/postgresql")
-                .join(format!("{module_stem}{}", std::env::consts::DLL_SUFFIX)),
-            b"acme-module\n",
-        );
-        write_file(
-            &root
-                .join("files/lib/modules")
-                .join(format!("{module_stem}{}", std::env::consts::DLL_SUFFIX)),
-            b"acme-embedded-module\n",
-        );
-        if mobile_prebuilt {
-            write_file(
-                &root
-                    .join("mobile-static/ios-simulator/extensions")
-                    .join(module_stem)
-                    .join(format!("liboliphaunt_extension_{module_stem}.a")),
-                b"acme-ios-simulator-static\n",
-            );
-            write_file(
-                &root.join("mobile-static/ios-simulator/dependencies/openssl/libcrypto.a"),
-                b"acme-ios-simulator-libcrypto\n",
-            );
-        }
-    }
-
-    fn write_extension_source_runtime(root: &Path, sql_name: &str, module_file: &str) {
-        write_file(
-            &root
-                .join("share/postgresql/extension")
-                .join(format!("{sql_name}.control")),
-            b"comment = 'acme extension'\n",
-        );
-        write_file(
-            &root
-                .join("share/postgresql/extension")
-                .join(format!("{sql_name}--1.0.sql")),
-            b"CREATE FUNCTION acme_ext_echo(integer) RETURNS integer AS 'MODULE_PATHNAME' LANGUAGE C STRICT;\n",
-        );
-        write_file(
-            &root.join("share/postgresql/data/acme_ext.rules"),
-            b"acme-data\n",
-        );
-        write_file(
-            &root.join("lib/postgresql").join(module_file),
-            b"acme-module\n",
-        );
-    }
-
-    fn write_external_legal_contract(
-        temp: &Path,
-        sql_name: &str,
-    ) -> NativeExtensionArtifactLegalContract {
-        let root = temp.join(format!("legal-{sql_name}"));
-        write_legal_fixture_file(&root.join("LICENSE"), b"fixture Oliphaunt license\n");
-        write_legal_fixture_file(
-            &root.join("THIRD_PARTY_NOTICES.md"),
-            b"fixture third-party notices\n",
-        );
-        let license = PathBuf::from(format!("share/licenses/{sql_name}/LICENSE"));
-        write_legal_fixture_file(&root.join(&license), b"fixture upstream license\n");
-        NativeExtensionArtifactLegalContract::new(
-            NativeExtensionArtifactLicenseProfile::ExternalNative,
-            root,
-        )
-        .license_file(license)
-    }
-
-    fn write_profiled_extension_artifact(
-        root: &Path,
-        sql_name: &str,
-        module_stem: &str,
-        target: &str,
-        profile: NativeExtensionArtifactLicenseProfile,
-        license_files: &[&str],
-    ) {
-        let module_file = format!("{module_stem}.so");
-        let license_value = license_files.join(",");
-        write_file(
-            &root.join("manifest.properties"),
-            format!(
-                "\
-packageLayout=oliphaunt-extension-artifact-v1
-pgMajor=18
-sqlName={sql_name}
-createsExtension=yes
-nativeModuleStem={module_stem}
-nativeModuleFile={module_file}
-nativeTarget={target}
-nativeRuntimeProduct=liboliphaunt-native
-nativeRuntimeVersion=1.2.3
-dependencies=
-dataFiles=
-extensionSqlFileNames=
-extensionSqlFilePrefixes=
-sharedPreloadLibraries=
-mobilePrebuilt=no
-mobileStaticArchives=
-mobileStaticDependencyArchives=
-staticSymbolPrefix=
-staticSymbolAliases=
-licenseFiles={license_value}
-licenseProfile={}
-files=files
-",
-                profile.as_str()
-            )
-            .as_bytes(),
-        );
-        write_legal_fixture_file(&root.join("LICENSE"), b"fixture Oliphaunt license\n");
-        write_legal_fixture_file(
-            &root.join("THIRD_PARTY_NOTICES.md"),
-            b"fixture third-party notices\n",
-        );
-        if matches!(
-            profile,
-            NativeExtensionArtifactLicenseProfile::ContribNative
-                | NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl
-        ) {
-            write_legal_fixture_file(
-                &root.join(EXTENSION_ARTIFACT_POSTGRESQL_LICENSE),
-                b"fixture PostgreSQL license\n",
-            );
-        }
-        if profile == NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl {
-            write_legal_fixture_file(
-                &root.join(EXTENSION_ARTIFACT_OPENSSL_LICENSE),
-                b"fixture OpenSSL license\n",
-            );
-        }
-        for license in license_files {
-            write_legal_fixture_file(
-                &root.join("files").join(license),
-                format!("fixture upstream license {license}\n").as_bytes(),
-            );
-        }
-        write_file(
-            &root
-                .join("files/share/postgresql/extension")
-                .join(format!("{sql_name}.control")),
-            b"comment = 'profile fixture'\n",
-        );
-        write_file(
-            &root
-                .join("files/share/postgresql/extension")
-                .join(format!("{sql_name}--1.0.sql")),
-            b"SELECT 1;\n",
-        );
-        write_file(
-            &root.join("files/lib/postgresql").join(&module_file),
-            b"fixture server module\n",
-        );
-        write_file(
-            &root.join("files/lib/modules").join(module_file),
-            b"fixture embedded module\n",
-        );
-    }
-
-    fn write_tar_archive_from_dir(archive_path: &Path, source: &Path, prefix: &str) {
-        if let Some(parent) = archive_path.parent() {
-            fs::create_dir_all(parent).unwrap();
-        }
-        let file = File::create(archive_path).unwrap();
-        let mut archive = tar::Builder::new(file);
-        archive.mode(tar::HeaderMode::Deterministic);
-        archive.append_dir_all(prefix, source).unwrap();
-        archive.finish().unwrap();
-    }
-
-    fn write_tar_archive_from_dir_with_top_level_sibling(
-        archive_path: &Path,
-        source: &Path,
-        prefix: &str,
-        sibling: &str,
-        sibling_is_directory: bool,
-    ) {
-        if let Some(parent) = archive_path.parent() {
-            fs::create_dir_all(parent).unwrap();
-        }
-        let file = File::create(archive_path).unwrap();
-        let mut archive = tar::Builder::new(file);
-        archive.append_dir_all(prefix, source).unwrap();
-        let mut header = tar::Header::new_ustar();
-        header.set_path(sibling).unwrap();
-        header.set_mode(if sibling_is_directory { 0o755 } else { 0o644 });
-        header.set_size(0);
-        header.set_entry_type(if sibling_is_directory {
-            EntryType::Directory
-        } else {
-            EntryType::Regular
-        });
-        header.set_cksum();
-        archive.append(&header, io::empty()).unwrap();
-        archive.finish().unwrap();
-    }
-
-    fn rewrite_tar_archive_member_mode(archive_path: &Path, member: &Path, mode: u32) {
-        let source_path = archive_path.with_extension("original.tar");
-        fs::rename(archive_path, &source_path).unwrap();
-        let source_file = File::open(&source_path).unwrap();
-        let mut source_archive = tar::Archive::new(source_file);
-        let output_file = File::create(archive_path).unwrap();
-        let mut output_archive = tar::Builder::new(output_file);
-        let mut found = false;
-        for entry in source_archive.entries().unwrap() {
-            let mut entry = entry.unwrap();
-            let path = entry.path().unwrap().into_owned();
-            let mut header = entry.header().clone();
-            if header.entry_type().is_file() {
-                header.set_mode(if path == member { mode } else { 0o644 });
-                header.set_cksum();
-                found |= path == member;
-            }
-            output_archive.append(&header, &mut entry).unwrap();
-        }
-        output_archive.finish().unwrap();
-        assert!(
-            found,
-            "tar fixture is missing mode override member {}",
-            member.display()
-        );
-        fs::remove_file(source_path).unwrap();
-    }
-
-    fn write_tar_zst_archive_from_dir(archive_path: &Path, source: &Path, prefix: &str) {
-        let tar_path = archive_path.with_extension("tar");
-        write_tar_archive_from_dir(&tar_path, source, prefix);
-        let tar_bytes = fs::read(&tar_path).unwrap();
-        let compressed = zstd::stream::encode_all(tar_bytes.as_slice(), 0).unwrap();
-        write_file(archive_path, &compressed);
-        let _ = fs::remove_file(tar_path);
-    }
-
-    fn write_extension_artifact_index(index: &Path, target: &str, artifacts: &[(&str, &Path)]) {
-        let mut text = String::from(
-            "\
-schema = \"oliphaunt-extension-artifact-index-v1\"
-pg_major = 18
-",
-        );
-        for (sql_name, artifact) in artifacts {
-            let file_name = artifact.file_name().unwrap().to_string_lossy();
-            let bytes = fs::metadata(artifact).unwrap().len();
-            let sha256 = sha256_file_hex(artifact).unwrap();
-            text.push_str(&format!(
-                "\n[[artifacts]]\nsql_name = \"{sql_name}\"\ntarget = \"{target}\"\npath = \"{file_name}\"\nsha256 = \"{sha256}\"\nbytes = {bytes}\n"
-            ));
-        }
-        write_file(index, text.as_bytes());
-    }
-
-    #[cfg(feature = "extension-signing")]
-    fn test_extension_index_key_pair() -> (String, String) {
-        use ed25519_dalek::SigningKey;
-
-        let signing_key_bytes = [7u8; 32];
-        let signing_key = SigningKey::from_bytes(&signing_key_bytes);
-        (
-            hex_bytes(&signing_key_bytes),
-            hex_bytes(&signing_key.verifying_key().to_bytes()),
-        )
-    }
-
-    fn runtime_resource_extensions(extensions: &[Extension]) -> Vec {
-        extensions
-            .iter()
-            .copied()
-            .map(built_in_runtime_resource_extension)
-            .collect()
-    }
-
-    fn unique_temp_root(prefix: &str) -> PathBuf {
-        let nanos = SystemTime::now()
-            .duration_since(UNIX_EPOCH)
-            .unwrap()
-            .as_nanos();
-        std::env::temp_dir().join(format!("{prefix}-{}-{nanos}", std::process::id()))
-    }
-}
diff --git a/tools/native-packaging/tests/extension_catalog_cli.rs b/tools/native-packaging/tests/extension_catalog_cli.rs
deleted file mode 100644
index 35501b929..000000000
--- a/tools/native-packaging/tests/extension_catalog_cli.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-use std::collections::BTreeMap;
-use std::process::Command;
-
-use oliphaunt_native_packaging::built_in_extension_catalog;
-
-#[test]
-fn extension_catalog_cli_lists_the_generated_packaging_inventory_without_runtime_inputs() {
-    let output = Command::new(env!("CARGO_BIN_EXE_oliphaunt-resources"))
-        .arg("--list-extensions")
-        .env_remove("LIBOLIPHAUNT_PATH")
-        .env_remove("OLIPHAUNT_POSTGRES")
-        .env_remove("OLIPHAUNT_INITDB")
-        .env_remove("OLIPHAUNT_INSTALL_DIR")
-        .output()
-        .expect("run oliphaunt-resources --list-extensions");
-    assert!(
-        output.status.success(),
-        "catalog command failed with status {}\nstdout:\n{}\nstderr:\n{}",
-        output.status,
-        String::from_utf8_lossy(&output.stdout),
-        String::from_utf8_lossy(&output.stderr)
-    );
-
-    let stdout = String::from_utf8(output.stdout).expect("catalog output must be UTF-8");
-    let mut lines = stdout.lines();
-    assert_eq!(
-        lines.next(),
-        Some(
-            "sql_name\tpg_major\tcreates_extension\tnative_module_stem\tdependencies\tshared_preload\tdesktop_prebuilt\tmobile_prebuilt\tmobile_static_registry_required\tmobile_static_archive_targets\tdata_files\tartifact"
-        )
-    );
-    let rows = lines
-        .map(|line| {
-            let columns = line.split('\t').collect::>();
-            assert_eq!(columns.len(), 12, "catalog row must have 12 columns");
-            (columns[0].to_owned(), columns)
-        })
-        .collect::>();
-
-    let expected = built_in_extension_catalog();
-    assert_eq!(rows.len(), expected.len());
-    for extension in expected {
-        let row = rows
-            .get(&extension.sql_name)
-            .unwrap_or_else(|| panic!("catalog must contain {}", extension.sql_name));
-        assert_eq!(row[1], extension.postgres_major.to_string());
-        assert_eq!(
-            row[2],
-            if extension.creates_extension {
-                "yes"
-            } else {
-                "no"
-            }
-        );
-        assert_eq!(
-            row[3],
-            extension.native_module_stem.as_deref().unwrap_or("-")
-        );
-        assert_eq!(row[6], "yes");
-        assert_eq!(row[7], "yes");
-        assert_eq!(row[11], "first-party");
-    }
-}
diff --git a/tools/native-tools-proof/Cargo.toml b/tools/native-tools-proof/Cargo.toml
deleted file mode 100644
index e151195ab..000000000
--- a/tools/native-tools-proof/Cargo.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "oliphaunt-native-tools-proof"
-version = "0.0.0"
-edition.workspace = true
-rust-version.workspace = true
-license.workspace = true
-publish = false
-
-[dev-dependencies]
-oliphaunt = { path = "../../src/sdks/rust" }
-oliphaunt-tools = { path = "../../src/runtimes/liboliphaunt/native/crates/tools" }
-serde_json = "1"
diff --git a/tools/native-tools-proof/moon.yml b/tools/native-tools-proof/moon.yml
deleted file mode 100644
index 163f58741..000000000
--- a/tools/native-tools-proof/moon.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-$schema: "https://moonrepo.dev/schemas/project.json"
-
-id: "native-tools-proof"
-language: "rust"
-layer: "tool"
-stack: "systems"
-tags: ["maintainer-tool", "native", "rust", "tools"]
-dependsOn:
-  - id: "liboliphaunt-native"
-    scope: "development"
-  - id: "shared-test-fixtures"
-    scope: "development"
-
-project:
-  title: "Native tools proof"
-  description: "Unpublished cross-product conformance for native SDK servers and PostgreSQL tool facades."
-  owner: "oliphaunt"
-
-owners:
-  defaultOwner: "@oliphaunt/sdk-rust"
-
-tasks:
-  unit:
-    tags: ["quality", "unit", "requires-rust"]
-    command: "cargo test -p oliphaunt-native-tools-proof --locked"
-    env:
-      CARGO_TARGET_DIR: "target/moon/native-tools-proof/unit"
-    inputs:
-      - "@group(cargo-workspace)"
-      - project: "liboliphaunt-native"
-        group: "runtime"
-      - project: "oliphaunt-rust"
-        group: "code"
-      - project: "shared-test-fixtures"
-        group: "fixtures"
-      - "**/*"
-    options:
-      cache: true
-      runFromWorkspaceRoot: true
diff --git a/tools/native-tools-proof/src/lib.rs b/tools/native-tools-proof/src/lib.rs
deleted file mode 100644
index b5374fe0d..000000000
--- a/tools/native-tools-proof/src/lib.rs
+++ /dev/null
@@ -1,225 +0,0 @@
-#[cfg(test)]
-#[path = "../../../src/runtimes/liboliphaunt/native/crates/tools/src/arguments.rs"]
-mod native_arguments;
-
-#[cfg(test)]
-mod tests {
-    use std::path::{Path, PathBuf};
-    use std::time::{SystemTime, UNIX_EPOCH};
-
-    use oliphaunt::{DatabaseStorage, Extension, OliphauntServer};
-    use oliphaunt_tools::{PgDumpOptions, PsqlOptions};
-    use serde_json::Value;
-
-    use super::native_arguments::{validate_pg_dump_arguments, validate_psql_arguments};
-
-    #[test]
-    fn native_argument_validation_matches_the_canonical_fixture() {
-        let fixture: Value = serde_json::from_str(&fixture("logical-tools.json"))
-            .expect("canonical logical-tools fixture must be valid JSON");
-        assert_fixture_cases(&fixture, "pgDump", |arguments| {
-            validate_pg_dump_arguments(arguments)
-        });
-        assert_fixture_cases(&fixture, "psql", |arguments| {
-            validate_psql_arguments(arguments)
-        });
-    }
-
-    #[test]
-    fn native_server_pg_dump_psql_round_trip_when_available() {
-        if std::env::var_os("LIBOLIPHAUNT_PATH").is_none() {
-            eprintln!("skipping native logical tools proof: LIBOLIPHAUNT_PATH is unset");
-            return;
-        }
-        if !native_extension_available("pgtap") {
-            eprintln!("skipping native logical tools proof: packaged pgtap is unavailable");
-            return;
-        }
-
-        let source_root = unique_root("native-logical-source");
-        let restored_root = unique_root("native-logical-restored");
-        let seed = fixture("logical-tools-seed.sql");
-        let verify = fixture("logical-tools-verify.sql");
-        let result = std::panic::catch_unwind(|| {
-            let mut source = OliphauntServer::builder()
-                .storage(DatabaseStorage::Directory(source_root.clone()))
-                .extension(Extension::PGTAP)
-                .start()
-                .expect("open native logical source server");
-            oliphaunt_tools::psql(
-                source.connection_string(),
-                PsqlOptions::new().script(seed.as_str()),
-            )
-            .expect("seed native server through public psql facade");
-            let dump_sql =
-                oliphaunt_tools::pg_dump(source.connection_string(), PgDumpOptions::new())
-                    .expect("dump native server through public pg_dump facade");
-            assert!(dump_sql.contains("COPY public.logical_items"));
-            assert!(!dump_sql.contains("INSERT INTO public.logical_items"));
-            source.close().expect("close native logical source server");
-
-            let mut restored = OliphauntServer::builder()
-                .storage(DatabaseStorage::Directory(restored_root.clone()))
-                .extension(Extension::PGTAP)
-                .start()
-                .expect("open native logical restore server");
-            oliphaunt_tools::psql(
-                restored.connection_string(),
-                PsqlOptions::new().script(dump_sql),
-            )
-            .expect("restore native server through public psql facade");
-            let verify_output = oliphaunt_tools::psql(
-                restored.connection_string(),
-                PsqlOptions::new().arg("-tA").script(verify.as_str()),
-            )
-            .expect("verify native logical restore through public psql facade");
-            assert_eq!(verify_output.trim(), expected_logical_tools_row());
-            restored
-                .close()
-                .expect("close native logical restore server");
-        });
-        let _ = std::fs::remove_dir_all(source_root);
-        let _ = std::fs::remove_dir_all(restored_root);
-        if let Err(payload) = result {
-            std::panic::resume_unwind(payload);
-        }
-    }
-
-    fn assert_fixture_cases(
-        fixture: &Value,
-        section: &str,
-        validate: impl Fn(&[String]) -> Result<(), String>,
-    ) {
-        for arguments in scalar_cases(fixture, section, "acceptedArgs")
-            .into_iter()
-            .map(|argument| vec![argument])
-            .chain(argv_cases(fixture, section, "acceptedArgv"))
-        {
-            validate(&arguments).unwrap_or_else(|error| {
-                panic!("canonical {section} argv {arguments:?} must be accepted: {error}")
-            });
-        }
-        for arguments in scalar_cases(fixture, section, "rejectedArgs")
-            .into_iter()
-            .map(|argument| vec![argument])
-            .chain(argv_cases(fixture, section, "rejectedArgv"))
-        {
-            assert!(
-                validate(&arguments).is_err(),
-                "canonical {section} argv {arguments:?} must be rejected"
-            );
-        }
-    }
-
-    fn scalar_cases(fixture: &Value, section: &str, field: &str) -> Vec {
-        fixture[section][field]
-            .as_array()
-            .unwrap_or_else(|| panic!("canonical {section}.{field} must be an array"))
-            .iter()
-            .map(|argument| {
-                argument
-                    .as_str()
-                    .unwrap_or_else(|| {
-                        panic!("canonical {section}.{field} entries must be strings")
-                    })
-                    .to_owned()
-            })
-            .collect()
-    }
-
-    fn argv_cases(fixture: &Value, section: &str, field: &str) -> Vec> {
-        fixture[section][field]
-            .as_array()
-            .unwrap_or_else(|| panic!("canonical {section}.{field} must be an array"))
-            .iter()
-            .map(|arguments| {
-                arguments
-                    .as_array()
-                    .unwrap_or_else(|| panic!("canonical {section}.{field} entries must be arrays"))
-                    .iter()
-                    .map(|argument| {
-                        argument
-                            .as_str()
-                            .unwrap_or_else(|| {
-                                panic!("canonical {section}.{field} argv entries must be strings")
-                            })
-                            .to_owned()
-                    })
-                    .collect()
-            })
-            .collect()
-    }
-
-    fn fixture(name: &str) -> String {
-        std::fs::read_to_string(
-            Path::new(env!("CARGO_MANIFEST_DIR"))
-                .join("../../src/shared/fixtures/postgres")
-                .join(name),
-        )
-        .unwrap_or_else(|error| panic!("read canonical logical tools fixture {name}: {error}"))
-    }
-
-    fn native_extension_available(sql_name: &str) -> bool {
-        let control = format!("{sql_name}.control");
-        if std::env::var_os("OLIPHAUNT_INSTALL_DIR").is_some_and(|root| {
-            PathBuf::from(root)
-                .join("share/postgresql/extension")
-                .join(&control)
-                .is_file()
-        }) {
-            return true;
-        }
-        let Some(resources) = std::env::var_os("OLIPHAUNT_RESOURCES_DIR") else {
-            return false;
-        };
-        let Ok(products) = std::fs::read_dir(PathBuf::from(resources).join("extension")) else {
-            return false;
-        };
-        products.flatten().any(|product| {
-            product
-                .path()
-                .join("share/postgresql/extension")
-                .join(&control)
-                .is_file()
-        })
-    }
-
-    fn expected_logical_tools_row() -> String {
-        let fixture: Value = serde_json::from_str(&fixture("logical-tools.json"))
-            .expect("canonical logical tools fixture must be valid JSON");
-        let expected = &fixture["expected"];
-        format!(
-            "{}|{}|{}|{}|{}|{}",
-            expected["rows"].as_i64().expect("fixture rows"),
-            expected["sum"].as_i64().expect("fixture sum"),
-            expected["sequenceLastValue"]
-                .as_i64()
-                .expect("fixture sequence last value"),
-            expected["quotedValue"]
-                .as_str()
-                .expect("fixture quoted value"),
-            expected["normalizedMatches"]
-                .as_i64()
-                .expect("fixture normalized matches"),
-            if expected["extensionLoaded"]
-                .as_bool()
-                .expect("fixture extension loaded")
-            {
-                "t"
-            } else {
-                "f"
-            }
-        )
-    }
-
-    fn unique_root(label: &str) -> PathBuf {
-        std::env::temp_dir().join(format!(
-            "oliphaunt-{label}-{}-{}",
-            std::process::id(),
-            SystemTime::now()
-                .duration_since(UNIX_EPOCH)
-                .expect("system clock is before Unix epoch")
-                .as_nanos()
-        ))
-    }
-}
diff --git a/tools/packaging/archive-directory.mts b/tools/packaging/archive-directory.mts
new file mode 100755
index 000000000..b8ad52e35
--- /dev/null
+++ b/tools/packaging/archive-directory.mts
@@ -0,0 +1,342 @@
+#!/usr/bin/env bun
+import fs from 'node:fs/promises';
+import path from 'node:path';
+import process from 'node:process';
+import { fileURLToPath } from 'node:url';
+import { crc32, deflateRawSync } from 'node:zlib';
+
+import { canonicalGzipSync, releaseZstdCompressSync } from './portable-archive.mts';
+
+function fail(message) {
+  throw new Error(`archive-directory.mts: ${message}`);
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function normalizedMode(stat, isDirectory) {
+  if (isDirectory) {
+    return 0o755;
+  }
+  return stat.mode & 0o100 ? 0o755 : 0o644;
+}
+
+function posixRelative(root, item) {
+  const relative = path.relative(root, item).split(path.sep).join('/');
+  return relative === '' ? '.' : relative;
+}
+
+function archiveEntryName(root, item, keepParent) {
+  const relative = posixRelative(root, item);
+  if (!keepParent) {
+    return relative;
+  }
+  const parent = path.basename(root);
+  if (
+    !parent ||
+    parent === '.' ||
+    parent === '..' ||
+    parent.includes('/') ||
+    parent.includes('\\')
+  ) {
+    fail(`source directory has an unsafe archive parent name: ${root}`);
+  }
+  return relative === '.' ? parent : `${parent}/${relative}`;
+}
+
+async function archiveEntries(root, { keepParent = false } = {}) {
+  const rootStat = await fs.lstat(root);
+  if (!rootStat.isDirectory()) {
+    fail(`source is not a real directory: ${root}`);
+  }
+  const entries = [
+    {
+      fullPath: root,
+      name: archiveEntryName(root, root, keepParent),
+      isDirectory: true,
+      stat: rootStat,
+    },
+  ];
+
+  async function walk(directory) {
+    const dirents = await fs.readdir(directory, { withFileTypes: true });
+    const directories = [];
+    const files = [];
+    for (const entry of dirents) {
+      const fullPath = path.join(directory, entry.name);
+      const stat = await fs.lstat(fullPath);
+      if (stat.isSymbolicLink()) {
+        fail(`source tree contains a symbolic link: ${fullPath}`);
+      }
+      if (stat.isDirectory()) {
+        directories.push({ entry, fullPath, stat });
+      } else if (stat.isFile()) {
+        files.push({ entry, fullPath, stat });
+      } else {
+        fail(`source tree contains an unsupported special entry: ${fullPath}`);
+      }
+    }
+    directories.sort((left, right) => compareText(left.entry.name, right.entry.name));
+    files.sort((left, right) => compareText(left.entry.name, right.entry.name));
+    for (const entry of directories) {
+      entries.push({
+        fullPath: entry.fullPath,
+        name: archiveEntryName(root, entry.fullPath, keepParent),
+        isDirectory: true,
+        stat: entry.stat,
+      });
+    }
+    for (const entry of files) {
+      entries.push({
+        fullPath: entry.fullPath,
+        name: archiveEntryName(root, entry.fullPath, keepParent),
+        isDirectory: false,
+        stat: entry.stat,
+      });
+    }
+    for (const entry of directories) {
+      await walk(entry.fullPath);
+    }
+  }
+
+  await walk(root);
+  return entries;
+}
+
+function tarPathParts(relativePath) {
+  if (Buffer.byteLength(relativePath) <= 100) {
+    return { name: relativePath, prefix: '' };
+  }
+  const parts = relativePath.split('/');
+  for (let index = 1; index < parts.length; index += 1) {
+    const prefix = parts.slice(0, index).join('/');
+    const name = parts.slice(index).join('/');
+    if (name.length > 0 && Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) {
+      return { name, prefix };
+    }
+  }
+  fail(`archive path is too long for ustar: ${relativePath}`);
+}
+
+function writeString(buffer, offset, length, value) {
+  const bytes = Buffer.from(value);
+  if (bytes.length > length) {
+    fail(`tar header field overflow for '${value}'`);
+  }
+  bytes.copy(buffer, offset);
+}
+
+function writeOctal(buffer, offset, length, value) {
+  const text = value.toString(8);
+  if (text.length > length - 1) {
+    fail(`tar header octal field overflow for '${value}'`);
+  }
+  writeString(buffer, offset, length, `${text.padStart(length - 1, '0')}\0`);
+}
+
+export function tarHeader(entry, size, mode) {
+  const header = Buffer.alloc(512, 0);
+  // POSIX identifies directories with typeflag `5`, but a trailing slash is
+  // the portable path spelling expected by archive listing tools and package
+  // consumers. Keep the root marker as `.` and canonicalize every other
+  // directory entry at the producer boundary.
+  const archiveName = entry.isDirectory && entry.name !== '.' ? `${entry.name}/` : entry.name;
+  const { name, prefix } = tarPathParts(archiveName);
+  writeString(header, 0, 100, name);
+  writeOctal(header, 100, 8, mode);
+  writeOctal(header, 108, 8, 0);
+  writeOctal(header, 116, 8, 0);
+  writeOctal(header, 124, 12, size);
+  writeOctal(header, 136, 12, 0);
+  header.fill(0x20, 148, 156);
+  writeString(header, 156, 1, entry.isDirectory ? '5' : '0');
+  writeString(header, 257, 6, 'ustar\0');
+  writeString(header, 263, 2, '00');
+  writeString(header, 265, 32, entry.owner ?? '');
+  writeString(header, 297, 32, entry.owner ?? '');
+  writeString(header, 345, 155, prefix);
+  let checksum = 0;
+  for (const byte of header) {
+    checksum += byte;
+  }
+  const checksumText = checksum.toString(8);
+  if (checksumText.length > 6) {
+    fail(`tar header checksum overflow for ${entry.name}`);
+  }
+  writeString(header, 148, 8, `${checksumText.padStart(6, '0')}\0 `);
+  return header;
+}
+
+export async function createDeterministicTar(root, options = {}) {
+  const chunks = [];
+  for (const entry of await archiveEntries(root, options)) {
+    const stat = entry.stat;
+    const mode = normalizedMode(stat, entry.isDirectory);
+    const data = entry.isDirectory ? Buffer.alloc(0) : await fs.readFile(entry.fullPath);
+    chunks.push(tarHeader(entry, data.length, mode));
+    if (data.length > 0) {
+      chunks.push(data);
+      const remainder = data.length % 512;
+      if (remainder !== 0) {
+        chunks.push(Buffer.alloc(512 - remainder, 0));
+      }
+    }
+  }
+  chunks.push(Buffer.alloc(1024, 0));
+  return Buffer.concat(chunks);
+}
+
+function dosDateTime() {
+  return {
+    time: 0,
+    date: ((1980 - 1980) << 9) | (1 << 5) | 1,
+  };
+}
+
+function writeUInt16(value) {
+  const buffer = Buffer.alloc(2);
+  buffer.writeUInt16LE(value);
+  return buffer;
+}
+
+function writeUInt32(value) {
+  const buffer = Buffer.alloc(4);
+  buffer.writeUInt32LE(value >>> 0);
+  return buffer;
+}
+
+function zipName(entry) {
+  return entry.isDirectory && entry.name !== '.' ? `${entry.name}/` : entry.name;
+}
+
+export async function createDeterministicZip(root, options = {}) {
+  const localChunks = [];
+  const centralChunks = [];
+  let offset = 0;
+  const { time, date } = dosDateTime();
+
+  for (const entry of await archiveEntries(root, options)) {
+    if (entry.name === '.') {
+      continue;
+    }
+    const stat = entry.stat;
+    const mode = normalizedMode(stat, entry.isDirectory);
+    const name = Buffer.from(zipName(entry));
+    const data = entry.isDirectory ? Buffer.alloc(0) : await fs.readFile(entry.fullPath);
+    const compressed = entry.isDirectory ? Buffer.alloc(0) : deflateRawSync(data, { level: 9 });
+    const method = entry.isDirectory ? 0 : 8;
+    const crc = crc32(data);
+    // A Unix-origin ZIP must include the POSIX file type as well as permission
+    // bits. Omitting S_IFREG/S_IFDIR makes the central directory ambiguous to
+    // strict consumers and causes platform-dependent `zipinfo` rendering.
+    const unixMode = (entry.isDirectory ? 0o040000 : 0o100000) | (mode & 0o777);
+    const externalAttributes = (unixMode << 16) | (entry.isDirectory ? 0x10 : 0);
+    const localHeader = Buffer.concat([
+      writeUInt32(0x04034b50),
+      writeUInt16(20),
+      writeUInt16(0),
+      writeUInt16(method),
+      writeUInt16(time),
+      writeUInt16(date),
+      writeUInt32(crc),
+      writeUInt32(compressed.length),
+      writeUInt32(data.length),
+      writeUInt16(name.length),
+      writeUInt16(0),
+      name,
+    ]);
+    localChunks.push(localHeader, compressed);
+    centralChunks.push(
+      Buffer.concat([
+        writeUInt32(0x02014b50),
+        writeUInt16((3 << 8) | 20),
+        writeUInt16(20),
+        writeUInt16(0),
+        writeUInt16(method),
+        writeUInt16(time),
+        writeUInt16(date),
+        writeUInt32(crc),
+        writeUInt32(compressed.length),
+        writeUInt32(data.length),
+        writeUInt16(name.length),
+        writeUInt16(0),
+        writeUInt16(0),
+        writeUInt16(0),
+        writeUInt16(0),
+        writeUInt32(externalAttributes),
+        writeUInt32(offset),
+        name,
+      ]),
+    );
+    offset += localHeader.length + compressed.length;
+  }
+
+  const centralDirectory = Buffer.concat(centralChunks);
+  const end = Buffer.concat([
+    writeUInt32(0x06054b50),
+    writeUInt16(0),
+    writeUInt16(0),
+    writeUInt16(centralChunks.length),
+    writeUInt16(centralChunks.length),
+    writeUInt32(centralDirectory.length),
+    writeUInt32(offset),
+    writeUInt16(0),
+  ]);
+  return Buffer.concat([...localChunks, centralDirectory, end]);
+}
+
+function parseArgs(argv) {
+  const values = [...argv];
+  let keepParent = false;
+  if (values[0] === '--keep-parent') {
+    keepParent = true;
+    values.shift();
+  }
+  if (values.length !== 2) {
+    fail(
+      'usage: tools/packaging/archive-directory.mts [--keep-parent]  ',
+    );
+  }
+  return {
+    keepParent,
+    source: path.resolve(values[0]),
+    output: path.resolve(values[1]),
+  };
+}
+
+export async function archiveDirectory(source, output, { keepParent = false } = {}) {
+  const sourceStat = await fs.lstat(source).catch(() => null);
+  if (!sourceStat?.isDirectory()) {
+    fail(`source is not a directory: ${source}`);
+  }
+  await fs.mkdir(path.dirname(output), { recursive: true });
+  if (output.endsWith('.tar.gz')) {
+    await fs.writeFile(
+      output,
+      canonicalGzipSync(await createDeterministicTar(source, { keepParent })),
+    );
+  } else if (output.endsWith('.tar.zst')) {
+    await fs.writeFile(
+      output,
+      releaseZstdCompressSync(await createDeterministicTar(source, { keepParent })),
+    );
+  } else if (path.extname(output) === '.zip') {
+    await fs.writeFile(output, await createDeterministicZip(source, { keepParent }));
+  } else {
+    fail(`unsupported archive extension: ${output}`);
+  }
+}
+
+if (
+  process.argv[1] !== undefined &&
+  path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
+) {
+  try {
+    const { source, output, keepParent } = parseArgs(process.argv.slice(2));
+    await archiveDirectory(source, output, { keepParent });
+  } catch (cause) {
+    console.error(cause instanceof Error ? cause.message : String(cause));
+    process.exit(2);
+  }
+}
diff --git a/tools/packaging/archive-directory.test.mts b/tools/packaging/archive-directory.test.mts
new file mode 100644
index 000000000..cca610d6b
--- /dev/null
+++ b/tools/packaging/archive-directory.test.mts
@@ -0,0 +1,262 @@
+#!/usr/bin/env bun
+
+import assert from 'node:assert/strict';
+import { createHash } from 'node:crypto';
+import {
+  chmodSync,
+  mkdirSync,
+  mkdtempSync,
+  readFileSync,
+  rmSync,
+  symlinkSync,
+  writeFileSync,
+} from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { gunzipSync, zstdDecompressSync } from 'node:zlib';
+
+import { archiveDirectory } from './archive-directory.mts';
+
+function tarString(buffer, offset, length) {
+  const end = buffer.indexOf(0, offset);
+  return buffer
+    .subarray(offset, end >= offset && end < offset + length ? end : offset + length)
+    .toString('utf8');
+}
+
+function tarOctal(buffer, offset, length) {
+  const value = tarString(buffer, offset, length).trim();
+  return value ? Number.parseInt(value, 8) : 0;
+}
+
+function entries(archive) {
+  const compressed = readFileSync(archive);
+  const buffer = archive.endsWith('.tar.zst')
+    ? zstdDecompressSync(compressed)
+    : gunzipSync(compressed);
+  const rows = [];
+  for (let offset = 0; offset + 512 <= buffer.length; ) {
+    const header = buffer.subarray(offset, offset + 512);
+    if (header.every((byte) => byte === 0)) break;
+    const name = tarString(header, 0, 100);
+    const prefix = tarString(header, 345, 155);
+    const size = tarOctal(header, 124, 12);
+    rows.push({
+      headerName: name,
+      name: prefix ? `${prefix}/${name}` : name,
+      prefix,
+      type: tarString(header, 156, 1),
+    });
+    offset += 512 + Math.ceil(size / 512) * 512;
+  }
+  return rows;
+}
+
+function digest(file) {
+  return createHash('sha256').update(readFileSync(file)).digest('hex');
+}
+
+function zipEntries(archive) {
+  const buffer = readFileSync(archive);
+  let eocd = -1;
+  for (
+    let offset = buffer.length - 22;
+    offset >= Math.max(0, buffer.length - 65_557);
+    offset -= 1
+  ) {
+    if (
+      buffer.readUInt32LE(offset) === 0x06054b50 &&
+      offset + 22 + buffer.readUInt16LE(offset + 20) === buffer.length
+    ) {
+      eocd = offset;
+      break;
+    }
+  }
+  assert.notEqual(eocd, -1, 'ZIP must have an exact end-of-central-directory record');
+  const count = buffer.readUInt16LE(eocd + 10);
+  const size = buffer.readUInt32LE(eocd + 12);
+  const start = buffer.readUInt32LE(eocd + 16);
+  assert.equal(start + size, eocd, 'ZIP central directory must end at the EOCD');
+  const rows = [];
+  let offset = start;
+  for (let index = 0; index < count; index += 1) {
+    assert.equal(buffer.readUInt32LE(offset), 0x02014b50, `missing central entry ${index}`);
+    const versionMadeBy = buffer.readUInt16LE(offset + 4);
+    const nameLength = buffer.readUInt16LE(offset + 28);
+    const extraLength = buffer.readUInt16LE(offset + 30);
+    const commentLength = buffer.readUInt16LE(offset + 32);
+    const externalAttributes = buffer.readUInt32LE(offset + 38);
+    const nameStart = offset + 46;
+    rows.push({
+      commentLength,
+      date: buffer.readUInt16LE(offset + 14),
+      dosDirectory: (externalAttributes & 0x10) !== 0,
+      extraLength,
+      host: versionMadeBy >>> 8,
+      mode: externalAttributes >>> 16,
+      name: buffer.subarray(nameStart, nameStart + nameLength).toString('utf8'),
+      time: buffer.readUInt16LE(offset + 12),
+    });
+    offset = nameStart + nameLength + extraLength + commentLength;
+  }
+  assert.equal(offset, eocd, 'ZIP central directory must contain only declared entries');
+  return rows;
+}
+
+test('writes deterministic canonical ustar directory markers', async () => {
+  const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-archive-dir-'));
+  try {
+    const source = path.join(root, 'source');
+    mkdirSync(path.join(source, 'nested', 'child'), { recursive: true });
+    const longParent = 'parent'.repeat(14);
+    const longChild = 'child'.repeat(7);
+    mkdirSync(path.join(source, longParent, longChild), { recursive: true });
+    writeFileSync(path.join(source, 'nested', 'child', 'payload.txt'), 'payload\n');
+    writeFileSync(path.join(source, 'top.txt'), 'top\n');
+    const first = path.join(root, 'first.tar.gz');
+    const second = path.join(root, 'second.tar.gz');
+    const firstZstd = path.join(root, 'first.tar.zst');
+    const secondZstd = path.join(root, 'second.tar.zst');
+    await archiveDirectory(source, first);
+    await archiveDirectory(source, second);
+    await archiveDirectory(source, firstZstd);
+    await archiveDirectory(source, secondZstd);
+
+    assert.equal(
+      digest(first),
+      digest(second),
+      'archive output must be byte-for-byte deterministic',
+    );
+    assert.equal(
+      digest(firstZstd),
+      digest(secondZstd),
+      'Zstandard archive output must be byte-for-byte deterministic',
+    );
+    assert.equal(
+      readFileSync(first).subarray(0, 10).toString('hex'),
+      '1f8b0800000000000003',
+      'tar.gz output must use the canonical cross-platform gzip header',
+    );
+    const expectedEntries = [
+      { headerName: '.', name: '.', prefix: '', type: '5' },
+      { headerName: 'nested/', name: 'nested/', prefix: '', type: '5' },
+      { headerName: `${longParent}/`, name: `${longParent}/`, prefix: '', type: '5' },
+      { headerName: 'top.txt', name: 'top.txt', prefix: '', type: '0' },
+      { headerName: 'nested/child/', name: 'nested/child/', prefix: '', type: '5' },
+      {
+        headerName: 'nested/child/payload.txt',
+        name: 'nested/child/payload.txt',
+        prefix: '',
+        type: '0',
+      },
+      {
+        headerName: `${longChild}/`,
+        name: `${longParent}/${longChild}/`,
+        prefix: longParent,
+        type: '5',
+      },
+    ];
+    assert.deepEqual(entries(first), expectedEntries);
+    assert.deepEqual(entries(firstZstd), expectedEntries);
+    assert.equal(
+      readFileSync(firstZstd).subarray(0, 4).toString('hex'),
+      '28b52ffd',
+      'tar.zst output must be a Zstandard frame',
+    );
+
+    const unsplittable = path.join(root, 'unsplittable');
+    mkdirSync(path.join(unsplittable, 'x'.repeat(100)), { recursive: true });
+    await assert.rejects(
+      archiveDirectory(unsplittable, path.join(root, 'unsplittable.tar.gz')),
+      /archive path is too long for ustar/u,
+    );
+  } finally {
+    rmSync(root, { force: true, recursive: true });
+  }
+});
+
+test('writes deterministic keep-parent ZIPs with unambiguous Unix member types', async () => {
+  const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-archive-dir-zip-'));
+  try {
+    const source = path.join(root, 'Fixture.xcframework');
+    mkdirSync(path.join(source, 'ios-arm64'), { recursive: true });
+    writeFileSync(path.join(source, 'Info.plist'), '\n');
+    const library = path.join(source, 'ios-arm64', 'libFixture');
+    writeFileSync(library, 'library\n');
+    chmodSync(library, 0o755);
+    const first = path.join(root, 'first.zip');
+    const second = path.join(root, 'second.zip');
+    await archiveDirectory(source, first, { keepParent: true });
+    await archiveDirectory(source, second, { keepParent: true });
+
+    assert.equal(digest(first), digest(second), 'ZIP output must be byte-for-byte deterministic');
+    assert.deepEqual(zipEntries(first), [
+      {
+        commentLength: 0,
+        date: 33,
+        dosDirectory: true,
+        extraLength: 0,
+        host: 3,
+        mode: 0o040755,
+        name: 'Fixture.xcframework/',
+        time: 0,
+      },
+      {
+        commentLength: 0,
+        date: 33,
+        dosDirectory: true,
+        extraLength: 0,
+        host: 3,
+        mode: 0o040755,
+        name: 'Fixture.xcframework/ios-arm64/',
+        time: 0,
+      },
+      {
+        commentLength: 0,
+        date: 33,
+        dosDirectory: false,
+        extraLength: 0,
+        host: 3,
+        mode: 0o100644,
+        name: 'Fixture.xcframework/Info.plist',
+        time: 0,
+      },
+      {
+        commentLength: 0,
+        date: 33,
+        dosDirectory: false,
+        extraLength: 0,
+        host: 3,
+        mode: 0o100755,
+        name: 'Fixture.xcframework/ios-arm64/libFixture',
+        time: 0,
+      },
+    ]);
+  } finally {
+    rmSync(root, { force: true, recursive: true });
+  }
+});
+
+test('rejects symbolic links instead of silently dereferencing release inputs', async () => {
+  const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-archive-dir-link-'));
+  try {
+    const source = path.join(root, 'source');
+    mkdirSync(source);
+    writeFileSync(path.join(source, 'payload'), 'payload\n');
+    symlinkSync('payload', path.join(source, 'payload-link'));
+
+    for (const output of [
+      path.join(root, 'output.tar.gz'),
+      path.join(root, 'output.tar.zst'),
+      path.join(root, 'output.zip'),
+    ]) {
+      await assert.rejects(
+        archiveDirectory(source, output),
+        /source tree contains a symbolic link/u,
+      );
+    }
+  } finally {
+    rmSync(root, { force: true, recursive: true });
+  }
+});
diff --git a/tools/packaging/archive-directory.test.sh b/tools/packaging/archive-directory.test.sh
new file mode 100644
index 000000000..c3460bb18
--- /dev/null
+++ b/tools/packaging/archive-directory.test.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../.."
+bun test ./tools/packaging/archive-directory.test.mts
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-archive-interop-XXXXXX")
+trap 'rm -rf "$scratch"' EXIT
+mkdir -p "$scratch/source/nested/empty" "$scratch/extracted"
+printf 'archive interoperability\n' > "$scratch/source/nested/data"
+bun tools/packaging/archive-directory.mts "$scratch/source" "$scratch/payload.tar.gz"
+tar -xzf "$scratch/payload.tar.gz" -C "$scratch/extracted"
+cmp "$scratch/source/nested/data" "$scratch/extracted/nested/data"
+test -d "$scratch/extracted/nested/empty"
diff --git a/tools/packaging/atomic-directory.mts b/tools/packaging/atomic-directory.mts
new file mode 100644
index 000000000..6bb9a66e9
--- /dev/null
+++ b/tools/packaging/atomic-directory.mts
@@ -0,0 +1,145 @@
+import {
+  chmodSync,
+  copyFileSync,
+  existsSync,
+  lstatSync,
+  mkdirSync,
+  mkdtempSync,
+  readdirSync,
+  renameSync,
+  rmSync,
+  utimesSync,
+} from 'node:fs';
+import path from 'node:path';
+
+const trackedTemporaryPaths = new Set();
+const trackedPromotions = new Map();
+let cleanupInstalled = false;
+
+function cleanupTracked() {
+  for (const { backup, destination } of [...trackedPromotions.values()].reverse()) {
+    try {
+      if (!existsSync(destination) && existsSync(backup)) {
+        renameSync(backup, destination);
+      } else if (existsSync(backup)) {
+        rmSync(backup, { force: true, recursive: true });
+      }
+    } catch {
+      // Preserve the recoverable backup when automatic restoration cannot run.
+    }
+  }
+  for (const temporary of [...trackedTemporaryPaths].reverse()) {
+    try {
+      rmSync(temporary, { force: true, recursive: true });
+    } catch {
+      // The original failure or signal remains authoritative.
+    }
+  }
+}
+
+function installCleanup() {
+  if (cleanupInstalled) return;
+  cleanupInstalled = true;
+  process.once('exit', cleanupTracked);
+  for (const [signal, code] of [
+    ['SIGINT', 130],
+    ['SIGTERM', 143],
+  ]) {
+    process.once(signal, () => {
+      cleanupTracked();
+      process.exit(code);
+    });
+  }
+}
+
+export function trackTemporaryPath(temporary) {
+  installCleanup();
+  trackedTemporaryPaths.add(path.resolve(temporary));
+  return temporary;
+}
+
+export function releaseTemporaryPath(temporary) {
+  trackedTemporaryPaths.delete(path.resolve(temporary));
+}
+
+export function removeTemporaryPath(temporary) {
+  rmSync(temporary, { force: true, recursive: true });
+  releaseTemporaryPath(temporary);
+}
+
+export function createSiblingStage(destination, label = 'stage') {
+  const resolved = path.resolve(destination);
+  const parent = path.dirname(resolved);
+  mkdirSync(parent, { recursive: true });
+  return trackTemporaryPath(
+    mkdtempSync(path.join(parent, `.${path.basename(resolved)}.${label}-`)),
+  );
+}
+
+export function copyDirectoryTree(source, destination) {
+  const sourceStat = lstatSync(source);
+  if (!sourceStat.isDirectory() || sourceStat.isSymbolicLink()) {
+    throw new Error(`directory copy source is not a real directory: ${source}`);
+  }
+  mkdirSync(destination, { recursive: true, mode: sourceStat.mode });
+  for (const entry of readdirSync(source, { withFileTypes: true })) {
+    const from = path.join(source, entry.name);
+    const to = path.join(destination, entry.name);
+    const stat = lstatSync(from);
+    if (stat.isSymbolicLink()) {
+      throw new Error(`directory copy refuses symbolic link ${from}`);
+    }
+    if (stat.isDirectory()) {
+      copyDirectoryTree(from, to);
+      chmodSync(to, stat.mode);
+      utimesSync(to, stat.atime, stat.mtime);
+    } else if (stat.isFile()) {
+      copyFileSync(from, to, 0);
+      chmodSync(to, stat.mode);
+      utimesSync(to, stat.atime, stat.mtime);
+    } else {
+      throw new Error(`directory copy refuses special file ${from}`);
+    }
+  }
+}
+
+export function stageExistingDirectory(destination, label = 'stage') {
+  const stage = createSiblingStage(destination, label);
+  if (existsSync(destination)) copyDirectoryTree(destination, stage);
+  return stage;
+}
+
+export function promoteDirectory(stage, destination) {
+  const resolvedStage = path.resolve(stage);
+  const resolvedDestination = path.resolve(destination);
+  if (path.dirname(resolvedStage) !== path.dirname(resolvedDestination)) {
+    throw new Error('atomic directory stage must be a sibling of its destination');
+  }
+  const backup = `${resolvedStage}.previous`;
+  trackedPromotions.set(resolvedStage, {
+    backup,
+    destination: resolvedDestination,
+  });
+  let movedExisting = false;
+  try {
+    if (existsSync(resolvedDestination)) {
+      renameSync(resolvedDestination, backup);
+      movedExisting = true;
+    }
+    try {
+      renameSync(resolvedStage, resolvedDestination);
+      releaseTemporaryPath(resolvedStage);
+    } catch (error) {
+      if (movedExisting) renameSync(backup, resolvedDestination);
+      throw error;
+    }
+    if (movedExisting) rmSync(backup, { force: true, recursive: true });
+    trackedPromotions.delete(resolvedStage);
+  } catch (error) {
+    if (movedExisting && !existsSync(resolvedDestination) && existsSync(backup)) {
+      renameSync(backup, resolvedDestination);
+    }
+    trackedPromotions.delete(resolvedStage);
+    throw error;
+  }
+}
diff --git a/tools/packaging/atomic-directory.test.mts b/tools/packaging/atomic-directory.test.mts
new file mode 100644
index 000000000..dbf00580f
--- /dev/null
+++ b/tools/packaging/atomic-directory.test.mts
@@ -0,0 +1,57 @@
+import {
+  existsSync,
+  mkdtempSync,
+  mkdirSync,
+  readFileSync,
+  readdirSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import { test } from 'node:test';
+import assert from 'node:assert/strict';
+
+import {
+  createSiblingStage,
+  promoteDirectory,
+  stageExistingDirectory,
+} from './atomic-directory.mts';
+
+if (process.argv[2] === 'exit-fixture') {
+  createSiblingStage(process.argv[3]);
+  process.exit(0);
+}
+
+test('promotes a staged directory and removes the old bytes', () => {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-atomic-directory-'));
+  try {
+    const destination = path.join(root, 'live');
+    mkdirSync(destination);
+    writeFileSync(path.join(destination, 'old'), 'old');
+    const stage = createSiblingStage(destination);
+    writeFileSync(path.join(stage, 'new'), 'new');
+
+    promoteDirectory(stage, destination);
+
+    assert.equal(readFileSync(path.join(destination, 'new'), 'utf8'), 'new');
+    assert.equal(existsSync(path.join(destination, 'old')), false);
+    assert.equal(existsSync(stage), false);
+    assert.equal(existsSync(`${stage}.previous`), false);
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
+
+test('staging an existing directory copies bytes without symbolic links', () => {
+  const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-atomic-directory-copy-'));
+  try {
+    const destination = path.join(root, 'live');
+    mkdirSync(destination);
+    writeFileSync(path.join(destination, 'kept'), 'bytes');
+    const stage = stageExistingDirectory(destination);
+    assert.equal(readFileSync(path.join(stage, 'kept'), 'utf8'), 'bytes');
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
diff --git a/tools/packaging/atomic-directory.test.sh b/tools/packaging/atomic-directory.test.sh
new file mode 100644
index 000000000..a35a573f5
--- /dev/null
+++ b/tools/packaging/atomic-directory.test.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../.."
+bun test ./tools/packaging/atomic-directory.test.mts
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-atomic-exit-XXXXXX")
+trap 'rm -rf "$scratch"' EXIT
+bun tools/packaging/atomic-directory.test.mts exit-fixture "$scratch/live"
+test -z "$(ls -A "$scratch")"
diff --git a/tools/packaging/audit-rust-dependency-licenses.sh b/tools/packaging/audit-rust-dependency-licenses.sh
new file mode 100644
index 000000000..c66d55b77
--- /dev/null
+++ b/tools/packaging/audit-rust-dependency-licenses.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+set -euo pipefail
+[[ $# == 2 ]] || { echo 'usage: audit-rust-dependency-licenses.sh  ' >&2; exit 2; }
+cd "$(dirname "${BASH_SOURCE[0]}")/../.."
+helper=$1
+package=$2
+[[ -f "$helper" && "$helper" != /* && "$helper" != -* && "$helper" != *..* ]] || { echo 'contract must be a repository-relative file' >&2; exit 2; }
+[[ "$package" =~ ^[a-zA-Z0-9_-]+$ ]] || { echo 'invalid Cargo package' >&2; exit 2; }
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-rust-licenses-XXXXXX")
+scratch=$(cd "$scratch" && pwd -P)
+trap 'rm -rf "$scratch"' EXIT
+bun "$helper" audit-targets > "$scratch/targets"
+# Cache the locked platform closure; the audit reads actual source license bytes.
+CARGO_NET_OFFLINE=false cargo fetch --locked
+cargo metadata --locked --offline --format-version 1 | head -c 134217729 > "$scratch/metadata.json"
+while IFS= read -r cargo_target; do
+  cargo tree -p "$package" --locked --offline -e normal --target "$cargo_target" \
+    --prefix none --format '{p}' | head -c 134217729 > "$scratch/$cargo_target.tree"
+done < "$scratch/targets"
+bun "$helper" audit-contract "$scratch"
diff --git a/tools/packaging/build-maven-artifact-manifest.mts b/tools/packaging/build-maven-artifact-manifest.mts
new file mode 100644
index 000000000..4a4e20a94
--- /dev/null
+++ b/tools/packaging/build-maven-artifact-manifest.mts
@@ -0,0 +1,461 @@
+#!/usr/bin/env bun
+import fs from 'node:fs/promises';
+import path from 'node:path';
+
+import { currentVersion } from '../release/product-version.mts';
+import {
+  allArtifactTargets,
+  exactExtensionProducts as logicalExactExtensionProducts,
+  extensionArtifactProductRoot,
+  extensionArtifactTargets as releaseExtensionArtifactTargets,
+  extensionMetadata,
+  extensionReleaseProduct,
+  extensionReleaseVersion,
+  extensionSqlNames,
+  registryPackageRows,
+} from '../release/release-artifact-targets.mts';
+import {
+  assertReleaseNoticesInEntries,
+  releaseProfileMavenLicenses,
+  releaseProfilePackageLicense,
+} from './release-notices.mts';
+import {
+  assertExtensionUpstreamLicensesInEntries,
+  extensionMavenLicenses,
+  extensionRegistryLicense,
+} from '../../src/extensions/tools/extension-upstream-licenses.mts';
+import { readPortableArchiveEntries } from './portable-archive.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../..');
+const PREFIX = 'build_maven_artifact_manifest.mts';
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function fail(message) {
+  throw new Error(`${PREFIX}: ${message}`);
+}
+
+function rel(file) {
+  return path.relative(ROOT, file).split(path.sep).join('/');
+}
+
+function canonicalMavenPayloadPrefix(file, entries) {
+  if (entries.has('LICENSE')) return '';
+
+  const roots = new Set([...entries.keys()].map((member) => member.split('/', 1)[0]));
+  const expected = path.basename(file).slice(0, -'.tar.gz'.length);
+  if (roots.size !== 1 || !roots.has(expected)) {
+    throw new Error(
+      `${path.basename(file)} must stage release notices at the archive root or beneath its ` +
+        `canonical single archive root ${expected}`,
+    );
+  }
+  return expected;
+}
+
+function assertMavenPayloadLegal(file, profile, sqlNames = []) {
+  try {
+    const entries = readPortableArchiveEntries(file);
+    const prefix = canonicalMavenPayloadPrefix(file, entries);
+    assertReleaseNoticesInEntries(entries, { profile, prefix, label: path.basename(file) });
+    if (sqlNames.length > 0) {
+      // Native singleton payloads install upstream notices with runtime files
+      // below files/, while aggregate bundles stage their combined legal tree
+      // directly below the canonical archive root.
+      const upstreamPrefix = prefix === '' ? 'files' : prefix;
+      assertExtensionUpstreamLicensesInEntries(sqlNames, entries, { prefix: upstreamPrefix });
+    }
+  } catch (error) {
+    fail(
+      `${rel(file)} failed Maven payload legal closure: ${error instanceof Error ? error.message : String(error)}`,
+    );
+  }
+  return file;
+}
+
+function repoPath(value) {
+  return path.isAbsolute(value) ? value : path.join(ROOT, value);
+}
+
+function productArtifactTargets(product, version) {
+  return allArtifactTargets(
+    {
+      product,
+    },
+    PREFIX,
+  )
+    .filter((target) => target.surfaces.includes('maven'))
+    .map((target) => ({
+      ...target,
+      asset: target.asset.replaceAll('{version}', version),
+    }))
+    .sort((left, right) => compareText(left.id, right.id));
+}
+
+function runtimeMavenArtifactId(target) {
+  if (target.kind === 'runtime-resources') {
+    if (target.target !== 'android-datum64') {
+      fail(`unsupported Maven runtime-resource target ${target.target}`);
+    }
+    return 'liboliphaunt-runtime-resources-android-datum64';
+  }
+  if (target.kind === 'icu-data') {
+    return 'oliphaunt-icu';
+  }
+  if (target.kind === 'native-runtime' && target.target.startsWith('android-')) {
+    return `liboliphaunt-${target.target}`;
+  }
+  return undefined;
+}
+
+function runtimeMavenArtifactMetadata(target) {
+  if (target.kind === 'runtime-resources') {
+    return {
+      name: 'Oliphaunt runtime resources',
+      description:
+        'Package-managed Oliphaunt PostgreSQL runtime resources for the Android datum64 physical domain.',
+      licenseProfile: 'native-runtime-resources',
+    };
+  }
+  if (target.kind === 'icu-data') {
+    return {
+      name: 'Oliphaunt ICU data',
+      description: 'Package-managed optional ICU data files for Oliphaunt app builds.',
+      licenseProfile: 'native-icu-data',
+    };
+  }
+  if (target.kind === 'native-runtime' && target.target.startsWith('android-')) {
+    const abi = target.target.slice('android-'.length);
+    return {
+      name: `Oliphaunt Android runtime ${abi}`,
+      description: `Package-managed liboliphaunt Android runtime for ${abi} app builds.`,
+      licenseProfile: 'native-runtime',
+    };
+  }
+  fail(`unsupported liboliphaunt-native Maven artifact target ${target.id}`);
+}
+
+function productMavenArtifacts(product, version) {
+  const artifacts = new Map();
+  for (const target of productArtifactTargets(product, version)) {
+    const artifactId = runtimeMavenArtifactId(target);
+    if (artifactId === undefined) {
+      continue;
+    }
+    if (artifacts.has(artifactId)) {
+      fail(`duplicate ${product} Maven artifact mapping for ${artifactId}`);
+    }
+    artifacts.set(artifactId, {
+      filename: target.asset,
+      ...runtimeMavenArtifactMetadata(target),
+    });
+  }
+  if (artifacts.size === 0) {
+    fail(`${product} artifact targets did not produce any Maven artifacts`);
+  }
+  return artifacts;
+}
+
+function splitMavenCoordinate(coordinate) {
+  const separator = coordinate.indexOf(':');
+  if (separator <= 0 || separator === coordinate.length - 1) {
+    fail(`invalid Maven coordinate ${JSON.stringify(coordinate)}; expected group:artifact`);
+  }
+  return [coordinate.slice(0, separator), coordinate.slice(separator + 1)];
+}
+
+async function requireFile(file, label) {
+  try {
+    const stat = await fs.stat(file);
+    if (stat.isFile()) {
+      return file;
+    }
+  } catch {
+    // Fall through to the shared diagnostic below.
+  }
+  fail(`missing ${label}: ${rel(file)}`);
+}
+
+function tsvRow({
+  groupId,
+  artifactId,
+  version,
+  file,
+  name,
+  description,
+  runtimeProduct = '',
+  runtimeVersion = '',
+  licenseSpdx,
+  licenses,
+}) {
+  if (typeof licenseSpdx !== 'string' || !licenseSpdx)
+    fail(`Maven artifact ${groupId}:${artifactId} has no package SPDX expression`);
+  if (!Array.isArray(licenses) || licenses.length === 0)
+    fail(`Maven artifact ${groupId}:${artifactId} has no structured license entries`);
+  const values = [
+    groupId,
+    artifactId,
+    version,
+    rel(file),
+    name,
+    description,
+    runtimeProduct,
+    runtimeVersion,
+    licenseSpdx,
+    JSON.stringify(licenses),
+  ];
+  if (values.some((value) => value.includes('\t') || value.includes('\n'))) {
+    fail(`Maven artifact manifest value contains a tab or newline: ${JSON.stringify(values)}`);
+  }
+  return values.join('\t');
+}
+
+async function productRows(assetRoot, product, artifactIds) {
+  const version = await currentVersion(product);
+  const artifacts = productMavenArtifacts(product, version);
+  const rows = [];
+  const selected = artifactIds === undefined ? undefined : new Set(artifactIds);
+  for (const coordinate of registryPackageRows(
+    {
+      product,
+      packageKind: 'maven',
+    },
+    PREFIX,
+  )
+    .map((row) => row.packageName)
+    .filter((name) => name.startsWith('dev.oliphaunt.runtime:'))) {
+    const [groupId, artifactId] = splitMavenCoordinate(coordinate);
+    if (selected && !selected.delete(artifactId)) continue;
+    if (groupId !== 'dev.oliphaunt.runtime') {
+      fail(`${product} Maven artifact ${coordinate} must use dev.oliphaunt.runtime`);
+    }
+    const artifact = artifacts.get(artifactId);
+    if (artifact === undefined) {
+      fail(`${product} Maven artifact ${coordinate} has no release asset mapping`);
+    }
+    const file = await requireFile(path.join(assetRoot, artifact.filename), artifactId);
+    assertMavenPayloadLegal(file, artifact.licenseProfile);
+    rows.push(
+      tsvRow({
+        groupId,
+        artifactId,
+        version,
+        file,
+        name: artifact.name,
+        description: artifact.description,
+        licenseSpdx: releaseProfilePackageLicense(artifact.licenseProfile).spdx,
+        licenses: releaseProfileMavenLicenses(artifact.licenseProfile, {
+          product,
+          version,
+        }),
+      }),
+    );
+  }
+  if (selected?.size)
+    fail(`unknown selected Maven artifacts for ${product}: ${[...selected].join(', ')}`);
+  return rows;
+}
+
+async function extensionRows(extensionRoot, selectedProducts) {
+  const products =
+    selectedProducts.length > 0 ? selectedProducts : logicalExactExtensionProducts(PREFIX);
+  const rows = [];
+  for (const product of [...products].sort()) {
+    const sqlNames = extensionSqlNames(product, PREFIX);
+    const version = extensionReleaseVersion(product, 'native', PREFIX);
+    const registryLicense = extensionRegistryLicense(product, sqlNames);
+    const compatibility = extensionMetadata(product, PREFIX).compatibility;
+    const releaseProduct = extensionReleaseProduct(product, 'native', PREFIX);
+    const runtimeProduct = compatibility.nativeRuntimeProduct;
+    const runtimeVersion = compatibility.nativeRuntimeVersion;
+    if (
+      typeof runtimeProduct !== 'string' ||
+      !runtimeProduct ||
+      typeof runtimeVersion !== 'string' ||
+      !runtimeVersion
+    ) {
+      fail(`${product} must declare exact native runtime compatibility for Maven carriers`);
+    }
+    const currentRuntimeVersion = await currentVersion(runtimeProduct);
+    if (runtimeVersion !== currentRuntimeVersion) {
+      fail(
+        `${product} native runtime compatibility ${runtimeVersion} does not match ${runtimeProduct}@${currentRuntimeVersion}`,
+      );
+    }
+    const productRoot = path.join(
+      extensionArtifactProductRoot(product, 'native', extensionRoot, PREFIX),
+      'release-assets',
+    );
+    const targets = [
+      ...new Map(
+        releaseExtensionArtifactTargets(
+          {
+            product,
+            family: 'native',
+          },
+          PREFIX,
+        )
+          .filter(
+            (target) =>
+              target.kind === 'native-static-registry' && target.target.startsWith('android-'),
+          )
+          .map((target) => [target.target, target]),
+      ).values(),
+    ];
+    if (targets.length === 0) {
+      fail(`${product} has no published Android Maven extension targets`);
+    }
+    const declaredCoordinates = new Set(
+      registryPackageRows({ product: releaseProduct, packageKind: 'maven' }, PREFIX)
+        .map((row) => row.packageName)
+        .filter((name) => name.startsWith(`dev.oliphaunt.extensions:${product}-`)),
+    );
+    for (const target of targets) {
+      const coordinate = `dev.oliphaunt.extensions:${product}-${target.target}`;
+      if (!declaredCoordinates.delete(coordinate)) {
+        fail(`${product} release metadata is missing Maven carrier ${coordinate}`);
+      }
+      const filename =
+        sqlNames.length > 1
+          ? `${product}-${version}-native-${target.target}-bundle.tar.gz`
+          : `${product}-${version}-native-${target.target}-runtime.tar.gz`;
+      const memberLabel =
+        sqlNames.length === 1
+          ? `the ${sqlNames[0]} PostgreSQL extension`
+          : `the PostgreSQL 18 contrib bundle (${sqlNames.length} exact extension members)`;
+      const file = await requireFile(
+        path.join(productRoot, filename),
+        `${product} ${target.target} Maven artifact`,
+      );
+      const licenseProfile =
+        product === 'oliphaunt-extension-contrib-pg18'
+          ? 'contrib-native-openssl'
+          : 'external-native';
+      assertMavenPayloadLegal(
+        file,
+        licenseProfile,
+        product === 'oliphaunt-extension-contrib-pg18' ? [] : sqlNames,
+      );
+      rows.push(
+        tsvRow({
+          groupId: 'dev.oliphaunt.extensions',
+          artifactId: `${product}-${target.target}`,
+          version,
+          file,
+          name: `Oliphaunt ${sqlNames.length === 1 ? `extension ${sqlNames[0]}` : 'PostgreSQL 18 contrib extensions'} ${target.target}`,
+          description: `Package-managed Oliphaunt Android runtime and static-link artifacts for ${memberLabel} on ${target.target}.`,
+          runtimeProduct,
+          runtimeVersion,
+          licenseSpdx:
+            product === 'oliphaunt-extension-contrib-pg18'
+              ? releaseProfilePackageLicense(licenseProfile).spdx
+              : registryLicense.packageSpdx,
+          licenses:
+            product === 'oliphaunt-extension-contrib-pg18'
+              ? releaseProfileMavenLicenses('contrib-native-openssl', { product, version })
+              : extensionMavenLicenses(product, sqlNames, { version }),
+        }),
+      );
+    }
+    if (declaredCoordinates.size > 0) {
+      fail(
+        `${product} declares unexpected Maven carrier(s): ${[...declaredCoordinates].sort().join(', ')}`,
+      );
+    }
+  }
+  return rows;
+}
+
+function valueArg(argv, index, name) {
+  const value = argv[index + 1];
+  if (value === undefined || value.startsWith('--')) {
+    fail(`${name} requires a value`);
+  }
+  return value;
+}
+
+function parseArgs(argv) {
+  const args = {
+    output: undefined,
+    artifactProduct: 'liboliphaunt-native',
+    runtimeAssetRoot: 'target/liboliphaunt/release-assets',
+    extensionArtifactRoot: 'target/extension-artifacts',
+    runtime: false,
+    extensions: false,
+    extensionProducts: [],
+  };
+  for (let index = 0; index < argv.length; ) {
+    const arg = argv[index];
+    if (arg === '--output') {
+      args.output = valueArg(argv, index, arg);
+      index += 2;
+    } else if (arg === '--artifact-product') {
+      args.artifactProduct = valueArg(argv, index, arg);
+      index += 2;
+    } else if (arg === '--runtime-asset-root') {
+      args.runtimeAssetRoot = valueArg(argv, index, arg);
+      index += 2;
+    } else if (arg === '--extension-artifact-root') {
+      args.extensionArtifactRoot = valueArg(argv, index, arg);
+      index += 2;
+    } else if (arg === '--runtime') {
+      args.runtime = true;
+      index += 1;
+    } else if (arg === '--extensions') {
+      args.extensions = true;
+      index += 1;
+    } else if (arg === '--extension-product') {
+      args.extensionProducts.push(valueArg(argv, index, arg));
+      index += 2;
+    } else {
+      fail(`unknown argument: ${arg}`);
+    }
+  }
+  if (!args.output) {
+    fail('--output is required');
+  }
+  return args;
+}
+
+export async function buildMavenArtifactManifest(
+  outputValue,
+  {
+    artifactProduct = 'liboliphaunt-native',
+    artifactIds,
+    runtimeAssetRoot = 'target/liboliphaunt/release-assets',
+    extensionArtifactRoot = 'target/extension-artifacts',
+    runtime = false,
+    extensions = false,
+    extensionProducts = [],
+  } = {},
+) {
+  const includeRuntime = runtime || !extensions;
+  const includeExtensions = extensions || extensionProducts.length > 0;
+  const rows = [];
+  if (includeRuntime) {
+    rows.push(...(await productRows(repoPath(runtimeAssetRoot), artifactProduct, artifactIds)));
+  }
+  if (includeExtensions) {
+    rows.push(...(await extensionRows(repoPath(extensionArtifactRoot), extensionProducts)));
+  }
+  if (rows.length === 0) {
+    fail('manifest would be empty');
+  }
+  const output = repoPath(outputValue);
+  await fs.mkdir(path.dirname(output), { recursive: true });
+  await fs.writeFile(output, `${rows.join('\n')}\n`, 'utf8');
+  console.log(`Wrote ${rows.length} Maven artifact publication row(s) to ${rel(output)}`);
+  return output;
+}
+
+if (import.meta.main) {
+  try {
+    const args = parseArgs(Bun.argv.slice(2));
+    await buildMavenArtifactManifest(args.output, args);
+  } catch (error) {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exitCode = 1;
+  }
+}
diff --git a/tools/packaging/cargo-dependencies.mts b/tools/packaging/cargo-dependencies.mts
new file mode 100644
index 000000000..d60e9b701
--- /dev/null
+++ b/tools/packaging/cargo-dependencies.mts
@@ -0,0 +1,49 @@
+// Cargo normalizes inline dependency syntax when packaging. Compare resolved
+// dependency semantics, not TOML spelling or independently maintained package lists.
+function dependencyTables(manifest) {
+  const tables = new Map();
+  const add = (prefix, table) => {
+    for (const kind of ['dependencies', 'build-dependencies', 'dev-dependencies']) {
+      for (const [name, value] of Object.entries(table[kind] ?? {})) {
+        const dependency = typeof value === 'string' ? { version: value } : value;
+        // Cargo omits development-only path dependencies with no registry version.
+        if (kind === 'dev-dependencies' && !dependency.version) continue;
+        tables.set(JSON.stringify([...prefix, kind, name]), dependency);
+      }
+    }
+  };
+  add([], manifest);
+  for (const [target, table] of Object.entries(manifest.target ?? {}))
+    add(['target', target], table);
+  return tables;
+}
+
+export function assertPackagedCargoDependencies(actual, expected, label) {
+  const wanted = dependencyTables(expected);
+  const packed = dependencyTables(actual);
+  for (const key of new Set([...wanted.keys(), ...packed.keys()])) {
+    const source = wanted.get(key);
+    const dependency = packed.get(key);
+    if (!source || !dependency)
+      throw new Error(`${label} dependency ${key} is missing or unexpected`);
+    if (
+      ['path', 'workspace', 'git', 'registry', 'registry-index'].some(
+        (field) => field in dependency,
+      )
+    ) {
+      throw new Error(`${label} dependency ${key} must resolve through crates.io`);
+    }
+    const normalize = (row) => ({
+      version: row.version,
+      package: row.package ?? null,
+      optional: row.optional ?? false,
+      defaultFeatures: row['default-features'] ?? true,
+      features: [...new Set(row.features ?? [])].sort(),
+    });
+    if (JSON.stringify(normalize(dependency)) !== JSON.stringify(normalize(source))) {
+      throw new Error(
+        `${label} dependency ${key} differs from its resolved source manifest: expected ${JSON.stringify(normalize(source))}, received ${JSON.stringify(normalize(dependency))}`,
+      );
+    }
+  }
+}
diff --git a/tools/packaging/cargo-dependencies.test.mts b/tools/packaging/cargo-dependencies.test.mts
new file mode 100644
index 000000000..7cab2ee79
--- /dev/null
+++ b/tools/packaging/cargo-dependencies.test.mts
@@ -0,0 +1,57 @@
+import { expect, test } from 'bun:test';
+import { assertPackagedCargoDependencies } from './cargo-dependencies.mts';
+
+const source = {
+  dependencies: {
+    runtime: { version: '=0.2.0' },
+    data: { package: 'icu-data', version: '=0.2.1', optional: true },
+    query: '0.1.0',
+  },
+  target: {
+    'cfg(unix)': {
+      dependencies: {
+        tools: {
+          version: '=0.3.0',
+          optional: true,
+          'default-features': false,
+          features: ['portable', 'aot'],
+        },
+      },
+    },
+  },
+};
+const packaged = () => ({
+  ...structuredClone(source),
+  dependencies: {
+    ...structuredClone(source.dependencies),
+    query: { version: '0.1.0' },
+  },
+});
+
+test('Cargo normalization preserves independent versions, aliases and optional target dependencies', () => {
+  const actual = packaged();
+  actual.target['cfg(unix)'].dependencies.tools.features.reverse();
+  expect(() => assertPackagedCargoDependencies(actual, source, 'consumer.crate')).not.toThrow();
+  actual.dependencies.data.version = '=0.2.0';
+  expect(() => assertPackagedCargoDependencies(actual, source, 'consumer.crate')).toThrow(
+    'resolved source manifest',
+  );
+});
+
+test('a packed crate cannot substitute local sources or silently enable optional resource payloads', () => {
+  const local = packaged();
+  local.dependencies.runtime.path = '../runtime';
+  expect(() => assertPackagedCargoDependencies(local, source, 'consumer.crate')).toThrow(
+    'crates.io',
+  );
+  const required = packaged();
+  required.dependencies.data.optional = false;
+  expect(() => assertPackagedCargoDependencies(required, source, 'consumer.crate')).toThrow(
+    'resolved source manifest',
+  );
+  const missing = packaged();
+  delete missing.target['cfg(unix)'].dependencies.tools;
+  expect(() => assertPackagedCargoDependencies(missing, source, 'consumer.crate')).toThrow(
+    'missing or unexpected',
+  );
+});
diff --git a/tools/packaging/cargo-package-test-closure.mts b/tools/packaging/cargo-package-test-closure.mts
new file mode 100644
index 000000000..e0dd509a9
--- /dev/null
+++ b/tools/packaging/cargo-package-test-closure.mts
@@ -0,0 +1,432 @@
+#!/usr/bin/env bun
+import {
+  chmodSync,
+  copyFileSync,
+  lstatSync,
+  mkdirSync,
+  readFileSync,
+  readdirSync,
+  realpathSync,
+  rmSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+
+import { extractPortableArchiveTree, readPortableArchiveEntries } from './portable-archive.mts';
+
+const TOOL = 'cargo-package-test-closure.mts';
+const CARGO_PACKAGE_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]*$/u;
+
+function error(message) {
+  return new Error(`${TOOL}: ${message}`);
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function regularFile(file, context) {
+  let metadata;
+  try {
+    metadata = lstatSync(file);
+  } catch (cause) {
+    throw error(`${context} is missing: ${file}: ${cause.message}`);
+  }
+  if (!metadata.isFile() || metadata.isSymbolicLink()) {
+    throw error(`${context} must be a regular, non-symlink file: ${file}`);
+  }
+  return metadata;
+}
+
+function parseManifest(file, context) {
+  regularFile(file, context);
+  try {
+    return Bun.TOML.parse(readFileSync(file, 'utf8'));
+  } catch (cause) {
+    throw error(`${context} is not valid TOML: ${file}: ${cause.message}`);
+  }
+}
+
+function packageIdentity(manifest, context) {
+  const pkg = manifest?.package;
+  if (
+    pkg === null ||
+    Array.isArray(pkg) ||
+    typeof pkg !== 'object' ||
+    typeof pkg.name !== 'string' ||
+    typeof pkg.version !== 'string' ||
+    !pkg.name ||
+    !pkg.version
+  ) {
+    throw error(`${context} must declare non-empty package.name and package.version strings`);
+  }
+  if (!CARGO_PACKAGE_NAME.test(pkg.name)) {
+    throw error(`${context} declares unsafe Cargo package name ${JSON.stringify(pkg.name)}`);
+  }
+  return { name: pkg.name, version: pkg.version };
+}
+
+function dependencyTables(manifest) {
+  const tables = [];
+  for (const name of ['dependencies', 'dev-dependencies', 'build-dependencies']) {
+    if (manifest?.[name] !== undefined) tables.push(manifest[name]);
+  }
+  const targets = manifest?.target ?? {};
+  if (targets === null || Array.isArray(targets) || typeof targets !== 'object') {
+    throw error('target dependencies must be TOML tables');
+  }
+  for (const target of Object.values(targets)) {
+    if (target === null || Array.isArray(target) || typeof target !== 'object') {
+      throw error('each target dependency section must be a TOML table');
+    }
+    for (const name of ['dependencies', 'dev-dependencies', 'build-dependencies']) {
+      if (target[name] !== undefined) tables.push(target[name]);
+    }
+  }
+  return tables;
+}
+
+function dependencyRows(manifest) {
+  const rows = [];
+  for (const table of dependencyTables(manifest)) {
+    if (table === null || Array.isArray(table) || typeof table !== 'object') {
+      throw error('dependency sections must be TOML tables');
+    }
+    for (const [alias, raw] of Object.entries(table)) {
+      const value = typeof raw === 'string' ? { version: raw } : raw;
+      if (value === null || Array.isArray(value) || typeof value !== 'object') {
+        throw error(`dependency ${alias} must be a version string or TOML table`);
+      }
+      const name = typeof value.package === 'string' ? value.package : alias;
+      if (!CARGO_PACKAGE_NAME.test(alias) || !CARGO_PACKAGE_NAME.test(name)) {
+        throw error(`dependency declares unsafe Cargo package name or alias: ${alias} -> ${name}`);
+      }
+      rows.push({
+        alias,
+        name,
+        path: typeof value.path === 'string' ? value.path : null,
+        version: typeof value.version === 'string' ? value.version : null,
+        features: Array.isArray(value.features)
+          ? value.features.filter((feature) => typeof feature === 'string')
+          : [],
+      });
+    }
+  }
+  return rows;
+}
+
+function exactVersion(requirement, dependency) {
+  const match = requirement?.match(/^=([0-9A-Za-z][0-9A-Za-z.+-]*)$/u);
+  if (!match) {
+    throw error(
+      `stub dependency ${dependency} must use an exact =version requirement, got ${requirement ?? 'none'}`,
+    );
+  }
+  return match[1];
+}
+
+function addPatch(patches, name, directory, context) {
+  const resolved = realpathSync(directory);
+  const previous = patches.get(name);
+  if (previous !== undefined && previous !== resolved) {
+    throw error(`${name} has conflicting local patches: ${previous} and ${resolved} (${context})`);
+  }
+  patches.set(name, resolved);
+}
+
+function copyCleanDependencySource(source, destination) {
+  const ignoredDirectories = new Set(['.git', 'artifacts', 'payload', 'target']);
+  rmSync(destination, { recursive: true, force: true });
+  mkdirSync(destination, { recursive: true });
+  const visit = (sourceDirectory, destinationDirectory) => {
+    for (const entry of readdirSync(sourceDirectory, { withFileTypes: true }).sort((left, right) =>
+      compareText(left.name, right.name),
+    )) {
+      if (
+        entry.name === '.DS_Store' ||
+        (entry.isDirectory() && ignoredDirectories.has(entry.name))
+      ) {
+        continue;
+      }
+      const sourcePath = path.join(sourceDirectory, entry.name);
+      const destinationPath = path.join(destinationDirectory, entry.name);
+      const metadata = lstatSync(sourcePath);
+      if (metadata.isSymbolicLink()) {
+        throw error(`path dependency source must not contain symbolic links: ${sourcePath}`);
+      }
+      if (metadata.isDirectory()) {
+        mkdirSync(destinationPath, { recursive: true });
+        visit(sourcePath, destinationPath);
+      } else if (metadata.isFile()) {
+        copyFileSync(sourcePath, destinationPath);
+        chmodSync(destinationPath, metadata.mode & 0o777);
+      } else {
+        throw error(`path dependency source contains a special file: ${sourcePath}`);
+      }
+    }
+  };
+  visit(source, destination);
+}
+
+function pathDependencyPatches(manifests, scratch, packagedManifests, packagedNames = new Set()) {
+  const patches = new Map();
+  const sourceDirectories = new Map();
+  const packagedDependencies = packagedManifests.flatMap(dependencyRows);
+  for (const manifestFile of manifests) {
+    const resolvedManifest = path.resolve(manifestFile);
+    const manifest = parseManifest(resolvedManifest, 'path-dependency source manifest');
+    for (const dependency of dependencyRows(manifest).filter((row) => row.path !== null)) {
+      if (packagedNames.has(dependency.name)) continue;
+      const directory = path.resolve(path.dirname(resolvedManifest), dependency.path);
+      const localManifestFile = path.join(directory, 'Cargo.toml');
+      const localManifest = parseManifest(localManifestFile, `local patch for ${dependency.name}`);
+      const local = packageIdentity(localManifest, `local patch for ${dependency.name}`);
+      if (local.name !== dependency.name) {
+        throw error(
+          `local patch ${localManifestFile} declares ${local.name}, expected ${dependency.name}`,
+        );
+      }
+      const packagedVersions = new Set(
+        packagedDependencies
+          .filter(({ name }) => name === dependency.name)
+          .map(({ version }) => exactVersion(version, dependency.name)),
+      );
+      if (packagedVersions.size !== 1 || !packagedVersions.has(local.version)) {
+        throw error(
+          `local patch ${dependency.name}@${local.version} does not match packaged requirement ${[...packagedVersions].join(', ') || 'none'}`,
+        );
+      }
+      const realSource = realpathSync(directory);
+      const previousSource = sourceDirectories.get(dependency.name);
+      if (previousSource !== undefined && previousSource !== realSource) {
+        throw error(
+          `${dependency.name} has conflicting path-dependency sources: ${previousSource} and ${realSource}`,
+        );
+      }
+      sourceDirectories.set(dependency.name, realSource);
+      const staged = path.join(scratch, 'path-dependency-sources', dependency.name);
+      if (!patches.has(dependency.name)) copyCleanDependencySource(directory, staged);
+      addPatch(patches, dependency.name, staged, resolvedManifest);
+    }
+  }
+  return patches;
+}
+
+function forwardedStubFeatures(manifest, aliases) {
+  const features = new Map([...aliases].map((alias) => [alias, new Set()]));
+  const packageFeatures = manifest.features ?? {};
+  if (
+    packageFeatures === null ||
+    Array.isArray(packageFeatures) ||
+    typeof packageFeatures !== 'object'
+  ) {
+    throw error('package features must be a TOML table');
+  }
+  for (const members of Object.values(packageFeatures)) {
+    if (!Array.isArray(members)) continue;
+    for (const member of members) {
+      if (typeof member !== 'string' || !member.includes('/')) continue;
+      const [alias, feature] = member.split('/', 2);
+      features.get(alias?.replace(/^dep:/u, '').replace(/\?$/u, ''))?.add(feature);
+    }
+  }
+  return features;
+}
+
+function createStubPatches({ manifest, scratch, names, prefixes, realPackages = new Set() }) {
+  const dependencies = dependencyRows(manifest);
+  const selected = dependencies.filter(
+    ({ name }) =>
+      !realPackages.has(name) &&
+      (names.has(name) || prefixes.some((prefix) => name.startsWith(prefix))),
+  );
+  for (const name of names) {
+    if (!selected.some((dependency) => dependency.name === name)) {
+      throw error(`requested stub dependency is absent from the packaged manifest: ${name}`);
+    }
+  }
+  for (const prefix of prefixes) {
+    if (!selected.some((dependency) => dependency.name.startsWith(prefix))) {
+      throw error(`stub dependency prefix matched no packaged dependency: ${prefix}`);
+    }
+  }
+
+  const aliasesByName = new Map();
+  for (const dependency of selected) {
+    const aliases = aliasesByName.get(dependency.name) ?? new Set();
+    aliases.add(dependency.alias);
+    aliasesByName.set(dependency.name, aliases);
+  }
+  const allAliases = new Set([...aliasesByName.values()].flatMap((aliases) => [...aliases]));
+  const forwarded = forwardedStubFeatures(manifest, allAliases);
+  const patches = new Map();
+  for (const name of [...aliasesByName.keys()].sort(compareText)) {
+    const rows = selected.filter((dependency) => dependency.name === name);
+    const versions = new Set(rows.map((dependency) => exactVersion(dependency.version, name)));
+    if (versions.size !== 1) {
+      throw error(
+        `stub dependency ${name} has conflicting exact versions: ${[...versions].join(', ')}`,
+      );
+    }
+    const [version] = versions;
+    const features = new Set(rows.flatMap((dependency) => dependency.features));
+    for (const alias of aliasesByName.get(name)) {
+      for (const feature of forwarded.get(alias) ?? []) features.add(feature);
+    }
+    const directory = path.join(scratch, 'dependency-stubs', name);
+    mkdirSync(path.join(directory, 'src'), { recursive: true });
+    const featureRows = [...features]
+      .sort(compareText)
+      .map((feature) => `${JSON.stringify(feature)} = []`);
+    writeFileSync(
+      path.join(directory, 'Cargo.toml'),
+      [
+        '[package]',
+        `name = ${JSON.stringify(name)}`,
+        `version = ${JSON.stringify(version)}`,
+        'edition = "2024"',
+        'publish = false',
+        '',
+        '[lib]',
+        'path = "src/lib.rs"',
+        '',
+        ...(featureRows.length > 0 ? ['[features]', ...featureRows, ''] : []),
+        '[workspace]',
+        '',
+      ].join('\n'),
+    );
+    writeFileSync(path.join(directory, 'src/lib.rs'), '#![forbid(unsafe_code)]\n');
+    addPatch(patches, name, directory, 'generated test-closure stub');
+  }
+  return patches;
+}
+
+function extractCrate(cratePath, scratch) {
+  const entries = readPortableArchiveEntries(cratePath);
+  const roots = new Set([...entries.keys()].map((name) => name.split('/', 1)[0]));
+  if (roots.size !== 1) {
+    throw error(`${cratePath} must contain exactly one package root, found ${roots.size}`);
+  }
+  const [rootName] = roots;
+  const packageRoot = path.join(scratch, rootName);
+  extractPortableArchiveTree(cratePath, packageRoot, rootName);
+  const manifestFile = path.join(packageRoot, 'Cargo.toml');
+  const manifest = parseManifest(manifestFile, 'extracted package manifest');
+  const identity = packageIdentity(manifest, 'extracted package manifest');
+  if (rootName !== `${identity.name}-${identity.version}`) {
+    throw error(`${cratePath} root is ${rootName}, expected ${identity.name}-${identity.version}`);
+  }
+  return { identity, manifest, manifestFile, packageRoot };
+}
+
+function writePatchConfig(scratch, patches) {
+  const configDir = path.join(scratch, '.cargo');
+  mkdirSync(configDir, { recursive: true });
+  const rows = [...patches.entries()].sort(([left], [right]) => compareText(left, right));
+  writeFileSync(
+    path.join(configDir, 'config.toml'),
+    [
+      '[net]',
+      'offline = true',
+      '',
+      ...(rows.length > 0
+        ? [
+            '[patch.crates-io]',
+            ...rows.map(
+              ([name, directory]) =>
+                `${JSON.stringify(name)} = { path = ${JSON.stringify(directory)} }`,
+            ),
+            '',
+          ]
+        : []),
+    ].join('\n'),
+  );
+}
+
+export function preparePackagedCargoTestClosure({
+  cratePath,
+  scratch,
+  pathDependencyManifests = [],
+  dependencyCrates = [],
+  stubDependencies = [],
+  stubDependencyPrefixes = [],
+} = {}) {
+  if (typeof cratePath !== 'string' || !cratePath) throw error('cratePath is required');
+  if (typeof scratch !== 'string' || !scratch) throw error('scratch directory is required');
+  const crate = path.resolve(cratePath);
+  regularFile(crate, 'crate archive');
+  const extracted = extractCrate(crate, scratch);
+  const packagedManifests = [extracted.manifest];
+  const patches = new Map();
+  for (const archive of dependencyCrates) {
+    const dependency = extractCrate(path.resolve(archive), path.join(scratch, 'dependencies'));
+    packagedManifests.push(dependency.manifest);
+    addPatch(patches, dependency.identity.name, dependency.packageRoot, archive);
+  }
+  const sources = pathDependencyPatches(
+    pathDependencyManifests,
+    scratch,
+    packagedManifests,
+    new Set(patches.keys()),
+  );
+  for (const [name, directory] of sources) addPatch(patches, name, directory, 'path dependency');
+  const stubs = createStubPatches({
+    manifest: extracted.manifest,
+    scratch,
+    names: new Set(stubDependencies),
+    prefixes: [...stubDependencyPrefixes],
+    realPackages: new Set(patches.keys()),
+  });
+  for (const [name, directory] of stubs) addPatch(patches, name, directory, 'stub dependency');
+  writePatchConfig(scratch, patches);
+  return extracted.manifestFile;
+}
+
+function requiredValue(argv, index, option) {
+  const value = argv[index];
+  if (value === undefined || value.startsWith('--')) throw error(`${option} requires a value`);
+  return value;
+}
+
+function parseArgs(argv) {
+  const options = {
+    cratePath: null,
+    pathDependencyManifests: [],
+    dependencyCrates: [],
+    stubDependencies: [],
+    stubDependencyPrefixes: [],
+  };
+  for (let index = 0; index < argv.length; index += 1) {
+    const option = argv[index];
+    if (option === '--crate') {
+      options.cratePath = requiredValue(argv, ++index, option);
+    } else if (option === '--dependency-crate') {
+      options.dependencyCrates.push(requiredValue(argv, ++index, option));
+    } else if (option === '--path-dependencies-from') {
+      options.pathDependencyManifests.push(requiredValue(argv, ++index, option));
+    } else if (option === '--stub-dependency') {
+      options.stubDependencies.push(requiredValue(argv, ++index, option));
+    } else if (option === '--stub-dependency-prefix') {
+      options.stubDependencyPrefixes.push(requiredValue(argv, ++index, option));
+    } else {
+      throw error(`unknown argument: ${option}`);
+    }
+  }
+  if (!options.cratePath) {
+    throw error(
+      'usage: cargo-package-test-closure.mts SCRATCH --crate FILE [--path-dependencies-from Cargo.toml] ' +
+        '[--stub-dependency NAME] [--stub-dependency-prefix PREFIX]',
+    );
+  }
+  return options;
+}
+
+if (import.meta.main) {
+  try {
+    const [scratch, ...args] = Bun.argv.slice(2);
+    console.log(preparePackagedCargoTestClosure({ ...parseArgs(args), scratch }));
+  } catch (cause) {
+    console.error(cause instanceof Error ? cause.message : String(cause));
+    process.exit(1);
+  }
+}
diff --git a/tools/packaging/cargo-package-test-closure.test.mts b/tools/packaging/cargo-package-test-closure.test.mts
new file mode 100644
index 000000000..35e89923f
--- /dev/null
+++ b/tools/packaging/cargo-package-test-closure.test.mts
@@ -0,0 +1,138 @@
+import assert from 'node:assert/strict';
+import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { gzipSync } from 'node:zlib';
+
+import { preparePackagedCargoTestClosure } from './cargo-package-test-closure.mts';
+import { createDeterministicTar, packageGeneratedCargoSource } from './cargo-source-package.mts';
+
+function fixture(t, name) {
+  const root = mkdtempSync(path.join(os.tmpdir(), `oliphaunt-${name}-`));
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+  return root;
+}
+
+function writePackage(directory, name, body = '#![forbid(unsafe_code)]\n') {
+  mkdirSync(path.join(directory, 'src'), { recursive: true });
+  writeFileSync(
+    path.join(directory, 'Cargo.toml'),
+    [
+      '[package]',
+      `name = ${JSON.stringify(name)}`,
+      'version = "0.1.0"',
+      'edition = "2024"',
+      'license = "MIT"',
+      '',
+      '[lib]',
+      'path = "src/lib.rs"',
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(path.join(directory, 'src/lib.rs'), body);
+}
+
+function closureCrate(root) {
+  const source = path.join(root, 'source');
+  mkdirSync(path.join(source, 'src'), { recursive: true });
+  writeFileSync(
+    path.join(source, 'Cargo.toml'),
+    [
+      '[package]',
+      'name = "closure-fixture"',
+      'version = "0.1.0"',
+      'edition = "2024"',
+      'license = "MIT"',
+      '',
+      '[features]',
+      'forward = ["carrier?/needed"]',
+      '',
+      '[dependencies]',
+      'carrier = { version = "=0.1.0", optional = true }',
+      '',
+      '[lib]',
+      'path = "src/lib.rs"',
+      '',
+    ].join('\n'),
+  );
+  writeFileSync(path.join(source, 'src/lib.rs'), '#![forbid(unsafe_code)]\n');
+  return packageGeneratedCargoSource(path.join(source, 'Cargo.toml'), path.join(root, 'crate'), {
+    root,
+    rel: String,
+    fail: (message) => {
+      throw new Error(message);
+    },
+  });
+}
+
+if (process.argv[2] === 'prepare') {
+  console.log(closureCrate(process.argv[3]));
+  process.exit(0);
+}
+
+test('rejects conflicting path-patch sources for the same package identity', (t) => {
+  const root = fixture(t, 'cargo-closure-conflict');
+  const cratePath = closureCrate(root);
+  const controllers = [];
+  for (const suffix of ['one', 'two']) {
+    const dependency = path.join(root, `carrier-${suffix}`);
+    writePackage(dependency, 'carrier');
+    const controller = path.join(root, `controller-${suffix}`);
+    writePackage(controller, `controller-${suffix}`);
+    writeFileSync(
+      path.join(controller, 'Cargo.toml'),
+      [
+        '[package]',
+        `name = "controller-${suffix}"`,
+        'version = "0.1.0"',
+        'edition = "2024"',
+        '',
+        '[dependencies]',
+        `carrier = { version = "*", path = ${JSON.stringify(dependency)} }`,
+        '',
+      ].join('\n'),
+    );
+    controllers.push(path.join(controller, 'Cargo.toml'));
+  }
+  assert.throws(
+    () =>
+      preparePackagedCargoTestClosure({
+        cratePath,
+        scratch: path.join(root, 'work'),
+        pathDependencyManifests: controllers,
+      }),
+    /conflicting path-dependency sources/u,
+  );
+});
+
+test('rejects unsafe packaged names', (t) => {
+  const root = fixture(t, 'cargo-closure-unsafe');
+  const stage = path.join(root, 'stage');
+  mkdirSync(path.join(stage, 'src'), { recursive: true });
+  writeFileSync(
+    path.join(stage, 'Cargo.toml'),
+    ['[package]', 'name = "../escape"', 'version = "0.1.0"', 'edition = "2024"', ''].join('\n'),
+  );
+  writeFileSync(path.join(stage, 'src/lib.rs'), '');
+  const unsafeCrate = path.join(root, 'unsafe.crate');
+  writeFileSync(
+    unsafeCrate,
+    gzipSync(
+      createDeterministicTar(stage, 'safe-root', {
+        fail: (message) => {
+          throw new Error(message);
+        },
+      }),
+      { mtime: 0 },
+    ),
+  );
+  assert.throws(
+    () =>
+      preparePackagedCargoTestClosure({
+        cratePath: unsafeCrate,
+        scratch: path.join(root, 'unsafe-work'),
+      }),
+    /unsafe Cargo package name/u,
+  );
+});
diff --git a/tools/packaging/cargo-package-test-closure.test.sh b/tools/packaging/cargo-package-test-closure.test.sh
new file mode 100644
index 000000000..9c3cca02b
--- /dev/null
+++ b/tools/packaging/cargo-package-test-closure.test.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../.."
+bun test ./tools/packaging/cargo-package-test-closure.test.mts
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-cargo-closure-XXXXXX")
+trap 'rm -rf "$scratch"' EXIT
+crate=$(bun tools/packaging/cargo-package-test-closure.test.mts prepare "$scratch")
+script=tools/packaging/check-cargo-package-tests.sh
+bash "$script" --crate "$crate" --target-dir "$scratch/target" \
+  --stub-dependency carrier --no-default-features --features forward --lib > "$scratch/checked.log"
+grep -q 'Cargo package test closure verified: closure-fixture-0.1.0' "$scratch/checked.log"
+reject() {
+  local expected="$1"; shift
+  if bash "$script" "$@" > "$scratch/rejected.log" 2>&1; then exit 1; fi
+  grep -q "$expected" "$scratch/rejected.log"
+}
+reject 'unknown argument' --unknown
+reject 'mutually exclusive' --crate "$crate" --all-features --features forward
+reject 'requires a value' --crate
diff --git a/tools/packaging/cargo-source-package.mts b/tools/packaging/cargo-source-package.mts
new file mode 100644
index 000000000..f8527149a
--- /dev/null
+++ b/tools/packaging/cargo-source-package.mts
@@ -0,0 +1,429 @@
+import {
+  chmodSync,
+  copyFileSync,
+  lstatSync,
+  mkdirSync,
+  readdirSync,
+  readFileSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+import { tarHeader } from './archive-directory.mts';
+import { canonicalGzipSync, readPortableArchiveEntries } from './portable-archive.mts';
+import { stageReleaseNotices } from './release-notices.mts';
+
+export const CARGO_PACKAGE_SIZE_LIMIT_BYTES = 10 * 1024 * 1024;
+
+// Keep 1 MiB below the registry limit. The raw budget only bounds working
+// memory; the finished deterministic .crate decides whether splitting is needed.
+export function fitCargoPayloadParts(buildParts, packagePart, rawBudget = 64 * 1024 * 1024) {
+  if (!Number.isSafeInteger(rawBudget) || rawBudget < 1) {
+    throw new Error('Cargo payload raw budget must be a positive integer');
+  }
+  for (;;) {
+    const parts = buildParts(rawBudget);
+    if (!parts.length) throw new Error('Cargo payload produced no parts');
+    if (parts.every((part) => statSync(packagePart(part)).size <= 9 * 1024 * 1024)) return parts;
+    if (rawBudget === 1) throw new Error('Cargo payload metadata exceeds the package size limit');
+    rawBudget = Math.max(1, Math.floor(rawBudget / 2));
+  }
+}
+
+export function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function abort(fail, message) {
+  if (typeof fail === 'function') {
+    fail(message);
+  }
+  throw new Error(message);
+}
+
+export function parseCargoPackageNameVersion(text, context, { fail = null } = {}) {
+  let inPackage = false;
+  let name = null;
+  let version = null;
+  for (const rawLine of text.split(/\r?\n/u)) {
+    const line = rawLine.trim();
+    if (line === '[package]') {
+      inPackage = true;
+      continue;
+    }
+    if (inPackage && line.startsWith('[')) {
+      break;
+    }
+    if (!inPackage) {
+      continue;
+    }
+    name ??= line.match(/^name\s*=\s*"([^"]+)"/u)?.[1] ?? null;
+    version ??= line.match(/^version\s*=\s*"([^"]+)"/u)?.[1] ?? null;
+  }
+  if (!name || !version) {
+    abort(fail, `${context} must declare package.name and package.version`);
+  }
+  return { name, version };
+}
+
+export function readCargoPackageNameVersion(manifest, { fail = null, rel = String } = {}) {
+  return parseCargoPackageNameVersion(readFileSync(manifest, 'utf8'), rel(manifest), { fail });
+}
+
+export function packagedCargoManifestText(source) {
+  let text = source
+    .replaceAll('repository.workspace = true', 'repository = "https://github.com/f0rr0/oliphaunt"')
+    .replaceAll('homepage.workspace = true', 'homepage = "https://oliphaunt.dev"');
+  text = text
+    .replace(/(\{\s*)path\s*=\s*"[^"]+",\s*/gu, '$1')
+    .replace(/,\s*path\s*=\s*"[^"]+"/gu, '');
+  if (!text.includes('\n[workspace]')) {
+    text = `${text.trimEnd()}\n\n[workspace]\n`;
+  }
+  return text;
+}
+
+const CARGO_VIRTUAL_PACKAGE_FILES = new Set([
+  '.cargo_vcs_info.json',
+  'Cargo.lock',
+  'Cargo.toml.orig',
+]);
+
+export function cargoPackageRelativePathParts(value) {
+  if (
+    !value ||
+    value.includes('\\') ||
+    value.includes('\0') ||
+    value.startsWith('/') ||
+    /^[A-Za-z]:/u.test(value)
+  ) {
+    throw new Error(`unsafe Cargo package path ${JSON.stringify(value)}`);
+  }
+  const parts = value.split('/');
+  if (
+    parts.some(
+      (part) =>
+        !part || part === '.' || part === '..' || /[<>:"|?*]/u.test(part) || /[ .]$/u.test(part),
+    )
+  ) {
+    throw new Error(`non-portable Cargo package path ${JSON.stringify(value)}`);
+  }
+  return parts;
+}
+
+function portablePackagePath(value, manifest, { fail, rel }) {
+  try {
+    return cargoPackageRelativePathParts(value);
+  } catch (cause) {
+    abort(fail, `cargo package --list for ${rel(manifest)} returned ${cause.message}`);
+  }
+}
+
+function parseCargoPackageFiles(text, manifest, { fail, rel }) {
+  const files = text.split(/\r?\n/u).filter(Boolean);
+  if (files.length === 0) {
+    abort(fail, `cargo package --list returned no files for ${rel(manifest)}`);
+  }
+  const seen = new Set();
+  for (const file of files) {
+    portablePackagePath(file, manifest, { fail, rel });
+    if (seen.has(file)) {
+      abort(fail, `cargo package --list repeated ${file} for ${rel(manifest)}`);
+    }
+    seen.add(file);
+  }
+  if (!seen.has('Cargo.toml')) {
+    abort(fail, `cargo package --list omitted Cargo.toml for ${rel(manifest)}`);
+  }
+  return files;
+}
+
+function sourceFileWithoutSymlinkComponents(sourceDir, parts, manifest, { fail, rel }) {
+  let source = sourceDir;
+  for (const part of parts) {
+    source = path.join(source, part);
+    let metadata;
+    try {
+      metadata = lstatSync(source);
+    } catch (cause) {
+      abort(
+        fail,
+        `cargo-listed source ${rel(source)} for ${rel(manifest)} is missing: ${cause.message}`,
+      );
+    }
+    if (metadata.isSymbolicLink()) {
+      abort(
+        fail,
+        `cargo-listed source ${rel(source)} for ${rel(manifest)} must not be a symbolic link`,
+      );
+    }
+  }
+  const metadata = lstatSync(source);
+  if (!metadata.isFile()) {
+    abort(fail, `cargo-listed source ${rel(source)} for ${rel(manifest)} must be a regular file`);
+  }
+  return { metadata, source };
+}
+
+function copyCargoPackageSource(manifest, destination, files, options) {
+  const sourceDir = path.dirname(manifest);
+  const copied = new Set(['Cargo.toml']);
+  rmSync(destination, { recursive: true, force: true });
+  mkdirSync(destination, { recursive: true });
+  for (const relative of files) {
+    if (relative === 'Cargo.toml') {
+      continue;
+    }
+    const parts = portablePackagePath(relative, manifest, options);
+    try {
+      lstatSync(path.join(sourceDir, ...parts));
+    } catch (cause) {
+      if (CARGO_VIRTUAL_PACKAGE_FILES.has(relative)) {
+        continue;
+      }
+      abort(
+        options.fail,
+        `cargo-listed source ${relative} for ${options.rel(manifest)} is missing: ${cause.message}`,
+      );
+    }
+    const { source, metadata } = sourceFileWithoutSymlinkComponents(
+      sourceDir,
+      parts,
+      manifest,
+      options,
+    );
+    const target = path.join(destination, ...parts);
+    mkdirSync(path.dirname(target), { recursive: true });
+    copyFileSync(source, target);
+    chmodSync(target, metadata.mode & 0o777);
+    copied.add(relative);
+  }
+  const manifestMetadata = lstatSync(manifest);
+  if (manifestMetadata.isSymbolicLink() || !manifestMetadata.isFile()) {
+    abort(options.fail, `${options.rel(manifest)} must be a regular, non-symlink Cargo manifest`);
+  }
+  const targetManifest = path.join(destination, 'Cargo.toml');
+  copyFileSync(manifest, targetManifest);
+  chmodSync(targetManifest, manifestMetadata.mode & 0o777);
+  return copied;
+}
+
+function requireExactCrateMembers(cratePath, packageRoot, expected, { fail, rel }) {
+  const prefix = `${packageRoot}/`;
+  const actual = [...readPortableArchiveEntries(cratePath)]
+    .filter(([, entry]) => !entry.isDirectory)
+    .map(([member]) => {
+      if (!member.startsWith(prefix) || member.length === prefix.length) {
+        abort(fail, `${rel(cratePath)} contains member outside ${packageRoot}: ${member}`);
+      }
+      return member.slice(prefix.length);
+    })
+    .sort(compareText);
+  const wanted = [...expected].sort(compareText);
+  if (actual.length !== wanted.length || actual.some((member, index) => member !== wanted[index])) {
+    const actualSet = new Set(actual);
+    const wantedSet = new Set(wanted);
+    const missing = wanted.filter((member) => !actualSet.has(member));
+    const unexpected = actual.filter((member) => !wantedSet.has(member));
+    abort(
+      fail,
+      `${rel(cratePath)} member set differs from Cargo's package selection: ` +
+        `missing=${JSON.stringify(missing)}, unexpected=${JSON.stringify(unexpected)}`,
+    );
+  }
+}
+
+function requirePackagedCargoTargetSources(
+  packageMetadata,
+  stageDir,
+  expectedMembers,
+  stagedManifest,
+  options,
+) {
+  if (!Array.isArray(packageMetadata.targets)) {
+    abort(
+      options.fail,
+      `cargo metadata for ${options.rel(stagedManifest)} omitted package targets`,
+    );
+  }
+  const absoluteStage = path.resolve(stageDir);
+  for (const target of packageMetadata.targets) {
+    if (target === null || typeof target !== 'object' || typeof target.src_path !== 'string') {
+      abort(
+        options.fail,
+        `cargo metadata for ${options.rel(stagedManifest)} returned an invalid package target`,
+      );
+    }
+    if (!path.isAbsolute(target.src_path)) {
+      abort(
+        options.fail,
+        `cargo target ${JSON.stringify(target.name)} for ${options.rel(stagedManifest)} has a non-absolute source path`,
+      );
+    }
+    const relative = path.relative(absoluteStage, path.resolve(target.src_path));
+    if (!relative || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
+      abort(
+        options.fail,
+        `cargo target ${JSON.stringify(target.name)} for ${options.rel(stagedManifest)} is outside the staged package`,
+      );
+    }
+    const normalized = relative.split(path.sep).join('/');
+    const parts = portablePackagePath(normalized, stagedManifest, options);
+    if (!expectedMembers.has(normalized)) {
+      abort(
+        options.fail,
+        `cargo target ${JSON.stringify(target.name)} source ${normalized} is absent from Cargo's package selection`,
+      );
+    }
+    sourceFileWithoutSymlinkComponents(stageDir, parts, stagedManifest, options);
+  }
+}
+
+function listArchiveEntries(directory) {
+  const files = [];
+  const entries = readdirSync(directory, { withFileTypes: true });
+  entries.sort((left, right) => compareText(left.name, right.name));
+  for (const entry of entries) {
+    const fullPath = path.join(directory, entry.name);
+    if (entry.isDirectory()) {
+      files.push(fullPath, ...listArchiveEntries(fullPath));
+    } else if (entry.isFile()) {
+      files.push(fullPath);
+    } else {
+      throw new Error(
+        'Cargo archive source must contain only regular files and directories: ' + fullPath,
+      );
+    }
+  }
+  return files;
+}
+
+export function createDeterministicTar(stageDir, packageRoot, options) {
+  const chunks = [];
+  const fixedFileMode = options.fixedFileMode;
+  if (
+    fixedFileMode !== undefined &&
+    (!Number.isInteger(fixedFileMode) || fixedFileMode < 0 || fixedFileMode > 0o777)
+  ) {
+    abort(
+      options.fail,
+      'fixed deterministic tar file mode must be an integer between 0000 and 0777',
+    );
+  }
+  const files = listArchiveEntries(stageDir).filter(
+    (file) => options.includeDirectories !== false || statSync(file).isFile(),
+  );
+  files.sort((left, right) =>
+    compareText(path.relative(stageDir, left), path.relative(stageDir, right)),
+  );
+  for (const file of files) {
+    const relative = path.relative(stageDir, file).split(path.sep).join('/');
+    const archivePath = `${packageRoot}/${relative}`;
+    const stats = statSync(file);
+    const isDirectory = stats.isDirectory();
+    const data = isDirectory ? Buffer.alloc(0) : readFileSync(file);
+    const mode = isDirectory ? 0o755 : (fixedFileMode ?? stats.mode & 0o777);
+    chunks.push(tarHeader({ name: archivePath, isDirectory }, data.length, mode));
+    chunks.push(data);
+    const remainder = data.length % 512;
+    if (remainder !== 0) {
+      chunks.push(Buffer.alloc(512 - remainder, 0));
+    }
+  }
+  chunks.push(Buffer.alloc(1024, 0));
+  return Buffer.concat(chunks);
+}
+
+export function prepareCargoPackageSource(
+  manifest,
+  outputDir,
+  files,
+  { fail = null, rel = String, noticeProfile = null } = {},
+) {
+  const { name, version } = readCargoPackageNameVersion(manifest, { fail, rel });
+  const packageRoot = `${name}-${version}`;
+  cargoPackageRelativePathParts(packageRoot);
+  const stageDir = path.resolve(outputDir, 'manual-package-stage', packageRoot);
+  const cratePath = path.resolve(outputDir, `${packageRoot}.crate`);
+  let expectedMembers = [...copyCargoPackageSource(manifest, stageDir, files, { fail, rel })];
+  if (noticeProfile !== null) {
+    stageReleaseNotices(stageDir, { profile: noticeProfile });
+    // Notice staging may add or remove profile-owned members. Cargo still owns
+    // every other source member; archive validation uses the final staged set.
+    expectedMembers = listArchiveEntries(stageDir)
+      .filter((file) => statSync(file).isFile())
+      .map((file) => path.relative(stageDir, file).split(path.sep).join('/'));
+  }
+  const stagedManifest = path.join(stageDir, 'Cargo.toml');
+  writeFileSync(stagedManifest, packagedCargoManifestText(readFileSync(stagedManifest, 'utf8')));
+  return { name, version, packageRoot, stageDir, cratePath, expectedMembers, stagedManifest };
+}
+
+export function finishCargoPackageSource(state, packageMetadata, options = {}) {
+  const { fail = null, rel = String } = options;
+  const { name, version, stageDir, stagedManifest } = state;
+  const expectedMembers = new Set(state.expectedMembers);
+  if (packageMetadata.name !== name || packageMetadata.version !== version) {
+    abort(fail, `${rel(stagedManifest)} produced unexpected cargo metadata`);
+  }
+  requirePackagedCargoTargetSources(packageMetadata, stageDir, expectedMembers, stagedManifest, {
+    fail,
+    rel,
+  });
+  return freezeCargoPackageSource(state, options);
+}
+
+function freezeCargoPackageSource(
+  { stageDir, packageRoot, cratePath, expectedMembers },
+  { fail = null, rel = String, packageSizeLimitBytes = CARGO_PACKAGE_SIZE_LIMIT_BYTES } = {},
+) {
+  rmSync(cratePath, { force: true });
+  writeFileSync(
+    cratePath,
+    canonicalGzipSync(createDeterministicTar(stageDir, packageRoot, { fail })),
+  );
+  requireExactCrateMembers(cratePath, packageRoot, expectedMembers, { fail, rel });
+  const size = statSync(cratePath).size;
+  if (size > packageSizeLimitBytes) {
+    abort(fail, `${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit`);
+  }
+  return cratePath;
+}
+
+/** Every file in this private generated source tree belongs to the carrier. */
+export function packageGeneratedCargoSource(manifest, outputDir, options = {}) {
+  const source = path.dirname(manifest);
+  const files = listArchiveEntries(source)
+    .filter((file) => statSync(file).isFile())
+    .map((file) => path.relative(source, file).split(path.sep).join('/'));
+  const state = prepareCargoPackageSource(manifest, outputDir, files, options);
+  return freezeCargoPackageSource(state, options);
+}
+
+if (import.meta.main) {
+  const [phase, stateFile, ...args] = process.argv.slice(2);
+  if (phase === 'prepare' && args.length === 3) {
+    const [manifest, outputDir, listing] = args;
+    const state = prepareCargoPackageSource(
+      manifest,
+      outputDir,
+      parseCargoPackageFiles(readFileSync(listing, 'utf8'), manifest, { fail: null, rel: String }),
+      { noticeProfile: process.env.OLIPHAUNT_CARGO_NOTICE_PROFILE ?? null },
+    );
+    writeFileSync(stateFile, JSON.stringify(state));
+    console.log(state.stagedManifest);
+  } else if (phase === 'finish' && args.length === 1) {
+    const metadata = JSON.parse(readFileSync(args[0], 'utf8'));
+    if (!Array.isArray(metadata.packages) || metadata.packages.length !== 1) {
+      throw new Error('Cargo metadata must contain exactly one package');
+    }
+    console.log(
+      finishCargoPackageSource(JSON.parse(readFileSync(stateFile, 'utf8')), metadata.packages[0]),
+    );
+  } else {
+    throw new Error(
+      'usage: cargo-source-package.mts prepare STATE MANIFEST OUTPUT LIST | finish STATE METADATA',
+    );
+  }
+}
diff --git a/tools/packaging/cargo-source-package.test.mts b/tools/packaging/cargo-source-package.test.mts
new file mode 100644
index 000000000..078010e97
--- /dev/null
+++ b/tools/packaging/cargo-source-package.test.mts
@@ -0,0 +1,241 @@
+import assert from 'node:assert/strict';
+import { randomBytes } from 'node:crypto';
+import {
+  chmodSync,
+  mkdirSync,
+  mkdtempSync,
+  readFileSync,
+  rmSync,
+  statSync,
+  symlinkSync,
+  writeFileSync,
+} from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+import test from 'node:test';
+import { gzipSync } from 'node:zlib';
+
+import {
+  cargoPackageRelativePathParts,
+  createDeterministicTar,
+  fitCargoPayloadParts,
+  packageGeneratedCargoSource,
+} from './cargo-source-package.mts';
+import { readPortableArchiveEntries } from './portable-archive.mts';
+import { assertReleaseNoticesInArchive } from './release-notices.mts';
+
+function fixture(t, name) {
+  const root = mkdtempSync(path.join(os.tmpdir(), `oliphaunt-${name}-`));
+  t.after(() => rmSync(root, { recursive: true, force: true }));
+  const source = path.join(root, 'source');
+  mkdirSync(path.join(source, 'src'), { recursive: true });
+  return { root, source };
+}
+
+function manifest(name, extra = []) {
+  return [
+    '[package]',
+    `name = ${JSON.stringify(name)}`,
+    'version = "0.1.0"',
+    'edition = "2024"',
+    'license = "MIT"',
+    ...extra,
+    '',
+    '[lib]',
+    'path = "src/lib.rs"',
+    '',
+  ].join('\n');
+}
+
+if (['prepare', 'verify'].includes(process.argv[2])) {
+  const [phase, root] = process.argv.slice(2);
+  const source = path.join(root, 'source');
+  if (phase === 'prepare') {
+    mkdirSync(path.join(source, 'src'), { recursive: true });
+    writeFileSync(
+      path.join(source, 'Cargo.toml'),
+      manifest('selected-package', ['exclude = ["forbidden.txt", "tools/**"]']),
+    );
+    writeFileSync(path.join(source, 'src/lib.rs'), 'pub fn selected() {}\n');
+    chmodSync(path.join(source, 'src/lib.rs'), 0o755);
+    writeFileSync(path.join(source, 'forbidden.txt'), 'must not ship\n');
+    writeFileSync(path.join(source, 'THIRD_PARTY_NOTICES.md'), 'stale source notice\n');
+    mkdirSync(path.join(source, 'tools'));
+    writeFileSync(path.join(source, 'tools/check.sh'), 'must not ship\n');
+
+    for (const kind of ['linked', 'special', 'generated']) {
+      const dir = path.join(root, kind);
+      mkdirSync(path.join(dir, 'src'), { recursive: true });
+      writeFileSync(path.join(dir, 'Cargo.toml'), manifest(kind + '-package'));
+      if (kind === 'generated')
+        writeFileSync(path.join(dir, 'src/lib.rs'), 'pub const VALUE: u32 = 42;\n');
+      if (kind === 'linked') {
+        writeFileSync(path.join(dir, 'real.rs'), 'pub fn linked() {}\n');
+        symlinkSync('../real.rs', path.join(dir, 'src/lib.rs'));
+      }
+    }
+    writeFileSync(
+      path.join(root, 'direct.path'),
+      packageGeneratedCargoSource(
+        path.join(root, 'generated/Cargo.toml'),
+        path.join(root, 'direct'),
+      ),
+    );
+  } else if (phase === 'verify') {
+    const first = readFileSync(path.join(root, 'first.path'), 'utf8').trim();
+    const second = readFileSync(path.join(root, 'second.path'), 'utf8').trim();
+    assert.deepEqual(readFileSync(first), readFileSync(second));
+    assert.equal(
+      readFileSync(first).subarray(0, 10).toString('hex'),
+      '1f8b0800000000000003',
+      'Cargo source packages must use the canonical cross-platform gzip header',
+    );
+
+    const entries = readPortableArchiveEntries(first);
+    assert.deepEqual(
+      [...entries].filter(([, entry]) => entry.isFile).map(([name]) => name),
+      [
+        'selected-package-0.1.0/Cargo.toml',
+        'selected-package-0.1.0/THIRD_PARTY_NOTICES.md',
+        'selected-package-0.1.0/src/lib.rs',
+      ],
+    );
+    assertReleaseNoticesInArchive(readFileSync(path.join(root, 'notices.path'), 'utf8').trim(), {
+      profile: 'source-sdk',
+      prefix: 'selected-package-0.1.0',
+    });
+    assert.equal(
+      readFileSync(path.join(source, 'THIRD_PARTY_NOTICES.md'), 'utf8'),
+      'stale source notice\n',
+    );
+    const sourceMode = statSync(path.join(source, 'src/lib.rs')).mode & 0o777;
+    assert.equal(entries.get('selected-package-0.1.0/src/lib.rs').mode, sourceMode);
+    if (process.platform !== 'win32') {
+      assert.equal(sourceMode, 0o755);
+    }
+    const generated = readFileSync(path.join(root, 'direct.path'), 'utf8').trim();
+    assert.deepEqual(
+      readFileSync(generated),
+      readFileSync(readFileSync(path.join(root, 'generated.path'), 'utf8').trim()),
+    );
+  } else throw new Error('expected prepare or verify');
+  process.exit(0);
+}
+
+test('payload splitting follows compressed crate size and preserves every byte', (t) => {
+  const { root } = fixture(t, 'compressed-parts');
+  for (const payload of [Buffer.alloc(20 * 1024 * 1024, 42), randomBytes(20 * 1024 * 1024)]) {
+    const parts = fitCargoPayloadParts(
+      (budget) => {
+        const directories = [];
+        for (let offset = 0; offset < payload.length; offset += budget) {
+          const directory = path.join(root, `part-${offset}`);
+          mkdirSync(directory, { recursive: true });
+          writeFileSync(path.join(directory, 'payload'), payload.subarray(offset, offset + budget));
+          directories.push(directory);
+        }
+        return directories;
+      },
+      (directory) => {
+        const archive = `${directory}.crate`;
+        writeFileSync(
+          archive,
+          gzipSync(
+            createDeterministicTar(directory, 'part', {
+              fail: (message) => {
+                throw new Error(message);
+              },
+            }),
+          ),
+        );
+        return archive;
+      },
+    );
+    assert.equal(parts.length, payload[0] === 42 && payload.every((byte) => byte === 42) ? 1 : 3);
+    assert.deepEqual(
+      Buffer.concat(parts.map((directory) => readFileSync(path.join(directory, 'payload')))),
+      payload,
+    );
+    for (const directory of parts)
+      assert.ok(statSync(`${directory}.crate`).size <= 9 * 1024 * 1024);
+  }
+});
+
+test('fixed tar file mode is host-independent while the default preserves filesystem modes', (t) => {
+  const { root } = fixture(t, 'deterministic-tar-modes');
+  const stage = path.join(root, 'stage');
+  mkdirSync(stage);
+  mkdirSync(path.join(stage, 'empty'));
+  const writable = path.join(stage, 'writable.txt');
+  const executable = path.join(stage, 'executable.sh');
+  writeFileSync(writable, 'writable\n');
+  writeFileSync(executable, '#!/bin/sh\n');
+  chmodSync(writable, 0o666);
+  chmodSync(executable, 0o755);
+  assert.equal(statSync(writable).mode & 0o777, 0o666);
+
+  const fail = (message) => {
+    throw new Error(message);
+  };
+  const fixedArchive = path.join(root, 'fixed.tar.gz');
+  writeFileSync(
+    fixedArchive,
+    gzipSync(createDeterministicTar(stage, 'carrier', { fail, fixedFileMode: 0o644 }), {
+      mtime: 0,
+    }),
+  );
+  const fixedEntries = readPortableArchiveEntries(fixedArchive);
+  assert.deepEqual(
+    [...fixedEntries].map(([name, entry]) => [name, entry.mode]),
+    [
+      ['carrier/empty', 0o755],
+      ['carrier/executable.sh', 0o644],
+      ['carrier/writable.txt', 0o644],
+    ],
+  );
+
+  const defaultArchive = path.join(root, 'default.tar.gz');
+  writeFileSync(
+    defaultArchive,
+    gzipSync(createDeterministicTar(stage, 'cargo', { fail }), { mtime: 0 }),
+  );
+  const defaultEntries = readPortableArchiveEntries(defaultArchive);
+  assert.equal(defaultEntries.get('cargo/writable.txt').mode, statSync(writable).mode & 0o777);
+  assert.equal(defaultEntries.get('cargo/executable.sh').mode, statSync(executable).mode & 0o777);
+  if (process.platform !== 'win32') {
+    assert.equal(defaultEntries.get('cargo/executable.sh').mode, 0o755);
+  }
+
+  assert.throws(
+    () => createDeterministicTar(stage, 'invalid', { fail, fixedFileMode: 0o1000 }),
+    /fixed deterministic tar file mode/u,
+  );
+});
+
+test('rejects absolute, parent, backslash, and non-portable Cargo member paths', () => {
+  assert.deepEqual(cargoPackageRelativePathParts('src/lib.rs'), ['src', 'lib.rs']);
+  for (const candidate of ['../escape', '/absolute', 'C:/absolute', 'src\\escape', 'bad:name']) {
+    assert.throws(() => cargoPackageRelativePathParts(candidate), /Cargo package path/u);
+  }
+});
+
+test('generated Cargo carriers match Cargo-selected source bytes and reject links', (t) => {
+  const { root, source } = fixture(t, 'generated-cargo');
+  writeFileSync(path.join(source, 'Cargo.toml'), manifest('generated-carrier'));
+  writeFileSync(path.join(source, 'src/lib.rs'), 'pub const VALUE: u32 = 42;\n');
+  writeFileSync(path.join(source, 'README.md'), 'Generated carrier\n');
+  const actual = packageGeneratedCargoSource(
+    path.join(source, 'Cargo.toml'),
+    path.join(root, 'generated'),
+  );
+  assert.equal(
+    readPortableArchiveEntries(actual).get('generated-carrier-0.1.0/src/lib.rs').data().toString(),
+    'pub const VALUE: u32 = 42;\n',
+  );
+  symlinkSync('lib.rs', path.join(source, 'src/link.rs'));
+  assert.throws(
+    () => packageGeneratedCargoSource(path.join(source, 'Cargo.toml'), path.join(root, 'unsafe')),
+    /regular files/,
+  );
+  assert.throws(() => createDeterministicTar(source, 'unsafe', {}), /regular files/);
+});
diff --git a/tools/packaging/cargo-source-package.test.sh b/tools/packaging/cargo-source-package.test.sh
new file mode 100644
index 000000000..1ace00338
--- /dev/null
+++ b/tools/packaging/cargo-source-package.test.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../.."
+bun test --timeout=30000 ./tools/packaging/cargo-source-package.test.mts
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-cargo-source-XXXXXX")
+trap 'rm -rf "$scratch"' EXIT
+bun tools/packaging/cargo-source-package.test.mts prepare "$scratch"
+for output in first second; do
+  bash tools/packaging/package-cargo-source.sh "$scratch/source/Cargo.toml" "$scratch/$output" > "$scratch/$output.path"
+done
+bash tools/packaging/package-cargo-source.sh "$scratch/generated/Cargo.toml" "$scratch/cargo-generated" > "$scratch/generated.path"
+OLIPHAUNT_CARGO_NOTICE_PROFILE=source-sdk bash tools/packaging/package-cargo-source.sh "$scratch/source/Cargo.toml" "$scratch/notices" > "$scratch/notices.path"
+bun tools/packaging/cargo-source-package.test.mts verify "$scratch"
+if bash tools/packaging/package-cargo-source.sh "$scratch/linked/Cargo.toml" "$scratch/linked-out" > "$scratch/link.log" 2>&1; then exit 1; fi
+grep -q 'must not be a symbolic link' "$scratch/link.log"
+if command -v mkfifo >/dev/null; then
+  mkfifo "$scratch/special/src/lib.rs"
+  if bash tools/packaging/package-cargo-source.sh "$scratch/special/Cargo.toml" "$scratch/special-out" > "$scratch/fifo.log" 2>&1; then exit 1; fi
+  grep -q "source src/lib.rs is absent from Cargo's package selection" "$scratch/fifo.log"
+fi
diff --git a/tools/packaging/check-cargo-package-tests.sh b/tools/packaging/check-cargo-package-tests.sh
new file mode 100644
index 000000000..553e79d71
--- /dev/null
+++ b/tools/packaging/check-cargo-package-tests.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+set -euo pipefail
+helper_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+target_dir="${CARGO_TARGET_DIR:-$helper_dir/../../target}"
+prepare_args=()
+test_args=()
+all_features=false
+explicit_features=false
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --target-dir|--features|--crate|--dependency-crate|--path-dependencies-from|--stub-dependency|--stub-dependency-prefix)
+      if [ "$#" -lt 2 ] || [[ "$2" == --* ]]; then echo "$1 requires a value" >&2; exit 1; fi
+      case "$1" in
+        --target-dir) target_dir="$2" ;;
+        --features) explicit_features=true; test_args+=("$1" "$2") ;;
+        *) prepare_args+=("$1" "$2") ;;
+      esac
+      shift 2 ;;
+    --all-features) all_features=true; test_args+=("$1"); shift ;;
+    --no-default-features|--lib) test_args+=("$1"); shift ;;
+    *) echo "unknown argument: $1" >&2; exit 1 ;;
+  esac
+done
+if "$all_features" && "$explicit_features"; then
+  echo '--all-features and --features are mutually exclusive' >&2; exit 1
+fi
+timeout_bin=$(command -v timeout || command -v gtimeout) || {
+  echo 'GNU timeout is required (coreutils on macOS)' >&2; exit 1;
+}
+mkdir -p "$target_dir"
+CARGO_TARGET_DIR=$(cd "$target_dir" && pwd)
+export CARGO_TARGET_DIR CARGO_TERM_COLOR=never
+scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-cargo-package-test-XXXXXX")
+scratch=$(cd "$scratch" && pwd -P)
+trap 'rm -rf "$scratch"' EXIT
+manifest=$(bun "$helper_dir/cargo-package-test-closure.mts" "$scratch" "${prepare_args[@]}")
+if [ ! -f "$(dirname "$manifest")/Cargo.lock" ]; then
+  cp "$helper_dir/../../Cargo.lock" "$(dirname "$manifest")/Cargo.lock"
+fi
+while IFS= read -r name; do
+  case "$name" in OLIPHAUNT_*) unset "$name" ;; esac
+done < <(compgen -e)
+cd "$scratch"
+# Populate the registry cache for the extracted package closure before offline compilation.
+"$timeout_bin" 1800 cargo --config net.offline=false fetch --manifest-path "$manifest"
+"$timeout_bin" 1800 cargo metadata --manifest-path "$manifest" --locked --offline --format-version 1 > /dev/null
+"$timeout_bin" 1800 cargo test --manifest-path "$manifest" --locked --offline --no-run "${test_args[@]}"
+echo "Cargo package test closure verified: $(basename "$(dirname "$manifest")")"
diff --git a/tools/release/check-linux-consumer-baseline.sh b/tools/packaging/check-linux-consumer-baseline.sh
similarity index 100%
rename from tools/release/check-linux-consumer-baseline.sh
rename to tools/packaging/check-linux-consumer-baseline.sh
diff --git a/tools/packaging/emit-javascript.mts b/tools/packaging/emit-javascript.mts
new file mode 100644
index 000000000..1d19238a8
--- /dev/null
+++ b/tools/packaging/emit-javascript.mts
@@ -0,0 +1,36 @@
+import { readFileSync, writeFileSync } from 'node:fs';
+import path from 'node:path';
+
+// Private packagers run with the pinned Bun toolchain. Consumers receive plain
+// JavaScript and do not need Bun or a TypeScript loader.
+export function releaseJavaScript(source: string): Buffer {
+  const code = new Bun.Transpiler({ loader: 'ts', target: 'node' })
+    .transformSync(readFileSync(source, 'utf8'))
+    .replace(/(["'])([^"'\n]+)\.mts\1/g, '$1$2.mjs$1')
+    .replace(/(["'])([^"'\n]+)\.cts\1/g, '$1$2.cjs$1');
+  return Buffer.from(code);
+}
+
+export function emitJavaScript(source: string, destination: string): void {
+  writeFileSync(destination, releaseJavaScript(source), { mode: 0o644 });
+}
+
+export async function bundleJavaScript(source: string): Promise {
+  const result = await Bun.build({
+    entrypoints: [source],
+    root: path.dirname(source),
+    target: 'node',
+    format: 'esm',
+  });
+  if (!result.success || result.outputs.length !== 1) {
+    throw new Error(`Cannot bundle ${source}: ${result.logs.join('\n')}`);
+  }
+  return Buffer.from(await result.outputs[0].arrayBuffer());
+}
+
+if (import.meta.main) {
+  const [source, destination, ...extra] = process.argv.slice(2);
+  if (!source || !destination || extra.length)
+    throw new Error('usage: emit-javascript.mts SOURCE DESTINATION');
+  emitJavaScript(source, destination);
+}
diff --git a/tools/packaging/finalize-helper-assets.mts b/tools/packaging/finalize-helper-assets.mts
new file mode 100644
index 000000000..63460b74a
--- /dev/null
+++ b/tools/packaging/finalize-helper-assets.mts
@@ -0,0 +1,94 @@
+import { readdirSync } from 'node:fs';
+import path from 'node:path';
+import {
+  artifactTargets,
+  compareText,
+  currentProductVersionSync,
+  expectedAssets,
+} from '../release/release-artifact-targets.mts';
+import { writeChecksumManifest } from './write-checksum-manifest.mts';
+
+export function assertExactFilenames(actual, expected, label) {
+  if (
+    new Set(actual).size !== actual.length ||
+    JSON.stringify([...actual].sort(compareText)) !==
+      JSON.stringify([...expected].sort(compareText))
+  )
+    throw new Error(
+      `${label} must be exact: expected=${JSON.stringify(expected)}, actual=${JSON.stringify(actual)}`,
+    );
+}
+
+export function exactRegularDirectoryFilenames(directory, label) {
+  const entries = readdirSync(directory, { withFileTypes: true });
+  const invalid = entries
+    .filter((entry) => !entry.isFile() || entry.isSymbolicLink())
+    .map((entry) => entry.name)
+    .sort(compareText);
+  if (invalid.length)
+    throw new Error(`${label} must contain only regular non-symlink files: ${invalid.join(', ')}`);
+  return entries.map((entry) => entry.name).sort(compareText);
+}
+
+// Each producer owns its validator; this shared step only assembles the complete
+// downloaded target set and returns the files for that producer to validate.
+export async function finalizeHelperAssets(product, kind, argv, { assetDir, npmPackageDir }) {
+  for (let index = 0; index < argv.length; index += 1) {
+    const flag = argv[index];
+    if (flag === '--aggregate') continue;
+    if (
+      !['--asset-dir', '--npm-package-dir'].includes(flag) ||
+      !argv[index + 1] ||
+      argv[index + 1].startsWith('--')
+    )
+      throw new Error(`unsupported aggregate option: ${flag}`);
+    if (flag === '--asset-dir') assetDir = argv[++index];
+    else {
+      if (npmPackageDir === undefined)
+        throw new Error(`${product} has no optional npm package directory`);
+      npmPackageDir = argv[++index];
+    }
+  }
+  assetDir = path.resolve(assetDir);
+  const version = currentProductVersionSync(product);
+  const expected = expectedAssets(product, kind, version, 'finalize-helper-assets');
+  const actual = exactRegularDirectoryFilenames(assetDir, `${product} aggregate asset directory`);
+  const payloads = expected.filter((name) => !name.endsWith('.sha256'));
+  const checksums = expected.filter((name) => name.endsWith('.sha256'));
+  assertExactFilenames(
+    actual.filter((name) => !checksums.includes(name)),
+    payloads,
+    `${product} aggregate payloads`,
+  );
+  const result = ['--asset-dir', assetDir];
+  if (npmPackageDir !== undefined) {
+    npmPackageDir = path.resolve(npmPackageDir);
+    const names = artifactTargets(product, kind, 'finalize-helper-assets').map((target) => {
+      if (!target.npmPackage) throw new Error(`${target.id} must declare an npm package`);
+      return `${target.npmPackage.replace(/^@/u, '').replaceAll('/', '-')}-${version}.tgz`;
+    });
+    assertExactFilenames(
+      exactRegularDirectoryFilenames(npmPackageDir, `${product} npm package directory`),
+      names,
+      `${product} optional npm packages`,
+    );
+    for (const name of names.sort(compareText))
+      result.push('--npm-package', path.join(npmPackageDir, name));
+  }
+  await writeChecksumManifest([
+    '--asset-dir',
+    assetDir,
+    '--output',
+    `${product}-${version}-release-assets.sha256`,
+    '--pattern',
+    `${product}-*.tar.gz`,
+    '--pattern',
+    `${product}-*.zip`,
+  ]);
+  assertExactFilenames(
+    exactRegularDirectoryFilenames(assetDir, `${product} aggregate asset directory`),
+    expected,
+    `${product} aggregate assets`,
+  );
+  return result;
+}
diff --git a/tools/packaging/finalize-helper-assets.test.mts b/tools/packaging/finalize-helper-assets.test.mts
new file mode 100644
index 000000000..02bb2dd5b
--- /dev/null
+++ b/tools/packaging/finalize-helper-assets.test.mts
@@ -0,0 +1,79 @@
+import { afterEach, describe, expect, test } from 'bun:test';
+import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+
+import { assertExactFilenames, exactRegularDirectoryFilenames } from './finalize-helper-assets.mts';
+
+const scratch = [];
+
+afterEach(() => {
+  for (const directory of scratch.splice(0)) {
+    rmSync(directory, { force: true, recursive: true });
+  }
+});
+
+describe('native helper aggregate release assets', () => {
+  test('accepts only an exact, duplicate-free carrier filename set', () => {
+    const expected = ['first.tgz', 'second.tgz'];
+    expect(() =>
+      assertExactFilenames([...expected].reverse(), expected, 'Node carriers'),
+    ).not.toThrow();
+    expect(() => assertExactFilenames(expected.slice(1), expected, 'Node carriers')).toThrow(
+      /must be exact/u,
+    );
+    expect(() =>
+      assertExactFilenames([...expected, expected[0]], expected, 'Node carriers'),
+    ).toThrow(/must be exact/u);
+    expect(() =>
+      assertExactFilenames([...expected, 'unexpected.tgz'], expected, 'Node carriers'),
+    ).toThrow(/must be exact/u);
+  });
+
+  test('rejects non-file and symlink entries instead of hiding them from closure checks', () => {
+    const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-native-helper-closure-'));
+    scratch.push(root);
+    writeFileSync(path.join(root, 'carrier.tgz'), 'carrier');
+    expect(exactRegularDirectoryFilenames(root, 'carrier directory')).toEqual(['carrier.tgz']);
+
+    mkdirSync(path.join(root, 'unexpected-directory'));
+    expect(() => exactRegularDirectoryFilenames(root, 'carrier directory')).toThrow(
+      /only regular non-symlink files: unexpected-directory/u,
+    );
+    rmSync(path.join(root, 'unexpected-directory'), { recursive: true });
+
+    symlinkSync(path.join(root, 'carrier.tgz'), path.join(root, 'unexpected-link.tgz'));
+    expect(() => exactRegularDirectoryFilenames(root, 'carrier directory')).toThrow(
+      /only regular non-symlink files: unexpected-link[.]tgz/u,
+    );
+  });
+});
+
+test('aggregate finalization hashes the complete payload set and rejects extra files before rewriting it', async () => {
+  const { createHash } = await import('node:crypto');
+  const { readFileSync } = await import('node:fs');
+  const { currentProductVersionSync, expectedAssets } = await import(
+    '../release/release-artifact-targets.mts'
+  );
+  const { finalizeHelperAssets } = await import('./finalize-helper-assets.mts');
+  const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-helper-finalize-'));
+  scratch.push(root);
+  const product = 'oliphaunt-broker';
+  const version = currentProductVersionSync(product);
+  const assets = expectedAssets(product, 'broker-helper', version, 'aggregate-test');
+  const checksum = assets.find((name) => name.endsWith('.sha256'));
+  for (const name of assets) writeFileSync(path.join(root, name), name);
+  const args = await finalizeHelperAssets(product, 'broker-helper', ['--aggregate'], {
+    assetDir: root,
+  });
+  expect(args).toEqual(['--asset-dir', root]);
+  const manifest = readFileSync(path.join(root, checksum), 'utf8');
+  for (const name of assets.filter((name) => name !== checksum)) {
+    expect(manifest).toContain(`${createHash('sha256').update(name).digest('hex')}  ./${name}`);
+  }
+  writeFileSync(path.join(root, 'unexpected.tar.gz'), 'unexpected');
+  await expect(
+    finalizeHelperAssets(product, 'broker-helper', ['--aggregate'], { assetDir: root }),
+  ).rejects.toThrow(/must be exact/);
+  expect(readFileSync(path.join(root, checksum), 'utf8')).toBe(manifest);
+});
diff --git a/tools/packaging/linux-abi-baseline.test.sh b/tools/packaging/linux-abi-baseline.test.sh
new file mode 100644
index 000000000..375c9dcd4
--- /dev/null
+++ b/tools/packaging/linux-abi-baseline.test.sh
@@ -0,0 +1,93 @@
+#!/usr/bin/env bash
+set -euo pipefail
+cd "$(dirname "${BASH_SOURCE[0]}")/../.."
+[ "$(uname -s)" = Linux ] || { echo 'Linux baseline command checks require Linux'; exit 0; }
+root="$PWD"
+mkdir -p target
+scratch="$(mktemp -d "$root/target/linux-baseline-test-XXXXXX")"
+outside="$(mktemp -d)"
+trap 'rm -rf "$scratch" "$outside"' EXIT
+mkdir -p "$scratch/bin" "$scratch/consumer"
+printf 'preserve\n' > "$outside/sentinel"
+case "$(uname -m)" in
+  x86_64|amd64) rust_host=x86_64-unknown-linux-gnu; target=linux-x64-gnu ;;
+  aarch64|arm64) rust_host=aarch64-unknown-linux-gnu; target=linux-arm64-gnu ;;
+  *) echo 'Unsupported test host' >&2; exit 1 ;;
+esac
+cat > "$scratch/bin/docker" <<'DOCKER'
+#!/usr/bin/env bash
+set -euo pipefail
+printf '%s\n' "$*" >> "$FAKE_DOCKER_LOG"
+if [ "${1:-}" = image ] && [ "${2:-}" = inspect ]; then
+  printf '%s\n' "${FAKE_IMAGE_DIGEST:-${!#}}"
+elif [ "${1:-}" = run ]; then
+  case "$*" in
+    *'cargo build -p oliphaunt-broker'*)
+      mkdir -p "$FAKE_TARGET_DIR/release"
+      printf '#!/bin/sh\nexit 0\n' > "$FAKE_TARGET_DIR/release/oliphaunt-broker"
+      chmod 755 "$FAKE_TARGET_DIR/release/oliphaunt-broker" ;;
+    *'cargo build --locked --offline --manifest-path /workspace/src/sdks/ts-wasix/node-addon/Cargo.toml'*)
+      mkdir -p "$FAKE_TARGET_DIR/$FAKE_RUST_HOST/release"
+      printf 'fixture\n' > "$FAKE_TARGET_DIR/$FAKE_RUST_HOST/release/liboliphaunt_wasix_napi.so" ;;
+  esac
+else exit 1
+fi
+DOCKER
+chmod 755 "$scratch/bin/docker"
+export PATH="$scratch/bin:$PATH" CARGO_HOME="$scratch/cargo-home"
+export FAKE_DOCKER_LOG="$scratch/docker.log" FAKE_TARGET_DIR="$scratch/output" FAKE_RUST_HOST="$rust_host"
+export OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR="$scratch/inputs/portable"
+export OLIPHAUNT_WASM_GENERATED_AOT_DIR="$scratch/inputs/aot"
+export OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="$scratch/inputs/extensions"
+export OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS="$scratch/inputs/build-inputs.json"
+mkdir -p "$OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR" "$OLIPHAUNT_WASM_GENERATED_AOT_DIR" "$OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT"
+printf '{}\n' > "$OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS"
+
+assert_isolated() {
+  local flag
+  for flag in '--pull never' '--network none' '--read-only' '--cap-drop ALL' '--security-opt no-new-privileges'; do
+    grep -Fq -- "$flag" "$FAKE_DOCKER_LOG"
+  done
+  ! grep -Eq 'docker\.sock|credentials|config\.json' "$FAKE_DOCKER_LOG"
+}
+broker=src/broker/tools/build-linux-broker-baseline.sh
+wasix=src/sdks/ts-wasix/node-addon/tools/build-linux-wasix-napi-baseline.sh
+consumer=tools/packaging/check-linux-consumer-baseline.sh
+bash "$broker" "$FAKE_TARGET_DIR"
+assert_isolated
+grep -Fq -- "$root:/workspace:ro" "$FAKE_DOCKER_LOG"
+grep -Fq 'CARGO_NET_OFFLINE=true' "$FAKE_DOCKER_LOG"
+grep -Fq 'OLIPHAUNT_BROKER_AUTH_TOKEN=abi-probe' "$FAKE_DOCKER_LOG"
+: > "$FAKE_DOCKER_LOG"
+bash "$wasix" "$FAKE_TARGET_DIR" "$rust_host" release
+assert_isolated
+grep -Fq 'OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR=/workspace/target/' "$FAKE_DOCKER_LOG"
+grep -Fq 'OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS=/workspace/target/' "$FAKE_DOCKER_LOG"
+grep -Fq 'cargo build --locked --offline' "$FAKE_DOCKER_LOG"
+grep -Fq -- '--features release' "$FAKE_DOCKER_LOG"
+: > "$FAKE_DOCKER_LOG"
+bash "$consumer" --target "$target" --root "$scratch/consumer"
+assert_isolated
+grep -Fq -- "$scratch/consumer:/consumer:ro" "$FAKE_DOCKER_LOG"
+
+reject() {
+  if "$@" > "$scratch/rejection" 2>&1; then
+    echo "Unexpectedly accepted: $*" >&2; exit 1
+  fi
+}
+outside_relative="$(realpath --relative-to="$root/target" "$outside")"
+for path in "$outside" "$root/target/$outside_relative"; do
+  reject bash "$broker" "$path"
+  grep -Fq 'must be below' "$scratch/rejection"
+  reject bash "$wasix" "$path" "$rust_host" release
+  grep -Fq 'must be below' "$scratch/rejection"
+done
+ln -s "$outside" "$scratch/escaped"
+reject bash "$broker" "$scratch/escaped"
+grep -Fq 'must be below' "$scratch/rejection"
+reject bash "$consumer" --target "$target" --root "$scratch/escaped"
+grep -Fq 'must be below' "$scratch/rejection"
+test "$(cat "$outside/sentinel")" = preserve
+reject env FAKE_IMAGE_DIGEST=wrong-image bash "$broker" "$FAKE_TARGET_DIR"
+grep -Fq 'required pinned digest' "$scratch/rejection"
+echo 'Linux baseline isolation, pin rejection and outside-path preservation passed'
diff --git a/tools/packaging/local-npm-tarball.mts b/tools/packaging/local-npm-tarball.mts
new file mode 100644
index 000000000..4eecae234
--- /dev/null
+++ b/tools/packaging/local-npm-tarball.mts
@@ -0,0 +1,10 @@
+import { copyFileSync } from 'node:fs';
+import { basename, join } from 'node:path';
+
+export function stageLocalNpmTarball(file, consumer) {
+  // Bun on Windows cannot reliably extract file:///D:/ tarball dependencies.
+  // Keep the archive beside the manifest, including when scratch is on another drive.
+  const name = basename(file);
+  copyFileSync(file, join(consumer, name));
+  return `file:./${name}`;
+}
diff --git a/tools/packaging/local-npm-tarball.test.mts b/tools/packaging/local-npm-tarball.test.mts
new file mode 100644
index 000000000..4c1c1e26b
--- /dev/null
+++ b/tools/packaging/local-npm-tarball.test.mts
@@ -0,0 +1,56 @@
+import assert from 'node:assert/strict';
+import { spawnSync } from 'node:child_process';
+import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import { tmpdir } from 'node:os';
+import { join } from 'node:path';
+import test from 'node:test';
+import { createDeterministicTar } from './cargo-source-package.mts';
+import { canonicalGzipSync } from './portable-archive.mts';
+import { stageLocalNpmTarball } from './local-npm-tarball.mts';
+
+test('npm and Bun consume the same staged carrier bytes from a path with spaces', () => {
+  const root = mkdtempSync(join(tmpdir(), 'local npm carrier '));
+  try {
+    const source = join(root, 'source');
+    mkdirSync(join(source, 'prebuilds'), { recursive: true });
+    const manifest = { name: '@fixture/carrier', version: '1.0.0' };
+    writeFileSync(join(source, 'package.json'), JSON.stringify(manifest));
+    const payload = Buffer.from([0, 1, 2, 255]);
+    writeFileSync(join(source, 'prebuilds', 'addon.node'), payload);
+    const archive = join(root, 'carrier-1.0.0.tgz');
+    writeFileSync(archive, canonicalGzipSync(createDeterministicTar(source, 'package', {})));
+    for (const manager of ['npm', 'bun']) {
+      const consumer = join(root, manager);
+      mkdirSync(consumer);
+      const dependency = stageLocalNpmTarball(archive, consumer);
+      assert.equal(dependency, 'file:./carrier-1.0.0.tgz');
+      assert.deepEqual(readFileSync(join(consumer, 'carrier-1.0.0.tgz')), readFileSync(archive));
+      writeFileSync(
+        join(consumer, 'package.json'),
+        JSON.stringify({
+          name: 'consumer',
+          private: true,
+          dependencies: { [manifest.name]: dependency },
+        }),
+      );
+      const result = spawnSync(manager, ['install', '--ignore-scripts'], {
+        cwd: consumer,
+        encoding: 'utf8',
+        timeout: 60_000,
+        shell: process.platform === 'win32' && manager === 'npm',
+        env: { ...process.env, NPM_CONFIG_AUDIT: 'false', NPM_CONFIG_FUND: 'false' },
+      });
+      assert.equal(
+        result.status,
+        0,
+        `${manager}: ${result.error ?? ''}\n${result.stdout}\n${result.stderr}`,
+      );
+      assert.deepEqual(
+        readFileSync(join(consumer, 'node_modules/@fixture/carrier/prebuilds/addon.node')),
+        payload,
+      );
+    }
+  } finally {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
diff --git a/tools/packaging/materialize-release-symlinks.mts b/tools/packaging/materialize-release-symlinks.mts
new file mode 100644
index 000000000..49b16a624
--- /dev/null
+++ b/tools/packaging/materialize-release-symlinks.mts
@@ -0,0 +1,175 @@
+#!/usr/bin/env bun
+
+import { randomUUID } from 'node:crypto';
+import { constants } from 'node:fs';
+import {
+  chmod,
+  copyFile,
+  lstat,
+  readlink,
+  readdir,
+  rename,
+  rm,
+  symlink,
+  utimes,
+} from 'node:fs/promises';
+import path from 'node:path';
+import process from 'node:process';
+import { fileURLToPath } from 'node:url';
+
+const TOOL = 'materialize-release-symlinks.mts';
+
+function fail(message) {
+  throw new Error(`${TOOL}: ${message}`);
+}
+
+function compareText(left, right) {
+  return left < right ? -1 : left > right ? 1 : 0;
+}
+
+function isInside(root, candidate) {
+  const relative = path.relative(root, candidate);
+  return (
+    relative === '' ||
+    (!path.isAbsolute(relative) && relative !== '..' && !relative.startsWith(`..${path.sep}`))
+  );
+}
+
+async function requiredLstat(file, context) {
+  try {
+    return await lstat(file);
+  } catch (error) {
+    fail(`${context}: ${error.message}`);
+  }
+}
+
+async function collectSymlinks(root, directory = root, links = []) {
+  const entries = (await readdir(directory)).sort(compareText);
+  for (const name of entries) {
+    const file = path.join(directory, name);
+    const stat = await requiredLstat(file, `cannot inspect ${file}`);
+    if (stat.isSymbolicLink()) {
+      links.push(file);
+    } else if (stat.isDirectory()) {
+      await collectSymlinks(root, file, links);
+    }
+  }
+  return links;
+}
+
+async function resolveRegularTarget(root, link) {
+  let current = link;
+  const visited = new Set([current]);
+
+  while (true) {
+    const target = await readlink(current);
+    if (target.length === 0 || path.isAbsolute(target) || path.win32.isAbsolute(target)) {
+      fail(`${link} must use only relative symbolic-link targets`);
+    }
+    const next = path.resolve(path.dirname(current), target);
+    if (!isInside(root, next)) {
+      fail(`${link} escapes the staged release tree through ${JSON.stringify(target)}`);
+    }
+    const stat = await requiredLstat(next, `${link} has a broken symbolic-link target`);
+    if (stat.isSymbolicLink()) {
+      if (visited.has(next)) {
+        fail(`${link} contains a symbolic-link cycle`);
+      }
+      visited.add(next);
+      current = next;
+      continue;
+    }
+    if (!stat.isFile()) {
+      fail(`${link} must resolve to a regular file, not a directory or special file`);
+    }
+    return { file: next, stat };
+  }
+}
+
+async function cleanupTemps(plans) {
+  await Promise.all(plans.map(({ temp }) => rm(temp, { force: true }).catch(() => {})));
+}
+
+export async function materializeReleaseSymlinks(rootInput) {
+  if (typeof rootInput !== 'string' || rootInput.length === 0 || rootInput.includes('\0')) {
+    fail('a staged release root is required');
+  }
+  const root = path.resolve(rootInput);
+  const rootStat = await requiredLstat(root, `cannot inspect staged release root ${root}`);
+  if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
+    fail(`staged release root must be a real directory: ${root}`);
+  }
+
+  const links = await collectSymlinks(root);
+  const plans = [];
+  for (const link of links) {
+    const originalTarget = await readlink(link);
+    const resolved = await resolveRegularTarget(root, link);
+    plans.push({
+      link,
+      originalTarget,
+      source: resolved.file,
+      sourceStat: resolved.stat,
+      temp: path.join(
+        path.dirname(link),
+        `.${path.basename(link)}.materialize-${randomUUID()}.tmp`,
+      ),
+    });
+  }
+
+  try {
+    for (const plan of plans) {
+      await copyFile(plan.source, plan.temp, constants.COPYFILE_EXCL);
+      await chmod(plan.temp, plan.sourceStat.mode & 0o777);
+      await utimes(plan.temp, plan.sourceStat.atime, plan.sourceStat.mtime);
+    }
+  } catch (error) {
+    await cleanupTemps(plans);
+    fail(`could not stage verified symbolic-link replacements: ${error.message}`);
+  }
+
+  const committed = [];
+  try {
+    for (const plan of plans) {
+      const currentStat = await requiredLstat(plan.link, `cannot revalidate ${plan.link}`);
+      const currentTarget = currentStat.isSymbolicLink() ? await readlink(plan.link) : '';
+      if (!currentStat.isSymbolicLink() || currentTarget !== plan.originalTarget) {
+        fail(`${plan.link} changed while its replacement was staged`);
+      }
+      await rename(plan.temp, plan.link);
+      committed.push(plan);
+    }
+  } catch (error) {
+    for (const plan of committed.reverse()) {
+      await rm(plan.link, { force: true }).catch(() => {});
+      await symlink(plan.originalTarget, plan.link).catch(() => {});
+    }
+    await cleanupTemps(plans);
+    throw error;
+  }
+
+  await cleanupTemps(plans);
+  const remaining = await collectSymlinks(root);
+  if (remaining.length !== 0) {
+    fail(`staged release tree still contains symbolic links: ${remaining.join(', ')}`);
+  }
+  return plans.length;
+}
+
+async function main(argv) {
+  if (argv.length !== 1) {
+    fail('usage: tools/packaging/materialize-release-symlinks.mts ROOT');
+  }
+  const count = await materializeReleaseSymlinks(argv[0]);
+  console.log(`materializedReleaseSymlinks=${count}`);
+}
+
+if (
+  process.argv[1] !== undefined &&
+  path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
+) {
+  main(process.argv.slice(2)).catch((error) => {
+    console.error(error instanceof Error ? error.message : String(error));
+    process.exit(1);
+  });
+}
diff --git a/tools/packaging/materialize-release-symlinks.test.mts b/tools/packaging/materialize-release-symlinks.test.mts
new file mode 100644
index 000000000..f0917d79f
--- /dev/null
+++ b/tools/packaging/materialize-release-symlinks.test.mts
@@ -0,0 +1,90 @@
+import { afterEach, describe, expect, test } from 'bun:test';
+import { chmod, lstat, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises';
+import { tmpdir } from 'node:os';
+import path from 'node:path';
+
+import { materializeReleaseSymlinks } from './materialize-release-symlinks.mts';
+
+const roots = [];
+
+async function fixture(name) {
+  const root = await mkdtemp(path.join(tmpdir(), `oliphaunt-materialize-${name}-`));
+  roots.push(root);
+  return root;
+}
+
+afterEach(async () => {
+  await Promise.all(roots.splice(0).map((root) => rm(root, { force: true, recursive: true })));
+});
+
+describe('release symlink materialization', () => {
+  test('materializes contained versioned library aliases as regular files', async () => {
+    const root = await fixture('aliases');
+    const lib = path.join(root, 'runtime', 'lib');
+    await mkdir(lib, { recursive: true });
+    const versioned = path.join(lib, 'libexample.so.3.1');
+    await writeFile(versioned, 'verified-library-bytes\n');
+    await chmod(versioned, 0o555);
+    await symlink('libexample.so.3.1', path.join(lib, 'libexample.so.3'));
+    await symlink('libexample.so.3', path.join(lib, 'libexample.so'));
+    await symlink('libexample.so.3.1', path.join(lib, 'libexample.dylib'));
+
+    expect(await materializeReleaseSymlinks(root)).toBe(3);
+    for (const name of ['libexample.so.3', 'libexample.so', 'libexample.dylib']) {
+      const file = path.join(lib, name);
+      const stat = await lstat(file);
+      expect(stat.isFile()).toBe(true);
+      expect(stat.isSymbolicLink()).toBe(false);
+      expect(stat.mode & 0o777).toBe(0o555);
+      expect(await readFile(file, 'utf8')).toBe('verified-library-bytes\n');
+    }
+  });
+
+  test('validates the complete tree before replacing any link', async () => {
+    const root = await fixture('transaction');
+    const outside = await fixture('outside');
+    await writeFile(path.join(root, 'library.so.1'), 'library\n');
+    await writeFile(path.join(outside, 'escape.so'), 'escape\n');
+    const valid = path.join(root, 'library.so');
+    const escaping = path.join(root, 'escape.so');
+    await symlink('library.so.1', valid);
+    await symlink(path.relative(root, path.join(outside, 'escape.so')), escaping);
+
+    await expect(materializeReleaseSymlinks(root)).rejects.toThrow(
+      /escapes the staged release tree/u,
+    );
+    expect((await lstat(valid)).isSymbolicLink()).toBe(true);
+    expect((await lstat(escaping)).isSymbolicLink()).toBe(true);
+  });
+
+  test('rejects absolute, broken, directory, cyclic, and symlink-root inputs', async () => {
+    const absoluteRoot = await fixture('absolute');
+    await writeFile(path.join(absoluteRoot, 'real.so'), 'library\n');
+    await symlink(path.join(absoluteRoot, 'real.so'), path.join(absoluteRoot, 'absolute.so'));
+    await expect(materializeReleaseSymlinks(absoluteRoot)).rejects.toThrow(/only relative/u);
+
+    const brokenRoot = await fixture('broken');
+    await symlink('missing.so', path.join(brokenRoot, 'broken.so'));
+    await expect(materializeReleaseSymlinks(brokenRoot)).rejects.toThrow(
+      /broken symbolic-link target/u,
+    );
+
+    const directoryRoot = await fixture('directory');
+    await mkdir(path.join(directoryRoot, 'real-directory'));
+    await symlink('real-directory', path.join(directoryRoot, 'directory-link'));
+    await expect(materializeReleaseSymlinks(directoryRoot)).rejects.toThrow(/regular file/u);
+
+    const cycleRoot = await fixture('cycle');
+    await symlink('second.so', path.join(cycleRoot, 'first.so'));
+    await symlink('first.so', path.join(cycleRoot, 'second.so'));
+    await expect(materializeReleaseSymlinks(cycleRoot)).rejects.toThrow(/cycle/u);
+
+    const targetRoot = await fixture('root-target');
+    const linkedRoot = `${targetRoot}-link`;
+    roots.push(linkedRoot);
+    await symlink(targetRoot, linkedRoot);
+    await expect(materializeReleaseSymlinks(linkedRoot)).rejects.toThrow(
+      /root must be a real directory/u,
+    );
+  });
+});
diff --git a/tools/packaging/maven-artifact-manifest.mts b/tools/packaging/maven-artifact-manifest.mts
new file mode 100644
index 000000000..8a89d269a
--- /dev/null
+++ b/tools/packaging/maven-artifact-manifest.mts
@@ -0,0 +1,149 @@
+import { lstatSync, readFileSync } from 'node:fs';
+import path from 'node:path';
+const ROOT = path.resolve(import.meta.dir, '../..');
+function error(message) {
+  return new Error('maven-artifact-manifest: ' + message);
+}
+const TOKEN = /^[A-Za-z0-9_.-]+$/u;
+const GROUP_SEGMENT = /^[A-Za-z0-9_-]+$/u;
+const CONTROL = /[\u0000-\u001f\u007f]/u;
+function relative(file) {
+  const value = path.relative(ROOT, file);
+  return value.startsWith('..') || path.isAbsolute(value)
+    ? file.split(path.sep).join('/')
+    : value.split(path.sep).join('/');
+}
+
+function requiredText(value, label) {
+  if (typeof value !== 'string' || value.length === 0 || CONTROL.test(value)) {
+    throw error(`${label} must be non-empty text without control characters`);
+  }
+  return value;
+}
+
+function token(value, label) {
+  requiredText(value, label);
+  if (!TOKEN.test(value) || value === '.' || value === '..') {
+    throw error(`${label} must be a portable non-dot Maven coordinate token`);
+  }
+  return value;
+}
+
+function mavenGroupId(value, label) {
+  requiredText(value, label);
+  const segments = value.split('.');
+  if (segments.some((segment) => !GROUP_SEGMENT.test(segment))) {
+    throw error(`${label} must contain non-empty dot-separated portable Maven coordinate segments`);
+  }
+  return value;
+}
+
+function parseLicenses(raw, label) {
+  let value;
+  try {
+    value = JSON.parse(raw);
+  } catch (cause) {
+    throw error(`${label} must be valid JSON: ${cause.message}`);
+  }
+  if (!Array.isArray(value) || value.length === 0) {
+    throw error(`${label} must be a non-empty JSON array`);
+  }
+  for (const [index, license] of value.entries()) {
+    const entry = `${label} entry ${index + 1}`;
+    if (
+      license === null ||
+      Array.isArray(license) ||
+      typeof license !== 'object' ||
+      JSON.stringify(Object.keys(license).sort()) !==
+        JSON.stringify(['distribution', 'name', 'url'])
+    ) {
+      throw error(`${entry} must contain exactly name, url, distribution`);
+    }
+    requiredText(license.name, `${entry}.name`);
+    const url = requiredText(license.url, `${entry}.url`);
+    if (!url.startsWith('https://')) throw error(`${entry}.url must use HTTPS`);
+    if (license.distribution !== 'repo') throw error(`${entry}.distribution must be repo`);
+  }
+  return value;
+}
+
+function requireArtifact(file, label) {
+  let metadata;
+  try {
+    metadata = lstatSync(file);
+  } catch (cause) {
+    throw error(`${label} is missing: ${cause.message}`);
+  }
+  if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) {
+    throw error(`${label} must be a non-empty regular non-symlink file`);
+  }
+}
+
+export function parseMavenArtifactManifest(file) {
+  requireArtifact(file, `${relative(file)} Maven artifact manifest`);
+  const rows = readFileSync(file, 'utf8')
+    .split(/\r?\n/u)
+    .filter((line) => line.length > 0);
+  if (rows.length === 0) throw error(`${relative(file)} Maven artifact manifest is empty`);
+  const coordinates = new Set();
+  return rows.map((line, index) => {
+    const label = `${relative(file)} line ${index + 1}`;
+    const fields = line.split('\t');
+    if (fields.length !== 10) throw error(`${label} must contain exactly ten tab-separated fields`);
+    const [
+      groupId,
+      artifactId,
+      version,
+      rawArtifact,
+      name,
+      description,
+      runtimeProduct,
+      runtimeVersion,
+      licenseSpdx,
+      licensesJson,
+    ] = fields;
+    mavenGroupId(groupId, `${label} groupId`);
+    token(artifactId, `${label} artifactId`);
+    token(version, `${label} version`);
+    const coordinate = `${groupId}:${artifactId}:${version}`;
+    if (coordinates.has(coordinate)) throw error(`${label} repeats Maven coordinate ${coordinate}`);
+    coordinates.add(coordinate);
+    requiredText(rawArtifact, `${label} artifact path`);
+    if (!rawArtifact.endsWith('.tar.gz'))
+      throw error(`${label} artifact must be a .tar.gz payload`);
+    const artifact = path.isAbsolute(rawArtifact) ? rawArtifact : path.resolve(ROOT, rawArtifact);
+    requireArtifact(artifact, `${label} artifact ${relative(artifact)}`);
+    requiredText(name, `${label} name`);
+    requiredText(description, `${label} description`);
+    if ((runtimeProduct.length === 0) !== (runtimeVersion.length === 0)) {
+      throw error(`${label} must declare both runtime product and version or neither`);
+    }
+    if (runtimeProduct.length > 0) {
+      token(runtimeProduct, `${label} runtime product`);
+      token(runtimeVersion, `${label} runtime version`);
+    }
+    if (
+      groupId === 'dev.oliphaunt.extensions' &&
+      (runtimeProduct !== 'liboliphaunt-native' ||
+        !/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/.test(runtimeVersion))
+    ) {
+      throw error(
+        label + ' extension carrier must bind an exact stable liboliphaunt-native runtime version',
+      );
+    }
+    requiredText(licenseSpdx, `${label} SPDX expression`);
+    const licenses = parseLicenses(licensesJson, `${label} licenses`);
+    return Object.freeze({
+      artifact,
+      artifactId,
+      description,
+      groupId,
+      licenses,
+      licenseSpdx,
+      name,
+      runtimeProduct: runtimeProduct || null,
+      runtimeVersion: runtimeVersion || null,
+      version,
+    });
+  });
+}
diff --git a/tools/packaging/maven-artifact-manifest.test.mts b/tools/packaging/maven-artifact-manifest.test.mts
new file mode 100644
index 000000000..b084e366f
--- /dev/null
+++ b/tools/packaging/maven-artifact-manifest.test.mts
@@ -0,0 +1,272 @@
+import { afterEach, expect, test } from 'bun:test';
+import { chmodSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
+import os from 'node:os';
+import path from 'node:path';
+
+import { buildMavenArtifactManifest } from './build-maven-artifact-manifest.mts';
+import { archiveDirectory } from './archive-directory.mts';
+import { createDeterministicTar } from './cargo-source-package.mts';
+import { stageExtensionUpstreamLicenses } from '../../src/extensions/tools/extension-upstream-licenses.mts';
+import { canonicalGzipSync } from './portable-archive.mts';
+import { parseMavenArtifactManifest } from './maven-artifact-manifest.mts';
+import {
+  currentProductVersionSync,
+  extensionReleaseVersion,
+} from '../release/release-artifact-targets.mts';
+import { ROOT } from '../release/release-graph.mts';
+import { stageReleaseNotices } from './release-notices.mts';
+
+const temporaryRoots = [];
+
+afterEach(() => {
+  for (const root of temporaryRoots.splice(0)) {
+    rmSync(root, { recursive: true, force: true });
+  }
+});
+
+function temporaryDirectory() {
+  const directory = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-maven-manifest-lock-'));
+  temporaryRoots.push(directory);
+  return directory;
+}
+
+function contribAndroidBundle(root, target, { archiveRoot } = {}) {
+  const product = 'oliphaunt-extension-contrib-pg18';
+  const version = extensionReleaseVersion(product, 'native');
+  const canonicalRoot = `${product}-${version}-native-${target}-bundle`;
+  const stage = path.join(root, 'bundle-stage', target);
+  const output = path.join(
+    root,
+    'liboliphaunt-native',
+    product,
+    'release-assets',
+    `${canonicalRoot}.tar.gz`,
+  );
+  mkdirSync(stage, { recursive: true });
+  mkdirSync(path.dirname(output), { recursive: true });
+  stageReleaseNotices(stage, { profile: 'contrib-native-openssl' });
+  writeFileSync(path.join(stage, 'bundle-manifest.json'), '{}\n');
+  writeFileSync(
+    output,
+    canonicalGzipSync(
+      createDeterministicTar(stage, archiveRoot ?? canonicalRoot, {
+        fail(message) {
+          throw new Error(message);
+        },
+        fixedFileMode: 0o644,
+      }),
+    ),
+  );
+  return output;
+}
+
+async function singletonAndroidRuntime(
+  root,
+  target,
+  { mutateUpstream = false, upstreamRoot = 'files' } = {},
+) {
+  const product = 'oliphaunt-extension-pg-hashids';
+  const version = currentProductVersionSync(product);
+  const name = `${product}-${version}-native-${target}-runtime.tar.gz`;
+  const stage = path.join(root, 'singleton-stage', target);
+  const output = path.join(root, product, 'release-assets', name);
+  rmSync(stage, { recursive: true, force: true });
+  mkdirSync(stage, { recursive: true });
+  chmodSync(stage, 0o755);
+  mkdirSync(path.dirname(output), { recursive: true });
+  stageReleaseNotices(stage, { profile: 'external-native' });
+  if (upstreamRoot !== null) {
+    const staged = stageExtensionUpstreamLicenses('pg_hashids', path.join(stage, upstreamRoot));
+    for (const directory of [
+      upstreamRoot,
+      `${upstreamRoot}/share`,
+      `${upstreamRoot}/share/licenses`,
+      `${upstreamRoot}/share/licenses/pg_hashids`,
+    ])
+      chmodSync(path.join(stage, directory), 0o755);
+    if (mutateUpstream) {
+      writeFileSync(path.join(stage, upstreamRoot, staged[0]), 'substituted upstream license\n');
+    }
+  }
+  writeFileSync(path.join(stage, 'manifest.properties'), 'packageLayout=fixture\n');
+  await archiveDirectory(stage, output);
+  return output;
+}
+
+test('the real Maven manifest builder feeds the canonical ten-field schema into Maven staging', {
+  timeout: 30_000,
+}, async () => {
+  const root = temporaryDirectory();
+  const assets = path.join(root, 'assets');
+  const manifestDirectory = path.join(root, 'maven-artifacts');
+  const manifest = path.join(manifestDirectory, 'runtime.tsv');
+  const version = currentProductVersionSync('database-resources');
+  mkdirSync(manifestDirectory, { recursive: true });
+
+  mkdirSync(assets);
+  for (const [suffix, profile] of [['icu-data', 'native-icu-data']]) {
+    const name = `database-resources-${version}-${suffix}`;
+    const stage = path.join(root, name);
+    mkdirSync(stage);
+    stageReleaseNotices(stage, { profile });
+    writeFileSync(
+      path.join(assets, `${name}.tar.gz`),
+      canonicalGzipSync(createDeterministicTar(stage, name, { fixedFileMode: 0o644 })),
+    );
+  }
+  await buildMavenArtifactManifest(manifest, {
+    runtime: true,
+    artifactProduct: 'database-resources',
+    artifactIds: ['oliphaunt-icu'],
+    runtimeAssetRoot: assets,
+  });
+
+  const original = readFileSync(manifest, 'utf8');
+  const rows = original.trimEnd().split('\n');
+  expect(rows).toHaveLength(1);
+  expect(rows.every((row) => row.split('\t').length === 10)).toBe(true);
+
+  const records = parseMavenArtifactManifest(manifest);
+  expect(records.map(({ groupId, artifactId }) => groupId + ':' + artifactId).sort()).toEqual([
+    'dev.oliphaunt.runtime:oliphaunt-icu',
+  ]);
+  expect(
+    records.every((record) => record.version === version && record.artifact.endsWith('.tar.gz')),
+  ).toBe(true);
+
+  const first = rows[0].split('\t');
+  const licenses = JSON.parse(first[9]).map(({ name, url, distribution }) => ({
+    url,
+    distribution,
+    name,
+  }));
+  writeFileSync(
+    manifest,
+    first.with(9, JSON.stringify(licenses, null, 0).replaceAll(',', ', ')).join('\t') + '\n',
+  );
+  expect(parseMavenArtifactManifest(manifest)).toHaveLength(1);
+  const mutations = [
+    ['legacy field count', first.slice(0, 8), /ten tab-separated fields/u],
+    ['missing display name', first.with(4, ''), /name/u],
+    [
+      'half runtime binding',
+      first.with(6, 'liboliphaunt-native'),
+      /both runtime product and version/u,
+    ],
+    ['missing SPDX expression', first.with(8, ''), /SPDX expression/u],
+    ['non-array licenses', first.with(9, '{}'), /non-empty JSON array/u],
+    [
+      'non-canonical license entry',
+      first.with(
+        9,
+        JSON.stringify([
+          { name: 'MIT', url: 'https://example.invalid/MIT', distribution: 'repo', extra: true },
+        ]),
+      ),
+      /must contain exactly name, url, distribution/u,
+    ],
+    [
+      'insecure license URL',
+      first.with(
+        9,
+        JSON.stringify([{ name: 'MIT', url: 'http://example.invalid/MIT', distribution: 'repo' }]),
+      ),
+      /must use HTTPS/u,
+    ],
+  ];
+  for (const [label, mutated, pattern] of mutations) {
+    writeFileSync(manifest, `${mutated.join('\t')}\n${rows.slice(1).join('\n')}\n`);
+    expect(() => parseMavenArtifactManifest(manifest), label).toThrow(pattern);
+  }
+});
+
+test('the Maven manifest builder validates notices beneath an exact bundle archive root', {
+  timeout: 30_000,
+}, async () => {
+  const root = temporaryDirectory();
+  const manifest = path.join(root, 'maven-artifacts', 'contrib.tsv');
+  for (const target of ['android-arm64-v8a', 'android-x86_64']) {
+    contribAndroidBundle(root, target);
+  }
+
+  await buildMavenArtifactManifest(manifest, {
+    extensions: true,
+    extensionProducts: ['oliphaunt-extension-contrib-pg18'],
+    extensionArtifactRoot: root,
+  });
+  const contribRows = readFileSync(manifest, 'utf8').trimEnd().split('\n');
+  expect(contribRows).toHaveLength(2);
+  const nativeVersion = currentProductVersionSync('liboliphaunt-native');
+  expect(contribRows.map((row) => row.split('\t').slice(0, 8))).toEqual([
+    [
+      'dev.oliphaunt.extensions',
+      'oliphaunt-extension-contrib-pg18-android-arm64-v8a',
+      nativeVersion,
+      expect.any(String),
+      expect.any(String),
+      expect.any(String),
+      'liboliphaunt-native',
+      nativeVersion,
+    ],
+    [
+      'dev.oliphaunt.extensions',
+      'oliphaunt-extension-contrib-pg18-android-x86_64',
+      nativeVersion,
+      expect.any(String),
+      expect.any(String),
+      expect.any(String),
+      'liboliphaunt-native',
+      nativeVersion,
+    ],
+  ]);
+
+  contribAndroidBundle(root, 'android-arm64-v8a', { archiveRoot: 'substituted-root' });
+  await expect(
+    buildMavenArtifactManifest(manifest, {
+      extensions: true,
+      extensionProducts: ['oliphaunt-extension-contrib-pg18'],
+      extensionArtifactRoot: root,
+    }),
+  ).rejects.toThrow(/canonical single archive root/u);
+});
+
+test('the Maven manifest builder validates singleton upstream licenses in the runtime files namespace', {
+  timeout: 30_000,
+}, async () => {
+  const root = temporaryDirectory();
+  const manifest = path.join(root, 'maven-artifacts', 'pg-hashids.tsv');
+  for (const target of ['android-arm64-v8a', 'android-x86_64']) {
+    await singletonAndroidRuntime(root, target);
+  }
+
+  await buildMavenArtifactManifest(manifest, {
+    extensions: true,
+    extensionProducts: ['oliphaunt-extension-pg-hashids'],
+    extensionArtifactRoot: root,
+  });
+  expect(readFileSync(manifest, 'utf8').trimEnd().split('\n')).toHaveLength(2);
+
+  for (const [label, options, pattern] of [
+    ['missing files namespace', { upstreamRoot: null }, /packed upstream license members differ/u],
+    [
+      'substituted files namespace',
+      { upstreamRoot: 'substituted-files' },
+      /packed upstream license members differ/u,
+    ],
+    [
+      'substituted upstream bytes',
+      { mutateUpstream: true },
+      /packed upstream license bytes changed/u,
+    ],
+  ]) {
+    await singletonAndroidRuntime(root, 'android-arm64-v8a', options);
+    await expect(
+      buildMavenArtifactManifest(manifest, {
+        extensions: true,
+        extensionProducts: ['oliphaunt-extension-pg-hashids'],
+        extensionArtifactRoot: root,
+      }),
+      label,
+    ).rejects.toThrow(pattern);
+  }
+});
diff --git a/tools/packaging/maven-artifact-staging.mts b/tools/packaging/maven-artifact-staging.mts
new file mode 100644
index 000000000..a9e54b98d
--- /dev/null
+++ b/tools/packaging/maven-artifact-staging.mts
@@ -0,0 +1,225 @@
+#!/usr/bin/env bun
+import { parseMavenArtifactManifest } from './maven-artifact-manifest.mts';
+
+import {
+  chmodSync,
+  copyFileSync,
+  existsSync,
+  lstatSync,
+  mkdirSync,
+  readFileSync,
+  readdirSync,
+  rmSync,
+  statSync,
+  writeFileSync,
+} from 'node:fs';
+import path from 'node:path';
+
+import { createDeterministicZip } from './archive-directory.mts';
+import { createSiblingStage, promoteDirectory, removeTemporaryPath } from './atomic-directory.mts';
+import { validateMavenCentralPublication } from './maven-central-contract.mts';
+import { stageReleaseNotices } from './release-notices.mts';
+
+const ROOT = path.resolve(import.meta.dir, '../..');
+const TOOL = 'maven-artifact-staging.mts';
+const MANIFEST = 'Manifest-Version: 1.0\r\n\r\n';
+
+function error(message) {
+  return new Error(`${TOOL}: ${message}`);
+}
+
+function relative(file) {
+  const value = path.relative(ROOT, file);
+  return value.startsWith('..') || path.isAbsolute(value)
+    ? file.split(path.sep).join('/')
+    : value.split(path.sep).join('/');
+}
+
+function xml(value) {
+  return String(value)
+    .replaceAll('&', '&')
+    .replaceAll('<', '<')
+    .replaceAll('>', '>')
+    .replaceAll('"', '"')
+    .replaceAll("'", ''');
+}
+
+export function renderMavenArtifactPom(row) {
+  const licenses = row.licenses
+    .map(
+      (license) => `    
+      ${xml(license.name)}
+      ${xml(license.url)}
+      ${xml(license.distribution)}
+    `,
+    )
+    .join('\n');
+  const runtimeProperties =
+    row.runtimeProduct === null
+      ? ''
+      : `
+    ${xml(row.runtimeProduct)}
+    ${xml(row.runtimeVersion)}`;
+  return `
+
+  4.0.0
+  ${xml(row.groupId)}
+  ${xml(row.artifactId)}
+  ${xml(row.version)}
+  tar.gz
+  ${xml(row.name)}
+  ${xml(row.description)}
+  https://github.com/f0rr0/oliphaunt
+  2026
+  
+${licenses}
+  
+  
+    
+      f0rr0
+      Oliphaunt Maintainers
+      https://github.com/f0rr0
+    
+  
+  
+    scm:git:https://github.com/f0rr0/oliphaunt.git
+    scm:git:ssh://git@github.com:f0rr0/oliphaunt.git
+    https://github.com/f0rr0/oliphaunt
+  
+  ${runtimeProperties}
+    ${xml(row.licenseSpdx)}
+  
+
+`;
+}
+
+function exactFiles(directory, expected, label) {
+  const actual = readdirSync(directory, { withFileTypes: true });
+  if (actual.some((entry) => !entry.isFile() || entry.isSymbolicLink())) {
+    throw error(`${label} must contain only regular files`);
+  }
+  const names = actual.map((entry) => entry.name).sort();
+  const wanted = [...expected].sort();
+  if (JSON.stringify(names) !== JSON.stringify(wanted)) {
+    throw error(
+      `${label} file closure differs: expected ${JSON.stringify(wanted)}, got ${JSON.stringify(names)}`,
+    );
+  }
+  return names;
+}
+
+async function writeCompanionJar(stageRoot, row, classifier) {
+  const coordinate = `${row.groupId}:${row.artifactId}:${row.version}`;
+  const root = path.join(stageRoot, `${classifier}-stage`);
+  mkdirSync(path.join(root, 'META-INF'), { recursive: true });
+  stageReleaseNotices(path.join(root, 'META-INF'), { profile: 'source-sdk' });
+  writeFileSync(path.join(root, 'META-INF/MANIFEST.MF'), MANIFEST, { mode: 0o644 });
+  if (classifier === 'sources') {
+    writeFileSync(
+      path.join(root, 'README.md'),
+      `# ${coordinate}\n\nThis binary carrier has no source API. See https://github.com/f0rr0/oliphaunt.\n`,
+      { mode: 0o644 },
+    );
+  } else {
+    writeFileSync(
+      path.join(root, 'index.html'),
+      `${xml(coordinate)}

This binary carrier has no Java API.

\n`, + { mode: 0o644 }, + ); + } + return createDeterministicZip(root); +} + +/** + * Materialize the immutable, unsigned Maven Central input closure without + * Gradle, Java, registry access, credentials, or dependency resolution. + */ +export async function stageMavenArtifactManifest(manifest, outputRoot) { + const rows = parseMavenArtifactManifest(path.resolve(manifest)); + const destination = path.resolve(outputRoot); + const stage = createSiblingStage(destination, 'maven-artifacts'); + try { + const staged = []; + for (const row of rows) { + const directory = path.join(stage, ...row.groupId.split('.'), row.artifactId, row.version); + const prefix = `${row.artifactId}-${row.version}`; + mkdirSync(directory, { recursive: true }); + const primary = path.join(directory, `${prefix}.tar.gz`); + const pom = path.join(directory, `${prefix}.pom`); + const sources = path.join(directory, `${prefix}-sources.jar`); + const javadoc = path.join(directory, `${prefix}-javadoc.jar`); + copyFileSync(row.artifact, primary); + chmodSync(primary, 0o644); + writeFileSync(pom, renderMavenArtifactPom(row), { mode: 0o644 }); + const companionRoot = path.join(stage, '.companion-stage', row.artifactId, row.version); + writeFileSync(sources, await writeCompanionJar(companionRoot, row, 'sources'), { + mode: 0o644, + }); + writeFileSync(javadoc, await writeCompanionJar(companionRoot, row, 'javadoc'), { + mode: 0o644, + }); + rmSync(companionRoot, { recursive: true, force: true }); + const files = exactFiles( + directory, + [ + path.basename(javadoc), + path.basename(pom), + path.basename(sources), + path.basename(primary), + ], + `${row.groupId}:${row.artifactId}:${row.version}`, + ); + const publication = validateMavenCentralPublication({ + context: `${row.groupId}:${row.artifactId}:${row.version}`, + files: files.map((name) => ({ name, size: statSync(path.join(directory, name)).size })), + pomText: readFileSync(pom, 'utf8'), + }); + staged.push( + Object.freeze({ + ...publication, + directory: path.join(destination, ...row.groupId.split('.'), row.artifactId, row.version), + files: Object.freeze(files), + }), + ); + } + rmSync(path.join(stage, '.companion-stage'), { recursive: true, force: true }); + promoteDirectory(stage, destination); + return Object.freeze(staged); + } catch (cause) { + if (existsSync(stage)) removeTemporaryPath(stage); + throw cause; + } +} + +function parseArgs(argv) { + let manifest = null; + let output = null; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--manifest') { + manifest = argv[++index] ?? null; + } else if (arg === '--output') { + output = argv[++index] ?? null; + } else { + throw error(`unknown argument ${JSON.stringify(arg)}`); + } + } + if (manifest === null || output === null) { + throw error('usage: maven-artifact-staging.mts --manifest FILE --output DIRECTORY'); + } + return { manifest, output }; +} + +if (import.meta.main) { + try { + const args = parseArgs(Bun.argv.slice(2)); + const staged = await stageMavenArtifactManifest(args.manifest, args.output); + console.log( + `Staged and validated ${staged.length} local Maven Central carrier(s) under ${relative(args.output)}.`, + ); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/packaging/maven-artifact-staging.test.mts b/tools/packaging/maven-artifact-staging.test.mts new file mode 100644 index 000000000..3b0c31e68 --- /dev/null +++ b/tools/packaging/maven-artifact-staging.test.mts @@ -0,0 +1,180 @@ +import { parseMavenArtifactManifest } from './maven-artifact-manifest.mts'; +import { afterEach, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + readdirSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { stageMavenArtifactManifest } from './maven-artifact-staging.mts'; +import { validateMavenCentralPublication } from './maven-central-contract.mts'; +import { readPortableArchiveEntries } from './portable-archive.mts'; + +const roots = []; + +afterEach(() => { + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); +}); + +function fixture() { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-maven-carrier-')); + roots.push(root); + const artifact = path.join(root, 'runtime.tar.gz'); + const manifest = path.join(root, 'manifest.tsv'); + const output = path.join(root, 'maven'); + writeFileSync(artifact, 'exact runtime carrier\n'); + const licenses = [ + { + name: 'MIT & PostgreSQL', + url: 'https://example.invalid/license?a=1&b=2', + distribution: 'repo', + }, + ]; + writeFileSync( + manifest, + [ + 'dev.oliphaunt.extensions', + 'oliphaunt-extension-example-android-arm64-v8a', + '1.2.3', + artifact, + 'Oliphaunt ', + 'Exact extension & runtime carrier.', + 'liboliphaunt-native', + '4.5.6', + 'MIT AND PostgreSQL', + JSON.stringify(licenses), + ].join('\t') + '\n', + ); + return { artifact, manifest, output, root }; +} + +function digest(file) { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} + +function files(directory) { + return readdirSync(directory) + .sort() + .map((name) => path.join(directory, name)); +} + +test('stages a deterministic exact Maven Central carrier closure without Gradle', async () => { + const value = fixture(); + const first = await stageMavenArtifactManifest(value.manifest, value.output); + expect(first).toHaveLength(1); + const directory = first[0].directory; + const stagedFiles = files(directory); + expect(stagedFiles.map((file) => path.basename(file))).toEqual([ + 'oliphaunt-extension-example-android-arm64-v8a-1.2.3-javadoc.jar', + 'oliphaunt-extension-example-android-arm64-v8a-1.2.3-sources.jar', + 'oliphaunt-extension-example-android-arm64-v8a-1.2.3.pom', + 'oliphaunt-extension-example-android-arm64-v8a-1.2.3.tar.gz', + ]); + expect( + readFileSync( + stagedFiles.find((file) => file.endsWith('.tar.gz')), + 'utf8', + ), + ).toBe('exact runtime carrier\n'); + + const pom = stagedFiles.find((file) => file.endsWith('.pom')); + expect(readFileSync(pom, 'utf8')).toContain('Oliphaunt <example>'); + expect(readFileSync(pom, 'utf8')).toContain('MIT & PostgreSQL'); + expect( + validateMavenCentralPublication({ + context: 'fixture', + files: stagedFiles.map((file) => ({ name: path.basename(file), size: lstatSync(file).size })), + pomText: readFileSync(pom, 'utf8'), + }), + ).toEqual({ + artifactId: 'oliphaunt-extension-example-android-arm64-v8a', + groupId: 'dev.oliphaunt.extensions', + packaging: 'tar.gz', + version: '1.2.3', + }); + + for (const jar of stagedFiles.filter((file) => file.endsWith('.jar'))) { + const entries = readPortableArchiveEntries(jar); + expect(entries.has('META-INF/MANIFEST.MF')).toBe(true); + expect(entries.has('META-INF/LICENSE')).toBe(true); + expect(entries.has('META-INF/THIRD_PARTY_NOTICES.md')).toBe(true); + expect([...entries.values()].every((entry) => entry.isSymbolicLink === false)).toBe(true); + } + + const firstDigests = Object.fromEntries( + stagedFiles.map((file) => [path.basename(file), digest(file)]), + ); + await stageMavenArtifactManifest(value.manifest, value.output); + expect( + Object.fromEntries(files(directory).map((file) => [path.basename(file), digest(file)])), + ).toEqual(firstDigests); +}); + +test('rejects duplicate coordinates, malformed licenses, missing artifacts, and symlinks', () => { + const value = fixture(); + const row = readFileSync(value.manifest, 'utf8'); + writeFileSync(value.manifest, row + row); + expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/repeats Maven coordinate/u); + + const fields = row.trimEnd().split('\t'); + writeFileSync(value.manifest, `${fields.with(9, '{}').join('\t')}\n`); + expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/non-empty JSON array/u); + + writeFileSync( + value.manifest, + `${fields.with(3, path.join(value.root, 'missing.tar.gz')).join('\t')}\n`, + ); + expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/is missing/u); + + const link = path.join(value.root, 'linked.tar.gz'); + symlinkSync(value.artifact, link); + writeFileSync(value.manifest, `${fields.with(3, link).join('\t')}\n`); + expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/non-symlink/u); +}); + +test('rejects coordinate dot segments before staging any path', async () => { + const value = fixture(); + const fields = readFileSync(value.manifest, 'utf8').trimEnd().split('\t'); + for (const [field, invalid] of [ + [0, '.'], + [0, '..'], + [0, '.dev.oliphaunt'], + [0, 'dev..oliphaunt'], + [0, 'dev.oliphaunt.'], + [1, '.'], + [1, '..'], + [2, '.'], + [2, '..'], + ]) { + writeFileSync(value.manifest, `${fields.with(field, invalid).join('\t')}\n`); + expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/non-dot|dot-separated/u); + await expect(stageMavenArtifactManifest(value.manifest, value.output)).rejects.toThrow( + /non-dot|dot-separated/u, + ); + } + expect(() => lstatSync(value.output)).toThrow(); +}); + +test('failed staging leaves the last complete output untouched', async () => { + const value = fixture(); + await stageMavenArtifactManifest(value.manifest, value.output); + const marker = path.join(value.output, 'complete.marker'); + writeFileSync(marker, 'keep\n'); + const fields = readFileSync(value.manifest, 'utf8').trimEnd().split('\t'); + writeFileSync( + value.manifest, + `${fields.with(3, path.join(value.root, 'missing.tar.gz')).join('\t')}\n`, + ); + await expect(stageMavenArtifactManifest(value.manifest, value.output)).rejects.toThrow( + /is missing/u, + ); + expect(readFileSync(marker, 'utf8')).toBe('keep\n'); +}); diff --git a/tools/packaging/maven-central-contract.mts b/tools/packaging/maven-central-contract.mts new file mode 100644 index 000000000..c17170d8a --- /dev/null +++ b/tools/packaging/maven-central-contract.mts @@ -0,0 +1,184 @@ +import path from 'node:path'; + +function error(message) { + return new Error(`maven-central-contract: ${message}`); +} + +function xmlBlock(block, tag) { + const match = block.match(new RegExp(`<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)`, 'u')); + return match?.[1] ?? null; +} + +function xmlText(block, tag) { + const inner = xmlBlock(block, tag); + if (inner === null) return null; + return inner + .replace(//gu, '$1') + .replace(/<[^>]+>/gu, '') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll(''', "'") + .replaceAll('&', '&') + .trim(); +} + +function uniqueXmlText(block, tag, context, { required = true } = {}) { + const matches = [ + ...block.matchAll(new RegExp(`<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)`, 'gu')), + ]; + if (matches.length === 0 && !required) return null; + if (matches.length !== 1) { + throw error(`${context} must define exactly one <${tag}>, found ${matches.length}`); + } + return xmlText(matches[0][0], tag); +} + +function xmlBlocks(block, tag) { + return [...block.matchAll(new RegExp(`<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)`, 'gu'))].map( + (match) => match[1], + ); +} + +function requireText(block, tag, context) { + const value = xmlText(block, tag); + if (value === null || value.length === 0) { + throw error(`${context} must define a nonempty <${tag}>`); + } + return value; +} + +function requireSafeCoordinate(value, context) { + if (!/^[A-Za-z0-9_.-]+$/u.test(value)) { + throw error(`${context} is not a safe Maven coordinate segment: ${JSON.stringify(value)}`); + } + return value; +} + +function normalizedFiles(files, context) { + if (!Array.isArray(files) || files.length === 0) { + throw error(`${context} must provide the complete publication file set`); + } + const names = new Map(); + for (const entry of files) { + const name = + typeof entry === 'string' + ? path.basename(entry) + : path.basename(entry?.name ?? entry?.path ?? ''); + const size = typeof entry === 'string' ? undefined : entry?.size; + if (name.length === 0 || name === '.' || name === '..') { + throw error(`${context} contains an invalid publication filename`); + } + if (names.has(name)) { + throw error(`${context} contains duplicate publication filename ${name}`); + } + if (size !== undefined && (!Number.isSafeInteger(size) || size <= 0)) { + throw error(`${context} file ${name} must be nonempty`); + } + names.set(name, { name, size }); + } + return names; +} + +function requireMetadata(project, context) { + const header = project.replace( + /<(parent|dependencies|dependencyManagement|licenses|developers|scm|properties|build|profiles|repositories|distributionManagement)(?:\s[^>]*)?>[\s\S]*?<\/\1>/gu, + '', + ); + for (const tag of ['name', 'description', 'url']) { + const value = uniqueXmlText(header, tag, context); + if (value === null || value.length === 0) + throw error(`${context} must define a nonempty <${tag}>`); + } + + const licenses = xmlBlock(project, 'licenses'); + if (licenses === null) throw error(`${context} must define `); + const validLicense = xmlBlocks(licenses, 'license').some( + (license) => + (xmlText(license, 'name')?.length ?? 0) > 0 && (xmlText(license, 'url')?.length ?? 0) > 0, + ); + if (!validLicense) { + throw error(`${context} must define at least one license with nonempty name and url`); + } + + const developers = xmlBlock(project, 'developers'); + if (developers === null) throw error(`${context} must define `); + const validDeveloper = xmlBlocks(developers, 'developer').some( + (developer) => + (xmlText(developer, 'name')?.length ?? 0) > 0 && + ((xmlText(developer, 'email')?.length ?? 0) > 0 || + (xmlText(developer, 'url')?.length ?? 0) > 0), + ); + if (!validDeveloper) { + throw error( + `${context} must define at least one developer with a nonempty name and email or url`, + ); + } + + const scm = xmlBlock(project, 'scm'); + if (scm === null) throw error(`${context} must define `); + for (const tag of ['connection', 'developerConnection', 'url']) { + requireText(scm, tag, `${context} `); + } +} + +/** + * Validate the immutable files for one Maven Central coordinate before any + * signing, upload, or GitHub release mutation occurs. + */ +export function validateMavenCentralPublication({ pomText, files, context = 'Maven publication' }) { + if (typeof pomText !== 'string' || pomText.length === 0) { + throw error(`${context} POM must be nonempty UTF-8 text`); + } + if (/]*)?>([\s\S]*?)<\/project>/gu)]; + if (projectMatches.length !== 1) { + throw error( + `${context} POM must contain exactly one document, found ${projectMatches.length}`, + ); + } + const project = projectMatches[0][1]; + const coordinates = project.replace( + /<(parent|dependencies|dependencyManagement|properties|build|profiles|repositories|distributionManagement)(?:\s[^>]*)?>[\s\S]*?<\/\1>/gu, + '', + ); + const modelVersion = uniqueXmlText(coordinates, 'modelVersion', context); + if (modelVersion !== '4.0.0') { + throw error(`${context} must use Maven modelVersion 4.0.0`); + } + const groupId = requireSafeCoordinate( + uniqueXmlText(coordinates, 'groupId', context), + `${context} groupId`, + ); + const artifactId = requireSafeCoordinate( + uniqueXmlText(coordinates, 'artifactId', context), + `${context} artifactId`, + ); + const version = requireSafeCoordinate( + uniqueXmlText(coordinates, 'version', context), + `${context} version`, + ); + const packaging = requireSafeCoordinate( + uniqueXmlText(coordinates, 'packaging', context, { required: false }) ?? 'jar', + `${context} packaging`, + ); + requireMetadata(project, context); + + const names = normalizedFiles(files, context); + const prefix = `${artifactId}-${version}`; + const required = [`${prefix}.pom`]; + if (packaging !== 'pom') { + required.push(`${prefix}.${packaging}`, `${prefix}-sources.jar`, `${prefix}-javadoc.jar`); + } + for (const name of required) { + if (!names.has(name)) { + throw error( + `${context} (${groupId}:${artifactId}:${version}, packaging ${packaging}) is missing required file ${name}`, + ); + } + } + + return { artifactId, groupId, packaging, version }; +} diff --git a/tools/packaging/maven-central-contract.test.mts b/tools/packaging/maven-central-contract.test.mts new file mode 100644 index 000000000..5328f9487 --- /dev/null +++ b/tools/packaging/maven-central-contract.test.mts @@ -0,0 +1,93 @@ +import { describe, expect, test } from 'bun:test'; + +import { validateMavenCentralPublication } from './maven-central-contract.mts'; + +function pom({ packaging = 'tar.gz', metadata = true } = {}) { + return ` + + 4.0.0 + dev.oliphaunt.extensions + vector-android-arm64 + 1.2.3 + ${packaging} + ${ + metadata + ? `Oliphaunt vector Android arm64 + Exact native extension carrier. + https://github.com/f0rr0/oliphaunt + PostgreSQLhttps://opensource.org/license/postgresql + Oliphaunt Maintainershttps://github.com/f0rr0 + scm:git:https://github.com/f0rr0/oliphaunt.gitscm:git:ssh://git@github.com/f0rr0/oliphaunt.githttps://github.com/f0rr0/oliphaunt` + : '' + } +`; +} + +const complete = [ + { name: 'vector-android-arm64-1.2.3.pom', size: 10 }, + { name: 'vector-android-arm64-1.2.3.tar.gz', size: 20 }, + { name: 'vector-android-arm64-1.2.3-sources.jar', size: 30 }, + { name: 'vector-android-arm64-1.2.3-javadoc.jar', size: 40 }, +]; + +describe('Maven Central immutable publication contract', () => { + test('accepts complete non-jar coordinates with Central metadata and placeholders', () => { + expect(validateMavenCentralPublication({ pomText: pom(), files: complete })).toEqual({ + artifactId: 'vector-android-arm64', + groupId: 'dev.oliphaunt.extensions', + packaging: 'tar.gz', + version: '1.2.3', + }); + }); + + test('permits a metadata-complete POM-only Gradle marker', () => { + expect( + validateMavenCentralPublication({ + pomText: pom({ packaging: 'pom' }), + files: [{ name: 'vector-android-arm64-1.2.3.pom', size: 10 }], + }).packaging, + ).toBe('pom'); + }); + + for (const missing of [ + 'vector-android-arm64-1.2.3.tar.gz', + 'vector-android-arm64-1.2.3-sources.jar', + 'vector-android-arm64-1.2.3-javadoc.jar', + ]) { + test(`rejects a non-POM coordinate missing ${missing}`, () => { + expect(() => + validateMavenCentralPublication({ + pomText: pom(), + files: complete.filter(({ name }) => name !== missing), + }), + ).toThrow(`missing required file ${missing}`); + }); + } + + test('rejects incomplete required Central POM metadata', () => { + expect(() => + validateMavenCentralPublication({ pomText: pom({ metadata: false }), files: complete }), + ).toThrow('exactly one , found 0'); + }); + + test('rejects duplicate root packaging emitted by an unsafe Gradle XML append', () => { + const duplicate = pom().replace( + 'tar.gz', + 'tar.gztar.gz', + ); + expect(() => validateMavenCentralPublication({ pomText: duplicate, files: complete })).toThrow( + 'exactly one , found 2', + ); + }); + + test('rejects empty publication files', () => { + expect(() => + validateMavenCentralPublication({ + pomText: pom(), + files: complete.map((entry) => + entry.name.endsWith('-sources.jar') ? { ...entry, size: 0 } : entry, + ), + }), + ).toThrow('must be nonempty'); + }); +}); diff --git a/tools/packaging/moon.yml b/tools/packaging/moon.yml new file mode 100644 index 000000000..314c5cb37 --- /dev/null +++ b/tools/packaging/moon.yml @@ -0,0 +1,50 @@ +$schema: https://moonrepo.dev/schemas/project.json +id: artifact-packaging +language: typescript +layer: library +stack: systems +tags: + - javascript-quality + - shared + - artifacts + - packaging +project: + title: Artifact Packaging + description: "Deterministic archive creation, reading, and safe staging shared by product packagers." + owner: oliphaunt +owners: + defaultOwner: "@oliphaunt/core" + paths: + "**/*": + - "@oliphaunt/core" +fileGroups: + source: + - "*.{mjs,mts}" + - "!*.test.{mjs,mts}" +tasks: + test: + tags: + - quality + - unit + - requires-rust + command: "bash tools/packaging/test.sh" + inputs: + - "@group(release-target-contract)" + - "@group(package-test-metadata)" + - "@group(legal-files)" + - /src/extensions/tools/extension-upstream-licenses.mts + - /src/extensions/external/**/upstream-license-data.json + - "@group(upstream-licenses)" + - "/src/runtimes/liboliphaunt-{native,wasix}/THIRD_PARTY_NOTICES.md" + - "/src/third-party/{icu,openssl}/source.toml" + - "**/*.mts" + - "**/*.sh" + - /src/database-resources/contracts/*.mts + - /tools/release/**/*.mts + - /src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json + - /src/runtimes/liboliphaunt-wasix/crates/**/* + - /src/postgres-tools/wasix/crates/**/* + - /src/database-resources/icu/cargo/**/* + options: + cache: true + runFromWorkspaceRoot: true diff --git a/tools/packaging/native-cargo-payload.mts b/tools/packaging/native-cargo-payload.mts new file mode 100644 index 000000000..710eab8cb --- /dev/null +++ b/tools/packaging/native-cargo-payload.mts @@ -0,0 +1,960 @@ +import { assertSameStringSet } from './release-carrier.mts'; +import { createHash } from 'node:crypto'; +import { + closeSync, + copyFileSync, + existsSync, + mkdirSync, + openSync, + readdirSync, + readFileSync, + readSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { + createDeterministicTar, + fitCargoPayloadParts, + packageGeneratedCargoSource, +} from './cargo-source-package.mts'; +import { canonicalGzipSync } from './portable-archive.mts'; +import { + assertReleaseNoticesInArchive, + assertReleaseNoticesInDirectory, + releaseNoticeRows, + releaseProfilePackageLicense, + stageReleaseNotices, +} from './release-notices.mts'; +import { + allArtifactTargets, + compareText, + currentProductVersion, + ROOT, +} from '../release/release-artifact-targets.mts'; + +const PREFIX = 'native-cargo-payload.mts'; +const PRODUCT = 'liboliphaunt-native'; +const CRATES_IO_MAX_BYTES = 10 * 1024 * 1024; +const DEFAULT_PART_BYTES = 64 * 1024 * 1024; +export const NATIVE_CARGO_CARRIER_LICENSES = Object.freeze({ + 'native-runtime': releaseProfilePackageLicense('native-runtime').spdx, + 'native-tools': releaseProfilePackageLicense('native-tools').spdx, + 'code-facade': releaseProfilePackageLicense('code-facade').spdx, +}); + +const AGGREGATOR_BUILD_RS = String.raw`use std::collections::BTreeMap; +use std::env; +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; + +const SCHEMA: &str = __SCHEMA__; +const PRODUCT: &str = __PRODUCT__; +const VERSION: &str = __VERSION__; +const KIND: &str = __KIND__; +const TARGET: &str = __TARGET__; +const PART_ROOTS: &[&str] = &[ +__PART_ROOTS__ +]; +const FILE_SHA256: &[(&str, &str)] = &[ +__FILE_SHA256__ +]; + +fn main() { + emit_manifest(); +} + +fn emit_manifest() { + let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set")); + let payload = out_dir.join("payload"); + if payload.exists() { + fs::remove_dir_all(&payload).expect("remove stale liboliphaunt native payload"); + } + fs::create_dir_all(&payload).expect("create liboliphaunt native payload directory"); + + let part_roots = part_roots(); + if part_roots.is_empty() { + if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() { + panic!("missing liboliphaunt native payload part crates"); + } + return; + } + + let mut chunk_files: BTreeMap> = BTreeMap::new(); + for root in part_roots { + println!("cargo::rerun-if-changed={}", root.display()); + copy_complete_files(&root.join("files"), &payload).expect("copy complete payload files"); + collect_chunks(&root.join("chunks"), &root.join("chunks"), &mut chunk_files) + .expect("collect payload chunks"); + } + + for (relative, mut chunks) in chunk_files { + chunks.sort_by_key(|(index, _)| *index); + for (expected, (actual, _)) in chunks.iter().enumerate() { + if *actual != expected { + panic!("non-contiguous liboliphaunt chunk indexes for {relative}"); + } + } + let output = payload.join(&relative); + if let Some(parent) = output.parent() { + fs::create_dir_all(parent).expect("create reconstructed file parent"); + } + let mut writer = fs::File::create(&output).expect("create reconstructed payload file"); + for (_, path) in chunks { + let mut reader = fs::File::open(&path).expect("open payload chunk"); + io::copy(&mut reader, &mut writer).expect("append payload chunk"); + } + } + + let files = collect_files(&payload).expect("collect reconstructed liboliphaunt payload files"); + if files.is_empty() { + panic!("liboliphaunt native payload part crates produced no files"); + } + let manifest = out_dir.join("oliphaunt-artifact.toml"); + let mut text = format!( + "schema = {SCHEMA:?}\nproduct = {PRODUCT:?}\nversion = {VERSION:?}\nkind = {KIND:?}\ntarget = {TARGET:?}\n" + ); + if files.len() != FILE_SHA256.len() { + panic!("reconstructed liboliphaunt payload file count does not match the frozen inventory"); + } + for file in files { + let relative = file.strip_prefix(&payload) + .expect("payload file stays under payload root") + .to_string_lossy() + .replace('\\', "/"); + let sha256 = FILE_SHA256.iter() + .find_map(|(candidate, digest)| (*candidate == relative).then_some(*digest)) + .unwrap_or_else(|| panic!("reconstructed liboliphaunt payload has undeclared file {relative}")); + text.push_str(&format!( + "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = {}\n", + file.display().to_string(), + relative, + sha256, + is_executable_relative(&relative), + )); + } + fs::write(&manifest, text).expect("write liboliphaunt native artifact manifest"); + println!("cargo::metadata=manifest={}", manifest.display()); +} + +fn part_roots() -> Vec { + PART_ROOTS.iter().map(PathBuf::from).collect() +} + +fn copy_complete_files(source: &Path, destination: &Path) -> io::Result<()> { + if !source.is_dir() { + return Ok(()); + } + for entry in fs::read_dir(source)? { + let entry = entry?; + let path = entry.path(); + let output = destination.join(path.strip_prefix(source).unwrap_or(&path)); + copy_tree_entry(&path, &output)?; + } + Ok(()) +} + +fn copy_tree_entry(source: &Path, destination: &Path) -> io::Result<()> { + let metadata = fs::metadata(source)?; + if metadata.is_dir() { + fs::create_dir_all(destination)?; + for entry in fs::read_dir(source)? { + let entry = entry?; + copy_tree_entry(&entry.path(), &destination.join(entry.file_name()))?; + } + } else if metadata.is_file() { + if let Some(parent) = destination.parent() { + fs::create_dir_all(parent)?; + } + fs::copy(source, destination)?; + } + Ok(()) +} + +fn collect_chunks( + root: &Path, + current: &Path, + chunks: &mut BTreeMap>, +) -> io::Result<()> { + if !current.is_dir() { + return Ok(()); + } + for entry in fs::read_dir(current)? { + let entry = entry?; + let path = entry.path(); + let metadata = fs::metadata(&path)?; + if metadata.is_dir() { + collect_chunks(root, &path, chunks)?; + continue; + } + if !metadata.is_file() { + continue; + } + let relative = path.strip_prefix(root).unwrap_or(&path).to_string_lossy().replace('\\', "/"); + let (file_relative, part_index) = split_part_relative(&relative) + .unwrap_or_else(|| panic!("invalid liboliphaunt chunk file name {relative}")); + chunks.entry(file_relative).or_default().push((part_index, path)); + } + Ok(()) +} + +fn split_part_relative(relative: &str) -> Option<(String, usize)> { + let (file, index) = relative.rsplit_once(".part")?; + if file.is_empty() || index.len() != 3 || !index.bytes().all(|byte| byte.is_ascii_digit()) { + return None; + } + Some((file.to_owned(), index.parse().ok()?)) +} + +fn collect_files(root: &Path) -> io::Result> { + let mut files = Vec::new(); + collect_files_inner(root, &mut files)?; + files.sort(); + Ok(files) +} + +fn collect_files_inner(path: &Path, files: &mut Vec) -> io::Result<()> { + if !path.is_dir() { + return Ok(()); + } + for entry in fs::read_dir(path)? { + let entry = entry?; + let entry_path = entry.path(); + let metadata = fs::metadata(&entry_path)?; + if metadata.is_dir() { + collect_files_inner(&entry_path, files)?; + } else if metadata.is_file() { + files.push(entry_path); + } + } + Ok(()) +} + +fn is_executable_relative(relative: &str) -> bool { + relative.starts_with("runtime/bin/") || relative.starts_with("bin/") +} +`; + +export function fail(message) { + console.error(`${PREFIX}: ${message}`); + process.exit(1); +} + +export function rel(file) { + const relative = path.relative(ROOT, String(file)); + if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) { + return String(file).split(path.sep).join('/'); + } + return relative.split(path.sep).join('/'); +} + +function repoPath(value) { + return path.isAbsolute(value) ? value : path.join(ROOT, value); +} + +export function isFile(file) { + try { + return statSync(file).isFile(); + } catch { + return false; + } +} + +function isDirectory(file) { + try { + return statSync(file).isDirectory(); + } catch { + return false; + } +} + +export function cargoPackageName(targetId, { packageBase = PRODUCT } = {}) { + return `${packageBase}-${targetId}`; +} + +function cargoLinksName(targetId, { artifactProduct = PRODUCT } = {}) { + return `oliphaunt_artifact_${artifactProduct.replaceAll('-', '_')}_${targetId.replaceAll('-', '_')}`; +} + +function partPackageName(targetId, index, { packageBase = PRODUCT } = {}) { + if (!Number.isSafeInteger(index) || index < 1 || index > 999) { + fail( + `Cargo payload part number must be an integer from 1 through 999, got ${JSON.stringify(index)}`, + ); + } + return `${cargoPackageName(targetId, { packageBase })}-part-${String(index).padStart(3, '0')}`; +} + +function partLinksName(targetId, index, { artifactProduct = PRODUCT } = {}) { + if (!Number.isSafeInteger(index) || index < 1 || index > 999) { + fail( + `Cargo payload part number must be an integer from 1 through 999, got ${JSON.stringify(index)}`, + ); + } + return `oliphaunt_artifact_part_${artifactProduct.replaceAll('-', '_')}_${targetId.replaceAll('-', '_')}_${String(index).padStart(3, '0')}`; +} + +function rustCrateIdent(crateName) { + return crateName.replaceAll('-', '_'); +} + +function tomlString(value) { + return JSON.stringify(value); +} + +function cargoIncludeMembers(profile, baseMembers) { + return JSON.stringify([ + ...baseMembers, + ...releaseNoticeRows({ profile }).map((row) => row.member), + ]); +} + +function writePartCrate( + crateDir, + { targetId, index, version, packageBase, artifactProduct, artifactLabel, noticeProfile }, +) { + rmSync(crateDir, { recursive: true, force: true }); + const name = partPackageName(targetId, index, { packageBase }); + const links = partLinksName(targetId, index, { artifactProduct }); + mkdirSync(path.join(crateDir, 'src'), { recursive: true }); + writeFileSync( + path.join(crateDir, 'Cargo.toml'), + `[package] +name = "${name}" +version = "${version}" +edition = "2024" +rust-version = "1.93" +description = "Cargo payload part ${String(index).padStart(3, '0')} for the ${targetId} ${artifactLabel}." +readme = "README.md" +repository = "https://github.com/f0rr0/oliphaunt" +homepage = "https://oliphaunt.dev" +license = "${NATIVE_CARGO_CARRIER_LICENSES[noticeProfile]}" +links = "${links}" +build = "build.rs" +include = ${cargoIncludeMembers(noticeProfile, ['Cargo.toml', 'README.md', 'build.rs', 'src/**', 'payload/**'])} + +[lib] +path = "src/lib.rs" + +[workspace] +`, + ); + writeFileSync( + path.join(crateDir, 'README.md'), + `# ${name} + +Cargo payload part for the \`${targetId}\` ${artifactLabel}. +Applications do not depend on this crate directly. +`, + ); + writeFileSync( + path.join(crateDir, 'src/lib.rs'), + `pub const RELEASE_TARGET: &str = "${targetId}"; +pub const PART_INDEX: usize = ${index}; +pub const PAYLOAD_ROOT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/payload"); +`, + ); + writeFileSync( + path.join(crateDir, 'build.rs'), + `use std::env; +use std::path::PathBuf; + +fn main() { + let manifest_dir = + PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set")); + let root = manifest_dir.join("payload"); + println!("cargo::rerun-if-changed={}", root.display()); + if !root.is_dir() { + if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() { + panic!("missing packaged Oliphaunt artifact payload under {}", root.display()); + } + return; + } + println!("cargo::metadata=root={}", root.display()); +} +`, + ); + stageReleaseNotices(crateDir, { profile: noticeProfile }); + assertReleaseNoticesInDirectory(crateDir, { profile: noticeProfile }); +} + +function writeAggregatorCrate( + crateDir, + { + target, + version, + partCount, + packageBase, + artifactProduct, + artifactKind, + artifactLabel, + payloadFiles, + }, +) { + rmSync(crateDir, { recursive: true, force: true }); + if (typeof target.triple !== 'string' || !target.triple) { + fail(`${target.id} must declare Cargo target triple`); + } + const name = cargoPackageName(target.target, { packageBase }); + const links = cargoLinksName(target.target, { artifactProduct }); + mkdirSync(path.join(crateDir, 'src'), { recursive: true }); + const dependencyLines = []; + const partRoots = []; + for (let offset = 0; offset < partCount; offset += 1) { + const partName = partPackageName(target.target, offset + 1, { packageBase }); + dependencyLines.push(`${partName} = { version = "=${version}", path = "../${partName}" }`); + partRoots.push(` ${rustCrateIdent(partName)}::PAYLOAD_ROOT,`); + } + const libraryRelativePath = target.libraryRelativePath ?? ''; + writeFileSync( + path.join(crateDir, 'Cargo.toml'), + `[package] +name = "${name}" +version = "${version}" +edition = "2024" +rust-version = "1.93" +description = "Cargo artifact crate for the ${target.target} ${artifactLabel}." +readme = "README.md" +repository = "https://github.com/f0rr0/oliphaunt" +homepage = "https://oliphaunt.dev" +license = "${NATIVE_CARGO_CARRIER_LICENSES['code-facade']}" +links = "${links}" +build = "build.rs" +include = ${cargoIncludeMembers('code-facade', ['Cargo.toml', 'README.md', 'build.rs', 'src/**'])} + +[lib] +path = "src/lib.rs" + +[build-dependencies] +${dependencyLines.join('\n')} + +[workspace] +`, + ); + writeFileSync( + path.join(crateDir, 'README.md'), + `# ${name} + +Cargo artifact crate for the \`${target.target}\` ${artifactLabel}. +Applications do not depend on this crate directly; \`oliphaunt\` selects it for +matching Cargo targets. +`, + ); + writeFileSync( + path.join(crateDir, 'src/lib.rs'), + `pub const PRODUCT: &str = "${artifactProduct}"; +pub const KIND: &str = "${artifactKind}"; +pub const RELEASE_TARGET: &str = "${target.target}"; +pub const CARGO_TARGET: &str = "${target.triple}"; +pub const LIBRARY_RELATIVE_PATH: &str = "${libraryRelativePath}"; +`, + ); + writeFileSync( + path.join(crateDir, 'build.rs'), + AGGREGATOR_BUILD_RS.replace('__SCHEMA__', tomlString('oliphaunt-artifact-manifest-v1')) + .replace('__PRODUCT__', tomlString(artifactProduct)) + .replace('__VERSION__', tomlString(version)) + .replace('__KIND__', tomlString(artifactKind)) + .replace('__TARGET__', tomlString(target.triple)) + .replace('__PART_ROOTS__', partRoots.join('\n')) + .replace( + '__FILE_SHA256__', + payloadFiles + .map(({ relative, sha256 }) => ` (${tomlString(relative)}, ${tomlString(sha256)}),`) + .join('\n'), + ), + ); + stageReleaseNotices(crateDir, { profile: 'code-facade' }); + assertReleaseNoticesInDirectory(crateDir, { profile: 'code-facade' }); +} + +function walkFiles(root) { + const files = []; + const visit = (current) => { + if (!existsSync(current)) { + return; + } + for (const entry of readdirSync(current, { withFileTypes: true })) { + const file = path.join(current, entry.name); + if (entry.isDirectory()) { + visit(file); + } else if (entry.isFile()) { + files.push(file); + } + } + }; + visit(root); + return files.sort(compareText); +} + +function frozenPayloadFiles(root) { + return walkFiles(root).map((file) => ({ + relative: path.relative(root, file).split(path.sep).join('/'), + sha256: createHash('sha256').update(readFileSync(file)).digest('hex'), + })); +} + +function nextPartDir( + sourceRoot, + targetId, + index, + version, + { packageBase, artifactProduct, artifactLabel, noticeProfile }, +) { + const crateDir = path.join(sourceRoot, partPackageName(targetId, index, { packageBase })); + writePartCrate(crateDir, { + targetId, + index, + version, + packageBase, + artifactProduct, + artifactLabel, + noticeProfile, + }); + return crateDir; +} + +function writeChunk(file, data) { + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, data); +} + +function copyPayloadFile(source, destination) { + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(source, destination); +} + +function buildPartCrates( + extractedRoot, + sourceRoot, + { targetId, version, partBytes, packageBase, artifactProduct, artifactLabel, noticeProfile }, +) { + const partDirs = []; + let currentDir; + let currentSize = 0; + const startPart = () => { + const partNumber = partDirs.length + 1; + if (partNumber > 999) { + fail(`${targetId} requires more than 999 ${artifactLabel} part crates`); + } + const partDir = nextPartDir(sourceRoot, targetId, partNumber, version, { + packageBase, + artifactProduct, + artifactLabel, + noticeProfile, + }); + partDirs.push(partDir); + return partDir; + }; + + for (const source of walkFiles(extractedRoot)) { + const relative = path.relative(extractedRoot, source).split(path.sep).join('/'); + const size = statSync(source).size; + if (size > partBytes) { + currentDir = undefined; + currentSize = 0; + const fd = openSync(source, 'r'); + try { + let partIndex = 0; + let offset = 0; + while (offset < size) { + const length = Math.min(partBytes, size - offset); + const buffer = Buffer.allocUnsafe(length); + const bytesRead = readSync(fd, buffer, 0, length, offset); + if (bytesRead <= 0) { + break; + } + const partDir = startPart(); + writeChunk( + path.join( + partDir, + 'payload/chunks', + `${relative}.part${String(partIndex).padStart(3, '0')}`, + ), + buffer.subarray(0, bytesRead), + ); + offset += bytesRead; + partIndex += 1; + } + } finally { + closeSync(fd); + } + continue; + } + if (currentDir === undefined || currentSize + size > partBytes) { + currentDir = startPart(); + currentSize = 0; + } + copyPayloadFile(source, path.join(currentDir, 'payload/files', relative)); + currentSize += size; + } + if (partDirs.length === 0) { + fail(`${targetId} generated no ${artifactLabel} part crates`); + } + return partDirs; +} + +function validateCrateSize(cratePath) { + const size = statSync(cratePath).size; + if (size > CRATES_IO_MAX_BYTES) { + fail(`${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit`); + } +} + +export function freezeSourceCrate(packageData, outputDir, cargoTargetDir) { + const generated = packageGeneratedCargoSource( + packageData.manifestPath, + path.join(cargoTargetDir, 'strict-package', packageData.name), + { root: ROOT, fail, rel }, + ); + assertReleaseNoticesInArchive(generated, { + prefix: `${packageData.name}-${packageData.version}`, + profile: packageData.noticeProfile, + }); + validateCrateSize(generated); + const cratePath = path.join(outputDir, path.basename(generated)); + copyFileSync(generated, cratePath); + return { ...packageData, cratePath }; +} + +export function packagePayload( + payloadRoot, + sourceRoot, + outputDir, + cargoTargetDir, + { + target, + version, + partBytes, + packageBase, + artifactProduct, + artifactKind, + artifactLabel, + noticeProfile, + }, +) { + const partDirs = fitCargoPayloadParts( + (rawBudget) => + buildPartCrates(payloadRoot, sourceRoot, { + targetId: target.target, + version, + partBytes: rawBudget, + packageBase, + artifactProduct, + artifactLabel, + noticeProfile, + }), + (partDir) => { + // Every file here was generated for this payload part; no source selection + // or dependency resolution is needed to measure its compressed archive. + const packageRoot = `${path.basename(partDir)}-${version}`; + const probeDir = path.join(cargoTargetDir, 'size-probe'); + mkdirSync(probeDir, { recursive: true }); + const crate = path.join(probeDir, `${packageRoot}.crate`); + writeFileSync( + crate, + canonicalGzipSync(createDeterministicTar(partDir, packageRoot, { fail })), + ); + return crate; + }, + partBytes, + ); + const aggregatorDir = path.join(sourceRoot, cargoPackageName(target.target, { packageBase })); + writeAggregatorCrate(aggregatorDir, { + target, + version, + partCount: partDirs.length, + packageBase, + artifactProduct, + artifactKind, + artifactLabel, + payloadFiles: frozenPayloadFiles(payloadRoot), + }); + + const packages = []; + for (let offset = 0; offset < partDirs.length; offset += 1) { + const partNumber = offset + 1; + const partDir = partDirs[offset]; + const name = partPackageName(target.target, partNumber, { packageBase }); + const cratePath = path.join(cargoTargetDir, 'size-probe', `${name}-${version}.crate`); + assertReleaseNoticesInArchive(cratePath, { + prefix: `${name}-${version}`, + profile: noticeProfile, + }); + validateCrateSize(cratePath); + const output = path.join(outputDir, path.basename(cratePath)); + copyFileSync(cratePath, output); + packages.push({ + name, + version, + manifestPath: path.join(partDir, 'Cargo.toml'), + cratePath: output, + target: target.target, + product: artifactProduct, + kind: artifactKind, + role: 'part', + noticeProfile, + index: partNumber, + }); + } + packages.push( + freezeSourceCrate( + { + name: cargoPackageName(target.target, { packageBase }), + version, + manifestPath: path.join(aggregatorDir, 'Cargo.toml'), + target: target.target, + product: artifactProduct, + kind: artifactKind, + role: 'aggregator', + noticeProfile: 'code-facade', + index: null, + }, + outputDir, + cargoTargetDir, + ), + ); + return packages; +} + +function usage() { + fail( + 'usage: package-cargo-artifacts.mts [--asset-dir DIR] [--output-dir DIR] [--work-dir DIR] [--version VERSION] [--target TARGET]... [--part-bytes BYTES]', + ); +} + +function help() { + console.log(`usage: package-cargo-artifacts.mts [options] + +Options: + --asset-dir DIR directory containing this product's checked release assets + --output-dir DIR directory where generated .crate files are written + --work-dir DIR isolated generated Cargo source/target workspace + --version VERSION release version to package + --target TARGET release target id to package; may be repeated + --part-bytes BYTES maximum raw payload bytes per generated part crate + -h, --help show this help +`); +} + +function optionValue(argv, index) { + const value = argv[index + 1]; + if (value === undefined || value.startsWith('--')) { + usage(); + } + return value; +} + +export async function parseCargoArtifactArgs(argv, { product, assetDir, outputDir, workDir }) { + const args = { + assetDir, + outputDir, + workDir, + version: undefined, + targets: [], + partBytes: DEFAULT_PART_BYTES, + }; + for (let index = 0; index < argv.length; ) { + const arg = argv[index]; + if (arg === '--asset-dir') { + args.assetDir = optionValue(argv, index); + index += 2; + } else if (arg === '--output-dir') { + args.outputDir = optionValue(argv, index); + index += 2; + } else if (arg === '--work-dir') { + args.workDir = optionValue(argv, index); + index += 2; + } else if (arg === '--version') { + args.version = optionValue(argv, index); + index += 2; + } else if (arg === '--target') { + args.targets.push(optionValue(argv, index)); + index += 2; + } else if (arg === '--part-bytes') { + const parsed = Number.parseInt(optionValue(argv, index), 10); + if (!Number.isInteger(parsed)) { + usage(); + } + args.partBytes = parsed; + index += 2; + } else if (arg === '-h' || arg === '--help') { + help(); + process.exit(0); + } else { + usage(); + } + } + return { + assetDir: repoPath(args.assetDir), + outputDir: repoPath(args.outputDir), + workDir: repoPath(args.workDir), + version: args.version ?? (await currentProductVersion(product, PREFIX)), + targets: args.targets, + partBytes: args.partBytes, + }; +} + +export function writePackagesManifest(packages, outputDir, product) { + const unfrozen = packages.filter((item) => item.cratePath === null); + if (unfrozen.length > 0) { + fail( + `all registry Cargo packages must have frozen .crate bytes: ${unfrozen.map((item) => item.name).join(', ')}`, + ); + } + const data = { + schema: 'oliphaunt-liboliphaunt-cargo-artifacts-v1', + product, + packages: packages.map((item) => ({ + name: item.name, + target: item.target, + product: item.product, + kind: item.kind, + role: item.role, + noticeProfile: item.noticeProfile, + index: item.index, + manifestPath: rel(item.manifestPath), + cratePath: rel(item.cratePath), + })), + }; + writeFileSync(path.join(outputDir, 'packages.json'), `${JSON.stringify(data, null, 2)}\n`); +} + +export function prepareCargoArtifactWorkspace(args) { + if (!isDirectory(args.assetDir)) fail('missing release asset directory: ' + rel(args.assetDir)); + if (args.partBytes <= 0 || args.partBytes > DEFAULT_PART_BYTES) + fail('--part-bytes must be between 1 and ' + DEFAULT_PART_BYTES); + const sourceRoot = path.join(args.workDir, 'cargo-package-sources'); + const cargoTargetDir = path.join(args.workDir, 'cargo-package-target'); + for (const dir of [sourceRoot, cargoTargetDir, args.outputDir]) + rmSync(dir, { recursive: true, force: true }); + mkdirSync(sourceRoot, { recursive: true }); + mkdirSync(args.outputDir, { recursive: true }); + return { sourceRoot, cargoTargetDir }; +} +export function selectCargoArtifactTargets(product, kind, selected) { + let targets = allArtifactTargets({ product, kind, surface: 'rust-native-direct' }, PREFIX); + if (selected.length) { + const unknown = selected.filter((id) => !targets.some((target) => target.target === id)); + if (unknown.length) fail('unknown Cargo artifact targets: ' + unknown.join(', ')); + targets = targets.filter((target) => selected.includes(target.target)); + } + return targets; +} +export function validateCargoArtifactPackages( + outputDir, + { product, expectedAggregators, expectedFacade, configuredCrates }, +) { + const manifestPath = path.join(outputDir, 'packages.json'); + if (!isFile(manifestPath)) { + fail(`missing generated ${product} Cargo artifact manifest: ${rel(manifestPath)}`); + } + let data; + try { + data = JSON.parse(readFileSync(manifestPath, 'utf8')); + } catch (error) { + fail(`${rel(manifestPath)} is not valid JSON: ${error.message}`); + } + if ( + data?.schema !== 'oliphaunt-liboliphaunt-cargo-artifacts-v1' || + !Array.isArray(data.packages) + ) { + fail(`${rel(manifestPath)} has an invalid liboliphaunt native Cargo artifact schema`); + } + + const expectedRegistryCrates = new Set([ + ...expectedAggregators, + ...(expectedFacade ? [expectedFacade] : []), + ]); + assertSameStringSet( + `${product} crates.io packages must match native runtime/tool artifact packages`, + configuredCrates, + expectedRegistryCrates, + ); + const aggregators = new Set(); + const facades = new Set(); + const expectedCratePaths = new Set(); + const packages = []; + + for (const item of data.packages) { + if (item === null || Array.isArray(item) || typeof item !== 'object') { + fail(`${rel(manifestPath)} package entries must be objects`); + } + const { name, role, manifestPath: rawManifest, cratePath: rawCrate } = item; + if ( + ![name, role, rawManifest].every((value) => typeof value === 'string' && value.length > 0) + ) { + fail(`${rel(manifestPath)} has an invalid package row: ${JSON.stringify(item)}`); + } + const sourceManifest = path.join(ROOT, rawManifest); + if (!isFile(sourceManifest)) { + fail(`missing generated ${product} Cargo source manifest: ${rawManifest}`); + } + if (typeof rawCrate !== 'string' || rawCrate.length === 0) { + fail(`generated ${product} registry crate ${name} must freeze a .crate archive`); + } + const cratePath = path.join(ROOT, rawCrate); + if (!isFile(cratePath) || !cratePath.endsWith('.crate')) { + fail(`missing generated ${product} Cargo archive for ${name}: ${rawCrate}`); + } + expectedCratePaths.add(path.resolve(cratePath)); + if (role === 'part') { + const aggregator = name.replace(/-part-\d{3}$/u, ''); + if (aggregator === name || !expectedAggregators.has(aggregator)) { + fail(`unexpected ${product} Cargo part crate ${name}`); + } + packages.push({ name, cratePath, manifestPath: sourceManifest, role }); + continue; + } + if (role === 'aggregator') { + if (!expectedAggregators.has(name)) { + fail(`unexpected ${product} Cargo aggregator crate ${name}`); + } + aggregators.add(name); + packages.push({ name, cratePath, manifestPath: sourceManifest, role }); + continue; + } + if (role === 'facade') { + if (name !== expectedFacade) { + fail(`unexpected ${product} Cargo facade crate ${name}`); + } + facades.add(name); + packages.push({ name, cratePath, manifestPath: sourceManifest, role }); + continue; + } + fail(`${rel(manifestPath)} has unsupported Cargo artifact role ${JSON.stringify(role)}`); + } + + const missingAggregators = [...expectedAggregators] + .filter((name) => !aggregators.has(name)) + .sort(compareText); + if (missingAggregators.length > 0) { + fail( + `generated ${product} Cargo artifacts are missing aggregator crates: ${missingAggregators.join(', ')}`, + ); + } + if (expectedFacade && !facades.has(expectedFacade)) { + fail(`generated ${product} Cargo artifacts are missing ${expectedFacade} facade crate`); + } + const unexpected = readdirSync(outputDir) + .filter((name) => name.endsWith('.crate')) + .map((name) => path.join(outputDir, name)) + .filter((file) => !expectedCratePaths.has(path.resolve(file))) + .map((file) => path.basename(file)) + .sort(compareText); + if (unexpected.length > 0) { + fail(`unexpected ${product} Cargo artifact crate(s): ${unexpected.join(', ')}`); + } + const roleOrder = new Map([ + ['part', 0], + ['aggregator', 1], + ['facade', 2], + ]); + return packages.sort( + (left, right) => + (roleOrder.get(left.role) ?? 99) - (roleOrder.get(right.role) ?? 99) || + compareText(left.name, right.name), + ); +} diff --git a/tools/packaging/npm-package.mts b/tools/packaging/npm-package.mts new file mode 100644 index 000000000..dcc6c00c5 --- /dev/null +++ b/tools/packaging/npm-package.mts @@ -0,0 +1,54 @@ +import { + chmodSync, + mkdirSync, + readdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { createDeterministicTar } from './cargo-source-package.mts'; +import { validateNpmTrustedPublishingManifest } from './npm-trusted-publishing.mts'; +import { canonicalGzipSync, portableMemberName } from './portable-archive.mts'; + +if (import.meta.main) { + if (process.argv.length !== 3) throw new Error('usage: npm-package.mts '); + const manifest = JSON.parse(readFileSync(path.join(process.argv[2], 'package.json'), 'utf8')); + const filename = `${safeNpmPackageFilenamePrefix(manifest.name)}-${manifest.version}.tgz`; + portableMemberName(filename, 'file', process.argv[2]); + console.log(filename); +} + +function safeNpmPackageFilenamePrefix(name) { + return name.replace(/^@/u, '').replaceAll('/', '-'); +} +function reject(message) { + throw new Error(message); +} + +export function packGeneratedNpmCarrier(packageDir, tarballRoot) { + const manifest = JSON.parse(readFileSync(path.join(packageDir, 'package.json'), 'utf8')); + validateNpmTrustedPublishingManifest(manifest, `${packageDir}/package.json`); + if (Object.keys(manifest.scripts ?? {}).length > 0) + reject('staged npm carriers must not contain lifecycle scripts'); + const packDir = path.join(tarballRoot, safeNpmPackageFilenamePrefix(manifest.name)); + const filename = `${safeNpmPackageFilenamePrefix(manifest.name)}-${manifest.version}.tgz`; + portableMemberName(filename, 'file', packageDir); + for (const member of manifest.publishConfig?.executableFiles ?? []) { + chmodSync(path.join(packageDir, portableMemberName(member, 'file', packageDir)), 0o755); + } + for (const entry of readdirSync(packageDir, { recursive: true, withFileTypes: true })) { + if (!entry.isFile()) continue; + const file = path.join(entry.parentPath, entry.name); + chmodSync(file, statSync(file).mode & 0o100 ? 0o755 : 0o644); + } + rmSync(packDir, { recursive: true, force: true }); + mkdirSync(packDir, { recursive: true }); + const tarball = path.join(packDir, filename); + writeFileSync( + tarball, + canonicalGzipSync(createDeterministicTar(packageDir, 'package', { fail: reject })), + ); + return tarball; +} diff --git a/tools/packaging/npm-trusted-publishing.mts b/tools/packaging/npm-trusted-publishing.mts new file mode 100644 index 000000000..3c65c9397 --- /dev/null +++ b/tools/packaging/npm-trusted-publishing.mts @@ -0,0 +1,45 @@ +export const NPM_TRUSTED_PUBLISHING_REPOSITORY = 'git+https://github.com/f0rr0/oliphaunt.git'; + +function object(value) { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +// This validator defines the npm manifests accepted by deterministic carrier +// materialization. Operational +// runtime and registry trust checks live in npm-trusted-publishing-runtime.mts +// so changes to release transport do not spuriously version package products. +export function validateNpmTrustedPublishingManifest(manifest, context = 'npm package') { + if (!object(manifest)) { + throw new TypeError(`${context} package.json must be an object`); + } + if (typeof manifest.name !== 'string' || !manifest.name.startsWith('@oliphaunt/')) { + throw new Error(`${context} must declare an @oliphaunt package name`); + } + if (typeof manifest.version !== 'string' || manifest.version.length === 0) { + throw new Error(`${context} must declare a package version`); + } + if (!object(manifest.repository)) { + throw new Error(`${context} repository must be an object for npm trusted publishing`); + } + if (manifest.repository.type !== 'git') { + throw new Error(`${context} repository.type must be "git" for npm trusted publishing`); + } + if (manifest.repository.url !== NPM_TRUSTED_PUBLISHING_REPOSITORY) { + throw new Error( + `${context} repository.url must exactly match ${NPM_TRUSTED_PUBLISHING_REPOSITORY}; got ${JSON.stringify(manifest.repository.url ?? null)}`, + ); + } + if (manifest.private === true) { + throw new Error(`${context} must not be private`); + } + if (manifest.publishConfig !== undefined && !object(manifest.publishConfig)) { + throw new Error(`${context} publishConfig must be an object when present`); + } + if (manifest.publishConfig?.provenance === false) { + throw new Error(`${context} must not disable npm provenance`); + } + if (manifest.publishConfig?.access !== undefined && manifest.publishConfig.access !== 'public') { + throw new Error(`${context} publishConfig.access must be "public" when present`); + } + return manifest; +} diff --git a/tools/packaging/package-cargo-source.sh b/tools/packaging/package-cargo-source.sh new file mode 100644 index 000000000..2392b3695 --- /dev/null +++ b/tools/packaging/package-cargo-source.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +# OLIPHAUNT_CARGO_NOTICE_PROFILE stages canonical notices in the private copy. +if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then + echo 'usage: package-cargo-source.sh MANIFEST OUTPUT_DIRECTORY [PACKAGE_LIST]' >&2 + exit 1 +fi +helper="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/cargo-source-package.mts" +scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-cargo-source-XXXXXX") +trap 'rm -rf "$scratch"' EXIT +cargo package --manifest-path "$1" --allow-dirty --list > "$scratch/files.txt" +manifest=$(bun "$helper" prepare "$scratch/state.json" "$1" "$2" "$scratch/files.txt") +cargo metadata --manifest-path "$manifest" --format-version 1 --no-deps > "$scratch/metadata.json" +bun "$helper" finish "$scratch/state.json" "$scratch/metadata.json" +if [ "$#" -eq 3 ]; then cp "$scratch/files.txt" "$3"; fi diff --git a/tools/packaging/platform-binary-contract.mts b/tools/packaging/platform-binary-contract.mts new file mode 100644 index 000000000..9d5b6e130 --- /dev/null +++ b/tools/packaging/platform-binary-contract.mts @@ -0,0 +1,1374 @@ +#!/usr/bin/env bun + +import { lstat, readFile, readdir } from 'node:fs/promises'; +import path from 'node:path'; + +import { + APPLE_PLATFORM_COMPATIBILITY, + platformCompatibilityContract, +} from '../release/platform-compatibility-policy.mts'; +import { + WINDOWS_VC_RUNTIME_DLLS, + inspectPortableExecutable, +} from './windows-vc-runtime-closure.mts'; + +const MACHO_LC_BUILD_VERSION = 0x32; +const ELF_TYPE_REL = 1; +const ELF_TYPE_EXEC = 2; +const ELF_TYPE_DYN = 3; +const ELF_SECTION_NOTE = 7; +const APPLE_PLATFORM_BY_ID = new Map( + Object.values(APPLE_PLATFORM_COMPATIBILITY).map((platform) => [platform.id, platform]), +); +const APPLE_PLATFORM_BY_CLI_NAME = new Map( + Object.values(APPLE_PLATFORM_COMPATIBILITY).map((platform) => [platform.cliName, platform]), +); +const WINDOWS_VC_RUNTIME_PROFILES = + platformCompatibilityContract('windows-x64-msvc').windowsVcRuntime.profiles; + +const EXPECTED_BINARY_PATH = /(?:\.dylib|\.dll|\.exe|\.node|\.so(?:\.[0-9]+)*)$/iu; +const STATIC_ARCHIVE_PATH = /\.a$/iu; +const MSVC_LIBRARY_PATH = /\.lib$/iu; +// Exact extension artifacts carry declared upstream grant text in this namespace. +// Only UTF-8 text at the canonical COPYING.LIB identity is metadata; detected +// formats and non-text bytes fail closed. +const WINDOWS_EXTENSION_LEGAL_TEXT_LIBRARY_PATH = + /(?:^|\/)files\/share\/licenses\/[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?\/COPYING\.LIB$/iu; +const MSVC_RUNTIME_IMPORT = /^(?:CONCRT|MSVCP|VCRUNTIME)[0-9A-Z_]*\.DLL$/iu; +const WINDOWS_VC_RUNTIME_DLL_SET = new Set(WINDOWS_VC_RUNTIME_DLLS); +const WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH = 'lib/oliphaunt.lib'; +const WINDOWS_RUNTIME_IMPORT_DLL = 'oliphaunt.dll'; +const WINDOWS_RUNTIME_IMPORT_SYMBOLS = Object.freeze([ + 'oliphaunt_init', + 'oliphaunt_logical_generation', + 'oliphaunt_close_if_generation', + 'oliphaunt_exec_protocol', + 'oliphaunt_exec_simple_query', + 'oliphaunt_exec_protocol_raw_stream', + 'oliphaunt_backup', + 'oliphaunt_restore', + 'oliphaunt_init_with_error', + 'oliphaunt_exec_protocol_with_error', + 'oliphaunt_exec_simple_query_with_error', + 'oliphaunt_exec_protocol_raw_stream_with_error', + 'oliphaunt_backup_with_error', + 'oliphaunt_restore_with_error', + 'oliphaunt_detach_with_error', + 'oliphaunt_cancel', + 'oliphaunt_detach', + 'oliphaunt_close', + 'oliphaunt_register_static_extensions', + 'oliphaunt_copy_last_error', + 'oliphaunt_version', + 'oliphaunt_free_response', +]); +const COFF_ARCHIVE_HEADER_SIZE = 60; +const COFF_OBJECT_HEADER_SIZE = 20; +const COFF_SECTION_HEADER_SIZE = 40; +const COFF_SYMBOL_SIZE = 18; +const COFF_RELOCATION_SIZE = 10; +const COFF_LINE_NUMBER_SIZE = 6; +const COFF_IMPORT_OBJECT_SIGNATURE = 0xffff; +const COFF_IMPORT_OBJECT_NAME_EXPORT_AS = 4; + +export class PlatformBinaryContractError extends Error { + constructor(message) { + super(message); + this.name = 'PlatformBinaryContractError'; + } +} + +function fail(label, message) { + throw new PlatformBinaryContractError(`${label}: ${message}`); +} + +function requireRange(buffer, offset, length, label, description) { + if ( + !Number.isSafeInteger(offset) || + !Number.isSafeInteger(length) || + offset < 0 || + length < 0 || + offset > buffer.length || + length > buffer.length - offset + ) { + fail(label, `${description} is outside the ${buffer.length}-byte file`); + } +} + +function safeNumber(value, label, description) { + if (value > BigInt(Number.MAX_SAFE_INTEGER)) { + fail(label, `${description} exceeds the safe parser range`); + } + return Number(value); +} + +function contractFor(target, label) { + const contract = platformCompatibilityContract(target); + if (contract === undefined) { + fail(label, `unsupported platform-binary target ${JSON.stringify(target)}`); + } + return contract; +} + +function compareVersion(left, right) { + for (let index = 0; index < Math.max(left.length, right.length); index += 1) { + const difference = (left[index] ?? 0) - (right[index] ?? 0); + if (difference !== 0) return difference; + } + return 0; +} + +function formatVersion(version) { + return version.length > 2 && version[2] !== 0 + ? `${version[0]}.${version[1]}.${version[2]}` + : `${version[0]}.${version[1]}`; +} + +function packedAppleVersion(value) { + return [(value >>> 16) & 0xffff, (value >>> 8) & 0xff, value & 0xff]; +} + +function detectFormat(buffer) { + if (buffer.length >= 8 && buffer.subarray(0, 8).equals(Buffer.from('!\n', 'ascii'))) { + return 'ar'; + } + if (buffer.length >= 4 && buffer.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46]))) { + return 'elf'; + } + if (buffer.length >= 2 && buffer[0] === 0x4d && buffer[1] === 0x5a) { + return 'pe'; + } + if (buffer.length >= 4) { + const magic = buffer.readUInt32BE(0); + if ( + magic === 0xfeedfacf || + magic === 0xcffaedfe || + magic === 0xcafebabe || + magic === 0xbebafeca || + magic === 0xcafebabf || + magic === 0xbfbafeca || + magic === 0xfeedface || + magic === 0xcefaedfe + ) { + return 'macho'; + } + } + return null; +} + +function isPlainText(buffer) { + if (buffer.length === 0) return false; + const text = buffer.toString('utf8'); + return ( + Buffer.from(text, 'utf8').equals(buffer) && + !/[\u0000-\u0008\u000b\u000e-\u001f\u007f]/u.test(text) + ); +} + +function isWindowsExtensionLegalTextLibrary(name, buffer, format) { + return ( + format === null && WINDOWS_EXTENSION_LEGAL_TEXT_LIBRARY_PATH.test(name) && isPlainText(buffer) + ); +} + +function parseArchiveDecimal(buffer, offset, length, label, description) { + requireRange(buffer, offset, length, label, description); + const text = buffer + .subarray(offset, offset + length) + .toString('ascii') + .trim(); + if (!/^[0-9]+$/u.test(text)) fail(label, `${description} is not an unsigned decimal integer`); + const value = Number(text); + if (!Number.isSafeInteger(value)) fail(label, `${description} exceeds the safe parser range`); + return value; +} + +function parseArArchiveMembers(buffer, label) { + requireRange(buffer, 0, 8, label, 'ar global header'); + if (!buffer.subarray(0, 8).equals(Buffer.from('!\n', 'ascii'))) { + fail(label, 'ar global header is invalid'); + } + let cursor = 8; + let longNames = null; + const members = []; + while (cursor < buffer.length) { + const headerOffset = cursor; + requireRange(buffer, cursor, COFF_ARCHIVE_HEADER_SIZE, label, 'ar member header'); + if (buffer.subarray(cursor + 58, cursor + 60).toString('ascii') !== '`\n') { + fail(label, `ar member at offset ${cursor} has an invalid header trailer`); + } + const rawName = buffer + .subarray(cursor, cursor + 16) + .toString('ascii') + .trim(); + const size = parseArchiveDecimal(buffer, cursor + 48, 10, label, 'ar member size'); + const dataOffset = cursor + COFF_ARCHIVE_HEADER_SIZE; + requireRange(buffer, dataOffset, size, label, `ar member ${rawName || ''}`); + let name = rawName.replace(/\/$/u, ''); + let payloadOffset = dataOffset; + let payloadSize = size; + if (rawName.startsWith('#1/')) { + const nameLengthText = rawName.slice(3).trim(); + if (!/^[0-9]+$/u.test(nameLengthText)) + fail(label, `ar BSD member name length is invalid: ${rawName}`); + const nameLength = Number(nameLengthText); + if (!Number.isSafeInteger(nameLength) || nameLength <= 0 || nameLength > size) { + fail(label, `ar BSD member name length ${nameLengthText} exceeds its member`); + } + name = buffer + .subarray(dataOffset, dataOffset + nameLength) + .toString('utf8') + .replace(/\x00+$/u, ''); + payloadOffset += nameLength; + payloadSize -= nameLength; + } else if (rawName === '//') { + longNames = buffer.subarray(dataOffset, dataOffset + size); + } else if (/^\/[0-9]+$/u.test(rawName)) { + if (longNames === null) + fail(label, `ar member ${rawName} refers to a missing long-name table`); + const nameOffset = Number(rawName.slice(1)); + if (!Number.isSafeInteger(nameOffset) || nameOffset < 0 || nameOffset >= longNames.length) { + fail(label, `ar member long-name offset ${nameOffset} is out of range`); + } + const gnuNameEnd = longNames.indexOf(Buffer.from('/\n', 'ascii'), nameOffset); + const coffNameEnd = longNames.indexOf(0, nameOffset); + const nameEnd = [gnuNameEnd, coffNameEnd] + .filter((offset) => offset >= nameOffset) + .sort((left, right) => left - right)[0]; + if (nameEnd === undefined) + fail(label, `ar member long name at offset ${nameOffset} is unterminated`); + name = longNames.subarray(nameOffset, nameEnd).toString('utf8'); + } + + const special = + rawName === '/' || + rawName === '//' || + rawName === '/SYM64/' || + name.startsWith('__.SYMDEF') || + name === 'SYM64'; + members.push({ + headerOffset, + name, + payload: buffer.subarray(payloadOffset, payloadOffset + payloadSize), + rawName, + special, + }); + cursor = dataOffset + size + (size % 2); + } + if (cursor !== buffer.length) fail(label, 'ar archive has a truncated alignment byte'); + return members; +} + +function parseArArchive(buffer, label, contract) { + const slices = []; + for (const { name, payload, special } of parseArArchiveMembers(buffer, label)) { + if (!special) { + if (payload.length === 0) fail(label, `ar object member ${JSON.stringify(name)} is empty`); + const format = detectFormat(payload); + if (format === 'macho' && contract.format === 'macho') { + slices.push(...parseMacho(payload, `${label}(${name})`, contract)); + } else if (format === 'elf' && contract.format === 'elf') { + slices.push(parseElf(payload, `${label}(${name})`, contract)); + } else { + fail( + label, + `ar member ${JSON.stringify(name)} is not a ${contract.format.toUpperCase()} object for this carrier`, + ); + } + } + } + if (slices.length === 0) fail(label, 'ar archive contains no inspectable native object members'); + return slices; +} + +function parseNullTerminatedStrings(buffer, offset, count, label, description) { + const values = []; + let cursor = offset; + for (let index = 0; index < count; index += 1) { + if (cursor >= buffer.length) { + fail(label, `${description} is missing string ${index + 1} of ${count}`); + } + const end = buffer.indexOf(0, cursor); + if (end < 0) fail(label, `${description} string ${index + 1} is unterminated`); + if (end === cursor) fail(label, `${description} string ${index + 1} is empty`); + values.push(buffer.subarray(cursor, end).toString('latin1')); + cursor = end + 1; + } + if (cursor !== buffer.length) { + fail(label, `${description} has ${buffer.length - cursor} trailing byte(s)`); + } + return values; +} + +function parseWindowsFirstLinkerMember(member, objectOffsets, label) { + const memberLabel = `${label} [first linker member]`; + requireRange(member.payload, 0, 4, memberLabel, 'symbol count'); + const count = member.payload.readUInt32BE(0); + if (count === 0 || count > 1_000_000) { + fail(memberLabel, `symbol count ${count} is invalid`); + } + requireRange(member.payload, 4, count * 4, memberLabel, 'member-offset table'); + const offsets = []; + for (let index = 0; index < count; index += 1) { + const offset = member.payload.readUInt32BE(4 + index * 4); + if (!objectOffsets.has(offset)) { + fail(memberLabel, `symbol ${index} refers to non-object archive offset ${offset}`); + } + offsets.push(offset); + } + const names = parseNullTerminatedStrings( + member.payload, + 4 + count * 4, + count, + memberLabel, + 'symbol-name table', + ); + return { names, offsets }; +} + +function parseWindowsSecondLinkerMember(member, objectMembers, label) { + const memberLabel = `${label} [second linker member]`; + requireRange(member.payload, 0, 4, memberLabel, 'archive-member count'); + const memberCount = member.payload.readUInt32LE(0); + if (memberCount === 0 || memberCount > 1_000_000) { + fail(memberLabel, `archive-member count ${memberCount} is invalid`); + } + requireRange( + member.payload, + 4, + memberCount * 4 + 4, + memberLabel, + 'member-offset and symbol-count tables', + ); + const offsets = []; + const seenOffsets = new Set(); + for (let index = 0; index < memberCount; index += 1) { + const offset = member.payload.readUInt32LE(4 + index * 4); + if (seenOffsets.has(offset)) fail(memberLabel, `archive-member offset ${offset} is repeated`); + seenOffsets.add(offset); + offsets.push(offset); + } + const expectedOffsets = new Set(objectMembers.map(({ headerOffset }) => headerOffset)); + if ( + offsets.length !== expectedOffsets.size || + offsets.some((offset) => !expectedOffsets.has(offset)) + ) { + fail(memberLabel, 'archive-member offsets do not exactly cover the COFF object members'); + } + const symbolCountOffset = 4 + memberCount * 4; + const symbolCount = member.payload.readUInt32LE(symbolCountOffset); + if (symbolCount === 0 || symbolCount > 1_000_000) { + fail(memberLabel, `symbol count ${symbolCount} is invalid`); + } + const indicesOffset = symbolCountOffset + 4; + requireRange(member.payload, indicesOffset, symbolCount * 2, memberLabel, 'symbol-index table'); + for (let index = 0; index < symbolCount; index += 1) { + const memberIndex = member.payload.readUInt16LE(indicesOffset + index * 2); + if (memberIndex === 0 || memberIndex > memberCount) { + fail(memberLabel, `symbol ${index} has out-of-range archive-member index ${memberIndex}`); + } + } + const names = parseNullTerminatedStrings( + member.payload, + indicesOffset + symbolCount * 2, + symbolCount, + memberLabel, + 'symbol-name table', + ); + for (let index = 1; index < names.length; index += 1) { + if ( + Buffer.compare( + Buffer.from(names[index - 1], 'latin1'), + Buffer.from(names[index], 'latin1'), + ) >= 0 + ) { + fail(memberLabel, 'symbol names must be unique and in ascending lexical order'); + } + } + return names; +} + +function requireCoffPointer(buffer, pointer, size, headerEnd, label, description) { + if (size === 0) return; + if (pointer < headerEnd) fail(label, `${description} overlaps the COFF headers`); + requireRange(buffer, pointer, size, label, description); +} + +function parseCoffObjectMember(buffer, label, contract) { + requireRange(buffer, 0, COFF_OBJECT_HEADER_SIZE, label, 'COFF object header'); + const machine = buffer.readUInt16LE(0); + if (machine !== contract.pe.machine) { + fail(label, `COFF object machine 0x${machine.toString(16)} is not ${contract.architecture}`); + } + const sectionCount = buffer.readUInt16LE(2); + if (sectionCount === 0 || sectionCount > 96) { + fail(label, `COFF object section count ${sectionCount} is invalid`); + } + const symbolTable = buffer.readUInt32LE(8); + const symbolCount = buffer.readUInt32LE(12); + const optionalHeaderSize = buffer.readUInt16LE(16); + if (optionalHeaderSize !== 0) { + fail(label, `COFF archive object has unexpected ${optionalHeaderSize}-byte optional header`); + } + const sectionTable = COFF_OBJECT_HEADER_SIZE; + const headerEnd = sectionTable + sectionCount * COFF_SECTION_HEADER_SIZE; + requireRange( + buffer, + sectionTable, + sectionCount * COFF_SECTION_HEADER_SIZE, + label, + 'COFF section table', + ); + for (let index = 0; index < sectionCount; index += 1) { + const section = sectionTable + index * COFF_SECTION_HEADER_SIZE; + const rawSize = buffer.readUInt32LE(section + 16); + const rawPointer = buffer.readUInt32LE(section + 20); + const relocationPointer = buffer.readUInt32LE(section + 24); + const lineNumberPointer = buffer.readUInt32LE(section + 28); + const relocationCount = buffer.readUInt16LE(section + 32); + const lineNumberCount = buffer.readUInt16LE(section + 34); + requireCoffPointer( + buffer, + rawPointer, + rawSize, + headerEnd, + label, + `COFF section ${index} raw data`, + ); + requireCoffPointer( + buffer, + relocationPointer, + relocationCount * COFF_RELOCATION_SIZE, + headerEnd, + label, + `COFF section ${index} relocations`, + ); + requireCoffPointer( + buffer, + lineNumberPointer, + lineNumberCount * COFF_LINE_NUMBER_SIZE, + headerEnd, + label, + `COFF section ${index} line numbers`, + ); + } + if (symbolCount === 0) { + if (symbolTable !== 0) fail(label, 'COFF object has a symbol-table pointer but zero symbols'); + } else { + requireCoffPointer( + buffer, + symbolTable, + symbolCount * COFF_SYMBOL_SIZE, + headerEnd, + label, + 'COFF symbol table', + ); + let symbolIndex = 0; + while (symbolIndex < symbolCount) { + const symbol = symbolTable + symbolIndex * COFF_SYMBOL_SIZE; + const auxiliaryCount = buffer[symbol + 17]; + if (auxiliaryCount > symbolCount - symbolIndex - 1) { + fail( + label, + `COFF symbol ${symbolIndex} has ${auxiliaryCount} out-of-range auxiliary record(s)`, + ); + } + symbolIndex += auxiliaryCount + 1; + } + const stringTable = symbolTable + symbolCount * COFF_SYMBOL_SIZE; + requireRange(buffer, stringTable, 4, label, 'COFF string-table size'); + const stringTableSize = buffer.readUInt32LE(stringTable); + if (stringTableSize < 4) fail(label, `COFF string-table size ${stringTableSize} is invalid`); + requireRange(buffer, stringTable, stringTableSize, label, 'COFF string table'); + if (stringTable + stringTableSize !== buffer.length) { + fail(label, 'COFF string table does not end at the object-member boundary'); + } + } + return { kind: 'coff-object', machine: contract.architecture }; +} + +function parseCoffImportObjectMember(buffer, label, contract) { + requireRange(buffer, 0, COFF_OBJECT_HEADER_SIZE, label, 'COFF import-object header'); + if (buffer.readUInt16LE(0) !== 0 || buffer.readUInt16LE(2) !== COFF_IMPORT_OBJECT_SIGNATURE) { + fail(label, 'COFF import-object signature is invalid'); + } + const version = buffer.readUInt16LE(4); + if (version !== 0) { + fail( + label, + `unsupported anonymous COFF object version ${version}; expected a short import object`, + ); + } + const machine = buffer.readUInt16LE(6); + if (machine !== contract.pe.machine) { + fail( + label, + `COFF import-object machine 0x${machine.toString(16)} is not ${contract.architecture}`, + ); + } + const sizeOfData = buffer.readUInt32LE(12); + if (sizeOfData !== buffer.length - COFF_OBJECT_HEADER_SIZE) { + fail( + label, + `COFF import-object data size ${sizeOfData} does not match its ${buffer.length - COFF_OBJECT_HEADER_SIZE}-byte payload`, + ); + } + const typeInfo = buffer.readUInt16LE(18); + const importType = typeInfo & 0x3; + const nameType = (typeInfo >>> 2) & 0x7; + if (importType > 2) fail(label, `COFF import-object type ${importType} is invalid`); + if (nameType > COFF_IMPORT_OBJECT_NAME_EXPORT_AS) { + fail(label, `COFF import-object name type ${nameType} is invalid`); + } + if ((typeInfo & 0xffe0) !== 0) fail(label, 'COFF import-object reserved type bits are nonzero'); + const strings = parseNullTerminatedStrings( + buffer, + COFF_OBJECT_HEADER_SIZE, + nameType === COFF_IMPORT_OBJECT_NAME_EXPORT_AS ? 3 : 2, + label, + 'COFF import-object data', + ); + return { + dll: strings[1], + kind: 'coff-import-object', + machine: contract.architecture, + symbol: strings[0], + }; +} + +function parseWindowsRuntimeImportLibrary(buffer, label, contract) { + const members = parseArArchiveMembers(buffer, label); + if (members.length < 3 || members[0].rawName !== '/' || members[1].rawName !== '/') { + fail(label, 'MSVC import library must begin with its first and second linker members'); + } + const objectMembers = members.filter(({ special }) => !special); + if (objectMembers.length === 0) + fail(label, 'MSVC import library contains no COFF object members'); + const unexpectedSpecial = members + .slice(2) + .find(({ rawName, special }) => special && rawName !== '//' && rawName !== '/'); + if (unexpectedSpecial !== undefined) { + fail( + label, + `MSVC import library contains unsupported special member ${JSON.stringify(unexpectedSpecial.rawName)}`, + ); + } + if (members.slice(2).some(({ rawName }) => rawName === '/')) { + fail(label, 'MSVC import library contains an unexpected additional linker member'); + } + if (members.filter(({ rawName }) => rawName === '//').length > 1) { + fail(label, 'MSVC import library repeats its long-name member'); + } + const objectOffsets = new Set(objectMembers.map(({ headerOffset }) => headerOffset)); + parseWindowsFirstLinkerMember(members[0], objectOffsets, label); + const linkerSymbols = parseWindowsSecondLinkerMember(members[1], objectMembers, label); + + const slices = []; + const imports = []; + for (const member of objectMembers) { + if (member.payload.length === 0) { + fail(label, `MSVC import-library member ${JSON.stringify(member.name)} is empty`); + } + const memberLabel = `${label}(${member.name})`; + const shortImport = + member.payload.length >= 4 && + member.payload.readUInt16LE(0) === 0 && + member.payload.readUInt16LE(2) === COFF_IMPORT_OBJECT_SIGNATURE; + const parsed = shortImport + ? parseCoffImportObjectMember(member.payload, memberLabel, contract) + : parseCoffObjectMember(member.payload, memberLabel, contract); + slices.push(parsed); + if (parsed.kind === 'coff-import-object') imports.push(parsed); + } + if (imports.length === 0) + fail(label, 'MSVC import library contains no short import-object members'); + const wrongDll = imports.find(({ dll }) => dll.toLowerCase() !== WINDOWS_RUNTIME_IMPORT_DLL); + if (wrongDll !== undefined) { + fail( + label, + `MSVC import object for ${JSON.stringify(wrongDll.symbol)} names unexpected DLL ${JSON.stringify(wrongDll.dll)}`, + ); + } + const importSymbols = new Set(imports.map(({ symbol }) => symbol)); + for (const requiredSymbol of WINDOWS_RUNTIME_IMPORT_SYMBOLS) { + if (!importSymbols.has(requiredSymbol)) { + fail(label, `MSVC import library does not expose required symbol ${requiredSymbol}`); + } + if (!linkerSymbols.includes(requiredSymbol)) { + fail(label, `MSVC second linker member does not index required symbol ${requiredSymbol}`); + } + } + return { + archived: true, + format: 'pe', + platforms: [], + slices, + }; +} + +function machoEndianAndWidth(buffer, offset, label) { + requireRange(buffer, offset, 4, label, 'Mach-O magic'); + const magic = buffer.readUInt32BE(offset); + if (magic === 0xfeedfacf) return { endian: 'be', bits: 64 }; + if (magic === 0xcffaedfe) return { endian: 'le', bits: 64 }; + if (magic === 0xfeedface || magic === 0xcefaedfe) { + fail(label, 'Mach-O image is 32-bit; release binaries must be 64-bit arm64'); + } + fail(label, 'Mach-O slice has an invalid thin-image magic'); +} + +function readMachoUInt32(buffer, offset, endian) { + return endian === 'le' ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); +} + +function parseMachoSlice(buffer, sliceOffset, sliceSize, label, contract) { + requireRange(buffer, sliceOffset, sliceSize, label, 'Mach-O slice'); + if (sliceSize < 32) fail(label, 'Mach-O 64-bit header is truncated'); + const { endian } = machoEndianAndWidth(buffer, sliceOffset, label); + const read32 = (relative) => { + requireRange(buffer, sliceOffset + relative, 4, label, 'Mach-O header field'); + return readMachoUInt32(buffer, sliceOffset + relative, endian); + }; + const cpuType = read32(4); + if (cpuType !== contract.macho.cpuType) { + fail(label, `Mach-O cpu type 0x${cpuType.toString(16)} is not arm64`); + } + const cpuSubtype = read32(8); + if (cpuSubtype !== contract.macho.cpuSubtype) { + fail( + label, + `Mach-O arm64 cpu subtype 0x${cpuSubtype.toString(16)} is not generic ARM64_ALL (arm64e-only slices are not portable arm64 carriers)`, + ); + } + const commandCount = read32(16); + const commandsSize = read32(20); + if (commandCount > 65_536) + fail(label, `Mach-O declares unreasonable load-command count ${commandCount}`); + requireRange(buffer, sliceOffset + 32, commandsSize, label, 'Mach-O load-command table'); + if (commandsSize > sliceSize - 32) fail(label, 'Mach-O load-command table exceeds its fat slice'); + + let cursor = sliceOffset + 32; + const commandsEnd = cursor + commandsSize; + const buildVersions = []; + for (let index = 0; index < commandCount; index += 1) { + requireRange(buffer, cursor, 8, label, `Mach-O load command ${index}`); + if (cursor + 8 > commandsEnd) fail(label, `Mach-O load command ${index} exceeds sizeofcmds`); + const command = readMachoUInt32(buffer, cursor, endian); + const commandSize = readMachoUInt32(buffer, cursor + 4, endian); + if (commandSize < 8 || commandSize % 4 !== 0) { + fail(label, `Mach-O load command ${index} has invalid cmdsize ${commandSize}`); + } + if (commandSize > commandsEnd - cursor) { + fail(label, `Mach-O load command ${index} exceeds sizeofcmds`); + } + if (command === MACHO_LC_BUILD_VERSION) { + if (commandSize < 24) fail(label, 'Mach-O LC_BUILD_VERSION is truncated'); + buildVersions.push({ + platform: readMachoUInt32(buffer, cursor + 8, endian), + minos: packedAppleVersion(readMachoUInt32(buffer, cursor + 12, endian)), + }); + } + cursor += commandSize; + } + if (cursor !== commandsEnd) { + fail( + label, + `Mach-O load commands consume ${cursor - (sliceOffset + 32)} bytes, expected ${commandsSize}`, + ); + } + if (buildVersions.length !== 1) { + fail( + label, + `Mach-O slice must contain exactly one LC_BUILD_VERSION, found ${buildVersions.length}`, + ); + } + const [{ platform, minos }] = buildVersions; + const platformMetadata = APPLE_PLATFORM_BY_ID.get(platform); + if (platformMetadata === undefined) { + fail(label, `Mach-O LC_BUILD_VERSION platform ${platform} is not macOS, iOS, or iOS Simulator`); + } + const platformContract = Object.values(contract.apple.platforms).find( + (candidate) => candidate.id === platform, + ); + if (platformContract === undefined) { + fail( + label, + `${contract.apple.carrier} contains unsupported ${platformMetadata.name} Mach-O content`, + ); + } + const maximum = platformContract.maximumMinimumOs; + if (compareVersion(minos, maximum) > 0) { + fail( + label, + `${platformMetadata.name} minimum OS ${formatVersion(minos)} exceeds the carrier contract ${formatVersion(maximum)}`, + ); + } + return { + platform, + platformName: platformMetadata.name, + minos, + machine: 'arm64', + cpuType, + cpuSubtype, + }; +} + +function parseMacho(buffer, label, contract) { + requireRange(buffer, 0, 4, label, 'Mach-O magic'); + const magic = buffer.readUInt32BE(0); + if (![0xcafebabe, 0xbebafeca, 0xcafebabf, 0xbfbafeca].includes(magic)) { + return [parseMachoSlice(buffer, 0, buffer.length, label, contract)]; + } + const littleEndian = magic === 0xbebafeca || magic === 0xbfbafeca; + const fat64 = magic === 0xcafebabf || magic === 0xbfbafeca; + const read32 = (offset) => + littleEndian ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); + const read64 = (offset) => + safeNumber( + littleEndian ? buffer.readBigUInt64LE(offset) : buffer.readBigUInt64BE(offset), + label, + 'fat Mach-O offset or size', + ); + requireRange(buffer, 0, 8, label, 'fat Mach-O header'); + const count = read32(4); + if (count === 0 || count > 64) fail(label, `fat Mach-O declares invalid slice count ${count}`); + const entrySize = fat64 ? 32 : 20; + requireRange(buffer, 8, count * entrySize, label, 'fat Mach-O architecture table'); + const tableEnd = 8 + count * entrySize; + const ranges = []; + const identities = new Set(); + const results = []; + for (let index = 0; index < count; index += 1) { + const entry = 8 + index * entrySize; + const cpuType = read32(entry); + if (cpuType !== contract.macho.cpuType) { + fail(label, `fat Mach-O slice ${index} cpu type 0x${cpuType.toString(16)} is not arm64`); + } + const cpuSubtype = read32(entry + 4); + if (cpuSubtype !== contract.macho.cpuSubtype) { + fail( + label, + `fat Mach-O slice ${index} arm64 cpu subtype 0x${cpuSubtype.toString(16)} is not generic ARM64_ALL`, + ); + } + const identity = `${cpuType}:${cpuSubtype}`; + if (identities.has(identity)) { + fail(label, `fat Mach-O slice ${index} duplicates architecture identity arm64/ARM64_ALL`); + } + identities.add(identity); + const offset = fat64 ? read64(entry + 8) : read32(entry + 8); + const size = fat64 ? read64(entry + 16) : read32(entry + 12); + const alignment = fat64 ? read32(entry + 24) : read32(entry + 16); + if (size === 0) fail(label, `fat Mach-O slice ${index} is empty`); + if (alignment > 31) + fail(label, `fat Mach-O slice ${index} has unsafe alignment exponent ${alignment}`); + if (offset < tableEnd) fail(label, `fat Mach-O slice ${index} overlaps its architecture table`); + if (offset % 2 ** alignment !== 0) + fail(label, `fat Mach-O slice ${index} offset is not aligned`); + requireRange(buffer, offset, size, label, `fat Mach-O slice ${index}`); + for (const range of ranges) { + if (offset < range.end && range.start < offset + size) { + fail(label, `fat Mach-O slice ${index} overlaps another slice`); + } + } + ranges.push({ start: offset, end: offset + size }); + const slice = parseMachoSlice(buffer, offset, size, `${label} [slice ${index}]`, contract); + if (slice.cpuType !== cpuType || slice.cpuSubtype !== cpuSubtype) { + fail( + label, + `fat Mach-O slice ${index} architecture table identity does not match its thin header`, + ); + } + results.push(slice); + } + return results; +} + +function scanRequiredElfVersions(buffer) { + const text = buffer.toString('latin1'); + const versions = []; + const pattern = /(?:^|(?<=\x00))(GLIBC(?:XX)?_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?)(?=\x00)/gu; + for (const match of text.matchAll(pattern)) { + versions.push({ + name: match[1], + family: match[1].startsWith('GLIBCXX_') ? 'GLIBCXX' : 'GLIBC', + version: [Number(match[2]), Number(match[3]), Number(match[4] ?? 0)], + }); + } + return versions; +} + +function validateElfTable(buffer, offset, entrySize, count, minimumSize, label, name) { + if (count === 0) return; + if (offset === 0) fail(label, `ELF ${name} count is nonzero but its offset is zero`); + if (entrySize < minimumSize) + fail(label, `ELF ${name} entry size ${entrySize} is below ${minimumSize}`); + if (count > 65_536) fail(label, `ELF ${name} count ${count} is unreasonable`); + requireRange(buffer, offset, entrySize * count, label, `ELF ${name}`); +} + +function alignFour(value) { + return (value + 3) & ~3; +} + +function androidApiNotes(buffer, sectionOffset, sectionEntrySize, sectionCount, label) { + const values = []; + for (let index = 0; index < sectionCount; index += 1) { + const section = sectionOffset + index * sectionEntrySize; + if (buffer.readUInt32LE(section + 4) !== ELF_SECTION_NOTE) continue; + const noteOffset = safeNumber( + buffer.readBigUInt64LE(section + 24), + label, + `ELF note section ${index} offset`, + ); + const noteSize = safeNumber( + buffer.readBigUInt64LE(section + 32), + label, + `ELF note section ${index} size`, + ); + requireRange(buffer, noteOffset, noteSize, label, `ELF note section ${index}`); + let cursor = noteOffset; + const end = noteOffset + noteSize; + while (cursor < end) { + if (end - cursor < 12) { + if (buffer.subarray(cursor, end).every((byte) => byte === 0)) break; + fail(label, `ELF note section ${index} has a truncated note header`); + } + const nameSize = buffer.readUInt32LE(cursor); + const descriptionSize = buffer.readUInt32LE(cursor + 4); + const type = buffer.readUInt32LE(cursor + 8); + if (nameSize === 0 || nameSize > 256 || descriptionSize > 1024 * 1024) { + fail(label, `ELF note section ${index} has unreasonable note sizes`); + } + const nameOffset = cursor + 12; + const descriptionOffset = nameOffset + alignFour(nameSize); + const next = descriptionOffset + alignFour(descriptionSize); + if (next > end) fail(label, `ELF note section ${index} contains a truncated note payload`); + const owner = buffer + .subarray(nameOffset, nameOffset + nameSize) + .toString('ascii') + .replace(/\x00+$/u, ''); + if (owner === 'Android' && type === 1) { + if (descriptionSize < 4) + fail(label, '.note.android.ident NT_VERSION description is truncated'); + values.push(buffer.readUInt32LE(descriptionOffset)); + } + cursor = next; + } + } + return values; +} + +function parseElf(buffer, label, contract) { + requireRange(buffer, 0, 64, label, 'ELF64 header'); + if (contract.elf.bits !== 64 || buffer[4] !== 2) { + fail(label, `ELF class ${buffer[4]} is not ELF${contract.elf.bits}`); + } + if (contract.elf.endianness !== 'little' || buffer[5] !== 1) { + fail(label, `ELF data encoding ${buffer[5]} is not ${contract.elf.endianness}-endian`); + } + if (buffer[6] !== 1) fail(label, `ELF identification version ${buffer[6]} is invalid`); + const elfType = buffer.readUInt16LE(16); + if (![ELF_TYPE_REL, ELF_TYPE_EXEC, ELF_TYPE_DYN].includes(elfType)) { + fail(label, `ELF type ${elfType} is not a relocatable object, executable, or shared library`); + } + const machine = buffer.readUInt16LE(18); + if (machine !== contract.elf.machine) { + fail(label, `ELF machine ${machine} does not match ${contract.architecture}`); + } + const headerSize = buffer.readUInt16LE(52); + if (headerSize < 64 || headerSize > buffer.length) + fail(label, `ELF header size ${headerSize} is invalid`); + const programOffset = safeNumber(buffer.readBigUInt64LE(32), label, 'ELF program-header offset'); + const sectionOffset = safeNumber(buffer.readBigUInt64LE(40), label, 'ELF section-header offset'); + const programEntrySize = buffer.readUInt16LE(54); + const programCount = buffer.readUInt16LE(56); + const sectionEntrySize = buffer.readUInt16LE(58); + const sectionCount = buffer.readUInt16LE(60); + const sectionNames = buffer.readUInt16LE(62); + if (programCount === 0xffff) fail(label, 'ELF extended program-header counts are not accepted'); + if (sectionCount === 0 && sectionOffset !== 0) + fail(label, 'ELF extended section-header counts are not accepted'); + if (sectionCount > 0 && sectionNames !== 0 && sectionNames >= sectionCount) { + fail(label, `ELF section-name table index ${sectionNames} is out of range`); + } + validateElfTable( + buffer, + programOffset, + programEntrySize, + programCount, + 56, + label, + 'program-header table', + ); + validateElfTable( + buffer, + sectionOffset, + sectionEntrySize, + sectionCount, + 64, + label, + 'section-header table', + ); + + const requiredVersions = scanRequiredElfVersions(buffer); + let androidApi = null; + if (Number.isSafeInteger(contract.elf.androidApiLevel)) { + const forbiddenFamilies = new Set(contract.elf.forbiddenRequiredVersionFamilies); + const forbidden = requiredVersions.find(({ family }) => forbiddenFamilies.has(family)); + if (forbidden !== undefined) { + fail(label, `Android ELF requires forbidden GNU desktop runtime version ${forbidden.name}`); + } + if (elfType === ELF_TYPE_EXEC || elfType === ELF_TYPE_DYN) { + const apiNotes = androidApiNotes( + buffer, + sectionOffset, + sectionEntrySize, + sectionCount, + label, + ); + if (apiNotes.length !== 1) { + fail( + label, + `Android ELF must contain exactly one .note.android.ident API record, found ${apiNotes.length}`, + ); + } + androidApi = apiNotes[0]; + if (androidApi !== contract.elf.androidApiLevel) { + fail( + label, + `Android ELF API level ${androidApi} does not match the release contract ${contract.elf.androidApiLevel}`, + ); + } + } + } else { + for (const required of requiredVersions) { + const ceiling = contract.elf.maximumRequiredVersions[required.family]; + if (ceiling === undefined) continue; + if (compareVersion(required.version, ceiling) > 0) { + fail( + label, + `${required.name} exceeds the ${required.family} compatibility ceiling ${formatVersion(ceiling)}`, + ); + } + } + } + return { + machine: contract.architecture, + androidApi, + requiredVersions: requiredVersions.map(({ name }) => name).sort(), + }; +} + +function parsePe(buffer, label, contract) { + requireRange(buffer, 0, 64, label, 'DOS header'); + if (buffer[0] !== 0x4d || buffer[1] !== 0x5a) fail(label, 'DOS signature is invalid'); + const peOffset = buffer.readUInt32LE(0x3c); + requireRange(buffer, peOffset, 24, label, 'PE signature and COFF header'); + if (!buffer.subarray(peOffset, peOffset + 4).equals(Buffer.from([0x50, 0x45, 0, 0]))) { + fail(label, 'PE signature is invalid'); + } + const coff = peOffset + 4; + const machine = buffer.readUInt16LE(coff); + if (machine !== contract.pe.machine) { + fail(label, `PE machine 0x${machine.toString(16)} is not ${contract.architecture}`); + } + const sectionCount = buffer.readUInt16LE(coff + 2); + if (sectionCount === 0 || sectionCount > 96) + fail(label, `PE section count ${sectionCount} is invalid`); + const optionalSize = buffer.readUInt16LE(coff + 16); + const optional = coff + 20; + requireRange(buffer, optional, optionalSize, label, 'PE optional header'); + if (optionalSize < 112) fail(label, `PE32+ optional header is only ${optionalSize} bytes`); + if (buffer.readUInt16LE(optional) !== contract.pe.optionalHeaderMagic) { + fail(label, 'PE optional header is not PE32+'); + } + const sizeOfHeaders = buffer.readUInt32LE(optional + 60); + if (sizeOfHeaders === 0 || sizeOfHeaders > buffer.length) + fail(label, `PE SizeOfHeaders ${sizeOfHeaders} is invalid`); + const directoryCount = buffer.readUInt32LE(optional + 108); + const availableDirectories = Math.floor((optionalSize - 112) / 8); + if (directoryCount > availableDirectories) { + fail( + label, + `PE optional header declares ${directoryCount} data directories but contains space for ${availableDirectories}`, + ); + } + const sectionTable = optional + optionalSize; + requireRange(buffer, sectionTable, sectionCount * 40, label, 'PE section table'); + const sections = []; + for (let index = 0; index < sectionCount; index += 1) { + const entry = sectionTable + index * 40; + const virtualSize = buffer.readUInt32LE(entry + 8); + const virtualAddress = buffer.readUInt32LE(entry + 12); + const rawSize = buffer.readUInt32LE(entry + 16); + const rawOffset = buffer.readUInt32LE(entry + 20); + if (rawSize > 0) + requireRange(buffer, rawOffset, rawSize, label, `PE section ${index} raw data`); + sections.push({ virtualSize, virtualAddress, rawSize, rawOffset }); + } + let imports; + try { + const portableExecutable = inspectPortableExecutable(buffer, label); + if (portableExecutable.machine !== contract.pe.machine) { + fail( + label, + `PE machine 0x${portableExecutable.machine.toString(16)} is not ${contract.architecture}`, + ); + } + imports = portableExecutable.imports; + } catch (error) { + if (error instanceof PlatformBinaryContractError) throw error; + fail(label, `PE dependency inspection failed: ${error.message}`); + } + const msvcRuntimeImports = imports.filter((name) => MSVC_RUNTIME_IMPORT.test(name)); + const undeclaredRuntime = msvcRuntimeImports.find( + (name) => !WINDOWS_VC_RUNTIME_DLL_SET.has(name.toLowerCase()), + ); + if (undeclaredRuntime !== undefined) { + fail(label, `release PE imports undeclared or debug VC runtime ${undeclaredRuntime}`); + } + return { + machine: 'x64', + imports, + msvcRuntimeImports, + }; +} + +export function inspectPlatformBinaryBuffer(input, { target, label = 'binary' }) { + const buffer = Buffer.isBuffer(input) ? input : Buffer.from(input); + const contract = contractFor(target, label); + const format = detectFormat(buffer); + if (format === null) fail(label, 'file does not contain a recognized Mach-O, ELF, or PE image'); + if (format === 'ar') { + if (!['macho', 'elf'].includes(contract.format)) { + fail(label, `static ar archive is not a valid ${target} release binary`); + } + const slices = parseArArchive(buffer, label, contract); + return { + format: contract.format, + archived: true, + slices, + platforms: + contract.format === 'macho' ? [...new Set(slices.map(({ platform }) => platform))] : [], + }; + } + if (format !== contract.format) { + fail( + label, + `${format.toUpperCase()} content does not match target ${target} (${contract.format.toUpperCase()})`, + ); + } + if (format === 'macho') { + const slices = parseMacho(buffer, label, contract); + return { format, slices, platforms: [...new Set(slices.map(({ platform }) => platform))] }; + } + if (format === 'elf') + return { format, slices: [parseElf(buffer, label, contract)], platforms: [] }; + return { format, slices: [parsePe(buffer, label, contract)], platforms: [] }; +} + +function finalizeInspection( + target, + inspected, + labels, + requiredApplePlatforms, + windowsVcRuntimeProfile, +) { + const contract = contractFor(target, 'platform-binary contract'); + if (inspected.length === 0) { + fail( + 'platform-binary contract', + `no ${contract.format.toUpperCase()} binaries were found for ${target}`, + ); + } + const platforms = new Set(inspected.flatMap(({ result }) => result.platforms)); + if (contract.apple !== undefined) { + if (requiredApplePlatforms !== undefined && !contract.apple.allowPlatformOverride) { + fail( + 'platform-binary contract', + `${contract.apple.carrier} does not allow a required-platform override`, + ); + } + const required = + requiredApplePlatforms ?? + contract.apple.requiredPlatforms.map((key) => contract.apple.platforms[key].id); + const missing = required.filter((platform) => !platforms.has(platform)); + if (missing.length > 0) { + fail( + 'platform-binary contract', + `${contract.apple.carrier} is missing ${missing.map((platform) => APPLE_PLATFORM_BY_ID.get(platform).name).join(' and ')} Mach-O content`, + ); + } + } + if (contract.windowsVcRuntime !== undefined) { + const profile = windowsVcRuntimeProfile ?? 'direct'; + if (!contract.windowsVcRuntime.profiles.includes(profile)) { + fail( + 'platform-binary contract', + `unknown Windows VC runtime profile ${JSON.stringify(profile)}; expected ${contract.windowsVcRuntime.profiles.join(' or ')}`, + ); + } + const bundledRuntimeNames = labels + .map((name) => path.basename(name)) + .filter((name) => MSVC_RUNTIME_IMPORT.test(name)); + const undeclaredPayload = bundledRuntimeNames.find( + (name) => !WINDOWS_VC_RUNTIME_DLL_SET.has(name.toLowerCase()), + ); + if (undeclaredPayload !== undefined) { + fail( + 'platform-binary contract', + `Windows carrier bundles undeclared or debug VC runtime ${undeclaredPayload}`, + ); + } + const bundled = new Set(bundledRuntimeNames.map((name) => name.toLowerCase())); + const required = new Set(); + for (const { result, label } of inspected) { + for (const slice of result.slices) { + for (const imported of slice.msvcRuntimeImports ?? []) { + const normalized = imported.toLowerCase(); + required.add(normalized); + if (!bundled.has(normalized)) { + fail( + label, + `imports MSVC runtime ${imported}, but the exact DLL is not bundled in the same carrier closure`, + ); + } + } + } + } + const expected = profile === 'provider' ? WINDOWS_VC_RUNTIME_DLL_SET : required; + const missing = [...expected].filter((name) => !bundled.has(name)); + if (missing.length > 0) { + fail( + 'platform-binary contract', + `Windows ${profile} VC runtime profile is missing ${missing.sort().join(', ')}`, + ); + } + const extra = [...bundled].filter((name) => !expected.has(name)); + if (extra.length > 0) { + fail( + 'platform-binary contract', + `Windows carrier bundles unneeded VC runtime closure member${extra.length === 1 ? '' : 's'} ${extra.sort().join(', ')}`, + ); + } + } + return { + target, + binaries: inspected.length, + slices: inspected.reduce((sum, { result }) => sum + result.slices.length, 0), + platforms: [...platforms].sort((left, right) => left - right), + files: labels, + }; +} + +export function inspectPlatformBinaryEntries( + entries, + { + target, + rootLabel = 'staged release tree', + requiredApplePlatforms, + requireWindowsRuntimeImportLibrary = false, + windowsVcRuntimeProfile, + }, +) { + contractFor(target, rootLabel); + if (requireWindowsRuntimeImportLibrary && target !== 'windows-x64-msvc') { + fail(rootLabel, 'the Windows runtime import library can only be required for windows-x64-msvc'); + } + const inspected = []; + const labels = []; + let windowsRuntimeImportLibrarySeen = false; + for (const entry of entries) { + if (entry === null || entry === undefined) continue; + const name = String(entry.name ?? ''); + if (entry.isSymbolicLink === true) { + fail(name || rootLabel, 'staged release tree contains a symbolic link'); + } + if (entry.isDirectory === true) continue; + if (entry.isFile === false) { + fail(name || rootLabel, 'staged release tree contains a non-regular special entry'); + } + const data = typeof entry.data === 'function' ? entry.data() : entry.data; + if (data === undefined) fail(name || rootLabel, 'binary entry has no readable data'); + const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data); + const format = detectFormat(buffer); + const windowsRuntimeImportLibrary = name === WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH; + const windowsExtensionLegalTextLibrary = + target === 'windows-x64-msvc' && isWindowsExtensionLegalTextLibrary(name, buffer, format); + const msvcLibraryPath = + target === 'windows-x64-msvc' && + MSVC_LIBRARY_PATH.test(name) && + !windowsExtensionLegalTextLibrary; + const expectedPath = + EXPECTED_BINARY_PATH.test(name) || STATIC_ARCHIVE_PATH.test(name) || msvcLibraryPath; + if (format === null && !expectedPath) continue; + if (format === null) + fail(name || rootLabel, 'expected native binary is malformed or truncated'); + const label = name ? `${rootLabel}/${name}` : rootLabel; + if (!windowsRuntimeImportLibrary && msvcLibraryPath) { + fail( + label, + `only the exact ${WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH} runtime import library is permitted`, + ); + } + if (target === 'windows-x64-msvc' && STATIC_ARCHIVE_PATH.test(name)) { + fail(label, 'static .a archives are not permitted in a Windows release carrier'); + } + let result; + if (windowsRuntimeImportLibrary) { + if (!requireWindowsRuntimeImportLibrary) { + fail( + label, + `MSVC import library is only permitted when the exact ${WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH} runtime contract is required`, + ); + } + if (windowsRuntimeImportLibrarySeen) { + fail(label, `staged release tree repeats ${WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH}`); + } + if (format !== 'ar') + fail(label, 'required MSVC import library is not an ar-format COFF archive'); + windowsRuntimeImportLibrarySeen = true; + result = parseWindowsRuntimeImportLibrary(buffer, label, contractFor(target, label)); + } else { + result = inspectPlatformBinaryBuffer(buffer, { target, label }); + } + inspected.push({ result, label }); + labels.push(name); + } + if (requireWindowsRuntimeImportLibrary && !windowsRuntimeImportLibrarySeen) { + fail( + `${rootLabel}/${WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH}`, + 'required Windows runtime import library is missing', + ); + } + return finalizeInspection( + target, + inspected, + labels.sort(), + requiredApplePlatforms, + windowsVcRuntimeProfile, + ); +} + +async function walkTree(root, relative = '') { + const directory = path.join(root, relative); + const names = await readdir(directory); + names.sort(); + const entries = []; + for (const name of names) { + const childRelative = relative ? path.join(relative, name) : name; + const child = path.join(root, childRelative); + const stat = await lstat(child); + if (stat.isSymbolicLink()) { + fail(child, 'staged release tree contains a symbolic link'); + } else if (stat.isDirectory()) { + entries.push(...(await walkTree(root, childRelative))); + } else if (stat.isFile()) { + entries.push({ + name: childRelative.split(path.sep).join('/'), + data: await readFile(child), + isFile: true, + }); + } else { + fail(child, 'staged release tree contains a non-regular special entry'); + } + } + return entries; +} + +export async function inspectPlatformBinaryTree( + root, + { + target, + requiredApplePlatforms, + requireWindowsRuntimeImportLibrary = false, + windowsVcRuntimeProfile, + }, +) { + const absolute = path.resolve(root); + const stat = await lstat(absolute).catch(() => null); + if (stat === null || !stat.isDirectory()) { + fail(absolute, 'staged release tree is missing or is not a directory'); + } + return inspectPlatformBinaryEntries(await walkTree(absolute), { + target, + rootLabel: absolute, + requiredApplePlatforms, + requireWindowsRuntimeImportLibrary, + windowsVcRuntimeProfile, + }); +} + +function usage() { + return 'usage: tools/packaging/platform-binary-contract.mts --target TARGET --root STAGED_RELEASE_TREE [--required-apple-platforms macos,ios,ios-simulator] [--require-windows-runtime-import-library] [--windows-vc-runtime-profile direct|provider]\n'; +} + +async function main(argv) { + let target = ''; + let root = ''; + let requiredApplePlatforms; + let requireWindowsRuntimeImportLibrary = false; + let windowsVcRuntimeProfile; + for (let index = 0; index < argv.length; index += 1) { + if (argv[index] === '--target') { + target = argv[++index] ?? ''; + } else if (argv[index] === '--root') { + root = argv[++index] ?? ''; + } else if (argv[index] === '--required-apple-platforms') { + const raw = argv[++index] ?? ''; + const names = raw.split(',').filter(Boolean); + if (names.length === 0 || new Set(names).size !== names.length) { + fail( + 'platform-binary-contract.mts', + '--required-apple-platforms must be a nonempty unique CSV', + ); + } + requiredApplePlatforms = names.map((name) => { + const platform = APPLE_PLATFORM_BY_CLI_NAME.get(name); + if (platform === undefined) { + fail('platform-binary-contract.mts', `unknown Apple platform ${JSON.stringify(name)}`); + } + return platform.id; + }); + } else if (argv[index] === '--require-windows-runtime-import-library') { + requireWindowsRuntimeImportLibrary = true; + } else if (argv[index] === '--windows-vc-runtime-profile') { + windowsVcRuntimeProfile = argv[++index] ?? ''; + if (!WINDOWS_VC_RUNTIME_PROFILES.includes(windowsVcRuntimeProfile)) { + fail( + 'platform-binary-contract.mts', + `--windows-vc-runtime-profile must be ${WINDOWS_VC_RUNTIME_PROFILES.join(' or ')}`, + ); + } + } else if (argv[index] === '--help' || argv[index] === '-h') { + process.stdout.write(usage()); + return; + } else { + fail('platform-binary-contract.mts', `unknown argument ${JSON.stringify(argv[index])}`); + } + } + if (!target || !root) { + process.stderr.write(usage()); + process.exitCode = 2; + return; + } + const result = await inspectPlatformBinaryTree(root, { + target, + requiredApplePlatforms, + requireWindowsRuntimeImportLibrary, + windowsVcRuntimeProfile, + }); + console.log( + `platform binary contract passed: target=${result.target} binaries=${result.binaries} slices=${result.slices}`, + ); +} + +if (import.meta.main) { + try { + await main(Bun.argv.slice(2)); + } catch (error) { + console.error(`platform-binary-contract.mts: ${error.message}`); + process.exit(1); + } +} diff --git a/tools/packaging/platform-binary-contract.test.mts b/tools/packaging/platform-binary-contract.test.mts new file mode 100644 index 000000000..0ea9dea2d --- /dev/null +++ b/tools/packaging/platform-binary-contract.test.mts @@ -0,0 +1,751 @@ +import { afterEach, describe, expect, test } from 'bun:test'; +import { mkdtemp, mkdir, rm, symlink, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; + +import { + inspectPlatformBinaryBuffer, + inspectPlatformBinaryEntries, + inspectPlatformBinaryTree, +} from './platform-binary-contract.mts'; +import { + OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS, + windowsImportLibraryFixture, +} from './testdata/release-fixture-utils.mts'; + +const temporaryRoots = []; + +afterEach(async () => { + await Promise.all( + temporaryRoots.splice(0).map((root) => rm(root, { recursive: true, force: true })), + ); +}); + +function packedVersion(major, minor = 0, patch = 0) { + return (major << 16) | (minor << 8) | patch; +} + +function macho({ + platform = 1, + minos = [11, 0, 0], + cpu = 0x0100000c, + cpuSubtype = 0, + commandSize = 24, + commands = 1, +} = {}) { + const buffer = Buffer.alloc(32 + commandSize); + buffer.writeUInt32LE(0xfeedfacf, 0); + buffer.writeUInt32LE(cpu, 4); + buffer.writeUInt32LE(cpuSubtype, 8); + buffer.writeUInt32LE(6, 12); + buffer.writeUInt32LE(commands, 16); + buffer.writeUInt32LE(commandSize, 20); + buffer.writeUInt32LE(0, 24); + buffer.writeUInt32LE(0, 28); + if (commands > 0 && commandSize >= 8) { + buffer.writeUInt32LE(0x32, 32); + buffer.writeUInt32LE(commandSize, 36); + if (commandSize >= 24) { + buffer.writeUInt32LE(platform, 40); + buffer.writeUInt32LE(packedVersion(...minos), 44); + buffer.writeUInt32LE(packedVersion(...minos), 48); + buffer.writeUInt32LE(0, 52); + } + } + return buffer; +} + +function fatMacho(slices) { + const tableSize = 8 + slices.length * 20; + let cursor = tableSize; + const offsets = []; + for (const slice of slices) { + while (cursor % 4 !== 0) cursor += 1; + offsets.push(cursor); + cursor += slice.length; + } + const buffer = Buffer.alloc(cursor); + buffer.writeUInt32BE(0xcafebabe, 0); + buffer.writeUInt32BE(slices.length, 4); + for (let index = 0; index < slices.length; index += 1) { + const entry = 8 + index * 20; + buffer.writeUInt32BE(0x0100000c, entry); + buffer.writeUInt32BE(slices[index].readUInt32LE(8), entry + 4); + buffer.writeUInt32BE(offsets[index], entry + 8); + buffer.writeUInt32BE(slices[index].length, entry + 12); + buffer.writeUInt32BE(2, entry + 16); + slices[index].copy(buffer, offsets[index]); + } + return buffer; +} + +function ar(members) { + const chunks = [Buffer.from('!\n', 'ascii')]; + for (const [name, data] of members) { + const encodedName = `${name}/`.padEnd(16, ' '); + const header = Buffer.from( + `${encodedName}${'0'.padEnd(12, ' ')}${'0'.padEnd(6, ' ')}${'0'.padEnd(6, ' ')}${'100644'.padEnd(8, ' ')}${String(data.length).padEnd(10, ' ')}\`\n`, + 'ascii', + ); + chunks.push(header, data); + if (data.length % 2 !== 0) chunks.push(Buffer.from('\n', 'ascii')); + } + return Buffer.concat(chunks); +} + +function elf({ + machine = 62, + bits = 64, + littleEndian = true, + versions = [], + truncateSectionTable = false, + androidApi = null, + type = 3, +} = {}) { + const versionBytes = Buffer.from(`\0${versions.join('\0')}\0`, 'ascii'); + const note = androidApi === null ? null : Buffer.alloc(24); + if (note !== null) { + note.writeUInt32LE(8, 0); + note.writeUInt32LE(4, 4); + note.writeUInt32LE(1, 8); + note.write('Android\0', 12, 'ascii'); + note.writeUInt32LE(androidApi, 20); + } + const noteOffset = align(64 + versionBytes.length, 4); + const sectionOffset = note === null ? 0 : align(noteOffset + note.length, 8); + const buffer = Buffer.alloc(note === null ? 64 + versionBytes.length : sectionOffset + 128); + Buffer.from([0x7f, 0x45, 0x4c, 0x46]).copy(buffer, 0); + buffer[4] = bits === 64 ? 2 : 1; + buffer[5] = littleEndian ? 1 : 2; + buffer[6] = 1; + buffer.writeUInt16LE(type, 16); + buffer.writeUInt16LE(machine, 18); + buffer.writeUInt32LE(1, 20); + buffer.writeUInt16LE(64, 52); + if (truncateSectionTable) { + buffer.writeBigUInt64LE(64n, 40); + buffer.writeUInt16LE(64, 58); + buffer.writeUInt16LE(2, 60); + } + versionBytes.copy(buffer, 64); + if (note !== null) { + note.copy(buffer, noteOffset); + buffer.writeBigUInt64LE(BigInt(sectionOffset), 40); + buffer.writeUInt16LE(64, 58); + buffer.writeUInt16LE(2, 60); + const noteSection = sectionOffset + 64; + buffer.writeUInt32LE(7, noteSection + 4); + buffer.writeBigUInt64LE(BigInt(noteOffset), noteSection + 24); + buffer.writeBigUInt64LE(BigInt(note.length), noteSection + 32); + buffer.writeBigUInt64LE(4n, noteSection + 48); + } + return buffer; +} + +function align(value, alignment) { + return Math.ceil(value / alignment) * alignment; +} + +function pe({ + machine = 0x8664, + optionalMagic = 0x20b, + imports = ['KERNEL32.dll'], + delayImports = [], +} = {}) { + const peOffset = 0x80; + const optionalSize = 240; + const sectionTable = peOffset + 24 + optionalSize; + const rawOffset = 0x200; + const rawSize = 0x400; + const virtualAddress = 0x1000; + const buffer = Buffer.alloc(rawOffset + rawSize); + buffer.write('MZ', 0, 'ascii'); + buffer.writeUInt32LE(peOffset, 0x3c); + buffer.write('PE\0\0', peOffset, 'ascii'); + const coff = peOffset + 4; + buffer.writeUInt16LE(machine, coff); + buffer.writeUInt16LE(1, coff + 2); + buffer.writeUInt16LE(optionalSize, coff + 16); + buffer.writeUInt16LE(0x2022, coff + 18); + const optional = coff + 20; + buffer.writeUInt16LE(optionalMagic, optional); + buffer.writeBigUInt64LE(0x140000000n, optional + 24); + buffer.writeUInt32LE(rawOffset, optional + 60); + buffer.writeUInt32LE(16, optional + 108); + const descriptorBytes = (imports.length + 1) * 20; + buffer.writeUInt32LE(virtualAddress, optional + 120); + buffer.writeUInt32LE(descriptorBytes, optional + 124); + if (delayImports.length > 0) { + const delayDescriptorOffset = rawOffset + 0x100; + buffer.writeUInt32LE(virtualAddress + (delayDescriptorOffset - rawOffset), optional + 216); + buffer.writeUInt32LE((delayImports.length + 1) * 32, optional + 220); + } + buffer.write('.rdata\0\0', sectionTable, 'ascii'); + buffer.writeUInt32LE(rawSize, sectionTable + 8); + buffer.writeUInt32LE(virtualAddress, sectionTable + 12); + buffer.writeUInt32LE(rawSize, sectionTable + 16); + buffer.writeUInt32LE(rawOffset, sectionTable + 20); + let nameOffset = rawOffset + 0x200; + for (let index = 0; index < imports.length; index += 1) { + const descriptor = rawOffset + index * 20; + buffer.writeUInt32LE(virtualAddress + (nameOffset - rawOffset), descriptor + 12); + buffer.write(`${imports[index]}\0`, nameOffset, 'ascii'); + nameOffset += Buffer.byteLength(imports[index]) + 1; + } + for (let index = 0; index < delayImports.length; index += 1) { + const descriptor = rawOffset + 0x100 + index * 32; + buffer.writeUInt32LE(1, descriptor); + buffer.writeUInt32LE(virtualAddress + (nameOffset - rawOffset), descriptor + 4); + buffer.write(`${delayImports[index]}\0`, nameOffset, 'ascii'); + nameOffset += Buffer.byteLength(delayImports[index]) + 1; + } + return buffer; +} + +function entry(name, data) { + return { name, data, isFile: true }; +} + +describe('Mach-O platform compatibility', () => { + test('accepts a thin arm64 direct macOS binary at the 11.0 floor', () => { + const result = inspectPlatformBinaryBuffer(macho(), { + target: 'macos-arm64', + label: 'lib.dylib', + }); + expect(result.slices[0].platformName).toBe('macOS'); + expect(result.slices[0].minos).toEqual([11, 0, 0]); + }); + + test('rejects the observed accidental macOS 26.0 floor', () => { + expect(() => + inspectPlatformBinaryBuffer(macho({ minos: [26, 0, 0] }), { + target: 'macos-arm64', + label: 'lib.dylib', + }), + ).toThrow(/minimum OS 26\.0 exceeds.*11\.0/u); + }); + + test('rejects x64, missing build metadata, and truncated load commands', () => { + expect(() => + inspectPlatformBinaryBuffer(macho({ cpu: 0x01000007 }), { + target: 'macos-arm64', + label: 'wrong.dylib', + }), + ).toThrow(/not arm64/u); + expect(() => + inspectPlatformBinaryBuffer(macho({ cpuSubtype: 2 }), { + target: 'macos-arm64', + label: 'arm64e.dylib', + }), + ).toThrow(/not generic ARM64_ALL.*arm64e-only/u); + expect(() => + inspectPlatformBinaryBuffer(macho({ commands: 0, commandSize: 0 }), { + target: 'macos-arm64', + label: 'missing.dylib', + }), + ).toThrow(/exactly one LC_BUILD_VERSION/u); + expect(() => + inspectPlatformBinaryBuffer(macho({ commandSize: 12 }), { + target: 'macos-arm64', + label: 'short.dylib', + }), + ).toThrow(/LC_BUILD_VERSION is truncated/u); + }); + + test('bounds-checks fat slices and validates every embedded slice', () => { + const valid = fatMacho([macho()]); + expect( + inspectPlatformBinaryBuffer(valid, { target: 'macos-arm64', label: 'fat' }).slices, + ).toHaveLength(1); + const outside = Buffer.from(valid); + outside.writeUInt32BE(outside.length - 4, 16); + expect(() => + inspectPlatformBinaryBuffer(outside, { target: 'macos-arm64', label: 'fat' }), + ).toThrow(/outside the .*file/u); + const highFloor = fatMacho([macho({ minos: [14, 0, 0] })]); + expect(() => + inspectPlatformBinaryBuffer(highFloor, { target: 'macos-arm64', label: 'fat' }), + ).toThrow(/exceeds.*11\.0/u); + expect(() => + inspectPlatformBinaryBuffer(fatMacho([macho(), macho()]), { + target: 'macos-arm64', + label: 'duplicate-fat', + }), + ).toThrow(/duplicates architecture identity arm64\/ARM64_ALL/u); + }); + + test('requires iOS device and simulator and permits macOS only through 14.0', () => { + const entries = [ + entry('device/lib', macho({ platform: 2, minos: [17, 0, 0] })), + entry('simulator/lib', macho({ platform: 7, minos: [17, 0, 0] })), + entry('macos/lib', macho({ platform: 1, minos: [14, 0, 0] })), + ]; + expect(inspectPlatformBinaryEntries(entries, { target: 'ios-xcframework' }).platforms).toEqual([ + 1, 2, 7, + ]); + expect(() => + inspectPlatformBinaryEntries(entries.slice(0, 1), { target: 'ios-xcframework' }), + ).toThrow(/missing macOS and iOS Simulator/u); + expect(() => + inspectPlatformBinaryEntries( + [...entries.slice(0, 2), entry('macos/lib', macho({ platform: 1, minos: [14, 1, 0] }))], + { target: 'ios-xcframework' }, + ), + ).toThrow(/macOS minimum OS 14\.1 exceeds.*14\.0/u); + }); + + test('inspects Mach-O object members in static XCFramework archives', () => { + const entries = [ + entry('macos/libextension.a', ar([['macos.o', macho({ platform: 1, minos: [11, 0, 0] })]])), + entry('device/libextension.a', ar([['device.o', macho({ platform: 2, minos: [17, 0, 0] })]])), + entry('simulator/libextension.a', ar([['sim.o', macho({ platform: 7, minos: [17, 0, 0] })]])), + ]; + expect( + inspectPlatformBinaryEntries(entries, { + target: 'ios-xcframework', + requiredApplePlatforms: [1, 2, 7], + }).slices, + ).toBe(3); + const malformed = Buffer.from(entries[1].data); + malformed[8 + 58] = 0; + expect(() => + inspectPlatformBinaryEntries( + [entries[0], entry('device/libextension.a', malformed), entries[2]], + { + target: 'ios-xcframework', + requiredApplePlatforms: [1, 2, 7], + }, + ), + ).toThrow(/invalid header trailer/u); + expect(() => + inspectPlatformBinaryEntries( + [ + entries[0], + entry('device/libextension.a', ar([['readme', Buffer.from('not an object')]])), + entries[2], + ], + { target: 'ios-xcframework', requiredApplePlatforms: [1, 2, 7] }, + ), + ).toThrow(/not a MACHO object/u); + expect(() => + inspectPlatformBinaryEntries(entries.slice(1), { + target: 'ios-xcframework', + requiredApplePlatforms: [1, 2, 7], + }), + ).toThrow(/missing macOS/u); + }); +}); + +describe('ELF platform and GNU symbol-version compatibility', () => { + test('accepts the Linux x64 and arm64 ceilings', () => { + const x64 = inspectPlatformBinaryBuffer(elf({ versions: ['GLIBC_2.38', 'GLIBCXX_3.4.30'] }), { + target: 'linux-x64-gnu', + label: 'postgres', + }); + expect(x64.slices[0].requiredVersions).toEqual(['GLIBCXX_3.4.30', 'GLIBC_2.38']); + expect(() => + inspectPlatformBinaryBuffer(elf({ machine: 183, versions: ['GLIBC_2.17'] }), { + target: 'linux-arm64-gnu', + label: 'postgres', + }), + ).not.toThrow(); + }); + + test('rejects GLIBC and GLIBCXX requirements above the contract', () => { + expect(() => + inspectPlatformBinaryBuffer(elf({ versions: ['GLIBC_2.39'] }), { + target: 'linux-x64-gnu', + label: 'new-glibc.so', + }), + ).toThrow(/GLIBC_2\.39 exceeds.*2\.38/u); + expect(() => + inspectPlatformBinaryBuffer(elf({ versions: ['GLIBCXX_3.4.31'] }), { + target: 'linux-x64-gnu', + label: 'new-libstdcxx.so', + }), + ).toThrow(/GLIBCXX_3\.4\.31 exceeds.*3\.4\.30/u); + }); + + test('rejects wrong architecture, class, byte order, and truncated tables', () => { + expect(() => + inspectPlatformBinaryBuffer(elf({ machine: 183 }), { + target: 'linux-x64-gnu', + label: 'wrong.so', + }), + ).toThrow(/does not match x64/u); + expect(() => + inspectPlatformBinaryBuffer(elf({ bits: 32 }), { target: 'linux-x64-gnu', label: '32.so' }), + ).toThrow(/not ELF64/u); + expect(() => + inspectPlatformBinaryBuffer(elf({ littleEndian: false }), { + target: 'linux-x64-gnu', + label: 'be.so', + }), + ).toThrow(/not little-endian/u); + expect(() => + inspectPlatformBinaryBuffer(elf({ truncateSectionTable: true }), { + target: 'linux-x64-gnu', + label: 'truncated.so', + }), + ).toThrow(/section-header table.*outside/u); + }); + + test('accepts Android without GNU desktop versions and rejects GLIBC leakage', () => { + expect(() => + inspectPlatformBinaryBuffer(elf({ machine: 183, androidApi: 24 }), { + target: 'android-arm64-v8a', + label: 'liboliphaunt.so', + }), + ).not.toThrow(); + expect(() => + inspectPlatformBinaryBuffer(elf({ machine: 183, versions: ['GLIBC_2.17'], androidApi: 24 }), { + target: 'android-arm64-v8a', + label: 'host-leak.so', + }), + ).toThrow(/Android ELF requires forbidden.*GLIBC_2\.17/u); + expect(() => + inspectPlatformBinaryBuffer(elf({ machine: 183 }), { + target: 'android-arm64-v8a', + label: 'missing-note.so', + }), + ).toThrow(/exactly one \.note\.android\.ident API record/u); + expect(() => + inspectPlatformBinaryBuffer(elf({ machine: 183, androidApi: 26 }), { + target: 'android-arm64-v8a', + label: 'wrong-api.so', + }), + ).toThrow(/API level 26 does not match.*24/u); + }); +}); + +describe('PE32+ architecture and self-contained runtime imports', () => { + test('accepts x64 PE32+ system imports', () => { + const result = inspectPlatformBinaryBuffer(pe({ imports: ['node.exe', 'KERNEL32.dll'] }), { + target: 'windows-x64-msvc', + label: 'oliphaunt_node.node', + }); + expect(result.slices[0].imports).toEqual(['KERNEL32.dll', 'node.exe']); + }); + + test('requires app-local production MSVC runtime closure and rejects debug CRT', () => { + const main = pe({ imports: ['VCRUNTIME140.dll'], delayImports: ['MSVCP140.dll'] }); + expect(() => + inspectPlatformBinaryEntries([entry('bin/oliphaunt.dll', main)], { + target: 'windows-x64-msvc', + }), + ).toThrow(/MSVCP140\.dll.*not bundled/u); + expect(() => + inspectPlatformBinaryEntries( + [ + entry('bin/oliphaunt.dll', main), + entry('bin/VCRUNTIME140.dll', pe()), + entry('bin/MSVCP140.dll', pe({ imports: ['VCRUNTIME140.dll'] })), + ], + { target: 'windows-x64-msvc' }, + ), + ).not.toThrow(); + expect(() => + inspectPlatformBinaryBuffer(pe({ imports: ['VCRUNTIME140D.dll'] }), { + target: 'windows-x64-msvc', + label: 'debug.exe', + }), + ).toThrow(/undeclared or debug VC runtime/u); + expect(() => + inspectPlatformBinaryBuffer(pe({ imports: ['CONCRT140.dll'] }), { + target: 'windows-x64-msvc', + label: 'undeclared.exe', + }), + ).toThrow(/undeclared or debug VC runtime CONCRT140\.dll/u); + expect(() => + inspectPlatformBinaryEntries( + [entry('bin/oliphaunt.dll', pe()), entry('bin/vcruntime140.dll', pe())], + { target: 'windows-x64-msvc' }, + ), + ).toThrow(/unneeded VC runtime closure member vcruntime140\.dll/u); + expect(() => + inspectPlatformBinaryEntries( + [ + entry('bin/oliphaunt.dll', pe()), + entry('bin/msvcp140.dll', pe()), + entry('bin/vcruntime140.dll', pe()), + entry('bin/vcruntime140_1.dll', pe()), + ], + { target: 'windows-x64-msvc', windowsVcRuntimeProfile: 'provider' }, + ), + ).not.toThrow(); + expect(() => + inspectPlatformBinaryEntries( + [entry('bin/oliphaunt.dll', pe()), entry('bin/vcruntime140.dll', pe())], + { target: 'windows-x64-msvc', windowsVcRuntimeProfile: 'provider' }, + ), + ).toThrow(/provider VC runtime profile is missing msvcp140\.dll, vcruntime140_1\.dll/u); + }); + + test('rejects x86, PE32, malformed import descriptors, and truncated files', () => { + expect(() => + inspectPlatformBinaryBuffer(pe({ machine: 0x14c }), { + target: 'windows-x64-msvc', + label: 'x86.exe', + }), + ).toThrow(/not x64/u); + expect(() => + inspectPlatformBinaryBuffer(pe({ optionalMagic: 0x10b }), { + target: 'windows-x64-msvc', + label: 'pe32.exe', + }), + ).toThrow(/not PE32\+/u); + const unterminated = pe({ imports: ['KERNEL32.dll'] }); + const optional = 0x80 + 24; + unterminated.writeUInt32LE(20, optional + 124); + expect(() => + inspectPlatformBinaryBuffer(unterminated, { target: 'windows-x64-msvc', label: 'bad.exe' }), + ).toThrow(/unterminated/u); + expect(() => + inspectPlatformBinaryBuffer(Buffer.from('MZ'), { + target: 'windows-x64-msvc', + label: 'short.exe', + }), + ).toThrow(/DOS header.*outside/u); + }); + + test('accepts only the required lib/oliphaunt.lib import-library identity behind an explicit runtime opt-in', async () => { + const importLibrary = windowsImportLibraryFixture(); + const runtimeEntries = [ + entry('bin/oliphaunt.dll', pe()), + entry('lib/oliphaunt.lib', importLibrary), + ]; + const result = inspectPlatformBinaryEntries(runtimeEntries, { + target: 'windows-x64-msvc', + requireWindowsRuntimeImportLibrary: true, + }); + expect(result.files).toEqual(['bin/oliphaunt.dll', 'lib/oliphaunt.lib']); + expect(result.binaries).toBe(2); + expect(result.slices).toBe(2 + OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS.length); + + expect(() => + inspectPlatformBinaryEntries(runtimeEntries, { target: 'windows-x64-msvc' }), + ).toThrow(/only permitted when the exact lib\/oliphaunt\.lib runtime contract is required/u); + expect(() => + inspectPlatformBinaryEntries( + [entry('bin/oliphaunt.dll', pe()), entry('lib/renamed.lib', importLibrary)], + { target: 'windows-x64-msvc', requireWindowsRuntimeImportLibrary: true }, + ), + ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); + expect(() => + inspectPlatformBinaryEntries([entry('bin/oliphaunt.dll', pe())], { + target: 'windows-x64-msvc', + requireWindowsRuntimeImportLibrary: true, + }), + ).toThrow(/lib\/oliphaunt\.lib.*required Windows runtime import library is missing/u); + expect(() => + inspectPlatformBinaryEntries([...runtimeEntries, entry('lib/oliphaunt.lib', importLibrary)], { + target: 'windows-x64-msvc', + requireWindowsRuntimeImportLibrary: true, + }), + ).toThrow(/repeats lib\/oliphaunt\.lib/u); + }); + + test('keeps PostGIS COPYING.LIB legal text out of Windows binary discovery without admitting stray libraries', () => { + const legalText = Buffer.from( + 'GNU LIBRARY GENERAL PUBLIC LICENSE\n\fTERMS AND CONDITIONS\n', + 'utf8', + ); + const entries = [ + entry('bin/oliphaunt.dll', pe()), + entry('files/lib/postgresql/postgis-3.dll', pe()), + entry('files/lib/modules/postgis-3.dll', pe()), + entry('lib/oliphaunt.lib', windowsImportLibraryFixture()), + entry('files/share/licenses/libcharset/COPYING.LIB', legalText), + entry('files/share/licenses/libiconv/COPYING.LIB', legalText), + ]; + const result = inspectPlatformBinaryEntries(entries, { + target: 'windows-x64-msvc', + requireWindowsRuntimeImportLibrary: true, + }); + expect(result.files).toEqual([ + 'bin/oliphaunt.dll', + 'files/lib/modules/postgis-3.dll', + 'files/lib/postgresql/postgis-3.dll', + 'lib/oliphaunt.lib', + ]); + expect(result.binaries).toBe(4); + + expect(() => + inspectPlatformBinaryEntries( + [...entries, entry('files/lib/arbitrary.lib', windowsImportLibraryFixture())], + { target: 'windows-x64-msvc', requireWindowsRuntimeImportLibrary: true }, + ), + ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); + expect(() => + inspectPlatformBinaryEntries( + [...entries, entry('files/lib/malformed.lib', Buffer.from('not an import library\n'))], + { target: 'windows-x64-msvc', requireWindowsRuntimeImportLibrary: true }, + ), + ).toThrow(/files\/lib\/malformed\.lib.*expected native binary is malformed or truncated/u); + expect(() => + inspectPlatformBinaryEntries( + [...entries, entry('files/share/uncontracted/COPYING.LIB', legalText)], + { target: 'windows-x64-msvc', requireWindowsRuntimeImportLibrary: true }, + ), + ).toThrow( + /files\/share\/uncontracted\/COPYING\.LIB.*expected native binary is malformed or truncated/u, + ); + expect(() => + inspectPlatformBinaryEntries( + entries.map((candidate) => + candidate.name === 'files/share/licenses/libcharset/COPYING.LIB' + ? entry(candidate.name, windowsImportLibraryFixture()) + : candidate, + ), + { target: 'windows-x64-msvc', requireWindowsRuntimeImportLibrary: true }, + ), + ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); + expect(() => + inspectPlatformBinaryEntries( + entries.map((candidate) => + candidate.name === 'files/share/licenses/libcharset/COPYING.LIB' + ? entry(candidate.name, Buffer.from([0x47, 0x50, 0x4c, 0x00, 0xff])) + : candidate, + ), + { target: 'windows-x64-msvc', requireWindowsRuntimeImportLibrary: true }, + ), + ).toThrow(/COPYING\.LIB.*expected native binary is malformed or truncated/u); + }); + + test('rejects malformed, wrong-machine, wrong-DLL, and arbitrary Windows libraries', () => { + const inspectImportLibrary = (data) => + inspectPlatformBinaryEntries( + [entry('bin/oliphaunt.dll', pe()), entry('lib/oliphaunt.lib', data)], + { target: 'windows-x64-msvc', requireWindowsRuntimeImportLibrary: true }, + ); + + expect(() => + inspectImportLibrary(windowsImportLibraryFixture({ objectMachine: 0x14c })), + ).toThrow(/COFF object machine 0x14c is not x64/u); + expect(() => + inspectImportLibrary(windowsImportLibraryFixture({ importMachine: 0x14c })), + ).toThrow(/COFF import-object machine 0x14c is not x64/u); + expect(() => + inspectImportLibrary(windowsImportLibraryFixture({ dllName: 'unrelated.dll' })), + ).toThrow(/names unexpected DLL "unrelated\.dll"/u); + expect(() => + inspectImportLibrary(windowsImportLibraryFixture({ symbol: 'unrelated_symbol' })), + ).toThrow(/does not expose required symbol oliphaunt_init/u); + expect(() => + inspectImportLibrary(windowsImportLibraryFixture({ importSymbols: ['oliphaunt_init'] })), + ).toThrow(/does not expose required symbol oliphaunt_logical_generation/u); + expect(() => + inspectImportLibrary( + windowsImportLibraryFixture({ + importSymbols: ['oliphaunt_init', 'oliphaunt_logical_generation'], + }), + ), + ).toThrow(/does not expose required symbol oliphaunt_close_if_generation/u); + expect(() => + inspectImportLibrary( + windowsImportLibraryFixture({ + importSymbols: OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS.filter( + (symbol) => symbol !== 'oliphaunt_copy_last_error', + ), + }), + ), + ).toThrow(/does not expose required symbol oliphaunt_copy_last_error/u); + + const invalidOffset = Buffer.from(windowsImportLibraryFixture()); + invalidOffset.writeUInt32BE(0, 8 + 60 + 4); + expect(() => inspectImportLibrary(invalidOffset)).toThrow( + /refers to non-object archive offset 0/u, + ); + expect(() => inspectImportLibrary(Buffer.from('not an import library\n'))).toThrow( + /expected native binary is malformed or truncated/u, + ); + expect(() => + inspectPlatformBinaryEntries( + [ + entry('bin/oliphaunt.dll', pe()), + entry('lib/arbitrary.lib', windowsImportLibraryFixture()), + ], + { target: 'windows-x64-msvc' }, + ), + ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); + expect(() => + inspectPlatformBinaryEntries( + [entry('bin/oliphaunt.dll', pe()), entry('lib/arbitrary.lib', pe())], + { target: 'windows-x64-msvc' }, + ), + ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); + expect(() => + inspectPlatformBinaryEntries( + [ + entry('bin/oliphaunt.dll', pe()), + entry('lib/development.a', windowsImportLibraryFixture()), + ], + { target: 'windows-x64-msvc' }, + ), + ).toThrow(/static \.a archives are not permitted in a Windows release carrier/u); + expect(() => + inspectPlatformBinaryEntries( + [entry('bin/oliphaunt.dll', pe()), entry('lib/development.a', pe())], + { target: 'windows-x64-msvc' }, + ), + ).toThrow(/static \.a archives are not permitted in a Windows release carrier/u); + }); +}); + +describe('staged-tree discovery', () => { + test('requires a binary and rejects malformed expected binary names', () => { + expect(() => + inspectPlatformBinaryEntries([entry('README.md', Buffer.from('text'))], { + target: 'linux-x64-gnu', + }), + ).toThrow(/no ELF binaries/u); + expect(() => + inspectPlatformBinaryEntries( + [entry('lib/good.so', elf()), entry('lib/truncated.dylib', Buffer.from([0xcf, 0xfa]))], + { target: 'linux-x64-gnu' }, + ), + ).toThrow(/truncated\.dylib.*malformed or truncated/u); + expect(() => + inspectPlatformBinaryEntries([entry('lib/wrong.so', macho())], { target: 'linux-x64-gnu' }), + ).toThrow(/MACHO content does not match/u); + }); + + test('walks a staged release tree without executing platform tools', async () => { + const root = await mkdtemp(path.join(tmpdir(), 'oliphaunt-platform-binary-')); + temporaryRoots.push(root); + await mkdir(path.join(root, 'lib'), { recursive: true }); + await writeFile(path.join(root, 'README.md'), 'fixture'); + await writeFile(path.join(root, 'lib', 'liboliphaunt.so'), elf({ versions: ['GLIBC_2.38'] })); + const result = await inspectPlatformBinaryTree(root, { target: 'linux-x64-gnu' }); + expect(result.binaries).toBe(1); + expect(result.files).toEqual(['lib/liboliphaunt.so']); + }); + + test('fails closed on symbolic links and non-regular archive entries', async () => { + expect(() => + inspectPlatformBinaryEntries( + [ + entry('lib/libok.so', elf()), + { name: 'lib/redirect.so', isFile: false, isSymbolicLink: true }, + ], + { target: 'linux-x64-gnu' }, + ), + ).toThrow(/redirect\.so.*symbolic link/u); + expect(() => + inspectPlatformBinaryEntries( + [entry('lib/libok.so', elf()), { name: 'lib/device', isFile: false }], + { target: 'linux-x64-gnu' }, + ), + ).toThrow(/device.*non-regular special entry/u); + + const root = await mkdtemp(path.join(tmpdir(), 'platform-binary-link-')); + temporaryRoots.push(root); + await mkdir(path.join(root, 'lib')); + await writeFile(path.join(root, 'lib/libok.so'), elf()); + await writeFile(path.join(root, 'target'), 'outside'); + await symlink('target', path.join(root, 'redirect')); + await expect(inspectPlatformBinaryTree(root, { target: 'linux-x64-gnu' })).rejects.toThrow( + /redirect.*symbolic link/u, + ); + }); +}); diff --git a/tools/packaging/portable-archive-extraction.test.mts b/tools/packaging/portable-archive-extraction.test.mts new file mode 100644 index 000000000..fc7865eb1 --- /dev/null +++ b/tools/packaging/portable-archive-extraction.test.mts @@ -0,0 +1,144 @@ +import { archiveDirectory } from './archive-directory.mts'; +import { expect, test } from 'bun:test'; +import { + chmodSync, + statSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + readdirSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { extractPortableArchiveTree, extractPortableTarGzipTree } from './portable-archive.mts'; +import { zipArchive } from './testdata/zip-fixture.mts'; +import { tarArchive } from './testdata/tar-fixture.mts'; +const ROOT = path.resolve(import.meta.dirname, '../..'); + +const ARCHIVER = path.join(ROOT, 'tools/packaging/archive-directory.mts'); + +test('FAT ZIP entries receive portable permissions before promotion', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-fat-zip-')); + try { + const archive = path.join(root, 'fat.zip'); + writeFileSync( + archive, + zipArchive([ + { name: 'directory/', data: '', versionMadeBy: 20, externalAttributes: 0x10 }, + { name: 'directory/file', data: 'payload', versionMadeBy: 20, externalAttributes: 0x20 }, + ]), + ); + const output = path.join(root, 'output'); + extractPortableArchiveTree(archive, output); + expect(readFileSync(path.join(output, 'directory/file'), 'utf8')).toBe('payload'); + expect(statSync(path.join(output, 'directory')).mode & 0o777).toBe(0o755); + expect(statSync(path.join(output, 'directory/file')).mode & 0o777).toBe(0o644); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +function writeFixtureFile(root, relativePath, contents) { + const file = path.join(root, ...relativePath.split('/')); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, contents); +} + +for (const format of ['zip', 'tar.gz']) + test(`native npm ${format} assembly preserves complete nested runtime trees`, async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-npm-zip-tree-')); + try { + const source = path.join(root, 'source'); + const archive = path.join(root, `native.${format}`); + const runtimeFiles = new Map([ + ['bin/initdb.exe', 'initdb\n'], + ['bin/pg_ctl.exe', 'pg_ctl\n'], + ['bin/postgres.exe', 'postgres\n'], + ['lib/postgresql/plpgsql.dll', 'plpgsql\n'], + ['share/postgresql/postgres.bki', 'catalog\n'], + ['share/postgresql/timezone/Africa/Abidjan', 'timezone\n'], + ]); + for (const [relativePath, contents] of runtimeFiles) { + writeFixtureFile(path.join(source, 'runtime'), relativePath, contents); + } + writeFixtureFile(source, 'lib/modules/dict_snowball.dll', 'embedded dict_snowball\n'); + writeFixtureFile(source, 'lib/modules/plpgsql.dll', 'embedded plpgsql\n'); + writeFixtureFile(source, 'outside/not-packaged.txt', 'outside\n'); + chmodSync(path.join(source, 'runtime/bin/initdb.exe'), 0o755); + + await archiveDirectory(source, archive); + + const stage = path.join(root, 'release-package', 'runtime'); + extractPortableArchiveTree(archive, stage, 'runtime'); + for (const [relativePath, contents] of runtimeFiles) { + expect(readFileSync(path.join(stage, ...relativePath.split('/')), 'utf8')).toBe(contents); + } + expect(statSync(path.join(stage, 'bin/initdb.exe')).mode & 0o777).toBe(0o755); + const empty = path.join(root, 'release-package', 'empty'); + const emptyArchive = path.join(root, `empty.${format}`); + writeFileSync( + emptyArchive, + format === 'zip' + ? zipArchive([{ name: 'empty/', data: '', externalAttributes: 0o40755 << 16 }]) + : tarArchive([{ name: 'empty/', type: '5', mode: 0o755 }]), + ); + extractPortableArchiveTree(emptyArchive, empty, 'empty'); + expect(readdirSync(empty)).toEqual([]); + const modules = path.join(root, 'release-package', 'lib/modules'); + extractPortableArchiveTree(archive, modules, 'lib/modules'); + expect(readFileSync(path.join(modules, 'dict_snowball.dll'), 'utf8')).toBe( + 'embedded dict_snowball\n', + ); + expect(readFileSync(path.join(modules, 'plpgsql.dll'), 'utf8')).toBe('embedded plpgsql\n'); + expect(existsSync(path.join(root, 'release-package', 'outside', 'not-packaged.txt'))).toBe( + false, + ); + writeFileSync(archive, readFileSync(archive).subarray(0, 40)); + expect(() => extractPortableArchiveTree(archive, stage, 'runtime')).toThrow(); + expect(readFileSync(path.join(stage, 'bin/initdb.exe'), 'utf8')).toBe('initdb\n'); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + +test('streaming TAR extraction preserves modes and validates the entire archive before promotion', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-stream-extract-')); + try { + const archive = path.join(root, 'carrier.tar.gz'); + const output = path.join(root, 'output'); + const rows = [ + { name: 'bin', type: '5', mode: 0o755 }, + { name: 'bin/run', data: 'run'.repeat(20000), mode: 0o755 }, + { name: 'empty', data: '', mode: 0o644 }, + ]; + writeFileSync(archive, tarArchive(rows)); + await extractPortableTarGzipTree(archive, output); + expect(readFileSync(path.join(output, 'bin/run'), 'utf8')).toBe(rows[1].data); + expect(statSync(path.join(output, 'bin/run')).mode & 0o777).toBe(0o755); + expect(statSync(path.join(output, 'empty')).size).toBe(0); + await extractPortableTarGzipTree(archive, output, {}, 'bin/run'); + expect(existsSync(path.join(output, 'empty'))).toBe(false); + for (const corrupt of [ + tarArchive([...rows, { name: '../escape', data: 'bad' }]), + tarArchive([...rows, { name: 'bin/run', data: 'duplicate' }]), + tarArchive([...rows, { name: 'link', type: '2', linkTarget: '/tmp' }]), + tarArchive(rows).subarray(0, -4), + ]) { + writeFileSync(archive, corrupt); + await expect(extractPortableTarGzipTree(archive, output, {}, 'bin/run')).rejects.toThrow(); + expect(readFileSync(path.join(output, 'bin/run'), 'utf8')).toBe(rows[1].data); + expect(readdirSync(root).sort()).toEqual(['carrier.tar.gz', 'output']); + } + writeFileSync(archive, tarArchive(rows)); + await expect( + extractPortableTarGzipTree(archive, output, { maxExpandedBytes: 10 }), + ).rejects.toThrow(); + await expect(extractPortableTarGzipTree(archive, output, {}, 'missing')).rejects.toThrow(); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/tools/packaging/portable-archive.mts b/tools/packaging/portable-archive.mts new file mode 100644 index 000000000..3342f4082 --- /dev/null +++ b/tools/packaging/portable-archive.mts @@ -0,0 +1,1553 @@ +import { + chmodSync, + closeSync, + createReadStream, + fstatSync, + lstatSync, + mkdirSync, + mkdtempSync, + openSync, + readFileSync, + readSync, + renameSync, + rmSync, + writeFileSync, + writeSync, +} from 'node:fs'; +import path from 'node:path'; +import * as zlib from 'node:zlib'; +import { crc32, gzipSync, inflateRawSync, constants as zlibConstants } from 'node:zlib'; + +export const RELEASE_ZSTD_COMPRESSION_LEVEL = 19; + +export const DEFAULT_PORTABLE_ARCHIVE_LIMITS = Object.freeze({ + maxArchiveBytes: 512 * 1024 * 1024, + maxEntries: 32_768, + maxEntryBytes: 512 * 1024 * 1024, + maxExpandedBytes: 1024 * 1024 * 1024, +}); + +const UTF8 = new TextDecoder('utf-8', { fatal: true }); +const ZIP_ALLOWED_FLAGS = 0x080e; +const ZIP_ALLOWED_EXTRA_FIELDS = new Set([0x5455, 0x5855, 0x7875]); +const ANDROID_ALIGNMENT_EXTRA_FIELD_ID = 0xd935; +const APK_SIGNING_BLOCK_MAGIC = Buffer.from('APK Sig Block 42', 'ascii'); +const APK_SIGNATURE_SCHEME_BLOCK_IDS = new Set([0x7109871a, 0xf05368c0, 0x1b93ad61]); + +function archiveError(file, message) { + return new Error(`portable-archive: ${path.basename(file)} ${message}`); +} + +/** + * Normalize only the gzip metadata bytes that are outside the compressed + * payload and trailer. zlib derives the OS byte from its build host, so an + * otherwise identical archive is not byte-for-byte portable without this + * explicit producer boundary. + */ +export function normalizeCanonicalGzipHeader(compressed) { + if (!Buffer.isBuffer(compressed) && !(compressed instanceof Uint8Array)) { + throw new TypeError('portable-archive: canonical gzip input must be a Buffer or Uint8Array'); + } + const normalized = Buffer.from(compressed); + if ( + normalized.length < 18 || + normalized[0] !== 0x1f || + normalized[1] !== 0x8b || + normalized[2] !== 0x08 || + normalized[3] !== 0x00 + ) { + throw new Error('portable-archive: canonical gzip input must be a flag-free gzip stream'); + } + normalized.fill(0, 4, 9); + normalized[9] = 0x03; + return normalized; +} + +export function canonicalGzipSync(input) { + return normalizeCanonicalGzipHeader(gzipSync(input, { mtime: 0 })); +} + +export function releaseZstdCompressSync(input) { + return zlib.zstdCompressSync(input, { + params: { + [zlibConstants.ZSTD_c_compressionLevel]: RELEASE_ZSTD_COMPRESSION_LEVEL, + }, + }); +} + +function positiveLimit(value, fallback, label) { + const result = value ?? fallback; + if (!Number.isSafeInteger(result) || result <= 0) { + throw new Error(`portable-archive: ${label} must be a positive safe integer`); + } + return result; +} + +function limits(options) { + return { + maxArchiveBytes: positiveLimit( + options.maxArchiveBytes, + DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxArchiveBytes, + 'maxArchiveBytes', + ), + maxEntries: positiveLimit( + options.maxEntries, + DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntries, + 'maxEntries', + ), + maxEntryBytes: positiveLimit( + options.maxEntryBytes, + DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntryBytes, + 'maxEntryBytes', + ), + maxExpandedBytes: positiveLimit( + options.maxExpandedBytes, + DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxExpandedBytes, + 'maxExpandedBytes', + ), + }; +} + +function requireRegularArchive(file, maxArchiveBytes) { + let stat; + try { + stat = lstatSync(file); + } catch (cause) { + throw archiveError(file, `cannot be inspected: ${cause.message}`); + } + if (!stat.isFile()) { + throw archiveError(file, 'must be a regular, non-symlink archive file'); + } + if (stat.size <= 0 || stat.size > maxArchiveBytes) { + throw archiveError( + file, + `must be non-empty and no larger than ${maxArchiveBytes} bytes; got ${stat.size}`, + ); + } + return stat; +} + +function boundedSlice(buffer, offset, length, file, label) { + if ( + !Number.isSafeInteger(offset) || + !Number.isSafeInteger(length) || + offset < 0 || + length < 0 || + offset > buffer.length || + length > buffer.length - offset + ) { + throw archiveError(file, `has a truncated or unsafe ${label}`); + } + return buffer.subarray(offset, offset + length); +} + +function decodeUtf8(bytes, file, label, { requireAscii = false } = {}) { + if (bytes.length === 0) { + throw archiveError(file, `has an empty ${label}`); + } + if (requireAscii && bytes.some((byte) => byte >= 0x80)) { + throw archiveError(file, `has a non-ASCII ${label} without the ZIP UTF-8 flag`); + } + try { + return UTF8.decode(bytes); + } catch { + throw archiveError(file, `has invalid UTF-8 in ${label}`); + } +} + +export function portableMemberName(raw, type, file, { allowRoot = false } = {}) { + if (allowRoot && type === 'directory' && (raw === '.' || raw === './')) return null; + const directoryMarker = raw.endsWith('/'); + if ((type === 'directory') !== directoryMarker) { + throw archiveError(file, `has a member type/path-marker mismatch: ${JSON.stringify(raw)}`); + } + if ( + raw.includes('\\') || + raw.startsWith('/') || + /^[A-Za-z]:/u.test(raw) || + /[\u0000-\u001f\u007f]/u.test(raw) + ) { + throw archiveError(file, `has an unsafe archive member: ${JSON.stringify(raw)}`); + } + let value = directoryMarker ? raw.slice(0, -1) : raw; + if (value === '.' || value === './') { + throw archiveError(file, `has an ambiguous root archive member: ${JSON.stringify(raw)}`); + } + if (value.startsWith('./')) value = value.slice(2); + const parts = value.split('/'); + if (parts.length === 0 || parts.some((part) => !part || part === '.' || part === '..')) { + throw archiveError(file, `has an unsafe archive member: ${JSON.stringify(raw)}`); + } + if (value !== value.normalize('NFC')) { + throw archiveError(file, `has a non-NFC archive member: ${JSON.stringify(raw)}`); + } + if (Buffer.byteLength(value, 'utf8') > 4096) { + throw archiveError(file, `has an overlong archive member: ${JSON.stringify(raw)}`); + } + for (const segment of parts) { + if ( + Buffer.byteLength(segment, 'utf8') > 255 || + /[<>:"|?*]/u.test(segment) || + /[ .]$/u.test(segment) || + /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(segment) + ) { + throw archiveError(file, `has a non-portable archive member: ${JSON.stringify(raw)}`); + } + } + return value; +} + +function checkedEntries(entries, file, archiveLimits, { caseSensitive = false } = {}) { + if (entries.length === 0) throw archiveError(file, 'contains no archive members'); + if (entries.length > archiveLimits.maxEntries) { + throw archiveError(file, `exceeds the ${archiveLimits.maxEntries}-entry limit`); + } + const exact = new Set(); + const portable = new Map(); + const files = new Set(); + let expandedBytes = 0; + for (const entry of entries) { + if (!Number.isSafeInteger(entry.size) || entry.size < 0) { + throw archiveError(file, `declares an unsafe size for ${entry.name}`); + } + if (entry.size > archiveLimits.maxEntryBytes) { + throw archiveError( + file, + `member ${entry.name} exceeds the ${archiveLimits.maxEntryBytes}-byte entry limit`, + ); + } + expandedBytes += entry.size; + if (!Number.isSafeInteger(expandedBytes) || expandedBytes > archiveLimits.maxExpandedBytes) { + throw archiveError( + file, + `exceeds the ${archiveLimits.maxExpandedBytes}-byte expanded-data limit`, + ); + } + if (exact.has(entry.name)) { + throw archiveError(file, `repeats archive member ${entry.name}`); + } + exact.add(entry.name); + // Android resource names are case-sensitive and aapt2 legitimately emits + // distinct hashed paths such as res/2F.xml and res/2f.xml. Other carrier + // formats retain the cross-filesystem case-folding collision check. + const portableKey = caseSensitive + ? entry.name.normalize('NFC') + : entry.name.normalize('NFC').toLowerCase(); + const prior = portable.get(portableKey); + if (prior !== undefined && prior !== entry.name) { + throw archiveError( + file, + `contains case/NFC-colliding archive members ${prior} and ${entry.name}`, + ); + } + portable.set(portableKey, entry.name); + if (entry.type !== 'directory') files.add(entry.name); + } + for (const entry of entries) { + let separator = entry.name.indexOf('/'); + while (separator >= 0) { + const parent = entry.name.slice(0, separator); + if (files.has(parent)) { + throw archiveError(file, `uses regular file ${parent} as an archive directory`); + } + separator = entry.name.indexOf('/', separator + 1); + } + } + return new Map(entries.map((entry) => [entry.name, Object.freeze(entry)])); +} + +function androidApkEntryAlignment(name) { + return name.endsWith('.so') ? 16 * 1024 : 4; +} + +function validateAndroidAlignmentExtra(value, file, label, { dataOffset, method, name }) { + if (method !== 0) { + throw archiveError(file, `uses APK alignment metadata on compressed ZIP member ${label}`); + } + if (value.length < 2) { + throw archiveError(file, `has malformed APK alignment ZIP metadata for ${label}`); + } + const alignment = value.readUInt16LE(0); + const padding = value.subarray(2); + const expectedAlignment = androidApkEntryAlignment(name); + const unpaddedDataOffset = dataOffset - padding.length; + const expectedPadding = + (expectedAlignment - (unpaddedDataOffset % expectedAlignment)) % expectedAlignment; + if ( + alignment !== expectedAlignment || + (alignment & (alignment - 1)) !== 0 || + padding.length !== expectedPadding || + padding.some((byte) => byte !== 0) || + dataOffset % alignment !== 0 + ) { + throw archiveError(file, `has malformed APK alignment ZIP metadata for ${label}`); + } +} + +function validateZipExtra( + extra, + file, + label, + { source = false, androidApkLocal = false, dataOffset = 0, method = -1, name = '' } = {}, +) { + const seen = new Set(); + for (let offset = 0; offset < extra.length; ) { + if (androidApkLocal && extra.subarray(offset).every((byte) => byte === 0)) { + const paddingLength = extra.length - offset; + const alignment = androidApkEntryAlignment(name); + const unpaddedDataOffset = dataOffset - paddingLength; + const expectedPadding = (alignment - (unpaddedDataOffset % alignment)) % alignment; + if (method !== 0 || paddingLength !== expectedPadding || dataOffset % alignment !== 0) { + throw archiveError(file, `has malformed legacy APK alignment padding for ${label}`); + } + return; + } + if (extra.length - offset < 4) { + throw archiveError(file, `has a truncated ZIP ${label} extra field`); + } + const id = extra.readUInt16LE(offset); + const size = extra.readUInt16LE(offset + 2); + offset += 4; + if (size > extra.length - offset) { + throw archiveError(file, `has a truncated ZIP ${label} extra field`); + } + if (seen.has(id)) { + throw archiveError( + file, + `repeats ZIP ${label} extra field 0x${id.toString(16).padStart(4, '0')}`, + ); + } + seen.add(id); + if ( + !ZIP_ALLOWED_EXTRA_FIELDS.has(id) && + !(source && id === 0x000a) && + !(androidApkLocal && id === ANDROID_ALIGNMENT_EXTRA_FIELD_ID) + ) { + throw archiveError( + file, + `uses unsupported ZIP ${label} extra field 0x${id.toString(16).padStart(4, '0')}`, + ); + } + const value = extra.subarray(offset, offset + size); + if (id === 0x000a) { + if ( + size !== 32 || + value.readUInt32LE(0) !== 0 || + value.readUInt16LE(4) !== 1 || + value.readUInt16LE(6) !== 24 + ) { + throw archiveError(file, 'has malformed NTFS timestamp ZIP metadata'); + } + } else if (id === ANDROID_ALIGNMENT_EXTRA_FIELD_ID) { + if (offset + size !== extra.length) { + throw archiveError(file, `does not place APK alignment ZIP metadata last for ${label}`); + } + validateAndroidAlignmentExtra(value, file, label, { dataOffset, method, name }); + } else if (id === 0x5455) { + if (![5, 9, 13].includes(size) || (value[0] & ~0x07) !== 0 || (value[0] & 0x01) === 0) { + throw archiveError(file, 'has malformed extended-timestamp ZIP metadata'); + } + } else if (id === 0x5855) { + if (size !== 8 && size !== 12) { + throw archiveError(file, 'has malformed legacy Unix ZIP metadata'); + } + } else if (id === 0x7875) { + if (size < 5 || value[0] !== 1) { + throw archiveError(file, 'has malformed Unix UID/GID ZIP metadata'); + } + const uidBytes = value[1]; + const gidOffset = 2 + uidBytes; + if (uidBytes < 1 || uidBytes > 8 || gidOffset >= value.length) { + throw archiveError(file, 'has malformed Unix UID/GID ZIP metadata'); + } + const gidBytes = value[gidOffset]; + if (gidBytes < 1 || gidBytes > 8 || gidOffset + 1 + gidBytes !== value.length) { + throw archiveError(file, 'has malformed Unix UID/GID ZIP metadata'); + } + } + offset += size; + } +} + +function safeZipUInt64(buffer, offset, file, label) { + const bytes = boundedSlice(buffer, offset, 8, file, label); + const value = bytes.readBigUInt64LE(0); + if (value > BigInt(Number.MAX_SAFE_INTEGER)) { + throw archiveError(file, `has an unsafe ${label}`); + } + return Number(value); +} + +function zipDescriptorMatches(buffer, entry, offset, length) { + if (length === 16) { + return ( + buffer.readUInt32LE(offset) === 0x08074b50 && + buffer.readUInt32LE(offset + 4) === entry.crc32 && + buffer.readUInt32LE(offset + 8) === entry.compressedSize && + buffer.readUInt32LE(offset + 12) === entry.size + ); + } + return ( + buffer.readUInt32LE(offset) === entry.crc32 && + buffer.readUInt32LE(offset + 4) === entry.compressedSize && + buffer.readUInt32LE(offset + 8) === entry.size + ); +} + +function apkZipDescriptorLength(buffer, entry, available, file) { + const candidates = []; + for (const length of [12, 16]) { + if (available >= length && zipDescriptorMatches(buffer, entry, entry.dataEnd, length)) { + candidates.push(length); + } + } + if (candidates.length !== 1) { + throw archiveError( + file, + `has an invalid or ambiguous ZIP descriptor before APK metadata for ${entry.name}`, + ); + } + return candidates[0]; +} + +function validateApkSigningBlock(buffer, recordsEnd, centralOffset, file) { + const gap = centralOffset - recordsEnd; + if (gap === 0) return; + if (gap < 32) { + throw archiveError( + file, + `has an unrecognized ${gap}-byte gap before its APK central directory`, + ); + } + const footerOffset = centralOffset - 24; + const magic = boundedSlice(buffer, centralOffset - 16, 16, file, 'APK Signing Block magic'); + if (!magic.equals(APK_SIGNING_BLOCK_MAGIC)) { + throw archiveError(file, 'has an unrecognized gap before its APK central directory'); + } + const size = safeZipUInt64(buffer, footerOffset, file, 'APK Signing Block footer size'); + if (size < 24 || size > centralOffset - recordsEnd - 8) { + throw archiveError(file, 'has an invalid APK Signing Block size'); + } + const blockOffset = centralOffset - size - 8; + const firstSize = safeZipUInt64(buffer, blockOffset, file, 'APK Signing Block header size'); + if (firstSize !== size) { + throw archiveError(file, 'has disagreeing APK Signing Block sizes'); + } + if (buffer.subarray(recordsEnd, blockOffset).some((byte) => byte !== 0)) { + throw archiveError(file, 'has non-zero padding before its APK Signing Block'); + } + const signingPadding = blockOffset - recordsEnd; + if ( + signingPadding !== 0 && + (signingPadding >= 4096 || + blockOffset % 4096 !== 0 || + signingPadding !== (4096 - (recordsEnd % 4096)) % 4096) + ) { + throw archiveError(file, 'has non-canonical zero padding before its APK Signing Block'); + } + const pairsEnd = footerOffset; + let offset = blockOffset + 8; + let pairCount = 0; + let hasSignatureScheme = false; + const pairIds = new Set(); + while (offset < pairsEnd) { + if (pairsEnd - offset < 12) { + throw archiveError(file, 'has a truncated APK Signing Block pair'); + } + const pairSize = safeZipUInt64(buffer, offset, file, 'APK Signing Block pair size'); + offset += 8; + if (pairSize < 4 || pairSize > pairsEnd - offset) { + throw archiveError(file, 'has an invalid APK Signing Block pair size'); + } + const pairId = buffer.readUInt32LE(offset); + if (pairIds.has(pairId)) { + throw archiveError( + file, + `repeats APK Signing Block pair ID 0x${pairId.toString(16).padStart(8, '0')}`, + ); + } + pairIds.add(pairId); + if (APK_SIGNATURE_SCHEME_BLOCK_IDS.has(pairId)) hasSignatureScheme = true; + // Unknown IDs are intentionally accepted. Android makes the signing-block + // container extensible; exact framing plus at least one known whole-file + // signature scheme is the archive-safety boundary here. + offset += pairSize; + pairCount += 1; + } + if (offset !== pairsEnd || pairCount === 0) { + throw archiveError(file, 'has an empty or truncated APK Signing Block pair sequence'); + } + if (!hasSignatureScheme) { + throw archiveError(file, 'has an APK Signing Block without a v2, v3, or v3.1 signature pair'); + } +} + +function zipEntryType(versionMadeBy, externalAttributes, rawName, file) { + const host = versionMadeBy >>> 8; + const unixMode = externalAttributes >>> 16; + const unixType = unixMode & 0o170000; + const pathDirectory = rawName.endsWith('/'); + const dosDirectory = (externalAttributes & 0x10) !== 0; + let type; + if (host === 3) { + if (unixType === 0o100000) { + if (dosDirectory) { + throw archiveError(file, `marks Unix regular file ${rawName} as a DOS directory`); + } + type = 'file'; + } else if (unixType === 0o040000) { + type = 'directory'; + } else if (unixType === 0) { + throw archiveError(file, `has an ambiguous Unix creator type for ${rawName}`); + } else { + throw archiveError(file, `contains a link or special ZIP entry: ${rawName}`); + } + } else if (host === 0) { + if (unixType !== 0) { + throw archiveError(file, `has conflicting FAT/Unix type metadata for ${rawName}`); + } + if (pathDirectory !== dosDirectory) { + throw archiveError(file, `has inconsistent FAT directory metadata for ${rawName}`); + } + type = pathDirectory ? 'directory' : 'file'; + } else { + throw archiveError(file, `uses unsupported ZIP creator host ${host} for ${rawName}`); + } + if ((type === 'directory') !== pathDirectory) { + throw archiveError(file, `has a member type/path-marker mismatch: ${rawName}`); + } + if (host === 3) validatePortableMode(unixMode & 0o7777, type, rawName, file); + return { mode: host === 0 ? (type === 'directory' ? 0o755 : 0o644) : unixMode, type }; +} + +function validatePortableMode(mode, type, name, file) { + if ((mode & 0o7000) !== 0) { + throw archiveError(file, `uses set-id or sticky permission bits for ${name}`); + } + if (type === 'file' && (mode & 0o400) === 0) { + throw archiveError(file, `has an owner-unreadable regular file ${name}`); + } + if (type === 'directory' && (mode & 0o500) !== 0o500) { + throw archiveError(file, `has an owner-unreadable or untraversable directory ${name}`); + } +} + +function findZipEnd(buffer, file) { + if (buffer.length < 22) throw archiveError(file, 'is too short to be a ZIP archive'); + const minimum = Math.max(0, buffer.length - 65_557); + for (let offset = buffer.length - 22; offset >= minimum; offset -= 1) { + if ( + buffer.readUInt32LE(offset) === 0x06054b50 && + offset + 22 + buffer.readUInt16LE(offset + 20) === buffer.length + ) { + return offset; + } + } + throw archiveError(file, 'has no well-formed ZIP end record'); +} + +// Actions artifact ZIPs can exceed 4 GiB. Inspect only central headers; unzip +// handles names, decompression and CRCs without buffering the archive in JS. +export function validateZipEntryTypes(file) { + const fd = openSync(file, 'r'); + try { + const length = fstatSync(fd).size; + const read = (offset, size) => { + if (!Number.isSafeInteger(offset) || offset < 0 || offset > length - size) + throw archiveError(file, 'has a truncated ZIP record'); + const buffer = Buffer.alloc(size); + let done = 0; + while (done < size) { + const count = readSync(fd, buffer, done, size - done, offset + done); + if (!count) throw archiveError(file, 'has a truncated ZIP record'); + done += count; + } + return buffer; + }; + const tailOffset = Math.max(0, length - 65_557); + const tail = read(tailOffset, length - tailOffset); + const endOffset = findZipEnd(tail, file); + const end = tail.subarray(endOffset); + let centralEnd = tailOffset + endOffset; + let count = end.readUInt16LE(10); + let size = end.readUInt32LE(12); + let offset = end.readUInt32LE(16); + if (end.readUInt16LE(4) || end.readUInt16LE(6) || end.readUInt16LE(8) !== count) + throw archiveError(file, 'uses multi-disk ZIP metadata'); + const locator = centralEnd >= 20 ? read(centralEnd - 20, 20) : Buffer.alloc(20); + if (locator.readUInt32LE(0) === 0x07064b50) { + if (locator.readUInt32LE(4) !== 0 || locator.readUInt32LE(16) !== 1) + throw archiveError(file, 'uses multi-disk ZIP64 metadata'); + const zip64Offset = safeZipUInt64(locator, 8, file, 'ZIP64 end offset'); + const zip64 = read(zip64Offset, 56); + if ( + zip64.readUInt32LE(0) !== 0x06064b50 || + safeZipUInt64(zip64, 4, file, 'ZIP64 end size') !== centralEnd - 20 - zip64Offset - 12 || + zip64.readUInt32LE(16) || + zip64.readUInt32LE(20) || + zip64.readBigUInt64LE(24) !== zip64.readBigUInt64LE(32) + ) + throw archiveError(file, 'has invalid ZIP64 end metadata'); + centralEnd = zip64Offset; + count = safeZipUInt64(zip64, 32, file, 'ZIP64 entry count'); + size = safeZipUInt64(zip64, 40, file, 'ZIP64 central size'); + offset = safeZipUInt64(zip64, 48, file, 'ZIP64 central offset'); + } + if (!count || count > size / 46 || offset + size !== centralEnd) + throw archiveError(file, 'has an invalid ZIP central-directory extent'); + for (let index = 0; index < count; index++) { + if (offset > centralEnd - 46) throw archiveError(file, 'has a truncated ZIP central header'); + const header = read(offset, 46); + if (header.readUInt32LE(0) !== 0x02014b50) + throw archiveError(file, 'has an invalid ZIP central header'); + const kind = (header.readUInt32LE(38) >>> 16) & 0o170000; + if (header.readUInt16LE(8) & 1 || ![0, 0o100000, 0o040000].includes(kind)) + throw archiveError(file, 'contains an encrypted, symbolic-link, or special ZIP member'); + offset += 46 + header.readUInt16LE(28) + header.readUInt16LE(30) + header.readUInt16LE(32); + } + if (offset !== centralEnd) + throw archiveError(file, 'has an invalid ZIP central-directory size'); + } finally { + closeSync(fd); + } +} + +function validateZipDescriptor(buffer, entry, offset, length, file) { + if (length !== 12 && length !== 16) { + throw archiveError(file, `has an ambiguous ${length}-byte gap after ZIP member ${entry.name}`); + } + const descriptor = boundedSlice(buffer, offset, length, file, `ZIP descriptor for ${entry.name}`); + let cursor = 0; + if (length === 16) { + if (descriptor.readUInt32LE(0) !== 0x08074b50) { + throw archiveError(file, `has an invalid ZIP descriptor signature for ${entry.name}`); + } + cursor = 4; + } + if ( + descriptor.readUInt32LE(cursor) !== entry.crc32 || + descriptor.readUInt32LE(cursor + 4) !== entry.compressedSize || + descriptor.readUInt32LE(cursor + 8) !== entry.size + ) { + throw archiveError(file, `has a ZIP descriptor that disagrees with ${entry.name}`); + } +} + +function inflateZipEntry(buffer, entry, file, maxEntryBytes) { + const compressed = boundedSlice( + buffer, + entry.dataOffset, + entry.compressedSize, + file, + `ZIP payload for ${entry.name}`, + ); + let data; + if (entry.method === 0) { + data = compressed; + } else { + let inflated; + try { + inflated = inflateRawSync(compressed, { + info: true, + maxOutputLength: Math.min(maxEntryBytes, entry.size) + 1, + }); + } catch (cause) { + throw archiveError( + file, + `has invalid or oversized deflate data for ${entry.name}: ${cause.message}`, + ); + } + if (inflated.engine.bytesWritten !== compressed.length) { + throw archiveError(file, `has trailing compressed bytes in ZIP member ${entry.name}`); + } + data = inflated.buffer; + } + if (data.length !== entry.size) { + throw archiveError( + file, + `expanded ZIP size for ${entry.name} is ${data.length}, expected ${entry.size}`, + ); + } + const actualCrc = crc32(data); + if (actualCrc !== entry.crc32) { + throw archiveError( + file, + `CRC-32 mismatch for ZIP member ${entry.name}: expected ${entry.crc32.toString(16).padStart(8, '0')}, got ${actualCrc.toString(16).padStart(8, '0')}`, + ); + } + return data; +} + +function readZipEntries(file, archiveLimits, { source = false, androidApk = false } = {}) { + const buffer = readFileSync(file); + const eocdOffset = findZipEnd(buffer, file); + const eocd = boundedSlice(buffer, eocdOffset, 22, file, 'ZIP end record'); + const disk = eocd.readUInt16LE(4); + const centralDisk = eocd.readUInt16LE(6); + const diskEntries = eocd.readUInt16LE(8); + const entryCount = eocd.readUInt16LE(10); + const centralSize = eocd.readUInt32LE(12); + const centralOffset = eocd.readUInt32LE(16); + const commentLength = eocd.readUInt16LE(20); + if ( + disk === 0xffff || + centralDisk === 0xffff || + diskEntries === 0xffff || + entryCount === 0xffff || + centralSize === 0xffffffff || + centralOffset === 0xffffffff + ) { + throw archiveError(file, 'uses unsupported ZIP64 metadata'); + } + if (disk !== 0 || centralDisk !== 0 || diskEntries !== entryCount) { + throw archiveError(file, 'uses unsupported multi-disk ZIP metadata'); + } + if (commentLength !== 0) throw archiveError(file, 'has an unsupported ZIP archive comment'); + if (entryCount === 0 || entryCount > archiveLimits.maxEntries) { + throw archiveError(file, `has an invalid ZIP entry count ${entryCount}`); + } + if (centralOffset + centralSize !== eocdOffset) { + throw archiveError(file, 'has an invalid or ambiguous ZIP central-directory extent'); + } + + const entries = []; + let offset = centralOffset; + let expandedBytes = 0; + for (let index = 0; index < entryCount; index += 1) { + const header = boundedSlice(buffer, offset, 46, file, `ZIP central header ${index + 1}`); + if (header.readUInt32LE(0) !== 0x02014b50) { + throw archiveError(file, `has an invalid ZIP central header ${index + 1}`); + } + const versionMadeBy = header.readUInt16LE(4); + const versionNeeded = header.readUInt16LE(6); + const flags = header.readUInt16LE(8); + const method = header.readUInt16LE(10); + const modTime = header.readUInt16LE(12); + const modDate = header.readUInt16LE(14); + const expectedCrc = header.readUInt32LE(16); + const compressedSize = header.readUInt32LE(20); + const size = header.readUInt32LE(24); + const nameLength = header.readUInt16LE(28); + const extraLength = header.readUInt16LE(30); + const memberCommentLength = header.readUInt16LE(32); + const diskStart = header.readUInt16LE(34); + const externalAttributes = header.readUInt32LE(38); + const localOffset = header.readUInt32LE(42); + if (versionNeeded > 20) { + throw archiveError(file, `requires unsupported ZIP version ${versionNeeded}`); + } + if ((flags & ~ZIP_ALLOWED_FLAGS) !== 0 || (flags & 0x0001) !== 0) { + throw archiveError(file, `uses unsupported or encrypted ZIP flags 0x${flags.toString(16)}`); + } + if (method !== 0 && method !== 8) { + throw archiveError(file, `uses unsupported ZIP compression method ${method}`); + } + if (method === 0 && (flags & 0x0006) !== 0) { + throw archiveError(file, 'uses deflate-only flags on a stored ZIP member'); + } + if ( + compressedSize === 0xffffffff || + size === 0xffffffff || + localOffset === 0xffffffff || + diskStart === 0xffff + ) { + throw archiveError(file, 'uses unsupported ZIP64 entry metadata'); + } + if (diskStart !== 0) throw archiveError(file, 'contains a multi-disk ZIP member'); + if (memberCommentLength !== 0) throw archiveError(file, 'contains a ZIP member comment'); + if (size > archiveLimits.maxEntryBytes) { + throw archiveError(file, `ZIP member ${index + 1} exceeds the entry-size limit`); + } + expandedBytes += size; + if (!Number.isSafeInteger(expandedBytes) || expandedBytes > archiveLimits.maxExpandedBytes) { + throw archiveError(file, 'exceeds the expanded ZIP data limit'); + } + const recordLength = 46 + nameLength + extraLength; + if (offset > eocdOffset - recordLength) { + throw archiveError(file, `has a truncated ZIP central member ${index + 1}`); + } + const variable = boundedSlice( + buffer, + offset + 46, + nameLength + extraLength, + file, + `ZIP central member ${index + 1}`, + ); + const rawNameBytes = variable.subarray(0, nameLength); + const rawName = decodeUtf8(rawNameBytes, file, `ZIP member name ${index + 1}`, { + requireAscii: (flags & 0x0800) === 0, + }); + validateZipExtra(variable.subarray(nameLength), file, `central ${JSON.stringify(rawName)}`, { + source, + }); + const { mode, type } = zipEntryType(versionMadeBy, externalAttributes, rawName, file); + const name = portableMemberName(rawName, type, file); + if (type === 'directory' && (size !== 0 || expectedCrc !== 0)) { + throw archiveError(file, `has a non-empty ZIP directory member ${rawName}`); + } + if (method === 0 && compressedSize !== size) { + throw archiveError(file, `has inconsistent stored ZIP sizes for ${rawName}`); + } + + const local = boundedSlice(buffer, localOffset, 30, file, `ZIP local header for ${name}`); + if (local.readUInt32LE(0) !== 0x04034b50) { + throw archiveError(file, `has an invalid ZIP local header for ${name}`); + } + if ( + local.readUInt16LE(4) !== versionNeeded || + local.readUInt16LE(6) !== flags || + local.readUInt16LE(8) !== method || + local.readUInt16LE(10) !== modTime || + local.readUInt16LE(12) !== modDate + ) { + throw archiveError(file, `has local/central ZIP metadata disagreement for ${name}`); + } + const localNameLength = local.readUInt16LE(26); + const localExtraLength = local.readUInt16LE(28); + const localVariable = boundedSlice( + buffer, + localOffset + 30, + localNameLength + localExtraLength, + file, + `ZIP local variable fields for ${name}`, + ); + if (!localVariable.subarray(0, localNameLength).equals(rawNameBytes)) { + throw archiveError(file, `has a local/central ZIP name disagreement for ${name}`); + } + const dataOffset = localOffset + 30 + localNameLength + localExtraLength; + validateZipExtra( + localVariable.subarray(localNameLength), + file, + `local ${JSON.stringify(rawName)}`, + { source, androidApkLocal: androidApk, dataOffset, method, name }, + ); + const descriptor = (flags & 0x0008) !== 0; + const localCrc = local.readUInt32LE(14); + const localCompressedSize = local.readUInt32LE(18); + const localSize = local.readUInt32LE(22); + if (descriptor) { + if ( + (localCrc !== 0 && localCrc !== expectedCrc) || + (localCompressedSize !== 0 && localCompressedSize !== compressedSize) || + (localSize !== 0 && localSize !== size) + ) { + throw archiveError(file, `has local/descriptor ZIP disagreement for ${name}`); + } + } else if ( + localCrc !== expectedCrc || + localCompressedSize !== compressedSize || + localSize !== size + ) { + throw archiveError(file, `has local/central ZIP CRC or size disagreement for ${name}`); + } + if (dataOffset > centralOffset || compressedSize > centralOffset - dataOffset) { + throw archiveError(file, `has ZIP payload outside local-record bounds for ${name}`); + } + entries.push({ + compressedSize, + crc32: expectedCrc, + dataEnd: dataOffset + compressedSize, + dataOffset, + descriptor, + isDirectory: type === 'directory', + isFile: type === 'file', + isSymbolicLink: false, + localOffset, + method, + mode, + name, + size, + type, + }); + offset += recordLength; + } + if (offset !== eocdOffset) { + throw archiveError(file, 'has trailing or missing ZIP central-directory records'); + } + const extents = [...entries].sort( + (left, right) => left.localOffset - right.localOffset || left.dataEnd - right.dataEnd, + ); + if (extents[0]?.localOffset !== 0) { + throw archiveError(file, 'has unreferenced bytes before its first ZIP local record'); + } + for (let index = 0; index < extents.length; index += 1) { + const entry = extents[index]; + const nextOffset = extents[index + 1]?.localOffset ?? centralOffset; + if (entry.dataEnd > nextOffset) throw archiveError(file, 'has overlapping ZIP local records'); + const gap = nextOffset - entry.dataEnd; + const finalEntry = index === extents.length - 1; + if (entry.descriptor && androidApk && finalEntry) { + const descriptorLength = apkZipDescriptorLength(buffer, entry, gap, file); + validateApkSigningBlock(buffer, entry.dataEnd + descriptorLength, centralOffset, file); + } else if (entry.descriptor) { + validateZipDescriptor(buffer, entry, entry.dataEnd, gap, file); + } else if (androidApk && finalEntry) { + validateApkSigningBlock(buffer, entry.dataEnd, centralOffset, file); + } else if (gap !== 0) { + throw archiveError(file, `has an ambiguous ${gap}-byte gap after ZIP member ${entry.name}`); + } + } + + for (const entry of entries) { + const payload = { + compressedSize: entry.compressedSize, + crc32: entry.crc32, + dataOffset: entry.dataOffset, + method: entry.method, + name: entry.name, + size: entry.size, + }; + inflateZipEntry(buffer, payload, file, archiveLimits.maxEntryBytes); + entry.data = () => inflateZipEntry(buffer, payload, file, archiveLimits.maxEntryBytes); + delete entry.compressedSize; + delete entry.crc32; + delete entry.dataEnd; + delete entry.dataOffset; + delete entry.descriptor; + delete entry.localOffset; + delete entry.method; + } + return checkedEntries(entries, file, archiveLimits, { caseSensitive: androidApk }); +} + +function tarString(header, offset, length, file, label, { allowEmpty = false } = {}) { + const field = header.subarray(offset, offset + length); + const zero = field.indexOf(0); + const value = zero < 0 ? field : field.subarray(0, zero); + if (zero >= 0 && field.subarray(zero).some((byte) => byte !== 0)) { + throw archiveError(file, `has malformed ustar ${label}`); + } + if (value.length === 0) { + if (allowEmpty) return ''; + throw archiveError(file, `has an empty ustar ${label}`); + } + try { + return UTF8.decode(value); + } catch { + throw archiveError(file, `has invalid UTF-8 in ustar ${label}`); + } +} + +function tarOctal(header, offset, length, file, label, { allowEmpty = false } = {}) { + const field = header.subarray(offset, offset + length); + if ((field[0] & 0x80) !== 0) { + throw archiveError(file, `uses unsupported base-256 ustar ${label}`); + } + const zero = field.indexOf(0); + const value = zero < 0 ? field : field.subarray(0, zero); + if (zero >= 0 && field.subarray(zero + 1).some((byte) => byte !== 0 && byte !== 0x20)) { + throw archiveError(file, `has non-padding bytes after the ustar ${label} terminator`); + } + if (value.some((byte) => byte !== 0x20 && (byte < 0x30 || byte > 0x37))) { + throw archiveError(file, `has invalid ustar ${label}`); + } + const text = value.toString('ascii').trim(); + if (text.length === 0 && allowEmpty) return 0; + if (!/^[0-7]+$/u.test(text)) throw archiveError(file, `has invalid ustar ${label}`); + const parsed = Number.parseInt(text, 8); + if (!Number.isSafeInteger(parsed) || parsed < 0) { + throw archiveError(file, `has unsafe ustar ${label}`); + } + return parsed; +} + +function gzipPortableText(compressed, start, end, file, label) { + const bytes = compressed.subarray(start, end); + if (bytes.some((byte) => byte < 0x20 || byte > 0x7e) || bytes.length === 0) { + throw archiveError(file, `has a non-portable gzip ${label}`); + } +} + +function gzipZeroTerminatedEnd(compressed, offset, trailerOffset, file, label) { + const end = compressed.indexOf(0, offset); + if (end < offset || end >= trailerOffset) { + throw archiveError(file, `has a truncated gzip ${label}`); + } + gzipPortableText(compressed, offset, end, file, label); + return end + 1; +} + +export function strictGunzip(compressed, file, maxOutputLength) { + if ( + compressed.length < 18 || + compressed[0] !== 0x1f || + compressed[1] !== 0x8b || + compressed[2] !== 8 + ) { + throw archiveError(file, 'is not a gzip-compressed deflate stream'); + } + const flags = compressed[3]; + if ((flags & 0xe0) !== 0) throw archiveError(file, 'uses reserved gzip flags'); + const trailerOffset = compressed.length - 8; + let offset = 10; + if ((flags & 0x04) !== 0) { + if (offset > trailerOffset - 2) throw archiveError(file, 'has a truncated gzip extra length'); + const extraLength = compressed.readUInt16LE(offset); + offset += 2; + if (extraLength > trailerOffset - offset) + throw archiveError(file, 'has truncated gzip extra data'); + offset += extraLength; + } + if ((flags & 0x08) !== 0) { + offset = gzipZeroTerminatedEnd(compressed, offset, trailerOffset, file, 'filename'); + } + if ((flags & 0x10) !== 0) { + offset = gzipZeroTerminatedEnd(compressed, offset, trailerOffset, file, 'comment'); + } + if ((flags & 0x02) !== 0) { + if (offset > trailerOffset - 2) throw archiveError(file, 'has a truncated gzip header CRC'); + const expectedHeaderCrc = compressed.readUInt16LE(offset); + const actualHeaderCrc = crc32(compressed.subarray(0, offset)) & 0xffff; + if (expectedHeaderCrc !== actualHeaderCrc) + throw archiveError(file, 'has an invalid gzip header CRC'); + offset += 2; + } + if (offset >= trailerOffset) throw archiveError(file, 'has no gzip deflate payload'); + const deflate = compressed.subarray(offset, trailerOffset); + let inflated; + try { + inflated = inflateRawSync(deflate, { info: true, maxOutputLength }); + } catch (cause) { + throw archiveError(file, `is not a bounded readable gzip stream: ${cause.message}`); + } + if (inflated.engine.bytesWritten !== deflate.length) { + throw archiveError(file, 'contains trailing data or multiple gzip members'); + } + const expectedCrc = compressed.readUInt32LE(trailerOffset); + const expectedSize = compressed.readUInt32LE(trailerOffset + 4); + const actualCrc = crc32(inflated.buffer); + if (actualCrc !== expectedCrc) throw archiveError(file, 'has an invalid gzip payload CRC-32'); + if (inflated.buffer.length !== expectedSize) + throw archiveError(file, 'has an invalid gzip payload size'); + return inflated.buffer; +} + +export function decompressSingleZstdFrame( + input, + { + label = 'Zstandard payload', + maxInputBytes = DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxArchiveBytes, + maxOutputBytes = DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxExpandedBytes, + } = {}, +) { + const checkedMaxInputBytes = positiveLimit( + maxInputBytes, + DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxArchiveBytes, + 'maxInputBytes', + ); + const checkedMaxOutputBytes = positiveLimit( + maxOutputBytes, + DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxExpandedBytes, + 'maxOutputBytes', + ); + if (!Buffer.isBuffer(input) && !(input instanceof Uint8Array)) { + throw archiveError(label, 'must be provided as a Buffer or Uint8Array'); + } + const compressed = Buffer.isBuffer(input) + ? input + : Buffer.from(input.buffer, input.byteOffset, input.byteLength); + if (compressed.length === 0 || compressed.length > checkedMaxInputBytes) { + throw archiveError( + label, + `must be non-empty and no larger than ${checkedMaxInputBytes} bytes; got ${compressed.length}`, + ); + } + if ( + compressed.length < 4 || + compressed[0] !== 0x28 || + compressed[1] !== 0xb5 || + compressed[2] !== 0x2f || + compressed[3] !== 0xfd + ) { + throw archiveError(label, 'is not a Zstandard frame'); + } + // Zstd decoders may consume concatenated frames. Read block extents first; + // decompression still owns payload validity, dictionaries and checksums. + // https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md + const descriptor = boundedSlice(compressed, 4, 1, label, 'Zstandard header')[0]; + const singleSegment = (descriptor & 0x20) !== 0; + let offset = + 5 + + (singleSegment ? 0 : 1) + + [0, 1, 2, 4][descriptor & 3] + + [singleSegment ? 1 : 0, 2, 4, 8][descriptor >>> 6]; + while (true) { + const block = boundedSlice(compressed, offset, 3, label, 'Zstandard block header').readUIntLE( + 0, + 3, + ); + const type = (block >>> 1) & 3; + if (type === 3) throw archiveError(label, 'has a reserved Zstandard block type'); + const size = type === 1 ? 1 : block >>> 3; + boundedSlice(compressed, offset + 3, size, label, 'Zstandard block'); + offset += 3 + size; + if (block & 1) break; + } + if (descriptor & 4) { + boundedSlice(compressed, offset, 4, label, 'Zstandard checksum'); + offset += 4; + } + if (offset !== compressed.length) + throw archiveError(label, 'contains trailing data or multiple Zstandard frames'); + try { + return zlib.zstdDecompressSync(compressed, { maxOutputLength: checkedMaxOutputBytes }); + } catch (cause) { + throw archiveError(label, `is not a bounded readable Zstandard stream: ${cause.message}`); + } +} + +function parseTarHeader(header, file, archiveLimits, { source = false, posixOnly = false } = {}) { + const posixUstar = + header.subarray(257, 263).equals(Buffer.from('ustar\0')) && + header.subarray(263, 265).equals(Buffer.from('00')); + if (posixOnly && !posixUstar) throw archiveError(file, 'contains a non-POSIX-ustar header'); + const gnuUstar = + header.subarray(257, 263).equals(Buffer.from('ustar ')) && + header[263] === 0x20 && + header[264] === 0; + const v7 = source && header.subarray(257).every((byte) => byte === 0); + if (!posixUstar && !gnuUstar && !v7) throw archiveError(file, 'contains a non-ustar header'); + const storedChecksum = tarOctal(header, 148, 8, file, 'checksum'); + let actualChecksum = 0; + for (let index = 0; index < 512; index += 1) { + actualChecksum += index >= 148 && index < 156 ? 0x20 : header[index]; + } + if (storedChecksum !== actualChecksum) { + throw archiveError(file, 'has an invalid ustar header checksum'); + } + const rawName = tarString(header, 0, 100, file, 'name'); + const prefix = v7 ? '' : tarString(header, 345, 155, file, 'prefix', { allowEmpty: true }); + const raw = prefix ? `${prefix}/${rawName}` : rawName; + const mode = tarOctal(header, 100, 8, file, `mode for ${raw}`); + const uid = tarOctal(header, 108, 8, file, `uid for ${raw}`, { allowEmpty: true }); + const gid = tarOctal(header, 116, 8, file, `gid for ${raw}`, { allowEmpty: true }); + const size = tarOctal(header, 124, 12, file, `size for ${raw}`); + const mtime = tarOctal(header, 136, 12, file, `mtime for ${raw}`, { allowEmpty: true }); + const typeFlag = header[156]; + const type = + typeFlag === 0 || typeFlag === 0x30 + ? 'file' + : typeFlag === 0x35 + ? 'directory' + : source && typeFlag === 0x31 + ? 'hardlink' + : source && typeFlag === 0x32 + ? 'symlink' + : null; + if (type === null) throw archiveError(file, `contains a link or special ustar entry: ${raw}`); + if (type !== 'file' && size !== 0) { + throw archiveError(file, `has a non-empty ustar directory member ${raw}`); + } + const linkTarget = tarString(header, 157, 100, file, `link name for ${raw}`, { + allowEmpty: true, + }); + if (!['symlink', 'hardlink'].includes(type) && linkTarget !== '') { + throw archiveError(file, `sets a link target on non-link ustar member ${raw}`); + } + tarString(header, 265, 32, file, `owner name for ${raw}`, { allowEmpty: true }); + tarString(header, 297, 32, file, `group name for ${raw}`, { allowEmpty: true }); + const deviceMajor = tarOctal(header, 329, 8, file, `device major for ${raw}`, { + allowEmpty: true, + }); + const deviceMinor = tarOctal(header, 337, 8, file, `device minor for ${raw}`, { + allowEmpty: true, + }); + if (deviceMajor !== 0 || deviceMinor !== 0) { + throw archiveError(file, `sets device numbers on non-device ustar member ${raw}`); + } + if (posixUstar && header.subarray(500, 512).some((byte) => byte !== 0)) { + throw archiveError(file, `has non-zero reserved ustar header bytes for ${raw}`); + } + if (gnuUstar && header.subarray(345, 512).some((byte) => byte !== 0)) { + throw archiveError(file, `uses unsupported extended GNU ustar metadata for ${raw}`); + } + if (mode > 0o7777) throw archiveError(file, `has invalid ustar permission bits for ${raw}`); + validatePortableMode(mode, type, raw, file); + if (size > archiveLimits.maxEntryBytes) { + throw archiveError(file, `ustar member ${raw} exceeds the entry-size limit`); + } + // POSIX typeflag 5 establishes a directory without requiring a trailing slash. + const name = portableMemberName( + type === 'directory' && !raw.endsWith('/') ? raw + '/' : raw, + type, + file, + { allowRoot: true }, + ); + return { + gid, + isDirectory: type === 'directory', + isFile: type === 'file', + isSymbolicLink: type === 'symlink', + ...(source ? { linkTarget } : {}), + mode, + mtime, + name, + size, + type, + uid, + }; +} + +function parseTarEntries(tar, file, archiveLimits, { source = false, posixOnly = false } = {}) { + if (tar.length === 0 || tar.length % 512 !== 0) { + throw archiveError(file, 'has a truncated or non-block-aligned ustar stream'); + } + const entries = []; + let offset = 0; + let memberCount = 0; + let zeroBlocks = 0; + while (offset < tar.length) { + const header = tar.subarray(offset, offset + 512); + if (header.every((byte) => byte === 0)) { + zeroBlocks += 1; + offset += 512; + if (zeroBlocks >= 2) { + if (posixOnly && offset !== tar.length) { + throw archiveError(file, 'has data after its two-block ustar end marker'); + } + if (tar.subarray(offset).some((byte) => byte !== 0)) { + throw archiveError(file, 'has data after its two-block ustar end marker'); + } + break; + } + continue; + } + if (zeroBlocks !== 0) throw archiveError(file, 'has an incomplete ustar end marker'); + memberCount += 1; + if (memberCount > archiveLimits.maxEntries) { + throw archiveError(file, `exceeds the ${archiveLimits.maxEntries}-entry limit`); + } + const entry = parseTarHeader(header, file, archiveLimits, { source, posixOnly }); + const { name, size } = entry; + const raw = name ?? '.'; + const dataOffset = offset + 512; + const paddedSize = Math.ceil(size / 512) * 512; + if ( + !Number.isSafeInteger(paddedSize) || + dataOffset > tar.length || + paddedSize > tar.length - dataOffset + ) { + throw archiveError(file, `has a truncated ustar payload for ${raw}`); + } + if (tar.subarray(dataOffset + size, dataOffset + paddedSize).some((byte) => byte !== 0)) { + throw archiveError(file, `has non-zero ustar padding for ${raw}`); + } + if (name !== null) { + const data = tar.subarray(dataOffset, dataOffset + size); + entries.push({ ...entry, data: () => data }); + } + offset = dataOffset + paddedSize; + } + if (zeroBlocks < 2) throw archiveError(file, 'is missing its two-block ustar end marker'); + return checkedEntries(entries, file, archiveLimits); +} + +function decompressedTarBuffer(compressed, file, archiveLimits, compression) { + try { + if (compression === 'gzip') { + return strictGunzip(compressed, file, archiveLimits.maxExpandedBytes); + } + return decompressSingleZstdFrame(compressed, { + label: file, + maxInputBytes: archiveLimits.maxArchiveBytes, + maxOutputBytes: archiveLimits.maxExpandedBytes, + }); + } catch (cause) { + if (cause instanceof Error && cause.message.startsWith('portable-archive:')) throw cause; + throw archiveError(file, `is not a bounded readable ${compression} stream: ${cause.message}`); + } +} + +function readTarBufferEntries(compressed, file, archiveLimits, compression = 'gzip') { + return parseTarEntries( + decompressedTarBuffer(compressed, file, archiveLimits, compression), + file, + archiveLimits, + ); +} + +function readTarEntries(file, archiveLimits, compression = 'gzip') { + return readTarBufferEntries(readFileSync(file), file, archiveLimits, compression); +} + +function inferredFormat(file) { + const lower = file.toLowerCase(); + if ( + lower.endsWith('.zip') || + lower.endsWith('.jar') || + lower.endsWith('.aar') || + lower.endsWith('.apk') + ) { + return 'zip'; + } + if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz') || lower.endsWith('.crate')) { + return 'tar.gz'; + } + if (lower.endsWith('.tar.zst')) return 'tar.zst'; + return undefined; +} + +export function readPortableArchiveEntries(file, options = {}) { + const archiveLimits = limits(options); + requireRegularArchive(file, archiveLimits.maxArchiveBytes); + const format = options.format ?? inferredFormat(file); + if (format === 'zip') return readZipEntries(file, archiveLimits); + if (format === 'tar.gz') return readTarEntries(file, archiveLimits); + if (format === 'tar.zst') return readTarEntries(file, archiveLimits, 'zstd'); + throw archiveError(file, `has an unsupported archive format ${JSON.stringify(format)}`); +} + +/** Source pins additionally permit V7 tar and links, validated before extraction. */ +export function readSourceArchiveEntries(file, options = {}) { + const archiveLimits = limits(options); + requireRegularArchive(file, archiveLimits.maxArchiveBytes); + if (file.endsWith('.zip')) return readZipEntries(file, archiveLimits, { source: true }); + return parseTarEntries( + decompressedTarBuffer(readFileSync(file), file, archiveLimits, 'gzip'), + file, + archiveLimits, + { source: true }, + ); +} + +/** + * Read an Android application package while retaining the portable ZIP safety + * contract. APKs additionally permit Android's local-header alignment padding + * and a structurally framed APK Signing Block immediately before the central + * directory; ordinary ZIP/JAR/AAR readers deliberately do not accept either. + */ +export function readAndroidApkEntries(file, options = {}) { + const archiveLimits = limits(options); + requireRegularArchive(file, archiveLimits.maxArchiveBytes); + return readZipEntries(file, archiveLimits, { androidApk: true }); +} + +/** File-only bundles accepted by the public Android and Swift consumers. */ +export function readFileOnlyTarGzipEntries(file, options = {}) { + const archiveLimits = limits(options); + requireRegularArchive(file, archiveLimits.maxArchiveBytes); + const mode = options.fileMode ?? 0o644; + const compressed = readFileSync(file); + if (compressed[3] !== 0) { + throw archiveError(file, 'must use gzip without optional header sections'); + } + const entries = parseTarEntries( + decompressedTarBuffer(compressed, file, archiveLimits, 'gzip'), + file, + archiveLimits, + { posixOnly: true }, + ); + for (const entry of entries.values()) { + if (!entry.isFile || entry.mode !== mode) { + throw archiveError( + file, + `member ${entry.name} must be a regular mode=${mode.toString(8)} file`, + ); + } + } + return entries; +} + +export function readPortableTarZstdBufferEntries(input, options = {}) { + const archiveLimits = limits(options); + if (!Buffer.isBuffer(input) && !(input instanceof Uint8Array)) { + throw archiveError( + options.label ?? 'nested.tar.zst', + 'must be provided as a Buffer or Uint8Array', + ); + } + const buffer = Buffer.isBuffer(input) + ? input + : Buffer.from(input.buffer, input.byteOffset, input.byteLength); + const label = options.label ?? 'nested.tar.zst'; + if (buffer.length === 0 || buffer.length > archiveLimits.maxArchiveBytes) { + throw archiveError( + label, + `must be non-empty and no larger than ${archiveLimits.maxArchiveBytes} bytes; got ${buffer.length}`, + ); + } + return readTarBufferEntries(buffer, label, archiveLimits, 'zstd'); +} + +/** Validate a decompressed portable tar without retaining file contents in memory. */ +export async function readPortableTarStream(stream, file, options = {}, extraction = undefined) { + if (options.source && extraction) + throw archiveError(file, 'source archives require link-aware extraction'); + const archiveLimits = limits(options); + const entries = []; + let descriptor; + let pending = Buffer.alloc(0); + let payload = 0; + let padding = 0; + let zeroBlocks = 0; + let count = 0; + let expanded = 0; + let rootSeen = false; + let streamed = 0; + try { + for await (const chunk of stream) { + streamed += chunk.length; + if (streamed > archiveLimits.maxExpandedBytes + archiveLimits.maxEntries * 1024 + 10240) + throw archiveError(file, 'exceeds its total stream-size limit'); + let data = Buffer.concat([pending, chunk]); + pending = Buffer.alloc(0); + while (data.length) { + if (payload || padding) { + const size = Math.min(payload || padding, data.length); + if (payload) { + if (descriptor !== undefined) { + let offset = 0; + while (offset < size) { + const written = writeSync(descriptor, data, offset, size - offset); + if (written === 0) throw archiveError(file, 'could not write extracted member'); + offset += written; + } + } + payload -= size; + if (payload === 0 && descriptor !== undefined) { + closeSync(descriptor); + descriptor = undefined; + } + } else { + if (data.subarray(0, size).some((byte) => byte !== 0)) + throw archiveError(file, 'has non-zero ustar padding'); + padding -= size; + } + data = data.subarray(size); + continue; + } + if (data.length < 512) { + pending = Buffer.from(data); + break; + } + const header = data.subarray(0, 512); + data = data.subarray(512); + if (header.every((byte) => byte === 0)) { + zeroBlocks += 1; + continue; + } + if (zeroBlocks) throw archiveError(file, 'has data after its ustar end marker'); + if (++count > archiveLimits.maxEntries) + throw archiveError(file, `exceeds its ${archiveLimits.maxEntries}-entry limit`); + const entry = parseTarHeader(header, file, archiveLimits, { source: options.source }); + expanded += entry.size; + if (expanded > archiveLimits.maxExpandedBytes) + throw archiveError(file, 'exceeds its expanded-data limit'); + payload = entry.size; + padding = (512 - (payload % 512)) % 512; + if (entry.name === null) { + if (rootSeen) throw archiveError(file, 'repeats its root directory'); + rootSeen = true; + } else { + entries.push(entry); + if (extraction && (!extraction.member || extraction.member === entry.name)) { + const output = path.join(extraction.root, entry.name); + if (entry.isDirectory) mkdirSync(output, { recursive: true }); + else { + mkdirSync(path.dirname(output), { recursive: true }); + descriptor = openSync(output, 'wx', entry.mode); + if (payload === 0) { + closeSync(descriptor); + descriptor = undefined; + } + chmodSync(output, entry.mode); + } + } + } + } + } + if (pending.length || payload || padding || zeroBlocks < 2) + throw archiveError(file, 'has a truncated ustar stream'); + return checkedEntries(entries, file, archiveLimits); + } finally { + if (descriptor !== undefined) closeSync(descriptor); + } +} + +export async function readPortableTarGzipInventory(file, options = {}, extraction = undefined) { + requireRegularArchive(file, limits(options).maxArchiveBytes); + const input = createReadStream(file); + const gunzip = zlib.createGunzip(); + input.on('error', (error) => gunzip.destroy(error)); + try { + return await readPortableTarStream(input.pipe(gunzip), file, options, extraction); + } finally { + input.destroy(); + gunzip.destroy(); + } +} + +/** Extract only into a private tree, promoting it after complete stream validation. */ +export async function extractPortableTarGzipTree( + archive, + destination, + options = {}, + member = undefined, +) { + const parent = path.dirname(path.resolve(destination)); + mkdirSync(parent, { recursive: true }); + const temp = mkdtempSync(path.join(parent, '.archive-extract-')); + try { + const entries = await readPortableTarGzipInventory(archive, options, { root: temp, member }); + if (member && !entries.get(member)?.isFile) + throw archiveError(archive, 'is missing regular member ' + member); + for (const entry of [...entries.values()].reverse()) { + if (entry.isDirectory && !member) chmodSync(path.join(temp, entry.name), entry.mode); + } + chmodSync(temp, 0o755); + rmSync(destination, { recursive: true, force: true }); + renameSync(temp, destination); + } finally { + rmSync(temp, { recursive: true, force: true }); + } +} + +export function extractPortableArchiveTree(archive, destination, sourcePrefix = '', options = {}) { + const root = sourcePrefix.replace(/\/+$/u, ''); + const prefix = root ? root + '/' : ''; + const entries = [...readPortableArchiveEntries(archive, options).values()].filter( + (entry) => (entry.name === root && entry.isDirectory) || entry.name.startsWith(prefix), + ); + if (entries.length === 0) throw archiveError(archive, `is missing directory ${sourcePrefix}`); + const parent = path.dirname(path.resolve(destination)); + mkdirSync(parent, { recursive: true }); + const temp = mkdtempSync(path.join(parent, '.archive-extract-')); + try { + for (const entry of entries) { + const output = path.join(temp, entry.name.slice(prefix.length)); + if (entry.isDirectory) { + mkdirSync(output, { recursive: true }); + } else { + mkdirSync(path.dirname(output), { recursive: true }); + writeFileSync(output, entry.data(), { flag: 'wx', mode: entry.mode }); + chmodSync(output, entry.mode); + } + } + for (const entry of entries.filter((entry) => entry.isDirectory).reverse()) { + chmodSync(path.join(temp, entry.name.slice(prefix.length)), entry.mode); + } + rmSync(destination, { recursive: true, force: true }); + renameSync(temp, destination); + chmodSync( + destination, + entries.find((entry) => entry.name === root && entry.isDirectory)?.mode ?? 0o755, + ); + } finally { + rmSync(temp, { recursive: true, force: true }); + } +} + +export function archiveLogicalTreeRows(entries, file, prefix) { + const rows = []; + for (const [name, entry] of entries) { + if (!name.startsWith(prefix) || entry.isDirectory) continue; + if (!entry.isFile) + throw new Error(`${file} member ${name} under ${prefix} must be a regular file`); + rows.push({ + path: name.slice(prefix.length), + bytes: typeof entry.data === 'function' ? entry.data() : entry.data, + }); + } + if (rows.length === 0) throw new Error(`${file} contains no files under ${prefix}`); + return rows; +} diff --git a/tools/packaging/portable-archive.test.mts b/tools/packaging/portable-archive.test.mts new file mode 100644 index 000000000..ca3a661ad --- /dev/null +++ b/tools/packaging/portable-archive.test.mts @@ -0,0 +1,839 @@ +import assert from 'node:assert/strict'; +import { + closeSync, + mkdirSync, + mkdtempSync, + openSync, + rmSync, + symlinkSync, + writeFileSync, + writeSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { gunzipSync, gzipSync, constants as zlibConstants, zstdCompressSync } from 'node:zlib'; +import { archiveDirectory } from './archive-directory.mts'; + +import { + canonicalGzipSync, + DEFAULT_PORTABLE_ARCHIVE_LIMITS, + decompressSingleZstdFrame, + normalizeCanonicalGzipHeader, + portableMemberName, + RELEASE_ZSTD_COMPRESSION_LEVEL, + readAndroidApkEntries, + readFileOnlyTarGzipEntries, + readPortableArchiveEntries, + readPortableTarStream, + readPortableTarZstdBufferEntries, + releaseZstdCompressSync, + validateZipEntryTypes, +} from './portable-archive.mts'; + +test('exposes the same portable member contract to nested carrier consumers', () => { + const archive = '/tmp/carrier.tar.gz'; + const member = 'carrier/extensions/postgis/postgis-ios-xcframework.tar.gz'; + assert.equal(portableMemberName(member, 'file', archive), member); + assert.throws( + () => portableMemberName('carrier/extensions/postgis/../escape', 'file', archive), + /unsafe archive member/u, + ); + assert.throws( + () => portableMemberName('carrier/extensions/postgis/file/', 'file', archive), + /type\/path-marker mismatch/u, + ); +}); + +import { zipArchive } from './testdata/zip-fixture.mts'; + +function androidAlignmentExtra(alignment, paddingLength, paddingByte = 0) { + const extra = Buffer.alloc(6 + paddingLength, paddingByte); + extra.writeUInt16LE(0xd935, 0); + extra.writeUInt16LE(2 + paddingLength, 2); + extra.writeUInt16LE(alignment, 4); + return extra; +} + +function apkSigningBlock(pairs = [{ id: 0x7109871a, data: 'signature' }]) { + const pairBuffers = pairs.map(({ id, data }) => { + const value = Buffer.from(data); + const pair = Buffer.alloc(12 + value.length); + pair.writeBigUInt64LE(BigInt(4 + value.length), 0); + pair.writeUInt32LE(id, 8); + value.copy(pair, 12); + return pair; + }); + const pairBytes = Buffer.concat(pairBuffers); + const size = 24 + pairBytes.length; + const header = Buffer.alloc(8); + const footer = Buffer.alloc(8); + header.writeBigUInt64LE(BigInt(size), 0); + footer.writeBigUInt64LE(BigInt(size), 0); + return Buffer.concat([header, pairBytes, footer, Buffer.from('APK Sig Block 42', 'ascii')]); +} + +import { tarArchive, tarOctal } from './testdata/tar-fixture.mts'; + +function refreshFirstTarChecksum(tar) { + tar.fill(0x20, 148, 156); + const checksum = tar.subarray(0, 512).reduce((sum, byte) => sum + byte, 0); + Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `, 'ascii').copy(tar, 148); +} + +function fixtureFile(t, name, bytes) { + const root = mkdtempSync(path.join(tmpdir(), 'portable-archive-test-')); + t.after(() => rmSync(root, { force: true, recursive: true })); + const file = path.join(root, name); + writeFileSync(file, bytes); + return { file, root }; +} + +test('uses a runner-safe default archive memory envelope', () => { + assert.deepEqual(DEFAULT_PORTABLE_ARCHIVE_LIMITS, { + maxArchiveBytes: 512 * 1024 * 1024, + maxEntries: 32_768, + maxEntryBytes: 512 * 1024 * 1024, + maxExpandedBytes: 1024 * 1024 * 1024, + }); +}); + +test('canonicalizes host-derived gzip metadata without changing payload or caller bytes', () => { + const payload = Buffer.from('portable gzip payload\n'); + const hostArchive = Buffer.from(gzipSync(payload, { mtime: 0 })); + hostArchive.fill(0x7f, 4, 9); + hostArchive[9] = 0x07; + const original = Buffer.from(hostArchive); + + const canonical = normalizeCanonicalGzipHeader(hostArchive); + assert.deepEqual( + canonical.subarray(0, 10), + Buffer.from([0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03]), + ); + assert.deepEqual(gunzipSync(canonical), payload); + assert.deepEqual(hostArchive, original); + assert.throws( + () => normalizeCanonicalGzipHeader(Buffer.from('not gzip')), + /flag-free gzip stream/u, + ); +}); + +test('uses the shared level-19 Zstandard release setting', () => { + const payload = Buffer.from('portable Zstandard payload\n'); + assert.equal(RELEASE_ZSTD_COMPRESSION_LEVEL, 19); + assert.deepEqual( + releaseZstdCompressSync(payload), + zstdCompressSync(payload, { + params: { + [zlibConstants.ZSTD_c_compressionLevel]: 19, + }, + }), + ); +}); + +test('reads a strict ZIP and validates payload bytes', async (t) => { + const { file } = fixtureFile(t, 'valid.zip', zipArchive([{ name: 'root/file.txt', data: 'ok' }])); + const entries = readPortableArchiveEntries(file); + assert.deepEqual([...entries.keys()], ['root/file.txt']); + assert.equal(entries.get('root/file.txt').data().toString(), 'ok'); +}); + +test('accepts an unambiguous FAT-origin ZIP member', async (t) => { + const { file } = fixtureFile( + t, + 'fat.zip', + zipArchive([{ name: 'file.txt', versionMadeBy: 0x0014, externalAttributes: 0 }]), + ); + assert.equal(readPortableArchiveEntries(file).get('file.txt').isFile, true); +}); + +test('accepts Android legacy and 0xd935 alignment only in the APK profile', async (t) => { + // This reproduces the exact two zero bytes on the AGP-produced + // assets/dexopt/baseline.prof that exposed the release failure. The leading + // record puts its data at a four-byte-aligned offset. + const legacy = fixtureFile( + t, + 'legacy-aligned.apk', + zipArchive([ + { name: 'aaaa' }, + { name: 'assets/dexopt/baseline.prof', data: 'profile', localExtra: Buffer.alloc(2) }, + ]), + ).file; + assert.throws(() => readPortableArchiveEntries(legacy), /truncated ZIP local/u); + assert.equal( + readAndroidApkEntries(legacy).get('assets/dexopt/baseline.prof').data().toString(), + 'profile', + ); + + // Official apksigner rewrites the same member to d935,size=3,alignment=4, + // one zero byte; with this path the payload begins at byte offset 64. + const structured = fixtureFile( + t, + 'structured-aligned.apk', + zipArchive([ + { + name: 'assets/dexopt/baseline.prof', + data: 'profile', + localExtra: androidAlignmentExtra(4, 1), + }, + ]), + ).file; + assert.throws(() => readPortableArchiveEntries(structured), /unsupported ZIP local/u); + assert.equal( + readAndroidApkEntries(structured).get('assets/dexopt/baseline.prof').data().toString(), + 'profile', + ); + + const sharedLibraryName = 'lib/arm64-v8a/liboliphaunt.so'; + const unpaddedSharedLibraryOffset = 30 + Buffer.byteLength(sharedLibraryName) + 6; + const sharedLibraryPadding = + (16 * 1024 - (unpaddedSharedLibraryOffset % (16 * 1024))) % (16 * 1024); + const sharedLibrary = fixtureFile( + t, + 'structured-shared-library.apk', + zipArchive([ + { + name: sharedLibraryName, + data: 'ELF', + localExtra: androidAlignmentExtra(16 * 1024, sharedLibraryPadding), + }, + ]), + ).file; + assert.equal( + readAndroidApkEntries(sharedLibrary).get(sharedLibraryName).data().toString(), + 'ELF', + ); +}); + +test('rejects malformed or misplaced Android alignment metadata', async (t) => { + const cases = [ + [ + 'legacy-unaligned.apk', + { name: 'assets/dexopt/baseline.prof', localExtra: Buffer.alloc(2) }, + /malformed legacy APK alignment/u, + ], + [ + 'legacy-nonzero.apk', + { name: 'assets/dexopt/baseline.prof', localExtra: Buffer.from([0, 1]) }, + /truncated ZIP local/u, + ], + [ + 'alignment-too-short.apk', + { name: 'assets/dexopt/baseline.prof', localExtra: Buffer.from([0x35, 0xd9, 1, 0, 4]) }, + /malformed APK alignment/u, + ], + [ + 'alignment-nonzero.apk', + { name: 'assets/dexopt/baseline.prof', localExtra: androidAlignmentExtra(4, 1, 1) }, + /malformed APK alignment/u, + ], + [ + 'alignment-unaligned.apk', + { name: 'assets/dexopt/baseline.prof', localExtra: androidAlignmentExtra(4, 0) }, + /malformed APK alignment/u, + ], + [ + 'alignment-wrong-multiple.apk', + { name: 'assets/dexopt/baseline.prof', localExtra: androidAlignmentExtra(8, 5) }, + /malformed APK alignment/u, + ], + [ + 'alignment-redundant.apk', + { name: 'assets/dexopt/baseline.prof', localExtra: androidAlignmentExtra(4, 5) }, + /malformed APK alignment/u, + ], + [ + 'alignment-compressed.apk', + { + name: 'assets/dexopt/baseline.prof', + method: 8, + localExtra: androidAlignmentExtra(4, 1), + }, + /alignment metadata on compressed/u, + ], + [ + 'alignment-central.apk', + { name: 'assets/dexopt/baseline.prof', centralExtra: androidAlignmentExtra(4, 1) }, + /unsupported ZIP central/u, + ], + [ + 'alignment-not-last.apk', + { + name: 'assets/dexopt/baseline.prof', + localExtra: Buffer.concat([ + androidAlignmentExtra(4, 1), + Buffer.from([0x55, 0x54, 5, 0, 1, 0, 0, 0, 0]), + ]), + }, + /does not place APK alignment ZIP metadata last/u, + ], + ]; + for (const [name, row, pattern] of cases) { + const file = fixtureFile(t, name, zipArchive([row])).file; + assert.throws(() => readAndroidApkEntries(file), pattern); + } +}); + +test('accepts a framed APK Signing Block and unknown extension pairs', async (t) => { + const block = apkSigningBlock([ + { id: 0x504b4453, data: 'unknown-but-framed' }, + { id: 0x7109871a, data: 'v2-signature-container' }, + ]); + for (const descriptor of [undefined, 'unsigned', 'signed']) { + const file = fixtureFile( + t, + `signed-${descriptor ?? 'none'}.apk`, + zipArchive([{ name: 'AndroidManifest.xml', data: 'manifest', descriptor }], { + beforeCentral: block, + }), + ).file; + assert.throws(() => readPortableArchiveEntries(file), /ambiguous .*gap/u); + assert.equal( + readAndroidApkEntries(file).get('AndroidManifest.xml').data().toString(), + 'manifest', + ); + } + + const manifestRecordBytes = + 30 + Buffer.byteLength('AndroidManifest.xml') + Buffer.byteLength('manifest'); + const canonicalPadding = 4096 - manifestRecordBytes; + const padded = fixtureFile( + t, + 'signed-canonical-padding.apk', + zipArchive([{ name: 'AndroidManifest.xml', data: 'manifest' }], { + beforeCentral: Buffer.concat([Buffer.alloc(canonicalPadding), block]), + }), + ).file; + assert.equal( + readAndroidApkEntries(padded).get('AndroidManifest.xml').data().toString(), + 'manifest', + ); +}); + +test('rejects malformed APK Signing Block gaps and descriptors', async (t) => { + const valid = apkSigningBlock(); + const badHeaderSize = Buffer.from(valid); + badHeaderSize.writeBigUInt64LE(badHeaderSize.readBigUInt64LE(0) + 1n, 0); + const badPairSize = Buffer.from(valid); + badPairSize.writeBigUInt64LE(3n, 8); + const unknownOnly = apkSigningBlock([{ id: 0x504b4453, data: 'extension' }]); + const duplicatePair = apkSigningBlock([ + { id: 0x7109871a, data: 'first' }, + { id: 0x7109871a, data: 'second' }, + ]); + const cases = [ + ['opaque-gap.apk', Buffer.alloc(32, 1), /unrecognized gap/u], + ['nonzero-padding.apk', Buffer.concat([Buffer.from([1]), valid]), /non-zero padding/u], + [ + 'noncanonical-zero-padding.apk', + Buffer.concat([Buffer.alloc(17), valid]), + /non-canonical zero padding/u, + ], + ['size-mismatch.apk', badHeaderSize, /disagreeing APK Signing Block sizes/u], + ['bad-pair.apk', badPairSize, /invalid APK Signing Block pair size/u], + ['no-signature-scheme.apk', unknownOnly, /without a v2, v3, or v3[.]1/u], + ['duplicate-pair.apk', duplicatePair, /repeats APK Signing Block pair ID/u], + ]; + for (const [name, beforeCentral, pattern] of cases) { + const file = fixtureFile( + t, + name, + zipArchive([{ name: 'AndroidManifest.xml', data: 'manifest' }], { beforeCentral }), + ).file; + assert.throws(() => readAndroidApkEntries(file), pattern); + } + + const invalidDescriptor = fixtureFile( + t, + 'invalid-descriptor.apk', + zipArchive([{ name: 'AndroidManifest.xml', descriptor: 'signed', descriptorCrc: 0x12345678 }], { + beforeCentral: valid, + }), + ).file; + assert.throws( + () => readAndroidApkEntries(invalidDescriptor), + /invalid or ambiguous ZIP descriptor/u, + ); + + const internalGap = fixtureFile( + t, + 'internal-gap.apk', + zipArchive([{ name: 'first', afterData: Buffer.alloc(4) }, { name: 'second' }]), + ).file; + assert.throws(() => readAndroidApkEntries(internalGap), /ambiguous 4-byte gap/u); +}); + +test('retains entry safety and integrity checks in the Android APK profile', async (t) => { + const cases = [ + ['traversal.apk', [{ name: '../escape' }], /unsafe archive member/u], + ['duplicate.apk', [{ name: 'same' }, { name: 'same' }], /repeats archive member/u], + ['link.apk', [{ name: 'link', externalAttributes: 0o120777 << 16 }], /link or special/u], + ['setid.apk', [{ name: 'file', externalAttributes: 0o104644 << 16 }], /set-id or sticky/u], + ['crc.apk', [{ name: 'file', crc: 0x12345678 }], /CRC-32 mismatch/u], + ]; + for (const [name, rows, pattern] of cases) { + const file = fixtureFile(t, name, zipArchive(rows)).file; + assert.throws(() => readAndroidApkEntries(file), pattern); + } + + const caseSensitive = fixtureFile( + t, + 'aapt-case-sensitive.apk', + zipArchive([{ name: 'res/2F.xml' }, { name: 'res/2f.xml' }]), + ).file; + assert.deepEqual([...readAndroidApkEntries(caseSensitive).keys()], ['res/2F.xml', 'res/2f.xml']); + assert.throws(() => readPortableArchiveEntries(caseSensitive), /case\/NFC-colliding/u); +}); + +test('requires ZIP directory type flags and trailing path markers to agree', async (t) => { + const valid = fixtureFile( + t, + 'directory.zip', + zipArchive([ + { + name: 'root/', + data: '', + externalAttributes: ((0o040755 << 16) | 0x10) >>> 0, + }, + { name: 'root/file.txt', data: 'ok' }, + ]), + ).file; + const entries = readPortableArchiveEntries(valid); + assert.equal(entries.get('root').isDirectory, true); + assert.equal(entries.get('root/file.txt').isFile, true); + + for (const [name, row] of [ + [ + 'missing-marker.zip', + { name: 'root', data: '', externalAttributes: ((0o040755 << 16) | 0x10) >>> 0 }, + ], + ['file-with-marker.zip', { name: 'root/', externalAttributes: 0o100644 << 16 }], + ]) { + const file = fixtureFile(t, name, zipArchive([row])).file; + assert.throws(() => readPortableArchiveEntries(file), /type\/path-marker|directory metadata/u); + } +}); + +test('rejects truncated ZIPs, duplicates, case collisions, and file-parent collisions', async (t) => { + const valid = zipArchive([{ name: 'root/file.txt' }]); + const truncated = fixtureFile(t, 'truncated.zip', valid.subarray(0, valid.length - 1)).file; + assert.throws(() => readPortableArchiveEntries(truncated), /well-formed ZIP end record/u); + + for (const [name, rows, pattern] of [ + ['duplicate.zip', [{ name: 'same' }, { name: 'same' }], /repeats archive member/u], + ['case.zip', [{ name: 'Name' }, { name: 'name' }], /case\/NFC-colliding/u], + ['parent.zip', [{ name: 'parent' }, { name: 'parent/child' }], /as an archive directory/u], + ]) { + const file = fixtureFile(t, name, zipArchive(rows)).file; + assert.throws(() => readPortableArchiveEntries(file), pattern); + } +}); + +test('rejects ZIP links, special entries, unsafe paths, and ambiguous creator types', async (t) => { + const cases = [ + ['symlink.zip', { name: 'link', externalAttributes: 0o120777 << 16 }, /link or special/u], + ['special.zip', { name: 'device', externalAttributes: 0o020666 << 16 }, /link or special/u], + [ + 'unsafe.zip', + { name: '../escape', externalAttributes: 0o100644 << 16 }, + /unsafe archive member/u, + ], + ['ambiguous.zip', { name: 'file', externalAttributes: 0 }, /ambiguous Unix creator type/u], + ]; + for (const [name, row, pattern] of cases) { + const file = fixtureFile(t, name, zipArchive([row])).file; + assert.throws(() => readPortableArchiveEntries(file), pattern); + } +}); + +test('rejects ZIP local-central mismatch, unsupported flags/extras, size bombs, and CRC errors', async (t) => { + const unknownExtra = Buffer.from([0xef, 0xbe, 0x00, 0x00]); + const cases = [ + ['mismatch.zip', { name: 'central', localName: 'local__' }, /name disagreement/u, {}], + ['flags.zip', { name: 'file', flags: 0x2000 }, /unsupported or encrypted ZIP flags/u, {}], + ['extra.zip', { name: 'file', centralExtra: unknownExtra }, /unsupported ZIP central/u, {}], + [ + 'bomb.zip', + { name: 'file', data: '0123456789', method: 8 }, + /entry-size limit/u, + { maxEntryBytes: 5 }, + ], + ['crc.zip', { name: 'file', crc: 0x12345678 }, /CRC-32 mismatch/u, {}], + ['setid.zip', { name: 'file', externalAttributes: 0o104644 << 16 }, /set-id or sticky/u, {}], + ]; + for (const [name, row, pattern, options] of cases) { + const file = fixtureFile(t, name, zipArchive([row])).file; + assert.throws(() => readPortableArchiveEntries(file, options), pattern); + } + + const overlappingBytes = zipArchive([ + { name: 'first', data: 'a' }, + { name: 'second', data: 'b' }, + ]); + const overlapEocd = overlappingBytes.length - 22; + const overlapCentral = overlappingBytes.readUInt32LE(overlapEocd + 16); + overlappingBytes.writeUInt32LE(2, 18); + overlappingBytes.writeUInt32LE(2, 22); + overlappingBytes.writeUInt32LE(2, overlapCentral + 20); + overlappingBytes.writeUInt32LE(2, overlapCentral + 24); + const overlapping = fixtureFile(t, 'overlap.zip', overlappingBytes).file; + assert.throws(() => readPortableArchiveEntries(overlapping), /overlapping ZIP local records/u); + + const aggregate = fixtureFile( + t, + 'aggregate.zip', + zipArchive([ + { name: 'one', data: '1234' }, + { name: 'two', data: '5678' }, + ]), + ).file; + assert.throws( + () => readPortableArchiveEntries(aggregate, { maxEntryBytes: 5, maxExpandedBytes: 7 }), + /expanded ZIP data limit/u, + ); + assert.throws( + () => readPortableArchiveEntries(aggregate, { maxArchiveBytes: 10 }), + /no larger than 10 bytes/u, + ); +}); + +test('reads strict ustar and rejects links, bad checksums, padding, and end markers', async (t) => { + const validBytes = tarArchive([{ name: 'root/file', data: 'ok' }]); + const valid = fixtureFile(t, 'valid.tar.gz', validBytes).file; + assert.equal(readPortableArchiveEntries(valid).get('root/file').data().toString(), 'ok'); + + const linked = fixtureFile(t, 'link.tar.gz', tarArchive([{ name: 'link', type: '2' }])).file; + assert.throws(() => readPortableArchiveEntries(linked), /link or special ustar entry/u); + const device = fixtureFile(t, 'device.tar.gz', tarArchive([{ name: 'device', type: '3' }])).file; + assert.throws(() => readPortableArchiveEntries(device), /link or special ustar entry/u); + + const setid = fixtureFile(t, 'setid.tar.gz', tarArchive([{ name: 'file', mode: 0o4644 }])).file; + assert.throws(() => readPortableArchiveEntries(setid), /set-id or sticky permission bits/u); + + const tar = gunzipForTest(validBytes); + tar[0] ^= 1; + const badChecksum = fixtureFile(t, 'checksum.tar.gz', gzipSync(tar, { mtime: 0 })).file; + assert.throws(() => readPortableArchiveEntries(badChecksum), /header checksum/u); + + const withoutEnd = gunzipForTest(validBytes).subarray(0, 1024); + const badEnd = fixtureFile(t, 'end.tar.gz', gzipSync(withoutEnd, { mtime: 0 })).file; + assert.throws(() => readPortableArchiveEntries(badEnd), /two-block ustar end marker/u); + + const paddedTar = gunzipForTest(validBytes); + paddedTar[512 + 2] = 1; + const badPadding = fixtureFile(t, 'padding.tar.gz', gzipSync(paddedTar, { mtime: 0 })).file; + assert.throws(() => readPortableArchiveEntries(badPadding), /non-zero ustar padding/u); + + assert.throws( + () => readPortableArchiveEntries(valid, { maxExpandedBytes: 1024 }), + /bounded readable gzip stream/u, + ); + + const numericJunkTar = gunzipForTest(validBytes); + numericJunkTar[155] = 'X'.charCodeAt(0); + const numericJunk = fixtureFile(t, 'numeric-junk.tar.gz', gzipSync(numericJunkTar)).file; + assert.throws( + () => readPortableArchiveEntries(numericJunk), + /non-padding bytes after the ustar checksum terminator/u, + ); + + const deviceFieldTar = gunzipForTest(validBytes); + tarOctal(1, 8).copy(deviceFieldTar, 329); + refreshFirstTarChecksum(deviceFieldTar); + const deviceField = fixtureFile(t, 'device-field.tar.gz', gzipSync(deviceFieldTar)).file; + assert.throws( + () => readPortableArchiveEntries(deviceField), + /sets device numbers on non-device/u, + ); + + const linkFieldTar = gunzipForTest(validBytes); + Buffer.from('unexpected-target\0').copy(linkFieldTar, 157); + refreshFirstTarChecksum(linkFieldTar); + const linkField = fixtureFile(t, 'link-field.tar.gz', gzipSync(linkFieldTar)).file; + assert.throws(() => readPortableArchiveEntries(linkField), /sets a link target on non-link/u); +}); + +test('accepts consumer-compatible tar metadata and rejects unsupported bundle formats', async (t) => { + const validBytes = tarArchive([ + { name: 'root/LICENSE', data: 'license\n' }, + { name: 'root/bundle-manifest.json', data: '{}\n' }, + ]); + const valid = fixtureFile(t, 'canonical.tar.gz', validBytes).file; + assert.deepEqual( + [...readFileOnlyTarGzipEntries(valid).keys()], + ['root/LICENSE', 'root/bundle-manifest.json'], + ); + + const wrongGzipHeader = Buffer.from(validBytes); + wrongGzipHeader[9] = 0; + const wrongGzip = fixtureFile(t, 'wrong-gzip-header.tar.gz', wrongGzipHeader).file; + assert.doesNotThrow(() => readFileOnlyTarGzipEntries(wrongGzip)); + + const optionalHeader = Buffer.from(validBytes); + optionalHeader[3] = 8; + assert.throws( + () => readFileOnlyTarGzipEntries(fixtureFile(t, 'optional-header.tar.gz', optionalHeader).file), + /without optional header sections/u, + ); + + const ownerTar = gunzipForTest(validBytes); + Buffer.from('builder\0', 'ascii').copy(ownerTar, 265); + refreshFirstTarChecksum(ownerTar); + const owner = fixtureFile(t, 'owner.tar.gz', canonicalGzipSync(ownerTar)).file; + assert.doesNotThrow(() => readPortableArchiveEntries(owner)); + assert.doesNotThrow(() => readFileOnlyTarGzipEntries(owner)); + + const extraPadding = fixtureFile( + t, + 'extra-padding.tar.gz', + canonicalGzipSync(Buffer.concat([gunzipForTest(validBytes), Buffer.alloc(512)])), + ).file; + assert.throws(() => readFileOnlyTarGzipEntries(extraPadding), /after its two-block/u); + + const gnuTar = gunzipForTest(validBytes); + Buffer.from('ustar \0', 'ascii').copy(gnuTar, 257); + refreshFirstTarChecksum(gnuTar); + assert.throws( + () => readFileOnlyTarGzipEntries(fixtureFile(t, 'gnu.tar.gz', canonicalGzipSync(gnuTar)).file), + /non-POSIX-ustar/u, + ); + + const unsorted = fixtureFile( + t, + 'unsorted.tar.gz', + tarArchive([ + { name: 'root/z', data: 'last' }, + { name: 'root/a', data: 'first' }, + ]), + ).file; + assert.doesNotThrow(() => readPortableArchiveEntries(unsorted)); + assert.doesNotThrow(() => readFileOnlyTarGzipEntries(unsorted)); +}); + +test('accepts POSIX directory type flags and rejects file entries with directory markers', async (t) => { + const valid = fixtureFile( + t, + 'directory.tar.gz', + tarArchive([ + { name: 'root', type: '5', mode: 0o755 }, + { name: 'root/file', data: 'ok' }, + ]), + ).file; + const entries = readPortableArchiveEntries(valid); + assert.equal(entries.get('root').isDirectory, true); + assert.equal(entries.get('root/file').isFile, true); + + const file = fixtureFile( + t, + 'file-with-marker.tar.gz', + tarArchive([{ name: 'root/', type: '0', mode: 0o644 }]), + ).file; + assert.throws(() => readPortableArchiveEntries(file), /type\/path-marker mismatch/u); +}); + +test('rejects trailing bytes, concatenated gzip members, and corrupt gzip trailers', async (t) => { + const valid = tarArchive([{ name: 'file', data: 'payload' }]); + const concatenated = fixtureFile(t, 'concatenated.tar.gz', Buffer.concat([valid, valid])).file; + assert.throws( + () => readPortableArchiveEntries(concatenated), + /trailing data or multiple gzip members/u, + ); + + const trailing = fixtureFile( + t, + 'trailing.tar.gz', + Buffer.concat([valid, Buffer.from('trailing')]), + ).file; + assert.throws(() => readPortableArchiveEntries(trailing), /gzip/u); + + const corrupt = Buffer.from(valid); + corrupt[corrupt.length - 8] ^= 1; + const corruptTrailer = fixtureFile(t, 'corrupt-trailer.tar.gz', corrupt).file; + assert.throws(() => readPortableArchiveEntries(corruptTrailer), /gzip payload CRC-32/u); +}); + +test('reads one Zstandard frame and rejects trailing bytes or concatenated frames', async (t) => { + const tar = gunzipForTest(tarArchive([{ name: 'root/file', data: 'payload' }])); + const valid = zstdCompressSync(tar); + const archive = fixtureFile(t, 'valid.tar.zst', valid).file; + assert.equal(readPortableArchiveEntries(archive).get('root/file').data().toString(), 'payload'); + + const trailing = fixtureFile( + t, + 'trailing.tar.zst', + Buffer.concat([valid, Buffer.from('trailing')]), + ).file; + assert.throws( + () => readPortableArchiveEntries(trailing), + /trailing data or multiple Zstandard frames/u, + ); + + assert.throws( + () => decompressSingleZstdFrame(Buffer.concat([valid, zstdCompressSync(Buffer.alloc(0))])), + /trailing data or multiple Zstandard frames/, + ); + const concatenated = fixtureFile(t, 'concatenated.tar.zst', Buffer.concat([valid, valid])).file; + assert.throws( + () => readPortableArchiveEntries(concatenated), + /trailing data or multiple Zstandard frames/u, + ); +}); + +test('strictly parses an in-memory tar.zst with the same bounded portable contract', () => { + const tar = gunzipForTest( + tarArchive([ + { name: 'oliphaunt/', type: '5', mode: 0o755 }, + { name: 'oliphaunt/bin/', type: '5', mode: 0o755 }, + { name: 'oliphaunt/bin/postgres', data: 'runtime' }, + ]), + ); + const compressed = zstdCompressSync(tar); + const entries = readPortableTarZstdBufferEntries(compressed, { + label: 'nested oliphaunt.wasix.tar.zst', + }); + assert.deepEqual([...entries.keys()], ['oliphaunt', 'oliphaunt/bin', 'oliphaunt/bin/postgres']); + assert.equal(entries.get('oliphaunt/bin/postgres').data().toString(), 'runtime'); + assert.equal(decompressSingleZstdFrame(compressed, { label: 'nested frame' }).equals(tar), true); + + for (const [label, rows, pattern] of [ + [ + 'duplicate', + [ + { name: 'same', data: 'one' }, + { name: 'same', data: 'two' }, + ], + /repeats archive member/u, + ], + ['traversal', [{ name: '../escape', data: 'bad' }], /unsafe archive member/u], + ['symlink', [{ name: 'link', type: '2' }], /link or special ustar entry/u], + ['special', [{ name: 'device', type: '3' }], /link or special ustar entry/u], + ]) { + const candidate = zstdCompressSync(gunzipForTest(tarArchive(rows))); + assert.throws(() => readPortableTarZstdBufferEntries(candidate, { label }), pattern, label); + } + + assert.throws( + () => readPortableTarZstdBufferEntries(Buffer.concat([compressed, compressed])), + /trailing data or multiple Zstandard frames/u, + ); + assert.throws( + () => readPortableTarZstdBufferEntries(compressed, { maxArchiveBytes: compressed.length - 1 }), + /no larger than/u, + ); + assert.throws( + () => decompressSingleZstdFrame(compressed, { maxOutputBytes: tar.length - 1 }), + /bounded readable Zstandard stream/u, + ); +}); + +test('rejects symlink archive inputs before parsing', async (t) => { + const { file, root } = fixtureFile(t, 'real.zip', zipArchive([{ name: 'file' }])); + const linked = path.join(root, 'linked.zip'); + symlinkSync(file, linked); + assert.throws(() => readPortableArchiveEntries(linked), /regular, non-symlink/u); +}); + +test('accepts ZIPs emitted by the canonical archive-directory producer', async (t) => { + const root = mkdtempSync(path.join(tmpdir(), 'portable-producer-test-')); + t.after(() => rmSync(root, { force: true, recursive: true })); + const source = path.join(root, 'Fixture.xcframework'); + mkdirSync(source); + writeFileSync(path.join(source, 'Info.plist'), 'fixture'); + const output = path.join(root, 'fixture.zip'); + await archiveDirectory(source, output, { keepParent: true }); + const entries = readPortableArchiveEntries(output); + assert.equal(entries.get('Fixture.xcframework/Info.plist').data().toString(), 'fixture'); +}); + +function gunzipForTest(buffer) { + return gunzipSync(buffer); +} + +test('streaming portable TAR validates split headers, padding, trailers and limits', async () => { + const tar = gunzipSync(tarArchive([{ name: 'file', data: 'payload' }])); + async function* chunks(bytes, size = 37) { + for (let i = 0; i < bytes.length; i += size) yield bytes.subarray(i, i + size); + } + const entries = await readPortableTarStream(chunks(tar), 'stream.tar'); + assert.equal(entries.get('file').size, 7); + for (const bytes of [ + tar.subarray(0, 513), + tar.subarray(0, -1), + Buffer.concat([tar, Buffer.alloc(512, 1)]), + ]) + await assert.rejects(readPortableTarStream(chunks(bytes), 'stream.tar')); + const padding = Buffer.from(tar); + padding[519] = 1; + await assert.rejects(readPortableTarStream(chunks(padding), 'stream.tar'), /padding/); + await assert.rejects( + readPortableTarStream(chunks(tar), 'stream.tar', { maxExpandedBytes: 6 }), + /expanded/, + ); + await assert.rejects( + readPortableTarStream(chunks(Buffer.alloc(12800)), 'stream.tar', { + maxExpandedBytes: 1, + maxEntries: 1, + }), + /stream-size/, + ); +}); + +test('artifact ZIP type validation supports sparse ZIP64 and rejects unsafe or truncated metadata', async (t) => { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-zip64-')); + t.after(() => rmSync(root, { recursive: true, force: true })); + const file = path.join(root, 'artifact.zip'); + for (const row of [ + { name: 'payload' }, + { name: 'directory/', externalAttributes: 0o40755 << 16, data: '' }, + { name: 'fat', versionMadeBy: 20, externalAttributes: 0x20 }, + { name: 'untyped', externalAttributes: 0o644 << 16 }, + ]) { + writeFileSync(file, zipArchive([row])); + validateZipEntryTypes(file); + } + for (const row of [ + { name: 'encrypted', flags: 1 }, + { name: 'symlink', externalAttributes: 0o120777 << 16 }, + { name: 'device', externalAttributes: 0o20644 << 16 }, + ]) { + writeFileSync(file, zipArchive([row])); + assert.throws(() => validateZipEntryTypes(file), /encrypted, symbolic-link, or special/); + } + const ordinary = zipArchive([{ name: 'payload' }]); + const end = Buffer.from(ordinary.subarray(-22)); + const central = ordinary.subarray(end.readUInt32LE(16), ordinary.length - 22); + const centralOffset = 2 ** 32 + 4096; + const zip64Offset = centralOffset + central.length; + const zip64 = Buffer.alloc(56), + locator = Buffer.alloc(20); + zip64.writeUInt32LE(0x06064b50); + zip64.writeBigUInt64LE(44n, 4); + zip64.writeBigUInt64LE(1n, 24); + zip64.writeBigUInt64LE(1n, 32); + zip64.writeBigUInt64LE(BigInt(central.length), 40); + zip64.writeBigUInt64LE(BigInt(centralOffset), 48); + locator.writeUInt32LE(0x07064b50); + locator.writeBigUInt64LE(BigInt(zip64Offset), 8); + locator.writeUInt32LE(1, 16); + end.writeUInt32LE(0xffffffff, 16); + const fd = openSync(file, 'w'); + try { + writeSync( + fd, + Buffer.concat([central, zip64, locator, end]), + 0, + central.length + 98, + centralOffset, + ); + } finally { + closeSync(fd); + } + validateZipEntryTypes(file); + const badCount = Buffer.from(ordinary); + badCount.writeUInt16LE(2, badCount.length - 14); + badCount.writeUInt16LE(2, badCount.length - 12); + for (const broken of [ordinary.subarray(0, -1), badCount]) { + writeFileSync(file, broken); + assert.throws(() => validateZipEntryTypes(file), /ZIP/); + } +}); diff --git a/tools/packaging/release-asset-validation.mts b/tools/packaging/release-asset-validation.mts new file mode 100644 index 000000000..124217fdc --- /dev/null +++ b/tools/packaging/release-asset-validation.mts @@ -0,0 +1,41 @@ +import { createHash } from 'node:crypto'; +import fs from 'node:fs/promises'; +import path from 'node:path'; + +import { readPortableArchiveEntries } from './portable-archive.mts'; + +export async function assertFileExists(file) { + const stat = await fs.stat(file).catch(() => null); + return stat?.isFile() === true; +} + +export async function sha256(file) { + return createHash('sha256') + .update(await fs.readFile(file)) + .digest('hex'); +} + +export async function checksumManifest(file, fail, prefix) { + const values = new Map(); + const lines = (await fs.readFile(file, 'utf8')).split(/\r?\n/u); + for (const [index, rawLine] of lines.entries()) { + const line = rawLine.trim(); + if (!line) { + continue; + } + const parts = line.split(/\s+/u); + if (parts.length < 2 || parts[0].length !== 64) { + fail(prefix, `malformed checksum line ${index + 1}: ${rawLine}`); + } + values.set(parts.slice(1).join(' ').replace(/^\.\//u, ''), parts[0].toLowerCase()); + } + return values; +} + +export async function readArchiveEntries(file, fail, prefix, productLabel) { + try { + return readPortableArchiveEntries(file); + } catch (error) { + fail(prefix, `${path.basename(file)} is not a valid ${productLabel} archive: ${error.message}`); + } +} diff --git a/tools/packaging/release-carrier.mts b/tools/packaging/release-carrier.mts new file mode 100644 index 000000000..e1dfc9385 --- /dev/null +++ b/tools/packaging/release-carrier.mts @@ -0,0 +1,649 @@ +import { existsSync } from 'node:fs'; +import path from 'node:path'; +import { ROOT, artifactTargets, compareText } from '../release/release-artifact-targets.mts'; +import { + chmodSync, + copyFileSync, + mkdirSync, + readFileSync, + readdirSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { createHash } from 'node:crypto'; +import { readPortableArchiveEntries } from './portable-archive.mts'; +import { packGeneratedNpmCarrier } from './npm-package.mts'; +import { validateNpmTrustedPublishingManifest } from './npm-trusted-publishing.mts'; +import { + WINDOWS_VC_RUNTIME_RECEIPT, + parseWindowsVcRuntimeReceipt, + windowsVcRuntimeProfileNames, +} from './windows-vc-runtime-closure.mts'; + +export const TOOL = 'package-release-carriers.mts'; + +export function fail(message, exitCode = 1) { + console.error(`${TOOL}: ${message}`); + process.exit(exitCode); +} + +export function rel(file) { + return path.relative(ROOT, file).split(path.sep).join('/'); +} + +function sortedStrings(values) { + return [...values].sort(compareText); +} + +export function assertSameStringSet(label, actual, expected) { + const actualSorted = sortedStrings(actual); + const expectedSorted = sortedStrings(expected); + if (JSON.stringify(actualSorted) !== JSON.stringify(expectedSorted)) { + fail( + `${label}: expected=${JSON.stringify(expectedSorted)}, actual=${JSON.stringify(actualSorted)}`, + ); + } +} + +export function isFile(file) { + try { + return statSync(file).isFile(); + } catch { + return false; + } +} + +export function isDirectory(file) { + try { + return statSync(file).isDirectory(); + } catch { + return false; + } +} + +export function sha256File(file) { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} + +function stagedRuntimeInputDirs(envName) { + const raw = process.env[envName] ?? process.env.OLIPHAUNT_RELEASE_ASSET_INPUT_DIRS ?? ''; + return raw + .split(path.delimiter) + .filter(Boolean) + .map((item) => { + const expanded = + item === '~' || item.startsWith('~/') + ? path.join(process.env.HOME ?? '', item.slice(1)) + : item; + return path.isAbsolute(expanded) ? expanded : path.join(ROOT, expanded); + }); +} + +function globRegex(pattern) { + return new RegExp(`^${pattern.split('*').map(escapeRegExp).join('.*')}$`, 'u'); +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&'); +} + +export function copyStagedRuntimeAssets({ product, destination, envName, patterns }) { + const sourceDirs = stagedRuntimeInputDirs(envName); + if (sourceDirs.length === 0) { + fail( + `${product} requires staged runtime artifacts; set ${envName} or OLIPHAUNT_RELEASE_ASSET_INPUT_DIRS to the downloaded CI artifact directory`, + ); + } + mkdirSync(destination, { recursive: true }); + const regexes = patterns.map(globRegex); + let copied = 0; + for (const sourceDir of sourceDirs) { + if (!isDirectory(sourceDir)) { + fail(`${product} release asset input directory does not exist: ${sourceDir}`); + } + for (const name of readdirSync(sourceDir).sort(compareText)) { + if (!regexes.some((regex) => regex.test(name))) { + continue; + } + const source = path.join(sourceDir, name); + if (!isFile(source)) { + continue; + } + const output = path.join(destination, name); + if (isFile(output)) { + if (sha256File(output) !== sha256File(source)) { + fail( + `${product} release asset input collision for ${name}: ${rel(output)} and ${rel(source)} have different bytes`, + ); + } + continue; + } + copyFileSync(source, output); + copied += 1; + } + } + if (copied === 0) { + fail( + `${product} found no staged runtime artifacts matching ${JSON.stringify(patterns)} under ${JSON.stringify(sourceDirs)}`, + ); + } +} + +function npmPackageDirsUnder(packageRoot) { + const packages = new Map(); + if (!isDirectory(packageRoot)) { + fail(`${rel(packageRoot)} does not contain npm package descriptors`); + } + for (const packageDirName of readdirSync(packageRoot).sort(compareText)) { + const packageDir = path.join(packageRoot, packageDirName); + const packageJsonPath = path.join(packageDir, 'package.json'); + if (!isFile(packageJsonPath)) { + continue; + } + let packageJson; + try { + packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')); + } catch (error) { + fail(`${rel(packageJsonPath)} is not valid JSON: ${error.message}`); + } + const packageName = packageJson.name; + if (typeof packageName !== 'string' || packageName.length === 0) { + fail(`${rel(packageJsonPath)} must declare name`); + } + if (packages.has(packageName)) { + fail( + `duplicate npm package name ${packageName} in ${rel(packages.get(packageName))} and ${rel(packageDir)}`, + ); + } + packages.set(packageName, packageDir); + } + if (packages.size === 0) { + fail(`${rel(packageRoot)} does not contain npm package descriptors`); + } + return packages; +} + +export function artifactNpmPackageTargets({ product, kind, surface, packageRoot, version }) { + const packageDirs = npmPackageDirsUnder(packageRoot); + const packages = []; + for (const target of artifactTargets(product, kind, TOOL).filter((candidate) => + candidate.surfaces.includes(surface), + )) { + const packageName = target.npm_package; + if (typeof packageName !== 'string' || packageName.length === 0) { + fail(`${target.id} must declare npm_package for npm artifact package publication`); + } + const packageDir = packageDirs.get(packageName); + if (packageDir === undefined) { + fail(`${target.id} declares unknown npm package ${packageName}`); + } + const packageJson = JSON.parse(readFileSync(path.join(packageDir, 'package.json'), 'utf8')); + if (packageJson.name !== packageName) { + fail(`${rel(packageDir)}/package.json name must be ${packageName}`); + } + if (packageJson.version !== version) { + fail(`${packageName} package version must match ${product} ${version}`); + } + packages.push([packageName, packageDir, target]); + } + const expected = packages.map(([packageName]) => packageName).sort(compareText); + const actual = [...packageDirs.keys()].sort(compareText); + if (JSON.stringify(actual) !== JSON.stringify(expected)) { + fail( + `${rel(packageRoot)} package descriptors must match published ${product} npm artifact targets for ${surface}`, + ); + } + return packages.sort((left, right) => compareText(left[0], right[0])); +} + +export function safeNpmPackageFilenamePrefix(packageName) { + return packageName.replace(/^@/u, '').replace('/', '-'); +} + +function validateNoConsumerInstallScripts(packageJson, context) { + const scripts = packageJson.scripts; + if (scripts === undefined) { + return; + } + if (scripts === null || typeof scripts !== 'object' || Array.isArray(scripts)) { + fail(`${context} scripts must be an object when present`); + } + for (const scriptName of ['preinstall', 'install', 'postinstall', 'prepare']) { + if (Object.hasOwn(scripts, scriptName)) { + fail(`${context} must not declare consumer install lifecycle script ${scriptName}`); + } + } +} + +function npmPackageSourceStageDir(packageName) { + return path.join( + ROOT, + 'target/release/npm-package-sources', + safeNpmPackageFilenamePrefix(packageName), + ); +} + +export function stageNpmPackageDescriptor( + packageName, + sourceDir, + version, + { extraDescriptors = [], target = null } = {}, +) { + const stageDir = npmPackageSourceStageDir(packageName); + rmSync(stageDir, { recursive: true, force: true }); + mkdirSync(stageDir, { recursive: true }); + for (const descriptor of ['package.json', 'README.md', ...extraDescriptors]) { + const source = path.join(sourceDir, descriptor); + if (!isFile(source)) { + fail(`${rel(sourceDir)} is missing ${descriptor}`); + } + copyFileSync(source, path.join(stageDir, descriptor)); + } + const packageJsonPath = path.join(stageDir, 'package.json'); + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8')); + if (packageJson.name !== packageName) { + fail(`${rel(packageJsonPath)} name must be ${packageName}`); + } + if (packageJson.version !== version) { + fail(`${packageName} package version must match ${version}`); + } + if (target !== null && packageJson.oliphaunt?.target !== target) { + fail(`${packageName} package oliphaunt.target must be ${target}`); + } + validateNoConsumerInstallScripts(packageJson, `${packageName} npm package`); + return stageDir; +} + +function readReleaseArchiveMember(archive, memberName) { + const entry = readPortableArchiveEntries(archive).get(memberName); + if (!entry?.isFile) fail(`${rel(archive)} is missing regular file ${memberName}`); + return entry.data(); +} + +export function extractReleaseArchiveFile(archive, memberName, destination, { mode = null } = {}) { + const data = readReleaseArchiveMember(archive, memberName); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, data); + if (mode !== null) { + chmodSync(destination, mode); + } +} + +export function packStagedNpmCarrier(packageDir) { + return packGeneratedNpmCarrier(packageDir, path.join(ROOT, 'target/release/npm-packages')); +} + +export function validatePackedNpmPackage({ + packageName, + version, + tarball, + requiredMembers, + executableMembers = [], +}) { + let entries; + try { + entries = readPortableArchiveEntries(tarball); + } catch (error) { + fail(`${rel(tarball)} is not a valid npm tarball: ${error.message}`); + } + if (!entries.has('package/package.json')) { + fail(`${rel(tarball)} is missing package/package.json`); + } + let packageJson; + try { + const packageData = entries.get('package/package.json')?.data() ?? null; + if (packageData === null) { + fail(`${rel(tarball)} package/package.json could not be read`); + } + packageJson = JSON.parse(packageData.toString('utf8')); + } catch (error) { + fail(`${rel(tarball)} package/package.json is not valid JSON: ${error.message}`); + } + if (packageJson.name !== packageName) { + fail( + `${rel(tarball)} package name must be ${packageName}, got ${JSON.stringify(packageJson.name)}`, + ); + } + if (packageJson.version !== version) { + fail( + `${rel(tarball)} package version must be ${version}, got ${JSON.stringify(packageJson.version)}`, + ); + } + try { + validateNpmTrustedPublishingManifest(packageJson, `${rel(tarball)} package/package.json`); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } + for (const member of requiredMembers) { + const entry = entries.get(member); + if (entry === undefined) { + fail(`${rel(tarball)} is missing ${member}`); + } + if (!entry.isFile || entry.size <= 0) { + fail(`${rel(tarball)} ${member} must be a non-empty regular file`); + } + } + for (const member of executableMembers) { + const entry = entries.get(member); + if (entry === undefined) { + fail(`${rel(tarball)} is missing executable ${member}`); + } + if (!entry.isFile || entry.size <= 0 || (entry.mode & 0o111) === 0) { + fail(`${rel(tarball)} ${member} must be a non-empty executable file`); + } + } + return packageJson; +} + +export function stageWindowsVcRuntimeMembers( + archive, + stage, + target, + prefix, + { alreadyExtracted = false, profile } = {}, +) { + if (target !== 'windows-x64-msvc') return []; + const normalizedPrefix = prefix.replace(/\/+$/u, ''); + const receiptMember = `${normalizedPrefix}/${WINDOWS_VC_RUNTIME_RECEIPT}`; + const receiptPath = path.join(stage, ...receiptMember.split('/')); + extractReleaseArchiveFile(archive, receiptMember, receiptPath); + const receipt = parseWindowsVcRuntimeReceipt( + readFileSync(receiptPath), + `${rel(archive)}:${receiptMember}`, + ); + const names = [...receipt.keys()].sort(compareText); + if (profile !== undefined) { + assertSameStringSet( + `${rel(archive)} ${normalizedPrefix} ${profile} VC runtime profile`, + names, + windowsVcRuntimeProfileNames(profile), + ); + } + for (const name of names) { + const member = `${normalizedPrefix}/${name}`; + const destination = path.join(stage, ...member.split('/')); + const expectedDigest = receipt.get(name); + if (!alreadyExtracted || !isFile(destination) || sha256File(destination) !== expectedDigest) { + extractReleaseArchiveFile(archive, member, destination); + } + if (!isFile(destination) || sha256File(destination) !== expectedDigest) { + fail(`${rel(archive)} exact VC runtime member ${member} does not match ${receiptMember}`); + } + } + return [receiptMember, ...names.map((name) => `${normalizedPrefix}/${name}`)]; +} + +export const PREFIX = 'artifact-packaging'; + +export function readJson(file) { + let data; + try { + data = JSON.parse(readFileSync(file, 'utf8')); + } catch (error) { + fail(`${rel(file)} is not valid JSON: ${error.message}`); + } + if (data === null || Array.isArray(data) || typeof data !== 'object') { + fail(`${rel(file)} must contain a JSON object`); + } + return data; +} + +export function parseUniquePropertiesText(text) { + const entries = new Map(); + for (const raw of text.split(/\r?\n/u)) { + const line = raw.trim(); + if (!line || line.startsWith('#')) { + continue; + } + const equals = line.indexOf('='); + if (equals < 0) { + throw new Error(`invalid properties line: ${JSON.stringify(raw)}`); + } + const key = line.slice(0, equals); + if (!key) { + throw new Error(`properties key must not be empty: ${JSON.stringify(raw)}`); + } + if (entries.has(key)) { + throw new Error(`properties text repeats key ${JSON.stringify(key)}`); + } + entries.set(key, line.slice(equals + 1)); + } + // Object.fromEntries defines every key as data, including names such as + // __proto__. Exact manifest comparison can therefore reject hostile or + // undeclared keys instead of losing them through prototype assignment. + return Object.fromEntries(entries); +} + +export function readPropertiesText(text) { + try { + return parseUniquePropertiesText(text); + } catch (error) { + fail(error.message); + } +} + +export const ARCHIVE_ENTRY_CACHE = new Map(); + +export const ARCHIVE_ENTRY_CACHE_LIMIT = 2; + +export function strictArchiveEntries(file, format) { + const fileStat = statSync(file, { bigint: true }); + const cacheKey = [ + format, + path.resolve(file), + fileStat.dev, + fileStat.ino, + fileStat.size, + fileStat.mtimeNs, + fileStat.ctimeNs, + ].join('\0'); + const cached = ARCHIVE_ENTRY_CACHE.get(cacheKey); + if (cached !== undefined) { + ARCHIVE_ENTRY_CACHE.delete(cacheKey); + ARCHIVE_ENTRY_CACHE.set(cacheKey, cached); + return cached; + } + let entries; + try { + entries = readPortableArchiveEntries(file, { format }); + } catch (error) { + fail(`${rel(file)} is not a strict portable ${format} archive: ${error.message}`); + } + ARCHIVE_ENTRY_CACHE.set(cacheKey, entries); + while (ARCHIVE_ENTRY_CACHE.size > ARCHIVE_ENTRY_CACHE_LIMIT) { + ARCHIVE_ENTRY_CACHE.delete(ARCHIVE_ENTRY_CACHE.keys().next().value); + } + return entries; +} + +export function archiveTarNames(file) { + return [...strictArchiveEntries(file, 'tar.gz')] + .filter(([, entry]) => entry.isFile) + .map(([name]) => name) + .sort(compareText); +} + +export function readZipEntries(file) { + return strictArchiveEntries(file, 'zip'); +} + +export function archiveZipNames(file) { + return [...readZipEntries(file)] + .filter(([, entry]) => entry.isFile) + .map(([name]) => name) + .sort(compareText); +} + +const SDK_ROOT = path.join(ROOT, 'target/sdk-artifacts'); + +const SDK_RUNTIME_PAYLOAD_PATTERNS = [ + /(^|\/)assets\/oliphaunt\/runtime\//u, + /(^|\/)assets\/oliphaunt\/cluster-seed\//u, + /(^|\/)assets\/oliphaunt\/static-registry\/archives\//u, + /(^|\/)oliphaunt\/runtime\/files\//u, + /(^|\/)runtime\/files\/share\/postgresql\//u, + /(^|\/)share\/postgresql\/extension\/[^/]+\.(control|sql)$/u, + /(^|\/)release-assets\//u, + /(^|\/)extension-artifacts\.json$/u, + /(^|\/)liboliphaunt\.(so|dylib|dll|a|lib)$/u, + /(^|\/)liboliphaunt_extensions\.(so|dylib|dll|a|lib)$/u, + /(^|\/)liboliphaunt_extension_[^/]+\.(so|dylib|dll|a|lib)$/u, + /\.xcframework(\/|$)/u, +]; + +const KOTLIN_ALLOWED_NATIVE_PAYLOADS = new Set(['liboliphaunt_mobile_bindings.so']); + +export function tarReadBytes(file, member) { + const entry = strictArchiveEntries(file, 'tar.gz').get(member); + if (!entry?.isFile) fail(`${rel(file)} is missing regular-file member ${member}`); + return Buffer.from(entry.data()); +} + +export function tarReadText(file, member) { + return tarReadBytes(file, member).toString('utf8'); +} + +export function cargoCrateManifest(file) { + const manifests = archiveTarNames(file).filter( + (name) => name.split('/').length === 2 && name.endsWith('/Cargo.toml'), + ); + if (manifests.length !== 1) { + fail(`${rel(file)} must contain exactly one top-level Cargo.toml`); + } + let data; + try { + data = Bun.TOML.parse(tarReadText(file, manifests[0])); + } catch (error) { + fail(`${rel(file)} contains an invalid Cargo.toml: ${error.message}`); + } + if (data === null || Array.isArray(data) || typeof data !== 'object') { + fail(`${rel(file)} Cargo.toml must contain a TOML table`); + } + return data; +} + +const CARGO_VIRTUAL_PACKAGE_FILES = new Set([ + '.cargo_vcs_info.json', + 'Cargo.lock', + 'Cargo.toml.orig', +]); + +export function cargoPackageMemberContractViolation(actual, listed) { + if (new Set(listed).size !== listed.length) { + return { kind: 'listing-duplicate' }; + } + const expected = listed.filter((entry) => !CARGO_VIRTUAL_PACKAGE_FILES.has(entry)); + const actualSorted = [...actual].sort(compareText); + const expectedSorted = [...expected].sort(compareText); + if (JSON.stringify(actualSorted) !== JSON.stringify(expectedSorted)) { + return { kind: 'mismatch', actual: actualSorted, expected: expectedSorted }; + } + return null; +} + +export function requireCrateMatchesCargoListing(crate, listing, packageName, packageVersion) { + if (!isFile(listing)) { + fail(`missing Cargo package listing: ${rel(listing)}`); + } + const listed = readFileSync(listing, 'utf8') + .split(/\r?\n/u) + .map((entry) => entry.trim()) + .filter(Boolean); + const prefix = `${packageName}-${packageVersion}/`; + const actual = archiveTarNames(crate).map((entry) => { + if (!entry.startsWith(prefix) || entry.length === prefix.length) { + fail(`${rel(crate)} contains member outside ${prefix.slice(0, -1)}: ${entry}`); + } + return entry.slice(prefix.length); + }); + const violation = cargoPackageMemberContractViolation(actual, listed); + if (violation?.kind === 'listing-duplicate') { + fail(`${rel(listing)} repeats a Cargo package entry`); + } + if (violation?.kind === 'mismatch') { + fail( + `${rel(crate)} Cargo-selected package members mismatch: ` + + `expected=${JSON.stringify(violation.expected)}, actual=${JSON.stringify(violation.actual)}`, + ); + } +} + +export function directoryNames(root) { + const result = []; + const visit = (dir) => { + if (!isDirectory(dir)) { + return; + } + for (const name of readdirSync(dir).sort(compareText)) { + const file = path.join(dir, name); + if (isDirectory(file)) { + visit(file); + } else if (isFile(file)) { + result.push(relFrom(root, file)); + } + } + }; + visit(root); + return result.sort(compareText); +} + +function relFrom(root, file) { + return path.relative(root, file).split(path.sep).join('/'); +} + +export function findSdkRuntimePayloadViolation(product, names, allowedNames = new Set()) { + for (const name of names) { + if (allowedNames.has(name)) { + continue; + } + const basename = path.basename(name); + if (product === 'oliphaunt-kotlin' && KOTLIN_ALLOWED_NATIVE_PAYLOADS.has(basename)) { + continue; + } + for (const pattern of SDK_RUNTIME_PAYLOAD_PATTERNS) { + if (pattern.test(name)) { + return name; + } + } + } + return null; +} + +export function rejectSdkRuntimePayload(product, artifact, names, allowedNames = new Set()) { + const violation = findSdkRuntimePayloadViolation(product, names, allowedNames); + if (violation !== null) { + fail( + `${product} SDK artifact ${rel(artifact)} must not include runtime/extension payload ${violation}`, + ); + } +} + +export async function inspectSdkProduct(product, inspect) { + const root = path.join(SDK_ROOT, product); + if (!existsSync(root)) fail(`missing staged SDK artifacts for ${product} under ${rel(root)}`); + const checked = await inspect(root); + if (!checked) + fail(`${product} did not contain any inspectable staged package artifacts under ${rel(root)}`); + console.log(`validated SDK artifact cleanliness: ${product}`); + return checked; +} + +export function walkFiles(root) { + if (!isDirectory(root)) { + return []; + } + const result = []; + const visit = (dir) => { + for (const name of readdirSync(dir).sort(compareText)) { + const file = path.join(dir, name); + if (isDirectory(file)) { + visit(file); + } else if (isFile(file)) { + result.push(file); + } + } + }; + visit(root); + return result; +} diff --git a/tools/packaging/release-carrier.test.mts b/tools/packaging/release-carrier.test.mts new file mode 100644 index 000000000..7281f877a --- /dev/null +++ b/tools/packaging/release-carrier.test.mts @@ -0,0 +1,53 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import { + cargoPackageMemberContractViolation, + parseUniquePropertiesText, +} from './release-carrier.mts'; + +test('Cargo packages exactly match their complete package listing', () => { + const listed = ['Cargo.toml', 'LICENSE', 'README.md', 'THIRD_PARTY_NOTICES.md', 'src/lib.rs']; + assert.equal(cargoPackageMemberContractViolation(listed, listed), null); + + const unexpected = cargoPackageMemberContractViolation([...listed, 'UNDECLARED.md'], listed); + assert.deepEqual(unexpected, { + kind: 'mismatch', + actual: [ + 'Cargo.toml', + 'LICENSE', + 'README.md', + 'THIRD_PARTY_NOTICES.md', + 'UNDECLARED.md', + 'src/lib.rs', + ], + expected: ['Cargo.toml', 'LICENSE', 'README.md', 'THIRD_PARTY_NOTICES.md', 'src/lib.rs'], + }); + + assert.deepEqual(cargoPackageMemberContractViolation(listed, [...listed, 'LICENSE']), { + kind: 'listing-duplicate', + }); +}); + +test('preserves hostile property names and rejects repeated keys', () => { + const hostile = parseUniquePropertiesText('__proto__=undeclared\n'); + assert.equal(Object.hasOwn(hostile, '__proto__'), true); + assert.equal(hostile.__proto__, 'undeclared'); + assert.throws( + () => + parseUniquePropertiesText( + 'asset.native.ios-xcframework.runtime=first.tar.gz\nasset.native.ios-xcframework.runtime=second.tar.gz\n', + ), + /repeats key "asset\.native\.ios-xcframework\.runtime"/u, + ); + assert.throws( + () => + parseUniquePropertiesText( + 'asset.native.ios-xcframework.ios-dependency-xcframework=geos.zip\nasset.native.ios-xcframework.ios-dependency-xcframework=geos-c.zip\n', + ), + /repeats key "asset\.native\.ios-xcframework\.ios-dependency-xcframework"/u, + ); + assert.throws( + () => parseUniquePropertiesText('__proto__=first\n__proto__=second\n'), + /repeats key "__proto__"/u, + ); +}); diff --git a/tools/packaging/release-directory-safety.mts b/tools/packaging/release-directory-safety.mts new file mode 100644 index 000000000..078ac5e14 --- /dev/null +++ b/tools/packaging/release-directory-safety.mts @@ -0,0 +1,119 @@ +import { lstatSync, mkdirSync, statSync } from 'node:fs'; +import path from 'node:path'; + +const DARWIN_ROOT_DIRECTORY_ALIASES = Object.freeze( + new Map([ + ['etc', 'private/etc'], + ['tmp', 'private/tmp'], + ['var', 'private/var'], + ]), +); + +function hasStableDirectoryIdentity(metadata) { + return ( + metadata?.isDirectory?.() === true && + typeof metadata.dev === 'bigint' && + metadata.dev > 0n && + typeof metadata.ino === 'bigint' && + metadata.ino > 0n + ); +} + +/** + * Canonicalize only Darwin's fixed root-level system directory aliases. + * + * The alias and canonical target must dereference to the same stable device + * and inode. Any inspection failure or mismatch returns the lexical path so + * the caller's lstat-based directory-chain validation fails closed. + * Caller-created aliases outside this fixed set are never followed. + */ +export function canonicalSystemDirectoryPath( + directory, + { platform = process.platform, lstat = lstatSync, stat = statSync } = {}, +) { + if (typeof directory !== 'string' || directory.length === 0) { + throw new TypeError('system directory canonicalization requires a nonempty path'); + } + const resolved = path.resolve(directory); + if (platform !== 'darwin') return resolved; + if (!path.posix.isAbsolute(resolved)) { + throw new Error('Darwin system directory canonicalization requires an absolute POSIX path'); + } + + const relative = path.posix.relative('/', resolved); + const [aliasName, ...suffix] = relative ? relative.split('/') : []; + const canonicalRelative = DARWIN_ROOT_DIRECTORY_ALIASES.get(aliasName); + if (!canonicalRelative) return resolved; + + const alias = path.posix.join('/', aliasName); + const canonicalAlias = path.posix.join('/', canonicalRelative); + let aliasEntry; + let aliasIdentity; + let canonicalIdentity; + try { + aliasEntry = lstat(alias, { bigint: true }); + aliasIdentity = stat(alias, { bigint: true }); + canonicalIdentity = stat(canonicalAlias, { bigint: true }); + } catch { + return resolved; + } + if ( + !aliasEntry.isSymbolicLink() || + !hasStableDirectoryIdentity(aliasIdentity) || + !hasStableDirectoryIdentity(canonicalIdentity) || + aliasIdentity.dev !== canonicalIdentity.dev || + aliasIdentity.ino !== canonicalIdentity.ino + ) { + return resolved; + } + return path.posix.join(canonicalAlias, ...suffix); +} + +/** + * Resolve and validate a complete directory chain without following arbitrary + * symlinks. Missing suffix directories may be created one at a time and are + * always re-inspected before use. + */ +export function requireSafeDirectoryChain( + directory, + { + create = false, + label = 'directory', + mode = 0o755, + platform = process.platform, + lstat = lstatSync, + stat = statSync, + mkdir = mkdirSync, + } = {}, +) { + const resolved = canonicalSystemDirectoryPath(directory, { platform, lstat, stat }); + const filesystemRoot = path.parse(resolved).root; + let cursor = filesystemRoot; + const inspect = (candidate, { allowCreate = false } = {}) => { + let metadata; + try { + metadata = lstat(candidate); + } catch (cause) { + if (cause?.code !== 'ENOENT' || !allowCreate) { + throw new Error(`${label} cannot be inspected: ${candidate}: ${cause.message}`); + } + try { + mkdir(candidate, { mode }); + metadata = lstat(candidate); + } catch (createCause) { + throw new Error(`${label} cannot be created safely: ${candidate}: ${createCause.message}`); + } + } + if (!metadata.isDirectory() || metadata.isSymbolicLink()) { + throw new Error(`${label} must not have a symlink or non-directory ancestor: ${candidate}`); + } + }; + + inspect(cursor); + const relative = path.relative(filesystemRoot, resolved); + for (const part of relative ? relative.split(path.sep) : []) { + cursor = path.join(cursor, part); + inspect(cursor, { allowCreate: create }); + } + return resolved; +} diff --git a/tools/packaging/release-directory-safety.test.mts b/tools/packaging/release-directory-safety.test.mts new file mode 100644 index 000000000..cbe8ef7bc --- /dev/null +++ b/tools/packaging/release-directory-safety.test.mts @@ -0,0 +1,196 @@ +import assert from 'node:assert/strict'; +import { lstatSync, mkdtempSync, mkdirSync, realpathSync, rmSync, symlinkSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; + +import { + canonicalSystemDirectoryPath, + requireSafeDirectoryChain, +} from './release-directory-safety.mts'; + +function directoryIdentity(device, inode) { + return { + dev: BigInt(device), + ino: BigInt(inode), + isDirectory: () => true, + }; +} + +function symbolicLinkMetadata() { + return { + isDirectory: () => false, + isSymbolicLink: () => true, + }; +} + +test('canonicalizes only identity-matching Darwin root directory aliases', () => { + const aliases = new Map([ + ['/etc', { canonical: '/private/etc', identity: directoryIdentity(1, 11) }], + ['/tmp', { canonical: '/private/tmp', identity: directoryIdentity(1, 12) }], + ['/var', { canonical: '/private/var', identity: directoryIdentity(1, 13) }], + ]); + const canonicalIdentities = new Map( + [...aliases.values()].map(({ canonical, identity }) => [canonical, identity]), + ); + const lstat = (file, options) => { + assert.deepEqual(options, { bigint: true }); + if (!aliases.has(file)) throw Object.assign(new Error(`missing ${file}`), { code: 'ENOENT' }); + return symbolicLinkMetadata(); + }; + const stat = (file, options) => { + assert.deepEqual(options, { bigint: true }); + const identity = aliases.get(file)?.identity ?? canonicalIdentities.get(file); + if (!identity) throw Object.assign(new Error(`missing ${file}`), { code: 'ENOENT' }); + return identity; + }; + + assert.equal( + canonicalSystemDirectoryPath('/var/folders/user/stage', { + platform: 'darwin', + lstat, + stat, + }), + '/private/var/folders/user/stage', + ); + assert.equal( + canonicalSystemDirectoryPath('/tmp/stage', { platform: 'darwin', lstat, stat }), + '/private/tmp/stage', + ); + assert.equal( + canonicalSystemDirectoryPath('/etc/oliphaunt', { platform: 'darwin', lstat, stat }), + '/private/etc/oliphaunt', + ); + assert.equal( + canonicalSystemDirectoryPath('/Users/runner/stage', { + platform: 'darwin', + lstat: () => assert.fail('an unrecognized root path must not be inspected as an alias'), + stat: () => assert.fail('an unrecognized root path must not be inspected as an alias'), + }), + '/Users/runner/stage', + ); + assert.equal( + canonicalSystemDirectoryPath('/var/folders/user/stage', { + platform: 'linux', + lstat: () => assert.fail('non-Darwin paths must not inspect system aliases'), + stat: () => assert.fail('non-Darwin paths must not inspect system aliases'), + }), + '/var/folders/user/stage', + ); + + const mismatchedStat = (file, options) => { + if (file === '/var') return stat(file, options); + if (file === '/private/var') return directoryIdentity(1, 99); + throw Object.assign(new Error(`missing ${file}`), { code: 'ENOENT' }); + }; + assert.equal( + canonicalSystemDirectoryPath('/var/folders/user/stage', { + platform: 'darwin', + lstat, + stat: mismatchedStat, + }), + '/var/folders/user/stage', + ); + assert.equal( + canonicalSystemDirectoryPath('/var/folders/user/stage', { + platform: 'darwin', + lstat: () => { + throw Object.assign(new Error('unavailable'), { code: 'EACCES' }); + }, + stat, + }), + '/var/folders/user/stage', + ); + assert.equal( + canonicalSystemDirectoryPath('/var/folders/user/stage', { + platform: 'darwin', + lstat, + stat: (file, options) => (file === '/var' ? stat(file, options) : directoryIdentity(0, 0)), + }), + '/var/folders/user/stage', + ); +}); + +test('creates only missing real suffixes and rejects caller-created aliases', (t) => { + const root = realpathSync(mkdtempSync(path.join(tmpdir(), 'release-directory-safety-'))); + t.after(() => rmSync(root, { recursive: true, force: true })); + const created = path.join(root, 'created', 'suffix'); + assert.equal( + requireSafeDirectoryChain(created, { create: true, label: 'shared test root' }), + created, + ); + assert.equal(lstatSync(created).isDirectory(), true); + + const missing = path.join(root, 'missing', 'suffix'); + assert.throws( + () => requireSafeDirectoryChain(missing, { label: 'shared test root' }), + /cannot be inspected/u, + ); + + const outside = path.join(root, 'outside'); + mkdirSync(outside); + const alias = path.join(root, 'alias'); + symlinkSync(outside, alias, process.platform === 'win32' ? 'junction' : 'dir'); + assert.throws( + () => + requireSafeDirectoryChain(path.join(alias, 'suffix'), { + create: true, + label: 'shared test root', + }), + /symlink or non-directory ancestor/u, + ); +}); + +test('re-inspects created suffixes and rejects a changed canonical target', () => { + const existing = new Set(['/', '/private', '/private/var']); + const inspections = new Map(); + const lstat = (file, options) => { + if (options?.bigint === true && file === '/var') return symbolicLinkMetadata(); + inspections.set(file, (inspections.get(file) ?? 0) + 1); + if (!existing.has(file)) throw Object.assign(new Error(`missing ${file}`), { code: 'ENOENT' }); + return { + isDirectory: () => true, + isSymbolicLink: () => file === '/private/var' && inspections.get(file) > 1, + }; + }; + const stat = () => directoryIdentity(1, 13); + const mkdir = (file, options) => { + assert.deepEqual(options, { mode: 0o755 }); + existing.add(file); + }; + assert.equal( + requireSafeDirectoryChain('/var/new/suffix', { + create: true, + label: 'injected chain', + platform: 'darwin', + lstat, + stat, + mkdir, + }), + '/private/var/new/suffix', + ); + assert.equal(inspections.get('/private/var/new'), 2); + assert.equal(inspections.get('/private/var/new/suffix'), 2); + + assert.throws( + () => + requireSafeDirectoryChain('/var/unsafe', { + create: true, + label: 'injected chain', + platform: 'darwin', + lstat, + stat, + mkdir, + }), + /symlink or non-directory ancestor/u, + ); +}); + +test('accepts the verified Darwin temporary-directory alias', { + skip: process.platform !== 'darwin', +}, (t) => { + const raw = mkdtempSync(path.join(tmpdir(), 'release-directory-safety-darwin-')); + const canonical = realpathSync(raw); + t.after(() => rmSync(canonical, { recursive: true, force: true })); + assert.equal(requireSafeDirectoryChain(raw), canonical); +}); diff --git a/tools/packaging/release-notices.mts b/tools/packaging/release-notices.mts new file mode 100644 index 000000000..67094d01a --- /dev/null +++ b/tools/packaging/release-notices.mts @@ -0,0 +1,750 @@ +#!/usr/bin/env bun + +import { createHash } from 'node:crypto'; + +import { + chmodSync, + copyFileSync, + lstatSync, + mkdirSync, + readFileSync, + readdirSync, + rmSync, +} from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { readPortableArchiveEntries } from './portable-archive.mts'; +import { requireSafeDirectoryChain as requireReleaseDirectoryChain } from './release-directory-safety.mts'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); +const PREFIX = 'release-notices.mts'; + +export const RELEASE_NOTICE_PRODUCTS = Object.freeze(['native', 'wasix']); +export const RELEASE_LICENSE_COMPONENTS = Object.freeze(['postgresql', 'icu', 'openssl']); +export const RELEASE_CARRIER_PROFILES = Object.freeze({ + 'source-sdk': Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), + 'code-facade': Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), + 'node-direct-addon': Object.freeze({ + products: Object.freeze([]), + components: Object.freeze([]), + }), + 'wasix-napi-addon': Object.freeze({ + products: Object.freeze(['wasix']), + components: Object.freeze(['postgresql', 'icu', 'openssl']), + }), + broker: Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), + 'native-runtime': Object.freeze({ + products: Object.freeze(['native']), + components: Object.freeze(['postgresql', 'icu']), + }), + 'native-tools': Object.freeze({ + products: Object.freeze(['native']), + components: Object.freeze(['postgresql']), + }), + 'native-runtime-resources': Object.freeze({ + products: Object.freeze(['native']), + components: Object.freeze(['postgresql']), + }), + 'native-icu-data': Object.freeze({ + products: Object.freeze(['native']), + components: Object.freeze(['icu']), + }), + 'wasix-runtime': Object.freeze({ + products: Object.freeze(['wasix']), + components: Object.freeze(['postgresql', 'icu']), + }), + 'wasix-tools': Object.freeze({ + products: Object.freeze(['wasix']), + components: Object.freeze(['postgresql', 'icu']), + }), + 'wasix-aot': Object.freeze({ + products: Object.freeze(['wasix']), + components: Object.freeze(['postgresql', 'icu']), + }), + 'wasix-icu-data': Object.freeze({ + products: Object.freeze(['wasix']), + components: Object.freeze(['postgresql', 'icu']), + }), + 'wasix-icu-data-crate': Object.freeze({ + products: Object.freeze(['wasix']), + components: Object.freeze(['icu']), + }), + 'contrib-native': Object.freeze({ + products: Object.freeze([]), + components: Object.freeze(['postgresql']), + }), + 'contrib-native-openssl': Object.freeze({ + products: Object.freeze([]), + components: Object.freeze(['postgresql', 'openssl']), + }), + 'contrib-wasix': Object.freeze({ + products: Object.freeze([]), + components: Object.freeze(['postgresql']), + }), + 'contrib-wasix-openssl': Object.freeze({ + products: Object.freeze([]), + components: Object.freeze(['postgresql', 'openssl']), + }), + 'external-native': Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), + 'external-wasix': Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), +}); + +const BASE_ROWS = Object.freeze([ + Object.freeze({ + member: 'LICENSE', + source: path.join(ROOT, 'LICENSE'), + }), + Object.freeze({ + member: 'THIRD_PARTY_NOTICES.md', + source: path.join(ROOT, 'THIRD_PARTY_NOTICES.md'), + }), +]); + +const PRODUCT_NOTICE_ROWS = Object.freeze({ + native: Object.freeze({ + member: 'THIRD_PARTY_NOTICES.liboliphaunt-native.md', + source: path.join(ROOT, 'src/runtimes/liboliphaunt-native/THIRD_PARTY_NOTICES.md'), + }), + wasix: Object.freeze({ + member: 'THIRD_PARTY_NOTICES.oliphaunt-wasix.md', + source: path.join(ROOT, 'src/sdks/rust-wasix/THIRD_PARTY_NOTICES.md'), + }), +}); + +const LICENSE_COMPONENT_ROWS = Object.freeze({ + postgresql: Object.freeze({ + id: 'postgresql', + spdx: 'PostgreSQL', + name: 'PostgreSQL License', + member: 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + source: path.join(ROOT, 'src/third-party/postgres/COPYRIGHT'), + sourceManifest: path.join(ROOT, 'src/third-party/postgres/source.toml'), + sourceVersion: '18.4', + sha256: '3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd', + sourceUrl: 'https://ftp.postgresql.org/pub/source/v18.4/postgresql-18.4.tar.bz2', + sourceIdentity: 'sha256:81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094', + licenseUrl: 'https://github.com/postgres/postgres/blob/REL_18_4/COPYRIGHT', + }), + icu: Object.freeze({ + id: 'icu', + spdx: 'Unicode-3.0', + name: 'Unicode License v3', + member: 'THIRD_PARTY_LICENSES/ICU-LICENSE', + source: path.join(ROOT, 'src/third-party/icu/LICENSE'), + sourceManifest: path.join(ROOT, 'src/third-party/icu/source.toml'), + sourceVersion: '76.1', + sourceBranch: 'release-76-1', + sourceCommit: '8eca245c7484ac6cc179e3e5f7c1ea7680810f39', + sha256: '01edac20612b1e590c1c1cfb02b7218c6adc7b0a944eda7a1e03aeee10725aed', + sourceUrl: 'https://github.com/unicode-org/icu.git', + sourceIdentity: 'git:8eca245c7484ac6cc179e3e5f7c1ea7680810f39', + licenseUrl: + 'https://github.com/unicode-org/icu/blob/8eca245c7484ac6cc179e3e5f7c1ea7680810f39/LICENSE', + }), + openssl: Object.freeze({ + id: 'openssl', + spdx: 'Apache-2.0', + name: 'Apache License 2.0 (OpenSSL)', + member: 'THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt', + source: path.join(ROOT, 'src/third-party/openssl/LICENSE.txt'), + sourceManifest: path.join(ROOT, 'src/third-party/openssl/source.toml'), + sourceVersion: '3.5.6', + sourceBranch: 'openssl-3.5.6', + sourceCommit: '286ddeaac037533bbdce65b3c689e3f7ffebf0f6', + sha256: '7d5450cb2d142651b8afa315b5f238efc805dad827d91ba367d8516bc9d49e7a', + sourceUrl: 'https://github.com/openssl/openssl.git', + sourceIdentity: 'git:286ddeaac037533bbdce65b3c689e3f7ffebf0f6', + licenseUrl: + 'https://github.com/openssl/openssl/blob/286ddeaac037533bbdce65b3c689e3f7ffebf0f6/LICENSE.txt', + }), +}); + +const PRODUCT_NOTICE_NAMESPACE_PATTERN = /^THIRD_PARTY_NOTICES\.[^/]+\.md$/u; +const LICENSE_NAMESPACE_ROOT = 'THIRD_PARTY_LICENSES'; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function checkedProducts(values = []) { + if (!Array.isArray(values)) { + throw new Error('release notices products must be an array'); + } + const result = [...new Set(values.map((value) => String(value)))].sort(compareText); + for (const product of result) { + if (!RELEASE_NOTICE_PRODUCTS.includes(product)) { + throw new Error( + `unsupported release notice product ${JSON.stringify(product)}; expected ${RELEASE_NOTICE_PRODUCTS.join(', ')}`, + ); + } + } + return result; +} + +function checkedComponents(values = []) { + const candidates = values; + if (!Array.isArray(candidates)) { + throw new Error('release license components must be an array'); + } + const selected = new Set(candidates.map((value) => String(value))); + for (const component of selected) { + if (!RELEASE_LICENSE_COMPONENTS.includes(component)) { + throw new Error( + `unsupported release license component ${JSON.stringify(component)}; expected ${RELEASE_LICENSE_COMPONENTS.join(', ')}`, + ); + } + } + return RELEASE_LICENSE_COMPONENTS.filter((component) => selected.has(component)); +} + +export function releaseCarrierProfile(name) { + const profile = RELEASE_CARRIER_PROFILES[name]; + if (!profile) { + throw new Error( + `unsupported release carrier profile ${JSON.stringify(name)}; expected ${Object.keys(RELEASE_CARRIER_PROFILES).join(', ')}`, + ); + } + return profile; +} + +function checkedSelection({ profile, products, components } = {}) { + if (profile !== undefined) { + if (products !== undefined || components !== undefined) { + throw new Error( + 'release carrier profile cannot be combined with explicit products or components', + ); + } + return releaseCarrierProfile(profile); + } + return Object.freeze({ + products: Object.freeze(checkedProducts(products ?? [])), + components: Object.freeze(checkedComponents(components ?? [])), + }); +} + +function requireRealDirectory(directory, label) { + let stat; + try { + stat = lstatSync(directory); + } catch (cause) { + throw new Error(`${label} cannot be inspected: ${cause.message}`); + } + if (!stat.isDirectory() || stat.isSymbolicLink()) { + throw new Error(`${label} must be a real directory: ${directory}`); + } +} + +function requireCanonicalSource(row) { + let stat; + try { + stat = lstatSync(row.source); + } catch (cause) { + throw new Error(`canonical release notice ${row.source} cannot be inspected: ${cause.message}`); + } + if (!stat.isFile() || stat.isSymbolicLink()) { + throw new Error(`canonical release notice must be a regular non-symlink file: ${row.source}`); + } + const bytes = readFileSync(row.source); + if (bytes.length === 0) { + throw new Error(`canonical release notice must be non-empty: ${row.source}`); + } + if (row.sha256) { + const actual = createHash('sha256').update(bytes).digest('hex'); + if (actual !== row.sha256) { + throw new Error( + `canonical release license digest changed for ${row.source}: expected ${row.sha256}, got ${actual}`, + ); + } + } + return bytes; +} + +function validateRuntimeLicenseSource(row) { + let manifest; + try { + manifest = Bun.TOML.parse(readFileSync(row.sourceManifest, 'utf8')); + } catch (cause) { + throw new Error( + `runtime license source manifest ${row.sourceManifest} cannot be parsed: ${cause.message}`, + ); + } + if (row.id === 'postgresql') { + const source = manifest?.postgresql; + if ( + source?.version !== row.sourceVersion || + source?.url !== row.sourceUrl || + `sha256:${source?.sha256}` !== row.sourceIdentity + ) { + throw new Error( + `PostgreSQL runtime license snapshot no longer matches ${row.sourceManifest}`, + ); + } + } else { + if ( + manifest?.name !== row.id || + manifest?.url !== row.sourceUrl || + manifest?.branch !== row.sourceBranch || + manifest?.commit !== row.sourceCommit || + row.sourceIdentity !== `git:${manifest.commit}` + ) { + throw new Error(`${row.id} runtime license snapshot no longer matches ${row.sourceManifest}`); + } + } + requireCanonicalSource(row); + return row; +} + +function checkedPrefix(value = '') { + const raw = String(value); + if ( + raw.startsWith('/') || + raw.includes('\\') || + /^[A-Za-z]:/u.test(raw) || + /[\u0000-\u001f\u007f]/u.test(raw) + ) { + throw new Error(`unsafe release notice archive prefix: ${JSON.stringify(value)}`); + } + const prefix = raw.replace(/^\.\//u, '').replace(/\/$/u, ''); + if ( + prefix.startsWith('/') || + /^[A-Za-z]:/u.test(prefix) || + prefix.split('/').some((part) => !part || part === '.' || part === '..') + ) { + if (prefix !== '') { + throw new Error(`unsafe release notice archive prefix: ${JSON.stringify(value)}`); + } + } + return prefix; +} + +function requireSafeDirectoryChain(directory, label) { + return requireReleaseDirectoryChain(directory, { create: true, label }); +} + +function requireSafeParent(root, destination, { create = false } = {}) { + const relative = path.relative(root, path.dirname(destination)); + if (relative.startsWith('..') || path.isAbsolute(relative)) { + throw new Error(`release notice destination escapes staging root: ${destination}`); + } + let cursor = root; + for (const part of relative ? relative.split(path.sep) : []) { + cursor = path.join(cursor, part); + let stat; + try { + stat = lstatSync(cursor); + } catch (cause) { + if (cause?.code !== 'ENOENT') { + throw new Error(`release notice parent ${cursor} cannot be inspected: ${cause.message}`); + } + if (!create) { + throw new Error(`release notice parent is missing: ${cursor}`); + } + mkdirSync(cursor, { mode: 0o755 }); + stat = lstatSync(cursor); + } + if (!stat.isDirectory() || stat.isSymbolicLink()) { + throw new Error(`release notice parent must be a real directory: ${cursor}`); + } + } +} + +function prefixedMember(prefix, member) { + return prefix ? `${prefix}/${member}` : member; +} + +function isExpectedNamespaceDirectory(member, expectedMembers) { + if (member === LICENSE_NAMESPACE_ROOT) return true; + return [...expectedMembers].some((expected) => expected.startsWith(`${member}/`)); +} + +function directoryNoticeNamespaceEntries(root) { + const entries = []; + for (const name of readdirSync(root).sort(compareText)) { + if (!PRODUCT_NOTICE_NAMESPACE_PATTERN.test(name)) continue; + const file = path.join(root, name); + entries.push({ member: name, file, stat: lstatSync(file), namespace: 'product notice' }); + } + + const licenses = path.join(root, LICENSE_NAMESPACE_ROOT); + let rootStat; + try { + rootStat = lstatSync(licenses); + } catch (cause) { + if (cause?.code === 'ENOENT') return entries; + throw new Error(`release license namespace ${licenses} cannot be inspected: ${cause.message}`); + } + entries.push({ + member: LICENSE_NAMESPACE_ROOT, + file: licenses, + stat: rootStat, + namespace: 'release license', + }); + if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) return entries; + + function walk(directory, memberPrefix) { + for (const name of readdirSync(directory).sort(compareText)) { + const file = path.join(directory, name); + const member = `${memberPrefix}/${name}`; + const stat = lstatSync(file); + entries.push({ member, file, stat, namespace: 'release license' }); + if (stat.isDirectory() && !stat.isSymbolicLink()) walk(file, member); + } + } + walk(licenses, LICENSE_NAMESPACE_ROOT); + return entries; +} + +function archiveNoticeNamespaceEntries(entries, prefix) { + const namespaceEntries = []; + const prefixMarker = prefix ? `${prefix}/` : ''; + for (const [archiveMember, entry] of entries) { + if (prefixMarker && !archiveMember.startsWith(prefixMarker)) continue; + const member = prefixMarker ? archiveMember.slice(prefixMarker.length) : archiveMember; + if (PRODUCT_NOTICE_NAMESPACE_PATTERN.test(member)) { + namespaceEntries.push({ archiveMember, entry, member, namespace: 'product notice' }); + } else if ( + member === LICENSE_NAMESPACE_ROOT || + member.startsWith(`${LICENSE_NAMESPACE_ROOT}/`) + ) { + namespaceEntries.push({ archiveMember, entry, member, namespace: 'release license' }); + } + } + return namespaceEntries.sort((left, right) => + compareText(left.archiveMember, right.archiveMember), + ); +} + +function unexpectedNamespaceEntry(namespaceEntry, expectedMembers) { + if (expectedMembers.has(namespaceEntry.member)) return false; + if ( + namespaceEntry.namespace === 'release license' && + isExpectedNamespaceDirectory(namespaceEntry.member, expectedMembers) + ) { + if (namespaceEntry.stat) { + return !namespaceEntry.stat.isDirectory() || namespaceEntry.stat.isSymbolicLink(); + } + return ( + namespaceEntry.entry?.isDirectory !== true || namespaceEntry.entry?.isSymbolicLink === true + ); + } + return true; +} + +export function releaseNoticeRows(options = {}) { + const selection = checkedSelection(options); + const rows = [ + ...BASE_ROWS, + ...selection.products.map((product) => PRODUCT_NOTICE_ROWS[product]), + ...selection.components.map((component) => + validateRuntimeLicenseSource(LICENSE_COMPONENT_ROWS[component]), + ), + ]; + return Object.freeze(rows.map((row) => Object.freeze({ ...row }))); +} + +export function releaseNoticeInputPaths( + options = { products: RELEASE_NOTICE_PRODUCTS, components: RELEASE_LICENSE_COMPONENTS }, +) { + return Object.freeze(releaseNoticeRows(options).map((row) => row.source)); +} + +export function releaseLicenseComponents(ids) { + return Object.freeze( + checkedComponents(ids).map((id) => validateRuntimeLicenseSource(LICENSE_COMPONENT_ROWS[id])), + ); +} + +export function releasePackageLicense({ components = [], includeOliphaunt = true } = {}) { + const entries = []; + if (includeOliphaunt) { + entries.push( + Object.freeze({ + id: 'oliphaunt', + spdx: 'MIT', + name: 'MIT License (Oliphaunt)', + member: 'LICENSE', + source: path.join(ROOT, 'LICENSE'), + licenseUrl: 'https://github.com/f0rr0/oliphaunt/blob/main/LICENSE', + }), + ); + } + entries.push(...releaseLicenseComponents(components)); + return Object.freeze({ + spdx: entries.map((entry) => entry.spdx).join(' AND '), + entries: Object.freeze(entries), + }); +} + +export function releaseProfilePackageLicense(profile, options = {}) { + const selection = releaseCarrierProfile(profile); + return releasePackageLicense({ + components: selection.components, + includeOliphaunt: options.includeOliphaunt ?? true, + }); +} + +export function releaseMavenLicenses({ + product, + version, + components = [], + includeOliphaunt = true, +} = {}) { + if (typeof product !== 'string' || !/^[a-z0-9][a-z0-9-]*$/u.test(product)) { + throw new Error('release Maven licenses require a canonical product id'); + } + if (typeof version !== 'string' || !/^[0-9A-Za-z][0-9A-Za-z._-]*$/u.test(version)) { + throw new Error('release Maven licenses require a portable package version'); + } + return Object.freeze( + releasePackageLicense({ components, includeOliphaunt }).entries.map((entry) => + Object.freeze({ + name: entry.name, + url: + entry.id === 'oliphaunt' + ? `https://github.com/f0rr0/oliphaunt/blob/${product}-v${version}/LICENSE` + : entry.licenseUrl, + distribution: 'repo', + }), + ), + ); +} + +export function releaseProfileMavenLicenses( + profile, + { product, version, includeOliphaunt = true } = {}, +) { + const selection = releaseCarrierProfile(profile); + return releaseMavenLicenses({ + product, + version, + components: selection.components, + includeOliphaunt, + }); +} + +export function stageReleaseNotices(destination, options = {}) { + const directory = requireSafeDirectoryChain(destination, 'release notice destination'); + const rows = releaseNoticeRows(options); + const expectedMembers = new Set(rows.map((row) => row.member)); + + // A reused package stage must not retain any unselected or unrecognized + // member in the canonical legal namespaces. Only regular files are safe to + // remove automatically; links, special files, and unexpected directory + // topology fail closed. + for (const entry of directoryNoticeNamespaceEntries(directory)) { + if (!unexpectedNamespaceEntry(entry, expectedMembers)) continue; + if (!entry.stat.isFile() || entry.stat.isSymbolicLink()) { + throw new Error( + `stale ${entry.namespace} path is not a regular non-symlink file: ${entry.file}`, + ); + } + rmSync(entry.file); + } + + for (const row of rows) { + requireCanonicalSource(row); + const destinationFile = path.join(directory, row.member); + requireSafeParent(directory, destinationFile, { create: true }); + let prior; + try { + prior = lstatSync(destinationFile); + } catch (cause) { + if (cause?.code !== 'ENOENT') { + throw new Error( + `release notice destination ${destinationFile} cannot be inspected: ${cause.message}`, + ); + } + } + if (prior && (!prior.isFile() || prior.isSymbolicLink())) { + throw new Error(`release notice destination is not a regular file: ${destinationFile}`); + } + copyFileSync(row.source, destinationFile); + chmodSync(destinationFile, 0o644); + } + assertReleaseNoticesInDirectory(directory, options); + return rows.map((row) => path.join(directory, row.member)); +} + +export function hasCanonicalReleaseStagingMode(mode, platform = process.platform) { + // Windows exposes synthetic Unix permission bits through stat(2). chmod can + // toggle the read-only attribute, but it cannot establish a meaningful 0644 + // filesystem contract. Archive checks require readability without special + // permission bits, allowing packers to preserve Windows synthetic modes. + return platform === 'win32' || (mode & 0o777) === 0o644; +} + +export function assertReleaseNoticesInDirectory(directory, options = {}) { + const { exact = true } = options; + const root = path.resolve(directory); + requireRealDirectory(root, 'release notice directory'); + const rows = releaseNoticeRows(options); + const expected = new Set(rows.map((row) => row.member)); + for (const row of rows) { + const file = path.join(root, row.member); + requireSafeParent(root, file); + let stat; + try { + stat = lstatSync(file); + } catch (cause) { + throw new Error(`missing release notice ${file}: ${cause.message}`); + } + if (!stat.isFile() || stat.isSymbolicLink()) { + throw new Error(`release notice must be a regular non-symlink file: ${file}`); + } + if (!hasCanonicalReleaseStagingMode(stat.mode)) { + throw new Error(`release notice must have mode 0644: ${file}`); + } + const canonical = requireCanonicalSource(row); + const actual = readFileSync(file); + if (!actual.equals(canonical)) { + throw new Error(`release notice differs byte-for-byte from ${row.source}: ${file}`); + } + } + if (exact) { + for (const entry of directoryNoticeNamespaceEntries(root)) { + if (!unexpectedNamespaceEntry(entry, expected)) continue; + throw new Error( + `release notice directory contains unexpected ${entry.namespace} member ${entry.member}`, + ); + } + } + return rows.map((row) => row.member); +} + +export function assertReleaseNoticesInEntries(entries, options = {}) { + const { prefix = '', exact = true, label = 'archive' } = options; + if (!(entries instanceof Map)) { + throw new Error('release notice archive entries must be a Map'); + } + const checkedArchivePrefix = checkedPrefix(prefix); + const rows = releaseNoticeRows(options); + const expected = new Set(rows.map((row) => row.member)); + for (const row of rows) { + const member = prefixedMember(checkedArchivePrefix, row.member); + const entry = entries.get(member); + if (!entry?.isFile || entry.isSymbolicLink) { + throw new Error(`${label} is missing regular release notice member ${member}`); + } + if ((entry.mode & 0o444) !== 0o444 || (entry.mode & 0o7000) !== 0) { + throw new Error( + `${label} release notice member ${member} must be readable by all users without special permission bits`, + ); + } + const canonical = requireCanonicalSource(row); + const actual = Buffer.from(entry.data()); + if (!actual.equals(canonical)) { + throw new Error( + `${label} release notice member ${member} differs byte-for-byte from ${row.source}`, + ); + } + } + if (exact) { + for (const entry of archiveNoticeNamespaceEntries(entries, checkedArchivePrefix)) { + if (!unexpectedNamespaceEntry(entry, expected)) continue; + throw new Error( + `${label} contains unexpected ${entry.namespace} member ${entry.archiveMember}`, + ); + } + } + return rows.map((row) => prefixedMember(checkedArchivePrefix, row.member)); +} + +export function assertReleaseNoticesInArchive(file, options = {}) { + const archive = path.resolve(file); + return assertReleaseNoticesInEntries(readPortableArchiveEntries(archive), { + ...options, + label: options.label ?? path.basename(archive), + }); +} + +function usage() { + return [ + 'usage:', + ' tools/packaging/release-notices.mts stage --profile ', + ' tools/packaging/release-notices.mts check-directory --profile ', + ' tools/packaging/release-notices.mts check-archive --profile [--prefix ]', + ' advanced: replace --profile with explicit --product and --component flags', + ].join('\n'); +} + +function parseCli(argv) { + const values = [...argv]; + const command = values.shift(); + const target = values.shift(); + if (!command || !target || !['stage', 'check-directory', 'check-archive'].includes(command)) { + throw new Error(usage()); + } + const products = []; + const components = []; + let componentsSupplied = false; + let prefix = ''; + let profile; + while (values.length > 0) { + const flag = values.shift(); + if (flag === '--profile') { + if (profile !== undefined) throw new Error('--profile may be supplied only once'); + profile = values.shift(); + if (!profile) throw new Error('--profile requires a value'); + releaseCarrierProfile(profile); + } else if (flag === '--product') { + const product = values.shift(); + if (!product) throw new Error('--product requires a value'); + products.push(product); + } else if (flag === '--component') { + const component = values.shift(); + if (!component) throw new Error('--component requires a value'); + components.push(component); + componentsSupplied = true; + } else if (flag === '--prefix' && command === 'check-archive') { + const value = values.shift(); + if (value === undefined) throw new Error('--prefix requires a value'); + prefix = value; + } else { + throw new Error(`unsupported release notice argument ${JSON.stringify(flag)}\n${usage()}`); + } + } + if (profile !== undefined && (products.length > 0 || componentsSupplied)) { + throw new Error('--profile cannot be combined with --product or --component'); + } + const checkedProductValues = checkedProducts(products); + return { + command, + prefix, + noticeOptions: + profile === undefined + ? { + products: checkedProductValues, + components: checkedComponents(componentsSupplied ? components : []), + } + : { profile }, + target, + }; +} + +function main() { + let args; + try { + args = parseCli(process.argv.slice(2)); + if (args.command === 'stage') { + stageReleaseNotices(args.target, args.noticeOptions); + } else if (args.command === 'check-directory') { + assertReleaseNoticesInDirectory(args.target, args.noticeOptions); + } else { + assertReleaseNoticesInArchive(args.target, { + prefix: args.prefix, + ...args.noticeOptions, + }); + } + } catch (error) { + console.error(`${PREFIX}: ${error instanceof Error ? error.message : String(error)}`); + process.exitCode = 1; + return; + } + console.log(`${PREFIX}: ${args.command} passed for ${args.target}`); +} + +const invoked = process.argv[1] ? path.resolve(process.argv[1]) : ''; +if (invoked === fileURLToPath(import.meta.url)) { + main(); +} diff --git a/tools/packaging/release-notices.test.mts b/tools/packaging/release-notices.test.mts new file mode 100644 index 000000000..11426d65a --- /dev/null +++ b/tools/packaging/release-notices.test.mts @@ -0,0 +1,347 @@ +import { archiveDirectory } from './archive-directory.mts'; +import assert from 'node:assert/strict'; +import { + chmodSync, + mkdtempSync, + mkdirSync, + readFileSync, + realpathSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { zstdCompressSync } from 'node:zlib'; + +import { createDeterministicTar } from './cargo-source-package.mts'; +import { + assertReleaseNoticesInArchive, + assertReleaseNoticesInDirectory, + assertReleaseNoticesInEntries, + hasCanonicalReleaseStagingMode, + releasePackageLicense, + releaseNoticeRows, + stageReleaseNotices, +} from './release-notices.mts'; + +const ROOT = path.resolve(import.meta.dirname, '../..'); + +function fixture(t) { + const root = realpathSync(mkdtempSync(path.join(tmpdir(), 'release-notices-test-'))); + t.after(() => rmSync(root, { recursive: true, force: true })); + const stage = path.join(root, 'stage'); + mkdirSync(stage); + return { root, stage }; +} + +test('defines stable canonical member names in deterministic order', () => { + assert.deepEqual( + releaseNoticeRows({ products: ['wasix', 'native', 'native'] }).map((row) => [ + row.member, + path.relative(ROOT, row.source).split(path.sep).join('/'), + ]), + [ + ['LICENSE', 'LICENSE'], + ['THIRD_PARTY_NOTICES.md', 'THIRD_PARTY_NOTICES.md'], + [ + 'THIRD_PARTY_NOTICES.liboliphaunt-native.md', + 'src/runtimes/liboliphaunt-native/THIRD_PARTY_NOTICES.md', + ], + ['THIRD_PARTY_NOTICES.oliphaunt-wasix.md', 'src/sdks/rust-wasix/THIRD_PARTY_NOTICES.md'], + ], + ); + assert.throws( + () => releaseNoticeRows({ products: ['unknown'] }), + /unsupported release notice product/u, + ); + assert.deepEqual( + releaseNoticeRows({ components: ['openssl', 'postgresql', 'icu'] }).map((row) => row.member), + [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + 'THIRD_PARTY_LICENSES/ICU-LICENSE', + 'THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt', + ], + ); + assert.throws( + () => releaseNoticeRows({ components: ['unknown'] }), + /unsupported release license component/u, + ); + assert.deepEqual(releasePackageLicense({ components: ['icu', 'postgresql'] }), { + spdx: 'MIT AND PostgreSQL AND Unicode-3.0', + entries: releasePackageLicense({ components: ['postgresql', 'icu'] }).entries, + }); + assert.deepEqual( + releaseNoticeRows({ profile: 'native-tools' }).map((row) => row.member), + [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_NOTICES.liboliphaunt-native.md', + 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + ], + ); +}); + +test('stages exact bytes and removes stale product notices', async (t) => { + const { stage } = fixture(t); + stageReleaseNotices(stage, { products: ['native', 'wasix'] }); + for (const row of releaseNoticeRows({ products: ['native', 'wasix'] })) { + assert.deepEqual(readFileSync(path.join(stage, row.member)), readFileSync(row.source)); + } + stageReleaseNotices(stage, { products: ['native'] }); + assert.deepEqual(assertReleaseNoticesInDirectory(stage, { products: ['native'] }), [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_NOTICES.liboliphaunt-native.md', + ]); + assert.throws( + () => assertReleaseNoticesInDirectory(stage, { products: [] }), + /unexpected product notice/u, + ); +}); + +test('rejects byte drift and POSIX directory mode drift', async (t) => { + const { stage } = fixture(t); + stageReleaseNotices(stage); + writeFileSync(path.join(stage, 'LICENSE'), 'not the license\n'); + assert.throws(() => assertReleaseNoticesInDirectory(stage), /differs byte-for-byte/u); + if (process.platform !== 'win32') { + stageReleaseNotices(stage); + chmodSync(path.join(stage, 'LICENSE'), 0o600); + assert.throws(() => assertReleaseNoticesInDirectory(stage), /mode 0644/u); + } +}); + +test('treats directory modes as POSIX-only staging metadata', () => { + assert.equal(hasCanonicalReleaseStagingMode(0o666, 'win32'), true); + assert.equal(hasCanonicalReleaseStagingMode(0o644, 'linux'), true); + assert.equal(hasCanonicalReleaseStagingMode(0o666, 'linux'), false); +}); + +test('accepts synthetic archive modes but rejects unreadable and privileged notices', () => { + const entries = new Map( + releaseNoticeRows().map((row) => [ + row.member, + { + isDirectory: false, + isFile: true, + isSymbolicLink: false, + mode: row.member === 'LICENSE' ? 0o666 : 0o644, + data: () => readFileSync(row.source), + }, + ]), + ); + assertReleaseNoticesInEntries(entries); + for (const mode of [0o600, 0o4644]) { + entries.get('LICENSE').mode = mode; + assert.throws( + () => assertReleaseNoticesInEntries(entries), + /readable.*special permission bits/u, + ); + } +}); + +test('exact validation rejects unknown legal namespace members and staging removes only safe stale files', async (t) => { + const { root, stage } = fixture(t); + stageReleaseNotices(stage, { components: ['postgresql'] }); + const unknownProductNotice = path.join(stage, 'THIRD_PARTY_NOTICES.unrecognized-runtime.md'); + const unknownLicense = path.join(stage, 'THIRD_PARTY_LICENSES', 'Unrecognized-LICENSE'); + writeFileSync(unknownProductNotice, 'unknown product notice\n'); + writeFileSync(unknownLicense, 'unknown component license\n'); + + assert.throws( + () => assertReleaseNoticesInDirectory(stage, { components: ['postgresql'] }), + /unexpected product notice member THIRD_PARTY_NOTICES\.unrecognized-runtime\.md/u, + ); + rmSync(unknownProductNotice); + assert.throws( + () => assertReleaseNoticesInDirectory(stage, { components: ['postgresql'] }), + /unexpected release license member THIRD_PARTY_LICENSES\/Unrecognized-LICENSE/u, + ); + + writeFileSync(unknownProductNotice, 'unknown product notice\n'); + stageReleaseNotices(stage, { components: ['postgresql'] }); + assertReleaseNoticesInDirectory(stage, { components: ['postgresql'] }); + + const outside = path.join(root, 'outside-license'); + writeFileSync(outside, 'not safe to remove\n'); + symlinkSync(outside, unknownLicense); + assert.throws( + () => stageReleaseNotices(stage, { components: ['postgresql'] }), + /stale release license path is not a regular non-symlink file/u, + ); +}); + +test('rejects unsafe prefixes and unsafe staging destinations', async (t) => { + const { root, stage } = fixture(t); + for (const prefix of ['/', '\\', 'a\\b', '../escape', 'C:/escape', 'a//b', './../escape']) { + assert.throws( + () => assertReleaseNoticesInEntries(new Map(), { prefix }), + /unsafe release notice archive prefix/u, + prefix, + ); + } + + const nonDirectory = path.join(root, 'not-a-directory'); + writeFileSync(nonDirectory, 'file\n'); + assert.throws( + () => stageReleaseNotices(nonDirectory), + /real directory|cannot be inspected|symlink or non-directory ancestor/u, + ); + + const outside = path.join(root, 'outside'); + mkdirSync(outside); + symlinkSync(outside, path.join(stage, 'THIRD_PARTY_LICENSES')); + assert.throws( + () => stageReleaseNotices(stage, { components: ['postgresql'] }), + /stale release license path is not a regular non-symlink file/u, + ); + + const realAncestor = path.join(root, 'real-ancestor'); + const existingStage = path.join(realAncestor, 'existing-stage'); + mkdirSync(existingStage, { recursive: true }); + const linkedAncestor = path.join(root, 'linked-ancestor'); + symlinkSync(realAncestor, linkedAncestor); + assert.throws( + () => stageReleaseNotices(path.join(linkedAncestor, 'existing-stage')), + /symlink or non-directory ancestor/u, + ); + + const linkedStage = path.join(root, 'linked-stage'); + symlinkSync(existingStage, linkedStage); + assert.throws(() => stageReleaseNotices(linkedStage), /symlink or non-directory ancestor/u); +}); + +test('rejects caller-created directory aliases and non-directory ancestors', async (t) => { + const { root } = fixture(t); + const outside = path.join(root, 'outside'); + const stage = path.join(outside, 'stage'); + mkdirSync(stage, { recursive: true }); + + const callerAlias = path.join(root, 'var'); + symlinkSync(outside, callerAlias, process.platform === 'win32' ? 'junction' : 'dir'); + assert.throws( + () => stageReleaseNotices(path.join(callerAlias, 'stage')), + /symlink or non-directory ancestor/u, + ); + + const nonDirectory = path.join(root, 'ordinary-file'); + writeFileSync(nonDirectory, 'not a directory\n'); + assert.throws( + () => stageReleaseNotices(path.join(nonDirectory, 'stage')), + /symlink or non-directory ancestor/u, + ); +}); + +test('validates exact archive members and canonical bytes', async (t) => { + const { root, stage } = fixture(t); + stageReleaseNotices(stage, { products: ['native'] }); + writeFileSync(path.join(stage, 'payload.txt'), 'payload\n'); + const archive = path.join(root, 'carrier.tar.gz'); + await archiveDirectory(stage, archive, { keepParent: true }); + assert.deepEqual( + assertReleaseNoticesInArchive(archive, { + prefix: path.basename(stage), + products: ['native'], + }), + [ + `${path.basename(stage)}/LICENSE`, + `${path.basename(stage)}/THIRD_PARTY_NOTICES.md`, + `${path.basename(stage)}/THIRD_PARTY_NOTICES.liboliphaunt-native.md`, + ], + ); + assert.throws( + () => assertReleaseNoticesInArchive(archive, { prefix: path.basename(stage) }), + /unexpected product notice/u, + ); +}); + +test('exact archive validation rejects unknown legal namespace members', async (t) => { + const { root, stage } = fixture(t); + const prefix = 'carrier'; + stageReleaseNotices(stage, { components: ['postgresql'] }); + + const productNotice = path.join(stage, 'THIRD_PARTY_NOTICES.unknown-product.md'); + writeFileSync(productNotice, 'unknown product notice\n'); + let archive = path.join(root, 'unknown-product.tar.zst'); + writeFileSync( + archive, + zstdCompressSync( + createDeterministicTar(stage, prefix, { + fail(message) { + throw new Error(message); + }, + }), + ), + ); + assert.throws( + () => assertReleaseNoticesInArchive(archive, { prefix, components: ['postgresql'] }), + /unexpected product notice member carrier\/THIRD_PARTY_NOTICES\.unknown-product\.md/u, + ); + + rmSync(productNotice); + writeFileSync(path.join(stage, 'THIRD_PARTY_LICENSES', 'Unknown-LICENSE'), 'unknown license\n'); + archive = path.join(root, 'unknown-license.tar.zst'); + writeFileSync( + archive, + zstdCompressSync( + createDeterministicTar(stage, prefix, { + fail(message) { + throw new Error(message); + }, + }), + ), + ); + assert.throws( + () => assertReleaseNoticesInArchive(archive, { prefix, components: ['postgresql'] }), + /unexpected release license member carrier\/THIRD_PARTY_LICENSES\/Unknown-LICENSE/u, + ); +}); + +test('validates exact notices in a real zstd-compressed ustar carrier', async (t) => { + const { root, stage } = fixture(t); + const profile = 'wasix-runtime'; + const prefix = 'liboliphaunt-wasix-runtime-portable'; + stageReleaseNotices(stage, { profile }); + writeFileSync(path.join(stage, 'runtime.bin'), 'runtime\n'); + const archive = path.join(root, `${prefix}.tar.zst`); + const tar = createDeterministicTar(stage, prefix, { + fail(message) { + throw new Error(message); + }, + }); + writeFileSync(archive, zstdCompressSync(tar)); + + assert.deepEqual( + assertReleaseNoticesInArchive(archive, { prefix, profile }), + releaseNoticeRows({ profile }).map((row) => `${prefix}/${row.member}`), + ); +}); + +test('rejects archive byte drift and accepts readable executable notices', async (t) => { + const { root, stage } = fixture(t); + stageReleaseNotices(stage, { components: ['postgresql'] }); + writeFileSync(path.join(stage, 'LICENSE'), 'not the license\n'); + const byteArchive = path.join(root, 'byte-drift.tar.gz'); + await archiveDirectory(stage, byteArchive, { keepParent: true }); + assert.throws( + () => + assertReleaseNoticesInArchive(byteArchive, { + prefix: path.basename(stage), + components: ['postgresql'], + }), + /differs byte-for-byte/u, + ); + + stageReleaseNotices(stage, { components: ['postgresql'] }); + chmodSync(path.join(stage, 'LICENSE'), 0o755); + const modeArchive = path.join(root, 'mode-drift.tar.gz'); + await archiveDirectory(stage, modeArchive, { keepParent: true }); + assertReleaseNoticesInArchive(modeArchive, { + prefix: path.basename(stage), + components: ['postgresql'], + }); +}); diff --git a/tools/packaging/rust-build-script-sha256.mts b/tools/packaging/rust-build-script-sha256.mts new file mode 100644 index 000000000..88021f565 --- /dev/null +++ b/tools/packaging/rust-build-script-sha256.mts @@ -0,0 +1,15 @@ +// Generated carrier build scripts use the same RustCrypto dependency as SDKs. +export const RUST_BUILD_SCRIPT_SHA256 = String.raw` +fn sha256_file(path: &Path) -> io::Result { + use sha2::{Digest, Sha256}; + let mut file = fs::File::open(path)?; + let mut digest = Sha256::new(); + let mut buffer = [0_u8; 128 * 1024]; + loop { + let count = file.read(&mut buffer)?; + if count == 0 { break; } + digest.update(&buffer[..count]); + } + Ok(format!("{:x}", digest.finalize())) +} +`; diff --git a/tools/packaging/rust-dependency-license-contract.mts b/tools/packaging/rust-dependency-license-contract.mts new file mode 100644 index 000000000..6e132008e --- /dev/null +++ b/tools/packaging/rust-dependency-license-contract.mts @@ -0,0 +1,1000 @@ +import { createHash } from 'node:crypto'; +import { + chmodSync, + lstatSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { readPortableArchiveEntries } from './portable-archive.mts'; +import { requireSafeDirectoryChain as requireReleaseDirectoryChain } from './release-directory-safety.mts'; +import { assertReleaseNoticesInEntries } from './release-notices.mts'; + +export function createRustDependencyLicenseContract({ + owner, + product, + payloadLicense, + noticeProfile = 'source-sdk', + targets, +}) { + const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); + const TOOL = `${product} dependency licenses`; + const CONTRACT_PATH = path.join(ROOT, owner, 'dependency-licenses.json'); + const BLOB_ROOT = path.join(ROOT, owner, 'dependency-license-blobs'); + const CARGO_LOCK_PATH = path.join(ROOT, 'Cargo.lock'); + const CARGO_SOURCE = 'registry+https://github.com/rust-lang/crates.io-index'; + const CONTRACT_SCHEMA = `${product}-dependency-license-contract-v1`; + const INDEX_SCHEMA = `${product}-target-dependency-license-index-v1`; + + const RUST_DEPENDENCY_LICENSE_ROOT = 'THIRD_PARTY_LICENSES/rust'; + const RUST_PAYLOAD_LICENSE = payloadLicense; + + const TARGET_ROWS = Object.freeze( + targets ?? [ + Object.freeze({ id: 'linux-x64-gnu', cargoTarget: 'x86_64-unknown-linux-gnu' }), + Object.freeze({ id: 'linux-arm64-gnu', cargoTarget: 'aarch64-unknown-linux-gnu' }), + Object.freeze({ id: 'macos-arm64', cargoTarget: 'aarch64-apple-darwin' }), + Object.freeze({ id: 'windows-x64-msvc', cargoTarget: 'x86_64-pc-windows-msvc' }), + ], + ); + const TARGET_IDS = Object.freeze(TARGET_ROWS.map(({ id }) => id)); + const TARGET_BY_ID = new Map(TARGET_ROWS.map((row) => [row.id, row])); + const PAYLOAD_LICENSE_ATOMS = Object.freeze(payloadLicense.split(' AND ')); + const LEGAL_BASENAME_PREFIXES = Object.freeze([ + 'acknowledg', + 'authors', + 'copying', + 'copyright', + 'credits', + 'legal', + 'license', + 'notice', + 'patents', + 'unlicense', + ]); + const LEGAL_BASENAME_FRAGMENTS = Object.freeze(['third-party', 'third_party', 'thirdparty']); + const HEX_64 = /^[0-9a-f]{64}$/u; + const PACKAGE_KEY = /^[a-zA-Z0-9_][a-zA-Z0-9_.-]*@[^\s/\\]+$/u; + const SAFE_MEMBER = + /^(?!\/)(?![A-Za-z]:)(?!.*(?:^|\/)\.\.(?:\/|$))(?!.*\\)(?!.*[\u0000-\u001f\u007f])[^/]+(?:\/[^/]+)*$/u; + + let validatedDefaultContract; + + function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; + } + + function fail(message) { + throw new Error(`${TOOL}: ${message}`); + } + + function sha256(bytes) { + return createHash('sha256').update(bytes).digest('hex'); + } + + function renderBase64(bytes) { + return `${ + bytes + .toString('base64') + .match(/.{1,76}/gu) + ?.join('\n') ?? '' + }\n`; + } + + function canonicalBlobBytes(digest, expectedBytes) { + const file = path.join(BLOB_ROOT, `${digest}.base64`); + requireRealFile(file, 'canonical Rust dependency license blob'); + const encoded = readFileSync(file, 'utf8'); + if (!/^(?:[A-Za-z0-9+/=]{1,76}\n)+$/u.test(encoded)) { + fail(`canonical Rust dependency license blob is not wrapped base64 text: ${file}`); + } + const content = Buffer.from(encoded.replaceAll('\n', ''), 'base64'); + if ( + content.length !== expectedBytes || + sha256(content) !== digest || + encoded !== renderBase64(content) + ) { + fail( + `canonical Rust dependency license blob does not match ${digest}/${expectedBytes}: ${file}`, + ); + } + return content; + } + + function packageKey(row) { + return `${row.name}@${row.version}`; + } + + function isAllowedRustPathPackageMetadataRow(row, workspaceMembers) { + if ( + !row || + typeof row !== 'object' || + row.source !== null || + row.license !== 'MIT' || + !workspaceMembers.has(row.id) || + typeof row.name !== 'string' || + typeof row.version !== 'string' || + row.version.length === 0 || + typeof row.manifest_path !== 'string' + ) { + return false; + } + try { + const manifest = realpathSync(row.manifest_path); + const relative = path.relative(realpathSync(ROOT), manifest); + return ( + relative !== '' && + !relative.startsWith(`..${path.sep}`) && + !path.isAbsolute(relative) && + path.basename(manifest) === 'Cargo.toml' + ); + } catch { + return false; + } + } + + function sameStrings(actual, expected) { + return JSON.stringify(actual) === JSON.stringify(expected); + } + + function exactObjectKeys(value, expected, label) { + if (!value || typeof value !== 'object' || Array.isArray(value)) { + fail(`${label} must be an object`); + } + const actual = Object.keys(value); + if (actual.length !== expected.length || actual.some((key) => !expected.includes(key))) { + fail(`${label} keys must be ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`); + } + } + + function hasCanonicalRustFilesystemMode(mode, expectedMode, platform = process.platform) { + // Windows exposes synthetic Unix permission bits through stat(2). chmod can + // toggle the read-only attribute, but it cannot establish meaningful 0644 + // or 0755 filesystem metadata. Published archives still carry and validate + // readability and special permission bits in assertRustDependencyLicensesInEntries. + return platform === 'win32' || (mode & 0o777) === expectedMode; + } + + function hasSafeRustSourceFilesystemMode(mode, platform = process.platform) { + if (platform === 'win32') return true; + const permissions = mode & 0o777; + // Git records only the executable bit for regular files; checkout read/write + // bits reflect the host umask. Staged and archived members are normalized and + // verified as exact 0644, so source inputs need only be readable and non-executable. + return (permissions & 0o444) !== 0 && (permissions & 0o111) === 0; + } + + function requireRealFile(file, label) { + let stat; + try { + stat = lstatSync(file); + } catch (cause) { + fail(`${label} cannot be inspected: ${file}: ${cause.message}`); + } + if (!stat.isFile() || stat.isSymbolicLink()) { + fail(`${label} must be a regular non-symlink file: ${file}`); + } + if (!hasSafeRustSourceFilesystemMode(stat.mode)) { + fail(`${label} must have a safe non-executable mode derived from 0644: ${file}`); + } + return stat; + } + + function requireRealDirectory(directory, label) { + let stat; + try { + stat = lstatSync(directory); + } catch (cause) { + fail(`${label} cannot be inspected: ${directory}: ${cause.message}`); + } + if (!stat.isDirectory() || stat.isSymbolicLink()) { + fail(`${label} must be a real non-symlink directory: ${directory}`); + } + return stat; + } + + function ensureSafeDirectoryChain(directory, label) { + try { + return requireReleaseDirectoryChain(directory, { create: true, label }); + } catch (cause) { + fail(cause.message); + } + } + + function requireSafeDirectoryChain(directory, label) { + try { + return requireReleaseDirectoryChain(directory, { label }); + } catch (cause) { + fail(cause.message); + } + } + + function safeMember(value, label) { + if (typeof value !== 'string' || !SAFE_MEMBER.test(value)) { + fail(`${label} is not a safe portable member path: ${JSON.stringify(value)}`); + } + return value; + } + + function targetRow(target) { + const row = TARGET_BY_ID.get(target); + if (!row) { + fail(`unsupported Rust target ${JSON.stringify(target)}; expected ${TARGET_IDS.join(', ')}`); + } + return row; + } + + function canonicalJson(value) { + return `${JSON.stringify(value, null, 2)}\n`; + } + + function legalSourceFile(relative) { + const basename = path.posix.basename(relative).toLowerCase(); + return ( + LEGAL_BASENAME_PREFIXES.some((prefix) => basename.startsWith(prefix)) || + LEGAL_BASENAME_FRAGMENTS.some((fragment) => basename.includes(fragment)) + ); + } + + function walkRegularFiles(root, relative = '') { + const files = []; + for (const name of readdirSync(path.join(root, ...relative.split('/').filter(Boolean))).sort( + compareText, + )) { + const member = relative ? `${relative}/${name}` : name; + const file = path.join(root, ...member.split('/')); + const stat = lstatSync(file); + if (stat.isSymbolicLink()) { + fail(`source dependency legal inventory contains a symlink: ${file}`); + } + if (stat.isDirectory()) { + files.push(...walkRegularFiles(root, member)); + } else if (stat.isFile()) { + files.push(member); + } + } + return files; + } + + function readCargoSnapshot(graphDirectory, file) { + const snapshot = path.join(graphDirectory, file); + const metadata = requireRealFile(snapshot, 'Rust Cargo snapshot'); + if (metadata.size > 128 * 1024 * 1024) fail('Rust Cargo snapshot exceeds 128 MiB'); + return new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(snapshot)); + } + + function cargoTreePackageKeys(cargoTarget, metadataPackages, graphDirectory, workspaceMembers) { + const output = readCargoSnapshot(graphDirectory, `${cargoTarget}.tree`); + const keys = new Set(); + for (const rawLine of output.split(/\r?\n/u)) { + const line = rawLine.replace(/ \(\*\)$/u, '').trim(); + if (!line) continue; + const match = /^([^\s]+) v([^\s]+)/u.exec(line); + if (!match) { + fail(`cannot parse cargo tree package line for ${cargoTarget}: ${JSON.stringify(rawLine)}`); + } + const key = `${match[1]}@${match[2]}`; + const candidates = metadataPackages.get(key) ?? []; + if (candidates.length === 0) { + fail(`cargo tree package ${key} is absent from cargo metadata`); + } + const registry = candidates.filter((row) => row.source === CARGO_SOURCE); + if (registry.length === 1) { + keys.add(key); + continue; + } + if (registry.length > 1) { + fail(`cargo metadata has duplicate crates.io identities for ${key}`); + } + const pathPackages = candidates.filter((row) => + isAllowedRustPathPackageMetadataRow(row, workspaceMembers), + ); + if (pathPackages.length !== 1) { + fail(`Rust graph contains unsupported non-crates.io dependency ${key}`); + } + } + return [...keys].sort(compareText); + } + + function payloadLicenseAtoms(selectedLicense) { + const atoms = selectedLicense.split(' AND '); + if (atoms.length === 0 || atoms.some((atom) => !PAYLOAD_LICENSE_ATOMS.includes(atom))) { + fail(`unsupported selected license expression ${JSON.stringify(selectedLicense)}`); + } + return atoms; + } + + function selectedLicenseIsCompatible(row) { + for (const atom of payloadLicenseAtoms(row.selectedLicense)) { + if (atom === 'CC-BY-3.0') { + if ( + !row.licenseFiles.some(({ name }) => + LEGAL_BASENAME_FRAGMENTS.some((fragment) => name.toLowerCase().includes(fragment)), + ) + ) { + fail( + `${packageKey(row)} selects CC-BY-3.0 without an exact third-party attribution file`, + ); + } + } else if (atom === 'BSD-3-Clause') { + if ( + !row.licenseFiles.some( + ({ name }) => name.toLowerCase().includes('bsd') || name === 'zstd/LICENSE', + ) + ) { + fail(`${packageKey(row)} selects BSD-3-Clause without an exact BSD license file`); + } + } else if (atom === 'Unicode-3.0') { + if (!row.declaredLicense.includes('Unicode-3.0')) { + fail(`${packageKey(row)} selects Unicode-3.0 but its declared license does not`); + } + } else if (!row.declaredLicense.includes(atom)) { + fail(`${packageKey(row)} selects ${atom} but declares ${row.declaredLicense}`); + } + } + } + + function validateContractShape(contract) { + exactObjectKeys( + contract, + ['schema', 'product', 'cargoSource', 'payloadLicense', 'targets', 'packages'], + 'Rust dependency license contract', + ); + if (contract.schema !== CONTRACT_SCHEMA) fail(`contract schema must be ${CONTRACT_SCHEMA}`); + if (contract.product !== product) fail(`contract product must be ${product}`); + if (contract.cargoSource !== CARGO_SOURCE) fail(`contract cargoSource must be ${CARGO_SOURCE}`); + if (contract.payloadLicense !== RUST_PAYLOAD_LICENSE) { + fail(`contract payloadLicense must be ${RUST_PAYLOAD_LICENSE}`); + } + if (!Array.isArray(contract.packages) || contract.packages.length === 0) { + fail('contract packages must be a non-empty array'); + } + exactObjectKeys(contract.targets, TARGET_IDS, 'contract targets'); + + const packages = new Map(); + const actualPackageOrder = []; + const selectedAtoms = new Set(); + for (const row of contract.packages) { + exactObjectKeys( + row, + [ + 'name', + 'version', + 'checksum', + 'declaredLicense', + 'selectedLicense', + 'targets', + 'licenseFiles', + ], + 'contract package', + ); + const key = packageKey(row); + if (!PACKAGE_KEY.test(key)) fail(`invalid contract package identity ${JSON.stringify(key)}`); + if (packages.has(key)) fail(`duplicate contract package ${key}`); + if (!HEX_64.test(row.checksum)) fail(`${key} has invalid Cargo checksum`); + if (typeof row.declaredLicense !== 'string' || !row.declaredLicense) + fail(`${key} has no declaredLicense`); + if (typeof row.selectedLicense !== 'string' || !row.selectedLicense) + fail(`${key} has no selectedLicense`); + selectedLicenseIsCompatible(row); + for (const atom of payloadLicenseAtoms(row.selectedLicense)) selectedAtoms.add(atom); + if ( + !Array.isArray(row.targets) || + row.targets.length === 0 || + !sameStrings(row.targets, [...new Set(row.targets)].sort(compareText)) || + row.targets.some((target) => !TARGET_BY_ID.has(target)) + ) { + fail(`${key} targets must be a sorted, unique, non-empty supported-target list`); + } + if (!Array.isArray(row.licenseFiles) || row.licenseFiles.length === 0) { + fail(`${key} must pin at least one legal source file`); + } + const legalNames = []; + for (const file of row.licenseFiles) { + exactObjectKeys( + file, + ['name', 'sha256', 'bytes', ...(file.upstream ? ['upstream'] : [])], + `${key} legal file`, + ); + safeMember(file.name, `${key} legal file name`); + if (!legalSourceFile(file.name)) { + fail( + `${key} legal file does not match the fail-closed legal-file classifier: ${file.name}`, + ); + } + if (!HEX_64.test(file.sha256)) fail(`${key} ${file.name} has invalid sha256`); + if (!Number.isSafeInteger(file.bytes) || file.bytes <= 0) + fail(`${key} ${file.name} has invalid byte count`); + if (file.upstream) { + exactObjectKeys( + file.upstream, + ['repository', 'commit', 'path'], + `${key} upstream license`, + ); + const repository = new URL(file.upstream.repository); + if ( + repository.protocol !== 'https:' || + repository.username || + repository.password || + repository.search || + repository.hash || + !/^[a-f0-9]{40}$/.test(file.upstream.commit) + ) + fail(`${key} upstream license must identify an HTTPS repository and exact Git commit`); + safeMember(file.upstream.path, `${key} upstream license path`); + if (!legalSourceFile(file.upstream.path)) + fail(`${key} upstream path is not a legal file`); + } + legalNames.push(file.name); + } + if (!sameStrings(legalNames, [...new Set(legalNames)].sort(compareText))) { + fail(`${key} legal files must be sorted and unique by source member`); + } + packages.set(key, row); + actualPackageOrder.push(key); + } + if (!sameStrings(actualPackageOrder, [...actualPackageOrder].sort(compareText))) { + fail('contract packages must be sorted by name@version'); + } + if ( + !sameStrings( + [...selectedAtoms].sort(compareText), + [...PAYLOAD_LICENSE_ATOMS].sort(compareText), + ) + ) { + fail( + `contract selected-license closure must be ${PAYLOAD_LICENSE_ATOMS.join(', ')}, got ${[...selectedAtoms].sort(compareText).join(', ')}`, + ); + } + + for (const target of TARGET_IDS) { + const row = contract.targets[target]; + exactObjectKeys(row, ['cargoTarget', 'packages'], `contract target ${target}`); + if (row.cargoTarget !== targetRow(target).cargoTarget) { + fail(`${target} cargoTarget must be ${targetRow(target).cargoTarget}`); + } + if ( + !Array.isArray(row.packages) || + row.packages.length === 0 || + !sameStrings(row.packages, [...new Set(row.packages)].sort(compareText)) + ) { + fail(`${target} packages must be a sorted, unique, non-empty list`); + } + for (const key of row.packages) { + if (!packages.has(key)) fail(`${target} references unknown package ${key}`); + if (!packages.get(key).targets.includes(target)) + fail(`${key} does not claim target ${target}`); + } + const reverse = contract.packages + .filter((pkg) => pkg.targets.includes(target)) + .map(packageKey); + if (!sameStrings(row.packages, reverse)) { + fail(`${target} package graph and package target claims disagree`); + } + } + + return packages; + } + + function validateCanonicalBlobs(contract) { + requireRealDirectory(BLOB_ROOT, 'Rust dependency license blob root'); + const expected = new Map(); + for (const row of contract.packages) { + for (const legal of row.licenseFiles) { + const prior = expected.get(legal.sha256); + if (prior !== undefined && prior !== legal.bytes) { + fail(`license digest ${legal.sha256} has inconsistent byte counts`); + } + expected.set(legal.sha256, legal.bytes); + } + } + const actualNames = readdirSync(BLOB_ROOT).sort(compareText); + const expectedNames = [...expected.keys()] + .sort(compareText) + .map((digest) => `${digest}.base64`); + if (!sameStrings(actualNames, expectedNames)) { + fail( + `canonical Rust dependency license blobs differ: expected=${JSON.stringify(expectedNames)}, actual=${JSON.stringify(actualNames)}`, + ); + } + for (const [digest, bytes] of expected) { + canonicalBlobBytes(digest, bytes); + } + } + + function validateLockIdentity(packages) { + let lock; + try { + lock = Bun.TOML.parse(readFileSync(CARGO_LOCK_PATH, 'utf8')); + } catch (cause) { + fail(`cannot parse Cargo.lock: ${cause.message}`); + } + const lockRows = new Map(); + for (const row of lock?.package ?? []) { + const key = packageKey(row); + if (!row.source) continue; + if (lockRows.has(key)) fail(`Cargo.lock contains ambiguous package identity ${key}`); + lockRows.set(key, row); + } + for (const [key, row] of packages) { + const locked = lockRows.get(key); + if (!locked) fail(`Cargo.lock is missing contracted Rust dependency ${key}`); + if (locked.source !== CARGO_SOURCE || locked.checksum !== row.checksum) { + fail( + `Cargo.lock identity changed for ${key}: expected ${CARGO_SOURCE}/${row.checksum}, got ${locked.source}/${locked.checksum}`, + ); + } + } + } + + function validateGraph(contract, packages, graphDirectory) { + requireSafeDirectoryChain(graphDirectory, 'Rust Cargo snapshot directory'); + const metadata = JSON.parse(readCargoSnapshot(graphDirectory, 'metadata.json')); + if ( + path.resolve(metadata.workspace_root) !== ROOT || + !Array.isArray(metadata.workspace_members) + ) + fail('Rust Cargo metadata must describe this workspace'); + const workspaceMembers = new Set(metadata.workspace_members); + const metadataPackages = new Map(); + for (const row of metadata.packages ?? []) { + const key = packageKey(row); + const values = metadataPackages.get(key) ?? []; + values.push(row); + metadataPackages.set(key, values); + } + for (const [key, row] of packages) { + const matches = (metadataPackages.get(key) ?? []).filter( + (candidate) => candidate.source === CARGO_SOURCE, + ); + if (matches.length !== 1) { + fail( + `cargo metadata must contain exactly one crates.io package for ${key}, got ${matches.length}`, + ); + } + const metadataRow = matches[0]; + if (metadataRow.license !== row.declaredLicense) { + fail( + `${key} declared license changed: expected ${row.declaredLicense}, got ${metadataRow.license}`, + ); + } + const sourceRoot = path.dirname(metadataRow.manifest_path); + requireRealDirectory(sourceRoot, `${key} Cargo source directory`); + const legalFiles = walkRegularFiles(sourceRoot).filter(legalSourceFile).sort(compareText); + const contracted = row.licenseFiles.filter((file) => !file.upstream).map(({ name }) => name); + if (!sameStrings(legalFiles, contracted)) { + fail( + `${key} legal source inventory changed: expected=${JSON.stringify(contracted)}, actual=${JSON.stringify(legalFiles)}`, + ); + } + for (const legal of row.licenseFiles) { + if (legal.upstream) { + const vcsPath = path.join(sourceRoot, '.cargo_vcs_info.json'); + requireRealFile(vcsPath, `${key} published Cargo VCS provenance`); + const vcs = JSON.parse(readFileSync(vcsPath, 'utf8')); + if ( + legal.upstream.repository !== metadataRow.repository || + legal.upstream.commit !== vcs.git?.sha1 || + legalFiles.includes(legal.name) + ) + fail( + `${key} supplemental license must match its published repository/commit and must not replace a crate legal file`, + ); + continue; + } + const file = path.join(sourceRoot, ...legal.name.split('/')); + const content = readFileSync(file); + if (content.length !== legal.bytes || sha256(content) !== legal.sha256) { + fail(`${key} legal source file changed: ${legal.name}`); + } + } + } + + for (const target of TARGET_IDS) { + const actual = cargoTreePackageKeys( + contract.targets[target].cargoTarget, + metadataPackages, + graphDirectory, + workspaceMembers, + ); + const expected = contract.targets[target].packages; + if (!sameStrings(actual, expected)) { + fail( + `${target} exact normal dependency graph changed: expected=${JSON.stringify(expected)}, actual=${JSON.stringify(actual)}`, + ); + } + } + } + + function loadRustDependencyLicenseContract({ + contractPath = CONTRACT_PATH, + auditLock = false, + graphDirectory, + } = {}) { + const resolvedContractPath = path.resolve(contractPath); + const cacheable = + resolvedContractPath === CONTRACT_PATH && !auditLock && graphDirectory === undefined; + if (cacheable && validatedDefaultContract !== undefined) return validatedDefaultContract; + requireRealFile(resolvedContractPath, 'Rust dependency license contract'); + const bytes = readFileSync(resolvedContractPath); + let contract; + try { + contract = JSON.parse(bytes.toString('utf8')); + } catch (cause) { + fail(`cannot parse ${resolvedContractPath}: ${cause.message}`); + } + const packages = validateContractShape(contract); + validateCanonicalBlobs(contract); + if (auditLock || graphDirectory !== undefined) validateLockIdentity(packages); + if (graphDirectory !== undefined) validateGraph(contract, packages, graphDirectory); + const result = Object.freeze({ contract, packages, contractPath: resolvedContractPath }); + if (cacheable) { + validatedDefaultContract = result; + } + return result; + } + + function targetPackages(contractState, target) { + const targetContract = contractState.contract.targets[target]; + return targetContract.packages.map((key) => contractState.packages.get(key)); + } + + function targetBlobMembers(contractState, target) { + const digests = [ + ...new Set( + targetPackages(contractState, target).flatMap((row) => + row.licenseFiles.map(({ sha256: digest }) => digest), + ), + ), + ].sort(compareText); + return new Map( + digests.map((digest, index) => [digest, `licenses/${String(index).padStart(3, '0')}.txt`]), + ); + } + + function renderedTargetIndex(contractState, target) { + const targetContract = contractState.contract.targets[target]; + const blobMembers = targetBlobMembers(contractState, target); + return { + schema: INDEX_SCHEMA, + product: product, + target, + cargoTarget: targetContract.cargoTarget, + payloadLicense: RUST_PAYLOAD_LICENSE, + packages: targetPackages(contractState, target).map((row) => ({ + name: row.name, + version: row.version, + checksum: row.checksum, + sourceUrl: `https://crates.io/api/v1/crates/${encodeURIComponent(row.name)}/${encodeURIComponent(row.version)}/download`, + declaredLicense: row.declaredLicense, + selectedLicense: row.selectedLicense, + licenseFiles: row.licenseFiles.map((legal) => ({ + name: legal.name, + sha256: legal.sha256, + bytes: legal.bytes, + member: blobMembers.get(legal.sha256), + ...(legal.upstream ? { upstream: legal.upstream } : {}), + })), + })), + }; + } + + function targetExpectedFiles(contractState, target) { + const files = new Map(); + const blobMembers = targetBlobMembers(contractState, target); + files.set( + `${RUST_DEPENDENCY_LICENSE_ROOT}/DEPENDENCIES.json`, + Buffer.from(canonicalJson(renderedTargetIndex(contractState, target))), + ); + for (const row of targetPackages(contractState, target)) { + for (const legal of row.licenseFiles) { + files.set( + `${RUST_DEPENDENCY_LICENSE_ROOT}/${blobMembers.get(legal.sha256)}`, + canonicalBlobBytes(legal.sha256, legal.bytes), + ); + } + } + return new Map([...files].sort(([left], [right]) => compareText(left, right))); + } + + function rustDependencyLicenseMembers(target, { prefix = '' } = {}) { + targetRow(target); + const state = loadRustDependencyLicenseContract(); + const checkedPrefix = prefix + ? safeMember(prefix.replace(/\/$/u, ''), 'Rust dependency archive prefix') + : ''; + return [...targetExpectedFiles(state, target).keys()].map((member) => + checkedPrefix ? `${checkedPrefix}/${member}` : member, + ); + } + + function expectedDirectories(expectedFiles) { + const directories = new Set(); + for (const member of expectedFiles.keys()) { + const parts = member.split('/'); + for (let index = 1; index < parts.length; index += 1) { + directories.add(parts.slice(0, index).join('/')); + } + } + return directories; + } + + function normalizeRustDependencyLicenseModes(destination, target) { + targetRow(target); + const state = loadRustDependencyLicenseContract(); + const root = requireSafeDirectoryChain(destination, 'Rust dependency license carrier root'); + const expected = targetExpectedFiles(state, target); + for (const member of expectedDirectories(expected)) { + const directory = path.join(root, ...member.split('/')); + requireRealDirectory(directory, `Rust dependency license directory ${member}`); + chmodSync(directory, 0o755); + } + for (const member of expected.keys()) { + const file = path.join(root, ...member.split('/')); + let stat; + try { + stat = lstatSync(file); + } catch (cause) { + fail(`Rust dependency license member cannot be inspected: ${member}: ${cause.message}`); + } + if (!stat.isFile() || stat.isSymbolicLink()) { + fail(`Rust dependency license member must be a regular non-symlink file: ${member}`); + } + chmodSync(file, 0o644); + } + } + + function stageRustDependencyLicenses(destination, target) { + targetRow(target); + const state = loadRustDependencyLicenseContract(); + const root = ensureSafeDirectoryChain(destination, 'Rust dependency license staging root'); + const dependencyRoot = path.join(root, ...RUST_DEPENDENCY_LICENSE_ROOT.split('/')); + // Validate the namespace ancestor before even inspecting the owned leaf. + // rmSync on a leaf beneath a symlinked THIRD_PARTY_LICENSES directory could + // otherwise remove data outside the carrier stage. + ensureSafeDirectoryChain( + path.dirname(dependencyRoot), + 'Rust dependency license namespace parent', + ); + let prior; + try { + prior = lstatSync(dependencyRoot); + } catch (cause) { + if (cause?.code !== 'ENOENT') + fail(`cannot inspect prior Rust dependency license root: ${cause.message}`); + } + if (prior) { + if (!prior.isDirectory() || prior.isSymbolicLink()) { + fail(`prior Rust dependency license root must be a real directory: ${dependencyRoot}`); + } + rmSync(dependencyRoot, { recursive: true }); + } + ensureSafeDirectoryChain( + path.join(dependencyRoot, 'licenses'), + 'Rust dependency license staging root', + ); + for (const [member, bytes] of targetExpectedFiles(state, target)) { + const file = path.join(root, ...member.split('/')); + ensureSafeDirectoryChain(path.dirname(file), 'Rust dependency license staging parent'); + writeFileSync(file, bytes); + chmodSync(file, 0o644); + } + normalizeRustDependencyLicenseModes(root, target); + assertRustDependencyLicensesInDirectory(root, { target }); + return rustDependencyLicenseMembers(target); + } + + function directoryNamespaceEntries(root) { + const namespace = path.join(root, ...RUST_DEPENDENCY_LICENSE_ROOT.split('/')); + requireSafeDirectoryChain(namespace, 'Rust dependency license namespace'); + const entries = new Map(); + function walk(directory, relative) { + for (const name of readdirSync(directory).sort(compareText)) { + const file = path.join(directory, name); + const member = relative ? `${relative}/${name}` : name; + const stat = lstatSync(file); + entries.set(`${RUST_DEPENDENCY_LICENSE_ROOT}/${member}`, { file, stat }); + if (stat.isDirectory() && !stat.isSymbolicLink()) walk(file, member); + } + } + walk(namespace, ''); + return entries; + } + + function assertRustDependencyLicensesInDirectory(directory, { target } = {}) { + targetRow(target); + const state = loadRustDependencyLicenseContract(); + const root = requireSafeDirectoryChain(directory, 'Rust dependency license carrier root'); + const expected = targetExpectedFiles(state, target); + const expectedDirs = expectedDirectories(expected); + const actual = directoryNamespaceEntries(root); + const expectedMembers = new Set([...expected.keys(), ...expectedDirs]); + for (const member of expectedMembers) { + if (member === 'THIRD_PARTY_LICENSES' || member === RUST_DEPENDENCY_LICENSE_ROOT) continue; + const entry = actual.get(member); + if (!entry) fail(`Rust dependency license carrier is missing ${member}`); + if (expected.has(member)) { + if (!entry.stat.isFile() || entry.stat.isSymbolicLink()) + fail(`${member} must be a regular non-symlink file`); + if (!hasCanonicalRustFilesystemMode(entry.stat.mode, 0o644)) + fail(`${member} must have mode 0644`); + if (!readFileSync(entry.file).equals(expected.get(member))) + fail(`${member} differs from the canonical dependency license bytes`); + } else { + if (!entry.stat.isDirectory() || entry.stat.isSymbolicLink()) + fail(`${member} must be a real non-symlink directory`); + if (!hasCanonicalRustFilesystemMode(entry.stat.mode, 0o755)) + fail(`${member} must have mode 0755`); + } + } + for (const member of actual.keys()) { + if (!expectedMembers.has(member)) + fail(`Rust dependency license carrier has unexpected member ${member}`); + } + return [...expected.keys()]; + } + + function checkedArchivePrefix(prefix) { + if (prefix === '') return ''; + return safeMember( + String(prefix).replace(/^\.\//u, '').replace(/\/$/u, ''), + 'Rust dependency archive prefix', + ); + } + + function assertRustDependencyLicensesInEntries( + entries, + { target, prefix = '', label = 'archive' } = {}, + ) { + targetRow(target); + if (!(entries instanceof Map)) fail('Rust dependency archive entries must be a Map'); + const state = loadRustDependencyLicenseContract(); + const archivePrefix = checkedArchivePrefix(prefix); + const localExpected = targetExpectedFiles(state, target); + const localDirs = expectedDirectories(localExpected); + const prefixed = (member) => (archivePrefix ? `${archivePrefix}/${member}` : member); + const expectedFiles = new Map( + [...localExpected].map(([member, bytes]) => [prefixed(member), bytes]), + ); + const expectedDirs = new Set([...localDirs].map(prefixed)); + const namespace = `${prefixed(RUST_DEPENDENCY_LICENSE_ROOT)}/`; + for (const [member, bytes] of expectedFiles) { + const entry = entries.get(member); + if (!entry?.isFile || entry.isSymbolicLink) + fail(`${label} is missing regular dependency license member ${member}`); + if ((entry.mode & 0o444) !== 0o444 || (entry.mode & 0o7000) !== 0) + fail( + `${label} dependency license member ${member} must be readable by all users without special permission bits`, + ); + if (!Buffer.from(entry.data()).equals(bytes)) + fail(`${label} dependency license member ${member} differs from canonical bytes`); + } + for (const [member, entry] of entries) { + if (expectedFiles.has(member)) continue; + if (expectedDirs.has(member)) { + if (!entry.isDirectory || entry.isSymbolicLink) + fail(`${label} dependency license directory ${member} must be a real directory`); + if ((entry.mode & 0o555) !== 0o555 || (entry.mode & 0o7000) !== 0) + fail( + `${label} dependency license directory ${member} must be readable and searchable by all users without special permission bits`, + ); + continue; + } + if (member !== prefixed(RUST_DEPENDENCY_LICENSE_ROOT) && !member.startsWith(namespace)) + continue; + fail(`${label} contains unexpected dependency license member ${member}`); + } + assertReleaseNoticesInEntries(entries, { + profile: noticeProfile, + prefix: archivePrefix, + exact: false, + label, + }); + return [...expectedFiles.keys()]; + } + + function assertRustDependencyLicensesInArchive(file, options = {}) { + const archive = path.resolve(file); + return assertRustDependencyLicensesInEntries(readPortableArchiveEntries(archive), { + ...options, + label: options.label ?? path.basename(archive), + }); + } + + function usage() { + return [ + 'usage:', + ` ${TOOL} check-contract`, + ` bash ${owner}/tools/audit-dependency-licenses.sh`, + ` ${TOOL} stage --target <${TARGET_IDS.join('|')}>`, + ` ${TOOL} check-directory --target <${TARGET_IDS.join('|')}>`, + ` ${TOOL} check-archive --target <${TARGET_IDS.join('|')}> [--prefix ]`, + ].join('\n'); + } + + function parseCli(argv) { + const values = [...argv]; + const command = values.shift(); + if (command === 'audit-contract' && values.length === 1) + return { command, graphDirectory: path.resolve(values[0]) }; + if (['check-contract', 'audit-targets'].includes(command)) { + if (values.length > 0) fail(usage()); + return { command }; + } + if (!['stage', 'check-directory', 'check-archive'].includes(command)) fail(usage()); + const subject = values.shift(); + if (!subject) fail(usage()); + let target; + let prefix = ''; + while (values.length > 0) { + const flag = values.shift(); + if (flag === '--target') { + if (target !== undefined) fail('--target may be supplied only once'); + target = values.shift(); + if (!target) fail('--target requires a value'); + } else if (flag === '--prefix' && command === 'check-archive') { + if (prefix) fail('--prefix may be supplied only once'); + prefix = values.shift(); + if (prefix === undefined) fail('--prefix requires a value'); + } else { + fail(`unsupported argument ${JSON.stringify(flag)}\n${usage()}`); + } + } + targetRow(target); + return { command, subject, target, prefix }; + } + + function main() { + try { + const args = parseCli(process.argv.slice(2)); + if (args.command === 'audit-targets') { + console.log(TARGET_ROWS.map((row) => row.cargoTarget).join('\n')); + } else if (args.command === 'check-contract') { + const state = loadRustDependencyLicenseContract(); + console.log( + `${TOOL}: self-contained license contract passed (${state.contract.packages.length} packages)`, + ); + } else if (args.command === 'audit-contract') { + const state = loadRustDependencyLicenseContract({ graphDirectory: args.graphDirectory }); + console.log( + `${TOOL}: exact graph/source audit passed (${state.contract.packages.length} packages)`, + ); + } else if (args.command === 'stage') { + stageRustDependencyLicenses(args.subject, args.target); + console.log(`${TOOL}: staged ${args.target} dependency licenses in ${args.subject}`); + } else if (args.command === 'check-directory') { + assertRustDependencyLicensesInDirectory(args.subject, { target: args.target }); + console.log(`${TOOL}: checked ${args.target} dependency licenses in ${args.subject}`); + } else { + assertRustDependencyLicensesInArchive(args.subject, { + target: args.target, + prefix: args.prefix, + }); + console.log(`${TOOL}: checked ${args.target} dependency licenses in ${args.subject}`); + } + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } + } + + return { + RUST_DEPENDENCY_LICENSE_ROOT, + RUST_PAYLOAD_LICENSE, + isAllowedRustPathPackageMetadataRow, + hasCanonicalRustFilesystemMode, + hasSafeRustSourceFilesystemMode, + loadRustDependencyLicenseContract, + rustDependencyLicenseMembers, + normalizeRustDependencyLicenseModes, + stageRustDependencyLicenses, + assertRustDependencyLicensesInDirectory, + assertRustDependencyLicensesInEntries, + assertRustDependencyLicensesInArchive, + runCli: main, + }; +} diff --git a/tools/packaging/rust-native-targets.mts b/tools/packaging/rust-native-targets.mts new file mode 100644 index 000000000..fb4b852f6 --- /dev/null +++ b/tools/packaging/rust-native-targets.mts @@ -0,0 +1,86 @@ +const NATIVE_TARGET_CFG = Object.freeze({ + 'linux-arm64-gnu': 'all(target_os = "linux", target_arch = "aarch64", target_env = "gnu")', + 'linux-x64-gnu': 'all(target_os = "linux", target_arch = "x86_64", target_env = "gnu")', + 'macos-arm64': 'all(target_os = "macos", target_arch = "aarch64")', + 'windows-x64-msvc': 'all(target_os = "windows", target_arch = "x86_64", target_env = "msvc")', +}); + +function fail(message) { + throw new Error(`rust-native-targets: ${message}`); +} + +function nonEmptyUniqueStrings(values, label) { + if (!Array.isArray(values) || values.length === 0) { + fail(`${label} must be a non-empty string list`); + } + if ( + !values.every( + (value) => typeof value === 'string' && value.trim() === value && value.length > 0, + ) + ) { + fail(`${label} must contain only non-empty, trimmed strings`); + } + if (new Set(values).size !== values.length) { + fail(`${label} must not contain duplicates`); + } + return values; +} + +export function rustNativeTargetCfg(target) { + const targetId = typeof target === 'string' ? target : target?.target; + if (typeof targetId !== 'string' || !(targetId in NATIVE_TARGET_CFG)) { + fail(`unsupported native Cargo target ${JSON.stringify(targetId)}`); + } + return NATIVE_TARGET_CFG[targetId]; +} + +export function assertSameNativeTargetSet(label, expected, actual) { + const expectedTargets = [...nonEmptyUniqueStrings(expected, `${label} expected targets`)].sort(); + const actualTargets = [...nonEmptyUniqueStrings(actual, `${label} actual targets`)].sort(); + if (JSON.stringify(expectedTargets) !== JSON.stringify(actualTargets)) { + fail( + `${label} target mismatch: expected=${JSON.stringify(expectedTargets)}, ` + + `actual=${JSON.stringify(actualTargets)}`, + ); + } +} + +export function renderUnsupportedNativeTargetGuard({ + product, + nativeTargets, + nativeCfgs, + feature = null, + featureLabel = null, + guidance, +}) { + if (typeof product !== 'string' || product.trim() !== product || product.length === 0) { + fail('guard product must be a non-empty, trimmed string'); + } + const targets = nonEmptyUniqueStrings(nativeTargets, `${product} guard targets`); + const cfgs = nonEmptyUniqueStrings(nativeCfgs, `${product} guard cfgs`); + if (targets.length !== cfgs.length) { + fail(`${product} guard requires one cfg per declared target`); + } + if ( + feature !== null && + (typeof feature !== 'string' || feature.trim() !== feature || feature.length === 0) + ) { + fail(`${product} guard feature must be null or a non-empty, trimmed string`); + } + if (featureLabel !== null && feature === null) { + fail(`${product} guard cannot declare a feature label without a feature`); + } + if (typeof guidance !== 'string' || guidance.trim() !== guidance || guidance.length === 0) { + fail(`${product} guard guidance must be a non-empty, trimmed string`); + } + + const unsupportedTarget = `not(any(${cfgs.join(', ')}))`; + const condition = + feature === null + ? unsupportedTarget + : `all(feature = ${JSON.stringify(feature)}, ${unsupportedTarget})`; + const subject = + feature === null ? product : `${product}'s ${featureLabel ?? `${feature} feature`}`; + const message = `${subject} supports only ${targets.join(', ')}; ${guidance}`; + return `#[cfg(${condition})]\ncompile_error!(${JSON.stringify(message)});`; +} diff --git a/tools/packaging/source-only-sdk-package.mts b/tools/packaging/source-only-sdk-package.mts new file mode 100644 index 000000000..17c668a1d --- /dev/null +++ b/tools/packaging/source-only-sdk-package.mts @@ -0,0 +1,297 @@ +#!/usr/bin/env bun + +import { chmodSync, lstatSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { readPortableArchiveEntries } from './portable-archive.mts'; +import { + assertReleaseNoticesInArchive, + assertReleaseNoticesInDirectory, + releasePackageLicense, + stageReleaseNotices, +} from './release-notices.mts'; +import { requireSafeDirectoryChain } from './release-directory-safety.mts'; + +const TOOL = 'source-only-sdk-package.mts'; +const SOURCE_NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' }); +const SOURCE_LICENSE = releasePackageLicense().spdx; +const NOTICE_FILES = Object.freeze(['LICENSE', 'THIRD_PARTY_NOTICES.md']); + +export const SOURCE_ONLY_NPM_PROFILES = Object.freeze({ + js: Object.freeze({ + name: '@oliphaunt/ts', + scripts: Object.freeze({}), + optionalDependencyVersions: Object.freeze({ + '@oliphaunt/broker-darwin-arm64': 'brokerVersion', + '@oliphaunt/broker-linux-arm64-gnu': 'brokerVersion', + '@oliphaunt/broker-linux-x64-gnu': 'brokerVersion', + '@oliphaunt/broker-win32-x64-msvc': 'brokerVersion', + '@oliphaunt/liboliphaunt-darwin-arm64': 'liboliphauntVersion', + '@oliphaunt/liboliphaunt-linux-arm64-gnu': 'liboliphauntVersion', + '@oliphaunt/liboliphaunt-linux-x64-gnu': 'liboliphauntVersion', + '@oliphaunt/liboliphaunt-win32-x64-msvc': 'liboliphauntVersion', + '@oliphaunt/node-direct-darwin-arm64': 'nodeDirectAddonVersion', + '@oliphaunt/node-direct-linux-arm64-gnu': 'nodeDirectAddonVersion', + '@oliphaunt/node-direct-linux-x64-gnu': 'nodeDirectAddonVersion', + '@oliphaunt/node-direct-win32-x64-msvc': 'nodeDirectAddonVersion', + }), + }), + 'react-native': Object.freeze({ + name: '@oliphaunt/react-native', + scripts: Object.freeze({ + 'package:verify-ios': 'node ./tools/verify-ios-package.mjs --package-dir .', + }), + }), +}); + +function requireRegularFile(file, label) { + let stat; + try { + stat = lstatSync(file); + } catch (cause) { + throw new Error(`${label} cannot be inspected: ${cause.message}`); + } + if (!stat.isFile() || stat.isSymbolicLink()) { + throw new Error(`${label} must be a regular non-symlink file: ${file}`); + } + return stat; +} + +function readJson(file, label) { + requireRegularFile(file, label); + let parsed; + try { + parsed = JSON.parse(readFileSync(file, 'utf8')); + } catch (cause) { + throw new Error(`${label} must contain valid JSON: ${cause.message}`); + } + if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { + throw new Error(`${label} must contain a JSON object`); + } + return parsed; +} + +function checkedScripts(value, label) { + if (!value || typeof value !== 'object' || Array.isArray(value)) { + throw new Error(`${label} scripts contract must be an object`); + } + const scripts = {}; + for (const name of Object.keys(value).sort()) { + const command = value[name]; + if (typeof command !== 'string' || command.length === 0) { + throw new Error(`${label} script ${JSON.stringify(name)} must be a non-empty string`); + } + scripts[name] = command; + } + return scripts; +} + +function exactOptionalDependencies(manifest, fields, label) { + if (fields === undefined) return undefined; + const metadata = manifest.oliphaunt; + if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata)) { + throw new Error(`${label} must declare oliphaunt compatibility metadata`); + } + const dependencies = {}; + for (const [name, field] of Object.entries(fields)) { + const version = metadata[field]; + if (typeof version !== 'string' || !/^\d+[.]\d+[.]\d+$/u.test(version)) { + throw new Error(`${label} oliphaunt.${field} must be an exact stable version`); + } + dependencies[name] = version; + } + return dependencies; +} + +function sameStringMap(left, right) { + const entries = Object.entries(left ?? {}); + return ( + entries.length === Object.keys(right).length && + entries.every(([name, version]) => right[name] === version) + ); +} + +function assertManifestContract(manifest, { name, scripts, optionalDependencyVersions }, label) { + if (manifest.name !== name) { + throw new Error(`${label} must identify ${name}, got ${JSON.stringify(manifest.name)}`); + } + if (manifest.license !== SOURCE_LICENSE) { + throw new Error( + `${label} must declare the source-only license ${SOURCE_LICENSE}, got ${JSON.stringify(manifest.license)}`, + ); + } + const expectedScripts = checkedScripts(scripts, label); + const actualScripts = manifest.scripts ?? {}; + if ( + !actualScripts || + typeof actualScripts !== 'object' || + Array.isArray(actualScripts) || + JSON.stringify(actualScripts) !== JSON.stringify(expectedScripts) + ) { + throw new Error( + `${label} must contain only the publish-safe scripts ${JSON.stringify(expectedScripts)}, got ${JSON.stringify(actualScripts)}`, + ); + } + if (Object.hasOwn(manifest, 'devDependencies')) { + throw new Error(`${label} must not publish development-only dependencies`); + } + const expectedOptional = exactOptionalDependencies(manifest, optionalDependencyVersions, label); + if ( + expectedOptional !== undefined && + !sameStringMap(manifest.optionalDependencies, expectedOptional) + ) { + throw new Error( + `${label} must pin its optional runtime packages to its compatibility versions`, + ); + } +} + +function requireNoticeAllowlist(manifest, label) { + if (!Array.isArray(manifest.files)) { + throw new Error(`${label} must declare an npm files allowlist`); + } + for (const member of NOTICE_FILES) { + if (!manifest.files.includes(member)) { + throw new Error(`${label} npm files allowlist must include ${member}`); + } + } +} + +function writeManifest(file, manifest) { + writeFileSync(file, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8'); + chmodSync(file, 0o644); +} + +export function prepareSourceOnlyNpmPackage(packageDir, contract) { + // Validate the complete lexical path before reading or rewriting package.json. + // Notice staging enforces the same boundary, but it runs after sanitation. + const directory = requireSafeDirectoryChain(packageDir, { + label: 'source-only npm package directory', + }); + const packageJsonFile = path.join(directory, 'package.json'); + const manifest = readJson(packageJsonFile, 'source-only npm package manifest'); + const expectedScripts = checkedScripts(contract.scripts, contract.name); + if (manifest.name !== contract.name) { + throw new Error( + `source-only npm package manifest must identify ${contract.name}, got ${JSON.stringify(manifest.name)}`, + ); + } + if (manifest.license !== SOURCE_LICENSE) { + throw new Error( + `source-only npm package manifest must declare ${SOURCE_LICENSE}, got ${JSON.stringify(manifest.license)}`, + ); + } + requireNoticeAllowlist(manifest, 'source-only npm package manifest'); + for (const [name, command] of Object.entries(expectedScripts)) { + if (manifest.scripts?.[name] !== command) { + throw new Error( + `source-only npm package manifest is missing publish-safe script ${name}=${JSON.stringify(command)}`, + ); + } + } + if (Object.keys(expectedScripts).length === 0) { + delete manifest.scripts; + } else { + manifest.scripts = expectedScripts; + } + const exactOptional = exactOptionalDependencies( + manifest, + contract.optionalDependencyVersions, + 'source-only npm package manifest', + ); + if (exactOptional !== undefined) { + const sourceOptional = manifest.optionalDependencies ?? {}; + const sameNames = + Object.keys(sourceOptional).length === Object.keys(exactOptional).length && + Object.keys(sourceOptional).every((name) => Object.hasOwn(exactOptional, name)); + const local = Object.values(sourceOptional).every((version) => version === 'workspace:*'); + const staged = Object.entries(exactOptional).every( + ([name, version]) => sourceOptional[name] === version, + ); + if (!sameNames || (!local && !staged)) { + throw new Error( + 'source-only npm package manifest optional runtime packages must use workspace:* locally or exact compatibility versions when staged', + ); + } + manifest.optionalDependencies = exactOptional; + } + delete manifest.devDependencies; + writeManifest(packageJsonFile, manifest); + stageReleaseNotices(directory, SOURCE_NOTICE_OPTIONS); + assertReleaseNoticesInDirectory(directory, SOURCE_NOTICE_OPTIONS); + assertManifestContract(manifest, contract, 'staged source-only npm package manifest'); + return packageJsonFile; +} + +function archiveJson(entries, member, label) { + const entry = entries.get(member); + if (!entry?.isFile || entry.isSymbolicLink) { + throw new Error(`${label} is missing regular member ${member}`); + } + if ((entry.mode & 0o444) !== 0o444 || (entry.mode & 0o7000) !== 0) { + throw new Error( + `${label} member ${member} must be readable by all users without special permission bits`, + ); + } + let parsed; + try { + parsed = JSON.parse(Buffer.from(entry.data()).toString('utf8')); + } catch (cause) { + throw new Error(`${label} member ${member} must contain valid JSON: ${cause.message}`); + } + return parsed; +} + +export function assertSourceOnlyNpmArchive(archive, contract) { + const file = path.resolve(archive); + const label = path.basename(file); + assertReleaseNoticesInArchive(file, { + ...SOURCE_NOTICE_OPTIONS, + prefix: 'package', + label, + }); + const entries = readPortableArchiveEntries(file); + const manifest = archiveJson(entries, 'package/package.json', label); + assertManifestContract(manifest, contract, `${label} package.json`); + requireNoticeAllowlist(manifest, `${label} package.json`); + return manifest; +} + +function usage() { + return [ + 'usage:', + ` ${TOOL} prepare-npm `, + ` ${TOOL} check-npm-archive `, + ].join('\n'); +} + +function profile(name) { + const selected = SOURCE_ONLY_NPM_PROFILES[name]; + if (!selected) { + throw new Error(`unsupported source-only npm package profile ${JSON.stringify(name)}`); + } + return selected; +} + +function main(argv) { + const [command, first, second, ...extra] = argv; + if (command === 'prepare-npm' && first && second && extra.length === 0) { + prepareSourceOnlyNpmPackage(second, profile(first)); + } else if (command === 'check-npm-archive' && first && second && extra.length === 0) { + assertSourceOnlyNpmArchive(second, profile(first)); + } else { + throw new Error(usage()); + } + console.log(`${TOOL}: ${command} passed`); +} + +const invoked = process.argv[1] ? path.resolve(process.argv[1]) : ''; +if (invoked === fileURLToPath(import.meta.url)) { + try { + main(process.argv.slice(2)); + } catch (error) { + console.error(`${TOOL}: ${error instanceof Error ? error.message : String(error)}`); + process.exitCode = 1; + } +} diff --git a/tools/packaging/source-only-sdk-package.test.mts b/tools/packaging/source-only-sdk-package.test.mts new file mode 100644 index 000000000..4aa69a018 --- /dev/null +++ b/tools/packaging/source-only-sdk-package.test.mts @@ -0,0 +1,129 @@ +import assert from 'node:assert/strict'; +import { + chmodSync, + existsSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import test from 'node:test'; + +import { + assertSourceOnlyNpmArchive, + prepareSourceOnlyNpmPackage, + SOURCE_ONLY_NPM_PROFILES, +} from './source-only-sdk-package.mts'; + +const QUERY_PACKAGE = '@oliphaunt/ts-query'; + +import { assertReleaseNoticesInDirectory } from './release-notices.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); + +function writeJson(file, value) { + writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, 'utf8'); +} + +function packageManifest(profile) { + const manifest = { + name: profile.name, + version: '1.2.3', + license: 'MIT', + files: ['index.js', 'LICENSE', 'THIRD_PARTY_NOTICES.md'], + scripts: { + build: 'false', + prepack: 'false', + test: 'false', + ...profile.scripts, + }, + dependencies: { [QUERY_PACKAGE]: '0.1.0' }, + devDependencies: { imaginary: '1.0.0' }, + }; + if (profile.optionalDependencyVersions !== undefined) { + manifest.oliphaunt = Object.fromEntries( + [...new Set(Object.values(profile.optionalDependencyVersions))].map((field) => [ + field, + '1.2.0', + ]), + ); + manifest.optionalDependencies = Object.fromEntries( + Object.keys(profile.optionalDependencyVersions).map((name) => [name, 'workspace:*']), + ); + } + return manifest; +} + +if (['prepare', 'verify'].includes(process.argv[2])) { + const scratch = process.argv[3]; + for (const [profileName, profile] of Object.entries(SOURCE_ONLY_NPM_PROFILES)) { + const packageDir = path.join(scratch, profileName, 'package'); + if (process.argv[2] === 'prepare') { + mkdirSync(packageDir, { recursive: true }); + writeJson(path.join(packageDir, 'package.json'), packageManifest(profile)); + writeFileSync(path.join(packageDir, 'index.js'), 'export {};\n', 'utf8'); + prepareSourceOnlyNpmPackage(packageDir, profile); + prepareSourceOnlyNpmPackage(packageDir, profile); + + const staged = JSON.parse(readFileSync(path.join(packageDir, 'package.json'), 'utf8')); + assert.equal(staged.license, 'MIT'); + assert.deepEqual(staged.scripts ?? {}, profile.scripts); + assert.equal(staged.devDependencies, undefined); + if (profile.optionalDependencyVersions !== undefined) { + assert.deepEqual( + staged.optionalDependencies, + Object.fromEntries( + Object.keys(profile.optionalDependencyVersions).map((name) => [name, '1.2.0']), + ), + ); + } + } else { + const destination = path.join(scratch, profileName, 'packed'); + const archives = readdirSync(destination).filter((entry) => entry.endsWith('.tgz')); + assert.equal(archives.length, 1); + const archive = path.join(destination, archives[0]); + const packed = assertSourceOnlyNpmArchive(archive, profile); + assert.deepEqual(packed.scripts ?? {}, profile.scripts); + assert.equal(packed.devDependencies, undefined); + + writeFileSync(path.join(packageDir, 'LICENSE'), 'not canonical\n', 'utf8'); + chmodSync(path.join(packageDir, 'LICENSE'), 0o644); + assert.throws( + () => assertReleaseNoticesInDirectory(packageDir, { profile: 'source-sdk' }), + /differs byte-for-byte/u, + ); + } + } + process.exit(0); +} + +test('rejects a symlinked package directory before rewriting its manifest', { + skip: process.platform === 'win32', +}, () => { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const scratch = mkdtempSync(path.join(ROOT, 'target', 'source-only-symlink-')); + try { + const packageDir = path.join(scratch, 'real-package'); + const alias = path.join(scratch, 'package-alias'); + mkdirSync(packageDir); + const manifestFile = path.join(packageDir, 'package.json'); + writeJson(manifestFile, packageManifest(SOURCE_ONLY_NPM_PROFILES.js)); + writeFileSync(path.join(packageDir, 'index.js'), 'export {};\n', 'utf8'); + const before = readFileSync(manifestFile); + symlinkSync(packageDir, alias, 'dir'); + + assert.throws( + () => prepareSourceOnlyNpmPackage(alias, SOURCE_ONLY_NPM_PROFILES.js), + /symlink or non-directory ancestor/u, + ); + assert.deepEqual(readFileSync(manifestFile), before); + assert.equal(existsSync(path.join(packageDir, 'LICENSE')), false); + assert.equal(existsSync(path.join(packageDir, 'THIRD_PARTY_NOTICES.md')), false); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); diff --git a/tools/packaging/source-only-sdk-package.test.sh b/tools/packaging/source-only-sdk-package.test.sh new file mode 100644 index 000000000..e2164becf --- /dev/null +++ b/tools/packaging/source-only-sdk-package.test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +bun test ./tools/packaging/source-only-sdk-package.test.mts +scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-source-sdk-XXXXXX") +trap 'rm -rf "$scratch"' EXIT +bun tools/packaging/source-only-sdk-package.test.mts prepare "$scratch" +for package in "$scratch"/*/package; do + mkdir -p "${package%/package}/packed" + bun pm pack --cwd "$package" --destination "${package%/package}/packed" --ignore-scripts +done +bun tools/packaging/source-only-sdk-package.test.mts verify "$scratch" diff --git a/tools/packaging/staging.mts b/tools/packaging/staging.mts new file mode 100644 index 000000000..989ec11f6 --- /dev/null +++ b/tools/packaging/staging.mts @@ -0,0 +1,108 @@ +import { cpSync, mkdirSync, readdirSync, rmSync, writeFileSync, statSync } from 'node:fs'; +import path from 'node:path'; + +export const ROOT = path.resolve(import.meta.dir, '../..'); + +const PREFIX = 'SDK artifact staging'; + +export function fail(message) { + console.error(`${PREFIX}: ${message}`); + process.exit(1); +} + +export function rel(file) { + const relative = path.relative(ROOT, String(file)); + if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) { + return String(file).split(path.sep).join('/'); + } + return relative.split(path.sep).join('/'); +} + +export function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +export function isFile(file) { + try { + return statSync(file).isFile(); + } catch { + return false; + } +} + +export function isDirectory(file) { + try { + return statSync(file).isDirectory(); + } catch { + return false; + } +} + +export function requireFile(file) { + if (!isFile(file)) { + fail(`missing package-shape output: ${rel(file)}`); + } +} + +export function requireDir(file) { + if (!isDirectory(file)) { + fail(`missing package-shape output directory: ${rel(file)}`); + } +} + +export function copyDirContents(source, destination, { filter = () => true } = {}) { + mkdirSync(destination, { recursive: true }); + for (const entry of readdirSync(source, { withFileTypes: true }).sort((left, right) => + compareText(left.name, right.name), + )) { + const sourcePath = path.join(source, entry.name); + const destinationPath = path.join(destination, entry.name); + cpSync(sourcePath, destinationPath, { + recursive: true, + filter, + }); + } +} + +export function filesUnder(root) { + const files = []; + const visit = (directory) => { + for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => + compareText(left.name, right.name), + )) { + const file = path.join(directory, entry.name); + if (entry.isDirectory()) { + visit(file); + } else if (entry.isFile()) { + files.push(file); + } + } + }; + visit(root); + return files; +} + +export async function stageSdkArtifacts(product, stage) { + const artifactRoot = path.join(ROOT, 'target/sdk-artifacts', product); + const workRoot = path.join(ROOT, 'target/sdk-artifacts-work', product); + for (const directory of [artifactRoot, workRoot]) { + rmSync(directory, { recursive: true, force: true }); + mkdirSync(directory, { recursive: true }); + } + await stage(artifactRoot, workRoot); + writeSdkArtifactIndex(artifactRoot); +} + +export function writeSdkArtifactIndex(artifactRoot) { + const entries = readdirSync(artifactRoot) + .sort() + .map((name) => path.join(artifactRoot, name)); + if (!entries.length) throw new Error('No SDK artifacts were staged'); + const index = path.join(artifactRoot, 'artifacts.txt'); + writeFileSync(index, [...entries, index].sort().map(rel).join('\n') + '\n'); +} + +if (import.meta.main) { + if (process.argv.length !== 3) throw new Error('usage: staging.mts '); + writeSdkArtifactIndex(path.resolve(process.argv[2])); +} diff --git a/tools/packaging/strict-json.mts b/tools/packaging/strict-json.mts new file mode 100644 index 000000000..3838a867a --- /dev/null +++ b/tools/packaging/strict-json.mts @@ -0,0 +1,22 @@ +// JSON.parse validates the grammar; this scan rejects keys it would overwrite. +export function parseStrictJson( + source: string, + reviver?: Parameters[1], +): unknown { + const value = JSON.parse(source, reviver); + const objects: Set[] = []; + for (const match of source.matchAll(/"(?:[^"\\]|\\.)*"|[{}]/gsu)) { + if (match[0] === '{') objects.push(new Set()); + else if (match[0] === '}') objects.pop(); + else { + let next = match.index + match[0].length; + while (next < source.length && ' \t\r\n'.includes(source[next])) next++; + if (source[next] !== ':') continue; + const key = JSON.parse(match[0]) as string; + const keys = objects.at(-1)!; + if (keys.has(key)) throw new Error(`duplicate JSON key ${JSON.stringify(key)}`); + keys.add(key); + } + } + return value; +} diff --git a/tools/packaging/strict-json.test.mts b/tools/packaging/strict-json.test.mts new file mode 100644 index 000000000..e5b65d022 --- /dev/null +++ b/tools/packaging/strict-json.test.mts @@ -0,0 +1,15 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { parseStrictJson } from './strict-json.mts'; +test('preserves JSON values and rejects duplicate keys, including escaped aliases', () => { + const value = { a: ['{"x":1}', { b: true }], c: null, d: '}', e: 'key:"value"' }; + assert.deepEqual(parseStrictJson(JSON.stringify(value, null, 2)), value); + for (const source of [ + '{"a":1,"\\u0061":2}', + '{"list":[{"a":1,"a":2}]}', + '{"a":1,}', + '{"a":1}\u00a0', + ]) { + assert.throws(() => parseStrictJson(source)); + } +}); diff --git a/tools/packaging/strip-native-binaries.sh b/tools/packaging/strip-native-binaries.sh new file mode 100755 index 000000000..8cdab9f63 --- /dev/null +++ b/tools/packaging/strip-native-binaries.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -euo pipefail +script_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +target= roots=() +while [ "$#" -gt 0 ]; do + case "$1" in + --target) [ "$#" -ge 2 ] && [ -n "$2" ] || { echo '--target requires a value' >&2; exit 2; }; target="$2"; shift ;; + --help|-h) echo 'usage: strip-native-binaries.sh [--target TARGET] PATH [PATH...]'; exit 0 ;; + -*) echo "unknown option: $1" >&2; exit 2 ;; + *) roots+=("$1") ;; + esac + shift +done +[ "${#roots[@]}" -gt 0 ] || { echo 'at least one input path is required' >&2; exit 2; } +for root in "${roots[@]}"; do [ -f "$root" ] || [ -d "$root" ] || { echo "input path does not exist: $root" >&2; exit 2; }; done +host="$(uname -s)" +vc_dlls="$(jq -r '.windowsVcRuntimeDlls[] | ascii_downcase' "$script_root/../../src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json")" +files="$(mktemp)" +trap 'rm -f "$files"' EXIT +find -H "${roots[@]}" -type f -print0 | LC_ALL=C sort -z >"$files" +checked=0 changed=0 +while IFS= read -r -d '' file; do + magic="$(od -An -tx1 -N8 "$file" | tr -d ' \n')" + case "$magic" in + 7f454c46*) kind=elf ;; + feedface*|cefaedfe*|feedfacf*|cffaedfe*|cafebabe*|bebafeca*) kind=macho ;; + 4d5a*) kind=pe ;; + 213c617263683e0a) kind=archive ;; + *) continue ;; + esac + checked=$((checked + 1)) + name="$(basename "$file" | tr '[:upper:]' '[:lower:]')" + if [ "$kind" = pe ] && grep -Fxq "$name" <<<"$vc_dlls"; then + printf 'preservedAppLocalVcRuntime=%s\n' "$file" >&2 + continue + fi + if [ "$kind" = archive ] && [[ "$name" = *.lib ]]; then + printf 'skippedMsvcImportLibrary=%s\n' "$file" >&2 + continue + fi + tool= flags=(--strip-unneeded) + if [[ "$target" = android-* ]] && { [ "$kind" = elf ] || [ "$kind" = archive ]; }; then + [ "$kind" != archive ] || flags=(--strip-debug) + tool="${OLIPHAUNT_ANDROID_STRIP:-${OLIPHAUNT_ELF_STRIP:-${OLIPHAUNT_STRIP:-}}}" + if [ -z "$tool" ]; then + ndk="${ANDROID_NDK_HOME:-${ANDROID_NDK_ROOT:-}}" + case "$host" in Linux) hosts=(linux-x86_64) ;; Darwin) hosts=(darwin-arm64 darwin-x86_64) ;; MINGW*|MSYS*) hosts=(windows-x86_64) ;; *) hosts=() ;; esac + for arch in "${hosts[@]}"; do + candidate="$ndk/toolchains/llvm/prebuilt/$arch/bin/llvm-strip" + [[ "$host" != MINGW* && "$host" != MSYS* ]] || candidate="$candidate.exe" + if [ -n "$ndk" ] && [ -x "$candidate" ]; then tool="$candidate"; break; fi + done + fi + elif [ "$kind" = macho ] || { [ "$kind" = archive ] && [ "$host" = Darwin ]; }; then + tool="${OLIPHAUNT_MACHO_STRIP:-${OLIPHAUNT_STRIP:-}}" + if [ -z "$tool" ] && [ "$host" = Darwin ]; then tool="$(xcrun --find strip 2>/dev/null || true)"; fi + [ -n "$tool" ] || tool="$(command -v strip || true)" + flags=(-S) + else + if [ "$kind" = pe ]; then tool="${OLIPHAUNT_PE_STRIP:-${OLIPHAUNT_STRIP:-}}"; else tool="${OLIPHAUNT_ELF_STRIP:-${OLIPHAUNT_STRIP:-}}"; fi + [ -n "$tool" ] || tool="$(command -v llvm-strip || command -v strip || true)" + if [ "$kind" = pe ] || [ "$kind" = archive ]; then flags=(--strip-debug); fi + if [ "$kind" = pe ] && [ -z "$tool" ]; then printf 'skippedPeNativeFile=%s\n' "$file" >&2; continue; fi + fi + [ -n "$tool" ] || { echo "missing $kind strip tool for $file (target $target)" >&2; exit 2; } + before="$(wc -c <"$file")" + "$tool" "${flags[@]}" "$file" + after="$(wc -c <"$file")" + [ "$before" = "$after" ] || changed=$((changed + 1)) +done <"$files" +printf 'strippedNativeFiles=%s\ncheckedNativeFiles=%s\n' "$changed" "$checked" diff --git a/tools/packaging/strip-native-binaries.test.sh b/tools/packaging/strip-native-binaries.test.sh new file mode 100755 index 000000000..40bbf4cca --- /dev/null +++ b/tools/packaging/strip-native-binaries.test.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail +[ "$(uname -s)" = Linux ] || { echo 'ELF strip execution requires Linux'; exit 0; } +script="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/strip-native-binaries.sh" +work="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-native-strip.XXXXXX")" +trap 'rm -rf "$work"' EXIT +cd "$work" +printf 'int answer(void) { return 42; }\n' >probe.c +printf 'extern int answer(void); int main(void) { return answer() != 42; }\n' >main.c +cc -g -fPIC -shared probe.c -o libprobe.so +cc -g main.c -L. -lprobe -Wl,-rpath,"$work" -o consumer +cc -g -c probe.c -o probe.o +ar cr libprobe.a probe.o +cp libprobe.a preserved.lib +cp preserved.lib before.lib +cp libprobe.so before.so +if bash "$script" libprobe.so missing-input >/dev/null 2>&1; then exit 1; fi +cmp before.so libprobe.so +rm before.so +before="$(wc -c symbols.before +bash "$script" --target linux-x64-gnu libprobe.so consumer libprobe.a preserved.lib +[ "$(wc -c symbols.after +cmp symbols.before symbols.after +cmp before.lib preserved.lib +./consumer +# Cross-compiled archives need the target's NDK tool, including on macOS hosts. +clang="$(command -v clang-22 || command -v clang || true)" +strip="$(command -v llvm-strip-22 || command -v llvm-strip || true)" +if [ -n "$clang" ] && [ -n "$strip" ]; then + "$clang" --target=aarch64-linux-gnu -g -c probe.c -o android.o + ar cr android.a android.o + mkdir -p ndk/toolchains/llvm/prebuilt/linux-x86_64/bin + ln -s "$strip" ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip + before="$(wc -c --version `); + } + args.set(key, value); + index += 1; + } + const assetDir = args.get('--asset-dir'); + const version = args.get('--version'); + if (!assetDir || !version || args.size !== 2) { + fail(`${description}\nusage: --asset-dir --version `); + } + return { assetDir: path.resolve(assetDir), version }; +} + +export async function writeEntriesArchive(output, entries, modes = {}) { + const stage = await fs.mkdtemp(path.join(os.tmpdir(), 'oliphaunt-release-fixture-')); + try { + for (const [name, data] of Object.entries(entries).sort(([left], [right]) => + left.localeCompare(right), + )) { + const file = path.join(stage, ...name.split('/')); + if (name.endsWith('/')) { + await fs.mkdir(file, { recursive: true }); + continue; + } + await fs.mkdir(path.dirname(file), { recursive: true }); + await fs.writeFile(file, data); + await fs.chmod(file, modes[name] ?? 0o644); + } + await archiveDirectory(stage, output); + } finally { + await fs.rm(stage, { recursive: true, force: true }); + } +} + +export async function writeChecksumManifest(assetDir, name) { + const checksumAsset = path.join(assetDir, name); + const dirents = await fs.readdir(assetDir, { withFileTypes: true }); + const files = dirents + .filter((entry) => entry.isFile() && entry.name !== name) + .map((entry) => entry.name) + .sort(); + const lines = []; + for (const file of files) { + const digest = createHash('sha256') + .update(await fs.readFile(path.join(assetDir, file))) + .digest('hex'); + lines.push(`${digest} ./${file}`); + } + await fs.writeFile(checksumAsset, `${lines.join('\n')}\n`, 'utf8'); +} + +function packedAppleVersion(major, minor = 0, patch = 0) { + return (major << 16) | (minor << 8) | patch; +} + +export function machoFixture({ + platform = 1, + minos = [11, 0, 0], + cpu = 0x0100000c, + cpuSubtype = 0, +} = {}) { + const commandSize = 24; + const buffer = Buffer.alloc(32 + commandSize); + buffer.writeUInt32LE(0xfeedfacf, 0); + buffer.writeUInt32LE(cpu, 4); + buffer.writeUInt32LE(cpuSubtype, 8); + buffer.writeUInt32LE(6, 12); + buffer.writeUInt32LE(1, 16); + buffer.writeUInt32LE(commandSize, 20); + buffer.writeUInt32LE(0, 24); + buffer.writeUInt32LE(0, 28); + buffer.writeUInt32LE(0x32, 32); + buffer.writeUInt32LE(commandSize, 36); + buffer.writeUInt32LE(platform, 40); + buffer.writeUInt32LE(packedAppleVersion(...minos), 44); + buffer.writeUInt32LE(packedAppleVersion(...minos), 48); + buffer.writeUInt32LE(0, 52); + return buffer; +} + +function align(value, alignment) { + return Math.ceil(value / alignment) * alignment; +} + +export function elfFixture({ + machine = 62, + requiredVersions = [], + androidApi = null, + type = 3, +} = {}) { + const versionBytes = Buffer.from(`\0${requiredVersions.join('\0')}\0`, 'ascii'); + const note = androidApi === null ? null : Buffer.alloc(24); + if (note !== null) { + note.writeUInt32LE(8, 0); + note.writeUInt32LE(4, 4); + note.writeUInt32LE(1, 8); + note.write('Android\0', 12, 'ascii'); + note.writeUInt32LE(androidApi, 20); + } + const noteOffset = align(64 + versionBytes.length, 4); + const sectionOffset = note === null ? 0 : align(noteOffset + note.length, 8); + const buffer = Buffer.alloc(note === null ? 64 + versionBytes.length : sectionOffset + 128); + Buffer.from([0x7f, 0x45, 0x4c, 0x46]).copy(buffer, 0); + buffer[4] = 2; + buffer[5] = 1; + buffer[6] = 1; + buffer.writeUInt16LE(type, 16); + buffer.writeUInt16LE(machine, 18); + buffer.writeUInt32LE(1, 20); + buffer.writeUInt16LE(64, 52); + versionBytes.copy(buffer, 64); + if (note !== null) { + note.copy(buffer, noteOffset); + buffer.writeBigUInt64LE(BigInt(sectionOffset), 40); + buffer.writeUInt16LE(64, 58); + buffer.writeUInt16LE(2, 60); + const noteSection = sectionOffset + 64; + buffer.writeUInt32LE(7, noteSection + 4); + buffer.writeBigUInt64LE(BigInt(noteOffset), noteSection + 24); + buffer.writeBigUInt64LE(BigInt(note.length), noteSection + 32); + buffer.writeBigUInt64LE(4n, noteSection + 48); + } + return buffer; +} + +export function windowsPeFixture({ machine = 0x8664, imports = [], delayImports = [] } = {}) { + const peOffset = 0x80; + const optionalSize = 240; + const sectionTable = peOffset + 24 + optionalSize; + const rawOffset = 0x200; + const rawSize = 0x400; + const virtualAddress = 0x1000; + const buffer = Buffer.alloc(rawOffset + rawSize); + buffer.write('MZ', 0, 'ascii'); + buffer.writeUInt32LE(peOffset, 0x3c); + buffer.write('PE\0\0', peOffset, 'ascii'); + const coff = peOffset + 4; + buffer.writeUInt16LE(machine, coff); + buffer.writeUInt16LE(1, coff + 2); + buffer.writeUInt16LE(optionalSize, coff + 16); + buffer.writeUInt16LE(0x2022, coff + 18); + const optional = coff + 20; + buffer.writeUInt16LE(0x20b, optional); + buffer.writeBigUInt64LE(0x140000000n, optional + 24); + buffer.writeUInt32LE(rawOffset, optional + 60); + buffer.writeUInt32LE(16, optional + 108); + const descriptorBytes = (imports.length + 1) * 20; + if (imports.length > 0) { + buffer.writeUInt32LE(virtualAddress, optional + 120); + buffer.writeUInt32LE(descriptorBytes, optional + 124); + } + if (delayImports.length > 0) { + const delayDescriptorOffset = rawOffset + 0x100; + buffer.writeUInt32LE(virtualAddress + delayDescriptorOffset - rawOffset, optional + 216); + buffer.writeUInt32LE((delayImports.length + 1) * 32, optional + 220); + } + buffer.write('.rdata\0\0', sectionTable, 'ascii'); + buffer.writeUInt32LE(rawSize, sectionTable + 8); + buffer.writeUInt32LE(virtualAddress, sectionTable + 12); + buffer.writeUInt32LE(rawSize, sectionTable + 16); + buffer.writeUInt32LE(rawOffset, sectionTable + 20); + let nameOffset = rawOffset + 0x200; + for (let index = 0; index < imports.length; index += 1) { + const descriptor = rawOffset + index * 20; + buffer.writeUInt32LE(virtualAddress + nameOffset - rawOffset, descriptor + 12); + buffer.write(`${imports[index]}\0`, nameOffset, 'ascii'); + nameOffset += Buffer.byteLength(imports[index]) + 1; + } + for (let index = 0; index < delayImports.length; index += 1) { + const descriptor = rawOffset + 0x100 + index * 32; + buffer.writeUInt32LE(1, descriptor); + buffer.writeUInt32LE(virtualAddress + nameOffset - rawOffset, descriptor + 4); + buffer.write(`${delayImports[index]}\0`, nameOffset, 'ascii'); + nameOffset += Buffer.byteLength(delayImports[index]) + 1; + } + return buffer; +} + +function coffArchiveMember(rawName, data) { + if (!Buffer.isBuffer(data)) { + throw new TypeError('COFF archive fixture member data must be a Buffer'); + } + if (!rawName || Buffer.byteLength(rawName, 'ascii') > 16) { + throw new Error(`invalid COFF archive fixture member name ${JSON.stringify(rawName)}`); + } + const header = Buffer.from( + `${rawName.padEnd(16, ' ')}${'0'.padEnd(12, ' ')}${'0'.padEnd(6, ' ')}${'0'.padEnd(6, ' ')}${'100644'.padEnd(8, ' ')}${String(data.length).padEnd(10, ' ')}\`\n`, + 'ascii', + ); + return Buffer.concat([ + header, + data, + ...(data.length % 2 === 0 ? [] : [Buffer.from('\n', 'ascii')]), + ]); +} + +function coffObjectFixture(machine, symbol) { + const symbolBytes = Buffer.from(`${symbol}\0`, 'ascii'); + const symbolTable = 20 + 40; + const stringTable = symbolTable + 18; + const buffer = Buffer.alloc(stringTable + 4 + symbolBytes.length); + buffer.writeUInt16LE(machine, 0); + buffer.writeUInt16LE(1, 2); + buffer.writeUInt32LE(symbolTable, 8); + buffer.writeUInt32LE(1, 12); + buffer.writeUInt16LE(0, 16); + buffer.write('.drectve', 20, 'ascii'); + buffer.writeUInt32LE(0, symbolTable); + buffer.writeUInt32LE(4, symbolTable + 4); + buffer.writeInt16LE(1, symbolTable + 12); + buffer.writeUInt8(2, symbolTable + 16); + buffer.writeUInt32LE(4 + symbolBytes.length, stringTable); + symbolBytes.copy(buffer, stringTable + 4); + return buffer; +} + +function coffImportObjectFixture({ dllName, machine, symbol }) { + const strings = Buffer.from(`${symbol}\0${dllName}\0`, 'ascii'); + const buffer = Buffer.alloc(20 + strings.length); + buffer.writeUInt16LE(0, 0); + buffer.writeUInt16LE(0xffff, 2); + buffer.writeUInt16LE(0, 4); + buffer.writeUInt16LE(machine, 6); + buffer.writeUInt32LE(strings.length, 12); + buffer.writeUInt16LE(1 << 2, 18); + strings.copy(buffer, 20); + return buffer; +} + +function nullTerminatedAscii(values) { + return Buffer.from(`${values.join('\0')}\0`, 'ascii'); +} + +export const OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS = Object.freeze([ + 'oliphaunt_backup', + 'oliphaunt_backup_with_error', + 'oliphaunt_cancel', + 'oliphaunt_close', + 'oliphaunt_close_if_generation', + 'oliphaunt_copy_last_error', + 'oliphaunt_detach', + 'oliphaunt_detach_with_error', + 'oliphaunt_exec_protocol', + 'oliphaunt_exec_protocol_raw_stream', + 'oliphaunt_exec_protocol_raw_stream_with_error', + 'oliphaunt_exec_protocol_with_error', + 'oliphaunt_exec_simple_query', + 'oliphaunt_exec_simple_query_with_error', + 'oliphaunt_free_response', + 'oliphaunt_init', + 'oliphaunt_init_with_error', + 'oliphaunt_logical_generation', + 'oliphaunt_register_static_extensions', + 'oliphaunt_restore', + 'oliphaunt_restore_with_error', + 'oliphaunt_version', +]); + +export function windowsImportLibraryFixture({ + dllName = 'oliphaunt.dll', + importMachine = 0x8664, + objectMachine = 0x8664, + symbol, + importSymbols = symbol === undefined ? OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS : [symbol], +} = {}) { + if (!Array.isArray(importSymbols) || importSymbols.length === 0) { + throw new Error('Windows import-library fixture requires at least one import symbol'); + } + const descriptorSymbol = '__IMPORT_DESCRIPTOR_oliphaunt'; + const symbols = [descriptorSymbol, ...importSymbols]; + const firstNames = nullTerminatedAscii(symbols); + const secondNames = nullTerminatedAscii(symbols); + const firstSize = 4 + symbols.length * 4 + firstNames.length; + const memberCount = 1 + importSymbols.length; + const secondSize = 4 + memberCount * 4 + 4 + symbols.length * 2 + secondNames.length; + const paddedMemberSize = (size) => 60 + size + (size % 2); + const firstOffset = 8; + const secondOffset = firstOffset + paddedMemberSize(firstSize); + const descriptorOffset = secondOffset + paddedMemberSize(secondSize); + const descriptor = coffObjectFixture(objectMachine, descriptorSymbol); + const memberOffsets = [descriptorOffset]; + let nextOffset = descriptorOffset + paddedMemberSize(descriptor.length); + const importObjects = importSymbols.map((importSymbol) => { + const object = coffImportObjectFixture({ + dllName, + machine: importMachine, + symbol: importSymbol, + }); + memberOffsets.push(nextOffset); + nextOffset += paddedMemberSize(object.length); + return object; + }); + + const first = Buffer.alloc(firstSize); + first.writeUInt32BE(symbols.length, 0); + for (let index = 0; index < memberOffsets.length; index += 1) { + first.writeUInt32BE(memberOffsets[index], 4 + index * 4); + } + firstNames.copy(first, 4 + memberOffsets.length * 4); + + const second = Buffer.alloc(secondSize); + second.writeUInt32LE(memberCount, 0); + for (let index = 0; index < memberOffsets.length; index += 1) { + second.writeUInt32LE(memberOffsets[index], 4 + index * 4); + } + const symbolCountOffset = 4 + memberCount * 4; + second.writeUInt32LE(symbols.length, symbolCountOffset); + for (let index = 0; index < symbols.length; index += 1) { + second.writeUInt16LE(index + 1, symbolCountOffset + 4 + index * 2); + } + secondNames.copy(second, symbolCountOffset + 4 + symbols.length * 2); + + return Buffer.concat([ + Buffer.from('!\n', 'ascii'), + coffArchiveMember('/', first), + coffArchiveMember('/', second), + coffArchiveMember('descr.obj/', descriptor), + ...importObjects.map((object, index) => coffArchiveMember(`import${index}.obj/`, object)), + ]); +} diff --git a/tools/packaging/testdata/tar-fixture.mts b/tools/packaging/testdata/tar-fixture.mts new file mode 100644 index 000000000..d2a0fa4a8 --- /dev/null +++ b/tools/packaging/testdata/tar-fixture.mts @@ -0,0 +1,64 @@ +import { mkdir, writeFile } from 'node:fs/promises'; +import { dirname } from 'node:path'; +import { canonicalGzipSync } from '../portable-archive.mts'; + +export function tarOctal(value, length) { + return Buffer.from(`${value.toString(8).padStart(length - 1, '0')}\0`, 'ascii'); +} + +export function tarArchive(rows) { + const records = []; + for (const row of rows) { + const header = Buffer.alloc(512); + let name = row.name, + prefix = ''; + if (Buffer.byteLength(name) > 100) { + const parts = name.split('/'); + for (let split = 1; split < parts.length; split++) { + const parent = parts.slice(0, split).join('/'), + leaf = parts.slice(split).join('/'); + if (Buffer.byteLength(parent) <= 155 && Buffer.byteLength(leaf) <= 100) { + prefix = parent; + name = leaf; + break; + } + } + if (!prefix || row.v7) throw new Error('fixture path does not fit ustar'); + } + Buffer.from(name).copy(header, 0); + Buffer.from(prefix).copy(header, 345); + tarOctal(row.mode ?? 0o644, 8).copy(header, 100); + tarOctal(0, 8).copy(header, 108); + tarOctal(0, 8).copy(header, 116); + const data = Buffer.from(row.data ?? ''); + tarOctal(row.size ?? data.length, 12).copy(header, 124); + tarOctal(0, 12).copy(header, 136); + header.fill(0x20, 148, 156); + header[156] = (row.type ?? '0').charCodeAt(0); + if (row.linkTarget) Buffer.from(row.linkTarget).copy(header, 157); + if (!row.v7) { + Buffer.from('ustar\0', 'binary').copy(header, 257); + Buffer.from('00').copy(header, 263); + } + const checksum = header.reduce((sum, byte) => sum + byte, 0); + Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `, 'ascii').copy(header, 148); + records.push(header, data, Buffer.alloc((512 - (data.length % 512)) % 512)); + } + return canonicalGzipSync(Buffer.concat([...records, Buffer.alloc(1024)])); +} + +export async function craftedTar(archive: string, entries: { name: string; type: string }[]) { + await mkdir(dirname(archive), { recursive: true }); + await writeFile( + archive, + tarArchive( + entries.map((row) => ({ + name: row.type === 'directory' && !row.name.endsWith('/') ? `${row.name}/` : row.name, + type: row.type === 'directory' ? '5' : row.type === 'symlink' ? '2' : '0', + mode: row.type === 'directory' ? 0o755 : 0o644, + linkTarget: row.type === 'symlink' ? 'target' : undefined, + data: ['directory', 'symlink'].includes(row.type) ? '' : 'fixture', + })), + ), + ); +} diff --git a/tools/packaging/testdata/zip-fixture.mts b/tools/packaging/testdata/zip-fixture.mts new file mode 100644 index 000000000..6a31299ea --- /dev/null +++ b/tools/packaging/testdata/zip-fixture.mts @@ -0,0 +1,152 @@ +import { mkdir, readdir, readFile, writeFile, stat } from 'node:fs/promises'; +import { dirname, join, posix } from 'node:path'; +import { deflateRawSync } from 'node:zlib'; + +let crcTable; +export function crc32(buffer) { + if (crcTable === undefined) { + crcTable = new Uint32Array(256); + for (let value = 0; value < 256; value += 1) { + let crc = value; + for (let bit = 0; bit < 8; bit += 1) { + crc = (crc & 1) !== 0 ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1; + } + crcTable[value] = crc >>> 0; + } + } + let crc = 0xffffffff; + for (const byte of buffer) crc = crcTable[(crc ^ byte) & 0xff] ^ (crc >>> 8); + return (crc ^ 0xffffffff) >>> 0; +} + +export function zipArchive(rows, { beforeCentral = Buffer.alloc(0) } = {}) { + const locals = []; + const centrals = []; + let localOffset = 0; + for (const row of rows) { + const name = Buffer.from(row.localName ?? row.name, 'utf8'); + const centralName = Buffer.from(row.name, 'utf8'); + const data = Buffer.from(row.data ?? 'payload'); + const method = row.method ?? 0; + const compressed = method === 8 ? deflateRawSync(data) : data; + const flags = (row.flags ?? 0) | (row.descriptor ? 0x0008 : 0); + const actualCrc = crc32(data); + const storedCrc = row.crc ?? actualCrc; + const localExtra = row.localExtra ?? Buffer.alloc(0); + const centralExtra = row.centralExtra ?? Buffer.alloc(0); + const local = Buffer.alloc(30); + local.writeUInt32LE(0x04034b50, 0); + local.writeUInt16LE(20, 4); + local.writeUInt16LE(flags, 6); + local.writeUInt16LE(method, 8); + local.writeUInt32LE(storedCrc, 14); + local.writeUInt32LE(compressed.length, 18); + local.writeUInt32LE(data.length, 22); + local.writeUInt16LE(name.length, 26); + local.writeUInt16LE(localExtra.length, 28); + let descriptor = Buffer.alloc(0); + if (row.descriptor) { + descriptor = Buffer.alloc(row.descriptor === 'signed' ? 16 : 12); + let descriptorOffset = 0; + if (row.descriptor === 'signed') { + descriptor.writeUInt32LE(0x08074b50, 0); + descriptorOffset = 4; + } + descriptor.writeUInt32LE(row.descriptorCrc ?? storedCrc, descriptorOffset); + descriptor.writeUInt32LE(compressed.length, descriptorOffset + 4); + descriptor.writeUInt32LE(data.length, descriptorOffset + 8); + } + const localRecord = Buffer.concat([ + local, + name, + localExtra, + compressed, + descriptor, + row.afterData ?? Buffer.alloc(0), + ]); + locals.push(localRecord); + + const central = Buffer.alloc(46); + central.writeUInt32LE(0x02014b50, 0); + central.writeUInt16LE(row.versionMadeBy ?? 0x0314, 4); + central.writeUInt16LE(20, 6); + central.writeUInt16LE(flags, 8); + central.writeUInt16LE(method, 10); + central.writeUInt32LE(storedCrc, 16); + central.writeUInt32LE(compressed.length, 20); + central.writeUInt32LE(row.declaredSize ?? data.length, 24); + central.writeUInt16LE(centralName.length, 28); + central.writeUInt16LE(centralExtra.length, 30); + central.writeUInt32LE((row.externalAttributes ?? 0o100644 << 16) >>> 0, 38); + central.writeUInt32LE(localOffset, 42); + centrals.push(Buffer.concat([central, centralName, centralExtra])); + localOffset += localRecord.length; + } + const centralDirectory = Buffer.concat(centrals); + const eocd = Buffer.alloc(22); + eocd.writeUInt32LE(0x06054b50, 0); + eocd.writeUInt16LE(rows.length, 8); + eocd.writeUInt16LE(rows.length, 10); + eocd.writeUInt32LE(centralDirectory.length, 12); + eocd.writeUInt32LE(localOffset + beforeCentral.length, 16); + return Buffer.concat([...locals, beforeCentral, centralDirectory, eocd]); +} + +export async function maliciousZip(archive: string, name: string, kind: string) { + await mkdir(dirname(archive), { recursive: true }); + await writeFile( + archive, + zipArchive([ + { + name, + data: kind === 'symlink' ? '../outside' : 'malicious', + externalAttributes: (kind === 'symlink' ? 0o120777 : 0o100644) << 16, + }, + ]), + ); +} +export async function fixtureFiles(root: string) { + if (!root) return []; + const rows: { name: string; data: Buffer }[] = []; + for (const name of (await readdir(root, { recursive: true })).sort()) { + const path = join(root, name); + if ((await stat(path)).isFile()) + rows.push({ name: name.replaceAll('\\', '/'), data: await readFile(path) }); + } + return rows; +} +export async function metadataZip(archive: string, creator: string, legalRoot = '') { + await mkdir(dirname(archive), { recursive: true }); + const unix = creator !== 'fat', + ambiguous = creator === 'ambiguous-unix'; + const directory = (name: string, ambiguous = false) => ({ + name, + data: '', + versionMadeBy: unix ? 0x0314 : 0x0014, + externalAttributes: unix ? ((ambiguous ? 0o755 : 0o40755) << 16) | 0x10 : 0x10, + }); + const file = (name: string, data: string | Buffer, ambiguous = false) => ({ + name, + data, + versionMadeBy: unix ? 0x0314 : 0x0014, + externalAttributes: unix ? ((ambiguous ? 0o644 : 0o100644) << 16) | 0x20 : 0x20, + }); + const extra = + creator === 'unicode-extra' ? Buffer.from('757005000100000000', 'hex') : Buffer.alloc(0); + const rows = [ + directory('liboliphaunt.xcframework/', ambiguous), + { + ...file('liboliphaunt.xcframework/Info.plist', '\n', ambiguous), + localExtra: extra, + centralExtra: extra, + }, + ]; + const legal = (await fixtureFiles(legalRoot)).filter((row) => row.name !== 'Info.plist'); + const parents = new Set(); + for (const { name } of legal) + for (let parent = posix.dirname(name); parent !== '.'; parent = posix.dirname(parent)) + parents.add(parent); + rows.push(...[...parents].sort().map((name) => directory(`liboliphaunt.xcframework/${name}/`))); + rows.push(...legal.map(({ name, data }) => file(`liboliphaunt.xcframework/${name}`, data))); + await writeFile(archive, zipArchive(rows)); +} diff --git a/tools/packaging/wasix-cargo-payload.mts b/tools/packaging/wasix-cargo-payload.mts new file mode 100644 index 000000000..ebe760ff1 --- /dev/null +++ b/tools/packaging/wasix-cargo-payload.mts @@ -0,0 +1,141 @@ +import { createHash } from 'node:crypto'; +import { copyFileSync, cpSync, existsSync, readFileSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { packageGeneratedCargoSource } from './cargo-source-package.mts'; +import { + assertReleaseNoticesInArchive, + assertReleaseNoticesInDirectory, + releaseNoticeRows, + releaseProfilePackageLicense, + stageReleaseNotices, +} from './release-notices.mts'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); +const CRATES_IO_MAX_BYTES = 10 * 1024 * 1024; +function fail(message) { + throw new Error(message); +} +function rel(file) { + return path.relative(ROOT, file).split(path.sep).join('/'); +} +function sha256File(file) { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} +function noticeProfileForSpec(spec) { + if (spec.kind === 'icu-data') return 'wasix-icu-data-crate'; + if (spec.kind === 'wasix-runtime') return 'wasix-runtime'; + if (spec.kind === 'wasix-tools') return 'wasix-tools'; + if (spec.kind === 'wasix-aot' || spec.kind === 'wasix-tools-aot') return 'wasix-aot'; + fail(`WASIX Cargo package ${spec.name} has no release notice profile for kind ${spec.kind}`); +} + +function injectCargoNoticeIncludes(text, profile) { + const members = releaseNoticeRows({ profile }).map((row) => row.member); + const match = + text.match(/^include = \[(?[\s\S]*?)^\]$/mu) ?? + text.match(/^include = \[(?[^\n]*?)\]$/mu); + if (!match?.groups) fail('Cargo package template must declare one include array'); + const existing = [...match.groups.body.matchAll(/"([^"]+)"/gu)].map((item) => item[1]); + const values = [...new Set([...existing, ...members])]; + const replacement = `include = [\n${values.map((value) => ` ${JSON.stringify(value)},`).join('\n')}\n]`; + return text.slice(0, match.index) + replacement + text.slice(match.index + match[0].length); +} + +function rewriteCargoManifest( + manifest, + { packageName, version, transformManifest, noticeProfile }, +) { + let text = readFileSync(manifest, 'utf8'); + text = text.replace(/^name = "[^"]+"$/mu, `name = "${packageName}"`); + text = text.replace(/^version = "[^"]+"$/mu, `version = "${version}"`); + text = text.replace(/^publish = false\n?/gmu, ''); + text = text.replace( + /^license = "[^"]+"$/mu, + `license = ${JSON.stringify(releaseProfilePackageLicense(noticeProfile).spdx)}`, + ); + text = injectCargoNoticeIncludes(text, noticeProfile); + if (transformManifest) text = transformManifest(text); + if (!text.includes('\n[workspace]')) { + text = `${text.trimEnd()}\n\n[workspace]\n`; + } + writeFileSync(manifest, text); + const packageData = Bun.TOML.parse(readFileSync(manifest, 'utf8')).package; + if (packageData.name !== packageName || packageData.version !== version) { + fail( + `${rel(manifest)} generated the wrong package metadata: name=${JSON.stringify(packageData.name)}, version=${JSON.stringify(packageData.version)}`, + ); + } +} + +function copyPackageSource(spec, sourceRoot, version, transformManifest) { + const crateDir = path.join(sourceRoot, spec.name); + if (existsSync(crateDir)) { + fail(`duplicate generated WASIX Cargo package source: ${rel(crateDir)}`); + } + cpSync(spec.templateDir, crateDir, { + recursive: true, + filter: (source) => !['target', 'payload', 'artifacts'].includes(path.basename(source)), + }); + cpSync(spec.payloadRoot, path.join(crateDir, spec.payloadDirName), { recursive: true }); + if (existsSync(path.join(crateDir, 'build-support.rs'))) { + writeFileSync( + path.join(crateDir, 'build.rs'), + 'const PACKAGE_LOCAL: bool = true;\ninclude!("build-support.rs");\n', + ); + } + const noticeProfile = noticeProfileForSpec(spec); + stageReleaseNotices(crateDir, { profile: noticeProfile }); + rewriteCargoManifest(path.join(crateDir, 'Cargo.toml'), { + packageName: spec.name, + version, + transformManifest, + noticeProfile, + }); + assertReleaseNoticesInDirectory(crateDir, { profile: noticeProfile }); + return crateDir; +} + +export function cargoPackage(crateDir, targetDir) { + const manifest = path.join(crateDir, 'Cargo.toml'); + const { name } = Bun.TOML.parse(readFileSync(manifest, 'utf8')).package; + return packageGeneratedCargoSource(manifest, path.join(targetDir, 'strict-package', name), { + root: ROOT, + fail, + rel, + }); +} + +export function validateCrateSize(cratePath) { + const size = statSync(cratePath).size; + if (size > CRATES_IO_MAX_BYTES) { + fail( + `${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit; reduce the WASIX Cargo payload before publishing`, + ); + } +} + +export function packageSpec( + spec, + { version, sourceRoot, outputDir, cargoTargetDir, transformManifest }, +) { + const crateDir = copyPackageSource(spec, sourceRoot, version, transformManifest); + const cratePath = cargoPackage(crateDir, cargoTargetDir); + validateCrateSize(cratePath); + const output = path.join(outputDir, path.basename(cratePath)); + copyFileSync(cratePath, output); + const noticeProfile = noticeProfileForSpec(spec); + assertReleaseNoticesInArchive(output, { + prefix: `${spec.name}-${version}`, + profile: noticeProfile, + }); + return { + name: spec.name, + manifestPath: path.join(crateDir, 'Cargo.toml'), + cratePath: output, + target: spec.target, + kind: spec.kind, + size: statSync(output).size, + sha256: sha256File(output), + }; +} diff --git a/tools/packaging/wasix-cargo-payload.test.mts b/tools/packaging/wasix-cargo-payload.test.mts new file mode 100644 index 000000000..74fb4652f --- /dev/null +++ b/tools/packaging/wasix-cargo-payload.test.mts @@ -0,0 +1,149 @@ +import { cpSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + filesystemTreeRows, + logicalTreeSha256, +} from '../../src/database-resources/contracts/native-manifest.mts'; +import { createDeterministicTar } from './cargo-source-package.mts'; +import { extractPortableArchiveTree, releaseZstdCompressSync } from './portable-archive.mts'; +import { packageSpec } from './wasix-cargo-payload.mts'; + +const root = path.resolve(import.meta.dir, '../..'); +const scratch = process.argv[2]; +if (!scratch) throw new Error('Run the paired Shell test'); +const triple = 'x86_64-unknown-linux-gnu'; +const cases = [ + [ + 'icu', + 'src/database-resources/icu/cargo', + 'icu-data', + 'payload', + 'icu-data', + 'OLIPHAUNT_ICU_DATA_DIR', + 'ICU_DATA_TREE_SHA256.unwrap().as_bytes()', + ], + [ + 'runtime', + 'src/runtimes/liboliphaunt-wasix/crates/assets', + 'wasix-runtime', + 'payload', + 'target/oliphaunt-wasix/assets', + 'OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR', + 'runtime_archive().unwrap()', + ], + [ + 'tools', + 'src/postgres-tools/wasix/crates/tools', + 'wasix-tools', + 'payload', + 'target/postgres-tools/wasix/assets', + 'OLIPHAUNT_WASIX_TOOLS_ASSETS_DIR', + 'pg_dump_wasm().unwrap()', + ], + [ + 'runtime-aot', + `src/runtimes/liboliphaunt-wasix/crates/aot/${triple}`, + 'wasix-aot', + 'artifacts', + `target/oliphaunt-wasix/aot/${triple}`, + 'OLIPHAUNT_WASM_GENERATED_AOT_DIR', + 'artifact_bytes("runtime:oliphaunt").unwrap()', + ], + [ + 'tools-aot', + `src/postgres-tools/wasix/crates/aot/${triple}`, + 'wasix-tools-aot', + 'artifacts', + `target/postgres-tools/wasix/aot/${triple}`, + 'OLIPHAUNT_WASIX_TOOLS_AOT_DIR', + 'artifact_bytes("tool:pg_dump").unwrap()', + ], +]; +const rows: string[] = []; +for (const [id, template, kind, payloadDirName, ancestorAssets, variable, expression] of cases) { + const base = path.join(scratch, id); + const external = path.join(base, ancestorAssets); + let payloadRoot = external; + let expected = 'selected-payload'; + if (id === 'icu') { + mkdirSync(payloadRoot, { recursive: true }); + writeFileSync(path.join(payloadRoot, 'icudt76l.dat'), expected); + expected = logicalTreeSha256(filesystemTreeRows(payloadRoot)); + const archive = releaseZstdCompressSync( + createDeterministicTar(payloadRoot, 'share/icu', { fixedFileMode: 0o644 }), + ); + payloadRoot = path.join(base, 'icu-payload'); + mkdirSync(payloadRoot); + writeFileSync(path.join(payloadRoot, 'icu-data.tar.zst'), archive); + } else { + mkdirSync(path.join(payloadRoot, 'bin'), { recursive: true }); + for (const file of [ + 'oliphaunt.wasix.tar.zst', + 'bin/initdb.wasix.wasm', + 'bin/pg_dump.wasix.wasm', + 'bin/psql.wasix.wasm', + 'oliphaunt-llvm-opta.bin.zst', + 'pg_dump-llvm-opta.bin.zst', + ]) { + writeFileSync(path.join(payloadRoot, file), 'selected-payload'); + } + const aot = kind.endsWith('aot'); + writeFileSync( + path.join(payloadRoot, 'manifest.json'), + JSON.stringify( + aot + ? { + artifacts: [ + { + name: id === 'tools-aot' ? 'tool:pg_dump' : 'runtime:oliphaunt', + path: + id === 'tools-aot' + ? 'pg_dump-llvm-opta.bin.zst' + : 'oliphaunt-llvm-opta.bin.zst', + }, + ], + } + : { extensions: [] }, + ), + ); + } + mkdirSync(path.join(base, '.git')); + for (const marker of [ + 'Cargo.toml', + 'src/sdks/rust-wasix/Cargo.toml', + 'src/runtimes/liboliphaunt-wasix/crates/assets/Cargo.toml', + ]) { + mkdirSync(path.dirname(path.join(base, marker)), { recursive: true }); + writeFileSync(path.join(base, marker), ''); + } + const manifest = Bun.TOML.parse(readFileSync(path.join(root, template, 'Cargo.toml'), 'utf8')); + const outputDir = path.join(base, 'packages'); + mkdirSync(outputDir); + const packed = packageSpec( + { + name: manifest.package.name, + templateDir: path.join(root, template), + kind, + target: kind.endsWith('aot') ? triple : 'portable', + payloadRoot, + payloadDirName, + }, + { + version: manifest.package.version, + sourceRoot: path.join(base, 'sources'), + outputDir, + cargoTargetDir: path.join(base, 'pack-target'), + }, + ); + const unpacked = path.join(base, 'extracted'); + extractPortableArchiveTree(packed.cratePath, unpacked); + const crate = path.join(unpacked, `${manifest.package.name}-${manifest.package.version}`); + mkdirSync(path.join(crate, 'examples')); + writeFileSync( + path.join(crate, 'examples/probe.rs'), + `fn main() { assert_eq!(${manifest.package.name.replaceAll('-', '_')}::${expression}, b${JSON.stringify(expected)}); }\n`, + ); + cpSync(path.join(root, 'Cargo.lock'), path.join(crate, 'Cargo.lock')); + rows.push([crate, payloadDirName, variable, external].join('\t')); +} +writeFileSync(path.join(scratch, 'cases.tsv'), `${rows.join('\n')}\n`); diff --git a/tools/packaging/wasix-cargo-payload.test.sh b/tools/packaging/wasix-cargo-payload.test.sh new file mode 100644 index 000000000..2240cff37 --- /dev/null +++ b/tools/packaging/wasix-cargo-payload.test.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +bun tools/packaging/wasix-cargo-payload.test.mts "$scratch" +while IFS=$'\t' read -r crate payload variable external; do + # Provision this fixture's locked dependencies before the offline assertions; + # a source-only CI job need not have compiled a Rust SDK beforehand. + # Cargo trims the copied workspace lock to this standalone package closure. + cargo fetch --manifest-path "$crate/Cargo.toml" + # A real extracted carrier embeds its own bytes. + CARGO_TARGET_DIR="$scratch/cargo-target" cargo run --locked --offline --quiet \ + --manifest-path "$crate/Cargo.toml" --example probe + if [[ "$payload" == artifacts ]]; then + mkdir "$crate/removed-aot" + mv "$crate/$payload/"*.zst "$crate/removed-aot/" + if CARGO_TARGET_DIR="$scratch/cargo-target" cargo check --locked --offline --quiet \ + --manifest-path "$crate/Cargo.toml" --lib > "$scratch/missing-aot.log" 2>&1; then + echo "Published carrier accepted missing declared AOT files: $crate" >&2 + exit 1 + fi + rg -q 'missing declared WASIX AOT artifact' "$scratch/missing-aot.log" + mv "$crate/removed-aot/"*.zst "$crate/$payload/" + fi + mv "$crate/$payload" "$crate/removed-payload" + # Neither a populated ancestor checkout nor an explicit override may repair + # an incomplete published package, even without the maintainer strict flag. + if env "$variable=$external" CARGO_TARGET_DIR="$scratch/cargo-target" \ + cargo run --locked --offline --quiet --manifest-path "$crate/Cargo.toml" \ + --example probe > "$scratch/missing.log" 2>&1; then + echo "Published carrier accepted missing payload: $crate" >&2 + exit 1 + fi + rg -q 'published (WASIX|ICU) carrier requires package-local' "$scratch/missing.log" + # The checkout entrypoint deliberately supports the same external inputs. + printf 'const PACKAGE_LOCAL: bool = false;\ninclude!("build-support.rs");\n' > "$crate/build.rs" + env "$variable=$external" CARGO_TARGET_DIR="$scratch/cargo-target" \ + cargo run --locked --offline --quiet --manifest-path "$crate/Cargo.toml" --example probe + mv "$external" "$external.saved" + CARGO_TARGET_DIR="$scratch/cargo-target" cargo check --locked --offline --quiet \ + --manifest-path "$crate/Cargo.toml" --lib +done < "$scratch/cases.tsv" +printf 'WASIX extracted Cargo carrier payload isolation passed\n' diff --git a/tools/packaging/windows-vc-runtime-closure.mts b/tools/packaging/windows-vc-runtime-closure.mts new file mode 100644 index 000000000..1d11df38e --- /dev/null +++ b/tools/packaging/windows-vc-runtime-closure.mts @@ -0,0 +1,693 @@ +#!/usr/bin/env bun +import { createHash, randomUUID } from 'node:crypto'; +import { + closeSync, + constants, + copyFileSync, + existsSync, + fsyncSync, + lstatSync, + mkdirSync, + openSync, + readFileSync, + readdirSync, + renameSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const TOOL = 'windows-vc-runtime-closure.mts'; +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); +const POLICY = JSON.parse( + readFileSync( + path.join(ROOT, 'src/runtimes/liboliphaunt-native/tools/native-runtime-payload-policy.json'), + 'utf8', + ), +); +const PE_MACHINE_AMD64 = 0x8664; +const PE_MAGIC_32 = 0x10b; +const PE_MAGIC_64 = 0x20b; +// Treat every Microsoft C/C++ runtime family as policy-controlled. This makes +// debug/non-redistributable or future runtime imports fail closed instead of +// silently relying on whatever happens to be installed on a build host. +const VC_RUNTIME_IMPORT = + /^(?:atl|concrt|mfc|mfcm|msvcp|ucrtbase|vcamp|vcomp|vcruntime)[a-z0-9_]*\.dll$/iu; +const CRT_DIRECTORY = 'Microsoft.VC145.CRT'; + +export const WINDOWS_VC_RUNTIME_DLLS = Object.freeze( + [...POLICY.windowsVcRuntimeDlls].map((name) => String(name).toLowerCase()).sort(), +); +export const WINDOWS_VC_RUNTIME_PROFILES = Object.freeze( + Object.fromEntries( + Object.entries(POLICY.windowsVcRuntimeProfiles ?? {}).map(([profile, names]) => [ + profile, + Object.freeze([...names].map((name) => String(name).toLowerCase()).sort()), + ]), + ), +); +export const WINDOWS_VC_RUNTIME_RECEIPT = String(POLICY.windowsVcRuntimeReceipt); + +function failure(message) { + return new Error(`${TOOL}: ${message}`); +} + +function fail(message) { + console.error(`${TOOL}: ${message}`); + process.exit(1); +} + +function requireRange(buffer, offset, length, label) { + if ( + !Number.isSafeInteger(offset) || + !Number.isSafeInteger(length) || + offset < 0 || + length < 0 || + offset + length > buffer.length + ) { + throw failure(`${label} is truncated at byte ${offset}`); + } +} + +function readAsciiZ(buffer, offset, label) { + requireRange(buffer, offset, 1, label); + const limit = Math.min(buffer.length, offset + 4096); + let end = offset; + while (end < limit && buffer[end] !== 0) { + const byte = buffer[end]; + if (byte < 0x20 || byte > 0x7e) { + throw failure(`${label} contains a non-ASCII import name`); + } + end += 1; + } + if (end === limit || buffer[end] !== 0) { + throw failure(`${label} has an unterminated import name`); + } + const value = buffer.subarray(offset, end).toString('ascii'); + if (!value || value.includes('/') || value.includes('\\')) { + throw failure(`${label} has an invalid import basename ${JSON.stringify(value)}`); + } + return value; +} + +function parsePortableExecutable(input, label = 'portable executable') { + const buffer = Buffer.isBuffer(input) ? input : Buffer.from(input); + requireRange(buffer, 0, 0x40, label); + if (buffer.subarray(0, 2).toString('ascii') !== 'MZ') { + throw failure(`${label} is not a PE image`); + } + const peOffset = buffer.readUInt32LE(0x3c); + requireRange(buffer, peOffset, 24, label); + if (!buffer.subarray(peOffset, peOffset + 4).equals(Buffer.from('PE\0\0', 'binary'))) { + throw failure(`${label} has no PE signature`); + } + const coff = peOffset + 4; + const machine = buffer.readUInt16LE(coff); + const sectionCount = buffer.readUInt16LE(coff + 2); + const optionalSize = buffer.readUInt16LE(coff + 16); + const optional = coff + 20; + requireRange(buffer, optional, optionalSize, label); + const magic = buffer.readUInt16LE(optional); + if (magic !== PE_MAGIC_32 && magic !== PE_MAGIC_64) { + throw failure(`${label} has unsupported PE optional-header magic 0x${magic.toString(16)}`); + } + const imageBase = + magic === PE_MAGIC_64 + ? Number(buffer.readBigUInt64LE(optional + 24)) + : buffer.readUInt32LE(optional + 28); + if (!Number.isSafeInteger(imageBase)) { + throw failure(`${label} has an unsupported image base`); + } + const dataDirectoryOffset = optional + (magic === PE_MAGIC_64 ? 112 : 96); + const directoryCountOffset = optional + (magic === PE_MAGIC_64 ? 108 : 92); + requireRange(buffer, directoryCountOffset, 4, label); + const directoryCount = buffer.readUInt32LE(directoryCountOffset); + + const sections = []; + let sectionOffset = optional + optionalSize; + for (let index = 0; index < sectionCount; index += 1) { + requireRange(buffer, sectionOffset, 40, label); + sections.push({ + virtualSize: buffer.readUInt32LE(sectionOffset + 8), + virtualAddress: buffer.readUInt32LE(sectionOffset + 12), + rawSize: buffer.readUInt32LE(sectionOffset + 16), + rawOffset: buffer.readUInt32LE(sectionOffset + 20), + }); + sectionOffset += 40; + } + + const rvaOffset = (rva, field) => { + for (const section of sections) { + const span = Math.max(section.virtualSize, section.rawSize); + if (rva >= section.virtualAddress && rva < section.virtualAddress + span) { + const delta = rva - section.virtualAddress; + if (delta >= section.rawSize) { + throw failure(`${label} ${field} points outside section file data`); + } + const offset = section.rawOffset + delta; + requireRange(buffer, offset, 1, label); + return offset; + } + } + throw failure(`${label} ${field} RVA 0x${rva.toString(16)} is not mapped by a section`); + }; + + const directory = (index) => { + if ( + directoryCount <= index || + dataDirectoryOffset + (index + 1) * 8 > optional + optionalSize + ) { + return { rva: 0, size: 0 }; + } + return { + rva: buffer.readUInt32LE(dataDirectoryOffset + index * 8), + size: buffer.readUInt32LE(dataDirectoryOffset + index * 8 + 4), + }; + }; + + const imports = new Set(); + const normal = directory(1); + if (normal.rva !== 0) { + let descriptor = rvaOffset(normal.rva, 'import directory'); + const end = normal.size > 0 ? Math.min(buffer.length, descriptor + normal.size) : buffer.length; + let terminated = false; + for (let count = 0; descriptor + 20 <= end && count < 4096; count += 1) { + requireRange(buffer, descriptor, 20, label); + const empty = buffer.subarray(descriptor, descriptor + 20).every((byte) => byte === 0); + if (empty) { + terminated = true; + break; + } + const nameRva = buffer.readUInt32LE(descriptor + 12); + if (nameRva === 0) { + throw failure(`${label} has an import descriptor without a DLL name`); + } + imports.add(readAsciiZ(buffer, rvaOffset(nameRva, 'import name'), label)); + descriptor += 20; + } + if (!terminated) { + throw failure(`${label} has an unterminated import descriptor table`); + } + } + + const delayed = directory(13); + if (delayed.rva !== 0) { + let descriptor = rvaOffset(delayed.rva, 'delay import directory'); + const end = + delayed.size > 0 ? Math.min(buffer.length, descriptor + delayed.size) : buffer.length; + let terminated = false; + for (let count = 0; descriptor + 32 <= end && count < 4096; count += 1) { + requireRange(buffer, descriptor, 32, label); + const empty = buffer.subarray(descriptor, descriptor + 32).every((byte) => byte === 0); + if (empty) { + terminated = true; + break; + } + const attributes = buffer.readUInt32LE(descriptor); + const rawName = buffer.readUInt32LE(descriptor + 4); + const nameRva = (attributes & 1) !== 0 ? rawName : rawName - imageBase; + if (!Number.isSafeInteger(nameRva) || nameRva <= 0) { + throw failure(`${label} has an invalid delay-import DLL name`); + } + imports.add(readAsciiZ(buffer, rvaOffset(nameRva, 'delay import name'), label)); + descriptor += 32; + } + if (!terminated) { + throw failure(`${label} has an unterminated delay-import descriptor table`); + } + } + + return { + machine, + magic, + imports: [...imports].sort(), + }; +} + +export function inspectPortableExecutable(input, label) { + const buffer = Buffer.isBuffer(input) ? input : readFileSync(input); + return parsePortableExecutable(buffer, label ?? String(input)); +} + +export function windowsVcRuntimeImports(input, label) { + return inspectPortableExecutable(input, label).imports.filter((name) => + VC_RUNTIME_IMPORT.test(name), + ); +} + +function isRegularFile(file) { + try { + const stat = lstatSync(file); + return stat.isFile() && !stat.isSymbolicLink(); + } catch { + return false; + } +} + +function requireDirectory(directory, label) { + let stat; + try { + stat = lstatSync(directory); + } catch (error) { + throw failure(`${label} does not exist at ${directory}: ${error.message}`); + } + if (!stat.isDirectory() || stat.isSymbolicLink()) { + throw failure(`${label} must be a real directory: ${directory}`); + } +} + +function entriesByLowercase(directory) { + const result = new Map(); + for (const name of readdirSync(directory)) { + const key = name.toLowerCase(); + if (result.has(key)) { + throw failure(`${directory} has case-colliding entries ${result.get(key)} and ${name}`); + } + result.set(key, name); + } + return result; +} + +export function resolveInitializedVcRuntimeDirectory(redistRoot = process.env.VCToolsRedistDir) { + if (typeof redistRoot !== 'string' || !redistRoot.trim()) { + throw failure( + 'VCToolsRedistDir is not set; initialize the exact x64 MSVC developer environment first', + ); + } + const root = path.resolve(redistRoot); + requireDirectory(root, 'VCToolsRedistDir'); + const x64 = path.join(root, 'x64'); + requireDirectory(x64, 'x64 VC redistributable directory'); + const candidates = readdirSync(x64, { withFileTypes: true }) + .filter( + (entry) => entry.isDirectory() && !entry.isSymbolicLink() && entry.name === CRT_DIRECTORY, + ) + .map((entry) => path.join(x64, entry.name)) + .filter((directory) => { + const names = entriesByLowercase(directory); + return WINDOWS_VC_RUNTIME_DLLS.every((name) => names.has(name)); + }); + if (candidates.length !== 1) { + throw failure( + `${x64} must contain exactly one initialized ${CRT_DIRECTORY} directory with ${WINDOWS_VC_RUNTIME_DLLS.join(', ')}; found ${candidates.length}`, + ); + } + return candidates[0]; +} + +function requiredSource(sourceDirectory, expected) { + requireDirectory(sourceDirectory, 'VC runtime source directory'); + const names = entriesByLowercase(sourceDirectory); + const actual = names.get(expected); + if (!actual) { + throw failure(`${sourceDirectory} is missing import-derived ${expected}`); + } + const source = path.join(sourceDirectory, actual); + if (!isRegularFile(source) || path.basename(source).toLowerCase() !== expected) { + throw failure(`${source} must be a regular file with exact basename ${expected}`); + } + const pe = inspectPortableExecutable(source); + if (pe.machine !== PE_MACHINE_AMD64 || pe.magic !== PE_MAGIC_64) { + throw failure( + `${source} is not an x64 PE32+ image (machine 0x${pe.machine.toString(16)}, magic 0x${pe.magic.toString(16)})`, + ); + } + return { expected, source, pe }; +} + +function sha256(file) { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} + +function copyAtomic(source, destination) { + mkdirSync(path.dirname(destination), { recursive: true }); + const sourceDigest = sha256(source); + if (existsSync(destination)) { + if (!isRegularFile(destination)) { + throw failure(`${destination} already exists and is not a regular file`); + } + if (sha256(destination) === sourceDigest) return; + } + const temporary = path.join( + path.dirname(destination), + `.${path.basename(destination)}.partial.${process.pid}.${randomUUID()}`, + ); + let descriptor; + try { + copyFileSync(source, temporary, constants.COPYFILE_EXCL); + // FlushFileBuffers requires a handle opened with write access on Windows. + // Bun forwards fsyncSync to that API, so reopening the copied file read-only + // makes an otherwise valid atomic stage fail with EPERM on Windows runners. + descriptor = openSync(temporary, 'r+'); + fsyncSync(descriptor); + closeSync(descriptor); + descriptor = undefined; + if (sha256(temporary) !== sourceDigest) { + throw failure(`atomic copy of ${source} changed bytes before promotion`); + } + // libuv maps rename-over-file to an atomic replace on Windows. If the + // replace is denied (for example, a locked DLL), the old durable file is + // retained and the unique partial is removed in finally. + renameSync(temporary, destination); + } finally { + if (descriptor !== undefined) closeSync(descriptor); + rmSync(temporary, { force: true }); + } +} + +function writeAtomic(destination, content) { + mkdirSync(path.dirname(destination), { recursive: true }); + const temporary = path.join( + path.dirname(destination), + `.${path.basename(destination)}.partial.${process.pid}.${randomUUID()}`, + ); + let descriptor; + try { + descriptor = openSync( + temporary, + constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, + 0o644, + ); + writeFileSync(descriptor, content, 'utf8'); + fsyncSync(descriptor); + closeSync(descriptor); + descriptor = undefined; + renameSync(temporary, destination); + } finally { + if (descriptor !== undefined) closeSync(descriptor); + rmSync(temporary, { force: true }); + } +} + +function checkedRuntimeImport(name, importer) { + const normalized = name.toLowerCase(); + if (!WINDOWS_VC_RUNTIME_DLLS.includes(normalized)) { + throw failure( + `${importer} imports undeclared or debug VC runtime ${name}; update the audited production closure from actual binary evidence`, + ); + } + return normalized; +} + +export function windowsVcRuntimeProfileNames(profile) { + if (profile === undefined || profile === null || profile === '') return []; + const names = WINDOWS_VC_RUNTIME_PROFILES[profile]; + if (names === undefined) { + throw failure( + `unknown VC runtime profile ${profile}; expected one of ${Object.keys(WINDOWS_VC_RUNTIME_PROFILES).sort().join(', ')}`, + ); + } + for (const name of names) checkedRuntimeImport(name, `VC runtime profile ${profile}`); + return [...names]; +} + +function carrierInventory(root) { + const inventory = []; + const direct = new Set(); + for (const file of walkRegularFiles(root)) { + if (!isPe(file)) continue; + const pe = inspectPortableExecutable(file); + if (pe.machine !== PE_MACHINE_AMD64 || pe.magic !== PE_MAGIC_64) { + throw failure( + `${file} is not an x64 PE32+ image (machine 0x${pe.machine.toString(16)}, magic 0x${pe.magic.toString(16)})`, + ); + } + const imports = pe.imports.filter((name) => VC_RUNTIME_IMPORT.test(name)); + const basename = path.basename(file).toLowerCase(); + if (!WINDOWS_VC_RUNTIME_DLLS.includes(basename)) { + for (const imported of imports) direct.add(checkedRuntimeImport(imported, file)); + } + inventory.push({ + file: path.relative(root, file).split(path.sep).join('/'), + vcRuntimeImports: imports, + }); + } + return { direct, inventory }; +} + +function closureFromSource(direct, sourceDirectory) { + const required = new Map(); + const pending = [...direct].sort(); + while (pending.length > 0) { + const name = pending.shift(); + if (required.has(name)) continue; + const source = requiredSource(sourceDirectory, name); + required.set(name, source); + for (const imported of source.pe.imports.filter((value) => VC_RUNTIME_IMPORT.test(value))) { + const dependency = checkedRuntimeImport(imported, source.source); + if (!required.has(dependency)) pending.push(dependency); + } + pending.sort(); + } + return required; +} + +function receiptText(required) { + return [...required] + .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0)) + .map(([name, { source }]) => `${sha256(source)} ${name}\n`) + .join(''); +} + +export function parseWindowsVcRuntimeReceipt(input, label = WINDOWS_VC_RUNTIME_RECEIPT) { + const text = Buffer.isBuffer(input) ? input.toString('utf8') : String(input); + const values = new Map(); + for (const [index, raw] of text.split(/\r?\n/u).entries()) { + if (!raw) continue; + const match = /^([0-9a-f]{64}) ([a-z0-9_]+\.dll)$/u.exec(raw); + if (!match) throw failure(`${label} has malformed line ${index + 1}`); + const [, digest, name] = match; + if (!WINDOWS_VC_RUNTIME_DLLS.includes(name) || values.has(name)) { + throw failure(`${label} has undeclared or duplicate entry ${name}`); + } + values.set(name, digest); + } + if (values.size === 0) throw failure(`${label} must not be empty`); + const sorted = [...values.keys()].sort(); + if (text !== sorted.map((name) => `${values.get(name)} ${name}\n`).join('')) { + throw failure(`${label} must be lowercase, sorted, and canonical`); + } + return values; +} + +function parseReceipt(directory) { + const receipt = path.join(directory, WINDOWS_VC_RUNTIME_RECEIPT); + if (!isRegularFile(receipt)) { + throw failure( + `${directory} is missing regular VC runtime digest receipt ${WINDOWS_VC_RUNTIME_RECEIPT}`, + ); + } + const values = parseWindowsVcRuntimeReceipt(readFileSync(receipt), receipt); + for (const [name, digest] of values) { + const file = path.join(directory, name); + if (!isRegularFile(file) || sha256(file) !== digest) { + throw failure(`${receipt} does not match regular ${file}`); + } + } + return values; +} + +function removeStaleRuntimeFiles(destination, requiredNames) { + const names = entriesByLowercase(destination); + for (const allowed of WINDOWS_VC_RUNTIME_DLLS) { + const actual = names.get(allowed); + if (actual === undefined || requiredNames.has(allowed)) continue; + const stale = path.join(destination, actual); + if (!isRegularFile(stale)) + throw failure(`refusing to remove non-regular stale VC runtime ${stale}`); + rmSync(stale); + } +} + +export function stageWindowsVcRuntime({ + root, + redistRoot, + sourceDirectory, + destinations, + profile, +}) { + const resolvedRoot = path.resolve(root); + requireDirectory(resolvedRoot, 'dependency-closure root'); + if (!Array.isArray(destinations) || destinations.length === 0) { + throw failure('at least one destination is required'); + } + if (redistRoot !== undefined && sourceDirectory !== undefined) { + throw failure('redistRoot and sourceDirectory are mutually exclusive'); + } + const source = + sourceDirectory === undefined + ? resolveInitializedVcRuntimeDirectory(redistRoot) + : path.resolve(sourceDirectory); + if (sourceDirectory !== undefined) parseReceipt(source); + const { direct } = carrierInventory(resolvedRoot); + for (const name of windowsVcRuntimeProfileNames(profile)) direct.add(name); + const sources = closureFromSource(direct, source); + const requiredNames = new Set(sources.keys()); + for (const destinationValue of destinations) { + const destination = path.resolve(destinationValue); + if (!within(resolvedRoot, destination)) { + throw failure(`VC runtime destination must stay within ${resolvedRoot}: ${destination}`); + } + mkdirSync(destination, { recursive: true }); + requireDirectory(destination, 'VC runtime destination'); + for (const entry of sources.values()) { + copyAtomic(entry.source, path.join(destination, entry.expected)); + } + removeStaleRuntimeFiles(destination, requiredNames); + const receipt = path.join(destination, WINDOWS_VC_RUNTIME_RECEIPT); + if (sources.size === 0) rmSync(receipt, { force: true }); + else writeAtomic(receipt, receiptText(sources)); + } + return verifyWindowsVcRuntimeClosure({ root: resolvedRoot, searchRoots: destinations, profile }); +} + +function walkRegularFiles(root) { + const files = []; + const visit = (directory) => { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + const file = path.join(directory, entry.name); + if (entry.isSymbolicLink()) { + throw failure(`dependency-closure root contains a symbolic link: ${file}`); + } + if (entry.isDirectory()) visit(file); + else if (entry.isFile()) files.push(file); + } + }; + visit(root); + return files.sort(); +} + +function isPe(file) { + if (!isRegularFile(file)) return false; + const buffer = readFileSync(file); + return buffer.length >= 2 && buffer[0] === 0x4d && buffer[1] === 0x5a; +} + +function within(parent, child) { + const relative = path.relative(parent, child); + return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative)); +} + +export function verifyWindowsVcRuntimeClosure({ root, searchRoots, profile }) { + const resolvedRoot = path.resolve(root); + requireDirectory(resolvedRoot, 'dependency-closure root'); + if (!Array.isArray(searchRoots) || searchRoots.length === 0) { + throw failure('at least one dependency search root is required'); + } + const resolvedSearchRoots = searchRoots.map((value) => path.resolve(value)); + const { direct, inventory } = carrierInventory(resolvedRoot); + for (const name of windowsVcRuntimeProfileNames(profile)) direct.add(name); + const sourceRoot = resolvedSearchRoots[0]; + const required = closureFromSource(direct, sourceRoot); + const expected = new Set(required.keys()); + for (const searchRoot of resolvedSearchRoots) { + if (!within(resolvedRoot, searchRoot)) { + throw failure(`dependency search root must stay within ${resolvedRoot}: ${searchRoot}`); + } + requireDirectory(searchRoot, 'dependency search root'); + const names = entriesByLowercase(searchRoot); + const actual = new Set(WINDOWS_VC_RUNTIME_DLLS.filter((name) => names.has(name))); + const missing = [...expected].filter((name) => !actual.has(name)); + const extra = [...actual].filter((name) => !expected.has(name)); + if (missing.length > 0 || extra.length > 0) { + throw failure( + `${searchRoot} VC runtime closure mismatch; missing [${missing.sort().join(', ')}], extra [${extra.sort().join(', ')}]`, + ); + } + if (expected.size === 0) { + if (names.has(WINDOWS_VC_RUNTIME_RECEIPT.toLowerCase())) { + throw failure( + `${searchRoot} has a VC runtime receipt but its carrier imports no VC runtime`, + ); + } + continue; + } + const receipt = parseReceipt(searchRoot); + if ([...receipt.keys()].sort().join('\0') !== [...expected].sort().join('\0')) { + throw failure( + `${searchRoot} digest receipt does not exactly describe its import-derived VC runtime closure`, + ); + } + } + return { required: [...expected].sort(), inventory }; +} + +function parseArgs(argv) { + const command = argv[0]; + const args = { + command, + redistRoot: undefined, + sourceDirectory: undefined, + profile: undefined, + destinations: [], + root: undefined, + searchRoots: [], + json: false, + printRequired: false, + }; + for (let index = 1; index < argv.length; index += 1) { + const flag = argv[index]; + if (flag === '--json') { + args.json = true; + continue; + } + if (flag === '--print-required') { + args.printRequired = true; + continue; + } + const value = argv[++index]; + if (value === undefined) throw failure(`${flag} requires a value`); + if (flag === '--redist-root') args.redistRoot = value; + else if (flag === '--source-dir') args.sourceDirectory = value; + else if (flag === '--destination') args.destinations.push(value); + else if (flag === '--profile') args.profile = value; + else if (flag === '--root') args.root = value; + else if (flag === '--search-root') args.searchRoots.push(value); + else throw failure(`unknown argument ${flag}`); + } + return args; +} + +function usage() { + return `Usage: + ${TOOL} stage --root DIR [--redist-root DIR | --source-dir DIR] [--profile NAME] --destination DIR [--destination DIR ...] [--print-required] + ${TOOL} verify --root DIR [--profile NAME] --search-root DIR [--search-root DIR ...] [--json] [--print-required] +`; +} + +export function main(argv = process.argv.slice(2)) { + let args; + try { + args = parseArgs(argv); + if (args.command === 'stage') { + if (!args.root) throw failure('stage requires --root'); + const result = stageWindowsVcRuntime({ + root: args.root, + redistRoot: args.redistRoot, + sourceDirectory: args.sourceDirectory, + destinations: args.destinations, + profile: args.profile, + }); + if (args.printRequired) console.log(result.required.join(',')); + return; + } + if (args.command === 'verify') { + if (!args.root) throw failure('verify requires --root'); + const result = verifyWindowsVcRuntimeClosure({ + root: args.root, + searchRoots: args.searchRoots, + profile: args.profile, + }); + if (args.json) console.log(JSON.stringify(result, null, 2)); + if (args.printRequired) console.log(result.required.join(',')); + return; + } + console.error(usage()); + process.exit(2); + } catch (error) { + fail(error instanceof Error ? error.message.replace(`${TOOL}: `, '') : String(error)); + } +} + +if (import.meta.main) main(); diff --git a/tools/packaging/windows-vc-runtime-closure.test.mts b/tools/packaging/windows-vc-runtime-closure.test.mts new file mode 100644 index 000000000..614038a80 --- /dev/null +++ b/tools/packaging/windows-vc-runtime-closure.test.mts @@ -0,0 +1,293 @@ +import { strict as assert } from 'node:assert'; +import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { describe, test } from 'node:test'; + +import { + WINDOWS_VC_RUNTIME_DLLS, + WINDOWS_VC_RUNTIME_PROFILES, + WINDOWS_VC_RUNTIME_RECEIPT, + inspectPortableExecutable, + resolveInitializedVcRuntimeDirectory, + stageWindowsVcRuntime, + verifyWindowsVcRuntimeClosure, +} from './windows-vc-runtime-closure.mts'; + +function pe({ machine = 0x8664, imports = [], delayImports = [] } = {}) { + const buffer = Buffer.alloc(0x800); + buffer.write('MZ', 0, 'ascii'); + buffer.writeUInt32LE(0x80, 0x3c); + buffer.write('PE\0\0', 0x80, 'binary'); + const coff = 0x84; + buffer.writeUInt16LE(machine, coff); + buffer.writeUInt16LE(1, coff + 2); + buffer.writeUInt16LE(0xf0, coff + 16); + const optional = coff + 20; + buffer.writeUInt16LE(0x20b, optional); + buffer.writeBigUInt64LE(0x140000000n, optional + 24); + buffer.writeUInt32LE(16, optional + 108); + const directories = optional + 112; + const section = optional + 0xf0; + buffer.write('.rdata', section, 'ascii'); + buffer.writeUInt32LE(0x600, section + 8); + buffer.writeUInt32LE(0x1000, section + 12); + buffer.writeUInt32LE(0x600, section + 16); + buffer.writeUInt32LE(0x200, section + 20); + + let strings = 0x600; + const writeName = (name) => { + const offset = strings; + buffer.write(`${name}\0`, offset, 'ascii'); + strings += Buffer.byteLength(name) + 1; + return 0x1000 + offset - 0x200; + }; + if (imports.length > 0) { + buffer.writeUInt32LE(0x1000, directories + 8); + buffer.writeUInt32LE((imports.length + 1) * 20, directories + 12); + imports.forEach((name, index) => { + buffer.writeUInt32LE(writeName(name), 0x200 + index * 20 + 12); + }); + } + if (delayImports.length > 0) { + const delayRva = 0x1200; + buffer.writeUInt32LE(delayRva, directories + 13 * 8); + buffer.writeUInt32LE((delayImports.length + 1) * 32, directories + 13 * 8 + 4); + delayImports.forEach((name, index) => { + const descriptor = 0x400 + index * 32; + buffer.writeUInt32LE(1, descriptor); + buffer.writeUInt32LE(writeName(name), descriptor + 4); + }); + } + return buffer.subarray(0, strings); +} + +function fixture(root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-vc-runtime-'))) { + const redist = path.join(root, 'redist'); + const source = path.join(redist, 'x64/Microsoft.VC145.CRT'); + mkdirSync(source, { recursive: true }); + for (const name of WINDOWS_VC_RUNTIME_DLLS) { + writeFileSync(path.join(source, name), pe({ imports: ['KERNEL32.dll'] })); + } + return { root, redist, source }; +} + +if (['prepare', 'verify'].includes(process.argv[2])) { + const root = process.argv[3]; + const carrier = path.join(root, 'carrier'); + const bin = path.join(carrier, 'bin'); + const producer = path.join(bin, 'app.exe'); + const runtime = path.join(bin, 'vcruntime140.dll'); + const receipt = path.join(bin, WINDOWS_VC_RUNTIME_RECEIPT); + if (process.argv[2] === 'prepare') { + const { redist } = fixture(root); + mkdirSync(bin, { recursive: true }); + writeFileSync(producer, pe({ imports: ['VCRUNTIME140.dll'] })); + stageWindowsVcRuntime({ root: carrier, redistRoot: redist, destinations: [bin] }); + for (const [name, file] of [ + ['producer', producer], + ['runtime', runtime], + ['receipt', receipt], + ]) { + writeFileSync(path.join(root, `${name}.before`), readFileSync(file)); + } + } else { + assert.notDeepEqual(readFileSync(producer), readFileSync(path.join(root, 'producer.before'))); + assert.deepEqual(readFileSync(runtime), readFileSync(path.join(root, 'runtime.before'))); + assert.deepEqual(readFileSync(receipt), readFileSync(path.join(root, 'receipt.before'))); + assert.match( + readFileSync(path.join(root, 'strip.log'), 'utf8'), + /preservedAppLocalVcRuntime=.*vcruntime140\.dll/u, + ); + verifyWindowsVcRuntimeClosure({ root: carrier, searchRoots: [bin] }); + } + process.exit(0); +} + +describe('Windows VC runtime dependency closure', () => { + test('parses normal and delay-load imports without an external Windows tool', () => { + const parsed = inspectPortableExecutable( + pe({ + imports: ['VCRUNTIME140.dll'], + delayImports: ['MSVCP140.dll'], + }), + 'fixture', + ); + assert.equal(parsed.machine, 0x8664); + assert.equal(parsed.magic, 0x20b); + assert.deepEqual(parsed.imports, ['MSVCP140.dll', 'VCRUNTIME140.dll']); + }); + + test('the provider profile carries the exact supported-extension union', () => { + const { root, redist } = fixture(); + try { + const carrier = path.join(root, 'carrier'); + const bin = path.join(carrier, 'bin'); + mkdirSync(bin, { recursive: true }); + writeFileSync(path.join(bin, 'oliphaunt.dll'), pe({ imports: ['VCRUNTIME140.dll'] })); + const result = stageWindowsVcRuntime({ + root: carrier, + redistRoot: redist, + destinations: [bin], + profile: 'provider', + }); + assert.deepEqual(result.required, WINDOWS_VC_RUNTIME_PROFILES.provider); + assert.deepEqual( + readFileSync(path.join(bin, WINDOWS_VC_RUNTIME_RECEIPT), 'utf8') + .trim() + .split('\n') + .map((line) => line.split(' ')[1]), + WINDOWS_VC_RUNTIME_PROFILES.provider, + ); + assert.throws( + () => verifyWindowsVcRuntimeClosure({ root: carrier, searchRoots: [bin] }), + /extra \[msvcp140\.dll, vcruntime140_1\.dll\]/u, + ); + assert.deepEqual( + verifyWindowsVcRuntimeClosure({ root: carrier, searchRoots: [bin], profile: 'provider' }) + .required, + WINDOWS_VC_RUNTIME_PROFILES.provider, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + + test('resolves exactly one initialized x64 CRT and atomically stages the audited union', () => { + const { root, redist, source } = fixture(); + try { + assert.equal(resolveInitializedVcRuntimeDirectory(redist), source); + const first = path.join(root, 'stage/bin'); + const second = path.join(root, 'stage/runtime/bin'); + mkdirSync(path.join(root, 'stage'), { recursive: true }); + writeFileSync(path.join(root, 'stage/app.exe'), pe({ imports: ['VCRUNTIME140.dll'] })); + stageWindowsVcRuntime({ + root: path.join(root, 'stage'), + redistRoot: redist, + destinations: [first, second], + }); + stageWindowsVcRuntime({ + root: path.join(root, 'stage'), + redistRoot: redist, + destinations: [first, second], + }); + assert.deepEqual( + readFileSync(path.join(first, 'vcruntime140.dll')), + readFileSync(path.join(source, 'vcruntime140.dll')), + ); + assert.deepEqual( + readFileSync(path.join(second, 'vcruntime140.dll')), + readFileSync(path.join(source, 'vcruntime140.dll')), + ); + assert.match( + readFileSync(path.join(first, WINDOWS_VC_RUNTIME_RECEIPT), 'utf8'), + /^[0-9a-f]{64} vcruntime140\.dll\n$/u, + ); + assert.equal( + WINDOWS_VC_RUNTIME_DLLS.filter((name) => name !== 'vcruntime140.dll').some((name) => + readFileSync(path.join(first, WINDOWS_VC_RUNTIME_RECEIPT), 'utf8').includes(name), + ), + false, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + + test('requires the exact VC145 redistributable directory and x64 source DLLs', () => { + const { root, redist, source } = fixture(); + try { + rmSync(source, { recursive: true, force: true }); + const duplicate = path.join(redist, 'x64/Microsoft.VC143.CRT'); + mkdirSync(duplicate, { recursive: true }); + for (const name of WINDOWS_VC_RUNTIME_DLLS) writeFileSync(path.join(duplicate, name), pe()); + assert.throws(() => resolveInitializedVcRuntimeDirectory(redist), /exactly one initialized/u); + rmSync(duplicate, { recursive: true, force: true }); + mkdirSync(source, { recursive: true }); + for (const name of WINDOWS_VC_RUNTIME_DLLS) writeFileSync(path.join(source, name), pe()); + writeFileSync(path.join(source, WINDOWS_VC_RUNTIME_DLLS[0]), pe({ machine: 0x14c })); + const carrier = path.join(root, 'carrier'); + mkdirSync(carrier); + writeFileSync(path.join(carrier, 'app.exe'), pe({ imports: [WINDOWS_VC_RUNTIME_DLLS[0]] })); + assert.throws( + () => + stageWindowsVcRuntime({ + root: carrier, + redistRoot: redist, + destinations: [path.join(carrier, 'bin')], + }), + /not an x64 PE32\+ image/u, + ); + const pe32 = pe(); + pe32.writeUInt16LE(0x10b, 0x98); + writeFileSync(path.join(source, WINDOWS_VC_RUNTIME_DLLS[0]), pe32); + assert.throws( + () => + stageWindowsVcRuntime({ + root: carrier, + redistRoot: redist, + destinations: [path.join(carrier, 'bin')], + }), + /not an x64 PE32\+ image/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + + test('atomically replaces a stale regular destination from the initialized toolchain', () => { + const { root, redist, source } = fixture(); + try { + const destination = path.join(root, 'out'); + mkdirSync(destination); + writeFileSync( + path.join(destination, 'app.exe'), + pe({ imports: [WINDOWS_VC_RUNTIME_DLLS[0]] }), + ); + stageWindowsVcRuntime({ root: destination, redistRoot: redist, destinations: [destination] }); + writeFileSync(path.join(destination, WINDOWS_VC_RUNTIME_DLLS[0]), 'tampered'); + stageWindowsVcRuntime({ root: destination, redistRoot: redist, destinations: [destination] }); + assert.deepEqual( + readFileSync(path.join(destination, WINDOWS_VC_RUNTIME_DLLS[0])), + readFileSync(path.join(source, WINDOWS_VC_RUNTIME_DLLS[0])), + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + + test('rejects a missing app-local DLL and an undeclared future VC runtime import', () => { + const { root, redist } = fixture(); + try { + const payload = path.join(root, 'payload'); + const bin = path.join(payload, 'bin'); + mkdirSync(bin, { recursive: true }); + writeFileSync(path.join(bin, 'postgres.exe'), pe({ imports: ['VCRUNTIME140.dll'] })); + stageWindowsVcRuntime({ root: payload, redistRoot: redist, destinations: [bin] }); + assert.equal( + verifyWindowsVcRuntimeClosure({ root: payload, searchRoots: [bin] }).inventory.length, + 2, + ); + + rmSync(path.join(bin, 'vcruntime140.dll')); + assert.throws( + () => verifyWindowsVcRuntimeClosure({ root: payload, searchRoots: [bin] }), + /is missing import-derived vcruntime140\.dll/u, + ); + writeFileSync(path.join(bin, 'vcruntime140.dll'), pe()); + writeFileSync(path.join(bin, 'future.dll'), pe({ delayImports: ['MSVCP999.dll'] })); + assert.throws( + () => verifyWindowsVcRuntimeClosure({ root: payload, searchRoots: [bin] }), + /imports undeclared or debug VC runtime MSVCP999\.dll/u, + ); + rmSync(path.join(bin, 'future.dll')); + writeFileSync(path.join(bin, 'debug.dll'), pe({ imports: ['ucrtbased.dll'] })); + assert.throws( + () => verifyWindowsVcRuntimeClosure({ root: payload, searchRoots: [bin] }), + /imports undeclared or debug VC runtime ucrtbased\.dll/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); +}); diff --git a/tools/packaging/windows-vc-runtime-closure.test.sh b/tools/packaging/windows-vc-runtime-closure.test.sh new file mode 100644 index 000000000..f7c04f1a3 --- /dev/null +++ b/tools/packaging/windows-vc-runtime-closure.test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +bun test ./tools/packaging/windows-vc-runtime-closure.test.mts +scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-vc-strip-XXXXXX") +trap 'rm -rf "$scratch"' EXIT +bun tools/packaging/windows-vc-runtime-closure.test.mts prepare "$scratch" +cat > "$scratch/strip" <<'STRIP' +#!/usr/bin/env bash +set -euo pipefail +printf X >> "${!#}" +STRIP +chmod +x "$scratch/strip" +OLIPHAUNT_PE_STRIP="$scratch/strip" bash tools/packaging/strip-native-binaries.sh \ + --target windows-x64-msvc "$scratch/carrier" > "$scratch/strip.log" 2>&1 +bun tools/packaging/windows-vc-runtime-closure.test.mts verify "$scratch" diff --git a/tools/packaging/write-checksum-manifest.mts b/tools/packaging/write-checksum-manifest.mts new file mode 100755 index 000000000..0f870ab83 --- /dev/null +++ b/tools/packaging/write-checksum-manifest.mts @@ -0,0 +1,132 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { createReadStream, readdirSync } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; + +function fail(message) { + console.error(`write_checksum_manifest.mts: ${message}`); + process.exit(2); +} + +function parseArgs(argv) { + const patterns = []; + let assetDir = null; + let output = null; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + switch (arg) { + case '--asset-dir': + assetDir = argv[index + 1] ?? null; + index += 1; + break; + case '--output': + output = argv[index + 1] ?? null; + index += 1; + break; + case '--pattern': + patterns.push(argv[index + 1] ?? ''); + index += 1; + break; + default: + fail(`unknown argument: ${arg}`); + } + } + if ( + !assetDir || + !output || + patterns.length === 0 || + patterns.some((pattern) => pattern.length === 0) + ) { + fail( + 'usage: tools/packaging/write-checksum-manifest.mts --asset-dir --output --pattern [--pattern ...]', + ); + } + return { + assetDir: path.resolve(assetDir), + output, + patterns, + }; +} + +async function sha256(file) { + const digest = createHash('sha256'); + for await (const chunk of createReadStream(file)) { + digest.update(chunk); + } + return digest.digest('hex'); +} + +function baseName(relativePath) { + return relativePath.split(/[\\/]/u).pop(); +} + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function releaseAssetFiles(assetDir) { + const files = []; + const visit = (directory, segments) => { + const entries = readdirSync(directory, { withFileTypes: true }).sort((left, right) => + compareText(left.name, right.name), + ); + for (const entry of entries) { + // Bun's filesystem globbing defaults to dot=false. Keep hidden files + // and hidden directory subtrees outside the candidate set before using + // its pure matcher so this replacement does not broaden release inputs. + if (entry.name.startsWith('.')) { + continue; + } + const nextSegments = [...segments, entry.name]; + const absolutePath = path.join(directory, entry.name); + if (entry.isDirectory()) { + visit(absolutePath, nextSegments); + } else if (entry.isFile()) { + files.push({ + absolutePath, + relativePath: nextSegments.join('/'), + }); + } + } + }; + visit(assetDir, []); + return files.sort((left, right) => compareText(left.relativePath, right.relativePath)); +} + +export function matchingAssets(assetDir, patterns) { + const assets = new Map(); + const files = releaseAssetFiles(assetDir); + for (const pattern of patterns) { + const glob = new Bun.Glob(pattern); + const explicitRelativePrefix = pattern.startsWith('./'); + for (const file of files) { + const matchPath = explicitRelativePrefix ? `./${file.relativePath}` : file.relativePath; + if (glob.match(matchPath)) { + assets.set(baseName(file.relativePath), file.absolutePath); + } + } + } + return [...assets.keys()].sort(compareText).map((name) => assets.get(name)); +} + +export async function writeChecksumManifest(argv) { + const args = parseArgs(argv); + const outputPath = path.join(args.assetDir, args.output); + const lines = []; + const assets = matchingAssets(args.assetDir, args.patterns); + if (assets.length === 0) { + fail(`no release assets found in ${args.assetDir} matching ${args.patterns.join(', ')}`); + } + for (const asset of assets) { + if (path.resolve(asset) === path.resolve(outputPath)) { + continue; + } + lines.push(`${await sha256(asset)} ./${path.basename(asset)}\n`); + } + await fs.writeFile(outputPath, lines.join('')); +} + +if (import.meta.main) { + await writeChecksumManifest(Bun.argv.slice(2)); +} diff --git a/tools/packaging/write-checksum-manifest.test.mts b/tools/packaging/write-checksum-manifest.test.mts new file mode 100644 index 000000000..0a3231758 --- /dev/null +++ b/tools/packaging/write-checksum-manifest.test.mts @@ -0,0 +1,100 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { matchingAssets, writeChecksumManifest } from './write-checksum-manifest.mts'; + +const TOOL = path.join(import.meta.dir, 'write-checksum-manifest.mts'); + +function writeFixture(root, relativePath, contents = `${relativePath}\n`) { + const file = path.join(root, ...relativePath.split('/')); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, contents); + return file; +} + +function relativeFiles(root, files) { + return files.map((file) => path.relative(root, file).split(path.sep).join('/')); +} + +function sha256(contents) { + return createHash('sha256').update(contents).digest('hex'); +} + +test('preserves recursive and root-relative glob semantics with deterministic output order', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-checksum-walk-')); + try { + writeFixture(root, 'z.zip'); + writeFixture(root, 'root.tar.gz'); + writeFixture(root, 'nested/b.tar.gz'); + writeFixture(root, 'nested/deeper/a.tar.gz'); + writeFixture(root, 'nested/ignored.txt'); + writeFixture(root, '.hidden.tar.gz'); + writeFixture(root, '.hidden/also-hidden.tar.gz'); + writeFixture(root, 'nested/.hidden-too.tar.gz'); + + expect(relativeFiles(root, matchingAssets(root, ['**/*.tar.gz', '*.zip']))).toEqual([ + 'nested/deeper/a.tar.gz', + 'nested/b.tar.gz', + 'root.tar.gz', + 'z.zip', + ]); + expect(relativeFiles(root, matchingAssets(root, ['*.tar.gz']))).toEqual(['root.tar.gz']); + expect(relativeFiles(root, matchingAssets(root, ['nested/*.tar.gz']))).toEqual([ + 'nested/b.tar.gz', + ]); + expect(relativeFiles(root, matchingAssets(root, ['./*.zip']))).toEqual(['z.zip']); + expect(matchingAssets(root, ['.hidden.tar.gz', '**/.hidden*.tar.gz'])).toEqual([]); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('does not follow file or directory symlinks while walking assets', () => { + const parent = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-checksum-symlink-')); + try { + const root = path.join(parent, 'assets'); + const outside = path.join(parent, 'outside'); + mkdirSync(root); + mkdirSync(outside); + writeFixture(root, 'real.tar.gz'); + const outsideAsset = writeFixture(outside, 'outside.tar.gz'); + symlinkSync( + outside, + path.join(root, 'linked-directory'), + process.platform === 'win32' ? 'junction' : 'dir', + ); + if (process.platform !== 'win32') { + symlinkSync(outsideAsset, path.join(root, 'linked-file.tar.gz'), 'file'); + } + + expect(relativeFiles(root, matchingAssets(root, ['**/*.tar.gz']))).toEqual(['real.tar.gz']); + } finally { + rmSync(parent, { recursive: true, force: true }); + } +}); + +test('writes the caller-facing checksum manifest deterministically', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-checksum-output-')); + try { + writeFixture(root, 'z.zip', 'zip payload\n'); + writeFixture(root, 'a.tar.gz', 'tar payload\n'); + await writeChecksumManifest([ + '--asset-dir', + root, + '--output', + 'release-assets.sha256', + '--pattern', + '*.zip', + '--pattern', + '*.tar.gz', + ]); + expect(readFileSync(path.join(root, 'release-assets.sha256'), 'utf8')).toBe( + `${sha256('tar payload\n')} ./a.tar.gz\n` + `${sha256('zip payload\n')} ./z.zip\n`, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/tools/perf/check-native-perf-report.sh b/tools/perf/check-native-perf-report.sh deleted file mode 100755 index 30f352e0e..000000000 --- a/tools/perf/check-native-perf-report.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -if [ -z "${OLIPHAUNT_PERF_RUN_DIR:-}" ]; then - echo "OLIPHAUNT_PERF_RUN_DIR must point at a target/perf/native-liboliphaunt-* run directory" >&2 - exit 2 -fi - -args=(verify --run-dir "$OLIPHAUNT_PERF_RUN_DIR") -if [ "${OLIPHAUNT_PERF_ALLOW_DIAGNOSTIC:-0}" = "1" ]; then - node tools/perf/matrix/native_oliphaunt_provenance.mjs "${args[@]}" -else - node tools/perf/matrix/native_oliphaunt_provenance.mjs "${args[@]}" --require-release-evidence -fi diff --git a/tools/perf/matrix/native_oliphaunt_provenance.mjs b/tools/perf/matrix/native_oliphaunt_provenance.mjs deleted file mode 100644 index bfb566b0a..000000000 --- a/tools/perf/matrix/native_oliphaunt_provenance.mjs +++ /dev/null @@ -1,934 +0,0 @@ -#!/usr/bin/env node -import { spawnSync } from 'node:child_process' -import { createHash } from 'node:crypto' -import fs from 'node:fs/promises' -import os from 'node:os' -import path from 'node:path' -import process from 'node:process' - -const SOURCE_INPUTS = [ - { type: 'file', path: 'Cargo.lock' }, - { type: 'file', path: 'Cargo.toml' }, - { type: 'file', path: 'src/sdks/rust/Cargo.toml' }, - { type: 'dir', path: 'src/sdks/rust/src', extensions: ['.rs'] }, - { type: 'dir', path: 'src/sdks/rust/tests', extensions: ['.rs'] }, - { type: 'dir', path: 'src/runtimes/liboliphaunt/native/bin', extensions: ['.sh'] }, - { type: 'dir', path: 'src/runtimes/liboliphaunt/native/include', extensions: ['.h'] }, - { type: 'dir', path: 'src/runtimes/liboliphaunt/native/patches', extensions: ['.patch'] }, - { type: 'dir', path: 'src/runtimes/liboliphaunt/native/postgres18', extensions: ['.toml'] }, - { type: 'dir', path: 'src/runtimes/liboliphaunt/native/src', extensions: ['.c', '.h'] }, - { type: 'file', path: 'tools/perf/runner/Cargo.toml' }, - { type: 'dir', path: 'tools/perf/runner/src', extensions: ['.rs'] }, - { type: 'dir', path: 'tools/perf/matrix', extensions: ['.mjs', '.sh'] }, -] - -const BENCHMARK_ENV_KEYS = [ - 'OLIPHAUNT_PGDATA_COPY_MODE', - 'OLIPHAUNT_RUNTIME_CACHE_DIR', - 'OLIPHAUNT_PERF_DURABILITY', - 'OLIPHAUNT_PERF_RUNTIME_FOOTPRINT', - 'OLIPHAUNT_PERF_STARTUP_GUCS', - 'OLIPHAUNT_STREAM_QUEUE_MAX_BYTES', - 'OLIPHAUNT_STACK_BYTES', -] - -function usage() { - console.error(`usage: - native_oliphaunt_provenance.mjs write --run-dir DIR --repo-root DIR [options] - native_oliphaunt_provenance.mjs verify --run-dir DIR [--repo-root DIR] [--require-release-evidence] - -write options: - --run-id ID - --native-engines LIST - --suites LIST - --durability PROFILE - --runtime-footprint PROFILE - --startup-gucs LIST - --rtt-iterations N - --rtt-repeats N - --prepared-rows N - --prepared-repeats N - --speed-repeats N - --backup-repeats N - --run-sqlite 0|1 - --run-prepared 0|1 - --release-evidence 0|1 - --partial-report 0|1 - --diagnostic-run 0|1 - --release-min-rtt-iterations N - --release-min-rtt-repeats N - --release-min-prepared-rows N - --release-min-prepared-repeats N - --release-min-speed-repeats N - --release-min-backup-repeats N - --pgdata-copy-mode MODE - --liboliphaunt PATH - --postgres-bin PATH - --initdb-bin PATH - --perf-runner PATH`) -} - -function parseArgs(argv) { - const command = argv[0] - const args = {} - for (let index = 1; index < argv.length; index += 1) { - const key = argv[index] - if (!key.startsWith('--')) { - throw new Error(`unexpected argument: ${key}`) - } - const hasValue = index + 1 < argv.length - const value = argv[index + 1] - if (hasValue && !value.startsWith('--')) { - args[key] = value - index += 1 - } else { - args[key] = 'true' - } - } - return { command, args } -} - -function requireArg(args, key) { - const value = args[key] - if (!value) { - throw new Error(`${key} is required`) - } - return value -} - -function optionalPath(value) { - return value && value !== 'true' ? path.resolve(value) : null -} - -function numberArg(args, key) { - const value = args[key] - if (value === undefined) { - return null - } - const parsed = Number(value) - if (!Number.isFinite(parsed)) { - throw new Error(`${key} must be numeric`) - } - return parsed -} - -function flagArg(args, key) { - const value = args[key] - if (value === undefined) { - return null - } - return value === '1' || value === 'true' -} - -function stringListArg(args, key) { - const value = args[key] - if (value === undefined || value === 'true') { - return [] - } - return value - .split(',') - .map((item) => item.trim()) - .filter((item) => item.length > 0) -} - -function sameStringList(actual, expected) { - return ( - Array.isArray(actual) && - actual.length === expected.length && - actual.every((value, index) => value === expected[index]) - ) -} - -function finiteNumber(value) { - return typeof value === 'number' && Number.isFinite(value) -} - -function repeatIndex(index, repeatCount) { - return String(index).padStart(String(repeatCount).length, '0') -} - -function benchmarkEnvironment(args) { - const env = {} - for (const key of BENCHMARK_ENV_KEYS) { - env[key] = process.env[key] ?? null - } - env.OLIPHAUNT_PGDATA_COPY_MODE = - args['--pgdata-copy-mode'] ?? env.OLIPHAUNT_PGDATA_COPY_MODE - return env -} - -function posixRelative(root, target) { - return path.relative(root, target).split(path.sep).join('/') -} - -async function fileSha256(file) { - return createHash('sha256').update(await fs.readFile(file)).digest('hex') -} - -function digestEntries(entries) { - const hash = createHash('sha256') - for (const entry of entries) { - hash.update(entry.path) - hash.update('\0') - hash.update(entry.sha256) - hash.update('\n') - } - return hash.digest('hex') -} - -async function walkFiles(root, extensions) { - const output = [] - - async function walk(dir) { - const entries = await fs.readdir(dir, { withFileTypes: true }) - for (const entry of entries) { - const absolute = path.join(dir, entry.name) - if (entry.isDirectory()) { - await walk(absolute) - } else if (entry.isFile() || entry.isSymbolicLink()) { - if (!extensions || extensions.includes(path.extname(entry.name))) { - output.push(absolute) - } - } - } - } - - await walk(root) - return output.sort() -} - -async function collectSource(repoRoot) { - const paths = new Set() - for (const input of SOURCE_INPUTS) { - const absolute = path.join(repoRoot, input.path) - const stat = await fs.stat(absolute) - if (input.type === 'file') { - if (!stat.isFile()) { - throw new Error(`source input is not a file: ${input.path}`) - } - paths.add(input.path) - } else { - if (!stat.isDirectory()) { - throw new Error(`source input is not a directory: ${input.path}`) - } - const files = await walkFiles(absolute, input.extensions) - for (const file of files) { - paths.add(posixRelative(repoRoot, file)) - } - } - } - - const entries = [] - for (const relativePath of [...paths].sort()) { - const absolute = path.join(repoRoot, relativePath) - const stat = await fs.stat(absolute) - entries.push({ - path: relativePath, - bytes: stat.size, - sha256: await fileSha256(absolute), - }) - } - - return { - inputs: SOURCE_INPUTS, - sourceSetSha256: digestEntries(entries), - entries, - } -} - -async function hashDirectory(root) { - const files = await walkFiles(root) - const entries = [] - let bytes = 0 - for (const file of files) { - const stat = await fs.lstat(file) - const relativeFile = posixRelative(root, file) - if (stat.isSymbolicLink()) { - const target = await fs.readlink(file) - const targetBytes = Buffer.byteLength(target) - bytes += targetBytes - entries.push({ - path: relativeFile, - kind: 'symlink', - bytes: targetBytes, - sha256: createHash('sha256').update(`symlink\0${target}`).digest('hex'), - }) - continue - } - bytes += stat.size - entries.push({ - path: relativeFile, - kind: 'file', - bytes: stat.size, - sha256: await fileSha256(file), - }) - } - return { - kind: 'directory', - bytes, - fileCount: entries.length, - sha256: digestEntries(entries), - } -} - -async function hashArtifact(name, artifactPath) { - const stat = await fs.stat(artifactPath) - if (stat.isDirectory()) { - const directory = await hashDirectory(artifactPath) - return { - name, - path: artifactPath, - ...directory, - } - } - if (!stat.isFile()) { - throw new Error(`artifact is neither a file nor directory: ${artifactPath}`) - } - return { - name, - path: artifactPath, - kind: 'file', - bytes: stat.size, - sha256: await fileSha256(artifactPath), - } -} - -async function collectArtifacts(args) { - const liboliphaunt = optionalPath(args['--liboliphaunt']) - const postgresBin = optionalPath(args['--postgres-bin']) - const initdbBin = optionalPath(args['--initdb-bin']) - const perfRunner = optionalPath(args['--perf-runner']) - const candidates = [ - ['liboliphaunt-native', liboliphaunt], - ['postgres', postgresBin], - ['initdb', initdbBin], - ['oliphaunt-perf', perfRunner], - ] - - if (liboliphaunt) { - candidates.push(['embedded-modules', path.join(path.dirname(liboliphaunt), 'modules')]) - } - if (postgresBin) { - candidates.push(['native-postgres-install', path.dirname(path.dirname(postgresBin))]) - } - - const artifacts = [] - for (const [name, artifactPath] of candidates) { - if (!artifactPath) { - continue - } - try { - artifacts.push(await hashArtifact(name, artifactPath)) - } catch (error) { - if (error && error.code === 'ENOENT') { - artifacts.push({ - name, - path: artifactPath, - missing: true, - sha256: null, - }) - } else { - throw error - } - } - } - return artifacts -} - -function runGit(repoRoot, args) { - const result = spawnSync('git', args, { - cwd: repoRoot, - encoding: 'utf8', - stdio: ['ignore', 'pipe', 'ignore'], - }) - if (result.status !== 0) { - return null - } - return result.stdout.trim() -} - -function gitMetadata(repoRoot) { - const status = runGit(repoRoot, ['status', '--porcelain', '--untracked-files=no']) ?? '' - return { - root: repoRoot, - commit: runGit(repoRoot, ['rev-parse', 'HEAD']), - branch: runGit(repoRoot, ['rev-parse', '--abbrev-ref', 'HEAD']), - dirtyTracked: status.length > 0, - trackedStatusLineCount: status ? status.split('\n').length : 0, - } -} - -async function writeProvenance(args) { - const runDir = path.resolve(requireArg(args, '--run-dir')) - const repoRoot = path.resolve(args['--repo-root'] ?? process.cwd()) - const source = await collectSource(repoRoot) - const artifacts = await collectArtifacts(args) - const provenance = { - schema: 'oliphaunt.native-perf.provenance.v1', - generatedAt: new Date().toISOString(), - runId: args['--run-id'] ?? path.basename(runDir), - repo: gitMetadata(repoRoot), - environment: { - platform: process.platform, - arch: process.arch, - node: process.version, - osRelease: os.release(), - host: os.hostname(), - }, - benchmark: { - nativeEngines: stringListArg(args, '--native-engines'), - suites: stringListArg(args, '--suites'), - durability: args['--durability'] ?? null, - runtimeFootprint: args['--runtime-footprint'] ?? null, - startupGucs: stringListArg(args, '--startup-gucs'), - rttIterations: numberArg(args, '--rtt-iterations'), - rttRepeats: numberArg(args, '--rtt-repeats'), - preparedRows: numberArg(args, '--prepared-rows'), - preparedRepeats: numberArg(args, '--prepared-repeats'), - speedRepeats: numberArg(args, '--speed-repeats'), - backupRepeats: numberArg(args, '--backup-repeats'), - pgdataCopyMode: args['--pgdata-copy-mode'] ?? null, - environment: benchmarkEnvironment(args), - includes: { - sqlite: flagArg(args, '--run-sqlite'), - preparedUpdates: flagArg(args, '--run-prepared'), - }, - quality: { - releaseEvidence: flagArg(args, '--release-evidence'), - partialReport: flagArg(args, '--partial-report'), - diagnosticRun: flagArg(args, '--diagnostic-run'), - releaseMinimums: { - rttIterations: numberArg(args, '--release-min-rtt-iterations'), - rttRepeats: numberArg(args, '--release-min-rtt-repeats'), - preparedRows: numberArg(args, '--release-min-prepared-rows'), - preparedRepeats: numberArg(args, '--release-min-prepared-repeats'), - speedRepeats: numberArg(args, '--release-min-speed-repeats'), - backupRepeats: numberArg(args, '--release-min-backup-repeats'), - }, - }, - }, - source, - artifacts, - } - await fs.mkdir(runDir, { recursive: true }) - const file = path.join(runDir, 'provenance.json') - await fs.writeFile(file, `${JSON.stringify(provenance, null, 2)}\n`) - console.log(file) -} - -async function readJson(file) { - return JSON.parse(await fs.readFile(file, 'utf8')) -} - -async function readRequiredJson(runDir, relativeFile, failures) { - const file = path.join(runDir, relativeFile) - try { - return JSON.parse(await fs.readFile(file, 'utf8')) - } catch (error) { - if (error && error.code === 'ENOENT') { - failures.push(`missing benchmark output: ${relativeFile}`) - return null - } - failures.push(`invalid benchmark JSON output ${relativeFile}: ${error.message}`) - return null - } -} - -async function requireNonEmptyFile(runDir, relativeFile, failures) { - const file = path.join(runDir, relativeFile) - try { - const stat = await fs.stat(file) - if (!stat.isFile()) { - failures.push(`benchmark output is not a file: ${relativeFile}`) - } else if (stat.size === 0) { - failures.push(`benchmark output is empty: ${relativeFile}`) - } - } catch (error) { - if (error && error.code === 'ENOENT') { - failures.push(`missing benchmark output: ${relativeFile}`) - } else { - throw error - } - } -} - -function compareSource(expected, actual) { - const failures = [] - if (expected.sourceSetSha256 !== actual.sourceSetSha256) { - failures.push( - `source set changed: expected ${expected.sourceSetSha256}, got ${actual.sourceSetSha256}`, - ) - } - - const expectedByPath = new Map(expected.entries.map((entry) => [entry.path, entry])) - const actualByPath = new Map(actual.entries.map((entry) => [entry.path, entry])) - for (const [entryPath, entry] of expectedByPath) { - const current = actualByPath.get(entryPath) - if (!current) { - failures.push(`source missing: ${entryPath}`) - } else if (current.sha256 !== entry.sha256) { - failures.push(`source changed: ${entryPath}`) - } - } - for (const entryPath of actualByPath.keys()) { - if (!expectedByPath.has(entryPath)) { - failures.push(`source added: ${entryPath}`) - } - } - return failures -} - -async function compareArtifacts(expectedArtifacts) { - const failures = [] - const checks = [] - for (const expected of expectedArtifacts ?? []) { - if (expected.missing) { - checks.push(`artifact skipped because original was missing: ${expected.name}`) - continue - } - try { - const actual = await hashArtifact(expected.name, expected.path) - if (actual.sha256 === expected.sha256) { - checks.push(`artifact ok: ${expected.name}`) - } else { - failures.push( - `artifact changed: ${expected.name} expected ${expected.sha256}, got ${actual.sha256}`, - ) - } - } catch (error) { - if (error && error.code === 'ENOENT') { - failures.push(`artifact missing: ${expected.name} (${expected.path})`) - } else { - throw error - } - } - } - return { failures, checks } -} - -function findBenchmarkRun(report, suite, mode) { - if (!Array.isArray(report?.runs)) { - return null - } - return report.runs.find((run) => run.suite === suite && run.mode === mode) ?? null -} - -function validateBenchmarkRun(name, run, suite, mode, failures) { - if (!run) { - failures.push(`benchmark output ${name}.json is missing run suite=${suite} mode=${mode}`) - return - } - if (!Array.isArray(run.tests) || run.tests.length === 0) { - failures.push(`benchmark output ${name}.json run ${suite}/${mode} has no tests`) - return - } - for (const test of run.tests) { - const id = test?.id ?? '' - for (const field of ['elapsedMicros', 'p50Micros', 'p90Micros', 'p95Micros', 'p99Micros']) { - if (!finiteNumber(test[field])) { - failures.push(`benchmark output ${name}.json ${suite}/${mode}/${id} is missing ${field}`) - } - } - if (!finiteNumber(test.sampleCount) || test.sampleCount < 1) { - failures.push(`benchmark output ${name}.json ${suite}/${mode}/${id} has invalid sampleCount`) - } - } -} - -async function benchmarkReportFailures(runDir, name, expectedRuns) { - const failures = [] - const report = await readRequiredJson(runDir, `${name}.json`, failures) - await requireNonEmptyFile(runDir, `${name}.resource.txt`, failures) - if (!report) { - return failures - } - if (!Array.isArray(report.runs)) { - failures.push(`benchmark output ${name}.json does not contain a runs array`) - return failures - } - for (const expected of expectedRuns) { - validateBenchmarkRun( - name, - findBenchmarkRun(report, expected.suite, expected.mode), - expected.suite, - expected.mode, - failures, - ) - } - return failures -} - -function validatePreparedRun(name, run, mode, failures) { - if (!run) { - failures.push(`benchmark output ${name}.json is missing prepared-update mode=${mode}`) - return - } - if (!Array.isArray(run.tests) || run.tests.length === 0) { - failures.push(`benchmark output ${name}.json prepared mode ${mode} has no tests`) - return - } - for (const test of run.tests) { - const id = test?.id ?? '' - for (const field of [ - 'openMicros', - 'connectMicros', - 'setupMicros', - 'elapsedMicros', - 'operationCount', - 'averageMicros', - ]) { - if (!finiteNumber(test[field])) { - failures.push(`benchmark output ${name}.json ${mode}/${id} is missing ${field}`) - } - } - } -} - -async function preparedReportFailures(runDir, name, expectedModes) { - const failures = [] - const report = await readRequiredJson(runDir, `${name}.json`, failures) - await requireNonEmptyFile(runDir, `${name}.resource.txt`, failures) - if (!report) { - return failures - } - if (!Array.isArray(report.runs)) { - failures.push(`benchmark output ${name}.json does not contain a runs array`) - return failures - } - for (const mode of expectedModes) { - const run = report.runs.find((entry) => entry.mode === mode) ?? null - validatePreparedRun(name, run, mode, failures) - } - return failures -} - -async function artifactSizesFailures(runDir) { - const failures = [] - const report = await readRequiredJson(runDir, 'artifact-sizes.json', failures) - if (!report) { - return failures - } - if (!Array.isArray(report.artifacts)) { - failures.push('artifact-sizes.json does not contain an artifacts array') - return failures - } - const artifacts = new Map(report.artifacts.map((entry) => [entry.name, entry])) - for (const name of ['liboliphaunt-native', 'embedded-modules', 'native-postgres-install']) { - const artifact = artifacts.get(name) - if (!artifact) { - failures.push(`artifact-sizes.json is missing artifact ${name}`) - } else if (!finiteNumber(artifact.bytes) || artifact.bytes < 0) { - failures.push(`artifact-sizes.json artifact ${name} has invalid bytes`) - } - } - return failures -} - -function nativeBenchmarkMode(engine) { - return `native_liboliphaunt_${engine}` -} - -function nativeCaseName(engine, suite) { - const directNames = { - rtt: 'native-liboliphaunt-rtt', - speed: 'native-liboliphaunt-speed', - streaming: 'native-liboliphaunt-streaming', - prepared: 'native-liboliphaunt-prepared-direct', - backup: 'native-liboliphaunt-backup', - } - const prefixedNames = { - rtt: `native-liboliphaunt-${engine}-rtt`, - speed: `native-liboliphaunt-${engine}-speed`, - streaming: `native-liboliphaunt-${engine}-streaming`, - prepared: `native-liboliphaunt-prepared-${engine}`, - backup: `native-liboliphaunt-${engine}-backup`, - } - return engine === 'direct' ? directNames[suite] : prefixedNames[suite] -} - -function nativePreparedModes(engine) { - const mode = nativeBenchmarkMode(engine) - return [`${mode}_prepared`, `${mode}_pipelined_prepared`] -} - -async function benchmarkReleaseOutputFailures(runDir, provenance) { - const benchmark = provenance.benchmark ?? {} - const failures = [] - failures.push(...(await artifactSizesFailures(runDir))) - await requireNonEmptyFile(runDir, 'report.md', failures) - - for (const engine of ['direct', 'broker', 'server']) { - const mode = nativeBenchmarkMode(engine) - for (const suite of ['rtt', 'speed', 'streaming']) { - failures.push( - ...(await benchmarkReportFailures(runDir, nativeCaseName(engine, suite), [ - { suite, mode }, - ])), - ) - } - failures.push( - ...(await benchmarkReportFailures(runDir, nativeCaseName(engine, 'backup'), [ - { suite: 'backup-restore', mode }, - ])), - ) - failures.push( - ...(await preparedReportFailures( - runDir, - nativeCaseName(engine, 'prepared'), - nativePreparedModes(engine), - )), - ) - } - - failures.push( - ...(await benchmarkReportFailures(runDir, 'native-postgres-tokio-all', [ - { suite: 'rtt', mode: 'native_postgres' }, - { suite: 'speed', mode: 'native_postgres' }, - ])), - ) - failures.push( - ...(await benchmarkReportFailures(runDir, 'native-postgres-sqlx-all', [ - { suite: 'rtt', mode: 'native_postgres_sqlx' }, - { suite: 'speed', mode: 'native_postgres_sqlx' }, - ])), - ) - failures.push( - ...(await benchmarkReportFailures(runDir, 'native-postgres-streaming', [ - { suite: 'streaming', mode: 'native_postgres_raw' }, - ])), - ) - failures.push( - ...(await benchmarkReportFailures(runDir, 'sqlite-speed', [ - { suite: 'speed', mode: 'sqlite' }, - ])), - ) - failures.push( - ...(await benchmarkReportFailures(runDir, 'native-postgres-backup', [ - { suite: 'backup-restore', mode: 'native_postgres' }, - { suite: 'backup-restore', mode: 'native_postgres_physical' }, - ])), - ) - failures.push( - ...(await benchmarkReportFailures(runDir, 'sqlite-backup', [ - { suite: 'backup-restore', mode: 'sqlite' }, - ])), - ) - failures.push( - ...(await preparedReportFailures(runDir, 'native-postgres-prepared', [ - 'native_postgres_tokio_prepared', - 'native_postgres_tokio_pipelined_prepared', - ])), - ) - - for (let index = 1; index <= benchmark.rttRepeats; index += 1) { - const repeat = repeatIndex(index, benchmark.rttRepeats) - for (const engine of ['direct', 'broker', 'server']) { - failures.push( - ...(await benchmarkReportFailures( - runDir, - `repeats/${nativeCaseName(engine, 'rtt')}-${repeat}`, - [{ suite: 'rtt', mode: nativeBenchmarkMode(engine) }], - )), - ) - } - failures.push( - ...(await benchmarkReportFailures(runDir, `repeats/native-postgres-tokio-rtt-${repeat}`, [ - { suite: 'rtt', mode: 'native_postgres' }, - ])), - ) - } - - for (let index = 1; index <= benchmark.speedRepeats; index += 1) { - const repeat = repeatIndex(index, benchmark.speedRepeats) - for (const engine of ['direct', 'broker', 'server']) { - failures.push( - ...(await benchmarkReportFailures( - runDir, - `repeats/${nativeCaseName(engine, 'speed')}-${repeat}`, - [{ suite: 'speed', mode: nativeBenchmarkMode(engine) }], - )), - ) - } - failures.push( - ...(await benchmarkReportFailures(runDir, `repeats/native-postgres-tokio-speed-${repeat}`, [ - { suite: 'speed', mode: 'native_postgres' }, - ])), - ) - failures.push( - ...(await benchmarkReportFailures(runDir, `repeats/sqlite-speed-${repeat}`, [ - { suite: 'speed', mode: 'sqlite' }, - ])), - ) - } - - for (let index = 1; index <= benchmark.preparedRepeats; index += 1) { - const repeat = repeatIndex(index, benchmark.preparedRepeats) - failures.push( - ...(await preparedReportFailures(runDir, `repeats/native-postgres-prepared-${repeat}`, [ - 'native_postgres_tokio_prepared', - 'native_postgres_tokio_pipelined_prepared', - ])), - ) - for (const engine of ['direct', 'broker', 'server']) { - failures.push( - ...(await preparedReportFailures( - runDir, - `repeats/${nativeCaseName(engine, 'prepared')}-${repeat}`, - nativePreparedModes(engine), - )), - ) - } - } - - for (let index = 1; index <= benchmark.backupRepeats; index += 1) { - const repeat = repeatIndex(index, benchmark.backupRepeats) - for (const engine of ['direct', 'broker', 'server']) { - failures.push( - ...(await benchmarkReportFailures( - runDir, - `repeats/${nativeCaseName(engine, 'backup')}-${repeat}`, - [{ suite: 'backup-restore', mode: nativeBenchmarkMode(engine) }], - )), - ) - } - failures.push( - ...(await benchmarkReportFailures(runDir, `repeats/native-postgres-backup-${repeat}`, [ - { suite: 'backup-restore', mode: 'native_postgres' }, - { suite: 'backup-restore', mode: 'native_postgres_physical' }, - ])), - ) - failures.push( - ...(await benchmarkReportFailures(runDir, `repeats/sqlite-backup-${repeat}`, [ - { suite: 'backup-restore', mode: 'sqlite' }, - ])), - ) - } - - return failures -} - -function benchmarkReleaseFailures(provenance) { - const benchmark = provenance.benchmark ?? {} - const quality = benchmark.quality ?? {} - const minimums = quality.releaseMinimums ?? { - rttIterations: 100, - rttRepeats: 10, - preparedRows: 25000, - preparedRepeats: 10, - speedRepeats: 20, - backupRepeats: 10, - } - const failures = [] - - if (quality.releaseEvidence !== true) { - failures.push('benchmark provenance is not marked as releaseEvidence=true') - } - if (quality.partialReport !== false) { - failures.push('benchmark provenance is partial; release evidence must cover the default matrix') - } - if (quality.diagnosticRun !== false) { - failures.push('benchmark provenance is diagnostic; release evidence must come from the default matrix') - } - if (!sameStringList(benchmark.nativeEngines, ['direct', 'broker', 'server'])) { - failures.push( - `benchmark native engines are ${JSON.stringify(benchmark.nativeEngines)}, expected ["direct","broker","server"]`, - ) - } - if (!sameStringList(benchmark.suites, ['rtt', 'speed', 'streaming', 'prepared', 'backup'])) { - failures.push( - `benchmark suites are ${JSON.stringify(benchmark.suites)}, expected ["rtt","speed","streaming","prepared","backup"]`, - ) - } - if (benchmark.includes?.sqlite !== true) { - failures.push('benchmark provenance does not include the SQLite embedded control') - } - if (benchmark.includes?.preparedUpdates !== true) { - failures.push('benchmark provenance does not include prepared-update suites') - } - - const numericChecks = [ - ['rttIterations', 'RTT samples'], - ['rttRepeats', 'RTT repeats'], - ['preparedRows', 'prepared-update rows'], - ['preparedRepeats', 'prepared-update repeats'], - ['speedRepeats', 'speed repeats'], - ['backupRepeats', 'backup/restore repeats'], - ] - for (const [key, label] of numericChecks) { - const actual = benchmark[key] - const minimum = minimums[key] - if (!Number.isFinite(actual) || !Number.isFinite(minimum) || actual < minimum) { - failures.push(`${label} ${actual ?? 'missing'} is below release minimum ${minimum ?? 'missing'}`) - } - } - - return failures -} - -async function verifyProvenance(args) { - const runDir = path.resolve(requireArg(args, '--run-dir')) - const provenance = await readJson(path.join(runDir, 'provenance.json')) - const repoRoot = path.resolve(args['--repo-root'] ?? provenance.repo?.root ?? process.cwd()) - const source = await collectSource(repoRoot) - const sourceFailures = compareSource(provenance.source, source) - const artifactResult = await compareArtifacts(provenance.artifacts) - const requireReleaseEvidence = flagArg(args, '--require-release-evidence') === true - const releaseFailures = requireReleaseEvidence ? benchmarkReleaseFailures(provenance) : [] - const releaseOutputFailures = requireReleaseEvidence - ? await benchmarkReleaseOutputFailures(runDir, provenance) - : [] - const failures = [ - ...sourceFailures, - ...artifactResult.failures, - ...releaseFailures, - ...releaseOutputFailures, - ] - - console.log(`run: ${provenance.runId}`) - console.log(`generated: ${provenance.generatedAt}`) - console.log(`repo commit: ${provenance.repo?.commit ?? 'n/a'}`) - console.log(`source set: ${provenance.source?.sourceSetSha256 ?? 'n/a'}`) - console.log( - `release evidence: ${provenance.benchmark?.quality?.releaseEvidence === true ? 'yes' : 'no'}`, - ) - console.log( - `partial report: ${provenance.benchmark?.quality?.partialReport === true ? 'yes' : 'no'}`, - ) - console.log( - `diagnostic run: ${provenance.benchmark?.quality?.diagnosticRun === true ? 'yes' : 'no'}`, - ) - for (const check of artifactResult.checks) { - console.log(check) - } - - if (failures.length > 0) { - console.error('\nprovenance verification failed:') - for (const failure of failures.slice(0, 40)) { - console.error(`- ${failure}`) - } - if (failures.length > 40) { - console.error(`- ... ${failures.length - 40} more`) - } - process.exitCode = 1 - return - } - - console.log('provenance verification passed') -} - -const { command, args } = parseArgs(process.argv.slice(2)) - -try { - if (command === 'write') { - await writeProvenance(args) - } else if (command === 'verify') { - await verifyProvenance(args) - } else { - usage() - process.exitCode = 2 - } -} catch (error) { - console.error(error) - usage() - process.exitCode = 1 -} diff --git a/tools/perf/matrix/run_mobile_footprint_matrix.sh b/tools/perf/matrix/run_mobile_footprint_matrix.sh deleted file mode 100755 index 639218604..000000000 --- a/tools/perf/matrix/run_mobile_footprint_matrix.sh +++ /dev/null @@ -1,780 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd "$(dirname "$0")" && pwd)" -if repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)"; then - : -else - repo_root="$(cd "$script_dir/../../.." && pwd)" -fi -example_dir="$repo_root/examples/react-native-expo" - -platform="both" -plan_only=0 -include_invalid_wal_min=0 -quick=0 -keep_going=0 -summarize_only=0 -crash_recovery="${OLIPHAUNT_MOBILE_FOOTPRINT_CRASH_RECOVERY:-per-case}" -shared_buffers_raw="${OLIPHAUNT_MOBILE_FOOTPRINT_SHARED_BUFFERS:-all}" -wal_buffers_raw="${OLIPHAUNT_MOBILE_FOOTPRINT_WAL_BUFFERS:-all}" -min_wal_sizes_raw="${OLIPHAUNT_MOBILE_FOOTPRINT_MIN_WAL_SIZES:-all}" -max_wal_sizes_raw="${OLIPHAUNT_MOBILE_FOOTPRINT_MAX_WAL_SIZES:-all}" -run_id="${OLIPHAUNT_MOBILE_FOOTPRINT_RUN_ID:-$(date -u +%Y%m%dT%H%M%SZ)}" -output_dir="${OLIPHAUNT_MOBILE_FOOTPRINT_OUTPUT_DIR:-$repo_root/target/perf/mobile-footprint-$run_id}" -output_dir_explicit=0 -run_id_explicit=0 - -usage() { - cat >&2 <<'USAGE' -usage: tools/perf/matrix/run_mobile_footprint_matrix.sh [options] - -Options: - --platform android|ios|both Platform benchmark harness to run. Default: both. - --plan-only Print concrete benchmark commands without running them. - --include-invalid-wal-min Include min_wal_size combinations smaller than two WAL segments. - Use only for negative validation. - --run-id ID Stable run id for the report directory. - --output-dir DIR Matrix output directory. Default: target/perf/mobile-footprint-. - --keep-going Continue after a failed case and summarize failures. - --shared-buffers VALUES shared_buffers values to run: all or a comma-separated - subset of 8MB,16MB,32MB,64MB,128MB. - --wal-buffers VALUES wal_buffers values to run: all or a comma-separated - subset of -1,256kB,1MB,4MB. - --min-wal-size VALUES min_wal_size values to run: all or a comma-separated - subset of 8MB,16MB,32MB,80MB. - --max-wal-size VALUES max_wal_size values to run: all or a comma-separated - subset of 32MB,64MB,default. - --crash-recovery off|per-case Run process-death recovery evidence for each case. - Cases retain PostgreSQL's safe defaults alongside - the explicit tuning GUCs. Default: per-case. - --summarize-only Rebuild summary.json and summary.md from an existing output dir. - --quick Forward quick benchmark sizing to the Expo benchmark harness when - supported by local overrides. - -h, --help Show this help. - -The matrix sweeps explicit PostgreSQL settings: - shared_buffers: 8/16/32/64/128MB - wal_buffers: -1/256kB/1MB/4MB - min_wal_size: 8/16/32/80MB - WAL segment size: fixed by the qualified PostgreSQL seed (16MB) - max_wal_size: 32/64MB plus default -USAGE -} - -while [[ $# -gt 0 ]]; do - case "$1" in - --platform) - platform="${2:?--platform requires a value}" - shift 2 - ;; - --plan-only) - plan_only=1 - shift - ;; - --include-invalid-wal-min) - include_invalid_wal_min=1 - shift - ;; - --quick) - quick=1 - shift - ;; - --keep-going) - keep_going=1 - shift - ;; - --shared-buffers|--shared-buffer) - shared_buffers_raw="${2:?$1 requires a value}" - shift 2 - ;; - --wal-buffers|--wal-buffer) - wal_buffers_raw="${2:?$1 requires a value}" - shift 2 - ;; - --min-wal-size|--min-wal-sizes) - min_wal_sizes_raw="${2:?$1 requires a value}" - shift 2 - ;; - --max-wal-size|--max-wal-sizes) - max_wal_sizes_raw="${2:?$1 requires a value}" - shift 2 - ;; - --crash-recovery) - crash_recovery="${2:?--crash-recovery requires a value}" - shift 2 - ;; - --summarize-only) - summarize_only=1 - shift - ;; - --run-id) - run_id="${2:?--run-id requires a value}" - run_id_explicit=1 - if [[ "$output_dir_explicit" -eq 0 ]]; then - output_dir="${OLIPHAUNT_MOBILE_FOOTPRINT_OUTPUT_DIR:-$repo_root/target/perf/mobile-footprint-$run_id}" - fi - shift 2 - ;; - --output-dir) - output_dir="${2:?--output-dir requires a value}" - output_dir_explicit=1 - shift 2 - ;; - -h|--help) - usage - exit 0 - ;; - *) - echo "unknown argument: $1" >&2 - usage - exit 2 - ;; - esac -done - -case "$platform" in - android|ios|both) ;; - *) - echo "unknown platform: $platform" >&2 - exit 2 - ;; -esac -case "$crash_recovery" in - off|per-case) ;; - *) - echo "unknown --crash-recovery value: $crash_recovery" >&2 - exit 2 - ;; -esac -if [[ "$summarize_only" -eq 1 && "$output_dir_explicit" -eq 1 && "$run_id_explicit" -eq 0 ]]; then - output_basename="$(basename "$output_dir")" - run_id="${output_basename#mobile-footprint-}" -fi - -shared_buffers=(8MB 16MB 32MB 64MB 128MB) -wal_buffers=(-1 256kB 1MB 4MB) -min_wal_sizes=(8MB 16MB 32MB 80MB) -max_wal_sizes=(32MB 64MB default) - -value_in() { - local wanted="$1" - shift - local value - for value in "$@"; do - if [[ "$value" = "$wanted" ]]; then - return 0 - fi - done - return 1 -} - -print_axis_values() { - local label="$1" - local raw="$2" - shift 2 - local allowed=("$@") - local selected=() - local old_ifs values value existing - old_ifs="$IFS" - IFS="," - # shellcheck disable=SC2206 - values=($raw) - IFS="$old_ifs" - - if [[ "${#values[@]}" -eq 0 ]]; then - echo "$label list must not be empty" >&2 - exit 2 - fi - - for value in "${values[@]}"; do - value="$(printf '%s' "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" - [[ -n "$value" ]] || continue - if [[ "$value" = "all" ]]; then - selected=("${allowed[@]}") - break - fi - if ! value_in "$value" "${allowed[@]}"; then - echo "unknown $label value: $value" >&2 - echo "expected all or one of: ${allowed[*]}" >&2 - exit 2 - fi - if [[ "${#selected[@]}" -gt 0 ]]; then - for existing in "${selected[@]}"; do - if [[ "$existing" = "$value" ]]; then - value="" - break - fi - done - fi - [[ -n "$value" ]] && selected+=("$value") - done - - if [[ "${#selected[@]}" -eq 0 ]]; then - echo "$label list must not be empty" >&2 - exit 2 - fi - printf '%s\n' "${selected[@]}" -} - -shared_buffers=($(print_axis_values shared_buffers "$shared_buffers_raw" "${shared_buffers[@]}")) -wal_buffers=($(print_axis_values wal_buffers "$wal_buffers_raw" "${wal_buffers[@]}")) -min_wal_sizes=($(print_axis_values min_wal_size "$min_wal_sizes_raw" "${min_wal_sizes[@]}")) -max_wal_sizes=($(print_axis_values max_wal_size "$max_wal_sizes_raw" "${max_wal_sizes[@]}")) - -platforms=() -case "$platform" in - android) platforms=(android) ;; - ios) platforms=(ios) ;; - both) platforms=(android ios) ;; -esac - -size_mb() { - case "$1" in - *MB) printf '%s\n' "${1%MB}" ;; - default) printf '1048576\n' ;; - *) - echo "unsupported size value: $1" >&2 - exit 2 - ;; - esac -} - -is_valid_wal_min_size() { - local min_wal="$1" - [[ "$(size_mb "$min_wal")" -ge 32 ]] -} - -is_valid_wal_range() { - local min_wal="$1" - local max_wal="$2" - if [[ "$max_wal" = "default" ]]; then - return 0 - fi - [[ "$(size_mb "$max_wal")" -ge "$(size_mb "$min_wal")" ]] -} - -shell_quote() { - printf '%q' "$1" -} - -case_slug() { - printf '%s' "$1" | tr -c 'A-Za-z0-9._-' '_' -} - -write_case_metadata() { - local case_dir="$1" - local case_id="$2" - local target_platform="$3" - local shared="$4" - local wal="$5" - local min_wal="$6" - local max_wal="$7" - local startup_gucs="$8" - local status="$9" - CASE_ID="$case_id" \ - CASE_PLATFORM="$target_platform" \ - CASE_SHARED_BUFFERS="$shared" \ - CASE_WAL_BUFFERS="$wal" \ - CASE_MIN_WAL_SIZE="$min_wal" \ - CASE_MAX_WAL_SIZE="$max_wal" \ - CASE_STARTUP_GUCS="$startup_gucs" \ - CASE_STATUS="$status" \ - node <<'NODE' >"$case_dir/case.json" -const data = { - id: process.env.CASE_ID, - platform: process.env.CASE_PLATFORM, - startupGUCs: process.env.CASE_STARTUP_GUCS, - gucs: { - shared_buffers: process.env.CASE_SHARED_BUFFERS, - wal_buffers: process.env.CASE_WAL_BUFFERS, - min_wal_size: process.env.CASE_MIN_WAL_SIZE, - max_wal_size: process.env.CASE_MAX_WAL_SIZE, - }, - status: process.env.CASE_STATUS, -}; -process.stdout.write(`${JSON.stringify(data, null, 2)}\n`); -NODE -} - -summarize_matrix() { - MATRIX_OUTPUT_DIR="$output_dir" MATRIX_RUN_ID="$run_id" node <<'NODE' -const fs = require('node:fs'); -const path = require('node:path'); - -const outputDir = process.env.MATRIX_OUTPUT_DIR; -const casesDir = path.join(outputDir, 'cases'); -const rows = []; - -function readJson(file) { - try { - return JSON.parse(fs.readFileSync(file, 'utf8')); - } catch { - return null; - } -} - -function readText(file) { - try { - return fs.readFileSync(file, 'utf8'); - } catch { - return ''; - } -} - -function workload(report, id) { - return report?.workloads?.find(entry => entry.id === id); -} - -function latency(report, id, field) { - const value = workload(report, id)?.latency?.[field]; - return typeof value === 'number' ? value : null; -} - -function throughput(report, id) { - const value = workload(report, id)?.throughput?.rowsPerSecond; - return typeof value === 'number' ? value : null; -} - -function parseAndroidMemory(text) { - const pss = text.match(/TOTAL PSS:\s*([0-9]+)/); - const rss = text.match(/TOTAL RSS:\s*([0-9]+)/); - return { - androidPssKb: pss ? Number(pss[1]) : null, - androidRssKb: rss ? Number(rss[1]) : null, - }; -} - -function parseIosProcess(text) { - const [, line] = text.trim().split(/\r?\n/); - if (!line) { - return { iosResidentKb: null, iosCpuPercent: null }; - } - const [pid, rss, cpu] = line.split('\t'); - const rssValue = typeof rss === 'string' && rss.trim() !== '' ? Number(rss) : null; - const cpuValue = typeof cpu === 'string' && cpu.trim() !== '' ? Number(cpu) : null; - return { - iosResidentKb: pid && Number.isFinite(rssValue) ? rssValue : null, - iosCpuPercent: pid && Number.isFinite(cpuValue) ? cpuValue : null, - }; -} - -if (fs.existsSync(casesDir)) { - for (const name of fs.readdirSync(casesDir).sort()) { - const caseDir = path.join(casesDir, name); - const stat = fs.statSync(caseDir); - if (!stat.isDirectory()) { - continue; - } - const meta = readJson(path.join(caseDir, 'case.json')); - if (!meta) { - continue; - } - const report = readJson(path.join(caseDir, 'scratch', 'reports', 'benchmark-report.json')); - const crashReport = readJson(path.join(caseDir, 'crash-scratch', 'reports', 'crash-report.json')); - const androidMemory = parseAndroidMemory( - readText(path.join(caseDir, 'scratch', 'reports', 'benchmark-meminfo.txt')), - ); - const iosProcess = parseIosProcess( - readText(path.join(caseDir, 'scratch', 'reports', 'benchmark-process.tsv')), - ); - const packageSizes = readJson( - path.join(caseDir, 'scratch', 'reports', 'benchmark-package-sizes.json'), - ); - rows.push({ - ...meta, - reportPath: report ? path.relative(outputDir, path.join(caseDir, 'scratch', 'reports', 'benchmark-report.json')) : null, - benchmarkPreset: typeof report?.metadata?.benchmarkPreset === 'string' ? report.metadata.benchmarkPreset : null, - postgresSettings: report?.postgresSettings && typeof report.postgresSettings === 'object' - ? report.postgresSettings - : null, - openMs: typeof report?.openMs === 'number' ? report.openMs : null, - closeMs: typeof report?.closeMs === 'number' ? report.closeMs : null, - elapsedMs: typeof report?.elapsedMs === 'number' ? report.elapsedMs : null, - typedP50Ms: latency(report, 'typed_select_rtt', 'p50Ms'), - typedP90Ms: latency(report, 'typed_select_rtt', 'p90Ms'), - typedP95Ms: latency(report, 'typed_select_rtt', 'p95Ms'), - typedP99Ms: latency(report, 'typed_select_rtt', 'p99Ms'), - parameterizedP50Ms: latency(report, 'parameterized_select_rtt', 'p50Ms'), - parameterizedP90Ms: latency(report, 'parameterized_select_rtt', 'p90Ms'), - parameterizedP95Ms: latency(report, 'parameterized_select_rtt', 'p95Ms'), - parameterizedP99Ms: latency(report, 'parameterized_select_rtt', 'p99Ms'), - backgroundCheckpointP50Ms: latency(report, 'background_checkpoint', 'p50Ms'), - backgroundCheckpointP90Ms: latency(report, 'background_checkpoint', 'p90Ms'), - backgroundCheckpointP95Ms: latency(report, 'background_checkpoint', 'p95Ms'), - backgroundCheckpointP99Ms: latency(report, 'background_checkpoint', 'p99Ms'), - sqliteOpenMs: typeof report?.sqliteBenchmark?.openMs === 'number' ? report.sqliteBenchmark.openMs : null, - sqliteSimpleP50Ms: latency(report?.sqliteBenchmark, 'sqlite_simple_select_rtt', 'p50Ms'), - sqliteSimpleP90Ms: latency(report?.sqliteBenchmark, 'sqlite_simple_select_rtt', 'p90Ms'), - sqliteSimpleP95Ms: latency(report?.sqliteBenchmark, 'sqlite_simple_select_rtt', 'p95Ms'), - sqliteSimpleP99Ms: latency(report?.sqliteBenchmark, 'sqlite_simple_select_rtt', 'p99Ms'), - sqliteParameterizedP50Ms: latency(report?.sqliteBenchmark, 'sqlite_parameterized_select_rtt', 'p50Ms'), - sqliteParameterizedP90Ms: latency(report?.sqliteBenchmark, 'sqlite_parameterized_select_rtt', 'p90Ms'), - sqliteParameterizedP95Ms: latency(report?.sqliteBenchmark, 'sqlite_parameterized_select_rtt', 'p95Ms'), - sqliteParameterizedP99Ms: latency(report?.sqliteBenchmark, 'sqlite_parameterized_select_rtt', 'p99Ms'), - sqliteLookupP50Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_lookup', 'p50Ms'), - sqliteLookupP90Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_lookup', 'p90Ms'), - sqliteLookupP95Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_lookup', 'p95Ms'), - sqliteLookupP99Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_lookup', 'p99Ms'), - sqliteAggregateP50Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_aggregate', 'p50Ms'), - sqliteAggregateP90Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_aggregate', 'p90Ms'), - sqliteAggregateP95Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_aggregate', 'p95Ms'), - sqliteAggregateP99Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_aggregate', 'p99Ms'), - sqliteUpdateP50Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_update', 'p50Ms'), - sqliteUpdateP90Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_update', 'p90Ms'), - sqliteUpdateP95Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_update', 'p95Ms'), - sqliteUpdateP99Ms: latency(report?.sqliteBenchmark, 'sqlite_indexed_update', 'p99Ms'), - sqliteCheckpointP50Ms: latency(report?.sqliteBenchmark, 'sqlite_wal_checkpoint', 'p50Ms'), - sqliteCheckpointP90Ms: latency(report?.sqliteBenchmark, 'sqlite_wal_checkpoint', 'p90Ms'), - sqliteCheckpointP95Ms: latency(report?.sqliteBenchmark, 'sqlite_wal_checkpoint', 'p95Ms'), - sqliteCheckpointP99Ms: latency(report?.sqliteBenchmark, 'sqlite_wal_checkpoint', 'p99Ms'), - sqliteLargeResultP50Ms: latency(report?.sqliteBenchmark, 'sqlite_large_result', 'p50Ms'), - sqliteLargeResultP90Ms: latency(report?.sqliteBenchmark, 'sqlite_large_result', 'p90Ms'), - sqliteLargeResultP95Ms: latency(report?.sqliteBenchmark, 'sqlite_large_result', 'p95Ms'), - sqliteLargeResultP99Ms: latency(report?.sqliteBenchmark, 'sqlite_large_result', 'p99Ms'), - sqliteInsertRowsPerSecond: throughput(report?.sqliteBenchmark, 'sqlite_transaction_insert'), - crashRecoveryElapsedMs: typeof crashReport?.elapsedMs === 'number' ? crashReport.elapsedMs : null, - crashRecoveryOpenMs: typeof crashReport?.openMs === 'number' ? crashReport.openMs : null, - insertRowsPerSecond: throughput(report, 'transaction_insert'), - sqliteDurability: typeof report?.sqliteBenchmark?.durability === 'string' - ? report.sqliteBenchmark.durability - : null, - androidApkBytes: typeof packageSizes?.apkBytes === 'number' ? packageSizes.apkBytes : null, - iosAppBytes: typeof packageSizes?.iosAppBytes === 'number' ? packageSizes.iosAppBytes : null, - rnPackageBytes: typeof packageSizes?.rnPackageBytes === 'number' ? packageSizes.rnPackageBytes : null, - jsTimerTicks: typeof report?.jsTimerTicks === 'number' ? report.jsTimerTicks : null, - androidPssKb: androidMemory.androidPssKb, - androidRssKb: androidMemory.androidRssKb, - iosResidentKb: iosProcess.iosResidentKb, - iosCpuPercent: iosProcess.iosCpuPercent, - }); - } -} - -const summary = { - schemaVersion: 1, - runId: process.env.MATRIX_RUN_ID, - outputDir, - generatedAt: new Date().toISOString(), - caseCount: rows.length, - passed: rows.filter(row => row.status === 'passed').length, - failed: rows.filter(row => row.status === 'failed').length, - rows, -}; -fs.mkdirSync(outputDir, { recursive: true }); -fs.writeFileSync(path.join(outputDir, 'summary.json'), `${JSON.stringify(summary, null, 2)}\n`); - -function fmt(value, digits = 2) { - return typeof value === 'number' && Number.isFinite(value) ? value.toFixed(digits) : ''; -} - -function fmtMb(kb) { - return typeof kb === 'number' && Number.isFinite(kb) ? (kb / 1024).toFixed(1) : ''; -} - -function fmtBytesMb(bytes) { - return typeof bytes === 'number' && Number.isFinite(bytes) ? (bytes / 1024 / 1024).toFixed(1) : ''; -} - -function effectiveGucSummary(settings) { - if (!settings || typeof settings !== 'object') { - return ''; - } - return [ - 'shared_buffers', - 'wal_buffers', - 'wal_segment_size', - 'min_wal_size', - 'max_wal_size', - 'synchronous_commit', - 'fsync', - 'full_page_writes', - 'io_method', - ] - .map(name => { - const value = settings[name]; - return typeof value === 'string' ? `${name}=${value}` : null; - }) - .filter(Boolean) - .join(', '); -} - -const lines = []; -lines.push(`# Mobile Footprint Matrix ${summary.runId}`); -lines.push(''); -lines.push(`- Generated: ${summary.generatedAt}`); -lines.push(`- Cases: ${summary.caseCount}; passed: ${summary.passed}; failed: ${summary.failed}`); -lines.push(''); -const summaryColumns = [ - 'Case', 'Platform', 'Benchmark preset', - 'shared_buffers', 'wal_buffers', 'min_wal_size', 'max_wal_size', - 'Effective GUCs', 'Open ms', - 'Typed p50 ms', 'Typed p90 ms', 'Typed p95 ms', 'Typed p99 ms', - 'Param p50 ms', 'Param p90 ms', 'Param p95 ms', 'Param p99 ms', - 'Background checkpoint p50 ms', 'Background checkpoint p90 ms', - 'Background checkpoint p95 ms', 'Background checkpoint p99 ms', - 'Crash recovery ms', 'Crash recovery open ms', - 'Insert rows/s', - 'SQLite open ms', 'SQLite simple p50 ms', 'SQLite simple p90 ms', - 'SQLite simple p95 ms', 'SQLite simple p99 ms', 'SQLite param p50 ms', - 'SQLite param p90 ms', 'SQLite param p95 ms', 'SQLite param p99 ms', - 'SQLite lookup p50 ms', 'SQLite lookup p90 ms', 'SQLite lookup p95 ms', - 'SQLite lookup p99 ms', 'SQLite aggregate p50 ms', 'SQLite aggregate p90 ms', - 'SQLite aggregate p95 ms', 'SQLite aggregate p99 ms', 'SQLite update p50 ms', - 'SQLite update p90 ms', 'SQLite update p95 ms', 'SQLite update p99 ms', - 'SQLite checkpoint p50 ms', 'SQLite checkpoint p90 ms', - 'SQLite checkpoint p95 ms', 'SQLite checkpoint p99 ms', - 'SQLite large result p50 ms', 'SQLite large result p90 ms', - 'SQLite large result p95 ms', 'SQLite large result p99 ms', - 'SQLite insert rows/s', 'SQLite durability', 'Android APK MB', - 'iOS app MB', 'RN package KB', 'Android PSS MB', 'Android RSS MB', - 'iOS RSS MB', 'iOS CPU %', 'Report', -]; - -function markdownRow(cells) { - return `| ${cells.join(' | ')} |`; -} - -lines.push(markdownRow(summaryColumns)); -lines.push(markdownRow(summaryColumns.map(() => '---'))); -for (const row of rows) { - lines.push(markdownRow([ - row.status === 'passed' ? row.id : `${row.id} (${row.status})`, - row.platform, - row.benchmarkPreset ?? '', - row.gucs?.shared_buffers ?? '', - row.gucs?.wal_buffers ?? '', - row.gucs?.min_wal_size ?? '', - row.gucs?.max_wal_size ?? '', - effectiveGucSummary(row.postgresSettings), - fmt(row.openMs), - fmt(row.typedP50Ms), - fmt(row.typedP90Ms), - fmt(row.typedP95Ms), - fmt(row.typedP99Ms), - fmt(row.parameterizedP50Ms), - fmt(row.parameterizedP90Ms), - fmt(row.parameterizedP95Ms), - fmt(row.parameterizedP99Ms), - fmt(row.backgroundCheckpointP50Ms), - fmt(row.backgroundCheckpointP90Ms), - fmt(row.backgroundCheckpointP95Ms), - fmt(row.backgroundCheckpointP99Ms), - fmt(row.crashRecoveryElapsedMs), - fmt(row.crashRecoveryOpenMs), - fmt(row.insertRowsPerSecond, 0), - fmt(row.sqliteOpenMs), - fmt(row.sqliteSimpleP50Ms), - fmt(row.sqliteSimpleP90Ms), - fmt(row.sqliteSimpleP95Ms), - fmt(row.sqliteSimpleP99Ms), - fmt(row.sqliteParameterizedP50Ms), - fmt(row.sqliteParameterizedP90Ms), - fmt(row.sqliteParameterizedP95Ms), - fmt(row.sqliteParameterizedP99Ms), - fmt(row.sqliteLookupP50Ms), - fmt(row.sqliteLookupP90Ms), - fmt(row.sqliteLookupP95Ms), - fmt(row.sqliteLookupP99Ms), - fmt(row.sqliteAggregateP50Ms), - fmt(row.sqliteAggregateP90Ms), - fmt(row.sqliteAggregateP95Ms), - fmt(row.sqliteAggregateP99Ms), - fmt(row.sqliteUpdateP50Ms), - fmt(row.sqliteUpdateP90Ms), - fmt(row.sqliteUpdateP95Ms), - fmt(row.sqliteUpdateP99Ms), - fmt(row.sqliteCheckpointP50Ms), - fmt(row.sqliteCheckpointP90Ms), - fmt(row.sqliteCheckpointP95Ms), - fmt(row.sqliteCheckpointP99Ms), - fmt(row.sqliteLargeResultP50Ms), - fmt(row.sqliteLargeResultP90Ms), - fmt(row.sqliteLargeResultP95Ms), - fmt(row.sqliteLargeResultP99Ms), - fmt(row.sqliteInsertRowsPerSecond, 0), - row.sqliteDurability ?? '', - fmtBytesMb(row.androidApkBytes), - fmtBytesMb(row.iosAppBytes), - typeof row.rnPackageBytes === 'number' && Number.isFinite(row.rnPackageBytes) - ? (row.rnPackageBytes / 1024).toFixed(1) - : '', - fmtMb(row.androidPssKb), - fmtMb(row.androidRssKb), - fmtMb(row.iosResidentKb), - fmt(row.iosCpuPercent), - row.reportPath ? `\`${row.reportPath}\`` : '', - ])); -} -lines.push(''); -fs.writeFileSync(path.join(outputDir, 'summary.md'), `${lines.join('\n')}\n`); -NODE -} - -print_or_run() { - local target_platform="$1" - local shared="$2" - local wal="$3" - local min_wal="$4" - local max_wal="$5" - local startup_gucs="shared_buffers=$shared,wal_buffers=$wal,min_wal_size=$min_wal" - if [[ "$max_wal" != "default" ]]; then - startup_gucs="$startup_gucs,max_wal_size=$max_wal" - fi - local script="bench:$target_platform" - local crash_script="crash:$target_platform" - local raw_case_id="$target_platform-shared-$shared-wal-$wal-minwal-$min_wal-maxwal-$max_wal" - local case_id - case_id="$(case_slug "$raw_case_id")" - local case_dir="$output_dir/cases/$case_id" - local scratch="$case_dir/scratch" - local crash_scratch="$case_dir/crash-scratch" - local benchmark_preset=full - if [[ "$quick" -eq 1 ]]; then - benchmark_preset=quick - fi - local base_prefix=( - env - "OLIPHAUNT_EXPO_MOBILE_STARTUP_GUCS=$startup_gucs" - "OLIPHAUNT_EXPO_MOBILE_BENCHMARK_PRESET=$benchmark_preset" - ) - local prefix=("${base_prefix[@]}") - local crash_prefix=("${base_prefix[@]}") - local run_crash=0 - [[ "$crash_recovery" = "per-case" ]] && run_crash=1 - - case "$target_platform" in - android) prefix+=("OLIPHAUNT_EXPO_ANDROID_SCRATCH=$scratch") ;; - ios) prefix+=("OLIPHAUNT_EXPO_IOS_SCRATCH=$scratch") ;; - esac - if [[ "$run_crash" -eq 1 ]]; then - case "$target_platform" in - android) crash_prefix+=("OLIPHAUNT_EXPO_ANDROID_SCRATCH=$crash_scratch") ;; - ios) crash_prefix+=("OLIPHAUNT_EXPO_IOS_SCRATCH=$crash_scratch") ;; - esac - fi - - if [[ "$quick" -eq 1 ]]; then - case "$target_platform" in - android) - prefix+=("OLIPHAUNT_EXPO_ANDROID_TIMEOUT_SECONDS=240") - crash_prefix+=("OLIPHAUNT_EXPO_ANDROID_TIMEOUT_SECONDS=240") - ;; - ios) - prefix+=("OLIPHAUNT_EXPO_IOS_TIMEOUT_SECONDS=240") - crash_prefix+=("OLIPHAUNT_EXPO_IOS_TIMEOUT_SECONDS=240") - ;; - esac - fi - - if [[ "$plan_only" -eq 1 ]]; then - printf 'case platform=%s shared_buffers=%s wal_buffers=%s min_wal_size=%s max_wal_size=%s\n' \ - "$target_platform" "$shared" "$wal" "$min_wal" "$max_wal" - printf 'benchmarkPreset=%s\n' "$benchmark_preset" - printf 'caseId=%s\n' "$case_id" - printf 'caseOutputDir=%s\n' "$case_dir" - printf 'command=' - for part in "${prefix[@]}"; do - printf '%s ' "$(shell_quote "$part")" - done - printf 'pnpm --dir %s run %s\n' "$(shell_quote "$example_dir")" "$(shell_quote "$script")" - if [[ "$run_crash" -eq 1 ]]; then - printf 'crashCommand=' - for part in "${crash_prefix[@]}"; do - printf '%s ' "$(shell_quote "$part")" - done - printf 'pnpm --dir %s run %s\n' "$(shell_quote "$example_dir")" "$(shell_quote "$crash_script")" - fi - return - fi - - mkdir -p "$case_dir" - write_case_metadata \ - "$case_dir" \ - "$case_id" \ - "$target_platform" \ - "$shared" \ - "$wal" \ - "$min_wal" \ - "$max_wal" \ - "$startup_gucs" \ - "running" - - echo "==> mobile footprint case $case_id" - set +e - "${prefix[@]}" pnpm --dir "$example_dir" run "$script" 2>&1 | tee "$case_dir/harness.log" - local status="${PIPESTATUS[0]}" - if [[ "$status" -eq 0 && "$run_crash" -eq 1 ]]; then - "${crash_prefix[@]}" pnpm --dir "$example_dir" run "$crash_script" 2>&1 | tee "$case_dir/crash-harness.log" - status="${PIPESTATUS[0]}" - fi - set -e - if [[ "$status" -eq 0 ]]; then - write_case_metadata \ - "$case_dir" \ - "$case_id" \ - "$target_platform" \ - "$shared" \ - "$wal" \ - "$min_wal" \ - "$max_wal" \ - "$startup_gucs" \ - "passed" - else - write_case_metadata \ - "$case_dir" \ - "$case_id" \ - "$target_platform" \ - "$shared" \ - "$wal" \ - "$min_wal" \ - "$max_wal" \ - "$startup_gucs" \ - "failed" - if [[ "$keep_going" -ne 1 ]]; then - summarize_matrix - exit "$status" - fi - fi -} - -if [[ "$summarize_only" -eq 1 ]]; then - summarize_matrix - printf 'mobile footprint summary: %s\n' "$output_dir/summary.md" - exit 0 -fi - -planned=0 -skipped=0 -skipped_wal_range=0 -for target_platform in "${platforms[@]}"; do - for shared in "${shared_buffers[@]}"; do - for wal in "${wal_buffers[@]}"; do - for min_wal in "${min_wal_sizes[@]}"; do - for max_wal in "${max_wal_sizes[@]}"; do - if ! is_valid_wal_min_size "$min_wal" && [[ "$include_invalid_wal_min" -ne 1 ]]; then - skipped=$((skipped + 1)) - continue - fi - if ! is_valid_wal_range "$min_wal" "$max_wal"; then - skipped_wal_range=$((skipped_wal_range + 1)) - continue - fi - planned=$((planned + 1)) - print_or_run "$target_platform" "$shared" "$wal" "$min_wal" "$max_wal" - done - done - done - done -done - -if [[ "$plan_only" -eq 1 ]]; then - printf 'runId=%s\n' "$run_id" - printf 'outputDir=%s\n' "$output_dir" - printf 'planned=%s\n' "$planned" - printf 'skippedInvalidMinWalSize=%s\n' "$skipped" - printf 'skippedInvalidWalRange=%s\n' "$skipped_wal_range" -else - summarize_matrix - printf 'mobile footprint summary: %s\n' "$output_dir/summary.md" -fi diff --git a/tools/perf/matrix/run_native_oliphaunt_matrix.sh b/tools/perf/matrix/run_native_oliphaunt_matrix.sh deleted file mode 100755 index d88396ffb..000000000 --- a/tools/perf/matrix/run_native_oliphaunt_matrix.sh +++ /dev/null @@ -1,782 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -if REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then - : -else - REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" -fi -TARGET_ROOT="$REPO_ROOT/target/perf" - -RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)" -RELEASE_MIN_RTT_ITERATIONS=100 -RELEASE_MIN_RTT_REPEATS=10 -RELEASE_MIN_PREPARED_ROWS=25000 -RELEASE_MIN_PREPARED_REPEATS=10 -RELEASE_MIN_SPEED_REPEATS=20 -RELEASE_MIN_BACKUP_REPEATS=10 -RTT_ITERATIONS="$RELEASE_MIN_RTT_ITERATIONS" -RTT_REPEATS="$RELEASE_MIN_RTT_REPEATS" -PREPARED_ROWS="$RELEASE_MIN_PREPARED_ROWS" -PREPARED_REPEATS="$RELEASE_MIN_PREPARED_REPEATS" -SPEED_REPEATS="$RELEASE_MIN_SPEED_REPEATS" -BACKUP_REPEATS="$RELEASE_MIN_BACKUP_REPEATS" -RUN_SQLITE=1 -RUN_PREPARED=1 -BUILD_PERF_RUNNER="${OLIPHAUNT_PERF_BUILD_RUNNER:-1}" -PLAN_ONLY=0 -DURABILITY="${OLIPHAUNT_PERF_DURABILITY:-safe}" -RUNTIME_FOOTPRINT="${OLIPHAUNT_PERF_RUNTIME_FOOTPRINT:-throughput}" -PGDATA_COPY_MODE="${OLIPHAUNT_PGDATA_COPY_MODE:-copy}" -NATIVE_ENGINES="${OLIPHAUNT_PERF_ENGINES:-direct,broker,server}" -SUITES="${OLIPHAUNT_PERF_SUITES:-rtt,speed,streaming,prepared,backup}" -STARTUP_GUCS=() -if [[ -n "${OLIPHAUNT_PERF_STARTUP_GUCS:-}" ]]; then - IFS=',' read -r -a STARTUP_GUCS <<< "${OLIPHAUNT_PERF_STARTUP_GUCS//[[:space:]]/}" -fi - -usage() { - cat >&2 <<'USAGE' -usage: tools/perf/matrix/run_native_oliphaunt_matrix.sh [options] - -Options: - --run-id ID Output run id. Defaults to current UTC timestamp. - --rtt-iterations N RTT samples per case. Default: 100. - --rtt-repeats N Fresh-process RTT repeats for release-grade gating. Default: 10. - --prepared-rows N Prepared-update rows. Default: 25000. - --prepared-repeats N Fresh-process prepared-update repeats for p90/p95. Default: 10. - --speed-repeats N Fresh-process speed-suite repeats for p50/p90/p95. Default: 20. - --backup-repeats N Fresh-process backup/restore repeats for p50/p90/p95. Default: 10. - --durability PROFILE Native durability profile: safe, balanced, or fast-dev. Default: safe. - --runtime-footprint PROFILE - Native runtime footprint: throughput, balanced-mobile, or small-mobile. - Default: throughput. - --startup-guc NAME=VALUE - PostgreSQL startup GUC override. Repeatable; applied after footprint - and durability defaults. - --pgdata-copy-mode MODE Cluster-seed hydration: copy or prefer-clone. Default: copy. - --engines LIST Comma-separated native engines: direct, broker, server, or all. - Default: direct,broker,server. - --suite LIST Alias for --suites. - --suites LIST Comma-separated suites: rtt, speed, streaming, prepared, backup, or all. - Default: rtt,speed,streaming,prepared,backup. - --quick Fast plumbing preset: 10 RTT samples, one repeat, 1000 prepared rows. - --plan-only Print the native-only benchmark plan and exit without artifact checks. - --skip-sqlite Skip SQLite embedded control. - --skip-prepared Skip prepared-update suites. - --skip-build Reuse target/release/oliphaunt-perf without rebuilding it. - -h, --help Show this help. - -Environment: - LIBOLIPHAUNT_PATH Required path to liboliphaunt.dylib/.so. - OLIPHAUNT_POSTGRES Path to matching postgres binary. - OLIPHAUNT_INITDB Path to matching initdb binary. - OLIPHAUNT_PERF_STARTUP_GUCS - Comma-separated NAME=VALUE startup GUC overrides. -USAGE -} - -while [[ $# -gt 0 ]]; do - case "$1" in - --run-id) - RUN_ID="${2:?--run-id requires a value}" - shift 2 - ;; - --rtt-iterations) - RTT_ITERATIONS="${2:?--rtt-iterations requires a value}" - shift 2 - ;; - --rtt-repeats) - RTT_REPEATS="${2:?--rtt-repeats requires a value}" - shift 2 - ;; - --prepared-rows) - PREPARED_ROWS="${2:?--prepared-rows requires a value}" - shift 2 - ;; - --prepared-repeats) - PREPARED_REPEATS="${2:?--prepared-repeats requires a value}" - shift 2 - ;; - --speed-repeats) - SPEED_REPEATS="${2:?--speed-repeats requires a value}" - shift 2 - ;; - --backup-repeats) - BACKUP_REPEATS="${2:?--backup-repeats requires a value}" - shift 2 - ;; - --durability) - DURABILITY="${2:?--durability requires a value}" - shift 2 - ;; - --runtime-footprint) - RUNTIME_FOOTPRINT="${2:?--runtime-footprint requires a value}" - shift 2 - ;; - --startup-guc) - STARTUP_GUCS+=("${2:?--startup-guc requires a value}") - shift 2 - ;; - --pgdata-copy-mode) - PGDATA_COPY_MODE="${2:?--pgdata-copy-mode requires a value}" - shift 2 - ;; - --engines) - NATIVE_ENGINES="${2:?--engines requires a value}" - shift 2 - ;; - --suite|--suites) - SUITES="${2:?--suites requires a value}" - shift 2 - ;; - --quick) - RTT_ITERATIONS=10 - RTT_REPEATS=1 - PREPARED_ROWS=1000 - PREPARED_REPEATS=1 - SPEED_REPEATS=1 - BACKUP_REPEATS=1 - shift - ;; - --plan-only) - PLAN_ONLY=1 - shift - ;; - --skip-sqlite) - RUN_SQLITE=0 - shift - ;; - --skip-prepared) - RUN_PREPARED=0 - shift - ;; - --skip-build) - BUILD_PERF_RUNNER=0 - shift - ;; - -h|--help) - usage - exit 0 - ;; - *) - echo "unknown argument: $1" >&2 - usage - exit 2 - ;; - esac -done - -csv_has() { - local csv="$1" - local value="$2" - [[ ",$csv," == *",$value,"* ]] -} - -normalize_csv_arg() { - local name="$1" - local raw="${2//[[:space:]]/}" - local allowed="$3" - local default_value="$4" - local item - local output="" - - if [[ -z "$raw" || "$raw" == "all" ]]; then - printf '%s\n' "$default_value" - return - fi - - IFS=',' read -r -a items <<< "$raw" - for item in "${items[@]}"; do - if [[ -z "$item" ]]; then - echo "$name must not contain empty entries" >&2 - exit 2 - fi - if [[ "$item" == "all" ]]; then - printf '%s\n' "$default_value" - return - fi - if ! csv_has "$allowed" "$item"; then - echo "unknown $name value: $item" >&2 - exit 2 - fi - if ! csv_has "$output" "$item"; then - output="${output:+$output,}$item" - fi - done - - if [[ -z "$output" ]]; then - echo "$name must not be empty" >&2 - exit 2 - fi - printf '%s\n' "$output" -} - -NATIVE_ENGINES="$(normalize_csv_arg "--engines" "$NATIVE_ENGINES" "direct,broker,server" "direct,broker,server")" -SUITES="$(normalize_csv_arg "--suites" "$SUITES" "rtt,speed,streaming,prepared,backup" "rtt,speed,streaming,prepared,backup")" -if ! csv_has "$SUITES" speed; then - RUN_SQLITE=0 -fi -if ! csv_has "$SUITES" prepared; then - RUN_PREPARED=0 -fi - -if [[ "$RTT_ITERATIONS" -le 0 || "$RTT_REPEATS" -le 0 || "$PREPARED_ROWS" -le 0 || "$PREPARED_REPEATS" -le 0 || "$SPEED_REPEATS" -le 0 || "$BACKUP_REPEATS" -le 0 ]]; then - echo "iteration, row, and repeat counts must be positive" >&2 - exit 2 -fi - -case "$DURABILITY" in - safe|balanced|fast-dev) ;; - *) - echo "unknown durability profile: $DURABILITY" >&2 - exit 2 - ;; -esac - -case "$RUNTIME_FOOTPRINT" in - throughput|balanced-mobile|small-mobile) ;; - *) - echo "unknown runtime footprint profile: $RUNTIME_FOOTPRINT" >&2 - exit 2 - ;; -esac - -STARTUP_GUC_COUNT="${#STARTUP_GUCS[@]}" -if [[ "$STARTUP_GUC_COUNT" -gt 0 ]]; then - for startup_guc in "${STARTUP_GUCS[@]}"; do - case "$startup_guc" in - *=?*) ;; - *) - echo "startup GUC must be formatted as name=value: $startup_guc" >&2 - exit 2 - ;; - esac - done -fi - -TUNING_ARGS=(--runtime-footprint "$RUNTIME_FOOTPRINT") -if [[ "$STARTUP_GUC_COUNT" -gt 0 ]]; then - for startup_guc in "${STARTUP_GUCS[@]}"; do - TUNING_ARGS+=(--startup-guc "$startup_guc") - done -fi - -join_csv() { - local IFS=, - printf '%s\n' "$*" -} -STARTUP_GUCS_CSV="" -if [[ "$STARTUP_GUC_COUNT" -gt 0 ]]; then - STARTUP_GUCS_CSV="$(join_csv "${STARTUP_GUCS[@]}")" -fi - -case "$PGDATA_COPY_MODE" in - prefer-clone|clone|copy|byte-copy|byte_copy|physical-copy|physical_copy) ;; - *) - echo "unknown PGDATA copy mode: $PGDATA_COPY_MODE" >&2 - exit 2 - ;; -esac -export OLIPHAUNT_PGDATA_COPY_MODE="$PGDATA_COPY_MODE" - -PARTIAL_REPORT=0 -if [[ "$NATIVE_ENGINES" != "direct,broker,server" || "$SUITES" != "rtt,speed,streaming,prepared,backup" || "$RUN_SQLITE" -ne 1 || "$RUN_PREPARED" -ne 1 ]]; then - PARTIAL_REPORT=1 -fi - -RELEASE_EVIDENCE=0 -if [[ "$PARTIAL_REPORT" -eq 0 && - "$RTT_ITERATIONS" -ge "$RELEASE_MIN_RTT_ITERATIONS" && - "$RTT_REPEATS" -ge "$RELEASE_MIN_RTT_REPEATS" && - "$PREPARED_ROWS" -ge "$RELEASE_MIN_PREPARED_ROWS" && - "$PREPARED_REPEATS" -ge "$RELEASE_MIN_PREPARED_REPEATS" && - "$SPEED_REPEATS" -ge "$RELEASE_MIN_SPEED_REPEATS" && - "$BACKUP_REPEATS" -ge "$RELEASE_MIN_BACKUP_REPEATS" ]]; then - RELEASE_EVIDENCE=1 -fi - -DIAGNOSTIC_RUN=0 -if [[ "$RELEASE_EVIDENCE" -ne 1 ]]; then - DIAGNOSTIC_RUN=1 -fi - -native_case_name() { - local engine="$1" - local suite="$2" - case "$engine:$suite" in - direct:rtt) echo "native-liboliphaunt-rtt" ;; - direct:speed) echo "native-liboliphaunt-speed" ;; - direct:streaming) echo "native-liboliphaunt-streaming" ;; - direct:prepared) echo "native-liboliphaunt-prepared-direct" ;; - direct:backup) echo "native-liboliphaunt-backup" ;; - broker:rtt) echo "native-liboliphaunt-broker-rtt" ;; - broker:speed) echo "native-liboliphaunt-broker-speed" ;; - broker:streaming) echo "native-liboliphaunt-broker-streaming" ;; - broker:prepared) echo "native-liboliphaunt-prepared-broker" ;; - broker:backup) echo "native-liboliphaunt-broker-backup" ;; - server:rtt) echo "native-liboliphaunt-server-rtt" ;; - server:speed) echo "native-liboliphaunt-server-speed" ;; - server:streaming) echo "native-liboliphaunt-server-streaming" ;; - server:prepared) echo "native-liboliphaunt-prepared-server" ;; - *) - echo "unsupported native case: $engine $suite" >&2 - exit 2 - ;; - esac -} - -print_native_plan_cases() { - local suite - local engine - for suite in rtt speed streaming prepared backup; do - if ! csv_has "$SUITES" "$suite"; then - continue - fi - if [[ "$suite" == "prepared" && "$RUN_PREPARED" -ne 1 ]]; then - continue - fi - for engine in direct broker server; do - if csv_has "$NATIVE_ENGINES" "$engine"; then - if [[ "$suite" == "backup" && "$engine" == "server" ]]; then - continue - fi - echo "case=$(native_case_name "$engine" "$suite")" - fi - done - done -} - -print_native_postgres_plan_cases() { - if csv_has "$SUITES" rtt && csv_has "$SUITES" speed; then - echo "case=native-postgres-tokio-all" - echo "case=native-postgres-sqlx-all" - else - if csv_has "$SUITES" rtt; then - echo "case=native-postgres-tokio-rtt" - echo "case=native-postgres-sqlx-rtt" - fi - if csv_has "$SUITES" speed; then - echo "case=native-postgres-tokio-speed" - echo "case=native-postgres-sqlx-speed" - fi - fi - if csv_has "$SUITES" streaming; then - echo "case=native-postgres-streaming" - fi - if csv_has "$SUITES" speed && [[ "$RUN_SQLITE" -eq 1 ]]; then - echo "case=sqlite-speed" - fi - if csv_has "$SUITES" prepared && [[ "$RUN_PREPARED" -eq 1 ]]; then - echo "case=native-postgres-prepared" - fi - if csv_has "$SUITES" backup; then - echo "case=native-postgres-backup" - if [[ "$RUN_SQLITE" -eq 1 ]]; then - echo "case=sqlite-backup" - fi - fi -} - -print_plan() { - cat <&2 - exit 1 -fi -if [[ ! -x "$POSTGRES_BIN" ]]; then - echo "missing native postgres binary: $POSTGRES_BIN" >&2 - exit 1 -fi -if [[ ! -x "$INITDB_BIN" ]]; then - echo "missing native initdb binary: $INITDB_BIN" >&2 - exit 1 -fi - -export LIBOLIPHAUNT_PATH="$OLIPHAUNT" -export OLIPHAUNT_POSTGRES="$POSTGRES_BIN" -export OLIPHAUNT_INITDB="$INITDB_BIN" - -RUN_DIR="$TARGET_ROOT/native-liboliphaunt-$RUN_ID" -mkdir -p "$RUN_DIR" - -PERF_RUNNER="$REPO_ROOT/target/release/oliphaunt-perf" - -RUN_DIR="$RUN_DIR" \ -OLIPHAUNT_PATH="$OLIPHAUNT" \ -POSTGRES_BIN_PATH="$POSTGRES_BIN" \ -INITDB_BIN_PATH="$INITDB_BIN" \ -node <<'NODE' > "$RUN_DIR/artifact-sizes.json" -const fs = require('node:fs') -const path = require('node:path') - -function sizeBytes(target) { - if (!target || !fs.existsSync(target)) return null - const stat = fs.lstatSync(target) - if (stat.isFile() || stat.isSymbolicLink()) return stat.size - if (!stat.isDirectory()) return 0 - let total = 0 - for (const entry of fs.readdirSync(target)) { - total += sizeBytes(path.join(target, entry)) ?? 0 - } - return total -} - -const liboliphaunt = process.env.OLIPHAUNT_PATH -const installDir = path.dirname(path.dirname(process.env.POSTGRES_BIN_PATH)) -const embeddedModules = path.join(path.dirname(liboliphaunt), 'modules') -const artifacts = [ - ['liboliphaunt-native', liboliphaunt], - ['embedded-modules', embeddedModules], - ['native-postgres-install', installDir], -] -console.log(JSON.stringify({ - artifacts: artifacts.map(([name, filePath]) => ({ - name, - path: filePath, - bytes: sizeBytes(filePath), - })), -}, null, 2)) -NODE - -if [[ "$BUILD_PERF_RUNNER" -eq 1 ]]; then - echo "Building native-only release oliphaunt-perf and native broker helper..." - cargo build --release -p oliphaunt-perf -p oliphaunt --bins -elif [[ ! -x "$PERF_RUNNER" ]]; then - echo "missing release oliphaunt-perf: $PERF_RUNNER" >&2 - echo "run without --skip-build first" >&2 - exit 1 -else - echo "Reusing existing release oliphaunt-perf: $PERF_RUNNER" -fi - -node "$SCRIPT_DIR/native_oliphaunt_provenance.mjs" write \ - --run-dir "$RUN_DIR" \ - --repo-root "$REPO_ROOT" \ - --run-id "$RUN_ID" \ - --native-engines "$NATIVE_ENGINES" \ - --suites "$SUITES" \ - --durability "$DURABILITY" \ - --runtime-footprint "$RUNTIME_FOOTPRINT" \ - --startup-gucs "$STARTUP_GUCS_CSV" \ - --rtt-iterations "$RTT_ITERATIONS" \ - --rtt-repeats "$RTT_REPEATS" \ - --prepared-rows "$PREPARED_ROWS" \ - --prepared-repeats "$PREPARED_REPEATS" \ - --speed-repeats "$SPEED_REPEATS" \ - --backup-repeats "$BACKUP_REPEATS" \ - --pgdata-copy-mode "$PGDATA_COPY_MODE" \ - --run-sqlite "$RUN_SQLITE" \ - --run-prepared "$RUN_PREPARED" \ - --release-evidence "$RELEASE_EVIDENCE" \ - --partial-report "$PARTIAL_REPORT" \ - --diagnostic-run "$DIAGNOSTIC_RUN" \ - --release-min-rtt-iterations "$RELEASE_MIN_RTT_ITERATIONS" \ - --release-min-rtt-repeats "$RELEASE_MIN_RTT_REPEATS" \ - --release-min-prepared-rows "$RELEASE_MIN_PREPARED_ROWS" \ - --release-min-prepared-repeats "$RELEASE_MIN_PREPARED_REPEATS" \ - --release-min-speed-repeats "$RELEASE_MIN_SPEED_REPEATS" \ - --release-min-backup-repeats "$RELEASE_MIN_BACKUP_REPEATS" \ - --liboliphaunt "$OLIPHAUNT" \ - --postgres-bin "$POSTGRES_BIN" \ - --initdb-bin "$INITDB_BIN" \ - --perf-runner "$PERF_RUNNER" \ - > "$RUN_DIR/provenance.path" - -run_timed_json() { - local name="$1" - shift - local json="$RUN_DIR/$name.json" - local resource="$RUN_DIR/$name.resource.txt" - - echo "Running $name..." - if [[ "$(uname -s)" == "Darwin" ]]; then - /usr/bin/time -l -o "$resource" "$@" > "$json" - elif /usr/bin/time -v true >/dev/null 2>&1; then - /usr/bin/time -v -o "$resource" "$@" > "$json" - else - /usr/bin/time -p -o "$resource" "$@" > "$json" - fi -} - -run_native_liboliphaunt_case() { - local engine="$1" - local suite="$2" - local name="${3:-}" - if [[ -z "$name" ]]; then - name="$(native_case_name "$engine" "$suite")" - fi - case "$suite" in - rtt) - run_timed_json "$name" \ - "$PERF_RUNNER" native-liboliphaunt \ - --engine "$engine" \ - --suite rtt \ - --durability "$DURABILITY" \ - "${TUNING_ARGS[@]}" \ - --iterations "$RTT_ITERATIONS" - ;; - speed) - run_timed_json "$name" \ - "$PERF_RUNNER" native-liboliphaunt \ - --engine "$engine" \ - --suite speed \ - --durability "$DURABILITY" \ - "${TUNING_ARGS[@]}" \ - --speed-source oliphaunt - ;; - streaming) - run_timed_json "$name" \ - "$PERF_RUNNER" native-liboliphaunt \ - --engine "$engine" \ - --suite streaming \ - --durability "$DURABILITY" \ - "${TUNING_ARGS[@]}" - ;; - prepared) - run_timed_json "$name" \ - "$PERF_RUNNER" native-liboliphaunt \ - --engine "$engine" \ - --durability "$DURABILITY" \ - "${TUNING_ARGS[@]}" \ - --suite prepared-updates \ - --rows "$PREPARED_ROWS" - ;; - backup) - run_timed_json "$name" \ - "$PERF_RUNNER" native-liboliphaunt \ - --engine "$engine" \ - --suite backup-restore \ - --durability "$DURABILITY" \ - "${TUNING_ARGS[@]}" - ;; - esac -} - -run_native_postgres_case() { - local name="$1" - local client="$2" - local suite="$3" - local args=( - "$PERF_RUNNER" native-postgres - --suite "$suite" - --durability "$DURABILITY" - "${TUNING_ARGS[@]}" - --postgres-bin "$POSTGRES_BIN" - --initdb-bin "$INITDB_BIN" - ) - if [[ "$suite" == "all" || "$suite" == "rtt" ]]; then - args+=(--iterations "$RTT_ITERATIONS") - fi - if [[ "$suite" == "all" || "$suite" == "speed" ]]; then - args+=(--speed-source oliphaunt) - fi - if [[ -n "$client" ]]; then - args+=(--client "$client") - fi - run_timed_json "$name" "${args[@]}" -} - -run_native_postgres_prepared() { - local name="$1" - run_timed_json "$name" \ - "$PERF_RUNNER" native-postgres \ - --suite prepared-updates \ - --rows "$PREPARED_ROWS" \ - --durability "$DURABILITY" \ - "${TUNING_ARGS[@]}" \ - --postgres-bin "$POSTGRES_BIN" \ - --initdb-bin "$INITDB_BIN" -} - -for suite in rtt speed streaming prepared backup; do - if ! csv_has "$SUITES" "$suite"; then - continue - fi - if [[ "$suite" == "prepared" && "$RUN_PREPARED" -ne 1 ]]; then - continue - fi - for engine in direct broker server; do - if csv_has "$NATIVE_ENGINES" "$engine"; then - if [[ "$suite" == "backup" && "$engine" == "server" ]]; then - continue - fi - run_native_liboliphaunt_case "$engine" "$suite" - fi - done -done - -if csv_has "$SUITES" rtt && csv_has "$SUITES" speed; then - run_native_postgres_case native-postgres-tokio-all tokio-postgres-simple all - run_native_postgres_case native-postgres-sqlx-all sqlx all -else - if csv_has "$SUITES" rtt; then - run_native_postgres_case native-postgres-tokio-rtt tokio-postgres-simple rtt - run_native_postgres_case native-postgres-sqlx-rtt sqlx rtt - fi - if csv_has "$SUITES" speed; then - run_native_postgres_case native-postgres-tokio-speed tokio-postgres-simple speed - run_native_postgres_case native-postgres-sqlx-speed sqlx speed - fi -fi - -if csv_has "$SUITES" streaming; then - run_native_postgres_case native-postgres-streaming "" streaming -fi - -if csv_has "$SUITES" speed && [[ "$RUN_SQLITE" -eq 1 ]]; then - run_timed_json sqlite-speed \ - "$PERF_RUNNER" sqlite \ - --suite speed \ - --durability "$DURABILITY" \ - --speed-source oliphaunt -fi - -if csv_has "$SUITES" prepared && [[ "$RUN_PREPARED" -eq 1 ]]; then - run_native_postgres_prepared native-postgres-prepared -fi - -if csv_has "$SUITES" backup; then - run_native_postgres_case native-postgres-backup tokio-postgres-simple backup-restore - if [[ "$RUN_SQLITE" -eq 1 ]]; then - run_timed_json sqlite-backup \ - "$PERF_RUNNER" sqlite \ - --suite backup-restore \ - --durability "$DURABILITY" - fi -fi - -if csv_has "$SUITES" prepared && [[ "$RUN_PREPARED" -eq 1 && "$PREPARED_REPEATS" -gt 1 ]]; then - mkdir -p "$RUN_DIR/repeats" - for index in $(seq -w 1 "$PREPARED_REPEATS"); do - run_native_postgres_prepared "repeats/native-postgres-prepared-$index" - for engine in direct broker server; do - if csv_has "$NATIVE_ENGINES" "$engine"; then - run_native_liboliphaunt_case "$engine" prepared "repeats/$(native_case_name "$engine" prepared)-$index" - fi - done - done -fi - -if csv_has "$SUITES" rtt && [[ "$RTT_REPEATS" -gt 1 ]]; then - mkdir -p "$RUN_DIR/repeats" - for index in $(seq -w 1 "$RTT_REPEATS"); do - for engine in direct broker server; do - if csv_has "$NATIVE_ENGINES" "$engine"; then - run_timed_json "repeats/$(native_case_name "$engine" rtt)-$index" \ - "$PERF_RUNNER" native-liboliphaunt \ - --engine "$engine" \ - --suite rtt \ - --durability "$DURABILITY" \ - "${TUNING_ARGS[@]}" \ - --iterations "$RTT_ITERATIONS" - fi - done - run_native_postgres_case "repeats/native-postgres-tokio-rtt-$index" tokio-postgres-simple rtt - done -fi - -if csv_has "$SUITES" speed && [[ "$SPEED_REPEATS" -gt 1 ]]; then - mkdir -p "$RUN_DIR/repeats" - for index in $(seq -w 1 "$SPEED_REPEATS"); do - for engine in direct broker server; do - if csv_has "$NATIVE_ENGINES" "$engine"; then - run_timed_json "repeats/$(native_case_name "$engine" speed)-$index" \ - "$PERF_RUNNER" native-liboliphaunt \ - --engine "$engine" \ - --suite speed \ - --durability "$DURABILITY" \ - "${TUNING_ARGS[@]}" \ - --speed-source oliphaunt - fi - done - run_native_postgres_case "repeats/native-postgres-tokio-speed-$index" tokio-postgres-simple speed - if [[ "$RUN_SQLITE" -eq 1 ]]; then - run_timed_json "repeats/sqlite-speed-$index" \ - "$PERF_RUNNER" sqlite \ - --suite speed \ - --durability "$DURABILITY" \ - --speed-source oliphaunt - fi - done -fi - -if csv_has "$SUITES" backup && [[ "$BACKUP_REPEATS" -gt 1 ]]; then - mkdir -p "$RUN_DIR/repeats" - for index in $(seq -w 1 "$BACKUP_REPEATS"); do - for engine in direct broker; do - if csv_has "$NATIVE_ENGINES" "$engine"; then - run_native_liboliphaunt_case "$engine" backup "repeats/$(native_case_name "$engine" backup)-$index" - fi - done - run_native_postgres_case "repeats/native-postgres-backup-$index" tokio-postgres-simple backup-restore - if [[ "$RUN_SQLITE" -eq 1 ]]; then - run_timed_json "repeats/sqlite-backup-$index" \ - "$PERF_RUNNER" sqlite \ - --suite backup-restore \ - --durability "$DURABILITY" - fi - done -fi - -node "$SCRIPT_DIR/summarize_native_oliphaunt_matrix.mjs" \ - --run-dir "$RUN_DIR" \ - --run-id "$RUN_ID" \ - --postgres-version "$("$POSTGRES_BIN" --version)" \ - --native-engines "$NATIVE_ENGINES" \ - --suites "$SUITES" \ - --durability "$DURABILITY" \ - --runtime-footprint "$RUNTIME_FOOTPRINT" \ - --startup-gucs "$STARTUP_GUCS_CSV" \ - --pgdata-copy-mode "$PGDATA_COPY_MODE" \ - --release-evidence "$RELEASE_EVIDENCE" \ - --partial-report "$PARTIAL_REPORT" \ - --rtt-repeats "$RTT_REPEATS" \ - --prepared-repeats "$PREPARED_REPEATS" \ - --speed-repeats "$SPEED_REPEATS" \ - --backup-repeats "$BACKUP_REPEATS" \ - > "$RUN_DIR/report.md" - -echo "$RUN_DIR/report.md" diff --git a/tools/perf/matrix/run_native_speed_diagnostics.sh b/tools/perf/matrix/run_native_speed_diagnostics.sh deleted file mode 100755 index d8e3a15cd..000000000 --- a/tools/perf/matrix/run_native_speed_diagnostics.sh +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -if REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then - : -else - REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" -fi - -RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)" -IDS="" -REPEATS=10 -DURABILITY="${OLIPHAUNT_PERF_DURABILITY:-safe}" -BUILD_PERF_RUNNER=1 - -usage() { - cat >&2 <<'USAGE' -usage: tools/perf/matrix/run_native_speed_diagnostics.sh --ids LIST [options] - -Options: - --ids LIST Comma-separated Oliphaunt fixture speed case ids. - --repeats N Fresh-process repeats per case. Default: 10. - --run-id ID Output run id. Defaults to current UTC timestamp. - --durability PROFILE - Native durability profile: safe, balanced, or fast-dev. - --skip-build Reuse target/release/oliphaunt-perf. - -h, --help Show this help. - -Environment: - LIBOLIPHAUNT_PATH Path to liboliphaunt.dylib/.so. Defaults to target artifact. - OLIPHAUNT_POSTGRES Path to matching postgres binary. Defaults to target artifact. - OLIPHAUNT_INITDB Path to matching initdb binary. Defaults to target artifact. -USAGE -} - -while [[ $# -gt 0 ]]; do - case "$1" in - --ids) - IDS="${2:?--ids requires a value}" - shift 2 - ;; - --ids=*) - IDS="${1#--ids=}" - shift - ;; - --repeats) - REPEATS="${2:?--repeats requires a value}" - shift 2 - ;; - --run-id) - RUN_ID="${2:?--run-id requires a value}" - shift 2 - ;; - --durability) - DURABILITY="${2:?--durability requires a value}" - shift 2 - ;; - --skip-build) - BUILD_PERF_RUNNER=0 - shift - ;; - -h|--help) - usage - exit 0 - ;; - *) - echo "unknown argument: $1" >&2 - usage - exit 2 - ;; - esac -done - -if [[ -z "$IDS" ]]; then - echo "--ids is required" >&2 - usage - exit 2 -fi -if [[ "$REPEATS" -le 0 ]]; then - echo "--repeats must be positive" >&2 - exit 2 -fi -case "$DURABILITY" in - safe|balanced|fast-dev) ;; - *) - echo "unknown durability profile: $DURABILITY" >&2 - exit 2 - ;; -esac - -OLIPHAUNT="${LIBOLIPHAUNT_PATH:-$REPO_ROOT/target/liboliphaunt-pg18/out/liboliphaunt.dylib}" -POSTGRES_BIN="${OLIPHAUNT_POSTGRES:-$REPO_ROOT/target/liboliphaunt-pg18/install/bin/postgres}" -INITDB_BIN="${OLIPHAUNT_INITDB:-$REPO_ROOT/target/liboliphaunt-pg18/install/bin/initdb}" -PERF_RUNNER="$REPO_ROOT/target/release/oliphaunt-perf" - -if [[ ! -f "$OLIPHAUNT" ]]; then - echo "missing native liboliphaunt-native: $OLIPHAUNT" >&2 - exit 1 -fi -if [[ ! -x "$POSTGRES_BIN" ]]; then - echo "missing native postgres binary: $POSTGRES_BIN" >&2 - exit 1 -fi -if [[ ! -x "$INITDB_BIN" ]]; then - echo "missing native initdb binary: $INITDB_BIN" >&2 - exit 1 -fi - -if [[ "$BUILD_PERF_RUNNER" -eq 1 ]]; then - cargo build --release -p oliphaunt-perf -p oliphaunt --bins -elif [[ ! -x "$PERF_RUNNER" ]]; then - echo "missing release oliphaunt-perf: $PERF_RUNNER" >&2 - exit 1 -fi - -RUN_DIR="$REPO_ROOT/target/perf/native-speed-diagnostics-$RUN_ID" -mkdir -p "$RUN_DIR/direct" "$RUN_DIR/native-postgres" - -IFS=',' read -r -a ID_LIST <<< "${IDS//[[:space:]]/}" -for id in "${ID_LIST[@]}"; do - if [[ -z "$id" ]]; then - echo "--ids must not contain empty entries" >&2 - exit 2 - fi -done - -safe_id() { - printf '%s\n' "${1//./_}" -} - -for repeat in $(seq -w 1 "$REPEATS"); do - echo "Running native-postgres speed diagnostics repeat $repeat..." - "$PERF_RUNNER" diagnose-speed-cases \ - --engine native-postgres \ - --ids "$IDS" \ - --durability "$DURABILITY" \ - --postgres-bin "$POSTGRES_BIN" \ - --initdb-bin "$INITDB_BIN" \ - > "$RUN_DIR/native-postgres/native-postgres-speed-cases-$repeat.json" \ - 2> "$RUN_DIR/native-postgres/native-postgres-speed-cases-$repeat.err" - - for id in "${ID_LIST[@]}"; do - id_file="$(safe_id "$id")" - echo "Running native-liboliphaunt speed diagnostic case $id repeat $repeat..." - LIBOLIPHAUNT_PATH="$OLIPHAUNT" \ - OLIPHAUNT_INSTALL_DIR="$(dirname "$(dirname "$POSTGRES_BIN")")" \ - "$PERF_RUNNER" diagnose-speed-cases \ - --engine native-liboliphaunt \ - --ids "$id" \ - --durability "$DURABILITY" \ - > "$RUN_DIR/direct/native-liboliphaunt-speed-case-$id_file-$repeat.json" \ - 2> "$RUN_DIR/direct/native-liboliphaunt-speed-case-$id_file-$repeat.err" - done -done - -node "$SCRIPT_DIR/summarize_native_speed_diagnostics.mjs" \ - --run-dir "$RUN_DIR" \ - --ids "$IDS" \ - --repeats "$REPEATS" - -echo "$RUN_DIR/summary.md" diff --git a/tools/perf/matrix/summarize_native_oliphaunt_matrix.mjs b/tools/perf/matrix/summarize_native_oliphaunt_matrix.mjs deleted file mode 100644 index 4e1a59eef..000000000 --- a/tools/perf/matrix/summarize_native_oliphaunt_matrix.mjs +++ /dev/null @@ -1,1327 +0,0 @@ -import fs from 'node:fs/promises' -import path from 'node:path' - -function parseArgs(argv) { - const args = {} - for (let index = 0; index < argv.length; index += 1) { - const key = argv[index] - if (!key.startsWith('--')) { - continue - } - const hasValue = index + 1 < argv.length - const value = argv[index + 1] - if (hasValue && !value.startsWith('--')) { - args[key] = value - index += 1 - } else { - args[key] = 'true' - } - } - return args -} - -function requireArg(args, key) { - const value = args[key] - if (!value) { - throw new Error(`${key} is required`) - } - return value -} - -function boolValue(value) { - if (value === undefined || value === null) { - return null - } - if (typeof value === 'boolean') { - return value - } - return value === '1' || value === 'true' -} - -async function readJsonIfExists(file) { - try { - return JSON.parse(await fs.readFile(file, 'utf8')) - } catch (error) { - if (error && error.code === 'ENOENT') { - return null - } - throw error - } -} - -async function readTextIfExists(file) { - try { - return await fs.readFile(file, 'utf8') - } catch (error) { - if (error && error.code === 'ENOENT') { - return '' - } - throw error - } -} - -function collectRun(report, suite, mode) { - if (!report) { - return null - } - return report.runs.find((entry) => entry.suite === suite && entry.mode === mode) ?? null -} - -function sum(values) { - return values.reduce((total, value) => total + value, 0) -} - -function mean(values) { - return values.length === 0 ? null : sum(values) / values.length -} - -function percentile(values, ratio) { - if (values.length === 0) { - return null - } - const sorted = [...values].sort((a, b) => a - b) - const index = Math.round((sorted.length - 1) * ratio) - return sorted[index] -} - -function round(value, digits = 2) { - if (value === null || value === undefined || Number.isNaN(value)) { - return null - } - return Number(value.toFixed(digits)) -} - -function fmtMsFromMicros(value) { - return value === null || value === undefined ? 'n/a' : `${round(value / 1000, 2)}` -} - -function fmtSecFromMicros(value) { - return value === null || value === undefined ? 'n/a' : `${round(value / 1_000_000, 3)}` -} - -function fmtMb(value) { - return value === null || value === undefined ? 'n/a' : `${round(value, 1)}` -} - -function fmtSec(value) { - return value === null || value === undefined ? 'n/a' : `${round(value, 2)}` -} - -function fmtBytes(value) { - if (value === null || value === undefined) { - return 'n/a' - } - if (value >= 1024 * 1024 * 1024) { - return `${round(value / 1024 / 1024 / 1024, 2)} GB` - } - if (value >= 1024 * 1024) { - return `${round(value / 1024 / 1024, 2)} MB` - } - if (value >= 1024) { - return `${round(value / 1024, 2)} KB` - } - return `${value} B` -} - -function shortSha(value) { - return value ? value.slice(0, 12) : 'n/a' -} - -function fmtRatio(value, baseline) { - if (!Number.isFinite(value) || !Number.isFinite(baseline) || baseline === 0) { - return 'n/a' - } - return `${round(value / baseline, 3)}x` -} - -function fmtRate(value) { - return value === null || value === undefined ? 'n/a' : `${round(value, 1)}` -} - -function fmtMbPerSec(value) { - return value === null || value === undefined ? 'n/a' : `${round(value / 1024 / 1024, 1)}` -} - -function fmtMbFromBytes(value) { - return value === null || value === undefined ? 'n/a' : `${round(value / 1024 / 1024, 2)}` -} - -function ratioNumber(value, baseline) { - if (!Number.isFinite(value) || !Number.isFinite(baseline) || baseline === 0) { - return null - } - return value / baseline -} - -function gateStatus(value, baseline, tolerance = 0.05) { - if (!Number.isFinite(value) || !Number.isFinite(baseline)) { - return 'n/a' - } - return value <= baseline * (1 + tolerance) ? 'pass' : 'miss' -} - -function gateStatusHigher(value, baseline, tolerance = 0.05) { - if (!Number.isFinite(value) || !Number.isFinite(baseline)) { - return 'n/a' - } - return value >= baseline * (1 - tolerance) ? 'pass' : 'miss' -} - -function speedTotalMicros(run) { - return run ? sum(run.tests.map((test) => test.elapsedMicros)) : null -} - -function benchmarkRunOperationCount(run) { - return run ? sum(run.tests.map((test) => test.operationCount ?? 0)) : null -} - -function benchmarkRunThroughputPerSecond(run) { - const totalMicros = speedTotalMicros(run) - const operationCount = benchmarkRunOperationCount(run) - if (!Number.isFinite(totalMicros) || !Number.isFinite(operationCount) || totalMicros <= 0) { - return null - } - return operationCount / (totalMicros / 1_000_000) -} - -function bytesToMb(value) { - return value === null || value === undefined ? null : value / 1024 / 1024 -} - -function rttSummary(run) { - if (!run) { - return null - } - const p50s = run.tests.map((test) => test.p50Micros).filter(Number.isFinite) - const p90s = run.tests.map((test) => test.p90Micros).filter(Number.isFinite) - const p95s = run.tests.map((test) => test.p95Micros).filter(Number.isFinite) - const p99s = run.tests.map((test) => test.p99Micros).filter(Number.isFinite) - return { - openMicros: run.openMicros, - connectMicros: run.connectMicros, - setupMicros: run.setupMicros, - medianP50Us: percentile(p50s, 0.5), - medianP90Us: percentile(p90s, 0.5), - medianP95Us: percentile(p95s, 0.5), - medianP99Us: percentile(p99s, 0.5), - maxP90Us: p90s.length ? Math.max(...p90s) : null, - maxP99Us: p99s.length ? Math.max(...p99s) : null, - observedServerPeakRssMb: bytesToMb(run.observedServerPeakRssBytes), - } -} - -function parseResource(text) { - const resource = { - realSec: null, - userSec: null, - sysSec: null, - cpuSec: null, - peakRssMb: null, - peakFootprintMb: null, - } - for (const rawLine of text.split('\n')) { - const line = rawLine.trim() - let darwinMatch = line.match( - /^([0-9.]+)\s+real\s+([0-9.]+)\s+user\s+([0-9.]+)\s+sys$/, - ) - if (darwinMatch) { - resource.realSec = Number(darwinMatch[1]) - resource.userSec = Number(darwinMatch[2]) - resource.sysSec = Number(darwinMatch[3]) - continue - } - let match = line.match(/^([0-9.]+)\s+real$/) - if (match) { - resource.realSec = Number(match[1]) - continue - } - match = line.match(/^([0-9.]+)\s+user$/) - if (match) { - resource.userSec = Number(match[1]) - continue - } - match = line.match(/^([0-9.]+)\s+sys$/) - if (match) { - resource.sysSec = Number(match[1]) - continue - } - match = line.match(/^([0-9]+)\s+maximum resident set size$/) - if (match) { - resource.peakRssMb = Number(match[1]) / 1024 / 1024 - continue - } - match = line.match(/^([0-9]+)\s+peak memory footprint$/) - if (match) { - resource.peakFootprintMb = Number(match[1]) / 1024 / 1024 - continue - } - match = line.match(/^Maximum resident set size .*:\s*([0-9]+)$/) - if (match) { - resource.peakRssMb = Number(match[1]) / 1024 - } - } - if (resource.userSec !== null || resource.sysSec !== null) { - resource.cpuSec = (resource.userSec ?? 0) + (resource.sysSec ?? 0) - } - return resource -} - -async function loadMeasuredRun(runDir, name) { - const report = await readJsonIfExists(path.join(runDir, `${name}.json`)) - const resource = parseResource(await readTextIfExists(path.join(runDir, `${name}.resource.txt`))) - return { report, resource } -} - -async function loadFirstMeasuredRun(runDir, names) { - let first = null - for (const name of names) { - const measurement = await loadMeasuredRun(runDir, name) - if (!first) { - first = measurement - } - if (measurement.report) { - return measurement - } - } - return first ?? { report: null, resource: parseResource('') } -} - -async function loadRttRepeatMeasurements(runDir, prefix, mode) { - const repeatDir = path.join(runDir, 'repeats') - let entries = [] - try { - entries = await fs.readdir(repeatDir) - } catch (error) { - if (error && error.code === 'ENOENT') { - return [] - } - throw error - } - const files = entries - .filter((entry) => entry.startsWith(prefix) && entry.endsWith('.json')) - .sort() - const measurements = [] - for (const file of files) { - const jsonPath = path.join(repeatDir, file) - const report = await readJsonIfExists(jsonPath) - const run = report?.runs?.find((entry) => entry.suite === 'rtt' && entry.mode === mode) - if (run) { - const resourcePath = jsonPath.replace(/\.json$/, '.resource.txt') - const resource = parseResource(await readTextIfExists(resourcePath)) - measurements.push({ file, run, resource }) - } - } - return measurements -} - -async function loadSpeedRepeatMeasurements(runDir, prefix) { - return loadBenchmarkRepeatMeasurements(runDir, prefix, 'speed') -} - -async function loadBackupRepeatMeasurements(runDir, prefix, mode = null) { - return loadBenchmarkRepeatMeasurements(runDir, prefix, 'backup-restore', mode) -} - -async function loadBenchmarkRepeatMeasurements(runDir, prefix, suite, mode = null) { - const repeatDir = path.join(runDir, 'repeats') - let entries = [] - try { - entries = await fs.readdir(repeatDir) - } catch (error) { - if (error && error.code === 'ENOENT') { - return [] - } - throw error - } - const files = entries - .filter((entry) => entry.startsWith(prefix) && entry.endsWith('.json')) - .sort() - const measurements = [] - for (const file of files) { - const jsonPath = path.join(repeatDir, file) - const report = await readJsonIfExists(jsonPath) - const run = report?.runs?.find( - (entry) => entry.suite === suite && (mode === null || entry.mode === mode), - ) - if (run) { - const resourcePath = jsonPath.replace(/\.json$/, '.resource.txt') - const resource = parseResource(await readTextIfExists(resourcePath)) - measurements.push({ file, run, resource }) - } - } - return measurements -} - -async function loadPreparedRepeatMeasurements(runDir, prefix) { - const repeatDir = path.join(runDir, 'repeats') - let entries = [] - try { - entries = await fs.readdir(repeatDir) - } catch (error) { - if (error && error.code === 'ENOENT') { - return [] - } - throw error - } - const files = entries - .filter((entry) => entry.startsWith(prefix) && entry.endsWith('.json')) - .sort() - const measurements = [] - for (const file of files) { - const jsonPath = path.join(repeatDir, file) - const report = await readJsonIfExists(jsonPath) - if (report?.runs?.length) { - const resourcePath = jsonPath.replace(/\.json$/, '.resource.txt') - const resource = parseResource(await readTextIfExists(resourcePath)) - measurements.push({ file, report, resource }) - } - } - return measurements -} - -function repeatedRttSummary(primaryRun, primaryResource, repeatMeasurements) { - const runs = repeatMeasurements.length - ? repeatMeasurements.map((measurement) => measurement.run) - : primaryRun - ? [primaryRun] - : [] - const resources = repeatMeasurements.length - ? repeatMeasurements.map((measurement) => measurement.resource) - : primaryResource - ? [primaryResource] - : [] - const summaries = runs.map(rttSummary).filter(Boolean) - const opens = summaries.map((summary) => summary.openMicros).filter(Number.isFinite) - const connects = summaries.map((summary) => summary.connectMicros).filter(Number.isFinite) - const medianP50s = summaries.map((summary) => summary.medianP50Us).filter(Number.isFinite) - const medianP90s = summaries.map((summary) => summary.medianP90Us).filter(Number.isFinite) - const medianP95s = summaries.map((summary) => summary.medianP95Us).filter(Number.isFinite) - const medianP99s = summaries.map((summary) => summary.medianP99Us).filter(Number.isFinite) - const maxP90s = summaries.map((summary) => summary.maxP90Us).filter(Number.isFinite) - const maxP99s = summaries.map((summary) => summary.maxP99Us).filter(Number.isFinite) - const rss = resources.map((resource) => resource.peakRssMb).filter(Number.isFinite) - const cpus = resources.map((resource) => resource.cpuSec).filter(Number.isFinite) - const observedServerRss = summaries - .map((summary) => summary.observedServerPeakRssMb) - .filter(Number.isFinite) - return { - n: runs.length, - openMicros: percentile(opens, 0.5), - openP90Micros: percentile(opens, 0.9), - connectMicros: percentile(connects, 0.5), - medianP50Us: percentile(medianP50s, 0.5), - medianP90Us: percentile(medianP90s, 0.5), - medianP95Us: percentile(medianP95s, 0.5), - medianP99Us: percentile(medianP99s, 0.5), - gateMedianP90Us: percentile(medianP90s, runs.length >= 10 ? 0.9 : 0.5), - maxP90Us: maxP90s.length ? Math.max(...maxP90s) : null, - maxP99Us: maxP99s.length ? Math.max(...maxP99s) : null, - peakRssMb: percentile(rss, 0.9), - observedServerPeakRssMb: percentile(observedServerRss, 0.9), - cpuSec: percentile(cpus, 0.9), - } -} - -function repeatedSpeedSummary(primaryRun, primaryResource, repeatMeasurements) { - const runs = repeatMeasurements.length - ? repeatMeasurements.map((measurement) => measurement.run) - : primaryRun - ? [primaryRun] - : [] - const resources = repeatMeasurements.length - ? repeatMeasurements.map((measurement) => measurement.resource) - : primaryResource - ? [primaryResource] - : [] - const totals = runs.map(speedTotalMicros) - const finiteTotals = totals.filter(Number.isFinite) - const throughputs = runs.map(benchmarkRunThroughputPerSecond).filter(Number.isFinite) - const operationCounts = runs.map(benchmarkRunOperationCount).filter(Number.isFinite) - const opens = runs.map((run) => run.openMicros).filter(Number.isFinite) - const rss = resources.map((resource) => resource.peakRssMb).filter(Number.isFinite) - const footprints = resources - .map((resource) => resource.peakFootprintMb) - .filter(Number.isFinite) - const cpus = resources.map((resource) => resource.cpuSec).filter(Number.isFinite) - const observedServerRss = runs - .map((run) => bytesToMb(run.observedServerPeakRssBytes)) - .filter(Number.isFinite) - const p90RssMb = percentile(rss, 0.9) - const p90ObservedServerRssMb = percentile(observedServerRss, 0.9) - const p99RssMb = percentile(rss, 0.99) - const p99ObservedServerRssMb = percentile(observedServerRss, 0.99) - return { - n: runs.length, - minTotalMicros: finiteTotals.length ? Math.min(...finiteTotals) : null, - maxTotalMicros: finiteTotals.length ? Math.max(...finiteTotals) : null, - p50TotalMicros: percentile(finiteTotals, 0.5), - p90TotalMicros: percentile(finiteTotals, 0.9), - p95TotalMicros: percentile(finiteTotals, 0.95), - p99TotalMicros: percentile(finiteTotals, 0.99), - p50OperationCount: percentile(operationCounts, 0.5), - p90OperationCount: percentile(operationCounts, 0.9), - p50ThroughputPerSecond: percentile(throughputs, 0.5), - tailP10ThroughputPerSecond: percentile(throughputs, 0.1), - p50OpenMicros: percentile(opens, 0.5), - p90OpenMicros: percentile(opens, 0.9), - p99OpenMicros: percentile(opens, 0.99), - p90RssMb, - p90ObservedServerRssMb, - p90MemoryBaselineRssMb: Math.max(p90RssMb ?? 0, p90ObservedServerRssMb ?? 0) || null, - p99RssMb, - p99ObservedServerRssMb, - p99MemoryBaselineRssMb: Math.max(p99RssMb ?? 0, p99ObservedServerRssMb ?? 0) || null, - p90FootprintMb: percentile(footprints, 0.9), - p99FootprintMb: percentile(footprints, 0.99), - p90CpuSec: percentile(cpus, 0.9), - p99CpuSec: percentile(cpus, 0.99), - } -} - -function runQuality(summary) { - if (!summary || summary.n === 0 || !Number.isFinite(summary.p50TotalMicros)) { - return { status: 'n/a', reason: 'missing speed measurements' } - } - if (summary.n < 10) { - return { status: 'insufficient', reason: 'fewer than ten fresh-process repeats' } - } - if (summary.n < 20) { - return { status: 'insufficient', reason: 'fewer than twenty repeats; tail quality is not release-grade' } - } - const p90ToP50 = ratioNumber(summary.p90TotalMicros, summary.p50TotalMicros) - const p95ToP50 = ratioNumber(summary.p95TotalMicros, summary.p50TotalMicros) - const p99ToP50 = ratioNumber(summary.p99TotalMicros, summary.p50TotalMicros) - if ((p90ToP50 ?? 0) > 1.2 || (p95ToP50 ?? 0) > 1.3 || (p99ToP50 ?? 0) > 1.5) { - return { status: 'noisy', reason: 'tail spread is too high for release parity claims' } - } - if ((p90ToP50 ?? 0) > 1.12 || (p95ToP50 ?? 0) > 1.2 || (p99ToP50 ?? 0) > 1.35) { - return { status: 'watch', reason: 'tail spread is elevated; repeat on an idle host' } - } - return { status: 'stable', reason: 'tail spread is within release-evidence bounds' } -} - -function speedCaseRows(modes) { - const base = modes.find((mode) => mode.run)?.run - if (!base) { - return [] - } - return base.tests.map((test) => { - const values = modes.map((mode) => { - if (mode.repeats.length > 0) { - const repeatedValues = mode.repeats - .map((measurement) => - measurement.run.tests.find((candidate) => candidate.id === test.id)?.elapsedMicros, - ) - .filter(Number.isFinite) - return fmtMsFromMicros(percentile(repeatedValues, 0.9)) - } - const match = mode.run?.tests.find((candidate) => candidate.id === test.id) - return fmtMsFromMicros(match?.elapsedMicros) - }) - return `| ${test.id} | ${test.label} | ${values.join(' | ')} |` - }) -} - -function speedCaseMicros(mode, testId) { - if (mode.repeats.length > 0) { - const repeatedValues = mode.repeats - .map((measurement) => - measurement.run.tests.find((candidate) => candidate.id === testId)?.elapsedMicros, - ) - .filter(Number.isFinite) - return percentile(repeatedValues, 0.9) - } - return mode.run?.tests.find((candidate) => candidate.id === testId)?.elapsedMicros ?? null -} - -function speedCaseGateMisses(nativeMode, baselineMode, tolerance = 0.05) { - if (!nativeMode?.run || !baselineMode?.run) { - return [] - } - const misses = [] - for (const test of nativeMode.run.tests) { - const nativeMicros = speedCaseMicros(nativeMode, test.id) - const baselineMicros = speedCaseMicros(baselineMode, test.id) - if (gateStatus(nativeMicros, baselineMicros, tolerance) === 'miss') { - misses.push({ - id: test.id, - label: test.label, - nativeMicros, - baselineMicros, - }) - } - } - return misses -} - -function slowestRepeatRows(modes, count = 3) { - const rows = [] - for (const mode of modes) { - if (!mode.run) { - continue - } - const measurements = mode.repeats.length - ? mode.repeats - : [{ file: 'primary', run: mode.run, resource: mode.resource }] - const summary = repeatedSpeedSummary(mode.run, mode.resource, mode.repeats) - const totals = measurements - .map((measurement) => ({ - file: measurement.file ?? 'primary', - totalMicros: speedTotalMicros(measurement.run), - openMicros: measurement.run.openMicros, - })) - .filter((entry) => Number.isFinite(entry.totalMicros)) - .sort((a, b) => b.totalMicros - a.totalMicros) - .slice(0, count) - for (const entry of totals) { - rows.push( - `| ${mode.label} | \`${entry.file}\` | ${fmtSecFromMicros(entry.totalMicros)} | ${fmtRatio(entry.totalMicros, summary.p50TotalMicros)} | ${fmtMsFromMicros(entry.openMicros)} |`, - ) - } - } - return rows -} - -function preparedTest(run, id) { - return run?.tests?.find((test) => test.id === id) ?? null -} - -function preparedBaselineMode(mode) { - return mode.includes('pipelined') - ? 'native_postgres_tokio_pipelined_prepared' - : 'native_postgres_tokio_prepared' -} - -function repeatedPreparedSummary(primaryMeasurement, repeatMeasurements, mode) { - const measurements = repeatMeasurements.length - ? repeatMeasurements - : primaryMeasurement.report - ? [primaryMeasurement] - : [] - const matched = measurements - .map((measurement) => ({ - run: measurement.report?.runs?.find((entry) => entry.mode === mode) ?? null, - resource: measurement.resource, - })) - .filter((measurement) => measurement.run) - const runs = matched.map((measurement) => measurement.run) - const resources = matched.map((measurement) => measurement.resource) - const numeric = runs - .map((run) => preparedTest(run, 'numeric_indexed')?.elapsedMicros) - .filter(Number.isFinite) - const text = runs - .map((run) => preparedTest(run, 'text_indexed')?.elapsedMicros) - .filter(Number.isFinite) - const rss = resources.map((resource) => resource.peakRssMb).filter(Number.isFinite) - const footprints = resources - .map((resource) => resource.peakFootprintMb) - .filter(Number.isFinite) - const cpus = resources.map((resource) => resource.cpuSec).filter(Number.isFinite) - const reals = resources.map((resource) => resource.realSec).filter(Number.isFinite) - return { - n: runs.length, - numericP50Micros: percentile(numeric, 0.5), - numericP90Micros: percentile(numeric, 0.9), - numericP95Micros: percentile(numeric, 0.95), - numericP99Micros: percentile(numeric, 0.99), - textP50Micros: percentile(text, 0.5), - textP90Micros: percentile(text, 0.9), - textP95Micros: percentile(text, 0.95), - textP99Micros: percentile(text, 0.99), - p90RssMb: percentile(rss, 0.9), - p99RssMb: percentile(rss, 0.99), - p90FootprintMb: percentile(footprints, 0.9), - p99FootprintMb: percentile(footprints, 0.99), - p90CpuSec: percentile(cpus, 0.9), - p99CpuSec: percentile(cpus, 0.99), - p90RealSec: percentile(reals, 0.9), - p99RealSec: percentile(reals, 0.99), - } -} - -function preparedRows(measurement, repeatMeasurements, baselineMeasurement, baselineRepeatMeasurements) { - if (!measurement.report && repeatMeasurements.length === 0) { - return [] - } - const modes = new Set() - for (const run of measurement.report?.runs ?? []) { - modes.add(run.mode) - } - for (const repeat of repeatMeasurements) { - for (const run of repeat.report?.runs ?? []) { - modes.add(run.mode) - } - } - return [...modes].map((mode) => { - const summary = repeatedPreparedSummary(measurement, repeatMeasurements, mode) - const baseline = repeatedPreparedSummary( - baselineMeasurement, - baselineRepeatMeasurements, - preparedBaselineMode(mode), - ) - return `| ${mode} | ${summary.n} | ${fmtSecFromMicros(summary.numericP50Micros)} | ${fmtSecFromMicros(summary.numericP90Micros)} | ${fmtSecFromMicros(summary.numericP95Micros)} | ${fmtSecFromMicros(summary.numericP99Micros)} | ${fmtRatio(summary.numericP90Micros, baseline.numericP90Micros)} | ${fmtSecFromMicros(summary.textP50Micros)} | ${fmtSecFromMicros(summary.textP90Micros)} | ${fmtSecFromMicros(summary.textP95Micros)} | ${fmtSecFromMicros(summary.textP99Micros)} | ${fmtRatio(summary.textP90Micros, baseline.textP90Micros)} | ${fmtMb(summary.p90RssMb)} | ${fmtMb(summary.p99RssMb)} | ${fmtMb(summary.p90FootprintMb)} | ${fmtMb(summary.p99FootprintMb)} | ${fmtSec(summary.p90CpuSec)} | ${fmtSec(summary.p99CpuSec)} | ${fmtSec(summary.p90RealSec)} | ${fmtSec(summary.p99RealSec)} |` - }) -} - -async function main() { - const args = parseArgs(process.argv.slice(2)) - const runDir = requireArg(args, '--run-dir') - const runId = requireArg(args, '--run-id') - const postgresVersion = requireArg(args, '--postgres-version') - const durability = args['--durability'] ?? 'safe' - const runtimeFootprint = args['--runtime-footprint'] ?? 'throughput' - const startupGucs = args['--startup-gucs'] ?? '' - - const nativeLibRtt = await loadMeasuredRun(runDir, 'native-liboliphaunt-rtt') - const nativeLibSpeed = await loadMeasuredRun(runDir, 'native-liboliphaunt-speed') - const nativeLibStreaming = await loadMeasuredRun(runDir, 'native-liboliphaunt-streaming') - const nativeLibBackup = await loadMeasuredRun(runDir, 'native-liboliphaunt-backup') - const nativeBrokerRtt = await loadMeasuredRun(runDir, 'native-liboliphaunt-broker-rtt') - const nativeBrokerSpeed = await loadMeasuredRun(runDir, 'native-liboliphaunt-broker-speed') - const nativeBrokerStreaming = await loadMeasuredRun(runDir, 'native-liboliphaunt-broker-streaming') - const nativeBrokerBackup = await loadMeasuredRun(runDir, 'native-liboliphaunt-broker-backup') - const nativeServerRtt = await loadMeasuredRun(runDir, 'native-liboliphaunt-server-rtt') - const nativeServerSpeed = await loadMeasuredRun(runDir, 'native-liboliphaunt-server-speed') - const nativeServerStreaming = await loadMeasuredRun(runDir, 'native-liboliphaunt-server-streaming') - const nativeTokioRtt = await loadFirstMeasuredRun(runDir, [ - 'native-postgres-tokio-all', - 'native-postgres-tokio-rtt', - ]) - const nativeTokioSpeed = await loadFirstMeasuredRun(runDir, [ - 'native-postgres-tokio-all', - 'native-postgres-tokio-speed', - ]) - const nativeSqlxRtt = await loadFirstMeasuredRun(runDir, [ - 'native-postgres-sqlx-all', - 'native-postgres-sqlx-rtt', - ]) - const nativeSqlxSpeed = await loadFirstMeasuredRun(runDir, [ - 'native-postgres-sqlx-all', - 'native-postgres-sqlx-speed', - ]) - const nativePostgresStreaming = await loadMeasuredRun(runDir, 'native-postgres-streaming') - const nativePostgresBackup = await loadMeasuredRun(runDir, 'native-postgres-backup') - const sqliteSpeed = await loadMeasuredRun(runDir, 'sqlite-speed') - const sqliteBackup = await loadMeasuredRun(runDir, 'sqlite-backup') - const artifactSizes = await readJsonIfExists(path.join(runDir, 'artifact-sizes.json')) - const provenance = await readJsonIfExists(path.join(runDir, 'provenance.json')) - const pgdataCopyMode = args['--pgdata-copy-mode'] ?? provenance?.benchmark?.pgdataCopyMode ?? 'n/a' - const selectedNativeEngines = args['--native-engines'] ?? provenance?.benchmark?.nativeEngines?.join(',') ?? 'direct,broker,server' - const selectedSuites = args['--suites'] ?? provenance?.benchmark?.suites?.join(',') ?? 'rtt,speed,streaming,prepared,backup' - const isPartialCoverage = - boolValue(args['--partial-report']) ?? - provenance?.benchmark?.quality?.partialReport ?? - (selectedNativeEngines !== 'direct,broker,server' || - selectedSuites !== 'rtt,speed,streaming,prepared,backup') - const releaseMinimums = provenance?.benchmark?.quality?.releaseMinimums ?? { - rttIterations: 100, - rttRepeats: 10, - preparedRows: 25000, - preparedRepeats: 10, - speedRepeats: 20, - backupRepeats: 10, - } - const rttRepeats = Number(args['--rtt-repeats'] ?? provenance?.benchmark?.rttRepeats ?? '1') - const speedRepeats = Number(args['--speed-repeats'] ?? provenance?.benchmark?.speedRepeats ?? '1') - const backupRepeats = Number(args['--backup-repeats'] ?? provenance?.benchmark?.backupRepeats ?? '1') - const preparedRepeats = Number(args['--prepared-repeats'] ?? provenance?.benchmark?.preparedRepeats ?? '1') - const releaseEvidenceInput = - boolValue(args['--release-evidence']) ?? provenance?.benchmark?.quality?.releaseEvidence ?? null - const releaseEvidence = - releaseEvidenceInput ?? - (!isPartialCoverage && - Number(args['--rtt-iterations'] ?? provenance?.benchmark?.rttIterations ?? '0') >= - releaseMinimums.rttIterations && - rttRepeats >= releaseMinimums.rttRepeats && - Number(args['--prepared-rows'] ?? provenance?.benchmark?.preparedRows ?? '0') >= - releaseMinimums.preparedRows && - preparedRepeats >= releaseMinimums.preparedRepeats && - speedRepeats >= releaseMinimums.speedRepeats && - backupRepeats >= (releaseMinimums.backupRepeats ?? 10)) - const nativePostgresPrepared = await loadMeasuredRun(runDir, 'native-postgres-prepared') - const nativePreparedDirect = await loadMeasuredRun(runDir, 'native-liboliphaunt-prepared-direct') - const nativePreparedBroker = await loadMeasuredRun(runDir, 'native-liboliphaunt-prepared-broker') - const nativePreparedServer = await loadMeasuredRun(runDir, 'native-liboliphaunt-prepared-server') - const nativeBackupDirectRepeats = await loadBackupRepeatMeasurements(runDir, 'native-liboliphaunt-backup-') - const nativeBackupBrokerRepeats = await loadBackupRepeatMeasurements(runDir, 'native-liboliphaunt-broker-backup-') - const nativePostgresBackupRepeats = await loadBackupRepeatMeasurements(runDir, 'native-postgres-backup-', 'native_postgres') - const nativePostgresPhysicalBackupRepeats = await loadBackupRepeatMeasurements(runDir, 'native-postgres-backup-', 'native_postgres_physical') - const sqliteBackupRepeats = await loadBackupRepeatMeasurements(runDir, 'sqlite-backup-') - const nativePostgresPreparedRepeats = await loadPreparedRepeatMeasurements(runDir, 'native-postgres-prepared-') - const nativePreparedDirectRepeats = await loadPreparedRepeatMeasurements(runDir, 'native-liboliphaunt-prepared-direct-') - const nativePreparedBrokerRepeats = await loadPreparedRepeatMeasurements(runDir, 'native-liboliphaunt-prepared-broker-') - const nativePreparedServerRepeats = await loadPreparedRepeatMeasurements(runDir, 'native-liboliphaunt-prepared-server-') - - const rttModes = [ - { - label: 'Native liboliphaunt direct', - run: collectRun(nativeLibRtt.report, 'rtt', 'native_liboliphaunt_direct'), - resource: nativeLibRtt.resource, - repeats: await loadRttRepeatMeasurements(runDir, 'native-liboliphaunt-rtt-', 'native_liboliphaunt_direct'), - }, - { - label: 'Native liboliphaunt broker', - run: collectRun(nativeBrokerRtt.report, 'rtt', 'native_liboliphaunt_broker'), - resource: nativeBrokerRtt.resource, - repeats: await loadRttRepeatMeasurements(runDir, 'native-liboliphaunt-broker-rtt-', 'native_liboliphaunt_broker'), - }, - { - label: 'Native liboliphaunt server', - run: collectRun(nativeServerRtt.report, 'rtt', 'native_liboliphaunt_server'), - resource: nativeServerRtt.resource, - repeats: await loadRttRepeatMeasurements(runDir, 'native-liboliphaunt-server-rtt-', 'native_liboliphaunt_server'), - }, - { - label: 'Native Postgres tokio simple', - run: collectRun(nativeTokioRtt.report, 'rtt', 'native_postgres'), - resource: nativeTokioRtt.resource, - repeats: await loadRttRepeatMeasurements(runDir, 'native-postgres-tokio-rtt-', 'native_postgres'), - }, - { - label: 'Native Postgres SQLx', - run: collectRun(nativeSqlxRtt.report, 'rtt', 'native_postgres_sqlx'), - resource: nativeSqlxRtt.resource, - repeats: [], - }, - ] - - const speedModes = [ - { - label: 'Native liboliphaunt direct', - run: collectRun(nativeLibSpeed.report, 'speed', 'native_liboliphaunt_direct'), - resource: nativeLibSpeed.resource, - repeats: await loadSpeedRepeatMeasurements(runDir, 'native-liboliphaunt-speed-'), - }, - { - label: 'Native liboliphaunt broker', - run: collectRun(nativeBrokerSpeed.report, 'speed', 'native_liboliphaunt_broker'), - resource: nativeBrokerSpeed.resource, - repeats: await loadSpeedRepeatMeasurements(runDir, 'native-liboliphaunt-broker-speed-'), - }, - { - label: 'Native liboliphaunt server', - run: collectRun(nativeServerSpeed.report, 'speed', 'native_liboliphaunt_server'), - resource: nativeServerSpeed.resource, - repeats: await loadSpeedRepeatMeasurements(runDir, 'native-liboliphaunt-server-speed-'), - }, - { - label: 'Native Postgres tokio simple', - run: collectRun(nativeTokioSpeed.report, 'speed', 'native_postgres'), - resource: nativeTokioSpeed.resource, - repeats: await loadSpeedRepeatMeasurements(runDir, 'native-postgres-tokio-speed-'), - }, - { - label: 'Native Postgres SQLx', - run: collectRun(nativeSqlxSpeed.report, 'speed', 'native_postgres_sqlx'), - resource: nativeSqlxSpeed.resource, - repeats: [], - }, - { - label: 'SQLite embedded', - run: collectRun(sqliteSpeed.report, 'speed', 'sqlite'), - resource: sqliteSpeed.resource, - repeats: await loadSpeedRepeatMeasurements(runDir, 'sqlite-speed-'), - }, - ] - const activeSpeedModes = speedModes.filter((mode) => mode.run) - const streamingModes = [ - ['Native liboliphaunt direct', collectRun(nativeLibStreaming.report, 'streaming', 'native_liboliphaunt_direct'), nativeLibStreaming.resource], - ['Native liboliphaunt broker', collectRun(nativeBrokerStreaming.report, 'streaming', 'native_liboliphaunt_broker'), nativeBrokerStreaming.resource], - ['Native liboliphaunt server', collectRun(nativeServerStreaming.report, 'streaming', 'native_liboliphaunt_server'), nativeServerStreaming.resource], - ['Native Postgres raw', collectRun(nativePostgresStreaming.report, 'streaming', 'native_postgres_raw'), nativePostgresStreaming.resource], - ] - const backupModes = [ - { - label: 'Native liboliphaunt direct', - run: collectRun(nativeLibBackup.report, 'backup-restore', 'native_liboliphaunt_direct'), - resource: nativeLibBackup.resource, - repeats: nativeBackupDirectRepeats, - }, - { - label: 'Native liboliphaunt broker', - run: collectRun(nativeBrokerBackup.report, 'backup-restore', 'native_liboliphaunt_broker'), - resource: nativeBrokerBackup.resource, - repeats: nativeBackupBrokerRepeats, - }, - { - label: 'Native Postgres physical archive', - run: collectRun(nativePostgresBackup.report, 'backup-restore', 'native_postgres_physical'), - resource: nativePostgresBackup.resource, - repeats: nativePostgresPhysicalBackupRepeats, - }, - { - label: 'Native Postgres pg_dump/pg_restore', - run: collectRun(nativePostgresBackup.report, 'backup-restore', 'native_postgres'), - resource: nativePostgresBackup.resource, - repeats: nativePostgresBackupRepeats, - }, - { - label: 'SQLite VACUUM/file restore', - run: collectRun(sqliteBackup.report, 'backup-restore', 'sqlite'), - resource: sqliteBackup.resource, - repeats: sqliteBackupRepeats, - }, - ] - const nativeDirectSpeed = speedModes[0] - const nativePostgresSpeed = speedModes.find( - (mode) => mode.label === 'Native Postgres tokio simple', - ) - const nativeDirectSpeedSummary = repeatedSpeedSummary( - nativeDirectSpeed.run, - nativeDirectSpeed.resource, - nativeDirectSpeed.repeats, - ) - const nativePostgresSpeedSummary = repeatedSpeedSummary( - nativePostgresSpeed.run, - nativePostgresSpeed.resource, - nativePostgresSpeed.repeats, - ) - const sqliteEmbeddedSpeed = speedModes.find((mode) => mode.label === 'SQLite embedded') - const sqliteEmbeddedSpeedSummary = repeatedSpeedSummary( - sqliteEmbeddedSpeed.run, - sqliteEmbeddedSpeed.resource, - sqliteEmbeddedSpeed.repeats, - ) - const nativeDirectRtt = rttModes[0] - const nativePostgresRtt = rttModes.find( - (mode) => mode.label === 'Native Postgres tokio simple', - ) - const nativeDirectRttSummary = repeatedRttSummary( - nativeDirectRtt.run, - nativeDirectRtt.resource, - nativeDirectRtt.repeats, - ) - const nativePostgresRttSummary = repeatedRttSummary( - nativePostgresRtt.run, - nativePostgresRtt.resource, - nativePostgresRtt.repeats, - ) - const nativeDirectBackupSummary = repeatedSpeedSummary( - backupModes[0].run, - backupModes[0].resource, - backupModes[0].repeats, - ) - const nativePostgresBackupSummary = repeatedSpeedSummary( - backupModes[3].run, - backupModes[3].resource, - backupModes[3].repeats, - ) - const nativeDirectGateRows = [ - { - metric: 'RTT repeat p90 median-p90', - nativeDisplay: `${nativeDirectRttSummary?.gateMedianP90Us ?? 'n/a'} us`, - baselineDisplay: `${nativePostgresRttSummary?.gateMedianP90Us ?? 'n/a'} us`, - ratio: fmtRatio(nativeDirectRttSummary?.gateMedianP90Us, nativePostgresRttSummary?.gateMedianP90Us), - status: gateStatus(nativeDirectRttSummary?.gateMedianP90Us, nativePostgresRttSummary?.gateMedianP90Us), - diagnostic: 'Run focused RTT repeats for direct and native PostgreSQL to confirm the transport tail before changing code.', - }, - { - metric: 'Speed suite p90', - nativeDisplay: `${fmtSecFromMicros(nativeDirectSpeedSummary.p90TotalMicros)} s`, - baselineDisplay: `${fmtSecFromMicros(nativePostgresSpeedSummary.p90TotalMicros)} s`, - ratio: fmtRatio(nativeDirectSpeedSummary.p90TotalMicros, nativePostgresSpeedSummary.p90TotalMicros), - status: gateStatus(nativeDirectSpeedSummary.p90TotalMicros, nativePostgresSpeedSummary.p90TotalMicros), - diagnostic: 'Run `oliphaunt-perf diagnose-speed-cases` for the missed case ids below, then compare with the native PostgreSQL diagnostic engine.', - }, - { - metric: 'Speed tail throughput p10', - nativeDisplay: `${fmtRate(nativeDirectSpeedSummary.tailP10ThroughputPerSecond)} ops/s`, - baselineDisplay: `${fmtRate(nativePostgresSpeedSummary.tailP10ThroughputPerSecond)} ops/s`, - ratio: fmtRatio(nativeDirectSpeedSummary.tailP10ThroughputPerSecond, nativePostgresSpeedSummary.tailP10ThroughputPerSecond), - status: gateStatusHigher(nativeDirectSpeedSummary.tailP10ThroughputPerSecond, nativePostgresSpeedSummary.tailP10ThroughputPerSecond), - diagnostic: 'Run speed-case diagnostics; throughput misses usually need the same per-SQL investigation as speed-suite p90 misses.', - }, - { - metric: 'Speed open p90', - nativeDisplay: `${fmtMsFromMicros(nativeDirectSpeedSummary.p90OpenMicros)} ms`, - baselineDisplay: `${fmtMsFromMicros(nativePostgresSpeedSummary.p90OpenMicros)} ms`, - ratio: fmtRatio(nativeDirectSpeedSummary.p90OpenMicros, nativePostgresSpeedSummary.p90OpenMicros), - status: gateStatus(nativeDirectSpeedSummary.p90OpenMicros, nativePostgresSpeedSummary.p90OpenMicros), - diagnostic: 'Compare runtime-footprint and startup-GUC sweeps; cold open is expected to differ from SQLite but should not regress against native PostgreSQL controls.', - }, - { - metric: 'Speed p90 RSS', - nativeDisplay: `${fmtMb(nativeDirectSpeedSummary.p90RssMb)} MB`, - baselineDisplay: `${fmtMb(nativePostgresSpeedSummary.p90MemoryBaselineRssMb)} MB`, - ratio: fmtRatio(nativeDirectSpeedSummary.p90RssMb, nativePostgresSpeedSummary.p90MemoryBaselineRssMb), - status: gateStatus(nativeDirectSpeedSummary.p90RssMb, nativePostgresSpeedSummary.p90MemoryBaselineRssMb), - diagnostic: 'Run the mobile/runtime-footprint matrix before source cuts; RSS misses should be attributed to specific GUCs first.', - }, - { - metric: 'Backup/restore physical total p90', - nativeDisplay: `${fmtSecFromMicros(nativeDirectBackupSummary.p90TotalMicros)} s`, - baselineDisplay: `${fmtSecFromMicros(nativePostgresBackupSummary.p90TotalMicros)} s`, - ratio: fmtRatio(nativeDirectBackupSummary.p90TotalMicros, nativePostgresBackupSummary.p90TotalMicros), - status: gateStatus(nativeDirectBackupSummary.p90TotalMicros, nativePostgresBackupSummary.p90TotalMicros), - diagnostic: 'Run the backup suite in isolation and inspect physical archive bytes, PGDATA copy mode, and restore verification timings.', - }, - { - metric: 'Backup/restore tail throughput p10', - nativeDisplay: `${fmtMbPerSec(nativeDirectBackupSummary.tailP10ThroughputPerSecond)} MB/s`, - baselineDisplay: `${fmtMbPerSec(nativePostgresBackupSummary.tailP10ThroughputPerSecond)} MB/s`, - ratio: fmtRatio(nativeDirectBackupSummary.tailP10ThroughputPerSecond, nativePostgresBackupSummary.tailP10ThroughputPerSecond), - status: gateStatusHigher(nativeDirectBackupSummary.tailP10ThroughputPerSecond, nativePostgresBackupSummary.tailP10ThroughputPerSecond), - diagnostic: 'Run backup suite isolation; tail throughput misses are usually archive/copy-mode issues rather than SQL execution issues.', - }, - ] - const nativeDirectGateMisses = nativeDirectGateRows.filter((row) => row.status === 'miss') - const firstRttReport = [ - nativeLibRtt, - nativeBrokerRtt, - nativeServerRtt, - nativeTokioRtt, - nativeSqlxRtt, - ].find((measurement) => measurement.report)?.report - const selectedEngineSet = new Set( - selectedNativeEngines.split(',').filter((engine) => engine.length > 0), - ) - const coverageStatus = (measured, selected, detail) => { - if (measured) { - return `measured via ${detail}` - } - return selected ? `selected but missing; expected via ${detail}` : 'not selected' - } - const nativeDirectMeasured = Boolean( - nativeLibRtt.report || - nativeLibSpeed.report || - nativeLibStreaming.report || - nativeLibBackup.report || - nativePreparedDirect.report || - nativeBackupDirectRepeats.length || - nativePreparedDirectRepeats.length, - ) - const nativeBrokerMeasured = Boolean( - nativeBrokerRtt.report || - nativeBrokerSpeed.report || - nativeBrokerStreaming.report || - nativeBrokerBackup.report || - nativePreparedBroker.report || - nativeBackupBrokerRepeats.length || - nativePreparedBrokerRepeats.length, - ) - const nativeServerMeasured = Boolean( - nativeServerRtt.report || - nativeServerSpeed.report || - nativeServerStreaming.report || - nativePreparedServer.report || - nativePreparedServerRepeats.length, - ) - - const lines = [] - lines.push(`# Native liboliphaunt Perf Matrix ${runId}`) - lines.push('') - lines.push(`Run directory: \`${runDir}\``) - lines.push('') - lines.push('## Method') - lines.push('') - lines.push('- Release binary: `target/release/oliphaunt-perf`; Cargo build time is excluded from benchmark timings.') - lines.push(`- Native control: \`${postgresVersion}\`.`) - lines.push('- Native direct: `oliphaunt` with one embedded PostgreSQL backend per benchmark process.') - lines.push('- Native broker: `oliphaunt` helper-process mode with local IPC to one embedded PostgreSQL backend.') - lines.push('- Native server: `oliphaunt` true local PostgreSQL server mode.') - lines.push(`- Native durability profile: \`${durability}\`.`) - lines.push(`- Native runtime footprint profile: \`${runtimeFootprint}\`.`) - if (startupGucs.length > 0) { - lines.push(`- Native startup GUC overrides: \`${startupGucs}\`.`) - } - lines.push(`- Cluster-seed hydration: \`${pgdataCopyMode}\`.`) - lines.push(`- Selected native engines: \`${selectedNativeEngines}\`.`) - lines.push(`- Selected suites: \`${selectedSuites}\`.`) - lines.push( - `- Run classification: ${ - releaseEvidence === true - ? 'release evidence' - : 'diagnostic; do not use for release claims without a default release-evidence matrix' - }.`, - ) - if (isPartialCoverage) { - lines.push('- Coverage scope: partial focused run; use the default all-engine/all-suite matrix for release evidence.') - } - lines.push('- Speed source: exact Oliphaunt fixture SQL files from `benchmarks/native/sql`.') - lines.push(`- RTT samples per case: ${firstRttReport?.rttIterations ?? 'n/a'}.`) - lines.push(`- RTT repeats: ${rttRepeats}. When repeats are present, RTT summary columns report p50 across fresh-process run summaries and the native direct gate uses p90 across repeated median-p90 RTT summaries.`) - lines.push(`- Prepared-update repeats: ${preparedRepeats}. Prepared rows report p50/p90/p95/p99 across fresh-process prepared-update suite runs when repeats are present.`) - lines.push(`- Speed repeats: ${speedRepeats}. p50/p90/p95/p99 collapse fresh-process suite totals when repeats are present; speed case rows use per-case p90 when repeats are present.`) - lines.push(`- Backup/restore repeats: ${backupRepeats}. Backup rows report p50/p90/p95/p99 across fresh-process physical archive or control backup/restore runs when repeats are present.`) - lines.push( - `- Release-evidence minimums: ${releaseMinimums.rttIterations} RTT samples, ${releaseMinimums.rttRepeats} RTT repeats, ${releaseMinimums.preparedRows} prepared rows, ${releaseMinimums.preparedRepeats} prepared repeats, ${releaseMinimums.speedRepeats} speed repeats, and ${releaseMinimums.backupRepeats ?? 10} backup/restore repeats across the default all-engine/all-suite matrix.`, - ) - lines.push('- Resource metrics come from `/usr/bin/time`; RSS and peak footprint are process-level values. Native broker/server `observed server RSS` is sampled separately from child process trees during xtask execution.') - if (provenance) { - lines.push(`- Provenance: \`provenance.json\` records source/artifact SHA-256s. Verify with \`node tools/perf/matrix/native_oliphaunt_provenance.mjs verify --run-dir ${runDir}\`.`) - } else { - lines.push('- Provenance: no `provenance.json` was found; rerun the matrix with the current harness before using this report as release evidence.') - } - lines.push('') - lines.push('## Coverage') - lines.push('') - lines.push('| Mode | Status |') - lines.push('| --- | --- |') - lines.push(`| NativeDirect | ${coverageStatus(nativeDirectMeasured, selectedEngineSet.has('direct'), 'native liboliphaunt')} |`) - lines.push(`| NativeBroker | ${coverageStatus(nativeBrokerMeasured, selectedEngineSet.has('broker'), 'oliphaunt broker helper process')} |`) - lines.push(`| NativeServer | ${coverageStatus(nativeServerMeasured, selectedEngineSet.has('server'), 'oliphaunt local PostgreSQL server mode; native PostgreSQL control remains the baseline')} |`) - if (sqliteSpeed.report) { - lines.push('| SQLite embedded | measured through rusqlite |') - } - lines.push('') - lines.push('## RTT Summary') - lines.push('') - lines.push('| Mode | n | open p50 ms | open p90 ms | connect p50 ms | median p50 us | median p90 us | gate p90 us | median p95 us | median p99 us | max p90 us | max p99 us | peak RSS MB | observed server RSS MB | CPU s |') - lines.push('| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |') - for (const mode of rttModes) { - if (!mode.run) { - continue - } - const summary = repeatedRttSummary(mode.run, mode.resource, mode.repeats) - lines.push( - `| ${mode.label} | ${summary.n} | ${fmtMsFromMicros(summary.openMicros)} | ${fmtMsFromMicros(summary.openP90Micros)} | ${fmtMsFromMicros(summary.connectMicros)} | ${summary.medianP50Us ?? 'n/a'} | ${summary.medianP90Us ?? 'n/a'} | ${summary.gateMedianP90Us ?? 'n/a'} | ${summary.medianP95Us ?? 'n/a'} | ${summary.medianP99Us ?? 'n/a'} | ${summary.maxP90Us ?? 'n/a'} | ${summary.maxP99Us ?? 'n/a'} | ${fmtMb(summary.peakRssMb)} | ${fmtMb(summary.observedServerPeakRssMb)} | ${fmtSec(summary.cpuSec)} |`, - ) - } - lines.push('') - lines.push('## Speed Summary') - lines.push('') - lines.push('| Mode | n | suite p50 s | suite p90 s | suite p95 s | suite p99 s | throughput p50 ops/s | tail throughput p10 ops/s | open p50 ms | open p90 ms | open p99 ms | p90 RSS MB | p99 RSS MB | p90 observed server RSS MB | p99 observed server RSS MB | p90 footprint MB | p99 footprint MB | p90 CPU s | p99 CPU s |') - lines.push('| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |') - for (const mode of speedModes) { - if (!mode.run) { - continue - } - const summary = repeatedSpeedSummary(mode.run, mode.resource, mode.repeats) - lines.push( - `| ${mode.label} | ${summary.n} | ${fmtSecFromMicros(summary.p50TotalMicros)} | ${fmtSecFromMicros(summary.p90TotalMicros)} | ${fmtSecFromMicros(summary.p95TotalMicros)} | ${fmtSecFromMicros(summary.p99TotalMicros)} | ${fmtRate(summary.p50ThroughputPerSecond)} | ${fmtRate(summary.tailP10ThroughputPerSecond)} | ${fmtMsFromMicros(summary.p50OpenMicros)} | ${fmtMsFromMicros(summary.p90OpenMicros)} | ${fmtMsFromMicros(summary.p99OpenMicros)} | ${fmtMb(summary.p90RssMb)} | ${fmtMb(summary.p99RssMb)} | ${fmtMb(summary.p90ObservedServerRssMb)} | ${fmtMb(summary.p99ObservedServerRssMb)} | ${fmtMb(summary.p90FootprintMb)} | ${fmtMb(summary.p99FootprintMb)} | ${fmtSec(summary.p90CpuSec)} | ${fmtSec(summary.p99CpuSec)} |`, - ) - } - lines.push('') - lines.push('## Backup/Restore Summary') - lines.push('') - lines.push('| Mode | n | total p50 s | total p90 s | total p95 s | total p99 s | payload p50 MB | throughput p50 MB/s | tail throughput p10 MB/s | open p50 ms | open p90 ms | open p99 ms | p90 RSS MB | p99 RSS MB | p90 observed server RSS MB | p99 observed server RSS MB | p90 footprint MB | p99 footprint MB | p90 CPU s | p99 CPU s |') - lines.push('| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |') - for (const mode of backupModes) { - if (!mode.run) { - continue - } - const summary = repeatedSpeedSummary(mode.run, mode.resource, mode.repeats) - const payloadBytes = Number.isFinite(summary.p50OperationCount) - ? summary.p50OperationCount / 2 - : null - lines.push( - `| ${mode.label} | ${summary.n} | ${fmtSecFromMicros(summary.p50TotalMicros)} | ${fmtSecFromMicros(summary.p90TotalMicros)} | ${fmtSecFromMicros(summary.p95TotalMicros)} | ${fmtSecFromMicros(summary.p99TotalMicros)} | ${fmtMbFromBytes(payloadBytes)} | ${fmtMbPerSec(summary.p50ThroughputPerSecond)} | ${fmtMbPerSec(summary.tailP10ThroughputPerSecond)} | ${fmtMsFromMicros(summary.p50OpenMicros)} | ${fmtMsFromMicros(summary.p90OpenMicros)} | ${fmtMsFromMicros(summary.p99OpenMicros)} | ${fmtMb(summary.p90RssMb)} | ${fmtMb(summary.p99RssMb)} | ${fmtMb(summary.p90ObservedServerRssMb)} | ${fmtMb(summary.p99ObservedServerRssMb)} | ${fmtMb(summary.p90FootprintMb)} | ${fmtMb(summary.p99FootprintMb)} | ${fmtSec(summary.p90CpuSec)} | ${fmtSec(summary.p99CpuSec)} |`, - ) - } - lines.push('') - lines.push('## Run Quality') - lines.push('') - lines.push('| Mode | n | min s | p50 s | p90/p50 | p95/p50 | p99/p50 | max s | status | reason |') - lines.push('| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | --- |') - for (const mode of speedModes) { - if (!mode.run) { - continue - } - const summary = repeatedSpeedSummary(mode.run, mode.resource, mode.repeats) - const quality = runQuality(summary) - lines.push( - `| ${mode.label} | ${summary.n} | ${fmtSecFromMicros(summary.minTotalMicros)} | ${fmtSecFromMicros(summary.p50TotalMicros)} | ${fmtRatio(summary.p90TotalMicros, summary.p50TotalMicros)} | ${fmtRatio(summary.p95TotalMicros, summary.p50TotalMicros)} | ${fmtRatio(summary.p99TotalMicros, summary.p50TotalMicros)} | ${fmtSecFromMicros(summary.maxTotalMicros)} | ${quality.status} | ${quality.reason} |`, - ) - } - lines.push('') - lines.push('## Slowest Speed Repeats') - lines.push('') - lines.push('Use this table to distinguish host-wide pauses from engine-specific tail events. Repeated indices that recur across engines usually indicate host noise; isolated rows point at an engine path that needs focused diagnostics.') - lines.push('') - lines.push('| Mode | Repeat | suite s | ratio vs mode p50 | open ms |') - lines.push('| --- | --- | ---: | ---: | ---: |') - lines.push(...slowestRepeatRows(speedModes)) - lines.push('') - if (artifactSizes?.artifacts?.length) { - lines.push('## Artifact Sizes') - lines.push('') - lines.push('| Artifact | Size | Path |') - lines.push('| --- | ---: | --- |') - for (const artifact of artifactSizes.artifacts) { - lines.push(`| ${artifact.name} | ${fmtBytes(artifact.bytes)} | \`${artifact.path}\` |`) - } - lines.push('') - } - if (provenance) { - lines.push('## Provenance') - lines.push('') - lines.push('| Item | Value |') - lines.push('| --- | --- |') - lines.push(`| Generated | ${provenance.generatedAt ?? 'n/a'} |`) - lines.push(`| Git commit | \`${shortSha(provenance.repo?.commit)}\` |`) - lines.push(`| Tracked dirty | ${provenance.repo?.dirtyTracked ? 'yes' : 'no'} |`) - lines.push(`| Source set SHA-256 | \`${shortSha(provenance.source?.sourceSetSha256)}\` |`) - lines.push(`| Source files | ${provenance.source?.entries?.length ?? 'n/a'} |`) - lines.push(`| PGDATA copy mode | \`${provenance.benchmark?.pgdataCopyMode ?? 'n/a'}\` |`) - lines.push('') - if (provenance.artifacts?.length) { - lines.push('| Artifact | SHA-256 | Path |') - lines.push('| --- | --- | --- |') - for (const artifact of provenance.artifacts) { - lines.push( - `| ${artifact.name} | \`${shortSha(artifact.sha256)}\` | \`${artifact.path}\` |`, - ) - } - lines.push('') - } - } - lines.push('## Native Direct Gate') - lines.push('') - lines.push('| Metric | Native liboliphaunt direct | Native Postgres control | Ratio | Status |') - lines.push('| --- | ---: | ---: | ---: | --- |') - for (const row of nativeDirectGateRows) { - lines.push( - `| ${row.metric} | ${row.nativeDisplay} | ${row.baselineDisplay} | ${row.ratio} | ${row.status} |`, - ) - } - lines.push('') - if (sqliteEmbeddedSpeed?.run) { - lines.push('## SQLite Comparison') - lines.push('') - lines.push('| Metric | Native liboliphaunt direct | SQLite embedded | Ratio |') - lines.push('| --- | ---: | ---: | ---: |') - lines.push( - `| Speed suite p90 | ${fmtSecFromMicros(nativeDirectSpeedSummary.p90TotalMicros)} s | ${fmtSecFromMicros(sqliteEmbeddedSpeedSummary.p90TotalMicros)} s | ${fmtRatio(nativeDirectSpeedSummary.p90TotalMicros, sqliteEmbeddedSpeedSummary.p90TotalMicros)} |`, - ) - lines.push( - `| Speed tail throughput p10 | ${fmtRate(nativeDirectSpeedSummary.tailP10ThroughputPerSecond)} ops/s | ${fmtRate(sqliteEmbeddedSpeedSummary.tailP10ThroughputPerSecond)} ops/s | ${fmtRatio(nativeDirectSpeedSummary.tailP10ThroughputPerSecond, sqliteEmbeddedSpeedSummary.tailP10ThroughputPerSecond)} |`, - ) - lines.push( - `| Speed open p90 | ${fmtMsFromMicros(nativeDirectSpeedSummary.p90OpenMicros)} ms | ${fmtMsFromMicros(sqliteEmbeddedSpeedSummary.p90OpenMicros)} ms | ${fmtRatio(nativeDirectSpeedSummary.p90OpenMicros, sqliteEmbeddedSpeedSummary.p90OpenMicros)} |`, - ) - lines.push( - `| Speed p90 RSS | ${fmtMb(nativeDirectSpeedSummary.p90RssMb)} MB | ${fmtMb(sqliteEmbeddedSpeedSummary.p90RssMb)} MB | ${fmtRatio(nativeDirectSpeedSummary.p90RssMb, sqliteEmbeddedSpeedSummary.p90RssMb)} |`, - ) - lines.push('') - } - const speedGateMissDetails = speedCaseGateMisses(nativeDirectSpeed, nativePostgresSpeed) - const gateMisses = speedGateMissDetails.map( - (miss) => - `| ${miss.id} | ${miss.label} | ${fmtMsFromMicros(miss.nativeMicros)} | ${fmtMsFromMicros(miss.baselineMicros)} | ${fmtRatio(miss.nativeMicros, miss.baselineMicros)} |`, - ) - if (gateMisses.length === 0) { - lines.push('- No speed case misses above the 5% native PostgreSQL tolerance.') - } else { - lines.push('Speed case misses above the 5% native PostgreSQL tolerance:') - lines.push('') - lines.push('| ID | Test | Native liboliphaunt direct p90 ms | Native Postgres tokio simple p90 ms | Ratio |') - lines.push('| --- | --- | ---: | ---: | ---: |') - lines.push(...gateMisses) - } - lines.push('') - if (nativeDirectGateMisses.length || speedGateMissDetails.length) { - lines.push('## Native Direct Regression Diagnostics') - lines.push('') - lines.push( - 'Run these diagnostics before changing PostgreSQL patches or source/build flags. They keep direct-mode regressions tied to a measured suite, case id, or runtime GUC instead of broad speculation.', - ) - lines.push('') - if (nativeDirectGateMisses.length) { - lines.push('| Missed gate | Diagnostic action |') - lines.push('| --- | --- |') - for (const miss of nativeDirectGateMisses) { - lines.push(`| ${miss.metric} | ${miss.diagnostic} |`) - } - lines.push('') - } - if (speedGateMissDetails.length) { - const ids = speedGateMissDetails.map((miss) => miss.id).join(',') - lines.push('Speed-case diagnostic commands:') - lines.push('') - lines.push('```sh') - lines.push( - `tools/perf/matrix/run_native_speed_diagnostics.sh --ids ${ids} --repeats 10 --skip-build`, - ) - lines.push( - `cargo run --release -p oliphaunt-perf -- diagnose-speed-cases --engine native-liboliphaunt --ids ${ids}`, - ) - lines.push( - `cargo run --release -p oliphaunt-perf -- diagnose-speed-cases --engine native-postgres --ids ${ids}`, - ) - lines.push('```') - lines.push('') - } - if (nativeDirectGateMisses.some((miss) => miss.metric.includes('RTT'))) { - lines.push('RTT tail diagnostic command:') - lines.push('') - lines.push('```sh') - lines.push( - 'tools/perf/matrix/run_native_oliphaunt_matrix.sh --quick --engines direct --suites rtt --skip-sqlite --skip-prepared', - ) - lines.push('```') - lines.push('') - } - if (nativeDirectGateMisses.some((miss) => miss.metric.includes('RSS') || miss.metric.includes('open'))) { - lines.push('Runtime-footprint diagnostic command:') - lines.push('') - lines.push('```sh') - lines.push( - 'tools/perf/matrix/run_native_oliphaunt_matrix.sh --quick --engines direct --suites speed --runtime-footprint balanced-mobile --startup-guc shared_buffers=32MB --startup-guc wal_buffers=-1 --skip-sqlite --skip-prepared', - ) - lines.push('```') - lines.push('') - } - if (nativeDirectGateMisses.some((miss) => miss.metric.includes('Backup/restore'))) { - lines.push('Backup/restore diagnostic command:') - lines.push('') - lines.push('```sh') - lines.push( - 'tools/perf/matrix/run_native_oliphaunt_matrix.sh --quick --engines direct --suites backup --skip-sqlite --skip-prepared', - ) - lines.push('```') - lines.push('') - } - } - lines.push('') - lines.push('## Speed Cases') - lines.push('') - if (activeSpeedModes.length) { - lines.push( - `| ID | Test | ${activeSpeedModes.map((mode) => `${mode.label} p90 ms`).join(' | ')} |`, - ) - lines.push(`| --- | --- | ${activeSpeedModes.map(() => '---:').join(' | ')} |`) - lines.push(...speedCaseRows(activeSpeedModes)) - } else { - lines.push('No speed suite measurements were selected for this run.') - } - lines.push('') - lines.push('## Streaming') - lines.push('') - lines.push('| Mode | open ms | case | elapsed ms | bytes | peak RSS MB | observed server RSS MB | CPU s |') - lines.push('| --- | ---: | --- | ---: | ---: | ---: | ---: | ---: |') - for (const [label, run, resource] of streamingModes) { - if (!run) { - continue - } - for (const test of run.tests) { - lines.push( - `| ${label} | ${fmtMsFromMicros(run.openMicros)} | ${test.id} | ${fmtMsFromMicros(test.elapsedMicros)} | ${test.operationCount ?? 'n/a'} | ${fmtMb(resource.peakRssMb)} | ${fmtMb(run.observedServerPeakRssBytes ? run.observedServerPeakRssBytes / 1024 / 1024 : undefined)} | ${fmtSec(resource.cpuSec)} |`, - ) - } - } - lines.push('') - lines.push('## Prepared Updates') - lines.push('') - lines.push('| Mode | n | numeric p50 s | numeric p90 s | numeric p95 s | numeric p99 s | numeric p90/native | text p50 s | text p90 s | text p95 s | text p99 s | text p90/native | p90 command RSS MB | p99 command RSS MB | p90 command footprint MB | p99 command footprint MB | p90 command CPU s | p99 command CPU s | p90 command wall s | p99 command wall s |') - lines.push('| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |') - lines.push(...preparedRows(nativePostgresPrepared, nativePostgresPreparedRepeats, nativePostgresPrepared, nativePostgresPreparedRepeats)) - lines.push(...preparedRows(nativePreparedDirect, nativePreparedDirectRepeats, nativePostgresPrepared, nativePostgresPreparedRepeats)) - lines.push(...preparedRows(nativePreparedBroker, nativePreparedBrokerRepeats, nativePostgresPrepared, nativePostgresPreparedRepeats)) - lines.push(...preparedRows(nativePreparedServer, nativePreparedServerRepeats, nativePostgresPrepared, nativePostgresPreparedRepeats)) - lines.push('') - lines.push('## Notes') - lines.push('') - lines.push('- Native liboliphaunt v1 is deliberately process-lifetime scoped; same-process reopen is not measured as a supported path.') - lines.push('- Native broker and native server are measured as their own SDK modes. No direct-mode multiplexing is counted as broker or server performance.') - lines.push('- Native PostgreSQL `observed server RSS` is sampled from the live server process tree during each suite. It is reported separately from `/usr/bin/time` process RSS because the control server runs out of process.') - lines.push('- SQLite embedded uses the same durability label mapped to explicit SQLite PRAGMAs inside xtask; it is a product comparison baseline, not the release gate for PostgreSQL execution parity.') - lines.push('- Compare direct mode with native PostgreSQL simple-query controls for backend execution parity; SQLx rows include client abstraction overhead.') - lines.push('') - - console.log(lines.join('\n')) -} - -main().catch((error) => { - console.error(error) - process.exitCode = 1 -}) diff --git a/tools/perf/matrix/summarize_native_speed_diagnostics.mjs b/tools/perf/matrix/summarize_native_speed_diagnostics.mjs deleted file mode 100644 index d51ec2f73..000000000 --- a/tools/perf/matrix/summarize_native_speed_diagnostics.mjs +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env node -import fs from 'node:fs/promises' -import path from 'node:path' -import process from 'node:process' - -function usage() { - console.error(`usage: - summarize_native_speed_diagnostics.mjs --run-dir DIR --ids LIST --repeats N`) -} - -function parseArgs(argv) { - const args = {} - for (let index = 0; index < argv.length; index += 1) { - const key = argv[index] - if (!key.startsWith('--')) { - throw new Error(`unexpected argument: ${key}`) - } - const value = argv[index + 1] - if (index + 1 < argv.length && !value.startsWith('--')) { - args[key] = value - index += 1 - } else { - args[key] = 'true' - } - } - return args -} - -function requireArg(args, key) { - const value = args[key] - if (!value || value === 'true') { - throw new Error(`${key} is required`) - } - return value -} - -function parseIds(value) { - const ids = value - .split(',') - .map((id) => id.trim()) - .filter(Boolean) - if (ids.length === 0) { - throw new Error('--ids must contain at least one speed case id') - } - return ids -} - -function parsePositiveInt(value, label) { - const parsed = Number(value) - if (!Number.isInteger(parsed) || parsed <= 0) { - throw new Error(`${label} must be a positive integer`) - } - return parsed -} - -function safeId(id) { - return id.replaceAll('.', '_') -} - -function percentile(values, p) { - if (values.length === 0) { - return null - } - const sorted = [...values].sort((a, b) => a - b) - const index = Math.round((sorted.length - 1) * p) - return sorted[index] -} - -function stats(values) { - return { - n: values.length, - minMicros: percentile(values, 0), - p50Micros: percentile(values, 0.5), - p90Micros: percentile(values, 0.9), - p95Micros: percentile(values, 0.95), - p99Micros: percentile(values, 0.99), - maxMicros: percentile(values, 1), - } -} - -function fmtMs(micros) { - if (micros === null || micros === undefined) { - return 'n/a' - } - return `${(micros / 1000).toFixed(3)}` -} - -function fmtRatio(a, b) { - if (!Number.isFinite(a) || !Number.isFinite(b) || b === 0) { - return 'n/a' - } - return `${(a / b).toFixed(3)}x` -} - -async function readJson(file) { - return JSON.parse(await fs.readFile(file, 'utf8')) -} - -function firstCase(report, id, engine) { - const found = report.cases?.find((item) => item.id === id) - if (!found) { - throw new Error(`${engine} diagnostic report missing case ${id}`) - } - return found -} - -async function main() { - const args = parseArgs(process.argv.slice(2)) - const runDir = path.resolve(requireArg(args, '--run-dir')) - const ids = parseIds(requireArg(args, '--ids')) - const repeats = parsePositiveInt(requireArg(args, '--repeats'), '--repeats') - - const cases = [] - for (const id of ids) { - const direct = [] - const nativePostgres = [] - for (let repeat = 1; repeat <= repeats; repeat += 1) { - const index = String(repeat).padStart(String(repeats).length, '0') - const directReport = await readJson( - path.join(runDir, 'direct', `native-liboliphaunt-speed-case-${safeId(id)}-${index}.json`), - ) - const pgReport = await readJson( - path.join(runDir, 'native-postgres', `native-postgres-speed-cases-${index}.json`), - ) - direct.push(firstCase(directReport, id, 'native-liboliphaunt')) - nativePostgres.push(firstCase(pgReport, id, 'native-postgres')) - } - - const directElapsed = stats(direct.map((item) => item.elapsed_micros)) - const pgElapsed = stats(nativePostgres.map((item) => item.elapsed_micros)) - const directOpen = stats(direct.map((item) => item.open_micros).filter((item) => item !== null)) - const pgOpen = stats(nativePostgres.map((item) => item.open_micros).filter((item) => item !== null)) - const directSetup = stats(direct.map((item) => item.setup_micros)) - const pgSetup = stats(nativePostgres.map((item) => item.setup_micros)) - const directRss = stats( - direct - .map((item) => item.observed_server_peak_rss_bytes) - .filter((item) => Number.isFinite(item)) - .map((item) => Math.round(item / 1024 / 1024 * 1000)), - ) - const pgRss = stats( - nativePostgres - .map((item) => item.observed_server_peak_rss_bytes) - .filter((item) => Number.isFinite(item)) - .map((item) => Math.round(item / 1024 / 1024 * 1000)), - ) - - cases.push({ - id, - label: direct[0].label, - repeats, - operationCount: direct[0].operation_count, - direct: { - elapsed: directElapsed, - open: directOpen, - setup: directSetup, - observedServerRssMbTimes1000: directRss, - settings: direct[0].settings, - }, - nativePostgres: { - elapsed: pgElapsed, - open: pgOpen, - setup: pgSetup, - observedServerRssMbTimes1000: pgRss, - settings: nativePostgres[0].settings, - }, - ratios: { - elapsedP90: directElapsed.p90Micros / pgElapsed.p90Micros, - elapsedP99: directElapsed.p99Micros / pgElapsed.p99Micros, - }, - }) - } - - const summary = { - schema: 'oliphaunt.native-speed-diagnostics.v1', - runDir, - ids, - repeats, - cases, - } - await fs.writeFile(path.join(runDir, 'summary.json'), `${JSON.stringify(summary, null, 2)}\n`) - - const lines = [] - lines.push(`# Native Speed Diagnostics`) - lines.push('') - lines.push(`Run directory: \`${runDir}\``) - lines.push('') - lines.push('| ID | Test | n | Direct p50 ms | Direct p90 ms | Direct p99 ms | Native PG p50 ms | Native PG p90 ms | Native PG p99 ms | p90 ratio | p99 ratio | Direct open p90 ms | Native PG open p90 ms |') - lines.push('| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |') - for (const item of cases) { - lines.push( - `| ${item.id} | ${item.label} | ${item.repeats} | ${fmtMs(item.direct.elapsed.p50Micros)} | ${fmtMs(item.direct.elapsed.p90Micros)} | ${fmtMs(item.direct.elapsed.p99Micros)} | ${fmtMs(item.nativePostgres.elapsed.p50Micros)} | ${fmtMs(item.nativePostgres.elapsed.p90Micros)} | ${fmtMs(item.nativePostgres.elapsed.p99Micros)} | ${fmtRatio(item.direct.elapsed.p90Micros, item.nativePostgres.elapsed.p90Micros)} | ${fmtRatio(item.direct.elapsed.p99Micros, item.nativePostgres.elapsed.p99Micros)} | ${fmtMs(item.direct.open.p90Micros)} | ${fmtMs(item.nativePostgres.open.p90Micros)} |`, - ) - } - lines.push('') - lines.push('## Setup And RSS') - lines.push('') - lines.push('| ID | Direct setup p90 ms | Native PG setup p90 ms | Direct observed RSS p90 MB | Native PG observed RSS p90 MB |') - lines.push('| --- | ---: | ---: | ---: | ---: |') - for (const item of cases) { - lines.push( - `| ${item.id} | ${fmtMs(item.direct.setup.p90Micros)} | ${fmtMs(item.nativePostgres.setup.p90Micros)} | ${fmtMs(item.direct.observedServerRssMbTimes1000.p90Micros)} | ${fmtMs(item.nativePostgres.observedServerRssMbTimes1000.p90Micros)} |`, - ) - } - lines.push('') - lines.push('NativeDirect diagnostics run one fresh process per case/repeat because direct mode owns one process-lifetime embedded backend.') - await fs.writeFile(path.join(runDir, 'summary.md'), `${lines.join('\n')}\n`) -} - -main().catch((error) => { - usage() - console.error(error) - process.exit(1) -}) diff --git a/tools/perf/moon.yml b/tools/perf/moon.yml deleted file mode 100644 index 16fb1dcd5..000000000 --- a/tools/perf/moon.yml +++ /dev/null @@ -1,230 +0,0 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "perf-tools" -language: "rust" -layer: "tool" -stack: "systems" -tags: ["tools", "performance", "bench"] -dependsOn: - - id: "oliphaunt-rust" - scope: "development" - - id: "oliphaunt-wasix-rust" - scope: "development" - - id: "liboliphaunt-wasix" - scope: "development" - - id: "shared-test-fixtures" - scope: "development" - - id: "shared-rust-query-core" - scope: "development" - - id: "benchmarks" - scope: "build" - -project: - title: "Performance Tools" - description: "Native, WASM, mobile, and SQLite benchmark orchestration and reporting." - owner: "oliphaunt" - -owners: - defaultOwner: "@oliphaunt/perf" - paths: - "**/*": ["@oliphaunt/perf"] - -tasks: - rust-api-model-check: - tags: ["bench", "diagnostic", "quality", "requires-rust"] - command: "bash tools/perf/rust-api-model/check.sh" - inputs: - - "@group(cargo-workspace)" - - project: "oliphaunt-rust" - group: "code" - - project: "oliphaunt-wasix-rust" - group: "code" - - project: "liboliphaunt-wasix" - group: "crates" - - project: "shared-rust-query-core" - group: "sources" - - "/tools/dev/bun.sh" - - "/tools/perf/runner/**/*" - - "/tools/perf/rust-api-model/**/*" - options: - cache: true - runFromWorkspaceRoot: true - - rust-api-model-native: - tags: ["bench", "diagnostic", "measured", "requires-rust"] - command: "bash tools/perf/rust-api-model/run.sh --runtime native" - deps: - - "liboliphaunt-native:build-runtime-desktop-target" - inputs: - - "@group(cargo-workspace)" - - "/src/runtimes/liboliphaunt/native/**/*" - - project: "shared-rust-query-core" - group: "sources" - - "/src/sdks/rust/**/*" - - "/tools/perf/runner/**/*" - - "/tools/perf/rust-api-model/**/*" - - "/src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh" - - "/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false - rust-api-model-wasix: - tags: ["bench", "diagnostic", "measured", "requires-rust"] - command: "bash tools/perf/rust-api-model/run.sh --runtime wasix" - deps: - - "liboliphaunt-wasix:runtime-aot" - inputs: - - "@group(cargo-workspace)" - - "/src/bindings/wasix-rust/**/*" - - project: "liboliphaunt-wasix" - group: "crates" - - project: "shared-rust-query-core" - group: "sources" - - "/tools/perf/runner/**/*" - - "/tools/perf/rust-api-model/**/*" - - "/src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh" - - "/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh" - - "/tools/xtask/**/*" - - "/target/oliphaunt-wasix/assets/**/*" - - "/target/oliphaunt-wasix/aot/**/*" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false - native-plan: - tags: ["bench", "plan"] - command: "bash tools/perf/matrix/run_native_oliphaunt_matrix.sh --plan-only" - inputs: - - "/tools/perf/matrix/run_native_oliphaunt_matrix.sh" - options: - cache: true - runFromWorkspaceRoot: true - runInCI: false - native-measure: - tags: ["bench", "measured"] - command: "bash tools/perf/matrix/run_native_oliphaunt_matrix.sh" - deps: - - "liboliphaunt-native:build-runtime-desktop-target" - inputs: - - "@group(cargo-workspace)" - - "/src/runtimes/liboliphaunt/native/**/*" - - "/src/sdks/rust/**/*" - - project: "shared-test-fixtures" - group: "fixtures" - - "/tools/perf/matrix/**/*" - - project: "benchmarks" - group: "native-sql" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false - mobile-plan: - tags: ["bench", "plan"] - command: "bash tools/perf/matrix/run_mobile_footprint_matrix.sh --plan-only --quick" - inputs: - - "/examples/react-native-expo/package.json" - - "/tools/perf/matrix/run_mobile_footprint_matrix.sh" - options: - cache: true - runFromWorkspaceRoot: true - runInCI: false - mobile-measure: - tags: ["bench", "measured"] - command: "bash tools/perf/matrix/run_mobile_footprint_matrix.sh" - inputs: - - "/examples/react-native-expo/**/*" - - "/src/sdks/kotlin/**/*" - - "/src/sdks/react-native/**/*" - - "/src/sdks/swift/**/*" - - project: "shared-test-fixtures" - group: "fixtures" - - "/tools/perf/matrix/**/*" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false - wasix-plan: - tags: ["bench", "plan"] - script: | - set -e - node --test tools/perf/wasix-browser/plan.test.mjs - node --test tools/perf/wasix-node/plan.test.mjs - node --check tools/perf/wasix-browser/plan.mjs - node --check tools/perf/wasix-node/engine-runner.mjs - node --check tools/perf/wasix-node/benchmark.mjs - node --check tools/perf/wasix-node/pglite-node-worker.mjs - node --check src/bindings/wasix-ts/tools/pgwire-client.mjs - node --check tools/perf/wasix-node/rss-sampler-worker.mjs - node --check tools/perf/wasix-node/streaming-quick.mjs - node tools/perf/wasix-node/benchmark.mjs --validate - inputs: - - "@group(pnpm-workspace)" - - "/benchmarks/wasix/**/*" - - "/src/bindings/wasix-ts/host/**/*" - - "/src/bindings/wasix-ts/package.json" - - "/tools/integration/wasix-ts/packed-node-fixture.mjs" - - "/src/bindings/wasix-ts/tools/pgwire-client.mjs" - - "/src/runtimes/wasix-napi/package.json" - - "/tools/perf/wasix-browser/*.mjs" - - "/tools/perf/wasix-node/*.mjs" - - "/tools/perf/wasix-node/package.json" - - "@group(release-archive-contract)" - - "/tools/release/wasix-runtime-npm-*.mjs" - - "/tools/release/wasix-tools-typescript-package.mjs" - - "/tools/release/wasix-typescript-package.mjs" - options: - cache: true - runFromWorkspaceRoot: true - runInCI: false - wasix-node-measure: - tags: ["bench", "measured", "local-only"] - script: | - set -e - pnpm --dir src/bindings/wasix-ts build - node src/bindings/wasix-ts/tools/stage-host.mjs - node tools/perf/wasix-node/benchmark.mjs --run - deps: - - "perf-tools:wasix-plan" - - "liboliphaunt-wasix:runtime-portable" - - "oliphaunt-wasix-ts:browser-host" - inputs: - - "@group(legal-files)" - - "@group(pnpm-workspace)" - - "/benchmarks/wasix/node-pglite-memory-v2.json" - - "/src/bindings/wasix-ts/**/*" - - "/tools/integration/wasix-ts/packed-node-fixture.mjs" - - "/tools/perf/wasix-node/*.mjs" - - "/tools/perf/wasix-node/package.json" - - "@group(release-archive-contract)" - - "/tools/release/wasix-runtime-npm-*.mjs" - - "/tools/release/wasix-tools-typescript-package.mjs" - - "/tools/release/wasix-typescript-package.mjs" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false - wasix-browser-measure: - tags: ["bench", "measured", "browser", "local-only"] - script: | - set -e - pnpm --dir src/bindings/wasix-ts build - node src/bindings/wasix-ts/tools/stage-host.mjs - node tools/integration/wasix-ts/smoke-browser.mjs --benchmark - deps: - - "perf-tools:wasix-plan" - - "liboliphaunt-wasix:runtime-portable" - - "oliphaunt-wasix-ts:browser-host" - inputs: - - "@group(legal-files)" - - "@group(pnpm-workspace)" - - "/benchmarks/wasix/browser-pglite-memory-v2.json" - - "/src/bindings/wasix-ts/**/*" - - "/tools/integration/wasix-ts/*.mjs" - - "/tools/perf/wasix-browser/*.mjs" - - "/tools/perf/wasix-node/installed-closure.mjs" - - "/tools/perf/wasix-node/plan.mjs" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false diff --git a/tools/perf/runner/Cargo.toml b/tools/perf/runner/Cargo.toml deleted file mode 100644 index 5c10adf48..000000000 --- a/tools/perf/runner/Cargo.toml +++ /dev/null @@ -1,34 +0,0 @@ -[package] -name = "oliphaunt-perf" -version = "0.0.0" -edition = "2024" -rust-version = "1.93" -license.workspace = true -publish = false -default-run = "oliphaunt-perf" - -[features] -default = [] -rust-api-model = [] -rust-api-model-wasix = ["rust-api-model", "dep:oliphaunt-wasix"] - -[dependencies] -anyhow = "1" -futures-util = "0.3" -oliphaunt = { path = "../../../src/sdks/rust" } -oliphaunt-wasix = { path = "../../../src/bindings/wasix-rust/crates/oliphaunt-wasix", optional = true } -rusqlite = { version = "0.37", features = ["bundled"] } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -sqlx = { version = "0.8", default-features = false, features = [ - "postgres", - "runtime-tokio", -] } -tar = "0.4" -tokio = { version = "1", features = ["rt-multi-thread"] } -tokio-postgres = "0.7" - -[[bin]] -name = "oliphaunt-rust-api-model" -path = "src/rust_api_model.rs" -required-features = ["rust-api-model"] diff --git a/tools/perf/runner/src/main.rs b/tools/perf/runner/src/main.rs deleted file mode 100644 index e45a44bb5..000000000 --- a/tools/perf/runner/src/main.rs +++ /dev/null @@ -1,813 +0,0 @@ -use std::env; -use std::fs; -use std::io::{BufReader, Cursor, Read, Write}; -use std::net::TcpListener; -#[cfg(not(unix))] -use std::net::TcpStream; -#[cfg(unix)] -use std::os::unix::net::UnixStream; -use std::path::{Component, Path, PathBuf}; -use std::process::{Child, Command, Stdio}; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; - -use anyhow::{Context, Result, anyhow, bail, ensure}; -use futures_util::future::try_join_all; -use serde::{Deserialize, Serialize}; -use sqlx::postgres::{PgConnectOptions, PgSslMode}; -use sqlx::{Connection, Executor}; -use tar::{Archive, Builder as TarBuilder, Header as TarHeader}; - -use crate::process_rss::ProcessTreeRssSampler; - -mod benchmarks; -mod diagnostics; -mod native_liboliphaunt; -mod native_postgres; -mod prepared_updates; -mod process_rss; -mod report; -mod shared; -mod sqlite; - -use benchmarks::*; -use diagnostics::*; -use native_liboliphaunt::*; -use native_postgres::*; -use prepared_updates::*; -use report::*; -use shared::*; -use sqlite::*; - -const NATIVE_BENCHMARK_DATABASE: &str = "template1"; -const OLIPHAUNT_BENCHMARK_SQL_DIR: &str = "benchmarks/native/sql"; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum NativeDurabilityProfile { - Safe, - Balanced, - FastDev, -} - -impl NativeDurabilityProfile { - fn postgres_gucs(self) -> &'static [(&'static str, &'static str)] { - match self { - Self::Safe => &[ - ("fsync", "on"), - ("full_page_writes", "on"), - ("synchronous_commit", "on"), - ], - Self::Balanced => &[ - ("fsync", "on"), - ("full_page_writes", "on"), - ("synchronous_commit", "off"), - ], - Self::FastDev => &[ - ("fsync", "off"), - ("full_page_writes", "off"), - ("synchronous_commit", "off"), - ], - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum RuntimeFootprintProfile { - Throughput, - BalancedMobile, - SmallMobile, -} - -impl RuntimeFootprintProfile { - fn postgres_gucs(self) -> &'static [(&'static str, &'static str)] { - match self { - Self::Throughput => &[ - ("shared_buffers", "128MB"), - ("wal_buffers", "4MB"), - ("min_wal_size", "80MB"), - ], - Self::BalancedMobile => &[ - ("max_connections", "1"), - ("shared_buffers", "32MB"), - ("min_wal_size", "32MB"), - ("max_wal_size", "64MB"), - ], - Self::SmallMobile => &[ - ("max_connections", "1"), - ("shared_buffers", "8MB"), - ("wal_buffers", "256kB"), - ("min_wal_size", "32MB"), - ("max_wal_size", "64MB"), - ], - } - } -} - -impl std::fmt::Display for RuntimeFootprintProfile { - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str(match self { - Self::Throughput => "throughput", - Self::BalancedMobile => "balanced-mobile", - Self::SmallMobile => "small-mobile", - }) - } -} - -#[derive(Debug, Clone)] -struct PostgresStartupGuc { - name: String, - value: String, -} - -impl PostgresStartupGuc { - fn new(name: impl Into, value: impl Into) -> Self { - Self { - name: name.into(), - value: value.into(), - } - } -} - -fn main() -> Result<()> { - perf(env::args().skip(1).collect()) -} - -pub(crate) fn perf(args: Vec) -> Result<()> { - match args.first().map(String::as_str) { - Some("diagnose-speed-cases") => perf_diagnose_speed_cases(&args[1..]), - Some("native-postgres") => perf_native_postgres(&args[1..]), - Some("native-liboliphaunt") => perf_native_liboliphaunt(&args[1..]), - Some("native-liboliphaunt-prepared-child") => { - perf_native_liboliphaunt_prepared_child(&args[1..]) - } - Some("native-liboliphaunt-restore-verify-child") => { - perf_native_liboliphaunt_restore_verify_child(&args[1..]) - } - Some("sqlite") => perf_sqlite(&args[1..]), - Some("smoke") => run( - "cargo", - &[ - "test", - "--workspace", - "--locked", - "preload", - "--", - "--nocapture", - ], - ), - Some(other) => bail!("unknown perf subcommand: {other}"), - None => bail!( - "usage: cargo run -p oliphaunt-perf -- " - ), - } -} - -fn now_micros() -> Result { - Ok(SystemTime::now() - .duration_since(UNIX_EPOCH) - .context("system clock is before UNIX_EPOCH")? - .as_micros()) -} - -fn run(command: &str, args: &[&str]) -> Result<()> { - let mut command = command_for_host(command); - command.args(args); - run_command(&mut command) -} - -fn command_for_host(command: &str) -> Command { - if cfg!(windows) - && Path::new(command) - .extension() - .and_then(|ext| ext.to_str()) - .is_some_and(|ext| ext.eq_ignore_ascii_case("sh")) - { - let mut shell = Command::new(windows_bash_path()); - shell.arg("--noprofile").arg("--norc"); - shell.arg(command); - return shell; - } - Command::new(command) -} - -#[cfg(windows)] -fn windows_bash_path() -> PathBuf { - for path in [ - r"C:\Program Files\Git\bin\bash.exe", - r"C:\Program Files\Git\usr\bin\bash.exe", - ] { - let path = PathBuf::from(path); - if path.is_file() { - return path; - } - } - PathBuf::from("bash") -} - -#[cfg(not(windows))] -fn windows_bash_path() -> &'static str { - "bash" -} - -fn run_command(command: &mut Command) -> Result<()> { - let status = command - .status() - .map_err(|err| anyhow!("failed to spawn command: {err}"))?; - if !status.success() { - bail!("command failed with {status}"); - } - Ok(()) -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum BenchmarkSuiteFilter { - All, - Rtt, - Speed, - Streaming, - PreparedUpdates, - BackupRestore, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum NativePostgresClientMode { - TokioPostgresSimple, - Sqlx, -} - -impl BenchmarkSuiteFilter { - fn includes(self, suite: &'static str) -> bool { - matches!( - (self, suite), - (Self::All, "rtt" | "speed") - | (Self::Rtt, "rtt") - | (Self::Speed, "speed") - | (Self::Streaming, "streaming") - | (Self::PreparedUpdates, "prepared-updates") - | (Self::BackupRestore, "backup-restore") - ) - } -} - -fn default_native_postgres_tool(tool: &str, env_names: &[&str]) -> PathBuf { - for env_name in env_names { - if let Ok(value) = env::var(env_name) - && !value.is_empty() - { - return PathBuf::from(value); - } - } - if let Ok(root) = env::current_dir() { - let repo_pinned = root - .join("target") - .join("liboliphaunt-pg18") - .join("install") - .join("bin") - .join(tool); - if repo_pinned.is_file() { - return repo_pinned; - } - } - PathBuf::from(tool) -} - -fn perf_native_postgres(args: &[String]) -> Result<()> { - let mut postgres_bin = default_native_postgres_tool("postgres", &["OLIPHAUNT_POSTGRES"]); - let mut initdb_bin = default_native_postgres_tool("initdb", &["OLIPHAUNT_INITDB"]); - let mut suite = BenchmarkSuiteFilter::Speed; - let mut speed_sql_source = SpeedSqlSource::OliphauntFixture; - let mut rtt_iterations = 100usize; - let mut prepared_rows = 25_000usize; - let mut client_mode = NativePostgresClientMode::TokioPostgresSimple; - let mut tuning = NativeBenchmarkTuning::default(); - let mut cursor = 0usize; - while cursor < args.len() { - match args[cursor].as_str() { - "--postgres-bin" => { - cursor += 1; - postgres_bin = PathBuf::from( - args.get(cursor) - .ok_or_else(|| anyhow!("--postgres-bin requires a value"))?, - ); - } - "--initdb-bin" => { - cursor += 1; - initdb_bin = PathBuf::from( - args.get(cursor) - .ok_or_else(|| anyhow!("--initdb-bin requires a value"))?, - ); - } - "--suite" => { - cursor += 1; - let value = args - .get(cursor) - .ok_or_else(|| anyhow!("--suite requires a value"))?; - suite = match value.as_str() { - "all" => BenchmarkSuiteFilter::All, - "rtt" | "roundtrip" | "round-trip" => BenchmarkSuiteFilter::Rtt, - "speed" | "sqlite" | "sqlite-suite" => BenchmarkSuiteFilter::Speed, - "stream" | "streaming" | "large-results" => BenchmarkSuiteFilter::Streaming, - "prepared" | "prepared-updates" => BenchmarkSuiteFilter::PreparedUpdates, - "backup" | "backup-restore" | "backup_restore" => { - BenchmarkSuiteFilter::BackupRestore - } - other => { - bail!( - "unknown --suite value {other:?}; use all, rtt, speed, streaming, prepared-updates, or backup-restore" - ) - } - }; - } - "--iterations" => { - cursor += 1; - let value = args - .get(cursor) - .ok_or_else(|| anyhow!("--iterations requires a value"))?; - rtt_iterations = value - .parse() - .with_context(|| format!("parse --iterations value {value:?}"))?; - } - "--rows" => { - cursor += 1; - let value = args - .get(cursor) - .ok_or_else(|| anyhow!("--rows requires a value"))?; - prepared_rows = value - .parse() - .with_context(|| format!("parse --rows value {value:?}"))?; - } - "--speed-source" => { - cursor += 1; - let value = args - .get(cursor) - .ok_or_else(|| anyhow!("--speed-source requires a value"))?; - speed_sql_source = match value.as_str() { - "generated" | "local" => SpeedSqlSource::Generated, - "oliphaunt" | "oliphaunt-vendored" | "upstream" => { - SpeedSqlSource::OliphauntFixture - } - other => { - bail!("unknown --speed-source value {other:?}; use generated or oliphaunt") - } - }; - } - "--client" => { - cursor += 1; - let value = args - .get(cursor) - .ok_or_else(|| anyhow!("--client requires a value"))?; - client_mode = match value.as_str() { - "tokio-postgres-simple" - | "tokio_postgres_simple" - | "tokio-postgres" - | "tokio_postgres" - | "simple" - | "simple-query" => NativePostgresClientMode::TokioPostgresSimple, - "sqlx" => NativePostgresClientMode::Sqlx, - other => { - bail!("unknown --client value {other:?}; use tokio-postgres-simple or sqlx") - } - }; - } - "--durability" => { - cursor += 1; - tuning.durability = parse_native_durability( - args.get(cursor) - .ok_or_else(|| anyhow!("--durability requires a value"))?, - )?; - } - "--runtime-footprint" => { - cursor += 1; - tuning.runtime_footprint = parse_runtime_footprint( - args.get(cursor) - .ok_or_else(|| anyhow!("--runtime-footprint requires a value"))?, - )?; - } - "--startup-guc" => { - cursor += 1; - tuning.startup_gucs.push(parse_startup_guc( - args.get(cursor) - .ok_or_else(|| anyhow!("--startup-guc requires a value"))?, - )?); - } - other => bail!("unknown perf native-postgres flag: {other}"), - } - cursor += 1; - } - ensure!(rtt_iterations > 0, "--iterations must be greater than zero"); - ensure!(prepared_rows > 0, "--rows must be greater than zero"); - - if suite == BenchmarkSuiteFilter::PreparedUpdates { - return perf_native_postgres_prepared_updates( - &postgres_bin, - &initdb_bin, - prepared_rows, - tuning, - ); - } - - let native_open_started = Instant::now(); - let native = NativePostgres::start(&postgres_bin, &initdb_bin, &tuning)?; - let native_open_micros = native_open_started.elapsed().as_micros(); - let mut runs = Vec::new(); - if suite.includes("rtt") || suite.includes("speed") { - let runtime = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .context("create native Postgres benchmark Tokio runtime")?; - let mut client_runs = runtime.block_on(async { - match client_mode { - NativePostgresClientMode::TokioPostgresSimple => { - let mut config = tokio_postgres::Config::new(); - configure_native_postgres_client(&mut config, &native); - let connect_started = Instant::now(); - let (client, connection) = config - .connect(tokio_postgres::NoTls) - .await - .context("connect to native Postgres benchmark cluster")?; - let connection_task = tokio::spawn(async move { - if let Err(err) = connection.await { - eprintln!("native Postgres benchmark connection error: {err}"); - } - }); - let connect_micros = connect_started.elapsed().as_micros(); - let server_pid = native.child.id(); - - let mut runs = Vec::new(); - if suite.includes("rtt") { - let mut sampler = ProcessTreeRssSampler::new(server_pid); - runs.push( - run_native_postgres_rtt_benchmark( - &client, - rtt_iterations, - native_open_micros, - connect_micros, - &mut sampler, - ) - .await?, - ); - } - if suite.includes("speed") { - let mut sampler = ProcessTreeRssSampler::new(server_pid); - runs.push( - run_native_postgres_speed_benchmark( - &client, - speed_sql_source, - native_open_micros, - connect_micros, - &mut sampler, - ) - .await?, - ); - } - drop(client); - connection_task.await.ok(); - Ok::<_, anyhow::Error>(runs) - } - NativePostgresClientMode::Sqlx => { - let connect_started = Instant::now(); - let mut conn = - sqlx::PgConnection::connect_with(&native_postgres_sqlx_options(&native)) - .await - .context("connect SQLx native Postgres benchmark client")?; - let connect_micros = connect_started.elapsed().as_micros(); - let server_pid = native.child.id(); - - let mut runs = Vec::new(); - if suite.includes("rtt") { - let mut sampler = ProcessTreeRssSampler::new(server_pid); - runs.push( - run_native_postgres_rtt_sqlx_benchmark( - &mut conn, - rtt_iterations, - native_open_micros, - connect_micros, - &mut sampler, - ) - .await?, - ); - } - if suite.includes("speed") { - let mut sampler = ProcessTreeRssSampler::new(server_pid); - runs.push( - run_native_postgres_speed_sqlx_benchmark( - &mut conn, - speed_sql_source, - native_open_micros, - connect_micros, - &mut sampler, - ) - .await?, - ); - } - conn.close() - .await - .context("close SQLx native Postgres benchmark client")?; - Ok::<_, anyhow::Error>(runs) - } - } - })?; - runs.append(&mut client_runs); - } - if suite.includes("streaming") { - let mut sampler = ProcessTreeRssSampler::new(native.child.id()); - runs.push(run_native_postgres_streaming_benchmark( - &native, - native_open_micros, - &mut sampler, - )?); - } - if suite.includes("backup-restore") { - let mut sampler = ProcessTreeRssSampler::new(native.child.id()); - runs.push(run_native_postgres_physical_backup_restore_benchmark( - &native, - &postgres_bin, - native_open_micros, - &mut sampler, - &tuning, - )?); - runs.push(run_native_postgres_backup_restore_benchmark( - &native, - &postgres_bin, - native_open_micros, - &mut sampler, - )?); - } - ensure!( - !runs.is_empty(), - "selected native Postgres suite produced no runs" - ); - - let report = BenchmarkReport { - engine: "native-postgres", - source_model: speed_sql_source.source_model(), - measurement_model: match client_mode { - NativePostgresClientMode::TokioPostgresSimple => { - "Native Postgres control. xtask starts a temporary local cluster with the selected durability profile and Oliphaunt-parity startup GUCs, connects to the same template1 database target used by liboliphaunt, then sends each benchmark SQL file as one simple-query buffer through tokio-postgres simple_query. This intentionally avoids psql -f because psql splits files client-side." - } - NativePostgresClientMode::Sqlx => { - "Native Postgres control. xtask starts a temporary local cluster with the selected durability profile and Oliphaunt-parity startup GUCs, connects to the same template1 database target used by liboliphaunt, then runs the benchmark SQL through one long-lived SQLx connection." - } - }, - native_tuning: Some(tuning.report()), - rtt_iterations, - speed_scale: 1.0, - runs, - }; - println!("{}", serde_json::to_string_pretty(&report)?); - Ok(()) -} - -fn perf_native_postgres_prepared_updates( - postgres_bin: &Path, - initdb_bin: &Path, - rows: usize, - tuning: NativeBenchmarkTuning, -) -> Result<()> { - let numeric_updates = parsed_numeric_updates(rows)?; - let text_updates = parsed_text_updates(rows)?; - let runs = vec![ - PreparedUpdateRun { - mode: "native_postgres_tokio_prepared".to_owned(), - description: "Native PostgreSQL control using tokio-postgres with one prepared statement and one Execute await per update.".to_owned(), - tests: run_native_prepared_update_tests( - postgres_bin, - initdb_bin, - &tuning, - &numeric_updates, - &text_updates, - PreparedExecution::Sequential, - )?, - }, - PreparedUpdateRun { - mode: "native_postgres_tokio_pipelined_prepared".to_owned(), - description: "Native PostgreSQL control using tokio-postgres with one prepared statement and pipelined Execute futures inside one transaction.".to_owned(), - tests: run_native_prepared_update_tests( - postgres_bin, - initdb_bin, - &tuning, - &numeric_updates, - &text_updates, - PreparedExecution::Pipelined, - )?, - }, - ]; - - let report = PreparedUpdateReport { - source_model: "Exact Oliphaunt fixture benchmark2/benchmark6 setup plus update values parsed from benchmark9 and benchmark10.", - measurement_model: "Native PostgreSQL prepared-update control. Each test starts a fresh temporary local PostgreSQL cluster with the selected durability profile and Oliphaunt-parity startup GUCs, connects through tokio-postgres, prepares one statement, then executes N updates inside one transaction.", - native_tuning: Some(tuning.report()), - rows, - runs, - }; - println!("{}", serde_json::to_string_pretty(&report)?); - Ok(()) -} - -async fn run_native_postgres_rtt_benchmark( - client: &tokio_postgres::Client, - iterations: usize, - open_micros: u128, - connect_micros: u128, - server_rss: &mut ProcessTreeRssSampler, -) -> Result { - let setup_started = Instant::now(); - client - .simple_query(rtt_setup_sql()) - .await - .context("execute native Postgres RTT setup")?; - let setup_micros = setup_started.elapsed().as_micros(); - server_rss.sample(); - - let mut tests = Vec::new(); - for case in rtt_cases() { - let mut samples = Vec::with_capacity(iterations); - for _ in 0..iterations { - let started = Instant::now(); - client - .simple_query(&case.sql) - .await - .with_context(|| format!("execute native Postgres RTT benchmark {}", case.id))?; - samples.push(started.elapsed().as_micros()); - } - tests.push(samples_result( - case.id, - format!("Test {}: {}", case.id, case.label), - "milliseconds", - iterations, - samples, - )); - server_rss.sample(); - } - - Ok(BenchmarkRun { - suite: "rtt", - mode: "native_postgres", - description: "Native Postgres over Unix socket using tokio-postgres simple_query against the liboliphaunt-matched template1 database target.", - open_micros, - connect_micros: Some(connect_micros), - setup_micros, - observed_server_peak_rss_bytes: server_rss.peak_bytes(), - tests, - }) -} - -async fn run_native_postgres_speed_benchmark( - client: &tokio_postgres::Client, - sql_source: SpeedSqlSource, - open_micros: u128, - connect_micros: u128, - server_rss: &mut ProcessTreeRssSampler, -) -> Result { - client - .simple_query( - "DROP TABLE IF EXISTS t1 CASCADE;\ - DROP TABLE IF EXISTS t2 CASCADE;\ - DROP TABLE IF EXISTS t2_1 CASCADE;\ - DROP TABLE IF EXISTS t3 CASCADE;\ - DROP TABLE IF EXISTS t3_1 CASCADE;", - ) - .await - .context("clear native Postgres speed benchmark tables")?; - server_rss.sample(); - - let mut tests = Vec::new(); - for case in speed_cases(1.0, sql_source)? { - let started = Instant::now(); - client - .simple_query(&case.sql) - .await - .with_context(|| format!("execute native Postgres speed benchmark {}", case.id))?; - tests.push(single_sample_result( - case.id, - case.label, - "seconds", - case.operation_count, - started.elapsed(), - )); - server_rss.sample(); - } - Ok(BenchmarkRun { - suite: "speed", - mode: "native_postgres", - description: "Native Postgres speed suite over Unix socket using tokio-postgres simple_query against the liboliphaunt-matched template1 database target.", - open_micros, - connect_micros: Some(connect_micros), - setup_micros: 0, - observed_server_peak_rss_bytes: server_rss.peak_bytes(), - tests, - }) -} - -async fn run_native_postgres_rtt_sqlx_benchmark( - conn: &mut sqlx::PgConnection, - iterations: usize, - open_micros: u128, - connect_micros: u128, - server_rss: &mut ProcessTreeRssSampler, -) -> Result { - let setup_started = Instant::now(); - conn.execute(rtt_setup_sql()) - .await - .context("execute native Postgres RTT setup over SQLx")?; - let setup_micros = setup_started.elapsed().as_micros(); - server_rss.sample(); - - let mut tests = Vec::new(); - for case in rtt_cases() { - let mut samples = Vec::with_capacity(iterations); - for _ in 0..iterations { - let started = Instant::now(); - conn.execute(case.sql.as_str()).await.with_context(|| { - format!( - "execute native Postgres RTT benchmark {} over SQLx", - case.id - ) - })?; - samples.push(started.elapsed().as_micros()); - } - tests.push(samples_result( - case.id, - format!("Test {}: {}", case.id, case.label), - "milliseconds", - iterations, - samples, - )); - server_rss.sample(); - } - - Ok(BenchmarkRun { - suite: "rtt", - mode: "native_postgres_sqlx", - description: "Native Postgres over TCP using one long-lived SQLx connection against the liboliphaunt-matched template1 database target.", - open_micros, - connect_micros: Some(connect_micros), - setup_micros, - observed_server_peak_rss_bytes: server_rss.peak_bytes(), - tests, - }) -} - -async fn run_native_postgres_speed_sqlx_benchmark( - conn: &mut sqlx::PgConnection, - sql_source: SpeedSqlSource, - open_micros: u128, - connect_micros: u128, - server_rss: &mut ProcessTreeRssSampler, -) -> Result { - conn.execute( - "DROP TABLE IF EXISTS t1 CASCADE;\ - DROP TABLE IF EXISTS t2 CASCADE;\ - DROP TABLE IF EXISTS t2_1 CASCADE;\ - DROP TABLE IF EXISTS t3 CASCADE;\ - DROP TABLE IF EXISTS t3_1 CASCADE;", - ) - .await - .context("clear native Postgres speed benchmark tables over SQLx")?; - server_rss.sample(); - - let mut tests = Vec::new(); - for case in speed_cases(1.0, sql_source)? { - let started = Instant::now(); - conn.execute(case.sql.as_str()).await.with_context(|| { - format!( - "execute native Postgres speed benchmark {} over SQLx", - case.id - ) - })?; - tests.push(single_sample_result( - case.id, - case.label, - "seconds", - case.operation_count, - started.elapsed(), - )); - server_rss.sample(); - } - Ok(BenchmarkRun { - suite: "speed", - mode: "native_postgres_sqlx", - description: "Native Postgres speed suite over TCP using one SQLx connection against the liboliphaunt-matched template1 database target.", - open_micros, - connect_micros: Some(connect_micros), - setup_micros: 0, - observed_server_peak_rss_bytes: server_rss.peak_bytes(), - tests, - }) -} - -fn unique_perf_root(name: &str) -> Result { - let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - .context("read system clock for perf root")? - .as_nanos(); - let root = env::temp_dir().join(format!( - "oliphaunt-perf-{name}-{}-{now}", - std::process::id() - )); - if root.exists() { - fs::remove_dir_all(&root) - .with_context(|| format!("remove stale perf root {}", root.display()))?; - } - fs::create_dir_all(&root).with_context(|| format!("create perf root {}", root.display()))?; - Ok(root) -} diff --git a/tools/perf/runner/src/rust_api_model.rs b/tools/perf/runner/src/rust_api_model.rs deleted file mode 100644 index 300755594..000000000 --- a/tools/perf/runner/src/rust_api_model.rs +++ /dev/null @@ -1,632 +0,0 @@ -use std::env; -use std::time::{Duration, Instant}; - -use anyhow::{Context, Result, bail, ensure}; -use serde::Serialize; - -const REPORT_SCHEMA: &str = "oliphaunt.rust-api-model-run.v1"; -const CLASSIFICATION: &str = "diagnostic-only"; -const SELECT_ONE_SQL: &str = "SELECT 1::text AS value"; - -fn main() -> Result<()> { - let arguments = env::args().skip(1).collect::>(); - if arguments - .iter() - .any(|argument| matches!(argument.as_str(), "-h" | "--help")) - { - print_help(); - return Ok(()); - } - - let options = Options::parse(&arguments)?; - let report = match (options.runtime, options.api) { - (RuntimeFamily::Native, ApiModel::Sync) => run_native_sync(options)?, - (RuntimeFamily::Native, ApiModel::Async) => run_native_async(options)?, - (RuntimeFamily::Wasix, ApiModel::Sync) => run_wasix_sync(options)?, - (RuntimeFamily::Wasix, ApiModel::Async) => run_wasix_async(options)?, - }; - println!("{}", serde_json::to_string_pretty(&report)?); - Ok(()) -} - -fn print_help() { - println!( - "oliphaunt-rust-api-model \ - --runtime native|wasix \ - --api sync|async \ - [--iterations N] [--warmup N]\n\n\ -Runs one API model in one process. Use tools/perf/rust-api-model/run.sh to run\n\ -the paired sync and async processes and produce a diagnostic-only report." - ); -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum RuntimeFamily { - Native, - Wasix, -} - -impl RuntimeFamily { - fn parse(value: &str) -> Result { - match value { - "native" => Ok(Self::Native), - "wasix" => Ok(Self::Wasix), - other => bail!("unsupported --runtime {other:?}; use native or wasix"), - } - } - - fn label(self) -> &'static str { - match self { - Self::Native => "native", - Self::Wasix => "wasix", - } - } - - fn execution_owner(self, api: ApiModel) -> &'static str { - match (self, api) { - (Self::Native, ApiModel::Sync) => "liboliphaunt-backend-thread", - (Self::Native, ApiModel::Async) => "sdk-owner-thread-plus-liboliphaunt-backend-thread", - (Self::Wasix, ApiModel::Sync) => "caller-thread", - (Self::Wasix, ApiModel::Async) => "sdk-owner-thread", - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum ApiModel { - Sync, - Async, -} - -impl ApiModel { - fn parse(value: &str) -> Result { - match value { - "sync" => Ok(Self::Sync), - "async" => Ok(Self::Async), - other => bail!("unsupported --api {other:?}; use sync or async"), - } - } - - fn label(self) -> &'static str { - match self { - Self::Sync => "sync", - Self::Async => "async", - } - } - - fn calling_contract(self) -> &'static str { - match self { - Self::Sync => "blocking", - Self::Async => "awaited", - } - } - - fn sdk_queue(self) -> &'static str { - match self { - Self::Sync => "none", - Self::Async => "one-owner-fifo", - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct Options { - runtime: RuntimeFamily, - api: ApiModel, - iterations: usize, - warmup_iterations: usize, -} - -impl Options { - fn parse(arguments: &[String]) -> Result { - let mut runtime = None; - let mut api = None; - let mut iterations = 200usize; - let mut warmup_iterations = 20usize; - let mut cursor = 0usize; - - while cursor < arguments.len() { - let flag = arguments[cursor].as_str(); - cursor += 1; - let value = arguments - .get(cursor) - .with_context(|| format!("{flag} requires a value"))?; - match flag { - "--runtime" => runtime = Some(RuntimeFamily::parse(value)?), - "--api" => api = Some(ApiModel::parse(value)?), - "--iterations" => { - iterations = value - .parse() - .with_context(|| format!("parse --iterations value {value:?}"))?; - } - "--warmup" => { - warmup_iterations = value - .parse() - .with_context(|| format!("parse --warmup value {value:?}"))?; - } - other => bail!("unsupported argument {other:?}; use --help for usage"), - } - cursor += 1; - } - - ensure!(iterations > 0, "--iterations must be greater than zero"); - ensure!(warmup_iterations > 0, "--warmup must be greater than zero"); - Ok(Self { - runtime: runtime.context("--runtime is required")?, - api: api.context("--api is required")?, - iterations, - warmup_iterations, - }) - } -} - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -struct RunReport { - schema: &'static str, - classification: &'static str, - release_evidence: bool, - runtime: &'static str, - api: &'static str, - calling_contract: &'static str, - execution_owner: &'static str, - sdk_queue: &'static str, - topology: &'static str, - process_model: &'static str, - sql: &'static str, - iterations: usize, - warmup_iterations: usize, - open_micros: f64, - close_micros: f64, - operations: Vec, -} - -impl RunReport { - fn new( - options: Options, - open: Duration, - close: Duration, - operations: Vec, - ) -> Self { - Self { - schema: REPORT_SCHEMA, - classification: CLASSIFICATION, - release_evidence: false, - runtime: options.runtime.label(), - api: options.api.label(), - calling_contract: options.api.calling_contract(), - execution_owner: options.runtime.execution_owner(options.api), - sdk_queue: options.api.sdk_queue(), - topology: "direct", - process_model: "one-api-model-per-process", - sql: SELECT_ONE_SQL, - iterations: options.iterations, - warmup_iterations: options.warmup_iterations, - open_micros: duration_micros(open), - close_micros: duration_micros(close), - operations, - } - } -} - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -struct OperationReport { - operation: &'static str, - samples: usize, - total_micros: f64, - mean_micros: f64, - operations_per_second: f64, - min_micros: f64, - p50_micros: f64, - p95_micros: f64, - p99_micros: f64, - max_micros: f64, -} - -impl OperationReport { - fn from_samples(operation: &'static str, mut samples: Vec) -> Result { - ensure!(!samples.is_empty(), "{operation} produced no samples"); - samples.sort_unstable(); - let total_nanos = samples.iter().map(|sample| *sample as u128).sum::(); - let total_micros = total_nanos as f64 / 1_000.0; - let sample_count = samples.len(); - Ok(Self { - operation, - samples: sample_count, - total_micros, - mean_micros: total_micros / sample_count as f64, - operations_per_second: sample_count as f64 * 1_000_000.0 / total_micros, - min_micros: samples[0] as f64 / 1_000.0, - p50_micros: percentile_nanos(&samples, 50) as f64 / 1_000.0, - p95_micros: percentile_nanos(&samples, 95) as f64 / 1_000.0, - p99_micros: percentile_nanos(&samples, 99) as f64 / 1_000.0, - max_micros: samples[sample_count - 1] as f64 / 1_000.0, - }) - } -} - -fn percentile_nanos(sorted: &[u64], percentile: usize) -> u64 { - let rank = (percentile * sorted.len()).div_ceil(100); - sorted[rank.saturating_sub(1).min(sorted.len() - 1)] -} - -fn duration_micros(duration: Duration) -> f64 { - duration.as_nanos() as f64 / 1_000.0 -} - -fn elapsed_nanos(started: Instant) -> u64 { - u64::try_from(started.elapsed().as_nanos()).unwrap_or(u64::MAX) -} - -fn simple_query_request(sql: &str) -> Vec { - let payload_len = sql.len() + 1; - let length = u32::try_from(payload_len + 4).expect("benchmark SQL request length fits u32"); - let mut request = Vec::with_capacity(payload_len + 5); - request.push(b'Q'); - request.extend(length.to_be_bytes()); - request.extend(sql.as_bytes()); - request.push(0); - request -} - -fn validate_protocol_response(response: &[u8]) -> Result<()> { - let mut offset = 0usize; - let mut ready = false; - while offset + 5 <= response.len() { - let tag = response[offset]; - let length = u32::from_be_bytes([ - response[offset + 1], - response[offset + 2], - response[offset + 3], - response[offset + 4], - ]) as usize; - ensure!(length >= 4, "invalid backend message length {length}"); - let frame_len = 1 + length; - ensure!( - frame_len <= response.len() - offset, - "truncated backend message" - ); - ensure!(tag != b'E', "backend returned ErrorResponse"); - ready |= tag == b'Z'; - offset += frame_len; - } - ensure!(offset == response.len(), "trailing backend response bytes"); - ensure!(ready, "backend response omitted ReadyForQuery"); - Ok(()) -} - -fn measure_sync( - iterations: usize, - mut operation: impl FnMut() -> Result, - mut validate: impl FnMut(T) -> Result<()>, -) -> Result> { - let mut samples = Vec::with_capacity(iterations); - for _ in 0..iterations { - let started = Instant::now(); - let value = operation()?; - samples.push(elapsed_nanos(started)); - validate(value)?; - } - Ok(samples) -} - -async fn measure_async( - iterations: usize, - mut operation: impl AsyncFnMut() -> Result, - mut validate: impl FnMut(T) -> Result<()>, -) -> Result> { - let mut samples = Vec::with_capacity(iterations); - for _ in 0..iterations { - let started = Instant::now(); - let value = operation().await?; - samples.push(elapsed_nanos(started)); - validate(value)?; - } - Ok(samples) -} - -trait SyncDiagnosticDatabase { - type QueryOutput; - - fn query_one(&mut self) -> Result; - fn raw_query(&mut self, request: &[u8]) -> Result>; - fn validate_query(output: Self::QueryOutput) -> Result<()>; -} - -trait AsyncDiagnosticDatabase { - type QueryOutput; - - async fn query_one(&self) -> Result; - async fn raw_query(&self, request: &[u8]) -> Result>; - fn validate_query(output: Self::QueryOutput) -> Result<()>; -} - -fn validate_select_one(value: Option<&str>) -> Result<()> { - ensure!(value == Some("1"), "unexpected SELECT 1 result"); - Ok(()) -} - -impl SyncDiagnosticDatabase for oliphaunt::Oliphaunt { - type QueryOutput = oliphaunt::QueryResult; - - fn query_one(&mut self) -> Result { - Ok(self.query(SELECT_ONE_SQL)?) - } - - fn raw_query(&mut self, request: &[u8]) -> Result> { - Ok(self.exec_protocol_raw(request)?) - } - - fn validate_query(output: Self::QueryOutput) -> Result<()> { - validate_select_one(output.get_text(0, "value")?) - } -} - -impl AsyncDiagnosticDatabase for oliphaunt::AsyncOliphaunt { - type QueryOutput = oliphaunt::QueryResult; - - async fn query_one(&self) -> Result { - Ok(self.query(SELECT_ONE_SQL).await?) - } - - async fn raw_query(&self, request: &[u8]) -> Result> { - Ok(self.exec_protocol_raw(request).await?) - } - - fn validate_query(output: Self::QueryOutput) -> Result<()> { - validate_select_one(output.get_text(0, "value")?) - } -} - -#[cfg(feature = "rust-api-model-wasix")] -impl SyncDiagnosticDatabase for oliphaunt_wasix::Oliphaunt { - type QueryOutput = oliphaunt_wasix::QueryResult; - - fn query_one(&mut self) -> Result { - Ok(self.query(SELECT_ONE_SQL)?) - } - - fn raw_query(&mut self, request: &[u8]) -> Result> { - Ok(self.exec_protocol_raw(request)?) - } - - fn validate_query(output: Self::QueryOutput) -> Result<()> { - validate_select_one(output.get_text(0, "value")?) - } -} - -#[cfg(feature = "rust-api-model-wasix")] -impl AsyncDiagnosticDatabase for oliphaunt_wasix::AsyncOliphaunt { - type QueryOutput = oliphaunt_wasix::QueryResult; - - async fn query_one(&self) -> Result { - Ok(self.query(SELECT_ONE_SQL).await?) - } - - async fn raw_query(&self, request: &[u8]) -> Result> { - Ok(self.exec_protocol_raw(request).await?) - } - - fn validate_query(output: Self::QueryOutput) -> Result<()> { - validate_select_one(output.get_text(0, "value")?) - } -} - -fn run_sync_operations( - database: &mut D, - options: Options, - request: &[u8], -) -> Result> { - measure_sync( - options.warmup_iterations, - || database.query_one(), - D::validate_query, - )?; - let query = OperationReport::from_samples( - "query-select-1", - measure_sync( - options.iterations, - || database.query_one(), - D::validate_query, - )?, - )?; - - measure_sync( - options.warmup_iterations, - || database.raw_query(request), - |response| validate_protocol_response(&response), - )?; - let raw = OperationReport::from_samples( - "raw-simple-query-select-1", - measure_sync( - options.iterations, - || database.raw_query(request), - |response| validate_protocol_response(&response), - )?, - )?; - - Ok(vec![query, raw]) -} - -async fn run_async_operations( - database: &D, - options: Options, - request: &[u8], -) -> Result> { - measure_async( - options.warmup_iterations, - async || database.query_one().await, - D::validate_query, - ) - .await?; - let query = OperationReport::from_samples( - "query-select-1", - measure_async( - options.iterations, - async || database.query_one().await, - D::validate_query, - ) - .await?, - )?; - - measure_async( - options.warmup_iterations, - async || database.raw_query(request).await, - |response| validate_protocol_response(&response), - ) - .await?; - let raw = OperationReport::from_samples( - "raw-simple-query-select-1", - measure_async( - options.iterations, - async || database.raw_query(request).await, - |response| validate_protocol_response(&response), - ) - .await?, - )?; - - Ok(vec![query, raw]) -} - -fn run_native_sync(options: Options) -> Result { - let opened = Instant::now(); - let mut database = oliphaunt::Oliphaunt::builder() - .direct() - .open() - .context("open native synchronous diagnostic database")?; - let open = opened.elapsed(); - let request = simple_query_request(SELECT_ONE_SQL); - let operations = run_sync_operations(&mut database, options, &request)?; - - let closed = Instant::now(); - database - .close() - .context("close native synchronous diagnostic database")?; - Ok(RunReport::new(options, open, closed.elapsed(), operations)) -} - -fn run_native_async(options: Options) -> Result { - tokio::runtime::Builder::new_current_thread() - .build() - .context("build diagnostic Tokio runtime")? - .block_on(async move { - let opened = Instant::now(); - let database = oliphaunt::AsyncOliphaunt::builder() - .direct() - .open() - .await - .context("open native asynchronous diagnostic database")?; - let open = opened.elapsed(); - let request = simple_query_request(SELECT_ONE_SQL); - let operations = run_async_operations(&database, options, &request).await?; - - let closed = Instant::now(); - database - .close() - .await - .context("close native asynchronous diagnostic database")?; - Ok(RunReport::new(options, open, closed.elapsed(), operations)) - }) -} - -#[cfg(feature = "rust-api-model-wasix")] -fn run_wasix_sync(options: Options) -> Result { - let opened = Instant::now(); - let mut database = - oliphaunt_wasix::Oliphaunt::open().context("open WASIX synchronous diagnostic database")?; - let open = opened.elapsed(); - let request = simple_query_request(SELECT_ONE_SQL); - let operations = run_sync_operations(&mut database, options, &request)?; - - let closed = Instant::now(); - database - .close() - .context("close WASIX synchronous diagnostic database")?; - Ok(RunReport::new(options, open, closed.elapsed(), operations)) -} - -#[cfg(not(feature = "rust-api-model-wasix"))] -fn run_wasix_sync(_options: Options) -> Result { - bail!("WASIX diagnostics require --features rust-api-model-wasix") -} - -#[cfg(feature = "rust-api-model-wasix")] -fn run_wasix_async(options: Options) -> Result { - tokio::runtime::Builder::new_current_thread() - .build() - .context("build diagnostic Tokio runtime")? - .block_on(async move { - let opened = Instant::now(); - let database = oliphaunt_wasix::AsyncOliphaunt::open() - .await - .context("open WASIX asynchronous diagnostic database")?; - let open = opened.elapsed(); - let request = simple_query_request(SELECT_ONE_SQL); - let operations = run_async_operations(&database, options, &request).await?; - - let closed = Instant::now(); - database - .close() - .await - .context("close WASIX asynchronous diagnostic database")?; - Ok(RunReport::new(options, open, closed.elapsed(), operations)) - }) -} - -#[cfg(not(feature = "rust-api-model-wasix"))] -fn run_wasix_async(_options: Options) -> Result { - bail!("WASIX diagnostics require --features rust-api-model-wasix") -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn options_require_explicit_runtime_and_api() { - let error = Options::parse(&[]).unwrap_err(); - assert!(error.to_string().contains("--runtime is required")); - - let options = Options::parse(&[ - "--runtime".into(), - "native".into(), - "--api".into(), - "async".into(), - "--iterations".into(), - "17".into(), - "--warmup".into(), - "3".into(), - ]) - .unwrap(); - assert_eq!(options.runtime, RuntimeFamily::Native); - assert_eq!(options.api, ApiModel::Async); - assert_eq!(options.iterations, 17); - assert_eq!(options.warmup_iterations, 3); - } - - #[test] - fn report_stats_use_nearest_rank_percentiles() { - let report = OperationReport::from_samples( - "probe", - (1_u64..=100).map(|value| value * 1_000).collect(), - ) - .unwrap(); - assert_eq!(report.samples, 100); - assert_eq!(report.mean_micros, 50.5); - assert_eq!(report.p50_micros, 50.0); - assert_eq!(report.p95_micros, 95.0); - assert_eq!(report.p99_micros, 99.0); - } - - #[test] - fn raw_response_validation_requires_ready_and_rejects_errors() { - let ready = [b'Z', 0, 0, 0, 5, b'I']; - validate_protocol_response(&ready).unwrap(); - - let error = [b'E', 0, 0, 0, 4]; - assert!(validate_protocol_response(&error).is_err()); - let command = [b'C', 0, 0, 0, 4]; - assert!(validate_protocol_response(&command).is_err()); - } -} diff --git a/tools/perf/rust-api-model/README.md b/tools/perf/rust-api-model/README.md deleted file mode 100644 index 00b8595c3..000000000 --- a/tools/perf/rust-api-model/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Rust sync-versus-async API diagnostic - -This harness measures the incremental public-call path for Oliphaunt's Rust -`sync` and `async` APIs. It supports both native liboliphaunt and WASIX, runs -each API model in a separate process, warms the database before sampling, and -reports open and close separately from the measured operations. - -The output is **diagnostic only**. It is not release evidence, has no baseline -or threshold, and is deliberately absent from the release performance matrix. -It answers a narrow question: what overhead does the async admission, owner -queue, wakeup, and reply path add to one sequential call on this machine? It -does not measure concurrent throughput or imply that the runtime and API model -use the same execution owner. - -Run a paired diagnostic with: - -```sh -bash tools/perf/rust-api-model/run.sh --runtime native -bash tools/perf/rust-api-model/run.sh --runtime wasix -``` - -Optional arguments are `--iterations N`, `--warmup N`, `--run-id ID`, and -`--output-dir DIR`. Native runs require the normal native runtime artifacts. -WASIX runs require the portable and host-AOT artifacts. The script performs the -same repository runtime preflight used by the product smoke tests. - -The output directory contains the two raw run documents, `summary.json`, and a -human-readable `report.md`. Every document identifies the runtime, API model, -calling contract, execution owner, queue model, and `diagnostic-only` -classification. - -The corresponding Moon tasks are intentionally non-release tasks: - -```sh -moon run perf-tools:rust-api-model-check -moon run perf-tools:rust-api-model-native -moon run perf-tools:rust-api-model-wasix -``` - -The native and WASIX measured tasks build their required runtime artifact -dependency and are disabled in ordinary CI. Run several fresh pairs before -drawing conclusions from small latency differences; scheduler and filesystem -noise can dominate a single local pair. diff --git a/tools/perf/rust-api-model/check.sh b/tools/perf/rust-api-model/check.sh deleted file mode 100755 index 1c8ace728..000000000 --- a/tools/perf/rust-api-model/check.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" -root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || { - echo "unable to determine the Oliphaunt repository root" >&2 - exit 1 -} -cd "$root" - -cargo test -p oliphaunt-perf --locked \ - --features rust-api-model-wasix \ - --bin oliphaunt-rust-api-model -tools/dev/bun.sh test tools/perf/rust-api-model/summarize.test.mjs diff --git a/tools/perf/rust-api-model/run.sh b/tools/perf/rust-api-model/run.sh deleted file mode 100755 index d615dd787..000000000 --- a/tools/perf/rust-api-model/run.sh +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" -root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null)" || { - echo "unable to determine the Oliphaunt repository root" >&2 - exit 1 -} -cd "$root" - -runtime="" -iterations=200 -warmup=20 -run_id="$(date -u +%Y%m%dT%H%M%SZ)" -output_dir="" - -usage() { - cat >&2 <<'USAGE' -usage: tools/perf/rust-api-model/run.sh --runtime native|wasix [options] - -Options: - --iterations N Measured calls per operation and API model. Default: 200. - --warmup N Warmup calls per operation and API model. Default: 20. - --run-id ID Output run identifier. Defaults to the current UTC time. - --output-dir DIR Explicit output directory. - -h, --help Show this help. - -This is a diagnostic-only paired run. It is not release performance evidence. -USAGE -} - -while [[ $# -gt 0 ]]; do - case "$1" in - --runtime) - runtime="${2:?--runtime requires a value}" - shift 2 - ;; - --iterations) - iterations="${2:?--iterations requires a value}" - shift 2 - ;; - --warmup) - warmup="${2:?--warmup requires a value}" - shift 2 - ;; - --run-id) - run_id="${2:?--run-id requires a value}" - shift 2 - ;; - --output-dir) - output_dir="${2:?--output-dir requires a value}" - shift 2 - ;; - -h|--help) - usage - exit 0 - ;; - *) - echo "unknown argument: $1" >&2 - usage - exit 2 - ;; - esac -done - -case "$runtime" in - native|wasix) - ;; - *) - echo "--runtime must be native or wasix" >&2 - usage - exit 2 - ;; -esac -case "$iterations" in - ''|*[!0-9]*|0) - echo "--iterations must be a positive integer" >&2 - exit 2 - ;; -esac -case "$warmup" in - ''|*[!0-9]*|0) - echo "--warmup must be a positive integer" >&2 - exit 2 - ;; -esac -if [[ -z "$run_id" || "$run_id" == */* || "$run_id" == *..* ]]; then - echo "--run-id must be a non-empty path segment" >&2 - exit 2 -fi - -if [[ -z "$output_dir" ]]; then - output_dir="$root/target/perf/rust-api-model/$runtime-$run_id" -elif [[ "$output_dir" != /* ]]; then - output_dir="$root/$output_dir" -fi -mkdir -p "$output_dir" -for output in sync.json async.json summary.json report.md; do - if [[ -e "$output_dir/$output" ]]; then - echo "refusing to overwrite existing diagnostic output: $output_dir/$output" >&2 - exit 1 - fi -done - -# Runtime artifact checks stay outside the measured processes. Cargo output is -# also on stderr, so each redirected stdout file contains only one JSON run. -. "$root/src/runtimes/liboliphaunt/native/tools/runtime-preflight.sh" -. "$root/src/runtimes/liboliphaunt/wasix/tools/runtime-preflight.sh" -features="rust-api-model" -if [[ "$runtime" == native ]]; then - oliphaunt_runtime_native_host_require basic -else - oliphaunt_runtime_wasm_require smoke - host="$(oliphaunt_runtime_wasm_host_triple)" - cargo run -p xtask -- assets install-local --target-triple "$host" - export OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR="$root/target/oliphaunt-wasix/assets" - export OLIPHAUNT_WASM_GENERATED_AOT_DIR="$root/target/oliphaunt-wasix/aot" - features="rust-api-model-wasix" -fi - -for api in sync async; do - cargo run --release --locked -p oliphaunt-perf \ - --features "$features" \ - --bin oliphaunt-rust-api-model -- \ - --runtime "$runtime" \ - --api "$api" \ - --iterations "$iterations" \ - --warmup "$warmup" >"$output_dir/$api.json" -done - -tools/dev/bun.sh tools/perf/rust-api-model/summarize.mjs \ - --runtime "$runtime" \ - --sync "$output_dir/sync.json" \ - --async "$output_dir/async.json" \ - --output-dir "$output_dir" - -printf 'diagnostic-only report: %s\n' "$output_dir/report.md" diff --git a/tools/perf/rust-api-model/summarize.mjs b/tools/perf/rust-api-model/summarize.mjs deleted file mode 100644 index 56fc09ed5..000000000 --- a/tools/perf/rust-api-model/summarize.mjs +++ /dev/null @@ -1,318 +0,0 @@ -#!/usr/bin/env node -import fs from 'node:fs/promises' -import path from 'node:path' -import process from 'node:process' -import { pathToFileURL } from 'node:url' - -export const RUN_SCHEMA = 'oliphaunt.rust-api-model-run.v1' -export const PAIR_SCHEMA = 'oliphaunt.rust-api-model-pair.v1' -export const CLASSIFICATION = 'diagnostic-only' -export const OPERATIONS = ['query-select-1', 'raw-simple-query-select-1'] - -const EXPECTED_PLACEMENT = { - native: { - sync: { - callingContract: 'blocking', - executionOwner: 'liboliphaunt-backend-thread', - sdkQueue: 'none', - }, - async: { - callingContract: 'awaited', - executionOwner: 'sdk-owner-thread-plus-liboliphaunt-backend-thread', - sdkQueue: 'one-owner-fifo', - }, - }, - wasix: { - sync: { - callingContract: 'blocking', - executionOwner: 'caller-thread', - sdkQueue: 'none', - }, - async: { - callingContract: 'awaited', - executionOwner: 'sdk-owner-thread', - sdkQueue: 'one-owner-fifo', - }, - }, -} - -function requireString(value, label) { - if (typeof value !== 'string' || value.length === 0) { - throw new Error(label + ' must be a non-empty string') - } - return value -} - -function requirePositiveInteger(value, label) { - if (!Number.isInteger(value) || value <= 0) { - throw new Error(label + ' must be a positive integer') - } - return value -} - -function requireFinite(value, label, positive = false) { - if (!Number.isFinite(value) || value < 0 || (positive && value <= 0)) { - throw new Error(label + ' must be a ' + (positive ? 'positive' : 'non-negative') + ' number') - } - return value -} - -function validateOperation(operation, label, iterations) { - requireString(operation?.operation, label + '.operation') - if (!OPERATIONS.includes(operation.operation)) { - throw new Error(label + '.operation is unsupported: ' + operation.operation) - } - if (operation.samples !== iterations) { - throw new Error(label + '.samples must equal iterations') - } - for (const field of [ - 'totalMicros', - 'meanMicros', - 'operationsPerSecond', - 'minMicros', - 'p50Micros', - 'p95Micros', - 'p99Micros', - 'maxMicros', - ]) { - requireFinite(operation[field], label + '.' + field, true) - } - if ( - !( - operation.minMicros <= operation.p50Micros && - operation.p50Micros <= operation.p95Micros && - operation.p95Micros <= operation.p99Micros && - operation.p99Micros <= operation.maxMicros - ) - ) { - throw new Error(label + ' percentiles are not monotonic') - } - return operation -} - -export function validateRun(run, runtime, api) { - if (run?.schema !== RUN_SCHEMA) { - throw new Error(api + ' run schema must be ' + RUN_SCHEMA) - } - if (run.classification !== CLASSIFICATION || run.releaseEvidence !== false) { - throw new Error(api + ' run must be diagnostic-only and releaseEvidence=false') - } - if (run.runtime !== runtime || run.api !== api) { - throw new Error(api + ' run labels do not match ' + runtime + '/' + api) - } - if (run.topology !== 'direct' || run.processModel !== 'one-api-model-per-process') { - throw new Error(api + ' run must use direct topology in its own process') - } - if (run.sql !== 'SELECT 1::text AS value') { - throw new Error(api + ' run SQL changed unexpectedly') - } - const placement = EXPECTED_PLACEMENT[runtime]?.[api] - if (!placement) { - throw new Error('unsupported runtime/API pair ' + runtime + '/' + api) - } - for (const [field, expected] of Object.entries(placement)) { - if (run[field] !== expected) { - throw new Error(api + ' run ' + field + ' must be ' + expected) - } - } - requirePositiveInteger(run.iterations, api + '.iterations') - requirePositiveInteger(run.warmupIterations, api + '.warmupIterations') - requireFinite(run.openMicros, api + '.openMicros') - requireFinite(run.closeMicros, api + '.closeMicros') - if (!Array.isArray(run.operations) || run.operations.length !== OPERATIONS.length) { - throw new Error(api + ' run must contain exactly ' + OPERATIONS.length + ' operations') - } - const byOperation = Object.fromEntries( - run.operations.map((operation, index) => [ - operation.operation, - validateOperation(operation, api + '.operations[' + index + ']', run.iterations), - ]), - ) - if (Object.keys(byOperation).length !== OPERATIONS.length) { - throw new Error(api + ' run contains duplicate operations') - } - for (const operation of OPERATIONS) { - if (!byOperation[operation]) { - throw new Error(api + ' run is missing ' + operation) - } - } - return { run, byOperation } -} - -export function createPairSummary(syncRun, asyncRun, runtime, generatedAt = new Date().toISOString()) { - if (!['native', 'wasix'].includes(runtime)) { - throw new Error('unsupported runtime ' + runtime) - } - const sync = validateRun(syncRun, runtime, 'sync') - const async = validateRun(asyncRun, runtime, 'async') - for (const field of ['iterations', 'warmupIterations', 'sql']) { - if (syncRun[field] !== asyncRun[field]) { - throw new Error('paired runs must use the same ' + field) - } - } - - const ratios = Object.fromEntries( - OPERATIONS.map((operation) => [ - operation, - { - meanAsyncOverSync: - async.byOperation[operation].meanMicros / sync.byOperation[operation].meanMicros, - p50AsyncOverSync: - async.byOperation[operation].p50Micros / sync.byOperation[operation].p50Micros, - p95AsyncOverSync: - async.byOperation[operation].p95Micros / sync.byOperation[operation].p95Micros, - p99AsyncOverSync: - async.byOperation[operation].p99Micros / sync.byOperation[operation].p99Micros, - }, - ]), - ) - - return { - schema: PAIR_SCHEMA, - classification: CLASSIFICATION, - releaseEvidence: false, - runtime, - topology: 'direct', - generatedAt, - methodology: { - processModel: 'separate-process-per-api-model', - startupIncludedInOperationSamples: false, - validationIncludedInOperationSamples: false, - concurrency: 'one-sequential-awaited-operation-at-a-time', - sql: syncRun.sql, - iterations: syncRun.iterations, - warmupIterations: syncRun.warmupIterations, - }, - runs: { - sync: sync.run, - async: async.run, - }, - ratios, - } -} - -function fixed(value, digits = 3) { - return Number.isFinite(value) ? value.toFixed(digits) : 'n/a' -} - -export function renderMarkdown(summary) { - const lines = [ - '# Rust ' + summary.runtime.toUpperCase() + ' sync-versus-async diagnostic', - '', - '> Diagnostic only. This report is not release evidence and does not participate in performance gates.', - '', - '- Runtime: ' + summary.runtime, - '- Topology: direct', - '- SQL: ' + summary.methodology.sql, - '- Measured iterations per operation: ' + summary.methodology.iterations, - '- Warmup iterations per operation: ' + summary.methodology.warmupIterations, - '- Process model: one fresh process per API model', - '- Open and close are reported separately and excluded from operation samples', - '- Each measured call is sequential; this does not measure concurrent throughput', - '', - '| API | Calling contract | Execution owner | Open us | Close us |', - '| --- | --- | --- | ---: | ---: |', - ] - for (const api of ['sync', 'async']) { - const run = summary.runs[api] - lines.push( - '| ' + - api + - ' | ' + - run.callingContract + - ' | ' + - run.executionOwner + - ' | ' + - fixed(run.openMicros) + - ' | ' + - fixed(run.closeMicros) + - ' |', - ) - } - - lines.push( - '', - '| Operation | API | mean us | p50 us | p95 us | p99 us | ops/s | async/sync mean |', - '| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: |', - ) - for (const operation of OPERATIONS) { - for (const api of ['sync', 'async']) { - const result = summary.runs[api].operations.find((item) => item.operation === operation) - const ratio = - api === 'async' ? fixed(summary.ratios[operation].meanAsyncOverSync) + 'x' : '—' - lines.push( - '| ' + - operation + - ' | ' + - api + - ' | ' + - fixed(result.meanMicros) + - ' | ' + - fixed(result.p50Micros) + - ' | ' + - fixed(result.p95Micros) + - ' | ' + - fixed(result.p99Micros) + - ' | ' + - fixed(result.operationsPerSecond, 1) + - ' | ' + - ratio + - ' |', - ) - } - } - lines.push( - '', - 'The async/sync ratio includes the public async admission, owner-FIFO dispatch, wakeup, and reply path. It is not a claim about runtime topology, database concurrency, or application-level throughput.', - '', - ) - return lines.join('\n') -} - -function parseArgs(argv) { - const args = {} - for (let index = 0; index < argv.length; index += 1) { - const key = argv[index] - if (!key.startsWith('--')) { - throw new Error('unexpected argument ' + key) - } - const value = argv[index + 1] - if (!value || value.startsWith('--')) { - throw new Error(key + ' requires a value') - } - args[key] = value - index += 1 - } - return args -} - -async function readJson(file) { - return JSON.parse(await fs.readFile(file, 'utf8')) -} - -async function main() { - const args = parseArgs(process.argv.slice(2)) - const runtime = requireString(args['--runtime'], '--runtime') - const syncPath = path.resolve(requireString(args['--sync'], '--sync')) - const asyncPath = path.resolve(requireString(args['--async'], '--async')) - const outputDir = path.resolve(requireString(args['--output-dir'], '--output-dir')) - const summary = createPairSummary( - await readJson(syncPath), - await readJson(asyncPath), - runtime, - ) - await fs.mkdir(outputDir, { recursive: true }) - await fs.writeFile( - path.join(outputDir, 'summary.json'), - JSON.stringify(summary, null, 2) + '\n', - ) - await fs.writeFile(path.join(outputDir, 'report.md'), renderMarkdown(summary)) - console.log(path.join(outputDir, 'report.md')) -} - -if ( - process.argv[1] && - import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href -) { - await main() -} diff --git a/tools/perf/rust-api-model/summarize.test.mjs b/tools/perf/rust-api-model/summarize.test.mjs deleted file mode 100644 index 6db6d8196..000000000 --- a/tools/perf/rust-api-model/summarize.test.mjs +++ /dev/null @@ -1,105 +0,0 @@ -import { describe, expect, test } from 'bun:test' - -import { - CLASSIFICATION, - OPERATIONS, - createPairSummary, - renderMarkdown, - validateRun, -} from './summarize.mjs' - -function operation(name, scale = 1) { - return { - operation: name, - samples: 10, - totalMicros: 100 * scale, - meanMicros: 10 * scale, - operationsPerSecond: 100_000 / scale, - minMicros: 5 * scale, - p50Micros: 9 * scale, - p95Micros: 14 * scale, - p99Micros: 16 * scale, - maxMicros: 18 * scale, - } -} - -function run(runtime, api, scale = 1) { - const placement = { - native: { - sync: ['blocking', 'liboliphaunt-backend-thread', 'none'], - async: [ - 'awaited', - 'sdk-owner-thread-plus-liboliphaunt-backend-thread', - 'one-owner-fifo', - ], - }, - wasix: { - sync: ['blocking', 'caller-thread', 'none'], - async: ['awaited', 'sdk-owner-thread', 'one-owner-fifo'], - }, - }[runtime][api] - return { - schema: 'oliphaunt.rust-api-model-run.v1', - classification: CLASSIFICATION, - releaseEvidence: false, - runtime, - api, - callingContract: placement[0], - executionOwner: placement[1], - sdkQueue: placement[2], - topology: 'direct', - processModel: 'one-api-model-per-process', - sql: 'SELECT 1::text AS value', - iterations: 10, - warmupIterations: 2, - openMicros: 1_000 * scale, - closeMicros: 100 * scale, - operations: OPERATIONS.map((name) => operation(name, scale)), - } -} - -describe('Rust API model diagnostic summary', () => { - for (const runtime of ['native', 'wasix']) { - test(`validates and pairs explicit ${runtime} sync/async placement`, () => { - const summary = createPairSummary( - run(runtime, 'sync'), - run(runtime, 'async', 1.5), - runtime, - '2026-08-28T00:00:00.000Z', - ) - expect(summary.classification).toBe('diagnostic-only') - expect(summary.releaseEvidence).toBe(false) - expect(summary.ratios['query-select-1'].meanAsyncOverSync).toBe(1.5) - expect(summary.methodology.startupIncludedInOperationSamples).toBe(false) - expect(renderMarkdown(summary)).toContain( - 'This report is not release evidence and does not participate in performance gates.', - ) - }) - } - - test('rejects release-evidence relabeling and execution-owner drift', () => { - const mislabeled = run('native', 'sync') - mislabeled.releaseEvidence = true - expect(() => validateRun(mislabeled, 'native', 'sync')).toThrow('diagnostic-only') - - const wrongOwner = run('wasix', 'async') - wrongOwner.executionOwner = 'caller-thread' - expect(() => validateRun(wrongOwner, 'wasix', 'async')).toThrow( - 'executionOwner must be sdk-owner-thread', - ) - }) - - test('rejects incomparable pairs and malformed samples', () => { - const asyncRun = run('native', 'async') - asyncRun.iterations = 11 - expect(() => - createPairSummary(run('native', 'sync'), asyncRun, 'native'), - ).toThrow('samples must equal iterations') - - const malformed = run('native', 'sync') - malformed.operations[0].p50Micros = 20 - expect(() => validateRun(malformed, 'native', 'sync')).toThrow( - 'percentiles are not monotonic', - ) - }) -}) diff --git a/tools/perf/wasix-browser/plan.mjs b/tools/perf/wasix-browser/plan.mjs deleted file mode 100644 index 8bcb1201f..000000000 --- a/tools/perf/wasix-browser/plan.mjs +++ /dev/null @@ -1,625 +0,0 @@ -import { readFile } from 'node:fs/promises'; -import { dirname, relative, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { comfortableWinGate, median, pairedRatioSummary, sha256 } from '../wasix-node/plan.mjs'; - -export const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..'); -export const defaultBrowserPlanFile = resolve( - repositoryRoot, - 'benchmarks/wasix/browser-pglite-memory-v2.json', -); - -const PLAN_SCHEMA = 'oliphaunt-wasix-browser-benchmark-plan-v2'; -const RESULT_SCHEMA = 'oliphaunt-wasix-browser-engine-result-v2'; -const PLAN_ID = 'browser-pglite-memory-v2'; -const CANDIDATE_PACKAGE = '@oliphaunt/wasix-ts'; -const COMPARISON_PACKAGE = '@electric-sql/pglite'; -const COMPARISON_VERSION = '0.5.4'; -const COMPARISON_INTEGRITY = - 'sha512-yYZUyyXrHU7tPlCjwZQJ6hIG9DscdCCn7Uk0mYKwC1FeHX286AbcmFveMiRBEak8e9iPupjsoVImN3yJZVed2g=='; -const COMPARISON_COMMIT = '25d0a55e1f1e4c59f26d9e125150dda88a33fd00'; -const COMPARISON_TREE_SHA256 = 'b3925de04c386f51859c1bf18c143b225e3850616718140dd32e8eb48e9a2c84'; -const ENGINE_NAMES = ['wasixDirect', 'wasixWorker', 'pgliteDirect', 'pgliteWorker']; -const PROFILE_FIELDS = [ - 'startupRuns', - 'workloadRuns', - 'insertDiagnosticRuns', - 'pointSamples', - 'rangeSamples', - 'aggregateSamples', - 'transactionInserts', - 'qualificationEligible', -]; -const QUICK_PROFILE = { - startupRuns: 2, - workloadRuns: 1, - insertDiagnosticRuns: 1, - pointSamples: 20, - rangeSamples: 10, - aggregateSamples: 5, - transactionInserts: 20, - qualificationEligible: false, -}; -const FULL_PROFILE = { - startupRuns: 5, - insertDiagnosticRuns: 5, - pointSamples: 200, - rangeSamples: 50, - aggregateSamples: 30, - transactionInserts: 100, - qualificationEligible: true, -}; -const MEASUREMENT = { - rows: 10_000, - storage: 'ephemeral-memory', - order: 'rotating-engines-with-same-run-pairing', - warmup: 'one-untimed-representative-workload-per-fresh-database', - timingBoundary: 'browser-caller-end-to-end-around-public-api', - pairing: 'same-run-oliphaunt-over-pglite', - percentileMethod: 'nearest-rank', -}; -const GATE_METRICS = [ - 'startup.warmReadyMs', - 'workload.createTableMs', - 'workload.insert10kMs', - 'workload.pointMedianMs', - 'workload.pointP95Ms', - 'workload.range100MedianMs', - 'workload.range100P95Ms', - 'workload.aggregateMedianMs', - 'workload.aggregateP95Ms', - 'workload.scanAndDecode10kMs', - 'workload.transactionInsertBatchMs', - 'workload.update1kMs', - 'workload.delete1kMs', -]; -const GATE_EXCLUSIONS = { - 'startup.firstReadyMs': - 'descriptive because the implementations use different compilation caches', - 'workload.readyMs': 'duplicates the independently sampled warm-start metric', - 'workload.closeMs': - 'descriptive because the public close methods make different worker-reclamation guarantees', - 'insertDiagnostic.*Ms': - 'diagnostic decomposition would otherwise overweight the primary insert workload', - 'insertDiagnostic.indexedInsertWalBytes': 'semantic parity constraint rather than a speed metric', -}; -const POSTGRES_SETTINGS = { - fsync: 'off', - synchronousCommit: 'on', - fullPageWrites: 'on', - walLevel: 'replica', -}; -const RUNTIME_BUILD = { - profile: 'release', - cflags: '-O2 -g0 -flto=thin', - ldflags: '-flto=thin', - configureWasmOpt: 'no', - buildWasmOpt: 'yes', - wasmOptFlags: '--converge:--strip-debug:--strip-producers', - wasmOptSuppressDefault: '', - wasmOptPreserveUnoptimized: '', - compilerFlags: '', - linkerFlags: '', - backendTiming: '0', -}; -const SURFACE_COMPARISONS = { - direct: ['wasixDirect', 'pgliteDirect'], - worker: ['wasixWorker', 'pgliteWorker'], -}; -const CANDIDATE_EXECUTION_SURFACES = { - direct: { - entrypoint: '@oliphaunt/wasix-ts', - callingContract: 'async', - executionOwner: 'caller', - }, - worker: { - entrypoint: '@oliphaunt/wasix-ts/worker', - callingContract: 'async', - executionOwner: 'sdk-worker', - }, -}; - -export async function loadBrowserPlan(file = defaultBrowserPlanFile) { - const bytes = await readFile(file); - let plan; - try { - plan = JSON.parse(bytes.toString('utf8')); - } catch (error) { - throw new Error(`${relative(repositoryRoot, file)} must contain JSON`, { cause: error }); - } - validateBrowserPlan(plan); - return { plan, file: resolve(file), sha256: sha256(bytes), size: bytes.length }; -} - -export function validateBrowserPlan(plan) { - requireRecord(plan, 'plan'); - requireEqual(plan.schema, PLAN_SCHEMA, 'plan.schema'); - validatePlanEnvelope(plan); - - const engines = requireRecord(plan.engines, 'plan.engines'); - requireExactKeys(engines, ['candidate', 'comparison'], 'plan.engines'); - const candidate = requireRecord(engines.candidate, 'plan.engines.candidate'); - const comparison = requireRecord(engines.comparison, 'plan.engines.comparison'); - requireExactKeys( - candidate, - ['package', 'storage', 'surfaces', 'dependencies', 'runtimeBuild'], - 'plan.engines.candidate', - ); - requireEqual(candidate.package, CANDIDATE_PACKAGE, 'plan.engines.candidate.package'); - requireEqual(candidate.storage, 'memory', 'plan.engines.candidate.storage'); - requireExactRecord( - requireRecord(candidate.surfaces, 'plan.engines.candidate.surfaces').direct, - { - engine: 'wasixDirect', - ...CANDIDATE_EXECUTION_SURFACES.direct, - }, - 'plan.engines.candidate.surfaces.direct', - ); - requireExactRecord( - candidate.surfaces.worker, - { - engine: 'wasixWorker', - ...CANDIDATE_EXECUTION_SURFACES.worker, - }, - 'plan.engines.candidate.surfaces.worker', - ); - requireExactKeys(candidate.surfaces, ['direct', 'worker'], 'plan.engines.candidate.surfaces'); - requireExactRecord( - candidate.dependencies, - { fzstd: '0.1.1' }, - 'plan.engines.candidate.dependencies', - ); - requireExactRecord(candidate.runtimeBuild, RUNTIME_BUILD, 'plan.engines.candidate.runtimeBuild'); - - requireExactKeys( - comparison, - [ - 'package', - 'version', - 'integrity', - 'homepage', - 'sourceRepository', - 'sourceCommit', - 'installedTreeHashSchema', - 'installedTreeSha256', - 'storage', - 'surfaces', - ], - 'plan.engines.comparison', - ); - for (const [field, expected] of Object.entries({ - package: COMPARISON_PACKAGE, - version: COMPARISON_VERSION, - integrity: COMPARISON_INTEGRITY, - homepage: 'https://pglite.dev', - sourceRepository: 'https://github.com/electric-sql/pglite', - sourceCommit: COMPARISON_COMMIT, - installedTreeHashSchema: 'oliphaunt-path-size-content-sha256-v1', - installedTreeSha256: COMPARISON_TREE_SHA256, - storage: 'memory', - })) { - requireEqual(comparison[field], expected, `plan.engines.comparison.${field}`); - } - const comparisonSurfaces = requireRecord(comparison.surfaces, 'plan.engines.comparison.surfaces'); - requireExactKeys( - comparisonSurfaces, - ['callerRealm', 'worker'], - 'plan.engines.comparison.surfaces', - ); - requireExactRecord( - comparisonSurfaces.callerRealm, - { - engine: 'pgliteDirect', - entrypoint: '@electric-sql/pglite', - callingContract: 'async', - executionOwner: 'caller', - }, - 'plan.engines.comparison.surfaces.callerRealm', - ); - requireExactRecord( - comparisonSurfaces.worker, - { - engine: 'pgliteWorker', - entrypoint: '@electric-sql/pglite/worker', - callingContract: 'async', - executionOwner: 'caller-provided-worker', - }, - 'plan.engines.comparison.surfaces.worker', - ); - - validateCommonPlan(plan); -} - -function validatePlanEnvelope(plan) { - requireExactKeys( - plan, - ['schema', 'id', 'description', 'engines', 'profiles', 'measurement', 'gate', 'postgres'], - 'plan', - ); - requireEqual(plan.id, PLAN_ID, 'plan.id'); - requireNonEmptyString(plan.description, 'plan.description'); -} - -function validateCommonPlan(plan) { - const profiles = requireRecord(plan.profiles, 'plan.profiles'); - requireExactKeys(profiles, ['quick', 'full'], 'plan.profiles'); - requireExactRecord(profiles.quick, QUICK_PROFILE, 'plan.profiles.quick'); - const full = requireRecord(profiles.full, 'plan.profiles.full'); - requireExactKeys(full, PROFILE_FIELDS, 'plan.profiles.full'); - for (const [field, expected] of Object.entries(FULL_PROFILE)) { - requireEqual(full[field], expected, `plan.profiles.full.${field}`); - } - requirePositiveInteger(full.workloadRuns, 'plan.profiles.full.workloadRuns'); - if ( - full.workloadRuns < ENGINE_NAMES.length * 2 || - full.workloadRuns % ENGINE_NAMES.length !== 0 - ) { - throw new Error('plan.profiles.full.workloadRuns must be a multiple of 4 and at least 8'); - } - - requireExactRecord(plan.measurement, MEASUREMENT, 'plan.measurement'); - const gate = requireRecord(plan.gate, 'plan.gate'); - requireExactKeys( - gate, - [ - 'maxGeomeanRatio', - 'requiresCorrectness', - 'requiresBothExecutionSurfaces', - 'metric', - 'metrics', - 'excluded', - ], - 'plan.gate', - ); - requireEqual(gate.maxGeomeanRatio, 0.8, 'plan.gate.maxGeomeanRatio'); - requireEqual(gate.requiresCorrectness, true, 'plan.gate.requiresCorrectness'); - requireEqual(gate.requiresBothExecutionSurfaces, true, 'plan.gate.requiresBothExecutionSurfaces'); - requireEqual( - gate.metric, - 'geometric-mean-of-median-paired-oliphaunt-over-pglite-ratios-lower-is-better', - 'plan.gate.metric', - ); - requireExactStringList(gate.metrics, GATE_METRICS, 'plan.gate.metrics'); - for (const metric of gate.metrics) validateMetricId(metric); - requireExactRecord(gate.excluded, GATE_EXCLUSIONS, 'plan.gate.excluded'); - - const postgres = requireRecord(plan.postgres, 'plan.postgres'); - requireExactKeys( - postgres, - ['major', 'settings', 'indexedInsertWalTolerancePercent'], - 'plan.postgres', - ); - requireEqual(postgres.major, 18, 'plan.postgres.major'); - requireExactRecord(postgres.settings, POSTGRES_SETTINGS, 'plan.postgres.settings'); - requireEqual( - postgres.indexedInsertWalTolerancePercent, - 0.1, - 'plan.postgres.indexedInsertWalTolerancePercent', - ); -} - -export function qualifyingGitProvenance({ commit, tree, status }) { - if (!/^[0-9a-f]{40}$/u.test(commit)) { - throw new Error('browser benchmark qualification requires an exact Git commit'); - } - if (!/^[0-9a-f]{40}$/u.test(tree)) { - throw new Error('browser benchmark qualification requires an exact Git tree'); - } - if (typeof status !== 'string') { - throw new Error('browser benchmark qualification requires Git porcelain status text'); - } - if (status !== '') { - throw new Error('browser benchmark qualification requires a clean Git worktree'); - } - return { commit, tree, dirty: false }; -} - -export function summarizeBrowserResult(planSource, result) { - const plan = planSource.plan; - validateBrowserResult(plan, result); - const correctness = summarizeCorrectness(plan, result); - const comparisons = Object.fromEntries( - Object.entries(SURFACE_COMPARISONS).map(([surface, [candidate, comparison]]) => { - const metrics = plan.gate.metrics.map((id) => { - const candidateSamplesMs = metricSamples(result, candidate, id); - const comparisonSamplesMs = metricSamples(result, comparison, id); - const paired = pairedRatioSummary(candidateSamplesMs, comparisonSamplesMs); - return { - id, - candidateSamplesMs, - comparisonSamplesMs, - candidateMedianMs: median(candidateSamplesMs), - comparisonMedianMs: median(comparisonSamplesMs), - pairs: paired.pairedRatios.map((ratio, repeat) => ({ - repeat, - candidateMs: candidateSamplesMs[repeat], - comparisonMs: comparisonSamplesMs[repeat], - ratio, - })), - pairedRatioMedian: paired.medianRatio, - }; - }); - const aggregate = comfortableWinGate( - metrics.map((metric) => metric.pairedRatioMedian), - plan.gate.maxGeomeanRatio, - correctness.passed, - ); - return [surface, { metrics, ...aggregate }]; - }), - ); - const qualificationEligible = plan.profiles[result.mode].qualificationEligible; - const performancePassed = Object.values(comparisons).every( - (comparison) => comparison.gate.passed, - ); - return { - correctness, - comparisons, - gate: { - required: qualificationEligible, - passed: qualificationEligible ? performancePassed && correctness.passed : null, - maxGeomeanRatio: plan.gate.maxGeomeanRatio, - requiresBothExecutionSurfaces: true, - metric: plan.gate.metric, - excluded: plan.gate.excluded, - }, - passed: correctness.passed && (!qualificationEligible || performancePassed), - }; -} - -export function browserPlanSummary(source) { - return { - id: source.plan.id, - schema: source.plan.schema, - sha256: source.sha256, - size: source.size, - engines: source.plan.engines, - profiles: source.plan.profiles, - measurement: source.plan.measurement, - gate: source.plan.gate, - postgres: source.plan.postgres, - }; -} - -export function browserMarkdownReport(report) { - const comparisonSections = Object.entries(report.summary.comparisons) - .map(([name, comparison]) => { - const rows = comparison.metrics - .map( - (metric) => - `| \`${metric.id}\` | ${metric.candidateMedianMs.toFixed(3)} | ` + - `${metric.comparisonMedianMs.toFixed(3)} | ${metric.pairedRatioMedian.toFixed(3)} |`, - ) - .join('\n'); - const gateLabel = report.summary.gate.required - ? `Comfortable-win gate: **${comparison.gate.passed ? 'PASS' : 'FAIL'}**` - : `Comfortable-win statistic: **${comparison.gate.passed ? 'would pass' : 'would fail'} (advisory quick profile)**`; - return `## ${name[0].toUpperCase()}${name.slice(1)} comparison - -- ${gateLabel} -- Geometric-mean ratio: **${comparison.geomeanRatio.toFixed(4)}** (required <= ${comparison.gate.maxGeomeanRatio.toFixed(2)}) -- Observed aggregate win: **${comparison.gate.observedWinPercent.toFixed(2)}%** - -| Metric (lower is better) | Oliphaunt median ms | PGlite median ms | Median paired ratio | -| --- | ---: | ---: | ---: | -${rows}`; - }) - .join('\n\n'); - return `# WASIX browser benchmark report - -- Plan: \`${report.plan.id}\` (\`${report.plan.sha256}\`) -- Candidate: \`${report.plan.engines.candidate.package}\` -- Comparison: \`${report.plan.engines.comparison.package}@${report.plan.engines.comparison.version}\` -- Browser: \`${report.result.environment.userAgent}\` -- Cross-origin isolated: **${report.result.environment.crossOriginIsolated ? 'yes' : 'no'}** -- Workload assertions: **${report.summary.correctness.workloadAssertionsPassed ? 'PASS' : 'FAIL'}** -- PostgreSQL durability parity: **${report.summary.correctness.durability.passed ? 'PASS' : 'FAIL'}** -- Indexed-insert WAL parity: **${report.summary.correctness.indexedInsertWal.passed ? 'PASS' : 'FAIL'}** -- Overall qualification: **${report.summary.gate.required ? (report.summary.gate.passed ? 'PASS' : 'FAIL') : 'NOT GATED (quick profile)'}** - -${comparisonSections} - -First cold open, duplicated workload-open time, close, and insert decomposition remain in the JSON report but are not speed-gated. Close is descriptive because the public APIs make different worker-reclamation guarantees. The gate requires the geometric mean of median same-run Oliphaunt/PGlite ratios to be at most 0.80 independently for the caller-owned root and explicit SDK-owned Worker execution surfaces, after workload assertions and PostgreSQL durability/WAL parity pass. -`; -} - -function validateBrowserResult(plan, result) { - requireRecord(result, 'browser result'); - requireEqual(result.schema, RESULT_SCHEMA, 'result.schema'); - requireEqual(result.plan, plan.id, 'result.plan'); - if (!['quick', 'full'].includes(result.mode)) throw new Error('result.mode is invalid'); - const expected = plan.profiles[result.mode]; - const configuration = requireRecord(result.configuration, 'result.configuration'); - for (const field of [ - 'startupRuns', - 'workloadRuns', - 'insertDiagnosticRuns', - 'pointSamples', - 'rangeSamples', - 'aggregateSamples', - 'transactionInserts', - ]) { - requireEqual(configuration[field], expected[field], `result.configuration.${field}`); - } - requireEqual(configuration.rows, plan.measurement.rows, 'result.configuration.rows'); - requireEqual(configuration.storage, plan.measurement.storage, 'result.configuration.storage'); - requireNestedExactRecord( - configuration.executionSurfaces, - CANDIDATE_EXECUTION_SURFACES, - 'result.configuration.executionSurfaces', - ); - requireEqual(result.correctness?.assertionsPassed, true, 'result correctness'); - requireEqual(result.environment?.crossOriginIsolated, true, 'cross-origin isolation'); - - for (const engine of ENGINE_NAMES) { - requireArrayLength( - result.samples?.startup?.[engine], - expected.startupRuns, - `${engine} startup`, - ); - requireArrayLength( - result.samples?.workload?.[engine], - expected.workloadRuns, - `${engine} workloads`, - ); - requireArrayLength( - result.insertDiagnostic?.samples?.[engine], - expected.insertDiagnosticRuns, - `${engine} insert diagnostics`, - ); - } -} - -function summarizeCorrectness(plan, result) { - const settings = plan.postgres.settings; - const durability = Object.fromEntries( - Object.entries(SURFACE_COMPARISONS).map(([surface, [candidate, comparison]]) => { - const candidateProfile = result.postgresProfiles[candidate]; - const comparisonProfile = result.postgresProfiles[comparison]; - const candidateValid = profileMatches(candidateProfile, settings, plan.postgres.major); - const comparisonValid = profileMatches(comparisonProfile, settings, plan.postgres.major); - const parity = Object.keys(settings).every( - (setting) => candidateProfile?.[setting] === comparisonProfile?.[setting], - ); - return [ - surface, - { - passed: candidateValid && comparisonValid && parity, - candidateProfile, - comparisonProfile, - }, - ]; - }), - ); - durability.passed = durability.direct.passed && durability.worker.passed; - - const wal = result.insertDiagnostic.summary.indexedInsertWalBytes; - const indexedInsertWal = Object.fromEntries( - Object.entries(SURFACE_COMPARISONS).map(([surface, [candidate, comparison]]) => { - const candidateBytes = positiveNumber(wal[candidate], `${candidate} WAL bytes`); - const comparisonBytes = positiveNumber(wal[comparison], `${comparison} WAL bytes`); - const deltaPercent = (Math.abs(candidateBytes - comparisonBytes) / comparisonBytes) * 100; - return [ - surface, - { - passed: deltaPercent <= plan.postgres.indexedInsertWalTolerancePercent, - candidateBytes, - comparisonBytes, - deltaBytes: candidateBytes - comparisonBytes, - deltaPercent, - tolerancePercent: plan.postgres.indexedInsertWalTolerancePercent, - }, - ]; - }), - ); - indexedInsertWal.passed = indexedInsertWal.direct.passed && indexedInsertWal.worker.passed; - const workloadAssertionsPassed = result.correctness.assertionsPassed === true; - return { - passed: workloadAssertionsPassed && durability.passed && indexedInsertWal.passed, - workloadAssertionsPassed, - durability, - indexedInsertWal, - }; -} - -function metricSamples(result, engine, id) { - if (id === 'startup.warmReadyMs') { - return result.samples.startup[engine] - .slice(1) - .map((value, index) => positiveNumber(value, `${engine} ${id} sample ${index}`)); - } - const match = /^workload\.([A-Za-z][A-Za-z0-9]*)$/u.exec(id); - if (match === null) throw new Error(`unsupported browser benchmark metric ${id}`); - return result.samples.workload[engine].map((run, index) => - positiveNumber(run?.metrics?.[match[1]], `${engine} ${id} sample ${index}`), - ); -} - -function validateMetricId(id) { - if (id === 'startup.warmReadyMs') return; - if (!/^workload\.(?!readyMs$|closeMs$)[A-Za-z][A-Za-z0-9]*$/u.test(id)) { - throw new Error(`unsupported gated browser benchmark metric ${JSON.stringify(id)}`); - } -} - -function profileMatches(profile, settings, major) { - return ( - profile !== null && - typeof profile === 'object' && - new RegExp(`^${major}\\.`).test(profile.version) && - Object.entries(settings).every(([name, expected]) => profile[name] === expected) - ); -} - -function requireArrayLength(value, length, label) { - if (!Array.isArray(value) || value.length !== length) { - throw new Error(`${label} must contain exactly ${length} entries`); - } -} - -function requireRecord(value, label) { - if (value === null || typeof value !== 'object' || Array.isArray(value)) { - throw new Error(`${label} must be an object`); - } - return value; -} - -function requireExactRecord(value, expected, label) { - const record = requireRecord(value, label); - requireExactKeys(record, Object.keys(expected), label); - for (const [field, expectedValue] of Object.entries(expected)) { - requireEqual(record[field], expectedValue, `${label}.${field}`); - } - return record; -} - -function requireNestedExactRecord(value, expected, label) { - const record = requireRecord(value, label); - requireExactKeys(record, Object.keys(expected), label); - for (const [field, expectedValue] of Object.entries(expected)) { - requireExactRecord(record[field], expectedValue, `${label}.${field}`); - } - return record; -} - -function requireExactKeys(value, expected, label) { - const actual = Object.keys(value).sort(); - const required = [...expected].sort(); - if (JSON.stringify(actual) !== JSON.stringify(required)) { - throw new Error(`${label} must contain exactly ${JSON.stringify(required)}`); - } -} - -function requireExactStringList(value, expected, label) { - if (!Array.isArray(value) || value.length !== expected.length) { - throw new Error(`${label} must contain exactly ${expected.length} entries`); - } - for (let index = 0; index < expected.length; index += 1) { - requireEqual(value[index], expected[index], `${label}[${index}]`); - } -} - -function requireNonEmptyString(value, label) { - if (typeof value !== 'string' || value.trim() === '') { - throw new Error(`${label} must be a non-empty string`); - } -} - -function requirePositiveInteger(value, label) { - if (!Number.isSafeInteger(value) || value <= 0) throw new Error(`${label} must be positive`); -} - -function positiveNumber(value, label) { - if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) { - throw new Error(`${label} must be a positive finite number`); - } - return value; -} - -function requireEqual(actual, expected, label) { - if (actual !== expected) { - throw new Error( - `${label} must be ${JSON.stringify(expected)}, received ${JSON.stringify(actual)}`, - ); - } -} diff --git a/tools/perf/wasix-browser/plan.test.mjs b/tools/perf/wasix-browser/plan.test.mjs deleted file mode 100644 index b71640deb..000000000 --- a/tools/perf/wasix-browser/plan.test.mjs +++ /dev/null @@ -1,289 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; - -import { - browserMarkdownReport, - browserPlanSummary, - loadBrowserPlan, - qualifyingGitProvenance, - summarizeBrowserResult, - validateBrowserPlan, -} from './plan.mjs'; - -const source = await loadBrowserPlan(); - -test('loads the exact browser plan and comparator pin', () => { - const summary = browserPlanSummary(source); - assert.equal(summary.id, 'browser-pglite-memory-v2'); - assert.match(summary.sha256, /^[0-9a-f]{64}$/u); - assert.equal(summary.engines.candidate.package, '@oliphaunt/wasix-ts'); - assert.deepEqual(summary.engines.candidate.surfaces.direct, { - engine: 'wasixDirect', - entrypoint: '@oliphaunt/wasix-ts', - callingContract: 'async', - executionOwner: 'caller', - }); - assert.deepEqual(summary.engines.candidate.surfaces.worker, { - engine: 'wasixWorker', - entrypoint: '@oliphaunt/wasix-ts/worker', - callingContract: 'async', - executionOwner: 'sdk-worker', - }); - assert.equal(summary.engines.comparison.package, '@electric-sql/pglite'); - assert.equal(summary.engines.comparison.version, '0.5.4'); - assert.equal(summary.profiles.full.workloadRuns, 8); - assert.equal(summary.gate.maxGeomeanRatio, 0.8); -}); - -test('rejects omitted metrics, settings, measurement fields, and execution surfaces', () => { - const cases = [ - { - label: 'gated metric', - mutate(plan) { - plan.gate.metrics.pop(); - }, - expected: /plan\.gate\.metrics must contain exactly/u, - }, - { - label: 'PostgreSQL setting', - mutate(plan) { - delete plan.postgres.settings.fsync; - }, - expected: /plan\.postgres\.settings must contain exactly/u, - }, - { - label: 'measurement rule', - mutate(plan) { - delete plan.measurement.timingBoundary; - }, - expected: /plan\.measurement must contain exactly/u, - }, - { - label: 'candidate surface', - mutate(plan) { - delete plan.engines.candidate.surfaces.direct.entrypoint; - }, - expected: /plan\.engines\.candidate\.surfaces\.direct must contain exactly/u, - }, - { - label: 'comparison surface', - mutate(plan) { - delete plan.engines.comparison.surfaces.worker.executionOwner; - }, - expected: /plan\.engines\.comparison\.surfaces\.worker must contain exactly/u, - }, - ]; - - for (const { label, mutate, expected } of cases) { - const plan = structuredClone(source.plan); - mutate(plan); - assert.throws(() => validateBrowserPlan(plan), expected, label); - } -}); - -test('balances full workload rotation across all four engines', () => { - assert.equal(source.plan.profiles.full.workloadRuns, 8); - assert.equal(source.plan.profiles.full.workloadRuns % 4, 0); - - for (const workloadRuns of [4, 6, 7, 9]) { - const plan = structuredClone(source.plan); - plan.profiles.full.workloadRuns = workloadRuns; - assert.throws( - () => validateBrowserPlan(plan), - /workloadRuns must be a multiple of 4 and at least 8/u, - ); - } - - const strongerPlan = structuredClone(source.plan); - strongerPlan.profiles.full.workloadRuns = 12; - assert.doesNotThrow(() => validateBrowserPlan(strongerPlan)); -}); - -test('requires a clean exact Git commit and tree for benchmark qualification', () => { - const clean = { - commit: 'a'.repeat(40), - tree: 'b'.repeat(40), - status: '', - }; - assert.deepEqual(qualifyingGitProvenance(clean), { - commit: clean.commit, - tree: clean.tree, - dirty: false, - }); - assert.throws( - () => qualifyingGitProvenance({ ...clean, status: ' M benchmark.ts' }), - /requires a clean Git worktree/u, - ); -}); - -test('requires a comfortable aggregate win independently on both execution surfaces', () => { - const result = fixture('full', { directRatio: 0.6, workerRatio: 0.5 }); - const summary = summarizeBrowserResult(source, result); - assert.ok(Math.abs(summary.comparisons.direct.geomeanRatio - 0.6) < 1e-12); - assert.ok(Math.abs(summary.comparisons.worker.geomeanRatio - 0.5) < 1e-12); - assert.equal(summary.correctness.passed, true); - assert.equal(summary.gate.required, true); - assert.equal(summary.gate.passed, true); - assert.equal(summary.passed, true); -}); - -test('requires independent calling-contract and execution-owner fields in v2 results', () => { - const result = fixture('quick', { directRatio: 0.6, workerRatio: 0.5 }); - assert.doesNotThrow(() => summarizeBrowserResult(source, result)); - - const flattened = structuredClone(result); - flattened.configuration.executionSurfaces = ['direct', 'worker']; - assert.throws( - () => summarizeBrowserResult(source, flattened), - /result\.configuration\.executionSurfaces must be an object/u, - ); - - const wrongOwner = structuredClone(result); - wrongOwner.configuration.executionSurfaces.worker.executionOwner = 'caller'; - assert.throws( - () => summarizeBrowserResult(source, wrongOwner), - /result\.configuration\.executionSurfaces\.worker\.executionOwner/u, - ); -}); - -test('does not let one execution surface subsidize a losing surface', () => { - const summary = summarizeBrowserResult( - source, - fixture('full', { directRatio: 0.5, workerRatio: 0.9 }), - ); - assert.equal(summary.comparisons.direct.gate.passed, true); - assert.equal(summary.comparisons.worker.gate.passed, false); - assert.equal(summary.gate.passed, false); - assert.equal(summary.passed, false); -}); - -test('renders reports with the direct and Worker comparison names', () => { - const result = fixture('quick', { directRatio: 0.5, workerRatio: 0.5 }); - result.environment.userAgent = 'benchmark-test'; - const markdown = browserMarkdownReport({ - plan: browserPlanSummary(source), - result, - summary: summarizeBrowserResult(source, result), - }); - - assert.match(markdown, /## Direct comparison/u); - assert.match(markdown, /## Worker comparison/u); -}); - -test('makes quick runs correctness smoke evidence rather than performance qualification', () => { - const summary = summarizeBrowserResult( - source, - fixture('quick', { directRatio: 0.95, workerRatio: 0.95 }), - ); - assert.equal(summary.gate.required, false); - assert.equal(summary.gate.passed, null); - assert.equal(summary.passed, true); -}); - -test('rejects durability drift even when both performance gates win', () => { - const result = fixture('full', { directRatio: 0.5, workerRatio: 0.5 }); - result.postgresProfiles.pgliteWorker.fsync = 'on'; - const summary = summarizeBrowserResult(source, result); - assert.equal(summary.correctness.durability.worker.passed, false); - assert.equal(summary.correctness.passed, false); - assert.equal(summary.gate.passed, false); - assert.equal(summary.passed, false); -}); - -test('rejects WAL-volume drift even when workload results and speed agree', () => { - const result = fixture('full', { directRatio: 0.5, workerRatio: 0.5 }); - result.insertDiagnostic.summary.indexedInsertWalBytes.wasixDirect = 1100; - const summary = summarizeBrowserResult(source, result); - assert.equal(summary.correctness.indexedInsertWal.direct.passed, false); - assert.equal(summary.correctness.passed, false); - assert.equal(summary.gate.passed, false); - assert.equal(summary.passed, false); -}); - -function fixture(mode, { directRatio, workerRatio }) { - const profile = source.plan.profiles[mode]; - const metrics = source.plan.gate.metrics - .filter((id) => id.startsWith('workload.')) - .map((id) => id.slice('workload.'.length)); - const runs = (ratio) => - Array.from({ length: profile.workloadRuns }, () => ({ - metrics: Object.fromEntries([ - ...metrics.map((metric) => [metric, 10 * ratio]), - ['readyMs', 10 * ratio], - ['closeMs', 1_000_000], - ]), - })); - const startup = (ratio) => [ - 10, - ...Array.from({ length: profile.startupRuns - 1 }, () => 10 * ratio), - ]; - const diagnostics = () => - Array.from({ length: profile.insertDiagnosticRuns }, () => ({ indexedInsertWalBytes: 1000 })); - const postgres = () => ({ - version: '18.4', - fsync: 'off', - synchronousCommit: 'on', - fullPageWrites: 'on', - walLevel: 'replica', - }); - return { - schema: 'oliphaunt-wasix-browser-engine-result-v2', - plan: source.plan.id, - mode, - environment: { crossOriginIsolated: true }, - configuration: { - ...profile, - executionSurfaces: { - direct: { - entrypoint: '@oliphaunt/wasix-ts', - callingContract: 'async', - executionOwner: 'caller', - }, - worker: { - entrypoint: '@oliphaunt/wasix-ts/worker', - callingContract: 'async', - executionOwner: 'sdk-worker', - }, - }, - rows: source.plan.measurement.rows, - storage: source.plan.measurement.storage, - }, - correctness: { assertionsPassed: true }, - postgresProfiles: { - wasixDirect: postgres(), - wasixWorker: postgres(), - pgliteDirect: postgres(), - pgliteWorker: postgres(), - }, - samples: { - startup: { - wasixDirect: startup(directRatio), - wasixWorker: startup(workerRatio), - pgliteDirect: startup(1), - pgliteWorker: startup(1), - }, - workload: { - wasixDirect: runs(directRatio), - wasixWorker: runs(workerRatio), - pgliteDirect: runs(1), - pgliteWorker: runs(1), - }, - }, - insertDiagnostic: { - summary: { - indexedInsertWalBytes: { - wasixDirect: 1000, - wasixWorker: 1000, - pgliteDirect: 1000, - pgliteWorker: 1000, - }, - }, - samples: { - wasixDirect: diagnostics(), - wasixWorker: diagnostics(), - pgliteDirect: diagnostics(), - pgliteWorker: diagnostics(), - }, - }, - }; -} diff --git a/tools/perf/wasix-node/benchmark.mjs b/tools/perf/wasix-node/benchmark.mjs deleted file mode 100644 index 7fada9410..000000000 --- a/tools/perf/wasix-node/benchmark.mjs +++ /dev/null @@ -1,756 +0,0 @@ -import { execFile } from 'node:child_process'; -import { lstat, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; -import { createRequire } from 'node:module'; -import { - arch, - cpus, - freemem, - homedir, - hostname, - platform, - release, - tmpdir, - totalmem, -} from 'node:os'; -import { dirname, relative, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { promisify } from 'node:util'; - -import { createPackedWasixConsumer } from '../../integration/wasix-ts/packed-node-fixture.mjs'; -import { installedPackageClosure } from './installed-closure.mjs'; -import { - assertNativeArtifactProvenance, - assertRuntimeBuildConfiguration, - comfortableWinGate, - defaultPlanFile, - findPackageManifest, - loadPlan, - median, - metricIds, - pairedRatioSummary, - planSummary, - postgresSettingsParity, - repositoryRoot, - sha256, -} from './plan.mjs'; - -const execFileAsync = promisify(execFile); -const toolRoot = dirname(fileURLToPath(import.meta.url)); -const engineRunner = resolve(toolRoot, 'engine-runner.mjs'); -const args = parseArguments(process.argv.slice(2)); -const source = await loadPlan(args.config); - -if (args.mode === 'plan') { - console.log(JSON.stringify(planSummary(source.plan, source), null, 2)); -} else if (args.mode === 'validate') { - const installedControl = await comparisonProvenance(source.plan); - console.log( - JSON.stringify( - { - status: 'PASS', - validation: - 'plan, native addon contract, package identity, private comparator pin, and generated SQL', - installedControl, - ...planSummary(source.plan, source), - }, - null, - 2, - ), - ); -} else { - await runMeasuredBenchmark(source, args); -} - -async function runMeasuredBenchmark(planSource, options) { - if (isCiEnvironment()) { - throw new Error('measured WASIX Node benchmarks are local-only and refuse CI environments'); - } - const git = await gitProvenance(); - const output = options.output ?? defaultOutputDirectory(git.commit); - await requireAbsent(output, 'benchmark output directory'); - await mkdir(dirname(output), { recursive: true }); - const scratch = await mkdtemp(resolve(tmpdir(), 'oliphaunt-wasix-node-bench-')); - - try { - const fixture = await createBenchmarkFixture({ - scratch, - consumerName: 'oliphaunt-wasix-node-benchmark-consumer', - }); - const candidateClosure = await candidateClosureProvenance( - fixture.consumer, - planSource.plan, - fixture.packages.runtime, - fixture.packages.nativeCarrier, - git.commit, - ); - const comparison = await comparisonProvenance(planSource.plan); - const sequence = []; - const runs = { - 'candidate-direct': [], - 'candidate-worker': [], - 'comparison-direct': [], - 'comparison-worker': [], - }; - const pids = new Set(); - await mkdir(resolve(scratch, 'runs')); - - for (let repeat = 0; repeat < planSource.plan.measurement.pairedRepeats; repeat += 1) { - const order = - repeat % 2 === 0 - ? ['candidate-worker', 'comparison-worker'] - : ['comparison-worker', 'candidate-worker']; - for (const engine of order) { - const result = await runEngine({ - engine, - repeat, - planSource, - candidateRoot: fixture.consumer, - scratch, - }); - validateEngineReport(result, engine, repeat, planSource); - if (pids.has(result.process.pid) || result.process.pid === process.pid) { - throw new Error(`engine process ${result.process.pid} was not fresh`); - } - pids.add(result.process.pid); - sequence.push({ phase: 'worker', repeat, engine, pid: result.process.pid }); - runs[engine].push(result); - } - } - - for (let repeat = 0; repeat < planSource.plan.measurement.pairedRepeats; repeat += 1) { - const order = - repeat % 2 === 0 - ? ['candidate-direct', 'comparison-direct'] - : ['comparison-direct', 'candidate-direct']; - for (const engine of order) { - const result = await runEngine({ - engine, - repeat, - planSource, - candidateRoot: fixture.consumer, - scratch, - }); - validateEngineReport(result, engine, repeat, planSource); - if (pids.has(result.process.pid) || result.process.pid === process.pid) { - throw new Error(`engine process ${result.process.pid} was not fresh`); - } - pids.add(result.process.pid); - sequence.push({ phase: 'direct', repeat, engine, pid: result.process.pid }); - runs[engine].push(result); - } - } - - const summary = summarizeRuns(planSource.plan, runs); - const report = { - schema: 'oliphaunt-wasix-node-benchmark-report-v2', - createdAt: new Date().toISOString(), - plan: planSummary(planSource.plan, planSource), - provenance: { - git, - machine: machineProvenance(), - tools: await toolProvenance(planSource.file), - candidate: { - packages: stripTemporaryPaths(fixture.packages), - closure: candidateClosure, - }, - comparison, - }, - execution: { - policy: planSource.plan.measurement.processOrder, - sequence, - }, - runs, - summary, - }; - await mkdir(output); - await writeFile(resolve(output, 'report.json'), `${JSON.stringify(report, null, 2)}\n`, { - flag: 'wx', - }); - await writeFile(resolve(output, 'report.md'), markdownReport(report), { flag: 'wx' }); - console.log( - `wasix-node benchmark: ${summary.gate.passed ? 'PASS' : 'FAIL'} ` + - `worker=${summary.comparisons.worker.geomeanRatio.toFixed(4)} ` + - `direct=${summary.comparisons.direct.geomeanRatio.toFixed(4)} ` + - `gate<=${summary.gate.maxGeomeanRatio.toFixed(2)} ` + - `report=${relative(repositoryRoot, output)}`, - ); - if (!summary.gate.passed) process.exitCode = 1; - } finally { - await rm(scratch, { force: true, recursive: true }); - } -} - -async function requireAbsent(path, label) { - try { - await lstat(path); - } catch (error) { - if (error?.code === 'ENOENT') return; - throw error; - } - throw new Error(`${label} already exists: ${path}`); -} - -async function runEngine({ engine, repeat, planSource, candidateRoot, scratch }) { - const output = resolve(scratch, 'runs', `${String(repeat).padStart(2, '0')}-${engine}.json`); - const childArgs = [ - engineRunner, - '--engine', - engine, - '--output', - output, - '--plan', - planSource.file, - '--repeat', - String(repeat), - ]; - if (engine.startsWith('candidate')) childArgs.push('--candidate-root', candidateRoot); - try { - await execFileAsync(process.execPath, childArgs, { - cwd: repositoryRoot, - env: process.env, - maxBuffer: 64 * 1024 * 1024, - timeout: 15 * 60_000, - }); - } catch (error) { - const stderr = typeof error?.stderr === 'string' ? `\n${error.stderr.trim()}` : ''; - throw new Error(`${engine} repeat ${repeat} failed${stderr}`, { cause: error }); - } - return JSON.parse(await readFile(output, 'utf8')); -} - -async function createBenchmarkFixture(options) { - try { - return await createPackedWasixConsumer(options); - } catch (cause) { - throwNativeCarrierPreflight(cause, 'measured WASIX Node benchmark'); - throw cause; - } -} - -function throwNativeCarrierPreflight(cause, consumer) { - const detail = cause instanceof Error ? cause.message : String(cause); - if ( - /native carrier|Node-API carrier|native artifact provenance|oliphaunt_wasix_napi|wasix-napi-/iu.test( - detail, - ) - ) { - throw new Error( - `${consumer} requires one optimized current-host WASIX Node-API carrier. ` + - 'After staging the portable/AOT runtime, ICU, and extension inputs, run ' + - '`bash src/runtimes/wasix-napi/tools/build-native.sh`, then retry. ' + - `Carrier preflight: ${detail}`, - { cause }, - ); - } -} - -function validateEngineReport(report, engine, repeat, planSource) { - if ( - report.schema !== 'oliphaunt-wasix-node-engine-run-v2' || - report.plan?.id !== planSource.plan.id || - report.plan?.sha256 !== planSource.sha256 || - report.engine?.kind !== engine || - report.repeat !== repeat || - report.correctness?.passed !== true - ) { - throw new Error(`${engine} repeat ${repeat} returned an invalid engine report`); - } - const candidate = engine.startsWith('candidate'); - const expectedEngine = candidate - ? planSource.plan.engines.candidate - : planSource.plan.engines.comparison; - const surface = - engine === 'candidate-direct' - ? expectedEngine.surfaces.direct - : engine === 'candidate-worker' - ? expectedEngine.surfaces.worker - : engine === 'comparison-worker' - ? expectedEngine.surfaces.worker - : expectedEngine.surfaces.callerRealm; - if ( - report.engine.package !== expectedEngine.package || - report.engine.storage !== expectedEngine.storage || - report.engine.entrypoint !== surface.entrypoint || - report.engine.callingContract !== surface.callingContract || - report.engine.executionOwner !== surface.executionOwner || - report.engine.executionBoundary !== surface.executionBoundary || - report.engine.isolationImplementation !== surface.isolationImplementation || - report.engine.timingBoundary !== surface.timingBoundary - ) { - throw new Error(`${engine} repeat ${repeat} used an unexpected engine identity`); - } - if (!candidate && report.engine.version !== expectedEngine.version) { - throw new Error(`${engine} repeat ${repeat} used version ${report.engine.version}`); - } -} - -function summarizeRuns(plan, runs) { - const correctness = summarizeCorrectness(runs, plan); - const worker = summarizePlacement( - plan, - runs['candidate-worker'], - 'candidate-worker', - runs['comparison-worker'], - 'comparison-worker', - correctness.passed, - ); - const direct = summarizePlacement( - plan, - runs['candidate-direct'], - 'candidate-direct', - runs['comparison-direct'], - 'comparison-direct', - correctness.passed, - ); - return { - correctness, - comparisons: { direct, worker }, - gate: { - passed: worker.gate.passed && direct.gate.passed, - correctnessPassed: correctness.passed, - maxGeomeanRatio: plan.gate.maxGeomeanRatio, - comparisons: { - worker: worker.gate.passed, - direct: direct.gate.passed, - }, - }, - }; -} - -function summarizePlacement( - plan, - candidateInput, - candidateEngine, - comparisonInput, - comparisonEngine, - correctnessPassed, -) { - const candidateRuns = orderedRuns( - candidateInput, - candidateEngine, - plan.measurement.pairedRepeats, - ); - const comparisonRuns = orderedRuns( - comparisonInput, - comparisonEngine, - plan.measurement.pairedRepeats, - ); - const metrics = metricIds(plan).map((id) => { - const candidateSamples = candidateRuns.map((run) => metricValue(run, id)); - const comparisonSamples = comparisonRuns.map((run) => metricValue(run, id)); - const candidateMedianMs = median(candidateSamples); - const comparisonMedianMs = median(comparisonSamples); - const paired = pairedRatioSummary(candidateSamples, comparisonSamples); - return { - id, - candidateSamplesMs: candidateSamples, - comparisonSamplesMs: comparisonSamples, - candidateMedianMs, - comparisonMedianMs, - pairs: paired.pairedRatios.map((ratio, repeat) => ({ - repeat, - candidateMs: candidateSamples[repeat], - comparisonMs: comparisonSamples[repeat], - ratio, - })), - pairedRatioMedian: paired.medianRatio, - }; - }); - const { geomeanRatio, gate } = comfortableWinGate( - metrics.map((metric) => metric.pairedRatioMedian), - plan.gate.maxGeomeanRatio, - correctnessPassed, - ); - return { - metrics, - startupComponents: summarizeStartupComponents(candidateRuns, comparisonRuns), - geomeanRatio, - gate, - }; -} - -function orderedRuns(runs, engine, expectedCount) { - if (!Array.isArray(runs) || runs.length !== expectedCount) { - throw new Error(`${engine} must provide exactly ${expectedCount} paired repeats`); - } - const byRepeat = new Map(); - for (const run of runs) { - if ( - !Number.isSafeInteger(run.repeat) || - run.repeat < 0 || - run.repeat >= expectedCount || - byRepeat.has(run.repeat) - ) { - throw new Error(`${engine} returned duplicate or invalid paired repeat ${run.repeat}`); - } - byRepeat.set(run.repeat, run); - } - return Array.from({ length: expectedCount }, (_, repeat) => { - const run = byRepeat.get(repeat); - if (run === undefined) throw new Error(`${engine} omitted paired repeat ${repeat}`); - return run; - }); -} - -function summarizeStartupComponents(candidateRuns, comparisonRuns) { - return { - separatelyGated: false, - components: startupComponentIds().map((id) => { - const candidateSamplesMs = candidateRuns.map((run) => startupComponentValue(run, id)); - const comparisonSamplesMs = comparisonRuns.map((run) => startupComponentValue(run, id)); - return { - id, - candidateSamplesMs, - comparisonSamplesMs, - candidateMedianMs: median(candidateSamplesMs), - comparisonMedianMs: median(comparisonSamplesMs), - }; - }), - }; -} - -function summarizeCorrectness(runs, plan) { - const all = Object.values(runs).flat(); - const expected = new Set(all.map((run) => run.correctness.expectedSha256)); - const responses = new Set(all.map((run) => run.correctness.responseSha256)); - const postgresSettings = postgresSettingsParity( - all, - plan.postgres.settings, - plan.postgres.expectedSettings, - ); - return { - passed: - all.length > 0 && - all.every((run) => run.correctness.passed) && - expected.size === 1 && - responses.size === 1 && - [...expected][0] === [...responses][0] && - postgresSettings.passed, - expectedSha256: expected.size === 1 ? [...expected][0] : null, - responseSha256: responses.size === 1 ? [...responses][0] : null, - postgresSettings, - }; -} - -function metricValue(run, id) { - if (id === 'cold-to-first-result') { - const openMs = startupComponentValue(run, 'public-open'); - const firstQueryMs = startupComponentValue(run, 'immediate-first-query'); - const composite = positiveTiming(run.timings.coldToFirstResultMs, id); - if (Math.abs(composite - (openMs + firstQueryMs)) > Number.EPSILON * composite * 4) { - throw new Error(`${id} must equal its reported startup components`); - } - return composite; - } - if (id.startsWith('warm-rtt/') && id.endsWith('/p50')) { - const benchmarkId = id.slice('warm-rtt/'.length, -'/p50'.length); - const row = run.timings.warmRtt.find((entry) => entry.id === benchmarkId); - return positiveTiming(row?.latency?.p50Ms, id); - } - if (id.startsWith('bulk/') && id.endsWith('/elapsed')) { - const benchmarkId = id.slice('bulk/'.length, -'/elapsed'.length); - const row = run.timings.bulk.find((entry) => entry.id === benchmarkId); - return positiveTiming(row?.elapsedMs, id); - } - throw new Error(`unsupported metric ${id}`); -} - -function startupComponentIds() { - return ['public-open', 'immediate-first-query']; -} - -function startupComponentValue(run, id) { - if (id === 'public-open') return positiveTiming(run.timings.openMs, id); - if (id === 'immediate-first-query') { - return positiveTiming(run.timings.firstQueryMs, id); - } - throw new Error(`unsupported startup component ${id}`); -} - -function positiveTiming(value, label) { - if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) { - throw new Error(`${label} must be a positive finite timing`); - } - return value; -} - -async function comparisonProvenance(plan) { - const require = createRequire(import.meta.url); - const { manifest } = await findPackageManifest( - require.resolve(plan.engines.comparison.package), - plan.engines.comparison.package, - ); - if (manifest.version !== plan.engines.comparison.version) { - throw new Error( - `installed ${manifest.name}@${manifest.version}, expected ${plan.engines.comparison.version}`, - ); - } - const lock = await readFile(resolve(repositoryRoot, 'pnpm-lock.yaml'), 'utf8'); - if (!lock.includes(plan.engines.comparison.integrity)) { - throw new Error('pnpm-lock.yaml does not contain the comparator integrity from the plan'); - } - const closure = await installedPackageClosure( - require.resolve(plan.engines.comparison.package), - plan.engines.comparison.package, - ); - const root = closure.packages.find((candidate) => candidate.id === closure.root); - if ( - closure.treeHashSchema !== plan.engines.comparison.installedTreeHashSchema || - root?.installedTreeSha256 !== plan.engines.comparison.installedTreeSha256 - ) { - throw new Error( - `installed ${manifest.name}@${manifest.version} tree is ${root?.installedTreeSha256 ?? 'missing'}, ` + - `expected ${plan.engines.comparison.installedTreeSha256}`, - ); - } - return { - package: manifest.name, - version: manifest.version, - homepage: plan.engines.comparison.homepage, - integrity: plan.engines.comparison.integrity, - sourceRepository: plan.engines.comparison.sourceRepository, - sourceCommit: plan.engines.comparison.sourceCommit, - installedClosure: closure, - }; -} - -async function candidateClosureProvenance( - consumer, - plan, - runtimePackage, - nativeCarrier, - artifactSourceSha, -) { - const require = createRequire(resolve(consumer, 'package.json')); - const { manifest } = await findPackageManifest( - require.resolve(plan.engines.candidate.package), - plan.engines.candidate.package, - ); - const nativeAddon = assertNativeArtifactProvenance( - nativeCarrier, - plan.engines.candidate.nativeAddon, - artifactSourceSha, - ); - for (const field of [ - 'dependencies', - 'devDependencies', - 'optionalDependencies', - 'peerDependencies', - ]) { - if (manifest[field]?.[plan.engines.comparison.package] !== undefined) { - throw new Error(`packed candidate ${field} includes benchmark-only PGlite`); - } - } - const installedClosure = await installedPackageClosure( - require.resolve(plan.engines.candidate.package), - plan.engines.candidate.package, - ); - const expectedPackages = [ - '@oliphaunt/liboliphaunt-wasix', - '@oliphaunt/wasix-ts', - nativeCarrier.name, - 'fzstd', - ].sort(); - const installedPackages = installedClosure.packages.map((candidate) => candidate.name).sort(); - if (JSON.stringify(installedPackages) !== JSON.stringify(expectedPackages)) { - throw new Error( - `packed candidate installed closure is ${JSON.stringify(installedPackages)}, expected ${JSON.stringify(expectedPackages)}`, - ); - } - if (manifest.dependencies?.fzstd !== '0.1.1') { - throw new Error(`packed candidate fzstd dependency is ${manifest.dependencies?.fzstd}`); - } - const build = runtimePackage?.build; - if ( - build?.schema !== 'oliphaunt-wasix-build-provenance-v1' || - build.configuration === undefined || - typeof build.buildProfile?.sha256 !== 'string' || - typeof build.outputs?.sha256 !== 'string' - ) { - throw new Error('packed candidate runtime build provenance is incomplete'); - } - try { - assertRuntimeBuildConfiguration( - build.configuration, - plan.engines.candidate.runtimeBuild, - 'packed candidate runtime build', - ); - } catch (error) { - throw new Error( - `packed candidate runtime build is ${JSON.stringify(build.configuration)}, ` + - `expected ${JSON.stringify(plan.engines.candidate.runtimeBuild)}`, - { cause: error }, - ); - } - return { - package: manifest.name, - version: manifest.version, - dependencies: manifest.dependencies ?? {}, - nativeAddon, - runtimeBuild: build, - installedClosure, - }; -} - -async function toolProvenance(planFile) { - const files = [ - resolve(toolRoot, 'benchmark.mjs'), - engineRunner, - resolve(toolRoot, 'installed-closure.mjs'), - resolve(toolRoot, 'plan.mjs'), - resolve(toolRoot, 'pglite-node-worker.mjs'), - resolve(repositoryRoot, 'tools/integration/wasix-ts/packed-node-fixture.mjs'), - resolve(repositoryRoot, 'tools/release/wasix-typescript-package.mjs'), - planFile, - ]; - const records = []; - for (const file of files) { - const bytes = await readFile(file); - records.push({ - path: relative(repositoryRoot, file).split('\\').join('/'), - sha256: sha256(bytes), - size: bytes.length, - }); - } - return records; -} - -async function gitProvenance() { - const [{ stdout: commit }, { stdout: status }] = await Promise.all([ - execFileAsync('git', ['rev-parse', 'HEAD'], { cwd: repositoryRoot }), - execFileAsync('git', ['status', '--porcelain=v1', '--untracked-files=all'], { - cwd: repositoryRoot, - maxBuffer: 16 * 1024 * 1024, - }), - ]); - const porcelain = status.trimEnd(); - return { - commit: commit.trim(), - dirty: porcelain.length > 0, - statusSha256: sha256(porcelain), - }; -} - -function machineProvenance() { - const processors = cpus(); - return { - hostname: hostname(), - platform: platform(), - release: release(), - arch: arch(), - node: process.version, - v8: process.versions.v8, - cpuModel: processors[0]?.model ?? 'unknown', - logicalCpus: processors.length, - totalMemoryBytes: totalmem(), - freeMemoryBytesAtStart: freemem(), - }; -} - -function stripTemporaryPaths(packages) { - return Object.fromEntries( - Object.entries(packages).map(([kind, descriptor]) => { - const { file: _, ...portable } = descriptor; - return [kind, portable]; - }), - ); -} - -function markdownReport(report) { - const comparisonSections = Object.entries(report.summary.comparisons) - .map(([comparison, summary]) => comparisonMarkdown(comparison, summary)) - .join('\n\n'); - return `# WASIX Node benchmark report - -- Plan: \`${report.plan.id}\` -- Candidate: \`${report.plan.engines.candidate.package}\` (blocking \`/direct\` API and explicit package-owned \`/worker\` entrypoint) -- Candidate runtime build: \`${report.provenance.candidate.packages.runtime.build.configuration.profile}\` with \`${report.provenance.candidate.packages.runtime.build.configuration.cflags}\` (signature \`${report.provenance.candidate.packages.runtime.build.buildProfile.sha256}\`) -- Candidate native host: \`${report.provenance.candidate.closure.nativeAddon.carrier}\` target \`${report.provenance.candidate.closure.nativeAddon.target}\`, addon ABI \`${report.plan.engines.candidate.nativeAddon.addonAbiVersion}\`, Node-API \`${report.plan.engines.candidate.nativeAddon.nodeApiVersion}\`, Cargo \`${report.provenance.candidate.closure.nativeAddon.artifactProvenance.build.cargoProfile}\`, thin LTO, one codegen unit, binary \`${report.provenance.candidate.closure.nativeAddon.artifactProvenance.binary.sha256}\` (artifact source \`${report.provenance.candidate.closure.nativeAddon.artifactProvenance.artifactSourceSha}\`) -- Comparison: \`${report.plan.engines.comparison.package}@${report.plan.engines.comparison.version}\` (harness-owned Worker and caller-realm API) -- Correctness: **${report.summary.correctness.passed ? 'PASS' : 'FAIL'}** -- PostgreSQL settings parity: **${report.summary.correctness.postgresSettings.passed ? 'PASS' : 'FAIL'}** -- Comfortable-win gate: **${report.summary.gate.passed ? 'PASS' : 'FAIL'}** (worker ${report.summary.comparisons.worker.geomeanRatio.toFixed(4)}, direct comparison ${report.summary.comparisons.direct.geomeanRatio.toFixed(4)}, each required <= ${report.summary.gate.maxGeomeanRatio.toFixed(2)}) - -${comparisonSections} - -Each comparison ran in ${report.plan.measurement.pairedRepeats} same-repeat pairs against fresh in-memory databases. Launch order alternated evenly within each comparison, and each paired candidate/PGlite ratio was computed before taking the per-metric median. Worker calls are timed end-to-end around one public RPC. The direct comparison times both Promise-shaped caller-realm APIs; Oliphaunt performs guest work in the calling realm while the promise is pending. The cold-to-first-result metric combines public open and the immediate first user query so moving lazy work between those phases cannot change its weight. - -Bulk operations use each package's public \`execProtocolRaw\` with identical PostgreSQL Simple Query bytes. Outside the timed call, the harness decodes that exact response and requires its command tags and result rows before validating database state. Both placement gates are eligible only after canonical response streams and all recorded PostgreSQL settings agree. - -PGlite's official worker wrapper targets browser Worker and Web Locks APIs, so the worker control uses the small harness-owned \`worker_threads\` RPC adapter recorded in provenance. PGlite's official browser benchmark places its timer inside that browser worker; this Node harness records the methodology as reference only and does not collect or serialize comparator-only timing telemetry during calls. -`; -} - -function comparisonMarkdown(comparison, summary) { - const title = comparison === 'worker' ? 'Worker comparison' : 'Direct comparison'; - const rows = summary.metrics - .map( - (metric) => - `| \`${metric.id}\` | ${metric.candidateMedianMs.toFixed(3)} | ` + - `${metric.comparisonMedianMs.toFixed(3)} | ${metric.pairedRatioMedian.toFixed(3)} |`, - ) - .join('\n'); - const startupRows = summary.startupComponents.components - .map( - (component) => - `| \`${component.id}\` | ${component.candidateMedianMs.toFixed(3)} | ` + - `${component.comparisonMedianMs.toFixed(3)} |`, - ) - .join('\n'); - return `## ${title} - -- Gate: **${summary.gate.passed ? 'PASS' : 'FAIL'}** (geomean ${summary.geomeanRatio.toFixed(4)}) - -| Metric (lower is better) | Oliphaunt median ms | PGlite median ms | Median paired ratio | -| --- | ---: | ---: | ---: | -${rows} - -| Startup component (not separately gated) | Oliphaunt median ms | PGlite median ms | -| --- | ---: | ---: | -${startupRows}`; -} - -function defaultOutputDirectory(commit) { - const timestamp = new Date() - .toISOString() - .replaceAll(':', '') - .replaceAll('-', '') - .replace(/\.\d{3}Z$/u, 'Z'); - return resolve(repositoryRoot, 'target/perf', `wasix-node-${timestamp}-${commit.slice(0, 12)}`); -} - -function isCiEnvironment() { - return ['BUILDKITE', 'CI', 'CIRCLECI', 'GITHUB_ACTIONS', 'JENKINS_URL', 'TF_BUILD'].some( - (name) => { - const value = process.env[name]; - return value !== undefined && !['', '0', 'false'].includes(value.toLowerCase()); - }, - ); -} - -function parseArguments(argv) { - let mode; - let config = defaultPlanFile; - let output; - for (let index = 0; index < argv.length; index += 1) { - const flag = argv[index]; - if (['--plan', '--run', '--validate'].includes(flag)) { - if (mode !== undefined) throw new Error('choose exactly one of --plan, --validate, or --run'); - mode = flag.slice(2); - } else if (flag === '--config' || flag === '--output') { - const value = argv[index + 1]; - if (value === undefined) throw new Error(`${flag} requires a value`); - if (flag === '--config') config = resolve(value); - else output = resolve(value); - index += 1; - } else { - throw new Error(`unknown benchmark option ${JSON.stringify(flag)}`); - } - } - mode ??= 'plan'; - if (mode !== 'run' && output !== undefined) throw new Error('--output is only valid with --run'); - if (output === homedir() || output === repositoryRoot) { - throw new Error('--output must not be a home or repository root'); - } - return { mode, config, output }; -} diff --git a/tools/perf/wasix-node/engine-runner.mjs b/tools/perf/wasix-node/engine-runner.mjs deleted file mode 100644 index 3844d75f1..000000000 --- a/tools/perf/wasix-node/engine-runner.mjs +++ /dev/null @@ -1,477 +0,0 @@ -import { createHash } from 'node:crypto'; -import { writeFile } from 'node:fs/promises'; -import { createRequire } from 'node:module'; -import { dirname, relative, resolve } from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; -import { Worker } from 'node:worker_threads'; - -import { - assertExpectedRawProtocolResponse, - assertExpectedResult, - bulkSql, - canonicalResult, - expandExpectedResult, - expectedBulkProtocol, - findPackageManifest, - latencySummary, - loadPlan, - sha256, - simpleQueryMessage, - stableJson, -} from './plan.mjs'; - -const args = parseArguments(process.argv.slice(2)); -const source = await loadPlan(args.plan); -const expectedStream = createHash('sha256'); -const responseStream = createHash('sha256'); -let database; - -try { - const opened = await timed(() => openEngine(args.engine, source.plan, args.candidateRoot)); - database = opened.value; - const first = await database.measureQuery(source.plan.firstQuery.sql, []); - const firstExpectedSha256 = recordResult( - first.result, - source.plan.firstQuery.expectedResult, - 'first query', - ); - const postgres = await postgresMetadata(database, source.plan); - - await database.execute(source.plan.warmSetupSql); - const warmRtt = []; - for (const benchmark of source.plan.warmRtt) { - const expectedHash = createHash('sha256'); - const responseHash = createHash('sha256'); - const samples = []; - const total = - source.plan.measurement.warmupIterations + source.plan.measurement.sampleIterations; - for (let iteration = 0; iteration < total; iteration += 1) { - const measured = await database.measureQuery(benchmark.sql, benchmark.parameters); - const expected = expectedWarmResult(benchmark, iteration); - assertExpectedResult( - measured.result, - expected, - `warm RTT ${benchmark.id} iteration ${iteration}`, - ); - recordStream(expectedHash, expected); - recordStream(responseHash, measured.result); - recordStream(expectedStream, expected); - recordStream(responseStream, measured.result); - if (iteration >= source.plan.measurement.warmupIterations) { - samples.push(measured.elapsedMs); - } - } - warmRtt.push({ - id: benchmark.id, - latency: latencySummary(samples, source.plan.measurement.trimFraction), - correctness: { - expectedSha256: expectedHash.digest('hex'), - responseSha256: responseHash.digest('hex'), - }, - }); - } - - const warmValidationExpected = expandExpectedResult(source.plan.warmValidation.expectedResult, { - $totalIterations: - source.plan.measurement.warmupIterations + source.plan.measurement.sampleIterations, - }); - const warmValidation = await database.query(source.plan.warmValidation.sql, []); - const warmValidationSha256 = recordResult( - warmValidation, - warmValidationExpected, - 'warm fixture validation', - ); - - const bulk = []; - for (const benchmark of source.plan.bulk) { - const sql = bulkSql(benchmark); - const measured = await database.measureRawProtocol(simpleQueryMessage(sql)); - const expectedProtocol = expectedBulkProtocol(benchmark); - const protocolOutcome = assertExpectedRawProtocolResponse( - measured.response, - expectedProtocol, - `bulk ${benchmark.id}`, - ); - recordStream(expectedStream, expectedProtocol); - recordStream(responseStream, protocolOutcome); - const result = await database.query(benchmark.validationSql ?? sql, []); - const expectedSha256 = recordResult(result, benchmark.expectedResult, `bulk ${benchmark.id}`); - bulk.push({ - id: benchmark.id, - elapsedMs: measured.elapsedMs, - correctness: { - expectedSha256, - protocolExpectedSha256: sha256(stableJson(expectedProtocol)), - protocolOutcomeSha256: sha256(stableJson(protocolOutcome)), - protocolResponseSha256: sha256(measured.response), - responseSha256: sha256(stableJson(result)), - }, - }); - } - - const expectedSha256 = expectedStream.digest('hex'); - const responseSha256 = responseStream.digest('hex'); - const correctness = { - passed: expectedSha256 === responseSha256, - expectedSha256, - responseSha256, - firstQuerySha256: firstExpectedSha256, - warmValidationSha256, - }; - if (!correctness.passed) throw new Error('correctness result-stream hashes differ'); - - const report = { - schema: 'oliphaunt-wasix-node-engine-run-v2', - plan: { id: source.plan.id, sha256: source.sha256 }, - engine: database.identity, - repeat: args.repeat, - process: { pid: process.pid, node: process.version }, - postgres, - timings: { - openMs: opened.elapsedMs, - firstQueryMs: first.elapsedMs, - coldToFirstResultMs: opened.elapsedMs + first.elapsedMs, - warmRtt, - bulk, - }, - correctness, - }; - await writeFile(args.output, `${JSON.stringify(report, null, 2)}\n`, { flag: 'wx' }); - console.log(`wasix-node engine run: PASS ${args.engine} repeat ${args.repeat}`); -} finally { - await database?.close(); -} - -async function openEngine(engine, plan, candidateRoot) { - if (engine === 'candidate-direct') return openCandidate(plan, candidateRoot, 'direct'); - if (engine === 'candidate-worker') return openCandidate(plan, candidateRoot, 'worker'); - if (engine === 'comparison-direct') return openComparisonCallerRealm(plan); - if (engine === 'comparison-worker') return openComparisonWorker(plan); - throw new Error(`unsupported benchmark engine ${JSON.stringify(engine)}`); -} - -async function openCandidate(plan, candidateRoot, surfaceName) { - if (candidateRoot === undefined) - throw new Error('--candidate-root is required for candidate runs'); - const require = createRequire(resolve(candidateRoot, 'package.json')); - const surface = plan.engines.candidate.surfaces[surfaceName]; - const entry = require.resolve(surface.entrypoint); - const { manifest } = await findPackageManifest(entry, plan.engines.candidate.package); - const expectedFile = surfaceName === 'worker' ? 'worker-entry.node.js' : 'direct.node.js'; - if (!entry.split('\\').join('/').endsWith(`/lib/${expectedFile}`)) { - throw new Error( - `${surface.entrypoint} resolved ${entry}, expected the conditional Node entrypoint lib/${expectedFile}`, - ); - } - const module = await import(pathToFileURL(entry).href); - const client = module.default; - if (typeof client?.open !== 'function') { - throw new Error(`${plan.engines.candidate.package} has no default open() client`); - } - if (typeof module.memory !== 'function') { - throw new Error(`${plan.engines.candidate.package} has no explicit memory storage selector`); - } - const instance = await client.open({ - storage: module.memory(), - }); - return { - identity: { - kind: surface.engine, - package: manifest.name, - version: manifest.version, - resolvedEntry: relative(candidateRoot, entry).split('\\').join('/'), - entrypoint: surface.entrypoint, - callingContract: surface.callingContract, - executionOwner: surface.executionOwner, - executionBoundary: surface.executionBoundary, - isolationImplementation: surface.isolationImplementation, - timingBoundary: surface.timingBoundary, - storage: plan.engines.candidate.storage, - }, - query: async (sql, parameters) => - canonicalCandidate( - await instance.query(sql, parameters, { rowMode: 'array', valueMode: 'text' }), - ), - execute: (sql) => instance.execute(sql), - measureQuery: async (sql, parameters) => { - const measured = await timed(() => - instance.query(sql, parameters, { rowMode: 'array', valueMode: 'text' }), - ); - return { result: canonicalCandidate(measured.value), elapsedMs: measured.elapsedMs }; - }, - measureRawProtocol: async (input) => { - const measured = await timed(() => instance.execProtocolRaw(input)); - return { response: measured.value, elapsedMs: measured.elapsedMs }; - }, - close: () => instance.close(), - }; -} - -async function openComparisonWorker(plan) { - const surface = plan.engines.comparison.surfaces.worker; - const resolved = await comparisonPackage(plan); - const rpc = benchmarkWorkerRpc( - new Worker(new URL('./pglite-node-worker.mjs', import.meta.url), { - name: 'oliphaunt-pglite-benchmark', - }), - ); - await rpc.ready; - return { - identity: { - kind: surface.engine, - package: resolved.manifest.name, - version: resolved.manifest.version, - resolvedEntry: resolved.entry, - entrypoint: surface.entrypoint, - callingContract: surface.callingContract, - executionOwner: surface.executionOwner, - executionBoundary: surface.executionBoundary, - isolationImplementation: surface.isolationImplementation, - isolationAdapter: 'tools/perf/wasix-node/pglite-node-worker.mjs', - timingBoundary: surface.timingBoundary, - storage: plan.engines.comparison.storage, - }, - query: async (sql, parameters) => - canonicalComparison((await rpc.request('query', [sql, parameters])).result), - execute: async (sql) => { - await rpc.request('execute', [sql]); - }, - measureQuery: async (sql, parameters) => { - const measured = await timed(() => rpc.request('query', [sql, parameters])); - return { - result: canonicalComparison(measured.value.result), - elapsedMs: measured.elapsedMs, - }; - }, - measureRawProtocol: async (input) => { - const measured = await timed(() => - rpc.request('rawProtocol', [input, plan.bulkTransport.pgliteSyncToFs], [input.buffer]), - ); - return { - response: measured.value.response, - elapsedMs: measured.elapsedMs, - }; - }, - close: () => rpc.close(), - }; -} - -async function openComparisonCallerRealm(plan) { - const surface = plan.engines.comparison.surfaces.callerRealm; - const resolved = await comparisonPackage(plan); - const { PGlite } = await import(plan.engines.comparison.package); - const instance = await PGlite.create('memory://'); - return { - identity: { - kind: surface.engine, - package: resolved.manifest.name, - version: resolved.manifest.version, - resolvedEntry: resolved.entry, - entrypoint: surface.entrypoint, - callingContract: surface.callingContract, - executionOwner: surface.executionOwner, - executionBoundary: surface.executionBoundary, - isolationImplementation: surface.isolationImplementation, - timingBoundary: surface.timingBoundary, - storage: plan.engines.comparison.storage, - }, - query: async (sql, parameters) => canonicalComparison(await instance.query(sql, parameters)), - execute: (sql) => instance.exec(sql), - measureQuery: async (sql, parameters) => { - const measured = await timed(() => instance.query(sql, parameters)); - return { result: canonicalComparison(measured.value), elapsedMs: measured.elapsedMs }; - }, - measureRawProtocol: async (input) => { - const measured = await timed(() => - instance.execProtocolRaw(input, { syncToFs: plan.bulkTransport.pgliteSyncToFs }), - ); - return { response: measured.value, elapsedMs: measured.elapsedMs }; - }, - close: () => instance.close(), - }; -} - -async function comparisonPackage(plan) { - const require = createRequire(import.meta.url); - const requireEntry = require.resolve(plan.engines.comparison.package); - const { file: manifestFile, manifest } = await findPackageManifest( - requireEntry, - plan.engines.comparison.package, - ); - if (manifest.version !== plan.engines.comparison.version) { - throw new Error( - `${plan.engines.comparison.package} resolved ${manifest.version}, expected ${plan.engines.comparison.version}`, - ); - } - const resolvedEntry = fileURLToPath(import.meta.resolve(plan.engines.comparison.package)); - return { - manifest, - entry: relative(dirname(manifestFile), resolvedEntry).split('\\').join('/'), - }; -} - -function benchmarkWorkerRpc(worker) { - let closing = false; - let nextId = 1; - let terminalError; - let resolveReady; - let rejectReady; - const pending = new Map(); - const ready = new Promise((resolvePromise, rejectPromise) => { - resolveReady = resolvePromise; - rejectReady = rejectPromise; - }); - worker.on('message', (message) => { - if (message?.type === 'ready') { - resolveReady(); - return; - } - if (message?.type !== 'response') return; - const request = pending.get(message.id); - if (request === undefined) return; - pending.delete(message.id); - if (message.error === undefined) { - request.resolve(message.result); - } else { - const error = new Error(message.error.message); - error.name = message.error.name; - error.stack = message.error.stack; - request.reject(error); - } - }); - worker.on('error', fail); - worker.on('exit', (code) => { - if (!closing) fail(new Error(`PGlite benchmark worker exited with code ${code}`)); - }); - - function fail(error) { - terminalError ??= error; - rejectReady(error); - for (const request of pending.values()) request.reject(error); - pending.clear(); - } - - function request(method, args, transfer = []) { - if (terminalError !== undefined) return Promise.reject(terminalError); - if (closing) return Promise.reject(new Error('PGlite benchmark worker is closing')); - const id = nextId; - nextId += 1; - return new Promise((resolvePromise, rejectPromise) => { - pending.set(id, { resolve: resolvePromise, reject: rejectPromise }); - worker.postMessage({ id, method, args }, transfer); - }); - } - - return { - ready, - request, - async close() { - const closed = request('close', []); - closing = true; - try { - await closed; - } finally { - await worker.terminate(); - } - }, - }; -} - -function canonicalCandidate(result) { - return canonicalResult( - result.fields.map((field) => field.name), - result.rows.map((row) => [...row]), - ); -} - -function canonicalComparison(result) { - const fields = result.fields.map((field) => field.name); - return canonicalResult( - fields, - result.rows.map((row) => - Array.isArray(row) ? row : fields.map((field) => row[field] ?? null), - ), - ); -} - -async function postgresMetadata(database, plan) { - const settingColumns = plan.postgres.settings - .map((setting) => `current_setting('${setting}')::text AS ${setting}`) - .join(', '); - const result = await database.query(`SELECT version()::text AS version, ${settingColumns}`, []); - const version = result.rows[0]?.[0]; - if (typeof version !== 'string' || !version.startsWith(`PostgreSQL ${plan.postgres.major}.`)) { - throw new Error( - `engine reported ${JSON.stringify(version)}, expected PostgreSQL ${plan.postgres.major}`, - ); - } - return { - version, - settings: Object.fromEntries( - plan.postgres.settings.map((setting, index) => [setting, result.rows[0][index + 1]]), - ), - }; -} - -function expectedWarmResult(benchmark, iteration) { - if (benchmark.expectation.kind === 'exact') return benchmark.expectation.result; - return { - fields: [benchmark.expectation.field], - rows: [[String(iteration + 1)]], - }; -} - -function recordResult(actual, expected, label) { - const expectedSha256 = assertExpectedResult(actual, expected, label); - recordStream(expectedStream, expected); - recordStream(responseStream, actual); - return expectedSha256; -} - -function recordStream(hash, result) { - hash.update(stableJson(result)); - hash.update('\n'); -} - -async function timed(operation) { - const started = process.hrtime.bigint(); - const value = await operation(); - const ended = process.hrtime.bigint(); - return { value, elapsedMs: Number(ended - started) / 1_000_000 }; -} - -function parseArguments(argv) { - const values = {}; - for (let index = 0; index < argv.length; index += 2) { - const flag = argv[index]; - const value = argv[index + 1]; - if (!['--candidate-root', '--engine', '--output', '--plan', '--repeat'].includes(flag)) { - throw new Error(`unknown engine runner option ${JSON.stringify(flag)}`); - } - if (value === undefined) throw new Error(`${flag} requires a value`); - if (values[flag] !== undefined) throw new Error(`${flag} may only be provided once`); - values[flag] = value; - } - if ( - !['candidate-direct', 'candidate-worker', 'comparison-direct', 'comparison-worker'].includes( - values['--engine'], - ) - ) { - throw new Error( - '--engine must be candidate-direct, candidate-worker, comparison-direct, or comparison-worker', - ); - } - const repeat = Number(values['--repeat']); - if (!Number.isSafeInteger(repeat) || repeat < 0) { - throw new Error('--repeat must be a non-negative integer'); - } - if (values['--output'] === undefined) throw new Error('--output is required'); - return { - engine: values['--engine'], - output: resolve(values['--output']), - plan: values['--plan'] === undefined ? undefined : resolve(values['--plan']), - repeat, - candidateRoot: - values['--candidate-root'] === undefined ? undefined : resolve(values['--candidate-root']), - }; -} diff --git a/tools/perf/wasix-node/installed-closure.mjs b/tools/perf/wasix-node/installed-closure.mjs deleted file mode 100644 index 33417a782..000000000 --- a/tools/perf/wasix-node/installed-closure.mjs +++ /dev/null @@ -1,148 +0,0 @@ -import { createHash } from 'node:crypto'; -import { lstat, readdir, readFile, readlink, realpath } from 'node:fs/promises'; -import { createRequire } from 'node:module'; -import { resolve } from 'node:path'; - -import { findPackageManifest, sha256, stableJson } from './plan.mjs'; - -const DEPENDENCY_FIELDS = [ - ['dependencies', true], - ['optionalDependencies', false], - ['peerDependencies', false], -]; - -export async function installedPackageClosure(entry, expectedName) { - const rootPackage = await installedPackage(entry, expectedName); - const pending = [rootPackage]; - const packagesByDirectory = new Map(); - - while (pending.length > 0) { - const current = pending.shift(); - if (packagesByDirectory.has(current.directory)) continue; - packagesByDirectory.set(current.directory, current); - const dependencies = declaredDependencies(current.manifest); - const require = createRequire(current.manifestFile); - for (const dependency of dependencies) { - let dependencyEntry; - try { - dependencyEntry = require.resolve(dependency.name); - } catch (error) { - if (!dependency.required && error?.code === 'MODULE_NOT_FOUND') { - dependency.installed = false; - continue; - } - throw new Error( - `${current.manifest.name}@${current.manifest.version} cannot resolve installed dependency ${dependency.name}`, - { cause: error }, - ); - } - const installed = await installedPackage(dependencyEntry, dependency.name); - dependency.installed = true; - dependency.targetDirectory = installed.directory; - pending.push(installed); - } - current.dependencies = dependencies; - } - - for (const current of packagesByDirectory.values()) { - current.treeSha256 = await directoryTreeSha256(current.directory); - current.id = packageId(current.manifest, current.treeSha256); - } - const packages = [...packagesByDirectory.values()] - .map((current) => ({ - id: current.id, - name: current.manifest.name, - version: current.manifest.version, - installedTreeSha256: current.treeSha256, - dependencies: current.dependencies.map((dependency) => ({ - name: dependency.name, - specifier: dependency.specifier, - kinds: dependency.kinds, - installed: dependency.installed, - target: - dependency.targetDirectory === undefined - ? null - : packagesByDirectory.get(dependency.targetDirectory).id, - })), - })) - .sort((left, right) => left.id.localeCompare(right.id)); - const root = packages.find((candidate) => candidate.id === rootPackage.id); - if (root === undefined) throw new Error(`installed closure lost root package ${expectedName}`); - return { - schema: 'oliphaunt-installed-node-package-closure-v1', - treeHashSchema: 'oliphaunt-path-size-content-sha256-v1', - root: root.id, - sha256: sha256(stableJson(packages)), - packages, - }; -} - -export async function directoryTreeSha256(root) { - const hash = createHash('sha256'); - await visit(await realpath(root), ''); - return hash.digest('hex'); - - async function visit(directory, prefix) { - const names = (await readdir(directory)).sort(); - for (const name of names) { - const absolute = resolve(directory, name); - const child = prefix === '' ? name : `${prefix}/${name}`; - const stats = await lstat(absolute); - if (stats.isDirectory()) { - hash.update(`d ${child}\n`); - await visit(absolute, child); - } else if (stats.isSymbolicLink()) { - hash.update(`l ${child} ${await readlink(absolute)}\n`); - } else if (stats.isFile()) { - hash.update(`f ${child} ${stats.size}\n`); - hash.update(await readFile(absolute)); - hash.update('\n'); - } else { - throw new Error(`unsupported installed package member ${absolute}`); - } - } - } -} - -async function installedPackage(entry, expectedName) { - const { file: manifestFile, manifest } = await findPackageManifest(entry, expectedName); - if ( - typeof manifest.name !== 'string' || - typeof manifest.version !== 'string' || - manifest.name !== expectedName - ) { - throw new Error(`installed package from ${entry} has an invalid ${expectedName} identity`); - } - return { - directory: await realpath(resolve(manifestFile, '..')), - manifestFile: await realpath(manifestFile), - manifest, - }; -} - -function declaredDependencies(manifest) { - const dependencies = new Map(); - for (const [field, required] of DEPENDENCY_FIELDS) { - for (const [name, specifier] of Object.entries(manifest[field] ?? {})) { - const existing = dependencies.get(name) ?? { - name, - specifier, - kinds: [], - required: false, - }; - if (existing.specifier !== specifier) { - throw new Error( - `${manifest.name}@${manifest.version} declares conflicting ${name} dependency specifiers`, - ); - } - existing.kinds.push(field); - existing.required ||= required; - dependencies.set(name, existing); - } - } - return [...dependencies.values()].sort((left, right) => left.name.localeCompare(right.name)); -} - -function packageId(manifest, treeSha256) { - return `${manifest.name}@${manifest.version}#${treeSha256.slice(0, 16)}`; -} diff --git a/tools/perf/wasix-node/package.json b/tools/perf/wasix-node/package.json deleted file mode 100644 index 3b4f7419d..000000000 --- a/tools/perf/wasix-node/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@oliphaunt/perf-wasix-node", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "bench:streaming": "node streaming-quick.mjs" - }, - "dependencies": { - "@electric-sql/pglite": "0.5.4" - }, - "engines": { - "node": ">=22.13 <25" - } -} diff --git a/tools/perf/wasix-node/plan.mjs b/tools/perf/wasix-node/plan.mjs deleted file mode 100644 index 80fa942c0..000000000 --- a/tools/perf/wasix-node/plan.mjs +++ /dev/null @@ -1,1203 +0,0 @@ -import { createHash } from 'node:crypto'; -import { readFile } from 'node:fs/promises'; -import { dirname, isAbsolute, relative as relativePath, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -export const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..'); -export const defaultPlanFile = resolve( - repositoryRoot, - 'benchmarks/wasix/node-pglite-memory-v2.json', -); - -const PLAN_SCHEMA = 'oliphaunt-wasix-node-benchmark-plan-v2'; -const PLAN_ID = 'node-pglite-memory-v2'; -const PACKAGE_NAME = '@oliphaunt/wasix-ts'; -const COMPARISON_PACKAGE = '@electric-sql/pglite'; -const COMPARISON_VERSION = '0.5.4'; -const COMPARISON_HOMEPAGE = 'https://pglite.dev'; -const COMPARISON_REPOSITORY = 'https://github.com/electric-sql/pglite'; -const COMPARISON_INTEGRITY = - 'sha512-yYZUyyXrHU7tPlCjwZQJ6hIG9DscdCCn7Uk0mYKwC1FeHX286AbcmFveMiRBEak8e9iPupjsoVImN3yJZVed2g=='; -const COMPARISON_COMMIT = '25d0a55e1f1e4c59f26d9e125150dda88a33fd00'; -const COMPARISON_TREE_SHA256 = 'b3925de04c386f51859c1bf18c143b225e3850616718140dd32e8eb48e9a2c84'; -const FZSTD_VERSION = '0.1.1'; -const NATIVE_ADDON = Object.freeze({ - schema: 'oliphaunt-wasix-napi-host-v1', - product: 'oliphaunt-wasix-napi', - binary: 'oliphaunt_wasix_napi.node', - addonAbiVersion: 1, - nodeApiVersion: 8, - profiles: Object.freeze(['standard', 'icu']), - build: Object.freeze({ - cargoProfile: 'release', - incremental: false, - codegenUnits: 1, - lto: 'thin', - strip: 'symbols', - features: Object.freeze(['release']), - }), -}); -const RUNTIME_BUILD = Object.freeze({ - profile: 'release', - cflags: '-O2 -g0 -flto=thin', - ldflags: '-flto=thin', - configureWasmOpt: 'no', - buildWasmOpt: 'yes', - wasmOptFlags: '--converge:--strip-debug:--strip-producers', - wasmOptSuppressDefault: '', - wasmOptPreserveUnoptimized: '', - compilerFlags: '', - linkerFlags: '', -}); -const GATED_TIMING_BOUNDARY = 'host-end-to-end-around-one-isolation-rpc'; -const LOWER_GIT_SHA = /^[0-9a-f]{40}$/u; -const SAFE_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u; -const SAFE_SETTING = /^[a-z][a-z0-9_]*$/u; -const BULK_OPERATIONS = new Set([ - 'aggregate-query', - 'create-and-insert-series', - 'create-payload-index', - 'reverse-indexed-prefix', -]); -const UTF8_ENCODER = new TextEncoder(); -const UTF8_DECODER = new TextDecoder(); - -export async function loadPlan(file = defaultPlanFile, { repositoryBindings = true } = {}) { - const bytes = await readFile(file); - let plan; - try { - plan = JSON.parse(bytes.toString('utf8')); - } catch (error) { - throw new Error(`${relative(file)} must contain JSON: ${describeError(error)}`); - } - validatePlan(plan); - if (repositoryBindings) { - await validateRepositoryBindings(plan); - } - return { plan, file: resolve(file), sha256: sha256(bytes), size: bytes.length }; -} - -function validateEngines(plan) { - equal(plan.id, PLAN_ID, 'plan.id'); - const engines = object(plan.engines, 'plan.engines'); - exactKeys(engines, ['candidate', 'comparison'], 'plan.engines'); - const candidate = object(engines.candidate, 'plan.engines.candidate'); - exactKeys( - candidate, - ['nativeAddon', 'package', 'runtimeBuild', 'storage', 'surfaces'], - 'plan.engines.candidate', - ); - validateCandidateIdentity(candidate); - const candidateSurfaces = object(candidate.surfaces, 'plan.engines.candidate.surfaces'); - exactKeys(candidateSurfaces, ['direct', 'worker'], 'plan.engines.candidate.surfaces'); - exactRecord( - candidateSurfaces.worker, - { - callingContract: 'async', - engine: 'candidate-worker', - entrypoint: '@oliphaunt/wasix-ts/worker', - executionBoundary: 'node-worker-thread', - executionOwner: 'sdk-worker', - isolationImplementation: 'package-owned-worker-rpc', - timingBoundary: GATED_TIMING_BOUNDARY, - }, - 'plan.engines.candidate.surfaces.worker', - ); - exactRecord( - candidateSurfaces.direct, - { - callingContract: 'async', - engine: 'candidate-direct', - entrypoint: '@oliphaunt/wasix-ts/direct', - executionBoundary: 'node-caller-realm', - executionOwner: 'caller', - isolationImplementation: 'none-caller-realm', - timingBoundary: 'caller-around-public-api', - }, - 'plan.engines.candidate.surfaces.direct', - ); - - const comparison = object(engines.comparison, 'plan.engines.comparison'); - exactKeys( - comparison, - [ - 'homepage', - 'installedTreeHashSchema', - 'installedTreeSha256', - 'integrity', - 'package', - 'sourceCommit', - 'sourceRepository', - 'storage', - 'surfaces', - 'version', - ], - 'plan.engines.comparison', - ); - validateComparisonIdentity(comparison); - const comparisonSurfaces = object(comparison.surfaces, 'plan.engines.comparison.surfaces'); - exactKeys(comparisonSurfaces, ['callerRealm', 'worker'], 'plan.engines.comparison.surfaces'); - exactRecord( - comparisonSurfaces.worker, - { - benchmarkMethodology: 'official-browser-worker-timer-reference-only-not-collected', - benchmarkMethodologySource: 'packages/benchmark/src/benchmarks-worker.js', - callingContract: 'async', - engine: 'comparison-worker', - entrypoint: 'tools/perf/wasix-node/pglite-node-worker.mjs', - executionBoundary: 'node-worker-thread', - executionOwner: 'harness-worker', - gatedResponsePayload: 'public-result-only-no-comparator-telemetry', - isolationImplementation: 'harness-owned-worker-threads-rpc', - officialWorkerModule: 'browser-worker-only', - timingBoundary: GATED_TIMING_BOUNDARY, - }, - 'plan.engines.comparison.surfaces.worker', - ); - exactRecord( - comparisonSurfaces.callerRealm, - { - callingContract: 'async', - engine: 'comparison-direct', - entrypoint: '@electric-sql/pglite', - executionBoundary: 'node-main-thread', - executionOwner: 'caller', - isolationImplementation: 'none-caller-realm', - timingBoundary: 'caller-around-public-api', - }, - 'plan.engines.comparison.surfaces.callerRealm', - ); -} - -function validateCandidateIdentity(candidate) { - equal(candidate.package, PACKAGE_NAME, 'plan.engines.candidate.package'); - equal(candidate.storage, 'memory', 'plan.engines.candidate.storage'); - assertNativeAddonContract( - candidate.nativeAddon, - NATIVE_ADDON, - 'plan.engines.candidate.nativeAddon', - ); - assertRuntimeBuildConfiguration( - object(candidate.runtimeBuild, 'plan.engines.candidate.runtimeBuild'), - RUNTIME_BUILD, - 'plan.engines.candidate.runtimeBuild', - ); -} - -function validateComparisonIdentity(comparison) { - equal(comparison.package, COMPARISON_PACKAGE, 'plan.engines.comparison.package'); - equal(comparison.version, COMPARISON_VERSION, 'plan.engines.comparison.version'); - equal(comparison.homepage, COMPARISON_HOMEPAGE, 'plan.engines.comparison.homepage'); - equal( - comparison.sourceRepository, - COMPARISON_REPOSITORY, - 'plan.engines.comparison.sourceRepository', - ); - equal(comparison.integrity, COMPARISON_INTEGRITY, 'plan.engines.comparison.integrity'); - if (!/^sha512-[A-Za-z0-9+/]+={0,2}$/u.test(comparison.integrity)) { - fail('plan.engines.comparison.integrity must be one exact SHA-512 SRI'); - } - equal(comparison.sourceCommit, COMPARISON_COMMIT, 'plan.engines.comparison.sourceCommit'); - if (!LOWER_GIT_SHA.test(comparison.sourceCommit)) { - fail('plan.engines.comparison.sourceCommit must be a full lowercase Git commit'); - } - equal(comparison.storage, 'memory', 'plan.engines.comparison.storage'); - equal( - comparison.installedTreeHashSchema, - 'oliphaunt-path-size-content-sha256-v1', - 'plan.engines.comparison.installedTreeHashSchema', - ); - equal( - comparison.installedTreeSha256, - COMPARISON_TREE_SHA256, - 'plan.engines.comparison.installedTreeSha256', - ); -} - -function exactRecord(actual, expected, label) { - const record = object(actual, label); - exactKeys(record, Object.keys(expected), label); - for (const [field, value] of Object.entries(expected)) { - equal(record[field], value, `${label}.${field}`); - } -} - -export function validatePlan(plan) { - object(plan, 'plan'); - exactKeys( - plan, - [ - 'bulk', - 'bulkTransport', - 'description', - 'engines', - 'firstQuery', - 'gate', - 'id', - 'measurement', - 'postgres', - 'schema', - 'warmRtt', - 'warmSetupSql', - 'warmValidation', - ], - 'plan', - ); - equal(plan.schema, PLAN_SCHEMA, 'plan.schema'); - validateEngines(plan); - safeId(plan.id, 'plan.id'); - nonEmptyString(plan.description, 'plan.description'); - - const measurement = object(plan.measurement, 'plan.measurement'); - exactKeys( - measurement, - [ - 'pairedRepeats', - 'pairing', - 'percentileMethod', - 'processOrder', - 'sampleIterations', - 'startupMetric', - 'startupMetricIncludes', - 'trimFraction', - 'warmupIterations', - ], - 'plan.measurement', - ); - positiveInteger(measurement.pairedRepeats, 'plan.measurement.pairedRepeats', 9); - if (measurement.pairedRepeats % 2 !== 0) { - fail('plan.measurement.pairedRepeats must be even to balance gated engine launch order'); - } - positiveInteger(measurement.warmupIterations, 'plan.measurement.warmupIterations', 1); - positiveInteger(measurement.sampleIterations, 'plan.measurement.sampleIterations', 20); - if ( - typeof measurement.trimFraction !== 'number' || - measurement.trimFraction < 0 || - measurement.trimFraction >= 0.5 - ) { - fail('plan.measurement.trimFraction must be a number from 0 up to, but not including, 0.5'); - } - equal( - measurement.processOrder, - 'alternating-worker-pairs-then-alternating-direct-pairs-fresh-processes', - 'plan.measurement.processOrder', - ); - equal(measurement.pairing, 'same-repeat-candidate-over-comparison', 'plan.measurement.pairing'); - equal(measurement.percentileMethod, 'nearest-rank', 'plan.measurement.percentileMethod'); - equal(measurement.startupMetric, 'cold-to-first-result', 'plan.measurement.startupMetric'); - exactStringList( - measurement.startupMetricIncludes, - ['public-open', 'immediate-first-query'], - 'plan.measurement.startupMetricIncludes', - ); - - const gate = object(plan.gate, 'plan.gate'); - exactKeys( - gate, - ['comparisons', 'includes', 'maxGeomeanRatio', 'metric', 'requiresCorrectness'], - 'plan.gate', - ); - if ( - typeof gate.maxGeomeanRatio !== 'number' || - gate.maxGeomeanRatio <= 0 || - gate.maxGeomeanRatio > 0.8 - ) { - fail('plan.gate.maxGeomeanRatio must be positive and no greater than 0.80'); - } - equal(gate.requiresCorrectness, true, 'plan.gate.requiresCorrectness'); - exactStringList(gate.comparisons, ['worker', 'direct'], 'plan.gate.comparisons'); - equal( - gate.metric, - 'geometric-mean-of-median-paired-candidate-over-comparison-ratios-lower-is-better', - 'plan.gate.metric', - ); - exactStringList( - gate.includes, - ['cold-to-first-result', 'warm-rtt-p50', 'bulk-elapsed'], - 'plan.gate.includes', - ); - - const bulkTransport = object(plan.bulkTransport, 'plan.bulkTransport'); - exactKeys( - bulkTransport, - ['pgliteSyncToFs', 'publicApi', 'request', 'response', 'validation'], - 'plan.bulkTransport', - ); - equal(bulkTransport.publicApi, 'execProtocolRaw', 'plan.bulkTransport.publicApi'); - equal(bulkTransport.request, 'postgres-simple-query-message', 'plan.bulkTransport.request'); - equal(bulkTransport.response, 'raw-postgres-protocol-bytes', 'plan.bulkTransport.response'); - equal(bulkTransport.pgliteSyncToFs, false, 'plan.bulkTransport.pgliteSyncToFs'); - equal( - bulkTransport.validation, - 'timed-response-semantics-and-canonical-state-validation', - 'plan.bulkTransport.validation', - ); - - const postgres = object(plan.postgres, 'plan.postgres'); - exactKeys(postgres, ['expectedSettings', 'major', 'settings'], 'plan.postgres'); - positiveInteger(postgres.major, 'plan.postgres.major', 1); - nonEmptyArray(postgres.settings, 'plan.postgres.settings'); - const settings = new Set(); - for (const [index, setting] of postgres.settings.entries()) { - if (typeof setting !== 'string' || !SAFE_SETTING.test(setting) || settings.has(setting)) { - fail(`plan.postgres.settings[${index}] must be a unique safe PostgreSQL setting name`); - } - settings.add(setting); - } - const expectedSettings = object(postgres.expectedSettings, 'plan.postgres.expectedSettings'); - exactKeys(expectedSettings, postgres.settings, 'plan.postgres.expectedSettings'); - for (const setting of postgres.settings) { - nonEmptyString(expectedSettings[setting], `plan.postgres.expectedSettings.${setting}`); - } - - validateQuery(plan.firstQuery, 'plan.firstQuery'); - nonEmptyString(plan.warmSetupSql, 'plan.warmSetupSql'); - validateWarmCases(plan.warmRtt); - validateQuery(plan.warmValidation, 'plan.warmValidation', { allowPlaceholder: true }); - validateBulk(plan.bulk); - return plan; -} - -export async function validateRepositoryBindings(plan) { - const candidateFile = resolve(repositoryRoot, 'src/bindings/wasix-ts/package.json'); - const candidate = JSON.parse(await readFile(candidateFile, 'utf8')); - equal(candidate.name, plan.engines.candidate.package, `${relative(candidateFile)}.name`); - equal( - candidate.exports?.['.']?.node, - './lib/index.node.js', - `${relative(candidateFile)}.exports["."].node`, - ); - equal( - candidate.exports?.['./direct']?.node, - './lib/direct.node.js', - `${relative(candidateFile)}.exports["./direct"].node`, - ); - equal( - candidate.exports?.['./worker']?.node, - './lib/worker-entry.node.js', - `${relative(candidateFile)}.exports["./worker"].node`, - ); - equal( - candidate.dependencies?.fzstd, - FZSTD_VERSION, - `${relative(candidateFile)}.dependencies.fzstd`, - ); - equal( - candidate.devDependencies?.[plan.engines.comparison.package], - plan.engines.comparison.version, - `${relative(candidateFile)}.devDependencies.${plan.engines.comparison.package}`, - ); - for (const field of ['dependencies', 'optionalDependencies', 'peerDependencies']) { - if (candidate[field]?.[plan.engines.comparison.package] !== undefined) { - fail( - `${relative(candidateFile)}.${field} must not publish the benchmark-only PGlite control`, - ); - } - } - - const harnessFile = resolve(repositoryRoot, 'tools/perf/wasix-node/package.json'); - const harness = JSON.parse(await readFile(harnessFile, 'utf8')); - equal(harness.private, true, `${relative(harnessFile)}.private`); - equal( - harness.dependencies?.[plan.engines.comparison.package], - plan.engines.comparison.version, - `${relative(harnessFile)}.dependencies.${plan.engines.comparison.package}`, - ); - const lockFile = resolve(repositoryRoot, 'pnpm-lock.yaml'); - const lock = await readFile(lockFile, 'utf8'); - const lockedControl = - ` '${plan.engines.comparison.package}@${plan.engines.comparison.version}':\n` + - ` resolution: {integrity: ${plan.engines.comparison.integrity}}`; - if (!lock.includes(lockedControl)) { - fail(`${relative(lockFile)} must lock the exact PGlite control and its expected integrity`); - } - const nativeProductFile = resolve(repositoryRoot, 'src/runtimes/wasix-napi/package.json'); - const nativeProduct = JSON.parse(await readFile(nativeProductFile, 'utf8')); - equal(nativeProduct.name, '@oliphaunt/wasix-napi', `${relative(nativeProductFile)}.name`); - equal( - nativeProduct.oliphaunt?.addonAbiVersion, - plan.engines.candidate.nativeAddon.addonAbiVersion, - `${relative(nativeProductFile)}.oliphaunt.addonAbiVersion`, - ); - equal( - nativeProduct.oliphaunt?.nodeApiVersion, - plan.engines.candidate.nativeAddon.nodeApiVersion, - `${relative(nativeProductFile)}.oliphaunt.nodeApiVersion`, - ); - exactStringList( - nativeProduct.oliphaunt?.profiles, - plan.engines.candidate.nativeAddon.profiles, - `${relative(nativeProductFile)}.oliphaunt.profiles`, - ); - return { candidate, harness }; -} - -export function planSummary(plan, source) { - return { - schema: plan.schema, - id: plan.id, - source: { - path: relative(source.file), - sha256: source.sha256, - size: source.size, - }, - engines: plan.engines, - measurement: plan.measurement, - gate: plan.gate, - bulkTransport: plan.bulkTransport, - postgres: plan.postgres, - metrics: metricIds(plan), - generatedSql: plan.bulk.map((entry) => ({ - id: entry.id, - operation: entry.operation, - sha256: sha256(bulkSql(entry)), - bytes: Buffer.byteLength(bulkSql(entry)), - })), - }; -} - -export function assertRuntimeBuildConfiguration(actual, expected, label = 'runtime build') { - object(actual, label); - object(expected, `${label} expectation`); - exactKeys(actual, Object.keys(expected), label); - for (const [field, value] of Object.entries(expected)) { - equal(actual[field], value, `${label}.${field}`); - } -} - -export function assertNativeAddonContract(actual, expected, label = 'native addon') { - const fields = [ - 'addonAbiVersion', - 'binary', - 'build', - 'nodeApiVersion', - 'product', - 'profiles', - 'schema', - ]; - const actualAddon = object(actual, label); - const expectedAddon = object(expected, `${label} expectation`); - exactKeys(actualAddon, fields, label); - exactKeys(expectedAddon, fields, `${label} expectation`); - for (const addon of [actualAddon, expectedAddon]) { - equal(addon.schema, 'oliphaunt-wasix-napi-host-v1', `${label}.schema`); - equal(addon.product, 'oliphaunt-wasix-napi', `${label}.product`); - equal(addon.binary, 'oliphaunt_wasix_napi.node', `${label}.binary`); - positiveInteger(addon.addonAbiVersion, `${label}.addonAbiVersion`, 1); - positiveInteger(addon.nodeApiVersion, `${label}.nodeApiVersion`, 8); - exactStringList(addon.profiles, ['standard', 'icu'], `${label}.profiles`); - const build = object(addon.build, `${label}.build`); - exactKeys( - build, - ['cargoProfile', 'codegenUnits', 'features', 'incremental', 'lto', 'strip'], - `${label}.build`, - ); - equal(build.cargoProfile, 'release', `${label}.build.cargoProfile`); - equal(build.incremental, false, `${label}.build.incremental`); - equal(build.codegenUnits, 1, `${label}.build.codegenUnits`); - equal(build.lto, 'thin', `${label}.build.lto`); - equal(build.strip, 'symbols', `${label}.build.strip`); - exactStringList(build.features, ['release'], `${label}.build.features`); - } - for (const field of ['schema', 'product', 'binary', 'addonAbiVersion', 'nodeApiVersion']) { - equal(actualAddon[field], expectedAddon[field], `${label}.${field}`); - } - exactStringList(actualAddon.profiles, expectedAddon.profiles, `${label}.profiles`); - for (const field of ['cargoProfile', 'incremental', 'codegenUnits', 'lto', 'strip']) { - equal(actualAddon.build[field], expectedAddon.build[field], `${label}.build.${field}`); - } - exactStringList( - actualAddon.build.features, - expectedAddon.build.features, - `${label}.build.features`, - ); - return actualAddon; -} - -export function assertNativeArtifactProvenance(carrier, expectedAddon, expectedArtifactSourceSha) { - assertNativeAddonContract(expectedAddon, expectedAddon, 'benchmark native addon contract'); - if (!LOWER_GIT_SHA.test(expectedArtifactSourceSha ?? '')) { - fail('benchmark artifact source must be a full lowercase Git commit'); - } - if (carrier === undefined) fail('packed candidate has no native carrier'); - const provenance = carrier.artifactProvenance; - const manifest = carrier.manifest; - const buildInputs = provenance?.buildInputs; - if ( - provenance?.schema !== 'oliphaunt-wasix-napi-provenance-v1' || - provenance.product !== expectedAddon.product || - provenance.target !== carrier.target || - provenance.artifactSourceSha !== expectedArtifactSourceSha || - provenance.binary?.filename !== expectedAddon.binary || - !/^[0-9a-f]{64}$/u.test(provenance.binary?.sha256 ?? '') || - buildInputs?.schema !== 'oliphaunt-wasix-napi-build-inputs-v1' || - buildInputs.target !== carrier.target || - manifest?.oliphaunt?.target !== carrier.target || - manifest.oliphaunt.addonAbiVersion !== expectedAddon.addonAbiVersion || - manifest.oliphaunt.nodeApiVersion !== expectedAddon.nodeApiVersion || - stableJson(manifest.oliphaunt.profiles) !== stableJson(expectedAddon.profiles) - ) { - fail('packed candidate native carrier differs from the benchmark addon/source contract'); - } - const build = provenance.build; - const { targetTriple, ...portableBuild } = build ?? {}; - if ( - typeof targetTriple !== 'string' || - targetTriple.length === 0 || - stableJson(portableBuild) !== stableJson(expectedAddon.build) || - targetTriple !== buildInputs.targetTriple - ) { - fail('packed candidate native carrier has incompatible optimized build provenance'); - } - return { - carrier: carrier.name, - version: carrier.version, - target: carrier.target, - artifactProvenanceMember: carrier.artifactProvenanceMember, - artifactProvenance: provenance, - }; -} - -export function metricIds(plan) { - return [ - 'cold-to-first-result', - ...plan.warmRtt.map((entry) => `warm-rtt/${entry.id}/p50`), - ...plan.bulk.map((entry) => `bulk/${entry.id}/elapsed`), - ]; -} - -export function bulkSql(entry) { - switch (entry.operation.kind) { - case 'create-and-insert-series': - return `CREATE TABLE bench_bulk (id integer PRIMARY KEY, payload text NOT NULL, revision integer NOT NULL DEFAULT 0); INSERT INTO bench_bulk (id, payload) SELECT i, md5(i::text) FROM generate_series(1, ${entry.operation.rows}) AS i;`; - case 'create-payload-index': - return 'CREATE INDEX bench_bulk_payload_idx ON bench_bulk(payload);'; - case 'reverse-indexed-prefix': - return `UPDATE bench_bulk SET payload = reverse(payload), revision = revision + 1 WHERE id <= ${entry.operation.rows};`; - case 'aggregate-query': - return 'SELECT count(*)::bigint AS rows, sum(id)::bigint AS sum_id, sum(octet_length(payload))::bigint AS total_bytes FROM bench_bulk'; - default: - throw new Error(`unsupported bulk operation ${JSON.stringify(entry.operation.kind)}`); - } -} - -export function simpleQueryMessage(sql) { - if (typeof sql !== 'string' || sql.includes('\0')) { - throw new Error('simple query SQL must be a string without NUL bytes'); - } - const body = UTF8_ENCODER.encode(sql); - const packet = new Uint8Array(body.length + 6); - packet[0] = 0x51; - writeI32(packet, 1, body.length + 5); - packet.set(body, 5); - return packet; -} - -export function assertSuccessfulRawProtocolResponse(bytes, label) { - decodeRawProtocolOutcome(bytes, label); -} - -export function assertExpectedRawProtocolResponse(bytes, expected, label) { - const actual = decodeRawProtocolOutcome(bytes, label); - if (stableJson(actual) !== stableJson(expected)) { - throw new Error( - `${label} returned protocol outcome ${stableJson(actual)}, expected ${stableJson(expected)}`, - ); - } - return actual; -} - -export function expectedBulkProtocol(entry) { - switch (entry.operation.kind) { - case 'create-and-insert-series': - return { - commandTags: ['CREATE TABLE', `INSERT 0 ${entry.operation.rows}`], - results: [], - transactionStatus: 'idle', - }; - case 'create-payload-index': - return { commandTags: ['CREATE INDEX'], results: [], transactionStatus: 'idle' }; - case 'reverse-indexed-prefix': - return { - commandTags: [`UPDATE ${entry.operation.rows}`], - results: [], - transactionStatus: 'idle', - }; - case 'aggregate-query': - return { - commandTags: ['SELECT 1'], - results: [entry.expectedResult], - transactionStatus: 'idle', - }; - default: - throw new Error(`unsupported bulk operation ${JSON.stringify(entry.operation.kind)}`); - } -} - -export function decodeRawProtocolOutcome(bytes, label) { - if (!(bytes instanceof Uint8Array)) { - throw new Error(`${label} must return raw PostgreSQL protocol bytes`); - } - let offset = 0; - let sawReady = false; - let transactionStatus; - let fields; - let rows = []; - const commandTags = []; - const results = []; - while (offset < bytes.length) { - if (bytes.length - offset < 5) { - throw new Error(`${label} returned a truncated PostgreSQL protocol frame`); - } - const tag = bytes[offset]; - const length = readI32(bytes, offset + 1); - const end = offset + 1 + length; - if (length < 4 || end > bytes.length) { - throw new Error(`${label} returned an invalid PostgreSQL protocol frame length ${length}`); - } - const body = bytes.subarray(offset + 5, end); - if (tag === 0x45) throw rawProtocolError(body, label); - if (tag === 0x54) { - if (fields !== undefined) throw new Error(`${label} returned nested RowDescription frames`); - fields = parseRawRowDescription(body, label); - rows = []; - } else if (tag === 0x44) { - if (fields === undefined) throw new Error(`${label} returned DataRow before RowDescription`); - rows.push(parseRawDataRow(body, fields.length, label)); - } else if (tag === 0x43) { - commandTags.push(parseRawCommandTag(body, label)); - if (fields !== undefined) { - results.push(canonicalResult(fields, rows)); - fields = undefined; - rows = []; - } - } else if (tag === 0x5a) { - if (length !== 5 || ![0x45, 0x49, 0x54].includes(bytes[offset + 5]) || fields !== undefined) { - throw new Error(`${label} returned an invalid ReadyForQuery frame`); - } - sawReady = true; - transactionStatus = { 69: 'failed', 73: 'idle', 84: 'transaction' }[bytes[offset + 5]]; - if (end !== bytes.length) throw new Error(`${label} returned bytes after ReadyForQuery`); - } else if (tag === 0x53) { - validateRawParameterStatus(body, label); - } else if (tag === 0x4e) { - validateRawFieldResponse(body, 'NoticeResponse', label); - } else { - throw new Error(`${label} returned unexpected PostgreSQL protocol tag 0x${tag.toString(16)}`); - } - offset = end; - } - if (!sawReady) throw new Error(`${label} ended before ReadyForQuery`); - return { commandTags, results, transactionStatus }; -} - -export function postgresSettingsParity(reports, expectedNames, expectedSettings) { - const expectedKeys = [...expectedNames].sort(); - const observations = reports.map((report) => { - const source = report?.postgres?.settings; - const validRecord = source !== null && !Array.isArray(source) && typeof source === 'object'; - const keys = validRecord ? Object.keys(source).sort() : []; - const valid = - validRecord && - stableJson(keys) === stableJson(expectedKeys) && - expectedNames.every((name) => typeof source[name] === 'string'); - const settings = valid - ? Object.fromEntries(expectedNames.map((name) => [name, source[name]])) - : null; - return { - engine: report?.engine?.kind ?? null, - repeat: report?.repeat ?? null, - settings, - contract: settings === null ? null : stableJson(settings), - }; - }); - const contracts = new Set(observations.map(({ contract }) => contract)); - const parityPassed = observations.length > 0 && !contracts.has(null) && contracts.size === 1; - const sharedSettings = parityPassed ? observations[0]?.settings : null; - const expectedPassed = - expectedSettings === undefined || stableJson(sharedSettings) === stableJson(expectedSettings); - const passed = parityPassed && expectedPassed; - return { - passed, - parityPassed, - expectedPassed, - expectedNames: [...expectedNames], - expectedSettings: expectedSettings ?? null, - sharedSettings, - mismatches: passed - ? [] - : observations.map(({ engine, repeat, settings }) => ({ engine, repeat, settings })), - }; -} - -export function pairedRatioSummary(candidateSamples, comparisonSamples) { - if ( - !Array.isArray(candidateSamples) || - !Array.isArray(comparisonSamples) || - candidateSamples.length === 0 || - candidateSamples.length !== comparisonSamples.length - ) { - throw new Error('paired ratio summary requires equally sized non-empty sample arrays'); - } - const pairedRatios = candidateSamples.map((candidate, index) => { - const comparison = comparisonSamples[index]; - if ( - typeof candidate !== 'number' || - !Number.isFinite(candidate) || - candidate <= 0 || - typeof comparison !== 'number' || - !Number.isFinite(comparison) || - comparison <= 0 - ) { - throw new Error('paired ratio samples must be positive finite numbers'); - } - return candidate / comparison; - }); - return { pairedRatios, medianRatio: median(pairedRatios) }; -} - -export function canonicalResult(fields, rows) { - if (!Array.isArray(fields) || !Array.isArray(rows)) { - fail('database result must contain field and row arrays'); - } - return { - fields: fields.map((field, index) => nonEmptyString(field, `result.fields[${index}]`)), - rows: rows.map((row, rowIndex) => { - if (!Array.isArray(row) || row.length !== fields.length) { - fail(`result.rows[${rowIndex}] must contain exactly ${fields.length} values`); - } - return row.map((value) => (value === null ? null : String(value))); - }), - }; -} - -export function expandExpectedResult(result, replacements = {}) { - return { - fields: [...result.fields], - rows: result.rows.map((row) => - row.map((value) => - typeof value === 'string' && Object.hasOwn(replacements, value) - ? String(replacements[value]) - : value, - ), - ), - }; -} - -export function assertExpectedResult(actual, expected, label) { - const left = stableJson(actual); - const right = stableJson(expected); - if (left !== right) { - throw new Error(`${label} returned ${left}, expected ${right}`); - } - return sha256(right); -} - -export function latencySummary(samples, trimFraction) { - if (!Array.isArray(samples) || samples.length === 0) { - throw new Error('latency summary requires samples'); - } - if ( - samples.some((sample) => typeof sample !== 'number' || !Number.isFinite(sample) || sample <= 0) - ) { - throw new Error('latency samples must be positive finite numbers'); - } - const sorted = [...samples].sort((left, right) => left - right); - const trim = Math.floor(sorted.length * trimFraction); - const trimmed = sorted.slice(trim, sorted.length - trim); - return { - samples: sorted.length, - trimmedSamples: trimmed.length, - minMs: sorted[0], - p50Ms: nearestRank(sorted, 0.5), - p90Ms: nearestRank(sorted, 0.9), - p95Ms: nearestRank(sorted, 0.95), - p99Ms: nearestRank(sorted, 0.99), - maxMs: sorted.at(-1), - trimmedMeanMs: trimmed.reduce((sum, value) => sum + value, 0) / trimmed.length, - }; -} - -export function median(values) { - if ( - !Array.isArray(values) || - values.length === 0 || - values.some((value) => typeof value !== 'number' || !Number.isFinite(value)) - ) { - throw new Error('median requires finite numeric values'); - } - const sorted = [...values].sort((left, right) => left - right); - const midpoint = Math.floor(sorted.length / 2); - return sorted.length % 2 === 0 ? (sorted[midpoint - 1] + sorted[midpoint]) / 2 : sorted[midpoint]; -} - -export function geomean(values) { - if ( - !Array.isArray(values) || - values.length === 0 || - values.some((value) => typeof value !== 'number' || !Number.isFinite(value) || value <= 0) - ) { - throw new Error('geomean requires positive finite numeric values'); - } - return Math.exp(values.reduce((sum, value) => sum + Math.log(value), 0) / values.length); -} - -export function comfortableWinGate(ratios, maxGeomeanRatio, correctnessPassed) { - if ( - typeof maxGeomeanRatio !== 'number' || - !Number.isFinite(maxGeomeanRatio) || - maxGeomeanRatio <= 0 - ) { - throw new Error('comfortable-win gate requires a positive finite maximum ratio'); - } - const geomeanRatio = geomean(ratios); - return { - geomeanRatio, - gate: { - passed: correctnessPassed && geomeanRatio <= maxGeomeanRatio, - correctnessPassed, - maxGeomeanRatio, - requiredMinimumWinPercent: (1 - maxGeomeanRatio) * 100, - observedWinPercent: (1 - geomeanRatio) * 100, - }, - }; -} - -export function sha256(value) { - return createHash('sha256').update(value).digest('hex'); -} - -export function stableJson(value) { - if (Array.isArray(value)) { - return `[${value.map(stableJson).join(',')}]`; - } - if (value !== null && typeof value === 'object') { - return `{${Object.keys(value) - .sort() - .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) - .join(',')}}`; - } - return JSON.stringify(value); -} - -export async function findPackageManifest(entry, expectedName) { - let directory = dirname(resolve(entry)); - for (;;) { - const file = resolve(directory, 'package.json'); - try { - const manifest = JSON.parse(await readFile(file, 'utf8')); - if (manifest.name === expectedName) return { file, manifest }; - } catch (error) { - if (error?.code !== 'ENOENT') throw error; - } - const parent = dirname(directory); - if (parent === directory) break; - directory = parent; - } - throw new Error(`could not locate ${expectedName} package.json from ${entry}`); -} - -function validateWarmCases(value) { - nonEmptyArray(value, 'plan.warmRtt'); - const ids = new Set(); - for (const [index, entryValue] of value.entries()) { - const label = `plan.warmRtt[${index}]`; - const entry = object(entryValue, label); - exactKeys(entry, ['expectation', 'id', 'parameters', 'sql'], label); - safeId(entry.id, `${label}.id`); - if (ids.has(entry.id)) fail(`${label}.id must be unique`); - ids.add(entry.id); - nonEmptyString(entry.sql, `${label}.sql`); - if (!Array.isArray(entry.parameters)) fail(`${label}.parameters must be an array`); - for (const [parameterIndex, parameter] of entry.parameters.entries()) { - if (!['boolean', 'number', 'string'].includes(typeof parameter) && parameter !== null) { - fail(`${label}.parameters[${parameterIndex}] must be a JSON scalar`); - } - } - const expectation = object(entry.expectation, `${label}.expectation`); - if (expectation.kind === 'exact') { - exactKeys(expectation, ['kind', 'result'], `${label}.expectation`); - validateExpectedResult(expectation.result, `${label}.expectation.result`); - } else if (expectation.kind === 'one-based-counter') { - exactKeys(expectation, ['field', 'kind'], `${label}.expectation`); - nonEmptyString(expectation.field, `${label}.expectation.field`); - } else { - fail(`${label}.expectation.kind is unsupported`); - } - } -} - -function validateBulk(value) { - nonEmptyArray(value, 'plan.bulk'); - const ids = new Set(); - let sourceRows; - for (const [index, entryValue] of value.entries()) { - const label = `plan.bulk[${index}]`; - const entry = object(entryValue, label); - const expectedKeys = - entry.operation?.kind === 'aggregate-query' - ? ['expectedResult', 'id', 'operation'] - : ['expectedResult', 'id', 'operation', 'validationSql']; - exactKeys(entry, expectedKeys, label); - safeId(entry.id, `${label}.id`); - if (ids.has(entry.id)) fail(`${label}.id must be unique`); - ids.add(entry.id); - const operation = object(entry.operation, `${label}.operation`); - if (!BULK_OPERATIONS.has(operation.kind)) fail(`${label}.operation.kind is unsupported`); - if (operation.kind === 'create-and-insert-series') { - exactKeys(operation, ['kind', 'rows'], `${label}.operation`); - positiveInteger(operation.rows, `${label}.operation.rows`, 1000); - sourceRows = operation.rows; - } else if (operation.kind === 'reverse-indexed-prefix') { - exactKeys(operation, ['kind', 'rows'], `${label}.operation`); - positiveInteger(operation.rows, `${label}.operation.rows`, 1); - if (sourceRows === undefined || operation.rows > sourceRows) { - fail(`${label}.operation.rows must not exceed the preceding inserted row count`); - } - } else { - exactKeys(operation, ['kind'], `${label}.operation`); - } - if (entry.validationSql !== undefined) { - nonEmptyString(entry.validationSql, `${label}.validationSql`); - } - validateExpectedResult(entry.expectedResult, `${label}.expectedResult`); - nonEmptyString(bulkSql(entry), `${label} generated SQL`); - } - if (sourceRows === undefined) fail('plan.bulk must create its deterministic source table'); -} - -function validateQuery(value, label, { allowPlaceholder = false } = {}) { - const query = object(value, label); - exactKeys(query, ['expectedResult', 'sql'], label); - nonEmptyString(query.sql, `${label}.sql`); - validateExpectedResult(query.expectedResult, `${label}.expectedResult`, { allowPlaceholder }); -} - -function validateExpectedResult(value, label, { allowPlaceholder = false } = {}) { - const result = object(value, label); - exactKeys(result, ['fields', 'rows'], label); - nonEmptyArray(result.fields, `${label}.fields`); - for (const [index, field] of result.fields.entries()) { - nonEmptyString(field, `${label}.fields[${index}]`); - } - if (!Array.isArray(result.rows)) fail(`${label}.rows must be an array`); - for (const [rowIndex, row] of result.rows.entries()) { - if (!Array.isArray(row) || row.length !== result.fields.length) { - fail(`${label}.rows[${rowIndex}] must contain exactly ${result.fields.length} values`); - } - for (const [columnIndex, column] of row.entries()) { - if (column !== null && typeof column !== 'string') { - fail(`${label}.rows[${rowIndex}][${columnIndex}] must be a string or null`); - } - if (typeof column === 'string' && column.startsWith('$') && !allowPlaceholder) { - fail(`${label}.rows[${rowIndex}][${columnIndex}] must not contain a placeholder`); - } - } - } -} - -function writeI32(bytes, offset, value) { - bytes[offset] = (value >>> 24) & 0xff; - bytes[offset + 1] = (value >>> 16) & 0xff; - bytes[offset + 2] = (value >>> 8) & 0xff; - bytes[offset + 3] = value & 0xff; -} - -function readI32(bytes, offset) { - return ( - bytes[offset] * 0x1000000 + - bytes[offset + 1] * 0x10000 + - bytes[offset + 2] * 0x100 + - bytes[offset + 3] - ); -} - -function readI16(bytes, offset) { - return bytes[offset] * 0x100 + bytes[offset + 1]; -} - -function readSignedI32(bytes, offset) { - const value = readI32(bytes, offset); - return value > 0x7fffffff ? value - 0x100000000 : value; -} - -function parseRawRowDescription(body, label) { - if (body.length < 2) throw new Error(`${label} returned a truncated RowDescription`); - const count = readI16(body, 0); - const fields = []; - let offset = 2; - for (let index = 0; index < count; index += 1) { - const field = readRawCString(body, offset, `${label} RowDescription field ${index}`); - fields.push(field.value); - offset = field.next; - if (offset + 18 > body.length) { - throw new Error(`${label} returned a truncated RowDescription field`); - } - const format = readI16(body, offset + 16); - if (format !== 0) throw new Error(`${label} returned a non-text RowDescription field`); - offset += 18; - } - if (offset !== body.length) throw new Error(`${label} returned trailing RowDescription bytes`); - return fields; -} - -function parseRawDataRow(body, expectedColumns, label) { - if (body.length < 2) throw new Error(`${label} returned a truncated DataRow`); - const count = readI16(body, 0); - if (count !== expectedColumns) { - throw new Error(`${label} returned ${count} DataRow columns, expected ${expectedColumns}`); - } - const row = []; - let offset = 2; - for (let index = 0; index < count; index += 1) { - if (offset + 4 > body.length) throw new Error(`${label} returned a truncated DataRow length`); - const length = readSignedI32(body, offset); - offset += 4; - if (length === -1) { - row.push(null); - continue; - } - if (length < 0 || offset + length > body.length) { - throw new Error(`${label} returned an invalid DataRow value length ${length}`); - } - row.push(decodeRawText(body.subarray(offset, offset + length), `${label} DataRow value`)); - offset += length; - } - if (offset !== body.length) throw new Error(`${label} returned trailing DataRow bytes`); - return row; -} - -function parseRawCommandTag(body, label) { - const command = readRawCString(body, 0, `${label} CommandComplete`); - if (command.next !== body.length) { - throw new Error(`${label} returned trailing CommandComplete bytes`); - } - return command.value; -} - -function validateRawParameterStatus(body, label) { - const name = readRawCString(body, 0, `${label} ParameterStatus name`); - if (name.value.length === 0) throw new Error(`${label} returned an empty ParameterStatus name`); - const value = readRawCString(body, name.next, `${label} ParameterStatus value`); - if (value.next !== body.length) { - throw new Error(`${label} returned trailing ParameterStatus bytes`); - } -} - -function validateRawFieldResponse(body, kind, label) { - let offset = 0; - for (;;) { - if (offset >= body.length) throw new Error(`${label} returned unterminated ${kind}`); - const code = body[offset]; - offset += 1; - if (code === 0) { - if (offset !== body.length) throw new Error(`${label} returned trailing ${kind} bytes`); - return; - } - const field = readRawCString(body, offset, `${label} ${kind} field 0x${code.toString(16)}`); - offset = field.next; - } -} - -function readRawCString(bytes, offset, label) { - const end = bytes.indexOf(0, offset); - if (end < 0) throw new Error(`${label} is missing its NUL terminator`); - return { value: decodeRawText(bytes.subarray(offset, end), label), next: end + 1 }; -} - -function decodeRawText(bytes, label) { - try { - return new TextDecoder('utf-8', { fatal: true }).decode(bytes); - } catch (error) { - throw new Error(`${label} is not valid UTF-8: ${describeError(error)}`); - } -} - -function rawProtocolError(body, label) { - let offset = 0; - let message = 'PostgreSQL ErrorResponse'; - let sqlstate; - while (offset < body.length) { - const code = body[offset]; - offset += 1; - if (code === 0) break; - const end = body.indexOf(0, offset); - if (end < 0) return new Error(`${label} returned a malformed PostgreSQL ErrorResponse`); - const value = UTF8_DECODER.decode(body.subarray(offset, end)); - if (code === 0x43) sqlstate = value; - if (code === 0x4d) message = value; - offset = end + 1; - } - return new Error( - `${label} returned PostgreSQL error${sqlstate === undefined ? '' : ` ${sqlstate}`}: ${message}`, - ); -} - -function nearestRank(sorted, percentile) { - return sorted[Math.max(0, Math.ceil(sorted.length * percentile) - 1)]; -} - -function object(value, label) { - if (value === null || Array.isArray(value) || typeof value !== 'object') { - fail(`${label} must be an object`); - } - return value; -} - -function exactKeys(value, keys, label) { - const actual = Object.keys(value).sort(); - const expected = [...keys].sort(); - if (stableJson(actual) !== stableJson(expected)) { - fail(`${label} fields are ${stableJson(actual)}, expected ${stableJson(expected)}`); - } -} - -function exactStringList(value, expected, label) { - if (!Array.isArray(value) || stableJson(value) !== stableJson(expected)) { - fail(`${label} must be ${stableJson(expected)}`); - } -} - -function nonEmptyArray(value, label) { - if (!Array.isArray(value) || value.length === 0) fail(`${label} must be a non-empty array`); - return value; -} - -function nonEmptyString(value, label) { - if (typeof value !== 'string' || value.length === 0 || value.includes('\0')) { - fail(`${label} must be a non-empty string without NUL bytes`); - } - return value; -} - -function positiveInteger(value, label, minimum) { - if (!Number.isSafeInteger(value) || value < minimum) { - fail(`${label} must be an integer of at least ${minimum}`); - } - return value; -} - -function safeId(value, label) { - if (typeof value !== 'string' || !SAFE_ID.test(value)) - fail(`${label} must be a safe kebab-case id`); -} - -function equal(actual, expected, label) { - if (actual !== expected) - fail(`${label} is ${JSON.stringify(actual)}, expected ${JSON.stringify(expected)}`); -} - -function fail(message) { - throw new Error(`wasix-node benchmark plan: ${message}`); -} - -function relative(file) { - const value = relativePath(repositoryRoot, resolve(file)); - return value === '' || value.startsWith('..') || isAbsolute(value) - ? resolve(file) - : value.split('\\').join('/'); -} - -function describeError(error) { - return error instanceof Error ? error.message : String(error); -} diff --git a/tools/perf/wasix-node/plan.test.mjs b/tools/perf/wasix-node/plan.test.mjs deleted file mode 100644 index a2a137bf5..000000000 --- a/tools/perf/wasix-node/plan.test.mjs +++ /dev/null @@ -1,520 +0,0 @@ -import assert from 'node:assert/strict'; -import { createRequire } from 'node:module'; -import test from 'node:test'; - -import { installedPackageClosure } from './installed-closure.mjs'; -import { dispatchPgliteRequest } from './pglite-node-worker.mjs'; -import { - assertExpectedRawProtocolResponse, - assertNativeAddonContract, - assertNativeArtifactProvenance, - assertRuntimeBuildConfiguration, - assertSuccessfulRawProtocolResponse, - bulkSql, - comfortableWinGate, - defaultPlanFile, - expandExpectedResult, - expectedBulkProtocol, - geomean, - latencySummary, - loadPlan, - median, - metricIds, - pairedRatioSummary, - planSummary, - postgresSettingsParity, - simpleQueryMessage, - validatePlan, -} from './plan.mjs'; - -test('the checked-in plan pins identities, generated SQL, and the comfortable-win gate', async () => { - const source = await loadPlan(defaultPlanFile); - const summary = planSummary(source.plan, source); - - assert.equal(summary.schema, 'oliphaunt-wasix-node-benchmark-plan-v2'); - assert.equal(summary.id, 'node-pglite-memory-v2'); - assert.equal(summary.engines.candidate.package, '@oliphaunt/wasix-ts'); - assert.deepEqual(summary.engines.candidate.nativeAddon, { - schema: 'oliphaunt-wasix-napi-host-v1', - product: 'oliphaunt-wasix-napi', - binary: 'oliphaunt_wasix_napi.node', - addonAbiVersion: 1, - nodeApiVersion: 8, - profiles: ['standard', 'icu'], - build: { - cargoProfile: 'release', - incremental: false, - codegenUnits: 1, - lto: 'thin', - strip: 'symbols', - features: ['release'], - }, - }); - assert.deepEqual(summary.engines.candidate.runtimeBuild, { - profile: 'release', - cflags: '-O2 -g0 -flto=thin', - ldflags: '-flto=thin', - configureWasmOpt: 'no', - buildWasmOpt: 'yes', - wasmOptFlags: '--converge:--strip-debug:--strip-producers', - wasmOptSuppressDefault: '', - wasmOptPreserveUnoptimized: '', - compilerFlags: '', - linkerFlags: '', - }); - assert.deepEqual(summary.engines.candidate.surfaces.worker, { - engine: 'candidate-worker', - entrypoint: '@oliphaunt/wasix-ts/worker', - callingContract: 'async', - executionOwner: 'sdk-worker', - executionBoundary: 'node-worker-thread', - isolationImplementation: 'package-owned-worker-rpc', - timingBoundary: 'host-end-to-end-around-one-isolation-rpc', - }); - assert.deepEqual(summary.engines.candidate.surfaces.direct, { - engine: 'candidate-direct', - entrypoint: '@oliphaunt/wasix-ts/direct', - callingContract: 'async', - executionOwner: 'caller', - executionBoundary: 'node-caller-realm', - isolationImplementation: 'none-caller-realm', - timingBoundary: 'caller-around-public-api', - }); - assert.equal(summary.engines.comparison.package, '@electric-sql/pglite'); - assert.equal(summary.engines.comparison.version, '0.5.4'); - assert.equal(summary.engines.comparison.homepage, 'https://pglite.dev'); - assert.equal( - summary.engines.comparison.sourceRepository, - 'https://github.com/electric-sql/pglite', - ); - assert.equal(summary.gate.maxGeomeanRatio, 0.8); - assert.deepEqual(summary.gate.comparisons, ['worker', 'direct']); - assert.deepEqual(summary.engines.comparison.surfaces.callerRealm, { - engine: 'comparison-direct', - entrypoint: '@electric-sql/pglite', - callingContract: 'async', - executionOwner: 'caller', - executionBoundary: 'node-main-thread', - isolationImplementation: 'none-caller-realm', - timingBoundary: 'caller-around-public-api', - }); - assert.equal( - summary.engines.candidate.surfaces.worker.timingBoundary, - summary.engines.comparison.surfaces.worker.timingBoundary, - ); - assert.equal( - summary.engines.comparison.surfaces.worker.benchmarkMethodology, - 'official-browser-worker-timer-reference-only-not-collected', - ); - assert.equal( - summary.engines.comparison.surfaces.worker.gatedResponsePayload, - 'public-result-only-no-comparator-telemetry', - ); - assert.equal(summary.measurement.pairedRepeats, 10); - assert.equal(summary.measurement.pairing, 'same-repeat-candidate-over-comparison'); - assert.equal(summary.measurement.startupMetric, 'cold-to-first-result'); - assert.deepEqual(summary.measurement.startupMetricIncludes, [ - 'public-open', - 'immediate-first-query', - ]); - assert.equal(summary.bulkTransport.publicApi, 'execProtocolRaw'); - assert.equal(summary.bulkTransport.pgliteSyncToFs, false); - assert.equal(summary.postgres.expectedSettings.shared_buffers, '128MB'); - assert.equal(summary.postgres.expectedSettings.max_parallel_maintenance_workers, '0'); - assert.deepEqual(metricIds(source.plan), [ - 'cold-to-first-result', - 'warm-rtt/parameter-scalar/p50', - 'warm-rtt/indexed-lookup/p50', - 'warm-rtt/counter-update/p50', - 'bulk/insert-series/elapsed', - 'bulk/create-index/elapsed', - 'bulk/indexed-update/elapsed', - 'bulk/aggregate/elapsed', - ]); - assert.deepEqual( - summary.generatedSql.map(({ sha256 }) => sha256), - [ - 'b33b0aea9b7fd4d93bb499069dc768fe53810bfc3c0bd1b0a3cde8e23205ef2b', - '6d7e5592e5d4135a1a42f78d796b6d9c2ff40b9ba7e14edd4a11cdd4e8340ced', - 'a431224ba0bd421b74fc2a9437b2a4a505b5e6fb1aa9a897a829d1c05f4b3ba6', - 'e21d82bb79fff4535b3368a5933b003f540aa86926422f823e8de9f07f991536', - ], - ); - assert.ok(source.plan.bulk.every((entry) => Buffer.byteLength(bulkSql(entry)) < 512)); -}); - -test('the gated comparator worker returns public results without private timing telemetry', async () => { - const rawResponse = Uint8Array.of(1, 2, 3); - const calls = []; - const database = { - async query(sql, parameters) { - calls.push(['query', sql, parameters]); - return { fields: [{ name: 'answer' }], rows: [{ answer: 42 }] }; - }, - async exec(sql) { - calls.push(['execute', sql]); - }, - async execProtocolRaw(input, options) { - calls.push(['rawProtocol', [...input], options]); - return rawResponse; - }, - async close() { - calls.push(['close']); - }, - }; - - const query = await dispatchPgliteRequest(database, { - id: 1, - method: 'query', - args: ['SELECT $1', [42]], - }); - assert.deepEqual(query.result, { - result: { fields: [{ name: 'answer' }], rows: [{ answer: 42 }] }, - }); - assert.deepEqual(Object.keys(query.result), ['result']); - - const raw = await dispatchPgliteRequest(database, { - id: 2, - method: 'rawProtocol', - args: [Uint8Array.of(9), false], - }); - assert.deepEqual(raw.result, { response: rawResponse }); - assert.deepEqual(Object.keys(raw.result), ['response']); - assert.deepEqual(raw.transfer, [rawResponse.buffer]); - - const execute = await dispatchPgliteRequest(database, { - id: 3, - method: 'execute', - args: ['SELECT 1'], - }); - assert.deepEqual(execute.result, {}); - assert.equal( - JSON.stringify([query.result, raw.result, execute.result]).includes('Elapsed'), - false, - ); - assert.deepEqual(calls, [ - ['query', 'SELECT $1', [42]], - ['rawProtocol', [9], { syncToFs: false }], - ['execute', 'SELECT 1'], - ]); -}); - -test('the exact installed comparator tree matches the plan byte pin', async () => { - const { plan } = await loadPlan(defaultPlanFile); - const require = createRequire(import.meta.url); - const closure = await installedPackageClosure( - require.resolve(plan.engines.comparison.package), - plan.engines.comparison.package, - ); - const root = closure.packages.find((candidate) => candidate.id === closure.root); - assert.equal(closure.treeHashSchema, plan.engines.comparison.installedTreeHashSchema); - assert.equal(root.installedTreeSha256, plan.engines.comparison.installedTreeSha256); - assert.deepEqual(root.dependencies, []); -}); - -test('candidate native addon contract rejects ABI, profile, and optimization drift', async () => { - const { plan } = await loadPlan(defaultPlanFile, { repositoryBindings: false }); - assert.deepEqual( - assertNativeAddonContract( - plan.engines.candidate.nativeAddon, - plan.engines.candidate.nativeAddon, - ), - plan.engines.candidate.nativeAddon, - ); - const drifts = [ - ['addon ABI', (value) => (value.addonAbiVersion = 2), /addonAbiVersion/u], - ['Node-API floor', (value) => (value.nodeApiVersion = 9), /nodeApiVersion/u], - ['profiles', (value) => value.profiles.reverse(), /profiles/u], - ['Cargo profile', (value) => (value.build.cargoProfile = 'debug'), /cargoProfile/u], - ['incremental', (value) => (value.build.incremental = true), /incremental/u], - ['codegen units', (value) => (value.build.codegenUnits = 16), /codegenUnits/u], - ['LTO', (value) => (value.build.lto = false), /build\.lto/u], - ['features', (value) => value.build.features.push('icu'), /build\.features/u], - ]; - for (const [label, mutate, error] of drifts) { - const drifted = structuredClone(plan.engines.candidate.nativeAddon); - mutate(drifted); - assert.throws( - () => assertNativeAddonContract(drifted, plan.engines.candidate.nativeAddon), - error, - label, - ); - } -}); - -test('candidate native artifact provenance must match the benchmark commit and target', async () => { - const { plan } = await loadPlan(defaultPlanFile, { repositoryBindings: false }); - const artifactSourceSha = 'a'.repeat(40); - const target = 'linux-x64-gnu'; - const targetTriple = 'x86_64-unknown-linux-gnu'; - const carrier = { - name: '@oliphaunt/wasix-napi-linux-x64-gnu', - version: '0.0.0', - target, - artifactProvenanceMember: 'package/artifact-provenance.json', - manifest: { - oliphaunt: { - target, - addonAbiVersion: plan.engines.candidate.nativeAddon.addonAbiVersion, - nodeApiVersion: plan.engines.candidate.nativeAddon.nodeApiVersion, - profiles: plan.engines.candidate.nativeAddon.profiles, - }, - }, - artifactProvenance: { - schema: 'oliphaunt-wasix-napi-provenance-v1', - product: 'oliphaunt-wasix-napi', - target, - artifactSourceSha, - build: { ...plan.engines.candidate.nativeAddon.build, targetTriple }, - buildInputs: { - schema: 'oliphaunt-wasix-napi-build-inputs-v1', - target, - targetTriple, - }, - binary: { - filename: plan.engines.candidate.nativeAddon.binary, - sha256: 'b'.repeat(64), - }, - }, - }; - - assert.equal( - assertNativeArtifactProvenance(carrier, plan.engines.candidate.nativeAddon, artifactSourceSha) - .artifactProvenance, - carrier.artifactProvenance, - ); - assert.throws( - () => - assertNativeArtifactProvenance(carrier, plan.engines.candidate.nativeAddon, 'c'.repeat(40)), - /addon\/source contract/u, - ); - const wrongBuildTarget = structuredClone(carrier); - wrongBuildTarget.artifactProvenance.buildInputs.target = 'linux-arm64-gnu'; - assert.throws( - () => - assertNativeArtifactProvenance( - wrongBuildTarget, - plan.engines.candidate.nativeAddon, - artifactSourceSha, - ), - /addon\/source contract/u, - ); -}); - -test('plan validation rejects comparator drift and a weaker performance claim', async () => { - const { plan } = await loadPlan(defaultPlanFile, { repositoryBindings: false }); - - const versionDrift = structuredClone(plan); - versionDrift.engines.comparison.version = '^0.5.4'; - assert.throws(() => validatePlan(versionDrift), /expected "0\.5\.4"/u); - - const integrityDrift = structuredClone(plan); - integrityDrift.engines.comparison.integrity = `sha512-${'A'.repeat(88)}`; - assert.throws(() => validatePlan(integrityDrift), /comparison\.integrity/u); - - const weakerGate = structuredClone(plan); - weakerGate.gate.maxGeomeanRatio = 0.81; - assert.throws(() => validatePlan(weakerGate), /no greater than 0\.80/u); - - const tooFewSamples = structuredClone(plan); - tooFewSamples.measurement.sampleIterations = 19; - assert.throws(() => validatePlan(tooFewSamples), /integer of at least 20/u); - - const tooFewPairs = structuredClone(plan); - tooFewPairs.measurement.pairedRepeats = 8; - assert.throws(() => validatePlan(tooFewPairs), /integer of at least 9/u); - - const comparatorTelemetry = structuredClone(plan); - comparatorTelemetry.engines.comparison.surfaces.worker.gatedResponsePayload = - 'public-result-plus-internal-timing'; - assert.throws(() => validatePlan(comparatorTelemetry), /gatedResponsePayload/u); - - const workerEntrypointDrift = structuredClone(plan); - workerEntrypointDrift.engines.candidate.surfaces.worker.entrypoint = '@oliphaunt/wasix-ts'; - assert.throws(() => validatePlan(workerEntrypointDrift), /surfaces\.worker\.entrypoint/u); - - const directOwnerDrift = structuredClone(plan); - directOwnerDrift.engines.candidate.surfaces.direct.executionOwner = 'sdk-worker'; - assert.throws(() => validatePlan(directOwnerDrift), /surfaces\.direct\.executionOwner/u); - - const invalidGateLabel = structuredClone(plan); - invalidGateLabel.gate.comparisons[1] = 'inline'; - assert.throws(() => validatePlan(invalidGateLabel), /gate\.comparisons/u); - - const unbalancedPairs = structuredClone(plan); - unbalancedPairs.measurement.pairedRepeats = 9; - assert.throws(() => validatePlan(unbalancedPairs), /must be even/u); - - const optimizedOutsideThePlan = structuredClone(plan.engines.candidate.runtimeBuild); - optimizedOutsideThePlan.compilerFlags = '-O3'; - assert.throws( - () => - assertRuntimeBuildConfiguration(optimizedOutsideThePlan, plan.engines.candidate.runtimeBuild), - /compilerFlags/u, - ); - - const hostWithoutLto = structuredClone(plan); - hostWithoutLto.engines.candidate.nativeAddon.build.lto = 'off'; - assert.throws(() => validatePlan(hostWithoutLto), /nativeAddon\.build\.lto/u); -}); - -test('summary math and correctness placeholders are deterministic', () => { - assert.deepEqual(latencySummary([9, 1, 5, 3, 7], 0.2), { - samples: 5, - trimmedSamples: 3, - minMs: 1, - p50Ms: 5, - p90Ms: 9, - p95Ms: 9, - p99Ms: 9, - maxMs: 9, - trimmedMeanMs: 5, - }); - assert.equal(median([7, 1, 5, 3]), 4); - assert.deepEqual(pairedRatioSummary([6, 4, 10], [3, 8, 5]), { - pairedRatios: [2, 0.5, 2], - medianRatio: 2, - }); - assert.ok(Math.abs(geomean([0.5, 0.8]) - Math.sqrt(0.4)) < Number.EPSILON); - assert.equal(comfortableWinGate([0.8], 0.8, true).gate.passed, true); - assert.equal(comfortableWinGate([0.81], 0.8, true).gate.passed, false); - assert.equal(comfortableWinGate([0.5], 0.8, false).gate.passed, false); - assert.deepEqual( - expandExpectedResult( - { fields: ['counter'], rows: [['$totalIterations']] }, - { $totalIterations: 110 }, - ), - { fields: ['counter'], rows: [['110']] }, - ); - assert.deepEqual( - [...simpleQueryMessage('SELECT 1')], - [0x51, 0, 0, 0, 13, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0x20, 0x31, 0], - ); - assert.doesNotThrow(() => - assertSuccessfulRawProtocolResponse( - Uint8Array.from([ - 0x43, 0, 0, 0, 11, 0x53, 0x45, 0x4c, 0x45, 0x43, 0x54, 0, 0x5a, 0, 0, 0, 5, 0x49, - ]), - 'test response', - ), - ); - const createIndex = expectedBulkProtocol({ operation: { kind: 'create-payload-index' } }); - const readyOnly = protocolFrame(0x5a, Uint8Array.of(0x49)); - assert.throws( - () => assertExpectedRawProtocolResponse(readyOnly, createIndex, 'bulk create-index'), - /expected/u, - ); - const createIndexResponse = concatenate([ - protocolFrame(0x53, new TextEncoder().encode('in_hot_standby\0off\0')), - protocolFrame(0x43, new TextEncoder().encode('CREATE INDEX\0')), - protocolFrame(0x4e, new TextEncoder().encode('SNOTICE\0Mvalidated notice\0\0')), - readyOnly, - ]); - assert.deepEqual( - assertExpectedRawProtocolResponse(createIndexResponse, createIndex, 'bulk create-index'), - createIndex, - ); - assert.throws( - () => - assertExpectedRawProtocolResponse( - concatenate([ - protocolFrame(0x53, new TextEncoder().encode('in_hot_standby\0off')), - protocolFrame(0x43, new TextEncoder().encode('CREATE INDEX\0')), - readyOnly, - ]), - createIndex, - 'malformed parameter status', - ), - /ParameterStatus value is missing its NUL terminator/u, - ); - const aggregate = { - commandTags: ['SELECT 1'], - results: [{ fields: ['answer'], rows: [['42']] }], - transactionStatus: 'idle', - }; - const aggregateResponse = concatenate([ - protocolFrame(0x54, rowDescription(['answer'])), - protocolFrame(0x44, dataRow(['42'])), - protocolFrame(0x43, new TextEncoder().encode('SELECT 1\0')), - readyOnly, - ]); - assert.deepEqual( - assertExpectedRawProtocolResponse(aggregateResponse, aggregate, 'bulk aggregate'), - aggregate, - ); - - const settingNames = ['fsync', 'shared_buffers']; - const reports = [ - reportSettings('candidate', 0, { fsync: 'off', shared_buffers: '128MB' }), - reportSettings('comparison', 0, { fsync: 'off', shared_buffers: '128MB' }), - ]; - assert.equal(postgresSettingsParity(reports, settingNames).passed, true); - assert.equal( - postgresSettingsParity(reports, settingNames, { - fsync: 'off', - shared_buffers: '128MB', - }).passed, - true, - ); - assert.equal( - postgresSettingsParity(reports, settingNames, { - fsync: 'on', - shared_buffers: '128MB', - }).passed, - false, - ); - reports[1].postgres.settings.fsync = 'on'; - assert.equal(postgresSettingsParity(reports, settingNames).passed, false); -}); - -function protocolFrame(tag, body) { - const frame = new Uint8Array(body.length + 5); - frame[0] = tag; - new DataView(frame.buffer).setUint32(1, body.length + 4); - frame.set(body, 5); - return frame; -} - -function concatenate(chunks) { - const output = new Uint8Array(chunks.reduce((size, chunk) => size + chunk.length, 0)); - let offset = 0; - for (const chunk of chunks) { - output.set(chunk, offset); - offset += chunk.length; - } - return output; -} - -function rowDescription(fields) { - const encoder = new TextEncoder(); - const names = fields.map((field) => encoder.encode(`${field}\0`)); - const body = new Uint8Array(2 + names.reduce((size, name) => size + name.length + 18, 0)); - const view = new DataView(body.buffer); - view.setUint16(0, fields.length); - let offset = 2; - for (const name of names) { - body.set(name, offset); - offset += name.length + 18; - } - return body; -} - -function dataRow(values) { - const encoder = new TextEncoder(); - const encoded = values.map((value) => encoder.encode(value)); - const body = new Uint8Array(2 + encoded.reduce((size, value) => size + 4 + value.length, 0)); - const view = new DataView(body.buffer); - view.setUint16(0, values.length); - let offset = 2; - for (const value of encoded) { - view.setInt32(offset, value.length); - offset += 4; - body.set(value, offset); - offset += value.length; - } - return body; -} - -function reportSettings(kind, repeat, settings) { - return { engine: { kind }, repeat, postgres: { settings } }; -} diff --git a/tools/perf/wasix-node/rss-sampler-worker.mjs b/tools/perf/wasix-node/rss-sampler-worker.mjs deleted file mode 100644 index 3fd7f0e92..000000000 --- a/tools/perf/wasix-node/rss-sampler-worker.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import { workerData } from 'node:worker_threads'; - -const peakRssKiB = new Int32Array(workerData); - -sample(); -setInterval(sample, 2); - -function sample() { - const rssKiB = Math.ceil(process.memoryUsage.rss() / 1024); - let current = Atomics.load(peakRssKiB, 0); - while (rssKiB > current) { - const observed = Atomics.compareExchange(peakRssKiB, 0, current, rssKiB); - if (observed === current) return; - current = observed; - } -} diff --git a/tools/perf/wasix-node/streaming-quick.mjs b/tools/perf/wasix-node/streaming-quick.mjs deleted file mode 100644 index 53c925e5e..000000000 --- a/tools/perf/wasix-node/streaming-quick.mjs +++ /dev/null @@ -1,762 +0,0 @@ -import { execFile } from 'node:child_process'; -import { access, mkdtemp, rm } from 'node:fs/promises'; -import { createRequire } from 'node:module'; -import { cpus, platform, release, tmpdir } from 'node:os'; -import { dirname, resolve } from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; -import { promisify } from 'node:util'; -import { Worker } from 'node:worker_threads'; - -import { createPackedWasixConsumer } from '../../integration/wasix-ts/packed-node-fixture.mjs'; -import { - connect, - onceClosed, - onceConnected, - readExchange, - simpleQuery, - startupPacket, -} from '../../../src/bindings/wasix-ts/tools/pgwire-client.mjs'; - -const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..'); -const execFileAsync = promisify(execFile); -const benchmarkOptions = parseArguments(process.argv.slice(2)); -const roundTripWarmups = 10; -const roundTripSamples = benchmarkOptions.full ? 200 : 100; -const bulkSizesMiB = benchmarkOptions.full ? [1 / 1024, 1, 64] : [1 / 1024, 1, 4]; -const inputSizesMiB = benchmarkOptions.full ? [1 / 1024, 1, 64] : [1 / 1024, 1, 4]; -const activeDatabaseCounts = benchmarkOptions.full ? [1, 4, 16] : [1, 4]; -const overloadConcurrency = benchmarkOptions.full ? 16 : 4; -const overloadInputMiB = benchmarkOptions.full ? 4 : 1; -const slowConsumerDelayMs = 1; -const toolRows = 4_096; -const started = performance.now(); - -await requireInputs(); -const scratch = await mkdtemp(resolve(tmpdir(), 'oliphaunt-wasix-streaming-quick-')); -const rssSampler = await openRssSampler().catch(async (error) => { - await rm(scratch, { force: true, recursive: true }); - throw error; -}); - -try { - const fixture = await createBenchmarkFixture({ - scratch, - consumerName: 'oliphaunt-wasix-streaming-quick-consumer', - includeTools: true, - }); - const provenance = await benchmarkProvenance(fixture.packages); - const fixtureRequire = createRequire(resolve(fixture.consumer, 'package.json')); - const bindingName = fixture.packages.binding.name; - const { default: ActorOliphaunt } = await importPackedEntrypoint( - fixtureRequire, - bindingName, - '/lib/index.node.js', - ); - const { default: DirectOliphaunt } = await importPackedEntrypoint( - fixtureRequire, - `${bindingName}/direct`, - '/lib/direct.node.js', - ); - const { default: WorkerOliphaunt } = await importPackedEntrypoint( - fixtureRequire, - `${bindingName}/worker`, - '/lib/worker-entry.node.js', - ); - const { openServer } = await importPackedEntrypoint( - fixtureRequire, - `${bindingName}/server`, - '/lib/server.node.js', - ); - const { pgDump, psql } = await importPackedEntrypoint( - fixtureRequire, - fixture.packages.toolsFacade.name, - '/lib/index.js', - ); - - const surfaces = { - actor: await benchmarkSurface(ActorOliphaunt, 'actor'), - direct: await benchmarkSurface(DirectOliphaunt, 'direct'), - worker: await benchmarkSurface(WorkerOliphaunt, 'worker'), - }; - const server = await benchmarkServer(openServer); - const tools = await benchmarkTools(ActorOliphaunt, pgDump, psql); - const fanout = await benchmarkDatabaseFanout(ActorOliphaunt); - const overload = await benchmarkActorOverload(ActorOliphaunt); - const report = { - schema: 'oliphaunt-wasix-placement-quick-v3', - measuredAt: new Date().toISOString(), - durationMs: rounded(performance.now() - started), - provenance, - environment: { - node: process.version, - platform: `${platform()} ${release()}`, - cpu: cpus()[0]?.model ?? 'unknown', - logicalCpus: cpus().length, - }, - configuration: { - roundTripWarmups, - roundTripSamples, - bulkSizesMiB, - inputSizesMiB, - activeDatabaseCounts, - overloadConcurrency, - overloadInputMiB, - slowConsumerDelayMs, - toolRows, - storage: 'memory', - executionSurfaces: { - actor: { - entrypoint: '@oliphaunt/wasix-ts', - callingContract: 'async', - executionOwner: 'rust-owner-thread', - }, - direct: { - entrypoint: '@oliphaunt/wasix-ts/direct', - callingContract: 'async', - executionOwner: 'caller', - }, - worker: { - entrypoint: '@oliphaunt/wasix-ts/worker', - callingContract: 'async', - executionOwner: 'sdk-worker', - }, - }, - resourceSamples: `representative ${bulkSizesMiB.at(-1)} MiB streams, data dump, and restore`, - surfaceOrder: ['actor', 'direct', 'worker'], - openCloseNote: - 'single sequential observations are descriptive and must not be used for placement comparisons', - resourceNote: - 'RSS is process-wide growth from each scenario start; retained allocations can reduce later deltas', - }, - surfaces, - comparison: compareSurfaces(surfaces), - server, - tools, - fanout, - overload, - }; - - if (benchmarkOptions.json) console.log(JSON.stringify(report, null, 2)); - else printReport(report); -} finally { - await Promise.all([ - rm(scratch, { force: true, recursive: true }), - rssSampler.terminate().then(() => undefined), - ]); -} - -async function createBenchmarkFixture(options) { - try { - return await createPackedWasixConsumer(options); - } catch (cause) { - const detail = cause instanceof Error ? cause.message : String(cause); - if ( - /native carrier|Node-API carrier|native artifact provenance|oliphaunt_wasix_napi|wasix-napi-/iu.test( - detail, - ) - ) { - throw new Error( - 'WASIX placement benchmark requires one optimized current-host Node-API carrier. ' + - 'After staging the portable/AOT runtime, ICU, and extension inputs, run ' + - '`bash src/runtimes/wasix-napi/tools/build-native.sh`, then retry. ' + - `Carrier preflight: ${detail}`, - { cause }, - ); - } - throw cause; - } -} - -async function importPackedEntrypoint(fixtureRequire, specifier, expectedSuffix) { - const entry = fixtureRequire.resolve(specifier); - if (!entry.split('\\').join('/').endsWith(expectedSuffix)) { - throw new Error( - `${specifier} resolved ${entry}, expected packed entrypoint ${expectedSuffix.slice(1)}`, - ); - } - return import(pathToFileURL(entry).href); -} - -async function benchmarkSurface(Oliphaunt, surface) { - const opening = await timed(() => Oliphaunt.open()); - const database = opening.value; - try { - const query = await samples(async () => { - const result = await database.query('SELECT 1::int AS value'); - if (result.rows[0]?.value !== 1) throw new Error('query benchmark returned wrong value'); - }); - const request = simpleQuery('SELECT 1'); - const expected = await database.execProtocolRaw(request); - const rawBuffered = await samples(async () => { - const response = await database.execProtocolRaw(request); - if (response.length !== expected.length) throw new Error('buffered protocol size changed'); - }); - const rawStreamed = await samples(async () => { - let bytes = 0; - await database.execProtocolRawStream(request, (chunk) => { - bytes += chunk.length; - }); - if (bytes !== expected.length) throw new Error('streamed protocol size changed'); - }); - const largeInput = []; - for (const sizeMiB of inputSizesMiB) { - const input = simpleQuery(largeInputQuery(sizeMiB)); - const measured = await resourceTimed(() => database.execProtocolRaw(input)); - if (measured.value.length === 0) throw new Error(`${surface} large input returned no bytes`); - largeInput.push({ - sizeMiB, - requestBytes: input.length, - responseBytes: measured.value.length, - elapsedMs: rounded(measured.ms), - resources: measured.resources, - }); - } - - await consumeStream(database, copyQuery(0.25)); - const bulk = []; - for (const sizeMiB of bulkSizesMiB) { - const input = simpleQuery(copyQuery(sizeMiB)); - const expectedCopyBytes = sizeMiB * 1024 * 1024; - const buffered = await timed(() => database.execProtocolRaw(input)); - if (buffered.value.length < expectedCopyBytes) { - throw new Error(`${surface} buffered COPY response was truncated`); - } - const streamed = - sizeMiB === bulkSizesMiB.at(-1) - ? await resourceTimed(() => consumeStream(database, input)) - : await timed(() => consumeStream(database, input)); - if (streamed.value.bytes !== buffered.value.length) { - throw new Error(`${surface} streamed COPY response differed from buffered response`); - } - bulk.push({ - sizeMiB, - buffered: transferResult(buffered.value.length, buffered.ms), - streamed: { - ...transferResult(streamed.value.bytes, streamed.ms), - chunks: streamed.value.chunks, - ...('resources' in streamed ? { resources: streamed.resources } : {}), - }, - }); - } - - let slowConsumer; - if (surface !== 'direct') { - const input = simpleQuery(copyQuery(1)); - const sleeper = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)); - const measured = await timed(async () => { - let bytes = 0; - let chunks = 0; - await database.execProtocolRawStream(input, (chunk) => { - bytes += chunk.length; - chunks += 1; - Atomics.wait(sleeper, 0, 0, slowConsumerDelayMs); - }); - return { bytes, chunks }; - }); - slowConsumer = { - delayPerChunkMs: slowConsumerDelayMs, - chunks: measured.value.chunks, - bytes: measured.value.bytes, - elapsedMs: rounded(measured.ms), - requestedDelayMs: rounded(measured.value.chunks * slowConsumerDelayMs), - }; - } - - const closing = await timed(() => database.close()); - return { - openMs: rounded(opening.ms), - closeMs: rounded(closing.ms), - smallRoundTripMs: { query, rawBuffered, rawStreamed }, - largeInput, - bulk, - ...(slowConsumer === undefined ? {} : { slowConsumer }), - }; - } catch (error) { - await database.close().catch(() => undefined); - throw error; - } -} - -async function benchmarkServer(openServer) { - const opening = await timed(() => openServer({ listen: { transport: 'tcp' } })); - const server = opening.value; - const socket = connect(server.connectionString); - try { - const startup = await timed(async () => { - await onceConnected(socket); - const response = readExchange(socket); - socket.write(startupPacket('postgres', 'postgres')); - await response; - }); - const roundTrip = await samples(async () => { - const response = readExchange(socket); - socket.write(simpleQuery('SELECT 1')); - await response; - }); - const bulk = []; - for (const sizeMiB of bulkSizesMiB) { - const response = readExchange(socket); - const measured = - sizeMiB === bulkSizesMiB.at(-1) - ? await resourceTimed(async () => { - socket.write(simpleQuery(copyQuery(sizeMiB))); - return response; - }) - : await timed(async () => { - socket.write(simpleQuery(copyQuery(sizeMiB))); - return response; - }); - const expected = sizeMiB * 1024 * 1024; - if (measured.value.copyBytes !== expected) { - throw new Error( - `server COPY returned ${measured.value.copyBytes} bytes, expected ${expected}`, - ); - } - bulk.push({ - sizeMiB, - ...transferResult(measured.value.totalBytes, measured.ms), - copyBytes: measured.value.copyBytes, - messages: measured.value.messages, - ...('resources' in measured ? { resources: measured.resources } : {}), - }); - } - socket.end(Uint8Array.of('X'.charCodeAt(0), 0, 0, 0, 4)); - await onceClosed(socket); - const closing = await timed(() => server.close()); - return { - openMs: rounded(opening.ms), - connectAndStartupMs: rounded(startup.ms), - closeMs: rounded(closing.ms), - smallRoundTripMs: roundTrip, - bulk, - }; - } catch (error) { - socket.destroy(); - await server.close().catch(() => undefined); - throw error; - } -} - -async function benchmarkTools(Oliphaunt, pgDump, psql) { - const source = await Oliphaunt.open(); - let dump; - try { - await source.execute( - `CREATE TABLE quick_tool_data AS - SELECT i::int AS id, repeat(md5(i::text), 8) AS payload - FROM generate_series(1, ${toolRows}) AS values(i)`, - ); - await source.execute('ALTER TABLE quick_tool_data ADD PRIMARY KEY (id)'); - const psqlCommand = await timed(() => psql(source, { command: 'SELECT 1' })); - const schemaDump = await timed(() => pgDump(source, { args: ['--schema-only'] })); - const dataDump = await resourceTimed(() => pgDump(source)); - dump = dataDump.value; - if (!dump.includes('COPY public.quick_tool_data')) { - throw new Error('tool benchmark pg_dump did not use standard COPY output'); - } - return { - psqlCommandMs: rounded(psqlCommand.ms), - schemaDump: textResult(schemaDump.value, schemaDump.ms), - dataDump: { ...textResult(dataDump.value, dataDump.ms), resources: dataDump.resources }, - restore: await benchmarkRestore(Oliphaunt, psql, dump), - }; - } finally { - await source.close(); - } -} - -async function benchmarkDatabaseFanout(Oliphaunt) { - const results = []; - for (const count of activeDatabaseCounts) { - const measured = await resourceTimed(async () => { - const databases = []; - try { - for (let index = 0; index < count; index += 1) { - databases.push(await Oliphaunt.open()); - } - await Promise.all( - databases.map(async (database) => { - const result = await database.query('SELECT 1::int AS value'); - if (result.rows[0]?.value !== 1) - throw new Error('fanout database returned wrong value'); - }), - ); - } finally { - await Promise.all(databases.map((database) => database.close().catch(() => undefined))); - } - }); - results.push({ count, elapsedMs: rounded(measured.ms), resources: measured.resources }); - } - return results; -} - -async function benchmarkActorOverload(Oliphaunt) { - const database = await Oliphaunt.open(); - try { - const input = simpleQuery(largeInputQuery(overloadInputMiB)); - const measured = await resourceTimed(async () => { - const responses = await Promise.all( - Array.from({ length: overloadConcurrency }, () => database.execProtocolRaw(input)), - ); - if (responses.some((response) => response.length === 0)) { - throw new Error('actor overload request returned an empty response'); - } - return responses.reduce((sum, response) => sum + response.length, 0); - }); - return { - concurrency: overloadConcurrency, - inputBytesPerCall: input.length, - queuedInputMiB: rounded((input.length * overloadConcurrency) / (1024 * 1024)), - responseBytes: measured.value, - elapsedMs: rounded(measured.ms), - resources: measured.resources, - }; - } finally { - await database.close(); - } -} - -async function benchmarkRestore(Oliphaunt, psql, dump) { - const target = await Oliphaunt.open(); - try { - const restored = await resourceTimed(() => psql(target, { script: dump })); - const rows = Number( - (await target.query('SELECT count(*)::int AS rows FROM quick_tool_data')).rows[0]?.rows, - ); - if (rows !== toolRows) throw new Error(`psql restored ${rows} rows, expected ${toolRows}`); - return { elapsedMs: rounded(restored.ms), rows, resources: restored.resources }; - } finally { - await target.close(); - } -} - -async function samples(operation) { - for (let index = 0; index < roundTripWarmups; index += 1) await operation(); - const values = []; - for (let index = 0; index < roundTripSamples; index += 1) { - values.push((await timed(operation)).ms); - } - values.sort((left, right) => left - right); - return { - median: rounded(percentile(values, 0.5)), - p95: rounded(percentile(values, 0.95)), - p99: rounded(percentile(values, 0.99)), - min: rounded(values[0]), - max: rounded(values.at(-1)), - }; -} - -async function timed(operation) { - const start = performance.now(); - const value = await operation(); - return { value, ms: performance.now() - start }; -} - -async function resourceTimed(operation) { - const intervalMs = 2; - let next = performance.now() + intervalMs; - let maxEventLoopDelayMs = 0; - const timer = setInterval(() => { - const now = performance.now(); - maxEventLoopDelayMs = Math.max(maxEventLoopDelayMs, now - next); - next = now + intervalMs; - }, intervalMs); - await delay(intervalMs * 2); - maxEventLoopDelayMs = 0; - next = performance.now() + intervalMs; - const rssStartBytes = process.memoryUsage.rss(); - rssSampler.reset(rssStartBytes); - try { - const measured = await timed(operation); - await delay(intervalMs * 2); - const peakRssBytes = rssSampler.peakBytes(); - return { - ...measured, - resources: { - maxEventLoopDelayMs: rounded(maxEventLoopDelayMs), - rssStartMiB: rounded(rssStartBytes / (1024 * 1024)), - peakRssMiB: rounded(peakRssBytes / (1024 * 1024)), - rssGrowthMiB: rounded(Math.max(0, peakRssBytes - rssStartBytes) / (1024 * 1024)), - }, - }; - } finally { - clearInterval(timer); - } -} - -function delay(milliseconds) { - return new Promise((resolveDelay) => setTimeout(resolveDelay, milliseconds)); -} - -async function consumeStream(database, input) { - const request = typeof input === 'string' ? simpleQuery(input) : input; - let bytes = 0; - let chunks = 0; - await database.execProtocolRawStream(request, (chunk) => { - bytes += chunk.length; - chunks += 1; - }); - return { bytes, chunks }; -} - -function copyQuery(sizeMiB) { - const rows = Math.max(1, Math.round(sizeMiB * 1024)); - return `COPY (SELECT repeat('x', 1023) FROM generate_series(1, ${rows})) TO STDOUT`; -} - -function largeInputQuery(sizeMiB) { - const bytes = Math.max(1, Math.round(sizeMiB * 1024 * 1024)); - return `SELECT 1 /*${'x'.repeat(bytes)}*/`; -} - -function transferResult(bytes, milliseconds) { - return { - bytes, - elapsedMs: rounded(milliseconds), - mebibytesPerSecond: rounded(bytes / (1024 * 1024) / (milliseconds / 1000)), - }; -} - -function textResult(value, milliseconds) { - return { - bytes: Buffer.byteLength(value), - elapsedMs: rounded(milliseconds), - }; -} - -function compareSurfaces(surfaces) { - const direct = surfaces.direct.smallRoundTripMs; - return Object.fromEntries( - ['query', 'rawBuffered', 'rawStreamed'].map((name) => [ - name, - Object.fromEntries( - ['actor', 'worker'].map((surface) => [ - surface, - { - minusDirectMedianMs: rounded( - surfaces[surface].smallRoundTripMs[name].median - direct[name].median, - ), - toDirectMedianRatio: rounded( - surfaces[surface].smallRoundTripMs[name].median / direct[name].median, - ), - }, - ]), - ), - ]), - ); -} - -function percentile(sorted, fraction) { - return sorted[Math.max(0, Math.ceil(sorted.length * fraction) - 1)]; -} - -function rounded(value) { - if (!Number.isFinite(value)) throw new Error(`benchmark produced non-finite value ${value}`); - return Number(value.toFixed(3)); -} - -async function benchmarkProvenance(packages) { - const artifact = packages.nativeCarrier?.artifactProvenance; - if (artifact === undefined) throw new Error('placement benchmark has no native carrier metadata'); - const { stdout } = await execFileAsync('git', ['rev-parse', 'HEAD'], { - cwd: repositoryRoot, - }); - const sourceSha = stdout.trim(); - if (artifact.artifactSourceSha !== sourceSha) { - throw new Error( - `placement benchmark native carrier source is ${artifact.artifactSourceSha}, expected current HEAD ${sourceSha}; ` + - 'rebuild it with `bash src/runtimes/wasix-napi/tools/build-native.sh`', - ); - } - return { - binding: { - package: packages.binding.name, - version: packages.binding.version, - archiveSha256: packages.binding.sha256, - }, - runtime: { - package: packages.runtime.name, - version: packages.runtime.version, - archiveSha256: packages.runtime.sha256, - buildProfileSha256: packages.runtime.build?.buildProfile?.sha256, - }, - nativeCarrier: { - package: packages.nativeCarrier.name, - version: packages.nativeCarrier.version, - target: packages.nativeCarrier.target, - archiveSha256: packages.nativeCarrier.sha256, - binarySha256: artifact.binary.sha256, - artifactSourceSha: artifact.artifactSourceSha, - build: artifact.build, - }, - }; -} - -function printReport(report) { - console.log(`WASIX streaming quick benchmark (${(report.durationMs / 1000).toFixed(1)}s)`); - console.log(`Node ${report.environment.node} · ${report.environment.cpu}`); - console.log( - `${report.provenance.nativeCarrier.package} (${report.provenance.nativeCarrier.target}, ` + - `${report.provenance.nativeCarrier.binarySha256.slice(0, 12)}, source ` + - `${report.provenance.nativeCarrier.artifactSourceSha.slice(0, 12)})`, - ); - console.log('\nSmall round-trip latency (median / p95 / p99 ms)'); - console.log('scenario direct actor worker'); - for (const [label, name] of [ - ['query()', 'query'], - ['raw buffered', 'rawBuffered'], - ['raw streamed', 'rawStreamed'], - ]) { - const direct = report.surfaces.direct.smallRoundTripMs[name]; - const actor = report.surfaces.actor.smallRoundTripMs[name]; - const worker = report.surfaces.worker.smallRoundTripMs[name]; - console.log( - `${label.padEnd(20)} ${formatPair(direct).padEnd(23)} ${formatPair(actor).padEnd(23)} ${formatPair(worker)}`, - ); - console.log( - `${''.padEnd(20)} actor ${formatDeltaMs(report.comparison[name].actor.minusDirectMedianMs)} (${report.comparison[name].actor.toDirectMedianRatio.toFixed(2)}x), ` + - `worker ${formatDeltaMs(report.comparison[name].worker.minusDirectMedianMs)} (${report.comparison[name].worker.toDirectMedianRatio.toFixed(2)}x)`, - ); - } - console.log('\nBulk protocol transfer (MiB/s; elapsed ms)'); - for (const surface of ['direct', 'actor', 'worker']) { - for (const row of report.surfaces[surface].bulk) { - console.log( - `${surface.padEnd(8)} ${String(row.sizeMiB).padStart(2)} MiB buffered ${formatTransfer(row.buffered)} streamed ${formatTransfer(row.streamed)} (${row.streamed.chunks} chunks)`, - ); - } - } - for (const surface of ['actor', 'worker']) { - const slow = report.surfaces[surface].slowConsumer; - console.log( - `\n${surface} slow consumer: ${slow.chunks} chunks × ${slow.delayPerChunkMs} ms requested; ` + - `${slow.elapsedMs.toFixed(3)} ms total`, - ); - } - console.log( - `Server: open ${formatMs(report.server.openMs)}, startup ${formatMs(report.server.connectAndStartupMs)}, ` + - `query ${formatPair(report.server.smallRoundTripMs)}`, - ); - console.log('Actor database fanout (count / elapsed / peak RSS growth)'); - for (const row of report.fanout) { - console.log( - `${String(row.count).padStart(2)} databases ${formatMs(row.elapsedMs).padEnd(12)} ${row.resources.rssGrowthMiB.toFixed(1)} MiB`, - ); - } - console.log( - `Actor overload: ${report.overload.concurrency} × ${formatBytes(report.overload.inputBytesPerCall)} input, ` + - `${formatMs(report.overload.elapsedMs)}, ${report.overload.resources.rssGrowthMiB.toFixed(1)} MiB RSS growth`, - ); - for (const row of report.server.bulk) { - console.log(`Server ${row.sizeMiB} MiB COPY: ${formatTransfer(row)}`); - } - console.log( - `Tools: psql command ${formatMs(report.tools.psqlCommandMs)}, ` + - `schema dump ${formatMs(report.tools.schemaDump.elapsedMs)}, ` + - `data dump ${formatMs(report.tools.dataDump.elapsedMs)} (${formatBytes(report.tools.dataDump.bytes)}), ` + - `restore ${formatMs(report.tools.restore.elapsedMs)}`, - ); - console.log('\nRepresentative event-loop delay / process RSS growth'); - const representativeBulkSize = report.configuration.bulkSizesMiB.at(-1); - for (const [label, resources] of [ - [ - `direct ${representativeBulkSize} MiB stream`, - report.surfaces.direct.bulk.at(-1).streamed.resources, - ], - [ - `actor ${representativeBulkSize} MiB stream`, - report.surfaces.actor.bulk.at(-1).streamed.resources, - ], - [ - `worker ${representativeBulkSize} MiB stream`, - report.surfaces.worker.bulk.at(-1).streamed.resources, - ], - [`server ${representativeBulkSize} MiB COPY`, report.server.bulk.at(-1).resources], - ['pg_dump data', report.tools.dataDump.resources], - ['psql restore', report.tools.restore.resources], - ]) { - console.log( - `${label.padEnd(22)} ${formatMs(resources.maxEventLoopDelayMs).padEnd(12)} ` + - `${resources.rssGrowthMiB.toFixed(1)} MiB`, - ); - } - console.log('RSS growth is descriptive; earlier scenarios can retain allocations.'); - console.log('\nUse --json for the complete machine-readable report.'); -} - -function formatPair(value) { - return `${value.median.toFixed(3)} / ${value.p95.toFixed(3)} / ${value.p99.toFixed(3)}`; -} - -function formatTransfer(value) { - return `${value.mebibytesPerSecond.toFixed(1)} MiB/s; ${value.elapsedMs.toFixed(1)} ms`; -} - -function formatMs(value) { - return `${value.toFixed(3)} ms`; -} - -function formatDeltaMs(value) { - return `${value >= 0 ? '+' : ''}${formatMs(value)}`; -} - -function formatBytes(value) { - return `${(value / (1024 * 1024)).toFixed(2)} MiB`; -} - -function parseArguments(args) { - const options = { json: false, full: false }; - for (const argument of args) { - if (argument === '--json') options.json = true; - else if (argument === '--full') options.full = true; - else { - throw new Error('usage: node tools/perf/wasix-node/streaming-quick.mjs [--json] [--full]'); - } - } - return options; -} - -async function requireInputs() { - const required = [ - 'src/bindings/wasix-ts/lib/index.node.js', - 'src/bindings/wasix-ts/lib/direct.node.js', - 'src/bindings/wasix-ts/lib/worker-entry.node.js', - 'src/bindings/wasix-ts/lib/host/index.mjs', - 'src/bindings/wasix-ts/tools-package/lib/index.js', - 'target/oliphaunt-wasix/assets/manifest.json', - 'target/oliphaunt-wasix/assets/bin/pg_dump.wasix.wasm', - 'target/oliphaunt-wasix/assets/bin/psql.wasix.wasm', - ]; - try { - await Promise.all(required.map((path) => access(resolve(repositoryRoot, path)))); - } catch (cause) { - throw new Error( - 'quick WASIX streaming benchmark needs staged TypeScript packages and portable runtime assets; ' + - 'run `moon run oliphaunt-wasix-ts:package liboliphaunt-wasix:runtime-portable` first', - { cause }, - ); - } -} - -async function openRssSampler() { - const peak = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)); - const worker = new Worker(new URL('./rss-sampler-worker.mjs', import.meta.url), { - name: 'oliphaunt-wasix-quick-rss-sampler', - workerData: peak.buffer, - }); - await new Promise((resolveOnline, rejectOnline) => { - worker.once('online', resolveOnline); - worker.once('error', rejectOnline); - }); - return { - reset(bytes) { - Atomics.store(peak, 0, Math.ceil(bytes / 1024)); - }, - peakBytes() { - return Atomics.load(peak, 0) * 1024; - }, - terminate() { - return worker.terminate(); - }, - }; -} diff --git a/tools/policy/assertions/repository-semantics.mjs b/tools/policy/assertions/repository-semantics.mjs deleted file mode 100644 index 8f9a2a4c5..000000000 --- a/tools/policy/assertions/repository-semantics.mjs +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env bun - -import { existsSync, readFileSync } from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../../dev/capture-command-output.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../../.."); - -function assert(condition, message) { - if (!condition) throw new Error(`repository-semantics.mjs: ${message}`); -} - -function object(value, label) { - assert(value !== null && typeof value === "object" && !Array.isArray(value), `${label} must be an object`); - return value; -} - -function stableVersion(value, label) { - assert(typeof value === "string" && /^\d+[.]\d+[.]\d+$/u.test(value), `${label} must pin x.y.z`); - return value.split(".").map((part) => Number.parseInt(part, 10)); -} - -function versionSatisfiesNodeBand(version, range) { - const [major, minor] = stableVersion(version, ".prototools node"); - const match = /^>=([0-9]+)[.]([0-9]+) <([0-9]+)$/u.exec(range); - if (match === null) return false; - const lowerMajor = Number.parseInt(match[1], 10); - const lowerMinor = Number.parseInt(match[2], 10); - const upperMajor = Number.parseInt(match[3], 10); - return (major > lowerMajor || (major === lowerMajor && minor >= lowerMinor)) && major < upperMajor; -} - -function readToml(file) { - return Bun.TOML.parse(readFileSync(path.join(ROOT, file), "utf8")); -} - -function readJson(file) { - return JSON.parse(readFileSync(path.join(ROOT, file), "utf8")); -} - -function trackedFiles() { - const result = captureCommandOutput("git", ["ls-files", "-z"], { - allowEmptyOutput: true, - cwd: ROOT, - label: "git ls-files", - stdoutTerminator: "\0", - }); - if (result.error !== undefined || result.status !== 0) { - throw new Error(result.error?.message ?? result.stderr.trim()); - } - return result.stdout.split("\0").filter(Boolean); -} - -function main() { - assert(Bun.argv.length === 3 && Bun.argv[2] === "tooling", "usage: repository-semantics.mjs tooling"); - - const pins = object(readToml(".prototools"), ".prototools"); - const packageJson = object(readJson("package.json"), "package.json"); - const pnpm = object(Bun.YAML.parse(readFileSync(path.join(ROOT, "pnpm-workspace.yaml"), "utf8")), "pnpm-workspace.yaml"); - - assert(packageJson.packageManager === `pnpm@${pins.pnpm}`, "packageManager must match the pinned pnpm version"); - assert(packageJson.engines?.pnpm === pins.pnpm, "engines.pnpm must match the pinned pnpm version"); - assert(versionSatisfiesNodeBand(pins.node, packageJson.engines?.node), "the pinned Node version must satisfy engines.node"); - assert(pnpm.minimumReleaseAge >= 1440, "dependencies must age for at least one day before installation"); - assert(pnpm.nodeLinker === "isolated", "workspace dependencies must use isolated linking"); - for (const [dependency, allowed] of Object.entries(object(pnpm.allowBuilds, "pnpm allowBuilds"))) { - assert(typeof allowed === "boolean", `pnpm allowBuilds.${dependency} must be explicit`); - } - - const unsafeRootFallback = /git\s+rev-parse\s+--show-toplevel[^\n]*(?:\|\||or)\s+pwd/u; - const unsafe = trackedFiles().filter((file) => { - if (!/(?:[.]sh|[.]mjs|[.]js|[.]py)$/u.test(file)) return false; - const absolute = path.join(ROOT, file); - return existsSync(absolute) && unsafeRootFallback.test(readFileSync(absolute, "utf8")); - }); - assert(unsafe.length === 0, `entrypoints must fail closed outside a checkout: ${unsafe.join(", ")}`); - - console.log("tooling safety checks passed"); -} - -try { - main(); -} catch (error) { - console.error(error.message ?? String(error)); - process.exit(1); -} diff --git a/tools/policy/assertions/workflow-security.mjs b/tools/policy/assertions/workflow-security.mjs deleted file mode 100644 index 3546100ae..000000000 --- a/tools/policy/assertions/workflow-security.mjs +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/bin/env bun - -import { readFileSync, readdirSync } from "node:fs"; -import path from "node:path"; - -const ROOT = path.resolve(import.meta.dir, "../../.."); -const FULL_COMMIT_SHA = /^[0-9a-f]{40}$/u; -const FULL_DIGEST = /^[0-9a-f]{64}$/u; - -function invariant(condition, message) { - if (!condition) throw new Error(`workflow security: ${message}`); -} - -function object(value) { - return value !== null && typeof value === "object" && !Array.isArray(value); -} - -function yamlFiles(root, relativeRoot) { - const files = []; - const visit = (relative) => { - for (const entry of readdirSync(path.join(root, relative), { withFileTypes: true })) { - const child = path.join(relative, entry.name); - if (entry.isDirectory()) visit(child); - else if (entry.isFile() && /[.]ya?ml$/u.test(entry.name)) files.push(child); - } - }; - visit(relativeRoot); - return files.sort(); -} - -function parseYaml(root, relativePath) { - try { - const value = Bun.YAML.parse(readFileSync(path.join(root, relativePath), "utf8")); - invariant(object(value), `${relativePath} must contain a YAML object`); - return value; - } catch (cause) { - if (cause instanceof Error && cause.message.startsWith("workflow security:")) throw cause; - throw new Error(`workflow security: cannot parse ${relativePath}: ${cause.message}`); - } -} - -function remoteUse(value) { - const uses = String(value ?? ""); - if (!uses || uses.startsWith("./")) return undefined; - if (uses.startsWith("docker://")) { - const revision = uses.match(/@sha256:([0-9a-f]+)$/u)?.[1]; - return { immutable: revision !== undefined && FULL_DIGEST.test(revision), uses }; - } - const separator = uses.lastIndexOf("@"); - const revision = separator === -1 ? "" : uses.slice(separator + 1); - return { immutable: FULL_COMMIT_SHA.test(revision), uses }; -} - -export function assertPinnedRemoteUses(document, label) { - const visit = (value, location) => { - if (Array.isArray(value)) { - value.forEach((entry, index) => visit(entry, `${location}[${index}]`)); - return; - } - if (!object(value)) return; - for (const [key, child] of Object.entries(value)) { - const childLocation = `${location}.${key}`; - if (key === "uses") { - const remote = remoteUse(child); - invariant( - remote === undefined || remote.immutable, - `${childLocation} must pin ${remote?.uses ?? child} by commit or digest`, - ); - } else { - visit(child, childLocation); - } - } - }; - visit(document, label); -} - -function assertPermissions(workflow, label) { - invariant(object(workflow.permissions), `${label} must declare top-level permissions`); - invariant(Object.keys(workflow.permissions).length > 0, `${label} permissions cannot be empty`); - for (const [scope, access] of Object.entries(workflow.permissions)) { - invariant( - access === "read" || access === "none", - `${label} top-level ${scope} permission must be read-only`, - ); - } - - for (const [jobId, job] of Object.entries(workflow.jobs)) { - if (job.permissions === undefined) continue; - invariant(object(job.permissions), `${label} ${jobId} permissions must be explicit`); - for (const [scope, access] of Object.entries(job.permissions)) { - invariant( - access === "read" || access === "write" || access === "none", - `${label} ${jobId} has invalid ${scope} permission ${String(access)}`, - ); - } - if (job.permissions["id-token"] === "write") { - invariant( - typeof job.environment === "string" && job.environment.length > 0, - `${label} ${jobId} must use a protected environment before requesting an OIDC token`, - ); - } - } -} - -function actionName(step) { - return String(step.uses ?? "").split("@")[0]; -} - -function assertArtifactsAndCheckouts(workflow, label) { - for (const [jobId, job] of Object.entries(workflow.jobs)) { - const canWrite = object(job.permissions) - && Object.values(job.permissions).includes("write"); - for (const [index, step] of (job.steps ?? []).entries()) { - const location = `${label} ${jobId}.steps[${index}]`; - const action = actionName(step); - if (action === "actions/checkout") { - invariant( - step.with?.["persist-credentials"] === false, - `${location} checkout must disable persisted credentials`, - ); - const ref = step.with?.ref; - invariant( - ref === undefined - || FULL_COMMIT_SHA.test(String(ref)) - || String(ref).startsWith("${{"), - `${location} checkout must use the triggering commit or an explicit SHA expression`, - ); - } - - if (action === "actions/upload-artifact") { - invariant( - typeof step.with?.name === "string" && step.with.name.length > 0, - `${location} upload must name its artifact`, - ); - invariant( - typeof step.with?.path === "string" && step.with.path.length > 0, - `${location} upload must declare its source path`, - ); - } - - if (action === "actions/download-artifact") { - const selectors = ["name", "pattern", "artifact-ids"] - .filter((key) => typeof step.with?.[key] === "string" && step.with[key].length > 0); - invariant( - selectors.length === 1, - `${location} download must select artifacts by one name, pattern, or ID`, - ); - invariant( - typeof step.with?.path === "string" && step.with.path.length > 0, - `${location} download must use an explicit destination`, - ); - for (const crossRunInput of ["run-id", "repository", "github-token"]) { - invariant( - step.with?.[crossRunInput] === undefined, - `${location} cannot download artifacts from another run or repository`, - ); - } - invariant( - !canWrite || selectors[0] === "artifact-ids", - `${location} in a write-capable job must select an exact artifact ID`, - ); - } - } - } -} - -export function assertWorkflowSecurity(workflow, label = "workflow") { - invariant(object(workflow.jobs) && Object.keys(workflow.jobs).length > 0, `${label} must declare jobs`); - assertPinnedRemoteUses(workflow, label); - assertPermissions(workflow, label); - assertArtifactsAndCheckouts(workflow, label); -} - -export function checkRepositoryWorkflowSecurity(root = ROOT) { - const workflows = yamlFiles(root, ".github/workflows"); - const actions = yamlFiles(root, ".github/actions"); - for (const relativePath of workflows) { - assertWorkflowSecurity(parseYaml(root, relativePath), relativePath); - } - for (const relativePath of actions) { - assertPinnedRemoteUses(parseYaml(root, relativePath), relativePath); - } - return { actions: actions.length, workflows: workflows.length }; -} - -function stripShellComment(line) { - let quote; - let escaped = false; - for (let index = 0; index < line.length; index += 1) { - const character = line[index]; - if (escaped) escaped = false; - else if (character === "\\" && quote !== "'") escaped = true; - else if (quote !== undefined && character === quote) quote = undefined; - else if (quote === undefined && /['"`]/u.test(character)) quote = character; - else if (quote === undefined && character === "#" && (index === 0 || /[\s;&|()]/u.test(line[index - 1]))) { - return line.slice(0, index); - } - } - return line; -} - -export function executableShell(source) { - const active = []; - const heredocs = []; - for (const line of String(source ?? "").replace(/\r\n?/gu, "\n").split("\n")) { - if (heredocs.length > 0) { - const current = heredocs[0]; - const candidate = current.stripTabs ? line.replace(/^\t+/u, "") : line; - if (candidate === current.marker) heredocs.shift(); - continue; - } - const code = stripShellComment(line); - active.push(code); - const matcher = /<<(-)?\s*(?:'([^']+)'|"([^"]+)"|([A-Za-z_][A-Za-z0-9_]*))/gu; - for (const match of code.matchAll(matcher)) { - heredocs.push({ marker: match[2] ?? match[3] ?? match[4], stripTabs: match[1] === "-" }); - } - } - return active.join("\n").replace(/\\\n/gu, " "); -} - -if (import.meta.main) { - if (process.argv.includes("--help")) { - console.log("usage: workflow-security.mjs"); - } else { - try { - const summary = checkRepositoryWorkflowSecurity(); - console.log(`workflow security checks passed (${summary.workflows} workflows, ${summary.actions} actions)`); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exitCode = 1; - } - } -} diff --git a/tools/policy/assertions/workflow-security.test.mjs b/tools/policy/assertions/workflow-security.test.mjs deleted file mode 100644 index 662cadaad..000000000 --- a/tools/policy/assertions/workflow-security.test.mjs +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - assertPinnedRemoteUses, - assertWorkflowSecurity, - executableShell, -} from "./workflow-security.mjs"; - -const SHA = "de0fac2e4500dabe0009e67214ff5f5447ce83dd"; - -function workflow(steps = [], extra = {}) { - return { - on: { workflow_dispatch: {} }, - permissions: { contents: "read" }, - jobs: { - check: { - "runs-on": "ubuntu-24.04", - steps, - }, - }, - ...extra, - }; -} - -test("remote actions require immutable revisions", () => { - assert.doesNotThrow(() => assertPinnedRemoteUses({ - steps: [ - { uses: `actions/checkout@${SHA}` }, - { uses: "./.github/actions/setup-bun" }, - { uses: `docker://example/image@sha256:${"a".repeat(64)}` }, - ], - }, "fixture")); - - for (const uses of ["actions/checkout@v4", "docker://example/image:latest"]) { - assert.throws( - () => assertPinnedRemoteUses({ steps: [{ uses }] }, "fixture"), - /must pin/u, - ); - } -}); - -test("workflow-wide permissions stay read-only", () => { - const candidate = workflow(); - candidate.permissions.contents = "write"; - assert.throws(() => assertWorkflowSecurity(candidate), /top-level contents permission/u); -}); - -test("OIDC tokens require a protected environment", () => { - const candidate = workflow(); - candidate.jobs.check.permissions = { contents: "read", "id-token": "write" }; - assert.throws(() => assertWorkflowSecurity(candidate), /protected environment/u); - candidate.jobs.check.environment = "release"; - assert.doesNotThrow(() => assertWorkflowSecurity(candidate)); -}); - -test("checkouts do not retain credentials or use mutable literal refs", () => { - const candidate = workflow([{ - uses: `actions/checkout@${SHA}`, - with: { ref: "main", "persist-credentials": false }, - }]); - assert.throws(() => assertWorkflowSecurity(candidate), /explicit SHA expression/u); - candidate.jobs.check.steps[0].with.ref = "${{ github.sha }}"; - assert.doesNotThrow(() => assertWorkflowSecurity(candidate)); - candidate.jobs.check.steps[0].with["persist-credentials"] = true; - assert.throws(() => assertWorkflowSecurity(candidate), /disable persisted credentials/u); -}); - -test("artifact downloads are explicit and stay in the current run", () => { - const candidate = workflow([{ - uses: `actions/download-artifact@${SHA}`, - with: { name: "candidate", path: "target/candidate" }, - }]); - assert.doesNotThrow(() => assertWorkflowSecurity(candidate)); - - candidate.jobs.check.steps[0].with["run-id"] = "123"; - assert.throws(() => assertWorkflowSecurity(candidate), /another run or repository/u); - delete candidate.jobs.check.steps[0].with["run-id"]; - delete candidate.jobs.check.steps[0].with.name; - assert.throws(() => assertWorkflowSecurity(candidate), /must select artifacts/u); - candidate.jobs.check.steps[0].with = { name: "candidate" }; - assert.throws(() => assertWorkflowSecurity(candidate), /explicit destination/u); -}); - -test("write-capable jobs consume artifacts only by exact ID", () => { - const candidate = workflow([{ - uses: `actions/download-artifact@${SHA}`, - with: { name: "candidate", path: "target/candidate" }, - }]); - candidate.jobs.check.permissions = { contents: "write" }; - assert.throws(() => assertWorkflowSecurity(candidate), /exact artifact ID/u); - candidate.jobs.check.steps[0].with = { - "artifact-ids": "${{ needs.build.outputs.artifact_id }}", - path: "target/candidate", - }; - assert.doesNotThrow(() => assertWorkflowSecurity(candidate)); -}); - -test("artifact uploads have an identity and source", () => { - const candidate = workflow([{ - uses: `actions/upload-artifact@${SHA}`, - with: { name: "proof", path: "target/proof" }, - }]); - assert.doesNotThrow(() => assertWorkflowSecurity(candidate)); - delete candidate.jobs.check.steps[0].with.path; - assert.throws(() => assertWorkflowSecurity(candidate), /source path/u); -}); - -test("dead comments and heredoc bodies are not executable workflow commands", () => { - const shell = executableShell([ - "# node dead.mjs", - "cat <<'BODY'", - "node also-dead.mjs", - "BODY", - "node live.mjs # node ignored.mjs", - ].join("\n")); - assert.doesNotMatch(shell, /dead[.]mjs/u); - assert.match(shell, /node live[.]mjs/u); -}); diff --git a/tools/policy/check-ci-gate.test.mjs b/tools/policy/check-ci-gate.test.mjs deleted file mode 100644 index 576d546b6..000000000 --- a/tools/policy/check-ci-gate.test.mjs +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import test from "node:test"; - -function gate(mode, { needs = {}, selected, required } = {}) { - const result = spawnSync( - process.execPath, - [".github/scripts/check-ci-gate.mjs", mode], - { - cwd: process.cwd(), - encoding: "utf8", - env: { - ...process.env, - NEEDS_JSON: JSON.stringify(needs), - ...(selected === undefined ? {} : { SELECTED_JOBS_JSON: JSON.stringify(selected) }), - ...(required === undefined ? {} : { REQUIRED_JOBS_JSON: JSON.stringify(required) }), - GATE_LABEL: "test gate", - }, - }, - ); - return { - status: result.status, - output: `${result.stdout}${result.stderr}`, - }; -} - -test("selected mode accepts success and an empty selection", () => { - assert.equal(gate("selected", { selected: [] }).status, 0); - assert.equal(gate("selected", { - selected: ["ios", "android", "ios"], - needs: { android: { result: "success" }, ios: { result: "success" } }, - }).status, 0); -}); - -for (const result of ["skipped", "failure", "cancelled"]) { - test(`selected mode rejects a ${result} selected job`, () => { - const checked = gate("selected", { - selected: ["ios"], - needs: { ios: { result } }, - }); - assert.equal(checked.status, 1); - assert.match(checked.output, new RegExp(`ios=${result}`)); - }); -} - -test("selected mode rejects a missing selected job", () => { - const checked = gate("selected", { selected: ["ios"], needs: {} }); - assert.equal(checked.status, 1); - assert.match(checked.output, /ios=missing/u); -}); - -test("selected mode rejects malformed selection input", () => { - const checked = gate("selected", { selected: "ios" }); - assert.equal(checked.status, 1); - assert.match(checked.output, /must be a JSON string array/u); -}); - -test("required mode rejects a skipped resolver", () => { - const checked = gate("required", { - required: ["resolve"], - needs: { resolve: { result: "skipped" } }, - }); - assert.equal(checked.status, 1); - assert.match(checked.output, /resolve=skipped/u); -}); - -test("permissive allow-skipped mode is not available", () => { - const checked = gate("allow-skipped", { - required: ["ios"], - needs: { ios: { result: "skipped" } }, - }); - assert.equal(checked.status, 1); - assert.match(checked.output, /usage: check-ci-gate\.mjs \[selected\|required\]/u); -}); diff --git a/tools/policy/check-cluster-seed-contract.mjs b/tools/policy/check-cluster-seed-contract.mjs deleted file mode 100644 index 779d50b9d..000000000 --- a/tools/policy/check-cluster-seed-contract.mjs +++ /dev/null @@ -1,248 +0,0 @@ -#!/usr/bin/env bun - -import { readFileSync } from "node:fs"; -import path from "node:path"; - -import { validateNativeClusterSeedManifest } from "../release/native-cluster-seed-contract.mjs"; - -const root = path.resolve(import.meta.dirname, "../.."); -const contractRoot = path.join(root, "src/shared/cluster-seed-contract"); -const contract = readJson("contract.json"); -const SHA256 = /^[0-9a-f]{64}$/u; -const COMMIT = /^[0-9a-f]{40}$/u; - -assertExactKeys(contract, [ - "compatibilityKeys", - "icu", - "icuDataSchema", - "manifests", - "physicalFormats", - "profiles", - "schema", -], "contract"); -assert(contract.schema === "oliphaunt-cluster-seed-contract-v1", "unsupported contract schema"); -assert(contract.icuDataSchema === "oliphaunt-icu-data-v1", "unsupported ICU-data schema"); -assertExactKeys(contract.manifests, ["native", "wasix"], "manifest families"); -assertExactKeys(contract.manifests.native, [ - "cacheKeyDisallowedValues", - "cacheKeyPattern", - "layout", - "schema", -], "native manifest contract"); -assertExactKeys(contract.manifests.wasix, ["schema"], "WASIX manifest contract"); -assert( - contract.manifests.native.schema === "oliphaunt-runtime-resources-v1" - && contract.manifests.native.layout === "oliphaunt-cluster-seed-v1", - "unsupported native manifest contract", -); -assert(contract.manifests.wasix.schema === "oliphaunt-cluster-seed-v1", "unsupported WASIX manifest schema"); -assert( - contract.manifests.native.cacheKeyPattern === "^[A-Za-z0-9._-]{1,128}$", - "cluster-seed cache-key grammar is invalid", -); -assert( - JSON.stringify(contract.manifests.native.cacheKeyDisallowedValues) === JSON.stringify([".", ".."]), - "cluster-seed cache-key path components are invalid", -); -assertExactKeys(contract.profiles, ["icu", "standard"], "contract profiles"); -assertProfileContract("standard", "cluster-seed-standard", []); -assertProfileContract("icu", "cluster-seed-icu", ["icu"]); -assertExactKeys(contract.icu, [ - "artifactRole", - "dataForm", - "dataVersion", - "internalReadinessEnvironment", - "internalReadinessValue", - "logicalTreeDigest", - "runtimePath", -], "contract ICU"); -assert(contract.icu.artifactRole === "icu-data", "ICU artifact role must be icu-data"); -assert(contract.icu.dataForm === "files-le", "ICU data form must be files-le"); -assert(contract.icu.dataVersion === "76.1", "ICU data version must be 76.1"); -assert(contract.icu.runtimePath === "share/icu", "ICU runtime path must be share/icu"); -assert( - contract.icu.logicalTreeDigest === "sha256(path-nul-size-nul-bytes-lf)", - "ICU logical tree digest algorithm is invalid", -); -assert( - contract.icu.internalReadinessEnvironment === "OLIPHAUNT_INTERNAL_ICU_READY" - && contract.icu.internalReadinessValue === "1", - "internal ICU readiness must use the exact locked name and value", -); -assert( - Object.keys(contract.compatibilityKeys.native).length === 6, - "native compatibility domains must be explicit", -); -for (const [target, key] of Object.entries(contract.compatibilityKeys.native)) { - assert(key === `native-pg18-${target}-v1`, `native compatibility key for ${target} is invalid`); - assert(key !== contract.compatibilityKeys.wasixDatum32, `${target} and WASIX seeds must have different compatibility keys`); -} - -validateSeed(readJson("fixtures/standard.valid.json"), "standard fixture"); -validateSeed(readJson("fixtures/icu.valid.json"), "ICU fixture"); -validateNativeClusterSeedManifest( - readFixture("native-standard.valid.properties"), - "standard", - { target: "linux-x64-gnu" }, -); -validateNativeClusterSeedManifest( - readFixture("native-icu.valid.properties"), - "icu", - { target: "linux-x64-gnu", icuDataTreeSha256: "a".repeat(64) }, -); -for (const name of [ - "native-malformed.invalid.properties", - "native-whitespace.invalid.properties", - "native-cache-key.invalid.properties", - "native-dot-cache-key.invalid.properties", - "native-dotdot-cache-key.invalid.properties", - "native-extra-field.invalid.properties", - "native-target-mismatch.invalid.properties", - "native-profile-mismatch.invalid.properties", -]) { - let nativeRejected = false; - try { - validateNativeClusterSeedManifest(readFixture(name), "standard", { - target: "linux-x64-gnu", - }); - } catch { - nativeRejected = true; - } - assert(nativeRejected, `${name} must be rejected`); -} -let rejected = false; -try { - validateSeed(readJson("fixtures/profile-mismatch.invalid.json"), "invalid fixture"); -} catch { - rejected = true; -} -assert(rejected, "profile-mismatch.invalid.json must be rejected"); - -console.log("cluster seed contract passed (WASIX and native standard/ICU fixtures; invalid vectors rejected)"); - -export function validateSeed(seed, label = "cluster seed") { - assertObject(seed, label); - assertExactKeys(seed, [ - "archive", - "artifactRole", - "catalogProfile", - "extensions", - "icu", - "initProfile", - "requiredRuntimeFeatures", - "runtime", - "schema", - "source", - ], label); - assert(seed.schema === contract.manifests.wasix.schema, `${label} has unsupported schema`); - const profile = contract.profiles[seed.catalogProfile]; - assert(profile !== undefined, `${label} has unsupported catalogProfile`); - assert(seed.artifactRole === profile.artifactRole, `${label} artifactRole/profile mismatch`); - assert( - JSON.stringify(seed.requiredRuntimeFeatures) === JSON.stringify(profile.requiredRuntimeFeatures), - `${label} requiredRuntimeFeatures/profile mismatch`, - ); - const runtimeKeys = [ - "compatibilityKey", - "consumerSha256", - "engineFamily", - "initdbSha256", - "physicalFormat", - "postgresMajor", - "producerSha256", - "product", - "version", - ]; - assertExactKeys(seed.runtime, runtimeKeys, `${label} runtime`); - assert(seed.runtime.engineFamily === "wasix", `${label} engineFamily must be wasix`); - assert( - seed.runtime.physicalFormat === contract.physicalFormats.wasix, - `${label} physicalFormat must be the WASIX format`, - ); - assert( - seed.runtime.compatibilityKey === contract.compatibilityKeys.wasixDatum32, - `${label} compatibilityKey must be the WASIX Datum32 key`, - ); - assert(seed.runtime.postgresMajor === 18, `${label} must target PostgreSQL 18`); - for (const key of ["consumerSha256", "producerSha256", "initdbSha256"]) { - assert(SHA256.test(seed.runtime[key]), `${label} runtime.${key} must be SHA-256`); - } - for (const key of ["product", "version"]) assertText(seed.runtime[key], `${label} runtime.${key}`); - assertExactKeys(seed.source, ["catalogVersion", "fingerprint", "lane", "producer"], `${label} source`); - for (const [key, value] of Object.entries(seed.source)) assertText(value, `${label} source.${key}`); - assertText(seed.initProfile, `${label} initProfile`); - assertExactKeys(seed.archive, [ - "compressedBytes", - "directories", - "expandedBytes", - "path", - "regularFiles", - "sha256", - ], `${label} archive`); - assert(seed.archive.path === `cluster-seeds/${seed.catalogProfile}.tar.zst`, `${label} archive path/profile mismatch`); - assert(SHA256.test(seed.archive.sha256), `${label} archive SHA-256 is invalid`); - for (const key of ["compressedBytes", "expandedBytes", "regularFiles", "directories"]) { - assert(Number.isSafeInteger(seed.archive[key]) && seed.archive[key] > 0, `${label} archive.${key} is invalid`); - } - assertExactKeys(seed.extensions, ["selected", "startupConfiguration"], `${label} extensions`); - assert( - Array.isArray(seed.extensions.selected) && seed.extensions.selected.length === 0 - && Array.isArray(seed.extensions.startupConfiguration) - && seed.extensions.startupConfiguration.length === 0, - `${label} must be extension-free`, - ); - if (seed.catalogProfile === "standard") { - assert(seed.icu === null, `${label} standard profile must not identify ICU data`); - } else { - assertExactKeys(seed.icu, [ - "artifactRole", - "dataForm", - "dataTreeSha256", - "dataVersion", - "sourceCommit", - "upstreamVersion", - ], `${label} ICU`); - assert(seed.icu.artifactRole === contract.icu.artifactRole, `${label} ICU artifact role is invalid`); - assert(seed.icu.dataForm === contract.icu.dataForm, `${label} ICU data form is invalid`); - assert(seed.icu.dataVersion === contract.icu.dataVersion, `${label} ICU data version is invalid`); - assert(seed.icu.upstreamVersion === contract.icu.dataVersion, `${label} ICU upstream version is invalid`); - assert(SHA256.test(seed.icu.dataTreeSha256), `${label} ICU tree SHA-256 is invalid`); - assert(COMMIT.test(seed.icu.sourceCommit), `${label} ICU source commit is invalid`); - } - return seed; -} - -function assertProfileContract(profile, artifactRole, requiredRuntimeFeatures) { - assertExactKeys(contract.profiles[profile], ["artifactRole", "requiredRuntimeFeatures"], `profile ${profile}`); - assert(contract.profiles[profile].artifactRole === artifactRole, `profile ${profile} role mismatch`); - assert( - JSON.stringify(contract.profiles[profile].requiredRuntimeFeatures) === JSON.stringify(requiredRuntimeFeatures), - `profile ${profile} features mismatch`, - ); -} - -function readJson(relative) { - return JSON.parse(readFileSync(path.join(contractRoot, ...relative.split("/")), "utf8")); -} - -function readFixture(name) { - return readFileSync(path.join(contractRoot, "fixtures", name)); -} - -function assertObject(value, label) { - assert(value !== null && typeof value === "object" && !Array.isArray(value), `${label} must be an object`); -} - -function assertExactKeys(value, expected, label) { - assertObject(value, label); - const actual = Object.keys(value).sort(); - assert(JSON.stringify(actual) === JSON.stringify([...expected].sort()), `${label} has non-canonical fields`); -} - -function assertText(value, label) { - assert(typeof value === "string" && value.length > 0 && !value.includes("\0"), `${label} must be non-empty text`); -} - -function assert(condition, message) { - if (!condition) throw new Error(`cluster seed contract: ${message}`); -} diff --git a/tools/policy/check-coverage-baseline.mjs b/tools/policy/check-coverage-baseline.mjs deleted file mode 100644 index 956233a48..000000000 --- a/tools/policy/check-coverage-baseline.mjs +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bun - -const EXPECTED_PRODUCTS = [ - 'oliphaunt-rust', - 'oliphaunt-swift', - 'oliphaunt-kotlin', - 'oliphaunt-js', - 'oliphaunt-react-native', - 'oliphaunt-wasix-rust', - 'oliphaunt-wasix-ts', -]; - -function fail(message) { - console.error(message); - process.exit(1); -} - -function numberValue(value) { - if (typeof value === 'number') { - return value; - } - if (typeof value === 'string' && value.trim().length > 0) { - return Number(value); - } - return Number.NaN; -} - -function requireString(value, context) { - if (typeof value !== 'string' || value.trim().length === 0) { - fail(`${context} must be a non-empty string`); - } -} - -const selected = process.argv[2] ?? 'all'; -const targets = selected === 'all' ? EXPECTED_PRODUCTS : [selected]; -const baseline = Bun.TOML.parse(await Bun.file('coverage/baseline.toml').text()); -const products = baseline.products ?? {}; - -for (const product of targets) { - const config = products[product]; - if (config === undefined || config === null || typeof config !== 'object') { - fail(`missing coverage product config: ${product}`); - } - if ('include_globs' in config) { - fail(`${product}: coverage must use source_globs, not include_globs`); - } - const sourceGlobs = config.source_globs; - if ( - !Array.isArray(sourceGlobs) || - sourceGlobs.length === 0 || - !sourceGlobs.every((item) => typeof item === 'string') - ) { - fail(`${product}: source_globs must be a non-empty string array`); - } - const lineThreshold = numberValue(config.line_threshold); - if (Number.isNaN(lineThreshold) || lineThreshold < 80.0) { - fail(`${product}: aggregate line_threshold must stay at or above 80`); - } - const perFileLineWarning = numberValue(config.per_file_line_warning); - if (Number.isNaN(perFileLineWarning) || perFileLineWarning <= 0 || perFileLineWarning > 100) { - fail(`${product}: per_file_line_warning must be between 0 and 100`); - } - for (const obsolete of [ - 'per_file_line_threshold', - 'measured_line_coverage', - 'branch_coverage', - 'function_coverage', - ]) { - if (obsolete in config) fail(`${product}: obsolete coverage setting ${obsolete} must be removed`); - } - const waivers = config.waivers; - if (!Array.isArray(waivers)) { - fail(`${product}: coverage waivers must be an explicit array, including when empty`); - } - for (const waiver of waivers) { - if (waiver === null || typeof waiver !== 'object' || Array.isArray(waiver)) { - fail(`${product}: waiver must be a TOML table`); - } - const hasPath = typeof waiver.path === 'string'; - const hasGlob = typeof waiver.glob === 'string'; - if (hasPath === hasGlob) { - fail(`${product}: waiver must define exactly one of path or glob`); - } - for (const key of ['reason', 'evidence', 'owner', 'expires']) { - requireString(waiver[key], `${product}: waiver ${key}`); - } - } -} diff --git a/tools/policy/check-crate-package.sh b/tools/policy/check-crate-package.sh deleted file mode 100755 index e896d2c66..000000000 --- a/tools/policy/check-crate-package.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -allow_dirty=() -packages=() -while [ "$#" -gt 0 ]; do - case "$1" in - --allow-dirty) - allow_dirty=(--allow-dirty) - shift - ;; - --package|-p) - if [ -z "${2:-}" ]; then - echo "--package requires a package name" >&2 - exit 2 - fi - packages+=("$2") - shift 2 - ;; - *) - echo "unknown argument: $1" >&2 - exit 2 - ;; - esac -done - -rm -f target/package/*.crate - -package_oliphaunt_wasix() { - bun tools/release/package_oliphaunt_wasix_sdk_crate.mjs --output-dir target/package >/dev/null -} - -default_packages() { - bun tools/policy/list-publishable-cargo-packages.mjs -} - -if [ "${#packages[@]}" -eq 0 ]; then - while IFS= read -r package; do - cargo package -p "$package" --locked --no-verify "${allow_dirty[@]}" - done < <(default_packages) - package_oliphaunt_wasix -else - for package in "${packages[@]}"; do - if [ "$package" = "oliphaunt-wasix" ]; then - package_oliphaunt_wasix - else - cargo package -p "$package" --locked --no-verify "${allow_dirty[@]}" - fi - done -fi -tools/policy/check-crate-size.sh --enforce diff --git a/tools/policy/check-crate-size.sh b/tools/policy/check-crate-size.sh deleted file mode 100755 index 82180ad6d..000000000 --- a/tools/policy/check-crate-size.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env sh -set -eu - -mode="${1:---warn}" -limit_bytes="${CRATES_IO_SIZE_LIMIT_BYTES:-10485760}" -crate_files="$(find target/package -maxdepth 1 -name '*.crate' -type f 2>/dev/null | sort || true)" - -if [ -z "$crate_files" ]; then - echo "No packaged crate found under target/package; run cargo package first." >&2 - exit 1 -fi - -limit_mib="$(awk "BEGIN { printf \"%.2f\", $limit_bytes / 1048576 }")" -failed=0 - -for crate_file in $crate_files; do - size_bytes="$(wc -c < "$crate_file" | tr -d ' ')" - size_mib="$(awk "BEGIN { printf \"%.2f\", $size_bytes / 1048576 }")" - - if [ "$size_bytes" -le "$limit_bytes" ]; then - echo "crate size ok: $crate_file is ${size_mib}MiB <= ${limit_mib}MiB" - continue - fi - - label="warning" - if [ "$mode" = "--enforce" ]; then - label="error" - fi - message="crate size $label: $crate_file is ${size_mib}MiB > ${limit_mib}MiB" - echo "$message" >&2 - failed=1 -done - -if [ "$mode" = "--enforce" ] && [ "$failed" -ne 0 ]; then - exit 1 -fi - -exit 0 diff --git a/tools/policy/check-dependency-invariants.sh b/tools/policy/check-dependency-invariants.sh deleted file mode 100755 index 2c003871c..000000000 --- a/tools/policy/check-dependency-invariants.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -bun tools/policy/check-wasix-release-dependency-invariants.mjs - -blocked='wasm''time|wasm''time-wasi|wasmer-compiler-(llvm|cranelift|singlepass)|llvm-sys|cranelift-|singlepass' - -if cargo tree -p oliphaunt-wasix --features extensions --locked | rg -n "$blocked"; then - cat >&2 <<'MSG' -blocked runtime dependency found in the normal user dependency tree. - -The production path must stay on headless Wasmer AOT loading. Backend compiler -crates such as LLVM, Cranelift, Singlepass, and Wasmtime must not enter the -normal user build. -MSG - exit 1 -fi - -if cargo tree -p xtask --features aot-serializer --locked | rg -n 'wasmer-compiler-(cranelift|singlepass)|cranelift-|singlepass|wasm''time'; then - cat >&2 <<'MSG' -blocked maintainer serializer dependency found. - -The AOT serializer may use Wasmer LLVM only. Cranelift, Singlepass, and Wasmtime -belong in isolated maintainer experiments, not in release/AOT tooling. -MSG - exit 1 -fi - -echo "dependency invariants ok" diff --git a/tools/policy/check-docs.sh b/tools/policy/check-docs.sh deleted file mode 100644 index 1147e1a3c..000000000 --- a/tools/policy/check-docs.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -if git grep -n -E \ - -e 'pglite[-_]oxide' \ - -e 'github[.]com/f0rr0/(pglite|oliphaunt)-oxide' \ - -e 'PostgreSQL 17[.]5' \ - -- README.md CONTRIBUTING.md docs/architecture docs/maintainers src/docs src/*/README.md; then - echo "public documentation contains a retired product or repository identity" >&2 - exit 1 -fi - -if git grep -n -F \ - -e 'tools/release/release.py' \ - -e 'tools/release/sync_release_pr.py' \ - -e 'tools/release/artifact_target_matrix.py' \ - -- README.md docs/architecture docs/maintainers src/docs; then - echo "maintained documentation points at removed release tools" >&2 - exit 1 -fi - -if git grep -n -E \ - -e '(^|[^[:alnum:]_-])npm --prefix' \ - -e '(^|[^[:alnum:]_-])npm (run|pack|start)([[:space:];|&]|$)' \ - -- README.md CONTRIBUTING.md docs/architecture docs/maintainers src/docs src/*/README.md; then - echo "public JavaScript instructions must use the pnpm workspace" >&2 - exit 1 -fi - -if git grep -n -E \ - -e 'pnpm run moon --' \ - -e 'pnpm run [[:alnum:]:-]+ -- --affected' \ - -- README.md CONTRIBUTING.md docs/architecture docs/maintainers src/docs src/*/README.md; then - echo "public pnpm instructions contain an invalid extra argument separator" >&2 - exit 1 -fi - -echo "documentation command and identity policy passed" diff --git a/tools/policy/check-feature-powerset.mjs b/tools/policy/check-feature-powerset.mjs deleted file mode 100755 index f3788c365..000000000 --- a/tools/policy/check-feature-powerset.mjs +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bun -import { chdirRepoRoot, run } from "./lib/run-command.mjs"; - -const PREFIX = "check-feature-powerset.mjs"; - -chdirRepoRoot(PREFIX); -run(PREFIX, "cargo", [ - "hack", - "check", - "--workspace", - "--feature-powerset", - "--no-dev-deps", - "--exclude-features", - "aot-serializer,cluster-seed-runner", -]); diff --git a/tools/policy/check-mobile-extension-artifacts.sh b/tools/policy/check-mobile-extension-artifacts.sh deleted file mode 100755 index b840286a3..000000000 --- a/tools/policy/check-mobile-extension-artifacts.sh +++ /dev/null @@ -1,484 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -if [ -z "${ANDROID_HOME:-}" ] && [ -d "$HOME/Library/Android/sdk" ]; then - export ANDROID_HOME="$HOME/Library/Android/sdk" -fi -if [ -n "${ANDROID_HOME:-}" ] && [ -z "${ANDROID_SDK_ROOT:-}" ]; then - export ANDROID_SDK_ROOT="$ANDROID_HOME" -fi - -source src/runtimes/liboliphaunt/native/bin/mobile-static-extensions.sh - -selected_raw="${OLIPHAUNT_MOBILE_EXTENSION_CHECK_EXTENSIONS:-vector}" -scratch_root="${OLIPHAUNT_MOBILE_EXTENSION_CHECK_SCRATCH:-$root/target/liboliphaunt-mobile-extension-check}" -resource_output="$scratch_root/resources" -jni_root="$scratch_root/android-jni" -kotlin_build_root="$scratch_root/kotlin-gradle" -kotlin_cxx_root="$scratch_root/kotlin-cxx" -kotlin_cache_root="$scratch_root/kotlin-gradle-cache" -rn_build_root="$scratch_root/react-native-gradle" -rn_cxx_root="$scratch_root/react-native-cxx" -rn_cache_root="$scratch_root/react-native-gradle-cache" -native_resource_work_root="$scratch_root/native-resource-runtime" -macos_extension_archive_root="$scratch_root/macos-extension-archives" - -selected_extensions=() -selected_createable_extensions=() -selected_module_extensions=() -selected_stems=() -selected_ios_dependencies=() -native_resource_env=() -mobile_catalog_cache="" - -run() { - printf '\n==> %s\n' "$*" - "$@" -} - -require() { - if ! command -v "$1" >/dev/null 2>&1; then - echo "missing required command: $1" >&2 - exit 1 - fi -} - -mobile_catalog() { - if [ -z "$mobile_catalog_cache" ]; then - mobile_catalog_cache="$(cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked -- --list-extensions)" - fi - printf '%s\n' "$mobile_catalog_cache" -} - -mobile_prebuilt_extensions() { - mobile_catalog | awk -F '\t' 'NR > 1 && $8 == "yes" { print $1 }' -} - -mobile_catalog_native_module_stem() { - local extension="$1" - mobile_catalog | awk -F '\t' -v extension="$extension" ' - NR > 1 && $1 == extension && $8 == "yes" { - print $4 - found = 1 - exit - } - END { - if (!found) { - exit 1 - } - } - ' -} - -mobile_catalog_creates_extension() { - local extension="$1" - mobile_catalog | awk -F '\t' -v extension="$extension" ' - NR > 1 && $1 == extension && $8 == "yes" { - print $3 - found = 1 - exit - } - END { - if (!found) { - exit 1 - } - } - ' -} - -array_contains() { - local value="$1" - shift || true - case " $* " in - *" $value "*) ;; - *) return 1 ;; - esac -} - -add_ios_dependency() { - local dependency="$1" - [ -n "$dependency" ] || return 0 - array_contains "$dependency" "${selected_ios_dependencies[@]}" || selected_ios_dependencies+=("$dependency") -} - -add_extension() { - local requested="$1" - local extension stem catalog_stem - requested="$(printf '%s\n' "$requested" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" - [ -n "$requested" ] || return 0 - if oliphaunt_mobile_static_extension_spec "$requested" >/dev/null; then - extension="$(oliphaunt_mobile_static_extension_sql_name "$requested")" - stem="$(oliphaunt_mobile_static_extension_module_stem "$requested")" - array_contains "$extension" "${selected_extensions[@]}" || selected_extensions+=("$extension") - array_contains "$extension" "${selected_module_extensions[@]}" || selected_module_extensions+=("$extension") - array_contains "$stem" "${selected_stems[@]}" || selected_stems+=("$stem") - local dependency - while IFS= read -r dependency; do - [ -n "$dependency" ] || continue - add_ios_dependency "$dependency" - done < <(oliphaunt_mobile_static_extension_dependencies_for_target "$extension" ios || true) - return 0 - fi - - if ! catalog_stem="$(mobile_catalog_native_module_stem "$requested")"; then - echo "unsupported mobile extension artifact check extension: $requested" >&2 - printf 'supported mobile-prebuilt exact extensions: ' >&2 - mobile_prebuilt_extensions | paste -sd ',' - >&2 - exit 2 - fi - - if [ "$catalog_stem" != "-" ]; then - echo "mobile-prebuilt extension $requested is missing a mobile static build spec for native module $catalog_stem" >&2 - exit 2 - fi - - array_contains "$requested" "${selected_extensions[@]}" || selected_extensions+=("$requested") -} - -join_csv() { - local old_ifs="$IFS" - IFS="," - printf '%s' "$*" - IFS="$old_ifs" -} - -join_sorted_csv() { - if [ "$#" -eq 0 ]; then - return 0 - fi - printf '%s\n' "$@" | LC_ALL=C sort -u | paste -sd ',' - -} - -prepare_native_resource_runtime() { - native_resource_env=() - if [ "${#selected_module_extensions[@]}" -eq 0 ]; then - return 0 - fi - local native_resource_log="$scratch_root/native-resource-runtime.log" - printf '\n==> env OLIPHAUNT_WORK_ROOT=%s OLIPHAUNT_BUILD_EXTENSIONS=1 OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES=%s OLIPHAUNT_POSTGIS_USE_PINNED_DEPS=1 src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh (log: %s)\n' \ - "$native_resource_work_root" \ - "$module_extensions_csv" \ - "$native_resource_log" - if ! env \ - OLIPHAUNT_WORK_ROOT="$native_resource_work_root" \ - OLIPHAUNT_BUILD_EXTENSIONS=1 \ - OLIPHAUNT_NATIVE_EXTENSION_SQL_NAMES="$module_extensions_csv" \ - OLIPHAUNT_POSTGIS_USE_PINNED_DEPS=1 \ - src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh > "$native_resource_log" 2>&1; then - echo "native macOS extension/resource runtime build failed; tail of $native_resource_log:" >&2 - tail -n 120 "$native_resource_log" >&2 || true - exit 1 - fi - native_resource_env=( - "OLIPHAUNT_INSTALL_DIR=$native_resource_work_root/install" - "LIBOLIPHAUNT_PATH=$native_resource_work_root/out/liboliphaunt.dylib" - ) -} - -require_text() { - local file="$1" - local text="$2" - local message="$3" - if ! grep -Fq "$text" "$file"; then - echo "$message" >&2 - echo "expected '$text' in $file" >&2 - exit 1 - fi -} - -require_manifest_line() { - local file="$1" - local line="$2" - local message="$3" - if ! grep -Fxq "$line" "$file"; then - echo "$message" >&2 - echo "expected exact line '$line' in $file" >&2 - exit 1 - fi -} - -reject_zip_entry() { - local archive="$1" - local pattern="$2" - local message="$3" - local entries - entries="$(unzip -Z1 "$archive")" - if grep -Eq "$pattern" <<< "$entries"; then - echo "$message" >&2 - echo "unexpected pattern '$pattern' in $archive" >&2 - exit 1 - fi -} - -require_zip_entry() { - local archive="$1" - local pattern="$2" - local message="$3" - local entries - entries="$(unzip -Z1 "$archive")" - if ! grep -Eq "$pattern" <<< "$entries"; then - echo "$message" >&2 - echo "expected pattern '$pattern' in $archive" >&2 - exit 1 - fi -} - -regex_escape() { - printf '%s' "$1" | sed -e 's/[][(){}.^$*+?|\\]/\\&/g' -} - -require_selected_extension_controls() { - local archive="$1" - local label="$2" - local extension escaped - for extension in "${selected_extensions[@]}"; do - if [ "$extension" = "auto_explain" ]; then - continue - fi - escaped="$(regex_escape "$extension")" - require_zip_entry "$archive" "assets/oliphaunt/runtime/files/share/postgresql/extension/$escaped\\.control$" \ - "$label must include selected $extension extension assets" - done -} - -reject_unselected_extension_controls() { - local archive="$1" - local label="$2" - local extension escaped - while IFS= read -r extension; do - [ -n "$extension" ] || continue - [ "$extension" != "auto_explain" ] || continue - array_contains "$extension" "${selected_extensions[@]}" && continue - escaped="$(regex_escape "$extension")" - reject_zip_entry "$archive" "assets/oliphaunt/runtime/files/share/postgresql/extension/$escaped\\.control$" \ - "$label must not leak unselected $extension assets" - done < <(mobile_prebuilt_extensions) -} - -require_library_symbol() { - local library="$1" - local symbol="$2" - local symbols - if ! symbols="$(nm -D --defined-only "$library" 2>/dev/null)"; then - echo "could not inspect symbols in $library" >&2 - exit 1 - fi - if ! grep -Eq "[[:space:]]$symbol$" <<< "$symbols"; then - echo "missing required symbol $symbol in $library" >&2 - exit 1 - fi -} - -require cargo -require unzip -require nm -require xcodebuild - -IFS="," -read -r -a requested_extensions <<< "$selected_raw" -IFS=$' \t\n' -for requested in "${requested_extensions[@]}"; do - case "$(printf '%s\n' "$requested" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')" in - all-mobile) - while IFS= read -r extension; do - add_extension "$extension" - done < <(mobile_prebuilt_extensions) - ;; - all-mobile-modules) - while IFS= read -r extension; do - add_extension "$extension" - done < <(oliphaunt_mobile_static_supported_extensions) - ;; - *) - add_extension "$requested" - ;; - esac -done - -if [ "${#selected_extensions[@]}" -eq 0 ]; then - echo "no mobile extension artifact check extensions selected" >&2 - exit 2 -fi - -for extension in "${selected_extensions[@]}"; do - creates_extension="$(mobile_catalog_creates_extension "$extension")" || { - echo "selected mobile extension $extension is missing canonical creates_extension catalog metadata" >&2 - exit 2 - } - case "$creates_extension" in - yes) selected_createable_extensions+=("$extension") ;; - no) ;; - *) - echo "selected mobile extension $extension has non-canonical creates_extension=$creates_extension" >&2 - exit 2 - ;; - esac -done - -selected_csv="$(join_sorted_csv "${selected_extensions[@]}")" -createable_csv="$(join_sorted_csv "${selected_createable_extensions[@]}")" -module_extensions_csv="$(join_csv "${selected_module_extensions[@]}")" -stems_csv="$(join_csv "${selected_stems[@]}")" -manifest_stems_csv="$(join_sorted_csv "${selected_stems[@]}")" - -printf 'checking mobile extension artifacts for extensions=%s stems=%s\n' "$selected_csv" "$stems_csv" - -rm -rf \ - "$resource_output" \ - "$jni_root" \ - "$kotlin_build_root" \ - "$kotlin_cxx_root" \ - "$rn_build_root" \ - "$rn_cxx_root" \ - "$native_resource_work_root" \ - "$macos_extension_archive_root" - -mobile_static_args=() -for stem in "${selected_stems[@]}"; do - mobile_static_args+=(--mobile-static-module "$stem") -done - -run env OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$module_extensions_csv" \ - src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-simulator.sh -run env OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$module_extensions_csv" \ - src/runtimes/liboliphaunt/native/bin/build-postgres18-ios-device.sh -run env OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$module_extensions_csv" \ - src/runtimes/liboliphaunt/native/bin/build-postgres18-android-arm64.sh - -prepare_native_resource_runtime - -if [ "${#selected_module_extensions[@]}" -gt 0 ]; then - run env \ - OLIPHAUNT_MACOS_RUNTIME_ROOT="$native_resource_work_root" \ - OLIPHAUNT_MACOS_EXTENSION_ARCHIVE_ROOT="$macos_extension_archive_root" \ - OLIPHAUNT_MOBILE_STATIC_EXTENSIONS="$module_extensions_csv" \ - src/runtimes/liboliphaunt/native/bin/build-macos-extension-archives.sh -fi - -run env "${native_resource_env[@]}" cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked -- \ - --output "$resource_output" \ - --extension "$selected_csv" \ - "${mobile_static_args[@]}" \ - --require-mobile-static-registry \ - --force - -runtime_manifest="$resource_output/oliphaunt/runtime/manifest.properties" -static_registry_source="$resource_output/oliphaunt/static-registry/oliphaunt_static_registry.c" -require_manifest_line "$runtime_manifest" "selectedExtensions=$selected_csv" \ - "Rust runtime resources must record the full exact selected extension domain" -require_manifest_line "$runtime_manifest" "extensions=$createable_csv" \ - "Rust runtime resources must record the exact CREATE EXTENSION domain" -require_manifest_line "$runtime_manifest" "nativeModuleStems=$manifest_stems_csv" \ - "Rust runtime resources must record selected native module stems" -if [ "${#selected_stems[@]}" -eq 0 ]; then - require_manifest_line "$runtime_manifest" "mobileStaticRegistryState=not-required" \ - "SQL-only mobile runtime resources must not invent a static registry" -else - require_manifest_line "$runtime_manifest" "mobileStaticRegistryState=complete" \ - "Rust runtime resources must prove mobile static registry completion" - require_text "$static_registry_source" "liboliphaunt_selected_static_extensions" \ - "Rust runtime resources must emit static extension registry glue" - for stem in "${selected_stems[@]}"; do - require_text "$static_registry_source" "$(oliphaunt_static_symbol_prefix "$stem")_Pg_magic_func" \ - "Rust runtime resources must strongly reference selected extension magic symbols" - done - case " ${selected_extensions[*]} " in - *" vector "*) - require_text "$static_registry_source" "vector_in" \ - "Rust runtime resources must strongly reference selected vector SQL symbols" - require_text "$static_registry_source" "pg_finfo_vector_in" \ - "Rust runtime resources must strongly reference selected vector SQL finfo symbols" - ;; - esac -fi - -run env OLIPHAUNT_MACOS_EXTENSION_OUT="$macos_extension_archive_root/out" \ - src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh \ - --runtime-resources "$resource_output" -run env OLIPHAUNT_MACOS_EXTENSION_OUT="$macos_extension_archive_root/out" \ - src/runtimes/liboliphaunt/native/bin/build-ios-extension-xcframeworks.sh \ - --check-current \ - --runtime-resources "$resource_output" - -for index in "${!selected_module_extensions[@]}"; do - extension="${selected_module_extensions[$index]}" - stem="${selected_stems[$index]}" - xcframework="target/liboliphaunt-ios-extension-xcframeworks/out/$stem/liboliphaunt_extension_$stem.xcframework" - [ -d "$xcframework" ] || { - echo "missing iOS extension XCFramework for $extension: $xcframework" >&2 - exit 1 - } - plutil -extract AvailableLibraries raw "$xcframework/Info.plist" >/dev/null -done - -for dependency in "${selected_ios_dependencies[@]}"; do - xcframework="target/liboliphaunt-ios-extension-xcframeworks/out/dependencies/$dependency/liboliphaunt_dependency_$dependency.xcframework" - [ -d "$xcframework" ] || { - echo "missing iOS dependency XCFramework for $dependency: $xcframework" >&2 - exit 1 - } - plutil -extract AvailableLibraries raw "$xcframework/Info.plist" >/dev/null -done - -mkdir -p "$jni_root/arm64-v8a" -cp target/liboliphaunt-pg18-android-arm64/out/liboliphaunt.so "$jni_root/arm64-v8a/liboliphaunt.so" - -kotlin_gradle="src/sdks/kotlin/gradlew" -run "$kotlin_gradle" -p src/sdks/kotlin :oliphaunt:bundleReleaseAar \ - -PoliphauntRuntimeResourcesDir="$resource_output" \ - -PoliphauntAndroidJniLibsDir="$jni_root" \ - -PoliphauntAndroidExtensionArchivesDir="$root/target/liboliphaunt-pg18-android-arm64/out" \ - -PoliphauntAndroidAbiFilters=arm64-v8a \ - -PoliphauntBuildRoot="$kotlin_build_root" \ - -PoliphauntCxxBuildRoot="$kotlin_cxx_root" \ - --project-cache-dir "$kotlin_cache_root" \ - --no-configuration-cache - -kotlin_aar="$kotlin_build_root/oliphaunt/outputs/aar/oliphaunt-release.aar" -if [ "${#selected_stems[@]}" -gt 0 ]; then - require_zip_entry "$kotlin_aar" 'jni/arm64-v8a/liboliphaunt_extensions\.so$' \ - "Kotlin Android release AAR must include selected-extension support library" -fi -require_selected_extension_controls "$kotlin_aar" "Kotlin Android release AAR" -reject_unselected_extension_controls "$kotlin_aar" "Kotlin Android release AAR" -reject_zip_entry "$kotlin_aar" 'assets/oliphaunt/static-registry/archives/' \ - "Kotlin Android release AAR must not ship build-only static extension archives" - -if [ "${#selected_stems[@]}" -gt 0 ]; then - kotlin_extension_library="$kotlin_build_root/oliphaunt/intermediates/cxx/RelWithDebInfo" - kotlin_extension_library="$(find "$kotlin_extension_library" -path '*/obj/arm64-v8a/liboliphaunt_extensions.so' -print -quit)" - require_library_symbol "$kotlin_extension_library" liboliphaunt_selected_static_extensions -fi - -run "$kotlin_gradle" -p src/sdks/react-native/android assembleDebug \ - -PoliphauntReactNativePackageRuntime=true \ - -PoliphauntRuntimeResourcesDir="$resource_output" \ - -PoliphauntAndroidJniLibsDir="$jni_root" \ - -PoliphauntAndroidExtensionArchivesDir="$root/target/liboliphaunt-pg18-android-arm64/out" \ - -PoliphauntAndroidAbiFilters=arm64-v8a \ - -PoliphauntKotlinSdkDir="$root/src/sdks/kotlin/oliphaunt" \ - -PoliphauntBuildRoot="$rn_build_root" \ - -PoliphauntCxxBuildRoot="$rn_cxx_root" \ - --project-cache-dir "$rn_cache_root" \ - --no-configuration-cache - -rn_aar="$rn_build_root/root/outputs/aar/oliphaunt-react-native-android-debug.aar" -require_selected_extension_controls "$rn_aar" "React Native Android AAR" -reject_unselected_extension_controls "$rn_aar" "React Native Android AAR" -if [ "${#selected_stems[@]}" -gt 0 ]; then - require_zip_entry "$rn_aar" 'jni/arm64-v8a/liboliphaunt_extensions\.so$' \ - "React Native Android AAR must include selected-extension support library" - reject_zip_entry "$rn_aar" 'assets/oliphaunt/static-registry/archives/' \ - "React Native Android AAR must not ship build-only static extension archives" - rn_extension_library="$rn_build_root/root/intermediates/cxx/Debug" - rn_extension_library="$(find "$rn_extension_library" -path '*/obj/arm64-v8a/liboliphaunt_extensions.so' -print -quit)" - require_library_symbol "$rn_extension_library" liboliphaunt_selected_static_extensions -fi - -printf '\nmobile extension artifact checks passed for %s\n' "$selected_csv" diff --git a/tools/policy/check-native-boundaries.mjs b/tools/policy/check-native-boundaries.mjs deleted file mode 100644 index 79123dd66..000000000 --- a/tools/policy/check-native-boundaries.mjs +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/bin/env bun -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); -const errors = []; - -const legacyPackageNames = new Set([ - 'oliphaunt-wasix', - 'liboliphaunt-wasix-portable', - 'oliphaunt-wasix-tools', -]); -const legacyNamePrefixes = [ - 'liboliphaunt-wasix-aot-', - 'oliphaunt-wasix-tools-aot-', -]; -const legacyRuntimeNames = new Set([ - 'wasmer', - 'wasmer-wasix', - 'wasmer-vfs', - 'wasmer-types', - 'wasmer-headless', -]); -const legacyPathFragments = [ - 'src/bindings/wasix-rust/crates/oliphaunt-wasix', - 'src/runtimes/liboliphaunt/wasix/crates/assets', - 'src/runtimes/liboliphaunt/wasix/crates/aot', - 'src/runtimes/liboliphaunt/wasix/crates/tools', - 'src/runtimes/liboliphaunt/wasix/crates/tools-aot', -]; - -function rel(file) { - return path.relative(root, file).split(path.sep).join('/'); -} - -function readText(relativePath) { - return fs.readFileSync(path.join(root, relativePath), 'utf8'); -} - -function readToml(relativePath) { - return Bun.TOML.parse(readText(relativePath)); -} - -function readJson(relativePath) { - return JSON.parse(readText(relativePath)); -} - -function isPlainObject(value) { - return value !== null && typeof value === 'object' && !Array.isArray(value); -} - -function* dependencyTables(manifest) { - for (const tableName of ['dependencies', 'dev-dependencies', 'build-dependencies']) { - yield [tableName, isPlainObject(manifest[tableName]) ? manifest[tableName] : {}]; - } - const targetTables = isPlainObject(manifest.target) ? manifest.target : {}; - for (const [cfg, table] of Object.entries(targetTables)) { - if (!isPlainObject(table)) { - continue; - } - for (const tableName of ['dependencies', 'dev-dependencies', 'build-dependencies']) { - yield [`target.${cfg}.${tableName}`, isPlainObject(table[tableName]) ? table[tableName] : {}]; - } - } -} - -function dependencyName(depKey, spec) { - return isPlainObject(spec) && typeof spec.package === 'string' ? spec.package : depKey; -} - -function dependencyPath(spec) { - return isPlainObject(spec) && typeof spec.path === 'string' ? spec.path : null; -} - -function isBlockedRustDependency(name) { - return ( - legacyPackageNames.has(name) || - legacyRuntimeNames.has(name) || - legacyNamePrefixes.some(prefix => name.startsWith(prefix)) - ); -} - -function pathInsideFragment(relativePath, fragment) { - return relativePath === fragment || relativePath.startsWith(`${fragment}/`); -} - -function checkNativeRustManifest(relativePath) { - const manifestPath = path.join(root, relativePath); - const manifest = readToml(relativePath); - for (const [tableName, deps] of dependencyTables(manifest)) { - for (const [depKey, spec] of Object.entries(deps)) { - const name = dependencyName(depKey, spec); - if (isBlockedRustDependency(name)) { - errors.push(`${relativePath} ${tableName}.${depKey} depends on legacy runtime resources ${JSON.stringify(name)}`); - } - const pathValue = dependencyPath(spec); - if (pathValue === null) { - continue; - } - const dependencyTarget = path.resolve(path.dirname(manifestPath), pathValue); - const dependencyTargetRel = rel(dependencyTarget); - if (legacyPathFragments.some(fragment => pathInsideFragment(dependencyTargetRel, fragment))) { - errors.push(`${relativePath} ${tableName}.${depKey} points at legacy path ${dependencyTargetRel}`); - } - } - } -} - -function checkJsonManifest(relativePath) { - const manifest = readJson(relativePath); - for (const tableName of ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']) { - const deps = isPlainObject(manifest[tableName]) ? manifest[tableName] : {}; - for (const name of Object.keys(deps)) { - if (legacyPackageNames.has(name) || legacyNamePrefixes.some(prefix => name.startsWith(prefix))) { - errors.push(`${relativePath} ${tableName}.${name} depends on legacy WASIX package`); - } - } - } -} - -function rejectManifestText(relativePath, patterns) { - const text = readText(relativePath); - for (const [label, pattern] of patterns) { - if (new RegExp(pattern, 'i').test(text)) { - errors.push(`${relativePath} contains blocked native-boundary reference: ${label}`); - } - } -} - -function checkToolCrateBoundaries() { - const manifest = readToml('tools/xtask/Cargo.toml'); - const features = isPlainObject(manifest.features) ? manifest.features : {}; - const dependencies = isPlainObject(manifest.dependencies) ? manifest.dependencies : {}; - - if (JSON.stringify(features.default ?? null) !== '[]') { - errors.push('tools/xtask/Cargo.toml must keep the default feature set empty'); - } - if ('perf' in features) { - errors.push('tools/xtask/Cargo.toml must not define product-aware feature "perf"; use tools/perf/runner'); - } - - const forbiddenXtaskDependencies = [ - 'directories', - 'futures-util', - 'oliphaunt', - 'oliphaunt-wasix', - 'rusqlite', - 'sqlx', - 'tokio-postgres', - ]; - for (const depName of forbiddenXtaskDependencies) { - if (depName in dependencies) { - errors.push(`tools/xtask/Cargo.toml must not depend on product/perf crate ${JSON.stringify(depName)}; use tools/perf/runner`); - } - } - - for (const depName of ['wasmer', 'wasmer-types', 'wasmer-wasix', 'webc', 'tokio']) { - const spec = dependencies[depName]; - if (!isPlainObject(spec) || spec.optional !== true) { - errors.push(`tools/xtask/Cargo.toml dependency ${JSON.stringify(depName)} must stay optional so default xtask builds do not compile template/AOT runtime support`); - } - } - - const perfManifest = readToml('tools/perf/runner/Cargo.toml'); - const perfFeatures = isPlainObject(perfManifest.features) ? perfManifest.features : {}; - const perfDependencies = isPlainObject(perfManifest.dependencies) ? perfManifest.dependencies : {}; - if (JSON.stringify(perfFeatures.default ?? null) !== '[]') { - errors.push('tools/perf/runner/Cargo.toml must keep the default feature set empty'); - } - for (const depName of ['oliphaunt', 'rusqlite', 'sqlx', 'tokio-postgres']) { - if (!(depName in perfDependencies)) { - errors.push(`tools/perf/runner/Cargo.toml must own benchmark dependency ${JSON.stringify(depName)}`); - } - } - for (const [depName, spec] of Object.entries(perfDependencies)) { - if (isPlainObject(spec) && typeof spec.path === 'string' && 'version' in spec) { - errors.push( - `tools/perf/runner/Cargo.toml path dependency ${JSON.stringify(depName)} must not declare a registry version; ` + - 'the unpublished perf runner must resolve the checked-out workspace source', - ); - } - } - - const wasixRunner = new Set(Array.isArray(features['wasix-runner']) ? features['wasix-runner'] : []); - for (const depName of ['dep:wasmer', 'dep:wasmer-wasix', 'dep:webc']) { - if (!wasixRunner.has(depName)) { - errors.push(`tools/xtask/Cargo.toml wasix-runner feature must explicitly gate ${depName}`); - } - } - - const aotSerializer = new Set(Array.isArray(features['aot-serializer']) ? features['aot-serializer'] : []); - if (!aotSerializer.has('dep:wasmer-types')) { - errors.push('tools/xtask/Cargo.toml aot-serializer feature must explicitly gate dep:wasmer-types'); - } -} - -function* walkFiles(relativeRoots, suffixes) { - const suffixSet = new Set(suffixes); - for (const relativeRoot of relativeRoots) { - const start = path.join(root, relativeRoot); - if (!fs.existsSync(start)) { - errors.push(`missing expected native boundary path: ${relativeRoot}`); - continue; - } - const stack = [start]; - while (stack.length > 0) { - const current = stack.pop(); - const entries = fs.readdirSync(current, { withFileTypes: true }).sort((left, right) => - right.name < left.name ? -1 : right.name > left.name ? 1 : 0); - for (const entry of entries) { - const file = path.join(current, entry.name); - if (entry.isDirectory()) { - stack.push(file); - } else if (entry.isFile() && suffixSet.has(path.extname(file))) { - yield file; - } - } - } - } -} - -checkNativeRustManifest('src/sdks/rust/Cargo.toml'); -checkJsonManifest('src/sdks/react-native/package.json'); -checkJsonManifest('examples/react-native-expo/package.json'); -checkToolCrateBoundaries(); - -const manifestTextPatterns = [ - ['oliphaunt-wasix package', String.raw`\boliphaunt-wasix\b`], - ['WASIX runtime', String.raw`\bwasix\b`], - ['Wasmer runtime', String.raw`\bwasmer\b`], -]; -for (const manifestPath of [ - 'src/sdks/swift/Package.swift', - 'src/sdks/react-native/OliphauntReactNative.podspec', - 'src/sdks/kotlin/build.gradle.kts', - 'src/sdks/kotlin/oliphaunt/build.gradle.kts', - 'src/sdks/react-native/android/build.gradle', - 'src/sdks/react-native/android/settings.gradle', -]) { - rejectManifestText(manifestPath, manifestTextPatterns); -} - -const sourcePatterns = [ - ['Rust import of legacy crate', String.raw`\b(use|extern\s+crate)\s+oliphaunt_wasix\b`], - ['Rust path to legacy crate', String.raw`\boliphaunt_wasix::`], - ['JavaScript import of legacy package', String.raw`\b(import|require)\s*(?:.+?\s+from\s*)?['"]oliphaunt-wasix['"]`], - ['Swift/Kotlin legacy module import', String.raw`\bimport\s+OliphauntWasm\b`], -]; -for (const filePath of walkFiles( - [ - 'src/sdks/rust/src', - 'src/sdks/rust/tests', - 'src/runtimes/liboliphaunt/native/include', - 'src/runtimes/liboliphaunt/native/src', - 'src/sdks/swift/Sources', - 'src/sdks/swift/Tests', - 'src/sdks/kotlin/oliphaunt/src', - 'src/sdks/react-native/src', - 'src/sdks/react-native/ios', - 'src/sdks/react-native/android/src', - ], - ['.rs', '.c', '.h', '.swift', '.kt', '.java', '.ts', '.tsx', '.m', '.mm', '.cpp'], -)) { - const text = fs.readFileSync(filePath, 'utf8'); - for (const [label, pattern] of sourcePatterns) { - if (new RegExp(pattern).test(text)) { - errors.push(`${rel(filePath)} contains blocked native-boundary code reference: ${label}`); - } - } -} - -const sdkManifest = readToml('tools/policy/sdk-manifest.toml'); -const expectedPaths = { - rust: 'src/sdks/rust', - swift: 'src/sdks/swift', - kotlin: 'src/sdks/kotlin', - 'react-native': 'src/sdks/react-native', -}; -const seenPaths = new Map(); -const sdkSections = isPlainObject(sdkManifest.sdks) ? sdkManifest.sdks : {}; -for (const [sdk, expectedPath] of Object.entries(expectedPaths)) { - const section = sdkSections[sdk]; - if (!isPlainObject(section)) { - errors.push(`tools/policy/sdk-manifest.toml is missing [sdks.${sdk}]`); - continue; - } - const actualPath = section.implementation_path; - if (actualPath !== expectedPath) { - errors.push(`tools/policy/sdk-manifest.toml [sdks.${sdk}].implementation_path is ${JSON.stringify(actualPath)}; expected ${JSON.stringify(expectedPath)}`); - } - if (seenPaths.has(actualPath)) { - errors.push(`tools/policy/sdk-manifest.toml shares implementation_path ${JSON.stringify(actualPath)} between ${seenPaths.get(actualPath)} and ${sdk}`); - } - seenPaths.set(actualPath, sdk); -} - -const reactNative = isPlainObject(sdkSections['react-native']) ? sdkSections['react-native'] : {}; -if (reactNative.runtime_owner !== false) { - errors.push('React Native SDK must stay a delegating adapter with runtime_owner = false'); -} -if (reactNative.delegates_apple_to !== 'swift') { - errors.push('React Native Apple runtime delegation must point at the Swift SDK'); -} -if (reactNative.delegates_android_to !== 'kotlin') { - errors.push('React Native Android runtime delegation must point at the Kotlin SDK'); -} - -if (errors.length > 0) { - console.error('native product boundary violations:'); - for (const error of errors) { - console.error(` - ${error}`); - } - process.exit(1); -} - -console.log('native product boundaries ok'); diff --git a/tools/policy/check-policy-tools.sh b/tools/policy/check-policy-tools.sh deleted file mode 100755 index 8f18fa7bf..000000000 --- a/tools/policy/check-policy-tools.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -run() { - printf '\n==> %s\n' "$*" - "$@" -} - -while IFS= read -r script; do - case "$(head -n 1 "$script")" in - '#!/usr/bin/env bash') - run bash -n "$script" - ;; - '#!/usr/bin/env sh') - run sh -n "$script" - ;; - esac -done < <(find tools/policy -type f -name '*.sh' | LC_ALL=C sort) - -js_check_root="$(mktemp -d)" -cleanup() { - rm -rf "$js_check_root" -} -trap cleanup EXIT HUP INT TERM - -js_files=() -while IFS= read -r script; do - js_files+=("$script") -done < <( - { - find .github/scripts examples/tools tools/policy tools/graph -type f -name '*.mjs' - printf '%s\n' src/runtimes/liboliphaunt/native/tools/build-ci-target.mjs - } | LC_ALL=C sort -) -run bun build "${js_files[@]}" --target=bun --root "$root" --outdir="$js_check_root/js" - -python_files=() -while IFS= read -r script; do - python_files+=("$script") -done < <(find tools/policy -type f -name '*.py' | LC_ALL=C sort) - -if ((${#python_files[@]} > 0)); then - run env \ - PYTHONPYCACHEPREFIX="$js_check_root/python-pycache" \ - python3 -m py_compile "${python_files[@]}" -fi diff --git a/tools/policy/check-release-intent.test.mjs b/tools/policy/check-release-intent.test.mjs deleted file mode 100644 index 8af4bb192..000000000 --- a/tools/policy/check-release-intent.test.mjs +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtempSync, rmSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { after, test } from "node:test"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const SCRIPT = path.join(ROOT, ".github/scripts/check-release-intent.sh"); - -function command(commandName, args, options = {}) { - const result = spawnSync(commandName, args, { - cwd: ROOT, - encoding: "utf8", - ...options, - }); - if (result.error || result.status !== 0) { - throw new Error( - result.stderr?.trim() - || result.error?.message - || `${commandName} ${args.join(" ")} exited ${String(result.status)}`, - ); - } - return result.stdout.trim(); -} - -const alternateObjects = command( - "git", - ["rev-parse", "--path-format=absolute", "--git-path", "objects"], -); -const isolatedObjects = mkdtempSync(path.join(tmpdir(), "oliphaunt-release-intent-objects-")); -const gitEnvironment = { - ...process.env, - GIT_OBJECT_DIRECTORY: isolatedObjects, - GIT_ALTERNATE_OBJECT_DIRECTORIES: [ - alternateObjects, - process.env.GIT_ALTERNATE_OBJECT_DIRECTORIES, - ].filter(Boolean).join(path.delimiter), -}; - -after(() => { - rmSync(isolatedObjects, { recursive: true, force: true }); -}); - -function commitTree(subject, timestamp, parent = "HEAD") { - const tree = command("git", ["rev-parse", `${parent}^{tree}`], { env: gitEnvironment }); - return command( - "git", - ["commit-tree", tree, "-p", parent], - { - input: `${subject}\n`, - env: { - ...gitEnvironment, - GIT_AUTHOR_NAME: "Release Intent Test", - GIT_AUTHOR_EMAIL: "release-intent@example.invalid", - GIT_AUTHOR_DATE: timestamp, - GIT_COMMITTER_NAME: "Release Intent Test", - GIT_COMMITTER_EMAIL: "release-intent@example.invalid", - GIT_COMMITTER_DATE: timestamp, - }, - }, - ); -} - -function releaseIntent({ - base, - branch = "main", - eventName = "workflow_dispatch", - fullRef = "refs/heads/main", - head, - subject = "fix: validate release intent", -}) { - const result = spawnSync( - "bash", - [SCRIPT, subject, base, head, branch, eventName, fullRef], - { - cwd: ROOT, - encoding: "utf8", - env: gitEnvironment, - }, - ); - return { - status: result.status, - output: `${result.stdout}${result.stderr}`, - }; -} - -const firstChild = commitTree("fix: validate release intent", "2026-01-01T00:00:01Z"); -const siblingChild = commitTree("fix: validate release intent", "2026-01-01T00:00:02Z"); - -test("accepts a manual main dispatch against its exact parent", { timeout: 20_000 }, () => { - const result = releaseIntent({ base: "HEAD", head: firstChild }); - assert.equal(result.status, 0, result.output); -}); - -test("rejects a manual main dispatch whose base is not its exact parent", () => { - const result = releaseIntent({ base: "HEAD^", head: firstChild }); - assert.equal(result.status, 1, result.output); - assert.match(result.output, /base must resolve to the exact commit parent/u); -}); - -test("rejects a non-fast-forward comparison", () => { - const result = releaseIntent({ - base: firstChild, - branch: "feature", - eventName: "push", - fullRef: "refs/heads/feature", - head: siblingChild, - }); - assert.equal(result.status, 1, result.output); - assert.match(result.output, /is not an ancestor/u); -}); - -test("manual main dispatch requires matching branch identities", () => { - const result = releaseIntent({ - base: "HEAD", - branch: "main", - fullRef: "refs/heads/diagnostic", - head: firstChild, - }); - assert.equal(result.status, 1, result.output); - assert.match(result.output, /requires matching main branch and full ref/u); -}); diff --git a/tools/policy/check-rust-helper-crates.mjs b/tools/policy/check-rust-helper-crates.mjs deleted file mode 100644 index 320cef1f3..000000000 --- a/tools/policy/check-rust-helper-crates.mjs +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bun - -import { readFileSync } from "node:fs"; - -const failures = []; -for await (const file of new Bun.Glob("tools/**/Cargo.toml").scan({ dot: true })) { - const manifest = Bun.TOML.parse(readFileSync(file, "utf8")); - if (manifest.package?.publish !== false) { - failures.push(file); - } -} - -if (failures.length > 0) { - console.error(`internal Rust tools must set package.publish = false:\n${failures.join("\n")}`); - process.exit(1); -} - -console.log("internal Rust tools are not publishable"); diff --git a/tools/policy/check-rust-lint.mjs b/tools/policy/check-rust-lint.mjs deleted file mode 100755 index 8a7d1869f..000000000 --- a/tools/policy/check-rust-lint.mjs +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bun -import { chdirRepoRoot, run } from "./lib/run-command.mjs"; - -const PREFIX = "check-rust-lint.mjs"; - -chdirRepoRoot(PREFIX); -run(PREFIX, "bash", ["tools/policy/check-dependency-invariants.sh"], { - announce: true, -}); -run( - PREFIX, - "cargo", - ["clippy", "--workspace", "--all-targets", "--locked", "--", "-D", "warnings"], - { announce: true }, -); diff --git a/tools/policy/check-sdk-header-copies.mjs b/tools/policy/check-sdk-header-copies.mjs deleted file mode 100755 index 124dc324d..000000000 --- a/tools/policy/check-sdk-header-copies.mjs +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bun - -import {readFileSync} from 'node:fs'; - -const canonicalPath = 'src/runtimes/liboliphaunt/native/include/oliphaunt.h'; -const copies = [ - 'src/sdks/kotlin/oliphaunt/src/androidMain/cpp/include/oliphaunt.h', - 'src/sdks/swift/Sources/COliphaunt/include/oliphaunt.h', - 'src/sdks/react-native/android/src/main/cpp/include/oliphaunt.h', -]; - -const canonical = readFileSync(canonicalPath); -const stale = copies.filter(copy => !readFileSync(copy).equals(canonical)); - -if (stale.length > 0) { - for (const copy of stale) { - console.error(`${copy} must be byte-identical to ${canonicalPath}`); - } - process.exit(1); -} - -console.log(`C ABI header copies verified (${copies.length} package copies).`); diff --git a/tools/policy/check-sdk-manifest.mjs b/tools/policy/check-sdk-manifest.mjs deleted file mode 100644 index 0ba7383b2..000000000 --- a/tools/policy/check-sdk-manifest.mjs +++ /dev/null @@ -1,348 +0,0 @@ -#!/usr/bin/env bun - -import { existsSync, readFileSync, statSync } from 'node:fs'; - -import { loadGraph } from '../release/release-graph.mjs'; - -const manifestPath = 'tools/policy/sdk-manifest.toml'; -const parityPolicyPath = 'docs/maintainers/sdk-parity-policy.md'; -const deferredIds = [ - 'FUTURE-EXTENSION-MIGRATION', - 'FUTURE-NATIVE-SERVER-SDK-BACKUP', - 'FUTURE-SWIFT-MACOS-SERVER-TOOLS', - 'FUTURE-RESTORE-REPLACE', - 'FUTURE-WASIX-CANCELLATION', - 'FUTURE-WASIX-DIRECT-COPY', -]; -const releaseProducts = loadGraph('check-sdk-manifest.mjs').products; -const releaseSdkProducts = Object.values(releaseProducts).filter((product) => product.kind === 'sdk'); -const requiredFields = new Set([ - 'package_identity', - 'implementation_path', - 'documentation_path', - 'consumer_targets', - 'runtime_owner', - 'runtime_boundary', - 'surfaces', -]); -const optionalFields = new Set(['delegates_apple_to', 'delegates_android_to']); -const stringFields = new Set([ - 'package_identity', - 'implementation_path', - 'documentation_path', - 'runtime_boundary', -]); -const listFields = new Set(['consumer_targets']); -const requiredSurfaceFields = new Set([ - 'id', - 'entrypoint', - 'calling_contract', - 'execution_owner', - 'main_safe', - 'topologies', -]); -const knownTopologies = new Set([ - 'native-direct', - 'native-broker', - 'native-server', - 'wasix-direct', - 'wasix-server', -]); -const knownCallingContracts = new Set(['async', 'sync']); -const knownExecutionOwners = new Set([ - 'caller', - 'platform-sdk', - 'sdk-runtime', - 'sdk-thread', - 'sdk-worker', -]); -const errors = []; - -function fail(message) { - console.error(`check-sdk-manifest.mjs: ${message}`); - process.exit(1); -} - -function usage() { - console.log('usage: tools/policy/check-sdk-manifest.mjs [--list] [--json]'); -} - -function isPlainObject(value) { - return value !== null && typeof value === 'object' && !Array.isArray(value); -} - -function formatValue(value) { - return JSON.stringify(value); -} - -function releaseRegistryIdentity(packageIdentity) { - return packageIdentity.startsWith('cargo:') - ? `crates:${packageIdentity.slice('cargo:'.length)}` - : packageIdentity; -} - -function requireDirectory(relativePath, sdkId, field) { - if (!existsSync(relativePath)) { - errors.push(`[sdks.${sdkId}].${field} points at missing path ${formatValue(relativePath)}`); - } else if (!statSync(relativePath).isDirectory()) { - errors.push(`[sdks.${sdkId}].${field} must point at a directory: ${formatValue(relativePath)}`); - } -} - -const args = process.argv.slice(2); -if (args.includes('--help')) { - usage(); - process.exit(0); -} -if (args.length > 1) fail(`expected at most one option, got ${args.join(' ')}`); -const mode = args[0] ?? 'check'; -if (!['check', '--list', '--json'].includes(mode)) fail(`unknown option: ${mode}`); - -const manifest = Bun.TOML.parse(readFileSync(manifestPath, 'utf8')); -const parityPolicy = readFileSync(parityPolicyPath, 'utf8'); -const actualDeferredIds = [...parityPolicy.matchAll(/\bFUTURE-[A-Z0-9-]+\b/g)].map(([id]) => id); -const expectedDeferredIds = [...deferredIds].sort(); -if ( - actualDeferredIds.length !== deferredIds.length - || [...actualDeferredIds].sort().some((id, index) => id !== expectedDeferredIds[index]) -) { - errors.push( - `${parityPolicyPath} must contain each canonical deferred ID exactly once; found ${formatValue(actualDeferredIds)}`, - ); -} -if (manifest.schema_version !== 6) { - errors.push(`schema_version is ${formatValue(manifest.schema_version)}; expected 6`); -} -if (!isPlainObject(manifest.sdks)) errors.push('manifest must contain an [sdks] table'); - -const sdks = isPlainObject(manifest.sdks) ? manifest.sdks : {}; -const sdkIds = Object.keys(sdks).sort(); -if (sdkIds.length === 0) errors.push('manifest must register at least one SDK'); - -const seenImplementationPaths = new Map(); -const seenPackageIdentities = new Map(); -for (const sdkId of sdkIds) { - const sdk = sdks[sdkId]; - if (!isPlainObject(sdk)) { - errors.push(`[sdks.${sdkId}] must be a table`); - continue; - } - for (const field of requiredFields) { - if (!(field in sdk)) errors.push(`[sdks.${sdkId}] is missing required field ${field}`); - } - for (const field of Object.keys(sdk)) { - if (!requiredFields.has(field) && !optionalFields.has(field)) { - errors.push(`[sdks.${sdkId}] has unknown field ${field}`); - } - } - for (const field of stringFields) { - if (typeof sdk[field] !== 'string' || sdk[field].length === 0) { - errors.push(`[sdks.${sdkId}].${field} must be a non-empty string`); - } - } - for (const field of listFields) { - const value = sdk[field]; - if (!Array.isArray(value) || value.length === 0 || !value.every((item) => typeof item === 'string' && item.length > 0)) { - errors.push(`[sdks.${sdkId}].${field} must be a non-empty list of non-empty strings`); - } else if (new Set(value).size !== value.length) { - errors.push(`[sdks.${sdkId}].${field} must not contain duplicates`); - } - } - if (!Array.isArray(sdk.surfaces) || sdk.surfaces.length === 0) { - errors.push(`[sdks.${sdkId}].surfaces must be a non-empty array of surface tables`); - } else { - const seenSurfaceIds = new Set(); - for (const [surfaceIndex, surface] of sdk.surfaces.entries()) { - const location = `[sdks.${sdkId}].surfaces[${surfaceIndex}]`; - if (!isPlainObject(surface)) { - errors.push(`${location} must be a table`); - continue; - } - for (const field of requiredSurfaceFields) { - if (!(field in surface)) errors.push(`${location} is missing required field ${field}`); - } - for (const field of Object.keys(surface)) { - if (!requiredSurfaceFields.has(field)) errors.push(`${location} has unknown field ${field}`); - } - for (const field of ['id', 'entrypoint', 'calling_contract', 'execution_owner']) { - if (typeof surface[field] !== 'string' || surface[field].length === 0) { - errors.push(`${location}.${field} must be a non-empty string`); - } - } - if (typeof surface.id === 'string') { - if (seenSurfaceIds.has(surface.id)) { - errors.push(`${location}.id duplicates surface ${formatValue(surface.id)}`); - } - seenSurfaceIds.add(surface.id); - } - if (!knownCallingContracts.has(surface.calling_contract)) { - errors.push(`${location}.calling_contract contains unknown contract ${formatValue(surface.calling_contract)}`); - } - if (!knownExecutionOwners.has(surface.execution_owner)) { - errors.push(`${location}.execution_owner contains unknown owner ${formatValue(surface.execution_owner)}`); - } - if (typeof surface.main_safe !== 'boolean') { - errors.push(`${location}.main_safe must be a boolean`); - } - if (surface.calling_contract === 'sync' && surface.main_safe !== false) { - errors.push(`${location} synchronous database surfaces must declare main_safe = false`); - } - if ( - !Array.isArray(surface.topologies) - || surface.topologies.length === 0 - || !surface.topologies.every((topology) => typeof topology === 'string' && topology.length > 0) - ) { - errors.push(`${location}.topologies must be a non-empty list of non-empty strings`); - } else { - if (new Set(surface.topologies).size !== surface.topologies.length) { - errors.push(`${location}.topologies must not contain duplicates`); - } - for (const topology of surface.topologies) { - if (!knownTopologies.has(topology)) { - errors.push(`${location}.topologies contains unknown topology ${formatValue(topology)}`); - } - } - } - } - if (!seenSurfaceIds.has('default')) { - errors.push(`[sdks.${sdkId}].surfaces must contain a default surface`); - } - } - if (typeof sdk.runtime_owner !== 'boolean') { - errors.push(`[sdks.${sdkId}].runtime_owner must be a boolean`); - } - if (typeof sdk.package_identity === 'string') { - if (!sdk.package_identity.includes(':')) { - errors.push(`[sdks.${sdkId}].package_identity must include its registry kind`); - } else if (seenPackageIdentities.has(sdk.package_identity)) { - errors.push( - `[sdks.${sdkId}].package_identity duplicates [sdks.${seenPackageIdentities.get(sdk.package_identity)}] identity ${formatValue(sdk.package_identity)}`, - ); - } - seenPackageIdentities.set(sdk.package_identity, sdkId); - } - if (typeof sdk.implementation_path === 'string') { - if (seenImplementationPaths.has(sdk.implementation_path)) { - errors.push( - `[sdks.${sdkId}].implementation_path duplicates [sdks.${seenImplementationPaths.get(sdk.implementation_path)}] path ${formatValue(sdk.implementation_path)}`, - ); - } - seenImplementationPaths.set(sdk.implementation_path, sdkId); - requireDirectory(sdk.implementation_path, sdkId, 'implementation_path'); - if ( - typeof sdk.package_identity === 'string' - && sdk.package_identity.startsWith('npm:') - && Array.isArray(sdk.surfaces) - ) { - const packageFile = `${sdk.implementation_path}/package.json`; - if (!existsSync(packageFile)) { - errors.push(`[sdks.${sdkId}] npm implementation has no package.json`); - } else { - const packageManifest = JSON.parse(readFileSync(packageFile, 'utf8')); - const packageName = sdk.package_identity.slice('npm:'.length); - for (const surface of sdk.surfaces) { - if (!isPlainObject(surface) || typeof surface.entrypoint !== 'string') continue; - const exportKey = surface.entrypoint === packageName - ? '.' - : surface.entrypoint.startsWith(`${packageName}/`) - ? `./${surface.entrypoint.slice(packageName.length + 1)}` - : undefined; - if (exportKey === undefined) { - errors.push( - `[sdks.${sdkId}] surface ${formatValue(surface.id)} entrypoint ${formatValue(surface.entrypoint)} is outside package ${formatValue(packageName)}`, - ); - } else if (!isPlainObject(packageManifest.exports) || !(exportKey in packageManifest.exports)) { - errors.push( - `[sdks.${sdkId}] surface ${formatValue(surface.id)} entrypoint ${formatValue(surface.entrypoint)} is missing package export ${formatValue(exportKey)}`, - ); - } - } - } - } - } - if (typeof sdk.documentation_path === 'string') { - requireDirectory(sdk.documentation_path, sdkId, 'documentation_path'); - } -} - -const releaseSdkByPath = new Map(); -for (const product of releaseSdkProducts) { - if (releaseSdkByPath.has(product.path)) { - errors.push(`release SDK products ${releaseSdkByPath.get(product.path).id} and ${product.id} share path ${formatValue(product.path)}`); - } - releaseSdkByPath.set(product.path, product); - if (!seenImplementationPaths.has(product.path)) { - errors.push(`release SDK product ${product.id} at ${formatValue(product.path)} is missing from the SDK manifest`); - } -} -for (const sdkId of sdkIds) { - const sdk = sdks[sdkId]; - if (!isPlainObject(sdk) || typeof sdk.implementation_path !== 'string') continue; - const product = releaseSdkByPath.get(sdk.implementation_path); - if (product === undefined) { - errors.push(`[sdks.${sdkId}] path ${formatValue(sdk.implementation_path)} is not an SDK product in the release graph`); - } else if ( - Array.isArray(product.registry_packages) - && product.registry_packages.length > 0 - && !product.registry_packages.includes(releaseRegistryIdentity(sdk.package_identity)) - ) { - errors.push(`[sdks.${sdkId}].package_identity ${formatValue(sdk.package_identity)} is not published by release SDK product ${product.id}`); - } -} - -for (const sdkId of sdkIds) { - const sdk = sdks[sdkId]; - if (!isPlainObject(sdk)) continue; - let delegationCount = 0; - for (const field of ['delegates_apple_to', 'delegates_android_to']) { - const delegate = sdk[field]; - if (delegate === undefined) continue; - delegationCount += 1; - if (typeof delegate !== 'string' || !(delegate in sdks)) { - errors.push(`[sdks.${sdkId}].${field} points at unknown SDK ${formatValue(delegate)}`); - } else if (sdks[delegate]?.runtime_owner !== true) { - errors.push(`[sdks.${sdkId}].${field} must point at a runtime-owning SDK`); - } - } - if (sdk.runtime_owner === false && delegationCount === 0) { - errors.push(`[sdks.${sdkId}] does not own a runtime and must declare delegation`); - } - if (sdk.runtime_owner === true && delegationCount > 0) { - errors.push(`[sdks.${sdkId}] owns its runtime and must not declare delegation`); - } -} - -if (errors.length > 0) { - for (const error of errors) console.error(`check-sdk-manifest.mjs: ${error}`); - process.exit(1); -} - -if (mode === '--json') { - console.log(JSON.stringify({ - schemaVersion: manifest.schema_version, - sdkCount: sdkIds.length, - sdks: Object.fromEntries(sdkIds.map((sdkId) => [sdkId, { - packageIdentity: sdks[sdkId].package_identity, - runtimeOwner: sdks[sdkId].runtime_owner, - surfaces: sdks[sdkId].surfaces.map((surface) => ({ - id: surface.id, - entrypoint: surface.entrypoint, - callingContract: surface.calling_contract, - executionOwner: surface.execution_owner, - mainSafe: surface.main_safe, - topologies: surface.topologies, - })), - consumerTargets: sdks[sdkId].consumer_targets, - }])), - }, null, 2)); -} else if (mode === '--list') { - for (const sdkId of sdkIds) { - const sdk = sdks[sdkId]; - const surfaces = sdk.surfaces - .map((surface) => `${surface.id}:${surface.calling_contract}/${surface.execution_owner}[${surface.topologies.join(',')}]`) - .join(' '); - console.log(`${sdkId}: surfaces=${surfaces} targets=${sdk.consumer_targets.join(',')}`); - } -} else { - console.log(`SDK manifest contract verified (${sdkIds.length} SDKs).`); -} diff --git a/tools/policy/check-semver.mjs b/tools/policy/check-semver.mjs deleted file mode 100755 index 4eb76f047..000000000 --- a/tools/policy/check-semver.mjs +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env bun -import { readFileSync } from "node:fs"; - -import { chdirRepoRoot, run } from "./lib/run-command.mjs"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; - -const PREFIX = "check-semver.mjs"; -const PRODUCT_PATH = "src/bindings/wasix-rust/crates/oliphaunt-wasix"; -const MANIFEST_PATH = `${PRODUCT_PATH}/Cargo.toml`; -const RELEASE_MANIFEST = ".release-please-manifest.json"; - -function commandOutput(command, args) { - const result = captureCommandOutput(command, args, { - label: [command, ...args].join(" "), - }); - if (result.error) throw result.error; - if (result.status !== 0) { - throw new Error(`${[command, ...args].join(" ")} failed: ${result.stderr.trim()}`); - } - return result.stdout.trim(); -} - -function readJson(file) { - return JSON.parse(readFileSync(file, "utf8")); -} - -function parentReleaseVersion() { - const parentManifest = commandOutput("git", ["show", `HEAD^:${RELEASE_MANIFEST}`]); - return JSON.parse(parentManifest)[PRODUCT_PATH]; -} - -export function semverCheckPlan({ - currentVersion, - initialVersion, - parentVersion = null, - publicTags = [], -}) { - if (typeof currentVersion !== "string" || typeof initialVersion !== "string") { - throw new Error("current and initial versions must be strings"); - } - - if (publicTags.length > 0) { - if (currentVersion === "0.0.0") { - throw new Error("public product tags exist while the release manifest still says 0.0.0"); - } - return { kind: "registry" }; - } - - if (currentVersion === "0.0.0") { - return { kind: "unreleased" }; - } - - if (currentVersion !== initialVersion || parentVersion !== "0.0.0") { - throw new Error( - "no public product tag exists, but this is not the exact first-release transition " + - `(parent ${parentVersion ?? ""}, current ${currentVersion}, initial ${initialVersion})`, - ); - } - - return { kind: "first-release", baselineRev: "HEAD^" }; -} - -function main() { - chdirRepoRoot(PREFIX); - - const releaseManifest = readJson(RELEASE_MANIFEST); - const releaseConfig = readJson("release-please-config.json"); - const productConfig = releaseConfig.packages?.[PRODUCT_PATH]; - if (!productConfig?.component) { - throw new Error(`${PRODUCT_PATH} is missing a Release Please component`); - } - - const currentVersion = releaseManifest[PRODUCT_PATH]; - const publicTags = commandOutput("git", [ - "tag", - "--list", - `${productConfig.component}-v[0-9]*`, - ]) - .split("\n") - .filter(Boolean); - const parentVersion = - publicTags.length === 0 && currentVersion !== "0.0.0" ? parentReleaseVersion() : null; - const plan = semverCheckPlan({ - currentVersion, - initialVersion: releaseConfig["initial-version"], - parentVersion, - publicTags, - }); - - if (plan.kind === "unreleased") { - console.log( - "SemVer check passed: oliphaunt-wasix is explicitly unreleased at 0.0.0 and has no public API baseline.", - ); - return; - } - - const args = [ - "semver-checks", - "check-release", - "--package", - "oliphaunt-wasix", - "--manifest-path", - MANIFEST_PATH, - ]; - if (plan.kind === "first-release") { - args.push("--baseline-rev", plan.baselineRev); - } - run(PREFIX, "cargo", args); -} - -if (import.meta.main) main(); diff --git a/tools/policy/check-semver.test.mjs b/tools/policy/check-semver.test.mjs deleted file mode 100644 index ead6449cb..000000000 --- a/tools/policy/check-semver.test.mjs +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import test from "node:test"; - -import { semverCheckPlan } from "./check-semver.mjs"; - -const base = { - currentVersion: "0.0.0", - initialVersion: "0.1.0", - parentVersion: null, - publicTags: [], -}; - -test("an explicitly unreleased crate does not require a fictitious registry baseline", () => { - assert.deepEqual(semverCheckPlan(base), { kind: "unreleased" }); -}); - -test("the exact first release compares against its introduction parent", () => { - assert.deepEqual( - semverCheckPlan({ ...base, currentVersion: "0.1.0", parentVersion: "0.0.0" }), - { kind: "first-release", baselineRev: "HEAD^" }, - ); -}); - -test("a published product uses its registry baseline", () => { - assert.deepEqual( - semverCheckPlan({ ...base, currentVersion: "0.2.0", publicTags: ["oliphaunt-wasix-rust-v0.1.0"] }), - { kind: "registry" }, - ); -}); - -test("missing tags cannot silently turn a later release into a first release", () => { - assert.throws( - () => semverCheckPlan({ ...base, currentVersion: "0.2.0", parentVersion: "0.1.0" }), - /not the exact first-release transition/u, - ); - assert.throws( - () => semverCheckPlan({ ...base, currentVersion: "0.2.0", parentVersion: "0.0.0" }), - /not the exact first-release transition/u, - ); -}); - -test("public tags and an unreleased manifest are rejected as contradictory", () => { - assert.throws( - () => semverCheckPlan({ ...base, publicTags: ["oliphaunt-wasix-rust-v0.1.0"] }), - /public product tags exist/u, - ); -}); diff --git a/tools/policy/check-shared-fixtures.mjs b/tools/policy/check-shared-fixtures.mjs deleted file mode 100644 index 49e507fdc..000000000 --- a/tools/policy/check-shared-fixtures.mjs +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env bun - -import { existsSync, readFileSync } from 'node:fs'; -import path from 'node:path'; - -const root = path.resolve(import.meta.dir, '../..'); -const fixtureRoot = path.join(root, 'src/shared/fixtures'); -const manifestPath = path.join(fixtureRoot, 'manifest.toml'); -const manifest = Bun.TOML.parse(readFileSync(manifestPath, 'utf8')); -const errors = []; - -if (manifest.schema_version !== 1) { - errors.push('src/shared/fixtures/manifest.toml must declare schema_version = 1'); -} - -const fixtures = Array.isArray(manifest.fixtures) ? manifest.fixtures : []; -if (fixtures.length === 0) { - errors.push('src/shared/fixtures/manifest.toml must declare at least one fixture'); -} - -const ids = new Set(); -const paths = new Set(); -const canonical = []; -for (const fixture of fixtures) { - if (typeof fixture?.id !== 'string' || fixture.id.length === 0) { - errors.push('every shared fixture must declare a non-empty id'); - continue; - } - if (ids.has(fixture.id)) errors.push(`duplicate shared fixture id ${JSON.stringify(fixture.id)}`); - ids.add(fixture.id); - - if (typeof fixture?.path !== 'string' || fixture.path.length === 0) { - errors.push(`shared fixture ${JSON.stringify(fixture.id)} must declare a non-empty path`); - continue; - } - if (path.isAbsolute(fixture.path) || fixture.path.split('/').includes('..')) { - errors.push(`shared fixture ${JSON.stringify(fixture.id)} must stay inside src/shared/fixtures`); - continue; - } - if (paths.has(fixture.path)) { - errors.push(`duplicate shared fixture path ${JSON.stringify(fixture.path)}`); - } - paths.add(fixture.path); - - const absolute = path.join(fixtureRoot, fixture.path); - if (!existsSync(absolute)) { - errors.push(`missing shared fixture src/shared/fixtures/${fixture.path}`); - continue; - } - canonical.push({ absolute, relative: `src/shared/fixtures/${fixture.path}` }); -} - -for (const fixture of canonical) { - if (path.extname(fixture.absolute) === '.json') { - validateUniqueJsonKeys(readFileSync(fixture.absolute, 'utf8'), fixture.relative); - } -} - -validateQueryResponseContract(); -validateJsonKeyScannerSelfCheck(); - -if (errors.length > 0) { - for (const error of errors) console.error(`shared fixture contract: ${error}`); - process.exit(1); -} - -console.log(`shared fixture contract passed (${canonical.length} canonical fixtures)`); - -function validateQueryResponseContract() { - const relative = 'protocol/query-response-cases.json'; - const absolute = path.join(fixtureRoot, relative); - if (!existsSync(absolute)) return; - - let contract; - try { - contract = JSON.parse(readFileSync(absolute, 'utf8')); - } catch (error) { - errors.push(`${relative} must be valid JSON: ${error.message}`); - return; - } - if (contract.schemaVersion !== 1) { - errors.push(`${relative} must declare schemaVersion 1`); - } - if (contract.kind !== 'postgres-backend-query-response') { - errors.push(`${relative} must declare the postgres-backend-query-response kind`); - } - - const expectedTypeOids = { - xmlArray: 143, - charArray: 1002, - nameArray: 1003, - timetz: 1266, - timetzArray: 1270, - }; - for (const [name, value] of Object.entries(expectedTypeOids)) { - if (contract.typeOids?.[name] !== value) { - errors.push(`${relative} typeOids.${name} must equal ${value}`); - } - } - - if (!Array.isArray(contract.cases)) { - errors.push(`${relative} must declare a cases array`); - return; - } - const cases = new Map(); - for (const fixture of contract.cases) { - if (typeof fixture?.name !== 'string' || fixture.name.length === 0) { - errors.push(`${relative} cases must have non-empty names`); - continue; - } - if (cases.has(fixture.name)) { - errors.push(`${relative} has duplicate case ${JSON.stringify(fixture.name)}`); - } - cases.set(fixture.name, fixture); - } - - for (const name of [ - 'extended_controls_insert', - 'bare_empty_without_extended_controls', - 'async_controls_before_command', - ]) { - validateProtocolModes(relative, name, cases.get(name)?.protocolModeExpectation); - } - - const errorDiagnostic = - cases.get('postgres_error_localized_severity_is_primary')?.queryExpectation?.postgresError; - validateFiniteDiagnostic(relative, 'PostgreSQL error', errorDiagnostic, 'ERREUR', 'ERROR'); - - const notices = - cases.get('notice_with_finite_standard_diagnostics')?.queryExpectation?.ok?.notices; - if (!Array.isArray(notices) || notices.length !== 1) { - errors.push(`${relative} must declare exactly one finite standard notice diagnostic`); - } else { - validateFiniteDiagnostic(relative, 'PostgreSQL notice', notices[0], 'AVERTISSEMENT', 'WARNING'); - } -} - -function validateProtocolModes(relative, caseName, expectation) { - if (!expectation || typeof expectation !== 'object') { - errors.push(`${relative} case ${caseName} must declare protocolModeExpectation`); - return; - } - for (const mode of ['simpleCommand', 'extendedCommand', 'extendedQuery']) { - const result = expectation[mode]; - if (!result || !['ok', 'engineError'].includes(result.outcome)) { - errors.push(`${relative} case ${caseName} must declare ${mode} outcome`); - continue; - } - if (result.outcome === 'ok' && !Object.hasOwn(result, 'commandTag')) { - errors.push(`${relative} case ${caseName} ${mode} must declare commandTag`); - } - if (result.outcome === 'engineError' && !(typeof result.contains === 'string' && result.contains)) { - errors.push(`${relative} case ${caseName} ${mode} must declare an error substring`); - } - } -} - -function validateFiniteDiagnostic(relative, label, diagnostic, localized, nonlocalized) { - const expected = { - severity: localized, - localizedSeverity: localized, - nonlocalizedSeverity: nonlocalized, - internalPosition: '12', - internalQuery: 'SELECT broken', - file: 'parse_expr.c', - line: '123', - routine: 'transformExpr', - }; - for (const [field, value] of Object.entries(expected)) { - if (diagnostic?.[field] !== value) { - errors.push(`${relative} ${label} ${field} must equal ${JSON.stringify(value)}`); - } - } -} - -function validateUniqueJsonKeys(source, relative) { - errors.push(...scanUniqueJsonKeys(source, relative)); -} - -function validateJsonKeyScannerSelfCheck() { - const duplicate = scanUniqueJsonKeys('{"plain":1,"\\u0070lain":2}', ''); - if (!duplicate.some((error) => error.includes('duplicate JSON key $.plain'))) { - errors.push('duplicate JSON key scanner must detect escaped-equivalent keys'); - } - const invalidWhitespace = scanUniqueJsonKeys('{\u00a0"key":1}', ''); - if (!invalidWhitespace.some((error) => error.includes('must be valid JSON'))) { - errors.push('duplicate JSON key scanner must reject non-JSON whitespace'); - } -} - -function scanUniqueJsonKeys(source, relative) { - let index = 0; - const findings = []; - - function isJsonWhitespace(character) { - return character === ' ' || character === '\t' || character === '\r' || character === '\n'; - } - - function skipWhitespace() { - while (isJsonWhitespace(source[index])) index += 1; - } - - function parseString() { - skipWhitespace(); - const start = index; - if (source[index] !== '"') throw new Error(`expected a string at byte ${index}`); - index += 1; - while (index < source.length) { - if (source[index] === '\\') { - index += 2; - } else if (source[index] === '"') { - index += 1; - return JSON.parse(source.slice(start, index)); - } else { - index += 1; - } - } - throw new Error(`unterminated string at byte ${start}`); - } - - function parseValue(jsonPath) { - skipWhitespace(); - if (source[index] === '{') { - parseObject(jsonPath); - return; - } - if (source[index] === '[') { - parseArray(jsonPath); - return; - } - if (source[index] === '"') { - parseString(); - return; - } - const start = index; - while ( - index < source.length && - !isJsonWhitespace(source[index]) && - ![',', ']', '}'].includes(source[index]) - ) { - index += 1; - } - if (start === index) throw new Error(`expected a value at byte ${index}`); - JSON.parse(source.slice(start, index)); - } - - function parseObject(jsonPath) { - index += 1; - skipWhitespace(); - const keys = new Set(); - if (source[index] === '}') { - index += 1; - return; - } - while (index < source.length) { - const key = parseString(); - const childPath = `${jsonPath}.${key}`; - if (keys.has(key)) findings.push(`${relative} has duplicate JSON key ${childPath}`); - keys.add(key); - skipWhitespace(); - if (source[index] !== ':') throw new Error(`expected ':' at byte ${index}`); - index += 1; - parseValue(childPath); - skipWhitespace(); - if (source[index] === '}') { - index += 1; - return; - } - if (source[index] !== ',') throw new Error(`expected ',' at byte ${index}`); - index += 1; - } - throw new Error(`unterminated object at byte ${index}`); - } - - function parseArray(jsonPath) { - index += 1; - skipWhitespace(); - if (source[index] === ']') { - index += 1; - return; - } - let element = 0; - while (index < source.length) { - parseValue(`${jsonPath}[${element}]`); - element += 1; - skipWhitespace(); - if (source[index] === ']') { - index += 1; - return; - } - if (source[index] !== ',') throw new Error(`expected ',' at byte ${index}`); - index += 1; - } - throw new Error(`unterminated array at byte ${index}`); - } - - try { - parseValue('$'); - skipWhitespace(); - if (index !== source.length) throw new Error(`trailing data at byte ${index}`); - } catch (error) { - findings.push(`${relative} must be valid JSON: ${error.message}`); - } - return findings; -} diff --git a/tools/policy/check-supply-chain.mjs b/tools/policy/check-supply-chain.mjs deleted file mode 100755 index c3675a3d7..000000000 --- a/tools/policy/check-supply-chain.mjs +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bun -import { chdirRepoRoot, run } from "./lib/run-command.mjs"; - -const PREFIX = "check-supply-chain.mjs"; - -chdirRepoRoot(PREFIX); -run(PREFIX, "cargo", ["deny", "check"]); diff --git a/tools/policy/check-tauri-example-rustfmt.sh b/tools/policy/check-tauri-example-rustfmt.sh deleted file mode 100755 index d15e17c21..000000000 --- a/tools/policy/check-tauri-example-rustfmt.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -mapfile -t rust_files < <(git ls-files -- examples/tauri/src-tauri examples/tauri-wasix/src-tauri | awk '/\.rs$/ { print }' | sort) -[ "${#rust_files[@]}" -gt 0 ] || exit 0 - -rustfmt --edition 2021 --check "${rust_files[@]}" diff --git a/tools/policy/check-tooling-stack.sh b/tools/policy/check-tooling-stack.sh deleted file mode 100755 index 55815bd0f..000000000 --- a/tools/policy/check-tooling-stack.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -bun tools/policy/assertions/repository-semantics.mjs tooling -bun tools/policy/check-rust-helper-crates.mjs - -echo "tooling stack checks passed" diff --git a/tools/policy/check-wasix-release-dependency-invariants.mjs b/tools/policy/check-wasix-release-dependency-invariants.mjs deleted file mode 100644 index 0a655d6fd..000000000 --- a/tools/policy/check-wasix-release-dependency-invariants.mjs +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env bun -import { readdir } from 'node:fs/promises'; -import { join } from 'node:path'; - -import { - canonicalWasixCargoToolchainVersions, - validateWasixConsumerDependencyPins, -} from '../release/wasix-cargo-toolchain-policy.mjs'; - -const PRODUCT_MANIFEST_PATH = - 'src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml'; -const XTASK_MANIFEST_PATH = 'tools/xtask/Cargo.toml'; -const RUNTIME_VERSION_PATH = 'src/runtimes/liboliphaunt/wasix/VERSION'; -const SOURCE_TEMPLATE_ASSETS_MANIFEST = - 'src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml'; -const SOURCE_TEMPLATE_TOOLS_MANIFEST = - 'src/runtimes/liboliphaunt/wasix/crates/tools/Cargo.toml'; -const SOURCE_TEMPLATE_AOT_MANIFESTS_DIR = 'src/runtimes/liboliphaunt/wasix/crates/aot'; -const SOURCE_TEMPLATE_TOOLS_AOT_MANIFESTS_DIR = - 'src/runtimes/liboliphaunt/wasix/crates/tools-aot'; - -function fail(errors) { - console.error('release version invariant violations:'); - for (const error of errors) { - console.error(` - ${error}`); - } - process.exit(1); -} - -async function readToml(path) { - return Bun.TOML.parse(await Bun.file(path).text()); -} - -function* dependencyTables(manifest) { - yield ['dependencies', manifest.dependencies ?? {}]; - for (const [cfg, table] of Object.entries(manifest.target ?? {})) { - yield [`target.${cfg}.dependencies`, table.dependencies ?? {}]; - } -} - -function dependencyName(depKey, spec) { - if (spec !== null && typeof spec === 'object' && !Array.isArray(spec)) { - return spec.package ?? depKey; - } - return depKey; -} - -function dependencyVersion(spec) { - if (typeof spec === 'string') { - return spec; - } - if (spec !== null && typeof spec === 'object' && !Array.isArray(spec)) { - return spec.version; - } - return undefined; -} - -function dependencyPath(spec) { - if (spec !== null && typeof spec === 'object' && !Array.isArray(spec)) { - return spec.path; - } - return undefined; -} - -function isWasixArtifactCrate(name) { - return ( - name === 'liboliphaunt-wasix-portable' || - name === 'oliphaunt-wasix-tools' || - name.startsWith('liboliphaunt-wasix-aot-') || - name.startsWith('oliphaunt-wasix-tools-aot-') - ); -} - -function validateExactDependency(manifest, manifestPath, name, expectedVersion, errors) { - const matches = []; - for (const [tableName, deps] of dependencyTables(manifest)) { - for (const [depKey, spec] of Object.entries(deps)) { - if (dependencyName(depKey, spec) === name) { - matches.push({ tableName, depKey, spec }); - } - } - } - if (matches.length !== 1) { - errors.push( - `${manifestPath} must declare ${name} exactly once, found ${matches.length}`, - ); - return; - } - const [{ tableName, depKey, spec }] = matches; - const actualVersion = dependencyVersion(spec); - if (actualVersion !== `=${expectedVersion}`) { - errors.push( - `${manifestPath} ${tableName}.${depKey} must pin ${name} exactly to ` + - `=${expectedVersion}, got ${JSON.stringify(actualVersion)}`, - ); - } -} - -const productManifest = await readToml(PRODUCT_MANIFEST_PATH); -const xtaskManifest = await readToml(XTASK_MANIFEST_PATH); -const runtimeVersion = (await Bun.file(RUNTIME_VERSION_PATH).text()).trim(); -const errors = []; -const productDeps = new Map(); - -let toolchainVersions; -try { - toolchainVersions = canonicalWasixCargoToolchainVersions(); -} catch (cause) { - errors.push(cause.message); -} -const wasmerVersion = toolchainVersions?.wasmer; -const wasmerWasixVersion = toolchainVersions?.wasmerWasix; -const webcVersion = toolchainVersions?.webc; -if (wasmerVersion !== undefined) { - for (const [manifestPath, manifest] of [ - [PRODUCT_MANIFEST_PATH, productManifest], - [XTASK_MANIFEST_PATH, xtaskManifest], - ]) { - validateExactDependency(manifest, manifestPath, 'wasmer', wasmerVersion, errors); - validateExactDependency(manifest, manifestPath, 'wasmer-types', wasmerVersion, errors); - } -} -if (wasmerWasixVersion !== undefined) { - validateExactDependency( - xtaskManifest, - XTASK_MANIFEST_PATH, - 'wasmer-wasix', - wasmerWasixVersion, - errors, - ); - errors.push(...validateWasixConsumerDependencyPins(productManifest, { - manifestPath: PRODUCT_MANIFEST_PATH, - toolchainVersions, - })); -} -if (webcVersion !== undefined) { - validateExactDependency( - xtaskManifest, - XTASK_MANIFEST_PATH, - 'webc', - webcVersion, - errors, - ); -} - -for (const [tableName, deps] of dependencyTables(productManifest)) { - for (const [depKey, spec] of Object.entries(deps)) { - const name = dependencyName(depKey, spec); - if (!isWasixArtifactCrate(name)) { - continue; - } - if (productDeps.has(name)) { - errors.push(`${name} is declared more than once in oliphaunt-wasix dependencies`); - } - productDeps.set(name, { tableName, spec }); - } -} - -const sourceTemplateManifestPaths = [SOURCE_TEMPLATE_ASSETS_MANIFEST, SOURCE_TEMPLATE_TOOLS_MANIFEST]; -for (const manifestsDir of [SOURCE_TEMPLATE_AOT_MANIFESTS_DIR, SOURCE_TEMPLATE_TOOLS_AOT_MANIFESTS_DIR]) { - for (const entry of (await readdir(manifestsDir, { withFileTypes: true })) - .filter((entry) => entry.isDirectory()) - .map((entry) => entry.name) - .sort()) { - sourceTemplateManifestPaths.push(join(manifestsDir, entry, 'Cargo.toml')); - } -} - -for (const manifestPath of sourceTemplateManifestPaths) { - const manifest = await readToml(manifestPath); - const packageConfig = manifest.package ?? {}; - const name = packageConfig.name; - const version = packageConfig.version; - if (typeof name !== 'string' || !isWasixArtifactCrate(name)) { - errors.push(`${manifestPath}: unexpected WASIX artifact crate name ${JSON.stringify(name)}`); - continue; - } - if (version !== runtimeVersion) { - errors.push( - `${manifestPath}: ${name} version ${version} does not match liboliphaunt-wasix runtime version ${runtimeVersion}`, - ); - } - if (packageConfig.publish !== false) { - errors.push( - `${manifestPath}: source artifact crate template ${name} must declare publish = false until release packaging injects payloads and strips the guard`, - ); - } - if (!productDeps.has(name)) { - errors.push(`oliphaunt-wasix must depend on WASIX artifact crate ${name}`); - } -} - -for (const [name, { tableName, spec }] of [...productDeps].sort(([left], [right]) => - left < right ? -1 : left > right ? 1 : 0, -)) { - const version = dependencyVersion(spec); - const sourcePath = dependencyPath(spec); - if (version !== '*') { - errors.push( - `${PRODUCT_MANIFEST_PATH} ${tableName}.${name} must use workspace version "*"; release packaging injects the declared runtime compatibility version, got ${JSON.stringify(version)}`, - ); - } - if (sourcePath === undefined || sourcePath === null || sourcePath === '') { - errors.push( - `${PRODUCT_MANIFEST_PATH} ${tableName}.${name} must keep a source-checkout path dependency`, - ); - } -} - -if (errors.length > 0) { - fail(errors); -} - -console.log('release version invariants ok'); diff --git a/tools/policy/check-workflows.sh b/tools/policy/check-workflows.sh deleted file mode 100755 index c04951855..000000000 --- a/tools/policy/check-workflows.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" -PATH="${CARGO_HOME:-$HOME/.cargo}/bin:$PATH" -export PATH - -require() { - if ! command -v "$1" >/dev/null 2>&1; then - echo "missing required command: $1" >&2 - echo "run tools/dev/bootstrap-tools.sh to install pinned maintainer tools" >&2 - exit 1 - fi -} - -run() { - printf '\n==> %s\n' "$*" - "$@" -} - -require actionlint -require zizmor -# actionlint 1.7.12 predates GitHub's `concurrency.queue: max` schema addition. -run actionlint -ignore 'unexpected key "queue" for "concurrency" section' -run zizmor --config .github/zizmor.yml --min-severity medium --persona auditor .github/workflows .github/actions -run tools/dev/bun.sh test tools/policy/assertions/workflow-security.test.mjs -run tools/dev/bun.sh tools/policy/assertions/workflow-security.mjs -run node --test \ - .github/scripts/configure-macos-release-toolchains.test.mjs \ - .github/scripts/moon-task-capabilities.test.mjs \ - .github/scripts/write-affected-moon-target-matrices.test.mjs \ - .github/scripts/resolve-planned-moon-execution.test.mjs -run tools/dev/bun.sh test \ - tools/policy/ci-plan-node-products.test.mjs \ - tools/policy/ci-plan-wasix-postmaster-release.test.mjs \ - tools/policy/workflow-moon-transfers.test.mjs -run tools/dev/bun.sh test tools/release/toolchain-bootstrap.test.mjs diff --git a/tools/policy/ci-plan-node-products.test.mjs b/tools/policy/ci-plan-node-products.test.mjs deleted file mode 100644 index fecf0d1f4..000000000 --- a/tools/policy/ci-plan-node-products.test.mjs +++ /dev/null @@ -1,445 +0,0 @@ -import assert from "node:assert/strict"; -import path from "node:path"; -import { test } from "node:test"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { moonCommand, moonEnvironment } from "../dev/moon-command.mjs"; -import { affectedNames, triggeringProjectNames, triggeringTaskNames } from "../graph/affected.mjs"; -import { planJobsForAffected } from "../graph/ci_plan.mjs"; -import { buildPlan, loadGraph, normalizeFiles } from "../release/release-graph.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const GRAPH = loadGraph("ci-plan-node-products.test.mjs"); - -function effects(paths) { - const relativePaths = Array.isArray(paths) ? paths : [paths]; - const environment = { ...process.env, MOON_CACHE: "off" }; - delete environment.MOON_BASE; - delete environment.MOON_HEAD; - const result = captureCommandOutput( - moonCommand(environment), - ["query", "affected", "stdin", "--upstream", "none", "--downstream", "direct"], - { - cwd: ROOT, - env: moonEnvironment(environment), - input: `${relativePaths.join("\n")}\n`, - label: `Moon Node-product chaos fixture ${relativePaths.join(", ")}`, - }, - ); - assert.equal(result.error, undefined, result.error?.message ?? result.stderr); - assert.equal(result.status, 0, result.stderr); - const affected = JSON.parse(result.stdout); - const projects = triggeringProjectNames(affected.projects); - const directTasks = triggeringTaskNames(affected.tasks); - const tasks = affectedNames(affected.tasks); - return { - directTasks, - jobs: [...planJobsForAffected(new Set(directTasks))].sort(), - projects, - releaseProducts: buildPlan( - GRAPH, - normalizeFiles(relativePaths), - "ci-plan-node-products.test.mjs", - ).releaseProducts, - tasks, - }; -} - -function actionTargets(target) { - const result = captureCommandOutput(moonCommand(), ["task-graph", target, "--json"], { - cwd: ROOT, - env: moonEnvironment(), - label: `Moon action graph for ${target}`, - }); - assert.equal(result.status, 0, result.stderr); - return new Set(Object.values(JSON.parse(result.stdout).data).map((task) => task.target)); -} - -function taskRecord(target) { - const result = captureCommandOutput(moonCommand(), ["task-graph", target, "--json"], { - cwd: ROOT, - env: moonEnvironment(), - label: `Moon task record for ${target}`, - }); - assert.equal(result.status, 0, result.stderr); - return Object.values(JSON.parse(result.stdout).data).find((task) => task.target === target); -} - -test("JavaScript SDK source does not rebuild the Node Direct addon", () => { - const result = effects("src/sdks/js/src/client.ts"); - assert.deepEqual(result.jobs, ["affected", "js-sdk-package"]); - assert.deepEqual(result.releaseProducts, ["oliphaunt-js"]); - assert.equal(result.tasks.includes("oliphaunt-js:compile"), true); - assert.equal(result.tasks.includes("oliphaunt-js:unit"), true); - assert.equal(result.tasks.includes("release-tools:node-direct-runtime"), false); - assert.equal(result.tasks.includes("release-tools:metadata"), false); - assert.equal(result.tasks.includes("release-tools:unit"), false); -}); - -test("product prose selects packaging and the cold action graph includes required compilation", () => { - const javascript = effects("src/sdks/js/README.md"); - assert.deepEqual(javascript.jobs, ["affected", "js-sdk-package"]); - assert.equal(javascript.tasks.includes("oliphaunt-js:package"), true); - for (const target of [ - "coverage-tools:js", - "integration-examples:js-sdk-smoke", - "oliphaunt-js:compile", - "oliphaunt-js:unit", - "sdk-contracts:native-boundaries", - ]) { - assert.equal(javascript.tasks.includes(target), false, `${target} does not consume SDK prose`); - } - const actions = actionTargets("release-tools:js-sdk-package"); - assert.equal(actions.has("oliphaunt-js:package"), true); - assert.equal(actions.has("oliphaunt-js:compile"), true); - assert.equal(actions.has("oliphaunt-js:unit"), false); - - const napi = effects("src/runtimes/wasix-napi/README.md"); - assert.deepEqual(napi.jobs, ["affected"]); - assert.equal(napi.tasks.includes("oliphaunt-wasix-napi:unit"), false); -}); - -test("shared implementation documentation has no product consumers", () => { - const result = effects("src/shared/js-core/README.md"); - assert.deepEqual(result.jobs, ["affected"]); - assert.equal(result.tasks.includes("shared-js-core:check"), false); - assert.equal(result.tasks.includes("shared-js-core:test"), false); - assert.equal(result.tasks.some((target) => target.endsWith(":compile")), false); -}); - -test("extension evidence validates evidence without rebuilding products", () => { - const result = effects("src/extensions/evidence/runs/2026-06-07-transitional-catalog-smoke.json"); - assert.equal(result.tasks.includes("extensions:lint"), true); - assert.equal(result.tasks.includes("docs:check"), true); - assert.equal(result.tasks.includes("sdk-contracts:fixtures"), false); - for (const job of [ - "extension-artifacts-native", - "extension-artifacts-wasix", - "native-extension-lifecycle", - ]) { - assert.equal(result.jobs.includes(job), false, `${job} does not consume evidence records`); - } -}); - -test("Node Direct source does not rebuild the independently versioned JavaScript SDK", () => { - const result = effects("src/runtimes/node-direct/native/node-addon/oliphaunt_node.cc"); - assert.deepEqual(result.jobs, [ - "affected", - "node-direct", - "node-direct-release-assets", - ]); - assert.deepEqual(result.releaseProducts, ["oliphaunt-node-direct"]); - assert.equal(result.tasks.includes("oliphaunt-node-direct:compile"), true); - assert.equal(result.tasks.includes("oliphaunt-js:unit"), false); -}); - -test("native implementation does not compile the version-decoupled broker", () => { - const result = effects("src/runtimes/liboliphaunt/native/src/liboliphaunt_process.c"); - assert.equal(result.tasks.includes("oliphaunt-broker:compile"), false); - assert.equal(result.tasks.includes("liboliphaunt-native:lint"), false); - assert.equal(result.tasks.includes("oliphaunt-rust:regression"), true); - assert.equal(result.tasks.includes("oliphaunt-swift:smoke"), true); -}); - -test("combined JavaScript SDK and WASIX N-API changes release only changed products", () => { - const result = effects([ - "src/runtimes/wasix-napi/src/lib.rs", - "src/sdks/js/src/client.ts", - ]); - assert.deepEqual(result.jobs, [ - "affected", - "extension-artifacts-wasix", - "js-sdk-package", - "liboliphaunt-wasix-aot", - "liboliphaunt-wasix-runtime", - "wasix-napi", - "wasix-napi-release-assets", - "wasix-ts-sdk-package", - ]); - assert.deepEqual(result.releaseProducts, [ - "oliphaunt-js", - "oliphaunt-wasix-napi", - ]); -}); - -test("shared contrib source releases only its two runtime owners", () => { - const release = buildPlan( - GRAPH, - ["src/extensions/contrib/postgres18.toml"], - "ci-plan-node-products.test.mjs", - ); - assert.deepEqual(release.directProducts, ["liboliphaunt-native", "liboliphaunt-wasix"]); - assert.deepEqual(release.releaseProducts, ["liboliphaunt-native", "liboliphaunt-wasix"]); -}); - -test("WASIX N-API source selects only its real WASIX artifact inputs", () => { - const result = effects("src/runtimes/wasix-napi/src/lib.rs"); - assert.deepEqual(result.jobs, [ - "affected", - "extension-artifacts-wasix", - "liboliphaunt-wasix-aot", - "liboliphaunt-wasix-runtime", - "wasix-napi", - "wasix-napi-release-assets", - "wasix-ts-sdk-package", - ]); - assert.deepEqual(result.releaseProducts, ["oliphaunt-wasix-napi"]); - assert.equal(result.tasks.includes("oliphaunt-wasix-napi:format-check"), true); - assert.equal(result.tasks.includes("oliphaunt-wasix-napi:unit"), true); -}); - -test("WASIX N-API isolated unit fixtures do not start artifact builders", () => { - const result = effects("src/runtimes/wasix-napi/tools/portable-command.test.mjs"); - assert.deepEqual(result.jobs, ["affected"]); - assert.equal(result.tasks.includes("oliphaunt-wasix-napi:unit"), true); -}); - -test("WASIX test helpers invalidate only tasks that execute them", () => { - const result = effects("src/runtimes/liboliphaunt/wasix/tools/cargo-test-filter.sh"); - for (const target of [ - "liboliphaunt-wasix:runtime-aot", - "liboliphaunt-wasix:smoke", - "liboliphaunt-wasix:regression", - ]) { - assert.equal(result.directTasks.includes(target), true, `${target} executes the helper`); - } - for (const target of [ - "coverage-tools:wasix-rust", - "extension-artifacts-wasix:build-target", - "liboliphaunt-wasix:assets-verify", - "liboliphaunt-wasix:release-assets", - "liboliphaunt-wasix:runtime-portable", - "perf-tools:wasix-browser-measure", - "perf-tools:wasix-node-measure", - ]) { - assert.equal(result.directTasks.includes(target), false, `${target} does not execute the helper`); - } -}); - -test("WASIX extension staging follows its own code and produced runtime artifact", () => { - const packager = effects("src/extensions/artifacts/wasix/tools/package-release-assets.mjs"); - assert.equal(packager.directTasks.includes("extension-artifacts-wasix:build-target"), true); - - const runtimeVersion = effects("src/runtimes/liboliphaunt/wasix/VERSION"); - assert.equal(runtimeVersion.directTasks.includes("extension-artifacts-wasix:build-target"), true); - - const releaseMetadata = effects("src/runtimes/liboliphaunt/wasix/release.toml"); - assert.equal(releaseMetadata.directTasks.includes("extension-artifacts-wasix:build-target"), false); - assert.equal(releaseMetadata.directTasks.includes("release-tools:wasix-napi-runtime"), true); -}); - -test("extension artifact builders materialize overlapping source scopes once", () => { - const native = actionTargets("extension-artifacts-native:build-target"); - assert.equal(native.has("source-inputs:source-fetch-native-runtime"), true); - assert.equal(native.has("source-inputs:source-fetch-extensions"), false); - - const wasix = actionTargets("extension-artifacts-wasix:build-target"); - assert.equal(wasix.has("source-inputs:source-fetch-wasix-runtime"), true); - assert.equal(wasix.has("source-inputs:source-fetch-extensions"), false); -}); - -test("executable packagers and Rust test configuration select their real owners", () => { - const nativeExtensions = effects("src/extensions/artifacts/native/tools/package-release-assets.sh"); - assert.equal(nativeExtensions.directTasks.includes("extension-artifacts-native:build-target"), true); - assert.equal(nativeExtensions.jobs.includes("extension-artifacts-native"), true); - - const mobile = effects("tools/release/package-liboliphaunt-mobile-assets.sh"); - for (const target of [ - "liboliphaunt-native:package-runtime-android-arm64-v8a", - "liboliphaunt-native:package-runtime-android-x86_64", - "liboliphaunt-native:package-runtime-ios-xcframework", - ]) { - assert.equal(mobile.directTasks.includes(target), true, `${target} executes the mobile packager`); - } - assert.equal(mobile.directTasks.some((target) => target.includes(":build-runtime-android-")), false); - assert.equal(mobile.directTasks.includes("liboliphaunt-native:build-runtime-ios-xcframework"), false); - - const desktop = effects("tools/release/package-liboliphaunt-linux-assets.sh"); - assert.equal(desktop.directTasks.includes("liboliphaunt-native:package-runtime-desktop-target"), true); - assert.equal(desktop.directTasks.includes("liboliphaunt-native:build-runtime-desktop-target"), false); - - const nextest = effects(".config/nextest.toml"); - assert.equal(nextest.directTasks.includes("coverage-tools:rust"), true); - assert.equal(nextest.directTasks.includes("oliphaunt-rust:unit-distinct"), true); - assert.equal(nextest.directTasks.includes("oliphaunt-rust:unit-shared"), true); - assert.equal(taskRecord("oliphaunt-rust:unit-shared").options.runInCI, false); - assert.equal(nextest.directTasks.includes("coverage-tools:wasix-rust"), true); - assert.equal(nextest.directTasks.includes("oliphaunt-wasix-rust:unit-distinct"), true); - assert.equal(nextest.directTasks.includes("oliphaunt-wasix-rust:unit-shared"), true); - assert.equal(taskRecord("oliphaunt-wasix-rust:unit-shared").options.runInCI, false); -}); - -test("coverage owns shared hosted suites while distinct product checks remain selected", () => { - const reactNative = effects("src/sdks/react-native/src/index.ts"); - for (const target of [ - "coverage-tools:react-native", - "oliphaunt-react-native:unit-distinct", - "oliphaunt-react-native:unit-shared", - ]) { - assert.equal(reactNative.directTasks.includes(target), true, target); - } - assert.equal(taskRecord("oliphaunt-react-native:unit-shared").options.runInCI, false); - - const wasixRust = effects("src/bindings/wasix-rust/crates/oliphaunt-wasix/src/lib.rs"); - for (const target of [ - "coverage-tools:wasix-rust", - "oliphaunt-wasix-rust:unit-distinct", - "oliphaunt-wasix-rust:unit-shared", - ]) { - assert.equal(wasixRust.directTasks.includes(target), true, target); - } - assert.equal(taskRecord("oliphaunt-wasix-rust:unit-shared").options.runInCI, false); -}); - -test("source acquisition and WASIX browser-host ownership stay narrow", () => { - const extensionPin = effects("src/extensions/external/vector/source.toml"); - assert.equal(extensionPin.directTasks.includes("source-inputs:source-fetch-extensions"), true); - assert.equal(extensionPin.directTasks.includes("source-inputs:source-fetch-native-runtime"), true); - assert.equal(extensionPin.directTasks.includes("source-inputs:source-fetch-wasix-runtime"), true); - - const browserHost = effects("src/bindings/wasix-ts/host/source.toml"); - assert.equal(browserHost.directTasks.includes("oliphaunt-wasix-ts:browser-host"), true); - assert.equal(browserHost.tasks.includes("oliphaunt-wasix-ts:package"), true); - assert.equal(browserHost.jobs.includes("wasix-ts-sdk-package"), true); - - const cargoLock = effects("Cargo.lock"); - assert.equal(cargoLock.directTasks.includes("oliphaunt-wasix-ts:browser-host"), true); -}); - -test("docs changes select the production artifact and built-site smoke", () => { - const result = effects("src/docs/src/app/docs/layout.tsx"); - assert.equal(result.directTasks.includes("docs:build"), true); - assert.equal(result.tasks.includes("docs:smoke"), true); -}); - -test("WASIX N-API production helpers keep the release builder affected", () => { - for (const relativePath of [ - "src/bindings/wasix-ts/tools/pgwire-client.mjs", - "src/runtimes/wasix-napi/tools/portable-command.mjs", - "tools/dev/deno.sh", - "tools/release/wasix-aot-manifest.mjs", - ]) { - const result = effects(relativePath); - assert.equal( - result.tasks.includes("release-tools:wasix-napi-runtime"), - true, - `${relativePath} must invalidate the WASIX N-API release builder`, - ); - assert.equal(result.jobs.includes("wasix-napi-release-assets"), true); - } -}); - -test("CI planner changes select the focused graph proof", () => { - const result = effects("tools/graph/ci_plan.mjs"); - assert.equal(result.tasks.includes("release-tools:graph-unit"), true); - assert.equal(result.tasks.includes("release-tools:unit"), false); -}); - -test("release mutation tests follow release helpers, not policy or workflow files", () => { - for (const relativePath of ["tools/policy/format.sh", ".github/workflows/ci.yml"]) { - const result = effects(relativePath); - assert.equal(result.tasks.includes("release-tools:unit"), false); - if (relativePath === "tools/policy/format.sh") { - assert.equal(result.tasks.includes("policy-tools:unit"), false); - } - } - const result = effects(".github/scripts/release-candidate-lib.mjs"); - assert.equal(result.tasks.includes("release-tools:unit"), true); - assert.equal(result.tasks.includes("release-tools:graph-unit"), false); -}); - -test("workflow changes run workflow checks without rebuilding product artifacts", () => { - const result = effects(".github/workflows/ci.yml"); - assert.deepEqual(result.jobs, ["affected"]); - assert.equal(result.tasks.includes("ci-workflows:check"), true); - assert.equal(result.tasks.includes("release-tools:metadata"), true); -}); - -test("release helper changes invalidate only their product artifacts", () => { - const kotlin = effects("tools/release/sdk-artifacts/kotlin.mjs"); - assert.deepEqual(kotlin.jobs, [ - "affected", - "extension-artifacts-native", - "kotlin-maven-staging", - "kotlin-sdk-package", - "liboliphaunt-native-android", - "liboliphaunt-native-ios", - "mobile-build-android", - "mobile-extension-packages", - "react-native-sdk-package", - ]); - - const nodeDirect = effects("tools/release/check-node-direct-release-assets.mjs"); - assert.deepEqual(nodeDirect.jobs, ["affected", "node-direct", "node-direct-release-assets"]); -}); - -test("product Moon topology selects the focused release graph proof", () => { - const result = effects("src/sdks/js/moon.yml"); - assert.deepEqual(result.jobs, ["affected", "js-sdk-package"]); - assert.equal(result.tasks.includes("release-tools:graph-unit"), true); - assert.equal(result.tasks.includes("release-tools:unit"), false); -}); - -test("JavaScript release metadata does not rebuild unrelated products", () => { - const result = effects("src/sdks/js/release.toml"); - assert.deepEqual(result.jobs, ["affected", "js-sdk-package"]); - assert.deepEqual(result.releaseProducts, ["oliphaunt-js"]); - assert.equal(result.tasks.includes("release-tools:graph-unit"), true); - assert.equal(result.tasks.includes("release-tools:metadata"), true); - assert.equal(result.tasks.includes("release-tools:unit"), false); - for (const target of [ - "release-tools:broker-runtime", - "release-tools:react-native-sdk-package", - "release-tools:swift-sdk-package", - "release-tools:wasix-napi-runtime", - ]) { - assert.equal(result.tasks.includes(target), false, `${target} is unrelated to the JavaScript SDK`); - } -}); - -test("release-please bookkeeping does not rebuild product artifacts", () => { - const result = effects(".release-please-manifest.json"); - assert.deepEqual(result.jobs, ["affected"]); - assert.equal(result.tasks.includes("release-tools:graph-unit"), true); - assert.equal(result.tasks.includes("release-tools:metadata"), true); - assert.equal(result.tasks.includes("release-tools:unit"), false); - assert.equal( - result.tasks.some((target) => /:(aggregate-release-assets|package-artifacts|release-assets|[a-z-]+-sdk-package)$/u.test(target)), - false, - ); -}); - -test("extension sources select shared builders without leaf package wrappers", () => { - for (const relativePath of [ - "src/extensions/external/pg_uuidv7/source.toml", - "src/extensions/contrib/carriers.toml", - ]) { - const result = effects(relativePath); - for (const job of [ - "extension-artifacts-native", - "extension-artifacts-wasix", - "extension-packages", - ]) { - assert.equal(result.jobs.includes(job), true, `${relativePath} must select ${job}`); - } - assert.equal( - result.tasks.some((target) => /^oliphaunt-extension-[^:]+:package$/u.test(target)), - false, - `${relativePath} must not need a duplicate leaf package task`, - ); - } -}); - -test("extension package tooling invalidates packaging without changing builders", () => { - const result = effects("src/extensions/artifacts/packages/tools/package-release-assets.sh"); - assert.equal(result.tasks.includes("extension-packages:package"), true); - assert.equal(result.tasks.includes("extension-packages:package-mobile"), false); - for (const target of [ - "extension-artifacts-native:build-target", - "extension-artifacts-wasix:build-target", - "liboliphaunt-wasix:runtime-portable", - "oliphaunt-rust:extension-regression", - ]) { - assert.equal(result.tasks.includes(target), false, `${target} does not consume package tooling`); - } -}); diff --git a/tools/policy/ci-plan-wasix-postmaster-release.test.mjs b/tools/policy/ci-plan-wasix-postmaster-release.test.mjs deleted file mode 100644 index a32b115f3..000000000 --- a/tools/policy/ci-plan-wasix-postmaster-release.test.mjs +++ /dev/null @@ -1,267 +0,0 @@ -import assert from 'node:assert/strict'; -import path from 'node:path'; -import {test} from 'node:test'; - -import {captureCommandOutput} from '../dev/capture-command-output.mjs'; -import {moonCommand, moonEnvironment} from '../dev/moon-command.mjs'; -import {affectedNames, triggeringProjectNames, triggeringTaskNames} from '../graph/affected.mjs'; -import { - CI_JOB_TARGETS, - planJobsForAffected, - renderPlanWithSelection, -} from '../graph/ci_plan.mjs'; -import {buildPlan, loadGraph, normalizeFiles} from '../release/release-graph.mjs'; - -const ROOT = path.resolve(import.meta.dir, '../..'); - -function taskGraph(target) { - const environment = {...process.env, MOON_CACHE: 'off'}; - const result = captureCommandOutput( - moonCommand(environment), - ['task-graph', target, '--json'], - { - cwd: ROOT, - env: moonEnvironment(environment), - label: `Moon task graph for ${target}`, - }, - ); - assert.equal(result.error, undefined, result.error?.message ?? result.stderr); - assert.equal(result.status, 0, result.stderr); - return Object.values(JSON.parse(result.stdout).data); -} - -test('postmaster CI selects only terminal product roots', () => { - assert.deepEqual(CI_JOB_TARGETS['wasix-postmaster'], [ - 'liboliphaunt-wasix-postmaster:portable-inputs', - 'liboliphaunt-wasix-postmaster:release-assets', - 'release-tools:postmaster-release-assets', - ]); -}); - -test('postmaster planner renders every supported release target', () => { - const plan = renderPlanWithSelection({ - jobs: new Set(['affected', 'wasix-postmaster']), - projects: new Set(), - tasks: new Set(CI_JOB_TARGETS['wasix-postmaster']), - reason: 'postmaster planner fixture', - selectedTargets: null, - selectedExtensionProducts: new Set(), - qualificationMode: 'affected', - qualificationBaseSha: 'base-sha', - qualificationHeadSha: 'head-sha', - }); - assert.equal(plan.qualification_mode, 'affected'); - assert.equal(plan.qualification_base_sha, 'base-sha'); - assert.equal(plan.qualification_head_sha, 'head-sha'); - assert.deepEqual( - plan.liboliphaunt_wasix_postmaster_runtime_matrix.include.map( - ({target_id}) => target_id, - ), - [ - 'linux-arm64-gnu', - 'linux-x64-gnu', - 'macos-arm64', - ], - ); - - const planWithoutPostmaster = renderPlanWithSelection({ - jobs: new Set(['affected']), - projects: new Set(), - tasks: new Set(), - reason: 'non-postmaster planner fixture', - selectedTargets: null, - selectedExtensionProducts: new Set(), - }); - assert.deepEqual( - planWithoutPostmaster.liboliphaunt_wasix_postmaster_runtime_matrix, - {include: []}, - ); - assert.equal(planWithoutPostmaster.qualification_mode, 'full-payload'); - assert.equal(planWithoutPostmaster.qualification_base_sha, null); - assert.equal(planWithoutPostmaster.qualification_head_sha, null); -}); - -test('postmaster source preparation waits for the shared source fetch', () => { - const task = taskGraph('liboliphaunt-wasix-postmaster:prepare-postgres').find( - ({target}) => target === 'liboliphaunt-wasix-postmaster:prepare-postgres', - ); - assert.ok(task); - assert.equal( - task.deps.some( - ({target}) => target === 'source-inputs:source-fetch-wasix-postmaster-runtime', - ), - true, - ); -}); - -test('postmaster production and qualification roots stay separate', () => { - const patchTests = 'liboliphaunt-wasix-postmaster:runtime-patch-tests'; - const targets = (root) => new Set(taskGraph(root).map(({target}) => target)); - const portableProduction = targets('liboliphaunt-wasix-postmaster:portable-inputs'); - const targetProduction = targets('liboliphaunt-wasix-postmaster:release-assets'); - assert.equal(portableProduction.has(patchTests), false); - assert.equal(targetProduction.has(patchTests), false); - for (const behavior of [ - 'liboliphaunt-wasix-postmaster:backend-wave-stress', - 'liboliphaunt-wasix-postmaster:immediate-recovery', - 'liboliphaunt-wasix-postmaster:linear-memory-integration', - ]) { - assert.equal(targetProduction.has(behavior), false); - } -}); - -function directEffects(relativePath) { - const environment = {...process.env, MOON_CACHE: 'off'}; - delete environment.MOON_BASE; - delete environment.MOON_HEAD; - const result = captureCommandOutput( - moonCommand(environment), - ['query', 'affected', 'stdin', '--upstream', 'none', '--downstream', 'direct'], - { - cwd: ROOT, - env: moonEnvironment(environment), - input: `${relativePath}\n`, - label: `moon WASIX postmaster release fixture ${relativePath}`, - }, - ); - assert.equal(result.error, undefined, result.error?.message ?? result.stderr); - assert.equal(result.status, 0, result.stderr); - const affected = JSON.parse(result.stdout); - const projects = triggeringProjectNames(affected.projects); - const directTasks = triggeringTaskNames(affected.tasks); - const tasks = affectedNames(affected.tasks); - const jobs = [...planJobsForAffected(new Set(directTasks))].sort(); - return {projects, directTasks, tasks, jobs}; -} - -function assertReleaseSelection(relativePath) { - const effects = directEffects(relativePath); - assert.equal(effects.projects.includes('liboliphaunt-wasix-postmaster'), true); - assert.equal(effects.jobs.includes('wasix-postmaster'), true); - - const releasePlan = buildPlan( - loadGraph('ci-plan-wasix-postmaster-release.test.mjs'), - normalizeFiles([relativePath]), - 'ci-plan-wasix-postmaster-release.test.mjs', - ); - assert.equal(releasePlan.hasReleaseChanges, true); - assert.equal( - releasePlan.releaseProducts.includes('liboliphaunt-wasix-postmaster'), - true, - ); -} - -function assertNativeExtensionLifecycleSelection(relativePath) { - const effects = directEffects(relativePath); - assert.equal( - effects.tasks.includes( - 'release-tools:native-extension-lifecycle', - ), - true, - ); - assert.equal(effects.jobs.includes('native-extension-lifecycle'), true); -} - -test('postmaster build-input pins select its builder and release', () => { - assertReleaseSelection('src/sources/third-party/wasix-postmaster/wasmer.toml'); -}); - -test('source fetch unit fixtures do not rebuild product artifacts', () => { - const effects = directEffects('src/sources/tools/source-fetch-core.test.mjs'); - assert.deepEqual(effects.jobs, ['affected']); - assert.equal(effects.tasks.includes('source-inputs:unit'), true); - assert.equal(effects.tasks.includes('policy-tools:unit'), false); - assert.equal( - effects.tasks.some((target) => target.startsWith('source-inputs:source-fetch-')), - false, - ); -}); - -test('source fetch implementation changes retain their real consumers', () => { - const effects = directEffects('src/sources/tools/source-fetch-core.mjs'); - for (const target of [ - 'extension-artifacts-native:build-target', - 'liboliphaunt-native:build-runtime-desktop-target', - 'liboliphaunt-wasix-postmaster:prepare-runtime', - 'liboliphaunt-wasix:runtime-portable', - ]) { - assert.equal(effects.tasks.includes(target), true, `${target} must consume source fetching`); - } -}); - -test('source prose, transport tests, and unrelated toolchains do not rebuild runtimes', () => { - const cases = [ - ['src/postgres/versions/18/fetch-source.test.sh', 'source-inputs:unit'], - ['src/runtimes/liboliphaunt/wasix-postmaster/runtime/README.md', null], - [ - 'src/runtimes/liboliphaunt/wasix-postmaster/runtime/bin/verify-source-lock.test.py', - 'liboliphaunt-wasix-postmaster:unit', - ], - ['src/sources/third-party/native/README.md', null], - ['src/sources/toolchains/maestro.toml', 'ci-workflows:check'], - ]; - for (const [relativePath, expectedTask] of cases) { - const effects = directEffects(relativePath); - if (expectedTask !== null) assert.equal(effects.tasks.includes(expectedTask), true); - for (const target of [ - 'liboliphaunt-native:package-runtime-desktop-target', - 'liboliphaunt-wasix-postmaster:prepare-runtime', - 'liboliphaunt-wasix:runtime-portable', - ]) { - assert.equal(effects.tasks.includes(target), false, `${target} does not consume ${relativePath}`); - } - } -}); - -test('runtime patch lint follows only the patch inputs it reads', () => { - for (const relativePath of [ - 'src/extensions/external/vector/source.toml', - 'src/runtimes/liboliphaunt/wasix/crates/tools/src/lib.rs', - 'tools/xtask/src/main.rs', - ]) { - const effects = directEffects(relativePath); - assert.equal(effects.tasks.includes('liboliphaunt-wasix:lint'), false); - } - assert.equal( - directEffects('src/postgres/versions/18/source.toml').tasks.includes('liboliphaunt-wasix:lint'), - true, - ); - assert.equal( - directEffects('docs/internal/OLIPHAUNT_PATCH_STACK.md').tasks.includes('liboliphaunt-native:lint'), - true, - ); -}); - -test('postmaster runtime changes select its production builder and release', () => { - assertReleaseSelection( - 'src/runtimes/liboliphaunt/wasix-postmaster/runtime/capabilities.tsv', - ); -}); - -test('postmaster aggregate helper is owned by release orchestration', () => { - const effects = directEffects('tools/release/merge-product-release-assets.mjs'); - assert.equal(effects.projects.includes('release-tools'), true); - assert.equal(effects.projects.includes('liboliphaunt-wasix-postmaster'), false); - assert.equal(effects.tasks.includes( - 'release-tools:postmaster-release-assets', - ), true); - assert.equal(effects.jobs.includes('wasix-postmaster'), true); -}); - -test('native lifecycle runner changes select its exact hosted proof', () => { - assertNativeExtensionLifecycleSelection( - 'tools/release/run-native-extension-lifecycle-proof.sh', - ); -}); - -test('native lifecycle proof source selects its exact hosted proof', () => { - assertNativeExtensionLifecycleSelection( - 'tools/native-extension-proof/src/main.rs', - ); -}); - -test('native lifecycle supervisor changes select its exact hosted proof', () => { - assertNativeExtensionLifecycleSelection( - 'src/runtimes/liboliphaunt/wasix-postmaster/lib/process-supervision.sh', - ); -}); diff --git a/tools/policy/format.sh b/tools/policy/format.sh deleted file mode 100755 index c6d228ca3..000000000 --- a/tools/policy/format.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -mode="${1:---check}" -case "$mode" in - --check) biome_args=(format); cargo_fmt_args=(--check); run_cargo=1 ;; - --check-js) biome_args=(format); cargo_fmt_args=(); run_cargo=0 ;; - --lint-js) biome_args=(lint --diagnostic-level=error); cargo_fmt_args=(); run_cargo=0 ;; - --write) biome_args=(format --write); cargo_fmt_args=(); run_cargo=1 ;; - *) echo "usage: tools/policy/format.sh [--check|--check-js|--lint-js|--write]" >&2; exit 2 ;; -esac - -if [ "$run_cargo" = 1 ]; then - cargo fmt "${cargo_fmt_args[@]}" -fi - -# Biome owns JS/TS/JSON/CSS formatting. Other language-native formatters are -# wired through their product build files to avoid overlapping format engines. -biome_paths=( - package.json \ - biome.json \ - renovate.json \ - .markdownlint-cli2.jsonc \ - src/docs/package.json \ - src/docs/next.config.mjs \ - src/docs/postcss.config.mjs \ - src/docs/proxy.ts \ - src/docs/source.config.ts \ - src/docs/src \ - src/docs/tools \ - src/bindings/wasix-ts/package.json \ - src/bindings/wasix-ts/src \ - src/bindings/wasix-ts/tools-package \ - examples/browser-wasix \ - src/bindings/wasix-ts/tools \ - src/shared/js-core/src \ - src/runtimes/liboliphaunt/native/tools-npm \ - src/runtimes/liboliphaunt/native/tools/smoke-packed-tools-npm.mjs \ - src/sdks/react-native/package.json \ - src/sdks/react-native/typedoc.json \ - src/sdks/react-native/react-native.config.js \ - src/sdks/react-native/src \ - src/sdks/js/package.json \ - src/sdks/js/typedoc.json \ - src/sdks/js/src \ - tools/integration \ - tools/perf/matrix \ - tools/perf/wasix-browser \ - tools/perf/wasix-node \ - tools/test -) -pnpm --dir src/docs exec biome "${biome_args[@]}" --config-path "$root/biome.json" \ - "${biome_paths[@]/#/$root/}" diff --git a/tools/policy/generate-sdk-api-surface.mjs b/tools/policy/generate-sdk-api-surface.mjs deleted file mode 100755 index fb40e9c0f..000000000 --- a/tools/policy/generate-sdk-api-surface.mjs +++ /dev/null @@ -1,1619 +0,0 @@ -#!/usr/bin/env node -import {execFileSync} from 'node:child_process'; -import {existsSync, readdirSync, readFileSync, writeFileSync} from 'node:fs'; -import path from 'node:path'; - -const root = execFileSync('git', ['rev-parse', '--show-toplevel'], { - encoding: 'utf8', -}).trim(); -const outputPath = path.join(root, 'docs/maintainers/sdk-api-surface.md'); -const mode = process.argv[2] ?? '--check'; - -if (!['--check', '--write'].includes(mode)) { - console.error('usage: tools/policy/generate-sdk-api-surface.mjs [--check|--write]'); - process.exit(2); -} - -function readRelative(relativePath) { - return readFileSync(path.join(root, relativePath), 'utf8'); -} - -function listFiles(relativeDir, extension) { - const absoluteDir = path.join(root, relativeDir); - if (!existsSync(absoluteDir)) { - return []; - } - return readdirSync(absoluteDir, {withFileTypes: true}) - .flatMap(entry => { - const child = path.join(relativeDir, entry.name); - if (entry.isDirectory()) { - return listFiles(child, extension); - } - return entry.isFile() && child.endsWith(extension) ? [child] : []; - }) - .sort(); -} - -function splitNames(raw) { - return raw - .split(',') - .map(name => name.trim()) - .filter(Boolean) - .map(name => name.replace(/\s+as\s+.*/u, '').trim()) - .filter(Boolean); -} - -function sorted(values) { - return Array.from(new Set(values)).sort(); -} - -function extractRustRootSymbols(indexFile, crateName) { - const lines = readRelative(indexFile).split('\n'); - const symbols = []; - let featureGate = null; - let skipDocHidden = false; - - for (let index = 0; index < lines.length; index += 1) { - const sourceLine = lines[index]; - const line = sourceLine.trim(); - if (line === '#[doc(hidden)]') { - skipDocHidden = true; - continue; - } - const gate = rustFeatureGate(line); - if (gate) { - featureGate = gate; - continue; - } - if (!sourceLine.startsWith('pub use ')) { - if (!rustItemPreamble(line)) { - featureGate = null; - skipDocHidden = false; - } - continue; - } - - let block = line; - while (!block.includes(';') && index + 1 < lines.length) { - index += 1; - block += ` ${lines[index].trim()}`; - } - if (!skipDocHidden) { - const spec = block - .replace(/^pub use\s+/u, '') - .replace(/;$/u, '') - .replace(/\s+/gu, ' ') - .trim(); - const grouped = spec.match(/^(.*)::\{(.*)\}$/u); - const names = grouped ? splitNames(grouped[2]) : [spec.split('::').pop()]; - for (const name of names.filter(Boolean)) { - symbols.push({featureGate, symbol: `${crateName}::${name}`}); - } - } - featureGate = null; - skipDocHidden = false; - } - - return symbols; -} - -function extractRustSurface( - indexFile = 'src/sdks/rust/src/lib.rs', - sourceDir = 'src/sdks/rust/src', - crateName = 'oliphaunt', - extraSourceFiles = [], - methodSourceFiles, -) { - const symbols = extractRustRootSymbols(indexFile, crateName).map( - rootSymbol => rootSymbol.symbol, - ); - - const sourceFiles = sorted([...listFiles(sourceDir, '.rs'), ...extraSourceFiles]); - for (const file of sourceFiles) { - const source = readRelative(file); - const macroPattern = - /#\[\s*macro_export\s*\]\s*(?:#\[[^\]]+\]\s*)*macro_rules!\s+([A-Za-z_][A-Za-z0-9_]*)/gu; - for (const match of source.matchAll(macroPattern)) { - symbols.push(`${crateName}::${match[1]}!`); - } - } - - const exportedNames = new Set( - symbols - .map(symbol => symbol.slice(`${crateName}::`.length)) - .filter(name => /^[A-Za-z_][A-Za-z0-9_]*$/u.test(name)), - ); - const exportedTypes = new Set(); - for (const file of sourceFiles) { - const source = readRelative(file); - for (const match of source.matchAll( - /^\s*pub\s+(?:struct|enum|union|trait|type)\s+([A-Za-z_][A-Za-z0-9_]*)/gmu, - )) { - if (exportedNames.has(match[1])) { - exportedTypes.add(match[1]); - } - } - } - symbols.push( - ...extractRustMembers( - sourceDir, - crateName, - exportedTypes, - extraSourceFiles, - methodSourceFiles, - ), - ); - - return sorted(symbols); -} - -function extractRustModuleSurface(files, sourceDir, crateName) { - const symbols = []; - const exportedTypes = new Set(); - for (const file of files) { - const source = readRelative(file); - for (const match of source.matchAll( - /^pub\s+(struct|enum|union|trait|type|const|static|fn)\s+([A-Za-z_][A-Za-z0-9_]*)/gmu, - )) { - const [, kind, name] = match; - symbols.push(`${crateName}::${name}${kind === 'fn' ? '()' : ''}`); - if (['struct', 'enum', 'union', 'trait', 'type'].includes(kind)) { - exportedTypes.add(name); - } - } - } - symbols.push(...extractRustMembers(sourceDir, crateName, exportedTypes)); - return sorted(symbols); -} - -function rustFeatureGate(line) { - const cfg = line.match(/^#\[cfg\((.*)\)\]$/u)?.[1]; - if (!cfg?.includes('feature')) { - return null; - } - const simple = cfg.match(/^feature\s*=\s*"([^"]+)"$/u); - return simple?.[1] ?? `cfg(${cfg})`; -} - -function rustItemPreamble(line) { - return line.length === 0 || line.startsWith('//') || line.startsWith('#['); -} - -function rustInherentImplType(header) { - const beforeBody = header.slice(0, header.indexOf('{')).trim(); - if (!beforeBody.startsWith('impl') || /\bfor\b/u.test(beforeBody)) { - return null; - } - let cursor = 'impl'.length; - while (/\s/u.test(beforeBody[cursor] ?? '')) cursor += 1; - if (beforeBody[cursor] === '<') { - let angleDepth = 0; - do { - const char = beforeBody[cursor]; - if (char === '<') angleDepth += 1; - if (char === '>') angleDepth -= 1; - cursor += 1; - } while (cursor < beforeBody.length && angleDepth > 0); - } - while (/\s/u.test(beforeBody[cursor] ?? '')) cursor += 1; - return beforeBody.slice(cursor).match(/^([A-Za-z_][A-Za-z0-9_]*)/u)?.[1] ?? null; -} - -function extractRustInherentMemberRecordsFromSource(source, crateName, exportedTypes) { - const members = []; - let depth = 0; - let pendingImpl = null; - let pendingImplFeatureGate = null; - let pendingMemberFeatureGate = null; - let skipDocHiddenMember = false; - let activeImpl = null; - - for (const line of source.split('\n')) { - if (activeImpl && depth < activeImpl.depth) { - activeImpl = null; - pendingMemberFeatureGate = null; - skipDocHiddenMember = false; - } - const trimmed = line.trim(); - - if (activeImpl && depth === activeImpl.depth) { - if (trimmed === '#[doc(hidden)]') { - skipDocHiddenMember = true; - } - const gate = rustFeatureGate(trimmed); - if (gate) { - pendingMemberFeatureGate = gate; - } - const method = trimmed.match( - /^pub\s+(?:(?:async|const|unsafe)\s+)*fn\s+([A-Za-z_][A-Za-z0-9_]*)/u, - ); - const constant = trimmed.match( - /^pub\s+const\s+([A-Za-z_][A-Za-z0-9_]*)\s*:/u, - ); - const memberName = method ? `${method[1]}()` : constant?.[1]; - if (memberName) { - if (!skipDocHiddenMember) { - members.push({ - featureGate: pendingMemberFeatureGate ?? activeImpl.featureGate, - symbol: `${crateName}::${activeImpl.name}.${memberName}`, - }); - } - pendingMemberFeatureGate = null; - skipDocHiddenMember = false; - } else if (!rustItemPreamble(trimmed)) { - pendingMemberFeatureGate = null; - skipDocHiddenMember = false; - } - } else if (!activeImpl && pendingImpl) { - pendingImpl += ` ${trimmed}`; - } else if (!activeImpl && /^impl(?:\s|<)/u.test(trimmed)) { - pendingImpl = trimmed; - } else if (!activeImpl) { - const gate = rustFeatureGate(trimmed); - if (gate) { - pendingImplFeatureGate = gate; - } else if (!rustItemPreamble(trimmed)) { - pendingImplFeatureGate = null; - } - } - - const braces = countBraces(line); - depth += braces.opens - braces.closes; - if (pendingImpl?.includes('{')) { - const name = rustInherentImplType(pendingImpl); - if (name && exportedTypes.has(name) && braces.opens > braces.closes) { - activeImpl = {featureGate: pendingImplFeatureGate, name, depth}; - } - pendingImpl = null; - pendingImplFeatureGate = null; - } - } - return members; -} - -function extractRustDeclaredMemberRecordsFromSource(source, crateName, exportedTypes) { - const members = []; - let depth = 0; - let pendingDeclaration = null; - let pendingDeclarationFeatureGate = null; - let pendingMemberFeatureGate = null; - let skipDocHiddenMember = false; - let activeDeclaration = null; - - for (const line of source.split('\n')) { - if (activeDeclaration && depth < activeDeclaration.depth) { - activeDeclaration = null; - pendingMemberFeatureGate = null; - skipDocHiddenMember = false; - } - const trimmed = line.trim(); - - if (activeDeclaration && depth === activeDeclaration.depth) { - if (trimmed === '#[doc(hidden)]') { - skipDocHiddenMember = true; - } - const gate = rustFeatureGate(trimmed); - if (gate) { - pendingMemberFeatureGate = gate; - } - - let memberName = null; - if (activeDeclaration.kind === 'trait') { - const method = trimmed.match( - /^(?:(?:async|const|unsafe)\s+)*fn\s+([A-Za-z_][A-Za-z0-9_]*)/u, - ); - const associatedType = trimmed.match( - /^type\s+([A-Za-z_][A-Za-z0-9_]*)/u, - ); - const associatedConstant = trimmed.match( - /^const\s+([A-Za-z_][A-Za-z0-9_]*)\s*:/u, - ); - memberName = method - ? `${method[1]}()` - : associatedType?.[1] ?? associatedConstant?.[1] ?? null; - } else { - memberName = trimmed.match( - /^pub\s+([A-Za-z_][A-Za-z0-9_]*)\s*:/u, - )?.[1] ?? null; - } - - if (memberName) { - if (!skipDocHiddenMember) { - members.push({ - featureGate: pendingMemberFeatureGate ?? activeDeclaration.featureGate, - symbol: `${crateName}::${activeDeclaration.name}.${memberName}`, - }); - } - pendingMemberFeatureGate = null; - skipDocHiddenMember = false; - } else if (!rustItemPreamble(trimmed)) { - pendingMemberFeatureGate = null; - skipDocHiddenMember = false; - } - } else if (!activeDeclaration && pendingDeclaration) { - pendingDeclaration.header += ` ${trimmed}`; - } else if (!activeDeclaration) { - const declaration = trimmed.match( - /^pub\s+(?:(?:unsafe|auto)\s+)?(struct|trait|union)\s+([A-Za-z_][A-Za-z0-9_]*)/u, - ); - if (declaration) { - pendingDeclaration = { - featureGate: pendingDeclarationFeatureGate, - header: trimmed, - kind: declaration[1], - name: declaration[2], - }; - } else { - const gate = rustFeatureGate(trimmed); - if (gate) { - pendingDeclarationFeatureGate = gate; - } else if (!rustItemPreamble(trimmed)) { - pendingDeclarationFeatureGate = null; - } - } - } - - const braces = countBraces(line); - depth += braces.opens - braces.closes; - if (pendingDeclaration?.header.includes('{')) { - if ( - exportedTypes.has(pendingDeclaration.name) - && braces.opens > braces.closes - ) { - activeDeclaration = { - depth, - featureGate: pendingDeclaration.featureGate, - kind: pendingDeclaration.kind, - name: pendingDeclaration.name, - }; - } - pendingDeclaration = null; - pendingDeclarationFeatureGate = null; - } else if (pendingDeclaration?.header.includes(';')) { - pendingDeclaration = null; - pendingDeclarationFeatureGate = null; - } - } - return members; -} - -function extractRustMemberRecords( - sourceDir, - crateName, - exportedTypes, - extraSourceFiles = [], - sourceFilesOverride, -) { - const sourceFiles = sourceFilesOverride - ?? sorted([...listFiles(sourceDir, '.rs'), ...extraSourceFiles]); - return sorted(sourceFiles).flatMap(file => { - const source = readRelative(file); - return [ - ...extractRustInherentMemberRecordsFromSource(source, crateName, exportedTypes), - ...extractRustDeclaredMemberRecordsFromSource(source, crateName, exportedTypes), - ]; - }); -} - -function extractRustMembers( - sourceDir, - crateName, - exportedTypes, - extraSourceFiles = [], - sourceFilesOverride, -) { - return extractRustMemberRecords( - sourceDir, - crateName, - exportedTypes, - extraSourceFiles, - sourceFilesOverride, - ).map(member => member.symbol); -} - -function extractNativeCSurface() { - const header = readRelative('src/runtimes/liboliphaunt/native/include/oliphaunt.h'); - const namedTypes = Array.from( - header.matchAll(/typedef[\s\S]*?\b(Oliphaunt[A-Za-z0-9_]*)\s*;/gu), - match => match[1], - ); - const functionPointerTypes = Array.from( - header.matchAll( - /typedef\s+[^;()]*\(\s*\*\s*(Oliphaunt[A-Za-z0-9_]*)\s*\)\s*\([^;]*\)\s*;/gu, - ), - match => match[1], - ); - const constants = Array.from( - header.matchAll(/^#define\s+(OLIPHAUNT_[A-Z0-9_]+)\s+[^\r\n]+$/gmu), - match => match[1], - ).filter(name => !['OLIPHAUNT_API', 'OLIPHAUNT_H'].includes(name)); - const functions = Array.from( - header.matchAll(/^OLIPHAUNT_API\s+[\s\S]*?\b(oliphaunt_[a-z0-9_]+)\s*\(/gmu), - match => `${match[1]}()`, - ); - return { - types: sorted([...namedTypes, ...functionPointerTypes]), - constants: sorted(constants), - functions: sorted(functions), - }; -} - -function countBraces(line) { - let opens = 0; - let closes = 0; - for (const char of line) { - if (char === '{') opens += 1; - if (char === '}') closes += 1; - } - return {opens, closes}; -} - -function multilineDeclarationStillOpen(line) { - return ( - !line.includes('{') && - ((line.includes('(') && !line.includes(')')) || line.endsWith(':')) - ); -} - -function swiftMemberName(line) { - const associatedTypeMatch = line.match( - /\bassociatedtype\s+([A-Za-z_][A-Za-z0-9_]*)/u, - ); - if (associatedTypeMatch) { - return associatedTypeMatch[1]; - } - if (/\bsubscript\s*[<(]/u.test(line)) { - return 'subscript'; - } - if (/\binit\s*\(/u.test(line)) { - return 'init'; - } - const functionMatch = line.match(/\bfunc\s+([A-Za-z_][A-Za-z0-9_]*)/u); - if (functionMatch) { - return `${functionMatch[1]}()`; - } - const valueMatch = line.match(/\b(?:var|let)\s+([A-Za-z_][A-Za-z0-9_]*)/u); - if (valueMatch) { - return valueMatch[1]; - } - return null; -} - -function extractSwiftFileSurface(source) { - const symbols = []; - let depth = 0; - const stack = []; - let awaitingContext = null; - const memberModifiers = - '(?:(?:static|class|final|override|required|convenience|mutating|nonmutating|nonisolated|distributed|borrowing|consuming)\\s+)*'; - const memberDeclaration = '(?:func|var|let|init|subscript|associatedtype)'; - const publicMemberPattern = new RegExp( - `^public\\s+${memberModifiers}${memberDeclaration}\\b`, - 'u', - ); - const implicitMemberPattern = new RegExp( - `^${memberModifiers}${memberDeclaration}\\b`, - 'u', - ); - - for (const line of source.split('\n')) { - while (stack.length > 0 && depth < stack[stack.length - 1].depth) { - stack.pop(); - } - - const trimmed = line.trim(); - if (trimmed.length === 0 || trimmed.startsWith('//')) { - const braces = countBraces(line); - depth += braces.opens - braces.closes; - continue; - } - - const active = awaitingContext ?? stack[stack.length - 1]; - let pendingContext = null; - const typeMatch = trimmed.match( - /^public\s+(?:(?:final|indirect)\s+)*(enum|struct|actor|protocol|class)\s+([A-Za-z_][A-Za-z0-9_]*)/u, - ); - const typealiasMatch = trimmed.match( - /^public\s+typealias\s+([A-Za-z_][A-Za-z0-9_]*)/u, - ); - const extensionMatch = trimmed.match( - /^public\s+extension\s+([A-Za-z_][A-Za-z0-9_.]*)/u, - ); - - if (typeMatch) { - const name = active ? `${active.name}.${typeMatch[2]}` : typeMatch[2]; - symbols.push(`${typeMatch[1]} ${name}`); - pendingContext = {kind: typeMatch[1], name, depth: depth + 1}; - } else if (typealiasMatch) { - const name = active - ? `${active.name}.${typealiasMatch[1]}` - : typealiasMatch[1]; - symbols.push(`typealias ${name}`); - } else if (extensionMatch) { - symbols.push(`extension ${extensionMatch[1]}`); - pendingContext = { - extension: true, - kind: 'extension', - name: extensionMatch[1], - depth: depth + 1, - }; - } else { - const inPublicExtension = active?.extension === true; - const isPublicMember = publicMemberPattern.test(trimmed); - const isExtensionMember = - inPublicExtension && implicitMemberPattern.test(trimmed); - const isProtocolRequirement = - active?.kind === 'protocol' && implicitMemberPattern.test(trimmed); - const isDeclarationDepth = active ? depth === active.depth : depth === 0; - if ( - (isPublicMember || isExtensionMember || isProtocolRequirement) - && isDeclarationDepth - ) { - const member = swiftMemberName(trimmed); - if (member) { - symbols.push(active ? `${active.name}.${member}` : member); - } - } - } - - const braces = countBraces(line); - depth += braces.opens - braces.closes; - if (pendingContext && braces.opens > braces.closes) { - pendingContext.depth = depth; - stack.push(pendingContext); - awaitingContext = null; - } else if (pendingContext && multilineDeclarationStillOpen(trimmed)) { - awaitingContext = pendingContext; - } else if (awaitingContext && braces.opens > braces.closes) { - awaitingContext.depth = depth; - stack.push(awaitingContext); - awaitingContext = null; - } else if (awaitingContext && trimmed.startsWith(')')) { - awaitingContext = null; - } - } - - return sorted(symbols); -} - -function extractSwiftSurface( - sourceDir = 'src/sdks/swift/Sources/Oliphaunt', -) { - return sorted( - listFiles(sourceDir, '.swift').flatMap(file => - extractSwiftFileSurface(readRelative(file)), - ), - ); -} - -function kotlinMemberName(line) { - const functionMatch = line.match( - /\bfun\s+(?:<[^>]+>\s*)?(?:(?:[A-Za-z_][A-Za-z0-9_]*\.)+)?([A-Za-z_][A-Za-z0-9_]*)\s*\(/u, - ); - if (functionMatch) { - const receiverMatch = line.match( - /\bfun\s+(?:<[^>]+>\s*)?((?:[A-Za-z_][A-Za-z0-9_]*\.)+)[A-Za-z_][A-Za-z0-9_]*\s*\(/u, - ); - return { - name: `${functionMatch[1]}()`, - receiver: receiverMatch ? receiverMatch[1].replace(/\.$/u, '') : null, - }; - } - const valueMatch = line.match(/\b(?:val|var)\s+([A-Za-z_][A-Za-z0-9_]*)/u); - if (valueMatch) { - return {name: valueMatch[1], receiver: null}; - } - return null; -} - -function kotlinConstructorPropertyNames(line) { - return Array.from( - line.matchAll( - /(?:^|[,(])\s*(?:(public|private|protected|internal)\s+)?(?:override\s+)?(?:vararg\s+)?(?:val|var)\s+([A-Za-z_][A-Za-z0-9_]*)/gu, - ), - match => ({name: match[2], visibility: match[1] ?? 'public'}), - ) - .filter(property => property.visibility === 'public') - .map(property => property.name); -} - -function extractKotlinFileSurface(source) { - const symbols = []; - let depth = 0; - const stack = []; - let awaitingContext = null; - - for (const line of source.split('\n')) { - while (stack.length > 0 && depth < stack[stack.length - 1].depth) { - stack.pop(); - } - - const trimmed = line.trim(); - if (trimmed.length === 0 || trimmed.startsWith('//')) { - const braces = countBraces(line); - depth += braces.opens - braces.closes; - continue; - } - - const active = awaitingContext ?? stack[stack.length - 1]; - let pendingContext = null; - const typeMatch = trimmed.match( - /^public\s+(?:(?:data|sealed|open)\s+)*(enum\s+class|data\s+class|sealed\s+class|open\s+class|value\s+class|fun\s+interface|class|object|interface)\s+([A-Za-z_][A-Za-z0-9_]*)/u, - ); - - if (typeMatch) { - const name = active ? `${active.name}.${typeMatch[2]}` : typeMatch[2]; - symbols.push(`${typeMatch[1]} ${name}`); - pendingContext = {name, depth: depth + 1}; - for (const property of kotlinConstructorPropertyNames(trimmed)) { - symbols.push(`${name}.${property}`); - } - } else if (awaitingContext) { - for (const property of kotlinConstructorPropertyNames(trimmed)) { - symbols.push(`${awaitingContext.name}.${property}`); - } - } - - if (!typeMatch && /^public\s+(?:expect\s+|actual\s+)?(?:suspend\s+)?fun\b/u.test(trimmed)) { - const member = kotlinMemberName(trimmed); - if (member) { - const owner = member.receiver ?? active?.name; - symbols.push(owner ? `${owner}.${member.name}` : member.name); - } - } else if (!typeMatch && /^public\s+(?:val|var)\b/u.test(trimmed)) { - const member = kotlinMemberName(trimmed); - if (member) { - symbols.push(active ? `${active.name}.${member.name}` : member.name); - } - } - - const braces = countBraces(line); - depth += braces.opens - braces.closes; - if (pendingContext && braces.opens > braces.closes) { - pendingContext.depth = depth; - stack.push(pendingContext); - awaitingContext = null; - } else if (pendingContext && multilineDeclarationStillOpen(trimmed)) { - awaitingContext = pendingContext; - } else if (awaitingContext && braces.opens > braces.closes) { - awaitingContext.depth = depth; - stack.push(awaitingContext); - awaitingContext = null; - } else if (awaitingContext && trimmed.startsWith(')')) { - awaitingContext = null; - } - } - - return sorted(symbols); -} - -function extractKotlinSurface() { - const sourceSets = ['commonMain', 'androidMain', 'jvmMain']; - const sections = []; - - for (const sourceSet of sourceSets) { - const files = listFiles( - `src/sdks/kotlin/oliphaunt/src/${sourceSet}/kotlin/dev/oliphaunt`, - '.kt', - ); - const symbols = []; - - for (const file of files) { - symbols.push(...extractKotlinFileSurface(readRelative(file))); - } - - sections.push({sourceSet, symbols: sorted(symbols)}); - } - - return sections; -} - -function extractKotlinGradlePluginSurface() { - const build = readRelative( - 'src/sdks/kotlin/oliphaunt-android-gradle-plugin/build.gradle.kts', - ); - const extension = readRelative( - 'src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidExtension.java', - ); - const symbols = []; - const pluginId = build.match(/^\s*id\s*=\s*"([^"]+)"/mu)?.[1]; - if (pluginId) symbols.push(`plugin ${pluginId}`); - const className = extension.match(/public\s+abstract\s+class\s+([A-Za-z_][A-Za-z0-9_]*)/u)?.[1]; - if (className) { - symbols.push(`class ${className}`); - for (const match of extension.matchAll( - /public\s+abstract\s+[^;()]+\s+(get[A-Za-z_][A-Za-z0-9_]*)\s*\(\s*\)\s*;/gu, - )) { - symbols.push(`${className}.${match[1]}()`); - } - } - return sorted(symbols); -} - -function extractTypeScriptSurface(indexFile, memberFiles) { - const indexFiles = Array.isArray(indexFile) ? indexFile : [indexFile]; - const text = indexFiles.map(readRelative).join('\n'); - const types = []; - const values = []; - - for (const match of text.matchAll(/export\s+type\s+\{([\s\S]*?)\}\s+from/gu)) { - types.push(...splitNames(match[1])); - } - for (const match of text.matchAll(/export\s+\{([\s\S]*?)\}\s+from/gu)) { - for (const entry of splitTypeScriptExportNames(match[1])) { - (entry.typeOnly ? types : values).push(entry.name); - } - } - for (const match of text.matchAll(/export\s+const\s+([A-Za-z_][A-Za-z0-9_]*)/gu)) { - values.push(match[1]); - } - for (const match of text.matchAll( - /export\s+(?:async\s+)?(?:class|function)\s+([A-Za-z_][A-Za-z0-9_]*)/gu, - )) { - values.push(match[1]); - } - for (const match of text.matchAll(/export\s+type\s+([A-Za-z_][A-Za-z0-9_]*)/gu)) { - types.push(match[1]); - } - - const exportedTypes = new Set(types); - const exportedValues = new Set(values); - const members = extractTypeScriptMembers(exportedTypes, exportedValues, memberFiles); - - return { - types: sorted(types), - values: sorted(values), - members, - }; -} - -function splitTypeScriptExportNames(raw) { - return raw - .split(',') - .map(name => name.trim()) - .filter(Boolean) - .map(name => { - const typeOnly = name.startsWith('type '); - return { - typeOnly, - name: name - .replace(/^type\s+/u, '') - .replace(/\s+as\s+.*/u, '') - .trim(), - }; - }) - .filter(entry => entry.name.length > 0); -} - -function extractReactNativeSurface() { - return extractTypeScriptSurface('src/sdks/react-native/src/index.ts', [ - 'src/sdks/react-native/src/client.ts', - 'src/shared/js-core/src/protocol.ts', - 'src/shared/js-core/src/query.ts', - ]); -} - -function extractOliphauntTsSurface() { - return extractTypeScriptSurface('src/sdks/js/src/index.ts', [ - 'src/sdks/js/src/client.ts', - 'src/shared/js-core/src/protocol.ts', - 'src/shared/js-core/src/query.ts', - 'src/sdks/js/src/types.ts', - ]); -} - -function extractOliphauntWasixTsSurface() { - return extractTypeScriptSurface([ - 'src/bindings/wasix-ts/src/index.ts', - 'src/bindings/wasix-ts/src/public.ts', - ], [ - 'src/bindings/wasix-ts/src/client.ts', - 'src/bindings/wasix-ts/src/errors.ts', - 'src/bindings/wasix-ts/src/extension-descriptor.ts', - 'src/shared/js-core/src/protocol.ts', - 'src/shared/js-core/src/query.ts', - 'src/bindings/wasix-ts/src/storage.ts', - 'src/bindings/wasix-ts/src/types.ts', - ]); -} - -function extractOliphauntWasixWorkerTsSurface() { - return extractTypeScriptSurface([ - 'src/bindings/wasix-ts/src/worker-entry.ts', - 'src/bindings/wasix-ts/src/public.ts', - ], [ - 'src/bindings/wasix-ts/src/worker-client.ts', - 'src/bindings/wasix-ts/src/worker-node-client.ts', - 'src/bindings/wasix-ts/src/errors.ts', - 'src/bindings/wasix-ts/src/extension-descriptor.ts', - 'src/shared/js-core/src/protocol.ts', - 'src/shared/js-core/src/query.ts', - 'src/bindings/wasix-ts/src/storage.ts', - 'src/bindings/wasix-ts/src/types.ts', - ]); -} - -function extractPackageExports(manifestFile) { - const manifest = JSON.parse(readRelative(manifestFile)); - return Object.entries(manifest.exports ?? {}).map(([subpath, entry]) => - `${subpath} = ${JSON.stringify(entry)}`, - ); -} - -function typeScriptMemberName(line) { - const declaration = line.replace(/^(?:public\s+)?(?:static\s+)?/u, ''); - const getterMatch = declaration.match(/^get\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/u); - if (getterMatch) { - return getterMatch[1]; - } - const computedMethodMatch = declaration.match( - /^\[Symbol\.([A-Za-z_][A-Za-z0-9_]*)\]\s*\(/u, - ); - if (computedMethodMatch) { - return `[Symbol.${computedMethodMatch[1]}]()`; - } - const methodMatch = declaration.match( - /^(?:async\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*(?:<|\()/u, - ); - if (methodMatch) { - return `${methodMatch[1]}()`; - } - const propertyMatch = declaration.match( - /^(?:readonly\s+)?([A-Za-z_][A-Za-z0-9_]*)\??:/u, - ); - if (propertyMatch) { - return propertyMatch[1]; - } - return null; -} - -function extractTypeScriptMembers(exportedTypes, exportedValues, files) { - const members = []; - - for (const file of files) { - let depth = 0; - const stack = []; - let awaitingContext = null; - let awaitingMemberEnd = null; - let skipInternalMember = false; - for (const line of readRelative(file).split('\n')) { - while (stack.length > 0 && depth < stack[stack.length - 1].depth) { - stack.pop(); - } - - if (awaitingMemberEnd && stack[stack.length - 1]?.name !== awaitingMemberEnd) { - awaitingMemberEnd = null; - } - - const trimmed = line.trim(); - if (trimmed === '/** @internal */') { - skipInternalMember = true; - continue; - } - if (trimmed.length === 0 || trimmed.startsWith('//')) { - const braces = countBraces(line); - depth += braces.opens - braces.closes; - continue; - } - - const active = stack[stack.length - 1] ?? awaitingContext; - let pendingContext = null; - const typeMatch = trimmed.match(/^export\s+type\s+([A-Za-z_][A-Za-z0-9_]*)/u); - const classMatch = trimmed.match(/^export\s+class\s+([A-Za-z_][A-Za-z0-9_]*)/u); - const functionMatch = trimmed.match( - /^export\s+(?:async\s+)?function\s+([A-Za-z_][A-Za-z0-9_]*)/u, - ); - const constMatch = trimmed.match(/^export\s+const\s+([A-Za-z_][A-Za-z0-9_]*)/u); - - if (typeMatch) { - if (exportedTypes.has(typeMatch[1])) { - pendingContext = {name: typeMatch[1], depth: depth + 1}; - } - } else if (classMatch) { - if (exportedValues.has(classMatch[1])) { - pendingContext = {name: classMatch[1], depth: depth + 1}; - } - } else if (functionMatch || constMatch) { - // Top-level exports are already recorded in Values. - } else if (active && depth === active.depth && awaitingMemberEnd === null) { - const isPrivate = trimmed.startsWith('#') || /^(?:private|protected)\b/u.test(trimmed); - const declaration = trimmed - .replace(/^#/u, '') - .replace(/^(?:private|protected)\s+/u, ''); - const member = typeScriptMemberName(declaration); - if (member) { - if (!skipInternalMember && !isPrivate) { - members.push(`${active.name}.${member}`); - } - const braces = countBraces(line); - if (!trimmed.includes(';') && braces.opens <= braces.closes) { - awaitingMemberEnd = active.name; - } - } - } - skipInternalMember = false; - - const braces = countBraces(line); - depth += braces.opens - braces.closes; - if (pendingContext && braces.opens > braces.closes) { - pendingContext.depth = depth; - stack.push(pendingContext); - awaitingContext = null; - } else if (pendingContext && !trimmed.includes(';')) { - awaitingContext = pendingContext; - } else if (awaitingContext && braces.opens > braces.closes) { - awaitingContext.depth = depth; - stack.push(awaitingContext); - awaitingContext = null; - } else if (awaitingContext && (trimmed.startsWith('}') || trimmed.includes(';'))) { - awaitingContext = null; - } - - if ( - awaitingMemberEnd && - (trimmed.includes(';') || braces.opens > braces.closes) - ) { - awaitingMemberEnd = null; - } - } - } - - return sorted(members); -} - -function requireTypeScriptQuerySurface(surface, packageName) { - for (const type of ['InferQueryRow', 'QueryDecoderMap', 'QueryOptions', 'QueryRowMode']) { - if (!surface.types.includes(type)) { - throw new Error(`TypeScript API inventory is missing ${packageName} type ${type}`); - } - } - for (const member of [ - 'OliphauntDatabase.query()', - 'OliphauntTransaction.query()', - 'QueryOptions.decoders', - 'QueryOptions.encoders', - 'QueryOptions.rowMode', - 'QueryOptions.valueMode', - ]) { - if (!surface.members.includes(member)) { - throw new Error(`TypeScript API inventory is missing ${packageName} member ${member}`); - } - } -} - -function markdownList(items) { - if (items.length === 0) { - return '- none\n'; - } - return `${items.map(item => `- \`${item}\``).join('\n')}\n`; -} - -function requireRustQueryCoreSurface(symbols, crateName) { - for (const member of [ - 'CommandResult.row_count()', - 'ExecResult.statements()', - 'FromSql.from_sql()', - 'IntoParameter.into_parameter()', - 'Parameter.binary()', - 'Parameter.typed_text()', - 'QueryField.name', - 'QueryField.type_oid_value()', - 'QueryResult.rows()', - 'QueryRow.try_get()', - 'StatementDescription.parameter_types()', - 'TypeOid.get()', - 'ValueRef.as_bytes()', - ]) { - const symbol = `${crateName}::${member}`; - if (!symbols.includes(symbol)) { - throw new Error(`Rust API inventory did not follow shared query core for ${symbol}`); - } - } -} - -function rejectRustRootSymbols(symbols, crateName, names) { - for (const name of names) { - const symbol = `${crateName}::${name}`; - if (symbols.includes(symbol)) { - throw new Error(`Rust API inventory flattened a nested module symbol into ${symbol}`); - } - } -} - -function addFeatureSymbol(featureSymbols, featureGate, symbol) { - if (!featureGate) { - return; - } - const symbols = featureSymbols.get(featureGate) ?? new Set(); - symbols.add(symbol); - featureSymbols.set(featureGate, symbols); -} - -function buildWasixRustFeatureSurface({ - members, - rootSymbols, - symbols, - toolSymbols, -}) { - const featureSymbols = new Map(); - const directlyGatedSymbols = new Set( - members.filter(member => member.featureGate).map(member => member.symbol), - ); - - for (const rootSymbol of rootSymbols) { - for (const symbol of symbols) { - if ( - !directlyGatedSymbols.has(symbol) - && (symbol === rootSymbol.symbol || symbol.startsWith(`${rootSymbol.symbol}.`)) - ) { - addFeatureSymbol(featureSymbols, rootSymbol.featureGate, symbol); - } - } - } - for (const member of members) { - addFeatureSymbol(featureSymbols, member.featureGate, member.symbol); - } - for (const symbol of toolSymbols) { - addFeatureSymbol(featureSymbols, 'tools', symbol); - } - - const gatedSymbols = new Set( - Array.from(featureSymbols.values()).flatMap(featureSet => [...featureSet]), - ); - return { - defaultSymbols: symbols.filter(symbol => !gatedSymbols.has(symbol)), - featureSymbols: new Map( - Array.from(featureSymbols, ([feature, featureSet]) => [ - feature, - sorted(featureSet), - ]), - ), - }; -} - -function requireWasixRustFeatureSurface(surface) { - const requiredDefault = [ - 'oliphaunt_wasix::AsyncOliphaunt.query()', - 'oliphaunt_wasix::Oliphaunt.query()', - ]; - const requiredExtensions = [ - 'oliphaunt_wasix::AsyncOliphauntBuilder.extension()', - 'oliphaunt_wasix::Extension', - 'oliphaunt_wasix::Extension.ALL', - 'oliphaunt_wasix::OliphauntBuilder.extensions()', - ]; - const requiredTools = [ - 'oliphaunt_wasix::AsyncOliphaunt.pg_dump()', - 'oliphaunt_wasix::Error.tool_error()', - 'oliphaunt_wasix::Oliphaunt.psql()', - 'oliphaunt_wasix::tools::PgDumpOptions', - ]; - for (const symbol of requiredDefault) { - if (!surface.defaultSymbols.includes(symbol)) { - throw new Error(`WASIX Rust default API inventory is missing ${symbol}`); - } - } - for (const [feature, required] of [ - ['extensions', requiredExtensions], - ['tools', requiredTools], - ]) { - const symbols = surface.featureSymbols.get(feature) ?? []; - for (const symbol of required) { - if (!symbols.includes(symbol)) { - throw new Error(`WASIX Rust ${feature} API inventory is missing ${symbol}`); - } - if (surface.defaultSymbols.includes(symbol)) { - throw new Error(`WASIX Rust default API inventory includes gated ${symbol}`); - } - } - } - - const declaredExtensionFeatures = sorted( - Array.from( - readRelative('src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml').matchAll( - /^(extension-[a-z0-9-]+)\s*=/gmu, - ), - match => match[1], - ), - ); - const inventoriedExtensionFeatures = sorted( - Array.from(surface.featureSymbols.keys()).filter(feature => - feature.startsWith('extension-'), - ), - ); - if ( - JSON.stringify(declaredExtensionFeatures) - !== JSON.stringify(inventoriedExtensionFeatures) - ) { - throw new Error( - 'WASIX Rust per-extension API inventory does not match declared Cargo features', - ); - } - for (const feature of declaredExtensionFeatures) { - const constants = surface.featureSymbols - .get(feature) - ?.filter(symbol => symbol.startsWith('oliphaunt_wasix::Extension.')) ?? []; - if (constants.length !== 1) { - throw new Error( - `WASIX Rust ${feature} API inventory must own exactly one Extension constant`, - ); - } - } -} - -function markdownFeatureList(featureSymbols) { - if (featureSymbols.length === 0) { - return '- none\n'; - } - return `${featureSymbols - .map(([feature, symbol]) => `- \`${feature}\`: \`${symbol}\``) - .join('\n')}\n`; -} - -function requireExtractorFixture(label, symbols, required, forbidden) { - for (const symbol of required) { - if (!symbols.includes(symbol)) { - throw new Error(`${label} extractor fixture is missing ${symbol}`); - } - } - for (const symbol of forbidden) { - if (symbols.includes(symbol)) { - throw new Error(`${label} extractor fixture exposed ${symbol}`); - } - } -} - -function requireApiExtractorFixtures() { - const rustSource = ` -pub struct Record { - pub visible: u32, - private: u32, - pub(crate) crate_visible: u32, -} - -pub trait Codec { - type Output; - const FORMAT: u8; - fn decode(&self); - #[doc(hidden)] - fn hidden(&self); -} - -impl Record { - pub const DEFAULT: Self = Self { visible: 0, private: 0, crate_visible: 0 }; - pub fn read(&self) {} - #[doc(hidden)] - pub fn hidden(&self) {} -} -`; - const rustTypes = new Set(['Codec', 'Record']); - const rustSymbols = [ - ...extractRustDeclaredMemberRecordsFromSource(rustSource, 'fixture', rustTypes), - ...extractRustInherentMemberRecordsFromSource(rustSource, 'fixture', rustTypes), - ].map(member => member.symbol); - requireExtractorFixture( - 'Rust', - rustSymbols, - [ - 'fixture::Codec.FORMAT', - 'fixture::Codec.Output', - 'fixture::Codec.decode()', - 'fixture::Record.DEFAULT', - 'fixture::Record.read()', - 'fixture::Record.visible', - ], - [ - 'fixture::Codec.hidden()', - 'fixture::Record.crate_visible', - 'fixture::Record.hidden()', - 'fixture::Record.private', - ], - ); - - const swiftSymbols = extractSwiftFileSurface(` -public protocol Codec { - associatedtype Output - static var format: Int { get } - mutating func decode() - subscript(index: Int) -> Output { get } -} - -internal protocol InternalCodec { - func hidden() -} -`); - requireExtractorFixture( - 'Swift', - swiftSymbols, - [ - 'Codec.Output', - 'Codec.decode()', - 'Codec.format', - 'Codec.subscript', - 'protocol Codec', - ], - ['InternalCodec.hidden()', 'protocol InternalCodec'], - ); - - const kotlinSymbols = extractKotlinFileSurface(` -public data class Record( - val implicit: String, - public var explicit: Int, - private val privateValue: String, - internal val internalValue: String, -) - -public sealed interface Node { - public data class Leaf(val value: String, protected val hidden: String) : Node -} - -internal data class InternalRecord(val hidden: String) -`); - requireExtractorFixture( - 'Kotlin', - kotlinSymbols, - [ - 'Node.Leaf.value', - 'Record.explicit', - 'Record.implicit', - ], - [ - 'InternalRecord.hidden', - 'Node.Leaf.hidden', - 'Record.internalValue', - 'Record.privateValue', - ], - ); -} - -function render() { - requireApiExtractorFixtures(); - const nativeC = extractNativeCSurface(); - const kotlin = extractKotlinSurface(); - const kotlinGradlePlugin = extractKotlinGradlePluginSurface(); - const swift = extractSwiftSurface(); - requireExtractorFixture( - 'Swift SDK', - swift, - [ - 'OliphauntPostgresDecodable.decodePostgres()', - 'protocol OliphauntPostgresDecodable', - 'typealias OliphauntPostgresNotice', - ], - [], - ); - const kotlinCommon = kotlin.find(section => section.sourceSet === 'commonMain')?.symbols ?? []; - requireExtractorFixture( - 'Kotlin SDK', - kotlinCommon, - [ - 'PostgresStartupGuc.name', - 'QueryField.name', - 'StatementResult.Command.result', - ], - [], - ); - const rn = extractReactNativeSurface(); - const ts = extractOliphauntTsSurface(); - const wasixTs = extractOliphauntWasixTsSurface(); - const wasixWorkerTs = extractOliphauntWasixWorkerTsSurface(); - const wasixIndexedDb = extractTypeScriptSurface( - 'src/bindings/wasix-ts/src/storage/indexed-db.ts', - ['src/bindings/wasix-ts/src/storage/indexed-db.ts'], - ); - const wasixOpfs = extractTypeScriptSurface( - 'src/bindings/wasix-ts/src/storage/opfs.ts', - ['src/bindings/wasix-ts/src/storage/opfs.ts'], - ); - const wasixNodeDirectory = extractTypeScriptSurface( - 'src/bindings/wasix-ts/src/storage/node.ts', - ['src/bindings/wasix-ts/src/storage/node.ts'], - ); - const wasixBunDirectory = extractTypeScriptSurface( - 'src/bindings/wasix-ts/src/storage/bun.ts', - ['src/bindings/wasix-ts/src/storage/bun.ts'], - ); - const wasixDenoDirectory = extractTypeScriptSurface( - 'src/bindings/wasix-ts/src/storage/deno.ts', - ['src/bindings/wasix-ts/src/storage/deno.ts'], - ); - const nativeToolsTs = extractTypeScriptSurface( - 'src/runtimes/liboliphaunt/native/tools-npm/index.d.ts', - ['src/runtimes/liboliphaunt/native/tools-npm/index.d.ts'], - ); - const wasixTsServer = extractTypeScriptSurface( - 'src/bindings/wasix-ts/src/server.node.ts', - ['src/bindings/wasix-ts/src/server.node.ts'], - ); - const wasixToolsTs = extractTypeScriptSurface( - 'src/bindings/wasix-ts/tools-package/src/index.ts', - ['src/bindings/wasix-ts/tools-package/src/index.ts'], - ); - requireTypeScriptQuerySurface(rn, '@oliphaunt/react-native'); - requireTypeScriptQuerySurface(ts, '@oliphaunt/ts'); - requireTypeScriptQuerySurface(wasixTs, '@oliphaunt/wasix-ts'); - requireTypeScriptQuerySurface(wasixWorkerTs, '@oliphaunt/wasix-ts/worker'); - const sharedRustQueryCore = ['src/shared/rust-query-core/query_core.rs']; - const nativeRustSourceDir = 'src/sdks/rust/src'; - const nativeRust = extractRustSurface( - 'src/sdks/rust/src/lib.rs', - nativeRustSourceDir, - 'oliphaunt', - sharedRustQueryCore, - [ - ...listFiles(nativeRustSourceDir, '.rs'), - ...sharedRustQueryCore, - ], - ); - const nativeRustBrokerSeam = extractRustModuleSurface( - [ - 'src/sdks/rust/src/broker_support.rs', - 'src/sdks/rust/src/ipc.rs', - ], - 'src/sdks/rust/src', - 'oliphaunt::__private', - ); - const nativeRustPackagingNames = new Set([ - 'NativePackagingCatalogProfile', - 'NativePackagingResources', - 'NativePackagingRuntime', - 'materialize_native_packaging_resources()', - ]); - const nativeRustPackagingSeam = extractRustModuleSurface( - ['src/sdks/rust/src/liboliphaunt/mod.rs'], - 'src/sdks/rust/src/liboliphaunt', - 'oliphaunt::__private::packaging', - ).filter(symbol => - nativeRustPackagingNames.has( - symbol.slice('oliphaunt::__private::packaging::'.length), - ), - ); - const wasixRustSourceDir = - 'src/bindings/wasix-rust/crates/oliphaunt-wasix/src'; - const wasixRustSourceFiles = [ - ...listFiles(wasixRustSourceDir, '.rs'), - ...sharedRustQueryCore, - ]; - const wasixRust = extractRustSurface( - 'src/bindings/wasix-rust/crates/oliphaunt-wasix/src/lib.rs', - wasixRustSourceDir, - 'oliphaunt_wasix', - sharedRustQueryCore, - wasixRustSourceFiles, - ); - const wasixRustExportedTypes = new Set( - wasixRust - .filter(symbol => /^oliphaunt_wasix::[A-Za-z_][A-Za-z0-9_]*$/u.test(symbol)) - .map(symbol => symbol.slice('oliphaunt_wasix::'.length)), - ); - const wasixRustTools = extractRustModuleSurface( - ['src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/tools.rs'], - 'src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt', - 'oliphaunt_wasix::tools', - ); - const wasixRustFeatureSurface = buildWasixRustFeatureSurface({ - members: extractRustMemberRecords( - wasixRustSourceDir, - 'oliphaunt_wasix', - wasixRustExportedTypes, - sharedRustQueryCore, - wasixRustSourceFiles, - ), - rootSymbols: extractRustRootSymbols( - 'src/bindings/wasix-rust/crates/oliphaunt-wasix/src/lib.rs', - 'oliphaunt_wasix', - ).filter(rootSymbol => rootSymbol.featureGate), - symbols: wasixRust, - toolSymbols: wasixRustTools, - }); - requireWasixRustFeatureSurface(wasixRustFeatureSurface); - requireRustQueryCoreSurface(nativeRust, 'oliphaunt'); - requireRustQueryCoreSurface(wasixRust, 'oliphaunt_wasix'); - rejectRustRootSymbols(nativeRust, 'oliphaunt', [ - 'BrokerIpcRequest', - 'NativePackagingCatalogProfile', - 'NativePackagingResources', - 'NativePackagingRuntime', - 'broker_ipc_read_request', - 'materialize_native_packaging_resources', - ]); - for (const required of [ - 'oliphaunt::__private::open()', - 'oliphaunt::__private::BrokerSession.exec_protocol_raw_stream()', - 'oliphaunt::__private::broker_ipc_read_request()', - ]) { - if (!nativeRustBrokerSeam.includes(required)) { - throw new Error(`Rust broker seam inventory is missing ${required}`); - } - } - for (const required of [ - 'oliphaunt::__private::packaging::NativePackagingResources', - 'oliphaunt::__private::packaging::materialize_native_packaging_resources()', - ]) { - if (!nativeRustPackagingSeam.includes(required)) { - throw new Error(`Rust packaging seam inventory is missing ${required}`); - } - } - rejectRustRootSymbols(wasixRust, 'oliphaunt_wasix', [ - 'PgDumpOptions', - 'PostgresToolError', - 'PsqlOptions', - 'pg_dump', - 'psql', - ]); - let output = `\n`; - output += `# SDK API Surface Inventory\n\n`; - output += `This no-build inventory records exported type names and statically named public members that its source extractors can resolve: named Rust fields, inherent members, and trait requirements; Swift public members and public-protocol requirements; Kotlin explicit public members and public primary-constructor properties; and TypeScript declared members. It intentionally does not model complete signatures, enum variants, unnamed Rust tuple fields, inherited or synthesized members, or JavaScript default exports. Compile-time public-API tests and package-shape checks own those contracts; this inventory is not a replacement for full language reference documentation.\n\n`; - output += `Regenerate with:\n\n`; - output += `\`\`\`sh\n`; - output += `node tools/policy/generate-sdk-api-surface.mjs --write\n`; - output += `\`\`\`\n\n`; - output += `## Rust: oliphaunt\n\n`; - output += markdownList(nativeRust); - output += `\n### Version-locked broker seam (not application API)\n\n`; - output += `The separately built \`oliphaunt-broker\` executable enables \`__internal-broker-helper\` and consumes this exact-version seam. It is absent from default builds and may change only in lockstep with that executable.\n\n`; - output += markdownList(nativeRustBrokerSeam); - output += `\n### Version-locked native packaging seam (not application API)\n\n`; - output += `The unpublished workspace packaging tool enables \`internal-native-packaging\` and consumes \`oliphaunt::__private::packaging\`. It is absent from default builds and may change only in lockstep with that tool.\n\n`; - output += markdownList(nativeRustPackagingSeam); - output += `\n## Rust build integration: oliphaunt-build\n\n`; - output += markdownList( - extractRustModuleSurface( - ['src/sdks/rust/crates/oliphaunt-build/src/lib.rs'], - 'src/sdks/rust/crates/oliphaunt-build/src', - 'oliphaunt_build', - ), - ); - output += `\n## Native Rust tools: oliphaunt-tools\n\n`; - output += markdownList( - extractRustModuleSurface( - ['src/runtimes/liboliphaunt/native/crates/tools/src/lib.rs'], - 'src/runtimes/liboliphaunt/native/crates/tools/src', - 'oliphaunt_tools', - ), - ); - output += `\n## Rust WASIX: oliphaunt-wasix\n\n`; - output += `### Default Cargo features (cross-target union)\n\n`; - output += - `These symbols require no optional Cargo feature. Target-gated symbols ` + - `(for example Unix-domain listener helpers) remain a cross-target union; ` + - `consumer compile tests own target availability.\n\n`; - output += markdownList(wasixRustFeatureSurface.defaultSymbols); - const wasixRustFeatureOrder = new Map([['extensions', 0], ['tools', 1]]); - const nonLeafWasixRustFeatures = Array.from( - wasixRustFeatureSurface.featureSymbols.keys(), - ) - .filter(feature => !feature.startsWith('extension-')) - .sort( - (left, right) => - (wasixRustFeatureOrder.get(left) ?? 2) - - (wasixRustFeatureOrder.get(right) ?? 2) - || left.localeCompare(right), - ); - for (const feature of nonLeafWasixRustFeatures) { - output += `\n### \`${feature}\` feature\n\n`; - output += markdownList(wasixRustFeatureSurface.featureSymbols.get(feature) ?? []); - } - output += `\n### Individual \`extension-*\` features\n\n`; - output += - `Each leaf feature also enables \`extensions\`; the constant below additionally ` + - `requires the feature shown.\n\n`; - output += markdownFeatureList( - Array.from(wasixRustFeatureSurface.featureSymbols.entries()) - .filter(([feature]) => feature.startsWith('extension-')) - .flatMap(([feature, symbols]) => symbols.map(symbol => [feature, symbol])) - .sort(([leftFeature], [rightFeature]) => leftFeature.localeCompare(rightFeature)), - ); - output += `\n## Native C ABI: liboliphaunt\n\n`; - output += `### Types\n\n`; - output += markdownList(nativeC.types); - output += `\n### Constants\n\n`; - output += markdownList(nativeC.constants); - output += `\n### Functions\n\n`; - output += markdownList(nativeC.functions); - output += `\n## Swift: Oliphaunt\n\n`; - output += markdownList(swift); - output += `\n## Swift: OliphauntExtensionSupport\n\n`; - output += - `This version-locked carrier seam is consumed by generated Swift extension ` + - `products. It is not ordinary application API; applications select extensions ` + - `by SQL name through \`Oliphaunt\`. See ` + - `[SDK parity policy](./sdk-parity-policy.md).\n\n`; - output += markdownList( - extractSwiftSurface('src/sdks/swift/Sources/OliphauntExtensionSupport'), - ); - output += `\n## Kotlin: oliphaunt\n\n`; - for (const section of kotlin) { - output += `### ${section.sourceSet}\n\n`; - output += markdownList(section.symbols); - output += `\n`; - } - output += `## Kotlin Android Gradle plugin\n\n`; - output += markdownList(kotlinGradlePlugin); - output += `\n`; - output += `## React Native: @oliphaunt/react-native\n\n`; - output += `### Package exports\n\n`; - output += markdownList(extractPackageExports('src/sdks/react-native/package.json')); - output += `\n`; - output += `### Types\n\n`; - output += markdownList(rn.types); - output += `\n### Values\n\n`; - output += markdownList(rn.values); - output += `\n### Members\n\n`; - output += markdownList(rn.members); - output += `\n## TypeScript: @oliphaunt/ts\n\n`; - output += `### Package exports\n\n`; - output += markdownList(extractPackageExports('src/sdks/js/package.json')); - output += `\n`; - output += `### Types\n\n`; - output += markdownList(ts.types); - output += `\n### Values\n\n`; - output += markdownList(ts.values); - output += `\n### Members\n\n`; - output += markdownList(ts.members); - output += `\n## Native TypeScript tools: @oliphaunt/tools\n\n`; - output += `### Package exports\n\n`; - output += markdownList(extractPackageExports('src/runtimes/liboliphaunt/native/tools-npm/package.json')); - output += `\n### Types\n\n`; - output += markdownList(nativeToolsTs.types); - output += `\n### Values\n\n`; - output += markdownList(nativeToolsTs.values); - output += `\n### Members\n\n`; - output += markdownList(nativeToolsTs.members); - output += `\n## WASIX TypeScript: @oliphaunt/wasix-ts\n\n`; - output += `### Package exports\n\n`; - output += markdownList(extractPackageExports('src/bindings/wasix-ts/package.json')); - output += `\n`; - output += `### Types\n\n`; - output += markdownList(wasixTs.types); - output += `\n### Values\n\n`; - output += markdownList(wasixTs.values); - output += `\n### Members\n\n`; - output += markdownList(wasixTs.members); - output += `\n### Worker subpath: @oliphaunt/wasix-ts/worker\n\n`; - output += `#### Types\n\n`; - output += markdownList(wasixWorkerTs.types); - output += `\n#### Values\n\n`; - output += markdownList(wasixWorkerTs.values); - output += `\n#### Members\n\n`; - output += markdownList(wasixWorkerTs.members); - output += `\n### Storage subpath: @oliphaunt/wasix-ts/storage/indexed-db\n\n`; - output += markdownList([...wasixIndexedDb.types, ...wasixIndexedDb.values]); - output += `\n### Storage subpath: @oliphaunt/wasix-ts/storage/opfs\n\n`; - output += markdownList([...wasixOpfs.types, ...wasixOpfs.values]); - output += `\n### Storage subpath: @oliphaunt/wasix-ts/storage/node\n\n`; - output += markdownList([...wasixNodeDirectory.types, ...wasixNodeDirectory.values]); - output += `\n### Storage subpath: @oliphaunt/wasix-ts/storage/bun\n\n`; - output += markdownList([...wasixBunDirectory.types, ...wasixBunDirectory.values]); - output += `\n### Storage subpath: @oliphaunt/wasix-ts/storage/deno\n\n`; - output += markdownList([...wasixDenoDirectory.types, ...wasixDenoDirectory.values]); - output += `\n### Server subpath: @oliphaunt/wasix-ts/server\n\n`; - output += markdownList([ - ...wasixTsServer.types, - ...wasixTsServer.values, - ...wasixTsServer.members, - ]); - output += `\n## WASIX TypeScript tools: @oliphaunt/wasix-tools\n\n`; - output += `### Package exports\n\n`; - output += markdownList( - extractPackageExports('src/bindings/wasix-ts/tools-package/package.json'), - ); - output += `\n### Types\n\n`; - output += markdownList(wasixToolsTs.types); - output += `\n### Values\n\n`; - output += markdownList(wasixToolsTs.values); - output += `\n### Members\n\n`; - output += markdownList(wasixToolsTs.members); - return output; -} - -const generated = render(); -if (mode === '--write') { - writeFileSync(outputPath, generated); -} else { - const current = existsSync(outputPath) ? readFileSync(outputPath, 'utf8') : ''; - if (current !== generated) { - console.error('docs/maintainers/sdk-api-surface.md is stale; run node tools/policy/generate-sdk-api-surface.mjs --write'); - process.exit(1); - } -} diff --git a/tools/policy/git-checkout-eol.test.mjs b/tools/policy/git-checkout-eol.test.mjs deleted file mode 100644 index acb459a20..000000000 --- a/tools/policy/git-checkout-eol.test.mjs +++ /dev/null @@ -1,63 +0,0 @@ -import { createHash } from "node:crypto"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtempSync, readFileSync, rmSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { describe, expect, test } from "bun:test"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const WASIX_ASSET_MANIFEST = - "src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv"; - -function sha256(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -describe("cross-platform Git checkout bytes", () => { - test("all tracked paths are normalized to LF when Git classifies them as text", () => { - const files = execFileSync("git", ["ls-files", "-z"], { - cwd: ROOT, - encoding: "utf8", - }).split("\0").filter(Boolean); - const fields = execFileSync("git", ["check-attr", "-z", "--stdin", "text", "eol"], { - cwd: ROOT, - encoding: "utf8", - input: `${files.join("\0")}\0`, - }).split("\0").filter(Boolean); - - expect(fields).toHaveLength(files.length * 6); - for (let index = 0; index < fields.length; index += 6) { - expect(fields[index]).toBe(files[index / 6]); - expect(fields[index + 1]).toBe("text"); - expect(["auto", "set"]).toContain(fields[index + 2]); - expect(fields[index + 3]).toBe(files[index / 6]); - expect(fields[index + 4]).toBe("eol"); - expect(fields[index + 5]).toBe("lf"); - } - }); - - test("core.autocrlf=true preserves the pinned WASIX manifest digest", () => { - const manifest = Bun.TOML.parse( - readFileSync(path.join(ROOT, "src/sources/toolchains/wasix.toml"), "utf8"), - ); - const checkout = mkdtempSync(path.join(tmpdir(), "oliphaunt-autocrlf-checkout-")); - try { - const prefix = `${checkout.split(path.sep).join("/")}/`; - execFileSync("git", [ - "-c", - "core.autocrlf=true", - "checkout-index", - "--force", - `--prefix=${prefix}`, - "--", - WASIX_ASSET_MANIFEST, - ], { cwd: ROOT }); - const bytes = readFileSync(path.join(checkout, WASIX_ASSET_MANIFEST)); - expect(bytes.includes(13)).toBe(false); - expect(sha256(bytes)).toBe(manifest.toolchain.assets_manifest_sha256); - } finally { - rmSync(checkout, { force: true, recursive: true }); - } - }); -}); diff --git a/tools/policy/ios-app-transport-security.test.mjs b/tools/policy/ios-app-transport-security.test.mjs deleted file mode 100644 index 76f0558a8..000000000 --- a/tools/policy/ios-app-transport-security.test.mjs +++ /dev/null @@ -1 +0,0 @@ -import "../../src/sdks/react-native/tools/ios-app-transport.test.mjs"; diff --git a/tools/policy/lib/run-command.mjs b/tools/policy/lib/run-command.mjs deleted file mode 100644 index bc156cb8c..000000000 --- a/tools/policy/lib/run-command.mjs +++ /dev/null @@ -1,39 +0,0 @@ -import { spawnSync } from "node:child_process"; -import process from "node:process"; - -import { captureCommandOutput } from "../../dev/capture-command-output.mjs"; - -export function fail(prefix, message) { - console.error(`${prefix}: ${message}`); - process.exit(1); -} - -export function repoRoot(prefix) { - const result = captureCommandOutput("git", ["rev-parse", "--show-toplevel"], { - label: "git rev-parse --show-toplevel", - }); - if (result.error) { - fail(prefix, result.error.message); - } - if (result.status !== 0 || !result.stdout.trim()) { - fail(prefix, "must run inside the Oliphaunt git checkout"); - } - return result.stdout.trim(); -} - -export function chdirRepoRoot(prefix) { - process.chdir(repoRoot(prefix)); -} - -export function run(prefix, command, args, { announce = false } = {}) { - if (announce) { - console.log(`\n==> ${[command, ...args].join(" ")}`); - } - const result = spawnSync(command, args, { stdio: "inherit" }); - if (result.error) { - fail(prefix, result.error.message); - } - if (result.status !== 0) { - process.exit(result.status ?? 1); - } -} diff --git a/tools/policy/list-publishable-cargo-packages.mjs b/tools/policy/list-publishable-cargo-packages.mjs deleted file mode 100644 index 9be77c6f7..000000000 --- a/tools/policy/list-publishable-cargo-packages.mjs +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bun -import { captureCommandOutput } from '../dev/capture-command-output.mjs'; - -const metadataResult = captureCommandOutput( - 'cargo', - ['metadata', '--no-deps', '--format-version', '1'], - { label: 'cargo metadata --no-deps --format-version 1' }, -); -if (metadataResult.error !== undefined || metadataResult.status !== 0) { - throw new Error( - metadataResult.error?.message - ?? (metadataResult.stderr.trim() || 'cargo metadata failed'), - ); -} -const metadata = JSON.parse(metadataResult.stdout); - -const packages = [...metadata.packages].sort((left, right) => - left.name < right.name ? -1 : left.name > right.name ? 1 : 0, -); - -for (const cargoPackage of packages) { - if (Array.isArray(cargoPackage.publish) && cargoPackage.publish.length === 0) { - continue; - } - if (cargoPackage.name === 'oliphaunt-wasix') { - continue; - } - console.log(cargoPackage.name); -} diff --git a/tools/policy/mobile-extension-selection.test.mjs b/tools/policy/mobile-extension-selection.test.mjs deleted file mode 100644 index bc4a23e36..000000000 --- a/tools/policy/mobile-extension-selection.test.mjs +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import test from "node:test"; - -import { extensionSqlNamesForProducts } from "../graph/ci_plan.mjs"; -import { exactExtensionProducts } from "../release/release-artifact-targets.mjs"; -import { ROOT } from "../release/release-graph.mjs"; -import { CORE_SNOWBALL_RUNTIME_DATA_FILES } from "../../src/sdks/react-native/tools/validate-mobile-runtime-files.mjs"; - -const METADATA_FILE = path.join(ROOT, "src/extensions/generated/sdk/extensions.json"); -const REGISTRY_FILE = path.join(ROOT, "src/extensions/generated/mobile/static-registry.json"); -const MOBILE_HELPER_PROCESS_TIMEOUT_MS = 20_000; -const SHELL = String.raw` -set -euo pipefail -root="$1" -metadata_override="$2" -mode="$3" -selection="$4" -platform="$5" -runtime_root="$6" -fail() { - printf '%s\n' "$*" >&2 - return 1 -} -. "$root/src/sdks/react-native/tools/mobile-extension-runtime.sh" -if [ -n "$metadata_override" ]; then - oliphaunt_dev_sdk_extension_json() { - printf '%s\n' "$metadata_override" - } -fi -case "$mode" in - normalize) - oliphaunt_dev_normalize_mobile_extensions "$selection" "$platform" - ;; - inspect) - normalized="$(oliphaunt_dev_normalize_mobile_extensions "$selection" "$platform")" - static_extensions="$(oliphaunt_dev_mobile_static_extensions_for_selection "$normalized")" - stems="$(oliphaunt_dev_mobile_module_stems_for_selection "$normalized")" - registered="$(oliphaunt_dev_mobile_module_extensions_for_selection "$normalized")" - printf '%s\n%s\n%s\n%s\n' "$normalized" "$static_extensions" "$stems" "$registered" - ;; - frameworks) - oliphaunt_dev_prebuilt_extension_asset_paths_for_selection() { - printf '%s|%s|%s\n' "$1" "$2" "$3" - } - oliphaunt_dev_prebuilt_ios_extension_framework_zips_for_selection "$selection" - ;; - unpack-sql-only) - oliphaunt_dev_prebuilt_extension_asset_paths_for_selection() { - fail "SQL-only selection unexpectedly requested a native iOS framework" - } - mkdir -p "$platform/stale.xcframework" - oliphaunt_dev_unpack_ios_extension_frameworks_for_selection "$selection" "$platform" - [ ! -e "$platform" ] || fail "SQL-only selection retained stale native iOS frameworks" - ;; - validate-list) - oliphaunt_dev_assert_runtime_file_list "$selection" "$platform" - ;; - validate-tree) - oliphaunt_dev_assert_runtime_extension_tree "$runtime_root" "$selection" "$platform" - ;; - *) - fail "unknown test mode: $mode" - ;; -esac -`; - -function runHelper( - mode, - selection, - platform, - { input = undefined, metadataFile = "", runtimeRoot = "" } = {}, -) { - return spawnSync( - "bash", - [ - "-c", - SHELL, - "mobile-extension-selection-test", - ROOT, - metadataFile, - mode, - selection, - platform, - runtimeRoot, - ], - { - cwd: ROOT, - encoding: "utf8", - env: { ...process.env, TZ: "UTC" }, - input, - maxBuffer: 16 * 1024 * 1024, - timeout: MOBILE_HELPER_PROCESS_TIMEOUT_MS, - }, - ); -} - -function packagedRuntimeFileList(extensionFiles, dataFiles = []) { - return [ - ...CORE_SNOWBALL_RUNTIME_DATA_FILES.map( - (file) => `assets/oliphaunt/runtime/files/${file}`, - ), - ...extensionFiles.map( - (file) => `assets/oliphaunt/runtime/files/share/postgresql/extension/${file}`, - ), - ...dataFiles.map((file) => `assets/oliphaunt/runtime/files/${file}`), - ].join("\n"); -} - -function writeCoreSnowballRuntimeData(runtimeRoot) { - for (const relativePath of CORE_SNOWBALL_RUNTIME_DATA_FILES) { - const file = path.join(runtimeRoot, ...relativePath.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, "core Snowball runtime data fixture\n"); - } -} - -function inspect(selection, platform) { - const result = runHelper("inspect", selection, platform); - assert.equal(result.status, 0, result.stderr || result.stdout); - const [normalized = "", staticExtensions = "", stems = "", registered = ""] = result.stdout.split("\n"); - return { - normalized: normalized.split(",").filter(Boolean), - staticExtensions: staticExtensions.split(",").filter(Boolean), - stems: stems.split(",").filter(Boolean), - registered: registered.split(",").filter(Boolean), - }; -} - -function exactPlannerSelection() { - return extensionSqlNamesForProducts(exactExtensionProducts("mobile-extension-selection-test")); -} - -test("the exact planner selection keeps SQL-only pgtap out of native static registration", () => { - const metadata = JSON.parse(readFileSync(METADATA_FILE, "utf8")); - const bySqlName = new Map(metadata.extensions.map((row) => [row["sql-name"], row])); - const selected = exactPlannerSelection(); - const expectedStatic = selected.filter((sqlName) => bySqlName.get(sqlName)?.["native-module-stem"] !== null); - const expectedStems = expectedStatic.map((sqlName) => bySqlName.get(sqlName)["native-module-stem"]); - - assert(selected.includes("pgtap"), "the canonical planner fixture must cover SQL-only pgtap"); - assert(selected.includes("postgis"), "the public planner must include PostGIS"); - assert(bySqlName.has("postgis"), "the public React Native SDK metadata must include PostGIS"); - const registry = JSON.parse(readFileSync(REGISTRY_FILE, "utf8")); - assert(registry.modules.some((row) => row["sql-name"] === "postgis")); - assert.equal(bySqlName.get("pgtap")?.["native-module-stem"], null); - - for (const platform of ["Android", "iOS"]) { - const result = inspect(selected.join(","), platform); - assert.deepEqual(result.normalized, selected, `${platform} must retain the exact planner selection`); - assert.deepEqual(result.staticExtensions, expectedStatic, `${platform} must derive only native static rows`); - assert.deepEqual(result.registered, expectedStatic, `${platform} must register only native static rows`); - assert.deepEqual(result.stems, expectedStems, `${platform} must emit exact generated module stems`); - assert(!result.staticExtensions.includes("pgtap")); - assert(!result.registered.includes("pgtap")); - } -}); - -test("a SQL-only pgtap selection requires resources but no native mobile carrier", () => { - for (const platform of ["Android", "iOS"]) { - assert.deepEqual(inspect("pgtap", platform), { - normalized: ["pgtap"], - staticExtensions: [], - stems: [], - registered: [], - }); - } - - const frameworks = runHelper("frameworks", "pgtap,vector", "unused"); - assert.equal(frameworks.status, 0, frameworks.stderr || frameworks.stdout); - assert.equal(frameworks.stdout, "vector|ios-xcframework|ios-xcframework\n"); - - const temp = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-sql-only-frameworks-")); - const destination = path.join(temp, "frameworks"); - try { - const unpack = runHelper("unpack-sql-only", "pgtap", destination); - assert.equal(unpack.status, 0, unpack.stderr || unpack.stdout); - } finally { - rmSync(temp, { force: true, recursive: true }); - } -}); - -test("mobile selection closes extension dependencies before carrier projection", () => { - for (const platform of ["Android", "iOS"]) { - const result = inspect("earthdistance", platform); - assert.deepEqual(result.normalized, ["cube", "earthdistance"]); - assert.deepEqual(result.staticExtensions, ["cube", "earthdistance"]); - assert.deepEqual(result.registered, ["cube", "earthdistance"]); - assert.equal(result.stems.length, 2); - } -}); - -test("mobile selection rejects unknown extension SQL names", () => { - const result = runHelper("normalize", "vector,not_a_real_extension", "Android"); - assert.notEqual(result.status, 0, "unknown extension unexpectedly normalized"); - assert.match(`${result.stderr}\n${result.stdout}`, /unsupported mobile extension for Android Expo smoke: not_a_real_extension/u); -}); - -test("mobile selection rejects unknown platform labels", () => { - const result = runHelper("normalize", "vector", "desktop"); - assert.notEqual(result.status, 0, "unknown platform unexpectedly normalized"); - assert.match(`${result.stderr}\n${result.stdout}`, /unsupported mobile extension platform: desktop/u); -}); - -test("mobile runtime inventory accepts pgtap ancillary SQL without inventing extensions", () => { - const result = runHelper("validate-list", "pgtap", "Android", { - input: packagedRuntimeFileList([ - "pgtap.control", - "pgtap--1.3.4.sql", - "pgtap--1.3.4--1.3.5.sql", - "pgtap.sql", - "pgtap-core--1.3.5.sql", - "pgtap-schema.sql", - "uninstall_pgtap.sql", - "plpgsql.control", - "plpgsql--1.0.sql", - ]), - }); - assert.equal(result.status, 0, result.stderr || result.stdout); -}); - -test("mobile runtime inventory accepts every declared PostGIS ancillary prefix", () => { - const registry = JSON.parse(readFileSync(REGISTRY_FILE, "utf8")); - const postgis = registry.modules.find((row) => row["sql-name"] === "postgis"); - assert(postgis, "missing generated PostGIS mobile registry fixture"); - const result = runHelper("validate-list", "postgis", "iOS", { - input: packagedRuntimeFileList( - [ - "postgis.control", - "postgis--3.6.3.sql", - "postgis_comments.sql", - "postgis_proc_set_search_path--3.6.3.sql", - "rtpostgis.sql", - "uninstall_postgis.sql", - ], - postgis["data-files"], - ), - }); - assert.equal(result.status, 0, result.stderr || result.stdout); -}); - -test("mobile runtime inventory rejects ancillary SQL owned by an unselected extension", () => { - const result = runHelper("validate-list", "", "Android", { - input: packagedRuntimeFileList(["pgtap-core--1.3.5.sql"]), - }); - assert.notEqual(result.status, 0, "unselected pgtap ancillary SQL unexpectedly passed"); - assert.match( - `${result.stderr}\n${result.stdout}`, - /unselected PostgreSQL extension asset: .*pgtap-core--1\.3\.5\.sql/u, - ); -}); - -test("mobile runtime inventory rejects undeclared and ambiguously owned SQL", () => { - const undeclared = runHelper("validate-list", "", "Android", { - input: packagedRuntimeFileList(["foreign--1.0.sql"]), - }); - assert.notEqual(undeclared.status, 0, "undeclared extension SQL unexpectedly passed"); - assert.match(`${undeclared.stderr}\n${undeclared.stdout}`, /undeclared PostgreSQL extension asset/u); - - const temp = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-mobile-ownership-")); - try { - const metadata = JSON.parse(readFileSync(METADATA_FILE, "utf8")); - const vector = metadata.extensions.find((row) => row["sql-name"] === "vector"); - assert(vector, "missing generated vector metadata fixture"); - vector["extension-sql-file-prefixes"] = ["pgtap-core"]; - const fixture = path.join(temp, "react-native.json"); - writeFileSync(fixture, `${JSON.stringify(metadata, null, 2)}\n`); - const ambiguous = runHelper("validate-list", "pgtap", "Android", { - input: packagedRuntimeFileList([ - "pgtap.control", - "pgtap--1.3.5.sql", - "pgtap-core--1.3.5.sql", - ]), - metadataFile: fixture, - }); - assert.notEqual(ambiguous.status, 0, "ambiguously owned extension SQL unexpectedly passed"); - assert.match(`${ambiguous.stderr}\n${ambiguous.stdout}`, /ambiguous ownership/u); - } finally { - rmSync(temp, { force: true, recursive: true }); - } -}); - -test("pgtap ancillary SQL cannot satisfy the canonical install-script contract", () => { - const result = runHelper("validate-list", "pgtap", "Android", { - input: packagedRuntimeFileList([ - "pgtap.control", - "pgtap.sql", - "pgtap-core--1.3.5.sql", - "pgtap-schema.sql", - "uninstall_pgtap.sql", - ]), - }); - assert.notEqual(result.status, 0, "pgtap ancillary SQL unexpectedly counted as an install script"); - assert.match(`${result.stderr}\n${result.stdout}`, /missing selected pgtap canonical install SQL file/u); -}); - -test("directory and packaged-list validation share the same ancillary ownership contract", () => { - const temp = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-mobile-runtime-tree-")); - try { - writeCoreSnowballRuntimeData(temp); - const extensionDirectory = path.join(temp, "share/postgresql/extension"); - mkdirSync(extensionDirectory, { recursive: true }); - for (const file of [ - "pgtap.control", - "pgtap--1.3.4.sql", - "pgtap--1.3.4--1.3.5.sql", - "pgtap-core--1.3.5.sql", - "pgtap-schema.sql", - "uninstall_pgtap.sql", - ]) { - writeFileSync( - path.join(extensionDirectory, file), - file === "pgtap.control" ? "default_version = '1.3.5'\n" : "-- fixture\n", - ); - } - const result = runHelper("validate-tree", "pgtap", "Android", { runtimeRoot: temp }); - assert.equal(result.status, 0, result.stderr || result.stdout); - } finally { - rmSync(temp, { force: true, recursive: true }); - } -}); diff --git a/tools/policy/moon.mjs b/tools/policy/moon.mjs deleted file mode 100644 index 9fc13bfdf..000000000 --- a/tools/policy/moon.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import { moonCommand, moonEnvironment } from '../dev/moon-command.mjs'; -import { captureCommandOutput } from '../dev/capture-command-output.mjs'; - -export function moonBin() { - return moonCommand(); -} - -export function runMoon(args, options = {}) { - const { - encoding: _encoding = 'utf8', - maxBuffer = 32 * 1024 * 1024, - ...captureOptions - } = options; - const result = captureCommandOutput(moonBin(), args, { - env: moonEnvironment(), - label: `${moonBin()} ${args.join(' ')}`, - maxOutputBytes: maxBuffer, - ...captureOptions, - }); - if (result.error !== undefined || result.status !== 0) { - throw new Error( - result.error?.message - ?? (result.stderr.trim() || result.stdout.trim() || `Moon exited ${result.status}`), - ); - } - return result.stdout; -} diff --git a/tools/policy/moon.yml b/tools/policy/moon.yml deleted file mode 100644 index 4ec11b559..000000000 --- a/tools/policy/moon.yml +++ /dev/null @@ -1,113 +0,0 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "policy-tools" -language: "javascript" -layer: "tool" -stack: "infrastructure" -tags: ["tools", "policy", "repo-hygiene"] - -project: - title: "Policy Checks" - description: "Cross-product repository policy, product graph, SDK parity, and package-boundary checks." - owner: "oliphaunt" - -owners: - defaultOwner: "@oliphaunt/core" - paths: - "**/*": ["@oliphaunt/core"] - -tasks: - fmt: - tags: ["format"] - command: "bash tools/policy/format.sh --write" - inputs: - - "@group(cargo-workspace)" - - "@group(js-quality)" - options: - cache: false - runFromWorkspaceRoot: true - js-format-check: - tags: ["format", "quality", "static"] - command: "bash tools/policy/format.sh --check-js" - inputs: - - "@group(js-quality)" - options: - cache: true - runFromWorkspaceRoot: true - js-lint: - tags: ["quality", "static"] - command: "bash tools/policy/format.sh --lint-js" - inputs: - - "@group(js-quality)" - options: - cache: true - runFromWorkspaceRoot: true - rust-format-check: - tags: ["format", "quality", "static", "requires-rust"] - command: "cargo fmt --check" - inputs: - - "@group(cargo-workspace)" - - "/src/**/Cargo.toml" - - "/src/**/*.rs" - options: - cache: true - runFromWorkspaceRoot: true - rust-lint: - tags: ["quality", "static", "requires-rust"] - command: "tools/dev/bun.sh tools/policy/check-rust-lint.mjs" - env: - CARGO_TARGET_DIR: "target/moon/cargo-quality" - inputs: - - "@group(cargo-workspace)" - - "/clippy.toml" - - "/src/**/Cargo.toml" - - "/src/**/*.rs" - - "/tools/**/Cargo.toml" - - "/tools/**/*.rs" - - "/tools/policy/check-rust-lint.mjs" - - "/tools/policy/check-dependency-invariants.sh" - options: - cache: true - runFromWorkspaceRoot: true - tools-compile: - tags: ["policy", "assertion", "quality", "static"] - command: "bash tools/policy/check-policy-tools.sh" - inputs: - - "/.github/scripts/**/*.mjs" - - "/examples/tools/**/*.mjs" - - "/src/runtimes/liboliphaunt/native/tools/build-ci-target.mjs" - - "/tools/graph/**/*" - - "**/*" - - "/tools/dev/capture-command-output.mjs" - - "/tools/dev/moon-command.mjs" - options: - cache: true - runFromWorkspaceRoot: true - unit: - tags: ["quality", "unit"] - command: "tools/dev/bun.sh tools/release/release-check.mjs --mutation-tests-only --mutation-scope=policy" - inputs: - - "/.gitattributes" - - "/.github/scripts/check-ci-gate.mjs" - - "/.github/scripts/check-release-intent.sh" - - "/.github/scripts/resolve-mobile-e2e.mjs" - - "/.github/scripts/resolve-mobile-e2e.test.mjs" - - "/.github/scripts/validate-release-workflow-inputs.sh" - - "/src/extensions/generated/**/*" - - "/src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv" - - "/src/sdks/react-native/tools/**/*" - - "/src/sources/**/*" - - "!/src/sources/tools/**/*.test.*" - - "/tools/dev/bun.sh" - - "/tools/dev/capture-command-output.mjs" - - "/tools/dev/moon-command.mjs" - - "**/*" - - "!/tools/policy/check-policy-tools.sh" - - "!/tools/policy/format.sh" - - "/tools/release/release-check.mjs" - - "/tools/release/release-cli-utils.mjs" - - "/tools/test/isolated-github-test-environment.mjs" - - "/tools/test/fd-backed-spawn-sync.mjs" - options: - cache: false - runFromWorkspaceRoot: true diff --git a/tools/policy/resolve-mobile-e2e.test.mjs b/tools/policy/resolve-mobile-e2e.test.mjs deleted file mode 100644 index 1b12f0fae..000000000 --- a/tools/policy/resolve-mobile-e2e.test.mjs +++ /dev/null @@ -1 +0,0 @@ -import "../../.github/scripts/resolve-mobile-e2e.test.mjs"; diff --git a/tools/policy/run-gradle-lint-checked.sh b/tools/policy/run-gradle-lint-checked.sh deleted file mode 100644 index 373ade369..000000000 --- a/tools/policy/run-gradle-lint-checked.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env sh -set -eu - -usage() { - echo "usage: tools/policy/run-gradle-lint-checked.sh -- [args...]" >&2 - exit 2 -} - -[ "$#" -ge 3 ] || usage -log_file="$1" -shift -[ "$1" = "--" ] || usage -shift -[ "$#" -gt 0 ] || usage - -mkdir -p "$(dirname "$log_file")" - -command_status=0 -if "$@" >"$log_file" 2>&1; then - : -else - command_status="$?" -fi - -# Gradle's Android Lint worker can print analyzer/compiler incompatibilities -# and still return success. Replay the complete combined output for CI and -# preserve a genuine command failure before checking for that false-green case. -cat "$log_file" -if [ "$command_status" -ne 0 ]; then - exit "$command_status" -fi - -forbidden_pattern='Module was compiled with an incompatible version of Kotlin|The binary version of its metadata is .*expected version is' -if grep -E -q "$forbidden_pattern" "$log_file"; then - echo "Gradle Lint emitted fatal analyzer compatibility diagnostics despite exiting successfully:" >&2 - grep -E -n "$forbidden_pattern" "$log_file" >&2 - exit 1 -fi diff --git a/tools/policy/run-gradle-lint-checked.test.mjs b/tools/policy/run-gradle-lint-checked.test.mjs deleted file mode 100644 index 8547c5cf3..000000000 --- a/tools/policy/run-gradle-lint-checked.test.mjs +++ /dev/null @@ -1,63 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { mkdtempSync, readFileSync, rmSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const HELPER = path.join(ROOT, "tools/policy/run-gradle-lint-checked.sh"); -const scratchRoots = []; - -afterEach(() => { - for (const scratchRoot of scratchRoots.splice(0)) { - rmSync(scratchRoot, { recursive: true, force: true }); - } -}); - -function runChecked(command) { - const scratchRoot = mkdtempSync(path.join(tmpdir(), "oliphaunt-gradle-lint-")); - scratchRoots.push(scratchRoot); - const logFile = path.join(scratchRoot, "nested", "lint.log"); - const result = spawnSync( - "sh", - [HELPER, logFile, "--", "sh", "-c", command], - { cwd: ROOT, encoding: "utf8" }, - ); - return { ...result, log: readFileSync(logFile, "utf8") }; -} - -describe("run-gradle-lint-checked", () => { - test("accepts clean successful output and preserves the log", () => { - const result = runChecked("printf 'lint clean\\n'"); - - expect(result.status).toBe(0); - expect(result.stdout).toBe("lint clean\n"); - expect(result.stderr).toBe(""); - expect(result.log).toBe("lint clean\n"); - }); - - test("preserves the underlying command failure", () => { - const result = runChecked("printf 'lint command failed\\n' >&2; exit 23"); - - expect(result.status).toBe(23); - expect(result.stdout).toBe("lint command failed\n"); - expect(result.stderr).toBe(""); - expect(result.log).toBe("lint command failed\n"); - }); - - test("rejects incompatible Kotlin metadata even when the command exits zero", () => { - const diagnostic = - "e: sample.kotlin_module Module was compiled with an incompatible version of Kotlin. " - + "The binary version of its metadata is 2.4.0, expected version is 2.2.0."; - const result = runChecked(`printf '%s\\n' '${diagnostic}'`); - - expect(result.status).toBe(1); - expect(result.stdout).toContain(diagnostic); - expect(result.stderr).toContain( - "Gradle Lint emitted fatal analyzer compatibility diagnostics despite exiting successfully", - ); - expect(result.stderr).toContain(diagnostic); - expect(result.log).toBe(`${diagnostic}\n`); - }); -}); diff --git a/tools/policy/setup-wasmer-llvm-install.test.sh b/tools/policy/setup-wasmer-llvm-install.test.sh deleted file mode 100755 index 522f9b2ea..000000000 --- a/tools/policy/setup-wasmer-llvm-install.test.sh +++ /dev/null @@ -1,303 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -repo_root="$(git -C "$script_dir" rev-parse --show-toplevel)" -installer="$repo_root/.github/actions/setup-wasmer-llvm/install.sh" -curl_platform_flags="$repo_root/tools/dev/curl-platform-flags.sh" - -fail() { - echo "install.test.sh: $*" >&2 - exit 1 -} - -sha256_file() { - if command -v shasum >/dev/null 2>&1; then - shasum -a 256 "$1" | awk '{print $1}' - else - sha256sum "$1" | awk '{print $1}' - fi -} - -work_root="$(mktemp -d)" -cleanup() { - rm -rf "$work_root" -} -trap cleanup EXIT HUP INT TERM - -make_archive() { - local archive="$1" - local version="$2" - local targets="$3" - local tree - tree="$work_root/archive-tree-$(basename "$archive")" - mkdir -p "$tree/bin" - # shellcheck disable=SC2016 # These literals are emitted into the fixture script. - printf '%s\n' \ - '#!/usr/bin/env bash' \ - 'set -euo pipefail' \ - 'if [[ "${OLIPHAUNT_WASMER_LLVM_TEST_REQUIRE_FINAL_ABSENT:-}" == 1 && -e "${OLIPHAUNT_WASMER_LLVM_TEST_FINAL:?}" ]]; then' \ - ' echo "final install existed before staged validation" >&2' \ - ' exit 93' \ - 'fi' \ - 'case "${1:-}" in' \ - " --version) printf '%s\\n' '$version' ;;" \ - " --targets-built) printf '%s\\n' '$targets' ;;" \ - ' *) exit 64 ;;' \ - 'esac' > "$tree/bin/llvm-config" - chmod 755 "$tree/bin/llvm-config" - ln -s llvm-config "$tree/bin/llvm-config-link" - ln -s llvm-config-link "$tree/bin/llvm-config-link-chain" - tar -cJf "$archive" -C "$tree" . -} - -assert_no_partial_install() { - local runner_temp="$1" - local cache_key="$2" - [ ! -e "$runner_temp/wasmer-llvm/$cache_key/llvm" ] || fail "failed installation left a final llvm directory" - local leftover - leftover="$(find "$runner_temp" \( -name '.llvm-stage.*' -o -name 'wasmer-llvm-*.archive.*' \) -print -quit)" - [ -z "$leftover" ] || fail "failed installation left temporary state: $leftover" -} - -assert_archive_rejected() { - local label="$1" - local archive="$2" - local sha runner cache_key - sha="$(sha256_file "$archive")" - runner="$work_root/$label-runner" - cache_key="wasmer-llvm-Linux-X64-22.1-$label" - if run_installer "$runner" "$cache_key" "$archive" "$sha" \ - "$work_root/$label-curl.log" >/dev/null 2>&1; then - fail "$label archive unexpectedly succeeded" - fi - assert_no_partial_install "$runner" "$cache_key" -} - -run_installer() { - local runner_temp="$1" - local cache_key="$2" - local archive="$3" - local expected_sha="$4" - local log="$5" - local expected_bytes="${6:-}" - if [ -z "$expected_bytes" ]; then - expected_bytes="$(wc -c < "$archive" | tr -d '[:space:]')" - fi - mkdir -p "$runner_temp" - : > "$runner_temp/github-env" - : > "$runner_temp/github-path" - OLIPHAUNT_WASMER_LLVM_TEST_ARCHIVE="$archive" \ - OLIPHAUNT_WASMER_LLVM_TEST_LOG="$log" \ - OLIPHAUNT_WASMER_LLVM_TEST_MODE="${OLIPHAUNT_WASMER_LLVM_TEST_MODE:-copy}" \ - LLVM_URL=https://downloads.invalid/llvm.tar.xz \ - LLVM_SHA256="$expected_sha" \ - LLVM_BYTES="$expected_bytes" \ - LLVM_VERSION=22.1 \ - ACTION_PATH="$repo_root/.github/actions/setup-wasmer-llvm" \ - CACHE_KEY="$cache_key" \ - RUNNER_TEMP="$runner_temp" \ - RUNNER_OS=Linux \ - GITHUB_ENV="$runner_temp/github-env" \ - GITHUB_PATH="$runner_temp/github-path" \ - PATH="$script_dir/testdata/setup-wasmer-llvm:$PATH" \ - bash "$installer" -} - -valid_archive="$work_root/valid.tar.xz" -make_archive "$valid_archive" 22.1.0 'X86 LoongArch WebAssembly' -valid_sha="$(sha256_file "$valid_archive")" -valid_bytes="$(wc -c < "$valid_archive" | tr -d '[:space:]')" - -# Wasmer LLVM shares the bootstrap-safe shell policy with downloaders that may -# run before Bun is available. Prove both sides of the platform branch and that -# the installer actually consumes it. -# shellcheck source=tools/dev/curl-platform-flags.sh -. "$curl_platform_flags" -[ "$(RUNNER_OS=Windows oliphaunt_curl_platform_tls_flag)" = '--ssl-revoke-best-effort' ] || - fail "Windows curl policy omitted Schannel revocation-offline handling" -[ -z "$(RUNNER_OS=Linux oliphaunt_curl_platform_tls_flag)" ] || - fail "Linux curl policy unexpectedly emitted a platform TLS flag" -[ -z "$(RUNNER_OS=macOS oliphaunt_curl_platform_tls_flag)" ] || - fail "macOS curl policy unexpectedly emitted a platform TLS flag" -uname() { printf '%s\n' 'MINGW64_NT-10.0'; } -[ "$(RUNNER_OS= oliphaunt_curl_platform_tls_flag)" = '--ssl-revoke-best-effort' ] || - fail "Git Bash uname fallback omitted Schannel revocation-offline handling" -unset -f uname - -transport_runner="$work_root/transport-runner" -transport_key=wasmer-llvm-Linux-X64-22.1-transport -if OLIPHAUNT_WASMER_LLVM_TEST_MODE=transport-fail \ - run_installer "$transport_runner" "$transport_key" "$valid_archive" "$valid_sha" \ - "$work_root/transport-curl.log" >/dev/null 2>&1; then - fail "failed archive transport unexpectedly succeeded" -fi -assert_no_partial_install "$transport_runner" "$transport_key" - -bad_sha_runner="$work_root/bad-sha-runner" -bad_sha_key=wasmer-llvm-Linux-X64-22.1-bad-sha -if run_installer "$bad_sha_runner" "$bad_sha_key" "$valid_archive" \ - 0000000000000000000000000000000000000000000000000000000000000000 \ - "$work_root/bad-sha-curl.log" >/dev/null 2>&1; then - fail "incorrect archive SHA-256 unexpectedly succeeded" -fi -assert_no_partial_install "$bad_sha_runner" "$bad_sha_key" - -bad_size_runner="$work_root/bad-size-runner" -bad_size_key=wasmer-llvm-Linux-X64-22.1-bad-size -if run_installer "$bad_size_runner" "$bad_size_key" "$valid_archive" "$valid_sha" \ - "$work_root/bad-size-curl.log" "$((valid_bytes + 1))" >/dev/null 2>&1; then - fail "incorrect archive byte size unexpectedly succeeded" -fi -assert_no_partial_install "$bad_size_runner" "$bad_size_key" - -unsafe_archive="$work_root/unsafe.tar.xz" -python3 - "$unsafe_archive" <<'PY' -import io -import sys -import tarfile - -with tarfile.open(sys.argv[1], "w:xz") as archive: - info = tarfile.TarInfo("../escaped") - payload = b"unsafe" - info.size = len(payload) - archive.addfile(info, io.BytesIO(payload)) -PY -unsafe_sha="$(sha256_file "$unsafe_archive")" -unsafe_runner="$work_root/unsafe-runner" -unsafe_key=wasmer-llvm-Linux-X64-22.1-unsafe -if run_installer "$unsafe_runner" "$unsafe_key" "$unsafe_archive" "$unsafe_sha" \ - "$work_root/unsafe-curl.log" >/dev/null 2>&1; then - fail "traversal archive unexpectedly succeeded" -fi -assert_no_partial_install "$unsafe_runner" "$unsafe_key" -[ ! -e "$unsafe_runner/wasmer-llvm/$unsafe_key/escaped" ] || fail "traversal archive wrote outside staging" - -unsafe_link_archive="$work_root/unsafe-link.tar.xz" -python3 - "$unsafe_link_archive" <<'PY' -import sys -import tarfile - -with tarfile.open(sys.argv[1], "w:xz") as archive: - info = tarfile.TarInfo("bin/escape") - info.type = tarfile.SYMTYPE - info.linkname = "../../escaped" - archive.addfile(info) -PY -assert_archive_rejected unsafe-link "$unsafe_link_archive" - -duplicate_archive="$work_root/duplicate.tar.xz" -python3 - "$duplicate_archive" <<'PY' -import io -import sys -import tarfile - -with tarfile.open(sys.argv[1], "w:xz") as archive: - for payload in (b"first", b"second"): - info = tarfile.TarInfo("bin/duplicate") - info.size = len(payload) - archive.addfile(info, io.BytesIO(payload)) -PY -assert_archive_rejected duplicate "$duplicate_archive" - -special_archive="$work_root/special.tar.xz" -python3 - "$special_archive" <<'PY' -import sys -import tarfile - -with tarfile.open(sys.argv[1], "w:xz") as archive: - info = tarfile.TarInfo("bin/fifo") - info.type = tarfile.FIFOTYPE - archive.addfile(info) -PY -assert_archive_rejected special "$special_archive" - -oversized_archive="$work_root/oversized.tar.xz" -python3 - "$oversized_archive" <<'PY' -import sys -import tarfile - -with tarfile.open(sys.argv[1], "w:xz") as archive: - info = tarfile.TarInfo("lib/oversized") - info.size = 4 * 1024 * 1024 * 1024 + 1 - # A header-only member is intentionally malformed as well as oversized. The - # validator must reject its declared expansion before extraction can run. - archive.addfile(info) -PY -assert_archive_rejected oversized "$oversized_archive" - -truncated_archive="$work_root/truncated.tar.xz" -head -c 64 "$valid_archive" > "$truncated_archive" -truncated_sha="$(sha256_file "$truncated_archive")" -truncated_runner="$work_root/truncated-runner" -truncated_key=wasmer-llvm-Linux-X64-22.1-truncated -if run_installer "$truncated_runner" "$truncated_key" "$truncated_archive" "$truncated_sha" \ - "$work_root/truncated-curl.log" >/dev/null 2>&1; then - fail "truncated archive unexpectedly succeeded" -fi -assert_no_partial_install "$truncated_runner" "$truncated_key" - -wrong_version_archive="$work_root/wrong-version.tar.xz" -make_archive "$wrong_version_archive" 21.1.0 'X86 LoongArch WebAssembly' -wrong_version_sha="$(sha256_file "$wrong_version_archive")" -wrong_version_runner="$work_root/wrong-version-runner" -wrong_version_key=wasmer-llvm-Linux-X64-22.1-wrong-version -if run_installer "$wrong_version_runner" "$wrong_version_key" "$wrong_version_archive" "$wrong_version_sha" \ - "$work_root/wrong-version-curl.log" >/dev/null 2>&1; then - fail "archive with the wrong LLVM version unexpectedly succeeded" -fi -assert_no_partial_install "$wrong_version_runner" "$wrong_version_key" - -wrong_targets_archive="$work_root/wrong-targets.tar.xz" -make_archive "$wrong_targets_archive" 22.1.0 'X86 WebAssembly' -wrong_targets_sha="$(sha256_file "$wrong_targets_archive")" -wrong_targets_runner="$work_root/wrong-targets-runner" -wrong_targets_key=wasmer-llvm-Linux-X64-22.1-wrong-targets -if run_installer "$wrong_targets_runner" "$wrong_targets_key" "$wrong_targets_archive" "$wrong_targets_sha" \ - "$work_root/wrong-targets-curl.log" >/dev/null 2>&1; then - fail "archive without the required LLVM targets unexpectedly succeeded" -fi -assert_no_partial_install "$wrong_targets_runner" "$wrong_targets_key" - -success_runner="$work_root/success-runner" -success_key=wasmer-llvm-Linux-X64-22.1-success -success_final="$success_runner/wasmer-llvm/$success_key/llvm" -success_log="$work_root/success-curl.log" -OLIPHAUNT_WASMER_LLVM_TEST_REQUIRE_FINAL_ABSENT=1 \ -OLIPHAUNT_WASMER_LLVM_TEST_FINAL="$success_final" \ - run_installer "$success_runner" "$success_key" "$valid_archive" "$valid_sha" "$success_log" -[ -x "$success_final/bin/llvm-config" ] || fail "verified staged install was not atomically promoted" -identity_file="$success_final/.oliphaunt-wasmer-llvm" -[ -f "$identity_file" ] || fail "promoted install omitted its pinned archive identity" -grep -Fx "sha256=$valid_sha" "$identity_file" >/dev/null || fail "cache identity omitted the archive SHA-256" -grep -Fx "bytes=$valid_bytes" "$identity_file" >/dev/null || fail "cache identity omitted the exact archive size" -grep -F "LLVM_PATH=$success_final" "$success_runner/github-env" >/dev/null || fail "LLVM_PATH omitted promoted install" -grep -F "$success_final/bin" "$success_runner/github-path" >/dev/null || fail "GITHUB_PATH omitted promoted bin directory" -for flag in \ - '--location' \ - '--fail' \ - '--retry 4' \ - '--retry-all-errors' \ - '--retry-delay 10' \ - '--retry-max-time 3600' \ - '--connect-timeout 30' \ - '--max-time 1800' \ - "--max-filesize $valid_bytes" \ - '--proto =https' \ - '--proto-redir =https' \ - '--tlsv1.2'; do - grep -F -- "$flag" "$success_log" >/dev/null || fail "curl invocation omitted $flag" -done - -curl_count="$(wc -l < "$success_log" | tr -d ' ')" -run_installer "$success_runner" "$success_key" "$work_root/does-not-exist" "$valid_sha" "$success_log" "$valid_bytes" -[ "$(wc -l < "$success_log" | tr -d ' ')" = "$curl_count" ] || fail "verified cache identity downloaded LLVM again" - -printf '%s\n' 'schema=0' > "$identity_file" -if run_installer "$success_runner" "$success_key" "$work_root/does-not-exist" "$valid_sha" \ - "$success_log" "$valid_bytes" >/dev/null 2>&1; then - fail "cache with a mismatched archive identity unexpectedly succeeded" -fi -assert_no_partial_install "$success_runner" "$success_key" - -echo "Wasmer LLVM atomic installation tests passed" diff --git a/tools/policy/validate-release-workflow-inputs.test.mjs b/tools/policy/validate-release-workflow-inputs.test.mjs deleted file mode 100644 index b8c722744..000000000 --- a/tools/policy/validate-release-workflow-inputs.test.mjs +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { readFileSync } from "node:fs"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import path from "node:path"; -import test from "node:test"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const SCRIPT = path.join(ROOT, ".github/scripts/validate-release-workflow-inputs.sh"); -const SHA = "84d90b9853530ab72e48a1aa6fb616aaed7a0dc6"; -const BASH = process.env.OLIPHAUNT_TEST_BASH - ? path.resolve(ROOT, process.env.OLIPHAUNT_TEST_BASH) - : (process.platform === "darwin" ? "/bin/bash" : "bash"); - -function validate({ - operation = "prepare-release-pr", - releaseCommit = "", - approvalRunId = "", - workflowSha = SHA, - workflowRef = "refs/heads/main", -} = {}) { - const result = spawnSync(BASH, [SCRIPT], { - cwd: ROOT, - encoding: "utf8", - env: { - ...process.env, - GITHUB_REF: workflowRef, - GITHUB_SHA: workflowSha, - RELEASE_OPERATION: operation, - RELEASE_COMMIT: releaseCommit, - RELEASE_APPROVAL_RUN_ID: approvalRunId, - }, - }); - return { - status: result.status, - output: `${result.stdout}${result.stderr}`, - }; -} - -test("accepts every supported root operation with its implicit workflow commit", () => { - for (const operation of ["prepare-release-pr", "publish-dry-run", "publish-bootstrap", "publish"]) { - const approvalRunId = operation === "publish" || operation === "publish-bootstrap" ? "33989155433" : ""; - const result = validate({ operation, approvalRunId }); - assert.equal(result.status, 0, `${operation}: ${result.output}`); - } -}); - -test("accepts a supplied exact release commit assertion without case sensitivity", () => { - for (const releaseCommit of [SHA, SHA.toUpperCase()]) { - const result = validate({ releaseCommit }); - assert.equal(result.status, 0, result.output); - } -}); - -test("rejects malformed and stale release commit assertions before every operation", () => { - for (const [operation, releaseCommit] of [ - ["prepare-release-pr", "84d90b9"], - ["publish-dry-run", "1111111111111111111111111111111111111111"], - ]) { - const result = validate({ operation, releaseCommit }); - assert.notEqual(result.status, 0, `${operation} unexpectedly accepted ${releaseCommit}`); - assert.match(result.output, /release_commit must (?:be a full 40-character commit SHA|equal the exact workflow SHA)/u); - } -}); - -test("publish operations admit a pinned source for subsequent controller and approval verification", () => { - for (const operation of ["publish", "publish-bootstrap"]) { - const result = validate({ operation, releaseCommit: "1".repeat(40), approvalRunId: "123" }); - assert.equal(result.status, 0, result.output); - } -}); - -test("release operations are main-only", () => { - const rootOnTag = validate({ - operation: "publish", - approvalRunId: "33989155433", - workflowRef: `refs/tags/oliphaunt-release-transport/${SHA}`, - }); - assert.notEqual(rootOnTag.status, 0, rootOnTag.output); - assert.match(rootOnTag.output, /release operations must execute from refs\/heads\/main/u); -}); - -test("requires one pinned approval run only for publish operations", () => { - for (const operation of ["publish", "publish-bootstrap"]) { - for (const approvalRunId of ["", "0", "latest", "12.5"]) { - const result = validate({ operation, approvalRunId }); - assert.notEqual(result.status, 0, `${operation} unexpectedly accepted ${approvalRunId}`); - assert.match(result.output, /requires approval_run_id/u); - } - } - for (const operation of ["prepare-release-pr", "publish-dry-run"]) { - const result = validate({ operation, approvalRunId: "33989155433" }); - assert.notEqual(result.status, 0, `${operation} unexpectedly accepted approval_run_id`); - assert.match(result.output, /approval_run_id is not valid/u); - } -}); - -test("rejects unsupported operations and malformed workflow identities", () => { - const unsupported = validate({ operation: "delete-everything" }); - assert.notEqual(unsupported.status, 0, unsupported.output); - assert.match(unsupported.output, /Unsupported release operation/u); - - const malformedSha = validate({ workflowSha: "84d90b9" }); - assert.notEqual(malformedSha.status, 0, malformedSha.output); - assert.match(malformedSha.output, /GITHUB_SHA must be a full 40-character commit SHA/u); -}); - - -test("release workflow CI gates run after the action that installs Bun", () => { - const workflow = Bun.YAML.parse(readFileSync(path.join(ROOT, ".github/workflows/release.yml"), "utf8")); - let gates = 0; - for (const [job, { steps = [] }] of Object.entries(workflow.jobs)) { - const setup = steps.findIndex((step) => step.uses === "./.github/actions/setup-moon"); - for (const [index, step] of steps.entries()) { - if (!step.run?.includes(".github/scripts/require-workflow-success.sh")) continue; - gates++; - assert.ok(setup >= 0 && setup < index, `${job}: ${step.name} requires Bun from setup-moon`); - } - } - assert.ok(gates >= 2, "bootstrap and publish gates must be inspected"); -}); - - -test("both npm publication jobs can generate required provenance", () => { - const workflow = Bun.YAML.parse(readFileSync(path.join(ROOT, ".github/workflows/release.yml"), "utf8")); - for (const job of ["publish", "publish-bootstrap"]) { - assert.equal(workflow.jobs[job].permissions["id-token"], "write", `${job} requires OIDC for npm --provenance even with token authentication`); - } -}); diff --git a/tools/policy/workflow-moon-transfers.test.mjs b/tools/policy/workflow-moon-transfers.test.mjs deleted file mode 100644 index 451e2231a..000000000 --- a/tools/policy/workflow-moon-transfers.test.mjs +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { moonCommand, moonEnvironment } from "../dev/moon-command.mjs"; -import { CI_JOB_TARGETS } from "../graph/ci_plan.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const workflow = Bun.YAML.parse(readFileSync(path.join(ROOT, ".github/workflows/ci.yml"), "utf8")); -const graphResult = captureCommandOutput(moonCommand(), ["task-graph", "--json"], { - cwd: ROOT, - env: moonEnvironment(), - label: "Moon task graph", -}); -assert.equal(graphResult.status, 0, graphResult.stderr); -const tasks = new Map( - Object.values(JSON.parse(graphResult.stdout).data).map((task) => [task.target, task]), -); - -test("cross-workflow artifact gates reference existing producer job names", () => { - const jobNames = Object.values(workflow.jobs).map((job) => job.name); - let gates = 0; - for (const file of ["release.yml", "mobile-e2e.yml"]) { - const consumer = Bun.YAML.parse(readFileSync(path.join(ROOT, ".github/workflows", file), "utf8")); - for (const job of Object.values(consumer.jobs)) { - for (const step of job.steps ?? []) { - const run = String(step.run ?? ""); - if (!/download-build-artifacts[.]mjs|require-workflow-success[.]sh/u.test(run)) continue; - for (const match of run.matchAll(/--job\s+(?:"([^"]+)"|'([^']+)'|([^\s\\]+))/gu)) { - const name = match[1] ?? match[2] ?? match[3]; - gates += 1; - assert.equal( - jobNames.filter((candidate) => candidate === name).length, - 1, - `${file}: ${step.name} requires exactly one CI job named ${name}`, - ); - } - } - } - } - assert.ok(gates > 0, "cross-workflow downloads must retain their producer gates"); -}); - -function dependencies(target) { - const task = tasks.get(target); - assert.ok(task, `workflow root ${target} must exist in Moon`); - return (task.deps ?? []).map((dependency) => - typeof dependency === "string" ? dependency : dependency.target); -} - -test("downloaded Moon dependencies are explicit direct handoffs", () => { - let handoffs = 0; - for (const [workflowJob, job] of Object.entries(workflow.jobs)) { - const steps = job.steps ?? []; - for (const [index, step] of steps.entries()) { - const run = String(step.run ?? ""); - assert.doesNotMatch(run, /OLIPHAUNT_MOON_UPSTREAM=none|run-moon-targets[.]sh --upstream none/u); - - const rawTransfers = step.env?.OLIPHAUNT_MOON_TRANSFERRED_DEPS_JSON; - if (rawTransfers === undefined) continue; - handoffs += 1; - const plannedJob = run.match(/run-planned-moon-job[.]sh ([a-z0-9-]+)/u)?.[1]; - assert.ok(plannedJob, `${workflowJob} transferred handoff must use the planned-job runner`); - const transfers = JSON.parse(rawTransfers); - assert.ok(Array.isArray(transfers) && transfers.length > 0); - - let roots = CI_JOB_TARGETS[plannedJob]; - const inlinePlan = step.env?.OLIPHAUNT_CI_JOB_TARGETS_JSON; - if (typeof inlinePlan === "string" && inlinePlan.startsWith("{")) { - roots = JSON.parse(inlinePlan)[plannedJob]; - } - assert.ok(Array.isArray(roots) && roots.length > 0, `${plannedJob} must resolve Moon roots`); - const direct = new Set(roots.flatMap(dependencies)); - for (const transfer of transfers) { - assert.ok(direct.has(transfer), `${workflowJob} transfers non-direct dependency ${transfer}`); - } - for (const dependency of direct) { - if (!transfers.includes(dependency)) { - assert.notEqual( - tasks.get(dependency)?.options?.internal, - true, - `${workflowJob} cannot directly run internal dependency ${dependency}`, - ); - } - } - - assert.ok( - steps.slice(0, index).some(({ uses }) => String(uses ?? "").startsWith("actions/download-artifact@")), - `${workflowJob} declares transferred dependencies without downloading artifacts`, - ); - const needs = Array.isArray(job.needs) ? job.needs : [job.needs]; - assert.ok(needs.some((need) => need && need !== "affected"), `${workflowJob} has no producer job`); - } - } - assert.ok(handoffs > 0, "CI must exercise at least one cross-runner Moon handoff"); -}); - -test("mobile artifact downloads materialize under the ABI finalizer inputs", () => { - const cases = [ - { - artifact: "liboliphaunt-native-target-android-arm64-v8a", - job: "liboliphaunt-native-android-abi", - path: "target/liboliphaunt-native-ci/android-arm64-v8a", - target: "liboliphaunt-native:finalize-runtime-android-abi", - }, - { - artifact: "liboliphaunt-native-target-android-x86_64", - job: "liboliphaunt-native-android-abi", - path: "target/liboliphaunt-native-ci/android-x86_64", - target: "liboliphaunt-native:finalize-runtime-android-abi", - }, - { - artifact: "liboliphaunt-native-target-ios-xcframework", - job: "liboliphaunt-native-ios-abi", - path: "target/liboliphaunt-native-ci/ios-xcframework", - target: "liboliphaunt-native:finalize-runtime-ios-abi", - }, - { - artifact: "liboliphaunt-native-release-assets-android-x86_64", - job: "liboliphaunt-native-android-abi", - path: "target/liboliphaunt/mobile-release-assets/android-x86_64", - target: "liboliphaunt-native:finalize-runtime-android-abi", - }, - { - artifact: "liboliphaunt-native-release-assets-ios-xcframework", - job: "liboliphaunt-native-ios-abi", - path: "target/liboliphaunt/mobile-release-assets/ios-xcframework", - target: "liboliphaunt-native:finalize-runtime-ios-abi", - }, - ]; - const scratch = mkdtempSync(path.join(tmpdir(), "oliphaunt-handoff-")); - try { - for (const entry of cases) { - const step = workflow.jobs[entry.job].steps.find(({ with: options }) => options?.name === entry.artifact); - assert.equal(step?.with?.path, entry.path); - const inputs = tasks.get(entry.target)?.inputs ?? []; - assert.ok(inputs.some((input) => - Object.values(input).some((value) => String(value).includes(entry.path.replace(/\/[^/]+$/u, "/"))))); - - const uploaded = path.join(scratch, "uploaded"); - const downloaded = path.join(scratch, entry.path); - rmSync(uploaded, { recursive: true, force: true }); - mkdirSync(uploaded, { recursive: true }); - writeFileSync(path.join(uploaded, "abi-receipt.json"), "{}\n"); - mkdirSync(downloaded, { recursive: true }); - cpSync(uploaded, downloaded, { recursive: true }); - assert.ok(existsSync(path.join(downloaded, "abi-receipt.json"))); - } - } finally { - rmSync(scratch, { recursive: true, force: true }); - } -}); diff --git a/tools/release/README.md b/tools/release/README.md index 127e6fcf0..0408608fe 100644 --- a/tools/release/README.md +++ b/tools/release/README.md @@ -1,19 +1,27 @@ # Release tooling -This directory owns cross-product release planning, immutable candidate -validation, registry publication, and release-asset assembly. Product build and -package-shape logic stays with the product that ships it. +This directory owns cross-product release planning, frozen candidate verification, +and registry publication. Builds, package preparation and product tests live +with their owning projects. -Primary entrypoints: +The normal workflow has two operations: prepare the release PR, then publish its +qualified candidate. Publication freezes package bytes, handles missing registry +identities when needed, and resumes from verified receipts. -- `release-check.mjs`: exact candidate metadata and mutation checks; -- `release-publish.mjs`: protected registry publication; -- `release-verify.mjs`: post-publication verification; -- `release-graph.mjs`: released-product and carrier relationships; and -- `sdk-artifacts/`: SDK-specific artifact staging adapters. +Local entrypoints: -Keep tests beside the module they exercise. Do not add generic helpers here -when `tools/dev`, `tools/policy`, or `tools/test` already owns the concern. -Existing underscore-named workflow entrypoints remain stable paths; rename or -split a domain only when doing so creates an independent ownership, import, or -task boundary. +- `bash tools/release/release-check.sh`: release metadata and release/policy tests. +- `bash tools/release/release-check-registries.sh --products-json '["oliphaunt-js"]' --head-ref HEAD`: + read-only registry preflight for the selected products. +- `bash tools/release/verify-product-tags.sh`: exact release-commit tag checks. +- `bash tools/release/package-release-carriers.sh --products-json '["oliphaunt-broker"]'`: + assemble the selected products' registry packages from staged runtime assets. +- `bash tools/release/release-verify.sh`: post-publication verification. +- `tools/release/release-publish.mts`: protected publication controller. +- `bash tools/release/qualified-release-replay.sh HEAD COMMIT_SHA`: verify a clean + source checkout matches the exact candidate before assembly. + +Product and carrier relationships live in `tools/release/`. +Each SDK owns its artifact staging under its own `tools/` directory. Keep tests +beside the implementation they exercise; Shell runs external commands and +TypeScript reads, transforms, and validates data. diff --git a/tools/release/artifact-target-matrix.mts b/tools/release/artifact-target-matrix.mts new file mode 100644 index 000000000..7e9dc33a7 --- /dev/null +++ b/tools/release/artifact-target-matrix.mts @@ -0,0 +1,474 @@ +import { + allArtifactTargets, + compareText, + exactExtensionProducts, + extensionArtifactTargets, + extensionTargetIds, + fail, + liboliphauntAndroidAbi, + liboliphauntNativeBuildRoot, + liboliphauntNativeCiArtifactRoot, +} from './release-artifact-targets.mts'; + +const PREFIX = 'artifact-target-matrix'; + +function stringSet(value, label) { + if (value === undefined) { + return undefined; + } + if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) { + fail(PREFIX, `${label} must be a JSON string list`); + } + return new Set(value); +} + +function filterRuntimeMatrix( + predicate, + { nativeTarget = 'all', selectedTargets = undefined, label }, +) { + let include = liboliphauntNativeRuntimeMatrix().include.filter((item) => predicate(item.target)); + if (nativeTarget !== 'all') { + include = include.filter((item) => item.target === nativeTarget); + } + if (selectedTargets !== undefined) { + include = include.filter((item) => selectedTargets.has(item.target)); + } + if (include.length === 0) { + fail(PREFIX, `no published liboliphaunt-native ${label} targets matched the selected CI plan`); + } + return { include }; +} + +export function liboliphauntNativeRuntimeMatrix() { + const include = allArtifactTargets( + { + product: 'liboliphaunt-native', + kind: 'native-runtime', + }, + PREFIX, + ).map((target) => { + if (!target.runner) { + fail(PREFIX, `${target.id} must declare runner`); + } + return { + target: target.target, + runner: target.runner, + 'build-root': liboliphauntNativeBuildRoot(target.target), + 'ci-artifact-root': liboliphauntNativeCiArtifactRoot(target.target), + }; + }); + if (include.length === 0) { + fail(PREFIX, 'no published liboliphaunt-native native-runtime targets'); + } + return { include }; +} + +export function liboliphauntNativeDesktopRuntimeMatrix( + nativeTarget = 'all', + selectedTargets = undefined, +) { + return filterRuntimeMatrix((target) => /^(linux|macos|windows)-/u.test(target), { + nativeTarget, + selectedTargets, + label: 'desktop', + }); +} + +export function liboliphauntNativeAndroidRuntimeMatrix( + nativeTarget = 'all', + selectedTargets = undefined, +) { + return filterRuntimeMatrix((target) => target.startsWith('android-'), { + nativeTarget, + selectedTargets, + label: 'Android', + }); +} + +export function liboliphauntNativeIosRuntimeMatrix( + nativeTarget = 'all', + selectedTargets = undefined, +) { + return filterRuntimeMatrix((target) => target === 'ios-xcframework', { + nativeTarget, + selectedTargets, + label: 'iOS', + }); +} + +export function liboliphauntNativeRuntimeTargetsForSurface(surface) { + const targets = allArtifactTargets( + { + product: 'liboliphaunt-native', + kind: 'native-runtime', + surface, + }, + PREFIX, + ).map((target) => target.target); + if (targets.length === 0) { + fail(PREFIX, `no published liboliphaunt-native native-runtime targets for surface ${surface}`); + } + return targets.sort(compareText); +} + +export function reactNativeAndroidMobileAppMatrix( + nativeTarget = 'all', + selectedTargets = undefined, +) { + const include = []; + for (const target of allArtifactTargets( + { + product: 'liboliphaunt-native', + kind: 'native-runtime', + surface: 'react-native-android', + }, + PREFIX, + )) { + if (nativeTarget !== 'all' && target.target !== nativeTarget) { + continue; + } + if (selectedTargets !== undefined && !selectedTargets.has(target.target)) { + continue; + } + include.push({ + target: target.target, + abi: liboliphauntAndroidAbi(target.target), + 'build-root': liboliphauntNativeBuildRoot(target.target), + }); + } + if (include.length === 0) { + const validTargets = + liboliphauntNativeRuntimeTargetsForSurface('react-native-android').join(', '); + fail( + PREFIX, + `no React Native Android app targets matched; expected one of: all, ${validTargets}`, + ); + } + include.sort((left, right) => compareText(left.target, right.target)); + return { include }; +} + +export function extensionArtifactsNativeMatrix( + nativeTarget = 'all', + selectedTargets = undefined, + selectedProducts = undefined, +) { + const runtimeTargets = new Map( + allArtifactTargets( + { + product: 'liboliphaunt-native', + kind: 'native-runtime', + }, + PREFIX, + ) + .filter((target) => target.extensionArtifacts) + .map((target) => [target.target, target]), + ); + const byTarget = new Map(); + for (const extensionTarget of extensionArtifactTargets({ family: 'native' }, PREFIX)) { + if (selectedProducts !== undefined && !selectedProducts.has(extensionTarget.product)) { + continue; + } + if (nativeTarget !== 'all' && extensionTarget.target !== nativeTarget) { + continue; + } + if (selectedTargets !== undefined && !selectedTargets.has(extensionTarget.target)) { + continue; + } + const runtimeTarget = runtimeTargets.get(extensionTarget.target); + if (!runtimeTarget) { + fail( + PREFIX, + `${extensionTarget.product} declares native extension target ${extensionTarget.target}, but liboliphaunt-native does not publish it`, + ); + } + if (!runtimeTarget.runner) { + fail(PREFIX, `${runtimeTarget.id} must declare runner`); + } + const group = byTarget.get(extensionTarget.target) ?? { + target: extensionTarget.target, + runner: runtimeTarget.runner, + buildRoot: liboliphauntNativeBuildRoot(extensionTarget.target), + ciArtifactRoot: liboliphauntNativeCiArtifactRoot(extensionTarget.target), + extensions: new Set(), + sqlNames: new Set(), + }; + group.extensions.add(extensionTarget.product); + group.sqlNames.add(extensionTarget.sqlName); + byTarget.set(extensionTarget.target, group); + } + const include = [...byTarget.values()].map((group) => { + const extensions = [...group.extensions].sort(compareText); + const sqlNames = [...group.sqlNames].sort(compareText); + return { + extensions_csv: extensions.join(','), + sql_names_csv: sqlNames.join(','), + extension_count: String(sqlNames.length), + target: group.target, + runner: group.runner, + 'build-root': group.buildRoot, + 'ci-artifact-root': group.ciArtifactRoot, + }; + }); + if (include.length === 0) { + const validTargets = extensionTargetIds({ family: 'native' }, PREFIX).join(', '); + fail( + PREFIX, + `unknown native extension artifact target ${nativeTarget}; expected one of: all, ${validTargets}`, + ); + } + include.sort((left, right) => compareText(left.target, right.target)); + return { include }; +} + +export function extensionArtifactsWasixMatrix(wasmTarget = 'all', selectedProducts = undefined) { + const byTarget = new Map(); + const extensionTargets = extensionArtifactTargets({ family: 'wasix' }, PREFIX); + for (const target of allArtifactTargets( + { + product: 'liboliphaunt-wasix', + }, + PREFIX, + )) { + if (target.kind !== 'wasix-runtime') { + continue; + } + const extensionTargetId = target.target === 'portable' ? 'wasix-portable' : target.target; + if (wasmTarget !== 'all' && target.target !== wasmTarget) { + continue; + } + for (const declared of extensionTargets) { + if (selectedProducts !== undefined && !selectedProducts.has(declared.product)) { + continue; + } + if (declared.target !== extensionTargetId) { + continue; + } + const group = byTarget.get(declared.target) ?? { + target: declared.target, + runner: target.runner ?? 'ubuntu-24.04', + runtimeKind: target.kind, + triple: target.triple ?? '', + extensions: new Set(), + sqlNames: new Set(), + }; + group.extensions.add(declared.product); + group.sqlNames.add(declared.sqlName); + byTarget.set(declared.target, group); + } + } + const include = [...byTarget.values()].map((group) => { + const extensions = [...group.extensions].sort(compareText); + const sqlNames = [...group.sqlNames].sort(compareText); + return { + extensions_csv: extensions.join(','), + sql_names_csv: sqlNames.join(','), + extension_count: String(sqlNames.length), + target: group.target, + runner: group.runner, + 'runtime-kind': group.runtimeKind, + triple: group.triple, + }; + }); + if (include.length === 0) { + const validTargets = allArtifactTargets( + { + product: 'liboliphaunt-wasix', + }, + PREFIX, + ) + .filter((target) => target.kind === 'wasix-runtime') + .map((target) => target.target) + .join(', '); + fail( + PREFIX, + `unknown WASIX extension artifact target ${wasmTarget}; expected one of: all, ${validTargets}`, + ); + } + include.sort((left, right) => compareText(left.target, right.target)); + return { include }; +} + +function wasixHostTargetMatrixRow(target) { + if (!target.runner) { + fail(PREFIX, `${target.id} must declare runner`); + } + if (!target.triple) { + fail(PREFIX, `${target.id} must declare triple`); + } + if (!target.llvmUrl) { + fail(PREFIX, `${target.id} must declare llvm_url`); + } + if (!target.llvmSha256 || !/^[0-9a-f]{64}$/u.test(target.llvmSha256)) { + fail(PREFIX, `${target.id} must declare a lowercase 64-hex llvm_sha256`); + } + if ( + !Number.isSafeInteger(target.llvmBytes) || + target.llvmBytes < 1 || + target.llvmBytes > 2 * 1024 * 1024 * 1024 + ) { + fail(PREFIX, `${target.id} must declare exact llvm_bytes between 1 and 2 GiB`); + } + return { + os: target.runner, + target: target.triple, + target_id: target.target, + llvm_url: target.llvmUrl, + llvm_sha256: target.llvmSha256, + llvm_bytes: target.llvmBytes, + }; +} + +function releaseAssetPath(target, root) { + const asset = target.asset; + if ( + asset.includes('/') || + asset.includes('\\') || + (asset.match(/\{version\}/gu) ?? []).length !== 1 || + /[*?[\]]/u.test(asset) + ) { + fail(PREFIX, `${target.id} must declare one flat, versioned release asset name`); + } + return `${root}/${asset.replace('{version}', '*')}`; +} + +export function liboliphauntWasixAotRuntimeMatrix(wasmTarget = 'all') { + const include = []; + for (const target of allArtifactTargets( + { + product: 'liboliphaunt-wasix', + kind: 'wasix-aot-runtime', + }, + PREFIX, + )) { + if (wasmTarget !== 'all' && !new Set([target.target, target.triple]).has(wasmTarget)) { + continue; + } + include.push({ + ...wasixHostTargetMatrixRow(target), + package: `liboliphaunt-wasix-aot-${target.triple}`, + artifact: `liboliphaunt-wasix-runtime-aot-${target.target}`, + }); + } + if (include.length === 0) { + const validTargets = allArtifactTargets( + { + product: 'liboliphaunt-wasix', + kind: 'wasix-aot-runtime', + }, + PREFIX, + ) + .map((target) => target.target) + .join(', '); + fail( + PREFIX, + `unknown WASIX AOT runtime target ${wasmTarget}; expected one of: all, ${validTargets}`, + ); + } + include.sort((left, right) => compareText(left.target_id, right.target_id)); + return { include }; +} + +export function liboliphauntWasixPostmasterRuntimeMatrix() { + const include = allArtifactTargets( + { + product: 'liboliphaunt-wasix-postmaster', + kind: 'wasix-postmaster-runtime', + }, + PREFIX, + ).map((target) => ({ + ...wasixHostTargetMatrixRow(target), + artifact: `liboliphaunt-wasix-postmaster-release-assets-${target.target}`, + release_asset_path: releaseAssetPath( + target, + 'target/oliphaunt-wasix-postmaster/release-assets', + ), + })); + if (include.length === 0) { + fail(PREFIX, 'WASIX postmaster CI matrix must contain at least one artifact target'); + } + include.sort((left, right) => compareText(left.target_id, right.target_id)); + return { include }; +} + +export function brokerRuntimeMatrix(nativeTarget = 'all') { + const matrix = { + include: allArtifactTargets( + { + product: 'oliphaunt-broker', + kind: 'broker-helper', + }, + PREFIX, + ).map((target) => { + if (!target.runner) { + fail(PREFIX, `${target.id} must declare runner`); + } + return { + target: target.target, + runner: target.runner, + }; + }), + }; + return filterDesktopRuntimeMatrix(matrix, nativeTarget, 'broker'); +} + +export function nodeDirectRuntimeMatrix(nativeTarget = 'all') { + const matrix = { + include: allArtifactTargets( + { + product: 'oliphaunt-node-direct', + kind: 'node-direct-addon', + }, + PREFIX, + ).map((target) => { + if (!target.runner) { + fail(PREFIX, `${target.id} must declare runner`); + } + return { + target: target.target, + runner: target.runner, + }; + }), + }; + return filterDesktopRuntimeMatrix(matrix, nativeTarget, 'Node direct'); +} + +export function wasixNapiRuntimeMatrix(nativeTarget = 'all') { + const matrix = { + include: allArtifactTargets( + { + product: 'oliphaunt-wasix-napi', + kind: 'wasix-napi-addon', + }, + PREFIX, + ).map((target) => { + if (!target.runner) { + fail(PREFIX, `${target.id} must declare runner`); + } + if (!target.triple) { + fail(PREFIX, `${target.id} must declare triple`); + } + return { + target: target.target, + runner: target.runner, + target_triple: target.triple, + }; + }), + }; + return filterDesktopRuntimeMatrix(matrix, nativeTarget, 'WASIX Node-API'); +} + +function filterDesktopRuntimeMatrix(matrix, nativeTarget, label) { + if (matrix.include.length === 0) { + fail(PREFIX, `no published ${label} targets`); + } + if (nativeTarget === 'all') { + return matrix; + } + const include = matrix.include.filter((target) => target.target === nativeTarget); + if (include.length === 0) { + const validTargets = matrix.include.map((target) => target.target).join(', '); + fail(PREFIX, `unknown ${label} target ${nativeTarget}; expected one of: all, ${validTargets}`); + } + return { include }; +} diff --git a/tools/release/artifact_target_matrix.mjs b/tools/release/artifact_target_matrix.mjs deleted file mode 100644 index b5d2e5af8..000000000 --- a/tools/release/artifact_target_matrix.mjs +++ /dev/null @@ -1,627 +0,0 @@ -#!/usr/bin/env bun -import { appendFileSync } from "node:fs"; - -import { - allArtifactTargets, - compareText, - exactExtensionProducts, - extensionArtifactTargets, - fail, - liboliphauntAndroidAbi, - liboliphauntNativeBuildRoot, - liboliphauntNativeCiArtifactRoot, - extensionTargetIds, -} from "./release-artifact-targets.mjs"; - -const PREFIX = "artifact_target_matrix.mjs"; - -function sortedValue(value) { - if (Array.isArray(value)) { - return value.map(sortedValue); - } - if (value !== null && typeof value === "object") { - return Object.fromEntries( - Object.keys(value) - .sort(compareText) - .map((key) => [key, sortedValue(value[key])]), - ); - } - return value; -} - -function printJson(value, { compact = false } = {}) { - console.log(JSON.stringify(sortedValue(value), null, compact ? 0 : 2)); -} - -function parseJsonFlag(argv, name) { - const raw = stringFlag(argv, name); - if (raw === undefined || raw === "") { - return undefined; - } - try { - return JSON.parse(raw); - } catch (error) { - fail(PREFIX, `--${name} must be valid JSON: ${error.message}`); - } -} - -function stringFlag(argv, name) { - const flag = `--${name}`; - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - if (value === flag) { - if (index + 1 >= argv.length) { - fail(PREFIX, `${flag} requires a value`); - } - return argv[index + 1]; - } - if (value.startsWith(`${flag}=`)) { - return value.slice(flag.length + 1); - } - } - return undefined; -} - -function parseOptions(argv) { - const options = { - githubOutput: false, - nativeTarget: stringFlag(argv, "native-target") ?? "all", - wasmTarget: stringFlag(argv, "wasm-target") ?? "all", - selectedTargets: stringSet(parseJsonFlag(argv, "selected-targets-json"), "--selected-targets-json"), - selectedProducts: stringSet(parseJsonFlag(argv, "selected-products-json"), "--selected-products-json"), - }; - const knownFlags = new Set([ - "--github-output", - "--native-target", - "--wasm-target", - "--selected-targets-json", - "--selected-products-json", - ]); - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - const name = value.includes("=") ? value.slice(0, value.indexOf("=")) : value; - if (name === "--github-output") { - options.githubOutput = true; - continue; - } - if (knownFlags.has(name)) { - if (!value.includes("=")) { - index += 1; - } - continue; - } - fail(PREFIX, `unknown argument ${value}`); - } - return options; -} - -function stringSet(value, label) { - if (value === undefined) { - return undefined; - } - if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) { - fail(PREFIX, `${label} must be a JSON string list`); - } - return new Set(value); -} - -function filterRuntimeMatrix(predicate, { nativeTarget = "all", selectedTargets = undefined, label }) { - let include = liboliphauntNativeRuntimeMatrix().include.filter((item) => predicate(item.target)); - if (nativeTarget !== "all") { - include = include.filter((item) => item.target === nativeTarget); - } - if (selectedTargets !== undefined) { - include = include.filter((item) => selectedTargets.has(item.target)); - } - if (include.length === 0) { - fail(PREFIX, `no published liboliphaunt-native ${label} targets matched the selected CI plan`); - } - return { include }; -} - -export function liboliphauntNativeRuntimeMatrix() { - const include = allArtifactTargets( - { - product: "liboliphaunt-native", - kind: "native-runtime", - }, - PREFIX, - ).map((target) => { - if (!target.runner) { - fail(PREFIX, `${target.id} must declare runner`); - } - return { - target: target.target, - runner: target.runner, - "build-root": liboliphauntNativeBuildRoot(target.target), - "ci-artifact-root": liboliphauntNativeCiArtifactRoot(target.target), - }; - }); - if (include.length === 0) { - fail(PREFIX, "no published liboliphaunt-native native-runtime targets"); - } - return { include }; -} - -export function liboliphauntNativeDesktopRuntimeMatrix(nativeTarget = "all", selectedTargets = undefined) { - return filterRuntimeMatrix((target) => /^(linux|macos|windows)-/u.test(target), { - nativeTarget, - selectedTargets, - label: "desktop", - }); -} - -export function liboliphauntNativeAndroidRuntimeMatrix(nativeTarget = "all", selectedTargets = undefined) { - return filterRuntimeMatrix((target) => target.startsWith("android-"), { - nativeTarget, - selectedTargets, - label: "Android", - }); -} - -export function liboliphauntNativeIosRuntimeMatrix(nativeTarget = "all", selectedTargets = undefined) { - return filterRuntimeMatrix((target) => target === "ios-xcframework", { - nativeTarget, - selectedTargets, - label: "iOS", - }); -} - -export function liboliphauntNativeRuntimeTargetsForSurface(surface) { - const targets = allArtifactTargets( - { - product: "liboliphaunt-native", - kind: "native-runtime", - surface, - }, - PREFIX, - ).map((target) => target.target); - if (targets.length === 0) { - fail(PREFIX, `no published liboliphaunt-native native-runtime targets for surface ${surface}`); - } - return targets.sort(compareText); -} - -export function reactNativeAndroidMobileAppMatrix(nativeTarget = "all", selectedTargets = undefined) { - const include = []; - for (const target of allArtifactTargets( - { - product: "liboliphaunt-native", - kind: "native-runtime", - surface: "react-native-android", - }, - PREFIX, - )) { - if (nativeTarget !== "all" && target.target !== nativeTarget) { - continue; - } - if (selectedTargets !== undefined && !selectedTargets.has(target.target)) { - continue; - } - include.push({ - target: target.target, - abi: liboliphauntAndroidAbi(target.target), - "build-root": liboliphauntNativeBuildRoot(target.target), - }); - } - if (include.length === 0) { - const validTargets = liboliphauntNativeRuntimeTargetsForSurface("react-native-android").join(", "); - fail(PREFIX, `no React Native Android app targets matched; expected one of: all, ${validTargets}`); - } - include.sort((left, right) => compareText(left.target, right.target)); - return { include }; -} - -export function extensionArtifactsNativeMatrix( - nativeTarget = "all", - selectedTargets = undefined, - selectedProducts = undefined, -) { - const runtimeTargets = new Map( - allArtifactTargets( - { - product: "liboliphaunt-native", - kind: "native-runtime", - }, - PREFIX, - ) - .filter((target) => target.extensionArtifacts) - .map((target) => [target.target, target]), - ); - const byTarget = new Map(); - for (const extensionTarget of extensionArtifactTargets({ family: "native" }, PREFIX)) { - if (selectedProducts !== undefined && !selectedProducts.has(extensionTarget.product)) { - continue; - } - if (nativeTarget !== "all" && extensionTarget.target !== nativeTarget) { - continue; - } - if (selectedTargets !== undefined && !selectedTargets.has(extensionTarget.target)) { - continue; - } - const runtimeTarget = runtimeTargets.get(extensionTarget.target); - if (!runtimeTarget) { - fail( - PREFIX, - `${extensionTarget.product} declares native extension target ${extensionTarget.target}, but liboliphaunt-native does not publish it`, - ); - } - if (!runtimeTarget.runner) { - fail(PREFIX, `${runtimeTarget.id} must declare runner`); - } - const group = - byTarget.get(extensionTarget.target) ?? - { - target: extensionTarget.target, - runner: runtimeTarget.runner, - buildRoot: liboliphauntNativeBuildRoot(extensionTarget.target), - ciArtifactRoot: liboliphauntNativeCiArtifactRoot(extensionTarget.target), - extensions: new Set(), - sqlNames: new Set(), - }; - group.extensions.add(extensionTarget.product); - group.sqlNames.add(extensionTarget.sqlName); - byTarget.set(extensionTarget.target, group); - } - const include = [...byTarget.values()].map((group) => { - const extensions = [...group.extensions].sort(compareText); - const sqlNames = [...group.sqlNames].sort(compareText); - return { - extensions_csv: extensions.join(","), - sql_names_csv: sqlNames.join(","), - extension_count: String(sqlNames.length), - target: group.target, - runner: group.runner, - "build-root": group.buildRoot, - "ci-artifact-root": group.ciArtifactRoot, - }; - }); - if (include.length === 0) { - const validTargets = extensionTargetIds({ family: "native" }, PREFIX).join(", "); - fail(PREFIX, `unknown native extension artifact target ${nativeTarget}; expected one of: all, ${validTargets}`); - } - include.sort((left, right) => compareText(left.target, right.target)); - return { include }; -} - -export function extensionArtifactsWasixMatrix(wasmTarget = "all", selectedProducts = undefined) { - const byTarget = new Map(); - const extensionTargets = extensionArtifactTargets({ family: "wasix" }, PREFIX); - for (const target of allArtifactTargets( - { - product: "liboliphaunt-wasix", - }, - PREFIX, - )) { - if (target.kind !== "wasix-runtime") { - continue; - } - const extensionTargetId = target.target === "portable" ? "wasix-portable" : target.target; - if (wasmTarget !== "all" && target.target !== wasmTarget) { - continue; - } - for (const declared of extensionTargets) { - if (selectedProducts !== undefined && !selectedProducts.has(declared.product)) { - continue; - } - if (declared.target !== extensionTargetId) { - continue; - } - const group = - byTarget.get(declared.target) ?? - { - target: declared.target, - runner: target.runner ?? "ubuntu-24.04", - runtimeKind: target.kind, - triple: target.triple ?? "", - extensions: new Set(), - sqlNames: new Set(), - }; - group.extensions.add(declared.product); - group.sqlNames.add(declared.sqlName); - byTarget.set(declared.target, group); - } - } - const include = [...byTarget.values()].map((group) => { - const extensions = [...group.extensions].sort(compareText); - const sqlNames = [...group.sqlNames].sort(compareText); - return { - extensions_csv: extensions.join(","), - sql_names_csv: sqlNames.join(","), - extension_count: String(sqlNames.length), - target: group.target, - runner: group.runner, - "runtime-kind": group.runtimeKind, - triple: group.triple, - }; - }); - if (include.length === 0) { - const validTargets = allArtifactTargets( - { - product: "liboliphaunt-wasix", - }, - PREFIX, - ) - .filter((target) => target.kind === "wasix-runtime") - .map((target) => target.target) - .join(", "); - fail(PREFIX, `unknown WASIX extension artifact target ${wasmTarget}; expected one of: all, ${validTargets}`); - } - include.sort((left, right) => compareText(left.target, right.target)); - return { include }; -} - -function wasixHostTargetMatrixRow(target) { - if (!target.runner) { - fail(PREFIX, `${target.id} must declare runner`); - } - if (!target.triple) { - fail(PREFIX, `${target.id} must declare triple`); - } - if (!target.llvmUrl) { - fail(PREFIX, `${target.id} must declare llvm_url`); - } - if (!target.llvmSha256 || !/^[0-9a-f]{64}$/u.test(target.llvmSha256)) { - fail(PREFIX, `${target.id} must declare a lowercase 64-hex llvm_sha256`); - } - if (!Number.isSafeInteger(target.llvmBytes) || target.llvmBytes < 1 || target.llvmBytes > 2 * 1024 * 1024 * 1024) { - fail(PREFIX, `${target.id} must declare exact llvm_bytes between 1 and 2 GiB`); - } - return { - os: target.runner, - target: target.triple, - target_id: target.target, - llvm_url: target.llvmUrl, - llvm_sha256: target.llvmSha256, - llvm_bytes: target.llvmBytes, - }; -} - -function releaseAssetPath(target, root) { - const asset = target.asset; - if ( - asset.includes("/") - || asset.includes("\\") - || (asset.match(/\{version\}/gu) ?? []).length !== 1 - || /[*?[\]]/u.test(asset) - ) { - fail(PREFIX, `${target.id} must declare one flat, versioned release asset name`); - } - return `${root}/${asset.replace("{version}", "*")}`; -} - -export function liboliphauntWasixAotRuntimeMatrix(wasmTarget = "all") { - const include = []; - for (const target of allArtifactTargets( - { - product: "liboliphaunt-wasix", - kind: "wasix-aot-runtime", - }, - PREFIX, - )) { - if (wasmTarget !== "all" && !new Set([target.target, target.triple]).has(wasmTarget)) { - continue; - } - include.push({ - ...wasixHostTargetMatrixRow(target), - package: `liboliphaunt-wasix-aot-${target.triple}`, - artifact: `liboliphaunt-wasix-runtime-aot-${target.target}`, - }); - } - if (include.length === 0) { - const validTargets = allArtifactTargets( - { - product: "liboliphaunt-wasix", - kind: "wasix-aot-runtime", - }, - PREFIX, - ) - .map((target) => target.target) - .join(", "); - fail(PREFIX, `unknown WASIX AOT runtime target ${wasmTarget}; expected one of: all, ${validTargets}`); - } - include.sort((left, right) => compareText(left.target_id, right.target_id)); - return { include }; -} - -export function liboliphauntWasixPostmasterRuntimeMatrix() { - const include = allArtifactTargets( - { - product: "liboliphaunt-wasix-postmaster", - kind: "wasix-postmaster-runtime", - }, - PREFIX, - ).map((target) => ({ - ...wasixHostTargetMatrixRow(target), - artifact: `liboliphaunt-wasix-postmaster-release-assets-${target.target}`, - release_asset_path: releaseAssetPath( - target, - "target/oliphaunt-wasix-postmaster/release-assets", - ), - })); - if (include.length === 0) { - fail(PREFIX, "WASIX postmaster CI matrix must contain at least one artifact target"); - } - include.sort((left, right) => compareText(left.target_id, right.target_id)); - return { include }; -} - -export function brokerRuntimeMatrix(nativeTarget = "all") { - const matrix = { - include: allArtifactTargets( - { - product: "oliphaunt-broker", - kind: "broker-helper", - }, - PREFIX, - ).map((target) => { - if (!target.runner) { - fail(PREFIX, `${target.id} must declare runner`); - } - return { - target: target.target, - runner: target.runner, - }; - }), - }; - return filterDesktopRuntimeMatrix(matrix, nativeTarget, "broker"); -} - -export function nodeDirectRuntimeMatrix(nativeTarget = "all") { - const matrix = { - include: allArtifactTargets( - { - product: "oliphaunt-node-direct", - kind: "node-direct-addon", - }, - PREFIX, - ).map((target) => { - if (!target.runner) { - fail(PREFIX, `${target.id} must declare runner`); - } - return { - target: target.target, - runner: target.runner, - }; - }), - }; - return filterDesktopRuntimeMatrix(matrix, nativeTarget, "Node direct"); -} - -export function wasixNapiRuntimeMatrix(nativeTarget = "all") { - const matrix = { - include: allArtifactTargets( - { - product: "oliphaunt-wasix-napi", - kind: "wasix-napi-addon", - }, - PREFIX, - ).map((target) => { - if (!target.runner) { - fail(PREFIX, `${target.id} must declare runner`); - } - if (!target.triple) { - fail(PREFIX, `${target.id} must declare triple`); - } - return { - target: target.target, - runner: target.runner, - target_triple: target.triple, - }; - }), - }; - return filterDesktopRuntimeMatrix(matrix, nativeTarget, "WASIX Node-API"); -} - -function filterDesktopRuntimeMatrix(matrix, nativeTarget, label) { - if (matrix.include.length === 0) { - fail(PREFIX, `no published ${label} targets`); - } - if (nativeTarget === "all") { - return matrix; - } - const include = matrix.include.filter((target) => target.target === nativeTarget); - if (include.length === 0) { - const validTargets = matrix.include.map((target) => target.target).join(", "); - fail(PREFIX, `unknown ${label} target ${nativeTarget}; expected one of: all, ${validTargets}`); - } - return { include }; -} - -function matrixByName(name, options) { - switch (name) { - case "liboliphaunt-native-runtime": - return liboliphauntNativeRuntimeMatrix(); - case "liboliphaunt-native-desktop-runtime": - return liboliphauntNativeDesktopRuntimeMatrix(options.nativeTarget, options.selectedTargets); - case "liboliphaunt-native-android-runtime": - return liboliphauntNativeAndroidRuntimeMatrix(options.nativeTarget, options.selectedTargets); - case "liboliphaunt-native-ios-runtime": - return liboliphauntNativeIosRuntimeMatrix(options.nativeTarget, options.selectedTargets); - case "react-native-android-mobile-app": - return reactNativeAndroidMobileAppMatrix(options.nativeTarget, options.selectedTargets); - case "extension-artifacts-native": - return extensionArtifactsNativeMatrix(options.nativeTarget, options.selectedTargets, options.selectedProducts); - case "extension-artifacts-wasix": - return extensionArtifactsWasixMatrix(options.wasmTarget, options.selectedProducts); - case "liboliphaunt-wasix-aot-runtime": - return liboliphauntWasixAotRuntimeMatrix(options.wasmTarget); - case "liboliphaunt-wasix-postmaster-runtime": - return liboliphauntWasixPostmasterRuntimeMatrix(); - case "broker-runtime": - return brokerRuntimeMatrix(options.nativeTarget); - case "node-direct-runtime": - return nodeDirectRuntimeMatrix(options.nativeTarget); - case "wasix-napi-runtime": - return wasixNapiRuntimeMatrix(options.nativeTarget); - default: - fail(PREFIX, `unknown matrix ${name}`); - } -} - -function emitGithubOutput(name, value) { - const rendered = JSON.stringify(sortedValue(value)); - const outputPath = process.env.GITHUB_OUTPUT; - if (outputPath) { - appendFileSync(outputPath, `${name}=${rendered}\n`, "utf8"); - } - console.log(`${name}=${rendered}`); -} - -function usage() { - return `usage: tools/release/artifact_target_matrix.mjs [options] - -Matrices: - liboliphaunt-native-runtime - liboliphaunt-native-desktop-runtime - liboliphaunt-native-android-runtime - liboliphaunt-native-ios-runtime - react-native-android-mobile-app - extension-artifacts-native - extension-artifacts-wasix - liboliphaunt-wasix-aot-runtime - liboliphaunt-wasix-postmaster-runtime - broker-runtime - node-direct-runtime - wasix-napi-runtime - -Options: - --github-output - --native-target TARGET - --wasm-target TARGET - --selected-targets-json JSON - --selected-products-json JSON - --surface SURFACE -`; -} - -function main(argv) { - const [command, ...rest] = argv; - if (!command || command === "--help" || command === "-h") { - console.log(usage()); - return; - } - if (command === "exact-extension-products") { - printJson(exactExtensionProducts(PREFIX)); - return; - } - if (command === "runtime-targets-for-surface") { - const surface = stringFlag(rest, "surface"); - if (!surface) { - fail(PREFIX, "runtime-targets-for-surface requires --surface"); - } - printJson(liboliphauntNativeRuntimeTargetsForSurface(surface)); - return; - } - const options = parseOptions(rest); - const matrix = matrixByName(command, options); - if (options.githubOutput) { - emitGithubOutput("matrix", matrix); - } else { - printJson(matrix); - } -} - -if (import.meta.main) { - main(Bun.argv.slice(2)); -} diff --git a/tools/release/atomic-directory.mjs b/tools/release/atomic-directory.mjs deleted file mode 100644 index 1bddf6d9d..000000000 --- a/tools/release/atomic-directory.mjs +++ /dev/null @@ -1,142 +0,0 @@ -import { - chmodSync, - copyFileSync, - existsSync, - lstatSync, - mkdirSync, - mkdtempSync, - readdirSync, - renameSync, - rmSync, - utimesSync, -} from "node:fs"; -import path from "node:path"; - -const trackedTemporaryPaths = new Set(); -const trackedPromotions = new Map(); -let cleanupInstalled = false; - -function cleanupTracked() { - for (const { backup, destination } of [...trackedPromotions.values()].reverse()) { - try { - if (!existsSync(destination) && existsSync(backup)) { - renameSync(backup, destination); - } else if (existsSync(backup)) { - rmSync(backup, { force: true, recursive: true }); - } - } catch { - // Preserve the recoverable backup when automatic restoration cannot run. - } - } - for (const temporary of [...trackedTemporaryPaths].reverse()) { - try { - rmSync(temporary, { force: true, recursive: true }); - } catch { - // The original failure or signal remains authoritative. - } - } -} - -function installCleanup() { - if (cleanupInstalled) return; - cleanupInstalled = true; - process.once("exit", cleanupTracked); - for (const [signal, code] of [["SIGINT", 130], ["SIGTERM", 143]]) { - process.once(signal, () => { - cleanupTracked(); - process.exit(code); - }); - } -} - -export function trackTemporaryPath(temporary) { - installCleanup(); - trackedTemporaryPaths.add(path.resolve(temporary)); - return temporary; -} - -export function releaseTemporaryPath(temporary) { - trackedTemporaryPaths.delete(path.resolve(temporary)); -} - -export function removeTemporaryPath(temporary) { - rmSync(temporary, { force: true, recursive: true }); - releaseTemporaryPath(temporary); -} - -export function createSiblingStage(destination, label = "stage") { - const resolved = path.resolve(destination); - const parent = path.dirname(resolved); - mkdirSync(parent, { recursive: true }); - return trackTemporaryPath( - mkdtempSync(path.join(parent, `.${path.basename(resolved)}.${label}-`)), - ); -} - -export function copyDirectoryTree(source, destination) { - const sourceStat = lstatSync(source); - if (!sourceStat.isDirectory() || sourceStat.isSymbolicLink()) { - throw new Error(`directory copy source is not a real directory: ${source}`); - } - mkdirSync(destination, { recursive: true, mode: sourceStat.mode }); - for (const entry of readdirSync(source, { withFileTypes: true })) { - const from = path.join(source, entry.name); - const to = path.join(destination, entry.name); - const stat = lstatSync(from); - if (stat.isSymbolicLink()) { - throw new Error(`directory copy refuses symbolic link ${from}`); - } - if (stat.isDirectory()) { - copyDirectoryTree(from, to); - chmodSync(to, stat.mode); - utimesSync(to, stat.atime, stat.mtime); - } else if (stat.isFile()) { - copyFileSync(from, to, 0); - chmodSync(to, stat.mode); - utimesSync(to, stat.atime, stat.mtime); - } else { - throw new Error(`directory copy refuses special file ${from}`); - } - } -} - -export function stageExistingDirectory(destination, label = "stage") { - const stage = createSiblingStage(destination, label); - if (existsSync(destination)) copyDirectoryTree(destination, stage); - return stage; -} - -export function promoteDirectory(stage, destination) { - const resolvedStage = path.resolve(stage); - const resolvedDestination = path.resolve(destination); - if (path.dirname(resolvedStage) !== path.dirname(resolvedDestination)) { - throw new Error("atomic directory stage must be a sibling of its destination"); - } - const backup = `${resolvedStage}.previous`; - trackedPromotions.set(resolvedStage, { - backup, - destination: resolvedDestination, - }); - let movedExisting = false; - try { - if (existsSync(resolvedDestination)) { - renameSync(resolvedDestination, backup); - movedExisting = true; - } - try { - renameSync(resolvedStage, resolvedDestination); - releaseTemporaryPath(resolvedStage); - } catch (error) { - if (movedExisting) renameSync(backup, resolvedDestination); - throw error; - } - if (movedExisting) rmSync(backup, { force: true, recursive: true }); - trackedPromotions.delete(resolvedStage); - } catch (error) { - if (movedExisting && !existsSync(resolvedDestination) && existsSync(backup)) { - renameSync(backup, resolvedDestination); - } - trackedPromotions.delete(resolvedStage); - throw error; - } -} diff --git a/tools/release/atomic-directory.test.mjs b/tools/release/atomic-directory.test.mjs deleted file mode 100644 index 8c0222ac5..000000000 --- a/tools/release/atomic-directory.test.mjs +++ /dev/null @@ -1,73 +0,0 @@ -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { - existsSync, - mkdtempSync, - mkdirSync, - readFileSync, - readdirSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { test } from "node:test"; -import assert from "node:assert/strict"; - -import { - createSiblingStage, - promoteDirectory, - stageExistingDirectory, -} from "./atomic-directory.mjs"; - -test("promotes a staged directory and removes the old bytes", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-atomic-directory-")); - try { - const destination = path.join(root, "live"); - mkdirSync(destination); - writeFileSync(path.join(destination, "old"), "old"); - const stage = createSiblingStage(destination); - writeFileSync(path.join(stage, "new"), "new"); - - promoteDirectory(stage, destination); - - assert.equal(readFileSync(path.join(destination, "new"), "utf8"), "new"); - assert.equal(existsSync(path.join(destination, "old")), false); - assert.equal(existsSync(stage), false); - assert.equal(existsSync(`${stage}.previous`), false); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("a normal termination cleans an unpromoted sibling stage", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-atomic-directory-exit-")); - try { - const destination = path.join(root, "live"); - const result = spawnSync( - process.execPath, - [ - "--input-type=module", - "--eval", - `import { createSiblingStage } from ${JSON.stringify(new URL("./atomic-directory.mjs", import.meta.url).href)}; createSiblingStage(${JSON.stringify(destination)});`, - ], - { encoding: "utf8" }, - ); - assert.equal(result.status, 0, result.stderr); - assert.deepEqual(readdirSync(root), []); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("staging an existing directory copies bytes without symbolic links", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-atomic-directory-copy-")); - try { - const destination = path.join(root, "live"); - mkdirSync(destination); - writeFileSync(path.join(destination, "kept"), "bytes"); - const stage = stageExistingDirectory(destination); - assert.equal(readFileSync(path.join(stage, "kept"), "utf8"), "bytes"); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/audit-github-release-controls.mjs b/tools/release/audit-github-release-controls.mjs deleted file mode 100644 index 8a1525948..000000000 --- a/tools/release/audit-github-release-controls.mjs +++ /dev/null @@ -1,596 +0,0 @@ -#!/usr/bin/env bun - -import { readFileSync } from "node:fs"; - -import { runGitHubGraphqlReadSync, runGitHubReadSync } from "./github-read.mjs"; - -export const CANONICAL_REPOSITORY = "f0rr0/oliphaunt"; -export const DEFAULT_BRANCH = "main"; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -const API_HEADERS = [ - "Accept: application/vnd.github+json", - "X-GitHub-Api-Version: 2022-11-28", -]; - -const BRANCH_PROTECTION_QUERY = ` -query OliphauntReleaseBranchProtection($owner: String!, $name: String!, $qualifiedName: String!) { - repository(owner: $owner, name: $name) { - nameWithOwner - ref(qualifiedName: $qualifiedName) { - name - branchProtectionRule { - id - pattern - allowsForcePushes - bypassForcePushAllowances(first: 100) { - totalCount - pageInfo { - hasNextPage - endCursor - } - nodes { - id - actor { - __typename - ... on User { - id - login - } - ... on Team { - id - slug - organization { - login - } - } - ... on App { - id - slug - } - } - } - } - } - } - } -}`; - -const RELEASE_TAG_APP_SECRETS = ["RELEASE_TAG_APP_CLIENT_ID", "RELEASE_TAG_APP_PRIVATE_KEY"]; -const RELEASE_PUBLISH_SECRETS = [ - ...RELEASE_TAG_APP_SECRETS, - "MAVEN_CENTRAL_PASSWORD", - "MAVEN_CENTRAL_USERNAME", - "MAVEN_GPG_KEY_ID", - "MAVEN_GPG_PASSPHRASE", - "MAVEN_GPG_PRIVATE_KEY", -]; - -const BOOTSTRAP_SECRETS = [ - "CRATES_IO_BOOTSTRAP_TOKEN", - "NPM_BOOTSTRAP_TOKEN", -]; - -const BOOTSTRAP_STATES = new Set(["idle", "ready", "retired"]); - -function expectedBootstrapSecrets(bootstrapState) { - if (!BOOTSTRAP_STATES.has(bootstrapState)) { - throw new Error(`bootstrap state must be idle, ready, or retired, got ${bootstrapState}`); - } - return bootstrapState === "ready" ? BOOTSTRAP_SECRETS : []; -} - -function expectedEnvironments(bootstrapState) { - return { - "release-bootstrap": [...RELEASE_TAG_APP_SECRETS, ...expectedBootstrapSecrets(bootstrapState)], - "release-dry-run": [], - "release-pr": ["RELEASE_PR_TOKEN"], - "release-publish": RELEASE_PUBLISH_SECRETS, - }; -} - -function finding(status, id, message) { - return { id, message, status }; -} - -function enabled(value) { - return value?.enabled === true; -} - -function requiredCheckNames(protection) { - const checks = protection?.required_status_checks; - return [...new Set([ - ...(Array.isArray(checks?.contexts) ? checks.contexts : []), - ...(Array.isArray(checks?.checks) - ? checks.checks.map((check) => check?.context).filter(Boolean) - : []), - ])].sort(); -} - -function reviewerRule(environment) { - return (environment?.protection_rules ?? []).find( - (rule) => rule?.type === "required_reviewers", - ); -} - -function reviewerCount(rule) { - return Array.isArray(rule?.reviewers) ? rule.reviewers.length : 0; -} - -function bypassActorCount(reviews) { - const bypass = reviews?.bypass_pull_request_allowances ?? {}; - return ["apps", "teams", "users"].reduce( - (total, key) => total + (Array.isArray(bypass[key]) ? bypass[key].length : 0), - 0, - ); -} - -function exactDeploymentPolicy(entry) { - const deployment = entry?.environment?.deployment_branch_policy; - const policies = entry?.branchPolicies ?? []; - const expected = [{ name: DEFAULT_BRANCH, type: "branch" }]; - const identity = (policy) => `${policy?.type ?? ""}\0${policy?.name ?? ""}`; - return deployment?.protected_branches === false - && deployment?.custom_branch_policies === true - && policies.length === expected.length - && JSON.stringify(policies.map(identity).sort()) === JSON.stringify(expected.map(identity).sort()); -} - -function arrayDifference(left, right) { - const rightSet = new Set(right); - return left.filter((value) => !rightSet.has(value)); -} - -function list(values) { - return values.length === 0 ? "none" : values.join(", "); -} - -/** - * Evaluate a read-only snapshot of GitHub repository controls. - * - * FAIL findings are release-safety blockers. WARN findings are governance or - * repository-hygiene recommendations and never change the process exit code. - */ -export function auditGitHubReleaseControls( - snapshot, - { bootstrapState = "idle", governance = "solo" } = {}, -) { - if (!new Set(["solo", "team"]).has(governance)) { - throw new Error(`governance must be solo or team, got ${governance}`); - } - expectedBootstrapSecrets(bootstrapState); - - const findings = []; - const repository = snapshot?.repository ?? {}; - const protection = snapshot?.branchProtection ?? {}; - const actions = snapshot?.actionsWorkflowPermissions ?? {}; - const reviews = protection?.required_pull_request_reviews; - const hasProtection = snapshot?.branchProtection != null - && Object.keys(snapshot.branchProtection).length > 0; - - findings.push(repository.full_name === CANONICAL_REPOSITORY - ? finding("PASS", "repository.identity", `repository is ${CANONICAL_REPOSITORY}`) - : finding("FAIL", "repository.identity", `expected ${CANONICAL_REPOSITORY}, got ${repository.full_name ?? "missing"}`)); - findings.push(repository.default_branch === DEFAULT_BRANCH - ? finding("PASS", "repository.default-branch", `default branch is ${DEFAULT_BRANCH}`) - : finding("FAIL", "repository.default-branch", `default branch must be ${DEFAULT_BRANCH}`)); - findings.push(repository.allow_squash_merge === true - ? finding("PASS", "repository.squash-merge", "squash merging is enabled") - : finding("FAIL", "repository.squash-merge", "squash merging must be enabled")); - findings.push(repository.allow_merge_commit === false - ? finding("PASS", "repository.merge-commit", "merge commits are disabled") - : finding("WARN", "repository.merge-commit", "disable merge commits to keep squash-only history")); - findings.push(repository.allow_rebase_merge === false - ? finding("PASS", "repository.rebase-merge", "rebase merging is disabled") - : finding("WARN", "repository.rebase-merge", "disable rebase merging to keep squash-only history")); - findings.push(repository.delete_branch_on_merge === true - ? finding("PASS", "repository.delete-branch", "merged branches are deleted automatically") - : finding("WARN", "repository.delete-branch", "enable automatic deletion of merged branches")); - - findings.push(hasProtection - ? finding("PASS", "branch.protection", `${DEFAULT_BRANCH} has branch protection`) - : finding("FAIL", "branch.protection", `${DEFAULT_BRANCH} must have branch protection`)); - findings.push(protection?.allow_force_pushes?.enabled === false - ? finding("PASS", "branch.force-push", `${DEFAULT_BRANCH} blocks force-pushes`) - : finding("FAIL", "branch.force-push", `${DEFAULT_BRANCH} must block force-pushes`)); - const graphProtection = snapshot?.branchProtectionGraphql; - const graphRule = graphProtection?.rule; - const forcePushAllowances = graphRule?.bypassForcePushAllowances; - const forcePushBypassCount = forcePushAllowances?.totalCount; - const forcePushBypassNodes = forcePushAllowances?.nodes; - const graphIdentityIsExact = graphProtection?.nameWithOwner === CANONICAL_REPOSITORY - && graphProtection?.refName === DEFAULT_BRANCH - && graphRule?.pattern === DEFAULT_BRANCH; - const graphForcePushesBlocked = graphRule?.allowsForcePushes === false; - const forcePushBypassInventoryIsComplete = Number.isSafeInteger(forcePushBypassCount) - && forcePushBypassCount >= 0 - && Array.isArray(forcePushBypassNodes) - && forcePushBypassNodes.length === forcePushBypassCount - && forcePushAllowances?.pageInfo?.hasNextPage === false; - const forcePushBypassesBlocked = forcePushBypassInventoryIsComplete - && forcePushBypassCount === 0; - findings.push(graphIdentityIsExact && graphForcePushesBlocked && forcePushBypassesBlocked - ? finding("PASS", "branch.force-push-bypass", `${DEFAULT_BRANCH} has no actor-specific force-push bypass`) - : finding( - "FAIL", - "branch.force-push-bypass", - !graphIdentityIsExact - ? `GraphQL must expose the exact ${CANONICAL_REPOSITORY} ${DEFAULT_BRANCH} branch-protection rule` - : !graphForcePushesBlocked - ? `${DEFAULT_BRANCH} must block force-pushes in its GraphQL branch-protection rule` - : !forcePushBypassInventoryIsComplete - ? `${DEFAULT_BRANCH} force-push bypass inventory is incomplete or malformed` - : Number.isSafeInteger(forcePushBypassCount) - ? `${forcePushBypassCount} actor(s) can bypass ${DEFAULT_BRANCH} force-push protection` - : `${DEFAULT_BRANCH} force-push bypass inventory is malformed`, - )); - findings.push(protection?.allow_deletions?.enabled === false - ? finding("PASS", "branch.deletion", `${DEFAULT_BRANCH} blocks deletion`) - : finding("FAIL", "branch.deletion", `${DEFAULT_BRANCH} must block deletion`)); - findings.push(enabled(protection.required_linear_history) - ? finding("PASS", "branch.linear-history", `${DEFAULT_BRANCH} requires linear history`) - : finding("FAIL", "branch.linear-history", `${DEFAULT_BRANCH} must require linear history`)); - findings.push(enabled(protection.required_conversation_resolution) - ? finding("PASS", "branch.conversation-resolution", "review conversations must be resolved") - : finding("FAIL", "branch.conversation-resolution", "review conversations must be resolved before merge")); - const checkNames = requiredCheckNames(protection); - findings.push(protection?.required_status_checks?.strict === true - ? finding("PASS", "branch.strict-checks", "required checks must pass on an up-to-date branch") - : finding("FAIL", "branch.strict-checks", "required status checks must use strict mode")); - findings.push(checkNames.includes("Required") - ? finding("PASS", "branch.required-check", "aggregate Required check is a merge gate") - : finding("FAIL", "branch.required-check", "aggregate Required check must be required")); - const extraChecks = checkNames.filter((name) => name !== "Required"); - findings.push(extraChecks.length === 0 - ? finding("PASS", "branch.aggregate-only", "Required is the only branch-protection check") - : finding("WARN", "branch.aggregate-only", `remove redundant required checks: ${list(extraChecks)}`)); - - const approvalCount = Number(reviews?.required_approving_review_count); - if (governance === "team") { - findings.push(reviews && Number.isSafeInteger(approvalCount) && approvalCount >= 1 - ? finding("PASS", "branch.pr-review", "pull requests require independent approval") - : finding("FAIL", "branch.pr-review", "team-governed pull requests must require at least one approval")); - } else { - findings.push(reviews && approvalCount === 0 - ? finding("PASS", "branch.pr-review", "solo pull requests do not require an unavailable self-approval") - : finding( - "FAIL", - "branch.pr-review", - `solo governance requires zero approvals; ${Number.isSafeInteger(approvalCount) ? approvalCount : "an invalid count"} makes self-authored pull requests unmergeable`, - )); - } - findings.push(reviews?.dismiss_stale_reviews === true - ? finding("PASS", "branch.stale-review", "new commits dismiss stale approvals") - : finding("FAIL", "branch.stale-review", "new commits must dismiss stale approvals")); - const bypassCount = bypassActorCount(reviews); - findings.push(bypassCount === 0 - ? finding("PASS", "branch.review-bypass", "no actor bypasses pull-request review") - : finding("WARN", "branch.review-bypass", `${bypassCount} actor(s) can bypass pull-request review`)); - if (governance === "team") { - findings.push(reviews?.require_last_push_approval === true - ? finding("PASS", "branch.last-push-review", "a different maintainer must approve the last push") - : finding("WARN", "branch.last-push-review", "with a second maintainer, require approval of the last push by someone else")); - } else { - findings.push(reviews?.require_last_push_approval !== true - ? finding("PASS", "branch.last-push-review", "solo governance does not require an unavailable second approver") - : finding("WARN", "branch.last-push-review", "last-push approval can make a solo-maintained repository unmergeable")); - } - - findings.push(actions.default_workflow_permissions === "read" - ? finding("PASS", "actions.default-token", "default workflow token permission is read") - : finding("FAIL", "actions.default-token", "default workflow token permission must be read")); - findings.push(actions.can_approve_pull_request_reviews === false - ? finding("PASS", "actions.pr-approval", "workflow tokens cannot approve pull requests") - : finding("FAIL", "actions.pr-approval", "workflow tokens must not approve pull requests")); - - const expected = expectedEnvironments(bootstrapState); - for (const environmentName of Object.keys(expected).sort()) { - const entry = snapshot?.environments?.[environmentName]; - if (!entry) { - findings.push(finding("FAIL", `environment.${environmentName}.exists`, `${environmentName} must exist`)); - continue; - } - - findings.push(finding("PASS", `environment.${environmentName}.exists`, `${environmentName} exists`)); - findings.push(exactDeploymentPolicy(entry) - ? finding( - "PASS", - `environment.${environmentName}.branch-policy`, - `${environmentName} accepts only branch main`, - ) - : finding( - "FAIL", - `environment.${environmentName}.branch-policy`, - `${environmentName} must use one exact custom branch policy for main and no tag policy`, - )); - - const actualSecrets = [...new Set(entry.secretNames ?? [])].sort(); - const expectedSecrets = [...expected[environmentName]].sort(); - const allowedSecrets = expectedSecrets; - const readyBootstrap = environmentName === "release-bootstrap" && bootstrapState === "ready"; - const missingSecrets = readyBootstrap - ? [...arrayDifference(RELEASE_TAG_APP_SECRETS, actualSecrets), - ...(actualSecrets.some((secret) => BOOTSTRAP_SECRETS.includes(secret)) ? [] : BOOTSTRAP_SECRETS)] - : arrayDifference(expectedSecrets, actualSecrets); - const unexpectedSecrets = arrayDifference(actualSecrets, allowedSecrets); - findings.push(missingSecrets.length === 0 - ? finding( - "PASS", - `environment.${environmentName}.secrets-present`, - readyBootstrap - ? `${environmentName} has tag App credentials and at least one approved registry bootstrap token name` - : `${environmentName} has all expected secret names`, - ) - : finding( - "FAIL", - `environment.${environmentName}.secrets-present`, - readyBootstrap - ? `${environmentName} must contain at least one token required by the approved lock: ${list(missingSecrets)}` - : `${environmentName} is missing secret names: ${list(missingSecrets)}`, - )); - findings.push(unexpectedSecrets.length === 0 - ? finding("PASS", `environment.${environmentName}.secrets-isolated`, `${environmentName} has no unexpected secret names`) - : finding("FAIL", `environment.${environmentName}.secrets-isolated`, `${environmentName} has unexpected secret names: ${list(unexpectedSecrets)}`)); - - if (!new Set(["release-bootstrap", "release-publish"]).has(environmentName)) continue; - const rule = reviewerRule(entry.environment); - if (governance === "team") { - findings.push(reviewerCount(rule) > 0 - ? finding("PASS", `environment.${environmentName}.reviewer`, `${environmentName} requires an environment reviewer`) - : finding("WARN", `environment.${environmentName}.reviewer`, `configure an independent reviewer for ${environmentName} when a second maintainer is available`)); - findings.push(rule?.prevent_self_review === true - ? finding("PASS", `environment.${environmentName}.self-review`, `${environmentName} prevents self-review`) - : finding("WARN", `environment.${environmentName}.self-review`, `enable prevent-self-review for ${environmentName} with team governance`)); - } else { - findings.push(rule?.prevent_self_review !== true - ? finding("PASS", `environment.${environmentName}.self-review`, `${environmentName} remains operable by a solo maintainer`) - : finding("WARN", `environment.${environmentName}.self-review`, `disable prevent-self-review for ${environmentName} while the repository has one maintainer`)); - } - } - - return findings.sort((left, right) => compareText(left.id, right.id)); -} - -export function summarizeFindings(findings) { - const summary = { PASS: 0, WARN: 0, FAIL: 0 }; - for (const item of findings) summary[item.status] += 1; - return summary; -} - -export function formatAudit(findings, options) { - const summary = summarizeFindings(findings); - const ordered = [...findings].sort((left, right) => compareText(left.id, right.id)); - const lines = [ - `GitHub release-controls audit: ${CANONICAL_REPOSITORY} (governance=${options.governance}, bootstrap=${options.bootstrapState})`, - ...ordered.map((item) => `${item.status.padEnd(4)} ${item.id}: ${item.message}`), - `Summary: ${summary.PASS} PASS, ${summary.WARN} WARN, ${summary.FAIL} FAIL`, - ]; - return lines.join("\n"); -} - -/** Run exactly one read-only GitHub REST request. */ -export function githubApiArguments(endpoint) { - const repositoryRoot = `repos/${CANONICAL_REPOSITORY}`; - const canonicalRepositoryEndpoint = endpoint === repositoryRoot - || endpoint.startsWith(`${repositoryRoot}/`) - || endpoint.startsWith(`${repositoryRoot}?`); - if (!canonicalRepositoryEndpoint) { - throw new Error(`refusing non-canonical GitHub API endpoint: ${endpoint}`); - } - const args = ["api"]; - for (const header of API_HEADERS) args.push("--header", header); - args.push(endpoint); - return args; -} - -export function ghApiGet(endpoint) { - const args = githubApiArguments(endpoint); - const output = runGitHubReadSync(args, { - label: `release-controls GET ${endpoint}`, - maxBuffer: 16 * 1024 * 1024, - }); - try { - return JSON.parse(output); - } catch (error) { - throw new Error(`GET ${endpoint} returned invalid JSON: ${error.message}`); - } -} - -function collectBranchProtectionGraphql(graphqlRead) { - const [owner, name] = CANONICAL_REPOSITORY.split("/"); - const output = graphqlRead(BRANCH_PROTECTION_QUERY, { - name, - owner, - qualifiedName: `refs/heads/${DEFAULT_BRANCH}`, - }, { - label: "release-controls GraphQL main branch-protection rule", - maxBuffer: 16 * 1024 * 1024, - }); - let response; - try { - response = JSON.parse(output); - } catch (error) { - throw new Error(`GraphQL branch-protection query returned invalid JSON: ${error.message}`); - } - if (response?.errors !== undefined && (!Array.isArray(response.errors) || response.errors.length > 0)) { - throw new Error("GraphQL branch-protection query returned errors"); - } - const repository = response?.data?.repository; - const ref = repository?.ref; - const rule = ref?.branchProtectionRule; - const allowances = rule?.bypassForcePushAllowances; - if (repository?.nameWithOwner !== CANONICAL_REPOSITORY || ref?.name !== DEFAULT_BRANCH) { - throw new Error("GraphQL did not return the exact canonical main ref"); - } - if ( - !rule - || typeof rule.id !== "string" - || rule.id === "" - || typeof rule.pattern !== "string" - || typeof rule.allowsForcePushes !== "boolean" - ) { - throw new Error("GraphQL did not return a complete main branch-protection rule"); - } - if ( - !Number.isSafeInteger(allowances?.totalCount) - || allowances.totalCount < 0 - || !Array.isArray(allowances?.nodes) - || allowances.nodes.length !== allowances.totalCount - || allowances?.pageInfo?.hasNextPage !== false - ) { - throw new Error("GraphQL main force-push bypass inventory is incomplete or malformed"); - } - for (const node of allowances.nodes) { - if ( - typeof node?.id !== "string" - || node.id === "" - || !new Set(["App", "Team", "User"]).has(node?.actor?.__typename) - ) { - throw new Error("GraphQL main force-push bypass actor is malformed"); - } - } - return { - nameWithOwner: repository.nameWithOwner, - refName: ref.name, - rule, - }; -} - -function paged(apiGet, endpoint, collectionKey) { - const values = []; - let page = 1; - while (true) { - const separator = endpoint.includes("?") ? "&" : "?"; - const response = apiGet(`${endpoint}${separator}per_page=100&page=${page}`); - const batch = response?.[collectionKey]; - if (!Array.isArray(batch)) { - throw new Error(`GET ${endpoint} did not return ${collectionKey}`); - } - values.push(...batch); - const total = Number(response.total_count ?? values.length); - if (values.length >= total || batch.length === 0) return values; - page += 1; - } -} - -export function collectGitHubReleaseControls( - apiGet = ghApiGet, - graphqlRead = runGitHubGraphqlReadSync, -) { - const repository = apiGet(`repos/${CANONICAL_REPOSITORY}`); - const branchProtection = apiGet(`repos/${CANONICAL_REPOSITORY}/branches/${DEFAULT_BRANCH}/protection`); - const branchProtectionGraphql = collectBranchProtectionGraphql(graphqlRead); - const actionsWorkflowPermissions = apiGet(`repos/${CANONICAL_REPOSITORY}/actions/permissions/workflow`); - const environmentList = paged( - apiGet, - `repos/${CANONICAL_REPOSITORY}/environments`, - "environments", - ); - const environmentByName = new Map(environmentList.map((environment) => [environment.name, environment])); - const environments = {}; - - for (const environmentName of Object.keys(expectedEnvironments("idle")).sort()) { - if (!environmentByName.has(environmentName)) continue; - const encodedName = encodeURIComponent(environmentName); - const root = `repos/${CANONICAL_REPOSITORY}/environments/${encodedName}`; - const environment = apiGet(root); - const branchPolicies = environment.deployment_branch_policy?.custom_branch_policies === true - ? paged(apiGet, `${root}/deployment-branch-policies`, "branch_policies") - : []; - const secrets = paged(apiGet, `${root}/secrets`, "secrets"); - environments[environmentName] = { - branchPolicies, - environment, - secretNames: secrets.map((secret) => secret.name).sort(), - }; - } - - return { - actionsWorkflowPermissions, - branchProtection, - branchProtectionGraphql, - environments, - repository, - }; -} - -function parseArgs(argv) { - const options = { - bootstrapState: "idle", - fixture: null, - governance: "solo", - json: false, - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "-h" || arg === "--help") return { ...options, help: true }; - if (arg === "--json") { - options.json = true; - continue; - } - if (arg === "--governance" || arg === "--bootstrap-state" || arg === "--fixture") { - const value = argv[index + 1]; - if (!value) throw new Error(`${arg} requires a value`); - index += 1; - if (arg === "--governance") options.governance = value; - else if (arg === "--bootstrap-state") options.bootstrapState = value; - else options.fixture = value; - continue; - } - throw new Error(`unknown argument: ${arg}`); - } - return options; -} - -function usage() { - return `usage: tools/dev/bun.sh tools/release/audit-github-release-controls.mjs [options] - -Read-only audit of ${CANONICAL_REPOSITORY}'s release safety controls. - -Options: - --governance solo|team Calibrate independent-review recommendations (default: solo) - --bootstrap-state idle|ready|retired - Require bootstrap tokens absent before bootstrap, one or both - approved registry tokens for an imminent lock-derived bootstrap, - or no tokens after revocation (default: idle) - --fixture PATH Audit a saved API snapshot without accessing GitHub - --json Emit deterministic JSON - -h, --help Show this help -`; -} - -function main(argv) { - let options; - try { - options = parseArgs(argv); - if (options.help) { - console.log(usage()); - return; - } - const snapshot = options.fixture - ? JSON.parse(readFileSync(options.fixture, "utf8")) - : collectGitHubReleaseControls(); - const findings = auditGitHubReleaseControls(snapshot, options); - const summary = summarizeFindings(findings); - if (options.json) { - console.log(JSON.stringify({ - bootstrapState: options.bootstrapState, - findings, - governance: options.governance, - repository: CANONICAL_REPOSITORY, - summary, - }, null, 2)); - } else { - console.log(formatAudit(findings, options)); - } - if (summary.FAIL > 0) process.exitCode = 1; - } catch (error) { - console.error(`audit-github-release-controls.mjs: ${error.message}`); - process.exitCode = 2; - } -} - -if (import.meta.main) main(Bun.argv.slice(2)); diff --git a/tools/release/audit-github-release-controls.mts b/tools/release/audit-github-release-controls.mts new file mode 100644 index 000000000..cc5af2c4a --- /dev/null +++ b/tools/release/audit-github-release-controls.mts @@ -0,0 +1,746 @@ +#!/usr/bin/env bun + +import { readFileSync } from 'node:fs'; + +import { requestGithubGraphql, requestGithubJsonWithRetry } from './github-read.mts'; + +export const CANONICAL_REPOSITORY = 'f0rr0/oliphaunt'; +export const DEFAULT_BRANCH = 'main'; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +const BRANCH_PROTECTION_QUERY = ` +query OliphauntReleaseBranchProtection($owner: String!, $name: String!, $qualifiedName: String!) { + repository(owner: $owner, name: $name) { + nameWithOwner + ref(qualifiedName: $qualifiedName) { + name + branchProtectionRule { + id + pattern + allowsForcePushes + bypassForcePushAllowances(first: 100) { + totalCount + pageInfo { + hasNextPage + endCursor + } + nodes { + id + actor { + __typename + ... on User { + id + login + } + ... on Team { + id + slug + organization { + login + } + } + ... on App { + id + slug + } + } + } + } + } + } + } +}`; + +const RELEASE_TAG_APP_SECRETS = ['RELEASE_TAG_APP_CLIENT_ID', 'RELEASE_TAG_APP_PRIVATE_KEY']; +const RELEASE_PUBLISH_SECRETS = [ + ...RELEASE_TAG_APP_SECRETS, + 'MAVEN_CENTRAL_PASSWORD', + 'MAVEN_CENTRAL_USERNAME', + 'MAVEN_GPG_KEY_ID', + 'MAVEN_GPG_PASSPHRASE', + 'MAVEN_GPG_PRIVATE_KEY', +]; + +const BOOTSTRAP_SECRETS = ['CRATES_IO_BOOTSTRAP_TOKEN', 'NPM_BOOTSTRAP_TOKEN']; + +const BOOTSTRAP_STATES = new Set(['idle', 'ready', 'retired']); + +function expectedBootstrapSecrets(bootstrapState) { + if (!BOOTSTRAP_STATES.has(bootstrapState)) { + throw new Error(`bootstrap state must be idle, ready, or retired, got ${bootstrapState}`); + } + return bootstrapState === 'ready' ? BOOTSTRAP_SECRETS : []; +} + +function expectedEnvironments(bootstrapState) { + return { + 'release-bootstrap': [...RELEASE_TAG_APP_SECRETS, ...expectedBootstrapSecrets(bootstrapState)], + 'release-dry-run': [], + 'release-pr': ['RELEASE_PR_TOKEN'], + 'release-publish': RELEASE_PUBLISH_SECRETS, + }; +} + +function finding(status, id, message) { + return { id, message, status }; +} + +function enabled(value) { + return value?.enabled === true; +} + +function requiredCheckNames(protection) { + const checks = protection?.required_status_checks; + return [ + ...new Set([ + ...(Array.isArray(checks?.contexts) ? checks.contexts : []), + ...(Array.isArray(checks?.checks) + ? checks.checks.map((check) => check?.context).filter(Boolean) + : []), + ]), + ].sort(); +} + +function reviewerRule(environment) { + return (environment?.protection_rules ?? []).find((rule) => rule?.type === 'required_reviewers'); +} + +function reviewerCount(rule) { + return Array.isArray(rule?.reviewers) ? rule.reviewers.length : 0; +} + +function bypassActorCount(reviews) { + const bypass = reviews?.bypass_pull_request_allowances ?? {}; + return ['apps', 'teams', 'users'].reduce( + (total, key) => total + (Array.isArray(bypass[key]) ? bypass[key].length : 0), + 0, + ); +} + +function exactDeploymentPolicy(entry) { + const deployment = entry?.environment?.deployment_branch_policy; + const policies = entry?.branchPolicies ?? []; + const expected = [{ name: DEFAULT_BRANCH, type: 'branch' }]; + const identity = (policy) => `${policy?.type ?? ''}\0${policy?.name ?? ''}`; + return ( + deployment?.protected_branches === false && + deployment?.custom_branch_policies === true && + policies.length === expected.length && + JSON.stringify(policies.map(identity).sort()) === JSON.stringify(expected.map(identity).sort()) + ); +} + +function arrayDifference(left, right) { + const rightSet = new Set(right); + return left.filter((value) => !rightSet.has(value)); +} + +function list(values) { + return values.length === 0 ? 'none' : values.join(', '); +} + +/** + * Evaluate a read-only snapshot of GitHub repository controls. + * + * FAIL findings are release-safety blockers. WARN findings are governance or + * repository-hygiene recommendations and never change the process exit code. + */ +export function auditGitHubReleaseControls( + snapshot, + { bootstrapState = 'idle', governance = 'solo' } = {}, +) { + if (!new Set(['solo', 'team']).has(governance)) { + throw new Error(`governance must be solo or team, got ${governance}`); + } + expectedBootstrapSecrets(bootstrapState); + + const findings = []; + const repository = snapshot?.repository ?? {}; + const protection = snapshot?.branchProtection ?? {}; + const actions = snapshot?.actionsWorkflowPermissions ?? {}; + const reviews = protection?.required_pull_request_reviews; + const hasProtection = + snapshot?.branchProtection != null && Object.keys(snapshot.branchProtection).length > 0; + + findings.push( + repository.full_name === CANONICAL_REPOSITORY + ? finding('PASS', 'repository.identity', `repository is ${CANONICAL_REPOSITORY}`) + : finding( + 'FAIL', + 'repository.identity', + `expected ${CANONICAL_REPOSITORY}, got ${repository.full_name ?? 'missing'}`, + ), + ); + findings.push( + repository.default_branch === DEFAULT_BRANCH + ? finding('PASS', 'repository.default-branch', `default branch is ${DEFAULT_BRANCH}`) + : finding('FAIL', 'repository.default-branch', `default branch must be ${DEFAULT_BRANCH}`), + ); + findings.push( + repository.allow_squash_merge === true + ? finding('PASS', 'repository.squash-merge', 'squash merging is enabled') + : finding('FAIL', 'repository.squash-merge', 'squash merging must be enabled'), + ); + findings.push( + repository.allow_merge_commit === false + ? finding('PASS', 'repository.merge-commit', 'merge commits are disabled') + : finding( + 'WARN', + 'repository.merge-commit', + 'disable merge commits to keep squash-only history', + ), + ); + findings.push( + repository.allow_rebase_merge === false + ? finding('PASS', 'repository.rebase-merge', 'rebase merging is disabled') + : finding( + 'WARN', + 'repository.rebase-merge', + 'disable rebase merging to keep squash-only history', + ), + ); + findings.push( + repository.delete_branch_on_merge === true + ? finding('PASS', 'repository.delete-branch', 'merged branches are deleted automatically') + : finding('WARN', 'repository.delete-branch', 'enable automatic deletion of merged branches'), + ); + + findings.push( + hasProtection + ? finding('PASS', 'branch.protection', `${DEFAULT_BRANCH} has branch protection`) + : finding('FAIL', 'branch.protection', `${DEFAULT_BRANCH} must have branch protection`), + ); + findings.push( + protection?.allow_force_pushes?.enabled === false + ? finding('PASS', 'branch.force-push', `${DEFAULT_BRANCH} blocks force-pushes`) + : finding('FAIL', 'branch.force-push', `${DEFAULT_BRANCH} must block force-pushes`), + ); + const graphProtection = snapshot?.branchProtectionGraphql; + const graphRule = graphProtection?.rule; + const forcePushAllowances = graphRule?.bypassForcePushAllowances; + const forcePushBypassCount = forcePushAllowances?.totalCount; + const forcePushBypassNodes = forcePushAllowances?.nodes; + const graphIdentityIsExact = + graphProtection?.nameWithOwner === CANONICAL_REPOSITORY && + graphProtection?.refName === DEFAULT_BRANCH && + graphRule?.pattern === DEFAULT_BRANCH; + const graphForcePushesBlocked = graphRule?.allowsForcePushes === false; + const forcePushBypassInventoryIsComplete = + Number.isSafeInteger(forcePushBypassCount) && + forcePushBypassCount >= 0 && + Array.isArray(forcePushBypassNodes) && + forcePushBypassNodes.length === forcePushBypassCount && + forcePushAllowances?.pageInfo?.hasNextPage === false; + const forcePushBypassesBlocked = forcePushBypassInventoryIsComplete && forcePushBypassCount === 0; + findings.push( + graphIdentityIsExact && graphForcePushesBlocked && forcePushBypassesBlocked + ? finding( + 'PASS', + 'branch.force-push-bypass', + `${DEFAULT_BRANCH} has no actor-specific force-push bypass`, + ) + : finding( + 'FAIL', + 'branch.force-push-bypass', + !graphIdentityIsExact + ? `GraphQL must expose the exact ${CANONICAL_REPOSITORY} ${DEFAULT_BRANCH} branch-protection rule` + : !graphForcePushesBlocked + ? `${DEFAULT_BRANCH} must block force-pushes in its GraphQL branch-protection rule` + : !forcePushBypassInventoryIsComplete + ? `${DEFAULT_BRANCH} force-push bypass inventory is incomplete or malformed` + : Number.isSafeInteger(forcePushBypassCount) + ? `${forcePushBypassCount} actor(s) can bypass ${DEFAULT_BRANCH} force-push protection` + : `${DEFAULT_BRANCH} force-push bypass inventory is malformed`, + ), + ); + findings.push( + protection?.allow_deletions?.enabled === false + ? finding('PASS', 'branch.deletion', `${DEFAULT_BRANCH} blocks deletion`) + : finding('FAIL', 'branch.deletion', `${DEFAULT_BRANCH} must block deletion`), + ); + findings.push( + enabled(protection.required_linear_history) + ? finding('PASS', 'branch.linear-history', `${DEFAULT_BRANCH} requires linear history`) + : finding('FAIL', 'branch.linear-history', `${DEFAULT_BRANCH} must require linear history`), + ); + findings.push( + enabled(protection.required_conversation_resolution) + ? finding('PASS', 'branch.conversation-resolution', 'review conversations must be resolved') + : finding( + 'FAIL', + 'branch.conversation-resolution', + 'review conversations must be resolved before merge', + ), + ); + const checkNames = requiredCheckNames(protection); + findings.push( + protection?.required_status_checks?.strict === true + ? finding('PASS', 'branch.strict-checks', 'required checks must pass on an up-to-date branch') + : finding('FAIL', 'branch.strict-checks', 'required status checks must use strict mode'), + ); + findings.push( + checkNames.includes('Required') + ? finding('PASS', 'branch.required-check', 'aggregate Required check is a merge gate') + : finding('FAIL', 'branch.required-check', 'aggregate Required check must be required'), + ); + const extraChecks = checkNames.filter((name) => name !== 'Required'); + findings.push( + extraChecks.length === 0 + ? finding('PASS', 'branch.aggregate-only', 'Required is the only branch-protection check') + : finding( + 'WARN', + 'branch.aggregate-only', + `remove redundant required checks: ${list(extraChecks)}`, + ), + ); + + const approvalCount = Number(reviews?.required_approving_review_count); + if (governance === 'team') { + findings.push( + reviews && Number.isSafeInteger(approvalCount) && approvalCount >= 1 + ? finding('PASS', 'branch.pr-review', 'pull requests require independent approval') + : finding( + 'FAIL', + 'branch.pr-review', + 'team-governed pull requests must require at least one approval', + ), + ); + } else { + findings.push( + reviews && approvalCount === 0 + ? finding( + 'PASS', + 'branch.pr-review', + 'solo pull requests do not require an unavailable self-approval', + ) + : finding( + 'FAIL', + 'branch.pr-review', + `solo governance requires zero approvals; ${Number.isSafeInteger(approvalCount) ? approvalCount : 'an invalid count'} makes self-authored pull requests unmergeable`, + ), + ); + } + findings.push( + reviews?.dismiss_stale_reviews === true + ? finding('PASS', 'branch.stale-review', 'new commits dismiss stale approvals') + : finding('FAIL', 'branch.stale-review', 'new commits must dismiss stale approvals'), + ); + const bypassCount = bypassActorCount(reviews); + findings.push( + bypassCount === 0 + ? finding('PASS', 'branch.review-bypass', 'no actor bypasses pull-request review') + : finding( + 'WARN', + 'branch.review-bypass', + `${bypassCount} actor(s) can bypass pull-request review`, + ), + ); + if (governance === 'team') { + findings.push( + reviews?.require_last_push_approval === true + ? finding( + 'PASS', + 'branch.last-push-review', + 'a different maintainer must approve the last push', + ) + : finding( + 'WARN', + 'branch.last-push-review', + 'with a second maintainer, require approval of the last push by someone else', + ), + ); + } else { + findings.push( + reviews?.require_last_push_approval !== true + ? finding( + 'PASS', + 'branch.last-push-review', + 'solo governance does not require an unavailable second approver', + ) + : finding( + 'WARN', + 'branch.last-push-review', + 'last-push approval can make a solo-maintained repository unmergeable', + ), + ); + } + + findings.push( + actions.default_workflow_permissions === 'read' + ? finding('PASS', 'actions.default-token', 'default workflow token permission is read') + : finding('FAIL', 'actions.default-token', 'default workflow token permission must be read'), + ); + findings.push( + actions.can_approve_pull_request_reviews === false + ? finding('PASS', 'actions.pr-approval', 'workflow tokens cannot approve pull requests') + : finding('FAIL', 'actions.pr-approval', 'workflow tokens must not approve pull requests'), + ); + + const expected = expectedEnvironments(bootstrapState); + for (const environmentName of Object.keys(expected).sort()) { + const entry = snapshot?.environments?.[environmentName]; + if (!entry) { + findings.push( + finding('FAIL', `environment.${environmentName}.exists`, `${environmentName} must exist`), + ); + continue; + } + + findings.push( + finding('PASS', `environment.${environmentName}.exists`, `${environmentName} exists`), + ); + findings.push( + exactDeploymentPolicy(entry) + ? finding( + 'PASS', + `environment.${environmentName}.branch-policy`, + `${environmentName} accepts only branch main`, + ) + : finding( + 'FAIL', + `environment.${environmentName}.branch-policy`, + `${environmentName} must use one exact custom branch policy for main and no tag policy`, + ), + ); + + const actualSecrets = [...new Set(entry.secretNames ?? [])].sort(); + const expectedSecrets = [...expected[environmentName]].sort(); + const allowedSecrets = expectedSecrets; + const readyBootstrap = environmentName === 'release-bootstrap' && bootstrapState === 'ready'; + const missingSecrets = readyBootstrap + ? [ + ...arrayDifference(RELEASE_TAG_APP_SECRETS, actualSecrets), + ...(actualSecrets.some((secret) => BOOTSTRAP_SECRETS.includes(secret)) + ? [] + : BOOTSTRAP_SECRETS), + ] + : arrayDifference(expectedSecrets, actualSecrets); + const unexpectedSecrets = arrayDifference(actualSecrets, allowedSecrets); + findings.push( + missingSecrets.length === 0 + ? finding( + 'PASS', + `environment.${environmentName}.secrets-present`, + readyBootstrap + ? `${environmentName} has tag App credentials and at least one approved registry bootstrap token name` + : `${environmentName} has all expected secret names`, + ) + : finding( + 'FAIL', + `environment.${environmentName}.secrets-present`, + readyBootstrap + ? `${environmentName} must contain at least one token required by the approved lock: ${list(missingSecrets)}` + : `${environmentName} is missing secret names: ${list(missingSecrets)}`, + ), + ); + findings.push( + unexpectedSecrets.length === 0 + ? finding( + 'PASS', + `environment.${environmentName}.secrets-isolated`, + `${environmentName} has no unexpected secret names`, + ) + : finding( + 'FAIL', + `environment.${environmentName}.secrets-isolated`, + `${environmentName} has unexpected secret names: ${list(unexpectedSecrets)}`, + ), + ); + + if (!new Set(['release-bootstrap', 'release-publish']).has(environmentName)) continue; + const rule = reviewerRule(entry.environment); + if (governance === 'team') { + findings.push( + reviewerCount(rule) > 0 + ? finding( + 'PASS', + `environment.${environmentName}.reviewer`, + `${environmentName} requires an environment reviewer`, + ) + : finding( + 'WARN', + `environment.${environmentName}.reviewer`, + `configure an independent reviewer for ${environmentName} when a second maintainer is available`, + ), + ); + findings.push( + rule?.prevent_self_review === true + ? finding( + 'PASS', + `environment.${environmentName}.self-review`, + `${environmentName} prevents self-review`, + ) + : finding( + 'WARN', + `environment.${environmentName}.self-review`, + `enable prevent-self-review for ${environmentName} with team governance`, + ), + ); + } else { + findings.push( + rule?.prevent_self_review !== true + ? finding( + 'PASS', + `environment.${environmentName}.self-review`, + `${environmentName} remains operable by a solo maintainer`, + ) + : finding( + 'WARN', + `environment.${environmentName}.self-review`, + `disable prevent-self-review for ${environmentName} while the repository has one maintainer`, + ), + ); + } + } + + return findings.sort((left, right) => compareText(left.id, right.id)); +} + +export function summarizeFindings(findings) { + const summary = { PASS: 0, WARN: 0, FAIL: 0 }; + for (const item of findings) summary[item.status] += 1; + return summary; +} + +export function formatAudit(findings, options) { + const summary = summarizeFindings(findings); + const ordered = [...findings].sort((left, right) => compareText(left.id, right.id)); + const lines = [ + `GitHub release-controls audit: ${CANONICAL_REPOSITORY} (governance=${options.governance}, bootstrap=${options.bootstrapState})`, + ...ordered.map((item) => `${item.status.padEnd(4)} ${item.id}: ${item.message}`), + `Summary: ${summary.PASS} PASS, ${summary.WARN} WARN, ${summary.FAIL} FAIL`, + ]; + return lines.join('\n'); +} + +export function githubApiUrl(endpoint) { + const url = new URL(endpoint, 'https://api.github.com/'); + const root = `/repos/${CANONICAL_REPOSITORY}`; + if ( + /[\u0000-\u0020\u007f]/u.test(endpoint) || + url.origin !== 'https://api.github.com' || + url.hash || + url.username || + url.password || + !(url.pathname === root || url.pathname.startsWith(root + '/')) + ) + throw new Error(`refusing non-canonical GitHub API endpoint: ${endpoint}`); + return url.href; +} + +function githubApiGet(endpoint) { + return requestGithubJsonWithRetry(githubApiUrl(endpoint)); +} + +async function collectBranchProtectionGraphql(graphqlRead) { + const [owner, name] = CANONICAL_REPOSITORY.split('/'); + const response = await graphqlRead( + BRANCH_PROTECTION_QUERY, + { + name, + owner, + qualifiedName: `refs/heads/${DEFAULT_BRANCH}`, + }, + { + label: 'release-controls GraphQL main branch-protection rule', + maxBuffer: 16 * 1024 * 1024, + }, + ); + if ( + response?.errors !== undefined && + (!Array.isArray(response.errors) || response.errors.length > 0) + ) { + throw new Error('GraphQL branch-protection query returned errors'); + } + const repository = response?.data?.repository; + const ref = repository?.ref; + const rule = ref?.branchProtectionRule; + const allowances = rule?.bypassForcePushAllowances; + if (repository?.nameWithOwner !== CANONICAL_REPOSITORY || ref?.name !== DEFAULT_BRANCH) { + throw new Error('GraphQL did not return the exact canonical main ref'); + } + if ( + !rule || + typeof rule.id !== 'string' || + rule.id === '' || + typeof rule.pattern !== 'string' || + typeof rule.allowsForcePushes !== 'boolean' + ) { + throw new Error('GraphQL did not return a complete main branch-protection rule'); + } + if ( + !Number.isSafeInteger(allowances?.totalCount) || + allowances.totalCount < 0 || + !Array.isArray(allowances?.nodes) || + allowances.nodes.length !== allowances.totalCount || + allowances?.pageInfo?.hasNextPage !== false + ) { + throw new Error('GraphQL main force-push bypass inventory is incomplete or malformed'); + } + for (const node of allowances.nodes) { + if ( + typeof node?.id !== 'string' || + node.id === '' || + !new Set(['App', 'Team', 'User']).has(node?.actor?.__typename) + ) { + throw new Error('GraphQL main force-push bypass actor is malformed'); + } + } + return { + nameWithOwner: repository.nameWithOwner, + refName: ref.name, + rule, + }; +} + +async function paged(apiGet, endpoint, collectionKey) { + const values = []; + let page = 1; + while (true) { + const separator = endpoint.includes('?') ? '&' : '?'; + const response = await apiGet(`${endpoint}${separator}per_page=100&page=${page}`); + const batch = response?.[collectionKey]; + if (!Array.isArray(batch)) { + throw new Error(`GET ${endpoint} did not return ${collectionKey}`); + } + values.push(...batch); + const total = Number(response.total_count ?? values.length); + if (values.length >= total || batch.length === 0) return values; + page += 1; + } +} + +export async function collectGitHubReleaseControls( + apiGet = githubApiGet, + graphqlRead = requestGithubGraphql, +) { + const repository = await apiGet(`repos/${CANONICAL_REPOSITORY}`); + const branchProtection = await apiGet( + `repos/${CANONICAL_REPOSITORY}/branches/${DEFAULT_BRANCH}/protection`, + ); + const branchProtectionGraphql = await collectBranchProtectionGraphql(graphqlRead); + const actionsWorkflowPermissions = await apiGet( + `repos/${CANONICAL_REPOSITORY}/actions/permissions/workflow`, + ); + const environmentList = await paged( + apiGet, + `repos/${CANONICAL_REPOSITORY}/environments`, + 'environments', + ); + const environmentByName = new Map( + environmentList.map((environment) => [environment.name, environment]), + ); + const environments = {}; + + for (const environmentName of Object.keys(expectedEnvironments('idle')).sort()) { + if (!environmentByName.has(environmentName)) continue; + const encodedName = encodeURIComponent(environmentName); + const root = `repos/${CANONICAL_REPOSITORY}/environments/${encodedName}`; + const environment = await apiGet(root); + const branchPolicies = + environment.deployment_branch_policy?.custom_branch_policies === true + ? await paged(apiGet, `${root}/deployment-branch-policies`, 'branch_policies') + : []; + const secrets = await paged(apiGet, `${root}/secrets`, 'secrets'); + environments[environmentName] = { + branchPolicies, + environment, + secretNames: secrets.map((secret) => secret.name).sort(), + }; + } + + return { + actionsWorkflowPermissions, + branchProtection, + branchProtectionGraphql, + environments, + repository, + }; +} + +function parseArgs(argv) { + const options = { + bootstrapState: 'idle', + fixture: null, + governance: 'solo', + json: false, + }; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '-h' || arg === '--help') return { ...options, help: true }; + if (arg === '--json') { + options.json = true; + continue; + } + if (arg === '--governance' || arg === '--bootstrap-state' || arg === '--fixture') { + const value = argv[index + 1]; + if (!value) throw new Error(`${arg} requires a value`); + index += 1; + if (arg === '--governance') options.governance = value; + else if (arg === '--bootstrap-state') options.bootstrapState = value; + else options.fixture = value; + continue; + } + throw new Error(`unknown argument: ${arg}`); + } + return options; +} + +function usage() { + return `usage: tools/dev/bun.sh tools/release/audit-github-release-controls.mts [options] + +Read-only audit of ${CANONICAL_REPOSITORY}'s release safety controls. + +Options: + --governance solo|team Calibrate independent-review recommendations (default: solo) + --bootstrap-state idle|ready|retired + Require bootstrap tokens absent before bootstrap, one or both + approved registry tokens for an imminent lock-derived bootstrap, + or no tokens after revocation (default: idle) + --fixture PATH Audit a saved API snapshot without accessing GitHub + --json Emit deterministic JSON + -h, --help Show this help +`; +} + +async function main(argv) { + let options; + try { + options = parseArgs(argv); + if (options.help) { + console.log(usage()); + return; + } + const snapshot = options.fixture + ? JSON.parse(readFileSync(options.fixture, 'utf8')) + : await collectGitHubReleaseControls(); + const findings = auditGitHubReleaseControls(snapshot, options); + const summary = summarizeFindings(findings); + if (options.json) { + console.log( + JSON.stringify( + { + bootstrapState: options.bootstrapState, + findings, + governance: options.governance, + repository: CANONICAL_REPOSITORY, + summary, + }, + null, + 2, + ), + ); + } else { + console.log(formatAudit(findings, options)); + } + if (summary.FAIL > 0) process.exitCode = 1; + } catch (error) { + console.error(`audit-github-release-controls.mts: ${error.message}`); + process.exitCode = 2; + } +} + +if (import.meta.main) await main(Bun.argv.slice(2)); diff --git a/tools/release/audit-github-release-controls.test.mjs b/tools/release/audit-github-release-controls.test.mjs deleted file mode 100644 index cfbcc8273..000000000 --- a/tools/release/audit-github-release-controls.test.mjs +++ /dev/null @@ -1,438 +0,0 @@ -import { describe, expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { - mkdtempSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { - auditGitHubReleaseControls, - collectGitHubReleaseControls, - formatAudit, - githubApiArguments, - summarizeFindings, -} from "./audit-github-release-controls.mjs"; - -const TAG_APP_SECRETS = ["RELEASE_TAG_APP_CLIENT_ID", "RELEASE_TAG_APP_PRIVATE_KEY"]; - -const FIXTURES = path.join(import.meta.dir, "fixtures/github-release-controls"); -const TOOL = path.join(import.meta.dir, "audit-github-release-controls.mjs"); - -function fixture(name) { - return JSON.parse(readFileSync(path.join(FIXTURES, `${name}.json`), "utf8")); -} - -function graphqlPayload(source) { - return { - data: { - repository: { - nameWithOwner: source.branchProtectionGraphql.nameWithOwner, - ref: { - name: source.branchProtectionGraphql.refName, - branchProtectionRule: structuredClone(source.branchProtectionGraphql.rule), - }, - }, - }, - }; -} - -function expectGraphqlCollectionFailure(payload, expected) { - const source = fixture("desired-solo"); - const apiGet = (endpoint) => { - if (endpoint === "repos/f0rr0/oliphaunt") return source.repository; - if (endpoint === "repos/f0rr0/oliphaunt/branches/main/protection") { - return source.branchProtection; - } - throw new Error(`unexpected endpoint after malformed GraphQL response: ${endpoint}`); - }; - expect(() => collectGitHubReleaseControls( - apiGet, - () => JSON.stringify(payload), - )).toThrow(expected); -} - -describe("GitHub release controls", () => { - test("accepts the desired solo-maintainer controls without team-only ceremony", () => { - const findings = auditGitHubReleaseControls(fixture("desired-solo"), { - bootstrapState: "ready", - governance: "solo", - }); - expect(summarizeFindings(findings)).toEqual({ PASS: 39, WARN: 0, FAIL: 0 }); - }); - - test("rejects a solo approval rule that the only collaborator cannot satisfy", () => { - const snapshot = fixture("desired-solo"); - snapshot.branchProtection.required_pull_request_reviews.required_approving_review_count = 1; - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "ready", - governance: "solo", - }); - const finding = findings.find(({ id }) => id === "branch.pr-review"); - expect(finding?.status).toBe("FAIL"); - expect(finding?.message).toContain("unmergeable"); - }); - - test("accepts independent review when team governance is available", () => { - const findings = auditGitHubReleaseControls(fixture("desired-team"), { - bootstrapState: "ready", - governance: "team", - }); - expect(summarizeFindings(findings)).toEqual({ PASS: 41, WARN: 0, FAIL: 0 }); - }); - - test("classifies the known unsafe configuration as hard failures and hygiene warnings", () => { - const findings = auditGitHubReleaseControls(fixture("current-bad"), { - bootstrapState: "ready", - governance: "solo", - }); - const summary = summarizeFindings(findings); - expect(summary.FAIL).toBeGreaterThanOrEqual(8); - expect(summary.WARN).toBeGreaterThanOrEqual(4); - expect(findings.find(({ id }) => id === "environment.release-bootstrap.exists")?.status).toBe("FAIL"); - expect(findings.find(({ id }) => id === "environment.release-dry-run.secrets-isolated")?.status).toBe("PASS"); - expect(findings.find(({ id }) => id === "branch.aggregate-only")?.status).toBe("WARN"); - }); - - test("rejects credentials in the dry-run environment", () => { - const snapshot = fixture("desired-solo"); - snapshot.environments["release-dry-run"].secretNames = ["LEAKED_WRITE_TOKEN"]; - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "ready", - governance: "solo", - }); - expect(findings.find(({ id }) => id === "environment.release-dry-run.secrets-isolated")?.status).toBe("FAIL"); - }); - - test("all release environments accept only main", () => { - for (const environmentName of ["release-bootstrap", "release-pr", "release-dry-run", "release-publish"]) { - const snapshot = fixture("desired-solo"); - snapshot.environments[environmentName].branchPolicies.push({ - name: "oliphaunt-release-transport/*", - type: "tag", - }); - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "ready", - governance: "solo", - }); - expect(findings.find( - ({ id }) => id === `environment.${environmentName}.branch-policy`, - )?.status).toBe("FAIL"); - } - }); - - test("accepts only the lock-required revocable registry credentials while bootstrap is ready", () => { - for (const token of ["CRATES_IO_BOOTSTRAP_TOKEN", "NPM_BOOTSTRAP_TOKEN"]) { - const snapshot = fixture("desired-solo"); - snapshot.environments["release-bootstrap"].secretNames = [...TAG_APP_SECRETS, token]; - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "ready", - governance: "solo", - }); - const finding = findings.find(({ id }) => id === "environment.release-bootstrap.secrets-present"); - expect(finding?.status).toBe("PASS"); - expect(finding?.message).toContain("at least one approved registry bootstrap token"); - expect(summarizeFindings(findings).FAIL).toBe(0); - } - }); - - test("ready bootstrap mode rejects an empty credential set", () => { - const snapshot = fixture("desired-solo"); - snapshot.environments["release-bootstrap"].secretNames = [...TAG_APP_SECRETS]; - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "ready", - governance: "solo", - }); - const finding = findings.find(({ id }) => id === "environment.release-bootstrap.secrets-present"); - expect(finding?.status).toBe("FAIL"); - expect(finding?.message).toContain("approved lock"); - expect(finding?.message).toContain("CRATES_IO_BOOTSTRAP_TOKEN"); - expect(finding?.message).toContain("NPM_BOOTSTRAP_TOKEN"); - }); - - test("accepts an idle pre-bootstrap environment without long-lived tokens", () => { - const snapshot = fixture("desired-solo"); - snapshot.environments["release-bootstrap"].secretNames = [...TAG_APP_SECRETS]; - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "idle", - governance: "solo", - }); - expect(summarizeFindings(findings).FAIL).toBe(0); - }); - - test("idle bootstrap mode rejects prematurely installed bootstrap tokens", () => { - const findings = auditGitHubReleaseControls(fixture("desired-solo"), { - bootstrapState: "idle", - governance: "solo", - }); - const finding = findings.find(({ id }) => id === "environment.release-bootstrap.secrets-isolated"); - expect(finding?.status).toBe("FAIL"); - expect(finding?.message).toContain("CRATES_IO_BOOTSTRAP_TOKEN"); - expect(finding?.message).toContain("NPM_BOOTSTRAP_TOKEN"); - }); - - test("rejects unverifiable crates.io capacity assertions as stale release secrets", () => { - const snapshot = fixture("desired-solo"); - snapshot.environments["release-publish"].secretNames.push("CRATES_IO_VERSION_RUN_CAPACITY"); - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "ready", - governance: "solo", - }); - expect(findings.find(({ id }) => id === "environment.release-publish.secrets-present")?.status).toBe("PASS"); - const isolation = findings.find(({ id }) => id === "environment.release-publish.secrets-isolated"); - expect(isolation?.status).toBe("FAIL"); - expect(isolation?.message).toContain("CRATES_IO_VERSION_RUN_CAPACITY"); - }); - - test("does not mistake absent branch protection for disabled mutations", () => { - const snapshot = fixture("desired-solo"); - snapshot.branchProtection = null; - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "ready", - governance: "solo", - }); - expect(findings.find(({ id }) => id === "branch.protection")?.status).toBe("FAIL"); - expect(findings.find(({ id }) => id === "branch.force-push")?.status).toBe("FAIL"); - expect(findings.find(({ id }) => id === "branch.deletion")?.status).toBe("FAIL"); - }); - - test("rejects an actor-specific force-push bypass hidden from the REST protection flag", () => { - const snapshot = fixture("desired-solo"); - snapshot.branchProtectionGraphql.rule.bypassForcePushAllowances = { - totalCount: 1, - pageInfo: { endCursor: "cursor-1", hasNextPage: false }, - nodes: [{ id: "BPFA_test", actor: { __typename: "User", id: "U_test", login: "f0rr0" } }], - }; - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "ready", - governance: "solo", - }); - expect(findings.find(({ id }) => id === "branch.force-push")?.status).toBe("PASS"); - expect(findings.find(({ id }) => id === "branch.force-push-bypass")?.status).toBe("FAIL"); - }); - - test("fails closed when the GraphQL force-push bypass inventory is absent", () => { - const snapshot = fixture("desired-solo"); - delete snapshot.branchProtectionGraphql; - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "ready", - governance: "solo", - }); - expect(findings.find(({ id }) => id === "branch.force-push-bypass")?.status).toBe("FAIL"); - }); - - test("retired bootstrap mode requires long-lived bootstrap tokens to be absent", () => { - const snapshot = fixture("desired-solo"); - snapshot.environments["release-bootstrap"].secretNames = [...TAG_APP_SECRETS]; - const findings = auditGitHubReleaseControls(snapshot, { - bootstrapState: "retired", - governance: "solo", - }); - expect(summarizeFindings(findings).FAIL).toBe(0); - }); - - test("retired bootstrap mode rejects lingering bootstrap tokens", () => { - const findings = auditGitHubReleaseControls(fixture("desired-solo"), { - bootstrapState: "retired", - governance: "solo", - }); - const finding = findings.find(({ id }) => id === "environment.release-bootstrap.secrets-isolated"); - expect(finding?.status).toBe("FAIL"); - expect(finding?.message).toContain("CRATES_IO_BOOTSTRAP_TOKEN"); - expect(finding?.message).toContain("NPM_BOOTSTRAP_TOKEN"); - }); - - test("rejects an unknown bootstrap lifecycle state", () => { - expect(() => auditGitHubReleaseControls(fixture("desired-solo"), { - bootstrapState: "staged", - governance: "solo", - })).toThrow(/idle, ready, or retired/u); - }); - - test("formats findings deterministically", () => { - const options = { bootstrapState: "ready", governance: "solo" }; - const findings = auditGitHubReleaseControls(fixture("desired-solo"), options); - const first = formatAudit(findings, options); - expect(formatAudit([...findings].reverse(), options)).toBe(first); - }); -}); - -describe("GitHub API snapshot collection", () => { - test("constructs GET-only commands for the canonical repository", () => { - expect(githubApiArguments("repos/f0rr0/oliphaunt").slice(0, 3)).toEqual([ - "api", - "--header", - "Accept: application/vnd.github+json", - ]); - expect(() => githubApiArguments("repos/another-owner/another-repo")).toThrow( - /refusing non-canonical/u, - ); - expect(() => githubApiArguments("repos/f0rr0/oliphaunt-typo")).toThrow( - /refusing non-canonical/u, - ); - }); - - test("uses only the fixed canonical read endpoints", () => { - const source = fixture("desired-solo"); - const endpoints = []; - const graphReads = []; - const apiGet = (endpoint) => { - endpoints.push(endpoint); - if (endpoint === "repos/f0rr0/oliphaunt") return source.repository; - if (endpoint === "repos/f0rr0/oliphaunt/branches/main/protection") return source.branchProtection; - if (endpoint === "repos/f0rr0/oliphaunt/actions/permissions/workflow") return source.actionsWorkflowPermissions; - if (endpoint.startsWith("repos/f0rr0/oliphaunt/environments?")) { - return { - total_count: 4, - environments: Object.values(source.environments).map(({ environment }) => environment), - }; - } - const environmentName = Object.keys(source.environments).find((name) => endpoint.includes(encodeURIComponent(name))); - if (!environmentName) throw new Error(`unexpected endpoint ${endpoint}`); - if (endpoint === `repos/f0rr0/oliphaunt/environments/${encodeURIComponent(environmentName)}`) { - return source.environments[environmentName].environment; - } - if (endpoint.includes("deployment-branch-policies")) { - return { - total_count: 1, - branch_policies: source.environments[environmentName].branchPolicies, - }; - } - if (endpoint.includes("/secrets?")) { - const secrets = source.environments[environmentName].secretNames.map((name) => ({ name })); - return { total_count: secrets.length, secrets }; - } - throw new Error(`unexpected endpoint ${endpoint}`); - }; - const graphqlRead = (document, variables) => { - graphReads.push({ document, variables }); - return JSON.stringify({ - data: { - repository: { - nameWithOwner: source.branchProtectionGraphql.nameWithOwner, - ref: { - name: source.branchProtectionGraphql.refName, - branchProtectionRule: source.branchProtectionGraphql.rule, - }, - }, - }, - }); - }; - - expect(collectGitHubReleaseControls(apiGet, graphqlRead)).toEqual(source); - expect(graphReads).toHaveLength(1); - expect(graphReads[0].document).toMatch(/^\s*query OliphauntReleaseBranchProtection/u); - expect(graphReads[0].variables).toEqual({ - name: "oliphaunt", - owner: "f0rr0", - qualifiedName: "refs/heads/main", - }); - expect(endpoints.every((endpoint) => !/[\s]|(^|[?&])method=/u.test(endpoint))).toBe(true); - expect(endpoints.every((endpoint) => endpoint === "repos/f0rr0/oliphaunt" || endpoint.startsWith("repos/f0rr0/oliphaunt/") || endpoint.startsWith("repos/f0rr0/oliphaunt?"))).toBe(true); - }); - - test("fails closed when GraphQL omits the response data", () => { - expectGraphqlCollectionFailure({}, /exact canonical main ref/u); - }); - - test("fails closed when GraphQL omits the main branch-protection rule", () => { - const source = fixture("desired-solo"); - const payload = graphqlPayload(source); - payload.data.repository.ref.branchProtectionRule = null; - expectGraphqlCollectionFailure(payload, /complete main branch-protection rule/u); - }); - - test("fails closed when the force-push bypass collection requires pagination", () => { - const source = fixture("desired-solo"); - const payload = graphqlPayload(source); - payload.data.repository.ref.branchProtectionRule - .bypassForcePushAllowances.pageInfo.hasNextPage = true; - expectGraphqlCollectionFailure(payload, /bypass inventory is incomplete or malformed/u); - }); - - test("fails closed when the force-push bypass total disagrees with its nodes", () => { - const source = fixture("desired-solo"); - const payload = graphqlPayload(source); - payload.data.repository.ref.branchProtectionRule - .bypassForcePushAllowances.totalCount = 1; - expectGraphqlCollectionFailure(payload, /bypass inventory is incomplete or malformed/u); - }); - - test("fails closed when GraphQL returns the wrong repository identity", () => { - const source = fixture("desired-solo"); - const payload = graphqlPayload(source); - payload.data.repository.nameWithOwner = "f0rr0/not-oliphaunt"; - expectGraphqlCollectionFailure(payload, /exact canonical main ref/u); - }); - - test("fails closed when GraphQL returns the wrong ref", () => { - const source = fixture("desired-solo"); - const payload = graphqlPayload(source); - payload.data.repository.ref.name = "release"; - expectGraphqlCollectionFailure(payload, /exact canonical main ref/u); - }); -}); - -describe("GitHub controls audit CLI", () => { - test("defaults to the least-privilege idle bootstrap state", () => { - const directory = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-github-audit-")); - try { - const snapshot = fixture("desired-solo"); - snapshot.environments["release-bootstrap"].secretNames = [...TAG_APP_SECRETS]; - const fixturePath = path.join(directory, "idle.json"); - writeFileSync(fixturePath, JSON.stringify(snapshot)); - const result = spawnSync(process.execPath, [ - TOOL, - "--fixture", - fixturePath, - "--governance", - "solo", - ], { encoding: "utf8" }); - expect(result.status).toBe(0); - expect(result.stdout).toContain("(governance=solo, bootstrap=idle)"); - expect(result.stdout).toContain("Summary:"); - } finally { - rmSync(directory, { force: true, recursive: true }); - } - }); - - test("warnings do not fail the audit process", () => { - const directory = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-github-audit-")); - try { - const snapshot = fixture("desired-solo"); - snapshot.repository.allow_merge_commit = true; - const fixturePath = path.join(directory, "warning.json"); - writeFileSync(fixturePath, JSON.stringify(snapshot)); - const result = spawnSync(process.execPath, [ - TOOL, - "--fixture", - fixturePath, - "--governance", - "solo", - "--bootstrap-state", - "ready", - ], { encoding: "utf8" }); - expect(result.status).toBe(0); - expect(result.stdout).toContain("WARN repository.merge-commit:"); - } finally { - rmSync(directory, { force: true, recursive: true }); - } - }); - - test("hard release-safety findings fail the audit process", () => { - const result = spawnSync(process.execPath, [ - TOOL, - "--fixture", - path.join(FIXTURES, "current-bad.json"), - "--governance", - "solo", - "--bootstrap-state", - "ready", - ], { encoding: "utf8" }); - expect(result.status).toBe(1); - expect(result.stdout).toMatch(/Summary: \d+ PASS, \d+ WARN, [1-9]\d* FAIL/u); - }); -}); diff --git a/tools/release/audit-github-release-controls.test.mts b/tools/release/audit-github-release-controls.test.mts new file mode 100644 index 000000000..4a9ce47b4 --- /dev/null +++ b/tools/release/audit-github-release-controls.test.mts @@ -0,0 +1,388 @@ +import { describe, expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; + +import { + auditGitHubReleaseControls, + collectGitHubReleaseControls, + formatAudit, + githubApiUrl, + summarizeFindings, +} from './audit-github-release-controls.mts'; + +const TAG_APP_SECRETS = ['RELEASE_TAG_APP_CLIENT_ID', 'RELEASE_TAG_APP_PRIVATE_KEY']; + +const FIXTURES = path.join(import.meta.dir, 'fixtures/github-release-controls'); + +function fixture(name) { + return JSON.parse(readFileSync(path.join(FIXTURES, `${name}.json`), 'utf8')); +} + +function graphqlPayload(source) { + return { + data: { + repository: { + nameWithOwner: source.branchProtectionGraphql.nameWithOwner, + ref: { + name: source.branchProtectionGraphql.refName, + branchProtectionRule: structuredClone(source.branchProtectionGraphql.rule), + }, + }, + }, + }; +} + +async function expectGraphqlCollectionFailure(payload, expected) { + const source = fixture('desired-solo'); + const apiGet = (endpoint) => { + if (endpoint === 'repos/f0rr0/oliphaunt') return source.repository; + if (endpoint === 'repos/f0rr0/oliphaunt/branches/main/protection') { + return source.branchProtection; + } + throw new Error(`unexpected endpoint after malformed GraphQL response: ${endpoint}`); + }; + await expect(collectGitHubReleaseControls(apiGet, () => payload)).rejects.toThrow(expected); +} + +describe('GitHub release controls', () => { + test('accepts the desired solo-maintainer controls without team-only ceremony', () => { + const findings = auditGitHubReleaseControls(fixture('desired-solo'), { + bootstrapState: 'ready', + governance: 'solo', + }); + expect(summarizeFindings(findings)).toEqual({ PASS: 39, WARN: 0, FAIL: 0 }); + }); + + test('rejects a solo approval rule that the only collaborator cannot satisfy', () => { + const snapshot = fixture('desired-solo'); + snapshot.branchProtection.required_pull_request_reviews.required_approving_review_count = 1; + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'ready', + governance: 'solo', + }); + const finding = findings.find(({ id }) => id === 'branch.pr-review'); + expect(finding?.status).toBe('FAIL'); + expect(finding?.message).toContain('unmergeable'); + }); + + test('accepts independent review when team governance is available', () => { + const findings = auditGitHubReleaseControls(fixture('desired-team'), { + bootstrapState: 'ready', + governance: 'team', + }); + expect(summarizeFindings(findings)).toEqual({ PASS: 41, WARN: 0, FAIL: 0 }); + }); + + test('classifies the known unsafe configuration as hard failures and hygiene warnings', () => { + const findings = auditGitHubReleaseControls(fixture('current-bad'), { + bootstrapState: 'ready', + governance: 'solo', + }); + const summary = summarizeFindings(findings); + expect(summary.FAIL).toBeGreaterThanOrEqual(8); + expect(summary.WARN).toBeGreaterThanOrEqual(4); + expect(findings.find(({ id }) => id === 'environment.release-bootstrap.exists')?.status).toBe( + 'FAIL', + ); + expect( + findings.find(({ id }) => id === 'environment.release-dry-run.secrets-isolated')?.status, + ).toBe('PASS'); + expect(findings.find(({ id }) => id === 'branch.aggregate-only')?.status).toBe('WARN'); + }); + + test('rejects credentials in the dry-run environment', () => { + const snapshot = fixture('desired-solo'); + snapshot.environments['release-dry-run'].secretNames = ['LEAKED_WRITE_TOKEN']; + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'ready', + governance: 'solo', + }); + expect( + findings.find(({ id }) => id === 'environment.release-dry-run.secrets-isolated')?.status, + ).toBe('FAIL'); + }); + + test('all release environments accept only main', () => { + for (const environmentName of [ + 'release-bootstrap', + 'release-pr', + 'release-dry-run', + 'release-publish', + ]) { + const snapshot = fixture('desired-solo'); + snapshot.environments[environmentName].branchPolicies.push({ + name: 'oliphaunt-release-transport/*', + type: 'tag', + }); + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'ready', + governance: 'solo', + }); + expect( + findings.find(({ id }) => id === `environment.${environmentName}.branch-policy`)?.status, + ).toBe('FAIL'); + } + }); + + test('accepts only the lock-required revocable registry credentials while bootstrap is ready', () => { + for (const token of ['CRATES_IO_BOOTSTRAP_TOKEN', 'NPM_BOOTSTRAP_TOKEN']) { + const snapshot = fixture('desired-solo'); + snapshot.environments['release-bootstrap'].secretNames = [...TAG_APP_SECRETS, token]; + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'ready', + governance: 'solo', + }); + const finding = findings.find( + ({ id }) => id === 'environment.release-bootstrap.secrets-present', + ); + expect(finding?.status).toBe('PASS'); + expect(finding?.message).toContain('at least one approved registry bootstrap token'); + expect(summarizeFindings(findings).FAIL).toBe(0); + } + }); + + test('ready bootstrap mode rejects an empty credential set', () => { + const snapshot = fixture('desired-solo'); + snapshot.environments['release-bootstrap'].secretNames = [...TAG_APP_SECRETS]; + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'ready', + governance: 'solo', + }); + const finding = findings.find( + ({ id }) => id === 'environment.release-bootstrap.secrets-present', + ); + expect(finding?.status).toBe('FAIL'); + expect(finding?.message).toContain('approved lock'); + expect(finding?.message).toContain('CRATES_IO_BOOTSTRAP_TOKEN'); + expect(finding?.message).toContain('NPM_BOOTSTRAP_TOKEN'); + }); + + test('accepts an idle pre-bootstrap environment without long-lived tokens', () => { + const snapshot = fixture('desired-solo'); + snapshot.environments['release-bootstrap'].secretNames = [...TAG_APP_SECRETS]; + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'idle', + governance: 'solo', + }); + expect(summarizeFindings(findings).FAIL).toBe(0); + }); + + test('idle bootstrap mode rejects prematurely installed bootstrap tokens', () => { + const findings = auditGitHubReleaseControls(fixture('desired-solo'), { + bootstrapState: 'idle', + governance: 'solo', + }); + const finding = findings.find( + ({ id }) => id === 'environment.release-bootstrap.secrets-isolated', + ); + expect(finding?.status).toBe('FAIL'); + expect(finding?.message).toContain('CRATES_IO_BOOTSTRAP_TOKEN'); + expect(finding?.message).toContain('NPM_BOOTSTRAP_TOKEN'); + }); + + test('rejects unverifiable crates.io capacity assertions as stale release secrets', () => { + const snapshot = fixture('desired-solo'); + snapshot.environments['release-publish'].secretNames.push('CRATES_IO_VERSION_RUN_CAPACITY'); + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'ready', + governance: 'solo', + }); + expect( + findings.find(({ id }) => id === 'environment.release-publish.secrets-present')?.status, + ).toBe('PASS'); + const isolation = findings.find( + ({ id }) => id === 'environment.release-publish.secrets-isolated', + ); + expect(isolation?.status).toBe('FAIL'); + expect(isolation?.message).toContain('CRATES_IO_VERSION_RUN_CAPACITY'); + }); + + test('does not mistake absent branch protection for disabled mutations', () => { + const snapshot = fixture('desired-solo'); + snapshot.branchProtection = null; + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'ready', + governance: 'solo', + }); + expect(findings.find(({ id }) => id === 'branch.protection')?.status).toBe('FAIL'); + expect(findings.find(({ id }) => id === 'branch.force-push')?.status).toBe('FAIL'); + expect(findings.find(({ id }) => id === 'branch.deletion')?.status).toBe('FAIL'); + }); + + test('rejects an actor-specific force-push bypass hidden from the REST protection flag', () => { + const snapshot = fixture('desired-solo'); + snapshot.branchProtectionGraphql.rule.bypassForcePushAllowances = { + totalCount: 1, + pageInfo: { endCursor: 'cursor-1', hasNextPage: false }, + nodes: [{ id: 'BPFA_test', actor: { __typename: 'User', id: 'U_test', login: 'f0rr0' } }], + }; + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'ready', + governance: 'solo', + }); + expect(findings.find(({ id }) => id === 'branch.force-push')?.status).toBe('PASS'); + expect(findings.find(({ id }) => id === 'branch.force-push-bypass')?.status).toBe('FAIL'); + }); + + test('fails closed when the GraphQL force-push bypass inventory is absent', () => { + const snapshot = fixture('desired-solo'); + delete snapshot.branchProtectionGraphql; + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'ready', + governance: 'solo', + }); + expect(findings.find(({ id }) => id === 'branch.force-push-bypass')?.status).toBe('FAIL'); + }); + + test('retired bootstrap mode requires long-lived bootstrap tokens to be absent', () => { + const snapshot = fixture('desired-solo'); + snapshot.environments['release-bootstrap'].secretNames = [...TAG_APP_SECRETS]; + const findings = auditGitHubReleaseControls(snapshot, { + bootstrapState: 'retired', + governance: 'solo', + }); + expect(summarizeFindings(findings).FAIL).toBe(0); + }); + + test('retired bootstrap mode rejects lingering bootstrap tokens', () => { + const findings = auditGitHubReleaseControls(fixture('desired-solo'), { + bootstrapState: 'retired', + governance: 'solo', + }); + const finding = findings.find( + ({ id }) => id === 'environment.release-bootstrap.secrets-isolated', + ); + expect(finding?.status).toBe('FAIL'); + expect(finding?.message).toContain('CRATES_IO_BOOTSTRAP_TOKEN'); + expect(finding?.message).toContain('NPM_BOOTSTRAP_TOKEN'); + }); + + test('rejects an unknown bootstrap lifecycle state', () => { + expect(() => + auditGitHubReleaseControls(fixture('desired-solo'), { + bootstrapState: 'staged', + governance: 'solo', + }), + ).toThrow(/idle, ready, or retired/u); + }); + + test('formats findings deterministically', () => { + const options = { bootstrapState: 'ready', governance: 'solo' }; + const findings = auditGitHubReleaseControls(fixture('desired-solo'), options); + const first = formatAudit(findings, options); + expect(formatAudit([...findings].reverse(), options)).toBe(first); + }); +}); + +describe('GitHub API snapshot collection', () => { + test('accepts only canonical repository read URLs', async () => { + expect(githubApiUrl('repos/f0rr0/oliphaunt')).toBe( + 'https://api.github.com/repos/f0rr0/oliphaunt', + ); + expect(() => githubApiUrl('repos/another-owner/another-repo')).toThrow( + /refusing non-canonical/u, + ); + expect(() => githubApiUrl('repos/f0rr0/oliphaunt-typo')).toThrow(/refusing non-canonical/u); + }); + + test('uses only the fixed canonical read endpoints', async () => { + const source = fixture('desired-solo'); + const endpoints = []; + const graphReads = []; + const apiGet = (endpoint) => { + endpoints.push(endpoint); + if (endpoint === 'repos/f0rr0/oliphaunt') return source.repository; + if (endpoint === 'repos/f0rr0/oliphaunt/branches/main/protection') + return source.branchProtection; + if (endpoint === 'repos/f0rr0/oliphaunt/actions/permissions/workflow') + return source.actionsWorkflowPermissions; + if (endpoint.startsWith('repos/f0rr0/oliphaunt/environments?')) { + return { + total_count: 4, + environments: Object.values(source.environments).map(({ environment }) => environment), + }; + } + const environmentName = Object.keys(source.environments).find((name) => + endpoint.includes(encodeURIComponent(name)), + ); + if (!environmentName) throw new Error(`unexpected endpoint ${endpoint}`); + if ( + endpoint === `repos/f0rr0/oliphaunt/environments/${encodeURIComponent(environmentName)}` + ) { + return source.environments[environmentName].environment; + } + if (endpoint.includes('deployment-branch-policies')) { + return { + total_count: 1, + branch_policies: source.environments[environmentName].branchPolicies, + }; + } + if (endpoint.includes('/secrets?')) { + const secrets = source.environments[environmentName].secretNames.map((name) => ({ name })); + return { total_count: secrets.length, secrets }; + } + throw new Error(`unexpected endpoint ${endpoint}`); + }; + const graphqlRead = (document, variables) => { + graphReads.push({ document, variables }); + return graphqlPayload(source); + }; + + expect(await collectGitHubReleaseControls(apiGet, graphqlRead)).toEqual(source); + expect(graphReads).toHaveLength(1); + expect(graphReads[0].document).toMatch(/^\s*query OliphauntReleaseBranchProtection/u); + expect(graphReads[0].variables).toEqual({ + name: 'oliphaunt', + owner: 'f0rr0', + qualifiedName: 'refs/heads/main', + }); + expect(endpoints.every((endpoint) => !/[\s]|(^|[?&])method=/u.test(endpoint))).toBe(true); + expect( + endpoints.every( + (endpoint) => + endpoint === 'repos/f0rr0/oliphaunt' || + endpoint.startsWith('repos/f0rr0/oliphaunt/') || + endpoint.startsWith('repos/f0rr0/oliphaunt?'), + ), + ).toBe(true); + }); + + test('fails closed when GraphQL omits the response data', async () => { + await expectGraphqlCollectionFailure({}, /exact canonical main ref/u); + }); + + test('fails closed when GraphQL omits the main branch-protection rule', async () => { + const source = fixture('desired-solo'); + const payload = graphqlPayload(source); + payload.data.repository.ref.branchProtectionRule = null; + await expectGraphqlCollectionFailure(payload, /complete main branch-protection rule/u); + }); + + test('fails closed when the force-push bypass collection requires pagination', async () => { + const source = fixture('desired-solo'); + const payload = graphqlPayload(source); + payload.data.repository.ref.branchProtectionRule.bypassForcePushAllowances.pageInfo.hasNextPage = true; + await expectGraphqlCollectionFailure(payload, /bypass inventory is incomplete or malformed/u); + }); + + test('fails closed when the force-push bypass total disagrees with its nodes', async () => { + const source = fixture('desired-solo'); + const payload = graphqlPayload(source); + payload.data.repository.ref.branchProtectionRule.bypassForcePushAllowances.totalCount = 1; + await expectGraphqlCollectionFailure(payload, /bypass inventory is incomplete or malformed/u); + }); + + test('fails closed when GraphQL returns the wrong repository identity', async () => { + const source = fixture('desired-solo'); + const payload = graphqlPayload(source); + payload.data.repository.nameWithOwner = 'f0rr0/not-oliphaunt'; + await expectGraphqlCollectionFailure(payload, /exact canonical main ref/u); + }); + + test('fails closed when GraphQL returns the wrong ref', async () => { + const source = fixture('desired-solo'); + const payload = graphqlPayload(source); + payload.data.repository.ref.name = 'release'; + await expectGraphqlCollectionFailure(payload, /exact canonical main ref/u); + }); +}); diff --git a/tools/release/audit-github-release-controls.test.sh b/tools/release/audit-github-release-controls.test.sh new file mode 100644 index 000000000..5ff7c1e69 --- /dev/null +++ b/tools/release/audit-github-release-controls.test.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/audit-github-release-controls.test.mts +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +fixtures=tools/release/fixtures/github-release-controls +jq '.environments["release-bootstrap"].secretNames = ["RELEASE_TAG_APP_CLIENT_ID", "RELEASE_TAG_APP_PRIVATE_KEY"]' "$fixtures/desired-solo.json" > "$scratch/idle.json" +bun tools/release/audit-github-release-controls.mts --fixture "$scratch/idle.json" --governance solo > "$scratch/result" +rg -q -F '(governance=solo, bootstrap=idle)' "$scratch/result" +jq '.repository.allow_merge_commit = true' "$fixtures/desired-solo.json" > "$scratch/warning.json" +bun tools/release/audit-github-release-controls.mts --fixture "$scratch/warning.json" --governance solo --bootstrap-state ready > "$scratch/result" +rg -q 'WARN repository.merge-commit:' "$scratch/result" +status=0 +bun tools/release/audit-github-release-controls.mts --fixture "$fixtures/current-bad.json" --governance solo --bootstrap-state ready > "$scratch/result" 2>&1 || status=$? +[[ "$status" == 1 ]] +rg -q 'Summary: [0-9]+ PASS, [0-9]+ WARN, [1-9][0-9]* FAIL' "$scratch/result" +echo 'GitHub controls CLI: idle default, nonblocking warnings and blocking failures passed' diff --git a/tools/release/bootstrap-execution-result.mjs b/tools/release/bootstrap-execution-result.mjs deleted file mode 100644 index d37792a25..000000000 --- a/tools/release/bootstrap-execution-result.mjs +++ /dev/null @@ -1,115 +0,0 @@ -const SCHEMA = "oliphaunt-bootstrap-execution-result-v1"; -const SHA = /^[0-9a-f]{40,64}$/u; -const DIGEST = /^[0-9a-f]{64}$/u; - -function error(message) { - return new Error(`bootstrap-execution-result: ${message}`); -} - -function stable(value) { - if (Array.isArray(value)) return `[${value.map(stable).join(",")}]`; - if (value !== null && typeof value === "object") { - return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stable(value[key])}`).join(",")}}`; - } - return JSON.stringify(value); -} - -function exactKeys(value, keys, context) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(`${context} must be an object`); - } - if (stable(Object.keys(value).sort()) !== stable([...keys].sort())) { - throw error(`${context} keys must be exactly ${[...keys].sort().join(", ")}`); - } -} - -function uniqueStrings(value, context, { ordered = false, nonempty = false } = {}) { - if ( - !Array.isArray(value) - || (nonempty && value.length === 0) - || value.some((item) => typeof item !== "string" || item.length === 0) - || new Set(value).size !== value.length - || (!ordered && stable(value) !== stable([...value].sort())) - ) { - throw error(`${context} must be a ${nonempty ? "nonempty " : ""}unique string list`); - } - return [...value]; -} - -export function validateBootstrapExecutionResult(value, expected = {}) { - exactKeys(value, [ - "admittedIds", "completedIds", "decision", "deferralMode", "lock", "newlyCompletedIds", - "notBeforeEpochSeconds", "operation", "products", "remainingIds", "schema", "source", - ], "execution result"); - if (value.schema !== SCHEMA || value.operation !== "publish-bootstrap") { - throw error("execution result schema or operation is invalid"); - } - if (!new Set(["complete", "deferred"]).has(value.decision)) { - throw error("execution result decision must be complete or deferred"); - } - exactKeys(value.source, ["commit", "tree"], "execution result source"); - if (!SHA.test(value.source.commit) || !SHA.test(value.source.tree)) { - throw error("execution result source must contain lowercase Git object IDs"); - } - exactKeys(value.lock, ["catalogDigest", "lockDigest", "packageEnvelopeDigest"], "execution result lock"); - if (Object.values(value.lock).some((digest) => typeof digest !== "string" || !DIGEST.test(digest))) { - throw error("execution result lock must contain lowercase SHA-256 digests"); - } - const normalized = { - ...value, - products: uniqueStrings(value.products, "execution result products", { nonempty: true }), - admittedIds: uniqueStrings(value.admittedIds, "execution result admittedIds", { ordered: true }), - completedIds: uniqueStrings(value.completedIds, "execution result completedIds", { ordered: true }), - newlyCompletedIds: uniqueStrings(value.newlyCompletedIds, "execution result newlyCompletedIds", { ordered: true }), - remainingIds: uniqueStrings(value.remainingIds, "execution result remainingIds", { ordered: true }), - }; - const completed = new Set(normalized.completedIds); - const remaining = new Set(normalized.remainingIds); - const plan = new Set([...completed, ...remaining]); - if (normalized.admittedIds.some((id) => !plan.has(id))) { - throw error("execution result admittedIds must be a projection of completedIds and remainingIds"); - } - if (normalized.newlyCompletedIds.some((id) => !completed.has(id) || !normalized.admittedIds.includes(id))) { - throw error("execution result newlyCompletedIds must be a subset of completedIds and admittedIds"); - } - if (normalized.completedIds.some((id) => remaining.has(id))) { - throw error("execution result completedIds and remainingIds must be disjoint"); - } - if (normalized.decision === "complete") { - if (normalized.deferralMode !== null || remaining.size !== 0 || normalized.notBeforeEpochSeconds !== null) { - throw error("complete execution result must have no deferral mode, remaining IDs, or not-before time"); - } - } else { - if (remaining.size === 0 || !Number.isSafeInteger(normalized.notBeforeEpochSeconds) || normalized.notBeforeEpochSeconds < 1) { - throw error("deferred execution result requires remaining work and a positive not-before time"); - } - const zeroProgress = normalized.newlyCompletedIds.length === 0; - if (normalized.deferralMode === "progress" && zeroProgress) { - throw error("progress deferral requires nonzero newly completed IDs"); - } - if (normalized.deferralMode === "pre-mutation-capacity" && (!zeroProgress || normalized.admittedIds.length !== 0)) { - throw error("pre-mutation capacity deferral must admit and mutate zero bootstrap operations"); - } - if (normalized.deferralMode === "rate-limit" && (!zeroProgress || !normalized.admittedIds.some((id) => remaining.has(id) && /^(?:carrier:)?cargo:/u.test(id)))) { - throw error("rate-limit deferral requires admitted remaining Cargo work and no new completion"); - } - if (normalized.deferralMode === "pre-mutation-deadline" && (!zeroProgress || !normalized.admittedIds.some((id) => remaining.has(id)))) { - throw error("pre-mutation deadline deferral requires admitted remaining work and no new completion"); - } - if (!["progress", "pre-mutation-capacity", "rate-limit", "pre-mutation-deadline"].includes(normalized.deferralMode)) { - throw error("deferred execution result requires an explicit supported deferral mode"); - } - } - for (const [key, actual] of [["releaseCommit", normalized.source.commit], ["releaseTree", normalized.source.tree]]) { - if (expected[key] !== undefined && String(actual) !== String(expected[key])) { - throw error(`execution result ${key} does not match the bootstrap context`); - } - } - if (expected.lock !== undefined && stable(normalized.lock) !== stable(expected.lock)) { - throw error("execution result lock does not match the bootstrap context"); - } - if (expected.products !== undefined && stable(normalized.products) !== stable(expected.products)) { - throw error("execution result products do not match the bootstrap context"); - } - return normalized; -} diff --git a/tools/release/bootstrap-execution-result.mts b/tools/release/bootstrap-execution-result.mts new file mode 100644 index 000000000..d3773506c --- /dev/null +++ b/tools/release/bootstrap-execution-result.mts @@ -0,0 +1,192 @@ +const SCHEMA = 'oliphaunt-bootstrap-execution-result-v1'; +const SHA = /^[0-9a-f]{40,64}$/u; +const DIGEST = /^[0-9a-f]{64}$/u; + +function error(message) { + return new Error(`bootstrap-execution-result: ${message}`); +} + +function stable(value) { + if (Array.isArray(value)) return `[${value.map(stable).join(',')}]`; + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort() + .map((key) => `${JSON.stringify(key)}:${stable(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +function exactKeys(value, keys, context) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw error(`${context} must be an object`); + } + if (stable(Object.keys(value).sort()) !== stable([...keys].sort())) { + throw error(`${context} keys must be exactly ${[...keys].sort().join(', ')}`); + } +} + +function uniqueStrings(value, context, { ordered = false, nonempty = false } = {}) { + if ( + !Array.isArray(value) || + (nonempty && value.length === 0) || + value.some((item) => typeof item !== 'string' || item.length === 0) || + new Set(value).size !== value.length || + (!ordered && stable(value) !== stable([...value].sort())) + ) { + throw error(`${context} must be a ${nonempty ? 'nonempty ' : ''}unique string list`); + } + return [...value]; +} + +export function validateBootstrapExecutionResult(value, expected = {}) { + exactKeys( + value, + [ + 'admittedIds', + 'completedIds', + 'decision', + 'deferralMode', + 'lock', + 'newlyCompletedIds', + 'notBeforeEpochSeconds', + 'operation', + 'products', + 'remainingIds', + 'schema', + 'source', + ], + 'execution result', + ); + if (value.schema !== SCHEMA || value.operation !== 'publish-bootstrap') { + throw error('execution result schema or operation is invalid'); + } + if (!new Set(['complete', 'deferred']).has(value.decision)) { + throw error('execution result decision must be complete or deferred'); + } + exactKeys(value.source, ['commit', 'tree'], 'execution result source'); + if (!SHA.test(value.source.commit) || !SHA.test(value.source.tree)) { + throw error('execution result source must contain lowercase Git object IDs'); + } + exactKeys( + value.lock, + ['catalogDigest', 'lockDigest', 'packageEnvelopeDigest'], + 'execution result lock', + ); + if ( + Object.values(value.lock).some((digest) => typeof digest !== 'string' || !DIGEST.test(digest)) + ) { + throw error('execution result lock must contain lowercase SHA-256 digests'); + } + const normalized = { + ...value, + products: uniqueStrings(value.products, 'execution result products', { nonempty: true }), + admittedIds: uniqueStrings(value.admittedIds, 'execution result admittedIds', { + ordered: true, + }), + completedIds: uniqueStrings(value.completedIds, 'execution result completedIds', { + ordered: true, + }), + newlyCompletedIds: uniqueStrings( + value.newlyCompletedIds, + 'execution result newlyCompletedIds', + { ordered: true }, + ), + remainingIds: uniqueStrings(value.remainingIds, 'execution result remainingIds', { + ordered: true, + }), + }; + const completed = new Set(normalized.completedIds); + const remaining = new Set(normalized.remainingIds); + const plan = new Set([...completed, ...remaining]); + if (normalized.admittedIds.some((id) => !plan.has(id))) { + throw error( + 'execution result admittedIds must be a projection of completedIds and remainingIds', + ); + } + if ( + normalized.newlyCompletedIds.some( + (id) => !completed.has(id) || !normalized.admittedIds.includes(id), + ) + ) { + throw error( + 'execution result newlyCompletedIds must be a subset of completedIds and admittedIds', + ); + } + if (normalized.completedIds.some((id) => remaining.has(id))) { + throw error('execution result completedIds and remainingIds must be disjoint'); + } + if (normalized.decision === 'complete') { + if ( + normalized.deferralMode !== null || + remaining.size !== 0 || + normalized.notBeforeEpochSeconds !== null + ) { + throw error( + 'complete execution result must have no deferral mode, remaining IDs, or not-before time', + ); + } + } else { + if ( + remaining.size === 0 || + !Number.isSafeInteger(normalized.notBeforeEpochSeconds) || + normalized.notBeforeEpochSeconds < 1 + ) { + throw error( + 'deferred execution result requires remaining work and a positive not-before time', + ); + } + const zeroProgress = normalized.newlyCompletedIds.length === 0; + if (normalized.deferralMode === 'progress' && zeroProgress) { + throw error('progress deferral requires nonzero newly completed IDs'); + } + if ( + normalized.deferralMode === 'pre-mutation-capacity' && + (!zeroProgress || normalized.admittedIds.length !== 0) + ) { + throw error('pre-mutation capacity deferral must admit and mutate zero bootstrap operations'); + } + if ( + normalized.deferralMode === 'rate-limit' && + (!zeroProgress || + !normalized.admittedIds.some((id) => remaining.has(id) && /^(?:carrier:)?cargo:/u.test(id))) + ) { + throw error( + 'rate-limit deferral requires admitted remaining Cargo work and no new completion', + ); + } + if ( + normalized.deferralMode === 'pre-mutation-deadline' && + (!zeroProgress || !normalized.admittedIds.some((id) => remaining.has(id))) + ) { + throw error( + 'pre-mutation deadline deferral requires admitted remaining work and no new completion', + ); + } + if ( + !['progress', 'pre-mutation-capacity', 'rate-limit', 'pre-mutation-deadline'].includes( + normalized.deferralMode, + ) + ) { + throw error('deferred execution result requires an explicit supported deferral mode'); + } + } + for (const [key, actual] of [ + ['releaseCommit', normalized.source.commit], + ['releaseTree', normalized.source.tree], + ]) { + if (expected[key] !== undefined && String(actual) !== String(expected[key])) { + throw error(`execution result ${key} does not match the bootstrap context`); + } + } + if (expected.lock !== undefined && stable(normalized.lock) !== stable(expected.lock)) { + throw error('execution result lock does not match the bootstrap context'); + } + if ( + expected.products !== undefined && + stable(normalized.products) !== stable(expected.products) + ) { + throw error('execution result products do not match the bootstrap context'); + } + return normalized; +} diff --git a/tools/release/bootstrap-execution-result.test.mjs b/tools/release/bootstrap-execution-result.test.mjs deleted file mode 100644 index 105932f70..000000000 --- a/tools/release/bootstrap-execution-result.test.mjs +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import test from "node:test"; - -import { validateBootstrapExecutionResult } from "./bootstrap-execution-result.mjs"; - -const digest = "a".repeat(64); -const deferred = { - schema: "oliphaunt-bootstrap-execution-result-v1", - operation: "publish-bootstrap", - decision: "deferred", - deferralMode: "progress", - source: { commit: "b".repeat(40), tree: "c".repeat(40) }, - lock: { catalogDigest: digest, lockDigest: digest, packageEnvelopeDigest: digest }, - products: ["sdk"], - admittedIds: ["cargo:a", "cargo:b"], - completedIds: ["cargo:a"], - newlyCompletedIds: ["cargo:a"], - remainingIds: ["cargo:b"], - notBeforeEpochSeconds: 1_800_000_000, -}; - -test("bootstrap deferrals preserve a disjoint, lock-bound progress decision", () => { - assert.equal(validateBootstrapExecutionResult(deferred).decision, "deferred"); - assert.throws( - () => validateBootstrapExecutionResult({ ...deferred, completedIds: ["cargo:a", "cargo:b"] }), - /must be disjoint/u, - ); - assert.throws( - () => validateBootstrapExecutionResult({ ...deferred, newlyCompletedIds: [] }), - /requires nonzero newly completed IDs/u, - ); -}); diff --git a/tools/release/bootstrap-execution-result.test.mts b/tools/release/bootstrap-execution-result.test.mts new file mode 100644 index 000000000..62f045618 --- /dev/null +++ b/tools/release/bootstrap-execution-result.test.mts @@ -0,0 +1,34 @@ +#!/usr/bin/env bun + +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { validateBootstrapExecutionResult } from './bootstrap-execution-result.mts'; + +const digest = 'a'.repeat(64); +const deferred = { + schema: 'oliphaunt-bootstrap-execution-result-v1', + operation: 'publish-bootstrap', + decision: 'deferred', + deferralMode: 'progress', + source: { commit: 'b'.repeat(40), tree: 'c'.repeat(40) }, + lock: { catalogDigest: digest, lockDigest: digest, packageEnvelopeDigest: digest }, + products: ['sdk'], + admittedIds: ['cargo:a', 'cargo:b'], + completedIds: ['cargo:a'], + newlyCompletedIds: ['cargo:a'], + remainingIds: ['cargo:b'], + notBeforeEpochSeconds: 1_800_000_000, +}; + +test('bootstrap deferrals preserve a disjoint, lock-bound progress decision', () => { + assert.equal(validateBootstrapExecutionResult(deferred).decision, 'deferred'); + assert.throws( + () => validateBootstrapExecutionResult({ ...deferred, completedIds: ['cargo:a', 'cargo:b'] }), + /must be disjoint/u, + ); + assert.throws( + () => validateBootstrapExecutionResult({ ...deferred, newlyCompletedIds: [] }), + /requires nonzero newly completed IDs/u, + ); +}); diff --git a/tools/release/bootstrap-ledger.mjs b/tools/release/bootstrap-ledger.mjs deleted file mode 100644 index 65dda8872..000000000 --- a/tools/release/bootstrap-ledger.mjs +++ /dev/null @@ -1,437 +0,0 @@ -#!/usr/bin/env bun -import { createHash, randomUUID } from "node:crypto"; -import { - closeSync, - existsSync, - fsyncSync, - linkSync, - mkdirSync, - openSync, - readFileSync, - readdirSync, - statSync, - unlinkSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import process from "node:process"; - -import { loadPublicationLock, lockedCarriers } from "./publication-lock.mjs"; -import { verifyLockedRegistryIntegrity } from "./registry-integrity.mjs"; -import { ROOT, compareText } from "./release-graph.mjs"; - -export const BOOTSTRAP_LEDGER_SCHEMA = "oliphaunt-bootstrap-ledger-checkpoint-v1"; -export const DEFAULT_BOOTSTRAP_LEDGER = path.join(ROOT, "target/release/bootstrap-ledger"); - -function error(message) { - return new Error(`bootstrap-ledger: ${message}`); -} - -function stableJson(value) { - if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`; - if (value !== null && typeof value === "object") { - return `{${Object.keys(value).sort(compareText).map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`; - } - return JSON.stringify(value); -} - -function digest(value) { - return createHash("sha256").update(stableJson(value)).digest("hex"); -} - -function fileDigest(file, algorithm, encoding = "hex") { - return createHash(algorithm).update(readFileSync(file)).digest(encoding); -} - -function assertHash(value, context) { - if (typeof value !== "string" || !/^[0-9a-f]{64}$/u.test(value)) throw error(`${context} must be a lowercase SHA-256 digest`); -} - -function uniqueProducts(products) { - if (!Array.isArray(products) || products.length === 0 || products.some((item) => typeof item !== "string" || item.length === 0)) { - throw error("products must be a non-empty product string list"); - } - const result = [...new Set(products)].sort(compareText); - if (result.length !== products.length) throw error("products must not contain duplicates"); - return result; -} - -function publicationExpectation(carrier) { - if (carrier.artifacts.length !== 1) { - throw error(`${carrier.id} must freeze exactly one registry publication archive`); - } - const artifact = carrier.artifacts[0]; - if (carrier.ecosystem === "cargo") { - if (!artifact.path.endsWith(".crate")) throw error(`${carrier.id} must freeze a .crate archive, not ${artifact.path}`); - return { algorithm: "sha256", digest: artifact.sha256, source: "crates.io-version-checksum" }; - } - if (carrier.ecosystem === "npm") { - if (!artifact.path.endsWith(".tgz")) throw error(`${carrier.id} must freeze an npm .tgz archive, not ${artifact.path}`); - const file = path.resolve(ROOT, artifact.path); - let stat; - try { stat = statSync(file); } catch { throw error(`${carrier.id} locked npm archive is unavailable: ${artifact.path}`); } - if (!stat.isFile() || stat.size !== artifact.size || fileDigest(file, "sha256") !== artifact.sha256) { - throw error(`${carrier.id} local npm archive does not match its frozen byte envelope`); - } - return { algorithm: "sha512", digest: fileDigest(file, "sha512", "base64"), source: "npm-dist-integrity" }; - } - throw error(`${carrier.id} is not a bootstrap Cargo/npm carrier`); -} - -function publicationRows(lock, products) { - const selected = new Set(products); - return lockedCarriers(lock) - .filter((carrier) => selected.has(carrier.product) && ["cargo", "npm"].includes(carrier.ecosystem)) - .map((carrier) => ({ - id: carrier.id, - product: carrier.product, - ecosystem: carrier.ecosystem, - name: carrier.name, - version: carrier.version, - role: carrier.role, - target: carrier.target, - publishOrder: carrier.publishOrder, - artifacts: carrier.artifacts.map(({ sha256, size }) => ({ sha256, size })), - registryExpectation: publicationExpectation(carrier), - })) - .sort((left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id)); -} - -function checkpointBase(lock, products, publicationIds = undefined) { - const selected = uniqueProducts(products); - const known = new Set(lock.products.map((product) => product.id)); - const unknown = selected.filter((product) => !known.has(product)); - if (unknown.length > 0) throw error(`selected products are absent from the publication lock: ${unknown.join(", ")}`); - const allPublications = publicationRows(lock, selected); - if ( - publicationIds !== undefined - && ( - !Array.isArray(publicationIds) - || publicationIds.some((id) => typeof id !== "string" || id.length === 0) - || new Set(publicationIds).size !== publicationIds.length - ) - ) { - throw error("bootstrap publication IDs must be a non-empty unique string list"); - } - const selectedIds = publicationIds === undefined - ? new Set(allPublications.map(({ id }) => id)) - : new Set(publicationIds); - if (selectedIds.size === 0) { - throw error("bootstrap publication IDs must be a non-empty unique string list"); - } - const allIds = new Set(allPublications.map(({ id }) => id)); - const unknownIds = [...selectedIds].filter((id) => !allIds.has(id)).sort(compareText); - if (unknownIds.length > 0) throw error(`bootstrap publication IDs are absent from the selected lock: ${unknownIds.join(", ")}`); - const publications = allPublications.filter(({ id }) => selectedIds.has(id)); - if (publications.length === 0) throw error("selected products have no Cargo or npm publication identities to bootstrap"); - return { - schema: BOOTSTRAP_LEDGER_SCHEMA, - lockDigest: lock.lockDigest, - packageEnvelopeDigest: lock.packageEnvelopeDigest, - catalogDigest: lock.catalogDigest, - source: { commit: lock.source.commit, tree: lock.source.tree }, - products: selected, - publications, - }; -} - -function withoutDigest(checkpoint) { - const copy = structuredClone(checkpoint); - delete copy.checkpointDigest; - return copy; -} - -export function buildBootstrapLedger(lock, products, { - sequence = 0, - previousCheckpointDigest = null, - publicationIds = undefined, - receipts = [], -} = {}) { - const checkpoint = { - ...checkpointBase(lock, products, publicationIds), - sequence, - previousCheckpointDigest, - receipts: [...receipts].sort((left, right) => compareText(left.id, right.id)), - }; - checkpoint.complete = checkpoint.receipts.length === checkpoint.publications.length; - checkpoint.checkpointDigest = digest(checkpoint); - return checkpoint; -} - -function validateReceipt(receipt, publication) { - if (receipt === null || Array.isArray(receipt) || typeof receipt !== "object") throw error("ledger receipt must be an object"); - for (const key of ["id", "product", "ecosystem", "name", "version"]) { - if (receipt[key] !== publication[key]) throw error(`${publication.id} receipt ${key} does not match its frozen publication`); - } - if (stableJson(receipt.lockedArtifacts) !== stableJson(publication.artifacts)) { - throw error(`${publication.id} receipt artifact bytes do not match the frozen publication`); - } - const proof = receipt.registryProof; - const expected = publication.registryExpectation; - if ( - proof === null || Array.isArray(proof) || typeof proof !== "object" - || proof.algorithm !== expected.algorithm - || proof.digest !== expected.digest - || proof.source !== expected.source - || typeof proof.url !== "string" || !/^https?:\/\//u.test(proof.url) - ) { - throw error(`${publication.id} receipt does not prove the frozen archive digest at its registry`); - } -} - -export function validateBootstrapLedger(checkpoint, lock, products) { - if (checkpoint === null || Array.isArray(checkpoint) || typeof checkpoint !== "object") throw error("ledger checkpoint must be an object"); - if (checkpoint.schema !== BOOTSTRAP_LEDGER_SCHEMA) throw error(`ledger schema must be ${BOOTSTRAP_LEDGER_SCHEMA}`); - assertHash(checkpoint.checkpointDigest, "ledger.checkpointDigest"); - if (checkpoint.checkpointDigest !== digest(withoutDigest(checkpoint))) throw error("ledger checkpoint digest mismatch"); - const publicationIds = Array.isArray(checkpoint.publications) - ? checkpoint.publications.map(({ id }) => id) - : []; - const expectedBase = checkpointBase(lock, products, publicationIds); - for (const key of ["schema", "lockDigest", "packageEnvelopeDigest", "catalogDigest", "source", "products", "publications"]) { - if (stableJson(checkpoint[key]) !== stableJson(expectedBase[key])) { - throw error(`ledger ${key} is not bound to the active publication lock/source/package envelope`); - } - } - if (!Number.isSafeInteger(checkpoint.sequence) || checkpoint.sequence < 0) throw error("ledger sequence must be non-negative"); - if (!(checkpoint.previousCheckpointDigest === null || /^[0-9a-f]{64}$/u.test(checkpoint.previousCheckpointDigest))) { - throw error("ledger previousCheckpointDigest is invalid"); - } - if (!Array.isArray(checkpoint.receipts)) throw error("ledger receipts must be a list"); - const byId = new Map(checkpoint.publications.map((publication) => [publication.id, publication])); - const seen = new Set(); - for (const receipt of checkpoint.receipts) { - if (seen.has(receipt?.id) || !byId.has(receipt?.id)) throw error(`ledger has a duplicate or unknown receipt ${String(receipt?.id)}`); - seen.add(receipt.id); - validateReceipt(receipt, byId.get(receipt.id)); - } - if (checkpoint.complete !== (checkpoint.receipts.length === checkpoint.publications.length)) throw error("ledger complete flag is inconsistent"); - return checkpoint; -} - -function checkpointFiles(directory) { - if (!existsSync(directory)) return []; - return readdirSync(directory, { withFileTypes: true }) - .filter((entry) => entry.isFile() && /^checkpoint-[0-9]{6}-[0-9a-f]{64}[.]json$/u.test(entry.name)) - .map((entry) => path.join(directory, entry.name)) - .sort(compareText); -} - -export function loadBootstrapLedger(directory, lock, products, { allowEmpty = false, requireComplete = false } = {}) { - const files = checkpointFiles(directory); - if (files.length === 0) { - if (allowEmpty) return null; - throw error(`bootstrap ledger chain has no checkpoints: ${directory}`); - } - let previous = null; - for (const [index, file] of files.entries()) { - let checkpoint; - try { checkpoint = JSON.parse(readFileSync(file, "utf8")); } catch (cause) { throw error(`cannot read ${file}: ${cause.message}`); } - validateBootstrapLedger(checkpoint, lock, products); - if (checkpoint.sequence !== index || checkpoint.previousCheckpointDigest !== (previous?.checkpointDigest ?? null)) { - throw error(`${file} breaks the immutable checkpoint chain at sequence ${index}`); - } - const expectedName = `checkpoint-${String(index).padStart(6, "0")}-${checkpoint.checkpointDigest}.json`; - if (path.basename(file) !== expectedName) throw error(`${file} name does not match its sequence/digest`); - if (previous !== null) { - const prior = new Map(previous.receipts.map((receipt) => [receipt.id, stableJson(receipt)])); - const current = new Map(checkpoint.receipts.map((receipt) => [receipt.id, stableJson(receipt)])); - for (const [id, bytes] of prior) { - if (current.get(id) !== bytes) throw error(`${file} rewrites or removes immutable receipt ${id}`); - } - } - previous = checkpoint; - } - if (requireComplete && !previous.complete) { - throw error(`bootstrap ledger is incomplete: ${previous.receipts.length}/${previous.publications.length} receipts`); - } - return previous; -} - -function writeCheckpoint(directory, checkpoint) { - mkdirSync(directory, { recursive: true }); - const file = path.join(directory, `checkpoint-${String(checkpoint.sequence).padStart(6, "0")}-${checkpoint.checkpointDigest}.json`); - const temporary = path.join( - directory, - `.${path.basename(file)}.tmp-${process.pid}-${randomUUID()}`, - ); - const body = `${JSON.stringify(checkpoint, null, 2)}\n`; - let descriptor; - try { - try { - descriptor = openSync(temporary, "wx", 0o644); - writeFileSync(descriptor, body); - // The final content-addressed name must never expose bytes that have not - // reached stable storage. A crash before the link can leave only an - // ignored private temp file; a crash after it can expose only the complete - // fsynced inode. - fsyncSync(descriptor); - } finally { - if (descriptor !== undefined) closeSync(descriptor); - } - } catch (cause) { - try { unlinkSync(temporary); } catch {} - throw cause; - } - - let published = false; - try { - try { - // Hard-link publication is atomic and has no replace semantics. Unlike - // rename, it cannot silently overwrite an immutable prior checkpoint. - linkSync(temporary, file); - published = true; - } catch (cause) { - if (cause?.code === "EEXIST") { - throw error(`refusing to overwrite immutable checkpoint ${file}`); - } - throw cause; - } - syncCheckpointDirectory(directory); - } finally { - try { unlinkSync(temporary); } catch {} - // Persist best-effort temp-name cleanup after the final link itself has - // already been made durable. A stale private temp remains harmless because - // checkpoint discovery accepts only canonical final names. - if (published) { - try { syncCheckpointDirectory(directory); } catch {} - } - } - return file; -} - -function syncCheckpointDirectory(directory) { - // The protected bootstrap route runs on Linux, where directory fsync makes - // the new hard-link durable. Windows does not support opening directories for - // fsync through Node; the fsynced inode plus atomic no-replace link remains - // the strongest available local guarantee there. - if (process.platform === "win32") return; - const descriptor = openSync(directory, "r"); - try { - fsyncSync(descriptor); - } finally { - closeSync(descriptor); - } -} - -export function appendBootstrapCheckpoint(directory, lock, products, receipts, { publicationIds = undefined } = {}) { - const previous = loadBootstrapLedger(directory, lock, products, { allowEmpty: true }); - const activePublicationIds = previous?.publications.map(({ id }) => id) ?? publicationIds; - if ( - previous !== null - && publicationIds !== undefined - && stableJson([...publicationIds].sort(compareText)) !== stableJson([...activePublicationIds].sort(compareText)) - ) { - throw error("bootstrap publication scope conflicts with its immutable first checkpoint"); - } - const merged = new Map((previous?.receipts ?? []).map((receipt) => [receipt.id, receipt])); - let added = 0; - for (const receipt of receipts) { - const existing = merged.get(receipt.id); - if (existing !== undefined && stableJson(existing) !== stableJson(receipt)) { - throw error(`registry proof for ${receipt.id} conflicts with its immutable prior checkpoint`); - } - if (existing === undefined) added += 1; - merged.set(receipt.id, receipt); - } - if (previous !== null && added === 0) return previous; - const checkpoint = buildBootstrapLedger(lock, products, { - sequence: previous === null ? 0 : previous.sequence + 1, - previousCheckpointDigest: previous?.checkpointDigest ?? null, - publicationIds: activePublicationIds, - receipts: [...merged.values()], - }); - validateBootstrapLedger(checkpoint, lock, products); - writeCheckpoint(directory, checkpoint); - return checkpoint; -} - -async function reverifyReceipts(checkpoint, lock) { - const observed = await verifyLockedRegistryIntegrity(lock, { carrierIds: checkpoint.receipts.map(({ id }) => id) }); - const actual = new Map(observed.map((receipt) => [receipt.id, stableJson(receipt)])); - for (const receipt of checkpoint.receipts) { - if (actual.get(receipt.id) !== stableJson(receipt)) throw error(`${receipt.id} registry proof changed since its immutable checkpoint`); - } -} - -function parseArgs(argv) { - const command = argv[0]; - let ledger = DEFAULT_BOOTSTRAP_LEDGER; - let lockFile = ""; - let productsJson = ""; - let product = ""; - let ecosystem = ""; - let carrierIdsJson = ""; - let verifyRegistries = false; - for (let index = 1; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--verify-registries" || arg === "--require-complete") { - if (arg === "--verify-registries") verifyRegistries = true; - continue; - } - const value = argv[index + 1] ?? ""; - if (arg === "--ledger") ledger = path.resolve(ROOT, value); - else if (arg === "--lock") lockFile = path.resolve(ROOT, value); - else if (arg === "--products-json") productsJson = value; - else if (arg === "--product") product = value; - else if (arg === "--ecosystem") ecosystem = value; - else if (arg === "--carrier-ids-json") carrierIdsJson = value; - else throw error(`unknown argument ${arg}`); - index += 1; - } - if (!["init", "checkpoint", "seal", "verify"].includes(command) || !lockFile || !productsJson) { - throw error("usage: bootstrap-ledger.mjs --lock FILE --products-json JSON [--ledger DIR] [--product ID --ecosystem cargo|npm | --carrier-ids-json JSON] [--verify-registries]"); - } - let products; - try { products = JSON.parse(productsJson); } catch (cause) { throw error(`--products-json must be valid JSON: ${cause.message}`); } - let carrierIds = []; - if (carrierIdsJson) { - try { carrierIds = JSON.parse(carrierIdsJson); } catch (cause) { throw error(`--carrier-ids-json must be valid JSON: ${cause.message}`); } - if ( - !Array.isArray(carrierIds) - || carrierIds.length === 0 - || carrierIds.some((id) => typeof id !== "string" || id.length === 0) - || new Set(carrierIds).size !== carrierIds.length - ) { - throw error("--carrier-ids-json must be a non-empty unique string list"); - } - } - if (command === "checkpoint") { - const productCheckpoint = Boolean(product) && ["cargo", "npm"].includes(ecosystem) && carrierIds.length === 0; - const carrierCheckpoint = !product && !ecosystem && carrierIds.length > 0; - if (!productCheckpoint && !carrierCheckpoint) { - throw error("checkpoint requires either --product with --ecosystem cargo|npm or --carrier-ids-json"); - } - } - return { command, ledger, lockFile, products, product, ecosystem, carrierIds, verifyRegistries }; -} - -if (import.meta.main) { - try { - const args = parseArgs(Bun.argv.slice(2)); - const lock = loadPublicationLock(args.lockFile); - let checkpoint; - if (args.command === "init") { - checkpoint = loadBootstrapLedger(args.ledger, lock, args.products, { allowEmpty: true }); - if (checkpoint === null) checkpoint = appendBootstrapCheckpoint(args.ledger, lock, args.products, []); - } else if (args.command === "checkpoint") { - const receipts = await verifyLockedRegistryIntegrity(lock, args.carrierIds.length > 0 - ? { carrierIds: args.carrierIds } - : { products: [args.product], ecosystems: [args.ecosystem] }); - checkpoint = appendBootstrapCheckpoint(args.ledger, lock, args.products, receipts); - } else if (args.command === "seal") { - checkpoint = loadBootstrapLedger(args.ledger, lock, args.products); - const expected = checkpoint.publications; - const receipts = await verifyLockedRegistryIntegrity(lock, { carrierIds: expected.map(({ id }) => id) }); - checkpoint = appendBootstrapCheckpoint(args.ledger, lock, args.products, receipts); - loadBootstrapLedger(args.ledger, lock, args.products, { requireComplete: true }); - } else { - checkpoint = loadBootstrapLedger(args.ledger, lock, args.products, { requireComplete: true }); - if (args.verifyRegistries) await reverifyReceipts(checkpoint, lock); - } - console.log(`${args.command} bootstrap checkpoint ${checkpoint.sequence} (${checkpoint.receipts.length}/${checkpoint.publications.length}, ${checkpoint.checkpointDigest})`); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/bootstrap-ledger.mts b/tools/release/bootstrap-ledger.mts new file mode 100644 index 000000000..037b69680 --- /dev/null +++ b/tools/release/bootstrap-ledger.mts @@ -0,0 +1,554 @@ +#!/usr/bin/env bun +import { createHash, randomUUID } from 'node:crypto'; +import { + closeSync, + existsSync, + fsyncSync, + linkSync, + mkdirSync, + openSync, + readFileSync, + readdirSync, + statSync, + unlinkSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; + +import { loadPublicationLock, lockedCarriers } from './publication-lock.mts'; +import { verifyLockedRegistryIntegrity } from './registry-integrity.mts'; +import { ROOT, compareText } from './release-graph.mts'; + +export const BOOTSTRAP_LEDGER_SCHEMA = 'oliphaunt-bootstrap-ledger-checkpoint-v1'; +export const DEFAULT_BOOTSTRAP_LEDGER = path.join(ROOT, 'target/release/bootstrap-ledger'); + +function error(message) { + return new Error(`bootstrap-ledger: ${message}`); +} + +function stableJson(value) { + if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`; + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort(compareText) + .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +function digest(value) { + return createHash('sha256').update(stableJson(value)).digest('hex'); +} + +function fileDigest(file, algorithm, encoding = 'hex') { + return createHash(algorithm).update(readFileSync(file)).digest(encoding); +} + +function assertHash(value, context) { + if (typeof value !== 'string' || !/^[0-9a-f]{64}$/u.test(value)) + throw error(`${context} must be a lowercase SHA-256 digest`); +} + +function uniqueProducts(products) { + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((item) => typeof item !== 'string' || item.length === 0) + ) { + throw error('products must be a non-empty product string list'); + } + const result = [...new Set(products)].sort(compareText); + if (result.length !== products.length) throw error('products must not contain duplicates'); + return result; +} + +function publicationExpectation(carrier) { + if (carrier.artifacts.length !== 1) { + throw error(`${carrier.id} must freeze exactly one registry publication archive`); + } + const artifact = carrier.artifacts[0]; + if (carrier.ecosystem === 'cargo') { + if (!artifact.path.endsWith('.crate')) + throw error(`${carrier.id} must freeze a .crate archive, not ${artifact.path}`); + return { algorithm: 'sha256', digest: artifact.sha256, source: 'crates.io-version-checksum' }; + } + if (carrier.ecosystem === 'npm') { + if (!artifact.path.endsWith('.tgz')) + throw error(`${carrier.id} must freeze an npm .tgz archive, not ${artifact.path}`); + const file = path.resolve(ROOT, artifact.path); + let stat; + try { + stat = statSync(file); + } catch { + throw error(`${carrier.id} locked npm archive is unavailable: ${artifact.path}`); + } + if ( + !stat.isFile() || + stat.size !== artifact.size || + fileDigest(file, 'sha256') !== artifact.sha256 + ) { + throw error(`${carrier.id} local npm archive does not match its frozen byte envelope`); + } + return { + algorithm: 'sha512', + digest: fileDigest(file, 'sha512', 'base64'), + source: 'npm-dist-integrity', + }; + } + throw error(`${carrier.id} is not a bootstrap Cargo/npm carrier`); +} + +function publicationRows(lock, products) { + const selected = new Set(products); + return lockedCarriers(lock) + .filter( + (carrier) => selected.has(carrier.product) && ['cargo', 'npm'].includes(carrier.ecosystem), + ) + .map((carrier) => ({ + id: carrier.id, + product: carrier.product, + ecosystem: carrier.ecosystem, + name: carrier.name, + version: carrier.version, + role: carrier.role, + target: carrier.target, + publishOrder: carrier.publishOrder, + artifacts: carrier.artifacts.map(({ sha256, size }) => ({ sha256, size })), + registryExpectation: publicationExpectation(carrier), + })) + .sort( + (left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id), + ); +} + +function checkpointBase(lock, products, publicationIds = undefined) { + const selected = uniqueProducts(products); + const known = new Set(lock.products.map((product) => product.id)); + const unknown = selected.filter((product) => !known.has(product)); + if (unknown.length > 0) + throw error(`selected products are absent from the publication lock: ${unknown.join(', ')}`); + const allPublications = publicationRows(lock, selected); + if ( + publicationIds !== undefined && + (!Array.isArray(publicationIds) || + publicationIds.some((id) => typeof id !== 'string' || id.length === 0) || + new Set(publicationIds).size !== publicationIds.length) + ) { + throw error('bootstrap publication IDs must be a non-empty unique string list'); + } + const selectedIds = + publicationIds === undefined + ? new Set(allPublications.map(({ id }) => id)) + : new Set(publicationIds); + if (selectedIds.size === 0) { + throw error('bootstrap publication IDs must be a non-empty unique string list'); + } + const allIds = new Set(allPublications.map(({ id }) => id)); + const unknownIds = [...selectedIds].filter((id) => !allIds.has(id)).sort(compareText); + if (unknownIds.length > 0) + throw error( + `bootstrap publication IDs are absent from the selected lock: ${unknownIds.join(', ')}`, + ); + const publications = allPublications.filter(({ id }) => selectedIds.has(id)); + if (publications.length === 0) + throw error('selected products have no Cargo or npm publication identities to bootstrap'); + return { + schema: BOOTSTRAP_LEDGER_SCHEMA, + lockDigest: lock.lockDigest, + packageEnvelopeDigest: lock.packageEnvelopeDigest, + catalogDigest: lock.catalogDigest, + source: { commit: lock.source.commit, tree: lock.source.tree }, + products: selected, + publications, + }; +} + +function withoutDigest(checkpoint) { + const copy = structuredClone(checkpoint); + delete copy.checkpointDigest; + return copy; +} + +export function buildBootstrapLedger( + lock, + products, + { sequence = 0, previousCheckpointDigest = null, publicationIds = undefined, receipts = [] } = {}, +) { + const checkpoint = { + ...checkpointBase(lock, products, publicationIds), + sequence, + previousCheckpointDigest, + receipts: [...receipts].sort((left, right) => compareText(left.id, right.id)), + }; + checkpoint.complete = checkpoint.receipts.length === checkpoint.publications.length; + checkpoint.checkpointDigest = digest(checkpoint); + return checkpoint; +} + +function validateReceipt(receipt, publication) { + if (receipt === null || Array.isArray(receipt) || typeof receipt !== 'object') + throw error('ledger receipt must be an object'); + for (const key of ['id', 'product', 'ecosystem', 'name', 'version']) { + if (receipt[key] !== publication[key]) + throw error(`${publication.id} receipt ${key} does not match its frozen publication`); + } + if (stableJson(receipt.lockedArtifacts) !== stableJson(publication.artifacts)) { + throw error(`${publication.id} receipt artifact bytes do not match the frozen publication`); + } + const proof = receipt.registryProof; + const expected = publication.registryExpectation; + if ( + proof === null || + Array.isArray(proof) || + typeof proof !== 'object' || + proof.algorithm !== expected.algorithm || + proof.digest !== expected.digest || + proof.source !== expected.source || + typeof proof.url !== 'string' || + !/^https?:\/\//u.test(proof.url) + ) { + throw error( + `${publication.id} receipt does not prove the frozen archive digest at its registry`, + ); + } +} + +export function validateBootstrapLedger(checkpoint, lock, products) { + if (checkpoint === null || Array.isArray(checkpoint) || typeof checkpoint !== 'object') + throw error('ledger checkpoint must be an object'); + if (checkpoint.schema !== BOOTSTRAP_LEDGER_SCHEMA) + throw error(`ledger schema must be ${BOOTSTRAP_LEDGER_SCHEMA}`); + assertHash(checkpoint.checkpointDigest, 'ledger.checkpointDigest'); + if (checkpoint.checkpointDigest !== digest(withoutDigest(checkpoint))) + throw error('ledger checkpoint digest mismatch'); + const publicationIds = Array.isArray(checkpoint.publications) + ? checkpoint.publications.map(({ id }) => id) + : []; + const expectedBase = checkpointBase(lock, products, publicationIds); + for (const key of [ + 'schema', + 'lockDigest', + 'packageEnvelopeDigest', + 'catalogDigest', + 'source', + 'products', + 'publications', + ]) { + if (stableJson(checkpoint[key]) !== stableJson(expectedBase[key])) { + throw error( + `ledger ${key} is not bound to the active publication lock/source/package envelope`, + ); + } + } + if (!Number.isSafeInteger(checkpoint.sequence) || checkpoint.sequence < 0) + throw error('ledger sequence must be non-negative'); + if ( + !( + checkpoint.previousCheckpointDigest === null || + /^[0-9a-f]{64}$/u.test(checkpoint.previousCheckpointDigest) + ) + ) { + throw error('ledger previousCheckpointDigest is invalid'); + } + if (!Array.isArray(checkpoint.receipts)) throw error('ledger receipts must be a list'); + const byId = new Map(checkpoint.publications.map((publication) => [publication.id, publication])); + const seen = new Set(); + for (const receipt of checkpoint.receipts) { + if (seen.has(receipt?.id) || !byId.has(receipt?.id)) + throw error(`ledger has a duplicate or unknown receipt ${String(receipt?.id)}`); + seen.add(receipt.id); + validateReceipt(receipt, byId.get(receipt.id)); + } + if (checkpoint.complete !== (checkpoint.receipts.length === checkpoint.publications.length)) + throw error('ledger complete flag is inconsistent'); + return checkpoint; +} + +function checkpointFiles(directory) { + if (!existsSync(directory)) return []; + return readdirSync(directory, { withFileTypes: true }) + .filter( + (entry) => entry.isFile() && /^checkpoint-[0-9]{6}-[0-9a-f]{64}[.]json$/u.test(entry.name), + ) + .map((entry) => path.join(directory, entry.name)) + .sort(compareText); +} + +export function loadBootstrapLedger( + directory, + lock, + products, + { allowEmpty = false, requireComplete = false } = {}, +) { + const files = checkpointFiles(directory); + if (files.length === 0) { + if (allowEmpty) return null; + throw error(`bootstrap ledger chain has no checkpoints: ${directory}`); + } + let previous = null; + for (const [index, file] of files.entries()) { + let checkpoint; + try { + checkpoint = JSON.parse(readFileSync(file, 'utf8')); + } catch (cause) { + throw error(`cannot read ${file}: ${cause.message}`); + } + validateBootstrapLedger(checkpoint, lock, products); + if ( + checkpoint.sequence !== index || + checkpoint.previousCheckpointDigest !== (previous?.checkpointDigest ?? null) + ) { + throw error(`${file} breaks the immutable checkpoint chain at sequence ${index}`); + } + const expectedName = `checkpoint-${String(index).padStart(6, '0')}-${checkpoint.checkpointDigest}.json`; + if (path.basename(file) !== expectedName) + throw error(`${file} name does not match its sequence/digest`); + if (previous !== null) { + const prior = new Map(previous.receipts.map((receipt) => [receipt.id, stableJson(receipt)])); + const current = new Map( + checkpoint.receipts.map((receipt) => [receipt.id, stableJson(receipt)]), + ); + for (const [id, bytes] of prior) { + if (current.get(id) !== bytes) + throw error(`${file} rewrites or removes immutable receipt ${id}`); + } + } + previous = checkpoint; + } + if (requireComplete && !previous.complete) { + throw error( + `bootstrap ledger is incomplete: ${previous.receipts.length}/${previous.publications.length} receipts`, + ); + } + return previous; +} + +function writeCheckpoint(directory, checkpoint) { + mkdirSync(directory, { recursive: true }); + const file = path.join( + directory, + `checkpoint-${String(checkpoint.sequence).padStart(6, '0')}-${checkpoint.checkpointDigest}.json`, + ); + const temporary = path.join( + directory, + `.${path.basename(file)}.tmp-${process.pid}-${randomUUID()}`, + ); + const body = `${JSON.stringify(checkpoint, null, 2)}\n`; + let descriptor; + try { + try { + descriptor = openSync(temporary, 'wx', 0o644); + writeFileSync(descriptor, body); + // The final content-addressed name must never expose bytes that have not + // reached stable storage. A crash before the link can leave only an + // ignored private temp file; a crash after it can expose only the complete + // fsynced inode. + fsyncSync(descriptor); + } finally { + if (descriptor !== undefined) closeSync(descriptor); + } + } catch (cause) { + try { + unlinkSync(temporary); + } catch {} + throw cause; + } + + let published = false; + try { + try { + // Hard-link publication is atomic and has no replace semantics. Unlike + // rename, it cannot silently overwrite an immutable prior checkpoint. + linkSync(temporary, file); + published = true; + } catch (cause) { + if (cause?.code === 'EEXIST') { + throw error(`refusing to overwrite immutable checkpoint ${file}`); + } + throw cause; + } + syncCheckpointDirectory(directory); + } finally { + try { + unlinkSync(temporary); + } catch {} + // Persist best-effort temp-name cleanup after the final link itself has + // already been made durable. A stale private temp remains harmless because + // checkpoint discovery accepts only canonical final names. + if (published) { + try { + syncCheckpointDirectory(directory); + } catch {} + } + } + return file; +} + +function syncCheckpointDirectory(directory) { + // The protected bootstrap route runs on Linux, where directory fsync makes + // the new hard-link durable. Windows does not support opening directories for + // fsync through Node; the fsynced inode plus atomic no-replace link remains + // the strongest available local guarantee there. + if (process.platform === 'win32') return; + const descriptor = openSync(directory, 'r'); + try { + fsyncSync(descriptor); + } finally { + closeSync(descriptor); + } +} + +export function appendBootstrapCheckpoint( + directory, + lock, + products, + receipts, + { publicationIds = undefined } = {}, +) { + const previous = loadBootstrapLedger(directory, lock, products, { allowEmpty: true }); + const activePublicationIds = previous?.publications.map(({ id }) => id) ?? publicationIds; + if ( + previous !== null && + publicationIds !== undefined && + stableJson([...publicationIds].sort(compareText)) !== + stableJson([...activePublicationIds].sort(compareText)) + ) { + throw error('bootstrap publication scope conflicts with its immutable first checkpoint'); + } + const merged = new Map((previous?.receipts ?? []).map((receipt) => [receipt.id, receipt])); + let added = 0; + for (const receipt of receipts) { + const existing = merged.get(receipt.id); + if (existing !== undefined && stableJson(existing) !== stableJson(receipt)) { + throw error(`registry proof for ${receipt.id} conflicts with its immutable prior checkpoint`); + } + if (existing === undefined) added += 1; + merged.set(receipt.id, receipt); + } + if (previous !== null && added === 0) return previous; + const checkpoint = buildBootstrapLedger(lock, products, { + sequence: previous === null ? 0 : previous.sequence + 1, + previousCheckpointDigest: previous?.checkpointDigest ?? null, + publicationIds: activePublicationIds, + receipts: [...merged.values()], + }); + validateBootstrapLedger(checkpoint, lock, products); + writeCheckpoint(directory, checkpoint); + return checkpoint; +} + +async function reverifyReceipts(checkpoint, lock) { + const observed = await verifyLockedRegistryIntegrity(lock, { + carrierIds: checkpoint.receipts.map(({ id }) => id), + }); + const actual = new Map(observed.map((receipt) => [receipt.id, stableJson(receipt)])); + for (const receipt of checkpoint.receipts) { + if (actual.get(receipt.id) !== stableJson(receipt)) + throw error(`${receipt.id} registry proof changed since its immutable checkpoint`); + } +} + +function parseArgs(argv) { + const command = argv[0]; + let ledger = DEFAULT_BOOTSTRAP_LEDGER; + let lockFile = ''; + let productsJson = ''; + let product = ''; + let ecosystem = ''; + let carrierIdsJson = ''; + let verifyRegistries = false; + for (let index = 1; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--verify-registries' || arg === '--require-complete') { + if (arg === '--verify-registries') verifyRegistries = true; + continue; + } + const value = argv[index + 1] ?? ''; + if (arg === '--ledger') ledger = path.resolve(ROOT, value); + else if (arg === '--lock') lockFile = path.resolve(ROOT, value); + else if (arg === '--products-json') productsJson = value; + else if (arg === '--product') product = value; + else if (arg === '--ecosystem') ecosystem = value; + else if (arg === '--carrier-ids-json') carrierIdsJson = value; + else throw error(`unknown argument ${arg}`); + index += 1; + } + if (!['init', 'checkpoint', 'seal', 'verify'].includes(command) || !lockFile || !productsJson) { + throw error( + 'usage: bootstrap-ledger.mts --lock FILE --products-json JSON [--ledger DIR] [--product ID --ecosystem cargo|npm | --carrier-ids-json JSON] [--verify-registries]', + ); + } + let products; + try { + products = JSON.parse(productsJson); + } catch (cause) { + throw error(`--products-json must be valid JSON: ${cause.message}`); + } + let carrierIds = []; + if (carrierIdsJson) { + try { + carrierIds = JSON.parse(carrierIdsJson); + } catch (cause) { + throw error(`--carrier-ids-json must be valid JSON: ${cause.message}`); + } + if ( + !Array.isArray(carrierIds) || + carrierIds.length === 0 || + carrierIds.some((id) => typeof id !== 'string' || id.length === 0) || + new Set(carrierIds).size !== carrierIds.length + ) { + throw error('--carrier-ids-json must be a non-empty unique string list'); + } + } + if (command === 'checkpoint') { + const productCheckpoint = + Boolean(product) && ['cargo', 'npm'].includes(ecosystem) && carrierIds.length === 0; + const carrierCheckpoint = !product && !ecosystem && carrierIds.length > 0; + if (!productCheckpoint && !carrierCheckpoint) { + throw error( + 'checkpoint requires either --product with --ecosystem cargo|npm or --carrier-ids-json', + ); + } + } + return { command, ledger, lockFile, products, product, ecosystem, carrierIds, verifyRegistries }; +} + +if (import.meta.main) { + try { + const args = parseArgs(Bun.argv.slice(2)); + const lock = loadPublicationLock(args.lockFile); + let checkpoint; + if (args.command === 'init') { + checkpoint = loadBootstrapLedger(args.ledger, lock, args.products, { allowEmpty: true }); + if (checkpoint === null) + checkpoint = appendBootstrapCheckpoint(args.ledger, lock, args.products, []); + } else if (args.command === 'checkpoint') { + const receipts = await verifyLockedRegistryIntegrity( + lock, + args.carrierIds.length > 0 + ? { carrierIds: args.carrierIds } + : { products: [args.product], ecosystems: [args.ecosystem] }, + ); + checkpoint = appendBootstrapCheckpoint(args.ledger, lock, args.products, receipts); + } else if (args.command === 'seal') { + checkpoint = loadBootstrapLedger(args.ledger, lock, args.products); + const expected = checkpoint.publications; + const receipts = await verifyLockedRegistryIntegrity(lock, { + carrierIds: expected.map(({ id }) => id), + }); + checkpoint = appendBootstrapCheckpoint(args.ledger, lock, args.products, receipts); + loadBootstrapLedger(args.ledger, lock, args.products, { requireComplete: true }); + } else { + checkpoint = loadBootstrapLedger(args.ledger, lock, args.products, { requireComplete: true }); + if (args.verifyRegistries) await reverifyReceipts(checkpoint, lock); + } + console.log( + `${args.command} bootstrap checkpoint ${checkpoint.sequence} (${checkpoint.receipts.length}/${checkpoint.publications.length}, ${checkpoint.checkpointDigest})`, + ); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/bootstrap-ledger.test.mjs b/tools/release/bootstrap-ledger.test.mjs deleted file mode 100644 index a211f955a..000000000 --- a/tools/release/bootstrap-ledger.test.mjs +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { mkdirSync, mkdtempSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { - BOOTSTRAP_LEDGER_SCHEMA, - appendBootstrapCheckpoint, - buildBootstrapLedger, - loadBootstrapLedger, - validateBootstrapLedger, -} from "./bootstrap-ledger.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const hash = (bytes, algorithm, encoding = "hex") => createHash(algorithm).update(bytes).digest(encoding); -const fixedHash = (character) => character.repeat(64); - -test("immutable checkpoints resume 417 Cargo plus 214 npm identities and reject registry-byte conflicts", () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "bootstrap-ledger-test-")); - try { - const crateBytes = Buffer.from("shared exact crate fixture\n"); - const npmBytes = Buffer.from("shared exact npm fixture\n"); - const crateFile = path.join(root, "fixture.crate"); - const npmFile = path.join(root, "fixture.tgz"); - writeFileSync(crateFile, crateBytes); - writeFileSync(npmFile, npmBytes); - const carriers = []; - for (let index = 0; index < 417; index += 1) { - carriers.push({ - id: `cargo:fixture-${index}`, - product: "alpha", - ecosystem: "cargo", - name: `fixture-${index}`, - version: "1.2.3", - role: "platform-leaf", - target: `target-${index}`, - publishOrder: index, - artifacts: [{ path: path.relative(ROOT, crateFile), sha256: hash(crateBytes, "sha256"), size: statSync(crateFile).size }], - }); - } - for (let index = 0; index < 214; index += 1) { - carriers.push({ - id: `npm:@example/fixture-${index}`, - product: "alpha", - ecosystem: "npm", - name: `@example/fixture-${index}`, - version: "1.2.3", - role: "platform-leaf", - target: `target-${index}`, - publishOrder: 417 + index, - artifacts: [{ path: path.relative(ROOT, npmFile), sha256: hash(npmBytes, "sha256"), size: statSync(npmFile).size }], - }); - } - const lock = { - lockDigest: fixedHash("a"), - packageEnvelopeDigest: fixedHash("b"), - catalogDigest: fixedHash("c"), - source: { commit: "1".repeat(40), tree: "2".repeat(40) }, - products: [{ id: "alpha" }], - carriers, - }; - const template = buildBootstrapLedger(lock, ["alpha"]); - assert.equal(template.schema, BOOTSTRAP_LEDGER_SCHEMA); - assert.equal(template.publications.length, 631); - const receipts = template.publications.map((publication) => ({ - id: publication.id, - product: publication.product, - ecosystem: publication.ecosystem, - name: publication.name, - version: publication.version, - lockedArtifacts: publication.artifacts, - registryProof: { - ...publication.registryExpectation, - url: `https://registry.example.invalid/${encodeURIComponent(publication.name)}/${publication.version}`, - }, - })); - - const scopedIds = template.publications.slice(-2).map(({ id }) => id); - const scoped = buildBootstrapLedger(lock, ["alpha"], { publicationIds: scopedIds }); - assert.deepEqual(scoped.publications.map(({ id }) => id), scopedIds); - assert.equal(validateBootstrapLedger(scoped, lock, ["alpha"]), scoped); - assert.throws( - () => buildBootstrapLedger(lock, ["alpha"], { publicationIds: ["npm:@example/absent"] }), - /absent from the selected lock/u, - ); - const scopedChain = path.join(root, "scoped-chain"); - appendBootstrapCheckpoint(scopedChain, lock, ["alpha"], [], { publicationIds: scopedIds }); - assert.throws( - () => appendBootstrapCheckpoint(scopedChain, lock, ["alpha"], [], { - publicationIds: [template.publications[0].id], - }), - /scope conflicts with its immutable first checkpoint/u, - ); - const scopedReceipts = receipts.filter(({ id }) => scopedIds.includes(id)); - appendBootstrapCheckpoint(scopedChain, lock, ["alpha"], scopedReceipts); - assert.equal( - loadBootstrapLedger(scopedChain, lock, ["alpha"], { requireComplete: true }).receipts.length, - scopedIds.length, - ); - - const chain = path.join(root, "chain"); - const genesis = appendBootstrapCheckpoint(chain, lock, ["alpha"], []); - assert.equal(genesis.sequence, 0); - assert.equal(genesis.complete, false); - assert.deepEqual( - readdirSync(chain).filter((name) => name.includes(".tmp-")), - [], - "successful checkpoint publication must remove its private temp name", - ); - - // Model termination after a private temp write but before atomic link - // publication. Discovery must ignore the partial bytes, preserve the last - // valid checkpoint, and allow the next append to recover normally. - const abandonedTemp = path.join( - chain, - `.checkpoint-000001-${fixedHash("f")}.json.tmp-crashed-writer`, - ); - writeFileSync(abandonedTemp, '{"schema":"partial'); - assert.equal(loadBootstrapLedger(chain, lock, ["alpha"]).checkpointDigest, genesis.checkpointDigest); - const interrupted = appendBootstrapCheckpoint(chain, lock, ["alpha"], receipts.slice(0, 271)); - assert.equal(interrupted.receipts.length, 271); - assert.equal(statSync(abandonedTemp).isFile(), true); - const resumed = loadBootstrapLedger(chain, lock, ["alpha"]); - assert.equal(resumed.checkpointDigest, interrupted.checkpointDigest); - const complete = appendBootstrapCheckpoint(chain, lock, ["alpha"], receipts.slice(271)); - assert.equal(complete.sequence, 2); - assert.equal(complete.receipts.length, 631); - assert.equal(complete.complete, true); - assert.equal(loadBootstrapLedger(chain, lock, ["alpha"], { requireComplete: true }).checkpointDigest, complete.checkpointDigest); - assert.equal(validateBootstrapLedger(complete, lock, ["alpha"]), complete); - - const conflicting = structuredClone(receipts[0]); - conflicting.registryProof.digest = conflicting.ecosystem === "cargo" ? fixedHash("9") : Buffer.alloc(64).toString("base64"); - assert.throws( - () => appendBootstrapCheckpoint(chain, lock, ["alpha"], [conflicting]), - /conflicts with its immutable prior checkpoint/u, - ); - - const tamperedChain = structuredClone(complete); - tamperedChain.receipts[0].registryProof.digest = fixedHash("8"); - assert.throws(() => validateBootstrapLedger(tamperedChain, lock, ["alpha"]), /digest mismatch/u); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/bootstrap-ledger.test.mts b/tools/release/bootstrap-ledger.test.mts new file mode 100644 index 000000000..8240a0338 --- /dev/null +++ b/tools/release/bootstrap-ledger.test.mts @@ -0,0 +1,175 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import test from 'node:test'; + +import { + BOOTSTRAP_LEDGER_SCHEMA, + appendBootstrapCheckpoint, + buildBootstrapLedger, + loadBootstrapLedger, + validateBootstrapLedger, +} from './bootstrap-ledger.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); +const hash = (bytes, algorithm, encoding = 'hex') => + createHash(algorithm).update(bytes).digest(encoding); +const fixedHash = (character) => character.repeat(64); + +test('immutable checkpoints resume 417 Cargo plus 214 npm identities and reject registry-byte conflicts', () => { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target', 'bootstrap-ledger-test-')); + try { + const crateBytes = Buffer.from('shared exact crate fixture\n'); + const npmBytes = Buffer.from('shared exact npm fixture\n'); + const crateFile = path.join(root, 'fixture.crate'); + const npmFile = path.join(root, 'fixture.tgz'); + writeFileSync(crateFile, crateBytes); + writeFileSync(npmFile, npmBytes); + const carriers = []; + for (let index = 0; index < 417; index += 1) { + carriers.push({ + id: `cargo:fixture-${index}`, + product: 'alpha', + ecosystem: 'cargo', + name: `fixture-${index}`, + version: '1.2.3', + role: 'platform-leaf', + target: `target-${index}`, + publishOrder: index, + artifacts: [ + { + path: path.relative(ROOT, crateFile), + sha256: hash(crateBytes, 'sha256'), + size: statSync(crateFile).size, + }, + ], + }); + } + for (let index = 0; index < 214; index += 1) { + carriers.push({ + id: `npm:@example/fixture-${index}`, + product: 'alpha', + ecosystem: 'npm', + name: `@example/fixture-${index}`, + version: '1.2.3', + role: 'platform-leaf', + target: `target-${index}`, + publishOrder: 417 + index, + artifacts: [ + { + path: path.relative(ROOT, npmFile), + sha256: hash(npmBytes, 'sha256'), + size: statSync(npmFile).size, + }, + ], + }); + } + const lock = { + lockDigest: fixedHash('a'), + packageEnvelopeDigest: fixedHash('b'), + catalogDigest: fixedHash('c'), + source: { commit: '1'.repeat(40), tree: '2'.repeat(40) }, + products: [{ id: 'alpha' }], + carriers, + }; + const template = buildBootstrapLedger(lock, ['alpha']); + assert.equal(template.schema, BOOTSTRAP_LEDGER_SCHEMA); + assert.equal(template.publications.length, 631); + const receipts = template.publications.map((publication) => ({ + id: publication.id, + product: publication.product, + ecosystem: publication.ecosystem, + name: publication.name, + version: publication.version, + lockedArtifacts: publication.artifacts, + registryProof: { + ...publication.registryExpectation, + url: `https://registry.example.invalid/${encodeURIComponent(publication.name)}/${publication.version}`, + }, + })); + + const scopedIds = template.publications.slice(-2).map(({ id }) => id); + const scoped = buildBootstrapLedger(lock, ['alpha'], { publicationIds: scopedIds }); + assert.deepEqual( + scoped.publications.map(({ id }) => id), + scopedIds, + ); + assert.equal(validateBootstrapLedger(scoped, lock, ['alpha']), scoped); + assert.throws( + () => buildBootstrapLedger(lock, ['alpha'], { publicationIds: ['npm:@example/absent'] }), + /absent from the selected lock/u, + ); + const scopedChain = path.join(root, 'scoped-chain'); + appendBootstrapCheckpoint(scopedChain, lock, ['alpha'], [], { publicationIds: scopedIds }); + assert.throws( + () => + appendBootstrapCheckpoint(scopedChain, lock, ['alpha'], [], { + publicationIds: [template.publications[0].id], + }), + /scope conflicts with its immutable first checkpoint/u, + ); + const scopedReceipts = receipts.filter(({ id }) => scopedIds.includes(id)); + appendBootstrapCheckpoint(scopedChain, lock, ['alpha'], scopedReceipts); + assert.equal( + loadBootstrapLedger(scopedChain, lock, ['alpha'], { requireComplete: true }).receipts.length, + scopedIds.length, + ); + + const chain = path.join(root, 'chain'); + const genesis = appendBootstrapCheckpoint(chain, lock, ['alpha'], []); + assert.equal(genesis.sequence, 0); + assert.equal(genesis.complete, false); + assert.deepEqual( + readdirSync(chain).filter((name) => name.includes('.tmp-')), + [], + 'successful checkpoint publication must remove its private temp name', + ); + + // Model termination after a private temp write but before atomic link + // publication. Discovery must ignore the partial bytes, preserve the last + // valid checkpoint, and allow the next append to recover normally. + const abandonedTemp = path.join( + chain, + `.checkpoint-000001-${fixedHash('f')}.json.tmp-crashed-writer`, + ); + writeFileSync(abandonedTemp, '{"schema":"partial'); + assert.equal( + loadBootstrapLedger(chain, lock, ['alpha']).checkpointDigest, + genesis.checkpointDigest, + ); + const interrupted = appendBootstrapCheckpoint(chain, lock, ['alpha'], receipts.slice(0, 271)); + assert.equal(interrupted.receipts.length, 271); + assert.equal(statSync(abandonedTemp).isFile(), true); + const resumed = loadBootstrapLedger(chain, lock, ['alpha']); + assert.equal(resumed.checkpointDigest, interrupted.checkpointDigest); + const complete = appendBootstrapCheckpoint(chain, lock, ['alpha'], receipts.slice(271)); + assert.equal(complete.sequence, 2); + assert.equal(complete.receipts.length, 631); + assert.equal(complete.complete, true); + assert.equal( + loadBootstrapLedger(chain, lock, ['alpha'], { requireComplete: true }).checkpointDigest, + complete.checkpointDigest, + ); + assert.equal(validateBootstrapLedger(complete, lock, ['alpha']), complete); + + const conflicting = structuredClone(receipts[0]); + conflicting.registryProof.digest = + conflicting.ecosystem === 'cargo' ? fixedHash('9') : Buffer.alloc(64).toString('base64'); + assert.throws( + () => appendBootstrapCheckpoint(chain, lock, ['alpha'], [conflicting]), + /conflicts with its immutable prior checkpoint/u, + ); + + const tamperedChain = structuredClone(complete); + tamperedChain.receipts[0].registryProof.digest = fixedHash('8'); + assert.throws( + () => validateBootstrapLedger(tamperedChain, lock, ['alpha']), + /digest mismatch/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/tools/release/bootstrap-publication-capsule.mjs b/tools/release/bootstrap-publication-capsule.mjs deleted file mode 100644 index e694e7078..000000000 --- a/tools/release/bootstrap-publication-capsule.mjs +++ /dev/null @@ -1,686 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { - closeSync, - constants, - existsSync, - fsyncSync, - fstatSync, - lstatSync, - mkdirSync, - mkdtempSync, - openSync, - readFileSync, - readSync, - renameSync, - rmSync, - statSync, - writeSync, -} from "node:fs"; -import path from "node:path"; -import process from "node:process"; -import { TextDecoder } from "node:util"; - -import { - assertPublicationLockSource, - loadPublicationLock, - lockedPublicationFiles, -} from "./publication-lock.mjs"; -import { ROOT, compareText } from "./release-graph.mjs"; - -export const PUBLICATION_CANDIDATE_SCHEMA = "oliphaunt-frozen-publication-candidate-v1"; -export const PUBLICATION_CANDIDATE_MANIFEST_PATH = "target/release/publication-candidate-manifest.json"; -export const PUBLICATION_CANDIDATE_LOCK_PATH = "target/release/publication-lock.json"; - -const BLOCK_SIZE = 512; -const END_MARKER_SIZE = BLOCK_SIZE * 2; -const COPY_BUFFER_SIZE = 1024 * 1024; -const MAX_METADATA_BYTES = 64 * 1024 * 1024; -const MAX_ARCHIVE_ENTRIES = 10_000; -const UTF8 = new TextDecoder("utf-8", { fatal: true }); - -function error(message) { - return new Error(`bootstrap-publication-capsule: ${message}`); -} - -function stableJson(value) { - if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`; - if (value !== null && typeof value === "object") { - return `{${Object.keys(value).sort(compareText).map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`; - } - return JSON.stringify(value); -} - -function canonicalJson(value) { - return `${JSON.stringify(value, null, 2)}\n`; -} - -function sha256(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function safeProducts(raw) { - let products = raw; - if (typeof raw === "string") { - try { - products = JSON.parse(raw); - } catch (cause) { - throw error(`products JSON is invalid: ${cause.message}`); - } - } - if ( - !Array.isArray(products) - || products.length === 0 - || products.some((product) => typeof product !== "string" || product.length === 0) - || new Set(products).size !== products.length - ) { - throw error("products must be a non-empty unique string list"); - } - return products.slice().sort(compareText); -} - -function safeArchivePath(value, context) { - if ( - typeof value !== "string" - || value.length === 0 - || value.includes("\\") - || /[\u0000-\u001f\u007f]/u.test(value) - || value.normalize("NFC") !== value - || value.startsWith("/") - || value.endsWith("/") - ) { - throw error(`${context} is not a canonical relative POSIX file path: ${JSON.stringify(value)}`); - } - const components = value.split("/"); - if (components.some((component) => component === "" || component === "." || component === "..")) { - throw error(`${context} contains an unsafe path component: ${value}`); - } - if (components[0] !== "target") { - throw error(`${context} must remain under target/: ${value}`); - } - return value; -} - -function workspaceFile(root, relative, context) { - const safe = safeArchivePath(relative, context); - const file = path.resolve(root, ...safe.split("/")); - const resolvedRoot = path.resolve(root); - const within = path.relative(resolvedRoot, file); - if (within.startsWith(`..${path.sep}`) || path.isAbsolute(within)) { - throw error(`${context} escapes its workspace: ${relative}`); - } - return file; -} - -function regularFileStat(file, context, maximum = Number.MAX_SAFE_INTEGER) { - let stat; - try { - stat = lstatSync(file); - } catch (cause) { - throw error(`${context} is unavailable: ${cause.message}`); - } - if (stat.isSymbolicLink() || !stat.isFile()) { - throw error(`${context} must be a regular non-symlink file`); - } - if (!Number.isSafeInteger(stat.size) || stat.size < 0 || stat.size > maximum) { - throw error(`${context} has an unsupported size ${stat.size}`); - } - return stat; -} - -function openRegularNoFollow(file, context) { - const noFollow = constants.O_NOFOLLOW ?? 0; - let descriptor; - try { - descriptor = openSync(file, constants.O_RDONLY | noFollow); - } catch (cause) { - throw error(`cannot open ${context} safely: ${cause.message}`); - } - const stat = fstatSync(descriptor); - if (!stat.isFile()) { - closeSync(descriptor); - throw error(`${context} must remain a regular file while it is read`); - } - return { descriptor, stat }; -} - -function readMetadataFile(file, context) { - const stat = regularFileStat(file, context, MAX_METADATA_BYTES); - const bytes = readFileSync(file); - if (bytes.length !== stat.size) throw error(`${context} changed while it was read`); - return bytes; -} - -function hashRegularFile(file, context, expectedSize = undefined) { - const { descriptor, stat } = openRegularNoFollow(file, context); - try { - if (expectedSize !== undefined && stat.size !== expectedSize) { - throw error(`${context} size ${stat.size} does not match the frozen size ${expectedSize}`); - } - const hash = createHash("sha256"); - const buffer = Buffer.allocUnsafe(COPY_BUFFER_SIZE); - let position = 0; - for (;;) { - const count = readSync(descriptor, buffer, 0, buffer.length, position); - if (count === 0) break; - hash.update(buffer.subarray(0, count)); - position += count; - } - const finalStat = fstatSync(descriptor); - if (position !== stat.size || finalStat.size !== stat.size) { - throw error(`${context} changed while it was hashed`); - } - return { size: stat.size, sha256: hash.digest("hex") }; - } finally { - closeSync(descriptor); - } -} - -function sameStrings(left, right) { - return stableJson(left.slice().sort(compareText)) === stableJson(right.slice().sort(compareText)); -} - -function assertSelectedProducts(lock, products) { - const selectedProducts = safeProducts(products); - const lockedProducts = lock.products.map(({ id }) => id).sort(compareText); - if (!sameStrings(selectedProducts, lockedProducts)) { - throw error( - `selected products do not exactly match the approved lock: selected=${JSON.stringify(selectedProducts)}, lock=${JSON.stringify(lockedProducts)}`, - ); - } - return selectedProducts; -} - -function safeRunId(value, context) { - const runId = String(value); - if (!/^[1-9][0-9]*$/u.test(runId)) throw error(`${context} must be a positive integer`); - return runId; -} - -function expectedManifest(lock, products, lockBytes, workspaceRoot, approvalRunId, qualificationRunId) { - const selectedProducts = assertSelectedProducts(lock, products); - const lockFile = { - path: PUBLICATION_CANDIDATE_LOCK_PATH, - size: lockBytes.length, - sha256: sha256(lockBytes), - }; - return { - schema: PUBLICATION_CANDIDATE_SCHEMA, - source: { - commit: lock.source.commit, - tree: lock.source.tree, - }, - approval: { - releaseRunId: safeRunId(approvalRunId, "approval run ID"), - qualificationRunId: safeRunId(qualificationRunId, "qualification run ID"), - }, - lockDigest: lock.lockDigest, - packageEnvelopeDigest: lock.packageEnvelopeDigest, - catalogDigest: lock.catalogDigest, - products: selectedProducts, - publicationLock: lockFile, - files: lockedPublicationFiles(lock, { products: selectedProducts, workspaceRoot }), - }; -} - -function verifyCandidateFiles(manifest, workspaceRoot) { - for (const artifact of manifest.files) { - const file = workspaceFile(workspaceRoot, artifact.path, "frozen candidate file path"); - const observed = hashRegularFile(file, artifact.path, artifact.size); - if (observed.sha256 !== artifact.sha256) { - throw error(`${artifact.path} bytes do not match the approved publication lock`); - } - } -} - -function tarPathParts(relative) { - const bytes = Buffer.byteLength(relative); - if (bytes <= 100) return { name: relative, prefix: "" }; - const components = relative.split("/"); - for (let index = 1; index < components.length; index += 1) { - const prefix = components.slice(0, index).join("/"); - const name = components.slice(index).join("/"); - if (name.length > 0 && Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) { - return { name, prefix }; - } - } - throw error(`archive path is too long for canonical ustar: ${relative}`); -} - -function writeString(buffer, offset, length, value, context) { - const bytes = Buffer.from(value, "utf8"); - if (bytes.length > length) throw error(`${context} exceeds its ustar field`); - bytes.copy(buffer, offset); -} - -function writeOctal(buffer, offset, length, value, context) { - if (!Number.isSafeInteger(value) || value < 0) throw error(`${context} is not a safe non-negative integer`); - const text = value.toString(8); - if (text.length > length - 1) throw error(`${context} exceeds its ustar field`); - writeString(buffer, offset, length, `${text.padStart(length - 1, "0")}\0`, context); -} - -function tarHeader(relative, size) { - const safe = safeArchivePath(relative, "archive member path"); - const { name, prefix } = tarPathParts(safe); - const header = Buffer.alloc(BLOCK_SIZE, 0); - writeString(header, 0, 100, name, `${safe} name`); - writeOctal(header, 100, 8, 0o644, `${safe} mode`); - writeOctal(header, 108, 8, 0, `${safe} uid`); - writeOctal(header, 116, 8, 0, `${safe} gid`); - writeOctal(header, 124, 12, size, `${safe} size`); - writeOctal(header, 136, 12, 0, `${safe} mtime`); - header.fill(0x20, 148, 156); - writeString(header, 156, 1, "0", `${safe} type`); - writeString(header, 257, 6, "ustar\0", `${safe} magic`); - writeString(header, 263, 2, "00", `${safe} version`); - writeString(header, 345, 155, prefix, `${safe} prefix`); - let checksum = 0; - for (const byte of header) checksum += byte; - const checksumText = checksum.toString(8); - if (checksumText.length > 6) throw error(`${safe} ustar checksum exceeds its field`); - writeString(header, 148, 8, `${checksumText.padStart(6, "0")}\0 `, `${safe} checksum`); - return header; -} - -function writeAll(descriptor, bytes) { - let offset = 0; - while (offset < bytes.length) { - offset += writeSync(descriptor, bytes, offset, bytes.length - offset); - } -} - -function copyFileIntoTar(output, source, expected) { - const { descriptor, stat } = openRegularNoFollow(source, expected.path); - try { - if (stat.size !== expected.size) { - throw error(`${expected.path} size changed before capsule creation`); - } - const hash = createHash("sha256"); - const buffer = Buffer.allocUnsafe(COPY_BUFFER_SIZE); - let position = 0; - while (position < expected.size) { - const count = readSync( - descriptor, - buffer, - 0, - Math.min(buffer.length, expected.size - position), - position, - ); - if (count === 0) throw error(`${expected.path} was truncated during capsule creation`); - const bytes = buffer.subarray(0, count); - hash.update(bytes); - writeAll(output, bytes); - position += count; - } - const finalStat = fstatSync(descriptor); - if (finalStat.size !== stat.size || hash.digest("hex") !== expected.sha256) { - throw error(`${expected.path} changed or differs from the approved publication lock`); - } - } finally { - closeSync(descriptor); - } -} - -function atomicTar(output, entries) { - const destination = path.resolve(output); - mkdirSync(path.dirname(destination), { recursive: true }); - if (existsSync(destination)) throw error(`refusing to overwrite existing capsule ${destination}`); - const temporaryRoot = mkdtempSync(path.join(path.dirname(destination), ".publication-candidate-pack-")); - const temporary = path.join(temporaryRoot, "capsule.tar"); - let descriptor; - try { - descriptor = openSync(temporary, "wx", 0o600); - for (const entry of entries) { - writeAll(descriptor, tarHeader(entry.path, entry.size)); - if (entry.bytes !== undefined) { - writeAll(descriptor, entry.bytes); - } else { - copyFileIntoTar(descriptor, entry.source, entry); - } - const remainder = entry.size % BLOCK_SIZE; - if (remainder !== 0) writeAll(descriptor, Buffer.alloc(BLOCK_SIZE - remainder, 0)); - } - writeAll(descriptor, Buffer.alloc(END_MARKER_SIZE, 0)); - fsyncSync(descriptor); - closeSync(descriptor); - descriptor = undefined; - renameSync(temporary, destination); - } finally { - if (descriptor !== undefined) closeSync(descriptor); - rmSync(temporaryRoot, { recursive: true, force: true }); - } -} - -function capsuleEntries(lock, products, lockBytes, workspaceRoot, approvalRunId, qualificationRunId) { - const manifest = expectedManifest( - lock, - products, - lockBytes, - workspaceRoot, - approvalRunId, - qualificationRunId, - ); - verifyCandidateFiles(manifest, workspaceRoot); - const manifestBytes = Buffer.from(canonicalJson(manifest)); - const entries = [ - { - path: PUBLICATION_CANDIDATE_MANIFEST_PATH, - size: manifestBytes.length, - sha256: sha256(manifestBytes), - bytes: manifestBytes, - }, - { - path: PUBLICATION_CANDIDATE_LOCK_PATH, - size: lockBytes.length, - sha256: sha256(lockBytes), - bytes: lockBytes, - }, - ...manifest.files.map((artifact) => ({ - path: artifact.path, - size: artifact.size, - sha256: artifact.sha256, - source: workspaceFile(workspaceRoot, artifact.path, "locked carrier artifact"), - })), - ].sort((left, right) => compareText(left.path, right.path)); - const folded = new Map(); - for (const entry of entries) { - const key = entry.path.toLocaleLowerCase("en-US"); - const prior = folded.get(key); - if (prior !== undefined) throw error(`capsule paths collide by case: ${prior} and ${entry.path}`); - folded.set(key, entry.path); - } - return { entries, manifest }; -} - -export function packBootstrapCapsule({ - lockFile, - products, - headRef = "HEAD", - output, - approvalRunId, - qualificationRunId, - workspaceRoot = ROOT, -}) { - const lockPath = path.resolve(lockFile); - const lockBytes = readMetadataFile(lockPath, "approved publication lock"); - const lock = loadPublicationLock(lockPath); - assertPublicationLockSource(lock, headRef); - const { entries, manifest } = capsuleEntries( - lock, - products, - lockBytes, - workspaceRoot, - approvalRunId, - qualificationRunId, - ); - atomicTar(output, entries); - return manifest; -} - -function readExact(descriptor, buffer, position, context) { - let offset = 0; - while (offset < buffer.length) { - const count = readSync(descriptor, buffer, offset, buffer.length - offset, position + offset); - if (count === 0) throw error(`${context} is truncated`); - offset += count; - } -} - -function tarString(header, offset, length, context) { - const field = header.subarray(offset, offset + length); - const nul = field.indexOf(0); - const end = nul === -1 ? field.length : nul; - if (nul !== -1 && field.subarray(nul).some((byte) => byte !== 0)) { - throw error(`${context} contains bytes after its NUL terminator`); - } - try { - return UTF8.decode(field.subarray(0, end)); - } catch { - throw error(`${context} is not valid UTF-8`); - } -} - -function tarOctal(header, offset, length, context) { - const value = tarString(header, offset, length, context).trim(); - if (!/^[0-7]+$/u.test(value)) throw error(`${context} is not canonical octal`); - const parsed = Number.parseInt(value, 8); - if (!Number.isSafeInteger(parsed) || parsed < 0) throw error(`${context} is outside the safe integer range`); - return parsed; -} - -function parseCanonicalHeader(header) { - const name = tarString(header, 0, 100, "ustar name"); - const prefix = tarString(header, 345, 155, "ustar prefix"); - const relative = safeArchivePath(prefix ? `${prefix}/${name}` : name, "ustar member path"); - const size = tarOctal(header, 124, 12, `${relative} size`); - const expected = tarHeader(relative, size); - if (!header.equals(expected)) throw error(`${relative} has a non-canonical ustar header`); - return { path: relative, size }; -} - -function ensureParentDirectories(root, relative) { - const components = relative.split("/"); - let current = root; - for (const component of components.slice(0, -1)) { - current = path.join(current, component); - let stat; - try { - stat = lstatSync(current); - } catch { - mkdirSync(current, { mode: 0o755 }); - stat = lstatSync(current); - } - if (stat.isSymbolicLink() || !stat.isDirectory()) { - throw error(`capsule extraction parent is not a regular directory: ${current}`); - } - } -} - -function extractCanonicalTar(transport, stage) { - const archiveStat = regularFileStat(transport, "publication candidate transport"); - const { descriptor } = openRegularNoFollow(transport, "publication candidate transport"); - const observed = []; - const names = new Set(); - const folded = new Map(); - let position = 0; - let zeroBlocks = 0; - try { - while (position < archiveStat.size) { - const header = Buffer.alloc(BLOCK_SIZE); - readExact(descriptor, header, position, "publication candidate transport"); - position += BLOCK_SIZE; - if (header.every((byte) => byte === 0)) { - zeroBlocks += 1; - if (zeroBlocks === 2) break; - continue; - } - if (zeroBlocks > 0) throw error("publication candidate has an incomplete ustar end marker"); - if (observed.length >= MAX_ARCHIVE_ENTRIES) throw error(`publication candidate exceeds ${MAX_ARCHIVE_ENTRIES} entries`); - const entry = parseCanonicalHeader(header); - if (names.has(entry.path)) throw error(`publication candidate repeats ${entry.path}`); - names.add(entry.path); - const caseKey = entry.path.toLocaleLowerCase("en-US"); - const prior = folded.get(caseKey); - if (prior !== undefined) throw error(`publication candidate paths collide by case: ${prior} and ${entry.path}`); - folded.set(caseKey, entry.path); - const target = workspaceFile(stage, entry.path, "capsule member path"); - ensureParentDirectories(stage, entry.path); - const output = openSync(target, "wx", 0o644); - const hash = createHash("sha256"); - try { - const buffer = Buffer.allocUnsafe(COPY_BUFFER_SIZE); - let remaining = entry.size; - while (remaining > 0) { - const count = Math.min(buffer.length, remaining); - readExact(descriptor, buffer.subarray(0, count), position, `${entry.path} payload`); - const bytes = buffer.subarray(0, count); - hash.update(bytes); - writeAll(output, bytes); - position += count; - remaining -= count; - } - fsyncSync(output); - } finally { - closeSync(output); - } - const remainder = entry.size % BLOCK_SIZE; - if (remainder !== 0) { - const padding = Buffer.alloc(BLOCK_SIZE - remainder); - readExact(descriptor, padding, position, `${entry.path} padding`); - if (padding.some((byte) => byte !== 0)) throw error(`${entry.path} has nonzero ustar padding`); - position += padding.length; - } - observed.push({ ...entry, sha256: hash.digest("hex") }); - } - if (zeroBlocks !== 2) throw error("publication candidate is missing its two-block ustar end marker"); - if (position !== archiveStat.size) throw error("publication candidate contains bytes after its ustar end marker"); - if (observed.map(({ path: member }) => member).join("\n") !== observed.map(({ path: member }) => member).sort(compareText).join("\n")) { - throw error("publication candidate members are not in canonical path order"); - } - return observed; - } finally { - closeSync(descriptor); - } -} - -function parseManifest(file) { - const bytes = readMetadataFile(file, "publication candidate manifest"); - let manifest; - try { - manifest = JSON.parse(bytes.toString("utf8")); - } catch (cause) { - throw error(`publication candidate manifest is invalid JSON: ${cause.message}`); - } - return { bytes, manifest }; -} - -function verifyObservedEntries(observed, expectedEntries) { - const actual = observed.map(({ path: member, size, sha256: digest }) => ({ path: member, size, sha256: digest })); - const expected = expectedEntries.map(({ path: member, size, sha256: digest }) => ({ path: member, size, sha256: digest })); - if (stableJson(actual) !== stableJson(expected)) { - throw error(`capsule file set or bytes differ from the approved lock: expected=${JSON.stringify(expected)}, actual=${JSON.stringify(actual)}`); - } -} - -export function verifyExtractBootstrapCapsule({ - transport, - approvedLock, - products, - headRef = "HEAD", - approvalRunId, - qualificationRunId, - workspaceRoot, -}) { - const root = path.resolve(workspaceRoot); - const rootStat = statSync(root, { throwIfNoEntry: false }); - if (!rootStat?.isDirectory() || lstatSync(root).isSymbolicLink()) { - throw error(`workspace root must be an existing regular directory: ${root}`); - } - const destination = path.join(root, "target"); - if (existsSync(destination)) { - throw error(`atomic capsule installation requires an absent destination: ${destination}`); - } - const approvedLockBytes = readMetadataFile(path.resolve(approvedLock), "separately downloaded approved publication lock"); - const stage = mkdtempSync(path.join(root, ".publication-candidate-extract-")); - try { - const observed = extractCanonicalTar(path.resolve(transport), stage); - const embeddedLockFile = workspaceFile(stage, PUBLICATION_CANDIDATE_LOCK_PATH, "embedded publication lock path"); - const embeddedLockBytes = readMetadataFile(embeddedLockFile, "embedded publication lock"); - if (!embeddedLockBytes.equals(approvedLockBytes)) { - throw error("embedded publication lock is not byte-identical to the separately downloaded approved lock"); - } - const lock = loadPublicationLock(embeddedLockFile); - assertPublicationLockSource(lock, headRef); - const manifestFile = workspaceFile(stage, PUBLICATION_CANDIDATE_MANIFEST_PATH, "candidate manifest path"); - const parsed = parseManifest(manifestFile); - const expected = capsuleEntries( - lock, - products, - embeddedLockBytes, - stage, - approvalRunId, - qualificationRunId ?? parsed.manifest?.approval?.qualificationRunId, - ); - const expectedManifestBytes = Buffer.from(canonicalJson(expected.manifest)); - if (!parsed.bytes.equals(expectedManifestBytes) || stableJson(parsed.manifest) !== stableJson(expected.manifest)) { - throw error("publication candidate manifest does not exactly describe its approval, lock, and files"); - } - verifyObservedEntries(observed, expected.entries); - renameSync(path.join(stage, "target"), destination); - return expected.manifest; - } finally { - rmSync(stage, { recursive: true, force: true }); - } -} - -function parseArgs(argv) { - const command = argv[0]; - if (!new Set(["pack", "verify-extract"]).has(command)) { - throw error( - "usage: bootstrap-publication-capsule.mjs --products-json JSON --head-ref SHA " - + "--approval-run-id ID --qualification-run-id ID " - + "[--lock FILE --output FILE | --transport FILE --approved-lock FILE --workspace-root DIR]", - ); - } - const values = new Map(); - for (let index = 1; index < argv.length; index += 2) { - const flag = argv[index]; - const value = argv[index + 1]; - if (!flag?.startsWith("--") || value === undefined || value.startsWith("--")) { - throw error(`invalid or missing value for ${flag ?? "argument"}`); - } - const name = flag.slice(2); - if (values.has(name)) throw error(`duplicate --${name}`); - values.set(name, value); - } - const allowed = command === "pack" - ? new Set(["lock", "products-json", "head-ref", "output", "approval-run-id", "qualification-run-id"]) - : new Set(["transport", "approved-lock", "products-json", "head-ref", "workspace-root", "approval-run-id", "qualification-run-id"]); - const unknown = [...values.keys()].filter((name) => !allowed.has(name)); - if (unknown.length > 0) throw error(`unsupported ${command} arguments: ${unknown.map((name) => `--${name}`).join(" ")}`); - const optional = command === "verify-extract" ? new Set(["qualification-run-id"]) : new Set(); - const missing = [...allowed].filter((name) => !optional.has(name) && !values.get(name)); - if (missing.length > 0) throw error(`${command} requires ${missing.map((name) => `--${name}`).join(" ")}`); - return { command, values }; -} - -function main(argv) { - const { command, values } = parseArgs(argv); - if (command === "pack") { - const manifest = packBootstrapCapsule({ - lockFile: values.get("lock"), - products: values.get("products-json"), - headRef: values.get("head-ref"), - output: values.get("output"), - approvalRunId: values.get("approval-run-id"), - qualificationRunId: values.get("qualification-run-id"), - }); - console.log( - `packed ${manifest.files.length} frozen publication files from approved lock ${manifest.lockDigest} into ${values.get("output")}`, - ); - return; - } - const manifest = verifyExtractBootstrapCapsule({ - transport: values.get("transport"), - approvedLock: values.get("approved-lock"), - products: values.get("products-json"), - headRef: values.get("head-ref"), - approvalRunId: values.get("approval-run-id"), - qualificationRunId: values.get("qualification-run-id"), - workspaceRoot: values.get("workspace-root"), - }); - console.log( - `verified and atomically installed ${manifest.files.length} frozen publication files from approved lock ${manifest.lockDigest}`, - ); -} - -if (import.meta.main) { - try { - main(Bun.argv.slice(2)); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/bootstrap-publication-capsule.mts b/tools/release/bootstrap-publication-capsule.mts new file mode 100644 index 000000000..fe6264c94 --- /dev/null +++ b/tools/release/bootstrap-publication-capsule.mts @@ -0,0 +1,723 @@ +#!/usr/bin/env bun + +import { createHash } from 'node:crypto'; +import { + closeSync, + constants, + existsSync, + fstatSync, + fsyncSync, + lstatSync, + mkdirSync, + mkdtempSync, + openSync, + readFileSync, + readSync, + renameSync, + rmSync, + statSync, + writeSync, +} from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { TextDecoder } from 'node:util'; +import { tarHeader as createTarHeader } from '../packaging/archive-directory.mts'; + +import { + assertPublicationLockSource, + loadPublicationLock, + lockedPublicationFiles, +} from './publication-lock.mts'; +import { compareText, ROOT } from './release-graph.mts'; + +export const PUBLICATION_CANDIDATE_SCHEMA = 'oliphaunt-frozen-publication-candidate-v1'; +export const PUBLICATION_CANDIDATE_MANIFEST_PATH = + 'target/release/publication-candidate-manifest.json'; +export const PUBLICATION_CANDIDATE_LOCK_PATH = 'target/release/publication-lock.json'; + +const BLOCK_SIZE = 512; +const END_MARKER_SIZE = BLOCK_SIZE * 2; +const COPY_BUFFER_SIZE = 1024 * 1024; +const MAX_METADATA_BYTES = 64 * 1024 * 1024; +const MAX_ARCHIVE_ENTRIES = 10_000; +const UTF8 = new TextDecoder('utf-8', { fatal: true }); + +function error(message) { + return new Error(`bootstrap-publication-capsule: ${message}`); +} + +function stableJson(value) { + if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`; + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort(compareText) + .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +function canonicalJson(value) { + return `${JSON.stringify(value, null, 2)}\n`; +} + +function sha256(bytes) { + return createHash('sha256').update(bytes).digest('hex'); +} + +function safeProducts(raw) { + let products = raw; + if (typeof raw === 'string') { + try { + products = JSON.parse(raw); + } catch (cause) { + throw error(`products JSON is invalid: ${cause.message}`); + } + } + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string' || product.length === 0) || + new Set(products).size !== products.length + ) { + throw error('products must be a non-empty unique string list'); + } + return products.slice().sort(compareText); +} + +function safeArchivePath(value, context) { + if ( + typeof value !== 'string' || + value.length === 0 || + value.includes('\\') || + /[\u0000-\u001f\u007f]/u.test(value) || + value.normalize('NFC') !== value || + value.startsWith('/') || + value.endsWith('/') + ) { + throw error(`${context} is not a canonical relative POSIX file path: ${JSON.stringify(value)}`); + } + const components = value.split('/'); + if (components.some((component) => component === '' || component === '.' || component === '..')) { + throw error(`${context} contains an unsafe path component: ${value}`); + } + if (components[0] !== 'target') { + throw error(`${context} must remain under target/: ${value}`); + } + return value; +} + +function workspaceFile(root, relative, context) { + const safe = safeArchivePath(relative, context); + const file = path.resolve(root, ...safe.split('/')); + const resolvedRoot = path.resolve(root); + const within = path.relative(resolvedRoot, file); + if (within.startsWith(`..${path.sep}`) || path.isAbsolute(within)) { + throw error(`${context} escapes its workspace: ${relative}`); + } + return file; +} + +function regularFileStat(file, context, maximum = Number.MAX_SAFE_INTEGER) { + let stat; + try { + stat = lstatSync(file); + } catch (cause) { + throw error(`${context} is unavailable: ${cause.message}`); + } + if (stat.isSymbolicLink() || !stat.isFile()) { + throw error(`${context} must be a regular non-symlink file`); + } + if (!Number.isSafeInteger(stat.size) || stat.size < 0 || stat.size > maximum) { + throw error(`${context} has an unsupported size ${stat.size}`); + } + return stat; +} + +function openRegularNoFollow(file, context) { + const noFollow = constants.O_NOFOLLOW ?? 0; + let descriptor; + try { + descriptor = openSync(file, constants.O_RDONLY | noFollow); + } catch (cause) { + throw error(`cannot open ${context} safely: ${cause.message}`); + } + const stat = fstatSync(descriptor); + if (!stat.isFile()) { + closeSync(descriptor); + throw error(`${context} must remain a regular file while it is read`); + } + return { descriptor, stat }; +} + +function readMetadataFile(file, context) { + const stat = regularFileStat(file, context, MAX_METADATA_BYTES); + const bytes = readFileSync(file); + if (bytes.length !== stat.size) throw error(`${context} changed while it was read`); + return bytes; +} + +function hashRegularFile(file, context, expectedSize = undefined) { + const { descriptor, stat } = openRegularNoFollow(file, context); + try { + if (expectedSize !== undefined && stat.size !== expectedSize) { + throw error(`${context} size ${stat.size} does not match the frozen size ${expectedSize}`); + } + const hash = createHash('sha256'); + const buffer = Buffer.allocUnsafe(COPY_BUFFER_SIZE); + let position = 0; + for (;;) { + const count = readSync(descriptor, buffer, 0, buffer.length, position); + if (count === 0) break; + hash.update(buffer.subarray(0, count)); + position += count; + } + const finalStat = fstatSync(descriptor); + if (position !== stat.size || finalStat.size !== stat.size) { + throw error(`${context} changed while it was hashed`); + } + return { size: stat.size, sha256: hash.digest('hex') }; + } finally { + closeSync(descriptor); + } +} + +function sameStrings(left, right) { + return stableJson(left.slice().sort(compareText)) === stableJson(right.slice().sort(compareText)); +} + +function assertSelectedProducts(lock, products) { + const selectedProducts = safeProducts(products); + const lockedProducts = lock.products.map(({ id }) => id).sort(compareText); + if (!sameStrings(selectedProducts, lockedProducts)) { + throw error( + `selected products do not exactly match the approved lock: selected=${JSON.stringify(selectedProducts)}, lock=${JSON.stringify(lockedProducts)}`, + ); + } + return selectedProducts; +} + +function safeRunId(value, context) { + const runId = String(value); + if (!/^[1-9][0-9]*$/u.test(runId)) throw error(`${context} must be a positive integer`); + return runId; +} + +function expectedManifest( + lock, + products, + lockBytes, + workspaceRoot, + approvalRunId, + qualificationRunId, +) { + const selectedProducts = assertSelectedProducts(lock, products); + const lockFile = { + path: PUBLICATION_CANDIDATE_LOCK_PATH, + size: lockBytes.length, + sha256: sha256(lockBytes), + }; + return { + schema: PUBLICATION_CANDIDATE_SCHEMA, + source: { + commit: lock.source.commit, + tree: lock.source.tree, + }, + approval: { + releaseRunId: safeRunId(approvalRunId, 'approval run ID'), + qualificationRunId: safeRunId(qualificationRunId, 'qualification run ID'), + }, + lockDigest: lock.lockDigest, + packageEnvelopeDigest: lock.packageEnvelopeDigest, + catalogDigest: lock.catalogDigest, + products: selectedProducts, + publicationLock: lockFile, + files: lockedPublicationFiles(lock, { products: selectedProducts, workspaceRoot }), + }; +} + +function verifyCandidateFiles(manifest, workspaceRoot) { + for (const artifact of manifest.files) { + const file = workspaceFile(workspaceRoot, artifact.path, 'frozen candidate file path'); + const observed = hashRegularFile(file, artifact.path, artifact.size); + if (observed.sha256 !== artifact.sha256) { + throw error(`${artifact.path} bytes do not match the approved publication lock`); + } + } +} + +function tarHeader(relative, size) { + if (!Number.isSafeInteger(size) || size < 0) throw error(`invalid archive member size: ${size}`); + return createTarHeader({ name: safeArchivePath(relative, 'archive member path') }, size, 0o644); +} + +function writeAll(descriptor, bytes) { + let offset = 0; + while (offset < bytes.length) { + offset += writeSync(descriptor, bytes, offset, bytes.length - offset); + } +} + +function copyFileIntoTar(output, source, expected) { + const { descriptor, stat } = openRegularNoFollow(source, expected.path); + try { + if (stat.size !== expected.size) { + throw error(`${expected.path} size changed before capsule creation`); + } + const hash = createHash('sha256'); + const buffer = Buffer.allocUnsafe(COPY_BUFFER_SIZE); + let position = 0; + while (position < expected.size) { + const count = readSync( + descriptor, + buffer, + 0, + Math.min(buffer.length, expected.size - position), + position, + ); + if (count === 0) throw error(`${expected.path} was truncated during capsule creation`); + const bytes = buffer.subarray(0, count); + hash.update(bytes); + writeAll(output, bytes); + position += count; + } + const finalStat = fstatSync(descriptor); + if (finalStat.size !== stat.size || hash.digest('hex') !== expected.sha256) { + throw error(`${expected.path} changed or differs from the approved publication lock`); + } + } finally { + closeSync(descriptor); + } +} + +function atomicTar(output, entries) { + const destination = path.resolve(output); + mkdirSync(path.dirname(destination), { recursive: true }); + if (existsSync(destination)) throw error(`refusing to overwrite existing capsule ${destination}`); + const temporaryRoot = mkdtempSync( + path.join(path.dirname(destination), '.publication-candidate-pack-'), + ); + const temporary = path.join(temporaryRoot, 'capsule.tar'); + let descriptor; + try { + descriptor = openSync(temporary, 'wx', 0o600); + for (const entry of entries) { + writeAll(descriptor, tarHeader(entry.path, entry.size)); + if (entry.bytes !== undefined) { + writeAll(descriptor, entry.bytes); + } else { + copyFileIntoTar(descriptor, entry.source, entry); + } + const remainder = entry.size % BLOCK_SIZE; + if (remainder !== 0) writeAll(descriptor, Buffer.alloc(BLOCK_SIZE - remainder, 0)); + } + writeAll(descriptor, Buffer.alloc(END_MARKER_SIZE, 0)); + fsyncSync(descriptor); + closeSync(descriptor); + descriptor = undefined; + renameSync(temporary, destination); + } finally { + if (descriptor !== undefined) closeSync(descriptor); + rmSync(temporaryRoot, { recursive: true, force: true }); + } +} + +function capsuleEntries( + lock, + products, + lockBytes, + workspaceRoot, + approvalRunId, + qualificationRunId, +) { + const manifest = expectedManifest( + lock, + products, + lockBytes, + workspaceRoot, + approvalRunId, + qualificationRunId, + ); + verifyCandidateFiles(manifest, workspaceRoot); + const manifestBytes = Buffer.from(canonicalJson(manifest)); + const entries = [ + { + path: PUBLICATION_CANDIDATE_MANIFEST_PATH, + size: manifestBytes.length, + sha256: sha256(manifestBytes), + bytes: manifestBytes, + }, + { + path: PUBLICATION_CANDIDATE_LOCK_PATH, + size: lockBytes.length, + sha256: sha256(lockBytes), + bytes: lockBytes, + }, + ...manifest.files.map((artifact) => ({ + path: artifact.path, + size: artifact.size, + sha256: artifact.sha256, + source: workspaceFile(workspaceRoot, artifact.path, 'locked carrier artifact'), + })), + ].sort((left, right) => compareText(left.path, right.path)); + const folded = new Map(); + for (const entry of entries) { + const key = entry.path.toLocaleLowerCase('en-US'); + const prior = folded.get(key); + if (prior !== undefined) + throw error(`capsule paths collide by case: ${prior} and ${entry.path}`); + folded.set(key, entry.path); + } + return { entries, manifest }; +} + +export function packBootstrapCapsule({ + lockFile, + products, + headRef = 'HEAD', + output, + approvalRunId, + qualificationRunId, + workspaceRoot = ROOT, +}) { + const lockPath = path.resolve(lockFile); + const lockBytes = readMetadataFile(lockPath, 'approved publication lock'); + const lock = loadPublicationLock(lockPath); + assertPublicationLockSource(lock, headRef); + const { entries, manifest } = capsuleEntries( + lock, + products, + lockBytes, + workspaceRoot, + approvalRunId, + qualificationRunId, + ); + atomicTar(output, entries); + return manifest; +} + +function readExact(descriptor, buffer, position, context) { + let offset = 0; + while (offset < buffer.length) { + const count = readSync(descriptor, buffer, offset, buffer.length - offset, position + offset); + if (count === 0) throw error(`${context} is truncated`); + offset += count; + } +} + +function tarString(header, offset, length, context) { + const field = header.subarray(offset, offset + length); + const nul = field.indexOf(0); + const end = nul === -1 ? field.length : nul; + if (nul !== -1 && field.subarray(nul).some((byte) => byte !== 0)) { + throw error(`${context} contains bytes after its NUL terminator`); + } + try { + return UTF8.decode(field.subarray(0, end)); + } catch { + throw error(`${context} is not valid UTF-8`); + } +} + +function tarOctal(header, offset, length, context) { + const value = tarString(header, offset, length, context).trim(); + if (!/^[0-7]+$/u.test(value)) throw error(`${context} is not canonical octal`); + const parsed = Number.parseInt(value, 8); + if (!Number.isSafeInteger(parsed) || parsed < 0) + throw error(`${context} is outside the safe integer range`); + return parsed; +} + +function parseCanonicalHeader(header) { + const name = tarString(header, 0, 100, 'ustar name'); + const prefix = tarString(header, 345, 155, 'ustar prefix'); + const relative = safeArchivePath(prefix ? `${prefix}/${name}` : name, 'ustar member path'); + const size = tarOctal(header, 124, 12, `${relative} size`); + const expected = tarHeader(relative, size); + if (!header.equals(expected)) throw error(`${relative} has a non-canonical ustar header`); + return { path: relative, size }; +} + +function ensureParentDirectories(root, relative) { + const components = relative.split('/'); + let current = root; + for (const component of components.slice(0, -1)) { + current = path.join(current, component); + let stat; + try { + stat = lstatSync(current); + } catch { + mkdirSync(current, { mode: 0o755 }); + stat = lstatSync(current); + } + if (stat.isSymbolicLink() || !stat.isDirectory()) { + throw error(`capsule extraction parent is not a regular directory: ${current}`); + } + } +} + +function extractCanonicalTar(transport, stage) { + const archiveStat = regularFileStat(transport, 'publication candidate transport'); + const { descriptor } = openRegularNoFollow(transport, 'publication candidate transport'); + const observed = []; + const names = new Set(); + const folded = new Map(); + let position = 0; + let zeroBlocks = 0; + try { + while (position < archiveStat.size) { + const header = Buffer.alloc(BLOCK_SIZE); + readExact(descriptor, header, position, 'publication candidate transport'); + position += BLOCK_SIZE; + if (header.every((byte) => byte === 0)) { + zeroBlocks += 1; + if (zeroBlocks === 2) break; + continue; + } + if (zeroBlocks > 0) throw error('publication candidate has an incomplete ustar end marker'); + if (observed.length >= MAX_ARCHIVE_ENTRIES) + throw error(`publication candidate exceeds ${MAX_ARCHIVE_ENTRIES} entries`); + const entry = parseCanonicalHeader(header); + if (names.has(entry.path)) throw error(`publication candidate repeats ${entry.path}`); + names.add(entry.path); + const caseKey = entry.path.toLocaleLowerCase('en-US'); + const prior = folded.get(caseKey); + if (prior !== undefined) + throw error(`publication candidate paths collide by case: ${prior} and ${entry.path}`); + folded.set(caseKey, entry.path); + const target = workspaceFile(stage, entry.path, 'capsule member path'); + ensureParentDirectories(stage, entry.path); + const output = openSync(target, 'wx', 0o644); + const hash = createHash('sha256'); + try { + const buffer = Buffer.allocUnsafe(COPY_BUFFER_SIZE); + let remaining = entry.size; + while (remaining > 0) { + const count = Math.min(buffer.length, remaining); + readExact(descriptor, buffer.subarray(0, count), position, `${entry.path} payload`); + const bytes = buffer.subarray(0, count); + hash.update(bytes); + writeAll(output, bytes); + position += count; + remaining -= count; + } + fsyncSync(output); + } finally { + closeSync(output); + } + const remainder = entry.size % BLOCK_SIZE; + if (remainder !== 0) { + const padding = Buffer.alloc(BLOCK_SIZE - remainder); + readExact(descriptor, padding, position, `${entry.path} padding`); + if (padding.some((byte) => byte !== 0)) + throw error(`${entry.path} has nonzero ustar padding`); + position += padding.length; + } + observed.push({ ...entry, sha256: hash.digest('hex') }); + } + if (zeroBlocks !== 2) + throw error('publication candidate is missing its two-block ustar end marker'); + if (position !== archiveStat.size) + throw error('publication candidate contains bytes after its ustar end marker'); + if ( + observed.map(({ path: member }) => member).join('\n') !== + observed + .map(({ path: member }) => member) + .sort(compareText) + .join('\n') + ) { + throw error('publication candidate members are not in canonical path order'); + } + return observed; + } finally { + closeSync(descriptor); + } +} + +function parseManifest(file) { + const bytes = readMetadataFile(file, 'publication candidate manifest'); + let manifest; + try { + manifest = JSON.parse(bytes.toString('utf8')); + } catch (cause) { + throw error(`publication candidate manifest is invalid JSON: ${cause.message}`); + } + return { bytes, manifest }; +} + +function verifyObservedEntries(observed, expectedEntries) { + const actual = observed.map(({ path: member, size, sha256: digest }) => ({ + path: member, + size, + sha256: digest, + })); + const expected = expectedEntries.map(({ path: member, size, sha256: digest }) => ({ + path: member, + size, + sha256: digest, + })); + if (stableJson(actual) !== stableJson(expected)) { + throw error( + `capsule file set or bytes differ from the approved lock: expected=${JSON.stringify(expected)}, actual=${JSON.stringify(actual)}`, + ); + } +} + +export function verifyExtractBootstrapCapsule({ + transport, + approvedLock, + products, + headRef = 'HEAD', + approvalRunId, + qualificationRunId, + workspaceRoot, +}) { + const root = path.resolve(workspaceRoot); + const rootStat = statSync(root, { throwIfNoEntry: false }); + if (!rootStat?.isDirectory() || lstatSync(root).isSymbolicLink()) { + throw error(`workspace root must be an existing regular directory: ${root}`); + } + const destination = path.join(root, 'target'); + if (existsSync(destination)) { + throw error(`atomic capsule installation requires an absent destination: ${destination}`); + } + const approvedLockBytes = readMetadataFile( + path.resolve(approvedLock), + 'separately downloaded approved publication lock', + ); + const stage = mkdtempSync(path.join(root, '.publication-candidate-extract-')); + try { + const observed = extractCanonicalTar(path.resolve(transport), stage); + const embeddedLockFile = workspaceFile( + stage, + PUBLICATION_CANDIDATE_LOCK_PATH, + 'embedded publication lock path', + ); + const embeddedLockBytes = readMetadataFile(embeddedLockFile, 'embedded publication lock'); + if (!embeddedLockBytes.equals(approvedLockBytes)) { + throw error( + 'embedded publication lock is not byte-identical to the separately downloaded approved lock', + ); + } + const lock = loadPublicationLock(embeddedLockFile); + assertPublicationLockSource(lock, headRef); + const manifestFile = workspaceFile( + stage, + PUBLICATION_CANDIDATE_MANIFEST_PATH, + 'candidate manifest path', + ); + const parsed = parseManifest(manifestFile); + const expected = capsuleEntries( + lock, + products, + embeddedLockBytes, + stage, + approvalRunId, + qualificationRunId ?? parsed.manifest?.approval?.qualificationRunId, + ); + const expectedManifestBytes = Buffer.from(canonicalJson(expected.manifest)); + if ( + !parsed.bytes.equals(expectedManifestBytes) || + stableJson(parsed.manifest) !== stableJson(expected.manifest) + ) { + throw error( + 'publication candidate manifest does not exactly describe its approval, lock, and files', + ); + } + verifyObservedEntries(observed, expected.entries); + renameSync(path.join(stage, 'target'), destination); + return expected.manifest; + } finally { + rmSync(stage, { recursive: true, force: true }); + } +} + +function parseArgs(argv) { + const command = argv[0]; + if (!new Set(['pack', 'verify-extract']).has(command)) { + throw error( + 'usage: bootstrap-publication-capsule.mts --products-json JSON --head-ref SHA ' + + '--approval-run-id ID --qualification-run-id ID ' + + '[--lock FILE --output FILE | --transport FILE --approved-lock FILE --workspace-root DIR]', + ); + } + const values = new Map(); + for (let index = 1; index < argv.length; index += 2) { + const flag = argv[index]; + const value = argv[index + 1]; + if (!flag?.startsWith('--') || value === undefined || value.startsWith('--')) { + throw error(`invalid or missing value for ${flag ?? 'argument'}`); + } + const name = flag.slice(2); + if (values.has(name)) throw error(`duplicate --${name}`); + values.set(name, value); + } + const allowed = + command === 'pack' + ? new Set([ + 'lock', + 'products-json', + 'head-ref', + 'output', + 'approval-run-id', + 'qualification-run-id', + ]) + : new Set([ + 'transport', + 'approved-lock', + 'products-json', + 'head-ref', + 'workspace-root', + 'approval-run-id', + 'qualification-run-id', + ]); + const unknown = [...values.keys()].filter((name) => !allowed.has(name)); + if (unknown.length > 0) + throw error( + `unsupported ${command} arguments: ${unknown.map((name) => `--${name}`).join(' ')}`, + ); + const optional = command === 'verify-extract' ? new Set(['qualification-run-id']) : new Set(); + const missing = [...allowed].filter((name) => !optional.has(name) && !values.get(name)); + if (missing.length > 0) + throw error(`${command} requires ${missing.map((name) => `--${name}`).join(' ')}`); + return { command, values }; +} + +function main(argv) { + const { command, values } = parseArgs(argv); + if (command === 'pack') { + const manifest = packBootstrapCapsule({ + lockFile: values.get('lock'), + products: values.get('products-json'), + headRef: values.get('head-ref'), + output: values.get('output'), + approvalRunId: values.get('approval-run-id'), + qualificationRunId: values.get('qualification-run-id'), + }); + console.log( + `packed ${manifest.files.length} frozen publication files from approved lock ${manifest.lockDigest} into ${values.get('output')}`, + ); + return; + } + const manifest = verifyExtractBootstrapCapsule({ + transport: values.get('transport'), + approvedLock: values.get('approved-lock'), + products: values.get('products-json'), + headRef: values.get('head-ref'), + approvalRunId: values.get('approval-run-id'), + qualificationRunId: values.get('qualification-run-id'), + workspaceRoot: values.get('workspace-root'), + }); + console.log( + `verified and atomically installed ${manifest.files.length} frozen publication files from approved lock ${manifest.lockDigest}`, + ); +} + +if (import.meta.main) { + try { + main(Bun.argv.slice(2)); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/bootstrap-publication-capsule.test.mjs b/tools/release/bootstrap-publication-capsule.test.mjs deleted file mode 100644 index b3b06dfba..000000000 --- a/tools/release/bootstrap-publication-capsule.test.mjs +++ /dev/null @@ -1,531 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { - copyFileSync, - lstatSync, - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - symlinkSync, - unlinkSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { isolatedGitHubTestEnvironment } from "../test/isolated-github-test-environment.mjs"; -import { - PUBLICATION_CANDIDATE_LOCK_PATH as BOOTSTRAP_CAPSULE_LOCK_PATH, - PUBLICATION_CANDIDATE_MANIFEST_PATH as BOOTSTRAP_CAPSULE_MANIFEST_PATH, - packBootstrapCapsule as packCandidate, - verifyExtractBootstrapCapsule as extractCandidate, -} from "./bootstrap-publication-capsule.mjs"; -import { - buildPublicationCandidate, - freezePublicationCandidate, -} from "./publication-lock.mjs"; -import { loadPublicationCatalog } from "./publication-catalog.mjs"; -import { ROOT } from "./release-graph.mjs"; - -const PRODUCTS = ["oliphaunt-rust", "oliphaunt-js"]; -const APPROVAL = { approvalRunId: "123", qualificationRunId: "456" }; - -function packBootstrapCapsule(options) { - return packCandidate({ ...APPROVAL, ...options }); -} - -function verifyExtractBootstrapCapsule(options) { - return extractCandidate({ ...APPROVAL, ...options }); -} - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function tarGzip(output, cwd, member) { - const result = spawnSync("tar", ["-czf", output, "-C", cwd, member], { encoding: "utf8" }); - assert.equal(result.status, 0, result.stderr || result.stdout); -} - -function cargoFixture(stageRoot, artifacts, name, version) { - const directoryName = `${name}-${version}`; - const stage = path.join(stageRoot, directoryName); - mkdirSync(path.join(stage, "src"), { recursive: true }); - writeFileSync( - path.join(stage, "Cargo.toml"), - `[package]\nname = ${JSON.stringify(name)}\nversion = ${JSON.stringify(version)}\nedition = "2024"\n`, - ); - writeFileSync(path.join(stage, "src/lib.rs"), `pub const NAME: &str = ${JSON.stringify(name)};\n`); - const output = path.join(artifacts, `${directoryName}.crate`); - tarGzip(output, stageRoot, directoryName); - return output; -} - -function npmFixture(stageRoot, artifacts, name, version) { - const stage = path.join(stageRoot, "npm", "package"); - mkdirSync(stage, { recursive: true }); - writeFileSync(path.join(stage, "index.js"), "export const fixture = true;\n"); - writeFileSync(path.join(stage, "package.json"), `${JSON.stringify({ - name, - version, - type: "module", - repository: { - type: "git", - url: "git+https://github.com/f0rr0/oliphaunt.git", - }, - publishConfig: { - access: "public", - provenance: true, - }, - }, null, 2)}\n`); - const output = path.join(artifacts, "oliphaunt-ts.tgz"); - tarGzip(output, path.dirname(stage), "package"); - return output; -} - -function mavenFixture(artifacts, group, name, version) { - const directory = path.join(artifacts, "maven", ...group.split("."), name, version); - mkdirSync(directory, { recursive: true }); - const basename = `${name}-${version}`; - const packaging = name.endsWith(".gradle.plugin") ? "pom" : "jar"; - writeFileSync( - path.join(directory, `${basename}.pom`), - `4.0.0${group}${name}${version}${packaging}FixtureFixture publicationhttps://github.com/f0rr0/oliphauntMIThttps://opensource.org/license/mitFixture Maintainerhttps://github.com/f0rr0scm:git:https://github.com/f0rr0/oliphaunt.gitscm:git:ssh://git@github.com/f0rr0/oliphaunt.githttps://github.com/f0rr0/oliphaunt\n`, - ); - if (packaging !== "pom") { - writeFileSync(path.join(directory, `${basename}.jar`), `fixture:${group}:${name}:${version}\n`); - writeFileSync(path.join(directory, `${basename}-sources.jar`), "fixture sources\n"); - writeFileSync(path.join(directory, `${basename}-javadoc.jar`), "fixture javadocs\n"); - } -} - -function fixture() { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "publication-candidate-test-")); - const stage = path.join(root, "stage"); - const artifacts = path.join(root, "artifacts"); - mkdirSync(stage, { recursive: true }); - mkdirSync(artifacts, { recursive: true }); - const catalog = loadPublicationCatalog("bootstrap-publication-capsule.test", { products: PRODUCTS }); - const versions = new Map(catalog.products.map(({ id, version }) => [id, version])); - const cargo = [ - cargoFixture(stage, artifacts, "oliphaunt", versions.get("oliphaunt-rust")), - cargoFixture(stage, artifacts, "oliphaunt-build", versions.get("oliphaunt-rust")), - ]; - const npm = npmFixture(stage, artifacts, "@oliphaunt/ts", versions.get("oliphaunt-js")); - const lock = freezePublicationCandidate(buildPublicationCandidate({ - products: PRODUCTS, - artifactRoots: [artifacts], - headRef: "HEAD", - })); - const lockFile = path.join(root, "publication-lock.json"); - writeFileSync(lockFile, `${JSON.stringify(lock, null, 2)}\n`); - return { root, lock, lockFile, cargo, npm }; -} - -function mavenOnlyFixture() { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "publication-candidate-empty-test-")); - const artifacts = path.join(root, "artifacts"); - mkdirSync(artifacts, { recursive: true }); - const products = ["oliphaunt-kotlin"]; - const catalog = loadPublicationCatalog("bootstrap-publication-capsule.empty.test", { products }); - const version = catalog.products[0].version; - for (const carrier of catalog.carriers) { - const separator = carrier.name.indexOf(":"); - mavenFixture( - artifacts, - carrier.name.slice(0, separator), - carrier.name.slice(separator + 1), - version, - ); - } - const lock = freezePublicationCandidate(buildPublicationCandidate({ - products, - artifactRoots: [artifacts], - headRef: "HEAD", - })); - const lockFile = path.join(root, "publication-lock.json"); - writeFileSync(lockFile, `${JSON.stringify(lock, null, 2)}\n`); - return { root, lock, lockFile, products }; -} - -function workspace() { - return mkdtempSync(path.join(os.tmpdir(), "oliphaunt-publication-candidate-workspace-")); -} - -function mutateTarPayload(source, destination, member, replacement) { - const bytes = Buffer.from(readFileSync(source)); - let position = 0; - for (;;) { - const header = bytes.subarray(position, position + 512); - assert.equal(header.length, 512); - if (header.every((byte) => byte === 0)) break; - const nul = header.indexOf(0, 0); - const name = header.subarray(0, nul === -1 || nul > 100 ? 100 : nul).toString("utf8"); - const prefixNul = header.indexOf(0, 345); - const prefix = header.subarray(345, prefixNul === -1 || prefixNul > 500 ? 500 : prefixNul).toString("utf8"); - const fullName = prefix ? `${prefix}/${name}` : name; - const sizeText = header.subarray(124, 136).toString("ascii").replaceAll("\0", "").trim(); - const size = Number.parseInt(sizeText, 8); - if (fullName === member) { - const payload = bytes.subarray(position + 512, position + 512 + size); - const changed = replacement(Buffer.from(payload)); - assert.equal(changed.length, payload.length, "payload mutation must preserve tar member size"); - changed.copy(bytes, position + 512); - writeFileSync(destination, bytes); - return; - } - position += 512 + Math.ceil(size / 512) * 512; - } - assert.fail(`archive member not found: ${member}`); -} - -function tarRecords(source) { - const bytes = Buffer.from(readFileSync(source)); - const records = []; - for (let position = 0; !bytes.subarray(position, position + 512).every((byte) => byte === 0);) { - const header = bytes.subarray(position, position + 512); - const size = Number.parseInt(header.subarray(124, 136).toString("ascii").replaceAll("\0", "").trim(), 8); - const end = position + 512 + Math.ceil(size / 512) * 512; - records.push(Buffer.from(bytes.subarray(position, end))); - position = end; - } - return records; -} - -function renamedTarRecord(record, name) { - assert.ok(Buffer.byteLength(name) <= 100); - const changed = Buffer.from(record); - changed.fill(0, 0, 100); - changed.write(name, 0, "utf8"); - changed.fill(0, 345, 500); - changed.fill(0x20, 148, 156); - let checksum = 0; - for (const byte of changed.subarray(0, 512)) checksum += byte; - changed.write(`${checksum.toString(8).padStart(6, "0")}\0 `, 148, "ascii"); - return changed; -} - -function writeTar(destination, records) { - writeFileSync(destination, Buffer.concat([...records, Buffer.alloc(1024)])); -} - -test("packs every locked publication file deterministically and atomically installs it", () => { - const value = fixture(); - const first = path.join(value.root, "first.tar"); - const second = path.join(value.root, "second.tar"); - const output = workspace(); - try { - const manifest = packBootstrapCapsule({ - lockFile: value.lockFile, - products: PRODUCTS, - output: first, - }); - packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output: second }); - assert.equal(sha256(first), sha256(second), "capsule must be byte-for-byte deterministic"); - assert.equal(manifest.approval.releaseRunId, APPROVAL.approvalRunId); - assert.equal(manifest.approval.qualificationRunId, APPROVAL.qualificationRunId); - assert.equal(manifest.files.length, 3); - - const installed = verifyExtractBootstrapCapsule({ - transport: first, - approvedLock: value.lockFile, - products: PRODUCTS, - workspaceRoot: output, - }); - assert.equal(installed.lockDigest, value.lock.lockDigest); - assert.deepEqual( - readFileSync(path.join(output, ...BOOTSTRAP_CAPSULE_LOCK_PATH.split("/"))), - readFileSync(value.lockFile), - ); - assert.equal(lstatSync(path.join(output, ...BOOTSTRAP_CAPSULE_MANIFEST_PATH.split("/"))).isFile(), true); - for (const source of [...value.cargo, value.npm]) { - const artifact = manifest.files.find((file) => file.sha256 === sha256(source)); - assert.ok(artifact); - assert.equal( - sha256(path.join(output, ...artifact.path.split("/"))), - artifact.sha256, - ); - } - } finally { - rmSync(value.root, { recursive: true, force: true }); - rmSync(output, { recursive: true, force: true }); - } -}); - -test("publish and bootstrap workflow commands install the same approved candidate and reject approval drift", () => { - const value = fixture(); - const workflow = Bun.YAML.parse(readFileSync(path.join(ROOT, ".github/workflows/release.yml"), "utf8")); - const destinations = []; - try { - for (const operation of ["publish", "publish-bootstrap"]) { - const approved = path.join(value.root, operation === "publish" ? "approved-publication" : "approved-bootstrap"); - mkdirSync(approved); - copyFileSync(value.lockFile, path.join(approved, "publication-lock.json")); - packBootstrapCapsule({ - lockFile: value.lockFile, - products: PRODUCTS, - output: path.join(approved, "oliphaunt-publication-candidate.tar"), - }); - const output = workspace(); - destinations.push(output); - const step = workflow.jobs[operation].steps.find(({ run }) => - run?.includes("bootstrap-publication-capsule.mjs verify-extract")); - assert.ok(step, `${operation} must install the approved candidate`); - const environment = isolatedGitHubTestEnvironment({ - APPROVAL_RUN_ID: APPROVAL.approvalRunId, - PRODUCTS_JSON: JSON.stringify(PRODUCTS), - RELEASE_HEAD_SHA: value.lock.source.commit, - RUNNER_TEMP: value.root, - GITHUB_WORKSPACE: output, - }); - const invoke = (approval) => spawnSync( - process.env.OLIPHAUNT_TEST_BASH || "bash", - ["--noprofile", "--norc", "-e", "-o", "pipefail", "-c", step.run], - { cwd: ROOT, encoding: "utf8", env: { ...environment, APPROVAL_RUN_ID: approval } }, - ); - const rejected = invoke("999"); - assert.notEqual(rejected.status, 0, `${operation} must reject a different approval`); - assert.match(`${rejected.stdout}${rejected.stderr}`, /approval/iu); - const accepted = invoke(APPROVAL.approvalRunId); - assert.equal(accepted.status, 0, `${operation}: ${accepted.stdout}${accepted.stderr}`); - assert.equal( - sha256(path.join(output, ...BOOTSTRAP_CAPSULE_LOCK_PATH.split("/"))), - sha256(value.lockFile), - ); - } - } finally { - rmSync(value.root, { recursive: true, force: true }); - for (const output of destinations) rmSync(output, { recursive: true, force: true }); - } -}); - -test("the real bootstrap command checkpoints a mixed inventory before a bounded deferral without uploading", () => { - const value = fixture(); - try { - const preload = path.join(value.root, "registry-fixture.mjs"); - writeFileSync(preload, ` - import { mock } from "bun:test"; - import * as childProcess from "node:child_process"; - mock.module("node:child_process", () => ({ ...childProcess, spawn() { throw new Error("unexpected publisher invocation"); } })); - globalThis.fetch = async (input, options = {}) => { - if (options.method && options.method !== "GET") throw new Error("unexpected registry mutation"); - const url = new URL(String(input)); - if (!["crates.io", "registry.npmjs.org"].includes(url.hostname)) throw new Error("unexpected registry"); - return new Response("{}", { status: url.hostname === "crates.io" && url.pathname.startsWith("/api/v1/crates/oliphaunt-build/") ? 200 : 404 }); - }; - `); - const npmrc = path.join(value.root, "npmrc"); - writeFileSync(npmrc, "//registry.npmjs.org/:_authToken=fixture-not-a-credential\n"); - const resultFile = path.join(value.root, "execution.json"); - const result = spawnSync(process.execPath, ["--preload", preload, ".github/scripts/bootstrap-registry-identities.mjs"], { - cwd: ROOT, encoding: "utf8", - env: { - ...isolatedGitHubTestEnvironment(), - PRODUCTS_JSON: JSON.stringify(PRODUCTS), RELEASE_HEAD_SHA: value.lock.source.commit, - PUBLICATION_LOCK_PATH: value.lockFile, BOOTSTRAP_LEDGER_PATH: path.join(value.root, "ledger"), - REGISTRY_MUTATION_DEADLINE_EPOCH: String(Math.floor(Date.now() / 1000) + 60), - REGISTRY_JOB_HARD_DEADLINE_EPOCH: String(Math.floor(Date.now() / 1000) + 600), - CARGO_REGISTRY_TOKEN: "fixture-not-a-credential", NPM_CONFIG_USERCONFIG: npmrc, - OLIPHAUNT_BOOTSTRAP_EXECUTION_RESULT: resultFile, - }, - }); - assert.equal(result.status, 0, `${result.stdout}${result.stderr}`); - const decision = JSON.parse(readFileSync(resultFile, "utf8")); - assert.equal(decision.decision, "deferred"); - assert.equal(decision.newlyCompletedIds.length, 0); - assert.equal(decision.remainingIds.length, 2); - } finally { rmSync(value.root, { recursive: true, force: true }); } -}); - -test("packs and verifies all Maven payloads for a Maven-only release", () => { - const value = mavenOnlyFixture(); - const first = path.join(value.root, "first.tar"); - const second = path.join(value.root, "second.tar"); - const output = workspace(); - try { - const manifest = packBootstrapCapsule({ - lockFile: value.lockFile, - products: value.products, - output: first, - }); - packBootstrapCapsule({ lockFile: value.lockFile, products: value.products, output: second }); - assert.ok(manifest.files.length > 0); - assert.equal(sha256(first), sha256(second)); - const installed = verifyExtractBootstrapCapsule({ - transport: first, - approvedLock: value.lockFile, - products: value.products, - workspaceRoot: output, - }); - assert.deepEqual(installed.files, manifest.files); - assert.deepEqual( - readFileSync(path.join(output, ...BOOTSTRAP_CAPSULE_LOCK_PATH.split("/"))), - readFileSync(value.lockFile), - ); - } finally { - rmSync(value.root, { recursive: true, force: true }); - rmSync(output, { recursive: true, force: true }); - } -}); - -test("fails closed on selection drift, external-lock drift, and a preexisting destination", () => { - const value = fixture(); - const capsule = path.join(value.root, "capsule.tar"); - const output = workspace(); - try { - assert.throws( - () => packBootstrapCapsule({ lockFile: value.lockFile, products: [PRODUCTS[0]], output: capsule }), - /selected products do not exactly match/u, - ); - packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output: capsule }); - assert.throws( - () => extractCandidate({ - ...APPROVAL, - approvalRunId: "999", - transport: capsule, - approvedLock: value.lockFile, - products: PRODUCTS, - workspaceRoot: output, - }), - /manifest does not exactly describe its approval/u, - ); - const changedLock = path.join(value.root, "changed-lock.json"); - copyFileSync(value.lockFile, changedLock); - writeFileSync(changedLock, `${readFileSync(changedLock, "utf8").trimEnd()} \n`); - assert.throws( - () => verifyExtractBootstrapCapsule({ - transport: capsule, - approvedLock: changedLock, - products: PRODUCTS, - workspaceRoot: output, - }), - /not byte-identical/u, - ); - assert.equal(lstatSync(output).isDirectory(), true); - assert.throws(() => lstatSync(path.join(output, "target")), /ENOENT/u); - - mkdirSync(path.join(output, "target")); - assert.throws( - () => verifyExtractBootstrapCapsule({ - transport: capsule, - approvedLock: value.lockFile, - products: PRODUCTS, - workspaceRoot: output, - }), - /requires an absent destination/u, - ); - } finally { - rmSync(value.root, { recursive: true, force: true }); - rmSync(output, { recursive: true, force: true }); - } -}); - -test("rejects tampered manifests and carrier bytes without installing partial output", () => { - const value = fixture(); - const capsule = path.join(value.root, "capsule.tar"); - const manifestTamper = path.join(value.root, "manifest-tamper.tar"); - const carrierTamper = path.join(value.root, "carrier-tamper.tar"); - const firstOutput = workspace(); - const secondOutput = workspace(); - try { - const manifest = packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output: capsule }); - mutateTarPayload(capsule, manifestTamper, BOOTSTRAP_CAPSULE_MANIFEST_PATH, (bytes) => { - const marker = Buffer.from("oliphaunt-frozen-publication-candidate-v1"); - const index = bytes.indexOf(marker); - assert.ok(index >= 0); - bytes[index] = "x".charCodeAt(0); - return bytes; - }); - mutateTarPayload(capsule, carrierTamper, manifest.files[0].path, (bytes) => { - bytes[Math.floor(bytes.length / 2)] ^= 0xff; - return bytes; - }); - - assert.throws( - () => verifyExtractBootstrapCapsule({ - transport: manifestTamper, - approvedLock: value.lockFile, - products: PRODUCTS, - workspaceRoot: firstOutput, - }), - /manifest does not exactly describe|file set or bytes differ/u, - ); - assert.throws(() => lstatSync(path.join(firstOutput, "target")), /ENOENT/u); - assert.throws( - () => verifyExtractBootstrapCapsule({ - transport: carrierTamper, - approvedLock: value.lockFile, - products: PRODUCTS, - workspaceRoot: secondOutput, - }), - /bytes do not match|file set or bytes differ/u, - ); - assert.throws(() => lstatSync(path.join(secondOutput, "target")), /ENOENT/u); - } finally { - rmSync(value.root, { recursive: true, force: true }); - rmSync(firstOutput, { recursive: true, force: true }); - rmSync(secondOutput, { recursive: true, force: true }); - } -}); - -test("rejects missing, extra, and unsafe archive members", () => { - const value = fixture(); - const capsule = path.join(value.root, "capsule.tar"); - const missing = path.join(value.root, "missing.tar"); - const extra = path.join(value.root, "extra.tar"); - const unsafe = path.join(value.root, "unsafe.tar"); - try { - packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output: capsule }); - const records = tarRecords(capsule); - writeTar(missing, records.slice(0, -1)); - writeTar(extra, [...records, renamedTarRecord(records.at(-1), "target/zzzz-unapproved")]); - writeTar(unsafe, [renamedTarRecord(records[0], "../escape"), ...records.slice(1)]); - for (const [transport, pattern] of [ - [missing, /unavailable|file set or bytes differ/u], - [extra, /file set or bytes differ/u], - [unsafe, /unsafe path component/u], - ]) { - const output = workspace(); - try { - assert.throws(() => verifyExtractBootstrapCapsule({ - transport, - approvedLock: value.lockFile, - products: PRODUCTS, - workspaceRoot: output, - }), pattern); - assert.throws(() => lstatSync(path.join(output, "target")), /ENOENT/u); - } finally { - rmSync(output, { recursive: true, force: true }); - } - } - } finally { - rmSync(value.root, { recursive: true, force: true }); - } -}); - -test("rejects symlinked frozen inputs before producing a capsule", () => { - const value = fixture(); - const output = path.join(value.root, "capsule.tar"); - const carrier = value.lock.carriers.find(({ ecosystem }) => ecosystem === "cargo"); - const artifact = path.resolve(ROOT, carrier.artifacts[0].path); - const replacement = path.join(value.root, "replacement.crate"); - try { - copyFileSync(artifact, replacement); - unlinkSync(artifact); - symlinkSync(replacement, artifact); - assert.throws( - () => packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output }), - /regular (?:non-symlink )?file|regular file or directory|open .* safely/u, - ); - assert.throws(() => lstatSync(output), /ENOENT/u); - } finally { - rmSync(value.root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/bootstrap-publication-capsule.test.mts b/tools/release/bootstrap-publication-capsule.test.mts new file mode 100644 index 000000000..5102af574 --- /dev/null +++ b/tools/release/bootstrap-publication-capsule.test.mts @@ -0,0 +1,516 @@ +#!/usr/bin/env bun + +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + unlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { gzipSync } from 'node:zlib'; +import { createDeterministicTar } from '../packaging/cargo-source-package.mts'; +import { + PUBLICATION_CANDIDATE_LOCK_PATH as BOOTSTRAP_CAPSULE_LOCK_PATH, + PUBLICATION_CANDIDATE_MANIFEST_PATH as BOOTSTRAP_CAPSULE_MANIFEST_PATH, + verifyExtractBootstrapCapsule as extractCandidate, + packBootstrapCapsule as packCandidate, +} from './bootstrap-publication-capsule.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { buildPublicationCandidate, freezePublicationCandidate } from './publication-lock.mts'; +import { ROOT } from './release-graph.mts'; + +const PRODUCTS = ['oliphaunt-rust', 'oliphaunt-js']; +const APPROVAL = { approvalRunId: '123', qualificationRunId: '456' }; + +function packBootstrapCapsule(options) { + return packCandidate({ ...APPROVAL, ...options }); +} + +function verifyExtractBootstrapCapsule(options) { + return extractCandidate({ ...APPROVAL, ...options }); +} + +function sha256(file) { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} + +function tarGzip(output, cwd, member) { + writeFileSync( + output, + gzipSync(createDeterministicTar(path.join(cwd, member), member, {}), { mtime: 0 }), + ); +} + +function cargoFixture(stageRoot, artifacts, name, version) { + const directoryName = `${name}-${version}`; + const stage = path.join(stageRoot, directoryName); + mkdirSync(path.join(stage, 'src'), { recursive: true }); + writeFileSync( + path.join(stage, 'Cargo.toml'), + `[package]\nname = ${JSON.stringify(name)}\nversion = ${JSON.stringify(version)}\nedition = "2024"\n`, + ); + writeFileSync( + path.join(stage, 'src/lib.rs'), + `pub const NAME: &str = ${JSON.stringify(name)};\n`, + ); + const output = path.join(artifacts, `${directoryName}.crate`); + tarGzip(output, stageRoot, directoryName); + return output; +} + +function npmFixture(stageRoot, artifacts, name, version) { + const stage = path.join(stageRoot, 'npm', 'package'); + mkdirSync(stage, { recursive: true }); + writeFileSync(path.join(stage, 'index.js'), 'export const fixture = true;\n'); + writeFileSync( + path.join(stage, 'package.json'), + `${JSON.stringify( + { + name, + version, + type: 'module', + repository: { + type: 'git', + url: 'git+https://github.com/f0rr0/oliphaunt.git', + }, + publishConfig: { + access: 'public', + provenance: true, + }, + }, + null, + 2, + )}\n`, + ); + const output = path.join(artifacts, 'oliphaunt-ts.tgz'); + tarGzip(output, path.dirname(stage), 'package'); + return output; +} + +function mavenFixture(artifacts, group, name, version) { + const directory = path.join(artifacts, 'maven', ...group.split('.'), name, version); + mkdirSync(directory, { recursive: true }); + const basename = `${name}-${version}`; + const packaging = name.endsWith('.gradle.plugin') ? 'pom' : 'jar'; + writeFileSync( + path.join(directory, `${basename}.pom`), + `4.0.0${group}${name}${version}${packaging}FixtureFixture publicationhttps://github.com/f0rr0/oliphauntMIThttps://opensource.org/license/mitFixture Maintainerhttps://github.com/f0rr0scm:git:https://github.com/f0rr0/oliphaunt.gitscm:git:ssh://git@github.com/f0rr0/oliphaunt.githttps://github.com/f0rr0/oliphaunt\n`, + ); + if (packaging !== 'pom') { + writeFileSync(path.join(directory, `${basename}.jar`), `fixture:${group}:${name}:${version}\n`); + writeFileSync(path.join(directory, `${basename}-sources.jar`), 'fixture sources\n'); + writeFileSync(path.join(directory, `${basename}-javadoc.jar`), 'fixture javadocs\n'); + } +} + +function fixture() { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target', 'publication-candidate-test-')); + const stage = path.join(root, 'stage'); + const artifacts = path.join(root, 'artifacts'); + mkdirSync(stage, { recursive: true }); + mkdirSync(artifacts, { recursive: true }); + const catalog = loadPublicationCatalog('bootstrap-publication-capsule.test', { + products: PRODUCTS, + }); + const versions = new Map(catalog.products.map(({ id, version }) => [id, version])); + const cargo = [ + cargoFixture(stage, artifacts, 'oliphaunt', versions.get('oliphaunt-rust')), + cargoFixture(stage, artifacts, 'oliphaunt-build', versions.get('oliphaunt-rust')), + ]; + const npm = npmFixture(stage, artifacts, '@oliphaunt/ts', versions.get('oliphaunt-js')); + const lock = freezePublicationCandidate( + buildPublicationCandidate({ + products: PRODUCTS, + artifactRoots: [artifacts], + headRef: 'HEAD', + }), + ); + const lockFile = path.join(root, 'publication-lock.json'); + writeFileSync(lockFile, `${JSON.stringify(lock, null, 2)}\n`); + return { root, lock, lockFile, cargo, npm }; +} + +function mavenOnlyFixture() { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target', 'publication-candidate-empty-test-')); + const artifacts = path.join(root, 'artifacts'); + mkdirSync(artifacts, { recursive: true }); + const products = ['oliphaunt-kotlin']; + const catalog = loadPublicationCatalog('bootstrap-publication-capsule.empty.test', { products }); + const version = catalog.products[0].version; + for (const carrier of catalog.carriers) { + const separator = carrier.name.indexOf(':'); + mavenFixture( + artifacts, + carrier.name.slice(0, separator), + carrier.name.slice(separator + 1), + version, + ); + } + const lock = freezePublicationCandidate( + buildPublicationCandidate({ + products, + artifactRoots: [artifacts], + headRef: 'HEAD', + }), + ); + const lockFile = path.join(root, 'publication-lock.json'); + writeFileSync(lockFile, `${JSON.stringify(lock, null, 2)}\n`); + return { root, lock, lockFile, products }; +} + +function workspace() { + return mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-publication-candidate-workspace-')); +} + +function mutateTarPayload(source, destination, member, replacement) { + const bytes = Buffer.from(readFileSync(source)); + let position = 0; + for (;;) { + const header = bytes.subarray(position, position + 512); + assert.equal(header.length, 512); + if (header.every((byte) => byte === 0)) break; + const nul = header.indexOf(0, 0); + const name = header.subarray(0, nul === -1 || nul > 100 ? 100 : nul).toString('utf8'); + const prefixNul = header.indexOf(0, 345); + const prefix = header + .subarray(345, prefixNul === -1 || prefixNul > 500 ? 500 : prefixNul) + .toString('utf8'); + const fullName = prefix ? `${prefix}/${name}` : name; + const sizeText = header.subarray(124, 136).toString('ascii').replaceAll('\0', '').trim(); + const size = Number.parseInt(sizeText, 8); + if (fullName === member) { + const payload = bytes.subarray(position + 512, position + 512 + size); + const changed = replacement(Buffer.from(payload)); + assert.equal( + changed.length, + payload.length, + 'payload mutation must preserve tar member size', + ); + changed.copy(bytes, position + 512); + writeFileSync(destination, bytes); + return; + } + position += 512 + Math.ceil(size / 512) * 512; + } + assert.fail(`archive member not found: ${member}`); +} + +function tarRecords(source) { + const bytes = Buffer.from(readFileSync(source)); + const records = []; + for (let position = 0; !bytes.subarray(position, position + 512).every((byte) => byte === 0); ) { + const header = bytes.subarray(position, position + 512); + const size = Number.parseInt( + header.subarray(124, 136).toString('ascii').replaceAll('\0', '').trim(), + 8, + ); + const end = position + 512 + Math.ceil(size / 512) * 512; + records.push(Buffer.from(bytes.subarray(position, end))); + position = end; + } + return records; +} + +function renamedTarRecord(record, name) { + assert.ok(Buffer.byteLength(name) <= 100); + const changed = Buffer.from(record); + changed.fill(0, 0, 100); + changed.write(name, 0, 'utf8'); + changed.fill(0, 345, 500); + changed.fill(0x20, 148, 156); + let checksum = 0; + for (const byte of changed.subarray(0, 512)) checksum += byte; + changed.write(`${checksum.toString(8).padStart(6, '0')}\0 `, 148, 'ascii'); + return changed; +} + +function writeTar(destination, records) { + writeFileSync(destination, Buffer.concat([...records, Buffer.alloc(1024)])); +} + +if (process.argv[2] === 'prepare') { + const value = fixture(); + writeFileSync(path.join(value.root, 'fixture.json'), JSON.stringify(value)); + writeFileSync( + path.join(value.root, 'registry-fixture.mts'), + ` +globalThis.fetch = async (input, options = {}) => { + if (options.method && options.method !== 'GET') throw new Error('unexpected registry mutation'); + const url = new URL(String(input)); + if (!['crates.io', 'registry.npmjs.org'].includes(url.hostname)) throw new Error('unexpected registry'); + return new Response('{}', {status: url.hostname === 'crates.io' && url.pathname.startsWith('/api/v1/crates/oliphaunt-build/') ? 200 : 404}); +}; +`, + ); + writeFileSync( + path.join(value.root, 'npmrc'), + '//registry.npmjs.org/:_authToken=fixture-not-a-credential\n', + ); + console.log(value.root); + process.exit(0); +} +if (process.argv[2] === 'verify') { + const result = JSON.parse(readFileSync(path.join(process.argv[3], 'execution.json'), 'utf8')); + assert.equal(result.decision, 'deferred'); + assert.equal(result.newlyCompletedIds.length, 0); + assert.equal(result.remainingIds.length, 2); + process.exit(0); +} + +test('packs every locked publication file deterministically and atomically installs it', () => { + const value = fixture(); + const first = path.join(value.root, 'first.tar'); + const second = path.join(value.root, 'second.tar'); + const output = workspace(); + try { + const manifest = packBootstrapCapsule({ + lockFile: value.lockFile, + products: PRODUCTS, + output: first, + }); + packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output: second }); + assert.equal(sha256(first), sha256(second), 'capsule must be byte-for-byte deterministic'); + assert.equal(manifest.approval.releaseRunId, APPROVAL.approvalRunId); + assert.equal(manifest.approval.qualificationRunId, APPROVAL.qualificationRunId); + assert.equal(manifest.files.length, 3); + + const installed = verifyExtractBootstrapCapsule({ + transport: first, + approvedLock: value.lockFile, + products: PRODUCTS, + workspaceRoot: output, + }); + assert.equal(installed.lockDigest, value.lock.lockDigest); + assert.deepEqual( + readFileSync(path.join(output, ...BOOTSTRAP_CAPSULE_LOCK_PATH.split('/'))), + readFileSync(value.lockFile), + ); + assert.equal( + lstatSync(path.join(output, ...BOOTSTRAP_CAPSULE_MANIFEST_PATH.split('/'))).isFile(), + true, + ); + for (const source of [...value.cargo, value.npm]) { + const artifact = manifest.files.find((file) => file.sha256 === sha256(source)); + assert.ok(artifact); + assert.equal(sha256(path.join(output, ...artifact.path.split('/'))), artifact.sha256); + } + } finally { + rmSync(value.root, { recursive: true, force: true }); + rmSync(output, { recursive: true, force: true }); + } +}); + +test('packs and verifies all Maven payloads for a Maven-only release', () => { + const value = mavenOnlyFixture(); + const first = path.join(value.root, 'first.tar'); + const second = path.join(value.root, 'second.tar'); + const output = workspace(); + try { + const manifest = packBootstrapCapsule({ + lockFile: value.lockFile, + products: value.products, + output: first, + }); + packBootstrapCapsule({ lockFile: value.lockFile, products: value.products, output: second }); + assert.ok(manifest.files.length > 0); + assert.equal(sha256(first), sha256(second)); + const installed = verifyExtractBootstrapCapsule({ + transport: first, + approvedLock: value.lockFile, + products: value.products, + workspaceRoot: output, + }); + assert.deepEqual(installed.files, manifest.files); + assert.deepEqual( + readFileSync(path.join(output, ...BOOTSTRAP_CAPSULE_LOCK_PATH.split('/'))), + readFileSync(value.lockFile), + ); + } finally { + rmSync(value.root, { recursive: true, force: true }); + rmSync(output, { recursive: true, force: true }); + } +}); + +test('fails closed on selection drift, external-lock drift, and a preexisting destination', () => { + const value = fixture(); + const capsule = path.join(value.root, 'capsule.tar'); + const output = workspace(); + try { + assert.throws( + () => + packBootstrapCapsule({ + lockFile: value.lockFile, + products: [PRODUCTS[0]], + output: capsule, + }), + /selected products do not exactly match/u, + ); + packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output: capsule }); + assert.throws( + () => + extractCandidate({ + ...APPROVAL, + approvalRunId: '999', + transport: capsule, + approvedLock: value.lockFile, + products: PRODUCTS, + workspaceRoot: output, + }), + /manifest does not exactly describe its approval/u, + ); + const changedLock = path.join(value.root, 'changed-lock.json'); + copyFileSync(value.lockFile, changedLock); + writeFileSync(changedLock, `${readFileSync(changedLock, 'utf8').trimEnd()} \n`); + assert.throws( + () => + verifyExtractBootstrapCapsule({ + transport: capsule, + approvedLock: changedLock, + products: PRODUCTS, + workspaceRoot: output, + }), + /not byte-identical/u, + ); + assert.equal(lstatSync(output).isDirectory(), true); + assert.throws(() => lstatSync(path.join(output, 'target')), /ENOENT/u); + + mkdirSync(path.join(output, 'target')); + assert.throws( + () => + verifyExtractBootstrapCapsule({ + transport: capsule, + approvedLock: value.lockFile, + products: PRODUCTS, + workspaceRoot: output, + }), + /requires an absent destination/u, + ); + } finally { + rmSync(value.root, { recursive: true, force: true }); + rmSync(output, { recursive: true, force: true }); + } +}); + +test('rejects tampered manifests and carrier bytes without installing partial output', () => { + const value = fixture(); + const capsule = path.join(value.root, 'capsule.tar'); + const manifestTamper = path.join(value.root, 'manifest-tamper.tar'); + const carrierTamper = path.join(value.root, 'carrier-tamper.tar'); + const firstOutput = workspace(); + const secondOutput = workspace(); + try { + const manifest = packBootstrapCapsule({ + lockFile: value.lockFile, + products: PRODUCTS, + output: capsule, + }); + mutateTarPayload(capsule, manifestTamper, BOOTSTRAP_CAPSULE_MANIFEST_PATH, (bytes) => { + const marker = Buffer.from('oliphaunt-frozen-publication-candidate-v1'); + const index = bytes.indexOf(marker); + assert.ok(index >= 0); + bytes[index] = 'x'.charCodeAt(0); + return bytes; + }); + mutateTarPayload(capsule, carrierTamper, manifest.files[0].path, (bytes) => { + bytes[Math.floor(bytes.length / 2)] ^= 0xff; + return bytes; + }); + + assert.throws( + () => + verifyExtractBootstrapCapsule({ + transport: manifestTamper, + approvedLock: value.lockFile, + products: PRODUCTS, + workspaceRoot: firstOutput, + }), + /manifest does not exactly describe|file set or bytes differ/u, + ); + assert.throws(() => lstatSync(path.join(firstOutput, 'target')), /ENOENT/u); + assert.throws( + () => + verifyExtractBootstrapCapsule({ + transport: carrierTamper, + approvedLock: value.lockFile, + products: PRODUCTS, + workspaceRoot: secondOutput, + }), + /bytes do not match|file set or bytes differ/u, + ); + assert.throws(() => lstatSync(path.join(secondOutput, 'target')), /ENOENT/u); + } finally { + rmSync(value.root, { recursive: true, force: true }); + rmSync(firstOutput, { recursive: true, force: true }); + rmSync(secondOutput, { recursive: true, force: true }); + } +}); + +test('rejects missing, extra, and unsafe archive members', () => { + const value = fixture(); + const capsule = path.join(value.root, 'capsule.tar'); + const missing = path.join(value.root, 'missing.tar'); + const extra = path.join(value.root, 'extra.tar'); + const unsafe = path.join(value.root, 'unsafe.tar'); + try { + packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output: capsule }); + const records = tarRecords(capsule); + writeTar(missing, records.slice(0, -1)); + writeTar(extra, [...records, renamedTarRecord(records.at(-1), 'target/zzzz-unapproved')]); + writeTar(unsafe, [renamedTarRecord(records[0], '../escape'), ...records.slice(1)]); + for (const [transport, pattern] of [ + [missing, /unavailable|file set or bytes differ/u], + [extra, /file set or bytes differ/u], + [unsafe, /unsafe path component/u], + ]) { + const output = workspace(); + try { + assert.throws( + () => + verifyExtractBootstrapCapsule({ + transport, + approvedLock: value.lockFile, + products: PRODUCTS, + workspaceRoot: output, + }), + pattern, + ); + assert.throws(() => lstatSync(path.join(output, 'target')), /ENOENT/u); + } finally { + rmSync(output, { recursive: true, force: true }); + } + } + } finally { + rmSync(value.root, { recursive: true, force: true }); + } +}); + +test('rejects symlinked frozen inputs before producing a capsule', () => { + const value = fixture(); + const output = path.join(value.root, 'capsule.tar'); + const carrier = value.lock.carriers.find(({ ecosystem }) => ecosystem === 'cargo'); + const artifact = path.resolve(ROOT, carrier.artifacts[0].path); + const replacement = path.join(value.root, 'replacement.crate'); + try { + copyFileSync(artifact, replacement); + unlinkSync(artifact); + symlinkSync(replacement, artifact); + assert.throws( + () => packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output }), + /regular (?:non-symlink )?file|regular file or directory|open .* safely/u, + ); + assert.throws(() => lstatSync(output), /ENOENT/u); + } finally { + rmSync(value.root, { recursive: true, force: true }); + } +}); diff --git a/tools/release/bootstrap-publication-capsule.test.sh b/tools/release/bootstrap-publication-capsule.test.sh new file mode 100644 index 000000000..22cefd99c --- /dev/null +++ b/tools/release/bootstrap-publication-capsule.test.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +if [ "${1:-}" != --context ]; then + for name in "${!GITHUB_@}" "${!GH_@}" "${!ACTIONS_@}" "${!OLIPHAUNT_GITHUB_@}" "${!OLIPHAUNT_RELEASE_@}" "${!RELEASE_@}"; do + [ -z "$name" ] || unset "$name" + done + unset CI_RUN_ID BOOTSTRAP_LEDGER_PATH OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL + exec bash tools/release/release-please-state.sh "$PWD" HEAD \ + bash tools/release/with-source.sh HEAD bash tools/ci/with-projects.sh --exec \ + bash tools/release/bootstrap-publication-capsule.test.sh --context +fi +bun test --timeout=30000 ./tools/release/bootstrap-publication-capsule.test.mts +scratch=$(bun tools/release/bootstrap-publication-capsule.test.mts prepare) +trap 'rm -rf "$scratch"' EXIT +export BUN_OPTIONS="--preload $scratch/registry-fixture.mts" +export PRODUCTS_JSON='["oliphaunt-rust","oliphaunt-js"]' +RELEASE_HEAD_SHA=$(git rev-parse HEAD) +export RELEASE_HEAD_SHA +export PUBLICATION_LOCK_PATH="$scratch/publication-lock.json" BOOTSTRAP_LEDGER_PATH="$scratch/ledger" +export REGISTRY_MUTATION_DEADLINE_EPOCH="$(($(date +%s) + 60))" +export REGISTRY_JOB_HARD_DEADLINE_EPOCH="$(($(date +%s) + 600))" +export CARGO_REGISTRY_TOKEN=fixture-not-a-credential NPM_CONFIG_USERCONFIG="$scratch/npmrc" +export OLIPHAUNT_BOOTSTRAP_EXECUTION_RESULT="$scratch/execution.json" +bash .github/scripts/bootstrap-registry-identities.sh +bun tools/release/bootstrap-publication-capsule.test.mts verify "$scratch" diff --git a/tools/release/bootstrap-publication-executor.mjs b/tools/release/bootstrap-publication-executor.mjs deleted file mode 100644 index 288f89fb8..000000000 --- a/tools/release/bootstrap-publication-executor.mjs +++ /dev/null @@ -1,223 +0,0 @@ -import { isRegistryPublicationDeferredError } from "./registry-publication-deferral.mjs"; - -const ECOSYSTEMS = ["cargo", "npm"]; - -function error(message) { - return new Error(`bootstrap-publication-executor: ${message}`); -} - -function deferred() { - let resolve; - const promise = new Promise((accept) => { - resolve = accept; - }); - return { promise, resolve }; -} - -function validatePlan(plan, satisfiedCarrierIds) { - if (!Array.isArray(plan)) throw error("plan must be a carrier list"); - if ( - !Array.isArray(satisfiedCarrierIds) - || satisfiedCarrierIds.some((id) => typeof id !== "string" || id.length === 0) - || new Set(satisfiedCarrierIds).size !== satisfiedCarrierIds.length - ) { - throw error("satisfied carrier IDs must be a unique string list"); - } - const satisfied = new Set(satisfiedCarrierIds); - const positions = new Map(); - let priorCarrier = null; - for (const [index, carrier] of plan.entries()) { - if ( - carrier === null - || typeof carrier !== "object" - || typeof carrier.id !== "string" - || carrier.id !== `${carrier.ecosystem}:${carrier.name}` - || !ECOSYSTEMS.includes(carrier.ecosystem) - || !Number.isSafeInteger(carrier.publishOrder) - || carrier.publishOrder < 0 - || (priorCarrier !== null && ( - carrier.publishOrder < priorCarrier.publishOrder - || (carrier.publishOrder === priorCarrier.publishOrder && carrier.id <= priorCarrier.id) - )) - ) { - throw error(`carrier ${index} is not in strict canonical publish order`); - } - if (positions.has(carrier.id) || satisfied.has(carrier.id)) { - throw error(`carrier ${carrier.id} is duplicated or already satisfied`); - } - if ( - !Array.isArray(carrier.dependencies) - || new Set(carrier.dependencies).size !== carrier.dependencies.length - || carrier.dependencies.some((dependency) => typeof dependency !== "string" || dependency.length === 0) - ) { - throw error(`carrier ${carrier.id} dependencies must be a unique string list`); - } - positions.set(carrier.id, index); - priorCarrier = carrier; - } - for (const [index, carrier] of plan.entries()) { - for (const dependency of carrier.dependencies) { - const position = positions.get(dependency); - if (position === undefined && !satisfied.has(dependency)) { - throw error(`${carrier.id} refers to unknown unsatisfied dependency ${dependency}`); - } - if (position !== undefined && position >= index) { - throw error(`${carrier.id} is not ordered after dependency ${dependency}`); - } - } - } -} - -function strictBatchSize(value) { - const parsed = typeof value === "number" ? value : Number(value); - if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 128) { - throw error("checkpoint batch size must be an integer from 1 through 128"); - } - return parsed; -} - -function normalizedFailure(cause) { - return cause instanceof Error ? cause : error(String(cause)); -} - -function finalFailure(failures) { - if (failures.length === 1) return failures[0]; - return new AggregateError(failures, "bootstrap publication and/or immutable checkpoint reconciliation failed"); -} - -/** - * Publish one immutable carrier at a time in each independent registry lane. - * Explicit cross-registry dependencies are awaited, while unrelated Cargo and - * npm carriers overlap. Checkpoint callbacks are globally serialized and - * receive only new, unique carrier IDs in canonical plan order. - * - * On any failure no new callback starts after the shared abort is observed. - * The peer lane's one in-flight immutable mutation is allowed to drain, then a - * final checkpoint attempt reconciles every callback that returned success. - */ -export async function executeBootstrapPublicationPlan({ - plan, - satisfiedCarrierIds = [], - publishCarrier, - checkpointCarrierIds, - checkpointBatchSize = 32, -}) { - validatePlan(plan, satisfiedCarrierIds); - if (typeof publishCarrier !== "function" || typeof checkpointCarrierIds !== "function") { - throw error("publishCarrier and checkpointCarrierIds callbacks are required"); - } - const batchSize = strictBatchSize(checkpointBatchSize); - const positions = new Map(plan.map((carrier, index) => [carrier.id, index])); - const completions = new Map(plan.map((carrier) => [carrier.id, deferred()])); - const completed = new Set(); - const checkpointed = new Set(); - const failures = []; - const deferrals = []; - let aborted = false; - let signalAbort; - const abortSignal = new Promise((resolve) => { - signalAbort = resolve; - }); - let checkpointTail = Promise.resolve(); - let checkpointFailed = false; - - function recordOutcome(cause, { allowDeferral = true } = {}) { - const normalized = normalizedFailure(cause); - const failure = !allowDeferral && isRegistryPublicationDeferredError(normalized) - ? error(`typed registry deferral is invalid during immutable checkpoint reconciliation: ${normalized.message}`) - : normalized; - if (allowDeferral && isRegistryPublicationDeferredError(failure)) { - if (!deferrals.includes(failure)) deferrals.push(failure); - } else if (!failures.includes(failure)) { - failures.push(failure); - } - if (!aborted) { - aborted = true; - signalAbort(); - } - return failure; - } - - function requireActive() { - if (aborted) throw failures[0] ?? deferrals[0]; - } - - async function waitForDependencies(carrier) { - requireActive(); - const dependencies = Promise.all(carrier.dependencies - .filter((dependency) => positions.has(dependency)) - .map((dependency) => completions.get(dependency).promise)); - await Promise.race([dependencies, abortSignal]); - requireActive(); - } - - function pendingCheckpointIds() { - return plan.filter(({ id }) => completed.has(id) && !checkpointed.has(id)).map(({ id }) => id); - } - - function serializeCheckpoint({ force, recovery }) { - const task = checkpointTail.then(async () => { - if (checkpointFailed && !recovery) throw failures[0]; - const ids = pendingCheckpointIds(); - if (ids.length === 0 || (!force && ids.length < batchSize)) return; - try { - await checkpointCarrierIds(ids); - } catch (cause) { - checkpointFailed = true; - throw recordOutcome(cause, { allowDeferral: false }); - } - for (const id of ids) checkpointed.add(id); - }); - checkpointTail = task.catch(() => {}); - return task; - } - - async function runLane(ecosystem) { - try { - for (const carrier of plan.filter((candidate) => candidate.ecosystem === ecosystem)) { - await waitForDependencies(carrier); - requireActive(); - await publishCarrier(carrier); - // A peer may have failed while this immutable callback was in flight. - // Its successful result is still checkpointable, but no next mutation - // may start because the next loop iteration observes the shared abort. - completed.add(carrier.id); - completions.get(carrier.id).resolve(); - if (!aborted && pendingCheckpointIds().length >= batchSize) { - await serializeCheckpoint({ force: false, recovery: false }); - } - } - } catch (cause) { - recordOutcome(cause); - } - } - - await Promise.all(ECOSYSTEMS.map(runLane)); - try { - // This recovery flush deliberately retries still-uncheckpointed IDs after - // an earlier checkpoint failure. Appends are immutable/idempotent, and a - // successful retry preserves evidence even though the original failure is - // still reported to the caller. - await serializeCheckpoint({ force: true, recovery: true }); - } catch (cause) { - recordOutcome(cause, { allowDeferral: false }); - } - - if (failures.length > 0) throw finalFailure(failures); - const completedCarrierIds = plan.filter(({ id }) => completed.has(id)).map(({ id }) => id); - const checkpointedCarrierIds = plan.filter(({ id }) => checkpointed.has(id)).map(({ id }) => id); - const remainingCarrierIds = plan.filter(({ id }) => !completed.has(id)).map(({ id }) => id); - const publicationDeferred = deferrals.length > 0; - return { - decision: publicationDeferred ? "deferred" : "complete", - completedCarrierIds, - checkpointedCarrierIds, - remainingCarrierIds, - deferReason: publicationDeferred - ? (deferrals.some(({ reason }) => reason === "deadline") ? "deadline" : "rate-limit") - : null, - notBeforeEpochSeconds: publicationDeferred - ? Math.max(...deferrals.map(({ notBeforeEpochSeconds }) => notBeforeEpochSeconds)) - : null, - }; -} diff --git a/tools/release/bootstrap-publication-executor.test.mjs b/tools/release/bootstrap-publication-executor.test.mjs deleted file mode 100644 index 1e3839303..000000000 --- a/tools/release/bootstrap-publication-executor.test.mjs +++ /dev/null @@ -1,294 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { executeBootstrapPublicationPlan } from "./bootstrap-publication-executor.mjs"; -import { RegistryPublicationDeferredError } from "./registry-publication-deferral.mjs"; - -function carrier(ecosystem, publishOrder, dependencies = []) { - const name = ecosystem === "cargo" ? `crate-${publishOrder}` : `@example/pkg-${publishOrder}`; - return { - id: `${ecosystem}:${name}`, - product: "fixture", - ecosystem, - name, - version: "1.0.0", - publishOrder, - dependencies, - }; -} - -function deferred() { - let resolve; - const promise = new Promise((accept) => { - resolve = accept; - }); - return { promise, resolve }; -} - -describe("bootstrap publication executor", () => { - test("overlaps independent registry lanes, serializes each lane, and checkpoints canonical IDs once", async () => { - const cargoFirst = carrier("cargo", 0); - const npmFirst = carrier("npm", 1); - const cargoSecond = carrier("cargo", 2); - const npmSecond = carrier("npm", 3); - const cargoStarted = deferred(); - const cargoSecondStarted = deferred(); - const npmStarted = deferred(); - const releaseCargo = deferred(); - const releaseNpm = deferred(); - const started = []; - const checkpoints = []; - const run = executeBootstrapPublicationPlan({ - plan: [cargoFirst, npmFirst, cargoSecond, npmSecond], - checkpointBatchSize: 3, - publishCarrier: async ({ id }) => { - started.push(id); - if (id === cargoFirst.id) { - cargoStarted.resolve(); - await releaseCargo.promise; - } else if (id === cargoSecond.id) { - cargoSecondStarted.resolve(); - } else if (id === npmFirst.id) { - npmStarted.resolve(); - await releaseNpm.promise; - } - }, - checkpointCarrierIds: async (ids) => checkpoints.push(ids), - }); - - await Promise.all([cargoStarted.promise, npmStarted.promise]); - expect(started).toEqual([cargoFirst.id, npmFirst.id]); - releaseCargo.resolve(); - await cargoSecondStarted.promise; - expect(started).toContain(cargoSecond.id); - expect(started).not.toContain(npmSecond.id); - releaseNpm.resolve(); - const result = await run; - const canonical = [cargoFirst.id, npmFirst.id, cargoSecond.id, npmSecond.id]; - expect(result.completedCarrierIds).toEqual(canonical); - expect(result.checkpointedCarrierIds).toEqual(canonical); - expect(checkpoints.flat()).toEqual(canonical); - expect(new Set(checkpoints.flat()).size).toBe(canonical.length); - }); - - test("honors cross-registry dependency barriers without deadlock", async () => { - const cargoBefore = carrier("cargo", 0); - const npmMiddle = carrier("npm", 1, [cargoBefore.id]); - const cargoAfter = carrier("cargo", 2, [npmMiddle.id]); - const events = []; - await executeBootstrapPublicationPlan({ - plan: [cargoBefore, npmMiddle, cargoAfter], - publishCarrier: async ({ id }) => events.push(id), - checkpointCarrierIds: async (ids) => events.push(`checkpoint:${ids.join("+")}`), - }); - expect(events).toEqual([ - cargoBefore.id, - npmMiddle.id, - cargoAfter.id, - `checkpoint:${cargoBefore.id}+${npmMiddle.id}+${cargoAfter.id}`, - ]); - }); - - test("drains a peer in-flight mutation and checkpoints it after a publication failure", async () => { - const cargoFirst = carrier("cargo", 0); - const npmFirst = carrier("npm", 1); - const cargoSecond = carrier("cargo", 2); - const npmSecond = carrier("npm", 3); - const cargoStarted = deferred(); - const npmStarted = deferred(); - const releaseCargo = deferred(); - const failNpm = deferred(); - const started = []; - const checkpoints = []; - const run = executeBootstrapPublicationPlan({ - plan: [cargoFirst, npmFirst, cargoSecond, npmSecond], - publishCarrier: async ({ id }) => { - started.push(id); - if (id === cargoFirst.id) { - cargoStarted.resolve(); - await releaseCargo.promise; - } else if (id === npmFirst.id) { - npmStarted.resolve(); - await failNpm.promise; - throw new Error("npm publication failed"); - } - }, - checkpointCarrierIds: async (ids) => checkpoints.push(ids), - }); - await Promise.all([cargoStarted.promise, npmStarted.promise]); - failNpm.resolve(); - await Promise.resolve(); - releaseCargo.resolve(); - await expect(run).rejects.toThrow("npm publication failed"); - expect(started).toEqual([cargoFirst.id, npmFirst.id]); - expect(checkpoints).toEqual([[cargoFirst.id]]); - }); - - test("a checkpoint failure aborts new mutations, drains the peer, and retries only uncheckpointed IDs", async () => { - const cargoFirst = carrier("cargo", 0); - const npmFirst = carrier("npm", 1); - const cargoSecond = carrier("cargo", 2); - const npmSecond = carrier("npm", 3); - const npmStarted = deferred(); - const releaseNpm = deferred(); - const started = []; - const checkpointCalls = []; - let attempts = 0; - const run = executeBootstrapPublicationPlan({ - plan: [cargoFirst, npmFirst, cargoSecond, npmSecond], - checkpointBatchSize: 1, - publishCarrier: async ({ id }) => { - started.push(id); - if (id === npmFirst.id) { - npmStarted.resolve(); - await releaseNpm.promise; - } - }, - checkpointCarrierIds: async (ids) => { - checkpointCalls.push(ids); - attempts += 1; - if (attempts === 1) throw new Error("checkpoint unavailable"); - }, - }); - await npmStarted.promise; - // Cargo's first completion starts the failing checkpoint while npm is in - // flight. Let npm drain only after the shared abort is established. - await Promise.resolve(); - releaseNpm.resolve(); - await expect(run).rejects.toThrow("checkpoint unavailable"); - expect(started).toEqual([cargoFirst.id, npmFirst.id]); - expect(checkpointCalls).toEqual([ - [cargoFirst.id], - [cargoFirst.id, npmFirst.id], - ]); - }); - - test("aggregates a primary publication failure with final checkpoint failure", async () => { - const cargo = carrier("cargo", 0); - const npm = carrier("npm", 1); - const cargoStarted = deferred(); - const releaseCargo = deferred(); - let observed; - try { - await executeBootstrapPublicationPlan({ - plan: [cargo, npm], - publishCarrier: async ({ id }) => { - if (id === cargo.id) { - cargoStarted.resolve(); - await releaseCargo.promise; - return; - } - await cargoStarted.promise; - releaseCargo.resolve(); - throw new Error("npm primary failure"); - }, - checkpointCarrierIds: async () => { - throw new Error("final checkpoint failure"); - }, - }); - } catch (cause) { - observed = cause; - } - expect(observed).toBeInstanceOf(AggregateError); - expect(observed.errors.map(({ message }) => message)).toEqual([ - "npm primary failure", - "final checkpoint failure", - ]); - }); - - test("accepts dependencies already proved public and rejects malformed plans before mutation", async () => { - const satisfied = carrier("cargo", 0); - const pending = carrier("npm", 1, [satisfied.id]); - const calls = []; - await executeBootstrapPublicationPlan({ - plan: [pending], - satisfiedCarrierIds: [satisfied.id], - publishCarrier: async ({ id }) => calls.push(id), - checkpointCarrierIds: async (ids) => calls.push(...ids), - }); - expect(calls).toEqual([pending.id, pending.id]); - - await expect(executeBootstrapPublicationPlan({ - plan: [{ ...pending, dependencies: ["cargo:unknown"] }], - publishCarrier: () => { throw new Error("must not publish"); }, - checkpointCarrierIds: () => { throw new Error("must not checkpoint"); }, - })).rejects.toThrow(/unknown unsatisfied dependency/u); - }); - - test("drains and checkpoints peer progress for a typed rate-limit deferral", async () => { - const cargo = carrier("cargo", 0); - const npm = carrier("npm", 1); - const checkpoints = []; - const result = await executeBootstrapPublicationPlan({ - plan: [cargo, npm], - publishCarrier: async ({ id }) => { - if (id === cargo.id) { - throw new RegistryPublicationDeferredError({ - reason: "rate-limit", - notBeforeEpochSeconds: 1_800_000_000, - context: "explicit crates.io 429 with valid Retry-After", - }); - } - }, - checkpointCarrierIds: async (ids) => checkpoints.push(ids), - }); - expect(result).toEqual({ - decision: "deferred", - completedCarrierIds: [npm.id], - checkpointedCarrierIds: [npm.id], - remainingCarrierIds: [cargo.id], - deferReason: "rate-limit", - notBeforeEpochSeconds: 1_800_000_000, - }); - expect(checkpoints).toEqual([[npm.id]]); - }); - - test("preserves a genuine first-operation 429 as a typed zero-progress rate-limit deferral", async () => { - const cargo = carrier("cargo", 0); - const result = await executeBootstrapPublicationPlan({ - plan: [cargo], - publishCarrier: async () => { - throw new RegistryPublicationDeferredError({ - reason: "rate-limit", - notBeforeEpochSeconds: 1_800_000_060, - context: "explicit crates.io 429 before the first accepted upload", - }); - }, - checkpointCarrierIds: async () => { - throw new Error("zero progress must not create a checkpoint"); - }, - }); - expect(result).toEqual({ - decision: "deferred", - completedCarrierIds: [], - checkpointedCarrierIds: [], - remainingCarrierIds: [cargo.id], - deferReason: "rate-limit", - notBeforeEpochSeconds: 1_800_000_060, - }); - }); - - test("never converts a lookalike or checkpoint failure into a safe deferral", async () => { - const cargo = carrier("cargo", 0); - const lookalike = Object.assign(new Error("ambiguous upload"), { - reason: "rate-limit", - notBeforeEpochSeconds: 1_800_000_000, - }); - await expect(executeBootstrapPublicationPlan({ - plan: [cargo], - publishCarrier: async () => { throw lookalike; }, - checkpointCarrierIds: async () => {}, - })).rejects.toBe(lookalike); - - await expect(executeBootstrapPublicationPlan({ - plan: [cargo], - publishCarrier: async () => {}, - checkpointCarrierIds: async () => { - throw new RegistryPublicationDeferredError({ - reason: "deadline", - notBeforeEpochSeconds: 1_800_000_000, - context: "invalid checkpoint control flow", - }); - }, - })).rejects.toThrow(/invalid during immutable checkpoint reconciliation/u); - }); -}); diff --git a/tools/release/bootstrap-publication-plan.mjs b/tools/release/bootstrap-publication-plan.mjs deleted file mode 100644 index 85c8b0b67..000000000 --- a/tools/release/bootstrap-publication-plan.mjs +++ /dev/null @@ -1,112 +0,0 @@ -import { lockedCarriers } from "./publication-lock.mjs"; - -const BOOTSTRAP_ECOSYSTEMS = new Set(["cargo", "npm"]); - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function error(message) { - return new Error(`bootstrap-publication-plan: ${message}`); -} - -function selectedProducts(lock, products) { - if ( - !Array.isArray(products) - || products.length === 0 - || products.some((product) => typeof product !== "string" || product.length === 0) - || new Set(products).size !== products.length - ) { - throw error("products must be a non-empty unique string list"); - } - const locked = new Set((lock.products ?? []).map(({ id }) => id)); - const unknown = products.filter((product) => !locked.has(product)); - if (unknown.length > 0) { - throw error(`selected products are absent from the publication lock: ${unknown.join(", ")}`); - } - return new Set(products); -} - -export function bootstrapPublicationPlan(lock, products) { - const selected = selectedProducts(lock, products); - const allCarriers = lockedCarriers(lock) - .slice() - .sort((left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id)); - const allById = new Map(allCarriers.map((carrier) => [carrier.id, carrier])); - if (allById.size !== allCarriers.length) { - throw error("publication lock contains duplicate carrier identities"); - } - for (const carrier of allCarriers) { - if ( - typeof carrier.id !== "string" - || typeof carrier.ecosystem !== "string" - || typeof carrier.name !== "string" - || carrier.id !== `${carrier.ecosystem}:${carrier.name}` - ) { - throw error(`invalid locked carrier identity ${JSON.stringify(carrier.id)}`); - } - if (!Array.isArray(carrier.dependencies) || carrier.dependencies.some( - (dependency) => typeof dependency !== "string" || dependency.length === 0, - )) { - throw error(`${carrier.id}.dependencies must be a string list`); - } - } - const carriers = allCarriers - .filter((carrier) => selected.has(carrier.product) && BOOTSTRAP_ECOSYSTEMS.has(carrier.ecosystem)) - .slice(); - if (carriers.length === 0) { - throw error("selected products contain no Cargo or npm identities to bootstrap"); - } - - const positions = new Map(carriers.map((carrier, index) => [carrier.id, index])); - if (positions.size !== carriers.length) { - throw error("bootstrap publication plan contains duplicate carrier identities"); - } - for (const [index, carrier] of carriers.entries()) { - if (!Number.isSafeInteger(carrier.publishOrder) || carrier.publishOrder < 0) { - throw error(`${carrier.id} has invalid publishOrder ${JSON.stringify(carrier.publishOrder)}`); - } - for (const dependency of carrier.dependencies) { - const lockedDependency = allById.get(dependency); - if (lockedDependency === undefined) { - throw error(`${carrier.id} refers to unknown locked dependency ${dependency}`); - } - // Bootstrap only pre-creates immutable-name registries. Maven has no - // separate identity-creation phase, so a resolved dependency in that - // non-bootstrap ecosystem remains intentionally external to this - // plan and is handled by the normal global publication topology. Every - // locked Cargo/npm dependency, however, must be in this exact selection. - if (!BOOTSTRAP_ECOSYSTEMS.has(lockedDependency.ecosystem)) { - continue; - } - const dependencyPosition = positions.get(dependency); - if (dependencyPosition === undefined) { - throw error(`${carrier.id} selection omits locked bootstrap dependency ${dependency}`); - } - if (dependencyPosition >= index) { - throw error(`${carrier.id} appears before bootstrap dependency ${dependency}`); - } - } - } - return carriers.map(({ id, product, ecosystem, name, version, publishOrder, dependencies, packageDependencies }) => ({ - id, - product, - ecosystem, - name, - version, - publishOrder, - dependencies: dependencies.filter((dependency) => BOOTSTRAP_ECOSYSTEMS.has(allById.get(dependency).ecosystem)), - packageDependencies: packageDependencies ?? [], - })); -} - -export function bootstrapCheckpointBatches(plan, batchSize = 32) { - if (!Number.isSafeInteger(batchSize) || batchSize < 1 || batchSize > 128) { - throw error("checkpoint batch size must be an integer from 1 through 128"); - } - const batches = []; - for (let index = 0; index < plan.length; index += batchSize) { - batches.push(plan.slice(index, index + batchSize).map(({ id }) => id)); - } - return batches; -} diff --git a/tools/release/bootstrap-publication-plan.mts b/tools/release/bootstrap-publication-plan.mts new file mode 100644 index 000000000..5de85ab4a --- /dev/null +++ b/tools/release/bootstrap-publication-plan.mts @@ -0,0 +1,141 @@ +import { lockedCarriers } from './publication-lock.mts'; + +const BOOTSTRAP_ECOSYSTEMS = new Set(['cargo', 'npm']); + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function error(message) { + return new Error(`bootstrap-publication-plan: ${message}`); +} + +function selectedProducts(lock, products) { + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string' || product.length === 0) || + new Set(products).size !== products.length + ) { + throw error('products must be a non-empty unique string list'); + } + const locked = new Set((lock.products ?? []).map(({ id }) => id)); + const unknown = products.filter((product) => !locked.has(product)); + if (unknown.length > 0) { + throw error(`selected products are absent from the publication lock: ${unknown.join(', ')}`); + } + return new Set(products); +} + +export function bootstrapPublicationPlan(lock, products) { + const selected = selectedProducts(lock, products); + const allCarriers = lockedCarriers(lock) + .slice() + .sort( + (left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id), + ); + const allById = new Map(allCarriers.map((carrier) => [carrier.id, carrier])); + if (allById.size !== allCarriers.length) { + throw error('publication lock contains duplicate carrier identities'); + } + for (const carrier of allCarriers) { + if ( + typeof carrier.id !== 'string' || + typeof carrier.ecosystem !== 'string' || + typeof carrier.name !== 'string' || + carrier.id !== `${carrier.ecosystem}:${carrier.name}` + ) { + throw error(`invalid locked carrier identity ${JSON.stringify(carrier.id)}`); + } + if ( + !Array.isArray(carrier.dependencies) || + carrier.dependencies.some( + (dependency) => typeof dependency !== 'string' || dependency.length === 0, + ) + ) { + throw error(`${carrier.id}.dependencies must be a string list`); + } + } + const carriers = allCarriers + .filter( + (carrier) => selected.has(carrier.product) && BOOTSTRAP_ECOSYSTEMS.has(carrier.ecosystem), + ) + .slice(); + if (carriers.length === 0) { + throw error('selected products contain no Cargo or npm identities to bootstrap'); + } + + const positions = new Map(carriers.map((carrier, index) => [carrier.id, index])); + if (positions.size !== carriers.length) { + throw error('bootstrap publication plan contains duplicate carrier identities'); + } + for (const [index, carrier] of carriers.entries()) { + if (!Number.isSafeInteger(carrier.publishOrder) || carrier.publishOrder < 0) { + throw error(`${carrier.id} has invalid publishOrder ${JSON.stringify(carrier.publishOrder)}`); + } + for (const dependency of carrier.dependencies) { + const lockedDependency = allById.get(dependency); + if (lockedDependency === undefined) { + throw error(`${carrier.id} refers to unknown locked dependency ${dependency}`); + } + // Bootstrap only pre-creates immutable-name registries. Maven has no + // separate identity-creation phase, so a resolved dependency in that + // non-bootstrap ecosystem remains intentionally external to this + // plan and is handled by the normal global publication topology. Every + // locked Cargo/npm dependency, however, must be in this exact selection. + if (!BOOTSTRAP_ECOSYSTEMS.has(lockedDependency.ecosystem)) { + continue; + } + const dependencyPosition = positions.get(dependency); + if (dependencyPosition === undefined) { + throw error(`${carrier.id} selection omits locked bootstrap dependency ${dependency}`); + } + if (dependencyPosition >= index) { + throw error(`${carrier.id} appears before bootstrap dependency ${dependency}`); + } + } + } + return carriers.map( + ({ + id, + product, + ecosystem, + name, + version, + publishOrder, + dependencies, + packageDependencies, + }) => ({ + id, + product, + ecosystem, + name, + version, + publishOrder, + dependencies: dependencies.filter((dependency) => + BOOTSTRAP_ECOSYSTEMS.has(allById.get(dependency).ecosystem), + ), + packageDependencies: packageDependencies ?? [], + }), + ); +} + +// The admitted subset must retain every dependency not already proven public. +export function bootstrapPublicationSchedule(plan, satisfiedCarrierIds) { + const satisfied = new Set(satisfiedCarrierIds); + const positions = new Map(plan.map((carrier, index) => [carrier.id, index])); + if (positions.size !== plan.length || plan.some((carrier) => satisfied.has(carrier.id))) + throw error('admitted bootstrap carriers must be unique and not already satisfied'); + return plan.map((carrier, index) => + carrier.dependencies.flatMap((id) => { + const dependency = positions.get(id); + if (dependency === undefined) { + if (!satisfied.has(id)) + throw error(carrier.id + ' refers to unknown unsatisfied dependency ' + id); + return []; + } + if (dependency >= index) throw error(carrier.id + ' is not ordered after dependency ' + id); + return [dependency]; + }), + ); +} diff --git a/tools/release/bootstrap-publication-plan.test.mjs b/tools/release/bootstrap-publication-plan.test.mjs deleted file mode 100644 index 5a27726cd..000000000 --- a/tools/release/bootstrap-publication-plan.test.mjs +++ /dev/null @@ -1,197 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { - bootstrapCheckpointBatches, - bootstrapPublicationPlan, -} from "./bootstrap-publication-plan.mjs"; -import { - loadPublicationCatalog, - resolveActualCarrier, -} from "./publication-catalog.mjs"; - -function lock(carriers) { - return { - products: [{ id: "runtime" }, { id: "extension" }, { id: "sdk" }], - carriers, - }; -} - -describe("registry identity bootstrap publication plan", () => { - test("uses frozen carrier order across product boundaries", () => { - const plan = bootstrapPublicationPlan(lock([ - { - id: "cargo:runtime", - product: "runtime", - ecosystem: "cargo", - name: "runtime", - version: "0.1.0", - publishOrder: 2, - dependencies: ["cargo:extension"], - }, - { - id: "npm:@example/sdk", - product: "sdk", - ecosystem: "npm", - name: "@example/sdk", - version: "0.1.0", - publishOrder: 3, - dependencies: [], - }, - { - id: "cargo:extension", - product: "extension", - ecosystem: "cargo", - name: "extension", - version: "0.1.0", - publishOrder: 1, - dependencies: [], - }, - { - id: "maven:dev.example:runtime", - product: "runtime", - ecosystem: "maven", - name: "dev.example:runtime", - version: "0.1.0", - publishOrder: 0, - dependencies: [], - }, - ]), ["runtime", "extension", "sdk"]); - - expect(plan.map(({ id }) => id)).toEqual([ - "cargo:extension", - "cargo:runtime", - "npm:@example/sdk", - ]); - expect(plan.find(({ id }) => id === "cargo:runtime").dependencies).toEqual(["cargo:extension"]); - expect(bootstrapCheckpointBatches(plan, 2)).toEqual([ - ["cargo:extension", "cargo:runtime"], - ["npm:@example/sdk"], - ]); - }); - - test("rejects a frozen order that precedes an internal dependency", () => { - expect(() => bootstrapPublicationPlan(lock([ - { - id: "cargo:runtime", - product: "runtime", - ecosystem: "cargo", - name: "runtime", - version: "0.1.0", - publishOrder: 0, - dependencies: ["cargo:extension"], - }, - { - id: "cargo:extension", - product: "extension", - ecosystem: "cargo", - name: "extension", - version: "0.1.0", - publishOrder: 1, - dependencies: [], - }, - ]), ["runtime", "extension"])).toThrow(/appears before bootstrap dependency/u); - }); - - test("rejects omitted and unknown locked Cargo/npm dependencies", () => { - const omitted = lock([ - { - id: "cargo:runtime", - product: "runtime", - ecosystem: "cargo", - name: "runtime", - version: "0.1.0", - publishOrder: 0, - dependencies: [], - }, - { - id: "cargo:sdk", - product: "sdk", - ecosystem: "cargo", - name: "sdk", - version: "0.1.0", - publishOrder: 1, - dependencies: ["cargo:runtime"], - }, - ]); - expect(() => bootstrapPublicationPlan(omitted, ["sdk"])) - .toThrow(/selection omits locked bootstrap dependency cargo:runtime/u); - - const unknown = lock([ - { - id: "npm:@example/sdk", - product: "sdk", - ecosystem: "npm", - name: "@example/sdk", - version: "0.1.0", - publishOrder: 0, - dependencies: ["npm:@example/missing"], - }, - ]); - expect(() => bootstrapPublicationPlan(unknown, ["sdk"])) - .toThrow(/refers to unknown locked dependency npm:@example\/missing/u); - }); - - test("keeps resolved Maven dependencies external to identity bootstrap", () => { - const plan = bootstrapPublicationPlan(lock([ - { - id: "maven:dev.example:runtime", - product: "runtime", - ecosystem: "maven", - name: "dev.example:runtime", - version: "0.1.0", - publishOrder: 0, - dependencies: [], - }, - { - id: "cargo:sdk", - product: "sdk", - ecosystem: "cargo", - name: "sdk", - version: "0.1.0", - publishOrder: 1, - dependencies: ["maven:dev.example:runtime"], - }, - ]), ["sdk"]); - expect(plan.map(({ id }) => id)).toEqual(["cargo:sdk"]); - expect(plan[0].dependencies).toEqual([]); - }); - - test("the complete real catalog closes over every Cargo/npm bootstrap carrier", () => { - const catalog = loadPublicationCatalog("bootstrap-publication-plan.test"); - const splitParent = catalog.carriers.find(({ ecosystem, role }) => - ecosystem === "cargo" && role === "platform-leaf" - ); - const splitPart = resolveActualCarrier( - catalog, - "cargo", - `${splitParent.name}-part-001`, - "bootstrap-publication-plan.test", - ); - const frozenCarriers = catalog.carriers.flatMap((carrier) => - carrier.id === splitParent.id - ? [splitPart, { ...carrier, dependencies: [splitPart.id] }] - : [{ ...carrier, dependencies: [] }] - ); - const frozen = { - products: catalog.products, - carriers: frozenCarriers.map((carrier, publishOrder) => ({ - ...carrier, - publishOrder, - dependencies: carrier.dependencies ?? [], - })), - }; - const plan = bootstrapPublicationPlan( - frozen, - catalog.products.map(({ id }) => id), - ); - const expected = frozen.carriers.filter(({ ecosystem }) => ecosystem === "cargo" || ecosystem === "npm"); - expect(plan.filter(({ ecosystem }) => ecosystem === "cargo")).toHaveLength( - expected.filter(({ ecosystem }) => ecosystem === "cargo").length, - ); - expect(plan.filter(({ ecosystem }) => ecosystem === "npm")).toHaveLength( - expected.filter(({ ecosystem }) => ecosystem === "npm").length, - ); - expect(plan.map(({ id }) => id)).toContain(splitPart.id); - expect(plan.map(({ id }) => id)).toEqual(expected.map(({ id }) => id)); - }); -}); diff --git a/tools/release/bootstrap-publication-plan.test.mts b/tools/release/bootstrap-publication-plan.test.mts new file mode 100644 index 000000000..61570a76b --- /dev/null +++ b/tools/release/bootstrap-publication-plan.test.mts @@ -0,0 +1,207 @@ +import { describe, expect, test } from 'bun:test'; +import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; +import { + bootstrapPublicationPlan, + bootstrapPublicationSchedule, +} from './bootstrap-publication-plan.mts'; + +function lock(carriers) { + return { + products: [{ id: 'runtime' }, { id: 'extension' }, { id: 'sdk' }], + carriers, + }; +} + +describe('registry identity bootstrap publication plan', () => { + test('uses frozen carrier order across product boundaries', () => { + const plan = bootstrapPublicationPlan( + lock([ + { + id: 'cargo:runtime', + product: 'runtime', + ecosystem: 'cargo', + name: 'runtime', + version: '0.1.0', + publishOrder: 2, + dependencies: ['cargo:extension'], + }, + { + id: 'npm:@example/sdk', + product: 'sdk', + ecosystem: 'npm', + name: '@example/sdk', + version: '0.1.0', + publishOrder: 3, + dependencies: [], + }, + { + id: 'cargo:extension', + product: 'extension', + ecosystem: 'cargo', + name: 'extension', + version: '0.1.0', + publishOrder: 1, + dependencies: [], + }, + { + id: 'maven:dev.example:runtime', + product: 'runtime', + ecosystem: 'maven', + name: 'dev.example:runtime', + version: '0.1.0', + publishOrder: 0, + dependencies: [], + }, + ]), + ['runtime', 'extension', 'sdk'], + ); + + expect(plan.map(({ id }) => id)).toEqual([ + 'cargo:extension', + 'cargo:runtime', + 'npm:@example/sdk', + ]); + expect(plan.find(({ id }) => id === 'cargo:runtime').dependencies).toEqual(['cargo:extension']); + expect(bootstrapPublicationSchedule(plan, [])).toEqual([[], [0], []]); + expect(() => bootstrapPublicationSchedule(plan.slice(1), [])).toThrow('unsatisfied dependency'); + expect(bootstrapPublicationSchedule(plan.slice(1), [plan[0].id])).toEqual([[], []]); + }); + + test('rejects a frozen order that precedes an internal dependency', () => { + expect(() => + bootstrapPublicationPlan( + lock([ + { + id: 'cargo:runtime', + product: 'runtime', + ecosystem: 'cargo', + name: 'runtime', + version: '0.1.0', + publishOrder: 0, + dependencies: ['cargo:extension'], + }, + { + id: 'cargo:extension', + product: 'extension', + ecosystem: 'cargo', + name: 'extension', + version: '0.1.0', + publishOrder: 1, + dependencies: [], + }, + ]), + ['runtime', 'extension'], + ), + ).toThrow(/appears before bootstrap dependency/u); + }); + + test('rejects omitted and unknown locked Cargo/npm dependencies', () => { + const omitted = lock([ + { + id: 'cargo:runtime', + product: 'runtime', + ecosystem: 'cargo', + name: 'runtime', + version: '0.1.0', + publishOrder: 0, + dependencies: [], + }, + { + id: 'cargo:sdk', + product: 'sdk', + ecosystem: 'cargo', + name: 'sdk', + version: '0.1.0', + publishOrder: 1, + dependencies: ['cargo:runtime'], + }, + ]); + expect(() => bootstrapPublicationPlan(omitted, ['sdk'])).toThrow( + /selection omits locked bootstrap dependency cargo:runtime/u, + ); + + const unknown = lock([ + { + id: 'npm:@example/sdk', + product: 'sdk', + ecosystem: 'npm', + name: '@example/sdk', + version: '0.1.0', + publishOrder: 0, + dependencies: ['npm:@example/missing'], + }, + ]); + expect(() => bootstrapPublicationPlan(unknown, ['sdk'])).toThrow( + /refers to unknown locked dependency npm:@example\/missing/u, + ); + }); + + test('keeps resolved Maven dependencies external to identity bootstrap', () => { + const plan = bootstrapPublicationPlan( + lock([ + { + id: 'maven:dev.example:runtime', + product: 'runtime', + ecosystem: 'maven', + name: 'dev.example:runtime', + version: '0.1.0', + publishOrder: 0, + dependencies: [], + }, + { + id: 'cargo:sdk', + product: 'sdk', + ecosystem: 'cargo', + name: 'sdk', + version: '0.1.0', + publishOrder: 1, + dependencies: ['maven:dev.example:runtime'], + }, + ]), + ['sdk'], + ); + expect(plan.map(({ id }) => id)).toEqual(['cargo:sdk']); + expect(plan[0].dependencies).toEqual([]); + }); + + test('the complete real catalog closes over every Cargo/npm bootstrap carrier', () => { + const catalog = loadPublicationCatalog('bootstrap-publication-plan.test'); + const splitParent = catalog.carriers.find( + ({ ecosystem, role }) => ecosystem === 'cargo' && role === 'platform-leaf', + ); + const splitPart = resolveActualCarrier( + catalog, + 'cargo', + `${splitParent.name}-part-001`, + 'bootstrap-publication-plan.test', + ); + const frozenCarriers = catalog.carriers.flatMap((carrier) => + carrier.id === splitParent.id + ? [splitPart, { ...carrier, dependencies: [splitPart.id] }] + : [{ ...carrier, dependencies: [] }], + ); + const frozen = { + products: catalog.products, + carriers: frozenCarriers.map((carrier, publishOrder) => ({ + ...carrier, + publishOrder, + dependencies: carrier.dependencies ?? [], + })), + }; + const plan = bootstrapPublicationPlan( + frozen, + catalog.products.map(({ id }) => id), + ); + const expected = frozen.carriers.filter( + ({ ecosystem }) => ecosystem === 'cargo' || ecosystem === 'npm', + ); + expect(plan.filter(({ ecosystem }) => ecosystem === 'cargo')).toHaveLength( + expected.filter(({ ecosystem }) => ecosystem === 'cargo').length, + ); + expect(plan.filter(({ ecosystem }) => ecosystem === 'npm')).toHaveLength( + expected.filter(({ ecosystem }) => ecosystem === 'npm').length, + ); + expect(plan.map(({ id }) => id)).toContain(splitPart.id); + expect(plan.map(({ id }) => id)).toEqual(expected.map(({ id }) => id)); + }); +}); diff --git a/tools/release/bootstrap-registry-credential-env.test.mjs b/tools/release/bootstrap-registry-credential-env.test.mjs deleted file mode 100644 index 19b1e7c08..000000000 --- a/tools/release/bootstrap-registry-credential-env.test.mjs +++ /dev/null @@ -1,51 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { bootstrapCarrierEnvironment } from "../../.github/scripts/bootstrap-registry-credential-env.mjs"; - -const parent = Object.freeze({ - CARGO_REGISTRIES_CRATES_IO_TOKEN: "cargo-alias", - CARGO_REGISTRY_TOKEN: "cargo-primary", - CRATES_IO_BOOTSTRAP_TOKEN: "cargo-bootstrap", - CRATES_IO_TRUST_CONFIG_TOKEN: "cargo-trust", - NODE_AUTH_TOKEN: "npm-node", - NPM_BOOTSTRAP_TOKEN: "npm-bootstrap", - NPM_CONFIG__AUTH: "npm-auth", - NPM_CONFIG__AUTHTOKEN: "npm-auth-token", - NPM_CONFIG_USERCONFIG: "/private/bootstrap.npmrc", - NPM_TOKEN: "npm-token", - RELEASE_HEAD_SHA: "a".repeat(40), -}); - -test("Cargo bootstrap children cannot read npm bootstrap credentials", () => { - const environment = bootstrapCarrierEnvironment("cargo", parent); - assert.equal(environment.CARGO_REGISTRY_TOKEN, "cargo-primary"); - assert.equal(environment.RELEASE_HEAD_SHA, parent.RELEASE_HEAD_SHA); - for (const name of [ - "NODE_AUTH_TOKEN", - "NPM_BOOTSTRAP_TOKEN", - "NPM_CONFIG__AUTH", - "NPM_CONFIG__AUTHTOKEN", - "NPM_CONFIG_USERCONFIG", - "NPM_TOKEN", - ]) assert.equal(Object.hasOwn(environment, name), false, name); -}); - -test("npm bootstrap children cannot read Cargo bootstrap credentials", () => { - const environment = bootstrapCarrierEnvironment("npm", parent); - assert.equal(environment.NPM_CONFIG_USERCONFIG, "/private/bootstrap.npmrc"); - assert.equal(environment.RELEASE_HEAD_SHA, parent.RELEASE_HEAD_SHA); - for (const name of [ - "CARGO_REGISTRIES_CRATES_IO_TOKEN", - "CARGO_REGISTRY_TOKEN", - "CRATES_IO_BOOTSTRAP_TOKEN", - "CRATES_IO_TRUST_CONFIG_TOKEN", - ]) assert.equal(Object.hasOwn(environment, name), false, name); -}); - -test("bootstrap credential routing rejects any unplanned registry lane", () => { - assert.throws( - () => bootstrapCarrierEnvironment("maven", parent), - /unsupported bootstrap credential ecosystem/u, - ); -}); diff --git a/tools/release/bootstrap-registry-reconciliation.mjs b/tools/release/bootstrap-registry-reconciliation.mjs deleted file mode 100644 index 8150e92b8..000000000 --- a/tools/release/bootstrap-registry-reconciliation.mjs +++ /dev/null @@ -1,203 +0,0 @@ -function error(message) { - return new Error(`bootstrap-registry-reconciliation: ${message}`); -} - -function identityKey(name, version) { - return `${name}\0${version}`; -} - -function requiredIdentity(value, context) { - if ( - value === null - || Array.isArray(value) - || typeof value !== "object" - || typeof value.name !== "string" - || value.name.length === 0 - || typeof value.version !== "string" - || value.version.length === 0 - ) { - throw error(`${context} must contain a package name and exact version`); - } - return identityKey(value.name, value.version); -} - -function uniqueSet(values, context) { - const result = new Set(values); - if (result.size !== values.length) throw error(`${context} contains duplicates`); - return result; -} - -function sameSet(left, right) { - return left.size === right.size && [...left].every((value) => right.has(value)); -} - -function inventoryStates(ecosystem, expectedCarriers, inventory) { - if ( - inventory === null - || Array.isArray(inventory) - || typeof inventory !== "object" - || !Array.isArray(inventory.selectedIdentities) - || !Array.isArray(inventory.publishedIdentities) - || !Array.isArray(inventory.pendingVersions) - || !Array.isArray(inventory.missingNames) - ) { - throw error(`${ecosystem} inventory must contain selected, published, pending-version, and missing-name lists`); - } - const expectedKeys = uniqueSet( - expectedCarriers.map(({ name, version }, index) => requiredIdentity({ name, version }, `${ecosystem} plan entry ${index}`)), - `${ecosystem} plan`, - ); - const selectedKeys = uniqueSet( - inventory.selectedIdentities.map((identity, index) => requiredIdentity(identity, `${ecosystem} selected identity ${index}`)), - `${ecosystem} selected identities`, - ); - if (!sameSet(expectedKeys, selectedKeys)) { - throw error(`${ecosystem} inventory selection does not exactly match the frozen bootstrap plan`); - } - - const published = uniqueSet( - inventory.publishedIdentities.map((identity, index) => requiredIdentity(identity, `${ecosystem} published identity ${index}`)), - `${ecosystem} published identities`, - ); - const pendingVersions = uniqueSet( - inventory.pendingVersions.map((identity, index) => requiredIdentity(identity, `${ecosystem} pending version ${index}`)), - `${ecosystem} pending versions`, - ); - const byName = new Map(expectedCarriers.map((carrier) => [carrier.name, carrier])); - if (byName.size !== expectedCarriers.length) { - throw error(`${ecosystem} bootstrap plan contains duplicate package names`); - } - const missingNames = uniqueSet(inventory.missingNames.map((name, index) => { - if (typeof name !== "string" || name.length === 0) { - throw error(`${ecosystem} missing name ${index} must be a non-empty string`); - } - if (!byName.has(name)) throw error(`${ecosystem} inventory contains unknown missing name ${name}`); - return name; - }), `${ecosystem} missing names`); - - const states = new Map(); - for (const carrier of expectedCarriers) { - const key = identityKey(carrier.name, carrier.version); - const matches = Number(published.has(key)) + Number(pendingVersions.has(key)) + Number(missingNames.has(carrier.name)); - if (matches !== 1) { - throw error(`${carrier.id} must have exactly one registry inventory state, observed ${matches}`); - } - if (published.has(key)) states.set(carrier.id, "published"); - else if (pendingVersions.has(key)) states.set(carrier.id, "pending-version"); - else states.set(carrier.id, "missing-name"); - } - for (const key of [...published, ...pendingVersions]) { - if (!expectedKeys.has(key)) throw error(`${ecosystem} inventory contains an identity outside the frozen bootstrap plan`); - } - return states; -} - -export function reconcileBootstrapRegistryState({ - plan, - cargoInventory, - npmInventory, - checkpoint = null, -}) { - if ( - !Array.isArray(plan) - || plan.length === 0 - || plan.some((carrier) => - carrier === null - || Array.isArray(carrier) - || typeof carrier !== "object" - || typeof carrier.id !== "string" - || carrier.id !== `${carrier.ecosystem}:${carrier.name}` - || !["cargo", "npm"].includes(carrier.ecosystem) - || typeof carrier.version !== "string" - || carrier.version.length === 0) - ) { - throw error("bootstrap plan must contain valid Cargo/npm carrier identities"); - } - if (new Set(plan.map(({ id }) => id)).size !== plan.length) { - throw error("bootstrap plan contains duplicate carrier IDs"); - } - - const cargo = plan.filter(({ ecosystem }) => ecosystem === "cargo"); - const npm = plan.filter(({ ecosystem }) => ecosystem === "npm"); - const states = new Map([ - ...inventoryStates("Cargo", cargo, cargoInventory), - ...inventoryStates("npm", npm, npmInventory), - ]); - const publicCarrierIds = plan.filter(({ id }) => states.get(id) === "published").map(({ id }) => id); - const missingCarriers = plan.filter(({ id }) => states.get(id) === "missing-name"); - const existingNameCarriers = plan.filter(({ id }) => states.get(id) === "pending-version"); - - if (checkpoint !== null) { - if ( - Array.isArray(checkpoint) - || typeof checkpoint !== "object" - || !Array.isArray(checkpoint.receipts) - ) { - throw error("validated bootstrap checkpoint must contain receipts"); - } - const planIds = new Set(plan.map(({ id }) => id)); - for (const receipt of checkpoint.receipts) { - if (!planIds.has(receipt?.id)) { - throw error(`bootstrap checkpoint contains receipt outside the active plan: ${String(receipt?.id)}`); - } - if (states.get(receipt.id) !== "published") { - throw error(`${receipt.id} has an immutable receipt but its exact registry version is not public`); - } - } - } - - return { - publicCarrierIds, - missingCarriers, - existingNameCarriers, - receiptedCarrierIds: checkpoint?.receipts.map(({ id }) => id) ?? [], - }; -} - -export function resolveBootstrapScope(plan, reconciliation, checkpoint = null) { - const scopeIds = checkpoint?.publications.map(({ id }) => id) - ?? reconciliation.missingCarriers.map(({ id }) => id); - if (scopeIds.length === 0) { - throw error("the approved candidate has no absent Cargo/npm package names to bootstrap; use normal publish"); - } - const scope = new Set(scopeIds); - const scopedPlan = plan.filter(({ id }) => scope.has(id)); - if (scopedPlan.length !== scope.size) { - throw error("bootstrap ledger scope contains a carrier outside the exact canonical plan"); - } - const scopeConflicts = reconciliation.existingNameCarriers.filter(({ id }) => scope.has(id)); - if (scopeConflicts.length > 0) { - throw error( - `bootstrap-scoped package names now exist without the locked exact version: ${scopeConflicts.map(({ id }) => id).join(", ")}`, - ); - } - const outsideMissing = reconciliation.missingCarriers.filter(({ id }) => !scope.has(id)); - if (outsideMissing.length > 0) { - throw error(`registry names disappeared outside the immutable bootstrap scope: ${outsideMissing.map(({ id }) => id).join(", ")}`); - } - const publicIds = new Set(reconciliation.publicCarrierIds); - const existingIds = new Set(reconciliation.existingNameCarriers.map(({ id }) => id)); - return scopedPlan.map((carrier) => ({ - ...carrier, - dependencies: carrier.dependencies.filter((dependency) => { - if (scope.has(dependency)) return true; - if (publicIds.has(dependency)) return false; - if (!existingIds.has(dependency)) { - throw error(`${carrier.id} depends on an unknown carrier outside the bootstrap scope: ${dependency}`); - } - const [ecosystem, ...nameParts] = dependency.split(":"); - const name = nameParts.join(":"); - const optionalNpmDependency = carrier.ecosystem === "npm" - && ecosystem === "npm" - && carrier.packageDependencies?.some((row) => - row.ecosystem === "npm" && row.name === name && row.scope === "optional" - ); - if (!optionalNpmDependency) { - throw error( - `${carrier.id} cannot bootstrap before existing-name dependency ${dependency} reaches its locked version`, - ); - } - return false; - }), - })); -} diff --git a/tools/release/bootstrap-registry-reconciliation.mts b/tools/release/bootstrap-registry-reconciliation.mts new file mode 100644 index 000000000..e19f09fa0 --- /dev/null +++ b/tools/release/bootstrap-registry-reconciliation.mts @@ -0,0 +1,241 @@ +function error(message) { + return new Error(`bootstrap-registry-reconciliation: ${message}`); +} + +function identityKey(name, version) { + return `${name}\0${version}`; +} + +function requiredIdentity(value, context) { + if ( + value === null || + Array.isArray(value) || + typeof value !== 'object' || + typeof value.name !== 'string' || + value.name.length === 0 || + typeof value.version !== 'string' || + value.version.length === 0 + ) { + throw error(`${context} must contain a package name and exact version`); + } + return identityKey(value.name, value.version); +} + +function uniqueSet(values, context) { + const result = new Set(values); + if (result.size !== values.length) throw error(`${context} contains duplicates`); + return result; +} + +function sameSet(left, right) { + return left.size === right.size && [...left].every((value) => right.has(value)); +} + +function inventoryStates(ecosystem, expectedCarriers, inventory) { + if ( + inventory === null || + Array.isArray(inventory) || + typeof inventory !== 'object' || + !Array.isArray(inventory.selectedIdentities) || + !Array.isArray(inventory.publishedIdentities) || + !Array.isArray(inventory.pendingVersions) || + !Array.isArray(inventory.missingNames) + ) { + throw error( + `${ecosystem} inventory must contain selected, published, pending-version, and missing-name lists`, + ); + } + const expectedKeys = uniqueSet( + expectedCarriers.map(({ name, version }, index) => + requiredIdentity({ name, version }, `${ecosystem} plan entry ${index}`), + ), + `${ecosystem} plan`, + ); + const selectedKeys = uniqueSet( + inventory.selectedIdentities.map((identity, index) => + requiredIdentity(identity, `${ecosystem} selected identity ${index}`), + ), + `${ecosystem} selected identities`, + ); + if (!sameSet(expectedKeys, selectedKeys)) { + throw error( + `${ecosystem} inventory selection does not exactly match the frozen bootstrap plan`, + ); + } + + const published = uniqueSet( + inventory.publishedIdentities.map((identity, index) => + requiredIdentity(identity, `${ecosystem} published identity ${index}`), + ), + `${ecosystem} published identities`, + ); + const pendingVersions = uniqueSet( + inventory.pendingVersions.map((identity, index) => + requiredIdentity(identity, `${ecosystem} pending version ${index}`), + ), + `${ecosystem} pending versions`, + ); + const byName = new Map(expectedCarriers.map((carrier) => [carrier.name, carrier])); + if (byName.size !== expectedCarriers.length) { + throw error(`${ecosystem} bootstrap plan contains duplicate package names`); + } + const missingNames = uniqueSet( + inventory.missingNames.map((name, index) => { + if (typeof name !== 'string' || name.length === 0) { + throw error(`${ecosystem} missing name ${index} must be a non-empty string`); + } + if (!byName.has(name)) + throw error(`${ecosystem} inventory contains unknown missing name ${name}`); + return name; + }), + `${ecosystem} missing names`, + ); + + const states = new Map(); + for (const carrier of expectedCarriers) { + const key = identityKey(carrier.name, carrier.version); + const matches = + Number(published.has(key)) + + Number(pendingVersions.has(key)) + + Number(missingNames.has(carrier.name)); + if (matches !== 1) { + throw error( + `${carrier.id} must have exactly one registry inventory state, observed ${matches}`, + ); + } + if (published.has(key)) states.set(carrier.id, 'published'); + else if (pendingVersions.has(key)) states.set(carrier.id, 'pending-version'); + else states.set(carrier.id, 'missing-name'); + } + for (const key of [...published, ...pendingVersions]) { + if (!expectedKeys.has(key)) + throw error(`${ecosystem} inventory contains an identity outside the frozen bootstrap plan`); + } + return states; +} + +export function reconcileBootstrapRegistryState({ + plan, + cargoInventory, + npmInventory, + checkpoint = null, +}) { + if ( + !Array.isArray(plan) || + plan.length === 0 || + plan.some( + (carrier) => + carrier === null || + Array.isArray(carrier) || + typeof carrier !== 'object' || + typeof carrier.id !== 'string' || + carrier.id !== `${carrier.ecosystem}:${carrier.name}` || + !['cargo', 'npm'].includes(carrier.ecosystem) || + typeof carrier.version !== 'string' || + carrier.version.length === 0, + ) + ) { + throw error('bootstrap plan must contain valid Cargo/npm carrier identities'); + } + if (new Set(plan.map(({ id }) => id)).size !== plan.length) { + throw error('bootstrap plan contains duplicate carrier IDs'); + } + + const cargo = plan.filter(({ ecosystem }) => ecosystem === 'cargo'); + const npm = plan.filter(({ ecosystem }) => ecosystem === 'npm'); + const states = new Map([ + ...inventoryStates('Cargo', cargo, cargoInventory), + ...inventoryStates('npm', npm, npmInventory), + ]); + const publicCarrierIds = plan + .filter(({ id }) => states.get(id) === 'published') + .map(({ id }) => id); + const missingCarriers = plan.filter(({ id }) => states.get(id) === 'missing-name'); + const existingNameCarriers = plan.filter(({ id }) => states.get(id) === 'pending-version'); + + if (checkpoint !== null) { + if ( + Array.isArray(checkpoint) || + typeof checkpoint !== 'object' || + !Array.isArray(checkpoint.receipts) + ) { + throw error('validated bootstrap checkpoint must contain receipts'); + } + const planIds = new Set(plan.map(({ id }) => id)); + for (const receipt of checkpoint.receipts) { + if (!planIds.has(receipt?.id)) { + throw error( + `bootstrap checkpoint contains receipt outside the active plan: ${String(receipt?.id)}`, + ); + } + if (states.get(receipt.id) !== 'published') { + throw error( + `${receipt.id} has an immutable receipt but its exact registry version is not public`, + ); + } + } + } + + return { + publicCarrierIds, + missingCarriers, + existingNameCarriers, + receiptedCarrierIds: checkpoint?.receipts.map(({ id }) => id) ?? [], + }; +} + +export function resolveBootstrapScope(plan, reconciliation, checkpoint = null) { + const scopeIds = + checkpoint?.publications.map(({ id }) => id) ?? + reconciliation.missingCarriers.map(({ id }) => id); + if (scopeIds.length === 0) { + throw error( + 'the approved candidate has no absent Cargo/npm package names to bootstrap; use normal publish', + ); + } + const scope = new Set(scopeIds); + const scopedPlan = plan.filter(({ id }) => scope.has(id)); + if (scopedPlan.length !== scope.size) { + throw error('bootstrap ledger scope contains a carrier outside the exact canonical plan'); + } + const scopeConflicts = reconciliation.existingNameCarriers.filter(({ id }) => scope.has(id)); + if (scopeConflicts.length > 0) { + throw error( + `bootstrap-scoped package names now exist without the locked exact version: ${scopeConflicts.map(({ id }) => id).join(', ')}`, + ); + } + const outsideMissing = reconciliation.missingCarriers.filter(({ id }) => !scope.has(id)); + if (outsideMissing.length > 0) { + throw error( + `registry names disappeared outside the immutable bootstrap scope: ${outsideMissing.map(({ id }) => id).join(', ')}`, + ); + } + const publicIds = new Set(reconciliation.publicCarrierIds); + const existingIds = new Set(reconciliation.existingNameCarriers.map(({ id }) => id)); + return scopedPlan.map((carrier) => ({ + ...carrier, + dependencies: carrier.dependencies.filter((dependency) => { + if (scope.has(dependency)) return true; + if (publicIds.has(dependency)) return false; + if (!existingIds.has(dependency)) { + throw error( + `${carrier.id} depends on an unknown carrier outside the bootstrap scope: ${dependency}`, + ); + } + const [ecosystem, ...nameParts] = dependency.split(':'); + const name = nameParts.join(':'); + const optionalNpmDependency = + carrier.ecosystem === 'npm' && + ecosystem === 'npm' && + carrier.packageDependencies?.some( + (row) => row.ecosystem === 'npm' && row.name === name && row.scope === 'optional', + ); + if (!optionalNpmDependency) { + throw error( + `${carrier.id} cannot bootstrap before existing-name dependency ${dependency} reaches its locked version`, + ); + } + return false; + }), + })); +} diff --git a/tools/release/bootstrap-registry-reconciliation.test.mjs b/tools/release/bootstrap-registry-reconciliation.test.mjs deleted file mode 100644 index 0e3fec6c5..000000000 --- a/tools/release/bootstrap-registry-reconciliation.test.mjs +++ /dev/null @@ -1,204 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { - reconcileBootstrapRegistryState, - resolveBootstrapScope, -} from "./bootstrap-registry-reconciliation.mjs"; -import { assessCratesIoBootstrapCapacity } from "./crates-io-bootstrap-capacity.mjs"; - -function carrier(ecosystem, index) { - const name = ecosystem === "cargo" ? `crate-${index}` : `@oliphaunt/pkg-${index}`; - return { - id: `${ecosystem}:${name}`, - product: "fixture", - ecosystem, - name, - version: "1.0.0", - publishOrder: index, - dependencies: [], - packageDependencies: [], - }; -} - -function identity({ name, version }) { - return { name, version }; -} - -describe("bootstrap registry reconciliation", () => { - test("scoped execution admits mixed registry inventories and resumes without losing missing identities", () => { - const plan = [0, 1, 2].map((index) => carrier("cargo", index)) - .concat([3, 4, 5].map((index) => carrier("npm", index))); - const inventory = (rows) => ({ - selectedIdentities: rows.map(identity), - publishedIdentities: [identity(rows[0])], - pendingVersions: [identity(rows[1])], - missingNames: [rows[2].name], - }); - const cargoInventory = inventory(plan.slice(0, 3)); - const npmInventory = inventory(plan.slice(3)); - const reconciliation = reconcileBootstrapRegistryState({ plan, cargoInventory, npmInventory, checkpoint: null }); - const scoped = resolveBootstrapScope(plan, reconciliation, null); - const assess = (bootstrapPlan) => assessCratesIoBootstrapCapacity({ - inventory: cargoInventory, npmInventory, bootstrapPlan, - nowEpochSeconds: 1000, deadlineEpochSeconds: 20800, - }); - expect(scoped.map(({ id }) => id)).toEqual([plan[2].id, plan[5].id]); - const admitted = assess(scoped); - expect(admitted.admittedCarrierIds).toEqual(scoped.map(({ id }) => id)); - expect(admitted.initialCargoTokens).toBe(0); - expect(() => assess(scoped.slice(1))).toThrow(/disagrees with the exact version inventory/u); - expect(() => assess(scoped.map((row) => ({ ...row, version: "9.0.0" })))).toThrow(/version disagrees/u); - cargoInventory.publishedIdentities.push(identity(plan[2])); - cargoInventory.missingNames = []; - const checkpoint = { publications: scoped.map(({ id }) => ({ id })), receipts: [{ id: plan[2].id }] }; - // Preserve the original frozen scope while the public inventory advances. - expect(assess(scoped).admittedCarrierIds).toEqual([plan[5].id]); - expect(reconcileBootstrapRegistryState({ plan, cargoInventory, npmInventory, checkpoint }).missingCarriers.map(({ id }) => id)) - .toEqual([plan[5].id]); - }); - test("a 630/631 resume executes only the one still-absent name", () => { - const cargo = Array.from({ length: 417 }, (_, index) => carrier("cargo", index)); - const npm = Array.from({ length: 214 }, (_, index) => carrier("npm", 417 + index)); - const plan = [...cargo, ...npm]; - const publicCarriers = plan.slice(0, 630); - const checkpoint = { - receipts: publicCarriers.map(({ id }) => ({ id })), - }; - const result = reconcileBootstrapRegistryState({ - plan, - cargoInventory: { - selectedIdentities: cargo.map(identity), - publishedIdentities: cargo.map(identity), - pendingVersions: [], - missingNames: [], - }, - npmInventory: { - selectedIdentities: npm.map(identity), - publishedIdentities: npm.slice(0, 213).map(identity), - pendingVersions: [], - missingNames: [npm[213].name], - }, - checkpoint, - }); - - expect(result.publicCarrierIds).toHaveLength(630); - expect(result.receiptedCarrierIds).toHaveLength(630); - expect(result.missingCarriers.map(({ id }) => id)).toEqual([npm[213].id]); - expect(result.existingNameCarriers).toEqual([]); - }); - - test("keeps existing names on the normal trusted-publication path", () => { - const cargo = carrier("cargo", 0); - const npm = carrier("npm", 1); - const result = reconcileBootstrapRegistryState({ - plan: [cargo, npm], - cargoInventory: { - selectedIdentities: [identity(cargo)], - publishedIdentities: [], - pendingVersions: [identity(cargo)], - missingNames: [], - }, - npmInventory: { - selectedIdentities: [identity(npm)], - publishedIdentities: [], - pendingVersions: [identity(npm)], - missingNames: [], - }, - }); - - expect(result.missingCarriers).toEqual([]); - expect(result.existingNameCarriers.map(({ id }) => id)).toEqual([cargo.id, npm.id]); - }); - - test("scopes mixed releases to absent names and preserves that scope across reruns", () => { - const existing = carrier("cargo", 0); - const missing = carrier("npm", 1); - const plan = [existing, missing]; - const reconciliation = reconcileBootstrapRegistryState({ - plan, - cargoInventory: { - selectedIdentities: [identity(existing)], - publishedIdentities: [], - pendingVersions: [identity(existing)], - missingNames: [], - }, - npmInventory: { - selectedIdentities: [identity(missing)], - publishedIdentities: [], - pendingVersions: [], - missingNames: [missing.name], - }, - }); - - expect(resolveBootstrapScope(plan, reconciliation).map(({ id }) => id)).toEqual([missing.id]); - expect(() => resolveBootstrapScope(plan, { - ...reconciliation, - existingNameCarriers: [existing, missing], - missingCarriers: [], - }, { publications: [missing] })).toThrow(/bootstrap-scoped package names now exist/u); - }); - - test("allows only optional npm dependencies to wait on normal existing-name publication", () => { - const existing = carrier("npm", 0); - const missing = { - ...carrier("npm", 1), - dependencies: [existing.id], - packageDependencies: [{ - ecosystem: "npm", - name: existing.name, - requirement: "1.0.0", - scope: "optional", - }], - }; - const reconciliation = { - publicCarrierIds: [], - missingCarriers: [missing], - existingNameCarriers: [existing], - }; - - expect(resolveBootstrapScope([existing, missing], reconciliation)[0].dependencies).toEqual([]); - expect(() => resolveBootstrapScope([existing, { - ...missing, - packageDependencies: [{ ...missing.packageDependencies[0], scope: "runtime" }], - }], reconciliation)).toThrow(/cannot bootstrap before existing-name dependency/u); - }); - - test("rejects a restored receipt unless its frozen exact version is public", () => { - const cargo = carrier("cargo", 0); - expect(() => reconcileBootstrapRegistryState({ - plan: [cargo], - cargoInventory: { - selectedIdentities: [identity(cargo)], - publishedIdentities: [], - pendingVersions: [], - missingNames: [cargo.name], - }, - npmInventory: { - selectedIdentities: [], - publishedIdentities: [], - pendingVersions: [], - missingNames: [], - }, - checkpoint: { receipts: [{ id: cargo.id }] }, - })).toThrow(/immutable receipt.*exact registry version is not public/u); - }); - - test("rejects inventories that do not exactly partition the frozen plan", () => { - const cargo = carrier("cargo", 0); - expect(() => reconcileBootstrapRegistryState({ - plan: [cargo], - cargoInventory: { - selectedIdentities: [identity(cargo)], - publishedIdentities: [identity(cargo)], - pendingVersions: [identity(cargo)], - missingNames: [], - }, - npmInventory: { - selectedIdentities: [], - publishedIdentities: [], - pendingVersions: [], - missingNames: [], - }, - })).toThrow(/must have exactly one registry inventory state/u); - }); -}); diff --git a/tools/release/bootstrap-registry-reconciliation.test.mts b/tools/release/bootstrap-registry-reconciliation.test.mts new file mode 100644 index 000000000..015fe3d6b --- /dev/null +++ b/tools/release/bootstrap-registry-reconciliation.test.mts @@ -0,0 +1,245 @@ +import { describe, expect, test } from 'bun:test'; + +import { + reconcileBootstrapRegistryState, + resolveBootstrapScope, +} from './bootstrap-registry-reconciliation.mts'; +import { assessCratesIoBootstrapCapacity } from './crates-io-bootstrap-capacity.mts'; + +function carrier(ecosystem, index) { + const name = ecosystem === 'cargo' ? `crate-${index}` : `@oliphaunt/pkg-${index}`; + return { + id: `${ecosystem}:${name}`, + product: 'fixture', + ecosystem, + name, + version: '1.0.0', + publishOrder: index, + dependencies: [], + packageDependencies: [], + }; +} + +function identity({ name, version }) { + return { name, version }; +} + +describe('bootstrap registry reconciliation', () => { + test('scoped execution admits mixed registry inventories and resumes without losing missing identities', () => { + const plan = [0, 1, 2] + .map((index) => carrier('cargo', index)) + .concat([3, 4, 5].map((index) => carrier('npm', index))); + const inventory = (rows) => ({ + selectedIdentities: rows.map(identity), + publishedIdentities: [identity(rows[0])], + pendingVersions: [identity(rows[1])], + missingNames: [rows[2].name], + }); + const cargoInventory = inventory(plan.slice(0, 3)); + const npmInventory = inventory(plan.slice(3)); + const reconciliation = reconcileBootstrapRegistryState({ + plan, + cargoInventory, + npmInventory, + checkpoint: null, + }); + const scoped = resolveBootstrapScope(plan, reconciliation, null); + const assess = (bootstrapPlan) => + assessCratesIoBootstrapCapacity({ + inventory: cargoInventory, + npmInventory, + bootstrapPlan, + nowEpochSeconds: 1000, + deadlineEpochSeconds: 20800, + }); + expect(scoped.map(({ id }) => id)).toEqual([plan[2].id, plan[5].id]); + const admitted = assess(scoped); + expect(admitted.admittedCarrierIds).toEqual(scoped.map(({ id }) => id)); + expect(admitted.initialCargoTokens).toBe(0); + expect(() => assess(scoped.slice(1))).toThrow(/disagrees with the exact version inventory/u); + expect(() => assess(scoped.map((row) => ({ ...row, version: '9.0.0' })))).toThrow( + /version disagrees/u, + ); + cargoInventory.publishedIdentities.push(identity(plan[2])); + cargoInventory.missingNames = []; + const checkpoint = { + publications: scoped.map(({ id }) => ({ id })), + receipts: [{ id: plan[2].id }], + }; + // Preserve the original frozen scope while the public inventory advances. + expect(assess(scoped).admittedCarrierIds).toEqual([plan[5].id]); + expect( + reconcileBootstrapRegistryState({ + plan, + cargoInventory, + npmInventory, + checkpoint, + }).missingCarriers.map(({ id }) => id), + ).toEqual([plan[5].id]); + }); + test('a 630/631 resume executes only the one still-absent name', () => { + const cargo = Array.from({ length: 417 }, (_, index) => carrier('cargo', index)); + const npm = Array.from({ length: 214 }, (_, index) => carrier('npm', 417 + index)); + const plan = [...cargo, ...npm]; + const publicCarriers = plan.slice(0, 630); + const checkpoint = { + receipts: publicCarriers.map(({ id }) => ({ id })), + }; + const result = reconcileBootstrapRegistryState({ + plan, + cargoInventory: { + selectedIdentities: cargo.map(identity), + publishedIdentities: cargo.map(identity), + pendingVersions: [], + missingNames: [], + }, + npmInventory: { + selectedIdentities: npm.map(identity), + publishedIdentities: npm.slice(0, 213).map(identity), + pendingVersions: [], + missingNames: [npm[213].name], + }, + checkpoint, + }); + + expect(result.publicCarrierIds).toHaveLength(630); + expect(result.receiptedCarrierIds).toHaveLength(630); + expect(result.missingCarriers.map(({ id }) => id)).toEqual([npm[213].id]); + expect(result.existingNameCarriers).toEqual([]); + }); + + test('keeps existing names on the normal trusted-publication path', () => { + const cargo = carrier('cargo', 0); + const npm = carrier('npm', 1); + const result = reconcileBootstrapRegistryState({ + plan: [cargo, npm], + cargoInventory: { + selectedIdentities: [identity(cargo)], + publishedIdentities: [], + pendingVersions: [identity(cargo)], + missingNames: [], + }, + npmInventory: { + selectedIdentities: [identity(npm)], + publishedIdentities: [], + pendingVersions: [identity(npm)], + missingNames: [], + }, + }); + + expect(result.missingCarriers).toEqual([]); + expect(result.existingNameCarriers.map(({ id }) => id)).toEqual([cargo.id, npm.id]); + }); + + test('scopes mixed releases to absent names and preserves that scope across reruns', () => { + const existing = carrier('cargo', 0); + const missing = carrier('npm', 1); + const plan = [existing, missing]; + const reconciliation = reconcileBootstrapRegistryState({ + plan, + cargoInventory: { + selectedIdentities: [identity(existing)], + publishedIdentities: [], + pendingVersions: [identity(existing)], + missingNames: [], + }, + npmInventory: { + selectedIdentities: [identity(missing)], + publishedIdentities: [], + pendingVersions: [], + missingNames: [missing.name], + }, + }); + + expect(resolveBootstrapScope(plan, reconciliation).map(({ id }) => id)).toEqual([missing.id]); + expect(() => + resolveBootstrapScope( + plan, + { + ...reconciliation, + existingNameCarriers: [existing, missing], + missingCarriers: [], + }, + { publications: [missing] }, + ), + ).toThrow(/bootstrap-scoped package names now exist/u); + }); + + test('allows only optional npm dependencies to wait on normal existing-name publication', () => { + const existing = carrier('npm', 0); + const missing = { + ...carrier('npm', 1), + dependencies: [existing.id], + packageDependencies: [ + { + ecosystem: 'npm', + name: existing.name, + requirement: '1.0.0', + scope: 'optional', + }, + ], + }; + const reconciliation = { + publicCarrierIds: [], + missingCarriers: [missing], + existingNameCarriers: [existing], + }; + + expect(resolveBootstrapScope([existing, missing], reconciliation)[0].dependencies).toEqual([]); + expect(() => + resolveBootstrapScope( + [ + existing, + { + ...missing, + packageDependencies: [{ ...missing.packageDependencies[0], scope: 'runtime' }], + }, + ], + reconciliation, + ), + ).toThrow(/cannot bootstrap before existing-name dependency/u); + }); + + test('rejects a restored receipt unless its frozen exact version is public', () => { + const cargo = carrier('cargo', 0); + expect(() => + reconcileBootstrapRegistryState({ + plan: [cargo], + cargoInventory: { + selectedIdentities: [identity(cargo)], + publishedIdentities: [], + pendingVersions: [], + missingNames: [cargo.name], + }, + npmInventory: { + selectedIdentities: [], + publishedIdentities: [], + pendingVersions: [], + missingNames: [], + }, + checkpoint: { receipts: [{ id: cargo.id }] }, + }), + ).toThrow(/immutable receipt.*exact registry version is not public/u); + }); + + test('rejects inventories that do not exactly partition the frozen plan', () => { + const cargo = carrier('cargo', 0); + expect(() => + reconcileBootstrapRegistryState({ + plan: [cargo], + cargoInventory: { + selectedIdentities: [identity(cargo)], + publishedIdentities: [identity(cargo)], + pendingVersions: [identity(cargo)], + missingNames: [], + }, + npmInventory: { + selectedIdentities: [], + publishedIdentities: [], + pendingVersions: [], + missingNames: [], + }, + }), + ).toThrow(/must have exactly one registry inventory state/u); + }); +}); diff --git a/tools/release/bootstrap-shell.test.mts b/tools/release/bootstrap-shell.test.mts new file mode 100644 index 000000000..7abd40303 --- /dev/null +++ b/tools/release/bootstrap-shell.test.mts @@ -0,0 +1,53 @@ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { bootstrapPublicationSchedule } from './bootstrap-publication-plan.mts'; + +const [mode, root, scenario] = process.argv.slice(2); +if (mode === 'prepare') { + const admittedPlan = Array.from({ length: 35 }, (_, index) => { + const ecosystem = [1, 34].includes(index) ? 'npm' : 'cargo'; + const dependencies = + index === 1 + ? ['cargo:p0'] + : index === 3 + ? ['npm:p1'] + : index >= 4 + ? [`cargo:p${index - 1}`] + : []; + return { + id: `${ecosystem}:p${index}`, + name: `p${index}`, + ecosystem, + publishOrder: index, + dependencies, + }; + }); + writeFileSync( + path.join(root, 'plan.json'), + JSON.stringify({ admittedPlan, dependencies: bootstrapPublicationSchedule(admittedPlan, []) }), + ); +} else if (mode === 'assert') { + const events = readFileSync(path.join(root, `${scenario}.log`), 'utf8') + .trim() + .split('\n'); + assert(events.includes('cargo-drained')); + const checkpoints = events.filter((event) => event.startsWith('checkpoint-')); + if (scenario === 'success') { + assert(checkpoints.length >= 2); + assert.equal(checkpoints.at(-1), 'checkpoint-35'); + } + if (scenario === 'mutation-failure' || scenario === 'deferral') { + assert(!events.includes('cargo-3')); + assert.equal(checkpoints.at(-1), 'checkpoint-2'); + assert(events.indexOf('cargo-drained') < events.indexOf('checkpoint-2')); + } + if (scenario === 'checkpoint-failure') { + assert(checkpoints.length >= 2); + assert(!events.includes('finish')); + } + if (scenario === 'deferral') { + assert(events.includes('deferred')); + assert(!events.includes('npm-publish')); + } +} else throw Error('expected prepare or assert'); diff --git a/tools/release/bootstrap-shell.test.sh b/tools/release/bootstrap-shell.test.sh new file mode 100644 index 000000000..d873678e2 --- /dev/null +++ b/tools/release/bootstrap-shell.test.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +source_root="$PWD" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +mkdir -p "$scratch/.github/scripts" "$scratch/tools/dev" "$scratch/tools/release" "$scratch/bin" +cp .github/scripts/bootstrap-registry-identities.sh "$scratch/.github/scripts/" +printf '#!/usr/bin/env bash\nshift\nexec "$@"\n' > "$scratch/tools/release/with-source.sh" +bun tools/release/bootstrap-shell.test.mts prepare "$scratch" +cat > "$scratch/tools/dev/bun.sh" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +phase="$2"; state="$3"; index="${4:-}" +event() { echo "$*" >> "$BOOT_FIXTURE_LOG"; } +case "$phase" in + --prepare) cp "$BOOT_FIXTURE_ROOT/plan.json" "$state/context.json" ;; + --checkpoint) + shopt -s nullglob; files=("$state"/operation-*.json); count="${#files[@]}" + event "checkpoint-$count" + if [[ "$BOOT_FIXTURE_MODE" == checkpoint-failure && ! -f "$state/tried" ]]; then : > "$state/tried"; exit 9; fi + echo "$count" > "$state/checkpoint-count" ;; + --finish) + if [[ -f "$state/status-1" && "$(cat "$state/status-1")" != 0 ]]; then + [[ "$(cat "$state/status-1")" == 75 ]] || exit 9 + event deferred + fi + [[ ! -f "$state/checkpoint-failed" ]] || exit 9 + event finish ;; + bootstrap-cargo) + [[ -z "${NPM_TOKEN:-}${NPM_CONFIG_USERCONFIG:-}${NODE_AUTH_TOKEN:-}" && "$CARGO_REGISTRY_TOKEN" == cargo-fixture ]] + if [[ "$index" == 2 ]]; then + event cargo-start; : > "$state/cargo-start" + until [[ -f "$state/npm-start" ]]; do sleep 0.01; done + sleep 0.15 + event cargo-drained + fi + echo '{}' > "$state/operation-$index.json"; event "cargo-$index" ;; + bootstrap-npm-before) + [[ -z "${CARGO_REGISTRY_TOKEN:-}${CRATES_IO_BOOTSTRAP_TOKEN:-}" && "$NPM_TOKEN" == npm-fixture ]] + : > "$state/npm-start" + if [[ "$index" == 1 && "$BOOT_FIXTURE_MODE" == deferral ]]; then + until [[ -f "$state/cargo-start" ]]; do sleep 0.01; done + event npm-deferred; exit 75 + fi + jq -n '{tarball:"frozen.tgz",registry:"https://registry.npmjs.org",timeout:2000}' > "$state/npm-$index.json" ;; + bootstrap-npm-after) + if [[ "$index" == 1 ]]; then + until [[ -f "$state/cargo-start" ]]; do sleep 0.01; done + if [[ "$BOOT_FIXTURE_MODE" == mutation-failure ]]; then event npm-failed; exit 9; fi + fi + echo '{}' > "$state/operation-$index.json"; event "npm-$index" ;; + *) exit 21 ;; +esac +SH +cat > "$scratch/bin/npm" <<'SH' +#!/usr/bin/env bash +[[ "$*" == 'publish frozen.tgz --access public --provenance --registry https://registry.npmjs.org' && "$NPM_CONFIG_FETCH_RETRIES" == 0 ]] || exit 22 +echo npm-publish >> "$BOOT_FIXTURE_LOG" +exit 7 +SH +chmod +x "$scratch/bin/npm" +deadline="$(command -v gtimeout || command -v timeout)" +for scenario in success mutation-failure deferral checkpoint-failure; do + status=0 + PATH="$scratch/bin:$PATH" BOOT_FIXTURE_ROOT="$scratch" BOOT_FIXTURE_LOG="$scratch/$scenario.log" BOOT_FIXTURE_MODE="$scenario" \ + RELEASE_HEAD_SHA=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa PUBLICATION_LOCK_PATH=lock.json BOOTSTRAP_LEDGER_PATH=ledger \ + CARGO_REGISTRY_TOKEN=cargo-fixture CRATES_IO_BOOTSTRAP_TOKEN=cargo-fixture NPM_TOKEN=npm-fixture \ + NODE_AUTH_TOKEN=npm-fixture NPM_CONFIG_USERCONFIG=fixture-npmrc \ + "$deadline" 15 bash "$scratch/.github/scripts/bootstrap-registry-identities.sh" > "$scratch/result" 2>&1 || status=$? + case "$scenario" in + success|deferral) [[ "$status" == 0 ]] || { cat "$scratch/result" >&2; exit 1; } ;; + *) [[ "$status" != 0 && "$status" != 124 ]] ;; + esac + bun "$source_root/tools/release/bootstrap-shell.test.mts" assert "$scratch" "$scenario" +done +echo 'Bootstrap lanes: credential isolation, batch checkpoints, deferral and draining passed' diff --git a/tools/release/bounded-gunzip-to-file.mjs b/tools/release/bounded-gunzip-to-file.mjs deleted file mode 100644 index d1ca1a965..000000000 --- a/tools/release/bounded-gunzip-to-file.mjs +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env node - -import { createReadStream, createWriteStream } from "node:fs"; -import { Transform } from "node:stream"; -import { pipeline } from "node:stream/promises"; -import { createGunzip } from "node:zlib"; - -const [input, output, rawLimit] = process.argv.slice(2); -const limit = Number(rawLimit); -if ( - typeof input !== "string" - || typeof output !== "string" - || !Number.isSafeInteger(limit) - || limit <= 0 -) { - throw new Error("bounded-gunzip-to-file.mjs requires "); -} - -let expanded = 0; -const bound = new Transform({ - transform(chunk, _encoding, callback) { - expanded += chunk.length; - if (expanded > limit) { - callback(new Error(`expanded gzip stream exceeds ${limit} bytes`)); - return; - } - callback(null, chunk); - }, -}); - -await pipeline( - createReadStream(input), - createGunzip(), - bound, - createWriteStream(output, { flags: "wx", mode: 0o600 }), -); diff --git a/tools/release/broker-carrier-notice-contract.test.mjs b/tools/release/broker-carrier-notice-contract.test.mjs deleted file mode 100644 index b5fd90f47..000000000 --- a/tools/release/broker-carrier-notice-contract.test.mjs +++ /dev/null @@ -1,39 +0,0 @@ -import assert from "node:assert/strict"; -import { readFileSync, readdirSync } from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { BROKER_PAYLOAD_LICENSE } from "./broker-dependency-license-contract.mjs"; -import { releaseNoticeRows } from "./release-notices.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -const NOTICE_MEMBERS = releaseNoticeRows({ profile: "broker" }).map((row) => row.member); - -function children(relative, manifest) { - return readdirSync(path.join(ROOT, relative), { withFileTypes: true }) - .filter((entry) => entry.isDirectory()) - .map((entry) => path.join(ROOT, relative, entry.name, manifest)) - .sort(); -} - -test("source broker is MIT while every compiled target carrier declares its complete payload license", () => { - const sourceCargo = Bun.TOML.parse(readFileSync(path.join(ROOT, "src/runtimes/broker/Cargo.toml"), "utf8")); - assert.equal(sourceCargo.package.license, "MIT"); - - for (const file of children("src/runtimes/broker/packages", "package.json")) { - const packageJson = JSON.parse(readFileSync(file, "utf8")); - assert.equal(packageJson.license, BROKER_PAYLOAD_LICENSE, file); - for (const member of NOTICE_MEMBERS) { - assert.ok(packageJson.files.includes(member), `${file} must include ${member}`); - } - assert.ok(packageJson.files.includes("THIRD_PARTY_LICENSES"), `${file} must include the exact dependency license tree`); - } - for (const file of children("src/runtimes/broker/crates", "Cargo.toml")) { - const cargo = Bun.TOML.parse(readFileSync(file, "utf8")); - assert.equal(cargo.package.license, BROKER_PAYLOAD_LICENSE, file); - for (const member of NOTICE_MEMBERS) { - assert.ok(cargo.package.include.includes(member), `${file} must include ${member}`); - } - assert.ok(cargo.package.include.includes("THIRD_PARTY_LICENSES/**"), `${file} must include the exact dependency license tree`); - } -}); diff --git a/tools/release/broker-dependency-license-contract.mjs b/tools/release/broker-dependency-license-contract.mjs deleted file mode 100644 index 111b47f3e..000000000 --- a/tools/release/broker-dependency-license-contract.mjs +++ /dev/null @@ -1,927 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { - chmodSync, - lstatSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { requireSafeDirectoryChain as requireReleaseDirectoryChain } from "./release-directory-safety.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { assertReleaseNoticesInEntries } from "./release-notices.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const TOOL = "broker-dependency-license-contract.mjs"; -const CONTRACT_PATH = path.join(ROOT, "src/runtimes/broker/dependency-licenses.json"); -const BLOB_ROOT = path.join(ROOT, "src/runtimes/broker/dependency-license-blobs"); -const CARGO_LOCK_PATH = path.join(ROOT, "Cargo.lock"); -const CARGO_SOURCE = "registry+https://github.com/rust-lang/crates.io-index"; -const CONTRACT_SCHEMA = "oliphaunt-broker-dependency-license-contract-v1"; -const INDEX_SCHEMA = "oliphaunt-broker-target-dependency-license-index-v1"; - -export const BROKER_DEPENDENCY_LICENSE_ROOT = "THIRD_PARTY_LICENSES/rust"; -export const BROKER_PAYLOAD_LICENSE = - "MIT AND ISC AND Unicode-3.0"; -// Cargo fetches every target's locked dependency closure when --target is -// omitted. Keep this exact command centralized: using the host target here -// would leave the Windows/macOS/Linux conditional graph only partly cached. -export const BROKER_DEPENDENCY_LICENSE_FETCH_ARGS = Object.freeze(["fetch", "--locked"]); - -const TARGET_ROWS = Object.freeze([ - Object.freeze({ id: "linux-x64-gnu", cargoTarget: "x86_64-unknown-linux-gnu" }), - Object.freeze({ id: "linux-arm64-gnu", cargoTarget: "aarch64-unknown-linux-gnu" }), - Object.freeze({ id: "macos-arm64", cargoTarget: "aarch64-apple-darwin" }), - Object.freeze({ id: "windows-x64-msvc", cargoTarget: "x86_64-pc-windows-msvc" }), -]); -const TARGET_IDS = Object.freeze(TARGET_ROWS.map(({ id }) => id)); -const TARGET_BY_ID = new Map(TARGET_ROWS.map((row) => [row.id, row])); -const PAYLOAD_LICENSE_ATOMS = Object.freeze([ - "MIT", - "ISC", - "Unicode-3.0", -]); -const PATH_PACKAGE_MANIFESTS = new Map([ - ["oliphaunt", path.join(ROOT, "src/sdks/rust/Cargo.toml")], - ["oliphaunt-broker", path.join(ROOT, "src/runtimes/broker/Cargo.toml")], -]); -const LEGAL_BASENAME_PREFIXES = Object.freeze([ - "acknowledg", - "authors", - "copying", - "copyright", - "credits", - "legal", - "license", - "notice", - "patents", - "unlicense", -]); -const LEGAL_BASENAME_FRAGMENTS = Object.freeze(["third-party", "third_party", "thirdparty"]); -const HEX_64 = /^[0-9a-f]{64}$/u; -const PACKAGE_KEY = /^[a-zA-Z0-9_][a-zA-Z0-9_.-]*@[^\s/\\]+$/u; -const SAFE_MEMBER = /^(?!\/)(?![A-Za-z]:)(?!.*(?:^|\/)\.\.(?:\/|$))(?!.*\\)(?!.*[\u0000-\u001f\u007f])[^/]+(?:\/[^/]+)*$/u; - -let validatedDefaultContract; -let auditedDefaultContract; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function sha256(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function renderBase64(bytes) { - return `${bytes.toString("base64").match(/.{1,76}/gu)?.join("\n") ?? ""}\n`; -} - -function canonicalBlobBytes(digest, expectedBytes) { - const file = path.join(BLOB_ROOT, `${digest}.base64`); - requireRealFile(file, "canonical broker dependency license blob"); - const encoded = readFileSync(file, "utf8"); - if (!/^(?:[A-Za-z0-9+/=]{1,76}\n)+$/u.test(encoded)) { - fail(`canonical broker dependency license blob is not wrapped base64 text: ${file}`); - } - const content = Buffer.from(encoded.replaceAll("\n", ""), "base64"); - if ( - content.length !== expectedBytes - || sha256(content) !== digest - || encoded !== renderBase64(content) - ) { - fail(`canonical broker dependency license blob does not match ${digest}/${expectedBytes}: ${file}`); - } - return content; -} - -function packageKey(row) { - return `${row.name}@${row.version}`; -} - -export function isAllowedBrokerPathPackageMetadataRow(row) { - if ( - !row - || typeof row !== "object" - || row.source !== null - || typeof row.name !== "string" - || typeof row.version !== "string" - || row.version.length === 0 - || typeof row.manifest_path !== "string" - ) { - return false; - } - const expectedManifest = PATH_PACKAGE_MANIFESTS.get(row.name); - return expectedManifest !== undefined && path.resolve(row.manifest_path) === expectedManifest; -} - -function sameStrings(actual, expected) { - return JSON.stringify(actual) === JSON.stringify(expected); -} - -function exactObjectKeys(value, expected, label) { - if (!value || typeof value !== "object" || Array.isArray(value)) { - fail(`${label} must be an object`); - } - const actual = Object.keys(value); - if (!sameStrings(actual, expected)) { - fail(`${label} keys must be ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`); - } -} - -export function hasCanonicalBrokerFilesystemMode(mode, expectedMode, platform = process.platform) { - // Windows exposes synthetic Unix permission bits through stat(2). chmod can - // toggle the read-only attribute, but it cannot establish meaningful 0644 - // or 0755 filesystem metadata. Published archives still carry and validate - // their explicit portable modes in assertBrokerDependencyLicensesInEntries. - return platform === "win32" || (mode & 0o777) === expectedMode; -} - -export function hasSafeBrokerSourceFilesystemMode(mode, platform = process.platform) { - if (platform === "win32") return true; - const permissions = mode & 0o777; - // Git records only the executable bit for regular files; checkout read/write - // bits reflect the host umask. Staged and archived members are normalized and - // verified as exact 0644, so source inputs need only be readable and non-executable. - return (permissions & 0o444) !== 0 && (permissions & 0o111) === 0; -} - -function requireRealFile(file, label) { - let stat; - try { - stat = lstatSync(file); - } catch (cause) { - fail(`${label} cannot be inspected: ${file}: ${cause.message}`); - } - if (!stat.isFile() || stat.isSymbolicLink()) { - fail(`${label} must be a regular non-symlink file: ${file}`); - } - if (!hasSafeBrokerSourceFilesystemMode(stat.mode)) { - fail(`${label} must have a safe non-executable mode derived from 0644: ${file}`); - } - return stat; -} - -function requireRealDirectory(directory, label) { - let stat; - try { - stat = lstatSync(directory); - } catch (cause) { - fail(`${label} cannot be inspected: ${directory}: ${cause.message}`); - } - if (!stat.isDirectory() || stat.isSymbolicLink()) { - fail(`${label} must be a real non-symlink directory: ${directory}`); - } - return stat; -} - -function ensureSafeDirectoryChain(directory, label) { - try { - return requireReleaseDirectoryChain(directory, { create: true, label }); - } catch (cause) { - fail(cause.message); - } -} - -function requireSafeDirectoryChain(directory, label) { - try { - return requireReleaseDirectoryChain(directory, { label }); - } catch (cause) { - fail(cause.message); - } -} - -function safeMember(value, label) { - if (typeof value !== "string" || !SAFE_MEMBER.test(value)) { - fail(`${label} is not a safe portable member path: ${JSON.stringify(value)}`); - } - return value; -} - -function targetRow(target) { - const row = TARGET_BY_ID.get(target); - if (!row) { - fail(`unsupported broker target ${JSON.stringify(target)}; expected ${TARGET_IDS.join(", ")}`); - } - return row; -} - -function canonicalJson(value) { - return `${JSON.stringify(value, null, 2)}\n`; -} - -function legalSourceFile(relative) { - const basename = path.posix.basename(relative).toLowerCase(); - return LEGAL_BASENAME_PREFIXES.some((prefix) => basename.startsWith(prefix)) - || LEGAL_BASENAME_FRAGMENTS.some((fragment) => basename.includes(fragment)); -} - -function walkRegularFiles(root, relative = "") { - const files = []; - for (const name of readdirSync(path.join(root, ...relative.split("/").filter(Boolean))).sort(compareText)) { - const member = relative ? `${relative}/${name}` : name; - const file = path.join(root, ...member.split("/")); - const stat = lstatSync(file); - if (stat.isSymbolicLink()) { - fail(`source dependency legal inventory contains a symlink: ${file}`); - } - if (stat.isDirectory()) { - files.push(...walkRegularFiles(root, member)); - } else if (stat.isFile()) { - files.push(member); - } - } - return files; -} - -function runCargo(args, label, { - cargoHome, - offline = true, - captureCargoCommand = captureCommandOutput, -} = {}) { - const checkedCargoHome = cargoHome === undefined - ? undefined - : requireSafeDirectoryChain(cargoHome, "broker dependency audit Cargo home"); - const result = captureCargoCommand("cargo", args, { - cwd: ROOT, - env: { - ...process.env, - ...(checkedCargoHome === undefined ? {} : { CARGO_HOME: checkedCargoHome }), - CARGO_NET_OFFLINE: offline ? "true" : "false", - }, - label, - maxOutputBytes: 128 * 1024 * 1024, - }); - if (result.error) { - fail(`${label} failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - fail(`${label} failed (${result.status ?? "signal"}): ${result.stderr.trim()}`); - } - return result.stdout; -} - -function cargoMetadata({ cargoHome } = {}) { - let metadata; - try { - metadata = JSON.parse(runCargo([ - "metadata", - "--locked", - "--offline", - "--format-version", - "1", - ], "cargo metadata", { cargoHome })); - } catch (cause) { - fail(`cargo metadata output is invalid: ${cause.message}`); - } - return metadata; -} - -function cargoTreePackageKeys(cargoTarget, metadataPackages, { cargoHome } = {}) { - const output = runCargo([ - "tree", - "-p", - "oliphaunt-broker", - "--locked", - "--offline", - "-e", - "normal", - "--target", - cargoTarget, - "--prefix", - "none", - "--format", - "{p}", - ], `cargo tree for ${cargoTarget}`, { cargoHome }); - const keys = new Set(); - for (const rawLine of output.split(/\r?\n/u)) { - const line = rawLine.replace(/ \(\*\)$/u, "").trim(); - if (!line) continue; - const match = /^([^\s]+) v([^\s]+)/u.exec(line); - if (!match) { - fail(`cannot parse cargo tree package line for ${cargoTarget}: ${JSON.stringify(rawLine)}`); - } - const key = `${match[1]}@${match[2]}`; - const candidates = metadataPackages.get(key) ?? []; - if (candidates.length === 0) { - fail(`cargo tree package ${key} is absent from cargo metadata`); - } - const registry = candidates.filter((row) => row.source === CARGO_SOURCE); - if (registry.length === 1) { - keys.add(key); - continue; - } - if (registry.length > 1) { - fail(`cargo metadata has duplicate crates.io identities for ${key}`); - } - const pathPackages = candidates.filter(isAllowedBrokerPathPackageMetadataRow); - if (pathPackages.length !== 1) { - fail(`broker graph contains unsupported non-crates.io dependency ${key}`); - } - } - return [...keys].sort(compareText); -} - -function payloadLicenseAtoms(selectedLicense) { - const atoms = selectedLicense.split(" AND "); - if (atoms.length === 0 || atoms.some((atom) => !PAYLOAD_LICENSE_ATOMS.includes(atom))) { - fail(`unsupported selected license expression ${JSON.stringify(selectedLicense)}`); - } - return atoms; -} - -function selectedLicenseIsCompatible(row) { - for (const atom of payloadLicenseAtoms(row.selectedLicense)) { - if (atom === "CC-BY-3.0") { - if (!row.licenseFiles.some(({ name }) => LEGAL_BASENAME_FRAGMENTS.some((fragment) => name.toLowerCase().includes(fragment)))) { - fail(`${packageKey(row)} selects CC-BY-3.0 without an exact third-party attribution file`); - } - } else if (atom === "BSD-3-Clause") { - if (!row.licenseFiles.some(({ name }) => name.toLowerCase().includes("bsd") || name === "zstd/LICENSE")) { - fail(`${packageKey(row)} selects BSD-3-Clause without an exact BSD license file`); - } - } else if (atom === "Unicode-3.0") { - if (!row.declaredLicense.includes("Unicode-3.0")) { - fail(`${packageKey(row)} selects Unicode-3.0 but its declared license does not`); - } - } else if (!row.declaredLicense.includes(atom)) { - fail(`${packageKey(row)} selects ${atom} but declares ${row.declaredLicense}`); - } - } -} - -function validateContractShape(contract, contractBytes) { - exactObjectKeys(contract, [ - "schema", - "product", - "cargoSource", - "payloadLicense", - "targets", - "packages", - ], "broker dependency license contract"); - if (contract.schema !== CONTRACT_SCHEMA) fail(`contract schema must be ${CONTRACT_SCHEMA}`); - if (contract.product !== "oliphaunt-broker") fail("contract product must be oliphaunt-broker"); - if (contract.cargoSource !== CARGO_SOURCE) fail(`contract cargoSource must be ${CARGO_SOURCE}`); - if (contract.payloadLicense !== BROKER_PAYLOAD_LICENSE) { - fail(`contract payloadLicense must be ${BROKER_PAYLOAD_LICENSE}`); - } - if (!Array.isArray(contract.packages) || contract.packages.length === 0) { - fail("contract packages must be a non-empty array"); - } - exactObjectKeys(contract.targets, TARGET_IDS, "contract targets"); - - const packages = new Map(); - const actualPackageOrder = []; - const selectedAtoms = new Set(); - for (const row of contract.packages) { - exactObjectKeys(row, [ - "name", - "version", - "checksum", - "declaredLicense", - "selectedLicense", - "targets", - "licenseFiles", - ], "contract package"); - const key = packageKey(row); - if (!PACKAGE_KEY.test(key)) fail(`invalid contract package identity ${JSON.stringify(key)}`); - if (packages.has(key)) fail(`duplicate contract package ${key}`); - if (!HEX_64.test(row.checksum)) fail(`${key} has invalid Cargo checksum`); - if (typeof row.declaredLicense !== "string" || !row.declaredLicense) fail(`${key} has no declaredLicense`); - if (typeof row.selectedLicense !== "string" || !row.selectedLicense) fail(`${key} has no selectedLicense`); - selectedLicenseIsCompatible(row); - for (const atom of payloadLicenseAtoms(row.selectedLicense)) selectedAtoms.add(atom); - if ( - !Array.isArray(row.targets) - || row.targets.length === 0 - || !sameStrings(row.targets, [...new Set(row.targets)].sort(compareText)) - || row.targets.some((target) => !TARGET_BY_ID.has(target)) - ) { - fail(`${key} targets must be a sorted, unique, non-empty supported-target list`); - } - if (!Array.isArray(row.licenseFiles) || row.licenseFiles.length === 0) { - fail(`${key} must pin at least one legal source file`); - } - const legalNames = []; - for (const file of row.licenseFiles) { - exactObjectKeys(file, ["name", "sha256", "bytes"], `${key} legal file`); - safeMember(file.name, `${key} legal file name`); - if (!legalSourceFile(file.name)) { - fail(`${key} legal file does not match the fail-closed legal-file classifier: ${file.name}`); - } - if (!HEX_64.test(file.sha256)) fail(`${key} ${file.name} has invalid sha256`); - if (!Number.isSafeInteger(file.bytes) || file.bytes <= 0) fail(`${key} ${file.name} has invalid byte count`); - legalNames.push(file.name); - } - if (!sameStrings(legalNames, [...new Set(legalNames)].sort(compareText))) { - fail(`${key} legal files must be sorted and unique by source member`); - } - packages.set(key, row); - actualPackageOrder.push(key); - } - if (!sameStrings(actualPackageOrder, [...actualPackageOrder].sort(compareText))) { - fail("contract packages must be sorted by name@version"); - } - if (!sameStrings([...selectedAtoms].sort(compareText), [...PAYLOAD_LICENSE_ATOMS].sort(compareText))) { - fail( - `contract selected-license closure must be ${PAYLOAD_LICENSE_ATOMS.join(", ")}, got ${[...selectedAtoms].sort(compareText).join(", ")}`, - ); - } - - for (const target of TARGET_IDS) { - const row = contract.targets[target]; - exactObjectKeys(row, ["cargoTarget", "packages"], `contract target ${target}`); - if (row.cargoTarget !== targetRow(target).cargoTarget) { - fail(`${target} cargoTarget must be ${targetRow(target).cargoTarget}`); - } - if ( - !Array.isArray(row.packages) - || row.packages.length === 0 - || !sameStrings(row.packages, [...new Set(row.packages)].sort(compareText)) - ) { - fail(`${target} packages must be a sorted, unique, non-empty list`); - } - for (const key of row.packages) { - if (!packages.has(key)) fail(`${target} references unknown package ${key}`); - if (!packages.get(key).targets.includes(target)) fail(`${key} does not claim target ${target}`); - } - const reverse = contract.packages.filter((pkg) => pkg.targets.includes(target)).map(packageKey); - if (!sameStrings(row.packages, reverse)) { - fail(`${target} package graph and package target claims disagree`); - } - } - - const canonical = Buffer.from(canonicalJson(contract)); - if (!contractBytes.equals(canonical)) { - fail("dependency-licenses.json must be canonical two-space JSON with one trailing newline"); - } - return packages; -} - -function validateCanonicalBlobs(contract) { - requireRealDirectory(BLOB_ROOT, "broker dependency license blob root"); - const expected = new Map(); - for (const row of contract.packages) { - for (const legal of row.licenseFiles) { - const prior = expected.get(legal.sha256); - if (prior !== undefined && prior !== legal.bytes) { - fail(`license digest ${legal.sha256} has inconsistent byte counts`); - } - expected.set(legal.sha256, legal.bytes); - } - } - const actualNames = readdirSync(BLOB_ROOT).sort(compareText); - const expectedNames = [...expected.keys()].sort(compareText).map((digest) => `${digest}.base64`); - if (!sameStrings(actualNames, expectedNames)) { - fail(`canonical broker dependency license blobs differ: expected=${JSON.stringify(expectedNames)}, actual=${JSON.stringify(actualNames)}`); - } - for (const [digest, bytes] of expected) { - canonicalBlobBytes(digest, bytes); - } -} - -function validateLockIdentity(packages) { - let lock; - try { - lock = Bun.TOML.parse(readFileSync(CARGO_LOCK_PATH, "utf8")); - } catch (cause) { - fail(`cannot parse Cargo.lock: ${cause.message}`); - } - const lockRows = new Map(); - for (const row of lock?.package ?? []) { - const key = packageKey(row); - if (!row.source) continue; - if (lockRows.has(key)) fail(`Cargo.lock contains ambiguous package identity ${key}`); - lockRows.set(key, row); - } - for (const [key, row] of packages) { - const locked = lockRows.get(key); - if (!locked) fail(`Cargo.lock is missing contracted broker dependency ${key}`); - if (locked.source !== CARGO_SOURCE || locked.checksum !== row.checksum) { - fail( - `Cargo.lock identity changed for ${key}: expected ${CARGO_SOURCE}/${row.checksum}, got ${locked.source}/${locked.checksum}`, - ); - } - } -} - -function validateGraph(contract, packages, { cargoHome } = {}) { - const metadata = cargoMetadata({ cargoHome }); - const metadataPackages = new Map(); - for (const row of metadata.packages ?? []) { - const key = packageKey(row); - const values = metadataPackages.get(key) ?? []; - values.push(row); - metadataPackages.set(key, values); - } - for (const [key, row] of packages) { - const matches = (metadataPackages.get(key) ?? []).filter((candidate) => candidate.source === CARGO_SOURCE); - if (matches.length !== 1) { - fail(`cargo metadata must contain exactly one crates.io package for ${key}, got ${matches.length}`); - } - const metadataRow = matches[0]; - if (metadataRow.license !== row.declaredLicense) { - fail(`${key} declared license changed: expected ${row.declaredLicense}, got ${metadataRow.license}`); - } - const sourceRoot = path.dirname(metadataRow.manifest_path); - requireRealDirectory(sourceRoot, `${key} Cargo source directory`); - const legalFiles = walkRegularFiles(sourceRoot).filter(legalSourceFile).sort(compareText); - const contracted = row.licenseFiles.map(({ name }) => name); - if (!sameStrings(legalFiles, contracted)) { - fail( - `${key} legal source inventory changed: expected=${JSON.stringify(contracted)}, actual=${JSON.stringify(legalFiles)}`, - ); - } - for (const legal of row.licenseFiles) { - const file = path.join(sourceRoot, ...legal.name.split("/")); - const content = readFileSync(file); - if (content.length !== legal.bytes || sha256(content) !== legal.sha256) { - fail(`${key} legal source file changed: ${legal.name}`); - } - } - } - - for (const target of TARGET_IDS) { - const actual = cargoTreePackageKeys( - contract.targets[target].cargoTarget, - metadataPackages, - { cargoHome }, - ); - const expected = contract.targets[target].packages; - if (!sameStrings(actual, expected)) { - fail( - `${target} exact normal dependency graph changed: expected=${JSON.stringify(expected)}, actual=${JSON.stringify(actual)}`, - ); - } - } -} - -export function loadBrokerDependencyLicenseContract({ - contractPath = CONTRACT_PATH, - auditLock = false, - auditGraph = false, - cargoHome, -} = {}) { - const resolvedContractPath = path.resolve(contractPath); - const cacheable = resolvedContractPath === CONTRACT_PATH && cargoHome === undefined; - if (cacheable) { - if (auditGraph && auditedDefaultContract !== undefined) return auditedDefaultContract; - if (!auditGraph && !auditLock && validatedDefaultContract !== undefined) return validatedDefaultContract; - } - requireRealFile(resolvedContractPath, "broker dependency license contract"); - const bytes = readFileSync(resolvedContractPath); - let contract; - try { - contract = JSON.parse(bytes.toString("utf8")); - } catch (cause) { - fail(`cannot parse ${resolvedContractPath}: ${cause.message}`); - } - const packages = validateContractShape(contract, bytes); - validateCanonicalBlobs(contract); - if (auditLock || auditGraph) validateLockIdentity(packages); - if (auditGraph) validateGraph(contract, packages, { cargoHome }); - const result = Object.freeze({ contract, packages, contractPath: resolvedContractPath }); - if (cacheable) { - validatedDefaultContract = result; - if (auditGraph) auditedDefaultContract = result; - } - return result; -} - -/** - * Run the connected production audit in a brand-new Cargo home. The fetch is - * deliberately online and target-neutral; every subsequent graph/source read - * is locked and offline in that same home. This proves the audit is complete - * without borrowing registry sources from a developer or runner cache. - */ -export function auditBrokerDependencyLicenseContract({ - contractPath = CONTRACT_PATH, - temporaryRoot = tmpdir(), - captureCargoCommand = captureCommandOutput, - verifyContract, -} = {}) { - const checkedTemporaryRoot = requireSafeDirectoryChain( - temporaryRoot, - "broker dependency audit temporary root", - ); - const cargoHome = mkdtempSync(path.join(checkedTemporaryRoot, "oliphaunt-broker-cargo-home-")); - chmodSync(cargoHome, 0o700); - try { - runCargo( - BROKER_DEPENDENCY_LICENSE_FETCH_ARGS, - "locked all-target Cargo dependency prefetch", - { cargoHome, offline: false, captureCargoCommand }, - ); - const verify = verifyContract ?? ((options) => loadBrokerDependencyLicenseContract(options)); - return verify({ - contractPath, - auditGraph: true, - cargoHome, - }); - } finally { - rmSync(cargoHome, { recursive: true, force: true }); - } -} - -function targetPackages(contractState, target) { - const targetContract = contractState.contract.targets[target]; - return targetContract.packages.map((key) => contractState.packages.get(key)); -} - -function targetBlobMembers(contractState, target) { - const digests = [...new Set( - targetPackages(contractState, target) - .flatMap((row) => row.licenseFiles.map(({ sha256: digest }) => digest)), - )].sort(compareText); - return new Map(digests.map((digest, index) => [digest, `licenses/${String(index).padStart(3, "0")}.txt`])); -} - -function renderedTargetIndex(contractState, target) { - const targetContract = contractState.contract.targets[target]; - const blobMembers = targetBlobMembers(contractState, target); - return { - schema: INDEX_SCHEMA, - product: "oliphaunt-broker", - target, - cargoTarget: targetContract.cargoTarget, - payloadLicense: BROKER_PAYLOAD_LICENSE, - packages: targetPackages(contractState, target).map((row) => ({ - name: row.name, - version: row.version, - checksum: row.checksum, - declaredLicense: row.declaredLicense, - selectedLicense: row.selectedLicense, - licenseFiles: row.licenseFiles.map((legal) => ({ - name: legal.name, - sha256: legal.sha256, - bytes: legal.bytes, - member: blobMembers.get(legal.sha256), - })), - })), - }; -} - -function targetExpectedFiles(contractState, target) { - const files = new Map(); - const blobMembers = targetBlobMembers(contractState, target); - files.set(`${BROKER_DEPENDENCY_LICENSE_ROOT}/DEPENDENCIES.json`, Buffer.from(canonicalJson(renderedTargetIndex(contractState, target)))); - for (const row of targetPackages(contractState, target)) { - for (const legal of row.licenseFiles) { - files.set( - `${BROKER_DEPENDENCY_LICENSE_ROOT}/${blobMembers.get(legal.sha256)}`, - canonicalBlobBytes(legal.sha256, legal.bytes), - ); - } - } - return new Map([...files].sort(([left], [right]) => compareText(left, right))); -} - -export function brokerDependencyLicenseMembers(target, { prefix = "" } = {}) { - targetRow(target); - const state = loadBrokerDependencyLicenseContract(); - const checkedPrefix = prefix ? safeMember(prefix.replace(/\/$/u, ""), "broker dependency archive prefix") : ""; - return [...targetExpectedFiles(state, target).keys()].map((member) => checkedPrefix ? `${checkedPrefix}/${member}` : member); -} - -function expectedDirectories(expectedFiles) { - const directories = new Set(); - for (const member of expectedFiles.keys()) { - const parts = member.split("/"); - for (let index = 1; index < parts.length; index += 1) { - directories.add(parts.slice(0, index).join("/")); - } - } - return directories; -} - -export function normalizeBrokerDependencyLicenseModes(destination, target) { - targetRow(target); - const state = loadBrokerDependencyLicenseContract(); - const root = requireSafeDirectoryChain(destination, "broker dependency license carrier root"); - const expected = targetExpectedFiles(state, target); - for (const member of expectedDirectories(expected)) { - const directory = path.join(root, ...member.split("/")); - requireRealDirectory(directory, `broker dependency license directory ${member}`); - chmodSync(directory, 0o755); - } - for (const member of expected.keys()) { - const file = path.join(root, ...member.split("/")); - let stat; - try { - stat = lstatSync(file); - } catch (cause) { - fail(`broker dependency license member cannot be inspected: ${member}: ${cause.message}`); - } - if (!stat.isFile() || stat.isSymbolicLink()) { - fail(`broker dependency license member must be a regular non-symlink file: ${member}`); - } - chmodSync(file, 0o644); - } -} - -export function stageBrokerDependencyLicenses(destination, target) { - targetRow(target); - const state = loadBrokerDependencyLicenseContract(); - const root = ensureSafeDirectoryChain(destination, "broker dependency license staging root"); - const dependencyRoot = path.join(root, ...BROKER_DEPENDENCY_LICENSE_ROOT.split("/")); - // Validate the namespace ancestor before even inspecting the owned leaf. - // rmSync on a leaf beneath a symlinked THIRD_PARTY_LICENSES directory could - // otherwise remove data outside the carrier stage. - ensureSafeDirectoryChain(path.dirname(dependencyRoot), "broker dependency license namespace parent"); - let prior; - try { - prior = lstatSync(dependencyRoot); - } catch (cause) { - if (cause?.code !== "ENOENT") fail(`cannot inspect prior broker dependency license root: ${cause.message}`); - } - if (prior) { - if (!prior.isDirectory() || prior.isSymbolicLink()) { - fail(`prior broker dependency license root must be a real directory: ${dependencyRoot}`); - } - rmSync(dependencyRoot, { recursive: true }); - } - ensureSafeDirectoryChain(path.join(dependencyRoot, "licenses"), "broker dependency license staging root"); - for (const [member, bytes] of targetExpectedFiles(state, target)) { - const file = path.join(root, ...member.split("/")); - ensureSafeDirectoryChain(path.dirname(file), "broker dependency license staging parent"); - writeFileSync(file, bytes); - chmodSync(file, 0o644); - } - normalizeBrokerDependencyLicenseModes(root, target); - assertBrokerDependencyLicensesInDirectory(root, { target }); - return brokerDependencyLicenseMembers(target); -} - -function directoryNamespaceEntries(root) { - const namespace = path.join(root, ...BROKER_DEPENDENCY_LICENSE_ROOT.split("/")); - requireSafeDirectoryChain(namespace, "broker dependency license namespace"); - const entries = new Map(); - function walk(directory, relative) { - for (const name of readdirSync(directory).sort(compareText)) { - const file = path.join(directory, name); - const member = relative ? `${relative}/${name}` : name; - const stat = lstatSync(file); - entries.set(`${BROKER_DEPENDENCY_LICENSE_ROOT}/${member}`, { file, stat }); - if (stat.isDirectory() && !stat.isSymbolicLink()) walk(file, member); - } - } - walk(namespace, ""); - return entries; -} - -export function assertBrokerDependencyLicensesInDirectory(directory, { target } = {}) { - targetRow(target); - const state = loadBrokerDependencyLicenseContract(); - const root = requireSafeDirectoryChain(directory, "broker dependency license carrier root"); - const expected = targetExpectedFiles(state, target); - const expectedDirs = expectedDirectories(expected); - const actual = directoryNamespaceEntries(root); - const expectedMembers = new Set([...expected.keys(), ...expectedDirs]); - for (const member of expectedMembers) { - if (member === "THIRD_PARTY_LICENSES" || member === BROKER_DEPENDENCY_LICENSE_ROOT) continue; - const entry = actual.get(member); - if (!entry) fail(`broker dependency license carrier is missing ${member}`); - if (expected.has(member)) { - if (!entry.stat.isFile() || entry.stat.isSymbolicLink()) fail(`${member} must be a regular non-symlink file`); - if (!hasCanonicalBrokerFilesystemMode(entry.stat.mode, 0o644)) fail(`${member} must have mode 0644`); - if (!readFileSync(entry.file).equals(expected.get(member))) fail(`${member} differs from the canonical dependency license bytes`); - } else { - if (!entry.stat.isDirectory() || entry.stat.isSymbolicLink()) fail(`${member} must be a real non-symlink directory`); - if (!hasCanonicalBrokerFilesystemMode(entry.stat.mode, 0o755)) fail(`${member} must have mode 0755`); - } - } - for (const member of actual.keys()) { - if (!expectedMembers.has(member)) fail(`broker dependency license carrier has unexpected member ${member}`); - } - return [...expected.keys()]; -} - -function checkedArchivePrefix(prefix) { - if (prefix === "") return ""; - return safeMember(String(prefix).replace(/^\.\//u, "").replace(/\/$/u, ""), "broker dependency archive prefix"); -} - -export function assertBrokerDependencyLicensesInEntries(entries, { target, prefix = "", label = "archive" } = {}) { - targetRow(target); - if (!(entries instanceof Map)) fail("broker dependency archive entries must be a Map"); - const state = loadBrokerDependencyLicenseContract(); - const archivePrefix = checkedArchivePrefix(prefix); - const localExpected = targetExpectedFiles(state, target); - const localDirs = expectedDirectories(localExpected); - const prefixed = (member) => archivePrefix ? `${archivePrefix}/${member}` : member; - const expectedFiles = new Map([...localExpected].map(([member, bytes]) => [prefixed(member), bytes])); - const expectedDirs = new Set([...localDirs].map(prefixed)); - const namespace = `${prefixed(BROKER_DEPENDENCY_LICENSE_ROOT)}/`; - for (const [member, bytes] of expectedFiles) { - const entry = entries.get(member); - if (!entry?.isFile || entry.isSymbolicLink) fail(`${label} is missing regular dependency license member ${member}`); - if ((entry.mode & 0o777) !== 0o644) fail(`${label} dependency license member ${member} must have mode 0644`); - if (!Buffer.from(entry.data()).equals(bytes)) fail(`${label} dependency license member ${member} differs from canonical bytes`); - } - for (const [member, entry] of entries) { - if (expectedFiles.has(member)) continue; - if (expectedDirs.has(member)) { - if (!entry.isDirectory || entry.isSymbolicLink) fail(`${label} dependency license directory ${member} must be a real directory`); - if ((entry.mode & 0o777) !== 0o755) fail(`${label} dependency license directory ${member} must have mode 0755`); - continue; - } - if (member !== prefixed(BROKER_DEPENDENCY_LICENSE_ROOT) && !member.startsWith(namespace)) continue; - fail(`${label} contains unexpected dependency license member ${member}`); - } - assertReleaseNoticesInEntries(entries, { - profile: "broker", - prefix: archivePrefix, - exact: false, - label, - }); - return [...expectedFiles.keys()]; -} - -export function assertBrokerDependencyLicensesInArchive(file, options = {}) { - const archive = path.resolve(file); - return assertBrokerDependencyLicensesInEntries(readPortableArchiveEntries(archive), { - ...options, - label: options.label ?? path.basename(archive), - }); -} - -function usage() { - return [ - "usage:", - ` ${TOOL} check-contract`, - ` ${TOOL} audit-contract`, - ` ${TOOL} stage --target <${TARGET_IDS.join("|")}>`, - ` ${TOOL} check-directory --target <${TARGET_IDS.join("|")}>`, - ` ${TOOL} check-archive --target <${TARGET_IDS.join("|")}> [--prefix ]`, - ].join("\n"); -} - -function parseCli(argv) { - const values = [...argv]; - const command = values.shift(); - if (["check-contract", "audit-contract"].includes(command)) { - if (values.length > 0) fail(usage()); - return { command }; - } - if (!["stage", "check-directory", "check-archive"].includes(command)) fail(usage()); - const subject = values.shift(); - if (!subject) fail(usage()); - let target; - let prefix = ""; - while (values.length > 0) { - const flag = values.shift(); - if (flag === "--target") { - if (target !== undefined) fail("--target may be supplied only once"); - target = values.shift(); - if (!target) fail("--target requires a value"); - } else if (flag === "--prefix" && command === "check-archive") { - if (prefix) fail("--prefix may be supplied only once"); - prefix = values.shift(); - if (prefix === undefined) fail("--prefix requires a value"); - } else { - fail(`unsupported argument ${JSON.stringify(flag)}\n${usage()}`); - } - } - targetRow(target); - return { command, subject, target, prefix }; -} - -function main() { - try { - const args = parseCli(process.argv.slice(2)); - if (args.command === "check-contract") { - const state = loadBrokerDependencyLicenseContract(); - console.log(`${TOOL}: canonical self-contained license contract passed (${state.contract.packages.length} packages)`); - } else if (args.command === "audit-contract") { - const state = auditBrokerDependencyLicenseContract(); - console.log(`${TOOL}: clean-cache exact graph/source audit passed (${state.contract.packages.length} packages)`); - } else if (args.command === "stage") { - stageBrokerDependencyLicenses(args.subject, args.target); - console.log(`${TOOL}: staged ${args.target} dependency licenses in ${args.subject}`); - } else if (args.command === "check-directory") { - assertBrokerDependencyLicensesInDirectory(args.subject, { target: args.target }); - console.log(`${TOOL}: checked ${args.target} dependency licenses in ${args.subject}`); - } else { - assertBrokerDependencyLicensesInArchive(args.subject, { target: args.target, prefix: args.prefix }); - console.log(`${TOOL}: checked ${args.target} dependency licenses in ${args.subject}`); - } - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exitCode = 1; - } -} - -const invoked = process.argv[1] ? path.resolve(process.argv[1]) : ""; -if (invoked === fileURLToPath(import.meta.url)) main(); diff --git a/tools/release/broker-dependency-license-contract.test.mjs b/tools/release/broker-dependency-license-contract.test.mjs deleted file mode 100644 index 85283486f..000000000 --- a/tools/release/broker-dependency-license-contract.test.mjs +++ /dev/null @@ -1,489 +0,0 @@ -import assert from "node:assert/strict"; -import { spawn } from "node:child_process"; -import { - chmodSync, - closeSync, - existsSync, - mkdtempSync, - mkdirSync, - openSync, - readFileSync, - readdirSync, - realpathSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -import { - BROKER_DEPENDENCY_LICENSE_FETCH_ARGS, - BROKER_DEPENDENCY_LICENSE_ROOT, - BROKER_PAYLOAD_LICENSE, - auditBrokerDependencyLicenseContract, - assertBrokerDependencyLicensesInArchive, - assertBrokerDependencyLicensesInDirectory, - assertBrokerDependencyLicensesInEntries, - brokerDependencyLicenseMembers, - hasCanonicalBrokerFilesystemMode, - hasSafeBrokerSourceFilesystemMode, - isAllowedBrokerPathPackageMetadataRow, - loadBrokerDependencyLicenseContract, - normalizeBrokerDependencyLicenseModes, - stageBrokerDependencyLicenses, -} from "./broker-dependency-license-contract.mjs"; -import { currentProductVersionSync } from "./release-artifact-targets.mjs"; -import { brokerNpmTarballs } from "./package-release-carriers.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -const CONTRACT = path.join(ROOT, "src/runtimes/broker/dependency-licenses.json"); -const BROKER_VERSION = currentProductVersionSync( - "oliphaunt-broker", - "broker-dependency-license-contract.test.mjs", -); -const TARGETS = ["linux-x64-gnu", "linux-arm64-gnu", "macos-arm64", "windows-x64-msvc"]; -const TIMEOUT = 120_000; - -function scratch(t, label) { - const directory = realpathSync(mkdtempSync(path.join(os.tmpdir(), `oliphaunt-broker-license-${label}-`))); - chmodSync(directory, 0o755); - t.after(() => rmSync(directory, { recursive: true, force: true })); - return directory; -} - -function stageCarrier(t, target) { - const directory = scratch(t, target); - stageReleaseNotices(directory, { profile: "broker" }); - stageBrokerDependencyLicenses(directory, target); - return directory; -} - -function writeMutatedContract(t, mutate) { - const directory = scratch(t, "contract"); - const contract = JSON.parse(readFileSync(CONTRACT, "utf8")); - mutate(contract); - const file = path.join(directory, "dependency-licenses.json"); - writeFileSync(file, `${JSON.stringify(contract, null, 2)}\n`, { mode: 0o644 }); - chmodSync(file, 0o644); - return file; -} - -function archive(directory, extension) { - const output = `${directory}.${extension}`; - const result = spawnSync( - path.join(ROOT, "src/shared/artifact-packaging/archive-directory.mjs"), - [directory, output], - { cwd: ROOT, encoding: "utf8" }, - ); - assert.equal(result.status, 0, result.stderr); - return output; -} - -function spawnResult(command, args, logRoot) { - return new Promise((resolve, reject) => { - const stdoutPath = path.join(logRoot, "stdout.log"); - const stderrPath = path.join(logRoot, "stderr.log"); - const stdoutDescriptor = openSync(stdoutPath, "wx", 0o600); - const stderrDescriptor = openSync(stderrPath, "wx", 0o600); - const child = spawn(command, args, { - cwd: ROOT, - stdio: ["ignore", stdoutDescriptor, stderrDescriptor], - }); - closeSync(stdoutDescriptor); - closeSync(stderrDescriptor); - child.once("error", reject); - child.once("close", (status, signal) => resolve({ - status, - signal, - stdout: readFileSync(stdoutPath, "utf8"), - stderr: readFileSync(stderrPath, "utf8"), - })); - }); -} - -test("broker contract pins the complete package-specific legal inventory", { timeout: TIMEOUT }, () => { - const { contract } = loadBrokerDependencyLicenseContract(); - assert.equal(contract.packages.length, 25); - assert.equal(contract.payloadLicense, BROKER_PAYLOAD_LICENSE); - const legalFiles = contract.packages.flatMap((row) => row.licenseFiles); - assert.equal(legalFiles.length, 50); - assert.equal(new Set(legalFiles.map(({ sha256 }) => sha256)).size, 27); - assert.ok(contract.packages.every((row) => row.licenseFiles.length > 0)); - assert.ok(contract.packages.some((row) => - row.name === "memchr" - && row.selectedLicense === "MIT" - && row.licenseFiles.some(({ name }) => name === "UNLICENSE"))); - assert.ok(contract.packages.some((row) => row.name === "libloading" && row.selectedLicense === "ISC")); - assert.ok(contract.packages.some((row) => row.name === "serde_json" && row.version === "1.0.150")); - assert.ok(contract.packages.some((row) => row.name === "unicode-ident" && row.selectedLicense === "MIT AND Unicode-3.0")); - assert.ok(contract.packages.some((row) => - row.name === "zmij" - && row.selectedLicense === "MIT" - && row.licenseFiles.some(({ name }) => name === "LICENSE-MIT"))); -}); - -test("production audit prefetches the exact locked all-target closure into a clean home before verification", (t) => { - const temporaryRoot = scratch(t, "clean-audit"); - let observedCargoHome; - const marker = "prefetched-all-target-sources"; - const state = auditBrokerDependencyLicenseContract({ - temporaryRoot, - captureCargoCommand(command, args, options) { - assert.equal(command, "cargo"); - assert.deepEqual(args, BROKER_DEPENDENCY_LICENSE_FETCH_ARGS); - assert.equal(args.includes("--target"), false); - assert.equal(options.cwd, ROOT); - assert.equal(options.env.CARGO_NET_OFFLINE, "false"); - observedCargoHome = options.env.CARGO_HOME; - assert.equal(path.dirname(observedCargoHome), temporaryRoot); - assert.deepEqual(readdirSync(observedCargoHome), []); - writeFileSync(path.join(observedCargoHome, marker), "ready\n", { mode: 0o600 }); - return { status: 0, stdout: "", stderr: "" }; - }, - verifyContract(options) { - assert.equal(options.auditGraph, true); - assert.equal(options.cargoHome, observedCargoHome); - assert.equal(readFileSync(path.join(options.cargoHome, marker), "utf8"), "ready\n"); - return Object.freeze({ verified: true }); - }, - }); - assert.deepEqual(state, { verified: true }); - assert.equal(existsSync(observedCargoHome), false); -}); - -test("broker path-package validation follows exact manifests without pinning release versions", () => { - const sdkManifest = path.join(ROOT, "src/sdks/rust/Cargo.toml"); - assert.equal(isAllowedBrokerPathPackageMetadataRow({ - name: "oliphaunt", - version: "17.23.401", - source: null, - manifest_path: sdkManifest, - }), true); - assert.equal(isAllowedBrokerPathPackageMetadataRow({ - name: "oliphaunt", - version: "17.23.401", - source: "registry+https://github.com/rust-lang/crates.io-index", - manifest_path: sdkManifest, - }), false); - assert.equal(isAllowedBrokerPathPackageMetadataRow({ - name: "unexpected-local-crate", - version: "17.23.401", - source: null, - manifest_path: sdkManifest, - }), false); - assert.equal(isAllowedBrokerPathPackageMetadataRow({ - name: "oliphaunt", - version: "17.23.401", - source: null, - manifest_path: path.join(ROOT, "Cargo.toml"), - }), false); -}); - -test("treats direct filesystem modes as POSIX-only metadata", () => { - assert.equal(hasCanonicalBrokerFilesystemMode(0o666, 0o644, "win32"), true); - assert.equal(hasCanonicalBrokerFilesystemMode(0o666, 0o755, "win32"), true); - assert.equal(hasCanonicalBrokerFilesystemMode(0o644, 0o644, "linux"), true); - assert.equal(hasCanonicalBrokerFilesystemMode(0o755, 0o755, "darwin"), true); - assert.equal(hasCanonicalBrokerFilesystemMode(0o666, 0o644, "linux"), false); - assert.equal(hasCanonicalBrokerFilesystemMode(0o666, 0o755, "darwin"), false); - assert.equal(hasSafeBrokerSourceFilesystemMode(0o600, "linux"), true); - assert.equal(hasSafeBrokerSourceFilesystemMode(0o640, "darwin"), true); - assert.equal(hasSafeBrokerSourceFilesystemMode(0o644, "linux"), true); - assert.equal(hasSafeBrokerSourceFilesystemMode(0o664, "linux"), true); - assert.equal(hasSafeBrokerSourceFilesystemMode(0o666, "linux"), true); - assert.equal(hasSafeBrokerSourceFilesystemMode(0o755, "darwin"), false); - assert.equal(hasSafeBrokerSourceFilesystemMode(0o000, "linux"), false); - assert.equal(hasSafeBrokerSourceFilesystemMode(0o666, "win32"), true); -}); - -test("selected-target carrier staging is self-contained without Cargo or registry sources", (t) => { - const directory = scratch(t, "offline-selected-target"); - const emptyPath = scratch(t, "empty-path"); - const emptyCargoHome = scratch(t, "empty-cargo-home"); - const result = spawnSync( - process.execPath, - [ - path.join(ROOT, "tools/release/broker-dependency-license-contract.mjs"), - "stage", - directory, - "--target", - "linux-x64-gnu", - ], - { - cwd: ROOT, - encoding: "utf8", - env: { - ...process.env, - CARGO_HOME: emptyCargoHome, - PATH: emptyPath, - }, - }, - ); - assert.equal(result.status, 0, `${result.stderr}\n${result.stdout}`); - assertBrokerDependencyLicensesInDirectory(directory, { target: "linux-x64-gnu" }); -}); - -test("target indexes exclude other operating systems' conditional dependencies", { timeout: TIMEOUT }, (t) => { - const indexes = new Map(); - for (const target of TARGETS) { - const directory = stageCarrier(t, target); - assertBrokerDependencyLicensesInDirectory(directory, { target }); - const index = JSON.parse(readFileSync( - path.join(directory, ...BROKER_DEPENDENCY_LICENSE_ROOT.split("/"), "DEPENDENCIES.json"), - "utf8", - )); - assert.equal(index.target, target); - assert.equal(index.payloadLicense, BROKER_PAYLOAD_LICENSE); - indexes.set(target, new Set(index.packages.map(({ name }) => name))); - } - assert.ok(indexes.get("linux-x64-gnu").has("libc")); - assert.ok(!indexes.get("linux-x64-gnu").has("windows-link")); - assert.ok(indexes.get("macos-arm64").has("libc")); - assert.ok(!indexes.get("macos-arm64").has("windows-link")); - assert.ok(indexes.get("windows-x64-msvc").has("windows-link")); - assert.ok(indexes.get("windows-x64-msvc").has("winapi")); - assert.ok(!indexes.get("windows-x64-msvc").has("libc")); -}); - -test("staged and packed closures preserve exact bytes, modes, and members", { timeout: TIMEOUT }, (t) => { - for (const [target, extension] of [["linux-x64-gnu", "tar.gz"], ["windows-x64-msvc", "zip"]]) { - const directory = stageCarrier(t, target); - const packed = archive(directory, extension); - t.after(() => rmSync(packed, { force: true })); - assertBrokerDependencyLicensesInArchive(packed, { target }); - const expected = brokerDependencyLicenseMembers(target); - assert.ok(expected.includes(`${BROKER_DEPENDENCY_LICENSE_ROOT}/DEPENDENCIES.json`)); - assert.ok(expected.some((member) => member.startsWith(`${BROKER_DEPENDENCY_LICENSE_ROOT}/licenses/`))); - } - - const extraDirectory = stageCarrier(t, "linux-x64-gnu"); - writeFileSync( - path.join(extraDirectory, ...BROKER_DEPENDENCY_LICENSE_ROOT.split("/"), "licenses/extra.txt"), - "undeclared\n", - { mode: 0o644 }, - ); - const extraArchive = archive(extraDirectory, "tar.gz"); - t.after(() => rmSync(extraArchive, { force: true })); - assert.throws( - () => assertBrokerDependencyLicensesInArchive(extraArchive, { target: "linux-x64-gnu" }), - /unexpected dependency license member/u, - ); -}); - -test("portable archive dependency-license modes remain exact on every host", { timeout: TIMEOUT }, (t) => { - const target = "windows-x64-msvc"; - const directory = stageCarrier(t, target); - const packed = archive(directory, "zip"); - t.after(() => rmSync(packed, { force: true })); - const entries = readPortableArchiveEntries(packed); - - const fileMember = `${BROKER_DEPENDENCY_LICENSE_ROOT}/DEPENDENCIES.json`; - const fileModeDrift = new Map(entries); - fileModeDrift.set(fileMember, { ...entries.get(fileMember), mode: 0o666 }); - assert.throws( - () => assertBrokerDependencyLicensesInEntries(fileModeDrift, { target }), - /dependency license member .* must have mode 0644/u, - ); - - const directoryMember = `${BROKER_DEPENDENCY_LICENSE_ROOT}/licenses`; - const directoryModeDrift = new Map(entries); - directoryModeDrift.set(directoryMember, { ...entries.get(directoryMember), mode: 0o700 }); - assert.throws( - () => assertBrokerDependencyLicensesInEntries(directoryModeDrift, { target }), - /dependency license directory .* must have mode 0755/u, - ); -}); - -test("real npm target tarballs reopen the exact target-specific dependency closure", { timeout: TIMEOUT }, (t) => { - const assetDir = scratch(t, "npm-assets"); - const fixture = spawnSync( - path.join(ROOT, "tools/dev/bun.sh"), - [ - "tools/test/create-broker-release-fixture.mjs", - "--asset-dir", - assetDir, - "--version", - BROKER_VERSION, - ], - { cwd: ROOT, encoding: "utf8" }, - ); - assert.equal(fixture.status, 0, fixture.stderr); - const packageTargets = new Map([ - ["@oliphaunt/broker-darwin-arm64", "macos-arm64"], - ["@oliphaunt/broker-linux-arm64-gnu", "linux-arm64-gnu"], - ["@oliphaunt/broker-linux-x64-gnu", "linux-x64-gnu"], - ["@oliphaunt/broker-win32-x64-msvc", "windows-x64-msvc"], - ]); - const tarballs = brokerNpmTarballs(BROKER_VERSION, { assetDir }); - assert.equal(tarballs.length, packageTargets.size); - for (const [packageName, tarball] of tarballs) { - assertBrokerDependencyLicensesInArchive(tarball, { - target: packageTargets.get(packageName), - prefix: "package", - }); - } - -}); - -test("concurrent real Cargo payload packagers are isolated and reopen exact target closures", { timeout: TIMEOUT }, async (t) => { - const assetDir = scratch(t, "cargo-assets"); - const outputDirs = [scratch(t, "cargo-output-a"), scratch(t, "cargo-output-b")]; - const sourceOutputDirs = [scratch(t, "cargo-source-a"), scratch(t, "cargo-source-b")]; - const logRoots = [scratch(t, "cargo-log-a"), scratch(t, "cargo-log-b")]; - const fixture = spawnSync( - path.join(ROOT, "tools/dev/bun.sh"), - [ - "tools/test/create-broker-release-fixture.mjs", - "--asset-dir", - assetDir, - "--version", - BROKER_VERSION, - ], - { cwd: ROOT, encoding: "utf8" }, - ); - assert.equal(fixture.status, 0, fixture.stderr); - const packagedRuns = await Promise.all(outputDirs.map((outputDir, index) => spawnResult( - path.join(ROOT, "tools/dev/bun.sh"), - [ - "tools/release/package_broker_cargo_artifacts.mjs", - "--asset-dir", - assetDir, - "--output-dir", - outputDir, - "--source-output-dir", - sourceOutputDirs[index], - "--version", - BROKER_VERSION, - ], - logRoots[index], - ))); - for (const packaged of packagedRuns) { - assert.equal( - packaged.status, - 0, - `${packaged.stderr}\n${packaged.stdout}\nsignal=${packaged.signal ?? "none"}`, - ); - } - const targets = new Map(TARGETS.map((target) => [ - `oliphaunt-broker-${target}-${BROKER_VERSION}.crate`, - target, - ])); - for (const outputDir of outputDirs) { - const crates = readdirSync(outputDir).filter((name) => name.endsWith(".crate")).sort(); - assert.deepEqual(crates, [...targets.keys()].sort()); - for (const crate of crates) { - assertBrokerDependencyLicensesInArchive(path.join(outputDir, crate), { - target: targets.get(crate), - prefix: crate.replace(/\.crate$/u, ""), - }); - } - } -}); - -test("directory closure rejects missing, changed, extra, executable, and symlinked legal members", { timeout: TIMEOUT }, (t) => { - const mutations = [ - ["missing", (directory, member) => rmSync(path.join(directory, ...member.split("/")))], - ["changed", (directory, member) => writeFileSync(path.join(directory, ...member.split("/")), "changed\n")], - ["executable", (directory, member) => chmodSync(path.join(directory, ...member.split("/")), 0o755)], - ["extra", (directory) => writeFileSync( - path.join(directory, ...BROKER_DEPENDENCY_LICENSE_ROOT.split("/"), "licenses/extra.txt"), - "extra\n", - { mode: 0o644 }, - )], - ]; - for (const [label, mutate] of mutations) { - const directory = stageCarrier(t, "linux-x64-gnu"); - const member = brokerDependencyLicenseMembers("linux-x64-gnu").find((value) => value.endsWith(".txt")); - mutate(directory, member); - assert.throws( - () => assertBrokerDependencyLicensesInDirectory(directory, { target: "linux-x64-gnu" }), - /broker dependency license|canonical|mode 0644|unexpected|missing/u, - label, - ); - } - - const directory = stageCarrier(t, "linux-x64-gnu"); - const licenses = path.join(directory, ...BROKER_DEPENDENCY_LICENSE_ROOT.split("/"), "licenses"); - const replacement = path.join(directory, "replacement"); - mkdirSync(replacement, { mode: 0o755 }); - rmSync(licenses, { recursive: true }); - symlinkSync(replacement, licenses, "dir"); - assert.throws( - () => assertBrokerDependencyLicensesInDirectory(directory, { target: "linux-x64-gnu" }), - /symlink|missing/u, - ); -}); - -test("staging rejects a symlinked legal namespace ancestor without touching its target", { timeout: TIMEOUT }, (t) => { - const directory = scratch(t, "symlink-parent-stage"); - const external = scratch(t, "symlink-parent-external"); - const externalRust = path.join(external, "rust"); - mkdirSync(externalRust, { mode: 0o755 }); - const sentinel = path.join(externalRust, "sentinel.txt"); - writeFileSync(sentinel, "must survive\n", { mode: 0o644 }); - symlinkSync(external, path.join(directory, "THIRD_PARTY_LICENSES"), "dir"); - - assert.throws( - () => stageBrokerDependencyLicenses(directory, "linux-x64-gnu"), - /symlink|non-directory ancestor/u, - ); - assert.throws( - () => normalizeBrokerDependencyLicenseModes(directory, "linux-x64-gnu"), - /symlink/u, - ); - assert.throws( - () => assertBrokerDependencyLicensesInDirectory(directory, { target: "linux-x64-gnu" }), - /symlink/u, - ); - assert.equal(readFileSync(sentinel, "utf8"), "must survive\n"); -}); - -test("contract mutations cannot omit legal files, change lock identity, lie about a selected branch, or skew target claims", { timeout: TIMEOUT }, (t) => { - { - const file = writeMutatedContract(t, (contract) => { - const memchr = contract.packages.find(({ name }) => name === "memchr"); - memchr.licenseFiles = memchr.licenseFiles.filter(({ name }) => name !== "UNLICENSE"); - }); - assert.throws( - () => loadBrokerDependencyLicenseContract({ contractPath: file }), - /license blobs differ/u, - ); - } - - { - const file = writeMutatedContract(t, (contract) => { - contract.packages[0].checksum = "0".repeat(64); - }); - assert.throws( - () => loadBrokerDependencyLicenseContract({ contractPath: file, auditLock: true }), - /Cargo\.lock identity changed/u, - ); - } - - { - const file = writeMutatedContract(t, (contract) => { - contract.packages.find(({ name }) => name === "libloading").selectedLicense = "MIT"; - }); - assert.throws( - () => loadBrokerDependencyLicenseContract({ contractPath: file, auditGraph: false }), - /selects MIT but declares ISC/u, - ); - } - - { - const file = writeMutatedContract(t, (contract) => { - const key = "libc@0.2.186"; - contract.targets["linux-x64-gnu"].packages = contract.targets["linux-x64-gnu"].packages.filter((value) => value !== key); - }); - assert.throws( - () => loadBrokerDependencyLicenseContract({ contractPath: file }), - /package graph and package target claims disagree/u, - ); - } -}); diff --git a/tools/release/build-cargo-sdk-ci-artifacts.mjs b/tools/release/build-cargo-sdk-ci-artifacts.mjs deleted file mode 100644 index a58f293b2..000000000 --- a/tools/release/build-cargo-sdk-ci-artifacts.mjs +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bun -import path from "node:path"; - -import { verifyPackagedCargoTestClosure } from "./check-cargo-package-test-closure.mjs"; -import { currentProductVersionSync } from "./release-artifact-targets.mjs"; -import { ROOT, run } from "./release-cli-utils.mjs"; - -const TOOL = "build-cargo-sdk-ci-artifacts.mjs"; -const PRODUCTS = ["oliphaunt-rust", "oliphaunt-wasix-rust"]; - -function fail(message) { - console.error(`${TOOL}: ${message}`); - process.exit(1); -} - -export function cargoSdkPackageClosure(product) { - if (!PRODUCTS.includes(product)) { - throw new Error(`${TOOL}: unsupported Cargo SDK product: ${product}`); - } - const version = currentProductVersionSync(product, TOOL); - const artifactRoot = path.join(ROOT, "target/sdk-artifacts", product); - if (product === "oliphaunt-rust") { - return { - cratePath: path.join(artifactRoot, `oliphaunt-${version}.crate`), - allFeatures: true, - stubDependencyPrefixes: ["liboliphaunt-native-", "oliphaunt-broker-"], - }; - } - if (product === "oliphaunt-wasix-rust") { - return { - cratePath: path.join(artifactRoot, `oliphaunt-wasix-${version}.crate`), - pathDependencyManifests: [ - path.join(ROOT, "src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"), - ], - noDefaultFeatures: true, - features: ["extensions", "tools", "icu"], - }; - } - throw new Error(`${TOOL}: missing Cargo SDK package-closure configuration: ${product}`); -} - -function main() { - const product = Bun.argv[2] ?? ""; - if (product === "--help" || product === "-h") { - console.log(`usage: tools/release/${TOOL} <${PRODUCTS.join("|")}>`); - process.exit(0); - } - if (!PRODUCTS.includes(product) || Bun.argv.length !== 3) { - fail(`usage: tools/release/${TOOL} <${PRODUCTS.join("|")}>`); - } - - run(TOOL, ["cargo", "fetch", "--locked"]); - run(TOOL, [process.execPath, "tools/release/build-sdk-ci-artifacts.mjs", product]); - verifyPackagedCargoTestClosure(cargoSdkPackageClosure(product)); - console.log(`Built and verified exact ${product} Cargo SDK artifacts`); -} - -if (import.meta.main) { - main(); -} diff --git a/tools/release/build-cargo-sdk-ci-artifacts.test.mjs b/tools/release/build-cargo-sdk-ci-artifacts.test.mjs deleted file mode 100644 index 2125ce90b..000000000 --- a/tools/release/build-cargo-sdk-ci-artifacts.test.mjs +++ /dev/null @@ -1,45 +0,0 @@ -import assert from "node:assert/strict"; -import path from "node:path"; -import test from "node:test"; - -import { cargoSdkPackageClosure } from "./build-cargo-sdk-ci-artifacts.mjs"; -import { currentProductVersionSync } from "./release-artifact-targets.mjs"; -import { ROOT } from "./release-cli-utils.mjs"; - -test("selects exact final-crate closure checks only for the two Cargo SDKs", () => { - const rustVersion = currentProductVersionSync("oliphaunt-rust", "cargo-sdk-wrapper.test"); - const rust = cargoSdkPackageClosure("oliphaunt-rust"); - assert.equal( - rust.cratePath, - path.join(ROOT, `target/sdk-artifacts/oliphaunt-rust/oliphaunt-${rustVersion}.crate`), - ); - assert.equal(rust.allFeatures, true); - assert.equal(rust.stubDependencies, undefined); - assert.deepEqual(rust.stubDependencyPrefixes, [ - "liboliphaunt-native-", - "oliphaunt-broker-", - ]); - - const wasixVersion = currentProductVersionSync( - "oliphaunt-wasix-rust", - "cargo-sdk-wrapper.test", - ); - const wasix = cargoSdkPackageClosure("oliphaunt-wasix-rust"); - assert.equal( - wasix.cratePath, - path.join( - ROOT, - `target/sdk-artifacts/oliphaunt-wasix-rust/oliphaunt-wasix-${wasixVersion}.crate`, - ), - ); - assert.equal(wasix.noDefaultFeatures, true); - assert.deepEqual(wasix.features, ["extensions", "tools", "icu"]); - assert.deepEqual(wasix.pathDependencyManifests, [ - path.join(ROOT, "src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"), - ]); - - assert.throws( - () => cargoSdkPackageClosure("oliphaunt-kotlin"), - /unsupported Cargo SDK product/u, - ); -}); diff --git a/tools/release/build-extension-ci-artifacts.mjs b/tools/release/build-extension-ci-artifacts.mjs deleted file mode 100644 index 56229a469..000000000 --- a/tools/release/build-extension-ci-artifacts.mjs +++ /dev/null @@ -1,1075 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import { - copyFileSync, - cpSync, - existsSync, - mkdirSync, - readdirSync, - readFileSync, - rmSync, - statSync, - writeFileSync, - chmodSync, -} from "node:fs"; -import path from "node:path"; - -import { - assertReleaseNoticesInArchive, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { - assertExtensionUpstreamLicensesInArchive, - extensionCarrierLegalContract, - stageExtensionUpstreamLicenses, -} from "./extension-upstream-licenses.mjs"; - -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { extensionRuntimeAssetContract } from "./extension-runtime-asset-contract.mjs"; -import { canonicalGzipSync } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - ROOT, - compareText, - currentProductVersionSync, - exactExtensionProducts, - extensionArtifactProductRoot, - extensionArtifactTargets, - extensionMetadata, - extensionReleaseProduct, - extensionReleaseVersion, - extensionSourceIdentity, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { - swiftExtensionCarrierAssetName, - writeSwiftExtensionCarrierManifest, -} from "./ios-carrier-manifest.mjs"; -import { AOT_TARGET_TRIPLES } from "./wasix-cargo-artifact-contract.mjs"; -import { assertCanonicalWasixAotManifest } from "./wasix-aot-manifest.mjs"; -import { - assertWasixExtensionArchiveInstall, - assertWasixExtensionInstallSidecar, - projectWasixExtensionInstallSidecar, -} from "../../src/shared/extension-runtime-contract/wasix-extension-install.mjs"; - -const PREFIX = "build-extension-ci-artifacts.mjs"; - -function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(1); -} - -function rel(file) { - return path.relative(ROOT, file).split(path.sep).join("/"); -} - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function extensionProducts() { - return exactExtensionProducts(PREFIX); -} - -function generatedExtensionRow(sqlName) { - const metadata = path.join(ROOT, "src/extensions/generated/sdk/extensions.json"); - const data = JSON.parse(readFileSync(metadata, "utf8")); - const row = (data.extensions ?? []).find((item) => item && item["sql-name"] === sqlName); - if (!row) { - fail(`generated extension metadata has no row for ${sqlName}`); - } - return row; -} - -function stringList(value, label) { - if ( - !Array.isArray(value) - || value.some((item) => typeof item !== "string" || item.length === 0) - || new Set(value).size !== value.length - ) { - fail(`generated extension metadata ${label} must be a unique non-empty string list`); - } - return [...value].sort(compareText); -} - -function propertiesCsv(values) { - return values.join(","); -} - -export function publicExtensionReleaseAsset(asset) { - return extensionRuntimeAssetContract(asset); -} - -function resolveRepoPath(value, { label }) { - const resolved = path.resolve(ROOT, value); - const relative = path.relative(ROOT, resolved); - if (relative.startsWith("..") || path.isAbsolute(relative)) { - fail(`${label} must be inside the repository: ${resolved}`); - } - return resolved; -} - -function nativeReleaseAssetRoot() { - return resolveRepoPath(process.env.OLIPHAUNT_NATIVE_EXTENSION_RELEASE_ASSET_ROOT ?? "target/extensions/native/release-assets", { - label: "native extension release asset root", - }); -} - -function wasixReleaseAssetRoot() { - return resolveRepoPath(process.env.OLIPHAUNT_WASIX_EXTENSION_RELEASE_ASSET_ROOT ?? "target/extensions/wasix/release-assets", { - label: "WASIX extension release asset root", - }); -} - -function wasixAotArtifactRoot() { - return resolveRepoPath(process.env.OLIPHAUNT_WASIX_EXTENSION_AOT_ARTIFACT_ROOT ?? "target/extensions/wasix/aot-artifacts", { - label: "WASIX extension AOT artifact root", - }); -} - -function parseTsv(file) { - const lines = readFileSync(file, "utf8").split(/\r?\n/u).filter((line) => line.length > 0); - if (lines.length === 0) { - return []; - } - const header = lines[0].split("\t"); - return lines.slice(1).map((line) => { - const values = line.split("\t"); - return Object.fromEntries(header.map((column, index) => [column, values[index] ?? ""])); - }); -} - -function indexContainsSqlName(index, sqlName) { - return parseTsv(index).some((row) => row.sql_name === sqlName); -} - -function publishedTargetIds(family) { - return [...new Set( - extensionArtifactTargets({ family }, PREFIX).map((target) => target.target), - )].sort(compareText); -} - -function nativeExtensionAssetIndexes(sqlName, product = undefined) { - const version = currentProductVersionSync("liboliphaunt-native", PREFIX); - const root = nativeReleaseAssetRoot(); - const indexes = []; - for (const target of publishedTargetIds("native")) { - const targetRoot = path.join(root, target); - if (product !== undefined) { - const productIndex = path.join(targetRoot, product, `liboliphaunt-${version}-native-extension-assets.tsv`); - if (existsSync(productIndex) && indexContainsSqlName(productIndex, sqlName)) { - indexes.push(productIndex); - continue; - } - } - const directIndex = path.join(targetRoot, `liboliphaunt-${version}-native-extension-assets.tsv`); - if (existsSync(directIndex)) { - indexes.push(directIndex); - } - } - return indexes.sort(compareText); -} - -function nativeAssetsFromTargetIndexes(sqlName, { product = undefined, required = false } = {}) { - const indexes = nativeExtensionAssetIndexes(sqlName, product); - if (indexes.length === 0) { - return []; - } - const assets = []; - const seen = new Set(); - for (const index of indexes) { - for (const row of parseTsv(index)) { - if (row.sql_name !== sqlName) { - continue; - } - const { target, kind, artifact } = row; - if (!target || !kind || !artifact) { - fail(`${rel(index)} has an incomplete native asset row for ${sqlName}`); - } - const identity = row.identity && row.identity !== "-" ? row.identity : null; - const registrationArtifact = row.registration_artifact && row.registration_artifact !== "-" - ? path.join(path.dirname(index), row.registration_artifact) - : null; - if (kind === "ios-dependency-xcframework" && identity === null) { - fail(`${rel(index)} iOS dependency XCFramework row for ${sqlName} must declare identity`); - } - if (kind !== "ios-dependency-xcframework" && identity !== null && kind !== "ios-xcframework") { - fail(`${rel(index)} ${kind} row for ${sqlName} must not declare identity`); - } - const dedupeKey = `${target}\0${kind}\0${identity ?? ""}`; - if (seen.has(dedupeKey)) { - fail(`duplicate native extension asset row for ${sqlName} target=${target} kind=${kind} identity=${identity ?? "-"}`); - } - seen.add(dedupeKey); - const asset = path.join(path.dirname(index), artifact); - if (!existsSync(asset) || !statSync(asset).isFile()) { - fail(`${rel(index)} references missing native asset ${rel(asset)}`); - } - if (registrationArtifact !== null && (!existsSync(registrationArtifact) || !statSync(registrationArtifact).isFile())) { - fail(`${rel(index)} references missing registration metadata ${rel(registrationArtifact)}`); - } - assets.push({ asset, target, kind, identity, registrationArtifact }); - } - } - if (required && assets.length === 0) { - fail(`${sqlName} has no native extension assets in native target asset indexes`); - } - return assets; -} - -function nativeAssetsFor(sqlName, { product = undefined, required = false } = {}) { - const indexed = nativeAssetsFromTargetIndexes(sqlName, { product, required: false }); - if (indexed.length > 0) { - return indexed; - } - if (required) { - fail(`${sqlName}${product ? ` for ${product}` : ""} has no native extension assets in native target asset indexes`); - } - return []; -} - -function wasixArchiveFor(sqlName, { product = undefined, required = false } = {}) { - const version = currentProductVersionSync("liboliphaunt-wasix", PREFIX); - const root = wasixReleaseAssetRoot(); - const indexes = []; - for (const target of publishedTargetIds("wasix")) { - const targetRoot = path.join(root, target); - if (product !== undefined) { - const productIndex = path.join(targetRoot, product, `liboliphaunt-wasix-${version}-wasix-extension-assets.tsv`); - if (existsSync(productIndex)) { - indexes.push(productIndex); - continue; - } - } - const directIndex = path.join(targetRoot, `liboliphaunt-wasix-${version}-wasix-extension-assets.tsv`); - if (existsSync(directIndex)) { - indexes.push(directIndex); - } - } - const assets = []; - for (const index of indexes) { - for (const row of parseTsv(index)) { - if (row.sql_name !== sqlName) { - continue; - } - const { target, kind, artifact, install_contract: installContractName } = row; - if ( - target !== "wasix-portable" - || kind !== "wasix-runtime" - || !artifact - || !/^[1-9][0-9]*$/u.test(row.artifact_bytes ?? "") - || !installContractName - ) { - fail(`${rel(index)} has an invalid WASIX asset row for ${sqlName}`); - } - const asset = path.join(path.dirname(index), artifact); - if (!existsSync(asset) || !statSync(asset).isFile()) { - fail(`${rel(index)} references missing WASIX asset ${rel(asset)}`); - } - if (statSync(asset).size !== Number(row.artifact_bytes)) { - fail(`${rel(index)} references a WASIX asset with a drifted byte count for ${sqlName}`); - } - const installContractPath = path.join(path.dirname(index), installContractName); - if (!existsSync(installContractPath) || !statSync(installContractPath).isFile()) { - fail(`${rel(index)} references missing WASIX install contract ${rel(installContractPath)}`); - } - let sidecar; - try { - sidecar = assertWasixExtensionInstallSidecar( - JSON.parse(readFileSync(installContractPath, "utf8")), - { - expectedArchive: `extensions/${sqlName}.tar.zst`, - expectedSha256: sha256(asset), - expectedSize: statSync(asset).size, - expectedSqlName: sqlName, - label: rel(installContractPath), - }, - ); - assertWasixExtensionArchiveInstall(readFileSync(asset), sidecar, { - label: rel(asset), - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - assets.push({ archive: asset, install: sidecar.install }); - } - } - if (assets.length > 1) { - fail(`${sqlName} has duplicate WASIX extension assets: ${assets.map(({ archive }) => rel(archive)).join(", ")}`); - } - if (assets.length === 1) { - return assets[0]; - } - const generatedRootValue = process.env.OLIPHAUNT_WASIX_GENERATED_ASSET_ROOT; - if (generatedRootValue) { - const generatedRoot = resolveRepoPath(generatedRootValue, { - label: "generated WASIX asset root", - }); - const manifestPath = path.join(generatedRoot, "manifest.json"); - if (!existsSync(manifestPath) || !statSync(manifestPath).isFile()) { - fail(`generated WASIX asset root is missing ${rel(manifestPath)}`); - } - let manifest; - try { - manifest = JSON.parse(readFileSync(manifestPath, "utf8")); - } catch (error) { - fail(`${rel(manifestPath)} is not valid JSON: ${error.message}`); - } - const rows = Array.isArray(manifest.extensions) - ? manifest.extensions.filter((row) => row?.["sql-name"] === sqlName) - : []; - if (rows.length !== 1) { - fail(`${rel(manifestPath)} must contain exactly one extension row for ${sqlName}, got ${rows.length}`); - } - const row = rows[0]; - const expectedArchive = `extensions/${sqlName}.tar.zst`; - if (row.archive !== expectedArchive || !/^[0-9a-f]{64}$/u.test(row.sha256 ?? "")) { - fail(`${rel(manifestPath)} has a noncanonical archive identity for ${sqlName}`); - } - const archive = path.join(generatedRoot, expectedArchive); - if (!existsSync(archive) || !statSync(archive).isFile()) { - fail(`${rel(manifestPath)} references missing WASIX extension archive ${rel(archive)}`); - } - if (sha256(archive) !== row.sha256) { - fail(`${rel(archive)} does not match the digest in ${rel(manifestPath)}`); - } - const modelPath = path.join(ROOT, "src/extensions/generated/wasix/extensions.json"); - let model; - try { - model = JSON.parse(readFileSync(modelPath, "utf8")); - } catch (error) { - fail(`${rel(modelPath)} is not valid JSON: ${error.message}`); - } - const modelRows = Array.isArray(model.extensions) - ? model.extensions.filter((candidate) => candidate?.["sql-name"] === sqlName) - : []; - if (modelRows.length !== 1) { - fail(`${rel(modelPath)} must contain exactly one static extension row for ${sqlName}, got ${modelRows.length}`); - } - let sidecar; - try { - sidecar = projectWasixExtensionInstallSidecar({ - modelRow: modelRows[0], - manifestRow: row, - }, { - archiveBytes: readFileSync(archive), - label: `${rel(manifestPath)} extension ${sqlName}`, - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - return { archive, install: sidecar.install }; - } - if (required) { - fail(`${sqlName} has no WASIX extension assets in target/extensions/wasix/release-assets target indexes`); - } - return undefined; -} - -function wasixAotDirsFor(sqlName) { - const root = wasixAotArtifactRoot(); - if (!existsSync(root) || !statSync(root).isDirectory()) { - return []; - } - return readdirSync(root, { withFileTypes: true }) - .filter((entry) => entry.isDirectory()) - .map((entry) => [entry.name, path.join(root, entry.name, sqlName)]) - .filter(([, candidate]) => existsSync(path.join(candidate, "manifest.json"))) - .sort(([left], [right]) => compareText(left, right)); -} - -function validateWasixAotDir(targetId, source) { - const expectedTarget = AOT_TARGET_TRIPLES[targetId]; - if (expectedTarget === undefined) { - fail(`WASIX extension AOT artifact root contains unknown target id ${targetId}`); - } - const manifestPath = path.join(source, "manifest.json"); - let manifest; - try { - manifest = JSON.parse(readFileSync(manifestPath, "utf8")); - } catch (error) { - fail(`${rel(manifestPath)} is not valid JSON: ${error.message}`); - } - try { - assertCanonicalWasixAotManifest(manifest, { - context: rel(manifestPath), - expectedTarget, - }); - } catch (error) { - fail(error.message); - } -} - -function copyAsset(source, destinationDir, { name }) { - mkdirSync(destinationDir, { recursive: true }); - const destination = path.join(destinationDir, name); - copyFileSync(source, destination); - // Release payloads are data, not host executables. A fixed mode keeps the - // aggregate archive independent of the producer's umask and checkout mode. - chmodSync(destination, 0o644); - return { - name: path.basename(destination), - path: rel(destination), - source: rel(source), - sha256: sha256(destination), - bytes: statSync(destination).size, - }; -} - -function nativeAssetName(product, version, target, kind, source) { - const suffix = archiveSuffix(source); - if (target === "macos-arm64") { - return `${product}-${version}-native-macos-arm64-runtime${suffix}`; - } - if (target.startsWith("linux-")) { - return `${product}-${version}-native-${target}-runtime${suffix}`; - } - if (target.startsWith("windows-")) { - return `${product}-${version}-native-${target}-runtime${suffix}`; - } - if (target === "ios-xcframework") { - if (kind === "runtime") { - return `${product}-${version}-native-ios-runtime${suffix}`; - } - if (kind === "ios-xcframework") { - return `${product}-${version}-native-ios-xcframework${suffix}`; - } - if (kind === "ios-dependency-xcframework") { - fail(`iOS dependency XCFramework ${path.basename(source)} requires its exact dependency identity`); - } - fail(`unsupported iOS extension artifact kind ${kind} for ${path.basename(source)}`); - } - if (target.startsWith("android-")) { - if (kind === "runtime") { - return `${product}-${version}-native-${target}-runtime${suffix}`; - } - if (kind === "android-static-archive") { - return `${product}-${version}-native-${target}-static${suffix}`; - } - fail(`unsupported Android extension artifact kind ${kind} for ${path.basename(source)}`); - } - fail(`unsupported native extension artifact target ${target} for ${path.basename(source)}`); -} - -function nativeAssetNameForRow(product, version, row) { - if (row.kind === "ios-dependency-xcframework") { - return `${product}-${version}-native-ios-dependency-${row.identity}-xcframework${archiveSuffix(row.asset)}`; - } - return nativeAssetName(product, version, row.target, row.kind, row.asset); -} - -function readIosRegistration(file, { sqlName, nativeModuleStem }) { - if (file === null) return null; - let value; - try { - value = JSON.parse(readFileSync(file, "utf8")); - } catch (error) { - fail(`${rel(file)} is not valid registration JSON: ${error.message}`); - } - if ( - value?.schema !== "oliphaunt-ios-extension-registration-v1" - || value.sqlName !== sqlName - || value.nativeModuleStem !== nativeModuleStem - || typeof value.magicSymbol !== "string" - || !(value.initSymbol === null || typeof value.initSymbol === "string") - || !Array.isArray(value.symbols) - ) { - fail(`${rel(file)} does not describe ${sqlName}/${nativeModuleStem} iOS registration`); - } - return value; -} - -function archiveSuffix(source) { - for (const suffix of [".tar.gz", ".tar.zst", ".zip"]) { - if (source.endsWith(suffix)) { - return suffix; - } - } - fail(`native extension asset ${path.basename(source)} must use .tar.gz, .tar.zst, or .zip`); -} - -function validateStagedTargets(product, assets, { requireNative, requireWasix, requireNativeTargets }) { - const declaredNativeTargets = new Set( - extensionArtifactTargets({ product, family: "native" }, PREFIX).map((target) => target.target), - ); - const declaredWasixTargets = new Set( - extensionArtifactTargets({ product, family: "wasix" }, PREFIX).map((target) => target.target), - ); - const stagedNativeTargets = new Set(assets.filter((asset) => asset.family === "native").map((asset) => String(asset.target))); - const stagedWasixTargets = new Set(assets.filter((asset) => asset.family === "wasix").map((asset) => String(asset.target))); - const extraNative = [...stagedNativeTargets].filter((target) => !declaredNativeTargets.has(target)).sort(compareText); - const extraWasix = [...stagedWasixTargets].filter((target) => !declaredWasixTargets.has(target)).sort(compareText); - if (extraNative.length > 0) { - fail(`${product} staged undeclared native extension targets: ${extraNative.join(", ")}`); - } - if (extraWasix.length > 0) { - fail(`${product} staged undeclared WASIX extension targets: ${extraWasix.join(", ")}`); - } - if (requireNativeTargets.size > 0) { - const unknownRequired = [...requireNativeTargets].filter((target) => !declaredNativeTargets.has(target)).sort(compareText); - if (unknownRequired.length > 0) { - fail(`${product} was asked to require undeclared native targets: ${unknownRequired.join(", ")}`); - } - const missingNative = [...requireNativeTargets].filter((target) => !stagedNativeTargets.has(target)).sort(compareText); - if (missingNative.length > 0) { - fail(`${product} is missing native extension artifacts for: ${missingNative.join(", ")}`); - } - } else if (requireNative) { - const missingNative = [...declaredNativeTargets].filter((target) => !stagedNativeTargets.has(target)).sort(compareText); - if (missingNative.length > 0) { - fail(`${product} is missing native extension artifacts for: ${missingNative.join(", ")}`); - } - } - if (requireWasix) { - const missingWasix = [...declaredWasixTargets].filter((target) => !stagedWasixTargets.has(target)).sort(compareText); - if (missingWasix.length > 0) { - fail(`${product} is missing WASIX extension artifacts for: ${missingWasix.join(", ")}`); - } - } -} - -function publicMemberAsset(asset) { - return publicExtensionReleaseAsset(asset); -} - -function stageMember(product, sqlName, version, productRoot, { - destinationDir, - bundle, - families, - requireNative, - requireWasix, - requireNativeTargets, -}) { - const extensionRow = generatedExtensionRow(sqlName); - const assets = []; - let wasixInstall = null; - let iosRegistration = null; - for (const row of families.has("native") - ? nativeAssetsFor(sqlName, { product, required: requireNative }) - : []) { - const target = row.target; - if (requireNativeTargets.size > 0 && !requireNativeTargets.has(target)) { - continue; - } - const metadata = copyAsset(row.asset, destinationDir, { - name: nativeAssetNameForRow(product, version, row), - }); - metadata.family = "native"; - metadata.kind = row.kind; - metadata.target = target; - metadata.identity = row.identity; - assets.push(metadata); - if (row.registrationArtifact !== null) { - const registration = readIosRegistration(row.registrationArtifact, { - sqlName, - nativeModuleStem: extensionRow["native-module-stem"], - }); - if (iosRegistration !== null && JSON.stringify(iosRegistration) !== JSON.stringify(registration)) { - fail(`${product} has conflicting iOS registration metadata`); - } - iosRegistration = registration; - } - } - - const wasix = families.has("wasix") - ? wasixArchiveFor(sqlName, { product, required: requireWasix }) - : undefined; - if (wasix !== undefined) { - const metadata = copyAsset(wasix.archive, destinationDir, { - name: `${product}-${version}-wasix-portable.tar.zst`, - }); - metadata.family = "wasix"; - metadata.kind = "wasix-runtime"; - metadata.target = "wasix-portable"; - metadata.identity = null; - assets.push(metadata); - wasixInstall = wasix.install; - } - - for (const [targetId, source] of families.has("wasix") ? wasixAotDirsFor(sqlName) : []) { - validateWasixAotDir(targetId, source); - const destination = bundle - ? path.join(productRoot, "wasix-aot", targetId, sqlName) - : path.join(productRoot, "wasix-aot", targetId); - rmSync(destination, { recursive: true, force: true }); - cpSync(source, destination, { recursive: true }); - } - - validateStagedTargets(product, assets, { - requireNative, - requireWasix, - requireNativeTargets, - }); - if (assets.length === 0) { - fail(`${product}/${sqlName} produced no extension artifacts`); - } - return { - sqlName, - createsExtension: extensionRow["creates-extension"] !== false, - dependencies: stringList(extensionRow["selected-extension-dependencies"], `${sqlName}.selected-extension-dependencies`), - dataFiles: stringList(extensionRow["runtime-share-data-files"], `${sqlName}.runtime-share-data-files`), - extensionSqlFileNames: stringList(extensionRow["extension-sql-file-names"], `${sqlName}.extension-sql-file-names`), - extensionSqlFilePrefixes: stringList(extensionRow["extension-sql-file-prefixes"], `${sqlName}.extension-sql-file-prefixes`), - nativeModuleStem: extensionRow["native-module-stem"], - iosNativeDependencies: assets - .filter((asset) => asset.kind === "ios-dependency-xcframework") - .map((asset) => asset.identity) - .sort(compareText), - iosRegistration, - wasixInstall, - sharedPreloadLibraries: stringList(extensionRow["shared-preload-libraries"], `${sqlName}.shared-preload-libraries`), - assets, - }; -} - -function bundleCarrierAssets(product, version, productRoot, members, compatibility) { - const assetDir = path.join(productRoot, "release-assets"); - const stageRoot = path.join(productRoot, ".bundle-stage"); - const groups = new Map(); - for (const member of members) { - for (const asset of member.assets) { - const key = `${asset.family}\0${asset.target}`; - const group = groups.get(key) ?? { family: asset.family, target: asset.target, rows: [] }; - group.rows.push({ sqlName: member.sqlName, asset }); - groups.set(key, group); - } - } - const carrierAssets = []; - for (const group of [...groups.values()].sort((left, right) => compareText(`${left.family}\0${left.target}`, `${right.family}\0${right.target}`))) { - const memberNames = [...new Set(group.rows.map((row) => row.sqlName))].sort(compareText); - const expectedNames = members.map((member) => member.sqlName).sort(compareText); - if (JSON.stringify(memberNames) !== JSON.stringify(expectedNames)) { - fail(`${product} ${group.family}/${group.target} bundle is missing exact members: expected ${expectedNames.join(",")}, got ${memberNames.join(",")}`); - } - const archiveRoot = `${product}-${version}-${group.family}-${group.target}-bundle`; - const stageDir = path.join(stageRoot, archiveRoot); - rmSync(stageDir, { recursive: true, force: true }); - mkdirSync(stageDir, { recursive: true }); - const manifestMembers = []; - for (const row of group.rows.sort((left, right) => compareText( - `${left.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ""}`, - `${right.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ""}`, - ))) { - const memberPath = `extensions/${row.sqlName}/${row.asset.name}`; - const source = path.join(ROOT, row.asset.path); - const destination = path.join(stageDir, ...memberPath.split("/")); - mkdirSync(path.dirname(destination), { recursive: true }); - copyFileSync(source, destination); - chmodSync(destination, 0o644); - const copiedSha256 = sha256(destination); - const copiedBytes = statSync(destination).size; - if (copiedSha256 !== row.asset.sha256 || copiedBytes !== row.asset.bytes) { - fail(`${product} ${group.family}/${group.target} changed ${row.sqlName} member bytes while staging ${memberPath}`); - } - const member = { - sqlName: row.sqlName, - kind: row.asset.kind, - identity: row.asset.identity ?? null, - path: memberPath, - sha256: row.asset.sha256, - bytes: row.asset.bytes, - }; - manifestMembers.push(member); - row.asset.carrierAsset = `${archiveRoot}.tar.gz`; - row.asset.carrierRoot = archiveRoot; - row.asset.memberPath = memberPath; - } - const externalLicenseFiles = []; - for (const sqlName of memberNames) { - externalLicenseFiles.push(...stageExtensionUpstreamLicenses(sqlName, stageDir)); - } - const legal = extensionCarrierLegalContract(product, memberNames, { - family: group.family, - target: group.target, - }); - const stagedLicenseFiles = [...new Set(externalLicenseFiles)].sort(compareText); - if (JSON.stringify(stagedLicenseFiles) !== JSON.stringify(legal.licenseFiles)) { - fail( - `${product} ${group.family}/${group.target} staged upstream licenses differ from its legal contract: ` - + `expected ${legal.licenseFiles.join(",")}, got ${stagedLicenseFiles.join(",")}`, - ); - } - const bundleManifest = path.join(stageDir, "bundle-manifest.json"); - writeFileSync(bundleManifest, `${JSON.stringify(sortValue({ - schema: "oliphaunt-extension-bundle-v1", - product, - version, - compatibility, - family: group.family, - target: group.target, - licenseProfile: legal.profile, - licenseFiles: legal.licenseFiles, - members: manifestMembers, - }), null, 2)}\n`, "utf8"); - chmodSync(bundleManifest, 0o644); - stageReleaseNotices(stageDir, { profile: legal.profile }); - const output = path.join(assetDir, `${archiveRoot}.tar.gz`); - writeFileSync(output, canonicalGzipSync(createDeterministicTar(stageDir, archiveRoot, { - fail, - // Every bundle member is data. Windows filesystem modes are synthetic, - // so encode the portable carrier contract instead of copying stat bits. - fixedFileMode: 0o644, - }))); - assertReleaseNoticesInArchive(output, { - prefix: archiveRoot, - profile: legal.profile, - }); - if (legal.upstreamMembers.length > 0) { - assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, output, { - prefix: archiveRoot, - }); - } - carrierAssets.push({ - name: path.basename(output), - path: rel(output), - sha256: sha256(output), - bytes: statSync(output).size, - family: group.family, - target: group.target, - kind: "extension-bundle", - memberCount: memberNames.length, - }); - } - rmSync(stageRoot, { recursive: true, force: true }); - return carrierAssets; -} - -export function extensionReleasePropertiesText({ - product, - releaseProduct = product, - family = null, - version, - manifest, - releaseData, - directAssets, -}) { - const sourceIdentity = releaseData.sourceIdentity; - const propertiesLines = [ - `schema=${releaseData.schema}\n`, - `product=${product}\n`, - ...(releaseProduct === product ? [] : [ - `releaseProduct=${releaseProduct}\n`, - `carrierFamily=${family ?? "combined"}\n`, - ]), - `version=${version}\n`, - `extensionClass=${releaseData.extensionClass}\n`, - `versioning=${releaseData.versioning}\n`, - `sourceKind=${sourceIdentity.kind}\n`, - ]; - if (manifest.schema === "oliphaunt-extension-ci-artifacts-v1") { - propertiesLines.push( - `sqlName=${manifest.sqlName}\n`, - `createsExtension=${manifest.createsExtension ? "true" : "false"}\n`, - `dependencies=${propertiesCsv(manifest.dependencies)}\n`, - `dataFiles=${propertiesCsv(manifest.dataFiles)}\n`, - `extensionSqlFileNames=${propertiesCsv(manifest.extensionSqlFileNames)}\n`, - `extensionSqlFilePrefixes=${propertiesCsv(manifest.extensionSqlFilePrefixes)}\n`, - `nativeModuleStem=${manifest.nativeModuleStem || ""}\n`, - `iosNativeDependencies=${propertiesCsv(manifest.iosNativeDependencies)}\n`, - `sharedPreloadLibraries=${propertiesCsv(manifest.sharedPreloadLibraries)}\n`, - ); - for (const asset of [...manifest.assets].sort((left, right) => compareText( - `${left.family}\0${left.target}\0${left.kind}\0${left.identity ?? ""}\0${left.name}`, - `${right.family}\0${right.target}\0${right.kind}\0${right.identity ?? ""}\0${right.name}`, - ))) { - const identity = asset.identity === null || asset.identity === undefined ? "" : `.${asset.identity}`; - propertiesLines.push(`asset.${asset.family}.${asset.target}.${asset.kind}${identity}=${asset.name}\n`); - } - } else { - propertiesLines.push(`extensions=${manifest.extensions.map((row) => row.sqlName).join(",")}\n`); - for (const member of manifest.extensions) { - const prefix = `extension.${member.sqlName}`; - propertiesLines.push( - `${prefix}.createsExtension=${member.createsExtension ? "true" : "false"}\n`, - `${prefix}.dependencies=${propertiesCsv(member.dependencies)}\n`, - `${prefix}.dataFiles=${propertiesCsv(member.dataFiles)}\n`, - `${prefix}.extensionSqlFileNames=${propertiesCsv(member.extensionSqlFileNames)}\n`, - `${prefix}.extensionSqlFilePrefixes=${propertiesCsv(member.extensionSqlFilePrefixes)}\n`, - `${prefix}.nativeModuleStem=${member.nativeModuleStem || ""}\n`, - `${prefix}.iosNativeDependencies=${propertiesCsv(member.iosNativeDependencies)}\n`, - `${prefix}.sharedPreloadLibraries=${propertiesCsv(member.sharedPreloadLibraries)}\n`, - ); - for (const asset of member.assets) { - const identity = asset.identity === null || asset.identity === undefined ? "" : `.${asset.identity}`; - propertiesLines.push(`asset.${member.sqlName}.${asset.family}.${asset.target}.${asset.kind}${identity}=${asset.carrierAsset}:${asset.memberPath}:${asset.sha256}:${asset.bytes}\n`); - } - } - for (const asset of [...directAssets].sort((left, right) => compareText(`${left.family}\0${left.target}\0${left.kind}`, `${right.family}\0${right.target}\0${right.kind}`))) { - propertiesLines.push(`carrier.${asset.family}.${asset.target}.${asset.kind}=${asset.name}\n`); - } - } - return propertiesLines.join(""); -} - -function writeReleaseControls({ product, releaseProduct, family, version, productRoot, manifest, releaseData, releaseMetadata, directAssets }) { - const assetDir = path.join(productRoot, "release-assets"); - const extensionManifest = path.join(productRoot, "extension-artifacts.json"); - writeFileSync(extensionManifest, `${JSON.stringify(sortValue(manifest), null, 2)}\n`, "utf8"); - const swiftCarrier = directAssets.some((asset) => asset.family === "native" && asset.target === "ios-xcframework") - ? path.join(assetDir, swiftExtensionCarrierAssetName(product, version)) - : null; - if (swiftCarrier !== null) { - writeSwiftExtensionCarrierManifest(swiftCarrier, { - extensionManifest, - nativeRuntimeVersion: releaseMetadata.compatibility.nativeRuntimeVersion, - }); - } - const releaseManifest = path.join(assetDir, `${product}-${version}-manifest.json`); - writeFileSync(releaseManifest, `${JSON.stringify(sortValue(releaseData), null, 2)}\n`, "utf8"); - - const propertiesManifest = path.join(assetDir, `${product}-${version}-manifest.properties`); - writeFileSync( - propertiesManifest, - extensionReleasePropertiesText({ product, releaseProduct, family, version, manifest, releaseData, directAssets }), - "utf8", - ); - - const checksumManifest = path.join(assetDir, `${product}-${version}-release-assets.sha256`); - const checksumLines = readdirSync(assetDir) - .map((name) => path.join(assetDir, name)) - .filter((file) => statSync(file).isFile() && file !== checksumManifest) - .sort(compareText) - .map((file) => `${sha256(file)} ./${path.basename(file)}\n`); - writeFileSync(checksumManifest, checksumLines.join(""), "utf8"); - const payloadPaths = Object.freeze(directAssets.map((asset) => asset.path)); - const controlPaths = Object.freeze([ - rel(releaseManifest), - rel(propertiesManifest), - ...(swiftCarrier === null ? [] : [rel(swiftCarrier)]), - rel(checksumManifest), - ]); - const artifactPaths = [...new Set([...payloadPaths, ...controlPaths])]; - writeFileSync( - path.join(productRoot, "artifacts.txt"), - artifactPaths.map((file) => `${file}\n`).join(""), - "utf8", - ); - return { swiftCarrier, releaseManifest, propertiesManifest, checksumManifest }; -} - -function stageProductVariant(product, { - outputRoot, - family, - requireNative, - requireWasix, - requireNativeTargets, -}) { - const known = new Set(extensionProducts()); - if (!known.has(product)) { - fail(`unknown exact-extension product ${product}; expected one of: ${[...known].sort(compareText).join(", ")}`); - } - const families = new Set(family === null ? ["native", "wasix"] : [family]); - const releaseProduct = extensionReleaseProduct(product, family ?? "native", PREFIX); - const ownership = releaseProduct === product - ? {} - : { releaseProduct, family: family ?? "combined" }; - const sqlNames = extensionSqlNames(product, PREFIX); - const version = extensionReleaseVersion(product, family ?? "native", PREFIX); - const productRoot = extensionArtifactProductRoot(product, family ?? "native", outputRoot, PREFIX); - const assetDir = path.join(productRoot, "release-assets"); - rmSync(productRoot, { recursive: true, force: true }); - mkdirSync(assetDir, { recursive: true }); - const bundle = sqlNames.length > 1; - const members = sqlNames.map((sqlName) => stageMember(product, sqlName, version, productRoot, { - destinationDir: bundle ? path.join(productRoot, "member-assets", sqlName) : assetDir, - bundle, - families, - requireNative: families.has("native") && requireNative, - requireWasix: families.has("wasix") && requireWasix, - requireNativeTargets: families.has("native") ? requireNativeTargets : new Set(), - })); - const releaseMetadata = extensionMetadata(product, PREFIX); - let manifest; - let releaseData; - let directAssets; - if (bundle) { - directAssets = bundleCarrierAssets( - product, - version, - productRoot, - members, - releaseMetadata.compatibility, - ); - manifest = { - schema: "oliphaunt-extension-ci-artifacts-v2", - product, - ...ownership, - version, - compatibility: releaseMetadata.compatibility, - extensions: members, - carrierAssets: directAssets, - }; - releaseData = { - schema: "oliphaunt-extension-release-manifest-v2", - product, - ...ownership, - version, - extensionClass: releaseMetadata.class, - versioning: releaseMetadata.versioning, - sourceIdentity: extensionSourceIdentity(product, PREFIX), - compatibility: releaseMetadata.compatibility, - extensions: members.map((member) => ({ ...member, assets: member.assets.map(publicMemberAsset) })), - assets: directAssets.map(publicExtensionReleaseAsset), - }; - } else { - const member = members[0]; - directAssets = member.assets; - manifest = { - schema: "oliphaunt-extension-ci-artifacts-v1", - product, - ...ownership, - version, - compatibility: releaseMetadata.compatibility, - ...member, - }; - releaseData = { - schema: "oliphaunt-extension-release-manifest-v1", - product, - ...ownership, - version, - sqlName: member.sqlName, - extensionClass: releaseMetadata.class, - versioning: releaseMetadata.versioning, - sourceIdentity: extensionSourceIdentity(product, PREFIX), - compatibility: releaseMetadata.compatibility, - dependencies: member.dependencies, - dataFiles: member.dataFiles, - extensionSqlFileNames: member.extensionSqlFileNames, - extensionSqlFilePrefixes: member.extensionSqlFilePrefixes, - createsExtension: member.createsExtension, - nativeModuleStem: member.nativeModuleStem, - iosNativeDependencies: member.iosNativeDependencies, - iosRegistration: member.iosRegistration, - wasixInstall: member.wasixInstall, - sharedPreloadLibraries: member.sharedPreloadLibraries, - assets: member.assets.map(publicExtensionReleaseAsset), - }; - } - writeReleaseControls({ - product, - releaseProduct, - family, - version, - productRoot, - manifest, - releaseData, - releaseMetadata, - directAssets, - }); - console.log(`${product} (${family ?? "combined"}, owned by ${releaseProduct}): staged ${members.length} exact member(s) in ${directAssets.length} direct carrier asset(s) under ${rel(productRoot)}`); -} - -function stageProduct(product, options) { - const nativeOwner = extensionReleaseProduct(product, "native", PREFIX); - const wasixOwner = extensionReleaseProduct(product, "wasix", PREFIX); - const families = options.family === null - ? nativeOwner === wasixOwner - ? [null] - : ["native", "wasix"] - : [options.family]; - for (const family of families) { - stageProductVariant(product, { ...options, family }); - } -} - -function selectedProductsFromEnv() { - const raw = process.env.OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS ?? ""; - const products = [...new Set(raw.split(",").map((item) => item.trim()).filter(Boolean))].sort(compareText); - if (products.length === 0) { - return []; - } - const known = new Set(extensionProducts()); - const unknown = products.filter((product) => !known.has(product)); - if (unknown.length > 0) { - fail(`OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS contains unknown exact-extension product(s): ${unknown.join(", ")}`); - } - return products; -} - -function parseArgs(argv) { - const args = { - products: [], - all: false, - outputRoot: "target/extension-artifacts", - family: null, - requireNative: false, - requireWasix: false, - requireNativeTargets: new Set(), - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--all") { - args.all = true; - } else if (arg === "--output-root") { - const value = argv[index + 1]; - if (!value) { - fail("--output-root requires a value"); - } - args.outputRoot = value; - index += 1; - } else if (arg === "--require-native") { - args.requireNative = true; - } else if (arg === "--family") { - const value = argv[index + 1]; - if (!value || !["native", "wasix"].includes(value)) { - fail("--family requires native or wasix"); - } - args.family = value; - index += 1; - } else if (arg === "--require-native-target") { - const value = argv[index + 1]; - if (!value) { - fail("--require-native-target requires a value"); - } - args.requireNativeTargets.add(value); - index += 1; - } else if (arg === "--require-wasix") { - args.requireWasix = true; - } else if (arg === "--help" || arg === "-h") { - console.log("usage: tools/release/build-extension-ci-artifacts.mjs [--all] [--output-root DIR] [--family native|wasix] [--require-native] [--require-native-target TARGET] [--require-wasix] [products...]"); - process.exit(0); - } else if (arg.startsWith("--")) { - fail(`unknown argument ${arg}`); - } else { - args.products.push(arg); - } - } - return args; -} - -function sortValue(value) { - if (Array.isArray(value)) { - return value.map(sortValue); - } - if (value !== null && typeof value === "object") { - return Object.fromEntries(Object.keys(value).sort(compareText).map((key) => [key, sortValue(value[key])])); - } - return value; -} - -async function main(argv) { - const args = parseArgs(argv); - const envProducts = selectedProductsFromEnv(); - const products = envProducts.length > 0 - ? envProducts - : args.all - ? extensionProducts() - : args.products; - if (products.length === 0) { - fail("pass --all or at least one exact-extension product id"); - } - const outputRoot = resolveRepoPath(args.outputRoot, { label: "output root" }); - for (const product of products) { - await stageProduct(product, { - outputRoot, - family: args.family, - requireNative: args.requireNative, - requireWasix: args.requireWasix, - requireNativeTargets: args.requireNativeTargets, - }); - } -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/build-sdk-ci-artifacts.mjs b/tools/release/build-sdk-ci-artifacts.mjs deleted file mode 100755 index db5578449..000000000 --- a/tools/release/build-sdk-ci-artifacts.mjs +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "node:child_process"; -import { - mkdirSync, - readdirSync, - rmSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const PREFIX = "build-sdk-ci-artifacts.mjs"; -const SDK_PRODUCT_MODULES = new Map([ - ["oliphaunt-rust", "./sdk-artifacts/rust.mjs"], - ["oliphaunt-swift", "./sdk-artifacts/swift.mjs"], - ["oliphaunt-kotlin", "./sdk-artifacts/kotlin.mjs"], - ["oliphaunt-js", "./sdk-artifacts/js.mjs"], - ["oliphaunt-react-native", "./sdk-artifacts/react-native.mjs"], - ["oliphaunt-wasix-rust", "./sdk-artifacts/wasix-rust.mjs"], - ["oliphaunt-wasix-ts", "./sdk-artifacts/wasix-ts.mjs"], -]); - -function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(1); -} - -function rel(file) { - const relative = path.relative(ROOT, String(file)); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - return String(file).split(path.sep).join("/"); - } - return relative.split(path.sep).join("/"); -} - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function writeArtifactIndex(artifactRoot) { - const entries = readdirSync(artifactRoot, { withFileTypes: true }) - .filter((entry) => entry.isFile() || entry.isDirectory()) - .map((entry) => path.join(artifactRoot, entry.name)) - .sort(compareText); - if (entries.length === 0) { - fail("no SDK artifacts were staged"); - } - const index = path.join(artifactRoot, "artifacts.txt"); - const lines = [...entries, index].sort(compareText).map((entry) => rel(entry)); - writeFileSync(index, `${lines.join("\n")}\n`); -} - -function checkStagedArtifacts(product) { - const result = spawnSync(process.execPath, [ - "tools/release/check-staged-artifacts.mjs", - "--require-sdk-product", - product, - ], { - cwd: ROOT, - stdio: "inherit", - }); - if (result.error) { - fail(`check staged SDK artifacts failed: ${result.error.message}`); - } - if (result.status !== 0) { - fail("check staged SDK artifacts failed"); - } -} - -async function main() { - const product = Bun.argv[2] ?? ""; - const products = [...SDK_PRODUCT_MODULES.keys()]; - if (product === "--help" || product === "-h") { - console.log(`usage: tools/release/build-sdk-ci-artifacts.mjs <${products.join("|")}>`); - process.exit(0); - } - if (!product) { - fail(`usage: tools/release/build-sdk-ci-artifacts.mjs <${products.join("|")}>`); - } - const moduleSpecifier = SDK_PRODUCT_MODULES.get(product); - if (!moduleSpecifier) { - fail(`unsupported SDK product: ${product}`); - } - - const artifactRoot = path.join(ROOT, "target/sdk-artifacts", product); - const workRoot = path.join(ROOT, "target/sdk-artifacts-work", product); - rmSync(artifactRoot, { recursive: true, force: true }); - rmSync(workRoot, { recursive: true, force: true }); - mkdirSync(artifactRoot, { recursive: true }); - mkdirSync(workRoot, { recursive: true }); - - const productModule = await import(moduleSpecifier); - if (typeof productModule.stageArtifacts !== "function") { - fail(`SDK artifact module for ${product} does not export stageArtifacts`); - } - await productModule.stageArtifacts(artifactRoot, workRoot); - - writeArtifactIndex(artifactRoot); - checkStagedArtifacts(product); - console.log(`Staged ${product} SDK artifacts under ${rel(artifactRoot)}`); -} - -if (import.meta.main) { - await main(); -} diff --git a/tools/release/build-sdk-ci-artifacts.test.mjs b/tools/release/build-sdk-ci-artifacts.test.mjs deleted file mode 100644 index d26c373d8..000000000 --- a/tools/release/build-sdk-ci-artifacts.test.mjs +++ /dev/null @@ -1,38 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; - -import { parsePnpmPackOutput } from "./sdk-artifacts/npm.mjs"; - -test("parses object and single-entry array pnpm pack envelopes", () => { - const object = parsePnpmPackOutput('{"filename":"oliphaunt.tgz","name":"@oliphaunt/sdk"}'); - assert.equal(object.manifest.filename, "oliphaunt.tgz"); - assert.equal(Array.isArray(object.envelope), false); - - const array = parsePnpmPackOutput('[{"filename":"oliphaunt.tgz"}]'); - assert.equal(array.manifest.filename, "oliphaunt.tgz"); - assert.equal(Array.isArray(array.envelope), true); -}); - -test("accepts lifecycle output before the final pnpm JSON envelope", () => { - const parsed = parsePnpmPackOutput( - 'verify-ios-package.mjs: verified selection-neutral package contract\n[\n {"filename":"oliphaunt-react-native.tgz"}\n]\n', - ); - assert.equal(parsed.manifest.filename, "oliphaunt-react-native.tgz"); -}); - -test("rejects missing, malformed, and non-package JSON output", () => { - assert.throws(() => parsePnpmPackOutput(""), /produced no output/u); - assert.throws(() => parsePnpmPackOutput("prepack complete\n{not json}"), /found 0/u); - assert.throws(() => parsePnpmPackOutput('{"name":"missing-filename"}'), /found 0/u); - assert.throws( - () => parsePnpmPackOutput('[{"filename":"one.tgz"},{"filename":"two.tgz"}]'), - /found 0/u, - ); -}); - -test("rejects multiple package envelopes instead of selecting the last filename", () => { - assert.throws( - () => parsePnpmPackOutput('{"filename":"stale.tgz"}\n{"filename":"selected.tgz"}'), - /more than one JSON package envelope/u, - ); -}); diff --git a/tools/release/build_maven_artifact_manifest.mjs b/tools/release/build_maven_artifact_manifest.mjs deleted file mode 100644 index 9ccad88c1..000000000 --- a/tools/release/build_maven_artifact_manifest.mjs +++ /dev/null @@ -1,408 +0,0 @@ -#!/usr/bin/env bun -import fs from "node:fs/promises"; -import path from "node:path"; - -import { currentVersion } from "./product-version.mjs"; -import { - allArtifactTargets, - exactExtensionProducts as logicalExactExtensionProducts, - extensionArtifactProductRoot, - extensionArtifactTargets as releaseExtensionArtifactTargets, - extensionMetadata, - extensionReleaseProduct, - extensionReleaseVersion, - extensionSqlNames, - registryPackageRows, -} from "./release-artifact-targets.mjs"; -import { - assertReleaseNoticesInEntries, - releaseProfileMavenLicenses, - releaseProfilePackageLicense, -} from "./release-notices.mjs"; -import { - assertExtensionUpstreamLicensesInEntries, - extensionMavenLicenses, - extensionRegistryLicense, -} from "./extension-upstream-licenses.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const PREFIX = "build_maven_artifact_manifest.mjs"; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(1); -} - -function rel(file) { - return path.relative(ROOT, file).split(path.sep).join("/"); -} - -function canonicalMavenPayloadPrefix(file, entries) { - if (entries.has("LICENSE")) return ""; - - const roots = new Set([...entries.keys()].map((member) => member.split("/", 1)[0])); - const expected = path.basename(file).slice(0, -".tar.gz".length); - if (roots.size !== 1 || !roots.has(expected)) { - throw new Error( - `${path.basename(file)} must stage release notices at the archive root or beneath its ` - + `canonical single archive root ${expected}`, - ); - } - return expected; -} - -function assertMavenPayloadLegal(file, profile, sqlNames = []) { - try { - const entries = readPortableArchiveEntries(file); - const prefix = canonicalMavenPayloadPrefix(file, entries); - assertReleaseNoticesInEntries(entries, { profile, prefix, label: path.basename(file) }); - if (sqlNames.length > 0) { - // Native singleton payloads install upstream notices with runtime files - // below files/, while aggregate bundles stage their combined legal tree - // directly below the canonical archive root. - const upstreamPrefix = prefix === "" ? "files" : prefix; - assertExtensionUpstreamLicensesInEntries(sqlNames, entries, { prefix: upstreamPrefix }); - } - } catch (error) { - fail(`${rel(file)} failed Maven payload legal closure: ${error instanceof Error ? error.message : String(error)}`); - } - return file; -} - -function repoPath(value) { - return path.isAbsolute(value) ? value : path.join(ROOT, value); -} - -function nativeRuntimeArtifactTargets(version) { - return allArtifactTargets({ - product: "liboliphaunt-native", - }, PREFIX) - .filter((target) => target.surfaces.includes("maven")) - .map((target) => ({ - ...target, - asset: target.asset.replaceAll("{version}", version), - })) - .sort((left, right) => compareText(left.id, right.id)); -} - -function runtimeMavenArtifactId(target) { - if (target.kind === "runtime-resources") { - if (target.target !== "android-datum64") { - fail(`unsupported Maven runtime-resource target ${target.target}`); - } - return "liboliphaunt-runtime-resources-android-datum64"; - } - if (target.kind === "icu-data") { - return "oliphaunt-icu"; - } - if (target.kind === "native-runtime" && target.target.startsWith("android-")) { - return `liboliphaunt-${target.target}`; - } - return undefined; -} - -function runtimeMavenArtifactMetadata(target) { - if (target.kind === "runtime-resources") { - return { - name: "Oliphaunt runtime resources", - description: "Package-managed Oliphaunt PostgreSQL runtime resources for the Android datum64 physical domain.", - licenseProfile: "native-runtime-resources", - }; - } - if (target.kind === "icu-data") { - return { - name: "Oliphaunt ICU data", - description: "Package-managed optional ICU data files for Oliphaunt app builds.", - licenseProfile: "native-icu-data", - }; - } - if (target.kind === "native-runtime" && target.target.startsWith("android-")) { - const abi = target.target.slice("android-".length); - return { - name: `Oliphaunt Android runtime ${abi}`, - description: `Package-managed liboliphaunt Android runtime for ${abi} app builds.`, - licenseProfile: "native-runtime", - }; - } - fail(`unsupported liboliphaunt-native Maven artifact target ${target.id}`); -} - -function runtimeMavenArtifacts(version) { - const artifacts = new Map(); - for (const target of nativeRuntimeArtifactTargets(version)) { - const artifactId = runtimeMavenArtifactId(target); - if (artifactId === undefined) { - continue; - } - if (artifacts.has(artifactId)) { - fail(`duplicate liboliphaunt-native Maven artifact mapping for ${artifactId}`); - } - artifacts.set(artifactId, { - filename: target.asset, - ...runtimeMavenArtifactMetadata(target), - }); - } - if (artifacts.size === 0) { - fail("liboliphaunt-native artifact targets did not produce any Maven runtime artifacts"); - } - return artifacts; -} - -function splitMavenCoordinate(coordinate) { - const separator = coordinate.indexOf(":"); - if (separator <= 0 || separator === coordinate.length - 1) { - fail(`invalid Maven coordinate ${JSON.stringify(coordinate)}; expected group:artifact`); - } - return [coordinate.slice(0, separator), coordinate.slice(separator + 1)]; -} - -async function requireFile(file, label) { - try { - const stat = await fs.stat(file); - if (stat.isFile()) { - return file; - } - } catch { - // Fall through to the shared diagnostic below. - } - fail(`missing ${label}: ${rel(file)}`); -} - -function tsvRow({ - groupId, - artifactId, - version, - file, - name, - description, - runtimeProduct = "", - runtimeVersion = "", - licenseSpdx, - licenses, -}) { - if (typeof licenseSpdx !== "string" || !licenseSpdx) fail(`Maven artifact ${groupId}:${artifactId} has no package SPDX expression`); - if (!Array.isArray(licenses) || licenses.length === 0) fail(`Maven artifact ${groupId}:${artifactId} has no structured license entries`); - const values = [ - groupId, - artifactId, - version, - rel(file), - name, - description, - runtimeProduct, - runtimeVersion, - licenseSpdx, - JSON.stringify(licenses), - ]; - if (values.some((value) => value.includes("\t") || value.includes("\n"))) { - fail(`Maven artifact manifest value contains a tab or newline: ${JSON.stringify(values)}`); - } - return values.join("\t"); -} - -async function runtimeRows(assetRoot) { - const version = await currentVersion("liboliphaunt-native"); - const artifacts = runtimeMavenArtifacts(version); - const rows = []; - for (const coordinate of registryPackageRows({ - product: "liboliphaunt-native", - packageKind: "maven", - }, PREFIX).map((row) => row.packageName).filter((name) => name.startsWith("dev.oliphaunt.runtime:"))) { - const [groupId, artifactId] = splitMavenCoordinate(coordinate); - if (groupId !== "dev.oliphaunt.runtime") { - fail(`liboliphaunt-native Maven artifact ${coordinate} must use dev.oliphaunt.runtime`); - } - const artifact = artifacts.get(artifactId); - if (artifact === undefined) { - fail(`liboliphaunt-native Maven artifact ${coordinate} has no release asset mapping`); - } - const file = await requireFile(path.join(assetRoot, artifact.filename), artifactId); - assertMavenPayloadLegal(file, artifact.licenseProfile); - rows.push( - tsvRow({ - groupId, - artifactId, - version, - file, - name: artifact.name, - description: artifact.description, - licenseSpdx: releaseProfilePackageLicense(artifact.licenseProfile).spdx, - licenses: releaseProfileMavenLicenses(artifact.licenseProfile, { - product: "liboliphaunt-native", - version, - }), - }), - ); - } - return rows; -} - -async function extensionRows(extensionRoot, selectedProducts) { - const products = selectedProducts.length > 0 - ? selectedProducts - : logicalExactExtensionProducts(PREFIX); - const rows = []; - for (const product of [...products].sort()) { - const sqlNames = extensionSqlNames(product, PREFIX); - const version = extensionReleaseVersion(product, "native", PREFIX); - const registryLicense = extensionRegistryLicense(product, sqlNames); - const compatibility = extensionMetadata(product, PREFIX).compatibility; - const releaseProduct = extensionReleaseProduct(product, "native", PREFIX); - const runtimeProduct = compatibility.nativeRuntimeProduct; - const runtimeVersion = compatibility.nativeRuntimeVersion; - if (typeof runtimeProduct !== "string" || !runtimeProduct || typeof runtimeVersion !== "string" || !runtimeVersion) { - fail(`${product} must declare exact native runtime compatibility for Maven carriers`); - } - const currentRuntimeVersion = await currentVersion(runtimeProduct); - if (runtimeVersion !== currentRuntimeVersion) { - fail(`${product} native runtime compatibility ${runtimeVersion} does not match ${runtimeProduct}@${currentRuntimeVersion}`); - } - const productRoot = path.join( - extensionArtifactProductRoot(product, "native", extensionRoot, PREFIX), - "release-assets", - ); - const targets = [...new Map(releaseExtensionArtifactTargets({ - product, - family: "native", - }, PREFIX).filter((target) => - target.kind === "native-static-registry" && target.target.startsWith("android-")) - .map((target) => [target.target, target])).values()]; - if (targets.length === 0) { - fail(`${product} has no published Android Maven extension targets`); - } - const declaredCoordinates = new Set( - registryPackageRows({ product: releaseProduct, packageKind: "maven" }, PREFIX) - .map((row) => row.packageName) - .filter((name) => name.startsWith(`dev.oliphaunt.extensions:${product}-`)), - ); - for (const target of targets) { - const coordinate = `dev.oliphaunt.extensions:${product}-${target.target}`; - if (!declaredCoordinates.delete(coordinate)) { - fail(`${product} release metadata is missing Maven carrier ${coordinate}`); - } - const filename = sqlNames.length > 1 - ? `${product}-${version}-native-${target.target}-bundle.tar.gz` - : `${product}-${version}-native-${target.target}-runtime.tar.gz`; - const memberLabel = sqlNames.length === 1 - ? `the ${sqlNames[0]} PostgreSQL extension` - : `the PostgreSQL 18 contrib bundle (${sqlNames.length} exact extension members)`; - const file = await requireFile( - path.join(productRoot, filename), - `${product} ${target.target} Maven artifact`, - ); - const licenseProfile = product === "oliphaunt-extension-contrib-pg18" - ? "contrib-native-openssl" - : "external-native"; - assertMavenPayloadLegal( - file, - licenseProfile, - product === "oliphaunt-extension-contrib-pg18" ? [] : sqlNames, - ); - rows.push( - tsvRow({ - groupId: "dev.oliphaunt.extensions", - artifactId: `${product}-${target.target}`, - version, - file, - name: `Oliphaunt ${sqlNames.length === 1 ? `extension ${sqlNames[0]}` : "PostgreSQL 18 contrib extensions"} ${target.target}`, - description: `Package-managed Oliphaunt Android runtime and static-link artifacts for ${memberLabel} on ${target.target}.`, - runtimeProduct, - runtimeVersion, - licenseSpdx: product === "oliphaunt-extension-contrib-pg18" - ? releaseProfilePackageLicense(licenseProfile).spdx - : registryLicense.packageSpdx, - licenses: product === "oliphaunt-extension-contrib-pg18" - ? releaseProfileMavenLicenses("contrib-native-openssl", { product, version }) - : extensionMavenLicenses(product, sqlNames, { version }), - }), - ); - } - if (declaredCoordinates.size > 0) { - fail(`${product} declares unexpected Maven carrier(s): ${[...declaredCoordinates].sort().join(", ")}`); - } - } - return rows; -} - -function valueArg(argv, index, name) { - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) { - fail(`${name} requires a value`); - } - return value; -} - -function parseArgs(argv) { - const args = { - output: undefined, - runtimeAssetRoot: "target/liboliphaunt/release-assets", - extensionArtifactRoot: "target/extension-artifacts", - runtime: false, - extensions: false, - extensionProducts: [], - }; - for (let index = 0; index < argv.length; ) { - const arg = argv[index]; - if (arg === "--output") { - args.output = valueArg(argv, index, arg); - index += 2; - } else if (arg === "--runtime-asset-root") { - args.runtimeAssetRoot = valueArg(argv, index, arg); - index += 2; - } else if (arg === "--extension-artifact-root") { - args.extensionArtifactRoot = valueArg(argv, index, arg); - index += 2; - } else if (arg === "--runtime") { - args.runtime = true; - index += 1; - } else if (arg === "--extensions") { - args.extensions = true; - index += 1; - } else if (arg === "--extension-product") { - args.extensionProducts.push(valueArg(argv, index, arg)); - index += 2; - } else { - fail(`unknown argument: ${arg}`); - } - } - if (!args.output) { - fail("--output is required"); - } - return args; -} - -export async function buildMavenArtifactManifest(outputValue, { - runtimeAssetRoot = "target/liboliphaunt/release-assets", - extensionArtifactRoot = "target/extension-artifacts", - runtime = false, - extensions = false, - extensionProducts = [], -} = {}) { - const includeRuntime = runtime || !extensions; - const includeExtensions = extensions || extensionProducts.length > 0; - const rows = []; - if (includeRuntime) { - rows.push(...(await runtimeRows(repoPath(runtimeAssetRoot)))); - } - if (includeExtensions) { - rows.push(...(await extensionRows(repoPath(extensionArtifactRoot), extensionProducts))); - } - if (rows.length === 0) { - fail("manifest would be empty"); - } - const output = repoPath(outputValue); - await fs.mkdir(path.dirname(output), { recursive: true }); - await fs.writeFile(output, `${rows.join("\n")}\n`, "utf8"); - console.log(`Wrote ${rows.length} Maven artifact publication row(s) to ${rel(output)}`); - return output; -} - -if (import.meta.main) { - const args = parseArgs(Bun.argv.slice(2)); - await buildMavenArtifactManifest(args.output, args); -} diff --git a/tools/release/capture-command-output.test.mjs b/tools/release/capture-command-output.test.mjs deleted file mode 100644 index fc4b8706c..000000000 --- a/tools/release/capture-command-output.test.mjs +++ /dev/null @@ -1,378 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { - chmodSync, - closeSync, - mkdtempSync, - openSync, - readFileSync, - rmSync, - writeFileSync, - writeSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { captureCommandBytes, captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { - execFileSync as fdBackedExecFileSync, - execSync as fdBackedExecSync, - spawnSync as fdBackedSpawnSync, -} from "../test/fd-backed-spawn-sync.mjs"; - -function fixtureScript(body) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-command-capture-test-")); - const script = path.join(root, "child.mjs"); - writeFileSync(script, body); - chmodSync(script, 0o755); - return { root, script }; -} - -test("file-backed capture retains stdout written at a successful child's final event-loop turn", () => { - const { root, script } = fixtureScript([ - "process.stdout.write('first\\0');", - "setImmediate(() => process.stdout.write('second\\0'));", - "", - ].join("\n")); - try { - const result = captureCommandOutput(process.execPath, [script], { - label: "delayed successful child", - stdoutTerminator: "\0", - }); - assert.equal(result.status, 0); - assert.equal(result.stdout, "first\0second\0"); - assert.equal(result.stderr, ""); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); -test("NUL inventory capture fails closed on a successful partial record", () => { - const { root, script } = fixtureScript("process.stdout.write('partial');\n"); - try { - assert.throws( - () => captureCommandOutput(process.execPath, [script], { - label: "partial inventory child", - stdoutTerminator: "\0", - }), - /missing its required terminal/u, - ); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("required record terminators reject a successful empty inventory", () => { - const { root, script } = fixtureScript(""); - try { - assert.throws( - () => captureCommandOutput(process.execPath, [script], { - label: "empty inventory child", - stdoutTerminator: "\0", - }), - /missing its required terminal/u, - ); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("optional record inventories accept empty stdout but still reject partial records", () => { - const empty = fixtureScript(""); - const partial = fixtureScript("process.stdout.write('partial');\n"); - try { - const result = captureCommandOutput(process.execPath, [empty.script], { - allowEmptyOutput: true, - label: "optional empty inventory child", - stdoutTerminator: "\0", - }); - assert.equal(result.status, 0); - assert.equal(result.stdout, ""); - assert.throws( - () => captureCommandOutput(process.execPath, [partial.script], { - allowEmptyOutput: true, - label: "optional partial inventory child", - stdoutTerminator: "\0", - }), - /missing its required terminal/u, - ); - } finally { - rmSync(empty.root, { force: true, recursive: true }); - rmSync(partial.root, { force: true, recursive: true }); - } -}); - -test("record capture rejects an explicitly empty terminator before spawning", () => { - assert.throws( - () => captureCommandOutput("command-that-must-not-run", [], { stdoutTerminator: "" }), - /non-empty stdout terminator/u, - ); -}); - -test("allowEmptyOutput is valid only for a terminated record protocol", () => { - assert.throws( - () => captureCommandOutput("command-that-must-not-run", [], { allowEmptyOutput: true }), - /allowEmptyOutput requires a stdout terminator/u, - ); -}); - -test("file-backed capture retains complete failure diagnostics", () => { - const { root, script } = fixtureScript([ - "process.stderr.write('first failure line\\n');", - "setImmediate(() => { process.stderr.write('last failure line\\n'); process.exitCode = 23; });", - "", - ].join("\n")); - try { - const result = captureCommandOutput(process.execPath, [script], { label: "failed child" }); - assert.equal(result.status, 23); - assert.equal(result.stderr, "first failure line\nlast failure line\n"); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("failed commands return diagnostics instead of enforcing success framing", () => { - const { root, script } = fixtureScript([ - "process.stderr.write('complete failure diagnostic\\n');", - "process.exitCode = 29;", - "", - ].join("\n")); - try { - const result = captureCommandOutput(process.execPath, [script], { - label: "failed framed child", - stdoutTerminator: "\0", - }); - assert.equal(result.status, 29); - assert.equal(result.stdout, ""); - assert.equal(result.stderr, "complete failure diagnostic\n"); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("start failures return their spawn error instead of enforcing success framing", () => { - const result = captureCommandOutput("oliphaunt-command-that-does-not-exist", [], { - label: "missing framed child", - stdoutTerminator: "\0", - }); - assert.notEqual(result.error, undefined); - assert.ok(result.status == null); - assert.equal(result.stdout, ""); -}); - -test("external stdout redirection preserves large bytes and leaves its descriptor open", () => { - const bytes = 2 * 1024 * 1024 + 17; - const { root, script } = fixtureScript([ - `const remaining = ${bytes};`, - "process.stdout.write(Buffer.alloc(remaining, 0xa5));", - "", - ].join("\n")); - const destination = path.join(root, "redirected.bin"); - const descriptor = openSync(destination, "wx", 0o600); - try { - const result = captureCommandBytes(process.execPath, [script], { - label: "large redirected child", - maxOutputBytes: 1024, - stdoutDescriptor: descriptor, - }); - assert.equal(result.status, 0); - assert.deepEqual(result.stdout, Buffer.alloc(0)); - assert.deepEqual(result.stderr, Buffer.alloc(0)); - assert.equal(writeSync(descriptor, Buffer.from([0x5a]), 0, 1, bytes), 1); - } finally { - closeSync(descriptor); - } - try { - const actual = readFileSync(destination); - assert.equal(actual.length, bytes + 1); - assert.equal(actual.subarray(0, bytes).every((byte) => byte === 0xa5), true); - assert.equal(actual[bytes], 0x5a); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("external stdout redirection retains complete failure diagnostics", () => { - const { root, script } = fixtureScript([ - "process.stdout.write('partial payload');", - "process.stderr.write('first failure line\\n');", - "setImmediate(() => { process.stderr.write('last failure line\\n'); process.exitCode = 31; });", - "", - ].join("\n")); - const destination = path.join(root, "redirected.bin"); - const descriptor = openSync(destination, "wx", 0o600); - try { - const result = captureCommandOutput(process.execPath, [script], { - label: "failed redirected child", - stdoutDescriptor: descriptor, - }); - assert.equal(result.status, 31); - assert.equal(result.stdout, ""); - assert.equal(result.stderr, "first failure line\nlast failure line\n"); - } finally { - closeSync(descriptor); - } - try { - assert.equal(readFileSync(destination, "utf8"), "partial payload"); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("external stdout redirection rejects record framing", () => { - const { root, script } = fixtureScript(""); - const destination = path.join(root, "redirected.bin"); - const descriptor = openSync(destination, "wx", 0o600); - try { - assert.throws( - () => captureCommandOutput(process.execPath, [script], { - stdoutDescriptor: descriptor, - stdoutTerminator: "\0", - }), - /cannot frame externally redirected stdout/u, - ); - assert.equal(writeSync(descriptor, Buffer.from([0x5a])), 1); - } finally { - closeSync(descriptor); - rmSync(root, { force: true, recursive: true }); - } -}); - -test("external stdout redirection rejects non-regular descriptors", { - skip: process.platform === "win32", -}, () => { - const descriptor = openSync("/dev/null", "w"); - try { - assert.throws( - () => captureCommandBytes(process.execPath, ["--version"], { stdoutDescriptor: descriptor }), - /must identify a regular file/u, - ); - assert.equal(writeSync(descriptor, Buffer.from([0x5a])), 1); - } finally { - closeSync(descriptor); - } -}); -test("binary capture preserves exact non-UTF-8 bytes without a pipe", () => { - const { root, script } = fixtureScript( - "process.stdout.write(Buffer.from([0x00, 0xff, 0x7f, 0x0a]));\n", - ); - try { - const result = captureCommandBytes(process.execPath, [script], { - label: "binary child", - stdoutTerminator: Buffer.from([0x0a]), - }); - assert.equal(result.status, 0); - assert.deepEqual(result.stdout, Buffer.from([0x00, 0xff, 0x7f, 0x0a])); - assert.deepEqual(result.stderr, Buffer.alloc(0)); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("file-backed stdin preserves exact binary bytes", () => { - const { root, script } = fixtureScript([ - "const chunks = [];", - "for await (const chunk of process.stdin) chunks.push(chunk);", - "process.stdout.write(Buffer.concat(chunks));", - "", - ].join("\n")); - try { - const input = Buffer.from([0x00, 0xff, 0x7f, 0x0a, 0x00]); - const result = captureCommandBytes(process.execPath, [script], { - input, - label: "binary stdin child", - }); - assert.equal(result.status, 0); - assert.deepEqual(result.stdout, input); - assert.deepEqual(result.stderr, Buffer.alloc(0)); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("file-backed stdin accepts an explicitly empty input", () => { - const { root, script } = fixtureScript([ - "let length = 0;", - "for await (const chunk of process.stdin) length += chunk.length;", - "process.stdout.write(`${length}\\n`);", - "", - ].join("\n")); - try { - const result = captureCommandOutput(process.execPath, [script], { - input: Buffer.alloc(0), - label: "empty stdin child", - stdoutTerminator: "\n", - }); - assert.equal(result.status, 0); - assert.equal(result.stdout, "0\n"); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("test spawn facade preserves the synchronous child result shape without pipes", () => { - const { root, script } = fixtureScript([ - "const chunks = [];", - "for await (const chunk of process.stdin) chunks.push(chunk);", - "process.stdout.write(Buffer.concat(chunks));", - "process.stderr.write('diagnostic\\n');", - "", - ].join("\n")); - try { - const result = fdBackedSpawnSync(process.execPath, [script], { - encoding: "utf8", - input: "complete-output\n", - maxBuffer: 1024, - stdio: ["pipe", "pipe", "pipe"], - windowsVerbatimArguments: false, - }); - assert.equal(result.status, 0); - assert.equal(result.signal, null); - assert.equal(result.error, undefined); - assert.equal(result.stdout, "complete-output\n"); - assert.equal(result.stderr, "diagnostic\n"); - assert.deepEqual(result.output, [null, result.stdout, result.stderr]); - assert.ok(Number.isSafeInteger(result.pid) && result.pid > 0); - - const binary = fdBackedSpawnSync(process.execPath, [script], { - input: Buffer.from([0x00, 0xff, 0x0a]), - }); - assert.equal(binary.status, 0); - assert.deepEqual(binary.stdout, Buffer.from([0x00, 0xff, 0x0a])); - assert.deepEqual(binary.stderr, Buffer.from("diagnostic\n")); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("test spawn facade delegates explicitly closed output and emulates execSync APIs", () => { - const ignored = fdBackedSpawnSync(process.execPath, ["-e", "process.exit(0)"], { - stdio: "ignore", - }); - assert.equal(ignored.status, 0); - assert.equal(ignored.stdout, null); - assert.equal(ignored.stderr, null); - - const output = fdBackedExecFileSync( - process.execPath, - ["-e", "process.stdout.write('facade-output')"], - { encoding: "utf8" }, - ); - assert.equal(output, "facade-output"); - assert.equal( - fdBackedExecSync("echo shell-output", { encoding: "utf8" }).trim(), - "shell-output", - ); - assert.throws( - () => fdBackedExecFileSync( - process.execPath, - ["-e", "process.stdout.write('partial'); process.stderr.write('failed'); process.exit(17)"], - { encoding: "utf8" }, - ), - (error) => error.status === 17 - && error.stdout === "partial" - && error.stderr === "failed" - && error.output[1] === "partial", - ); -}); diff --git a/tools/release/cargo-crate-filename.mjs b/tools/release/cargo-crate-filename.mjs deleted file mode 100644 index e5cd0b5ec..000000000 --- a/tools/release/cargo-crate-filename.mjs +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bun - -function fail(message) { - console.error(`cargo-crate-filename.mjs: ${message}`); - process.exit(2); -} - -const manifest = Bun.argv[2]; -if (manifest === undefined || manifest.length === 0) { - fail('usage: tools/release/cargo-crate-filename.mjs '); -} - -let parsed; -try { - parsed = Bun.TOML.parse(await Bun.file(manifest).text()); -} catch (error) { - fail(`could not parse ${manifest}: ${error.message}`); -} - -const packageConfig = parsed.package; -if (packageConfig === null || typeof packageConfig !== 'object' || Array.isArray(packageConfig)) { - fail(`${manifest} must declare a [package] table`); -} - -const { name, version } = packageConfig; -if (typeof name !== 'string' || name.length === 0) { - fail(`${manifest} must declare package.name`); -} -if (typeof version !== 'string' || version.length === 0) { - fail(`${manifest} must declare package.version`); -} - -console.log(`${name}-${version}.crate`); diff --git a/tools/release/cargo-crate-filename.mts b/tools/release/cargo-crate-filename.mts new file mode 100644 index 000000000..512946e6d --- /dev/null +++ b/tools/release/cargo-crate-filename.mts @@ -0,0 +1,33 @@ +#!/usr/bin/env bun + +function fail(message) { + console.error(`cargo-crate-filename.mts: ${message}`); + process.exit(2); +} + +const manifest = Bun.argv[2]; +if (manifest === undefined || manifest.length === 0) { + fail('usage: tools/release/cargo-crate-filename.mts '); +} + +let parsed; +try { + parsed = Bun.TOML.parse(await Bun.file(manifest).text()); +} catch (error) { + fail(`could not parse ${manifest}: ${error.message}`); +} + +const packageConfig = parsed.package; +if (packageConfig === null || typeof packageConfig !== 'object' || Array.isArray(packageConfig)) { + fail(`${manifest} must declare a [package] table`); +} + +const { name, version } = packageConfig; +if (typeof name !== 'string' || name.length === 0) { + fail(`${manifest} must declare package.name`); +} +if (typeof version !== 'string' || version.length === 0) { + fail(`${manifest} must declare package.version`); +} + +console.log(`${name}-${version}.crate`); diff --git a/tools/release/cargo-source-package.mjs b/tools/release/cargo-source-package.mjs deleted file mode 100644 index 34cd7d1cd..000000000 --- a/tools/release/cargo-source-package.mjs +++ /dev/null @@ -1,451 +0,0 @@ -import { - chmodSync, - copyFileSync, - lstatSync, - mkdirSync, - readFileSync, - readdirSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { - canonicalGzipSync, - readPortableArchiveEntries, -} from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -export const CARGO_PACKAGE_SIZE_LIMIT_BYTES = 10 * 1024 * 1024; - -export function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function abort(fail, message) { - if (typeof fail === "function") { - fail(message); - } - throw new Error(message); -} - -export function parseCargoPackageNameVersion(text, context, { fail = null } = {}) { - let inPackage = false; - let name = null; - let version = null; - for (const rawLine of text.split(/\r?\n/u)) { - const line = rawLine.trim(); - if (line === "[package]") { - inPackage = true; - continue; - } - if (inPackage && line.startsWith("[")) { - break; - } - if (!inPackage) { - continue; - } - name ??= line.match(/^name\s*=\s*"([^"]+)"/u)?.[1] ?? null; - version ??= line.match(/^version\s*=\s*"([^"]+)"/u)?.[1] ?? null; - } - if (!name || !version) { - abort(fail, `${context} must declare package.name and package.version`); - } - return { name, version }; -} - -export function readCargoPackageNameVersion(manifest, { fail = null, rel = String } = {}) { - return parseCargoPackageNameVersion(readFileSync(manifest, "utf8"), rel(manifest), { fail }); -} - -export function packagedCargoManifestText(source) { - let text = source - .replaceAll("repository.workspace = true", 'repository = "https://github.com/f0rr0/oliphaunt"') - .replaceAll("homepage.workspace = true", 'homepage = "https://oliphaunt.dev"'); - text = text.replace(/, path = "[^"]+"/gu, ""); - if (!text.includes("\n[workspace]")) { - text = `${text.trimEnd()}\n\n[workspace]\n`; - } - return text; -} - -function cargoMetadataPackageFromManifest(manifest, { root, fail, rel }) { - const args = [ - "metadata", - "--manifest-path", - manifest, - "--format-version", - "1", - "--no-deps", - ]; - const result = captureCommandOutput("cargo", args, { - cwd: root, - label: `cargo metadata --manifest-path ${rel(manifest)}`, - }); - if (result.error !== undefined) { - abort(fail, `cargo failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - abort(fail, `cargo metadata failed for ${rel(manifest)}: ${result.stderr.trim()}`); - } - let data; - try { - data = JSON.parse(result.stdout); - } catch (error) { - abort(fail, `cargo metadata for ${rel(manifest)} did not return valid JSON: ${error.message}`); - } - const packages = data.packages; - if (!Array.isArray(packages) || packages.length !== 1 || typeof packages[0] !== "object") { - abort(fail, `cargo metadata for ${rel(manifest)} did not return exactly one package`); - } - return packages[0]; -} - -const CARGO_VIRTUAL_PACKAGE_FILES = new Set([ - ".cargo_vcs_info.json", - "Cargo.lock", - "Cargo.toml.orig", -]); - -export function cargoPackageRelativePathParts(value) { - if ( - !value - || value.includes("\\") - || value.includes("\0") - || value.startsWith("/") - || /^[A-Za-z]:/u.test(value) - ) { - throw new Error(`unsafe Cargo package path ${JSON.stringify(value)}`); - } - const parts = value.split("/"); - if ( - parts.some((part) => - !part - || part === "." - || part === ".." - || /[<>:"|?*]/u.test(part) - || /[ .]$/u.test(part) - ) - ) { - throw new Error(`non-portable Cargo package path ${JSON.stringify(value)}`); - } - return parts; -} - -function portablePackagePath(value, manifest, { fail, rel }) { - try { - return cargoPackageRelativePathParts(value); - } catch (cause) { - abort(fail, `cargo package --list for ${rel(manifest)} returned ${cause.message}`); - } -} - -function cargoPackageSourceFiles(manifest, { root, fail, rel }) { - const args = [ - "package", - "--manifest-path", - manifest, - "--allow-dirty", - "--list", - ]; - const result = captureCommandOutput("cargo", args, { - cwd: root, - label: `cargo package --list --manifest-path ${rel(manifest)}`, - }); - if (result.error !== undefined) { - abort(fail, `cargo failed to start while listing ${rel(manifest)}: ${result.error.message}`); - } - if (result.status !== 0) { - const detail = [result.stdout, result.stderr].filter(Boolean).join("\n").trim(); - abort(fail, `cargo package --list failed for ${rel(manifest)}${detail ? `: ${detail}` : ""}`); - } - const files = result.stdout.split(/\r?\n/u).filter(Boolean); - if (files.length === 0) { - abort(fail, `cargo package --list returned no files for ${rel(manifest)}`); - } - const seen = new Set(); - for (const file of files) { - portablePackagePath(file, manifest, { fail, rel }); - if (seen.has(file)) { - abort(fail, `cargo package --list repeated ${file} for ${rel(manifest)}`); - } - seen.add(file); - } - if (!seen.has("Cargo.toml")) { - abort(fail, `cargo package --list omitted Cargo.toml for ${rel(manifest)}`); - } - return files; -} - -function sourceFileWithoutSymlinkComponents(sourceDir, parts, manifest, { fail, rel }) { - let source = sourceDir; - for (const part of parts) { - source = path.join(source, part); - let metadata; - try { - metadata = lstatSync(source); - } catch (cause) { - abort(fail, `cargo-listed source ${rel(source)} for ${rel(manifest)} is missing: ${cause.message}`); - } - if (metadata.isSymbolicLink()) { - abort(fail, `cargo-listed source ${rel(source)} for ${rel(manifest)} must not be a symbolic link`); - } - } - const metadata = lstatSync(source); - if (!metadata.isFile()) { - abort(fail, `cargo-listed source ${rel(source)} for ${rel(manifest)} must be a regular file`); - } - return { metadata, source }; -} - -function copyCargoPackageSource(manifest, destination, options) { - const sourceDir = path.dirname(manifest); - const copied = new Set(["Cargo.toml"]); - rmSync(destination, { recursive: true, force: true }); - mkdirSync(destination, { recursive: true }); - for (const relative of cargoPackageSourceFiles(manifest, options)) { - if (relative === "Cargo.toml") { - continue; - } - const parts = portablePackagePath(relative, manifest, options); - try { - lstatSync(path.join(sourceDir, ...parts)); - } catch (cause) { - if (CARGO_VIRTUAL_PACKAGE_FILES.has(relative)) { - continue; - } - abort( - options.fail, - `cargo-listed source ${relative} for ${options.rel(manifest)} is missing: ${cause.message}`, - ); - } - const { source, metadata } = sourceFileWithoutSymlinkComponents( - sourceDir, - parts, - manifest, - options, - ); - const target = path.join(destination, ...parts); - mkdirSync(path.dirname(target), { recursive: true }); - copyFileSync(source, target); - chmodSync(target, metadata.mode & 0o777); - copied.add(relative); - } - const manifestMetadata = lstatSync(manifest); - if (manifestMetadata.isSymbolicLink() || !manifestMetadata.isFile()) { - abort(options.fail, `${options.rel(manifest)} must be a regular, non-symlink Cargo manifest`); - } - const targetManifest = path.join(destination, "Cargo.toml"); - copyFileSync(manifest, targetManifest); - chmodSync(targetManifest, manifestMetadata.mode & 0o777); - return copied; -} - -function requireExactCrateMembers(cratePath, packageRoot, expected, { fail, rel }) { - const prefix = `${packageRoot}/`; - const actual = [...readPortableArchiveEntries(cratePath).keys()].map((member) => { - if (!member.startsWith(prefix) || member.length === prefix.length) { - abort(fail, `${rel(cratePath)} contains member outside ${packageRoot}: ${member}`); - } - return member.slice(prefix.length); - }).sort(compareText); - const wanted = [...expected].sort(compareText); - if (actual.length !== wanted.length || actual.some((member, index) => member !== wanted[index])) { - const actualSet = new Set(actual); - const wantedSet = new Set(wanted); - const missing = wanted.filter((member) => !actualSet.has(member)); - const unexpected = actual.filter((member) => !wantedSet.has(member)); - abort( - fail, - `${rel(cratePath)} member set differs from Cargo's package selection: ` - + `missing=${JSON.stringify(missing)}, unexpected=${JSON.stringify(unexpected)}`, - ); - } -} - -function requirePackagedCargoTargetSources( - packageMetadata, - stageDir, - expectedMembers, - stagedManifest, - options, -) { - if (!Array.isArray(packageMetadata.targets)) { - abort(options.fail, `cargo metadata for ${options.rel(stagedManifest)} omitted package targets`); - } - const absoluteStage = path.resolve(stageDir); - for (const target of packageMetadata.targets) { - if (target === null || typeof target !== "object" || typeof target.src_path !== "string") { - abort( - options.fail, - `cargo metadata for ${options.rel(stagedManifest)} returned an invalid package target`, - ); - } - if (!path.isAbsolute(target.src_path)) { - abort( - options.fail, - `cargo target ${JSON.stringify(target.name)} for ${options.rel(stagedManifest)} has a non-absolute source path`, - ); - } - const relative = path.relative(absoluteStage, path.resolve(target.src_path)); - if (!relative || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { - abort( - options.fail, - `cargo target ${JSON.stringify(target.name)} for ${options.rel(stagedManifest)} is outside the staged package`, - ); - } - const normalized = relative.split(path.sep).join("/"); - const parts = portablePackagePath(normalized, stagedManifest, options); - if (!expectedMembers.has(normalized)) { - abort( - options.fail, - `cargo target ${JSON.stringify(target.name)} source ${normalized} is absent from Cargo's package selection`, - ); - } - sourceFileWithoutSymlinkComponents(stageDir, parts, stagedManifest, options); - } -} - -function listFilesRecursive(directory) { - const files = []; - const entries = readdirSync(directory, { withFileTypes: true }); - entries.sort((left, right) => compareText(left.name, right.name)); - for (const entry of entries) { - const fullPath = path.join(directory, entry.name); - if (entry.isDirectory()) { - files.push(...listFilesRecursive(fullPath)); - } else if (entry.isFile() || entry.isSymbolicLink()) { - files.push(fullPath); - } - } - return files; -} - -function tarPathParts(relativePath, { fail }) { - const normalized = relativePath.split(path.sep).join("/"); - if (Buffer.byteLength(normalized) <= 100) { - return { name: normalized, prefix: "" }; - } - const parts = normalized.split("/"); - for (let index = 1; index < parts.length; index += 1) { - const prefix = parts.slice(0, index).join("/"); - const name = parts.slice(index).join("/"); - if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) { - return { name, prefix }; - } - } - abort(fail, `crate archive path is too long for ustar: ${normalized}`); -} - -function writeString(buffer, offset, length, value, { fail }) { - const bytes = Buffer.from(value); - if (bytes.length > length) { - abort(fail, `tar header field overflow for '${value}'`); - } - bytes.copy(buffer, offset); -} - -function writeOctal(buffer, offset, length, value, options) { - const text = value.toString(8); - if (text.length > length - 1) { - abort(options.fail, `tar header octal field overflow for '${value}'`); - } - writeString(buffer, offset, length, `${text.padStart(length - 1, "0")}\0`, options); -} - -function tarHeader(relativePath, size, mode, options) { - const header = Buffer.alloc(512, 0); - const { name, prefix } = tarPathParts(relativePath, options); - writeString(header, 0, 100, name, options); - writeOctal(header, 100, 8, mode, options); - writeOctal(header, 108, 8, 0, options); - writeOctal(header, 116, 8, 0, options); - writeOctal(header, 124, 12, size, options); - writeOctal(header, 136, 12, 0, options); - header.fill(0x20, 148, 156); - writeString(header, 156, 1, "0", options); - writeString(header, 257, 6, "ustar\0", options); - writeString(header, 263, 2, "00", options); - writeString(header, 345, 155, prefix, options); - let checksum = 0; - for (const byte of header) { - checksum += byte; - } - const checksumText = checksum.toString(8); - if (checksumText.length > 6) { - abort(options.fail, `tar header checksum overflow for ${relativePath}`); - } - writeString(header, 148, 8, `${checksumText.padStart(6, "0")}\0 `, options); - return header; -} - -export function createDeterministicTar(stageDir, packageRoot, options) { - const chunks = []; - const fixedFileMode = options.fixedFileMode; - if ( - fixedFileMode !== undefined - && (!Number.isInteger(fixedFileMode) || fixedFileMode < 0 || fixedFileMode > 0o777) - ) { - abort(options.fail, "fixed deterministic tar file mode must be an integer between 0000 and 0777"); - } - const files = listFilesRecursive(stageDir); - files.sort((left, right) => compareText(path.relative(stageDir, left), path.relative(stageDir, right))); - for (const file of files) { - const relative = path.relative(stageDir, file).split(path.sep).join("/"); - const archivePath = `${packageRoot}/${relative}`; - const stats = statSync(file); - const data = readFileSync(file); - const mode = fixedFileMode ?? (stats.mode & 0o777); - chunks.push(tarHeader(archivePath, data.length, mode, options)); - chunks.push(data); - const remainder = data.length % 512; - if (remainder !== 0) { - chunks.push(Buffer.alloc(512 - remainder, 0)); - } - } - chunks.push(Buffer.alloc(1024, 0)); - return Buffer.concat(chunks); -} - -export function manualCargoPackageSource( - manifest, - outputDir, - { - root, - fail = null, - rel = String, - packageSizeLimitBytes = CARGO_PACKAGE_SIZE_LIMIT_BYTES, - }, -) { - const { name, version } = readCargoPackageNameVersion(manifest, { fail, rel }); - const packageRoot = `${name}-${version}`; - const stageRoot = path.join(outputDir, "manual-package-stage"); - const stageDir = path.join(stageRoot, packageRoot); - const cratePath = path.join(outputDir, `${packageRoot}.crate`); - const expectedMembers = copyCargoPackageSource(manifest, stageDir, { root, fail, rel }); - - const stagedManifest = path.join(stageDir, "Cargo.toml"); - writeFileSync(stagedManifest, packagedCargoManifestText(readFileSync(stagedManifest, "utf8"))); - const packageMetadata = cargoMetadataPackageFromManifest(stagedManifest, { root, fail, rel }); - if (packageMetadata.name !== name || packageMetadata.version !== version) { - abort(fail, `${rel(stagedManifest)} produced unexpected cargo metadata`); - } - requirePackagedCargoTargetSources( - packageMetadata, - stageDir, - expectedMembers, - stagedManifest, - { fail, rel }, - ); - - mkdirSync(outputDir, { recursive: true }); - rmSync(cratePath, { force: true }); - writeFileSync(cratePath, canonicalGzipSync(createDeterministicTar(stageDir, packageRoot, { fail }))); - requireExactCrateMembers(cratePath, packageRoot, expectedMembers, { fail, rel }); - const size = statSync(cratePath).size; - if (size > packageSizeLimitBytes) { - abort(fail, `${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit`); - } - return cratePath; -} diff --git a/tools/release/cargo-source-package.test.mjs b/tools/release/cargo-source-package.test.mjs deleted file mode 100644 index 6bd0e9c46..000000000 --- a/tools/release/cargo-source-package.test.mjs +++ /dev/null @@ -1,169 +0,0 @@ -import assert from "node:assert/strict"; -import { - chmodSync, - mkdtempSync, - mkdirSync, - readFileSync, - rmSync, - statSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; -import { gzipSync } from "node:zlib"; - -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -import { - cargoPackageRelativePathParts, - createDeterministicTar, - manualCargoPackageSource, -} from "./cargo-source-package.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -function fixture(t, name) { - const root = mkdtempSync(path.join(os.tmpdir(), `oliphaunt-${name}-`)); - t.after(() => rmSync(root, { recursive: true, force: true })); - const source = path.join(root, "source"); - mkdirSync(path.join(source, "src"), { recursive: true }); - return { root, source }; -} - -function manifest(name, extra = []) { - return [ - "[package]", - `name = ${JSON.stringify(name)}`, - 'version = "0.1.0"', - 'edition = "2024"', - 'license = "MIT"', - ...extra, - "", - "[lib]", - 'path = "src/lib.rs"', - "", - ].join("\n"); -} - -function packageSource(root, source, output) { - return manualCargoPackageSource(path.join(source, "Cargo.toml"), output, { - root, - rel: String, - fail: (message) => { throw new Error(message); }, - }); -} - -test("uses Cargo's file selection, preserves modes, and emits deterministic exact members", (t) => { - const { root, source } = fixture(t, "cargo-source-selection"); - writeFileSync(path.join(source, "Cargo.toml"), manifest("selected-package", [ - 'exclude = ["forbidden.txt", "tools/**"]', - ])); - writeFileSync(path.join(source, "src/lib.rs"), "pub fn selected() {}\n"); - chmodSync(path.join(source, "src/lib.rs"), 0o755); - writeFileSync(path.join(source, "forbidden.txt"), "must not ship\n"); - mkdirSync(path.join(source, "tools")); - writeFileSync(path.join(source, "tools/check.sh"), "must not ship\n"); - - const first = packageSource(root, source, path.join(root, "first")); - const second = packageSource(root, source, path.join(root, "second")); - assert.deepEqual(readFileSync(first), readFileSync(second)); - assert.equal( - readFileSync(first).subarray(0, 10).toString("hex"), - "1f8b0800000000000003", - "Cargo source packages must use the canonical cross-platform gzip header", - ); - - const entries = readPortableArchiveEntries(first); - assert.deepEqual([...entries.keys()], [ - "selected-package-0.1.0/Cargo.toml", - "selected-package-0.1.0/src/lib.rs", - ]); - const sourceMode = statSync(path.join(source, "src/lib.rs")).mode & 0o777; - assert.equal(entries.get("selected-package-0.1.0/src/lib.rs").mode, sourceMode); - if (process.platform !== "win32") { - assert.equal(sourceMode, 0o755); - } -}); - -test("fixed tar file mode is host-independent while the default preserves filesystem modes", (t) => { - const { root } = fixture(t, "deterministic-tar-modes"); - const stage = path.join(root, "stage"); - mkdirSync(stage); - const writable = path.join(stage, "writable.txt"); - const executable = path.join(stage, "executable.sh"); - writeFileSync(writable, "writable\n"); - writeFileSync(executable, "#!/bin/sh\n"); - chmodSync(writable, 0o666); - chmodSync(executable, 0o755); - assert.equal(statSync(writable).mode & 0o777, 0o666); - - const fail = (message) => { throw new Error(message); }; - const fixedArchive = path.join(root, "fixed.tar.gz"); - writeFileSync( - fixedArchive, - gzipSync(createDeterministicTar(stage, "carrier", { fail, fixedFileMode: 0o644 }), { mtime: 0 }), - ); - const fixedEntries = readPortableArchiveEntries(fixedArchive); - assert.deepEqual( - [...fixedEntries].map(([name, entry]) => [name, entry.mode]), - [ - ["carrier/executable.sh", 0o644], - ["carrier/writable.txt", 0o644], - ], - ); - - const defaultArchive = path.join(root, "default.tar.gz"); - writeFileSync( - defaultArchive, - gzipSync(createDeterministicTar(stage, "cargo", { fail }), { mtime: 0 }), - ); - const defaultEntries = readPortableArchiveEntries(defaultArchive); - assert.equal(defaultEntries.get("cargo/writable.txt").mode, statSync(writable).mode & 0o777); - assert.equal(defaultEntries.get("cargo/executable.sh").mode, statSync(executable).mode & 0o777); - if (process.platform !== "win32") { - assert.equal(defaultEntries.get("cargo/executable.sh").mode, 0o755); - } - - assert.throws( - () => createDeterministicTar(stage, "invalid", { fail, fixedFileMode: 0o1000 }), - /fixed deterministic tar file mode/u, - ); -}); - -test("rejects Cargo-selected symbolic links and special-file targets", (t) => { - const linked = fixture(t, "cargo-source-link"); - writeFileSync(path.join(linked.source, "Cargo.toml"), manifest("linked-package")); - writeFileSync(path.join(linked.source, "real.rs"), "pub fn linked() {}\n"); - rmSync(path.join(linked.source, "src/lib.rs"), { force: true }); - symlinkSync(path.join("..", "real.rs"), path.join(linked.source, "src/lib.rs")); - assert.throws( - () => packageSource(linked.root, linked.source, path.join(linked.root, "output")), - /must not be a symbolic link/u, - ); - - const special = fixture(t, "cargo-source-special"); - const fifo = path.join(special.source, "src/lib.rs"); - const created = spawnSync("mkfifo", [fifo], { encoding: "utf8" }); - if (created.error?.code === "ENOENT") { - t.diagnostic("mkfifo unavailable; special-file case skipped"); - return; - } - assert.equal(created.status, 0, created.stderr); - writeFileSync(path.join(special.source, "Cargo.toml"), manifest("special-package")); - assert.throws( - () => packageSource( - special.root, - special.source, - path.join(special.root, "output"), - ), - /target .* source src\/lib[.]rs is absent from Cargo's package selection/u, - ); -}); - -test("rejects absolute, parent, backslash, and non-portable Cargo member paths", () => { - assert.deepEqual(cargoPackageRelativePathParts("src/lib.rs"), ["src", "lib.rs"]); - for (const candidate of ["../escape", "/absolute", "C:/absolute", "src\\escape", "bad:name"]) { - assert.throws(() => cargoPackageRelativePathParts(candidate), /Cargo package path/u); - } -}); diff --git a/tools/release/cargo-upload-reconciliation.mjs b/tools/release/cargo-upload-reconciliation.mjs deleted file mode 100644 index 68faa6a0d..000000000 --- a/tools/release/cargo-upload-reconciliation.mjs +++ /dev/null @@ -1,70 +0,0 @@ -import { isRegistryPublicationDeferredError } from "./registry-publication-deferral.mjs"; - -const DEFAULT_VISIBILITY_ATTEMPTS = 12; - -function requiredFunction(value, context) { - if (typeof value !== "function") { - throw new Error(`cargo-upload-reconciliation: ${context} must be a function`); - } - return value; -} - -function mutationFailureDetail(cause) { - if (cause instanceof Error && cause.message.trim().length > 0) return cause.message.trim(); - return String(cause); -} - -/** - * Execute one immutable Cargo upload attempt and reconcile it through the - * exact-version registry view. The upload is intentionally outside the - * visibility loop: an ambiguous response must never cause a second mutation. - */ -export async function uploadCargoOnceAndReconcileExactVersion({ - crateName, - version, - upload, - exactVersionPublished, - waitBeforeNextProbe, - visibilityAttempts = DEFAULT_VISIBILITY_ATTEMPTS, -}) { - const publish = requiredFunction(upload, "upload"); - const inspectExactVersion = requiredFunction(exactVersionPublished, "exactVersionPublished"); - const wait = requiredFunction(waitBeforeNextProbe, "waitBeforeNextProbe"); - if (!Number.isSafeInteger(visibilityAttempts) || visibilityAttempts < 1) { - throw new Error("cargo-upload-reconciliation: visibilityAttempts must be a positive integer"); - } - - let mutationFailed = false; - let mutationFailure; - try { - await publish(); - } catch (cause) { - // Typed deferrals are emitted only before an upload can become ambiguous: - // either the bounded deadline was already exhausted or crates.io returned - // an explicit 429 with a valid Retry-After. Preserve that control signal - // so the caller can checkpoint and continue instead of turning it into a - // terminal mutation failure. Every other exception remains ambiguous and - // must be reconciled without replaying the upload. - if (isRegistryPublicationDeferredError(cause)) throw cause; - mutationFailed = true; - mutationFailure = cause; - } - - for (let attempt = 0; attempt < visibilityAttempts; attempt += 1) { - if (await inspectExactVersion()) { - return { reconciledMutationFailure: mutationFailed }; - } - if (attempt + 1 < visibilityAttempts) { - await wait(); - } - } - - const visibilityFailure = `${crateName} ${version} did not appear on crates.io after the single frozen upload attempt`; - if (mutationFailed) { - throw new Error( - `Cargo upload for ${crateName}@${version} failed (${mutationFailureDetail(mutationFailure)}) and immutable registry state did not reconcile: ${visibilityFailure}`, - { cause: mutationFailure }, - ); - } - throw new Error(visibilityFailure); -} diff --git a/tools/release/cargo-upload-reconciliation.mts b/tools/release/cargo-upload-reconciliation.mts new file mode 100644 index 000000000..b4bbe9c6f --- /dev/null +++ b/tools/release/cargo-upload-reconciliation.mts @@ -0,0 +1,70 @@ +import { isRegistryPublicationDeferredError } from './registry-publication-deferral.mts'; + +const DEFAULT_VISIBILITY_ATTEMPTS = 12; + +function requiredFunction(value, context) { + if (typeof value !== 'function') { + throw new Error(`cargo-upload-reconciliation: ${context} must be a function`); + } + return value; +} + +function mutationFailureDetail(cause) { + if (cause instanceof Error && cause.message.trim().length > 0) return cause.message.trim(); + return String(cause); +} + +/** + * Execute one immutable Cargo upload attempt and reconcile it through the + * exact-version registry view. The upload is intentionally outside the + * visibility loop: an ambiguous response must never cause a second mutation. + */ +export async function uploadCargoOnceAndReconcileExactVersion({ + crateName, + version, + upload, + exactVersionPublished, + waitBeforeNextProbe, + visibilityAttempts = DEFAULT_VISIBILITY_ATTEMPTS, +}) { + const publish = requiredFunction(upload, 'upload'); + const inspectExactVersion = requiredFunction(exactVersionPublished, 'exactVersionPublished'); + const wait = requiredFunction(waitBeforeNextProbe, 'waitBeforeNextProbe'); + if (!Number.isSafeInteger(visibilityAttempts) || visibilityAttempts < 1) { + throw new Error('cargo-upload-reconciliation: visibilityAttempts must be a positive integer'); + } + + let mutationFailed = false; + let mutationFailure; + try { + await publish(); + } catch (cause) { + // Typed deferrals are emitted only before an upload can become ambiguous: + // either the bounded deadline was already exhausted or crates.io returned + // an explicit 429 with a valid Retry-After. Preserve that control signal + // so the caller can checkpoint and continue instead of turning it into a + // terminal mutation failure. Every other exception remains ambiguous and + // must be reconciled without replaying the upload. + if (isRegistryPublicationDeferredError(cause)) throw cause; + mutationFailed = true; + mutationFailure = cause; + } + + for (let attempt = 0; attempt < visibilityAttempts; attempt += 1) { + if (await inspectExactVersion()) { + return { reconciledMutationFailure: mutationFailed }; + } + if (attempt + 1 < visibilityAttempts) { + await wait(); + } + } + + const visibilityFailure = `${crateName} ${version} did not appear on crates.io after the single frozen upload attempt`; + if (mutationFailed) { + throw new Error( + `Cargo upload for ${crateName}@${version} failed (${mutationFailureDetail(mutationFailure)}) and immutable registry state did not reconcile: ${visibilityFailure}`, + { cause: mutationFailure }, + ); + } + throw new Error(visibilityFailure); +} diff --git a/tools/release/cargo-upload-reconciliation.test.mjs b/tools/release/cargo-upload-reconciliation.test.mjs deleted file mode 100644 index bdb0ddd77..000000000 --- a/tools/release/cargo-upload-reconciliation.test.mjs +++ /dev/null @@ -1,90 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { uploadCargoOnceAndReconcileExactVersion } from "./cargo-upload-reconciliation.mjs"; -import { RegistryPublicationDeferredError } from "./registry-publication-deferral.mjs"; - -function laggingExactVersionFixture({ uploadFailure = null } = {}) { - const events = []; - const registryStates = ["missing-name", "pending-version", "published-exact-version"]; - return { - events, - options: { - crateName: "oliphaunt-fixture", - version: "1.2.3", - upload: async () => { - events.push("upload"); - if (uploadFailure !== null) throw uploadFailure; - }, - exactVersionPublished: async () => { - const state = registryStates.shift(); - events.push(`inspect:${state}`); - return state === "published-exact-version"; - }, - waitBeforeNextProbe: async () => { - events.push("wait"); - }, - }, - }; -} - -describe("Cargo upload reconciliation", () => { - test("a successful upload tolerates name visibility before exact-version visibility", async () => { - const fixture = laggingExactVersionFixture(); - - await expect(uploadCargoOnceAndReconcileExactVersion(fixture.options)).resolves.toEqual({ - reconciledMutationFailure: false, - }); - expect(fixture.events).toEqual([ - "upload", - "inspect:missing-name", - "wait", - "inspect:pending-version", - "wait", - "inspect:published-exact-version", - ]); - expect(fixture.events.filter((event) => event === "upload")).toHaveLength(1); - }); - - test("an ambiguous upload failure polls through the same lag without replaying mutation", async () => { - const fixture = laggingExactVersionFixture({ uploadFailure: new Error("connection reset after request body") }); - - await expect(uploadCargoOnceAndReconcileExactVersion(fixture.options)).resolves.toEqual({ - reconciledMutationFailure: true, - }); - expect(fixture.events).toEqual([ - "upload", - "inspect:missing-name", - "wait", - "inspect:pending-version", - "wait", - "inspect:published-exact-version", - ]); - expect(fixture.events.filter((event) => event === "upload")).toHaveLength(1); - }); - - test("a typed pre-upload or explicit 429 deferral is preserved without visibility polling", async () => { - const deferral = new RegistryPublicationDeferredError({ - reason: "rate-limit", - notBeforeEpochSeconds: 1_234, - context: "crates.io returned an explicit Retry-After before accepting the upload", - }); - const events = []; - - await expect(uploadCargoOnceAndReconcileExactVersion({ - crateName: "oliphaunt-fixture", - version: "1.2.3", - upload: async () => { - events.push("upload"); - throw deferral; - }, - exactVersionPublished: async () => { - events.push("inspect"); - return false; - }, - waitBeforeNextProbe: async () => { - events.push("wait"); - }, - })).rejects.toBe(deferral); - expect(events).toEqual(["upload"]); - }); -}); diff --git a/tools/release/cargo-upload-reconciliation.test.mts b/tools/release/cargo-upload-reconciliation.test.mts new file mode 100644 index 000000000..d724551a8 --- /dev/null +++ b/tools/release/cargo-upload-reconciliation.test.mts @@ -0,0 +1,94 @@ +import { describe, expect, test } from 'bun:test'; + +import { uploadCargoOnceAndReconcileExactVersion } from './cargo-upload-reconciliation.mts'; +import { RegistryPublicationDeferredError } from './registry-publication-deferral.mts'; + +function laggingExactVersionFixture({ uploadFailure = null } = {}) { + const events = []; + const registryStates = ['missing-name', 'pending-version', 'published-exact-version']; + return { + events, + options: { + crateName: 'oliphaunt-fixture', + version: '1.2.3', + upload: async () => { + events.push('upload'); + if (uploadFailure !== null) throw uploadFailure; + }, + exactVersionPublished: async () => { + const state = registryStates.shift(); + events.push(`inspect:${state}`); + return state === 'published-exact-version'; + }, + waitBeforeNextProbe: async () => { + events.push('wait'); + }, + }, + }; +} + +describe('Cargo upload reconciliation', () => { + test('a successful upload tolerates name visibility before exact-version visibility', async () => { + const fixture = laggingExactVersionFixture(); + + await expect(uploadCargoOnceAndReconcileExactVersion(fixture.options)).resolves.toEqual({ + reconciledMutationFailure: false, + }); + expect(fixture.events).toEqual([ + 'upload', + 'inspect:missing-name', + 'wait', + 'inspect:pending-version', + 'wait', + 'inspect:published-exact-version', + ]); + expect(fixture.events.filter((event) => event === 'upload')).toHaveLength(1); + }); + + test('an ambiguous upload failure polls through the same lag without replaying mutation', async () => { + const fixture = laggingExactVersionFixture({ + uploadFailure: new Error('connection reset after request body'), + }); + + await expect(uploadCargoOnceAndReconcileExactVersion(fixture.options)).resolves.toEqual({ + reconciledMutationFailure: true, + }); + expect(fixture.events).toEqual([ + 'upload', + 'inspect:missing-name', + 'wait', + 'inspect:pending-version', + 'wait', + 'inspect:published-exact-version', + ]); + expect(fixture.events.filter((event) => event === 'upload')).toHaveLength(1); + }); + + test('a typed pre-upload or explicit 429 deferral is preserved without visibility polling', async () => { + const deferral = new RegistryPublicationDeferredError({ + reason: 'rate-limit', + notBeforeEpochSeconds: 1_234, + context: 'crates.io returned an explicit Retry-After before accepting the upload', + }); + const events = []; + + await expect( + uploadCargoOnceAndReconcileExactVersion({ + crateName: 'oliphaunt-fixture', + version: '1.2.3', + upload: async () => { + events.push('upload'); + throw deferral; + }, + exactVersionPublished: async () => { + events.push('inspect'); + return false; + }, + waitBeforeNextProbe: async () => { + events.push('wait'); + }, + }), + ).rejects.toBe(deferral); + expect(events).toEqual(['upload']); + }); +}); diff --git a/tools/release/carrier-license-contract.test.mjs b/tools/release/carrier-license-contract.test.mjs deleted file mode 100644 index e9d67dfe6..000000000 --- a/tools/release/carrier-license-contract.test.mjs +++ /dev/null @@ -1,93 +0,0 @@ -import assert from "node:assert/strict"; -import { - lstatSync, - readFileSync, - readdirSync, -} from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { BROKER_PAYLOAD_LICENSE } from "./broker-dependency-license-contract.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const CODE_LICENSE = "MIT"; -const NATIVE_RUNTIME_LICENSE = "MIT AND PostgreSQL AND Unicode-3.0"; -const NATIVE_TOOLS_LICENSE = "MIT AND PostgreSQL"; -const ICU_CARRIER_LICENSE = "MIT AND Unicode-3.0"; - -function readCargoLicense(relative) { - const file = path.join(ROOT, relative); - const stat = lstatSync(file); - assert.ok(stat.isFile() && !stat.isSymbolicLink(), `${relative} must be a regular manifest`); - const manifest = Bun.TOML.parse(readFileSync(file, "utf8")); - assert.equal(typeof manifest?.package?.name, "string", `${relative} must declare package.name`); - return manifest.package.license; -} - -function readNpmLicense(relative) { - const file = path.join(ROOT, relative); - const stat = lstatSync(file); - assert.ok(stat.isFile() && !stat.isSymbolicLink(), `${relative} must be a regular manifest`); - const manifest = JSON.parse(readFileSync(file, "utf8")); - assert.equal(typeof manifest?.name, "string", `${relative} must declare name`); - return manifest.license; -} - -function childManifests(relative, manifestName) { - const directory = path.join(ROOT, relative); - const entries = readdirSync(directory, { withFileTypes: true }); - const directories = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort(); - assert.ok(directories.length > 0, `${relative} must contain platform carrier directories`); - return directories.map((name) => `${relative}/${name}/${manifestName}`); -} - -function assertCargoLicenses(files, expected) { - for (const file of files) { - assert.equal(readCargoLicense(file), expected, `${file} must declare ${expected}`); - } -} - -function assertNpmLicenses(files, expected) { - for (const file of files) { - assert.equal(readNpmLicense(file), expected, `${file} must declare ${expected}`); - } -} - -test("broker source is MIT and compiled payload carriers declare their exact dependency license closure", () => { - assertCargoLicenses(["src/runtimes/broker/Cargo.toml"], CODE_LICENSE); - assertCargoLicenses( - childManifests("src/runtimes/broker/crates", "Cargo.toml"), - BROKER_PAYLOAD_LICENSE, - ); - assertNpmLicenses( - childManifests("src/runtimes/broker/packages", "package.json"), - BROKER_PAYLOAD_LICENSE, - ); -}); - -test("native source facades and payload carriers declare their exact role licenses", () => { - assertCargoLicenses([ - "src/runtimes/liboliphaunt/native/crates/tools/Cargo.toml", - ], CODE_LICENSE); - assertNpmLicenses( - childManifests("src/runtimes/liboliphaunt/native/packages", "package.json"), - NATIVE_RUNTIME_LICENSE, - ); - assertNpmLicenses( - childManifests("src/runtimes/liboliphaunt/native/tools-packages", "package.json"), - NATIVE_TOOLS_LICENSE, - ); -}); - -test("portable ICU carrier declares its exact data-only license closure", () => { - assertNpmLicenses([ - "src/runtimes/liboliphaunt/native/icu-npm/package.json", - ], ICU_CARRIER_LICENSE); - const podspec = readFileSync( - path.join(ROOT, "src/runtimes/liboliphaunt/native/icu-npm/OliphauntICU.podspec"), - "utf8", - ); - const declarations = [...podspec.matchAll(/^[ \t]*s[.]license[ \t]*=[ \t]*\{[ \t]*:type[ \t]*=>[ \t]*'([^']+)'[ \t]*\}[ \t]*$/gmu)]; - assert.equal(declarations.length, 1, "OliphauntICU.podspec must declare exactly one simple license type"); - assert.equal(declarations[0][1], ICU_CARRIER_LICENSE); -}); diff --git a/tools/release/carrier-license-contract.test.mts b/tools/release/carrier-license-contract.test.mts new file mode 100644 index 000000000..59696d4c8 --- /dev/null +++ b/tools/release/carrier-license-contract.test.mts @@ -0,0 +1,90 @@ +import assert from 'node:assert/strict'; +import { lstatSync, readFileSync, readdirSync } from 'node:fs'; +import path from 'node:path'; +import test from 'node:test'; + +import { BROKER_PAYLOAD_LICENSE } from '../../src/broker/tools/broker-dependency-license-contract.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); +const CODE_LICENSE = 'MIT'; +const NATIVE_RUNTIME_LICENSE = 'MIT AND PostgreSQL AND Unicode-3.0'; +const NATIVE_TOOLS_LICENSE = 'MIT AND PostgreSQL'; +const ICU_CARRIER_LICENSE = 'MIT AND Unicode-3.0'; + +function readCargoLicense(relative) { + const file = path.join(ROOT, relative); + const stat = lstatSync(file); + assert.ok(stat.isFile() && !stat.isSymbolicLink(), `${relative} must be a regular manifest`); + const manifest = Bun.TOML.parse(readFileSync(file, 'utf8')); + assert.equal(typeof manifest?.package?.name, 'string', `${relative} must declare package.name`); + return manifest.package.license; +} + +function readNpmLicense(relative) { + const file = path.join(ROOT, relative); + const stat = lstatSync(file); + assert.ok(stat.isFile() && !stat.isSymbolicLink(), `${relative} must be a regular manifest`); + const manifest = JSON.parse(readFileSync(file, 'utf8')); + assert.equal(typeof manifest?.name, 'string', `${relative} must declare name`); + return manifest.license; +} + +function childManifests(relative, manifestName) { + const directory = path.join(ROOT, relative); + const entries = readdirSync(directory, { withFileTypes: true }); + const directories = entries + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name) + .sort(); + assert.ok(directories.length > 0, `${relative} must contain platform carrier directories`); + return directories.map((name) => `${relative}/${name}/${manifestName}`); +} + +function assertCargoLicenses(files, expected) { + for (const file of files) { + assert.equal(readCargoLicense(file), expected, `${file} must declare ${expected}`); + } +} + +function assertNpmLicenses(files, expected) { + for (const file of files) { + assert.equal(readNpmLicense(file), expected, `${file} must declare ${expected}`); + } +} + +test('broker source is MIT and compiled payload carriers declare their exact dependency license closure', () => { + assertCargoLicenses(['src/broker/Cargo.toml'], CODE_LICENSE); + assertCargoLicenses(childManifests('src/broker/crates', 'Cargo.toml'), BROKER_PAYLOAD_LICENSE); + assertNpmLicenses(childManifests('src/broker/packages', 'package.json'), BROKER_PAYLOAD_LICENSE); +}); + +test('native source facades and payload carriers declare their exact role licenses', () => { + assertCargoLicenses(['src/postgres-tools/native/crates/tools/Cargo.toml'], CODE_LICENSE); + assertNpmLicenses( + childManifests('src/runtimes/liboliphaunt-native/packages', 'package.json'), + NATIVE_RUNTIME_LICENSE, + ); + assertNpmLicenses( + childManifests('src/postgres-tools/native/npm-platforms', 'package.json'), + NATIVE_TOOLS_LICENSE, + ); +}); + +test('portable ICU carrier declares its exact data-only license closure', () => { + assertNpmLicenses(['src/database-resources/icu/npm/package.json'], ICU_CARRIER_LICENSE); + const podspec = readFileSync( + path.join(ROOT, 'src/database-resources/icu/npm/OliphauntICU.podspec'), + 'utf8', + ); + const declarations = [ + ...podspec.matchAll( + /^[ \t]*s[.]license[ \t]*=[ \t]*\{[ \t]*:type[ \t]*=>[ \t]*'([^']+)'[ \t]*\}[ \t]*$/gmu, + ), + ]; + assert.equal( + declarations.length, + 1, + 'OliphauntICU.podspec must declare exactly one simple license type', + ); + assert.equal(declarations[0][1], ICU_CARRIER_LICENSE); +}); diff --git a/tools/release/check-broker-release-assets.mjs b/tools/release/check-broker-release-assets.mjs deleted file mode 100644 index 4247cb8d5..000000000 --- a/tools/release/check-broker-release-assets.mjs +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import path from "node:path"; - -import { - assertFileExists, - checksumManifest, - readArchiveEntries, - sha256, -} from "./release-asset-validation.mjs"; -import { - ROOT, - artifactTargets, - compareText, - currentProductVersion, - expectedAssets, - fail, -} from "./release-artifact-targets.mjs"; -import { inspectPlatformBinaryEntries } from "./platform-binary-contract.mjs"; -import { - WINDOWS_VC_RUNTIME_DLLS, - WINDOWS_VC_RUNTIME_RECEIPT, - inspectPortableExecutable, - windowsVcRuntimeImports, -} from "./windows-vc-runtime-closure.mjs"; -import { assertBrokerDependencyLicensesInEntries } from "./broker-dependency-license-contract.mjs"; - -const PREFIX = "check-broker-release-assets.mjs"; -const PRODUCT = "oliphaunt-broker"; -const KIND = "broker-helper"; - -function parseArgs(argv) { - const args = { - assetDir: path.join(ROOT, "target/oliphaunt-broker/release-assets"), - allowPartial: false, - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--asset-dir") { - const value = argv[index + 1]; - if (!value) { - fail(PREFIX, "--asset-dir requires a value"); - } - args.assetDir = path.resolve(value); - index += 1; - } else if (arg === "--allow-partial") { - args.allowPartial = true; - } else { - fail(PREFIX, `unknown argument ${arg}`); - } - } - return args; -} - -async function validateArchive(file, target) { - const entries = await readArchiveEntries(file, fail, PREFIX, "broker"); - try { - assertBrokerDependencyLicensesInEntries(entries, { - target: target.target, - label: path.basename(file), - }); - } catch (error) { - fail(PREFIX, error instanceof Error ? error.message : String(error)); - } - const executable = target.executableRelativePath; - if (!entries.has(executable)) { - fail(PREFIX, `${path.basename(file)} is missing ${executable}`); - } - if (!entries.has("manifest.properties")) { - fail(PREFIX, `${path.basename(file)} is missing manifest.properties`); - } - const broker = entries.get(executable); - if (!broker.isFile) { - fail(PREFIX, `${path.basename(file)} ${executable} is not a regular file`); - } - if (file.endsWith(".tar.gz") && (broker.mode & 0o111) === 0) { - fail(PREFIX, `${path.basename(file)} ${executable} is not executable`); - } - if (path.extname(file) === ".zip" && broker.size === 0) { - fail(PREFIX, `${path.basename(file)} ${executable} is empty`); - } - if (target.target === "windows-x64-msvc") { - const allowed = new Set(WINDOWS_VC_RUNTIME_DLLS); - const required = new Set(); - const pending = windowsVcRuntimeImports(Buffer.from(broker.data()), `${path.basename(file)}:${executable}`) - .map((name) => name.toLowerCase()); - while (pending.length > 0) { - const name = pending.shift(); - if (!allowed.has(name)) { - fail(PREFIX, `${path.basename(file)} imports undeclared or debug VC runtime ${name}`); - } - if (required.has(name)) continue; - const member = `bin/${name}`; - const entry = entries.get(member); - if (!entry?.isFile || entry.size <= 0) { - fail(PREFIX, `${path.basename(file)} is missing import-derived app-local ${member}`); - } - let inspected; - try { - inspected = inspectPortableExecutable(Buffer.from(entry.data()), `${path.basename(file)}:${member}`); - } catch (error) { - fail(PREFIX, error instanceof Error ? error.message : String(error)); - } - if (inspected.machine !== 0x8664 || inspected.magic !== 0x20b) { - fail(PREFIX, `${path.basename(file)} ${member} is not an x64 PE32+ image`); - } - required.add(name); - pending.push(...windowsVcRuntimeImports(Buffer.from(entry.data()), `${path.basename(file)}:${member}`).map((value) => value.toLowerCase())); - pending.sort(compareText); - } - const actual = WINDOWS_VC_RUNTIME_DLLS.filter((name) => entries.has(`bin/${name}`)); - if (actual.join("\0") !== [...required].sort(compareText).join("\0")) { - fail(PREFIX, `${path.basename(file)} app-local VC runtime members must exactly match its PE import closure`); - } - const receiptMember = `bin/${WINDOWS_VC_RUNTIME_RECEIPT}`; - const receiptEntry = entries.get(receiptMember); - if (!receiptEntry?.isFile) { - fail(PREFIX, `${path.basename(file)} is missing ${receiptMember}`); - } - const receipt = Buffer.from(receiptEntry.data()).toString("utf8"); - const expectedReceipt = [...required].sort(compareText).map((name) => { - const digest = createHash("sha256").update(Buffer.from(entries.get(`bin/${name}`).data())).digest("hex"); - return `${digest} ${name}\n`; - }).join(""); - if (receipt !== expectedReceipt) { - fail(PREFIX, `${path.basename(file)} ${receiptMember} does not exactly bind its app-local VC runtime bytes`); - } - const manifest = Buffer.from(entries.get("manifest.properties").data()).toString("utf8"); - const expectedLine = `windowsVcRuntimeDlls=${[...required].sort(compareText).join(",")}`; - if (!manifest.split(/\r?\n/u).includes(expectedLine)) { - fail(PREFIX, `${path.basename(file)} manifest.properties must declare ${expectedLine}`); - } - } - inspectPlatformBinaryEntries( - [...entries].map(([name, entry]) => ({ name, ...entry })), - { target: target.target, rootLabel: path.basename(file) }, - ); -} - -async function main() { - const args = parseArgs(Bun.argv.slice(2)); - const version = await currentProductVersion(PRODUCT, PREFIX); - const requiredAssets = expectedAssets(PRODUCT, KIND, version, PREFIX); - const targets = artifactTargets(PRODUCT, KIND, PREFIX); - const targetsByAsset = new Map(targets.map((target) => [target.asset.replaceAll("{version}", version), target])); - const missing = []; - for (const asset of requiredAssets) { - if (!(await assertFileExists(path.join(args.assetDir, asset)))) { - missing.push(asset); - } - } - if (missing.length > 0) { - if (!args.allowPartial) { - fail(PREFIX, `missing oliphaunt-broker release asset(s): ${missing.join(", ")}`); - } - let presentBrokerAssets = 0; - for (const target of targets) { - if (await assertFileExists(path.join(args.assetDir, target.asset.replaceAll("{version}", version)))) { - presentBrokerAssets += 1; - } - } - if (presentBrokerAssets === 0) { - fail(PREFIX, "partial oliphaunt-broker release asset validation requires at least one broker asset"); - } - } - - const checksumAsset = `oliphaunt-broker-${version}-release-assets.sha256`; - const checksumPath = path.join(args.assetDir, checksumAsset); - if (!(await assertFileExists(checksumPath))) { - fail(PREFIX, `missing checksum manifest: ${checksumAsset}`); - } - const checksums = await checksumManifest(checksumPath, fail, PREFIX); - for (const asset of requiredAssets.sort(compareText)) { - const assetPath = path.join(args.assetDir, asset); - if (args.allowPartial && !(await assertFileExists(assetPath))) { - continue; - } - if (asset === checksumAsset) { - continue; - } - const expected = checksums.get(asset); - if (!expected) { - fail(PREFIX, `${checksumAsset} does not cover ${asset}`); - } - const actual = await sha256(assetPath); - if (actual !== expected) { - fail(PREFIX, `checksum mismatch for ${asset}: expected ${expected}, got ${actual}`); - } - } - for (const [asset, target] of targetsByAsset) { - const assetPath = path.join(args.assetDir, asset); - if (args.allowPartial && !(await assertFileExists(assetPath))) { - continue; - } - await validateArchive(assetPath, target); - } - console.log(`oliphaunt-broker release assets validated: ${args.assetDir}`); -} - -await main(); diff --git a/tools/release/check-cargo-package-test-closure.mjs b/tools/release/check-cargo-package-test-closure.mjs deleted file mode 100644 index cb81d3093..000000000 --- a/tools/release/check-cargo-package-test-closure.mjs +++ /dev/null @@ -1,467 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "node:child_process"; -import { - chmodSync, - copyFileSync, - lstatSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - realpathSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const TOOL = "check-cargo-package-test-closure.mjs"; -const TIMEOUT_MS = 30 * 60_000; -const CARGO_PACKAGE_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]*$/u; - -function error(message) { - return new Error(`${TOOL}: ${message}`); -} - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function regularFile(file, context) { - let metadata; - try { - metadata = lstatSync(file); - } catch (cause) { - throw error(`${context} is missing: ${file}: ${cause.message}`); - } - if (!metadata.isFile() || metadata.isSymbolicLink()) { - throw error(`${context} must be a regular, non-symlink file: ${file}`); - } - return metadata; -} - -function parseManifest(file, context) { - regularFile(file, context); - try { - return Bun.TOML.parse(readFileSync(file, "utf8")); - } catch (cause) { - throw error(`${context} is not valid TOML: ${file}: ${cause.message}`); - } -} - -function packageIdentity(manifest, context) { - const pkg = manifest?.package; - if ( - pkg === null - || Array.isArray(pkg) - || typeof pkg !== "object" - || typeof pkg.name !== "string" - || typeof pkg.version !== "string" - || !pkg.name - || !pkg.version - ) { - throw error(`${context} must declare non-empty package.name and package.version strings`); - } - if (!CARGO_PACKAGE_NAME.test(pkg.name)) { - throw error(`${context} declares unsafe Cargo package name ${JSON.stringify(pkg.name)}`); - } - return { name: pkg.name, version: pkg.version }; -} - -function dependencyTables(manifest) { - const tables = []; - for (const name of ["dependencies", "dev-dependencies", "build-dependencies"]) { - if (manifest?.[name] !== undefined) tables.push(manifest[name]); - } - const targets = manifest?.target ?? {}; - if (targets === null || Array.isArray(targets) || typeof targets !== "object") { - throw error("target dependencies must be TOML tables"); - } - for (const target of Object.values(targets)) { - if (target === null || Array.isArray(target) || typeof target !== "object") { - throw error("each target dependency section must be a TOML table"); - } - for (const name of ["dependencies", "dev-dependencies", "build-dependencies"]) { - if (target[name] !== undefined) tables.push(target[name]); - } - } - return tables; -} - -function dependencyRows(manifest) { - const rows = []; - for (const table of dependencyTables(manifest)) { - if (table === null || Array.isArray(table) || typeof table !== "object") { - throw error("dependency sections must be TOML tables"); - } - for (const [alias, raw] of Object.entries(table)) { - const value = typeof raw === "string" ? { version: raw } : raw; - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(`dependency ${alias} must be a version string or TOML table`); - } - const name = typeof value.package === "string" ? value.package : alias; - if (!CARGO_PACKAGE_NAME.test(alias) || !CARGO_PACKAGE_NAME.test(name)) { - throw error(`dependency declares unsafe Cargo package name or alias: ${alias} -> ${name}`); - } - rows.push({ - alias, - name, - path: typeof value.path === "string" ? value.path : null, - version: typeof value.version === "string" ? value.version : null, - features: Array.isArray(value.features) - ? value.features.filter((feature) => typeof feature === "string") - : [], - }); - } - } - return rows; -} - -function exactVersion(requirement, dependency) { - const match = requirement?.match(/^=([0-9A-Za-z][0-9A-Za-z.+-]*)$/u); - if (!match) { - throw error(`stub dependency ${dependency} must use an exact =version requirement, got ${requirement ?? "none"}`); - } - return match[1]; -} - -function addPatch(patches, name, directory, context) { - const resolved = realpathSync(directory); - const previous = patches.get(name); - if (previous !== undefined && previous !== resolved) { - throw error(`${name} has conflicting local patches: ${previous} and ${resolved} (${context})`); - } - patches.set(name, resolved); -} - -function copyCleanDependencySource(source, destination) { - const ignoredDirectories = new Set([".git", "artifacts", "payload", "target"]); - rmSync(destination, { recursive: true, force: true }); - mkdirSync(destination, { recursive: true }); - const visit = (sourceDirectory, destinationDirectory) => { - for (const entry of readdirSync(sourceDirectory, { withFileTypes: true }).sort((left, right) => - compareText(left.name, right.name))) { - if (entry.name === ".DS_Store" || (entry.isDirectory() && ignoredDirectories.has(entry.name))) { - continue; - } - const sourcePath = path.join(sourceDirectory, entry.name); - const destinationPath = path.join(destinationDirectory, entry.name); - const metadata = lstatSync(sourcePath); - if (metadata.isSymbolicLink()) { - throw error(`path dependency source must not contain symbolic links: ${sourcePath}`); - } - if (metadata.isDirectory()) { - mkdirSync(destinationPath, { recursive: true }); - visit(sourcePath, destinationPath); - } else if (metadata.isFile()) { - copyFileSync(sourcePath, destinationPath); - chmodSync(destinationPath, metadata.mode & 0o777); - } else { - throw error(`path dependency source contains a special file: ${sourcePath}`); - } - } - }; - visit(source, destination); -} - -function pathDependencyPatches(manifests, scratch, packagedManifest) { - const patches = new Map(); - const sourceDirectories = new Map(); - const packagedDependencies = dependencyRows(packagedManifest); - for (const manifestFile of manifests) { - const resolvedManifest = path.resolve(manifestFile); - const manifest = parseManifest(resolvedManifest, "path-dependency source manifest"); - for (const dependency of dependencyRows(manifest).filter((row) => row.path !== null)) { - const directory = path.resolve(path.dirname(resolvedManifest), dependency.path); - const localManifestFile = path.join(directory, "Cargo.toml"); - const localManifest = parseManifest(localManifestFile, `local patch for ${dependency.name}`); - const local = packageIdentity(localManifest, `local patch for ${dependency.name}`); - if (local.name !== dependency.name) { - throw error(`local patch ${localManifestFile} declares ${local.name}, expected ${dependency.name}`); - } - const packagedVersions = new Set( - packagedDependencies - .filter(({ name }) => name === dependency.name) - .map(({ version }) => exactVersion(version, dependency.name)), - ); - if (packagedVersions.size !== 1 || !packagedVersions.has(local.version)) { - throw error( - `local patch ${dependency.name}@${local.version} does not match packaged requirement ${[...packagedVersions].join(", ") || "none"}`, - ); - } - const realSource = realpathSync(directory); - const previousSource = sourceDirectories.get(dependency.name); - if (previousSource !== undefined && previousSource !== realSource) { - throw error( - `${dependency.name} has conflicting path-dependency sources: ${previousSource} and ${realSource}`, - ); - } - sourceDirectories.set(dependency.name, realSource); - const staged = path.join(scratch, "path-dependency-sources", dependency.name); - if (!patches.has(dependency.name)) copyCleanDependencySource(directory, staged); - addPatch(patches, dependency.name, staged, resolvedManifest); - } - } - return patches; -} - -function forwardedStubFeatures(manifest, aliases) { - const features = new Map([...aliases].map((alias) => [alias, new Set()])); - const packageFeatures = manifest.features ?? {}; - if (packageFeatures === null || Array.isArray(packageFeatures) || typeof packageFeatures !== "object") { - throw error("package features must be a TOML table"); - } - for (const members of Object.values(packageFeatures)) { - if (!Array.isArray(members)) continue; - for (const member of members) { - if (typeof member !== "string" || !member.includes("/")) continue; - const [alias, feature] = member.split("/", 2); - features.get(alias?.replace(/^dep:/u, "").replace(/\?$/u, ""))?.add(feature); - } - } - return features; -} - -function createStubPatches({ manifest, scratch, names, prefixes }) { - const dependencies = dependencyRows(manifest); - const selected = dependencies.filter(({ name }) => - names.has(name) || prefixes.some((prefix) => name.startsWith(prefix))); - for (const name of names) { - if (!selected.some((dependency) => dependency.name === name)) { - throw error(`requested stub dependency is absent from the packaged manifest: ${name}`); - } - } - for (const prefix of prefixes) { - if (!selected.some((dependency) => dependency.name.startsWith(prefix))) { - throw error(`stub dependency prefix matched no packaged dependency: ${prefix}`); - } - } - - const aliasesByName = new Map(); - for (const dependency of selected) { - const aliases = aliasesByName.get(dependency.name) ?? new Set(); - aliases.add(dependency.alias); - aliasesByName.set(dependency.name, aliases); - } - const allAliases = new Set([...aliasesByName.values()].flatMap((aliases) => [...aliases])); - const forwarded = forwardedStubFeatures(manifest, allAliases); - const patches = new Map(); - for (const name of [...aliasesByName.keys()].sort(compareText)) { - const rows = selected.filter((dependency) => dependency.name === name); - const versions = new Set(rows.map((dependency) => exactVersion(dependency.version, name))); - if (versions.size !== 1) { - throw error(`stub dependency ${name} has conflicting exact versions: ${[...versions].join(", ")}`); - } - const [version] = versions; - const features = new Set(rows.flatMap((dependency) => dependency.features)); - for (const alias of aliasesByName.get(name)) { - for (const feature of forwarded.get(alias) ?? []) features.add(feature); - } - const directory = path.join(scratch, "dependency-stubs", name); - mkdirSync(path.join(directory, "src"), { recursive: true }); - const featureRows = [...features].sort(compareText).map((feature) => - `${JSON.stringify(feature)} = []`); - writeFileSync(path.join(directory, "Cargo.toml"), [ - "[package]", - `name = ${JSON.stringify(name)}`, - `version = ${JSON.stringify(version)}`, - 'edition = "2024"', - "publish = false", - "", - "[lib]", - 'path = "src/lib.rs"', - "", - ...(featureRows.length > 0 ? ["[features]", ...featureRows, ""] : []), - "[workspace]", - "", - ].join("\n")); - writeFileSync(path.join(directory, "src/lib.rs"), "#![forbid(unsafe_code)]\n"); - addPatch(patches, name, directory, "generated test-closure stub"); - } - return patches; -} - -function extractCrate(cratePath, scratch) { - const entries = readPortableArchiveEntries(cratePath); - const roots = new Set([...entries.keys()].map((name) => name.split("/", 1)[0])); - if (roots.size !== 1) { - throw error(`${cratePath} must contain exactly one package root, found ${roots.size}`); - } - const [rootName] = roots; - for (const entry of entries.values()) { - const destination = path.join(scratch, ...entry.name.split("/")); - if (entry.isDirectory) { - mkdirSync(destination, { recursive: true }); - continue; - } - mkdirSync(path.dirname(destination), { recursive: true }); - writeFileSync(destination, entry.data(), { flag: "wx", mode: entry.mode & 0o777 }); - chmodSync(destination, entry.mode & 0o777); - } - const packageRoot = path.join(scratch, rootName); - const manifestFile = path.join(packageRoot, "Cargo.toml"); - const manifest = parseManifest(manifestFile, "extracted package manifest"); - const identity = packageIdentity(manifest, "extracted package manifest"); - if (rootName !== `${identity.name}-${identity.version}`) { - throw error(`${cratePath} root is ${rootName}, expected ${identity.name}-${identity.version}`); - } - return { identity, manifest, manifestFile, packageRoot }; -} - -function writePatchConfig(scratch, patches) { - const configDir = path.join(scratch, ".cargo"); - mkdirSync(configDir, { recursive: true }); - const rows = [...patches.entries()].sort(([left], [right]) => compareText(left, right)); - writeFileSync(path.join(configDir, "config.toml"), [ - "[net]", - "offline = true", - "", - ...(rows.length > 0 - ? [ - "[patch.crates-io]", - ...rows.map(([name, directory]) => - `${JSON.stringify(name)} = { path = ${JSON.stringify(directory)} }`), - "", - ] - : []), - ].join("\n")); -} - -export function verifyPackagedCargoTestClosure({ - cratePath, - targetDir = process.env.CARGO_TARGET_DIR ?? path.join(ROOT, "target/cargo-package-test-closure"), - pathDependencyManifests = [], - stubDependencies = [], - stubDependencyPrefixes = [], - allFeatures = false, - noDefaultFeatures = false, - features = [], - lib = false, -} = {}) { - if (typeof cratePath !== "string" || !cratePath) throw error("cratePath is required"); - if (allFeatures && features.length > 0) { - throw error("allFeatures and explicit features are mutually exclusive"); - } - const crate = path.resolve(cratePath); - regularFile(crate, "crate archive"); - const scratch = mkdtempSync(path.join(realpathSync(os.tmpdir()), "oliphaunt-cargo-package-test-")); - try { - const extracted = extractCrate(crate, scratch); - const patches = pathDependencyPatches( - pathDependencyManifests, - scratch, - extracted.manifest, - ); - const stubs = createStubPatches({ - manifest: extracted.manifest, - scratch, - names: new Set(stubDependencies), - prefixes: [...stubDependencyPrefixes], - }); - for (const [name, directory] of stubs) addPatch(patches, name, directory, "stub dependency"); - writePatchConfig(scratch, patches); - - const cargoEnvironment = { ...process.env }; - for (const name of Object.keys(cargoEnvironment)) { - if (name.startsWith("OLIPHAUNT_")) delete cargoEnvironment[name]; - } - cargoEnvironment.CARGO_TARGET_DIR = path.resolve(targetDir); - cargoEnvironment.CARGO_TERM_COLOR = "never"; - const runCargo = (args) => { - const result = spawnSync("cargo", args, { - cwd: scratch, - env: cargoEnvironment, - stdio: "inherit", - timeout: TIMEOUT_MS, - }); - if (result.error !== undefined) { - throw error(`cargo ${args.join(" ")} failed to start for ${path.basename(crate)}: ${result.error.message}`); - } - if (result.status !== 0) { - throw error( - `cargo ${args.join(" ")} exited ${result.status ?? `for signal ${result.signal ?? "unknown"}`} ` - + `for ${path.basename(crate)}`, - ); - } - }; - runCargo(["generate-lockfile", "--manifest-path", extracted.manifestFile, "--offline"]); - - const args = ["test", "--manifest-path", extracted.manifestFile, "--locked", "--offline", "--no-run"]; - if (allFeatures) args.push("--all-features"); - if (noDefaultFeatures) args.push("--no-default-features"); - if (features.length > 0) args.push("--features", features.join(",")); - if (lib) args.push("--lib"); - runCargo(args); - console.log( - `Cargo package test closure verified: ${extracted.identity.name}@${extracted.identity.version}`, - ); - return extracted.identity; - } finally { - rmSync(scratch, { recursive: true, force: true }); - } -} - -function requiredValue(argv, index, option) { - const value = argv[index]; - if (value === undefined || value.startsWith("--")) throw error(`${option} requires a value`); - return value; -} - -function parseArgs(argv) { - const options = { - cratePath: null, - targetDir: process.env.CARGO_TARGET_DIR ?? path.join(ROOT, "target/cargo-package-test-closure"), - pathDependencyManifests: [], - stubDependencies: [], - stubDependencyPrefixes: [], - allFeatures: false, - noDefaultFeatures: false, - features: [], - lib: false, - }; - for (let index = 0; index < argv.length; index += 1) { - const option = argv[index]; - if (option === "--crate") { - options.cratePath = requiredValue(argv, ++index, option); - } else if (option === "--target-dir") { - options.targetDir = requiredValue(argv, ++index, option); - } else if (option === "--path-dependencies-from") { - options.pathDependencyManifests.push(requiredValue(argv, ++index, option)); - } else if (option === "--stub-dependency") { - options.stubDependencies.push(requiredValue(argv, ++index, option)); - } else if (option === "--stub-dependency-prefix") { - options.stubDependencyPrefixes.push(requiredValue(argv, ++index, option)); - } else if (option === "--features") { - options.features.push(...requiredValue(argv, ++index, option).split(",").filter(Boolean)); - } else if (option === "--all-features") { - options.allFeatures = true; - } else if (option === "--no-default-features") { - options.noDefaultFeatures = true; - } else if (option === "--lib") { - options.lib = true; - } else { - throw error(`unknown argument: ${option}`); - } - } - if (!options.cratePath) { - throw error( - "usage: check-cargo-package-test-closure.mjs --crate FILE [--path-dependencies-from Cargo.toml] " - + "[--stub-dependency NAME] [--stub-dependency-prefix PREFIX] [--all-features|--features LIST] " - + "[--no-default-features] [--lib]", - ); - } - return options; -} - -if (import.meta.main) { - try { - verifyPackagedCargoTestClosure(parseArgs(Bun.argv.slice(2))); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/check-cargo-package-test-closure.test.mjs b/tools/release/check-cargo-package-test-closure.test.mjs deleted file mode 100644 index 1c4dfeac1..000000000 --- a/tools/release/check-cargo-package-test-closure.test.mjs +++ /dev/null @@ -1,162 +0,0 @@ -import assert from "node:assert/strict"; -import { - mkdtempSync, - mkdirSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; -import { gzipSync } from "node:zlib"; - -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -import { verifyPackagedCargoTestClosure } from "./check-cargo-package-test-closure.mjs"; -import { - createDeterministicTar, - manualCargoPackageSource, -} from "./cargo-source-package.mjs"; - -const SCRIPT = path.resolve(import.meta.dirname, "check-cargo-package-test-closure.mjs"); - -function fixture(t, name) { - const root = mkdtempSync(path.join(os.tmpdir(), `oliphaunt-${name}-`)); - t.after(() => rmSync(root, { recursive: true, force: true })); - return root; -} - -function writePackage(directory, name, body = "#![forbid(unsafe_code)]\n") { - mkdirSync(path.join(directory, "src"), { recursive: true }); - writeFileSync(path.join(directory, "Cargo.toml"), [ - "[package]", - `name = ${JSON.stringify(name)}`, - 'version = "0.1.0"', - 'edition = "2024"', - 'license = "MIT"', - "", - "[lib]", - 'path = "src/lib.rs"', - "", - ].join("\n")); - writeFileSync(path.join(directory, "src/lib.rs"), body); -} - -function closureCrate(root) { - const source = path.join(root, "source"); - mkdirSync(path.join(source, "src"), { recursive: true }); - writeFileSync(path.join(source, "Cargo.toml"), [ - "[package]", - 'name = "closure-fixture"', - 'version = "0.1.0"', - 'edition = "2024"', - 'license = "MIT"', - "", - "[features]", - 'forward = ["carrier?/needed"]', - "", - "[dependencies]", - 'carrier = { version = "=0.1.0", optional = true }', - "", - "[lib]", - 'path = "src/lib.rs"', - "", - ].join("\n")); - writeFileSync(path.join(source, "src/lib.rs"), "#![forbid(unsafe_code)]\n"); - return manualCargoPackageSource( - path.join(source, "Cargo.toml"), - path.join(root, "crate"), - { - root, - rel: String, - fail: (message) => { throw new Error(message); }, - }, - ); -} - -test("compiles an unpacked crate offline with locked weak-feature carrier stubs", (t) => { - const root = fixture(t, "cargo-closure-stub"); - const cratePath = closureCrate(root); - assert.deepEqual( - verifyPackagedCargoTestClosure({ - cratePath, - targetDir: path.join(root, "target"), - stubDependencies: ["carrier"], - noDefaultFeatures: true, - features: ["forward"], - lib: true, - }), - { name: "closure-fixture", version: "0.1.0" }, - ); -}); - -test("rejects conflicting path-patch sources for the same package identity", (t) => { - const root = fixture(t, "cargo-closure-conflict"); - const cratePath = closureCrate(root); - const controllers = []; - for (const suffix of ["one", "two"]) { - const dependency = path.join(root, `carrier-${suffix}`); - writePackage(dependency, "carrier"); - const controller = path.join(root, `controller-${suffix}`); - writePackage(controller, `controller-${suffix}`); - writeFileSync(path.join(controller, "Cargo.toml"), [ - "[package]", - `name = "controller-${suffix}"`, - 'version = "0.1.0"', - 'edition = "2024"', - "", - "[dependencies]", - `carrier = { version = "*", path = ${JSON.stringify(dependency)} }`, - "", - ].join("\n")); - controllers.push(path.join(controller, "Cargo.toml")); - } - assert.throws( - () => verifyPackagedCargoTestClosure({ - cratePath, - targetDir: path.join(root, "target"), - pathDependencyManifests: controllers, - noDefaultFeatures: true, - lib: true, - }), - /conflicting path-dependency sources/u, - ); -}); - -test("rejects unsafe packaged names and invalid CLI/config combinations", (t) => { - const root = fixture(t, "cargo-closure-unsafe"); - const stage = path.join(root, "stage"); - mkdirSync(path.join(stage, "src"), { recursive: true }); - writeFileSync(path.join(stage, "Cargo.toml"), [ - "[package]", - 'name = "../escape"', - 'version = "0.1.0"', - 'edition = "2024"', - "", - ].join("\n")); - writeFileSync(path.join(stage, "src/lib.rs"), ""); - const unsafeCrate = path.join(root, "unsafe.crate"); - writeFileSync( - unsafeCrate, - gzipSync(createDeterministicTar(stage, "safe-root", { - fail: (message) => { throw new Error(message); }, - }), { mtime: 0 }), - ); - assert.throws( - () => verifyPackagedCargoTestClosure({ cratePath: unsafeCrate }), - /unsafe Cargo package name/u, - ); - - const cratePath = closureCrate(root); - assert.throws( - () => verifyPackagedCargoTestClosure({ - cratePath, - allFeatures: true, - features: ["forward"], - }), - /mutually exclusive/u, - ); - const cli = spawnSync(process.execPath, [SCRIPT, "--unknown"], { encoding: "utf8" }); - assert.equal(cli.status, 1); - assert.match(`${cli.stdout}${cli.stderr}`, /unknown argument/u); -}); diff --git a/tools/release/check-cross-family-icu-data.mjs b/tools/release/check-cross-family-icu-data.mjs deleted file mode 100644 index b64b9c58a..000000000 --- a/tools/release/check-cross-family-icu-data.mjs +++ /dev/null @@ -1,143 +0,0 @@ -#!/usr/bin/env bun - -import { lstatSync, readdirSync } from "node:fs"; -import path from "node:path"; - -import { - ICU_DATA_FORM, - ICU_DATA_VERSION, - parseNativeIcuDataIdentity, -} from "./native-icu-data-contract.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { WASIX_PORTABLE_RELEASE_MEMBERS } from "./wasix-runtime-npm-contract.mjs"; - -const TOOL = "check-cross-family-icu-data.mjs"; -const LOWER_SHA256 = /^[0-9a-f]{64}$/u; -const UTF8 = new TextDecoder("utf-8", { fatal: true }); - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function onlyAsset(directory, pattern, label) { - const matches = readdirSync(directory, { withFileTypes: true }) - .filter((entry) => entry.isFile() && !entry.isSymbolicLink() && pattern.test(entry.name)) - .map((entry) => path.join(directory, entry.name)); - if (matches.length !== 1) { - fail(`${label} directory must contain exactly one matching release asset; found ${matches.length}`); - } - const metadata = lstatSync(matches[0]); - if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) { - fail(`${label} release asset must be a non-empty regular file`); - } - return matches[0]; -} - -function requiredEntry(entries, member, label) { - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${label} must contain ${member} as a non-empty regular file`); - } - return Buffer.from(entry.data()); -} - -function json(bytes, label) { - let text; - try { - text = UTF8.decode(bytes); - } catch { - fail(`${label} is not valid UTF-8`); - } - let value; - try { - value = JSON.parse(text); - } catch (error) { - fail(`${label} is not valid JSON: ${error.message}`); - } - if (value === null || Array.isArray(value) || typeof value !== "object") fail(`${label} must be an object`); - return value; -} - -function checkedDigest(value, label) { - if (typeof value !== "string" || !LOWER_SHA256.test(value)) { - fail(`${label} must be a lowercase SHA-256 digest`); - } - return value; -} - -export function wasixIcuDataIdentity(portableRuntimeArchive) { - const entries = readPortableArchiveEntries(path.resolve(portableRuntimeArchive)); - const outer = json( - requiredEntry(entries, WASIX_PORTABLE_RELEASE_MEMBERS.manifest, "WASIX portable runtime release"), - "WASIX portable runtime manifest", - ); - const seed = json( - requiredEntry(entries, WASIX_PORTABLE_RELEASE_MEMBERS.icuSeedManifest, "WASIX portable runtime release"), - "WASIX ICU cluster-seed manifest", - ); - const data = seed.icu; - const closure = outer["cluster-seeds"]?.icu; - if ( - outer["format-version"] !== 2 - || seed.schema !== "oliphaunt-cluster-seed-v1" - || seed.artifactRole !== "cluster-seed-icu" - || seed.catalogProfile !== "icu" - || data?.artifactRole !== "icu-data" - || data?.dataVersion !== ICU_DATA_VERSION - || data?.dataForm !== ICU_DATA_FORM - || closure?.manifest !== "cluster-seeds/icu.json" - ) { - fail("WASIX portable runtime does not contain the canonical ICU identity metadata"); - } - const dataTreeSha256 = checkedDigest(data.dataTreeSha256, "WASIX ICU data tree identity"); - if (closure["icu-data-tree-sha256"] !== dataTreeSha256) { - fail("WASIX portable runtime manifest and ICU cluster-seed manifest disagree on the ICU data tree identity"); - } - return Object.freeze({ - dataVersion: data.dataVersion, - dataForm: data.dataForm, - dataTreeSha256, - }); -} - -export function assertCrossFamilyIcuDataIdentity(nativeIdentity, wasixIdentity) { - for (const field of ["dataVersion", "dataForm", "dataTreeSha256"]) { - if (nativeIdentity[field] !== wasixIdentity[field]) { - fail( - `native and WASIX ICU ${field} differ: ` - + `${JSON.stringify(nativeIdentity[field])} != ${JSON.stringify(wasixIdentity[field])}`, - ); - } - } - return nativeIdentity; -} - -export function checkCrossFamilyIcuData(nativeReleaseAssets, wasixReleaseAssets) { - const nativeArchive = onlyAsset( - path.resolve(nativeReleaseAssets), - /^liboliphaunt-[0-9][0-9A-Za-z.+-]*-icu-data[.]tar[.]gz$/u, - "native", - ); - const wasixArchive = onlyAsset( - path.resolve(wasixReleaseAssets), - /^liboliphaunt-wasix-[0-9][0-9A-Za-z.+-]*-runtime-portable[.]tar[.]zst$/u, - "WASIX", - ); - const nativeEntries = readPortableArchiveEntries(nativeArchive); - const nativeIdentity = parseNativeIcuDataIdentity( - requiredEntry(nativeEntries, "manifest.properties", "native ICU data release"), - "native ICU data release manifest", - ); - return assertCrossFamilyIcuDataIdentity(nativeIdentity, wasixIcuDataIdentity(wasixArchive)); -} - -if (import.meta.main) { - const [nativeReleaseAssets, wasixReleaseAssets] = process.argv.slice(2); - if (!nativeReleaseAssets || !wasixReleaseAssets || process.argv.length !== 4) { - fail(`usage: ${TOOL} NATIVE_RELEASE_ASSET_DIR WASIX_RELEASE_ASSET_DIR`); - } - const identity = checkCrossFamilyIcuData(nativeReleaseAssets, wasixReleaseAssets); - process.stdout.write( - `ICU data identity matches across native and WASIX: ${identity.dataVersion}/${identity.dataForm}/${identity.dataTreeSha256}\n`, - ); -} diff --git a/tools/release/check-cross-family-icu-data.test.mjs b/tools/release/check-cross-family-icu-data.test.mjs deleted file mode 100644 index 1c114abd3..000000000 --- a/tools/release/check-cross-family-icu-data.test.mjs +++ /dev/null @@ -1,103 +0,0 @@ -import { afterEach, expect, test } from "bun:test"; -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { checkCrossFamilyIcuData } from "./check-cross-family-icu-data.mjs"; -import { nativeIcuDataManifestFromRows } from "./native-icu-data-contract.mjs"; -import { canonicalGzipSync, releaseZstdCompressSync } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { WASIX_PORTABLE_RELEASE_MEMBERS } from "./wasix-runtime-npm-contract.mjs"; - -const scratch = []; - -afterEach(() => { - for (const directory of scratch.splice(0)) rmSync(directory, { recursive: true, force: true }); -}); - -function temporaryRoot() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-cross-family-icu-")); - scratch.push(root); - return root; -} - -function writeMember(root, member, bytes) { - const file = path.join(root, ...member.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, bytes); -} - -function archive(root, output, compression) { - const tar = createDeterministicTar(root, ".", { - fail(message) { - throw new Error(message); - }, - fixedFileMode: 0o644, - }); - writeFileSync(output, compression(tar)); -} - -function fixture({ wasixTreeSha256 } = {}) { - const root = temporaryRoot(); - const nativeAssets = path.join(root, "native-assets"); - const wasixAssets = path.join(root, "wasix-assets"); - const nativeStage = path.join(root, "native-stage"); - const wasixStage = path.join(root, "wasix-stage"); - mkdirSync(nativeAssets); - mkdirSync(wasixAssets); - - const nativeManifest = nativeIcuDataManifestFromRows([ - { path: "icudt76l/root.res", bytes: Buffer.from("same logical ICU tree\n") }, - ]); - const nativeTreeSha256 = /^icuDataTreeSha256=([0-9a-f]{64})$/mu.exec(nativeManifest.toString("utf8"))[1]; - const tree = wasixTreeSha256 ?? nativeTreeSha256; - writeMember(nativeStage, "manifest.properties", nativeManifest); - archive( - nativeStage, - path.join(nativeAssets, "liboliphaunt-1.2.3-icu-data.tar.gz"), - canonicalGzipSync, - ); - - writeMember(wasixStage, WASIX_PORTABLE_RELEASE_MEMBERS.manifest, `${JSON.stringify({ - "format-version": 2, - "cluster-seeds": { - icu: { - manifest: "cluster-seeds/icu.json", - "icu-data-tree-sha256": tree, - }, - }, - })}\n`); - writeMember(wasixStage, WASIX_PORTABLE_RELEASE_MEMBERS.icuSeedManifest, `${JSON.stringify({ - schema: "oliphaunt-cluster-seed-v1", - artifactRole: "cluster-seed-icu", - catalogProfile: "icu", - icu: { - artifactRole: "icu-data", - dataVersion: "76.1", - dataForm: "files-le", - dataTreeSha256: tree, - }, - })}\n`); - archive( - wasixStage, - path.join(wasixAssets, "liboliphaunt-wasix-4.5.6-runtime-portable.tar.zst"), - releaseZstdCompressSync, - ); - return { nativeAssets, wasixAssets, nativeTreeSha256 }; -} - -test("accepts one canonical logical ICU identity across native and WASIX releases", () => { - const value = fixture(); - expect(checkCrossFamilyIcuData(value.nativeAssets, value.wasixAssets)).toEqual({ - dataVersion: "76.1", - dataForm: "files-le", - dataTreeSha256: value.nativeTreeSha256, - }); -}); - -test("rejects internally valid native and WASIX releases with different ICU trees", () => { - const value = fixture({ wasixTreeSha256: "f".repeat(64) }); - expect(() => checkCrossFamilyIcuData(value.nativeAssets, value.wasixAssets)).toThrow( - /native and WASIX ICU dataTreeSha256 differ/u, - ); -}); diff --git a/tools/release/check-github-release-assets.sh b/tools/release/check-github-release-assets.sh new file mode 100644 index 000000000..34e77a4ff --- /dev/null +++ b/tools/release/check-github-release-assets.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +bash tools/release/with-release-tags.sh bash tools/dev/bun.sh tools/release/check_github_release_assets.mts "$@" diff --git a/tools/release/check-icu-npm-cocoapods-consumer.sh b/tools/release/check-icu-npm-cocoapods-consumer.sh deleted file mode 100755 index c4248235a..000000000 --- a/tools/release/check-icu-npm-cocoapods-consumer.sh +++ /dev/null @@ -1,342 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -tool="check-icu-npm-cocoapods-consumer.sh" - -fail() { - echo "$tool: $*" >&2 - exit 1 -} - -require() { - command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1" -} - -[ "$#" -eq 1 ] || fail "usage: tools/release/$tool LIBOLIPHAUNT_ICU_DATA.tar.gz" -[ "$(uname -s)" = "Darwin" ] || fail "this regression check requires macOS" - -for command in cp find git grep mktemp pod ruby sed sort tail tar uniq xcodebuild; do - require "$command" -done - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || - fail "must run inside the Oliphaunt git checkout" -podspec_source="$root/src/runtimes/liboliphaunt/native/icu-npm/OliphauntICU.podspec" -[ -f "$podspec_source" ] || fail "missing source podspec: $podspec_source" - -archive_input="$1" -[ -f "$archive_input" ] || fail "missing ICU data archive: $archive_input" -archive_directory="$(cd "$(dirname "$archive_input")" && pwd -P)" -archive="$archive_directory/$(basename "$archive_input")" -case "$archive" in - *.tar.gz) - ;; - *) - fail "ICU data archive must end in .tar.gz: $archive" - ;; -esac - -scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-icu-cocoapods.XXXXXX")" -scratch="$(cd "$scratch" && pwd -P)" -cleanup() { - rm -rf "$scratch" -} -trap cleanup EXIT -trap 'exit 130' INT -trap 'exit 143' TERM HUP - -work="$scratch/consumer" -pod_root="$work/OliphauntICU" -bundle_root="$pod_root/OliphauntICU.bundle" -source_icu="$bundle_root/share/icu" -derived_data="$scratch/DerivedData" -pod_log="$scratch/pod-install.log" -xcode_log="$scratch/xcodebuild.log" -members="$scratch/archive-members.txt" -mkdir -p "$bundle_root" "$work" "$scratch/cocoapods-home" "$scratch/swiftpm-cache" - -if ! tar -tzf "$archive" >"$members"; then - fail "cannot list ICU data archive: $archive" -fi -[ -s "$members" ] || fail "ICU data archive is empty: $archive" - -while IFS= read -r member || [ -n "$member" ]; do - normalized="${member#./}" - case "$normalized" in - ""|.) - continue - ;; - /*) - fail "ICU data archive contains an absolute member: $member" - ;; - esac - case "/$normalized/" in - */../*) - fail "ICU data archive contains a parent traversal: $member" - ;; - esac -done <"$members" - -duplicate_members="$(LC_ALL=C sort "$members" | uniq -d)" -[ -z "$duplicate_members" ] || - fail "ICU data archive contains duplicate members: $(printf '%s\n' "$duplicate_members" | sed -n '1,5p')" -grep -Eq '^(\./)?share/icu/' "$members" || - fail "ICU data archive has no share/icu tree: $archive" - -cp "$podspec_source" "$pod_root/OliphauntICU.podspec" -grep -Fq "s.resources = 'OliphauntICU.bundle'" "$pod_root/OliphauntICU.podspec" || - fail "source podspec must install OliphauntICU.bundle through s.resources" -if grep -Fq "resource_bundles" "$pod_root/OliphauntICU.podspec"; then - fail "source podspec must not generate a CocoaPods resource-bundle target" -fi - -if ! tar -xzf "$archive" -C "$bundle_root" share/icu; then - fail "cannot extract share/icu from $archive" -fi -[ -d "$source_icu" ] || fail "staged pod has no OliphauntICU.bundle/share/icu" -source_symlink="$(find "$source_icu" -type l -print -quit)" -[ -z "$source_symlink" ] || fail "staged ICU data contains a symbolic link: $source_symlink" -source_file="$(find "$source_icu" -type f -path '*/icudt*' -print -quit)" -[ -n "$source_file" ] || fail "staged ICU data has no icudt* payload files" - -ruby - "$source_icu" <<'RUBY' -root = ARGV.fetch(0) -resources = Dir.glob(File.join(root, "**", "*.res")).select { |file| File.file?(file) } -duplicates = resources.group_by { |file| File.basename(file) }.values.select { |files| files.length > 1 } -abort "ICU payload has no repeated .res basename and does not exercise the CocoaPods regression" if duplicates.empty? -puts "ICU collision stimulus: #{duplicates.length} repeated .res basename groups" -RUBY - -ruby - "$work" <<'RUBY' -require "fileutils" -require "xcodeproj" - -root = File.expand_path(ARGV.fetch(0)) -project_path = File.join(root, "OliphauntICUSmoke.xcodeproj") - -File.write(File.join(root, "main.c"), <<~SOURCE) - int main(int argc, char **argv) { - return argc > 0 && argv[0] != 0 ? 0 : 1; - } -SOURCE - -File.write(File.join(root, "Info.plist"), <<~PLIST) - - - - - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - - -PLIST - -File.write(File.join(root, "Podfile"), <<~PODFILE) - platform :ios, '17.0' - install! 'cocoapods', :deterministic_uuids => true - - target 'OliphauntICUSmoke' do - pod 'OliphauntICU', :path => 'OliphauntICU' - end -PODFILE - -project = Xcodeproj::Project.new(project_path) -project.root_object.attributes["LastUpgradeCheck"] = "1600" -target = project.new_target(:application, "OliphauntICUSmoke", :ios, "17.0") -source = project.main_group.new_file("main.c") -target.add_file_references([source]) - -target.build_configurations.each do |configuration| - settings = configuration.build_settings - settings["CODE_SIGNING_ALLOWED"] = "NO" - settings["CODE_SIGNING_REQUIRED"] = "NO" - settings["CURRENT_PROJECT_VERSION"] = "1" - settings["ENABLE_USER_SCRIPT_SANDBOXING"] = "NO" - settings["GENERATE_INFOPLIST_FILE"] = "NO" - settings["INFOPLIST_FILE"] = "Info.plist" - settings["IPHONEOS_DEPLOYMENT_TARGET"] = "17.0" - settings["MARKETING_VERSION"] = "1.0" - settings["PRODUCT_BUNDLE_IDENTIFIER"] = "dev.oliphaunt.icu-cocoapods-smoke" - settings["PRODUCT_NAME"] = "$(TARGET_NAME)" - settings["SUPPORTED_PLATFORMS"] = "iphonesimulator" - settings["TARGETED_DEVICE_FAMILY"] = "1,2" -end - -project.save -scheme = Xcodeproj::XCScheme.new -scheme.add_build_target(target) -scheme.set_launch_target(target) -scheme.save_as(project_path, "OliphauntICUSmoke", true) -RUBY - -if ! ( - cd "$work" - env \ - COCOAPODS_DISABLE_STATS=true \ - COCOAPODS_SKIP_UPDATE_MESSAGE=true \ - CP_HOME_DIR="$scratch/cocoapods-home" \ - LANG=en_US.UTF-8 \ - LC_ALL=en_US.UTF-8 \ - pod install -) >"$pod_log" 2>&1; then - tail -200 "$pod_log" >&2 - fail "CocoaPods installation failed" -fi - -if grep -Eq 'Generated duplicate UUIDs|Multiple commands produce' "$pod_log"; then - tail -200 "$pod_log" >&2 - fail "CocoaPods generated a duplicate resource graph" -fi - -lockfile="$work/Podfile.lock" -[ -f "$lockfile" ] || fail "CocoaPods did not create Podfile.lock" -grep -Fq 'EXTERNAL SOURCES:' "$lockfile" || fail "Podfile.lock does not record the local ICU pod" -grep -Fq ':path: OliphauntICU' "$lockfile" || fail "Podfile.lock did not resolve ICU from its local path" -if grep -Fq 'SPEC REPOS:' "$lockfile"; then - fail "standalone CocoaPods consumer unexpectedly resolved a specs repository" -fi -if grep -Eq 'https?://|:git:' "$lockfile"; then - fail "standalone CocoaPods consumer resolved a network dependency" -fi - -pods_project="$work/Pods/Pods.xcodeproj" -pods_pbxproj="$pods_project/project.pbxproj" -[ -f "$pods_pbxproj" ] || fail "CocoaPods did not create Pods.xcodeproj" - -ruby - "$pods_project" <<'RUBY' -require "xcodeproj" - -project = Xcodeproj::Project.open(ARGV.fetch(0)) -bundle_targets = project.targets.select do |target| - target.name.include?("OliphauntICU") && - target.respond_to?(:product_type) && - target.product_type == "com.apple.product-type.bundle" -end -unless bundle_targets.empty? - abort "generated ICU resource-bundle targets: #{bundle_targets.map(&:name).join(', ')}" -end - -resource_files = project.files.each_with_object([]) do |reference, files| - path = reference.path.to_s - files << path if File.extname(path) == ".res" -end -unless resource_files.empty? - abort "individual ICU .res file references: #{resource_files.first(10).join(', ')}" -end - -bundle_references = project.files.select { |reference| reference.path.to_s == "OliphauntICU.bundle" } -unless bundle_references.length == 1 - abort "expected one opaque OliphauntICU.bundle reference, found #{bundle_references.length}" -end -RUBY - -if grep -Fq '.res' "$pods_pbxproj"; then - fail "Pods project contains individual .res resource entries" -fi -if grep -Fq 'OliphauntICU-OliphauntICU' "$pods_pbxproj"; then - fail "Pods project contains a generated OliphauntICU resource-bundle target" -fi -generated_bundle_metadata="$(find "$work/Pods" -type f -name 'ResourceBundle-*OliphauntICU*' -print -quit)" -[ -z "$generated_bundle_metadata" ] || - fail "CocoaPods generated resource-bundle target metadata: $generated_bundle_metadata" - -resources_script="$work/Pods/Target Support Files/Pods-OliphauntICUSmoke/Pods-OliphauntICUSmoke-resources.sh" -[ -f "$resources_script" ] || fail "CocoaPods did not generate its aggregate resource script" -bundle_install_count="$(grep -F 'install_resource ' "$resources_script" | grep -F -c 'OliphauntICU.bundle' || true)" -[ "$bundle_install_count" -gt 0 ] || fail "aggregate resource script does not install OliphauntICU.bundle" -invalid_icu_install="$(grep -F 'install_resource ' "$resources_script" | grep -F 'OliphauntICU' | grep -Fv 'OliphauntICU.bundle' || true)" -[ -z "$invalid_icu_install" ] || fail "aggregate resource script installs non-bundle ICU resources" - -machine_arch="$(uname -m)" -case "$machine_arch" in - arm64|x86_64) - ;; - *) - fail "unsupported macOS runner architecture: $machine_arch" - ;; -esac - -if ! xcodebuild \ - -workspace "$work/OliphauntICUSmoke.xcworkspace" \ - -scheme OliphauntICUSmoke \ - -configuration Release \ - -sdk iphonesimulator \ - -destination 'generic/platform=iOS Simulator' \ - -derivedDataPath "$derived_data" \ - -clonedSourcePackagesDirPath "$scratch/swiftpm-cache" \ - -disableAutomaticPackageResolution \ - -skipPackageUpdates \ - ARCHS="$machine_arch" \ - ONLY_ACTIVE_ARCH=YES \ - CODE_SIGNING_ALLOWED=NO \ - CODE_SIGNING_REQUIRED=NO \ - CODE_SIGN_IDENTITY= \ - COMPILER_INDEX_STORE_ENABLE=NO \ - build >"$xcode_log" 2>&1; then - grep -n -E 'error:|Multiple commands produce|BUILD FAILED|The following build commands failed' "$xcode_log" | tail -160 >&2 || - tail -200 "$xcode_log" >&2 - fail "xcodebuild failed" -fi - -if grep -Fq 'Multiple commands produce' "$xcode_log"; then - tail -200 "$xcode_log" >&2 - fail "xcodebuild reported duplicate resource outputs" -fi -grep -Fq '** BUILD SUCCEEDED **' "$xcode_log" || fail "xcodebuild did not report success" - -app="$derived_data/Build/Products/Release-iphonesimulator/OliphauntICUSmoke.app" -built_icu="$app/OliphauntICU.bundle/share/icu" -[ -d "$app" ] || fail "xcodebuild did not produce the expected app: $app" -[ -d "$built_icu" ] || fail "built app is missing OliphauntICU.bundle/share/icu" - -ruby - "$source_icu" "$built_icu" <<'RUBY' -require "digest" - -def tree_manifest(root) - Dir.chdir(root) do - Dir.glob("**/*", File::FNM_DOTMATCH).sort.each_with_object([]) do |relative, entries| - next if relative.split(File::SEPARATOR).any? { |part| part == "." || part == ".." } - - stat = File.lstat(relative) - if stat.directory? - entries << ["directory", relative] - elsif stat.file? - entries << ["file", relative, stat.size, Digest::SHA256.file(relative).hexdigest] - else - abort "unsupported ICU tree entry: #{File.join(root, relative)}" - end - end - end -end - -source_root, built_root = ARGV -source = tree_manifest(source_root) -built = tree_manifest(built_root) -unless source == built - source_only = source - built - built_only = built - source - warn "source-only ICU entries: #{source_only.first(10).inspect}" unless source_only.empty? - warn "built-only ICU entries: #{built_only.first(10).inspect}" unless built_only.empty? - abort "built ICU tree does not byte-match the staged source tree" -end - -files = source.count { |entry| entry[0] == "file" } -bytes = source.sum { |entry| entry[0] == "file" ? entry[2] : 0 } -puts "Built ICU bundle matches source: #{files} files, #{bytes} bytes" -RUBY - -echo "$tool: PASS ($archive)" diff --git a/tools/release/check-liboliphaunt-release-assets.mjs b/tools/release/check-liboliphaunt-release-assets.mjs deleted file mode 100644 index 4e7d5a60e..000000000 --- a/tools/release/check-liboliphaunt-release-assets.mjs +++ /dev/null @@ -1,747 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import { - chmodSync, - existsSync, - mkdirSync, - mkdtempSync, - readdirSync, - readFileSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { spawnSync } from "node:child_process"; - -import { - ROOT, - allArtifactTargets, - compareText, - currentProductVersion, -} from "./release-artifact-targets.mjs"; -import { inspectPlatformBinaryTree } from "./platform-binary-contract.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - assertReleaseNoticesInArchive, - releaseNoticeRows, -} from "./release-notices.mjs"; -import { SNOWBALL_STOPWORD_LANGUAGES } from "./optimize_native_runtime_payload.mjs"; -import { - parseProperties, - validateNativeClusterSeedManifest, -} from "./native-cluster-seed-contract.mjs"; -import { validateNativeIcuDataManifestRows } from "./native-icu-data-contract.mjs"; -import { NATIVE_RUNTIME_CARRIER_SCHEMA } from "./native-runtime-carrier-contract.mjs"; -import { - compareNativeMobileAbiReceipts, - NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN, -} from "./native-mobile-abi-contract.mjs"; - -const PREFIX = "check-liboliphaunt-release-assets.mjs"; -const PRODUCT = "liboliphaunt-native"; -const EMPTY_STATIC_REGISTRY_MANIFEST = [ - "packageLayout=oliphaunt-static-registry-v1", - "abiVersion=1", - "state=not-required", - "source=", - "registeredExtensions=", - "pendingExtensions=", - "nativeModuleStems=", - "modules=", - "archiveTargets=", - "dependencyArchiveTargets=", - "dependencyArchives=", - "", -].join("\n"); - -function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(1); -} - -function rel(file) { - const relative = path.relative(ROOT, file); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - return file; - } - return relative.split(path.sep).join("/"); -} - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function requireFile(file, description) { - let stat; - try { - stat = statSync(file); - } catch { - fail(`missing ${description}: ${file}`); - } - if (!stat.isFile()) { - fail(`${description} is not a file: ${file}`); - } - if (stat.size <= 0) { - fail(`${description} is empty: ${file}`); - } -} - -function parseChecksumFile(file) { - const checksums = new Map(); - for (const rawLine of readFileSync(file, "utf8").split(/\r?\n/u)) { - if (!rawLine.trim()) { - continue; - } - const parts = rawLine.trim().split(/\s+/u); - if (parts.length !== 2) { - fail(`malformed checksum line in ${file}: ${JSON.stringify(rawLine)}`); - } - const [digest, filename] = parts; - if (!filename.startsWith("./")) { - fail(`checksum path must be relative './name': ${filename}`); - } - checksums.set(filename.slice(2), digest); - } - return checksums; -} - -function validateChecksums(assetDir, checksumFile) { - const checksums = parseChecksumFile(checksumFile); - const expectedAssets = readdirSync(assetDir) - .map((name) => path.join(assetDir, name)) - .filter((file) => statSync(file).isFile() && path.extname(file) !== ".sha256") - .sort(compareText); - if (expectedAssets.length === 0) { - fail(`no release assets found in ${assetDir}`); - } - const assetNames = new Set(expectedAssets.map((file) => path.basename(file))); - for (const asset of expectedAssets) { - const recorded = checksums.get(path.basename(asset)); - if (!recorded) { - fail(`checksum file does not cover release asset: ${path.basename(asset)}`); - } - const actual = sha256(asset); - if (recorded !== actual) { - fail(`checksum mismatch for ${path.basename(asset)}: expected ${recorded}, got ${actual}`); - } - } - const extra = [...checksums.keys()].filter((name) => !assetNames.has(name)).sort(compareText); - if (extra.length > 0) { - fail(`checksum file contains entries for missing assets: ${extra.join(", ")}`); - } -} - -function generatedExtensionMetadata() { - const metadataPath = path.join(ROOT, "src/extensions/generated/sdk/extensions.json"); - let metadata; - try { - metadata = JSON.parse(readFileSync(metadataPath, "utf8")); - } catch (error) { - fail(`read generated Rust SDK extension metadata ${metadataPath}: ${error.message}`); - } - if (!Array.isArray(metadata.extensions)) { - fail(`${metadataPath} must define an extensions array`); - } - const expected = new Map(); - for (const [index, row] of metadata.extensions.entries()) { - if (row === null || Array.isArray(row) || typeof row !== "object") { - fail(`${metadataPath} extensions[${index}] must be an object`); - } - const sqlName = row["sql-name"]; - if (typeof sqlName !== "string" || !sqlName) { - fail(`${metadataPath} extensions[${index}] must define sql-name`); - } - const dataFiles = row["runtime-share-data-files"]; - if (!Array.isArray(dataFiles) || !dataFiles.every((value) => typeof value === "string")) { - fail(`${metadataPath} extension ${sqlName} must define runtime-share-data-files`); - } - const nativeModuleStem = row["native-module-stem"]; - if (nativeModuleStem !== null && nativeModuleStem !== undefined && typeof nativeModuleStem !== "string") { - fail(`${metadataPath} extension ${sqlName} native-module-stem must be a string or null`); - } - expected.set(sqlName, { - createsExtension: row["creates-extension"] === true, - dataFiles, - dataFilesTsv: dataFiles.length > 0 ? dataFiles.join(",") : "-", - nativeModuleStem, - }); - } - return expected; -} - -export function canonicalTarEntryMarkerError(name, type) { - if (name === "." || name === "./") return null; - const directoryMarker = name.endsWith("/"); - if (type === "5" && !directoryMarker) { - return `directory member must use a trailing slash: ${JSON.stringify(name)}`; - } - if ((type === "" || type === "0") && directoryMarker) { - return `regular-file member must not use a trailing slash: ${JSON.stringify(name)}`; - } - return null; -} - -export function canonicalEmptyStaticRegistryManifestError(text) { - if (text === EMPTY_STATIC_REGISTRY_MANIFEST) { - return null; - } - return "standard runtime static-registry manifest must be the canonical empty oliphaunt-static-registry-v1 manifest"; -} - -function readArchiveEntries(file) { - try { - return readPortableArchiveEntries(file); - } catch (error) { - fail(`${file} is not a strict portable release archive: ${error.message}`); - } -} - -function archiveMemberNames(file) { - return new Set(readArchiveEntries(file).keys()); -} - -function releaseNoticeNamespaceNames(profile) { - const names = new Set(); - for (const { member } of releaseNoticeRows({ profile })) { - names.add(member); - const parts = member.split("/"); - for (let index = 1; index < parts.length; index += 1) { - names.add(parts.slice(0, index).join("/")); - } - } - return names; -} - -function archiveText(entries, file, memberName) { - const entry = entries.get(memberName); - if (!entry) { - fail(`${file} is missing ${memberName}`); - } - if (!entry.isFile) { - fail(`${file} member ${memberName} is not a regular file`); - } - try { - const data = typeof entry.data === "function" ? entry.data() : entry.data; - return Buffer.from(data).toString("utf8"); - } catch (error) { - fail(`${file} member ${memberName} is not readable UTF-8: ${error.message}`); - } -} - -function archiveTreeBytes(entries, file, prefix) { - let total = 0; - for (const [name, entry] of entries) { - if (!name.startsWith(prefix) || entry.isDirectory) { - continue; - } - if (!entry.isFile) { - fail(`${file} member ${name} under ${prefix} must be a regular file`); - } - const data = typeof entry.data === "function" ? entry.data() : entry.data; - total += Buffer.byteLength(data); - } - return total; -} - -function archiveLogicalTreeRows(entries, file, prefix) { - const rows = []; - for (const [name, entry] of entries) { - if (!name.startsWith(prefix) || entry.isDirectory) continue; - if (!entry.isFile) fail(`${file} member ${name} under ${prefix} must be a regular file`); - rows.push({ - path: name.slice(prefix.length), - bytes: typeof entry.data === "function" ? entry.data() : entry.data, - }); - } - if (rows.length === 0) fail(`${file} contains no files under ${prefix}`); - return rows; -} - -function expectedRuntimeResourcePackageSizeReport(entries, file) { - const runtimeBytes = archiveTreeBytes(entries, file, "oliphaunt/runtime/files/"); - const standardSeedBytes = archiveTreeBytes(entries, file, "oliphaunt/cluster-seed/files/"); - const icuSeedBytes = archiveTreeBytes(entries, file, "oliphaunt/cluster-seed-icu/files/"); - const staticRegistryBytes = archiveTreeBytes(entries, file, "oliphaunt/static-registry/"); - return [ - "kind\tid\textensions\tfiles\tbytes", - `package\ttotal\t-\t-\t${runtimeBytes + standardSeedBytes + icuSeedBytes + staticRegistryBytes}`, - `package\truntime\t-\t-\t${runtimeBytes}`, - `package\tcluster-seed\t-\t-\t${standardSeedBytes}`, - `package\tcluster-seed-icu\t-\t-\t${icuSeedBytes}`, - `package\tstatic-registry\t-\t-\t${staticRegistryBytes}`, - "extensions\tselected\t-\t-\t0", - "", - ].join("\n"); -} - -function validateMobileAbiProofEntries(entries, file, domain, prefix = "oliphaunt/") { - const targets = NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[domain]; - if (targets === undefined) fail(`${file} uses unsupported mobile ABI domain ${domain}`); - const proofPrefix = `${prefix}provenance/native-mobile-abi/`; - try { - compareNativeMobileAbiReceipts( - domain, - targets.map((target) => { - const member = `${proofPrefix}${target}.properties`; - return { label: `${file} ${member}`, text: archiveText(entries, file, member) }; - }), - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} - -function extractArchive(file, destination) { - rmSync(destination, { recursive: true, force: true }); - mkdirSync(destination, { recursive: true }); - for (const [name, entry] of readArchiveEntries(file)) { - if (entry.isDirectory) { - continue; - } - if (!entry.isFile) { - fail(`${file} member ${name} must be a regular file`); - } - const output = path.join(destination, ...name.split("/")); - mkdirSync(path.dirname(output), { recursive: true }); - const data = typeof entry.data === "function" ? entry.data() : entry.data; - writeFileSync(output, data); - if (entry.mode) { - chmodSync(output, entry.mode & 0o777); - } - } -} - -function validateNativeRuntimeCarrierEntries( - entries, - file, - { prefix = "", target, icuDataTreeSha256 }, -) { - const member = (relative) => `${prefix}${relative}`; - for (const required of [ - "manifest.properties", - "cluster-seed/manifest.properties", - "cluster-seed/files/PG_VERSION", - "cluster-seed/files/global/pg_control", - "cluster-seed-icu/manifest.properties", - "cluster-seed-icu/files/PG_VERSION", - "cluster-seed-icu/files/global/pg_control", - ]) { - if (!entries.get(member(required))?.isFile) { - fail(`${file} is missing native runtime closure member ${member(required)}`); - } - } - for (const profile of ["cluster-seed", "cluster-seed-icu"]) { - const filesPrefix = member(`${profile}/files/`); - const pgVersion = entries.get(`${filesPrefix}PG_VERSION`); - const control = entries.get(`${filesPrefix}global/pg_control`); - const pgWal = entries.get(`${filesPrefix}pg_wal/`) ?? entries.get(`${filesPrefix}pg_wal`); - if (pgVersion?.isSymbolicLink - || archiveText(entries, file, `${filesPrefix}PG_VERSION`).trim() !== "18") { - fail(`${file} has invalid ${filesPrefix}PG_VERSION`); - } - if (control?.isSymbolicLink || control?.size <= 0) { - fail(`${file} has invalid ${filesPrefix}global/pg_control`); - } - if (!pgWal?.isDirectory || pgWal.isSymbolicLink) { - fail(`${file} is missing real directory ${filesPrefix}pg_wal/`); - } - for (const [name, entry] of entries) { - if (!name.startsWith(filesPrefix)) continue; - if (entry.isSymbolicLink || (!entry.isFile && !entry.isDirectory)) { - fail(`${file} cluster seed member ${name} must be a regular file or directory`); - } - } - for (const transient of ["postmaster.pid", "postmaster.opts"]) { - if (entries.has(`${filesPrefix}${transient}`)) { - fail(`${file} cluster seed contains transient ${filesPrefix}${transient}`); - } - } - } - try { - const receipt = parseProperties( - Buffer.from(archiveText(entries, file, member("manifest.properties"))), - `${file} ${member("manifest.properties")}`, - ); - if (receipt.size !== 4 - || receipt.get("schema") !== NATIVE_RUNTIME_CARRIER_SCHEMA - || receipt.get("clusterSeedTarget") !== target - || receipt.get("clusterSeedRelativePath") !== "cluster-seed" - || receipt.get("icuClusterSeedRelativePath") !== "cluster-seed-icu") { - fail(`${file} has an invalid ${target} native runtime carrier receipt`); - } - validateNativeClusterSeedManifest( - Buffer.from(archiveText(entries, file, member("cluster-seed/manifest.properties"))), - "standard", - { label: `${file} ${member("cluster-seed/manifest.properties")}`, target }, - ); - validateNativeClusterSeedManifest( - Buffer.from(archiveText(entries, file, member("cluster-seed-icu/manifest.properties"))), - "icu", - { - label: `${file} ${member("cluster-seed-icu/manifest.properties")}`, - target, - icuDataTreeSha256, - }, - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} - -async function validateNativeTargetArtifact( - file, - target, - { requireRuntime, toolSet, icuDataTreeSha256 }, -) { - if (requireRuntime && toolSet === "runtime") { - const entries = readPortableArchiveEntries(file); - validateNativeRuntimeCarrierEntries(entries, file, { target, icuDataTreeSha256 }); - if (target === "windows-x64-msvc") { - for (const directory of ["bin", "runtime/bin"]) { - for (const name of ["icudt76.dll", "icuin76.dll", "icuuc76.dll"]) { - const member = `${directory}/${name}`; - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${file} ICU-enabled Windows runtime is missing ${member}`); - } - } - } - } - } - const temp = mkdtempSync(path.join(tmpdir(), `oliphaunt-native-${target}-`)); - try { - const extracted = path.join(temp, "payload"); - extractArchive(file, extracted); - const command = [ - "tools/release/optimize_native_runtime_payload.mjs", - extracted, - "--target", - target, - "--tool-set", - toolSet, - "--check", - ]; - if (!requireRuntime) { - command.push("--allow-missing-runtime"); - } - await inspectPlatformBinaryTree(extracted, { - target, - requireWindowsRuntimeImportLibrary: - target === "windows-x64-msvc" && toolSet === "runtime", - windowsVcRuntimeProfile: - target === "windows-x64-msvc" && toolSet === "runtime" ? "provider" : undefined, - }); - const result = spawnSync(process.execPath, command, { - cwd: ROOT, - stdio: "inherit", - }); - if (result.status !== 0) { - process.exit(result.status ?? 1); - } - } finally { - rmSync(temp, { recursive: true, force: true }); - } -} - -function assetName(target, version) { - return target.asset.replaceAll("{version}", version); -} - -async function validateNativeTargetArtifacts(assetDir, version, icuDataTreeSha256) { - const runtimeTargets = new Set( - allArtifactTargets({ - product: PRODUCT, - kind: "native-runtime", - surface: "rust-native-direct", - }).map((target) => target.target), - ); - for (const target of allArtifactTargets({ - product: PRODUCT, - kind: "native-runtime", - surface: "github-release", - })) { - await validateNativeTargetArtifact(path.join(assetDir, assetName(target, version)), target.target, { - requireRuntime: runtimeTargets.has(target.target), - toolSet: "runtime", - icuDataTreeSha256, - }); - } - for (const target of allArtifactTargets({ - product: PRODUCT, - kind: "native-tools", - surface: "github-release", - })) { - await validateNativeTargetArtifact(path.join(assetDir, assetName(target, version)), target.target, { - requireRuntime: true, - toolSet: "tools", - }); - } -} - -function validateRuntimeResourceArtifactContents( - file, - { target, icuDataTreeSha256, extensionMetadata }, -) { - const entries = readArchiveEntries(file); - const names = new Set(entries.keys()); - const runtimePrefix = "oliphaunt/runtime/files/"; - for (const requiredMember of [ - "oliphaunt/manifest.properties", - "oliphaunt/package-size.tsv", - "oliphaunt/runtime/manifest.properties", - "oliphaunt/static-registry/manifest.properties", - "oliphaunt/cluster-seed/manifest.properties", - "oliphaunt/cluster-seed/files/PG_VERSION", - "oliphaunt/cluster-seed/files/global/pg_control", - "oliphaunt/cluster-seed-icu/manifest.properties", - "oliphaunt/cluster-seed-icu/files/PG_VERSION", - "oliphaunt/cluster-seed-icu/files/global/pg_control", - ]) { - if (!names.has(requiredMember)) { - fail(`${file} must contain ${requiredMember}`); - } - } - if (!names.has(`${runtimePrefix}share/postgresql/README.release-fixture`) && ![...names].some((name) => name.startsWith(runtimePrefix))) { - fail(`${file} must contain an oliphaunt/runtime/files tree`); - } - if ([...names].some((name) => name.startsWith(`${runtimePrefix}share/icu/`))) { - fail(`${file} standard runtime must not contain ICU data under ${runtimePrefix}share/icu`); - } - for (const required of [ - `${runtimePrefix}share/postgresql/extension/plpgsql--1.0.sql`, - `${runtimePrefix}share/postgresql/extension/plpgsql.control`, - `${runtimePrefix}share/postgresql/snowball_create.sql`, - ...SNOWBALL_STOPWORD_LANGUAGES.map( - (language) => `${runtimePrefix}share/postgresql/tsearch_data/${language}.stop`, - ), - ]) { - const entry = entries.get(required); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${file} standard runtime is missing required core PostgreSQL resource ${required}`); - } - } - for (const [sqlName, metadata] of extensionMetadata) { - const control = `${runtimePrefix}share/postgresql/extension/${sqlName}.control`; - if (names.has(control)) { - fail(`${file} standard runtime must not contain optional extension control file ${control}`); - } - for (const dataFile of metadata.dataFiles) { - const dataPath = `${runtimePrefix}share/postgresql/${dataFile}`; - if (names.has(dataPath)) { - fail(`${file} standard runtime must not contain optional extension data file ${dataPath}`); - } - } - if (typeof metadata.nativeModuleStem === "string" && metadata.nativeModuleStem) { - for (const suffix of [".dylib", ".so", ".dll"]) { - const module = `${runtimePrefix}lib/postgresql/${metadata.nativeModuleStem}${suffix}`; - if (names.has(module)) { - fail(`${file} standard runtime must not contain optional extension module ${module}`); - } - } - } - } - - validateNativeRuntimeCarrierEntries(entries, file, { - prefix: "oliphaunt/", - target, - icuDataTreeSha256, - }); - validateMobileAbiProofEntries(entries, file, target); - - const staticRegistryManifest = archiveText( - entries, - file, - "oliphaunt/static-registry/manifest.properties", - ); - const staticRegistryError = canonicalEmptyStaticRegistryManifestError(staticRegistryManifest); - if (staticRegistryError !== null) { - fail(`${file} ${staticRegistryError}`); - } - - const embeddedPackageSize = archiveText(entries, file, "oliphaunt/package-size.tsv"); - const expectedPackageSize = expectedRuntimeResourcePackageSizeReport(entries, file); - if (embeddedPackageSize !== expectedPackageSize) { - fail(`${file} package-size report does not match the actual packaged resource bytes`); - } -} - -function validateIcuDataArtifactContents(file) { - assertReleaseNoticesInArchive(file, { profile: "native-icu-data" }); - const entries = readArchiveEntries(file); - const names = new Set(entries.keys()); - const icuEntries = [...names] - .filter((name) => { - if (!name.startsWith("share/icu/")) { - return false; - } - const parts = name.slice("share/icu/".length).split("/").filter(Boolean); - return parts.length > 0 && parts[0].startsWith("icudt"); - }) - .sort(compareText); - if (icuEntries.length === 0) { - fail(`${file} must contain ICU data files under share/icu/icudt*`); - } - let receipt; - try { - receipt = validateNativeIcuDataManifestRows( - Buffer.from(archiveText(entries, file, "manifest.properties")), - archiveLogicalTreeRows(entries, file, "share/icu/"), - `${file} manifest.properties`, - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - const icuDataBytes = archiveTreeBytes(entries, file, "share/icu/"); - const expectedSizeReport = [ - "kind\tid\textensions\tfiles\tbytes", - `package\ttotal\t-\t-\t${icuDataBytes}`, - `package\ticu-data\t-\t-\t${icuDataBytes}`, - "", - ].join("\n"); - if (archiveText(entries, file, "package-size.tsv") !== expectedSizeReport) { - fail(`${file} ICU package-size report does not match the actual data bytes`); - } - const legalNames = releaseNoticeNamespaceNames("native-icu-data"); - const unexpected = [...names] - .filter((name) => - name !== "." - && name !== "share" - && name !== "share/icu" - && !name.startsWith("share/icu/") - && name !== "manifest.properties" - && name !== "package-size.tsv" - && !legalNames.has(name)) - .sort(compareText); - if (unexpected.length > 0) { - fail(`${file} must contain only ICU data and its receipt, found: ${unexpected.slice(0, 5).join(", ")}`); - } - return receipt.icuDataTreeSha256; -} - -const RELEASE_NOTICE_OPTIONS_BY_KIND = new Map([ - ["native-runtime", Object.freeze({ profile: "native-runtime" })], - ["native-tools", Object.freeze({ profile: "native-tools" })], - [ - "apple-swiftpm-binary", - Object.freeze({ - profile: "native-runtime", - prefix: "liboliphaunt.xcframework", - }), - ], - ["runtime-resources", Object.freeze({ profile: "native-runtime-resources" })], - ["icu-data", Object.freeze({ profile: "native-icu-data" })], -]); - -export function assertLiboliphauntArtifactReleaseNotices(file, kind) { - const options = RELEASE_NOTICE_OPTIONS_BY_KIND.get(kind); - if (options === undefined) { - return false; - } - assertReleaseNoticesInArchive(file, options); - return true; -} - -function validateReleaseNoticeClosure(assetDir, version) { - for (const target of allArtifactTargets({ - product: PRODUCT, - surface: "github-release", - })) { - assertLiboliphauntArtifactReleaseNotices( - path.join(assetDir, assetName(target, version)), - target.kind, - ); - } -} - -function expectedGithubAssets(version) { - return allArtifactTargets({ - product: PRODUCT, - surface: "github-release", - }).map((target) => assetName(target, version)).sort(compareText); -} - -async function validate(assetDir) { - const version = await currentProductVersion(PRODUCT, PREFIX); - const metadata = generatedExtensionMetadata(); - const required = expectedGithubAssets(version); - const expected = new Set(required); - const actual = new Set(readdirSync(assetDir).filter((name) => statSync(path.join(assetDir, name)).isFile())); - const missing = [...expected].filter((name) => !actual.has(name)).sort(compareText); - if (missing.length > 0) { - fail(`liboliphaunt-native release asset directory is missing expected assets: ${missing.join(", ")}`); - } - const unexpected = [...actual].filter((name) => !expected.has(name)).sort(compareText); - if (unexpected.length > 0) { - fail(`liboliphaunt-native release asset directory contains unexpected assets: ${unexpected.join(", ")}`); - } - for (const filename of required) { - requireFile(path.join(assetDir, filename), `liboliphaunt release artifact ${filename}`); - } - validateReleaseNoticeClosure(assetDir, version); - const leakedExtensionAssets = [...actual] - .filter((name) => name.includes("extension") && !name.endsWith("-release-assets.sha256")) - .sort(compareText); - if (leakedExtensionAssets.length > 0) { - fail( - "liboliphaunt-native release assets must not include exact-extension artifacts; " + - `publish them through oliphaunt-extension-* products instead: ${leakedExtensionAssets.join(", ")}`, - ); - } - const icuDataTreeSha256 = validateIcuDataArtifactContents( - path.join(assetDir, `liboliphaunt-${version}-icu-data.tar.gz`), - ); - for (const target of ["ios-datum64", "android-datum64"]) { - validateRuntimeResourceArtifactContents( - path.join(assetDir, `liboliphaunt-${version}-runtime-resources-${target}.tar.gz`), - { target, icuDataTreeSha256, extensionMetadata: metadata }, - ); - } - for (const filename of [ - `liboliphaunt-${version}-ios-xcframework.tar.gz`, - `liboliphaunt-${version}-apple-spm-xcframework.zip`, - ]) { - const file = path.join(assetDir, filename); - const entries = readArchiveEntries(file); - for (const slice of ["ios-arm64", "ios-arm64-simulator"]) { - validateMobileAbiProofEntries( - entries, - file, - "ios-datum64", - `liboliphaunt.xcframework/${slice}/liboliphaunt.framework/Resources/oliphaunt/`, - ); - } - } - await validateNativeTargetArtifacts(assetDir, version, icuDataTreeSha256); - validateChecksums(assetDir, path.join(assetDir, `liboliphaunt-${version}-release-assets.sha256`)); -} - -function parseArgs(argv) { - const args = { - assetDir: path.join(ROOT, "target/liboliphaunt/release-assets"), - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--asset-dir") { - const value = argv[index + 1]; - if (!value) { - fail("--asset-dir requires a value"); - } - args.assetDir = path.resolve(ROOT, value); - index += 1; - } else { - fail(`unknown argument ${arg}`); - } - } - return args; -} - -if (import.meta.main) { - const args = parseArgs(Bun.argv.slice(2)); - if (!existsSync(args.assetDir) || !statSync(args.assetDir).isDirectory()) { - fail(`release asset directory does not exist: ${args.assetDir}`); - } - await validate(args.assetDir); - console.log(`liboliphaunt release assets validated: ${rel(args.assetDir)}`); -} diff --git a/tools/release/check-liboliphaunt-release-assets.test.mjs b/tools/release/check-liboliphaunt-release-assets.test.mjs deleted file mode 100644 index 4ec21a550..000000000 --- a/tools/release/check-liboliphaunt-release-assets.test.mjs +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { spawnSync } from "node:child_process"; -import test from "node:test"; - -import { - assertLiboliphauntArtifactReleaseNotices, - canonicalEmptyStaticRegistryManifestError, - canonicalTarEntryMarkerError, -} from "./check-liboliphaunt-release-assets.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); - -test("release archive validation requires canonical producer markers", () => { - assert.equal(canonicalTarEntryMarkerError(".", "5"), null); - assert.equal(canonicalTarEntryMarkerError("./", "5"), null); - assert.equal(canonicalTarEntryMarkerError("runtime/", "5"), null); - assert.equal(canonicalTarEntryMarkerError("runtime/manifest.properties", "0"), null); - assert.match(canonicalTarEntryMarkerError("runtime", "5"), /directory member must use a trailing slash/u); - assert.match(canonicalTarEntryMarkerError("runtime\/manifest.properties/", "0"), /regular-file member must not use a trailing slash/u); -}); - -test("standard runtime validation requires the exact current empty static-registry manifest", () => { - const canonical = [ - "packageLayout=oliphaunt-static-registry-v1", - "abiVersion=1", - "state=not-required", - "source=", - "registeredExtensions=", - "pendingExtensions=", - "nativeModuleStems=", - "modules=", - "archiveTargets=", - "dependencyArchiveTargets=", - "dependencyArchives=", - "", - ].join("\n"); - assert.equal(canonicalEmptyStaticRegistryManifestError(canonical), null); - assert.match( - canonicalEmptyStaticRegistryManifestError( - "schema=oliphaunt-static-registry-v1\nregistered=\npending=\n", - ), - /canonical empty oliphaunt-static-registry-v1 manifest/u, - ); -}); - -test("aggregate validation reads Apple notices from the canonical XCFramework member root", (t) => { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-apple-notice-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const framework = path.join(root, "liboliphaunt.xcframework"); - mkdirSync(framework); - writeFileSync(path.join(framework, "Info.plist"), "fixture\n"); - stageReleaseNotices(framework, { profile: "native-runtime" }); - const archive = path.join(root, "liboliphaunt-0.0.0-apple-spm-xcframework.zip"); - const result = spawnSync( - path.join(ROOT, "tools/dev/bun.sh"), - ["src/shared/artifact-packaging/archive-directory.mjs", "--keep-parent", framework, archive], - { cwd: ROOT, stdio: "inherit" }, - ); - assert.equal(result.status, 0, result.stderr); - assert.equal( - assertLiboliphauntArtifactReleaseNotices( - archive, - "apple-swiftpm-binary", - ), - true, - ); - - rmSync(path.join(framework, "LICENSE")); - const missingNoticeArchive = path.join(root, "missing-notice.zip"); - const missingNoticeResult = spawnSync( - path.join(ROOT, "tools/dev/bun.sh"), - [ - "src/shared/artifact-packaging/archive-directory.mjs", - "--keep-parent", - framework, - missingNoticeArchive, - ], - { cwd: ROOT, stdio: "inherit" }, - ); - assert.equal(missingNoticeResult.status, 0, missingNoticeResult.stderr); - assert.throws( - () => - assertLiboliphauntArtifactReleaseNotices( - missingNoticeArchive, - "apple-swiftpm-binary", - ), - /liboliphaunt[.]xcframework\/LICENSE/u, - ); -}); diff --git a/tools/release/check-liboliphaunt-wasix-release-assets.mjs b/tools/release/check-liboliphaunt-wasix-release-assets.mjs deleted file mode 100644 index 3899dfe10..000000000 --- a/tools/release/check-liboliphaunt-wasix-release-assets.mjs +++ /dev/null @@ -1,636 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import { - existsSync, - lstatSync, - readdirSync, - readFileSync, -} from "node:fs"; -import path from "node:path"; - -import { - ROOT, - compareText, - currentProductVersionSync, - expectedAssetRows, -} from "./release-artifact-targets.mjs"; -import { - assertReleaseNoticesInEntries, - releaseNoticeRows, -} from "./release-notices.mjs"; -import { - DEFAULT_PORTABLE_ARCHIVE_LIMITS, - decompressSingleZstdFrame, - portableMemberName, - readPortableArchiveEntries, - readPortableTarZstdBufferEntries, -} from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - AOT_TARGET_TRIPLES, - CORE_RUNTIME_ARCHIVE_FILES, -} from "./wasix-cargo-artifact-contract.mjs"; -import { assertCanonicalWasixAotManifest } from "./wasix-aot-manifest.mjs"; -import { WASIX_PORTABLE_RELEASE_MEMBERS } from "./wasix-runtime-npm-contract.mjs"; - -const TOOL = "check-liboliphaunt-wasix-release-assets.mjs"; -const PRODUCT = "liboliphaunt-wasix"; -const DEFAULT_ASSET_DIR = "target/oliphaunt-wasix/release-assets"; -const PORTABLE_RUNTIME_ARCHIVE_MEMBER = WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive; -const PORTABLE_MANIFEST_MEMBER = WASIX_PORTABLE_RELEASE_MEMBERS.manifest; -const SPLIT_TOOL_PAYLOAD_MEMBERS = new Set([ - "target/oliphaunt-wasix/assets/bin/pg_dump.wasix.wasm", - "target/oliphaunt-wasix/assets/bin/psql.wasix.wasm", -]); -const FORBIDDEN_PORTABLE_ASSET_MEMBERS = new Set([ - "target/oliphaunt-wasix/assets/bin/pg_ctl.wasix.wasm", -]); -const CORE_RUNTIME_MEMBERS = new Set(CORE_RUNTIME_ARCHIVE_FILES); -const FORBIDDEN_RUNTIME_MEMBERS = new Set([ - "oliphaunt/bin/pg_ctl", - "oliphaunt/bin/pg_dump", - "oliphaunt/bin/psql", -]); -const LOWER_SHA256 = /^[0-9a-f]{64}$/u; -const UTF8 = new TextDecoder("utf-8", { fatal: true }); - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function rel(file) { - const relative = path.relative(ROOT, String(file)); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - return String(file).split(path.sep).join("/"); - } - return relative.split(path.sep).join("/"); -} - -function isFile(file) { - try { - const metadata = lstatSync(file); - return metadata.isFile() && !metadata.isSymbolicLink(); - } catch { - return false; - } -} - -function isDirectory(file) { - try { - const metadata = lstatSync(file); - return metadata.isDirectory() && !metadata.isSymbolicLink(); - } catch { - return false; - } -} - -function sha256File(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function sha256Bytes(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function readArchiveJsonEntry(entries, member, archive) { - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${rel(archive)} must contain ${member} as one non-empty regular file`); - } - let data; - try { - data = UTF8.decode(entry.data()); - } catch { - fail(`${rel(archive)} ${member} is not valid UTF-8`); - } - try { - return JSON.parse(data); - } catch (error) { - fail(`${rel(archive)} ${member} is not valid JSON: ${error.message}`); - } -} - -function checkedSha256(value, context) { - if (typeof value !== "string" || !LOWER_SHA256.test(value)) { - throw new Error(`${context} must be a lowercase SHA-256 digest`); - } - return value; -} - -function checkedAotArtifactName(value, context) { - if ( - typeof value !== "string" - || value.length === 0 - || value !== value.trim() - || value !== value.normalize("NFC") - || Buffer.byteLength(value, "utf8") > 255 - || /[\u0000-\u001f\u007f/\\]/u.test(value) - ) { - throw new Error(`${context} name must be a normalized portable non-empty string`); - } - return value; -} - -export function assertWasixAotArtifactPayloads( - manifest, - { - context = "WASIX AOT manifest", - readArtifact, - maxRawBytes = DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntryBytes, - } = {}, -) { - if (!Array.isArray(manifest?.artifacts) || manifest.artifacts.length === 0) { - throw new Error(`${context} must contain a non-empty artifacts array`); - } - if (typeof readArtifact !== "function") { - throw new Error(`${context} requires an artifact byte reader`); - } - if (!Number.isSafeInteger(maxRawBytes) || maxRawBytes <= 0) { - throw new Error(`${context} maxRawBytes must be a positive safe integer`); - } - - const expectedKeys = [ - "compressed", - "module-sha256", - "name", - "path", - "raw-sha256", - "raw-size", - "sha256", - ]; - const names = new Set(); - const portableNames = new Map(); - const paths = new Set(); - const portablePaths = new Map(); - const rows = []; - for (const [index, artifact] of manifest.artifacts.entries()) { - const artifactContext = `${context} artifact[${index}]`; - if (artifact === null || Array.isArray(artifact) || typeof artifact !== "object") { - throw new Error(`${artifactContext} must be an object`); - } - const actualKeys = Object.keys(artifact).sort(compareText); - if (JSON.stringify(actualKeys) !== JSON.stringify(expectedKeys)) { - throw new Error( - `${artifactContext} metadata fields must be exactly ${JSON.stringify(expectedKeys)}, got ${JSON.stringify(actualKeys)}`, - ); - } - const name = checkedAotArtifactName(artifact.name, artifactContext); - if (names.has(name)) throw new Error(`${context} repeats AOT artifact name ${name}`); - names.add(name); - const portableName = name.toLowerCase(); - const priorName = portableNames.get(portableName); - if (priorName !== undefined) { - throw new Error(`${context} has case-colliding AOT artifact names ${priorName} and ${name}`); - } - portableNames.set(portableName, name); - - if (typeof artifact.path !== "string" || artifact.path.length === 0) { - throw new Error(`${artifactContext} path must be a non-empty string`); - } - let artifactPath; - try { - artifactPath = portableMemberName(artifact.path, "file", artifactContext); - } catch (error) { - throw new Error(error.message); - } - if (artifactPath !== artifact.path) { - throw new Error(`${artifactContext} path must already be normalized, got ${JSON.stringify(artifact.path)}`); - } - if (paths.has(artifactPath)) throw new Error(`${context} repeats AOT artifact path ${artifactPath}`); - paths.add(artifactPath); - const portablePath = artifactPath.toLowerCase(); - const priorPath = portablePaths.get(portablePath); - if (priorPath !== undefined) { - throw new Error(`${context} has case-colliding AOT artifact paths ${priorPath} and ${artifactPath}`); - } - portablePaths.set(portablePath, artifactPath); - - const sha256 = checkedSha256(artifact.sha256, `${artifactContext} sha256`); - const rawSha256 = checkedSha256(artifact["raw-sha256"], `${artifactContext} raw-sha256`); - checkedSha256(artifact["module-sha256"], `${artifactContext} module-sha256`); - const rawSize = artifact["raw-size"]; - if (!Number.isSafeInteger(rawSize) || rawSize <= 0 || rawSize > maxRawBytes) { - throw new Error(`${artifactContext} raw-size must be an integer in 1..${maxRawBytes}`); - } - if (typeof artifact.compressed !== "boolean") { - throw new Error(`${artifactContext} compressed must be a Boolean`); - } - if (artifact.compressed !== artifactPath.endsWith(".zst")) { - throw new Error(`${artifactContext} compressed metadata must match the .zst path suffix`); - } - - const value = readArtifact(artifactPath, artifact); - if (!Buffer.isBuffer(value) && !(value instanceof Uint8Array)) { - throw new Error(`${artifactContext} byte reader did not return a Buffer or Uint8Array`); - } - const bytes = Buffer.isBuffer(value) - ? value - : Buffer.from(value.buffer, value.byteOffset, value.byteLength); - if (bytes.length <= 0 || bytes.length > DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntryBytes) { - throw new Error(`${artifactContext} must reference a non-empty bounded regular file`); - } - const actualSha256 = sha256Bytes(bytes); - if (actualSha256 !== sha256) { - throw new Error(`${artifactContext} compressed SHA-256 mismatch: expected ${sha256}, got ${actualSha256}`); - } - const raw = artifact.compressed - ? decompressSingleZstdFrame(bytes, { - label: `${artifactContext} ${artifactPath}`, - maxInputBytes: DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntryBytes, - maxOutputBytes: rawSize, - }) - : bytes; - if (raw.length !== rawSize) { - throw new Error(`${artifactContext} raw-size mismatch: expected ${rawSize}, got ${raw.length}`); - } - const actualRawSha256 = sha256Bytes(raw); - if (actualRawSha256 !== rawSha256) { - throw new Error( - `${artifactContext} raw SHA-256 mismatch: expected ${rawSha256}, got ${actualRawSha256}`, - ); - } - rows.push(Object.freeze({ artifact, bytes, name, path: artifactPath, raw })); - } - return Object.freeze(rows); -} - -function expectedParentDirs(paths) { - const parents = new Set(); - for (const item of paths) { - const parts = item.split("/"); - for (let index = 1; index < parts.length; index += 1) { - parents.add(parts.slice(0, index).join("/")); - } - } - return parents; -} - -export function expectedReleaseNoticeFiles(profile, prefix = "") { - const marker = prefix ? `${prefix}/` : ""; - return new Set(releaseNoticeRows({ profile }).map((row) => `${marker}${row.member}`)); -} - -export function unexpectedTreeMembers(members, expectedMembers) { - const expected = new Set(expectedMembers); - for (const parent of expectedParentDirs(expected)) expected.add(parent); - return [...members] - .filter((member) => !expected.has(member)) - .sort(compareText); -} - -export function assertWasixReleaseNoticeEntries(entries, profile, prefix = "") { - return assertReleaseNoticesInEntries(entries, { prefix, profile }); -} - -function checkedWasixArchiveEntries(archive, profile, prefix = "") { - const entries = readPortableArchiveEntries(archive); - assertWasixReleaseNoticeEntries(entries, profile, prefix); - return entries; -} - -function parseChecksumManifest(file) { - const checksums = new Map(); - for (const [index, rawLine] of readFileSync(file, "utf8").split(/\r?\n/u).entries()) { - const line = rawLine.trim(); - if (!line) { - continue; - } - const match = line.match(/^([0-9a-f]{64}) \.\/([^/]+)$/u); - if (match === null) { - fail(`${rel(file)}:${index + 1} must use ' ./' entries`); - } - const [, sha256, assetName] = match; - if (checksums.has(assetName)) { - fail(`${rel(file)}:${index + 1} declares duplicate checksum for ${assetName}`); - } - checksums.set(assetName, sha256); - } - return checksums; -} - -function expectedAssetNames(version) { - return expectedAssetRows({ product: PRODUCT, version }, TOOL) - .map((row) => row.assetName) - .sort(compareText); -} - -export function exactRegularAssetDirectoryNames(assetDir) { - const entries = readdirSync(assetDir, { withFileTypes: true }); - const invalid = entries - .filter((entry) => !entry.isFile() || entry.isSymbolicLink()) - .map((entry) => entry.name) - .sort(compareText); - if (invalid.length > 0) { - fail( - `${PRODUCT} staged release asset directory must contain only regular non-symlink files: ${invalid.join(", ")}`, - ); - } - return entries.map((entry) => entry.name).sort(compareText); -} - -function validateAssetSet(assetDir, version) { - const expected = new Set(expectedAssetNames(version)); - const actual = new Set(exactRegularAssetDirectoryNames(assetDir)); - if (JSON.stringify([...actual].sort(compareText)) !== JSON.stringify([...expected].sort(compareText))) { - fail( - `${PRODUCT} staged release assets must match release metadata exactly: ` + - `expected=${JSON.stringify([...expected].sort(compareText))}, actual=${JSON.stringify([...actual].sort(compareText))}`, - ); - } - - const checksumName = `${PRODUCT}-${version}-release-assets.sha256`; - const checksumPath = path.join(assetDir, checksumName); - if (!isFile(checksumPath)) { - fail(`${PRODUCT} staged release assets are missing checksum manifest ${checksumName}`); - } - const checksums = parseChecksumManifest(checksumPath); - const expectedChecksumAssets = new Set([...expected].filter((name) => name !== checksumName)); - const actualChecksumAssets = new Set(checksums.keys()); - if ( - JSON.stringify([...actualChecksumAssets].sort(compareText)) !== - JSON.stringify([...expectedChecksumAssets].sort(compareText)) - ) { - fail( - `${PRODUCT} checksum manifest must cover release assets exactly: ` + - `expected=${JSON.stringify([...expectedChecksumAssets].sort(compareText))}, ` + - `actual=${JSON.stringify([...actualChecksumAssets].sort(compareText))}`, - ); - } - for (const [assetName, expectedSha] of checksums) { - const actualSha = sha256File(path.join(assetDir, assetName)); - if (actualSha !== expectedSha) { - fail(`${PRODUCT} release asset ${assetName} checksum mismatch`); - } - } -} - -export function validatePortableReleaseAsset(archive) { - const entries = checkedWasixArchiveEntries(archive, "wasix-runtime"); - const members = new Set(entries.keys()); - const extensionMembers = [...members] - .filter((member) => member.startsWith("target/oliphaunt-wasix/assets/extensions/")) - .sort(compareText); - if (extensionMembers.length > 0) { - fail(`${rel(archive)} must not contain extension payloads: ${extensionMembers.slice(0, 5).join(", ")}`); - } - const missingToolPayloads = [...SPLIT_TOOL_PAYLOAD_MEMBERS] - .filter((member) => { - const entry = entries.get(member); - return entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0; - }) - .sort(compareText); - if (missingToolPayloads.length > 0) { - fail(`${rel(archive)} must include split WASIX tool payloads for registry tools crates: ${missingToolPayloads.join(", ")}`); - } - const forbiddenPortableMembers = [...members] - .filter((member) => FORBIDDEN_PORTABLE_ASSET_MEMBERS.has(member)) - .sort(compareText); - if (forbiddenPortableMembers.length > 0) { - fail(`${rel(archive)} must not contain WASIX pg_ctl payloads: ${forbiddenPortableMembers.join(", ")}`); - } - - const manifest = readArchiveJsonEntry(entries, PORTABLE_MANIFEST_MEMBER, archive); - if (JSON.stringify(manifest.extensions) !== "[]") { - fail(`${rel(archive)} asset manifest must contain an empty extensions array`); - } - for (const key of ["pg-dump", "psql"]) { - if (Object.hasOwn(manifest, key)) { - fail(`${rel(archive)} asset manifest must not contain split WASIX tool entry ${key}`); - } - } - - const icuSidecarMembers = [...members] - .filter((member) => member === "target/oliphaunt-wasix/icu" || member.startsWith("target/oliphaunt-wasix/icu/")) - .sort(compareText); - if (icuSidecarMembers.length > 0) { - fail(`${rel(archive)} must not contain ICU data sidecar files: ${icuSidecarMembers.slice(0, 5).join(", ")}`); - } - - if (manifest.runtime === null || Array.isArray(manifest.runtime) || typeof manifest.runtime !== "object") { - fail(`${rel(archive)} asset manifest must contain runtime metadata`); - } - if (manifest.runtime.archive !== path.basename(PORTABLE_RUNTIME_ARCHIVE_MEMBER)) { - fail( - `${rel(archive)} asset manifest runtime.archive must be ${path.basename(PORTABLE_RUNTIME_ARCHIVE_MEMBER)}`, - ); - } - if (typeof manifest.runtime.sha256 !== "string" || !LOWER_SHA256.test(manifest.runtime.sha256)) { - fail(`${rel(archive)} asset manifest runtime.sha256 must be a lowercase SHA-256 digest`); - } - const runtimeEntry = entries.get(PORTABLE_RUNTIME_ARCHIVE_MEMBER); - if ( - runtimeEntry === undefined - || !runtimeEntry.isFile - || runtimeEntry.isSymbolicLink - || runtimeEntry.size <= 0 - ) { - fail(`${rel(archive)} must contain ${PORTABLE_RUNTIME_ARCHIVE_MEMBER} as one non-empty regular file`); - } - const runtimeArchive = runtimeEntry.data(); - const runtimeSha256 = sha256Bytes(runtimeArchive); - if (runtimeSha256 !== manifest.runtime.sha256) { - fail( - `${rel(archive)} asset manifest runtime.sha256 mismatch: ` + - `expected ${manifest.runtime.sha256}, got ${runtimeSha256}`, - ); - } - let runtimeEntries; - try { - runtimeEntries = readPortableTarZstdBufferEntries(runtimeArchive, { - label: `${rel(archive)} ${PORTABLE_RUNTIME_ARCHIVE_MEMBER}`, - }); - } catch (error) { - fail(error.message); - } - const runtimeMembers = new Set(runtimeEntries.keys()); - const missing = [...CORE_RUNTIME_MEMBERS] - .filter((member) => { - const entry = runtimeEntries.get(member); - return entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0; - }) - .sort(compareText); - if (missing.length > 0) { - fail(`${rel(archive)} must bundle the core WASIX runtime closure inside ${PORTABLE_RUNTIME_ARCHIVE_MEMBER}: ${missing.join(", ")}`); - } - const bundledIcu = [...runtimeMembers] - .filter((member) => member === "oliphaunt/share/icu" || member.startsWith("oliphaunt/share/icu/")) - .sort(compareText); - if (bundledIcu.length > 0) { - fail(`${rel(archive)} must not bundle ICU data inside ${PORTABLE_RUNTIME_ARCHIVE_MEMBER}: ${bundledIcu.slice(0, 5).join(", ")}`); - } - const bundledTools = [...runtimeMembers] - .filter((member) => FORBIDDEN_RUNTIME_MEMBERS.has(member)) - .sort(compareText); - if (bundledTools.length > 0) { - fail(`${rel(archive)} must not bundle standalone tools inside ${PORTABLE_RUNTIME_ARCHIVE_MEMBER}: ${bundledTools.join(", ")}`); - } -} - -export function validateIcuReleaseAsset(archive) { - const members = new Set(checkedWasixArchiveEntries(archive, "wasix-icu-data").keys()); - const icuRoot = "target/oliphaunt-wasix/icu/share/icu"; - const icuEntries = [...members] - .filter((member) => { - if (!member.startsWith(`${icuRoot}/`)) { - return false; - } - const relative = member.slice(`${icuRoot}/`.length).split("/").filter(Boolean); - return relative.length > 0 && relative[0].startsWith("icudt"); - }) - .sort(compareText); - if (icuEntries.length === 0) { - fail(`${rel(archive)} must contain ICU data files under ${icuRoot}`); - } - const expectedMembers = new Set([ - ...icuEntries, - ...expectedReleaseNoticeFiles("wasix-icu-data"), - ]); - const unexpected = unexpectedTreeMembers(members, expectedMembers); - if (unexpected.length > 0) { - fail(`${rel(archive)} contains unexpected non-ICU files: ${unexpected.slice(0, 5).join(", ")}`); - } -} - -export function validateAotReleaseAsset(archive, expectedTarget) { - const entries = checkedWasixArchiveEntries(archive, "wasix-aot", `target/oliphaunt-wasix/aot/${expectedTarget}`); - const members = new Set(entries.keys()); - const manifestMembers = [...members] - .filter((member) => member.startsWith("target/oliphaunt-wasix/aot/") && member.endsWith("/manifest.json")) - .sort(compareText); - if (manifestMembers.length !== 1) { - fail(`${rel(archive)} must contain exactly one AOT manifest, got ${JSON.stringify(manifestMembers)}`); - } - const manifestPath = manifestMembers[0]; - const aotRoot = manifestPath.slice(0, -"/manifest.json".length); - if (aotRoot !== `target/oliphaunt-wasix/aot/${expectedTarget}`) { - fail(`${rel(archive)} AOT archive root ${aotRoot} does not match target ${expectedTarget}`); - } - const manifest = readArchiveJsonEntry(entries, manifestPath, archive); - try { - assertCanonicalWasixAotManifest(manifest, { - context: `${rel(archive)} ${manifestPath}`, - expectedTarget, - }); - } catch (error) { - fail(error.message); - } - const expectedFiles = new Set([ - manifestPath, - ...expectedReleaseNoticeFiles("wasix-aot", aotRoot), - ]); - let artifactRows; - try { - artifactRows = assertWasixAotArtifactPayloads(manifest, { - context: `${rel(archive)} ${manifestPath}`, - readArtifact(artifactPath) { - const member = `${aotRoot}/${artifactPath}`; - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - throw new Error(`${rel(archive)} AOT artifact ${artifactPath} must be a non-empty regular file`); - } - return entry.data(); - }, - }); - } catch (error) { - fail(error.message); - } - for (const row of artifactRows) { - if (row.name.startsWith("extension:")) { - fail(`${rel(archive)} must not contain extension AOT artifact ${row.name}`); - } - expectedFiles.add(`${aotRoot}/${row.path}`); - } - - const unexpected = unexpectedTreeMembers(members, expectedFiles); - if (unexpected.length > 0 || [...expectedFiles].some((member) => !members.has(member))) { - fail( - `${rel(archive)} AOT file set mismatch: ` + - `expected ${JSON.stringify([...expectedFiles].sort(compareText))}, got ${JSON.stringify([...members].sort(compareText))}`, - ); - } -} - -function validateAssetContents(assetDir, version) { - validatePortableReleaseAsset(path.join(assetDir, `${PRODUCT}-${version}-runtime-portable.tar.zst`)); - validateIcuReleaseAsset(path.join(assetDir, `${PRODUCT}-${version}-icu-data.tar.zst`)); - const aotArchives = readdirSync(assetDir) - .filter((name) => name.startsWith(`${PRODUCT}-${version}-runtime-aot-`) && name.endsWith(".tar.zst")) - .map((name) => path.join(assetDir, name)) - .sort(compareText); - if (aotArchives.length === 0) { - fail(`${PRODUCT} release assets are missing target AOT archives`); - } - for (const archive of aotArchives) { - const name = path.basename(archive); - const prefix = `${PRODUCT}-${version}-runtime-aot-`; - const targetId = name.slice(prefix.length, -".tar.zst".length); - const expectedTarget = AOT_TARGET_TRIPLES[targetId]; - if (expectedTarget === undefined) { - fail(`${PRODUCT} release asset ${name} has unknown AOT target id ${targetId}`); - } - validateAotReleaseAsset(archive, expectedTarget); - } -} - -function usage() { - console.log(`usage: tools/release/check-liboliphaunt-wasix-release-assets.mjs [--asset-dir DIR] [--version VERSION] - -Validates staged liboliphaunt-wasix GitHub release assets, their checksum -manifest, and runtime/ICU/AOT archive boundaries. -`); -} - -function optionValue(argv, index) { - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) { - usage(); - fail(`${argv[index]} requires a value`); - } - return value; -} - -function parseArgs(argv) { - const args = { - assetDir: DEFAULT_ASSET_DIR, - version: null, - }; - for (let index = 0; index < argv.length;) { - const arg = argv[index]; - if (arg === "--asset-dir") { - args.assetDir = optionValue(argv, index); - index += 2; - } else if (arg === "--version") { - args.version = optionValue(argv, index); - index += 2; - } else if (arg === "-h" || arg === "--help") { - usage(); - process.exit(0); - } else { - usage(); - fail(`unknown argument ${arg}`); - } - } - return { - assetDir: path.isAbsolute(args.assetDir) ? args.assetDir : path.join(ROOT, args.assetDir), - version: args.version ?? currentProductVersionSync(PRODUCT, TOOL), - }; -} - -export function main(argv = Bun.argv.slice(2)) { - const args = parseArgs(argv); - if (!existsSync(args.assetDir) || !isDirectory(args.assetDir)) { - fail(`${PRODUCT} release asset directory does not exist: ${rel(args.assetDir)}`); - } - validateAssetSet(args.assetDir, args.version); - validateAssetContents(args.assetDir, args.version); - console.log(`validated ${PRODUCT} staged release assets under ${rel(args.assetDir)}`); -} - -if (import.meta.main) { - try { - main(); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - console.error(message.startsWith(`${TOOL}:`) ? message : `${TOOL}: ${message}`); - process.exitCode = 1; - } -} diff --git a/tools/release/check-liboliphaunt-wasix-release-assets.test.mjs b/tools/release/check-liboliphaunt-wasix-release-assets.test.mjs deleted file mode 100644 index 785478f22..000000000 --- a/tools/release/check-liboliphaunt-wasix-release-assets.test.mjs +++ /dev/null @@ -1,377 +0,0 @@ -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { - mkdtempSync, - mkdirSync, - readFileSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import test from "node:test"; -import { zstdCompressSync } from "node:zlib"; - -import { - exactRegularAssetDirectoryNames, - expectedReleaseNoticeFiles, - unexpectedTreeMembers, - validateAotReleaseAsset, - validateIcuReleaseAsset, - validatePortableReleaseAsset, -} from "./check-liboliphaunt-wasix-release-assets.mjs"; -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; -import { - AOT_TARGET_TRIPLES, - CORE_RUNTIME_ARCHIVE_FILES, -} from "./wasix-cargo-artifact-contract.mjs"; -import { canonicalWasixAotMetadata } from "./wasix-aot-manifest.mjs"; - -function fixture(t) { - const root = mkdtempSync(path.join(tmpdir(), "wasix-release-assets-check-test-")); - t.after(() => rmSync(root, { force: true, recursive: true })); - return root; -} - -function archiveStage(stage, archive, archiveRoot) { - const tar = createDeterministicTar(stage, archiveRoot, { - fail(message) { - throw new Error(message); - }, - fixedFileMode: 0o644, - }); - writeFileSync(archive, zstdCompressSync(tar)); - return archive; -} - -function stageIcuPayload(stage, profile = "wasix-icu-data") { - const payload = path.join( - stage, - "target/oliphaunt-wasix/icu/share/icu/icudt76l/data.res", - ); - mkdirSync(path.dirname(payload), { recursive: true }); - writeFileSync(payload, "icu-data\n"); - stageReleaseNotices(stage, { profile }); -} - -function stageAotPayload(stage, target, profile = "wasix-aot") { - const canonical = canonicalWasixAotMetadata(); - const raw = Buffer.from(`aot-payload:${target}\n`); - const compressed = zstdCompressSync(raw); - const manifest = { - "format-version": 1, - "source-lane": canonical.sourceLane, - "target-triple": target, - engine: canonical.engine, - "wasmer-version": canonical.wasmerVersion, - "wasmer-wasix-version": canonical.wasmerWasixVersion, - artifacts: [{ - name: "runtime:oliphaunt", - path: "runtime.bin.zst", - sha256: sha256(compressed), - "raw-sha256": sha256(raw), - "raw-size": raw.length, - "module-sha256": sha256(Buffer.from("runtime-module")), - compressed: true, - }], - }; - mkdirSync(stage, { recursive: true }); - writeFileSync(path.join(stage, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`); - writeFileSync(path.join(stage, "runtime.bin.zst"), compressed); - stageReleaseNotices(stage, { profile }); - return { - artifact: path.join(stage, "runtime.bin.zst"), - manifest: path.join(stage, "manifest.json"), - raw, - }; -} - -function sha256(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function stagePortablePayload(stage, runtimeBytes) { - const root = path.join(stage, "target/oliphaunt-wasix/assets"); - mkdirSync(path.join(root, "bin"), { recursive: true }); - writeFileSync(path.join(root, "bin/pg_dump.wasix.wasm"), "pg_dump\n"); - writeFileSync(path.join(root, "bin/psql.wasix.wasm"), "psql\n"); - writeFileSync(path.join(root, "oliphaunt.wasix.tar.zst"), runtimeBytes); - writeFileSync(path.join(root, "manifest.json"), `${JSON.stringify({ - "format-version": 1, - runtime: { - archive: "oliphaunt.wasix.tar.zst", - sha256: sha256(runtimeBytes), - }, - extensions: [], - }, null, 2)}\n`); - stageReleaseNotices(stage, { profile: "wasix-runtime" }); -} - -function runtimeArchive(root, name = "runtime.tar.zst") { - const stage = path.join(root, `${name}-stage`, "oliphaunt"); - for (const member of CORE_RUNTIME_ARCHIVE_FILES) { - const relative = member.replace(/^oliphaunt\//u, ""); - const file = path.join(stage, relative); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, `${relative}\n`); - } - return readFileSync(archiveStage(stage, path.join(root, name), "oliphaunt")); -} - -function withParents(files) { - const members = new Set(files); - for (const file of files) { - const parts = file.split("/"); - for (let index = 1; index < parts.length; index += 1) { - members.add(parts.slice(0, index).join("/")); - } - } - return members; -} - -test("ICU release assets admit only their exact canonical notice closure", () => { - const payload = "target/oliphaunt-wasix/icu/share/icu/76.1/icudt76l/data.bin"; - const notices = expectedReleaseNoticeFiles("wasix-icu-data"); - assert.deepEqual( - [...notices].sort(), - [ - "LICENSE", - "THIRD_PARTY_LICENSES/ICU-LICENSE", - "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", - "THIRD_PARTY_NOTICES.md", - "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", - ], - ); - - const expected = new Set([payload, ...notices]); - const members = withParents(expected); - assert.deepEqual(unexpectedTreeMembers(members, expected), []); - - members.add("THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt"); - assert.deepEqual( - unexpectedTreeMembers(members, expected), - ["THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt"], - ); -}); - -test("the release asset directory rejects entries hidden from a regular-file inventory", (t) => { - const root = fixture(t); - const asset = path.join(root, "asset.tar.zst"); - writeFileSync(asset, "asset\n"); - assert.deepEqual(exactRegularAssetDirectoryNames(root), ["asset.tar.zst"]); - - const directory = path.join(root, "unexpected-directory"); - mkdirSync(directory); - assert.throws( - () => exactRegularAssetDirectoryNames(root), - /only regular non-symlink files: unexpected-directory/u, - ); - rmSync(directory, { recursive: true }); - - if (process.platform !== "win32") { - symlinkSync(asset, path.join(root, "unexpected-link.tar.zst")); - assert.throws( - () => exactRegularAssetDirectoryNames(root), - /only regular non-symlink files: unexpected-link[.]tar[.]zst/u, - ); - } -}); - -test("every AOT target admits its prefixed canonical notice closure and rejects extras", () => { - for (const target of Object.values(AOT_TARGET_TRIPLES).sort()) { - const root = `target/oliphaunt-wasix/aot/${target}`; - const notices = expectedReleaseNoticeFiles("wasix-aot", root); - assert.ok(notices.has(`${root}/LICENSE`), target); - assert.ok(notices.has(`${root}/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT`), target); - assert.ok(notices.has(`${root}/THIRD_PARTY_LICENSES/ICU-LICENSE`), target); - - const expected = new Set([ - `${root}/manifest.json`, - `${root}/runtime.cwasm`, - ...notices, - ]); - const members = withParents(expected); - assert.deepEqual(unexpectedTreeMembers(members, expected), [], target); - - const extra = `${root}/THIRD_PARTY_LICENSES/Unknown-LICENSE`; - members.add(extra); - assert.deepEqual(unexpectedTreeMembers(members, expected), [extra], target); - } -}); - -test("the real ICU validator accepts producer-shaped notices and rejects extra or incomplete notices", (t) => { - const root = fixture(t); - const validStage = path.join(root, "icu-valid"); - stageIcuPayload(validStage); - const valid = archiveStage(validStage, path.join(root, "icu-valid.tar.zst"), "."); - assert.doesNotThrow(() => validateIcuReleaseAsset(valid)); - - const payloadExtraStage = path.join(root, "icu-payload-extra"); - stageIcuPayload(payloadExtraStage); - const payloadExtra = path.join( - payloadExtraStage, - "target/oliphaunt-wasix/icu/share/icu/config/mh-linux", - ); - mkdirSync(path.dirname(payloadExtra), { recursive: true }); - writeFileSync(payloadExtra, "build-only-config\n"); - const payloadExtraArchive = archiveStage( - payloadExtraStage, - path.join(root, "icu-payload-extra.tar.zst"), - ".", - ); - assert.throws( - () => validateIcuReleaseAsset(payloadExtraArchive), - /unexpected non-ICU files: target\/oliphaunt-wasix\/icu\/share\/icu\/config\/mh-linux/u, - ); - - const unknown = path.join(validStage, "THIRD_PARTY_LICENSES/Unknown-LICENSE"); - writeFileSync(unknown, "unknown\n"); - const extra = archiveStage(validStage, path.join(root, "icu-extra.tar.zst"), "."); - assert.throws( - () => validateIcuReleaseAsset(extra), - /unexpected release license member THIRD_PARTY_LICENSES\/Unknown-LICENSE/u, - ); - - const wrongStage = path.join(root, "icu-wrong-profile"); - stageIcuPayload(wrongStage, "code-facade"); - const wrong = archiveStage(wrongStage, path.join(root, "icu-wrong-profile.tar.zst"), "."); - assert.throws( - () => validateIcuReleaseAsset(wrong), - /missing regular release notice member THIRD_PARTY_NOTICES[.]oliphaunt-wasix[.]md/u, - ); -}); - -test("the real AOT validator accepts every target and rejects extra or incomplete notices", (t) => { - const root = fixture(t); - const targets = Object.values(AOT_TARGET_TRIPLES).sort(); - for (const [index, target] of targets.entries()) { - const stage = path.join(root, `aot-valid-${index}`); - const archiveRoot = `target/oliphaunt-wasix/aot/${target}`; - stageAotPayload(stage, target); - const archive = archiveStage(stage, path.join(root, `aot-valid-${index}.tar.zst`), archiveRoot); - assert.doesNotThrow(() => validateAotReleaseAsset(archive, target), target); - } - - const target = targets[0]; - const archiveRoot = `target/oliphaunt-wasix/aot/${target}`; - const extraStage = path.join(root, "aot-extra"); - stageAotPayload(extraStage, target); - writeFileSync(path.join(extraStage, "THIRD_PARTY_LICENSES/Unknown-LICENSE"), "unknown\n"); - const extra = archiveStage(extraStage, path.join(root, "aot-extra.tar.zst"), archiveRoot); - assert.throws( - () => validateAotReleaseAsset(extra, target), - new RegExp(`${archiveRoot}/THIRD_PARTY_LICENSES/Unknown-LICENSE`, "u"), - ); - - const wrongStage = path.join(root, "aot-wrong-profile"); - stageAotPayload(wrongStage, target, "code-facade"); - const wrong = archiveStage(wrongStage, path.join(root, "aot-wrong-profile.tar.zst"), archiveRoot); - assert.throws( - () => validateAotReleaseAsset(wrong, target), - new RegExp(`${archiveRoot}/THIRD_PARTY_NOTICES[.]oliphaunt-wasix[.]md`, "u"), - ); -}); - -test("the portable validator strictly checks nested runtime bytes and their manifest digest", (t) => { - const root = fixture(t); - const runtime = runtimeArchive(root); - const validStage = path.join(root, "portable-valid"); - stagePortablePayload(validStage, runtime); - const valid = archiveStage(validStage, path.join(root, "portable-valid.tar.zst"), "."); - assert.doesNotThrow(() => validatePortableReleaseAsset(valid)); - - const badDigestStage = path.join(root, "portable-bad-digest"); - stagePortablePayload(badDigestStage, runtime); - const manifestPath = path.join( - badDigestStage, - "target/oliphaunt-wasix/assets/manifest.json", - ); - const manifest = JSON.parse(readFileSync(manifestPath, "utf8")); - manifest.runtime.sha256 = "0".repeat(64); - writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); - const badDigest = archiveStage( - badDigestStage, - path.join(root, "portable-bad-digest.tar.zst"), - ".", - ); - assert.throws( - () => validatePortableReleaseAsset(badDigest), - /runtime[.]sha256 mismatch/u, - ); - - const concatenatedStage = path.join(root, "portable-concatenated"); - stagePortablePayload(concatenatedStage, Buffer.concat([runtime, runtime])); - const concatenated = archiveStage( - concatenatedStage, - path.join(root, "portable-concatenated.tar.zst"), - ".", - ); - assert.throws( - () => validatePortableReleaseAsset(concatenated), - /trailing data or multiple Zstandard frames/u, - ); -}); - -test("the AOT validator rejects duplicate metadata, tampering, and non-canonical zstd payloads", (t) => { - const root = fixture(t); - const target = Object.values(AOT_TARGET_TRIPLES).sort()[0]; - const archiveRoot = `target/oliphaunt-wasix/aot/${target}`; - - function rejected(name, mutate, pattern) { - const stage = path.join(root, name); - const fixtureData = stageAotPayload(stage, target); - const manifest = JSON.parse(readFileSync(fixtureData.manifest, "utf8")); - mutate({ ...fixtureData, manifest }); - writeFileSync(fixtureData.manifest, `${JSON.stringify(manifest, null, 2)}\n`); - const archive = archiveStage(stage, path.join(root, `${name}.tar.zst`), archiveRoot); - assert.throws(() => validateAotReleaseAsset(archive, target), pattern, name); - } - - rejected("duplicate-name", ({ manifest }) => { - manifest.artifacts.push({ ...manifest.artifacts[0], path: "second.bin.zst" }); - }, /repeats AOT artifact name/u); - - rejected("duplicate-path", ({ manifest }) => { - manifest.artifacts.push({ ...manifest.artifacts[0], name: "runtime-support:other" }); - }, /repeats AOT artifact path/u); - - rejected("unnormalized-path", ({ manifest }) => { - manifest.artifacts[0].path = "./runtime.bin.zst"; - }, /path must already be normalized/u); - - rejected("tampered-compressed", ({ artifact }) => { - const bytes = Buffer.from(readFileSync(artifact)); - bytes[bytes.length - 1] ^= 1; - writeFileSync(artifact, bytes); - }, /compressed SHA-256 mismatch/u); - - rejected("concatenated-zstd", ({ artifact, manifest }) => { - const bytes = readFileSync(artifact); - const concatenated = Buffer.concat([bytes, bytes]); - writeFileSync(artifact, concatenated); - manifest.artifacts[0].sha256 = sha256(concatenated); - }, /trailing data or multiple Zstandard frames/u); - - rejected("wrong-raw-size", ({ manifest }) => { - manifest.artifacts[0]["raw-size"] += 1; - }, /bounded readable Zstandard stream|raw-size mismatch/u); - - rejected("wrong-raw-digest", ({ manifest }) => { - manifest.artifacts[0]["raw-sha256"] = "0".repeat(64); - }, /raw SHA-256 mismatch/u); - - rejected("malformed-compressed", ({ manifest }) => { - manifest.artifacts[0].compressed = "true"; - }, /compressed must be a Boolean/u); - - rejected("extra-metadata", ({ manifest }) => { - manifest.artifacts[0].unexpected = true; - }, /metadata fields must be exactly/u); - - rejected("empty-artifact", ({ artifact, manifest }) => { - writeFileSync(artifact, Buffer.alloc(0)); - manifest.artifacts[0].sha256 = sha256(Buffer.alloc(0)); - }, /non-empty regular file/u); -}); diff --git a/tools/release/check-native-helper-aggregate-assets.mjs b/tools/release/check-native-helper-aggregate-assets.mjs deleted file mode 100644 index 0de861d9c..000000000 --- a/tools/release/check-native-helper-aggregate-assets.mjs +++ /dev/null @@ -1,261 +0,0 @@ -#!/usr/bin/env bun -import { readdirSync } from "node:fs"; -import path from "node:path"; - -import { - ROOT, - artifactTargets, - compareText, - currentProductVersionSync, - expectedAssets, -} from "./release-artifact-targets.mjs"; -import { run } from "./release-cli-utils.mjs"; - -const TOOL = "check-native-helper-aggregate-assets.mjs"; -const BROKER_PRODUCT = "oliphaunt-broker"; -const NODE_DIRECT_PRODUCT = "oliphaunt-node-direct"; -const WASIX_NAPI_PRODUCT = "oliphaunt-wasix-napi"; - -function fail(message, exitCode = 1) { - console.error(`${TOOL}: ${message}`); - process.exit(exitCode); -} - -function safeNpmPackageFilenamePrefix(packageName) { - return packageName.replace(/^@/u, "").replaceAll("/", "-"); -} - -function expectedOptionalNpmPackageNames(product, kind, version, label) { - return artifactTargets(product, kind, TOOL) - .map((target) => { - if (typeof target.npmPackage !== "string" || target.npmPackage.length === 0) { - throw new Error(`${target.id} must declare its ${label} npm package`); - } - return `${safeNpmPackageFilenamePrefix(target.npmPackage)}-${version}.tgz`; - }) - .sort(compareText); -} - -export function expectedNodeDirectNpmPackageNames(version) { - return expectedOptionalNpmPackageNames( - NODE_DIRECT_PRODUCT, - "node-direct-addon", - version, - "Node direct", - ); -} - -export function expectedWasixNapiNpmPackageNames(version) { - return expectedOptionalNpmPackageNames( - WASIX_NAPI_PRODUCT, - "wasix-napi-addon", - version, - "WASIX Node-API", - ); -} - -export function assertExactFilenames(actual, expected, label) { - const actualSorted = [...actual].sort(compareText); - const expectedSorted = [...expected].sort(compareText); - if ( - new Set(actualSorted).size !== actualSorted.length - || JSON.stringify(actualSorted) !== JSON.stringify(expectedSorted) - ) { - throw new Error( - `${label} must be exact: expected=${JSON.stringify(expectedSorted)}, actual=${JSON.stringify(actualSorted)}`, - ); - } -} - -export function exactRegularDirectoryFilenames(directory, label) { - let entries; - try { - entries = readdirSync(directory, { withFileTypes: true }); - } catch (error) { - throw new Error(`cannot inspect ${label} ${directory}: ${error.message}`); - } - const invalid = entries - .filter((entry) => !entry.isFile() || entry.isSymbolicLink()) - .map((entry) => entry.name) - .sort(compareText); - if (invalid.length > 0) { - throw new Error(`${label} must contain only regular non-symlink files: ${invalid.join(", ")}`); - } - return entries.map((entry) => entry.name).sort(compareText); -} - -function requireExactAssetDirectory(product, kind, assetDir, version) { - try { - assertExactFilenames( - exactRegularDirectoryFilenames(assetDir, `${product} aggregate asset directory`), - expectedAssets(product, kind, version, TOOL), - `${product} aggregate asset directory`, - ); - } catch (error) { - fail(error.message); - } -} - -function requirePreChecksumAssetDirectory(product, kind, assetDir, version) { - const expected = expectedAssets(product, kind, version, TOOL); - const payloads = expected.filter((name) => !name.endsWith(".sha256")); - const checksum = expected.filter((name) => name.endsWith(".sha256")); - let actual; - try { - actual = exactRegularDirectoryFilenames( - assetDir, - `${product} aggregate asset directory`, - ); - const accepted = [payloads, [...payloads, ...checksum]]; - if (!accepted.some((candidate) => { - const sorted = [...candidate].sort(compareText); - return JSON.stringify(actual) === JSON.stringify(sorted); - })) { - throw new Error( - `${product} aggregate asset directory must contain the exact target payload set, with at most the replaceable checksum manifest: actual=${JSON.stringify(actual)}`, - ); - } - } catch (error) { - fail(error.message); - } -} - -function parseArgs(argv) { - const args = { - assetDir: null, - npmPackageDir: null, - product: null, - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--asset-dir") { - args.assetDir = argv[index + 1] ?? fail("--asset-dir requires a value", 2); - index += 1; - } else if (arg === "--npm-package-dir") { - args.npmPackageDir = argv[index + 1] ?? fail("--npm-package-dir requires a value", 2); - index += 1; - } else if (arg === "--product") { - args.product = argv[index + 1] ?? fail("--product requires a value", 2); - index += 1; - } else if (arg === "--help" || arg === "-h") { - console.log( - `usage: tools/release/${TOOL} --product <${BROKER_PRODUCT}|${NODE_DIRECT_PRODUCT}|${WASIX_NAPI_PRODUCT}> ` - + "[--asset-dir DIR] [--npm-package-dir DIR]", - ); - process.exit(0); - } else { - fail(`unknown argument ${arg}`, 2); - } - } - if (![BROKER_PRODUCT, NODE_DIRECT_PRODUCT, WASIX_NAPI_PRODUCT].includes(args.product)) { - fail(`--product must be ${BROKER_PRODUCT}, ${NODE_DIRECT_PRODUCT}, or ${WASIX_NAPI_PRODUCT}`, 2); - } - return args; -} - -function resolveDir(value, fallback) { - return path.resolve(value ?? fallback); -} - -function rewriteChecksums(product, assetDir, version) { - const stem = product === BROKER_PRODUCT - ? "oliphaunt-broker" - : product === NODE_DIRECT_PRODUCT - ? "oliphaunt-node-direct" - : "oliphaunt-wasix-napi"; - const patterns = [`${stem}-*.tar.gz`, `${stem}-*.zip`]; - const command = [ - process.execPath, - "tools/release/write_checksum_manifest.mjs", - "--asset-dir", - assetDir, - "--output", - `${product}-${version}-release-assets.sha256`, - ]; - for (const pattern of patterns) command.push("--pattern", pattern); - run(TOOL, command); -} - -function optionalNpmPackages(npmPackageDir, expected, label) { - let names; - try { - names = exactRegularDirectoryFilenames( - npmPackageDir, - `staged ${label} optional npm package directory`, - ); - } catch (error) { - fail(error.message); - } - try { - assertExactFilenames( - names, - expected, - `staged ${label} optional npm packages`, - ); - } catch (error) { - fail(error.message); - } - return names.map((name) => path.join(npmPackageDir, name)); -} - -export function main(argv = Bun.argv.slice(2)) { - const args = parseArgs(argv); - const version = currentProductVersionSync(args.product, TOOL); - if (args.product === BROKER_PRODUCT) { - const assetDir = resolveDir( - args.assetDir, - process.env.OLIPHAUNT_BROKER_RELEASE_ASSETS - ?? path.join(ROOT, "target/oliphaunt-broker/release-assets"), - ); - requirePreChecksumAssetDirectory(args.product, "broker-helper", assetDir, version); - rewriteChecksums(args.product, assetDir, version); - requireExactAssetDirectory(args.product, "broker-helper", assetDir, version); - run(TOOL, [ - process.execPath, - "tools/release/check-broker-release-assets.mjs", - "--asset-dir", - assetDir, - ]); - return; - } - - const isWasixNapi = args.product === WASIX_NAPI_PRODUCT; - const outputRoot = isWasixNapi ? "target/oliphaunt-wasix-napi" : "target/oliphaunt-node-direct"; - const kind = isWasixNapi ? "wasix-napi-addon" : "node-direct-addon"; - const label = isWasixNapi ? "WASIX Node-API" : "Node direct"; - const assetDir = resolveDir( - args.assetDir, - (isWasixNapi - ? process.env.OLIPHAUNT_WASIX_NAPI_ASSET_OUT_DIR - : process.env.OLIPHAUNT_NODE_ADDON_ASSET_OUT_DIR) - ?? path.join(ROOT, outputRoot, "release-assets"), - ); - const npmPackageDir = resolveDir( - args.npmPackageDir, - (isWasixNapi - ? process.env.OLIPHAUNT_WASIX_NAPI_NPM_PACKAGE_OUT_DIR - : process.env.OLIPHAUNT_NODE_ADDON_NPM_PACKAGE_OUT_DIR) - ?? path.join(ROOT, outputRoot, "npm-packages"), - ); - requirePreChecksumAssetDirectory(args.product, kind, assetDir, version); - rewriteChecksums(args.product, assetDir, version); - requireExactAssetDirectory(args.product, kind, assetDir, version); - const npmPackages = optionalNpmPackages( - npmPackageDir, - isWasixNapi - ? expectedWasixNapiNpmPackageNames(version) - : expectedNodeDirectNpmPackageNames(version), - label, - ); - run(TOOL, [ - process.execPath, - isWasixNapi - ? "tools/release/check-wasix-napi-release-assets.mjs" - : "tools/release/check-node-direct-release-assets.mjs", - "--asset-dir", - assetDir, - ...npmPackages.flatMap((npmPackage) => ["--npm-package", npmPackage]), - ]); -} - -if (import.meta.main) main(); diff --git a/tools/release/check-native-helper-aggregate-assets.test.mjs b/tools/release/check-native-helper-aggregate-assets.test.mjs deleted file mode 100644 index acbed892d..000000000 --- a/tools/release/check-native-helper-aggregate-assets.test.mjs +++ /dev/null @@ -1,72 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { - mkdirSync, - mkdtempSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { - assertExactFilenames, - exactRegularDirectoryFilenames, - expectedNodeDirectNpmPackageNames, - expectedWasixNapiNpmPackageNames, -} from "./check-native-helper-aggregate-assets.mjs"; - -const scratch = []; - -afterEach(() => { - for (const directory of scratch.splice(0)) { - rmSync(directory, { force: true, recursive: true }); - } -}); - -describe("native helper aggregate release assets", () => { - test("derives the exact Node direct optional npm carrier set", () => { - expect(expectedNodeDirectNpmPackageNames("1.2.3")).toEqual([ - "oliphaunt-node-direct-darwin-arm64-1.2.3.tgz", - "oliphaunt-node-direct-linux-arm64-gnu-1.2.3.tgz", - "oliphaunt-node-direct-linux-x64-gnu-1.2.3.tgz", - "oliphaunt-node-direct-win32-x64-msvc-1.2.3.tgz", - ]); - }); - - test("derives the exact WASIX Node-API optional npm carrier set", () => { - expect(expectedWasixNapiNpmPackageNames("1.2.3")).toEqual([ - "oliphaunt-wasix-napi-darwin-arm64-1.2.3.tgz", - "oliphaunt-wasix-napi-linux-arm64-gnu-1.2.3.tgz", - "oliphaunt-wasix-napi-linux-x64-gnu-1.2.3.tgz", - "oliphaunt-wasix-napi-win32-x64-msvc-1.2.3.tgz", - ]); - }); - - test("accepts only an exact, duplicate-free carrier filename set", () => { - const expected = expectedNodeDirectNpmPackageNames("1.2.3"); - expect(() => assertExactFilenames([...expected].reverse(), expected, "Node carriers")).not.toThrow(); - expect(() => assertExactFilenames(expected.slice(1), expected, "Node carriers")) - .toThrow(/must be exact/u); - expect(() => assertExactFilenames([...expected, expected[0]], expected, "Node carriers")) - .toThrow(/must be exact/u); - expect(() => assertExactFilenames([...expected, "unexpected.tgz"], expected, "Node carriers")) - .toThrow(/must be exact/u); - }); - - test("rejects non-file and symlink entries instead of hiding them from closure checks", () => { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-native-helper-closure-")); - scratch.push(root); - writeFileSync(path.join(root, "carrier.tgz"), "carrier"); - expect(exactRegularDirectoryFilenames(root, "carrier directory")).toEqual(["carrier.tgz"]); - - mkdirSync(path.join(root, "unexpected-directory")); - expect(() => exactRegularDirectoryFilenames(root, "carrier directory")) - .toThrow(/only regular non-symlink files: unexpected-directory/u); - rmSync(path.join(root, "unexpected-directory"), { recursive: true }); - - symlinkSync(path.join(root, "carrier.tgz"), path.join(root, "unexpected-link.tgz")); - expect(() => exactRegularDirectoryFilenames(root, "carrier directory")) - .toThrow(/only regular non-symlink files: unexpected-link[.]tgz/u); - }); -}); diff --git a/tools/release/check-node-direct-release-assets.mjs b/tools/release/check-node-direct-release-assets.mjs deleted file mode 100644 index 5659e7d23..000000000 --- a/tools/release/check-node-direct-release-assets.mjs +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/env bun -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { - assertFileExists, - checksumManifest, - readArchiveEntries, - sha256, -} from "./release-asset-validation.mjs"; -import { - ROOT, - artifactTargets, - compareText, - currentProductVersion, - expectedAssets, - fail, -} from "./release-artifact-targets.mjs"; -import { inspectPlatformBinaryEntries } from "./platform-binary-contract.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - assertReleaseNoticesInEntries, - releaseProfilePackageLicense, -} from "./release-notices.mjs"; - -const PREFIX = "check-node-direct-release-assets.mjs"; -const PRODUCT = "oliphaunt-node-direct"; -const KIND = "node-direct-addon"; -const NOTICE_OPTIONS = Object.freeze({ profile: "source-sdk" }); -const NOTICE_MEMBERS = Object.freeze(["LICENSE", "THIRD_PARTY_NOTICES.md"]); -const PACKAGE_LICENSE = releaseProfilePackageLicense("source-sdk").spdx; - -function parseArgs(argv) { - const args = { - assetDir: path.join(ROOT, "target/oliphaunt-node-direct/release-assets"), - allowPartial: false, - npmPackages: [], - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--asset-dir") { - const value = argv[index + 1]; - if (!value) { - fail(PREFIX, "--asset-dir requires a value"); - } - args.assetDir = path.resolve(value); - index += 1; - } else if (arg === "--allow-partial") { - args.allowPartial = true; - } else if (arg === "--npm-package") { - const value = argv[index + 1]; - if (!value) { - fail(PREFIX, "--npm-package requires a value"); - } - args.npmPackages.push(path.resolve(value)); - index += 1; - } else { - fail(PREFIX, `unknown argument ${arg}`); - } - } - return args; -} - -export function assertNodeDirectReleaseNoticeEntries(entries, { prefix = "", label = "Node direct archive" } = {}) { - return assertReleaseNoticesInEntries(entries, { - ...NOTICE_OPTIONS, - prefix, - label, - }); -} - -function archiveJson(entries, member, label) { - const entry = entries.get(member); - if (!entry?.isFile || entry.isSymbolicLink) { - throw new Error(`${label} is missing regular member ${member}`); - } - if ((entry.mode & 0o777) !== 0o644) { - throw new Error(`${label} member ${member} must have mode 0644`); - } - try { - return JSON.parse(Buffer.from(entry.data()).toString("utf8")); - } catch (cause) { - throw new Error(`${label} member ${member} must contain valid JSON: ${cause.message}`); - } -} - -export function assertNodeDirectNpmArchive(file, targets, version) { - const label = path.basename(file); - const entries = readArchiveEntriesForNotices(file, label); - assertNodeDirectReleaseNoticeEntries(entries, { prefix: "package", label }); - const manifest = archiveJson(entries, "package/package.json", label); - const target = targets.find((candidate) => candidate.npmPackage === manifest.name); - if (!target) { - throw new Error(`${label} package name is not a published Node direct carrier: ${JSON.stringify(manifest.name)}`); - } - if (manifest.version !== version) { - throw new Error(`${label} package version must be ${version}, got ${JSON.stringify(manifest.version)}`); - } - if (manifest.license !== PACKAGE_LICENSE) { - throw new Error(`${label} package license must be ${PACKAGE_LICENSE}, got ${JSON.stringify(manifest.license)}`); - } - if (manifest.oliphaunt?.target !== target.target) { - throw new Error( - `${label} package target must be ${target.target}, got ${JSON.stringify(manifest.oliphaunt?.target)}`, - ); - } - if (!Array.isArray(manifest.files)) { - throw new Error(`${label} package.json must declare an npm files allowlist`); - } - if ( - manifest.files.some((member) => typeof member !== "string" || member.length === 0) - || new Set(manifest.files).size !== manifest.files.length - ) { - throw new Error(`${label} package.json npm files allowlist must contain unique non-empty strings`); - } - for (const member of NOTICE_MEMBERS) { - if (!manifest.files.includes(member)) { - throw new Error(`${label} package.json npm files allowlist must include ${member}`); - } - } - const prebuild = entries.get("package/prebuilds/oliphaunt_node.node"); - if (!prebuild?.isFile || prebuild.isSymbolicLink || prebuild.size === 0) { - throw new Error(`${label} is missing a non-empty regular package/prebuilds/oliphaunt_node.node`); - } - return manifest; -} - -function readArchiveEntriesForNotices(file, label) { - try { - return readPortableArchiveEntries(file); - } catch (error) { - throw new Error(`${label} is not a valid portable archive: ${error.message}`); - } -} - -async function validateArchive(file, target) { - const entries = await readArchiveEntries(file, fail, PREFIX, "Node direct"); - try { - assertNodeDirectReleaseNoticeEntries(entries, { label: path.basename(file) }); - } catch (error) { - fail(PREFIX, error.message); - } - const memberName = target.libraryRelativePath; - if (!entries.has(memberName)) { - fail(PREFIX, `${path.basename(file)} is missing ${memberName}`); - } - const member = entries.get(memberName); - if (!member.isFile) { - fail(PREFIX, `${path.basename(file)} ${memberName} is not a regular file`); - } - if (member.size === 0) { - fail(PREFIX, `${path.basename(file)} ${memberName} is empty`); - } - inspectPlatformBinaryEntries( - [...entries].map(([name, entry]) => ({ name, ...entry })), - { target: target.target, rootLabel: path.basename(file) }, - ); -} - -async function main(argv) { - const args = parseArgs(argv); - const version = await currentProductVersion(PRODUCT, PREFIX); - const requiredAssets = expectedAssets(PRODUCT, KIND, version, PREFIX); - const targets = artifactTargets(PRODUCT, KIND, PREFIX); - const targetsByAsset = new Map(targets.map((target) => [target.asset.replaceAll("{version}", version), target])); - const missing = []; - for (const asset of requiredAssets) { - if (!(await assertFileExists(path.join(args.assetDir, asset)))) { - missing.push(asset); - } - } - if (missing.length > 0) { - if (!args.allowPartial) { - fail(PREFIX, `missing oliphaunt-node-direct release asset(s): ${missing.join(", ")}`); - } - let presentAddons = 0; - for (const target of targets) { - if (await assertFileExists(path.join(args.assetDir, target.asset.replaceAll("{version}", version)))) { - presentAddons += 1; - } - } - if (presentAddons === 0) { - fail(PREFIX, "partial oliphaunt-node-direct release asset validation requires at least one addon asset"); - } - } - - const checksumAsset = `oliphaunt-node-direct-${version}-release-assets.sha256`; - const checksumPath = path.join(args.assetDir, checksumAsset); - if (!(await assertFileExists(checksumPath))) { - fail(PREFIX, `missing checksum manifest: ${checksumAsset}`); - } - const checksums = await checksumManifest(checksumPath, fail, PREFIX); - for (const asset of requiredAssets.sort(compareText)) { - const assetPath = path.join(args.assetDir, asset); - if (args.allowPartial && !(await assertFileExists(assetPath))) { - continue; - } - if (asset === checksumAsset) { - continue; - } - const expected = checksums.get(asset); - if (!expected) { - fail(PREFIX, `${checksumAsset} does not cover ${asset}`); - } - const actual = await sha256(assetPath); - if (actual !== expected) { - fail(PREFIX, `checksum mismatch for ${asset}: expected ${expected}, got ${actual}`); - } - } - for (const [asset, target] of targetsByAsset) { - const assetPath = path.join(args.assetDir, asset); - if (args.allowPartial && !(await assertFileExists(assetPath))) { - continue; - } - await validateArchive(assetPath, target); - } - for (const npmPackage of args.npmPackages) { - try { - assertNodeDirectNpmArchive(npmPackage, targets, version); - } catch (error) { - fail(PREFIX, error.message); - } - } - console.log(`oliphaunt-node-direct release assets validated: ${args.assetDir}`); -} - -const invoked = process.argv[1] ? path.resolve(process.argv[1]) : ""; -if (invoked === fileURLToPath(import.meta.url)) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/check-node-direct-release-assets.test.mjs b/tools/release/check-node-direct-release-assets.test.mjs deleted file mode 100644 index 2bfd0ab23..000000000 --- a/tools/release/check-node-direct-release-assets.test.mjs +++ /dev/null @@ -1,126 +0,0 @@ -import assert from "node:assert/strict"; -import { - chmodSync, - mkdtempSync, - mkdirSync, - readFileSync, - realpathSync, - renameSync, - rmSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { - assertNodeDirectNpmArchive, - assertNodeDirectReleaseNoticeEntries, -} from "./check-node-direct-release-assets.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -const TARGET = Object.freeze({ - npmPackage: "@oliphaunt/node-direct-linux-x64-gnu", - target: "linux-x64-gnu", -}); - -function fixture(t) { - const root = realpathSync(mkdtempSync(path.join(tmpdir(), "node-direct-notices-test-"))); - t.after(() => rmSync(root, { recursive: true, force: true })); - return root; -} - -function archiveDirectory(source, output, { keepParent = false } = {}) { - const archive = output.endsWith(".tar.gz") || output.endsWith(".zip") - ? output - : `${output}.tar.gz`; - const args = ["src/shared/artifact-packaging/archive-directory.mjs"]; - if (keepParent) args.push("--keep-parent"); - args.push(source, archive); - const result = spawnSync(path.join(ROOT, "tools/dev/bun.sh"), args, { - cwd: ROOT, - encoding: "utf8", - }); - assert.equal(result.status, 0, result.stderr); - if (archive !== output) renameSync(archive, output); -} - -function stageNpmPackage(root) { - const packageDir = path.join(root, "package"); - mkdirSync(path.join(packageDir, "prebuilds"), { recursive: true }); - const manifest = JSON.parse( - readFileSync(path.join(ROOT, "src/runtimes/node-direct/packages/linux-x64-gnu/package.json"), "utf8"), - ); - writeFileSync(path.join(packageDir, "package.json"), `${JSON.stringify(manifest, null, 2)}\n`); - writeFileSync(path.join(packageDir, "prebuilds/oliphaunt_node.node"), "fixture-addon\n"); - stageReleaseNotices(packageDir, { profile: "source-sdk" }); - return { manifest, packageDir }; -} - -test("Node direct addon and npm carriers contain only exact adapter notices", (t) => { - const root = fixture(t); - const addonStage = path.join(root, "addon"); - mkdirSync(addonStage); - writeFileSync(path.join(addonStage, "oliphaunt_node.node"), "fixture-addon\n"); - stageReleaseNotices(addonStage, { profile: "source-sdk" }); - const addonArchive = path.join(root, "addon.tar.gz"); - archiveDirectory(addonStage, addonArchive); - assert.deepEqual( - assertNodeDirectReleaseNoticeEntries(readPortableArchiveEntries(addonArchive), { - label: path.basename(addonArchive), - }), - ["LICENSE", "THIRD_PARTY_NOTICES.md"], - ); - const addonZip = path.join(root, "addon.zip"); - archiveDirectory(addonStage, addonZip); - assert.deepEqual( - assertNodeDirectReleaseNoticeEntries(readPortableArchiveEntries(addonZip), { - label: path.basename(addonZip), - }), - ["LICENSE", "THIRD_PARTY_NOTICES.md"], - ); - - const { manifest: sourceManifest, packageDir } = stageNpmPackage(root); - const npmArchive = path.join(root, "node-direct.tgz"); - archiveDirectory(packageDir, npmArchive, { keepParent: true }); - const manifest = assertNodeDirectNpmArchive(npmArchive, [TARGET], sourceManifest.version); - assert.equal(manifest.license, "MIT"); -}); - -test("Node direct npm validation rejects notice drift and runtime-license carryover", (t) => { - const root = fixture(t); - let staged = stageNpmPackage(path.join(root, "byte-drift")); - writeFileSync(path.join(staged.packageDir, "LICENSE"), "not canonical\n"); - let archive = path.join(root, "byte-drift.tgz"); - archiveDirectory(staged.packageDir, archive, { keepParent: true }); - assert.throws( - () => assertNodeDirectNpmArchive(archive, [TARGET], staged.manifest.version), - /differs byte-for-byte/u, - ); - - staged = stageNpmPackage(path.join(root, "stale-runtime")); - staged.manifest.files.push("THIRD_PARTY_LICENSES"); - writeFileSync( - path.join(staged.packageDir, "package.json"), - `${JSON.stringify(staged.manifest, null, 2)}\n`, - ); - stageReleaseNotices(staged.packageDir, { profile: "native-runtime" }); - archive = path.join(root, "stale-runtime.tgz"); - archiveDirectory(staged.packageDir, archive, { keepParent: true }); - assert.throws( - () => assertNodeDirectNpmArchive(archive, [TARGET], staged.manifest.version), - /unexpected (?:product notice|release license)/u, - ); - - staged = stageNpmPackage(path.join(root, "mode-drift")); - chmodSync(path.join(staged.packageDir, "THIRD_PARTY_NOTICES.md"), 0o755); - archive = path.join(root, "mode-drift.tgz"); - archiveDirectory(staged.packageDir, archive, { keepParent: true }); - assert.throws( - () => assertNodeDirectNpmArchive(archive, [TARGET], staged.manifest.version), - /mode 0644/u, - ); -}); diff --git a/tools/release/check-registry-publication-http.test.mjs b/tools/release/check-registry-publication-http.test.mjs deleted file mode 100644 index 66f84f596..000000000 --- a/tools/release/check-registry-publication-http.test.mjs +++ /dev/null @@ -1,154 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { - CRATES_IO_RATE_LIMIT_FALLBACK_SECONDS, - CRATES_IO_READ_INTERVAL_SECONDS, - CRATES_IO_READ_RETRY_BUDGET_SECONDS, - boundedRegistrySleep, - cratesioUrlExists, - readBoundedRegistryJson, - registryRequestTimeoutMilliseconds, -} from "./check_registry_publication.mjs"; - -describe("registry publication HTTP response boundary", () => { - test("parses a response only within the configured byte limit", async () => { - await expect(readBoundedRegistryJson(Response.json({ present: true }), "registry", 64)) - .resolves.toEqual({ present: true }); - await expect(readBoundedRegistryJson(new Response("{}", { - headers: { "content-length": "65" }, - }), "registry", 64)).rejects.toThrow("registry response exceeds 64 bytes"); - }); - - test("rejects streamed overflow and malformed JSON deterministically", async () => { - await expect(readBoundedRegistryJson(new Response("12345"), "registry", 4)) - .rejects.toThrow("registry response exceeds 4 bytes"); - await expect(readBoundedRegistryJson(new Response("not-json"), "registry", 64)) - .rejects.toThrow("registry returned invalid JSON"); - }); - - test("clamps requests and all retry sleeps before the shared mutation deadline reserve", async () => { - const previousDeadline = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; - const now = 1_000_000; - const sleeps = []; - try { - process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = "1010"; - expect(registryRequestTimeoutMilliseconds("registry request", { nowImpl: () => now })).toBe(5_000); - await expect(boundedRegistrySleep(4, "HTTP Retry-After", { - nowImpl: () => now, - sleepImpl: async (milliseconds) => sleeps.push(milliseconds), - })).resolves.toBeUndefined(); - expect(sleeps).toEqual([4_000]); - await expect(boundedRegistrySleep(5, "outer publication retry", { - nowImpl: () => now, - sleepImpl: async () => { - throw new Error("must not consume the cleanup reserve"); - }, - })).rejects.toThrow("cannot wait 5s before the shared registry mutation deadline"); - - process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = "1005"; - expect(() => registryRequestTimeoutMilliseconds("registry request", { nowImpl: () => now })) - .toThrow("shared registry mutation deadline has been reached"); - } finally { - if (previousDeadline === undefined) delete process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; - else process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = previousDeadline; - } - }); - - test("retains the ordinary read-only timeout and sleep behavior when no mutation deadline is present", async () => { - const previousDeadline = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; - const sleeps = []; - try { - delete process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; - expect(registryRequestTimeoutMilliseconds("registry request", { nowImpl: () => 1_000_000 })).toBe(20_000); - await boundedRegistrySleep(30, "read-only retry", { - nowImpl: () => 1_000_000, - sleepImpl: async (milliseconds) => sleeps.push(milliseconds), - }); - expect(sleeps).toEqual([30_000]); - } finally { - if (previousDeadline === undefined) delete process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; - else process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = previousDeadline; - } - }); - - test("paces every crates.io existence read and honors Retry-After before retrying", async () => { - let calls = 0; - let now = 1_000_000; - const sleeps = []; - const exists = await cratesioUrlExists( - "https://crates.example.test/api/v1/crates/example/1.0.0", - "example 1.0.0", - { - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - fetchImpl: async () => { - calls += 1; - return calls === 1 - ? new Response("", { status: 429, headers: { "Retry-After": "2" } }) - : new Response("", { status: 200 }); - }, - }, - ); - - expect(exists).toBe(true); - expect(calls).toBe(2); - expect(sleeps).toEqual([ - CRATES_IO_READ_INTERVAL_SECONDS * 1000, - 2_000, - CRATES_IO_READ_INTERVAL_SECONDS * 1000, - ]); - }); - - test("uses a conservative bounded crates.io 429 fallback and never retries before an excessive Retry-After", async () => { - let calls = 0; - let now = 1_000_000; - const fallbackSleeps = []; - await expect(cratesioUrlExists( - "https://crates.example.test/api/v1/crates/absent/1.0.0", - "absent 1.0.0", - { - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - fallbackSleeps.push(milliseconds); - now += milliseconds; - }, - fetchImpl: async () => { - calls += 1; - return calls === 1 - ? new Response("", { status: 429 }) - : new Response("", { status: 404 }); - }, - }, - )).resolves.toBe(false); - expect(fallbackSleeps).toEqual([ - CRATES_IO_READ_INTERVAL_SECONDS * 1000, - CRATES_IO_RATE_LIMIT_FALLBACK_SECONDS * 1000, - CRATES_IO_READ_INTERVAL_SECONDS * 1000, - ]); - - calls = 0; - const excessiveSleeps = []; - await expect(cratesioUrlExists( - "https://crates.example.test/api/v1/crates/later/1.0.0", - "later 1.0.0", - { - nowImpl: () => 1_000_000, - sleepImpl: async (milliseconds) => excessiveSleeps.push(milliseconds), - fetchImpl: async () => { - calls += 1; - return new Response("", { - status: 429, - headers: { "Retry-After": String(CRATES_IO_READ_RETRY_BUDGET_SECONDS + 1) }, - }); - }, - }, - )).rejects.toThrow( - `exceeds its bounded ${CRATES_IO_READ_RETRY_BUDGET_SECONDS}s retry-delay budget`, - ); - expect(calls).toBe(1); - expect(excessiveSleeps).toEqual([CRATES_IO_READ_INTERVAL_SECONDS * 1000]); - }); -}); diff --git a/tools/release/check-registry-publication-http.test.mts b/tools/release/check-registry-publication-http.test.mts new file mode 100644 index 000000000..bccfa768a --- /dev/null +++ b/tools/release/check-registry-publication-http.test.mts @@ -0,0 +1,168 @@ +import { describe, expect, test } from 'bun:test'; + +import { + CRATES_IO_RATE_LIMIT_FALLBACK_SECONDS, + CRATES_IO_READ_INTERVAL_SECONDS, + CRATES_IO_READ_RETRY_BUDGET_SECONDS, + boundedRegistrySleep, + cratesioUrlExists, + readBoundedRegistryJson, + registryRequestTimeoutMilliseconds, +} from './check_registry_publication.mts'; + +describe('registry publication HTTP response boundary', () => { + test('parses a response only within the configured byte limit', async () => { + await expect( + readBoundedRegistryJson(Response.json({ present: true }), 'registry', 64), + ).resolves.toEqual({ present: true }); + await expect( + readBoundedRegistryJson( + new Response('{}', { + headers: { 'content-length': '65' }, + }), + 'registry', + 64, + ), + ).rejects.toThrow('registry response exceeds 64 bytes'); + }); + + test('rejects streamed overflow and malformed JSON deterministically', async () => { + await expect(readBoundedRegistryJson(new Response('12345'), 'registry', 4)).rejects.toThrow( + 'registry response exceeds 4 bytes', + ); + await expect(readBoundedRegistryJson(new Response('not-json'), 'registry', 64)).rejects.toThrow( + 'registry returned invalid JSON', + ); + }); + + test('clamps requests and all retry sleeps before the shared mutation deadline reserve', async () => { + const previousDeadline = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; + const now = 1_000_000; + const sleeps = []; + try { + process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = '1010'; + expect(registryRequestTimeoutMilliseconds('registry request', { nowImpl: () => now })).toBe( + 5_000, + ); + await expect( + boundedRegistrySleep(4, 'HTTP Retry-After', { + nowImpl: () => now, + sleepImpl: async (milliseconds) => sleeps.push(milliseconds), + }), + ).resolves.toBeUndefined(); + expect(sleeps).toEqual([4_000]); + await expect( + boundedRegistrySleep(5, 'outer publication retry', { + nowImpl: () => now, + sleepImpl: async () => { + throw new Error('must not consume the cleanup reserve'); + }, + }), + ).rejects.toThrow('cannot wait 5s before the shared registry mutation deadline'); + + process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = '1005'; + expect(() => + registryRequestTimeoutMilliseconds('registry request', { nowImpl: () => now }), + ).toThrow('shared registry mutation deadline has been reached'); + } finally { + if (previousDeadline === undefined) delete process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; + else process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = previousDeadline; + } + }); + + test('retains the ordinary read-only timeout and sleep behavior when no mutation deadline is present', async () => { + const previousDeadline = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; + const sleeps = []; + try { + delete process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; + expect( + registryRequestTimeoutMilliseconds('registry request', { nowImpl: () => 1_000_000 }), + ).toBe(20_000); + await boundedRegistrySleep(30, 'read-only retry', { + nowImpl: () => 1_000_000, + sleepImpl: async (milliseconds) => sleeps.push(milliseconds), + }); + expect(sleeps).toEqual([30_000]); + } finally { + if (previousDeadline === undefined) delete process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; + else process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = previousDeadline; + } + }); + + test('paces every crates.io existence read and honors Retry-After before retrying', async () => { + let calls = 0; + let now = 1_000_000; + const sleeps = []; + const exists = await cratesioUrlExists( + 'https://crates.example.test/api/v1/crates/example/1.0.0', + 'example 1.0.0', + { + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + fetchImpl: async () => { + calls += 1; + return calls === 1 + ? new Response('', { status: 429, headers: { 'Retry-After': '2' } }) + : new Response('', { status: 200 }); + }, + }, + ); + + expect(exists).toBe(true); + expect(calls).toBe(2); + expect(sleeps).toEqual([ + CRATES_IO_READ_INTERVAL_SECONDS * 1000, + 2_000, + CRATES_IO_READ_INTERVAL_SECONDS * 1000, + ]); + }); + + test('uses a conservative bounded crates.io 429 fallback and never retries before an excessive Retry-After', async () => { + let calls = 0; + let now = 1_000_000; + const fallbackSleeps = []; + await expect( + cratesioUrlExists('https://crates.example.test/api/v1/crates/absent/1.0.0', 'absent 1.0.0', { + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + fallbackSleeps.push(milliseconds); + now += milliseconds; + }, + fetchImpl: async () => { + calls += 1; + return calls === 1 + ? new Response('', { status: 429 }) + : new Response('', { status: 404 }); + }, + }), + ).resolves.toBe(false); + expect(fallbackSleeps).toEqual([ + CRATES_IO_READ_INTERVAL_SECONDS * 1000, + CRATES_IO_RATE_LIMIT_FALLBACK_SECONDS * 1000, + CRATES_IO_READ_INTERVAL_SECONDS * 1000, + ]); + + calls = 0; + const excessiveSleeps = []; + await expect( + cratesioUrlExists('https://crates.example.test/api/v1/crates/later/1.0.0', 'later 1.0.0', { + nowImpl: () => 1_000_000, + sleepImpl: async (milliseconds) => excessiveSleeps.push(milliseconds), + fetchImpl: async () => { + calls += 1; + return new Response('', { + status: 429, + headers: { 'Retry-After': String(CRATES_IO_READ_RETRY_BUDGET_SECONDS + 1) }, + }); + }, + }), + ).rejects.toThrow( + `exceeds its bounded ${CRATES_IO_READ_RETRY_BUDGET_SECONDS}s retry-delay budget`, + ); + expect(calls).toBe(1); + expect(excessiveSleeps).toEqual([CRATES_IO_READ_INTERVAL_SECONDS * 1000]); + }); +}); diff --git a/tools/release/check-registry-publication-products.test.mjs b/tools/release/check-registry-publication-products.test.mjs deleted file mode 100644 index 9ae6df9cb..000000000 --- a/tools/release/check-registry-publication-products.test.mjs +++ /dev/null @@ -1,83 +0,0 @@ -import { expect, test } from "bun:test"; - -import { - productRegistryPackages, - productRegistryPackagesFromLock, -} from "./check_registry_publication.mjs"; -import { - contribCarrierDescriptor, - exactExtensionReleaseProducts, -} from "./release-artifact-targets.mjs"; - -test("no-lock exact-extension registry inventory is explicit, complete, and unique", async () => { - expect(process.env.OLIPHAUNT_PUBLICATION_LOCK).toBeUndefined(); - for (const product of exactExtensionReleaseProducts("check-registry-publication-products.test")) { - const packages = await productRegistryPackages(product); - const identities = packages.map(({ kind, name }) => `${kind}:${name}`); - expect(new Set(identities).size).toBe(identities.length); - expect(identities.filter((identity) => identity === `crates:${product}`)).toHaveLength(1); - } -}); - -test("runtime owners expose their complete contrib registry inventory", async () => { - const descriptor = contribCarrierDescriptor("check-registry-publication-products.test"); - const contribPackages = async (owner) => (await productRegistryPackages(owner)) - .filter(({ name }) => name.includes("contrib-pg18")); - expect(await contribPackages(descriptor.nativeOwner)).toHaveLength(12); - expect(await contribPackages(descriptor.wasixOwner)).toHaveLength(6); -}); - -test("publication-lock inventory includes dynamic Cargo payload-part carriers", () => { - const product = "fixture-native"; - const version = "1.2.3"; - const publicationLock = { - products: [{ id: product, version }], - carriers: [ - { - ecosystem: "cargo", - name: "fixture-native-linux-x64-gnu-part-001", - product, - role: "payload-part", - version, - }, - { - ecosystem: "cargo", - name: "fixture-native-linux-x64-gnu", - product, - role: "platform-leaf", - version, - }, - { - ecosystem: "npm", - name: "@fixture/native-linux-x64-gnu", - product, - role: "platform-leaf", - version, - }, - ], - }; - - expect(productRegistryPackagesFromLock(publicationLock, product)).toEqual([ - { - kind: "crates", - name: "fixture-native-linux-x64-gnu-part-001", - version, - }, - { - kind: "crates", - name: "fixture-native-linux-x64-gnu", - version, - }, - { - kind: "npm", - name: "@fixture/native-linux-x64-gnu", - version, - }, - ]); - expect(productRegistryPackagesFromLock(publicationLock, product, { - registryKind: "crates", - }).map(({ name }) => name)).toEqual([ - "fixture-native-linux-x64-gnu-part-001", - "fixture-native-linux-x64-gnu", - ]); -}); diff --git a/tools/release/check-registry-publication-products.test.mts b/tools/release/check-registry-publication-products.test.mts new file mode 100644 index 000000000..8a2ba2ba2 --- /dev/null +++ b/tools/release/check-registry-publication-products.test.mts @@ -0,0 +1,82 @@ +import { expect, test } from 'bun:test'; + +import { + productRegistryPackages, + productRegistryPackagesFromLock, +} from './check_registry_publication.mts'; +import { + contribCarrierDescriptor, + exactExtensionReleaseProducts, +} from './release-artifact-targets.mts'; + +test('no-lock exact-extension registry inventory is explicit, complete, and unique', async () => { + expect(process.env.OLIPHAUNT_PUBLICATION_LOCK).toBeUndefined(); + for (const product of exactExtensionReleaseProducts('check-registry-publication-products.test')) { + const packages = await productRegistryPackages(product); + const identities = packages.map(({ kind, name }) => `${kind}:${name}`); + expect(new Set(identities).size).toBe(identities.length); + expect(identities.filter((identity) => identity === `crates:${product}`)).toHaveLength(1); + } +}); + +test('runtime owners expose their complete contrib registry inventory', async () => { + const descriptor = contribCarrierDescriptor('check-registry-publication-products.test'); + const contribPackages = async (owner) => + (await productRegistryPackages(owner)).filter(({ name }) => name.includes('contrib-pg18')); + expect(await contribPackages(descriptor.nativeOwner)).toHaveLength(12); + expect(await contribPackages(descriptor.wasixOwner)).toHaveLength(6); +}); + +test('publication-lock inventory includes dynamic Cargo payload-part carriers', () => { + const product = 'fixture-native'; + const version = '1.2.3'; + const publicationLock = { + products: [{ id: product, version }], + carriers: [ + { + ecosystem: 'cargo', + name: 'fixture-native-linux-x64-gnu-part-001', + product, + role: 'payload-part', + version, + }, + { + ecosystem: 'cargo', + name: 'fixture-native-linux-x64-gnu', + product, + role: 'platform-leaf', + version, + }, + { + ecosystem: 'npm', + name: '@fixture/native-linux-x64-gnu', + product, + role: 'platform-leaf', + version, + }, + ], + }; + + expect(productRegistryPackagesFromLock(publicationLock, product)).toEqual([ + { + kind: 'crates', + name: 'fixture-native-linux-x64-gnu-part-001', + version, + }, + { + kind: 'crates', + name: 'fixture-native-linux-x64-gnu', + version, + }, + { + kind: 'npm', + name: '@fixture/native-linux-x64-gnu', + version, + }, + ]); + expect( + productRegistryPackagesFromLock(publicationLock, product, { + registryKind: 'crates', + }).map(({ name }) => name), + ).toEqual(['fixture-native-linux-x64-gnu-part-001', 'fixture-native-linux-x64-gnu']); +}); diff --git a/tools/release/check-release-intent.test.sh b/tools/release/check-release-intent.test.sh new file mode 100644 index 000000000..0b36d9d56 --- /dev/null +++ b/tools/release/check-release-intent.test.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/../.." +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +objects="$(git rev-parse --path-format=absolute --git-path objects)" +mkdir "$scratch/objects" +export GIT_OBJECT_DIRECTORY="$scratch/objects" +export GIT_ALTERNATE_OBJECT_DIRECTORIES="$objects${GIT_ALTERNATE_OBJECT_DIRECTORIES:+:$GIT_ALTERNATE_OBJECT_DIRECTORIES}" +export GIT_AUTHOR_NAME='Release Intent Test' GIT_COMMITTER_NAME='Release Intent Test' +export GIT_AUTHOR_EMAIL=release-intent@example.invalid GIT_COMMITTER_EMAIL=release-intent@example.invalid +tree="$(git rev-parse 'HEAD^{tree}')" +first="$(printf 'fix: validate release intent\n' | git commit-tree "$tree" -p HEAD)" +sibling="$(printf 'fix: sibling change\n' | git commit-tree "$tree" -p HEAD)" +script=.github/scripts/check-release-intent.sh +bash "$script" 'fix: validate release intent' HEAD "$first" main workflow_dispatch refs/heads/main + +reject() { + local expected="$1" + shift + if bash "$script" 'fix: validate release intent' "$@" > "$scratch/rejected.log" 2>&1; then + echo "Release intent accepted invalid comparison: $*" >&2 + exit 1 + fi + grep -Fq "$expected" "$scratch/rejected.log" +} +reject 'base must resolve to the exact commit parent' HEAD^ "$first" main workflow_dispatch refs/heads/main +reject 'is not an ancestor' "$first" "$sibling" feature push refs/heads/feature +reject 'requires matching main branch and full ref' HEAD "$first" main workflow_dispatch refs/heads/diagnostic +echo 'Release intent exact-parent and ancestry checks passed' diff --git a/tools/release/check-release-metadata.mjs b/tools/release/check-release-metadata.mjs deleted file mode 100755 index b7646700d..000000000 --- a/tools/release/check-release-metadata.mjs +++ /dev/null @@ -1,603 +0,0 @@ -#!/usr/bin/env bun - -import { existsSync, readFileSync, statSync } from "node:fs"; -import path from "node:path"; - -import { - compatibilityVersionSource, - requireCompatibilityVersionBinding, -} from "./compatibility-version-policy.mjs"; -import { - extensionNativeRegistryPackageStrings, - extensionRegistryPackageStrings, - extensionWasixRegistryPackageStrings, -} from "./extension-registry-packages.mjs"; -import { - allArtifactTargets, - currentProductVersionSync, - exactExtensionProducts, - exactExtensionReleaseProducts, - extensionArtifactTargets, - extensionMetadata, - extensionReleaseProduct, - extensionSqlNames, - extensionRegistryPackageTargetSets, - extensionSourceIdentity, - registryPackageRows, - releaseMetadata, - sdkPackageProducts, -} from "./release-artifact-targets.mjs"; -import { - ROOT, - compareText, - compatibilityVersionEntries, - compatibilityVersionValue, - loadGraph, - moonReleaseMetadataRows, - parseStableVersion, - releaseOrder, - versionFiles, -} from "./release-graph.mjs"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { latestVerifiedReleaseCommit } from "./verify-release-commit.mjs"; -import { - PUBLICATION_CATALOG_SCHEMA, - REGISTRY_KIND_TO_ECOSYSTEM, - declaredCarrierMap, - loadPublicationCatalog, - publicationCatalogDigest, -} from "./publication-catalog.mjs"; -import { - AOT_PACKAGES, - AOT_TARGET_TRIPLES, - ICU_PACKAGE, - RUNTIME_PACKAGE, - TOOLS_AOT_PACKAGES, - TOOLS_PACKAGE, - publicAotCargoDependencies, - publicCargoPackageNames, - publicToolsAotCargoDependencies, - publicToolsFeatureDependencies, -} from "./wasix-cargo-artifact-contract.mjs"; - -const TOOL = "check-release-metadata.mjs"; -const STABLE_VERSION = /^[0-9]+[.][0-9]+[.][0-9]+$/u; -const INSTALL_SCRIPTS = new Set(["preinstall", "install", "postinstall"]); -const REGISTRY_TARGET_ECOSYSTEM = Object.freeze({ - "crates-io": "cargo", - "maven-central": "maven", - npm: "npm", -}); -const KNOWN_PUBLISH_TARGETS = new Set([ - ...Object.keys(REGISTRY_TARGET_ECOSYSTEM), - "github-release", - "github-release-assets", - "swift-package-source-tag", -]); - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function assert(condition, message) { - if (!condition) { - fail(message); - } -} - -function object(value, label) { - assert(value !== null && typeof value === "object" && !Array.isArray(value), `${label} must be an object`); - return value; -} - -function stringList(value, label, { nonEmpty = false } = {}) { - assert( - Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.length > 0), - `${label} must be a list of non-empty strings`, - ); - assert(!nonEmpty || value.length > 0, `${label} must not be empty`); - assert(new Set(value).size === value.length, `${label} must not contain duplicates`); - return value; -} - -function sorted(values) { - return [...values].sort(compareText); -} - -function sameStrings(left, right) { - return JSON.stringify(sorted(left)) === JSON.stringify(sorted(right)); -} - -function readJson(relativePath) { - try { - return object(JSON.parse(readFileSync(path.join(ROOT, relativePath), "utf8")), relativePath); - } catch (error) { - fail(`${relativePath} is not valid JSON: ${error.message}`); - } -} - -function readToml(relativePath) { - try { - return object(Bun.TOML.parse(readFileSync(path.join(ROOT, relativePath), "utf8")), relativePath); - } catch (error) { - fail(`${relativePath} is not valid TOML: ${error.message}`); - } -} - -function requireFile(relativePath, label = relativePath) { - const absolute = path.join(ROOT, relativePath); - assert(existsSync(absolute) && statSync(absolute).isFile(), `${label} does not exist: ${relativePath}`); -} - -function requireDirectory(relativePath, label = relativePath) { - const absolute = path.join(ROOT, relativePath); - assert(existsSync(absolute) && statSync(absolute).isDirectory(), `${label} is not a directory: ${relativePath}`); -} - -function stableVersion(value, label) { - assert(typeof value === "string" && STABLE_VERSION.test(value), `${label} must be stable x.y.z, got ${JSON.stringify(value)}`); - parseStableVersion(value, TOOL); - return value; -} - -function dottedValue(value, expression, label) { - assert(typeof expression === "string" && expression.startsWith("$.") && expression.length > 2, `${label} must use $.path syntax`); - let cursor = value; - for (const key of expression.slice(2).split(".")) { - assert(cursor !== null && typeof cursor === "object" && !Array.isArray(cursor) && key in cursor, `${label} does not resolve ${expression}`); - cursor = cursor[key]; - } - return cursor; -} - -function genericMarkedVersion(relativePath) { - const text = readFileSync(path.join(ROOT, relativePath), "utf8"); - const singleLines = text - .split(/\r?\n/u) - .filter((line) => line.includes("x-release-please-version")); - if (singleLines.length === 1) { - const matches = singleLines[0].match(/[0-9]+[.][0-9]+[.][0-9]+/gu) ?? []; - assert(matches.length === 1, `${relativePath} release-please version marker must own exactly one stable version`); - return matches[0]; - } - const block = /x-release-please-start-version(?[\s\S]*?)x-release-please-end/u.exec(text)?.groups?.body; - assert(singleLines.length === 0 && block !== undefined, `${relativePath} must have one release-please version marker or marker block`); - const matches = block.match(/[0-9]+[.][0-9]+[.][0-9]+/gu) ?? []; - assert(matches.length === 1, `${relativePath} release-please version block must own exactly one stable version`); - return matches[0]; -} - -function conventionalVersion(relativePath) { - const basename = path.basename(relativePath); - const text = readFileSync(path.join(ROOT, relativePath), "utf8"); - if (basename === "Cargo.toml") { - const manifest = readToml(relativePath); - return object(manifest.package, `${relativePath}.package`).version; - } - if (basename === "package.json") { - return readJson(relativePath).version; - } - if (basename === "VERSION" || basename === "LIBOLIPHAUNT_VERSION") { - return text.trim(); - } - if (basename === "gradle.properties") { - const matches = [...text.matchAll(/^VERSION_NAME=(.+)$/gmu)].map((match) => match[1].trim()); - assert(matches.length === 1, `${relativePath} must declare VERSION_NAME exactly once`); - return matches[0]; - } - return genericMarkedVersion(relativePath); -} - -function releasePleaseVersion(relativePath, entry) { - if (typeof entry === "string") { - return conventionalVersion(relativePath); - } - const type = entry.type ?? "generic"; - if (type === "generic") { - return conventionalVersion(relativePath); - } - const parsers = { - json: readJson, - toml: readToml, - yaml: (file) => object(Bun.YAML.parse(readFileSync(path.join(ROOT, file), "utf8")), file), - }; - const parser = parsers[type]; - assert(parser !== undefined, `${relativePath} uses unsupported structured release-please type ${JSON.stringify(type)}`); - const value = parser(relativePath); - return dottedValue(value, entry.jsonpath, `${relativePath}.jsonpath`); -} - -function resolveDerivedPath(config, candidate) { - if (existsSync(path.join(ROOT, candidate))) { - return candidate; - } - return path.posix.join(config.path, candidate); -} - -function validateReleasePleaseVersions(graph) { - const config = readJson("release-please-config.json"); - const manifest = readJson(".release-please-manifest.json"); - const packages = object(config.packages, "release-please-config.json.packages"); - const productsByPath = new Map(Object.entries(graph.products).map(([product, productConfig]) => [productConfig.path, product])); - assert(sameStrings(Object.keys(packages), productsByPath.keys()), "release-please package paths must exactly match release graph products"); - assert(sameStrings(Object.keys(manifest), productsByPath.keys()), "release-please manifest paths must exactly match release graph products"); - - for (const [packagePath, packageConfigValue] of Object.entries(packages)) { - const packageConfig = object(packageConfigValue, `release-please packages.${packagePath}`); - const product = productsByPath.get(packagePath); - const productConfig = graph.products[product]; - assert(packageConfig.component === product, `${packagePath}.component must be ${product}`); - assert(manifest[packagePath] === productConfig.version, `${packagePath} release-please manifest version must match ${product}`); - const changelog = packageConfig["changelog-path"] ?? "CHANGELOG.md"; - assert(typeof changelog === "string" && changelog.length > 0, `${packagePath}.changelog-path must be a non-empty string`); - const changelogPath = path.posix.join(packagePath, changelog); - requireFile(changelogPath, `${product} changelog`); - if (manifest[packagePath] === "0.0.0") { - assert( - readFileSync(path.join(ROOT, changelogPath)).length === 0, - `${product} unreleased 0.0.0 changelog must be exactly empty so Release Please can create its canonical heading`, - ); - } - assert(productConfig.changelog_path === changelogPath, `${product} graph changelog must match release-please`); - - const releaseType = packageConfig["release-type"]; - const canonical = packageConfig["version-file"] - ?? (releaseType === "rust" ? "Cargo.toml" : ["node", "expo"].includes(releaseType) ? "package.json" : undefined); - assert(typeof canonical === "string" && canonical.length > 0, `${packagePath} must declare a canonical version file`); - const extraFiles = packageConfig["extra-files"] ?? []; - assert(Array.isArray(extraFiles), `${packagePath}.extra-files must be a list`); - const entries = [canonical, ...extraFiles] - .map((entry) => ({ entry, relative: typeof entry === "string" ? entry : entry.path })); - for (const { entry, relative } of entries) { - assert(typeof relative === "string" && relative.length > 0, `${packagePath} version-file entry must declare a path`); - const file = path.posix.join(packagePath, relative); - requireFile(file, `${product} version file`); - const value = releasePleaseVersion(file, entry); - assert(value === productConfig.version, `${file} version ${JSON.stringify(value)} must match ${product} ${productConfig.version}`); - } - const files = entries.map(({ relative }) => path.posix.join(packagePath, relative)); - assert(sameStrings(files, versionFiles(product, TOOL)), `${product} release graph version files must match release-please`); - } -} - -function validateGraph(graph) { - const productIds = sorted(Object.keys(graph.products)); - assert(productIds.length > 0, "release graph must contain products"); - const moonRows = moonReleaseMetadataRows({}, TOOL); - assert(sameStrings(moonRows.map((row) => row.product), productIds), "Moon release products must exactly match the release graph"); - const packagePaths = new Set(); - for (const product of productIds) { - const config = object(graph.products[product], `${product} config`); - assert(config.id === product, `${product}.id must match its graph key`); - assert(typeof config.owner === "string" && config.owner.length > 0, `${product}.owner must be non-empty`); - assert(typeof config.kind === "string" && config.kind.length > 0, `${product}.kind must be non-empty`); - assert(typeof config.path === "string" && config.path.length > 0, `${product}.path must be non-empty`); - assert(!packagePaths.has(config.path), `release package path is shared by more than one product: ${config.path}`); - packagePaths.add(config.path); - requireDirectory(config.path, `${product} package path`); - requireFile(`${config.path}/release.toml`, `${product} metadata`); - stableVersion(config.version, `${product}.version`); - assert(currentProductVersionSync(product, TOOL) === config.version, `${product} canonical version must match the release manifest`); - stringList(config.publish_targets, `${product}.publish_targets`, { nonEmpty: true }); - stringList(config.release_artifacts, `${product}.release_artifacts`, { nonEmpty: true }); - stringList(config.registry_packages ?? [], `${product}.registry_packages`); - for (const target of config.publish_targets) { - assert(KNOWN_PUBLISH_TARGETS.has(target), `${product} declares unsupported publish target ${target}`); - } - assert(config.tag_prefix === `${product}-v`, `${product}.tag_prefix must be ${product}-v`); - for (const file of config.version_files) { - requireFile(file, `${product} version file`); - } - for (const candidate of config.derived_version_files ?? []) { - requireFile(resolveDerivedPath(config, candidate), `${product} derived version file`); - } - const moon = moonRows.find((row) => row.product === product); - assert(moon.component === product, `${product} Moon release component must match`); - assert(moon.packagePath === config.path, `${product} Moon package path must match release.toml`); - releaseMetadata(product, TOOL); - } - assert(sameStrings(releaseOrder(graph.products, graph.moon_projects, new Set(productIds), TOOL), productIds), "release order must cover every product exactly once"); - validateReleasePleaseVersions(graph); -} - -function validateCompatibility(graph) { - const entries = compatibilityVersionEntries(graph.products, { requireSourceProduct: true, prefix: TOOL }); - assert(new Set(entries.map((entry) => entry.id)).size === entries.length, "compatibility field ids must be globally unique"); - const pendingRelease = latestVerifiedReleaseCommit({ repo: ROOT }); - const pendingVersions = new Map(Object.entries(pendingRelease?.versions ?? {})); - const versionSources = new Map(); - for (const entry of entries) { - const value = compatibilityVersionValue(entry, { prefix: TOOL }); - let source = versionSources.get(entry.product); - if (source === undefined) { - source = compatibilityVersionSource(entry, graph.products, pendingVersions, { - headRef: "HEAD", - pendingCommit: pendingRelease?.commit, - prefix: TOOL, - root: ROOT, - }); - versionSources.set(entry.product, source); - } - const expected = source.kind === "tagged-sink" - ? compatibilityVersionValue(entry, { - ref: source.ref, - prefix: TOOL, - // A compatibility pin can become explicit before the sink's next - // release. Once published, its immutable tag supplies this value. - missingValue: value, - }) - : graph.products[entry.sourceProduct].version; - const provenance = source.kind === "tagged-sink" - ? `immutable ${entry.product} tag ${source.tag}` - : `${entry.sourceProduct} ${expected}`; - requireCompatibilityVersionBinding({ - id: entry.id, - value, - expected, - sourceProduct: entry.sourceProduct, - sourceVersion: graph.products[entry.sourceProduct].version, - provenance, - }, { prefix: TOOL }); - } - return entries.length; -} - -function validateNpmManifest(relativePath, product, catalogCarriers) { - const manifest = readJson(relativePath); - assert(typeof manifest.name === "string" && manifest.name.length > 0, `${relativePath}.name must be non-empty`); - assert(manifest.version === product.version, `${relativePath}.version must match ${product.id} ${product.version}`); - const scripts = object(manifest.scripts ?? {}, `${relativePath}.scripts`); - for (const [name, command] of Object.entries(scripts)) { - assert(typeof command === "string", `${relativePath}.scripts.${name} must be a string`); - assert(!INSTALL_SCRIPTS.has(name), `${relativePath} must not run ${name} during consumer installation`); - } - if (manifest.private !== true) { - const carrier = catalogCarriers.get(`npm:${manifest.name}`); - assert(carrier?.product === product.id, `${relativePath} public npm identity ${manifest.name} must belong to ${product.id} in the publication catalog`); - assert(manifest.publishConfig?.access === "public", `${relativePath}.publishConfig.access must be public`); - assert(manifest.publishConfig?.provenance === true, `${relativePath}.publishConfig.provenance must be true`); - } -} - -function validateCargoManifest(relativePath, product, catalogCarriers) { - const manifest = readToml(relativePath); - const packageConfig = object(manifest.package, `${relativePath}.package`); - assert(typeof packageConfig.name === "string" && packageConfig.name.length > 0, `${relativePath}.package.name must be non-empty`); - assert(packageConfig.version === product.version, `${relativePath}.package.version must match ${product.id} ${product.version}`); - if (packageConfig.publish !== false) { - const carrier = catalogCarriers.get(`cargo:${packageConfig.name}`); - assert(carrier?.product === product.id, `${relativePath} publishable Cargo identity ${packageConfig.name} must belong to ${product.id}`); - } -} - -function validateSourcePackageManifests(graph, catalog) { - const carriers = declaredCarrierMap(catalog); - let npm = 0; - let cargo = 0; - for (const [id, config] of Object.entries(graph.products)) { - const product = { id, ...config }; - for (const file of config.version_files) { - if (path.basename(file) === "package.json") { - validateNpmManifest(file, product, carriers); - npm += 1; - } else if (path.basename(file) === "Cargo.toml") { - validateCargoManifest(file, product, carriers); - cargo += 1; - } - } - } - return { npm, cargo }; -} - -function validateCatalogAndTargets(graph) { - const catalog = loadPublicationCatalog(TOOL); - assert(catalog.schema === PUBLICATION_CATALOG_SCHEMA, `publication catalog must use ${PUBLICATION_CATALOG_SCHEMA}`); - const productRows = new Map(catalog.products.map((product) => [product.id, product])); - assert(sameStrings(productRows.keys(), Object.keys(graph.products)), "publication catalog products must exactly match the release graph"); - for (const [product, config] of Object.entries(graph.products)) { - const row = productRows.get(product); - assert(row.version === config.version, `${product} publication version must match the release graph`); - assert(sameStrings(row.publishTargets, config.publish_targets), `${product} publication targets must match release.toml`); - const declared = registryPackageRows({ product }, TOOL).map((entry) => { - const ecosystem = REGISTRY_KIND_TO_ECOSYSTEM[entry.packageKind]; - assert(ecosystem !== undefined, `${product} uses unsupported registry package kind ${entry.packageKind}`); - return `${ecosystem}:${entry.packageName}`; - }); - const catalogDeclared = catalog.carriers - .filter((carrier) => carrier.product === product && carrier.declared) - .map((carrier) => carrier.id); - assert( - sameStrings(declared, catalogDeclared), - `${product} declared registry packages must exactly match the publication catalog`, - ); - for (const [target, ecosystem] of Object.entries(REGISTRY_TARGET_ECOSYSTEM)) { - const count = catalog.carriers.filter((carrier) => carrier.product === product && carrier.ecosystem === ecosystem).length; - assert(config.publish_targets.includes(target) === (count > 0), `${product} ${target} target and ${ecosystem} carrier declarations must agree`); - } - } - - const runtimeTargets = allArtifactTargets({}, TOOL); - assert(runtimeTargets.length > 0, "runtime artifact target catalog must not be empty"); - const carriers = declaredCarrierMap(catalog); - for (const target of runtimeTargets.filter((row) => row.npmPackage !== undefined)) { - assert(carriers.get(`npm:${target.npmPackage}`)?.product === target.product, `${target.id} npm package must be declared by ${target.product}`); - } - - const extensionProducts = exactExtensionProducts(TOOL); - assert( - sameStrings(exactExtensionReleaseProducts(TOOL), Object.entries(graph.products).filter(([, config]) => ["exact-extension-artifact", "exact-extension-bundle"].includes(config.kind)).map(([product]) => product)), - "exact-extension release products must match the release graph", - ); - let extensionTargets = 0; - for (const product of extensionProducts) { - const metadata = extensionMetadata(product, TOOL); - extensionSourceIdentity(product, TOOL); - const targets = extensionArtifactTargets({ product }, TOOL); - assert(targets.some((target) => target.family === "native"), `${product} must publish at least one native target`); - assert(targets.some((target) => target.family === "wasix"), `${product} must publish at least one WASIX target`); - const targetSets = extensionRegistryPackageTargetSets(product, TOOL); - const expected = extensionRegistryPackageStrings({ - product, - ...targetSets, - }); - const expectedNative = extensionNativeRegistryPackageStrings({ product, ...targetSets }); - const expectedWasix = extensionWasixRegistryPackageStrings({ - product, - includeAot: targetSets.includeWasixAot, - }); - assert( - sameStrings(expected, [...expectedNative, ...expectedWasix]), - `${product} registry package families must exactly partition its package identities`, - ); - assert( - expectedNative.every((entry) => !expectedWasix.includes(entry)), - `${product} native and WASIX registry package families must be disjoint`, - ); - const nativeOwner = extensionReleaseProduct(product, "native", TOOL); - const wasixOwner = extensionReleaseProduct(product, "wasix", TOOL); - const nativeDeclared = registryPackageRows({ product: nativeOwner }, TOOL) - .map((entry) => `${entry.packageKind}:${entry.packageName}`) - .filter((entry) => expectedNative.includes(entry)); - const wasixDeclared = registryPackageRows({ product: wasixOwner }, TOOL) - .map((entry) => `${entry.packageKind}:${entry.packageName}`) - .filter((entry) => expectedWasix.includes(entry)); - assert( - sameStrings(expectedNative, nativeDeclared) && sameStrings(expectedWasix, wasixDeclared), - `${product} registry packages must be owned by its native and WASIX release products`, - ); - extensionTargets += targets.length; - } - - return { - catalog, - runtimeTargets: runtimeTargets.length, - extensionProducts: extensionProducts.length, - extensionTargets, - }; -} - -function workspaceDependency(table, name, { optional = false } = {}) { - const dependency = object(table?.[name], `oliphaunt-wasix dependency ${name}`); - assert(dependency.version === "*", `${name} must use the local workspace runtime without a release-version constraint`); - assert(typeof dependency.path === "string" && dependency.path.length > 0, `${name} must use a local workspace path`); - assert(optional ? dependency.optional === true : dependency.optional !== true, `${name} optional dependency contract is wrong`); -} - -function validateWasixContract(graph, catalog) { - const runtimeVersion = graph.products["liboliphaunt-wasix"].version; - const coreCargoPackages = publicCargoPackageNames(); - const runtimeCargo = catalog.carriers - .filter((carrier) => - carrier.product === "liboliphaunt-wasix" - && carrier.ecosystem === "cargo" - && coreCargoPackages.includes(carrier.name)) - .map((carrier) => carrier.name); - assert(sameStrings(runtimeCargo, coreCargoPackages), "liboliphaunt-wasix core Cargo carriers must exactly match the WASIX artifact contract"); - - const manifests = new Map([ - [ICU_PACKAGE, "src/runtimes/liboliphaunt/icu/Cargo.toml"], - [RUNTIME_PACKAGE, "src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml"], - [TOOLS_PACKAGE, "src/runtimes/liboliphaunt/wasix/crates/tools/Cargo.toml"], - ...Object.entries(AOT_PACKAGES).map(([target, name]) => [name, `src/runtimes/liboliphaunt/wasix/crates/aot/${AOT_TARGET_TRIPLES[target]}/Cargo.toml`]), - ...Object.entries(TOOLS_AOT_PACKAGES).map(([target, name]) => [name, `src/runtimes/liboliphaunt/wasix/crates/tools-aot/${AOT_TARGET_TRIPLES[target]}/Cargo.toml`]), - ]); - for (const [name, file] of manifests) { - const packageConfig = object(readToml(file).package, `${file}.package`); - assert(packageConfig.name === name, `${file} package name must be ${name}`); - assert(packageConfig.version === runtimeVersion, `${file} version must match liboliphaunt-wasix`); - } - - const sdk = readToml("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"); - const dependencies = object(sdk.dependencies, "oliphaunt-wasix dependencies"); - workspaceDependency(dependencies, RUNTIME_PACKAGE); - workspaceDependency(dependencies, TOOLS_PACKAGE, { optional: true }); - workspaceDependency(dependencies, ICU_PACKAGE, { optional: true }); - const targetTables = object(sdk.target, "oliphaunt-wasix target dependencies"); - for (const [cfg, name] of Object.entries(publicAotCargoDependencies())) { - workspaceDependency(object(targetTables[cfg], `oliphaunt-wasix target ${cfg}`).dependencies, name); - } - for (const [cfg, name] of Object.entries(publicToolsAotCargoDependencies())) { - workspaceDependency(object(targetTables[cfg], `oliphaunt-wasix target ${cfg}`).dependencies, name, { optional: true }); - } - assert(sameStrings(sdk.features?.tools ?? [], publicToolsFeatureDependencies()), "oliphaunt-wasix tools feature must select exactly the split tool carriers"); - assert(!("bundled" in object(sdk.features, "oliphaunt-wasix features")), "oliphaunt-wasix must not expose an inert bundled feature"); - const extensionFeatures = exactExtensionProducts(TOOL) - .flatMap((product) => extensionSqlNames(product, TOOL)) - .map((sqlName) => `extension-${sqlName.replaceAll("_", "-")}`); - const sdkExtensionFeatures = Object.keys(sdk.features).filter((feature) => feature.startsWith("extension-")); - assert(sameStrings(extensionFeatures, sdkExtensionFeatures), "oliphaunt-wasix extension features must exactly match modeled extensions"); - const runtimeFeatures = Object.keys(readToml("src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml").features ?? {}); - assert(sameStrings(extensionFeatures, runtimeFeatures), "portable WASIX runtime features must exactly match modeled extensions"); - const dump = (sdk.bin ?? []).find((entry) => entry.name === "oliphaunt-wasix-dump"); - assert(Array.isArray(dump?.["required-features"]) && dump["required-features"].includes("tools"), "oliphaunt-wasix-dump must require the tools feature"); -} - -function validateNativeContract(graph) { - const targets = allArtifactTargets({ product: "liboliphaunt-native" }, TOOL); - assert(targets.some((target) => target.kind === "native-runtime"), "liboliphaunt-native must declare runtime targets"); - assert(targets.some((target) => target.kind === "native-tools"), "liboliphaunt-native must declare split tool targets"); - assert(currentProductVersionSync("liboliphaunt-native", TOOL) === graph.products["liboliphaunt-native"].version, "native C product version must match the release graph"); -} - -function validateSdkSet(graph) { - const expected = Object.entries(graph.products) - .filter(([, config]) => config.kind === "sdk") - .map(([product]) => product); - const actual = sdkPackageProducts(TOOL).map((row) => row.product); - assert(sameStrings(expected, actual), "SDK package artifact products must exactly match SDK release products"); -} - -function parseArgs(argv) { - let json = false; - for (const arg of argv) { - if (arg === "--json") { - json = true; - } else if (arg === "-h" || arg === "--help") { - console.log("usage: tools/release/check-release-metadata.mjs [--json]"); - process.exit(0); - } else { - fail(`unknown argument ${arg}`); - } - } - return { json }; -} - -function main(argv) { - const args = parseArgs(argv); - const graph = loadGraph(TOOL); - validateGraph(graph); - const compatibilityFields = validateCompatibility(graph); - const targetReport = validateCatalogAndTargets(graph); - const manifests = validateSourcePackageManifests(graph, targetReport.catalog); - validateNativeContract(graph); - validateWasixContract(graph, targetReport.catalog); - validateSdkSet(graph); - const report = { - schema: "oliphaunt-release-metadata-validation-v1", - products: Object.keys(graph.products).length, - carriers: targetReport.catalog.carriers.length, - catalogDigest: publicationCatalogDigest(targetReport.catalog), - runtimeTargets: targetReport.runtimeTargets, - extensionProducts: targetReport.extensionProducts, - extensionTargets: targetReport.extensionTargets, - compatibilityFields, - sourceNpmManifests: manifests.npm, - sourceCargoManifests: manifests.cargo, - }; - if (args.json) { - console.log(`${JSON.stringify(report, null, 2)}\n`); - } else { - console.log( - `release metadata checks passed (${report.products} products, ${report.carriers} catalog-declared registry carrier minima, ${report.runtimeTargets + report.extensionTargets} artifact targets, ${report.compatibilityFields} compatibility fields)`, - ); - } -} - -if (import.meta.main) { - try { - main(Bun.argv.slice(2)); - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(1); - } -} diff --git a/tools/release/check-release-metadata.mts b/tools/release/check-release-metadata.mts new file mode 100755 index 000000000..9c12897b8 --- /dev/null +++ b/tools/release/check-release-metadata.mts @@ -0,0 +1,568 @@ +#!/usr/bin/env bun + +import { existsSync, readFileSync, statSync } from 'node:fs'; +import path from 'node:path'; +import { + extensionNativeRegistryPackageStrings, + extensionWasixRegistryPackageStrings, +} from '../../src/extensions/artifacts/packages/tools/extension-registry-packages.mts'; +import { + compatibilityVersionSource, + requireCompatibilityVersionBinding, + requireCompatibilityVersionBounds, +} from './compatibility-version-policy.mts'; +import { + declaredCarrierMap, + loadPublicationCatalog, + publicationCatalogDigest, +} from './publication-catalog.mts'; +import { + allArtifactTargets, + exactExtensionProducts, + extensionArtifactTargets, + extensionRegistryPackageTargetSets, + extensionReleaseProduct, + extensionSourceIdentity, + registryPackageRows, + releaseMetadata, +} from './release-artifact-targets.mts'; +import { + compareText, + compatibilityVersionEntries, + compatibilityVersionValue, + latestProductTag, + loadProducts, + parseStableVersion, + productVersionTransitionStatus, + ROOT, + versionFiles, +} from './release-graph.mts'; +import { latestVerifiedReleaseCommit } from './verify-release-commit.mts'; + +const TOOL = 'check-release-metadata.mts'; +const STABLE_VERSION = /^[0-9]+[.][0-9]+[.][0-9]+$/u; +const INSTALL_SCRIPTS = new Set(['preinstall', 'install', 'postinstall']); +const REGISTRY_TARGET_ECOSYSTEM = Object.freeze({ + 'crates-io': 'cargo', + 'maven-central': 'maven', + npm: 'npm', +}); +function fail(message) { + throw new Error(`${TOOL}: ${message}`); +} + +function assert(condition, message) { + if (!condition) { + fail(message); + } +} + +function object(value, label) { + assert( + value !== null && typeof value === 'object' && !Array.isArray(value), + `${label} must be an object`, + ); + return value; +} + +function stringList(value, label, { nonEmpty = false } = {}) { + assert( + Array.isArray(value) && value.every((entry) => typeof entry === 'string' && entry.length > 0), + `${label} must be a list of non-empty strings`, + ); + assert(!nonEmpty || value.length > 0, `${label} must not be empty`); + assert(new Set(value).size === value.length, `${label} must not contain duplicates`); + return value; +} + +function sorted(values) { + return [...values].sort(compareText); +} + +function sameStrings(left, right) { + return JSON.stringify(sorted(left)) === JSON.stringify(sorted(right)); +} + +function readJson(relativePath) { + try { + return object(JSON.parse(readFileSync(path.join(ROOT, relativePath), 'utf8')), relativePath); + } catch (error) { + fail(`${relativePath} is not valid JSON: ${error.message}`); + } +} + +function readToml(relativePath) { + try { + return object( + Bun.TOML.parse(readFileSync(path.join(ROOT, relativePath), 'utf8')), + relativePath, + ); + } catch (error) { + fail(`${relativePath} is not valid TOML: ${error.message}`); + } +} + +function requireFile(relativePath, label = relativePath) { + const absolute = path.join(ROOT, relativePath); + assert( + existsSync(absolute) && statSync(absolute).isFile(), + `${label} does not exist: ${relativePath}`, + ); +} + +function stableVersion(value, label) { + assert( + typeof value === 'string' && STABLE_VERSION.test(value), + `${label} must be stable x.y.z, got ${JSON.stringify(value)}`, + ); + parseStableVersion(value, TOOL); + return value; +} + +function dottedValue(value, expression, label) { + assert( + typeof expression === 'string' && expression.startsWith('$.') && expression.length > 2, + `${label} must use $.path syntax`, + ); + let cursor = value; + for (const key of expression.slice(2).split('.')) { + assert( + cursor !== null && typeof cursor === 'object' && !Array.isArray(cursor) && key in cursor, + `${label} does not resolve ${expression}`, + ); + cursor = cursor[key]; + } + return cursor; +} + +function genericMarkedVersion(relativePath) { + const text = readFileSync(path.join(ROOT, relativePath), 'utf8'); + const singleLines = text + .split(/\r?\n/u) + .filter((line) => line.includes('x-release-please-version')); + if (singleLines.length === 1) { + const matches = singleLines[0].match(/[0-9]+[.][0-9]+[.][0-9]+/gu) ?? []; + assert( + matches.length === 1, + `${relativePath} release-please version marker must own exactly one stable version`, + ); + return matches[0]; + } + const block = /x-release-please-start-version(?[\s\S]*?)x-release-please-end/u.exec(text) + ?.groups?.body; + assert( + singleLines.length === 0 && block !== undefined, + `${relativePath} must have one release-please version marker or marker block`, + ); + const matches = block.match(/[0-9]+[.][0-9]+[.][0-9]+/gu) ?? []; + assert( + matches.length === 1, + `${relativePath} release-please version block must own exactly one stable version`, + ); + return matches[0]; +} + +function conventionalVersion(relativePath) { + const basename = path.basename(relativePath); + const text = readFileSync(path.join(ROOT, relativePath), 'utf8'); + if (basename === 'Cargo.toml') { + const manifest = readToml(relativePath); + return object(manifest.package, `${relativePath}.package`).version; + } + if (basename === 'package.json') { + return readJson(relativePath).version; + } + if (basename === 'VERSION' || basename === 'LIBOLIPHAUNT_VERSION') { + return text.trim(); + } + if (basename === 'gradle.properties') { + const matches = [...text.matchAll(/^VERSION_NAME=(.+)$/gmu)].map((match) => match[1].trim()); + assert(matches.length === 1, `${relativePath} must declare VERSION_NAME exactly once`); + return matches[0]; + } + return genericMarkedVersion(relativePath); +} + +function releasePleaseVersion(relativePath, entry) { + if (typeof entry === 'string') { + return conventionalVersion(relativePath); + } + const type = entry.type ?? 'generic'; + if (type === 'generic') { + return conventionalVersion(relativePath); + } + const parsers = { + json: readJson, + toml: readToml, + yaml: (file) => object(Bun.YAML.parse(readFileSync(path.join(ROOT, file), 'utf8')), file), + }; + const parser = parsers[type]; + assert( + parser !== undefined, + `${relativePath} uses unsupported structured release-please type ${JSON.stringify(type)}`, + ); + const value = parser(relativePath); + return dottedValue(value, entry.jsonpath, `${relativePath}.jsonpath`); +} + +function validateReleasePleaseVersions(graph) { + const config = readJson('release-please-config.json'); + const manifest = readJson('.release-please-manifest.json'); + const packages = object(config.packages, 'release-please-config.json.packages'); + const productsByPath = new Map( + Object.entries(graph.products).map(([product, productConfig]) => [productConfig.path, product]), + ); + assert( + sameStrings(Object.keys(packages), productsByPath.keys()), + 'release-please package paths must exactly match release graph products', + ); + assert( + sameStrings(Object.keys(manifest), productsByPath.keys()), + 'release-please manifest paths must exactly match release graph products', + ); + + for (const [packagePath, packageConfigValue] of Object.entries(packages)) { + const packageConfig = object(packageConfigValue, `release-please packages.${packagePath}`); + const product = productsByPath.get(packagePath); + const productConfig = graph.products[product]; + assert(packageConfig.component === product, `${packagePath}.component must be ${product}`); + assert( + manifest[packagePath] === productConfig.version, + `${packagePath} release-please manifest version must match ${product}`, + ); + const changelog = packageConfig['changelog-path'] ?? 'CHANGELOG.md'; + assert( + typeof changelog === 'string' && changelog.length > 0, + `${packagePath}.changelog-path must be a non-empty string`, + ); + const changelogPath = path.posix.join(packagePath, changelog); + requireFile(changelogPath, `${product} changelog`); + if (manifest[packagePath] === '0.0.0') { + assert( + readFileSync(path.join(ROOT, changelogPath)).length === 0, + `${product} unreleased 0.0.0 changelog must be exactly empty so Release Please can create its canonical heading`, + ); + } + assert( + productConfig.changelog_path === changelogPath, + `${product} graph changelog must match release-please`, + ); + + const releaseType = packageConfig['release-type']; + const canonical = + packageConfig['version-file'] ?? + (releaseType === 'rust' + ? 'Cargo.toml' + : ['node', 'expo'].includes(releaseType) + ? 'package.json' + : undefined); + assert( + typeof canonical === 'string' && canonical.length > 0, + `${packagePath} must declare a canonical version file`, + ); + const extraFiles = packageConfig['extra-files'] ?? []; + assert(Array.isArray(extraFiles), `${packagePath}.extra-files must be a list`); + const entries = [canonical, ...extraFiles].map((entry) => ({ + entry, + relative: typeof entry === 'string' ? entry : entry.path, + })); + for (const { entry, relative } of entries) { + assert( + typeof relative === 'string' && relative.length > 0, + `${packagePath} version-file entry must declare a path`, + ); + const file = path.posix.join(packagePath, relative); + requireFile(file, `${product} version file`); + const value = releasePleaseVersion(file, entry); + assert( + value === productConfig.version, + `${file} version ${JSON.stringify(value)} must match ${product} ${productConfig.version}`, + ); + } + const files = entries.map(({ relative }) => path.posix.join(packagePath, relative)); + assert( + sameStrings(files, versionFiles(product, TOOL)), + `${product} release graph version files must match release-please`, + ); + } +} + +function validateCompatibility(graph, { publication = false } = {}) { + const entries = compatibilityVersionEntries(graph.products, { + requireSourceProduct: true, + prefix: TOOL, + }); + assert( + new Set(entries.map((entry) => entry.id)).size === entries.length, + 'compatibility field ids must be globally unique', + ); + let pendingRelease; + let checkedPendingRelease = false; + let pendingVersions = new Map(); + const versionSources = new Map(); + for (const entry of entries) { + const value = compatibilityVersionValue(entry, { prefix: TOOL }); + if (!publication) { + requireCompatibilityVersionBounds( + { + id: entry.id, + value, + sourceProduct: entry.sourceProduct, + sourceVersion: graph.products[entry.sourceProduct].version, + }, + { prefix: TOOL }, + ); + continue; + } + let source = versionSources.get(entry.product); + if (source === undefined) { + const product = graph.products[entry.product]; + if (!checkedPendingRelease && product.version !== '0.0.0') { + const baseRef = latestProductTag(product, 'HEAD', TOOL, ROOT); + const status = productVersionTransitionStatus(entry.product, product, baseRef, 'HEAD', { + prefix: TOOL, + root: ROOT, + }); + // Published compatibility pins already have immutable tag provenance. + // Only an unpublished version needs its release commit validated. + if (status.currentTagCommit === null) { + pendingRelease = latestVerifiedReleaseCommit({ repo: ROOT }); + pendingVersions = new Map(Object.entries(pendingRelease?.versions ?? {})); + checkedPendingRelease = true; + } + } + source = compatibilityVersionSource(entry, graph.products, pendingVersions, { + headRef: 'HEAD', + pendingCommit: pendingRelease?.commit, + prefix: TOOL, + root: ROOT, + }); + versionSources.set(entry.product, source); + } + const expected = + source.kind === 'tagged-sink' + ? compatibilityVersionValue(entry, { + ref: source.ref, + prefix: TOOL, + // A compatibility pin can become explicit before the sink's next + // release. Once published, its immutable tag supplies this value. + missingValue: value, + }) + : graph.products[entry.sourceProduct].version; + const provenance = + source.kind === 'tagged-sink' + ? `immutable ${entry.product} tag ${source.tag}` + : `${entry.sourceProduct} ${expected}`; + requireCompatibilityVersionBinding( + { + id: entry.id, + value, + expected, + sourceProduct: entry.sourceProduct, + sourceVersion: graph.products[entry.sourceProduct].version, + provenance, + }, + { prefix: TOOL }, + ); + } + return entries.length; +} + +function validateNpmManifest(relativePath, product, catalogCarriers) { + const manifest = readJson(relativePath); + assert( + typeof manifest.name === 'string' && manifest.name.length > 0, + `${relativePath}.name must be non-empty`, + ); + assert( + manifest.version === product.version, + `${relativePath}.version must match ${product.id} ${product.version}`, + ); + const scripts = object(manifest.scripts ?? {}, `${relativePath}.scripts`); + for (const [name, command] of Object.entries(scripts)) { + assert(typeof command === 'string', `${relativePath}.scripts.${name} must be a string`); + assert( + !INSTALL_SCRIPTS.has(name), + `${relativePath} must not run ${name} during consumer installation`, + ); + } + if (manifest.private !== true) { + const carrier = catalogCarriers.get(`npm:${manifest.name}`); + assert( + carrier?.product === product.id, + `${relativePath} public npm identity ${manifest.name} must belong to ${product.id} in the publication catalog`, + ); + assert( + manifest.publishConfig?.access === 'public', + `${relativePath}.publishConfig.access must be public`, + ); + assert( + manifest.publishConfig?.provenance === true, + `${relativePath}.publishConfig.provenance must be true`, + ); + } +} + +function validateCargoManifest(relativePath, product, catalogCarriers) { + const manifest = readToml(relativePath); + const packageConfig = object(manifest.package, `${relativePath}.package`); + assert( + typeof packageConfig.name === 'string' && packageConfig.name.length > 0, + `${relativePath}.package.name must be non-empty`, + ); + assert( + packageConfig.version === product.version, + `${relativePath}.package.version must match ${product.id} ${product.version}`, + ); + if (packageConfig.publish !== false) { + const carrier = catalogCarriers.get(`cargo:${packageConfig.name}`); + assert( + carrier?.product === product.id, + `${relativePath} publishable Cargo identity ${packageConfig.name} must belong to ${product.id}`, + ); + } +} + +function validateSourcePackageManifests(graph, catalog) { + const carriers = declaredCarrierMap(catalog); + let npm = 0; + let cargo = 0; + for (const [id, config] of Object.entries(graph.products)) { + const product = { id, ...config }; + for (const file of config.version_files) { + if (path.basename(file) === 'package.json') { + validateNpmManifest(file, product, carriers); + npm += 1; + } else if (path.basename(file) === 'Cargo.toml') { + validateCargoManifest(file, product, carriers); + cargo += 1; + } + } + } + return { npm, cargo }; +} + +function validateCatalogAndTargets(graph) { + const catalog = loadPublicationCatalog(TOOL); + for (const [product, config] of Object.entries(graph.products)) { + for (const [target, ecosystem] of Object.entries(REGISTRY_TARGET_ECOSYSTEM)) { + const count = catalog.carriers.filter( + (carrier) => carrier.product === product && carrier.ecosystem === ecosystem, + ).length; + assert( + config.publish_targets.includes(target) === count > 0, + `${product} ${target} target and ${ecosystem} carrier declarations must agree`, + ); + } + } + + const runtimeTargets = allArtifactTargets({}, TOOL); + assert(runtimeTargets.length > 0, 'runtime artifact target catalog must not be empty'); + const carriers = declaredCarrierMap(catalog); + for (const target of runtimeTargets.filter((row) => row.npmPackage !== undefined)) { + assert( + carriers.get(`npm:${target.npmPackage}`)?.product === target.product, + `${target.id} npm package must be declared by ${target.product}`, + ); + } + + const extensionProducts = exactExtensionProducts(TOOL); + let extensionTargets = 0; + for (const product of extensionProducts) { + extensionSourceIdentity(product, TOOL); + const targets = extensionArtifactTargets({ product }, TOOL); + assert( + targets.some((target) => target.family === 'native'), + `${product} must publish at least one native target`, + ); + assert( + targets.some((target) => target.family === 'wasix'), + `${product} must publish at least one WASIX target`, + ); + const targetSets = extensionRegistryPackageTargetSets(product, TOOL); + const expectedNative = extensionNativeRegistryPackageStrings({ product, ...targetSets }); + const expectedWasix = extensionWasixRegistryPackageStrings({ + product, + includeAot: targetSets.includeWasixAot, + }); + assert( + expectedNative.every((entry) => !expectedWasix.includes(entry)), + `${product} native and WASIX registry package families must be disjoint`, + ); + const nativeOwner = extensionReleaseProduct(product, 'native', TOOL); + const wasixOwner = extensionReleaseProduct(product, 'wasix', TOOL); + const nativeDeclared = registryPackageRows({ product: nativeOwner }, TOOL) + .map((entry) => `${entry.packageKind}:${entry.packageName}`) + .filter((entry) => expectedNative.includes(entry)); + const wasixDeclared = registryPackageRows({ product: wasixOwner }, TOOL) + .map((entry) => `${entry.packageKind}:${entry.packageName}`) + .filter((entry) => expectedWasix.includes(entry)); + assert( + sameStrings(expectedNative, nativeDeclared) && sameStrings(expectedWasix, wasixDeclared), + `${product} registry packages must be owned by its native and WASIX release products`, + ); + extensionTargets += targets.length; + } + + return { + catalog, + runtimeTargets: runtimeTargets.length, + extensionProducts: extensionProducts.length, + extensionTargets, + }; +} + +function parseArgs(argv) { + let json = false; + let publication = false; + for (const arg of argv) { + if (arg === '--json') { + json = true; + } else if (arg === '--publication') { + publication = true; + } else if (arg === '-h' || arg === '--help') { + console.log('usage: tools/release/check-release-metadata.mts [--json] [--publication]'); + process.exit(0); + } else { + fail(`unknown argument ${arg}`); + } + } + return { json, publication }; +} + +function main(argv) { + const args = parseArgs(argv); + const graph = { products: loadProducts(TOOL) }; + validateReleasePleaseVersions(graph); + const compatibilityFields = validateCompatibility(graph, args); + const targetReport = validateCatalogAndTargets(graph); + const manifests = validateSourcePackageManifests(graph, targetReport.catalog); + const report = { + schema: 'oliphaunt-release-metadata-validation-v1', + products: Object.keys(graph.products).length, + carriers: targetReport.catalog.carriers.length, + catalogDigest: publicationCatalogDigest(targetReport.catalog), + runtimeTargets: targetReport.runtimeTargets, + extensionProducts: targetReport.extensionProducts, + extensionTargets: targetReport.extensionTargets, + compatibilityFields, + sourceNpmManifests: manifests.npm, + sourceCargoManifests: manifests.cargo, + }; + if (args.json) { + console.log(`${JSON.stringify(report, null, 2)}\n`); + } else { + console.log( + `release metadata checks passed (${report.products} products, ${report.carriers} catalog-declared registry carrier minima, ${report.runtimeTargets + report.extensionTargets} artifact targets, ${report.compatibilityFields} compatibility fields)`, + ); + } +} + +if (import.meta.main) { + try { + main(Bun.argv.slice(2)); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exit(1); + } +} diff --git a/tools/release/check-release-versions.sh b/tools/release/check-release-versions.sh new file mode 100644 index 000000000..84c8c3f4d --- /dev/null +++ b/tools/release/check-release-versions.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +head_ref=HEAD +args=("$@") +for ((index=0; index<${#args[@]}; index++)); do + case "${args[index]}" in + --head-ref) + index=$((index + 1)) + head_ref="${args[index]:?--head-ref requires a value}" ;; + --head-ref=*) head_ref="${args[index]#*=}" ;; + esac +done +RELEASE_HEAD_COMMIT=$(git rev-parse --verify --end-of-options "$head_ref^{commit}") +export RELEASE_HEAD_COMMIT +bash tools/release/with-release-tags.sh bash tools/dev/bun.sh tools/release/check_release_versions.mts "$@" diff --git a/tools/release/check-staged-artifacts.mjs b/tools/release/check-staged-artifacts.mjs deleted file mode 100644 index 85ef79a03..000000000 --- a/tools/release/check-staged-artifacts.mjs +++ /dev/null @@ -1,2982 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import { - existsSync, - readdirSync, - readFileSync, - statSync, -} from "node:fs"; -import path from "node:path"; - -import { - ROOT, - allArtifactTargets, - compareText, - currentProductVersion, - exactExtensionProducts, - extensionArtifactProductRoot, - extensionArtifactTargets, - extensionMetadata, - extensionReleaseProduct, - extensionReleaseVersion, - extensionSourceIdentity, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { loadGraph, productCompatibilityVersion } from "./release-graph.mjs"; -import { extensionRuntimeAssetContract } from "./extension-runtime-asset-contract.mjs"; -import { - assertSameNativeTargetSet, - rustNativeTargetCfg, -} from "./rust-native-targets.mjs"; -import { - AOT_PACKAGES as WASIX_AOT_PACKAGES, - AOT_TARGET_CFGS as WASIX_AOT_TARGET_CFGS, - AOT_TARGET_TRIPLES as WASIX_AOT_TARGET_TRIPLES, - ICU_PACKAGE, - RUNTIME_PACKAGE as WASIX_RUNTIME_PACKAGE, - TOOLS_AOT_PACKAGES as WASIX_TOOLS_AOT_PACKAGES, - TOOLS_PACKAGE as WASIX_TOOLS_PACKAGE, -} from "./wasix-cargo-artifact-contract.mjs"; -import { - IOS_CARRIER_FILENAME, - buildSwiftExtensionCarrierManifest, - swiftExtensionCarrierAssetName, -} from "./ios-carrier-manifest.mjs"; -import { - portableMemberName, - readAndroidApkEntries, - readCanonicalTarGzipEntries, - readPortableArchiveEntries, -} from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - assertReleaseNoticesInArchive, - releaseNoticeRows, -} from "./release-notices.mjs"; -import { - assertExtensionUpstreamLicensesInArchive, - extensionCarrierLegalContract, -} from "./extension-upstream-licenses.mjs"; -import { - assertSourceOnlyNpmArchive, - SOURCE_ONLY_NPM_PROFILES, -} from "./source-only-sdk-package.mjs"; -import { assertWasixTypescriptNpmArchive } from "./wasix-typescript-package.mjs"; -import { assertWasixToolsTypescriptNpmArchive } from "./wasix-tools-typescript-package.mjs"; -import { assertWasixExtensionMemberInstall } from "../../src/shared/extension-runtime-contract/wasix-extension-install.mjs"; -import { - validateSelectionNeutralSwiftCarrierIdentity, - validateSelectionNeutralSwiftSourceCarrierFile, - validateSwiftSourceReleaseContract, -} from "./swift-source-carrier-contract.mjs"; -import { validateMobileRuntimeFiles } from "../../src/sdks/react-native/tools/validate-mobile-runtime-files.mjs"; - -const PREFIX = "check-staged-artifacts.mjs"; -const SDK_ROOT = path.join(ROOT, "target/sdk-artifacts"); -const EXTENSION_ROOT = path.resolve( - ROOT, - process.env.OLIPHAUNT_EXTENSION_ARTIFACT_ROOT ?? "target/extension-artifacts", -); -if (path.relative(ROOT, EXTENSION_ROOT).startsWith("..")) { - throw new Error("extension artifact root must stay inside the repository"); -} -const MOBILE_ROOT = path.join(ROOT, "target/mobile-build/react-native"); -const SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT = path.join( - ROOT, - "src/sdks/swift/Tests/Fixtures/swiftpm-extension-resources", -); -const SWIFT_SOURCE_FIXTURE_ARCHIVE_ROOT = "package/Tests/Fixtures/swiftpm-extension-resources"; -const REACT_NATIVE_EXTENSION_METADATA = path.join( - ROOT, - "src/extensions/generated/sdk/extensions.json", -); -const MOBILE_STATIC_REGISTRY = path.join( - ROOT, - "src/extensions/generated/mobile/static-registry.json", -); - -const PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS = new Set([ - "schema", - "product", - "version", - "sqlName", - "extensionClass", - "versioning", - "sourceIdentity", - "compatibility", - "createsExtension", - "dependencies", - "dataFiles", - "extensionSqlFileNames", - "extensionSqlFilePrefixes", - "nativeModuleStem", - "iosNativeDependencies", - "iosRegistration", - "wasixInstall", - "sharedPreloadLibraries", - "assets", -]); -const PUBLIC_EXTENSION_BUNDLE_RELEASE_MANIFEST_KEYS = new Set([ - "schema", - "product", - "version", - "extensionClass", - "versioning", - "sourceIdentity", - "compatibility", - "extensions", - "assets", -]); -const EXTENSION_BUNDLE_MEMBER_KEYS = new Set([ - "sqlName", - "createsExtension", - "dependencies", - "dataFiles", - "extensionSqlFileNames", - "extensionSqlFilePrefixes", - "nativeModuleStem", - "iosNativeDependencies", - "iosRegistration", - "wasixInstall", - "sharedPreloadLibraries", - "assets", -]); -const PUBLIC_EXTENSION_RELEASE_ASSET_KEYS = new Set([ - "name", - "family", - "target", - "kind", - "identity", - "sha256", - "bytes", -]); -const PUBLIC_EXTENSION_RELEASE_ASSET_KEY_ORDER = [ - "name", - "family", - "target", - "kind", - "identity", - "sha256", - "bytes", -]; -const PUBLIC_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS = new Set([ - ...PUBLIC_EXTENSION_RELEASE_ASSET_KEY_ORDER, - "carrierAsset", - "carrierRoot", - "memberPath", -]); -const PUBLIC_EXTENSION_BUNDLE_CARRIER_ASSET_KEYS = new Set([ - "name", - "family", - "target", - "kind", - "sha256", - "bytes", - "memberCount", -]); -const INTERNAL_EXTENSION_BUNDLE_ROOT_KEYS = new Set([ - "schema", - "product", - "version", - "compatibility", - "extensions", - "carrierAssets", -]); -const INTERNAL_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS = new Set([ - "name", - "path", - "source", - "sha256", - "bytes", - "family", - "kind", - "target", - "identity", - "carrierAsset", - "carrierRoot", - "memberPath", -]); -const INTERNAL_EXTENSION_BUNDLE_CARRIER_ASSET_KEYS = new Set([ - "name", - "path", - "sha256", - "bytes", - "family", - "target", - "kind", - "memberCount", -]); -const SDK_RUNTIME_PAYLOAD_PATTERNS = [ - /(^|\/)assets\/oliphaunt\/runtime\//u, - /(^|\/)assets\/oliphaunt\/cluster-seed\//u, - /(^|\/)assets\/oliphaunt\/static-registry\/archives\//u, - /(^|\/)oliphaunt\/runtime\/files\//u, - /(^|\/)runtime\/files\/share\/postgresql\//u, - /(^|\/)share\/postgresql\/extension\/[^/]+\.(control|sql)$/u, - /(^|\/)release-assets\//u, - /(^|\/)extension-artifacts\.json$/u, - /(^|\/)liboliphaunt\.(so|dylib|dll|a|lib)$/u, - /(^|\/)liboliphaunt_extensions\.(so|dylib|dll|a|lib)$/u, - /(^|\/)liboliphaunt_extension_[^/]+\.(so|dylib|dll|a|lib)$/u, - /\.xcframework(\/|$)/u, -]; -const KOTLIN_ALLOWED_NATIVE_PAYLOADS = new Set(["liboliphaunt_kotlin_android.so"]); -const KOTLIN_RELEASE_ABIS = new Set(["arm64-v8a", "x86_64"]); -const IOS_EXTENSION_LINK_PREFIX = "liboliphaunt_extension_"; -const IOS_EXTENSION_LINK_STEM = /^[a-z_][a-z0-9_-]{0,127}$/u; -function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(1); -} - -function rel(file) { - const relative = path.relative(ROOT, String(file)); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - return String(file).split(path.sep).join("/"); - } - return relative.split(path.sep).join("/"); -} - -function isFile(file) { - try { - return statSync(file).isFile(); - } catch { - return false; - } -} - -function isDirectory(file) { - try { - return statSync(file).isDirectory(); - } catch { - return false; - } -} - -function sha256File(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function readJson(file) { - let data; - try { - data = JSON.parse(readFileSync(file, "utf8")); - } catch (error) { - fail(`${rel(file)} is not valid JSON: ${error.message}`); - } - if (data === null || Array.isArray(data) || typeof data !== "object") { - fail(`${rel(file)} must contain a JSON object`); - } - return data; -} - -export function parseUniquePropertiesText(text) { - const entries = new Map(); - for (const raw of text.split(/\r?\n/u)) { - const line = raw.trim(); - if (!line || line.startsWith("#")) { - continue; - } - const equals = line.indexOf("="); - if (equals < 0) { - throw new Error(`invalid properties line: ${JSON.stringify(raw)}`); - } - const key = line.slice(0, equals); - if (!key) { - throw new Error(`properties key must not be empty: ${JSON.stringify(raw)}`); - } - if (entries.has(key)) { - throw new Error(`properties text repeats key ${JSON.stringify(key)}`); - } - entries.set(key, line.slice(equals + 1)); - } - // Object.fromEntries defines every key as data, including names such as - // __proto__. Exact manifest comparison can therefore reject hostile or - // undeclared keys instead of losing them through prototype assignment. - return Object.fromEntries(entries); -} - -function readPropertiesText(text) { - try { - return parseUniquePropertiesText(text); - } catch (error) { - fail(error.message); - } -} - -function csvValues(value) { - if (!value) { - return []; - } - return String(value).split(",").map((item) => item.trim()).filter(Boolean); -} - -const ARCHIVE_ENTRY_CACHE = new Map(); -const ARCHIVE_ENTRY_CACHE_LIMIT = 2; - -function strictArchiveEntries(file, format) { - const fileStat = statSync(file, { bigint: true }); - const cacheKey = [ - format, - path.resolve(file), - fileStat.dev, - fileStat.ino, - fileStat.size, - fileStat.mtimeNs, - fileStat.ctimeNs, - ].join("\0"); - const cached = ARCHIVE_ENTRY_CACHE.get(cacheKey); - if (cached !== undefined) { - ARCHIVE_ENTRY_CACHE.delete(cacheKey); - ARCHIVE_ENTRY_CACHE.set(cacheKey, cached); - return cached; - } - let entries; - try { - entries = readPortableArchiveEntries(file, { format }); - } catch (error) { - fail(`${rel(file)} is not a strict portable ${format} archive: ${error.message}`); - } - ARCHIVE_ENTRY_CACHE.set(cacheKey, entries); - while (ARCHIVE_ENTRY_CACHE.size > ARCHIVE_ENTRY_CACHE_LIMIT) { - ARCHIVE_ENTRY_CACHE.delete(ARCHIVE_ENTRY_CACHE.keys().next().value); - } - return entries; -} - -function strictAndroidApkEntries(file) { - const fileStat = statSync(file, { bigint: true }); - const cacheKey = [ - "android-apk", - path.resolve(file), - fileStat.dev, - fileStat.ino, - fileStat.size, - fileStat.mtimeNs, - fileStat.ctimeNs, - ].join("\0"); - const cached = ARCHIVE_ENTRY_CACHE.get(cacheKey); - if (cached !== undefined) { - ARCHIVE_ENTRY_CACHE.delete(cacheKey); - ARCHIVE_ENTRY_CACHE.set(cacheKey, cached); - return cached; - } - let entries; - try { - entries = readAndroidApkEntries(file); - } catch (error) { - fail(`${rel(file)} is not a strict Android APK archive: ${error.message}`); - } - ARCHIVE_ENTRY_CACHE.set(cacheKey, entries); - while (ARCHIVE_ENTRY_CACHE.size > ARCHIVE_ENTRY_CACHE_LIMIT) { - ARCHIVE_ENTRY_CACHE.delete(ARCHIVE_ENTRY_CACHE.keys().next().value); - } - return entries; -} - -function archiveTarNames(file) { - return [...strictArchiveEntries(file, "tar.gz")] - .filter(([, entry]) => entry.isFile) - .map(([name]) => name) - .sort(compareText); -} - -function tarReadBytes(file, member) { - const entry = strictArchiveEntries(file, "tar.gz").get(member); - if (!entry?.isFile) fail(`${rel(file)} is missing regular-file member ${member}`); - return Buffer.from(entry.data()); -} - -function tarReadText(file, member) { - return tarReadBytes(file, member).toString("utf8"); -} - -function canonicalBundleTarEntries(file) { - let archiveEntries; - try { - archiveEntries = readCanonicalTarGzipEntries(file, { fileMode: 0o644 }); - } catch (error) { - fail(`${rel(file)} is not an exact canonical bundle: ${error.message}`); - } - const entries = new Map(); - for (const [name, entry] of archiveEntries) { - entries.set(name, Buffer.from(entry.data())); - } - if (entries.size === 0) { - fail(`${rel(file)} must contain at least one regular file and a canonical tar end marker`); - } - return entries; -} - -function cargoCrateManifest(file) { - const manifests = archiveTarNames(file).filter((name) => name.split("/").length === 2 && name.endsWith("/Cargo.toml")); - if (manifests.length !== 1) { - fail(`${rel(file)} must contain exactly one top-level Cargo.toml`); - } - let data; - try { - data = Bun.TOML.parse(tarReadText(file, manifests[0])); - } catch (error) { - fail(`${rel(file)} contains an invalid Cargo.toml: ${error.message}`); - } - if (data === null || Array.isArray(data) || typeof data !== "object") { - fail(`${rel(file)} Cargo.toml must contain a TOML table`); - } - return data; -} - -const CARGO_VIRTUAL_PACKAGE_FILES = new Set([ - ".cargo_vcs_info.json", - "Cargo.lock", - "Cargo.toml.orig", -]); -export function cargoPackageMemberContractViolation(actual, listed) { - if (new Set(listed).size !== listed.length) { - return { kind: "listing-duplicate" }; - } - const expected = listed.filter((entry) => !CARGO_VIRTUAL_PACKAGE_FILES.has(entry)); - const actualSorted = [...actual].sort(compareText); - const expectedSorted = [...expected].sort(compareText); - if (JSON.stringify(actualSorted) !== JSON.stringify(expectedSorted)) { - return { kind: "mismatch", actual: actualSorted, expected: expectedSorted }; - } - return null; -} - -function requireCrateMatchesCargoListing( - crate, - listing, - packageName, - packageVersion, -) { - if (!isFile(listing)) { - fail(`missing Cargo package listing: ${rel(listing)}`); - } - const listed = readFileSync(listing, "utf8") - .split(/\r?\n/u) - .map((entry) => entry.trim()) - .filter(Boolean); - const prefix = `${packageName}-${packageVersion}/`; - const actual = archiveTarNames(crate).map((entry) => { - if (!entry.startsWith(prefix) || entry.length === prefix.length) { - fail(`${rel(crate)} contains member outside ${prefix.slice(0, -1)}: ${entry}`); - } - return entry.slice(prefix.length); - }); - const violation = cargoPackageMemberContractViolation(actual, listed); - if (violation?.kind === "listing-duplicate") { - fail(`${rel(listing)} repeats a Cargo package entry`); - } - if (violation?.kind === "mismatch") { - fail( - `${rel(crate)} Cargo-selected package members mismatch: ` - + `expected=${JSON.stringify(violation.expected)}, actual=${JSON.stringify(violation.actual)}`, - ); - } -} - -function readZipEntries(file) { - return strictArchiveEntries(file, "zip"); -} - -function archiveZipNames(file) { - return [...readZipEntries(file)] - .filter(([, entry]) => entry.isFile) - .map(([name]) => name) - .sort(compareText); -} - -function zipReadText(file, name) { - const entry = readZipEntries(file).get(name); - if (!entry || !entry.isFile) { - fail(`${rel(file)} is missing ${name}`); - } - try { - return Buffer.from(entry.data()).toString("utf8"); - } catch (error) { - fail(`${rel(file)} member ${name} is not readable UTF-8: ${error.message}`); - } -} - -function archiveAndroidApkNames(file) { - return [...strictAndroidApkEntries(file)] - .filter(([, entry]) => entry.isFile) - .map(([name]) => name) - .sort(compareText); -} - -function androidApkReadText(file, name) { - const entry = strictAndroidApkEntries(file).get(name); - if (!entry || !entry.isFile) { - fail(`${rel(file)} is missing ${name}`); - } - try { - return Buffer.from(entry.data()).toString("utf8"); - } catch (error) { - fail(`${rel(file)} member ${name} is not readable UTF-8: ${error.message}`); - } -} - -function validateZstdArchiveMagic(file) { - if (!readFileSync(file).subarray(0, 4).equals(Buffer.from([0x28, 0xb5, 0x2f, 0xfd]))) { - fail(`${rel(file)} is not a zstd archive`); - } -} - -function validateReleaseArchivePayload(file) { - if (file.endsWith(".tar.gz") || file.endsWith(".tgz") || file.endsWith(".crate")) { - if (archiveTarNames(file).length === 0) { - fail(`${rel(file)} must contain at least one file`); - } - return; - } - if (file.endsWith(".zip") || file.endsWith(".aar") || file.endsWith(".jar")) { - if (archiveZipNames(file).length === 0) { - fail(`${rel(file)} must contain at least one file`); - } - return; - } - if (file.endsWith(".tar.zst")) { - validateZstdArchiveMagic(file); - } -} - -function directoryNames(root) { - const result = []; - const visit = (dir) => { - if (!isDirectory(dir)) { - return; - } - for (const name of readdirSync(dir).sort(compareText)) { - const file = path.join(dir, name); - if (isDirectory(file)) { - visit(file); - } else if (isFile(file)) { - result.push(relFrom(root, file)); - } - } - }; - visit(root); - return result.sort(compareText); -} - -function relFrom(root, file) { - return path.relative(root, file).split(path.sep).join("/"); -} - -function pathBytes(file) { - if (isFile(file)) { - return statSync(file).size; - } - if (isDirectory(file)) { - let total = 0; - for (const name of directoryNames(file)) { - total += statSync(path.join(file, ...name.split("/"))).size; - } - return total; - } - fail(`missing path while measuring bytes: ${rel(file)}`); -} - -function dirReadText(root, name) { - const file = path.join(root, ...name.split("/")); - if (!isFile(file)) { - fail(`${rel(root)} is missing ${name}`); - } - return readFileSync(file, "utf8"); -} - -function graphProducts() { - return loadGraph(PREFIX).products; -} - -function sdkProducts() { - return Object.entries(graphProducts()) - .filter(([, config]) => config.kind === "sdk") - .map(([product]) => product) - .sort(compareText); -} - -function publicAotCargoDependencies() { - return Object.fromEntries( - Object.entries(WASIX_AOT_PACKAGES).map(([target, name]) => [ - WASIX_AOT_TARGET_CFGS[WASIX_AOT_TARGET_TRIPLES[target]], - name, - ]), - ); -} - -function publicToolsAotCargoDependencies() { - return Object.fromEntries( - Object.entries(WASIX_TOOLS_AOT_PACKAGES).map(([target, name]) => [ - WASIX_AOT_TARGET_CFGS[WASIX_AOT_TARGET_TRIPLES[target]], - name, - ]), - ); -} - -function exactSortedStrings(label, actual, expected) { - const actualSorted = [...actual].sort(compareText); - const expectedSorted = [...expected].sort(compareText); - if (JSON.stringify(actualSorted) !== JSON.stringify(expectedSorted)) { - fail(`${label} mismatch: expected=${JSON.stringify(expectedSorted)}, actual=${JSON.stringify(actualSorted)}`); - } -} - -function rustSdkArtifactTargets(product, kind, surface) { - return allArtifactTargets({ product, kind, surface }, PREFIX); -} - -function requireRegistryTargetDependency(crate, dependencies, cfg, name, version) { - const dependency = dependencies[name]; - if ( - dependency === null - || Array.isArray(dependency) - || typeof dependency !== "object" - || dependency.version !== `=${version}` - || ["path", "git", "registry"].some((key) => key in dependency) - ) { - fail( - `${rel(crate)} target dependency ${cfg}:${name} must use registry version ` - + `=${version} without path, git, or alternate-registry metadata`, - ); - } -} - -async function validateRustSdkCrate(crate) { - const manifest = cargoCrateManifest(crate); - const packageConfig = manifest.package; - if (packageConfig === null || Array.isArray(packageConfig) || typeof packageConfig !== "object") { - fail(`${rel(crate)} must declare a Cargo package`); - } - const packageName = packageConfig.name; - if (!["oliphaunt", "oliphaunt-build"].includes(packageName)) { - fail(`${rel(crate)} contains unexpected oliphaunt-rust package ${JSON.stringify(packageName)}`); - } - const sdkVersion = await currentProductVersion("oliphaunt-rust", PREFIX); - if (packageConfig.version !== sdkVersion) { - fail(`${rel(crate)} package ${packageName} must use oliphaunt-rust version ${sdkVersion}`); - } - if (packageConfig.license !== "MIT") { - fail(`${rel(crate)} source-only package ${packageName} must declare license MIT`); - } - if (packageName === "oliphaunt") { - const packagedQueryCore = tarReadText( - crate, - `${packageName}-${sdkVersion}/src/query_core.rs`, - ); - const canonicalQueryCore = readFileSync( - path.join(ROOT, "src/shared/rust-query-core/query_core.rs"), - "utf8", - ); - if (packagedQueryCore !== canonicalQueryCore) { - fail(`${rel(crate)} Rust query core is stale relative to src/shared/rust-query-core/query_core.rs`); - } - } - try { - assertReleaseNoticesInArchive(crate, { - profile: "source-sdk", - prefix: `${packageName}-${sdkVersion}`, - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - if (packageName === "oliphaunt-build") { - return packageName; - } - - const nativeTargets = rustSdkArtifactTargets("liboliphaunt-native", "native-runtime", "rust-native-direct"); - const brokerTargets = rustSdkArtifactTargets("oliphaunt-broker", "broker-helper", "rust-broker"); - const targetIds = nativeTargets.map((target) => target.target); - try { - assertSameNativeTargetSet( - "staged oliphaunt Rust SDK native runtime/broker", - targetIds, - brokerTargets.map((target) => target.target), - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - - const targetTables = manifest.target; - if (targetTables === null || Array.isArray(targetTables) || typeof targetTables !== "object") { - fail(`${rel(crate)} oliphaunt package must declare target-specific native release dependencies`); - } - const expectedCfgs = targetIds.map((target) => `cfg(${rustNativeTargetCfg(target)})`); - exactSortedStrings(`${rel(crate)} native target tables`, Object.keys(targetTables), expectedCfgs); - - const nativeVersion = productCompatibilityVersion("oliphaunt-rust", "liboliphaunt-native", PREFIX); - const brokerVersion = productCompatibilityVersion("oliphaunt-rust", "oliphaunt-broker", PREFIX); - for (const target of nativeTargets) { - const cfg = `cfg(${rustNativeTargetCfg(target)})`; - const table = targetTables[cfg]; - const dependencies = table && typeof table === "object" && !Array.isArray(table) - ? table.dependencies - : null; - if (dependencies === null || Array.isArray(dependencies) || typeof dependencies !== "object") { - fail(`${rel(crate)} target table ${cfg} must declare release dependencies`); - } - const expectedDependencies = [ - `liboliphaunt-native-${target.target}`, - `oliphaunt-broker-${target.target}`, - ]; - exactSortedStrings( - `${rel(crate)} target dependencies for ${cfg}`, - Object.keys(dependencies), - expectedDependencies, - ); - requireRegistryTargetDependency(crate, dependencies, cfg, expectedDependencies[0], nativeVersion); - requireRegistryTargetDependency(crate, dependencies, cfg, expectedDependencies[1], brokerVersion); - } - - const sourceMembers = archiveTarNames(crate).filter((name) => name.endsWith("/src/lib.rs")); - if (sourceMembers.length !== 1) { - fail(`${rel(crate)} oliphaunt package must contain exactly one src/lib.rs`); - } - const source = tarReadText(crate, sourceMembers[0]); - for (const fragment of [ - "Generated release-only native target guard.", - "compile_error!", - "oliphaunt-wasix", - ...targetIds, - ]) { - if (!source.includes(fragment)) { - fail(`${rel(crate)} oliphaunt release source is missing ${JSON.stringify(fragment)}`); - } - } - return packageName; -} - -async function validateWasixSdkCrate(crate) { - const manifest = cargoCrateManifest(crate); - const packageConfig = manifest.package; - if (packageConfig === null || Array.isArray(packageConfig) || typeof packageConfig !== "object" || packageConfig.name !== "oliphaunt-wasix") { - fail(`${rel(crate)} must package the oliphaunt-wasix crate`); - } - const sdkVersion = await currentProductVersion("oliphaunt-wasix-rust", PREFIX); - if (packageConfig.version !== sdkVersion) { - fail(`${rel(crate)} package oliphaunt-wasix must use version ${sdkVersion}`); - } - const packagedQueryCore = tarReadText( - crate, - `oliphaunt-wasix-${sdkVersion}/src/oliphaunt/query_core.rs`, - ); - const canonicalQueryCore = readFileSync( - path.join(ROOT, "src/shared/rust-query-core/query_core.rs"), - "utf8", - ); - if (packagedQueryCore !== canonicalQueryCore) { - fail(`${rel(crate)} Rust query core is stale relative to src/shared/rust-query-core/query_core.rs`); - } - const runtimeVersion = productCompatibilityVersion( - "oliphaunt-wasix-rust", - "liboliphaunt-wasix", - PREFIX, - ); - const dependencies = manifest.dependencies; - if (dependencies === null || Array.isArray(dependencies) || typeof dependencies !== "object") { - fail(`${rel(crate)} must declare Cargo dependencies`); - } - for (const name of [WASIX_RUNTIME_PACKAGE, WASIX_TOOLS_PACKAGE, ICU_PACKAGE].sort(compareText)) { - const dependency = dependencies[name]; - if (dependency === null || Array.isArray(dependency) || typeof dependency !== "object" || dependency.version !== `=${runtimeVersion}` || "path" in dependency) { - fail(`${rel(crate)} dependency ${name} must use registry version =${runtimeVersion} without a path`); - } - } - const targetTables = manifest.target; - if (targetTables === null || Array.isArray(targetTables) || typeof targetTables !== "object") { - fail(`${rel(crate)} must declare target-specific WASIX AOT dependencies`); - } - const expectedTargets = new Map(); - for (const [cfg, name] of Object.entries(publicAotCargoDependencies())) { - if (!expectedTargets.has(cfg)) { - expectedTargets.set(cfg, []); - } - expectedTargets.get(cfg).push(name); - } - for (const [cfg, name] of Object.entries(publicToolsAotCargoDependencies())) { - if (!expectedTargets.has(cfg)) { - expectedTargets.set(cfg, []); - } - expectedTargets.get(cfg).push(name); - } - for (const [cfg, crates] of [...expectedTargets].sort(([left], [right]) => compareText(left, right))) { - const target = targetTables[cfg]; - const targetDependencies = target && typeof target === "object" && !Array.isArray(target) ? (target.dependencies ?? {}) : {}; - for (const name of crates.sort(compareText)) { - const dependency = targetDependencies[name]; - if (dependency === null || Array.isArray(dependency) || typeof dependency !== "object" || dependency.version !== `=${runtimeVersion}` || "path" in dependency) { - fail(`${rel(crate)} target dependency ${cfg}:${name} must use registry version =${runtimeVersion} without a path`); - } - } - } -} - -function generatedExtensionRows() { - const data = readJson(REACT_NATIVE_EXTENSION_METADATA); - const rows = data.extensions; - if (!Array.isArray(rows)) { - fail(`${rel(REACT_NATIVE_EXTENSION_METADATA)} must contain an extensions array`); - } - const result = new Map(); - for (const row of rows) { - if (row && typeof row === "object" && !Array.isArray(row)) { - const sqlName = row["sql-name"]; - if (typeof sqlName === "string" && sqlName) { - result.set(sqlName, row); - } - } - } - return result; -} - -function canonicalMobileDomain(values, label) { - const canonical = [...new Set(values)].sort(compareText); - if (canonical.length !== values.length || JSON.stringify(canonical) !== JSON.stringify(values)) { - throw new Error(`${label} must be a sorted, duplicate-free CSV domain; got ${JSON.stringify(values)}`); - } - return canonical; -} - -function requireSameMobileDomain(actual, expected, label) { - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - throw new Error(`${label}=${JSON.stringify(actual)}, expected ${JSON.stringify(expected)}`); - } -} - -export function validateMobileExtensionManifestDomains({ - runtime, - staticRegistry, - rows, - label = "mobile runtime manifest", -}) { - for (const key of [ - "selectedExtensions", - "extensions", - "mobileStaticRegistryState", - "mobileStaticRegistryRegistered", - "mobileStaticRegistryPending", - "nativeModuleStems", - ]) { - if (!Object.hasOwn(runtime, key)) { - throw new Error( - key === "selectedExtensions" - ? `${label} must define the full selectedExtensions domain` - : `${label} must define ${key}`, - ); - } - } - for (const key of [ - "state", - "registeredExtensions", - "pendingExtensions", - "nativeModuleStems", - "modules", - ]) { - if (!Object.hasOwn(staticRegistry, key)) { - throw new Error(`${label} static-registry manifest must define ${key}`); - } - } - const selectedExtensions = canonicalMobileDomain( - csvValues(runtime.selectedExtensions), - `${label} selectedExtensions`, - ); - const createableExtensions = []; - const nativeExtensions = []; - const nativeModuleStems = []; - for (const extension of selectedExtensions) { - const row = rows.get(extension); - if (!row) { - throw new Error(`${label} selected extension ${JSON.stringify(extension)} is missing from generated extension metadata`); - } - if (row["creates-extension"] === true) { - createableExtensions.push(extension); - } - const stem = row["native-module-stem"]; - if (typeof stem === "string" && stem && stem !== "-") { - nativeExtensions.push(extension); - nativeModuleStems.push(stem); - } - } - nativeModuleStems.sort(compareText); - - requireSameMobileDomain( - canonicalMobileDomain(csvValues(runtime.extensions), `${label} extensions`), - createableExtensions, - `${label} createable extensions`, - ); - requireSameMobileDomain( - canonicalMobileDomain( - csvValues(runtime.mobileStaticRegistryRegistered), - `${label} mobileStaticRegistryRegistered`, - ), - nativeExtensions, - `${label} registered native extensions`, - ); - requireSameMobileDomain( - canonicalMobileDomain(csvValues(runtime.nativeModuleStems), `${label} nativeModuleStems`), - nativeModuleStems, - `${label} native module stems`, - ); - requireSameMobileDomain( - canonicalMobileDomain( - csvValues(staticRegistry.registeredExtensions), - `${label} static-registry registeredExtensions`, - ), - nativeExtensions, - `${label} static-registry registered native extensions`, - ); - requireSameMobileDomain( - canonicalMobileDomain( - csvValues(staticRegistry.nativeModuleStems), - `${label} static-registry nativeModuleStems`, - ), - nativeModuleStems, - `${label} static-registry native module stems`, - ); - requireSameMobileDomain( - canonicalMobileDomain(csvValues(runtime.mobileStaticRegistryPending), `${label} mobileStaticRegistryPending`), - [], - `${label} pending native extensions`, - ); - requireSameMobileDomain( - canonicalMobileDomain( - csvValues(staticRegistry.pendingExtensions), - `${label} static-registry pendingExtensions`, - ), - [], - `${label} static-registry pending native extensions`, - ); - requireSameMobileDomain( - canonicalMobileDomain(csvValues(staticRegistry.modules), `${label} static-registry modules`), - nativeModuleStems, - `${label} static-registry modules`, - ); - const expectedRegistryState = nativeExtensions.length > 0 ? "complete" : "not-required"; - if (runtime.mobileStaticRegistryState !== expectedRegistryState) { - throw new Error( - `${label} mobileStaticRegistryState=${JSON.stringify(runtime.mobileStaticRegistryState)}, ` + - `expected ${JSON.stringify(expectedRegistryState)}`, - ); - } - if (staticRegistry.state !== expectedRegistryState) { - throw new Error( - `${label} static-registry state=${JSON.stringify(staticRegistry.state)}, ` + - `expected ${JSON.stringify(expectedRegistryState)}`, - ); - } - - return { - createableExtensions, - nativeExtensions, - nativeModuleStems, - selectedExtensions, - }; -} - -export function findSdkRuntimePayloadViolation(product, names, allowedNames = new Set()) { - for (const name of names) { - if (allowedNames.has(name)) { - continue; - } - const basename = path.basename(name); - if (product === "oliphaunt-kotlin" && KOTLIN_ALLOWED_NATIVE_PAYLOADS.has(basename)) { - continue; - } - for (const pattern of SDK_RUNTIME_PAYLOAD_PATTERNS) { - if (pattern.test(name)) { - return name; - } - } - } - return null; -} - -function rejectSdkRuntimePayload(product, artifact, names, allowedNames = new Set()) { - const violation = findSdkRuntimePayloadViolation(product, names, allowedNames); - if (violation !== null) { - fail(`${product} SDK artifact ${rel(artifact)} must not include runtime/extension payload ${violation}`); - } -} - -export function validateSwiftSourceFixtureEntries(artifact, entries) { - if (!(entries instanceof Map)) { - throw new Error(`${rel(artifact)} Swift source fixture entries must be a Map`); - } - if (!isDirectory(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT)) { - throw new Error( - `${rel(artifact)} cannot validate Swift source fixtures because ` - + `${rel(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT)} is missing`, - ); - } - - const prefix = `${SWIFT_SOURCE_FIXTURE_ARCHIVE_ROOT}/`; - const expectedNames = directoryNames(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT) - .map((name) => `${prefix}${name}`) - .sort(compareText); - const actualNames = [...entries] - .filter(([name, entry]) => name.startsWith(prefix) && entry.isFile) - .map(([name]) => name) - .sort(compareText); - if (JSON.stringify(actualNames) !== JSON.stringify(expectedNames)) { - const expected = new Set(expectedNames); - const actual = new Set(actualNames); - const missing = expectedNames.filter((name) => !actual.has(name)); - const extra = actualNames.filter((name) => !expected.has(name)); - throw new Error( - `${rel(artifact)} Swift source fixture file set must exactly match ` - + `${rel(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT)}; missing=${JSON.stringify(missing)}, ` - + `extra=${JSON.stringify(extra)}`, - ); - } - - for (const archiveName of expectedNames) { - const repositoryName = archiveName.slice(prefix.length); - const repositoryFile = path.join( - SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT, - ...repositoryName.split("/"), - ); - const actual = Buffer.from(entries.get(archiveName).data()); - const expected = readFileSync(repositoryFile); - if (!actual.equals(expected)) { - throw new Error( - `${rel(artifact)} Swift source fixture ${archiveName} must byte-for-byte match ` - + rel(repositoryFile), - ); - } - } - - return new Set(expectedNames); -} - -function validateKotlinAndroidAar(artifact, names) { - const presentAbis = new Set( - names - .map((name) => name.split("/")) - .filter((parts) => parts.length === 3 && parts[0] === "jni" && parts[2] === "liboliphaunt_kotlin_android.so") - .map((parts) => parts[1]), - ); - if (presentAbis.size !== KOTLIN_RELEASE_ABIS.size || [...presentAbis].some((abi) => !KOTLIN_RELEASE_ABIS.has(abi))) { - fail( - `Kotlin Android release AAR ${rel(artifact)} must contain JNI adapters for ` + - `${[...KOTLIN_RELEASE_ABIS].sort(compareText).join(", ")}; got ${[...presentAbis].sort(compareText).join(", ") || "(none)"}`, - ); - } -} - -/** - * Prove that the selection-neutral Apple carrier users receive in the React - * Native npm package is the exact carrier staged as release evidence. - */ -export function validateReactNativePackagedCarrier({ - artifact, - evidence, - expectedNativeVersion, - memberBytes, - names, -}) { - const member = `package/${IOS_CARRIER_FILENAME}`; - const matches = names.filter((name) => name === member); - if (matches.length !== 1) { - throw new Error( - `${rel(artifact)} must contain exactly one ${member}; found ${matches.length}`, - ); - } - if (!Buffer.isBuffer(memberBytes) || !Buffer.isBuffer(evidence)) { - throw new TypeError("React Native carrier inputs must be byte buffers"); - } - if (!memberBytes.equals(evidence)) { - throw new Error( - `${rel(artifact)} ${member} must byte-for-byte match its staged carrier evidence`, - ); - } - let carrier; - try { - carrier = JSON.parse(memberBytes.toString("utf8")); - } catch (error) { - throw new Error(`${rel(artifact)} ${member} is not valid JSON: ${error.message}`); - } - return validateSelectionNeutralSwiftCarrierIdentity({ - carrier, - expectedNativeVersion, - label: `${rel(artifact)} packaged React Native Apple carrier`, - }); -} - -async function checkSdkProduct(product, { require }) { - const root = path.join(SDK_ROOT, product); - if (!existsSync(root)) { - if (require) { - fail(`missing staged SDK artifacts for ${product} under ${rel(root)}`); - } - return false; - } - let checked = false; - if (product === "oliphaunt-wasix-ts") { - const tarballs = readdirSync(root) - .filter((name) => name.endsWith(".tgz")) - .map((name) => path.join(root, name)) - .sort(compareText); - if (tarballs.length !== 2) { - fail(`${product} must stage the binding and tools npm tarballs under ${rel(root)}`); - } - try { - const binding = tarballs.find((file) => path.basename(file).startsWith('oliphaunt-wasix-ts-')); - const tools = tarballs.find((file) => path.basename(file).startsWith('oliphaunt-wasix-tools-')); - if (binding === undefined || tools === undefined) { - fail(`${product} staged unexpected npm tarball names`); - } - assertWasixTypescriptNpmArchive(binding); - assertWasixToolsTypescriptNpmArchive(tools); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - checked = true; - } else if (["oliphaunt-js", "oliphaunt-react-native"].includes(product)) { - const tarballs = readdirSync(root).filter((name) => name.endsWith(".tgz")).map((name) => path.join(root, name)).sort(compareText); - if (tarballs.length === 0 && require) { - fail(`${product} must stage an npm tarball under ${rel(root)}`); - } - for (const tarball of tarballs) { - const names = archiveTarNames(tarball); - rejectSdkRuntimePayload(product, tarball, names); - try { - assertSourceOnlyNpmArchive( - tarball, - product === "oliphaunt-js" - ? SOURCE_ONLY_NPM_PROFILES.js - : SOURCE_ONLY_NPM_PROFILES["react-native"], - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - if (product === "oliphaunt-react-native") { - const carrierEvidence = path.join(root, "ios-carriers", IOS_CARRIER_FILENAME); - const carrierMember = `package/${IOS_CARRIER_FILENAME}`; - if (!isFile(carrierEvidence)) { - fail( - `${product} must stage selection-neutral carrier evidence at ${rel(carrierEvidence)}`, - ); - } - if (names.filter((name) => name === carrierMember).length !== 1) { - fail( - `${rel(tarball)} must contain exactly one ${carrierMember}; found ` - + names.filter((name) => name === carrierMember).length, - ); - } - try { - validateReactNativePackagedCarrier({ - artifact: tarball, - evidence: readFileSync(carrierEvidence), - expectedNativeVersion: productCompatibilityVersion( - "oliphaunt-swift", - "liboliphaunt-native", - PREFIX, - ), - memberBytes: tarReadBytes(tarball, carrierMember), - names, - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - } - checked = true; - } - } else if (product === "oliphaunt-swift") { - const archives = readdirSync(root).filter((name) => name.endsWith(".zip")).map((name) => path.join(root, name)).sort(compareText); - if (archives.length === 0 && require) { - fail(`${product} must stage a source zip under ${rel(root)}`); - } - for (const archive of archives) { - const entries = readZipEntries(archive); - const names = [...entries] - .filter(([, entry]) => entry.isFile) - .map(([name]) => name) - .sort(compareText); - let allowedFixtureNames; - try { - allowedFixtureNames = validateSwiftSourceFixtureEntries(archive, entries); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - rejectSdkRuntimePayload(product, archive, names, allowedFixtureNames); - checked = true; - } - const releaseManifest = path.join(root, "Package.swift.release"); - if (!existsSync(releaseManifest) && require) { - fail(`${product} must stage ${rel(releaseManifest)} for release installation`); - } - if (existsSync(releaseManifest)) { - const text = readFileSync(releaseManifest, "utf8"); - if (text.includes("file://")) { - fail(`${rel(releaseManifest)} must not contain local file URLs`); - } - if (!text.includes("liboliphaunt-native-v") || !text.includes("checksum:")) { - fail(`${rel(releaseManifest)} must reference checksummed public liboliphaunt assets`); - } - const sourceCarrier = path.join( - root, - "release-tree/src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json", - ); - if (!isFile(sourceCarrier)) { - fail(`${product} must stage its selection-neutral source carrier at ${rel(sourceCarrier)}`); - } - try { - const carrier = validateSelectionNeutralSwiftSourceCarrierFile( - sourceCarrier, - rel(sourceCarrier), - ); - validateSwiftSourceReleaseContract({ - carrier, - expectedNativeVersion: productCompatibilityVersion( - "oliphaunt-swift", - "liboliphaunt-native", - PREFIX, - ), - label: `${product} staged source release`, - manifestText: text, - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - } - const generatorRoot = path.join(root, "extension-generator"); - for (const [name, source] of [ - ["extension-owner-catalog.json", path.join(ROOT, "src/extensions/generated/sdk/extensions.json")], - ["extension-resource-inventory.mjs", path.join(ROOT, "src/sdks/swift/tools/extension-resource-inventory.mjs")], - ["render-extension-products.mjs", path.join(ROOT, "src/sdks/swift/tools/render-extension-products.mjs")], - ["swift-carrier-resolver.mjs", path.join(ROOT, "src/sdks/swift/tools/swift-carrier-resolver.mjs")], - ]) { - const frozen = path.join(generatorRoot, name); - if (!isFile(frozen)) { - fail(`${product} must stage frozen extension generator input ${rel(frozen)}`); - } - if (!readFileSync(frozen).equals(readFileSync(source))) { - fail(`${rel(frozen)} must byte-for-byte match ${rel(source)}`); - } - } - } else if (product === "oliphaunt-kotlin") { - const mavenRoot = path.join(root, "maven"); - if (!isDirectory(mavenRoot)) { - if (require) { - fail(`${product} must stage a Maven repository under ${rel(mavenRoot)}`); - } - return false; - } - for (const archive of walkFiles(root).filter((file) => file.endsWith(".aar") || file.endsWith(".jar")).sort(compareText)) { - const names = archiveZipNames(archive); - rejectSdkRuntimePayload(product, archive, names); - if (archive.endsWith(".aar")) { - validateKotlinAndroidAar(archive, names); - } - checked = true; - } - } else if (product === "oliphaunt-rust") { - const crates = readdirSync(root).filter((name) => name.endsWith(".crate")).map((name) => path.join(root, name)).sort(compareText); - if (crates.length === 0 && require) { - fail(`${product} must stage a Cargo crate under ${rel(root)}`); - } - const packageNames = []; - const cratesByPackage = new Map(); - for (const crate of crates) { - rejectSdkRuntimePayload(product, crate, archiveTarNames(crate)); - const packageName = await validateRustSdkCrate(crate); - packageNames.push(packageName); - cratesByPackage.set(packageName, crate); - checked = true; - } - if (crates.length > 0) { - exactSortedStrings( - `${product} staged Cargo packages`, - packageNames, - ["oliphaunt", "oliphaunt-build"], - ); - const version = await currentProductVersion("oliphaunt-rust", PREFIX); - requireCrateMatchesCargoListing( - cratesByPackage.get("oliphaunt"), - path.join(root, "cargo-package-files.txt"), - "oliphaunt", - version, - ); - } - } else if (product === "oliphaunt-wasix-rust") { - const crates = readdirSync(root).filter((name) => name.endsWith(".crate")).map((name) => path.join(root, name)).sort(compareText); - if (crates.length === 0 && require) { - fail(`${product} must stage a Cargo crate under ${rel(root)}`); - } - for (const crate of crates) { - rejectSdkRuntimePayload(product, crate, archiveTarNames(crate)); - await validateWasixSdkCrate(crate); - const version = await currentProductVersion("oliphaunt-wasix-rust", PREFIX); - requireCrateMatchesCargoListing( - crate, - path.join(root, "cargo-package-files.txt"), - "oliphaunt-wasix", - version, - ); - checked = true; - } - const listing = path.join(root, "cargo-package-files.txt"); - if (!isFile(listing)) { - if (require) { - fail(`${product} must stage a Cargo package file list under ${rel(root)}`); - } - return false; - } - const entries = new Set(readFileSync(listing, "utf8").split(/\r?\n/u).map((line) => line.trim()).filter(Boolean)); - for (const requiredEntry of [ - "Cargo.toml", - "README.md", - "src/lib.rs", - "src/bin/oliphaunt_wasix_dump.rs", - "src/bin/oliphaunt_wasix_proxy.rs", - "src/oliphaunt/assets.rs", - "src/oliphaunt/query_core.rs", - ]) { - if (!entries.has(requiredEntry)) { - fail(`${product} package file list is missing ${requiredEntry}`); - } - } - for (const entry of entries) { - if (entry.startsWith("target/") || entry.startsWith("src/runtimes/") || entry.startsWith("src/extensions/generated/")) { - fail(`${product} package file list contains generated or external payload entry ${entry}`); - } - } - checked = true; - } else { - fail(`unsupported SDK product ${product}`); - } - if (require && !checked) { - fail(`${product} did not contain any inspectable staged package artifacts under ${rel(root)}`); - } - if (checked) { - console.log(`validated SDK artifact cleanliness: ${product}`); - } - return checked; -} - -function walkFiles(root) { - if (!isDirectory(root)) { - return []; - } - const result = []; - const visit = (dir) => { - for (const name of readdirSync(dir).sort(compareText)) { - const file = path.join(dir, name); - if (isDirectory(file)) { - visit(file); - } else if (isFile(file)) { - result.push(file); - } - } - }; - visit(root); - return result; -} - -function extensionArtifactKindAllowed(family, target, kind) { - if (family === "wasix") { - return target === "wasix-portable" && kind === "wasix-runtime"; - } - if (family !== "native") { - return false; - } - if (target === "ios-xcframework") { - return new Set(["runtime", "ios-xcframework", "ios-dependency-xcframework"]).has(kind); - } - if (target.startsWith("android-")) { - return kind === "runtime"; - } - return kind === "runtime"; -} - -function publicExtensionAsset(asset) { - return extensionRuntimeAssetContract(asset); -} - -function requireExactKeys(value, expected, context) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(`${context} must be an object`); - } - const actual = new Set(Object.keys(value)); - if (!setEquals(actual, expected)) { - fail(`${context} keys must be ${JSON.stringify([...expected].sort(compareText))}, got ${JSON.stringify([...actual].sort(compareText))}`); - } -} - -function requireSortedUniqueStrings(value, context) { - if ( - !Array.isArray(value) - || value.some((item) => typeof item !== "string" || !item) - || new Set(value).size !== value.length - || JSON.stringify(value) !== JSON.stringify([...value].sort(compareText)) - ) { - fail(`${context} must be a sorted unique string list`); - } -} - -function validateMemberWasixInstall(member, context) { - try { - assertWasixExtensionMemberInstall(member, { label: context }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} - -function publicExtensionBundleMember(member) { - return { - ...Object.fromEntries(Object.entries(member).filter(([key]) => key !== "assets")), - assets: member.assets.map(publicExtensionAsset), - }; -} - -function publicExtensionBundleCarrier(asset) { - return extensionRuntimeAssetContract(asset); -} - -export function expectedExtensionBundleManifest({ product, version, data, carrier, rows }) { - const legal = extensionCarrierLegalContract( - product, - [...new Set(rows.map(({ member }) => member.sqlName))].sort(compareText), - { family: carrier.family, target: carrier.target }, - ); - return { - schema: "oliphaunt-extension-bundle-v1", - product, - version, - compatibility: data.compatibility, - family: carrier.family, - target: carrier.target, - licenseProfile: legal.profile, - licenseFiles: legal.licenseFiles, - members: rows.map(({ member, asset }) => ({ - sqlName: member.sqlName, - kind: asset.kind, - identity: asset.identity, - path: asset.memberPath, - sha256: asset.sha256, - bytes: asset.bytes, - })), - }; -} - -function expectedExtensionRoles(member, targets) { - const roles = []; - const nativeStem = typeof member.nativeModuleStem === "string" && member.nativeModuleStem - ? member.nativeModuleStem - : null; - for (const target of [...targets].sort(compareText)) { - if (target === "wasix-portable") { - roles.push(`wasix:${target}:wasix-runtime:`); - continue; - } - roles.push(`native:${target}:runtime:`); - if (target === "ios-xcframework" && nativeStem !== null) { - roles.push(`native:${target}:ios-xcframework:${nativeStem}`); - for (const dependency of member.iosNativeDependencies) { - roles.push(`native:${target}:ios-dependency-xcframework:${dependency}`); - } - } - } - return roles.sort(compareText); -} - -function validateBundleMemberMetadata(member, manifest, stagedTargets) { - requireExactKeys(member, EXTENSION_BUNDLE_MEMBER_KEYS, `${rel(manifest)} member ${JSON.stringify(member?.sqlName)}`); - if (typeof member.sqlName !== "string" || !member.sqlName) { - fail(`${rel(manifest)} bundle member must declare sqlName`); - } - if (typeof member.createsExtension !== "boolean") { - fail(`${rel(manifest)} member ${member.sqlName} createsExtension must be boolean`); - } - for (const field of [ - "dependencies", - "dataFiles", - "extensionSqlFileNames", - "extensionSqlFilePrefixes", - "iosNativeDependencies", - "sharedPreloadLibraries", - ]) { - requireSortedUniqueStrings(member[field], `${rel(manifest)} member ${member.sqlName}.${field}`); - } - if (!(member.nativeModuleStem === null || typeof member.nativeModuleStem === "string" && member.nativeModuleStem)) { - fail(`${rel(manifest)} member ${member.sqlName}.nativeModuleStem must be null or a non-empty string`); - } - validateMemberWasixInstall(member, `${rel(manifest)} member ${member.sqlName}`); - const stagesIos = stagedTargets.has("ios-xcframework"); - if (member.nativeModuleStem === null) { - if (member.iosNativeDependencies.length > 0 || member.iosRegistration !== null) { - fail(`${rel(manifest)} SQL-only member ${member.sqlName} must not declare iOS native metadata`); - } - } else if (stagesIos) { - if (member.iosRegistration === null || Array.isArray(member.iosRegistration) || typeof member.iosRegistration !== "object") { - fail(`${rel(manifest)} native member ${member.sqlName} must include build-derived iOS registration metadata`); - } - if ( - member.iosRegistration.sqlName !== member.sqlName - || member.iosRegistration.nativeModuleStem !== member.nativeModuleStem - ) { - fail(`${rel(manifest)} iOS registration metadata does not match ${member.sqlName}/${member.nativeModuleStem}`); - } - } else if (member.iosNativeDependencies.length > 0 || member.iosRegistration !== null) { - fail(`${rel(manifest)} member ${member.sqlName} must not claim iOS metadata without an iOS carrier`); - } -} - -function checkExtensionArtifactInventory(root, expectedPaths) { - const inventory = path.join(root, "artifacts.txt"); - if (!isFile(inventory)) { - fail(`${rel(root)} must contain artifacts.txt`); - } - const actual = readFileSync(inventory, "utf8").split(/\r?\n/u).filter(Boolean); - if (new Set(actual).size !== actual.length) { - fail(`${rel(inventory)} must not contain duplicate upload paths`); - } - const normalizedExpected = [...new Set(expectedPaths)]; - if (JSON.stringify(actual) !== JSON.stringify(normalizedExpected)) { - fail(`${rel(inventory)} must enumerate direct publish artifacts exactly: expected=${JSON.stringify(normalizedExpected)}, actual=${JSON.stringify(actual)}`); - } -} - -async function checkExtensionBundleProduct(product, root, manifest, data, { family, requireFullTargets }) { - const releaseProduct = extensionReleaseProduct(product, family ?? "native", PREFIX); - const ownership = releaseProduct === product ? {} : { releaseProduct, family }; - requireExactKeys(data, new Set([...INTERNAL_EXTENSION_BUNDLE_ROOT_KEYS, ...Object.keys(ownership)]), rel(manifest)); - const version = extensionReleaseVersion(product, family ?? "native", PREFIX); - if ( - data.product !== product - || data.version !== version - || Object.entries(ownership).some(([key, value]) => data[key] !== value) - ) { - fail(`${rel(manifest)} must describe ${product}@${version}`); - } - const releaseMetadata = extensionMetadata(product, PREFIX); - if (!deepEqual(data.compatibility, releaseMetadata.compatibility)) { - fail(`${rel(manifest)} has stale compatibility metadata`); - } - const expectedSqlNames = extensionSqlNames(product, PREFIX); - if (!Array.isArray(data.extensions)) { - fail(`${rel(manifest)} must declare extensions`); - } - const actualSqlNames = data.extensions.map((member) => member?.sqlName); - if (JSON.stringify(actualSqlNames) !== JSON.stringify(expectedSqlNames)) { - fail(`${rel(manifest)} bundle members must exactly match release metadata: expected=${JSON.stringify(expectedSqlNames)}, actual=${JSON.stringify(actualSqlNames)}`); - } - - const targetRows = extensionArtifactTargets({ product }, PREFIX) - .filter((row) => family === null || row.family === family); - const allowedTargetFamilies = new Map(); - for (const row of targetRows) { - const current = allowedTargetFamilies.get(row.target); - if (current !== undefined && current !== row.family) { - fail(`${product} release metadata maps ${row.target} to multiple artifact families`); - } - allowedTargetFamilies.set(row.target, row.family); - } - const allowedTargets = new Set(allowedTargetFamilies.keys()); - if (!Array.isArray(data.carrierAssets) || data.carrierAssets.length === 0) { - fail(`${rel(manifest)} must declare at least one aggregate carrier`); - } - const carriersByName = new Map(); - const carrierEntries = new Map(); - const carrierLegal = new Map(); - const seenCarrierRoles = new Set(); - const stagedTargets = new Set(); - for (const carrier of data.carrierAssets) { - requireExactKeys(carrier, INTERNAL_EXTENSION_BUNDLE_CARRIER_ASSET_KEYS, `${rel(manifest)} carrier ${JSON.stringify(carrier?.name)}`); - const { name, path: pathValue, family, target, kind, sha256, bytes, memberCount } = carrier; - if (![name, pathValue, family, target, kind, sha256].every((value) => typeof value === "string" && value)) { - fail(`${rel(manifest)} contains an incomplete aggregate carrier: ${JSON.stringify(carrier)}`); - } - if (kind !== "extension-bundle" || memberCount !== expectedSqlNames.length) { - fail(`${rel(manifest)} carrier ${name} must be an exact ${expectedSqlNames.length}-member extension-bundle`); - } - if (!/^[0-9a-f]{64}$/u.test(sha256) || !Number.isInteger(bytes) || bytes <= 0) { - fail(`${rel(manifest)} carrier ${name} must declare a positive byte count and SHA-256`); - } - if (allowedTargetFamilies.get(target) !== family) { - fail(`${rel(manifest)} carrier ${name} uses undeclared family/target ${family}/${target}`); - } - const role = `${family}:${target}`; - if (seenCarrierRoles.has(role) || carriersByName.has(name)) { - fail(`${rel(manifest)} repeats aggregate carrier ${role} or name ${name}`); - } - seenCarrierRoles.add(role); - carriersByName.set(name, carrier); - stagedTargets.add(target); - const expectedName = `${product}-${version}-${family}-${target}-bundle.tar.gz`; - if (name !== expectedName) { - fail(`${rel(manifest)} carrier ${name} must use canonical name ${expectedName}`); - } - const carrierPath = path.join(ROOT, pathValue); - if (path.dirname(carrierPath) !== path.join(root, "release-assets") || path.basename(carrierPath) !== name) { - fail(`${rel(manifest)} aggregate carrier ${name} must live directly under ${rel(path.join(root, "release-assets"))}`); - } - if (!isFile(carrierPath) || statSync(carrierPath).size !== bytes || sha256File(carrierPath) !== sha256) { - fail(`${rel(manifest)} aggregate carrier ${name} is missing or does not match its outer size/digest`); - } - const legal = extensionCarrierLegalContract(product, expectedSqlNames, { family, target }); - const carrierRoot = name.replace(/\.tar\.gz$/u, ""); - assertReleaseNoticesInArchive(carrierPath, { - prefix: carrierRoot, - profile: legal.profile, - }); - if (legal.upstreamMembers.length > 0) { - assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, carrierPath, { - prefix: carrierRoot, - }); - } - carrierLegal.set(name, legal); - carrierEntries.set(name, canonicalBundleTarEntries(carrierPath)); - } - if (requireFullTargets) { - const missing = [...allowedTargets].filter((target) => !stagedTargets.has(target)).sort(compareText); - if (missing.length > 0) { - fail(`${product} is missing aggregate carriers for declared targets: ${missing.join(", ")}`); - } - } - - const allMemberAssets = []; - for (const member of data.extensions) { - validateBundleMemberMetadata(member, manifest, stagedTargets); - if (!Array.isArray(member.assets) || member.assets.length === 0) { - fail(`${rel(manifest)} member ${member.sqlName} must declare assets`); - } - const roles = new Set(); - const memberTargets = new Set(); - for (const asset of member.assets) { - requireExactKeys(asset, INTERNAL_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS, `${rel(manifest)} member ${member.sqlName} asset ${JSON.stringify(asset?.name)}`); - const { name, path: pathValue, source, family, target, kind, identity, sha256, bytes, carrierAsset, carrierRoot, memberPath } = asset; - if (![name, pathValue, source, family, target, kind, sha256, carrierAsset, carrierRoot, memberPath].every((value) => typeof value === "string" && value)) { - fail(`${rel(manifest)} member ${member.sqlName} contains an incomplete nested asset`); - } - if (!/^[0-9a-f]{64}$/u.test(sha256) || !Number.isInteger(bytes) || bytes <= 0) { - fail(`${rel(manifest)} member ${member.sqlName} asset ${name} must declare a positive byte count and SHA-256`); - } - if (!(identity === null || typeof identity === "string" && identity)) { - fail(`${rel(manifest)} member ${member.sqlName} asset ${name} has invalid identity`); - } - if (kind === "ios-dependency-xcframework" && identity === null) { - fail(`${rel(manifest)} member ${member.sqlName} iOS dependency ${name} must declare identity`); - } - if (kind !== "ios-dependency-xcframework" && kind !== "ios-xcframework" && identity !== null) { - fail(`${rel(manifest)} member ${member.sqlName} asset ${name} must not declare identity for kind=${kind}`); - } - if (allowedTargetFamilies.get(target) !== family || !extensionArtifactKindAllowed(family, target, kind)) { - fail(`${rel(manifest)} member ${member.sqlName} asset ${name} uses invalid family/target/kind ${family}/${target}/${kind}`); - } - const role = `${family}:${target}:${kind}:${identity ?? ""}`; - if (roles.has(role)) { - fail(`${rel(manifest)} member ${member.sqlName} repeats artifact role ${role}`); - } - roles.add(role); - memberTargets.add(target); - const carrier = carriersByName.get(carrierAsset); - if (carrier === undefined || carrier.family !== family || carrier.target !== target) { - fail(`${rel(manifest)} member ${member.sqlName} asset ${name} references the wrong aggregate carrier ${carrierAsset}`); - } - const expectedCarrierRoot = carrierAsset.replace(/\.tar\.gz$/u, ""); - const expectedMemberPath = `extensions/${member.sqlName}/${name}`; - if (carrierRoot !== expectedCarrierRoot || memberPath !== expectedMemberPath) { - fail(`${rel(manifest)} member ${member.sqlName} asset ${name} has a noncanonical nested locator`); - } - const composedPath = `${carrierRoot}/${memberPath}`; - if ( - portableMemberName( - composedPath, - "file", - path.join(root, "release-assets", carrierAsset), - ) !== composedPath - ) { - fail(`${rel(manifest)} member ${member.sqlName} asset ${name} has an unsafe nested locator`); - } - const localPath = path.join(ROOT, pathValue); - const expectedLocalDir = path.join(root, "member-assets", member.sqlName); - if (path.dirname(localPath) !== expectedLocalDir || path.basename(localPath) !== name) { - fail(`${rel(manifest)} member ${member.sqlName} asset ${name} must be staged under ${rel(expectedLocalDir)}`); - } - if (!isFile(localPath) || statSync(localPath).size !== bytes || sha256File(localPath) !== sha256) { - fail(`${rel(manifest)} member ${member.sqlName} local asset ${name} is missing or does not match its size/digest`); - } - // canonicalBundleTarEntries also applies this contract to every key in - // the archive before any nested member is looked up. - const inner = carrierEntries.get(carrierAsset)?.get(composedPath); - if (inner === undefined || inner.length !== bytes || createHash("sha256").update(inner).digest("hex") !== sha256) { - fail(`${rel(manifest)} member ${member.sqlName} asset ${name} is missing or has wrong bytes inside ${carrierAsset}`); - } - allMemberAssets.push({ member, asset }); - } - if (!setEquals(memberTargets, stagedTargets)) { - fail(`${rel(manifest)} member ${member.sqlName} must be present in every staged aggregate target`); - } - const expectedRoles = expectedExtensionRoles(member, stagedTargets); - const actualRoles = [...roles].sort(compareText); - if (JSON.stringify(actualRoles) !== JSON.stringify(expectedRoles)) { - fail(`${rel(manifest)} member ${member.sqlName} artifact roles are not dependency-closed: expected=${JSON.stringify(expectedRoles)}, actual=${JSON.stringify(actualRoles)}`); - } - } - - for (const carrier of data.carrierAssets) { - const carrierRoot = carrier.name.replace(/\.tar\.gz$/u, ""); - const rows = allMemberAssets - .filter(({ asset }) => asset.carrierAsset === carrier.name) - .sort((left, right) => compareText( - `${left.member.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ""}`, - `${right.member.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ""}`, - )); - const memberNames = [...new Set(rows.map(({ member }) => member.sqlName))].sort(compareText); - if (JSON.stringify(memberNames) !== JSON.stringify(expectedSqlNames)) { - fail(`${rel(manifest)} carrier ${carrier.name} does not contain every exact bundle member`); - } - const expectedBundleManifest = expectedExtensionBundleManifest({ - product, - version, - data, - carrier, - rows, - }); - const entries = carrierEntries.get(carrier.name); - const manifestName = `${carrierRoot}/bundle-manifest.json`; - const manifestBytes = entries.get(manifestName); - if (manifestBytes === undefined) { - fail(`${carrier.name} is missing ${manifestName}`); - } - const expectedManifestBytes = Buffer.from( - `${JSON.stringify(sortValue(expectedBundleManifest), null, 2)}\n`, - ); - if (!manifestBytes.equals(expectedManifestBytes)) { - fail(`${carrier.name} bundle-manifest.json must use its exact canonical nested member and legal bytes`); - } - let actualBundleManifest; - try { - actualBundleManifest = JSON.parse(manifestBytes.toString("utf8")); - } catch (error) { - fail(`${carrier.name} has invalid bundle-manifest.json: ${error.message}`); - } - if (!deepEqual(actualBundleManifest, expectedBundleManifest)) { - fail(`${carrier.name} bundle-manifest.json does not exactly describe its nested member bytes`); - } - const expectedArchiveNames = [ - manifestName, - ...rows.map(({ asset }) => `${carrierRoot}/${asset.memberPath}`), - ...releaseNoticeRows({ profile: carrierLegal.get(carrier.name).profile }) - .map(({ member }) => `${carrierRoot}/${member}`), - ...carrierLegal.get(carrier.name).licenseFiles - .map((member) => `${carrierRoot}/${member}`), - ].sort(compareText); - const actualArchiveNames = [...entries.keys()].sort(compareText); - if (JSON.stringify(actualArchiveNames) !== JSON.stringify(expectedArchiveNames)) { - fail(`${carrier.name} contents do not exactly match its declared members`); - } - } - - const releaseManifest = path.join(root, "release-assets", `${product}-${version}-manifest.json`); - const releaseData = readJson(releaseManifest); - requireExactKeys( - releaseData, - new Set([...PUBLIC_EXTENSION_BUNDLE_RELEASE_MANIFEST_KEYS, ...Object.keys(ownership)]), - rel(releaseManifest), - ); - const expectedReleaseData = { - schema: "oliphaunt-extension-release-manifest-v2", - product, - ...ownership, - version, - extensionClass: releaseMetadata.class, - versioning: releaseMetadata.versioning, - sourceIdentity: extensionSourceIdentity(product, PREFIX), - compatibility: releaseMetadata.compatibility, - extensions: data.extensions.map(publicExtensionBundleMember), - assets: data.carrierAssets.map(publicExtensionBundleCarrier), - }; - if (!deepEqual(releaseData, expectedReleaseData)) { - fail(`${rel(releaseManifest)} must exactly match stable metadata and nested staged artifacts`); - } - for (const member of releaseData.extensions) { - requireExactKeys(member, EXTENSION_BUNDLE_MEMBER_KEYS, `${rel(releaseManifest)} member ${member?.sqlName}`); - for (const asset of member.assets) { - requireExactKeys(asset, PUBLIC_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS, `${rel(releaseManifest)} member ${member.sqlName} asset ${asset?.name}`); - } - } - for (const carrier of releaseData.assets) { - requireExactKeys(carrier, PUBLIC_EXTENSION_BUNDLE_CARRIER_ASSET_KEYS, `${rel(releaseManifest)} carrier ${carrier?.name}`); - } - - const stagesIos = stagedTargets.has("ios-xcframework"); - const swiftCarrier = path.join(root, "release-assets", swiftExtensionCarrierAssetName(product, version)); - if (stagesIos) { - if (!isFile(swiftCarrier)) { - fail(`${product} must stage independently consumable Swift iOS carrier ${rel(swiftCarrier)}`); - } - let expectedCarrier; - try { - expectedCarrier = buildSwiftExtensionCarrierManifest({ - extensionManifest: manifest, - nativeRuntimeVersion: releaseMetadata.compatibility.nativeRuntimeVersion, - }); - } catch (error) { - fail(`${rel(swiftCarrier)} cannot be derived from exact staged bundle artifacts: ${error.message}`); - } - if (!deepEqual(readJson(swiftCarrier), expectedCarrier)) { - fail(`${rel(swiftCarrier)} must exactly describe every bundle member and its compatible native base`); - } - } else if (isFile(swiftCarrier)) { - fail(`${product} must not stage a Swift carrier without an iOS aggregate carrier`); - } - - const propertiesManifest = path.join(root, "release-assets", `${product}-${version}-manifest.properties`); - if (!isFile(propertiesManifest)) { - fail(`${product} must stage properties manifest ${rel(propertiesManifest)}`); - } - const expectedProperties = { - schema: "oliphaunt-extension-release-manifest-v2", - product, - ...(releaseProduct === product ? {} : { releaseProduct, carrierFamily: family }), - version: String(version), - extensionClass: String(releaseData.extensionClass), - versioning: String(releaseData.versioning), - sourceKind: String(releaseData.sourceIdentity.kind), - extensions: expectedSqlNames.join(","), - }; - for (const member of data.extensions) { - const prefix = `extension.${member.sqlName}`; - expectedProperties[`${prefix}.createsExtension`] = member.createsExtension ? "true" : "false"; - expectedProperties[`${prefix}.dependencies`] = member.dependencies.join(","); - expectedProperties[`${prefix}.dataFiles`] = member.dataFiles.join(","); - expectedProperties[`${prefix}.extensionSqlFileNames`] = member.extensionSqlFileNames.join(","); - expectedProperties[`${prefix}.extensionSqlFilePrefixes`] = member.extensionSqlFilePrefixes.join(","); - expectedProperties[`${prefix}.nativeModuleStem`] = member.nativeModuleStem ?? ""; - expectedProperties[`${prefix}.iosNativeDependencies`] = member.iosNativeDependencies.join(","); - expectedProperties[`${prefix}.sharedPreloadLibraries`] = member.sharedPreloadLibraries.join(","); - for (const asset of member.assets) { - const identity = asset.identity === null ? "" : `.${asset.identity}`; - expectedProperties[`asset.${member.sqlName}.${asset.family}.${asset.target}.${asset.kind}${identity}`] - = `${asset.carrierAsset}:${asset.memberPath}:${asset.sha256}:${asset.bytes}`; - } - } - for (const carrier of data.carrierAssets) { - expectedProperties[`carrier.${carrier.family}.${carrier.target}.${carrier.kind}`] = carrier.name; - } - const actualProperties = readPropertiesText(readFileSync(propertiesManifest, "utf8")); - if (!deepEqual(actualProperties, expectedProperties)) { - fail(`${rel(propertiesManifest)} must exactly describe every aggregate carrier and nested member locator`); - } - - const checksumManifest = path.join(root, "release-assets", `${product}-${version}-release-assets.sha256`); - if (!isFile(checksumManifest)) { - fail(`${product} must stage checksum manifest ${rel(checksumManifest)}`); - } - validateChecksumManifest(checksumManifest, path.join(root, "release-assets")); - checkExtensionArtifactInventory(root, [ - ...data.carrierAssets.map((asset) => asset.path), - rel(releaseManifest), - rel(propertiesManifest), - ...(stagesIos ? [rel(swiftCarrier)] : []), - rel(checksumManifest), - ]); - console.log(`validated exact-extension bundle artifacts: ${product} (${expectedSqlNames.length} members, ${data.carrierAssets.length} carriers)`); - return true; -} - -async function checkExtensionProductVariant(product, root, manifest, data, { family, requireFullTargets }) { - if (data.schema === "oliphaunt-extension-ci-artifacts-v2") { - return checkExtensionBundleProduct(product, root, manifest, data, { family, requireFullTargets }); - } - const releaseProduct = extensionReleaseProduct(product, family ?? "native", PREFIX); - const ownership = releaseProduct === product ? {} : { releaseProduct, family }; - const expected = { - schema: "oliphaunt-extension-ci-artifacts-v1", - product, - ...ownership, - version: extensionReleaseVersion(product, family ?? "native", PREFIX), - }; - const metadata = extensionMetadata(product, PREFIX); - for (const [key, value] of Object.entries(expected)) { - if (data[key] !== value) { - fail(`${rel(manifest)} has ${key}=${JSON.stringify(data[key])}, expected ${JSON.stringify(value)}`); - } - } - if (!deepEqual(data.compatibility, metadata.compatibility)) { - fail(`${rel(manifest)} has stale compatibility metadata`); - } - const sqlNames = extensionSqlNames(product, PREFIX); - if (sqlNames.length !== 1) { - fail(`${product} singleton artifact manifest requires exactly one SQL name`); - } - const [expectedSqlName] = sqlNames; - if (data.sqlName !== expectedSqlName) { - fail(`${rel(manifest)} has sqlName=${JSON.stringify(data.sqlName)}, expected ${JSON.stringify(expectedSqlName)}`); - } - if (typeof data.createsExtension !== "boolean") { - fail(`${rel(manifest)}.createsExtension must be boolean`); - } - for (const field of [ - "dependencies", - "dataFiles", - "extensionSqlFileNames", - "extensionSqlFilePrefixes", - "sharedPreloadLibraries", - ]) { - requireSortedUniqueStrings(data[field], `${rel(manifest)}.${field}`); - } - const assets = data.assets; - if (!Array.isArray(assets) || assets.length === 0) { - fail(`${rel(manifest)} must declare at least one asset`); - } - const seenNames = new Set(); - const seenRoles = new Set(); - const stagedTargets = new Set(); - const allowedTargets = new Set(extensionArtifactTargets({ product }, PREFIX).map((target) => target.target)); - for (const asset of assets) { - if (asset === null || Array.isArray(asset) || typeof asset !== "object") { - fail(`${rel(manifest)} contains a non-object asset entry`); - } - const { family, target, kind, identity, name, path: pathValue, sha256, bytes } = asset; - if (![family, target, kind, name, pathValue, sha256].every((value) => typeof value === "string" && value)) { - fail(`${rel(manifest)} contains an incomplete asset entry: ${JSON.stringify(asset)}`); - } - if (!Number.isInteger(bytes) || bytes <= 0) { - fail(`${rel(manifest)} asset ${name} must declare positive bytes`); - } - if (seenNames.has(name)) { - fail(`${rel(manifest)} declares duplicate asset name ${name}`); - } - seenNames.add(name); - if (!(identity === null || typeof identity === "string" && identity.length > 0)) { - fail(`${rel(manifest)} asset ${name} identity must be null or a non-empty string`); - } - if (kind === "ios-dependency-xcframework" && identity === null) { - fail(`${rel(manifest)} iOS dependency XCFramework ${name} must declare its identity`); - } - if (kind !== "ios-dependency-xcframework" && kind !== "ios-xcframework" && identity !== null) { - fail(`${rel(manifest)} asset ${name} must not declare identity for kind=${kind}`); - } - const role = `${family}:${target}:${kind}:${identity ?? ""}`; - if (seenRoles.has(role)) { - fail(`${rel(manifest)} repeats artifact role ${role}`); - } - seenRoles.add(role); - stagedTargets.add(target); - if (!allowedTargets.has(target)) { - fail(`${rel(manifest)} stages undeclared target=${JSON.stringify(target)}`); - } - if (!extensionArtifactKindAllowed(family, target, kind)) { - fail(`${rel(manifest)} stages invalid artifact kind=${JSON.stringify(kind)} for family=${JSON.stringify(family)} target=${JSON.stringify(target)}`); - } - const assetPath = path.join(ROOT, pathValue); - if (path.dirname(assetPath) !== path.join(root, "release-assets") || path.basename(assetPath) !== name) { - fail(`${rel(manifest)} asset ${name} must live directly under ${rel(path.join(root, "release-assets"))}`); - } - if (!isFile(assetPath)) { - fail(`${rel(manifest)} references missing asset ${rel(assetPath)}`); - } - if (statSync(assetPath).size !== bytes) { - fail(`${rel(assetPath)} size does not match ${rel(manifest)}`); - } - if (sha256File(assetPath) !== sha256) { - fail(`${rel(assetPath)} checksum does not match ${rel(manifest)}`); - } - validateReleaseArchivePayload(assetPath); - } - const nativeStem = typeof data.nativeModuleStem === "string" && data.nativeModuleStem.length > 0 - ? data.nativeModuleStem - : null; - const iosDependencies = Array.isArray(data.iosNativeDependencies) - ? data.iosNativeDependencies - : fail(`${rel(manifest)} must declare iosNativeDependencies`); - if ( - iosDependencies.some((value) => typeof value !== "string" || value.length === 0) - || new Set(iosDependencies).size !== iosDependencies.length - || JSON.stringify([...iosDependencies].sort(compareText)) !== JSON.stringify(iosDependencies) - ) { - fail(`${rel(manifest)} iosNativeDependencies must be a sorted unique string list`); - } - const stagesIos = stagedTargets.has("ios-xcframework"); - if (nativeStem === null && (iosDependencies.length > 0 || data.iosRegistration !== null)) { - fail(`${rel(manifest)} SQL-only extension must not fabricate iOS native dependencies or registration`); - } - if (nativeStem !== null && stagesIos) { - if (data.iosRegistration === null || typeof data.iosRegistration !== "object" || Array.isArray(data.iosRegistration)) { - fail(`${rel(manifest)} native extension must include build-derived iOS registration metadata`); - } - if (data.iosRegistration.sqlName !== data.sqlName || data.iosRegistration.nativeModuleStem !== nativeStem) { - fail(`${rel(manifest)} iOS registration metadata does not match ${data.sqlName}/${nativeStem}`); - } - } - if (!stagesIos && (iosDependencies.length > 0 || data.iosRegistration !== null)) { - fail(`${rel(manifest)} must not claim iOS dependency/registration metadata without staging the iOS target`); - } - validateMemberWasixInstall(data, rel(manifest)); - const expectedRoles = []; - const targetsToCheck = requireFullTargets ? allowedTargets : stagedTargets; - for (const target of [...targetsToCheck].sort(compareText)) { - if (target === "wasix-portable") { - expectedRoles.push(`wasix:${target}:wasix-runtime:`); - } else { - expectedRoles.push(`native:${target}:runtime:`); - if (target === "ios-xcframework" && nativeStem !== null) { - expectedRoles.push(`native:${target}:ios-xcframework:${nativeStem}`); - for (const dependency of iosDependencies) { - expectedRoles.push(`native:${target}:ios-dependency-xcframework:${dependency}`); - } - } - } - } - const actualRoles = [...seenRoles].sort(compareText); - expectedRoles.sort(compareText); - if (JSON.stringify(actualRoles) !== JSON.stringify(expectedRoles)) { - fail(`${rel(manifest)} artifact roles are not dependency-closed: expected=${JSON.stringify(expectedRoles)}, actual=${JSON.stringify(actualRoles)}`); - } - const releaseManifest = path.join(root, "release-assets", `${product}-${expected.version}-manifest.json`); - if (!existsSync(releaseManifest)) { - fail(`${product} must stage release manifest ${rel(releaseManifest)}`); - } - const releaseData = readJson(releaseManifest); - const expectedRelease = { - schema: "oliphaunt-extension-release-manifest-v1", - product, - ...ownership, - version: String(expected.version), - sqlName: String(expectedSqlName), - extensionClass: metadata.class, - versioning: metadata.versioning, - sourceIdentity: extensionSourceIdentity(product, PREFIX), - compatibility: metadata.compatibility, - createsExtension: data.createsExtension, - dependencies: data.dependencies, - dataFiles: data.dataFiles, - extensionSqlFileNames: data.extensionSqlFileNames, - extensionSqlFilePrefixes: data.extensionSqlFilePrefixes, - nativeModuleStem: data.nativeModuleStem, - iosNativeDependencies: data.iosNativeDependencies, - iosRegistration: data.iosRegistration, - wasixInstall: data.wasixInstall, - sharedPreloadLibraries: data.sharedPreloadLibraries, - assets: assets.map(publicExtensionAsset), - }; - requireExactKeys( - releaseData, - new Set([...PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS, ...Object.keys(ownership)]), - rel(releaseManifest), - ); - if (!deepEqual(releaseData, expectedRelease)) { - fail(`${rel(releaseManifest)} must exactly match stable metadata and staged artifacts`); - } - if (stagesIos) { - const carrier = path.join( - root, - "release-assets", - swiftExtensionCarrierAssetName(product, expected.version), - ); - if (!existsSync(carrier)) { - fail(`${product} must stage independently consumable Swift iOS carrier ${rel(carrier)}`); - } - let expectedCarrier; - try { - expectedCarrier = buildSwiftExtensionCarrierManifest({ - extensionManifest: manifest, - nativeRuntimeVersion: metadata.compatibility.nativeRuntimeVersion, - }); - } catch (error) { - fail(`${rel(carrier)} cannot be derived from exact staged artifacts: ${error.message}`); - } - if (!deepEqual(readJson(carrier), expectedCarrier)) { - fail(`${rel(carrier)} must exactly describe this extension and its compatible native base`); - } - } - const publicAssets = releaseData.assets; - for (const asset of publicAssets) { - if (asset === null || Array.isArray(asset) || typeof asset !== "object") { - fail(`${rel(releaseManifest)} contains a non-object public asset row`); - } - if (!setEquals(new Set(Object.keys(asset)), PUBLIC_EXTENSION_RELEASE_ASSET_KEYS)) { - fail(`${rel(releaseManifest)} public asset ${JSON.stringify(asset.name)} keys must be ${JSON.stringify([...PUBLIC_EXTENSION_RELEASE_ASSET_KEYS].sort(compareText))}, got ${JSON.stringify(Object.keys(asset).sort(compareText))}`); - } - } - const propertiesManifest = path.join(root, "release-assets", `${product}-${expected.version}-manifest.properties`); - if (!existsSync(propertiesManifest)) { - fail(`${product} must stage properties manifest ${rel(propertiesManifest)}`); - } - const properties = readPropertiesText(readFileSync(propertiesManifest, "utf8")); - const expectedProperties = { - schema: "oliphaunt-extension-release-manifest-v1", - product, - ...(releaseProduct === product ? {} : { releaseProduct, carrierFamily: family }), - version: String(expected.version), - sqlName: String(expectedSqlName), - extensionClass: String(releaseData.extensionClass), - versioning: String(releaseData.versioning), - sourceKind: String(releaseData.sourceIdentity.kind), - createsExtension: data.createsExtension ? "true" : "false", - dependencies: data.dependencies.join(","), - dataFiles: data.dataFiles.join(","), - extensionSqlFileNames: data.extensionSqlFileNames.join(","), - extensionSqlFilePrefixes: data.extensionSqlFilePrefixes.join(","), - nativeModuleStem: data.nativeModuleStem ?? "", - iosNativeDependencies: data.iosNativeDependencies.join(","), - sharedPreloadLibraries: data.sharedPreloadLibraries.join(","), - }; - for (const asset of assets) { - const identity = asset.identity === null ? "" : `.${asset.identity}`; - expectedProperties[`asset.${asset.family}.${asset.target}.${asset.kind}${identity}`] = asset.name; - } - if (!deepEqual(properties, expectedProperties)) { - fail(`${rel(propertiesManifest)} must exactly describe stable metadata and every staged asset identity`); - } - const checksumManifest = path.join(root, "release-assets", `${product}-${expected.version}-release-assets.sha256`); - if (!existsSync(checksumManifest)) { - fail(`${product} must stage checksum manifest ${rel(checksumManifest)}`); - } - validateChecksumManifest(checksumManifest, path.join(root, "release-assets")); - checkExtensionArtifactInventory(root, [ - ...assets.map((asset) => asset.path), - rel(releaseManifest), - rel(propertiesManifest), - ...(stagesIos ? [rel(path.join(root, "release-assets", swiftExtensionCarrierAssetName(product, expected.version)))] : []), - rel(checksumManifest), - ]); - if (requireFullTargets) { - const missing = [...allowedTargets].filter((target) => !stagedTargets.has(target)).sort(compareText); - if (missing.length > 0) { - fail(`${product} is missing published exact-extension targets: ${missing.join(", ")}`); - } - } - console.log(`validated exact-extension package artifacts: ${product}`); - return true; -} - -async function checkExtensionProduct(product, { family, require, requireFullTargets }) { - const variants = family === null - ? (() => { - const nativeRoot = extensionArtifactProductRoot(product, "native", EXTENSION_ROOT, PREFIX); - const wasixRoot = extensionArtifactProductRoot(product, "wasix", EXTENSION_ROOT, PREFIX); - return nativeRoot === wasixRoot - ? [{ family: null, root: nativeRoot }] - : [{ family: "native", root: nativeRoot }, { family: "wasix", root: wasixRoot }]; - })() - : [{ - family, - root: extensionArtifactProductRoot(product, family, EXTENSION_ROOT, PREFIX), - }]; - let checked = false; - for (const variant of variants) { - const manifest = path.join(variant.root, "extension-artifacts.json"); - if (!existsSync(manifest)) { - if (require) { - fail(`missing staged exact-extension ${variant.family ?? "combined"} package manifest for ${product} under ${rel(variant.root)}`); - } - continue; - } - checked = await checkExtensionProductVariant( - product, - variant.root, - manifest, - readJson(manifest), - { family: variant.family, requireFullTargets }, - ) || checked; - } - return checked; -} - -function setEquals(left, right) { - return left.size === right.size && [...left].every((item) => right.has(item)); -} - -function sortValue(value) { - if (Array.isArray(value)) { - return value.map(sortValue); - } - if (value !== null && typeof value === "object") { - return Object.fromEntries(Object.keys(value).sort(compareText).map((key) => [key, sortValue(value[key])])); - } - return value; -} - -function deepEqual(left, right) { - return JSON.stringify(sortValue(left)) === JSON.stringify(sortValue(right)); -} - -function validateChecksumManifest(file, assetDir) { - const declared = new Map(); - const lines = readFileSync(file, "utf8").split(/\r?\n/u); - for (let index = 0; index < lines.length; index += 1) { - const line = lines[index].trim(); - if (!line) { - continue; - } - const parts = line.split(/\s+/u); - if (parts.length !== 2) { - fail(`${rel(file)}:${index + 1} must contain ' ./'`); - } - const [sha, name] = parts; - if (!/^[0-9a-f]{64}$/u.test(sha) || !name.startsWith("./") || name.slice(2).includes("/")) { - fail(`${rel(file)}:${index + 1} contains an invalid checksum entry`); - } - const assetName = name.slice(2); - if (declared.has(assetName)) { - fail(`${rel(file)} declares duplicate checksum entry for ${assetName}`); - } - declared.set(assetName, sha); - } - const expectedNames = readdirSync(assetDir) - .map((name) => path.join(assetDir, name)) - .filter((candidate) => isFile(candidate) && candidate !== file) - .map((candidate) => path.basename(candidate)) - .sort(compareText); - if (JSON.stringify([...declared.keys()].sort(compareText)) !== JSON.stringify(expectedNames)) { - fail(`${rel(file)} must cover release assets exactly`); - } - for (const [name, expectedSha] of declared) { - const actual = sha256File(path.join(assetDir, name)); - if (actual !== expectedSha) { - fail(`${rel(file)} checksum mismatch for ${name}`); - } - } -} - -function discoverMobileArtifacts(platform) { - if (platform === "android") { - const root = path.join(MOBILE_ROOT, "android"); - return existsSync(root) - ? readdirSync(root).filter((name) => name.endsWith(".apk")).map((name) => { - const file = path.join(root, name); - return { - platform: "android", - path: file, - names: archiveAndroidApkNames(file), - readText: (member) => androidApkReadText(file, member), - }; - }).sort((left, right) => compareText(left.path, right.path)) - : []; - } - if (platform === "ios") { - const root = path.join(MOBILE_ROOT, "ios"); - return existsSync(root) - ? readdirSync(root).filter((name) => name.endsWith(".app") && isDirectory(path.join(root, name))).map((name) => { - const app = path.join(root, name); - return { platform: "ios", path: app, names: directoryNames(app), readText: (member) => dirReadText(app, member) }; - }).sort((left, right) => compareText(left.path, right.path)) - : []; - } - fail(`unsupported mobile platform ${platform}`); -} - -function mobilePrefix(platform) { - if (platform === "android") { - return "assets/oliphaunt/"; - } - if (platform === "ios") { - return "OliphauntReactNativeResources.bundle/oliphaunt/"; - } - fail(`unsupported mobile platform ${platform}`); -} - -function mobileTargetForArtifact(artifact) { - if (artifact.platform === "ios") { - return "ios-xcframework"; - } - const abis = artifact.names - .map((name) => name.split("/")) - .filter((parts) => parts.length === 3 && parts[0] === "lib" && parts[2] === "liboliphaunt.so") - .map((parts) => parts[1]) - .sort(compareText); - if (abis.length !== 1) { - fail(`${rel(artifact.path)} must contain exactly one Android liboliphaunt ABI, got ${JSON.stringify(abis)}`); - } - if (abis[0] === "arm64-v8a") { - return "android-arm64-v8a"; - } - if (abis[0] === "x86_64") { - return "android-x86_64"; - } - fail(`${rel(artifact.path)} contains unsupported Android ABI ${abis[0]}`); -} - -export function validatePackagedMobileRuntimeFiles({ - artifactNames, - metadata, - platform, - prefix, - registry, - selected, -}) { - const runtimePrefix = `${prefix}runtime/files/`; - const runtimePaths = new Set( - artifactNames - .filter((name) => name.startsWith(runtimePrefix) && !name.endsWith("/")) - .map((name) => name.slice(runtimePrefix.length)), - ); - validateMobileRuntimeFiles({ - metadata, - metadataLabel: rel(REACT_NATIVE_EXTENSION_METADATA), - platform, - registry, - registryLabel: rel(MOBILE_STATIC_REGISTRY), - runtimePaths, - selected: selected.join(","), - }); -} - -function mobileBuildReport(platform) { - const report = path.join(MOBILE_ROOT, platform, "build-report.json"); - if (!isFile(report)) { - return null; - } - const data = readJson(report); - if (data.schema !== "oliphaunt-react-native-mobile-build-v1") { - fail(`${rel(report)} has invalid mobile build report schema`); - } - if (data.platform !== platform) { - fail(`${rel(report)} has platform=${JSON.stringify(data.platform)}, expected ${JSON.stringify(platform)}`); - } - return data; -} - -function resolveReportPath(value, reportPath, field) { - if (typeof value !== "string" || !value) { - fail(`${rel(reportPath)} must declare ${field}`); - } - return path.isAbsolute(value) ? value : path.join(ROOT, value); -} - -function checkExtensionPackageHasMobileTarget(sqlName, target) { - for (const product of exactExtensionProducts(PREFIX)) { - const manifest = path.join( - extensionArtifactProductRoot(product, "native", EXTENSION_ROOT, PREFIX), - "extension-artifacts.json", - ); - if (!isFile(manifest)) { - continue; - } - const data = readJson(manifest); - const member = data.schema === "oliphaunt-extension-ci-artifacts-v2" - ? data.extensions?.find((row) => row?.sqlName === sqlName) - : data.sqlName === sqlName ? data : null; - if (member === null || member === undefined) { - continue; - } - const assets = member.assets; - if (!Array.isArray(assets)) { - fail(`${rel(manifest)} must declare assets`); - } - const runtimeMatches = assets.filter((asset) => asset && asset.family === "native" && asset.target === target && asset.kind === "runtime"); - if (runtimeMatches.length !== 1) { - fail(`${sqlName} exact-extension package must contain one native runtime asset for ${target}`); - } - if (target === "ios-xcframework") { - const frameworkMatches = assets.filter((asset) => asset && asset.family === "native" && asset.target === target && asset.kind === "ios-xcframework"); - const dependencyMatches = assets.filter((asset) => asset && asset.family === "native" && asset.target === target && asset.kind === "ios-dependency-xcframework"); - const hasNativeModule = typeof member.nativeModuleStem === "string" && member.nativeModuleStem.length > 0; - if (frameworkMatches.length !== (hasNativeModule ? 1 : 0)) { - fail(`${sqlName} exact-extension package has the wrong iOS XCFramework role count for ${hasNativeModule ? "native" : "SQL-only"} metadata`); - } - const expectedDependencies = hasNativeModule && Array.isArray(member.iosNativeDependencies) - ? member.iosNativeDependencies - : []; - if (JSON.stringify(dependencyMatches.map((asset) => asset.identity).sort(compareText)) !== JSON.stringify(expectedDependencies)) { - fail(`${sqlName} exact-extension package iOS dependency XCFrameworks do not match its frozen dependency closure`); - } - } - return; - } - fail(`no exact-extension package found for selected mobile extension ${sqlName}`); -} - -export function iosPayloadCocoaPodsFileListPaths(scratchPath) { - const podName = "OliphauntReactNativePayload"; - const supportRoot = path.join( - scratchPath, - "examples/react-native-expo/ios/Pods/Target Support Files", - podName, - ); - return { - inputFile: path.join(supportRoot, `${podName}-xcframeworks-input-files.xcfilelist`), - outputFile: path.join(supportRoot, `${podName}-xcframeworks-output-files.xcfilelist`), - podName, - supportRoot, - }; -} - -function canonicalIosExtensionLinkStems(stems) { - if (!Array.isArray(stems)) { - throw new Error("expected iOS extension native-module stems must be an array"); - } - const raw = new Set(); - const symbols = new Map(); - for (const stem of stems) { - if (typeof stem !== "string" || !IOS_EXTENSION_LINK_STEM.test(stem)) { - throw new Error(`invalid iOS extension native-module stem ${JSON.stringify(stem)}`); - } - if (raw.has(stem)) { - throw new Error(`duplicate iOS extension native-module stem ${JSON.stringify(stem)}`); - } - raw.add(stem); - const symbolStem = stem.replaceAll("-", "_"); - const prior = symbols.get(symbolStem); - if (prior !== undefined) { - throw new Error( - `iOS extension native-module stems ${JSON.stringify(prior)} and ${JSON.stringify(stem)} ` - + `collide after registration-symbol normalization to ${JSON.stringify(symbolStem)}`, - ); - } - symbols.set(symbolStem, stem); - } - return [...raw].sort(compareText); -} - -function iosCocoaPodsExtensionArtifacts(text, kind) { - if (typeof text !== "string") { - throw new Error(`CocoaPods ${kind} file list must be text`); - } - const suffixes = kind === "input" - ? [".xcframework"] - : kind === "output" ? [".framework", ".a"] : null; - if (suffixes === null) { - throw new Error(`unsupported CocoaPods file-list kind ${JSON.stringify(kind)}`); - } - const artifacts = new Set(); - for (const [index, raw] of text.split(/\r?\n/u).entries()) { - if (raw.includes("\0")) { - throw new Error(`CocoaPods ${kind} file list line ${index + 1} contains NUL`); - } - const record = raw.trim(); - if (!record) { - continue; - } - const components = record.split("/"); - const candidates = kind === "input" ? components : [components.at(-1)]; - for (const component of candidates) { - if (!component.startsWith(IOS_EXTENSION_LINK_PREFIX)) { - continue; - } - const suffix = suffixes.find((value) => component.endsWith(value)); - if (suffix === undefined) { - throw new Error( - `CocoaPods ${kind} file list line ${index + 1} has unsupported ` - + `Oliphaunt extension artifact component ${JSON.stringify(component)}`, - ); - } - const stem = component.slice(IOS_EXTENSION_LINK_PREFIX.length, -suffix.length); - if (!IOS_EXTENSION_LINK_STEM.test(stem)) { - throw new Error( - `CocoaPods ${kind} file list line ${index + 1} has invalid ` - + `Oliphaunt extension native-module stem ${JSON.stringify(stem)}`, - ); - } - const artifact = `${IOS_EXTENSION_LINK_PREFIX}${stem}`; - if (artifacts.has(artifact)) { - throw new Error( - `CocoaPods ${kind} file list repeats Oliphaunt extension artifact ${JSON.stringify(artifact)}`, - ); - } - artifacts.add(artifact); - } - } - return [...artifacts].sort(compareText); -} - -export function iosCocoaPodsExtensionLinkEvidence({ expectedStems, inputText, outputText }) { - const expectedArtifacts = canonicalIosExtensionLinkStems(expectedStems) - .map((stem) => `${IOS_EXTENSION_LINK_PREFIX}${stem}`); - const inputArtifacts = iosCocoaPodsExtensionArtifacts(inputText, "input"); - const outputArtifacts = iosCocoaPodsExtensionArtifacts(outputText, "output"); - const expected = new Set(expectedArtifacts); - const input = new Set(inputArtifacts); - const output = new Set(outputArtifacts); - return { - expectedArtifacts, - inputArtifacts, - missingInput: expectedArtifacts.filter((artifact) => !input.has(artifact)), - missingOutput: expectedArtifacts.filter((artifact) => !output.has(artifact)), - outputArtifacts, - unexpectedInput: inputArtifacts.filter((artifact) => !expected.has(artifact)), - unexpectedOutput: outputArtifacts.filter((artifact) => !expected.has(artifact)), - }; -} - -function checkIosPrebuiltExtensionLinkage(artifact, stems) { - if (stems.length === 0) { - return; - } - const sourceLeaks = artifact.names - .filter((name) => name.includes("/static-registry/oliphaunt_static_registry.c") || name.includes("/extension-frameworks/") || name.endsWith(".xcframework")) - .sort(compareText); - if (sourceLeaks.length > 0) { - fail(`${rel(artifact.path)} includes build-only iOS static-extension inputs as app resources: ${sourceLeaks.slice(0, 10).join(", ")}`); - } - const report = mobileBuildReport("ios"); - if (report === null) { - fail(`${rel(artifact.path)} requires ${rel(path.join(MOBILE_ROOT, "ios/build-report.json"))} for iOS extension link evidence`); - } - const scratchRoot = report.scratchRoot; - if (typeof scratchRoot !== "string" || !scratchRoot) { - fail(`${rel(path.join(MOBILE_ROOT, "ios/build-report.json"))} must declare scratchRoot for iOS extension link evidence`); - } - const scratchPath = scratchRoot; - const xcodeLog = path.join(scratchPath, "xcodebuild.log"); - if (!isFile(xcodeLog)) { - fail(`iOS extension link evidence is missing xcodebuild log: ${rel(xcodeLog)}`); - } - const logText = readFileSync(xcodeLog, "utf8"); - if (!logText.includes("** BUILD SUCCEEDED **")) { - fail(`iOS extension link evidence requires a successful xcodebuild log: ${rel(xcodeLog)}`); - } - const { inputFile, outputFile } = iosPayloadCocoaPodsFileListPaths(scratchPath); - if (!isFile(inputFile)) { - fail(`iOS extension link evidence is missing CocoaPods XCFramework input file list: ${rel(inputFile)}`); - } - if (!isFile(outputFile)) { - fail(`iOS extension link evidence is missing CocoaPods XCFramework output file list: ${rel(outputFile)}`); - } - let podEvidence; - try { - podEvidence = iosCocoaPodsExtensionLinkEvidence({ - expectedStems: stems, - inputText: readFileSync(inputFile, "utf8"), - outputText: readFileSync(outputFile, "utf8"), - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - const expectedFrameworks = new Set(podEvidence.expectedArtifacts); - const productsRoot = path.join(scratchPath, "DerivedData/Build/Products"); - if (!isDirectory(productsRoot)) { - fail(`iOS extension link evidence is missing Xcode build products: ${rel(productsRoot)}`); - } - const builtFrameworks = new Set( - walkFiles(productsRoot) - .map((file) => path.basename(file)) - .filter((name) => /^liboliphaunt_extension_.*(\.a|\.framework)$/u.test(name)) - .map((name) => name.replace(/\.a$/u, "").replace(/\.framework$/u, "")), - ); - if (podEvidence.missingInput.length > 0) { - fail(`CocoaPods input file list does not include selected iOS extension XCFramework(s): ${podEvidence.missingInput.join(", ")}`); - } - if (podEvidence.missingOutput.length > 0) { - fail(`CocoaPods output file list does not include selected iOS extension linked artifact(s): ${podEvidence.missingOutput.join(", ")}`); - } - const missingBuilt = [...expectedFrameworks].filter((item) => !builtFrameworks.has(item)).sort(compareText); - if (missingBuilt.length > 0) { - fail(`Xcode build products do not include selected iOS extension linked artifact(s): ${missingBuilt.join(", ")}`); - } - if (podEvidence.unexpectedInput.length > 0) { - fail(`CocoaPods input file list includes unselected iOS extension XCFramework(s): ${podEvidence.unexpectedInput.join(", ")}`); - } - if (podEvidence.unexpectedOutput.length > 0) { - fail(`CocoaPods output file list includes unselected iOS extension linked artifact(s): ${podEvidence.unexpectedOutput.join(", ")}`); - } - const unexpectedBuilt = [...builtFrameworks].filter((item) => !expectedFrameworks.has(item)).sort(compareText); - if (unexpectedBuilt.length > 0) { - fail(`Xcode build products include unselected iOS extension linked artifact(s): ${unexpectedBuilt.join(", ")}`); - } -} - -function checkAndroidPrebuiltExtensionLinkage(artifact, stems, report, reportPath, expectedAbi, staticRegistry, target) { - if (stems.length === 0) { - return; - } - const evidencePath = resolveReportPath(report.androidLinkEvidence, reportPath, "androidLinkEvidence"); - if (!isFile(evidencePath)) { - fail(`Android extension link evidence is missing: ${rel(evidencePath)}`); - } - if (!/^[0-9a-f]{64}$/u.test(report.androidLinkEvidenceSha256 ?? "")) { - fail(`${rel(reportPath)} androidLinkEvidenceSha256 must be a lowercase SHA-256 digest`); - } - const evidenceSha256 = sha256File(evidencePath); - if (evidenceSha256 !== report.androidLinkEvidenceSha256) { - fail(`${rel(reportPath)} androidLinkEvidenceSha256 does not match ${rel(evidencePath)}`); - } - const linkedStems = new Set(); - const linkedDependencies = new Set(); - let evidenceAbi = ""; - let runtimePath = ""; - let schemaRows = 0; - let abiRows = 0; - const requireExistingPath = (rawPath, lineNumber, rowKind) => { - const resolved = path.isAbsolute(rawPath) ? rawPath : path.join(path.dirname(evidencePath), rawPath); - if (!isFile(resolved)) { - fail(`${rel(evidencePath)}:${lineNumber} ${rowKind} path does not exist: ${resolved}`); - } - return resolved; - }; - const lines = readFileSync(evidencePath, "utf8").split(/\r?\n/u); - for (let index = 0; index < lines.length; index += 1) { - const parts = lines[index].split("\t"); - if (!parts.length || !parts[0]) { - continue; - } - const lineNumber = index + 1; - const kind = parts[0]; - if (kind === "schema") { - if (JSON.stringify(parts) !== JSON.stringify(["schema", "oliphaunt-android-static-extension-link-v1"])) { - fail(`${rel(evidencePath)}:${lineNumber} has invalid schema row`); - } - schemaRows += 1; - } else if (kind === "abi") { - if (parts.length !== 2) { - fail(`${rel(evidencePath)}:${lineNumber} has invalid abi row`); - } - evidenceAbi = parts[1]; - abiRows += 1; - } else if (kind === "runtime") { - if (parts.length !== 3 || parts[1] !== "liboliphaunt") { - fail(`${rel(evidencePath)}:${lineNumber} has invalid runtime row`); - } - const runtime = requireExistingPath(parts[2], lineNumber, "runtime"); - if (path.basename(runtime) !== "liboliphaunt.so") { - fail(`${rel(evidencePath)}:${lineNumber} runtime path must end in liboliphaunt.so`); - } - if (runtimePath) { - fail(`${rel(evidencePath)} contains duplicate runtime rows`); - } - runtimePath = runtime; - } else if (kind === "extension") { - if (parts.length !== 3) { - fail(`${rel(evidencePath)}:${lineNumber} has invalid extension row`); - } - const [stem, archive] = [parts[1], parts[2]]; - const expectedName = `liboliphaunt_extension_${stem}.a`; - const archivePath = requireExistingPath(archive, lineNumber, "extension"); - const expectedRelative = staticRegistry[`module.${stem}.archive.${target}`]; - if (!expectedRelative) { - fail(`${rel(artifact.path)} static registry manifest has no module.${stem}.archive.${target} entry`); - } - if (path.basename(archivePath) !== expectedName) { - fail(`${rel(evidencePath)}:${lineNumber} archive ${JSON.stringify(archive)} does not match stem ${JSON.stringify(stem)}`); - } - if (!archivePath.split(path.sep).join("/").endsWith(expectedRelative)) { - fail(`${rel(evidencePath)}:${lineNumber} archive ${JSON.stringify(archive)} does not match static-registry path ${JSON.stringify(expectedRelative)}`); - } - linkedStems.add(stem); - } else if (kind === "dependency") { - if (parts.length !== 3 || !parts[1]) { - fail(`${rel(evidencePath)}:${lineNumber} has invalid dependency row`); - } - const dependencyName = parts[1]; - const dependencyPath = requireExistingPath(parts[2], lineNumber, "dependency"); - const expectedRelative = staticRegistry[`dependency.${dependencyName}.archive.${target}`]; - if (!expectedRelative) { - fail(`${rel(evidencePath)}:${lineNumber} dependency ${JSON.stringify(dependencyName)} is not declared by the static-registry manifest for ${target}`); - } - if (!dependencyPath.split(path.sep).join("/").endsWith(expectedRelative)) { - fail(`${rel(evidencePath)}:${lineNumber} dependency path ${JSON.stringify(parts[2])} does not match static-registry path ${JSON.stringify(expectedRelative)}`); - } - linkedDependencies.add(dependencyName); - } else { - fail(`${rel(evidencePath)}:${lineNumber} has unknown row kind ${JSON.stringify(kind)}`); - } - } - if (schemaRows !== 1) { - fail(`${rel(evidencePath)} must contain exactly one schema row`); - } - if (abiRows !== 1) { - fail(`${rel(evidencePath)} must contain exactly one abi row`); - } - if (evidenceAbi !== expectedAbi) { - fail(`${rel(evidencePath)} declares abi=${JSON.stringify(evidenceAbi)}, expected ${JSON.stringify(expectedAbi)}`); - } - if (!runtimePath) { - fail(`${rel(evidencePath)} does not show liboliphaunt runtime link input`); - } - const expectedStems = new Set(stems); - const missing = [...expectedStems].filter((stem) => !linkedStems.has(stem)).sort(compareText); - if (missing.length > 0) { - fail(`${rel(evidencePath)} does not show selected Android extension archive link input(s): ${missing.join(", ")}`); - } - const unexpected = [...linkedStems].filter((stem) => !expectedStems.has(stem)).sort(compareText); - if (unexpected.length > 0) { - fail(`${rel(evidencePath)} shows unselected Android extension archive link input(s): ${unexpected.join(", ")}`); - } - const expectedDependencies = new Set(csvValues(staticRegistry.dependencyArchives)); - const missingDependencies = [...expectedDependencies].filter((dependency) => !linkedDependencies.has(dependency)).sort(compareText); - if (missingDependencies.length > 0) { - fail(`${rel(evidencePath)} does not show required Android extension dependency archive link input(s): ${missingDependencies.join(", ")}`); - } - const unexpectedDependencies = [...linkedDependencies].filter((dependency) => !expectedDependencies.has(dependency)).sort(compareText); - if (unexpectedDependencies.length > 0) { - fail(`${rel(evidencePath)} shows unselected Android extension dependency archive link input(s): ${unexpectedDependencies.join(", ")}`); - } -} - -export function validatePackagedMobileRuntimeManifest(runtime, source = "mobile runtime manifest") { - if (runtime.schema !== "oliphaunt-runtime-resources-v1") { - throw new Error(`${source} has invalid runtime resource manifest schema`); - } - if (runtime.mode !== "native-direct") { - throw new Error(`${source} must declare mode=native-direct`); - } -} - -function checkMobileArtifact(artifact, { requirePrebuiltExtensions }) { - const prefix = mobilePrefix(artifact.platform); - const runtimeManifestName = `${prefix}runtime/manifest.properties`; - const staticRegistryManifestName = `${prefix}static-registry/manifest.properties`; - const packageSizeName = `${prefix}package-size.tsv`; - const runtime = readPropertiesText(artifact.readText(runtimeManifestName)); - try { - validatePackagedMobileRuntimeManifest(runtime, `${rel(artifact.path)} runtime resource manifest`); - } catch (error) { - fail(error.message); - } - const rows = generatedExtensionRows(); - const staticRegistry = readPropertiesText(artifact.readText(staticRegistryManifestName)); - let domains; - try { - domains = validateMobileExtensionManifestDomains({ - label: `${rel(artifact.path)} runtime manifest`, - rows, - runtime, - staticRegistry, - }); - } catch (error) { - fail(error.message); - } - const selected = domains.selectedExtensions; - const target = mobileTargetForArtifact(artifact); - const reportPath = path.join(MOBILE_ROOT, artifact.platform, "build-report.json"); - const report = mobileBuildReport(artifact.platform); - if (report === null) { - fail(`${rel(artifact.path)} requires mobile build report ${rel(reportPath)}`); - } - const reportArtifact = resolveReportPath(report.appArtifact, reportPath, "appArtifact"); - if (path.resolve(reportArtifact) !== path.resolve(artifact.path)) { - fail(`${rel(reportPath)} appArtifact=${reportArtifact} does not match inspected artifact ${artifact.path}`); - } - if (report.appArtifactBytes !== pathBytes(artifact.path)) { - fail(`${rel(reportPath)} appArtifactBytes does not match inspected artifact size`); - } - if (!Array.isArray(report.selectedExtensions)) { - fail(`${rel(reportPath)} selectedExtensions must be an array`); - } - const reportSelected = report.selectedExtensions.map((value) => String(value)).filter(Boolean).sort(compareText); - if (JSON.stringify(reportSelected) !== JSON.stringify([...selected].sort(compareText))) { - fail(`${rel(reportPath)} selectedExtensions=${JSON.stringify(reportSelected)} must match runtime manifest ${JSON.stringify([...selected].sort(compareText))}`); - } - let expectedAbi = ""; - if (artifact.platform === "android") { - expectedAbi = target === "android-arm64-v8a" ? "arm64-v8a" : "x86_64"; - if (report.abi !== expectedAbi) { - fail(`${rel(reportPath)} abi=${JSON.stringify(report.abi)}, expected ${JSON.stringify(expectedAbi)}`); - } - } - try { - validatePackagedMobileRuntimeFiles({ - artifactNames: artifact.names, - metadata: readJson(REACT_NATIVE_EXTENSION_METADATA), - platform: artifact.platform === "android" ? "Android" : "iOS", - prefix, - registry: readJson(MOBILE_STATIC_REGISTRY), - selected, - }); - } catch (error) { - fail(`${rel(artifact.path)} failed mobile runtime inventory validation: ${error.message}`); - } - for (const extension of selected) { - if (requirePrebuiltExtensions) { - checkExtensionPackageHasMobileTarget(extension, target); - } - } - const stems = domains.nativeModuleStems; - const nativeSelected = domains.nativeExtensions; - if (stems.length > 0) { - if (runtime.mobileStaticRegistryState !== "complete") { - fail(`${rel(artifact.path)} must mark mobile static registry complete for native-module extensions`); - } - if (artifact.platform === "android" && !artifact.names.some((name) => name.endsWith("/liboliphaunt_extensions.so"))) { - fail(`${rel(artifact.path)} Android app is missing liboliphaunt_extensions.so`); - } - if (artifact.platform === "android" && requirePrebuiltExtensions) { - checkAndroidPrebuiltExtensionLinkage(artifact, stems, report, reportPath, expectedAbi, staticRegistry, target); - } - if (artifact.platform === "ios" && requirePrebuiltExtensions) { - checkIosPrebuiltExtensionLinkage(artifact, stems); - } - if (artifact.names.some((name) => name.includes("static-registry/archives/"))) { - fail(`${rel(artifact.path)} must not ship build-only static-registry archives`); - } - } else if (![undefined, "", "not-required"].includes(runtime.mobileStaticRegistryState)) { - fail(`${rel(artifact.path)} must not claim a static registry for SQL-only extensions`); - } - const packageSize = artifact.readText(packageSizeName); - const packageSizeExtensions = packageSize - .split(/\r?\n/u) - .filter((line) => line.startsWith("extension\t")) - .map((line) => line.split("\t")[1]) - .filter(Boolean) - .sort(compareText); - if (JSON.stringify(packageSizeExtensions) !== JSON.stringify([...selected].sort(compareText))) { - fail(`${rel(artifact.path)} package-size extension rows ${JSON.stringify(packageSizeExtensions)} must exactly match selected extensions ${JSON.stringify([...selected].sort(compareText))}`); - } - console.log(`validated mobile app extension contents: ${artifact.platform} ${rel(artifact.path)}`); -} - -function checkMobilePlatform(platform, { require, requirePrebuiltExtensions }) { - const artifacts = discoverMobileArtifacts(platform); - if (artifacts.length === 0) { - if (require) { - fail(`missing staged React Native ${platform} mobile app artifacts under ${rel(path.join(MOBILE_ROOT, platform))}`); - } - return false; - } - for (const artifact of artifacts) { - checkMobileArtifact(artifact, { requirePrebuiltExtensions }); - } - return true; -} - -function expandProducts(values, { allProducts, label }) { - const expanded = []; - for (const value of values) { - if (value === "all") { - expanded.push(...[...allProducts].sort(compareText)); - } else if (!allProducts.has(value)) { - fail(`unknown ${label} ${value}; expected one of: all, ${[...allProducts].sort(compareText).join(", ")}`); - } else { - expanded.push(value); - } - } - return [...new Set(expanded)].sort(compareText); -} - -function usage() { - return `usage: tools/release/check-staged-artifacts.mjs [options] - -Options: - --require-sdk-product PRODUCT SDK product to require, or all - --require-extension-product PRODUCT exact-extension product to require, or all - --family native|wasix validate only that extension carrier family - --require-full-extension-targets require every published exact-extension target - --require-mobile android|ios|all mobile app artifact platform to require - --require-mobile-prebuilt-extensions require matching exact-extension package inputs - --inspect-present also inspect any present staged artifacts - -h, --help show this help -`; -} - -function parseArgs(argv) { - const args = { - requireSdkProduct: [], - requireExtensionProduct: [], - family: null, - requireFullExtensionTargets: false, - requireMobile: [], - requireMobilePrebuiltExtensions: false, - inspectPresent: false, - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--require-sdk-product") { - const value = argv[index + 1]; - if (!value) { - fail("--require-sdk-product requires a value"); - } - args.requireSdkProduct.push(value); - index += 1; - } else if (arg === "--require-extension-product") { - const value = argv[index + 1]; - if (!value) { - fail("--require-extension-product requires a value"); - } - args.requireExtensionProduct.push(value); - index += 1; - } else if (arg === "--family") { - const value = argv[index + 1]; - if (!value || !["native", "wasix"].includes(value)) { - fail("--family requires native or wasix"); - } - args.family = value; - index += 1; - } else if (arg === "--require-full-extension-targets") { - args.requireFullExtensionTargets = true; - } else if (arg === "--require-mobile") { - const value = argv[index + 1]; - if (!["android", "ios", "all"].includes(value)) { - fail("--require-mobile requires one of: android, ios, all"); - } - args.requireMobile.push(value); - index += 1; - } else if (arg === "--require-mobile-prebuilt-extensions") { - args.requireMobilePrebuiltExtensions = true; - } else if (arg === "--inspect-present") { - args.inspectPresent = true; - } else if (arg === "--help" || arg === "-h") { - process.stdout.write(usage()); - process.exit(0); - } else { - fail(`unknown argument ${arg}`); - } - } - return args; -} - -async function main(argv) { - const args = parseArgs(argv); - let checked = 0; - - const sdkProductSet = new Set(sdkProducts()); - const requiredSdkProducts = expandProducts(args.requireSdkProduct, { - allProducts: sdkProductSet, - label: "SDK product", - }); - for (const product of requiredSdkProducts) { - checked += Number(await checkSdkProduct(product, { require: true })); - } - if (args.inspectPresent) { - for (const product of [...sdkProductSet].filter((product) => !requiredSdkProducts.includes(product)).sort(compareText)) { - checked += Number(await checkSdkProduct(product, { require: false })); - } - } - - const extensionProductSet = new Set(exactExtensionProducts(PREFIX)); - const requiredExtensionProducts = expandProducts(args.requireExtensionProduct, { - allProducts: extensionProductSet, - label: "exact-extension product", - }); - for (const product of requiredExtensionProducts) { - checked += Number(await checkExtensionProduct(product, { - family: args.family, - require: true, - requireFullTargets: args.requireFullExtensionTargets, - })); - } - if (args.inspectPresent) { - for (const product of [...extensionProductSet].filter((product) => !requiredExtensionProducts.includes(product)).sort(compareText)) { - checked += Number(await checkExtensionProduct(product, { - family: args.family, - require: false, - requireFullTargets: false, - })); - } - } - - const requiredMobile = new Set(); - for (const value of args.requireMobile) { - if (value === "all") { - requiredMobile.add("android"); - requiredMobile.add("ios"); - } else { - requiredMobile.add(value); - } - } - for (const platform of [...requiredMobile].sort(compareText)) { - checked += Number(checkMobilePlatform(platform, { - require: true, - requirePrebuiltExtensions: args.requireMobilePrebuiltExtensions, - })); - } - if (args.inspectPresent) { - for (const platform of ["android", "ios"].filter((value) => !requiredMobile.has(value))) { - checked += Number(checkMobilePlatform(platform, { - require: false, - requirePrebuiltExtensions: args.requireMobilePrebuiltExtensions, - })); - } - } - - if (checked === 0) { - fail("no staged artifacts were checked; pass --require-* or --inspect-present"); - } -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/check-staged-artifacts.test.mjs b/tools/release/check-staged-artifacts.test.mjs deleted file mode 100644 index 73819118f..000000000 --- a/tools/release/check-staged-artifacts.test.mjs +++ /dev/null @@ -1,724 +0,0 @@ -import assert from "node:assert/strict"; -import { readdirSync, readFileSync, statSync } from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { extensionReleasePropertiesText } from "./build-extension-ci-artifacts.mjs"; -import { iosBaseLegalMetadata } from "./ios-carrier-manifest.mjs"; -import { - cargoPackageMemberContractViolation, - expectedExtensionBundleManifest, - findSdkRuntimePayloadViolation, - iosCocoaPodsExtensionLinkEvidence, - iosPayloadCocoaPodsFileListPaths, - parseUniquePropertiesText, - validateReactNativePackagedCarrier, - validateMobileExtensionManifestDomains, - validatePackagedMobileRuntimeFiles, - validatePackagedMobileRuntimeManifest, - validateSwiftSourceFixtureEntries, -} from "./check-staged-artifacts.mjs"; -import { CORE_SNOWBALL_RUNTIME_DATA_FILES } from "../../src/sdks/react-native/tools/validate-mobile-runtime-files.mjs"; - -test("Cargo packages exactly match their complete package listing", () => { - const listed = [ - "Cargo.toml", - "LICENSE", - "README.md", - "THIRD_PARTY_NOTICES.md", - "src/lib.rs", - ]; - assert.equal( - cargoPackageMemberContractViolation(listed, listed), - null, - ); - - const unexpected = cargoPackageMemberContractViolation( - [...listed, "UNDECLARED.md"], - listed, - ); - assert.deepEqual(unexpected, { - kind: "mismatch", - actual: [ - "Cargo.toml", - "LICENSE", - "README.md", - "THIRD_PARTY_NOTICES.md", - "UNDECLARED.md", - "src/lib.rs", - ], - expected: [ - "Cargo.toml", - "LICENSE", - "README.md", - "THIRD_PARTY_NOTICES.md", - "src/lib.rs", - ], - }); - - assert.deepEqual( - cargoPackageMemberContractViolation(listed, [...listed, "LICENSE"]), - { kind: "listing-duplicate" }, - ); -}); - -const REPOSITORY_ROOT = path.join( - import.meta.dir, - "../../src/sdks/swift/Tests/Fixtures/swiftpm-extension-resources", -); -const ARCHIVE_ROOT = "package/Tests/Fixtures/swiftpm-extension-resources"; -const REACT_NATIVE_METADATA = JSON.parse(readFileSync(path.join( - import.meta.dir, - "../../src/extensions/generated/sdk/extensions.json", -), "utf8")); -const MOBILE_STATIC_REGISTRY = JSON.parse(readFileSync(path.join( - import.meta.dir, - "../../src/extensions/generated/mobile/static-registry.json", -), "utf8")); -const EXPO_IOS_RUNNER = path.join( - import.meta.dir, - "../../src/sdks/react-native/tools/expo-ios-runner.sh", -); - -function packagedMobileRuntimeNames(prefix, extensionAssets) { - return [ - ...CORE_SNOWBALL_RUNTIME_DATA_FILES.map((name) => `${prefix}runtime/files/${name}`), - ...extensionAssets.map( - (name) => `${prefix}runtime/files/share/postgresql/extension/${name}`, - ), - ]; -} - -test("packaged mobile apps require the native-direct runtime contract", () => { - assert.doesNotThrow(() => validatePackagedMobileRuntimeManifest({ - schema: "oliphaunt-runtime-resources-v1", - mode: "native-direct", - })); - assert.throws( - () => validatePackagedMobileRuntimeManifest({ - schema: "oliphaunt-runtime-resources-v1", - mode: "native-server", - }), - /mode=native-direct/u, - ); -}); - -test("staged iOS evidence and the Expo runner share the Payload CocoaPods file-list contract", () => { - const scratchPath = path.join(path.sep, "candidate-scratch"); - const contract = iosPayloadCocoaPodsFileListPaths(scratchPath); - assert.deepEqual(contract, { - inputFile: path.join( - scratchPath, - "examples/react-native-expo/ios/Pods/Target Support Files/OliphauntReactNativePayload/OliphauntReactNativePayload-xcframeworks-input-files.xcfilelist", - ), - outputFile: path.join( - scratchPath, - "examples/react-native-expo/ios/Pods/Target Support Files/OliphauntReactNativePayload/OliphauntReactNativePayload-xcframeworks-output-files.xcfilelist", - ), - podName: "OliphauntReactNativePayload", - supportRoot: path.join( - scratchPath, - "examples/react-native-expo/ios/Pods/Target Support Files/OliphauntReactNativePayload", - ), - }); - - const runner = readFileSync(EXPO_IOS_RUNNER, "utf8"); - const validator = runner.match( - /validate_ios_static_extension_linkage\(\) \{(?[\s\S]*?)\n\}/u, - )?.groups?.body; - assert.ok(validator, "Expo iOS runner must define its static-extension linkage validator"); - assert.match( - validator, - /local pods_support="\$example_dir\/ios\/Pods\/Target Support Files\/OliphauntReactNativePayload"/u, - ); - assert.match( - validator, - /local input_file="\$pods_support\/OliphauntReactNativePayload-xcframeworks-input-files\.xcfilelist"/u, - ); - assert.match( - validator, - /local output_file="\$pods_support\/OliphauntReactNativePayload-xcframeworks-output-files\.xcfilelist"/u, - ); -}); - -test("matches CocoaPods iOS link inputs exactly for all generated extension identities", () => { - assert.equal(REACT_NATIVE_METADATA.extensions.length, 39); - const bySqlName = new Map(REACT_NATIVE_METADATA.extensions.map((row) => [ - row["sql-name"], - row["native-module-stem"], - ])); - assert.equal(bySqlName.get("intarray"), "_int"); - assert.equal(bySqlName.get("pgtap"), null); - assert.equal(bySqlName.get("postgis"), "postgis-3"); - assert.equal(bySqlName.get("uuid-ossp"), "uuid-ossp"); - - const expectedStems = [...bySqlName.values()].filter((stem) => stem !== null).sort(); - assert.equal(expectedStems.length, 38); - const evidence = iosCocoaPodsExtensionLinkEvidence({ - expectedStems, - inputText: expectedStems.map( - (stem) => `\${PODS_ROOT}/../oliphaunt/frameworks/extensions/liboliphaunt_extension_${stem}.xcframework`, - ).join("\r\n"), - outputText: expectedStems.map( - (stem, index) => `\${PODS_XCFRAMEWORKS_BUILD_DIR}/OliphauntReactNativePayload/liboliphaunt_extension_${stem}${index === 0 ? ".framework" : ".a"}`, - ).join("\n"), - }); - const expectedArtifacts = expectedStems.map((stem) => `liboliphaunt_extension_${stem}`).sort(); - - assert.deepEqual(evidence, { - expectedArtifacts, - inputArtifacts: expectedArtifacts, - missingInput: [], - missingOutput: [], - outputArtifacts: expectedArtifacts, - unexpectedInput: [], - unexpectedOutput: [], - }); -}); - -test("does not let prefix collisions or free-text fragments satisfy iOS link identities", () => { - const evidence = iosCocoaPodsExtensionLinkEvidence({ - expectedStems: ["postgis-3", "uuid-ossp"], - inputText: [ - "note: liboliphaunt_extension_postgis-3.xcframework is not a path component", - "${PODS_ROOT}/liboliphaunt_extension_postgis-30.xcframework", - "${PODS_ROOT}/liboliphaunt_extension_uuid-ossp-extra.xcframework", - ].join("\n"), - outputText: [ - "${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-30.a", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_uuid-ossp-extra.a", - ].join("\n"), - }); - - assert.deepEqual(evidence.missingInput, [ - "liboliphaunt_extension_postgis-3", - "liboliphaunt_extension_uuid-ossp", - ]); - assert.deepEqual(evidence.unexpectedInput, [ - "liboliphaunt_extension_postgis-30", - "liboliphaunt_extension_uuid-ossp-extra", - ]); - assert.deepEqual(evidence.missingOutput, evidence.missingInput); - assert.deepEqual(evidence.unexpectedOutput, evidence.unexpectedInput); - - const inputOnly = iosCocoaPodsExtensionLinkEvidence({ - expectedStems: ["postgis-3"], - inputText: "${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework", - outputText: "", - }); - assert.deepEqual(inputOnly.missingInput, []); - assert.deepEqual(inputOnly.missingOutput, ["liboliphaunt_extension_postgis-3"]); - - const outputOnly = iosCocoaPodsExtensionLinkEvidence({ - expectedStems: ["postgis-3"], - inputText: "", - outputText: "${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-3.a", - }); - assert.deepEqual(outputOnly.missingInput, ["liboliphaunt_extension_postgis-3"]); - assert.deepEqual(outputOnly.missingOutput, []); - - assert.throws( - () => iosCocoaPodsExtensionLinkEvidence({ - expectedStems: ["postgis-3"], - inputText: "${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework.attacker", - outputText: "${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-3.a", - }), - /unsupported Oliphaunt extension artifact component/u, - ); - assert.throws( - () => iosCocoaPodsExtensionLinkEvidence({ - expectedStems: ["postgis-3"], - inputText: [ - "${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework", - "${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework", - ].join("\n"), - outputText: "${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-3.a", - }), - /input file list repeats Oliphaunt extension artifact/u, - ); - assert.throws( - () => iosCocoaPodsExtensionLinkEvidence({ - expectedStems: ["postgis-3"], - inputText: "${PODS_ROOT}/liboliphaunt_extension_postgis-3.xcframework\0", - outputText: "${PODS_XCFRAMEWORKS_BUILD_DIR}/liboliphaunt_extension_postgis-3.a", - }), - /input file list line 1 contains NUL/u, - ); - assert.throws( - () => iosCocoaPodsExtensionLinkEvidence({ - expectedStems: ["future-name", "future_name"], - inputText: "", - outputText: "", - }), - /collide after registration-symbol normalization/u, - ); -}); - -function selectionNeutralCarrier(version = "1.2.3") { - const product = "liboliphaunt-native"; - const tag = `${product}-v${version}`; - const assets = [ - ["base-xcframework", `liboliphaunt-${version}-apple-spm-xcframework.zip`, "zip", "liboliphaunt.xcframework", "a"], - ["runtime-resources", `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`, "tar.gz", "oliphaunt", "b"], - ["icu-data", `liboliphaunt-${version}-icu-data.tar.gz`, "tar.gz", ".", "c"], - ].map(([role, name, format, member, digit], index) => ({ - bytes: index + 1, - format, - member, - name, - role, - sha256: digit.repeat(64), - url: `https://github.com/f0rr0/oliphaunt/releases/download/${tag}/${name}`, - })); - return { - base: { assets, product, tag, version }, - carriers: [], - extensions: [], - legal: { base: iosBaseLegalMetadata(), extensions: [] }, - schema: "oliphaunt-react-native-ios-carrier-v1", - }; -} - -function fixtureFiles(root = REPOSITORY_ROOT) { - const files = []; - const visit = (directory) => { - for (const name of readdirSync(directory).sort()) { - const file = path.join(directory, name); - if (statSync(file).isDirectory()) { - visit(file); - } else if (statSync(file).isFile()) { - files.push(file); - } - } - }; - visit(root); - return files; -} - -function repositoryFixtureEntries() { - return new Map(fixtureFiles().map((file) => { - const relative = path.relative(REPOSITORY_ROOT, file).split(path.sep).join("/"); - const bytes = readFileSync(file); - return [ - `${ARCHIVE_ROOT}/${relative}`, - { isFile: true, data: () => bytes }, - ]; - })); -} - -test("permits only an exact byte-for-byte Swift extension-resource fixture mirror", () => { - const entries = repositoryFixtureEntries(); - const allowed = validateSwiftSourceFixtureEntries("Oliphaunt-source.zip", entries); - - assert.deepEqual([...allowed].sort(), [...entries.keys()].sort()); - assert.equal( - findSdkRuntimePayloadViolation("oliphaunt-swift", [...entries.keys()], allowed), - null, - ); -}); - -test("rejects missing and extra Swift extension-resource fixture files", () => { - const missing = repositoryFixtureEntries(); - missing.delete(missing.keys().next().value); - assert.throws( - () => validateSwiftSourceFixtureEntries("missing.zip", missing), - /file set must exactly match.*missing=\["/u, - ); - - const extra = repositoryFixtureEntries(); - extra.set(`${ARCHIVE_ROOT}/unexpected/extra.control`, { - isFile: true, - data: () => Buffer.from("unexpected\n"), - }); - assert.throws( - () => validateSwiftSourceFixtureEntries("extra.zip", extra), - /file set must exactly match.*extra=\["/u, - ); -}); - -test("rejects tampered Swift extension-resource fixture bytes", () => { - const entries = repositoryFixtureEntries(); - const [name, entry] = entries.entries().next().value; - entries.set(name, { - ...entry, - data: () => Buffer.concat([Buffer.from(entry.data()), Buffer.from("tampered")]), - }); - - assert.throws( - () => validateSwiftSourceFixtureEntries("tampered.zip", entries), - /must byte-for-byte match/u, - ); -}); - -test("continues to reject runtime payloads outside the exact fixture subtree", () => { - const entries = repositoryFixtureEntries(); - const allowed = validateSwiftSourceFixtureEntries("Oliphaunt-source.zip", entries); - const outsideFixture = - "package/Sources/Oliphaunt/Resources/runtime/files/share/postgresql/extension/pgtap.control"; - - assert.equal( - findSdkRuntimePayloadViolation( - "oliphaunt-swift", - [...entries.keys(), outsideFixture], - allowed, - ), - outsideFixture, - ); -}); - -test("mobile artifact gate uses generated ownership for ancillary extension SQL", () => { - for (const [platform, prefix] of [ - ["Android", "assets/oliphaunt/"], - ["iOS", "OliphauntReactNativeResources.bundle/oliphaunt/"], - ]) { - const artifactNames = packagedMobileRuntimeNames(prefix, [ - "pgtap.control", - "pgtap--1.3.5.sql", - "pgtap-core--1.3.5.sql", - "pgtap-schema.sql", - "uninstall_pgtap.sql", - "plpgsql.control", - "plpgsql--1.0.sql", - ]); - - assert.doesNotThrow(() => validatePackagedMobileRuntimeFiles({ - artifactNames, - metadata: REACT_NATIVE_METADATA, - platform, - prefix, - registry: MOBILE_STATIC_REGISTRY, - selected: ["pgtap"], - })); - assert.throws( - () => validatePackagedMobileRuntimeFiles({ - artifactNames: artifactNames.filter((name) => !name.endsWith("/english.stop")), - metadata: REACT_NATIVE_METADATA, - platform, - prefix, - registry: MOBILE_STATIC_REGISTRY, - selected: ["pgtap"], - }), - /missing PostgreSQL core Snowball runtime data: .*english[.]stop/u, - ); - assert.throws( - () => validatePackagedMobileRuntimeFiles({ - artifactNames, - metadata: REACT_NATIVE_METADATA, - platform, - prefix, - registry: MOBILE_STATIC_REGISTRY, - selected: [], - }), - /unselected PostgreSQL extension asset/u, - ); - } -}); - -test("mobile manifests keep full, createable, and native extension domains distinct", () => { - const rows = new Map([ - ["auto_explain", { - "creates-extension": false, - "native-module-stem": "auto_explain", - "sql-name": "auto_explain", - }], - ["future_hook", { - "creates-extension": false, - "native-module-stem": "-", - "sql-name": "future_hook", - }], - ["pgtap", { - "creates-extension": true, - "native-module-stem": "-", - "sql-name": "pgtap", - }], - ]); - const runtime = { - extensions: "pgtap", - mobileStaticRegistryRegistered: "auto_explain", - mobileStaticRegistryPending: "", - mobileStaticRegistryState: "complete", - nativeModuleStems: "auto_explain", - selectedExtensions: "auto_explain,future_hook,pgtap", - }; - const staticRegistry = { - modules: "auto_explain", - nativeModuleStems: "auto_explain", - pendingExtensions: "", - registeredExtensions: "auto_explain", - state: "complete", - }; - - assert.deepEqual( - validateMobileExtensionManifestDomains({ runtime, staticRegistry, rows }), - { - createableExtensions: ["pgtap"], - nativeExtensions: ["auto_explain"], - nativeModuleStems: ["auto_explain"], - selectedExtensions: ["auto_explain", "future_hook", "pgtap"], - }, - ); - assert.throws( - () => validateMobileExtensionManifestDomains({ - runtime: Object.fromEntries( - Object.entries(runtime).filter(([key]) => key !== "selectedExtensions"), - ), - staticRegistry, - rows, - }), - /must define the full selectedExtensions domain/u, - ); - assert.throws( - () => validateMobileExtensionManifestDomains({ - runtime: { ...runtime, extensions: "auto_explain,pgtap" }, - staticRegistry, - rows, - }), - /createable extensions/u, - ); - assert.throws( - () => validateMobileExtensionManifestDomains({ - runtime: { ...runtime, mobileStaticRegistryRegistered: "pgtap" }, - staticRegistry, - rows, - }), - /registered native extensions/u, - ); - assert.throws( - () => validateMobileExtensionManifestDomains({ - runtime: { ...runtime, mobileStaticRegistryState: "not-required" }, - staticRegistry, - rows, - }), - /mobileStaticRegistryState/u, - ); - assert.throws( - () => validateMobileExtensionManifestDomains({ - runtime, - staticRegistry: { ...staticRegistry, modules: "" }, - rows, - }), - /static-registry modules/u, - ); -}); - -test("binds the React Native npm carrier bytes to selection-neutral staged evidence", () => { - const member = "package/oliphaunt-react-native-ios-carriers.json"; - const bytes = Buffer.from(`${JSON.stringify(selectionNeutralCarrier(), null, 2)}\n`); - assert.deepEqual( - validateReactNativePackagedCarrier({ - artifact: "oliphaunt-react-native.tgz", - evidence: bytes, - expectedNativeVersion: "1.2.3", - memberBytes: bytes, - names: [member], - }), - selectionNeutralCarrier(), - ); - - assert.throws( - () => validateReactNativePackagedCarrier({ - artifact: "missing.tgz", - evidence: bytes, - expectedNativeVersion: "1.2.3", - memberBytes: Buffer.alloc(0), - names: [], - }), - /must contain exactly one/u, - ); - assert.throws( - () => validateReactNativePackagedCarrier({ - artifact: "skewed.tgz", - evidence: bytes, - expectedNativeVersion: "1.2.3", - memberBytes: Buffer.from(`${JSON.stringify(selectionNeutralCarrier("1.2.4"))}\n`), - names: [member], - }), - /byte-for-byte match/u, - ); - assert.throws( - () => validateReactNativePackagedCarrier({ - artifact: "wrong-version.tgz", - evidence: Buffer.from(`${JSON.stringify(selectionNeutralCarrier("1.2.4"))}\n`), - expectedNativeVersion: "1.2.3", - memberBytes: Buffer.from(`${JSON.stringify(selectionNeutralCarrier("1.2.4"))}\n`), - names: [member], - }), - /must match liboliphaunt-native 1\.2\.3/u, - ); -}); - -test("derives nested bundle compatibility from the staged bundle data", () => { - const compatibility = { - nativeRuntimeProduct: "liboliphaunt-native", - nativeRuntimeVersion: "1.2.3", - postgresMajor: "18", - }; - const carrier = { - family: "native", - target: "android-arm64-v8a", - }; - const rows = [{ - member: { sqlName: "cube" }, - asset: { - bytes: 123, - identity: null, - kind: "runtime", - memberPath: "extensions/cube/cube.tar.gz", - sha256: "a".repeat(64), - }, - }]; - - assert.deepEqual( - expectedExtensionBundleManifest({ - product: "oliphaunt-extension-contrib-pg18", - version: "1.0.0", - data: { compatibility }, - carrier, - rows, - }), - { - schema: "oliphaunt-extension-bundle-v1", - product: "oliphaunt-extension-contrib-pg18", - version: "1.0.0", - compatibility, - family: "native", - target: "android-arm64-v8a", - licenseProfile: "contrib-native", - licenseFiles: [], - members: [{ - sqlName: "cube", - kind: "runtime", - identity: null, - path: "extensions/cube/cube.tar.gz", - sha256: "a".repeat(64), - bytes: 123, - }], - }, - ); -}); - -test("renders every single-extension asset identity into the public properties manifest", () => { - const dependencyIdentities = ["geos", "geos-c", "json-c", "libxml2", "proj", "sqlite"]; - const assets = [ - ...dependencyIdentities.map((identity) => ({ - family: "native", - target: "ios-xcframework", - kind: "ios-dependency-xcframework", - identity, - name: `postgis-${identity}.zip`, - })), - { - family: "native", - target: "ios-xcframework", - kind: "ios-xcframework", - identity: "postgis-3", - name: "postgis.zip", - }, - { - family: "native", - target: "ios-xcframework", - kind: "runtime", - identity: null, - name: "postgis-runtime.tar.gz", - }, - ]; - const text = extensionReleasePropertiesText({ - product: "oliphaunt-extension-postgis", - version: "1.0.0", - manifest: { - schema: "oliphaunt-extension-ci-artifacts-v1", - sqlName: "postgis", - createsExtension: true, - dependencies: [], - dataFiles: ["contrib/postgis-3.6/postgis.sql", "proj/proj.db"], - extensionSqlFileNames: ["uninstall_postgis.sql"], - extensionSqlFilePrefixes: ["postgis_comments", "rtpostgis"], - nativeModuleStem: "postgis-3", - iosNativeDependencies: dependencyIdentities, - sharedPreloadLibraries: [], - assets, - }, - releaseData: { - schema: "oliphaunt-extension-release-manifest-v1", - extensionClass: "external", - versioning: "independent", - sourceIdentity: { kind: "git" }, - }, - directAssets: assets, - }); - const assetLines = text.split("\n").filter((line) => line.startsWith("asset.")); - - assert.deepEqual(assetLines, [ - "asset.native.ios-xcframework.ios-dependency-xcframework.geos=postgis-geos.zip", - "asset.native.ios-xcframework.ios-dependency-xcframework.geos-c=postgis-geos-c.zip", - "asset.native.ios-xcframework.ios-dependency-xcframework.json-c=postgis-json-c.zip", - "asset.native.ios-xcframework.ios-dependency-xcframework.libxml2=postgis-libxml2.zip", - "asset.native.ios-xcframework.ios-dependency-xcframework.proj=postgis-proj.zip", - "asset.native.ios-xcframework.ios-dependency-xcframework.sqlite=postgis-sqlite.zip", - "asset.native.ios-xcframework.ios-xcframework.postgis-3=postgis.zip", - "asset.native.ios-xcframework.runtime=postgis-runtime.tar.gz", - ]); - assert.equal( - Object.keys(parseUniquePropertiesText(text)).filter((key) => key.startsWith("asset.")).length, - 8, - ); - const properties = parseUniquePropertiesText(text); - assert.equal(properties.createsExtension, "true"); - assert.equal(properties.dataFiles, "contrib/postgis-3.6/postgis.sql,proj/proj.db"); - assert.equal(properties.extensionSqlFileNames, "uninstall_postgis.sql"); - assert.equal(properties.extensionSqlFilePrefixes, "postgis_comments,rtpostgis"); - assert.doesNotMatch(text, /^carrier\./mu); -}); - -test("freezes each bundle member desktop inventory in the public properties manifest", () => { - const text = extensionReleasePropertiesText({ - product: "oliphaunt-extension-contrib-pg18", - version: "1.0.0", - manifest: { - schema: "oliphaunt-extension-ci-artifacts-v2", - extensions: [{ - sqlName: "pgtap", - createsExtension: true, - dependencies: [], - dataFiles: [], - extensionSqlFileNames: ["uninstall_pgtap.sql"], - extensionSqlFilePrefixes: ["pgtap-core", "pgtap-schema"], - nativeModuleStem: null, - iosNativeDependencies: [], - sharedPreloadLibraries: [], - assets: [], - }], - }, - releaseData: { - schema: "oliphaunt-extension-release-manifest-v2", - extensionClass: "contrib", - versioning: "coordinated", - sourceIdentity: { kind: "repository" }, - }, - directAssets: [], - }); - const properties = parseUniquePropertiesText(text); - - assert.equal(properties["extension.pgtap.createsExtension"], "true"); - assert.equal(properties["extension.pgtap.dataFiles"], ""); - assert.equal(properties["extension.pgtap.extensionSqlFileNames"], "uninstall_pgtap.sql"); - assert.equal(properties["extension.pgtap.extensionSqlFilePrefixes"], "pgtap-core,pgtap-schema"); -}); - -test("preserves hostile property names and rejects repeated keys", () => { - const hostile = parseUniquePropertiesText("__proto__=undeclared\n"); - assert.equal(Object.hasOwn(hostile, "__proto__"), true); - assert.equal(hostile.__proto__, "undeclared"); - assert.throws( - () => parseUniquePropertiesText("asset.native.ios-xcframework.runtime=first.tar.gz\nasset.native.ios-xcframework.runtime=second.tar.gz\n"), - /repeats key "asset\.native\.ios-xcframework\.runtime"/u, - ); - assert.throws( - () => parseUniquePropertiesText("asset.native.ios-xcframework.ios-dependency-xcframework=geos.zip\nasset.native.ios-xcframework.ios-dependency-xcframework=geos-c.zip\n"), - /repeats key "asset\.native\.ios-xcframework\.ios-dependency-xcframework"/u, - ); - assert.throws( - () => parseUniquePropertiesText("__proto__=first\n__proto__=second\n"), - /repeats key "__proto__"/u, - ); -}); diff --git a/tools/release/check-wasix-napi-release-assets.mjs b/tools/release/check-wasix-napi-release-assets.mjs deleted file mode 100644 index 2e66b7be7..000000000 --- a/tools/release/check-wasix-napi-release-assets.mjs +++ /dev/null @@ -1,478 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { readFileSync } from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { - assertFileExists, - checksumManifest, - readArchiveEntries, - sha256, -} from "./release-asset-validation.mjs"; -import { - ROOT, - artifactTargets, - compareText, - currentProductVersion, - exactExtensionProducts, - expectedAssets, - extensionSqlNames, - extensionWasixAotMemberSqlNames, - fail, -} from "./release-artifact-targets.mjs"; -import { inspectPlatformBinaryEntries } from "./platform-binary-contract.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - assertReleaseNoticesInEntries, - releaseProfilePackageLicense, -} from "./release-notices.mjs"; -import { - WINDOWS_VC_RUNTIME_DLLS, - WINDOWS_VC_RUNTIME_RECEIPT, -} from "./windows-vc-runtime-closure.mjs"; - -const PREFIX = "check-wasix-napi-release-assets.mjs"; -const PRODUCT = "oliphaunt-wasix-napi"; -const KIND = "wasix-napi-addon"; -const PROFILE = "wasix-napi-addon"; -const PACKAGE_LICENSE = releaseProfilePackageLicense(PROFILE).spdx; -const BINARY = "oliphaunt_wasix_napi.node"; -const PRODUCT_MANIFEST = JSON.parse( - readFileSync(path.join(ROOT, "src/runtimes/wasix-napi/package.json"), "utf8"), -); -const SHA256 = /^[0-9a-f]{64}$/u; - -function parseArgs(argv) { - const args = { - assetDir: path.join(ROOT, "target/oliphaunt-wasix-napi/release-assets"), - allowPartial: false, - npmPackages: [], - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--asset-dir") { - const value = argv[index + 1]; - if (!value) fail(PREFIX, "--asset-dir requires a value"); - args.assetDir = path.resolve(value); - index += 1; - } else if (arg === "--allow-partial") { - args.allowPartial = true; - } else if (arg === "--npm-package") { - const value = argv[index + 1]; - if (!value) fail(PREFIX, "--npm-package requires a value"); - args.npmPackages.push(path.resolve(value)); - index += 1; - } else { - fail(PREFIX, `unknown argument ${arg}`); - } - } - return args; -} - -function archiveJson(entries, member, label) { - const entry = entries.get(member); - if (!entry?.isFile || entry.isSymbolicLink) { - throw new Error(`${label} is missing regular member ${member}`); - } - try { - return JSON.parse(Buffer.from(entry.data()).toString("utf8")); - } catch (cause) { - throw new Error(`${label} member ${member} must contain valid JSON: ${cause.message}`); - } -} - -function entrySha256(entry) { - return createHash("sha256").update(Buffer.from(entry.data())).digest("hex"); -} - -function assertSameStrings(actual, expected, label) { - const actualSorted = [...actual].sort(compareText); - const expectedSorted = [...expected].sort(compareText); - if ( - actualSorted.length !== new Set(actualSorted).size - || JSON.stringify(actualSorted) !== JSON.stringify(expectedSorted) - ) { - throw new Error( - `${label} must be exactly ${expectedSorted.join(", ")}; got ${actualSorted.join(", ")}`, - ); - } -} - -function canonicalRepoPath(value, label) { - if ( - typeof value !== "string" - || value.length === 0 - || value.includes("\\") - || path.posix.isAbsolute(value) - || path.posix.normalize(value) !== value - || value.split("/").some((part) => !part || part === "." || part === "..") - ) { - throw new Error(`${label} must be a canonical repository-relative path`); - } - return value; -} - -function digestRecord(value, label, { expectedPath, pathPrefix, pathSuffix } = {}) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw new Error(`${label} must be an object`); - } - const recordPath = canonicalRepoPath(value.path, `${label} path`); - if ( - (expectedPath !== undefined && recordPath !== expectedPath) - || (pathPrefix !== undefined && !recordPath.startsWith(pathPrefix)) - || (pathSuffix !== undefined && !recordPath.endsWith(pathSuffix)) - ) { - throw new Error(`${label} has incompatible path ${recordPath}`); - } - if (!SHA256.test(value.sha256 ?? "")) { - throw new Error(`${label} must record a lowercase SHA-256 digest`); - } - return recordPath; -} - -function assertBuildInputs(buildInputs, target, label) { - if ( - buildInputs?.schema !== "oliphaunt-wasix-napi-build-inputs-v1" - || buildInputs.target !== target.target - || buildInputs.targetTriple !== target.triple - || buildInputs.inputs === null - || Array.isArray(buildInputs.inputs) - || typeof buildInputs.inputs !== "object" - ) { - throw new Error(`${label} has incompatible embedded build-input provenance`); - } - const inputs = buildInputs.inputs; - digestRecord(inputs.portableManifest, `${label} portable WASIX manifest`, { - expectedPath: "target/oliphaunt-wasix/assets/manifest.json", - }); - if (!Array.isArray(inputs.portableTools)) { - throw new Error(`${label} portable tool inventory must be an array`); - } - assertSameStrings( - inputs.portableTools.map((row) => row?.name), - ["pg_dump", "psql"], - `${label} portable tool inventory`, - ); - for (const tool of inputs.portableTools) { - digestRecord(tool, `${label} portable tool ${tool.name}`, { - expectedPath: `target/oliphaunt-wasix/assets/bin/${tool.name}.wasix.wasm`, - }); - } - if (inputs.runtimeAotManifest?.targetTriple !== target.triple) { - throw new Error(`${label} runtime AOT manifest must target ${target.triple}`); - } - digestRecord(inputs.runtimeAotManifest, `${label} runtime AOT manifest`, { - expectedPath: `target/oliphaunt-wasix/aot/${target.triple}/manifest.json`, - }); - if (!Array.isArray(inputs.extensionArtifacts)) { - throw new Error(`${label} extension artifact inventory must be an array`); - } - const expectedProducts = exactExtensionProducts(PREFIX); - assertSameStrings( - inputs.extensionArtifacts.map((row) => row?.product), - expectedProducts, - `${label} extension product inventory`, - ); - for (const extension of inputs.extensionArtifacts) { - const product = extension.product; - digestRecord(extension.manifest, `${label} ${product} extension manifest`, { - pathPrefix: "target/extension-artifacts/", - pathSuffix: "/extension-artifacts.json", - }); - if (!Array.isArray(extension.portableArchives)) { - throw new Error(`${label} ${product} portable extension inventory must be an array`); - } - assertSameStrings( - extension.portableArchives.map((row) => row?.sqlName), - extensionSqlNames(product, PREFIX), - `${label} ${product} portable extension inventory`, - ); - for (const archive of extension.portableArchives) { - digestRecord(archive, `${label} ${product}/${archive.sqlName} portable extension`, { - pathPrefix: "target/extension-artifacts/", - pathSuffix: "-wasix-portable.tar.zst", - }); - } - if (!Array.isArray(extension.aotManifests)) { - throw new Error(`${label} ${product} extension AOT inventory must be an array`); - } - assertSameStrings( - extension.aotManifests.map((row) => row?.sqlName), - extensionWasixAotMemberSqlNames(product, PREFIX), - `${label} ${product} extension AOT inventory`, - ); - for (const aot of extension.aotManifests) { - if (aot?.targetTriple !== target.triple) { - throw new Error(`${label} ${product}/${aot?.sqlName} AOT manifest must target ${target.triple}`); - } - digestRecord(aot, `${label} ${product}/${aot.sqlName} AOT manifest`, { - pathPrefix: "target/extension-artifacts/", - pathSuffix: "/manifest.json", - }); - } - } - digestRecord(inputs.icuData, `${label} ICU data inventory`, { - expectedPath: "target/oliphaunt-wasix/wasix-build/work/icu-wasix/share/icu", - }); - if (!Number.isSafeInteger(inputs.icuData.fileCount) || inputs.icuData.fileCount < 1) { - throw new Error(`${label} ICU data inventory must record at least one regular file`); - } -} - -export function assertWasixNapiCarrierManifest(manifest, target, version, label = "carrier") { - if (manifest.name !== target.npmPackage || manifest.version !== version) { - throw new Error(`${label} must identify ${target.npmPackage}@${version}`); - } - if (manifest.license !== PACKAGE_LICENSE) { - throw new Error(`${label} package license must be ${PACKAGE_LICENSE}, got ${JSON.stringify(manifest.license)}`); - } - if ( - manifest.oliphaunt?.target !== target.target - || manifest.oliphaunt?.runtimeProduct !== PRODUCT_MANIFEST.oliphaunt.runtimeProduct - || manifest.oliphaunt?.runtimeVersion !== PRODUCT_MANIFEST.oliphaunt.runtimeVersion - || manifest.oliphaunt?.addonAbiVersion !== PRODUCT_MANIFEST.oliphaunt.addonAbiVersion - || manifest.oliphaunt?.nodeApiVersion !== PRODUCT_MANIFEST.oliphaunt.nodeApiVersion - || JSON.stringify(manifest.oliphaunt?.profiles) !== JSON.stringify(["standard", "icu"]) - ) { - throw new Error(`${label} has incompatible WASIX Node-API target/runtime/ABI/profile metadata`); - } - if ( - JSON.stringify(manifest.os) !== JSON.stringify([target.npmOs]) - || JSON.stringify(manifest.cpu) !== JSON.stringify([target.npmCpu]) - || (target.npmLibc === undefined - ? Object.hasOwn(manifest, "libc") - : JSON.stringify(manifest.libc) !== JSON.stringify([target.npmLibc])) - || manifest.optional !== true - || manifest.type !== "commonjs" - || Object.hasOwn(manifest, "scripts") - ) { - throw new Error(`${label} has incompatible npm platform or lifecycle metadata`); - } - const expectedFiles = [ - "prebuilds", - "artifact-provenance.json", - "README.md", - "LICENSE", - "THIRD_PARTY_NOTICES.md", - "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", - "THIRD_PARTY_LICENSES", - ]; - if (JSON.stringify(manifest.files) !== JSON.stringify(expectedFiles)) { - throw new Error(`${label} must declare the exact one-addon package file surface`); - } - if ( - manifest.exports?.[`./${BINARY}`] !== `./prebuilds/${BINARY}` - || JSON.stringify(Object.keys(manifest.exports ?? {})) - !== JSON.stringify([`./${BINARY}`, "./artifact-provenance.json", "./package.json"]) - ) { - throw new Error(`${label} must expose exactly one stable addon binary subpath`); - } - return manifest; -} - -export function assertSingleWasixNapiAddonMember(entries, binaryMember, label = "carrier") { - const nativeMembers = [...entries.keys()].filter((name) => name.endsWith(".node")); - if (JSON.stringify(nativeMembers) !== JSON.stringify([binaryMember])) { - throw new Error( - `${label} must contain exactly one native addon member ${binaryMember}; got ${nativeMembers.join(", ")}`, - ); - } -} - -export function assertWasixNapiPlatformEntries( - entries, - { target, label = "carrier", prefix = "", binaryDirectory = "" }, -) { - inspectPlatformBinaryEntries( - [...entries].map(([name, entry]) => ({ name, ...entry })), - { target, rootLabel: label }, - ); - if (target !== "windows-x64-msvc") return; - - const sibling = (name) => [prefix, binaryDirectory, name].filter(Boolean).join("/"); - const runtimeNames = new Set(WINDOWS_VC_RUNTIME_DLLS); - const actualRuntimeMembers = [...entries] - .filter(([name, entry]) => entry?.isFile && runtimeNames.has(path.posix.basename(name).toLowerCase())) - .map(([name]) => name) - .sort(compareText); - const expectedRuntimeMembers = WINDOWS_VC_RUNTIME_DLLS - .filter((name) => entries.has(sibling(name))) - .map((name) => sibling(name)) - .sort(compareText); - if (JSON.stringify(actualRuntimeMembers) !== JSON.stringify(expectedRuntimeMembers)) { - throw new Error( - `${label} must place its exact app-local VC runtime closure beside ${sibling(BINARY)}`, - ); - } - - const expectedReceiptMember = sibling(WINDOWS_VC_RUNTIME_RECEIPT); - const actualReceiptMembers = [...entries.keys()] - .filter((name) => path.posix.basename(name).toLowerCase() === WINDOWS_VC_RUNTIME_RECEIPT) - .sort(compareText); - const expectedReceiptMembers = expectedRuntimeMembers.length > 0 ? [expectedReceiptMember] : []; - if (JSON.stringify(actualReceiptMembers) !== JSON.stringify(expectedReceiptMembers)) { - throw new Error(`${label} must carry one VC runtime receipt beside its app-local closure`); - } - if (expectedRuntimeMembers.length === 0) return; - - const receipt = entries.get(expectedReceiptMember); - if (!receipt?.isFile || receipt.isSymbolicLink) { - throw new Error(`${label} is missing regular member ${expectedReceiptMember}`); - } - const expectedReceipt = expectedRuntimeMembers - .map((member) => `${entrySha256(entries.get(member))} ${path.posix.basename(member)}\n`) - .join(""); - if (Buffer.from(receipt.data()).toString("utf8") !== expectedReceipt) { - throw new Error(`${label} ${expectedReceiptMember} does not bind its exact VC runtime bytes`); - } -} - -function assertPayload(entries, { prefix = "", label, target, version, npm = false }) { - assertReleaseNoticesInEntries(entries, { profile: PROFILE, prefix, label }); - const member = (name) => prefix ? `${prefix}/${name}` : name; - const provenance = archiveJson(entries, member("artifact-provenance.json"), label); - if ( - provenance.schema !== "oliphaunt-wasix-napi-provenance-v1" - || provenance.product !== PRODUCT - || provenance.target !== target.target - || !/^[0-9a-f]{40}$/u.test(provenance.sourceSha ?? "") - || !/^[0-9a-f]{40}$/u.test(provenance.artifactSourceSha ?? "") - ) { - throw new Error(`${label} has incompatible WASIX Node-API provenance`); - } - if (provenance.sourceSha !== provenance.artifactSourceSha) { - throw new Error(`${label} provenance must bind addon source and embedded artifacts to one commit`); - } - const expectedBuild = { - cargoProfile: "release", - incremental: false, - codegenUnits: 1, - lto: "thin", - strip: "symbols", - features: ["release"], - targetTriple: target.triple, - }; - if (JSON.stringify(provenance.build) !== JSON.stringify(expectedBuild)) { - throw new Error( - `${label} provenance must record the exact optimized addon build: ${JSON.stringify(expectedBuild)}`, - ); - } - assertBuildInputs(provenance.buildInputs, target, label); - const binaryMember = member(npm ? `prebuilds/${BINARY}` : BINARY); - const entry = entries.get(binaryMember); - if (!entry?.isFile || entry.isSymbolicLink || entry.size <= 0) { - throw new Error(`${label} is missing non-empty regular ${binaryMember}`); - } - const actual = entrySha256(entry); - if ( - provenance.binary?.filename !== BINARY - || provenance.binary?.sha256 !== actual - || Object.hasOwn(provenance, "binaries") - ) { - throw new Error(`${label} provenance must bind its sole ${BINARY} subject to ${actual}`); - } - if (!npm) return; - assertSingleWasixNapiAddonMember(entries, binaryMember, label); - const manifest = archiveJson(entries, member("package.json"), label); - assertWasixNapiCarrierManifest(manifest, target, version, label); -} - -export function assertWasixNapiNpmArchive(file, targets, version) { - const label = path.basename(file); - let entries; - try { - entries = readPortableArchiveEntries(file); - } catch (error) { - throw new Error(`${label} is not a valid portable archive: ${error.message}`); - } - const manifest = archiveJson(entries, "package/package.json", label); - const target = targets.find((candidate) => candidate.npmPackage === manifest.name); - if (!target) { - throw new Error(`${label} package name is not a published WASIX Node-API carrier: ${JSON.stringify(manifest.name)}`); - } - assertPayload(entries, { prefix: "package", label, target, version, npm: true }); - assertWasixNapiPlatformEntries(entries, { - target: target.target, - label, - prefix: "package", - binaryDirectory: "prebuilds", - }); - return manifest; -} - -async function validateArchive(file, target, version) { - const entries = await readArchiveEntries(file, fail, PREFIX, "WASIX Node-API"); - try { - assertPayload(entries, { label: path.basename(file), target, version }); - } catch (error) { - fail(PREFIX, error.message); - } - assertWasixNapiPlatformEntries(entries, { - target: target.target, - label: path.basename(file), - }); -} - -async function main(argv) { - const args = parseArgs(argv); - const version = await currentProductVersion(PRODUCT, PREFIX); - const requiredAssets = expectedAssets(PRODUCT, KIND, version, PREFIX); - const targets = artifactTargets(PRODUCT, KIND, PREFIX); - const targetsByAsset = new Map( - targets.map((target) => [target.asset.replaceAll("{version}", version), target]), - ); - const missing = []; - for (const asset of requiredAssets) { - if (!(await assertFileExists(path.join(args.assetDir, asset)))) missing.push(asset); - } - if (missing.length > 0) { - if (!args.allowPartial) { - fail(PREFIX, `missing WASIX Node-API release asset(s): ${missing.join(", ")}`); - } - let present = 0; - for (const asset of targetsByAsset.keys()) { - if (await assertFileExists(path.join(args.assetDir, asset))) present += 1; - } - if (present === 0) { - fail(PREFIX, "partial WASIX Node-API validation requires at least one addon asset"); - } - } - - const checksumAsset = `${PRODUCT}-${version}-release-assets.sha256`; - const checksumPath = path.join(args.assetDir, checksumAsset); - if (!(await assertFileExists(checksumPath))) { - fail(PREFIX, `missing checksum manifest: ${checksumAsset}`); - } - const checksums = await checksumManifest(checksumPath, fail, PREFIX); - for (const asset of requiredAssets.sort(compareText)) { - const assetPath = path.join(args.assetDir, asset); - if (args.allowPartial && !(await assertFileExists(assetPath))) continue; - if (asset === checksumAsset) continue; - const expected = checksums.get(asset); - if (!expected) fail(PREFIX, `${checksumAsset} does not cover ${asset}`); - const actual = await sha256(assetPath); - if (actual !== expected) { - fail(PREFIX, `checksum mismatch for ${asset}: expected ${expected}, got ${actual}`); - } - } - for (const [asset, target] of targetsByAsset) { - const assetPath = path.join(args.assetDir, asset); - if (args.allowPartial && !(await assertFileExists(assetPath))) continue; - await validateArchive(assetPath, target, version); - } - for (const npmPackage of args.npmPackages) { - try { - assertWasixNapiNpmArchive(npmPackage, targets, version); - } catch (error) { - fail(PREFIX, error.message); - } - } - console.log(`WASIX Node-API release assets validated: ${args.assetDir}`); -} - -const invoked = process.argv[1] ? path.resolve(process.argv[1]) : ""; -if (invoked === fileURLToPath(import.meta.url)) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/check_artifact_targets.mjs b/tools/release/check_artifact_targets.mjs deleted file mode 100644 index 5502438c8..000000000 --- a/tools/release/check_artifact_targets.mjs +++ /dev/null @@ -1,1296 +0,0 @@ -#!/usr/bin/env bun - -import { existsSync, readFileSync, statSync } from "node:fs"; -import path from "node:path"; - -import { - BUILDER_JOBS, - addRequiredJobs, - planForFullRun, - planJobsForAffected, - renderPlanForFullRun, -} from "../graph/ci_plan.mjs"; -import { - extensionNativeRegistryPackageStrings, - extensionRegistryPackageStrings, - extensionWasixRegistryPackageStrings, -} from "./extension-registry-packages.mjs"; -import { - brokerRuntimeMatrix, - extensionArtifactsNativeMatrix, - extensionArtifactsWasixMatrix, - liboliphauntNativeAndroidRuntimeMatrix, - liboliphauntNativeDesktopRuntimeMatrix, - liboliphauntNativeIosRuntimeMatrix, - liboliphauntNativeRuntimeMatrix, - liboliphauntWasixAotRuntimeMatrix, - liboliphauntWasixPostmasterRuntimeMatrix, - nodeDirectRuntimeMatrix, - reactNativeAndroidMobileAppMatrix, - wasixNapiRuntimeMatrix, -} from "./artifact_target_matrix.mjs"; -import { - allArtifactTargets, - ciNpmPackageArtifactRows, - ciReleaseAssetArtifactRows, - exactExtensionProducts, - extensionArtifactTargets, - extensionMetadata, - extensionMemberPath, - extensionReleaseProduct, - extensionRegistryPackageTargetSets, - extensionSqlNames, - nativeToolsOptionalPackageProducts, - rawArtifactTargetRows, - registryPackageRows, - releaseMetadata, - sdkPackageProducts, - typescriptOptionalRuntimePackageProducts, -} from "./release-artifact-targets.mjs"; -import { ROOT, compareText, loadGraph } from "./release-graph.mjs"; -import { parseWorkflow } from "./read-workflow.mjs"; -import { declaredCarrierMap, loadPublicationCatalog } from "./publication-catalog.mjs"; - -const TOOL = "check_artifact_targets.mjs"; -const GITHUB = "github-release"; -const DESKTOP_SURFACES = [GITHUB, "rust-native-direct", "typescript-native-direct"]; -const BROKER_SURFACES = [GITHUB, "rust-broker", "typescript-broker"]; -const NODE_SURFACES = [GITHUB, "npm-optional"]; -const WASIX_NAPI_SURFACES = [GITHUB, "npm-optional"]; - -const DESKTOP = Object.freeze([ - { - target: "linux-arm64-gnu", - triple: "aarch64-unknown-linux-gnu", - runner: "ubuntu-24.04-arm", - archive: "tar.gz", - os: "linux", - cpu: "arm64", - libc: "glibc", - library: "lib/liboliphaunt.so", - nativeNpm: "@oliphaunt/liboliphaunt-linux-arm64-gnu", - toolsNpm: "@oliphaunt/tools-linux-arm64-gnu", - brokerNpm: "@oliphaunt/broker-linux-arm64-gnu", - nodeNpm: "@oliphaunt/node-direct-linux-arm64-gnu", - wasixNapiNpm: "@oliphaunt/wasix-napi-linux-arm64-gnu", - }, - { - target: "linux-x64-gnu", - triple: "x86_64-unknown-linux-gnu", - runner: "ubuntu-24.04", - archive: "tar.gz", - os: "linux", - cpu: "x64", - libc: "glibc", - library: "lib/liboliphaunt.so", - nativeNpm: "@oliphaunt/liboliphaunt-linux-x64-gnu", - toolsNpm: "@oliphaunt/tools-linux-x64-gnu", - brokerNpm: "@oliphaunt/broker-linux-x64-gnu", - nodeNpm: "@oliphaunt/node-direct-linux-x64-gnu", - wasixNapiNpm: "@oliphaunt/wasix-napi-linux-x64-gnu", - }, - { - target: "macos-arm64", - triple: "aarch64-apple-darwin", - runner: "macos-26", - archive: "tar.gz", - os: "darwin", - cpu: "arm64", - library: "lib/liboliphaunt.dylib", - nativeNpm: "@oliphaunt/liboliphaunt-darwin-arm64", - toolsNpm: "@oliphaunt/tools-darwin-arm64", - brokerNpm: "@oliphaunt/broker-darwin-arm64", - nodeNpm: "@oliphaunt/node-direct-darwin-arm64", - wasixNapiNpm: "@oliphaunt/wasix-napi-darwin-arm64", - }, - { - target: "windows-x64-msvc", - triple: "x86_64-pc-windows-msvc", - runner: "windows-2025-vs2026", - archive: "zip", - os: "win32", - cpu: "x64", - library: "bin/oliphaunt.dll", - nativeNpm: "@oliphaunt/liboliphaunt-win32-x64-msvc", - toolsNpm: "@oliphaunt/tools-win32-x64-msvc", - brokerNpm: "@oliphaunt/broker-win32-x64-msvc", - nodeNpm: "@oliphaunt/node-direct-win32-x64-msvc", - wasixNapiNpm: "@oliphaunt/wasix-napi-win32-x64-msvc", - }, -]); - -const WASIX_AOT = Object.freeze([ - ["linux-arm64-gnu", "aarch64-unknown-linux-gnu", "ubuntu-24.04-arm", "llvm-linux-aarch64.tar.xz", 668873496, "1fddcf5b30f9d3e073eb161509220b4136ea8e2f114f23084bdec33e40fa87c1"], - ["linux-x64-gnu", "x86_64-unknown-linux-gnu", "ubuntu-24.04", "llvm-linux-amd64.tar.xz", 741670068, "5fb1c687c5e895d517a23e7aabea9ec3557e3a3e33f8a8d3a8d21395157b3906"], - ["macos-arm64", "aarch64-apple-darwin", "macos-26", "llvm-darwin-aarch64.tar.xz", 479103872, "f64460f6c8a28876737402542fc5b28bb1f4262cef85f799b65ce2a7ee6f8847"], - ["windows-x64-msvc", "x86_64-pc-windows-msvc", "windows-2025-vs2026", "llvm-windows-amd64.tar.xz", 757929860, "19ff22b0cf74b53dad2fc717db2209f8162b768fc6dede9e2caa6a83c724496e"], -]); -const WASIX_POSTMASTER_TARGETS = new Set([ - "linux-arm64-gnu", - "linux-x64-gnu", - "macos-arm64", -]); - -function invariant(condition, message) { - if (!condition) throw new Error(`${TOOL}: ${message}`); -} - -function object(value, label) { - invariant(value !== null && typeof value === "object" && !Array.isArray(value), `${label} must be an object`); - return value; -} - -function sorted(values) { - return [...values].sort(compareText); -} - -function sameStrings(left, right) { - const actual = sorted(left); - const expected = sorted(right); - return actual.length === expected.length && actual.every((value, index) => value === expected[index]); -} - -function assertSameStrings(actual, expected, label) { - invariant( - sameStrings(actual, expected), - `${label} must be ${JSON.stringify(sorted(expected))}; got ${JSON.stringify(sorted(actual))}`, - ); -} - -function readJson(relativePath) { - try { - return object(JSON.parse(readFileSync(path.join(ROOT, relativePath), "utf8")), relativePath); - } catch (error) { - throw new Error(`${TOOL}: ${relativePath} is invalid JSON: ${error.message}`); - } -} - -function readToml(relativePath) { - try { - return object(Bun.TOML.parse(readFileSync(path.join(ROOT, relativePath), "utf8")), relativePath); - } catch (error) { - throw new Error(`${TOOL}: ${relativePath} is invalid TOML: ${error.message}`); - } -} - -function targetRow({ - product, - id, - kind, - target, - asset, - surfaces, - triple = null, - runner = null, - library = null, - executable = null, - npm = null, - os = null, - cpu = null, - libc = null, - llvm = null, - llvmSha256 = null, - llvmBytes = null, - tier = null, - extensionArtifacts = true, -}) { - return { - id: `${product}.${id}`, - product, - kind, - target, - asset, - surfaces: sorted(surfaces), - triple, - runner, - library, - executable, - npm, - os, - cpu, - libc, - llvm, - llvmSha256, - llvmBytes, - tier, - extensionArtifacts, - }; -} - -function portableRow(product, id, kind, asset, surfaces = [GITHUB]) { - return targetRow({ product, id, kind, target: "portable", asset, surfaces }); -} - -export function expectedArtifactTargetContract() { - const rows = []; - for (const platform of DESKTOP) { - const common = { - target: platform.target, - triple: platform.triple, - runner: platform.runner, - os: platform.os, - cpu: platform.cpu, - libc: platform.libc ?? null, - }; - rows.push( - targetRow({ - product: "liboliphaunt-native", - id: platform.target, - kind: "native-runtime", - asset: `liboliphaunt-{version}-${platform.target}.${platform.archive}`, - surfaces: DESKTOP_SURFACES, - library: platform.library, - npm: platform.nativeNpm, - ...common, - }), - targetRow({ - product: "liboliphaunt-native", - id: `tools-${platform.target}`, - kind: "native-tools", - asset: `oliphaunt-tools-{version}-${platform.target}.${platform.archive}`, - surfaces: DESKTOP_SURFACES, - npm: platform.toolsNpm, - ...common, - }), - targetRow({ - product: "oliphaunt-broker", - id: platform.target, - kind: "broker-helper", - asset: `oliphaunt-broker-{version}-${platform.target}.${platform.archive}`, - surfaces: BROKER_SURFACES, - executable: platform.os === "win32" ? "bin/oliphaunt-broker.exe" : "bin/oliphaunt-broker", - npm: platform.brokerNpm, - ...common, - }), - targetRow({ - product: "oliphaunt-node-direct", - id: platform.target, - kind: "node-direct-addon", - asset: `oliphaunt-node-direct-{version}-${platform.target}.${platform.archive}`, - surfaces: NODE_SURFACES, - library: "oliphaunt_node.node", - npm: platform.nodeNpm, - ...common, - }), - targetRow({ - product: "oliphaunt-wasix-napi", - id: platform.target, - kind: "wasix-napi-addon", - asset: `oliphaunt-wasix-napi-{version}-${platform.target}.${platform.archive}`, - surfaces: WASIX_NAPI_SURFACES, - library: "oliphaunt_wasix_napi.node", - npm: platform.wasixNapiNpm, - extensionArtifacts: false, - ...common, - }), - ); - } - rows.push( - targetRow({ - product: "liboliphaunt-native", - id: "android-arm64-v8a", - kind: "native-runtime", - target: "android-arm64-v8a", - asset: "liboliphaunt-{version}-android-arm64-v8a.tar.gz", - surfaces: [GITHUB, "maven", "react-native-android"], - triple: "aarch64-linux-android", - runner: "ubuntu-24.04", - library: "jni/arm64-v8a/liboliphaunt.so", - }), - targetRow({ - product: "liboliphaunt-native", - id: "android-x86_64", - kind: "native-runtime", - target: "android-x86_64", - asset: "liboliphaunt-{version}-android-x86_64.tar.gz", - surfaces: [GITHUB, "maven", "react-native-android"], - triple: "x86_64-linux-android", - runner: "ubuntu-24.04", - library: "jni/x86_64/liboliphaunt.so", - }), - targetRow({ - product: "liboliphaunt-native", - id: "ios-xcframework", - kind: "native-runtime", - target: "ios-xcframework", - asset: "liboliphaunt-{version}-ios-xcframework.tar.gz", - surfaces: [GITHUB, "react-native-ios", "swiftpm"], - triple: "ios-xcframework", - runner: "macos-26", - library: "liboliphaunt.xcframework", - }), - targetRow({ - product: "liboliphaunt-native", - id: "apple-spm-xcframework", - kind: "apple-swiftpm-binary", - target: "apple-spm-xcframework", - asset: "liboliphaunt-{version}-apple-spm-xcframework.zip", - surfaces: [GITHUB, "swiftpm"], - triple: "apple-xcframework", - runner: "macos-26", - }), - targetRow({ - product: "liboliphaunt-native", - id: "runtime-resources-ios-datum64", - kind: "runtime-resources", - target: "ios-datum64", - asset: "liboliphaunt-{version}-runtime-resources-ios-datum64.tar.gz", - surfaces: [GITHUB, "react-native-ios"], - }), - targetRow({ - product: "liboliphaunt-native", - id: "runtime-resources-android-datum64", - kind: "runtime-resources", - target: "android-datum64", - asset: "liboliphaunt-{version}-runtime-resources-android-datum64.tar.gz", - surfaces: [GITHUB, "maven", "react-native-android"], - }), - targetRow({ - product: "liboliphaunt-native", - id: "icu-data", - kind: "icu-data", - target: "portable", - asset: "liboliphaunt-{version}-icu-data.tar.gz", - surfaces: [GITHUB, "maven", "react-native-android", "react-native-ios", "rust-native-direct", "swiftpm", "typescript-native-direct"], - npm: "@oliphaunt/icu", - }), - portableRow("liboliphaunt-native", "checksums", "checksums", "liboliphaunt-{version}-release-assets.sha256"), - portableRow("liboliphaunt-wasix", "runtime-portable", "wasix-runtime", "liboliphaunt-wasix-{version}-runtime-portable.tar.zst"), - portableRow("liboliphaunt-wasix", "icu-data", "icu-data", "liboliphaunt-wasix-{version}-icu-data.tar.zst"), - portableRow("liboliphaunt-wasix", "checksums", "checksums", "liboliphaunt-wasix-{version}-release-assets.sha256"), - targetRow({ - product: "liboliphaunt-wasix-postmaster", - id: "checksums", - kind: "checksums", - target: "portable", - asset: "liboliphaunt-wasix-postmaster-{version}-release-assets.sha256", - surfaces: [GITHUB], - extensionArtifacts: false, - }), - portableRow("oliphaunt-broker", "checksums", "checksums", "oliphaunt-broker-{version}-release-assets.sha256", BROKER_SURFACES), - portableRow("oliphaunt-node-direct", "checksums", "checksums", "oliphaunt-node-direct-{version}-release-assets.sha256"), - targetRow({ - product: "oliphaunt-wasix-napi", - id: "checksums", - kind: "checksums", - target: "portable", - asset: "oliphaunt-wasix-napi-{version}-release-assets.sha256", - surfaces: [GITHUB], - extensionArtifacts: false, - }), - ); - for (const [target, triple, runner, llvmArchive, llvmBytes, llvmSha256] of WASIX_AOT) { - rows.push(targetRow({ - product: "liboliphaunt-wasix", - id: `aot-${target}`, - kind: "wasix-aot-runtime", - target, - asset: `liboliphaunt-wasix-{version}-runtime-aot-${target}.tar.zst`, - surfaces: [GITHUB], - triple, - runner, - llvm: `https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/${llvmArchive}`, - llvmSha256, - llvmBytes, - })); - if (WASIX_POSTMASTER_TARGETS.has(target)) { - rows.push(targetRow({ - product: "liboliphaunt-wasix-postmaster", - id: target, - kind: "wasix-postmaster-runtime", - target, - asset: `liboliphaunt-wasix-postmaster-{version}-${target}.tar.zst`, - surfaces: [GITHUB], - triple, - runner, - llvm: `https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/${llvmArchive}`, - llvmSha256, - llvmBytes, - extensionArtifacts: false, - })); - } - } - return rows.sort((left, right) => compareText(left.id, right.id)); -} - -function projectTarget(target) { - return { - id: target.id, - product: target.product, - kind: target.kind, - target: target.target, - asset: target.asset, - surfaces: sorted(target.surfaces), - triple: target.triple ?? null, - runner: target.runner ?? null, - library: target.libraryRelativePath ?? target.library_relative_path ?? target.library ?? null, - executable: target.executableRelativePath ?? target.executable_relative_path ?? target.executable ?? null, - npm: target.npmPackage ?? target.npm_package ?? target.npm ?? null, - os: target.npmOs ?? target.npm_os ?? target.os ?? null, - cpu: target.npmCpu ?? target.npm_cpu ?? target.cpu ?? null, - libc: target.npmLibc ?? target.npm_libc ?? target.libc ?? null, - llvm: target.llvmUrl ?? target.llvm_url ?? target.llvm ?? null, - llvmSha256: target.llvmSha256 ?? target.llvm_sha256 ?? null, - llvmBytes: target.llvmBytes ?? target.llvm_bytes ?? null, - tier: target.tier ?? null, - extensionArtifacts: target.extensionArtifacts ?? target.extension_artifacts ?? true, - }; -} - -export function validateArtifactTargetContract(actualTargets, expectedTargets = expectedArtifactTargetContract()) { - const actual = actualTargets.map(projectTarget).sort((left, right) => compareText(left.id, right.id)); - const expected = expectedTargets.map(projectTarget).sort((left, right) => compareText(left.id, right.id)); - assertSameStrings(actual.map(({ id }) => id), expected.map(({ id }) => id), "artifact target ids"); - const expectedById = new Map(expected.map((row) => [row.id, row])); - const seenAssets = new Set(); - for (const row of actual) { - const wanted = expectedById.get(row.id); - invariant(JSON.stringify(row) === JSON.stringify(wanted), `${row.id} public target contract differs: expected ${JSON.stringify(wanted)}, got ${JSON.stringify(row)}`); - invariant(row.asset.includes("{version}"), `${row.id} asset must bind the product version`); - if (row.surfaces.includes(GITHUB)) { - const key = `${row.product}\0${row.asset}`; - invariant(!seenAssets.has(key), `${row.product} publishes duplicate asset ${row.asset}`); - seenAssets.add(key); - } - } -} - -export function validateExtensionCoverage(runtimeTargets, products, extensionTargets) { - invariant(products.length > 0 && new Set(products).size === products.length, "extension product ids must be a non-empty unique set"); - const nativeTargets = runtimeTargets - .filter((row) => row.product === "liboliphaunt-native" && row.kind === "native-runtime" && row.extensionArtifacts) - .map(({ target }) => target); - const wasixTargets = runtimeTargets - .filter((row) => row.product === "liboliphaunt-wasix" && row.kind === "wasix-runtime") - .map(({ target }) => target === "portable" ? "wasix-portable" : target); - const expectedPairs = new Set(products.flatMap((product) => extensionSqlNames(product, TOOL).flatMap((sqlName) => [ - ...nativeTargets.map((target) => `${product}\0${sqlName}\0native\0${target}`), - ...wasixTargets.map((target) => `${product}\0${sqlName}\0wasix\0${target}`), - ]))); - const actualPairs = new Set(extensionTargets.map((row) => `${row.product}\0${row.sqlName}\0${row.family}\0${row.target}`)); - assertSameStrings(actualPairs, expectedPairs, "exact-extension product/member/family/target pairs"); - invariant(actualPairs.size === extensionTargets.length, "exact-extension target rows must be unique"); - for (const row of extensionTargets) { - const expectedKind = row.family === "wasix" - ? "wasix-runtime" - : row.target === "ios-xcframework" || row.target.startsWith("android-") - ? "native-static-registry" - : "native-dynamic"; - invariant(row.kind === expectedKind, `${row.product}/${row.target} must use ${expectedKind}, got ${row.kind}`); - invariant(extensionSqlNames(row.product, TOOL).includes(row.sqlName), `${row.product} target row has undeclared SQL member ${row.sqlName}`); - } -} - -function matrixPairs(matrix, { productField = "extensions_csv" } = {}) { - const pairs = []; - for (const row of matrix.include) { - for (const product of String(row[productField] ?? "").split(",").filter(Boolean)) pairs.push(`${product}\0${row.target}`); - } - return pairs; -} - -export function validateMatrixCoverage(targets, extensions, matrices) { - const selected = (product, kind) => targets.filter((row) => row.product === product && row.kind === kind); - assertSameStrings( - matrices.native.include.map(({ target }) => target), - selected("liboliphaunt-native", "native-runtime").map(({ target }) => target), - "native runtime CI matrix", - ); - const partitions = [matrices.nativeDesktop, matrices.nativeAndroid, matrices.nativeIos]; - assertSameStrings(partitions.flatMap(({ include }) => include.map(({ target }) => target)), matrices.native.include.map(({ target }) => target), "native runtime CI matrix partitions"); - invariant(new Set(partitions.flatMap(({ include }) => include.map(({ target }) => target))).size === matrices.native.include.length, "native runtime CI partitions must not overlap"); - assertSameStrings( - matrices.reactNativeAndroid.include.map(({ target }) => target), - selected("liboliphaunt-native", "native-runtime").filter(({ surfaces }) => surfaces.includes("react-native-android")).map(({ target }) => target), - "React Native Android CI matrix", - ); - assertSameStrings(matrices.broker.include.map(({ target }) => target), selected("oliphaunt-broker", "broker-helper").map(({ target }) => target), "broker CI matrix"); - assertSameStrings(matrices.nodeDirect.include.map(({ target }) => target), selected("oliphaunt-node-direct", "node-direct-addon").map(({ target }) => target), "Node direct CI matrix"); - assertSameStrings(matrices.wasixNapi.include.map(({ target }) => target), selected("oliphaunt-wasix-napi", "wasix-napi-addon").map(({ target }) => target), "WASIX Node-API CI matrix"); - assertSameStrings(matrices.wasixAot.include.map(({ target_id }) => target_id), selected("liboliphaunt-wasix", "wasix-aot-runtime").map(({ target }) => target), "WASIX AOT CI matrix"); - const wasixAotTargets = new Map( - selected("liboliphaunt-wasix", "wasix-aot-runtime").map((target) => [target.target, target]), - ); - for (const row of matrices.wasixAot.include) { - const target = wasixAotTargets.get(row.target_id); - invariant(target !== undefined, `WASIX AOT CI matrix has unknown target ${row.target_id}`); - invariant(row.llvm_url === target.llvmUrl, `WASIX AOT CI matrix ${row.target_id} must bind its declared LLVM URL`); - invariant( - row.llvm_sha256 === target.llvmSha256 && /^[0-9a-f]{64}$/u.test(row.llvm_sha256), - `WASIX AOT CI matrix ${row.target_id} must bind its exact LLVM SHA-256`, - ); - invariant( - row.llvm_bytes === target.llvmBytes - && Number.isSafeInteger(row.llvm_bytes) - && row.llvm_bytes > 0 - && row.llvm_bytes <= 2 * 1024 * 1024 * 1024, - `WASIX AOT CI matrix ${row.target_id} must bind its exact supported LLVM byte size`, - ); - } - const postmasterTargets = targets.filter( - ({ product, kind }) => product === "liboliphaunt-wasix-postmaster" && kind === "wasix-postmaster-runtime", - ); - assertSameStrings( - matrices.wasixPostmaster.include.map(({ target_id }) => target_id), - postmasterTargets.map(({ target }) => target), - "WASIX postmaster CI matrix", - ); - const postmasterByTarget = new Map(postmasterTargets.map((target) => [target.target, target])); - for (const row of matrices.wasixPostmaster.include) { - const target = postmasterByTarget.get(row.target_id); - invariant(target !== undefined, `WASIX postmaster CI matrix has unknown target ${row.target_id}`); - invariant( - row.os === target.runner && row.target === target.triple, - `WASIX postmaster CI matrix ${row.target_id} must bind its declared runner and target triple`, - ); - invariant( - row.artifact === `liboliphaunt-wasix-postmaster-release-assets-${target.target}`, - `WASIX postmaster CI matrix ${row.target_id} must bind its exact CI artifact name`, - ); - invariant( - row.release_asset_path - === `target/oliphaunt-wasix-postmaster/release-assets/${target.asset.replace("{version}", "*")}`, - `WASIX postmaster CI matrix ${row.target_id} must bind its catalog-derived release asset path`, - ); - invariant( - row.llvm_url === target.llvmUrl - && row.llvm_sha256 === target.llvmSha256 - && row.llvm_bytes === target.llvmBytes, - `WASIX postmaster CI matrix ${row.target_id} must bind its declared LLVM toolchain`, - ); - } - assertSameStrings( - new Set(matrixPairs(matrices.extensionNative)), - new Set(extensions.filter(({ family }) => family === "native").map(({ product, target }) => `${product}\0${target}`)), - "native extension CI matrix", - ); - assertSameStrings( - new Set(matrixPairs(matrices.extensionWasix)), - new Set(extensions.filter(({ family }) => family === "wasix").map(({ product, target }) => `${product}\0${target}`)), - "WASIX extension CI matrix", - ); - const matrixSqlPairs = (matrix) => matrix.include.flatMap((row) => String(row.sql_names_csv ?? "").split(",").filter(Boolean).map((sqlName) => `${sqlName}\0${row.target}`)); - assertSameStrings( - matrixSqlPairs(matrices.extensionNative), - extensions.filter(({ family }) => family === "native").map(({ sqlName, target }) => `${sqlName}\0${target}`), - "native extension member CI matrix", - ); - assertSameStrings( - matrixSqlPairs(matrices.extensionWasix), - extensions.filter(({ family }) => family === "wasix").map(({ sqlName, target }) => `${sqlName}\0${target}`), - "WASIX extension member CI matrix", - ); -} - -function manifestArray(value) { - return value === undefined ? [] : Array.isArray(value) ? value.map(String) : []; -} - -export function validateCarrierCoverage({ - graph, - catalog, - targets, - jsManifest, - nativeToolsManifest, - rustManifest, - platformManifests, -}) { - const carriers = declaredCarrierMap(catalog); - const runtimeProducts = new Set(["liboliphaunt-native", "oliphaunt-broker", "oliphaunt-node-direct", "oliphaunt-wasix-napi"]); - for (const product of runtimeProducts) { - const expected = registryPackageRows({ product, packageKind: "npm" }, TOOL) - .map((row) => row.packageName); - const actual = catalog.carriers.filter((row) => row.product === product && row.ecosystem === "npm").map((row) => row.name); - assertSameStrings(actual, expected, `${product} npm carrier identities`); - } - for (const target of targets.filter((row) => row.npmPackage)) { - const carrier = carriers.get(`npm:${target.npmPackage}`); - invariant(carrier?.product === target.product && carrier.version === graph.products[target.product].version, `${target.id} npm carrier is missing or version-skewed`); - if (target.npmOs === undefined) continue; - const manifest = platformManifests.get(target.npmPackage); - invariant(manifest !== undefined, `${target.npmPackage} has no package manifest`); - invariant(manifest.version === graph.products[target.product].version && manifest.optional === true, `${target.npmPackage} must be optional and match ${target.product} version`); - assertSameStrings(manifestArray(manifest.os), [target.npmOs], `${target.npmPackage} os selector`); - assertSameStrings(manifestArray(manifest.cpu), [target.npmCpu], `${target.npmPackage} cpu selector`); - assertSameStrings(manifestArray(manifest.libc), target.npmLibc === undefined ? [] : [target.npmLibc], `${target.npmPackage} libc selector`); - invariant(manifest.oliphaunt?.target === target.target, `${target.npmPackage} must select target ${target.target}`); - } - const expectedOptional = new Map(typescriptOptionalRuntimePackageProducts(TOOL).map((row) => [ - row.packageName, - "workspace:*", - ])); - const actualOptional = object(jsManifest.optionalDependencies ?? {}, "TypeScript optionalDependencies"); - assertSameStrings(Object.keys(actualOptional), [...expectedOptional.keys()], "TypeScript optional runtime packages"); - for (const [name, version] of expectedOptional) invariant(actualOptional[name] === version, `TypeScript optional runtime ${name} must use ${version}`); - const expectedToolsOptional = new Map(nativeToolsOptionalPackageProducts(TOOL).map((row) => [ - row.packageName, - `workspace:${graph.products[row.product].version}`, - ])); - const actualToolsOptional = object( - nativeToolsManifest.optionalDependencies ?? {}, - "native tools facade optionalDependencies", - ); - assertSameStrings( - Object.keys(actualToolsOptional), - [...expectedToolsOptional.keys()], - "native tools facade optional packages", - ); - for (const [name, version] of expectedToolsOptional) { - invariant( - actualToolsOptional[name] === version, - `native tools facade optional package ${name} must use ${version}`, - ); - } - const brokerMetadata = object(object(rustManifest.package, "Rust package").metadata?.oliphaunt, "Rust broker metadata"); - invariant(brokerMetadata["broker-helper"] === "oliphaunt-broker", "Rust SDK broker helper identity must be oliphaunt-broker"); - invariant(brokerMetadata["broker-version"] === graph.products["oliphaunt-broker"].version, "Rust SDK broker helper version must match the broker product"); -} - -export function validateExtensionCarrierCoverage(graph, catalog, products) { - for (const product of products) { - const targetSets = extensionRegistryPackageTargetSets(product, TOOL); - const expected = extensionRegistryPackageStrings({ product, ...targetSets }) - .map((identity) => identity.replace(/^crates:/u, "cargo:")); - const expectedNative = extensionNativeRegistryPackageStrings({ product, ...targetSets }) - .map((identity) => identity.replace(/^crates:/u, "cargo:")); - const expectedWasix = extensionWasixRegistryPackageStrings({ - product, - includeAot: targetSets.includeWasixAot, - }).map((identity) => identity.replace(/^crates:/u, "cargo:")); - const actual = catalog.carriers.filter((row) => expected.includes(row.id)); - assertSameStrings(actual.map((row) => row.id), expected, `${product} registry carriers`); - for (const [family, identities] of [["native", expectedNative], ["wasix", expectedWasix]]) { - const owner = extensionReleaseProduct(product, family, TOOL); - invariant( - actual.filter((row) => identities.includes(row.id)) - .every((row) => row.product === owner && row.version === graph.products[owner].version), - `${product} ${family} carrier versions must match ${owner}`, - ); - } - } -} - -function workflowJob(workflow, jobId) { - return object(workflow.jobs?.[jobId], `workflow job ${jobId}`); -} - -function workflowNeeds(workflow, jobId) { - const needs = workflowJob(workflow, jobId).needs ?? []; - return new Set((Array.isArray(needs) ? needs : [needs]).map(String)); -} - -function actionSteps(workflow, jobId, action) { - const steps = workflowJob(workflow, jobId).steps; - invariant(Array.isArray(steps), `${jobId} must declare steps`); - return steps.filter((step) => String(step.uses ?? "").startsWith(action)); -} - -function namedStep(workflow, jobId, name) { - const steps = workflowJob(workflow, jobId).steps; - invariant(Array.isArray(steps), `${jobId} must declare steps`); - return steps.find((step) => step.name === name); -} - -function validateCrossFamilyIcuWorkflow(ci, release) { - const condition = "${{ contains(fromJson(needs.affected.outputs.builder_jobs), 'liboliphaunt-native-release-assets') && contains(fromJson(needs.affected.outputs.builder_jobs), 'liboliphaunt-wasix-release-assets') }}"; - const native = namedStep(ci, "builds", "Download native ICU release asset for cross-family validation"); - const wasix = namedStep(ci, "builds", "Download WASIX release assets for cross-family ICU validation"); - const proof = namedStep(ci, "builds", "Prove native and WASIX ICU data identity"); - invariant( - native?.if === condition - && native.with?.name === "liboliphaunt-native-icu-data" - && wasix?.if === condition - && wasix.with?.name === "liboliphaunt-wasix-release-assets" - && proof?.if === condition - && String(proof.run ?? "").includes("check-cross-family-icu-data.mjs"), - "final build qualification must compare canonical native and WASIX ICU receipts only when both release families exist", - ); - - const releaseProof = namedStep(release, "publish-dry-run", "Prove native and WASIX ICU data identity"); - invariant( - String(releaseProof?.if ?? "").includes("'liboliphaunt-native'") - && String(releaseProof?.if ?? "").includes("'liboliphaunt-wasix'") - && String(releaseProof?.run ?? "").includes("check-cross-family-icu-data.mjs"), - "release publication must recheck cross-family ICU identity when both products are selected", - ); -} - -function expandTemplate(template, rows) { - const values = []; - for (const row of rows) { - const value = String(template).replace(/\$\{\{\s*matrix\.([A-Za-z0-9_-]+)\s*\}\}/gu, (_match, field) => { - invariant(row[field] !== undefined, `artifact template ${template} requires absent matrix field ${field}`); - return String(row[field]); - }); - invariant(!value.includes("${{"), `cannot materialize artifact template ${template}`); - values.push(value); - } - return values; -} - -function plannerOwnedMatrix(workflow, jobId) { - const matrix = workflowJob(workflow, jobId).strategy?.matrix; - invariant(typeof matrix === "string", `${jobId} must consume a planner-owned matrix expression`); - const references = [...matrix.matchAll(/needs[.]affected[.]outputs[.]([A-Za-z0-9_]+)/gu)].map((match) => match[1]); - invariant(new Set(references).size === 1, `${jobId} matrix must consume exactly one affected-plan output`); - invariant(Object.hasOwn(workflowJob(workflow, "affected").outputs ?? {}, references[0]), `${jobId} references missing affected-plan output ${references[0]}`); -} - -export function validateWorkflowProducer(workflow, jobId, template, rows, expectedArtifacts) { - if (rows.length > 1 || String(template).includes("matrix.")) plannerOwnedMatrix(workflow, jobId); - const matches = actionSteps(workflow, jobId, "actions/upload-artifact@").filter((step) => step.with?.name === template); - invariant(matches.length === 1, `${jobId} must upload ${template} exactly once`); - invariant(matches[0].with?.["if-no-files-found"] === "error", `${jobId}/${template} must fail when its payload is absent`); - assertSameStrings(expandTemplate(template, rows), expectedArtifacts, `${jobId} produced artifact set`); -} - -function globMatches(pattern, value) { - const expression = `^${String(pattern).split("*").map((part) => part.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")).join(".*")}$`; - return new RegExp(expression, "u").test(value); -} - -export function validateWorkflowConsumer(workflow, jobId, producerJobs, requiredArtifacts, rows = [{}]) { - const needs = workflowNeeds(workflow, jobId); - for (const producer of producerJobs) invariant(needs.has(producer), `${jobId} must depend on artifact producer ${producer}`); - const specs = actionSteps(workflow, jobId, "actions/download-artifact@").flatMap((step) => { - const value = step.with?.name ?? step.with?.pattern; - return value === undefined ? [] : expandTemplate(value, rows); - }); - for (const artifact of requiredArtifacts) invariant(specs.some((pattern) => globMatches(pattern, artifact)), `${jobId} does not download required artifact ${artifact}`); -} - -function validateMergedSameRunDownload(workflow, jobId, pattern, artifactPath) { - const matches = actionSteps(workflow, jobId, "actions/download-artifact@") - .filter((step) => step.with?.pattern === pattern); - invariant(matches.length === 1, `${jobId} must download ${pattern} exactly once`); - const options = matches[0].with ?? {}; - invariant( - options.path === artifactPath - && options["merge-multiple"] === true - && options.name === undefined - && options["run-id"] === undefined - && options.repository === undefined - && options["github-token"] === undefined, - `${jobId}/${pattern} must merge exact same-run artifacts into ${artifactPath}`, - ); -} - -export function validateCiArtifactCoverage(workflow, inventory) { - const matrixRows = { - nativeDesktop: inventory.matrices.nativeDesktop.include, - nativeAndroid: inventory.matrices.nativeAndroid.include, - nativeIos: inventory.matrices.nativeIos.include, - broker: inventory.matrices.broker.include, - nodeDirect: inventory.matrices.nodeDirect.include, - wasixNapi: inventory.matrices.wasixNapi.include, - extensionNative: inventory.matrices.extensionNative.include, - extensionWasix: inventory.matrices.extensionWasix.include, - wasixAot: inventory.matrices.wasixAot.include, - wasixPostmaster: inventory.matrices.wasixPostmaster.include, - reactNativeAndroid: inventory.matrices.reactNativeAndroid.include, - }; - const releaseAssets = (product, kind) => ciReleaseAssetArtifactRows(product, kind, TOOL).map(({ artifactName }) => artifactName); - const npmPackages = (product, kind) => ciNpmPackageArtifactRows(product, kind, TOOL).map(({ artifactName }) => artifactName); - const nativeRelease = releaseAssets("liboliphaunt-native", "native-runtime"); - const nativeBy = (predicate) => nativeRelease.filter((name) => predicate(name.replace("liboliphaunt-native-release-assets-", ""))); - validateWorkflowProducer(workflow, "liboliphaunt-native-desktop", "liboliphaunt-native-release-assets-${{ matrix.target }}", matrixRows.nativeDesktop, nativeBy((target) => /^(linux|macos|windows)-/u.test(target))); - validateWorkflowProducer(workflow, "liboliphaunt-native-desktop", "liboliphaunt-native-icu-data", [{}], ["liboliphaunt-native-icu-data"]); - const portableIcuUpload = actionSteps(workflow, "liboliphaunt-native-desktop", "actions/upload-artifact@") - .find((step) => step.with?.name === "liboliphaunt-native-icu-data"); - const portableIcuPackages = workflowJob(workflow, "liboliphaunt-native-desktop").steps - .filter((step) => String(step.run ?? "").includes("package-liboliphaunt-icu-data.sh")); - invariant( - portableIcuUpload?.if === "${{ matrix.target == 'macos-arm64' }}" - && portableIcuPackages.length === 1 - && portableIcuPackages[0].if === "${{ matrix.target == 'macos-arm64' }}", - "portable ICU package and upload must be produced by exactly the macos-arm64 desktop matrix row", - ); - validateWorkflowProducer(workflow, "liboliphaunt-native-android", "liboliphaunt-native-release-assets-${{ matrix.target }}", matrixRows.nativeAndroid, nativeBy((target) => target.startsWith("android-"))); - validateWorkflowProducer(workflow, "liboliphaunt-native-ios", "liboliphaunt-native-release-assets-${{ matrix.target }}", matrixRows.nativeIos, nativeBy((target) => target === "ios-xcframework")); - validateWorkflowProducer( - workflow, - "liboliphaunt-native-android-abi", - "liboliphaunt-native-abi-compatible-release-assets-android-datum64", - [{}], - ["liboliphaunt-native-abi-compatible-release-assets-android-datum64"], - ); - validateWorkflowProducer( - workflow, - "liboliphaunt-native-ios-abi", - "liboliphaunt-native-abi-compatible-release-assets-ios-datum64", - [{}], - ["liboliphaunt-native-abi-compatible-release-assets-ios-datum64"], - ); - validateWorkflowProducer(workflow, "broker-runtime", "oliphaunt-broker-release-assets-${{ matrix.target }}", matrixRows.broker, releaseAssets("oliphaunt-broker", "broker-helper")); - validateWorkflowProducer(workflow, "node-direct", "oliphaunt-node-direct-release-assets-${{ matrix.target }}", matrixRows.nodeDirect, releaseAssets("oliphaunt-node-direct", "node-direct-addon")); - validateWorkflowProducer(workflow, "node-direct", "oliphaunt-node-direct-npm-package-${{ matrix.target }}", matrixRows.nodeDirect, npmPackages("oliphaunt-node-direct", "node-direct-addon")); - validateWorkflowProducer(workflow, "wasix-napi", "oliphaunt-wasix-napi-release-assets-${{ matrix.target }}", matrixRows.wasixNapi, releaseAssets("oliphaunt-wasix-napi", "wasix-napi-addon")); - validateWorkflowProducer(workflow, "wasix-napi", "oliphaunt-wasix-napi-npm-package-${{ matrix.target }}", matrixRows.wasixNapi, npmPackages("oliphaunt-wasix-napi", "wasix-napi-addon")); - const nativeExtensionArtifacts = sorted(new Set(inventory.extensions.filter(({ family }) => family === "native").map(({ target }) => `liboliphaunt-native-extension-artifacts-${target}`))); - const wasixExtensionArtifacts = sorted(new Set(inventory.extensions.filter(({ family }) => family === "wasix").map(({ target }) => `liboliphaunt-wasix-extension-artifacts-${target}`))); - validateWorkflowProducer(workflow, "extension-artifacts-native", "liboliphaunt-native-extension-artifacts-${{ matrix.target }}", matrixRows.extensionNative, nativeExtensionArtifacts); - validateWorkflowProducer(workflow, "extension-artifacts-wasix", "liboliphaunt-wasix-extension-artifacts-${{ matrix.target }}", matrixRows.extensionWasix, wasixExtensionArtifacts); - const wasixAot = matrixRows.wasixAot.map(({ target_id }) => `liboliphaunt-wasix-runtime-aot-${target_id}`); - const extensionAot = matrixRows.wasixAot.map(({ target_id }) => `liboliphaunt-wasix-extension-aot-${target_id}`); - validateWorkflowProducer(workflow, "liboliphaunt-wasix-aot", "liboliphaunt-wasix-runtime-aot-${{ matrix.target_id }}", matrixRows.wasixAot, wasixAot); - validateWorkflowProducer(workflow, "liboliphaunt-wasix-aot", "liboliphaunt-wasix-extension-aot-${{ matrix.target_id }}", matrixRows.wasixAot, extensionAot); - for (const row of inventory.sdkProducts) validateWorkflowProducer(workflow, row.product.replace(/^oliphaunt-/u, "") === "wasix-rust" ? "wasix-rust-package" : `${row.product.replace(/^oliphaunt-/u, "")}-sdk-package`, row.artifactName, [{}], [row.artifactName]); - for (const [jobId, artifact] of [ - ["liboliphaunt-native-release-assets", "liboliphaunt-native-release-assets"], - ["extension-packages", "oliphaunt-extension-package-artifacts"], - ["mobile-extension-packages", "oliphaunt-mobile-extension-package-artifacts"], - ["liboliphaunt-wasix-runtime", "liboliphaunt-wasix-runtime-portable"], - ["liboliphaunt-wasix-release-assets", "liboliphaunt-wasix-release-assets"], - ["wasix-postmaster", "liboliphaunt-wasix-postmaster-release-assets"], - ]) validateWorkflowProducer(workflow, jobId, artifact, [{}], [artifact]); - const iosMobileExtensions = actionSteps(workflow, "mobile-build-ios", "actions/download-artifact@") - .find((step) => step.with?.name === "oliphaunt-mobile-extension-package-artifacts"); - const iosCarrierManifest = namedStep(workflow, "mobile-build-ios", "Render exact-SHA cache-warm iOS carrier manifest"); - const iosSwiftConsumer = namedStep(workflow, "mobile-build-ios", "Run exact-extension Swift release consumer"); - const iosMobileBuild = namedStep(workflow, "mobile-build-ios", "Build iOS mobile app"); - const iosMobileJob = workflowJob(workflow, "mobile-build-ios"); - invariant( - iosMobileExtensions?.with?.path === "target/mobile-extension-artifacts" - && String(iosCarrierManifest?.run ?? "").includes("--extension-root target/mobile-extension-artifacts") - && iosMobileJob.env?.OLIPHAUNT_EXTENSION_ARTIFACT_ROOT === "${{ github.workspace }}/target/mobile-extension-artifacts" - && iosMobileBuild?.env?.OLIPHAUNT_EXPO_EXTENSION_ARTIFACT_ROOT === "${{ env.OLIPHAUNT_EXTENSION_ARTIFACT_ROOT }}" - && String(iosSwiftConsumer?.run ?? "").includes("$OLIPHAUNT_EXTENSION_ARTIFACT_ROOT/${product_root#target/extension-artifacts/}"), - "iOS consumers must restore and read mobile extension artifacts at their frozen producer root", - ); - const postmasterReleaseAssets = releaseAssets( - "liboliphaunt-wasix-postmaster", - "wasix-postmaster-runtime", - ); - validateWorkflowProducer( - workflow, - "wasix-postmaster-target", - "liboliphaunt-wasix-postmaster-release-assets-${{ matrix.target_id }}", - matrixRows.wasixPostmaster, - postmasterReleaseAssets, - ); - validateWorkflowProducer( - workflow, - "wasix-postmaster-portable", - "liboliphaunt-wasix-postmaster-portable-build-inputs", - [{}], - ["liboliphaunt-wasix-postmaster-portable-build-inputs"], - ); - const portablePostmasterSteps = workflowJob(workflow, "wasix-postmaster-portable").steps; - const portablePostmasterBuild = portablePostmasterSteps.find((step) => - step.run?.includes("liboliphaunt-wasix-postmaster:portable-inputs")); - invariant( - portablePostmasterBuild?.run?.includes("--upstream deep") - && portablePostmasterBuild.run.includes("liboliphaunt-wasix-postmaster:runtime-patch-tests") - && portablePostmasterBuild.run.includes("liboliphaunt-wasix-postmaster:regression"), - "portable WASIX postmaster production and qualification must execute their complete Moon graphs", - ); - const targetPostmasterSteps = workflowJob(workflow, "wasix-postmaster-target").steps; - const targetPostmasterBuild = targetPostmasterSteps.find((step) => - step.run?.includes("liboliphaunt-wasix-postmaster:release-assets")); - invariant( - targetPostmasterBuild?.run?.includes("--upstream deep") - && targetPostmasterBuild.if === undefined - && targetPostmasterBuild.run.includes("liboliphaunt-wasix-postmaster:immediate-recovery") - && targetPostmasterBuild.run.includes("liboliphaunt-wasix-postmaster:linear-memory-integration"), - "every WASIX postmaster target must execute complete production and qualification Moon graphs", - ); - const postmasterUpload = actionSteps(workflow, "wasix-postmaster-target", "actions/upload-artifact@") - .find((step) => step.with?.name === "liboliphaunt-wasix-postmaster-release-assets-${{ matrix.target_id }}"); - invariant( - postmasterUpload?.if === undefined - && postmasterUpload.with?.path === "${{ matrix.release_asset_path }}", - "every WASIX postmaster target must upload its catalog-derived release asset path", - ); - invariant( - actionSteps(workflow, "wasix-postmaster", "./.github/actions/setup-moon").length === 1, - "WASIX postmaster aggregation must load its release catalog through the pinned Moon toolchain", - ); - validateMergedSameRunDownload( - workflow, - "wasix-postmaster", - "liboliphaunt-wasix-postmaster-release-assets-*", - "target/oliphaunt-wasix-postmaster/release-assets", - ); - validateWorkflowConsumer( - workflow, - "wasix-postmaster-target", - ["wasix-postmaster-portable"], - ["liboliphaunt-wasix-postmaster-portable-build-inputs"], - ); - validateWorkflowConsumer( - workflow, - "wasix-postmaster", - ["wasix-postmaster-target"], - postmasterReleaseAssets, - ); - validateWorkflowConsumer( - workflow, - "broker-release-assets", - ["broker-runtime"], - releaseAssets("oliphaunt-broker", "broker-helper"), - ); - validateWorkflowConsumer( - workflow, - "node-direct-release-assets", - ["node-direct"], - [ - ...releaseAssets("oliphaunt-node-direct", "node-direct-addon"), - ...npmPackages("oliphaunt-node-direct", "node-direct-addon"), - ], - ); - validateMergedSameRunDownload( - workflow, - "broker-release-assets", - "oliphaunt-broker-release-assets-*", - "target/oliphaunt-broker/release-assets", - ); - validateMergedSameRunDownload( - workflow, - "node-direct-release-assets", - "oliphaunt-node-direct-release-assets-*", - "target/oliphaunt-node-direct/release-assets", - ); - validateWorkflowConsumer( - workflow, - "wasix-napi-release-assets", - ["wasix-napi"], - [ - ...releaseAssets("oliphaunt-wasix-napi", "wasix-napi-addon"), - ...npmPackages("oliphaunt-wasix-napi", "wasix-napi-addon"), - ], - ); - validateMergedSameRunDownload( - workflow, - "wasix-napi-release-assets", - "oliphaunt-wasix-napi-release-assets-*", - "target/oliphaunt-wasix-napi/release-assets", - ); - validateMergedSameRunDownload( - workflow, - "wasix-napi-release-assets", - "oliphaunt-wasix-napi-npm-package-*", - "target/oliphaunt-wasix-napi/npm-packages", - ); - validateMergedSameRunDownload( - workflow, - "node-direct-release-assets", - "oliphaunt-node-direct-npm-package-*", - "target/oliphaunt-node-direct/npm-packages", - ); - for (const jobId of ["broker-release-assets", "node-direct-release-assets", "wasix-napi-release-assets"]) { - invariant( - actionSteps(workflow, jobId, "actions/upload-artifact@").length === 0, - `${jobId} must validate same-run target artifacts without uploading a duplicate product artifact`, - ); - } - validateWorkflowConsumer( - workflow, - "liboliphaunt-native-android-abi", - ["liboliphaunt-native-android"], - [ - "liboliphaunt-native-target-android-arm64-v8a", - "liboliphaunt-native-target-android-x86_64", - "liboliphaunt-native-release-assets-android-x86_64", - ], - ); - validateWorkflowConsumer( - workflow, - "liboliphaunt-native-ios-abi", - ["liboliphaunt-native-ios"], - [ - "liboliphaunt-native-target-ios-xcframework", - "liboliphaunt-native-release-assets-ios-xcframework", - ], - ); - validateWorkflowConsumer( - workflow, - "liboliphaunt-native-release-assets", - [ - "liboliphaunt-native-desktop", - "liboliphaunt-native-android", - "liboliphaunt-native-android-abi", - "liboliphaunt-native-ios", - "liboliphaunt-native-ios-abi", - ], - [ - ...nativeRelease, - "liboliphaunt-native-abi-compatible-release-assets-android-datum64", - "liboliphaunt-native-abi-compatible-release-assets-ios-datum64", - ], - ); - validateWorkflowConsumer(workflow, "extension-artifacts-wasix", ["liboliphaunt-wasix-runtime"], ["liboliphaunt-wasix-runtime-portable"]); - validateWorkflowConsumer(workflow, "liboliphaunt-wasix-aot", ["liboliphaunt-wasix-runtime"], ["liboliphaunt-wasix-runtime-portable"]); - validateWorkflowConsumer( - workflow, - "wasix-napi", - ["extension-artifacts-wasix", "liboliphaunt-wasix-aot", "liboliphaunt-wasix-runtime"], - [ - "liboliphaunt-wasix-runtime-portable", - ...wasixExtensionArtifacts, - ...wasixAot, - ...extensionAot, - ], - matrixRows.wasixNapi, - ); - validateMergedSameRunDownload( - workflow, - "wasix-napi", - "liboliphaunt-wasix-extension-artifacts-*", - "target/extensions/wasix/release-assets", - ); - const wasixNapiBuild = namedStep(workflow, "wasix-napi", "Build WASIX Node-API release assets"); - invariant( - wasixNapiBuild?.env?.OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD === "1" - && wasixNapiBuild.env.OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR === "${{ github.workspace }}/target/oliphaunt-wasix/assets" - && wasixNapiBuild.env.OLIPHAUNT_WASM_GENERATED_AOT_DIR === "${{ github.workspace }}/target/oliphaunt-wasix/aot" - && wasixNapiBuild.env.OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT === "${{ github.workspace }}/target/extension-artifacts" - && wasixNapiBuild.env.OLIPHAUNT_ICU_DATA_DIR === "${{ github.workspace }}/target/oliphaunt-wasix/wasix-build/work/icu-wasix/share/icu" - && wasixNapiBuild.env.OLIPHAUNT_WASIX_NAPI_ARTIFACT_SOURCE_SHA === "${{ github.event.pull_request.head.sha || github.sha }}", - "WASIX Node-API builds must fail closed on exact same-run portable, ICU, AOT, and extension payload roots", - ); - const releaseTasks = object( - Bun.YAML.parse(readFileSync(path.join(ROOT, "tools/release/moon.yml"), "utf8")), - "tools/release/moon.yml", - ).tasks; - invariant( - String(releaseTasks?.["wasix-napi-runtime"]?.command ?? "").startsWith("bash ") - && String(releaseTasks["wasix-napi-runtime"].command).includes("build-extension-ci-artifacts.mjs --all --family wasix --require-wasix"), - "WASIX Node-API builds must stage complete exact-extension portable and target AOT inputs", - ); - const wasixNapiAotRestore = namedStep(workflow, "wasix-napi", "Restore exact target core and tool AOT layout"); - invariant( - wasixNapiAotRestore?.env?.EXPECTED_TARGET_TRIPLE === "${{ matrix.target_triple }}" - && String(wasixNapiAotRestore.run ?? "").includes("target-triple.txt") - && String(wasixNapiAotRestore.run ?? "").includes("target/oliphaunt-wasix/aot/$target"), - "WASIX Node-API builds must restore marker-validated host AOT inputs to the Cargo artifact layout", - ); - validateWorkflowConsumer(workflow, "wasix-release-regression", ["extension-artifacts-wasix", "liboliphaunt-wasix-runtime", "liboliphaunt-wasix-aot"], [ - "liboliphaunt-wasix-runtime-portable", - ...wasixExtensionArtifacts, - "liboliphaunt-wasix-runtime-aot-linux-x64-gnu", - "liboliphaunt-wasix-extension-aot-linux-x64-gnu", - ]); - validateWorkflowConsumer(workflow, "liboliphaunt-wasix-release-assets", ["liboliphaunt-wasix-runtime", "liboliphaunt-wasix-aot"], ["liboliphaunt-wasix-runtime-portable", ...wasixAot]); - validateWorkflowConsumer(workflow, "extension-packages", ["extension-artifacts-native", "extension-artifacts-wasix", "liboliphaunt-wasix-aot"], [...nativeExtensionArtifacts, ...wasixExtensionArtifacts, ...extensionAot]); - validateWorkflowConsumer(workflow, "mobile-extension-packages", ["extension-artifacts-native"], nativeExtensionArtifacts); - const abiCompatibleIosRelease = ["liboliphaunt-native-abi-compatible-release-assets-ios-datum64"]; - validateWorkflowConsumer(workflow, "swift-sdk-package", ["liboliphaunt-native-ios-abi"], abiCompatibleIosRelease); - validateWorkflowConsumer(workflow, "react-native-sdk-package", ["liboliphaunt-native-ios-abi"], abiCompatibleIosRelease); - validateWorkflowConsumer(workflow, "mobile-build-android", ["liboliphaunt-native-android", "liboliphaunt-native-android-abi", "mobile-extension-packages", "kotlin-sdk-package", "react-native-sdk-package"], [ - ...matrixRows.reactNativeAndroid.map(({ target }) => `liboliphaunt-native-target-${target}`), - "liboliphaunt-native-abi-compatible-release-assets-android-datum64", - "oliphaunt-mobile-extension-package-artifacts", - "oliphaunt-kotlin-sdk-package-artifacts", - "oliphaunt-react-native-sdk-package-artifacts", - ], matrixRows.reactNativeAndroid); - validateWorkflowConsumer(workflow, "mobile-build-ios", ["liboliphaunt-native-ios", "liboliphaunt-native-ios-abi", "mobile-extension-packages", "react-native-sdk-package", "swift-sdk-package"], [ - "liboliphaunt-native-target-ios-xcframework", - ...abiCompatibleIosRelease, - "oliphaunt-mobile-extension-package-artifacts", - "oliphaunt-react-native-sdk-package-artifacts", - "oliphaunt-swift-sdk-package-artifacts", - ]); - for (const jobId of ["swift-sdk-package", "react-native-sdk-package", "mobile-build-ios"]) { - invariant( - actionSteps(workflow, jobId, "actions/download-artifact@") - .every((step) => step.with?.name !== "liboliphaunt-native-release-assets-ios-xcframework"), - `${jobId} must not bypass iOS ABI-compatibility admission`, - ); - } - invariant( - actionSteps(workflow, "mobile-build-android", "actions/download-artifact@") - .every((step) => step.with?.name !== "liboliphaunt-native-release-assets-android-x86_64"), - "mobile-build-android must not bypass Android ABI-compatibility admission", - ); - validateWorkflowConsumer( - workflow, - "mobile-e2e-android", - ["mobile-build-android"], - ["react-native-mobile-android-app-android-x86_64"], - ); - validateWorkflowConsumer( - workflow, - "mobile-e2e-ios", - ["mobile-build-ios"], - ["react-native-mobile-ios-app"], - ); - for (const [jobId, platform] of [["mobile-e2e-android", "android"], ["mobile-e2e-ios", "ios"]]) { - const execution = workflowJob(workflow, jobId).steps.find( - (step) => step.name === `Run ${platform === "android" ? "Android" : "iOS"} installed-app E2E`, - ); - invariant( - String(execution?.run ?? "").includes(`mobile-e2e.sh ${platform}`), - `${jobId} must execute the installed-app receipt validator`, - ); - } - const finalE2eNeeds = workflowNeeds(workflow, "e2e"); - invariant( - finalE2eNeeds.has("mobile-e2e-android") && finalE2eNeeds.has("mobile-e2e-ios"), - "final E2E qualification must depend on both representative mobile executions", - ); - const finalExecutionGate = workflowJob(workflow, "e2e").steps.find( - (step) => step.name === "Check final release execution qualification", - ); - invariant( - finalExecutionGate?.env?.SELECTED_JOBS_JSON === "${{ needs.affected.outputs.e2e_jobs }}" - && String(finalExecutionGate.run ?? "").includes("check-ci-gate.mjs selected"), - "final release execution qualification must enforce the planner-selected E2E jobs", - ); - invariant( - workflowNeeds(workflow, "required").has("e2e") - && workflowNeeds(workflow, "qualified").has("required"), - "release qualification must remain downstream of final mobile execution qualification", - ); -} - -function platformPackageManifests(graph, targets) { - const names = new Set(targets.filter(({ npmPackage }) => npmPackage).map(({ npmPackage }) => npmPackage)); - const manifests = new Map(); - for (const config of Object.values(graph.products)) { - for (const relativePath of config.version_files ?? []) { - if (path.basename(relativePath) !== "package.json") continue; - const manifest = readJson(relativePath); - if (!names.has(manifest.name)) continue; - invariant(!manifests.has(manifest.name), `duplicate platform package manifest ${manifest.name}`); - manifests.set(manifest.name, manifest); - } - } - return manifests; -} - -function validateStructuredExtensionRecipes(products, extensions, graph) { - for (const product of products) { - for (const sqlName of extensionSqlNames(product, TOOL)) { - const mobile = extensions.some(({ product: owner, sqlName: member, kind }) => owner === product && member === sqlName && kind === "native-static-registry"); - if (!mobile) continue; - const recipe = path.join(extensionMemberPath(product, sqlName, TOOL), "targets/native-static-registry.toml"); - if (!existsSync(path.join(ROOT, recipe))) continue; - invariant(statSync(path.join(ROOT, recipe)).isFile(), `${recipe} must be a file`); - invariant(readToml(recipe).status === undefined, `${recipe} must not carry an intermediate support status`); - } - } -} - -export function repositoryInventory() { - const graph = loadGraph(TOOL); - const targets = allArtifactTargets({}, TOOL); - const products = exactExtensionProducts(TOOL); - const extensions = extensionArtifactTargets({}, TOOL); - return { - graph, - targets, - products, - extensions, - catalog: loadPublicationCatalog(TOOL), - sdkProducts: sdkPackageProducts(TOOL), - matrices: { - native: liboliphauntNativeRuntimeMatrix(), - nativeDesktop: liboliphauntNativeDesktopRuntimeMatrix(), - nativeAndroid: liboliphauntNativeAndroidRuntimeMatrix(), - nativeIos: liboliphauntNativeIosRuntimeMatrix(), - reactNativeAndroid: reactNativeAndroidMobileAppMatrix(), - extensionNative: extensionArtifactsNativeMatrix(), - extensionWasix: extensionArtifactsWasixMatrix(), - wasixAot: liboliphauntWasixAotRuntimeMatrix(), - wasixPostmaster: liboliphauntWasixPostmasterRuntimeMatrix(), - broker: brokerRuntimeMatrix(), - nodeDirect: nodeDirectRuntimeMatrix(), - wasixNapi: wasixNapiRuntimeMatrix(), - }, - }; -} - -export function validateRepository() { - const inventory = repositoryInventory(); - invariant((inventory.graph.artifact_targets ?? []).length === 0, "artifact targets must be owned by Moon product metadata, not a central legacy table"); - for (const [product, preset] of Object.entries({ - "liboliphaunt-native": "liboliphaunt-native", - "liboliphaunt-wasix": "liboliphaunt-wasix", - "liboliphaunt-wasix-postmaster": "liboliphaunt-wasix-postmaster", - "oliphaunt-broker": "broker-helper", - "oliphaunt-node-direct": "node-direct-addon", - "oliphaunt-wasix-napi": "wasix-napi-addon", - })) invariant(releaseMetadata(product, TOOL).artifactTargets?.preset === preset, `${product} must use Moon artifact target preset ${preset}`); - validateArtifactTargetContract(inventory.targets); - validateExtensionCoverage(inventory.targets, inventory.products, inventory.extensions); - validateMatrixCoverage(inventory.targets, inventory.extensions, inventory.matrices); - validateCarrierCoverage({ - graph: inventory.graph, - catalog: inventory.catalog, - targets: inventory.targets, - jsManifest: readJson("src/sdks/js/package.json"), - nativeToolsManifest: readJson("src/runtimes/liboliphaunt/native/tools-npm/package.json"), - rustManifest: readToml("src/sdks/rust/Cargo.toml"), - platformManifests: platformPackageManifests(inventory.graph, inventory.targets), - }); - validateExtensionCarrierCoverage(inventory.graph, inventory.catalog, inventory.products); - validateStructuredExtensionRecipes(inventory.products, inventory.extensions, inventory.graph); - const ci = parseWorkflow(ROOT, ".github/workflows/ci.yml"); - const release = parseWorkflow(ROOT, ".github/workflows/release.yml"); - invariant( - actionSteps(release, "prepare-release-pr", "./.github/actions/setup-moon")[0]?.with?.["install-workspace"] === "true", - "release PR preparation must install workspace dependencies before validating generated metadata", - ); - validateCiArtifactCoverage(ci, inventory); - validateCrossFamilyIcuWorkflow(ci, release); - const fullPlan = planForFullRun({ wasmTarget: "all", nativeTarget: "all", mobileTarget: "all" }); - invariant([...BUILDER_JOBS].every((job) => fullPlan.jobs.has(job)), "full CI planning must select every product artifact builder"); - const wasixNapiPlan = new Set(["wasix-napi"]); - addRequiredJobs(wasixNapiPlan); - invariant( - ["extension-artifacts-wasix", "liboliphaunt-wasix-aot", "liboliphaunt-wasix-runtime"] - .every((job) => wasixNapiPlan.has(job)), - "WASIX Node-API CI planning must select every same-run embedded payload producer", - ); - const extensionPlan = planJobsForAffected( - new Set(["extension-artifacts-wasix:build-target"]), - ); - invariant( - [ - "wasix-napi", - "extension-artifacts-wasix", - "liboliphaunt-wasix-aot", - "liboliphaunt-wasix-runtime", - ].every((job) => extensionPlan.has(job)), - "WASIX extension changes must rebuild Node-API carriers and every embedded payload producer", - ); - const focusedWasix = planForFullRun({ wasmTarget: "linux-x64-gnu", nativeTarget: "all", mobileTarget: "all" }); - assertSameStrings(focusedWasix.jobs, ["affected", "extension-artifacts-wasix", "liboliphaunt-wasix-aot", "liboliphaunt-wasix-runtime"], "focused WASIX CI jobs"); - const focusedAndroid = renderPlanForFullRun({ - wasmTarget: "all", - nativeTarget: "android-arm64-v8a", - mobileTarget: "android", - }); - assertSameStrings( - focusedAndroid.liboliphaunt_native_android_runtime_matrix.include.map(({ target }) => target), - ["android-arm64-v8a", "android-x86_64"], - "focused Android compatibility-domain runtime targets", - ); - assertSameStrings( - focusedAndroid.react_native_android_mobile_app_matrix.include.map(({ target }) => target), - ["android-x86_64"], - "focused Android representative app target", - ); - invariant(rawArtifactTargetRows(TOOL).length === inventory.targets.length, "raw and normalized artifact target inventories must have equal cardinality"); - return { - artifactTargets: inventory.targets.length, - extensionProducts: inventory.products.length, - extensionTargets: inventory.extensions.length, - registryCarriers: inventory.catalog.carriers.length, - sdkProducts: inventory.sdkProducts.length, - }; -} - -if (import.meta.main) { - try { - const summary = validateRepository(); - console.log( - `artifact target checks passed (${summary.artifactTargets} runtime/helper rows, ` + - `${summary.extensionProducts} exact-extension products, ${summary.extensionTargets} extension rows, ` + - `${summary.registryCarriers} catalog-declared registry carrier minima, ${summary.sdkProducts} SDK packages)`, - ); - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exitCode = 1; - } -} diff --git a/tools/release/check_artifact_targets.mts b/tools/release/check_artifact_targets.mts new file mode 100644 index 000000000..219b146be --- /dev/null +++ b/tools/release/check_artifact_targets.mts @@ -0,0 +1,535 @@ +#!/usr/bin/env bun +import { readFileSync } from 'node:fs'; +import path from 'node:path'; + +import { + extensionNativeRegistryPackageStrings, + extensionRegistryPackageStrings, + extensionWasixRegistryPackageStrings, +} from '../../src/extensions/artifacts/packages/tools/extension-registry-packages.mts'; +import { + brokerRuntimeMatrix, + extensionArtifactsNativeMatrix, + extensionArtifactsWasixMatrix, + liboliphauntNativeAndroidRuntimeMatrix, + liboliphauntNativeDesktopRuntimeMatrix, + liboliphauntNativeIosRuntimeMatrix, + liboliphauntNativeRuntimeMatrix, + liboliphauntWasixAotRuntimeMatrix, + liboliphauntWasixPostmasterRuntimeMatrix, + nodeDirectRuntimeMatrix, + reactNativeAndroidMobileAppMatrix, + wasixNapiRuntimeMatrix, +} from './artifact-target-matrix.mts'; +import { declaredCarrierMap, loadPublicationCatalog } from './publication-catalog.mts'; +import { + allArtifactTargets, + ciNpmPackageArtifactRows, + ciReleaseAssetArtifactRows, + exactExtensionProducts, + extensionArtifactTargets, + extensionMemberPath, + extensionMetadata, + extensionRegistryPackageTargetSets, + extensionReleaseProduct, + extensionSqlNames, + nativeToolsOptionalPackageProducts, + rawArtifactTargetRows, + registryPackageRows, + releaseMetadata, + sdkPackageProducts, + typescriptOptionalRuntimePackageProducts, +} from './release-artifact-targets.mts'; +import { compareText, loadProducts, ROOT } from './release-graph.mts'; + +const TOOL = 'check_artifact_targets.mts'; +function invariant(condition, message) { + if (!condition) throw new Error(`${TOOL}: ${message}`); +} + +function object(value, label) { + invariant( + value !== null && typeof value === 'object' && !Array.isArray(value), + `${label} must be an object`, + ); + return value; +} + +function sorted(values) { + return [...values].sort(compareText); +} + +function sameStrings(left, right) { + const actual = sorted(left); + const expected = sorted(right); + return ( + actual.length === expected.length && actual.every((value, index) => value === expected[index]) + ); +} + +function assertSameStrings(actual, expected, label) { + invariant( + sameStrings(actual, expected), + `${label} must be ${JSON.stringify(sorted(expected))}; got ${JSON.stringify(sorted(actual))}`, + ); +} + +function readJson(relativePath) { + try { + return object(JSON.parse(readFileSync(path.join(ROOT, relativePath), 'utf8')), relativePath); + } catch (error) { + throw new Error(`${TOOL}: ${relativePath} is invalid JSON: ${error.message}`); + } +} + +function readToml(relativePath) { + try { + return object( + Bun.TOML.parse(readFileSync(path.join(ROOT, relativePath), 'utf8')), + relativePath, + ); + } catch (error) { + throw new Error(`${TOOL}: ${relativePath} is invalid TOML: ${error.message}`); + } +} + +export function validateExtensionCoverage(runtimeTargets, products, extensionTargets) { + invariant( + products.length > 0 && new Set(products).size === products.length, + 'extension product ids must be a non-empty unique set', + ); + const nativeTargets = runtimeTargets + .filter( + (row) => + row.product === 'liboliphaunt-native' && + row.kind === 'native-runtime' && + row.extensionArtifacts, + ) + .map(({ target }) => target); + const wasixTargets = runtimeTargets + .filter((row) => row.product === 'liboliphaunt-wasix' && row.kind === 'wasix-runtime') + .map(({ target }) => (target === 'portable' ? 'wasix-portable' : target)); + const expectedPairs = new Set( + products.flatMap((product) => + extensionSqlNames(product, TOOL).flatMap((sqlName) => [ + ...nativeTargets.map((target) => `${product}\0${sqlName}\0native\0${target}`), + ...wasixTargets.map((target) => `${product}\0${sqlName}\0wasix\0${target}`), + ]), + ), + ); + const actualPairs = new Set( + extensionTargets.map((row) => `${row.product}\0${row.sqlName}\0${row.family}\0${row.target}`), + ); + assertSameStrings( + actualPairs, + expectedPairs, + 'exact-extension product/member/family/target pairs', + ); + invariant( + actualPairs.size === extensionTargets.length, + 'exact-extension target rows must be unique', + ); + for (const row of extensionTargets) { + const expectedKind = + row.family === 'wasix' + ? 'wasix-runtime' + : row.target === 'ios-xcframework' || row.target.startsWith('android-') + ? 'native-static-registry' + : 'native-dynamic'; + invariant( + row.kind === expectedKind, + `${row.product}/${row.target} must use ${expectedKind}, got ${row.kind}`, + ); + invariant( + extensionSqlNames(row.product, TOOL).includes(row.sqlName), + `${row.product} target row has undeclared SQL member ${row.sqlName}`, + ); + } +} + +function matrixPairs(matrix, { productField = 'extensions_csv' } = {}) { + const pairs = []; + for (const row of matrix.include) { + for (const product of String(row[productField] ?? '') + .split(',') + .filter(Boolean)) + pairs.push(`${product}\0${row.target}`); + } + return pairs; +} + +export function validateMatrixCoverage(targets, extensions, matrices) { + const selected = (product, kind) => + targets.filter((row) => row.product === product && row.kind === kind); + assertSameStrings( + matrices.native.include.map(({ target }) => target), + selected('liboliphaunt-native', 'native-runtime').map(({ target }) => target), + 'native runtime CI matrix', + ); + const partitions = [matrices.nativeDesktop, matrices.nativeAndroid, matrices.nativeIos]; + assertSameStrings( + partitions.flatMap(({ include }) => include.map(({ target }) => target)), + matrices.native.include.map(({ target }) => target), + 'native runtime CI matrix partitions', + ); + invariant( + new Set(partitions.flatMap(({ include }) => include.map(({ target }) => target))).size === + matrices.native.include.length, + 'native runtime CI partitions must not overlap', + ); + assertSameStrings( + matrices.reactNativeAndroid.include.map(({ target }) => target), + selected('liboliphaunt-native', 'native-runtime') + .filter(({ surfaces }) => surfaces.includes('react-native-android')) + .map(({ target }) => target), + 'React Native Android CI matrix', + ); + assertSameStrings( + matrices.broker.include.map(({ target }) => target), + selected('oliphaunt-broker', 'broker-helper').map(({ target }) => target), + 'broker CI matrix', + ); + assertSameStrings( + matrices.nodeDirect.include.map(({ target }) => target), + selected('oliphaunt-node-direct', 'node-direct-addon').map(({ target }) => target), + 'Node direct CI matrix', + ); + assertSameStrings( + matrices.wasixNapi.include.map(({ target }) => target), + selected('oliphaunt-wasix-napi', 'wasix-napi-addon').map(({ target }) => target), + 'WASIX Node-API CI matrix', + ); + assertSameStrings( + matrices.wasixAot.include.map(({ target_id }) => target_id), + selected('liboliphaunt-wasix', 'wasix-aot-runtime').map(({ target }) => target), + 'WASIX AOT CI matrix', + ); + const wasixAotTargets = new Map( + selected('liboliphaunt-wasix', 'wasix-aot-runtime').map((target) => [target.target, target]), + ); + for (const row of matrices.wasixAot.include) { + const target = wasixAotTargets.get(row.target_id); + invariant(target !== undefined, `WASIX AOT CI matrix has unknown target ${row.target_id}`); + invariant( + row.llvm_url === target.llvmUrl, + `WASIX AOT CI matrix ${row.target_id} must bind its declared LLVM URL`, + ); + invariant( + row.llvm_sha256 === target.llvmSha256 && /^[0-9a-f]{64}$/u.test(row.llvm_sha256), + `WASIX AOT CI matrix ${row.target_id} must bind its exact LLVM SHA-256`, + ); + invariant( + row.llvm_bytes === target.llvmBytes && + Number.isSafeInteger(row.llvm_bytes) && + row.llvm_bytes > 0 && + row.llvm_bytes <= 2 * 1024 * 1024 * 1024, + `WASIX AOT CI matrix ${row.target_id} must bind its exact supported LLVM byte size`, + ); + } + const postmasterTargets = targets.filter( + ({ product, kind }) => + product === 'liboliphaunt-wasix-postmaster' && kind === 'wasix-postmaster-runtime', + ); + assertSameStrings( + matrices.wasixPostmaster.include.map(({ target_id }) => target_id), + postmasterTargets.map(({ target }) => target), + 'WASIX postmaster CI matrix', + ); + const postmasterByTarget = new Map(postmasterTargets.map((target) => [target.target, target])); + for (const row of matrices.wasixPostmaster.include) { + const target = postmasterByTarget.get(row.target_id); + invariant( + target !== undefined, + `WASIX postmaster CI matrix has unknown target ${row.target_id}`, + ); + invariant( + row.os === target.runner && row.target === target.triple, + `WASIX postmaster CI matrix ${row.target_id} must bind its declared runner and target triple`, + ); + invariant( + row.artifact === `liboliphaunt-wasix-postmaster-release-assets-${target.target}`, + `WASIX postmaster CI matrix ${row.target_id} must bind its exact CI artifact name`, + ); + invariant( + row.release_asset_path === + `target/oliphaunt-wasix-postmaster/release-assets/${target.asset.replace('{version}', '*')}`, + `WASIX postmaster CI matrix ${row.target_id} must bind its catalog-derived release asset path`, + ); + invariant( + row.llvm_url === target.llvmUrl && + row.llvm_sha256 === target.llvmSha256 && + row.llvm_bytes === target.llvmBytes, + `WASIX postmaster CI matrix ${row.target_id} must bind its declared LLVM toolchain`, + ); + } + assertSameStrings( + new Set(matrixPairs(matrices.extensionNative)), + new Set( + extensions + .filter(({ family }) => family === 'native') + .map(({ product, target }) => `${product}\0${target}`), + ), + 'native extension CI matrix', + ); + assertSameStrings( + new Set(matrixPairs(matrices.extensionWasix)), + new Set( + extensions + .filter(({ family }) => family === 'wasix') + .map(({ product, target }) => `${product}\0${target}`), + ), + 'WASIX extension CI matrix', + ); + const matrixSqlPairs = (matrix) => + matrix.include.flatMap((row) => + String(row.sql_names_csv ?? '') + .split(',') + .filter(Boolean) + .map((sqlName) => `${sqlName}\0${row.target}`), + ); + assertSameStrings( + matrixSqlPairs(matrices.extensionNative), + extensions + .filter(({ family }) => family === 'native') + .map(({ sqlName, target }) => `${sqlName}\0${target}`), + 'native extension member CI matrix', + ); + assertSameStrings( + matrixSqlPairs(matrices.extensionWasix), + extensions + .filter(({ family }) => family === 'wasix') + .map(({ sqlName, target }) => `${sqlName}\0${target}`), + 'WASIX extension member CI matrix', + ); +} + +function manifestArray(value) { + return value === undefined ? [] : Array.isArray(value) ? value.map(String) : []; +} + +export function validateCarrierCoverage({ + graph, + catalog, + targets, + jsManifest, + nativeToolsManifest, + rustManifest, + platformManifests, +}) { + const carriers = declaredCarrierMap(catalog); + const runtimeProducts = new Set([ + 'liboliphaunt-native', + 'oliphaunt-broker', + 'oliphaunt-node-direct', + 'oliphaunt-wasix-napi', + ]); + for (const product of runtimeProducts) { + const expected = registryPackageRows({ product, packageKind: 'npm' }, TOOL).map( + (row) => row.packageName, + ); + const actual = catalog.carriers + .filter((row) => row.product === product && row.ecosystem === 'npm') + .map((row) => row.name); + assertSameStrings(actual, expected, `${product} npm carrier identities`); + } + for (const target of targets.filter((row) => row.npmPackage)) { + const carrier = carriers.get(`npm:${target.npmPackage}`); + invariant( + carrier?.product === target.product && + carrier.version === graph.products[target.product].version, + `${target.id} npm carrier is missing or version-skewed`, + ); + if (target.npmOs === undefined) continue; + const manifest = platformManifests.get(target.npmPackage); + invariant(manifest !== undefined, `${target.npmPackage} has no package manifest`); + invariant( + manifest.version === graph.products[target.product].version, + `${target.npmPackage} must match ${target.product} version`, + ); + assertSameStrings( + manifestArray(manifest.os), + [target.npmOs], + `${target.npmPackage} os selector`, + ); + assertSameStrings( + manifestArray(manifest.cpu), + [target.npmCpu], + `${target.npmPackage} cpu selector`, + ); + assertSameStrings( + manifestArray(manifest.libc), + target.npmLibc === undefined ? [] : [target.npmLibc], + `${target.npmPackage} libc selector`, + ); + } + const expectedOptional = new Map( + typescriptOptionalRuntimePackageProducts(TOOL).map((row) => [row.packageName, 'workspace:*']), + ); + const actualOptional = object( + jsManifest.optionalDependencies ?? {}, + 'TypeScript optionalDependencies', + ); + assertSameStrings( + Object.keys(actualOptional), + [...expectedOptional.keys()], + 'TypeScript optional runtime packages', + ); + for (const [name, version] of expectedOptional) + invariant( + actualOptional[name] === version, + `TypeScript optional runtime ${name} must use ${version}`, + ); + const expectedToolsOptional = new Map( + nativeToolsOptionalPackageProducts(TOOL).map((row) => [ + row.packageName, + `workspace:${graph.products[row.product].version}`, + ]), + ); + const actualToolsOptional = object( + nativeToolsManifest.optionalDependencies ?? {}, + 'native tools facade optionalDependencies', + ); + assertSameStrings( + Object.keys(actualToolsOptional), + [...expectedToolsOptional.keys()], + 'native tools facade optional packages', + ); + for (const [name, version] of expectedToolsOptional) { + invariant( + actualToolsOptional[name] === version, + `native tools facade optional package ${name} must use ${version}`, + ); + } + const brokerMetadata = object( + object(rustManifest.package, 'Rust package').metadata?.oliphaunt, + 'Rust broker metadata', + ); + invariant( + brokerMetadata['broker-helper'] === 'oliphaunt-broker', + 'Rust SDK broker helper identity must be oliphaunt-broker', + ); + invariant( + brokerMetadata['broker-version'] === graph.products['oliphaunt-broker'].version, + 'Rust SDK broker helper version must match the broker product', + ); +} + +export function validateExtensionCarrierCoverage(graph, catalog, products) { + for (const product of products) { + const targetSets = extensionRegistryPackageTargetSets(product, TOOL); + const expected = extensionRegistryPackageStrings({ product, ...targetSets }).map((identity) => + identity.replace(/^crates:/u, 'cargo:'), + ); + const expectedNative = extensionNativeRegistryPackageStrings({ product, ...targetSets }).map( + (identity) => identity.replace(/^crates:/u, 'cargo:'), + ); + const expectedWasix = extensionWasixRegistryPackageStrings({ + product, + includeAot: targetSets.includeWasixAot, + }).map((identity) => identity.replace(/^crates:/u, 'cargo:')); + const actual = catalog.carriers.filter((row) => expected.includes(row.id)); + assertSameStrings( + actual.map((row) => row.id), + expected, + `${product} registry carriers`, + ); + for (const [family, identities] of [ + ['native', expectedNative], + ['wasix', expectedWasix], + ]) { + const owner = extensionReleaseProduct(product, family, TOOL); + invariant( + actual + .filter((row) => identities.includes(row.id)) + .every((row) => row.product === owner && row.version === graph.products[owner].version), + `${product} ${family} carrier versions must match ${owner}`, + ); + } + } +} + +function platformPackageManifests(graph, targets) { + const names = new Set( + targets.filter(({ npmPackage }) => npmPackage).map(({ npmPackage }) => npmPackage), + ); + const manifests = new Map(); + for (const config of Object.values(graph.products)) { + for (const relativePath of config.version_files ?? []) { + if (path.basename(relativePath) !== 'package.json') continue; + const manifest = readJson(relativePath); + if (!names.has(manifest.name)) continue; + invariant( + !manifests.has(manifest.name), + `duplicate platform package manifest ${manifest.name}`, + ); + manifests.set(manifest.name, manifest); + } + } + return manifests; +} + +export function repositoryInventory() { + const graph = { products: loadProducts(TOOL) }; + const targets = allArtifactTargets({}, TOOL); + const products = exactExtensionProducts(TOOL); + const extensions = extensionArtifactTargets({}, TOOL); + return { + graph, + targets, + products, + extensions, + catalog: loadPublicationCatalog(TOOL), + sdkProducts: sdkPackageProducts(TOOL), + matrices: { + native: liboliphauntNativeRuntimeMatrix(), + nativeDesktop: liboliphauntNativeDesktopRuntimeMatrix(), + nativeAndroid: liboliphauntNativeAndroidRuntimeMatrix(), + nativeIos: liboliphauntNativeIosRuntimeMatrix(), + reactNativeAndroid: reactNativeAndroidMobileAppMatrix(), + extensionNative: extensionArtifactsNativeMatrix(), + extensionWasix: extensionArtifactsWasixMatrix(), + wasixAot: liboliphauntWasixAotRuntimeMatrix(), + wasixPostmaster: liboliphauntWasixPostmasterRuntimeMatrix(), + broker: brokerRuntimeMatrix(), + nodeDirect: nodeDirectRuntimeMatrix(), + wasixNapi: wasixNapiRuntimeMatrix(), + }, + }; +} + +export function validateRepository() { + const inventory = repositoryInventory(); + validateExtensionCoverage(inventory.targets, inventory.products, inventory.extensions); + validateMatrixCoverage(inventory.targets, inventory.extensions, inventory.matrices); + validateCarrierCoverage({ + graph: inventory.graph, + catalog: inventory.catalog, + targets: inventory.targets, + jsManifest: readJson('src/sdks/ts/sdk/package.json'), + nativeToolsManifest: readJson('src/postgres-tools/native/npm/package.json'), + rustManifest: readToml('src/sdks/rust/sdk/Cargo.toml'), + platformManifests: platformPackageManifests(inventory.graph, inventory.targets), + }); + validateExtensionCarrierCoverage(inventory.graph, inventory.catalog, inventory.products); + return { + artifactTargets: inventory.targets.length, + extensionProducts: inventory.products.length, + extensionTargets: inventory.extensions.length, + registryCarriers: inventory.catalog.carriers.length, + sdkProducts: inventory.sdkProducts.length, + }; +} + +if (import.meta.main) { + try { + const summary = validateRepository(); + console.log( + `artifact target checks passed (${summary.artifactTargets} runtime/helper rows, ` + + `${summary.extensionProducts} exact-extension products, ${summary.extensionTargets} extension rows, ` + + `${summary.registryCarriers} catalog-declared registry carrier minima, ${summary.sdkProducts} SDK packages)`, + ); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } +} diff --git a/tools/release/check_github_release_assets.mjs b/tools/release/check_github_release_assets.mjs deleted file mode 100644 index 77ee97202..000000000 --- a/tools/release/check_github_release_assets.mjs +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bun -// Verify product-scoped GitHub release assets without requiring attestations. - -import { currentVersion } from "./product-version.mjs"; -import { - expectedAssets, - verifyReleaseAssets, -} from "./verify_github_release_attestations.mjs"; - -function fail(message) { - console.error(`check_github_release_assets.mjs: ${message}`); - process.exit(1); -} - -function parseArgs(argv) { - const args = { - asset: [], - defaultAssets: false, - product: undefined, - version: undefined, - }; - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - if (value === "--asset") { - const asset = argv[++index]; - if (!asset) { - fail("--asset requires a value"); - } - args.asset.push(asset); - } else if (value.startsWith("--asset=")) { - args.asset.push(value.slice("--asset=".length)); - } else if (value === "--default-assets") { - args.defaultAssets = true; - } else if (value === "--version") { - args.version = argv[++index]; - if (!args.version) { - fail("--version requires a value"); - } - } else if (value.startsWith("--version=")) { - args.version = value.slice("--version=".length); - } else if (value === "--help" || value === "-h") { - console.log("usage: tools/release/check_github_release_assets.mjs [--version VERSION] [--default-assets] [--asset NAME...]"); - process.exit(0); - } else if (value.startsWith("--")) { - fail(`unknown argument ${value}`); - } else if (args.product === undefined) { - args.product = value; - } else { - fail(`unexpected positional argument ${value}`); - } - } - if (args.product === undefined) { - fail("product is required"); - } - return args; -} - -async function main(argv) { - const args = parseArgs(argv); - const version = args.version ?? await currentVersion(args.product); - const assets = [...args.asset]; - if (args.defaultAssets) { - assets.push(...await expectedAssets(args.product, version)); - } - const uniqueAssets = [...new Set(assets)].sort(); - if (uniqueAssets.length === 0) { - fail("pass --default-assets or at least one --asset"); - } - await verifyReleaseAssets(args.product, version, uniqueAssets); -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/check_github_release_assets.mts b/tools/release/check_github_release_assets.mts new file mode 100644 index 000000000..3f5ac7248 --- /dev/null +++ b/tools/release/check_github_release_assets.mts @@ -0,0 +1,73 @@ +#!/usr/bin/env bun +// Verify product-scoped GitHub release assets without requiring attestations. + +import { currentVersion } from './product-version.mts'; +import { expectedAssets, verifyReleaseAssets } from './verify_github_release_attestations.mts'; + +function fail(message) { + console.error(`check_github_release_assets.mts: ${message}`); + process.exit(1); +} + +function parseArgs(argv) { + const args = { + asset: [], + defaultAssets: false, + product: undefined, + version: undefined, + }; + for (let index = 0; index < argv.length; index += 1) { + const value = argv[index]; + if (value === '--asset') { + const asset = argv[++index]; + if (!asset) { + fail('--asset requires a value'); + } + args.asset.push(asset); + } else if (value.startsWith('--asset=')) { + args.asset.push(value.slice('--asset='.length)); + } else if (value === '--default-assets') { + args.defaultAssets = true; + } else if (value === '--version') { + args.version = argv[++index]; + if (!args.version) { + fail('--version requires a value'); + } + } else if (value.startsWith('--version=')) { + args.version = value.slice('--version='.length); + } else if (value === '--help' || value === '-h') { + console.log( + 'usage: tools/release/check_github_release_assets.mts [--version VERSION] [--default-assets] [--asset NAME...]', + ); + process.exit(0); + } else if (value.startsWith('--')) { + fail(`unknown argument ${value}`); + } else if (args.product === undefined) { + args.product = value; + } else { + fail(`unexpected positional argument ${value}`); + } + } + if (args.product === undefined) { + fail('product is required'); + } + return args; +} + +async function main(argv) { + const args = parseArgs(argv); + const version = args.version ?? (await currentVersion(args.product)); + const assets = [...args.asset]; + if (args.defaultAssets) { + assets.push(...(await expectedAssets(args.product, version))); + } + const uniqueAssets = [...new Set(assets)].sort(); + if (uniqueAssets.length === 0) { + fail('pass --default-assets or at least one --asset'); + } + await verifyReleaseAssets(args.product, version, uniqueAssets); +} + +if (import.meta.main) { + await main(Bun.argv.slice(2)); +} diff --git a/tools/release/check_publish_environment.mjs b/tools/release/check_publish_environment.mjs deleted file mode 100755 index ac6dfb10b..000000000 --- a/tools/release/check_publish_environment.mjs +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env bun -import fs from 'node:fs/promises'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); -const oidcTargets = new Set(['crates-io', 'npm']); -const mavenTargets = new Set(['maven-central']); -const githubTargets = new Set(['github-release', 'github-release-assets', 'swift-package-source-tag']); -const forbiddenEnvVars = { - CARGO_REGISTRY_TOKEN: [ - new Set(['crates-io']), - 'Cargo publishing uses crates.io trusted publishing through GitHub Actions OIDC', - ], - NPM_TOKEN: [ - new Set(['npm']), - 'npm publishing uses trusted publishing with provenance through GitHub Actions OIDC', - ], - NODE_AUTH_TOKEN: [ - new Set(['npm']), - 'npm publishing uses trusted publishing with provenance through GitHub Actions OIDC', - ], - COCOAPODS_TRUNK_TOKEN: [ - new Set(), - 'Apple SDK releases use SwiftPM plus GitHub assets, not CocoaPods trunk', - ], - COCOAPODS_TRUNK_EMAIL: [ - new Set(), - 'Apple SDK releases use SwiftPM plus GitHub assets, not CocoaPods trunk', - ], -}; - -function fail(message) { - console.error(`check_publish_environment.mjs: ${message}`); - process.exit(1); -} - -function parseArgs(argv) { - let productsJson = null; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === '--products-json') { - productsJson = argv[index + 1] ?? null; - index += 1; - continue; - } - fail(`unknown argument: ${arg}`); - } - if (productsJson === null) { - fail('usage: tools/release/check_publish_environment.mjs --products-json '); - } - return { productsJson }; -} - -function parseProducts(raw) { - let value; - try { - value = JSON.parse(raw); - } catch (error) { - fail(`--products-json must be valid JSON: ${error.message}`); - } - if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) { - fail('--products-json must be a JSON string list'); - } - return new Set(value); -} - -async function productConfigs() { - const releasePlease = JSON.parse(await fs.readFile(path.join(root, 'release-please-config.json'), 'utf8')); - if (typeof releasePlease.packages !== 'object' || releasePlease.packages === null) { - fail('release-please-config.json must define packages'); - } - const products = new Map(); - const packageEntries = Object.entries(releasePlease.packages).sort(([left], [right]) => - left < right ? -1 : left > right ? 1 : 0, - ); - for (const [packagePath, packageConfig] of packageEntries) { - if (path.isAbsolute(packagePath) || packagePath.split(/[\\/]/u).includes('..')) { - fail(`release-please package path must stay inside the repository: ${packagePath}`); - } - const component = packageConfig?.component; - if (typeof component !== 'string' || component.length === 0) { - fail(`${packagePath}.component must be a non-empty string`); - } - const file = path.join(root, packagePath, 'release.toml'); - const metadata = Bun.TOML.parse(await fs.readFile(file, 'utf8')); - const id = metadata.id; - if (id !== component) { - fail(`${path.relative(root, file)} must declare id = "${component}"`); - } - if (products.has(id)) { - fail(`duplicate release product id ${id}`); - } - const publishTargets = metadata.publish_targets ?? []; - if ( - !Array.isArray(publishTargets) || - publishTargets.some((target) => typeof target !== 'string') - ) { - fail(`${id}.publish_targets must be a string list`); - } - products.set(id, { publishTargets }); - } - return products; -} - -function requireEnv(name, context, failures) { - if (!process.env[name]) { - failures.push(`${context} requires ${name}`); - } -} - -function requireAnyEnv(names, context, failures) { - if (!names.some((name) => process.env[name])) { - failures.push(`${context} requires one of ${names.join(', ')}`); - } -} - -function intersects(left, right) { - for (const value of left) { - if (right.has(value)) { - return true; - } - } - return false; -} - -const args = parseArgs(Bun.argv.slice(2)); -const products = parseProducts(args.productsJson); -const configs = await productConfigs(); -const unknown = [...products].filter((product) => !configs.has(product)).sort(); -if (unknown.length > 0) { - fail(`unknown release products: ${unknown.join(', ')}`); -} - -const publishTargets = new Set(); -for (const product of products) { - for (const target of configs.get(product).publishTargets) { - publishTargets.add(target); - } -} - -const failures = []; -for (const [name, [blockedTargets, reason]] of Object.entries(forbiddenEnvVars).sort()) { - const appliesToSelection = - products.size > 0 && (blockedTargets.size === 0 || intersects(publishTargets, blockedTargets)); - if (appliesToSelection && process.env[name]) { - failures.push(`forbidden release credential ${name} is set: ${reason}`); - } -} - -if (intersects(publishTargets, oidcTargets)) { - requireEnv('ACTIONS_ID_TOKEN_REQUEST_TOKEN', 'trusted publishing', failures); - requireEnv('ACTIONS_ID_TOKEN_REQUEST_URL', 'trusted publishing', failures); -} - -if (intersects(publishTargets, githubTargets)) { - requireAnyEnv(['GH_TOKEN', 'GITHUB_TOKEN'], 'GitHub release assets and tags', failures); -} - -if (intersects(publishTargets, mavenTargets)) { - for (const name of [ - 'ORG_GRADLE_PROJECT_mavenCentralUsername', - 'ORG_GRADLE_PROJECT_mavenCentralPassword', - 'ORG_GRADLE_PROJECT_signingInMemoryKey', - 'ORG_GRADLE_PROJECT_signingInMemoryKeyId', - 'ORG_GRADLE_PROJECT_signingInMemoryKeyPassword', - ]) { - requireEnv(name, 'Maven Central publish', failures); - } -} - -if (failures.length > 0) { - fail(`missing publish environment:\n - ${failures.join('\n - ')}`); -} - -console.log('publish environment checks passed'); diff --git a/tools/release/check_publish_environment.mts b/tools/release/check_publish_environment.mts new file mode 100755 index 000000000..5d523d5dd --- /dev/null +++ b/tools/release/check_publish_environment.mts @@ -0,0 +1,182 @@ +#!/usr/bin/env bun +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); +const oidcTargets = new Set(['crates-io', 'npm']); +const mavenTargets = new Set(['maven-central']); +const githubTargets = new Set([ + 'github-release', + 'github-release-assets', + 'swift-package-source-tag', +]); +const forbiddenEnvVars = { + CARGO_REGISTRY_TOKEN: [ + new Set(['crates-io']), + 'Cargo publishing uses crates.io trusted publishing through GitHub Actions OIDC', + ], + NPM_TOKEN: [ + new Set(['npm']), + 'npm publishing uses trusted publishing with provenance through GitHub Actions OIDC', + ], + NODE_AUTH_TOKEN: [ + new Set(['npm']), + 'npm publishing uses trusted publishing with provenance through GitHub Actions OIDC', + ], + COCOAPODS_TRUNK_TOKEN: [ + new Set(), + 'Apple SDK releases use SwiftPM plus GitHub assets, not CocoaPods trunk', + ], + COCOAPODS_TRUNK_EMAIL: [ + new Set(), + 'Apple SDK releases use SwiftPM plus GitHub assets, not CocoaPods trunk', + ], +}; + +function fail(message) { + console.error(`check_publish_environment.mts: ${message}`); + process.exit(1); +} + +function parseArgs(argv) { + let productsJson = null; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--products-json') { + productsJson = argv[index + 1] ?? null; + index += 1; + continue; + } + fail(`unknown argument: ${arg}`); + } + if (productsJson === null) { + fail('usage: tools/release/check_publish_environment.mts --products-json '); + } + return { productsJson }; +} + +function parseProducts(raw) { + let value; + try { + value = JSON.parse(raw); + } catch (error) { + fail(`--products-json must be valid JSON: ${error.message}`); + } + if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) { + fail('--products-json must be a JSON string list'); + } + return new Set(value); +} + +async function productConfigs() { + const releasePlease = JSON.parse( + await fs.readFile(path.join(root, 'release-please-config.json'), 'utf8'), + ); + if (typeof releasePlease.packages !== 'object' || releasePlease.packages === null) { + fail('release-please-config.json must define packages'); + } + const products = new Map(); + const packageEntries = Object.entries(releasePlease.packages).sort(([left], [right]) => + left < right ? -1 : left > right ? 1 : 0, + ); + for (const [packagePath, packageConfig] of packageEntries) { + if (path.isAbsolute(packagePath) || packagePath.split(/[\\/]/u).includes('..')) { + fail(`release-please package path must stay inside the repository: ${packagePath}`); + } + const component = packageConfig?.component; + if (typeof component !== 'string' || component.length === 0) { + fail(`${packagePath}.component must be a non-empty string`); + } + const file = path.join(root, packagePath, 'release.toml'); + const metadata = Bun.TOML.parse(await fs.readFile(file, 'utf8')); + const id = metadata.id; + if (id !== component) { + fail(`${path.relative(root, file)} must declare id = "${component}"`); + } + if (products.has(id)) { + fail(`duplicate release product id ${id}`); + } + const publishTargets = metadata.publish_targets ?? []; + if ( + !Array.isArray(publishTargets) || + publishTargets.some((target) => typeof target !== 'string') + ) { + fail(`${id}.publish_targets must be a string list`); + } + products.set(id, { publishTargets }); + } + return products; +} + +function requireEnv(name, context, failures) { + if (!process.env[name]) { + failures.push(`${context} requires ${name}`); + } +} + +function requireAnyEnv(names, context, failures) { + if (!names.some((name) => process.env[name])) { + failures.push(`${context} requires one of ${names.join(', ')}`); + } +} + +function intersects(left, right) { + for (const value of left) { + if (right.has(value)) { + return true; + } + } + return false; +} + +const args = parseArgs(Bun.argv.slice(2)); +const products = parseProducts(args.productsJson); +const configs = await productConfigs(); +const unknown = [...products].filter((product) => !configs.has(product)).sort(); +if (unknown.length > 0) { + fail(`unknown release products: ${unknown.join(', ')}`); +} + +const publishTargets = new Set(); +for (const product of products) { + for (const target of configs.get(product).publishTargets) { + publishTargets.add(target); + } +} + +const failures = []; +for (const [name, [blockedTargets, reason]] of Object.entries(forbiddenEnvVars).sort()) { + const appliesToSelection = + products.size > 0 && (blockedTargets.size === 0 || intersects(publishTargets, blockedTargets)); + if (appliesToSelection && process.env[name]) { + failures.push(`forbidden release credential ${name} is set: ${reason}`); + } +} + +if (intersects(publishTargets, oidcTargets)) { + requireEnv('ACTIONS_ID_TOKEN_REQUEST_TOKEN', 'trusted publishing', failures); + requireEnv('ACTIONS_ID_TOKEN_REQUEST_URL', 'trusted publishing', failures); +} + +if (intersects(publishTargets, githubTargets)) { + requireAnyEnv(['GH_TOKEN', 'GITHUB_TOKEN'], 'GitHub release assets and tags', failures); +} + +if (intersects(publishTargets, mavenTargets)) { + for (const name of [ + 'ORG_GRADLE_PROJECT_mavenCentralUsername', + 'ORG_GRADLE_PROJECT_mavenCentralPassword', + 'ORG_GRADLE_PROJECT_signingInMemoryKey', + 'ORG_GRADLE_PROJECT_signingInMemoryKeyId', + 'ORG_GRADLE_PROJECT_signingInMemoryKeyPassword', + ]) { + requireEnv(name, 'Maven Central publish', failures); + } +} + +if (failures.length > 0) { + fail(`missing publish environment:\n - ${failures.join('\n - ')}`); +} + +console.log('publish environment checks passed'); diff --git a/tools/release/check_registry_publication.mjs b/tools/release/check_registry_publication.mjs deleted file mode 100644 index 9bc5537c8..000000000 --- a/tools/release/check_registry_publication.mjs +++ /dev/null @@ -1,897 +0,0 @@ -#!/usr/bin/env bun -import { readFile } from "node:fs/promises"; -import path from "node:path"; -import { currentVersion } from "./product-version.mjs"; -import { - loadPublicationCatalog, - REGISTRY_KIND_TO_ECOSYSTEM, -} from "./publication-catalog.mjs"; -import { loadPublicationLock, lockedCarriers } from "./publication-lock.mjs"; -import { - retryAfterSeconds, - registryRetryDelaySeconds, - registryStatusRetryable, -} from "./registry-http-retry.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const CRATES_IO_API = process.env.CRATES_IO_API || "https://crates.io/api/v1"; -const NPM_REGISTRY = process.env.NPM_REGISTRY || "https://registry.npmjs.org"; -const MAVEN_CENTRAL_BASE = process.env.MAVEN_CENTRAL_BASE || "https://repo1.maven.org/maven2"; -const REQUEST_ATTEMPTS = Math.max(1, Number.parseInt(process.env.OLIPHAUNT_REGISTRY_QUERY_ATTEMPTS || "8", 10) || 8); -const REQUEST_RETRY_DELAY_SECONDS = Math.max(0, Number.parseFloat(process.env.OLIPHAUNT_REGISTRY_QUERY_RETRY_DELAY || "1.0") || 0); -const REQUEST_TIMEOUT_MS = 20_000; -const DEADLINE_CLEANUP_RESERVE_MS = 5_000; -export const CRATES_IO_READ_INTERVAL_SECONDS = 1; -export const CRATES_IO_READ_RETRY_BUDGET_SECONDS = 10 * 60; -export const CRATES_IO_RATE_LIMIT_FALLBACK_SECONDS = 60; -const MAX_REGISTRY_JSON_BYTES = 8 * 1024 * 1024; -const REGISTRY_TARGETS = new Set(["crates-io", "npm", "maven-central"]); -const REGISTRY_KINDS = new Set(["crates", "npm", "maven"]); -const REGISTRY_KIND_BY_ECOSYSTEM = new Map( - Object.entries(REGISTRY_KIND_TO_ECOSYSTEM).map(([kind, ecosystem]) => [ecosystem, kind]), -); -const USER_AGENT = "oliphaunt-release-check (https://github.com/f0rr0/oliphaunt)"; - -const caches = { - releaseConfig: undefined, - packageByProduct: undefined, - publicationLock: undefined, -}; - -class RegistryHttpError extends Error { - constructor(status, label) { - super(`HTTP ${status} for ${label}`); - this.status = status; - } -} - -class RegistryResponseError extends Error {} - -function registryDeadlineRemainingMilliseconds(context, nowImpl = () => Date.now()) { - const raw = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH?.trim(); - if (!raw) return null; - if (!/^[1-9][0-9]*$/u.test(raw)) { - throw new RegistryResponseError("REGISTRY_MUTATION_DEADLINE_EPOCH must be a positive Unix timestamp"); - } - const deadlineMilliseconds = Number(raw) * 1000; - if (!Number.isSafeInteger(deadlineMilliseconds)) { - throw new RegistryResponseError("REGISTRY_MUTATION_DEADLINE_EPOCH exceeds the safe timestamp range"); - } - const remaining = deadlineMilliseconds - nowImpl() - DEADLINE_CLEANUP_RESERVE_MS; - if (remaining <= 0) { - throw new RegistryResponseError( - `${context} refused because the shared registry mutation deadline has been reached`, - ); - } - return remaining; -} - -export function registryRequestTimeoutMilliseconds(context, { - nowImpl = () => Date.now(), -} = {}) { - const remaining = registryDeadlineRemainingMilliseconds(context, nowImpl); - return remaining === null ? REQUEST_TIMEOUT_MS : Math.max(1, Math.min(REQUEST_TIMEOUT_MS, remaining)); -} - -export async function boundedRegistrySleep(seconds, context, { - nowImpl = () => Date.now(), - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), -} = {}) { - if (!Number.isFinite(seconds) || seconds < 0) { - throw new RegistryResponseError(`${context} requested an invalid registry retry delay`); - } - const milliseconds = seconds * 1000; - const remaining = registryDeadlineRemainingMilliseconds(context, nowImpl); - if (remaining !== null && milliseconds >= remaining) { - throw new RegistryResponseError( - `${context} cannot wait ${Math.ceil(seconds)}s before the shared registry mutation deadline`, - ); - } - if (milliseconds > 0) await sleepImpl(milliseconds); -} - -export async function readBoundedRegistryJson(response, label, maximum = MAX_REGISTRY_JSON_BYTES) { - if (!Number.isSafeInteger(maximum) || maximum < 1) { - throw new RegistryResponseError("registry response byte limit must be a positive safe integer"); - } - const contentLength = response.headers?.get?.("content-length"); - if (contentLength !== null && contentLength !== undefined) { - const declared = Number(contentLength); - if (!Number.isSafeInteger(declared) || declared < 0) { - await response.body?.cancel?.().catch(() => {}); - throw new RegistryResponseError(`${label} returned an invalid Content-Length`); - } - if (declared > maximum) { - await response.body?.cancel?.().catch(() => {}); - throw new RegistryResponseError(`${label} response exceeds ${maximum} bytes`); - } - } - const reader = response.body?.getReader?.(); - let bytes; - if (reader === undefined) { - bytes = Buffer.from(await response.arrayBuffer()); - if (bytes.length > maximum) { - throw new RegistryResponseError(`${label} response exceeds ${maximum} bytes`); - } - } else { - const chunks = []; - let size = 0; - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > maximum) { - await reader.cancel().catch(() => {}); - throw new RegistryResponseError(`${label} response exceeds ${maximum} bytes`); - } - chunks.push(Buffer.from(value)); - } - } finally { - reader.releaseLock(); - } - bytes = Buffer.concat(chunks, size); - } - try { - return JSON.parse(bytes.toString("utf8")); - } catch (error) { - throw new RegistryResponseError(`${label} returned invalid JSON: ${error.message}`); - } -} - -function fail(message) { - console.error(`check_registry_publication.mjs: ${message}`); - process.exit(1); -} - -function rel(file) { - const relative = path.relative(ROOT, file); - return relative.startsWith("..") || path.isAbsolute(relative) ? file : relative.split(path.sep).join("/"); -} - -async function readJson(file) { - let text; - try { - text = await readFile(file, "utf8"); - } catch { - fail(`missing ${rel(file)}`); - } - const value = JSON.parse(text); - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(`${rel(file)} must contain a JSON object`); - } - return value; -} - -async function releaseConfig() { - if (caches.releaseConfig === undefined) { - caches.releaseConfig = await readJson(path.join(ROOT, "release-please-config.json")); - } - return caches.releaseConfig; -} - -function assertRelative(value, context) { - if (typeof value !== "string" || value.length === 0) { - fail(`${context} must be a non-empty string`); - } - const parts = value.split(/[\\/]/u); - if (path.isAbsolute(value) || /^[A-Za-z]:[\\/]/u.test(value) || parts.includes("..")) { - fail(`${context} must stay inside the repository: ${JSON.stringify(value)}`); - } - return value; -} - -async function packageByProduct() { - if (caches.packageByProduct !== undefined) { - return caches.packageByProduct; - } - const config = await releaseConfig(); - const packages = config.packages; - if (packages === null || Array.isArray(packages) || typeof packages !== "object") { - fail("release-please-config.json must define packages"); - } - const byProduct = new Map(); - for (const [rawPackagePath, packageConfig] of Object.entries(packages)) { - if (packageConfig === null || Array.isArray(packageConfig) || typeof packageConfig !== "object") { - fail(`${rawPackagePath} release-please config must be an object`); - } - const component = packageConfig.component; - if (typeof component !== "string" || component.length === 0) { - fail(`${rawPackagePath}.component must be a non-empty string`); - } - if (byProduct.has(component)) { - fail(`duplicate release-please component ${component}`); - } - const packagePath = assertRelative(rawPackagePath, `${component}.packagePath`); - byProduct.set(component, { packagePath, packageConfig }); - } - caches.packageByProduct = byProduct; - return byProduct; -} - -async function productIds() { - return [...(await packageByProduct()).keys()]; -} - -async function productCrates(product) { - const catalog = loadPublicationCatalog("check_registry_publication.mjs", { products: [product] }); - const productRow = catalog.products.find((row) => row.id === product); - if (!productRow?.publishTargets.includes("crates-io")) { - fail(`${product} does not publish to crates.io`); - } - const crates = catalog.carriers - .filter((carrier) => carrier.product === product && carrier.ecosystem === "cargo") - .map((carrier) => carrier.name); - if (crates.length === 0) { - fail(`${product} does not declare Cargo registry packages`); - } - const duplicates = [...new Set(crates.filter((crate, index) => crates.indexOf(crate) !== index))].sort(); - if (duplicates.length > 0) { - fail(`${product} declares duplicate Cargo registry packages: ${duplicates.join(", ")}`); - } - return crates.sort(); -} - -function packageLabel(pkg) { - return `${pkg.kind}:${pkg.name}@${pkg.version}`; -} - -function identityLabel(pkg) { - return `${pkg.kind}:${pkg.name}`; -} - -export function productRegistryPackagesFromLock( - publicationLock, - product, - { versionOverride = undefined, registryKind = undefined } = {}, -) { - const productRow = publicationLock.products.find((row) => row.id === product); - if (productRow === undefined) { - fail(`publication lock does not contain release product ${JSON.stringify(product)}`); - } - if (versionOverride !== undefined && versionOverride !== productRow.version) { - fail(`${product} requested version ${versionOverride} does not match frozen publication-lock version ${productRow.version}`); - } - const ecosystemByKind = new Map([["crates", "cargo"], ["npm", "npm"], ["maven", "maven"]]); - if (registryKind !== undefined && !ecosystemByKind.has(registryKind)) { - fail(`unsupported registry kind ${JSON.stringify(registryKind)}`); - } - const ecosystem = registryKind === undefined ? undefined : ecosystemByKind.get(registryKind); - const kindByEcosystem = new Map([["cargo", "crates"], ["npm", "npm"], ["maven", "maven"]]); - const packages = lockedCarriers(publicationLock, { product, ecosystem }).map((carrier) => ({ - kind: kindByEcosystem.get(carrier.ecosystem), - name: carrier.name, - version: carrier.version, - })); - if (registryKind !== undefined && packages.length === 0) { - fail(`${product} has no ${registryKind} registry packages in the publication lock`); - } - return packages; -} - -export async function productRegistryPackages(product, { versionOverride = undefined, registryKind = undefined } = {}) { - const publicationLockPath = process.env.OLIPHAUNT_PUBLICATION_LOCK; - if (publicationLockPath) { - if (caches.publicationLock === undefined) { - caches.publicationLock = loadPublicationLock(path.resolve(ROOT, publicationLockPath)); - } - return productRegistryPackagesFromLock(caches.publicationLock, product, { - versionOverride, - registryKind, - }); - } - const version = versionOverride || (await currentVersion(product)); - const catalog = loadPublicationCatalog("check_registry_publication.mjs", { products: [product] }); - const productRow = catalog.products.find((row) => row.id === product); - const publishTargets = new Set(productRow?.publishTargets ?? []); - const expectedKinds = new Map([ - ["crates-io", "crates"], - ["npm", "npm"], - ["maven-central", "maven"], - ]); - const packages = catalog.carriers - .filter((carrier) => carrier.product === product) - .map((carrier) => ({ - kind: REGISTRY_KIND_BY_ECOSYSTEM.get(carrier.ecosystem), - name: carrier.name, - version, - })); - const targetByKind = new Map([...expectedKinds].map(([target, kind]) => [kind, target])); - const stalePackages = packages - .filter((pkg) => !publishTargets.has(targetByKind.get(pkg.kind))) - .map(identityLabel) - .sort(); - if (stalePackages.length > 0) { - fail(`${product} publication catalog contains entries without a matching registry publish target: ${stalePackages.join(", ")}`); - } - const duplicateIdentities = packages - .map(identityLabel) - .filter((identity, index, identities) => identities.indexOf(identity) !== index); - if (duplicateIdentities.length > 0) { - fail(`${product}.registry_packages contains duplicate identities: ${[...new Set(duplicateIdentities)].sort().join(", ")}`); - } - const missingKinds = []; - for (const [target, kind] of expectedKinds.entries()) { - if (publishTargets.has(target) && !packages.some((pkg) => pkg.kind === kind)) { - missingKinds.push(kind); - } - } - if (missingKinds.length > 0) { - const selectedTargets = [...publishTargets].filter((target) => REGISTRY_TARGETS.has(target)).sort(); - fail(`${product} publishes to ${JSON.stringify(selectedTargets)} but is missing registry_packages entries for: ${missingKinds.join(", ")}`); - } - let filtered = packages; - if (registryKind !== undefined) { - if (!REGISTRY_KINDS.has(registryKind)) { - fail(`unsupported registry kind ${JSON.stringify(registryKind)}`); - } - filtered = packages.filter((pkg) => pkg.kind === registryKind); - if (filtered.length === 0) { - fail(`${product} has no ${registryKind} registry packages to check`); - } - } - return filtered; -} - -async function requestJson(url, label, { fetchImpl = fetch } = {}) { - let lastError; - for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { - let retryHeaders; - try { - const response = await fetchImpl(url, { - headers: { - Accept: "application/json", - "User-Agent": USER_AGENT, - }, - redirect: "follow", - signal: AbortSignal.timeout(registryRequestTimeoutMilliseconds(`registry request for ${label}`)), - }); - if (response.ok) { - return await readBoundedRegistryJson(response, label); - } - const error = new RegistryHttpError(response.status, label); - const headers = response.headers; - await response.body?.cancel?.().catch(() => {}); - if (!registryStatusRetryable(response.status)) { - throw error; - } - retryHeaders = headers; - lastError = error; - } catch (error) { - lastError = error; - if (error instanceof RegistryResponseError) { - throw error; - } - if (error instanceof RegistryHttpError && !registryStatusRetryable(error.status)) { - throw error; - } - } - if (attempt + 1 < REQUEST_ATTEMPTS) { - await boundedRegistrySleep(registryRetryDelaySeconds({ - headers: retryHeaders, - attempt, - baseSeconds: REQUEST_RETRY_DELAY_SECONDS, - }), `registry retry for ${label}`); - } - } - throw lastError ?? new Error(`failed to query ${label}`); -} - -async function urlExistsViaGet(url, options = {}) { - return urlExists(url, { ...options, method: "GET", allowMethodFallback: false }); -} - -export function cratesIoReadRetryDelaySeconds({ headers, status, attempt, now = Date.now() }) { - if (status === 429) { - const requested = retryAfterSeconds(headers, now); - if (requested !== null) return requested; - return Math.min(300, CRATES_IO_RATE_LIMIT_FALLBACK_SECONDS * (2 ** attempt)); - } - return registryRetryDelaySeconds({ headers, attempt, now }); -} - -export async function urlExists(url, { - method = "HEAD", - allowMethodFallback = true, - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = () => Date.now(), - beforeRequestSeconds = 0, - retryBudgetSeconds = null, - retryDelayImpl = ({ headers, attempt, now }) => - registryRetryDelaySeconds({ headers, attempt, baseSeconds: REQUEST_RETRY_DELAY_SECONDS, now }), - retryContext = `registry retry for ${url}`, -} = {}) { - let lastError; - let retryDelaySpentSeconds = 0; - for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { - let retryHeaders; - let retryStatus; - try { - await boundedRegistrySleep(beforeRequestSeconds, `registry read pacing for ${url}`, { - nowImpl, - sleepImpl, - }); - const response = await fetchImpl(url, { - method, - headers: { - Accept: "application/json", - "User-Agent": USER_AGENT, - }, - redirect: "follow", - signal: AbortSignal.timeout(registryRequestTimeoutMilliseconds(`registry request for ${url}`, { nowImpl })), - }); - if (response.ok) { - await response.body?.cancel?.().catch(() => {}); - return true; - } - if (response.status === 404) { - await response.body?.cancel?.().catch(() => {}); - return false; - } - if (response.status === 405 && method === "HEAD" && allowMethodFallback) { - await response.body?.cancel?.().catch(() => {}); - return urlExistsViaGet(url, { - fetchImpl, - sleepImpl, - nowImpl, - beforeRequestSeconds, - retryBudgetSeconds, - retryDelayImpl, - retryContext, - }); - } - const error = new RegistryHttpError(response.status, url); - const headers = response.headers; - await response.body?.cancel?.().catch(() => {}); - if (!registryStatusRetryable(response.status)) { - fail(`registry returned HTTP ${response.status} for ${url}`); - } - retryHeaders = headers; - retryStatus = response.status; - lastError = error; - } catch (error) { - lastError = error; - if (error instanceof RegistryResponseError) { - throw error; - } - if (error instanceof RegistryHttpError && !registryStatusRetryable(error.status)) { - fail(`registry returned HTTP ${error.status} for ${url}`); - } - } - if (attempt + 1 < REQUEST_ATTEMPTS) { - const delaySeconds = retryDelayImpl({ - headers: retryHeaders, - status: retryStatus, - attempt, - now: nowImpl(), - }); - if (!Number.isFinite(delaySeconds) || delaySeconds < 0) { - throw new RegistryResponseError(`${retryContext} requested an invalid delay`); - } - if ( - retryBudgetSeconds !== null - && delaySeconds > retryBudgetSeconds - retryDelaySpentSeconds - ) { - throw new RegistryResponseError( - `${retryContext} exceeds its bounded ${retryBudgetSeconds}s retry-delay budget`, - ); - } - retryDelaySpentSeconds += delaySeconds; - await boundedRegistrySleep(delaySeconds, retryContext, { nowImpl, sleepImpl }); - } - } - if (lastError instanceof RegistryHttpError) { - fail(`registry returned HTTP ${lastError.status} for ${url}`); - } - fail(`failed to query registry URL ${url}: ${lastError}`); -} - -export async function cratesioUrlExists(url, label, { - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = () => Date.now(), -} = {}) { - try { - return await urlExists(url, { - method: "GET", - allowMethodFallback: false, - fetchImpl, - sleepImpl, - nowImpl, - beforeRequestSeconds: CRATES_IO_READ_INTERVAL_SECONDS, - retryBudgetSeconds: CRATES_IO_READ_RETRY_BUDGET_SECONDS, - retryDelayImpl: cratesIoReadRetryDelaySeconds, - retryContext: `crates.io existence retry for ${label}`, - }); - } catch (error) { - if (error instanceof RegistryHttpError && error.status === 404) { - return false; - } - throw error; - } -} - -async function crateVersionExists(crate, version) { - const cratePath = encodeURIComponent(crate); - const versionPath = encodeURIComponent(version); - const url = `${CRATES_IO_API.replace(/\/+$/u, "")}/crates/${cratePath}/${versionPath}`; - return cratesioUrlExists(url, `${crate} ${version}`); -} - -async function crateExists(crate) { - const cratePath = encodeURIComponent(crate); - const url = `${CRATES_IO_API.replace(/\/+$/u, "")}/crates/${cratePath}`; - return cratesioUrlExists(url, crate); -} - -async function npmPackageMetadata(packageName) { - const packagePath = encodeURIComponent(packageName); - const url = `${NPM_REGISTRY.replace(/\/+$/u, "")}/${packagePath}`; - try { - const data = await requestJson(url, packageName); - return data && !Array.isArray(data) && typeof data === "object" ? data : undefined; - } catch (error) { - if (error instanceof RegistryHttpError && error.status === 404) { - return undefined; - } - if (error instanceof RegistryHttpError) { - fail(`npm registry returned HTTP ${error.status} for ${packageName}`); - } - fail(`failed to query npm registry for ${packageName}: ${error}`); - } -} - -async function npmVersionExists(packageName, version) { - const data = await npmPackageMetadata(packageName); - if (data === undefined) { - return false; - } - const versions = data.versions; - return versions !== null && !Array.isArray(versions) && typeof versions === "object" && version in versions; -} - -async function npmPackageExists(packageName) { - return (await npmPackageMetadata(packageName)) !== undefined; -} - -function mavenCoordinatePaths(coordinate, version = undefined) { - const parts = coordinate.split(":"); - if (parts.length !== 2 || parts.some((part) => part.length === 0)) { - fail(`invalid Maven coordinate ${JSON.stringify(coordinate)}; expected group:artifact`); - } - const [group, artifact] = parts; - const groupPath = group.split(".").map((part) => encodeURIComponent(part)).join("/"); - const artifactPath = encodeURIComponent(artifact); - if (version === undefined) { - return `${MAVEN_CENTRAL_BASE.replace(/\/+$/u, "")}/${groupPath}/${artifactPath}/maven-metadata.xml`; - } - const versionPath = encodeURIComponent(version); - return `${MAVEN_CENTRAL_BASE.replace(/\/+$/u, "")}/${groupPath}/${artifactPath}/${versionPath}/${artifactPath}-${versionPath}.pom`; -} - -async function mavenVersionExists(coordinate, version) { - return urlExists(mavenCoordinatePaths(coordinate, version)); -} - -async function mavenCoordinateExists(coordinate) { - return urlExists(mavenCoordinatePaths(coordinate)); -} - -async function packageExists(pkg) { - if (pkg.kind === "crates") { - return crateVersionExists(pkg.name, pkg.version); - } - if (pkg.kind === "npm") { - return npmVersionExists(pkg.name, pkg.version); - } - if (pkg.kind === "maven") { - return mavenVersionExists(pkg.name, pkg.version); - } - fail(`unsupported registry package kind ${JSON.stringify(pkg.kind)}`); -} - -async function packageIdentityExists(pkg) { - if (pkg.kind === "crates") { - return crateExists(pkg.name); - } - if (pkg.kind === "npm") { - return npmPackageExists(pkg.name); - } - if (pkg.kind === "maven") { - return mavenCoordinateExists(pkg.name); - } - fail(`unsupported registry package kind ${JSON.stringify(pkg.kind)}`); -} - -async function queryProductPublication(product, { versionOverride = undefined, registryKind = undefined, retries = 0, retryDelay = 0 } = {}) { - const packages = await productRegistryPackages(product, { versionOverride, registryKind }); - const attempts = Math.max(1, retries + 1); - let lastMissing = []; - let lastPublished = []; - for (let attempt = 0; attempt < attempts; attempt += 1) { - const missing = []; - const published = []; - for (const pkg of packages) { - if (await packageExists(pkg)) { - published.push(pkg); - } else { - missing.push(pkg); - } - } - lastMissing = missing; - lastPublished = published; - if (missing.length === 0 || attempt === attempts - 1) { - break; - } - await boundedRegistrySleep(retryDelay, `publication visibility retry for ${product}`); - } - return { packages, missing: lastMissing, published: lastPublished }; -} - -async function productIdentityStatus(product, { registryKind = undefined } = {}) { - const packages = await productRegistryPackages(product, { registryKind }); - const present = []; - const missing = []; - for (const pkg of packages) { - if (await packageIdentityExists(pkg)) { - present.push(pkg); - } else { - missing.push(pkg); - } - } - return { packages, present, missing }; -} - -function parseFlags(argv) { - const flags = new Map(); - const positionals = []; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (!arg.startsWith("--")) { - positionals.push(arg); - continue; - } - const eq = arg.indexOf("="); - if (eq !== -1) { - flags.set(arg.slice(2, eq), arg.slice(eq + 1)); - continue; - } - const name = arg.slice(2); - if (["require-published", "require-unpublished", "report", "require-identities", "report-identities", "json"].includes(name)) { - flags.set(name, true); - continue; - } - if (index + 1 >= argv.length) { - fail(`${arg} requires a value`); - } - flags.set(name, argv[index + 1]); - index += 1; - } - return { flags, positionals }; -} - -function flagString(flags, name, { required = false } = {}) { - const value = flags.get(name); - if (value === undefined) { - if (required) { - fail(`--${name} is required`); - } - return undefined; - } - if (value === true) { - fail(`--${name} requires a value`); - } - return value; -} - -function flagNumber(flags, name, defaultValue) { - const raw = flagString(flags, name); - if (raw === undefined) { - return defaultValue; - } - const value = Number(raw); - if (!Number.isFinite(value)) { - fail(`--${name} must be numeric`); - } - return value; -} - -function activatePublicationLockFlag(flags) { - const publicationLock = flagString(flags, "publication-lock"); - if (publicationLock !== undefined) { - process.env.OLIPHAUNT_PUBLICATION_LOCK = path.resolve(ROOT, publicationLock); - } -} - -async function parseProducts(flags) { - const rawProducts = flagString(flags, "products-json"); - const product = flagString(flags, "product"); - if (Boolean(rawProducts) === Boolean(product)) { - fail("pass exactly one of --product or --products-json"); - } - if (product !== undefined) { - return [product]; - } - let value; - try { - value = JSON.parse(rawProducts); - } catch (error) { - fail(`--products-json must be valid JSON: ${error.message}`); - } - if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) { - fail("--products-json must be a JSON string list"); - } - const known = new Set(await productIds()); - const unknown = value.filter((item) => !known.has(item)).sort(); - if (unknown.length > 0) { - fail(`unknown release products: ${unknown.join(", ")}`); - } - return value; -} - -function serializeQueryResult(result) { - return { - packages: result.packages.map((pkg) => ({ ...pkg, label: packageLabel(pkg) })), - missing: result.missing.map((pkg) => ({ ...pkg, label: packageLabel(pkg) })), - published: result.published.map((pkg) => ({ ...pkg, label: packageLabel(pkg) })), - }; -} - -function printJson(value) { - console.log(JSON.stringify(value, null, 2)); -} - -async function runProductCrates(flags) { - const product = flagString(flags, "product", { required: true }); - const version = flagString(flags, "version") ?? (await currentVersion(product)); - printJson({ product, version, crates: await productCrates(product) }); -} - -async function runCrateVersionExists(flags) { - const crate = flagString(flags, "crate", { required: true }); - const version = flagString(flags, "version", { required: true }); - printJson({ crate, version, exists: await crateVersionExists(crate, version) }); -} - -async function runCrateExists(flags) { - const crate = flagString(flags, "crate", { required: true }); - printJson({ crate, exists: await crateExists(crate) }); -} - -async function runQueryProductPublication(flags) { - const product = flagString(flags, "product", { required: true }); - const registryKind = flagString(flags, "registry-kind"); - const versionOverride = flagString(flags, "version"); - const retries = flagNumber(flags, "retries", 0); - const retryDelay = flagNumber(flags, "retry-delay", 0); - if (retries < 0 || retryDelay < 0) { - fail("--retries and --retry-delay must be non-negative"); - } - printJson(serializeQueryResult(await queryProductPublication(product, { - versionOverride, - registryKind, - retries, - retryDelay, - }))); -} - -async function runProductRegistryPackages(flags) { - const product = flagString(flags, "product", { required: true }); - const registryKind = flagString(flags, "registry-kind"); - const versionOverride = flagString(flags, "version"); - printJson({ - packages: (await productRegistryPackages(product, { versionOverride, registryKind })).map((pkg) => ({ - ...pkg, - label: packageLabel(pkg), - })), - }); -} - -async function runPublicationCli(flags) { - const versionOverride = flagString(flags, "version"); - const registryKind = flagString(flags, "registry-kind"); - const retries = flagNumber(flags, "retries", 0); - const retryDelay = flagNumber(flags, "retry-delay", 0); - if (versionOverride !== undefined && flagString(flags, "product") === undefined) { - fail("--version can only be used with --product"); - } - if (retries < 0 || retryDelay < 0) { - fail("--retries and --retry-delay must be non-negative"); - } - const modes = ["require-published", "require-unpublished", "report", "require-identities", "report-identities"].filter((mode) => flags.has(mode)); - if (modes.length !== 1) { - fail("pass exactly one publication mode"); - } - const products = await parseProducts(flags); - const mode = modes[0]; - if (mode === "require-identities") { - const missingMessages = []; - for (const product of products) { - const status = await productIdentityStatus(product, { registryKind }); - if (status.packages.length === 0) { - console.log(`${product} has no external registry package identities to check`); - } else if (status.missing.length > 0) { - missingMessages.push(`${product}: ${status.missing.map(identityLabel).join(", ")}`); - } else { - console.log(`${product} registry identity check passed: ${status.packages.map(identityLabel).join(", ")}`); - } - } - if (missingMessages.length > 0) { - fail(`registry package identities are missing:\n - ${missingMessages.join("\n - ")}`); - } - return; - } - for (const product of products) { - if (mode === "report-identities") { - const status = await productIdentityStatus(product, { registryKind }); - if (status.packages.length === 0) { - console.log(`${product} has no external registry package identities to check`); - } - if (status.present.length > 0) { - console.log(`${product} registry identities present: ${status.present.map(identityLabel).join(", ")}`); - } - if (status.missing.length > 0) { - console.log(`${product} registry identities missing: ${status.missing.map(identityLabel).join(", ")}`); - } - continue; - } - const result = await queryProductPublication(product, { - versionOverride, - registryKind, - retries, - retryDelay, - }); - if (result.packages.length === 0) { - console.log(`${product} has no external registry packages to check`); - continue; - } - if (mode === "report") { - if (result.published.length > 0) { - console.log(`${product} registry versions already present: ${result.published.map(packageLabel).join(", ")}`); - } - if (result.missing.length > 0) { - console.log(`${product} registry versions not yet present: ${result.missing.map(packageLabel).join(", ")}`); - } - continue; - } - if (mode === "require-published" && result.missing.length > 0) { - fail(`${product} registry publication is missing: ${result.missing.map(packageLabel).join(", ")}`); - } - if (mode === "require-unpublished" && result.published.length > 0) { - fail(`${product} version is already published in public registries: ${result.published.map(packageLabel).join(", ")}`); - } - const state = mode === "require-published" ? "published" : "unpublished"; - console.log(`${product} registry ${state} check passed: ${result.packages.map(packageLabel).join(", ")}`); - } -} - -async function main(argv) { - const subcommands = new Map([ - ["product-crates", runProductCrates], - ["crate-version-exists", runCrateVersionExists], - ["crate-exists", runCrateExists], - ["query-product-publication", runQueryProductPublication], - ["product-registry-packages", runProductRegistryPackages], - ]); - const first = argv[0]; - if (subcommands.has(first)) { - const { flags, positionals } = parseFlags(argv.slice(1)); - activatePublicationLockFlag(flags); - if (positionals.length > 0) { - fail(`unexpected positional arguments: ${positionals.join(", ")}`); - } - await subcommands.get(first)(flags); - return; - } - const { flags, positionals } = parseFlags(argv); - activatePublicationLockFlag(flags); - if (positionals.length > 0) { - fail(`unexpected positional arguments: ${positionals.join(", ")}`); - } - await runPublicationCli(flags); -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/check_registry_publication.mts b/tools/release/check_registry_publication.mts new file mode 100644 index 000000000..148679ee1 --- /dev/null +++ b/tools/release/check_registry_publication.mts @@ -0,0 +1,1003 @@ +#!/usr/bin/env bun +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { currentVersion } from './product-version.mts'; +import { loadPublicationCatalog, REGISTRY_KIND_TO_ECOSYSTEM } from './publication-catalog.mts'; +import { loadPublicationLock, lockedCarriers } from './publication-lock.mts'; +import { + retryAfterSeconds, + registryRetryDelaySeconds, + registryStatusRetryable, +} from './registry-http-retry.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); +const CRATES_IO_API = process.env.CRATES_IO_API || 'https://crates.io/api/v1'; +const NPM_REGISTRY = process.env.NPM_REGISTRY || 'https://registry.npmjs.org'; +const MAVEN_CENTRAL_BASE = process.env.MAVEN_CENTRAL_BASE || 'https://repo1.maven.org/maven2'; +const REQUEST_ATTEMPTS = Math.max( + 1, + Number.parseInt(process.env.OLIPHAUNT_REGISTRY_QUERY_ATTEMPTS || '8', 10) || 8, +); +const REQUEST_RETRY_DELAY_SECONDS = Math.max( + 0, + Number.parseFloat(process.env.OLIPHAUNT_REGISTRY_QUERY_RETRY_DELAY || '1.0') || 0, +); +const REQUEST_TIMEOUT_MS = 20_000; +const DEADLINE_CLEANUP_RESERVE_MS = 5_000; +export const CRATES_IO_READ_INTERVAL_SECONDS = 1; +export const CRATES_IO_READ_RETRY_BUDGET_SECONDS = 10 * 60; +export const CRATES_IO_RATE_LIMIT_FALLBACK_SECONDS = 60; +const MAX_REGISTRY_JSON_BYTES = 8 * 1024 * 1024; +const REGISTRY_TARGETS = new Set(['crates-io', 'npm', 'maven-central']); +const REGISTRY_KINDS = new Set(['crates', 'npm', 'maven']); +const REGISTRY_KIND_BY_ECOSYSTEM = new Map( + Object.entries(REGISTRY_KIND_TO_ECOSYSTEM).map(([kind, ecosystem]) => [ecosystem, kind]), +); +const USER_AGENT = 'oliphaunt-release-check (https://github.com/f0rr0/oliphaunt)'; + +const caches = { + releaseConfig: undefined, + packageByProduct: undefined, + publicationLock: undefined, +}; + +class RegistryHttpError extends Error { + constructor(status, label) { + super(`HTTP ${status} for ${label}`); + this.status = status; + } +} + +class RegistryResponseError extends Error {} + +function registryDeadlineRemainingMilliseconds(context, nowImpl = () => Date.now()) { + const raw = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH?.trim(); + if (!raw) return null; + if (!/^[1-9][0-9]*$/u.test(raw)) { + throw new RegistryResponseError( + 'REGISTRY_MUTATION_DEADLINE_EPOCH must be a positive Unix timestamp', + ); + } + const deadlineMilliseconds = Number(raw) * 1000; + if (!Number.isSafeInteger(deadlineMilliseconds)) { + throw new RegistryResponseError( + 'REGISTRY_MUTATION_DEADLINE_EPOCH exceeds the safe timestamp range', + ); + } + const remaining = deadlineMilliseconds - nowImpl() - DEADLINE_CLEANUP_RESERVE_MS; + if (remaining <= 0) { + throw new RegistryResponseError( + `${context} refused because the shared registry mutation deadline has been reached`, + ); + } + return remaining; +} + +export function registryRequestTimeoutMilliseconds(context, { nowImpl = () => Date.now() } = {}) { + const remaining = registryDeadlineRemainingMilliseconds(context, nowImpl); + return remaining === null + ? REQUEST_TIMEOUT_MS + : Math.max(1, Math.min(REQUEST_TIMEOUT_MS, remaining)); +} + +export async function boundedRegistrySleep( + seconds, + context, + { + nowImpl = () => Date.now(), + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + } = {}, +) { + if (!Number.isFinite(seconds) || seconds < 0) { + throw new RegistryResponseError(`${context} requested an invalid registry retry delay`); + } + const milliseconds = seconds * 1000; + const remaining = registryDeadlineRemainingMilliseconds(context, nowImpl); + if (remaining !== null && milliseconds >= remaining) { + throw new RegistryResponseError( + `${context} cannot wait ${Math.ceil(seconds)}s before the shared registry mutation deadline`, + ); + } + if (milliseconds > 0) await sleepImpl(milliseconds); +} + +export async function readBoundedRegistryJson(response, label, maximum = MAX_REGISTRY_JSON_BYTES) { + if (!Number.isSafeInteger(maximum) || maximum < 1) { + throw new RegistryResponseError('registry response byte limit must be a positive safe integer'); + } + const contentLength = response.headers?.get?.('content-length'); + if (contentLength !== null && contentLength !== undefined) { + const declared = Number(contentLength); + if (!Number.isSafeInteger(declared) || declared < 0) { + await response.body?.cancel?.().catch(() => {}); + throw new RegistryResponseError(`${label} returned an invalid Content-Length`); + } + if (declared > maximum) { + await response.body?.cancel?.().catch(() => {}); + throw new RegistryResponseError(`${label} response exceeds ${maximum} bytes`); + } + } + const reader = response.body?.getReader?.(); + let bytes; + if (reader === undefined) { + bytes = Buffer.from(await response.arrayBuffer()); + if (bytes.length > maximum) { + throw new RegistryResponseError(`${label} response exceeds ${maximum} bytes`); + } + } else { + const chunks = []; + let size = 0; + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > maximum) { + await reader.cancel().catch(() => {}); + throw new RegistryResponseError(`${label} response exceeds ${maximum} bytes`); + } + chunks.push(Buffer.from(value)); + } + } finally { + reader.releaseLock(); + } + bytes = Buffer.concat(chunks, size); + } + try { + return JSON.parse(bytes.toString('utf8')); + } catch (error) { + throw new RegistryResponseError(`${label} returned invalid JSON: ${error.message}`); + } +} + +function fail(message) { + console.error(`check_registry_publication.mts: ${message}`); + process.exit(1); +} + +function rel(file) { + const relative = path.relative(ROOT, file); + return relative.startsWith('..') || path.isAbsolute(relative) + ? file + : relative.split(path.sep).join('/'); +} + +async function readJson(file) { + let text; + try { + text = await readFile(file, 'utf8'); + } catch { + fail(`missing ${rel(file)}`); + } + const value = JSON.parse(text); + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(`${rel(file)} must contain a JSON object`); + } + return value; +} + +async function releaseConfig() { + if (caches.releaseConfig === undefined) { + caches.releaseConfig = await readJson(path.join(ROOT, 'release-please-config.json')); + } + return caches.releaseConfig; +} + +function assertRelative(value, context) { + if (typeof value !== 'string' || value.length === 0) { + fail(`${context} must be a non-empty string`); + } + const parts = value.split(/[\\/]/u); + if (path.isAbsolute(value) || /^[A-Za-z]:[\\/]/u.test(value) || parts.includes('..')) { + fail(`${context} must stay inside the repository: ${JSON.stringify(value)}`); + } + return value; +} + +async function packageByProduct() { + if (caches.packageByProduct !== undefined) { + return caches.packageByProduct; + } + const config = await releaseConfig(); + const packages = config.packages; + if (packages === null || Array.isArray(packages) || typeof packages !== 'object') { + fail('release-please-config.json must define packages'); + } + const byProduct = new Map(); + for (const [rawPackagePath, packageConfig] of Object.entries(packages)) { + if ( + packageConfig === null || + Array.isArray(packageConfig) || + typeof packageConfig !== 'object' + ) { + fail(`${rawPackagePath} release-please config must be an object`); + } + const component = packageConfig.component; + if (typeof component !== 'string' || component.length === 0) { + fail(`${rawPackagePath}.component must be a non-empty string`); + } + if (byProduct.has(component)) { + fail(`duplicate release-please component ${component}`); + } + const packagePath = assertRelative(rawPackagePath, `${component}.packagePath`); + byProduct.set(component, { packagePath, packageConfig }); + } + caches.packageByProduct = byProduct; + return byProduct; +} + +async function productIds() { + return [...(await packageByProduct()).keys()]; +} + +async function productCrates(product) { + const catalog = loadPublicationCatalog('check_registry_publication.mts', { products: [product] }); + const productRow = catalog.products.find((row) => row.id === product); + if (!productRow?.publishTargets.includes('crates-io')) { + fail(`${product} does not publish to crates.io`); + } + const crates = catalog.carriers + .filter((carrier) => carrier.product === product && carrier.ecosystem === 'cargo') + .map((carrier) => carrier.name); + if (crates.length === 0) { + fail(`${product} does not declare Cargo registry packages`); + } + const duplicates = [ + ...new Set(crates.filter((crate, index) => crates.indexOf(crate) !== index)), + ].sort(); + if (duplicates.length > 0) { + fail(`${product} declares duplicate Cargo registry packages: ${duplicates.join(', ')}`); + } + return crates.sort(); +} + +function packageLabel(pkg) { + return `${pkg.kind}:${pkg.name}@${pkg.version}`; +} + +function identityLabel(pkg) { + return `${pkg.kind}:${pkg.name}`; +} + +export function productRegistryPackagesFromLock( + publicationLock, + product, + { versionOverride = undefined, registryKind = undefined } = {}, +) { + const productRow = publicationLock.products.find((row) => row.id === product); + if (productRow === undefined) { + fail(`publication lock does not contain release product ${JSON.stringify(product)}`); + } + if (versionOverride !== undefined && versionOverride !== productRow.version) { + fail( + `${product} requested version ${versionOverride} does not match frozen publication-lock version ${productRow.version}`, + ); + } + const ecosystemByKind = new Map([ + ['crates', 'cargo'], + ['npm', 'npm'], + ['maven', 'maven'], + ]); + if (registryKind !== undefined && !ecosystemByKind.has(registryKind)) { + fail(`unsupported registry kind ${JSON.stringify(registryKind)}`); + } + const ecosystem = registryKind === undefined ? undefined : ecosystemByKind.get(registryKind); + const kindByEcosystem = new Map([ + ['cargo', 'crates'], + ['npm', 'npm'], + ['maven', 'maven'], + ]); + const packages = lockedCarriers(publicationLock, { product, ecosystem }).map((carrier) => ({ + kind: kindByEcosystem.get(carrier.ecosystem), + name: carrier.name, + version: carrier.version, + })); + if (registryKind !== undefined && packages.length === 0) { + fail(`${product} has no ${registryKind} registry packages in the publication lock`); + } + return packages; +} + +export async function productRegistryPackages( + product, + { versionOverride = undefined, registryKind = undefined } = {}, +) { + const publicationLockPath = process.env.OLIPHAUNT_PUBLICATION_LOCK; + if (publicationLockPath) { + if (caches.publicationLock === undefined) { + caches.publicationLock = loadPublicationLock(path.resolve(ROOT, publicationLockPath)); + } + return productRegistryPackagesFromLock(caches.publicationLock, product, { + versionOverride, + registryKind, + }); + } + const version = versionOverride || (await currentVersion(product)); + const catalog = loadPublicationCatalog('check_registry_publication.mts', { products: [product] }); + const productRow = catalog.products.find((row) => row.id === product); + const publishTargets = new Set(productRow?.publishTargets ?? []); + const expectedKinds = new Map([ + ['crates-io', 'crates'], + ['npm', 'npm'], + ['maven-central', 'maven'], + ]); + const packages = catalog.carriers + .filter((carrier) => carrier.product === product) + .map((carrier) => ({ + kind: REGISTRY_KIND_BY_ECOSYSTEM.get(carrier.ecosystem), + name: carrier.name, + version, + })); + const targetByKind = new Map([...expectedKinds].map(([target, kind]) => [kind, target])); + const stalePackages = packages + .filter((pkg) => !publishTargets.has(targetByKind.get(pkg.kind))) + .map(identityLabel) + .sort(); + if (stalePackages.length > 0) { + fail( + `${product} publication catalog contains entries without a matching registry publish target: ${stalePackages.join(', ')}`, + ); + } + const duplicateIdentities = packages + .map(identityLabel) + .filter((identity, index, identities) => identities.indexOf(identity) !== index); + if (duplicateIdentities.length > 0) { + fail( + `${product}.registry_packages contains duplicate identities: ${[...new Set(duplicateIdentities)].sort().join(', ')}`, + ); + } + const missingKinds = []; + for (const [target, kind] of expectedKinds.entries()) { + if (publishTargets.has(target) && !packages.some((pkg) => pkg.kind === kind)) { + missingKinds.push(kind); + } + } + if (missingKinds.length > 0) { + const selectedTargets = [...publishTargets] + .filter((target) => REGISTRY_TARGETS.has(target)) + .sort(); + fail( + `${product} publishes to ${JSON.stringify(selectedTargets)} but is missing registry_packages entries for: ${missingKinds.join(', ')}`, + ); + } + let filtered = packages; + if (registryKind !== undefined) { + if (!REGISTRY_KINDS.has(registryKind)) { + fail(`unsupported registry kind ${JSON.stringify(registryKind)}`); + } + filtered = packages.filter((pkg) => pkg.kind === registryKind); + if (filtered.length === 0) { + fail(`${product} has no ${registryKind} registry packages to check`); + } + } + return filtered; +} + +async function requestJson(url, label, { fetchImpl = fetch } = {}) { + let lastError; + for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { + let retryHeaders; + try { + const response = await fetchImpl(url, { + headers: { + Accept: 'application/json', + 'User-Agent': USER_AGENT, + }, + redirect: 'follow', + signal: AbortSignal.timeout( + registryRequestTimeoutMilliseconds(`registry request for ${label}`), + ), + }); + if (response.ok) { + return await readBoundedRegistryJson(response, label); + } + const error = new RegistryHttpError(response.status, label); + const headers = response.headers; + await response.body?.cancel?.().catch(() => {}); + if (!registryStatusRetryable(response.status)) { + throw error; + } + retryHeaders = headers; + lastError = error; + } catch (error) { + lastError = error; + if (error instanceof RegistryResponseError) { + throw error; + } + if (error instanceof RegistryHttpError && !registryStatusRetryable(error.status)) { + throw error; + } + } + if (attempt + 1 < REQUEST_ATTEMPTS) { + await boundedRegistrySleep( + registryRetryDelaySeconds({ + headers: retryHeaders, + attempt, + baseSeconds: REQUEST_RETRY_DELAY_SECONDS, + }), + `registry retry for ${label}`, + ); + } + } + throw lastError ?? new Error(`failed to query ${label}`); +} + +async function urlExistsViaGet(url, options = {}) { + return urlExists(url, { ...options, method: 'GET', allowMethodFallback: false }); +} + +export function cratesIoReadRetryDelaySeconds({ headers, status, attempt, now = Date.now() }) { + if (status === 429) { + const requested = retryAfterSeconds(headers, now); + if (requested !== null) return requested; + return Math.min(300, CRATES_IO_RATE_LIMIT_FALLBACK_SECONDS * 2 ** attempt); + } + return registryRetryDelaySeconds({ headers, attempt, now }); +} + +export async function urlExists( + url, + { + method = 'HEAD', + allowMethodFallback = true, + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + nowImpl = () => Date.now(), + beforeRequestSeconds = 0, + retryBudgetSeconds = null, + retryDelayImpl = ({ headers, attempt, now }) => + registryRetryDelaySeconds({ + headers, + attempt, + baseSeconds: REQUEST_RETRY_DELAY_SECONDS, + now, + }), + retryContext = `registry retry for ${url}`, + } = {}, +) { + let lastError; + let retryDelaySpentSeconds = 0; + for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { + let retryHeaders; + let retryStatus; + try { + await boundedRegistrySleep(beforeRequestSeconds, `registry read pacing for ${url}`, { + nowImpl, + sleepImpl, + }); + const response = await fetchImpl(url, { + method, + headers: { + Accept: 'application/json', + 'User-Agent': USER_AGENT, + }, + redirect: 'follow', + signal: AbortSignal.timeout( + registryRequestTimeoutMilliseconds(`registry request for ${url}`, { nowImpl }), + ), + }); + if (response.ok) { + await response.body?.cancel?.().catch(() => {}); + return true; + } + if (response.status === 404) { + await response.body?.cancel?.().catch(() => {}); + return false; + } + if (response.status === 405 && method === 'HEAD' && allowMethodFallback) { + await response.body?.cancel?.().catch(() => {}); + return urlExistsViaGet(url, { + fetchImpl, + sleepImpl, + nowImpl, + beforeRequestSeconds, + retryBudgetSeconds, + retryDelayImpl, + retryContext, + }); + } + const error = new RegistryHttpError(response.status, url); + const headers = response.headers; + await response.body?.cancel?.().catch(() => {}); + if (!registryStatusRetryable(response.status)) { + fail(`registry returned HTTP ${response.status} for ${url}`); + } + retryHeaders = headers; + retryStatus = response.status; + lastError = error; + } catch (error) { + lastError = error; + if (error instanceof RegistryResponseError) { + throw error; + } + if (error instanceof RegistryHttpError && !registryStatusRetryable(error.status)) { + fail(`registry returned HTTP ${error.status} for ${url}`); + } + } + if (attempt + 1 < REQUEST_ATTEMPTS) { + const delaySeconds = retryDelayImpl({ + headers: retryHeaders, + status: retryStatus, + attempt, + now: nowImpl(), + }); + if (!Number.isFinite(delaySeconds) || delaySeconds < 0) { + throw new RegistryResponseError(`${retryContext} requested an invalid delay`); + } + if ( + retryBudgetSeconds !== null && + delaySeconds > retryBudgetSeconds - retryDelaySpentSeconds + ) { + throw new RegistryResponseError( + `${retryContext} exceeds its bounded ${retryBudgetSeconds}s retry-delay budget`, + ); + } + retryDelaySpentSeconds += delaySeconds; + await boundedRegistrySleep(delaySeconds, retryContext, { nowImpl, sleepImpl }); + } + } + if (lastError instanceof RegistryHttpError) { + fail(`registry returned HTTP ${lastError.status} for ${url}`); + } + fail(`failed to query registry URL ${url}: ${lastError}`); +} + +export async function cratesioUrlExists( + url, + label, + { + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + nowImpl = () => Date.now(), + } = {}, +) { + try { + return await urlExists(url, { + method: 'GET', + allowMethodFallback: false, + fetchImpl, + sleepImpl, + nowImpl, + beforeRequestSeconds: CRATES_IO_READ_INTERVAL_SECONDS, + retryBudgetSeconds: CRATES_IO_READ_RETRY_BUDGET_SECONDS, + retryDelayImpl: cratesIoReadRetryDelaySeconds, + retryContext: `crates.io existence retry for ${label}`, + }); + } catch (error) { + if (error instanceof RegistryHttpError && error.status === 404) { + return false; + } + throw error; + } +} + +async function crateVersionExists(crate, version) { + const cratePath = encodeURIComponent(crate); + const versionPath = encodeURIComponent(version); + const url = `${CRATES_IO_API.replace(/\/+$/u, '')}/crates/${cratePath}/${versionPath}`; + return cratesioUrlExists(url, `${crate} ${version}`); +} + +async function crateExists(crate) { + const cratePath = encodeURIComponent(crate); + const url = `${CRATES_IO_API.replace(/\/+$/u, '')}/crates/${cratePath}`; + return cratesioUrlExists(url, crate); +} + +async function npmPackageMetadata(packageName) { + const packagePath = encodeURIComponent(packageName); + const url = `${NPM_REGISTRY.replace(/\/+$/u, '')}/${packagePath}`; + try { + const data = await requestJson(url, packageName); + return data && !Array.isArray(data) && typeof data === 'object' ? data : undefined; + } catch (error) { + if (error instanceof RegistryHttpError && error.status === 404) { + return undefined; + } + if (error instanceof RegistryHttpError) { + fail(`npm registry returned HTTP ${error.status} for ${packageName}`); + } + fail(`failed to query npm registry for ${packageName}: ${error}`); + } +} + +export async function npmPublishedVersion(packageName, version) { + const data = await npmPackageMetadata(packageName); + return data?.versions?.[version]; +} + +async function npmVersionExists(packageName, version) { + return (await npmPublishedVersion(packageName, version)) !== undefined; +} + +async function npmPackageExists(packageName) { + return (await npmPackageMetadata(packageName)) !== undefined; +} + +function mavenCoordinatePaths(coordinate, version = undefined) { + const parts = coordinate.split(':'); + if (parts.length !== 2 || parts.some((part) => part.length === 0)) { + fail(`invalid Maven coordinate ${JSON.stringify(coordinate)}; expected group:artifact`); + } + const [group, artifact] = parts; + const groupPath = group + .split('.') + .map((part) => encodeURIComponent(part)) + .join('/'); + const artifactPath = encodeURIComponent(artifact); + if (version === undefined) { + return `${MAVEN_CENTRAL_BASE.replace(/\/+$/u, '')}/${groupPath}/${artifactPath}/maven-metadata.xml`; + } + const versionPath = encodeURIComponent(version); + return `${MAVEN_CENTRAL_BASE.replace(/\/+$/u, '')}/${groupPath}/${artifactPath}/${versionPath}/${artifactPath}-${versionPath}.pom`; +} + +async function mavenVersionExists(coordinate, version) { + return urlExists(mavenCoordinatePaths(coordinate, version)); +} + +async function mavenCoordinateExists(coordinate) { + return urlExists(mavenCoordinatePaths(coordinate)); +} + +async function packageExists(pkg) { + if (pkg.kind === 'crates') { + return crateVersionExists(pkg.name, pkg.version); + } + if (pkg.kind === 'npm') { + return npmVersionExists(pkg.name, pkg.version); + } + if (pkg.kind === 'maven') { + return mavenVersionExists(pkg.name, pkg.version); + } + fail(`unsupported registry package kind ${JSON.stringify(pkg.kind)}`); +} + +async function packageIdentityExists(pkg) { + if (pkg.kind === 'crates') { + return crateExists(pkg.name); + } + if (pkg.kind === 'npm') { + return npmPackageExists(pkg.name); + } + if (pkg.kind === 'maven') { + return mavenCoordinateExists(pkg.name); + } + fail(`unsupported registry package kind ${JSON.stringify(pkg.kind)}`); +} + +export async function queryProductPublication( + product, + { versionOverride = undefined, registryKind = undefined, retries = 0, retryDelay = 0 } = {}, +) { + const packages = await productRegistryPackages(product, { versionOverride, registryKind }); + return queryRegistryPackages(packages, { retries, retryDelay }); +} + +export async function queryRegistryPackages(packages, { retries = 0, retryDelay = 0 } = {}) { + const attempts = Math.max(1, retries + 1); + let lastMissing = []; + let lastPublished = []; + for (let attempt = 0; attempt < attempts; attempt += 1) { + const missing = []; + const published = []; + for (const pkg of packages) { + if (await packageExists(pkg)) { + published.push(pkg); + } else { + missing.push(pkg); + } + } + lastMissing = missing; + lastPublished = published; + if (missing.length === 0 || attempt === attempts - 1) { + break; + } + await boundedRegistrySleep(retryDelay, 'publication visibility retry'); + } + return { packages, missing: lastMissing, published: lastPublished }; +} + +async function productIdentityStatus(product, { registryKind = undefined } = {}) { + const packages = await productRegistryPackages(product, { registryKind }); + const present = []; + const missing = []; + for (const pkg of packages) { + if (await packageIdentityExists(pkg)) { + present.push(pkg); + } else { + missing.push(pkg); + } + } + return { packages, present, missing }; +} + +function parseFlags(argv) { + const flags = new Map(); + const positionals = []; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (!arg.startsWith('--')) { + positionals.push(arg); + continue; + } + const eq = arg.indexOf('='); + if (eq !== -1) { + flags.set(arg.slice(2, eq), arg.slice(eq + 1)); + continue; + } + const name = arg.slice(2); + if ( + [ + 'require-published', + 'require-unpublished', + 'report', + 'require-identities', + 'report-identities', + 'json', + ].includes(name) + ) { + flags.set(name, true); + continue; + } + if (index + 1 >= argv.length) { + fail(`${arg} requires a value`); + } + flags.set(name, argv[index + 1]); + index += 1; + } + return { flags, positionals }; +} + +function flagString(flags, name, { required = false } = {}) { + const value = flags.get(name); + if (value === undefined) { + if (required) { + fail(`--${name} is required`); + } + return undefined; + } + if (value === true) { + fail(`--${name} requires a value`); + } + return value; +} + +function flagNumber(flags, name, defaultValue) { + const raw = flagString(flags, name); + if (raw === undefined) { + return defaultValue; + } + const value = Number(raw); + if (!Number.isFinite(value)) { + fail(`--${name} must be numeric`); + } + return value; +} + +function activatePublicationLockFlag(flags) { + const publicationLock = flagString(flags, 'publication-lock'); + if (publicationLock !== undefined) { + process.env.OLIPHAUNT_PUBLICATION_LOCK = path.resolve(ROOT, publicationLock); + } +} + +async function parseProducts(flags) { + const rawProducts = flagString(flags, 'products-json'); + const product = flagString(flags, 'product'); + if (Boolean(rawProducts) === Boolean(product)) { + fail('pass exactly one of --product or --products-json'); + } + if (product !== undefined) { + return [product]; + } + let value; + try { + value = JSON.parse(rawProducts); + } catch (error) { + fail(`--products-json must be valid JSON: ${error.message}`); + } + if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) { + fail('--products-json must be a JSON string list'); + } + const known = new Set(await productIds()); + const unknown = value.filter((item) => !known.has(item)).sort(); + if (unknown.length > 0) { + fail(`unknown release products: ${unknown.join(', ')}`); + } + return value; +} + +function serializeQueryResult(result) { + return { + packages: result.packages.map((pkg) => ({ ...pkg, label: packageLabel(pkg) })), + missing: result.missing.map((pkg) => ({ ...pkg, label: packageLabel(pkg) })), + published: result.published.map((pkg) => ({ ...pkg, label: packageLabel(pkg) })), + }; +} + +function printJson(value) { + console.log(JSON.stringify(value, null, 2)); +} + +async function runProductCrates(flags) { + const product = flagString(flags, 'product', { required: true }); + const version = flagString(flags, 'version') ?? (await currentVersion(product)); + printJson({ product, version, crates: await productCrates(product) }); +} + +async function runCrateVersionExists(flags) { + const crate = flagString(flags, 'crate', { required: true }); + const version = flagString(flags, 'version', { required: true }); + printJson({ crate, version, exists: await crateVersionExists(crate, version) }); +} + +async function runCrateExists(flags) { + const crate = flagString(flags, 'crate', { required: true }); + printJson({ crate, exists: await crateExists(crate) }); +} + +async function runQueryProductPublication(flags) { + const product = flagString(flags, 'product', { required: true }); + const registryKind = flagString(flags, 'registry-kind'); + const versionOverride = flagString(flags, 'version'); + const retries = flagNumber(flags, 'retries', 0); + const retryDelay = flagNumber(flags, 'retry-delay', 0); + if (retries < 0 || retryDelay < 0) { + fail('--retries and --retry-delay must be non-negative'); + } + printJson( + serializeQueryResult( + await queryProductPublication(product, { + versionOverride, + registryKind, + retries, + retryDelay, + }), + ), + ); +} + +async function runProductRegistryPackages(flags) { + const product = flagString(flags, 'product', { required: true }); + const registryKind = flagString(flags, 'registry-kind'); + const versionOverride = flagString(flags, 'version'); + printJson({ + packages: (await productRegistryPackages(product, { versionOverride, registryKind })).map( + (pkg) => ({ + ...pkg, + label: packageLabel(pkg), + }), + ), + }); +} + +async function runPublicationCli(flags) { + const versionOverride = flagString(flags, 'version'); + const registryKind = flagString(flags, 'registry-kind'); + const retries = flagNumber(flags, 'retries', 0); + const retryDelay = flagNumber(flags, 'retry-delay', 0); + if (versionOverride !== undefined && flagString(flags, 'product') === undefined) { + fail('--version can only be used with --product'); + } + if (retries < 0 || retryDelay < 0) { + fail('--retries and --retry-delay must be non-negative'); + } + const modes = [ + 'require-published', + 'require-unpublished', + 'report', + 'require-identities', + 'report-identities', + ].filter((mode) => flags.has(mode)); + if (modes.length !== 1) { + fail('pass exactly one publication mode'); + } + const products = await parseProducts(flags); + const mode = modes[0]; + if (mode === 'require-identities') { + const missingMessages = []; + for (const product of products) { + const status = await productIdentityStatus(product, { registryKind }); + if (status.packages.length === 0) { + console.log(`${product} has no external registry package identities to check`); + } else if (status.missing.length > 0) { + missingMessages.push(`${product}: ${status.missing.map(identityLabel).join(', ')}`); + } else { + console.log( + `${product} registry identity check passed: ${status.packages.map(identityLabel).join(', ')}`, + ); + } + } + if (missingMessages.length > 0) { + fail(`registry package identities are missing:\n - ${missingMessages.join('\n - ')}`); + } + return; + } + for (const product of products) { + if (mode === 'report-identities') { + const status = await productIdentityStatus(product, { registryKind }); + if (status.packages.length === 0) { + console.log(`${product} has no external registry package identities to check`); + } + if (status.present.length > 0) { + console.log( + `${product} registry identities present: ${status.present.map(identityLabel).join(', ')}`, + ); + } + if (status.missing.length > 0) { + console.log( + `${product} registry identities missing: ${status.missing.map(identityLabel).join(', ')}`, + ); + } + continue; + } + const result = await queryProductPublication(product, { + versionOverride, + registryKind, + retries, + retryDelay, + }); + if (result.packages.length === 0) { + console.log(`${product} has no external registry packages to check`); + continue; + } + if (mode === 'report') { + if (result.published.length > 0) { + console.log( + `${product} registry versions already present: ${result.published.map(packageLabel).join(', ')}`, + ); + } + if (result.missing.length > 0) { + console.log( + `${product} registry versions not yet present: ${result.missing.map(packageLabel).join(', ')}`, + ); + } + continue; + } + if (mode === 'require-published' && result.missing.length > 0) { + fail( + `${product} registry publication is missing: ${result.missing.map(packageLabel).join(', ')}`, + ); + } + if (mode === 'require-unpublished' && result.published.length > 0) { + fail( + `${product} version is already published in public registries: ${result.published.map(packageLabel).join(', ')}`, + ); + } + const state = mode === 'require-published' ? 'published' : 'unpublished'; + console.log( + `${product} registry ${state} check passed: ${result.packages.map(packageLabel).join(', ')}`, + ); + } +} + +export async function checkRegistryPublication(argv) { + const subcommands = new Map([ + ['product-crates', runProductCrates], + ['crate-version-exists', runCrateVersionExists], + ['crate-exists', runCrateExists], + ['query-product-publication', runQueryProductPublication], + ['product-registry-packages', runProductRegistryPackages], + ]); + const first = argv[0]; + if (subcommands.has(first)) { + const { flags, positionals } = parseFlags(argv.slice(1)); + activatePublicationLockFlag(flags); + if (positionals.length > 0) { + fail(`unexpected positional arguments: ${positionals.join(', ')}`); + } + await subcommands.get(first)(flags); + return; + } + const { flags, positionals } = parseFlags(argv); + activatePublicationLockFlag(flags); + if (positionals.length > 0) { + fail(`unexpected positional arguments: ${positionals.join(', ')}`); + } + await runPublicationCli(flags); +} + +if (import.meta.main) { + await checkRegistryPublication(Bun.argv.slice(2)); +} diff --git a/tools/release/check_release_please_config.mjs b/tools/release/check_release_please_config.mjs deleted file mode 100755 index a41ab1c9f..000000000 --- a/tools/release/check_release_please_config.mjs +++ /dev/null @@ -1,436 +0,0 @@ -#!/usr/bin/env bun -import fs from 'node:fs/promises'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { moonCommand, moonEnvironment } from '../dev/moon-command.mjs'; -import { captureCommandOutput } from '../dev/capture-command-output.mjs'; -import { releasePleaseBootstrapLifecycleError } from './release-please-bootstrap.mjs'; -import { assertReleasePleasePackageIdentity } from './release-please-package-identity.mjs'; - -const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); -const configPath = path.join(root, 'release-please-config.json'); -const manifestPath = path.join(root, '.release-please-manifest.json'); -const RELEASE_PR_TITLE_PATTERN = 'chore${scope}: release${component} ${version}'; -const GROUP_RELEASE_PR_TITLE_PATTERN = 'chore(release): prepare ${branch} releases'; - -function fail(message) { - console.error(`check_release_please_config.mjs: ${message}`); - process.exit(2); -} - -function rel(file) { - return path.relative(root, file).split(path.sep).join('/'); -} - -async function readJson(file) { - let value; - try { - value = JSON.parse(await fs.readFile(file, 'utf8')); - } catch (error) { - fail(`failed to read ${rel(file)}: ${error.message}`); - } - if (typeof value !== 'object' || value === null || Array.isArray(value)) { - fail(`${rel(file)} must contain a JSON object`); - } - return value; -} - -async function requireFile(file, context) { - try { - const stat = await fs.stat(file); - if (stat.isFile()) { - return; - } - } catch { - // handled below - } - fail(`${context} references missing file ${rel(file)}`); -} - -function rejectUnsafeRelativePath(value, context) { - if ( - typeof value !== 'string' || - value.length === 0 || - path.isAbsolute(value) || - value.split(/[\\/]/u).includes('..') - ) { - fail(`${context} must stay inside its release-please package path: ${JSON.stringify(value)}`); - } -} - -function parseStableVersion(value, context) { - const match = /^([0-9]+)[.]([0-9]+)[.]([0-9]+)$/u.exec(value); - if (!match) { - fail(`${context} must be a stable semver version, got ${JSON.stringify(value)}`); - } - return match.slice(1).map((part) => Number(part)); -} - -function compareStableVersion(left, right) { - for (let index = 0; index < left.length; index += 1) { - if (left[index] !== right[index]) { - return left[index] - right[index]; - } - } - return 0; -} - -function validateSwiftReleasePleaseBootstrap(packagePath, packageConfig, manifestVersion) { - if (packageConfig['bump-patch-for-minor-pre-major'] !== false) { - fail( - `${packagePath}.bump-patch-for-minor-pre-major must be false so SwiftPM feature releases move past legacy unscoped semver tags`, - ); - } - - if (packageConfig['initial-version'] !== '0.6.0') { - fail(`${packagePath}.initial-version must be 0.6.0 to clear legacy unscoped SwiftPM tags`); - } - const current = parseStableVersion(manifestVersion, `${packagePath} manifest version`); - const zero = parseStableVersion('0.0.0', 'unreleased SwiftPM seed'); - const firstPublicVersion = parseStableVersion('0.6.0', 'SwiftPM first public version'); - if ( - compareStableVersion(current, zero) > 0 && - compareStableVersion(current, firstPublicVersion) < 0 - ) { - fail( - `${packagePath} version ${JSON.stringify( - manifestVersion, - )} is below the first safe Oliphaunt SwiftPM version 0.6.0`, - ); - } -} - -async function validateBootstrapChangelog(packagePath, changelogPath, manifestVersion) { - const file = path.join(root, packagePath, changelogPath); - const text = await fs.readFile(file, 'utf8'); - if (manifestVersion === '0.0.0' && text.trim() !== '') { - const detail = text.trim() === '# Changelog' - ? 'the preseed-only heading would make release-please append a duplicate Changelog section' - : 'unreleased 0.0.0 products must start from an empty changelog owned by release-please'; - fail(`${rel(file)} must be empty before the first release: ${detail}`); - } -} - -function runMoonProjects() { - let result; - try { - result = captureCommandOutput(moonCommand(), ['query', 'projects'], { - cwd: root, - env: moonEnvironment(), - label: 'moon query projects', - }); - } catch (error) { - fail(`moon query projects failed to start: ${error.message}`); - } - if (result.error !== undefined) { - fail(`moon query projects failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - const stderr = result.stderr.trim(); - fail(`moon query projects failed${stderr ? `: ${stderr}` : ''}`); - } - const value = JSON.parse(result.stdout); - if (!Array.isArray(value.projects)) { - fail('moon query projects did not return a projects array'); - } - return value.projects; -} - -function moonReleaseProducts() { - const products = new Map(); - for (const project of runMoonProjects()) { - const projectId = project?.id; - const config = project?.config ?? {}; - const tags = Array.isArray(config.tags) ? config.tags : []; - const release = config.project?.metadata?.release; - if (!tags.includes('release-product')) { - if (release !== undefined) { - fail(`Moon project ${projectId} declares release metadata but is not tagged release-product`); - } - continue; - } - if (typeof projectId !== 'string' || !projectId) { - fail('Moon release product must have a project id'); - } - if (typeof release !== 'object' || release === null || Array.isArray(release)) { - fail(`Moon release product ${projectId} must declare project.metadata.release`); - } - const component = release.component; - const packagePath = release.packagePath; - if (component !== projectId) { - fail(`Moon release product ${projectId} release.component must match the project id`); - } - if (typeof packagePath !== 'string' || !packagePath) { - fail(`Moon release product ${projectId} must declare release.packagePath`); - } - rejectUnsafeRelativePath(packagePath, `${projectId}.release.packagePath`); - if (products.has(component)) { - fail(`duplicate Moon release component ${component}`); - } - products.set(component, packagePath); - } - if (products.size === 0) { - fail('Moon project graph does not contain any release-product projects'); - } - return products; -} - -function parseCargoVersion(text) { - let inPackage = false; - for (const rawLine of text.split(/\r?\n/u)) { - const line = rawLine.trim(); - if (line === '[package]') { - inPackage = true; - continue; - } - if (inPackage && line.startsWith('[')) { - break; - } - if (!inPackage) { - continue; - } - const match = line.match(/^version\s*=\s*"([^"]+)"/u); - if (match) { - return match[1]; - } - } - return ''; -} - -function canonicalVersionFile(packagePath, packageConfig, product) { - const versionFile = packageConfig['version-file']; - if (versionFile !== undefined) { - if (typeof versionFile !== 'string' || !versionFile) { - fail(`${packagePath}.version-file must be a non-empty string`); - } - rejectUnsafeRelativePath(versionFile, `${packagePath}.version-file`); - return versionFile; - } - const releaseType = packageConfig['release-type']; - if (releaseType === 'rust') { - return 'Cargo.toml'; - } - if (releaseType === 'node' || releaseType === 'expo') { - return 'package.json'; - } - fail(`${product} release-please config must declare version-file for release type ${JSON.stringify(releaseType)}`); -} - -async function currentVersion(product, packagePath, packageConfig) { - const versionFile = canonicalVersionFile(packagePath, packageConfig, product); - const file = path.join(root, packagePath, versionFile); - await requireFile(file, `${packagePath}.version-file`); - const text = await fs.readFile(file, 'utf8'); - const name = path.basename(versionFile); - let version = ''; - if (name === 'Cargo.toml') { - version = parseCargoVersion(text); - } else if (name === 'package.json') { - const data = JSON.parse(text); - version = typeof data.version === 'string' ? data.version : ''; - } else if (name === 'VERSION' || name === 'LIBOLIPHAUNT_VERSION') { - version = text.trim(); - } else { - fail(`${product}.version-file has unsupported version file type: ${versionFile}`); - } - if (!version) { - fail(`${rel(file)} does not define a release version for ${product}`); - } - return version; -} - -async function validateExtraFiles(packagePath, packageConfig) { - const extraFiles = packageConfig['extra-files'] ?? []; - if (!Array.isArray(extraFiles)) { - fail(`${packagePath}.extra-files must be a list`); - } - for (const [index, entry] of extraFiles.entries()) { - const context = `${packagePath}.extra-files[${index}]`; - if (typeof entry === 'string') { - rejectUnsafeRelativePath(entry, context); - await requireFile(path.join(root, packagePath, entry), context); - continue; - } - if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) { - fail(`${context} must be a path string or object`); - } - const entryPath = entry.path; - if (typeof entryPath !== 'string' || !entryPath) { - fail(`${context}.path must be a non-empty string`); - } - rejectUnsafeRelativePath(entryPath, `${context}.path`); - await requireFile(path.join(root, packagePath, entryPath), context); - const entryType = entry.type; - if (['json', 'toml', 'yaml'].includes(entryType) && typeof entry.jsonpath !== 'string') { - fail(`${context} type ${JSON.stringify(entryType)} requires jsonpath`); - } - if (entryType === 'xml' && typeof entry.xpath !== 'string') { - fail(`${context} type 'xml' requires xpath`); - } - } -} - -const config = await readJson(configPath); -const manifest = await readJson(manifestPath); -const bootstrapLifecycleError = releasePleaseBootstrapLifecycleError(config, manifest); -if (bootstrapLifecycleError !== undefined) { - fail(bootstrapLifecycleError); -} -const packages = config.packages; -if (typeof packages !== 'object' || packages === null || Array.isArray(packages) || Object.keys(packages).length === 0) { - fail('release-please-config.json must define non-empty packages'); -} - -const pathsById = moonReleaseProducts(); -const expectedPaths = new Set(pathsById.values()); -const actualPaths = new Set(Object.keys(packages)); -const manifestPaths = new Set(Object.keys(manifest)); -const sortedDifference = (left, right) => [...left].filter((item) => !right.has(item)).sort(); - -function validatePlugins(plugins) { - if (!Array.isArray(plugins)) { - fail('release-please plugins must be a list'); - } - const expected = [ - { - type: 'node-workspace', - merge: false, - }, - ]; - if (JSON.stringify(plugins) !== JSON.stringify(expected)) { - fail('release-please plugins must use node-workspace without internal merging'); - } -} - -function releasePleaseTitlePatternRegex(pattern) { - if (typeof pattern !== 'string' || !pattern) { - fail(`release-please title pattern must be a non-empty string: ${JSON.stringify(pattern)}`); - } - return new RegExp( - `^${pattern - .replace('[', '\\[') - .replace(']', '\\]') - .replace('(', '\\(') - .replace(')', '\\)') - .replace('${scope}', '(\\((?[\\w-./]+)\\))?') - .replace('${component}', ' ?(?@?[\\w-./]*)?') - .replace('${version}', 'v?(?[0-9].*)') - .replace('${branch}', '(?[\\w-./]+)?')}$`, - ); -} - -function assertParseableReleasePleaseTitle(pattern, title, context) { - const match = title.match(releasePleaseTitlePatternRegex(pattern)); - if (!match?.groups) { - fail(`${context} must be parseable by release-please: ${JSON.stringify(title)}`); - } -} - -function renderReleasePleaseTitle(pattern, { targetBranch }) { - return pattern - .replace('${scope}', targetBranch ? `(${targetBranch})` : '') - .replace('${component}', '') - .replace('${version}', '') - .replace('${branch}', targetBranch ?? '') - .trim(); -} -if (actualPaths.size !== expectedPaths.size || sortedDifference(expectedPaths, actualPaths).length > 0) { - fail( - `release-please packages must match release products:\nmissing=${JSON.stringify(sortedDifference(expectedPaths, actualPaths))}\nextra=${JSON.stringify(sortedDifference(actualPaths, expectedPaths))}`, - ); -} -if (manifestPaths.size !== expectedPaths.size || sortedDifference(expectedPaths, manifestPaths).length > 0) { - fail( - `.release-please-manifest.json paths must match release products:\nmissing=${JSON.stringify(sortedDifference(expectedPaths, manifestPaths))}\nextra=${JSON.stringify(sortedDifference(manifestPaths, expectedPaths))}`, - ); -} - -if (config['tag-separator'] !== '-') { - fail("release-please tag-separator must be '-' for -v tags"); -} -if (config['include-v-in-tag'] !== true) { - fail('release-please must include v in tags'); -} -const expectedChangelogSections = [ - { type: 'feat', section: 'Features', hidden: false }, - { type: 'fix', section: 'Bug Fixes', hidden: false }, - { type: 'perf', section: 'Performance Improvements', hidden: false }, - { type: 'refactor', section: 'Code Refactoring', hidden: false }, - { type: 'revert', section: 'Reverts', hidden: false }, -]; -if (JSON.stringify(config['changelog-sections']) !== JSON.stringify(expectedChangelogSections)) { - fail('release-please changelog-sections must expose exactly feat, fix, perf, refactor, and revert so accepted release intent cannot drift from generated releases'); -} -if (config['pull-request-title-pattern'] !== RELEASE_PR_TITLE_PATTERN) { - fail("release-please pull-request-title-pattern must keep release-please's parseable default shape"); -} -if (config['group-pull-request-title-pattern'] !== GROUP_RELEASE_PR_TITLE_PATTERN) { - fail('release-please group-pull-request-title-pattern must keep grouped release PRs parseable'); -} -const generatedGroupTitle = renderReleasePleaseTitle(GROUP_RELEASE_PR_TITLE_PATTERN, { targetBranch: 'main' }); -if (generatedGroupTitle !== 'chore(release): prepare main releases') { - fail(`release-please grouped release PR title rendered unexpectedly: ${JSON.stringify(generatedGroupTitle)}`); -} -assertParseableReleasePleaseTitle( - GROUP_RELEASE_PR_TITLE_PATTERN, - generatedGroupTitle, - 'generated grouped release PR title', -); -assertParseableReleasePleaseTitle( - GROUP_RELEASE_PR_TITLE_PATTERN, - 'chore(release): prepare product releases', - 'already-merged grouped release PR #80 title', -); -if (config['initial-version'] !== '0.1.0') { - fail('release-please initial-version must bootstrap the first generated release PR to 0.1.0'); -} -if (config['bump-minor-pre-major'] !== true) { - fail('release-please must minor-bump breaking changes while product versions are below 1.0.0'); -} -if (config['bump-patch-for-minor-pre-major'] !== true) { - fail('release-please must patch-bump feat commits after the 0.1.0 bootstrap while versions stay below 1.0.0'); -} -validatePlugins(config.plugins ?? []); - -const idsByPath = new Map([...pathsById.entries()].map(([product, packagePath]) => [packagePath, product])); -for (const [packagePath, packageConfig] of Object.entries(packages)) { - if (typeof packageConfig !== 'object' || packageConfig === null || Array.isArray(packageConfig)) { - fail(`${packagePath} config must be an object`); - } - const product = idsByPath.get(packagePath); - const component = packageConfig.component; - if (component !== product) { - fail(`${packagePath}.component must be ${JSON.stringify(product)}, got ${JSON.stringify(component)}`); - } - const tagPrefix = `${component}-v`; - if (tagPrefix !== `${product}-v`) { - fail(`${product} release-please component does not match tag prefix ${JSON.stringify(tagPrefix)}`); - } - const manifestVersion = manifest[packagePath]; - const version = await currentVersion(product, packagePath, packageConfig); - if (manifestVersion !== version) { - fail(`${packagePath} manifest version ${JSON.stringify(manifestVersion)} does not match current ${product} version ${JSON.stringify(version)}`); - } - if (product === 'oliphaunt-swift') { - validateSwiftReleasePleaseBootstrap(packagePath, packageConfig, manifestVersion); - } - if (['expo', 'node'].includes(packageConfig['release-type'])) { - const packageManifest = await readJson(path.join(root, packagePath, 'package.json')); - try { - assertReleasePleasePackageIdentity(packagePath, packageConfig, packageManifest); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - } - const changelogPath = packageConfig['changelog-path'] ?? 'CHANGELOG.md'; - if (typeof changelogPath !== 'string' || !changelogPath) { - fail(`${packagePath}.changelog-path must be a non-empty string`); - } - rejectUnsafeRelativePath(changelogPath, `${packagePath}.changelog-path`); - await requireFile(path.join(root, packagePath, changelogPath), `${packagePath}.changelog-path`); - await validateBootstrapChangelog(packagePath, changelogPath, manifestVersion); - await validateExtraFiles(packagePath, packageConfig); -} - -console.log('release-please config checks passed'); diff --git a/tools/release/check_release_please_config.mts b/tools/release/check_release_please_config.mts new file mode 100755 index 000000000..c289663a8 --- /dev/null +++ b/tools/release/check_release_please_config.mts @@ -0,0 +1,76 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import { readFileSync, statSync } from 'node:fs'; +import path from 'node:path'; +import { currentProductVersionSync } from './release-artifact-targets.mts'; +import { loadProducts, ROOT, readJson } from './release-graph.mts'; +import { releasePleaseBootstrapLifecycleError } from './release-please-bootstrap.mts'; +import { assertReleasePleasePackageIdentity } from './release-please-package-identity.mts'; + +const TOOL = 'check_release_please_config.mts'; + +try { + const config = readJson('release-please-config.json', TOOL); + const manifest = readJson('.release-please-manifest.json', TOOL); + const bootstrapError = releasePleaseBootstrapLifecycleError(config, manifest); + assert.equal(bootstrapError, undefined, bootstrapError); + // Shared metadata parsing already validates product identities, tag prefixes, + // package-relative version/changelog paths, and their existence. + const products = loadProducts(TOOL); + assert.deepEqual( + Object.keys(manifest).sort(), + Object.values(products) + .map((product) => product.path) + .sort(), + 'release manifest paths must match configured products', + ); + for (const [id, product] of Object.entries(products)) { + const packageConfig = config.packages[product.path]; + assert.equal( + currentProductVersionSync(id, TOOL), + product.version, + `${id} canonical version must match the release manifest`, + ); + for (const file of [...product.version_files, product.changelog_path]) { + assert(statSync(path.join(ROOT, file)).isFile(), `${file} must be a regular file`); + } + if (['expo', 'node'].includes(packageConfig['release-type'])) { + assertReleasePleasePackageIdentity( + product.path, + packageConfig, + readJson(`${product.path}/package.json`, TOOL), + ); + } + if (product.version === '0.0.0') { + assert.equal( + readFileSync(path.join(ROOT, product.changelog_path), 'utf8').trim(), + '', + `${product.changelog_path} must be empty before its first generated release`, + ); + } + for (const entry of packageConfig['extra-files'] ?? []) { + if (typeof entry === 'string') continue; + if (['json', 'toml', 'yaml'].includes(entry.type)) { + assert.equal(typeof entry.jsonpath, 'string', `${entry.path} requires jsonpath`); + } else if (entry.type === 'xml') { + assert.equal(typeof entry.xpath, 'string', `${entry.path} requires xpath`); + } + } + if (id === 'oliphaunt-swift') { + assert.equal( + packageConfig['initial-version'], + '0.6.0', + 'Swift must clear legacy semver tags', + ); + assert.equal(packageConfig['bump-patch-for-minor-pre-major'], false); + assert( + product.version === '0.0.0' || Bun.semver.order(product.version, '0.6.0') >= 0, + 'Swift releases must start at 0.6.0 to clear legacy semver tags', + ); + } + } + console.log('release-please config checks passed'); +} catch (error) { + console.error(`${TOOL}: ${error.message}`); + process.exitCode = 2; +} diff --git a/tools/release/check_release_pr_coverage.mjs b/tools/release/check_release_pr_coverage.mjs deleted file mode 100644 index b5612d797..000000000 --- a/tools/release/check_release_pr_coverage.mjs +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env bun -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { captureCommandOutput } from '../dev/capture-command-output.mjs'; -import { loadGraph } from './release-graph.mjs'; -import { releaseProductVersionCoverage } from './release-product-version-coverage.mjs'; -import { deriveReleaseProducts, verifyReleaseCommit } from './verify-release-commit.mjs'; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); -const MANIFEST = '.release-please-manifest.json'; - -function fail(message) { - console.error(`check_release_pr_coverage.mjs: ${message}`); - process.exit(1); -} - -function run(command, args, { check = true, cwd = ROOT } = {}) { - const result = captureCommandOutput(command, args, { - cwd, - label: `${command} ${args.join(' ')}`, - }); - if (result.error) { - if (check) { - fail(`failed to run ${command}: ${result.error.message}`); - } - return result; - } - if (check && result.status !== 0) { - fail(`${command} ${args.join(' ')} failed: ${result.stderr.trim()}`); - } - return result; -} - -function git(args, options = {}) { - return run('git', args, options); -} - -function gitStdout(args, options = {}) { - return git(args, options).stdout.trim(); -} - -function refExists(ref) { - return git(['rev-parse', '--verify', '--quiet', `${ref}^{commit}`], { check: false }).status === 0; -} - -function baseRef() { - const candidates = []; - const baseBranch = process.env.GITHUB_BASE_REF; - if (baseBranch) { - candidates.push(`origin/${baseBranch}`, baseBranch); - } - candidates.push('origin/main', 'main'); - return candidates.find(refExists) ?? null; -} - -function parseJsonObject(raw, context) { - let value; - try { - value = JSON.parse(raw); - } catch (error) { - fail(`${context} must be valid JSON: ${error.message}`); - } - if (value === null || typeof value !== 'object' || Array.isArray(value)) { - fail(`${context} must be a JSON object`); - } - return value; -} - -function requireStringObject(value, context) { - if ( - value === null || - typeof value !== 'object' || - Array.isArray(value) || - Object.entries(value).some(([key, item]) => typeof key !== 'string' || typeof item !== 'string') - ) { - fail(`${context} must be a JSON string object`); - } - return value; -} - -function manifestAt(ref) { - if (git(['cat-file', '-e', `${ref}:${MANIFEST}`], { check: false }).status !== 0) { - return {}; - } - const raw = gitStdout(['show', `${ref}:${MANIFEST}`]); - return requireStringObject(parseJsonObject(raw, `${MANIFEST} at ${ref}`), `${MANIFEST} at ${ref}`); -} - -function currentManifest() { - const raw = fs.readFileSync(path.join(ROOT, MANIFEST), 'utf8'); - return requireStringObject(parseJsonObject(raw, MANIFEST), MANIFEST); -} - -function currentReleasePleaseConfig() { - return parseJsonObject( - fs.readFileSync(path.join(ROOT, 'release-please-config.json'), 'utf8'), - 'release-please-config.json', - ); -} - -function releasePleaseProductPaths(config) { - const packages = config.packages; - if (packages === null || typeof packages !== 'object' || Array.isArray(packages)) { - fail('release-please-config.json must define packages'); - } - const productPaths = new Map(); - for (const [packagePath, packageConfig] of Object.entries(packages)) { - const component = packageConfig?.component; - if (typeof component !== 'string' || component.length === 0) { - fail(`release-please package ${packagePath} must define component`); - } - if (productPaths.has(component)) { - fail(`release-please-config.json declares duplicate component ${component}`); - } - productPaths.set(component, packagePath); - } - return productPaths; -} - -function main() { - const afterManifest = currentManifest(); - const releasePleaseConfig = currentReleasePleaseConfig(); - -const ref = baseRef(); -if (ref === null) { - fail('could not resolve base ref for release PR coverage check'); -} - -const beforeManifest = manifestAt(ref); -const productPaths = releasePleaseProductPaths(releasePleaseConfig); -const versionedProducts = new Set(); - -for (const [product, packagePath] of productPaths.entries()) { - const before = beforeManifest[packagePath]; - const after = afterManifest[packagePath]; - if (before === undefined && after === '0.0.0') { - continue; - } - if (before !== after) { - versionedProducts.add(product); - } -} - -if (versionedProducts.size === 0) { - console.log('release PR coverage check skipped; release-please manifest is unchanged'); - process.exit(0); -} - -const graph = loadGraph('check_release_pr_coverage.mjs'); -const knownProducts = new Set(Object.keys(graph.products)); -const unknownVersioned = [...versionedProducts].filter(product => !knownProducts.has(product)).sort(); -if (unknownVersioned.length > 0) { - fail(`${MANIFEST} changed unknown products: ${unknownVersioned.join(', ')}`); -} - -const versionedProductList = [...versionedProducts].sort(); -try { - const derivedProducts = deriveReleaseProducts({ repo: ROOT, headRef: 'HEAD' }).products; - if (JSON.stringify(derivedProducts) !== JSON.stringify(versionedProductList)) { - fail( - `release commit manifest transitions disagree with base coverage: ` + - `base=${JSON.stringify(versionedProductList)}, parent=${JSON.stringify(derivedProducts)}`, - ); - } - const verified = verifyReleaseCommit({ - repo: ROOT, - headRef: 'HEAD', - products: versionedProductList, - }); - const baseCommit = gitStdout(['rev-parse', `${ref}^{commit}`]); - if (verified.parent !== baseCommit) { - fail(`release commit parent ${verified.parent} does not match coverage base ${baseCommit}`); - } -} catch (error) { - fail(error instanceof Error ? error.message.replace(/^verify-release-commit[.]mjs: /u, '') : String(error)); -} - -let coverage; -try { - coverage = releaseProductVersionCoverage(graph, versionedProductList, 'check_release_pr_coverage.mjs'); -} catch (error) { - fail(error.message.replace(/^check_release_pr_coverage[.]mjs: /u, '')); -} -const missing = coverage.missingProducts; -if (missing.length > 0) { - fail( - 'the generated release PR did not version every selected release product. ' + - 'Each independently versioned product must own its version, changelog, and tag. ' + - 'Missing product version bumps: ' + - missing.join(', '), - ); -} - - console.log('release PR product coverage checks passed'); -} - -if (import.meta.main) { - main(); -} diff --git a/tools/release/check_release_versions.mjs b/tools/release/check_release_versions.mjs deleted file mode 100644 index 1f804fcce..000000000 --- a/tools/release/check_release_versions.mjs +++ /dev/null @@ -1,471 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "node:child_process"; -import { mkdirSync, writeFileSync } from "node:fs"; -import path from "node:path"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { currentVersion } from "./product-version.mjs"; -import { - ROOT, - assertStringList as graphAssertStringList, - commandJson, - compareVersion, - compatibilityVersionEntries, - compatibilityVersionValue, - formatVersion, - loadGraph, - parseStableVersion as graphParseStableVersion, - tagMatchPattern, - tagPrefixes as graphTagPrefixes, -} from "./release-graph.mjs"; - -const TOOL = "check_release_versions.mjs"; -const REGISTRY_TARGETS = new Set(["crates-io", "npm", "maven-central"]); -const REGISTRY_INVENTORY_SCHEMA = "oliphaunt-release-registry-inventory-v1"; - -function fail(message) { - console.error(`${TOOL}: ${message}`); - process.exit(1); -} - -function gitOutput(args) { - const result = captureCommandOutput("git", args, { - cwd: ROOT, - label: `git ${args.join(" ")}`, - stdoutTerminator: "\n", - }); - if (result.error !== undefined || result.status !== 0) { - fail(result.error?.message || result.stderr.trim() || `git ${args.join(" ")} failed`); - } - return result.stdout.trim(); -} - -function run(args) { - const result = spawnSync(args[0], args.slice(1), { cwd: ROOT, stdio: "inherit" }); - if (result.error) { - fail(`failed to run ${args.join(" ")}: ${result.error.message}`); - } - if (result.status !== 0) { - process.exit(result.status ?? 1); - } -} - -function parseStableVersion(version) { - return graphParseStableVersion(version, TOOL); -} - -function assertStringList(value, context) { - return graphAssertStringList(value, context, TOOL); -} - -function parseProducts(raw, graph) { - const products = graph.products; - if (products === null || Array.isArray(products) || typeof products !== "object") { - fail("release metadata must define [products.] entries"); - } - if (raw === undefined) { - return Object.keys(products).sort(); - } - const value = JSON.parse(raw); - if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) { - fail("--products-json must be a JSON string list"); - } - const unknown = value.filter((product) => !(product in products)).sort(); - if (unknown.length > 0) { - fail(`unknown release products: ${unknown.join(", ")}`); - } - return value; -} - -function registryCommand(args) { - return [process.execPath, "tools/release/check_registry_publication.mjs", ...args]; -} - -function registryRun(args) { - run(registryCommand(args)); -} - -function registryJson(args) { - return commandJson(registryCommand(args), TOOL); -} - -function registryAssertProductPublication(product, { requirePublished, versionOverride } = {}) { - const args = ["--product", product, requirePublished ? "--require-published" : "--require-unpublished"]; - if (versionOverride !== undefined) { - args.push("--version", versionOverride); - } - registryRun(args); -} - -function registryQueryProductPublication(product) { - const data = registryJson(["query-product-publication", "--product", product]); - if (!Array.isArray(data.packages) || !Array.isArray(data.missing) || !Array.isArray(data.published)) { - fail("registry publication helper returned malformed publication status"); - } - return data; -} - -function registryInventoryPackages(packages, context) { - return packages.map((pkg, index) => { - if ( - pkg === null - || Array.isArray(pkg) - || typeof pkg !== "object" - || typeof pkg.kind !== "string" - || typeof pkg.name !== "string" - || typeof pkg.version !== "string" - ) { - fail(`${context}[${index}] is not a registry package identity`); - } - return { kind: pkg.kind, name: pkg.name, version: pkg.version }; - }); -} - -function verifyGithubReleaseAssets(product, version) { - run([ - process.execPath, - "tools/release/check_github_release_assets.mjs", - product, - "--version", - version, - "--default-assets", - ]); -} - -function tagPrefixes(config) { - return graphTagPrefixes(config, TOOL); -} - -function productTags(prefix) { - const args = ["tag", "--list", tagMatchPattern(prefix)]; - const result = captureCommandOutput("git", args, { - allowEmptyOutput: true, - cwd: ROOT, - label: `git ${args.join(" ")}`, - stdoutTerminator: "\n", - }); - if (result.error !== undefined || result.status !== 0) { - fail(result.error?.message || result.stderr.trim() || `git ${args.join(" ")} failed`); - } - return result.stdout - .split(/\r?\n/) - .map((line) => line.trim()) - .filter(Boolean); -} - -function tagVersion(prefix, tag) { - if (!tag.startsWith(prefix)) { - return undefined; - } - const version = tag.slice(prefix.length); - if (!/^[0-9]+[.][0-9]+[.][0-9]+$/.test(version)) { - return undefined; - } - return parseStableVersion(version); -} - -function tagCommit(tag) { - return gitOutput(["rev-list", "-n", "1", tag]); -} - -function commitParents(commit) { - return gitOutput(["rev-list", "--parents", "-n", "1", commit]) - .split(/\s+/u) - .filter(Boolean) - .slice(1); -} - -function tagExists(tag) { - const result = spawnSync("git", ["rev-parse", "--verify", "--quiet", `refs/tags/${tag}^{commit}`], { - cwd: ROOT, - stdio: "ignore", - }); - return result.status === 0; -} - -function commitForRef(ref) { - return gitOutput(["rev-parse", `${ref}^{commit}`]); -} - -function validateSwiftpmVersionTag(product, version, headCommit) { - if (product !== "oliphaunt-swift") { - return; - } - const existing = tagExists(version) ? tagCommit(version) : null; - if (existing === null) { - return; - } - const parents = commitParents(existing); - const sourceCommit = parents.length === 1 ? parents[0] : existing; - if (sourceCommit === headCommit) { - console.log(`SwiftPM version tag ${version} is bound to release commit ${headCommit}`); - return; - } - fail( - `SwiftPM version tag ${version} already exists at ${existing}, whose source parent is ${sourceCommit}, not exact release commit ${headCommit}`, - ); -} - -async function validateProduct(product, config, headRef) { - if (typeof config.tag_prefix !== "string" || config.tag_prefix.length === 0) { - fail(`${product} must declare tag_prefix`); - } - const version = await currentVersion(product); - const current = parseStableVersion(version); - const currentTag = `${config.tag_prefix}${version}`; - const headCommit = commitForRef(headRef); - const tags = productTags(config.tag_prefix); - if (tags.includes(currentTag)) { - const currentTagCommit = tagCommit(currentTag); - if (currentTagCommit !== headCommit) { - fail( - `${product} version ${version} is already tagged as ${currentTag} at ${currentTagCommit}, not exact release commit ${headCommit}; every different commit requires a new version`, - ); - } - validateSwiftpmVersionTag(product, version, headCommit); - return true; - } - validateSwiftpmVersionTag(product, version, headCommit); - const previousVersions = []; - for (const candidatePrefix of tagPrefixes(config)) { - for (const tag of productTags(candidatePrefix)) { - const parsed = tagVersion(candidatePrefix, tag); - if (parsed !== undefined) { - previousVersions.push(parsed); - } - } - } - if (previousVersions.length > 0) { - const latest = previousVersions.reduce((max, candidate) => - compareVersion(candidate, max) > 0 ? candidate : max, - ); - if (compareVersion(current, latest) <= 0) { - fail( - `${product} version ${version} is not newer than latest tagged version ${formatVersion( - latest, - )}; merge the release-please release PR before publishing`, - ); - } - } - return false; -} - -async function validateRegistryPublication(products, graph, currentTagAtHead, headRef) { - const graphProducts = graph.products; - const headCommit = commitForRef(headRef); - const inventory = []; - for (const product of products) { - const config = graphProducts[product]; - const targets = assertStringList(config.publish_targets ?? [], `${product}.publish_targets`); - const registryTargets = targets.filter((target) => REGISTRY_TARGETS.has(target)); - if (registryTargets.length === 0) { - inventory.push({ product, packages: [], missing: [], published: [] }); - continue; - } - if (currentTagAtHead[product] === true) { - const { packages, missing, published } = registryQueryProductPublication(product); - if (packages.length === 0) { - console.log(`${product} has no external registry packages to check`); - } else { - console.log( - `${product} registry completion check: ${published.length} published, ${missing.length} missing`, - ); - } - inventory.push({ - product, - packages: registryInventoryPackages(packages, `${product}.packages`), - missing: registryInventoryPackages(missing, `${product}.missing`), - published: registryInventoryPackages(published, `${product}.published`), - }); - continue; - } - const { packages, missing, published } = registryQueryProductPublication(product); - if (packages.length === 0) { - console.log(`${product} has no external registry packages to check`); - } else if (published.length > 0) { - if (typeof config.tag_prefix !== "string" || config.tag_prefix.length === 0) { - fail(`${product} must declare tag_prefix`); - } - const version = await currentVersion(product); - const currentTag = `${config.tag_prefix}${version}`; - console.log( - `${product} has registry versions awaiting workflow finalization: ${published - .map((item) => String(item.label)) - .join(", ")}; ${currentTag} is not yet exact at ${headCommit}. The protected publish workflow must prove these versions with the immutable bootstrap ledger before it stages exact-SHA tags; never create product tags manually.`, - ); - } else { - console.log( - `${product} registry unpublished check passed: ${packages.map((item) => String(item.label)).join(", ")}`, - ); - } - inventory.push({ - product, - packages: registryInventoryPackages(packages, `${product}.packages`), - missing: registryInventoryPackages(missing, `${product}.missing`), - published: registryInventoryPackages(published, `${product}.published`), - }); - } - return { - schema: REGISTRY_INVENTORY_SCHEMA, - source: { commit: headCommit }, - products: [...products], - results: inventory, - }; -} - -function validateReleasedDependencyArtifacts(consumer, dependency, dependencyVersion, graph) { - const dependencyConfig = graph.products[dependency]; - if (dependencyConfig === null || Array.isArray(dependencyConfig) || typeof dependencyConfig !== "object") { - fail(`${consumer} declares unknown release dependency ${dependency}`); - } - const targets = assertStringList(dependencyConfig.publish_targets ?? [], `${dependency}.publish_targets`); - const registryTargets = targets.filter((target) => REGISTRY_TARGETS.has(target)); - if (registryTargets.length > 0) { - registryAssertProductPublication(dependency, { - requirePublished: true, - versionOverride: dependencyVersion, - }); - } - if (targets.includes("github-release-assets")) { - verifyGithubReleaseAssets(dependency, dependencyVersion); - } -} - -async function validateDependencyTag(consumer, dependency, dependencyVersion, graph, selected) { - parseStableVersion(dependencyVersion); - if (selectedDependencySatisfiesPin( - selected, - dependency, - dependencyVersion, - selected.has(dependency) ? await currentVersion(dependency) : undefined, - )) { - return; - } - const dependencyConfig = graph.products[dependency]; - if (dependencyConfig === null || Array.isArray(dependencyConfig) || typeof dependencyConfig !== "object") { - fail(`${consumer} declares unknown release dependency ${dependency}`); - } - if (typeof dependencyConfig.tag_prefix !== "string" || dependencyConfig.tag_prefix.length === 0) { - fail(`${dependency} must declare tag_prefix`); - } - const tag = `${dependencyConfig.tag_prefix}${dependencyVersion}`; - if (!tagExists(tag)) { - fail( - `${consumer} depends on ${dependency} ${dependencyVersion}, but release tag ${tag} does not exist; ` + - `publish that exact dependency version first or select ${dependency} at ${dependencyVersion}`, - ); - } - validateReleasedDependencyArtifacts(consumer, dependency, dependencyVersion, graph); -} - -export function selectedDependencySatisfiesPin(selected, dependency, pinnedVersion, selectedVersion) { - return selected.has(dependency) && selectedVersion === pinnedVersion; -} - -async function validateReleaseDependencies(products, graph) { - const selected = new Set(products); - const entries = compatibilityVersionEntries(graph.products, { - requireSourceProduct: true, - prefix: TOOL, - }); - for (const product of products) { - const dependencies = new Map(); - for (const entry of entries.filter(({ product: owner }) => owner === product)) { - const version = compatibilityVersionValue(entry, { prefix: TOOL }); - const existing = dependencies.get(entry.sourceProduct); - if (existing !== undefined && existing !== version) { - fail(`${product} declares conflicting versions of ${entry.sourceProduct}`); - } - dependencies.set(entry.sourceProduct, version); - } - for (const [dependency, dependencyVersion] of dependencies) { - await validateDependencyTag( - product, - dependency, - dependencyVersion, - graph, - selected, - ); - } - } -} - -function parseArgs(argv) { - const args = { - productsJson: undefined, - headRef: "HEAD", - checkRegistries: false, - registryInventoryOutput: "", - }; - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - if (value === "--products-json") { - if (index + 1 >= argv.length) { - fail("--products-json requires a value"); - } - args.productsJson = argv[index + 1]; - index += 1; - } else if (value.startsWith("--products-json=")) { - args.productsJson = value.slice("--products-json=".length); - } else if (value === "--head-ref") { - if (index + 1 >= argv.length) { - fail("--head-ref requires a value"); - } - args.headRef = argv[index + 1]; - index += 1; - } else if (value.startsWith("--head-ref=")) { - args.headRef = value.slice("--head-ref=".length); - } else if (value === "--check-registries") { - args.checkRegistries = true; - } else if (value === "--registry-inventory-output") { - if (index + 1 >= argv.length) { - fail("--registry-inventory-output requires a value"); - } - args.registryInventoryOutput = argv[index + 1]; - index += 1; - } else if (value.startsWith("--registry-inventory-output=")) { - args.registryInventoryOutput = value.slice("--registry-inventory-output=".length); - } else if (value === "-h" || value === "--help") { - console.log("usage: tools/release/check_release_versions.mjs [--products-json JSON] [--head-ref REF] [--check-registries] [--registry-inventory-output FILE]"); - process.exit(0); - } else { - fail(`unknown argument ${value}`); - } - } - return args; -} - -async function main(argv) { - const args = parseArgs(argv); - const graph = loadGraph(); - const selected = parseProducts(args.productsJson, graph); - if (args.registryInventoryOutput && !args.checkRegistries) { - fail("--registry-inventory-output requires --check-registries"); - } - const currentTagAtHead = {}; - for (const product of selected) { - currentTagAtHead[product] = await validateProduct(product, graph.products[product], args.headRef); - } - await validateReleaseDependencies(selected, graph); - if (args.checkRegistries) { - const inventory = await validateRegistryPublication( - selected, - graph, - currentTagAtHead, - args.headRef, - ); - if (args.registryInventoryOutput) { - const output = path.resolve(ROOT, args.registryInventoryOutput); - mkdirSync(path.dirname(output), { recursive: true }); - writeFileSync(output, `${JSON.stringify(inventory, null, 2)}\n`, { - encoding: "utf8", - flag: "wx", - mode: 0o644, - }); - } - } - console.log("release version checks passed"); -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/check_release_versions.mts b/tools/release/check_release_versions.mts new file mode 100644 index 000000000..9ff167344 --- /dev/null +++ b/tools/release/check_release_versions.mts @@ -0,0 +1,430 @@ +#!/usr/bin/env bun +import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { parseTagCommits, parseTagRefs } from './git-tag-state.mts'; +import { currentVersion } from './product-version.mts'; +import { + compareVersion, + compatibilityVersionEntries, + compatibilityVersionValue, + formatVersion, + assertStringList as graphAssertStringList, + parseStableVersion as graphParseStableVersion, + tagPrefixes as graphTagPrefixes, + loadProducts, + ROOT, +} from './release-graph.mts'; +import { + checkRegistryPublication, + queryProductPublication, +} from './check_registry_publication.mts'; +import { expectedAssets, verifyReleaseAssets } from './verify_github_release_attestations.mts'; + +const TOOL = 'check_release_versions.mts'; +const REGISTRY_TARGETS = new Set(['crates-io', 'npm', 'maven-central']); +const REGISTRY_INVENTORY_SCHEMA = 'oliphaunt-release-registry-inventory-v1'; + +function fail(message) { + console.error(`${TOOL}: ${message}`); + process.exit(1); +} + +let git; + +function parseStableVersion(version) { + return graphParseStableVersion(version, TOOL); +} + +function assertStringList(value, context) { + return graphAssertStringList(value, context, TOOL); +} + +function parseProducts(raw, graph) { + const products = graph.products; + if (products === null || Array.isArray(products) || typeof products !== 'object') { + fail('release metadata must define [products.] entries'); + } + if (raw === undefined) { + return Object.keys(products).sort(); + } + const value = JSON.parse(raw); + if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) { + fail('--products-json must be a JSON string list'); + } + const unknown = value.filter((product) => !(product in products)).sort(); + if (unknown.length > 0) { + fail(`unknown release products: ${unknown.join(', ')}`); + } + return value; +} + +function registryInventoryPackages(packages, context) { + return packages.map((pkg, index) => { + if ( + pkg === null || + Array.isArray(pkg) || + typeof pkg !== 'object' || + typeof pkg.kind !== 'string' || + typeof pkg.name !== 'string' || + typeof pkg.version !== 'string' + ) { + fail(`${context}[${index}] is not a registry package identity`); + } + return { kind: pkg.kind, name: pkg.name, version: pkg.version }; + }); +} + +function tagPrefixes(config) { + return graphTagPrefixes(config, TOOL); +} + +function productTags(prefix, state = git) { + return [...state.refs.keys()] + .filter((ref) => !ref.endsWith('^{}')) + .map((ref) => ref.slice('refs/tags/'.length)) + .filter((tag) => tag.startsWith(prefix) && /^[0-9]/u.test(tag.slice(prefix.length))); +} + +function tagVersion(prefix, tag) { + if (!tag.startsWith(prefix)) { + return undefined; + } + const version = tag.slice(prefix.length); + if (!/^[0-9]+[.][0-9]+[.][0-9]+$/.test(version)) { + return undefined; + } + return parseStableVersion(version); +} + +function tagCommit(tag, state = git) { + const ref = `refs/tags/${tag}`; + const commit = state.refs.get(ref + '^{}') ?? state.refs.get(ref); + return state.commits.has(commit) ? commit : undefined; +} + +function tagExists(tag) { + return tagCommit(tag) !== undefined; +} + +function validateSwiftpmVersionTag(product, version, headCommit, state) { + if (product !== 'oliphaunt-swift') { + return; + } + const existing = tagCommit(version, state) ?? null; + if (existing === null) { + return; + } + const parents = state.commits.get(existing); + const sourceCommit = parents.length === 1 ? parents[0] : existing; + if (sourceCommit === headCommit) { + console.log(`SwiftPM version tag ${version} is bound to release commit ${headCommit}`); + return; + } + throw new Error( + `SwiftPM version tag ${version} already exists at ${existing}, whose source parent is ${sourceCommit}, not exact release commit ${headCommit}`, + ); +} + +export function validateVersionTags(product, version, config, state) { + if (typeof config.tag_prefix !== 'string' || config.tag_prefix.length === 0) { + throw new Error(`${product} must declare tag_prefix`); + } + const current = parseStableVersion(version); + const currentTag = `${config.tag_prefix}${version}`; + const headCommit = state.headCommit; + const tags = productTags(config.tag_prefix, state); + if (tags.includes(currentTag)) { + const currentTagCommit = tagCommit(currentTag, state); + if (currentTagCommit !== headCommit) { + throw new Error( + `${product} version ${version} is already tagged as ${currentTag} at ${currentTagCommit}, not exact release commit ${headCommit}; every different commit requires a new version`, + ); + } + validateSwiftpmVersionTag(product, version, headCommit, state); + return true; + } + validateSwiftpmVersionTag(product, version, headCommit, state); + const previousVersions = []; + for (const candidatePrefix of tagPrefixes(config)) { + for (const tag of productTags(candidatePrefix, state)) { + const parsed = tagVersion(candidatePrefix, tag); + if (parsed !== undefined) { + previousVersions.push(parsed); + } + } + } + if (previousVersions.length > 0) { + const latest = previousVersions.reduce((max, candidate) => + compareVersion(candidate, max) > 0 ? candidate : max, + ); + if (compareVersion(current, latest) <= 0) { + throw new Error( + `${product} version ${version} is not newer than latest tagged version ${formatVersion( + latest, + )}; merge the release-please release PR before publishing`, + ); + } + } + return false; +} + +async function validateRegistryPublication(products, graph, currentTagAtHead) { + const graphProducts = graph.products; + const headCommit = git.headCommit; + const inventory = []; + for (const product of products) { + const config = graphProducts[product]; + const targets = assertStringList(config.publish_targets ?? [], `${product}.publish_targets`); + const registryTargets = targets.filter((target) => REGISTRY_TARGETS.has(target)); + if (registryTargets.length === 0) { + inventory.push({ product, packages: [], missing: [], published: [] }); + continue; + } + if (currentTagAtHead[product] === true) { + const { packages, missing, published } = await queryProductPublication(product); + if (packages.length === 0) { + console.log(`${product} has no external registry packages to check`); + } else { + console.log( + `${product} registry completion check: ${published.length} published, ${missing.length} missing`, + ); + } + inventory.push({ + product, + packages: registryInventoryPackages(packages, `${product}.packages`), + missing: registryInventoryPackages(missing, `${product}.missing`), + published: registryInventoryPackages(published, `${product}.published`), + }); + continue; + } + const { packages, missing, published } = await queryProductPublication(product); + if (packages.length === 0) { + console.log(`${product} has no external registry packages to check`); + } else if (published.length > 0) { + if (typeof config.tag_prefix !== 'string' || config.tag_prefix.length === 0) { + fail(`${product} must declare tag_prefix`); + } + const version = await currentVersion(product); + const currentTag = `${config.tag_prefix}${version}`; + console.log( + `${product} has registry versions awaiting workflow finalization: ${published + .map((item) => `${item.kind}:${item.name}@${item.version}`) + .join( + ', ', + )}; ${currentTag} is not yet exact at ${headCommit}. The protected publish workflow must prove these versions with the immutable bootstrap ledger before it stages exact-SHA tags; never create product tags manually.`, + ); + } else { + console.log( + `${product} registry unpublished check passed: ${packages.map((item) => `${item.kind}:${item.name}@${item.version}`).join(', ')}`, + ); + } + inventory.push({ + product, + packages: registryInventoryPackages(packages, `${product}.packages`), + missing: registryInventoryPackages(missing, `${product}.missing`), + published: registryInventoryPackages(published, `${product}.published`), + }); + } + return { + schema: REGISTRY_INVENTORY_SCHEMA, + source: { commit: headCommit }, + products: [...products], + results: inventory, + }; +} + +async function validateReleasedDependencyArtifacts(consumer, dependency, dependencyVersion, graph) { + const dependencyConfig = graph.products[dependency]; + if ( + dependencyConfig === null || + Array.isArray(dependencyConfig) || + typeof dependencyConfig !== 'object' + ) { + fail(`${consumer} declares unknown release dependency ${dependency}`); + } + const targets = assertStringList( + dependencyConfig.publish_targets ?? [], + `${dependency}.publish_targets`, + ); + const registryTargets = targets.filter((target) => REGISTRY_TARGETS.has(target)); + if (registryTargets.length > 0) { + await checkRegistryPublication([ + '--product', + dependency, + '--require-published', + '--version', + dependencyVersion, + ]); + } + if (targets.includes('github-release-assets')) { + await verifyReleaseAssets( + dependency, + dependencyVersion, + await expectedAssets(dependency, dependencyVersion), + ); + } +} + +async function validateDependencyTag(consumer, dependency, dependencyVersion, graph, selected) { + parseStableVersion(dependencyVersion); + if ( + selectedDependencySatisfiesPin( + selected, + dependency, + dependencyVersion, + selected.has(dependency) ? await currentVersion(dependency) : undefined, + ) + ) { + return; + } + const dependencyConfig = graph.products[dependency]; + if ( + dependencyConfig === null || + Array.isArray(dependencyConfig) || + typeof dependencyConfig !== 'object' + ) { + fail(`${consumer} declares unknown release dependency ${dependency}`); + } + if (typeof dependencyConfig.tag_prefix !== 'string' || dependencyConfig.tag_prefix.length === 0) { + fail(`${dependency} must declare tag_prefix`); + } + const tag = `${dependencyConfig.tag_prefix}${dependencyVersion}`; + if (!tagExists(tag)) { + fail( + `${consumer} depends on ${dependency} ${dependencyVersion}, but release tag ${tag} does not exist; ` + + `publish that exact dependency version first or select ${dependency} at ${dependencyVersion}`, + ); + } + await validateReleasedDependencyArtifacts(consumer, dependency, dependencyVersion, graph); +} + +export function selectedDependencySatisfiesPin( + selected, + dependency, + pinnedVersion, + selectedVersion, +) { + return selected.has(dependency) && selectedVersion === pinnedVersion; +} + +async function validateReleaseDependencies(products, graph) { + const selected = new Set(products); + const entries = compatibilityVersionEntries(graph.products, { + requireSourceProduct: true, + prefix: TOOL, + }); + for (const product of products) { + const dependencies = new Map(); + for (const entry of entries.filter(({ product: owner }) => owner === product)) { + const version = compatibilityVersionValue(entry, { prefix: TOOL }); + const existing = dependencies.get(entry.sourceProduct); + if (existing !== undefined && existing !== version) { + fail(`${product} declares conflicting versions of ${entry.sourceProduct}`); + } + dependencies.set(entry.sourceProduct, version); + } + for (const [dependency, dependencyVersion] of dependencies) { + await validateDependencyTag(product, dependency, dependencyVersion, graph, selected); + } + } +} + +function parseArgs(argv) { + const args = { + productsJson: undefined, + headRef: 'HEAD', + checkRegistries: false, + registryInventoryOutput: '', + }; + for (let index = 0; index < argv.length; index += 1) { + const value = argv[index]; + if (value === '--products-json') { + if (index + 1 >= argv.length) { + fail('--products-json requires a value'); + } + args.productsJson = argv[index + 1]; + index += 1; + } else if (value.startsWith('--products-json=')) { + args.productsJson = value.slice('--products-json='.length); + } else if (value === '--head-ref') { + if (index + 1 >= argv.length) { + fail('--head-ref requires a value'); + } + args.headRef = argv[index + 1]; + index += 1; + } else if (value.startsWith('--head-ref=')) { + args.headRef = value.slice('--head-ref='.length); + } else if (value === '--check-registries') { + args.checkRegistries = true; + } else if (value === '--registry-inventory-output') { + if (index + 1 >= argv.length) { + fail('--registry-inventory-output requires a value'); + } + args.registryInventoryOutput = argv[index + 1]; + index += 1; + } else if (value.startsWith('--registry-inventory-output=')) { + args.registryInventoryOutput = value.slice('--registry-inventory-output='.length); + } else if (value === '-h' || value === '--help') { + console.log( + 'usage: tools/release/check_release_versions.mts [--products-json JSON] [--head-ref REF] [--check-registries] [--registry-inventory-output FILE]', + ); + process.exit(0); + } else { + fail(`unknown argument ${value}`); + } + } + return args; +} + +async function main(argv) { + const args = parseArgs(argv); + if ( + !/^[0-9a-f]{40}$/u.test(process.env.RELEASE_HEAD_COMMIT ?? '') || + !process.env.RELEASE_TAG_REFS || + !process.env.RELEASE_TAG_COMMITS + ) { + fail('use check-release-versions.sh to read the checked-out Git state'); + } + git = { + headCommit: process.env.RELEASE_HEAD_COMMIT, + refs: parseTagRefs(readFileSync(process.env.RELEASE_TAG_REFS, 'utf8')), + commits: parseTagCommits(readFileSync(process.env.RELEASE_TAG_COMMITS, 'utf8')), + }; + const graph = { products: loadProducts() }; + const selected = parseProducts(args.productsJson, graph); + if (args.registryInventoryOutput && !args.checkRegistries) { + fail('--registry-inventory-output requires --check-registries'); + } + const currentTagAtHead = {}; + for (const product of selected) { + currentTagAtHead[product] = validateVersionTags( + product, + await currentVersion(product), + graph.products[product], + git, + ); + } + await validateReleaseDependencies(selected, graph); + if (args.checkRegistries) { + const inventory = await validateRegistryPublication( + selected, + graph, + currentTagAtHead, + args.headRef, + ); + if (args.registryInventoryOutput) { + const output = path.resolve(ROOT, args.registryInventoryOutput); + mkdirSync(path.dirname(output), { recursive: true }); + writeFileSync(output, `${JSON.stringify(inventory, null, 2)}\n`, { + encoding: 'utf8', + flag: 'wx', + mode: 0o644, + }); + } + } + console.log('release version checks passed'); +} + +if (import.meta.main) { + await main(Bun.argv.slice(2)); +} diff --git a/tools/release/close-release-candidate.sh b/tools/release/close-release-candidate.sh new file mode 100644 index 000000000..533106fd1 --- /dev/null +++ b/tools/release/close-release-candidate.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +[[ $# == 1 ]] || { + echo 'usage: close-release-candidate.sh OUTPUT_DIRECTORY' >&2 + exit 2 +} +[[ "$(cat "$1/required")" == true ]] || exit 0 +title="$(cat "$1/title")" +git config user.name "$(bun -p 'require("./tools/release/release-bot.json").name')" +git config user.email "$(bun -p 'require("./tools/release/release-bot.json").email')" +git add -A +git commit -m "$title" +bash tools/release/sync-release-pr.sh +if [[ -n "$(git status --porcelain --untracked-files=all)" ]]; then + git add -A + git commit --amend --no-edit +fi +products="$(bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" HEAD tools/dev/bun.sh tools/release/verify-release-commit.mts --derive-products --head-ref HEAD)" +bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" HEAD tools/dev/bun.sh tools/release/verify-release-commit.mts --products-json "$products" --head-ref HEAD +bash tools/release/release-metadata-check.sh --publication diff --git a/tools/release/compatibility-version-policy.mjs b/tools/release/compatibility-version-policy.mjs deleted file mode 100644 index 1d8c89884..000000000 --- a/tools/release/compatibility-version-policy.mjs +++ /dev/null @@ -1,121 +0,0 @@ -import { - EMPTY_TREE, - ROOT, - commitForRef, - latestProductTag, - productVersionTransitionStatus, -} from "./release-graph.mjs"; - -function policyError(prefix, message) { - return new Error(`${prefix}: ${message}`); -} - -function stableVersion(value, context, prefix) { - const match = /^(0|[1-9][0-9]*)[.](0|[1-9][0-9]*)[.](0|[1-9][0-9]*)$/u.exec(value); - if (match === null) { - throw policyError(prefix, `${context} must be a stable x.y.z version, got ${JSON.stringify(value)}`); - } - return match.slice(1).map((part) => Number.parseInt(part, 10)); -} - -function compareVersions(left, right) { - for (let index = 0; index < left.length; index += 1) { - if (left[index] !== right[index]) return left[index] - right[index]; - } - return 0; -} - -/** - * Choose the immutable source of a compatibility field. A sink whose manifest - * is pending from the latest verified release commit follows the current - * source product. Every unchanged released sink follows its own immutable - * current tag, regardless of whether it is an extension, runtime, or SDK. - */ -export function compatibilityVersionSource( - entry, - products, - pendingVersions, - { - root = ROOT, - headRef = "HEAD", - pendingCommit = headRef, - prefix = "compatibility-version-policy", - } = {}, -) { - const sink = products[entry.product]; - if (sink === undefined) { - throw policyError(prefix, `compatibility sink ${entry.product} is not a release product`); - } - if (sink.version === "0.0.0") { - return { kind: "current-source", ref: null, tag: null }; - } - const baseRef = latestProductTag(sink, headRef, prefix, root); - const status = productVersionTransitionStatus(entry.product, sink, baseRef, headRef, { - prefix, - root, - }); - if (status.currentTagCommit !== null) { - const headCommit = commitForRef(headRef, root); - if ( - pendingVersions.get(entry.product) === sink.version && - commitForRef(pendingCommit, root) === headCommit - ) { - if (status.currentTagCommit !== headCommit) { - throw policyError( - prefix, - `${entry.product} cannot advance to already-tagged immutable version ${sink.version} from ${status.currentTag}`, - ); - } - return { kind: "current-source", ref: null, tag: null }; - } - return { - kind: "tagged-sink", - ref: status.currentTagCommit, - tag: status.currentTag, - }; - } - - if (pendingVersions.get(entry.product) === sink.version) { - if (!status.eligible && !status.firstRelease) { - throw policyError( - prefix, - `${entry.product} advanced in its verified release commit without an eligible version transition`, - ); - } - return { kind: "current-source", ref: null, tag: null }; - } - - const prior = baseRef === EMPTY_TREE ? "no prior product tag" : `latest reachable tag ${baseRef}`; - throw policyError( - prefix, - `${entry.product} version ${sink.version} has no immutable current-version tag and is not pending from a verified release commit (${prior})`, - ); -} - -export function requireCompatibilityVersionBinding( - { - id, - value, - expected, - sourceProduct, - sourceVersion, - provenance, - }, - { prefix = "compatibility-version-policy" } = {}, -) { - const valueParts = stableVersion(value, `${id} compatibility value`, prefix); - const sourceParts = stableVersion(sourceVersion, `${sourceProduct} version`, prefix); - stableVersion(expected, `${id} expected compatibility value`, prefix); - if (compareVersions(valueParts, sourceParts) > 0) { - throw policyError( - prefix, - `${id} compatibility value ${JSON.stringify(value)} cannot be newer than ${sourceProduct} ${sourceVersion}`, - ); - } - if (value !== expected) { - throw policyError( - prefix, - `${id} compatibility value ${JSON.stringify(value)} must match ${provenance}`, - ); - } -} diff --git a/tools/release/compatibility-version-policy.mts b/tools/release/compatibility-version-policy.mts new file mode 100644 index 000000000..29caeddc2 --- /dev/null +++ b/tools/release/compatibility-version-policy.mts @@ -0,0 +1,124 @@ +import { + EMPTY_TREE, + ROOT, + commitForRef, + latestProductTag, + productVersionTransitionStatus, +} from './release-graph.mts'; + +function policyError(prefix, message) { + return new Error(`${prefix}: ${message}`); +} + +function stableVersion(value, context, prefix) { + const match = /^(0|[1-9][0-9]*)[.](0|[1-9][0-9]*)[.](0|[1-9][0-9]*)$/u.exec(value); + if (match === null) { + throw policyError( + prefix, + `${context} must be a stable x.y.z version, got ${JSON.stringify(value)}`, + ); + } + return match.slice(1).map((part) => Number.parseInt(part, 10)); +} + +function compareVersions(left, right) { + for (let index = 0; index < left.length; index += 1) { + if (left[index] !== right[index]) return left[index] - right[index]; + } + return 0; +} + +/** + * Choose the immutable source of a compatibility field. A sink whose manifest + * is pending from the latest verified release commit follows the current + * source product. Every unchanged released sink follows its own immutable + * current tag, regardless of whether it is an extension, runtime, or SDK. + */ +export function compatibilityVersionSource( + entry, + products, + pendingVersions, + { + root = ROOT, + headRef = 'HEAD', + pendingCommit = headRef, + prefix = 'compatibility-version-policy', + } = {}, +) { + const sink = products[entry.product]; + if (sink === undefined) { + throw policyError(prefix, `compatibility sink ${entry.product} is not a release product`); + } + if (sink.version === '0.0.0') { + return { kind: 'current-source', ref: null, tag: null }; + } + const baseRef = latestProductTag(sink, headRef, prefix, root); + const status = productVersionTransitionStatus(entry.product, sink, baseRef, headRef, { + prefix, + root, + }); + if (status.currentTagCommit !== null) { + const headCommit = commitForRef(headRef, root); + if ( + pendingVersions.get(entry.product) === sink.version && + commitForRef(pendingCommit, root) === headCommit + ) { + if (status.currentTagCommit !== headCommit) { + throw policyError( + prefix, + `${entry.product} cannot advance to already-tagged immutable version ${sink.version} from ${status.currentTag}`, + ); + } + return { kind: 'current-source', ref: null, tag: null }; + } + return { + kind: 'tagged-sink', + ref: status.currentTagCommit, + tag: status.currentTag, + }; + } + + if (pendingVersions.get(entry.product) === sink.version) { + if (!status.eligible && !status.firstRelease) { + throw policyError( + prefix, + `${entry.product} advanced in its verified release commit without an eligible version transition`, + ); + } + return { kind: 'current-source', ref: null, tag: null }; + } + + const prior = baseRef === EMPTY_TREE ? 'no prior product tag' : `latest reachable tag ${baseRef}`; + throw policyError( + prefix, + `${entry.product} version ${sink.version} has no immutable current-version tag and is not pending from a verified release commit (${prior})`, + ); +} + +export function requireCompatibilityVersionBounds( + { id, value, sourceProduct, sourceVersion }, + { prefix = 'compatibility-version-policy' } = {}, +) { + const valueParts = stableVersion(value, `${id} compatibility value`, prefix); + const sourceParts = stableVersion(sourceVersion, `${sourceProduct} version`, prefix); + if (compareVersions(valueParts, sourceParts) > 0) { + throw policyError( + prefix, + `${id} compatibility value ${JSON.stringify(value)} cannot be newer than ${sourceProduct} ${sourceVersion}`, + ); + } +} + +export function requireCompatibilityVersionBinding( + { id, value, expected, sourceProduct, sourceVersion, provenance }, + { prefix = 'compatibility-version-policy' } = {}, +) { + requireCompatibilityVersionBounds({ id, value, sourceProduct, sourceVersion }, { prefix }); + stableVersion(expected, `${id} expected compatibility value`, prefix); + if (value !== expected) { + throw policyError( + prefix, + `${id} compatibility value ${JSON.stringify(value)} must match ${provenance}`, + ); + } +} diff --git a/tools/release/compatibility-version-policy.test.mjs b/tools/release/compatibility-version-policy.test.mjs deleted file mode 100644 index c207c95e1..000000000 --- a/tools/release/compatibility-version-policy.test.mjs +++ /dev/null @@ -1,332 +0,0 @@ -import assert from "node:assert/strict"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - compatibilityVersionSource, - requireCompatibilityVersionBinding, -} from "./compatibility-version-policy.mjs"; - -const NATIVE = "liboliphaunt-native"; -const CONTRIB = "oliphaunt-extension-amcheck"; -const EXTERNAL = "oliphaunt-extension-vector"; -const SDK = "oliphaunt-js"; -const RUNTIME_CONSUMER = "oliphaunt-node-direct"; -const PATHS = { - [NATIVE]: "packages/native", - [CONTRIB]: "packages/amcheck", - [EXTERNAL]: "packages/vector", - [SDK]: "packages/js", - [RUNTIME_CONSUMER]: "packages/node-direct", -}; -const EXTERNAL_ENTRY = { - id: "vector-native-runtime", - product: EXTERNAL, - sourceProduct: NATIVE, - path: `${PATHS[EXTERNAL]}/release.toml`, - parser: "toml:compatibility.native", -}; - -function git(root, ...args) { - return execFileSync("git", args, { cwd: root, encoding: "utf8" }).trim(); -} - -function writeState(root, versions, { compatibilityByProduct = {} } = {}) { - const releaseManifest = {}; - for (const [product, packagePath] of Object.entries(PATHS)) { - const directory = path.join(root, packagePath); - mkdirSync(directory, { recursive: true }); - writeFileSync(path.join(directory, "VERSION"), `${versions[product]}\n`); - const compatibility = compatibilityByProduct[product] ?? versions[NATIVE]; - writeFileSync(path.join(directory, "release.toml"), `[compatibility]\nnative = ${JSON.stringify(compatibility)}\n`); - releaseManifest[packagePath] = versions[product]; - } - writeFileSync( - path.join(root, ".release-please-manifest.json"), - `${JSON.stringify(releaseManifest, null, 2)}\n`, - ); -} - -function commit(root, subject) { - git(root, "add", "."); - git(root, "commit", "-m", subject); - return git(root, "rev-parse", "HEAD"); -} - -function fixture(t, versions) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-compatibility-policy-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - git(root, "init", "-q"); - git(root, "config", "user.name", "Release Test"); - git(root, "config", "user.email", "release-test@example.invalid"); - writeFileSync(path.join(root, "legacy.txt"), "legacy\n"); - commit(root, "legacy history"); - writeState(root, versions); - commit(root, "release state"); - return root; -} - -function products(versions) { - return { - [NATIVE]: { - path: PATHS[NATIVE], - tag_prefix: `${NATIVE}-v`, - version: versions[NATIVE], - version_files: [`${PATHS[NATIVE]}/VERSION`], - }, - [CONTRIB]: { - path: PATHS[CONTRIB], - tag_prefix: `${CONTRIB}-v`, - version: versions[CONTRIB], - version_files: [`${PATHS[CONTRIB]}/VERSION`], - extension: { class: "contrib" }, - }, - [EXTERNAL]: { - path: PATHS[EXTERNAL], - tag_prefix: `${EXTERNAL}-v`, - version: versions[EXTERNAL], - version_files: [`${PATHS[EXTERNAL]}/VERSION`], - extension: { class: "external" }, - }, - [SDK]: { - path: PATHS[SDK], - tag_prefix: `${SDK}-v`, - version: versions[SDK], - version_files: [`${PATHS[SDK]}/VERSION`], - kind: "sdk", - }, - [RUNTIME_CONSUMER]: { - path: PATHS[RUNTIME_CONSUMER], - tag_prefix: `${RUNTIME_CONSUMER}-v`, - version: versions[RUNTIME_CONSUMER], - version_files: [`${PATHS[RUNTIME_CONSUMER]}/VERSION`], - kind: "runtime", - }, - }; -} - -const ZERO = Object.fromEntries(Object.keys(PATHS).map((product) => [product, "0.0.0"])); -const V1 = Object.fromEntries(Object.keys(PATHS).map((product) => [product, "1.0.0"])); - -function pending(versions, ...productIds) { - return new Map(productIds.map((product) => [product, versions[product]])); -} - -test("an untagged external in the first release follows the current runtime", (t) => { - const root = fixture(t, ZERO); - const released = Object.fromEntries(Object.keys(PATHS).map((product) => [product, "0.1.0"])); - writeState(root, released); - commit(root, "chore(release): first release"); - - assert.deepEqual( - compatibilityVersionSource(EXTERNAL_ENTRY, products(released), pending(released, EXTERNAL), { - root, - prefix: "compatibility-test", - }), - { kind: "current-source", ref: null, tag: null }, - ); - assert.throws( - () => compatibilityVersionSource(EXTERNAL_ENTRY, products(released), new Map([[EXTERNAL, "1.2.0"]]), { - root, - prefix: "compatibility-test", - }), - /is not pending from a verified release commit/u, - ); -}); - -test("an unchanged independently versioned external is bound to its immutable current tag", (t) => { - const root = fixture(t, V1); - const taggedCommit = git(root, "rev-parse", "HEAD"); - git(root, "tag", `${EXTERNAL}-v1.0.0`); - const released = { ...V1, [NATIVE]: "1.1.0", [CONTRIB]: "1.1.0" }; - writeState(root, released, { compatibilityByProduct: { [EXTERNAL]: "1.0.0" } }); - commit(root, "chore(release): runtime release"); - - assert.deepEqual( - compatibilityVersionSource(EXTERNAL_ENTRY, products(released), pending(released, NATIVE, CONTRIB), { - root, - prefix: "compatibility-test", - }), - { kind: "tagged-sink", ref: taggedCommit, tag: `${EXTERNAL}-v1.0.0` }, - ); -}); - -test("a newly bumped external without its not-yet-created tag follows the current runtime", (t) => { - const root = fixture(t, V1); - git(root, "tag", `${EXTERNAL}-v1.0.0`); - const released = { ...V1, [EXTERNAL]: "1.1.0" }; - writeState(root, released); - commit(root, "chore(release): vector release"); - - assert.deepEqual( - compatibilityVersionSource(EXTERNAL_ENTRY, products(released), pending(released, EXTERNAL), { - root, - prefix: "compatibility-test", - }), - { kind: "current-source", ref: null, tag: null }, - ); -}); - -test("an unchanged released external without its current immutable tag fails closed", (t) => { - const root = fixture(t, V1); - assert.throws( - () => compatibilityVersionSource(EXTERNAL_ENTRY, products(V1), new Map(), { - root, - prefix: "compatibility-test", - }), - /version 1[.]0[.]0 has no immutable current-version tag and is not pending from a verified release commit/u, - ); -}); - -test("a current-version tag whose manifest names another version fails closed", (t) => { - const mismatched = { ...V1, [EXTERNAL]: "0.9.0" }; - const root = fixture(t, mismatched); - git(root, "tag", `${EXTERNAL}-v1.0.0`); - writeState(root, V1); - commit(root, "chore(release): vector 1.0.0"); - - assert.throws( - () => compatibilityVersionSource(EXTERNAL_ENTRY, products(V1), pending(V1, EXTERNAL), { - root, - prefix: "compatibility-test", - }), - /tag .* names 1[.]0[.]0, but its manifest contains "0[.]9[.]0"/u, - ); -}); - -test("a current-version tag on unrelated history fails closed", (t) => { - const root = fixture(t, V1); - const candidate = git(root, "rev-parse", "HEAD"); - git(root, "checkout", "-q", "--orphan", "collision"); - git(root, "rm", "-q", "-rf", "."); - writeState(root, V1); - commit(root, "unrelated vector identity"); - git(root, "tag", `${EXTERNAL}-v1.0.0`); - git(root, "checkout", "-q", "--detach", candidate); - - assert.throws( - () => compatibilityVersionSource(EXTERNAL_ENTRY, products(V1), new Map(), { - root, - headRef: candidate, - prefix: "compatibility-test", - }), - /current-version tag .* is not an ancestor of release candidate/u, - ); -}); - -test("a release commit cannot reuse a current-version tag from an ancestor", (t) => { - const root = fixture(t, V1); - git(root, "tag", `${EXTERNAL}-v1.0.0`); - const regressed = { ...V1, [EXTERNAL]: "0.9.0" }; - writeState(root, regressed); - commit(root, "regress vector identity"); - writeState(root, V1); - commit(root, "chore(release): reuse vector 1.0.0"); - - assert.throws( - () => compatibilityVersionSource(EXTERNAL_ENTRY, products(V1), pending(V1, EXTERNAL), { - root, - prefix: "compatibility-test", - }), - /cannot advance to already-tagged immutable version 1[.]0[.]0/u, - ); -}); - -test("unchanged SDK and runtime consumer sinks remain bound to their immutable product tags", (t) => { - const root = fixture(t, V1); - const taggedCommit = git(root, "rev-parse", "HEAD"); - for (const product of [SDK, RUNTIME_CONSUMER]) git(root, "tag", `${product}-v1.0.0`); - const released = { ...V1, [NATIVE]: "1.1.0", [CONTRIB]: "1.1.0" }; - writeState(root, released, { - compatibilityByProduct: { - [SDK]: "1.0.0", - [RUNTIME_CONSUMER]: "1.0.0", - }, - }); - commit(root, "chore(release): runtime release"); - - for (const product of [SDK, RUNTIME_CONSUMER]) { - assert.deepEqual( - compatibilityVersionSource({ ...EXTERNAL_ENTRY, product }, products(released), pending(released, NATIVE, CONTRIB), { - root, - prefix: "compatibility-test", - }), - { kind: "tagged-sink", ref: taggedCommit, tag: `${product}-v1.0.0` }, - ); - } -}); - -test("a newly bumped SDK without its not-yet-created tag follows the current source", (t) => { - const root = fixture(t, V1); - git(root, "tag", `${SDK}-v1.0.0`); - const released = { ...V1, [SDK]: "1.1.0" }; - writeState(root, released); - commit(root, "chore(release): JS SDK release"); - - assert.deepEqual( - compatibilityVersionSource({ ...EXTERNAL_ENTRY, product: SDK }, products(released), pending(released, SDK), { - root, - prefix: "compatibility-test", - }), - { kind: "current-source", ref: null, tag: null }, - ); -}); - -test("a transitioned contrib sink follows current source, then binds to its tag on ordinary commits", (t) => { - const root = fixture(t, V1); - git(root, "tag", `${CONTRIB}-v1.0.0`); - const released = { ...V1, [NATIVE]: "1.1.0", [CONTRIB]: "1.1.0" }; - writeState(root, released); - const releaseCommit = commit(root, "chore(release): runtime consumer release"); - const entry = { ...EXTERNAL_ENTRY, product: CONTRIB }; - - assert.deepEqual( - compatibilityVersionSource(entry, products(released), pending(released, NATIVE, CONTRIB), { - root, - prefix: "compatibility-test", - }), - { kind: "current-source", ref: null, tag: null }, - ); - - git(root, "tag", `${CONTRIB}-v1.1.0`); - writeFileSync(path.join(root, "ordinary-change.txt"), "ordinary change\n"); - commit(root, "docs: ordinary post-release commit"); - assert.deepEqual( - compatibilityVersionSource(entry, products(released), new Map(), { - root, - prefix: "compatibility-test", - }), - { kind: "tagged-sink", ref: releaseCommit, tag: `${CONTRIB}-v1.1.0` }, - ); -}); - -test("a tagged external compatibility field cannot drift with a later runtime release", () => { - assert.throws( - () => requireCompatibilityVersionBinding({ - id: EXTERNAL_ENTRY.id, - value: "1.1.0", - expected: "1.0.0", - sourceProduct: NATIVE, - sourceVersion: "1.1.0", - provenance: `immutable ${EXTERNAL} tag ${EXTERNAL}-v1.0.0`, - }, { prefix: "compatibility-test" }), - /compatibility value "1[.]1[.]0" must match immutable .* tag/u, - ); -}); - -test("a compatibility field cannot claim a future runtime version", () => { - assert.throws( - () => requireCompatibilityVersionBinding({ - id: EXTERNAL_ENTRY.id, - value: "2.0.0", - expected: "2.0.0", - sourceProduct: NATIVE, - sourceVersion: "1.1.0", - provenance: `${NATIVE} 2.0.0`, - }, { prefix: "compatibility-test" }), - /cannot be newer than liboliphaunt-native 1[.]1[.]0/u, - ); -}); diff --git a/tools/release/compatibility-version-policy.test.mts b/tools/release/compatibility-version-policy.test.mts new file mode 100644 index 000000000..ff0ac3b09 --- /dev/null +++ b/tools/release/compatibility-version-policy.test.mts @@ -0,0 +1,250 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { compatibilityVersionSource } from './compatibility-version-policy.mts'; + +import { + requireCompatibilityVersionBinding, + requireCompatibilityVersionBounds, +} from './compatibility-version-policy.mts'; + +const NATIVE = 'liboliphaunt-native'; +const CONTRIB = 'oliphaunt-extension-amcheck'; +const EXTERNAL = 'oliphaunt-extension-vector'; +const SDK = 'oliphaunt-js'; +const RUNTIME_CONSUMER = 'oliphaunt-node-direct'; +const PATHS = { + [NATIVE]: 'packages/native', + [CONTRIB]: 'packages/amcheck', + [EXTERNAL]: 'packages/vector', + [SDK]: 'packages/js', + [RUNTIME_CONSUMER]: 'packages/node-direct', +}; +const EXTERNAL_ENTRY = { + id: 'vector-native-runtime', + product: EXTERNAL, + sourceProduct: NATIVE, + path: `${PATHS[EXTERNAL]}/release.toml`, + parser: 'toml:compatibility.native', +}; + +function writeState(root, versions, { compatibilityByProduct = {} } = {}) { + const releaseManifest = {}; + for (const [product, packagePath] of Object.entries(PATHS)) { + const directory = path.join(root, packagePath); + mkdirSync(directory, { recursive: true }); + writeFileSync(path.join(directory, 'VERSION'), `${versions[product]}\n`); + const compatibility = compatibilityByProduct[product] ?? versions[NATIVE]; + writeFileSync( + path.join(directory, 'release.toml'), + `[compatibility]\nnative = ${JSON.stringify(compatibility)}\n`, + ); + releaseManifest[packagePath] = versions[product]; + } + writeFileSync( + path.join(root, '.release-please-manifest.json'), + `${JSON.stringify(releaseManifest, null, 2)}\n`, + ); +} + +function products(versions) { + return { + [NATIVE]: { + path: PATHS[NATIVE], + tag_prefix: `${NATIVE}-v`, + version: versions[NATIVE], + version_files: [`${PATHS[NATIVE]}/VERSION`], + }, + [CONTRIB]: { + path: PATHS[CONTRIB], + tag_prefix: `${CONTRIB}-v`, + version: versions[CONTRIB], + version_files: [`${PATHS[CONTRIB]}/VERSION`], + extension: { class: 'contrib' }, + }, + [EXTERNAL]: { + path: PATHS[EXTERNAL], + tag_prefix: `${EXTERNAL}-v`, + version: versions[EXTERNAL], + version_files: [`${PATHS[EXTERNAL]}/VERSION`], + extension: { class: 'external' }, + }, + [SDK]: { + path: PATHS[SDK], + tag_prefix: `${SDK}-v`, + version: versions[SDK], + version_files: [`${PATHS[SDK]}/VERSION`], + kind: 'sdk', + }, + [RUNTIME_CONSUMER]: { + path: PATHS[RUNTIME_CONSUMER], + tag_prefix: `${RUNTIME_CONSUMER}-v`, + version: versions[RUNTIME_CONSUMER], + version_files: [`${PATHS[RUNTIME_CONSUMER]}/VERSION`], + kind: 'runtime', + }, + }; +} + +const ZERO = Object.fromEntries(Object.keys(PATHS).map((product) => [product, '0.0.0'])); +const V1 = Object.fromEntries(Object.keys(PATHS).map((product) => [product, '1.0.0'])); + +const [phase, root, scenario, stage, graphPath, taggedCommit] = process.argv.slice(2); +const runtimeRelease = { ...V1, [NATIVE]: '1.1.0', [CONTRIB]: '1.1.0' }; +const released = + scenario === 'first' + ? Object.fromEntries(Object.keys(PATHS).map((product) => [product, '0.1.0'])) + : ['external-tag', 'consumer-tags', 'contrib'].includes(scenario) + ? runtimeRelease + : scenario === 'external-bump' + ? { ...V1, [EXTERNAL]: '1.1.0' } + : scenario === 'sdk-bump' + ? { ...V1, [SDK]: '1.1.0' } + : V1; +const current = products(released); +if (scenario === 'workspace') + current['postgres-tools-wasix'] = { + path: 'src/postgres-tools/wasix', + tag_prefix: 'postgres-tools-wasix-v', + version: '0.2.1', + version_files: ['src/postgres-tools/wasix/VERSION'], + }; +if (phase === 'write') { + const versions = + stage === 'zero' + ? ZERO + : stage === 'v1' + ? V1 + : stage === 'mismatch' + ? { ...V1, [EXTERNAL]: '0.9.0' } + : released; + const compatibilityByProduct = + scenario === 'external-tag' + ? { [EXTERNAL]: '1.0.0' } + : scenario === 'consumer-tags' + ? { [SDK]: '1.0.0', [RUNTIME_CONSUMER]: '1.0.0' } + : {}; + writeState(root, versions, { compatibilityByProduct }); + writeFileSync(graphPath, JSON.stringify({ products: current })); +} else if (phase === 'workspace') { + mkdirSync(path.join(root, 'src/postgres-tools/wasix'), { recursive: true }); + writeFileSync(path.join(root, 'src/postgres-tools/wasix/VERSION'), '0.2.1\n'); +} else if (phase === 'assert') { + const pending = (...ids) => new Map(ids.map((id) => [id, released[id]])); + const options = { root, prefix: 'compatibility-test' }; + const source = (entry = EXTERNAL_ENTRY, selected = new Map()) => + compatibilityVersionSource(entry, current, selected, options); + const currentSource = { kind: 'current-source', ref: null, tag: null }; + switch (scenario) { + case 'workspace': + assert.doesNotThrow(() => + requireCompatibilityVersionBounds({ + id: 'new-tools-runtime', + value: '1.0.0', + sourceProduct: NATIVE, + sourceVersion: '1.0.0', + }), + ); + assert.throws( + () => + source( + { ...EXTERNAL_ENTRY, product: 'postgres-tools-wasix', id: 'new-tools-runtime' }, + new Map([['postgres-tools-wasix', '0.2.1']]), + ), + /manifest version.*must be a stable.*undefined/u, + ); + break; + case 'first': + assert.deepEqual(source(EXTERNAL_ENTRY, pending(EXTERNAL)), currentSource); + assert.throws( + () => source(EXTERNAL_ENTRY, new Map([[EXTERNAL, '1.2.0']])), + /is not pending from a verified release commit/u, + ); + break; + case 'external-tag': + assert.deepEqual(source(EXTERNAL_ENTRY, pending(NATIVE, CONTRIB)), { + kind: 'tagged-sink', + ref: taggedCommit, + tag: `${EXTERNAL}-v1.0.0`, + }); + break; + case 'external-bump': + assert.deepEqual(source(EXTERNAL_ENTRY, pending(EXTERNAL)), currentSource); + break; + case 'missing': + assert.throws( + () => source(), + /version 1[.]0[.]0 has no immutable current-version tag and is not pending from a verified release commit/u, + ); + break; + case 'mismatch': + assert.throws( + () => source(EXTERNAL_ENTRY, pending(EXTERNAL)), + /tag .* names 1[.]0[.]0, but its manifest contains "0[.]9[.]0"/u, + ); + break; + case 'unrelated': + assert.throws( + () => source(), + /current-version tag .* is not an ancestor of release candidate/u, + ); + break; + case 'reused': + assert.throws( + () => source(EXTERNAL_ENTRY, pending(EXTERNAL)), + /cannot advance to already-tagged immutable version 1[.]0[.]0/u, + ); + break; + case 'consumer-tags': + for (const product of [SDK, RUNTIME_CONSUMER]) + assert.deepEqual(source({ ...EXTERNAL_ENTRY, product }, pending(NATIVE, CONTRIB)), { + kind: 'tagged-sink', + ref: taggedCommit, + tag: `${product}-v1.0.0`, + }); + break; + case 'sdk-bump': + assert.deepEqual(source({ ...EXTERNAL_ENTRY, product: SDK }, pending(SDK)), currentSource); + break; + case 'contrib': + assert.deepEqual( + source( + { ...EXTERNAL_ENTRY, product: CONTRIB }, + stage === 'tagged' ? new Map() : pending(NATIVE, CONTRIB), + ), + stage === 'tagged' + ? { kind: 'tagged-sink', ref: taggedCommit, tag: `${CONTRIB}-v1.1.0` } + : currentSource, + ); + break; + default: + throw new Error('unknown compatibility scenario'); + } + console.log(`compatibility ${scenario} ${stage}: passed`); +} else if (phase === 'bindings') { + assert.throws( + () => + requireCompatibilityVersionBinding({ + id: EXTERNAL_ENTRY.id, + value: '1.1.0', + expected: '1.0.0', + sourceProduct: NATIVE, + sourceVersion: '1.1.0', + provenance: `immutable ${EXTERNAL} tag ${EXTERNAL}-v1.0.0`, + }), + /compatibility value "1[.]1[.]0" must match immutable .* tag/u, + ); + assert.throws( + () => + requireCompatibilityVersionBinding({ + id: EXTERNAL_ENTRY.id, + value: '2.0.0', + expected: '2.0.0', + sourceProduct: NATIVE, + sourceVersion: '1.1.0', + provenance: `${NATIVE} 2.0.0`, + }), + /cannot be newer than liboliphaunt-native 1[.]1[.]0/u, + ); + console.log('compatibility value bounds and immutable binding: passed'); +} else throw new Error('run through compatibility-version-policy.test.sh'); diff --git a/tools/release/compatibility-version-policy.test.sh b/tools/release/compatibility-version-policy.test.sh new file mode 100644 index 000000000..73a6e67dc --- /dev/null +++ b/tools/release/compatibility-version-policy.test.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +if [[ -z "${OLIPHAUNT_RELEASE_PLEASE_STATE:-}" ]]; then + exec bash "$root/tools/release/release-please-state.sh" "$root" HEAD \ + bash "$root/tools/release/compatibility-version-policy.test.sh" +fi +scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-compatibility-policy.XXXXXX")" +trap 'rm -rf "$scratch"' EXIT +fixture="$root/tools/release/compatibility-version-policy.test.mts" +commit() { git -C "$repo" add .; git -C "$repo" commit -qm "$1"; } +write() { bash "$root/tools/dev/bun.sh" "$fixture" write "$repo" "$scenario" "$1" "$scratch/graph.json"; } +assert_history() { + bash "$root/tools/release/with-product-history.sh" "$repo" HEAD '' "$scratch/graph.json" \ + bash "$root/tools/dev/bun.sh" "$fixture" assert "$repo" "$scenario" "$1" "$scratch/graph.json" "$2" +} +for scenario in workspace first external-tag external-bump missing mismatch unrelated reused consumer-tags sdk-bump contrib; do + repo="$scratch/$scenario" + git init -q "$repo" + git -C "$repo" config user.name 'Release Test' + git -C "$repo" config user.email release-test@example.invalid + printf 'legacy\n' > "$repo/legacy.txt" + commit 'legacy history' + case "$scenario" in first) write zero ;; mismatch) write mismatch ;; *) write v1 ;; esac + commit 'release state' + tagged="$(git -C "$repo" rev-parse HEAD)" + case "$scenario" in + workspace) + bash "$root/tools/dev/bun.sh" "$fixture" workspace "$repo" "$scenario" ;; + first) write released; commit 'chore(release): first release' ;; + external-tag|external-bump|mismatch) + git -C "$repo" tag oliphaunt-extension-vector-v1.0.0 + write released + commit 'chore(release): product release' ;; + unrelated) + git -C "$repo" checkout -q --orphan collision + git -C "$repo" rm -qrf . + write v1 + commit 'unrelated vector identity' + git -C "$repo" tag oliphaunt-extension-vector-v1.0.0 + git -C "$repo" checkout -q --detach "$tagged" ;; + reused) + git -C "$repo" tag oliphaunt-extension-vector-v1.0.0 + write mismatch + commit 'regress vector identity' + write v1 + commit 'chore(release): reuse vector 1.0.0' ;; + consumer-tags) + git -C "$repo" tag oliphaunt-js-v1.0.0 + git -C "$repo" tag oliphaunt-node-direct-v1.0.0 + write released + commit 'chore(release): runtime release' ;; + sdk-bump) + git -C "$repo" tag oliphaunt-js-v1.0.0 + write released + commit 'chore(release): JS SDK release' ;; + contrib) + git -C "$repo" tag oliphaunt-extension-amcheck-v1.0.0 + write released + commit 'chore(release): runtime consumer release' ;; + esac + assert_history pending "$tagged" + if [[ "$scenario" == contrib ]]; then + tagged="$(git -C "$repo" rev-parse HEAD)" + git -C "$repo" tag oliphaunt-extension-amcheck-v1.1.0 + printf 'ordinary change\n' > "$repo/ordinary-change.txt" + commit 'docs: ordinary post-release commit' + assert_history tagged "$tagged" + fi +done +bash "$root/tools/dev/bun.sh" "$fixture" bindings diff --git a/tools/release/completed-bootstrap.test.mjs b/tools/release/completed-bootstrap.test.mjs deleted file mode 100644 index a26c9c946..000000000 --- a/tools/release/completed-bootstrap.test.mjs +++ /dev/null @@ -1,110 +0,0 @@ -import assert from "node:assert/strict"; -import { mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; -import { restoreCompletedBootstrap, isCompletedMainRelease } from "../../.github/scripts/download-completed-bootstrap.mjs"; -import { appendBootstrapCheckpoint, buildBootstrapLedger, loadBootstrapLedger } from "./bootstrap-ledger.mjs"; - -const repo = "f0rr0/oliphaunt"; -const lock = { - lockDigest: "a".repeat(64), catalogDigest: "b".repeat(64), packageEnvelopeDigest: "c".repeat(64), - source: { commit: "1".repeat(40), tree: "2".repeat(40) }, products: [{ id: "alpha" }], - carriers: [{ id: "cargo:alpha", product: "alpha", ecosystem: "cargo", name: "alpha", version: "1.0.0", - role: "platform-leaf", target: "linux", publishOrder: 0, - artifacts: [{ path: "target/alpha.crate", sha256: "d".repeat(64), size: 42 }] }], -}; -const run = { - id: 123, status: "completed", conclusion: "success", event: "workflow_dispatch", head_branch: "main", - path: ".github/workflows/release.yml", repository: { full_name: repo }, head_repository: { full_name: repo }, - head_sha: "3".repeat(40), -}; - -test("completed bootstrap discovery requires canonical successful main workflow origin", () => { - assert.equal(isCompletedMainRelease(run, repo), true); - for (const change of [ - { conclusion: "failure" }, { status: "in_progress" }, { event: "pull_request" }, - { head_branch: "other" }, { path: ".github/workflows/other.yml" }, - { repository: { full_name: "fork/oliphaunt" } }, { head_repository: { full_name: "fork/oliphaunt" } }, - { head_sha: "main" }, { id: -1 }, - ]) assert.equal(isCompletedMainRelease({ ...run, ...change }, repo), false); -}); - -test("new publisher reuses a completed older bootstrap, rejecting incomplete, corrupt, and wrong evidence", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "completed-bootstrap-")); - const destination = path.join(root, "ledger"); - let mode = "complete"; - let sourceChecks = 0; - const artifact = { id: 456, name: "oliphaunt-bootstrap-ledger", expired: false, digest: "sha256:" + "e".repeat(64), size_in_bytes: 42 }; - const dependencies = { - list: (endpoint) => endpoint.includes("/artifacts") ? [artifact] : [run], - assertSource: (observed) => { - assert.equal(observed.head_sha, run.head_sha); - sourceChecks++; - if (mode === "source") throw new Error("non-publication changes"); - }, - download: (observed, envelope, directory) => { - assert.equal(observed.id, run.id); - assert.equal(envelope.id, artifact.id); - const input = structuredClone(lock); - if (mode === "wrong-lock") input.lockDigest = "f".repeat(64); - if (mode === "wrong-source") input.source.commit = "9".repeat(40); - appendBootstrapCheckpoint(directory, input, ["alpha"], []); - if (mode !== "incomplete") { - const publication = buildBootstrapLedger(input, ["alpha"]).publications[0]; - appendBootstrapCheckpoint(directory, input, ["alpha"], [{ - id: publication.id, product: publication.product, ecosystem: publication.ecosystem, - name: publication.name, version: publication.version, lockedArtifacts: publication.artifacts, - registryProof: { ...publication.registryExpectation, url: "https://crates.io/api/v1/crates/alpha/1.0.0" }, - }]); - } - if (mode === "corrupt") { - const file = path.join(directory, readdirSync(directory).sort()[1]); - const checkpoint = JSON.parse(readFileSync(file, "utf8")); - checkpoint.receipts[0].registryProof.digest = "f".repeat(64); - writeFileSync(file, JSON.stringify(checkpoint)); - } - if (mode === "extra") writeFileSync(path.join(directory, "unexpected"), "bytes"); - }, - }; - try { - assert.equal(restoreCompletedBootstrap({ repo, lock, destination }, dependencies), run.id); - assert.equal(sourceChecks, 1); - const before = loadBootstrapLedger(destination, lock, ["alpha"], { requireComplete: true }).checkpointDigest; - for (const [value, pattern] of [ - ["incomplete", /incomplete/u], ["corrupt", /digest mismatch/u], ["wrong-lock", /no completed main bootstrap/u], - ["wrong-source", /not bound/u], ["source", /non-publication changes/u], ["extra", /only checkpoint/u], - ]) { - mode = value; - assert.throws(() => restoreCompletedBootstrap({ repo, lock, destination }, dependencies), pattern); - assert.equal(loadBootstrapLedger(destination, lock, ["alpha"], { requireComplete: true }).checkpointDigest, before); - } - } finally { rmSync(root, { recursive: true, force: true }); } -}); - -test("release workflow scopes and refreshes tag tokens, and requires complete bootstrap evidence", () => { - const workflow = Bun.YAML.parse(readFileSync(".github/workflows/release.yml", "utf8")); - for (const [jobName, consumers] of [ - ["publish", { ensure_release_transport_ref: "release_tag_token", stage_github_releases: "release_tag_token", publish_swift_source_tag: "swift_tag_token" }], - ["publish-bootstrap", { ensure_bootstrap_transport_ref: "bootstrap_tag_token" }], - ]) { - const steps = workflow.jobs[jobName].steps; - for (const [consumerId, tokenId] of Object.entries(consumers)) { - const index = steps.findIndex(({ id }) => id === consumerId); - const tokenIndex = steps.findIndex(({ id }) => id === tokenId); - assert.ok(tokenIndex >= 0 && tokenIndex < index); - assert.match(steps[index].env.GH_TOKEN, new RegExp(`steps[.]${tokenId}[.]outputs[.]token`, "u")); - const token = steps[tokenIndex]; - assert.match(token.uses, /^actions\/create-github-app-token@[0-9a-f]{40}$/u); - assert.equal(token.with["permission-contents"], "write"); - assert.equal(token.with["permission-workflows"], "write"); - assert.equal(token.with.owner, "f0rr0"); - assert.equal(token.with.repositories, "oliphaunt"); - assert.equal(token.with["skip-token-revoke"], undefined); - } - } - const steps = workflow.jobs.publish.steps; - assert.ok(steps.findIndex(({ id }) => id === "check_release_tag_app") < steps.findIndex(({ name }) => name === "Require the explicitly approved dry-run candidate")); - assert.match(steps.find(({ name }) => name === "Download immutable registry bootstrap ledger").run, /download-completed-bootstrap/u); - assert.match(steps.find(({ name }) => name === "Verify immutable bootstrap ledger and registry existence").run, /--require-complete/u); -}); diff --git a/tools/release/completed-bootstrap.test.mts b/tools/release/completed-bootstrap.test.mts new file mode 100644 index 000000000..e66107758 --- /dev/null +++ b/tools/release/completed-bootstrap.test.mts @@ -0,0 +1,164 @@ +import assert from 'node:assert/strict'; +import { mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { + discoverCompletedBootstrap, + installCompletedBootstrap, + isCompletedMainRelease, +} from '../../.github/scripts/download-completed-bootstrap.mts'; +import { + appendBootstrapCheckpoint, + buildBootstrapLedger, + loadBootstrapLedger, +} from './bootstrap-ledger.mts'; + +const repo = 'f0rr0/oliphaunt'; +const lock = { + lockDigest: 'a'.repeat(64), + catalogDigest: 'b'.repeat(64), + packageEnvelopeDigest: 'c'.repeat(64), + source: { commit: '1'.repeat(40), tree: '2'.repeat(40) }, + products: [{ id: 'alpha' }], + carriers: [ + { + id: 'cargo:alpha', + product: 'alpha', + ecosystem: 'cargo', + name: 'alpha', + version: '1.0.0', + role: 'platform-leaf', + target: 'linux', + publishOrder: 0, + artifacts: [{ path: 'target/alpha.crate', sha256: 'd'.repeat(64), size: 42 }], + }, + ], +}; +const run = { + id: 123, + status: 'completed', + conclusion: 'success', + event: 'workflow_dispatch', + head_branch: 'main', + path: '.github/workflows/release.yml', + repository: { full_name: repo }, + head_repository: { full_name: repo }, + head_sha: '3'.repeat(40), +}; + +test('completed bootstrap discovery requires canonical successful main workflow origin', () => { + assert.equal(isCompletedMainRelease(run, repo), true); + for (const change of [ + { conclusion: 'failure' }, + { status: 'in_progress' }, + { event: 'pull_request' }, + { head_branch: 'other' }, + { path: '.github/workflows/other.yml' }, + { repository: { full_name: 'fork/oliphaunt' } }, + { head_repository: { full_name: 'fork/oliphaunt' } }, + { head_sha: 'main' }, + { id: -1 }, + ]) + assert.equal(isCompletedMainRelease({ ...run, ...change }, repo), false); +}); + +test('new publisher reuses a completed older bootstrap, rejecting incomplete, corrupt, and wrong evidence', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'completed-bootstrap-')); + const destination = path.join(root, 'ledger'); + let mode = 'complete'; + + const artifact = { + id: 456, + name: 'oliphaunt-bootstrap-ledger', + expired: false, + digest: 'sha256:' + 'e'.repeat(64), + size_in_bytes: 42, + }; + const dependencies = { + list: (endpoint) => (endpoint.includes('/artifacts') ? [artifact] : [run]), + download: (observed, envelope, directory) => { + assert.equal(observed.id, run.id); + assert.equal(envelope.id, artifact.id); + const input = structuredClone(lock); + if (mode === 'wrong-lock') input.lockDigest = 'f'.repeat(64); + if (mode === 'wrong-source') input.source.commit = '9'.repeat(40); + appendBootstrapCheckpoint(directory, input, ['alpha'], []); + if (mode !== 'incomplete') { + const publication = buildBootstrapLedger(input, ['alpha']).publications[0]; + appendBootstrapCheckpoint( + directory, + input, + ['alpha'], + [ + { + id: publication.id, + product: publication.product, + ecosystem: publication.ecosystem, + name: publication.name, + version: publication.version, + lockedArtifacts: publication.artifacts, + registryProof: { + ...publication.registryExpectation, + url: 'https://crates.io/api/v1/crates/alpha/1.0.0', + }, + }, + ], + ); + } + if (mode === 'corrupt') { + const file = path.join(directory, readdirSync(directory).sort()[1]); + const checkpoint = JSON.parse(readFileSync(file, 'utf8')); + checkpoint.receipts[0].registryProof.digest = 'f'.repeat(64); + writeFileSync(file, JSON.stringify(checkpoint)); + } + if (mode === 'extra') writeFileSync(path.join(directory, 'unexpected'), 'bytes'); + }, + }; + async function restore() { + const stage = path.join(root, 'stage'); + try { + const selected = await discoverCompletedBootstrap({ repo, lock, stage }, dependencies); + return installCompletedBootstrap({ + run: selected, + stage, + lock, + destination, + environment: { + OLIPHAUNT_PUBLICATION_CONTROLLER_JSON: JSON.stringify({ + source: lock.source.commit, + controller: mode === 'source' ? '0'.repeat(40) : selected.head_sha, + mode: 'changes', + }), + }, + }); + } finally { + rmSync(stage, { force: true, recursive: true }); + } + } + try { + assert.equal(await restore(), run.id); + + const before = loadBootstrapLedger(destination, lock, ['alpha'], { + requireComplete: true, + }).checkpointDigest; + for (const [value, pattern] of [ + ['incomplete', /incomplete/u], + ['corrupt', /digest mismatch/u], + ['wrong-lock', /no completed main bootstrap/u], + ['wrong-source', /not bound/u], + ['source', /matching proof/u], + ['extra', /only checkpoint/u], + ]) { + mode = value; + await assert.rejects(() => restore(), pattern); + assert.equal( + loadBootstrapLedger(destination, lock, ['alpha'], { requireComplete: true }) + .checkpointDigest, + before, + ); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/tools/release/concurrent-github-release-asset-upload.mjs b/tools/release/concurrent-github-release-asset-upload.mjs deleted file mode 100644 index 0d1229135..000000000 --- a/tools/release/concurrent-github-release-asset-upload.mjs +++ /dev/null @@ -1,256 +0,0 @@ -import { - mkdirSync, - renameSync, - rmSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -const FULL_SHA = /^[0-9a-f]{40}$/u; - -export class ConcurrentGithubReleaseAssetUploadError extends Error { - constructor(message, report, options = {}) { - super(`concurrent-github-release-asset-upload: ${message}`, options); - this.name = "ConcurrentGithubReleaseAssetUploadError"; - this.report = report; - } -} - -function error(message, report, options = {}) { - return new ConcurrentGithubReleaseAssetUploadError(message, report, options); -} - -function validatePlan(plan) { - if ( - plan === null - || Array.isArray(plan) - || typeof plan !== "object" - || !Array.isArray(plan.waves) - || !Number.isSafeInteger(plan.assetCount) - || plan.assetCount < 0 - || !Number.isSafeInteger(plan.productCount) - || plan.productCount < 0 - || (plan.waves.length === 0 && (plan.productCount !== 0 || plan.assetCount !== 0)) - || (plan.waves.length > 0 && plan.productCount < 1) - ) { - throw error("plan is malformed", null); - } - const products = new Set(); - let assetCount = 0; - for (const [waveIndex, wave] of plan.waves.entries()) { - if ( - wave === null - || Array.isArray(wave) - || typeof wave !== "object" - || !Array.isArray(wave.rows) - || wave.rows.length === 0 - || !Number.isSafeInteger(wave.windowMs) - || wave.windowMs < 1 - ) { - throw error(`wave ${waveIndex + 1} is malformed`, null); - } - let waveAssetCount = 0; - const waveProducts = []; - for (const row of wave.rows) { - if ( - row === null - || Array.isArray(row) - || typeof row !== "object" - || typeof row.product !== "string" - || row.product.length === 0 - || !Number.isSafeInteger(row.assetCount) - || row.assetCount < 0 - || products.has(row.product) - ) { - throw error(`wave ${waveIndex + 1} contains a malformed or duplicate product`, null); - } - products.add(row.product); - waveProducts.push(row.product); - waveAssetCount += row.assetCount; - } - if ( - wave.assetCount !== waveAssetCount - || !Array.isArray(wave.products) - || wave.products.length !== waveProducts.length - || wave.products.some((product, index) => product !== waveProducts[index]) - ) { - throw error(`wave ${waveIndex + 1} summary disagrees with its rows`, null); - } - assetCount += waveAssetCount; - } - if (products.size !== plan.productCount || assetCount !== plan.assetCount) { - throw error("plan product or asset count disagrees with its waves", null); - } -} - -function failureDetail(cause) { - if (cause instanceof Error) return cause.message; - return String(cause); -} - -function validateExecution(plan, execution) { - if ( - execution === null - || Array.isArray(execution) - || typeof execution !== "object" - || execution.assetCount !== plan.assetCount - || execution.productCount !== plan.productCount - || execution.waveCount !== plan.waves.length - || !Number.isSafeInteger(execution.completedWaves) - || execution.completedWaves < 0 - || execution.completedWaves > plan.waves.length - || !new Set(["failure", "success"]).has(execution.status) - || !Array.isArray(execution.products) - ) { - throw error("execution report is malformed or disagrees with its plan", execution); - } - const completedRows = plan.waves - .slice(0, execution.completedWaves) - .flatMap(({ rows }) => rows); - if ( - execution.products.length !== completedRows.length - || execution.products.some((outcome, index) => { - const row = completedRows[index]; - return outcome === null - || Array.isArray(outcome) - || typeof outcome !== "object" - || outcome.product !== row.product - || outcome.assetCount !== row.assetCount - || !new Set(["failure", "success"]).has(outcome.status); - }) - || (execution.status === "success" - && (execution.completedWaves !== plan.waves.length - || execution.products.some(({ status }) => status !== "success"))) - || (execution.status === "failure" - && !execution.products.some(({ status }) => status === "failure")) - ) { - throw error("execution outcomes do not exactly cover the completed plan waves", execution); - } -} - -export function writeConcurrentGithubReleaseAssetUploadReport( - file, - { execution, plan, sourceCommit }, -) { - if ( - typeof file !== "string" - || file.length === 0 - || file.includes("\0") - || typeof sourceCommit !== "string" - || !FULL_SHA.test(sourceCommit) - ) { - throw error("report requires a path and exact lowercase source commit", execution ?? null); - } - validatePlan(plan); - validateExecution(plan, execution); - const destination = path.resolve(file); - mkdirSync(path.dirname(destination), { recursive: true }); - const temporary = `${destination}.tmp-${process.pid}`; - try { - writeFileSync(temporary, `${JSON.stringify({ - execution, - plan, - schema: "oliphaunt-concurrent-github-release-asset-upload-report-v1", - sourceCommit, - }, null, 2)}\n`, { flag: "wx", mode: 0o600 }); - renameSync(temporary, destination); - } finally { - rmSync(temporary, { force: true }); - } -} - -export function githubReleaseAssetUploadChildEnvironment( - parentEnvironment, - { abortPath, windowMs }, -) { - if ( - parentEnvironment === null - || Array.isArray(parentEnvironment) - || typeof parentEnvironment !== "object" - || typeof abortPath !== "string" - || abortPath.length === 0 - || abortPath.includes("\0") - || !Number.isSafeInteger(windowMs) - || windowMs < 1 - ) { - throw error("child environment requires a parent environment, abort path, and positive window", null); - } - return { - ...parentEnvironment, - OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: String(windowMs), - OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH: abortPath, - }; -} - -/** - * Execute complete product waves. A lane failure publishes the shared abort - * signal immediately, but the current wave is always drained so an immutable - * upload already in flight can finish exact-state reconciliation. No later wave - * starts after any failure. - */ -export async function executeConcurrentGithubReleaseAssetUploadPlan( - plan, - { - abort = () => {}, - uploadProduct, - } = {}, -) { - validatePlan(plan); - if (typeof uploadProduct !== "function" || typeof abort !== "function") { - throw error("uploadProduct and abort must be functions", null); - } - const report = { - assetCount: plan.assetCount, - completedWaves: 0, - productCount: plan.productCount, - products: [], - status: "running", - waveCount: plan.waves.length, - }; - if (plan.waves.length === 0) { - report.status = "success"; - return report; - } - let aborted = false; - for (const [waveIndex, wave] of plan.waves.entries()) { - const outcomes = await Promise.all(wave.rows.map(async (row) => { - try { - const value = await uploadProduct(row, { - aborted: () => aborted, - wave, - waveIndex, - }); - return { assetCount: row.assetCount, product: row.product, status: "success", value }; - } catch (cause) { - const outcome = { - assetCount: row.assetCount, - detail: failureDetail(cause), - product: row.product, - status: "failure", - }; - if (!aborted) { - aborted = true; - try { - await abort(outcome); - } catch (abortCause) { - outcome.abortDetail = failureDetail(abortCause); - } - } - return outcome; - } - })); - report.products.push(...outcomes); - report.completedWaves += 1; - const failures = outcomes.filter(({ status }) => status === "failure"); - if (failures.length > 0) { - report.status = "failure"; - throw error( - `wave ${waveIndex + 1} failed after draining all in-flight lanes: ` - + failures.map(({ detail, product }) => `${product} (${detail})`).join(", "), - report, - ); - } - } - report.status = "success"; - return report; -} diff --git a/tools/release/concurrent-github-release-asset-upload.mts b/tools/release/concurrent-github-release-asset-upload.mts new file mode 100644 index 000000000..751238908 --- /dev/null +++ b/tools/release/concurrent-github-release-asset-upload.mts @@ -0,0 +1,258 @@ +import { mkdirSync, renameSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +const FULL_SHA = /^[0-9a-f]{40}$/u; + +export class ConcurrentGithubReleaseAssetUploadError extends Error { + constructor(message, report, options = {}) { + super(`concurrent-github-release-asset-upload: ${message}`, options); + this.name = 'ConcurrentGithubReleaseAssetUploadError'; + this.report = report; + } +} + +function error(message, report, options = {}) { + return new ConcurrentGithubReleaseAssetUploadError(message, report, options); +} + +function validatePlan(plan) { + if ( + plan === null || + Array.isArray(plan) || + typeof plan !== 'object' || + !Array.isArray(plan.waves) || + !Number.isSafeInteger(plan.assetCount) || + plan.assetCount < 0 || + !Number.isSafeInteger(plan.productCount) || + plan.productCount < 0 || + (plan.waves.length === 0 && (plan.productCount !== 0 || plan.assetCount !== 0)) || + (plan.waves.length > 0 && plan.productCount < 1) + ) { + throw error('plan is malformed', null); + } + const products = new Set(); + let assetCount = 0; + for (const [waveIndex, wave] of plan.waves.entries()) { + if ( + wave === null || + Array.isArray(wave) || + typeof wave !== 'object' || + !Array.isArray(wave.rows) || + wave.rows.length === 0 || + !Number.isSafeInteger(wave.windowMs) || + wave.windowMs < 1 + ) { + throw error(`wave ${waveIndex + 1} is malformed`, null); + } + let waveAssetCount = 0; + const waveProducts = []; + for (const row of wave.rows) { + if ( + row === null || + Array.isArray(row) || + typeof row !== 'object' || + typeof row.product !== 'string' || + row.product.length === 0 || + !Number.isSafeInteger(row.assetCount) || + row.assetCount < 0 || + products.has(row.product) + ) { + throw error(`wave ${waveIndex + 1} contains a malformed or duplicate product`, null); + } + products.add(row.product); + waveProducts.push(row.product); + waveAssetCount += row.assetCount; + } + if ( + wave.assetCount !== waveAssetCount || + !Array.isArray(wave.products) || + wave.products.length !== waveProducts.length || + wave.products.some((product, index) => product !== waveProducts[index]) + ) { + throw error(`wave ${waveIndex + 1} summary disagrees with its rows`, null); + } + assetCount += waveAssetCount; + } + if (products.size !== plan.productCount || assetCount !== plan.assetCount) { + throw error('plan product or asset count disagrees with its waves', null); + } +} + +function failureDetail(cause) { + if (cause instanceof Error) return cause.message; + return String(cause); +} + +function validateExecution(plan, execution) { + if ( + execution === null || + Array.isArray(execution) || + typeof execution !== 'object' || + execution.assetCount !== plan.assetCount || + execution.productCount !== plan.productCount || + execution.waveCount !== plan.waves.length || + !Number.isSafeInteger(execution.completedWaves) || + execution.completedWaves < 0 || + execution.completedWaves > plan.waves.length || + !new Set(['failure', 'success']).has(execution.status) || + !Array.isArray(execution.products) + ) { + throw error('execution report is malformed or disagrees with its plan', execution); + } + const completedRows = plan.waves.slice(0, execution.completedWaves).flatMap(({ rows }) => rows); + if ( + execution.products.length !== completedRows.length || + execution.products.some((outcome, index) => { + const row = completedRows[index]; + return ( + outcome === null || + Array.isArray(outcome) || + typeof outcome !== 'object' || + outcome.product !== row.product || + outcome.assetCount !== row.assetCount || + !new Set(['failure', 'success']).has(outcome.status) + ); + }) || + (execution.status === 'success' && + (execution.completedWaves !== plan.waves.length || + execution.products.some(({ status }) => status !== 'success'))) || + (execution.status === 'failure' && + !execution.products.some(({ status }) => status === 'failure')) + ) { + throw error('execution outcomes do not exactly cover the completed plan waves', execution); + } +} + +export function writeConcurrentGithubReleaseAssetUploadReport( + file, + { execution, plan, sourceCommit }, +) { + if ( + typeof file !== 'string' || + file.length === 0 || + file.includes('\0') || + typeof sourceCommit !== 'string' || + !FULL_SHA.test(sourceCommit) + ) { + throw error('report requires a path and exact lowercase source commit', execution ?? null); + } + validatePlan(plan); + validateExecution(plan, execution); + const destination = path.resolve(file); + mkdirSync(path.dirname(destination), { recursive: true }); + const temporary = `${destination}.tmp-${process.pid}`; + try { + writeFileSync( + temporary, + `${JSON.stringify( + { + execution, + plan, + schema: 'oliphaunt-concurrent-github-release-asset-upload-report-v1', + sourceCommit, + }, + null, + 2, + )}\n`, + { flag: 'wx', mode: 0o600 }, + ); + renameSync(temporary, destination); + } finally { + rmSync(temporary, { force: true }); + } +} + +export function githubReleaseAssetUploadEnvironment(parentEnvironment, { abortPath, windowMs }) { + if ( + parentEnvironment === null || + Array.isArray(parentEnvironment) || + typeof parentEnvironment !== 'object' || + typeof abortPath !== 'string' || + abortPath.length === 0 || + abortPath.includes('\0') || + !Number.isSafeInteger(windowMs) || + windowMs < 1 + ) { + throw error( + 'upload environment requires a parent environment, abort path, and positive window', + null, + ); + } + return { + ...parentEnvironment, + OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: String(windowMs), + OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH: abortPath, + }; +} + +/** + * Execute complete product waves. A lane failure publishes the shared abort + * signal immediately, but the current wave is always drained so an immutable + * upload already in flight can finish exact-state reconciliation. No later wave + * starts after any failure. + */ +export async function executeConcurrentGithubReleaseAssetUploadPlan( + plan, + { abort = () => {}, uploadProduct } = {}, +) { + validatePlan(plan); + if (typeof uploadProduct !== 'function' || typeof abort !== 'function') { + throw error('uploadProduct and abort must be functions', null); + } + const report = { + assetCount: plan.assetCount, + completedWaves: 0, + productCount: plan.productCount, + products: [], + status: 'running', + waveCount: plan.waves.length, + }; + if (plan.waves.length === 0) { + report.status = 'success'; + return report; + } + let aborted = false; + for (const [waveIndex, wave] of plan.waves.entries()) { + const outcomes = await Promise.all( + wave.rows.map(async (row) => { + try { + const value = await uploadProduct(row, { + aborted: () => aborted, + wave, + waveIndex, + }); + return { assetCount: row.assetCount, product: row.product, status: 'success', value }; + } catch (cause) { + const outcome = { + assetCount: row.assetCount, + detail: failureDetail(cause), + product: row.product, + status: 'failure', + }; + if (!aborted) { + aborted = true; + try { + await abort(outcome); + } catch (abortCause) { + outcome.abortDetail = failureDetail(abortCause); + } + } + return outcome; + } + }), + ); + report.products.push(...outcomes); + report.completedWaves += 1; + const failures = outcomes.filter(({ status }) => status === 'failure'); + if (failures.length > 0) { + report.status = 'failure'; + throw error( + `wave ${waveIndex + 1} failed after draining all in-flight lanes: ` + + failures.map(({ detail, product }) => `${product} (${detail})`).join(', '), + report, + ); + } + } + report.status = 'success'; + return report; +} diff --git a/tools/release/concurrent-github-release-asset-upload.test.mjs b/tools/release/concurrent-github-release-asset-upload.test.mjs deleted file mode 100644 index 87fab2cea..000000000 --- a/tools/release/concurrent-github-release-asset-upload.test.mjs +++ /dev/null @@ -1,250 +0,0 @@ -import { describe, expect, test } from "bun:test"; -import { spawn } from "node:child_process"; -import { - mkdtempSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { pathToFileURL } from "node:url"; - -import { - ConcurrentGithubReleaseAssetUploadError, - executeConcurrentGithubReleaseAssetUploadPlan, - githubReleaseAssetUploadChildEnvironment, - writeConcurrentGithubReleaseAssetUploadReport, -} from "./concurrent-github-release-asset-upload.mjs"; - -function plan(waves) { - const rows = waves.flat(); - return { - assetCount: rows.reduce((total, row) => total + row.assetCount, 0), - productCount: rows.length, - totalWindowMs: waves.length * 1_000, - waves: waves.map((wave) => ({ - assetCount: wave.reduce((total, row) => total + row.assetCount, 0), - products: wave.map(({ product }) => product), - rows: wave, - windowMs: 1_000, - })), - }; -} - -describe("concurrent GitHub release asset upload execution", () => { - test("propagates every shared journal/deadline root and pins wave coordination overrides", () => { - const parent = { - GH_TOKEN: "secret", - OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH: "/tmp/pacer.json", - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: "/tmp/core.json", - OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: "untrusted-parent-value", - OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH: "/tmp/untrusted-parent-abort", - REGISTRY_JOB_HARD_DEADLINE_EPOCH: "9999", - RELEASE_HEAD_SHA: "a".repeat(40), - }; - expect(githubReleaseAssetUploadChildEnvironment(parent, { - abortPath: "/tmp/wave-abort.json", - windowMs: 2_300_000, - })).toEqual({ - ...parent, - OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: "2300000", - OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH: "/tmp/wave-abort.json", - }); - }); - - test("drains a failed wave, emits one shared abort, and never starts a later wave", async () => { - const events = []; - let releasePeer; - const peer = new Promise((resolve) => { releasePeer = resolve; }); - const execution = executeConcurrentGithubReleaseAssetUploadPlan( - plan([ - [ - { product: "failed", assetCount: 2 }, - { product: "in-flight", assetCount: 3 }, - ], - [{ product: "must-not-start", assetCount: 1 }], - ]), - { - abort: ({ product }) => { - events.push(`abort:${product}`); - releasePeer(); - }, - uploadProduct: async ({ product }) => { - events.push(`start:${product}`); - if (product === "failed") throw new Error("exact snapshot mismatch"); - if (product === "in-flight") { - await peer; - events.push("reconciled:in-flight"); - } - }, - }, - ); - let failure; - try { - await execution; - } catch (cause) { - failure = cause; - } - expect(failure).toBeInstanceOf(ConcurrentGithubReleaseAssetUploadError); - expect(failure.message).toContain("failed (exact snapshot mismatch)"); - expect(failure.report.status).toBe("failure"); - expect(failure.report.completedWaves).toBe(1); - expect(failure.report.products.map(({ product, status }) => [product, status])).toEqual([ - ["failed", "failure"], - ["in-flight", "success"], - ]); - expect(events).toContain("abort:failed"); - expect(events).toContain("reconciled:in-flight"); - expect(events).not.toContain("start:must-not-start"); - }); - - test("aggregates every same-wave exact snapshot failure", async () => { - let failure; - try { - await executeConcurrentGithubReleaseAssetUploadPlan( - plan([[ - { product: "alpha", assetCount: 1 }, - { product: "beta", assetCount: 1 }, - ]]), - { - uploadProduct: async ({ product }) => { - throw new Error(`${product} immutable remote asset conflict`); - }, - }, - ); - } catch (cause) { - failure = cause; - } - expect(failure.report.products).toEqual([ - expect.objectContaining({ - detail: "alpha immutable remote asset conflict", - product: "alpha", - status: "failure", - }), - expect.objectContaining({ - detail: "beta immutable remote asset conflict", - product: "beta", - status: "failure", - }), - ]); - expect(failure.message).toContain("alpha (alpha immutable remote asset conflict)"); - expect(failure.message).toContain("beta (beta immutable remote asset conflict)"); - }); - - test("returns complete success evidence in wave order", async () => { - const result = await executeConcurrentGithubReleaseAssetUploadPlan( - plan([ - [{ product: "a", assetCount: 1 }], - [{ product: "b", assetCount: 0 }], - ]), - { uploadProduct: async ({ product }) => ({ exact: product }) }, - ); - expect(result.status).toBe("success"); - expect(result.completedWaves).toBe(2); - expect(result.products.map(({ product }) => product)).toEqual(["a", "b"]); - }); - - test("returns an exact empty success report when every selected product is receipt-only", async () => { - const result = await executeConcurrentGithubReleaseAssetUploadPlan({ - assetCount: 0, - productCount: 0, - selectionVerificationWindowMs: 60_000, - totalWindowMs: 60_000, - waves: [], - }, { - uploadProduct: async () => { - throw new Error("an empty plan must not start an uploader"); - }, - }); - expect(result).toEqual({ - assetCount: 0, - completedWaves: 0, - productCount: 0, - products: [], - status: "success", - waveCount: 0, - }); - }); - - test("subprocess lanes preserve every shared journal reservation and emit one exact report", async () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-concurrent-upload-report-")); - try { - const pacerPath = path.join(root, "pacer.json"); - const corePath = path.join(root, "core.json"); - const reportPath = path.join(root, "report.json"); - const workerPath = path.join(root, "worker.mjs"); - writeFileSync(workerPath, ` -import { reserveGitHubContentWriteSync } from ${JSON.stringify(pathToFileURL(path.resolve("tools/release/github-content-write-pacer.mjs")).href)}; -import { reserveGitHubCoreRequestSync } from ${JSON.stringify(pathToFileURL(path.resolve("tools/release/github-core-request-journal.mjs")).href)}; -for (let attempt = 0; attempt < 2; attempt += 1) { - const label = \`upload-\${process.argv[2]}-\${attempt}\`; - reserveGitHubContentWriteSync({ - environment: process.env, - label, - timing: { intervalMs: 5, maxLockWaitMs: 1_000 }, - }); - reserveGitHubCoreRequestSync({ environment: process.env, label }); -} -`); - const sourceCommit = "e".repeat(40); - const environment = githubReleaseAssetUploadChildEnvironment({ - ...process.env, - GITHUB_ACTIONS: "false", - GITHUB_REPOSITORY: "f0rr0/oliphaunt", - GITHUB_RUN_ATTEMPT: "1", - GITHUB_RUN_ID: "789", - GITHUB_SHA: sourceCommit, - OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH: pacerPath, - OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE: "true", - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: corePath, - OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: "true", - }, { - abortPath: path.join(root, "abort.json"), - windowMs: 1_000, - }); - const rows = Array.from({ length: 5 }, (_, index) => ({ - assetCount: 2, - product: `product-${index}`, - })); - const exactPlan = plan([rows]); - const runWorker = (product) => new Promise((resolve, reject) => { - const child = spawn(process.execPath, [workerPath, product], { - env: environment, - stdio: ["ignore", "ignore", "pipe"], - }); - let stderr = ""; - child.stderr.on("data", (chunk) => { stderr += String(chunk); }); - child.once("error", reject); - child.once("close", (code, signal) => { - if (code === 0 && signal === null) resolve({ product }); - else reject(new Error(`${product} worker failed (${code}/${signal}): ${stderr}`)); - }); - }); - const execution = await executeConcurrentGithubReleaseAssetUploadPlan(exactPlan, { - uploadProduct: ({ product }) => runWorker(product), - }); - writeConcurrentGithubReleaseAssetUploadReport(reportPath, { - execution, - plan: exactPlan, - sourceCommit, - }); - - const pacer = JSON.parse(readFileSync(pacerPath, "utf8")); - const core = JSON.parse(readFileSync(corePath, "utf8")); - const report = JSON.parse(readFileSync(reportPath, "utf8")); - expect(pacer.sequence).toBe(10); - expect(pacer.reservations).toHaveLength(10); - expect(core.sequence).toBe(10); - expect(core.attempts).toHaveLength(10); - expect(report).toEqual({ - execution, - plan: exactPlan, - schema: "oliphaunt-concurrent-github-release-asset-upload-report-v1", - sourceCommit, - }); - } finally { - rmSync(root, { force: true, recursive: true }); - } - }); -}); diff --git a/tools/release/concurrent-github-release-asset-upload.test.mts b/tools/release/concurrent-github-release-asset-upload.test.mts new file mode 100644 index 000000000..0efbba8c4 --- /dev/null +++ b/tools/release/concurrent-github-release-asset-upload.test.mts @@ -0,0 +1,223 @@ +import { describe, expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { + ConcurrentGithubReleaseAssetUploadError, + executeConcurrentGithubReleaseAssetUploadPlan, + githubReleaseAssetUploadEnvironment, + writeConcurrentGithubReleaseAssetUploadReport, +} from './concurrent-github-release-asset-upload.mts'; +import { reserveGitHubContentWrite } from './github-content-write-pacer.mts'; +import { reserveGitHubCoreRequest } from './github-core-request-journal.mts'; + +function plan(waves) { + const rows = waves.flat(); + return { + assetCount: rows.reduce((total, row) => total + row.assetCount, 0), + productCount: rows.length, + totalWindowMs: waves.length * 1_000, + waves: waves.map((wave) => ({ + assetCount: wave.reduce((total, row) => total + row.assetCount, 0), + products: wave.map(({ product }) => product), + rows: wave, + windowMs: 1_000, + })), + }; +} + +if (['worker', 'verify'].includes(process.argv[2])) { + const root = process.argv[3]; + const environment = githubReleaseAssetUploadEnvironment( + { + GITHUB_ACTIONS: 'false', + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_RUN_ATTEMPT: '1', + GITHUB_RUN_ID: '789', + GITHUB_SHA: 'e'.repeat(40), + OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH: path.join(root, 'pacer.json'), + OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE: 'true', + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, 'core.json'), + OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: 'true', + }, + { abortPath: path.join(root, 'abort.json'), windowMs: 1000 }, + ); + if (process.argv[2] === 'worker') { + for (let attempt = 0; attempt < 2; attempt++) { + const label = `upload-${process.argv[4]}-${attempt}`; + await reserveGitHubContentWrite({ + environment, + label, + timing: { intervalMs: 5, maxLockWaitMs: 1000 }, + }); + await reserveGitHubCoreRequest({ environment, label }); + } + } else { + const pacer = JSON.parse(readFileSync(path.join(root, 'pacer.json'), 'utf8')); + const core = JSON.parse(readFileSync(path.join(root, 'core.json'), 'utf8')); + expect(pacer.sequence).toBe(10); + expect(pacer.lastReservedAtMs).toBeGreaterThan(0); + expect(core.sequence).toBe(10); + expect(core.attempts).toHaveLength(10); + const exactPlan = plan([ + Array.from({ length: 5 }, (_, i) => ({ assetCount: 2, product: `product-${i}` })), + ]); + const execution = await executeConcurrentGithubReleaseAssetUploadPlan(exactPlan, { + uploadProduct: async ({ product }) => ({ product }), + }); + const reportPath = path.join(root, 'report.json'); + writeConcurrentGithubReleaseAssetUploadReport(reportPath, { + execution, + plan: exactPlan, + sourceCommit: 'e'.repeat(40), + }); + expect(JSON.parse(readFileSync(reportPath, 'utf8'))).toEqual({ + execution, + plan: exactPlan, + schema: 'oliphaunt-concurrent-github-release-asset-upload-report-v1', + sourceCommit: 'e'.repeat(40), + }); + } + process.exit(0); +} + +describe('concurrent GitHub release asset upload execution', () => { + test('propagates every shared journal/deadline root and pins wave coordination overrides', () => { + const parent = { + GH_TOKEN: 'secret', + OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH: '/tmp/pacer.json', + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: '/tmp/core.json', + OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: 'untrusted-parent-value', + OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH: '/tmp/untrusted-parent-abort', + REGISTRY_JOB_HARD_DEADLINE_EPOCH: '9999', + RELEASE_HEAD_SHA: 'a'.repeat(40), + }; + expect( + githubReleaseAssetUploadEnvironment(parent, { + abortPath: '/tmp/wave-abort.json', + windowMs: 2_300_000, + }), + ).toEqual({ + ...parent, + OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: '2300000', + OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH: '/tmp/wave-abort.json', + }); + }); + + test('drains a failed wave, emits one shared abort, and never starts a later wave', async () => { + const events = []; + let releasePeer; + const peer = new Promise((resolve) => { + releasePeer = resolve; + }); + const execution = executeConcurrentGithubReleaseAssetUploadPlan( + plan([ + [ + { product: 'failed', assetCount: 2 }, + { product: 'in-flight', assetCount: 3 }, + ], + [{ product: 'must-not-start', assetCount: 1 }], + ]), + { + abort: ({ product }) => { + events.push(`abort:${product}`); + releasePeer(); + }, + uploadProduct: async ({ product }) => { + events.push(`start:${product}`); + if (product === 'failed') throw new Error('exact snapshot mismatch'); + if (product === 'in-flight') { + await peer; + events.push('reconciled:in-flight'); + } + }, + }, + ); + let failure; + try { + await execution; + } catch (cause) { + failure = cause; + } + expect(failure).toBeInstanceOf(ConcurrentGithubReleaseAssetUploadError); + expect(failure.message).toContain('failed (exact snapshot mismatch)'); + expect(failure.report.status).toBe('failure'); + expect(failure.report.completedWaves).toBe(1); + expect(failure.report.products.map(({ product, status }) => [product, status])).toEqual([ + ['failed', 'failure'], + ['in-flight', 'success'], + ]); + expect(events).toContain('abort:failed'); + expect(events).toContain('reconciled:in-flight'); + expect(events).not.toContain('start:must-not-start'); + }); + + test('aggregates every same-wave exact snapshot failure', async () => { + let failure; + try { + await executeConcurrentGithubReleaseAssetUploadPlan( + plan([ + [ + { product: 'alpha', assetCount: 1 }, + { product: 'beta', assetCount: 1 }, + ], + ]), + { + uploadProduct: async ({ product }) => { + throw new Error(`${product} immutable remote asset conflict`); + }, + }, + ); + } catch (cause) { + failure = cause; + } + expect(failure.report.products).toEqual([ + expect.objectContaining({ + detail: 'alpha immutable remote asset conflict', + product: 'alpha', + status: 'failure', + }), + expect.objectContaining({ + detail: 'beta immutable remote asset conflict', + product: 'beta', + status: 'failure', + }), + ]); + expect(failure.message).toContain('alpha (alpha immutable remote asset conflict)'); + expect(failure.message).toContain('beta (beta immutable remote asset conflict)'); + }); + + test('returns complete success evidence in wave order', async () => { + const result = await executeConcurrentGithubReleaseAssetUploadPlan( + plan([[{ product: 'a', assetCount: 1 }], [{ product: 'b', assetCount: 0 }]]), + { uploadProduct: async ({ product }) => ({ exact: product }) }, + ); + expect(result.status).toBe('success'); + expect(result.completedWaves).toBe(2); + expect(result.products.map(({ product }) => product)).toEqual(['a', 'b']); + }); + + test('returns an exact empty success report when every selected product is receipt-only', async () => { + const result = await executeConcurrentGithubReleaseAssetUploadPlan( + { + assetCount: 0, + productCount: 0, + selectionVerificationWindowMs: 60_000, + totalWindowMs: 60_000, + waves: [], + }, + { + uploadProduct: async () => { + throw new Error('an empty plan must not start an uploader'); + }, + }, + ); + expect(result).toEqual({ + assetCount: 0, + completedWaves: 0, + productCount: 0, + products: [], + status: 'success', + waveCount: 0, + }); + }); +}); diff --git a/tools/release/concurrent-github-release-asset-upload.test.sh b/tools/release/concurrent-github-release-asset-upload.test.sh new file mode 100644 index 000000000..d0aa78b41 --- /dev/null +++ b/tools/release/concurrent-github-release-asset-upload.test.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +bun test ./tools/release/concurrent-github-release-asset-upload.test.mts +scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-upload-concurrency-XXXXXX") +trap 'rm -rf "$scratch"' EXIT +pids=() +for product in 0 1 2 3 4; do + bun tools/release/concurrent-github-release-asset-upload.test.mts worker "$scratch" "$product" & + pids+=("$!") +done +status=0 +for pid in "${pids[@]}"; do wait "$pid" || status=1; done +[ "$status" = 0 ] +bun tools/release/concurrent-github-release-asset-upload.test.mts verify "$scratch" diff --git a/tools/release/contrib-carriers.mjs b/tools/release/contrib-carriers.mjs deleted file mode 100644 index 6252661f8..000000000 --- a/tools/release/contrib-carriers.mjs +++ /dev/null @@ -1,61 +0,0 @@ -import { existsSync, readFileSync } from "node:fs"; -import path from "node:path"; - -export const CONTRIB_CARRIERS_PATH = "src/extensions/contrib/carriers.toml"; - -function fail(prefix, message) { - throw new Error(`${prefix}: ${message}`); -} - -function toml(root, relativePath, prefix) { - const file = path.join(root, relativePath); - if (!existsSync(file)) fail(prefix, `missing ${relativePath}`); - const value = Bun.TOML.parse(readFileSync(file, "utf8")); - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(prefix, `${relativePath} must contain a TOML table`); - } - return value; -} - -function string(value, context, prefix) { - if (typeof value !== "string" || value.length === 0) fail(prefix, `${context} must be a non-empty string`); - return value; -} - -export function loadContribCarriers(root, prefix = "contrib-carriers") { - const descriptor = toml(root, CONTRIB_CARRIERS_PATH, prefix); - const artifactProduct = string(descriptor.logical_product, "logical_product", prefix); - const memberManifest = string(descriptor.member_manifest, "member_manifest", prefix); - const source = string(descriptor.source, "source", prefix); - const contract = string(descriptor.contract, "contract", prefix); - const nativeOwner = string(descriptor.native_owner, "native_owner", prefix); - const wasixOwner = string(descriptor.wasix_owner, "wasix_owner", prefix); - const members = toml(root, memberManifest, prefix).extensions; - if (!Array.isArray(members) || members.some((member) => - member === null || Array.isArray(member) || typeof member !== "object" || typeof member.id !== "string" - )) { - fail(prefix, `${memberManifest}.extensions must name contrib member ids`); - } - const ids = members.map(({ id }) => id); - if (new Set(ids).size !== ids.length) fail(prefix, `${memberManifest}.extensions ids must be unique`); - const inputFiles = [ - CONTRIB_CARRIERS_PATH, - memberManifest, - "src/shared/extension-runtime-contract/extension-target-profiles.toml", - source, - contract, - ]; - for (const file of inputFiles) { - if (!existsSync(path.join(root, file))) fail(prefix, `missing contrib carrier input ${file}`); - } - return { - artifactProduct, - contract, - inputFiles, - memberManifest, - members, - nativeOwner, - source, - wasixOwner, - }; -} diff --git a/tools/release/crates-io-bootstrap-capacity.mjs b/tools/release/crates-io-bootstrap-capacity.mjs deleted file mode 100644 index b0d1c4762..000000000 --- a/tools/release/crates-io-bootstrap-capacity.mjs +++ /dev/null @@ -1,931 +0,0 @@ -import process from "node:process"; - -import { - CRATES_IO_READ_START_INTERVAL_MILLISECONDS, - createCratesIoReadGate, - retryAfterSeconds, - registryRetryDelaySeconds, - registryStatusRetryable, -} from "./registry-http-retry.mjs"; -export { - CRATES_IO_READ_START_INTERVAL_MILLISECONDS, - createCratesIoReadGate, -}; -export { - RegistryPublicationDeferredError, - isRegistryPublicationDeferredError, -} from "./registry-publication-deferral.mjs"; - -// Primary contract: https://crates.io/docs/rate-limits. The upstream -// implementation independently defines these per-user leaky buckets in -// rust-lang/crates.io/src/rate_limiter.rs. Keep tests and maintainer setup in -// sync if crates.io changes either published limit. -export const CRATES_IO_DEFAULT_NEW_CRATE_BURST = 5; -export const CRATES_IO_NEW_CRATE_REFILL_SECONDS = 10 * 60; -export const REGISTRY_MUTATION_DEADLINE_VARIABLE = "REGISTRY_MUTATION_DEADLINE_EPOCH"; -export const REGISTRY_BOOTSTRAP_CARGO_SECONDS_VARIABLE = "REGISTRY_BOOTSTRAP_CARGO_SECONDS_PER_CARRIER"; -export const REGISTRY_BOOTSTRAP_NPM_SECONDS_VARIABLE = "REGISTRY_BOOTSTRAP_NPM_SECONDS_PER_CARRIER"; -export const REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_VARIABLE = "REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_PER_CARRIER"; -export const REGISTRY_BOOTSTRAP_RESERVE_SECONDS_VARIABLE = "REGISTRY_BOOTSTRAP_RESERVE_SECONDS"; -export const REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER = 30; -export const REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER = 30; -export const REGISTRY_BOOTSTRAP_INTEGRITY_CONCURRENCY = 8; -// registry-integrity bounds one request at 45s. At the fixed concurrency of -// eight, six seconds per public carrier covers a complete worst-case request -// wave; the separate reserve covers bounded retry and local ledger overhead. -export const REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER = 6; -// These timing values are calibrated admission estimates, not upper bounds on third-party -// registry latency. A separate absolute deadline stops mutation; immutable -// public versions and checkpoint receipts make interrupted runs resumable. -export const REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS = 10 * 60; - -const DEFAULT_CRATES_IO_API = "https://crates.io/api/v1"; -const USER_AGENT = "oliphaunt-bootstrap-capacity/1; https://github.com/f0rr0/oliphaunt"; -const REQUEST_ATTEMPTS = 8; -const REQUEST_TIMEOUT_MS = 30_000; -const DEADLINE_RESERVE_MS = 5_000; -const MAX_READ_RETRY_DELAY_BUDGET_SECONDS = 3 * 60; -const MAX_RATE_LIMIT_RETRY_DELAY_SECONDS = 5 * 60; -const MINIMUM_MUTATION_WINDOW_SECONDS = 15 * 60; -const MAX_PLANNING_SECONDS_PER_CARRIER = 60 * 60; -const MAX_RESERVE_SECONDS = 6 * 60 * 60; - -function error(message) { - return new Error(`crates-io-bootstrap-capacity: ${message}`); -} - -function compareText(left, right) { - const a = String(left); - const b = String(right); - return a < b ? -1 : a > b ? 1 : 0; -} - -function strictNonNegativeInteger(raw, context, maximum = Number.MAX_SAFE_INTEGER) { - const text = typeof raw === "number" ? String(raw) : raw?.trim?.(); - if (typeof text !== "string" || !/^(?:0|[1-9][0-9]*)$/u.test(text)) { - throw error(`${context} must be a base-10 non-negative integer`); - } - const value = Number(text); - if (!Number.isSafeInteger(value) || value > maximum) { - throw error(`${context} must not exceed ${maximum}`); - } - return value; -} - -export function parseRegistryMutationDeadline(raw) { - return strictNonNegativeInteger( - raw, - REGISTRY_MUTATION_DEADLINE_VARIABLE, - Math.floor(Number.MAX_SAFE_INTEGER / 1000), - ); -} - -function planningSeconds(raw, variable, fallback, { minimum, maximum }) { - if (raw === undefined || raw === null || String(raw).trim().length === 0) { - return fallback; - } - const value = strictNonNegativeInteger(raw, variable, maximum); - if (value < minimum) { - throw error(`${variable} must be at least ${minimum}`); - } - return value; -} - -export function parseRegistryBootstrapCargoSeconds(raw) { - return planningSeconds( - raw, - REGISTRY_BOOTSTRAP_CARGO_SECONDS_VARIABLE, - REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER, - { - minimum: REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER, - maximum: MAX_PLANNING_SECONDS_PER_CARRIER, - }, - ); -} - -export function parseRegistryBootstrapNpmSeconds(raw) { - return planningSeconds( - raw, - REGISTRY_BOOTSTRAP_NPM_SECONDS_VARIABLE, - REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER, - { - minimum: REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER, - maximum: MAX_PLANNING_SECONDS_PER_CARRIER, - }, - ); -} - -export function parseRegistryBootstrapReconciliationSeconds(raw) { - return planningSeconds( - raw, - REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_VARIABLE, - REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER, - { - minimum: REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER, - maximum: MAX_PLANNING_SECONDS_PER_CARRIER, - }, - ); -} - -export function parseRegistryBootstrapReserveSeconds(raw) { - return planningSeconds( - raw, - REGISTRY_BOOTSTRAP_RESERVE_SECONDS_VARIABLE, - REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS, - { - minimum: REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS, - maximum: MAX_RESERVE_SECONDS, - }, - ); -} - -function selectedCargoIdentities(plan) { - if (!Array.isArray(plan)) { - throw error("bootstrap publication plan must be a list"); - } - const identities = plan - .filter(({ ecosystem }) => ecosystem === "cargo") - .map(({ name, version }, index) => { - if (typeof name !== "string" || name.length === 0 || typeof version !== "string" || version.length === 0) { - throw error(`Cargo plan entry ${index} must have a package name and version`); - } - return { name, version }; - }); - const names = identities.map(({ name }) => name); - const unique = [...new Set(names)].sort(compareText); - if (unique.length !== names.length) { - throw error("exact publication lock selects duplicate Cargo package names"); - } - return identities.sort((left, right) => compareText(left.name, right.name)); -} - -function selectedCargoNames(plan) { - return selectedCargoIdentities(plan).map(({ name }) => name); -} - -async function closeResponse(response) { - try { - await response.body?.cancel?.(); - } catch { - // The bounded existence check does not need the response body. - } -} - -async function crateResourceExists(resourceSegments, label, { - apiBase, - fetchImpl, - nowImpl, - deadlineEpochSeconds, - readGate, -}) { - const resource = resourceSegments.map((segment) => encodeURIComponent(segment)).join("/"); - const url = `${apiBase.replace(/\/+$/u, "")}/crates/${resource}`; - let lastFailure = null; - let retryDelaySpentSeconds = 0; - for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { - try { - const remainingMilliseconds = (deadlineEpochSeconds - nowImpl()) * 1000 - DEADLINE_RESERVE_MS; - if (remainingMilliseconds <= 0) { - throw error(`read-only existence check for ${label} cannot start before the registry mutation deadline`); - } - await readGate.beforeRequest(label, deadlineEpochSeconds); - const requestRemainingMilliseconds = (deadlineEpochSeconds - nowImpl()) * 1000 - DEADLINE_RESERVE_MS; - if (requestRemainingMilliseconds <= 0) { - throw error(`read-only existence check for ${label} cannot start before the registry mutation deadline`); - } - const response = await fetchImpl(url, { - headers: { - Accept: "application/json", - "User-Agent": USER_AGENT, - }, - redirect: "error", - signal: AbortSignal.timeout(Math.max(1, Math.min(REQUEST_TIMEOUT_MS, requestRemainingMilliseconds))), - }); - if (response.status === 200) { - await closeResponse(response); - return true; - } - if (response.status === 404) { - await closeResponse(response); - return false; - } - const retryable = registryStatusRetryable(response.status); - const status = response.status; - const headers = response.headers; - await closeResponse(response); - lastFailure = `HTTP ${status}`; - if (!retryable || attempt + 1 >= REQUEST_ATTEMPTS) { - break; - } - const requestedDelaySeconds = retryAfterSeconds(headers, nowImpl() * 1000); - const delaySeconds = requestedDelaySeconds - ?? (status === 429 - ? Math.min(60 * (2 ** attempt), MAX_RATE_LIMIT_RETRY_DELAY_SECONDS) - : registryRetryDelaySeconds({ headers, attempt, now: nowImpl() * 1000 })); - if (delaySeconds > MAX_READ_RETRY_DELAY_BUDGET_SECONDS - retryDelaySpentSeconds) { - throw error( - `read-only existence check for ${label} exceeds its bounded ${MAX_READ_RETRY_DELAY_BUDGET_SECONDS}s retry-delay budget; retry the release later`, - ); - } - const delayMilliseconds = Math.ceil(delaySeconds * 1000); - const retryRemainingMilliseconds = (deadlineEpochSeconds - nowImpl()) * 1000 - DEADLINE_RESERVE_MS; - if (delayMilliseconds >= retryRemainingMilliseconds) { - throw error(`read-only existence check for ${label} cannot retry before the registry mutation deadline`); - } - retryDelaySpentSeconds += delaySeconds; - readGate.defer(delaySeconds); - } catch (cause) { - if ( - cause instanceof Error - && (cause.message.startsWith("crates-io-bootstrap-capacity:") - || cause.message.startsWith("registry-http-retry:")) - ) { - throw cause; - } - lastFailure = cause instanceof Error ? cause.message : String(cause); - if (attempt + 1 >= REQUEST_ATTEMPTS) { - break; - } - const delaySeconds = registryRetryDelaySeconds({ attempt, now: nowImpl() * 1000 }); - if (delaySeconds > MAX_READ_RETRY_DELAY_BUDGET_SECONDS - retryDelaySpentSeconds) { - throw error( - `read-only existence check for ${label} exceeds its bounded ${MAX_READ_RETRY_DELAY_BUDGET_SECONDS}s retry-delay budget; retry the release later`, - ); - } - const delayMilliseconds = Math.ceil(delaySeconds * 1000); - const retryRemainingMilliseconds = (deadlineEpochSeconds - nowImpl()) * 1000 - DEADLINE_RESERVE_MS; - if (delayMilliseconds >= retryRemainingMilliseconds) { - throw error(`read-only existence check for ${label} cannot retry before the registry mutation deadline`); - } - retryDelaySpentSeconds += delaySeconds; - readGate.defer(delaySeconds); - } - } - throw error(`cannot determine whether Cargo identity ${label} exists on crates.io: ${lastFailure ?? "unknown response"}`); -} - -export async function inspectCratesIoBootstrapNames({ - plan, - apiBase = process.env.CRATES_IO_API ?? DEFAULT_CRATES_IO_API, - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = () => Date.now() / 1000, - deadlineEpochSeconds, - concurrency = 8, -}) { - if (!Number.isSafeInteger(deadlineEpochSeconds) || deadlineEpochSeconds <= nowImpl()) { - throw error(`${REGISTRY_MUTATION_DEADLINE_VARIABLE} must be a future Unix timestamp`); - } - if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) { - throw error("existence-check concurrency must be an integer from 1 through 32"); - } - const names = selectedCargoNames(plan); - const readGate = createCratesIoReadGate({ nowImpl, sleepImpl }); - const observed = new Array(names.length); - let cursor = 0; - const workers = Array.from({ length: Math.min(concurrency, names.length) }, async () => { - for (;;) { - const index = cursor; - cursor += 1; - if (index >= names.length) return; - observed[index] = await crateResourceExists([names[index]], names[index], { - apiBase, - fetchImpl, - nowImpl, - deadlineEpochSeconds, - readGate, - }); - } - }); - await Promise.all(workers); - return { - selectedNames: names, - existingNames: names.filter((_, index) => observed[index]), - missingNames: names.filter((_, index) => !observed[index]), - }; -} - -export async function inspectCratesIoVersionState({ - plan, - apiBase = process.env.CRATES_IO_API ?? DEFAULT_CRATES_IO_API, - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = () => Date.now() / 1000, - deadlineEpochSeconds, - concurrency = 8, -}) { - if (!Number.isSafeInteger(deadlineEpochSeconds) || deadlineEpochSeconds <= nowImpl()) { - throw error(`${REGISTRY_MUTATION_DEADLINE_VARIABLE} must be a future Unix timestamp`); - } - if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) { - throw error("existence-check concurrency must be an integer from 1 through 32"); - } - const identities = selectedCargoIdentities(plan); - const readGate = createCratesIoReadGate({ nowImpl, sleepImpl }); - const observed = new Array(identities.length); - let cursor = 0; - const workers = Array.from({ length: Math.min(concurrency, identities.length) }, async () => { - for (;;) { - const index = cursor; - cursor += 1; - if (index >= identities.length) return; - const identity = identities[index]; - const label = `${identity.name}@${identity.version}`; - const versionExists = await crateResourceExists([identity.name, identity.version], label, { - apiBase, - fetchImpl, - nowImpl, - deadlineEpochSeconds, - readGate, - }); - if (versionExists) { - observed[index] = "published"; - continue; - } - const nameExists = await crateResourceExists([identity.name], identity.name, { - apiBase, - fetchImpl, - nowImpl, - deadlineEpochSeconds, - readGate, - }); - observed[index] = nameExists ? "pending-version" : "missing-name"; - } - }); - await Promise.all(workers); - const withState = identities.map((identity, index) => ({ ...identity, state: observed[index] })); - return { - selectedIdentities: identities, - publishedIdentities: withState.filter(({ state }) => state === "published").map(({ name, version }) => ({ name, version })), - pendingVersions: withState.filter(({ state }) => state === "pending-version").map(({ name, version }) => ({ name, version })), - missingNames: withState.filter(({ state }) => state === "missing-name").map(({ name }) => name), - }; -} - -function validateBootstrapPublicationPlan(bootstrapPlan) { - if (!Array.isArray(bootstrapPlan)) throw error("bootstrap publication plan must be a carrier list"); - const positions = new Map(); - let priorCarrier = null; - for (const [index, carrier] of bootstrapPlan.entries()) { - if ( - carrier === null - || typeof carrier !== "object" - || typeof carrier.id !== "string" - || carrier.id !== `${carrier.ecosystem}:${carrier.name}` - || !new Set(["cargo", "npm"]).has(carrier.ecosystem) - || !Number.isSafeInteger(carrier.publishOrder) - || carrier.publishOrder < 0 - || (priorCarrier !== null && ( - carrier.publishOrder < priorCarrier.publishOrder - || (carrier.publishOrder === priorCarrier.publishOrder && carrier.id <= priorCarrier.id) - )) - ) { - throw error(`bootstrap carrier ${index} is not in strict canonical publish order`); - } - if (positions.has(carrier.id)) throw error(`bootstrap carrier ${carrier.id} is duplicated`); - if ( - !Array.isArray(carrier.dependencies) - || new Set(carrier.dependencies).size !== carrier.dependencies.length - || carrier.dependencies.some((dependency) => typeof dependency !== "string" || dependency.length === 0) - ) { - throw error(`bootstrap carrier ${carrier.id} dependencies must be a unique string list`); - } - positions.set(carrier.id, index); - priorCarrier = carrier; - } - for (const [index, carrier] of bootstrapPlan.entries()) { - for (const dependency of carrier.dependencies) { - const position = positions.get(dependency); - if (position === undefined) throw error(`${carrier.id} refers to unknown bootstrap dependency ${dependency}`); - if (position >= index) throw error(`${carrier.id} is not ordered after bootstrap dependency ${dependency}`); - } - } -} - -function validatedTokenBucketInputs({ publicationCount, burst, refillSeconds, workSeconds, initialTokens }) { - for (const [value, context] of [ - [publicationCount, "publicationCount"], - [burst, "burst"], - [refillSeconds, "refillSeconds"], - [workSeconds, "workSeconds"], - [initialTokens, "initialTokens"], - ]) { - if (!Number.isSafeInteger(value) || value < 0) { - throw error(`${context} must be a non-negative integer`); - } - } - if (burst < 1 || refillSeconds < 1 || initialTokens > burst) { - throw error("token bucket burst/refill must be positive and initialTokens cannot exceed burst"); - } -} - -/** - * Model crates.io's documented per-user token bucket without double-counting - * upload work. Tokens refill while a frozen carrier is being published; when - * work is slower than refill, the bucket may recover completely between - * operations. Returned times are conservative whole seconds. - */ -export function cratesIoTokenBucketSchedule({ - publicationCount, - burst, - refillSeconds, - workSeconds, - initialTokens = burst, -}) { - validatedTokenBucketInputs({ publicationCount, burst, refillSeconds, workSeconds, initialTokens }); - let elapsedSeconds = 0; - let tokenClockSeconds = 0; - // One token is exactly `refillSeconds` integer credit units. All planning - // inputs are whole seconds, so this rational representation cannot drift - // across a refill boundary and conservatively round 60s into 61s. - const capacityUnits = burst * refillSeconds; - let tokenUnits = initialTokens * refillSeconds; - let waitSeconds = 0; - const startSeconds = []; - for (let index = 0; index < publicationCount; index += 1) { - tokenUnits = Math.min(capacityUnits, tokenUnits + (elapsedSeconds - tokenClockSeconds)); - tokenClockSeconds = elapsedSeconds; - if (tokenUnits < refillSeconds) { - const wait = refillSeconds - tokenUnits; - elapsedSeconds += wait; - waitSeconds += wait; - tokenUnits = refillSeconds; - tokenClockSeconds = elapsedSeconds; - } - startSeconds.push(elapsedSeconds); - tokenUnits -= refillSeconds; - elapsedSeconds += workSeconds; - } - return { - elapsedSeconds: Math.ceil(elapsedSeconds), - waitSeconds: Math.ceil(waitSeconds), - workSeconds: publicationCount * workSeconds, - publicationCount, - initialTokens, - startSeconds, - }; -} - -function consumeTokenAtOrAfter(state, earliestStartSeconds) { - let startSeconds = earliestStartSeconds; - state.tokenUnits = Math.min( - state.burst * state.refillSeconds, - state.tokenUnits + (startSeconds - state.clockSeconds), - ); - state.clockSeconds = startSeconds; - if (state.tokenUnits < state.refillSeconds) { - startSeconds += state.refillSeconds - state.tokenUnits; - state.tokenUnits = state.refillSeconds; - state.clockSeconds = startSeconds; - } - state.tokenUnits -= state.refillSeconds; - return startSeconds; -} - -export function bootstrapPublicationCriticalPathSeconds(bootstrapPlan, carrierSeconds) { - validateBootstrapPublicationPlan(bootstrapPlan); - if (!(carrierSeconds instanceof Map)) { - throw error("bootstrap carrier seconds must be a Map keyed by carrier ID"); - } - const finishById = new Map(); - const priorByEcosystem = new Map(); - let criticalPathSeconds = 0; - for (const carrier of bootstrapPlan) { - const seconds = carrierSeconds.get(carrier.id); - if (!Number.isSafeInteger(seconds) || seconds < 0) { - throw error(`${carrier.id} must have a non-negative integer bootstrap budget`); - } - let startSeconds = 0; - for (const dependency of carrier.dependencies) { - startSeconds = Math.max(startSeconds, finishById.get(dependency)); - } - const prior = priorByEcosystem.get(carrier.ecosystem); - if (prior !== undefined) startSeconds = Math.max(startSeconds, finishById.get(prior)); - const finishSeconds = startSeconds + seconds; - if (!Number.isSafeInteger(finishSeconds)) throw error("bootstrap publication critical path exceeds the safe integer range"); - finishById.set(carrier.id, finishSeconds); - priorByEcosystem.set(carrier.ecosystem, carrier.id); - criticalPathSeconds = Math.max(criticalPathSeconds, finishSeconds); - } - return criticalPathSeconds; -} - -function bootstrapPublicationSchedule({ - bootstrapPlan, - cargoInventory, - npmInventory, - cargoSecondsPerCarrier, - npmSecondsPerCarrier, - selectedCarrierIds, - initialCargoTokens, -}) { - validateBootstrapPublicationPlan(bootstrapPlan); - const cargoState = exactVersionStateByName(cargoInventory, "Cargo"); - const npmState = exactVersionStateByName(npmInventory, "npm"); - const stateByEcosystem = new Map([["cargo", cargoState], ["npm", npmState]]); - for (const ecosystem of ["cargo", "npm"]) { - const planned = new Set(bootstrapPlan - .filter((carrier) => carrier.ecosystem === ecosystem) - .map(({ name }) => name)); - const states = stateByEcosystem.get(ecosystem); - if ([...planned].some((name) => !states.has(name)) - || [...states].some(([name, state]) => state.state === "missing" && !planned.has(name))) { - throw error(`${ecosystem} bootstrap plan disagrees with the exact version inventory`); - } - for (const carrier of bootstrapPlan.filter((row) => row.ecosystem === ecosystem)) { - if (states.get(carrier.name).version !== carrier.version) { - throw error(`${ecosystem} bootstrap plan version disagrees with the exact version inventory`); - } - } - } - const selected = new Set(selectedCarrierIds); - if (selected.size !== selectedCarrierIds.length) { - throw error("selected bootstrap carrier IDs must be unique"); - } - const finishById = new Map(); - const priorByEcosystem = new Map(); - const tokenState = { - burst: CRATES_IO_DEFAULT_NEW_CRATE_BURST, - refillSeconds: CRATES_IO_NEW_CRATE_REFILL_SECONDS, - tokenUnits: initialCargoTokens * CRATES_IO_NEW_CRATE_REFILL_SECONDS, - clockSeconds: 0, - }; - let criticalPathSeconds = 0; - let selectedCargoCount = 0; - let selectedNpmCount = 0; - for (const carrier of bootstrapPlan) { - const state = stateByEcosystem.get(carrier.ecosystem).get(carrier.name).state; - if (state === "published") { - finishById.set(carrier.id, 0); - continue; - } - if (!selected.has(carrier.id)) continue; - if (state !== "missing") { - throw error(`selected bootstrap carrier ${carrier.id} is not a brand-new identity`); - } - let startSeconds = 0; - for (const dependency of carrier.dependencies) { - const finish = finishById.get(dependency); - if (finish === undefined) { - throw error(`selected bootstrap carrier ${carrier.id} omits unsatisfied dependency ${dependency}`); - } - startSeconds = Math.max(startSeconds, finish); - } - const prior = priorByEcosystem.get(carrier.ecosystem); - if (prior !== undefined) startSeconds = Math.max(startSeconds, finishById.get(prior)); - if (carrier.ecosystem === "cargo") { - startSeconds = consumeTokenAtOrAfter(tokenState, startSeconds); - selectedCargoCount += 1; - } else { - selectedNpmCount += 1; - } - const finishSeconds = startSeconds - + (carrier.ecosystem === "cargo" ? cargoSecondsPerCarrier : npmSecondsPerCarrier); - finishById.set(carrier.id, finishSeconds); - priorByEcosystem.set(carrier.ecosystem, carrier.id); - criticalPathSeconds = Math.max(criticalPathSeconds, finishSeconds); - } - const unknown = [...selected].filter((id) => !finishById.has(id)); - if (unknown.length > 0) { - throw error(`selected bootstrap carrier IDs are absent or dependency-ineligible: ${unknown.join(", ")}`); - } - return { - criticalPathSeconds: Math.ceil(criticalPathSeconds), - selectedCargoCount, - selectedNpmCount, - }; -} - -function selectBootstrapPublicationBatch({ - bootstrapPlan, - cargoInventory, - npmInventory, - cargoSecondsPerCarrier, - npmSecondsPerCarrier, - initialCargoTokens, - availableSeconds, -}) { - validateBootstrapPublicationPlan(bootstrapPlan); - const cargoState = exactVersionStateByName(cargoInventory, "Cargo"); - const npmState = exactVersionStateByName(npmInventory, "npm"); - const states = new Map([["cargo", cargoState], ["npm", npmState]]); - const carrierById = new Map(bootstrapPlan.map((carrier) => [carrier.id, carrier])); - const selectedCarrierIds = []; - const selected = new Set(); - for (const carrier of bootstrapPlan) { - const state = states.get(carrier.ecosystem).get(carrier.name).state; - if (state !== "missing") continue; - const dependencyClosed = carrier.dependencies.every((dependency) => { - const dependencyCarrier = carrierById.get(dependency); - const dependencyState = states.get(dependencyCarrier.ecosystem).get(dependencyCarrier.name).state; - return dependencyState === "published" || selected.has(dependency); - }); - if (!dependencyClosed) continue; - const tentative = [...selectedCarrierIds, carrier.id]; - const schedule = bootstrapPublicationSchedule({ - bootstrapPlan, - cargoInventory, - npmInventory, - cargoSecondsPerCarrier, - npmSecondsPerCarrier, - selectedCarrierIds: tentative, - initialCargoTokens, - }); - if (schedule.criticalPathSeconds <= availableSeconds) { - selectedCarrierIds.push(carrier.id); - selected.add(carrier.id); - } - } - const schedule = bootstrapPublicationSchedule({ - bootstrapPlan, - cargoInventory, - npmInventory, - cargoSecondsPerCarrier, - npmSecondsPerCarrier, - selectedCarrierIds, - initialCargoTokens, - }); - return { selectedCarrierIds, ...schedule }; -} - -export function assessCratesIoBootstrapCapacity({ - inventory, - npmInventory = { - selectedIdentities: [], - publishedIdentities: [], - pendingVersions: [], - missingNames: [], - }, - bootstrapPlan = undefined, - cargoSecondsPerCarrier, - npmSecondsPerCarrier, - reconciliationSecondsPerCarrier, - reserveSeconds, - deadlineEpochSeconds, - nowEpochSeconds = Math.floor(Date.now() / 1000), -}) { - const nameInventory = inventory !== null - && typeof inventory === "object" - && Array.isArray(inventory.selectedNames) - && Array.isArray(inventory.existingNames) - && Array.isArray(inventory.missingNames); - const versionInventory = inventory !== null - && typeof inventory === "object" - && Array.isArray(inventory.selectedIdentities) - && Array.isArray(inventory.publishedIdentities) - && Array.isArray(inventory.pendingVersions) - && Array.isArray(inventory.missingNames); - if (!nameInventory && !versionInventory) { - throw error("Cargo inventory must contain either name state or exact-version state lists"); - } - if ( - npmInventory === null - || typeof npmInventory !== "object" - || !Array.isArray(npmInventory.selectedIdentities) - || !Array.isArray(npmInventory.publishedIdentities) - || !Array.isArray(npmInventory.pendingVersions) - || !Array.isArray(npmInventory.missingNames) - ) { - throw error("npm inventory must contain selected, published, pending-version, and missing-name lists"); - } - const missingCount = inventory.missingNames.length; - const selectedCount = versionInventory ? inventory.selectedIdentities.length : inventory.selectedNames.length; - const existingCount = selectedCount - missingCount; - const publishedCargoCount = versionInventory ? inventory.publishedIdentities.length : existingCount; - const cargoConflictCount = versionInventory ? inventory.pendingVersions.length : 0; - const pendingCargoCount = missingCount; - const selectedNpmCount = npmInventory.selectedIdentities.length; - const publishedNpmCount = npmInventory.publishedIdentities.length; - const npmConflictCount = npmInventory.pendingVersions.length; - const missingNpmCount = npmInventory.missingNames.length; - const pendingNpmCount = missingNpmCount; - if (publishedNpmCount + npmConflictCount + missingNpmCount !== selectedNpmCount) { - throw error("npm exact-version inventory does not partition every selected identity"); - } - if (versionInventory && publishedCargoCount + cargoConflictCount + pendingCargoCount !== selectedCount) { - throw error("Cargo exact-version inventory does not partition every selected identity"); - } - const remainingSeconds = deadlineEpochSeconds - nowEpochSeconds; - const parsedCargoSeconds = parseRegistryBootstrapCargoSeconds(cargoSecondsPerCarrier); - const parsedNpmSeconds = parseRegistryBootstrapNpmSeconds(npmSecondsPerCarrier); - const parsedReconciliationSeconds = parseRegistryBootstrapReconciliationSeconds(reconciliationSecondsPerCarrier); - const parsedReserveSeconds = parseRegistryBootstrapReserveSeconds(reserveSeconds); - const plannedPublicationSeconds = (pendingCargoCount * parsedCargoSeconds) + (pendingNpmCount * parsedNpmSeconds); - const reconciliationCount = publishedCargoCount + publishedNpmCount; - const plannedReconciliationSeconds = reconciliationCount * parsedReconciliationSeconds; - const initialCargoTokens = publishedCargoCount === 0 - ? CRATES_IO_DEFAULT_NEW_CRATE_BURST - : 0; - const defaultTokenBucket = cratesIoTokenBucketSchedule({ - publicationCount: pendingCargoCount, - burst: CRATES_IO_DEFAULT_NEW_CRATE_BURST, - refillSeconds: CRATES_IO_NEW_CRATE_REFILL_SECONDS, - workSeconds: parsedCargoSeconds, - initialTokens: initialCargoTokens, - }); - let admittedCarrierIds = []; - let admittedCargoCount = 0; - let admittedNpmCount = 0; - let plannedPublicationCriticalPathSeconds = plannedPublicationSeconds; - const availablePublicationSeconds = Math.max( - 0, - remainingSeconds - plannedReconciliationSeconds - parsedReserveSeconds, - ); - if (bootstrapPlan !== undefined) { - if (!versionInventory) throw error("exact-version Cargo inventory is required with a bootstrap publication plan"); - const batch = selectBootstrapPublicationBatch({ - bootstrapPlan, - cargoInventory: inventory, - npmInventory, - cargoSecondsPerCarrier: parsedCargoSeconds, - npmSecondsPerCarrier: parsedNpmSeconds, - initialCargoTokens, - availableSeconds: remainingSeconds < MINIMUM_MUTATION_WINDOW_SECONDS ? 0 : availablePublicationSeconds, - }); - admittedCarrierIds = batch.selectedCarrierIds; - admittedCargoCount = batch.selectedCargoCount; - admittedNpmCount = batch.selectedNpmCount; - plannedPublicationCriticalPathSeconds = batch.criticalPathSeconds; - } else if (missingCount + missingNpmCount > 0 && remainingSeconds >= MINIMUM_MUTATION_WINDOW_SECONDS) { - // Compatibility for name-only callers: admit the Cargo count that fits - // the official bucket and all npm identities only when their two-lane - // estimate fits. Exact release execution always supplies bootstrapPlan. - for (let count = 1; count <= pendingCargoCount; count += 1) { - const schedule = cratesIoTokenBucketSchedule({ - publicationCount: count, - burst: CRATES_IO_DEFAULT_NEW_CRATE_BURST, - refillSeconds: CRATES_IO_NEW_CRATE_REFILL_SECONDS, - workSeconds: parsedCargoSeconds, - initialTokens: initialCargoTokens, - }); - if (schedule.elapsedSeconds <= availablePublicationSeconds) admittedCargoCount = count; - } - admittedNpmCount = pendingNpmCount * parsedNpmSeconds <= availablePublicationSeconds ? pendingNpmCount : 0; - plannedPublicationCriticalPathSeconds = Math.max( - cratesIoTokenBucketSchedule({ - publicationCount: admittedCargoCount, - burst: CRATES_IO_DEFAULT_NEW_CRATE_BURST, - refillSeconds: CRATES_IO_NEW_CRATE_REFILL_SECONDS, - workSeconds: parsedCargoSeconds, - initialTokens: initialCargoTokens, - }).elapsedSeconds, - admittedNpmCount * parsedNpmSeconds, - ); - } - const admittedCount = bootstrapPlan === undefined - ? admittedCargoCount + admittedNpmCount - : admittedCarrierIds.length; - const remainingMutationCount = pendingCargoCount + pendingNpmCount - admittedCount; - const requiredWindowSeconds = Math.max( - MINIMUM_MUTATION_WINDOW_SECONDS, - plannedPublicationCriticalPathSeconds + plannedReconciliationSeconds + parsedReserveSeconds, - ); - const timeSatisfied = remainingSeconds >= requiredWindowSeconds; - const makesProgress = admittedCount > 0 || remainingMutationCount === 0; - const decision = timeSatisfied && makesProgress ? "execute" : "defer"; - return { - selectedCount, - existingCount, - publishedCargoCount, - cargoConflictCount, - pendingCargoCount, - selectedNpmCount, - publishedNpmCount, - npmConflictCount, - missingNpmCount, - pendingNpmCount, - missingCount, - missingNames: inventory.missingNames, - initialCargoTokens, - tokenBucketPublicationSeconds: defaultTokenBucket.elapsedSeconds, - tokenBucketWaitSeconds: defaultTokenBucket.waitSeconds, - defaultMinimumSeconds: defaultTokenBucket.elapsedSeconds, - remainingSeconds, - minimumMutationWindowSeconds: requiredWindowSeconds, - planningHeadroomSeconds: Math.max(0, remainingSeconds - requiredWindowSeconds), - plannedPublicationSeconds, - plannedPublicationCriticalPathSeconds, - reconciliationCount, - plannedReconciliationSeconds, - cargoSecondsPerCarrier: parsedCargoSeconds, - npmSecondsPerCarrier: parsedNpmSeconds, - reconciliationSecondsPerCarrier: parsedReconciliationSeconds, - reserveSeconds: parsedReserveSeconds, - admittedCarrierIds, - admittedCargoCount, - admittedNpmCount, - admittedCount, - remainingMutationCount, - completeAfterExecution: remainingMutationCount === 0, - notBeforeEpochSeconds: decision === "defer" - ? nowEpochSeconds + CRATES_IO_NEW_CRATE_REFILL_SECONDS - : null, - decision, - timeSatisfied, - allowed: decision === "execute", - }; -} - -function exactVersionStateByName(inventory, ecosystem) { - const selected = new Map(); - for (const [index, identity] of inventory.selectedIdentities.entries()) { - if ( - identity === null - || typeof identity !== "object" - || typeof identity.name !== "string" - || identity.name.length === 0 - || typeof identity.version !== "string" - || identity.version.length === 0 - ) { - throw error(`${ecosystem} selected identity ${index} must contain a name and version`); - } - if (selected.has(identity.name)) { - throw error(`${ecosystem} version inventory selects duplicate package name ${identity.name}`); - } - selected.set(identity.name, { version: identity.version, state: null }); - } - - function recordIdentities(identities, state) { - const observed = new Set(); - for (const [index, identity] of identities.entries()) { - if ( - identity === null - || typeof identity !== "object" - || typeof identity.name !== "string" - || typeof identity.version !== "string" - ) { - throw error(`${ecosystem} ${state} identity ${index} must contain a name and version`); - } - const expected = selected.get(identity.name); - if (expected === undefined || expected.version !== identity.version) { - throw error(`${ecosystem} ${state} identity ${identity.name}@${identity.version} is absent from the exact selection`); - } - if (observed.has(identity.name) || expected.state !== null) { - throw error(`${ecosystem} identity ${identity.name} is duplicated across version-inventory states`); - } - observed.add(identity.name); - expected.state = state; - } - } - - recordIdentities(inventory.publishedIdentities, "published"); - recordIdentities(inventory.pendingVersions, "pending"); - const missing = new Set(); - for (const [index, name] of inventory.missingNames.entries()) { - if (typeof name !== "string" || name.length === 0) { - throw error(`${ecosystem} missing-name identity ${index} must be a nonempty string`); - } - const expected = selected.get(name); - if (expected === undefined) { - throw error(`${ecosystem} missing name ${name} is absent from the exact selection`); - } - if (missing.has(name) || expected.state !== null) { - throw error(`${ecosystem} identity ${name} is duplicated across version-inventory states`); - } - missing.add(name); - expected.state = "missing"; - } - const unclassified = [...selected].filter(([, value]) => value.state === null).map(([name]) => name); - if (unclassified.length > 0) { - throw error(`${ecosystem} version inventory does not classify ${unclassified.join(", ")}`); - } - return selected; -} - -function durationText(seconds) { - const minutes = Math.ceil(seconds / 60); - const hours = Math.floor(minutes / 60); - const remainder = minutes % 60; - return hours === 0 ? `${minutes}m` : `${hours}h ${remainder}m`; -} - -export function cratesIoCapacitySummary(assessment) { - return [ - "### Cargo/npm bootstrap token-bucket admission", - "", - `- Exact-lock Cargo names selected: ${assessment.selectedCount}`, - `- Names already present on crates.io: ${assessment.existingCount}`, - `- Brand-new names still missing: ${assessment.missingCount}`, - `- Cargo versions already public: ${assessment.publishedCargoCount}`, - `- Existing Cargo names left for normal trusted publication: ${assessment.cargoConflictCount}`, - `- Brand-new Cargo names still requiring their first version: ${assessment.pendingCargoCount}`, - `- Exact-lock npm versions selected: ${assessment.selectedNpmCount}`, - `- npm versions already public: ${assessment.publishedNpmCount}`, - `- Existing npm names left for normal trusted publication: ${assessment.npmConflictCount}`, - `- Brand-new npm names still requiring their first version: ${assessment.pendingNpmCount}`, - `- Conservatively available Cargo tokens at invocation start: ${assessment.initialCargoTokens}`, - `- Official token-bucket time for every pending Cargo identity: ${durationText(assessment.tokenBucketPublicationSeconds)} (${durationText(assessment.tokenBucketWaitSeconds)} waiting, with publication work overlapping refill)`, - `- Aggregate carrier publication work: ${durationText(assessment.plannedPublicationSeconds)} (${assessment.cargoSecondsPerCarrier}s/Cargo + ${assessment.npmSecondsPerCarrier}s/npm)`, - `- Cargo/npm lane + dependency-DAG critical path: ${durationText(assessment.plannedPublicationCriticalPathSeconds)}`, - `- Planned public-version reconciliation time: ${durationText(assessment.plannedReconciliationSeconds)} (${assessment.reconciliationSecondsPerCarrier}s across ${assessment.reconciliationCount} carriers)`, - `- Non-publication reserve: ${durationText(assessment.reserveSeconds)}`, - `- Admission-model mutation window: ${durationText(assessment.minimumMutationWindowSeconds)}`, - `- Remaining bounded mutation window: ${durationText(Math.max(0, assessment.remainingSeconds))}`, - `- Additional planning headroom: ${durationText(assessment.planningHeadroomSeconds)}`, - `- Dependency-closed carriers admitted for this invocation: ${assessment.admittedCount} (${assessment.admittedCargoCount} Cargo, ${assessment.admittedNpmCount} npm)`, - `- Carriers remaining after the admitted invocation: ${assessment.remainingMutationCount}`, - "- Model boundary: timing is a calibrated admission estimate, not an upper bound on external registry latency; the hard deadline and exact-lock checkpoint recovery remain authoritative.", - `- Decision: ${assessment.decision.toUpperCase()}`, - "", - ].join("\n"); -} diff --git a/tools/release/crates-io-bootstrap-capacity.mts b/tools/release/crates-io-bootstrap-capacity.mts new file mode 100644 index 000000000..f8894dc12 --- /dev/null +++ b/tools/release/crates-io-bootstrap-capacity.mts @@ -0,0 +1,1009 @@ +import process from 'node:process'; + +import { + CRATES_IO_READ_START_INTERVAL_MILLISECONDS, + createCratesIoReadGate, + retryAfterSeconds, + registryRetryDelaySeconds, + registryStatusRetryable, +} from './registry-http-retry.mts'; +export { CRATES_IO_READ_START_INTERVAL_MILLISECONDS, createCratesIoReadGate }; +export { + RegistryPublicationDeferredError, + isRegistryPublicationDeferredError, +} from './registry-publication-deferral.mts'; + +// Primary contract: https://crates.io/docs/rate-limits. The upstream +// implementation independently defines these per-user leaky buckets in +// rust-lang/crates.io/src/rate_limiter.rs. Keep tests and maintainer setup in +// sync if crates.io changes either published limit. +export const CRATES_IO_DEFAULT_NEW_CRATE_BURST = 5; +export const CRATES_IO_NEW_CRATE_REFILL_SECONDS = 10 * 60; +export const REGISTRY_MUTATION_DEADLINE_VARIABLE = 'REGISTRY_MUTATION_DEADLINE_EPOCH'; +export const REGISTRY_BOOTSTRAP_CARGO_SECONDS_VARIABLE = + 'REGISTRY_BOOTSTRAP_CARGO_SECONDS_PER_CARRIER'; +export const REGISTRY_BOOTSTRAP_NPM_SECONDS_VARIABLE = 'REGISTRY_BOOTSTRAP_NPM_SECONDS_PER_CARRIER'; +export const REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_VARIABLE = + 'REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_PER_CARRIER'; +export const REGISTRY_BOOTSTRAP_RESERVE_SECONDS_VARIABLE = 'REGISTRY_BOOTSTRAP_RESERVE_SECONDS'; +export const REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER = 30; +export const REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER = 30; +export const REGISTRY_BOOTSTRAP_INTEGRITY_CONCURRENCY = 8; +// registry-integrity bounds one request at 45s. At the fixed concurrency of +// eight, six seconds per public carrier covers a complete worst-case request +// wave; the separate reserve covers bounded retry and local ledger overhead. +export const REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER = 6; +// These timing values are calibrated admission estimates, not upper bounds on third-party +// registry latency. A separate absolute deadline stops mutation; immutable +// public versions and checkpoint receipts make interrupted runs resumable. +export const REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS = 10 * 60; + +const DEFAULT_CRATES_IO_API = 'https://crates.io/api/v1'; +const USER_AGENT = 'oliphaunt-bootstrap-capacity/1; https://github.com/f0rr0/oliphaunt'; +const REQUEST_ATTEMPTS = 8; +const REQUEST_TIMEOUT_MS = 30_000; +const DEADLINE_RESERVE_MS = 5_000; +const MAX_READ_RETRY_DELAY_BUDGET_SECONDS = 3 * 60; +const MAX_RATE_LIMIT_RETRY_DELAY_SECONDS = 5 * 60; +const MINIMUM_MUTATION_WINDOW_SECONDS = 15 * 60; +const MAX_PLANNING_SECONDS_PER_CARRIER = 60 * 60; +const MAX_RESERVE_SECONDS = 6 * 60 * 60; + +function error(message) { + return new Error(`crates-io-bootstrap-capacity: ${message}`); +} + +function compareText(left, right) { + const a = String(left); + const b = String(right); + return a < b ? -1 : a > b ? 1 : 0; +} + +function strictNonNegativeInteger(raw, context, maximum = Number.MAX_SAFE_INTEGER) { + const text = typeof raw === 'number' ? String(raw) : raw?.trim?.(); + if (typeof text !== 'string' || !/^(?:0|[1-9][0-9]*)$/u.test(text)) { + throw error(`${context} must be a base-10 non-negative integer`); + } + const value = Number(text); + if (!Number.isSafeInteger(value) || value > maximum) { + throw error(`${context} must not exceed ${maximum}`); + } + return value; +} + +export function parseRegistryMutationDeadline(raw) { + return strictNonNegativeInteger( + raw, + REGISTRY_MUTATION_DEADLINE_VARIABLE, + Math.floor(Number.MAX_SAFE_INTEGER / 1000), + ); +} + +function planningSeconds(raw, variable, fallback, { minimum, maximum }) { + if (raw === undefined || raw === null || String(raw).trim().length === 0) { + return fallback; + } + const value = strictNonNegativeInteger(raw, variable, maximum); + if (value < minimum) { + throw error(`${variable} must be at least ${minimum}`); + } + return value; +} + +export function parseRegistryBootstrapCargoSeconds(raw) { + return planningSeconds( + raw, + REGISTRY_BOOTSTRAP_CARGO_SECONDS_VARIABLE, + REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER, + { + minimum: REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER, + maximum: MAX_PLANNING_SECONDS_PER_CARRIER, + }, + ); +} + +export function parseRegistryBootstrapNpmSeconds(raw) { + return planningSeconds( + raw, + REGISTRY_BOOTSTRAP_NPM_SECONDS_VARIABLE, + REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER, + { + minimum: REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER, + maximum: MAX_PLANNING_SECONDS_PER_CARRIER, + }, + ); +} + +export function parseRegistryBootstrapReconciliationSeconds(raw) { + return planningSeconds( + raw, + REGISTRY_BOOTSTRAP_RECONCILIATION_SECONDS_VARIABLE, + REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER, + { + minimum: REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER, + maximum: MAX_PLANNING_SECONDS_PER_CARRIER, + }, + ); +} + +export function parseRegistryBootstrapReserveSeconds(raw) { + return planningSeconds( + raw, + REGISTRY_BOOTSTRAP_RESERVE_SECONDS_VARIABLE, + REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS, + { + minimum: REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS, + maximum: MAX_RESERVE_SECONDS, + }, + ); +} + +function selectedCargoIdentities(plan) { + if (!Array.isArray(plan)) { + throw error('bootstrap publication plan must be a list'); + } + const identities = plan + .filter(({ ecosystem }) => ecosystem === 'cargo') + .map(({ name, version }, index) => { + if ( + typeof name !== 'string' || + name.length === 0 || + typeof version !== 'string' || + version.length === 0 + ) { + throw error(`Cargo plan entry ${index} must have a package name and version`); + } + return { name, version }; + }); + const names = identities.map(({ name }) => name); + const unique = [...new Set(names)].sort(compareText); + if (unique.length !== names.length) { + throw error('exact publication lock selects duplicate Cargo package names'); + } + return identities.sort((left, right) => compareText(left.name, right.name)); +} + +function selectedCargoNames(plan) { + return selectedCargoIdentities(plan).map(({ name }) => name); +} + +async function closeResponse(response) { + try { + await response.body?.cancel?.(); + } catch { + // The bounded existence check does not need the response body. + } +} + +async function crateResourceExists( + resourceSegments, + label, + { apiBase, fetchImpl, nowImpl, deadlineEpochSeconds, readGate }, +) { + const resource = resourceSegments.map((segment) => encodeURIComponent(segment)).join('/'); + const url = `${apiBase.replace(/\/+$/u, '')}/crates/${resource}`; + let lastFailure = null; + let retryDelaySpentSeconds = 0; + for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { + try { + const remainingMilliseconds = (deadlineEpochSeconds - nowImpl()) * 1000 - DEADLINE_RESERVE_MS; + if (remainingMilliseconds <= 0) { + throw error( + `read-only existence check for ${label} cannot start before the registry mutation deadline`, + ); + } + await readGate.beforeRequest(label, deadlineEpochSeconds); + const requestRemainingMilliseconds = + (deadlineEpochSeconds - nowImpl()) * 1000 - DEADLINE_RESERVE_MS; + if (requestRemainingMilliseconds <= 0) { + throw error( + `read-only existence check for ${label} cannot start before the registry mutation deadline`, + ); + } + const response = await fetchImpl(url, { + headers: { + Accept: 'application/json', + 'User-Agent': USER_AGENT, + }, + redirect: 'error', + signal: AbortSignal.timeout( + Math.max(1, Math.min(REQUEST_TIMEOUT_MS, requestRemainingMilliseconds)), + ), + }); + if (response.status === 200) { + await closeResponse(response); + return true; + } + if (response.status === 404) { + await closeResponse(response); + return false; + } + const retryable = registryStatusRetryable(response.status); + const status = response.status; + const headers = response.headers; + await closeResponse(response); + lastFailure = `HTTP ${status}`; + if (!retryable || attempt + 1 >= REQUEST_ATTEMPTS) { + break; + } + const requestedDelaySeconds = retryAfterSeconds(headers, nowImpl() * 1000); + const delaySeconds = + requestedDelaySeconds ?? + (status === 429 + ? Math.min(60 * 2 ** attempt, MAX_RATE_LIMIT_RETRY_DELAY_SECONDS) + : registryRetryDelaySeconds({ headers, attempt, now: nowImpl() * 1000 })); + if (delaySeconds > MAX_READ_RETRY_DELAY_BUDGET_SECONDS - retryDelaySpentSeconds) { + throw error( + `read-only existence check for ${label} exceeds its bounded ${MAX_READ_RETRY_DELAY_BUDGET_SECONDS}s retry-delay budget; retry the release later`, + ); + } + const delayMilliseconds = Math.ceil(delaySeconds * 1000); + const retryRemainingMilliseconds = + (deadlineEpochSeconds - nowImpl()) * 1000 - DEADLINE_RESERVE_MS; + if (delayMilliseconds >= retryRemainingMilliseconds) { + throw error( + `read-only existence check for ${label} cannot retry before the registry mutation deadline`, + ); + } + retryDelaySpentSeconds += delaySeconds; + readGate.defer(delaySeconds); + } catch (cause) { + if ( + cause instanceof Error && + (cause.message.startsWith('crates-io-bootstrap-capacity:') || + cause.message.startsWith('registry-http-retry:')) + ) { + throw cause; + } + lastFailure = cause instanceof Error ? cause.message : String(cause); + if (attempt + 1 >= REQUEST_ATTEMPTS) { + break; + } + const delaySeconds = registryRetryDelaySeconds({ attempt, now: nowImpl() * 1000 }); + if (delaySeconds > MAX_READ_RETRY_DELAY_BUDGET_SECONDS - retryDelaySpentSeconds) { + throw error( + `read-only existence check for ${label} exceeds its bounded ${MAX_READ_RETRY_DELAY_BUDGET_SECONDS}s retry-delay budget; retry the release later`, + ); + } + const delayMilliseconds = Math.ceil(delaySeconds * 1000); + const retryRemainingMilliseconds = + (deadlineEpochSeconds - nowImpl()) * 1000 - DEADLINE_RESERVE_MS; + if (delayMilliseconds >= retryRemainingMilliseconds) { + throw error( + `read-only existence check for ${label} cannot retry before the registry mutation deadline`, + ); + } + retryDelaySpentSeconds += delaySeconds; + readGate.defer(delaySeconds); + } + } + throw error( + `cannot determine whether Cargo identity ${label} exists on crates.io: ${lastFailure ?? 'unknown response'}`, + ); +} + +export async function inspectCratesIoBootstrapNames({ + plan, + apiBase = process.env.CRATES_IO_API ?? DEFAULT_CRATES_IO_API, + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + nowImpl = () => Date.now() / 1000, + deadlineEpochSeconds, + concurrency = 8, +}) { + if (!Number.isSafeInteger(deadlineEpochSeconds) || deadlineEpochSeconds <= nowImpl()) { + throw error(`${REGISTRY_MUTATION_DEADLINE_VARIABLE} must be a future Unix timestamp`); + } + if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) { + throw error('existence-check concurrency must be an integer from 1 through 32'); + } + const names = selectedCargoNames(plan); + const readGate = createCratesIoReadGate({ nowImpl, sleepImpl }); + const observed = new Array(names.length); + let cursor = 0; + const workers = Array.from({ length: Math.min(concurrency, names.length) }, async () => { + for (;;) { + const index = cursor; + cursor += 1; + if (index >= names.length) return; + observed[index] = await crateResourceExists([names[index]], names[index], { + apiBase, + fetchImpl, + nowImpl, + deadlineEpochSeconds, + readGate, + }); + } + }); + await Promise.all(workers); + return { + selectedNames: names, + existingNames: names.filter((_, index) => observed[index]), + missingNames: names.filter((_, index) => !observed[index]), + }; +} + +export async function inspectCratesIoVersionState({ + plan, + apiBase = process.env.CRATES_IO_API ?? DEFAULT_CRATES_IO_API, + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + nowImpl = () => Date.now() / 1000, + deadlineEpochSeconds, + concurrency = 8, +}) { + if (!Number.isSafeInteger(deadlineEpochSeconds) || deadlineEpochSeconds <= nowImpl()) { + throw error(`${REGISTRY_MUTATION_DEADLINE_VARIABLE} must be a future Unix timestamp`); + } + if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) { + throw error('existence-check concurrency must be an integer from 1 through 32'); + } + const identities = selectedCargoIdentities(plan); + const readGate = createCratesIoReadGate({ nowImpl, sleepImpl }); + const observed = new Array(identities.length); + let cursor = 0; + const workers = Array.from({ length: Math.min(concurrency, identities.length) }, async () => { + for (;;) { + const index = cursor; + cursor += 1; + if (index >= identities.length) return; + const identity = identities[index]; + const label = `${identity.name}@${identity.version}`; + const versionExists = await crateResourceExists([identity.name, identity.version], label, { + apiBase, + fetchImpl, + nowImpl, + deadlineEpochSeconds, + readGate, + }); + if (versionExists) { + observed[index] = 'published'; + continue; + } + const nameExists = await crateResourceExists([identity.name], identity.name, { + apiBase, + fetchImpl, + nowImpl, + deadlineEpochSeconds, + readGate, + }); + observed[index] = nameExists ? 'pending-version' : 'missing-name'; + } + }); + await Promise.all(workers); + const withState = identities.map((identity, index) => ({ ...identity, state: observed[index] })); + return { + selectedIdentities: identities, + publishedIdentities: withState + .filter(({ state }) => state === 'published') + .map(({ name, version }) => ({ name, version })), + pendingVersions: withState + .filter(({ state }) => state === 'pending-version') + .map(({ name, version }) => ({ name, version })), + missingNames: withState.filter(({ state }) => state === 'missing-name').map(({ name }) => name), + }; +} + +function validateBootstrapPublicationPlan(bootstrapPlan) { + if (!Array.isArray(bootstrapPlan)) + throw error('bootstrap publication plan must be a carrier list'); + const positions = new Map(); + let priorCarrier = null; + for (const [index, carrier] of bootstrapPlan.entries()) { + if ( + carrier === null || + typeof carrier !== 'object' || + typeof carrier.id !== 'string' || + carrier.id !== `${carrier.ecosystem}:${carrier.name}` || + !new Set(['cargo', 'npm']).has(carrier.ecosystem) || + !Number.isSafeInteger(carrier.publishOrder) || + carrier.publishOrder < 0 || + (priorCarrier !== null && + (carrier.publishOrder < priorCarrier.publishOrder || + (carrier.publishOrder === priorCarrier.publishOrder && carrier.id <= priorCarrier.id))) + ) { + throw error(`bootstrap carrier ${index} is not in strict canonical publish order`); + } + if (positions.has(carrier.id)) throw error(`bootstrap carrier ${carrier.id} is duplicated`); + if ( + !Array.isArray(carrier.dependencies) || + new Set(carrier.dependencies).size !== carrier.dependencies.length || + carrier.dependencies.some( + (dependency) => typeof dependency !== 'string' || dependency.length === 0, + ) + ) { + throw error(`bootstrap carrier ${carrier.id} dependencies must be a unique string list`); + } + positions.set(carrier.id, index); + priorCarrier = carrier; + } + for (const [index, carrier] of bootstrapPlan.entries()) { + for (const dependency of carrier.dependencies) { + const position = positions.get(dependency); + if (position === undefined) + throw error(`${carrier.id} refers to unknown bootstrap dependency ${dependency}`); + if (position >= index) + throw error(`${carrier.id} is not ordered after bootstrap dependency ${dependency}`); + } + } +} + +function validatedTokenBucketInputs({ + publicationCount, + burst, + refillSeconds, + workSeconds, + initialTokens, +}) { + for (const [value, context] of [ + [publicationCount, 'publicationCount'], + [burst, 'burst'], + [refillSeconds, 'refillSeconds'], + [workSeconds, 'workSeconds'], + [initialTokens, 'initialTokens'], + ]) { + if (!Number.isSafeInteger(value) || value < 0) { + throw error(`${context} must be a non-negative integer`); + } + } + if (burst < 1 || refillSeconds < 1 || initialTokens > burst) { + throw error('token bucket burst/refill must be positive and initialTokens cannot exceed burst'); + } +} + +/** + * Model crates.io's documented per-user token bucket without double-counting + * upload work. Tokens refill while a frozen carrier is being published; when + * work is slower than refill, the bucket may recover completely between + * operations. Returned times are conservative whole seconds. + */ +export function cratesIoTokenBucketSchedule({ + publicationCount, + burst, + refillSeconds, + workSeconds, + initialTokens = burst, +}) { + validatedTokenBucketInputs({ + publicationCount, + burst, + refillSeconds, + workSeconds, + initialTokens, + }); + let elapsedSeconds = 0; + let tokenClockSeconds = 0; + // One token is exactly `refillSeconds` integer credit units. All planning + // inputs are whole seconds, so this rational representation cannot drift + // across a refill boundary and conservatively round 60s into 61s. + const capacityUnits = burst * refillSeconds; + let tokenUnits = initialTokens * refillSeconds; + let waitSeconds = 0; + const startSeconds = []; + for (let index = 0; index < publicationCount; index += 1) { + tokenUnits = Math.min(capacityUnits, tokenUnits + (elapsedSeconds - tokenClockSeconds)); + tokenClockSeconds = elapsedSeconds; + if (tokenUnits < refillSeconds) { + const wait = refillSeconds - tokenUnits; + elapsedSeconds += wait; + waitSeconds += wait; + tokenUnits = refillSeconds; + tokenClockSeconds = elapsedSeconds; + } + startSeconds.push(elapsedSeconds); + tokenUnits -= refillSeconds; + elapsedSeconds += workSeconds; + } + return { + elapsedSeconds: Math.ceil(elapsedSeconds), + waitSeconds: Math.ceil(waitSeconds), + workSeconds: publicationCount * workSeconds, + publicationCount, + initialTokens, + startSeconds, + }; +} + +function consumeTokenAtOrAfter(state, earliestStartSeconds) { + let startSeconds = earliestStartSeconds; + state.tokenUnits = Math.min( + state.burst * state.refillSeconds, + state.tokenUnits + (startSeconds - state.clockSeconds), + ); + state.clockSeconds = startSeconds; + if (state.tokenUnits < state.refillSeconds) { + startSeconds += state.refillSeconds - state.tokenUnits; + state.tokenUnits = state.refillSeconds; + state.clockSeconds = startSeconds; + } + state.tokenUnits -= state.refillSeconds; + return startSeconds; +} + +export function bootstrapPublicationCriticalPathSeconds(bootstrapPlan, carrierSeconds) { + validateBootstrapPublicationPlan(bootstrapPlan); + if (!(carrierSeconds instanceof Map)) { + throw error('bootstrap carrier seconds must be a Map keyed by carrier ID'); + } + const finishById = new Map(); + const priorByEcosystem = new Map(); + let criticalPathSeconds = 0; + for (const carrier of bootstrapPlan) { + const seconds = carrierSeconds.get(carrier.id); + if (!Number.isSafeInteger(seconds) || seconds < 0) { + throw error(`${carrier.id} must have a non-negative integer bootstrap budget`); + } + let startSeconds = 0; + for (const dependency of carrier.dependencies) { + startSeconds = Math.max(startSeconds, finishById.get(dependency)); + } + const prior = priorByEcosystem.get(carrier.ecosystem); + if (prior !== undefined) startSeconds = Math.max(startSeconds, finishById.get(prior)); + const finishSeconds = startSeconds + seconds; + if (!Number.isSafeInteger(finishSeconds)) + throw error('bootstrap publication critical path exceeds the safe integer range'); + finishById.set(carrier.id, finishSeconds); + priorByEcosystem.set(carrier.ecosystem, carrier.id); + criticalPathSeconds = Math.max(criticalPathSeconds, finishSeconds); + } + return criticalPathSeconds; +} + +function bootstrapPublicationSchedule({ + bootstrapPlan, + cargoInventory, + npmInventory, + cargoSecondsPerCarrier, + npmSecondsPerCarrier, + selectedCarrierIds, + initialCargoTokens, +}) { + validateBootstrapPublicationPlan(bootstrapPlan); + const cargoState = exactVersionStateByName(cargoInventory, 'Cargo'); + const npmState = exactVersionStateByName(npmInventory, 'npm'); + const stateByEcosystem = new Map([ + ['cargo', cargoState], + ['npm', npmState], + ]); + for (const ecosystem of ['cargo', 'npm']) { + const planned = new Set( + bootstrapPlan.filter((carrier) => carrier.ecosystem === ecosystem).map(({ name }) => name), + ); + const states = stateByEcosystem.get(ecosystem); + if ( + [...planned].some((name) => !states.has(name)) || + [...states].some(([name, state]) => state.state === 'missing' && !planned.has(name)) + ) { + throw error(`${ecosystem} bootstrap plan disagrees with the exact version inventory`); + } + for (const carrier of bootstrapPlan.filter((row) => row.ecosystem === ecosystem)) { + if (states.get(carrier.name).version !== carrier.version) { + throw error( + `${ecosystem} bootstrap plan version disagrees with the exact version inventory`, + ); + } + } + } + const selected = new Set(selectedCarrierIds); + if (selected.size !== selectedCarrierIds.length) { + throw error('selected bootstrap carrier IDs must be unique'); + } + const finishById = new Map(); + const priorByEcosystem = new Map(); + const tokenState = { + burst: CRATES_IO_DEFAULT_NEW_CRATE_BURST, + refillSeconds: CRATES_IO_NEW_CRATE_REFILL_SECONDS, + tokenUnits: initialCargoTokens * CRATES_IO_NEW_CRATE_REFILL_SECONDS, + clockSeconds: 0, + }; + let criticalPathSeconds = 0; + let selectedCargoCount = 0; + let selectedNpmCount = 0; + for (const carrier of bootstrapPlan) { + const state = stateByEcosystem.get(carrier.ecosystem).get(carrier.name).state; + if (state === 'published') { + finishById.set(carrier.id, 0); + continue; + } + if (!selected.has(carrier.id)) continue; + if (state !== 'missing') { + throw error(`selected bootstrap carrier ${carrier.id} is not a brand-new identity`); + } + let startSeconds = 0; + for (const dependency of carrier.dependencies) { + const finish = finishById.get(dependency); + if (finish === undefined) { + throw error( + `selected bootstrap carrier ${carrier.id} omits unsatisfied dependency ${dependency}`, + ); + } + startSeconds = Math.max(startSeconds, finish); + } + const prior = priorByEcosystem.get(carrier.ecosystem); + if (prior !== undefined) startSeconds = Math.max(startSeconds, finishById.get(prior)); + if (carrier.ecosystem === 'cargo') { + startSeconds = consumeTokenAtOrAfter(tokenState, startSeconds); + selectedCargoCount += 1; + } else { + selectedNpmCount += 1; + } + const finishSeconds = + startSeconds + + (carrier.ecosystem === 'cargo' ? cargoSecondsPerCarrier : npmSecondsPerCarrier); + finishById.set(carrier.id, finishSeconds); + priorByEcosystem.set(carrier.ecosystem, carrier.id); + criticalPathSeconds = Math.max(criticalPathSeconds, finishSeconds); + } + const unknown = [...selected].filter((id) => !finishById.has(id)); + if (unknown.length > 0) { + throw error( + `selected bootstrap carrier IDs are absent or dependency-ineligible: ${unknown.join(', ')}`, + ); + } + return { + criticalPathSeconds: Math.ceil(criticalPathSeconds), + selectedCargoCount, + selectedNpmCount, + }; +} + +function selectBootstrapPublicationBatch({ + bootstrapPlan, + cargoInventory, + npmInventory, + cargoSecondsPerCarrier, + npmSecondsPerCarrier, + initialCargoTokens, + availableSeconds, +}) { + validateBootstrapPublicationPlan(bootstrapPlan); + const cargoState = exactVersionStateByName(cargoInventory, 'Cargo'); + const npmState = exactVersionStateByName(npmInventory, 'npm'); + const states = new Map([ + ['cargo', cargoState], + ['npm', npmState], + ]); + const carrierById = new Map(bootstrapPlan.map((carrier) => [carrier.id, carrier])); + const selectedCarrierIds = []; + const selected = new Set(); + for (const carrier of bootstrapPlan) { + const state = states.get(carrier.ecosystem).get(carrier.name).state; + if (state !== 'missing') continue; + const dependencyClosed = carrier.dependencies.every((dependency) => { + const dependencyCarrier = carrierById.get(dependency); + const dependencyState = states + .get(dependencyCarrier.ecosystem) + .get(dependencyCarrier.name).state; + return dependencyState === 'published' || selected.has(dependency); + }); + if (!dependencyClosed) continue; + const tentative = [...selectedCarrierIds, carrier.id]; + const schedule = bootstrapPublicationSchedule({ + bootstrapPlan, + cargoInventory, + npmInventory, + cargoSecondsPerCarrier, + npmSecondsPerCarrier, + selectedCarrierIds: tentative, + initialCargoTokens, + }); + if (schedule.criticalPathSeconds <= availableSeconds) { + selectedCarrierIds.push(carrier.id); + selected.add(carrier.id); + } + } + const schedule = bootstrapPublicationSchedule({ + bootstrapPlan, + cargoInventory, + npmInventory, + cargoSecondsPerCarrier, + npmSecondsPerCarrier, + selectedCarrierIds, + initialCargoTokens, + }); + return { selectedCarrierIds, ...schedule }; +} + +export function assessCratesIoBootstrapCapacity({ + inventory, + npmInventory = { + selectedIdentities: [], + publishedIdentities: [], + pendingVersions: [], + missingNames: [], + }, + bootstrapPlan = undefined, + cargoSecondsPerCarrier, + npmSecondsPerCarrier, + reconciliationSecondsPerCarrier, + reserveSeconds, + deadlineEpochSeconds, + nowEpochSeconds = Math.floor(Date.now() / 1000), +}) { + const nameInventory = + inventory !== null && + typeof inventory === 'object' && + Array.isArray(inventory.selectedNames) && + Array.isArray(inventory.existingNames) && + Array.isArray(inventory.missingNames); + const versionInventory = + inventory !== null && + typeof inventory === 'object' && + Array.isArray(inventory.selectedIdentities) && + Array.isArray(inventory.publishedIdentities) && + Array.isArray(inventory.pendingVersions) && + Array.isArray(inventory.missingNames); + if (!nameInventory && !versionInventory) { + throw error('Cargo inventory must contain either name state or exact-version state lists'); + } + if ( + npmInventory === null || + typeof npmInventory !== 'object' || + !Array.isArray(npmInventory.selectedIdentities) || + !Array.isArray(npmInventory.publishedIdentities) || + !Array.isArray(npmInventory.pendingVersions) || + !Array.isArray(npmInventory.missingNames) + ) { + throw error( + 'npm inventory must contain selected, published, pending-version, and missing-name lists', + ); + } + const missingCount = inventory.missingNames.length; + const selectedCount = versionInventory + ? inventory.selectedIdentities.length + : inventory.selectedNames.length; + const existingCount = selectedCount - missingCount; + const publishedCargoCount = versionInventory + ? inventory.publishedIdentities.length + : existingCount; + const cargoConflictCount = versionInventory ? inventory.pendingVersions.length : 0; + const pendingCargoCount = missingCount; + const selectedNpmCount = npmInventory.selectedIdentities.length; + const publishedNpmCount = npmInventory.publishedIdentities.length; + const npmConflictCount = npmInventory.pendingVersions.length; + const missingNpmCount = npmInventory.missingNames.length; + const pendingNpmCount = missingNpmCount; + if (publishedNpmCount + npmConflictCount + missingNpmCount !== selectedNpmCount) { + throw error('npm exact-version inventory does not partition every selected identity'); + } + if ( + versionInventory && + publishedCargoCount + cargoConflictCount + pendingCargoCount !== selectedCount + ) { + throw error('Cargo exact-version inventory does not partition every selected identity'); + } + const remainingSeconds = deadlineEpochSeconds - nowEpochSeconds; + const parsedCargoSeconds = parseRegistryBootstrapCargoSeconds(cargoSecondsPerCarrier); + const parsedNpmSeconds = parseRegistryBootstrapNpmSeconds(npmSecondsPerCarrier); + const parsedReconciliationSeconds = parseRegistryBootstrapReconciliationSeconds( + reconciliationSecondsPerCarrier, + ); + const parsedReserveSeconds = parseRegistryBootstrapReserveSeconds(reserveSeconds); + const plannedPublicationSeconds = + pendingCargoCount * parsedCargoSeconds + pendingNpmCount * parsedNpmSeconds; + const reconciliationCount = publishedCargoCount + publishedNpmCount; + const plannedReconciliationSeconds = reconciliationCount * parsedReconciliationSeconds; + const initialCargoTokens = publishedCargoCount === 0 ? CRATES_IO_DEFAULT_NEW_CRATE_BURST : 0; + const defaultTokenBucket = cratesIoTokenBucketSchedule({ + publicationCount: pendingCargoCount, + burst: CRATES_IO_DEFAULT_NEW_CRATE_BURST, + refillSeconds: CRATES_IO_NEW_CRATE_REFILL_SECONDS, + workSeconds: parsedCargoSeconds, + initialTokens: initialCargoTokens, + }); + let admittedCarrierIds = []; + let admittedCargoCount = 0; + let admittedNpmCount = 0; + let plannedPublicationCriticalPathSeconds = plannedPublicationSeconds; + const availablePublicationSeconds = Math.max( + 0, + remainingSeconds - plannedReconciliationSeconds - parsedReserveSeconds, + ); + if (bootstrapPlan !== undefined) { + if (!versionInventory) + throw error('exact-version Cargo inventory is required with a bootstrap publication plan'); + const batch = selectBootstrapPublicationBatch({ + bootstrapPlan, + cargoInventory: inventory, + npmInventory, + cargoSecondsPerCarrier: parsedCargoSeconds, + npmSecondsPerCarrier: parsedNpmSeconds, + initialCargoTokens, + availableSeconds: + remainingSeconds < MINIMUM_MUTATION_WINDOW_SECONDS ? 0 : availablePublicationSeconds, + }); + admittedCarrierIds = batch.selectedCarrierIds; + admittedCargoCount = batch.selectedCargoCount; + admittedNpmCount = batch.selectedNpmCount; + plannedPublicationCriticalPathSeconds = batch.criticalPathSeconds; + } else if ( + missingCount + missingNpmCount > 0 && + remainingSeconds >= MINIMUM_MUTATION_WINDOW_SECONDS + ) { + // Compatibility for name-only callers: admit the Cargo count that fits + // the official bucket and all npm identities only when their two-lane + // estimate fits. Exact release execution always supplies bootstrapPlan. + for (let count = 1; count <= pendingCargoCount; count += 1) { + const schedule = cratesIoTokenBucketSchedule({ + publicationCount: count, + burst: CRATES_IO_DEFAULT_NEW_CRATE_BURST, + refillSeconds: CRATES_IO_NEW_CRATE_REFILL_SECONDS, + workSeconds: parsedCargoSeconds, + initialTokens: initialCargoTokens, + }); + if (schedule.elapsedSeconds <= availablePublicationSeconds) admittedCargoCount = count; + } + admittedNpmCount = + pendingNpmCount * parsedNpmSeconds <= availablePublicationSeconds ? pendingNpmCount : 0; + plannedPublicationCriticalPathSeconds = Math.max( + cratesIoTokenBucketSchedule({ + publicationCount: admittedCargoCount, + burst: CRATES_IO_DEFAULT_NEW_CRATE_BURST, + refillSeconds: CRATES_IO_NEW_CRATE_REFILL_SECONDS, + workSeconds: parsedCargoSeconds, + initialTokens: initialCargoTokens, + }).elapsedSeconds, + admittedNpmCount * parsedNpmSeconds, + ); + } + const admittedCount = + bootstrapPlan === undefined ? admittedCargoCount + admittedNpmCount : admittedCarrierIds.length; + const remainingMutationCount = pendingCargoCount + pendingNpmCount - admittedCount; + const requiredWindowSeconds = Math.max( + MINIMUM_MUTATION_WINDOW_SECONDS, + plannedPublicationCriticalPathSeconds + plannedReconciliationSeconds + parsedReserveSeconds, + ); + const timeSatisfied = remainingSeconds >= requiredWindowSeconds; + const makesProgress = admittedCount > 0 || remainingMutationCount === 0; + const decision = timeSatisfied && makesProgress ? 'execute' : 'defer'; + return { + selectedCount, + existingCount, + publishedCargoCount, + cargoConflictCount, + pendingCargoCount, + selectedNpmCount, + publishedNpmCount, + npmConflictCount, + missingNpmCount, + pendingNpmCount, + missingCount, + missingNames: inventory.missingNames, + initialCargoTokens, + tokenBucketPublicationSeconds: defaultTokenBucket.elapsedSeconds, + tokenBucketWaitSeconds: defaultTokenBucket.waitSeconds, + defaultMinimumSeconds: defaultTokenBucket.elapsedSeconds, + remainingSeconds, + minimumMutationWindowSeconds: requiredWindowSeconds, + planningHeadroomSeconds: Math.max(0, remainingSeconds - requiredWindowSeconds), + plannedPublicationSeconds, + plannedPublicationCriticalPathSeconds, + reconciliationCount, + plannedReconciliationSeconds, + cargoSecondsPerCarrier: parsedCargoSeconds, + npmSecondsPerCarrier: parsedNpmSeconds, + reconciliationSecondsPerCarrier: parsedReconciliationSeconds, + reserveSeconds: parsedReserveSeconds, + admittedCarrierIds, + admittedCargoCount, + admittedNpmCount, + admittedCount, + remainingMutationCount, + completeAfterExecution: remainingMutationCount === 0, + notBeforeEpochSeconds: + decision === 'defer' ? nowEpochSeconds + CRATES_IO_NEW_CRATE_REFILL_SECONDS : null, + decision, + timeSatisfied, + allowed: decision === 'execute', + }; +} + +function exactVersionStateByName(inventory, ecosystem) { + const selected = new Map(); + for (const [index, identity] of inventory.selectedIdentities.entries()) { + if ( + identity === null || + typeof identity !== 'object' || + typeof identity.name !== 'string' || + identity.name.length === 0 || + typeof identity.version !== 'string' || + identity.version.length === 0 + ) { + throw error(`${ecosystem} selected identity ${index} must contain a name and version`); + } + if (selected.has(identity.name)) { + throw error(`${ecosystem} version inventory selects duplicate package name ${identity.name}`); + } + selected.set(identity.name, { version: identity.version, state: null }); + } + + function recordIdentities(identities, state) { + const observed = new Set(); + for (const [index, identity] of identities.entries()) { + if ( + identity === null || + typeof identity !== 'object' || + typeof identity.name !== 'string' || + typeof identity.version !== 'string' + ) { + throw error(`${ecosystem} ${state} identity ${index} must contain a name and version`); + } + const expected = selected.get(identity.name); + if (expected === undefined || expected.version !== identity.version) { + throw error( + `${ecosystem} ${state} identity ${identity.name}@${identity.version} is absent from the exact selection`, + ); + } + if (observed.has(identity.name) || expected.state !== null) { + throw error( + `${ecosystem} identity ${identity.name} is duplicated across version-inventory states`, + ); + } + observed.add(identity.name); + expected.state = state; + } + } + + recordIdentities(inventory.publishedIdentities, 'published'); + recordIdentities(inventory.pendingVersions, 'pending'); + const missing = new Set(); + for (const [index, name] of inventory.missingNames.entries()) { + if (typeof name !== 'string' || name.length === 0) { + throw error(`${ecosystem} missing-name identity ${index} must be a nonempty string`); + } + const expected = selected.get(name); + if (expected === undefined) { + throw error(`${ecosystem} missing name ${name} is absent from the exact selection`); + } + if (missing.has(name) || expected.state !== null) { + throw error(`${ecosystem} identity ${name} is duplicated across version-inventory states`); + } + missing.add(name); + expected.state = 'missing'; + } + const unclassified = [...selected] + .filter(([, value]) => value.state === null) + .map(([name]) => name); + if (unclassified.length > 0) { + throw error(`${ecosystem} version inventory does not classify ${unclassified.join(', ')}`); + } + return selected; +} + +function durationText(seconds) { + const minutes = Math.ceil(seconds / 60); + const hours = Math.floor(minutes / 60); + const remainder = minutes % 60; + return hours === 0 ? `${minutes}m` : `${hours}h ${remainder}m`; +} + +export function cratesIoCapacitySummary(assessment) { + return [ + '### Cargo/npm bootstrap token-bucket admission', + '', + `- Exact-lock Cargo names selected: ${assessment.selectedCount}`, + `- Names already present on crates.io: ${assessment.existingCount}`, + `- Brand-new names still missing: ${assessment.missingCount}`, + `- Cargo versions already public: ${assessment.publishedCargoCount}`, + `- Existing Cargo names left for normal trusted publication: ${assessment.cargoConflictCount}`, + `- Brand-new Cargo names still requiring their first version: ${assessment.pendingCargoCount}`, + `- Exact-lock npm versions selected: ${assessment.selectedNpmCount}`, + `- npm versions already public: ${assessment.publishedNpmCount}`, + `- Existing npm names left for normal trusted publication: ${assessment.npmConflictCount}`, + `- Brand-new npm names still requiring their first version: ${assessment.pendingNpmCount}`, + `- Conservatively available Cargo tokens at invocation start: ${assessment.initialCargoTokens}`, + `- Official token-bucket time for every pending Cargo identity: ${durationText(assessment.tokenBucketPublicationSeconds)} (${durationText(assessment.tokenBucketWaitSeconds)} waiting, with publication work overlapping refill)`, + `- Aggregate carrier publication work: ${durationText(assessment.plannedPublicationSeconds)} (${assessment.cargoSecondsPerCarrier}s/Cargo + ${assessment.npmSecondsPerCarrier}s/npm)`, + `- Cargo/npm lane + dependency-DAG critical path: ${durationText(assessment.plannedPublicationCriticalPathSeconds)}`, + `- Planned public-version reconciliation time: ${durationText(assessment.plannedReconciliationSeconds)} (${assessment.reconciliationSecondsPerCarrier}s across ${assessment.reconciliationCount} carriers)`, + `- Non-publication reserve: ${durationText(assessment.reserveSeconds)}`, + `- Admission-model mutation window: ${durationText(assessment.minimumMutationWindowSeconds)}`, + `- Remaining bounded mutation window: ${durationText(Math.max(0, assessment.remainingSeconds))}`, + `- Additional planning headroom: ${durationText(assessment.planningHeadroomSeconds)}`, + `- Dependency-closed carriers admitted for this invocation: ${assessment.admittedCount} (${assessment.admittedCargoCount} Cargo, ${assessment.admittedNpmCount} npm)`, + `- Carriers remaining after the admitted invocation: ${assessment.remainingMutationCount}`, + '- Model boundary: timing is a calibrated admission estimate, not an upper bound on external registry latency; the hard deadline and exact-lock checkpoint recovery remain authoritative.', + `- Decision: ${assessment.decision.toUpperCase()}`, + '', + ].join('\n'); +} diff --git a/tools/release/crates-io-bootstrap-capacity.test.mjs b/tools/release/crates-io-bootstrap-capacity.test.mjs deleted file mode 100644 index 764740b11..000000000 --- a/tools/release/crates-io-bootstrap-capacity.test.mjs +++ /dev/null @@ -1,558 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { - CRATES_IO_DEFAULT_NEW_CRATE_BURST, - CRATES_IO_NEW_CRATE_REFILL_SECONDS, - CRATES_IO_READ_START_INTERVAL_MILLISECONDS, - REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER, - REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER, - REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER, - REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS, - assessCratesIoBootstrapCapacity, - cratesIoCapacitySummary, - cratesIoTokenBucketSchedule, - createCratesIoReadGate, - inspectCratesIoBootstrapNames, - inspectCratesIoVersionState, -} from "./crates-io-bootstrap-capacity.mjs"; - -function cargoPlan(names) { - return names.map((name, publishOrder) => ({ - id: `cargo:${name}`, - product: "fixture", - ecosystem: "cargo", - name, - version: "0.1.0", - publishOrder, - })); -} - -describe("crates.io release capacity gates", () => { - test("shares one paced read-start and Retry-After barrier across concurrent workers", async () => { - let now = 1_000; - const sleeps = []; - const starts = []; - const gate = createCratesIoReadGate({ - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds / 1000; - }, - }); - - await Promise.all(["first", "second", "third"].map(async (label) => { - starts.push(await gate.beforeRequest(label, 2_000)); - })); - gate.defer(2); - await Promise.all(["after-limit-1", "after-limit-2"].map(async (label) => { - starts.push(await gate.beforeRequest(label, 2_000)); - })); - - expect(starts).toEqual([1_000, 1_000.25, 1_000.5, 1_002.5, 1_002.75]); - expect(sleeps).toEqual([ - CRATES_IO_READ_START_INTERVAL_MILLISECONDS, - CRATES_IO_READ_START_INTERVAL_MILLISECONDS, - 2_000, - CRATES_IO_READ_START_INTERVAL_MILLISECONDS, - ]); - }); - - test("admits a dependency-closed first bootstrap batch without pretending 193 Cargo names fit one runner", () => { - const cargo = Array.from({ length: 193 }, (_, index) => ({ name: `crate-${index}`, version: "0.1.0" })); - const npm = Array.from({ length: 59 }, (_, index) => ({ name: `@oliphaunt/pkg-${index}`, version: "0.1.0" })); - const bootstrapPlan = [ - ...cargo.map((identity, publishOrder) => ({ - id: `cargo:${identity.name}`, - product: "fixture", - ecosystem: "cargo", - ...identity, - publishOrder, - dependencies: [], - })), - ...npm.map((identity, index) => ({ - id: `npm:${identity.name}`, - product: "fixture", - ecosystem: "npm", - ...identity, - publishOrder: cargo.length + index, - dependencies: [], - })), - ]; - const assessment = assessCratesIoBootstrapCapacity({ - inventory: { - selectedIdentities: cargo, - publishedIdentities: [], - pendingVersions: [], - missingNames: cargo.map(({ name }) => name), - }, - npmInventory: { - selectedIdentities: npm, - publishedIdentities: [], - pendingVersions: [], - missingNames: npm.map(({ name }) => name), - }, - bootstrapPlan, - deadlineEpochSeconds: 20_800, - nowEpochSeconds: 1_000, - }); - - expect(assessment.pendingCargoCount).toBe(193); - expect(assessment.pendingNpmCount).toBe(59); - expect(assessment.plannedPublicationSeconds).toBe( - (193 * REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER) - + (59 * REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER), - ); - expect(assessment.tokenBucketPublicationSeconds).toBe(112_830); - expect(assessment.admittedCargoCount).toBe(36); - expect(assessment.admittedNpmCount).toBe(59); - expect(assessment.admittedCount).toBe(95); - expect(assessment.remainingMutationCount).toBe(157); - expect(assessment.plannedPublicationCriticalPathSeconds).toBe(18_630); - expect(assessment.reserveSeconds).toBe(REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS); - expect(assessment.minimumMutationWindowSeconds).toBe(19_230); - expect(assessment.planningHeadroomSeconds).toBe(570); - expect(assessment.allowed).toBe(true); - expect(assessment.completeAfterExecution).toBe(false); - expect(cratesIoCapacitySummary(assessment)).toContain("calibrated admission estimate"); - - const tooShortToMakeProgress = assessCratesIoBootstrapCapacity({ - inventory: { - selectedIdentities: cargo, - publishedIdentities: [], - pendingVersions: [], - missingNames: cargo.map(({ name }) => name), - }, - npmInventory: { - selectedIdentities: npm, - publishedIdentities: [], - pendingVersions: [], - missingNames: npm.map(({ name }) => name), - }, - bootstrapPlan, - deadlineEpochSeconds: 1_899, - nowEpochSeconds: 1_000, - }); - expect(tooShortToMakeProgress.decision).toBe("defer"); - expect(tooShortToMakeProgress.admittedCount).toBe(0); - }); - - test("resume inventory removes already-public exact versions from the time requirement", () => { - const cargo = Array.from({ length: 4 }, (_, index) => ({ name: `crate-${index}`, version: "0.1.0" })); - const npm = Array.from({ length: 3 }, (_, index) => ({ name: `@oliphaunt/pkg-${index}`, version: "0.1.0" })); - const assessment = assessCratesIoBootstrapCapacity({ - inventory: { - selectedIdentities: cargo, - publishedIdentities: cargo.slice(0, 3), - pendingVersions: [], - missingNames: [cargo[3].name], - }, - npmInventory: { - selectedIdentities: npm, - publishedIdentities: npm.slice(0, 2), - pendingVersions: [], - missingNames: [npm[2].name], - }, - cargoSecondsPerCarrier: "45", - npmSecondsPerCarrier: "60", - reserveSeconds: "600", - deadlineEpochSeconds: 1_900, - nowEpochSeconds: 1_000, - }); - - expect(assessment.pendingCargoCount).toBe(1); - expect(assessment.pendingNpmCount).toBe(1); - expect(assessment.plannedPublicationSeconds).toBe(105); - expect(assessment.minimumMutationWindowSeconds).toBe(900); - expect(assessment.allowed).toBe(true); - }); - - test("bootstrap capacity adds cross-registry dependencies to its two-lane critical path", () => { - const cargo = { name: "input", version: "0.1.0" }; - const npm = { name: "@example/output", version: "0.1.0" }; - const cargoCarrier = { - id: "cargo:input", - product: "fixture", - ecosystem: "cargo", - ...cargo, - publishOrder: 0, - dependencies: [], - }; - const npmCarrier = { - id: "npm:@example/output", - product: "fixture", - ecosystem: "npm", - ...npm, - publishOrder: 1, - dependencies: [cargoCarrier.id], - }; - const assessment = assessCratesIoBootstrapCapacity({ - inventory: { - selectedIdentities: [cargo], - publishedIdentities: [], - pendingVersions: [], - missingNames: [cargo.name], - }, - npmInventory: { - selectedIdentities: [npm], - publishedIdentities: [], - pendingVersions: [], - missingNames: [npm.name], - }, - bootstrapPlan: [cargoCarrier, npmCarrier], - deadlineEpochSeconds: 2_000, - nowEpochSeconds: 1_000, - }); - expect(assessment.plannedPublicationSeconds).toBe(60); - expect(assessment.plannedPublicationCriticalPathSeconds).toBe(60); - const independent = assessCratesIoBootstrapCapacity({ - inventory: { - selectedIdentities: [cargo], - publishedIdentities: [], - pendingVersions: [], - missingNames: [cargo.name], - }, - npmInventory: { - selectedIdentities: [npm], - publishedIdentities: [], - pendingVersions: [], - missingNames: [npm.name], - }, - bootstrapPlan: [cargoCarrier, { ...npmCarrier, dependencies: [] }], - deadlineEpochSeconds: 2_000, - nowEpochSeconds: 1_000, - }); - expect(independent.plannedPublicationCriticalPathSeconds).toBe(30); - }); - - test("skips an over-budget dependency chain while admitting later independent work", () => { - const publicCargo = { name: "already-public", version: "0.1.0" }; - const pendingCargo = { name: "needs-token", version: "0.1.0" }; - const dependentNpm = { name: "@example/dependent", version: "0.1.0" }; - const independentNpm = { name: "@example/independent", version: "0.1.0" }; - const bootstrapPlan = [ - { - id: `cargo:${publicCargo.name}`, - product: "fixture", - ecosystem: "cargo", - ...publicCargo, - publishOrder: 0, - dependencies: [], - }, - { - id: `cargo:${pendingCargo.name}`, - product: "fixture", - ecosystem: "cargo", - ...pendingCargo, - publishOrder: 1, - dependencies: [], - }, - { - id: `npm:${dependentNpm.name}`, - product: "fixture", - ecosystem: "npm", - ...dependentNpm, - publishOrder: 2, - dependencies: [`cargo:${pendingCargo.name}`], - }, - { - id: `npm:${independentNpm.name}`, - product: "fixture", - ecosystem: "npm", - ...independentNpm, - publishOrder: 3, - dependencies: [], - }, - ]; - const assessment = assessCratesIoBootstrapCapacity({ - inventory: { - selectedIdentities: [publicCargo, pendingCargo], - publishedIdentities: [publicCargo], - pendingVersions: [], - missingNames: [pendingCargo.name], - }, - npmInventory: { - selectedIdentities: [dependentNpm, independentNpm], - publishedIdentities: [], - pendingVersions: [], - missingNames: [dependentNpm.name, independentNpm.name], - }, - bootstrapPlan, - deadlineEpochSeconds: 1_900, - nowEpochSeconds: 1_000, - }); - expect(assessment.initialCargoTokens).toBe(0); - expect(assessment.admittedCarrierIds).toEqual([`npm:${independentNpm.name}`]); - expect(assessment.remainingMutationCount).toBe(2); - expect(assessment.decision).toBe("execute"); - }); - - test("accounts for concurrent integrity reconciliation on a 630/631 resume", () => { - const cargo = Array.from({ length: 417 }, (_, index) => ({ name: `crate-${index}`, version: "0.1.0" })); - const npm = Array.from({ length: 214 }, (_, index) => ({ name: `@oliphaunt/pkg-${index}`, version: "0.1.0" })); - const assessment = assessCratesIoBootstrapCapacity({ - inventory: { - selectedIdentities: cargo, - publishedIdentities: cargo.slice(0, 416), - pendingVersions: [], - missingNames: [cargo[416].name], - }, - npmInventory: { - selectedIdentities: npm, - publishedIdentities: npm, - pendingVersions: [], - missingNames: [], - }, - deadlineEpochSeconds: 6_010, - nowEpochSeconds: 1_000, - }); - - expect(assessment.reconciliationCount).toBe(630); - expect(assessment.plannedReconciliationSeconds).toBe( - 630 * REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER, - ); - expect(assessment.plannedPublicationSeconds).toBe(30); - expect(assessment.minimumMutationWindowSeconds).toBe(5_010); - expect(assessment.allowed).toBe(true); - - const oneSecondShort = assessCratesIoBootstrapCapacity({ - inventory: { - selectedIdentities: cargo, - publishedIdentities: cargo.slice(0, 416), - pendingVersions: [], - missingNames: [cargo[416].name], - }, - npmInventory: { - selectedIdentities: npm, - publishedIdentities: npm, - pendingVersions: [], - missingNames: [], - }, - deadlineEpochSeconds: 6_009, - nowEpochSeconds: 1_000, - }); - expect(oneSecondShort.decision).toBe("defer"); - expect(oneSecondShort.admittedCargoCount).toBe(0); - }); - - test("excludes existing names awaiting later versions from bootstrap work", () => { - const cargoIdentity = { name: "already-cargo", version: "2.0.0" }; - const npmIdentity = { name: "@oliphaunt/already-npm", version: "2.0.0" }; - const assessment = assessCratesIoBootstrapCapacity({ - inventory: { - selectedIdentities: [cargoIdentity], - publishedIdentities: [], - pendingVersions: [cargoIdentity], - missingNames: [], - }, - npmInventory: { - selectedIdentities: [npmIdentity], - publishedIdentities: [], - pendingVersions: [npmIdentity], - missingNames: [], - }, - deadlineEpochSeconds: 10_000, - nowEpochSeconds: 1_000, - }); - expect(assessment.plannedPublicationSeconds).toBe(0); - expect(assessment.pendingCargoCount).toBe(0); - expect(assessment.pendingNpmCount).toBe(0); - expect(assessment.decision).toBe("execute"); - }); - - test("counts only missing exact-lock Cargo names using read-only requests", async () => { - const calls = []; - const inventory = await inspectCratesIoBootstrapNames({ - plan: [ - ...cargoPlan(["already-owned", "brand-new"]), - { id: "npm:fixture", ecosystem: "npm", name: "fixture", version: "0.1.0" }, - ], - deadlineEpochSeconds: 10_000, - nowImpl: () => 1_000, - concurrency: 1, - fetchImpl: async (url, init) => { - calls.push({ url, init }); - return new Response("", { status: url.endsWith("/already-owned") ? 200 : 404 }); - }, - }); - - expect(inventory).toEqual({ - selectedNames: ["already-owned", "brand-new"], - existingNames: ["already-owned"], - missingNames: ["brand-new"], - }); - expect(calls).toHaveLength(2); - expect(calls.every(({ init }) => init.method === undefined && init.redirect === "error")).toBe(true); - }); - - test("uses the official token bucket and ignores unverifiable numeric capacity assertions", () => { - const inventory = { - selectedNames: Array.from({ length: 193 }, (_, index) => `crate-${index}`), - existingNames: [], - missingNames: Array.from({ length: 193 }, (_, index) => `crate-${index}`), - }; - const defaultAssessment = assessCratesIoBootstrapCapacity({ - inventory, - deadlineEpochSeconds: 20_800, - nowEpochSeconds: 1_000, - }); - expect(defaultAssessment.initialCargoTokens).toBe(CRATES_IO_DEFAULT_NEW_CRATE_BURST); - expect(defaultAssessment.tokenBucketPublicationSeconds).toBe(112_830); - expect(defaultAssessment.admittedCargoCount).toBe(36); - expect(defaultAssessment.allowed).toBe(true); - expect(cratesIoCapacitySummary(defaultAssessment)).toContain("31h 21m"); - - const attemptedOverride = assessCratesIoBootstrapCapacity({ - inventory, - configuredCapacity: "99999", - deadlineEpochSeconds: 20_800, - nowEpochSeconds: 1_000, - }); - expect(attemptedOverride).toEqual(defaultAssessment); - }); - - test("fails malformed timing and duplicate contracts, and types a late admission as defer", async () => { - expect(() => assessCratesIoBootstrapCapacity({ - inventory: { selectedNames: ["new"], existingNames: [], missingNames: ["new"] }, - cargoSecondsPerCarrier: "29", - deadlineEpochSeconds: 10_000, - nowEpochSeconds: 1_000, - })).toThrow(/CARGO_SECONDS_PER_CARRIER must be at least 30/u); - expect(() => assessCratesIoBootstrapCapacity({ - inventory: { selectedNames: ["new"], existingNames: [], missingNames: ["new"] }, - reserveSeconds: "599", - deadlineEpochSeconds: 10_000, - nowEpochSeconds: 1_000, - })).toThrow(/RESERVE_SECONDS must be at least 600/u); - await expect(inspectCratesIoBootstrapNames({ - plan: cargoPlan(["same", "same"]), - deadlineEpochSeconds: 10_000, - nowImpl: () => 1_000, - fetchImpl: async () => new Response("", { status: 404 }), - })).rejects.toThrow(/duplicate Cargo package names/u); - - const late = assessCratesIoBootstrapCapacity({ - inventory: { selectedNames: ["new"], existingNames: [], missingNames: ["new"] }, - deadlineEpochSeconds: 1_500, - nowEpochSeconds: 1_000, - }); - expect(late.decision).toBe("defer"); - expect(late.notBeforeEpochSeconds).toBe(1_600); - }); - - test("honors bounded transient read retry and rejects an excessive Retry-After", async () => { - let calls = 0; - let now = 1_000; - const sleeps = []; - const inventory = await inspectCratesIoBootstrapNames({ - plan: cargoPlan(["retry-me"]), - deadlineEpochSeconds: 10_000, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds / 1000; - }, - fetchImpl: async () => { - calls += 1; - return calls === 1 - ? new Response("", { status: 503, headers: { "Retry-After": "2" } }) - : new Response("", { status: 404 }); - }, - }); - expect(inventory.missingNames).toEqual(["retry-me"]); - expect(sleeps).toEqual([2_000]); - - let rateLimitedCalls = 0; - let rateLimitedNow = 1_000; - const rateLimitedSleeps = []; - const rateLimitedInventory = await inspectCratesIoBootstrapNames({ - plan: cargoPlan(["later"]), - deadlineEpochSeconds: 10_000, - nowImpl: () => rateLimitedNow, - sleepImpl: async (milliseconds) => { - rateLimitedSleeps.push(milliseconds); - rateLimitedNow += milliseconds / 1000; - }, - fetchImpl: async () => { - rateLimitedCalls += 1; - return rateLimitedCalls === 1 - ? new Response("", { status: 429, headers: { "Retry-After": "60" } }) - : new Response("", { status: 404 }); - }, - }); - expect(rateLimitedInventory.missingNames).toEqual(["later"]); - expect(rateLimitedSleeps).toEqual([60_000]); - - await expect(inspectCratesIoBootstrapNames({ - plan: cargoPlan(["too-late"]), - deadlineEpochSeconds: 10_000, - nowImpl: () => 1_000, - fetchImpl: async () => new Response("", { status: 429, headers: { "Retry-After": "181" } }), - })).rejects.toThrow(/bounded 180s retry-delay budget/u); - - let sustainedCalls = 0; - let sustainedNow = 1_000; - const sustainedSleeps = []; - await expect(inspectCratesIoBootstrapNames({ - plan: cargoPlan(["sustained"]), - deadlineEpochSeconds: 10_000, - nowImpl: () => sustainedNow, - sleepImpl: async (milliseconds) => { - sustainedSleeps.push(milliseconds); - sustainedNow += milliseconds / 1000; - }, - fetchImpl: async () => { - sustainedCalls += 1; - return new Response("", { status: 429 }); - }, - })).rejects.toThrow(/bounded 180s retry-delay budget/u); - expect(sustainedCalls).toBe(3); - expect(sustainedSleeps).toEqual([60_000, 120_000]); - - let deadlineCalls = 0; - await expect(inspectCratesIoBootstrapNames({ - plan: cargoPlan(["deadline-clamped"]), - deadlineEpochSeconds: 1_005, - nowImpl: () => 1_000, - fetchImpl: async () => { - deadlineCalls += 1; - return new Response("", { status: 404 }); - }, - })).rejects.toThrow(/cannot start before the registry mutation deadline/u); - expect(deadlineCalls).toBe(0); - - const deadlineSleeps = []; - await expect(inspectCratesIoBootstrapNames({ - plan: cargoPlan(["retry-crosses-deadline"]), - deadlineEpochSeconds: 1_007, - nowImpl: () => 1_000, - sleepImpl: async (milliseconds) => deadlineSleeps.push(milliseconds), - fetchImpl: async () => new Response("", { status: 503, headers: { "Retry-After": "2" } }), - })).rejects.toThrow(/cannot retry before the registry mutation deadline/u); - expect(deadlineSleeps).toEqual([]); - }); - - test("classifies published versions, pending updates, and names that still need bootstrap", async () => { - const inventory = await inspectCratesIoVersionState({ - plan: cargoPlan(["missing", "pending", "published"]), - deadlineEpochSeconds: 10_000, - nowImpl: () => 1_000, - concurrency: 1, - fetchImpl: async (url) => { - if (url.endsWith("/crates/published/0.1.0")) return new Response("", { status: 200 }); - if (url.endsWith("/crates/pending")) return new Response("", { status: 200 }); - return new Response("", { status: 404 }); - }, - }); - - expect(inventory).toEqual({ - selectedIdentities: [ - { name: "missing", version: "0.1.0" }, - { name: "pending", version: "0.1.0" }, - { name: "published", version: "0.1.0" }, - ], - publishedIdentities: [{ name: "published", version: "0.1.0" }], - pendingVersions: [{ name: "pending", version: "0.1.0" }], - missingNames: ["missing"], - }); - }); -}); diff --git a/tools/release/crates-io-bootstrap-capacity.test.mts b/tools/release/crates-io-bootstrap-capacity.test.mts new file mode 100644 index 000000000..b0b92406a --- /dev/null +++ b/tools/release/crates-io-bootstrap-capacity.test.mts @@ -0,0 +1,596 @@ +import { describe, expect, test } from 'bun:test'; + +import { + CRATES_IO_DEFAULT_NEW_CRATE_BURST, + CRATES_IO_NEW_CRATE_REFILL_SECONDS, + CRATES_IO_READ_START_INTERVAL_MILLISECONDS, + REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER, + REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER, + REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER, + REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS, + assessCratesIoBootstrapCapacity, + cratesIoCapacitySummary, + cratesIoTokenBucketSchedule, + createCratesIoReadGate, + inspectCratesIoBootstrapNames, + inspectCratesIoVersionState, +} from './crates-io-bootstrap-capacity.mts'; + +function cargoPlan(names) { + return names.map((name, publishOrder) => ({ + id: `cargo:${name}`, + product: 'fixture', + ecosystem: 'cargo', + name, + version: '0.1.0', + publishOrder, + })); +} + +describe('crates.io release capacity gates', () => { + test('shares one paced read-start and Retry-After barrier across concurrent workers', async () => { + let now = 1_000; + const sleeps = []; + const starts = []; + const gate = createCratesIoReadGate({ + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds / 1000; + }, + }); + + await Promise.all( + ['first', 'second', 'third'].map(async (label) => { + starts.push(await gate.beforeRequest(label, 2_000)); + }), + ); + gate.defer(2); + await Promise.all( + ['after-limit-1', 'after-limit-2'].map(async (label) => { + starts.push(await gate.beforeRequest(label, 2_000)); + }), + ); + + expect(starts).toEqual([1_000, 1_000.25, 1_000.5, 1_002.5, 1_002.75]); + expect(sleeps).toEqual([ + CRATES_IO_READ_START_INTERVAL_MILLISECONDS, + CRATES_IO_READ_START_INTERVAL_MILLISECONDS, + 2_000, + CRATES_IO_READ_START_INTERVAL_MILLISECONDS, + ]); + }); + + test('admits a dependency-closed first bootstrap batch without pretending 193 Cargo names fit one runner', () => { + const cargo = Array.from({ length: 193 }, (_, index) => ({ + name: `crate-${index}`, + version: '0.1.0', + })); + const npm = Array.from({ length: 59 }, (_, index) => ({ + name: `@oliphaunt/pkg-${index}`, + version: '0.1.0', + })); + const bootstrapPlan = [ + ...cargo.map((identity, publishOrder) => ({ + id: `cargo:${identity.name}`, + product: 'fixture', + ecosystem: 'cargo', + ...identity, + publishOrder, + dependencies: [], + })), + ...npm.map((identity, index) => ({ + id: `npm:${identity.name}`, + product: 'fixture', + ecosystem: 'npm', + ...identity, + publishOrder: cargo.length + index, + dependencies: [], + })), + ]; + const assessment = assessCratesIoBootstrapCapacity({ + inventory: { + selectedIdentities: cargo, + publishedIdentities: [], + pendingVersions: [], + missingNames: cargo.map(({ name }) => name), + }, + npmInventory: { + selectedIdentities: npm, + publishedIdentities: [], + pendingVersions: [], + missingNames: npm.map(({ name }) => name), + }, + bootstrapPlan, + deadlineEpochSeconds: 20_800, + nowEpochSeconds: 1_000, + }); + + expect(assessment.pendingCargoCount).toBe(193); + expect(assessment.pendingNpmCount).toBe(59); + expect(assessment.plannedPublicationSeconds).toBe( + 193 * REGISTRY_BOOTSTRAP_DEFAULT_CARGO_SECONDS_PER_CARRIER + + 59 * REGISTRY_BOOTSTRAP_DEFAULT_NPM_SECONDS_PER_CARRIER, + ); + expect(assessment.tokenBucketPublicationSeconds).toBe(112_830); + expect(assessment.admittedCargoCount).toBe(36); + expect(assessment.admittedNpmCount).toBe(59); + expect(assessment.admittedCount).toBe(95); + expect(assessment.remainingMutationCount).toBe(157); + expect(assessment.plannedPublicationCriticalPathSeconds).toBe(18_630); + expect(assessment.reserveSeconds).toBe(REGISTRY_BOOTSTRAP_DEFAULT_RESERVE_SECONDS); + expect(assessment.minimumMutationWindowSeconds).toBe(19_230); + expect(assessment.planningHeadroomSeconds).toBe(570); + expect(assessment.allowed).toBe(true); + expect(assessment.completeAfterExecution).toBe(false); + expect(cratesIoCapacitySummary(assessment)).toContain('calibrated admission estimate'); + + const tooShortToMakeProgress = assessCratesIoBootstrapCapacity({ + inventory: { + selectedIdentities: cargo, + publishedIdentities: [], + pendingVersions: [], + missingNames: cargo.map(({ name }) => name), + }, + npmInventory: { + selectedIdentities: npm, + publishedIdentities: [], + pendingVersions: [], + missingNames: npm.map(({ name }) => name), + }, + bootstrapPlan, + deadlineEpochSeconds: 1_899, + nowEpochSeconds: 1_000, + }); + expect(tooShortToMakeProgress.decision).toBe('defer'); + expect(tooShortToMakeProgress.admittedCount).toBe(0); + }); + + test('resume inventory removes already-public exact versions from the time requirement', () => { + const cargo = Array.from({ length: 4 }, (_, index) => ({ + name: `crate-${index}`, + version: '0.1.0', + })); + const npm = Array.from({ length: 3 }, (_, index) => ({ + name: `@oliphaunt/pkg-${index}`, + version: '0.1.0', + })); + const assessment = assessCratesIoBootstrapCapacity({ + inventory: { + selectedIdentities: cargo, + publishedIdentities: cargo.slice(0, 3), + pendingVersions: [], + missingNames: [cargo[3].name], + }, + npmInventory: { + selectedIdentities: npm, + publishedIdentities: npm.slice(0, 2), + pendingVersions: [], + missingNames: [npm[2].name], + }, + cargoSecondsPerCarrier: '45', + npmSecondsPerCarrier: '60', + reserveSeconds: '600', + deadlineEpochSeconds: 1_900, + nowEpochSeconds: 1_000, + }); + + expect(assessment.pendingCargoCount).toBe(1); + expect(assessment.pendingNpmCount).toBe(1); + expect(assessment.plannedPublicationSeconds).toBe(105); + expect(assessment.minimumMutationWindowSeconds).toBe(900); + expect(assessment.allowed).toBe(true); + }); + + test('bootstrap capacity adds cross-registry dependencies to its two-lane critical path', () => { + const cargo = { name: 'input', version: '0.1.0' }; + const npm = { name: '@example/output', version: '0.1.0' }; + const cargoCarrier = { + id: 'cargo:input', + product: 'fixture', + ecosystem: 'cargo', + ...cargo, + publishOrder: 0, + dependencies: [], + }; + const npmCarrier = { + id: 'npm:@example/output', + product: 'fixture', + ecosystem: 'npm', + ...npm, + publishOrder: 1, + dependencies: [cargoCarrier.id], + }; + const assessment = assessCratesIoBootstrapCapacity({ + inventory: { + selectedIdentities: [cargo], + publishedIdentities: [], + pendingVersions: [], + missingNames: [cargo.name], + }, + npmInventory: { + selectedIdentities: [npm], + publishedIdentities: [], + pendingVersions: [], + missingNames: [npm.name], + }, + bootstrapPlan: [cargoCarrier, npmCarrier], + deadlineEpochSeconds: 2_000, + nowEpochSeconds: 1_000, + }); + expect(assessment.plannedPublicationSeconds).toBe(60); + expect(assessment.plannedPublicationCriticalPathSeconds).toBe(60); + const independent = assessCratesIoBootstrapCapacity({ + inventory: { + selectedIdentities: [cargo], + publishedIdentities: [], + pendingVersions: [], + missingNames: [cargo.name], + }, + npmInventory: { + selectedIdentities: [npm], + publishedIdentities: [], + pendingVersions: [], + missingNames: [npm.name], + }, + bootstrapPlan: [cargoCarrier, { ...npmCarrier, dependencies: [] }], + deadlineEpochSeconds: 2_000, + nowEpochSeconds: 1_000, + }); + expect(independent.plannedPublicationCriticalPathSeconds).toBe(30); + }); + + test('skips an over-budget dependency chain while admitting later independent work', () => { + const publicCargo = { name: 'already-public', version: '0.1.0' }; + const pendingCargo = { name: 'needs-token', version: '0.1.0' }; + const dependentNpm = { name: '@example/dependent', version: '0.1.0' }; + const independentNpm = { name: '@example/independent', version: '0.1.0' }; + const bootstrapPlan = [ + { + id: `cargo:${publicCargo.name}`, + product: 'fixture', + ecosystem: 'cargo', + ...publicCargo, + publishOrder: 0, + dependencies: [], + }, + { + id: `cargo:${pendingCargo.name}`, + product: 'fixture', + ecosystem: 'cargo', + ...pendingCargo, + publishOrder: 1, + dependencies: [], + }, + { + id: `npm:${dependentNpm.name}`, + product: 'fixture', + ecosystem: 'npm', + ...dependentNpm, + publishOrder: 2, + dependencies: [`cargo:${pendingCargo.name}`], + }, + { + id: `npm:${independentNpm.name}`, + product: 'fixture', + ecosystem: 'npm', + ...independentNpm, + publishOrder: 3, + dependencies: [], + }, + ]; + const assessment = assessCratesIoBootstrapCapacity({ + inventory: { + selectedIdentities: [publicCargo, pendingCargo], + publishedIdentities: [publicCargo], + pendingVersions: [], + missingNames: [pendingCargo.name], + }, + npmInventory: { + selectedIdentities: [dependentNpm, independentNpm], + publishedIdentities: [], + pendingVersions: [], + missingNames: [dependentNpm.name, independentNpm.name], + }, + bootstrapPlan, + deadlineEpochSeconds: 1_900, + nowEpochSeconds: 1_000, + }); + expect(assessment.initialCargoTokens).toBe(0); + expect(assessment.admittedCarrierIds).toEqual([`npm:${independentNpm.name}`]); + expect(assessment.remainingMutationCount).toBe(2); + expect(assessment.decision).toBe('execute'); + }); + + test('accounts for concurrent integrity reconciliation on a 630/631 resume', () => { + const cargo = Array.from({ length: 417 }, (_, index) => ({ + name: `crate-${index}`, + version: '0.1.0', + })); + const npm = Array.from({ length: 214 }, (_, index) => ({ + name: `@oliphaunt/pkg-${index}`, + version: '0.1.0', + })); + const assessment = assessCratesIoBootstrapCapacity({ + inventory: { + selectedIdentities: cargo, + publishedIdentities: cargo.slice(0, 416), + pendingVersions: [], + missingNames: [cargo[416].name], + }, + npmInventory: { + selectedIdentities: npm, + publishedIdentities: npm, + pendingVersions: [], + missingNames: [], + }, + deadlineEpochSeconds: 6_010, + nowEpochSeconds: 1_000, + }); + + expect(assessment.reconciliationCount).toBe(630); + expect(assessment.plannedReconciliationSeconds).toBe( + 630 * REGISTRY_BOOTSTRAP_DEFAULT_RECONCILIATION_SECONDS_PER_CARRIER, + ); + expect(assessment.plannedPublicationSeconds).toBe(30); + expect(assessment.minimumMutationWindowSeconds).toBe(5_010); + expect(assessment.allowed).toBe(true); + + const oneSecondShort = assessCratesIoBootstrapCapacity({ + inventory: { + selectedIdentities: cargo, + publishedIdentities: cargo.slice(0, 416), + pendingVersions: [], + missingNames: [cargo[416].name], + }, + npmInventory: { + selectedIdentities: npm, + publishedIdentities: npm, + pendingVersions: [], + missingNames: [], + }, + deadlineEpochSeconds: 6_009, + nowEpochSeconds: 1_000, + }); + expect(oneSecondShort.decision).toBe('defer'); + expect(oneSecondShort.admittedCargoCount).toBe(0); + }); + + test('excludes existing names awaiting later versions from bootstrap work', () => { + const cargoIdentity = { name: 'already-cargo', version: '2.0.0' }; + const npmIdentity = { name: '@oliphaunt/already-npm', version: '2.0.0' }; + const assessment = assessCratesIoBootstrapCapacity({ + inventory: { + selectedIdentities: [cargoIdentity], + publishedIdentities: [], + pendingVersions: [cargoIdentity], + missingNames: [], + }, + npmInventory: { + selectedIdentities: [npmIdentity], + publishedIdentities: [], + pendingVersions: [npmIdentity], + missingNames: [], + }, + deadlineEpochSeconds: 10_000, + nowEpochSeconds: 1_000, + }); + expect(assessment.plannedPublicationSeconds).toBe(0); + expect(assessment.pendingCargoCount).toBe(0); + expect(assessment.pendingNpmCount).toBe(0); + expect(assessment.decision).toBe('execute'); + }); + + test('counts only missing exact-lock Cargo names using read-only requests', async () => { + const calls = []; + const inventory = await inspectCratesIoBootstrapNames({ + plan: [ + ...cargoPlan(['already-owned', 'brand-new']), + { id: 'npm:fixture', ecosystem: 'npm', name: 'fixture', version: '0.1.0' }, + ], + deadlineEpochSeconds: 10_000, + nowImpl: () => 1_000, + concurrency: 1, + fetchImpl: async (url, init) => { + calls.push({ url, init }); + return new Response('', { status: url.endsWith('/already-owned') ? 200 : 404 }); + }, + }); + + expect(inventory).toEqual({ + selectedNames: ['already-owned', 'brand-new'], + existingNames: ['already-owned'], + missingNames: ['brand-new'], + }); + expect(calls).toHaveLength(2); + expect(calls.every(({ init }) => init.method === undefined && init.redirect === 'error')).toBe( + true, + ); + }); + + test('uses the official token bucket and ignores unverifiable numeric capacity assertions', () => { + const inventory = { + selectedNames: Array.from({ length: 193 }, (_, index) => `crate-${index}`), + existingNames: [], + missingNames: Array.from({ length: 193 }, (_, index) => `crate-${index}`), + }; + const defaultAssessment = assessCratesIoBootstrapCapacity({ + inventory, + deadlineEpochSeconds: 20_800, + nowEpochSeconds: 1_000, + }); + expect(defaultAssessment.initialCargoTokens).toBe(CRATES_IO_DEFAULT_NEW_CRATE_BURST); + expect(defaultAssessment.tokenBucketPublicationSeconds).toBe(112_830); + expect(defaultAssessment.admittedCargoCount).toBe(36); + expect(defaultAssessment.allowed).toBe(true); + expect(cratesIoCapacitySummary(defaultAssessment)).toContain('31h 21m'); + + const attemptedOverride = assessCratesIoBootstrapCapacity({ + inventory, + configuredCapacity: '99999', + deadlineEpochSeconds: 20_800, + nowEpochSeconds: 1_000, + }); + expect(attemptedOverride).toEqual(defaultAssessment); + }); + + test('fails malformed timing and duplicate contracts, and types a late admission as defer', async () => { + expect(() => + assessCratesIoBootstrapCapacity({ + inventory: { selectedNames: ['new'], existingNames: [], missingNames: ['new'] }, + cargoSecondsPerCarrier: '29', + deadlineEpochSeconds: 10_000, + nowEpochSeconds: 1_000, + }), + ).toThrow(/CARGO_SECONDS_PER_CARRIER must be at least 30/u); + expect(() => + assessCratesIoBootstrapCapacity({ + inventory: { selectedNames: ['new'], existingNames: [], missingNames: ['new'] }, + reserveSeconds: '599', + deadlineEpochSeconds: 10_000, + nowEpochSeconds: 1_000, + }), + ).toThrow(/RESERVE_SECONDS must be at least 600/u); + await expect( + inspectCratesIoBootstrapNames({ + plan: cargoPlan(['same', 'same']), + deadlineEpochSeconds: 10_000, + nowImpl: () => 1_000, + fetchImpl: async () => new Response('', { status: 404 }), + }), + ).rejects.toThrow(/duplicate Cargo package names/u); + + const late = assessCratesIoBootstrapCapacity({ + inventory: { selectedNames: ['new'], existingNames: [], missingNames: ['new'] }, + deadlineEpochSeconds: 1_500, + nowEpochSeconds: 1_000, + }); + expect(late.decision).toBe('defer'); + expect(late.notBeforeEpochSeconds).toBe(1_600); + }); + + test('honors bounded transient read retry and rejects an excessive Retry-After', async () => { + let calls = 0; + let now = 1_000; + const sleeps = []; + const inventory = await inspectCratesIoBootstrapNames({ + plan: cargoPlan(['retry-me']), + deadlineEpochSeconds: 10_000, + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds / 1000; + }, + fetchImpl: async () => { + calls += 1; + return calls === 1 + ? new Response('', { status: 503, headers: { 'Retry-After': '2' } }) + : new Response('', { status: 404 }); + }, + }); + expect(inventory.missingNames).toEqual(['retry-me']); + expect(sleeps).toEqual([2_000]); + + let rateLimitedCalls = 0; + let rateLimitedNow = 1_000; + const rateLimitedSleeps = []; + const rateLimitedInventory = await inspectCratesIoBootstrapNames({ + plan: cargoPlan(['later']), + deadlineEpochSeconds: 10_000, + nowImpl: () => rateLimitedNow, + sleepImpl: async (milliseconds) => { + rateLimitedSleeps.push(milliseconds); + rateLimitedNow += milliseconds / 1000; + }, + fetchImpl: async () => { + rateLimitedCalls += 1; + return rateLimitedCalls === 1 + ? new Response('', { status: 429, headers: { 'Retry-After': '60' } }) + : new Response('', { status: 404 }); + }, + }); + expect(rateLimitedInventory.missingNames).toEqual(['later']); + expect(rateLimitedSleeps).toEqual([60_000]); + + await expect( + inspectCratesIoBootstrapNames({ + plan: cargoPlan(['too-late']), + deadlineEpochSeconds: 10_000, + nowImpl: () => 1_000, + fetchImpl: async () => new Response('', { status: 429, headers: { 'Retry-After': '181' } }), + }), + ).rejects.toThrow(/bounded 180s retry-delay budget/u); + + let sustainedCalls = 0; + let sustainedNow = 1_000; + const sustainedSleeps = []; + await expect( + inspectCratesIoBootstrapNames({ + plan: cargoPlan(['sustained']), + deadlineEpochSeconds: 10_000, + nowImpl: () => sustainedNow, + sleepImpl: async (milliseconds) => { + sustainedSleeps.push(milliseconds); + sustainedNow += milliseconds / 1000; + }, + fetchImpl: async () => { + sustainedCalls += 1; + return new Response('', { status: 429 }); + }, + }), + ).rejects.toThrow(/bounded 180s retry-delay budget/u); + expect(sustainedCalls).toBe(3); + expect(sustainedSleeps).toEqual([60_000, 120_000]); + + let deadlineCalls = 0; + await expect( + inspectCratesIoBootstrapNames({ + plan: cargoPlan(['deadline-clamped']), + deadlineEpochSeconds: 1_005, + nowImpl: () => 1_000, + fetchImpl: async () => { + deadlineCalls += 1; + return new Response('', { status: 404 }); + }, + }), + ).rejects.toThrow(/cannot start before the registry mutation deadline/u); + expect(deadlineCalls).toBe(0); + + const deadlineSleeps = []; + await expect( + inspectCratesIoBootstrapNames({ + plan: cargoPlan(['retry-crosses-deadline']), + deadlineEpochSeconds: 1_007, + nowImpl: () => 1_000, + sleepImpl: async (milliseconds) => deadlineSleeps.push(milliseconds), + fetchImpl: async () => new Response('', { status: 503, headers: { 'Retry-After': '2' } }), + }), + ).rejects.toThrow(/cannot retry before the registry mutation deadline/u); + expect(deadlineSleeps).toEqual([]); + }); + + test('classifies published versions, pending updates, and names that still need bootstrap', async () => { + const inventory = await inspectCratesIoVersionState({ + plan: cargoPlan(['missing', 'pending', 'published']), + deadlineEpochSeconds: 10_000, + nowImpl: () => 1_000, + concurrency: 1, + fetchImpl: async (url) => { + if (url.endsWith('/crates/published/0.1.0')) return new Response('', { status: 200 }); + if (url.endsWith('/crates/pending')) return new Response('', { status: 200 }); + return new Response('', { status: 404 }); + }, + }); + + expect(inventory).toEqual({ + selectedIdentities: [ + { name: 'missing', version: '0.1.0' }, + { name: 'pending', version: '0.1.0' }, + { name: 'published', version: '0.1.0' }, + ], + publishedIdentities: [{ name: 'published', version: '0.1.0' }], + pendingVersions: [{ name: 'pending', version: '0.1.0' }], + missingNames: ['missing'], + }); + }); +}); diff --git a/tools/release/crates-io-trusted-publishing.mjs b/tools/release/crates-io-trusted-publishing.mjs deleted file mode 100644 index 8d86d4ba7..000000000 --- a/tools/release/crates-io-trusted-publishing.mjs +++ /dev/null @@ -1,286 +0,0 @@ -import { RegistryPublicationDeferredError } from "./registry-publication-deferral.mjs"; - -const CRATES_IO_TOKEN_ENDPOINT = "https://crates.io/api/v1/trusted_publishing/tokens"; -const CRATES_IO_AUDIENCE = "crates.io"; -const REQUEST_TIMEOUT_MS = 60_000; -const MAX_RESPONSE_BYTES = 64 * 1024; -const TOKEN_LIFETIME_MS = 30 * 60 * 1000; -const REGISTRY_MUTATION_DEADLINE_VARIABLE = "REGISTRY_MUTATION_DEADLINE_EPOCH"; -export const CRATES_IO_TRUSTED_REVOKE_RESERVE_MS = REQUEST_TIMEOUT_MS; - -function error(message) { - return new Error(`crates-io-trusted-publishing: ${message}`); -} - -async function boundedText(response, context) { - const declared = Number(response.headers.get("content-length")); - if (Number.isFinite(declared) && declared > MAX_RESPONSE_BYTES) { - await response.body?.cancel?.().catch(() => {}); - throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); - } - if (response.body?.getReader === undefined) { - const text = await response.text(); - if (Buffer.byteLength(text) > MAX_RESPONSE_BYTES) throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); - return text; - } - const reader = response.body.getReader(); - const chunks = []; - let size = 0; - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > MAX_RESPONSE_BYTES) { - await reader.cancel().catch(() => {}); - throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - return Buffer.concat(chunks).toString("utf8"); -} - -async function strictJson(response, context) { - const text = await boundedText(response, context); - if (!response.ok) { - throw error(`${context} returned HTTP ${response.status}`); - } - try { - return JSON.parse(text); - } catch (cause) { - throw error(`${context} returned invalid JSON: ${cause.message}`); - } -} - -function requiredEnvironment(env, name) { - const value = env[name]?.trim(); - if (!value) throw error(`${name} is required in the protected GitHub Actions publish job`); - return value; -} - -function safeSecret(value, context) { - if (typeof value !== "string" || value.length === 0 || value.length > 16 * 1024 || /[\u0000-\u001f\u007f]/u.test(value)) { - throw error(`${context} returned an invalid secret`); - } - return value; -} - -function requestSignal(timeoutMs) { - if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > REQUEST_TIMEOUT_MS) { - throw error(`timeoutMs must be an integer from 1 through ${REQUEST_TIMEOUT_MS}`); - } - return AbortSignal.timeout(timeoutMs); -} - -function sharedDeadlineMilliseconds({ env = process.env, deadlineEpochMs } = {}) { - if (deadlineEpochMs !== undefined) { - if (!Number.isSafeInteger(deadlineEpochMs) || deadlineEpochMs < 1) { - throw error("deadlineEpochMs must be a positive Unix timestamp in milliseconds"); - } - return deadlineEpochMs; - } - const raw = env[REGISTRY_MUTATION_DEADLINE_VARIABLE]?.trim(); - if (!raw) return null; - if (!/^[1-9][0-9]*$/u.test(raw)) { - throw error(`${REGISTRY_MUTATION_DEADLINE_VARIABLE} must be a positive Unix timestamp`); - } - const deadline = Number(raw) * 1000; - if (!Number.isSafeInteger(deadline)) throw error(`${REGISTRY_MUTATION_DEADLINE_VARIABLE} exceeds the safe timestamp range`); - return deadline; -} - -function deadlineClampedTimeout({ - deadlineEpochMs, - nowImpl, - timeoutMs, - reservedAfterMs, - context, - deferrable = false, -}) { - if (deadlineEpochMs === null) return timeoutMs; - const now = nowImpl(); - const available = deadlineEpochMs - now - reservedAfterMs; - if (available < 1) { - const detail = `${context} refused because mandatory later token exchange/revocation time is no longer available before the registry mutation deadline`; - if (deferrable) { - throw new RegistryPublicationDeferredError({ - reason: "deadline", - notBeforeEpochSeconds: Math.floor(now / 1000) + 1, - context: detail, - }); - } - throw error(detail); - } - return Math.min(timeoutMs, available); -} - -function maskSecret(secret, maskImpl) { - // GitHub's workflow command registers the value before it can reach any - // downstream publisher. Secrets containing controls are rejected above, so - // one command cannot be smuggled into another. - maskImpl(`::add-mask::${secret.replaceAll("%", "%25")}\n`); -} - -export async function acquireCratesIoTrustedPublishingToken({ - env = process.env, - fetchImpl = fetch, - maskImpl = (command) => process.stdout.write(command), - nowImpl = Date.now, - timeoutMs = REQUEST_TIMEOUT_MS, - deadlineEpochMs = undefined, -} = {}) { - if (env.GITHUB_ACTIONS !== "true") { - throw error("temporary trusted-publishing tokens may be acquired only inside GitHub Actions"); - } - const requestUrl = requiredEnvironment(env, "ACTIONS_ID_TOKEN_REQUEST_URL"); - const requestToken = requiredEnvironment(env, "ACTIONS_ID_TOKEN_REQUEST_TOKEN"); - let oidcUrl; - try { - oidcUrl = new URL(requestUrl); - } catch { - throw error("ACTIONS_ID_TOKEN_REQUEST_URL is not a valid URL"); - } - if (oidcUrl.protocol !== "https:") { - throw error("ACTIONS_ID_TOKEN_REQUEST_URL must use HTTPS"); - } - oidcUrl.searchParams.set("audience", CRATES_IO_AUDIENCE); - requestSignal(timeoutMs); - const sharedDeadline = sharedDeadlineMilliseconds({ env, deadlineEpochMs }); - const acquisitionReserve = (2 * timeoutMs) + CRATES_IO_TRUSTED_REVOKE_RESERVE_MS; - const admissionNow = nowImpl(); - if (sharedDeadline !== null && sharedDeadline - admissionNow < acquisitionReserve) { - throw new RegistryPublicationDeferredError({ - reason: "deadline", - notBeforeEpochSeconds: Math.floor(admissionNow / 1000) + 1, - context: `temporary token acquisition requires ${acquisitionReserve}ms for two bounded exchanges plus mandatory revocation before the registry mutation deadline`, - }); - } - - const oidcResponse = await fetchImpl(oidcUrl, { - method: "GET", - headers: { Authorization: `Bearer ${requestToken}` }, - redirect: "error", - signal: requestSignal(deadlineClampedTimeout({ - deadlineEpochMs: sharedDeadline, - nowImpl, - timeoutMs, - reservedAfterMs: timeoutMs + CRATES_IO_TRUSTED_REVOKE_RESERVE_MS, - context: "GitHub OIDC token request", - deferrable: true, - })), - }); - const oidc = await strictJson(oidcResponse, "GitHub OIDC token request"); - const jwt = safeSecret(oidc?.value, "GitHub OIDC token request"); - - const tokenResponse = await fetchImpl(CRATES_IO_TOKEN_ENDPOINT, { - method: "POST", - headers: { - "Content-Type": "application/json", - "User-Agent": "oliphaunt-trusted-publisher/1; https://github.com/f0rr0/oliphaunt", - }, - body: JSON.stringify({ jwt }), - redirect: "error", - signal: requestSignal(deadlineClampedTimeout({ - deadlineEpochMs: sharedDeadline, - nowImpl, - timeoutMs, - reservedAfterMs: CRATES_IO_TRUSTED_REVOKE_RESERVE_MS, - context: "crates.io trusted-publishing token request", - deferrable: true, - })), - }); - const body = await strictJson(tokenResponse, "crates.io trusted-publishing token request"); - const token = safeSecret(body?.token, "crates.io trusted-publishing token request"); - maskSecret(token, maskImpl); - const acquiredAt = nowImpl(); - const publicationDeadlineEpochMs = sharedDeadline === null - ? acquiredAt + TOKEN_LIFETIME_MS - : Math.min(acquiredAt + TOKEN_LIFETIME_MS, sharedDeadline - CRATES_IO_TRUSTED_REVOKE_RESERVE_MS); - if (publicationDeadlineEpochMs <= acquiredAt) { - const reserveError = error("temporary token was acquired without the mandatory revocation reserve intact"); - try { - await revokeCratesIoTrustedPublishingToken(token, { - env, - fetchImpl, - nowImpl, - timeoutMs, - deadlineEpochMs: sharedDeadline ?? undefined, - }); - } catch (revokeError) { - throw new AggregateError( - [reserveError, revokeError], - "temporary trusted-publishing token was acquired too late and could not be revoked", - ); - } - throw reserveError; - } - return { token, acquiredAt, expiresAt: acquiredAt + TOKEN_LIFETIME_MS, publicationDeadlineEpochMs }; -} - -export async function revokeCratesIoTrustedPublishingToken(token, { - env = process.env, - fetchImpl = fetch, - nowImpl = Date.now, - timeoutMs = REQUEST_TIMEOUT_MS, - deadlineEpochMs = undefined, -} = {}) { - const secret = safeSecret(token, "trusted-publishing revoke"); - requestSignal(timeoutMs); - const sharedDeadline = sharedDeadlineMilliseconds({ env, deadlineEpochMs }); - const response = await fetchImpl(CRATES_IO_TOKEN_ENDPOINT, { - method: "DELETE", - headers: { - Authorization: `Bearer ${secret}`, - "User-Agent": "oliphaunt-trusted-publisher/1; https://github.com/f0rr0/oliphaunt", - }, - redirect: "error", - signal: requestSignal(deadlineClampedTimeout({ - deadlineEpochMs: sharedDeadline, - nowImpl, - timeoutMs, - reservedAfterMs: 0, - context: "crates.io trusted-publishing token revoke", - })), - }); - // Consume a bounded body even on the expected empty success response so a - // malicious intermediary cannot retain an unbounded stream. - await boundedText(response, "crates.io trusted-publishing token revoke"); - if (!response.ok) { - throw error(`crates.io trusted-publishing token revoke returned HTTP ${response.status}`); - } -} - -export async function withCratesIoTrustedPublishingToken(callback, options = {}) { - if (typeof callback !== "function") throw error("callback is required"); - const session = await acquireCratesIoTrustedPublishingToken(options); - let callbackError; - try { - return await callback(session); - } catch (cause) { - callbackError = cause; - throw cause; - } finally { - try { - await revokeCratesIoTrustedPublishingToken(session.token, options); - } catch (revokeError) { - if (callbackError !== undefined) { - throw new AggregateError( - [callbackError, revokeError], - "crates.io publication failed and its temporary trusted-publishing token could not be revoked", - ); - } - throw revokeError; - } - } -} - -// Stop using a 30-minute registry token after 20 minutes. The remaining ten -// minutes bound index visibility, integrity proof, and mandatory revocation -// even when the final upload consumed its full mutation deadline. -export const CRATES_IO_TRUSTED_TOKEN_MAX_BATCH_AGE_MS = 20 * 60 * 1000; -export const CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE = 20; -// This is a calibrated admission estimate for ordinary upload, visibility, -// integrity, and token-exchange latency, not a worst-case promise that all 12 -// visibility probes complete in 30 seconds. The hard registry/job deadlines -// bound pathological latency, and an exact-lock rerun recovers any matching -// immutable versions that became public before interruption. -export const CRATES_IO_TRUSTED_PUBLISH_PLANNING_SECONDS_PER_CARRIER = 30; diff --git a/tools/release/crates-io-trusted-publishing.mts b/tools/release/crates-io-trusted-publishing.mts new file mode 100644 index 000000000..3cbbe35c3 --- /dev/null +++ b/tools/release/crates-io-trusted-publishing.mts @@ -0,0 +1,314 @@ +import { RegistryPublicationDeferredError } from './registry-publication-deferral.mts'; + +const CRATES_IO_TOKEN_ENDPOINT = 'https://crates.io/api/v1/trusted_publishing/tokens'; +const CRATES_IO_AUDIENCE = 'crates.io'; +const REQUEST_TIMEOUT_MS = 60_000; +const MAX_RESPONSE_BYTES = 64 * 1024; +const TOKEN_LIFETIME_MS = 30 * 60 * 1000; +const REGISTRY_MUTATION_DEADLINE_VARIABLE = 'REGISTRY_MUTATION_DEADLINE_EPOCH'; +export const CRATES_IO_TRUSTED_REVOKE_RESERVE_MS = REQUEST_TIMEOUT_MS; + +function error(message) { + return new Error(`crates-io-trusted-publishing: ${message}`); +} + +async function boundedText(response, context) { + const declared = Number(response.headers.get('content-length')); + if (Number.isFinite(declared) && declared > MAX_RESPONSE_BYTES) { + await response.body?.cancel?.().catch(() => {}); + throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); + } + if (response.body?.getReader === undefined) { + const text = await response.text(); + if (Buffer.byteLength(text) > MAX_RESPONSE_BYTES) + throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); + return text; + } + const reader = response.body.getReader(); + const chunks = []; + let size = 0; + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > MAX_RESPONSE_BYTES) { + await reader.cancel().catch(() => {}); + throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); + } + chunks.push(Buffer.from(value)); + } + return Buffer.concat(chunks).toString('utf8'); +} + +async function strictJson(response, context) { + const text = await boundedText(response, context); + if (!response.ok) { + throw error(`${context} returned HTTP ${response.status}`); + } + try { + return JSON.parse(text); + } catch (cause) { + throw error(`${context} returned invalid JSON: ${cause.message}`); + } +} + +function requiredEnvironment(env, name) { + const value = env[name]?.trim(); + if (!value) throw error(`${name} is required in the protected GitHub Actions publish job`); + return value; +} + +function safeSecret(value, context) { + if ( + typeof value !== 'string' || + value.length === 0 || + value.length > 16 * 1024 || + /[\u0000-\u001f\u007f]/u.test(value) + ) { + throw error(`${context} returned an invalid secret`); + } + return value; +} + +function requestSignal(timeoutMs) { + if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > REQUEST_TIMEOUT_MS) { + throw error(`timeoutMs must be an integer from 1 through ${REQUEST_TIMEOUT_MS}`); + } + return AbortSignal.timeout(timeoutMs); +} + +function sharedDeadlineMilliseconds({ env = process.env, deadlineEpochMs } = {}) { + if (deadlineEpochMs !== undefined) { + if (!Number.isSafeInteger(deadlineEpochMs) || deadlineEpochMs < 1) { + throw error('deadlineEpochMs must be a positive Unix timestamp in milliseconds'); + } + return deadlineEpochMs; + } + const raw = env[REGISTRY_MUTATION_DEADLINE_VARIABLE]?.trim(); + if (!raw) return null; + if (!/^[1-9][0-9]*$/u.test(raw)) { + throw error(`${REGISTRY_MUTATION_DEADLINE_VARIABLE} must be a positive Unix timestamp`); + } + const deadline = Number(raw) * 1000; + if (!Number.isSafeInteger(deadline)) + throw error(`${REGISTRY_MUTATION_DEADLINE_VARIABLE} exceeds the safe timestamp range`); + return deadline; +} + +function deadlineClampedTimeout({ + deadlineEpochMs, + nowImpl, + timeoutMs, + reservedAfterMs, + context, + deferrable = false, +}) { + if (deadlineEpochMs === null) return timeoutMs; + const now = nowImpl(); + const available = deadlineEpochMs - now - reservedAfterMs; + if (available < 1) { + const detail = `${context} refused because mandatory later token exchange/revocation time is no longer available before the registry mutation deadline`; + if (deferrable) { + throw new RegistryPublicationDeferredError({ + reason: 'deadline', + notBeforeEpochSeconds: Math.floor(now / 1000) + 1, + context: detail, + }); + } + throw error(detail); + } + return Math.min(timeoutMs, available); +} + +function maskSecret(secret, maskImpl) { + // GitHub's workflow command registers the value before it can reach any + // downstream publisher. Secrets containing controls are rejected above, so + // one command cannot be smuggled into another. + maskImpl(`::add-mask::${secret.replaceAll('%', '%25')}\n`); +} + +export async function acquireCratesIoTrustedPublishingToken({ + env = process.env, + fetchImpl = fetch, + maskImpl = (command) => process.stdout.write(command), + nowImpl = Date.now, + timeoutMs = REQUEST_TIMEOUT_MS, + deadlineEpochMs = undefined, +} = {}) { + if (env.GITHUB_ACTIONS !== 'true') { + throw error('temporary trusted-publishing tokens may be acquired only inside GitHub Actions'); + } + const requestUrl = requiredEnvironment(env, 'ACTIONS_ID_TOKEN_REQUEST_URL'); + const requestToken = requiredEnvironment(env, 'ACTIONS_ID_TOKEN_REQUEST_TOKEN'); + let oidcUrl; + try { + oidcUrl = new URL(requestUrl); + } catch { + throw error('ACTIONS_ID_TOKEN_REQUEST_URL is not a valid URL'); + } + if (oidcUrl.protocol !== 'https:') { + throw error('ACTIONS_ID_TOKEN_REQUEST_URL must use HTTPS'); + } + oidcUrl.searchParams.set('audience', CRATES_IO_AUDIENCE); + requestSignal(timeoutMs); + const sharedDeadline = sharedDeadlineMilliseconds({ env, deadlineEpochMs }); + const acquisitionReserve = 2 * timeoutMs + CRATES_IO_TRUSTED_REVOKE_RESERVE_MS; + const admissionNow = nowImpl(); + if (sharedDeadline !== null && sharedDeadline - admissionNow < acquisitionReserve) { + throw new RegistryPublicationDeferredError({ + reason: 'deadline', + notBeforeEpochSeconds: Math.floor(admissionNow / 1000) + 1, + context: `temporary token acquisition requires ${acquisitionReserve}ms for two bounded exchanges plus mandatory revocation before the registry mutation deadline`, + }); + } + + const oidcResponse = await fetchImpl(oidcUrl, { + method: 'GET', + headers: { Authorization: `Bearer ${requestToken}` }, + redirect: 'error', + signal: requestSignal( + deadlineClampedTimeout({ + deadlineEpochMs: sharedDeadline, + nowImpl, + timeoutMs, + reservedAfterMs: timeoutMs + CRATES_IO_TRUSTED_REVOKE_RESERVE_MS, + context: 'GitHub OIDC token request', + deferrable: true, + }), + ), + }); + const oidc = await strictJson(oidcResponse, 'GitHub OIDC token request'); + const jwt = safeSecret(oidc?.value, 'GitHub OIDC token request'); + + const tokenResponse = await fetchImpl(CRATES_IO_TOKEN_ENDPOINT, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'User-Agent': 'oliphaunt-trusted-publisher/1; https://github.com/f0rr0/oliphaunt', + }, + body: JSON.stringify({ jwt }), + redirect: 'error', + signal: requestSignal( + deadlineClampedTimeout({ + deadlineEpochMs: sharedDeadline, + nowImpl, + timeoutMs, + reservedAfterMs: CRATES_IO_TRUSTED_REVOKE_RESERVE_MS, + context: 'crates.io trusted-publishing token request', + deferrable: true, + }), + ), + }); + const body = await strictJson(tokenResponse, 'crates.io trusted-publishing token request'); + const token = safeSecret(body?.token, 'crates.io trusted-publishing token request'); + maskSecret(token, maskImpl); + const acquiredAt = nowImpl(); + const publicationDeadlineEpochMs = + sharedDeadline === null + ? acquiredAt + TOKEN_LIFETIME_MS + : Math.min( + acquiredAt + TOKEN_LIFETIME_MS, + sharedDeadline - CRATES_IO_TRUSTED_REVOKE_RESERVE_MS, + ); + if (publicationDeadlineEpochMs <= acquiredAt) { + const reserveError = error( + 'temporary token was acquired without the mandatory revocation reserve intact', + ); + try { + await revokeCratesIoTrustedPublishingToken(token, { + env, + fetchImpl, + nowImpl, + timeoutMs, + deadlineEpochMs: sharedDeadline ?? undefined, + }); + } catch (revokeError) { + throw new AggregateError( + [reserveError, revokeError], + 'temporary trusted-publishing token was acquired too late and could not be revoked', + ); + } + throw reserveError; + } + return { + token, + acquiredAt, + expiresAt: acquiredAt + TOKEN_LIFETIME_MS, + publicationDeadlineEpochMs, + }; +} + +export async function revokeCratesIoTrustedPublishingToken( + token, + { + env = process.env, + fetchImpl = fetch, + nowImpl = Date.now, + timeoutMs = REQUEST_TIMEOUT_MS, + deadlineEpochMs = undefined, + } = {}, +) { + const secret = safeSecret(token, 'trusted-publishing revoke'); + requestSignal(timeoutMs); + const sharedDeadline = sharedDeadlineMilliseconds({ env, deadlineEpochMs }); + const response = await fetchImpl(CRATES_IO_TOKEN_ENDPOINT, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${secret}`, + 'User-Agent': 'oliphaunt-trusted-publisher/1; https://github.com/f0rr0/oliphaunt', + }, + redirect: 'error', + signal: requestSignal( + deadlineClampedTimeout({ + deadlineEpochMs: sharedDeadline, + nowImpl, + timeoutMs, + reservedAfterMs: 0, + context: 'crates.io trusted-publishing token revoke', + }), + ), + }); + // Consume a bounded body even on the expected empty success response so a + // malicious intermediary cannot retain an unbounded stream. + await boundedText(response, 'crates.io trusted-publishing token revoke'); + if (!response.ok) { + throw error(`crates.io trusted-publishing token revoke returned HTTP ${response.status}`); + } +} + +export async function withCratesIoTrustedPublishingToken(callback, options = {}) { + if (typeof callback !== 'function') throw error('callback is required'); + const session = await acquireCratesIoTrustedPublishingToken(options); + let result; + const failures = []; + try { + result = await callback(session); + } catch (cause) { + failures.push(cause); + } + try { + await revokeCratesIoTrustedPublishingToken(session.token, options); + } catch (cause) { + failures.push(cause); + } + if (failures.length === 2) { + throw new AggregateError( + failures, + 'crates.io publication failed and its temporary trusted-publishing token could not be revoked', + ); + } + if (failures.length) throw failures[0]; + return result; +} + +// Stop using a 30-minute registry token after 20 minutes. The remaining ten +// minutes bound index visibility, integrity proof, and mandatory revocation +// even when the final upload consumed its full mutation deadline. +export const CRATES_IO_TRUSTED_TOKEN_MAX_BATCH_AGE_MS = 20 * 60 * 1000; +export const CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE = 20; +// This is a calibrated admission estimate for ordinary upload, visibility, +// integrity, and token-exchange latency, not a worst-case promise that all 12 +// visibility probes complete in 30 seconds. The hard registry/job deadlines +// bound pathological latency, and an exact-lock rerun recovers any matching +// immutable versions that became public before interruption. +export const CRATES_IO_TRUSTED_PUBLISH_PLANNING_SECONDS_PER_CARRIER = 30; diff --git a/tools/release/crates-io-trusted-publishing.test.mjs b/tools/release/crates-io-trusted-publishing.test.mjs deleted file mode 100644 index 968f94692..000000000 --- a/tools/release/crates-io-trusted-publishing.test.mjs +++ /dev/null @@ -1,223 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { - acquireCratesIoTrustedPublishingToken, - revokeCratesIoTrustedPublishingToken, - withCratesIoTrustedPublishingToken, -} from "./crates-io-trusted-publishing.mjs"; -import { isRegistryPublicationDeferredError } from "./registry-publication-deferral.mjs"; - -const ENV = { - GITHUB_ACTIONS: "true", - ACTIONS_ID_TOKEN_REQUEST_URL: "https://pipelines.actions.example/id-token?api-version=1", - ACTIONS_ID_TOKEN_REQUEST_TOKEN: "github-request-secret", -}; - -function response(value, init = {}) { - return new Response(value === undefined ? "" : JSON.stringify(value), { - status: init.status ?? 200, - headers: { "Content-Type": "application/json", ...(init.headers ?? {}) }, - }); -} - -function tokenFetch(methods) { - return async (_url, init) => { - methods.push(init.method); - if (init.method === "GET") return response({ value: "jwt" }); - if (init.method === "POST") return response({ token: "temporary-token" }); - return new Response(""); - }; -} - -describe("crates.io trusted-publishing token broker", () => { - test("requests a fresh crates.io-audience JWT, exchanges it, and masks the temporary token", async () => { - const calls = []; - const masks = []; - const session = await acquireCratesIoTrustedPublishingToken({ - env: ENV, - nowImpl: () => 123_000, - maskImpl: (command) => masks.push(command), - fetchImpl: async (url, init) => { - calls.push({ url: String(url), init }); - if (calls.length === 1) return response({ value: "one-use-jwt" }); - return response({ token: "temporary%cargo-token" }); - }, - }); - expect(new URL(calls[0].url).searchParams.get("audience")).toBe("crates.io"); - expect(calls[0].url).toStartWith("https://pipelines.actions.example/"); - expect(calls[0].init).toMatchObject({ method: "GET", redirect: "error" }); - expect(new Headers(calls[0].init.headers).get("authorization")).toBe("Bearer github-request-secret"); - expect(calls[1].url).toBe("https://crates.io/api/v1/trusted_publishing/tokens"); - expect(calls[1].init).toMatchObject({ method: "POST", redirect: "error", body: JSON.stringify({ jwt: "one-use-jwt" }) }); - expect(session).toEqual({ - token: "temporary%cargo-token", - acquiredAt: 123_000, - expiresAt: 1_923_000, - publicationDeadlineEpochMs: 1_923_000, - }); - expect(masks).toEqual(["::add-mask::temporary%25cargo-token\n"]); - }); - - test("revokes the same in-memory token with a bounded non-redirecting request", async () => { - let call; - await revokeCratesIoTrustedPublishingToken("temporary-token", { - fetchImpl: async (url, init) => { - call = { url: String(url), init }; - return new Response("", { status: 200 }); - }, - }); - expect(call.url).toBe("https://crates.io/api/v1/trusted_publishing/tokens"); - expect(call.init).toMatchObject({ method: "DELETE", redirect: "error" }); - expect(new Headers(call.init.headers).get("authorization")).toBe("Bearer temporary-token"); - }); - - test("revokes in finally when publication fails", async () => { - const methods = []; - await expect(withCratesIoTrustedPublishingToken(async () => { - throw new Error("publish failed"); - }, { - env: ENV, - maskImpl: () => {}, - fetchImpl: async (_url, init) => { - methods.push(init.method); - if (init.method === "GET") return response({ value: "jwt" }); - if (init.method === "POST") return response({ token: "token" }); - return new Response("", { status: 200 }); - }, - })).rejects.toThrow("publish failed"); - expect(methods).toEqual(["GET", "POST", "DELETE"]); - }); - - test("refuses near-deadline acquisition before requesting OIDC and preserves revocation time from publication", async () => { - const calls = []; - let deferred; - try { - await acquireCratesIoTrustedPublishingToken({ - env: ENV, - deadlineEpochMs: 1_000_000, - nowImpl: () => 820_001, - fetchImpl: async (...args) => { - calls.push(args); - throw new Error("must not request a token"); - }, - }); - } catch (cause) { - deferred = cause; - } - expect(isRegistryPublicationDeferredError(deferred)).toBe(true); - expect(deferred).toMatchObject({ reason: "deadline", notBeforeEpochSeconds: 821 }); - expect(calls).toEqual([]); - - const methods = []; - const session = await acquireCratesIoTrustedPublishingToken({ - env: ENV, - deadlineEpochMs: 1_000_000, - nowImpl: () => 800_000, - maskImpl: () => {}, - fetchImpl: tokenFetch(methods), - }); - expect(methods).toEqual(["GET", "POST"]); - expect(session.publicationDeadlineEpochMs).toBe(940_000); - }); - - test("types a deterministic inter-exchange deadline but keeps endpoint and network failures hard", async () => { - let now = 800_000; - const methods = []; - let deferred; - try { - await acquireCratesIoTrustedPublishingToken({ - env: ENV, - deadlineEpochMs: 1_000_000, - nowImpl: () => now, - fetchImpl: async (_url, init) => { - methods.push(init.method); - now = 950_000; - return response({ value: "jwt" }); - }, - }); - } catch (cause) { - deferred = cause; - } - expect(isRegistryPublicationDeferredError(deferred)).toBe(true); - expect(methods).toEqual(["GET"]); - - for (const fetchImpl of [ - async () => { throw new Error("network ambiguity"); }, - async () => response({ errors: [] }, { status: 503 }), - ]) { - let failure; - try { - await acquireCratesIoTrustedPublishingToken({ env: ENV, fetchImpl }); - } catch (cause) { - failure = cause; - } - expect(isRegistryPublicationDeferredError(failure)).toBe(false); - } - }); - - test("clamps mandatory revocation to the shared deadline and refuses it after expiry", async () => { - let requested = false; - let failure; - try { - await revokeCratesIoTrustedPublishingToken("temporary-token", { - deadlineEpochMs: 1_000_000, - nowImpl: () => 1_000_000, - fetchImpl: async () => { - requested = true; - return new Response(""); - }, - }); - } catch (cause) { - failure = cause; - } - expect(failure.message).toMatch(/mandatory later token exchange\/revocation time/u); - expect(isRegistryPublicationDeferredError(failure)).toBe(false); - expect(requested).toBe(false); - }); - - test("makes revoke failure terminal even after a publish failure", async () => { - let thrown; - try { - await withCratesIoTrustedPublishingToken(async () => { - throw new Error("publish failed"); - }, { - env: ENV, - maskImpl: () => {}, - fetchImpl: async (_url, init) => { - if (init.method === "GET") return response({ value: "jwt" }); - if (init.method === "POST") return response({ token: "token" }); - return response({ errors: [] }, { status: 503 }); - }, - }); - } catch (cause) { - thrown = cause; - } - expect(thrown).toBeInstanceOf(AggregateError); - expect(thrown.errors.map(({ message }) => message)).toEqual([ - "publish failed", - "crates-io-trusted-publishing: crates.io trusted-publishing token revoke returned HTTP 503", - ]); - }); - - test("rejects non-Actions use, insecure request URLs, timeouts, and malformed responses", async () => { - await expect(acquireCratesIoTrustedPublishingToken({ env: {}, fetchImpl: () => { throw new Error("must not call"); } })) - .rejects.toThrow("only inside GitHub Actions"); - await expect(acquireCratesIoTrustedPublishingToken({ - env: { ...ENV, ACTIONS_ID_TOKEN_REQUEST_URL: "http://actions.invalid/token" }, - fetchImpl: () => { throw new Error("must not call"); }, - })).rejects.toThrow("must use HTTPS"); - await expect(acquireCratesIoTrustedPublishingToken({ env: ENV, timeoutMs: 0 })) - .rejects.toThrow("timeoutMs"); - await expect(acquireCratesIoTrustedPublishingToken({ - env: ENV, - fetchImpl: async () => response({ nope: "jwt" }), - })).rejects.toThrow("invalid secret"); - }); - - test("bounds response bodies before parsing", async () => { - await expect(acquireCratesIoTrustedPublishingToken({ - env: ENV, - fetchImpl: async () => new Response("x", { headers: { "Content-Length": "70000" } }), - })).rejects.toThrow("response exceeds 65536 bytes"); - }); -}); diff --git a/tools/release/crates-io-trusted-publishing.test.mts b/tools/release/crates-io-trusted-publishing.test.mts new file mode 100644 index 000000000..1c675ea38 --- /dev/null +++ b/tools/release/crates-io-trusted-publishing.test.mts @@ -0,0 +1,254 @@ +import { describe, expect, test } from 'bun:test'; + +import { + acquireCratesIoTrustedPublishingToken, + revokeCratesIoTrustedPublishingToken, + withCratesIoTrustedPublishingToken, +} from './crates-io-trusted-publishing.mts'; +import { isRegistryPublicationDeferredError } from './registry-publication-deferral.mts'; + +const ENV = { + GITHUB_ACTIONS: 'true', + ACTIONS_ID_TOKEN_REQUEST_URL: 'https://pipelines.actions.example/id-token?api-version=1', + ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'github-request-secret', +}; + +function response(value, init = {}) { + return new Response(value === undefined ? '' : JSON.stringify(value), { + status: init.status ?? 200, + headers: { 'Content-Type': 'application/json', ...(init.headers ?? {}) }, + }); +} + +function tokenFetch(methods) { + return async (_url, init) => { + methods.push(init.method); + if (init.method === 'GET') return response({ value: 'jwt' }); + if (init.method === 'POST') return response({ token: 'temporary-token' }); + return new Response(''); + }; +} + +describe('crates.io trusted-publishing token broker', () => { + test('requests a fresh crates.io-audience JWT, exchanges it, and masks the temporary token', async () => { + const calls = []; + const masks = []; + const session = await acquireCratesIoTrustedPublishingToken({ + env: ENV, + nowImpl: () => 123_000, + maskImpl: (command) => masks.push(command), + fetchImpl: async (url, init) => { + calls.push({ url: String(url), init }); + if (calls.length === 1) return response({ value: 'one-use-jwt' }); + return response({ token: 'temporary%cargo-token' }); + }, + }); + expect(new URL(calls[0].url).searchParams.get('audience')).toBe('crates.io'); + expect(calls[0].url).toStartWith('https://pipelines.actions.example/'); + expect(calls[0].init).toMatchObject({ method: 'GET', redirect: 'error' }); + expect(new Headers(calls[0].init.headers).get('authorization')).toBe( + 'Bearer github-request-secret', + ); + expect(calls[1].url).toBe('https://crates.io/api/v1/trusted_publishing/tokens'); + expect(calls[1].init).toMatchObject({ + method: 'POST', + redirect: 'error', + body: JSON.stringify({ jwt: 'one-use-jwt' }), + }); + expect(session).toEqual({ + token: 'temporary%cargo-token', + acquiredAt: 123_000, + expiresAt: 1_923_000, + publicationDeadlineEpochMs: 1_923_000, + }); + expect(masks).toEqual(['::add-mask::temporary%25cargo-token\n']); + }); + + test('revokes the same in-memory token with a bounded non-redirecting request', async () => { + let call; + await revokeCratesIoTrustedPublishingToken('temporary-token', { + fetchImpl: async (url, init) => { + call = { url: String(url), init }; + return new Response('', { status: 200 }); + }, + }); + expect(call.url).toBe('https://crates.io/api/v1/trusted_publishing/tokens'); + expect(call.init).toMatchObject({ method: 'DELETE', redirect: 'error' }); + expect(new Headers(call.init.headers).get('authorization')).toBe('Bearer temporary-token'); + }); + + test('revokes in finally when publication fails', async () => { + const methods = []; + await expect( + withCratesIoTrustedPublishingToken( + async () => { + throw new Error('publish failed'); + }, + { + env: ENV, + maskImpl: () => {}, + fetchImpl: async (_url, init) => { + methods.push(init.method); + if (init.method === 'GET') return response({ value: 'jwt' }); + if (init.method === 'POST') return response({ token: 'token' }); + return new Response('', { status: 200 }); + }, + }, + ), + ).rejects.toThrow('publish failed'); + expect(methods).toEqual(['GET', 'POST', 'DELETE']); + }); + + test('refuses near-deadline acquisition before requesting OIDC and preserves revocation time from publication', async () => { + const calls = []; + let deferred; + try { + await acquireCratesIoTrustedPublishingToken({ + env: ENV, + deadlineEpochMs: 1_000_000, + nowImpl: () => 820_001, + fetchImpl: async (...args) => { + calls.push(args); + throw new Error('must not request a token'); + }, + }); + } catch (cause) { + deferred = cause; + } + expect(isRegistryPublicationDeferredError(deferred)).toBe(true); + expect(deferred).toMatchObject({ reason: 'deadline', notBeforeEpochSeconds: 821 }); + expect(calls).toEqual([]); + + const methods = []; + const session = await acquireCratesIoTrustedPublishingToken({ + env: ENV, + deadlineEpochMs: 1_000_000, + nowImpl: () => 800_000, + maskImpl: () => {}, + fetchImpl: tokenFetch(methods), + }); + expect(methods).toEqual(['GET', 'POST']); + expect(session.publicationDeadlineEpochMs).toBe(940_000); + }); + + test('types a deterministic inter-exchange deadline but keeps endpoint and network failures hard', async () => { + let now = 800_000; + const methods = []; + let deferred; + try { + await acquireCratesIoTrustedPublishingToken({ + env: ENV, + deadlineEpochMs: 1_000_000, + nowImpl: () => now, + fetchImpl: async (_url, init) => { + methods.push(init.method); + now = 950_000; + return response({ value: 'jwt' }); + }, + }); + } catch (cause) { + deferred = cause; + } + expect(isRegistryPublicationDeferredError(deferred)).toBe(true); + expect(methods).toEqual(['GET']); + + for (const fetchImpl of [ + async () => { + throw new Error('network ambiguity'); + }, + async () => response({ errors: [] }, { status: 503 }), + ]) { + let failure; + try { + await acquireCratesIoTrustedPublishingToken({ env: ENV, fetchImpl }); + } catch (cause) { + failure = cause; + } + expect(isRegistryPublicationDeferredError(failure)).toBe(false); + } + }); + + test('clamps mandatory revocation to the shared deadline and refuses it after expiry', async () => { + let requested = false; + let failure; + try { + await revokeCratesIoTrustedPublishingToken('temporary-token', { + deadlineEpochMs: 1_000_000, + nowImpl: () => 1_000_000, + fetchImpl: async () => { + requested = true; + return new Response(''); + }, + }); + } catch (cause) { + failure = cause; + } + expect(failure.message).toMatch(/mandatory later token exchange\/revocation time/u); + expect(isRegistryPublicationDeferredError(failure)).toBe(false); + expect(requested).toBe(false); + }); + + test('makes revoke failure terminal even after a publish failure', async () => { + let thrown; + try { + await withCratesIoTrustedPublishingToken( + async () => { + throw new Error('publish failed'); + }, + { + env: ENV, + maskImpl: () => {}, + fetchImpl: async (_url, init) => { + if (init.method === 'GET') return response({ value: 'jwt' }); + if (init.method === 'POST') return response({ token: 'token' }); + return response({ errors: [] }, { status: 503 }); + }, + }, + ); + } catch (cause) { + thrown = cause; + } + expect(thrown).toBeInstanceOf(AggregateError); + expect(thrown.errors.map(({ message }) => message)).toEqual([ + 'publish failed', + 'crates-io-trusted-publishing: crates.io trusted-publishing token revoke returned HTTP 503', + ]); + }); + + test('rejects non-Actions use, insecure request URLs, timeouts, and malformed responses', async () => { + await expect( + acquireCratesIoTrustedPublishingToken({ + env: {}, + fetchImpl: () => { + throw new Error('must not call'); + }, + }), + ).rejects.toThrow('only inside GitHub Actions'); + await expect( + acquireCratesIoTrustedPublishingToken({ + env: { ...ENV, ACTIONS_ID_TOKEN_REQUEST_URL: 'http://actions.invalid/token' }, + fetchImpl: () => { + throw new Error('must not call'); + }, + }), + ).rejects.toThrow('must use HTTPS'); + await expect(acquireCratesIoTrustedPublishingToken({ env: ENV, timeoutMs: 0 })).rejects.toThrow( + 'timeoutMs', + ); + await expect( + acquireCratesIoTrustedPublishingToken({ + env: ENV, + fetchImpl: async () => response({ nope: 'jwt' }), + }), + ).rejects.toThrow('invalid secret'); + }); + + test('bounds response bodies before parsing', async () => { + await expect( + acquireCratesIoTrustedPublishingToken({ + env: ENV, + fetchImpl: async () => new Response('x', { headers: { 'Content-Length': '70000' } }), + }), + ).rejects.toThrow('response exceeds 65536 bytes'); + }); +}); diff --git a/tools/release/download-bootstrap-ledger.test.mjs b/tools/release/download-bootstrap-ledger.test.mjs deleted file mode 100644 index 521e995a6..000000000 --- a/tools/release/download-bootstrap-ledger.test.mjs +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bun - -// Bun deliberately skips hidden directories during test discovery. Keep the -// integration fixture beside the GitHub script while exposing it through the -// repository's normal release-test surface. -import "../../.github/scripts/download-bootstrap-ledger.test.mjs"; diff --git a/tools/release/download-bootstrap-ledger.test.mts b/tools/release/download-bootstrap-ledger.test.mts new file mode 100644 index 000000000..d81acc1d3 --- /dev/null +++ b/tools/release/download-bootstrap-ledger.test.mts @@ -0,0 +1,206 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { zipArchive } from '../packaging/testdata/zip-fixture.mts'; +import { + selectEarlierAttemptArtifact, + validateAttemptMetadata, +} from '../../.github/scripts/download-bootstrap-ledger.mts'; + +const SHA = 'a'.repeat(40); +const cases = [ + 'earlier', + 'wrong-sha', + 'current-only', + 'transient', + 'truncated', + 'identity-mismatch', + 'collision', +]; +function checkpoint(sequence, fill) { + return `checkpoint-${String(sequence).padStart(6, '0')}-${fill.repeat(64)}.json`; +} +function artifact(id, createdAt, updatedAt = createdAt, extra = {}) { + return { + digest: `sha256:${'a'.repeat(64)}`, + id, + name: 'oliphaunt-bootstrap-ledger', + expired: false, + size_in_bytes: 1, + created_at: createdAt, + updated_at: updatedAt, + workflow_run: { id: 900 }, + ...extra, + }; +} +if (process.argv[2] === 'prepare') { + const root = process.argv[3]; + for (const name of cases) { + const directory = path.join(root, name); + mkdirSync(directory, { recursive: true }); + const zips = {}; + function zip(id, sequence, fill) { + const file = path.join(directory, `${id}.zip`); + writeFileSync( + file, + zipArchive([{ name: checkpoint(sequence, fill), data: `remote-${id}\n` }]), + ); + zips[id] = file; + } + let artifacts = [artifact(101, '2026-07-15T09:00:00Z')]; + zip(101, 7, 'a'); + if (name === 'earlier') { + artifacts.push(artifact(202, '2026-07-15T10:00:01Z')); + zip(202, 9, 'c'); + } else if (name === 'wrong-sha') { + artifacts = [ + artifact(101, '2026-07-15T09:00:00Z', undefined, { + workflow_run: { id: 900, head_sha: 'b'.repeat(40) }, + }), + ]; + } else if (name === 'current-only') { + artifacts = [artifact(202, '2026-07-15T10:00:01Z')]; + zip(202, 9, 'c'); + } + if (['truncated', 'identity-mismatch', 'collision'].includes(name)) { + mkdirSync(path.join(directory, 'destination')); + writeFileSync(path.join(directory, 'destination', checkpoint(8, 'b')), 'durable\n'); + if (name === 'collision') zip(101, 8, 'b'); + } + writeFileSync(path.join(directory, 'github-output'), ''); + const environment = { + BOOTSTRAP_LEDGER_PATH: path.join(directory, 'destination'), + FAKE_ARTIFACTS_BY_RUN: JSON.stringify({ 900: artifacts }), + FAKE_ATTEMPT_METADATA: JSON.stringify({ + id: 900, + run_attempt: 2, + run_started_at: '2026-07-15T10:00:00Z', + head_sha: SHA, + event: 'workflow_dispatch', + }), + FAKE_CURRENT_RUN: JSON.stringify({ + id: 900, + workflow_id: 42, + head_sha: SHA, + event: 'workflow_dispatch', + created_at: '2026-07-15T10:00:00Z', + status: 'in_progress', + }), + FAKE_DOWNLOAD_MODE: ['transient', 'truncated', 'identity-mismatch'].includes(name) + ? name + : 'success', + FAKE_DOWNLOAD_STATE: path.join(directory, 'download-state'), + FAKE_GH_LOG: path.join(directory, 'gh.log'), + FAKE_ZIPS_BY_ARTIFACT: JSON.stringify(zips), + GH_REPO: 'f0rr0/oliphaunt', + GH_TOKEN: 'test-token', + GITHUB_OUTPUT: path.join(directory, 'github-output'), + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_RUN_ATTEMPT: '2', + GITHUB_RUN_ID: '900', + GITHUB_SHA: SHA, + RELEASE_HEAD_SHA: 'b'.repeat(40), + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: '0', + OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: '0', + }; + writeFileSync( + path.join(directory, 'environment'), + Object.entries(environment) + .map(([key, value]) => `${key}=${value}\0`) + .join(''), + ); + } + process.exit(0); +} + +test('attempt boundary uses creation and update time and binds the release SHA', () => { + const selected = selectEarlierAttemptArtifact( + [ + artifact(101, '2026-07-15T09:00:00Z', '2026-07-15T09:30:00Z'), + artifact(102, '2026-07-15T09:10:00Z', '2026-07-15T10:00:00Z'), + artifact(103, '2026-07-15T09:20:00Z', '2026-07-15T09:40:00Z'), + ], + { runId: '900', currentAttemptStartedAt: '2026-07-15T10:00:00Z' }, + ); + assert.equal(selected.artifact.id, 103); + assert.deepEqual(selected.excludedCurrentAttemptIds, ['102']); + assert.throws( + () => + selectEarlierAttemptArtifact([artifact(104, 'invalid')], { + runId: '900', + currentAttemptStartedAt: '2026-07-15T10:00:00Z', + }), + /created_at must be a UTC timestamp/u, + ); + assert.throws( + () => + validateAttemptMetadata( + { + id: 900, + run_attempt: 2, + run_started_at: '2026-07-15T10:00:00Z', + head_sha: 'b'.repeat(40), + event: 'workflow_dispatch', + }, + { runId: '900', attempt: 2, sha: SHA }, + ), + /wrong release SHA/u, + ); +}); +for (const name of cases) { + test(`bootstrap ledger CLI: ${name}`, () => { + const root = process.env.OLIPHAUNT_LEDGER_TEST_ROOT; + if (!root) throw new Error('Run bash tools/release/download-bootstrap-ledger.test.sh'); + const directory = path.join(root, name); + const result = readFileSync(path.join(directory, 'result'), 'utf8'); + const status = Number(readFileSync(path.join(directory, 'status'), 'utf8')); + const calls = readFileSync(path.join(directory, 'gh.log'), 'utf8') + .trim() + .split('\n') + .filter(Boolean) + .map((line) => JSON.parse(line)); + const downloads = calls + .map((url) => /\/artifacts\/([0-9]+)\/zip$/u.exec(url)?.[1]) + .filter(Boolean); + const output = readFileSync(path.join(directory, 'github-output'), 'utf8'); + const destination = path.join(directory, 'destination'); + if (name === 'earlier' || name === 'transient') { + assert.equal(status, 0, result); + assert.deepEqual(downloads, name === 'transient' ? ['101', '101'] : ['101']); + assert.deepEqual(readdirSync(destination), [checkpoint(7, 'a')]); + assert.equal( + readFileSync(path.join(destination, checkpoint(7, 'a')), 'utf8'), + 'remote-101\n', + ); + assert.equal(output, 'found=true\nrun_id=900\n'); + } else { + assert.equal(status, 1, result); + assert.equal(output, ''); + if (name === 'wrong-sha' || name === 'current-only') { + assert.deepEqual(downloads, []); + assert.match( + result, + name === 'wrong-sha' + ? /artifact disagrees with its exact-SHA binding/u + : /no artifact can be proven to predate the attempt.*refusing genesis/u, + ); + } else { + assert.deepEqual(readdirSync(destination), [checkpoint(8, 'b')]); + assert.equal(readFileSync(path.join(destination, checkpoint(8, 'b')), 'utf8'), 'durable\n'); + assert.match( + result, + name === 'collision' ? /prior checkpoint conflicts/u : /retry budget exhausted/u, + ); + if (name === 'identity-mismatch') assert.match(result, /transport identity mismatch/u); + if (name !== 'collision') + assert.equal(readFileSync(path.join(directory, 'download-state'), 'utf8'), '4'); + } + } + assert.equal( + readdirSync(directory).some((entry) => entry.startsWith('.destination.')), + false, + ); + assert.equal(existsSync(path.join(destination, '.artifact.zip')), false); + }); +} diff --git a/tools/release/download-bootstrap-ledger.test.sh b/tools/release/download-bootstrap-ledger.test.sh new file mode 100644 index 000000000..7d5b8e582 --- /dev/null +++ b/tools/release/download-bootstrap-ledger.test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/../.." +root="$PWD" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +bun tools/release/download-bootstrap-ledger.test.mts prepare "$scratch" +for directory in "$scratch"/*; do + environment=() + while IFS= read -r -d '' assignment; do environment+=("$assignment"); done < "$directory/environment" + status=0 + env -i PATH="$PATH" BUN_OPTIONS="--preload=$root/tools/release/testdata/bootstrap-ledger-github.mts" \ + "${environment[@]}" bun .github/scripts/download-bootstrap-ledger.mts > "$directory/result" 2>&1 || status=$? + printf '%s\n' "$status" > "$directory/status" +done +OLIPHAUNT_LEDGER_TEST_ROOT="$scratch" bun test ./tools/release/download-bootstrap-ledger.test.mts diff --git a/tools/release/download-build-artifacts.test.mjs b/tools/release/download-build-artifacts.test.mjs deleted file mode 100644 index db68c2cea..000000000 --- a/tools/release/download-build-artifacts.test.mjs +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { - chmodSync, - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { isolatedGitHubTestEnvironment } from "../test/isolated-github-test-environment.mjs"; - -const SCRIPT = path.resolve(".github/scripts/download-build-artifacts.mjs"); -const CHECKSUM_MERGER = path.resolve(".github/scripts/merge-checksum-manifest.mjs"); -const SHA = "a".repeat(40); -const ARTIFACT = "exact-artifact"; -const DOWNLOAD_PROCESS_TIMEOUT_MS = 10_000; - -test("the workflow Node runtime reaches argument validation without a Bun global", () => { - const result = spawnSync("node", [SCRIPT], { - encoding: "utf8", - env: isolatedGitHubTestEnvironment(), - }); - assert.equal(result.status, 2); - assert.match(result.stderr, /usage: download-build-artifacts[.]mjs/u); - assert.doesNotMatch(result.stderr, /Bun is not defined|ERR_INVALID_ARG_TYPE/u); -}); - -function fakeGh(root) { - const bin = path.join(root, "bin"); - const executable = path.join(bin, "gh"); - const mkdir = spawnSync("mkdir", ["-p", bin]); - assert.equal(mkdir.status, 0); - writeFileSync(executable, `#!/usr/bin/env node -const fs = require("node:fs"); -const crypto = require("node:crypto"); -const args = process.argv.slice(2); -fs.appendFileSync(process.env.FAKE_GH_LOG, JSON.stringify(args) + "\\n"); -if (args[0] === "api") { - const endpoint = args.find((arg) => arg.startsWith("repos/")); - if (/actions\\/workflows[?]/.test(endpoint)) { - process.stdout.write("HTTP/2.0 200 OK\\n\\n" + JSON.stringify({ workflows: [{ id: 9, name: "CI" }] })); - process.exit(0); - } - if (/actions\\/workflows\\/9\\/runs[?]/.test(endpoint)) { - const url = new URL("https://api.github.com/" + endpoint); - const page = Number(url.searchParams.get("page")); - const selected = { - id: 77, - head_sha: "${SHA}", - workflow_id: 9, - status: "completed", - conclusion: "success", - }; - const workflow_runs = process.env.FAKE_CANDIDATE_MODE === "beyond-first-page" - ? page === 1 - ? Array.from({ length: 100 }, (_, index) => ({ - ...selected, - id: 100 + index, - conclusion: "failure", - })) - : [selected] - : [selected]; - let link = ""; - if (process.env.FAKE_CANDIDATE_MODE === "beyond-first-page" && page === 1) { - const next = new URL(url); - next.searchParams.set("page", "2"); - link = \`Link: <\${next}>; rel="next", <\${next}>; rel="last"\\n\`; - } - process.stdout.write("HTTP/2.0 200 OK\\n" + link + "\\n" + JSON.stringify({ workflow_runs })); - process.exit(0); - } - if (/actions\\/runs\\/77\\/artifacts/.test(endpoint)) { - const bytes = fs.readFileSync(process.env.FAKE_ARTIFACT_ARCHIVE); - const identity = { - id: Number(process.env.FAKE_ARTIFACT_ID || "101"), - name: "${ARTIFACT}", - size_in_bytes: bytes.length, - expired: false, - digest: "sha256:" + crypto.createHash("sha256").update(bytes).digest("hex"), - }; - process.stdout.write("HTTP/2.0 200 OK\\n\\n" + JSON.stringify({ - artifacts: [identity, { ...identity, id: 102, name: "${ARTIFACT}-near-match" }], - })); - process.exit(0); - } - if (/actions\\/runs\\/77\\/jobs/.test(endpoint)) { - const jobs = [{ id: 501, name: "Qualified", status: "completed", conclusion: "success", run_attempt: 1 }]; - if (process.env.FAKE_DUPLICATE_JOB === "true") jobs.push({ ...jobs[0], id: 502 }); - process.stdout.write("HTTP/2.0 200 OK\\n\\n" + JSON.stringify({ jobs })); - process.exit(0); - } - if (/actions\\/runs\\/77$/.test(endpoint)) { - process.stdout.write(JSON.stringify({ - id: 77, - head_sha: "${SHA}", - workflow_id: 9, - run_attempt: 1, - status: process.env.FAKE_RUN_STATUS || "completed", - conclusion: process.env.FAKE_RUN_CONCLUSION || "success", - })); - process.exit(0); - } - if (/actions\\/workflows\\/9$/.test(endpoint)) { - process.stdout.write(JSON.stringify({ id: 9, name: "CI" })); - process.exit(0); - } - if (/actions\\/artifacts\\/101\\/zip$/.test(endpoint)) { - const state = process.env.FAKE_GH_STATE; - const count = fs.existsSync(state) ? Number(fs.readFileSync(state, "utf8")) : 0; - fs.writeFileSync(state, String(count + 1)); - if (process.env.FAKE_MODE === "transient" && count === 0) { - process.stderr.write("HTTP 503 unexpected EOF\\n"); - process.exit(1); - } - if (process.env.FAKE_MODE === "permanent") { - process.stderr.write("HTTP 404 not found\\n"); - process.exit(1); - } - process.stdout.write(fs.readFileSync(process.env.FAKE_ARTIFACT_ARCHIVE)); - process.exit(0); - } -} -throw new Error("unexpected gh command " + JSON.stringify(args)); -`); - chmodSync(executable, 0o755); - return bin; -} - -function fixture(t, label) { - const root = mkdtempSync(path.join(os.tmpdir(), `oliphaunt-build-download-${label}-`)); - t.after(() => rmSync(root, { force: true, recursive: true })); - const bin = fakeGh(root); - const payload = path.join(root, "payload.txt"); - const archive = path.join(root, "artifact.zip"); - writeFileSync(payload, "correct"); - const zip = spawnSync("zip", ["-q", archive, "payload.txt"], { cwd: root }); - assert.equal(zip.status, 0, zip.stderr?.toString()); - return { - archive, - bin, - destination: path.join(root, "durable"), - log: path.join(root, "gh.log"), - root, - snapshots: path.join(root, "snapshots"), - state: path.join(root, "state"), - }; -} - -function invoke(f, mode, extra = [], environment = {}) { - return spawnSync( - process.execPath, - [ - SCRIPT, - "CI", - SHA, - f.destination, - "--run-id", - "77", - "--job", - "Qualified", - "--artifact", - ARTIFACT, - ...extra, - ], - { - encoding: "utf8", - timeout: DOWNLOAD_PROCESS_TIMEOUT_MS, - env: isolatedGitHubTestEnvironment({ - PATH: `${f.bin}${path.delimiter}${process.env.PATH}`, - FAKE_ARTIFACT_ARCHIVE: f.archive, - FAKE_GH_LOG: f.log, - FAKE_GH_STATE: f.state, - FAKE_MODE: mode, - ...environment, - GH_REPO: "f0rr0/oliphaunt", - GH_TOKEN: "test-token", - OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR: f.snapshots, - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "0", - OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: "0", - }), - }, - ); -} - -function invokeFallback(f, candidateMode) { - return spawnSync( - process.execPath, - [SCRIPT, "CI", SHA, f.destination, "--job", "Qualified", "--artifact", ARTIFACT], - { - encoding: "utf8", - timeout: DOWNLOAD_PROCESS_TIMEOUT_MS, - env: isolatedGitHubTestEnvironment({ - PATH: `${f.bin}${path.delimiter}${process.env.PATH}`, - FAKE_ARTIFACT_ARCHIVE: f.archive, - FAKE_CANDIDATE_MODE: candidateMode, - FAKE_GH_LOG: f.log, - FAKE_GH_STATE: f.state, - FAKE_MODE: "success", - GH_REPO: "f0rr0/oliphaunt", - GH_TOKEN: "test-token", - OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR: f.snapshots, - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "0", - OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: "0", - }), - }, - ); -} - -function temporarySiblings(f) { - return readdirSync(f.root).filter((name) => name.startsWith(".durable.")); -} - -test("generic per-target checksum manifests merge deterministically and reject conflicts", (t) => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-checksum-merge-")); - t.after(() => rmSync(root, { force: true, recursive: true })); - const linux = path.join(root, "linux", "liboliphaunt-1.2.3-release-assets.sha256"); - const windows = path.join(root, "windows", "liboliphaunt-1.2.3-release-assets.sha256"); - const conflict = path.join(root, "conflict", "liboliphaunt-1.2.3-release-assets.sha256"); - for (const file of [linux, windows, conflict]) { - mkdirSync(path.dirname(file), { recursive: true }); - } - const linuxDigest = "1".repeat(64); - const windowsDigest = "2".repeat(64); - writeFileSync(linux, `${linuxDigest} ./liboliphaunt-1.2.3-linux-x64-gnu.tar.gz\n`); - writeFileSync(windows, [ - `${windowsDigest} liboliphaunt-1.2.3-windows-x64-msvc.zip`, - `${linuxDigest} ./liboliphaunt-1.2.3-linux-x64-gnu.tar.gz`, - "", - ].join("\n")); - - const merged = spawnSync(process.execPath, [CHECKSUM_MERGER, linux, windows], { - encoding: "utf8", - }); - assert.equal(merged.status, 0, merged.stderr); - assert.equal(readFileSync(linux, "utf8"), [ - `${linuxDigest} ./liboliphaunt-1.2.3-linux-x64-gnu.tar.gz`, - `${windowsDigest} ./liboliphaunt-1.2.3-windows-x64-msvc.zip`, - "", - ].join("\n")); - - const beforeConflict = readFileSync(linux, "utf8"); - writeFileSync(conflict, `${"3".repeat(64)} ./liboliphaunt-1.2.3-linux-x64-gnu.tar.gz\n`); - const rejected = spawnSync(process.execPath, [CHECKSUM_MERGER, linux, conflict], { - encoding: "utf8", - }); - assert.equal(rejected.status, 1); - assert.match(rejected.stderr, /conflicting checksum for liboliphaunt-1[.]2[.]3-linux-x64-gnu[.]tar[.]gz/u); - assert.equal(readFileSync(linux, "utf8"), beforeConflict); - assert.equal( - readdirSync(path.dirname(linux)).some((name) => name.startsWith(".oliphaunt-checksums-")), - false, - ); -}); - -test("transient download retries in a fresh directory and promotes only the complete envelope", (t) => { - const f = fixture(t, "transient"); - const result = invoke(f, "transient"); - assert.equal(result.status, 0, result.stderr); - assert.equal(readFileSync(path.join(f.destination, "payload.txt"), "utf8"), "correct"); - assert.equal(existsSync(path.join(f.destination, "partial.txt")), false); - assert.equal(readFileSync(f.state, "utf8"), "2"); - assert.deepEqual(temporarySiblings(f), []); -}); - -test("permanent failure preserves the prior destination and leaves no partial durable state", (t) => { - const f = fixture(t, "permanent"); - const mkdir = spawnSync("mkdir", ["-p", f.destination]); - assert.equal(mkdir.status, 0); - writeFileSync(path.join(f.destination, "existing.txt"), "preserve-me"); - const result = invoke(f, "permanent"); - assert.equal(result.status, 1); - assert.match(result.stderr, /permanent read failure[\s\S]*HTTP 404/iu); - assert.equal(readFileSync(path.join(f.destination, "existing.txt"), "utf8"), "preserve-me"); - assert.equal(existsSync(path.join(f.destination, "partial.txt")), false); - assert.equal(readFileSync(f.state, "utf8"), "1"); - assert.deepEqual(temporarySiblings(f), []); -}); - -test("different bytes at an existing path fail closed without changing the destination", (t) => { - const f = fixture(t, "collision"); - const mkdir = spawnSync("mkdir", ["-p", f.destination]); - assert.equal(mkdir.status, 0); - writeFileSync(path.join(f.destination, "payload.txt"), "old-bytes"); - const result = invoke(f, "success"); - assert.equal(result.status, 1); - assert.match(result.stderr, /overwrite payload[.]txt with different bytes|conflicts with the durable destination/u); - assert.equal(readFileSync(path.join(f.destination, "payload.txt"), "utf8"), "old-bytes"); - assert.deepEqual(temporarySiblings(f), []); -}); - -test("exact run, workflow, job, SHA, and artifact name remain mandatory", (t) => { - const f = fixture(t, "identity"); - const result = spawnSync( - process.execPath, - [SCRIPT, "CI", "b".repeat(40), f.destination, "--run-id", "77", "--job", "Qualified", "--artifact", ARTIFACT], - { - encoding: "utf8", - timeout: DOWNLOAD_PROCESS_TIMEOUT_MS, - env: isolatedGitHubTestEnvironment({ - PATH: `${f.bin}${path.delimiter}${process.env.PATH}`, - FAKE_ARTIFACT_ARCHIVE: f.archive, - FAKE_GH_LOG: f.log, - FAKE_GH_STATE: f.state, - FAKE_MODE: "success", - GH_REPO: "f0rr0/oliphaunt", - GH_TOKEN: "test-token", - OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR: f.snapshots, - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "0", - OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: "0", - }), - }, - ); - assert.equal(result.status, 1); - assert.match(result.stderr, /does not belong to commit/u); - assert.equal(existsSync(f.destination), false); - assert.equal(existsSync(f.state), false, "identity rejection must happen before download"); -}); - -test("approved artifact metadata pins exact id, compressed size, and digest", (t) => { - const f = fixture(t, "approved-identity"); - const bytes = readFileSync(f.archive); - const metadata = [{ - digest: `sha256:${createHash("sha256").update(bytes).digest("hex")}`, - id: 101, - name: ARTIFACT, - size: statSync(f.archive).size, - }]; - const accepted = invoke(f, "success", ["--artifact-metadata-json", JSON.stringify(metadata)]); - assert.equal(accepted.status, 0, accepted.stderr); - - rmSync(f.destination, { recursive: true, force: true }); - const rejected = invoke( - f, - "success", - ["--artifact-metadata-json", JSON.stringify([{ ...metadata[0], id: 999 }])], - ); - assert.equal(rejected.status, 1); - assert.match(rejected.stderr, /immutable identity drifted/u); -}); - -test("one approved artifact set may authorize a strict requested subset", (t) => { - const f = fixture(t, "approved-subset"); - const bytes = readFileSync(f.archive); - const digest = `sha256:${createHash("sha256").update(bytes).digest("hex")}`; - const metadata = [ - { digest, id: 101, name: ARTIFACT, size: statSync(f.archive).size }, - { digest, id: 102, name: `${ARTIFACT}-near-match`, size: statSync(f.archive).size }, - ]; - const accepted = invoke(f, "success", ["--artifact-metadata-json", JSON.stringify(metadata)]); - assert.equal(accepted.status, 0, accepted.stderr); - - rmSync(f.destination, { recursive: true, force: true }); - const duplicate = invoke(f, "success", [ - "--artifact-metadata-json", - JSON.stringify([metadata[0], metadata[0]]), - ]); - assert.equal(duplicate.status, 2); - assert.match(duplicate.stderr, /unique artifact names/u); -}); - -test("one immutable run snapshot is reused while each requested artifact is downloaded by exact id", (t) => { - const f = fixture(t, "snapshot-cache"); - const first = invoke(f, "success"); - assert.equal(first.status, 0, first.stderr); - const second = invoke(f, "success"); - assert.equal(second.status, 0, second.stderr); - const calls = readFileSync(f.log, "utf8").trim().split(/\r?\n/u).map(JSON.parse); - const endpoints = calls - .filter((args) => args[0] === "api") - .map((args) => args.find((arg) => arg.startsWith("repos/"))); - assert.equal(endpoints.filter((endpoint) => /actions\/runs\/77$/u.test(endpoint)).length, 1); - assert.equal(endpoints.filter((endpoint) => /actions\/workflows\/9$/u.test(endpoint)).length, 1); - assert.equal(endpoints.filter((endpoint) => /actions\/runs\/77\/jobs/u.test(endpoint)).length, 1); - assert.equal(endpoints.filter((endpoint) => /actions\/runs\/77\/artifacts/u.test(endpoint)).length, 1); - assert.equal(endpoints.filter((endpoint) => /actions\/artifacts\/101\/zip$/u.test(endpoint)).length, 2); - const downloads = calls.filter((args) => - args.some((arg) => /actions\/artifacts\/101\/zip$/u.test(arg))); - assert.ok(downloads.every((args) => args.includes("Accept: application/vnd.github+json"))); - assert.ok(downloads.every((args) => !args.includes("Accept: application/octet-stream"))); -}); - -test("fallback discovery traverses exact-SHA workflow pages instead of truncating the latest runs", (t) => { - const f = fixture(t, "fallback-pagination"); - const result = invokeFallback(f, "beyond-first-page"); - assert.equal(result.status, 0, result.stderr); - assert.equal(readFileSync(path.join(f.destination, "payload.txt"), "utf8"), "correct"); - const calls = readFileSync(f.log, "utf8").trim().split(/\r?\n/u).map(JSON.parse); - assert.equal( - calls.filter((args) => args.some((arg) => arg.includes("/actions/workflows/9/runs?"))).length, - 2, - ); - assert.equal(calls.some((args) => args[0] === "run" && args[1] === "list"), false); - assert.equal(calls.flat().includes("--limit"), false); -}); - -for (const [label, environment] of [ - ["in-progress", { FAKE_RUN_STATUS: "in_progress", FAKE_RUN_CONCLUSION: "" }], - ["failed", { FAKE_RUN_STATUS: "completed", FAKE_RUN_CONCLUSION: "failure" }], -]) { - test(`${label === "in-progress" ? "an" : "a"} ${label} enclosing workflow run cannot authorize artifact download`, (t) => { - const f = fixture(t, `run-${label}`); - const result = invoke(f, "success", [], environment); - assert.equal(result.status, 1); - assert.match(result.stderr, /malformed or not completed\/success|does not belong to commit/u); - assert.equal(existsSync(f.destination), false); - assert.equal(existsSync(f.state), false, "run rejection must happen before download"); - }); -} - -test("a duplicate named gate cannot authorize artifact download", (t) => { - const f = fixture(t, "duplicate-job"); - const result = invoke(f, "success", [], { FAKE_DUPLICATE_JOB: "true" }); - assert.equal(result.status, 1); - assert.match(result.stderr, /does not satisfy required job Qualified/u); - assert.equal(existsSync(f.destination), false); - assert.equal(existsSync(f.state), false, "gate rejection must happen before download"); -}); diff --git a/tools/release/download-build-artifacts.test.mts b/tools/release/download-build-artifacts.test.mts new file mode 100644 index 000000000..ab3efa80d --- /dev/null +++ b/tools/release/download-build-artifacts.test.mts @@ -0,0 +1,64 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { zipArchive } from '../packaging/testdata/zip-fixture.mts'; + +const [mode, root, kind] = process.argv.slice(2); +const archive = path.join(root, 'artifact.zip'); +if (mode === 'prepare') { + mkdirSync(root, { recursive: true }); + const row = + kind === 'traversal' + ? { name: '../../escaped.txt', data: 'bad' } + : kind === 'corrupt' + ? { name: 'payload.txt', data: 'bad', crc: 1 } + : { name: 'payload.txt', data: 'correct' }; + writeFileSync(archive, zipArchive([row])); + const bytes = readFileSync(archive); + const artifact = { + digest: `sha256:${createHash('sha256').update(bytes).digest('hex')}`, + id: 101, + name: 'exact-artifact', + size: bytes.length, + }; + for (const [name, value] of Object.entries({ + approved: [artifact], + wrong: [{ ...artifact, id: 999 }], + subset: [artifact, { ...artifact, id: 102, name: 'exact-artifact-near-match' }], + duplicate: [artifact, artifact], + })) + writeFileSync(path.join(root, `${name}.json`), JSON.stringify(value)); +} else if (mode === 'assert') { + assert.deepEqual( + readdirSync(root).filter( + (name) => name.startsWith('.durable.') || name.startsWith('oliphaunt-artifact-download.'), + ), + [], + ); + assert.equal(existsSync(path.join(root, 'durable/partial.txt')), false); + if (kind === 'snapshot' || kind === 'pagination') { + const endpoints = readFileSync(path.join(root, 'gh.log'), 'utf8') + .trim() + .split(/\r?\n/u) + .map(JSON.parse); + if (kind === 'pagination') + assert.equal( + endpoints.filter((endpoint) => endpoint.includes('/actions/workflows/9/runs?')).length, + 2, + ); + else { + for (const pattern of [ + /actions\/runs\/77$/u, + /actions\/workflows\/9$/u, + /actions\/runs\/77\/jobs/u, + /actions\/runs\/77\/artifacts/u, + ]) + assert.equal(endpoints.filter((endpoint) => pattern.test(endpoint)).length, 1); + assert.equal( + endpoints.filter((endpoint) => /actions\/artifacts\/101\/zip$/u.test(endpoint)).length, + 2, + ); + } + } +} else throw Error('expected prepare or assert'); diff --git a/tools/release/download-build-artifacts.test.sh b/tools/release/download-build-artifacts.test.sh new file mode 100644 index 000000000..a38f60fb1 --- /dev/null +++ b/tools/release/download-build-artifacts.test.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +source_root="$PWD" +scratch="$(mktemp -d)" +trap 'exit_status=$? + if [ "$exit_status" -ne 0 ] && [ -f "${case_root:-$scratch}/result" ]; then cat "$case_root/result" >&2; fi + rm -rf "$scratch"; exit "$exit_status"' EXIT +sha=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +prepare() { + case_root="$scratch/$1" + bun tools/release/download-build-artifacts.test.mts prepare "$case_root" "${2:-}" +} +invoke() { + local mode="$1"; shift + env -i PATH="$PATH" HOME="$HOME" \ + BUN_OPTIONS="--preload=$source_root/tools/release/testdata/download-build-artifacts-github.mts" \ + TMPDIR="$case_root" FAKE_ARTIFACT_ARCHIVE="$case_root/artifact.zip" \ + FAKE_GH_LOG="$case_root/gh.log" FAKE_GH_STATE="$case_root/state" FAKE_MODE="$mode" \ + FAKE_CANDIDATE_MODE="${candidate_mode:-}" FAKE_DUPLICATE_JOB="${duplicate_job:-}" \ + FAKE_RUN_STATUS="${run_status:-completed}" FAKE_RUN_CONCLUSION="${run_conclusion-success}" \ + GH_REPO=f0rr0/oliphaunt GH_TOKEN=test-token \ + OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR="$case_root/snapshots" \ + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS=0 OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS=0 \ + bash .github/scripts/download-build-artifacts.sh CI "${requested_sha:-$sha}" "$case_root/durable" \ + --job Qualified --artifact exact-artifact "$@" > "$case_root/result" 2>&1 +} +reject() { + local expected="$1" message="$2"; shift 2 + local status=0 + invoke "$@" || status=$? + if [[ "$status" != "$expected" ]]; then cat "$case_root/result" >&2; exit 1; fi + rg -q "$message" "$case_root/result" +} +clean() { bun tools/release/download-build-artifacts.test.mts assert "$case_root" "${1:-}"; } +prepare transient +invoke transient --run-id 77 +[[ "$(cat "$case_root/durable/payload.txt")" == correct && "$(cat "$case_root/state")" == 2 ]] +clean +prepare permanent +mkdir "$case_root/durable" +printf preserve-me > "$case_root/durable/existing.txt" +reject 1 'HTTP 404' permanent --run-id 77 +[[ "$(cat "$case_root/durable/existing.txt")" == preserve-me && "$(cat "$case_root/state")" == 1 ]] +clean +prepare collision +mkdir "$case_root/durable" +printf old-bytes > "$case_root/durable/payload.txt" +reject 1 'different bytes|conflicts with the durable destination' success --run-id 77 +[[ "$(cat "$case_root/durable/payload.txt")" == old-bytes ]] +clean +prepare identity +requested_sha=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb reject 1 'does not belong to commit' success --run-id 77 +[[ ! -e "$case_root/durable" && ! -e "$case_root/state" ]] +prepare approved +invoke success --run-id 77 --artifact-metadata-json "$(cat "$case_root/approved.json")" +rm -rf "$case_root/durable" +reject 1 'immutable identity drifted' success --run-id 77 --artifact-metadata-json "$(cat "$case_root/wrong.json")" +prepare subset +invoke success --run-id 77 --artifact-metadata-json "$(cat "$case_root/subset.json")" +rm -rf "$case_root/durable" +reject 2 'unique artifact names' success --run-id 77 --artifact-metadata-json "$(cat "$case_root/duplicate.json")" +prepare snapshot +invoke success --run-id 77 +invoke success --run-id 77 +clean snapshot +prepare pagination +candidate_mode=beyond-first-page invoke success +[[ "$(cat "$case_root/durable/payload.txt")" == correct ]] +clean pagination +for status in in_progress completed; do + prepare "run-$status" + conclusion=failure + [[ "$status" != in_progress ]] || conclusion='' + run_status="$status" run_conclusion="$conclusion" reject 1 'malformed or not completed/success|does not belong to commit' success --run-id 77 + [[ ! -e "$case_root/durable" && ! -e "$case_root/state" ]] +done +prepare duplicate-job +duplicate_job=true reject 1 'does not satisfy required job Qualified' success --run-id 77 +[[ ! -e "$case_root/durable" && ! -e "$case_root/state" ]] +for kind in traversal corrupt; do + prepare "$kind" "$kind" + mkdir "$case_root/durable" + printf preserve > "$case_root/durable/existing.txt" + if invoke success --run-id 77; then echo 'Unsafe ZIP accepted' >&2; exit 1; fi + [[ "$(cat "$case_root/durable/existing.txt")" == preserve && ! -e "$scratch/escaped.txt" && ! -e "$case_root/escaped.txt" ]] + clean +done +# Checksum merging uses the actual CLI and must not damage the destination on conflict. +mkdir "$scratch/checksums" +checksum="$scratch/checksums" +one=1111111111111111111111111111111111111111111111111111111111111111 +two=2222222222222222222222222222222222222222222222222222222222222222 +printf '%s ./linux.tar.gz\n' "$one" > "$checksum/first" +printf '%s windows.zip\n%s ./linux.tar.gz\n' "$two" "$one" > "$checksum/second" +bun .github/scripts/merge-checksum-manifest.mts "$checksum/first" "$checksum/second" +printf '%s ./linux.tar.gz\n%s ./windows.zip\n' "$one" "$two" > "$checksum/expected" +cmp "$checksum/first" "$checksum/expected" +printf '%s ./linux.tar.gz\n' "$two" > "$checksum/conflict" +if bun .github/scripts/merge-checksum-manifest.mts "$checksum/first" "$checksum/conflict" > "$checksum/result" 2>&1; then exit 1; fi +rg -q 'conflicting checksum for linux' "$checksum/result" +cmp "$checksum/first" "$checksum/expected" +compgen -G "$checksum/.oliphaunt-checksums-*" > /dev/null && exit 1 +echo 'Artifact downloads: exact identities, retries, atomic promotion, corruption and checksum conflicts passed' diff --git a/tools/release/download-wasix-runtime-build-artifacts.test.mjs b/tools/release/download-wasix-runtime-build-artifacts.test.mjs deleted file mode 100644 index 4d258abaa..000000000 --- a/tools/release/download-wasix-runtime-build-artifacts.test.mjs +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { isolatedGitHubTestEnvironment } from "../test/isolated-github-test-environment.mjs"; - -const SCRIPT = path.resolve(".github/scripts/download-wasix-runtime-build-artifacts.mjs"); -const CONTROL_SHA = "a".repeat(40); -const ARTIFACT_SHA = "b".repeat(40); - -function fixture(t) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-wasix-artifact-download-")); - const bin = path.join(root, "bin"); - const capture = path.join(root, "capture.json"); - mkdirSync(bin); - const cargo = path.join(bin, "cargo"); - writeFileSync(cargo, `#!/usr/bin/env node -const { writeFileSync } = require("node:fs"); -writeFileSync(process.env.CAPTURE_PATH, JSON.stringify({ - args: process.argv.slice(2), - releaseArtifactSha: process.env.RELEASE_ARTIFACT_SHA, - releaseHeadSha: process.env.RELEASE_HEAD_SHA, -})); -`); - chmodSync(cargo, 0o755); - t.after(() => rmSync(root, { force: true, recursive: true })); - return { bin, capture }; -} - -function runWrapper(t, overrides = {}) { - const { bin, capture } = fixture(t); - const result = spawnSync("bun", [SCRIPT], { - encoding: "utf8", - env: isolatedGitHubTestEnvironment({ - CAPTURE_PATH: capture, - GITHUB_TOKEN: "fixture-token", - PATH: `${bin}${path.delimiter}${process.env.PATH ?? ""}`, - RELEASE_ARTIFACT_SHA: ARTIFACT_SHA, - RELEASE_HEAD_SHA: CONTROL_SHA, - ...overrides, - }), - }); - assert.equal(result.status, 0, result.stderr); - return JSON.parse(readFileSync(capture, "utf8")); -} - -test("exact run download preserves controller lineage while selecting frozen payload artifacts", (t) => { - const capture = runWrapper(t, { CI_RUN_ID: "30358387218" }); - assert.deepEqual(capture, { - args: [ - "run", - "-p", - "xtask", - "--", - "assets", - "download", - "--run-id", - "30358387218", - "--required-job", - "Builds", - "--all-targets", - ], - releaseArtifactSha: ARTIFACT_SHA, - releaseHeadSha: CONTROL_SHA, - }); -}); - -test("artifact SHA wins only as the payload selector when no run ID is supplied", (t) => { - const capture = runWrapper(t); - assert.deepEqual(capture.args.slice(6, 8), ["--sha", ARTIFACT_SHA]); - assert.equal(capture.releaseHeadSha, CONTROL_SHA); -}); diff --git a/tools/release/download-wasix-runtime-build-artifacts.test.mts b/tools/release/download-wasix-runtime-build-artifacts.test.mts new file mode 100644 index 000000000..52af2640c --- /dev/null +++ b/tools/release/download-wasix-runtime-build-artifacts.test.mts @@ -0,0 +1,29 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { AOT_TARGET_TRIPLES } from '../../src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts'; + +const mode = process.argv[2]; +if (mode === 'targets') { + for (const id of Object.keys(AOT_TARGET_TRIPLES)) console.log(id); +} else { + const commands = readFileSync(process.argv[3], 'utf8'); + const count = 1 + Object.keys(AOT_TARGET_TRIPLES).length; + if (mode === 'failed') { + assert.doesNotMatch(commands, /unpack|import-download/); + } else if (mode === 'public') { + assert.equal(commands.split('\nunpack\n').length - 1, count); + assert.match(commands, /import-download/); + } else { + const sha = 'b'.repeat(40); + assert.equal(commands.split(`CI\n${sha}\n`).length - 1, count); + assert.ok(!commands.includes('a'.repeat(40))); + const run = mode === 'selected' ? '777' : '30358387218'; + assert.equal(commands.split(`--run-id\n${run}\n--job\nBuilds\n`).length - 1, count); + if (mode === 'selected') assert.ok(commands.includes(`--commit\n${sha}\n--status\nsuccess`)); + const install = commands.slice(commands.indexOf('import-download\n')); + for (const [id, triple] of Object.entries(AOT_TARGET_TRIPLES)) { + assert.ok(commands.includes(`--artifact\nliboliphaunt-wasix-runtime-aot-${id}\n`)); + assert.ok(install.includes(`--target-triple\n${triple}\n`)); + } + } +} diff --git a/tools/release/download-wasix-runtime-build-artifacts.test.sh b/tools/release/download-wasix-runtime-build-artifacts.test.sh new file mode 100644 index 000000000..374d6601a --- /dev/null +++ b/tools/release/download-wasix-runtime-build-artifacts.test.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +scratch=$(mktemp -d "${TMPDIR:-/tmp}/wasix-download-XXXXXX") +trap 'rm -rf "$scratch"' EXIT +mkdir "$scratch/bin" +TEST_REAL_BASH=$(command -v bash) +export TEST_REAL_BASH +for name in "${!GITHUB_@}" "${!GH_@}" "${!ACTIONS_@}" "${!OLIPHAUNT_GITHUB_@}" "${!OLIPHAUNT_RELEASE_@}" "${!RELEASE_@}"; do + [ -z "$name" ] || unset "$name" +done +unset CI_RUN_ID BOOTSTRAP_LEDGER_PATH OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL +export GITHUB_TOKEN=fixture-token GH_REPO=fixture/oliphaunt +export RELEASE_ARTIFACT_SHA=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +export RELEASE_HEAD_SHA=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +cat > "$scratch/bin/cargo" <<'SH' +#!/usr/bin/env bash +printf '%s\n' cargo "$@" >> "$CAPTURE_PATH" +SH +printf '#!%s\n' "$TEST_REAL_BASH" > "$scratch/bin/bash" +cat >> "$scratch/bin/bash" <<'SH' +if [ "$1" = .github/scripts/download-build-artifacts.sh ]; then + printf '%s\n' bash "$@" >> "$CAPTURE_PATH" + exit "${DOWNLOAD_FAILURE:-0}" +fi +exec "$TEST_REAL_BASH" "$@" +SH +cat > "$scratch/bin/gh" <<'SH' +#!/usr/bin/env bash +printf '%s\n' gh "$@" >> "$CAPTURE_PATH" +echo 777 +SH +cat > "$scratch/bin/curl" <<'SH' +#!/usr/bin/env bash +set -eu +url= output= +while [ "$#" -gt 0 ]; do + case "$1" in --output) output="$2"; shift;; https://*) url="$1";; esac + shift +done +case "$url" in + *sha256) + digest=$(printf payload | shasum -a 256); digest="${digest%% *}" + [ "${CORRUPT:-0}" = 0 ] || digest=0000000000000000000000000000000000000000000000000000000000000000 + for target in portable $AOT_TARGETS; do + printf '%s liboliphaunt-wasix-1.0.0-runtime-%s.tar.zst\n' "$digest" "$target" + done > "$output";; + *) printf payload > "$output";; +esac +SH +chmod +x "$scratch/bin/"* +export PATH="$scratch/bin:$PATH" CAPTURE_PATH="$scratch/commands" +AOT_TARGETS=$(bun tools/release/download-wasix-runtime-build-artifacts.test.mts targets | sed 's/^/aot-/') +export AOT_TARGETS +for mode in frozen selected failed public corrupt; do + : > "$CAPTURE_PATH" + unset CI_RUN_ID DOWNLOAD_FAILURE CORRUPT + case "$mode" in + frozen) export CI_RUN_ID=30358387218;; + failed) export CI_RUN_ID=77 DOWNLOAD_FAILURE=17;; + corrupt) export CORRUPT=1;; + esac + status=0 + if [[ "$mode" = public || "$mode" = corrupt ]]; then + bash src/runtimes/liboliphaunt-wasix/tools/download-assets.sh --release liboliphaunt-wasix-v1.0.0 --all-targets > "$scratch/log" 2>&1 || status=$? + else + bash .github/scripts/download-wasix-runtime-build-artifacts.sh > "$scratch/log" 2>&1 || status=$? + fi + case "$mode" in + failed) test "$status" = 17;; + corrupt) test "$status" != 0; mode=failed;; + *) [ "$status" = 0 ] || { cat "$scratch/log"; exit 1; };; + esac + bun tools/release/download-wasix-runtime-build-artifacts.test.mts "$mode" "$CAPTURE_PATH" +done diff --git a/tools/release/example-cargo-policy.mjs b/tools/release/example-cargo-policy.mjs deleted file mode 100644 index 75fce23ac..000000000 --- a/tools/release/example-cargo-policy.mjs +++ /dev/null @@ -1,419 +0,0 @@ -#!/usr/bin/env bun - -import { existsSync, readFileSync } from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { - loadPublicationCatalog, - resolveActualCarrier, -} from "./publication-catalog.mjs"; -import { - REQUIRED_WASIX_CONSUMER_PINS, - canonicalWasixCargoToolchainVersions, - validateResolvedWasixToolchainPolicy, - validateWasixConsumerDependencyPins, -} from "./wasix-cargo-toolchain-policy.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const TOOL = "example-cargo-policy.mjs"; -const WASIX_PRODUCT_MANIFEST_PATH = - "src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"; - -const ADVISORY_VERSION_FLOORS = new Map([ - ["crossbeam-epoch", "0.9.20"], - ["postgres-protocol", "0.6.12"], -]); - -export { - REQUIRED_WASIX_CONSUMER_PINS, - validateWasixConsumerDependencyPins, -}; - -const LINUX_X64_GNU_TARGET = - 'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'; - -function dependencyBinding(name, tableParts) { - return Object.freeze({ - name, - entryParts: Object.freeze([...tableParts, name]), - }); -} - -function exampleCargoPolicy({ dependencyBindings, runtime = undefined, ...policy }) { - const frozenBindings = Object.freeze(dependencyBindings); - return Object.freeze({ - ...policy, - dependencyBindings: frozenBindings, - directPackages: Object.freeze(frozenBindings.map(({ name }) => name)), - ...(runtime === undefined ? {} : { runtime: Object.freeze(runtime) }), - }); -} - -export const EXAMPLE_CARGO_POLICIES = Object.freeze([ - exampleCargoPolicy({ - id: "native-tauri", - crateDir: "examples/tauri/src-tauri", - ignoredLock: "examples/tauri/src-tauri/Cargo.lock", - wasixToolchain: false, - dependencyBindings: [ - dependencyBinding("oliphaunt-build", ["build-dependencies"]), - dependencyBinding("oliphaunt", ["dependencies"]), - dependencyBinding("liboliphaunt-native-linux-x64-gnu", ["target", LINUX_X64_GNU_TARGET, "dependencies"]), - dependencyBinding("oliphaunt-broker-linux-x64-gnu", ["target", LINUX_X64_GNU_TARGET, "dependencies"]), - dependencyBinding("oliphaunt-extension-contrib-pg18-linux-x64-gnu", ["target", LINUX_X64_GNU_TARGET, "dependencies"]), - ], - runtime: { - product: "liboliphaunt-native", - productParts: Object.freeze(["package", "metadata", "oliphaunt", "runtime"]), - versionParts: Object.freeze(["package", "metadata", "oliphaunt", "runtime-version"]), - }, - requiredPackages: Object.freeze([ - "oliphaunt", - "oliphaunt-build", - "liboliphaunt-native-linux-x64-gnu", - "oliphaunt-broker-linux-x64-gnu", - "oliphaunt-extension-contrib-pg18-linux-x64-gnu", - ]), - }), - exampleCargoPolicy({ - id: "wasix-tauri", - crateDir: "examples/tauri-wasix/src-tauri", - ignoredLock: "examples/tauri-wasix/src-tauri/Cargo.lock", - wasixToolchain: true, - dependencyBindings: [ - dependencyBinding("oliphaunt-wasix", ["dependencies"]), - dependencyBinding("oliphaunt-wasix", ["dev-dependencies"]), - dependencyBinding("oliphaunt-wasix-tools", ["dev-dependencies"]), - dependencyBinding("liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", ["target", LINUX_X64_GNU_TARGET, "dependencies"]), - dependencyBinding("oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", ["target", LINUX_X64_GNU_TARGET, "dev-dependencies"]), - ], - requiredPackages: Object.freeze([ - "oliphaunt-wasix", - "oliphaunt-wasix-tools", - "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", - "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", - "oliphaunt-extension-contrib-pg18-wasix", - "oliphaunt-extension-contrib-pg18-aot-linux-x64", - ]), - }), - exampleCargoPolicy({ - id: "wasix-electron-sidecar", - crateDir: "examples/electron-wasix/src-wasix", - ignoredLock: "examples/electron-wasix/src-wasix/Cargo.lock", - wasixToolchain: true, - dependencyBindings: [ - dependencyBinding("oliphaunt-wasix", ["dependencies"]), - dependencyBinding("oliphaunt-wasix", ["dev-dependencies"]), - dependencyBinding("oliphaunt-wasix-tools", ["dev-dependencies"]), - dependencyBinding("liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", ["target", LINUX_X64_GNU_TARGET, "dependencies"]), - dependencyBinding("oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", ["target", LINUX_X64_GNU_TARGET, "dev-dependencies"]), - ], - requiredPackages: Object.freeze([ - "oliphaunt-wasix", - "oliphaunt-wasix-tools", - "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", - "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", - "oliphaunt-extension-contrib-pg18-wasix", - "oliphaunt-extension-contrib-pg18-aot-linux-x64", - ]), - }), -]); - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function objectTable(value) { - return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {}; -} - -function readToml(file) { - return Bun.TOML.parse(readFileSync(file, "utf8")); -} - -function effectivePublishVersion(version, initialVersion) { - return version === "0.0.0" ? initialVersion : version; -} - -function initialReleaseVersion() { - const config = JSON.parse(readFileSync(path.join(ROOT, "release-please-config.json"), "utf8")); - const version = config["initial-version"]; - if (typeof version !== "string" || !/^\d+[.]\d+[.]\d+$/u.test(version)) { - fail("release-please-config.json must declare a stable initial-version"); - } - return version; -} - -export function exampleCargoPolicyById(id) { - const policy = EXAMPLE_CARGO_POLICIES.find((candidate) => candidate.id === id); - if (policy === undefined) { - fail(`unknown example Cargo policy ${JSON.stringify(id)}`); - } - return policy; -} - -function catalogContext() { - const initialVersion = initialReleaseVersion(); - const catalog = loadPublicationCatalog(TOOL); - return { catalog, initialVersion }; -} - -function expectedCarrierVersion(name, context) { - const carrier = resolveActualCarrier(context.catalog, "cargo", name, TOOL); - return effectivePublishVersion(carrier.version, context.initialVersion); -} - -function expectedProductVersion(product, context) { - const rows = context.catalog.products.filter(({ id }) => id === product); - if (rows.length !== 1) { - fail(`release product ${JSON.stringify(product)} must appear exactly once in the publication catalog`); - } - return effectivePublishVersion(rows[0].version, context.initialVersion); -} - -export function exampleCargoReleaseVersionBindings() { - const context = catalogContext(); - const bindings = []; - for (const policy of EXAMPLE_CARGO_POLICIES) { - const file = `${policy.crateDir}/Cargo.toml`; - for (const dependency of policy.dependencyBindings) { - const carrier = resolveActualCarrier(context.catalog, "cargo", dependency.name, TOOL); - const entryParts = [...dependency.entryParts]; - bindings.push(Object.freeze({ - kind: "dependency", - policyId: policy.id, - file, - name: dependency.name, - entryParts: Object.freeze(entryParts), - versionPaths: Object.freeze([ - Object.freeze(entryParts), - Object.freeze([...entryParts, "version"]), - ]), - sourceProduct: carrier.product, - expected: `=${effectivePublishVersion(carrier.version, context.initialVersion)}`, - wrapped: true, - })); - } - if (policy.runtime !== undefined) { - const entryParts = [...policy.runtime.versionParts]; - bindings.push(Object.freeze({ - kind: "runtime", - policyId: policy.id, - file, - name: "runtime-version", - entryParts: Object.freeze(entryParts), - versionPaths: Object.freeze([Object.freeze(entryParts)]), - sourceProduct: policy.runtime.product, - expected: expectedProductVersion(policy.runtime.product, context), - wrapped: false, - })); - } - } - return Object.freeze(bindings); -} - -export function isOliphauntCargoName(name) { - return name === "oliphaunt" || name.startsWith("oliphaunt-") || name.startsWith("liboliphaunt-"); -} - -function dependencyTables(manifest) { - const tables = [ - objectTable(manifest.dependencies), - objectTable(manifest["build-dependencies"]), - objectTable(manifest["dev-dependencies"]), - ]; - for (const target of Object.values(objectTable(manifest.target))) { - const targetTable = objectTable(target); - tables.push( - objectTable(targetTable.dependencies), - objectTable(targetTable["build-dependencies"]), - objectTable(targetTable["dev-dependencies"]), - ); - } - return tables; -} - -function dependencyVersion(spec) { - if (typeof spec === "string") return spec; - return typeof spec?.version === "string" ? spec.version : null; -} - -function valueAt(root, parts) { - let current = root; - for (const part of parts) { - if (current === null || typeof current !== "object") return undefined; - current = current[part]; - } - return current; -} - -export function validateExampleManifestPolicy(policy, manifest, bindings) { - const manifestLabel = `${policy.crateDir}/Cargo.toml`; - const failures = []; - if (Object.hasOwn(manifest, "patch")) { - failures.push(`${manifestLabel} must not commit candidate registry patches`); - } - - const dependencyBindings = bindings.filter(({ kind }) => kind === "dependency"); - const expectedByName = new Map(dependencyBindings.map((binding) => [binding.name, binding])); - const seen = []; - for (const table of dependencyTables(manifest)) { - for (const [name, spec] of Object.entries(table)) { - if (!isOliphauntCargoName(name)) continue; - seen.push(name); - if (typeof spec === "object" && spec !== null && Object.hasOwn(spec, "registry")) { - failures.push(`${manifestLabel} ${name} must use normal crates.io resolution`); - } - const expected = expectedByName.get(name)?.expected; - const actual = dependencyVersion(spec); - if (expected !== undefined && actual !== expected) { - failures.push(`${manifestLabel} ${name} uses ${JSON.stringify(actual)}; expected ${expected}`); - } - } - } - - const expectedDirect = [...policy.directPackages].sort(); - const actualDirect = [...seen].sort(); - if (JSON.stringify(actualDirect) !== JSON.stringify(expectedDirect)) { - failures.push( - `${policy.id} direct Oliphaunt dependencies are ${JSON.stringify(actualDirect)}; expected ${JSON.stringify(expectedDirect)}`, - ); - } - for (const binding of dependencyBindings) { - if (valueAt(manifest, binding.entryParts) === undefined) { - failures.push( - `${manifestLabel} ${binding.name} must remain at TOML path ${binding.entryParts.join(".")}`, - ); - } - } - - if (policy.runtime !== undefined) { - const actualProduct = valueAt(manifest, policy.runtime.productParts); - if (actualProduct !== policy.runtime.product) { - failures.push( - `${manifestLabel} runtime uses ${JSON.stringify(actualProduct)}; expected ${policy.runtime.product}`, - ); - } - const binding = bindings.find(({ kind }) => kind === "runtime"); - const actualVersion = valueAt(manifest, policy.runtime.versionParts); - if (binding === undefined) { - failures.push(`${manifestLabel} has no release binding for runtime-version`); - } else if (actualVersion !== binding.expected) { - failures.push( - `${manifestLabel} runtime-version uses ${JSON.stringify(actualVersion)}; expected ${binding.expected}`, - ); - } - } - return failures; -} - -export function validateExampleManifests() { - const context = catalogContext(); - const releaseBindings = exampleCargoReleaseVersionBindings(); - const failures = []; - const toolchainVersions = canonicalWasixCargoToolchainVersions(ROOT); - failures.push(...validateWasixConsumerDependencyPins( - readToml(path.join(ROOT, WASIX_PRODUCT_MANIFEST_PATH)), - { toolchainVersions }, - )); - for (const policy of EXAMPLE_CARGO_POLICIES) { - const manifestPath = path.join(ROOT, policy.crateDir, "Cargo.toml"); - const manifest = readToml(manifestPath); - if (existsSync(path.join(ROOT, policy.ignoredLock))) { - failures.push(`${policy.ignoredLock} must be ephemeral and untracked`); - } - const policyBindings = releaseBindings.filter(({ policyId }) => policy.id === policyId); - failures.push(...validateExampleManifestPolicy(policy, manifest, policyBindings)); - for (const required of policy.requiredPackages) { - try { - expectedCarrierVersion(required, context); - } catch (error) { - failures.push(`${policy.id} required package: ${error.message}`); - } - } - } - return failures; -} - -function packageByName(packages) { - const byName = new Map(); - for (const pkg of packages) { - const rows = byName.get(pkg.name) ?? []; - rows.push(pkg); - byName.set(pkg.name, rows); - } - return byName; -} - -function semverParts(version) { - const match = version.match(/^(\d+)[.](\d+)[.](\d+)(?:-([0-9A-Za-z.-]+))?(?:[+][0-9A-Za-z.-]+)?$/u); - if (match === null) return null; - return { - numbers: match.slice(1, 4).map((part) => Number.parseInt(part, 10)), - prerelease: match[4] ?? null, - }; -} - -function compareSemver(left, right) { - const leftParts = semverParts(left); - const rightParts = semverParts(right); - if (leftParts === null || rightParts === null) return null; - for (let index = 0; index < leftParts.numbers.length; index += 1) { - if (leftParts.numbers[index] !== rightParts.numbers[index]) { - return leftParts.numbers[index] < rightParts.numbers[index] ? -1 : 1; - } - } - if (leftParts.prerelease === rightParts.prerelease) return 0; - if (leftParts.prerelease === null) return 1; - if (rightParts.prerelease === null) return -1; - return leftParts.prerelease < rightParts.prerelease - ? -1 - : leftParts.prerelease > rightParts.prerelease - ? 1 - : 0; -} - -export function validateResolvedPackagePolicy( - lockfile, - packages, - { wasixToolchain = false, toolchainVersions } = {}, -) { - const failures = []; - const byName = packageByName(packages); - for (const [name, floor] of ADVISORY_VERSION_FLOORS) { - for (const pkg of byName.get(name) ?? []) { - const comparison = compareSemver(pkg.version, floor); - if (comparison === null) { - failures.push(`${lockfile}: ${name} has invalid semantic version ${pkg.version}`); - } else if (comparison < 0) { - failures.push(`${lockfile}: ${name} ${pkg.version} is below required floor ${floor}`); - } - } - } - if (!wasixToolchain) return failures; - failures.push(...validateResolvedWasixToolchainPolicy( - lockfile, - packages, - { toolchainVersions }, - )); - return failures; -} - -function main(argv) { - if (argv.length > 1 || (argv.length === 1 && argv[0] !== "--check")) { - fail("usage: tools/release/example-cargo-policy.mjs [--check]"); - } - const failures = validateExampleManifests(); - if (failures.length > 0) fail(failures.join("\n")); - console.log(`example Cargo manifests are registry-neutral and ${EXAMPLE_CARGO_POLICIES.length} ephemeral lock policies are valid`); -} - -if (import.meta.main) { - try { - main(Bun.argv.slice(2)); - } catch (error) { - console.error(error.message); - process.exit(1); - } -} diff --git a/tools/release/example-cargo-policy.test.mjs b/tools/release/example-cargo-policy.test.mjs deleted file mode 100644 index 93ec79a77..000000000 --- a/tools/release/example-cargo-policy.test.mjs +++ /dev/null @@ -1,239 +0,0 @@ -import { describe, expect, test } from "bun:test"; -import { - readFileSync, -} from "node:fs"; -import path from "node:path"; - -import { - EXAMPLE_CARGO_POLICIES, - REQUIRED_WASIX_CONSUMER_PINS, - exampleCargoReleaseVersionBindings, - validateExampleManifestPolicy, - validateResolvedPackagePolicy, - validateWasixConsumerDependencyPins, -} from "./example-cargo-policy.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const cratesIo = "registry+https://github.com/rust-lang/crates.io-index"; -const toolchainVersions = { - wasmer: "7.2.1", - wasmerWasix: "0.702.1", - webc: "12.0.0", -}; -const wasmerPackages = [ - ["wasmer", "7.2.1"], - ["wasmer-compiler", "7.2.1"], - ["wasmer-derive", "7.2.1"], - ["wasmer-types", "7.2.1"], - ["wasmer-vm", "7.2.1"], - ["wasmer-config", "0.702.1"], - ["wasmer-journal", "0.702.1"], - ["wasmer-package", "0.702.1"], - ["wasmer-wasix", "0.702.1"], - ["wasmer-wasix-types", "0.702.1"], - ["virtual-fs", "0.702.1"], - ["virtual-mio", "0.702.1"], - ["virtual-net", "0.702.1"], - ["webc", "12.0.0"], -].map(([name, version]) => ({ name, version, source: cratesIo })); - -describe("ephemeral example Cargo policy", () => { - test("owns every registry example version and native runtime binding", () => { - const bindings = exampleCargoReleaseVersionBindings(); - expect(bindings.filter(({ kind }) => kind === "dependency")).toHaveLength( - EXAMPLE_CARGO_POLICIES.reduce((count, policy) => count + policy.directPackages.length, 0), - ); - expect(bindings.filter(({ kind }) => kind === "runtime")).toHaveLength( - EXAMPLE_CARGO_POLICIES.filter(({ runtime }) => runtime !== undefined).length, - ); - expect(new Set(bindings.map(({ file }) => file))).toEqual(new Set( - EXAMPLE_CARGO_POLICIES.map(({ crateDir }) => `${crateDir}/Cargo.toml`), - )); - for (const policy of EXAMPLE_CARGO_POLICIES) { - expect(bindings.filter(({ policyId, kind }) => policyId === policy.id && kind === "dependency")) - .toHaveLength(policy.directPackages.length); - } - }); - - test("rejects stale runtime metadata, duplicate dependencies, and dependency scope drift", () => { - const policy = EXAMPLE_CARGO_POLICIES.find(({ id }) => id === "native-tauri"); - const bindings = exampleCargoReleaseVersionBindings().filter(({ policyId }) => policyId === policy.id); - const runtimeBinding = bindings.find(({ kind }) => kind === "runtime"); - const manifest = Bun.TOML.parse(readFileSync(path.join(ROOT, policy.crateDir, "Cargo.toml"), "utf8")); - - manifest.package.metadata.oliphaunt["runtime-version"] = "9.9.9"; - manifest["dev-dependencies"] = { oliphaunt: bindings.find(({ name }) => name === "oliphaunt").expected }; - delete manifest.dependencies.oliphaunt; - const failures = validateExampleManifestPolicy(policy, manifest, bindings); - expect(failures).toContain( - `${policy.crateDir}/Cargo.toml runtime-version uses "9.9.9"; expected ${runtimeBinding.expected}`, - ); - expect(failures).toContain( - `${policy.crateDir}/Cargo.toml oliphaunt must remain at TOML path dependencies.oliphaunt`, - ); - - manifest.dependencies.oliphaunt = bindings.find(({ name }) => name === "oliphaunt").expected; - expect(validateExampleManifestPolicy(policy, manifest, bindings).some( - (failure) => failure.includes("direct Oliphaunt dependencies"), - )).toBe(true); - }); - - test("requires exact non-optional pins for the published WASIX family closure", () => { - const dependencies = Object.fromEntries( - REQUIRED_WASIX_CONSUMER_PINS.map((name) => [ - name, - name === "webc" - ? "=12.0.0" - : { version: "=0.702.1", "default-features": false }, - ]), - ); - expect(validateWasixConsumerDependencyPins( - { dependencies }, - { manifestPath: "fixture.toml", toolchainVersions }, - )).toEqual([]); - - dependencies["virtual-mio"] = { version: "0.702.1", "default-features": false }; - dependencies["virtual-net"] = { - version: "=0.702.1", - optional: true, - "default-features": false, - }; - delete dependencies["virtual-fs"]; - expect(validateWasixConsumerDependencyPins( - { dependencies }, - { manifestPath: "fixture.toml", toolchainVersions }, - )).toEqual([ - "fixture.toml must declare non-optional virtual-fs exactly once, found 0", - "fixture.toml dependencies.virtual-mio must pin virtual-mio exactly to =0.702.1, got \"0.702.1\"", - "fixture.toml dependencies.virtual-net must keep virtual-net non-optional", - ]); - }); - - test("rejects default-feature and source substitutions in published WASIX pins", () => { - const dependencies = Object.fromEntries( - REQUIRED_WASIX_CONSUMER_PINS.map((name) => [ - name, - name === "webc" - ? "=12.0.0" - : { version: "=0.702.1", "default-features": false }, - ]), - ); - delete dependencies["wasmer-config"]["default-features"]; - dependencies["wasmer-journal"]["default-features"] = true; - dependencies["wasmer-package"].path = "../../substituted"; - dependencies["wasmer-wasix-types"].git = "https://example.invalid/wasix"; - dependencies["virtual-fs"].registry = "substituted"; - - expect(validateWasixConsumerDependencyPins( - { dependencies }, - { manifestPath: "fixture.toml", toolchainVersions }, - )).toEqual([ - "fixture.toml dependencies.wasmer-config must set default-features = false for wasmer-config", - "fixture.toml dependencies.wasmer-journal must set default-features = false for wasmer-journal", - "fixture.toml dependencies.wasmer-package must resolve wasmer-package from crates.io without source selectors, found path", - "fixture.toml dependencies.wasmer-wasix-types must resolve wasmer-wasix-types from crates.io without source selectors, found git", - "fixture.toml dependencies.virtual-fs must resolve virtual-fs from crates.io without source selectors, found registry", - ]); - }); - - test("rejects missing, ranged, optional, and source-substituted WebC pins", () => { - const dependencies = Object.fromEntries( - REQUIRED_WASIX_CONSUMER_PINS.map((name) => [ - name, - name === "webc" - ? "=12.0.0" - : { version: "=0.702.1", "default-features": false }, - ]), - ); - - delete dependencies.webc; - expect(validateWasixConsumerDependencyPins( - { dependencies }, - { manifestPath: "missing.toml", toolchainVersions }, - )).toContain("missing.toml must declare non-optional webc exactly once, found 0"); - - dependencies.webc = { - version: "^12.0.0", - optional: true, - git: "https://example.invalid/webc", - }; - expect(validateWasixConsumerDependencyPins( - { dependencies }, - { manifestPath: "substituted.toml", toolchainVersions }, - )).toEqual([ - "substituted.toml dependencies.webc must pin webc exactly to =12.0.0, got \"^12.0.0\"", - "substituted.toml dependencies.webc must keep webc non-optional", - "substituted.toml dependencies.webc must resolve webc from crates.io without source selectors, found git", - ]); - }); - - test("accepts canonical stable WASIX packages and advisory floors", () => { - expect(validateResolvedPackagePolicy("fixture.lock", [ - ...wasmerPackages, - { name: "crossbeam-epoch", version: "0.9.20", source: cratesIo }, - { name: "postgres-protocol", version: "0.6.12", source: cratesIo }, - ], { wasixToolchain: true, toolchainVersions })).toEqual([]); - }); - - test("rejects prerelease Wasmer drift", () => { - const packages = wasmerPackages.map((pkg) => - pkg.name === "wasmer-wasix" ? { ...pkg, version: "0.702.1-alpha.3" } : pkg, - ); - expect(validateResolvedPackagePolicy("fixture.lock", packages, { - wasixToolchain: true, - toolchainVersions, - })).toContain("fixture.lock: wasmer-wasix resolved 0.702.1-alpha.3; expected 0.702.1"); - }); - - test("rejects duplicate or drifted WebC identities from fresh consumer locks", () => { - const duplicate = [ - ...wasmerPackages, - { name: "webc", version: "11.0.0", source: cratesIo }, - ]; - expect(validateResolvedPackagePolicy("fixture.lock", duplicate, { - wasixToolchain: true, - toolchainVersions, - })).toContain("fixture.lock: expected exactly one resolved webc package, found 2"); - - const drifted = wasmerPackages.map((pkg) => - pkg.name === "webc" ? { ...pkg, version: "12.0.1" } : pkg - ); - expect(validateResolvedPackagePolicy("fixture.lock", drifted, { - wasixToolchain: true, - toolchainVersions, - })).toContain("fixture.lock: webc resolved 12.0.1; expected 12.0.0"); - }); - - test("rejects advisory versions below their floors", () => { - expect(validateResolvedPackagePolicy("fixture.lock", [ - { name: "crossbeam-epoch", version: "0.9.18", source: cratesIo }, - { name: "postgres-protocol", version: "0.6.11", source: cratesIo }, - ])).toEqual([ - "fixture.lock: crossbeam-epoch 0.9.18 is below required floor 0.9.20", - "fixture.lock: postgres-protocol 0.6.11 is below required floor 0.6.12", - ]); - }); - - test("fails closed when a required transitive package disappears", () => { - expect(validateResolvedPackagePolicy( - "fixture.lock", - wasmerPackages.filter((pkg) => pkg.name !== "virtual-net"), - { wasixToolchain: true, toolchainVersions }, - )).toContain("fixture.lock: expected exactly one resolved virtual-net package, found 0"); - }); - - test("rejects unknown Wasmer and virtual packages instead of accepting stable drift", () => { - const failures = validateResolvedPackagePolicy("fixture.lock", [ - ...wasmerPackages, - { name: "wasmer-future", version: "1.0.0", source: cratesIo }, - { name: "virtual-future", version: "0.702.1", source: cratesIo }, - ], { wasixToolchain: true, toolchainVersions }); - expect(failures).toContain( - "fixture.lock: unexpected non-canonical WASIX toolchain package wasmer-future@1.0.0", - ); - expect(failures).toContain( - "fixture.lock: unexpected non-canonical WASIX toolchain package virtual-future@0.702.1", - ); - }); - -}); diff --git a/tools/release/example-cargo-versions.mts b/tools/release/example-cargo-versions.mts new file mode 100644 index 000000000..ab3bc2dd6 --- /dev/null +++ b/tools/release/example-cargo-versions.mts @@ -0,0 +1,99 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { ROOT } from './release-graph.mts'; +import { cargoManifestPaths } from './release-please-transition.mts'; +import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; + +const TOOL = 'example-cargo-versions'; +const TABLES = ['dependencies', 'dev-dependencies', 'build-dependencies']; + +// The manifest owns dependency names, scopes and aliases. The release catalog +// supplies versions; it must not impose a second, handwritten dependency graph. +export function exampleCargoPolicy(file, manifest) { + const crateDir = path.posix.dirname(file); + const dependencyBindings = []; + const collect = (table, parts) => { + for (const [name, spec] of Object.entries(table ?? {})) { + const packageName = typeof spec === 'object' ? (spec.package ?? name) : name; + if (!/^(?:oliphaunt(?:-|$)|liboliphaunt-)/u.test(packageName)) continue; + // Local/workspace and external-source dependencies retain their own semantics. + if ( + typeof spec === 'object' && + ['path', 'workspace', 'git', 'registry'].some((key) => Object.hasOwn(spec, key)) + ) + continue; + dependencyBindings.push({ name, packageName, entryParts: [...parts, name] }); + } + }; + for (const table of TABLES) collect(manifest[table], [table]); + for (const [target, config] of Object.entries(manifest.target ?? {})) { + for (const table of TABLES) collect(config[table], ['target', target, table]); + } + const runtime = manifest.package?.metadata?.oliphaunt?.runtime; + return { + id: crateDir, + crateDir, + dependencyBindings, + ...(runtime === undefined + ? {} + : { + runtime: { + product: runtime, + productParts: ['package', 'metadata', 'oliphaunt', 'runtime'], + versionParts: ['package', 'metadata', 'oliphaunt', 'runtime-version'], + }, + }), + }; +} + +export function exampleCargoPolicies() { + return cargoManifestPaths().flatMap((file) => { + const relative = path.relative(ROOT, file).split(path.sep).join('/'); + if (!relative.startsWith('src/examples/')) return []; + return [exampleCargoPolicy(relative, Bun.TOML.parse(readFileSync(file, 'utf8')))]; + }); +} + +export function exampleCargoReleaseVersionBindings() { + const catalog = loadPublicationCatalog(TOOL); + const initialVersion = JSON.parse( + readFileSync(path.join(ROOT, 'release-please-config.json'), 'utf8'), + )['initial-version']; + const effectiveVersion = (version) => (version === '0.0.0' ? initialVersion : version); + const bindings = []; + for (const policy of exampleCargoPolicies()) { + const file = `${policy.crateDir}/Cargo.toml`; + for (const { name, packageName, entryParts } of policy.dependencyBindings) { + const carrier = resolveActualCarrier(catalog, 'cargo', packageName, TOOL); + bindings.push({ + kind: 'dependency', + policyId: policy.id, + file, + name, + entryParts, + versionPaths: [entryParts, [...entryParts, 'version']], + sourceProduct: carrier.product, + expected: `=${effectiveVersion(carrier.version)}`, + wrapped: true, + }); + } + if (policy.runtime !== undefined) { + const products = catalog.products.filter(({ id }) => id === policy.runtime.product); + if (products.length !== 1) + throw new Error(`${TOOL}: unknown runtime ${policy.runtime.product}`); + const entryParts = policy.runtime.versionParts; + bindings.push({ + kind: 'runtime', + policyId: policy.id, + file, + name: 'runtime-version', + entryParts, + versionPaths: [entryParts], + sourceProduct: policy.runtime.product, + expected: effectiveVersion(products[0].version), + wrapped: false, + }); + } + } + return bindings; +} diff --git a/tools/release/example-cargo-versions.test.mts b/tools/release/example-cargo-versions.test.mts new file mode 100644 index 000000000..af109b636 --- /dev/null +++ b/tools/release/example-cargo-versions.test.mts @@ -0,0 +1,24 @@ +import { expect, test } from 'bun:test'; +import { exampleCargoPolicy } from './example-cargo-versions.mts'; + +test('release bindings follow renamed packages and target scopes without controlling local dependencies', () => { + const policy = exampleCargoPolicy('src/examples/new-app/Cargo.toml', { + dependencies: { + database: { package: 'oliphaunt', version: '=0.2.0' }, + 'oliphaunt-local': { path: '../local', version: '*' }, + 'oliphaunt-shared': { workspace: true }, + 'oliphaunt-fork': { git: 'https://example.invalid/fork' }, + 'oliphaunt-private': { registry: 'private', version: '1' }, + serde: '1', + }, + target: { 'cfg(unix)': { 'dev-dependencies': { oliphaunt: '=0.2.0' } } }, + }); + expect(policy.dependencyBindings).toEqual([ + { name: 'database', packageName: 'oliphaunt', entryParts: ['dependencies', 'database'] }, + { + name: 'oliphaunt', + packageName: 'oliphaunt', + entryParts: ['target', 'cfg(unix)', 'dev-dependencies', 'oliphaunt'], + }, + ]); +}); diff --git a/tools/release/extension-artifact-archive-policy.mjs b/tools/release/extension-artifact-archive-policy.mjs deleted file mode 100644 index 04531e79c..000000000 --- a/tools/release/extension-artifact-archive-policy.mjs +++ /dev/null @@ -1,116 +0,0 @@ -import { readFileSync } from "node:fs"; -import path from "node:path"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -export const EXTENSION_ARTIFACT_ARCHIVE_POLICY_PATH = - "src/shared/extension-runtime-contract/extension-artifact-archive-policy.properties"; - -const EXPECTED_SCHEMA = "oliphaunt-extension-artifact-archive-policy-v1"; -const EXPECTED_KEYS = Object.freeze([ - "schema", - "maxCompressedBytes", - "maxExpandedBytes", - "maxMemberBytes", - "maxMembers", -]); - -function fail(message) { - throw new Error(`extension artifact archive policy: ${message}`); -} - -function parseCanonicalProperties(text) { - if ( - text.includes("\r") - || !text.endsWith("\n") - || text.endsWith("\n\n") - || text !== text.normalize("NFC") - ) { - fail("must use canonical NFC UTF-8 key=value text with LF lines and one final newline"); - } - const values = new Map(); - for (const [index, line] of text.slice(0, -1).split("\n").entries()) { - const separator = line.indexOf("="); - if (separator <= 0 || separator === line.length - 1) { - fail(`line ${index + 1} must be a non-empty key=value pair`); - } - const key = line.slice(0, separator); - const value = line.slice(separator + 1); - if (values.has(key)) fail(`repeats property ${key}`); - values.set(key, value); - } - if (JSON.stringify([...values.keys()]) !== JSON.stringify(EXPECTED_KEYS)) { - fail(`property keys must be exactly ${EXPECTED_KEYS.join(",")}`); - } - if (values.get("schema") !== EXPECTED_SCHEMA) { - fail(`schema must be ${EXPECTED_SCHEMA}`); - } - const positiveInteger = (key) => { - const value = Number(values.get(key)); - if (!Number.isSafeInteger(value) || value <= 0 || String(value) !== values.get(key)) { - fail(`${key} must be a canonical positive safe integer`); - } - return value; - }; - const policy = { - maxCompressedBytes: positiveInteger("maxCompressedBytes"), - maxExpandedBytes: positiveInteger("maxExpandedBytes"), - maxMemberBytes: positiveInteger("maxMemberBytes"), - maxMembers: positiveInteger("maxMembers"), - }; - if (policy.maxMemberBytes > policy.maxExpandedBytes) { - fail("maxMemberBytes must not exceed maxExpandedBytes"); - } - return Object.freeze(policy); -} - -export const EXTENSION_ARTIFACT_ARCHIVE_POLICY = parseCanonicalProperties( - readFileSync(path.join(ROOT, EXTENSION_ARTIFACT_ARCHIVE_POLICY_PATH), "utf8"), -); - -export function validateExtensionArtifactArchivePlan(members, label = "extension artifact") { - if (!Array.isArray(members) || members.length === 0) { - fail(`${label} must contain at least one regular member`); - } - if (members.length > EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMembers) { - fail(`${label} contains more than ${EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMembers} members`); - } - let expandedBytes = 1024; - for (const [index, member] of members.entries()) { - const bytes = member?.bytes; - const name = typeof member?.name === "string" && member.name.length > 0 - ? member.name - : `member ${index}`; - if (!Number.isSafeInteger(bytes) || bytes < 0) { - fail(`${label} ${name} has an invalid byte count`); - } - if (bytes > EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes) { - fail( - `${label} member ${name} exceeds ${EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes} bytes`, - ); - } - const padded = Math.ceil(bytes / 512) * 512; - expandedBytes += 512 + padded; - if (!Number.isSafeInteger(expandedBytes)) { - fail(`${label} expanded size overflows a safe integer`); - } - if (expandedBytes > EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxExpandedBytes) { - fail( - `${label} expands beyond ${EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxExpandedBytes} bytes`, - ); - } - } - return expandedBytes; -} - -export function validateExtensionArtifactCompressedBytes(bytes, label = "extension artifact") { - if ( - !Number.isSafeInteger(bytes) - || bytes <= 0 - || bytes > EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxCompressedBytes - ) { - fail( - `${label} compressed bytes must be between 1 and ${EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxCompressedBytes}`, - ); - } - return bytes; -} diff --git a/tools/release/extension-artifact-inventory.mjs b/tools/release/extension-artifact-inventory.mjs deleted file mode 100644 index d1889bd5a..000000000 --- a/tools/release/extension-artifact-inventory.mjs +++ /dev/null @@ -1,937 +0,0 @@ -import { createHash } from "node:crypto"; -import { - closeSync, - constants, - fstatSync, - lstatSync, - mkdtempSync, - openSync, - readFileSync, - readSync, - rmSync, - statSync, - writeSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { TextDecoder } from "node:util"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { EXTENSION_ARTIFACT_ARCHIVE_POLICY } from "./extension-artifact-archive-policy.mjs"; -import { - extensionCarrierLegalContract, - extensionUpstreamLicenseRow, -} from "./extension-upstream-licenses.mjs"; -import { extensionProductForSqlName } from "./release-artifact-targets.mjs"; -import { releaseNoticeRows } from "./release-notices.mjs"; - -export const EXTENSION_ARTIFACT_PROPERTY_KEYS = Object.freeze([ - "packageLayout", - "pgMajor", - "sqlName", - "createsExtension", - "nativeModuleStem", - "nativeModuleFile", - "nativeTarget", - "nativeRuntimeProduct", - "nativeRuntimeVersion", - "dependencies", - "dataFiles", - "extensionSqlFileNames", - "extensionSqlFilePrefixes", - "sharedPreloadLibraries", - "mobilePrebuilt", - "mobileStaticArchives", - "mobileStaticDependencyArchives", - "staticSymbolPrefix", - "staticSymbolAliases", - "licenseFiles", - "licenseProfile", - "files", -]); - -const PORTABLE_ID = /^[A-Za-z0-9._-]{1,128}$/u; -const C_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u; -const SHA256 = /^[0-9a-f]{64}$/u; -const { - maxCompressedBytes: MAX_COMPRESSED_ARCHIVE_BYTES, - maxExpandedBytes: MAX_EXPANDED_ARCHIVE_BYTES, - maxMemberBytes: MAX_ARCHIVE_MEMBER_BYTES, - maxMembers: MAX_ARCHIVE_MEMBERS, -} = EXTENSION_ARTIFACT_ARCHIVE_POLICY; -const UTF8 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }); -const DESKTOP_NATIVE_TARGETS = new Set([ - "linux-x64-gnu", - "linux-arm64-gnu", - "macos-arm64", - "windows-x64-msvc", -]); -const BOUNDED_GUNZIP = path.join(import.meta.dirname, "bounded-gunzip-to-file.mjs"); - -function inventoryError(label, message) { - return new Error(`${label}: ${message}`); -} - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function safeRelativePath(value, label) { - if (typeof value !== "string" || value.length === 0 || value.includes("\0")) { - throw inventoryError(label, "must be a non-empty relative path"); - } - if (value.includes("\\") || value !== value.normalize("NFC") || /[\u0000-\u001f\u007f]/u.test(value)) { - throw inventoryError(label, "must use NFC UTF-8 text without backslashes or control characters"); - } - const parts = value.split("/"); - if ( - value.startsWith("/") - || /^[A-Za-z]:/u.test(value) - || parts.some((part) => part.length === 0 || part === "." || part === "..") - ) { - throw inventoryError(label, `must be a canonical relative path; got ${JSON.stringify(value)}`); - } - return parts.join("/"); -} - -function csv(value, label, { paths = false } = {}) { - if (typeof value !== "string") throw inventoryError(label, "must be a string"); - if (value.length === 0) return []; - const rows = value.split(",").map((row, index) => { - if (row.length === 0 || row.trim() !== row) { - throw inventoryError(label, `contains a malformed item at index ${index}`); - } - return paths ? safeRelativePath(row, `${label}[${index}]`) : row; - }); - if (new Set(rows).size !== rows.length) throw inventoryError(label, "must not contain duplicates"); - const sorted = [...rows].sort(compareText); - if (JSON.stringify(rows) !== JSON.stringify(sorted)) { - throw inventoryError(label, "must be sorted deterministically"); - } - return rows; -} - -export function parseExtensionArtifactProperties(text, label) { - if ( - typeof text !== "string" - || text.startsWith("\uFEFF") - || text.includes("\r") - || text.includes("\\") - || text !== text.normalize("NFC") - || /[\u0000-\u0009\u000b-\u001f\u007f]/u.test(text) - || !text.endsWith("\n") - || text.endsWith("\n\n") - ) { - throw inventoryError( - label, - "must be canonical NFC UTF-8 key=value text with LF lines and exactly one final newline", - ); - } - const properties = new Map(); - const lines = text.slice(0, -1).split("\n"); - for (const [index, rawLine] of lines.entries()) { - if (rawLine.length === 0) { - throw inventoryError(label, `has an internal blank line at ${index + 1}`); - } - const separator = rawLine.indexOf("="); - if (separator <= 0 || rawLine.trim() !== rawLine) { - throw inventoryError(label, `has malformed properties line ${index + 1}`); - } - const key = rawLine.slice(0, separator); - if (properties.has(key)) { - throw inventoryError(label, `repeats property ${key}`); - } - properties.set(key, rawLine.slice(separator + 1)); - } - const actual = [...properties.keys()].sort(compareText); - const expected = [...EXTENSION_ARTIFACT_PROPERTY_KEYS].sort(compareText); - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - throw inventoryError( - label, - `property fields must be exactly ${expected.join(",")}; got ${actual.join(",")}`, - ); - } - if (JSON.stringify([...properties.keys()]) !== JSON.stringify(EXTENSION_ARTIFACT_PROPERTY_KEYS)) { - throw inventoryError(label, "properties must use the canonical field order"); - } - return properties; -} - -function decodeUtf8(bytes, label) { - try { - return UTF8.decode(bytes); - } catch (error) { - throw inventoryError(label, `contains invalid UTF-8: ${error.message}`); - } -} - -function tarString(buffer, offset, length, label, field) { - const bytes = buffer.subarray(offset, offset + length); - const end = bytes.indexOf(0); - if (end >= 0 && !bytes.subarray(end).every((byte) => byte === 0)) { - throw inventoryError(label, `tar ${field} has nonzero bytes after its terminator`); - } - return decodeUtf8( - bytes.subarray(0, end < 0 ? bytes.length : end), - `${label} tar ${field}`, - ); -} - -function canonicalTarOctal(length, value) { - return Buffer.from(`${value.toString(8).padStart(length - 1, "0")}\0`, "ascii"); -} - -function tarOctal(buffer, offset, length, label, field) { - if (field === "checksum") { - const bytes = buffer.subarray(offset, offset + length); - if (length !== 8 || bytes[6] !== 0 || bytes[7] !== 0x20) { - throw inventoryError(label, "has noncanonical tar checksum encoding"); - } - const digits = decodeUtf8(bytes.subarray(0, 6), `${label} tar checksum`); - if (!/^[0-7]{6}$/u.test(digits)) { - throw inventoryError(label, `has invalid tar checksum field ${JSON.stringify(digits)}`); - } - return Number.parseInt(digits, 8); - } - const value = tarString(buffer, offset, length, label, field).trim(); - if (!/^[0-7]+$/u.test(value)) { - throw inventoryError(label, `has invalid tar ${field} field ${JSON.stringify(value)}`); - } - const parsed = Number.parseInt(value, 8); - if (!Number.isSafeInteger(parsed) || parsed < 0) { - throw inventoryError(label, `has out-of-range tar ${field}`); - } - return parsed; -} - -function readExact(descriptor, position, length, label) { - const buffer = Buffer.alloc(length); - let offset = 0; - while (offset < length) { - const bytes = readSync(descriptor, buffer, offset, length - offset, position + offset); - if (bytes === 0) throw inventoryError(label, "tar stream ended unexpectedly"); - offset += bytes; - } - return buffer; -} - -function writeAll(descriptor, buffer, label) { - let offset = 0; - while (offset < buffer.length) { - const bytes = writeSync(descriptor, buffer, offset, buffer.length - offset); - if (bytes <= 0) throw inventoryError(label, "failed to snapshot the carrier bytes"); - offset += bytes; - } -} - -function rangeIsZero(descriptor, position, length, label) { - const buffer = Buffer.alloc(Math.min(64 * 1024, Math.max(length, 1))); - let checked = 0; - while (checked < length) { - const wanted = Math.min(buffer.length, length - checked); - const bytes = readSync(descriptor, buffer, 0, wanted, position + checked); - if (bytes !== wanted) throw inventoryError(label, "tar stream ended unexpectedly"); - if (!buffer.subarray(0, bytes).every((byte) => byte === 0)) return false; - checked += bytes; - } - return true; -} - -function canonicalTarPathParts(archiveName, label) { - if (Buffer.byteLength(archiveName) <= 100) { - return { name: archiveName, prefix: "" }; - } - const parts = archiveName.split("/"); - for (let index = 1; index < parts.length; index += 1) { - const prefix = parts.slice(0, index).join("/"); - const name = parts.slice(index).join("/"); - if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) { - return { name, prefix }; - } - } - throw inventoryError(label, `member ${archiveName} cannot use the canonical producer ustar split`); -} - -function validateCanonicalHeader(header, label, block, collisionNames, entries) { - const storedChecksum = tarOctal(header, 148, 8, label, "checksum"); - const checksumHeader = Buffer.from(header); - checksumHeader.fill(0x20, 148, 156); - const actualChecksum = checksumHeader.reduce((sum, byte) => sum + byte, 0); - if (storedChecksum !== actualChecksum) { - throw inventoryError(label, `has a tar header checksum mismatch at block ${block}`); - } - if (tarString(header, 257, 6, label, "magic") !== "ustar") { - throw inventoryError(label, "must use canonical ustar headers"); - } - const name = tarString(header, 0, 100, label, "name"); - const prefix = tarString(header, 345, 155, label, "prefix"); - const archiveName = safeRelativePath(prefix ? `${prefix}/${name}` : name, `${label} tar member`); - const canonicalPath = canonicalTarPathParts(archiveName, label); - if (name !== canonicalPath.name || prefix !== canonicalPath.prefix) { - throw inventoryError( - label, - `member ${archiveName} must use canonical ustar name/prefix split ${JSON.stringify(canonicalPath)}`, - ); - } - const collisionKey = archiveName.normalize("NFC").toLowerCase(); - const collision = collisionNames.get(collisionKey); - if (collision !== undefined && collision !== archiveName) { - throw inventoryError(label, `contains case/NFC-colliding members ${collision} and ${archiveName}`); - } - collisionNames.set(collisionKey, archiveName); - if (header[156] !== 0x30) { - throw inventoryError(label, `member ${archiveName} must be a regular file`); - } - const mode = tarOctal(header, 100, 8, label, "mode"); - const uid = tarOctal(header, 108, 8, label, "uid"); - const gid = tarOctal(header, 116, 8, label, "gid"); - const size = tarOctal(header, 124, 12, label, "size"); - const mtime = tarOctal(header, 136, 12, label, "mtime"); - if (size > MAX_ARCHIVE_MEMBER_BYTES) { - throw inventoryError(label, `member ${archiveName} exceeds ${MAX_ARCHIVE_MEMBER_BYTES} bytes`); - } - if (![0o644, 0o755].includes(mode) || uid !== 0 || gid !== 0 || mtime !== 0) { - throw inventoryError( - label, - `member ${archiveName} must use mode 0644/0755, uid=0, gid=0 and mtime=0`, - ); - } - for (const [field, offset, length, value] of [ - ["mode", 100, 8, mode], - ["uid", 108, 8, uid], - ["gid", 116, 8, gid], - ["size", 124, 12, size], - ["mtime", 136, 12, mtime], - ]) { - if (!header.subarray(offset, offset + length).equals(canonicalTarOctal(length, value))) { - throw inventoryError(label, `member ${archiveName} has noncanonical tar ${field} encoding`); - } - } - if ( - !header.subarray(148, 156).equals( - Buffer.from(`${storedChecksum.toString(8).padStart(6, "0")}\0 `, "ascii"), - ) - || !header.subarray(157, 257).every((byte) => byte === 0) - || !header.subarray(257, 263).equals(Buffer.from("ustar\0", "ascii")) - || !header.subarray(263, 265).equals(Buffer.from("00", "ascii")) - || tarString(header, 265, 32, label, "uname") !== "root" - || tarString(header, 297, 32, label, "gname") !== "root" - || !header.subarray(329, 345).every((byte) => byte === 0) - || !header.subarray(500, 512).every((byte) => byte === 0) - ) { - throw inventoryError(label, `member ${archiveName} does not use the canonical producer ustar header`); - } - if (entries.has(archiveName)) { - throw inventoryError(label, `contains duplicate member ${archiveName}`); - } - return { archiveName, mode, size }; -} - -/** Read exactly the bounded deterministic gzip+ustar emitted by extension-artifact-packager.mjs. */ -export function readCanonicalExtensionArtifactArchive(file, label = file) { - const carrierMetadata = lstatSync(file, { bigint: true }); - if (carrierMetadata.isSymbolicLink() || !carrierMetadata.isFile()) { - throw inventoryError(label, "carrier input must be a regular non-symlink file"); - } - const temporary = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-extension-archive-")); - const compressedSnapshot = path.join(temporary, "carrier.tar.gz"); - const expanded = path.join(temporary, "archive.tar"); - try { - let compressedDescriptor; - let snapshotDescriptor; - let gzipHeader; - let compressedBytes; - try { - compressedDescriptor = openSync( - file, - constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0), - ); - const opened = fstatSync(compressedDescriptor, { bigint: true }); - if ( - !opened.isFile() - || opened.dev !== carrierMetadata.dev - || opened.ino !== carrierMetadata.ino - ) { - throw inventoryError(label, "carrier changed between path inspection and no-follow open"); - } - compressedBytes = Number(opened.size); - if ( - !Number.isSafeInteger(compressedBytes) - || compressedBytes === 0 - || compressedBytes > MAX_COMPRESSED_ARCHIVE_BYTES - ) { - throw inventoryError( - label, - `archive bytes must be between 1 and ${MAX_COMPRESSED_ARCHIVE_BYTES}`, - ); - } - gzipHeader = readExact(compressedDescriptor, 0, 10, label); - snapshotDescriptor = openSync( - compressedSnapshot, - constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | (constants.O_NOFOLLOW ?? 0), - 0o600, - ); - const buffer = Buffer.alloc(256 * 1024); - let position = 0; - while (position < compressedBytes) { - const wanted = Math.min(buffer.length, compressedBytes - position); - const bytes = readSync(compressedDescriptor, buffer, 0, wanted, position); - if (bytes !== wanted) { - throw inventoryError(label, "carrier changed or ended while taking its private snapshot"); - } - writeAll(snapshotDescriptor, buffer.subarray(0, bytes), label); - position += bytes; - } - const after = fstatSync(compressedDescriptor, { bigint: true }); - if ( - !after.isFile() - || after.dev !== opened.dev - || after.ino !== opened.ino - || after.size !== opened.size - || after.mtimeNs !== opened.mtimeNs - || after.ctimeNs !== opened.ctimeNs - ) { - throw inventoryError(label, "carrier metadata changed while taking its private snapshot"); - } - } finally { - if (snapshotDescriptor !== undefined) closeSync(snapshotDescriptor); - if (compressedDescriptor !== undefined) closeSync(compressedDescriptor); - } - if ( - gzipHeader[0] !== 0x1f - || gzipHeader[1] !== 0x8b - || gzipHeader[2] !== 8 - || gzipHeader[3] !== 0 - || !gzipHeader.subarray(4, 8).every((byte) => byte === 0) - || gzipHeader[8] !== 0 - || gzipHeader[9] !== 0x03 - ) { - throw inventoryError(label, "must use the canonical cross-platform gzip header"); - } - if (statSync(compressedSnapshot).size !== compressedBytes) { - throw inventoryError(label, "private carrier snapshot has the wrong byte count"); - } - const result = captureCommandOutput( - process.execPath, - [BOUNDED_GUNZIP, compressedSnapshot, expanded, String(MAX_EXPANDED_ARCHIVE_BYTES)], - { - label: `bounded gzip reader for ${label}`, - maxOutputBytes: 1024 * 1024, - }, - ); - if (result.error) { - throw inventoryError(label, `bounded gzip reader failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - const detail = String(result.stderr || result.stdout || "").trim(); - throw inventoryError(label, `is not a valid bounded gzip stream${detail ? `: ${detail}` : ""}`); - } - const expandedBytes = statSync(expanded).size; - if ( - expandedBytes < 1024 - || expandedBytes > MAX_EXPANDED_ARCHIVE_BYTES - || expandedBytes % 512 !== 0 - ) { - throw inventoryError(label, "must contain a bounded block-aligned ustar stream"); - } - const entries = new Map(); - const collisionNames = new Map(); - let descriptor; - let offset = 0; - let ended = false; - try { - descriptor = openSync(expanded, "r"); - while (offset < expandedBytes) { - const header = readExact(descriptor, offset, 512, label); - if (header.every((byte) => byte === 0)) { - if ( - expandedBytes - offset !== 1024 - || !rangeIsZero(descriptor, offset, 1024, label) - ) { - throw inventoryError(label, "tar end marker or trailing padding is not canonical"); - } - ended = true; - break; - } - const { archiveName, mode, size } = validateCanonicalHeader( - header, - label, - offset / 512, - collisionNames, - entries, - ); - const dataStart = offset + 512; - const dataEnd = dataStart + size; - const paddedEnd = dataStart + Math.ceil(size / 512) * 512; - if (dataEnd > expandedBytes || paddedEnd > expandedBytes) { - throw inventoryError(label, `member ${archiveName} exceeds the tar stream`); - } - const data = readExact(descriptor, dataStart, size, label); - if (!rangeIsZero(descriptor, dataEnd, paddedEnd - dataEnd, label)) { - throw inventoryError(label, `member ${archiveName} has nonzero tar padding`); - } - entries.set(archiveName, { - bytes: data.length, - data, - mode, - sha256: createHash("sha256").update(data).digest("hex"), - }); - if (entries.size > MAX_ARCHIVE_MEMBERS) { - throw inventoryError(label, `contains more than ${MAX_ARCHIVE_MEMBERS} members`); - } - offset = paddedEnd; - } - } finally { - if (descriptor !== undefined) closeSync(descriptor); - } - if (!ended || entries.size === 0) { - throw inventoryError(label, "must contain regular files and a canonical tar end marker"); - } - const names = [...entries.keys()]; - if (JSON.stringify(names) !== JSON.stringify([...names].sort(compareText))) { - throw inventoryError(label, "tar members must be sorted deterministically"); - } - return entries; - } finally { - rmSync(temporary, { recursive: true, force: true }); - } -} - -function normalizeMetadata(row, label) { - const sqlName = row?.sqlName ?? row?.["sql-name"]; - if (typeof sqlName !== "string" || !PORTABLE_ID.test(sqlName)) { - throw inventoryError(label, "has an invalid sqlName"); - } - const list = (camel, kebab, explicitValue = undefined) => { - const value = explicitValue ?? row?.[camel] ?? row?.[kebab]; - if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) { - throw inventoryError(label, `${kebab} must be a string array`); - } - const sorted = [...value].sort(compareText); - if (new Set(sorted).size !== sorted.length) { - throw inventoryError(label, `${kebab} must not contain duplicates`); - } - return sorted; - }; - const nativeModuleStem = row?.nativeModuleStem ?? row?.["native-module-stem"] ?? null; - if (nativeModuleStem !== null && (typeof nativeModuleStem !== "string" || !PORTABLE_ID.test(nativeModuleStem))) { - throw inventoryError(label, "native-module-stem must be null or a portable identifier"); - } - const createsExtension = row?.createsExtension ?? row?.["creates-extension"]; - if (typeof createsExtension !== "boolean") { - throw inventoryError(label, "creates-extension must be boolean"); - } - const metadata = { - sqlName, - createsExtension, - nativeModuleStem, - dependencies: (() => { - const selected = row?.selectedExtensionDependencies - ?? row?.["selected-extension-dependencies"] - ?? row?.dependencies; - return list("selectedExtensionDependencies", "selected-extension-dependencies", selected); - })(), - dataFiles: list( - "runtimeShareDataFiles", - "runtime-share-data-files", - row?.runtimeShareDataFiles ?? row?.["runtime-share-data-files"] ?? row?.dataFiles, - ).map((item, index) => - safeRelativePath(item, `${label}.runtime-share-data-files[${index}]`)), - extensionSqlFileNames: list("extensionSqlFileNames", "extension-sql-file-names"), - extensionSqlFilePrefixes: list("extensionSqlFilePrefixes", "extension-sql-file-prefixes"), - sharedPreloadLibraries: list("sharedPreloadLibraries", "shared-preload-libraries"), - }; - for (const [field, values] of [ - ["selected-extension-dependencies", metadata.dependencies], - ["shared-preload-libraries", metadata.sharedPreloadLibraries], - ]) { - if (values.some((item) => !PORTABLE_ID.test(item))) { - throw inventoryError(label, `${field} contains a non-portable identifier`); - } - } - if ( - metadata.extensionSqlFileNames.some( - (item) => path.posix.basename(item) !== item || !item.endsWith(".sql"), - ) - ) { - throw inventoryError(label, "extension-sql-file-names must contain SQL basenames"); - } - if ( - metadata.extensionSqlFilePrefixes.some( - (item) => !PORTABLE_ID.test(item) || item.includes("."), - ) - ) { - throw inventoryError(label, "extension-sql-file-prefixes must contain portable basename prefixes"); - } - return metadata; -} - -function moduleSuffix(target) { - if (target === "windows-x64-msvc") return ".dll"; - if (target === "macos-arm64" || target === "ios-xcframework") return ".dylib"; - return ".so"; -} - -function sqlFileOwned(fileName, metadata) { - return ( - (metadata.createsExtension && fileName === `${metadata.sqlName}.control`) - || (metadata.createsExtension && fileName === `${metadata.sqlName}.sql`) - || (metadata.createsExtension && fileName.startsWith(`${metadata.sqlName}--`) && fileName.endsWith(".sql")) - || metadata.extensionSqlFileNames.includes(fileName) - || (fileName.endsWith(".sql") - && metadata.extensionSqlFilePrefixes.some((prefix) => fileName.startsWith(prefix))) - ); -} - -export function isCanonicalExtensionInstallSql(fileName, sqlName) { - const prefix = `${sqlName}--`; - if (!fileName.startsWith(prefix) || !fileName.endsWith(".sql")) return false; - const version = fileName.slice(prefix.length, -".sql".length); - return /^[0-9][A-Za-z0-9._-]*$/u.test(version) && !version.includes("--"); -} - -function extensionSqlVersion(value) { - return /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value) && !value.includes("--"); -} - -export function extensionControlDefaultVersion(control, sqlName, label) { - const values = []; - for (const [index, raw] of control.split(/\r?\n/u).entries()) { - const line = raw.trim(); - if (line.length === 0 || line.startsWith("#")) continue; - if (!/^default_version(?:\s|=)/u.test(line)) continue; - const match = line.match(/^default_version\s*=\s*'([^']+)'\s*(?:#.*)?$/u); - if (match === null || !extensionSqlVersion(match[1])) { - throw inventoryError(label, `${sqlName}.control has invalid default_version on line ${index + 1}`); - } - values.push(match[1]); - } - if (values.length !== 1) { - throw inventoryError(label, `${sqlName}.control must declare default_version exactly once`); - } - return values[0]; -} - -function canonicalInstallVersion(fileName, sqlName) { - if (!isCanonicalExtensionInstallSql(fileName, sqlName)) return null; - return fileName.slice(`${sqlName}--`.length, -".sql".length); -} - -function canonicalUpdateEdge(fileName, sqlName) { - const prefix = `${sqlName}--`; - if (!fileName.startsWith(prefix) || !fileName.endsWith(".sql")) return null; - const versions = fileName.slice(prefix.length, -".sql".length).split("--"); - if (versions.length !== 2 || !versions.every(extensionSqlVersion)) return null; - return versions; -} - -/** Prove that PostgreSQL can install the control file's default version. */ -export function validateExtensionInstallSqlReachability({ sqlName, control, fileNames, label }) { - const defaultVersion = extensionControlDefaultVersion(control, sqlName, label); - const installVersions = new Set(); - const updateTargets = new Map(); - for (const fileName of [...new Set(fileNames)].sort(compareText)) { - const installVersion = canonicalInstallVersion(fileName, sqlName); - if (installVersion !== null) installVersions.add(installVersion); - const edge = canonicalUpdateEdge(fileName, sqlName); - if (edge !== null) { - const [from, to] = edge; - const targets = updateTargets.get(from) ?? new Set(); - targets.add(to); - updateTargets.set(from, targets); - } - } - if (installVersions.has(defaultVersion)) return; - - const reachable = new Set(installVersions); - const pending = [...installVersions].sort(compareText); - for (let index = 0; index < pending.length; index += 1) { - const current = pending[index]; - for (const next of [...(updateTargets.get(current) ?? [])].sort(compareText)) { - if (reachable.has(next)) continue; - reachable.add(next); - pending.push(next); - } - } - if (reachable.has(defaultVersion)) return; - - const updates = [...updateTargets] - .flatMap(([from, targets]) => [...targets].map((to) => `${from}->${to}`)) - .sort(compareText); - throw inventoryError( - label, - `${sqlName} default_version '${defaultVersion}' has no canonical installation script or update path; ` - + `install versions=${[...installVersions].sort(compareText).join(",") || "-"}; updates=${updates.join(",") || "-"}`, - ); -} - -function declaredMobilePaths(properties, metadata, label) { - const paths = []; - const staticRows = csv(properties.get("mobileStaticArchives"), `${label} mobileStaticArchives`); - for (const [index, row] of staticRows.entries()) { - const separator = row.indexOf(":"); - if (separator <= 0 || metadata.nativeModuleStem === null) { - throw inventoryError(label, `mobileStaticArchives[${index}] is malformed`); - } - const target = row.slice(0, separator); - const member = safeRelativePath(row.slice(separator + 1), `${label} mobileStaticArchives[${index}]`); - if (!PORTABLE_ID.test(target)) throw inventoryError(label, `mobile static target ${target} is invalid`); - const expected = `mobile-static/${target}/extensions/${metadata.nativeModuleStem}/liboliphaunt_extension_${metadata.nativeModuleStem}.a`; - if (member !== expected) { - throw inventoryError(label, `mobile static member ${member} must be ${expected}`); - } - paths.push(member); - } - const dependencyRows = csv( - properties.get("mobileStaticDependencyArchives"), - `${label} mobileStaticDependencyArchives`, - ); - for (const [index, row] of dependencyRows.entries()) { - const first = row.indexOf(":"); - const second = row.indexOf(":", first + 1); - if (first <= 0 || second <= first + 1) { - throw inventoryError(label, `mobileStaticDependencyArchives[${index}] is malformed`); - } - const target = row.slice(0, first); - const dependency = row.slice(first + 1, second); - const member = safeRelativePath( - row.slice(second + 1), - `${label} mobileStaticDependencyArchives[${index}]`, - ); - if (!PORTABLE_ID.test(target) || !PORTABLE_ID.test(dependency)) { - throw inventoryError(label, `mobile static dependency identity ${target}:${dependency} is invalid`); - } - const prefix = `mobile-static/${target}/dependencies/${dependency}/`; - if (!member.startsWith(prefix) || path.posix.basename(member) !== member.slice(prefix.length)) { - throw inventoryError(label, `mobile static dependency member ${member} is not canonical`); - } - paths.push(member); - } - if (new Set(paths).size !== paths.length) { - throw inventoryError(label, "mobile static archive paths must not repeat"); - } - return paths; -} - -function validateStaticLinkage(properties, metadata, target, label) { - const prefix = properties.get("staticSymbolPrefix"); - if (prefix !== "" && !C_IDENTIFIER.test(prefix)) { - throw inventoryError(label, "staticSymbolPrefix must be empty or a C identifier"); - } - const aliases = csv(properties.get("staticSymbolAliases"), `${label} staticSymbolAliases`); - const sqlSymbols = new Set(); - for (const [index, alias] of aliases.entries()) { - const fields = alias.split(":"); - if (fields.length !== 2 || fields.some((field) => !C_IDENTIFIER.test(field))) { - throw inventoryError(label, `staticSymbolAliases[${index}] must be a C-identifier pair`); - } - if (sqlSymbols.has(fields[0])) { - throw inventoryError(label, `staticSymbolAliases repeats SQL-visible symbol ${fields[0]}`); - } - sqlSymbols.add(fields[0]); - } - if (DESKTOP_NATIVE_TARGETS.has(target) && (prefix !== "" || aliases.length !== 0)) { - throw inventoryError(label, "desktop artifacts must not declare static symbol linkage"); - } - if (metadata.nativeModuleStem === null && (prefix !== "" || aliases.length !== 0)) { - throw inventoryError(label, "SQL-only artifacts must not declare static symbol linkage"); - } -} - -function canonicalLegalContract(metadata, target, label) { - let contract; - try { - const product = extensionProductForSqlName(metadata.sqlName, "extension-artifact-inventory.mjs"); - contract = extensionCarrierLegalContract(product, [metadata.sqlName], { family: "native", target }); - } catch (cause) { - throw inventoryError(label, `cannot resolve canonical legal contract: ${cause.message}`); - } - const members = new Map(); - const add = (member, sha256, source) => { - const prior = members.get(member); - if (prior !== undefined && prior.sha256 !== sha256) { - throw inventoryError(label, `canonical legal member collision at ${member}`); - } - members.set(member, { sha256, source }); - }; - for (const row of releaseNoticeRows({ profile: contract.profile })) { - add( - row.member, - createHash("sha256").update(readFileSync(row.source)).digest("hex"), - row.source, - ); - } - const upstreamFiles = contract.upstreamMembers.flatMap( - (sqlName) => extensionUpstreamLicenseRow(sqlName).files, - ); - const destinations = upstreamFiles.map(({ destination }) => destination).sort(compareText); - if (JSON.stringify(destinations) !== JSON.stringify([...contract.licenseFiles])) { - throw inventoryError(label, "canonical upstream legal files disagree with the carrier contract"); - } - for (const row of upstreamFiles) { - add(`files/${row.destination}`, row.sha256, `${metadata.sqlName}:${row.path}`); - } - return { contract, members }; -} - -/** - * Validate both manifest semantics and the exact leaf inventory of a native extension artifact. - * Returns the runtime `files/` rows used by npm staging. - */ -export function validateExtensionArtifactEntries({ - entries, - metadata: rawMetadata, - target, - nativeRuntimeVersion, - label, -}) { - if (!DESKTOP_NATIVE_TARGETS.has(target)) { - throw inventoryError(label, `native target ${JSON.stringify(target)} is not a canonical desktop target`); - } - if (typeof nativeRuntimeVersion !== "string" || !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(nativeRuntimeVersion)) { - throw inventoryError(label, "native runtime version must be stable SemVer X.Y.Z"); - } - const metadata = normalizeMetadata(rawMetadata, `${label} canonical metadata`); - const manifestEntry = entries.get("manifest.properties"); - if (manifestEntry === undefined) throw inventoryError(label, "is missing manifest.properties"); - const properties = parseExtensionArtifactProperties( - decodeUtf8(manifestEntry.data, `${label} manifest.properties`), - `${label} manifest.properties`, - ); - const legal = canonicalLegalContract(metadata, target, label); - const expectedProperties = new Map([ - ["packageLayout", "oliphaunt-extension-artifact-v1"], - ["pgMajor", "18"], - ["sqlName", metadata.sqlName], - ["createsExtension", metadata.createsExtension ? "yes" : "no"], - ["nativeModuleStem", metadata.nativeModuleStem ?? ""], - ["nativeModuleFile", metadata.nativeModuleStem === null ? "" : `${metadata.nativeModuleStem}${moduleSuffix(target)}`], - ["nativeTarget", target], - ["nativeRuntimeProduct", "liboliphaunt-native"], - ["nativeRuntimeVersion", nativeRuntimeVersion], - ["dependencies", metadata.dependencies.join(",")], - ["dataFiles", metadata.dataFiles.join(",")], - ["extensionSqlFileNames", metadata.extensionSqlFileNames.join(",")], - ["extensionSqlFilePrefixes", metadata.extensionSqlFilePrefixes.join(",")], - ["sharedPreloadLibraries", metadata.sharedPreloadLibraries.join(",")], - ["licenseFiles", legal.contract.licenseFiles.join(",")], - ["licenseProfile", legal.contract.profile], - ["files", "files"], - ]); - for (const [key, expected] of expectedProperties) { - if (properties.get(key) !== expected) { - throw inventoryError( - label, - `manifest ${key} must be ${JSON.stringify(expected)}; got ${JSON.stringify(properties.get(key))}`, - ); - } - } - if (!new Set(["yes", "no"]).has(properties.get("mobilePrebuilt"))) { - throw inventoryError(label, "manifest mobilePrebuilt must be yes or no"); - } - validateStaticLinkage(properties, metadata, target, label); - - const allowed = new Set(["manifest.properties"]); - for (const [member, expected] of legal.members) { - allowed.add(member); - const entry = entries.get(member); - if (entry !== undefined) { - if (entry.mode !== 0o644) { - throw inventoryError(label, `legal member ${member} must have mode 0644`); - } - if (entry.sha256 !== expected.sha256) { - throw inventoryError( - label, - `legal member ${member} does not match canonical bytes from ${expected.source}`, - ); - } - } - } - const extensionPrefix = "files/share/postgresql/extension/"; - let hasControl = false; - let hasInstallSql = false; - const extensionFileNames = []; - for (const name of entries.keys()) { - if (!name.startsWith(extensionPrefix)) continue; - const fileName = name.slice(extensionPrefix.length); - if (fileName.includes("/") || !sqlFileOwned(fileName, metadata)) { - throw inventoryError(label, `contains undeclared extension SQL/control file ${name}`); - } - allowed.add(name); - extensionFileNames.push(fileName); - if (fileName === `${metadata.sqlName}.control`) hasControl = true; - if (isCanonicalExtensionInstallSql(fileName, metadata.sqlName)) hasInstallSql = true; - } - if (metadata.createsExtension && (!hasControl || !hasInstallSql)) { - throw inventoryError(label, `must contain ${metadata.sqlName}.control and canonical base installation SQL`); - } - if (metadata.createsExtension) { - const controlName = `${extensionPrefix}${metadata.sqlName}.control`; - validateExtensionInstallSqlReachability({ - sqlName: metadata.sqlName, - control: decodeUtf8(entries.get(controlName).data, `${label} ${controlName}`), - fileNames: extensionFileNames, - label, - }); - } - for (const dataFile of metadata.dataFiles) { - allowed.add(`files/share/postgresql/${dataFile}`); - } - if (metadata.nativeModuleStem !== null) { - allowed.add(`files/lib/postgresql/${properties.get("nativeModuleFile")}`); - if (DESKTOP_NATIVE_TARGETS.has(target)) { - allowed.add(`files/lib/modules/${properties.get("nativeModuleFile")}`); - } - } - const mobilePaths = declaredMobilePaths(properties, metadata, label); - if ( - DESKTOP_NATIVE_TARGETS.has(target) - && (properties.get("mobilePrebuilt") !== "no" || mobilePaths.length !== 0) - ) { - throw inventoryError(label, "desktop artifacts must not declare mobile prebuilt files"); - } - for (const mobilePath of mobilePaths) { - allowed.add(mobilePath); - } - const actual = [...entries.keys()].sort(compareText); - const expected = [...allowed].sort(compareText); - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - const undeclared = actual.filter((name) => !allowed.has(name)); - const missing = expected.filter((name) => !entries.has(name)); - throw inventoryError( - label, - `leaf inventory mismatch${undeclared.length ? `; undeclared: ${undeclared.join(",")}` : ""}` - + `${missing.length ? `; missing: ${missing.join(",")}` : ""}`, - ); - } - const runtimeFiles = actual - .filter((name) => name.startsWith("files/")) - .map((name) => { - const entry = entries.get(name); - return { - path: name.slice("files/".length), - bytes: entry.bytes, - sha256: entry.sha256, - }; - }); - if (runtimeFiles.some((row) => !SHA256.test(row.sha256))) { - throw inventoryError(label, "computed an invalid runtime file digest"); - } - const legalFiles = [...legal.members.keys()].sort(compareText).map((name) => { - const entry = entries.get(name); - return { - path: name, - bytes: entry.bytes, - sha256: entry.sha256, - }; - }); - return { metadata, properties, runtimeFiles, legalFiles }; -} - -export function validateExtensionArtifactArchive(options) { - const entries = readCanonicalExtensionArtifactArchive(options.file, options.label ?? options.file); - return { - entries, - ...validateExtensionArtifactEntries({ ...options, entries, label: options.label ?? options.file }), - }; -} diff --git a/tools/release/extension-artifact-inventory.test.mjs b/tools/release/extension-artifact-inventory.test.mjs deleted file mode 100644 index b465cc9e5..000000000 --- a/tools/release/extension-artifact-inventory.test.mjs +++ /dev/null @@ -1,1191 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createWriteStream } from "node:fs"; -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import { Readable } from "node:stream"; -import { pipeline } from "node:stream/promises"; -import test from "node:test"; -import { createGzip } from "node:zlib"; - -import { - EXTENSION_ARTIFACT_PROPERTY_KEYS, - parseExtensionArtifactProperties, - validateExtensionArtifactArchive, -} from "./extension-artifact-inventory.mjs"; -import { - EXTENSION_ARTIFACT_ARCHIVE_POLICY, - validateExtensionArtifactArchivePlan, -} from "./extension-artifact-archive-policy.mjs"; -import { canonicalGzipSync } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - extensionCarrierLegalContract, - stageExtensionUpstreamLicenses, -} from "./extension-upstream-licenses.mjs"; -import { extensionProductForSqlName } from "./release-artifact-targets.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; -import { elfFixture } from "../test/release-fixture-utils.mjs"; - -const REPOSITORY = path.resolve(import.meta.dirname, "../.."); - -function writeString(buffer, offset, length, value) { - const bytes = Buffer.from(value); - assert.ok(bytes.length <= length); - bytes.copy(buffer, offset); -} - -function writeOctal(buffer, offset, length, value) { - writeString(buffer, offset, length, `${value.toString(8).padStart(length - 1, "0")}\0`); -} - -function tarPathParts(archiveName) { - if (Buffer.byteLength(archiveName) <= 100) return { name: archiveName, prefix: "" }; - const parts = archiveName.split("/"); - for (let index = 1; index < parts.length; index += 1) { - const prefix = parts.slice(0, index).join("/"); - const name = parts.slice(index).join("/"); - if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) { - return { name, prefix }; - } - } - throw new Error(`test archive path is too long for ustar: ${archiveName}`); -} - -function tarHeader(archiveName, bytes, mode = 0o644) { - const header = Buffer.alloc(512); - const { name, prefix } = tarPathParts(archiveName); - writeString(header, 0, 100, name); - writeOctal(header, 100, 8, mode); - writeOctal(header, 108, 8, 0); - writeOctal(header, 116, 8, 0); - writeOctal(header, 124, 12, bytes); - writeOctal(header, 136, 12, 0); - header.fill(0x20, 148, 156); - writeString(header, 156, 1, "0"); - writeString(header, 257, 6, "ustar\0"); - writeString(header, 263, 2, "00"); - writeString(header, 265, 32, "root"); - writeString(header, 297, 32, "root"); - writeString(header, 345, 155, prefix); - const checksum = header.reduce((sum, byte) => sum + byte, 0); - writeString(header, 148, 8, `${checksum.toString(8).padStart(6, "0")}\0 `); - return header; -} - -function refreshChecksum(header) { - header.fill(0x20, 148, 156); - const checksum = header.reduce((sum, byte) => sum + byte, 0); - writeString(header, 148, 8, `${checksum.toString(8).padStart(6, "0")}\0 `); -} - -function rewriteTarPath(header, { name, prefix }) { - header.fill(0, 0, 100); - header.fill(0, 345, 500); - writeString(header, 0, 100, name); - writeString(header, 345, 155, prefix); -} - -function canonicalArchive(entries, { mutateHeader = undefined, trailingZeroBlocks = 2 } = {}) { - const chunks = []; - for (const [index, [name, raw]] of [...entries].sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).entries()) { - const data = Buffer.isBuffer(raw) ? raw : Buffer.from(raw); - const header = tarHeader(name, data.length, name.includes("/lib/postgresql/") ? 0o755 : 0o644); - mutateHeader?.(header, name, index); - if (mutateHeader !== undefined) refreshChecksum(header); - chunks.push(header); - chunks.push(data); - if (data.length % 512 !== 0) chunks.push(Buffer.alloc(512 - (data.length % 512))); - } - chunks.push(Buffer.alloc(512 * trailingZeroBlocks)); - return canonicalGzipSync(Buffer.concat(chunks)); -} - -function legalContract(sqlName, target) { - return extensionCarrierLegalContract( - extensionProductForSqlName(sqlName, "extension-artifact-inventory.test.mjs"), - [sqlName], - { family: "native", target }, - ); -} - -function manifest(overrides = {}) { - const sqlName = overrides.sqlName ?? "pgtap"; - const nativeTarget = overrides.nativeTarget ?? "linux-x64-gnu"; - const legal = legalContract(sqlName, nativeTarget); - const values = { - packageLayout: "oliphaunt-extension-artifact-v1", - pgMajor: "18", - sqlName, - createsExtension: "yes", - nativeModuleStem: "", - nativeModuleFile: "", - nativeTarget, - nativeRuntimeProduct: "liboliphaunt-native", - nativeRuntimeVersion: "1.2.3", - dependencies: "", - dataFiles: "", - extensionSqlFileNames: "uninstall_pgtap.sql", - extensionSqlFilePrefixes: "pgtap-core,pgtap-schema", - sharedPreloadLibraries: "", - mobilePrebuilt: "no", - mobileStaticArchives: "", - mobileStaticDependencyArchives: "", - staticSymbolPrefix: "", - staticSymbolAliases: "", - licenseFiles: legal.licenseFiles.join(","), - licenseProfile: legal.profile, - files: "files", - ...overrides, - }; - return `${EXTENSION_ARTIFACT_PROPERTY_KEYS.map((key) => `${key}=${values[key]}`).join("\n")}\n`; -} - -async function canonicalLegalEntries(root, sqlName, target = "linux-x64-gnu") { - const contract = legalContract(sqlName, target); - const stage = await fs.mkdtemp(path.join(root, `legal-${sqlName}-`)); - try { - stageReleaseNotices(stage, { profile: contract.profile }); - stageExtensionUpstreamLicenses(sqlName, path.join(stage, "files")); - const rows = []; - const visit = async (directory) => { - const entries = await fs.readdir(directory, { withFileTypes: true }); - entries.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0); - for (const entry of entries) { - const file = path.join(directory, entry.name); - if (entry.isDirectory()) { - await visit(file); - } else { - assert.equal(entry.isFile(), true, `legal fixture contains a non-file entry: ${file}`); - rows.push([ - path.relative(stage, file).split(path.sep).join("/"), - await fs.readFile(file), - ]); - } - } - }; - await visit(stage); - return new Map(rows); - } finally { - await fs.rm(stage, { recursive: true, force: true }); - } -} - -const pgtapMetadata = { - sqlName: "pgtap", - createsExtension: true, - nativeModuleStem: null, - dependencies: [], - dataFiles: [], - extensionSqlFileNames: ["uninstall_pgtap.sql"], - extensionSqlFilePrefixes: ["pgtap-core", "pgtap-schema"], - sharedPreloadLibraries: [], -}; - -async function writeArchive(root, name, entries, options = undefined) { - const file = path.join(root, name); - await fs.writeFile(file, canonicalArchive(entries, options)); - return file; -} - -async function expectArchiveFailure(root, name, entries, metadata, pattern) { - const file = await writeArchive(root, name, entries); - assert.throws( - () => validateExtensionArtifactArchive({ - file, - metadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: name, - }), - pattern, - ); -} - -async function main() { - assert.deepEqual(EXTENSION_ARTIFACT_ARCHIVE_POLICY, { - maxCompressedBytes: 128 * 1024 * 1024, - maxExpandedBytes: 512 * 1024 * 1024, - maxMemberBytes: 256 * 1024 * 1024, - maxMembers: 4096, - }); - const observedAndroidPostgisMembers = [154_827_564, 110_259_522, 80_534_608]; - observedAndroidPostgisMembers.length = 27; - observedAndroidPostgisMembers.fill(0, 3); - const observedAndroidPostgisExpanded = validateExtensionArtifactArchivePlan( - observedAndroidPostgisMembers.map((bytes, index) => ({ name: `member-${index}`, bytes })), - "observed Android ARM64 PostGIS artifact", - ); - assert.ok(64_676_748 <= EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxCompressedBytes); - assert.ok(observedAndroidPostgisExpanded <= EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxExpandedBytes); - - const packagerSource = await fs.readFile( - path.join( - REPOSITORY, - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - ), - "utf8", - ); - assert.doesNotMatch( - packagerSource, - /localeCompare/u, - "native extension carrier ordering must be ordinal and locale-independent", - ); - assert.match( - packagerSource, - /compareText\(left[.]target, right[.]target\)[\s\S]*compareText\(left[.]name, right[.]name\)/u, - "mobile static dependency metadata must use the ordinal carrier comparator", - ); - const root = await fs.realpath(await fs.mkdtemp(path.join(os.tmpdir(), "oliphaunt-extension-inventory-"))); - try { - const pgtapLegal = await canonicalLegalEntries(root, "pgtap"); - const legitimate = new Map([ - ["manifest.properties", manifest()], - ["files/share/postgresql/extension/pgtap--1.3.5.sql", "install"], - ["files/share/postgresql/extension/pgtap-core--fixture.sql", "owned prefix"], - ["files/share/postgresql/extension/pgtap.control", "default_version = '1.3.5'\n"], - ["files/share/postgresql/extension/uninstall_pgtap.sql", "owned exact"], - ...pgtapLegal, - ]); - const validFile = await writeArchive(root, "legitimate.tar.gz", legitimate); - assert.equal((await fs.readFile(validFile)).subarray(0, 10).toString("hex"), "1f8b0800000000000003"); - const validated = validateExtensionArtifactArchive({ - file: validFile, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "legitimate", - }); - assert.deepEqual( - validated.legalFiles.map(({ path: member }) => member), - [...pgtapLegal.keys()].sort(), - ); - assert.equal(validated.runtimeFiles.length, 4 + legalContract("pgtap", "linux-x64-gnu").licenseFiles.length); - - const pgtapUpstreamLegalMember = `files/${legalContract( - "pgtap", - "linux-x64-gnu", - ).licenseFiles[0]}`; - assert.equal(pgtapLegal.has(pgtapUpstreamLegalMember), true); - for (const [caseName, member] of [ - ["root", "LICENSE"], - ["upstream", pgtapUpstreamLegalMember], - ]) { - const missingLegal = new Map(legitimate); - missingLegal.delete(member); - await expectArchiveFailure( - root, - `missing-${caseName}-legal.tar.gz`, - missingLegal, - pgtapMetadata, - new RegExp(`missing: ${member.replaceAll("/", "\\/").replaceAll(".", "\\.")}`, "u"), - ); - - const mutatedLegal = new Map(legitimate); - mutatedLegal.set(member, `mutated ${caseName} legal bytes`); - await expectArchiveFailure( - root, - `mutated-${caseName}-legal.tar.gz`, - mutatedLegal, - pgtapMetadata, - /legal member .* does not match canonical bytes/u, - ); - - const executableLegalFile = await writeArchive( - root, - `executable-${caseName}-legal.tar.gz`, - legitimate, - { - mutateHeader(header, name) { - if (name === member) writeOctal(header, 100, 8, 0o755); - }, - }, - ); - assert.throws( - () => validateExtensionArtifactArchive({ - file: executableLegalFile, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: `executable ${caseName} legal member`, - }), - new RegExp(`legal member ${member.replaceAll("/", "\\/").replaceAll(".", "\\.")} must have mode 0644`, "u"), - ); - } - - const unexpectedLegal = new Map(legitimate); - unexpectedLegal.set("THIRD_PARTY_LICENSES/undeclared.txt", "not contracted"); - await expectArchiveFailure( - root, - "unexpected-legal.tar.gz", - unexpectedLegal, - pgtapMetadata, - /undeclared: THIRD_PARTY_LICENSES\/undeclared[.]txt/u, - ); - - for (const [name, overrides, pattern] of [ - ["license-files", { licenseFiles: "" }, /manifest licenseFiles must be/u], - ["license-profile", { licenseProfile: "contrib-native" }, /manifest licenseProfile must be/u], - ]) { - const driftedLegalProperty = new Map(legitimate); - driftedLegalProperty.set("manifest.properties", manifest(overrides)); - await expectArchiveFailure( - root, - `drifted-${name}.tar.gz`, - driftedLegalProperty, - pgtapMetadata, - pattern, - ); - } - assert.throws( - () => parseExtensionArtifactProperties( - manifest().replace( - /licenseFiles=([^\n]*)\nlicenseProfile=([^\n]*)\n/u, - "licenseProfile=$2\nlicenseFiles=$1\n", - ), - "reordered legal properties", - ), - /properties must use the canonical field order/u, - ); - - const carrierSymlink = path.join(root, "carrier-symlink.tar.gz"); - await fs.symlink(validFile, carrierSymlink); - assert.throws( - () => validateExtensionArtifactArchive({ - file: carrierSymlink, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "carrier symlink", - }), - /regular non-symlink file/u, - ); - - const extraPaddingFile = await writeArchive(root, "extra-zero-padding.tar.gz", legitimate, { - trailingZeroBlocks: 3, - }); - assert.throws( - () => validateExtensionArtifactArchive({ - file: extraPaddingFile, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "extra zero padding", - }), - /tar end marker or trailing padding is not canonical/u, - ); - - const shortAlternateSplit = await writeArchive( - root, - "short-alternate-ustar-split.tar.gz", - legitimate, - { - mutateHeader(header, name) { - if (name === "files/share/postgresql/extension/pgtap.control") { - rewriteTarPath(header, { - prefix: "files", - name: "share/postgresql/extension/pgtap.control", - }); - } - }, - }, - ); - assert.throws( - () => validateExtensionArtifactArchive({ - file: shortAlternateSplit, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "short alternate ustar split", - }), - /canonical ustar name\/prefix split/u, - ); - - const longMember = `files/share/postgresql/data/${"a".repeat(40)}/${"b".repeat(40)}/${"c".repeat(40)}.bin`; - const longAlternateSplit = await writeArchive( - root, - "long-alternate-ustar-split.tar.gz", - new Map([...legitimate, [longMember, "long path"]]), - { - mutateHeader(header, name) { - if (name !== longMember) return; - const parts = name.split("/"); - const validSplits = []; - for (let index = 1; index < parts.length; index += 1) { - const prefix = parts.slice(0, index).join("/"); - const memberName = parts.slice(index).join("/"); - if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(memberName) <= 100) { - validSplits.push({ prefix, name: memberName }); - } - } - assert.ok(validSplits.length > 1); - rewriteTarPath(header, validSplits[1]); - }, - }, - ); - assert.throws( - () => validateExtensionArtifactArchive({ - file: longAlternateSplit, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "long alternate ustar split", - }), - /canonical ustar name\/prefix split/u, - ); - - const producerRuntime = path.join(root, "producer-runtime"); - const producerExtensionDir = path.join(producerRuntime, "share/postgresql/extension"); - await fs.mkdir(producerExtensionDir, { recursive: true }); - for (const [name, bytes] of [ - ["pgtap.control", "default_version = '1.3.5'\n"], - ["pgtap--1.3.5.sql", "install"], - ["uninstall_pgtap.sql", "owned exact"], - ["pgtap-core--fixture.sql", "owned prefix"], - ["pgtap-core-evil.control", "must be filtered"], - ["foreign.control", "must be filtered"], - ]) { - await fs.writeFile(path.join(producerExtensionDir, name), bytes); - } - const producerArchive = path.join(root, "producer-contract.tar.gz"); - const producer = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerRuntime, - "--sql-name", "pgtap", - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--format", "tar-gz", - "--output", producerArchive, - "--force", - ], - { cwd: REPOSITORY, encoding: "utf8" }, - ); - assert.equal(producer.status, 0, producer.stderr || producer.stdout); - assert.equal( - (await fs.readFile(producerArchive)).subarray(0, 10).toString("hex"), - "1f8b0800000000000003", - ); - const producerValidated = validateExtensionArtifactArchive({ - file: producerArchive, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "real producer contract", - }); - assert.equal(producerValidated.entries.has( - "files/share/postgresql/extension/pgtap-core-evil.control", - ), false); - assert.equal(producerValidated.entries.has( - "files/share/postgresql/extension/foreign.control", - ), false); - - await fs.writeFile( - path.join(producerExtensionDir, "pgtap.control"), - "default_version = '1.3.4'\n", - ); - const sourceSkewedProducer = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerRuntime, - "--sql-name", "pgtap", - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--format", "tar-gz", - "--output", path.join(root, "producer-source-version-skew.tar.gz"), - "--force", - ], - { cwd: REPOSITORY, encoding: "utf8" }, - ); - assert.notEqual(sourceSkewedProducer.status, 0); - assert.match( - sourceSkewedProducer.stderr || sourceSkewedProducer.stdout, - /pgtap[.]control default_version '1[.]3[.]4' does not match source-owned catalog version '1[.]3[.]5'/u, - ); - await fs.writeFile( - path.join(producerExtensionDir, "pgtap.control"), - "default_version = '1.3.5'\n", - ); - - await fs.rm(path.join(producerExtensionDir, "pgtap--1.3.5.sql")); - for (const [name, bytes] of [ - ["pgtap--1.3.3.sql", "older install"], - ["pgtap--1.3.3--1.3.4.sql", "first update"], - ["pgtap--1.3.4--1.3.5.sql", "default update"], - ]) { - await fs.writeFile(path.join(producerExtensionDir, name), bytes); - } - const updateChainArchive = path.join(root, "producer-update-chain.tar.gz"); - const updateChainProducer = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerRuntime, - "--sql-name", "pgtap", - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--format", "tar-gz", - "--output", updateChainArchive, - "--force", - ], - { cwd: REPOSITORY, encoding: "utf8" }, - ); - assert.equal(updateChainProducer.status, 0, updateChainProducer.stderr || updateChainProducer.stdout); - const updateChainValidated = validateExtensionArtifactArchive({ - file: updateChainArchive, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "reachable default through packaged updates", - }); - for (const name of [ - "pgtap--1.3.3.sql", - "pgtap--1.3.3--1.3.4.sql", - "pgtap--1.3.4--1.3.5.sql", - ]) { - assert.equal( - updateChainValidated.entries.has(`files/share/postgresql/extension/${name}`), - true, - `producer omitted ${name}`, - ); - } - - await fs.rm(path.join(producerExtensionDir, "pgtap--1.3.4--1.3.5.sql")); - const disconnectedUpdateProducer = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerRuntime, - "--sql-name", "pgtap", - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--format", "tar-gz", - "--output", path.join(root, "producer-disconnected-update.tar.gz"), - "--force", - ], - { cwd: REPOSITORY, encoding: "utf8" }, - ); - assert.notEqual(disconnectedUpdateProducer.status, 0); - assert.match( - disconnectedUpdateProducer.stderr || disconnectedUpdateProducer.stdout, - /default_version '1[.]3[.]5' has no canonical installation script or update path/u, - ); - for (const name of ["pgtap--1.3.3.sql", "pgtap--1.3.3--1.3.4.sql"]) { - await fs.rm(path.join(producerExtensionDir, name)); - } - await fs.writeFile(path.join(producerExtensionDir, "pgtap--1.3.5.sql"), "install"); - - await fs.rm(path.join(producerExtensionDir, "pgtap--1.3.5.sql")); - await fs.writeFile( - path.join(producerExtensionDir, "pgtap--1.3.4--1.3.5.sql"), - "transition only", - ); - const ancillaryOnlyProducer = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerRuntime, - "--sql-name", "pgtap", - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--format", "tar-gz", - "--output", path.join(root, "producer-ancillary-only.tar.gz"), - "--force", - ], - { cwd: REPOSITORY, encoding: "utf8" }, - ); - assert.notEqual(ancillaryOnlyProducer.status, 0); - assert.match( - ancillaryOnlyProducer.stderr || ancillaryOnlyProducer.stdout, - /control file and canonical base install SQL/u, - ); - await fs.rm(path.join(producerExtensionDir, "pgtap--1.3.4--1.3.5.sql")); - await fs.writeFile( - path.join(producerExtensionDir, "pgtap--release.sql"), - "letter-leading version is not a canonical base install", - ); - const letterLeadingProducer = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerRuntime, - "--sql-name", "pgtap", - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--format", "tar-gz", - "--output", path.join(root, "producer-letter-leading-only.tar.gz"), - "--force", - ], - { cwd: REPOSITORY, encoding: "utf8" }, - ); - assert.notEqual(letterLeadingProducer.status, 0); - assert.match( - letterLeadingProducer.stderr || letterLeadingProducer.stdout, - /control file and canonical base install SQL/u, - ); - await fs.rm(path.join(producerExtensionDir, "pgtap--release.sql")); - await fs.writeFile(path.join(producerExtensionDir, "pgtap--1.3.5.sql"), "install"); - - const streamedDataFiles = [ - "oliphaunt-streaming/a.bin", - "oliphaunt-streaming/b.bin", - "oliphaunt-streaming/c.bin", - ]; - for (const [index, dataFile] of streamedDataFiles.entries()) { - const destination = path.join(producerRuntime, "share/postgresql", dataFile); - await fs.mkdir(path.dirname(destination), { recursive: true }); - await fs.writeFile(destination, Buffer.alloc(24 * 1024 * 1024, index + 1)); - } - const streamedProducerArchive = path.join(root, "producer-expanded-over-64mib.tar.gz"); - const streamedProducer = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerRuntime, - "--sql-name", "pgtap", - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--data-files", streamedDataFiles.join(","), - "--format", "tar-gz", - "--output", streamedProducerArchive, - "--force", - ], - { cwd: REPOSITORY, encoding: "utf8" }, - ); - assert.equal(streamedProducer.status, 0, streamedProducer.stderr || streamedProducer.stdout); - const streamedValidated = validateExtensionArtifactArchive({ - file: streamedProducerArchive, - metadata: { ...pgtapMetadata, dataFiles: streamedDataFiles }, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "current producer expanded over 64 MiB", - }); - assert.ok( - streamedValidated.runtimeFiles.reduce((total, row) => total + row.bytes, 0) - > 64 * 1024 * 1024, - ); - - const staleEighteenFieldManifest = manifest() - .replace("extensionSqlFileNames=uninstall_pgtap.sql\n", "") - .replace("extensionSqlFilePrefixes=pgtap-core,pgtap-schema\n", ""); - assert.throws( - () => parseExtensionArtifactProperties(staleEighteenFieldManifest, "stale leaf manifest"), - /property fields must be exactly/u, - ); - for (const [field, value] of [ - ["extensionSqlFileNames", "foreign.sql"], - ["extensionSqlFilePrefixes", "foreign-prefix"], - ]) { - const drifted = new Map(legitimate); - drifted.set("manifest.properties", manifest({ [field]: value })); - await expectArchiveFailure( - root, - `frozen-${field}-drift.tar.gz`, - drifted, - pgtapMetadata, - new RegExp(`manifest ${field} must be`, "u"), - ); - } - - const contaminated = new Map(legitimate); - contaminated.set("files/share/postgresql/extension/foreign.control", "undeclared"); - await expectArchiveFailure( - root, - "recomputed-contaminated.tar.gz", - contaminated, - pgtapMetadata, - /undeclared extension SQL\/control file.*foreign\.control/u, - ); - - const prefixedControl = new Map(legitimate); - prefixedControl.set("files/share/postgresql/extension/pgtap-core-evil.control", "undeclared"); - await expectArchiveFailure( - root, - "prefixed-control.tar.gz", - prefixedControl, - pgtapMetadata, - /pgtap-core-evil\.control/u, - ); - - const ancillaryOnly = new Map(legitimate); - ancillaryOnly.delete("files/share/postgresql/extension/pgtap--1.3.5.sql"); - ancillaryOnly.set( - "files/share/postgresql/extension/pgtap--1.3.4--1.3.5.sql", - "transition SQL is owned but is not a base install", - ); - await expectArchiveFailure( - root, - "ancillary-only.tar.gz", - ancillaryOnly, - pgtapMetadata, - /control and canonical base installation SQL/u, - ); - - const disconnectedDefault = new Map(legitimate); - disconnectedDefault.delete("files/share/postgresql/extension/pgtap--1.3.5.sql"); - disconnectedDefault.set("files/share/postgresql/extension/pgtap--1.3.3.sql", "older install"); - disconnectedDefault.set( - "files/share/postgresql/extension/pgtap--1.3.3--1.3.4.sql", - "incomplete update path", - ); - await expectArchiveFailure( - root, - "disconnected-default.tar.gz", - disconnectedDefault, - pgtapMetadata, - /default_version '1[.]3[.]5' has no canonical installation script or update path/u, - ); - - const plainSqlOnly = new Map(legitimate); - plainSqlOnly.delete("files/share/postgresql/extension/pgtap--1.3.5.sql"); - plainSqlOnly.set( - "files/share/postgresql/extension/pgtap.sql", - "PostgreSQL 18 does not discover this as a versioned install script", - ); - await expectArchiveFailure( - root, - "plain-sql-only.tar.gz", - plainSqlOnly, - pgtapMetadata, - /control and canonical base installation SQL/u, - ); - - const letterLeadingOnly = new Map(legitimate); - letterLeadingOnly.delete("files/share/postgresql/extension/pgtap--1.3.5.sql"); - letterLeadingOnly.set( - "files/share/postgresql/extension/pgtap--release.sql", - "letter-leading version is owned but is not a base install", - ); - await expectArchiveFailure( - root, - "letter-leading-only.tar.gz", - letterLeadingOnly, - pgtapMetadata, - /control and canonical base installation SQL/u, - ); - - const autoExplainMetadata = { - ...pgtapMetadata, - sqlName: "auto_explain", - createsExtension: false, - nativeModuleStem: "auto_explain", - extensionSqlFileNames: [], - extensionSqlFilePrefixes: [], - }; - const moduleFile = "auto_explain.so"; - const producerAutoRuntime = path.join(root, "producer-auto-runtime"); - const producerAutoEmbedded = path.join(root, "producer-auto-embedded"); - const stripShim = path.join(root, "no-op-elf-strip"); - await fs.mkdir(path.join(producerAutoRuntime, "lib/postgresql"), { recursive: true }); - await fs.mkdir(producerAutoEmbedded, { recursive: true }); - await fs.writeFile( - path.join(producerAutoRuntime, "lib/postgresql", moduleFile), - elfFixture({ machine: 62 }), - ); - await fs.writeFile( - path.join(producerAutoEmbedded, moduleFile), - elfFixture({ machine: 62, requiredVersions: ["GLIBC_2.17"] }), - ); - await fs.chmod(path.join(producerAutoRuntime, "lib/postgresql", moduleFile), 0o755); - await fs.chmod(path.join(producerAutoEmbedded, moduleFile), 0o755); - await fs.writeFile(stripShim, "#!/usr/bin/env sh\nexit 0\n"); - await fs.chmod(stripShim, 0o755); - const producerAutoArchive = path.join(root, "producer-auto-explain.tar.gz"); - const producerAuto = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerAutoRuntime, - "--embedded-module-root", producerAutoEmbedded, - "--sql-name", "auto_explain", - "--creates-extension", "false", - "--native-module-stem", "auto_explain", - "--native-module-file", moduleFile, - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--stage-root", path.join(root, "producer-stage"), - "--format", "tar-gz", - "--output", producerAutoArchive, - "--force", - ], - { - cwd: REPOSITORY, - encoding: "utf8", - env: { ...process.env, OLIPHAUNT_ELF_STRIP: stripShim }, - }, - ); - assert.equal(producerAuto.status, 0, producerAuto.stderr || producerAuto.stdout); - const producerAutoValidated = validateExtensionArtifactArchive({ - file: producerAutoArchive, - metadata: autoExplainMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "dual-profile producer contract", - }); - const serverMember = `files/lib/postgresql/${moduleFile}`; - const embeddedMember = `files/lib/modules/${moduleFile}`; - assert.equal(producerAutoValidated.entries.has(serverMember), true); - assert.equal(producerAutoValidated.entries.has(embeddedMember), true); - assert.notEqual( - producerAutoValidated.entries.get(serverMember).sha256, - producerAutoValidated.entries.get(embeddedMember).sha256, - "normal and embedded module byte identities must remain independently frozen", - ); - - const missingEmbeddedRootProducer = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerAutoRuntime, - "--sql-name", "auto_explain", - "--creates-extension", "false", - "--native-module-stem", "auto_explain", - "--native-module-file", moduleFile, - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--output", path.join(root, "producer-auto-explain-missing-embedded"), - "--force", - ], - { cwd: REPOSITORY, encoding: "utf8" }, - ); - assert.notEqual(missingEmbeddedRootProducer.status, 0); - assert.match( - missingEmbeddedRootProducer.stderr || missingEmbeddedRootProducer.stdout, - /desktop prebuilt extension artifacts with nativeModuleStem require --embedded-module-root/u, - ); - const sqlOnlyEmbeddedRootProducer = spawnSync( - path.join(REPOSITORY, "tools/dev/bun.sh"), - [ - "src/extensions/artifacts/native/tools/extension-artifact-packager.mjs", - "create-artifact", - "--runtime", producerRuntime, - "--embedded-module-root", producerAutoEmbedded, - "--sql-name", "pgtap", - "--native-target", "linux-x64-gnu", - "--native-runtime-product", "liboliphaunt-native", - "--native-runtime-version", "1.2.3", - "--output", path.join(root, "producer-pgtap-unexpected-embedded"), - "--force", - ], - { cwd: REPOSITORY, encoding: "utf8" }, - ); - assert.notEqual(sqlOnlyEmbeddedRootProducer.status, 0); - assert.match( - sqlOnlyEmbeddedRootProducer.stderr || sqlOnlyEmbeddedRootProducer.stdout, - /--embedded-module-root is only valid for desktop native-module extension artifacts/u, - ); - const autoExplain = new Map([ - ["manifest.properties", manifest({ - sqlName: "auto_explain", - createsExtension: "no", - nativeModuleStem: "auto_explain", - nativeModuleFile: "auto_explain.so", - extensionSqlFileNames: "", - extensionSqlFilePrefixes: "", - })], - ["files/lib/postgresql/auto_explain.so", "module"], - ["files/share/postgresql/extension/auto_explain.control", "undeclared"], - ]); - await expectArchiveFailure( - root, - "load-only-control.tar.gz", - autoExplain, - autoExplainMetadata, - /auto_explain\.control/u, - ); - - const postgisMetadata = { - sqlName: "postgis", - createsExtension: true, - nativeModuleStem: "postgis-3", - dependencies: [], - dataFiles: [ - "contrib/postgis-3.6/legacy.sql", - "contrib/postgis-3.6/legacy_gist.sql", - "contrib/postgis-3.6/legacy_minimal.sql", - "contrib/postgis-3.6/postgis.sql", - "contrib/postgis-3.6/postgis_upgrade.sql", - "contrib/postgis-3.6/spatial_ref_sys.sql", - "contrib/postgis-3.6/uninstall_legacy.sql", - "contrib/postgis-3.6/uninstall_postgis.sql", - "proj/proj.db", - ], - extensionSqlFileNames: [], - extensionSqlFilePrefixes: ["postgis_comments"], - sharedPreloadLibraries: [], - }; - const postgisLegal = await canonicalLegalEntries(root, "postgis"); - const postgis = new Map([ - ["manifest.properties", manifest({ - sqlName: "postgis", - nativeModuleStem: "postgis-3", - nativeModuleFile: "postgis-3.so", - dataFiles: postgisMetadata.dataFiles.join(","), - extensionSqlFileNames: postgisMetadata.extensionSqlFileNames.join(","), - extensionSqlFilePrefixes: postgisMetadata.extensionSqlFilePrefixes.join(","), - })], - ["files/lib/postgresql/postgis-3.so", "module"], - ["files/lib/modules/postgis-3.so", "embedded module"], - ["files/share/postgresql/extension/postgis--3.6.1--3.6.2.sql", "upgrade"], - ["files/share/postgresql/extension/postgis--3.6.2--3.6.3.sql", "upgrade"], - ["files/share/postgresql/extension/postgis--3.6.3.sql", "install"], - ["files/share/postgresql/extension/postgis.control", "default_version = '3.6.3'\n"], - ...postgisMetadata.dataFiles.map((dataFile) => [ - `files/share/postgresql/${dataFile}`, - `declared data ${dataFile}`, - ]), - ...postgisLegal, - ]); - const postgisFile = await writeArchive(root, "postgis-legitimate.tar.gz", postgis); - const validatedPostgis = validateExtensionArtifactArchive({ - file: postgisFile, - metadata: postgisMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "postgis legitimate", - }); - assert.equal( - validatedPostgis.runtimeFiles.length, - [...postgis.keys()].filter((member) => member.startsWith("files/")).length, - ); - assert.deepEqual( - validatedPostgis.legalFiles.map(({ path: member }) => member), - [...postgisLegal.keys()].sort(), - ); - - const missingEmbeddedPostgis = new Map(postgis); - missingEmbeddedPostgis.delete("files/lib/modules/postgis-3.so"); - await expectArchiveFailure( - root, - "postgis-missing-embedded-module.tar.gz", - missingEmbeddedPostgis, - postgisMetadata, - /missing: files\/lib\/modules\/postgis-3[.]so/u, - ); - - for (const [name, text, pattern] of [ - ["bom", `\uFEFF${manifest()}`, /canonical NFC UTF-8/u], - ["crlf", manifest().replaceAll("\n", "\r\n"), /canonical NFC UTF-8/u], - ["blank", manifest().replace("pgMajor=18\n", "pgMajor=18\n\n"), /internal blank line/u], - ["duplicate", manifest().replace("pgMajor=18\n", "pgMajor=18\npgMajor=18\n"), /repeats property pgMajor/u], - ]) { - assert.throws( - () => parseExtensionArtifactProperties(text, name), - pattern, - ); - } - - const invalidUtf8 = new Map(legitimate); - invalidUtf8.set("manifest.properties", Buffer.concat([Buffer.from(manifest().slice(0, -1)), Buffer.from([0xff, 0x0a])])); - await expectArchiveFailure( - root, - "invalid-utf8.tar.gz", - invalidUtf8, - pgtapMetadata, - /invalid UTF-8/u, - ); - const bomManifest = new Map(legitimate); - bomManifest.set("manifest.properties", Buffer.concat([ - Buffer.from([0xef, 0xbb, 0xbf]), - Buffer.from(manifest()), - ])); - await expectArchiveFailure( - root, - "bom-manifest.tar.gz", - bomManifest, - pgtapMetadata, - /canonical NFC UTF-8/u, - ); - - const caseCollision = new Map(legitimate); - caseCollision.set("files/share/postgresql/extension/Pgtap.control", "collision"); - await expectArchiveFailure( - root, - "case-collision.tar.gz", - caseCollision, - pgtapMetadata, - /case\/NFC-colliding members/u, - ); - - for (const [name, memberPath, pattern] of [ - ["backslash-path", "files\\share/postgresql/extension/evil", /without backslashes/u], - ["traversal-path", "../evil", /canonical relative path/u], - ["non-nfc-path", "files/share/postgresql/extension/pgta\u0065\u0301.sql", /NFC UTF-8/u], - ]) { - const entries = new Map(legitimate); - entries.set(memberPath, "unsafe"); - await expectArchiveFailure(root, `${name}.tar.gz`, entries, pgtapMetadata, pattern); - } - - const duplicateMembers = [...legitimate, [ - "files/share/postgresql/extension/pgtap.control", - "duplicate", - ]]; - await expectArchiveFailure( - root, - "duplicate-member.tar.gz", - duplicateMembers, - pgtapMetadata, - /duplicate member.*pgtap\.control/u, - ); - - const symlinkFile = await writeArchive(root, "symlink-type.tar.gz", legitimate, { - mutateHeader(header, _name, index) { - if (index === 0) header[156] = "2".charCodeAt(0); - }, - }); - assert.throws( - () => validateExtensionArtifactArchive({ - file: symlinkFile, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "symlink type", - }), - /must be a regular file/u, - ); - - const invalidHeader = Buffer.from(await fs.readFile(validFile)); - invalidHeader[9] = 0x13; - const invalidHeaderFile = path.join(root, "invalid-gzip-header.tar.gz"); - await fs.writeFile(invalidHeaderFile, invalidHeader); - assert.throws( - () => validateExtensionArtifactArchive({ - file: invalidHeaderFile, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "invalid gzip header", - }), - /canonical cross-platform gzip header/u, - ); - - const invalidAlias = new Map(legitimate); - invalidAlias.set("manifest.properties", manifest({ staticSymbolAliases: "sql:not-valid!" })); - await expectArchiveFailure( - root, - "invalid-alias.tar.gz", - invalidAlias, - pgtapMetadata, - /C-identifier pair/u, - ); - const duplicateAlias = new Map(legitimate); - duplicateAlias.set( - "manifest.properties", - manifest({ staticSymbolAliases: "sql_symbol:linked_one,sql_symbol:linked_two" }), - ); - await expectArchiveFailure( - root, - "duplicate-alias.tar.gz", - duplicateAlias, - pgtapMetadata, - /repeats SQL-visible symbol sql_symbol/u, - ); - - const oversizedMemberName = "files/share/postgresql/extension/pgtap--oversized.sql"; - const oversizedMember = new Map(legitimate); - oversizedMember.set(oversizedMemberName, "declared-size-only"); - const oversizedMemberFile = await writeArchive( - root, - "oversized-member.tar.gz", - oversizedMember, - { - mutateHeader(header, name) { - if (name === oversizedMemberName) { - writeOctal( - header, - 124, - 12, - EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes + 1, - ); - } - }, - }, - ); - assert.throws( - () => validateExtensionArtifactArchive({ - file: oversizedMemberFile, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "oversized member", - }), - /member .* exceeds 268435456 bytes/u, - ); - - assert.throws( - () => validateExtensionArtifactArchivePlan([ - { name: "one", bytes: EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes }, - { name: "two", bytes: EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxMemberBytes }, - ]), - /expands beyond 536870912 bytes/u, - ); - - const excessiveMembers = new Map([["manifest.properties", manifest()]]); - for (let index = 0; index < 4097; index += 1) { - excessiveMembers.set( - `files/share/postgresql/extension/pgtap--${String(index).padStart(4, "0")}.sql`, - "x", - ); - } - await expectArchiveFailure( - root, - "excessive-members.tar.gz", - excessiveMembers, - pgtapMetadata, - /more than 4096 members/u, - ); - - const unbounded = path.join(root, "expanded-bomb.tar.gz"); - async function* oversizedZeros() { - const chunk = Buffer.alloc(1024 * 1024); - const chunks = EXTENSION_ARTIFACT_ARCHIVE_POLICY.maxExpandedBytes / chunk.length + 1; - for (let index = 0; index < chunks; index += 1) yield chunk; - } - await pipeline(Readable.from(oversizedZeros()), createGzip(), createWriteStream(unbounded)); - const unboundedDescriptor = await fs.open(unbounded, "r+"); - try { - await unboundedDescriptor.write(Buffer.from("1f8b0800000000000003", "hex"), 0, 10, 0); - } finally { - await unboundedDescriptor.close(); - } - assert.throws( - () => validateExtensionArtifactArchive({ - file: unbounded, - metadata: pgtapMetadata, - target: "linux-x64-gnu", - nativeRuntimeVersion: "1.2.3", - label: "expanded bomb", - }), - /valid bounded gzip stream|expanded archive exceeds/u, - ); - - console.log("extension-artifact-inventory.test.mjs: exact inventory and adversarial bounds checks passed"); - } finally { - await fs.rm(root, { recursive: true, force: true }); - } -} - -test("extension artifact inventory enforces exact inventory and adversarial bounds", { timeout: 120_000 }, main); diff --git a/tools/release/extension-package-assembly.test.mjs b/tools/release/extension-package-assembly.test.mjs deleted file mode 100644 index b15227a95..000000000 --- a/tools/release/extension-package-assembly.test.mjs +++ /dev/null @@ -1,264 +0,0 @@ -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { - chmodSync, - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { zstdCompressSync } from "node:zlib"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { afterEach, test } from "node:test"; - -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { extensionSqlNames } from "./release-artifact-targets.mjs"; -import { - loadNativeComponentContract, - resolveNativeComponentClosure, -} from "../../src/extensions/tools/native-component-contract.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const TEST_BASH = process.env.OLIPHAUNT_TEST_BASH - ? path.resolve(ROOT, process.env.OLIPHAUNT_TEST_BASH) - : (process.platform === "darwin" ? "/bin/bash" : "bash"); -const RELEASE_SCRIPT = "src/extensions/artifacts/packages/tools/package-release-assets.sh"; -const MOBILE_SCRIPT = "src/extensions/artifacts/packages/tools/package-mobile-release-assets.sh"; -const WASIX_ASSET_PACKAGER = "src/extensions/artifacts/wasix/tools/package-release-assets.mjs"; -const CONTRIB_PRODUCT = "oliphaunt-extension-contrib-pg18"; -const nativeComponentContract = loadNativeComponentContract(); -const roots = []; - -function fixtureRun(script, { environment = {}, failTool = "" } = {}) { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-extension-package-")); - roots.push(root); - const initialized = spawnSync("git", ["init", "--quiet"], { cwd: root, encoding: "utf8" }); - assert.equal(initialized.status, 0, initialized.stderr); - - const toolDirectory = path.join(root, "tools/dev"); - mkdirSync(toolDirectory, { recursive: true }); - const callsFile = path.join(root, "calls.txt"); - const bunShim = path.join(toolDirectory, "bun.sh"); - writeFileSync(bunShim, `#!/usr/bin/env bash -set -euo pipefail -printf '%s\\n' "$*" >> "$OLIPHAUNT_TEST_CALLS_FILE" -if [[ "\${OLIPHAUNT_TEST_FAIL_TOOL:-}" == "$1" ]]; then - exit 73 -fi -`); - chmodSync(bunShim, 0o755); - - const execution = spawnSync(TEST_BASH, [path.join(ROOT, script)], { - cwd: root, - encoding: "utf8", - env: { - ...process.env, - ...environment, - OLIPHAUNT_TEST_CALLS_FILE: callsFile, - OLIPHAUNT_TEST_FAIL_TOOL: failTool, - }, - }); - const calls = existsSync(callsFile) - ? readFileSync(callsFile, "utf8").trimEnd().split("\n") - : []; - return { calls, execution }; -} - -afterEach(() => { - for (const root of roots.splice(0)) rmSync(root, { force: true, recursive: true }); -}); - -test("full extension assembly validates exactly the planner-selected products and all targets", () => { - const { calls, execution } = fixtureRun(RELEASE_SCRIPT, { - environment: { - OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS: - "oliphaunt-extension-postgis, oliphaunt-extension-vector", - }, - }); - assert.equal(execution.status, 0, execution.stderr); - assert.deepEqual(calls, [ - "tools/release/build-extension-ci-artifacts.mjs --all --require-native --require-wasix", - "tools/release/check-staged-artifacts.mjs --require-full-extension-targets --require-extension-product oliphaunt-extension-postgis --require-extension-product oliphaunt-extension-vector", - ]); -}); - -test("full extension assembly requires every product when no focused selection exists", () => { - const { calls, execution } = fixtureRun(RELEASE_SCRIPT); - assert.equal(execution.status, 0, execution.stderr); - assert.deepEqual(calls, [ - "tools/release/build-extension-ci-artifacts.mjs --all --require-native --require-wasix", - "tools/release/check-staged-artifacts.mjs --require-full-extension-targets --require-extension-product all", - ]); -}); - -test("extension assembly stops after producer failure and propagates validator failure", () => { - const producerFailure = fixtureRun(RELEASE_SCRIPT, { - failTool: "tools/release/build-extension-ci-artifacts.mjs", - }); - assert.equal(producerFailure.execution.status, 73); - assert.deepEqual(producerFailure.calls, [ - "tools/release/build-extension-ci-artifacts.mjs --all --require-native --require-wasix", - ]); - - const validatorFailure = fixtureRun(RELEASE_SCRIPT, { - failTool: "tools/release/check-staged-artifacts.mjs", - }); - assert.equal(validatorFailure.execution.status, 73); - assert.deepEqual(validatorFailure.calls, [ - "tools/release/build-extension-ci-artifacts.mjs --all --require-native --require-wasix", - "tools/release/check-staged-artifacts.mjs --require-full-extension-targets --require-extension-product all", - ]); -}); - -test("mobile contrib assembly scopes both staging and validation to native carriers", () => { - const { calls, execution } = fixtureRun(MOBILE_SCRIPT, { - environment: { - OLIPHAUNT_EXTENSION_PACKAGE_NATIVE_TARGETS: "android-arm64-v8a,ios-xcframework", - OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS: "oliphaunt-extension-contrib-pg18", - }, - failTool: "tools/release/check-staged-artifacts.mjs", - }); - assert.equal(execution.status, 73); - assert.deepEqual(calls, [ - "tools/release/build-extension-ci-artifacts.mjs --output-root target/mobile-extension-artifacts --family native oliphaunt-extension-contrib-pg18 --require-native-target android-arm64-v8a --require-native-target ios-xcframework", - "tools/release/check-staged-artifacts.mjs --family native --require-extension-product oliphaunt-extension-contrib-pg18", - ]); -}); - -test("mobile extension assembly rejects delimiter-only selections without nounset errors", () => { - const emptyProducts = fixtureRun(MOBILE_SCRIPT, { - environment: { - OLIPHAUNT_EXTENSION_PACKAGE_NATIVE_TARGETS: "android-arm64-v8a", - OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS: ", ,", - }, - }); - assert.equal(emptyProducts.execution.status, 1); - assert.match(emptyProducts.execution.stderr, /did not contain any products/u); - assert.doesNotMatch(emptyProducts.execution.stderr, /unbound variable/u); - - const emptyTargets = fixtureRun(MOBILE_SCRIPT, { - environment: { - OLIPHAUNT_EXTENSION_PACKAGE_NATIVE_TARGETS: ", ,", - OLIPHAUNT_EXTENSION_PACKAGE_PRODUCTS: "oliphaunt-extension-postgis", - }, - }); - assert.equal(emptyTargets.execution.status, 1); - assert.match(emptyTargets.execution.stderr, /did not contain any targets/u); - assert.doesNotMatch(emptyTargets.execution.stderr, /unbound variable/u); -}); - -test("WASIX release staging resolves runtime-owned contrib through its logical artifact product", () => { - const fixture = mkdtempSync(path.join(tmpdir(), "oliphaunt-wasix-extension-package-")); - roots.push(fixture); - const assetRoot = path.join(fixture, "assets"); - const extensionRoot = path.join(assetRoot, "extensions"); - const metadataPath = path.join(fixture, "extensions.json"); - const manifestPath = path.join(fixture, "manifest.json"); - const outDir = path.join(fixture, "out"); - mkdirSync(extensionRoot, { recursive: true }); - - const sqlNames = extensionSqlNames(CONTRIB_PRODUCT, "extension-package-assembly.test"); - const builtExtensions = []; - const extensions = sqlNames.map((sqlName) => { - const componentClosure = resolveNativeComponentClosure(nativeComponentContract, { - extension: sqlName, - family: "wasix", - kind: "wasix-runtime", - target: "wasix-portable", - }); - const archive = `extensions/${sqlName}.tar.zst`; - const archiveRoot = path.join(fixture, "archive-input", sqlName); - const controlPath = `share/postgresql/extension/${sqlName}.control`; - const controlFile = path.join(archiveRoot, ...controlPath.split("/")); - mkdirSync(path.dirname(controlFile), { recursive: true }); - writeFileSync(controlFile, `default_version = '1.0'\n`); - const archiveBytes = zstdCompressSync(createDeterministicTar(archiveRoot, ".", { - fail(message) { - throw new Error(message); - }, - fixedFileMode: 0o644, - })); - writeFileSync(path.join(assetRoot, archive), archiveBytes); - const lifecycle = { - "create-extension": true, - "create-schema": null, - "load-sql": [], - "post-create-sql": [], - "startup-config": [], - "preload-required": false, - "restart-required": false, - "shared-memory-required": false, - }; - builtExtensions.push({ - name: sqlName, - "sql-name": sqlName, - archive, - sha256: createHash("sha256").update(archiveBytes).digest("hex"), - size: archiveBytes.length, - "native-module": null, - "native-modules": [], - "core-exports-required": [], - dependencies: [], - "load-order": [], - lifecycle, - "installed-files": [controlPath], - "unresolved-imports": [], - }); - return { - "sql-name": sqlName, - archive, - dependencies: [], - "load-order": [], - lifecycle, - "native-module-file": null, - "native-support-modules": [], - "native-components": componentClosure.components, - "native-link-units": componentClosure.linkUnits, - "native-runtime-files": componentClosure.runtimeFiles, - }; - }); - writeFileSync(metadataPath, `${JSON.stringify({ extensions }, null, 2)}\n`); - writeFileSync(manifestPath, `${JSON.stringify({ extensions: builtExtensions }, null, 2)}\n`); - - const execution = spawnSync( - TEST_BASH, - [ - path.join(ROOT, "tools/dev/bun.sh"), - path.join(ROOT, WASIX_ASSET_PACKAGER), - "--root", - ROOT, - "--asset-root", - assetRoot, - "--metadata", - metadataPath, - "--manifest", - manifestPath, - "--out-dir", - outDir, - "--target", - "wasix-portable", - "--extension-products", - CONTRIB_PRODUCT, - ], - { cwd: ROOT, encoding: "utf8" }, - ); - - assert.equal(execution.status, 0, execution.stderr); - assert.match(execution.stdout, new RegExp(`staged ${sqlNames.length} WASIX exact-extension artifact`)); - const staged = readdirSync(outDir).sort(); - assert.equal(staged.length, sqlNames.length * 2 + 1); - const index = staged.find((entry) => entry.endsWith("-wasix-extension-assets.tsv")); - assert.ok(index); - const indexedSqlNames = readFileSync(path.join(outDir, index), "utf8") - .trimEnd() - .split("\n") - .slice(1) - .map((line) => line.split("\t", 1)[0]) - .sort(); - assert.deepEqual(indexedSqlNames, sqlNames); -}); diff --git a/tools/release/extension-registry-packages.mjs b/tools/release/extension-registry-packages.mjs deleted file mode 100644 index 4ddfca60e..000000000 --- a/tools/release/extension-registry-packages.mjs +++ /dev/null @@ -1,202 +0,0 @@ -import { - expectedExtensionAotTargets, - wasixExtensionAotPackageName, - wasixExtensionPackageName, -} from "./wasix-cargo-artifact-contract.mjs"; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -const REGISTRY_KIND_ORDER = new Map([ - ["crates", 0], - ["npm", 1], - ["maven", 2], -]); - -function stringTargetList(value, label) { - if (!Array.isArray(value) || !value.every((item) => typeof item === "string" && item.length > 0)) { - throw new TypeError(`${label} must be a string list`); - } - return [...value].sort(compareText); -} - -export function extensionNpmPackage(sqlName) { - return `@oliphaunt/extension-${sqlName.replaceAll("_", "-")}`; -} - -export function extensionNpmTargetPackage(sqlName, target) { - return `${extensionNpmPackage(sqlName)}-${target}`; -} - -export function extensionNpmPackageForProduct(product) { - if (typeof product !== "string" || !product.startsWith("oliphaunt-extension-")) { - throw new TypeError(`extension product must start with oliphaunt-extension-: ${JSON.stringify(product)}`); - } - return `@oliphaunt/${product.slice("oliphaunt-".length)}`; -} - -/** - * Host-neutral npm carrier for one product's portable WASIX extension bytes. - * - * Keep the unsuffixed npm identity as the established native/default facade. - * Browser, Node, Bun, and Deno WASIX hosts intentionally share this one explicit carrier. - */ -export function extensionNpmWasixPackageForProduct(product) { - return `${extensionNpmPackageForProduct(product)}-wasix`; -} - -export function extensionNpmTargetPackageForProduct(product, target) { - return `${extensionNpmPackageForProduct(product)}-${target}`; -} - -export function nativeExtensionCargoPackageName(product, target) { - return `${product}-${target}`; -} - -export function nativeExtensionCargoLinksName(product, target) { - const stem = `extension_${product.replace(/^oliphaunt-extension-/u, "")}_${target}`; - return `oliphaunt_artifact_${stem.replaceAll("-", "_")}`; -} - -export function nativeExtensionCargoPartPackageName(product, target, index) { - if (!Number.isSafeInteger(index) || index < 1 || index > 999) { - throw new TypeError(`native extension Cargo part number must be an integer from 1 through 999: ${JSON.stringify(index)}`); - } - return `${nativeExtensionCargoPackageName(product, target)}-part-${String(index).padStart(3, "0")}`; -} - -export function assertCargoPackageName(name, { splittable = false, context = "Cargo package" } = {}) { - if (typeof name !== "string" || name.length === 0) { - throw new TypeError(`${context} name must be a non-empty string`); - } - if (name.length > 64) { - throw new TypeError(`${context} ${JSON.stringify(name)} is ${name.length} characters; crates.io allows at most 64`); - } - if (splittable && `${name}-part-001`.length > 64) { - throw new TypeError(`${context} ${JSON.stringify(name)} cannot be split: ${JSON.stringify(`${name}-part-001`)} exceeds crates.io's 64-character limit`); - } - return name; -} - -export function extensionStableNpmPackageNames(sqlName, targets) { - const targetList = stringTargetList(targets, "extension npm targets"); - return [ - extensionNpmPackage(sqlName), - ...targetList.map((target) => extensionNpmTargetPackage(sqlName, target)), - ].sort(compareText); -} - -export function extensionStableNpmPackageNamesForProduct(product, targets) { - const targetList = stringTargetList(targets, "extension npm targets"); - return [ - extensionNpmPackageForProduct(product), - ...targetList.map((target) => extensionNpmTargetPackageForProduct(product, target)), - ].sort(compareText); -} - -export function extensionNativeCargoPackageNames(product, targets) { - return stringTargetList(targets, "native extension Cargo targets") - .map((target) => assertCargoPackageName(nativeExtensionCargoPackageName(product, target), { - splittable: true, - context: `${product} native carrier`, - })) - .sort(compareText); -} - -export function extensionWasixCargoPackageNames( - product, - { includeAot = true, aotTargets = expectedExtensionAotTargets() } = {}, -) { - return [ - assertCargoPackageName(wasixExtensionPackageName(product), { - splittable: true, - context: `${product} portable WASIX carrier`, - }), - ...(includeAot ? aotTargets.map((target) => assertCargoPackageName(wasixExtensionAotPackageName(product, target), { - splittable: true, - context: `${product} WASIX AOT carrier`, - })) : []), - ].sort(compareText); -} - -export function extensionMavenPackageNames(product, androidTargets) { - return stringTargetList(androidTargets, "extension Android Maven targets") - .map((target) => `dev.oliphaunt.extensions:${product}-${target}`) - .sort(compareText); -} - -export function extensionRegistryPackageEntries({ - product, - androidTargets, - npmTargets, - nativeCargoTargets, - includeWasixAot = true, - includeWasixNpm = true, - wasixAotTargets = expectedExtensionAotTargets(), -}) { - return [ - ...extensionNativeRegistryPackageEntries({ - product, - androidTargets, - npmTargets, - nativeCargoTargets, - }), - ...extensionWasixRegistryPackageEntries({ - product, - includeAot: includeWasixAot, - includeNpm: includeWasixNpm, - aotTargets: wasixAotTargets, - }), - ].sort((left, right) => - (REGISTRY_KIND_ORDER.get(left.kind) ?? 99) - (REGISTRY_KIND_ORDER.get(right.kind) ?? 99) - || compareText(left.name, right.name) - ); -} - -export function extensionNativeRegistryPackageEntries({ - product, - androidTargets, - npmTargets, - nativeCargoTargets, - includeFacade = true, -}) { - return [ - ...(includeFacade - ? [{ kind: "crates", name: assertCargoPackageName(product, { context: `${product} facade` }) }] - : []), - ...extensionNativeCargoPackageNames(product, nativeCargoTargets).map((name) => ({ kind: "crates", name })), - ...extensionStableNpmPackageNamesForProduct(product, npmTargets).map((name) => ({ kind: "npm", name })), - ...extensionMavenPackageNames(product, androidTargets).map((name) => ({ kind: "maven", name })), - ].sort((left, right) => - (REGISTRY_KIND_ORDER.get(left.kind) ?? 99) - (REGISTRY_KIND_ORDER.get(right.kind) ?? 99) - || compareText(left.name, right.name) - ); -} - -export function extensionWasixRegistryPackageEntries({ - product, - includeAot = true, - includeNpm = true, - aotTargets = expectedExtensionAotTargets(), -}) { - return [ - ...extensionWasixCargoPackageNames(product, { includeAot, aotTargets }) - .map((name) => ({ kind: "crates", name })), - ...(includeNpm - ? [{ kind: "npm", name: extensionNpmWasixPackageForProduct(product) }] - : []), - ]; -} - -export function extensionRegistryPackageStrings(options) { - return extensionRegistryPackageEntries(options).map((entry) => `${entry.kind}:${entry.name}`); -} - -export function extensionNativeRegistryPackageStrings(options) { - return extensionNativeRegistryPackageEntries(options).map((entry) => `${entry.kind}:${entry.name}`); -} - -export function extensionWasixRegistryPackageStrings(options) { - return extensionWasixRegistryPackageEntries(options).map((entry) => `${entry.kind}:${entry.name}`); -} diff --git a/tools/release/extension-runtime-asset-contract.mjs b/tools/release/extension-runtime-asset-contract.mjs deleted file mode 100644 index 386f4a7a8..000000000 --- a/tools/release/extension-runtime-asset-contract.mjs +++ /dev/null @@ -1,21 +0,0 @@ -const EXTENSION_RUNTIME_ASSET_CONTRACT_FIELDS = Object.freeze([ - "name", - "family", - "target", - "kind", - "identity", - "sha256", - "bytes", - "carrierAsset", - "carrierRoot", - "memberPath", - "memberCount", -]); - -export function extensionRuntimeAssetContract(asset) { - const result = {}; - for (const key of EXTENSION_RUNTIME_ASSET_CONTRACT_FIELDS) { - if (Object.hasOwn(asset, key)) result[key] = asset[key]; - } - return result; -} diff --git a/tools/release/extension-upstream-licenses.mjs b/tools/release/extension-upstream-licenses.mjs deleted file mode 100644 index 218fdb057..000000000 --- a/tools/release/extension-upstream-licenses.mjs +++ /dev/null @@ -1,956 +0,0 @@ -import { createHash } from "node:crypto"; -import { - chmodSync, - existsSync, - lstatSync, - mkdirSync, - readFileSync, - readdirSync, - realpathSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { archiveTreeDigest } from "../../src/sources/tools/source-fetch-core.mjs"; -import { requireSafeDirectoryChain as requireReleaseDirectoryChain } from "./release-directory-safety.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - hasCanonicalReleaseStagingMode, - releaseNoticeRows, - releaseMavenLicenses, - releaseProfilePackageLicense, -} from "./release-notices.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const EXTERNAL_ROOT = path.join(ROOT, "src/extensions/external"); -const PRODUCT_DATA_FILE = "upstream-license-data.json"; -const CHECKOUT_ROOT = path.resolve( - process.env.OLIPHAUNT_EXTENSION_SOURCE_CHECKOUT_ROOT - ?? path.join(ROOT, "target/oliphaunt-sources/checkouts"), -); -const SCHEMA = "oliphaunt-extension-upstream-license-data-v1"; -const SHA256 = /^[0-9a-f]{64}$/u; -const GIT_COMMIT = /^[0-9a-f]{40}$/u; -const SAFE_ID = /^[A-Za-z0-9._-]+$/u; -const FILE_ROLES = new Set(["license", "notice"]); -const SPDX_ORDER = Object.freeze([ - "MIT", - "Apache-2.0", - "PostgreSQL", - "Unicode-3.0", - "MPL-2.0", - "GPL-2.0-or-later", - "LGPL-2.1-or-later", - "blessing", -]); -const SUPPORTED_SPDX_IDS = new Set(SPDX_ORDER); -const CONTRIB_LICENSE = Object.freeze({ - product: "oliphaunt-extension-contrib-pg18", - upstreamSpdx: "PostgreSQL", - packageSpdx: "MIT AND PostgreSQL", -}); -const OPENSSL_EMBEDDED_NATIVE_TARGETS = new Set([ - "android-arm64-v8a", - "android-x86_64", - "ios-xcframework", - "macos-arm64", - "macos-x64", - "windows-x64-msvc", -]); - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function fail(message) { - throw new Error(`extension-upstream-licenses: ${message}`); -} - -function simpleRelative(value, label) { - if (typeof value !== "string" || !value || path.isAbsolute(value) || value.includes("\\")) { - fail(`${label} must be a non-empty portable relative path`); - } - const parts = value.split("/"); - if (parts.some((part) => !part || part === "." || part === "..")) { - fail(`${label} must not contain empty, '.' or '..' components`); - } - return parts.join("/"); -} - -function httpsUrl(value, label) { - let url; - try { - url = new URL(value); - } catch (cause) { - fail(`${label} must be an absolute URL: ${cause.message}`); - } - if ( - typeof value !== "string" - || value.trim() !== value - || value.includes("\\") - || url.protocol !== "https:" - || url.username - || url.password - || url.hash - ) { - fail(`${label} must be one canonical credential-free HTTPS URL without a fragment`); - } - return value; -} - -function spdxExpression(ids) { - const selected = new Set(ids); - const known = SPDX_ORDER.filter((id) => selected.delete(id)); - return [...known, ...[...selected].sort(compareText)].join(" AND "); -} - -export function assertSupportedExtensionUpstreamSpdxId(value, label = "extension upstream license") { - if (typeof value !== "string" || !SUPPORTED_SPDX_IDS.has(value)) { - fail( - `${label} must declare one supported SPDX identifier (${SPDX_ORDER.join(", ")}); got ${JSON.stringify(value)}`, - ); - } - return value; -} - -function parseSource(raw) { - const id = raw?.id; - if (typeof id !== "string" || !SAFE_ID.test(id)) fail(`invalid source id ${JSON.stringify(id)}`); - const manifest = simpleRelative(raw.manifest, `${id} source manifest`); - if (!manifest.startsWith("src/extensions/external/")) { - fail(`${id} source manifest must be under src/extensions/external/`); - } - const kind = raw.kind; - if (!new Set(["git", "archive"]).has(kind)) fail(`${id} source kind must be git or archive`); - const url = httpsUrl(raw.url, `${id} source URL`); - const branch = raw.branch; - const commit = raw.commit; - if (typeof branch !== "string" || !branch || /[\u0000-\u001f\u007f]/u.test(branch)) { - fail(`${id} source branch must be a non-empty printable string`); - } - if (kind === "git" ? !GIT_COMMIT.test(commit) : !SHA256.test(commit)) { - fail(`${id} source commit is not an exact ${kind} identity`); - } - const manifestFile = path.join(ROOT, ...manifest.split("/")); - let manifestData; - let stat; - try { - stat = lstatSync(manifestFile); - manifestData = Bun.TOML.parse(readFileSync(manifestFile, "utf8")); - } catch (cause) { - fail(`${manifest} cannot be inspected and parsed: ${cause.message}`); - } - if (!stat.isFile() || stat.isSymbolicLink()) fail(`${manifest} must be a regular non-symlink file`); - const manifestKind = manifestData.kind ?? "git"; - if ( - manifestData.name !== id - || manifestKind !== kind - || manifestData.url !== url - || manifestData.branch !== branch - || manifestData.commit !== commit - || (kind === "archive" && manifestData.sha256 !== commit) - ) { - fail(`${id} source identity does not match ${manifest}`); - } - return Object.freeze({ id, manifest, kind, url, branch, commit }); -} - -function canonicalSource(source) { - return { - id: source.id, - manifest: source.manifest, - kind: source.kind, - url: source.url, - branch: source.branch, - commit: source.commit, - }; -} - -function canonicalFile(file) { - return { - source: file.source.id, - path: file.path, - destination: file.destination, - role: file.role, - spdx: file.spdx, - license_url: file.licenseUrl, - sha256: file.sha256, - }; -} - -function decodeProductBlobs(rawBlobs, expectedDigests, label) { - if (rawBlobs === null || typeof rawBlobs !== "object" || Array.isArray(rawBlobs)) { - fail(`${label} must declare a blobs object`); - } - const digests = Object.keys(rawBlobs); - if (JSON.stringify(digests) !== JSON.stringify([...digests].sort(compareText))) { - fail(`${label} blob digests must be sorted`); - } - const expected = [...new Set(expectedDigests)].sort(compareText); - if (JSON.stringify(digests) !== JSON.stringify(expected)) { - fail(`${label} blob set differs: expected ${expected.join(", ")}, got ${digests.join(", ")}`); - } - const decoded = new Map(); - for (const digest of digests) { - const encoded = rawBlobs[digest]; - if ( - !SHA256.test(digest) - || typeof encoded !== "string" - || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u.test(encoded) - ) { - fail(`${label} contains a malformed digest or base64 payload`); - } - const payload = Buffer.from(encoded, "base64"); - if ( - payload.toString("base64") !== encoded - || createHash("sha256").update(payload).digest("hex") !== digest - ) { - fail(`${label} payload does not match digest ${digest}`); - } - decoded.set(digest, payload); - } - return decoded; -} - -function parseProductContract(contractFile) { - const label = path.relative(ROOT, contractFile); - let bytes; - let data; - let stat; - try { - stat = lstatSync(contractFile); - bytes = readFileSync(contractFile, "utf8"); - data = JSON.parse(bytes); - } catch (cause) { - fail(`${label} cannot be inspected and parsed: ${cause.message}`); - } - if (!stat.isFile() || stat.isSymbolicLink()) fail(`${label} must be a regular non-symlink file`); - if ( - data?.schema !== SCHEMA - || !Array.isArray(data.sources) - || data.extension === null - || typeof data.extension !== "object" - || Array.isArray(data.extension) - || data.blobs === null - || typeof data.blobs !== "object" - || Array.isArray(data.blobs) - || Object.keys(data).join("\0") !== "schema\0sources\0extension\0blobs" - ) { - fail(`${label} must declare only schema ${SCHEMA}, sources, extension, and blobs`); - } - - const sources = data.sources.map(parseSource); - if (new Set(sources.map((source) => source.id)).size !== sources.length) { - fail(`${label} source ids must be unique`); - } - const sortedSources = [...sources].sort((left, right) => compareText(left.id, right.id)); - if (JSON.stringify(sources) !== JSON.stringify(sortedSources)) fail(`${label} source rows must be sorted by id`); - const sourceById = new Map(sources.map((source) => [source.id, source])); - - const sqlName = data.extension.sql_name; - const owner = path.basename(path.dirname(contractFile)); - if (typeof sqlName !== "string" || !SAFE_ID.test(sqlName) || sqlName !== owner) { - fail(`${label} must be owned by its exact extension_sql_name directory`); - } - if (!Array.isArray(data.extension.files) || data.extension.files.length === 0) { - fail(`${sqlName} must declare at least one upstream license or notice file`); - } - const files = []; - const destinations = new Set(); - const usedSources = new Set(); - for (const rawFile of data.extension.files) { - const source = sourceById.get(rawFile?.source); - if (!source) fail(`${sqlName} file references unknown source ${JSON.stringify(rawFile?.source)}`); - usedSources.add(source.id); - const sourcePath = simpleRelative(rawFile.path, `${sqlName} license path`); - const destination = simpleRelative(rawFile.destination, `${sqlName} license destination`); - if (!destination.startsWith("share/licenses/")) { - fail(`${sqlName} license destination must be under share/licenses/: ${destination}`); - } - if (destinations.has(destination)) fail(`${sqlName} repeats license destination ${destination}`); - destinations.add(destination); - if (!FILE_ROLES.has(rawFile.role)) fail(`${sqlName} ${destination} must have role license or notice`); - const spdx = assertSupportedExtensionUpstreamSpdxId(rawFile.spdx, `${sqlName} ${destination}`); - if (typeof rawFile.sha256 !== "string" || !SHA256.test(rawFile.sha256)) { - fail(`${sqlName} ${destination} must declare a lowercase SHA-256 digest`); - } - files.push(Object.freeze({ - checkout: source.id, - source, - path: sourcePath, - destination, - role: rawFile.role, - spdx, - licenseUrl: httpsUrl(rawFile.license_url, `${sqlName} ${destination} license URL`), - sha256: rawFile.sha256, - })); - } - const sortedFiles = [...files].sort((left, right) => compareText(left.destination, right.destination)); - if (JSON.stringify(files) !== JSON.stringify(sortedFiles)) { - fail(`${sqlName} license files must be sorted by destination`); - } - const unusedSources = sources.map((source) => source.id).filter((id) => !usedSources.has(id)); - if (unusedSources.length > 0) fail(`${label} has unused source identities: ${unusedSources.join(", ")}`); - const blobs = decodeProductBlobs(data.blobs, files.map((file) => file.sha256), label); - const canonical = `${JSON.stringify({ - schema: SCHEMA, - sources: sources.map(canonicalSource), - extension: { - sql_name: sqlName, - files: files.map(canonicalFile), - }, - blobs: Object.fromEntries([...blobs.keys()].map((digest) => [digest, data.blobs[digest]])), - }, null, 2)}\n`; - if (bytes !== canonical) fail(`${label} must be canonical two-space JSON with one trailing newline`); - return Object.freeze({ - row: Object.freeze({ - sqlName, - upstreamSpdx: spdxExpression(files.map((file) => file.spdx)), - packageSpdx: spdxExpression(["MIT", ...files.map((file) => file.spdx)]), - files: Object.freeze(files), - }), - sources: Object.freeze(sources), - blobs, - }); -} - -const cachedProductContracts = new Map(); - -function productContractFile(sqlName) { - if (typeof sqlName !== "string" || !SAFE_ID.test(sqlName)) { - fail(`invalid extension SQL name ${JSON.stringify(sqlName)}`); - } - return path.join(EXTERNAL_ROOT, sqlName, PRODUCT_DATA_FILE); -} - -function productContract(sqlName) { - let parsed = cachedProductContracts.get(sqlName); - if (parsed === undefined) { - parsed = parseProductContract(productContractFile(sqlName)); - cachedProductContracts.set(sqlName, parsed); - } - return parsed; -} - -function productContractSqlNames() { - return readdirSync(EXTERNAL_ROOT, { withFileTypes: true }) - .filter((entry) => entry.isDirectory() && existsSync(path.join(EXTERNAL_ROOT, entry.name, PRODUCT_DATA_FILE))) - .map((entry) => entry.name) - .sort(compareText); -} - -function parseContract() { - const productContracts = productContractSqlNames().map(productContract); - const rows = productContracts.map((entry) => entry.row); - const sortedRows = [...rows].sort((left, right) => compareText(left.sqlName, right.sqlName)); - if (JSON.stringify(rows) !== JSON.stringify(sortedRows)) fail("extension license rows must be sorted by sql_name"); - const sourceById = new Map(); - for (const source of productContracts.flatMap((entry) => entry.sources)) { - const prior = sourceById.get(source.id); - if (prior !== undefined && JSON.stringify(canonicalSource(prior)) !== JSON.stringify(canonicalSource(source))) { - fail(`source id ${source.id} has conflicting identities across product-owned upstream license data`); - } - sourceById.set(source.id, source); - } - const sortedSources = [...sourceById.values()].sort((left, right) => compareText(left.id, right.id)); - const blobs = new Map(); - for (const productContract of productContracts) { - for (const [digest, payload] of productContract.blobs) { - const prior = blobs.get(digest); - if (prior !== undefined && !prior.equals(payload)) fail(`committed upstream license blob conflicts at ${digest}`); - blobs.set(digest, payload); - } - } - return Object.freeze({ - rows: Object.freeze(rows), - sources: Object.freeze(sortedSources), - blobs, - }); -} - -let cachedContract; - -function contract() { - cachedContract ??= parseContract(); - return cachedContract; -} - -export function extensionUpstreamLicenseRows() { - return contract().rows; -} - -export function extensionUpstreamLicenseSources() { - return contract().sources; -} - -export function extensionUpstreamLicenseRow(sqlName) { - return productContract(sqlName).row; -} - -export function externalReleaseExtensionSqlNames() { - const sqlNames = []; - for (const entry of readdirSync(path.join(ROOT, "src/extensions/external"), { withFileTypes: true })) { - if (!entry.isDirectory()) continue; - const releaseFile = path.join(ROOT, "src/extensions/external", entry.name, "release.toml"); - if (existsSync(releaseFile)) { - let release; - try { - release = Bun.TOML.parse(readFileSync(releaseFile, "utf8")); - } catch (cause) { - fail(`${path.relative(ROOT, releaseFile)} cannot be read: ${cause.message}`); - } - if (typeof release?.extension_sql_name !== "string" || !SAFE_ID.test(release.extension_sql_name)) { - fail(`${path.relative(ROOT, releaseFile)} must declare a safe extension_sql_name`); - } - sqlNames.push(release.extension_sql_name); - continue; - } - } - const canonical = [...new Set(sqlNames)].sort(compareText); - if (canonical.length !== sqlNames.length) fail("external release SQL names must be unique"); - return Object.freeze(canonical); -} - -export function validateExtensionUpstreamLicenseContract() { - const rows = extensionUpstreamLicenseRows(); - const expected = externalReleaseExtensionSqlNames(); - const actual = rows.map((row) => row.sqlName); - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - fail(`contract extension set mismatch: expected ${expected.join(", ")}, got ${actual.join(", ")}`); - } - committedLicenseBlobs(rows.flatMap((row) => row.files.map((file) => file.sha256))); - return rows; -} - -function externalLicenseRow(product, members) { - if (members.length !== 1) { - fail(`${product} is not the explicit contrib bundle and must have exactly one external extension member`); - } - const row = extensionUpstreamLicenseRow(members[0]); - const releaseToml = path.join(ROOT, "src/extensions/external", row.sqlName, "release.toml"); - let release; - try { - release = Bun.TOML.parse(readFileSync(releaseToml, "utf8")); - } catch (cause) { - fail(`${path.relative(ROOT, releaseToml)} cannot be read: ${cause.message}`); - } - if (release?.id !== product || release?.extension_sql_name !== row.sqlName) { - fail(`${product} does not match ${row.sqlName}'s release identity`); - } - return row; -} - -export function extensionRegistryLicense(product, members) { - if ( - typeof product !== "string" - || !Array.isArray(members) - || members.length === 0 - || members.some((member) => typeof member !== "string" || !member) - ) { - fail("registry license lookup requires a product and non-empty member list"); - } - if (product === CONTRIB_LICENSE.product) return CONTRIB_LICENSE; - const row = externalLicenseRow(product, members); - return Object.freeze({ - product, - upstreamSpdx: row.upstreamSpdx, - packageSpdx: row.packageSpdx, - }); -} - -export function extensionMavenLicenses(product, members, { version } = {}) { - if (product === CONTRIB_LICENSE.product) { - return releaseMavenLicenses({ product, version, components: ["postgresql"] }); - } - const row = externalLicenseRow(product, members); - const entries = [...releaseMavenLicenses({ product, version })]; - const seen = new Set(entries.map((entry) => JSON.stringify(entry))); - for (const file of row.files.filter((candidate) => candidate.role === "license")) { - const entry = Object.freeze({ - name: `${file.spdx} (${file.source.id})`, - url: file.licenseUrl, - distribution: "repo", - }); - const key = JSON.stringify(entry); - if (!seen.has(key)) { - entries.push(entry); - seen.add(key); - } - } - return Object.freeze(entries); -} - -function hashFile(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function committedLicenseBlobs(expectedDigests) { - const blobs = contract().blobs; - const actual = [...blobs.keys()].sort(compareText); - const expected = [...new Set(expectedDigests)].sort(compareText); - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - fail(`committed upstream license blob set differs: expected ${expected.join(", ")}, got ${actual.join(", ")}`); - } - return blobs; -} - -function productLicenseBlobs(sqlName, expectedDigests) { - const blobs = productContract(sqlName).blobs; - const actual = [...blobs.keys()].sort(compareText); - const expected = [...new Set(expectedDigests)].sort(compareText); - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - fail(`${sqlName} committed upstream license blob set differs: expected ${expected.join(", ")}, got ${actual.join(", ")}`); - } - return blobs; -} - -function requireRealDirectory(directory, label, { create = false } = {}) { - let stat; - try { - stat = lstatSync(directory); - } catch (cause) { - if (cause?.code !== "ENOENT" || !create) fail(`${label} cannot be inspected: ${cause.message}`); - mkdirSync(directory, { mode: 0o755 }); - stat = lstatSync(directory); - } - if (!stat.isDirectory() || stat.isSymbolicLink()) fail(`${label} must be a real directory: ${directory}`); -} - -function requireSafeDirectoryChain(directory, { create = true, label = "license staging" } = {}) { - try { - return requireReleaseDirectoryChain(directory, { create, label }); - } catch (cause) { - fail(cause.message); - } -} - -function safeDestination(root, relative) { - const destination = path.join(root, ...relative.split("/")); - let cursor = root; - for (const part of relative.split("/").slice(0, -1)) { - cursor = path.join(cursor, part); - requireRealDirectory(cursor, "license staging parent", { create: true }); - } - let stat; - try { - stat = lstatSync(destination); - } catch (cause) { - if (cause?.code !== "ENOENT") fail(`license destination cannot be inspected: ${destination} (${cause.message})`); - } - if (stat && (!stat.isFile() || stat.isSymbolicLink())) { - fail(`license destination must be absent or a regular non-symlink file: ${destination}`); - } - return destination; -} - -const validatedCheckouts = new Set(); - -function validateCheckout(source) { - const sourceIdentity = JSON.stringify(canonicalSource(source)); - if (validatedCheckouts.has(sourceIdentity)) return path.join(CHECKOUT_ROOT, source.id); - const checkout = path.join(CHECKOUT_ROOT, source.id); - requireRealDirectory(checkout, `${source.id} checkout`); - if (source.kind === "git") { - const gitDirectory = path.join(checkout, ".git"); - requireRealDirectory(gitDirectory, `${source.id} Git metadata`); - const git = (args, label) => { - const result = captureCommandOutput("git", [ - "-c", - "core.fsmonitor=false", - "-c", - "core.autocrlf=false", - "-c", - "core.eol=lf", - ...args, - ], { - cwd: checkout, - label, - maxOutputBytes: 1024 * 1024, - }); - if (result.error || result.signal || result.status !== 0) { - fail(`${label} failed: ${result.error?.message ?? result.stderr.trim() ?? `status ${result.status}`}`); - } - return result.stdout.trim(); - }; - const head = git(["rev-parse", "--verify", "HEAD"], `read ${source.id} source HEAD`); - const remote = git(["remote", "get-url", "origin"], `read ${source.id} source origin`); - const status = git(["status", "--porcelain=v1", "--untracked-files=all"], `read ${source.id} source status`); - if (head !== source.commit || remote !== source.url || status !== "") { - fail(`${source.id} checkout does not exactly match clean pinned source ${source.url}@${source.commit}`); - } - } else { - const marker = path.join(checkout, ".oliphaunt-source-pin"); - let markerStat; - let fields; - try { - markerStat = lstatSync(marker); - fields = new Map(readFileSync(marker, "utf8").trimEnd().split("\n").map((line) => { - const separator = line.indexOf("="); - if (separator <= 0) fail(`${source.id} archive source marker is malformed`); - return [line.slice(0, separator), line.slice(separator + 1)]; - })); - } catch (cause) { - fail(`${source.id} archive source marker cannot be inspected: ${cause.message}`); - } - if (!markerStat.isFile() || markerStat.isSymbolicLink()) fail(`${source.id} archive marker must be a regular file`); - if ( - fields.size !== 9 - || fields.get("safety") !== "source-archive-v2" - || fields.get("name") !== source.id - || fields.get("kind") !== "archive" - || fields.get("url") !== source.url - || fields.get("branch") !== source.branch - || fields.get("commit") !== source.commit - || fields.get("sha256") !== source.commit - || !SHA256.test(fields.get("tree-sha256") ?? "") - || archiveTreeDigest(checkout) !== fields.get("tree-sha256") - ) { - fail(`${source.id} archive checkout does not exactly match its pinned source marker and tree digest`); - } - } - validatedCheckouts.add(sourceIdentity); - return checkout; -} - -export function stageExtensionUpstreamLicenses(sqlName, filesRoot) { - const externalRoot = path.join(ROOT, "src/extensions/external", sqlName); - if (!existsSync(path.join(externalRoot, "release.toml"))) return Object.freeze([]); - const row = extensionUpstreamLicenseRow(sqlName); - const blobs = productLicenseBlobs(sqlName, row.files.map((file) => file.sha256)); - const stagingRoot = requireSafeDirectoryChain(filesRoot); - const staged = []; - for (const file of row.files) { - const source = blobs.get(file.sha256); - if (source === undefined) fail(`${sqlName} has no committed legal bytes for ${file.destination}`); - const destination = safeDestination(stagingRoot, file.destination); - writeFileSync(destination, source); - chmodSync(destination, 0o644); - const destinationStat = lstatSync(destination); - if ( - !destinationStat.isFile() - || destinationStat.isSymbolicLink() - || !hasCanonicalReleaseStagingMode(destinationStat.mode) - ) { - fail(`${sqlName} staged license is not a regular mode-0644 file: ${file.destination}`); - } - if (hashFile(destination) !== file.sha256) fail(`${sqlName} staged license bytes changed for ${file.destination}`); - staged.push(file.destination); - } - return Object.freeze(staged); -} - -export function auditExtensionUpstreamLicenseSources() { - const blobs = committedLicenseBlobs(extensionUpstreamLicenseRows().flatMap((row) => row.files.map((file) => file.sha256))); - let checked = 0; - for (const row of extensionUpstreamLicenseRows()) { - for (const file of row.files) { - const sourceRoot = validateCheckout(file.source); - const source = path.join(sourceRoot, ...file.path.split("/")); - let sourceStat; - try { - sourceStat = lstatSync(source); - } catch (cause) { - fail(`${row.sqlName} license source is missing: ${path.relative(ROOT, source)} (${cause.message})`); - } - if (!sourceStat.isFile() || sourceStat.isSymbolicLink()) { - fail(`${row.sqlName} license source must be a regular non-symlink file: ${path.relative(ROOT, source)}`); - } - const realRoot = realpathSync(sourceRoot); - const realSource = realpathSync(source); - if (!realSource.startsWith(`${realRoot}${path.sep}`)) { - fail(`${row.sqlName} license source escapes checkout ${file.source.id}: ${file.path}`); - } - const sourceBytes = readFileSync(source); - const actualSha256 = createHash("sha256").update(sourceBytes).digest("hex"); - if (actualSha256 !== file.sha256 || !sourceBytes.equals(blobs.get(file.sha256))) { - fail( - `${row.sqlName} legal bytes changed for ${file.source.id}/${file.path}: expected committed digest ${file.sha256}, got ${actualSha256}`, - ); - } - checked += 1; - } - } - return checked; -} - -function checkedLicenseRows(sqlNames) { - if ( - !Array.isArray(sqlNames) - || sqlNames.length === 0 - || sqlNames.some((sqlName) => typeof sqlName !== "string" || !SAFE_ID.test(sqlName)) - || new Set(sqlNames).size !== sqlNames.length - ) { - fail("upstream license assertion requires a non-empty unique extension member list"); - } - return sqlNames.map(extensionUpstreamLicenseRow); -} - -function expectedLicenseFiles(sqlNames) { - const expected = new Map(); - for (const row of checkedLicenseRows(sqlNames)) { - for (const file of row.files) { - const prior = expected.get(file.destination); - if (prior && prior.sha256 !== file.sha256) { - fail(`upstream license destination collision at ${file.destination}`); - } - expected.set(file.destination, file); - } - } - return expected; -} - -export function extensionUpstreamLicenseFileInventory(sqlNames) { - return Object.freeze( - [...expectedLicenseFiles(sqlNames).values()] - .sort((left, right) => compareText(left.destination, right.destination)) - .map((file) => Object.freeze({ - path: file.destination, - sha256: file.sha256, - mode: "0644", - })), - ); -} - -export function extensionCarrierLegalContract( - product, - sqlNames, - { family, target, carriesPayload = true } = {}, -) { - if ( - typeof product !== "string" - || !product - || !Array.isArray(sqlNames) - || sqlNames.length === 0 - || sqlNames.some((sqlName) => typeof sqlName !== "string" || !SAFE_ID.test(sqlName)) - || new Set(sqlNames).size !== sqlNames.length - || typeof carriesPayload !== "boolean" - ) { - fail("carrier legal lookup requires a product, a unique non-empty extension member list, and carriesPayload"); - } - if (!carriesPayload) { - return Object.freeze({ - profile: "code-facade", - packageSpdx: releaseProfilePackageLicense("code-facade").spdx, - upstreamMembers: Object.freeze([]), - licenseFiles: Object.freeze([]), - }); - } - if (!new Set(["native", "wasix"]).has(family) || typeof target !== "string" || !target) { - fail("payload-bearing carrier legal lookup requires family=native|wasix and an exact target"); - } - if (product === CONTRIB_LICENSE.product) { - const embedsOpenSsl = sqlNames.includes("pgcrypto") - && (family === "wasix" || OPENSSL_EMBEDDED_NATIVE_TARGETS.has(target)); - const profile = `${family === "native" ? "contrib-native" : "contrib-wasix"}${embedsOpenSsl ? "-openssl" : ""}`; - return Object.freeze({ - profile, - packageSpdx: releaseProfilePackageLicense(profile).spdx, - upstreamMembers: Object.freeze([]), - licenseFiles: Object.freeze([]), - }); - } - const registry = extensionRegistryLicense(product, sqlNames); - const licenseFiles = [...expectedLicenseFiles(sqlNames).keys()].sort(compareText); - return Object.freeze({ - profile: `external-${family}`, - packageSpdx: registry.packageSpdx, - upstreamMembers: Object.freeze([...sqlNames]), - licenseFiles: Object.freeze(licenseFiles), - }); -} - -export function extensionCarrierLegalFileInventory( - product, - sqlNames, - { family, target, carriesPayload = true } = {}, -) { - const legal = extensionCarrierLegalContract(product, sqlNames, { - family, - target, - carriesPayload, - }); - const files = new Map(); - const add = (file, bytes, expectedSha256 = undefined) => { - const payload = Buffer.from(bytes); - const sha256 = createHash("sha256").update(payload).digest("hex"); - if (expectedSha256 !== undefined && sha256 !== expectedSha256) { - fail(`canonical legal bytes changed for ${file}: expected ${expectedSha256}, got ${sha256}`); - } - const row = Object.freeze({ - path: simpleRelative(file, "carrier legal member"), - sha256, - bytes: payload.length, - mode: "0644", - }); - const prior = files.get(row.path); - if ( - prior !== undefined - && (prior.sha256 !== row.sha256 || prior.bytes !== row.bytes || prior.mode !== row.mode) - ) { - fail(`carrier legal member collision at ${row.path}`); - } - files.set(row.path, prior ?? row); - }; - - for (const row of releaseNoticeRows({ profile: legal.profile })) { - add(row.member, readFileSync(row.source), row.sha256); - } - - const upstreamPaths = []; - for (const sqlName of legal.upstreamMembers) { - const row = extensionUpstreamLicenseRow(sqlName); - const blobs = productLicenseBlobs(sqlName, row.files.map((file) => file.sha256)); - for (const file of row.files) { - const bytes = blobs.get(file.sha256); - if (bytes === undefined) fail(`${sqlName} has no committed legal bytes for ${file.destination}`); - upstreamPaths.push(file.destination); - add(file.destination, bytes, file.sha256); - } - } - const actualUpstreamPaths = [...new Set(upstreamPaths)].sort(compareText); - if (JSON.stringify(actualUpstreamPaths) !== JSON.stringify([...legal.licenseFiles])) { - fail( - `carrier legal file inventory differs from its contract: expected ${legal.licenseFiles.join(", ")}, ` - + `got ${actualUpstreamPaths.join(", ")}`, - ); - } - - return Object.freeze([...files.values()].sort((left, right) => compareText(left.path, right.path))); -} - -function checkedArchivePrefix(value = "") { - if (value === "") return ""; - return simpleRelative(String(value).replace(/\/$/u, ""), "upstream license archive prefix"); -} - -function prefixed(prefix, member) { - return prefix ? `${prefix}/${member}` : member; -} - -export function assertExtensionUpstreamLicensesInDirectory(sqlNames, filesRoot) { - const root = requireSafeDirectoryChain(filesRoot, { - create: false, - label: "upstream license assertion", - }); - const expected = expectedLicenseFiles(sqlNames); - const actualFiles = []; - const actualDirectories = []; - const licensesRoot = path.join(root, "share/licenses"); - const visit = (directory) => { - for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareText(left.name, right.name))) { - const candidate = path.join(directory, entry.name); - const stat = lstatSync(candidate); - if (stat.isSymbolicLink()) fail(`staged upstream license must not be a symlink: ${candidate}`); - if (stat.isDirectory()) { - actualDirectories.push(path.relative(root, candidate).split(path.sep).join("/")); - visit(candidate); - } else if (stat.isFile()) { - actualFiles.push(path.relative(root, candidate).split(path.sep).join("/")); - } else { - fail(`staged upstream license tree contains a special entry: ${candidate}`); - } - } - }; - if (!existsSync(licensesRoot)) fail(`staged upstream license directory is missing: ${licensesRoot}`); - const licensesRootStat = lstatSync(licensesRoot); - if (!licensesRootStat.isDirectory() || licensesRootStat.isSymbolicLink()) { - fail(`staged upstream license root must be a real directory: ${licensesRoot}`); - } - visit(licensesRoot); - const expectedNames = [...expected.keys()].sort(compareText); - const expectedDirectories = expectedLicenseDirectories(expectedNames); - if (JSON.stringify(actualFiles.sort(compareText)) !== JSON.stringify(expectedNames)) { - fail(`staged upstream license members differ: expected ${expectedNames.join(", ")}, got ${actualFiles.sort(compareText).join(", ")}`); - } - if (JSON.stringify(actualDirectories.sort(compareText)) !== JSON.stringify(expectedDirectories)) { - fail( - `staged upstream license directories differ: expected ${expectedDirectories.join(", ")}, ` - + `got ${actualDirectories.sort(compareText).join(", ")}`, - ); - } - for (const [destination, file] of expected) { - const staged = path.join(root, ...destination.split("/")); - const stat = lstatSync(staged); - if (!stat.isFile() || stat.isSymbolicLink() || !hasCanonicalReleaseStagingMode(stat.mode)) { - fail(`staged upstream license must be a regular mode-0644 file: ${destination}`); - } - if (hashFile(staged) !== file.sha256) fail(`staged upstream license bytes changed for ${destination}`); - } - return Object.freeze(expectedNames); -} - -function expectedLicenseDirectories(expectedNames, prefix = "") { - const namespaceRoot = prefixed(prefix, "share/licenses"); - const directories = new Set(); - for (const member of expectedNames) { - let directory = path.posix.dirname(member); - while (directory !== namespaceRoot) { - if (!directory.startsWith(`${namespaceRoot}/`)) { - fail(`upstream license member escapes its namespace: ${member}`); - } - directories.add(directory); - directory = path.posix.dirname(directory); - } - } - return [...directories].sort(compareText); -} - -function archiveEntryKind(entry) { - if (entry?.isSymbolicLink) return "symlink"; - if (entry?.isFile && !entry?.isDirectory) return "file"; - if (entry?.isDirectory && !entry?.isFile) return "directory"; - return "special"; -} - -export function assertExtensionUpstreamLicensesInEntries(sqlNames, entries, { prefix = "" } = {}) { - if (!(entries instanceof Map)) fail("upstream license archive entries must be a Map"); - const normalizedPrefix = checkedArchivePrefix(prefix); - const expected = expectedLicenseFiles(sqlNames); - const expectedNames = [...expected.keys()].map((member) => prefixed(normalizedPrefix, member)).sort(compareText); - const namespaceRoot = prefixed(normalizedPrefix, "share/licenses"); - const expectedDirectories = new Set(expectedLicenseDirectories(expectedNames, normalizedPrefix)); - expectedDirectories.add(namespaceRoot); - const actualNames = []; - for (const [member, entry] of entries) { - if (member !== namespaceRoot && !member.startsWith(`${namespaceRoot}/`)) continue; - const kind = archiveEntryKind(entry); - if (expectedNames.includes(member)) { - if (kind !== "file" || (entry.mode & 0o7777) !== 0o644) { - fail(`packed upstream license must be a regular non-symlink mode-0644 file: ${member}`); - } - actualNames.push(member); - continue; - } - if (expectedDirectories.has(member)) { - if (kind !== "directory" || (entry.mode & 0o7777) !== 0o755) { - fail(`packed upstream license directory must be a real mode-0755 directory: ${member}`); - } - continue; - } - fail(`packed upstream license namespace contains unexpected ${kind} member: ${member}`); - } - actualNames.sort(compareText); - if (JSON.stringify(actualNames) !== JSON.stringify(expectedNames)) { - fail(`packed upstream license members differ: expected ${expectedNames.join(", ")}, got ${actualNames.join(", ")}`); - } - for (const [destination, file] of expected) { - const member = prefixed(normalizedPrefix, destination); - const entry = entries.get(member); - if (archiveEntryKind(entry) !== "file" || (entry.mode & 0o7777) !== 0o644) { - fail(`packed upstream license must be a regular non-symlink mode-0644 file: ${member}`); - } - const actual = createHash("sha256").update(entry.data()).digest("hex"); - if (actual !== file.sha256) fail(`packed upstream license bytes changed for ${member}`); - } - return Object.freeze(expectedNames); -} - -export function assertExtensionUpstreamLicensesInArchive(sqlNames, archive, options = {}) { - return assertExtensionUpstreamLicensesInEntries( - sqlNames, - readPortableArchiveEntries(archive), - options, - ); -} diff --git a/tools/release/extension-upstream-licenses.test.mjs b/tools/release/extension-upstream-licenses.test.mjs deleted file mode 100644 index 3653bd980..000000000 --- a/tools/release/extension-upstream-licenses.test.mjs +++ /dev/null @@ -1,489 +0,0 @@ -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { - existsSync, - lstatSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { - canonicalGzipSync, - readPortableArchiveEntries, -} from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { hasCanonicalReleaseStagingMode } from "./release-notices.mjs"; -import { - auditExtensionUpstreamLicenseSources, - assertExtensionUpstreamLicensesInEntries, - assertExtensionUpstreamLicensesInArchive, - assertExtensionUpstreamLicensesInDirectory, - assertSupportedExtensionUpstreamSpdxId, - externalReleaseExtensionSqlNames, - extensionCarrierLegalContract, - extensionCarrierLegalFileInventory, - extensionMavenLicenses, - extensionRegistryLicense, - stageExtensionUpstreamLicenses, - extensionUpstreamLicenseFileInventory, - extensionUpstreamLicenseRows, - extensionUpstreamLicenseSources, - validateExtensionUpstreamLicenseContract, -} from "./extension-upstream-licenses.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); - -test("every active external release has an exact upstream license contract", () => { - const rows = validateExtensionUpstreamLicenseContract(); - assert.deepEqual(rows.map((row) => row.sqlName), externalReleaseExtensionSqlNames()); - assert.deepEqual(rows.map((row) => row.sqlName), [ - "pg_hashids", - "pg_ivm", - "pg_textsearch", - "pg_uuidv7", - "pgtap", - "postgis", - "vector", - ]); - for (const row of rows) { - assert.ok(row.files.length > 0, `${row.sqlName} must ship at least one license file`); - assert.equal(new Set(row.files.map((file) => file.destination)).size, row.files.length); - } - assert.deepEqual(extensionUpstreamLicenseSources().map((source) => source.id), [ - "geos", - "json-c", - "libiconv", - "libxml2", - "pg_hashids", - "pg_ivm", - "pg_textsearch", - "pg_uuidv7", - "pgtap", - "pgvector", - "postgis", - "proj", - "sqlite", - ]); -}); - -test("npm extension legal inventory binds canonical paths, bytes, and modes", () => { - const row = extensionUpstreamLicenseRows().find(({ sqlName }) => sqlName === "pg_uuidv7"); - assert.ok(row, "pg_uuidv7 must have canonical upstream legal metadata"); - assert.deepEqual( - extensionUpstreamLicenseFileInventory(["pg_uuidv7"]), - row.files.map((file) => ({ - path: file.destination, - sha256: file.sha256, - mode: "0644", - })), - ); - const postgis = extensionUpstreamLicenseFileInventory(["postgis"]); - assert.deepEqual(postgis.map(({ path: member }) => member), [...postgis] - .map(({ path: member }) => member) - .sort()); - assert.equal(Object.isFrozen(postgis), true); - assert.equal(postgis.every(Object.isFrozen), true); - assert.throws( - () => extensionUpstreamLicenseFileInventory([]), - /requires a non-empty unique extension member list/u, - ); -}); - -test("carrier legal inventory binds release notices and PostGIS upstream bytes", () => { - const legal = extensionCarrierLegalContract( - "oliphaunt-extension-postgis", - ["postgis"], - { family: "native", target: "android-arm64-v8a" }, - ); - const files = extensionCarrierLegalFileInventory( - "oliphaunt-extension-postgis", - ["postgis"], - { family: "native", target: "android-arm64-v8a" }, - ); - assert.deepEqual( - files.filter(({ path: file }) => file.startsWith("share/licenses/")) - .map(({ path: file }) => file), - [...legal.licenseFiles], - ); - assert.deepEqual(files.slice(0, 2).map(({ path: file }) => file), [ - "LICENSE", - "THIRD_PARTY_NOTICES.md", - ]); - assert.equal(files.every(({ bytes }) => Number.isSafeInteger(bytes) && bytes > 0), true); - assert.equal(files.every(({ sha256 }) => /^[0-9a-f]{64}$/u.test(sha256)), true); - assert.equal(files.every(({ mode }) => mode === "0644"), true); - assert.equal(Object.isFrozen(files), true); - assert.equal(files.every(Object.isFrozen), true); -}); - -test("each external product owns an exact self-contained legal-data closure", () => { - const externalRoot = path.join(ROOT, "src/extensions/external"); - const files = readdirSync(externalRoot, { withFileTypes: true }) - .filter((entry) => entry.isDirectory()) - .map((entry) => path.join(externalRoot, entry.name, "upstream-license-data.json")) - .filter(existsSync) - .sort(); - assert.equal(files.length, 7); - for (const file of files) { - const data = JSON.parse(readFileSync(file, "utf8")); - const owner = path.basename(path.dirname(file)); - assert.equal(data.extension.sql_name, owner, file); - const referencedSources = [...new Set(data.extension.files.map((row) => row.source))].sort(); - assert.deepEqual(data.sources.map((row) => row.id), referencedSources, file); - const referencedBlobs = [...new Set(data.extension.files.map((row) => row.sha256))].sort(); - assert.deepEqual(Object.keys(data.blobs), referencedBlobs, file); - } - assert.equal(existsSync(path.join(externalRoot, "upstream-licenses.toml")), false); - assert.equal(existsSync(path.join(externalRoot, "upstream-license-blobs.json")), false); -}); - -test("committed legal bytes stage every active external release without source checkouts", (t) => { - const root = mkdtempSync(path.join(tmpdir(), "external-license-clean-stage-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const missingCheckouts = path.join(root, "intentionally-absent-checkouts"); - const script = ` - import { mkdirSync, writeFileSync } from "node:fs"; - import path from "node:path"; - import { createDeterministicTar } from ${JSON.stringify(path.join(ROOT, "tools/release/cargo-source-package.mjs"))}; - import { canonicalGzipSync } from ${JSON.stringify(path.join(ROOT, "src/shared/artifact-packaging/portable-archive.mjs"))}; - import { - assertExtensionUpstreamLicensesInArchive, - assertExtensionUpstreamLicensesInDirectory, - externalReleaseExtensionSqlNames, - stageExtensionUpstreamLicenses, - } from ${JSON.stringify(path.join(ROOT, "tools/release/extension-upstream-licenses.mjs"))}; - const root = process.env.OLIPHAUNT_CLEAN_LEGAL_STAGE; - for (const sqlName of externalReleaseExtensionSqlNames()) { - const stage = path.join(root, sqlName); - mkdirSync(stage, { recursive: true }); - const staged = stageExtensionUpstreamLicenses(sqlName, stage); - const checked = assertExtensionUpstreamLicensesInDirectory([sqlName], stage); - if (JSON.stringify(staged) !== JSON.stringify(checked)) throw new Error(sqlName + " staged legal bytes differ"); - const archive = path.join(root, sqlName + ".tar.gz"); - writeFileSync(archive, canonicalGzipSync(createDeterministicTar(stage, sqlName, { - fail(message) { throw new Error(message); }, - }))); - const packed = assertExtensionUpstreamLicensesInArchive([sqlName], archive, { prefix: sqlName }); - if (JSON.stringify(packed) !== JSON.stringify(staged.map((member) => sqlName + "/" + member))) { - throw new Error(sqlName + " archived legal bytes differ"); - } - } - `; - const result = spawnSync(process.execPath, ["-e", script], { - cwd: ROOT, - encoding: "utf8", - env: { - ...process.env, - OLIPHAUNT_CLEAN_LEGAL_STAGE: root, - OLIPHAUNT_EXTENSION_SOURCE_CHECKOUT_ROOT: missingCheckouts, - }, - }); - assert.equal(result.status, 0, result.stderr || result.stdout); - assert.equal(existsSync(missingCheckouts), false); -}); - -test("available pinned source checkouts match committed legal bytes", () => { - if (!existsSync(path.join(ROOT, "target/oliphaunt-sources/checkouts/pg_hashids/.git"))) return; - assert.ok(auditExtensionUpstreamLicenseSources() > 0); -}); - -test("the contract retains dependency licenses and pgtap's complete upstream grant", () => { - const rows = extensionUpstreamLicenseRows(); - const postgis = rows.find((row) => row.sqlName === "postgis"); - assert.deepEqual([...new Set(postgis.files.map((file) => file.checkout))], [ - "geos", - "json-c", - "libiconv", - "libxml2", - "postgis", - "proj", - "sqlite", - ]); - assert.deepEqual( - postgis.files.filter((file) => file.checkout === "libiconv").map((file) => file.path), - ["libcharset/COPYING.LIB", "COPYING.LIB"], - ); - assert.deepEqual( - postgis.files - .filter((file) => file.checkout === "geos" && file.path.startsWith("src/deps/ryu/")) - .map((file) => file.path), - ["src/deps/ryu/LICENSE", "src/deps/ryu/LICENSE-Apache2", "src/deps/ryu/LICENSE-Boost"], - ); - assert.deepEqual( - postgis.files - .filter((file) => file.checkout === "postgis") - .map((file) => file.path), - [ - "COPYING", - "LICENSE.TXT", - "deps/flatgeobuf/include/flatbuffers/LICENSE", - "deps/ryu/LICENSE", - "deps/ryu/LICENSE-Apache2", - "deps/ryu/LICENSE-Boost", - ], - ); - const pgtap = rows.find((row) => row.sqlName === "pgtap"); - assert.equal(pgtap.files.length, 1); - assert.equal(pgtap.files[0].path, "README.md"); - const source = path.join(ROOT, "target/oliphaunt-sources/checkouts/pgtap/README.md"); - try { - const text = readFileSync(source, "utf8"); - assert.match(text, /Permission to use, copy, modify, and distribute/u); - } catch (error) { - if (error?.code !== "ENOENT") throw error; - } -}); - -test("registry metadata derives external and contrib SPDX expressions from the same contract", () => { - assert.deepEqual( - extensionRegistryLicense("oliphaunt-extension-pg-uuidv7", ["pg_uuidv7"]), - { - product: "oliphaunt-extension-pg-uuidv7", - upstreamSpdx: "MPL-2.0", - packageSpdx: "MIT AND MPL-2.0", - }, - ); - assert.deepEqual( - extensionRegistryLicense("oliphaunt-extension-postgis", ["postgis"]), - { - product: "oliphaunt-extension-postgis", - upstreamSpdx: "MIT AND Apache-2.0 AND GPL-2.0-or-later AND LGPL-2.1-or-later AND blessing", - packageSpdx: "MIT AND Apache-2.0 AND GPL-2.0-or-later AND LGPL-2.1-or-later AND blessing", - }, - ); - assert.deepEqual( - extensionRegistryLicense("oliphaunt-extension-contrib-pg18", ["hstore", "pgcrypto"]), - { - product: "oliphaunt-extension-contrib-pg18", - upstreamSpdx: "PostgreSQL", - packageSpdx: "MIT AND PostgreSQL", - }, - ); - assert.deepEqual( - extensionRegistryLicense("oliphaunt-extension-pg-hashids", ["pg_hashids"]).packageSpdx, - "MIT", - ); - const maven = extensionMavenLicenses( - "oliphaunt-extension-pg-uuidv7", - ["pg_uuidv7"], - { version: "0.1.0" }, - ); - assert.deepEqual(maven.map((entry) => entry.name), ["MIT License (Oliphaunt)", "MPL-2.0 (pg_uuidv7)"]); - assert.match(maven[0].url, /\/blob\/oliphaunt-extension-pg-uuidv7-v0\.1\.0\/LICENSE$/u); - assert.match(maven[1].url, /c707aae2411181be4802f5fa565b44d9c0bcbc29\/LICENSE$/u); -}); - -test("carrier legal roles derive exact contrib and external payload closure", () => { - assert.deepEqual( - extensionCarrierLegalContract( - "oliphaunt-extension-contrib-pg18", - ["hstore", "pgcrypto"], - { family: "native", target: "linux-x64-gnu" }, - ), - { - profile: "contrib-native", - packageSpdx: "MIT AND PostgreSQL", - upstreamMembers: [], - licenseFiles: [], - }, - ); - assert.equal( - extensionCarrierLegalContract( - "oliphaunt-extension-contrib-pg18", - ["hstore", "pgcrypto"], - { family: "wasix", target: "wasix" }, - ).profile, - "contrib-wasix-openssl", - ); - const postgis = extensionCarrierLegalContract( - "oliphaunt-extension-postgis", - ["postgis"], - { family: "native", target: "android-arm64-v8a" }, - ); - assert.equal(postgis.profile, "external-native"); - assert.deepEqual(postgis.upstreamMembers, ["postgis"]); - assert.deepEqual(postgis.licenseFiles, [ - "share/licenses/geos/COPYING", - "share/licenses/geos/src/deps/ryu/LICENSE", - "share/licenses/geos/src/deps/ryu/LICENSE-Apache2", - "share/licenses/geos/src/deps/ryu/LICENSE-Boost", - "share/licenses/json-c/COPYING", - "share/licenses/libcharset/COPYING.LIB", - "share/licenses/libiconv/COPYING.LIB", - "share/licenses/libxml2/Copyright", - "share/licenses/postgis/COPYING", - "share/licenses/postgis/LICENSE.TXT", - "share/licenses/postgis/deps/flatgeobuf/flatbuffers/LICENSE", - "share/licenses/postgis/deps/ryu/LICENSE", - "share/licenses/postgis/deps/ryu/LICENSE-Apache2", - "share/licenses/postgis/deps/ryu/LICENSE-Boost", - "share/licenses/proj/COPYING", - "share/licenses/sqlite/LICENSE.md", - ]); - assert.deepEqual( - extensionCarrierLegalContract( - "oliphaunt-extension-vector", - ["vector"], - { carriesPayload: false }, - ), - { - profile: "code-facade", - packageSpdx: "MIT", - upstreamMembers: [], - licenseFiles: [], - }, - ); -}); - -test("SPDX metadata fails closed to the identifiers supported by the carrier contract", () => { - assert.equal(assertSupportedExtensionUpstreamSpdxId("MPL-2.0"), "MPL-2.0"); - assert.throws( - () => assertSupportedExtensionUpstreamSpdxId("Unknown-License-1.0"), - /must declare one supported SPDX identifier/u, - ); -}); - -test("staging verifies committed bytes, mode, and directory safety", (t) => { - const root = mkdtempSync(path.join(tmpdir(), "extension-license-stage-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const stage = path.join(root, "stage"); - const staged = stageExtensionUpstreamLicenses("pg_hashids", stage); - assert.deepEqual(staged, ["share/licenses/pg_hashids/LICENSE"]); - const output = path.join(stage, staged[0]); - assert.equal(hasCanonicalReleaseStagingMode(lstatSync(output).mode), true); - assert.equal( - createHash("sha256").update(readFileSync(output)).digest("hex"), - extensionUpstreamLicenseRows().find(({ sqlName }) => sqlName === "pg_hashids").files[0].sha256, - ); - assert.deepEqual(assertExtensionUpstreamLicensesInDirectory(["pg_hashids"], stage), staged); - - const archive = path.join(root, "pg-hashids.crate"); - writeFileSync(archive, canonicalGzipSync(createDeterministicTar(stage, "pg-hashids-0.1.0", { - fail(message) { - throw new Error(message); - }, - }))); - assert.deepEqual( - assertExtensionUpstreamLicensesInArchive(["pg_hashids"], archive, { prefix: "pg-hashids-0.1.0" }), - ["pg-hashids-0.1.0/share/licenses/pg_hashids/LICENSE"], - ); - - const entries = readPortableArchiveEntries(archive); - const assertion = (mutated) => assertExtensionUpstreamLicensesInEntries( - ["pg_hashids"], - mutated, - { prefix: "pg-hashids-0.1.0" }, - ); - const inject = (member, entry) => new Map([...entries, [member, entry]]); - const fakeEntry = (overrides = {}) => ({ - data: () => Buffer.from("unexpected"), - isDirectory: false, - isFile: true, - isSymbolicLink: false, - mode: 0o644, - ...overrides, - }); - assert.throws( - () => assertion(inject("pg-hashids-0.1.0/share/licenses/unknown/LICENSE", fakeEntry())), - /unexpected file member/u, - ); - assert.throws( - () => assertion(inject( - "pg-hashids-0.1.0/share/licenses/unknown", - fakeEntry({ isDirectory: true, isFile: false, mode: 0o755 }), - )), - /unexpected directory member/u, - ); - assert.throws( - () => assertion(inject( - "pg-hashids-0.1.0/share/licenses/unknown-link", - fakeEntry({ isFile: false, isSymbolicLink: true, mode: 0o777 }), - )), - /unexpected symlink member/u, - ); - assert.throws( - () => assertion(inject( - "pg-hashids-0.1.0/share/licenses/unknown-special", - fakeEntry({ isFile: false, mode: 0o600 }), - )), - /unexpected special member/u, - ); - const wrongDirectoryMode = new Map(entries); - const directoryMember = "pg-hashids-0.1.0/share/licenses/pg_hashids"; - wrongDirectoryMode.set(directoryMember, { - ...wrongDirectoryMode.get(directoryMember), - mode: 0o700, - }); - assert.throws(() => assertion(wrongDirectoryMode), /directory must be a real mode-0755/u); - - const privilegedFileMode = new Map(entries); - const licenseMember = "pg-hashids-0.1.0/share/licenses/pg_hashids/LICENSE"; - privilegedFileMode.set(licenseMember, { - ...privilegedFileMode.get(licenseMember), - mode: 0o4644, - }); - assert.throws( - () => assertion(privilegedFileMode), - /must be a regular non-symlink mode-0644 file/u, - ); - - const missingAssertionRoot = path.join(root, "missing-parent", "missing-stage"); - assert.throws( - () => assertExtensionUpstreamLicensesInDirectory(["pg_hashids"], missingAssertionRoot), - /upstream license assertion cannot be inspected/u, - ); - assert.equal(existsSync(path.join(root, "missing-parent")), false); - - const unsafe = path.join(root, "unsafe"); - const outside = path.join(root, "outside"); - mkdirSync(unsafe); - mkdirSync(outside); - symlinkSync(outside, path.join(unsafe, "share")); - assert.throws( - () => stageExtensionUpstreamLicenses("pg_hashids", unsafe), - /staging parent must be a real directory/u, - ); - - const realAncestor = path.join(root, "real-ancestor"); - const existingStage = path.join(realAncestor, "existing-stage"); - mkdirSync(existingStage, { recursive: true }); - const linkedAncestor = path.join(root, "linked-ancestor"); - symlinkSync(realAncestor, linkedAncestor); - assert.throws( - () => stageExtensionUpstreamLicenses("pg_hashids", path.join(linkedAncestor, "existing-stage")), - /symlink or non-directory ancestor/u, - ); -}); - -test("the public PostGIS carrier's compiled-component legal atoms are pinned, staged, and exact in archives", (t) => { - const root = mkdtempSync(path.join(tmpdir(), "postgis-license-stage-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const stage = path.join(root, "stage"); - const expected = extensionCarrierLegalContract( - "oliphaunt-extension-postgis", - ["postgis"], - { family: "wasix", target: "wasix-portable" }, - ).licenseFiles; - assert.deepEqual(stageExtensionUpstreamLicenses("postgis", stage), expected); - assert.deepEqual(assertExtensionUpstreamLicensesInDirectory(["postgis"], stage), expected); - - const archive = path.join(root, "postgis.tar.gz"); - writeFileSync(archive, canonicalGzipSync(createDeterministicTar(stage, "postgis", { - fail(message) { - throw new Error(message); - }, - }))); - assert.deepEqual( - assertExtensionUpstreamLicensesInArchive(["postgis"], archive, { prefix: "postgis" }), - expected.map((member) => `postgis/${member}`), - ); -}); diff --git a/tools/release/extension-wasix-npm-packages.test.mjs b/tools/release/extension-wasix-npm-packages.test.mjs deleted file mode 100644 index bc618216a..000000000 --- a/tools/release/extension-wasix-npm-packages.test.mjs +++ /dev/null @@ -1,404 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { zstdCompressSync } from "node:zlib"; -import { afterAll, expect, test } from "bun:test"; - -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { - stageExtensionNpmPackagesForTargets, - stageExtensionWasixNpmPackages, -} from "./package-extension-release-carriers.mjs"; -import { - extensionNpmPackageForProduct, - extensionNpmWasixPackageForProduct, - extensionRegistryPackageEntries, -} from "./extension-registry-packages.mjs"; -import { canonicalGzipSync } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - currentProductVersionSync, - extensionReleaseVersion, - extensionRegistryPackageTargetSets, -} from "./release-artifact-targets.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const directories = []; - -afterAll(() => { - for (const directory of directories) rmSync(directory, { recursive: true, force: true }); -}); - -function temporaryRoot(name) { - const root = mkdtempSync(path.join(os.tmpdir(), name)); - directories.push(root); - return root; -} - -function sha256Bytes(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function deterministicTar(stage, archiveRoot) { - return createDeterministicTar(stage, archiveRoot, { - fail(message) { - throw new Error(message); - }, - fixedFileMode: 0o644, - }); -} - -function portableExtensionBytes(root, sqlName) { - const stage = path.join(root, "portable-members", sqlName); - const control = path.join(stage, "postgresql", "extension", `${sqlName}.control`); - mkdirSync(path.dirname(control), { recursive: true }); - writeFileSync(control, `comment = '${sqlName} fixture'\ndefault_version = '1.0'\n`); - return zstdCompressSync(deterministicTar(stage, "share")); -} - -function compatibility() { - return { - extensionRuntimeContract: "src/shared/extension-runtime-contract/contract.toml", - nativeRuntimeProduct: "liboliphaunt-native", - nativeRuntimeVersion: currentProductVersionSync("liboliphaunt-native", "extension-wasix-npm-packages.test"), - postgresMajor: "18", - wasixRuntimeProduct: "liboliphaunt-wasix", - wasixRuntimeVersion: currentProductVersionSync("liboliphaunt-wasix", "extension-wasix-npm-packages.test"), - }; -} - -function wasixInstall(sqlName, dependencies = []) { - return { - schema: "oliphaunt-wasix-extension-install-v1", - name: sqlName, - nativeModule: null, - nativeModules: [], - coreExportsRequired: [], - dependencies, - loadOrder: [], - lifecycle: { - createExtension: true, - createSchema: "pg_catalog", - loadSql: [], - postCreateSql: [], - startupConfig: [], - preloadRequired: false, - restartRequired: false, - sharedMemoryRequired: false, - }, - installedFiles: [`share/postgresql/extension/${sqlName}.control`], - unresolvedImports: [], - }; -} - -function inventory(sqlName, dependencies = []) { - return { - sqlName, - createsExtension: true, - nativeModuleStem: null, - dependencies, - dataFiles: [], - extensionSqlFileNames: [`${sqlName}.control`], - extensionSqlFilePrefixes: [sqlName], - sharedPreloadLibraries: [], - }; -} - -function singletonFixture(root, { dependencies = ["plpgsql"] } = {}) { - const product = "oliphaunt-extension-pgtap"; - const version = "9.8.7"; - const sqlName = "pgtap"; - const extensionRoot = path.join(root, product); - const releaseAssets = path.join(extensionRoot, "release-assets"); - const name = `${product}-${version}-wasix-portable.tar.zst`; - const archive = path.join(releaseAssets, name); - const bytes = portableExtensionBytes(root, sqlName); - mkdirSync(releaseAssets, { recursive: true }); - writeFileSync(archive, bytes); - const member = inventory(sqlName, dependencies); - member.wasixInstall = wasixInstall(sqlName, dependencies); - const asset = { - name, - family: "wasix", - target: "wasix-portable", - kind: "wasix-runtime", - identity: null, - path: archive, - sha256: sha256Bytes(bytes), - bytes: bytes.length, - }; - const frozenCompatibility = compatibility(); - writeFileSync(path.join(extensionRoot, "extension-artifacts.json"), `${JSON.stringify({ - schema: "oliphaunt-extension-ci-artifacts-v1", - product, - version, - compatibility: frozenCompatibility, - ...member, - assets: [asset], - }, null, 2)}\n`); - writeFileSync(path.join(releaseAssets, `${product}-${version}-manifest.json`), `${JSON.stringify({ - schema: "oliphaunt-extension-release-manifest-v1", - product, - version, - versioning: "upstream-bound", - compatibility: frozenCompatibility, - ...member, - assets: [asset], - }, null, 2)}\n`); - return { extensionRoot, product, sqlName, version }; -} - -function bundleFixture(root) { - const product = "oliphaunt-extension-contrib-pg18"; - const version = extensionReleaseVersion(product, "wasix", "extension-wasix-npm-packages.test"); - const extensionRoot = path.join(root, product); - const releaseAssets = path.join(extensionRoot, "release-assets"); - const archiveRoot = `${product}-${version}-wasix-wasix-portable-bundle`; - const carrierName = `${archiveRoot}.tar.gz`; - const aggregateStage = path.join(root, "aggregate-stage"); - const members = [ - inventory("cube"), - inventory("earthdistance", ["cube"]), - ].map((member) => { - const bytes = portableExtensionBytes(root, member.sqlName); - const name = `${product}-${version}-wasix-portable.tar.zst`; - const memberPath = `extensions/${member.sqlName}/${name}`; - const file = path.join(aggregateStage, ...memberPath.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, bytes); - return { - ...member, - wasixInstall: wasixInstall(member.sqlName, member.dependencies), - assets: [{ - name, - family: "wasix", - target: "wasix-portable", - kind: "wasix-runtime", - identity: null, - path: file, - sha256: sha256Bytes(bytes), - bytes: bytes.length, - carrierAsset: carrierName, - carrierRoot: archiveRoot, - memberPath, - }], - }; - }); - mkdirSync(releaseAssets, { recursive: true }); - const carrier = path.join(releaseAssets, carrierName); - const carrierBytes = canonicalGzipSync(deterministicTar(aggregateStage, archiveRoot)); - writeFileSync(carrier, carrierBytes); - const carrierRow = { - name: carrierName, - family: "wasix", - target: "wasix-portable", - kind: "extension-bundle", - sha256: sha256Bytes(carrierBytes), - bytes: carrierBytes.length, - memberCount: members.length, - }; - const frozenCompatibility = compatibility(); - writeFileSync(path.join(extensionRoot, "extension-artifacts.json"), `${JSON.stringify({ - schema: "oliphaunt-extension-ci-artifacts-v2", - product, - version, - compatibility: frozenCompatibility, - extensions: members, - carrierAssets: [carrierRow], - }, null, 2)}\n`); - writeFileSync(path.join(releaseAssets, `${product}-${version}-manifest.json`), `${JSON.stringify({ - schema: "oliphaunt-extension-release-manifest-v2", - product, - version, - versioning: "runtime-bound", - compatibility: frozenCompatibility, - extensions: members, - assets: [carrierRow], - }, null, 2)}\n`); - return { extensionRoot, product, version }; -} - -function packedTarball(result) { - const tarballs = result.staged.filter((file) => file.endsWith(".tgz")); - expect(tarballs).toHaveLength(1); - return path.isAbsolute(tarballs[0]) ? tarballs[0] : path.join(ROOT, tarballs[0]); -} - -function extractPackage(tarball, root) { - mkdirSync(root, { recursive: true }); - const result = spawnSync("tar", ["-xzf", tarball, "-C", root], { encoding: "utf8" }); - expect(result.status, result.stderr).toBe(0); - return path.join(root, "package"); -} - -function inspectDescriptorWithNode(entrypoint) { - const script = ` -import { createHash } from "node:crypto"; -import { readFileSync } from "node:fs"; -import { pathToFileURL } from "node:url"; -const descriptor = (await import(pathToFileURL(process.env.ENTRYPOINT).href)).default; -if (!Object.isFrozen(descriptor) || !Object.isFrozen(descriptor.carriers)) throw new Error("descriptor is mutable"); -function assertDeepFrozen(value, label) { - if (value !== null && typeof value === "object") { - if (!Object.isFrozen(value)) throw new Error(label + " is mutable"); - for (const [key, child] of Object.entries(value)) assertDeepFrozen(child, label + "." + key); - } -} -assertDeepFrozen(descriptor.compatibility, "compatibility"); -const carriers = descriptor.carriers.map((carrier) => { - if (!Object.isFrozen(carrier)) throw new Error("carrier is mutable"); - assertDeepFrozen(carrier.install, "carrier.install"); - const bytes = readFileSync(carrier.source); - const sha256 = createHash("sha256").update(bytes).digest("hex"); - if (bytes.length !== carrier.size || sha256 !== carrier.sha256) throw new Error("carrier integrity mismatch"); - return { ...carrier, source: carrier.source.href, actualSha256: sha256, actualSize: bytes.length }; -}); -console.log(JSON.stringify({ descriptor: { ...descriptor, carriers }, frozen: true })); -`; - const result = spawnSync("node", ["--input-type=module", "--eval", script], { - encoding: "utf8", - env: { ...process.env, ENTRYPOINT: entrypoint }, - }); - expect(result.status, `${result.stdout}\n${result.stderr}`).toBe(0); - return JSON.parse(result.stdout); -} - -test("derives one explicit WASIX npm identity without renaming the native/default package", () => { - const product = "oliphaunt-extension-pgtap"; - expect(extensionNpmPackageForProduct(product)).toBe("@oliphaunt/extension-pgtap"); - expect(extensionNpmWasixPackageForProduct(product)).toBe("@oliphaunt/extension-pgtap-wasix"); - const identities = extensionRegistryPackageEntries({ - product, - ...extensionRegistryPackageTargetSets(product, "extension-wasix-npm-packages.test"), - }).filter(({ kind }) => kind === "npm").map(({ name }) => name); - expect(identities).toContain("@oliphaunt/extension-pgtap"); - expect(identities).toContain("@oliphaunt/extension-pgtap-wasix"); - expect(identities).not.toContain("@oliphaunt/extension-pgtap-native"); -}); - -test("packs a host-neutral singleton descriptor that Node imports and verifies byte-for-byte", () => { - const root = temporaryRoot("oliphaunt-wasix-npm-singleton-"); - const fixture = singletonFixture(root); - const staging = path.join(root, "staging"); - const result = { staged: [], skipped: [] }; - expect(stageExtensionWasixNpmPackages([fixture.extensionRoot], staging, result)).not.toBeNull(); - expect(result.skipped).toEqual([]); - - const unpacked = extractPackage(packedTarball(result), path.join(root, "unpacked")); - const inspected = inspectDescriptorWithNode(path.join(unpacked, "index.js")); - expect(inspected.frozen).toBe(true); - expect(inspected.descriptor).toMatchObject({ - schema: "oliphaunt-wasix-extension-v1", - runtime: "wasix", - product: fixture.product, - version: fixture.version, - sqlName: fixture.sqlName, - compatibility: { - extensionRuntimeContract: "oliphaunt-extension-runtime-contract-v1", - postgresMajor: "18", - wasixRuntimeProduct: "liboliphaunt-wasix", - }, - }); - expect(inspected.descriptor.carriers.map(({ sqlName }) => sqlName)).toEqual(["pgtap"]); - expect(inspected.descriptor.carriers[0].source).toMatch(/\/extensions\/pgtap\/extension[.]tar[.]zst$/u); - expect(inspected.descriptor.carriers[0].actualSize).toBeGreaterThan(0); - expect(inspected.descriptor.carriers[0].install).toMatchObject({ - schema: "oliphaunt-wasix-extension-install-v1", - dependencies: ["plpgsql"], - installedFiles: ["share/postgresql/extension/pgtap.control"], - }); - - const packageJson = JSON.parse(readFileSync(path.join(unpacked, "package.json"), "utf8")); - expect(packageJson.name).toBe("@oliphaunt/extension-pgtap-wasix"); - expect(packageJson.version).toBe(fixture.version); - expect(packageJson.exports["."].types).toBe("./index.d.ts"); - - const repeated = { staged: [], skipped: [] }; - stageExtensionWasixNpmPackages( - [fixture.extensionRoot], - path.join(root, "staging-repeated"), - repeated, - ); - expect(readFileSync(packedTarball(repeated))).toEqual(readFileSync(packedTarball(result))); -}); - -test("stages one physical WASIX leaf across the complete native target set", () => { - const root = temporaryRoot("oliphaunt-wasix-npm-target-set-"); - const fixture = singletonFixture(root); - const targets = [ - "linux-arm64-gnu", - "linux-x64-gnu", - "macos-arm64", - "windows-x64-msvc", - ]; - const result = { staged: [], skipped: [] }; - const staged = stageExtensionNpmPackagesForTargets( - [fixture.extensionRoot], - path.join(root, "staging"), - targets, - result, - ); - expect(Object.keys(staged.nativeRoots)).toEqual(targets); - expect(Object.values(staged.nativeRoots).every((value) => value === null)).toBe(true); - expect(staged.wasixRoot).not.toBeNull(); - expect(result.staged.filter((file) => file.endsWith(".tgz"))).toHaveLength(1); - - const unpacked = extractPackage(packedTarball(result), path.join(root, "unpacked")); - const packageJson = JSON.parse(readFileSync(path.join(unpacked, "package.json"), "utf8")); - expect(packageJson.name).toBe("@oliphaunt/extension-pgtap-wasix"); - const readme = readFileSync(path.join(unpacked, "README.md"), "utf8"); - expect(readme).toContain("import Oliphaunt from '@oliphaunt/wasix-ts';"); - expect(readme).toContain("import pgtap from '@oliphaunt/extension-pgtap-wasix';"); - expect(readme).toContain("extensions: [pgtap]"); - expect(readme).toContain("This carrier is selected by the binding"); -}); - -test("contrib subpath imports carry their exact transitive dependency closure", () => { - const root = temporaryRoot("oliphaunt-wasix-npm-bundle-"); - const fixture = bundleFixture(root); - const staging = path.join(root, "staging"); - const result = { staged: [], skipped: [] }; - stageExtensionWasixNpmPackages([fixture.extensionRoot], staging, result); - const unpacked = extractPackage(packedTarball(result), path.join(root, "unpacked")); - - const earthdistance = inspectDescriptorWithNode( - path.join(unpacked, "descriptors", "earthdistance.js"), - ).descriptor; - expect(earthdistance.sqlName).toBe("earthdistance"); - expect(earthdistance.carriers.map(({ sqlName }) => sqlName)).toEqual(["cube", "earthdistance"]); - expect(earthdistance.carriers.every(({ actualSha256, sha256 }) => actualSha256 === sha256)).toBe(true); - - const cube = inspectDescriptorWithNode(path.join(unpacked, "descriptors", "cube.js")).descriptor; - expect(cube.carriers.map(({ sqlName }) => sqlName)).toEqual(["cube"]); - const packageJson = JSON.parse(readFileSync(path.join(unpacked, "package.json"), "utf8")); - expect(packageJson.exports["."]).toBeUndefined(); - expect(Object.keys(packageJson.exports).sort()).toEqual(["./cube", "./earthdistance", "./package.json"]); - expect(packageJson.oliphaunt.memberExports).toEqual({ - cube: "./cube", - earthdistance: "./earthdistance", - }); - const readme = readFileSync(path.join(unpacked, "README.md"), "utf8"); - expect(readme).toContain(`import cube from '${packageJson.name}/cube';`); - expect(readme).toContain( - `import earthdistance from '${packageJson.name}/earthdistance';`, - ); - expect(readme).toContain("extensions: [cube, earthdistance]"); -}); - -test("fails closed instead of publishing an incomplete cross-product descriptor", () => { - const root = temporaryRoot("oliphaunt-wasix-npm-cross-product-"); - const fixture = singletonFixture(root, { dependencies: ["vector"] }); - expect(() => stageExtensionWasixNpmPackages( - [fixture.extensionRoot], - path.join(root, "staging"), - { staged: [], skipped: [] }, - )).toThrow(/unsupported cross-product or unavailable WASIX dependency "vector"/u); -}); diff --git a/tools/release/extract-node-headers.mjs b/tools/release/extract-node-headers.mjs deleted file mode 100644 index de4d13214..000000000 --- a/tools/release/extract-node-headers.mjs +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/env node - -import { - mkdirSync, - readFileSync, - readdirSync, - statSync, - writeFileSync, -} from 'node:fs'; -import path from 'node:path'; -import process from 'node:process'; -import {gunzipSync} from 'node:zlib'; - -const BLOCK_SIZE = 512; -const MAX_ARCHIVE_BYTES = 64 * 1024 * 1024; -const MAX_EXPANDED_BYTES = 256 * 1024 * 1024; -const MAX_FILE_BYTES = 32 * 1024 * 1024; -const MAX_ENTRIES = 20_000; -const REQUIRED_HEADERS = [ - 'include/node/node_api.h', - 'include/node/node.h', - 'include/node/v8.h', -]; - -function fail(message) { - throw new Error(message); -} - -function fieldString(block, start, length, label) { - const field = block.subarray(start, start + length); - const nul = field.indexOf(0); - const used = nul === -1 ? field : field.subarray(0, nul); - if (nul !== -1 && field.subarray(nul).some((byte) => byte !== 0)) { - fail(`tar ${label} contains bytes after its NUL terminator`); - } - if (used.some((byte) => byte < 0x20 || byte > 0x7e)) { - fail(`tar ${label} must contain printable ASCII only`); - } - return used.toString('ascii'); -} - -function octalField(block, start, length, label) { - const field = block.subarray(start, start + length); - if ((field[0] ?? 0) >= 0x80) { - fail(`tar ${label} uses unsupported base-256 encoding`); - } - const text = field.toString('ascii').replaceAll('\0', '').trim(); - if (text === '') { - return 0; - } - if (!/^[0-7]+$/u.test(text)) { - fail(`tar ${label} is not an octal value`); - } - const value = Number.parseInt(text, 8); - if (!Number.isSafeInteger(value) || value < 0) { - fail(`tar ${label} exceeds the supported integer range`); - } - return value; -} - -function verifyHeaderChecksum(block) { - const expected = octalField(block, 148, 8, 'checksum'); - let actual = 0; - for (let index = 0; index < BLOCK_SIZE; index += 1) { - actual += index >= 148 && index < 156 ? 0x20 : block[index]; - } - if (actual !== expected) { - fail(`tar header checksum mismatch: expected ${expected}, received ${actual}`); - } -} - -function archivePath(block) { - const name = fieldString(block, 0, 100, 'name'); - const prefix = fieldString(block, 345, 155, 'prefix'); - return prefix === '' ? name : `${prefix}/${name}`; -} - -function safeRelativePath(rawPath, expectedRoot, type) { - if (rawPath === '' || rawPath.includes('\\') || rawPath.startsWith('/')) { - fail(`unsafe tar path: ${rawPath || ''}`); - } - if (/^[A-Za-z]:/u.test(rawPath) || /[\u0000-\u001f\u007f]/u.test(rawPath)) { - fail(`unsafe tar path: ${rawPath}`); - } - - const withoutTrailingSlash = type === 'directory' && rawPath.endsWith('/') - ? rawPath.slice(0, -1) - : rawPath; - if (withoutTrailingSlash === '' || withoutTrailingSlash.endsWith('/')) { - fail(`unsafe tar path: ${rawPath}`); - } - - const parts = withoutTrailingSlash.split('/'); - if (parts.some((part) => part === '' || part === '.' || part === '..')) { - fail(`unsafe tar path: ${rawPath}`); - } - if (parts[0] !== expectedRoot) { - fail(`tar entry is outside the expected ${expectedRoot}/ root: ${rawPath}`); - } - - const relativeParts = parts.slice(1); - if (relativeParts.length === 0 && type !== 'directory') { - fail(`tar root entry must be a directory: ${rawPath}`); - } - for (const part of relativeParts) { - if (part.endsWith('.') || part.endsWith(' ') || part.includes(':')) { - fail(`tar path is not portable across release hosts: ${rawPath}`); - } - } - return relativeParts.join('/'); -} - -function isZeroBlock(block) { - return block.every((byte) => byte === 0); -} - -function parseArchive(expanded, expectedRoot) { - const entries = []; - const paths = new Map(); - let offset = 0; - let zeroBlocks = 0; - let expandedFileBytes = 0; - let pendingLongName = null; - - while (offset + BLOCK_SIZE <= expanded.length) { - const block = expanded.subarray(offset, offset + BLOCK_SIZE); - offset += BLOCK_SIZE; - if (isZeroBlock(block)) { - zeroBlocks += 1; - if (zeroBlocks === 2) { - if (!expanded.subarray(offset).every((byte) => byte === 0)) { - fail('tar archive contains data after its end marker'); - } - break; - } - continue; - } - if (zeroBlocks !== 0) { - fail('tar archive contains an isolated zero block'); - } - - verifyHeaderChecksum(block); - const typeFlag = block[156]; - const size = octalField(block, 124, 12, 'size'); - if (size > MAX_FILE_BYTES) { - fail(`tar entry exceeds the ${MAX_FILE_BYTES}-byte per-file limit`); - } - if (offset + size > expanded.length) { - fail('tar entry payload is truncated'); - } - const data = expanded.subarray(offset, offset + size); - offset += Math.ceil(size / BLOCK_SIZE) * BLOCK_SIZE; - - if (typeFlag === 0x4c) { - if (pendingLongName !== null) { - fail('tar archive contains consecutive GNU long-name records'); - } - if (archivePath(block) !== '././@LongLink' || size < 2 || size > 4096 || data.at(-1) !== 0) { - fail('tar archive contains an invalid GNU long-name record'); - } - const nameBytes = data.subarray(0, -1); - if (nameBytes.includes(0) || nameBytes.some((byte) => byte < 0x20 || byte > 0x7e)) { - fail('tar GNU long-name record must contain printable ASCII and one trailing NUL'); - } - pendingLongName = nameBytes.toString('ascii'); - continue; - } - - const type = typeFlag === 0 || typeFlag === 0x30 - ? 'file' - : typeFlag === 0x35 - ? 'directory' - : null; - if (type === null) { - const printableType = typeFlag >= 0x20 && typeFlag <= 0x7e - ? String.fromCharCode(typeFlag) - : `0x${typeFlag.toString(16).padStart(2, '0')}`; - fail(`tar entry type ${printableType} is not a regular file or directory`); - } - - if (type === 'directory' && size !== 0) { - fail('tar directory entry must have size zero'); - } - expandedFileBytes += size; - if (expandedFileBytes > MAX_EXPANDED_BYTES) { - fail(`tar file payloads exceed the ${MAX_EXPANDED_BYTES}-byte total limit`); - } - - const relativePath = safeRelativePath(pendingLongName ?? archivePath(block), expectedRoot, type); - pendingLongName = null; - const collisionKey = relativePath.toLowerCase(); - if (paths.has(collisionKey)) { - fail(`tar archive contains a duplicate or case-colliding path: ${relativePath || expectedRoot}`); - } - paths.set(collisionKey, type); - - if (entries.length >= MAX_ENTRIES) { - fail(`tar archive exceeds the ${MAX_ENTRIES}-entry limit`); - } - entries.push({data, relativePath, size, type}); - } - - if (zeroBlocks < 2) { - fail('tar archive is missing its two-block end marker'); - } - if (pendingLongName !== null) { - fail('tar archive ends with an unapplied GNU long-name record'); - } - - for (const entry of entries) { - const parts = entry.relativePath === '' ? [] : entry.relativePath.split('/'); - for (let index = 1; index < parts.length; index += 1) { - const parent = parts.slice(0, index).join('/').toLowerCase(); - if (paths.get(parent) === 'file') { - fail(`tar path has a regular-file parent: ${entry.relativePath}`); - } - } - } - - for (const required of REQUIRED_HEADERS) { - const entry = entries.find((candidate) => candidate.relativePath === required); - if (entry === undefined || entry.type !== 'file' || entry.size === 0) { - fail(`Node headers archive is missing non-empty ${required}`); - } - } - return entries; -} - -function extract(entries, destination) { - const destinationRoot = path.resolve(destination); - mkdirSync(destinationRoot, {recursive: true, mode: 0o755}); - if (readdirSync(destinationRoot).length !== 0) { - fail(`Node headers extraction destination is not empty: ${destinationRoot}`); - } - - const targetPath = (relativePath) => { - const target = path.resolve(destinationRoot, ...relativePath.split('/')); - if (target !== destinationRoot && !target.startsWith(`${destinationRoot}${path.sep}`)) { - fail(`resolved tar path escapes extraction root: ${relativePath}`); - } - return target; - }; - - for (const entry of entries.filter((candidate) => candidate.type === 'directory')) { - if (entry.relativePath !== '') { - mkdirSync(targetPath(entry.relativePath), {recursive: true, mode: 0o755}); - } - } - for (const entry of entries.filter((candidate) => candidate.type === 'file')) { - const target = targetPath(entry.relativePath); - mkdirSync(path.dirname(target), {recursive: true, mode: 0o755}); - writeFileSync(target, entry.data, {flag: 'wx', mode: 0o644}); - } -} - -function main() { - const [archive, destination, expectedRoot] = process.argv.slice(2); - if (archive === undefined || destination === undefined || expectedRoot === undefined || process.argv.length !== 5) { - fail('usage: tools/release/extract-node-headers.mjs '); - } - if (!/^node-v[0-9]+\.[0-9]+\.[0-9]+$/u.test(expectedRoot)) { - fail(`invalid expected Node headers root: ${expectedRoot}`); - } - const archiveSize = statSync(archive).size; - if (archiveSize <= 0 || archiveSize > MAX_ARCHIVE_BYTES) { - fail(`Node headers archive size must be between 1 and ${MAX_ARCHIVE_BYTES} bytes`); - } - const compressed = readFileSync(archive); - let expanded; - try { - expanded = gunzipSync(compressed, {maxOutputLength: MAX_EXPANDED_BYTES}); - } catch (error) { - fail(`could not decompress bounded Node headers archive: ${error.message}`); - } - extract(parseArchive(expanded, expectedRoot), destination); -} - -try { - main(); -} catch (error) { - console.error(`Node headers extraction failed: ${error.message}`); - process.exit(1); -} diff --git a/tools/release/finalize-native-mobile-abi-proofs.mjs b/tools/release/finalize-native-mobile-abi-proofs.mjs deleted file mode 100644 index c9fbfcf20..000000000 --- a/tools/release/finalize-native-mobile-abi-proofs.mjs +++ /dev/null @@ -1,172 +0,0 @@ -#!/usr/bin/env bun - -import { spawnSync } from "node:child_process"; -import { - chmodSync, - cpSync, - lstatSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - renameSync, - rmSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { - compareNativeMobileAbiReceipts, - NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN, - parseNativeMobileAbiReceipt, -} from "./native-mobile-abi-contract.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -function fail(message) { - throw new Error(`finalize-native-mobile-abi-proofs.mjs: ${message}`); -} - -function receiptFiles(root) { - const files = []; - const visit = (directory) => { - for (const name of readdirSync(directory).sort()) { - const file = path.join(directory, name); - const metadata = lstatSync(file); - if (metadata.isSymbolicLink()) fail(`receipt input contains a symbolic link: ${file}`); - if (metadata.isDirectory()) visit(file); - else if (metadata.isFile() && /^native-mobile-abi(?:-producer)?\.properties$/u.test(name)) { - files.push(file); - } - } - }; - visit(root); - return files; -} - -function loadDomainReceipts(domain, root) { - const required = NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[domain]; - if (required === undefined) fail(`unsupported compatibility domain ${domain}`); - const byTarget = new Map(); - for (const file of receiptFiles(root)) { - const text = readFileSync(file, "utf8"); - const target = parseNativeMobileAbiReceipt(text, file).get("target"); - if (!required.includes(target)) continue; - const existing = byTarget.get(target); - if (existing !== undefined && existing.text !== text) { - fail(`${domain} has divergent duplicate receipts for ${target}: ${existing.file}, ${file}`); - } - if (existing === undefined) byTarget.set(target, { file, text }); - } - const missing = required.filter((target) => !byTarget.has(target)); - if (missing.length > 0) fail(`${domain} is missing receipts for ${missing.join(", ")}`); - const receipts = required.map((target) => ({ - label: byTarget.get(target).file, - text: byTarget.get(target).text, - })); - compareNativeMobileAbiReceipts(domain, receipts); - return new Map(required.map((target) => [target, byTarget.get(target).text])); -} - -function materializeArchive(archive, destination) { - for (const [rawName, entry] of readPortableArchiveEntries(archive)) { - const name = rawName.replace(/\/$/u, ""); - if (name === "." || name.length === 0) continue; - const output = path.join(destination, ...name.split("/")); - if (entry.isDirectory) { - mkdirSync(output, { recursive: true }); - continue; - } - if (!entry.isFile || entry.isSymbolicLink) { - fail(`${archive} contains unsupported member ${rawName}`); - } - mkdirSync(path.dirname(output), { recursive: true }); - writeFileSync(output, entry.data()); - chmodSync(output, (entry.mode ?? 0o644) & 0o777); - } -} - -function finalizeArchive(archive, receipts) { - const work = mkdtempSync(path.join(tmpdir(), "oliphaunt-mobile-abi-proof-")); - const staging = path.join(work, "carrier"); - const output = `${archive}.tmp-${process.pid}.tar.gz`; - try { - mkdirSync(staging); - materializeArchive(archive, staging); - const proof = path.join(staging, "oliphaunt/provenance/native-mobile-abi"); - rmSync(proof, { recursive: true, force: true }); - mkdirSync(proof, { recursive: true }); - for (const [target, text] of receipts) { - writeFileSync(path.join(proof, `${target}.properties`), text); - } - const archiveScript = path.resolve( - import.meta.dirname, - "../../src/shared/artifact-packaging/archive-directory.mjs", - ); - const result = spawnSync(process.execPath, [archiveScript, staging, output], { - stdio: "inherit", - }); - if (result.status !== 0) fail(`failed to rebuild ${archive}`); - renameSync(output, archive); - } finally { - rmSync(output, { force: true }); - rmSync(work, { recursive: true, force: true }); - } -} - -export function finalizeNativeMobileAbiProofs({ domain, assetDir, receiptRoot, outputDir = assetDir }) { - const receipts = loadDomainReceipts(domain, receiptRoot); - const suffix = `-runtime-resources-${domain}.tar.gz`; - const archives = readdirSync(assetDir) - .filter((name) => name.endsWith(suffix)) - .map((name) => path.join(assetDir, name)); - if (archives.length !== 1) { - fail(`${assetDir} must contain exactly one *${suffix}; found ${archives.length}`); - } - const sourceArchive = archives[0]; - let outputArchive = sourceArchive; - if (path.resolve(outputDir) !== path.resolve(assetDir)) { - rmSync(outputDir, {recursive: true, force: true}); - cpSync(assetDir, outputDir, {recursive: true}); - outputArchive = path.join(outputDir, path.basename(sourceArchive)); - } - finalizeArchive(outputArchive, receipts); - return { archive: outputArchive, targets: [...receipts.keys()] }; -} - -function parseArgs(argv) { - const values = new Map(); - for (let index = 0; index < argv.length; index += 2) { - const key = argv[index]; - const value = argv[index + 1]; - if (!key?.startsWith("--") || value === undefined || values.has(key)) { - fail("usage: --domain DOMAIN --asset-dir DIR --receipt-root DIR [--output-dir DIR]"); - } - values.set(key, value); - } - if ( - (values.size !== 3 && values.size !== 4) - || !values.has("--domain") - || !values.has("--asset-dir") - || !values.has("--receipt-root") - ) { - fail("usage: --domain DOMAIN --asset-dir DIR --receipt-root DIR"); - } - return { - domain: values.get("--domain"), - assetDir: path.resolve(values.get("--asset-dir")), - receiptRoot: path.resolve(values.get("--receipt-root")), - outputDir: values.has("--output-dir") ? path.resolve(values.get("--output-dir")) : undefined, - }; -} - -if (import.meta.main) { - try { - const result = finalizeNativeMobileAbiProofs(parseArgs(process.argv.slice(2))); - console.log(`nativeMobileAbiProofArchive=${result.archive}`); - console.log(`nativeMobileAbiProofTargets=${result.targets.join(",")}`); - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(2); - } -} diff --git a/tools/release/finalize-native-mobile-abi-proofs.test.mjs b/tools/release/finalize-native-mobile-abi-proofs.test.mjs deleted file mode 100644 index d462617db..000000000 --- a/tools/release/finalize-native-mobile-abi-proofs.test.mjs +++ /dev/null @@ -1,133 +0,0 @@ -import { expect, test } from "bun:test"; -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { writeEntriesArchive } from "../test/release-fixture-utils.mjs"; -import { finalizeNativeMobileAbiProofs } from "./finalize-native-mobile-abi-proofs.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -function receipt(target, blockSize = 8192) { - return [ - "schema=oliphaunt-native-mobile-abi-v1", - `target=${target}`, - "byteOrder=little", - "datumBytes=8", - "maximumAlignof=8", - "float8ByVal=1", - `blockSize=${blockSize}`, - "walBlockSize=8192", - "relationSegmentSize=131072", - "nameDataLength=64", - "indexMaxKeys=32", - "catalogVersion=202506291", - "pgControlVersion=1800", - "", - ].join("\n"); -} - -function writeReceipt(root, directory, name, text) { - const target = path.join(root, directory); - mkdirSync(target, { recursive: true }); - writeFileSync(path.join(target, name), text); -} - -async function fixture() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-mobile-proof-test-")); - const assetDir = path.join(root, "assets"); - const receiptRoot = path.join(root, "receipts"); - mkdirSync(assetDir); - mkdirSync(receiptRoot); - const archive = path.join( - assetDir, - "liboliphaunt-1.2.3-runtime-resources-android-datum64.tar.gz", - ); - await writeEntriesArchive(archive, { "oliphaunt/runtime/files/value": "value\n" }); - writeReceipt( - receiptRoot, - "arm", - "native-mobile-abi.properties", - receipt("android-arm64-v8a"), - ); - writeReceipt( - receiptRoot, - "x86", - "native-mobile-abi.properties", - receipt("android-x86_64"), - ); - const producer = receipt("linux-x64-gnu"); - writeReceipt(receiptRoot, "arm", "native-mobile-abi-producer.properties", producer); - writeReceipt(receiptRoot, "x86", "native-mobile-abi-producer.properties", producer); - return { root, assetDir, receiptRoot, archive }; -} - -test("finalizes one domain with exact deterministic proof members", async () => { - const current = await fixture(); - try { - finalizeNativeMobileAbiProofs({ - domain: "android-datum64", - assetDir: current.assetDir, - receiptRoot: current.receiptRoot, - }); - const first = readFileSync(current.archive); - const proofPrefix = "oliphaunt/provenance/native-mobile-abi/"; - const proofMembers = [...readPortableArchiveEntries(current.archive).keys()] - .filter((name) => name.startsWith(proofPrefix) && name.endsWith(".properties")) - .sort(); - expect(proofMembers).toEqual([ - `${proofPrefix}android-arm64-v8a.properties`, - `${proofPrefix}android-x86_64.properties`, - `${proofPrefix}linux-x64-gnu.properties`, - ]); - - finalizeNativeMobileAbiProofs({ - domain: "android-datum64", - assetDir: current.assetDir, - receiptRoot: current.receiptRoot, - }); - expect(readFileSync(current.archive)).toEqual(first); - } finally { - rmSync(current.root, { recursive: true, force: true }); - } -}); - -test("rejects divergent duplicate producer receipts", async () => { - const current = await fixture(); - try { - writeReceipt( - current.receiptRoot, - "x86", - "native-mobile-abi-producer.properties", - receipt("linux-x64-gnu", 4096), - ); - expect(() => finalizeNativeMobileAbiProofs({ - domain: "android-datum64", - assetDir: current.assetDir, - receiptRoot: current.receiptRoot, - })).toThrow(/divergent duplicate receipts/u); - } finally { - rmSync(current.root, { recursive: true, force: true }); - } -}); - -test("can finalize an immutable input archive into a separately owned output", async () => { - const current = await fixture(); - try { - const baseArchive = path.join(current.assetDir, "liboliphaunt-1.2.3-android-x86_64.tar.gz"); - writeFileSync(baseArchive, "base carrier"); - const before = readFileSync(current.archive); - const outputDir = path.join(current.root, "final"); - const result = finalizeNativeMobileAbiProofs({ - domain: "android-datum64", - assetDir: current.assetDir, - receiptRoot: current.receiptRoot, - outputDir, - }); - expect(readFileSync(current.archive)).toEqual(before); - expect(result.archive).toBe(path.join(outputDir, path.basename(current.archive))); - expect(readFileSync(result.archive)).not.toEqual(before); - expect(readFileSync(path.join(outputDir, path.basename(baseArchive)), "utf8")).toBe("base carrier"); - } finally { - rmSync(current.root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/finalize-native-runtime-carrier.mjs b/tools/release/finalize-native-runtime-carrier.mjs deleted file mode 100644 index ee3637fa4..000000000 --- a/tools/release/finalize-native-runtime-carrier.mjs +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env node - -import { spawnSync } from "node:child_process"; -import { - existsSync, - lstatSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { - bindNativeRuntimeResourceManifest, - nativeRuntimeCarrierManifest, - validateNativeRuntimeCarrier, -} from "./native-runtime-carrier-contract.mjs"; - -function fail(message) { - throw new Error(`finalize-native-runtime-carrier.mjs: ${message}`); -} - -function treeBytes(root) { - const metadata = lstatSync(root); - if (metadata.isSymbolicLink()) fail(`carrier tree must not contain symlinks: ${root}`); - if (metadata.isFile()) return metadata.size; - if (!metadata.isDirectory()) fail(`carrier tree contains a special file: ${root}`); - return readdirSync(root).reduce((total, name) => total + treeBytes(path.join(root, name)), 0); -} - -function rewritePackageSizeReport(root) { - const report = path.join(root, "package-size.tsv"); - const rows = readFileSync(report, "utf8").split(/\r?\n/u).filter(Boolean); - if (rows.shift() !== "kind\tid\textensions\tfiles\tbytes") { - fail(`${report} has an unsupported header`); - } - const retained = rows.filter((row) => !row.startsWith("package\t")); - const runtime = treeBytes(path.join(root, "runtime/files")); - const standard = treeBytes(path.join(root, "cluster-seed/files")); - const icu = treeBytes(path.join(root, "cluster-seed-icu/files")); - const staticRegistry = treeBytes(path.join(root, "static-registry")); - const total = runtime + standard + icu + staticRegistry; - writeFileSync(report, [ - "kind\tid\textensions\tfiles\tbytes", - `package\ttotal\t-\t-\t${total}`, - `package\truntime\t-\t-\t${runtime}`, - `package\tcluster-seed\t-\t-\t${standard}`, - `package\tcluster-seed-icu\t-\t-\t${icu}`, - `package\tstatic-registry\t-\t-\t${staticRegistry}`, - ...retained, - "", - ].join("\n")); -} - -function materializeDesktopRuntimeManifest(runtimeSource, embeddedModules, target) { - const scratch = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-runtime-manifest-")); - try { - const result = spawnSync("cargo", [ - "run", "-p", "oliphaunt-native-packaging", "--bin", "oliphaunt-resources", "--locked", "--", - "--output", scratch, - "--mode", "native-direct", - "--force", - ], { - cwd: path.resolve(import.meta.dirname, "../.."), - env: { - ...process.env, - OLIPHAUNT_INSTALL_DIR: runtimeSource, - OLIPHAUNT_EMBEDDED_MODULE_DIR: embeddedModules, - }, - encoding: "utf8", - maxBuffer: 64 * 1024 * 1024, - }); - if (result.status !== 0) { - fail(`native-direct runtime manifest producer failed: ${(result.stderr || result.stdout || "").trim()}`); - } - return bindNativeRuntimeResourceManifest( - readFileSync(path.join(scratch, "oliphaunt/runtime/manifest.properties")), - target, - ); - } finally { - rmSync(scratch, { recursive: true, force: true }); - } -} - -export function finalizeNativeRuntimeCarrier( - root, - target, - icuData, - { runtimeSource, embeddedModules } = {}, -) { - writeFileSync(path.join(root, "manifest.properties"), nativeRuntimeCarrierManifest(target)); - const runtimeManifest = path.join(root, "runtime/manifest.properties"); - if (existsSync(runtimeManifest)) { - writeFileSync( - runtimeManifest, - bindNativeRuntimeResourceManifest(readFileSync(runtimeManifest), target), - ); - } else if (runtimeSource !== undefined && embeddedModules !== undefined) { - writeFileSync( - runtimeManifest, - materializeDesktopRuntimeManifest(runtimeSource, embeddedModules, target), - ); - } else { - fail(`${runtimeManifest} is missing`); - } - if (existsSync(path.join(root, "package-size.tsv"))) rewritePackageSizeReport(root); - return validateNativeRuntimeCarrier(root, { icuData }); -} - -function parseArgs(argv) { - const values = new Map(); - for (let index = 0; index < argv.length; index += 2) { - const key = argv[index]; - const value = argv[index + 1]; - if (!key?.startsWith("--") || value === undefined || values.has(key)) { - fail("usage: --root DIR --target TARGET --icu-data DIR [--runtime-source DIR --embedded-modules DIR]"); - } - values.set(key, value); - } - const allowed = new Set(["--root", "--target", "--icu-data", "--runtime-source", "--embedded-modules"]); - if ([...values.keys()].some((key) => !allowed.has(key)) - || !values.has("--root") - || !values.has("--target") - || !values.has("--icu-data") - || values.has("--runtime-source") !== values.has("--embedded-modules")) { - fail("usage: --root DIR --target TARGET --icu-data DIR [--runtime-source DIR --embedded-modules DIR]"); - } - return { - root: path.resolve(values.get("--root")), - target: values.get("--target"), - icuData: path.resolve(values.get("--icu-data")), - runtimeSource: values.has("--runtime-source") - ? path.resolve(values.get("--runtime-source")) - : undefined, - embeddedModules: values.has("--embedded-modules") - ? path.resolve(values.get("--embedded-modules")) - : undefined, - }; -} - -if (import.meta.main) { - try { - const args = parseArgs(process.argv.slice(2)); - const result = finalizeNativeRuntimeCarrier(args.root, args.target, args.icuData, args); - console.log(`clusterSeedTarget=${result.target}`); - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(2); - } -} diff --git a/tools/release/frozen-cargo-publish.mjs b/tools/release/frozen-cargo-publish.mjs deleted file mode 100644 index ca0d3e24c..000000000 --- a/tools/release/frozen-cargo-publish.mjs +++ /dev/null @@ -1,490 +0,0 @@ -import { readFileSync } from "node:fs"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { RegistryPublicationDeferredError } from "./registry-publication-deferral.mjs"; -import { retryAfterSeconds } from "./registry-http-retry.mjs"; - -const DEFAULT_CRATES_IO_API = "https://crates.io/api/v1"; -const MAX_U32 = 0xffff_ffff; -const UPLOAD_TIMEOUT_MS = 60_000; -const MAX_RATE_LIMIT_RETRIES = 3; -// Without a caller deadline, retain a bounded fallback wait. Hosted publishers -// use their mutation deadline so a normal ten-minute refill can finish in place. -const MAX_RATE_LIMIT_WAIT_SECONDS = 9 * 60; -const MAX_RESPONSE_BYTES = 64 * 1024; -const RATE_LIMIT_CLOCK_SKEW_MS = 2_000; -const DEADLINE_RESERVE_MS = 5_000; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function error(message) { - return new Error(`frozen-cargo-publish: ${message}`); -} - -function commandOutput(args, context) { - const result = captureCommandOutput(args[0], args.slice(1), { - label: context, - maxOutputBytes: 32 * 1024 * 1024, - }); - if (result.error !== undefined || result.status !== 0) { - const detail = (result.stderr || result.error?.message || "").trim(); - throw error(`${context} failed${detail ? `: ${detail}` : ""}`); - } - return result.stdout; -} - -function checkedArchiveMember(rawMember, cratePath) { - const directory = rawMember.endsWith("/"); - const member = directory ? rawMember.slice(0, -1) : rawMember; - if ( - member.length === 0 - || member.includes("\\") - || member.includes("\0") - || member.startsWith("/") - || /^[A-Za-z]:/u.test(member) - ) { - throw error(`${cratePath} contains unsafe archive member ${JSON.stringify(rawMember)}`); - } - const parts = member.split("/"); - if (parts.some((part) => part.length === 0 || part === "." || part === "..")) { - throw error(`${cratePath} contains unsafe archive member ${JSON.stringify(rawMember)}`); - } - return { directory, member: parts.join("/"), parts }; -} - -function crateArchiveLayout(cratePath) { - const rawMembers = commandOutput(["tar", "-tzf", cratePath], `list ${cratePath}`) - .split(/\r?\n/u) - .filter(Boolean); - if (rawMembers.length === 0) { - throw error(`${cratePath} is empty`); - } - const members = rawMembers.map((member) => checkedArchiveMember(member, cratePath)); - const seen = new Set(); - for (const { member } of members) { - if (seen.has(member)) { - throw error(`${cratePath} repeats archive member ${member}`); - } - seen.add(member); - } - const roots = [...new Set(members.map(({ parts }) => parts[0]))]; - if (roots.length !== 1) { - throw error(`${cratePath} must contain exactly one top-level crate root, found ${roots.length}`); - } - const manifestMembers = members.filter(({ directory, parts }) => - !directory && parts.length === 2 && parts[1] === "Cargo.toml"); - if (manifestMembers.length !== 1) { - throw error( - `${cratePath} must contain exactly one top-level crate Cargo.toml, found ${manifestMembers.length}`, - ); - } - return { - root: roots[0], - manifestMember: manifestMembers[0].member, - files: new Set(members.filter(({ directory }) => !directory).map(({ member }) => member)), - }; -} - -function archiveMemberText(cratePath, member) { - return commandOutput(["tar", "-xOzf", cratePath, "--", member], `read ${member} from ${cratePath}`); -} - -function relativeArchivePath(value, context) { - if ( - value.length === 0 - || value.includes("\\") - || value.includes("\0") - || value.startsWith("/") - || /^[A-Za-z]:/u.test(value) - ) { - throw error(`${context} must be a portable relative path inside the crate: ${value}`); - } - const parts = value.split("/"); - if (parts.some((part) => part.length === 0 || part === "." || part === "..")) { - throw error(`${context} must be a portable relative path inside the crate: ${value}`); - } - return parts.join("/"); -} - -function optionalString(value, context) { - if (value === undefined || value === null || value === false) { - return null; - } - if (typeof value !== "string") { - throw error(`${context} must be a string when present`); - } - return value; -} - -function stringList(value, context) { - if (value === undefined) { - return []; - } - if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) { - throw error(`${context} must be a string list`); - } - return value; -} - -function dependencyRows(table, { kind, target }) { - if (table === undefined) { - return []; - } - if (table === null || Array.isArray(table) || typeof table !== "object") { - throw error(`${target ?? "root"} ${kind} dependencies must be a table`); - } - return Object.entries(table).map(([alias, value]) => { - const dependency = typeof value === "string" ? { version: value } : value; - if (dependency === null || Array.isArray(dependency) || typeof dependency !== "object") { - throw error(`dependency ${alias} must be a version string or table`); - } - if (typeof dependency.version !== "string" || dependency.version.length === 0) { - throw error(`dependency ${alias} in a packaged crate must have a registry version`); - } - for (const forbidden of ["git", "path", "registry", "registry-index"]) { - if (dependency[forbidden] !== undefined) { - throw error(`dependency ${alias} retains forbidden ${forbidden} source metadata`); - } - } - const renamedPackage = optionalString(dependency.package, `dependency ${alias}.package`); - const artifactValue = dependency.artifact; - const artifact = artifactValue === undefined - ? undefined - : stringList(Array.isArray(artifactValue) ? artifactValue : [artifactValue], `dependency ${alias}.artifact`); - const bindepTarget = optionalString(dependency.target, `dependency ${alias}.target`); - return { - optional: dependency.optional === true, - default_features: dependency["default-features"] !== false, - name: renamedPackage ?? alias, - features: stringList(dependency.features, `dependency ${alias}.features`), - version_req: dependency.version, - target, - kind, - ...(renamedPackage === null ? {} : { explicit_name_in_toml: alias }), - ...(artifact === undefined ? {} : { artifact }), - ...(bindepTarget === null ? {} : { bindep_target: bindepTarget }), - ...(dependency.lib === true ? { lib: true } : {}), - }; - }); -} - -function packageDependencies(manifest) { - const dependencies = [ - ...dependencyRows(manifest.dependencies, { kind: "normal", target: null }), - ...dependencyRows(manifest["build-dependencies"], { kind: "build", target: null }), - ...dependencyRows(manifest["dev-dependencies"], { kind: "dev", target: null }), - ]; - const targets = manifest.target ?? {}; - if (targets === null || Array.isArray(targets) || typeof targets !== "object") { - throw error("target dependencies must be a table"); - } - for (const [target, tables] of Object.entries(targets)) { - if (tables === null || Array.isArray(tables) || typeof tables !== "object") { - throw error(`target ${target} must be a table`); - } - dependencies.push( - ...dependencyRows(tables.dependencies, { kind: "normal", target }), - ...dependencyRows(tables["build-dependencies"], { kind: "build", target }), - ...dependencyRows(tables["dev-dependencies"], { kind: "dev", target }), - ); - } - return dependencies.sort((left, right) => - compareText( - `${left.target ?? ""}:${left.kind}:${left.name}:${left.explicit_name_in_toml ?? ""}`, - `${right.target ?? ""}:${right.kind}:${right.name}:${right.explicit_name_in_toml ?? ""}`, - )); -} - -function stringMapOfLists(value, context) { - if (value === undefined) { - return {}; - } - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(`${context} must be a table`); - } - return Object.fromEntries(Object.entries(value).map(([name, members]) => [ - name, - stringList(members, `${context}.${name}`), - ])); -} - -function badges(value) { - if (value === undefined) { - return {}; - } - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error("badges must be a table"); - } - return Object.fromEntries(Object.entries(value).map(([name, fields]) => { - if (fields === null || Array.isArray(fields) || typeof fields !== "object") { - throw error(`badge ${name} must be a table`); - } - const entries = Object.entries(fields); - if (entries.some(([, field]) => typeof field !== "string")) { - throw error(`badge ${name} fields must be strings`); - } - return [name, Object.fromEntries(entries)]; - })); -} - -export function cargoPublishMetadataFromCrate(cratePath) { - const layout = crateArchiveLayout(cratePath); - const manifestMember = layout.manifestMember; - let manifest; - try { - manifest = Bun.TOML.parse(archiveMemberText(cratePath, manifestMember)); - } catch (cause) { - throw error(`cannot parse packaged Cargo.toml from ${cratePath}: ${cause.message}`); - } - const pkg = manifest.package; - if (pkg === null || Array.isArray(pkg) || typeof pkg !== "object") { - throw error(`${cratePath} packaged Cargo.toml must contain [package]`); - } - if (typeof pkg.name !== "string" || typeof pkg.version !== "string") { - throw error(`${cratePath} packaged Cargo.toml must define package name and version`); - } - const expectedRoot = `${pkg.name}-${pkg.version}`; - if (layout.root !== expectedRoot) { - throw error( - `${cratePath} top-level crate root must be ${expectedRoot}, found ${layout.root}`, - ); - } - const readmeFile = optionalString(pkg.readme, "package.readme"); - let readme = null; - if (readmeFile !== null) { - const readmeMember = `${layout.root}/${relativeArchivePath(readmeFile, "package.readme")}`; - if (!layout.files.has(readmeMember)) { - throw error(`${cratePath} does not contain declared README ${readmeFile}`); - } - readme = archiveMemberText(cratePath, readmeMember); - } - return { - name: pkg.name, - vers: pkg.version, - deps: packageDependencies(manifest), - features: stringMapOfLists(manifest.features, "features"), - authors: stringList(pkg.authors, "package.authors"), - description: optionalString(pkg.description, "package.description"), - documentation: optionalString(pkg.documentation, "package.documentation"), - homepage: optionalString(pkg.homepage, "package.homepage"), - readme, - readme_file: readmeFile, - keywords: stringList(pkg.keywords, "package.keywords"), - categories: stringList(pkg.categories, "package.categories"), - license: optionalString(pkg.license, "package.license"), - license_file: optionalString(pkg["license-file"], "package.license-file"), - repository: optionalString(pkg.repository, "package.repository"), - badges: badges(manifest.badges), - links: optionalString(pkg.links, "package.links"), - rust_version: optionalString(pkg["rust-version"], "package.rust-version"), - }; -} - -export function encodeCargoPublishRequest(metadata, crateBytes) { - const json = Buffer.from(JSON.stringify(metadata), "utf8"); - const bytes = Buffer.from(crateBytes); - if (json.length > MAX_U32 || bytes.length > MAX_U32) { - throw error("publish metadata or crate exceeds the registry protocol u32 length limit"); - } - const jsonLength = Buffer.allocUnsafe(4); - jsonLength.writeUInt32LE(json.length); - const crateLength = Buffer.allocUnsafe(4); - crateLength.writeUInt32LE(bytes.length); - return Buffer.concat([jsonLength, json, crateLength, bytes]); -} - -function responseDetail(body) { - try { - const parsed = JSON.parse(body); - const details = parsed?.errors?.map?.((item) => item?.detail).filter((item) => typeof item === "string"); - if (details?.length > 0) { - return details.join("; ").slice(0, 500); - } - } catch { - // Fall through to the bounded plain-text diagnostic. - } - return body.replace(/[\r\n\t]+/gu, " ").trim().slice(0, 500); -} - -function cargoPublishResponse(body, identity) { - if (body.length === 0) { - return { warnings: { invalid_categories: [], invalid_badges: [], other: [] } }; - } - let value; - try { - value = JSON.parse(body); - } catch (cause) { - throw error(`registry upload returned invalid JSON: ${cause.message}`); - } - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error("registry upload success response must be a JSON object"); - } - if (Object.hasOwn(value, "errors")) { - const details = Array.isArray(value.errors) - ? value.errors.map((item) => item?.detail).filter((item) => typeof item === "string" && item.length > 0) - : []; - throw error( - `registry rejected ${identity} despite HTTP success${details.length > 0 ? `: ${details.join("; ").slice(0, 500)}` : ": malformed errors response"}`, - ); - } - const warnings = value.warnings ?? {}; - if (warnings === null || Array.isArray(warnings) || typeof warnings !== "object") { - throw error("registry upload warnings must be an object when present"); - } - const normalized = {}; - for (const field of ["invalid_categories", "invalid_badges", "other"]) { - const messages = warnings[field] ?? []; - if (!Array.isArray(messages) || messages.some((message) => typeof message !== "string")) { - throw error(`registry upload warnings.${field} must be a string list`); - } - normalized[field] = messages; - } - for (const category of normalized.invalid_categories) { - console.warn(`crates.io ignored invalid category for ${identity}: ${category}`); - } - for (const badge of normalized.invalid_badges) { - console.warn(`crates.io ignored invalid badge for ${identity}: ${badge}`); - } - for (const warning of normalized.other) { - console.warn(`crates.io warning for ${identity}: ${warning}`); - } - return { ...value, warnings: normalized }; -} - -async function boundedResponseText(response, identity) { - const contentLength = response.headers.get("content-length"); - if (contentLength !== null) { - const declared = Number(contentLength); - if (Number.isFinite(declared) && declared > MAX_RESPONSE_BYTES) { - await response.body?.cancel?.().catch(() => {}); - throw error(`registry response for ${identity} exceeds ${MAX_RESPONSE_BYTES} bytes`); - } - } - if (response.body?.getReader === undefined) { - const text = await response.text(); - if (Buffer.byteLength(text) > MAX_RESPONSE_BYTES) { - throw error(`registry response for ${identity} exceeds ${MAX_RESPONSE_BYTES} bytes`); - } - return text; - } - const reader = response.body.getReader(); - const chunks = []; - let size = 0; - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > MAX_RESPONSE_BYTES) { - await reader.cancel().catch(() => {}); - throw error(`registry response for ${identity} exceeds ${MAX_RESPONSE_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - return Buffer.concat(chunks).toString("utf8"); -} - -export async function publishFrozenCargoCrate({ - cratePath, - expectedName, - expectedVersion, - token, - apiBase = process.env.CRATES_IO_API ?? DEFAULT_CRATES_IO_API, - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = Date.now, - deadlineEpochMs = undefined, - maxRateLimitRetries = MAX_RATE_LIMIT_RETRIES, -}) { - if (typeof token !== "string" || token.length === 0) { - throw error("CARGO_REGISTRY_TOKEN is required"); - } - if ( - deadlineEpochMs !== undefined - && (!Number.isSafeInteger(deadlineEpochMs) || deadlineEpochMs <= 0) - ) { - throw error("registry mutation deadline must be a positive Unix timestamp in milliseconds"); - } - if (!Number.isSafeInteger(maxRateLimitRetries) || maxRateLimitRetries < 0 || maxRateLimitRetries > 10) { - throw error("maxRateLimitRetries must be an integer from 0 through 10"); - } - const metadata = cargoPublishMetadataFromCrate(cratePath); - if (metadata.name !== expectedName || metadata.vers !== expectedVersion) { - throw error( - `${cratePath} identifies ${metadata.name}@${metadata.vers}, expected ${expectedName}@${expectedVersion}`, - ); - } - const body = encodeCargoPublishRequest(metadata, readFileSync(cratePath)); - const url = `${apiBase.replace(/\/+$/u, "")}/crates/new`; - const identity = `${metadata.name}@${metadata.vers}`; - for (let rateLimitAttempt = 0; ; rateLimitAttempt += 1) { - const now = nowImpl(); - if (deadlineEpochMs !== undefined && now + DEADLINE_RESERVE_MS >= deadlineEpochMs) { - throw new RegistryPublicationDeferredError({ - reason: "deadline", - notBeforeEpochSeconds: Math.floor(now / 1000) + 1, - context: `registry mutation deadline expired before uploading ${identity}`, - }); - } - const timeoutMs = deadlineEpochMs === undefined - ? UPLOAD_TIMEOUT_MS - : Math.min(UPLOAD_TIMEOUT_MS, Math.max(1, deadlineEpochMs - now - DEADLINE_RESERVE_MS)); - const response = await fetchImpl(url, { - method: "PUT", - headers: { - Accept: "application/json", - Authorization: token, - "Content-Type": "application/octet-stream", - "User-Agent": "oliphaunt-frozen-publisher/1; https://github.com/f0rr0/oliphaunt", - }, - body, - redirect: "error", - signal: AbortSignal.timeout(timeoutMs), - }); - const responseBody = await boundedResponseText(response, identity); - if (response.ok) { - return cargoPublishResponse(responseBody, identity); - } - const detail = responseDetail(responseBody); - if (response.status !== 429) { - throw error(`registry upload for ${identity} returned HTTP ${response.status}${detail ? `: ${detail}` : ""}`); - } - - // crates.io checks its leaky bucket before storing a rejected upload and - // returns the next permitted time in Retry-After. That explicit 429 is the - // only failed mutation response that is safe to replay automatically. All - // transport and other HTTP failures remain ambiguous and return to the - // caller for an immutable-version registry check. - const retryAfter = retryAfterSeconds(response.headers, now); - if (retryAfter === null || !Number.isFinite(retryAfter)) { - throw error(`registry rate limited ${identity} without a valid Retry-After header${detail ? `: ${detail}` : ""}`); - } - const delayMs = Math.ceil(retryAfter * 1000) + RATE_LIMIT_CLOCK_SKEW_MS; - if (rateLimitAttempt >= maxRateLimitRetries) { - throw new RegistryPublicationDeferredError({ - reason: "rate-limit", - notBeforeEpochSeconds: Math.ceil((now + delayMs) / 1000), - context: `crates.io rejected ${identity} ${rateLimitAttempt + 1} times with valid Retry-After headers`, - }); - } - if (deadlineEpochMs === undefined && retryAfter > MAX_RATE_LIMIT_WAIT_SECONDS) { - throw new RegistryPublicationDeferredError({ - reason: "rate-limit", - notBeforeEpochSeconds: Math.ceil((now + delayMs) / 1000), - context: `crates.io rejected ${identity} with a valid Retry-After beyond the bounded in-process wait`, - }); - } - if (deadlineEpochMs !== undefined && now + delayMs + DEADLINE_RESERVE_MS >= deadlineEpochMs) { - throw new RegistryPublicationDeferredError({ - reason: "rate-limit", - notBeforeEpochSeconds: Math.ceil((now + delayMs) / 1000), - context: `crates.io rejected ${identity} and its valid Retry-After cannot clear before the bounded registry mutation deadline`, - }); - } - console.warn( - `crates.io rate limited ${identity}; retrying the exact frozen bytes after ${Math.ceil(delayMs / 1000)}s`, - ); - await sleepImpl(delayMs); - } -} diff --git a/tools/release/frozen-cargo-publish.mts b/tools/release/frozen-cargo-publish.mts new file mode 100644 index 000000000..794e7d724 --- /dev/null +++ b/tools/release/frozen-cargo-publish.mts @@ -0,0 +1,464 @@ +import { readFileSync } from 'node:fs'; + +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { retryAfterSeconds } from './registry-http-retry.mts'; +import { RegistryPublicationDeferredError } from './registry-publication-deferral.mts'; + +const DEFAULT_CRATES_IO_API = 'https://crates.io/api/v1'; +const MAX_U32 = 0xffff_ffff; +const UPLOAD_TIMEOUT_MS = 60_000; +const MAX_RATE_LIMIT_RETRIES = 3; +// Without a caller deadline, retain a bounded fallback wait. Hosted publishers +// use their mutation deadline so a normal ten-minute refill can finish in place. +const MAX_RATE_LIMIT_WAIT_SECONDS = 9 * 60; +const MAX_RESPONSE_BYTES = 64 * 1024; +const RATE_LIMIT_CLOCK_SKEW_MS = 2_000; +const DEADLINE_RESERVE_MS = 5_000; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function error(message) { + return new Error(`frozen-cargo-publish: ${message}`); +} + +function crateArchiveLayout(cratePath) { + const entries = readPortableArchiveEntries(cratePath); + const roots = [...new Set([...entries.keys()].map((name) => name.split('/')[0]))]; + if (roots.length !== 1) { + throw error( + `${cratePath} must contain exactly one top-level crate root, found ${roots.length}`, + ); + } + const root = roots[0]; + const manifest = entries.get(`${root}/Cargo.toml`); + if (!manifest?.isFile) { + throw error(`${cratePath} must contain exactly one top-level crate Cargo.toml`); + } + return { root, manifest, entries }; +} + +function relativeArchivePath(value, context) { + if ( + value.length === 0 || + value.includes('\\') || + value.includes('\0') || + value.startsWith('/') || + /^[A-Za-z]:/u.test(value) + ) { + throw error(`${context} must be a portable relative path inside the crate: ${value}`); + } + const parts = value.split('/'); + if (parts.some((part) => part.length === 0 || part === '.' || part === '..')) { + throw error(`${context} must be a portable relative path inside the crate: ${value}`); + } + return parts.join('/'); +} + +function optionalString(value, context) { + if (value === undefined || value === null || value === false) { + return null; + } + if (typeof value !== 'string') { + throw error(`${context} must be a string when present`); + } + return value; +} + +function stringList(value, context) { + if (value === undefined) { + return []; + } + if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) { + throw error(`${context} must be a string list`); + } + return value; +} + +function dependencyRows(table, { kind, target }) { + if (table === undefined) { + return []; + } + if (table === null || Array.isArray(table) || typeof table !== 'object') { + throw error(`${target ?? 'root'} ${kind} dependencies must be a table`); + } + return Object.entries(table).map(([alias, value]) => { + const dependency = typeof value === 'string' ? { version: value } : value; + if (dependency === null || Array.isArray(dependency) || typeof dependency !== 'object') { + throw error(`dependency ${alias} must be a version string or table`); + } + if (typeof dependency.version !== 'string' || dependency.version.length === 0) { + throw error(`dependency ${alias} in a packaged crate must have a registry version`); + } + for (const forbidden of ['git', 'path', 'registry', 'registry-index']) { + if (dependency[forbidden] !== undefined) { + throw error(`dependency ${alias} retains forbidden ${forbidden} source metadata`); + } + } + const renamedPackage = optionalString(dependency.package, `dependency ${alias}.package`); + const artifactValue = dependency.artifact; + const artifact = + artifactValue === undefined + ? undefined + : stringList( + Array.isArray(artifactValue) ? artifactValue : [artifactValue], + `dependency ${alias}.artifact`, + ); + const bindepTarget = optionalString(dependency.target, `dependency ${alias}.target`); + return { + optional: dependency.optional === true, + default_features: dependency['default-features'] !== false, + name: renamedPackage ?? alias, + features: stringList(dependency.features, `dependency ${alias}.features`), + version_req: dependency.version, + target, + kind, + ...(renamedPackage === null ? {} : { explicit_name_in_toml: alias }), + ...(artifact === undefined ? {} : { artifact }), + ...(bindepTarget === null ? {} : { bindep_target: bindepTarget }), + ...(dependency.lib === true ? { lib: true } : {}), + }; + }); +} + +function packageDependencies(manifest) { + const dependencies = [ + ...dependencyRows(manifest.dependencies, { kind: 'normal', target: null }), + ...dependencyRows(manifest['build-dependencies'], { kind: 'build', target: null }), + ...dependencyRows(manifest['dev-dependencies'], { kind: 'dev', target: null }), + ]; + const targets = manifest.target ?? {}; + if (targets === null || Array.isArray(targets) || typeof targets !== 'object') { + throw error('target dependencies must be a table'); + } + for (const [target, tables] of Object.entries(targets)) { + if (tables === null || Array.isArray(tables) || typeof tables !== 'object') { + throw error(`target ${target} must be a table`); + } + dependencies.push( + ...dependencyRows(tables.dependencies, { kind: 'normal', target }), + ...dependencyRows(tables['build-dependencies'], { kind: 'build', target }), + ...dependencyRows(tables['dev-dependencies'], { kind: 'dev', target }), + ); + } + return dependencies.sort((left, right) => + compareText( + `${left.target ?? ''}:${left.kind}:${left.name}:${left.explicit_name_in_toml ?? ''}`, + `${right.target ?? ''}:${right.kind}:${right.name}:${right.explicit_name_in_toml ?? ''}`, + ), + ); +} + +function stringMapOfLists(value, context) { + if (value === undefined) { + return {}; + } + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw error(`${context} must be a table`); + } + return Object.fromEntries( + Object.entries(value).map(([name, members]) => [ + name, + stringList(members, `${context}.${name}`), + ]), + ); +} + +function badges(value) { + if (value === undefined) { + return {}; + } + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw error('badges must be a table'); + } + return Object.fromEntries( + Object.entries(value).map(([name, fields]) => { + if (fields === null || Array.isArray(fields) || typeof fields !== 'object') { + throw error(`badge ${name} must be a table`); + } + const entries = Object.entries(fields); + if (entries.some(([, field]) => typeof field !== 'string')) { + throw error(`badge ${name} fields must be strings`); + } + return [name, Object.fromEntries(entries)]; + }), + ); +} + +export function cargoPublishMetadataFromCrate(cratePath) { + const layout = crateArchiveLayout(cratePath); + let manifest; + try { + manifest = Bun.TOML.parse( + new TextDecoder('utf-8', { fatal: true }).decode(layout.manifest.data()), + ); + } catch (cause) { + throw error(`cannot parse packaged Cargo.toml from ${cratePath}: ${cause.message}`); + } + const pkg = manifest.package; + if (pkg === null || Array.isArray(pkg) || typeof pkg !== 'object') { + throw error(`${cratePath} packaged Cargo.toml must contain [package]`); + } + if (typeof pkg.name !== 'string' || typeof pkg.version !== 'string') { + throw error(`${cratePath} packaged Cargo.toml must define package name and version`); + } + const expectedRoot = `${pkg.name}-${pkg.version}`; + if (layout.root !== expectedRoot) { + throw error(`${cratePath} top-level crate root must be ${expectedRoot}, found ${layout.root}`); + } + const readmeFile = optionalString(pkg.readme, 'package.readme'); + let readme = null; + if (readmeFile !== null) { + const readmeMember = `${layout.root}/${relativeArchivePath(readmeFile, 'package.readme')}`; + if (!layout.entries.get(readmeMember)?.isFile) { + throw error(`${cratePath} does not contain declared README ${readmeFile}`); + } + readme = new TextDecoder('utf-8', { fatal: true }).decode( + layout.entries.get(readmeMember).data(), + ); + } + return { + name: pkg.name, + vers: pkg.version, + deps: packageDependencies(manifest), + features: stringMapOfLists(manifest.features, 'features'), + authors: stringList(pkg.authors, 'package.authors'), + description: optionalString(pkg.description, 'package.description'), + documentation: optionalString(pkg.documentation, 'package.documentation'), + homepage: optionalString(pkg.homepage, 'package.homepage'), + readme, + readme_file: readmeFile, + keywords: stringList(pkg.keywords, 'package.keywords'), + categories: stringList(pkg.categories, 'package.categories'), + license: optionalString(pkg.license, 'package.license'), + license_file: optionalString(pkg['license-file'], 'package.license-file'), + repository: optionalString(pkg.repository, 'package.repository'), + badges: badges(manifest.badges), + links: optionalString(pkg.links, 'package.links'), + rust_version: optionalString(pkg['rust-version'], 'package.rust-version'), + }; +} + +export function encodeCargoPublishRequest(metadata, crateBytes) { + const json = Buffer.from(JSON.stringify(metadata), 'utf8'); + const bytes = Buffer.from(crateBytes); + if (json.length > MAX_U32 || bytes.length > MAX_U32) { + throw error('publish metadata or crate exceeds the registry protocol u32 length limit'); + } + const jsonLength = Buffer.allocUnsafe(4); + jsonLength.writeUInt32LE(json.length); + const crateLength = Buffer.allocUnsafe(4); + crateLength.writeUInt32LE(bytes.length); + return Buffer.concat([jsonLength, json, crateLength, bytes]); +} + +function responseDetail(body) { + try { + const parsed = JSON.parse(body); + const details = parsed?.errors + ?.map?.((item) => item?.detail) + .filter((item) => typeof item === 'string'); + if (details?.length > 0) { + return details.join('; ').slice(0, 500); + } + } catch { + // Fall through to the bounded plain-text diagnostic. + } + return body + .replace(/[\r\n\t]+/gu, ' ') + .trim() + .slice(0, 500); +} + +function cargoPublishResponse(body, identity) { + if (body.length === 0) { + return { warnings: { invalid_categories: [], invalid_badges: [], other: [] } }; + } + let value; + try { + value = JSON.parse(body); + } catch (cause) { + throw error(`registry upload returned invalid JSON: ${cause.message}`); + } + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw error('registry upload success response must be a JSON object'); + } + if (Object.hasOwn(value, 'errors')) { + const details = Array.isArray(value.errors) + ? value.errors + .map((item) => item?.detail) + .filter((item) => typeof item === 'string' && item.length > 0) + : []; + throw error( + `registry rejected ${identity} despite HTTP success${details.length > 0 ? `: ${details.join('; ').slice(0, 500)}` : ': malformed errors response'}`, + ); + } + const warnings = value.warnings ?? {}; + if (warnings === null || Array.isArray(warnings) || typeof warnings !== 'object') { + throw error('registry upload warnings must be an object when present'); + } + const normalized = {}; + for (const field of ['invalid_categories', 'invalid_badges', 'other']) { + const messages = warnings[field] ?? []; + if (!Array.isArray(messages) || messages.some((message) => typeof message !== 'string')) { + throw error(`registry upload warnings.${field} must be a string list`); + } + normalized[field] = messages; + } + for (const category of normalized.invalid_categories) { + console.warn(`crates.io ignored invalid category for ${identity}: ${category}`); + } + for (const badge of normalized.invalid_badges) { + console.warn(`crates.io ignored invalid badge for ${identity}: ${badge}`); + } + for (const warning of normalized.other) { + console.warn(`crates.io warning for ${identity}: ${warning}`); + } + return { ...value, warnings: normalized }; +} + +async function boundedResponseText(response, identity) { + const contentLength = response.headers.get('content-length'); + if (contentLength !== null) { + const declared = Number(contentLength); + if (Number.isFinite(declared) && declared > MAX_RESPONSE_BYTES) { + await response.body?.cancel?.().catch(() => {}); + throw error(`registry response for ${identity} exceeds ${MAX_RESPONSE_BYTES} bytes`); + } + } + if (response.body?.getReader === undefined) { + const text = await response.text(); + if (Buffer.byteLength(text) > MAX_RESPONSE_BYTES) { + throw error(`registry response for ${identity} exceeds ${MAX_RESPONSE_BYTES} bytes`); + } + return text; + } + const reader = response.body.getReader(); + const chunks = []; + let size = 0; + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > MAX_RESPONSE_BYTES) { + await reader.cancel().catch(() => {}); + throw error(`registry response for ${identity} exceeds ${MAX_RESPONSE_BYTES} bytes`); + } + chunks.push(Buffer.from(value)); + } + return Buffer.concat(chunks).toString('utf8'); +} + +export async function publishFrozenCargoCrate({ + cratePath, + expectedName, + expectedVersion, + token, + apiBase = process.env.CRATES_IO_API ?? DEFAULT_CRATES_IO_API, + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + nowImpl = Date.now, + deadlineEpochMs = undefined, + maxRateLimitRetries = MAX_RATE_LIMIT_RETRIES, +}) { + if (typeof token !== 'string' || token.length === 0) { + throw error('CARGO_REGISTRY_TOKEN is required'); + } + if ( + deadlineEpochMs !== undefined && + (!Number.isSafeInteger(deadlineEpochMs) || deadlineEpochMs <= 0) + ) { + throw error('registry mutation deadline must be a positive Unix timestamp in milliseconds'); + } + if ( + !Number.isSafeInteger(maxRateLimitRetries) || + maxRateLimitRetries < 0 || + maxRateLimitRetries > 10 + ) { + throw error('maxRateLimitRetries must be an integer from 0 through 10'); + } + const metadata = cargoPublishMetadataFromCrate(cratePath); + if (metadata.name !== expectedName || metadata.vers !== expectedVersion) { + throw error( + `${cratePath} identifies ${metadata.name}@${metadata.vers}, expected ${expectedName}@${expectedVersion}`, + ); + } + const body = encodeCargoPublishRequest(metadata, readFileSync(cratePath)); + const url = `${apiBase.replace(/\/+$/u, '')}/crates/new`; + const identity = `${metadata.name}@${metadata.vers}`; + for (let rateLimitAttempt = 0; ; rateLimitAttempt += 1) { + const now = nowImpl(); + if (deadlineEpochMs !== undefined && now + DEADLINE_RESERVE_MS >= deadlineEpochMs) { + throw new RegistryPublicationDeferredError({ + reason: 'deadline', + notBeforeEpochSeconds: Math.floor(now / 1000) + 1, + context: `registry mutation deadline expired before uploading ${identity}`, + }); + } + const timeoutMs = + deadlineEpochMs === undefined + ? UPLOAD_TIMEOUT_MS + : Math.min(UPLOAD_TIMEOUT_MS, Math.max(1, deadlineEpochMs - now - DEADLINE_RESERVE_MS)); + const response = await fetchImpl(url, { + method: 'PUT', + headers: { + Accept: 'application/json', + Authorization: token, + 'Content-Type': 'application/octet-stream', + 'User-Agent': 'oliphaunt-frozen-publisher/1; https://github.com/f0rr0/oliphaunt', + }, + body, + redirect: 'error', + signal: AbortSignal.timeout(timeoutMs), + }); + const responseBody = await boundedResponseText(response, identity); + if (response.ok) { + return cargoPublishResponse(responseBody, identity); + } + const detail = responseDetail(responseBody); + if (response.status !== 429) { + throw error( + `registry upload for ${identity} returned HTTP ${response.status}${detail ? `: ${detail}` : ''}`, + ); + } + + // crates.io checks its leaky bucket before storing a rejected upload and + // returns the next permitted time in Retry-After. That explicit 429 is the + // only failed mutation response that is safe to replay automatically. All + // transport and other HTTP failures remain ambiguous and return to the + // caller for an immutable-version registry check. + const retryAfter = retryAfterSeconds(response.headers, now); + if (retryAfter === null || !Number.isFinite(retryAfter)) { + throw error( + `registry rate limited ${identity} without a valid Retry-After header${detail ? `: ${detail}` : ''}`, + ); + } + const delayMs = Math.ceil(retryAfter * 1000) + RATE_LIMIT_CLOCK_SKEW_MS; + if (rateLimitAttempt >= maxRateLimitRetries) { + throw new RegistryPublicationDeferredError({ + reason: 'rate-limit', + notBeforeEpochSeconds: Math.ceil((now + delayMs) / 1000), + context: `crates.io rejected ${identity} ${rateLimitAttempt + 1} times with valid Retry-After headers`, + }); + } + if (deadlineEpochMs === undefined && retryAfter > MAX_RATE_LIMIT_WAIT_SECONDS) { + throw new RegistryPublicationDeferredError({ + reason: 'rate-limit', + notBeforeEpochSeconds: Math.ceil((now + delayMs) / 1000), + context: `crates.io rejected ${identity} with a valid Retry-After beyond the bounded in-process wait`, + }); + } + if (deadlineEpochMs !== undefined && now + delayMs + DEADLINE_RESERVE_MS >= deadlineEpochMs) { + throw new RegistryPublicationDeferredError({ + reason: 'rate-limit', + notBeforeEpochSeconds: Math.ceil((now + delayMs) / 1000), + context: `crates.io rejected ${identity} and its valid Retry-After cannot clear before the bounded registry mutation deadline`, + }); + } + console.warn( + `crates.io rate limited ${identity}; retrying the exact frozen bytes after ${Math.ceil(delayMs / 1000)}s`, + ); + await sleepImpl(delayMs); + } +} diff --git a/tools/release/frozen-cargo-publish.test.mjs b/tools/release/frozen-cargo-publish.test.mjs deleted file mode 100644 index 3ad6d29e8..000000000 --- a/tools/release/frozen-cargo-publish.test.mjs +++ /dev/null @@ -1,358 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { - cargoPublishMetadataFromCrate, - encodeCargoPublishRequest, - publishFrozenCargoCrate, -} from "./frozen-cargo-publish.mjs"; -import { - isRegistryPublicationDeferredError, -} from "./registry-publication-deferral.mjs"; - -const temporaryDirectories = []; - -function cargoFixture({ - archiveRoot = "fixture-crate-1.2.3", - duplicateManifest = false, - nestedManifest = false, - pathDependency = false, -} = {}) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-frozen-cargo-")); - temporaryDirectories.push(root); - const packageRoot = path.join(root, archiveRoot); - mkdirSync(path.join(packageRoot, "src"), { recursive: true }); - writeFileSync(path.join(packageRoot, "README.md"), "# Frozen fixture\n"); - writeFileSync(path.join(packageRoot, "src/lib.rs"), "pub const FROZEN: bool = true;\n"); - writeFileSync(path.join(packageRoot, "Cargo.toml"), `[package] -name = "fixture-crate" -version = "1.2.3" -edition = "2024" -rust-version = "1.85" -authors = ["Oliphaunt Maintainers"] -description = "Frozen publication fixture" -documentation = "https://docs.rs/fixture-crate" -homepage = "https://oliphaunt.dev" -readme = "README.md" -keywords = ["postgres"] -categories = ["database"] -license = "MIT OR Apache-2.0" -repository = "https://github.com/f0rr0/oliphaunt" -links = "fixture_native" - -[lib] -path = "src/lib.rs" - -[dependencies.serde_alias] -version = "1" -package = "serde" -features = ["derive"] -optional = true -default-features = false -${pathDependency ? "path = \"../serde\"" : ""} - -[target.'cfg(unix)'.build-dependencies.cc] -version = "1.1" - -[features] -default = ["serde_alias"] - -[badges.maintenance] -status = "actively-developed" -`); - if (nestedManifest) { - mkdirSync(path.join(packageRoot, "examples", "nested-crate", "src"), { recursive: true }); - writeFileSync( - path.join(packageRoot, "examples", "nested-crate", "Cargo.toml"), - '[package]\nname = "nested-crate"\nversion = "0.1.0"\n', - ); - writeFileSync(path.join(packageRoot, "examples", "nested-crate", "src", "lib.rs"), ""); - } - const cratePath = path.join(root, "fixture-crate-1.2.3.crate"); - const archiveOperands = [archiveRoot]; - if (duplicateManifest) archiveOperands.push(`${archiveRoot}/Cargo.toml`); - const result = spawnSync("tar", ["-czf", cratePath, "-C", root, ...archiveOperands], { - encoding: "utf8", - }); - if (result.status !== 0) { - throw new Error(result.stderr || `tar exited ${result.status}`); - } - return cratePath; -} - -afterEach(() => { - while (temporaryDirectories.length > 0) { - rmSync(temporaryDirectories.pop(), { recursive: true, force: true }); - } -}); - -describe("frozen Cargo registry publication", () => { - test("derives Cargo Publish API metadata from the packaged manifest", () => { - const metadata = cargoPublishMetadataFromCrate(cargoFixture()); - expect(metadata).toMatchObject({ - name: "fixture-crate", - vers: "1.2.3", - authors: ["Oliphaunt Maintainers"], - description: "Frozen publication fixture", - readme: "# Frozen fixture\n", - readme_file: "README.md", - license: "MIT OR Apache-2.0", - rust_version: "1.85", - features: { default: ["serde_alias"] }, - badges: { maintenance: { status: "actively-developed" } }, - }); - expect(metadata.deps).toEqual([ - { - optional: true, - default_features: false, - name: "serde", - features: ["derive"], - version_req: "1", - target: null, - kind: "normal", - explicit_name_in_toml: "serde_alias", - }, - { - optional: false, - default_features: true, - name: "cc", - features: [], - version_req: "1.1", - target: "cfg(unix)", - kind: "build", - }, - ]); - }); - - test("selects the canonical crate manifest while allowing packaged nested Cargo manifests", () => { - const metadata = cargoPublishMetadataFromCrate(cargoFixture({ nestedManifest: true })); - expect(metadata).toMatchObject({ name: "fixture-crate", vers: "1.2.3" }); - }); - - test("rejects ambiguous members and a top-level crate root that disagrees with package identity", () => { - expect(() => cargoPublishMetadataFromCrate(cargoFixture({ duplicateManifest: true }))).toThrow( - "repeats archive member fixture-crate-1.2.3/Cargo.toml", - ); - expect(() => cargoPublishMetadataFromCrate(cargoFixture({ archiveRoot: "substituted-root" }))).toThrow( - "top-level crate root must be fixture-crate-1.2.3, found substituted-root", - ); - }); - - test("encodes and uploads the exact supplied crate bytes with the raw Cargo token", async () => { - const cratePath = cargoFixture(); - const crateBytes = readFileSync(cratePath); - let request = null; - const result = await publishFrozenCargoCrate({ - cratePath, - expectedName: "fixture-crate", - expectedVersion: "1.2.3", - token: "cargo-oidc-token", - apiBase: "https://registry.invalid/api/v1/", - fetchImpl: async (url, init) => { - request = { url, init }; - return new Response(JSON.stringify({ warnings: { other: ["fixture warning"] } }), { - status: 200, - headers: { "Content-Type": "application/json" }, - }); - }, - }); - - expect(request.url).toBe("https://registry.invalid/api/v1/crates/new"); - const headers = new Headers(request.init.headers); - expect(headers.get("authorization")).toBe("cargo-oidc-token"); - expect(headers.get("content-type")).toBe("application/octet-stream"); - expect(headers.get("accept")).toBe("application/json"); - expect(headers.get("user-agent")).toContain("oliphaunt-frozen-publisher"); - const body = Buffer.from(request.init.body); - const jsonLength = body.readUInt32LE(0); - const metadata = JSON.parse(body.subarray(4, 4 + jsonLength).toString("utf8")); - const crateLengthOffset = 4 + jsonLength; - const crateLength = body.readUInt32LE(crateLengthOffset); - expect(metadata.name).toBe("fixture-crate"); - expect(crateLength).toBe(crateBytes.length); - expect(body.subarray(crateLengthOffset + 4)).toEqual(crateBytes); - expect(result.warnings.other).toEqual(["fixture warning"]); - }); - - test("rejects non-registry dependency sources and identity substitutions", async () => { - expect(() => cargoPublishMetadataFromCrate(cargoFixture({ pathDependency: true }))).toThrow( - "forbidden path", - ); - await expect(publishFrozenCargoCrate({ - cratePath: cargoFixture(), - expectedName: "substituted-name", - expectedVersion: "1.2.3", - token: "token", - fetchImpl: () => { - throw new Error("must not be called"); - }, - })).rejects.toThrow("expected substituted-name@1.2.3"); - }); - - test("treats Cargo API errors as failure even with HTTP 200", async () => { - await expect(publishFrozenCargoCrate({ - cratePath: cargoFixture(), - expectedName: "fixture-crate", - expectedVersion: "1.2.3", - token: "token", - fetchImpl: async () => Response.json({ errors: [{ detail: "identity is not authorized" }] }, { status: 200 }), - })).rejects.toThrow("identity is not authorized"); - }); - - test("waits through the ten-minute crates.io refill and replays only exact frozen bytes", async () => { - const cratePath = cargoFixture(); - const requests = []; - const sleeps = []; - let now = Date.parse("Wed, 21 Oct 2015 07:27:00 GMT"); - const result = await publishFrozenCargoCrate({ - cratePath, - expectedName: "fixture-crate", - expectedVersion: "1.2.3", - token: "token", - deadlineEpochMs: now + 700_000, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - fetchImpl: async (_url, init) => { - requests.push(Buffer.from(init.body)); - if (requests.length === 1) { - return Response.json( - { errors: [{ detail: "new-crate bucket empty" }] }, - { - status: 429, - headers: { "Retry-After": "Wed, 21 Oct 2015 07:37:00 GMT" }, - }, - ); - } - return Response.json({ warnings: {} }); - }, - }); - - expect(sleeps).toEqual([602_000]); - expect(requests).toHaveLength(2); - expect(requests[1]).toEqual(requests[0]); - expect(result.warnings).toEqual({ invalid_categories: [], invalid_badges: [], other: [] }); - }); - - test("does not guess a rate-limit delay or wait beyond the mutation deadline", async () => { - const request = (headers = {}) => publishFrozenCargoCrate({ - cratePath: cargoFixture(), - expectedName: "fixture-crate", - expectedVersion: "1.2.3", - token: "token", - nowImpl: () => 1_000_000, - deadlineEpochMs: 1_500_000, - sleepImpl: async () => { - throw new Error("must not sleep"); - }, - fetchImpl: async () => Response.json({ errors: [{ detail: "limited" }] }, { status: 429, headers }), - }); - - await expect(request()).rejects.toThrow("without a valid Retry-After"); - let deferred; - try { - await request({ "Retry-After": "600" }); - } catch (cause) { - deferred = cause; - } - expect(isRegistryPublicationDeferredError(deferred)).toBe(true); - expect(deferred).toMatchObject({ - reason: "rate-limit", - notBeforeEpochSeconds: 1_602, - }); - expect(deferred.notBeforeEpochSeconds - 1_000).toBeLessThanOrEqual(15 * 60); - - let deadline; - try { - await publishFrozenCargoCrate({ - cratePath: cargoFixture(), - expectedName: "fixture-crate", - expectedVersion: "1.2.3", - token: "token", - nowImpl: () => 1_000_000, - deadlineEpochMs: 1_004_000, - fetchImpl: async () => { throw new Error("must not upload"); }, - }); - } catch (cause) { - deadline = cause; - } - expect(isRegistryPublicationDeferredError(deadline)).toBe(true); - expect(deadline).toMatchObject({ reason: "deadline", notBeforeEpochSeconds: 1_001 }); - }); - - test("turns exhausted valid 429s into a bounded continuation without weakening malformed responses", async () => { - let exhausted; - try { - await publishFrozenCargoCrate({ - cratePath: cargoFixture(), - expectedName: "fixture-crate", - expectedVersion: "1.2.3", - token: "token", - nowImpl: () => 1_000_000, - deadlineEpochMs: 2_000_000, - maxRateLimitRetries: 0, - fetchImpl: async () => Response.json( - { errors: [{ detail: "limited" }] }, - { status: 429, headers: { "Retry-After": "10" } }, - ), - }); - } catch (cause) { - exhausted = cause; - } - expect(isRegistryPublicationDeferredError(exhausted)).toBe(true); - expect(exhausted).toMatchObject({ - reason: "rate-limit", - notBeforeEpochSeconds: 1_012, - }); - - await expect(publishFrozenCargoCrate({ - cratePath: cargoFixture(), - expectedName: "fixture-crate", - expectedVersion: "1.2.3", - token: "token", - nowImpl: () => 1_000_000, - deadlineEpochMs: 2_000_000, - maxRateLimitRetries: 0, - fetchImpl: async () => Response.json( - { errors: [{ detail: "limited" }] }, - { status: 429 }, - ), - })).rejects.toThrow("without a valid Retry-After"); - }); - - test("rejects malformed success warning shapes", async () => { - await expect(publishFrozenCargoCrate({ - cratePath: cargoFixture(), - expectedName: "fixture-crate", - expectedVersion: "1.2.3", - token: "token", - fetchImpl: async () => Response.json({ warnings: { other: "not-a-list" } }), - })).rejects.toThrow("warnings.other must be a string list"); - }); - - test("rejects an oversized registry response before parsing diagnostics", async () => { - await expect(publishFrozenCargoCrate({ - cratePath: cargoFixture(), - expectedName: "fixture-crate", - expectedVersion: "1.2.3", - token: "token", - fetchImpl: async () => new Response("x".repeat(64 * 1024 + 1), { - status: 502, - headers: { "Content-Type": "text/plain" }, - }), - })).rejects.toThrow("registry response for fixture-crate@1.2.3 exceeds 65536 bytes"); - }); - - test("encodes protocol lengths independently from caller buffers", () => { - const body = encodeCargoPublishRequest({ name: "x" }, Buffer.from([1, 2, 3])); - const jsonLength = body.readUInt32LE(0); - expect(JSON.parse(body.subarray(4, 4 + jsonLength).toString("utf8"))).toEqual({ name: "x" }); - expect(body.readUInt32LE(4 + jsonLength)).toBe(3); - expect([...body.subarray(8 + jsonLength)]).toEqual([1, 2, 3]); - }); -}); diff --git a/tools/release/frozen-cargo-publish.test.mts b/tools/release/frozen-cargo-publish.test.mts new file mode 100644 index 000000000..747a2d5c0 --- /dev/null +++ b/tools/release/frozen-cargo-publish.test.mts @@ -0,0 +1,378 @@ +import { afterEach, describe, expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { tarArchive } from '../packaging/testdata/tar-fixture.mts'; + +import { + cargoPublishMetadataFromCrate, + encodeCargoPublishRequest, + publishFrozenCargoCrate, +} from './frozen-cargo-publish.mts'; +import { isRegistryPublicationDeferredError } from './registry-publication-deferral.mts'; + +const temporaryDirectories = []; + +function cargoFixture({ + archiveRoot = 'fixture-crate-1.2.3', + duplicateManifest = false, + nestedManifest = false, + pathDependency = false, +} = {}) { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-frozen-cargo-')); + temporaryDirectories.push(root); + const packageRoot = path.join(root, archiveRoot); + mkdirSync(path.join(packageRoot, 'src'), { recursive: true }); + writeFileSync(path.join(packageRoot, 'README.md'), '# Frozen fixture\n'); + writeFileSync(path.join(packageRoot, 'src/lib.rs'), 'pub const FROZEN: bool = true;\n'); + writeFileSync( + path.join(packageRoot, 'Cargo.toml'), + `[package] +name = "fixture-crate" +version = "1.2.3" +edition = "2024" +rust-version = "1.85" +authors = ["Oliphaunt Maintainers"] +description = "Frozen publication fixture" +documentation = "https://docs.rs/fixture-crate" +homepage = "https://oliphaunt.dev" +readme = "README.md" +keywords = ["postgres"] +categories = ["database"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/f0rr0/oliphaunt" +links = "fixture_native" + +[lib] +path = "src/lib.rs" + +[dependencies.serde_alias] +version = "1" +package = "serde" +features = ["derive"] +optional = true +default-features = false +${pathDependency ? 'path = "../serde"' : ''} + +[target.'cfg(unix)'.build-dependencies.cc] +version = "1.1" + +[features] +default = ["serde_alias"] + +[badges.maintenance] +status = "actively-developed" +`, + ); + if (nestedManifest) { + mkdirSync(path.join(packageRoot, 'examples', 'nested-crate', 'src'), { recursive: true }); + writeFileSync( + path.join(packageRoot, 'examples', 'nested-crate', 'Cargo.toml'), + '[package]\nname = "nested-crate"\nversion = "0.1.0"\n', + ); + writeFileSync(path.join(packageRoot, 'examples', 'nested-crate', 'src', 'lib.rs'), ''); + } + const cratePath = path.join(root, 'fixture-crate-1.2.3.crate'); + const files = ['Cargo.toml', 'README.md', 'src/lib.rs']; + if (nestedManifest) + files.push('examples/nested-crate/Cargo.toml', 'examples/nested-crate/src/lib.rs'); + if (duplicateManifest) files.push('Cargo.toml'); + writeFileSync( + cratePath, + tarArchive( + files.map((file) => ({ + name: archiveRoot + '/' + file, + data: readFileSync(path.join(packageRoot, file)), + })), + ), + ); + return cratePath; +} + +afterEach(() => { + while (temporaryDirectories.length > 0) { + rmSync(temporaryDirectories.pop(), { recursive: true, force: true }); + } +}); + +describe('frozen Cargo registry publication', () => { + test('derives Cargo Publish API metadata from the packaged manifest', () => { + const metadata = cargoPublishMetadataFromCrate(cargoFixture()); + expect(metadata).toMatchObject({ + name: 'fixture-crate', + vers: '1.2.3', + authors: ['Oliphaunt Maintainers'], + description: 'Frozen publication fixture', + readme: '# Frozen fixture\n', + readme_file: 'README.md', + license: 'MIT OR Apache-2.0', + rust_version: '1.85', + features: { default: ['serde_alias'] }, + badges: { maintenance: { status: 'actively-developed' } }, + }); + expect(metadata.deps).toEqual([ + { + optional: true, + default_features: false, + name: 'serde', + features: ['derive'], + version_req: '1', + target: null, + kind: 'normal', + explicit_name_in_toml: 'serde_alias', + }, + { + optional: false, + default_features: true, + name: 'cc', + features: [], + version_req: '1.1', + target: 'cfg(unix)', + kind: 'build', + }, + ]); + }); + + test('selects the canonical crate manifest while allowing packaged nested Cargo manifests', () => { + const metadata = cargoPublishMetadataFromCrate(cargoFixture({ nestedManifest: true })); + expect(metadata).toMatchObject({ name: 'fixture-crate', vers: '1.2.3' }); + }); + + test('rejects ambiguous members and a top-level crate root that disagrees with package identity', () => { + expect(() => cargoPublishMetadataFromCrate(cargoFixture({ duplicateManifest: true }))).toThrow( + /repeats archive member.*Cargo[.]toml/u, + ); + expect(() => + cargoPublishMetadataFromCrate(cargoFixture({ archiveRoot: 'substituted-root' })), + ).toThrow('top-level crate root must be fixture-crate-1.2.3, found substituted-root'); + }); + + test('encodes and uploads the exact supplied crate bytes with the raw Cargo token', async () => { + const cratePath = cargoFixture(); + const crateBytes = readFileSync(cratePath); + let request = null; + const result = await publishFrozenCargoCrate({ + cratePath, + expectedName: 'fixture-crate', + expectedVersion: '1.2.3', + token: 'cargo-oidc-token', + apiBase: 'https://registry.invalid/api/v1/', + fetchImpl: async (url, init) => { + request = { url, init }; + return new Response(JSON.stringify({ warnings: { other: ['fixture warning'] } }), { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }); + }, + }); + + expect(request.url).toBe('https://registry.invalid/api/v1/crates/new'); + const headers = new Headers(request.init.headers); + expect(headers.get('authorization')).toBe('cargo-oidc-token'); + expect(headers.get('content-type')).toBe('application/octet-stream'); + expect(headers.get('accept')).toBe('application/json'); + expect(headers.get('user-agent')).toContain('oliphaunt-frozen-publisher'); + const body = Buffer.from(request.init.body); + const jsonLength = body.readUInt32LE(0); + const metadata = JSON.parse(body.subarray(4, 4 + jsonLength).toString('utf8')); + const crateLengthOffset = 4 + jsonLength; + const crateLength = body.readUInt32LE(crateLengthOffset); + expect(metadata.name).toBe('fixture-crate'); + expect(crateLength).toBe(crateBytes.length); + expect(body.subarray(crateLengthOffset + 4)).toEqual(crateBytes); + expect(result.warnings.other).toEqual(['fixture warning']); + }); + + test('rejects non-registry dependency sources and identity substitutions', async () => { + expect(() => cargoPublishMetadataFromCrate(cargoFixture({ pathDependency: true }))).toThrow( + 'forbidden path', + ); + await expect( + publishFrozenCargoCrate({ + cratePath: cargoFixture(), + expectedName: 'substituted-name', + expectedVersion: '1.2.3', + token: 'token', + fetchImpl: () => { + throw new Error('must not be called'); + }, + }), + ).rejects.toThrow('expected substituted-name@1.2.3'); + }); + + test('treats Cargo API errors as failure even with HTTP 200', async () => { + await expect( + publishFrozenCargoCrate({ + cratePath: cargoFixture(), + expectedName: 'fixture-crate', + expectedVersion: '1.2.3', + token: 'token', + fetchImpl: async () => + Response.json({ errors: [{ detail: 'identity is not authorized' }] }, { status: 200 }), + }), + ).rejects.toThrow('identity is not authorized'); + }); + + test('waits through the ten-minute crates.io refill and replays only exact frozen bytes', async () => { + const cratePath = cargoFixture(); + const requests = []; + const sleeps = []; + let now = Date.parse('Wed, 21 Oct 2015 07:27:00 GMT'); + const result = await publishFrozenCargoCrate({ + cratePath, + expectedName: 'fixture-crate', + expectedVersion: '1.2.3', + token: 'token', + deadlineEpochMs: now + 700_000, + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + fetchImpl: async (_url, init) => { + requests.push(Buffer.from(init.body)); + if (requests.length === 1) { + return Response.json( + { errors: [{ detail: 'new-crate bucket empty' }] }, + { + status: 429, + headers: { 'Retry-After': 'Wed, 21 Oct 2015 07:37:00 GMT' }, + }, + ); + } + return Response.json({ warnings: {} }); + }, + }); + + expect(sleeps).toEqual([602_000]); + expect(requests).toHaveLength(2); + expect(requests[1]).toEqual(requests[0]); + expect(result.warnings).toEqual({ invalid_categories: [], invalid_badges: [], other: [] }); + }); + + test('does not guess a rate-limit delay or wait beyond the mutation deadline', async () => { + const request = (headers = {}) => + publishFrozenCargoCrate({ + cratePath: cargoFixture(), + expectedName: 'fixture-crate', + expectedVersion: '1.2.3', + token: 'token', + nowImpl: () => 1_000_000, + deadlineEpochMs: 1_500_000, + sleepImpl: async () => { + throw new Error('must not sleep'); + }, + fetchImpl: async () => + Response.json({ errors: [{ detail: 'limited' }] }, { status: 429, headers }), + }); + + await expect(request()).rejects.toThrow('without a valid Retry-After'); + let deferred; + try { + await request({ 'Retry-After': '600' }); + } catch (cause) { + deferred = cause; + } + expect(isRegistryPublicationDeferredError(deferred)).toBe(true); + expect(deferred).toMatchObject({ + reason: 'rate-limit', + notBeforeEpochSeconds: 1_602, + }); + expect(deferred.notBeforeEpochSeconds - 1_000).toBeLessThanOrEqual(15 * 60); + + let deadline; + try { + await publishFrozenCargoCrate({ + cratePath: cargoFixture(), + expectedName: 'fixture-crate', + expectedVersion: '1.2.3', + token: 'token', + nowImpl: () => 1_000_000, + deadlineEpochMs: 1_004_000, + fetchImpl: async () => { + throw new Error('must not upload'); + }, + }); + } catch (cause) { + deadline = cause; + } + expect(isRegistryPublicationDeferredError(deadline)).toBe(true); + expect(deadline).toMatchObject({ reason: 'deadline', notBeforeEpochSeconds: 1_001 }); + }); + + test('turns exhausted valid 429s into a bounded continuation without weakening malformed responses', async () => { + let exhausted; + try { + await publishFrozenCargoCrate({ + cratePath: cargoFixture(), + expectedName: 'fixture-crate', + expectedVersion: '1.2.3', + token: 'token', + nowImpl: () => 1_000_000, + deadlineEpochMs: 2_000_000, + maxRateLimitRetries: 0, + fetchImpl: async () => + Response.json( + { errors: [{ detail: 'limited' }] }, + { status: 429, headers: { 'Retry-After': '10' } }, + ), + }); + } catch (cause) { + exhausted = cause; + } + expect(isRegistryPublicationDeferredError(exhausted)).toBe(true); + expect(exhausted).toMatchObject({ + reason: 'rate-limit', + notBeforeEpochSeconds: 1_012, + }); + + await expect( + publishFrozenCargoCrate({ + cratePath: cargoFixture(), + expectedName: 'fixture-crate', + expectedVersion: '1.2.3', + token: 'token', + nowImpl: () => 1_000_000, + deadlineEpochMs: 2_000_000, + maxRateLimitRetries: 0, + fetchImpl: async () => Response.json({ errors: [{ detail: 'limited' }] }, { status: 429 }), + }), + ).rejects.toThrow('without a valid Retry-After'); + }); + + test('rejects malformed success warning shapes', async () => { + await expect( + publishFrozenCargoCrate({ + cratePath: cargoFixture(), + expectedName: 'fixture-crate', + expectedVersion: '1.2.3', + token: 'token', + fetchImpl: async () => Response.json({ warnings: { other: 'not-a-list' } }), + }), + ).rejects.toThrow('warnings.other must be a string list'); + }); + + test('rejects an oversized registry response before parsing diagnostics', async () => { + await expect( + publishFrozenCargoCrate({ + cratePath: cargoFixture(), + expectedName: 'fixture-crate', + expectedVersion: '1.2.3', + token: 'token', + fetchImpl: async () => + new Response('x'.repeat(64 * 1024 + 1), { + status: 502, + headers: { 'Content-Type': 'text/plain' }, + }), + }), + ).rejects.toThrow('registry response for fixture-crate@1.2.3 exceeds 65536 bytes'); + }); + + test('encodes protocol lengths independently from caller buffers', () => { + const body = encodeCargoPublishRequest({ name: 'x' }, Buffer.from([1, 2, 3])); + const jsonLength = body.readUInt32LE(0); + expect(JSON.parse(body.subarray(4, 4 + jsonLength).toString('utf8'))).toEqual({ name: 'x' }); + expect(body.readUInt32LE(4 + jsonLength)).toBe(3); + expect([...body.subarray(8 + jsonLength)]).toEqual([1, 2, 3]); + }); +}); diff --git a/tools/release/frozen-maven-publish.mjs b/tools/release/frozen-maven-publish.mjs deleted file mode 100644 index 85a9677b6..000000000 --- a/tools/release/frozen-maven-publish.mjs +++ /dev/null @@ -1,655 +0,0 @@ -import { createHash } from "node:crypto"; -import { - chmodSync, - copyFileSync, - mkdirSync, - readFileSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { mavenCentralAuthorization } from "./maven-central-auth.mjs"; -import { lockedCarrierFiles, lockedCarriers } from "./publication-lock.mjs"; -import { ROOT } from "./release-cli-utils.mjs"; -import { validateMavenCentralPublication } from "./maven-central-contract.mjs"; - -const CENTRAL_API = "https://central.sonatype.com/api/v1/publisher"; -const TERMINAL_STATES = new Set(["PUBLISHED", "FAILED"]); -const DEPLOYMENT_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu; -const DROP_VISIBILITY_ATTEMPTS = 30; -const DROP_VISIBILITY_INTERVAL_MS = 1_000; -const MAX_CENTRAL_RESPONSE_BYTES = 1024 * 1024; -export const MAX_CENTRAL_BUNDLE_BYTES = 1_000_000_000; -const CENTRAL_REQUEST_TIMEOUT_MS = 60_000; -const DEADLINE_RESERVE_MS = 5_000; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function error(message) { - return new Error(`frozen-maven-publish: ${message}`); -} - -function deadlineMilliseconds(deadlineEpochSeconds) { - if (!Number.isSafeInteger(deadlineEpochSeconds) || deadlineEpochSeconds < 1) { - throw error("registry mutation deadline must be a positive Unix timestamp"); - } - return deadlineEpochSeconds * 1000; -} - -function remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }) { - const remaining = deadlineMilliseconds(deadlineEpochSeconds) - nowImpl() - DEADLINE_RESERVE_MS; - if (remaining <= 0) { - throw error(`${context} refused because the shared registry mutation deadline has been reached`); - } - return remaining; -} - -async function boundedSleep(milliseconds, { - deadlineEpochSeconds, - nowImpl, - sleep, - context, -}) { - const remaining = remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }); - if (!Number.isFinite(milliseconds) || milliseconds < 0 || milliseconds >= remaining) { - throw error(`${context} cannot wait ${Math.ceil(milliseconds / 1000)}s before the shared registry mutation deadline`); - } - await sleep(milliseconds); -} - -function safeCoordinate(value, context) { - if (typeof value !== "string" || !/^[A-Za-z0-9_.-]+$/u.test(value)) { - throw error(`${context} is not a safe Maven coordinate segment: ${JSON.stringify(value)}`); - } - return value; -} - -function coordinate(carrier) { - const separator = carrier.name.lastIndexOf(":"); - if (separator <= 0 || separator === carrier.name.length - 1) { - throw error(`${carrier.id} has invalid Maven coordinates`); - } - const group = safeCoordinate(carrier.name.slice(0, separator), `${carrier.id} group`); - const artifact = safeCoordinate(carrier.name.slice(separator + 1), `${carrier.id} artifact`); - const version = safeCoordinate(carrier.version, `${carrier.id} version`); - return { group, artifact, version }; -} - -function remoteFilename(carrier, artifactPath, artifactName) { - const localName = path.basename(artifactPath); - const prefix = `${artifactName}-${carrier.version}`; - if (localName.startsWith(prefix) && localName.length > prefix.length) { - return localName; - } - const compound = [".tar.gz", ".tar.zst"].find((suffix) => localName.endsWith(suffix)); - const suffix = compound ?? path.extname(localName); - if (suffix.length === 0) { - throw error(`${carrier.id} cannot map ${localName} to a Maven filename`); - } - return `${prefix}${suffix}`; -} - -function digestFile(file, algorithm) { - return createHash(algorithm).update(readFileSync(file)).digest("hex"); -} - -function run(args, { cwd = ROOT, input = undefined, context }) { - const result = captureCommandOutput(args[0], args.slice(1), { - cwd, - input, - label: context, - maxOutputBytes: 10 * 1024 * 1024, - }); - if (result.error !== undefined || result.status !== 0) { - const detail = (result.stderr || result.error?.message || "").trim(); - throw error(`${context} failed${detail ? `: ${detail}` : ""}`); - } - return result.stdout; -} - -function normalizedGpgKeyId(keyId) { - if (typeof keyId !== "string") { - throw error("Maven signing key ID must be a hexadecimal OpenPGP key ID or fingerprint"); - } - const normalized = keyId.trim().replace(/^0x/iu, "").toUpperCase(); - if (!/^[0-9A-F]{8,64}$/u.test(normalized)) { - throw error("Maven signing key ID must be 8-64 hexadecimal characters, optionally prefixed by 0x"); - } - return normalized; -} - -export function createGpgSigner({ privateKey, keyId, passphrase, home, runImpl = run }) { - if (![privateKey, keyId, passphrase].every((value) => typeof value === "string" && value.length > 0)) { - throw error("Maven signing key, key ID, and passphrase are required"); - } - const signingKeyId = normalizedGpgKeyId(keyId); - mkdirSync(home, { recursive: true }); - chmodSync(home, 0o700); - runImpl(["gpg", "--batch", "--homedir", home, "--import"], { - input: privateKey, - context: "import Maven signing key", - }); - return (file, signature) => { - runImpl([ - "gpg", - "--batch", - "--yes", - "--no-tty", - "--pinentry-mode", - "loopback", - "--passphrase-fd", - "0", - "--homedir", - home, - "--local-user", - signingKeyId, - "--armor", - "--detach-sign", - "--output", - signature, - file, - ], { input: `${passphrase}\n`, context: `sign ${path.basename(file)}` }); - }; -} - -export function verifyGpgSigningCredentials({ privateKey, keyId, passphrase, home, runImpl = run }) { - const signingKeyId = normalizedGpgKeyId(keyId); - const payload = path.join(home, "oliphaunt-maven-signing-preflight.txt"); - const signature = `${payload}.asc`; - const signFile = createGpgSigner({ privateKey, keyId: signingKeyId, passphrase, home, runImpl }); - writeFileSync(payload, "oliphaunt Maven signing readiness preflight\n", { mode: 0o600 }); - signFile(payload, signature); - const status = runImpl([ - "gpg", - "--batch", - "--no-auto-key-retrieve", - "--homedir", - home, - "--status-fd", - "1", - "--verify", - signature, - payload, - ], { context: "verify Maven signing preflight signature" }); - const validSignatures = status - .split(/\r?\n/u) - .filter((line) => line.startsWith("[GNUPG:] VALIDSIG ")); - if (validSignatures.length !== 1) { - throw error(`Maven signing preflight expected one valid signature, got ${validSignatures.length}`); - } - const fingerprints = validSignatures[0] - .trim() - .split(/\s+/u) - .filter((field) => /^(?:[0-9A-F]{40}|[0-9A-F]{64})$/iu.test(field)) - .map((field) => field.toUpperCase()); - if (fingerprints.length === 0) { - throw error("Maven signing preflight did not report a valid signature fingerprint"); - } - const signerFingerprint = fingerprints[0]; - const primaryFingerprint = fingerprints.length > 1 ? fingerprints.at(-1) : signerFingerprint; - if (signerFingerprint !== primaryFingerprint) { - throw error("Maven Central requires artifacts to be signed by the primary OpenPGP key, not a signing subkey"); - } - if (!primaryFingerprint.endsWith(signingKeyId)) { - throw error("configured Maven signing key ID does not match the verified signature fingerprint"); - } - return { - signerFingerprint, - primaryFingerprint, - }; -} - -export function inspectArmoredPublicKeyFingerprints({ armoredKey, home, runImpl = run }) { - if (typeof armoredKey !== "string" || armoredKey.length === 0) { - throw error("published Maven signing public key must be nonempty armored OpenPGP data"); - } - const listing = runImpl([ - "gpg", - "--batch", - "--homedir", - home, - "--with-colons", - "--import-options", - "show-only", - "--import", - ], { input: armoredKey, context: "inspect published Maven signing public key" }); - const primaryFingerprints = []; - let awaitingPrimaryFingerprint = false; - for (const line of listing.split(/\r?\n/u)) { - const fields = line.split(":"); - if (fields[0] === "pub") { - awaitingPrimaryFingerprint = true; - continue; - } - if (fields[0] === "sub") { - awaitingPrimaryFingerprint = false; - continue; - } - if (fields[0] === "fpr" && awaitingPrimaryFingerprint) { - const fingerprint = fields[9]?.toUpperCase() ?? ""; - if (!/^(?:[0-9A-F]{40}|[0-9A-F]{64})$/u.test(fingerprint)) { - throw error("published Maven signing key reported an invalid primary fingerprint"); - } - primaryFingerprints.push(fingerprint); - awaitingPrimaryFingerprint = false; - } - } - if (primaryFingerprints.length === 0) { - throw error("published Maven signing key did not contain a primary OpenPGP fingerprint"); - } - return primaryFingerprints; -} - -export function prepareFrozenMavenBundle({ lock, products, outputRoot, signFile }) { - if (typeof signFile !== "function") { - throw error("signFile callback is required"); - } - const carriers = lockedCarriers(lock, { products, ecosystem: "maven" }) - .sort((left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id)); - if (carriers.length === 0) { - throw error(`publication lock contains no Maven carriers for ${products.join(",")}`); - } - const layout = path.join(outputRoot, "layout"); - const bundle = path.join(outputRoot, "central-bundle.zip"); - rmSync(layout, { recursive: true, force: true }); - rmSync(bundle, { force: true }); - mkdirSync(layout, { recursive: true }); - const payloads = []; - for (const carrier of carriers) { - const { group, artifact, version } = coordinate(carrier); - const frozen = lockedCarrierFiles(lock, "maven", carrier.name); - const destination = path.join(layout, ...group.split("."), artifact, version); - mkdirSync(destination, { recursive: true }); - const names = new Set(); - for (const { artifact: envelope, file } of frozen.files) { - if (/\.(?:asc|md5|sha1|sha256|sha512)$/u.test(file)) { - throw error(`${carrier.id} lock must freeze primary Maven payloads, not generated signature/checksum ${envelope.path}`); - } - const name = remoteFilename(carrier, file, artifact); - if (names.has(name)) { - throw error(`${carrier.id} maps multiple frozen artifacts to ${name}`); - } - names.add(name); - const staged = path.join(destination, name); - copyFileSync(file, staged); - payloads.push({ carrier: carrier.id, frozenPath: envelope.path, staged, sha256: digestFile(staged, "sha256") }); - } - if (![...names].some((name) => name === `${artifact}-${version}.pom`)) { - throw error(`${carrier.id} must freeze its generated POM before publication`); - } - const pom = path.join(destination, `${artifact}-${version}.pom`); - validateMavenCentralPublication({ - pomText: readFileSync(pom, "utf8"), - files: [...names].map((name) => ({ name, size: statSync(path.join(destination, name)).size })), - context: carrier.id, - }); - } - for (const payload of payloads) { - signFile(payload.staged, `${payload.staged}.asc`); - writeFileSync(`${payload.staged}.md5`, digestFile(payload.staged, "md5")); - writeFileSync(`${payload.staged}.sha1`, digestFile(payload.staged, "sha1")); - } - run(["zip", "-q", "-X", "-r", bundle, "."], { cwd: layout, context: "create Maven Central deployment bundle" }); - const bundleSize = statSync(bundle).size; - assertMavenCentralBundleSize(bundleSize); - return { bundle, bundleSize, carriers, layout, payloads }; -} - -export function assertMavenCentralBundleSize(size, maximum = MAX_CENTRAL_BUNDLE_BYTES) { - if (!Number.isSafeInteger(size) || size < 1) { - throw error(`Maven Central deployment bundle size must be a positive integer, got ${size}`); - } - if (!Number.isSafeInteger(maximum) || maximum < 1) { - throw error(`Maven Central deployment bundle maximum must be a positive integer, got ${maximum}`); - } - if (size >= maximum) { - throw error(`Maven Central deployment bundle is ${size} bytes; the portal requires bundles smaller than ${maximum} bytes`); - } -} - -function boundedDetail(body) { - return body.replace(/[\r\n\t]+/gu, " ").trim().slice(0, 500); -} - -async function boundedResponseText(response) { - const contentLength = response.headers?.get?.("content-length"); - if (contentLength !== null && contentLength !== undefined) { - const declared = Number(contentLength); - if (!Number.isSafeInteger(declared) || declared < 0) { - await response.body?.cancel?.().catch(() => {}); - throw error("Maven Central returned an invalid Content-Length"); - } - if (declared > MAX_CENTRAL_RESPONSE_BYTES) { - await response.body?.cancel?.().catch(() => {}); - throw error(`Maven Central response exceeds ${MAX_CENTRAL_RESPONSE_BYTES} bytes`); - } - } - - const reader = response.body?.getReader?.(); - if (reader === undefined) { - const text = await response.text(); - if (Buffer.byteLength(text) > MAX_CENTRAL_RESPONSE_BYTES) { - throw error(`Maven Central response exceeds ${MAX_CENTRAL_RESPONSE_BYTES} bytes`); - } - return text; - } - const chunks = []; - let size = 0; - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > MAX_CENTRAL_RESPONSE_BYTES) { - await reader.cancel().catch(() => {}); - throw error(`Maven Central response exceeds ${MAX_CENTRAL_RESPONSE_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - } finally { - reader.releaseLock(); - } - return Buffer.concat(chunks, size).toString("utf8"); -} - -async function centralRequest(url, { - authorization, - deadlineEpochSeconds, - nowImpl, - method = "GET", - body = undefined, - fetchImpl = fetch, -}) { - const timeoutMs = Math.min( - CENTRAL_REQUEST_TIMEOUT_MS, - remainingBeforeReserve({ - deadlineEpochSeconds, - nowImpl, - context: `Maven Central ${method} ${url}`, - }), - ); - const response = await fetchImpl(url, { - method, - headers: { - Accept: "application/json", - Authorization: authorization, - }, - body, - redirect: "error", - signal: AbortSignal.timeout(Math.max(1, timeoutMs)), - }); - const text = await boundedResponseText(response); - if (!response.ok) { - throw error(`Maven Central request returned HTTP ${response.status}${text ? `: ${boundedDetail(text)}` : ""}`); - } - return text; -} - -async function findDeployment({ - authorization, - deadlineEpochSeconds, - deploymentName, - namespace, - apiBase, - fetchImpl, - nowImpl, -}) { - const url = new URL(`${apiBase.replace(/\/+$/u, "")}/deployments`); - url.searchParams.set("namespace", namespace); - url.searchParams.set("page", "0"); - url.searchParams.set("size", "100"); - const text = await centralRequest(url, { - authorization, - deadlineEpochSeconds, - fetchImpl, - nowImpl, - }); - let value; - try { - value = JSON.parse(text); - } catch (cause) { - throw error(`Maven Central deployments response is invalid JSON: ${cause.message}`); - } - const matches = value?.deployments?.filter((deployment) => deployment?.deploymentName === deploymentName) ?? []; - if (matches.length > 1) { - throw error(`Maven Central contains multiple deployments named ${deploymentName}`); - } - return matches[0] ?? null; -} - -async function uploadBundle({ - bundle, - authorization, - deploymentName, - namespace, - apiBase, - deadlineEpochSeconds, - fetchImpl, - nowImpl, - sleep, -}) { - const request = { authorization, deadlineEpochSeconds, fetchImpl, nowImpl }; - const existing = await findDeployment({ - ...request, - deploymentName, - namespace, - apiBase, - }); - if (existing !== null) { - const id = existing.deploymentId; - if (typeof id !== "string" || !DEPLOYMENT_ID.test(id)) { - throw error(`Maven Central deployment ${deploymentName} has invalid deployment ID ${JSON.stringify(id)}`); - } - // A list response that already identifies a deployment as anything other - // than FAILED is never eligible for deletion. This preserves the existing - // VALIDATED promotion path and makes PUBLISHING/PUBLISHED fail-safe even - // if a subsequent status response were inconsistent. - if (existing.deploymentState !== undefined && existing.deploymentState !== "FAILED") { - return id; - } - const status = await deploymentStatus({ id, apiBase, ...request }); - if (status?.deploymentState !== "FAILED") { - return id; - } - if (status.deploymentId !== id) { - throw error( - `refusing to drop failed Maven Central deployment ${id}: status returned deployment ID ${JSON.stringify(status.deploymentId)}`, - ); - } - if (status.deploymentName !== undefined && status.deploymentName !== deploymentName) { - throw error( - `refusing to drop failed Maven Central deployment ${id}: status returned name ${JSON.stringify(status.deploymentName)}`, - ); - } - await centralRequest(`${apiBase.replace(/\/+$/u, "")}/deployment/${encodeURIComponent(id)}`, { - ...request, - method: "DELETE", - }); - for (let attempt = 0; attempt < DROP_VISIBILITY_ATTEMPTS; attempt += 1) { - const retained = await findDeployment({ - ...request, - deploymentName, - namespace, - apiBase, - }); - if (retained === null) { - break; - } - if (retained.deploymentId !== id) { - throw error( - `Maven Central deployment name ${deploymentName} was reused by ${JSON.stringify(retained.deploymentId)} while dropping ${id}`, - ); - } - if (attempt === DROP_VISIBILITY_ATTEMPTS - 1) { - throw error(`Maven Central failed deployment ${id} remained visible after it was dropped`); - } - await boundedSleep(DROP_VISIBILITY_INTERVAL_MS, { - deadlineEpochSeconds, - nowImpl, - sleep, - context: `Maven Central failed-deployment removal for ${id}`, - }); - } - } - const url = new URL(`${apiBase.replace(/\/+$/u, "")}/upload`); - url.searchParams.set("name", deploymentName); - url.searchParams.set("publishingType", "USER_MANAGED"); - const form = new FormData(); - form.set("bundle", new Blob([readFileSync(bundle)], { type: "application/octet-stream" }), path.basename(bundle)); - try { - const text = await centralRequest(url, { - ...request, - method: "POST", - body: form, - }); - const id = text.trim(); - if (!DEPLOYMENT_ID.test(id)) { - throw error(`Maven Central upload returned invalid deployment ID ${JSON.stringify(id)}`); - } - return id; - } catch (cause) { - // Never retry an ambiguous upload. Reconcile by its lock-derived unique - // name; if the server did not retain it, the caller can safely rerun. - const reconciled = await findDeployment({ - ...request, - deploymentName, - namespace, - apiBase, - }); - if (reconciled !== null) { - return reconciled.deploymentId; - } - throw cause; - } -} - -async function deploymentStatus({ - id, - authorization, - deadlineEpochSeconds, - apiBase, - fetchImpl, - nowImpl, -}) { - const url = new URL(`${apiBase.replace(/\/+$/u, "")}/status`); - url.searchParams.set("id", id); - const text = await centralRequest(url, { - authorization, - deadlineEpochSeconds, - method: "POST", - fetchImpl, - nowImpl, - }); - try { - return JSON.parse(text); - } catch (cause) { - throw error(`Maven Central status response is invalid JSON: ${cause.message}`); - } -} - -async function waitForDeployment({ - id, - authorization, - deadlineEpochSeconds, - apiBase, - fetchImpl, - nowImpl, - sleep, - acceptable, -}) { - for (let attempt = 0; attempt < 90; attempt += 1) { - const status = await deploymentStatus({ - id, - authorization, - deadlineEpochSeconds, - apiBase, - fetchImpl, - nowImpl, - }); - if (status?.deploymentState === "FAILED") { - throw error(`Maven Central deployment ${id} failed: ${boundedDetail(JSON.stringify(status.errors ?? status))}`); - } - if (acceptable.has(status?.deploymentState)) { - return status; - } - if (TERMINAL_STATES.has(status?.deploymentState)) { - throw error(`Maven Central deployment ${id} reached unexpected state ${status.deploymentState}`); - } - await boundedSleep(10_000, { - deadlineEpochSeconds, - nowImpl, - sleep, - context: `Maven Central deployment ${id} visibility wait`, - }); - } - throw error(`Maven Central deployment ${id} did not reach ${[...acceptable].join(" or ")} within 15 minutes`); -} - -export async function publishFrozenMavenBundle({ - bundle, - lockDigest, - deploymentScope, - namespace, - username, - password, - deadlineEpochSeconds, - apiBase = CENTRAL_API, - fetchImpl = fetch, - nowImpl = () => Date.now(), - sleep = Bun.sleep, -}) { - const authorization = mavenCentralAuthorization(username, password); - if (typeof deploymentScope !== "string" || deploymentScope.length === 0) { - throw error("deploymentScope is required to distinguish product subsets from one publication lock"); - } - const scopeDigest = createHash("sha256").update(deploymentScope).digest("hex").slice(0, 12); - const deploymentName = `oliphaunt-${lockDigest.slice(0, 16)}-${scopeDigest}`; - const id = await uploadBundle({ - bundle, - authorization, - deploymentName, - namespace, - apiBase, - deadlineEpochSeconds, - fetchImpl, - nowImpl, - sleep, - }); - const validated = await waitForDeployment({ - id, - authorization, - deadlineEpochSeconds, - apiBase, - fetchImpl, - nowImpl, - sleep, - acceptable: new Set(["VALIDATED", "PUBLISHING", "PUBLISHED"]), - }); - if (validated.deploymentState === "VALIDATED") { - await centralRequest(`${apiBase.replace(/\/+$/u, "")}/deployment/${encodeURIComponent(id)}`, { - authorization, - deadlineEpochSeconds, - method: "POST", - fetchImpl, - nowImpl, - }); - } - const published = validated.deploymentState === "PUBLISHED" - ? validated - : await waitForDeployment({ - id, - authorization, - deadlineEpochSeconds, - apiBase, - fetchImpl, - nowImpl, - sleep, - acceptable: new Set(["PUBLISHED"]), - }); - return { deploymentId: id, deploymentName, status: published }; -} diff --git a/tools/release/frozen-maven-publish.mts b/tools/release/frozen-maven-publish.mts new file mode 100644 index 000000000..9211aff01 --- /dev/null +++ b/tools/release/frozen-maven-publish.mts @@ -0,0 +1,562 @@ +import { createHash } from 'node:crypto'; +import { copyFileSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { validateMavenCentralPublication } from '../packaging/maven-central-contract.mts'; + +import { mavenCentralAuthorization } from './maven-central-auth.mts'; +import { lockedCarrierFiles, lockedCarriers } from './publication-lock.mts'; + +const CENTRAL_API = 'https://central.sonatype.com/api/v1/publisher'; +const TERMINAL_STATES = new Set(['PUBLISHED', 'FAILED']); +const DEPLOYMENT_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu; +const DROP_VISIBILITY_ATTEMPTS = 30; +const DROP_VISIBILITY_INTERVAL_MS = 1_000; +const MAX_CENTRAL_RESPONSE_BYTES = 1024 * 1024; +export const MAX_CENTRAL_BUNDLE_BYTES = 1_000_000_000; +const CENTRAL_REQUEST_TIMEOUT_MS = 60_000; +const DEADLINE_RESERVE_MS = 5_000; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function error(message) { + return new Error(`frozen-maven-publish: ${message}`); +} + +function deadlineMilliseconds(deadlineEpochSeconds) { + if (!Number.isSafeInteger(deadlineEpochSeconds) || deadlineEpochSeconds < 1) { + throw error('registry mutation deadline must be a positive Unix timestamp'); + } + return deadlineEpochSeconds * 1000; +} + +function remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }) { + const remaining = deadlineMilliseconds(deadlineEpochSeconds) - nowImpl() - DEADLINE_RESERVE_MS; + if (remaining <= 0) { + throw error( + `${context} refused because the shared registry mutation deadline has been reached`, + ); + } + return remaining; +} + +async function boundedSleep(milliseconds, { deadlineEpochSeconds, nowImpl, sleep, context }) { + const remaining = remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }); + if (!Number.isFinite(milliseconds) || milliseconds < 0 || milliseconds >= remaining) { + throw error( + `${context} cannot wait ${Math.ceil(milliseconds / 1000)}s before the shared registry mutation deadline`, + ); + } + await sleep(milliseconds); +} + +function safeCoordinate(value, context) { + if (typeof value !== 'string' || !/^[A-Za-z0-9_.-]+$/u.test(value)) { + throw error(`${context} is not a safe Maven coordinate segment: ${JSON.stringify(value)}`); + } + return value; +} + +function coordinate(carrier) { + const separator = carrier.name.lastIndexOf(':'); + if (separator <= 0 || separator === carrier.name.length - 1) { + throw error(`${carrier.id} has invalid Maven coordinates`); + } + const group = safeCoordinate(carrier.name.slice(0, separator), `${carrier.id} group`); + const artifact = safeCoordinate(carrier.name.slice(separator + 1), `${carrier.id} artifact`); + const version = safeCoordinate(carrier.version, `${carrier.id} version`); + return { group, artifact, version }; +} + +function remoteFilename(carrier, artifactPath, artifactName) { + const localName = path.basename(artifactPath); + const prefix = `${artifactName}-${carrier.version}`; + if (localName.startsWith(prefix) && localName.length > prefix.length) { + return localName; + } + const compound = ['.tar.gz', '.tar.zst'].find((suffix) => localName.endsWith(suffix)); + const suffix = compound ?? path.extname(localName); + if (suffix.length === 0) { + throw error(`${carrier.id} cannot map ${localName} to a Maven filename`); + } + return `${prefix}${suffix}`; +} + +function digestFile(file, algorithm) { + return createHash(algorithm).update(readFileSync(file)).digest('hex'); +} + +export function stageFrozenMavenBundle({ lock, products, outputRoot }) { + const carriers = lockedCarriers(lock, { products, ecosystem: 'maven' }).sort( + (left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id), + ); + if (carriers.length === 0) { + throw error(`publication lock contains no Maven carriers for ${products.join(',')}`); + } + const layout = path.join(outputRoot, 'layout'); + const bundle = path.join(outputRoot, 'central-bundle.zip'); + rmSync(layout, { recursive: true, force: true }); + rmSync(bundle, { force: true }); + mkdirSync(layout, { recursive: true }); + const payloads = []; + for (const carrier of carriers) { + const { group, artifact, version } = coordinate(carrier); + const frozen = lockedCarrierFiles(lock, 'maven', carrier.name); + const destination = path.join(layout, ...group.split('.'), artifact, version); + mkdirSync(destination, { recursive: true }); + const names = new Set(); + for (const { artifact: envelope, file } of frozen.files) { + if (/\.(?:asc|md5|sha1|sha256|sha512)$/u.test(file)) { + throw error( + `${carrier.id} lock must freeze primary Maven payloads, not generated signature/checksum ${envelope.path}`, + ); + } + const name = remoteFilename(carrier, file, artifact); + if (names.has(name)) { + throw error(`${carrier.id} maps multiple frozen artifacts to ${name}`); + } + names.add(name); + const staged = path.join(destination, name); + copyFileSync(file, staged); + payloads.push({ + carrier: carrier.id, + frozenPath: envelope.path, + staged, + sha256: digestFile(staged, 'sha256'), + }); + } + if (![...names].some((name) => name === `${artifact}-${version}.pom`)) { + throw error(`${carrier.id} must freeze its generated POM before publication`); + } + const pom = path.join(destination, `${artifact}-${version}.pom`); + validateMavenCentralPublication({ + pomText: readFileSync(pom, 'utf8'), + files: [...names].map((name) => ({ + name, + size: statSync(path.join(destination, name)).size, + })), + context: carrier.id, + }); + } + for (const payload of payloads) { + writeFileSync(`${payload.staged}.md5`, digestFile(payload.staged, 'md5')); + writeFileSync(`${payload.staged}.sha1`, digestFile(payload.staged, 'sha1')); + } + return { bundle, carriers, layout, payloads }; +} + +// The preflight signs once. Publication reuses those bytes after binding the +// saved bundle to the current exact lock and selected Maven carrier set. +export function recordPreparedMavenBundle(prepared, lockDigest) { + const size = statSync(prepared.bundle).size; + assertMavenCentralBundleSize(size); + const receipt = { + lockDigest, + carriers: prepared.carriers.map(({ id }) => id).sort(compareText), + sha256: digestFile(prepared.bundle, 'sha256'), + size, + }; + writeFileSync(path.join(path.dirname(prepared.bundle), 'prepared.json'), JSON.stringify(receipt)); + return receipt; +} + +export function loadPreparedMavenBundle({ lock, products, outputRoot }) { + const receipt = JSON.parse(readFileSync(path.join(outputRoot, 'prepared.json'), 'utf8')); + const carriers = lockedCarriers(lock, { products, ecosystem: 'maven' }); + const expected = carriers.map(({ id }) => id).sort(compareText); + if ( + !expected.length || + receipt.lockDigest !== lock.lockDigest || + JSON.stringify(receipt.carriers) !== JSON.stringify(expected) + ) + throw error('prepared Maven bundle does not match the exact publication lock and selection'); + const bundle = path.join(outputRoot, 'central-bundle.zip'); + const size = statSync(bundle).size; + assertMavenCentralBundleSize(size); + if (receipt.size !== size || receipt.sha256 !== digestFile(bundle, 'sha256')) + throw error('prepared Maven bundle bytes changed after preflight'); + return { bundle, bundleSize: size, carriers }; +} + +export function assertMavenCentralBundleSize(size, maximum = MAX_CENTRAL_BUNDLE_BYTES) { + if (!Number.isSafeInteger(size) || size < 1) { + throw error(`Maven Central deployment bundle size must be a positive integer, got ${size}`); + } + if (!Number.isSafeInteger(maximum) || maximum < 1) { + throw error( + `Maven Central deployment bundle maximum must be a positive integer, got ${maximum}`, + ); + } + if (size >= maximum) { + throw error( + `Maven Central deployment bundle is ${size} bytes; the portal requires bundles smaller than ${maximum} bytes`, + ); + } +} + +function boundedDetail(body) { + return body + .replace(/[\r\n\t]+/gu, ' ') + .trim() + .slice(0, 500); +} + +async function boundedResponseText(response) { + const contentLength = response.headers?.get?.('content-length'); + if (contentLength !== null && contentLength !== undefined) { + const declared = Number(contentLength); + if (!Number.isSafeInteger(declared) || declared < 0) { + await response.body?.cancel?.().catch(() => {}); + throw error('Maven Central returned an invalid Content-Length'); + } + if (declared > MAX_CENTRAL_RESPONSE_BYTES) { + await response.body?.cancel?.().catch(() => {}); + throw error(`Maven Central response exceeds ${MAX_CENTRAL_RESPONSE_BYTES} bytes`); + } + } + + const reader = response.body?.getReader?.(); + if (reader === undefined) { + const text = await response.text(); + if (Buffer.byteLength(text) > MAX_CENTRAL_RESPONSE_BYTES) { + throw error(`Maven Central response exceeds ${MAX_CENTRAL_RESPONSE_BYTES} bytes`); + } + return text; + } + const chunks = []; + let size = 0; + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > MAX_CENTRAL_RESPONSE_BYTES) { + await reader.cancel().catch(() => {}); + throw error(`Maven Central response exceeds ${MAX_CENTRAL_RESPONSE_BYTES} bytes`); + } + chunks.push(Buffer.from(value)); + } + } finally { + reader.releaseLock(); + } + return Buffer.concat(chunks, size).toString('utf8'); +} + +async function centralRequest( + url, + { + authorization, + deadlineEpochSeconds, + nowImpl, + method = 'GET', + body = undefined, + fetchImpl = fetch, + }, +) { + const timeoutMs = Math.min( + CENTRAL_REQUEST_TIMEOUT_MS, + remainingBeforeReserve({ + deadlineEpochSeconds, + nowImpl, + context: `Maven Central ${method} ${url}`, + }), + ); + const response = await fetchImpl(url, { + method, + headers: { + Accept: 'application/json', + Authorization: authorization, + }, + body, + redirect: 'error', + signal: AbortSignal.timeout(Math.max(1, timeoutMs)), + }); + const text = await boundedResponseText(response); + if (!response.ok) { + throw error( + `Maven Central request returned HTTP ${response.status}${text ? `: ${boundedDetail(text)}` : ''}`, + ); + } + return text; +} + +async function findDeployment({ + authorization, + deadlineEpochSeconds, + deploymentName, + namespace, + apiBase, + fetchImpl, + nowImpl, +}) { + const url = new URL(`${apiBase.replace(/\/+$/u, '')}/deployments`); + url.searchParams.set('namespace', namespace); + url.searchParams.set('page', '0'); + url.searchParams.set('size', '100'); + const text = await centralRequest(url, { + authorization, + deadlineEpochSeconds, + fetchImpl, + nowImpl, + }); + let value; + try { + value = JSON.parse(text); + } catch (cause) { + throw error(`Maven Central deployments response is invalid JSON: ${cause.message}`); + } + const matches = + value?.deployments?.filter((deployment) => deployment?.deploymentName === deploymentName) ?? []; + if (matches.length > 1) { + throw error(`Maven Central contains multiple deployments named ${deploymentName}`); + } + return matches[0] ?? null; +} + +async function uploadBundle({ + bundle, + authorization, + deploymentName, + namespace, + apiBase, + deadlineEpochSeconds, + fetchImpl, + nowImpl, + sleep, +}) { + const request = { authorization, deadlineEpochSeconds, fetchImpl, nowImpl }; + const existing = await findDeployment({ + ...request, + deploymentName, + namespace, + apiBase, + }); + if (existing !== null) { + const id = existing.deploymentId; + if (typeof id !== 'string' || !DEPLOYMENT_ID.test(id)) { + throw error( + `Maven Central deployment ${deploymentName} has invalid deployment ID ${JSON.stringify(id)}`, + ); + } + // A list response that already identifies a deployment as anything other + // than FAILED is never eligible for deletion. This preserves the existing + // VALIDATED promotion path and makes PUBLISHING/PUBLISHED fail-safe even + // if a subsequent status response were inconsistent. + if (existing.deploymentState !== undefined && existing.deploymentState !== 'FAILED') { + return id; + } + const status = await deploymentStatus({ id, apiBase, ...request }); + if (status?.deploymentState !== 'FAILED') { + return id; + } + if (status.deploymentId !== id) { + throw error( + `refusing to drop failed Maven Central deployment ${id}: status returned deployment ID ${JSON.stringify(status.deploymentId)}`, + ); + } + if (status.deploymentName !== undefined && status.deploymentName !== deploymentName) { + throw error( + `refusing to drop failed Maven Central deployment ${id}: status returned name ${JSON.stringify(status.deploymentName)}`, + ); + } + await centralRequest(`${apiBase.replace(/\/+$/u, '')}/deployment/${encodeURIComponent(id)}`, { + ...request, + method: 'DELETE', + }); + for (let attempt = 0; attempt < DROP_VISIBILITY_ATTEMPTS; attempt += 1) { + const retained = await findDeployment({ + ...request, + deploymentName, + namespace, + apiBase, + }); + if (retained === null) { + break; + } + if (retained.deploymentId !== id) { + throw error( + `Maven Central deployment name ${deploymentName} was reused by ${JSON.stringify(retained.deploymentId)} while dropping ${id}`, + ); + } + if (attempt === DROP_VISIBILITY_ATTEMPTS - 1) { + throw error(`Maven Central failed deployment ${id} remained visible after it was dropped`); + } + await boundedSleep(DROP_VISIBILITY_INTERVAL_MS, { + deadlineEpochSeconds, + nowImpl, + sleep, + context: `Maven Central failed-deployment removal for ${id}`, + }); + } + } + const url = new URL(`${apiBase.replace(/\/+$/u, '')}/upload`); + url.searchParams.set('name', deploymentName); + url.searchParams.set('publishingType', 'USER_MANAGED'); + const form = new FormData(); + form.set( + 'bundle', + new Blob([readFileSync(bundle)], { type: 'application/octet-stream' }), + path.basename(bundle), + ); + try { + const text = await centralRequest(url, { + ...request, + method: 'POST', + body: form, + }); + const id = text.trim(); + if (!DEPLOYMENT_ID.test(id)) { + throw error(`Maven Central upload returned invalid deployment ID ${JSON.stringify(id)}`); + } + return id; + } catch (cause) { + // Never retry an ambiguous upload. Reconcile by its lock-derived unique + // name; if the server did not retain it, the caller can safely rerun. + const reconciled = await findDeployment({ + ...request, + deploymentName, + namespace, + apiBase, + }); + if (reconciled !== null) { + return reconciled.deploymentId; + } + throw cause; + } +} + +async function deploymentStatus({ + id, + authorization, + deadlineEpochSeconds, + apiBase, + fetchImpl, + nowImpl, +}) { + const url = new URL(`${apiBase.replace(/\/+$/u, '')}/status`); + url.searchParams.set('id', id); + const text = await centralRequest(url, { + authorization, + deadlineEpochSeconds, + method: 'POST', + fetchImpl, + nowImpl, + }); + try { + return JSON.parse(text); + } catch (cause) { + throw error(`Maven Central status response is invalid JSON: ${cause.message}`); + } +} + +async function waitForDeployment({ + id, + authorization, + deadlineEpochSeconds, + apiBase, + fetchImpl, + nowImpl, + sleep, + acceptable, +}) { + for (let attempt = 0; attempt < 90; attempt += 1) { + const status = await deploymentStatus({ + id, + authorization, + deadlineEpochSeconds, + apiBase, + fetchImpl, + nowImpl, + }); + if (status?.deploymentState === 'FAILED') { + throw error( + `Maven Central deployment ${id} failed: ${boundedDetail(JSON.stringify(status.errors ?? status))}`, + ); + } + if (acceptable.has(status?.deploymentState)) { + return status; + } + if (TERMINAL_STATES.has(status?.deploymentState)) { + throw error( + `Maven Central deployment ${id} reached unexpected state ${status.deploymentState}`, + ); + } + await boundedSleep(10_000, { + deadlineEpochSeconds, + nowImpl, + sleep, + context: `Maven Central deployment ${id} visibility wait`, + }); + } + throw error( + `Maven Central deployment ${id} did not reach ${[...acceptable].join(' or ')} within 15 minutes`, + ); +} + +export async function publishFrozenMavenBundle({ + bundle, + lockDigest, + deploymentScope, + namespace, + username, + password, + deadlineEpochSeconds, + apiBase = CENTRAL_API, + fetchImpl = fetch, + nowImpl = () => Date.now(), + sleep = Bun.sleep, +}) { + const authorization = mavenCentralAuthorization(username, password); + if (typeof deploymentScope !== 'string' || deploymentScope.length === 0) { + throw error( + 'deploymentScope is required to distinguish product subsets from one publication lock', + ); + } + const scopeDigest = createHash('sha256').update(deploymentScope).digest('hex').slice(0, 12); + const deploymentName = `oliphaunt-${lockDigest.slice(0, 16)}-${scopeDigest}`; + const id = await uploadBundle({ + bundle, + authorization, + deploymentName, + namespace, + apiBase, + deadlineEpochSeconds, + fetchImpl, + nowImpl, + sleep, + }); + const validated = await waitForDeployment({ + id, + authorization, + deadlineEpochSeconds, + apiBase, + fetchImpl, + nowImpl, + sleep, + acceptable: new Set(['VALIDATED', 'PUBLISHING', 'PUBLISHED']), + }); + if (validated.deploymentState === 'VALIDATED') { + await centralRequest(`${apiBase.replace(/\/+$/u, '')}/deployment/${encodeURIComponent(id)}`, { + authorization, + deadlineEpochSeconds, + method: 'POST', + fetchImpl, + nowImpl, + }); + } + const published = + validated.deploymentState === 'PUBLISHED' + ? validated + : await waitForDeployment({ + id, + authorization, + deadlineEpochSeconds, + apiBase, + fetchImpl, + nowImpl, + sleep, + acceptable: new Set(['PUBLISHED']), + }); + return { deploymentId: id, deploymentName, status: published }; +} diff --git a/tools/release/frozen-maven-publish.test.mjs b/tools/release/frozen-maven-publish.test.mjs deleted file mode 100644 index 57e245f46..000000000 --- a/tools/release/frozen-maven-publish.test.mjs +++ /dev/null @@ -1,512 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { createHash } from "node:crypto"; -import { mkdtempSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs"; -import path from "node:path"; - -import { - assertMavenCentralBundleSize, - prepareFrozenMavenBundle, - publishFrozenMavenBundle, - verifyGpgSigningCredentials, -} from "./frozen-maven-publish.mjs"; - -const temporaryDirectories = []; -const root = path.join(import.meta.dir, "../.."); -const testDeadlineEpochSeconds = 2_000; -const testNow = () => 1_000_000; - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function fixtureLock() { - const directory = mkdtempSync(path.join(root, "target/frozen-maven-test-")); - temporaryDirectories.push(directory); - const jar = path.join(directory, "fixture-1.2.3.jar"); - const pom = path.join(directory, "fixture-1.2.3.pom"); - const sources = path.join(directory, "fixture-1.2.3-sources.jar"); - const javadocs = path.join(directory, "fixture-1.2.3-javadoc.jar"); - writeFileSync(jar, "exact frozen jar bytes\n"); - writeFileSync(sources, "exact frozen sources placeholder\n"); - writeFileSync(javadocs, "exact frozen javadocs placeholder\n"); - writeFileSync(pom, "4.0.0dev.oliphauntfixture1.2.3FixtureFixture publicationhttps://github.com/f0rr0/oliphauntMIThttps://opensource.org/license/mitFixture Maintainerhttps://github.com/f0rr0scm:git:https://github.com/f0rr0/oliphaunt.gitscm:git:ssh://git@github.com:f0rr0/oliphaunt.githttps://github.com/f0rr0/oliphaunt\n"); - const envelope = (file) => ({ - path: path.relative(root, file).split(path.sep).join("/"), - sha256: sha256(file), - size: statSync(file).size, - }); - return { - directory, - jar, - lock: { - lockDigest: "a".repeat(64), - carriers: [{ - id: "maven:dev.oliphaunt:fixture", - product: "fixture-product", - ecosystem: "maven", - name: "dev.oliphaunt:fixture", - version: "1.2.3", - publishOrder: 0, - artifacts: [envelope(jar), envelope(pom), envelope(sources), envelope(javadocs)], - }], - }, - }; -} - -afterEach(() => { - while (temporaryDirectories.length > 0) { - rmSync(temporaryDirectories.pop(), { recursive: true, force: true }); - } -}); - -describe("frozen Maven Central publication", () => { - test("preflights the configured signing key, passphrase, signature, and fingerprint", () => { - const home = mkdtempSync(path.join(root, "target/frozen-maven-gpg-preflight-test-")); - temporaryDirectories.push(home); - const signingFingerprint = "A".repeat(40); - const primaryFingerprint = signingFingerprint; - const calls = []; - const result = verifyGpgSigningCredentials({ - privateKey: "armored private key", - keyId: `0x${primaryFingerprint.slice(-16)}`, - passphrase: "correct passphrase", - home, - runImpl(args, options) { - calls.push({ args, options }); - if (args.includes("--verify")) { - return `[GNUPG:] VALIDSIG ${signingFingerprint} 2026-07-20 0 4 0 1 10 00 ${primaryFingerprint}\n`; - } - return ""; - }, - }); - expect(result).toEqual({ signerFingerprint: signingFingerprint, primaryFingerprint }); - expect(calls.map(({ args }) => args.includes("--import") - ? "import" - : args.includes("--detach-sign") - ? "sign" - : args.includes("--verify") - ? "verify" - : "unexpected")).toEqual(["import", "sign", "verify"]); - expect(calls[0].options.input).toBe("armored private key"); - expect(calls[1].options.input).toBe("correct passphrase\n"); - }); - - test("rejects a verified signature from a different configured key ID", () => { - const home = mkdtempSync(path.join(root, "target/frozen-maven-gpg-mismatch-test-")); - temporaryDirectories.push(home); - expect(() => verifyGpgSigningCredentials({ - privateKey: "armored private key", - keyId: "C".repeat(16), - passphrase: "correct passphrase", - home, - runImpl(args) { - if (args.includes("--verify")) { - return `[GNUPG:] VALIDSIG ${"A".repeat(40)} 2026-07-20 0 4 0 1 10 00 ${"A".repeat(40)}\n`; - } - return ""; - }, - })).toThrow("configured Maven signing key ID does not match"); - }); - - test("rejects a valid signature made by a signing subkey", () => { - const home = mkdtempSync(path.join(root, "target/frozen-maven-gpg-subkey-test-")); - temporaryDirectories.push(home); - expect(() => verifyGpgSigningCredentials({ - privateKey: "armored private key", - keyId: "B".repeat(16), - passphrase: "correct passphrase", - home, - runImpl(args) { - if (args.includes("--verify")) { - return `[GNUPG:] VALIDSIG ${"A".repeat(40)} 2026-07-20 0 4 0 1 10 00 ${"B".repeat(40)}\n`; - } - return ""; - }, - })).toThrow("requires artifacts to be signed by the primary OpenPGP key"); - }); - - test("rejects malformed key selectors before importing signing material", () => { - const home = mkdtempSync(path.join(root, "target/frozen-maven-gpg-key-id-test-")); - temporaryDirectories.push(home); - let calls = 0; - expect(() => verifyGpgSigningCredentials({ - privateKey: "armored private key", - keyId: "release@example.invalid", - passphrase: "correct passphrase", - home, - runImpl() { - calls += 1; - return ""; - }, - })).toThrow("8-64 hexadecimal characters"); - expect(calls).toBe(0); - }); - - test("bundles exact locked payloads and generates only signatures and checksums", () => { - const { directory, jar, lock } = fixtureLock(); - const outputRoot = path.join(directory, "output"); - mkdirSync(outputRoot, { recursive: true }); - const result = prepareFrozenMavenBundle({ - lock, - products: ["fixture-product"], - outputRoot, - signFile(file, signature) { - writeFileSync(signature, `signature:${sha256(file)}\n`); - }, - }); - const staged = path.join(result.layout, "dev/oliphaunt/fixture/1.2.3/fixture-1.2.3.jar"); - expect(readFileSync(staged)).toEqual(readFileSync(jar)); - expect(readFileSync(`${staged}.md5`, "utf8")).toMatch(/^[0-9a-f]{32}$/u); - expect(readFileSync(`${staged}.sha1`, "utf8")).toMatch(/^[0-9a-f]{40}$/u); - expect(readFileSync(`${staged}.asc`, "utf8")).toContain(`signature:${sha256(jar)}`); - expect(statSync(result.bundle).size).toBeGreaterThan(0); - expect(result.bundleSize).toBe(statSync(result.bundle).size); - }); - - test("rejects a deployment bundle larger than the Central portal limit", () => { - expect(() => assertMavenCentralBundleSize(1_000_000_001)).toThrow("smaller than 1000000000 bytes"); - expect(() => assertMavenCentralBundleSize(1_000_000_000)).toThrow("smaller than 1000000000 bytes"); - expect(() => assertMavenCentralBundleSize(100, 99)).toThrow("smaller than 99 bytes"); - expect(() => assertMavenCentralBundleSize(100, 100)).toThrow("smaller than 100 bytes"); - expect(() => assertMavenCentralBundleSize(99, 100)).not.toThrow(); - }); - - test("uses a user-managed, lock-named deployment before explicit promotion", async () => { - const directory = mkdtempSync(path.join(root, "target/frozen-maven-api-test-")); - temporaryDirectories.push(directory); - const bundle = path.join(directory, "bundle.zip"); - writeFileSync(bundle, "bundle bytes"); - const calls = []; - let statusCalls = 0; - const fetchImpl = async (rawUrl, init) => { - const url = new URL(rawUrl); - calls.push({ url, init }); - expect(new Headers(init.headers).get("authorization")).toBe("Bearer dXNlcjpwYXNz"); - if (url.pathname.endsWith("/deployments")) { - return Response.json({ deployments: [], page: 0, pageSize: 100, pageCount: 0, totalResultCount: 0 }); - } - if (url.pathname.endsWith("/upload")) { - expect(url.searchParams.get("publishingType")).toBe("USER_MANAGED"); - expect(url.searchParams.get("name")).toMatch(/^oliphaunt-b{16}-[0-9a-f]{12}$/u); - expect(init.body.get("bundle")).toBeInstanceOf(Blob); - return new Response("28570f16-da32-4c14-bd2e-c1acc0782365", { status: 201 }); - } - if (url.pathname.endsWith("/status")) { - statusCalls += 1; - return Response.json({ - deploymentId: "28570f16-da32-4c14-bd2e-c1acc0782365", - deploymentState: statusCalls === 1 ? "VALIDATED" : "PUBLISHED", - }); - } - if (url.pathname.includes("/deployment/")) { - return new Response(null, { status: 204 }); - } - throw new Error(`unexpected URL ${url}`); - }; - const result = await publishFrozenMavenBundle({ - bundle, - lockDigest: "b".repeat(64), - deploymentScope: "fixture-product", - namespace: "dev.oliphaunt", - username: "user", - password: "pass", - deadlineEpochSeconds: testDeadlineEpochSeconds, - apiBase: "https://central.invalid/api/v1/publisher", - fetchImpl, - nowImpl: testNow, - sleep: async () => {}, - }); - expect(result.deploymentId).toBe("28570f16-da32-4c14-bd2e-c1acc0782365"); - expect(result.status.deploymentState).toBe("PUBLISHED"); - expect(calls.map(({ url, init }) => `${init.method}:${url.pathname.split("/").at(-1)}`)).toEqual([ - "GET:deployments", - "POST:upload", - "POST:status", - "POST:28570f16-da32-4c14-bd2e-c1acc0782365", - "POST:status", - ]); - }); - - test("drops an existing failed deployment, verifies removal, and re-uploads the frozen bundle", async () => { - const directory = mkdtempSync(path.join(root, "target/frozen-maven-failed-retry-test-")); - temporaryDirectories.push(directory); - const bundle = path.join(directory, "bundle.zip"); - writeFileSync(bundle, "exact frozen bundle bytes"); - const failedId = "11111111-1111-4111-8111-111111111111"; - const retriedId = "22222222-2222-4222-8222-222222222222"; - const calls = []; - let deploymentListCalls = 0; - let retriedStatusCalls = 0; - let deploymentName; - const fetchImpl = async (rawUrl, init) => { - const url = new URL(rawUrl); - calls.push({ url, init }); - if (url.pathname.endsWith("/deployments")) { - deploymentListCalls += 1; - return Response.json({ - deployments: deploymentListCalls === 1 - ? [{ - deploymentId: failedId, - deploymentName: url.searchParams.get("name") ?? deploymentName, - deploymentState: "FAILED", - }] - : [], - }); - } - if (url.pathname.endsWith("/status")) { - const id = url.searchParams.get("id"); - if (id === failedId) { - return Response.json({ - deploymentId: failedId, - deploymentName, - deploymentState: "FAILED", - errors: { bundle: ["validation failed"] }, - }); - } - expect(id).toBe(retriedId); - retriedStatusCalls += 1; - return Response.json({ - deploymentId: retriedId, - deploymentName, - deploymentState: retriedStatusCalls === 1 ? "VALIDATED" : "PUBLISHED", - }); - } - if (url.pathname.endsWith(`/deployment/${failedId}`)) { - expect(init.method).toBe("DELETE"); - return new Response(null, { status: 204 }); - } - if (url.pathname.endsWith("/upload")) { - expect(init.method).toBe("POST"); - deploymentName = url.searchParams.get("name"); - expect(deploymentName).toMatch(/^oliphaunt-c{16}-[0-9a-f]{12}$/u); - expect(await init.body.get("bundle").text()).toBe("exact frozen bundle bytes"); - return new Response(retriedId, { status: 201 }); - } - if (url.pathname.endsWith(`/deployment/${retriedId}`)) { - expect(init.method).toBe("POST"); - return new Response(null, { status: 204 }); - } - throw new Error(`unexpected URL ${url}`); - }; - deploymentName = `oliphaunt-${"c".repeat(16)}-${createHash("sha256").update("fixture-product").digest("hex").slice(0, 12)}`; - const result = await publishFrozenMavenBundle({ - bundle, - lockDigest: "c".repeat(64), - deploymentScope: "fixture-product", - namespace: "dev.oliphaunt", - username: "user", - password: "pass", - deadlineEpochSeconds: testDeadlineEpochSeconds, - apiBase: "https://central.invalid/api/v1/publisher", - fetchImpl, - nowImpl: testNow, - sleep: async () => {}, - }); - expect(result.deploymentId).toBe(retriedId); - expect(result.status.deploymentState).toBe("PUBLISHED"); - expect(calls.map(({ url, init }) => `${init.method}:${url.pathname}`)).toEqual([ - "GET:/api/v1/publisher/deployments", - "POST:/api/v1/publisher/status", - `DELETE:/api/v1/publisher/deployment/${failedId}`, - "GET:/api/v1/publisher/deployments", - "POST:/api/v1/publisher/upload", - "POST:/api/v1/publisher/status", - `POST:/api/v1/publisher/deployment/${retriedId}`, - "POST:/api/v1/publisher/status", - ]); - }); - - test("refuses to drop a failed deployment when the status identity does not match", async () => { - const directory = mkdtempSync(path.join(root, "target/frozen-maven-failed-identity-test-")); - temporaryDirectories.push(directory); - const bundle = path.join(directory, "bundle.zip"); - writeFileSync(bundle, "exact frozen bundle bytes"); - const id = "44444444-4444-4444-8444-444444444444"; - const calls = []; - const expectedDeploymentName = `oliphaunt-${"e".repeat(16)}-${createHash("sha256").update("fixture-product").digest("hex").slice(0, 12)}`; - const fetchImpl = async (rawUrl, init) => { - const url = new URL(rawUrl); - calls.push({ url, init }); - if (url.pathname.endsWith("/deployments")) { - return Response.json({ - deployments: [{ - deploymentId: id, - deploymentName: expectedDeploymentName, - deploymentState: "FAILED", - }], - }); - } - if (url.pathname.endsWith("/status")) { - return Response.json({ - deploymentId: "55555555-5555-4555-8555-555555555555", - deploymentName: expectedDeploymentName, - deploymentState: "FAILED", - }); - } - throw new Error(`unsafe mutation attempted: ${init.method} ${url}`); - }; - await expect(publishFrozenMavenBundle({ - bundle, - lockDigest: "e".repeat(64), - deploymentScope: "fixture-product", - namespace: "dev.oliphaunt", - username: "user", - password: "pass", - deadlineEpochSeconds: testDeadlineEpochSeconds, - apiBase: "https://central.invalid/api/v1/publisher", - fetchImpl, - nowImpl: testNow, - sleep: async () => {}, - })).rejects.toThrow("refusing to drop failed Maven Central deployment"); - expect(calls.every(({ url }) => url.pathname.endsWith("/deployments") || url.pathname.endsWith("/status"))).toBe(true); - }); - - for (const existingState of ["PUBLISHING", "PUBLISHED"]) { - test(`reuses an existing ${existingState} deployment without deleting or re-uploading`, async () => { - const directory = mkdtempSync(path.join(root, `target/frozen-maven-${existingState.toLowerCase()}-test-`)); - temporaryDirectories.push(directory); - const bundle = path.join(directory, "bundle.zip"); - writeFileSync(bundle, "exact frozen bundle bytes"); - const id = "33333333-3333-4333-8333-333333333333"; - const expectedDeploymentName = `oliphaunt-${"d".repeat(16)}-${createHash("sha256").update("fixture-product").digest("hex").slice(0, 12)}`; - const calls = []; - let statusCalls = 0; - const fetchImpl = async (rawUrl, init) => { - const url = new URL(rawUrl); - calls.push({ url, init }); - if (url.pathname.endsWith("/deployments")) { - return Response.json({ - deployments: [{ - deploymentId: id, - deploymentName: expectedDeploymentName, - deploymentState: existingState, - }], - }); - } - if (url.pathname.endsWith("/status")) { - statusCalls += 1; - return Response.json({ - deploymentId: id, - deploymentState: statusCalls === 1 ? existingState : "PUBLISHED", - }); - } - throw new Error(`unsafe mutation attempted for ${existingState}: ${init.method} ${url}`); - }; - const result = await publishFrozenMavenBundle({ - bundle, - lockDigest: "d".repeat(64), - deploymentScope: "fixture-product", - namespace: "dev.oliphaunt", - username: "user", - password: "pass", - deadlineEpochSeconds: testDeadlineEpochSeconds, - apiBase: "https://central.invalid/api/v1/publisher", - fetchImpl, - nowImpl: testNow, - sleep: async () => {}, - }); - expect(result.deploymentId).toBe(id); - expect(result.status.deploymentState).toBe("PUBLISHED"); - expect(calls.every(({ url }) => url.pathname.endsWith("/deployments") || url.pathname.endsWith("/status"))).toBe(true); - expect(calls.some(({ url, init }) => init.method === "DELETE" || url.pathname.endsWith("/upload"))).toBe(false); - }); - } - - test("rejects mutation before bundle creation", () => { - const { directory, jar, lock } = fixtureLock(); - writeFileSync(jar, "regenerated jar bytes\n"); - expect(() => prepareFrozenMavenBundle({ - lock, - products: ["fixture-product"], - outputRoot: path.join(directory, "output"), - signFile() {}, - })).toThrow("bytes do not match"); - }); - - test("rejects an oversized Central response before upload", async () => { - const directory = mkdtempSync(path.join(root, "target/frozen-maven-oversized-response-test-")); - temporaryDirectories.push(directory); - const bundle = path.join(directory, "bundle.zip"); - writeFileSync(bundle, "exact frozen bundle bytes"); - let calls = 0; - const fetchImpl = async () => { - calls += 1; - return new Response("x", { - status: 200, - headers: { "content-length": String(1024 * 1024 + 1) }, - }); - }; - await expect(publishFrozenMavenBundle({ - bundle, - lockDigest: "f".repeat(64), - deploymentScope: "fixture-product", - namespace: "dev.oliphaunt", - username: "user", - password: "pass", - deadlineEpochSeconds: testDeadlineEpochSeconds, - apiBase: "https://central.invalid/api/v1/publisher", - fetchImpl, - nowImpl: testNow, - sleep: async () => {}, - })).rejects.toThrow("Maven Central response exceeds"); - expect(calls).toBe(1); - }); - - test("refuses requests and visibility waits that cannot fit the shared deadline", async () => { - const directory = mkdtempSync(path.join(root, "target/frozen-maven-deadline-test-")); - temporaryDirectories.push(directory); - const bundle = path.join(directory, "bundle.zip"); - writeFileSync(bundle, "exact frozen bundle bytes"); - let calls = 0; - - await expect(publishFrozenMavenBundle({ - bundle, - lockDigest: "1".repeat(64), - deploymentScope: "fixture-product", - namespace: "dev.oliphaunt", - username: "user", - password: "pass", - deadlineEpochSeconds: 1_005, - apiBase: "https://central.invalid/api/v1/publisher", - fetchImpl: async () => { - calls += 1; - return Response.json({ deployments: [] }); - }, - nowImpl: () => 1_000_000, - sleep: async () => {}, - })).rejects.toThrow(/shared registry mutation deadline has been reached/u); - expect(calls).toBe(0); - - let now = 1_000_000; - await expect(publishFrozenMavenBundle({ - bundle, - lockDigest: "2".repeat(64), - deploymentScope: "fixture-product", - namespace: "dev.oliphaunt", - username: "user", - password: "pass", - deadlineEpochSeconds: 1_020, - apiBase: "https://central.invalid/api/v1/publisher", - fetchImpl: async (rawUrl) => { - const url = new URL(rawUrl); - if (url.pathname.endsWith("/deployments")) { - return Response.json({ - deployments: [{ - deploymentId: "33333333-3333-4333-8333-333333333333", - deploymentName: `oliphaunt-${"2".repeat(16)}-${createHash("sha256").update("fixture-product").digest("hex").slice(0, 12)}`, - deploymentState: "PUBLISHING", - }], - }); - } - return Response.json({ - deploymentId: "33333333-3333-4333-8333-333333333333", - deploymentState: "PUBLISHING", - }); - }, - nowImpl: () => now, - sleep: async (milliseconds) => { - now += milliseconds; - }, - })).rejects.toThrow(/cannot wait 10s before the shared registry mutation deadline/u); - }); -}); diff --git a/tools/release/frozen-maven-publish.test.mts b/tools/release/frozen-maven-publish.test.mts new file mode 100644 index 000000000..14f41a8dd --- /dev/null +++ b/tools/release/frozen-maven-publish.test.mts @@ -0,0 +1,506 @@ +import { afterEach, describe, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { readZipEntries } from '../packaging/release-carrier.mts'; +import { + assertMavenCentralBundleSize, + loadPreparedMavenBundle, + publishFrozenMavenBundle, + stageFrozenMavenBundle, +} from './frozen-maven-publish.mts'; + +const temporaryDirectories = []; +const root = path.join(import.meta.dir, '../..'); +mkdirSync(path.join(root, 'target'), { recursive: true }); +const testDeadlineEpochSeconds = 2_000; +const testNow = () => 1_000_000; + +function sha256(file) { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} + +function fixtureLock(directory = mkdtempSync(path.join(root, 'target/frozen-maven-test-'))) { + temporaryDirectories.push(directory); + const jar = path.join(directory, 'fixture-1.2.3.jar'); + const pom = path.join(directory, 'fixture-1.2.3.pom'); + const sources = path.join(directory, 'fixture-1.2.3-sources.jar'); + const javadocs = path.join(directory, 'fixture-1.2.3-javadoc.jar'); + writeFileSync(jar, 'exact frozen jar bytes\n'); + writeFileSync(sources, 'exact frozen sources placeholder\n'); + writeFileSync(javadocs, 'exact frozen javadocs placeholder\n'); + writeFileSync( + pom, + '4.0.0dev.oliphauntfixture1.2.3FixtureFixture publicationhttps://github.com/f0rr0/oliphauntMIThttps://opensource.org/license/mitFixture Maintainerhttps://github.com/f0rr0scm:git:https://github.com/f0rr0/oliphaunt.gitscm:git:ssh://git@github.com:f0rr0/oliphaunt.githttps://github.com/f0rr0/oliphaunt\n', + ); + const envelope = (file) => ({ + path: path.relative(root, file).split(path.sep).join('/'), + sha256: sha256(file), + size: statSync(file).size, + }); + return { + directory, + jar, + lock: { + lockDigest: 'a'.repeat(64), + carriers: [ + { + id: 'maven:dev.oliphaunt:fixture', + product: 'fixture-product', + ecosystem: 'maven', + name: 'dev.oliphaunt:fixture', + version: '1.2.3', + publishOrder: 0, + artifacts: [envelope(jar), envelope(pom), envelope(sources), envelope(javadocs)], + }, + ], + }, + }; +} + +if (['prepare-signing', 'verify-signing'].includes(process.argv[2])) { + const directory = process.argv[3]; + const statePath = path.join(directory, 'test-state.json'); + const outputRoot = path.join(directory, 'output'); + if (process.argv[2] === 'prepare-signing') { + const { jar, lock } = fixtureLock(directory); + mkdirSync(outputRoot, { recursive: true }); + const prepared = stageFrozenMavenBundle({ lock, products: ['fixture-product'], outputRoot }); + const staged = path.join(prepared.layout, 'dev/oliphaunt/fixture/1.2.3/fixture-1.2.3.jar'); + expect(readFileSync(staged)).toEqual(readFileSync(jar)); + expect(readFileSync(staged + '.md5', 'utf8')).toMatch(/^[0-9a-f]{32}$/u); + expect(readFileSync(staged + '.sha1', 'utf8')).toMatch(/^[0-9a-f]{40}$/u); + writeFileSync( + path.join(outputRoot, 'context.json'), + JSON.stringify({ prepared, lockDigest: lock.lockDigest }), + ); + writeFileSync(statePath, JSON.stringify({ lock, prepared })); + writeFileSync( + path.join(directory, 'payloads.txt'), + prepared.payloads.map((payload) => payload.staged).join('\n') + '\n', + ); + } else { + const { lock, prepared } = JSON.parse(readFileSync(statePath, 'utf8')); + const ready = loadPreparedMavenBundle({ lock, products: ['fixture-product'], outputRoot }); + expect(ready.bundleSize).toBe(statSync(prepared.bundle).size); + const entries = readZipEntries(prepared.bundle); + expect(entries.size).toBeGreaterThan(0); + for (const payload of prepared.payloads) { + const name = path.relative(prepared.layout, payload.staged).split(path.sep).join('/'); + expect(Buffer.from(entries.get(name).data())).toEqual(readFileSync(payload.staged)); + expect(readFileSync(payload.staged + '.asc', 'utf8')).toContain('BEGIN PGP SIGNATURE'); + } + expect(() => + loadPreparedMavenBundle({ + lock: { ...lock, lockDigest: 'b'.repeat(64) }, + products: ['fixture-product'], + outputRoot, + }), + ).toThrow('exact publication lock'); + expect(() => loadPreparedMavenBundle({ lock, products: ['other'], outputRoot })).toThrow( + 'exact publication lock', + ); + writeFileSync(prepared.bundle, 'changed ZIP'); + expect(() => + loadPreparedMavenBundle({ lock, products: ['fixture-product'], outputRoot }), + ).toThrow('bytes changed'); + } + process.exit(0); +} + +afterEach(() => { + while (temporaryDirectories.length > 0) { + rmSync(temporaryDirectories.pop(), { recursive: true, force: true }); + } +}); + +describe('frozen Maven Central publication', () => { + test('rejects a deployment bundle larger than the Central portal limit', () => { + expect(() => assertMavenCentralBundleSize(1_000_000_001)).toThrow( + 'smaller than 1000000000 bytes', + ); + expect(() => assertMavenCentralBundleSize(1_000_000_000)).toThrow( + 'smaller than 1000000000 bytes', + ); + expect(() => assertMavenCentralBundleSize(100, 99)).toThrow('smaller than 99 bytes'); + expect(() => assertMavenCentralBundleSize(100, 100)).toThrow('smaller than 100 bytes'); + expect(() => assertMavenCentralBundleSize(99, 100)).not.toThrow(); + }); + + test('uses a user-managed, lock-named deployment before explicit promotion', async () => { + const directory = mkdtempSync(path.join(root, 'target/frozen-maven-api-test-')); + temporaryDirectories.push(directory); + const bundle = path.join(directory, 'bundle.zip'); + writeFileSync(bundle, 'bundle bytes'); + const calls = []; + let statusCalls = 0; + const fetchImpl = async (rawUrl, init) => { + const url = new URL(rawUrl); + calls.push({ url, init }); + expect(new Headers(init.headers).get('authorization')).toBe('Bearer dXNlcjpwYXNz'); + if (url.pathname.endsWith('/deployments')) { + return Response.json({ + deployments: [], + page: 0, + pageSize: 100, + pageCount: 0, + totalResultCount: 0, + }); + } + if (url.pathname.endsWith('/upload')) { + expect(url.searchParams.get('publishingType')).toBe('USER_MANAGED'); + expect(url.searchParams.get('name')).toMatch(/^oliphaunt-b{16}-[0-9a-f]{12}$/u); + expect(init.body.get('bundle')).toBeInstanceOf(Blob); + return new Response('28570f16-da32-4c14-bd2e-c1acc0782365', { status: 201 }); + } + if (url.pathname.endsWith('/status')) { + statusCalls += 1; + return Response.json({ + deploymentId: '28570f16-da32-4c14-bd2e-c1acc0782365', + deploymentState: statusCalls === 1 ? 'VALIDATED' : 'PUBLISHED', + }); + } + if (url.pathname.includes('/deployment/')) { + return new Response(null, { status: 204 }); + } + throw new Error(`unexpected URL ${url}`); + }; + const result = await publishFrozenMavenBundle({ + bundle, + lockDigest: 'b'.repeat(64), + deploymentScope: 'fixture-product', + namespace: 'dev.oliphaunt', + username: 'user', + password: 'pass', + deadlineEpochSeconds: testDeadlineEpochSeconds, + apiBase: 'https://central.invalid/api/v1/publisher', + fetchImpl, + nowImpl: testNow, + sleep: async () => {}, + }); + expect(result.deploymentId).toBe('28570f16-da32-4c14-bd2e-c1acc0782365'); + expect(result.status.deploymentState).toBe('PUBLISHED'); + expect( + calls.map(({ url, init }) => `${init.method}:${url.pathname.split('/').at(-1)}`), + ).toEqual([ + 'GET:deployments', + 'POST:upload', + 'POST:status', + 'POST:28570f16-da32-4c14-bd2e-c1acc0782365', + 'POST:status', + ]); + }); + + test('drops an existing failed deployment, verifies removal, and re-uploads the frozen bundle', async () => { + const directory = mkdtempSync(path.join(root, 'target/frozen-maven-failed-retry-test-')); + temporaryDirectories.push(directory); + const bundle = path.join(directory, 'bundle.zip'); + writeFileSync(bundle, 'exact frozen bundle bytes'); + const failedId = '11111111-1111-4111-8111-111111111111'; + const retriedId = '22222222-2222-4222-8222-222222222222'; + const calls = []; + let deploymentListCalls = 0; + let retriedStatusCalls = 0; + let deploymentName; + const fetchImpl = async (rawUrl, init) => { + const url = new URL(rawUrl); + calls.push({ url, init }); + if (url.pathname.endsWith('/deployments')) { + deploymentListCalls += 1; + return Response.json({ + deployments: + deploymentListCalls === 1 + ? [ + { + deploymentId: failedId, + deploymentName: url.searchParams.get('name') ?? deploymentName, + deploymentState: 'FAILED', + }, + ] + : [], + }); + } + if (url.pathname.endsWith('/status')) { + const id = url.searchParams.get('id'); + if (id === failedId) { + return Response.json({ + deploymentId: failedId, + deploymentName, + deploymentState: 'FAILED', + errors: { bundle: ['validation failed'] }, + }); + } + expect(id).toBe(retriedId); + retriedStatusCalls += 1; + return Response.json({ + deploymentId: retriedId, + deploymentName, + deploymentState: retriedStatusCalls === 1 ? 'VALIDATED' : 'PUBLISHED', + }); + } + if (url.pathname.endsWith(`/deployment/${failedId}`)) { + expect(init.method).toBe('DELETE'); + return new Response(null, { status: 204 }); + } + if (url.pathname.endsWith('/upload')) { + expect(init.method).toBe('POST'); + deploymentName = url.searchParams.get('name'); + expect(deploymentName).toMatch(/^oliphaunt-c{16}-[0-9a-f]{12}$/u); + expect(await init.body.get('bundle').text()).toBe('exact frozen bundle bytes'); + return new Response(retriedId, { status: 201 }); + } + if (url.pathname.endsWith(`/deployment/${retriedId}`)) { + expect(init.method).toBe('POST'); + return new Response(null, { status: 204 }); + } + throw new Error(`unexpected URL ${url}`); + }; + deploymentName = `oliphaunt-${'c'.repeat(16)}-${createHash('sha256').update('fixture-product').digest('hex').slice(0, 12)}`; + const result = await publishFrozenMavenBundle({ + bundle, + lockDigest: 'c'.repeat(64), + deploymentScope: 'fixture-product', + namespace: 'dev.oliphaunt', + username: 'user', + password: 'pass', + deadlineEpochSeconds: testDeadlineEpochSeconds, + apiBase: 'https://central.invalid/api/v1/publisher', + fetchImpl, + nowImpl: testNow, + sleep: async () => {}, + }); + expect(result.deploymentId).toBe(retriedId); + expect(result.status.deploymentState).toBe('PUBLISHED'); + expect(calls.map(({ url, init }) => `${init.method}:${url.pathname}`)).toEqual([ + 'GET:/api/v1/publisher/deployments', + 'POST:/api/v1/publisher/status', + `DELETE:/api/v1/publisher/deployment/${failedId}`, + 'GET:/api/v1/publisher/deployments', + 'POST:/api/v1/publisher/upload', + 'POST:/api/v1/publisher/status', + `POST:/api/v1/publisher/deployment/${retriedId}`, + 'POST:/api/v1/publisher/status', + ]); + }); + + test('refuses to drop a failed deployment when the status identity does not match', async () => { + const directory = mkdtempSync(path.join(root, 'target/frozen-maven-failed-identity-test-')); + temporaryDirectories.push(directory); + const bundle = path.join(directory, 'bundle.zip'); + writeFileSync(bundle, 'exact frozen bundle bytes'); + const id = '44444444-4444-4444-8444-444444444444'; + const calls = []; + const expectedDeploymentName = `oliphaunt-${'e'.repeat(16)}-${createHash('sha256').update('fixture-product').digest('hex').slice(0, 12)}`; + const fetchImpl = async (rawUrl, init) => { + const url = new URL(rawUrl); + calls.push({ url, init }); + if (url.pathname.endsWith('/deployments')) { + return Response.json({ + deployments: [ + { + deploymentId: id, + deploymentName: expectedDeploymentName, + deploymentState: 'FAILED', + }, + ], + }); + } + if (url.pathname.endsWith('/status')) { + return Response.json({ + deploymentId: '55555555-5555-4555-8555-555555555555', + deploymentName: expectedDeploymentName, + deploymentState: 'FAILED', + }); + } + throw new Error(`unsafe mutation attempted: ${init.method} ${url}`); + }; + await expect( + publishFrozenMavenBundle({ + bundle, + lockDigest: 'e'.repeat(64), + deploymentScope: 'fixture-product', + namespace: 'dev.oliphaunt', + username: 'user', + password: 'pass', + deadlineEpochSeconds: testDeadlineEpochSeconds, + apiBase: 'https://central.invalid/api/v1/publisher', + fetchImpl, + nowImpl: testNow, + sleep: async () => {}, + }), + ).rejects.toThrow('refusing to drop failed Maven Central deployment'); + expect( + calls.every( + ({ url }) => url.pathname.endsWith('/deployments') || url.pathname.endsWith('/status'), + ), + ).toBe(true); + }); + + for (const existingState of ['PUBLISHING', 'PUBLISHED']) { + test(`reuses an existing ${existingState} deployment without deleting or re-uploading`, async () => { + const directory = mkdtempSync( + path.join(root, `target/frozen-maven-${existingState.toLowerCase()}-test-`), + ); + temporaryDirectories.push(directory); + const bundle = path.join(directory, 'bundle.zip'); + writeFileSync(bundle, 'exact frozen bundle bytes'); + const id = '33333333-3333-4333-8333-333333333333'; + const expectedDeploymentName = `oliphaunt-${'d'.repeat(16)}-${createHash('sha256').update('fixture-product').digest('hex').slice(0, 12)}`; + const calls = []; + let statusCalls = 0; + const fetchImpl = async (rawUrl, init) => { + const url = new URL(rawUrl); + calls.push({ url, init }); + if (url.pathname.endsWith('/deployments')) { + return Response.json({ + deployments: [ + { + deploymentId: id, + deploymentName: expectedDeploymentName, + deploymentState: existingState, + }, + ], + }); + } + if (url.pathname.endsWith('/status')) { + statusCalls += 1; + return Response.json({ + deploymentId: id, + deploymentState: statusCalls === 1 ? existingState : 'PUBLISHED', + }); + } + throw new Error(`unsafe mutation attempted for ${existingState}: ${init.method} ${url}`); + }; + const result = await publishFrozenMavenBundle({ + bundle, + lockDigest: 'd'.repeat(64), + deploymentScope: 'fixture-product', + namespace: 'dev.oliphaunt', + username: 'user', + password: 'pass', + deadlineEpochSeconds: testDeadlineEpochSeconds, + apiBase: 'https://central.invalid/api/v1/publisher', + fetchImpl, + nowImpl: testNow, + sleep: async () => {}, + }); + expect(result.deploymentId).toBe(id); + expect(result.status.deploymentState).toBe('PUBLISHED'); + expect( + calls.every( + ({ url }) => url.pathname.endsWith('/deployments') || url.pathname.endsWith('/status'), + ), + ).toBe(true); + expect( + calls.some(({ url, init }) => init.method === 'DELETE' || url.pathname.endsWith('/upload')), + ).toBe(false); + }); + } + + test('rejects mutation before bundle creation', () => { + const { directory, jar, lock } = fixtureLock(); + writeFileSync(jar, 'regenerated jar bytes\n'); + expect(() => + stageFrozenMavenBundle({ + lock, + products: ['fixture-product'], + outputRoot: path.join(directory, 'output'), + }), + ).toThrow('bytes do not match'); + }); + + test('rejects an oversized Central response before upload', async () => { + const directory = mkdtempSync(path.join(root, 'target/frozen-maven-oversized-response-test-')); + temporaryDirectories.push(directory); + const bundle = path.join(directory, 'bundle.zip'); + writeFileSync(bundle, 'exact frozen bundle bytes'); + let calls = 0; + const fetchImpl = async () => { + calls += 1; + return new Response('x', { + status: 200, + headers: { 'content-length': String(1024 * 1024 + 1) }, + }); + }; + await expect( + publishFrozenMavenBundle({ + bundle, + lockDigest: 'f'.repeat(64), + deploymentScope: 'fixture-product', + namespace: 'dev.oliphaunt', + username: 'user', + password: 'pass', + deadlineEpochSeconds: testDeadlineEpochSeconds, + apiBase: 'https://central.invalid/api/v1/publisher', + fetchImpl, + nowImpl: testNow, + sleep: async () => {}, + }), + ).rejects.toThrow('Maven Central response exceeds'); + expect(calls).toBe(1); + }); + + test('refuses requests and visibility waits that cannot fit the shared deadline', async () => { + const directory = mkdtempSync(path.join(root, 'target/frozen-maven-deadline-test-')); + temporaryDirectories.push(directory); + const bundle = path.join(directory, 'bundle.zip'); + writeFileSync(bundle, 'exact frozen bundle bytes'); + let calls = 0; + + await expect( + publishFrozenMavenBundle({ + bundle, + lockDigest: '1'.repeat(64), + deploymentScope: 'fixture-product', + namespace: 'dev.oliphaunt', + username: 'user', + password: 'pass', + deadlineEpochSeconds: 1_005, + apiBase: 'https://central.invalid/api/v1/publisher', + fetchImpl: async () => { + calls += 1; + return Response.json({ deployments: [] }); + }, + nowImpl: () => 1_000_000, + sleep: async () => {}, + }), + ).rejects.toThrow(/shared registry mutation deadline has been reached/u); + expect(calls).toBe(0); + + let now = 1_000_000; + await expect( + publishFrozenMavenBundle({ + bundle, + lockDigest: '2'.repeat(64), + deploymentScope: 'fixture-product', + namespace: 'dev.oliphaunt', + username: 'user', + password: 'pass', + deadlineEpochSeconds: 1_020, + apiBase: 'https://central.invalid/api/v1/publisher', + fetchImpl: async (rawUrl) => { + const url = new URL(rawUrl); + if (url.pathname.endsWith('/deployments')) { + return Response.json({ + deployments: [ + { + deploymentId: '33333333-3333-4333-8333-333333333333', + deploymentName: `oliphaunt-${'2'.repeat(16)}-${createHash('sha256').update('fixture-product').digest('hex').slice(0, 12)}`, + deploymentState: 'PUBLISHING', + }, + ], + }); + } + return Response.json({ + deploymentId: '33333333-3333-4333-8333-333333333333', + deploymentState: 'PUBLISHING', + }); + }, + nowImpl: () => now, + sleep: async (milliseconds) => { + now += milliseconds; + }, + }), + ).rejects.toThrow(/cannot wait 10s before the shared registry mutation deadline/u); + }); +}); diff --git a/tools/release/frozen-maven-publish.test.sh b/tools/release/frozen-maven-publish.test.sh new file mode 100644 index 000000000..9070431f0 --- /dev/null +++ b/tools/release/frozen-maven-publish.test.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/frozen-maven-publish.test.mts +scratch="$(mktemp -d "$PWD/target/frozen-maven-signing.XXXXXX")" +signing_home="$scratch/gpg" +cleanup() { gpgconf --homedir "$signing_home" --kill all >/dev/null 2>&1 || true; rm -rf "$scratch"; } +trap cleanup EXIT +mkdir -m 700 "$signing_home" +bun tools/release/frozen-maven-publish.test.mts prepare-signing "$scratch" +printf '%s\n' 'fixture password' | gpg --batch --homedir "$signing_home" --pinentry-mode loopback --passphrase-fd 0 --quick-generate-key 'Maven bundle ' ed25519 sign 0 +fingerprint="$(gpg --batch --homedir "$signing_home" --with-colons --list-keys | awk -F: '$1=="fpr" {print $10;exit}')" +export ORG_GRADLE_PROJECT_signingInMemoryKeyId="$fingerprint" +export ORG_GRADLE_PROJECT_signingInMemoryKeyPassword='fixture password' +ORG_GRADLE_PROJECT_signingInMemoryKey="$(printf '%s\n' 'fixture password' | gpg --batch --homedir "$signing_home" --pinentry-mode loopback --passphrase-fd 0 --armor --export-secret-keys "$fingerprint")" +export ORG_GRADLE_PROJECT_signingInMemoryKey +bash tools/release/preflight-maven-central-bundle.sh --sign-staged "$scratch/output" +unset ORG_GRADLE_PROJECT_signingInMemoryKey ORG_GRADLE_PROJECT_signingInMemoryKeyPassword ORG_GRADLE_PROJECT_signingInMemoryKeyId +while IFS= read -r payload; do + gpg --batch --homedir "$signing_home" --verify "$payload.asc" "$payload" +done < "$scratch/payloads.txt" +bun tools/release/frozen-maven-publish.test.mts verify-signing "$scratch" +echo 'Frozen Maven signing, locked payload bytes, and immutable bundle checks passed' diff --git a/tools/release/frozen-npm-publish.mjs b/tools/release/frozen-npm-publish.mjs deleted file mode 100644 index 9ee394390..000000000 --- a/tools/release/frozen-npm-publish.mjs +++ /dev/null @@ -1,547 +0,0 @@ -import { spawnSync } from "node:child_process"; -import { createHash } from "node:crypto"; -import { readFileSync, statSync } from "node:fs"; -import process from "node:process"; - -import { - registryRetryDelaySeconds, - registryStatusRetryable, -} from "./registry-http-retry.mjs"; -import { requirePreMutationRegistryWindow } from "./registry-publication-deferral.mjs"; - -const DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org"; -const USER_AGENT = "oliphaunt-frozen-npm-publisher/1; https://github.com/f0rr0/oliphaunt"; -const REQUEST_ATTEMPTS = 5; -const REQUEST_TIMEOUT_MS = 30_000; -const PUBLISH_TIMEOUT_MS = 2 * 60_000; -const MINIMUM_PUBLISH_ATTEMPT_MS = 30_000; -const DEADLINE_RESERVE_MS = 5_000; -const MAX_METADATA_RESPONSE_BYTES = 8 * 1024 * 1024; -const MAX_READ_RETRY_DELAY_SECONDS = 30; -const VISIBILITY_ATTEMPTS = 12; -const VISIBILITY_DELAY_MS = 10_000; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function error(message) { - return new Error(`frozen-npm-publish: ${message}`); -} - -function requiredText(value, context) { - if (typeof value !== "string" || value.trim().length === 0) { - throw error(`${context} is required`); - } - return value.trim(); -} - -function deadlineMilliseconds(deadlineEpochSeconds) { - if (!Number.isSafeInteger(deadlineEpochSeconds) || deadlineEpochSeconds < 1) { - throw error("registry mutation deadline must be a positive Unix timestamp"); - } - return deadlineEpochSeconds * 1000; -} - -function remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }) { - const remaining = deadlineMilliseconds(deadlineEpochSeconds) - nowImpl() - DEADLINE_RESERVE_MS; - if (remaining <= 0) { - throw error(`${context} refused because the shared registry mutation deadline has been reached`); - } - return remaining; -} - -function requestTimeout({ deadlineEpochSeconds, nowImpl, context }) { - return Math.max(1, Math.min( - REQUEST_TIMEOUT_MS, - remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }), - )); -} - -async function closeResponse(response) { - try { - await response.body?.cancel?.(); - } catch { - // The exact-version existence response has no useful body on 404. - } -} - -async function boundedJson(response, context) { - const declared = response.headers?.get?.("content-length"); - if (declared !== null && declared !== undefined) { - const length = Number(declared); - if (!Number.isSafeInteger(length) || length < 0) { - await closeResponse(response); - throw error(`${context} returned an invalid Content-Length`); - } - if (length > MAX_METADATA_RESPONSE_BYTES) { - await closeResponse(response); - throw error(`${context} response exceeds ${MAX_METADATA_RESPONSE_BYTES} bytes`); - } - } - let bytes; - const reader = response.body?.getReader?.(); - if (reader === undefined) { - bytes = Buffer.from(await response.arrayBuffer()); - if (bytes.length > MAX_METADATA_RESPONSE_BYTES) { - throw error(`${context} response exceeds ${MAX_METADATA_RESPONSE_BYTES} bytes`); - } - } else { - const chunks = []; - let size = 0; - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > MAX_METADATA_RESPONSE_BYTES) { - await reader.cancel().catch(() => {}); - throw error(`${context} response exceeds ${MAX_METADATA_RESPONSE_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - } finally { - reader.releaseLock(); - } - bytes = Buffer.concat(chunks, size); - } - try { - return JSON.parse(bytes.toString("utf8")); - } catch (cause) { - throw error(`${context} returned invalid JSON: ${cause.message}`); - } -} - -async function boundedSleep(milliseconds, { - deadlineEpochSeconds, - nowImpl, - sleepImpl, - context, -}) { - if (!Number.isFinite(milliseconds) || milliseconds < 0) { - throw error(`${context} requested an invalid retry delay`); - } - const remaining = remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }); - if (milliseconds >= remaining) { - throw error(`${context} cannot wait ${Math.ceil(milliseconds / 1000)}s before the shared registry mutation deadline`); - } - await sleepImpl(milliseconds); -} - -function npmVersionUrl(registry, packageName, version) { - return `${registry.replace(/\/+$/u, "")}/${encodeURIComponent(packageName)}/${encodeURIComponent(version)}`; -} - -function npmPackageUrl(registry, packageName) { - return `${registry.replace(/\/+$/u, "")}/${encodeURIComponent(packageName)}`; -} - -function canonicalNpmRegistry(value) { - const raw = requiredText(value, "npm registry"); - let parsed; - try { - parsed = new URL(raw); - } catch { - throw error(`npm registry must be ${DEFAULT_NPM_REGISTRY}`); - } - const normalizedPath = parsed.pathname.replace(/\/+$/u, "") || "/"; - if ( - parsed.protocol !== "https:" - || parsed.hostname !== "registry.npmjs.org" - || (parsed.port !== "" && parsed.port !== "443") - || normalizedPath !== "/" - || parsed.username !== "" - || parsed.password !== "" - || parsed.search !== "" - || parsed.hash !== "" - ) { - throw error(`npm registry must be the canonical public registry ${DEFAULT_NPM_REGISTRY}`); - } - return DEFAULT_NPM_REGISTRY; -} - -async function inspectNpmJsonResource({ - url, - context, - consumeJson, - deadlineEpochSeconds, - fetchImpl, - sleepImpl, - nowImpl, -}) { - let lastFailure = null; - for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { - const controller = new AbortController(); - const timeoutMs = requestTimeout({ deadlineEpochSeconds, nowImpl, context }); - const timeout = setTimeout( - () => controller.abort(new Error(`${context} timed out`)), - timeoutMs, - ); - try { - const response = await fetchImpl(url, { - headers: { - Accept: "application/json", - "User-Agent": USER_AGENT, - }, - redirect: "error", - signal: controller.signal, - }); - if (response.status === 404) { - await closeResponse(response); - return { found: false, metadata: null }; - } - if (response.status !== 200) { - const status = response.status; - const headers = response.headers; - await closeResponse(response); - lastFailure = `HTTP ${status}`; - if (!registryStatusRetryable(status) || attempt + 1 >= REQUEST_ATTEMPTS) break; - const delaySeconds = registryRetryDelaySeconds({ headers, attempt, now: nowImpl() }); - if (delaySeconds > MAX_READ_RETRY_DELAY_SECONDS) { - throw error(`${context} was rate limited for too long; retry the release later`); - } - await boundedSleep(Math.ceil(delaySeconds * 1000), { - deadlineEpochSeconds, - nowImpl, - sleepImpl, - context, - }); - continue; - } - if (!consumeJson) { - await closeResponse(response); - return { found: true, metadata: null }; - } - return { - found: true, - metadata: await boundedJson(response, `${context} metadata`), - }; - } catch (cause) { - if (cause instanceof Error && cause.message.startsWith("frozen-npm-publish:")) throw cause; - lastFailure = cause instanceof Error ? cause.message : String(cause); - if (attempt + 1 >= REQUEST_ATTEMPTS) break; - const delaySeconds = registryRetryDelaySeconds({ attempt, now: nowImpl() }); - await boundedSleep(Math.ceil(delaySeconds * 1000), { - deadlineEpochSeconds, - nowImpl, - sleepImpl, - context, - }); - } finally { - clearTimeout(timeout); - } - } - throw error(`cannot classify ${context}: ${lastFailure ?? "unknown registry response"}`); -} - -export async function inspectNpmPackageName({ - packageName, - registry = process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, - deadlineEpochSeconds, - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = () => Date.now(), -}) { - const name = requiredText(packageName, "npm package name"); - const canonicalRegistry = canonicalNpmRegistry(registry); - const url = npmPackageUrl(canonicalRegistry, name); - const state = await inspectNpmJsonResource({ - url, - context: `npm package-name check for ${name}`, - consumeJson: false, - deadlineEpochSeconds, - fetchImpl, - sleepImpl, - nowImpl, - }); - return { packageName: name, exists: state.found, url }; -} - -export function frozenNpmIntegrity(tarball) { - const file = requiredText(tarball, "frozen npm tarball"); - let stat; - try { - stat = statSync(file); - } catch { - throw error(`frozen npm tarball is unavailable: ${file}`); - } - if (!stat.isFile()) { - throw error(`frozen npm tarball is not a file: ${file}`); - } - const digest = createHash("sha512").update(readFileSync(file)).digest("base64"); - return `sha512-${digest}`; -} - -export async function inspectNpmExactVersion({ - packageName, - version, - expectedIntegrity = undefined, - registry = process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, - deadlineEpochSeconds, - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = () => Date.now(), -}) { - const name = requiredText(packageName, "npm package name"); - const exactVersion = requiredText(version, "npm package version"); - const canonicalRegistry = canonicalNpmRegistry(registry); - const url = npmVersionUrl(canonicalRegistry, name, exactVersion); - const exact = await inspectNpmJsonResource({ - url, - context: `npm exact-version check for ${name}@${exactVersion}`, - consumeJson: true, - deadlineEpochSeconds, - fetchImpl, - sleepImpl, - nowImpl, - }); - if (!exact.found) { - // A version-level 404 is ambiguous: bootstrap is allowed to create only a - // completely absent package name, never a later version of an existing - // package. Resolve the package-name state with a normal JSON registry GET. - const packageState = await inspectNpmPackageName({ - packageName: name, - registry: canonicalRegistry, - deadlineEpochSeconds, - fetchImpl, - sleepImpl, - nowImpl, - }); - return { - packageName: name, - version: exactVersion, - published: false, - nameExists: packageState.exists, - state: packageState.exists ? "pending-version" : "missing-name", - integrity: null, - url, - packageUrl: packageState.url, - }; - } - const integrity = exact.metadata?.dist?.integrity; - if (typeof integrity !== "string" || integrity.trim().length === 0) { - throw error(`npm metadata for ${name}@${exactVersion} lacks dist.integrity`); - } - const tokens = integrity.trim().split(/\s+/u); - if (expectedIntegrity !== undefined && !tokens.includes(expectedIntegrity)) { - throw error( - `immutable npm version ${name}@${exactVersion} conflicts with the frozen tarball: expected ${expectedIntegrity}, registry=${integrity}`, - ); - } - return { - packageName: name, - version: exactVersion, - published: true, - nameExists: true, - state: "published", - integrity, - url, - packageUrl: npmPackageUrl(canonicalRegistry, name), - }; -} - -function selectedNpmIdentities(plan) { - if (!Array.isArray(plan)) throw error("bootstrap publication plan must be a list"); - const identities = plan - .filter(({ ecosystem }) => ecosystem === "npm") - .map(({ name, version }, index) => ({ - name: requiredText(name, `npm plan entry ${index} name`), - version: requiredText(version, `npm plan entry ${index} version`), - })) - .sort((left, right) => compareText(`${left.name}@${left.version}`, `${right.name}@${right.version}`)); - const unique = new Set(identities.map(({ name }) => name)); - if (unique.size !== identities.length) { - throw error("exact publication lock selects duplicate npm package names"); - } - return identities; -} - -export async function inspectNpmVersionState({ - plan, - registry = process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, - deadlineEpochSeconds, - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = () => Date.now(), - concurrency = 8, -}) { - if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) { - throw error("npm existence-check concurrency must be an integer from 1 through 32"); - } - const identities = selectedNpmIdentities(plan); - const observed = new Array(identities.length); - let cursor = 0; - const workers = Array.from({ length: Math.min(concurrency, identities.length) }, async () => { - for (;;) { - const index = cursor; - cursor += 1; - if (index >= identities.length) return; - const identity = identities[index]; - observed[index] = await inspectNpmExactVersion({ - packageName: identity.name, - version: identity.version, - registry, - deadlineEpochSeconds, - fetchImpl, - sleepImpl, - nowImpl, - }); - } - }); - await Promise.all(workers); - return { - selectedIdentities: identities, - publishedIdentities: identities.filter((_, index) => observed[index].published), - pendingVersions: identities.filter((_, index) => observed[index].state === "pending-version"), - missingNames: identities.filter((_, index) => observed[index].state === "missing-name").map(({ name }) => name), - }; -} - -export async function waitForNpmExactVersion({ - packageName, - version, - expectedIntegrity, - registry = process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, - deadlineEpochSeconds, - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = () => Date.now(), - attempts = VISIBILITY_ATTEMPTS, - delayMilliseconds = VISIBILITY_DELAY_MS, -}) { - if (!Number.isSafeInteger(attempts) || attempts < 1) throw error("npm visibility attempts must be positive"); - for (let attempt = 0; attempt < attempts; attempt += 1) { - const state = await inspectNpmExactVersion({ - packageName, - version, - expectedIntegrity, - registry, - deadlineEpochSeconds, - fetchImpl, - sleepImpl, - nowImpl, - }); - if (state.published) return state; - if (attempt + 1 < attempts) { - await boundedSleep(delayMilliseconds, { - deadlineEpochSeconds, - nowImpl, - sleepImpl, - context: `npm visibility wait for ${packageName}@${version}`, - }); - } - } - throw error(`${packageName}@${version} did not become visible with frozen SRI before the bounded visibility attempts ended`); -} - -function publishTimedOut(result) { - return result?.error?.code === "ETIMEDOUT"; -} - -export async function publishFrozenNpmPackage({ - packageName, - version, - tarball, - cwd = process.cwd(), - registry = process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, - deadlineEpochSeconds, - fetchImpl = fetch, - spawnImpl = undefined, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - nowImpl = () => Date.now(), - visibilityAttempts = VISIBILITY_ATTEMPTS, - visibilityDelayMilliseconds = VISIBILITY_DELAY_MS, - identityCreationOnly = false, -}) { - const name = requiredText(packageName, "npm package name"); - const exactVersion = requiredText(version, "npm package version"); - const file = requiredText(tarball, "frozen npm tarball"); - const canonicalRegistry = canonicalNpmRegistry(registry); - const expectedIntegrity = frozenNpmIntegrity(file); - const existing = await inspectNpmExactVersion({ - packageName: name, - version: exactVersion, - expectedIntegrity, - registry: canonicalRegistry, - deadlineEpochSeconds, - fetchImpl, - sleepImpl, - nowImpl, - }); - if (existing.published) { - return { - state: existing, - skipped: true, - reconciledMutationFailure: false, - reconciledTimeout: false, - }; - } - if (identityCreationOnly && existing.nameExists) { - throw error( - `identity bootstrap cannot publish ${name}@${exactVersion}: package name ${name} already exists while the locked exact version is absent`, - ); - } - - const available = requirePreMutationRegistryWindow({ - deadlineEpochSeconds, - nowEpochMilliseconds: nowImpl(), - minimumMilliseconds: MINIMUM_PUBLISH_ATTEMPT_MS, - reserveMilliseconds: DEADLINE_RESERVE_MS, - context: `npm publish for ${name}@${exactVersion}`, - }); - const timeout = Math.min(PUBLISH_TIMEOUT_MS, available); - const publishArgs = ["publish", file, "--access", "public", "--provenance", "--registry", canonicalRegistry]; - const publishOptions = { cwd, env: process.env, stdio: "inherit", timeout }; - const result = spawnImpl === undefined - ? spawnSync("npm", publishArgs, { cwd, env: process.env, stdio: "inherit", timeout }) - : spawnImpl("npm", publishArgs, publishOptions); - - if (result?.error !== undefined || result?.status !== 0) { - const timedOut = publishTimedOut(result); - const detail = result?.error?.message ?? `npm exited with status ${String(result?.status)}`; - try { - const state = await waitForNpmExactVersion({ - packageName: name, - version: exactVersion, - expectedIntegrity, - registry: canonicalRegistry, - deadlineEpochSeconds, - fetchImpl, - sleepImpl, - nowImpl, - attempts: visibilityAttempts, - delayMilliseconds: visibilityDelayMilliseconds, - }); - return { - state, - skipped: false, - reconciledMutationFailure: true, - reconciledTimeout: timedOut, - }; - } catch (cause) { - throw error( - `npm publish for ${name}@${exactVersion} ${timedOut ? "timed out" : `failed (${detail})`} ` - + `and immutable registry state did not reconcile: ${cause.message}`, - ); - } - } - - const state = await waitForNpmExactVersion({ - packageName: name, - version: exactVersion, - expectedIntegrity, - registry: canonicalRegistry, - deadlineEpochSeconds, - fetchImpl, - sleepImpl, - nowImpl, - attempts: visibilityAttempts, - delayMilliseconds: visibilityDelayMilliseconds, - }); - return { - state, - skipped: false, - reconciledMutationFailure: false, - reconciledTimeout: false, - }; -} diff --git a/tools/release/frozen-npm-publish.mts b/tools/release/frozen-npm-publish.mts new file mode 100644 index 000000000..302fbc6da --- /dev/null +++ b/tools/release/frozen-npm-publish.mts @@ -0,0 +1,499 @@ +import { createHash } from 'node:crypto'; +import { readFileSync, statSync } from 'node:fs'; +import process from 'node:process'; + +import { registryRetryDelaySeconds, registryStatusRetryable } from './registry-http-retry.mts'; +import { requirePreMutationRegistryWindow } from './registry-publication-deferral.mts'; + +const DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org'; +const USER_AGENT = 'oliphaunt-frozen-npm-publisher/1; https://github.com/f0rr0/oliphaunt'; +const REQUEST_ATTEMPTS = 5; +const REQUEST_TIMEOUT_MS = 30_000; +const PUBLISH_TIMEOUT_MS = 2 * 60_000; +const MINIMUM_PUBLISH_ATTEMPT_MS = 30_000; +const DEADLINE_RESERVE_MS = 5_000; +const MAX_METADATA_RESPONSE_BYTES = 8 * 1024 * 1024; +const MAX_READ_RETRY_DELAY_SECONDS = 30; +const VISIBILITY_ATTEMPTS = 12; +const VISIBILITY_DELAY_MS = 10_000; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function error(message) { + return new Error(`frozen-npm-publish: ${message}`); +} + +function requiredText(value, context) { + if (typeof value !== 'string' || value.trim().length === 0) { + throw error(`${context} is required`); + } + return value.trim(); +} + +function deadlineMilliseconds(deadlineEpochSeconds) { + if (!Number.isSafeInteger(deadlineEpochSeconds) || deadlineEpochSeconds < 1) { + throw error('registry mutation deadline must be a positive Unix timestamp'); + } + return deadlineEpochSeconds * 1000; +} + +function remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }) { + const remaining = deadlineMilliseconds(deadlineEpochSeconds) - nowImpl() - DEADLINE_RESERVE_MS; + if (remaining <= 0) { + throw error( + `${context} refused because the shared registry mutation deadline has been reached`, + ); + } + return remaining; +} + +function requestTimeout({ deadlineEpochSeconds, nowImpl, context }) { + return Math.max( + 1, + Math.min( + REQUEST_TIMEOUT_MS, + remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }), + ), + ); +} + +async function closeResponse(response) { + try { + await response.body?.cancel?.(); + } catch { + // The exact-version existence response has no useful body on 404. + } +} + +async function boundedJson(response, context) { + const declared = response.headers?.get?.('content-length'); + if (declared !== null && declared !== undefined) { + const length = Number(declared); + if (!Number.isSafeInteger(length) || length < 0) { + await closeResponse(response); + throw error(`${context} returned an invalid Content-Length`); + } + if (length > MAX_METADATA_RESPONSE_BYTES) { + await closeResponse(response); + throw error(`${context} response exceeds ${MAX_METADATA_RESPONSE_BYTES} bytes`); + } + } + let bytes; + const reader = response.body?.getReader?.(); + if (reader === undefined) { + bytes = Buffer.from(await response.arrayBuffer()); + if (bytes.length > MAX_METADATA_RESPONSE_BYTES) { + throw error(`${context} response exceeds ${MAX_METADATA_RESPONSE_BYTES} bytes`); + } + } else { + const chunks = []; + let size = 0; + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > MAX_METADATA_RESPONSE_BYTES) { + await reader.cancel().catch(() => {}); + throw error(`${context} response exceeds ${MAX_METADATA_RESPONSE_BYTES} bytes`); + } + chunks.push(Buffer.from(value)); + } + } finally { + reader.releaseLock(); + } + bytes = Buffer.concat(chunks, size); + } + try { + return JSON.parse(bytes.toString('utf8')); + } catch (cause) { + throw error(`${context} returned invalid JSON: ${cause.message}`); + } +} + +async function boundedSleep(milliseconds, { deadlineEpochSeconds, nowImpl, sleepImpl, context }) { + if (!Number.isFinite(milliseconds) || milliseconds < 0) { + throw error(`${context} requested an invalid retry delay`); + } + const remaining = remainingBeforeReserve({ deadlineEpochSeconds, nowImpl, context }); + if (milliseconds >= remaining) { + throw error( + `${context} cannot wait ${Math.ceil(milliseconds / 1000)}s before the shared registry mutation deadline`, + ); + } + await sleepImpl(milliseconds); +} + +function npmVersionUrl(registry, packageName, version) { + return `${registry.replace(/\/+$/u, '')}/${encodeURIComponent(packageName)}/${encodeURIComponent(version)}`; +} + +function npmPackageUrl(registry, packageName) { + return `${registry.replace(/\/+$/u, '')}/${encodeURIComponent(packageName)}`; +} + +function canonicalNpmRegistry(value) { + const raw = requiredText(value, 'npm registry'); + let parsed; + try { + parsed = new URL(raw); + } catch { + throw error(`npm registry must be ${DEFAULT_NPM_REGISTRY}`); + } + const normalizedPath = parsed.pathname.replace(/\/+$/u, '') || '/'; + if ( + parsed.protocol !== 'https:' || + parsed.hostname !== 'registry.npmjs.org' || + (parsed.port !== '' && parsed.port !== '443') || + normalizedPath !== '/' || + parsed.username !== '' || + parsed.password !== '' || + parsed.search !== '' || + parsed.hash !== '' + ) { + throw error(`npm registry must be the canonical public registry ${DEFAULT_NPM_REGISTRY}`); + } + return DEFAULT_NPM_REGISTRY; +} + +async function inspectNpmJsonResource({ + url, + context, + consumeJson, + deadlineEpochSeconds, + fetchImpl, + sleepImpl, + nowImpl, +}) { + let lastFailure = null; + for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { + const controller = new AbortController(); + const timeoutMs = requestTimeout({ deadlineEpochSeconds, nowImpl, context }); + const timeout = setTimeout( + () => controller.abort(new Error(`${context} timed out`)), + timeoutMs, + ); + try { + const response = await fetchImpl(url, { + headers: { + Accept: 'application/json', + 'User-Agent': USER_AGENT, + }, + redirect: 'error', + signal: controller.signal, + }); + if (response.status === 404) { + await closeResponse(response); + return { found: false, metadata: null }; + } + if (response.status !== 200) { + const status = response.status; + const headers = response.headers; + await closeResponse(response); + lastFailure = `HTTP ${status}`; + if (!registryStatusRetryable(status) || attempt + 1 >= REQUEST_ATTEMPTS) break; + const delaySeconds = registryRetryDelaySeconds({ headers, attempt, now: nowImpl() }); + if (delaySeconds > MAX_READ_RETRY_DELAY_SECONDS) { + throw error(`${context} was rate limited for too long; retry the release later`); + } + await boundedSleep(Math.ceil(delaySeconds * 1000), { + deadlineEpochSeconds, + nowImpl, + sleepImpl, + context, + }); + continue; + } + if (!consumeJson) { + await closeResponse(response); + return { found: true, metadata: null }; + } + return { + found: true, + metadata: await boundedJson(response, `${context} metadata`), + }; + } catch (cause) { + if (cause instanceof Error && cause.message.startsWith('frozen-npm-publish:')) throw cause; + lastFailure = cause instanceof Error ? cause.message : String(cause); + if (attempt + 1 >= REQUEST_ATTEMPTS) break; + const delaySeconds = registryRetryDelaySeconds({ attempt, now: nowImpl() }); + await boundedSleep(Math.ceil(delaySeconds * 1000), { + deadlineEpochSeconds, + nowImpl, + sleepImpl, + context, + }); + } finally { + clearTimeout(timeout); + } + } + throw error(`cannot classify ${context}: ${lastFailure ?? 'unknown registry response'}`); +} + +export async function inspectNpmPackageName({ + packageName, + registry = process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, + deadlineEpochSeconds, + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + nowImpl = () => Date.now(), +}) { + const name = requiredText(packageName, 'npm package name'); + const canonicalRegistry = canonicalNpmRegistry(registry); + const url = npmPackageUrl(canonicalRegistry, name); + const state = await inspectNpmJsonResource({ + url, + context: `npm package-name check for ${name}`, + consumeJson: false, + deadlineEpochSeconds, + fetchImpl, + sleepImpl, + nowImpl, + }); + return { packageName: name, exists: state.found, url }; +} + +export function frozenNpmIntegrity(tarball) { + const file = requiredText(tarball, 'frozen npm tarball'); + let stat; + try { + stat = statSync(file); + } catch { + throw error(`frozen npm tarball is unavailable: ${file}`); + } + if (!stat.isFile()) { + throw error(`frozen npm tarball is not a file: ${file}`); + } + const digest = createHash('sha512').update(readFileSync(file)).digest('base64'); + return `sha512-${digest}`; +} + +export async function inspectNpmExactVersion({ + packageName, + version, + expectedIntegrity = undefined, + registry = process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, + deadlineEpochSeconds, + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + nowImpl = () => Date.now(), +}) { + const name = requiredText(packageName, 'npm package name'); + const exactVersion = requiredText(version, 'npm package version'); + const canonicalRegistry = canonicalNpmRegistry(registry); + const url = npmVersionUrl(canonicalRegistry, name, exactVersion); + const exact = await inspectNpmJsonResource({ + url, + context: `npm exact-version check for ${name}@${exactVersion}`, + consumeJson: true, + deadlineEpochSeconds, + fetchImpl, + sleepImpl, + nowImpl, + }); + if (!exact.found) { + // A version-level 404 is ambiguous: bootstrap is allowed to create only a + // completely absent package name, never a later version of an existing + // package. Resolve the package-name state with a normal JSON registry GET. + const packageState = await inspectNpmPackageName({ + packageName: name, + registry: canonicalRegistry, + deadlineEpochSeconds, + fetchImpl, + sleepImpl, + nowImpl, + }); + return { + packageName: name, + version: exactVersion, + published: false, + nameExists: packageState.exists, + state: packageState.exists ? 'pending-version' : 'missing-name', + integrity: null, + url, + packageUrl: packageState.url, + }; + } + const integrity = exact.metadata?.dist?.integrity; + if (typeof integrity !== 'string' || integrity.trim().length === 0) { + throw error(`npm metadata for ${name}@${exactVersion} lacks dist.integrity`); + } + const tokens = integrity.trim().split(/\s+/u); + if (expectedIntegrity !== undefined && !tokens.includes(expectedIntegrity)) { + throw error( + `immutable npm version ${name}@${exactVersion} conflicts with the frozen tarball: expected ${expectedIntegrity}, registry=${integrity}`, + ); + } + return { + packageName: name, + version: exactVersion, + published: true, + nameExists: true, + state: 'published', + integrity, + url, + packageUrl: npmPackageUrl(canonicalRegistry, name), + }; +} + +function selectedNpmIdentities(plan) { + if (!Array.isArray(plan)) throw error('bootstrap publication plan must be a list'); + const identities = plan + .filter(({ ecosystem }) => ecosystem === 'npm') + .map(({ name, version }, index) => ({ + name: requiredText(name, `npm plan entry ${index} name`), + version: requiredText(version, `npm plan entry ${index} version`), + })) + .sort((left, right) => + compareText(`${left.name}@${left.version}`, `${right.name}@${right.version}`), + ); + const unique = new Set(identities.map(({ name }) => name)); + if (unique.size !== identities.length) { + throw error('exact publication lock selects duplicate npm package names'); + } + return identities; +} + +export async function inspectNpmVersionState({ + plan, + registry = process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, + deadlineEpochSeconds, + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + nowImpl = () => Date.now(), + concurrency = 8, +}) { + if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) { + throw error('npm existence-check concurrency must be an integer from 1 through 32'); + } + const identities = selectedNpmIdentities(plan); + const observed = new Array(identities.length); + let cursor = 0; + const workers = Array.from({ length: Math.min(concurrency, identities.length) }, async () => { + for (;;) { + const index = cursor; + cursor += 1; + if (index >= identities.length) return; + const identity = identities[index]; + observed[index] = await inspectNpmExactVersion({ + packageName: identity.name, + version: identity.version, + registry, + deadlineEpochSeconds, + fetchImpl, + sleepImpl, + nowImpl, + }); + } + }); + await Promise.all(workers); + return { + selectedIdentities: identities, + publishedIdentities: identities.filter((_, index) => observed[index].published), + pendingVersions: identities.filter((_, index) => observed[index].state === 'pending-version'), + missingNames: identities + .filter((_, index) => observed[index].state === 'missing-name') + .map(({ name }) => name), + }; +} + +export async function waitForNpmExactVersion({ + packageName, + version, + expectedIntegrity, + registry = process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, + deadlineEpochSeconds, + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + nowImpl = () => Date.now(), + attempts = VISIBILITY_ATTEMPTS, + delayMilliseconds = VISIBILITY_DELAY_MS, +}) { + if (!Number.isSafeInteger(attempts) || attempts < 1) + throw error('npm visibility attempts must be positive'); + for (let attempt = 0; attempt < attempts; attempt += 1) { + const state = await inspectNpmExactVersion({ + packageName, + version, + expectedIntegrity, + registry, + deadlineEpochSeconds, + fetchImpl, + sleepImpl, + nowImpl, + }); + if (state.published) return state; + if (attempt + 1 < attempts) { + await boundedSleep(delayMilliseconds, { + deadlineEpochSeconds, + nowImpl, + sleepImpl, + context: `npm visibility wait for ${packageName}@${version}`, + }); + } + } + throw error( + `${packageName}@${version} did not become visible with frozen SRI before the bounded visibility attempts ended`, + ); +} + +export async function prepareFrozenNpmPublication({ + packageName, + version, + tarball, + deadlineEpochSeconds, + identityCreationOnly = false, + ...options +}) { + const registry = canonicalNpmRegistry( + options.registry ?? process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY, + ); + const expectedIntegrity = frozenNpmIntegrity(tarball); + const state = await inspectNpmExactVersion({ + packageName, + version, + expectedIntegrity, + registry, + deadlineEpochSeconds, + ...options, + }); + if (identityCreationOnly && !state.published && state.nameExists) + throw error( + 'identity bootstrap cannot publish ' + + packageName + + '@' + + version + + ': package name already exists while the locked exact version is absent', + ); + const timeout = state.published + ? 0 + : Math.min( + PUBLISH_TIMEOUT_MS, + requirePreMutationRegistryWindow({ + deadlineEpochSeconds, + nowEpochMilliseconds: (options.nowImpl ?? Date.now)(), + minimumMilliseconds: MINIMUM_PUBLISH_ATTEMPT_MS, + reserveMilliseconds: DEADLINE_RESERVE_MS, + context: 'npm publish for ' + packageName + '@' + version, + }), + ); + return { + packageName, + version, + tarball, + registry, + expectedIntegrity, + deadlineEpochSeconds, + skipped: state.published, + state, + timeout, + }; +} + +export async function reconcileFrozenNpmPublication(prepared, options = {}) { + if (frozenNpmIntegrity(prepared.tarball) !== prepared.expectedIntegrity) + throw error('npm tarball changed after publication admission'); + return await waitForNpmExactVersion({ ...prepared, ...options }); +} diff --git a/tools/release/frozen-npm-publish.test.mjs b/tools/release/frozen-npm-publish.test.mjs deleted file mode 100644 index face8e410..000000000 --- a/tools/release/frozen-npm-publish.test.mjs +++ /dev/null @@ -1,387 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { - frozenNpmIntegrity, - inspectNpmExactVersion, - inspectNpmVersionState, - publishFrozenNpmPackage, -} from "./frozen-npm-publish.mjs"; -import { isRegistryPublicationDeferredError } from "./registry-publication-deferral.mjs"; - -const temporaryDirectories = []; - -function tarball() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-frozen-npm-")); - temporaryDirectories.push(root); - const file = path.join(root, "fixture-1.2.3.tgz"); - writeFileSync(file, "immutable npm fixture\n"); - return file; -} - -function publishedResponse(integrity) { - return Response.json({ name: "@oliphaunt/fixture", version: "1.2.3", dist: { integrity } }); -} - -function timeoutResult() { - const cause = new Error("spawnSync npm ETIMEDOUT"); - cause.code = "ETIMEDOUT"; - return { error: cause, status: null, signal: "SIGTERM" }; -} - -afterEach(() => { - while (temporaryDirectories.length > 0) { - rmSync(temporaryDirectories.pop(), { recursive: true, force: true }); - } -}); - -describe("frozen npm registry publication", () => { - test("classifies exact versions and rejects immutable SRI conflicts", async () => { - const file = tarball(); - const expectedIntegrity = frozenNpmIntegrity(file); - const urls = []; - const state = await inspectNpmExactVersion({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - expectedIntegrity, - deadlineEpochSeconds: 2_000, - nowImpl: () => 1_000_000, - fetchImpl: async (url, options) => { - urls.push(url); - expect(options.headers.Accept).toBe("application/json"); - return publishedResponse(expectedIntegrity); - }, - }); - expect(state.published).toBe(true); - expect(urls).toEqual(["https://registry.npmjs.org/%40oliphaunt%2Ffixture/1.2.3"]); - - await expect(inspectNpmExactVersion({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - expectedIntegrity, - deadlineEpochSeconds: 2_000, - nowImpl: () => 1_000_000, - fetchImpl: async () => publishedResponse("sha512-conflicting"), - })).rejects.toThrow(/immutable npm version.*conflicts/u); - }); - - test("inventories npm exact versions so resumptions omit public carriers", async () => { - const calls = []; - const inventory = await inspectNpmVersionState({ - plan: [ - { ecosystem: "cargo", name: "not-npm", version: "1.0.0" }, - { ecosystem: "npm", name: "@oliphaunt/missing", version: "1.0.0" }, - { ecosystem: "npm", name: "@oliphaunt/pending", version: "1.0.0" }, - { ecosystem: "npm", name: "@oliphaunt/published", version: "1.0.0" }, - ], - deadlineEpochSeconds: 2_000, - nowImpl: () => 1_000_000, - concurrency: 1, - fetchImpl: async (url, options) => { - calls.push({ url, options }); - if (url.includes("published")) return publishedResponse("sha512-present"); - if (url === "https://registry.npmjs.org/%40oliphaunt%2Fpending") { - return Response.json({ name: "@oliphaunt/pending" }); - } - return new Response("", { status: 404 }); - }, - }); - - expect(inventory).toEqual({ - selectedIdentities: [ - { name: "@oliphaunt/missing", version: "1.0.0" }, - { name: "@oliphaunt/pending", version: "1.0.0" }, - { name: "@oliphaunt/published", version: "1.0.0" }, - ], - publishedIdentities: [{ name: "@oliphaunt/published", version: "1.0.0" }], - pendingVersions: [{ name: "@oliphaunt/pending", version: "1.0.0" }], - missingNames: ["@oliphaunt/missing"], - }); - expect(calls.every(({ options }) => options.headers.Accept === "application/json")).toBe(true); - expect(calls.map(({ url }) => url)).toContain("https://registry.npmjs.org/%40oliphaunt%2Fpending"); - }); - - test("identity bootstrap refuses an existing package name whose locked exact version is absent", async () => { - const file = tarball(); - let spawns = 0; - await expect(publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 2_000, - nowImpl: () => 1_000_000, - identityCreationOnly: true, - fetchImpl: async (url, options) => { - expect(options.headers.Accept).toBe("application/json"); - return url.endsWith("/1.2.3") - ? new Response("", { status: 404 }) - : Response.json({ name: "@oliphaunt/fixture" }); - }, - spawnImpl: () => { - spawns += 1; - return { status: 0 }; - }, - })).rejects.toThrow(/identity bootstrap cannot publish.*package name.*already exists/u); - expect(spawns).toBe(0); - }); - - test("skips an already-public lock-matching version without invoking npm", async () => { - const file = tarball(); - let spawns = 0; - const result = await publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 2_000, - nowImpl: () => 1_000_000, - fetchImpl: async () => publishedResponse(frozenNpmIntegrity(file)), - spawnImpl: () => { - spawns += 1; - return { status: 0 }; - }, - }); - - expect(result.skipped).toBe(true); - expect(spawns).toBe(0); - }); - - test("bounds npm publish and proves the resulting immutable version plus SRI", async () => { - const file = tarball(); - const expectedIntegrity = frozenNpmIntegrity(file); - let reads = 0; - const spawnCalls = []; - const result = await publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 1_100, - nowImpl: () => 1_000_000, - fetchImpl: async () => { - reads += 1; - return reads === 1 ? new Response("", { status: 404 }) : publishedResponse(expectedIntegrity); - }, - spawnImpl: (...args) => { - spawnCalls.push(args); - return { status: 0 }; - }, - }); - - expect(result).toMatchObject({ skipped: false, reconciledTimeout: false }); - expect(spawnCalls).toHaveLength(1); - expect(spawnCalls[0][0]).toBe("npm"); - expect(spawnCalls[0][1]).toEqual([ - "publish", - file, - "--access", - "public", - "--provenance", - "--registry", - "https://registry.npmjs.org", - ]); - expect(spawnCalls[0][2].timeout).toBe(95_000); - }); - - test("rejects noncanonical npm registries before any read or mutation", async () => { - const file = tarball(); - for (const registry of [ - "http://registry.npmjs.org", - "https://registry.example.invalid", - "https://registry.npmjs.org/custom", - "https://user:secret@registry.npmjs.org", - ]) { - let reads = 0; - let spawns = 0; - await expect(publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - registry, - deadlineEpochSeconds: 2_000, - nowImpl: () => 1_000_000, - fetchImpl: async () => { - reads += 1; - return new Response("", { status: 404 }); - }, - spawnImpl: () => { - spawns += 1; - return { status: 0 }; - }, - })).rejects.toThrow(/canonical public registry/u); - expect(reads).toBe(0); - expect(spawns).toBe(0); - } - }); - - test("reconciles an ambiguous npm timeout from exact registry SRI without retrying publish", async () => { - const file = tarball(); - const expectedIntegrity = frozenNpmIntegrity(file); - let reads = 0; - let spawns = 0; - const result = await publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 2_000, - nowImpl: () => 1_000_000, - fetchImpl: async () => { - reads += 1; - return reads === 1 ? new Response("", { status: 404 }) : publishedResponse(expectedIntegrity); - }, - spawnImpl: () => { - spawns += 1; - return timeoutResult(); - }, - }); - - expect(result.reconciledTimeout).toBe(true); - expect(result.reconciledMutationFailure).toBe(true); - expect(spawns).toBe(1); - }); - - test("reconciles a status-one mutation failure from exact SRI without replaying publish", async () => { - const file = tarball(); - const expectedIntegrity = frozenNpmIntegrity(file); - let reads = 0; - let spawns = 0; - const result = await publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 2_000, - nowImpl: () => 1_000_000, - fetchImpl: async () => { - reads += 1; - return reads === 1 ? new Response("", { status: 404 }) : publishedResponse(expectedIntegrity); - }, - spawnImpl: () => { - spawns += 1; - return { status: 1, signal: null }; - }, - }); - - expect(result).toMatchObject({ - reconciledMutationFailure: true, - reconciledTimeout: false, - skipped: false, - }); - expect(spawns).toBe(1); - }); - - test("surfaces a status-one failure when immutable registry state remains absent", async () => { - const file = tarball(); - let spawns = 0; - let now = 1_000_000; - await expect(publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 2_000, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - now += milliseconds; - }, - fetchImpl: async () => new Response("", { status: 404 }), - spawnImpl: () => { - spawns += 1; - return { status: 1, signal: null }; - }, - visibilityAttempts: 2, - visibilityDelayMilliseconds: 1_000, - })).rejects.toThrow(/failed \(npm exited with status 1\).*immutable registry state did not reconcile/u); - expect(spawns).toBe(1); - }); - - test("never blindly retries a timed-out mutation when the exact version remains absent", async () => { - const file = tarball(); - let spawns = 0; - let now = 1_000_000; - await expect(publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 2_000, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - now += milliseconds; - }, - fetchImpl: async () => new Response("", { status: 404 }), - spawnImpl: () => { - spawns += 1; - return timeoutResult(); - }, - visibilityAttempts: 2, - visibilityDelayMilliseconds: 1_000, - })).rejects.toThrow(/timed out and immutable registry state did not reconcile/u); - expect(spawns).toBe(1); - }); - - test("rejects a timed-out mutation that resolves to conflicting immutable SRI", async () => { - const file = tarball(); - let reads = 0; - let spawns = 0; - await expect(publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 2_000, - nowImpl: () => 1_000_000, - fetchImpl: async () => { - reads += 1; - return reads === 1 - ? new Response("", { status: 404 }) - : publishedResponse("sha512-conflicting"); - }, - spawnImpl: () => { - spawns += 1; - return timeoutResult(); - }, - })).rejects.toThrow(/timed out.*immutable npm version.*conflicts/u); - expect(spawns).toBe(1); - }); - - test("refuses mutation and visibility sleeps that cannot fit the absolute deadline", async () => { - const file = tarball(); - let spawns = 0; - let preMutationFailure; - try { - await publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 1_020, - nowImpl: () => 1_000_000, - fetchImpl: async () => new Response("", { status: 404 }), - spawnImpl: () => { - spawns += 1; - return { status: 0 }; - }, - }); - } catch (cause) { - preMutationFailure = cause; - } - expect(isRegistryPublicationDeferredError(preMutationFailure)).toBe(true); - expect(preMutationFailure.message).toMatch(/requires 30s.*15s remain/u); - expect(spawns).toBe(0); - - let postMutationFailure; - try { - await publishFrozenNpmPackage({ - packageName: "@oliphaunt/fixture", - version: "1.2.3", - tarball: file, - deadlineEpochSeconds: 1_040, - nowImpl: () => 1_000_000, - fetchImpl: async () => new Response("", { status: 404 }), - spawnImpl: () => ({ status: 0 }), - visibilityAttempts: 2, - visibilityDelayMilliseconds: 40_000, - }); - } catch (cause) { - postMutationFailure = cause; - } - expect(isRegistryPublicationDeferredError(postMutationFailure)).toBe(false); - expect(postMutationFailure.message).toMatch(/cannot wait 40s before the shared registry mutation deadline/u); - }); -}); diff --git a/tools/release/frozen-npm-publish.test.mts b/tools/release/frozen-npm-publish.test.mts new file mode 100644 index 000000000..a30050d56 --- /dev/null +++ b/tools/release/frozen-npm-publish.test.mts @@ -0,0 +1,218 @@ +import { afterEach, describe, expect, test } from 'bun:test'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { + frozenNpmIntegrity, + inspectNpmExactVersion, + inspectNpmVersionState, + prepareFrozenNpmPublication, + reconcileFrozenNpmPublication, +} from './frozen-npm-publish.mts'; +import { isRegistryPublicationDeferredError } from './registry-publication-deferral.mts'; + +const temporaryDirectories = []; + +function tarball() { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-frozen-npm-')); + temporaryDirectories.push(root); + const file = path.join(root, 'fixture-1.2.3.tgz'); + writeFileSync(file, 'immutable npm fixture\n'); + return file; +} + +function publishedResponse(integrity) { + return Response.json({ name: '@oliphaunt/fixture', version: '1.2.3', dist: { integrity } }); +} + +afterEach(() => { + while (temporaryDirectories.length > 0) { + rmSync(temporaryDirectories.pop(), { recursive: true, force: true }); + } +}); + +describe('frozen npm registry publication', () => { + test('classifies exact versions and rejects immutable SRI conflicts', async () => { + const file = tarball(); + const expectedIntegrity = frozenNpmIntegrity(file); + const urls = []; + const state = await inspectNpmExactVersion({ + packageName: '@oliphaunt/fixture', + version: '1.2.3', + expectedIntegrity, + deadlineEpochSeconds: 2_000, + nowImpl: () => 1_000_000, + fetchImpl: async (url, options) => { + urls.push(url); + expect(options.headers.Accept).toBe('application/json'); + return publishedResponse(expectedIntegrity); + }, + }); + expect(state.published).toBe(true); + expect(urls).toEqual(['https://registry.npmjs.org/%40oliphaunt%2Ffixture/1.2.3']); + + await expect( + inspectNpmExactVersion({ + packageName: '@oliphaunt/fixture', + version: '1.2.3', + expectedIntegrity, + deadlineEpochSeconds: 2_000, + nowImpl: () => 1_000_000, + fetchImpl: async () => publishedResponse('sha512-conflicting'), + }), + ).rejects.toThrow(/immutable npm version.*conflicts/u); + }); + + test('inventories npm exact versions so resumptions omit public carriers', async () => { + const calls = []; + const inventory = await inspectNpmVersionState({ + plan: [ + { ecosystem: 'cargo', name: 'not-npm', version: '1.0.0' }, + { ecosystem: 'npm', name: '@oliphaunt/missing', version: '1.0.0' }, + { ecosystem: 'npm', name: '@oliphaunt/pending', version: '1.0.0' }, + { ecosystem: 'npm', name: '@oliphaunt/published', version: '1.0.0' }, + ], + deadlineEpochSeconds: 2_000, + nowImpl: () => 1_000_000, + concurrency: 1, + fetchImpl: async (url, options) => { + calls.push({ url, options }); + if (url.includes('published')) return publishedResponse('sha512-present'); + if (url === 'https://registry.npmjs.org/%40oliphaunt%2Fpending') { + return Response.json({ name: '@oliphaunt/pending' }); + } + return new Response('', { status: 404 }); + }, + }); + + expect(inventory).toEqual({ + selectedIdentities: [ + { name: '@oliphaunt/missing', version: '1.0.0' }, + { name: '@oliphaunt/pending', version: '1.0.0' }, + { name: '@oliphaunt/published', version: '1.0.0' }, + ], + publishedIdentities: [{ name: '@oliphaunt/published', version: '1.0.0' }], + pendingVersions: [{ name: '@oliphaunt/pending', version: '1.0.0' }], + missingNames: ['@oliphaunt/missing'], + }); + expect(calls.every(({ options }) => options.headers.Accept === 'application/json')).toBe(true); + expect(calls.map(({ url }) => url)).toContain( + 'https://registry.npmjs.org/%40oliphaunt%2Fpending', + ); + }); + + test('native admission distinguishes existing names, exact versions, and bounded new publication', async () => { + const file = tarball(); + const options = { + packageName: '@oliphaunt/fixture', + version: '1.2.3', + tarball: file, + deadlineEpochSeconds: 2000, + nowImpl: () => 1_000_000, + }; + const existing = await prepareFrozenNpmPublication({ + ...options, + fetchImpl: async () => publishedResponse(frozenNpmIntegrity(file)), + }); + expect(existing.skipped).toBe(true); + expect(existing.timeout).toBe(0); + await expect( + prepareFrozenNpmPublication({ + ...options, + identityCreationOnly: true, + fetchImpl: async (url) => + url.endsWith('/1.2.3') + ? new Response('', { status: 404 }) + : Response.json({ name: options.packageName }), + }), + ).rejects.toThrow('package name already exists'); + const admitted = await prepareFrozenNpmPublication({ + ...options, + identityCreationOnly: true, + fetchImpl: async () => new Response('', { status: 404 }), + }); + expect(admitted.skipped).toBe(false); + expect(admitted.timeout).toBe(120000); + expect(admitted.expectedIntegrity).toBe(frozenNpmIntegrity(file)); + }); + + test('native post-upload reconciliation requires exact frozen SRI and never hides changed local bytes', async () => { + const file = tarball(); + const options = { + packageName: '@oliphaunt/fixture', + version: '1.2.3', + tarball: file, + deadlineEpochSeconds: 2000, + nowImpl: () => 1_000_000, + }; + const prepared = await prepareFrozenNpmPublication({ + ...options, + fetchImpl: async () => new Response('', { status: 404 }), + }); + expect( + ( + await reconcileFrozenNpmPublication(prepared, { + nowImpl: options.nowImpl, + fetchImpl: async () => publishedResponse(prepared.expectedIntegrity), + }) + ).published, + ).toBe(true); + await expect( + reconcileFrozenNpmPublication(prepared, { + nowImpl: options.nowImpl, + fetchImpl: async () => publishedResponse('sha512-wrong'), + }), + ).rejects.toThrow('conflicts'); + await expect( + reconcileFrozenNpmPublication(prepared, { + nowImpl: options.nowImpl, + fetchImpl: async () => new Response('', { status: 404 }), + attempts: 2, + delayMilliseconds: 0, + sleepImpl: async () => {}, + }), + ).rejects.toThrow('did not become visible'); + writeFileSync(file, 'different bytes'); + await expect( + reconcileFrozenNpmPublication(prepared, { + fetchImpl: () => { + throw new Error('unexpected read'); + }, + }), + ).rejects.toThrow('changed after publication admission'); + }); + + test('native admission rejects unsafe registries and defers before insufficient mutation time', async () => { + const options = { + packageName: '@oliphaunt/fixture', + version: '1.2.3', + tarball: tarball(), + deadlineEpochSeconds: 1030, + nowImpl: () => 1_000_000, + }; + for (const registry of [ + 'http://registry.npmjs.org', + 'https://example.invalid', + 'https://registry.npmjs.org/path', + ]) + await expect( + prepareFrozenNpmPublication({ + ...options, + registry, + fetchImpl: () => { + throw new Error('unexpected registry read'); + }, + }), + ).rejects.toThrow('canonical public registry'); + try { + await prepareFrozenNpmPublication({ + ...options, + fetchImpl: async () => new Response('', { status: 404 }), + }); + throw new Error('unexpected admission'); + } catch (cause) { + expect(isRegistryPublicationDeferredError(cause)).toBe(true); + } + }); +}); diff --git a/tools/release/git-tag-state.mts b/tools/release/git-tag-state.mts new file mode 100644 index 000000000..e3ead5b87 --- /dev/null +++ b/tools/release/git-tag-state.mts @@ -0,0 +1,21 @@ +export function parseTagRefs(text) { + const refs = new Map(); + for (const line of text.split(/\r?\n/u).filter(Boolean)) { + const match = /^([0-9a-f]{40}) (refs\/tags\/[^\s]+)$/u.exec(line); + if (!match || refs.has(match[2])) throw new Error('invalid or repeated Git tag reference'); + refs.set(match[2], match[1]); + } + return refs; +} + +export function parseTagCommits(text) { + const commits = new Map(); + for (const line of text.split(/\r?\n/u).filter(Boolean)) { + const [commit, ...parents] = line.trim().split(' '); + if ([commit, ...parents].some((sha) => !/^[0-9a-f]{40}$/u.test(sha)) || commits.has(commit)) { + throw new Error('invalid or repeated Git tag commit'); + } + commits.set(commit, parents); + } + return commits; +} diff --git a/tools/release/github-content-write-pacer.mjs b/tools/release/github-content-write-pacer.mjs deleted file mode 100644 index cd0455e9c..000000000 --- a/tools/release/github-content-write-pacer.mjs +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env node - -import { - closeSync, - existsSync, - lstatSync, - mkdirSync, - openSync, - readFileSync, - renameSync, - rmSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import process from "node:process"; -import { fileURLToPath } from "node:url"; -import { githubReleaseLineageIdentity } from "./github-release-lineage.mjs"; - -export const GITHUB_CONTENT_WRITE_INTERVAL_MS = 10_000; -export const GITHUB_CONTENT_WRITES_PER_ROLLING_HOUR = - Math.floor((60 * 60_000) / GITHUB_CONTENT_WRITE_INTERVAL_MS) + 1; -export const GITHUB_CONTENT_WRITES_PER_ROLLING_MINUTE = - Math.floor(60_000 / GITHUB_CONTENT_WRITE_INTERVAL_MS) + 1; - -const SCHEMA = "oliphaunt-github-content-write-pacer-v4"; -const POSITIVE_INTEGER = /^[1-9][0-9]*$/u; -const MAX_LOCK_WAIT_MS = 60_000; -const TEST_TIMING_ENV = "OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE"; - -export class GitHubContentWritePacerError extends Error { - constructor(message, options = {}) { - super(`github-content-write-pacer: ${message}`, options); - this.name = "GitHubContentWritePacerError"; - } -} - -function fail(message, options = {}) { - throw new GitHubContentWritePacerError(message, options); -} - -function sleepSync(milliseconds) { - if (milliseconds <= 0) return; - const cell = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)); - Atomics.wait(cell, 0, 0, milliseconds); -} - -function pacerPath(environment) { - const configured = environment.OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH?.trim() ?? ""; - if (configured === "") { - if (environment.GITHUB_ACTIONS === "true") { - fail("OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH is required in GitHub Actions"); - } - return null; - } - if (configured.includes("\0")) fail("pacer path contains a NUL byte"); - return path.resolve(configured); -} - -function assertRegularFile(file, label) { - const stat = lstatSync(file, { throwIfNoEntry: false }); - if (stat !== undefined && (!stat.isFile() || stat.isSymbolicLink())) { - fail(`${label} must be an absent or regular non-symbolic-link file`); - } -} - -function parseState(file, expectedIdentity, timing) { - if (!existsSync(file)) return null; - assertRegularFile(file, "pacer state"); - let state; - try { - state = JSON.parse(readFileSync(file, "utf8")); - } catch (cause) { - fail("pacer state is not valid JSON", { cause }); - } - if ( - state === null - || Array.isArray(state) - || typeof state !== "object" - || state.schema !== SCHEMA - || state.intervalMs !== timing.intervalMs - || !Number.isSafeInteger(state.sequence) - || state.sequence < 1 - || !Number.isSafeInteger(state.lastReservedAtMs) - || state.lastReservedAtMs < 0 - || typeof state.lastLabel !== "string" - || state.lastLabel.length === 0 - || /[\u0000-\u001f\u007f]/u.test(state.lastLabel) - || !Array.isArray(state.reservations) - || state.reservations.length !== state.sequence - ) { - fail("pacer state has a malformed envelope"); - } - for (const field of ["headSha", "repository", "runId"]) { - if (state[field] !== expectedIdentity[field]) { - fail(`pacer state ${field} does not match the current release lineage`); - } - } - let previousReservedAtMs = null; - for (const [index, reservation] of state.reservations.entries()) { - if ( - reservation === null - || Array.isArray(reservation) - || typeof reservation !== "object" - || reservation.sequence !== index + 1 - || !Number.isSafeInteger(reservation.reservedAtMs) - || reservation.reservedAtMs < 0 - || typeof reservation.label !== "string" - || reservation.label.length === 0 - || reservation.label.length > 200 - || /[\u0000-\u001f\u007f]/u.test(reservation.label) - || (previousReservedAtMs !== null - && reservation.reservedAtMs < previousReservedAtMs + timing.intervalMs) - ) { - fail("pacer state contains a malformed or insufficiently paced reservation journal"); - } - previousReservedAtMs = reservation.reservedAtMs; - } - const last = state.reservations.at(-1); - if (last.reservedAtMs !== state.lastReservedAtMs || last.label !== state.lastLabel) { - fail("pacer state summary does not match its complete reservation journal"); - } - return state; -} - -function writeState(file, state) { - const directory = path.dirname(file); - mkdirSync(directory, { recursive: true }); - assertRegularFile(file, "pacer state"); - const temporary = `${file}.tmp-${process.pid}-${state.sequence}`; - assertRegularFile(temporary, "temporary pacer state"); - try { - writeFileSync(temporary, `${JSON.stringify(state)}\n`, { flag: "wx", mode: 0o600 }); - renameSync(temporary, file); - } finally { - rmSync(temporary, { force: true }); - } -} - -function acquireLock(file, { maxLockWaitMs, now, sleep }) { - const lock = `${file}.lock`; - const startedAt = now(); - while (true) { - let descriptor; - try { - descriptor = openSync(lock, "wx", 0o600); - writeFileSync(descriptor, `${process.pid}\n`); - closeSync(descriptor); - return lock; - } catch (cause) { - if (descriptor !== undefined) closeSync(descriptor); - if (cause?.code !== "EEXIST") rmSync(lock, { force: true }); - if (cause?.code !== "EEXIST") fail("could not acquire the pacer lock", { cause }); - if (now() - startedAt >= maxLockWaitMs) fail("timed out waiting for the pacer lock"); - sleep(100); - } - } -} - -function hardDeadlineMs(environment) { - const value = environment.REGISTRY_JOB_HARD_DEADLINE_EPOCH; - if (value === undefined || value === "") return null; - if (!POSITIVE_INTEGER.test(value)) fail("REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp"); - const result = Number(value) * 1_000; - if (!Number.isSafeInteger(result)) fail("REGISTRY_JOB_HARD_DEADLINE_EPOCH is outside the safe timestamp range"); - return result; -} - -function timingOptions(environment, timing) { - if (timing === undefined) { - return { - intervalMs: GITHUB_CONTENT_WRITE_INTERVAL_MS, - maxLockWaitMs: MAX_LOCK_WAIT_MS, - }; - } - if (environment.GITHUB_ACTIONS === "true" || environment[TEST_TIMING_ENV] !== "true") { - fail(`custom timing is test-only and requires ${TEST_TIMING_ENV}=true outside GitHub Actions`); - } - if (timing === null || Array.isArray(timing) || typeof timing !== "object") { - fail("custom timing must be an object"); - } - const result = { - intervalMs: timing.intervalMs, - maxLockWaitMs: timing.maxLockWaitMs, - }; - for (const [label, value] of Object.entries({ - "interval timing": result.intervalMs, - "lock-wait timing": result.maxLockWaitMs, - })) { - if (!Number.isSafeInteger(value) || value < 1) fail(`custom ${label} must be a positive safe integer`); - } - return result; -} - -export function reserveGitHubContentWriteSync({ - environment = process.env, - label, - now = Date.now, - sleep = sleepSync, - timing = undefined, -} = {}) { - if ( - typeof label !== "string" - || label.length === 0 - || label.length > 200 - || /[\u0000-\u001f\u007f]/u.test(label) - ) { - fail("reservation label must be a non-empty printable string of at most 200 characters"); - } - const file = pacerPath(environment); - if (file === null) return { enabled: false, sequence: 0, waitedMs: 0 }; - const resolvedTiming = timingOptions(environment, timing); - const expectedIdentity = githubReleaseLineageIdentity(environment); - mkdirSync(path.dirname(file), { recursive: true }); - const lock = acquireLock(file, { maxLockWaitMs: resolvedTiming.maxLockWaitMs, now, sleep }); - let reservedAt; - let sequence; - let waitMs; - try { - const previous = parseState(file, expectedIdentity, resolvedTiming); - const observedAt = now(); - if (!Number.isSafeInteger(observedAt) || observedAt < 0) fail("clock returned an invalid timestamp"); - // Allocate and persist the next globally ordered slot while holding the - // lock briefly, then wait outside it. A crashed waiter burns its slot - // conservatively. - const earliest = previous === null - ? observedAt - : previous.lastReservedAtMs + resolvedTiming.intervalMs; - reservedAt = Math.max(observedAt, earliest); - waitMs = reservedAt - observedAt; - const deadline = hardDeadlineMs(environment); - if (deadline !== null && reservedAt >= deadline) { - fail("the next content-write reservation would reach the hard release deadline"); - } - sequence = (previous?.sequence ?? 0) + 1; - const reservation = { label, reservedAtMs: reservedAt, sequence }; - const state = { - schema: SCHEMA, - ...expectedIdentity, - intervalMs: resolvedTiming.intervalMs, - sequence, - lastReservedAtMs: reservedAt, - lastLabel: label, - reservations: [...(previous?.reservations ?? []), reservation], - }; - writeState(file, state); - } finally { - rmSync(lock, { force: true }); - } - - sleep(waitMs); - const observedAfterWait = now(); - if (!Number.isSafeInteger(observedAfterWait) || observedAfterWait < reservedAt) { - fail("clock did not advance through the required content-write pacing interval"); - } - const deadline = hardDeadlineMs(environment); - if (deadline !== null && observedAfterWait >= deadline) { - fail("the content-write reservation reached the hard release deadline while waiting"); - } - return { enabled: true, sequence, waitedMs: waitMs }; -} - -function main(argv) { - if (argv[0] !== "reserve" || argv.length !== 3 || argv[1] !== "--label") { - fail("usage: github-content-write-pacer.mjs reserve --label LABEL"); - } - const result = reserveGitHubContentWriteSync({ label: argv[2] }); - if (!result.enabled) fail("the content-write pacer is not enabled"); - console.log(`reserved GitHub content write ${result.sequence} after ${result.waitedMs}ms`); -} - -if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { - try { - main(process.argv.slice(2)); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/github-content-write-pacer.mts b/tools/release/github-content-write-pacer.mts new file mode 100644 index 000000000..77c3e0825 --- /dev/null +++ b/tools/release/github-content-write-pacer.mts @@ -0,0 +1,253 @@ +#!/usr/bin/env bun + +import { + closeSync, + existsSync, + lstatSync, + mkdirSync, + openSync, + readFileSync, + renameSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { setTimeout as wait } from 'node:timers/promises'; +import { fileURLToPath } from 'node:url'; +import { githubReleaseLineageIdentity } from './github-release-lineage.mts'; + +export const GITHUB_CONTENT_WRITE_INTERVAL_MS = 10_000; +export const GITHUB_CONTENT_WRITES_PER_ROLLING_HOUR = + Math.floor((60 * 60_000) / GITHUB_CONTENT_WRITE_INTERVAL_MS) + 1; +export const GITHUB_CONTENT_WRITES_PER_ROLLING_MINUTE = + Math.floor(60_000 / GITHUB_CONTENT_WRITE_INTERVAL_MS) + 1; + +const SCHEMA = 'oliphaunt-github-content-write-pacer-v5'; +const POSITIVE_INTEGER = /^[1-9][0-9]*$/u; +const MAX_LOCK_WAIT_MS = 60_000; +const TEST_TIMING_ENV = 'OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE'; + +export class GitHubContentWritePacerError extends Error { + constructor(message, options = {}) { + super(`github-content-write-pacer: ${message}`, options); + this.name = 'GitHubContentWritePacerError'; + } +} + +function fail(message, options = {}) { + throw new GitHubContentWritePacerError(message, options); +} + +function pacerPath(environment) { + const configured = environment.OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH?.trim() ?? ''; + if (configured === '') { + if (environment.GITHUB_ACTIONS === 'true') { + fail('OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH is required in GitHub Actions'); + } + return null; + } + if (configured.includes('\0')) fail('pacer path contains a NUL byte'); + return path.resolve(configured); +} + +function assertRegularFile(file, label) { + const stat = lstatSync(file, { throwIfNoEntry: false }); + if (stat !== undefined && (!stat.isFile() || stat.isSymbolicLink())) { + fail(`${label} must be an absent or regular non-symbolic-link file`); + } +} + +function parseState(file, expectedIdentity, timing) { + if (!existsSync(file)) return null; + assertRegularFile(file, 'pacer state'); + let state; + try { + state = JSON.parse(readFileSync(file, 'utf8')); + } catch (cause) { + fail('pacer state is not valid JSON', { cause }); + } + if ( + state === null || + Array.isArray(state) || + typeof state !== 'object' || + Object.keys(state).sort().join(',') !== + 'headSha,intervalMs,lastLabel,lastReservedAtMs,repository,runId,schema,sequence' || + state.schema !== SCHEMA || + state.intervalMs !== timing.intervalMs || + !Number.isSafeInteger(state.sequence) || + state.sequence < 1 || + !Number.isSafeInteger(state.lastReservedAtMs) || + state.lastReservedAtMs < 0 || + typeof state.lastLabel !== 'string' || + state.lastLabel.length === 0 || + state.lastLabel.length > 200 || + /[\u0000-\u001f\u007f]/u.test(state.lastLabel) + ) { + fail('pacer state has a malformed envelope'); + } + for (const field of ['headSha', 'repository', 'runId']) { + if (state[field] !== expectedIdentity[field]) { + fail(`pacer state ${field} does not match the current release lineage`); + } + } + return state; +} + +function writeState(file, state) { + const directory = path.dirname(file); + mkdirSync(directory, { recursive: true }); + assertRegularFile(file, 'pacer state'); + const temporary = `${file}.tmp-${process.pid}-${state.sequence}`; + assertRegularFile(temporary, 'temporary pacer state'); + try { + writeFileSync(temporary, `${JSON.stringify(state)}\n`, { flag: 'wx', mode: 0o600 }); + renameSync(temporary, file); + } finally { + rmSync(temporary, { force: true }); + } +} + +async function acquireLock(file, { maxLockWaitMs, now, sleep }) { + const lock = `${file}.lock`; + const startedAt = now(); + while (true) { + let descriptor; + try { + descriptor = openSync(lock, 'wx', 0o600); + writeFileSync(descriptor, `${process.pid}\n`); + closeSync(descriptor); + return lock; + } catch (cause) { + if (descriptor !== undefined) closeSync(descriptor); + if (cause?.code !== 'EEXIST') rmSync(lock, { force: true }); + if (cause?.code !== 'EEXIST') fail('could not acquire the pacer lock', { cause }); + if (now() - startedAt >= maxLockWaitMs) fail('timed out waiting for the pacer lock'); + await sleep(100); + } + } +} + +function hardDeadlineMs(environment) { + const value = environment.REGISTRY_JOB_HARD_DEADLINE_EPOCH; + if (value === undefined || value === '') return null; + if (!POSITIVE_INTEGER.test(value)) + fail('REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp'); + const result = Number(value) * 1_000; + if (!Number.isSafeInteger(result)) + fail('REGISTRY_JOB_HARD_DEADLINE_EPOCH is outside the safe timestamp range'); + return result; +} + +function timingOptions(environment, timing) { + if (timing === undefined) { + return { + intervalMs: GITHUB_CONTENT_WRITE_INTERVAL_MS, + maxLockWaitMs: MAX_LOCK_WAIT_MS, + }; + } + if (environment.GITHUB_ACTIONS === 'true' || environment[TEST_TIMING_ENV] !== 'true') { + fail(`custom timing is test-only and requires ${TEST_TIMING_ENV}=true outside GitHub Actions`); + } + if (timing === null || Array.isArray(timing) || typeof timing !== 'object') { + fail('custom timing must be an object'); + } + const result = { + intervalMs: timing.intervalMs, + maxLockWaitMs: timing.maxLockWaitMs, + }; + for (const [label, value] of Object.entries({ + 'interval timing': result.intervalMs, + 'lock-wait timing': result.maxLockWaitMs, + })) { + if (!Number.isSafeInteger(value) || value < 1) + fail(`custom ${label} must be a positive safe integer`); + } + return result; +} + +export async function reserveGitHubContentWrite({ + environment = process.env, + label, + now = Date.now, + sleep = wait, + timing = undefined, +} = {}) { + if ( + typeof label !== 'string' || + label.length === 0 || + label.length > 200 || + /[\u0000-\u001f\u007f]/u.test(label) + ) { + fail('reservation label must be a non-empty printable string of at most 200 characters'); + } + const file = pacerPath(environment); + if (file === null) return { enabled: false, sequence: 0, waitedMs: 0 }; + const resolvedTiming = timingOptions(environment, timing); + const expectedIdentity = githubReleaseLineageIdentity(environment); + mkdirSync(path.dirname(file), { recursive: true }); + const lock = await acquireLock(file, { maxLockWaitMs: resolvedTiming.maxLockWaitMs, now, sleep }); + let reservedAt; + let sequence; + let waitMs; + try { + const previous = parseState(file, expectedIdentity, resolvedTiming); + const observedAt = now(); + if (!Number.isSafeInteger(observedAt) || observedAt < 0) + fail('clock returned an invalid timestamp'); + // Allocate and persist the next globally ordered slot while holding the + // lock briefly, then wait outside it. A crashed waiter burns its slot + // conservatively. + const earliest = + previous === null ? observedAt : previous.lastReservedAtMs + resolvedTiming.intervalMs; + reservedAt = Math.max(observedAt, earliest); + waitMs = reservedAt - observedAt; + const deadline = hardDeadlineMs(environment); + if (deadline !== null && reservedAt >= deadline) { + fail('the next content-write reservation would reach the hard release deadline'); + } + sequence = (previous?.sequence ?? 0) + 1; + if (!Number.isSafeInteger(sequence) || !Number.isSafeInteger(reservedAt)) + fail('reservation exceeds the safe integer range'); + const state = { + schema: SCHEMA, + ...expectedIdentity, + intervalMs: resolvedTiming.intervalMs, + sequence, + lastReservedAtMs: reservedAt, + lastLabel: label, + }; + writeState(file, state); + } finally { + rmSync(lock, { force: true }); + } + + await sleep(waitMs); + const observedAfterWait = now(); + if (!Number.isSafeInteger(observedAfterWait) || observedAfterWait < reservedAt) { + fail('clock did not advance through the required content-write pacing interval'); + } + const deadline = hardDeadlineMs(environment); + if (deadline !== null && observedAfterWait >= deadline) { + fail('the content-write reservation reached the hard release deadline while waiting'); + } + return { enabled: true, sequence, waitedMs: waitMs, reservedAtMs: reservedAt }; +} + +async function main(argv) { + if (argv[0] !== 'reserve' || argv.length !== 3 || argv[1] !== '--label') { + fail('usage: github-content-write-pacer.mts reserve --label LABEL'); + } + const result = await reserveGitHubContentWrite({ label: argv[2] }); + if (!result.enabled) fail('the content-write pacer is not enabled'); + console.log(`reserved GitHub content write ${result.sequence} after ${result.waitedMs}ms`); +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + try { + await main(process.argv.slice(2)); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/github-content-write-pacer.test.mjs b/tools/release/github-content-write-pacer.test.mjs deleted file mode 100644 index 117028003..000000000 --- a/tools/release/github-content-write-pacer.test.mjs +++ /dev/null @@ -1,263 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import { spawn } from "node:child_process"; -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; -import { pathToFileURL } from "node:url"; - -import { - GITHUB_CONTENT_WRITE_INTERVAL_MS, - reserveGitHubContentWriteSync, -} from "./github-content-write-pacer.mjs"; -import { - runGitHubMutationSync, -} from "./github-release-mutations.mjs"; - -const SHA = "a".repeat(40); - -function fixture(t) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-github-pacer-")); - t.after(() => rmSync(root, { force: true, recursive: true })); - const environment = { - GH_TOKEN: "test-token", - GITHUB_ACTIONS: "true", - GITHUB_REPOSITORY: "f0rr0/oliphaunt", - GITHUB_RUN_ATTEMPT: "1", - GITHUB_RUN_ID: "123", - GITHUB_SHA: SHA, - OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH: path.join(root, "pacer.json"), - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, "core-requests.json"), - }; - let nowMs = 1_010_000; - const sleeps = []; - return { - environment, - now: () => nowMs, - setNow: (value) => { nowMs = value; }, - sleep: (milliseconds) => { sleeps.push(milliseconds); nowMs += milliseconds; }, - sleeps, - }; -} - -test("a new runner reserves immediately and persists each subsequent request slot", (t) => { - const f = fixture(t); - const first = reserveGitHubContentWriteSync({ - environment: f.environment, - label: "first", - now: f.now, - sleep: f.sleep, - }); - assert.equal(first.waitedMs, 0); - assert.equal(first.sequence, 1); - const second = reserveGitHubContentWriteSync({ - environment: f.environment, - label: "second", - now: f.now, - sleep: f.sleep, - }); - assert.equal(second.waitedMs, GITHUB_CONTENT_WRITE_INTERVAL_MS); - assert.equal(second.sequence, 2); - const state = JSON.parse(readFileSync(f.environment.OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH, "utf8")); - assert.equal(state.sequence, 2); - assert.equal(state.lastLabel, "second"); - assert.deepEqual(state.reservations, [ - { label: "first", reservedAtMs: 1_010_000, sequence: 1 }, - { label: "second", reservedAtMs: 1_020_000, sequence: 2 }, - ]); -}); - -test("a malformed or identity-replaced durable journal fails closed", (t) => { - const f = fixture(t); - reserveGitHubContentWriteSync({ - environment: f.environment, - label: "first", - now: f.now, - sleep: f.sleep, - }); - const file = f.environment.OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH; - const state = JSON.parse(readFileSync(file, "utf8")); - state.reservations[0].reservedAtMs += 1; - writeFileSync(file, `${JSON.stringify(state)}\n`); - assert.throws( - () => reserveGitHubContentWriteSync({ - environment: f.environment, - label: "second", - now: f.now, - sleep: f.sleep, - }), - /summary does not match.*journal/u, - ); -}); - -test("five concurrent product lanes serialize repeated shared pacer and core-request reservations without loss", async (t) => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-github-journal-processes-")); - t.after(() => rmSync(root, { force: true, recursive: true })); - const pacer = path.join(root, "pacer.json"); - const core = path.join(root, "core.json"); - const worker = path.join(root, "reserve-worker.mjs"); - writeFileSync(worker, ` -import { reserveGitHubContentWriteSync } from ${JSON.stringify(pathToFileURL(path.resolve("tools/release/github-content-write-pacer.mjs")).href)}; -import { reserveGitHubCoreRequestSync } from ${JSON.stringify(pathToFileURL(path.resolve("tools/release/github-core-request-journal.mjs")).href)}; -for (let attempt = 0; attempt < 4; attempt += 1) { - const label = \`asset-\${process.argv[2]}-\${attempt}\`; - reserveGitHubContentWriteSync({ - environment: process.env, - label, - timing: { intervalMs: 50, maxLockWaitMs: 2_000 }, - }); - reserveGitHubCoreRequestSync({ environment: process.env, label }); -} -`); - const environment = { - ...process.env, - GITHUB_ACTIONS: "false", - GITHUB_REPOSITORY: "f0rr0/oliphaunt", - GITHUB_RUN_ATTEMPT: "1", - GITHUB_RUN_ID: "456", - GITHUB_SHA: SHA, - OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH: pacer, - OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE: "true", - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: core, - OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: "true", - }; - const seedReservedAtMs = Date.now() + 500; - writeFileSync(pacer, `${JSON.stringify({ - schema: "oliphaunt-github-content-write-pacer-v4", - headSha: SHA, - repository: "f0rr0/oliphaunt", - runId: "456", - intervalMs: 50, - sequence: 1, - lastReservedAtMs: seedReservedAtMs, - lastLabel: "seed future slot", - reservations: [{ - label: "seed future slot", - reservedAtMs: seedReservedAtMs, - sequence: 1, - }], - })}\n`); - const run = (index) => new Promise((resolve, reject) => { - const child = spawn(process.execPath, [worker, String(index)], { - env: environment, - stdio: ["ignore", "pipe", "pipe"], - }); - let stderr = ""; - child.stderr.on("data", (chunk) => { stderr += String(chunk); }); - child.once("error", reject); - child.once("close", (code, signal) => { - if (code === 0 && signal === null) resolve(); - else reject(new Error(`journal worker ${index} failed (${code}/${signal}): ${stderr}`)); - }); - }); - await Promise.all(Array.from({ length: 5 }, (_, index) => run(index))); - const pacerState = JSON.parse(readFileSync(pacer, "utf8")); - const coreState = JSON.parse(readFileSync(core, "utf8")); - assert.equal(pacerState.sequence, 21); - assert.equal(pacerState.reservations.length, 21); - assert.deepEqual(pacerState.reservations.map(({ sequence }) => sequence), - Array.from({ length: 21 }, (_, index) => index + 1)); - const laneReservations = pacerState.reservations.slice(1); - assert.deepEqual( - new Set(laneReservations.map(({ label }) => label)), - new Set(Array.from( - { length: 5 }, - (_, index) => Array.from({ length: 4 }, (__, attempt) => `asset-${index}-${attempt}`), - ).flat()), - ); - for (let index = 0; index < 5; index += 1) { - assert.deepEqual( - laneReservations - .map(({ label }) => label) - .filter((label) => label.startsWith(`asset-${index}-`)), - Array.from({ length: 4 }, (_, attempt) => `asset-${index}-${attempt}`), - ); - } - for (const [index, reservation] of pacerState.reservations.entries()) { - if (index === 0) continue; - assert.ok( - reservation.reservedAtMs >= pacerState.reservations[index - 1].reservedAtMs + 50, - ); - } - assert.equal(coreState.sequence, 20); - assert.equal(coreState.attempts.length, 20); - assert.deepEqual( - new Set(coreState.attempts.map(({ label }) => label)), - new Set(Array.from( - { length: 5 }, - (_, index) => Array.from({ length: 4 }, (__, attempt) => `asset-${index}-${attempt}`), - ).flat()), - ); -}); - -test("GitHub Actions cannot weaken production pacer timing", (t) => { - const f = fixture(t); - assert.throws( - () => reserveGitHubContentWriteSync({ - environment: { ...f.environment, OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE: "true" }, - label: "forbidden-override", - timing: { intervalMs: 1, maxLockWaitMs: 1 }, - }), - /custom timing is test-only/u, - ); -}); - -test("pacing occurs outside a complete 60-second request timeout", (t) => { - const f = fixture(t); - reserveGitHubContentWriteSync({ - environment: f.environment, - label: "first", - now: f.now, - sleep: f.sleep, - }); - f.sleeps.length = 0; - let observedTimeout = 0; - const output = runGitHubMutationSync( - ["api", "repos/f0rr0/oliphaunt/git/refs", "-X", "POST", "--input", "-"], - { - environment: f.environment, - input: `${JSON.stringify({ ref: "refs/tags/test-v1.0.0", sha: SHA })}\n`, - pacerOptions: { now: f.now, sleep: f.sleep }, - spawn: (_command, _args, options) => { - observedTimeout = options.timeout; - return { status: 0, stdout: "{}", stderr: "" }; - }, - timeoutMs: 60_000, - }, - ); - assert.equal(output, "{}"); - assert.equal(observedTimeout, 60_000); - assert.equal(f.sleeps[0], GITHUB_CONTENT_WRITE_INTERVAL_MS); -}); - -test("pacing that crosses the absolute deadline issues no transport attempt", (t) => { - const f = fixture(t); - reserveGitHubContentWriteSync({ - environment: f.environment, - label: "first", - now: f.now, - sleep: f.sleep, - }); - let spawnCalls = 0; - assert.throws( - () => runGitHubMutationSync( - ["api", "repos/f0rr0/oliphaunt/git/refs", "-X", "POST", "--input", "-"], - { - deadlineMs: 1_079_999, - environment: f.environment, - input: `${JSON.stringify({ ref: "refs/tags/test-v1.0.0", sha: SHA })}\n`, - now: f.now, - pacerOptions: { now: f.now, sleep: f.sleep }, - spawn: () => { - spawnCalls += 1; - return { status: 0, stdout: "{}", stderr: "" }; - }, - timeoutMs: 60_000, - }, - ), - /requires its complete 60000ms transport timeout after pacing/u, - ); - assert.equal(spawnCalls, 0); -}); diff --git a/tools/release/github-content-write-pacer.test.mts b/tools/release/github-content-write-pacer.test.mts new file mode 100644 index 000000000..de3169588 --- /dev/null +++ b/tools/release/github-content-write-pacer.test.mts @@ -0,0 +1,260 @@ +#!/usr/bin/env bun + +import assert from 'node:assert/strict'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; + +import { + GITHUB_CONTENT_WRITE_INTERVAL_MS, + reserveGitHubContentWrite, +} from './github-content-write-pacer.mts'; +import { reserveGitHubCoreRequest } from './github-core-request-journal.mts'; +import { requestGithubMutation } from './github-release-mutations.mts'; + +const SHA = 'a'.repeat(40); + +function fixture(t) { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-github-pacer-')); + t.after(() => rmSync(root, { force: true, recursive: true })); + const environment = { + GH_TOKEN: 'test-token', + GITHUB_ACTIONS: 'true', + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_RUN_ATTEMPT: '1', + GITHUB_RUN_ID: '123', + GITHUB_SHA: SHA, + OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH: path.join(root, 'pacer.json'), + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, 'core-requests.json'), + }; + let nowMs = 1_010_000; + const sleeps = []; + return { + environment, + now: () => nowMs, + setNow: (value) => { + nowMs = value; + }, + sleep: (milliseconds) => { + sleeps.push(milliseconds); + nowMs += milliseconds; + }, + sleeps, + }; +} + +const [mode, lane] = process.argv.slice(2); +if (mode === 'seed') { + await reserveGitHubContentWrite({ + environment: process.env, + label: 'seed future slot', + timing: { intervalMs: 50, maxLockWaitMs: 2000 }, + now: () => Date.now() + 500, + sleep: async () => {}, + }); + process.exit(0); +} +if (mode === 'worker') { + for (let attempt = 0; attempt < 4; attempt++) { + const label = `asset-${lane}-${attempt}`; + const reservation = await reserveGitHubContentWrite({ + environment: process.env, + label, + timing: { intervalMs: 50, maxLockWaitMs: 2000 }, + }); + await reserveGitHubCoreRequest({ environment: process.env, label }); + console.log(JSON.stringify({ label, ...reservation })); + } + process.exit(0); +} +if (mode === 'assert') { + const pacer = process.env.OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH; + const core = process.env.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH; + const pacerState = JSON.parse(readFileSync(pacer, 'utf8')); + const coreState = JSON.parse(readFileSync(core, 'utf8')); + assert.equal(pacerState.sequence, 21); + const laneReservations = Array.from({ length: 5 }, (_, lane) => + readFileSync(path.join(path.dirname(pacer), `${lane}.log`), 'utf8') + .trim() + .split('\n') + .map((line) => JSON.parse(line)), + ) + .flat() + .sort((a, b) => a.sequence - b.sequence); + assert.deepEqual( + laneReservations.map(({ sequence }) => sequence), + Array.from({ length: 20 }, (_, i) => i + 2), + ); + assert.deepEqual( + new Set(laneReservations.map(({ label }) => label)), + new Set( + Array.from({ length: 5 }, (_, index) => + Array.from({ length: 4 }, (__, attempt) => `asset-${index}-${attempt}`), + ).flat(), + ), + ); + for (let index = 0; index < 5; index += 1) { + assert.deepEqual( + laneReservations + .map(({ label }) => label) + .filter((label) => label.startsWith(`asset-${index}-`)), + Array.from({ length: 4 }, (_, attempt) => `asset-${index}-${attempt}`), + ); + } + for (let index = 1; index < laneReservations.length; index++) { + assert.ok( + laneReservations[index].reservedAtMs >= laneReservations[index - 1].reservedAtMs + 50, + ); + } + assert.equal(pacerState.lastReservedAtMs, laneReservations.at(-1).reservedAtMs); + assert.equal(coreState.sequence, 20); + assert.equal(coreState.attempts.length, 20); + + process.exit(0); +} + +test('a new runner reserves immediately and persists each subsequent request slot', async (t) => { + const f = fixture(t); + const first = await reserveGitHubContentWrite({ + environment: f.environment, + label: 'first', + now: f.now, + sleep: f.sleep, + }); + assert.equal(first.waitedMs, 0); + assert.equal(first.sequence, 1); + const second = await reserveGitHubContentWrite({ + environment: f.environment, + label: 'second', + now: f.now, + sleep: f.sleep, + }); + assert.equal(second.waitedMs, GITHUB_CONTENT_WRITE_INTERVAL_MS); + assert.equal(second.sequence, 2); + const state = JSON.parse( + readFileSync(f.environment.OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH, 'utf8'), + ); + assert.equal(state.sequence, 2); + assert.equal(state.lastLabel, 'second'); + assert.equal(state.lastReservedAtMs, 1_020_000); + assert.equal(state.reservations, undefined); +}); + +test('malformed or identity-replaced reservation state fails closed', async (t) => { + const f = fixture(t); + await reserveGitHubContentWrite({ + environment: f.environment, + label: 'first', + now: f.now, + sleep: f.sleep, + }); + const file = f.environment.OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH; + const valid = JSON.parse(readFileSync(file, 'utf8')); + for (const change of [ + { lastReservedAtMs: -1 }, + { headSha: 'b'.repeat(40) }, + { sequence: Number.MAX_SAFE_INTEGER }, + ]) { + writeFileSync(file, JSON.stringify({ ...valid, ...change })); + const before = readFileSync(file, 'utf8'); + await assert.rejects(() => + reserveGitHubContentWrite({ + environment: f.environment, + label: 'second', + now: f.now, + sleep: f.sleep, + }), + ); + assert.equal(readFileSync(file, 'utf8'), before); + } +}); + +test('GitHub Actions cannot weaken production pacer timing', async (t) => { + const f = fixture(t); + await assert.rejects( + async () => + await reserveGitHubContentWrite({ + environment: { ...f.environment, OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE: 'true' }, + label: 'forbidden-override', + timing: { intervalMs: 1, maxLockWaitMs: 1 }, + }), + /custom timing is test-only/u, + ); +}); + +test('pacing occurs outside a complete 60-second request timeout', async (t) => { + const f = fixture(t); + await reserveGitHubContentWrite({ + environment: f.environment, + label: 'first', + now: f.now, + sleep: f.sleep, + }); + f.sleeps.length = 0; + let observedSignal; + const output = await requestGithubMutation('repos/f0rr0/oliphaunt/git/refs', { + method: 'POST', + environment: f.environment, + input: `${JSON.stringify({ ref: 'refs/tags/test-v1.0.0', sha: SHA })}\n`, + pacerOptions: { now: f.now, sleep: f.sleep }, + fetchImpl: (_url, options) => { + observedSignal = options.signal; + return new Response('{}'); + }, + timeoutMs: 60_000, + }); + assert.equal(output, '{}'); + assert.ok(observedSignal instanceof AbortSignal); + assert.equal(observedSignal.aborted, false); + assert.equal(f.sleeps[0], GITHUB_CONTENT_WRITE_INTERVAL_MS); +}); + +test('pacing that crosses the absolute deadline issues no transport attempt', async (t) => { + const f = fixture(t); + await reserveGitHubContentWrite({ + environment: f.environment, + label: 'first', + now: f.now, + sleep: f.sleep, + }); + let spawnCalls = 0; + await assert.rejects( + async () => + await requestGithubMutation('repos/f0rr0/oliphaunt/git/refs', { + method: 'POST', + deadlineMs: 1_079_999, + environment: f.environment, + input: `${JSON.stringify({ ref: 'refs/tags/test-v1.0.0', sha: SHA })}\n`, + now: f.now, + pacerOptions: { now: f.now, sleep: f.sleep }, + fetchImpl: () => { + spawnCalls += 1; + return new Response('{}'); + }, + timeoutMs: 60_000, + }), + /requires its complete 60000ms transport timeout after pacing/u, + ); + assert.equal(spawnCalls, 0); +}); + +test('pacing waits leave the event loop available to in-flight uploads', async (t) => { + const f = fixture(t); + const options = { + environment: { + ...f.environment, + GITHUB_ACTIONS: 'false', + OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE: 'true', + }, + timing: { intervalMs: 50, maxLockWaitMs: 1_000 }, + }; + await reserveGitHubContentWrite({ ...options, label: 'first' }); + let progressed = false; + const timer = setTimeout(() => { + progressed = true; + }, 0); + t.after(() => clearTimeout(timer)); + await reserveGitHubContentWrite({ ...options, label: 'second' }); + assert.equal(progressed, true); +}); diff --git a/tools/release/github-content-write-pacer.test.sh b/tools/release/github-content-write-pacer.test.sh new file mode 100644 index 000000000..4d592a468 --- /dev/null +++ b/tools/release/github-content-write-pacer.test.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/github-content-write-pacer.test.mts +scratch="$(mktemp -d)" +pids=() +cleanup() { + for pid in "${pids[@]}"; do kill "$pid" 2>/dev/null || true; done + for pid in "${pids[@]}"; do wait "$pid" 2>/dev/null || true; done + rm -rf "$scratch" +} +trap cleanup EXIT +export GITHUB_ACTIONS=false GITHUB_REPOSITORY=f0rr0/oliphaunt GITHUB_RUN_ATTEMPT=1 GITHUB_RUN_ID=456 +export GITHUB_SHA=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +export OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH="$scratch/pacer.json" OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE=true +export OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH="$scratch/core.json" OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL=true +bun tools/release/github-content-write-pacer.test.mts seed +for lane in 0 1 2 3 4; do + bun tools/release/github-content-write-pacer.test.mts worker "$lane" > "$scratch/$lane.log" 2>&1 & + pids+=("$!") +done +failed=0 +for pid in "${pids[@]}"; do wait "$pid" || failed=1; done +pids=() +if [[ "$failed" != 0 ]]; then cat "$scratch/"*.log >&2; exit 1; fi +bun tools/release/github-content-write-pacer.test.mts assert +echo 'GitHub pacer: five concurrent lanes preserve all ordered reservations' diff --git a/tools/release/github-core-request-journal.mjs b/tools/release/github-core-request-journal.mjs deleted file mode 100644 index 4a353f904..000000000 --- a/tools/release/github-core-request-journal.mjs +++ /dev/null @@ -1,263 +0,0 @@ -#!/usr/bin/env node - -import { - closeSync, - existsSync, - lstatSync, - mkdirSync, - openSync, - readFileSync, - renameSync, - rmSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import process from "node:process"; -import { fileURLToPath } from "node:url"; -import { githubReleaseLineageIdentity } from "./github-release-lineage.mjs"; - -export const GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS = 60 * 60_000; -export const GITHUB_CORE_REQUEST_ROLLING_CEILING = 900; -export const GITHUB_CORE_REQUEST_RETRY_RESERVE = 100; - -const SCHEMA = "oliphaunt-github-core-request-journal-v3"; -const MAX_LOCK_WAIT_MS = 60_000; - -export class GitHubCoreRequestJournalError extends Error { - constructor(message, options = {}) { - super(`github-core-request-journal: ${message}`, options); - this.name = "GitHubCoreRequestJournalError"; - } -} - -function fail(message, options = {}) { - throw new GitHubCoreRequestJournalError(message, options); -} - -function sleepSync(milliseconds) { - if (milliseconds <= 0) return; - const cell = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)); - Atomics.wait(cell, 0, 0, milliseconds); -} - -function journalPath(environment) { - const configured = environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH?.trim() ?? ""; - const required = environment.OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL ?? "false"; - if (required !== "true" && required !== "false") { - fail("OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL must be true or false"); - } - if (configured === "") { - if (required === "true") { - fail("OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH is required for this release operation"); - } - return null; - } - if (configured.includes("\0")) fail("journal path contains a NUL byte"); - return path.resolve(configured); -} - -function assertRegularFile(file, label) { - const stat = lstatSync(file, { throwIfNoEntry: false }); - if (stat !== undefined && (!stat.isFile() || stat.isSymbolicLink())) { - fail(`${label} must be an absent or regular non-symbolic-link file`); - } -} - -function emptyState(expectedIdentity) { - return { - schema: SCHEMA, - ...expectedIdentity, - sequence: 0, - attempts: [], - }; -} - -function validateState(state, expectedIdentity) { - if (state === null || Array.isArray(state) || typeof state !== "object") { - fail("core-request journal must be an object"); - } - const expectedKeys = ["attempts", "headSha", "repository", "runId", "schema", "sequence"]; - if (JSON.stringify(Object.keys(state).sort()) !== JSON.stringify(expectedKeys)) { - fail(`core-request journal keys must be exactly ${expectedKeys.join(", ")}`); - } - if (state.schema !== SCHEMA) fail(`core-request journal schema must be ${SCHEMA}`); - for (const key of ["headSha", "repository", "runId"]) { - if (state[key] !== expectedIdentity[key]) { - fail(`core-request journal ${key} does not match the current release`); - } - } - if (!Number.isSafeInteger(state.sequence) || state.sequence < 0) { - fail("core-request journal sequence must be a non-negative safe integer"); - } - if (!Array.isArray(state.attempts) || state.attempts.length !== state.sequence) { - fail("core-request journal attempts do not match its sequence"); - } - let previous = -1; - const attempts = state.attempts.map((attempt, index) => { - if ( - attempt === null - || Array.isArray(attempt) - || typeof attempt !== "object" - || JSON.stringify(Object.keys(attempt).sort()) - !== JSON.stringify(["label", "reservedAtMs", "sequence"]) - ) { - fail(`core-request attempt ${index + 1} has invalid fields`); - } - validateLabel(attempt.label); - if (!Number.isSafeInteger(attempt.reservedAtMs) || attempt.reservedAtMs < previous) { - fail("core-request journal attempts are not timestamp ordered"); - } - if (attempt.sequence !== index + 1) { - fail("core-request journal attempt sequences are not contiguous"); - } - previous = attempt.reservedAtMs; - return { ...attempt }; - }); - return { ...expectedIdentity, attempts, schema: SCHEMA, sequence: state.sequence }; -} - -function parseState(file, expectedIdentity) { - if (!existsSync(file)) return emptyState(expectedIdentity); - assertRegularFile(file, "core-request journal"); - let state; - try { - state = JSON.parse(readFileSync(file, "utf8")); - } catch (cause) { - fail("core-request journal is not valid JSON", { cause }); - } - try { - return validateState(state, expectedIdentity); - } catch (cause) { - fail( - `core-request journal has a malformed envelope: ${cause instanceof Error ? cause.message : String(cause)}`, - { cause }, - ); - } -} - -function writeState(file, state) { - mkdirSync(path.dirname(file), { recursive: true }); - assertRegularFile(file, "core-request journal"); - const temporary = `${file}.tmp-${process.pid}-${state.sequence}`; - assertRegularFile(temporary, "temporary core-request journal"); - try { - writeFileSync(temporary, `${JSON.stringify(state)}\n`, { flag: "wx", mode: 0o600 }); - renameSync(temporary, file); - } finally { - rmSync(temporary, { force: true }); - } -} - -function acquireLock(file, { now, sleep }) { - const lock = `${file}.lock`; - const startedAt = now(); - while (true) { - let descriptor; - try { - descriptor = openSync(lock, "wx", 0o600); - writeFileSync(descriptor, `${process.pid}\n`); - closeSync(descriptor); - return lock; - } catch (cause) { - if (descriptor !== undefined) closeSync(descriptor); - if (cause?.code !== "EEXIST") rmSync(lock, { force: true }); - if (cause?.code !== "EEXIST") fail("could not acquire the core-request journal lock", { cause }); - if (now() - startedAt >= MAX_LOCK_WAIT_MS) fail("timed out waiting for the core-request journal lock"); - sleep(100); - } - } -} - -function validateLabel(label) { - if ( - typeof label !== "string" - || label.length === 0 - || label.length > 200 - || /[\u0000-\u001f\u007f]/u.test(label) - ) { - fail("request label must be a non-empty printable string of at most 200 characters"); - } -} - -function rollingAttempts(state, nowMs) { - const boundary = nowMs - GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS; - return state.attempts.filter(({ reservedAtMs }) => reservedAtMs >= boundary); -} - -export function readGitHubCoreRequestJournal({ environment = process.env, now = Date.now } = {}) { - const file = journalPath(environment); - if (file === null) return { enabled: false, rollingCount: 0, sequence: 0 }; - const nowMs = now(); - if (!Number.isSafeInteger(nowMs) || nowMs < 0) fail("clock returned an invalid timestamp"); - const state = parseState(file, githubReleaseLineageIdentity(environment)); - if (state.attempts.at(-1)?.reservedAtMs > nowMs) fail("clock moved backwards behind the request journal"); - return { - enabled: true, - rollingCount: rollingAttempts(state, nowMs).length, - sequence: state.sequence, - }; -} - -export function reserveGitHubCoreRequestSync({ - environment = process.env, - label, - now = Date.now, - sleep = sleepSync, -} = {}) { - validateLabel(label); - const file = journalPath(environment); - if (file === null) return { enabled: false, rollingCount: 0, sequence: 0 }; - const expectedIdentity = githubReleaseLineageIdentity(environment); - mkdirSync(path.dirname(file), { recursive: true }); - const lock = acquireLock(file, { now, sleep }); - try { - const state = parseState(file, expectedIdentity); - const reservedAtMs = now(); - if (!Number.isSafeInteger(reservedAtMs) || reservedAtMs < 0) fail("clock returned an invalid timestamp"); - if (state.attempts.at(-1)?.reservedAtMs > reservedAtMs) { - fail("clock moved backwards behind the request journal"); - } - const rollingCount = rollingAttempts(state, reservedAtMs).length; - if (rollingCount >= GITHUB_CORE_REQUEST_ROLLING_CEILING) { - fail( - `refusing request ${JSON.stringify(label)} because ${rollingCount} attempts already occupy the ` - + `${GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS / 60_000}-minute safety window`, - ); - } - const sequence = state.sequence + 1; - const next = { - ...state, - sequence, - attempts: [...state.attempts, { label, reservedAtMs, sequence }], - }; - writeState(file, next); - return { enabled: true, rollingCount: rollingCount + 1, sequence }; - } finally { - rmSync(lock, { force: true }); - } -} - -function main(argv) { - if (argv[0] === "reserve" && argv.length === 3 && argv[1] === "--label") { - const result = reserveGitHubCoreRequestSync({ label: argv[2] }); - if (!result.enabled) fail("the core-request journal is not enabled"); - console.log(`reserved GitHub core request ${result.sequence} (${result.rollingCount} in the safety window)`); - return; - } - if (argv[0] === "status" && argv.length === 1) { - const result = readGitHubCoreRequestJournal(); - if (!result.enabled) fail("the core-request journal is not enabled"); - console.log(JSON.stringify(result)); - return; - } - fail("usage: github-core-request-journal.mjs "); -} - -if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { - try { - main(process.argv.slice(2)); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/github-core-request-journal.mts b/tools/release/github-core-request-journal.mts new file mode 100644 index 000000000..76191f018 --- /dev/null +++ b/tools/release/github-core-request-journal.mts @@ -0,0 +1,257 @@ +#!/usr/bin/env bun + +import { + closeSync, + existsSync, + lstatSync, + mkdirSync, + openSync, + readFileSync, + renameSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { setTimeout as wait } from 'node:timers/promises'; +import { fileURLToPath } from 'node:url'; +import { githubReleaseLineageIdentity } from './github-release-lineage.mts'; + +export const GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS = 60 * 60_000; +export const GITHUB_CORE_REQUEST_ROLLING_CEILING = 900; +export const GITHUB_CORE_REQUEST_RETRY_RESERVE = 100; + +const SCHEMA = 'oliphaunt-github-core-request-journal-v4'; +const MAX_LOCK_WAIT_MS = 60_000; + +export class GitHubCoreRequestJournalError extends Error { + constructor(message, options = {}) { + super(`github-core-request-journal: ${message}`, options); + this.name = 'GitHubCoreRequestJournalError'; + } +} + +function fail(message, options = {}) { + throw new GitHubCoreRequestJournalError(message, options); +} + +function journalPath(environment) { + const configured = environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH?.trim() ?? ''; + const required = environment.OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL ?? 'false'; + if (required !== 'true' && required !== 'false') { + fail('OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL must be true or false'); + } + if (configured === '') { + if (required === 'true') { + fail('OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH is required for this release operation'); + } + return null; + } + if (configured.includes('\0')) fail('journal path contains a NUL byte'); + return path.resolve(configured); +} + +function assertRegularFile(file, label) { + const stat = lstatSync(file, { throwIfNoEntry: false }); + if (stat !== undefined && (!stat.isFile() || stat.isSymbolicLink())) { + fail(`${label} must be an absent or regular non-symbolic-link file`); + } +} + +function emptyState(expectedIdentity) { + return { + schema: SCHEMA, + ...expectedIdentity, + sequence: 0, + attempts: [], + }; +} + +function validateState(state, expectedIdentity) { + if (state === null || Array.isArray(state) || typeof state !== 'object') { + fail('core-request journal must be an object'); + } + const expectedKeys = ['attempts', 'headSha', 'repository', 'runId', 'schema', 'sequence']; + if (JSON.stringify(Object.keys(state).sort()) !== JSON.stringify(expectedKeys)) { + fail(`core-request journal keys must be exactly ${expectedKeys.join(', ')}`); + } + if (state.schema !== SCHEMA) fail(`core-request journal schema must be ${SCHEMA}`); + for (const key of ['headSha', 'repository', 'runId']) { + if (state[key] !== expectedIdentity[key]) { + fail(`core-request journal ${key} does not match the current release`); + } + } + if (!Number.isSafeInteger(state.sequence) || state.sequence < 0) { + fail('core-request journal sequence must be a non-negative safe integer'); + } + if ( + !Array.isArray(state.attempts) || + state.attempts.length > GITHUB_CORE_REQUEST_ROLLING_CEILING || + state.attempts.length > state.sequence || + (state.sequence > 0 && state.attempts.length === 0) + ) { + fail('core-request journal attempts do not match its sequence'); + } + let previous = -1; + for (const timestamp of state.attempts) { + if (!Number.isSafeInteger(timestamp) || timestamp < 0 || timestamp < previous) { + fail('core-request journal attempts are not timestamp ordered'); + } + previous = timestamp; + } + const attempts = state.attempts; + return { ...expectedIdentity, attempts, schema: SCHEMA, sequence: state.sequence }; +} + +function parseState(file, expectedIdentity) { + if (!existsSync(file)) return emptyState(expectedIdentity); + assertRegularFile(file, 'core-request journal'); + let state; + try { + state = JSON.parse(readFileSync(file, 'utf8')); + } catch (cause) { + fail('core-request journal is not valid JSON', { cause }); + } + try { + return validateState(state, expectedIdentity); + } catch (cause) { + fail( + `core-request journal has a malformed envelope: ${cause instanceof Error ? cause.message : String(cause)}`, + { cause }, + ); + } +} + +function writeState(file, state) { + mkdirSync(path.dirname(file), { recursive: true }); + assertRegularFile(file, 'core-request journal'); + const temporary = `${file}.tmp-${process.pid}-${state.sequence}`; + assertRegularFile(temporary, 'temporary core-request journal'); + try { + writeFileSync(temporary, `${JSON.stringify(state)}\n`, { flag: 'wx', mode: 0o600 }); + renameSync(temporary, file); + } finally { + rmSync(temporary, { force: true }); + } +} + +async function acquireLock(file, { now, sleep }) { + const lock = `${file}.lock`; + const startedAt = now(); + while (true) { + let descriptor; + try { + descriptor = openSync(lock, 'wx', 0o600); + writeFileSync(descriptor, `${process.pid}\n`); + closeSync(descriptor); + return lock; + } catch (cause) { + if (descriptor !== undefined) closeSync(descriptor); + if (cause?.code !== 'EEXIST') rmSync(lock, { force: true }); + if (cause?.code !== 'EEXIST') + fail('could not acquire the core-request journal lock', { cause }); + if (now() - startedAt >= MAX_LOCK_WAIT_MS) + fail('timed out waiting for the core-request journal lock'); + await sleep(100); + } + } +} + +function validateLabel(label) { + if ( + typeof label !== 'string' || + label.length === 0 || + label.length > 200 || + /[\u0000-\u001f\u007f]/u.test(label) + ) { + fail('request label must be a non-empty printable string of at most 200 characters'); + } +} + +function rollingAttempts(state, nowMs) { + const boundary = nowMs - GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS; + return state.attempts.filter((reservedAtMs) => reservedAtMs >= boundary); +} + +export function readGitHubCoreRequestJournal({ environment = process.env, now = Date.now } = {}) { + const file = journalPath(environment); + if (file === null) return { enabled: false, rollingCount: 0, sequence: 0 }; + const nowMs = now(); + if (!Number.isSafeInteger(nowMs) || nowMs < 0) fail('clock returned an invalid timestamp'); + const state = parseState(file, githubReleaseLineageIdentity(environment)); + if (state.attempts.at(-1) > nowMs) fail('clock moved backwards behind the request journal'); + return { + enabled: true, + rollingCount: rollingAttempts(state, nowMs).length, + sequence: state.sequence, + }; +} + +export async function reserveGitHubCoreRequest({ + environment = process.env, + label, + now = Date.now, + sleep = wait, +} = {}) { + validateLabel(label); + const file = journalPath(environment); + if (file === null) return { enabled: false, rollingCount: 0, sequence: 0 }; + const expectedIdentity = githubReleaseLineageIdentity(environment); + mkdirSync(path.dirname(file), { recursive: true }); + const lock = await acquireLock(file, { now, sleep }); + try { + const state = parseState(file, expectedIdentity); + const reservedAtMs = now(); + if (!Number.isSafeInteger(reservedAtMs) || reservedAtMs < 0) + fail('clock returned an invalid timestamp'); + if (state.attempts.at(-1) > reservedAtMs) { + fail('clock moved backwards behind the request journal'); + } + const attempts = rollingAttempts(state, reservedAtMs); + const rollingCount = attempts.length; + if (rollingCount >= GITHUB_CORE_REQUEST_ROLLING_CEILING) { + fail( + `refusing request ${JSON.stringify(label)} because ${rollingCount} attempts already occupy the ` + + `${GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS / 60_000}-minute safety window`, + ); + } + const sequence = state.sequence + 1; + if (!Number.isSafeInteger(sequence)) fail('request sequence exceeds the safe integer range'); + const next = { + ...state, + sequence, + attempts: [...attempts, reservedAtMs], + }; + writeState(file, next); + return { enabled: true, rollingCount: rollingCount + 1, sequence }; + } finally { + rmSync(lock, { force: true }); + } +} + +async function main(argv) { + if (argv[0] === 'reserve' && argv.length === 3 && argv[1] === '--label') { + const result = await reserveGitHubCoreRequest({ label: argv[2] }); + if (!result.enabled) fail('the core-request journal is not enabled'); + console.log( + `reserved GitHub core request ${result.sequence} (${result.rollingCount} in the safety window)`, + ); + return; + } + if (argv[0] === 'status' && argv.length === 1) { + const result = readGitHubCoreRequestJournal(); + if (!result.enabled) fail('the core-request journal is not enabled'); + console.log(JSON.stringify(result)); + return; + } + fail('usage: github-core-request-journal.mts '); +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + try { + await main(process.argv.slice(2)); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/github-core-request-journal.test.mjs b/tools/release/github-core-request-journal.test.mjs deleted file mode 100644 index 73f6353c3..000000000 --- a/tools/release/github-core-request-journal.test.mjs +++ /dev/null @@ -1,89 +0,0 @@ -import { expect, test } from "bun:test"; -import { mkdtempSync, rmSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { - GITHUB_CORE_REQUEST_ROLLING_CEILING, - GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS, - readGitHubCoreRequestJournal, - reserveGitHubCoreRequestSync, -} from "./github-core-request-journal.mjs"; -import { runGitHubReadSync } from "./github-read.mjs"; - -function fixture() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-core-request-journal-")); - const environment = { - GITHUB_ACTIONS: "true", - GITHUB_REPOSITORY: "f0rr0/oliphaunt", - GITHUB_RUN_ATTEMPT: "1", - GITHUB_RUN_ID: "123", - GITHUB_SHA: "a".repeat(40), - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, "journal.json"), - }; - return { environment, root }; -} - -test("durable core-request journal refuses the operational ceiling before attempt 901", () => { - const { environment, root } = fixture(); - let nowMs = 10_000; - try { - for (let index = 0; index < GITHUB_CORE_REQUEST_ROLLING_CEILING; index += 1) { - const result = reserveGitHubCoreRequestSync({ - environment, - label: `attempt ${index + 1}`, - now: () => nowMs, - }); - expect(result.sequence).toBe(index + 1); - } - expect(readGitHubCoreRequestJournal({ environment, now: () => nowMs }).rollingCount).toBe(900); - expect(() => reserveGitHubCoreRequestSync({ - environment, - label: "attempt 901", - now: () => nowMs, - })).toThrow(/900 attempts already occupy the 60-minute safety window/u); - - nowMs += GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS + 1; - const admitted = reserveGitHubCoreRequestSync({ - environment, - label: "new rolling window", - now: () => nowMs, - }); - expect(admitted.sequence).toBe(901); - expect(admitted.rollingCount).toBe(1); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("every retried GitHub read attempt is durably reserved", () => { - const { environment, root } = fixture(); - let calls = 0; - try { - const output = runGitHubReadSync( - ["api", "repos/f0rr0/oliphaunt/releases/1"], - { - baseDelayMs: 0, - coreJournalOptions: { now: () => 20_000 }, - environment, - maxAttempts: 3, - maxDelayMs: 0, - now: () => 20_000, - spawn: () => { - calls += 1; - return calls < 3 - ? { status: 1, stderr: "temporary failure", stdout: "" } - : { status: 0, stderr: "", stdout: "{}" }; - }, - }, - ); - expect(output).toBe("{}"); - expect(calls).toBe(3); - expect(readGitHubCoreRequestJournal({ environment, now: () => 20_000 })).toMatchObject({ - rollingCount: 3, - sequence: 3, - }); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); diff --git a/tools/release/github-core-request-journal.test.mts b/tools/release/github-core-request-journal.test.mts new file mode 100644 index 000000000..b56dbf7e6 --- /dev/null +++ b/tools/release/github-core-request-journal.test.mts @@ -0,0 +1,125 @@ +import { expect, test } from 'bun:test'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +import { + GITHUB_CORE_REQUEST_ROLLING_CEILING, + GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS, + readGitHubCoreRequestJournal, + reserveGitHubCoreRequest, +} from './github-core-request-journal.mts'; +import { requestGithubRepositoryJson } from './github-read.mts'; + +function fixture() { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-core-request-journal-')); + const environment = { + GITHUB_ACTIONS: 'true', + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_RUN_ATTEMPT: '1', + GITHUB_RUN_ID: '123', + GITHUB_SHA: 'a'.repeat(40), + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, 'journal.json'), + }; + return { environment, root }; +} + +test('durable core-request journal refuses the operational ceiling before attempt 901', async () => { + const { environment, root } = fixture(); + let nowMs = 10_000; + try { + for (let index = 0; index < GITHUB_CORE_REQUEST_ROLLING_CEILING; index += 1) { + const result = await reserveGitHubCoreRequest({ + environment, + label: `attempt ${index + 1}`, + now: () => nowMs, + }); + expect(result.sequence).toBe(index + 1); + } + expect(readGitHubCoreRequestJournal({ environment, now: () => nowMs }).rollingCount).toBe(900); + await expect( + (async () => + await reserveGitHubCoreRequest({ + environment, + label: 'attempt 901', + now: () => nowMs, + }))(), + ).rejects.toThrow(/900 attempts already occupy the 60-minute safety window/u); + + nowMs += GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS + 1; + const admitted = await reserveGitHubCoreRequest({ + environment, + label: 'new rolling window', + now: () => nowMs, + }); + expect(admitted.sequence).toBe(901); + expect(admitted.rollingCount).toBe(1); + const state = JSON.parse( + readFileSync(environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH, 'utf8'), + ); + expect(state.attempts).toEqual([nowMs]); + } finally { + rmSync(root, { force: true, recursive: true }); + } +}); + +test('rolling timestamps preserve the boundary and reject clock reversal or corrupt lineage', async () => { + const { environment, root } = fixture(); + const file = environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH; + try { + await reserveGitHubCoreRequest({ environment, label: 'first', now: () => 1000 }); + const boundary = 1000 + GITHUB_CORE_REQUEST_ROLLING_WINDOW_MS; + expect(readGitHubCoreRequestJournal({ environment, now: () => boundary }).rollingCount).toBe(1); + expect( + readGitHubCoreRequestJournal({ environment, now: () => boundary + 1 }).rollingCount, + ).toBe(0); + await expect( + reserveGitHubCoreRequest({ environment, label: 'backwards', now: () => 999 }), + ).rejects.toThrow('clock moved backwards'); + const valid = readFileSync(file, 'utf8'); + for (const change of [ + { headSha: 'b'.repeat(40) }, + { attempts: [-1] }, + { attempts: [1001, 1000], sequence: 2 }, + { attempts: [], sequence: 1 }, + { sequence: Number.MAX_SAFE_INTEGER }, + ]) { + writeFileSync(file, JSON.stringify({ ...JSON.parse(valid), ...change })); + const before = readFileSync(file, 'utf8'); + await expect( + reserveGitHubCoreRequest({ environment, label: 'invalid', now: () => 2000 }), + ).rejects.toThrow(); + expect(readFileSync(file, 'utf8')).toBe(before); + } + } finally { + rmSync(root, { force: true, recursive: true }); + } +}); + +test('every retried GitHub read attempt is durably reserved', async () => { + const { environment, root } = fixture(); + let calls = 0; + try { + const output = await requestGithubRepositoryJson('repos/f0rr0/oliphaunt/releases/1', { + baseDelayMs: 0, + coreJournalOptions: { now: () => 20_000 }, + environment, + maxAttempts: 3, + maxDelayMs: 0, + now: () => 20_000, + sleep: () => {}, + fetchImpl: () => { + calls += 1; + return calls < 3 ? new Response('', { status: 503 }) : Response.json({}); + }, + }); + expect(output).toEqual({}); + expect(calls).toBe(3); + expect(readGitHubCoreRequestJournal({ environment, now: () => 20_000 })).toMatchObject({ + rollingCount: 3, + sequence: 3, + }); + } finally { + rmSync(root, { force: true, recursive: true }); + } +}); diff --git a/tools/release/github-read.mjs b/tools/release/github-read.mjs deleted file mode 100644 index 952e5cfe4..000000000 --- a/tools/release/github-read.mjs +++ /dev/null @@ -1,792 +0,0 @@ -#!/usr/bin/env node - -import path from "node:path"; -import process from "node:process"; -import { fileURLToPath } from "node:url"; - -import { reserveGitHubCoreRequestSync } from "./github-core-request-journal.mjs"; -import { captureCommandBytes, captureCommandOutput } from "../dev/capture-command-output.mjs"; - -const DEFAULTS = Object.freeze({ - attemptTimeoutMs: 45_000, - baseDelayMs: 750, - deadlineMs: 180_000, - maxAttempts: 4, - maxDelayMs: 8_000, -}); -const MAX_CAPTURE_BYTES = 128 * 1024 * 1024; -const GITHUB_PAGINATION_PAGE_SIZE = 100; -const GITHUB_PAGINATION_MAX_PAGES = 1_000; -const INTEGER = /^(?:0|[1-9][0-9]*)$/u; -const RETRYABLE_STATUS = new Set([408, 409, 425, 429, 500, 502, 503, 504]); -const RETRYABLE_TEXT = [ - /connection (?:closed|refused|reset|timed out)/iu, - /could not resolve host/iu, - /econn(?:refused|reset)/iu, - /http (?:408|409|425|429|5[0-9]{2})\b/iu, - /i\/o timeout/iu, - /rate limit/iu, - /remote end closed/iu, - /socket hang up/iu, - /temporary failure/iu, - /tls handshake timeout/iu, - /unexpected eof/iu, -]; -const PERMANENT_TEXT = [ - /bad credentials/iu, - /http (?:400|401|404|405|410|422)\b/iu, - /not found/iu, - /permission denied/iu, - /requires authentication/iu, - /resource not accessible by integration/iu, - /unknown (?:command|flag)/iu, - /usage:/iu, -]; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -export class GitHubReadError extends Error { - constructor(message, { attempts = 0, cause = undefined, deadlineExhausted = false, retryable = false } = {}) { - super(message, { cause }); - this.name = "GitHubReadError"; - this.attempts = attempts; - this.deadlineExhausted = deadlineExhausted; - this.retryable = retryable; - } -} - -export class RetryableReadError extends Error { - constructor(message, { cause = undefined } = {}) { - super(message, { cause }); - this.name = "RetryableReadError"; - this.retryable = true; - } -} - -function integerSetting(environment, name, fallback, { maximum = Number.MAX_SAFE_INTEGER, minimum = 0 } = {}) { - const raw = environment[name]; - if (raw === undefined || raw === "") return fallback; - if (!INTEGER.test(raw)) { - throw new GitHubReadError(`${name} must be an integer`); - } - const value = Number(raw); - if (!Number.isSafeInteger(value) || value < minimum || value > maximum) { - throw new GitHubReadError(`${name} must be between ${minimum} and ${maximum}`); - } - return value; -} - -export function githubReadOptionsFromEnv(environment = process.env, overrides = {}) { - const result = { - attemptTimeoutMs: integerSetting( - environment, - "OLIPHAUNT_GITHUB_READ_ATTEMPT_TIMEOUT_MS", - DEFAULTS.attemptTimeoutMs, - { maximum: 10 * 60_000, minimum: 1 }, - ), - baseDelayMs: integerSetting( - environment, - "OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS", - DEFAULTS.baseDelayMs, - { maximum: 30_000 }, - ), - deadlineMs: integerSetting( - environment, - "OLIPHAUNT_GITHUB_READ_DEADLINE_MS", - DEFAULTS.deadlineMs, - { maximum: 60 * 60_000, minimum: 1 }, - ), - maxAttempts: integerSetting( - environment, - "OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS", - DEFAULTS.maxAttempts, - { maximum: 10, minimum: 1 }, - ), - maxDelayMs: integerSetting( - environment, - "OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS", - DEFAULTS.maxDelayMs, - { maximum: 60_000 }, - ), - ...overrides, - }; - for (const [name, value, minimum, maximum] of [ - ["attemptTimeoutMs", result.attemptTimeoutMs, 1, 10 * 60_000], - ["baseDelayMs", result.baseDelayMs, 0, 30_000], - ["deadlineMs", result.deadlineMs, 1, 60 * 60_000], - ["maxAttempts", result.maxAttempts, 1, 10], - ["maxDelayMs", result.maxDelayMs, 0, 60_000], - ]) { - if (!Number.isSafeInteger(value) || value < minimum || value > maximum) { - throw new GitHubReadError(`${name} must be between ${minimum} and ${maximum}`); - } - } - if (result.maxDelayMs < result.baseDelayMs) { - throw new GitHubReadError( - "OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS must be at least OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS", - ); - } - return result; -} - -function sleepSync(milliseconds) { - if (milliseconds <= 0) return; - const cell = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)); - Atomics.wait(cell, 0, 0, milliseconds); -} - -function renderedError(error) { - if (error instanceof Error) { - const detail = error.detail ? `${error.message}\n${error.detail}` : error.message; - return detail; - } - return String(error); -} - -export function redactGitHubReadDetail(value, environment = process.env) { - let result = String(value ?? ""); - for (const name of ["GH_TOKEN", "GITHUB_TOKEN"]) { - const secret = environment[name]; - if (secret) result = result.split(secret).join(""); - } - result = result - .replace(/(authorization\s*:\s*)(?:bearer|token)\s+[^\s]+/giu, "$1") - .replace(/([?&](?:access_?token|auth|token)=)[^&#\s]+/giu, "$1") - .replace(/https:\/\/[^/@\s]+@/giu, "https://@") - .replace(/\b(?:gh[opusr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})\b/gu, "") - .trim(); - if (result.length > 800) result = `${result.slice(0, 797)}...`; - return result; -} - -function statusFromText(text) { - const match = /(?:http(?: status)?|status code)\s*[:=]?\s*([1-5][0-9]{2})\b/iu.exec(text); - return match ? Number(match[1]) : undefined; -} - -export function isRetryableGitHubReadError(error) { - if (typeof error?.retryable === "boolean") return error.retryable; - if (["ETIMEDOUT", "ECONNRESET", "ECONNREFUSED", "EAI_AGAIN"].includes(error?.code)) return true; - if ([2, 126, 127].includes(error?.status)) return false; - const text = renderedError(error); - const status = error?.httpStatus ?? statusFromText(text); - if (status !== undefined) { - if (status === 403 && /(?:abuse|rate limit|secondary rate)/iu.test(text)) return true; - if (RETRYABLE_STATUS.has(status)) return true; - if (status >= 400 && status < 500) return false; - } - if (PERMANENT_TEXT.some((pattern) => pattern.test(text))) return false; - if (RETRYABLE_TEXT.some((pattern) => pattern.test(text))) return true; - // Reads are idempotent. Unknown transport/CLI exit-1 failures are retried inside the fixed budget. - return true; -} - -function retryDelay(attempt, { baseDelayMs, maxDelayMs, random }) { - const exponential = Math.min(maxDelayMs, baseDelayMs * (2 ** Math.max(0, attempt - 1))); - const jitter = 0.8 + (Math.max(0, Math.min(1, random())) * 0.4); - return Math.round(exponential * jitter); -} - -export function retryReadOperationSync(label, operation, options = {}) { - if (typeof label !== "string" || label.trim() === "") { - throw new GitHubReadError("GitHub read label is required"); - } - if (typeof operation !== "function") { - throw new GitHubReadError(`${label}: read operation must be a function`); - } - const settings = githubReadOptionsFromEnv(options.environment ?? process.env, options); - const now = settings.now ?? Date.now; - const random = settings.random ?? Math.random; - const sleep = settings.sleep ?? sleepSync; - const classify = settings.classify ?? isRetryableGitHubReadError; - const onRetry = settings.onRetry ?? (() => {}); - const startedAt = now(); - const deadline = startedAt + settings.deadlineMs; - let attempts = 0; - let lastError; - - while (attempts < settings.maxAttempts) { - const remainingMs = deadline - now(); - if (remainingMs <= 0) { - throw new GitHubReadError(`${label}: overall deadline exhausted after ${attempts} attempt(s)`, { - attempts, - cause: lastError, - deadlineExhausted: true, - retryable: true, - }); - } - attempts += 1; - try { - return operation({ - attempt: attempts, - attemptTimeoutMs: Math.max(1, Math.min(settings.attemptTimeoutMs, remainingMs)), - deadlineMs: deadline, - remainingMs, - remainingTimeMs: () => deadline - now(), - }); - } catch (error) { - lastError = error; - const retryable = classify(error); - const safeDetail = redactGitHubReadDetail(renderedError(error), settings.environment); - if (!retryable) { - throw new GitHubReadError( - `${label}: permanent read failure on attempt ${attempts}${safeDetail ? `: ${safeDetail}` : ""}`, - { attempts, cause: error, retryable: false }, - ); - } - if (error?.deadlineExhausted === true) { - throw new GitHubReadError(`${label}: overall deadline exhausted after ${attempts} attempt(s)`, { - attempts, - cause: error, - deadlineExhausted: true, - retryable: true, - }); - } - if (attempts >= settings.maxAttempts) { - throw new GitHubReadError( - `${label}: retry budget exhausted after ${attempts} attempt(s)${safeDetail ? `: ${safeDetail}` : ""}`, - { attempts, cause: error, retryable: true }, - ); - } - const delay = retryDelay(attempts, { ...settings, random }); - const beforeSleepRemaining = deadline - now(); - if (beforeSleepRemaining <= delay) { - throw new GitHubReadError(`${label}: overall deadline exhausted after ${attempts} attempt(s)`, { - attempts, - cause: error, - deadlineExhausted: true, - retryable: true, - }); - } - onRetry({ attempt: attempts, delayMs: delay, error, label }); - sleep(delay); - } - } - throw new GitHubReadError(`${label}: retry budget exhausted`, { - attempts, - cause: lastError, - retryable: true, - }); -} - -function ensureSafeApiReadArgs(args) { - let endpoint = null; - for (let index = 1; index < args.length; index += 1) { - const arg = args[index]; - if (arg === "--include") continue; - if (arg === "--paginate" || arg === "--slurp") { - throw new GitHubReadError( - `GitHub read helper refuses opaque ${arg} requests; use the journal-aware pagination helper`, - ); - } - if (arg === "--jq" || arg === "-q" || arg === "--header" || arg === "-H") { - const value = args[index + 1]; - if (value === undefined) { - throw new GitHubReadError(`GitHub API read flag ${arg} requires a value`); - } - if (arg === "--header" || arg === "-H") { - if (!new Set([ - "Accept: application/octet-stream", - "Accept: application/vnd.github+json", - "X-GitHub-Api-Version: 2022-11-28", - ]).has(value)) { - throw new GitHubReadError("GitHub API read helper refuses non-canonical headers"); - } - } - index += 1; - continue; - } - if (arg.startsWith("--jq=") || arg.startsWith("-q=")) continue; - if (arg.startsWith("-")) { - throw new GitHubReadError(`GitHub API read helper refuses unsupported flag ${arg}`); - } - if (endpoint !== null) { - throw new GitHubReadError("GitHub API read helper requires exactly one endpoint"); - } - endpoint = arg; - } - if (endpoint === null) { - throw new GitHubReadError("GitHub API read helper requires exactly one endpoint"); - } - const relative = endpoint.startsWith("repos/") - ? endpoint - : endpoint.startsWith("https://api.github.com/repos/") - ? endpoint.slice("https://api.github.com/".length) - : null; - if ( - relative === null - || !/^repos\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+(?:[/?][^\s\\\u0000-\u001f\u007f]*)?$/u.test(relative) - ) { - throw new GitHubReadError("GitHub API read endpoint is outside the repository allowlist"); - } - let decoded; - try { - decoded = decodeURIComponent(relative.split("?", 1)[0]); - } catch (error) { - throw new GitHubReadError("GitHub API read endpoint contains malformed encoding", { cause: error }); - } - if (decoded.split("/").some((segment) => segment === "." || segment === "..")) { - throw new GitHubReadError("GitHub API read endpoint contains a traversal segment"); - } -} - -function ensureReadOnlyGhArgs(args) { - if (!Array.isArray(args) || args.length < 2 || args.some((arg) => typeof arg !== "string")) { - throw new GitHubReadError("GitHub read command requires gh arguments"); - } - const [group, verb] = args; - if (group === "api") { - const mutationFlags = /^(?:--field(?:=|$)|--input(?:=|$)|--method(?:=|$)|--raw-field(?:=|$)|-[FfX](?:.|$))/u; - if (args.some((arg) => mutationFlags.test(arg))) { - throw new GitHubReadError("GitHub read helper refuses API mutation arguments"); - } - if (verb === "graphql") { - throw new GitHubReadError("GitHub read helper refuses implicit POST GraphQL requests"); - } - ensureSafeApiReadArgs(args); - return; - } - const allowed = new Set(["release:download", "release:view", "run:download", "run:list", "run:view"]); - if (!allowed.has(`${group}:${verb}`)) { - throw new GitHubReadError(`GitHub read helper refuses non-read command gh ${group} ${verb}`); - } - if (args.some((arg) => /^(?:--hostname|--web)(?:=|$)/u.test(arg))) { - throw new GitHubReadError("GitHub read helper refuses alternate hosts and browser side effects"); - } -} - -class CommandReadError extends Error { - constructor(message, { code, detail, httpStatus, retryable, status } = {}) { - super(message); - this.name = "CommandReadError"; - this.code = code; - this.detail = detail; - this.httpStatus = httpStatus; - this.retryable = retryable; - this.status = status; - } -} - -function runGitHubCommandReadSync(args, options = {}) { - const environment = options.environment ?? process.env; - const label = options.label ?? `GitHub ${args[0]} ${args[1]} read`; - const binary = options.binary === true; - const maxBuffer = options.maxBuffer ?? MAX_CAPTURE_BYTES; - if (!Number.isSafeInteger(maxBuffer) || maxBuffer < 1 || maxBuffer > MAX_CAPTURE_BYTES) { - throw new GitHubReadError(`GitHub read maxBuffer must be between 1 and ${MAX_CAPTURE_BYTES}`); - } - return retryReadOperationSync( - label, - ({ attemptTimeoutMs, remainingTimeMs }) => { - reserveGitHubCoreRequestSync({ - environment, - label: `${label} attempt`, - ...(options.coreJournalOptions ?? {}), - }); - const remainingAfterJournalMs = remainingTimeMs(); - if (remainingAfterJournalMs <= 0) { - const error = new RetryableReadError( - `${label}: overall deadline exhausted during request-journal admission`, - ); - error.deadlineExhausted = true; - throw error; - } - const transportTimeoutMs = Math.max(1, Math.min(attemptTimeoutMs, remainingAfterJournalMs)); - const result = options.spawn === undefined - ? (binary ? captureCommandBytes : captureCommandOutput)("gh", args, { - cwd: options.cwd, - env: environment, - label, - maxOutputBytes: maxBuffer, - timeout: transportTimeoutMs, - windowsHide: true, - }) - : options.spawn("gh", args, { - cwd: options.cwd, - encoding: binary ? null : "utf8", - env: environment, - maxBuffer, - stdio: ["ignore", "pipe", "pipe"], - timeout: transportTimeoutMs, - windowsHide: true, - }); - if (result.error) { - throw new CommandReadError("GitHub CLI could not complete the read", { - code: result.error.code, - detail: result.error.message, - status: result.status, - }); - } - if (result.status !== 0) { - const stderr = Buffer.isBuffer(result.stderr) - ? result.stderr.toString("utf8") - : String(result.stderr ?? ""); - throw new CommandReadError("GitHub CLI read failed", { - detail: stderr, - status: result.status, - }); - } - return result.stdout ?? (binary ? Buffer.alloc(0) : ""); - }, - { ...options, environment }, - ); -} - -export function runGitHubReadSync(args, options = {}) { - ensureReadOnlyGhArgs(args); - return runGitHubCommandReadSync(args, options); -} - -function assertSafeGraphqlQuery(document) { - if (typeof document !== "string" || document.length === 0 || document.length > 32 * 1024) { - throw new GitHubReadError("GitHub GraphQL read requires one bounded query document"); - } - if (/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u.test(document)) { - throw new GitHubReadError("GitHub GraphQL query contains unsupported control characters"); - } - const normalized = document.trim(); - const operations = [...normalized.matchAll(/\b(query|mutation|subscription)\b/gu)]; - if ( - operations.length !== 1 - || operations[0][1] !== "query" - || !/^query\s+[A-Za-z_][A-Za-z0-9_]*(?:\s*\([^)]*\))?\s*\{[\s\S]*\}$/u.test(normalized) - || /["'`#]/u.test(normalized) - ) { - throw new GitHubReadError("GitHub GraphQL read requires exactly one named query operation"); - } - let depth = 0; - for (const character of normalized) { - if (character === "{") depth += 1; - else if (character === "}") depth -= 1; - if (depth < 0) break; - } - if (depth !== 0) { - throw new GitHubReadError("GitHub GraphQL query has unbalanced selection braces"); - } -} - -function graphqlVariableArguments(variables) { - if ( - variables === null - || typeof variables !== "object" - || Array.isArray(variables) - || ![Object.prototype, null].includes(Object.getPrototypeOf(variables)) - ) { - throw new GitHubReadError("GitHub GraphQL variables must be a plain object"); - } - const args = []; - for (const name of Object.keys(variables).sort()) { - const value = variables[name]; - if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(name)) { - throw new GitHubReadError(`GitHub GraphQL variable name is invalid: ${name}`); - } - if ( - typeof value !== "string" - || value.length > 4_096 - || /[\u0000-\u001f\u007f]/u.test(value) - ) { - throw new GitHubReadError(`GitHub GraphQL variable ${name} must be a bounded printable string`); - } - args.push("-f", `${name}=${value}`); - } - return args; -} - -export function runGitHubGraphqlReadSync(document, variables = {}, options = {}) { - assertSafeGraphqlQuery(document); - const variableArgs = graphqlVariableArguments(variables); - return runGitHubCommandReadSync( - ["api", "graphql", "-f", `query=${document}`, ...variableArgs], - { ...options, label: options.label ?? "GitHub GraphQL read" }, - ); -} - -function parseIncludedGithubJson(output, label) { - if (typeof output !== "string") { - throw new GitHubReadError(`${label} returned a non-text included response`); - } - const boundary = /\r?\n\r?\n/u.exec(output); - if (boundary === null || boundary.index === 0) { - throw new GitHubReadError(`${label} did not include one HTTP response header block`); - } - const headerBlock = output.slice(0, boundary.index); - const body = output.slice(boundary.index + boundary[0].length); - const lines = headerBlock.split(/\r?\n/u); - if (!/^HTTP\/(?:1[.][01]|2(?:[.]0)?|3(?:[.]0)?) 200(?:\s|$)/u.test(lines[0] ?? "")) { - throw new GitHubReadError(`${label} did not include an HTTP 200 status line`); - } - const headers = new Map(); - for (const line of lines.slice(1)) { - if (/^[ \t]/u.test(line)) { - throw new GitHubReadError(`${label} returned an obsolete folded HTTP header`); - } - const separator = line.indexOf(":"); - if (separator <= 0) throw new GitHubReadError(`${label} returned a malformed HTTP header`); - const name = line.slice(0, separator).trim().toLowerCase(); - const value = line.slice(separator + 1).trim(); - if (!/^[a-z0-9-]+$/u.test(name) || /[\u0000-\u001f\u007f]/u.test(value)) { - throw new GitHubReadError(`${label} returned a malformed HTTP header`); - } - headers.set(name, headers.has(name) ? `${headers.get(name)}, ${value}` : value); - } - let data; - try { - data = JSON.parse(body); - } catch (cause) { - throw new GitHubReadError(`${label} returned malformed JSON`, { cause }); - } - return { data, link: headers.get("link") ?? "" }; -} - -function parseGithubPaginationLinks(value, label) { - if (value === "") return new Map(); - const links = new Map(); - for (const rawEntry of value.split(/,\s*(?=<)/u)) { - const match = /^<([^<>]+)>;\s*rel="(first|last|next|prev)"$/u.exec(rawEntry.trim()); - if (match === null || links.has(match[2])) { - throw new GitHubReadError(`${label} returned a malformed or duplicate pagination Link relation`); - } - links.set(match[2], match[1]); - } - return links; -} - -function escapedRegex(value) { - return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"); -} - -function exactQueryEntries(url, label) { - const entries = [...url.searchParams.entries()]; - if (new Set(entries.map(([name]) => name)).size !== entries.length) { - throw new GitHubReadError(`${label} contains a duplicate query parameter`); - } - return entries.sort(([leftName, leftValue], [rightName, rightValue]) => - compareText(leftName, rightName) || compareText(leftValue, rightValue)); -} - -function paginationEndpoint(endpoint) { - if (typeof endpoint !== "string" || !endpoint.startsWith("repos/")) { - throw new GitHubReadError("journal-aware pagination requires a repository API endpoint"); - } - ensureSafeApiReadArgs(["api", endpoint]); - const url = new URL(endpoint, "https://api.github.com/"); - if (url.origin !== "https://api.github.com" || url.hash !== "") { - throw new GitHubReadError("journal-aware pagination requires the canonical GitHub API origin"); - } - const match = /^\/repos\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)\/(.+)$/u.exec(url.pathname); - if (match === null || match[3].endsWith("/")) { - throw new GitHubReadError("journal-aware pagination endpoint must name one repository resource"); - } - const fixedQuery = exactQueryEntries(url, "journal-aware pagination endpoint"); - if (fixedQuery.some(([name]) => name === "page" || name === "per_page")) { - throw new GitHubReadError("journal-aware pagination owns the page and per_page parameters"); - } - return { - fixedQuery, - owner: match[1], - repo: match[2], - requestedPath: url.pathname, - resource: match[3], - }; -} - -function validateGithubPaginationLink(rawUrl, expected, relation, currentPage, canonicalRepositoryPath) { - let url; - try { - url = new URL(rawUrl); - } catch (cause) { - throw new GitHubReadError(`${expected.label} returned a malformed pagination URL`, { cause }); - } - if ( - url.protocol !== "https:" - || url.hostname !== "api.github.com" - || url.port !== "" - || url.username !== "" - || url.password !== "" - || url.hash !== "" - ) { - throw new GitHubReadError(`${expected.label} pagination URL must use the canonical GitHub API origin`); - } - const canonicalMatch = new RegExp( - `^/repositories/([1-9][0-9]*)/${escapedRegex(expected.resource)}$`, - "u", - ).exec(url.pathname); - if (url.pathname !== expected.requestedPath && canonicalMatch === null) { - throw new GitHubReadError(`${expected.label} pagination URL changed repository or endpoint`); - } - let nextCanonicalPath = canonicalRepositoryPath; - if (canonicalMatch !== null) { - if (canonicalRepositoryPath !== null && url.pathname !== canonicalRepositoryPath) { - throw new GitHubReadError(`${expected.label} pagination URL changed canonical repository identity`); - } - nextCanonicalPath = url.pathname; - } - const pageValue = url.searchParams.get("page"); - if (!/^[1-9][0-9]*$/u.test(pageValue ?? "")) { - throw new GitHubReadError(`${expected.label} pagination URL has an invalid page number`); - } - const linkedPage = Number(pageValue); - if (!Number.isSafeInteger(linkedPage)) { - throw new GitHubReadError(`${expected.label} pagination page exceeds the safe integer range`); - } - const wantedPage = relation === "next" - ? currentPage + 1 - : relation === "prev" - ? currentPage - 1 - : relation === "first" - ? 1 - : linkedPage; - if (linkedPage !== wantedPage || (relation === "last" && linkedPage < currentPage)) { - throw new GitHubReadError(`${expected.label} returned a non-canonical ${relation} page number`); - } - const actualQuery = exactQueryEntries(url, `${expected.label} pagination URL`); - const expectedQuery = [ - ...expected.fixedQuery, - ["page", String(linkedPage)], - ["per_page", String(GITHUB_PAGINATION_PAGE_SIZE)], - ].sort(([leftName, leftValue], [rightName, rightValue]) => - compareText(leftName, rightName) || compareText(leftValue, rightValue)); - if (JSON.stringify(actualQuery) !== JSON.stringify(expectedQuery)) { - throw new GitHubReadError(`${expected.label} pagination URL changed the exact page query`); - } - return nextCanonicalPath; -} - -export function runGitHubPaginatedJsonSync(endpoint, options = {}) { - const expected = paginationEndpoint(endpoint); - const label = options.label ?? "GitHub paginated JSON read"; - const itemsField = options.itemsField ?? null; - const maxPages = options.maxPages ?? GITHUB_PAGINATION_MAX_PAGES; - const settings = githubReadOptionsFromEnv(options.environment ?? process.env, options); - const now = settings.now ?? Date.now; - const paginationStartedAtMs = now(); - const paginationDeadlineMs = paginationStartedAtMs + settings.deadlineMs; - if (!Number.isSafeInteger(paginationDeadlineMs)) { - throw new GitHubReadError(`${label} pagination deadline exceeds the safe timestamp range`); - } - if (!Number.isSafeInteger(maxPages) || maxPages < 1 || maxPages > GITHUB_PAGINATION_MAX_PAGES) { - throw new GitHubReadError(`paginated JSON maxPages must be between 1 and ${GITHUB_PAGINATION_MAX_PAGES}`); - } - if (itemsField !== null && (typeof itemsField !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(itemsField))) { - throw new GitHubReadError("paginated JSON itemsField must be null or a safe object field name"); - } - const rows = []; - let canonicalRepositoryPath = null; - for (let page = 1; page <= maxPages; page += 1) { - const query = new URLSearchParams(expected.fixedQuery); - query.set("per_page", String(GITHUB_PAGINATION_PAGE_SIZE)); - query.set("page", String(page)); - const pageEndpoint = `${expected.requestedPath.slice(1)}?${query.toString()}`; - const pageLabel = `${label} page ${page}`; - const pageStartedAtMs = now(); - const remainingPaginationMs = paginationDeadlineMs - pageStartedAtMs; - if (remainingPaginationMs <= 0) { - throw new GitHubReadError(`${label}: pagination deadline exhausted before page ${page}`, { - deadlineExhausted: true, - retryable: true, - }); - } - let pageClockAnchored = false; - const pageNow = () => { - if (!pageClockAnchored) { - pageClockAnchored = true; - return pageStartedAtMs; - } - return now(); - }; - const { data, link } = parseIncludedGithubJson( - runGitHubReadSync( - ["api", "--include", pageEndpoint], - { - ...options, - deadlineMs: remainingPaginationMs, - label: pageLabel, - now: pageNow, - }, - ), - pageLabel, - ); - const pageRows = itemsField === null - ? data - : data !== null && !Array.isArray(data) && typeof data === "object" - ? data[itemsField] - : undefined; - if (!Array.isArray(pageRows) || pageRows.length > GITHUB_PAGINATION_PAGE_SIZE) { - throw new GitHubReadError( - `${pageLabel} must contain an array of at most ${GITHUB_PAGINATION_PAGE_SIZE} rows` - + (itemsField === null ? "" : ` in ${itemsField}`), - ); - } - rows.push(...pageRows); - const links = parseGithubPaginationLinks(link, pageLabel); - for (const [relation, rawUrl] of links) { - canonicalRepositoryPath = validateGithubPaginationLink( - rawUrl, - { ...expected, label: pageLabel }, - relation, - page, - canonicalRepositoryPath, - ); - } - if (!links.has("next")) return rows; - if (pageRows.length !== GITHUB_PAGINATION_PAGE_SIZE) { - throw new GitHubReadError(`${pageLabel} advertised a next page after only ${pageRows.length} rows`); - } - } - throw new GitHubReadError(`${label} exceeds ${maxPages} pages`); -} - -function cli(argv) { - let label = "GitHub CLI read"; - let binary = false; - let paginateField; - let index = 0; - while (index < argv.length && argv[index] !== "--" && argv[index].startsWith("--")) { - if (argv[index] === "--label") { - label = argv[index + 1] ?? ""; - index += 2; - } else if (argv[index] === "--binary") { - binary = true; - index += 1; - } else if (argv[index] === "--paginate-field") { - paginateField = argv[index + 1]; - if (paginateField === undefined || paginateField === "") { - throw new GitHubReadError("--paginate-field requires a field name or - for a top-level array"); - } - index += 2; - } else { - throw new GitHubReadError(`unknown github-read option: ${argv[index]}`); - } - } - if (argv[index] === "--") index += 1; - if (paginateField !== undefined) { - if (binary || argv.length - index !== 1) { - throw new GitHubReadError("journal-aware pagination requires exactly one non-binary API endpoint"); - } - const output = runGitHubPaginatedJsonSync(argv[index], { - itemsField: paginateField === "-" ? null : paginateField, - label, - }); - process.stdout.write(`${JSON.stringify(output)}\n`); - return; - } - const output = runGitHubReadSync(argv.slice(index), { - binary, - label, - onRetry: ({ attempt, delayMs }) => { - console.error(`${label}: transient failure after attempt ${attempt}; retrying in ${delayMs}ms`); - }, - }); - process.stdout.write(output); -} - -if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) { - try { - cli(process.argv.slice(2)); - } catch (error) { - console.error(redactGitHubReadDetail(error instanceof Error ? error.message : String(error))); - process.exit(error?.retryable ? 75 : 64); - } -} diff --git a/tools/release/github-read.mts b/tools/release/github-read.mts new file mode 100644 index 000000000..6994adf2e --- /dev/null +++ b/tools/release/github-read.mts @@ -0,0 +1,1003 @@ +#!/usr/bin/env bun + +import path from 'node:path'; +import process from 'node:process'; +import { setTimeout as sleep } from 'node:timers/promises'; +import { fileURLToPath } from 'node:url'; +import { reserveGitHubCoreRequest } from './github-core-request-journal.mts'; + +const DEFAULTS = Object.freeze({ + attemptTimeoutMs: 45_000, + baseDelayMs: 750, + deadlineMs: 180_000, + maxAttempts: 4, + maxDelayMs: 8_000, +}); +const GITHUB_PAGINATION_PAGE_SIZE = 100; +const GITHUB_PAGINATION_MAX_PAGES = 1_000; +const INTEGER = /^(?:0|[1-9][0-9]*)$/u; +const RETRYABLE_STATUS = new Set([408, 409, 425, 429, 500, 502, 503, 504]); +const RETRYABLE_TEXT = [ + /connection (?:closed|refused|reset|timed out)/iu, + /could not resolve host/iu, + /econn(?:refused|reset)/iu, + /http (?:408|409|425|429|5[0-9]{2})\b/iu, + /i\/o timeout/iu, + /rate limit/iu, + /remote end closed/iu, + /socket hang up/iu, + /temporary failure/iu, + /tls handshake timeout/iu, + /unexpected eof/iu, +]; +const PERMANENT_TEXT = [ + /bad credentials/iu, + /http (?:400|401|404|405|410|422)\b/iu, + /not found/iu, + /permission denied/iu, + /requires authentication/iu, + /resource not accessible by integration/iu, + /unknown (?:command|flag)/iu, + /usage:/iu, +]; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +export class GitHubReadError extends Error { + constructor( + message, + { attempts = 0, cause = undefined, deadlineExhausted = false, retryable = false } = {}, + ) { + super(message, { cause }); + this.name = 'GitHubReadError'; + this.attempts = attempts; + this.deadlineExhausted = deadlineExhausted; + this.retryable = retryable; + } +} + +export class RetryableReadError extends Error { + constructor(message, { cause = undefined } = {}) { + super(message, { cause }); + this.name = 'RetryableReadError'; + this.retryable = true; + } +} + +function integerSetting( + environment, + name, + fallback, + { maximum = Number.MAX_SAFE_INTEGER, minimum = 0 } = {}, +) { + const raw = environment[name]; + if (raw === undefined || raw === '') return fallback; + if (!INTEGER.test(raw)) { + throw new GitHubReadError(`${name} must be an integer`); + } + const value = Number(raw); + if (!Number.isSafeInteger(value) || value < minimum || value > maximum) { + throw new GitHubReadError(`${name} must be between ${minimum} and ${maximum}`); + } + return value; +} + +export function githubReadOptionsFromEnv(environment = process.env, overrides = {}) { + const result = { + attemptTimeoutMs: integerSetting( + environment, + 'OLIPHAUNT_GITHUB_READ_ATTEMPT_TIMEOUT_MS', + DEFAULTS.attemptTimeoutMs, + { maximum: 10 * 60_000, minimum: 1 }, + ), + baseDelayMs: integerSetting( + environment, + 'OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS', + DEFAULTS.baseDelayMs, + { maximum: 30_000 }, + ), + deadlineMs: integerSetting( + environment, + 'OLIPHAUNT_GITHUB_READ_DEADLINE_MS', + DEFAULTS.deadlineMs, + { maximum: 60 * 60_000, minimum: 1 }, + ), + maxAttempts: integerSetting( + environment, + 'OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS', + DEFAULTS.maxAttempts, + { maximum: 10, minimum: 1 }, + ), + maxDelayMs: integerSetting( + environment, + 'OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS', + DEFAULTS.maxDelayMs, + { maximum: 60_000 }, + ), + ...overrides, + }; + for (const [name, value, minimum, maximum] of [ + ['attemptTimeoutMs', result.attemptTimeoutMs, 1, 10 * 60_000], + ['baseDelayMs', result.baseDelayMs, 0, 30_000], + ['deadlineMs', result.deadlineMs, 1, 60 * 60_000], + ['maxAttempts', result.maxAttempts, 1, 10], + ['maxDelayMs', result.maxDelayMs, 0, 60_000], + ]) { + if (!Number.isSafeInteger(value) || value < minimum || value > maximum) { + throw new GitHubReadError(`${name} must be between ${minimum} and ${maximum}`); + } + } + if (result.maxDelayMs < result.baseDelayMs) { + throw new GitHubReadError( + 'OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS must be at least OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS', + ); + } + return result; +} + +function renderedError(error) { + if (error instanceof Error) { + const detail = error.detail ? `${error.message}\n${error.detail}` : error.message; + return detail; + } + return String(error); +} + +export function redactGitHubReadDetail(value, environment = process.env) { + let result = String(value ?? ''); + for (const name of ['GH_TOKEN', 'GITHUB_TOKEN']) { + const secret = environment[name]; + if (secret) result = result.split(secret).join(''); + } + result = result + .replace(/(authorization\s*:\s*)(?:bearer|token)\s+[^\s]+/giu, '$1') + .replace(/([?&](?:access_?token|auth|token)=)[^&#\s]+/giu, '$1') + .replace(/https:\/\/[^/@\s]+@/giu, 'https://@') + .replace(/\b(?:gh[opusr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})\b/gu, '') + .trim(); + if (result.length > 800) result = `${result.slice(0, 797)}...`; + return result; +} + +function statusFromText(text) { + const match = /(?:http(?: status)?|status code)\s*[:=]?\s*([1-5][0-9]{2})\b/iu.exec(text); + return match ? Number(match[1]) : undefined; +} + +export function isRetryableGitHubReadError(error) { + if (typeof error?.retryable === 'boolean') return error.retryable; + if (['ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED', 'EAI_AGAIN'].includes(error?.code)) return true; + if ([2, 126, 127].includes(error?.status)) return false; + const text = renderedError(error); + const status = error?.httpStatus ?? statusFromText(text); + if (status !== undefined) { + if (status === 403 && /(?:abuse|rate limit|secondary rate)/iu.test(text)) return true; + if (RETRYABLE_STATUS.has(status)) return true; + if (status >= 400 && status < 500) return false; + } + if (PERMANENT_TEXT.some((pattern) => pattern.test(text))) return false; + if (RETRYABLE_TEXT.some((pattern) => pattern.test(text))) return true; + // Reads are idempotent. Unknown transport/CLI exit-1 failures are retried inside the fixed budget. + return true; +} + +function retryDelay(attempt, { baseDelayMs, maxDelayMs, random }) { + const exponential = Math.min(maxDelayMs, baseDelayMs * 2 ** Math.max(0, attempt - 1)); + const jitter = 0.8 + Math.max(0, Math.min(1, random())) * 0.4; + return Math.round(exponential * jitter); +} + +export async function retryReadOperation(label, operation, options = {}) { + if (typeof label !== 'string' || label.trim() === '') { + throw new GitHubReadError('GitHub read label is required'); + } + if (typeof operation !== 'function') { + throw new GitHubReadError(`${label}: read operation must be a function`); + } + const settings = githubReadOptionsFromEnv(options.environment ?? process.env, options); + const now = settings.now ?? Date.now; + const random = settings.random ?? Math.random; + const wait = settings.sleep ?? sleep; + const classify = settings.classify ?? isRetryableGitHubReadError; + const onRetry = settings.onRetry ?? (() => {}); + const startedAt = now(); + const deadline = startedAt + settings.deadlineMs; + let attempts = 0; + let lastError; + + while (attempts < settings.maxAttempts) { + const remainingMs = deadline - now(); + if (remainingMs <= 0) { + throw new GitHubReadError( + `${label}: overall deadline exhausted after ${attempts} attempt(s)`, + { + attempts, + cause: lastError, + deadlineExhausted: true, + retryable: true, + }, + ); + } + attempts += 1; + try { + return await operation({ + attempt: attempts, + attemptTimeoutMs: Math.max(1, Math.min(settings.attemptTimeoutMs, remainingMs)), + deadlineMs: deadline, + remainingMs, + remainingTimeMs: () => deadline - now(), + }); + } catch (error) { + lastError = error; + const retryable = classify(error); + const safeDetail = redactGitHubReadDetail(renderedError(error), settings.environment); + if (!retryable) { + throw new GitHubReadError( + `${label}: permanent read failure on attempt ${attempts}${safeDetail ? `: ${safeDetail}` : ''}`, + { attempts, cause: error, retryable: false }, + ); + } + if (error?.deadlineExhausted === true) { + throw new GitHubReadError( + `${label}: overall deadline exhausted after ${attempts} attempt(s)`, + { + attempts, + cause: error, + deadlineExhausted: true, + retryable: true, + }, + ); + } + if (attempts >= settings.maxAttempts) { + throw new GitHubReadError( + `${label}: retry budget exhausted after ${attempts} attempt(s)${safeDetail ? `: ${safeDetail}` : ''}`, + { attempts, cause: error, retryable: true }, + ); + } + const delay = retryDelay(attempts, { ...settings, random }); + const beforeSleepRemaining = deadline - now(); + if (beforeSleepRemaining <= delay) { + throw new GitHubReadError( + `${label}: overall deadline exhausted after ${attempts} attempt(s)`, + { + attempts, + cause: error, + deadlineExhausted: true, + retryable: true, + }, + ); + } + onRetry({ attempt: attempts, delayMs: delay, error, label }); + await wait(delay); + } + } + throw new GitHubReadError(`${label}: retry budget exhausted`, { + attempts, + cause: lastError, + retryable: true, + }); +} + +function validateGithubEndpoint(endpoint) { + if (typeof endpoint !== 'string') + throw new GitHubReadError('GitHub API endpoint must be a string'); + const relative = endpoint.startsWith('repos/') + ? endpoint + : endpoint.startsWith('https://api.github.com/repos/') + ? endpoint.slice('https://api.github.com/'.length) + : null; + if ( + relative === null || + endpoint.includes('#') || + !/^repos\/[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+(?:[/?][^\s\\\u0000-\u001f\u007f]*)?$/u.test(relative) + ) { + throw new GitHubReadError('GitHub API read endpoint is outside the repository allowlist'); + } + let decoded; + try { + decoded = decodeURIComponent(relative.split('?', 1)[0]); + } catch (error) { + throw new GitHubReadError('GitHub API read endpoint contains malformed encoding', { + cause: error, + }); + } + if (decoded.split('/').some((segment) => segment === '.' || segment === '..')) { + throw new GitHubReadError('GitHub API read endpoint contains a traversal segment'); + } +} + +function assertSafeGraphqlQuery(document) { + if (typeof document !== 'string' || document.length === 0 || document.length > 32 * 1024) { + throw new GitHubReadError('GitHub GraphQL read requires one bounded query document'); + } + if (/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u.test(document)) { + throw new GitHubReadError('GitHub GraphQL query contains unsupported control characters'); + } + const normalized = document.trim(); + const operations = [...normalized.matchAll(/\b(query|mutation|subscription)\b/gu)]; + if ( + operations.length !== 1 || + operations[0][1] !== 'query' || + !/^query\s+[A-Za-z_][A-Za-z0-9_]*(?:\s*\([^)]*\))?\s*\{[\s\S]*\}$/u.test(normalized) || + /["'`#]/u.test(normalized) + ) { + throw new GitHubReadError('GitHub GraphQL read requires exactly one named query operation'); + } + let depth = 0; + for (const character of normalized) { + if (character === '{') depth += 1; + else if (character === '}') depth -= 1; + if (depth < 0) break; + } + if (depth !== 0) { + throw new GitHubReadError('GitHub GraphQL query has unbalanced selection braces'); + } +} + +function validateGraphqlVariables(variables) { + if ( + variables === null || + typeof variables !== 'object' || + Array.isArray(variables) || + ![Object.prototype, null].includes(Object.getPrototypeOf(variables)) + ) { + throw new GitHubReadError('GitHub GraphQL variables must be a plain object'); + } + for (const name of Object.keys(variables).sort()) { + const value = variables[name]; + if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(name)) { + throw new GitHubReadError(`GitHub GraphQL variable name is invalid: ${name}`); + } + if (typeof value !== 'string' || value.length > 4_096 || /[\u0000-\u001f\u007f]/u.test(value)) { + throw new GitHubReadError( + `GitHub GraphQL variable ${name} must be a bounded printable string`, + ); + } + } +} + +export async function requestGithubGraphql(document, variables = {}, options = {}) { + assertSafeGraphqlQuery(document); + validateGraphqlVariables(variables); + const environment = options.environment ?? process.env; + const fetchImpl = options.fetchImpl ?? fetch; + return await requestGithubJsonWithRetry('https://api.github.com/graphql', { + ...options, + authToken: environment.GH_TOKEN || environment.GITHUB_TOKEN || '', + coreJournalOptions: { environment, ...options.coreJournalOptions }, + fetchImpl: (url, init) => + fetchImpl(url, { + ...init, + method: 'POST', + headers: { ...init.headers, 'Content-Type': 'application/json' }, + body: JSON.stringify({ query: document, variables }), + }), + }); +} + +function parseGithubPaginationLinks(value, label) { + if (value === '') return new Map(); + const links = new Map(); + for (const rawEntry of value.split(/,\s*(?=<)/u)) { + const match = /^<([^<>]+)>;\s*rel="(first|last|next|prev)"$/u.exec(rawEntry.trim()); + if (match === null || links.has(match[2])) { + throw new GitHubReadError( + `${label} returned a malformed or duplicate pagination Link relation`, + ); + } + links.set(match[2], match[1]); + } + return links; +} + +function escapedRegex(value) { + return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&'); +} + +function exactQueryEntries(url, label) { + const entries = [...url.searchParams.entries()]; + if (new Set(entries.map(([name]) => name)).size !== entries.length) { + throw new GitHubReadError(`${label} contains a duplicate query parameter`); + } + return entries.sort( + ([leftName, leftValue], [rightName, rightValue]) => + compareText(leftName, rightName) || compareText(leftValue, rightValue), + ); +} + +function paginationEndpoint(endpoint) { + if (typeof endpoint !== 'string' || !endpoint.startsWith('repos/')) { + throw new GitHubReadError('journal-aware pagination requires a repository API endpoint'); + } + validateGithubEndpoint(endpoint); + const url = new URL(endpoint, 'https://api.github.com/'); + if (url.origin !== 'https://api.github.com' || url.hash !== '') { + throw new GitHubReadError('journal-aware pagination requires the canonical GitHub API origin'); + } + const match = /^\/repos\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)\/(.+)$/u.exec(url.pathname); + if (match === null || match[3].endsWith('/')) { + throw new GitHubReadError( + 'journal-aware pagination endpoint must name one repository resource', + ); + } + const fixedQuery = exactQueryEntries(url, 'journal-aware pagination endpoint'); + if (fixedQuery.some(([name]) => name === 'page' || name === 'per_page')) { + throw new GitHubReadError('journal-aware pagination owns the page and per_page parameters'); + } + return { + fixedQuery, + owner: match[1], + repo: match[2], + requestedPath: url.pathname, + resource: match[3], + }; +} + +function validateGithubPaginationLink( + rawUrl, + expected, + relation, + currentPage, + canonicalRepositoryPath, +) { + let url; + try { + url = new URL(rawUrl); + } catch (cause) { + throw new GitHubReadError(`${expected.label} returned a malformed pagination URL`, { cause }); + } + if ( + url.protocol !== 'https:' || + url.hostname !== 'api.github.com' || + url.port !== '' || + url.username !== '' || + url.password !== '' || + url.hash !== '' + ) { + throw new GitHubReadError( + `${expected.label} pagination URL must use the canonical GitHub API origin`, + ); + } + const canonicalMatch = new RegExp( + `^/repositories/([1-9][0-9]*)/${escapedRegex(expected.resource)}$`, + 'u', + ).exec(url.pathname); + if (url.pathname !== expected.requestedPath && canonicalMatch === null) { + throw new GitHubReadError(`${expected.label} pagination URL changed repository or endpoint`); + } + let nextCanonicalPath = canonicalRepositoryPath; + if (canonicalMatch !== null) { + if (canonicalRepositoryPath !== null && url.pathname !== canonicalRepositoryPath) { + throw new GitHubReadError( + `${expected.label} pagination URL changed canonical repository identity`, + ); + } + nextCanonicalPath = url.pathname; + } + const pageValue = url.searchParams.get('page'); + if (!/^[1-9][0-9]*$/u.test(pageValue ?? '')) { + throw new GitHubReadError(`${expected.label} pagination URL has an invalid page number`); + } + const linkedPage = Number(pageValue); + if (!Number.isSafeInteger(linkedPage)) { + throw new GitHubReadError(`${expected.label} pagination page exceeds the safe integer range`); + } + const wantedPage = + relation === 'next' + ? currentPage + 1 + : relation === 'prev' + ? currentPage - 1 + : relation === 'first' + ? 1 + : linkedPage; + if (linkedPage !== wantedPage || (relation === 'last' && linkedPage < currentPage)) { + throw new GitHubReadError(`${expected.label} returned a non-canonical ${relation} page number`); + } + const actualQuery = exactQueryEntries(url, `${expected.label} pagination URL`); + const expectedQuery = [ + ...expected.fixedQuery, + ['page', String(linkedPage)], + ['per_page', String(GITHUB_PAGINATION_PAGE_SIZE)], + ].sort( + ([leftName, leftValue], [rightName, rightValue]) => + compareText(leftName, rightName) || compareText(leftValue, rightValue), + ); + if (JSON.stringify(actualQuery) !== JSON.stringify(expectedQuery)) { + throw new GitHubReadError(`${expected.label} pagination URL changed the exact page query`); + } + return nextCanonicalPath; +} + +export async function requestGithubPages(endpoint, options = {}) { + const environment = options.environment ?? process.env; + const expected = paginationEndpoint(endpoint); + const label = options.label ?? 'GitHub paginated JSON read'; + const itemsField = options.itemsField ?? null; + const maxPages = options.maxPages ?? GITHUB_PAGINATION_MAX_PAGES; + const settings = githubReadOptionsFromEnv(options.environment ?? process.env, options); + const now = settings.now ?? Date.now; + const paginationStartedAtMs = now(); + const paginationDeadlineMs = Math.min( + paginationStartedAtMs + settings.deadlineMs, + githubReleaseQueryDeadline(paginationStartedAtMs, environment), + ); + if (!Number.isSafeInteger(paginationDeadlineMs)) { + throw new GitHubReadError(`${label} pagination deadline exceeds the safe timestamp range`); + } + if (!Number.isSafeInteger(maxPages) || maxPages < 1 || maxPages > GITHUB_PAGINATION_MAX_PAGES) { + throw new GitHubReadError( + `paginated JSON maxPages must be between 1 and ${GITHUB_PAGINATION_MAX_PAGES}`, + ); + } + if ( + itemsField !== null && + (typeof itemsField !== 'string' || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(itemsField)) + ) { + throw new GitHubReadError('paginated JSON itemsField must be null or a safe object field name'); + } + const rows = []; + let canonicalRepositoryPath = null; + for (let page = 1; page <= maxPages; page += 1) { + const query = new URLSearchParams(expected.fixedQuery); + query.set('per_page', String(GITHUB_PAGINATION_PAGE_SIZE)); + query.set('page', String(page)); + const pageEndpoint = `${expected.requestedPath.slice(1)}?${query.toString()}`; + const pageLabel = `${label} page ${page}`; + const pageStartedAtMs = now(); + const remainingPaginationMs = paginationDeadlineMs - pageStartedAtMs; + if (remainingPaginationMs <= 0) { + throw new GitHubReadError(`${label}: pagination deadline exhausted before page ${page}`, { + deadlineExhausted: true, + retryable: true, + }); + } + const { data, link } = await requestGithubJsonWithRetry( + 'https://api.github.com/' + pageEndpoint, + { + authToken: environment.GH_TOKEN || environment.GITHUB_TOKEN || '', + coreJournalOptions: { environment, ...options.coreJournalOptions }, + deadlineMs: paginationDeadlineMs, + fetchImpl: options.fetchImpl, + nowImpl: now, + sleepImpl: options.sleepImpl ?? options.sleep, + attemptTimeoutMs: settings.attemptTimeoutMs, + maxAttempts: settings.maxAttempts, + responseMetadata: true, + }, + ); + const pageRows = + itemsField === null + ? data + : data !== null && !Array.isArray(data) && typeof data === 'object' + ? data[itemsField] + : undefined; + if (!Array.isArray(pageRows) || pageRows.length > GITHUB_PAGINATION_PAGE_SIZE) { + throw new GitHubReadError( + `${pageLabel} must contain an array of at most ${GITHUB_PAGINATION_PAGE_SIZE} rows` + + (itemsField === null ? '' : ` in ${itemsField}`), + ); + } + rows.push(...pageRows); + const links = parseGithubPaginationLinks(link, pageLabel); + for (const [relation, rawUrl] of links) { + canonicalRepositoryPath = validateGithubPaginationLink( + rawUrl, + { ...expected, label: pageLabel }, + relation, + page, + canonicalRepositoryPath, + ); + } + if (!links.has('next')) return rows; + if (pageRows.length !== GITHUB_PAGINATION_PAGE_SIZE) { + throw new GitHubReadError( + `${pageLabel} advertised a next page after only ${pageRows.length} rows`, + ); + } + } + throw new GitHubReadError(`${label} exceeds ${maxPages} pages`); +} + +export async function requestGithubRepositoryJson(endpoint, options = {}) { + validateGithubEndpoint(endpoint); + const environment = options.environment ?? process.env; + const settings = githubReadOptionsFromEnv(environment, options); + const now = options.now ?? Date.now; + return await requestGithubJsonWithRetry( + endpoint.startsWith('https:') ? endpoint : 'https://api.github.com/' + endpoint, + { + authToken: environment.GH_TOKEN || environment.GITHUB_TOKEN || '', + coreJournalOptions: { environment, ...options.coreJournalOptions }, + deadlineMs: Math.min( + now() + settings.deadlineMs, + githubReleaseQueryDeadline(now(), environment), + ), + attemptTimeoutMs: settings.attemptTimeoutMs, + fetchImpl: options.fetchImpl, + nowImpl: now, + sleepImpl: options.sleepImpl ?? options.sleep, + maxAttempts: settings.maxAttempts, + }, + ); +} + +const MAX_GITHUB_JSON_BYTES = 8 * 1024 * 1024; +const MAX_GITHUB_ERROR_BYTES = 64 * 1024; +const GITHUB_API_TIMEOUT_MS = 30_000; +const GITHUB_RELEASE_QUERY_WINDOW_MS = 5 * 60 * 1000; +const GITHUB_RELEASE_QUERY_MAX_ATTEMPTS = 3; +const GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS = 4 * 60 * 1000; + +export function authHeaders(accept, token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN) { + const headers = { + Accept: accept, + 'User-Agent': 'oliphaunt-release-check', + 'X-GitHub-Api-Version': '2022-11-28', + }; + if (token) { + if (typeof token !== 'string' || /[\0\r\n]/u.test(token)) { + throw new Error('GitHub API token is invalid'); + } + headers.Authorization = `Bearer ${token}`; + } + return headers; +} + +export function responseContentLength(response, context) { + const raw = response.headers?.get?.('content-length'); + if (raw === null || raw === undefined) return null; + const value = Number(raw); + if (!Number.isSafeInteger(value) || value < 0) { + throw new Error(`${context} returned an invalid Content-Length`); + } + return value; +} + +export async function boundedResponseBytes(response, maximum, context) { + const declared = responseContentLength(response, context); + if (declared !== null && declared > maximum) { + await response.body?.cancel?.().catch(() => {}); + throw new Error(`${context} exceeds ${maximum} bytes`); + } + const reader = response.body?.getReader?.(); + if (reader === undefined) { + const bytes = new Uint8Array(await response.arrayBuffer()); + if (bytes.byteLength > maximum) throw new Error(`${context} exceeds ${maximum} bytes`); + return bytes; + } + const chunks = []; + let size = 0; + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > maximum) { + await reader.cancel().catch(() => {}); + throw new Error(`${context} exceeds ${maximum} bytes`); + } + chunks.push(Buffer.from(value)); + } + } finally { + reader.releaseLock(); + } + return new Uint8Array(Buffer.concat(chunks, size)); +} + +export async function requestBoundedGithubJson( + url, + { fetchImpl = fetch, timeoutMs = GITHUB_API_TIMEOUT_MS } = {}, +) { + const response = await fetchImpl(url, { + headers: authHeaders('application/vnd.github+json'), + redirect: 'error', + signal: AbortSignal.timeout(timeoutMs), + }); + if (!response.ok) { + await response.body?.cancel?.().catch(() => {}); + throw new Error(`GitHub API returned HTTP ${response.status} for ${url}`); + } + const bytes = await boundedResponseBytes(response, MAX_GITHUB_JSON_BYTES, 'GitHub API response'); + try { + return JSON.parse(new TextDecoder().decode(bytes)); + } catch (error) { + throw new GitHubReadError(`GitHub API returned invalid JSON for ${url}: ${error.message}`); + } +} + +function githubRateLimitedResponse(response, detail) { + if (response.status === 429) return true; + if (response.status !== 403) return false; + return ( + response.headers?.has?.('retry-after') === true || + response.headers?.get?.('x-ratelimit-remaining')?.trim() === '0' || + /(?:abuse|rate limit|secondary limit)/iu.test(detail) + ); +} + +function retryableGithubResponse(response, rateLimited) { + return ( + rateLimited || + response.status === 408 || + response.status === 425 || + (response.status >= 500 && response.status <= 599) + ); +} + +async function githubErrorDetail(response) { + try { + const bytes = await boundedResponseBytes( + response, + MAX_GITHUB_ERROR_BYTES, + `GitHub API HTTP ${response.status} error response`, + ); + const text = new TextDecoder().decode(bytes); + try { + const parsed = JSON.parse(text); + return typeof parsed?.message === 'string' ? parsed.message : text; + } catch { + return text; + } + } catch { + await response.body?.cancel?.().catch(() => {}); + return ''; + } +} + +function retryAfterDelay(response, nowMs, context) { + const raw = response.headers?.get?.('retry-after')?.trim(); + if (!raw) return null; + let delay; + if (/^[0-9]+$/u.test(raw)) { + delay = Number(raw) * 1000; + } else { + const date = Date.parse(raw); + if (!Number.isFinite(date)) { + throw new Error(`${context} returned an invalid Retry-After header`); + } + delay = Math.max(0, date - nowMs); + } + if (!Number.isSafeInteger(delay) || delay > GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS) { + throw new Error( + `${context} requested Retry-After ${JSON.stringify(raw)}, exceeding the ${GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS}ms retry cap`, + ); + } + return delay; +} + +function rateLimitDelay(response, nowMs, headerlessSecondaryAttempt, context) { + const retryAfter = retryAfterDelay(response, nowMs, context); + if (retryAfter !== null) return retryAfter; + + if (response.headers?.get?.('x-ratelimit-remaining')?.trim() === '0') { + const rawReset = response.headers?.get?.('x-ratelimit-reset')?.trim(); + if (rawReset === undefined || rawReset === null || rawReset === '') { + throw new Error(`${context} exhausted the primary rate limit without X-RateLimit-Reset`); + } + if (!/^[1-9][0-9]*$/u.test(rawReset)) { + throw new Error(`${context} returned an invalid X-RateLimit-Reset header`); + } + const resetMs = Number(rawReset) * 1000; + const delay = Math.max(0, resetMs - nowMs) + 1_000; + if (!Number.isSafeInteger(resetMs) || delay > GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS) { + throw new Error( + `${context} requires a primary-rate-limit wait exceeding the ${GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS}ms retry cap`, + ); + } + return delay; + } + + // GitHub requires at least a one-minute pause for a secondary limit without + // usable rate-limit headers, followed by exponential backoff. + return Math.min( + GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS, + 60_000 * 2 ** Math.max(0, headerlessSecondaryAttempt - 1), + ); +} + +export function githubReleaseQueryDeadline(nowMs = Date.now(), env = process.env) { + let deadline = nowMs + GITHUB_RELEASE_QUERY_WINDOW_MS; + const raw = env.REGISTRY_JOB_HARD_DEADLINE_EPOCH?.trim(); + if (raw !== undefined && raw !== '') { + if (!/^[1-9][0-9]*$/u.test(raw)) { + throw new Error('REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp'); + } + const hardDeadline = Number(raw) * 1000; + if (!Number.isSafeInteger(hardDeadline)) { + throw new Error('REGISTRY_JOB_HARD_DEADLINE_EPOCH exceeds the safe timestamp range'); + } + deadline = Math.min(deadline, hardDeadline); + } + if (deadline <= nowMs) { + throw new Error('GitHub release query deadline has already expired'); + } + return deadline; +} + +export async function requestGithubJsonWithRetry( + url, + { + attemptTimeoutMs = GITHUB_API_TIMEOUT_MS, + authToken, + coreJournalOptions, + deadlineMs, + fetchImpl = fetch, + maxAttempts = GITHUB_RELEASE_QUERY_MAX_ATTEMPTS, + nowImpl = Date.now, + responseMetadata = false, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + } = {}, +) { + if (!Number.isSafeInteger(maxAttempts) || maxAttempts <= 0) { + throw new Error('GitHub request maxAttempts must be a positive safe integer'); + } + const effectiveDeadline = deadlineMs ?? githubReleaseQueryDeadline(nowImpl()); + let headerlessSecondaryFailures = 0; + let lastError; + for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { + const now = nowImpl(); + const remaining = effectiveDeadline - now; + if (remaining <= 0) { + throw new Error(`GitHub release query deadline expired for ${url}`); + } + let response; + let rateLimited = false; + await reserveGitHubCoreRequest({ + ...(coreJournalOptions ?? {}), + label: `GitHub release JSON ${new URL(url).pathname}`, + }); + const transportRemaining = effectiveDeadline - nowImpl(); + if (transportRemaining <= 0) { + throw new Error( + `GitHub release query deadline expired during request-journal admission for ${url}`, + ); + } + try { + response = await fetchImpl(url, { + headers: authHeaders('application/vnd.github+json', authToken), + redirect: 'error', + signal: AbortSignal.timeout(Math.max(1, Math.min(attemptTimeoutMs, transportRemaining))), + }); + } catch (error) { + lastError = error; + if (attempt === maxAttempts) break; + } + if (response?.ok) { + const bytes = await boundedResponseBytes( + response, + MAX_GITHUB_JSON_BYTES, + 'GitHub API response', + ); + try { + const data = JSON.parse(new TextDecoder().decode(bytes)); + return responseMetadata ? { data, link: response.headers?.get?.('link') ?? '' } : data; + } catch (error) { + throw new GitHubReadError(`GitHub API returned invalid JSON for ${url}: ${error.message}`); + } + } + if (response !== undefined) { + const detail = await githubErrorDetail(response); + rateLimited = githubRateLimitedResponse(response, detail); + if (!retryableGithubResponse(response, rateLimited)) { + throw new Error(`GitHub API returned HTTP ${response.status} for ${url}`); + } + lastError = new Error(`GitHub API returned transient HTTP ${response.status} for ${url}`); + if (attempt === maxAttempts) break; + } + const current = nowImpl(); + const retryAfter = + response === undefined + ? null + : retryAfterDelay(response, current, `GitHub API HTTP ${response.status}`); + const headerlessSecondary = + response !== undefined && + rateLimited && + retryAfter === null && + response.headers?.get?.('x-ratelimit-remaining')?.trim() !== '0'; + headerlessSecondaryFailures = headerlessSecondary ? headerlessSecondaryFailures + 1 : 0; + const delay = + retryAfter ?? + (rateLimited + ? rateLimitDelay( + response, + current, + headerlessSecondaryFailures, + `GitHub API HTTP ${response.status}`, + ) + : Math.min(2_000, 250 * 2 ** (attempt - 1))); + if (current + delay >= effectiveDeadline) { + throw new Error(`GitHub release query retry for ${url} would exceed its deadline`); + } + await sleepImpl(delay); + } + throw new Error( + `${lastError?.message ?? `GitHub API request failed for ${url}`} after ${maxAttempts} attempts`, + ); +} + +// Actions downloads redirect to short-lived storage URLs. Never forward the +// GitHub credential to storage, and keep the whole transfer under one timeout. +export async function requestGithubDownload( + url, + { environment = process.env, fetchImpl = fetch, timeoutMs = 5 * 60_000 } = {}, +) { + let location = new URL(url); + if ( + location.origin !== 'https://api.github.com' || + location.username || + location.password || + location.hash + ) + throw new GitHubReadError('GitHub download must start at the canonical API origin'); + const signal = AbortSignal.timeout(timeoutMs); + await reserveGitHubCoreRequest({ environment, label: `GitHub download ${location.pathname}` }); + for (let redirects = 0; redirects <= 5; redirects++) { + if (location.protocol !== 'https:' || location.username || location.password || location.hash) + throw new GitHubReadError( + 'GitHub download redirect must use HTTPS without credentials or fragments', + ); + let response; + try { + response = await fetchImpl(location, { + headers: + redirects === 0 + ? authHeaders( + 'application/vnd.github+json', + environment.GH_TOKEN || environment.GITHUB_TOKEN || '', + ) + : {}, + redirect: 'manual', + signal, + }); + } catch (cause) { + throw new RetryableReadError('GitHub artifact transfer failed', { cause }); + } + if (response.ok) return response; + if ([301, 302, 303, 307, 308].includes(response.status)) { + const next = response.headers.get('location'); + await response.body?.cancel?.().catch(() => {}); + if (!next) throw new GitHubReadError('GitHub download redirect omitted Location'); + location = new URL(next, location); + continue; + } + const detail = await githubErrorDetail(response); + throw new GitHubReadError(`GitHub artifact download returned HTTP ${response.status}`, { + retryable: + RETRYABLE_STATUS.has(response.status) || githubRateLimitedResponse(response, detail), + }); + } + throw new GitHubReadError('GitHub artifact download exceeds five redirects'); +} + +async function cli(argv) { + let label = 'GitHub read', + field; + while (argv[0]?.startsWith('--') && argv[0] !== '--') { + const flag = argv.shift(); + const value = argv.shift(); + if (!value) throw new GitHubReadError(`${flag} requires a value`); + if (flag === '--label') label = value; + else if (flag === '--paginate-field') field = value; + else throw new GitHubReadError(`unknown github-read option: ${flag}`); + } + if (argv[0] === '--') argv.shift(); + if (argv.length !== 1 || !argv[0].startsWith('repos/')) + throw new GitHubReadError('GitHub read requires exactly one repository API endpoint'); + validateGithubEndpoint(argv[0]); + const data = + field === undefined + ? await requestGithubRepositoryJson(argv[0], { label }) + : await requestGithubPages(argv[0], { label, itemsField: field === '-' ? null : field }); + process.stdout.write(JSON.stringify(data) + '\n'); +} + +if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) { + try { + await cli(process.argv.slice(2)); + } catch (error) { + console.error(redactGitHubReadDetail(error instanceof Error ? error.message : String(error))); + process.exit(isRetryableGitHubReadError(error) ? 75 : 64); + } +} diff --git a/tools/release/github-read.test.mjs b/tools/release/github-read.test.mjs deleted file mode 100644 index f6d425215..000000000 --- a/tools/release/github-read.test.mjs +++ /dev/null @@ -1,484 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { isolatedGitHubTestEnvironment } from "../test/isolated-github-test-environment.mjs"; - -import { - GitHubReadError, - RetryableReadError, - githubReadOptionsFromEnv, - redactGitHubReadDetail, - retryReadOperationSync, - runGitHubGraphqlReadSync, - runGitHubPaginatedJsonSync, - runGitHubReadSync, -} from "./github-read.mjs"; -import { readGitHubCoreRequestJournal } from "./github-core-request-journal.mjs"; - -function deterministic(overrides = {}) { - let time = 1_000; - return { - attemptTimeoutMs: 50, - baseDelayMs: 10, - deadlineMs: 1_000, - environment: {}, - maxAttempts: 4, - maxDelayMs: 40, - now: () => time, - random: () => 0.5, - sleep: (delay) => { - time += delay; - }, - ...overrides, - }; -} - -function journalFixture(t, label) { - const root = mkdtempSync(path.join(os.tmpdir(), `oliphaunt-github-read-${label}-`)); - t.after(() => rmSync(root, { force: true, recursive: true })); - return { - environment: { - GITHUB_REPOSITORY: "o/r", - GITHUB_RUN_ATTEMPT: "1", - GITHUB_RUN_ID: "123", - GITHUB_SHA: "a".repeat(40), - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, "journal.json"), - OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: "true", - }, - root, - }; -} - -test("bounded read retries a transient failure and returns the successful result", () => { - const attempts = []; - const retries = []; - const result = retryReadOperationSync( - "artifact inventory", - ({ attempt, attemptTimeoutMs }) => { - attempts.push([attempt, attemptTimeoutMs]); - if (attempt === 1) throw new Error("HTTP 503 temporary failure"); - return "complete"; - }, - deterministic({ onRetry: (event) => retries.push([event.attempt, event.delayMs]) }), - ); - assert.equal(result, "complete"); - assert.deepEqual(attempts, [[1, 50], [2, 50]]); - assert.deepEqual(retries, [[1, 10]]); -}); - -test("permanent authentication and usage failures never consume the retry budget", () => { - let attempts = 0; - assert.throws( - () => retryReadOperationSync( - "run metadata", - () => { - attempts += 1; - const error = new Error("HTTP 401 Bad credentials"); - error.status = 1; - throw error; - }, - deterministic(), - ), - (error) => error instanceof GitHubReadError && error.retryable === false && error.attempts === 1, - ); - assert.equal(attempts, 1); -}); - -test("rate-limited HTTP 403 reads remain retryable but ordinary forbidden reads do not", () => { - let attempts = 0; - const result = retryReadOperationSync( - "rate-limited inventory", - () => { - attempts += 1; - if (attempts === 1) throw new Error("HTTP 403 secondary rate limit exceeded"); - return "ok"; - }, - deterministic(), - ); - assert.equal(result, "ok"); - assert.equal(attempts, 2); - assert.throws( - () => retryReadOperationSync( - "forbidden inventory", - () => { - throw new Error("HTTP 403 Resource not accessible by integration"); - }, - deterministic(), - ), - (error) => error.retryable === false && error.attempts === 1, - ); -}); - -test("retry budget and overall deadline are independent fail-closed bounds", () => { - let budgetAttempts = 0; - assert.throws( - () => retryReadOperationSync( - "workflow search", - () => { - budgetAttempts += 1; - throw new RetryableReadError("socket hang up"); - }, - deterministic({ maxAttempts: 3 }), - ), - (error) => error.retryable === true && error.attempts === 3 && /retry budget exhausted/u.test(error.message), - ); - assert.equal(budgetAttempts, 3); - - let time = 5_000; - let deadlineAttempts = 0; - assert.throws( - () => retryReadOperationSync( - "artifact download", - () => { - deadlineAttempts += 1; - time += 25; - throw new RetryableReadError("unexpected EOF"); - }, - { - ...deterministic(), - baseDelayMs: 10, - deadlineMs: 30, - maxDelayMs: 10, - now: () => time, - sleep: (delay) => { - time += delay; - }, - }, - ), - (error) => error.deadlineExhausted === true && error.attempts === 1, - ); - assert.equal(deadlineAttempts, 1); -}); - -test("GitHub CLI wrapper applies a per-attempt timeout and retries read-only commands", () => { - const calls = []; - const spawn = (command, args, options) => { - calls.push({ args, command, timeout: options.timeout }); - if (calls.length === 1) { - return { error: undefined, status: 1, stderr: "HTTP 502", stdout: "partial-secret-output" }; - } - return { error: undefined, status: 0, stderr: "", stdout: '[{"databaseId":9}]' }; - }; - const output = runGitHubReadSync( - ["run", "list", "--repo", "f0rr0/oliphaunt", "--json", "databaseId"], - { ...deterministic(), label: "CI run list", spawn }, - ); - assert.equal(output, '[{"databaseId":9}]'); - assert.equal(calls.length, 2); - assert.deepEqual(calls.map(({ timeout }) => timeout), [50, 50]); -}); - -test("binary GitHub reads retain non-UTF-8 bytes from a successful delayed final write", (t) => { - const temporary = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-github-binary-capture-")); - t.after(() => rmSync(temporary, { force: true, recursive: true })); - const gh = path.join(temporary, "gh"); - writeFileSync(gh, [ - `#!${process.execPath}`, - "process.stdout.write(Buffer.from([0x00, 0xff]));", - "setImmediate(() => process.stdout.write(Buffer.from([0x7f, 0x0a])));", - "", - ].join("\n"), { mode: 0o755 }); - const output = runGitHubReadSync( - ["run", "download", "123"], - { - ...deterministic({ attemptTimeoutMs: 1_000, deadlineMs: 5_000, maxAttempts: 1 }), - binary: true, - environment: { - HOME: process.env.HOME ?? temporary, - PATH: `${temporary}${path.delimiter}${process.env.PATH ?? ""}`, - }, - }, - ); - assert.deepEqual(output, Buffer.from([0x00, 0xff, 0x7f, 0x0a])); -}); - -test("journal admission delay clamps the read transport to the live deadline remainder", (t) => { - const { environment } = journalFixture(t, "clamp"); - const journal = environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH; - const lock = `${journal}.lock`; - writeFileSync(lock, "occupied\n"); - let nowMs = 1_000; - let observedTimeout; - const output = runGitHubReadSync( - ["api", "repos/o/r/releases"], - { - attemptTimeoutMs: 100, - baseDelayMs: 0, - coreJournalOptions: { - now: () => nowMs, - sleep: (delayMs) => { - nowMs += delayMs; - rmSync(lock, { force: true }); - }, - }, - deadlineMs: 175, - environment, - maxAttempts: 1, - maxDelayMs: 0, - now: () => nowMs, - spawn: (_command, _args, options) => { - observedTimeout = options.timeout; - return { status: 0, stderr: "", stdout: "[]" }; - }, - }, - ); - assert.equal(output, "[]"); - assert.equal(observedTimeout, 75); -}); - -test("journal admission that exhausts the read deadline never starts transport", (t) => { - const { environment } = journalFixture(t, "expiry"); - const journal = environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH; - const lock = `${journal}.lock`; - writeFileSync(lock, "occupied\n"); - let nowMs = 1_000; - let spawned = false; - assert.throws( - () => runGitHubReadSync( - ["api", "repos/o/r/releases"], - { - attemptTimeoutMs: 50, - baseDelayMs: 0, - coreJournalOptions: { - now: () => nowMs, - sleep: (delayMs) => { - nowMs += delayMs; - rmSync(lock, { force: true }); - }, - }, - deadlineMs: 75, - environment, - maxAttempts: 2, - maxDelayMs: 0, - now: () => nowMs, - spawn: () => { - spawned = true; - return { status: 0, stderr: "", stdout: "[]" }; - }, - }, - ), - (error) => error instanceof GitHubReadError - && error.deadlineExhausted === true - && error.attempts === 1, - ); - assert.equal(spawned, false); - assert.deepEqual( - readGitHubCoreRequestJournal({ environment, now: () => nowMs }), - { enabled: true, rollingCount: 1, sequence: 1 }, - ); -}); - -test("GitHub CLI wrapper refuses mutation-shaped commands before spawning", () => { - let spawned = false; - const spawn = () => { - spawned = true; - }; - for (const args of [ - ["api", "repos/f0rr0/oliphaunt/releases", "--method", "POST"], - ["api", "repos/f0rr0/oliphaunt/releases", "--method=POST"], - ["api", "repos/f0rr0/oliphaunt/releases", "--field=name=value"], - ["api", "repos/f0rr0/oliphaunt/releases", "-Fname=value"], - ["api", "repos/f0rr0/oliphaunt/releases", "--raw-field=name=value"], - ["api", "repos/f0rr0/oliphaunt/releases", "-fname=value"], - ["api", "repos/f0rr0/oliphaunt/releases", "--input=-"], - ["api", "repos/f0rr0/oliphaunt/releases", "-XPOST"], - ["release", "delete", "v1"], - ["api", "graphql"], - ["api", "https://example.invalid/repos/f0rr0/oliphaunt"], - ["api", "repos/f0rr0/oliphaunt", "--hostname", "example.invalid"], - ["api", "repos/f0rr0/oliphaunt", "-H", "Authorization: Bearer secret"], - ["api", "repos/f0rr0/oliphaunt/releases", "--paginate"], - ["api", "repos/f0rr0/oliphaunt/releases", "--slurp"], - ["api", "repos/f0rr0/oliphaunt", "repos/other/repository"], - ["api", "repos/f0rr0/oliphaunt/%2e%2e/actions/runs"], - ["run", "view", "1", "--hostname=example.invalid"], - ]) { - assert.throws( - () => runGitHubReadSync(args, { ...deterministic(), spawn }), - /refuses|allowlist|requires|traversal/u, - ); - } - assert.equal(spawned, false); -}); - -test("narrow GraphQL reads are query-only, journaled, and built from scalar variables", (t) => { - const { environment } = journalFixture(t, "graphql"); - const document = ` -query ReleaseControls($owner: String!, $name: String!) { - repository(owner: $owner, name: $name) { - nameWithOwner - } -}`; - let observedArgs; - const output = runGitHubGraphqlReadSync( - document, - { owner: "f0rr0", name: "oliphaunt" }, - { - ...deterministic(), - coreJournalOptions: { now: () => 1_000 }, - environment, - spawn: (_command, args) => { - observedArgs = args; - return { status: 0, stderr: "", stdout: '{"data":{"repository":{"nameWithOwner":"f0rr0/oliphaunt"}}}' }; - }, - }, - ); - assert.match(output, /f0rr0\/oliphaunt/u); - assert.deepEqual(observedArgs, [ - "api", - "graphql", - "-f", - `query=${document}`, - "-f", - "name=oliphaunt", - "-f", - "owner=f0rr0", - ]); - assert.deepEqual( - readGitHubCoreRequestJournal({ environment, now: () => 1_000 }), - { enabled: true, rollingCount: 1, sequence: 1 }, - ); -}); - -test("narrow GraphQL reads reject non-query documents and unsafe variables before spawning", () => { - let spawned = false; - const options = { ...deterministic(), spawn: () => { spawned = true; } }; - for (const document of [ - "mutation Bad { viewer { login } }", - "subscription Bad { viewer { login } }", - "{ viewer { login } }", - "query One { viewer { login } } query Two { viewer { login } }", - 'query Literal { repository(owner: "f0rr0", name: "oliphaunt") { name } }', - ]) { - assert.throws( - () => runGitHubGraphqlReadSync(document, {}, options), - /exactly one named query|query document/u, - ); - } - for (const variables of [ - [], - { owner: 42 }, - { owner: "bad\nvalue" }, - { "bad-name": "value" }, - ]) { - assert.throws( - () => runGitHubGraphqlReadSync("query Safe { viewer { login } }", variables, options), - /variables|variable/u, - ); - } - assert.equal(spawned, false); -}); - -test("journal-aware envelope pagination owns page queries and follows an exact next Link", () => { - const calls = []; - const firstPage = Array.from({ length: 100 }, (_, index) => ({ id: index + 1 })); - const secondPage = [{ id: 101 }]; - const spawn = (_command, args) => { - calls.push(args); - const page = calls.length; - const link = page === 1 - ? '; rel="next"' - : ""; - return { - status: 0, - stderr: "", - stdout: `HTTP/2.0 200 OK\n${link === "" ? "" : `Link: ${link}\n`}\n${JSON.stringify({ - jobs: page === 1 ? firstPage : secondPage, - })}`, - }; - }; - const rows = runGitHubPaginatedJsonSync( - "repos/f0rr0/oliphaunt/actions/runs/9/jobs?filter=latest", - { - ...deterministic(), - itemsField: "jobs", - spawn, - }, - ); - assert.equal(rows.length, 101); - assert.deepEqual(calls, [ - ["api", "--include", "repos/f0rr0/oliphaunt/actions/runs/9/jobs?filter=latest&per_page=100&page=1"], - ["api", "--include", "repos/f0rr0/oliphaunt/actions/runs/9/jobs?filter=latest&per_page=100&page=2"], - ]); -}); - -test("diagnostics redact tokens, authorization headers, query credentials, and URL userinfo", () => { - const secret = "github_pat_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - const rendered = redactGitHubReadDetail( - `Authorization: Bearer ${secret}\nhttps://user:pass@example.invalid/a?token=${secret}\n${secret}`, - { GH_TOKEN: secret }, - ); - assert.equal(rendered.includes(secret), false); - assert.match(rendered, //u); - assert.equal(rendered.includes("user:pass"), false); -}); - -test("environment and override settings enforce fixed retry, timeout, and memory bounds", () => { - assert.throws( - () => githubReadOptionsFromEnv({ OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: "0" }), - /must be between 1 and 10/u, - ); - assert.throws( - () => githubReadOptionsFromEnv({ OLIPHAUNT_GITHUB_READ_DEADLINE_MS: "0" }), - /must be between 1 and 3600000/u, - ); - assert.throws( - () => githubReadOptionsFromEnv({ - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "10", - OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: "9", - }), - /must be at least/u, - ); - assert.throws( - () => githubReadOptionsFromEnv({ OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: "11" }), - /between 1 and 10/u, - ); - assert.throws( - () => githubReadOptionsFromEnv({}, { deadlineMs: 60 * 60_000 + 1 }), - /deadlineMs must be between/u, - ); - assert.throws( - () => runGitHubReadSync( - ["api", "repos/f0rr0/oliphaunt"], - { ...deterministic(), maxBuffer: 128 * 1024 * 1024 + 1, spawn: () => ({ status: 0 }) }, - ), - /maxBuffer must be between/u, - ); -}); - -test("CLI entrypoint runs through Bun with both repository-relative and absolute script paths", (t) => { - const temporary = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-github-read-cli-")); - t.after(() => rmSync(temporary, { force: true, recursive: true })); - const gh = path.join(temporary, "gh"); - writeFileSync(gh, [ - `#!${process.execPath}`, - "process.stdout.write('[{\"databaseId\":');", - "setImmediate(() => process.stdout.write('42}]\\n'));", - "", - ].join("\n"), { mode: 0o755 }); - chmodSync(gh, 0o755); - const script = path.resolve("tools/release/github-read.mjs"); - const common = { - encoding: "utf8", - env: isolatedGitHubTestEnvironment({ - PATH: `${temporary}${path.delimiter}${process.env.PATH}`, - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "0", - OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: "0", - }), - }; - for (const entrypoint of [path.relative(process.cwd(), script), script]) { - const result = spawnSync( - process.execPath, - [entrypoint, "--", "run", "list", "--json", "databaseId"], - common, - ); - assert.equal(result.status, 0, result.stderr); - assert.equal(result.stdout.trim(), '[{"databaseId":42}]'); - } -}); diff --git a/tools/release/github-read.test.mts b/tools/release/github-read.test.mts new file mode 100644 index 000000000..56bd54679 --- /dev/null +++ b/tools/release/github-read.test.mts @@ -0,0 +1,460 @@ +#!/usr/bin/env bun + +import assert from 'node:assert/strict'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; + +import { readGitHubCoreRequestJournal } from './github-core-request-journal.mts'; +import { + GitHubReadError, + githubReadOptionsFromEnv, + RetryableReadError, + redactGitHubReadDetail, + requestGithubGraphql, + requestGithubRepositoryJson, + retryReadOperation, +} from './github-read.mts'; + +function deterministic(overrides = {}) { + let time = 1_000; + return { + attemptTimeoutMs: 50, + baseDelayMs: 10, + deadlineMs: 1_000, + environment: {}, + maxAttempts: 4, + maxDelayMs: 40, + now: () => time, + random: () => 0.5, + sleep: (delay) => { + time += delay; + }, + ...overrides, + }; +} + +function journalFixture(t, label) { + const root = mkdtempSync(path.join(os.tmpdir(), `oliphaunt-github-read-${label}-`)); + t.after(() => rmSync(root, { force: true, recursive: true })); + return { + environment: { + GITHUB_REPOSITORY: 'o/r', + GITHUB_RUN_ATTEMPT: '1', + GITHUB_RUN_ID: '123', + GITHUB_SHA: 'a'.repeat(40), + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, 'journal.json'), + OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: 'true', + }, + root, + }; +} + +test('bounded read retries a transient failure and returns the successful result', async () => { + const attempts = []; + const retries = []; + const result = await retryReadOperation( + 'artifact inventory', + ({ attempt, attemptTimeoutMs }) => { + attempts.push([attempt, attemptTimeoutMs]); + if (attempt === 1) throw new Error('HTTP 503 temporary failure'); + return 'complete'; + }, + deterministic({ onRetry: (event) => retries.push([event.attempt, event.delayMs]) }), + ); + assert.equal(result, 'complete'); + assert.deepEqual(attempts, [ + [1, 50], + [2, 50], + ]); + assert.deepEqual(retries, [[1, 10]]); +}); + +test('permanent authentication and usage failures never consume the retry budget', async () => { + let attempts = 0; + await assert.rejects( + async () => + await retryReadOperation( + 'run metadata', + () => { + attempts += 1; + const error = new Error('HTTP 401 Bad credentials'); + error.status = 1; + throw error; + }, + deterministic(), + ), + (error) => + error instanceof GitHubReadError && error.retryable === false && error.attempts === 1, + ); + assert.equal(attempts, 1); +}); + +test('rate-limited HTTP 403 reads remain retryable but ordinary forbidden reads do not', async () => { + let attempts = 0; + const result = await retryReadOperation( + 'rate-limited inventory', + () => { + attempts += 1; + if (attempts === 1) throw new Error('HTTP 403 secondary rate limit exceeded'); + return 'ok'; + }, + deterministic(), + ); + assert.equal(result, 'ok'); + assert.equal(attempts, 2); + await assert.rejects( + async () => + await retryReadOperation( + 'forbidden inventory', + () => { + throw new Error('HTTP 403 Resource not accessible by integration'); + }, + deterministic(), + ), + (error) => error.retryable === false && error.attempts === 1, + ); +}); + +test('retry budget and overall deadline are independent fail-closed bounds', async () => { + let budgetAttempts = 0; + await assert.rejects( + async () => + await retryReadOperation( + 'workflow search', + () => { + budgetAttempts += 1; + throw new RetryableReadError('socket hang up'); + }, + deterministic({ maxAttempts: 3 }), + ), + (error) => + error.retryable === true && + error.attempts === 3 && + /retry budget exhausted/u.test(error.message), + ); + assert.equal(budgetAttempts, 3); + + let time = 5_000; + let deadlineAttempts = 0; + await assert.rejects( + async () => + await retryReadOperation( + 'artifact download', + () => { + deadlineAttempts += 1; + time += 25; + throw new RetryableReadError('unexpected EOF'); + }, + { + ...deterministic(), + baseDelayMs: 10, + deadlineMs: 30, + maxDelayMs: 10, + now: () => time, + sleep: (delay) => { + time += delay; + }, + }, + ), + (error) => error.deadlineExhausted === true && error.attempts === 1, + ); + assert.equal(deadlineAttempts, 1); +}); + +test('journal admission delay clamps the read transport to the live deadline remainder', async (t) => { + const { environment } = journalFixture(t, 'clamp'); + const journal = environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH; + const lock = `${journal}.lock`; + writeFileSync(lock, 'occupied\n'); + let nowMs = 1_000; + let observedTimeout; + const originalTimeout = AbortSignal.timeout; + AbortSignal.timeout = (ms) => { + observedTimeout = ms; + return originalTimeout(ms); + }; + t.after(() => { + AbortSignal.timeout = originalTimeout; + }); + const output = await requestGithubRepositoryJson('repos/o/r/releases', { + attemptTimeoutMs: 100, + baseDelayMs: 0, + coreJournalOptions: { + now: () => nowMs, + sleep: (delayMs) => { + nowMs += delayMs; + rmSync(lock, { force: true }); + }, + }, + deadlineMs: 175, + environment, + maxAttempts: 1, + maxDelayMs: 0, + now: () => nowMs, + fetchImpl: () => Response.json([]), + }); + assert.deepEqual(output, []); + assert.equal(observedTimeout, 75); +}); + +test('journal admission that exhausts the read deadline never starts transport', async (t) => { + const { environment } = journalFixture(t, 'expiry'); + const journal = environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH; + const lock = `${journal}.lock`; + writeFileSync(lock, 'occupied\n'); + let nowMs = 1_000; + let spawned = false; + await assert.rejects( + async () => + await requestGithubRepositoryJson('repos/o/r/releases', { + attemptTimeoutMs: 50, + baseDelayMs: 0, + coreJournalOptions: { + now: () => nowMs, + sleep: (delayMs) => { + nowMs += delayMs; + rmSync(lock, { force: true }); + }, + }, + deadlineMs: 75, + environment, + maxAttempts: 2, + maxDelayMs: 0, + now: () => nowMs, + fetchImpl: () => { + spawned = true; + return Response.json([]); + }, + }), + /deadline expired during request-journal/u, + ); + assert.equal(spawned, false); + assert.deepEqual(readGitHubCoreRequestJournal({ environment, now: () => nowMs }), { + enabled: true, + rollingCount: 1, + sequence: 1, + }); +}); + +test('repository reads reject foreign URLs and traversal before HTTP', async () => { + let calls = 0; + for (const endpoint of [ + 'graphql', + 'https://example.invalid/repos/o/r', + 'https://secret@api.github.com/repos/o/r', + 'repos/o/r/../issues', + 'repos/o/r/%2e%2e/issues', + 'repos/o/r#fragment', + 'repos/o/r\\issues', + ]) { + await assert.rejects( + async () => + await requestGithubRepositoryJson(endpoint, { + fetchImpl: () => { + calls++; + }, + }), + /allowlist|traversal/u, + ); + } + assert.equal(calls, 0); +}); + +test('narrow GraphQL reads are query-only, journaled, and built from scalar variables', async (t) => { + const { environment } = journalFixture(t, 'graphql'); + const document = ` +query ReleaseControls($owner: String!, $name: String!) { + repository(owner: $owner, name: $name) { + nameWithOwner + } +}`; + let observed; + const output = await requestGithubGraphql( + document, + { owner: 'f0rr0', name: 'oliphaunt' }, + { + coreJournalOptions: { now: () => 1_000 }, + environment, + fetchImpl: async (url, options) => { + assert.equal(url, 'https://api.github.com/graphql'); + assert.equal(options.method, 'POST'); + assert.equal(options.redirect, 'error'); + observed = JSON.parse(options.body); + return Response.json({ data: { repository: { nameWithOwner: 'f0rr0/oliphaunt' } } }); + }, + }, + ); + assert.equal(output.data.repository.nameWithOwner, 'f0rr0/oliphaunt'); + assert.deepEqual(observed, { query: document, variables: { owner: 'f0rr0', name: 'oliphaunt' } }); + assert.deepEqual(readGitHubCoreRequestJournal({ environment, now: () => 1_000 }), { + enabled: true, + rollingCount: 1, + sequence: 1, + }); +}); + +test('narrow GraphQL reads reject non-query documents and unsafe variables before any HTTP request', async () => { + let spawned = false; + const options = { + ...deterministic(), + fetchImpl: () => { + spawned = true; + }, + }; + for (const document of [ + 'mutation Bad { viewer { login } }', + 'subscription Bad { viewer { login } }', + '{ viewer { login } }', + 'query One { viewer { login } } query Two { viewer { login } }', + 'query Literal { repository(owner: "f0rr0", name: "oliphaunt") { name } }', + ]) { + await assert.rejects( + async () => await requestGithubGraphql(document, {}, options), + /exactly one named query|query document/u, + ); + } + for (const variables of [[], { owner: 42 }, { owner: 'bad\nvalue' }, { 'bad-name': 'value' }]) { + await assert.rejects( + async () => await requestGithubGraphql('query Safe { viewer { login } }', variables, options), + /variables|variable/u, + ); + } + assert.equal(spawned, false); +}); + +test('diagnostics redact tokens, authorization headers, query credentials, and URL userinfo', () => { + const secret = 'github_pat_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'; + const rendered = redactGitHubReadDetail( + `Authorization: Bearer ${secret}\nhttps://user:pass@example.invalid/a?token=${secret}\n${secret}`, + { GH_TOKEN: secret }, + ); + assert.equal(rendered.includes(secret), false); + assert.match(rendered, //u); + assert.equal(rendered.includes('user:pass'), false); +}); + +test('environment and override settings enforce fixed retry, timeout, and memory bounds', () => { + assert.throws( + () => githubReadOptionsFromEnv({ OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: '0' }), + /must be between 1 and 10/u, + ); + assert.throws( + () => githubReadOptionsFromEnv({ OLIPHAUNT_GITHUB_READ_DEADLINE_MS: '0' }), + /must be between 1 and 3600000/u, + ); + assert.throws( + () => + githubReadOptionsFromEnv({ + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: '10', + OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: '9', + }), + /must be at least/u, + ); + assert.throws( + () => githubReadOptionsFromEnv({ OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: '11' }), + /between 1 and 10/u, + ); + assert.throws( + () => githubReadOptionsFromEnv({}, { deadlineMs: 60 * 60_000 + 1 }), + /deadlineMs must be between/u, + ); +}); + +test('native HTTP pagination retains exact page queries, link validation, and one deadline', async () => { + const { requestGithubPages } = await import('./github-read.mts'); + const endpoint = 'repos/f0rr0/oliphaunt/actions/runs/9/jobs?filter=latest'; + const full = Array.from({ length: 100 }, (_, id) => ({ id })); + const next = + 'https://api.github.com/repositories/123/actions/runs/9/jobs?filter=latest&per_page=100&page=2'; + const calls = []; + const rows = await requestGithubPages(endpoint, { + environment: {}, + itemsField: 'jobs', + fetchImpl: async (url, options) => { + calls.push(url); + assert.equal(options.redirect, 'error'); + return calls.length === 1 + ? Response.json({ jobs: full }, { headers: { link: `<${next}>; rel="next"` } }) + : Response.json({ jobs: [{ id: 100 }] }); + }, + }); + assert.equal(rows.length, 101); + assert.deepEqual( + calls.map((url) => new URL(url).search), + ['?filter=latest&per_page=100&page=1', '?filter=latest&per_page=100&page=2'], + ); + for (const [link, jobs, message] of [ + [next.replace('api.github.com', 'example.invalid'), full, /canonical GitHub API origin/u], + [next.replace('filter=latest', 'filter=all'), full, /exact page query/u], + [next, [], /advertised a next page/u], + ]) { + let reads = 0; + await assert.rejects( + requestGithubPages(endpoint, { + environment: {}, + itemsField: 'jobs', + fetchImpl: async () => { + reads++; + return Response.json({ jobs }, { headers: { link: `<${link}>; rel="next"` } }); + }, + }), + message, + ); + assert.equal(reads, 1); + } + let now = 0; + await assert.rejects( + requestGithubPages(endpoint, { + environment: {}, + itemsField: 'jobs', + deadlineMs: 100, + now: () => now, + fetchImpl: async () => { + now = 101; + return Response.json({ jobs: full }, { headers: { link: `<${next}>; rel="next"` } }); + }, + }), + /pagination deadline exhausted/u, + ); +}); + +test('native artifact redirects omit credentials and reject insecure destinations', async () => { + const { requestGithubDownload } = await import('./github-read.mts'); + const url = 'https://api.github.com/repos/f0rr0/oliphaunt/actions/artifacts/1/zip'; + const calls = []; + const response = await requestGithubDownload(url, { + environment: { GH_TOKEN: 'test-token' }, + fetchImpl: async (location, options) => { + calls.push({ location: location.href, options }); + return calls.length === 1 + ? new Response(null, { + status: 302, + headers: { location: 'https://storage.example.invalid/archive' }, + }) + : new Response('archive'); + }, + }); + assert.equal(await response.text(), 'archive'); + assert.equal(calls[0].options.headers.Authorization, 'Bearer test-token'); + assert.deepEqual(calls[1].options.headers, {}); + assert.equal(calls[0].options.signal, calls[1].options.signal); + for (const location of [ + 'http://storage.example.invalid/a', + 'https://user:secret@storage.example.invalid/a', + ]) { + let reads = 0; + await assert.rejects( + requestGithubDownload(url, { + environment: {}, + fetchImpl: async () => { + reads++; + return new Response(null, { status: 302, headers: { location } }); + }, + }), + /HTTPS without credentials/u, + ); + assert.equal(reads, 1); + } +}); diff --git a/tools/release/github-read.test.sh b/tools/release/github-read.test.sh new file mode 100644 index 000000000..188a93e99 --- /dev/null +++ b/tools/release/github-read.test.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/github-read.test.mts +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +printf '%s\n' 'globalThis.fetch = async () => Response.json([{id: 42}]);' > "$scratch/fetch.mts" +env -i PATH="$PATH" HOME="$HOME" bun --preload "$scratch/fetch.mts" \ + tools/release/github-read.mts -- repos/f0rr0/oliphaunt/actions/runs/42 > "$scratch/result" +[[ "$(cat "$scratch/result")" == '[{"id":42}]' ]] +echo 'GitHub read CLI: isolated Bun transport passed' diff --git a/tools/release/github-release-asset-upload-plan.mjs b/tools/release/github-release-asset-upload-plan.mjs deleted file mode 100644 index 94fae050c..000000000 --- a/tools/release/github-release-asset-upload-plan.mjs +++ /dev/null @@ -1,196 +0,0 @@ -import { - DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, - githubReleaseAssetUploadWindowMs, - GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, - MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS, -} from "./upload_github_release_assets.mjs"; -import { GITHUB_CONTENT_WRITE_INTERVAL_MS } from "./github-content-write-pacer.mjs"; - -// The durable content-write pacer allocates future request slots while holding -// its filesystem lock only for short state transitions. Keep uploader -// concurrency bounded so transport overlap, abort draining, and the complete -// wave deadline remain predictable. -export const MAX_CONCURRENT_GITHUB_RELEASE_ASSET_PRODUCTS = 5; -export const GITHUB_RELEASE_ASSET_WAVE_OVERHEAD_MS = 60_000; -export const GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS = 60_000; -export const MAX_GITHUB_RELEASE_ASSET_HANDOFF_WINDOW_MS = 95 * 60_000; -// These are the protected workflow's hard per-step bounds between the final -// read-only admission and the authoritative registry mutation gate. Policy -// checks keep the YAML values equal to these constants. -export const GITHUB_RELEASE_DRAFT_STAGE_STEP_TIMEOUT_MS = 31 * 60_000; -export const GITHUB_RELEASE_TAG_VERIFY_STEP_TIMEOUT_MS = 5 * 60_000; -export const GITHUB_RELEASE_STAGING_VERIFY_STEP_TIMEOUT_MS = 5 * 60_000; -export const GITHUB_RELEASE_ATTESTATION_STEP_TIMEOUT_MS = 5 * 60_000; -export const GITHUB_RELEASE_ATTESTATION_EVIDENCE_STEP_TIMEOUT_MS = 10 * 60_000; -export const GITHUB_RELEASE_SWIFTPM_STEP_TIMEOUT_MS = 6 * 60_000; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function error(message) { - return new Error(`github-release-asset-upload-plan: ${message}`); -} - -function positiveSafeInteger(value, label) { - if (!Number.isSafeInteger(value) || value < 1) { - throw error(`${label} must be a positive safe integer`); - } - return value; -} - -function rowsFromAssetCounts(assetCounts) { - if (!(assetCounts instanceof Map) || assetCounts.size === 0) { - throw error("assetCounts must be a non-empty product/count map"); - } - const rows = []; - for (const [product, assetCount] of assetCounts) { - if ( - typeof product !== "string" - || product.length === 0 - || !Number.isSafeInteger(assetCount) - || assetCount < 0 - ) { - throw error("assetCounts must contain non-empty product names and non-negative safe integer counts"); - } - // Keep the per-product uploader ceiling authoritative even though all - // products in a wave receive the larger shared wave deadline. - githubReleaseAssetUploadWindowMs(assetCount); - // Products without GitHub release assets do not need an uploader process. - // Both pre-mutation and final attestation receipts independently snapshot - // every selected release and prove those products have an exact empty - // asset set. - if (assetCount > 0) rows.push({ assetCount, product }); - } - return rows.sort((left, right) => - right.assetCount - left.assetCount || compareText(left.product, right.product)); -} - -/** - * Bound one concurrent upload wave under the real shared content-write pacer. - * - * Every product has at most one upload transport in flight. Across a wave, all - * starts remain serialized by the durable 10-second pacer, while transports - * overlap. A product can therefore finish no later than the complete wave's - * pacing budget plus its own sequential transports. The largest product is the - * longest such lane. Pre/post/ambiguity snapshots use the uploader's shared - * reserve and run concurrently across product lanes. - */ -export function githubReleaseAssetUploadWaveWindowMs(rows, { - contentWriteIntervalMs = GITHUB_CONTENT_WRITE_INTERVAL_MS, - snapshotReserveMs = GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, - uploadTimeoutMs = DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, - waveOverheadMs = GITHUB_RELEASE_ASSET_WAVE_OVERHEAD_MS, -} = {}) { - if (!Array.isArray(rows) || rows.length === 0) { - throw error("an upload wave must contain at least one product"); - } - for (const [label, value] of Object.entries({ - contentWriteIntervalMs, - snapshotReserveMs, - uploadTimeoutMs, - waveOverheadMs, - })) { - positiveSafeInteger(value, label); - } - let assetCount = 0; - let largestProductAssetCount = 0; - const products = new Set(); - for (const row of rows) { - if ( - row === null - || Array.isArray(row) - || typeof row !== "object" - || typeof row.product !== "string" - || row.product.length === 0 - || !Number.isSafeInteger(row.assetCount) - || row.assetCount < 0 - || products.has(row.product) - ) { - throw error("upload wave rows must contain unique products and non-negative safe integer counts"); - } - products.add(row.product); - assetCount += row.assetCount; - largestProductAssetCount = Math.max(largestProductAssetCount, row.assetCount); - } - const windowMs = waveOverheadMs - + snapshotReserveMs - + (assetCount * contentWriteIntervalMs) - + (largestProductAssetCount * uploadTimeoutMs); - if (!Number.isSafeInteger(windowMs)) { - throw error("upload wave window exceeds the safe integer range"); - } - return windowMs; -} - -export function concurrentGithubReleaseAssetUploadPlan(assetCounts, { - maxConcurrentProducts = MAX_CONCURRENT_GITHUB_RELEASE_ASSET_PRODUCTS, - maxHandoffWindowMs = MAX_GITHUB_RELEASE_ASSET_HANDOFF_WINDOW_MS, - maxWaveWindowMs = MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS, -} = {}) { - positiveSafeInteger(maxConcurrentProducts, "maximum concurrent products"); - positiveSafeInteger(maxHandoffWindowMs, "maximum handoff window"); - positiveSafeInteger(maxWaveWindowMs, "maximum wave window"); - const rows = rowsFromAssetCounts(assetCounts); - if (rows.length === 0) { - return { - assetCount: 0, - productCount: 0, - selectionVerificationWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, - totalWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, - waves: [], - }; - } - const waves = []; - let pending = []; - - const flush = () => { - if (pending.length === 0) return; - const windowMs = githubReleaseAssetUploadWaveWindowMs(pending); - waves.push({ - assetCount: pending.reduce((total, row) => total + row.assetCount, 0), - largestProductAssetCount: Math.max(...pending.map(({ assetCount }) => assetCount)), - products: pending.map(({ product }) => product), - rows: pending.map((row) => ({ ...row })), - windowMs, - }); - pending = []; - }; - - for (const row of rows) { - const candidate = [...pending, row]; - const candidateWindowMs = githubReleaseAssetUploadWaveWindowMs(candidate); - if ( - pending.length > 0 - && (candidate.length > maxConcurrentProducts || candidateWindowMs > maxWaveWindowMs) - ) { - flush(); - } - const singleOrNewWave = [...pending, row]; - const newWindowMs = githubReleaseAssetUploadWaveWindowMs(singleOrNewWave); - if (singleOrNewWave.length > maxConcurrentProducts || newWindowMs > maxWaveWindowMs) { - throw error( - `${row.product} cannot fit a bounded concurrent upload wave: ${newWindowMs}ms exceeds ` - + `${maxWaveWindowMs}ms or the ${maxConcurrentProducts}-product concurrency ceiling`, - ); - } - pending = singleOrNewWave; - } - flush(); - - const totalWindowMs = GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS - + waves.reduce((total, wave) => total + wave.windowMs, 0); - if (!Number.isSafeInteger(totalWindowMs) || totalWindowMs > maxHandoffWindowMs) { - throw error( - `the complete ${rows.length}-product GitHub release asset handoff requires ${totalWindowMs}ms, ` - + `exceeding the ${maxHandoffWindowMs}ms pre-registry ceiling`, - ); - } - return { - assetCount: rows.reduce((total, row) => total + row.assetCount, 0), - productCount: rows.length, - selectionVerificationWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, - totalWindowMs, - waves, - }; -} diff --git a/tools/release/github-release-asset-upload-plan.mts b/tools/release/github-release-asset-upload-plan.mts new file mode 100644 index 000000000..ca192c51e --- /dev/null +++ b/tools/release/github-release-asset-upload-plan.mts @@ -0,0 +1,209 @@ +import { + DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, + githubReleaseAssetUploadWindowMs, + GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, + MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS, +} from './upload_github_release_assets.mts'; +import { GITHUB_CONTENT_WRITE_INTERVAL_MS } from './github-content-write-pacer.mts'; + +// The durable content-write pacer allocates future request slots while holding +// its filesystem lock only for short state transitions. Keep uploader +// concurrency bounded so transport overlap, abort draining, and the complete +// wave deadline remain predictable. +export const MAX_CONCURRENT_GITHUB_RELEASE_ASSET_PRODUCTS = 5; +export const GITHUB_RELEASE_ASSET_WAVE_OVERHEAD_MS = 60_000; +export const GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS = 60_000; +export const MAX_GITHUB_RELEASE_ASSET_HANDOFF_WINDOW_MS = 95 * 60_000; +// These are the protected workflow's hard per-step bounds between the final +// read-only admission and the authoritative registry mutation gate. Policy +// checks keep the YAML values equal to these constants. +export const GITHUB_RELEASE_DRAFT_STAGE_STEP_TIMEOUT_MS = 31 * 60_000; +export const GITHUB_RELEASE_TAG_VERIFY_STEP_TIMEOUT_MS = 5 * 60_000; +export const GITHUB_RELEASE_STAGING_VERIFY_STEP_TIMEOUT_MS = 5 * 60_000; +export const GITHUB_RELEASE_ATTESTATION_STEP_TIMEOUT_MS = 5 * 60_000; +export const GITHUB_RELEASE_ATTESTATION_EVIDENCE_STEP_TIMEOUT_MS = 10 * 60_000; +export const GITHUB_RELEASE_SWIFTPM_STEP_TIMEOUT_MS = 6 * 60_000; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function error(message) { + return new Error(`github-release-asset-upload-plan: ${message}`); +} + +function positiveSafeInteger(value, label) { + if (!Number.isSafeInteger(value) || value < 1) { + throw error(`${label} must be a positive safe integer`); + } + return value; +} + +function rowsFromAssetCounts(assetCounts) { + if (!(assetCounts instanceof Map) || assetCounts.size === 0) { + throw error('assetCounts must be a non-empty product/count map'); + } + const rows = []; + for (const [product, assetCount] of assetCounts) { + if ( + typeof product !== 'string' || + product.length === 0 || + !Number.isSafeInteger(assetCount) || + assetCount < 0 + ) { + throw error( + 'assetCounts must contain non-empty product names and non-negative safe integer counts', + ); + } + // Keep the per-product uploader ceiling authoritative even though all + // products in a wave receive the larger shared wave deadline. + githubReleaseAssetUploadWindowMs(assetCount); + // Products without GitHub release assets do not need an uploader process. + // Both pre-mutation and final attestation receipts independently snapshot + // every selected release and prove those products have an exact empty + // asset set. + if (assetCount > 0) rows.push({ assetCount, product }); + } + return rows.sort( + (left, right) => right.assetCount - left.assetCount || compareText(left.product, right.product), + ); +} + +/** + * Bound one concurrent upload wave under the real shared content-write pacer. + * + * Every product has at most one upload transport in flight. Across a wave, all + * starts remain serialized by the durable 10-second pacer, while transports + * overlap. A product can therefore finish no later than the complete wave's + * pacing budget plus its own sequential transports. The largest product is the + * longest such lane. Pre/post/ambiguity snapshots use the uploader's shared + * reserve and run concurrently across product lanes. + */ +export function githubReleaseAssetUploadWaveWindowMs( + rows, + { + contentWriteIntervalMs = GITHUB_CONTENT_WRITE_INTERVAL_MS, + snapshotReserveMs = GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, + uploadTimeoutMs = DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, + waveOverheadMs = GITHUB_RELEASE_ASSET_WAVE_OVERHEAD_MS, + } = {}, +) { + if (!Array.isArray(rows) || rows.length === 0) { + throw error('an upload wave must contain at least one product'); + } + for (const [label, value] of Object.entries({ + contentWriteIntervalMs, + snapshotReserveMs, + uploadTimeoutMs, + waveOverheadMs, + })) { + positiveSafeInteger(value, label); + } + let assetCount = 0; + let largestProductAssetCount = 0; + const products = new Set(); + for (const row of rows) { + if ( + row === null || + Array.isArray(row) || + typeof row !== 'object' || + typeof row.product !== 'string' || + row.product.length === 0 || + !Number.isSafeInteger(row.assetCount) || + row.assetCount < 0 || + products.has(row.product) + ) { + throw error( + 'upload wave rows must contain unique products and non-negative safe integer counts', + ); + } + products.add(row.product); + assetCount += row.assetCount; + largestProductAssetCount = Math.max(largestProductAssetCount, row.assetCount); + } + const windowMs = + waveOverheadMs + + snapshotReserveMs + + assetCount * contentWriteIntervalMs + + largestProductAssetCount * uploadTimeoutMs; + if (!Number.isSafeInteger(windowMs)) { + throw error('upload wave window exceeds the safe integer range'); + } + return windowMs; +} + +export function concurrentGithubReleaseAssetUploadPlan( + assetCounts, + { + maxConcurrentProducts = MAX_CONCURRENT_GITHUB_RELEASE_ASSET_PRODUCTS, + maxHandoffWindowMs = MAX_GITHUB_RELEASE_ASSET_HANDOFF_WINDOW_MS, + maxWaveWindowMs = MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS, + } = {}, +) { + positiveSafeInteger(maxConcurrentProducts, 'maximum concurrent products'); + positiveSafeInteger(maxHandoffWindowMs, 'maximum handoff window'); + positiveSafeInteger(maxWaveWindowMs, 'maximum wave window'); + const rows = rowsFromAssetCounts(assetCounts); + if (rows.length === 0) { + return { + assetCount: 0, + productCount: 0, + selectionVerificationWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, + totalWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, + waves: [], + }; + } + const waves = []; + let pending = []; + + const flush = () => { + if (pending.length === 0) return; + const windowMs = githubReleaseAssetUploadWaveWindowMs(pending); + waves.push({ + assetCount: pending.reduce((total, row) => total + row.assetCount, 0), + largestProductAssetCount: Math.max(...pending.map(({ assetCount }) => assetCount)), + products: pending.map(({ product }) => product), + rows: pending.map((row) => ({ ...row })), + windowMs, + }); + pending = []; + }; + + for (const row of rows) { + const candidate = [...pending, row]; + const candidateWindowMs = githubReleaseAssetUploadWaveWindowMs(candidate); + if ( + pending.length > 0 && + (candidate.length > maxConcurrentProducts || candidateWindowMs > maxWaveWindowMs) + ) { + flush(); + } + const singleOrNewWave = [...pending, row]; + const newWindowMs = githubReleaseAssetUploadWaveWindowMs(singleOrNewWave); + if (singleOrNewWave.length > maxConcurrentProducts || newWindowMs > maxWaveWindowMs) { + throw error( + `${row.product} cannot fit a bounded concurrent upload wave: ${newWindowMs}ms exceeds ` + + `${maxWaveWindowMs}ms or the ${maxConcurrentProducts}-product concurrency ceiling`, + ); + } + pending = singleOrNewWave; + } + flush(); + + const totalWindowMs = + GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS + + waves.reduce((total, wave) => total + wave.windowMs, 0); + if (!Number.isSafeInteger(totalWindowMs) || totalWindowMs > maxHandoffWindowMs) { + throw error( + `the complete ${rows.length}-product GitHub release asset handoff requires ${totalWindowMs}ms, ` + + `exceeding the ${maxHandoffWindowMs}ms pre-registry ceiling`, + ); + } + return { + assetCount: rows.reduce((total, row) => total + row.assetCount, 0), + productCount: rows.length, + selectionVerificationWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, + totalWindowMs, + waves, + }; +} diff --git a/tools/release/github-release-asset-upload-plan.test.mjs b/tools/release/github-release-asset-upload-plan.test.mjs deleted file mode 100644 index b1049a5d4..000000000 --- a/tools/release/github-release-asset-upload-plan.test.mjs +++ /dev/null @@ -1,54 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { - concurrentGithubReleaseAssetUploadPlan, - GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, - GITHUB_RELEASE_ASSET_WAVE_OVERHEAD_MS, - githubReleaseAssetUploadWaveWindowMs, -} from "./github-release-asset-upload-plan.mjs"; -import { GITHUB_CONTENT_WRITE_INTERVAL_MS } from "./github-content-write-pacer.mjs"; -import { - DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, - GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, -} from "./upload_github_release_assets.mjs"; - -describe("bounded concurrent GitHub release asset upload plan", () => { - test("uses global pacing plus the longest sequential transport lane", () => { - const rows = [ - { product: "large", assetCount: 8 }, - { product: "small-a", assetCount: 3 }, - { product: "small-b", assetCount: 0 }, - ]; - expect(githubReleaseAssetUploadWaveWindowMs(rows)).toBe( - GITHUB_RELEASE_ASSET_WAVE_OVERHEAD_MS - + GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS - + (11 * GITHUB_CONTENT_WRITE_INTERVAL_MS) - + (8 * DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS), - ); - }); - - test("splits only at the concurrency/window ceiling and rejects an oversized total handoff", () => { - const counts = new Map(Array.from({ length: 5 }, (_, index) => [`product-${index}`, 1])); - const plan = concurrentGithubReleaseAssetUploadPlan(counts, { - maxConcurrentProducts: 2, - maxHandoffWindowMs: 60 * 60_000, - }); - expect(plan.waves.map(({ products }) => products.length)).toEqual([2, 2, 1]); - expect(concurrentGithubReleaseAssetUploadPlan( - new Map(Array.from({ length: 10 }, (_, index) => [`empty-${index}`, 0])), - )).toEqual({ - assetCount: 0, - productCount: 0, - selectionVerificationWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, - totalWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, - waves: [], - }); - }); - - test("rejects malformed or individually unbounded products before a wave starts", () => { - expect(() => concurrentGithubReleaseAssetUploadPlan(new Map())).toThrow(/non-empty product\/count map/u); - expect(() => concurrentGithubReleaseAssetUploadPlan(new Map([["oversized", 294]]))).toThrow( - /package the product into fewer aggregate assets/u, - ); - }); -}); diff --git a/tools/release/github-release-asset-upload-plan.test.mts b/tools/release/github-release-asset-upload-plan.test.mts new file mode 100644 index 000000000..53fd95016 --- /dev/null +++ b/tools/release/github-release-asset-upload-plan.test.mts @@ -0,0 +1,58 @@ +import { describe, expect, test } from 'bun:test'; + +import { + concurrentGithubReleaseAssetUploadPlan, + GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, + GITHUB_RELEASE_ASSET_WAVE_OVERHEAD_MS, + githubReleaseAssetUploadWaveWindowMs, +} from './github-release-asset-upload-plan.mts'; +import { GITHUB_CONTENT_WRITE_INTERVAL_MS } from './github-content-write-pacer.mts'; +import { + DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, + GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, +} from './upload_github_release_assets.mts'; + +describe('bounded concurrent GitHub release asset upload plan', () => { + test('uses global pacing plus the longest sequential transport lane', () => { + const rows = [ + { product: 'large', assetCount: 8 }, + { product: 'small-a', assetCount: 3 }, + { product: 'small-b', assetCount: 0 }, + ]; + expect(githubReleaseAssetUploadWaveWindowMs(rows)).toBe( + GITHUB_RELEASE_ASSET_WAVE_OVERHEAD_MS + + GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS + + 11 * GITHUB_CONTENT_WRITE_INTERVAL_MS + + 8 * DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, + ); + }); + + test('splits only at the concurrency/window ceiling and rejects an oversized total handoff', () => { + const counts = new Map(Array.from({ length: 5 }, (_, index) => [`product-${index}`, 1])); + const plan = concurrentGithubReleaseAssetUploadPlan(counts, { + maxConcurrentProducts: 2, + maxHandoffWindowMs: 60 * 60_000, + }); + expect(plan.waves.map(({ products }) => products.length)).toEqual([2, 2, 1]); + expect( + concurrentGithubReleaseAssetUploadPlan( + new Map(Array.from({ length: 10 }, (_, index) => [`empty-${index}`, 0])), + ), + ).toEqual({ + assetCount: 0, + productCount: 0, + selectionVerificationWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, + totalWindowMs: GITHUB_RELEASE_ASSET_SELECTION_VERIFY_MS, + waves: [], + }); + }); + + test('rejects malformed or individually unbounded products before a wave starts', () => { + expect(() => concurrentGithubReleaseAssetUploadPlan(new Map())).toThrow( + /non-empty product\/count map/u, + ); + expect(() => concurrentGithubReleaseAssetUploadPlan(new Map([['oversized', 294]]))).toThrow( + /package the product into fewer aggregate assets/u, + ); + }); +}); diff --git a/tools/release/github-release-lineage.mjs b/tools/release/github-release-lineage.mjs deleted file mode 100644 index 60fc655a0..000000000 --- a/tools/release/github-release-lineage.mjs +++ /dev/null @@ -1,29 +0,0 @@ -const FULL_SHA = /^[0-9a-f]{40}$/u; -const POSITIVE_INTEGER = /^[1-9][0-9]*$/u; - -export class GitHubReleaseLineageError extends Error { - constructor(message) { - super(`github-release-lineage: ${message}`); - this.name = "GitHubReleaseLineageError"; - } -} -function fail(message) { - throw new GitHubReleaseLineageError(message); -} - -/** Each job owns a runner-local request journal. A rerun starts a new one. */ -export function githubReleaseLineageIdentity(environment = process.env) { - const repository = environment.GITHUB_REPOSITORY?.trim() ?? ""; - const currentRunId = environment.GITHUB_RUN_ID?.trim() ?? ""; - const headSha = (environment.RELEASE_HEAD_SHA ?? environment.GITHUB_SHA ?? "").trim(); - if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository)) { - fail("GITHUB_REPOSITORY must be OWNER/NAME"); - } - if (!POSITIVE_INTEGER.test(currentRunId)) { - fail("GITHUB_RUN_ID must be a positive integer"); - } - if (!FULL_SHA.test(headSha)) { - fail("RELEASE_HEAD_SHA or GITHUB_SHA must be a full lowercase commit SHA"); - } - return { headSha, repository, runId: currentRunId }; -} diff --git a/tools/release/github-release-lineage.mts b/tools/release/github-release-lineage.mts new file mode 100644 index 000000000..3c342015c --- /dev/null +++ b/tools/release/github-release-lineage.mts @@ -0,0 +1,29 @@ +const FULL_SHA = /^[0-9a-f]{40}$/u; +const POSITIVE_INTEGER = /^[1-9][0-9]*$/u; + +export class GitHubReleaseLineageError extends Error { + constructor(message) { + super(`github-release-lineage: ${message}`); + this.name = 'GitHubReleaseLineageError'; + } +} +function fail(message) { + throw new GitHubReleaseLineageError(message); +} + +/** Each job owns a runner-local request journal. A rerun starts a new one. */ +export function githubReleaseLineageIdentity(environment = process.env) { + const repository = environment.GITHUB_REPOSITORY?.trim() ?? ''; + const currentRunId = environment.GITHUB_RUN_ID?.trim() ?? ''; + const headSha = (environment.RELEASE_HEAD_SHA ?? environment.GITHUB_SHA ?? '').trim(); + if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository)) { + fail('GITHUB_REPOSITORY must be OWNER/NAME'); + } + if (!POSITIVE_INTEGER.test(currentRunId)) { + fail('GITHUB_RUN_ID must be a positive integer'); + } + if (!FULL_SHA.test(headSha)) { + fail('RELEASE_HEAD_SHA or GITHUB_SHA must be a full lowercase commit SHA'); + } + return { headSha, repository, runId: currentRunId }; +} diff --git a/tools/release/github-release-lineage.test.mjs b/tools/release/github-release-lineage.test.mjs deleted file mode 100644 index 106accf15..000000000 --- a/tools/release/github-release-lineage.test.mjs +++ /dev/null @@ -1,21 +0,0 @@ -import { expect, test } from "bun:test"; - -import { githubReleaseLineageIdentity } from "./github-release-lineage.mjs"; - -const base = { - GITHUB_REPOSITORY: "f0rr0/oliphaunt", - GITHUB_RUN_ID: "200", - GITHUB_SHA: "a".repeat(40), -}; - -test("uses the current run for the runner-local journal", () => { - expect(githubReleaseLineageIdentity(base)).toEqual({ - headSha: "a".repeat(40), - repository: "f0rr0/oliphaunt", - runId: "200", - }); -}); - -test("rejects a malformed current run identity", () => { - expect(() => githubReleaseLineageIdentity({ ...base, GITHUB_RUN_ID: "" })).toThrow("GITHUB_RUN_ID"); -}); diff --git a/tools/release/github-release-lineage.test.mts b/tools/release/github-release-lineage.test.mts new file mode 100644 index 000000000..edc11f133 --- /dev/null +++ b/tools/release/github-release-lineage.test.mts @@ -0,0 +1,23 @@ +import { expect, test } from 'bun:test'; + +import { githubReleaseLineageIdentity } from './github-release-lineage.mts'; + +const base = { + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_RUN_ID: '200', + GITHUB_SHA: 'a'.repeat(40), +}; + +test('uses the current run for the runner-local journal', () => { + expect(githubReleaseLineageIdentity(base)).toEqual({ + headSha: 'a'.repeat(40), + repository: 'f0rr0/oliphaunt', + runId: '200', + }); +}); + +test('rejects a malformed current run identity', () => { + expect(() => githubReleaseLineageIdentity({ ...base, GITHUB_RUN_ID: '' })).toThrow( + 'GITHUB_RUN_ID', + ); +}); diff --git a/tools/release/github-release-mutations.mjs b/tools/release/github-release-mutations.mjs deleted file mode 100644 index 9ff87464f..000000000 --- a/tools/release/github-release-mutations.mjs +++ /dev/null @@ -1,809 +0,0 @@ -import process from "node:process"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { - githubReadOptionsFromEnv, - redactGitHubReadDetail, - runGitHubPaginatedJsonSync, - runGitHubReadSync, -} from "./github-read.mjs"; -import { reserveGitHubContentWriteSync } from "./github-content-write-pacer.mjs"; -import { reserveGitHubCoreRequestSync } from "./github-core-request-journal.mjs"; - -const DEFAULT_MUTATION_ATTEMPT_TIMEOUT_MS = 60_000; -const DEFAULT_MUTATION_BASE_DELAY_MS = 1_000; -const DEFAULT_MUTATION_MAX_ATTEMPTS = 3; -const DEFAULT_OPERATION_WINDOW_MS = 15 * 60_000; -const DEFAULT_HARD_DEADLINE_RESERVE_MS = 30_000; -const INTEGER = /^(?:0|[1-9][0-9]*)$/u; -const FULL_SHA = /^[0-9a-f]{40}$/u; -const MAX_MUTATION_CAPTURE_BYTES = 4 * 1024 * 1024; -const RECONCILIATION_KINDS = new Set(["absent", "conflict", "desired", "unchanged"]); - -export const GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS = - Object.freeze([2_000, 4_000, 8_000, 16_000, 30_000, 30_000]); -export const GITHUB_RELEASE_SNAPSHOT_MAX_READS = - GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.length + 1; -export const GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS = 10_000; -export const GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS = 1; -export const GITHUB_RELEASE_SNAPSHOT_VISIBILITY_WINDOW_MS = - GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.reduce((total, delay) => total + delay, 0); - -export class GitHubReleaseMutationError extends Error { - constructor(message, options = {}) { - super(message, options); - this.name = "GitHubReleaseMutationError"; - } -} - -export class GitHubReleaseSnapshotRaceError extends GitHubReleaseMutationError { - constructor(message, { observedRelease = undefined, ...options } = {}) { - super(message, options); - this.name = "GitHubReleaseSnapshotRaceError"; - this.observedRelease = observedRelease; - } -} - -function mutationError(message, options = {}) { - return new GitHubReleaseMutationError(message, options); -} - -function releaseSnapshotRaceError(message, options = {}) { - return new GitHubReleaseSnapshotRaceError(message, options); -} - -function nonNegativeInteger(environment, name, fallback, { maximum = Number.MAX_SAFE_INTEGER, minimum = 0 } = {}) { - const raw = environment[name]; - if (raw === undefined || raw === "") return fallback; - if (!INTEGER.test(raw)) { - throw mutationError(`${name} must be an integer`); - } - const value = Number(raw); - if (!Number.isSafeInteger(value) || value < minimum || value > maximum) { - throw mutationError(`${name} must be between ${minimum} and ${maximum}`); - } - return value; -} - -function safeDetail(error, environment) { - const parts = []; - let current = error; - for (let depth = 0; current !== undefined && current !== null && depth < 8; depth += 1) { - if (typeof current === "string") { - parts.push(current); - break; - } - if (typeof current.message === "string") parts.push(current.message); - if (typeof current.detail === "string") parts.push(current.detail); - current = current.cause; - } - return redactGitHubReadDetail(parts.join("\n"), environment); -} - -export function isExplicitGitHubNotFound(error) { - let current = error; - for (let depth = 0; current !== undefined && current !== null && depth < 8; depth += 1) { - if (current.httpStatus === 404) return true; - const text = [current.message, current.detail] - .filter((value) => typeof value === "string") - .join("\n"); - if (/\bHTTP(?: status)?[ :=]*(?:status code[ :=]*)?404\b/iu.test(text)) return true; - current = current.cause; - } - return false; -} - -export function releaseNotesForVersion(changelog, version) { - if (typeof changelog !== "string" || typeof version !== "string" || version.length === 0) { - throw new TypeError("releaseNotesForVersion requires changelog text and a version"); - } - const lines = changelog.split(/\r?\n/u); - const headingIndex = lines.findIndex((line) => { - const heading = line.match(/^##[ \t]+(?:\[)?([^\] (]+)(?:\])?(?:[ \t(]|$)/u)?.[1]; - return heading === version; - }); - if (headingIndex === -1) { - throw new Error(`changelog has no release heading for ${version}`); - } - let end = lines.length; - for (let index = headingIndex + 1; index < lines.length; index += 1) { - if (/^##[ \t]+/u.test(lines[index])) { - end = index; - break; - } - } - const notes = lines.slice(headingIndex + 1, end).join("\n").trim(); - return notes || `Release ${version}.`; -} - -export function exactTagRefPayload(tag, headRef) { - if (typeof tag !== "string" || tag.length === 0 || !FULL_SHA.test(headRef)) { - throw new TypeError("exactTagRefPayload requires a tag and a full lowercase commit SHA"); - } - return { ref: `refs/tags/${tag}`, sha: headRef }; -} - -export function exactReleaseMetadata({ body, headRef, product, tag, version }) { - for (const [label, value] of Object.entries({ body, product, tag, version })) { - if (typeof value !== "string" || value.length === 0) { - throw new TypeError(`exactReleaseMetadata requires a non-empty ${label}`); - } - } - if (!FULL_SHA.test(headRef)) { - throw new TypeError("exactReleaseMetadata requires a full lowercase commit SHA"); - } - return { - body, - name: `${product} v${version}`, - prerelease: version.includes("-"), - tag_name: tag, - target_commitish: headRef, - }; -} - -function assertReleaseShape(release, context = "GitHub release") { - if (release === null || Array.isArray(release) || typeof release !== "object") { - throw new TypeError(`${context} metadata must be an object`); - } - if (!Number.isSafeInteger(release.id) || release.id <= 0) { - throw new TypeError(`${context} id must be a positive integer`); - } - if (typeof release.draft !== "boolean" || typeof release.prerelease !== "boolean") { - throw new TypeError(`${context} draft and prerelease fields must be booleans`); - } - if (typeof release.tag_name !== "string" || release.tag_name.length === 0) { - throw new TypeError(`${context} tag_name must be a non-empty string`); - } - for (const field of ["body", "name", "target_commitish"]) { - if (release[field] !== null && typeof release[field] !== "string") { - throw new TypeError(`${context} ${field} must be a string or null`); - } - } - return release; -} - -export function assertResumableReleaseMetadata(release, expected) { - assertReleaseShape(release, "existing GitHub release"); - const conflicts = []; - for (const field of ["tag_name", "name", "body", "prerelease", "target_commitish"]) { - if (release[field] !== expected[field]) { - conflicts.push( - `${field}=${JSON.stringify(release[field])}, expected ${JSON.stringify(expected[field])}`, - ); - } - } - if (conflicts.length > 0) { - throw new Error( - `${expected.tag_name} existing GitHub release ${release.id} conflicts with frozen release metadata: ${conflicts.join("; ")}`, - ); - } - return release; -} - -function repositoryPath(repo) { - if (typeof repo !== "string" || !/^[^/\s]+\/[^/\s]+$/u.test(repo)) { - throw mutationError("GitHub repository must be OWNER/NAME"); - } - return `repos/${repo}`; -} - -function endpointSegment(value, label) { - if (typeof value !== "string" || value.length === 0 || /[\u0000-\u001f\u007f]/u.test(value)) { - throw mutationError(`${label} must be a non-empty printable string`); - } - return encodeURIComponent(value); -} - -function parseJson(output, label) { - let value; - try { - value = JSON.parse(output); - } catch (error) { - throw mutationError(`${label} returned malformed JSON`, { cause: error }); - } - return value; -} - -export function githubJsonReadSync(args, options = {}) { - const label = options.label ?? "GitHub JSON read"; - return parseJson(runGitHubReadSync(args, { ...options, label }), label); -} - -export function githubPaginatedArrayReadSync(repo, resource, options = {}) { - const prefix = repositoryPath(repo); - if ( - typeof resource !== "string" - || resource.length === 0 - || !/^[A-Za-z0-9_.~%/-]+$/u.test(resource) - || resource.startsWith("/") - || resource.endsWith("/") - || resource.split("/").some((segment) => segment === "" || segment === "." || segment === "..") - ) { - throw mutationError("GitHub paginated resource path is malformed"); - } - return runGitHubPaginatedJsonSync(`${prefix}/${resource}`, { - ...options, - itemsField: null, - label: options.label ?? "GitHub paginated array read", - }); -} - -export function githubOptionalJsonReadSync(args, options = {}) { - try { - return githubJsonReadSync(args, options); - } catch (error) { - if (isExplicitGitHubNotFound(error)) return null; - throw error; - } -} - -export function readTagRefSync(repo, tag, options = {}) { - const label = `GitHub tag ref ${tag}`; - const value = githubOptionalJsonReadSync( - ["api", `${repositoryPath(repo)}/git/ref/tags/${endpointSegment(tag, "tag")}`], - { ...options, label }, - ); - if (value === null) return null; - if ( - value === null - || Array.isArray(value) - || typeof value !== "object" - || value.ref !== `refs/tags/${tag}` - || value.object === null - || Array.isArray(value.object) - || typeof value.object !== "object" - || typeof value.object.sha !== "string" - || !FULL_SHA.test(value.object.sha) - || typeof value.object.type !== "string" - ) { - throw mutationError(`${label} returned malformed metadata`); - } - return { ref: value.ref, sha: value.object.sha, type: value.object.type }; -} - -export function readReleaseByTagSync(repo, tag, options = {}) { - const label = `GitHub release for tag ${tag}`; - const value = githubOptionalJsonReadSync( - ["api", `${repositoryPath(repo)}/releases/tags/${endpointSegment(tag, "tag")}`], - { ...options, label }, - ); - return value === null ? null : assertReleaseShape(value, label); -} - -export function readReleaseByIdSync(repo, releaseId, options = {}) { - if (!Number.isSafeInteger(releaseId) || releaseId <= 0) { - throw mutationError("GitHub release id must be a positive integer"); - } - const label = `GitHub release ${releaseId}`; - const value = githubOptionalJsonReadSync( - ["api", `${repositoryPath(repo)}/releases/${releaseId}`], - { ...options, label }, - ); - return value === null ? null : assertReleaseShape(value, label); -} - -export function readReleaseMapSync(repo, options = {}) { - const label = "GitHub release list"; - const releases = githubPaginatedArrayReadSync(repo, "releases", { ...options, label }); - const byTag = new Map(); - const byId = new Map(); - for (const release of releases) { - assertReleaseShape(release); - const priorId = byId.get(release.id); - if (priorId !== undefined) { - const stableFields = ["body", "name", "prerelease", "tag_name", "target_commitish"]; - const changedField = stableFields.find((field) => priorId[field] !== release[field]); - if (changedField !== undefined) { - throw mutationError( - `GitHub returned release ${release.id} more than once with conflicting ${changedField} metadata`, - ); - } - throw releaseSnapshotRaceError( - `GitHub release list repeated release ${release.id} across one paginated snapshot`, - { observedRelease: release }, - ); - } - if (byTag.has(release.tag_name)) { - throw mutationError(`GitHub returned duplicate releases for tag ${release.tag_name}`); - } - byId.set(release.id, release); - byTag.set(release.tag_name, release); - } - return byTag; -} - -function assertReleaseAssetShape(asset, context) { - if (asset === null || Array.isArray(asset) || typeof asset !== "object") { - throw mutationError(`${context} must be an object`); - } - if (!Number.isSafeInteger(asset.id) || asset.id <= 0) { - throw mutationError(`${context} id must be a positive integer`); - } - if (typeof asset.name !== "string" || asset.name.length === 0) { - throw mutationError(`${context} name must be a non-empty string`); - } - if (!Number.isSafeInteger(asset.size) || asset.size < 0 || asset.state !== "uploaded") { - throw mutationError(`${context} must have a non-negative size and uploaded state`); - } - if ( - asset.digest !== undefined - && asset.digest !== null - && !/^sha256:[0-9a-f]{64}$/u.test(asset.digest) - ) { - throw mutationError(`${context} digest is malformed`); - } - return asset; -} - -export function readReleaseAssetsSync(repo, releaseId, options = {}) { - if (!Number.isSafeInteger(releaseId) || releaseId <= 0) { - throw mutationError("GitHub release id must be a positive integer"); - } - const label = `GitHub release ${releaseId} asset list`; - const assets = githubPaginatedArrayReadSync(repo, `releases/${releaseId}/assets`, { ...options, label }); - const byName = new Map(); - const ids = new Set(); - for (const asset of assets) { - assertReleaseAssetShape(asset, `${label} entry`); - if (byName.has(asset.name) || ids.has(asset.id)) { - throw mutationError(`${label} contains a duplicate asset name or id`); - } - byName.set(asset.name, asset); - ids.add(asset.id); - } - return byName; -} - -export function createGitHubOperationBudget({ - defaultWindowMs = DEFAULT_OPERATION_WINDOW_MS, - environment = process.env, - now = Date.now, -} = {}) { - if (!Number.isSafeInteger(defaultWindowMs) || defaultWindowMs <= 0) { - throw mutationError("default GitHub operation window must be a positive integer"); - } - const startedAtMs = now(); - const windowMs = nonNegativeInteger( - environment, - "OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS", - defaultWindowMs, - { maximum: 60 * 60_000, minimum: 1 }, - ); - const reserveMs = nonNegativeInteger( - environment, - "OLIPHAUNT_GITHUB_HARD_DEADLINE_RESERVE_MS", - DEFAULT_HARD_DEADLINE_RESERVE_MS, - { maximum: 10 * 60_000 }, - ); - let deadlineMs = startedAtMs + windowMs; - const hardDeadline = environment.REGISTRY_JOB_HARD_DEADLINE_EPOCH; - if (hardDeadline !== undefined && hardDeadline !== "") { - if (!/^[1-9][0-9]*$/u.test(hardDeadline)) { - throw mutationError("REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp"); - } - const hardDeadlineMs = Number(hardDeadline) * 1_000; - if (!Number.isSafeInteger(hardDeadlineMs)) { - throw mutationError("REGISTRY_JOB_HARD_DEADLINE_EPOCH exceeds the safe timestamp range"); - } - deadlineMs = Math.min(deadlineMs, hardDeadlineMs - reserveMs); - } - if (deadlineMs <= startedAtMs) { - throw mutationError("GitHub operation deadline has already expired"); - } - return Object.freeze({ deadlineMs, environment, now, startedAtMs }); -} - -export function remainingGitHubReadOptions(budget, overrides = {}) { - const remainingMs = budget.deadlineMs - budget.now(); - if (remainingMs <= 0) { - throw mutationError("GitHub operation deadline has been reached"); - } - const configured = githubReadOptionsFromEnv(budget.environment); - return { - ...overrides, - deadlineMs: Math.max(1, Math.min(configured.deadlineMs, remainingMs)), - environment: budget.environment, - }; -} - -function mutationSettings(environment, overrides) { - const settings = { - attemptTimeoutMs: overrides.attemptTimeoutMs ?? nonNegativeInteger( - environment, - "OLIPHAUNT_GITHUB_MUTATION_ATTEMPT_TIMEOUT_MS", - DEFAULT_MUTATION_ATTEMPT_TIMEOUT_MS, - { maximum: 2 * 60_000, minimum: 1 }, - ), - baseDelayMs: overrides.baseDelayMs ?? nonNegativeInteger( - environment, - "OLIPHAUNT_GITHUB_MUTATION_BASE_DELAY_MS", - DEFAULT_MUTATION_BASE_DELAY_MS, - { maximum: 30_000 }, - ), - maxAttempts: overrides.maxAttempts ?? nonNegativeInteger( - environment, - "OLIPHAUNT_GITHUB_MUTATION_MAX_ATTEMPTS", - DEFAULT_MUTATION_MAX_ATTEMPTS, - { maximum: 5, minimum: 1 }, - ), - }; - if ( - !Number.isSafeInteger(settings.attemptTimeoutMs) - || settings.attemptTimeoutMs < 1 - || settings.attemptTimeoutMs > 2 * 60_000 - || !Number.isSafeInteger(settings.baseDelayMs) - || settings.baseDelayMs < 0 - || settings.baseDelayMs > 30_000 - || !Number.isSafeInteger(settings.maxAttempts) - || settings.maxAttempts < 1 - || settings.maxAttempts > 5 - ) { - throw mutationError("GitHub mutation retry settings exceed their fixed safety bounds"); - } - return settings; -} - -function assertReconciliationState(state, label) { - if ( - state === null - || Array.isArray(state) - || typeof state !== "object" - || !RECONCILIATION_KINDS.has(state.kind) - ) { - throw mutationError(`${label}: state inspection returned an invalid reconciliation result`); - } - return state; -} - -function reconciliationConflict(label, state, environment) { - const detail = redactGitHubReadDetail(state.detail ?? "remote state conflicts", environment); - return mutationError(`${label}: ${detail}`); -} - -function sleepSync(milliseconds) { - if (milliseconds <= 0) return; - const cell = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)); - Atomics.wait(cell, 0, 0, milliseconds); -} - -export function reconcileGitHubMutationSync({ inspect, label, mutate, options = {} }) { - if (typeof label !== "string" || label.length === 0) { - throw mutationError("GitHub mutation label is required"); - } - if (typeof inspect !== "function" || typeof mutate !== "function") { - throw mutationError(`${label}: inspect and mutate callbacks are required`); - } - const environment = options.environment ?? process.env; - const now = options.now ?? options.budget?.now ?? Date.now; - const sleep = options.sleep ?? sleepSync; - const budget = options.budget ?? createGitHubOperationBudget({ environment, now }); - const settings = mutationSettings(environment, options); - let mutationAttempts = 0; - let lastMutationError = null; - - const inspectState = (phase) => { - const remainingMs = budget.deadlineMs - now(); - if (remainingMs <= 0) { - throw mutationError(`${label}: GitHub mutation deadline reached before ${phase}`); - } - return assertReconciliationState( - inspect({ attempt: mutationAttempts, phase, remainingMs }), - label, - ); - }; - - while (mutationAttempts < settings.maxAttempts) { - const before = inspectState("pre-mutation reconciliation"); - if (before.kind === "desired") { - return { mutationAttempts, recovered: mutationAttempts > 0 && lastMutationError !== null }; - } - if (before.kind === "conflict") { - throw reconciliationConflict(label, before, environment); - } - - const remainingMs = budget.deadlineMs - now(); - if (remainingMs < settings.attemptTimeoutMs) { - throw mutationError(`${label}: GitHub mutation deadline reached before attempt ${mutationAttempts + 1}`); - } - mutationAttempts += 1; - lastMutationError = null; - try { - mutate({ - attempt: mutationAttempts, - deadlineMs: budget.deadlineMs, - now, - timeoutMs: settings.attemptTimeoutMs, - }); - } catch (error) { - lastMutationError = error; - } - - const after = inspectState("post-mutation reconciliation"); - if (after.kind === "desired") { - return { mutationAttempts, recovered: lastMutationError !== null }; - } - if (after.kind === "conflict") { - throw reconciliationConflict(label, after, environment); - } - if (mutationAttempts >= settings.maxAttempts) break; - - const delayMs = settings.baseDelayMs * mutationAttempts; - if (budget.deadlineMs - now() <= delayMs) { - throw mutationError(`${label}: retry delay would exceed the GitHub mutation deadline`, { - cause: lastMutationError ?? undefined, - }); - } - sleep(delayMs); - } - - const detail = lastMutationError === null - ? "mutation returned without the exact desired state becoming observable" - : `mutation failed and exact state remained absent or unchanged: ${safeDetail(lastMutationError, environment)}`; - throw mutationError( - `${label}: exhausted ${mutationAttempts} mutation attempt(s); ${detail}`, - { cause: lastMutationError ?? undefined }, - ); -} - -function assertExactKeys(value, expected, label) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw mutationError(`${label} payload must be an object`); - } - const actual = Object.keys(value).sort(); - const wanted = [...expected].sort(); - if (actual.length !== wanted.length || actual.some((key, index) => key !== wanted[index])) { - throw mutationError(`${label} payload fields are not the frozen mutation shape`); - } -} - -function assertJsonMutation(endpoint, method, args, input) { - if ( - args.length !== 6 - || args[2] !== "-X" - || args[3] !== method - || args[4] !== "--input" - || args[5] !== "-" - || typeof input !== "string" - || Buffer.byteLength(input, "utf8") > 1024 * 1024 - ) { - throw mutationError("GitHub JSON mutation must use one exact method and stdin payload"); - } - let payload; - try { - payload = JSON.parse(input); - } catch (error) { - throw mutationError("GitHub JSON mutation payload is malformed", { cause: error }); - } - if (/\/git\/refs$/u.test(endpoint)) { - assertExactKeys(payload, ["ref", "sha"], "GitHub tag creation"); - if (!/^refs\/tags\/[^\u0000-\u001f\u007f]+$/u.test(payload.ref) || !FULL_SHA.test(payload.sha)) { - throw mutationError("GitHub tag creation payload must bind one tag to a full lowercase commit SHA"); - } - return; - } - if (/\/releases$/u.test(endpoint)) { - assertExactKeys( - payload, - ["body", "draft", "name", "prerelease", "tag_name", "target_commitish"], - "GitHub draft release creation", - ); - if ( - payload.draft !== true - || typeof payload.body !== "string" - || typeof payload.name !== "string" - || typeof payload.prerelease !== "boolean" - || typeof payload.tag_name !== "string" - || !FULL_SHA.test(payload.target_commitish) - ) { - throw mutationError("GitHub draft release payload is not exact-SHA frozen metadata"); - } - return; - } - if (/\/issues\/[1-9][0-9]*\/labels$/u.test(endpoint)) { - assertExactKeys(payload, ["labels"], "Release Please lifecycle label addition"); - if ( - !Array.isArray(payload.labels) - || payload.labels.length !== 1 - || payload.labels[0] !== "autorelease: tagged" - ) { - throw mutationError( - "Release Please lifecycle label addition may add only autorelease: tagged", - ); - } - return; - } - assertExactKeys(payload, ["draft"], "GitHub release promotion"); - if (payload.draft !== false) { - throw mutationError("GitHub release promotion may only clear the draft flag"); - } -} - -function assertAssetMutation(endpoint, args, input) { - if (input !== undefined || args.length !== 12 || args[2] !== "-X" || args[3] !== "POST") { - throw mutationError("GitHub release asset upload must use one exact-ID binary request"); - } - let url; - try { - url = new URL(endpoint); - } catch (error) { - throw mutationError("GitHub release asset upload endpoint is malformed", { cause: error }); - } - if ( - url.protocol !== "https:" - || url.hostname !== "uploads.github.com" - || !/^\/repos\/[^/\s]+\/[^/\s]+\/releases\/[1-9][0-9]*\/assets$/u.test(url.pathname) - || [...url.searchParams.keys()].length !== 1 - || !url.searchParams.has("name") - ) { - throw mutationError("GitHub release asset upload must target one canonical exact release id"); - } - const expectedHeaders = new Set([ - "Accept: application/vnd.github+json", - "Content-Type: application/octet-stream", - "X-GitHub-Api-Version: 2022-11-28", - ]); - const headers = []; - for (let index = 4; index < 10; index += 2) { - if (args[index] !== "-H") { - throw mutationError("GitHub release asset upload headers are not the frozen request shape"); - } - headers.push(args[index + 1]); - } - if (headers.length !== expectedHeaders.size || headers.some((header) => !expectedHeaders.has(header))) { - throw mutationError("GitHub release asset upload headers are not the frozen request shape"); - } - const file = args[10] === "--input" ? args[11] : ""; - const assetName = url.searchParams.get("name"); - if ( - typeof assetName !== "string" - || assetName.length === 0 - || /[\/\\\u0000-\u001f\u007f]/u.test(assetName) - || typeof file !== "string" - || file.length === 0 - || file.split(/[\\/]/u).at(-1) !== assetName - ) { - throw mutationError("GitHub release asset input must retain its frozen safe asset name"); - } -} - -function assertMutationArgs(args, input) { - if (!Array.isArray(args) || args.some((arg) => typeof arg !== "string")) { - throw mutationError("GitHub mutation requires gh arguments"); - } - if (args[0] !== "api") { - throw mutationError("GitHub mutation helper only permits an exact GitHub API release mutation"); - } - const endpoint = args[1]; - if (typeof endpoint !== "string") { - throw mutationError("GitHub API mutation endpoint is required"); - } - if (endpoint.startsWith("https://uploads.github.com/")) { - assertAssetMutation(endpoint, args, input); - return; - } - const tagCreate = /^repos\/[^/\s]+\/[^/\s]+\/git\/refs$/u.test(endpoint); - const releaseCreate = /^repos\/[^/\s]+\/[^/\s]+\/releases$/u.test(endpoint); - const releasePromote = /^repos\/[^/\s]+\/[^/\s]+\/releases\/[1-9][0-9]*$/u.test(endpoint); - const releasePleaseLabelAdd = - /^repos\/[^/\s]+\/[^/\s]+\/issues\/[1-9][0-9]*\/labels$/u.test(endpoint); - const releasePleasePendingLabelDelete = - /^repos\/[^/\s]+\/[^/\s]+\/issues\/[1-9][0-9]*\/labels\/autorelease%3A%20pending$/u.test( - endpoint, - ); - if (releasePleasePendingLabelDelete) { - if ( - args.length !== 4 - || args[2] !== "-X" - || args[3] !== "DELETE" - || input !== undefined - ) { - throw mutationError( - "Release Please lifecycle pending-label removal must use one exact DELETE without a payload", - ); - } - return; - } - if (!tagCreate && !releaseCreate && !releasePromote && !releasePleaseLabelAdd) { - throw mutationError("GitHub API mutation endpoint is outside the frozen release allowlist"); - } - assertJsonMutation( - endpoint, - releasePromote ? "PATCH" : "POST", - args, - input, - ); -} - -export function runGitHubMutationSync(args, options = {}) { - assertMutationArgs(args, options.input); - if ( - options.assertMutationAllowed !== undefined - && typeof options.assertMutationAllowed !== "function" - ) { - throw mutationError("GitHub mutation abort guard must be a function"); - } - if (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs <= 0) { - throw mutationError("GitHub mutation timeout must be a positive integer"); - } - const environment = options.environment ?? process.env; - const spawn = options.spawn; - const now = options.now ?? options.pacerOptions?.now ?? Date.now; - if ( - options.deadlineMs !== undefined - && (!Number.isSafeInteger(options.deadlineMs) || options.deadlineMs <= 0) - ) { - throw mutationError("GitHub mutation deadline must be a positive absolute timestamp"); - } - reserveGitHubContentWriteSync({ - environment, - label: options.pacerLabel ?? ( - String(args[1]).startsWith("https://uploads.github.com/") - ? "GitHub release asset upload" - : `GitHub release ${args[2] === "-X" ? args[3] : "mutation"}` - ), - ...(options.pacerOptions ?? {}), - }); - options.assertMutationAllowed?.(); - if (options.deadlineMs !== undefined) { - const remainingAfterPacingMs = options.deadlineMs - now(); - if (remainingAfterPacingMs < options.timeoutMs) { - throw mutationError( - `GitHub mutation requires its complete ${options.timeoutMs}ms transport timeout after pacing; ` - + `${Math.max(0, remainingAfterPacingMs)}ms remains`, - ); - } - } - reserveGitHubCoreRequestSync({ - environment, - label: options.coreRequestLabel ?? "GitHub release mutation", - ...(options.coreJournalOptions ?? {}), - }); - // Recheck after the independently locked request journal so a peer failure - // observed while this worker waited cannot leak a new mutation transport. - options.assertMutationAllowed?.(); - if (options.deadlineMs !== undefined) { - const remainingAfterJournalMs = options.deadlineMs - now(); - if (remainingAfterJournalMs < options.timeoutMs) { - throw mutationError( - `GitHub mutation requires its complete ${options.timeoutMs}ms transport timeout after request-journal admission; ` - + `${Math.max(0, remainingAfterJournalMs)}ms remains`, - ); - } - } - const spawnOptions = { - cwd: options.cwd, - encoding: "utf8", - env: environment, - input: options.input, - maxBuffer: options.maxBuffer ?? MAX_MUTATION_CAPTURE_BYTES, - stdio: [options.input === undefined ? "ignore" : "pipe", "pipe", "pipe"], - // Pacing is admission time, not request execution time. The request keeps - // its complete bounded transport timeout after the reserved slot opens. - timeout: options.timeoutMs, - windowsHide: true, - }; - const result = spawn === undefined - ? captureCommandOutput("gh", args, { - cwd: options.cwd, - env: environment, - input: options.input, - label: `gh ${args.join(" ")}`, - maxOutputBytes: options.maxBuffer ?? MAX_MUTATION_CAPTURE_BYTES, - timeout: options.timeoutMs, - windowsHide: true, - }) - : spawn("gh", args, spawnOptions); - if (result.error !== undefined) { - const error = mutationError("GitHub CLI could not complete the mutation"); - error.code = result.error.code; - error.detail = result.error.message; - throw error; - } - if (result.status !== 0) { - const error = mutationError(`GitHub mutation exited with status ${result.status}`); - error.status = result.status; - error.detail = String(result.stderr ?? ""); - throw error; - } - return result.stdout ?? ""; -} diff --git a/tools/release/github-release-mutations.mts b/tools/release/github-release-mutations.mts new file mode 100644 index 000000000..c8e47d01c --- /dev/null +++ b/tools/release/github-release-mutations.mts @@ -0,0 +1,792 @@ +import { createReadStream, lstatSync } from 'node:fs'; +import process from 'node:process'; +import { setTimeout as sleep } from 'node:timers/promises'; +import { reserveGitHubContentWrite } from './github-content-write-pacer.mts'; +import { reserveGitHubCoreRequest } from './github-core-request-journal.mts'; +import { + authHeaders, + boundedResponseBytes, + githubReadOptionsFromEnv, + redactGitHubReadDetail, + requestGithubPages, + requestGithubRepositoryJson, +} from './github-read.mts'; + +const DEFAULT_MUTATION_ATTEMPT_TIMEOUT_MS = 60_000; +const DEFAULT_MUTATION_BASE_DELAY_MS = 1_000; +const DEFAULT_MUTATION_MAX_ATTEMPTS = 3; +const DEFAULT_OPERATION_WINDOW_MS = 15 * 60_000; +const DEFAULT_HARD_DEADLINE_RESERVE_MS = 30_000; +const INTEGER = /^(?:0|[1-9][0-9]*)$/u; +const FULL_SHA = /^[0-9a-f]{40}$/u; +const MAX_MUTATION_CAPTURE_BYTES = 4 * 1024 * 1024; +const RECONCILIATION_KINDS = new Set(['absent', 'conflict', 'desired', 'unchanged']); + +export const GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS = Object.freeze([ + 2_000, 4_000, 8_000, 16_000, 30_000, 30_000, +]); +export const GITHUB_RELEASE_SNAPSHOT_MAX_READS = + GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.length + 1; +export const GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS = 10_000; +export const GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS = 1; +export const GITHUB_RELEASE_SNAPSHOT_VISIBILITY_WINDOW_MS = + GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.reduce((total, delay) => total + delay, 0); + +export class GitHubReleaseMutationError extends Error { + constructor(message, options = {}) { + super(message, options); + this.name = 'GitHubReleaseMutationError'; + } +} + +export class GitHubReleaseSnapshotRaceError extends GitHubReleaseMutationError { + constructor(message, { observedRelease = undefined, ...options } = {}) { + super(message, options); + this.name = 'GitHubReleaseSnapshotRaceError'; + this.observedRelease = observedRelease; + } +} + +function mutationError(message, options = {}) { + return new GitHubReleaseMutationError(message, options); +} + +function releaseSnapshotRaceError(message, options = {}) { + return new GitHubReleaseSnapshotRaceError(message, options); +} + +function nonNegativeInteger( + environment, + name, + fallback, + { maximum = Number.MAX_SAFE_INTEGER, minimum = 0 } = {}, +) { + const raw = environment[name]; + if (raw === undefined || raw === '') return fallback; + if (!INTEGER.test(raw)) { + throw mutationError(`${name} must be an integer`); + } + const value = Number(raw); + if (!Number.isSafeInteger(value) || value < minimum || value > maximum) { + throw mutationError(`${name} must be between ${minimum} and ${maximum}`); + } + return value; +} + +function safeDetail(error, environment) { + const parts = []; + let current = error; + for (let depth = 0; current !== undefined && current !== null && depth < 8; depth += 1) { + if (typeof current === 'string') { + parts.push(current); + break; + } + if (typeof current.message === 'string') parts.push(current.message); + if (typeof current.detail === 'string') parts.push(current.detail); + current = current.cause; + } + return redactGitHubReadDetail(parts.join('\n'), environment); +} + +export function isExplicitGitHubNotFound(error) { + let current = error; + for (let depth = 0; current !== undefined && current !== null && depth < 8; depth += 1) { + if (current.httpStatus === 404) return true; + const text = [current.message, current.detail] + .filter((value) => typeof value === 'string') + .join('\n'); + if (/\bHTTP(?: status)?[ :=]*(?:status code[ :=]*)?404\b/iu.test(text)) return true; + current = current.cause; + } + return false; +} + +export function releaseNotesForVersion(changelog, version) { + if (typeof changelog !== 'string' || typeof version !== 'string' || version.length === 0) { + throw new TypeError('releaseNotesForVersion requires changelog text and a version'); + } + const lines = changelog.split(/\r?\n/u); + const headingIndex = lines.findIndex((line) => { + const heading = line.match(/^##[ \t]+(?:\[)?([^\] (]+)(?:\])?(?:[ \t(]|$)/u)?.[1]; + return heading === version; + }); + if (headingIndex === -1) { + throw new Error(`changelog has no release heading for ${version}`); + } + let end = lines.length; + for (let index = headingIndex + 1; index < lines.length; index += 1) { + if (/^##[ \t]+/u.test(lines[index])) { + end = index; + break; + } + } + const notes = lines + .slice(headingIndex + 1, end) + .join('\n') + .trim(); + return notes || `Release ${version}.`; +} + +export function exactTagRefPayload(tag, headRef) { + if (typeof tag !== 'string' || tag.length === 0 || !FULL_SHA.test(headRef)) { + throw new TypeError('exactTagRefPayload requires a tag and a full lowercase commit SHA'); + } + return { ref: `refs/tags/${tag}`, sha: headRef }; +} + +export function exactReleaseMetadata({ body, headRef, product, tag, version }) { + for (const [label, value] of Object.entries({ body, product, tag, version })) { + if (typeof value !== 'string' || value.length === 0) { + throw new TypeError(`exactReleaseMetadata requires a non-empty ${label}`); + } + } + if (!FULL_SHA.test(headRef)) { + throw new TypeError('exactReleaseMetadata requires a full lowercase commit SHA'); + } + return { + body, + name: `${product} v${version}`, + prerelease: version.includes('-'), + tag_name: tag, + target_commitish: headRef, + }; +} + +function assertReleaseShape(release, context = 'GitHub release') { + if (release === null || Array.isArray(release) || typeof release !== 'object') { + throw new TypeError(`${context} metadata must be an object`); + } + if (!Number.isSafeInteger(release.id) || release.id <= 0) { + throw new TypeError(`${context} id must be a positive integer`); + } + if (typeof release.draft !== 'boolean' || typeof release.prerelease !== 'boolean') { + throw new TypeError(`${context} draft and prerelease fields must be booleans`); + } + if (typeof release.tag_name !== 'string' || release.tag_name.length === 0) { + throw new TypeError(`${context} tag_name must be a non-empty string`); + } + for (const field of ['body', 'name', 'target_commitish']) { + if (release[field] !== null && typeof release[field] !== 'string') { + throw new TypeError(`${context} ${field} must be a string or null`); + } + } + return release; +} + +export function assertResumableReleaseMetadata(release, expected) { + assertReleaseShape(release, 'existing GitHub release'); + const conflicts = []; + for (const field of ['tag_name', 'name', 'body', 'prerelease', 'target_commitish']) { + if (release[field] !== expected[field]) { + conflicts.push( + `${field}=${JSON.stringify(release[field])}, expected ${JSON.stringify(expected[field])}`, + ); + } + } + if (conflicts.length > 0) { + throw new Error( + `${expected.tag_name} existing GitHub release ${release.id} conflicts with frozen release metadata: ${conflicts.join('; ')}`, + ); + } + return release; +} + +function repositoryPath(repo) { + if ( + typeof repo !== 'string' || + !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repo) || + repo.split('/').some((part) => part === '.' || part === '..') + ) { + throw mutationError('GitHub repository must be OWNER/NAME'); + } + return `repos/${repo}`; +} + +function endpointSegment(value, label) { + if (typeof value !== 'string' || value.length === 0 || /[\u0000-\u001f\u007f]/u.test(value)) { + throw mutationError(`${label} must be a non-empty printable string`); + } + return encodeURIComponent(value); +} + +export async function githubPaginatedArrayRead(repo, resource, options = {}) { + const prefix = repositoryPath(repo); + if ( + typeof resource !== 'string' || + resource.length === 0 || + !/^[A-Za-z0-9_.~%/-]+$/u.test(resource) || + resource.startsWith('/') || + resource.endsWith('/') || + resource.split('/').some((segment) => segment === '' || segment === '.' || segment === '..') + ) { + throw mutationError('GitHub paginated resource path is malformed'); + } + return await requestGithubPages(`${prefix}/${resource}`, { + ...options, + itemsField: null, + label: options.label ?? 'GitHub paginated array read', + }); +} + +export async function githubOptionalJsonRead(args, options = {}) { + try { + return await requestGithubRepositoryJson(args, options); + } catch (error) { + if (isExplicitGitHubNotFound(error)) return null; + throw error; + } +} + +export async function readTagRef(repo, tag, options = {}) { + const label = `GitHub tag ref ${tag}`; + const value = await githubOptionalJsonRead( + `${repositoryPath(repo)}/git/ref/tags/${endpointSegment(tag, 'tag')}`, + { ...options, label }, + ); + if (value === null) return null; + if ( + value === null || + Array.isArray(value) || + typeof value !== 'object' || + value.ref !== `refs/tags/${tag}` || + value.object === null || + Array.isArray(value.object) || + typeof value.object !== 'object' || + typeof value.object.sha !== 'string' || + !FULL_SHA.test(value.object.sha) || + typeof value.object.type !== 'string' + ) { + throw mutationError(`${label} returned malformed metadata`); + } + return { ref: value.ref, sha: value.object.sha, type: value.object.type }; +} + +export async function readReleaseByTag(repo, tag, options = {}) { + const label = `GitHub release for tag ${tag}`; + const value = await githubOptionalJsonRead( + `${repositoryPath(repo)}/releases/tags/${endpointSegment(tag, 'tag')}`, + { ...options, label }, + ); + return value === null ? null : assertReleaseShape(value, label); +} + +export async function readReleaseById(repo, releaseId, options = {}) { + if (!Number.isSafeInteger(releaseId) || releaseId <= 0) { + throw mutationError('GitHub release id must be a positive integer'); + } + const label = `GitHub release ${releaseId}`; + const value = await githubOptionalJsonRead(`${repositoryPath(repo)}/releases/${releaseId}`, { + ...options, + label, + }); + return value === null ? null : assertReleaseShape(value, label); +} + +export async function readReleaseMap(repo, options = {}) { + const label = 'GitHub release list'; + const releases = await githubPaginatedArrayRead(repo, 'releases', { ...options, label }); + const byTag = new Map(); + const byId = new Map(); + for (const release of releases) { + assertReleaseShape(release); + const priorId = byId.get(release.id); + if (priorId !== undefined) { + const stableFields = ['body', 'name', 'prerelease', 'tag_name', 'target_commitish']; + const changedField = stableFields.find((field) => priorId[field] !== release[field]); + if (changedField !== undefined) { + throw mutationError( + `GitHub returned release ${release.id} more than once with conflicting ${changedField} metadata`, + ); + } + throw releaseSnapshotRaceError( + `GitHub release list repeated release ${release.id} across one paginated snapshot`, + { observedRelease: release }, + ); + } + if (byTag.has(release.tag_name)) { + throw mutationError(`GitHub returned duplicate releases for tag ${release.tag_name}`); + } + byId.set(release.id, release); + byTag.set(release.tag_name, release); + } + return byTag; +} + +function assertReleaseAssetShape(asset, context) { + if (asset === null || Array.isArray(asset) || typeof asset !== 'object') { + throw mutationError(`${context} must be an object`); + } + if (!Number.isSafeInteger(asset.id) || asset.id <= 0) { + throw mutationError(`${context} id must be a positive integer`); + } + if (typeof asset.name !== 'string' || asset.name.length === 0) { + throw mutationError(`${context} name must be a non-empty string`); + } + if (!Number.isSafeInteger(asset.size) || asset.size < 0 || asset.state !== 'uploaded') { + throw mutationError(`${context} must have a non-negative size and uploaded state`); + } + if ( + asset.digest !== undefined && + asset.digest !== null && + !/^sha256:[0-9a-f]{64}$/u.test(asset.digest) + ) { + throw mutationError(`${context} digest is malformed`); + } + return asset; +} + +export async function readReleaseAssets(repo, releaseId, options = {}) { + if (!Number.isSafeInteger(releaseId) || releaseId <= 0) { + throw mutationError('GitHub release id must be a positive integer'); + } + const label = `GitHub release ${releaseId} asset list`; + const assets = await githubPaginatedArrayRead(repo, `releases/${releaseId}/assets`, { + ...options, + label, + }); + const byName = new Map(); + const ids = new Set(); + for (const asset of assets) { + assertReleaseAssetShape(asset, `${label} entry`); + if (byName.has(asset.name) || ids.has(asset.id)) { + throw mutationError(`${label} contains a duplicate asset name or id`); + } + byName.set(asset.name, asset); + ids.add(asset.id); + } + return byName; +} + +export function createGitHubOperationBudget({ + defaultWindowMs = DEFAULT_OPERATION_WINDOW_MS, + environment = process.env, + now = Date.now, +} = {}) { + if (!Number.isSafeInteger(defaultWindowMs) || defaultWindowMs <= 0) { + throw mutationError('default GitHub operation window must be a positive integer'); + } + const startedAtMs = now(); + const windowMs = nonNegativeInteger( + environment, + 'OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS', + defaultWindowMs, + { maximum: 60 * 60_000, minimum: 1 }, + ); + const reserveMs = nonNegativeInteger( + environment, + 'OLIPHAUNT_GITHUB_HARD_DEADLINE_RESERVE_MS', + DEFAULT_HARD_DEADLINE_RESERVE_MS, + { maximum: 10 * 60_000 }, + ); + let deadlineMs = startedAtMs + windowMs; + const hardDeadline = environment.REGISTRY_JOB_HARD_DEADLINE_EPOCH; + if (hardDeadline !== undefined && hardDeadline !== '') { + if (!/^[1-9][0-9]*$/u.test(hardDeadline)) { + throw mutationError('REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp'); + } + const hardDeadlineMs = Number(hardDeadline) * 1_000; + if (!Number.isSafeInteger(hardDeadlineMs)) { + throw mutationError('REGISTRY_JOB_HARD_DEADLINE_EPOCH exceeds the safe timestamp range'); + } + deadlineMs = Math.min(deadlineMs, hardDeadlineMs - reserveMs); + } + if (deadlineMs <= startedAtMs) { + throw mutationError('GitHub operation deadline has already expired'); + } + return Object.freeze({ deadlineMs, environment, now, startedAtMs }); +} + +export function remainingGitHubReadOptions(budget, overrides = {}) { + const remainingMs = budget.deadlineMs - budget.now(); + if (remainingMs <= 0) { + throw mutationError('GitHub operation deadline has been reached'); + } + const configured = githubReadOptionsFromEnv(budget.environment); + return { + ...overrides, + deadlineMs: Math.max(1, Math.min(configured.deadlineMs, remainingMs)), + environment: budget.environment, + }; +} + +function mutationSettings(environment, overrides) { + const settings = { + attemptTimeoutMs: + overrides.attemptTimeoutMs ?? + nonNegativeInteger( + environment, + 'OLIPHAUNT_GITHUB_MUTATION_ATTEMPT_TIMEOUT_MS', + DEFAULT_MUTATION_ATTEMPT_TIMEOUT_MS, + { maximum: 2 * 60_000, minimum: 1 }, + ), + baseDelayMs: + overrides.baseDelayMs ?? + nonNegativeInteger( + environment, + 'OLIPHAUNT_GITHUB_MUTATION_BASE_DELAY_MS', + DEFAULT_MUTATION_BASE_DELAY_MS, + { maximum: 30_000 }, + ), + maxAttempts: + overrides.maxAttempts ?? + nonNegativeInteger( + environment, + 'OLIPHAUNT_GITHUB_MUTATION_MAX_ATTEMPTS', + DEFAULT_MUTATION_MAX_ATTEMPTS, + { maximum: 5, minimum: 1 }, + ), + }; + if ( + !Number.isSafeInteger(settings.attemptTimeoutMs) || + settings.attemptTimeoutMs < 1 || + settings.attemptTimeoutMs > 2 * 60_000 || + !Number.isSafeInteger(settings.baseDelayMs) || + settings.baseDelayMs < 0 || + settings.baseDelayMs > 30_000 || + !Number.isSafeInteger(settings.maxAttempts) || + settings.maxAttempts < 1 || + settings.maxAttempts > 5 + ) { + throw mutationError('GitHub mutation retry settings exceed their fixed safety bounds'); + } + return settings; +} + +function assertReconciliationState(state, label) { + if ( + state === null || + Array.isArray(state) || + typeof state !== 'object' || + !RECONCILIATION_KINDS.has(state.kind) + ) { + throw mutationError(`${label}: state inspection returned an invalid reconciliation result`); + } + return state; +} + +function reconciliationConflict(label, state, environment) { + const detail = redactGitHubReadDetail(state.detail ?? 'remote state conflicts', environment); + return mutationError(`${label}: ${detail}`); +} + +export async function reconcileGitHubMutation({ inspect, label, mutate, options = {} }) { + if (typeof label !== 'string' || label.length === 0) { + throw mutationError('GitHub mutation label is required'); + } + if (typeof inspect !== 'function' || typeof mutate !== 'function') { + throw mutationError(`${label}: inspect and mutate callbacks are required`); + } + const environment = options.environment ?? process.env; + const now = options.now ?? options.budget?.now ?? Date.now; + const wait = options.sleep ?? sleep; + const budget = options.budget ?? createGitHubOperationBudget({ environment, now }); + const settings = mutationSettings(environment, options); + let mutationAttempts = 0; + let lastMutationError = null; + + const inspectState = async (phase) => { + const remainingMs = budget.deadlineMs - now(); + if (remainingMs <= 0) { + throw mutationError(`${label}: GitHub mutation deadline reached before ${phase}`); + } + return assertReconciliationState( + await inspect({ attempt: mutationAttempts, phase, remainingMs }), + label, + ); + }; + + while (mutationAttempts < settings.maxAttempts) { + const before = await inspectState('pre-mutation reconciliation'); + if (before.kind === 'desired') { + return { mutationAttempts, recovered: mutationAttempts > 0 && lastMutationError !== null }; + } + if (before.kind === 'conflict') { + throw reconciliationConflict(label, before, environment); + } + + const remainingMs = budget.deadlineMs - now(); + if (remainingMs < settings.attemptTimeoutMs) { + throw mutationError( + `${label}: GitHub mutation deadline reached before attempt ${mutationAttempts + 1}`, + ); + } + mutationAttempts += 1; + lastMutationError = null; + try { + await mutate({ + attempt: mutationAttempts, + deadlineMs: budget.deadlineMs, + now, + timeoutMs: settings.attemptTimeoutMs, + }); + } catch (error) { + lastMutationError = error; + } + + const after = await inspectState('post-mutation reconciliation'); + if (after.kind === 'desired') { + return { mutationAttempts, recovered: lastMutationError !== null }; + } + if (after.kind === 'conflict') { + throw reconciliationConflict(label, after, environment); + } + if (mutationAttempts >= settings.maxAttempts) break; + + const delayMs = settings.baseDelayMs * mutationAttempts; + if (budget.deadlineMs - now() <= delayMs) { + throw mutationError(`${label}: retry delay would exceed the GitHub mutation deadline`, { + cause: lastMutationError ?? undefined, + }); + } + await wait(delayMs); + } + + const detail = + lastMutationError === null + ? 'mutation returned without the exact desired state becoming observable' + : `mutation failed and exact state remained absent or unchanged: ${safeDetail(lastMutationError, environment)}`; + throw mutationError(`${label}: exhausted ${mutationAttempts} mutation attempt(s); ${detail}`, { + cause: lastMutationError ?? undefined, + }); +} + +function assertExactKeys(value, expected, label) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw mutationError(`${label} payload must be an object`); + } + const actual = Object.keys(value).sort(); + const wanted = [...expected].sort(); + if (actual.length !== wanted.length || actual.some((key, index) => key !== wanted[index])) { + throw mutationError(`${label} payload fields are not the frozen mutation shape`); + } +} + +function assertJsonMutation(endpoint, input) { + if (typeof input !== 'string' || Buffer.byteLength(input, 'utf8') > 1024 * 1024) { + throw mutationError('GitHub JSON mutation must use one bounded JSON payload'); + } + let payload; + try { + payload = JSON.parse(input); + } catch (error) { + throw mutationError('GitHub JSON mutation payload is malformed', { cause: error }); + } + if (/\/git\/refs$/u.test(endpoint)) { + assertExactKeys(payload, ['ref', 'sha'], 'GitHub tag creation'); + if ( + !/^refs\/tags\/[^\u0000-\u001f\u007f]+$/u.test(payload.ref) || + !FULL_SHA.test(payload.sha) + ) { + throw mutationError( + 'GitHub tag creation payload must bind one tag to a full lowercase commit SHA', + ); + } + return; + } + if (/\/releases$/u.test(endpoint)) { + assertExactKeys( + payload, + ['body', 'draft', 'name', 'prerelease', 'tag_name', 'target_commitish'], + 'GitHub draft release creation', + ); + if ( + payload.draft !== true || + typeof payload.body !== 'string' || + typeof payload.name !== 'string' || + typeof payload.prerelease !== 'boolean' || + typeof payload.tag_name !== 'string' || + !FULL_SHA.test(payload.target_commitish) + ) { + throw mutationError('GitHub draft release payload is not exact-SHA frozen metadata'); + } + return; + } + if (/\/issues\/[1-9][0-9]*\/labels$/u.test(endpoint)) { + assertExactKeys(payload, ['labels'], 'Release Please lifecycle label addition'); + if ( + !Array.isArray(payload.labels) || + payload.labels.length !== 1 || + payload.labels[0] !== 'autorelease: tagged' + ) { + throw mutationError( + 'Release Please lifecycle label addition may add only autorelease: tagged', + ); + } + return; + } + assertExactKeys(payload, ['draft'], 'GitHub release promotion'); + if (payload.draft !== false) { + throw mutationError('GitHub release promotion may only clear the draft flag'); + } +} + +function assertAssetMutation(endpoint, { method, file, input }) { + if (input !== undefined || method !== 'POST') { + throw mutationError('GitHub release asset upload must use one exact-ID binary request'); + } + let url; + try { + url = new URL(endpoint); + } catch (error) { + throw mutationError('GitHub release asset upload endpoint is malformed', { cause: error }); + } + if ( + url.origin !== 'https://uploads.github.com' || + url.username || + url.password || + url.hash || + !/^\/repos\/[^/\s]+\/[^/\s]+\/releases\/[1-9][0-9]*\/assets$/u.test(url.pathname) || + [...url.searchParams.keys()].length !== 1 || + !url.searchParams.has('name') + ) { + throw mutationError('GitHub release asset upload must target one canonical exact release id'); + } + repositoryPath(url.pathname.split('/').slice(2, 4).join('/')); + const assetName = url.searchParams.get('name'); + if ( + typeof assetName !== 'string' || + assetName.length === 0 || + /[\/\\\u0000-\u001f\u007f]/u.test(assetName) || + typeof file !== 'string' || + file.length === 0 || + file.split(/[\\/]/u).at(-1) !== assetName + ) { + throw mutationError('GitHub release asset input must retain its frozen safe asset name'); + } +} + +function assertMutationRequest(endpoint, { method, file, input }) { + if (typeof endpoint !== 'string') throw mutationError('GitHub mutation endpoint is required'); + if (endpoint.startsWith('https://uploads.github.com/')) { + assertAssetMutation(endpoint, { method, file, input }); + return; + } + repositoryPath(endpoint.split('/').slice(1, 3).join('/')); + const tagCreate = /^repos\/[^/\s]+\/[^/\s]+\/git\/refs$/u.test(endpoint); + const releaseCreate = /^repos\/[^/\s]+\/[^/\s]+\/releases$/u.test(endpoint); + const releasePromote = /^repos\/[^/\s]+\/[^/\s]+\/releases\/[1-9][0-9]*$/u.test(endpoint); + const releasePleaseLabelAdd = /^repos\/[^/\s]+\/[^/\s]+\/issues\/[1-9][0-9]*\/labels$/u.test( + endpoint, + ); + const releasePleasePendingLabelDelete = + /^repos\/[^/\s]+\/[^/\s]+\/issues\/[1-9][0-9]*\/labels\/autorelease%3A%20pending$/u.test( + endpoint, + ); + if (releasePleasePendingLabelDelete) { + if (method !== 'DELETE' || input !== undefined || file !== undefined) { + throw mutationError( + 'Release Please lifecycle pending-label removal must use one exact DELETE without a payload', + ); + } + return; + } + if (!tagCreate && !releaseCreate && !releasePromote && !releasePleaseLabelAdd) { + throw mutationError('GitHub API mutation endpoint is outside the frozen release allowlist'); + } + if (file !== undefined || method !== (releasePromote ? 'PATCH' : 'POST')) + throw mutationError( + 'GitHub mutation method or payload is outside the frozen release allowlist', + ); + assertJsonMutation(endpoint, input); +} + +export async function requestGithubMutation(endpoint, options = {}) { + assertMutationRequest(endpoint, options); + if ( + options.assertMutationAllowed !== undefined && + typeof options.assertMutationAllowed !== 'function' + ) { + throw mutationError('GitHub mutation abort guard must be a function'); + } + if (!Number.isSafeInteger(options.timeoutMs) || options.timeoutMs <= 0) { + throw mutationError('GitHub mutation timeout must be a positive integer'); + } + const environment = options.environment ?? process.env; + const now = options.now ?? options.pacerOptions?.now ?? Date.now; + if ( + options.deadlineMs !== undefined && + (!Number.isSafeInteger(options.deadlineMs) || options.deadlineMs <= 0) + ) { + throw mutationError('GitHub mutation deadline must be a positive absolute timestamp'); + } + await reserveGitHubContentWrite({ + environment, + label: + options.pacerLabel ?? + (endpoint.startsWith('https://uploads.github.com/') + ? 'GitHub release asset upload' + : `GitHub release ${options.method}`), + ...(options.pacerOptions ?? {}), + }); + options.assertMutationAllowed?.(); + if (options.deadlineMs !== undefined) { + const remainingAfterPacingMs = options.deadlineMs - now(); + if (remainingAfterPacingMs < options.timeoutMs) { + throw mutationError( + `GitHub mutation requires its complete ${options.timeoutMs}ms transport timeout after pacing; ` + + `${Math.max(0, remainingAfterPacingMs)}ms remains`, + ); + } + } + await reserveGitHubCoreRequest({ + environment, + label: options.coreRequestLabel ?? 'GitHub release mutation', + ...(options.coreJournalOptions ?? {}), + }); + // Recheck after the independently locked request journal so a peer failure + // observed while this worker waited cannot leak a new mutation transport. + options.assertMutationAllowed?.(); + if (options.deadlineMs !== undefined) { + const remainingAfterJournalMs = options.deadlineMs - now(); + if (remainingAfterJournalMs < options.timeoutMs) { + throw mutationError( + `GitHub mutation requires its complete ${options.timeoutMs}ms transport timeout after request-journal admission; ` + + `${Math.max(0, remainingAfterJournalMs)}ms remains`, + ); + } + } + const upload = endpoint.startsWith('https://uploads.github.com/'); + const url = upload ? endpoint : 'https://api.github.com/' + endpoint; + const headers = authHeaders( + 'application/vnd.github+json', + environment.GH_TOKEN || environment.GITHUB_TOKEN || '', + ); + let body = options.input; + if (upload) { + const file = options.file; + const stat = lstatSync(file); + if (!stat.isFile() || stat.isSymbolicLink()) + throw mutationError('GitHub upload requires a regular file'); + headers['Content-Type'] = 'application/octet-stream'; + headers['Content-Length'] = String(stat.size); + body = createReadStream(file); + } else if (body !== undefined) { + headers['Content-Type'] = 'application/json'; + } + try { + // Never replay a write here. Callers reconcile the exact remote state first. + const response = await (options.fetchImpl ?? fetch)(url, { + method: options.method, + headers, + body, + redirect: 'error', + signal: AbortSignal.timeout(options.timeoutMs), + ...(upload ? { duplex: 'half' } : {}), + }); + const bytes = await boundedResponseBytes( + response, + MAX_MUTATION_CAPTURE_BYTES, + 'GitHub mutation response', + ); + const text = new TextDecoder('utf-8', { fatal: true }).decode(bytes); + if (!response.ok) { + const error = mutationError(`GitHub mutation returned HTTP ${response.status}`); + error.httpStatus = response.status; + error.detail = redactGitHubReadDetail(text, environment); + throw error; + } + return text; + } finally { + if (upload) body.destroy(); + } +} diff --git a/tools/release/github-release-mutations.test.mjs b/tools/release/github-release-mutations.test.mjs deleted file mode 100644 index cfa2b455d..000000000 --- a/tools/release/github-release-mutations.test.mjs +++ /dev/null @@ -1,650 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - createGitHubOperationBudget, - GitHubReleaseSnapshotRaceError, - githubPaginatedArrayReadSync, - githubJsonReadSync, - githubOptionalJsonReadSync, - isExplicitGitHubNotFound, - readReleaseMapSync, - readTagRefSync, - reconcileGitHubMutationSync, - runGitHubMutationSync, -} from "./github-release-mutations.mjs"; -import { readGitHubCoreRequestJournal } from "./github-core-request-journal.mjs"; - -function fixedBudget(deadlineMs = 180_000, now = () => 0, environment = {}) { - return { deadlineMs, environment, now, startedAtMs: now() }; -} - -const deterministic = { - baseDelayMs: 0, - environment: {}, - maxAttempts: 3, - sleep: () => {}, -}; - -function journalFixture() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-paginated-read-")); - return { - environment: { - GITHUB_ACTIONS: "true", - GITHUB_REPOSITORY: "o/r", - GITHUB_RUN_ATTEMPT: "1", - GITHUB_RUN_ID: "123", - GITHUB_SHA: "a".repeat(40), - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, "journal.json"), - OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: "true", - }, - root, - }; -} - -function releaseRows(firstId, count) { - return Array.from({ length: count }, (_, offset) => { - const id = firstId + offset; - return { - body: `release ${id}`, - draft: true, - id, - name: `release ${id}`, - prerelease: false, - tag_name: `v${id}`, - target_commitish: "a".repeat(40), - }; - }); -} - -function includedJson(data, link = "") { - return [ - "HTTP/2.0 200 OK", - "Content-Type: application/json; charset=utf-8", - ...(link === "" ? [] : [`Link: ${link}`]), - "", - JSON.stringify(data), - ].join("\n"); -} - -function deterministicReadOptions(environment, spawn) { - return { - baseDelayMs: 0, - coreJournalOptions: { now: () => 20_000 }, - deadlineMs: 1_000, - environment, - maxAttempts: 2, - maxDelayMs: 0, - now: () => 20_000, - sleep: () => {}, - spawn, - }; -} - -test("a successful mutation is followed by exact-state reconciliation", () => { - let present = false; - let mutationCalls = 0; - const result = reconcileGitHubMutationSync({ - inspect: () => ({ kind: present ? "desired" : "absent" }), - label: "create tag", - mutate: () => { - mutationCalls += 1; - present = true; - }, - options: { ...deterministic, budget: fixedBudget() }, - }); - assert.equal(mutationCalls, 1); - assert.deepEqual(result, { mutationAttempts: 1, recovered: false }); -}); - -test("pre-send failure retries only after a fresh read proves absence", () => { - let present = false; - let mutationCalls = 0; - let inspections = 0; - const result = reconcileGitHubMutationSync({ - inspect: () => { - inspections += 1; - return { kind: present ? "desired" : "absent" }; - }, - label: "create release", - mutate: () => { - mutationCalls += 1; - if (mutationCalls === 1) throw new Error("connect failed before request write"); - present = true; - }, - options: { ...deterministic, budget: fixedBudget() }, - }); - assert.equal(mutationCalls, 2); - assert.ok(inspections >= 4, "state is inspected before and after each attempted mutation"); - assert.deepEqual(result, { mutationAttempts: 2, recovered: false }); -}); - -test("an applied mutation followed by timeout is accepted without duplicate replay", () => { - let present = false; - let mutationCalls = 0; - const result = reconcileGitHubMutationSync({ - inspect: () => ({ kind: present ? "desired" : "absent" }), - label: "upload asset", - mutate: () => { - mutationCalls += 1; - present = true; - throw new Error("socket timed out after sending the response body"); - }, - options: { ...deterministic, budget: fixedBudget() }, - }); - assert.equal(mutationCalls, 1); - assert.deepEqual(result, { mutationAttempts: 1, recovered: true }); -}); - -test("pre-existing desired state resumes without issuing a mutation", () => { - let mutationCalls = 0; - const result = reconcileGitHubMutationSync({ - inspect: () => ({ kind: "desired" }), - label: "promote release", - mutate: () => { - mutationCalls += 1; - }, - options: { ...deterministic, budget: fixedBudget() }, - }); - assert.equal(mutationCalls, 0); - assert.deepEqual(result, { mutationAttempts: 0, recovered: false }); -}); - -test("conflicting post-mutation state is terminal", () => { - let state = "absent"; - let mutationCalls = 0; - assert.throws( - () => reconcileGitHubMutationSync({ - inspect: () => state === "conflict" - ? { detail: "tag points at another full SHA", kind: "conflict" } - : { kind: state }, - label: "create tag", - mutate: () => { - mutationCalls += 1; - state = "conflict"; - throw new Error("HTTP 422"); - }, - options: { ...deterministic, budget: fixedBudget() }, - }), - /tag points at another full SHA/u, - ); - assert.equal(mutationCalls, 1); -}); - -for (const [label, readError] of [ - ["auth", new Error("HTTP 401 bad credentials")], - ["malformed", new Error("successful response contained malformed JSON")], -]) { - test(`${label} failure during ambiguous reconciliation never replays the mutation`, () => { - let inspections = 0; - let mutationCalls = 0; - assert.throws( - () => reconcileGitHubMutationSync({ - inspect: () => { - inspections += 1; - if (inspections > 1) throw readError; - return { kind: "absent" }; - }, - label: "create release", - mutate: () => { - mutationCalls += 1; - throw new Error("ambiguous timeout"); - }, - options: { ...deterministic, budget: fixedBudget() }, - }), - new RegExp(readError.message, "u"), - ); - assert.equal(mutationCalls, 1); - }); -} - -test("the shared deadline stops replay even when mutation attempts remain", () => { - let nowMs = 0; - let mutationCalls = 0; - assert.throws( - () => reconcileGitHubMutationSync({ - inspect: () => ({ kind: "absent" }), - label: "create release", - mutate: () => { - mutationCalls += 1; - nowMs = 99; - throw new Error("pre-send failure"); - }, - options: { - ...deterministic, - attemptTimeoutMs: 50, - baseDelayMs: 2, - budget: fixedBudget(100, () => nowMs), - now: () => nowMs, - }, - }), - /deadline/u, - ); - assert.equal(mutationCalls, 1); -}); - -test("mutation diagnostics redact credentials", () => { - const token = "github_pat_123456789012345678901234567890"; - assert.throws( - () => reconcileGitHubMutationSync({ - inspect: () => ({ kind: "absent" }), - label: "create release", - mutate: () => { - const cause = new Error("upload failed"); - cause.detail = `Authorization: Bearer ${token}`; - throw cause; - }, - options: { - ...deterministic, - budget: fixedBudget(180_000, () => 0, { GH_TOKEN: token }), - environment: { GH_TOKEN: token }, - maxAttempts: 1, - }, - }), - (cause) => !cause.message.includes(token) && cause.message.includes(""), - ); -}); - -test("only an explicit HTTP 404 is classified as absence", () => { - const notFound = new Error("read failed", { cause: Object.assign(new Error("gh failed"), { - detail: "gh: Not Found (HTTP 404)", - }) }); - assert.equal(isExplicitGitHubNotFound(notFound), true); - assert.equal(isExplicitGitHubNotFound(new Error("HTTP 401 bad credentials")), false); - assert.equal(isExplicitGitHubNotFound(new Error("repository was not found in local cache")), false); -}); - -test("optional reads distinguish 404 from auth and malformed successful JSON", () => { - const spawn404 = () => ({ status: 1, stderr: "gh: Not Found (HTTP 404)", stdout: "" }); - assert.equal(githubOptionalJsonReadSync(["api", "repos/o/r/releases/tags/v1"], { - baseDelayMs: 0, - deadlineMs: 100, - maxAttempts: 1, - spawn: spawn404, - }), null); - - const spawnAuth = () => ({ status: 1, stderr: "gh: Bad credentials (HTTP 401)", stdout: "" }); - assert.throws( - () => githubOptionalJsonReadSync(["api", "repos/o/r/releases/tags/v1"], { - baseDelayMs: 0, - deadlineMs: 100, - maxAttempts: 1, - spawn: spawnAuth, - }), - /401|credentials/iu, - ); - - const spawnMalformed = () => ({ status: 0, stderr: "", stdout: "{" }); - assert.throws( - () => githubJsonReadSync(["api", "repos/o/r/releases"], { - baseDelayMs: 0, - deadlineMs: 100, - maxAttempts: 1, - spawn: spawnMalformed, - }), - /malformed JSON/u, - ); -}); - -test("an exact 100-row release page stops from Link metadata without an empty trailing request", (t) => { - const { environment, root } = journalFixture(); - t.after(() => rmSync(root, { force: true, recursive: true })); - const endpoints = []; - const releases = readReleaseMapSync("o/r", deterministicReadOptions(environment, (_command, args) => { - endpoints.push(args.at(-1)); - return { status: 0, stderr: "", stdout: includedJson(releaseRows(1, 100)) }; - })); - assert.equal(releases.size, 100); - assert.deepEqual(endpoints, ["repos/o/r/releases?per_page=100&page=1"]); - assert.deepEqual( - readGitHubCoreRequestJournal({ environment, now: () => 20_000 }), - { enabled: true, rollingCount: 1, sequence: 1 }, - ); -}); - -test("each paginated REST page retry is independently journaled and exact 200 rows stop at page two", (t) => { - const { environment, root } = journalFixture(); - t.after(() => rmSync(root, { force: true, recursive: true })); - const endpoints = []; - let pageTwoAttempts = 0; - const releases = readReleaseMapSync("o/r", deterministicReadOptions(environment, (_command, args) => { - const endpoint = args.at(-1); - endpoints.push(endpoint); - if (endpoint.endsWith("page=1")) { - const next = "https://api.github.com/repositories/42/releases?per_page=100&page=2"; - const last = "https://api.github.com/repositories/42/releases?per_page=100&page=2"; - return { - status: 0, - stderr: "", - stdout: includedJson( - releaseRows(1, 100), - `<${next}>; rel="next", <${last}>; rel="last"`, - ), - }; - } - pageTwoAttempts += 1; - if (pageTwoAttempts === 1) { - return { status: 1, stderr: "gh: transient failure (HTTP 503)", stdout: "" }; - } - return { status: 0, stderr: "", stdout: includedJson(releaseRows(101, 100)) }; - })); - assert.equal(releases.size, 200); - assert.deepEqual(endpoints, [ - "repos/o/r/releases?per_page=100&page=1", - "repos/o/r/releases?per_page=100&page=2", - "repos/o/r/releases?per_page=100&page=2", - ]); - assert.deepEqual( - readGitHubCoreRequestJournal({ environment, now: () => 20_000 }), - { enabled: true, rollingCount: 3, sequence: 3 }, - ); -}); - -test("a repeated release id across pagination is the only retryable snapshot race shape", () => { - const next = "https://api.github.com/repositories/42/releases?per_page=100&page=2"; - const spawnWithSecondPage = (rows) => (_command, args) => { - const endpoint = args.at(-1); - if (endpoint.endsWith("page=1")) { - return { - status: 0, - stderr: "", - stdout: includedJson(releaseRows(1, 100), `<${next}>; rel="next"`), - }; - } - return { status: 0, stderr: "", stdout: includedJson(rows) }; - }; - assert.throws( - () => readReleaseMapSync("o/r", { - baseDelayMs: 0, - deadlineMs: 1_000, - maxAttempts: 1, - spawn: spawnWithSecondPage(releaseRows(100, 1)), - }), - (cause) => - cause instanceof GitHubReleaseSnapshotRaceError - && /repeated release 100 across one paginated snapshot/u.test(cause.message), - ); - - const conflictingTag = { - ...releaseRows(101, 1)[0], - tag_name: "v100", - }; - assert.throws( - () => readReleaseMapSync("o/r", { - baseDelayMs: 0, - deadlineMs: 1_000, - maxAttempts: 1, - spawn: spawnWithSecondPage([conflictingTag]), - }), - (cause) => - !(cause instanceof GitHubReleaseSnapshotRaceError) - && /duplicate releases for tag v100/u.test(cause.message), - ); -}); - -test("one pagination deadline is shared across every physical page", () => { - let nowMs = 0; - const endpoints = []; - assert.throws( - () => githubPaginatedArrayReadSync("o/r", "releases", { - baseDelayMs: 0, - deadlineMs: 100, - maxAttempts: 1, - now: () => nowMs, - spawn: (_command, args) => { - const endpoint = args.at(-1); - endpoints.push(endpoint); - nowMs = 101; - const next = "https://api.github.com/repositories/42/releases?per_page=100&page=2"; - return { - status: 0, - stderr: "", - stdout: includedJson(releaseRows(1, 100), `<${next}>; rel="next"`), - }; - }, - }), - /pagination deadline exhausted before page 2/u, - ); - assert.deepEqual(endpoints, ["repos/o/r/releases?per_page=100&page=1"]); -}); - -test("paginated reads reject cross-endpoint and query-mutating next links", () => { - const invoke = (next) => githubPaginatedArrayReadSync("o/r", "releases", { - baseDelayMs: 0, - deadlineMs: 100, - maxAttempts: 1, - spawn: () => ({ - status: 0, - stderr: "", - stdout: includedJson(releaseRows(1, 100), `<${next}>; rel="next"`), - }), - }); - assert.throws( - () => invoke("https://api.github.com/repositories/42/issues?per_page=100&page=2"), - /changed repository or endpoint/u, - ); - assert.throws( - () => invoke("https://api.github.com/repositories/42/releases?per_page=100&page=2&extra=true"), - /changed the exact page query/u, - ); -}); - -test("malformed tag-ref metadata fails closed", () => { - const spawn = () => ({ - status: 0, - stderr: "", - stdout: JSON.stringify({ object: { sha: "a".repeat(40), type: "commit" }, ref: "refs/heads/main" }), - }); - assert.throws( - () => readTagRefSync("o/r", "v1", { - baseDelayMs: 0, - deadlineMs: 100, - maxAttempts: 1, - spawn, - }), - /malformed metadata/u, - ); -}); - -test("operation budget clamps to the release hard deadline and rejects expiry", () => { - const budget = createGitHubOperationBudget({ - defaultWindowMs: 100_000, - environment: { - OLIPHAUNT_GITHUB_HARD_DEADLINE_RESERVE_MS: "1000", - REGISTRY_JOB_HARD_DEADLINE_EPOCH: "12", - }, - now: () => 10_000, - }); - assert.equal(budget.deadlineMs, 11_000); - assert.throws( - () => createGitHubOperationBudget({ - environment: { - OLIPHAUNT_GITHUB_HARD_DEADLINE_RESERVE_MS: "1000", - REGISTRY_JOB_HARD_DEADLINE_EPOCH: "11", - }, - now: () => 10_000, - }), - /already expired/u, - ); -}); - -test("journal lock admission cannot erode the complete mutation transport timeout", (t) => { - const { environment, root } = journalFixture(); - delete environment.GITHUB_ACTIONS; - t.after(() => rmSync(root, { force: true, recursive: true })); - const journal = environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH; - const lock = `${journal}.lock`; - writeFileSync(lock, "occupied\n"); - let nowMs = 1_000; - let spawned = false; - assert.throws( - () => runGitHubMutationSync( - ["api", "repos/o/r/git/refs", "-X", "POST", "--input", "-"], - { - coreJournalOptions: { - now: () => nowMs, - sleep: (delayMs) => { - nowMs += delayMs; - rmSync(lock, { force: true }); - }, - }, - deadlineMs: 1_075, - environment, - input: JSON.stringify({ ref: "refs/tags/v1", sha: "a".repeat(40) }), - now: () => nowMs, - spawn: () => { - spawned = true; - return { status: 0, stderr: "", stdout: "" }; - }, - timeoutMs: 50, - }, - ), - /complete 50ms transport timeout after request-journal admission/u, - ); - assert.equal(spawned, false); - assert.deepEqual( - readGitHubCoreRequestJournal({ environment, now: () => nowMs }), - { enabled: true, rollingCount: 1, sequence: 1 }, - ); -}); - -test("mutation command helper rejects moving-tag uploads and accepts only an exact release-id upload", () => { - assert.throws( - () => runGitHubMutationSync( - ["release", "upload", "v1", "asset.tgz", "--clobber", "--repo", "o/r"], - { spawn: () => ({ status: 0, stderr: "", stdout: "" }), timeoutMs: 123 }, - ), - /only permits an exact GitHub API release mutation/u, - ); - assert.throws( - () => runGitHubMutationSync( - ["release", "upload", "v1", "asset.tgz", "--repo", "o/r"], - { spawn: () => ({ status: 0, stderr: "", stdout: "" }), timeoutMs: 123 }, - ), - /only permits an exact GitHub API release mutation/u, - ); - let observed; - const args = [ - "api", - "https://uploads.github.com/repos/o/r/releases/123/assets?name=asset.tgz", - "-X", - "POST", - "-H", - "Accept: application/vnd.github+json", - "-H", - "Content-Type: application/octet-stream", - "-H", - "X-GitHub-Api-Version: 2022-11-28", - "--input", - "/tmp/asset.tgz", - ]; - runGitHubMutationSync( - args, - { - environment: {}, - spawn: (_command, args) => { - observed = args; - return { status: 0, stderr: "", stdout: "" }; - }, - timeoutMs: 123, - }, - ); - assert.deepEqual(observed, args); - assert.throws( - () => runGitHubMutationSync( - [...args.slice(0, 2), "-X", "DELETE", ...args.slice(4)], - { spawn: () => ({ status: 0, stderr: "", stdout: "" }), timeoutMs: 123 }, - ), - /exact-ID binary request/u, - ); -}); - -test("mutation command helper admits only exact additive Release Please lifecycle transitions", () => { - const addArgs = [ - "api", - "repos/o/r/issues/99/labels", - "-X", - "POST", - "--input", - "-", - ]; - let observed; - runGitHubMutationSync(addArgs, { - environment: {}, - input: JSON.stringify({ labels: ["autorelease: tagged"] }), - spawn: (_command, actual) => { - observed = actual; - return { status: 0, stderr: "", stdout: "[]" }; - }, - timeoutMs: 123, - }); - assert.deepEqual(observed, addArgs); - - const deleteArgs = [ - "api", - "repos/o/r/issues/99/labels/autorelease%3A%20pending", - "-X", - "DELETE", - ]; - runGitHubMutationSync(deleteArgs, { - environment: {}, - spawn: (_command, actual) => { - observed = actual; - return { status: 0, stderr: "", stdout: "[]" }; - }, - timeoutMs: 123, - }); - assert.deepEqual(observed, deleteArgs); - - for (const [changedArgs, input] of [ - [[...addArgs.slice(0, 3), "PUT", ...addArgs.slice(4)], JSON.stringify({ labels: ["autorelease: tagged"] })], - [[...addArgs.slice(0, 1), "repos/o/r/issues/0/labels", ...addArgs.slice(2)], JSON.stringify({ labels: ["autorelease: tagged"] })], - [addArgs, JSON.stringify({ labels: ["autorelease: pending", "autorelease: tagged"] })], - [addArgs, JSON.stringify({ labels: ["reviewed"] })], - [addArgs, JSON.stringify({ labels: ["autorelease: tagged", "autorelease: tagged"] })], - [addArgs, JSON.stringify({ labels: ["autorelease: tagged"], extra: true })], - [[...deleteArgs, "--input", "-"], "{}"], - [[...deleteArgs.slice(0, 3), "POST"], undefined], - [[...deleteArgs.slice(0, 1), "repos/o/r/issues/99/labels/reviewed", ...deleteArgs.slice(2)], undefined], - ]) { - assert.throws( - () => runGitHubMutationSync(changedArgs, { - environment: {}, - input, - spawn: () => ({ status: 0, stderr: "", stdout: "[]" }), - timeoutMs: 123, - }), - /mutation|lifecycle|payload|allowlist/u, - ); - } -}); - -test("a shared abort guard is rechecked after pacing and journal admission before transport", () => { - let guardCalls = 0; - let spawned = false; - assert.throws( - () => runGitHubMutationSync( - ["api", "repos/o/r/git/refs", "-X", "POST", "--input", "-"], - { - assertMutationAllowed: () => { - guardCalls += 1; - if (guardCalls === 2) throw new Error("peer upload failed"); - }, - environment: {}, - input: JSON.stringify({ ref: "refs/tags/v1", sha: "a".repeat(40) }), - spawn: () => { - spawned = true; - return { status: 0, stderr: "", stdout: "" }; - }, - timeoutMs: 123, - }, - ), - /peer upload failed/u, - ); - assert.equal(guardCalls, 2); - assert.equal(spawned, false); -}); diff --git a/tools/release/github-release-mutations.test.mts b/tools/release/github-release-mutations.test.mts new file mode 100644 index 000000000..80145e481 --- /dev/null +++ b/tools/release/github-release-mutations.test.mts @@ -0,0 +1,680 @@ +import assert from 'node:assert/strict'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { readGitHubCoreRequestJournal } from './github-core-request-journal.mts'; +import { requestGithubRepositoryJson } from './github-read.mts'; +import { + createGitHubOperationBudget, + GitHubReleaseSnapshotRaceError, + githubOptionalJsonRead, + githubPaginatedArrayRead, + isExplicitGitHubNotFound, + readReleaseMap, + readTagRef, + reconcileGitHubMutation, + requestGithubMutation, +} from './github-release-mutations.mts'; + +function fixedBudget(deadlineMs = 180_000, now = () => 0, environment = {}) { + return { deadlineMs, environment, now, startedAtMs: now() }; +} + +const deterministic = { + baseDelayMs: 0, + environment: {}, + maxAttempts: 3, + sleep: () => {}, +}; + +function journalFixture() { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-paginated-read-')); + return { + environment: { + GITHUB_ACTIONS: 'true', + GITHUB_REPOSITORY: 'o/r', + GITHUB_RUN_ATTEMPT: '1', + GITHUB_RUN_ID: '123', + GITHUB_SHA: 'a'.repeat(40), + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, 'journal.json'), + OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: 'true', + }, + root, + }; +} + +function releaseRows(firstId, count) { + return Array.from({ length: count }, (_, offset) => { + const id = firstId + offset; + return { + body: `release ${id}`, + draft: true, + id, + name: `release ${id}`, + prerelease: false, + tag_name: `v${id}`, + target_commitish: 'a'.repeat(40), + }; + }); +} + +function includedJson(data, link = '') { + return Response.json(data, { headers: link ? { Link: link } : {} }); +} + +function deterministicReadOptions(environment, fetchImpl) { + return { + baseDelayMs: 0, + coreJournalOptions: { now: () => 20_000 }, + deadlineMs: 1_000, + environment, + maxAttempts: 2, + maxDelayMs: 0, + now: () => 20_000, + sleep: () => {}, + fetchImpl, + }; +} + +test('a successful mutation is followed by exact-state reconciliation', async () => { + let present = false; + let mutationCalls = 0; + const result = await reconcileGitHubMutation({ + inspect: () => ({ kind: present ? 'desired' : 'absent' }), + label: 'create tag', + mutate: () => { + mutationCalls += 1; + present = true; + }, + options: { ...deterministic, budget: fixedBudget() }, + }); + assert.equal(mutationCalls, 1); + assert.deepEqual(result, { mutationAttempts: 1, recovered: false }); +}); + +test('pre-send failure retries only after a fresh read proves absence', async () => { + let present = false; + let mutationCalls = 0; + let inspections = 0; + const result = await reconcileGitHubMutation({ + inspect: () => { + inspections += 1; + return { kind: present ? 'desired' : 'absent' }; + }, + label: 'create release', + mutate: () => { + mutationCalls += 1; + if (mutationCalls === 1) throw new Error('connect failed before request write'); + present = true; + }, + options: { ...deterministic, budget: fixedBudget() }, + }); + assert.equal(mutationCalls, 2); + assert.ok(inspections >= 4, 'state is inspected before and after each attempted mutation'); + assert.deepEqual(result, { mutationAttempts: 2, recovered: false }); +}); + +test('an applied mutation followed by timeout is accepted without duplicate replay', async () => { + let present = false; + let mutationCalls = 0; + const result = await reconcileGitHubMutation({ + inspect: () => ({ kind: present ? 'desired' : 'absent' }), + label: 'upload asset', + mutate: () => { + mutationCalls += 1; + present = true; + throw new Error('socket timed out after sending the response body'); + }, + options: { ...deterministic, budget: fixedBudget() }, + }); + assert.equal(mutationCalls, 1); + assert.deepEqual(result, { mutationAttempts: 1, recovered: true }); +}); + +test('pre-existing desired state resumes without issuing a mutation', async () => { + let mutationCalls = 0; + const result = await reconcileGitHubMutation({ + inspect: () => ({ kind: 'desired' }), + label: 'promote release', + mutate: () => { + mutationCalls += 1; + }, + options: { ...deterministic, budget: fixedBudget() }, + }); + assert.equal(mutationCalls, 0); + assert.deepEqual(result, { mutationAttempts: 0, recovered: false }); +}); + +test('conflicting post-mutation state is terminal', async () => { + let state = 'absent'; + let mutationCalls = 0; + await assert.rejects( + async () => + await reconcileGitHubMutation({ + inspect: () => + state === 'conflict' + ? { detail: 'tag points at another full SHA', kind: 'conflict' } + : { kind: state }, + label: 'create tag', + mutate: () => { + mutationCalls += 1; + state = 'conflict'; + throw new Error('HTTP 422'); + }, + options: { ...deterministic, budget: fixedBudget() }, + }), + /tag points at another full SHA/u, + ); + assert.equal(mutationCalls, 1); +}); + +for (const [label, readError] of [ + ['auth', new Error('HTTP 401 bad credentials')], + ['malformed', new Error('successful response contained malformed JSON')], +]) { + test(`${label} failure during ambiguous reconciliation never replays the mutation`, async () => { + let inspections = 0; + let mutationCalls = 0; + await assert.rejects( + async () => + await reconcileGitHubMutation({ + inspect: () => { + inspections += 1; + if (inspections > 1) throw readError; + return { kind: 'absent' }; + }, + label: 'create release', + mutate: () => { + mutationCalls += 1; + throw new Error('ambiguous timeout'); + }, + options: { ...deterministic, budget: fixedBudget() }, + }), + new RegExp(readError.message, 'u'), + ); + assert.equal(mutationCalls, 1); + }); +} + +test('the shared deadline stops replay even when mutation attempts remain', async () => { + let nowMs = 0; + let mutationCalls = 0; + await assert.rejects( + async () => + await reconcileGitHubMutation({ + inspect: () => ({ kind: 'absent' }), + label: 'create release', + mutate: () => { + mutationCalls += 1; + nowMs = 99; + throw new Error('pre-send failure'); + }, + options: { + ...deterministic, + attemptTimeoutMs: 50, + baseDelayMs: 2, + budget: fixedBudget(100, () => nowMs), + now: () => nowMs, + }, + }), + /deadline/u, + ); + assert.equal(mutationCalls, 1); +}); + +test('mutation diagnostics redact credentials', async () => { + const token = 'github_pat_123456789012345678901234567890'; + await assert.rejects( + async () => + await reconcileGitHubMutation({ + inspect: () => ({ kind: 'absent' }), + label: 'create release', + mutate: () => { + const cause = new Error('upload failed'); + cause.detail = `Authorization: Bearer ${token}`; + throw cause; + }, + options: { + ...deterministic, + budget: fixedBudget(180_000, () => 0, { GH_TOKEN: token }), + environment: { GH_TOKEN: token }, + maxAttempts: 1, + }, + }), + (cause) => !cause.message.includes(token) && cause.message.includes(''), + ); +}); + +test('only an explicit HTTP 404 is classified as absence', () => { + const notFound = new Error('read failed', { + cause: Object.assign(new Error('gh failed'), { + detail: 'gh: Not Found (HTTP 404)', + }), + }); + assert.equal(isExplicitGitHubNotFound(notFound), true); + assert.equal(isExplicitGitHubNotFound(new Error('HTTP 401 bad credentials')), false); + assert.equal( + isExplicitGitHubNotFound(new Error('repository was not found in local cache')), + false, + ); +}); + +test('optional reads distinguish 404 from auth and malformed successful JSON', async () => { + const spawn404 = () => new Response('', { status: 404 }); + assert.equal( + await githubOptionalJsonRead('repos/o/r/releases/tags/v1', { + baseDelayMs: 0, + deadlineMs: 100, + maxAttempts: 1, + fetchImpl: spawn404, + }), + null, + ); + + const spawnAuth = () => new Response('', { status: 401 }); + await assert.rejects( + async () => + await githubOptionalJsonRead('repos/o/r/releases/tags/v1', { + baseDelayMs: 0, + deadlineMs: 100, + maxAttempts: 1, + fetchImpl: spawnAuth, + }), + /401|credentials/iu, + ); + + const spawnMalformed = () => new Response('{', { status: 200 }); + await assert.rejects( + async () => + await requestGithubRepositoryJson('repos/o/r/releases', { + baseDelayMs: 0, + deadlineMs: 100, + maxAttempts: 1, + fetchImpl: spawnMalformed, + }), + /invalid JSON/u, + ); +}); + +test('an exact 100-row release page stops from Link metadata without an empty trailing request', async (t) => { + const { environment, root } = journalFixture(); + t.after(() => rmSync(root, { force: true, recursive: true })); + const endpoints = []; + const releases = await readReleaseMap( + 'o/r', + deterministicReadOptions(environment, (url) => { + endpoints.push(String(url).replace('https://api.github.com/', '')); + return includedJson(releaseRows(1, 100)); + }), + ); + assert.equal(releases.size, 100); + assert.deepEqual(endpoints, ['repos/o/r/releases?per_page=100&page=1']); + assert.deepEqual(readGitHubCoreRequestJournal({ environment, now: () => 20_000 }), { + enabled: true, + rollingCount: 1, + sequence: 1, + }); +}); + +test('each paginated REST page retry is independently journaled and exact 200 rows stop at page two', async (t) => { + const { environment, root } = journalFixture(); + t.after(() => rmSync(root, { force: true, recursive: true })); + const endpoints = []; + let pageTwoAttempts = 0; + const releases = await readReleaseMap( + 'o/r', + deterministicReadOptions(environment, (url) => { + const endpoint = String(url).replace('https://api.github.com/', ''); + endpoints.push(endpoint); + if (endpoint.endsWith('page=1')) { + const next = 'https://api.github.com/repositories/42/releases?per_page=100&page=2'; + const last = 'https://api.github.com/repositories/42/releases?per_page=100&page=2'; + return includedJson(releaseRows(1, 100), `<${next}>; rel="next", <${last}>; rel="last"`); + } + pageTwoAttempts += 1; + if (pageTwoAttempts === 1) { + return new Response('', { status: 503 }); + } + return includedJson(releaseRows(101, 100)); + }), + ); + assert.equal(releases.size, 200); + assert.deepEqual(endpoints, [ + 'repos/o/r/releases?per_page=100&page=1', + 'repos/o/r/releases?per_page=100&page=2', + 'repos/o/r/releases?per_page=100&page=2', + ]); + assert.deepEqual(readGitHubCoreRequestJournal({ environment, now: () => 20_000 }), { + enabled: true, + rollingCount: 3, + sequence: 3, + }); +}); + +test('a repeated release id across pagination is the only retryable snapshot race shape', async () => { + const next = 'https://api.github.com/repositories/42/releases?per_page=100&page=2'; + const spawnWithSecondPage = (rows) => (url) => { + const endpoint = String(url).replace('https://api.github.com/', ''); + if (endpoint.endsWith('page=1')) { + return includedJson(releaseRows(1, 100), `<${next}>; rel="next"`); + } + return includedJson(rows); + }; + await assert.rejects( + async () => + await readReleaseMap('o/r', { + baseDelayMs: 0, + deadlineMs: 1_000, + maxAttempts: 1, + fetchImpl: spawnWithSecondPage(releaseRows(100, 1)), + }), + (cause) => + cause instanceof GitHubReleaseSnapshotRaceError && + /repeated release 100 across one paginated snapshot/u.test(cause.message), + ); + + const conflictingTag = { + ...releaseRows(101, 1)[0], + tag_name: 'v100', + }; + await assert.rejects( + async () => + await readReleaseMap('o/r', { + baseDelayMs: 0, + deadlineMs: 1_000, + maxAttempts: 1, + fetchImpl: spawnWithSecondPage([conflictingTag]), + }), + (cause) => + !(cause instanceof GitHubReleaseSnapshotRaceError) && + /duplicate releases for tag v100/u.test(cause.message), + ); +}); + +test('one pagination deadline is shared across every physical page', async () => { + let nowMs = 0; + const endpoints = []; + await assert.rejects( + async () => + await githubPaginatedArrayRead('o/r', 'releases', { + baseDelayMs: 0, + deadlineMs: 100, + maxAttempts: 1, + now: () => nowMs, + fetchImpl: (url) => { + const endpoint = String(url).replace('https://api.github.com/', ''); + endpoints.push(endpoint); + nowMs = 101; + const next = 'https://api.github.com/repositories/42/releases?per_page=100&page=2'; + return includedJson(releaseRows(1, 100), `<${next}>; rel="next"`); + }, + }), + /pagination deadline exhausted before page 2/u, + ); + assert.deepEqual(endpoints, ['repos/o/r/releases?per_page=100&page=1']); +}); + +test('paginated reads reject cross-endpoint and query-mutating next links', async () => { + const invoke = async (next) => + await githubPaginatedArrayRead('o/r', 'releases', { + baseDelayMs: 0, + deadlineMs: 100, + maxAttempts: 1, + fetchImpl: () => includedJson(releaseRows(1, 100), `<${next}>; rel="next"`), + }); + await assert.rejects( + async () => await invoke('https://api.github.com/repositories/42/issues?per_page=100&page=2'), + /changed repository or endpoint/u, + ); + await assert.rejects( + async () => + await invoke( + 'https://api.github.com/repositories/42/releases?per_page=100&page=2&extra=true', + ), + /changed the exact page query/u, + ); +}); + +test('malformed tag-ref metadata fails closed', async () => { + const fetchImpl = () => + new Response( + JSON.stringify({ + object: { sha: 'a'.repeat(40), type: 'commit' }, + ref: 'refs/heads/main', + }), + { status: 200 }, + ); + await assert.rejects( + async () => + await readTagRef('o/r', 'v1', { + baseDelayMs: 0, + deadlineMs: 100, + maxAttempts: 1, + fetchImpl, + }), + /malformed metadata/u, + ); +}); + +test('operation budget clamps to the release hard deadline and rejects expiry', () => { + const budget = createGitHubOperationBudget({ + defaultWindowMs: 100_000, + environment: { + OLIPHAUNT_GITHUB_HARD_DEADLINE_RESERVE_MS: '1000', + REGISTRY_JOB_HARD_DEADLINE_EPOCH: '12', + }, + now: () => 10_000, + }); + assert.equal(budget.deadlineMs, 11_000); + assert.throws( + () => + createGitHubOperationBudget({ + environment: { + OLIPHAUNT_GITHUB_HARD_DEADLINE_RESERVE_MS: '1000', + REGISTRY_JOB_HARD_DEADLINE_EPOCH: '11', + }, + now: () => 10_000, + }), + /already expired/u, + ); +}); + +test('journal lock admission cannot erode the complete mutation transport timeout', async (t) => { + const { environment, root } = journalFixture(); + delete environment.GITHUB_ACTIONS; + t.after(() => rmSync(root, { force: true, recursive: true })); + const journal = environment.OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH; + const lock = `${journal}.lock`; + writeFileSync(lock, 'occupied\n'); + let nowMs = 1_000; + let spawned = false; + await assert.rejects( + async () => + await requestGithubMutation('repos/o/r/git/refs', { + method: 'POST', + coreJournalOptions: { + now: () => nowMs, + sleep: (delayMs) => { + nowMs += delayMs; + rmSync(lock, { force: true }); + }, + }, + deadlineMs: 1_075, + environment, + input: JSON.stringify({ ref: 'refs/tags/v1', sha: 'a'.repeat(40) }), + now: () => nowMs, + fetchImpl: () => { + spawned = true; + return new Response(''); + }, + timeoutMs: 50, + }), + /complete 50ms transport timeout after request-journal admission/u, + ); + assert.equal(spawned, false); + assert.deepEqual(readGitHubCoreRequestJournal({ environment, now: () => nowMs }), { + enabled: true, + rollingCount: 1, + sequence: 1, + }); +}); + +test('asset upload streams frozen bytes to an exact release id and rejects changed identities', async (t) => { + const root = mkdtempSync(path.join(os.tmpdir(), 'github-upload-')); + t.after(() => rmSync(root, { recursive: true, force: true })); + const file = path.join(root, 'asset+linux.tgz'); + const bytes = Buffer.from([0, 255, 127, 10]); + writeFileSync(file, bytes); + const endpoint = + 'https://uploads.github.com/repos/o/r/releases/123/assets?name=asset%2Blinux.tgz'; + let calls = 0; + const fetchImpl = async (url, options) => { + calls++; + assert.equal(url, endpoint); + assert.equal(options.method, 'POST'); + assert.equal(options.redirect, 'error'); + assert.equal(options.headers['Content-Length'], String(bytes.length)); + assert.equal(options.headers.Authorization, 'Bearer fixture-token'); + assert.equal(options.headers['Content-Type'], 'application/octet-stream'); + assert.equal(options.headers['X-GitHub-Api-Version'], '2022-11-28'); + assert.ok(options.signal instanceof AbortSignal); + const chunks = []; + for await (const chunk of options.body) chunks.push(chunk); + assert.deepEqual(Buffer.concat(chunks), bytes); + return Response.json({ id: 42 }); + }; + const options = { + file, + method: 'POST', + environment: { GH_TOKEN: 'fixture-token' }, + fetchImpl, + timeoutMs: 1_000, + }; + assert.equal(await requestGithubMutation(endpoint, options), '{"id":42}'); + for (const [url, changed] of [ + [endpoint.replace('/123/', '/tags/v1/'), {}], + [endpoint.replace('uploads.github.com', 'example.invalid'), {}], + [endpoint.replace('https://', 'https://secret@'), {}], + [endpoint + '#fragment', {}], + [endpoint + '&name=other.tgz', {}], + [endpoint, { method: 'DELETE' }], + [endpoint, { input: '{}' }], + [endpoint, { file: path.join(root, 'other.tgz') }], + ]) + await assert.rejects( + async () => await requestGithubMutation(url, { ...options, ...changed }), + /mutation|upload|repository|asset/u, + ); + assert.equal(calls, 1); +}); + +test('lifecycle writes admit only exact additive label transitions', async () => { + const endpoint = 'repos/o/r/issues/99/labels'; + const deletion = endpoint + '/autorelease%3A%20pending'; + const input = JSON.stringify({ labels: ['autorelease: tagged'] }); + const observed = []; + const options = { + environment: {}, + timeoutMs: 123, + fetchImpl: (url, init) => { + observed.push([url, init.method, init.body]); + assert.equal(init.redirect, 'error'); + assert.equal(init.headers.Authorization, undefined); + return new Response('[]'); + }, + }; + await requestGithubMutation(endpoint, { ...options, method: 'POST', input }); + await requestGithubMutation(deletion, { ...options, method: 'DELETE' }); + assert.deepEqual(observed, [ + ['https://api.github.com/' + endpoint, 'POST', input], + ['https://api.github.com/' + deletion, 'DELETE', undefined], + ]); + for (const [url, changed] of [ + [endpoint, { method: 'PUT', input }], + [endpoint.replace('/99/', '/0/'), { method: 'POST', input }], + [ + endpoint, + { + method: 'POST', + input: JSON.stringify({ labels: ['autorelease: pending', 'autorelease: tagged'] }), + }, + ], + [endpoint, { method: 'POST', input: JSON.stringify({ labels: ['reviewed'] }) }], + [ + endpoint, + { + method: 'POST', + input: JSON.stringify({ labels: ['autorelease: tagged', 'autorelease: tagged'] }), + }, + ], + [ + endpoint, + { method: 'POST', input: JSON.stringify({ labels: ['autorelease: tagged'], extra: true }) }, + ], + [deletion, { method: 'DELETE', input: '{}' }], + [deletion, { method: 'POST' }], + [deletion.replace('autorelease%3A%20pending', 'reviewed'), { method: 'DELETE' }], + ]) + await assert.rejects( + async () => await requestGithubMutation(url, { ...options, ...changed }), + /mutation|lifecycle|payload|allowlist/u, + ); + assert.equal(observed.length, 2); +}); + +test('mutation HTTP failures never replay a write and bound response bytes', async () => { + const endpoint = 'repos/o/r/git/refs'; + const base = { + environment: { GH_TOKEN: 'fixture-secret' }, + method: 'POST', + input: JSON.stringify({ ref: 'refs/tags/v1', sha: 'a'.repeat(40) }), + timeoutMs: 1_000, + }; + let calls = 0; + for (const response of [ + new Response('fixture-secret', { status: 503 }), + new Response('', { headers: { 'content-length': String(4 * 1024 * 1024 + 1) } }), + ]) { + await assert.rejects( + async () => + await requestGithubMutation(endpoint, { + ...base, + fetchImpl: () => { + calls++; + return response; + }, + }), + (error) => { + assert.ok(!String(error.detail ?? error.message).includes('fixture-secret')); + return /HTTP 503|exceeds/u.test(error.message); + }, + ); + } + assert.equal(calls, 2); +}); + +test('a shared abort guard is rechecked after pacing and journal admission before transport', async () => { + let guardCalls = 0; + let spawned = false; + await assert.rejects( + async () => + await requestGithubMutation('repos/o/r/git/refs', { + method: 'POST', + assertMutationAllowed: () => { + guardCalls += 1; + if (guardCalls === 2) throw new Error('peer upload failed'); + }, + environment: {}, + input: JSON.stringify({ ref: 'refs/tags/v1', sha: 'a'.repeat(40) }), + fetchImpl: () => { + spawned = true; + return new Response(''); + }, + timeoutMs: 123, + }), + /peer upload failed/u, + ); + assert.equal(guardCalls, 2); + assert.equal(spawned, false); +}); diff --git a/tools/release/icu-npm-carrier-contract.mjs b/tools/release/icu-npm-carrier-contract.mjs deleted file mode 100644 index e76bb2e6a..000000000 --- a/tools/release/icu-npm-carrier-contract.mjs +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { validateNativeIcuDataManifestRows } from "./native-icu-data-contract.mjs"; - -export const ICU_BUNDLE_DIRECTORY = "OliphauntICU.bundle"; -export const ICU_DATA_RELATIVE_PATH = `${ICU_BUNDLE_DIRECTORY}/share/icu`; -export const ICU_MANIFEST_RELATIVE_PATH = `${ICU_BUNDLE_DIRECTORY}/manifest.properties`; -export const ICU_UNSTAGED_TREE_SHA256 = "x-release-icu-data-tree-sha256"; -export const ICU_REACT_NATIVE_CONFIG = "react-native.config.js"; -export const ICU_PODSPEC = "OliphauntICU.podspec"; - -const PACKED_ROOT = "package"; -const PACKED_DATA_ROOT = `${PACKED_ROOT}/${ICU_DATA_RELATIVE_PATH}`; -const LEGACY_PACKED_DATA_ROOT = `${PACKED_ROOT}/share/icu`; -const CANONICAL_REACT_NATIVE_CONFIG = `module.exports = { - dependency: { - platforms: { - ios: null, - android: null, - }, - }, -}; -`; - -function contractError(label, message) { - throw new Error(`${label}: ${message}`); -} - -function asUtf8(bytes, label) { - if (!(typeof bytes === "string" || bytes instanceof Uint8Array)) { - contractError(label, "must be UTF-8 text bytes"); - } - const buffer = Buffer.isBuffer(bytes) ? bytes : Buffer.from(bytes); - const text = buffer.toString("utf8"); - if (!Buffer.from(text, "utf8").equals(buffer)) { - contractError(label, "must be canonical UTF-8 text"); - } - return { buffer, text }; -} - -export function assertIcuReactNativeConfig(bytes, label = ICU_REACT_NATIVE_CONFIG) { - const { text } = asUtf8(bytes, label); - // This descriptor is intentionally static. Executing reviewed JavaScript is - // unnecessary and, under Bun 1.3.14, sandboxed evaluation can leave bytewise - // sorting of a 4,000+ file ICU manifest pathologically CPU-bound. Exact bytes prove - // the two-platform autolink exclusion without evaluating package code. - if (text !== CANONICAL_REACT_NATIVE_CONFIG) { - contractError(label, "must exactly match the canonical two-platform autolink exclusion descriptor"); - } -} - -export function assertIcuPodspec(bytes, label = ICU_PODSPEC) { - const { text } = asUtf8(bytes, label); - const resourceAssignments = [...text.matchAll(/^\s*s\.(resources|resource_bundles?)\s*=/gmu)]; - if (resourceAssignments.length !== 1) { - contractError(label, `must declare exactly one resources assignment, got ${resourceAssignments.length}`); - } - if (!/^\s*s\.resources\s*=\s*(['"])OliphauntICU\.bundle\1\s*$/mu.test(text)) { - contractError(label, "must copy the preassembled OliphauntICU.bundle as one resource"); - } - if (/\bs\.resource_bundles?\s*=/u.test(text) || /share\/icu(?:\/|['"])/u.test(text)) { - contractError(label, "must not rebuild or directly glob the ICU data tree"); - } -} - -export function assertIcuPackageManifest( - packageJson, - label = "@oliphaunt/icu package.json", - { allowUnstagedDigest = false } = {}, -) { - if (packageJson === null || typeof packageJson !== "object" || Array.isArray(packageJson)) { - contractError(label, "must be an object"); - } - if (packageJson.type !== "commonjs") { - contractError(label, `type must be "commonjs", got ${JSON.stringify(packageJson.type)}`); - } - const metadata = packageJson.oliphaunt; - if ( - metadata?.product !== "oliphaunt-icu" - || metadata?.kind !== "icu-data" - || metadata?.target !== "portable" - || metadata?.dataRelativePath !== ICU_DATA_RELATIVE_PATH - || metadata?.manifestRelativePath !== ICU_MANIFEST_RELATIVE_PATH - || !( - /^[0-9a-f]{64}$/u.test(metadata?.icuDataTreeSha256 ?? "") - || (allowUnstagedDigest && metadata?.icuDataTreeSha256 === ICU_UNSTAGED_TREE_SHA256) - ) - ) { - contractError( - label, - "must declare portable oliphaunt-icu metadata with matching ICU data, manifest, and tree digest", - ); - } - if (!Array.isArray(packageJson.files)) { - contractError(label, "files must be an array"); - } - if (new Set(packageJson.files).size !== packageJson.files.length) { - contractError(label, "files must not contain duplicate entries"); - } - for (const member of [ICU_BUNDLE_DIRECTORY, ICU_PODSPEC, ICU_REACT_NATIVE_CONFIG]) { - if (!packageJson.files.includes(member)) { - contractError(label, `files must include ${member}`); - } - } - const legacyEntries = packageJson.files.filter((member) => - typeof member === "string" && (member === "share" || member.startsWith("share/")), - ); - if (legacyEntries.length > 0) { - contractError(label, `files must not include the legacy ICU tree: ${legacyEntries.join(", ")}`); - } -} - -function normalizeEntries(entries, label) { - const normalized = []; - const seen = new Set(); - for (const entry of entries) { - const name = typeof entry === "string" ? entry : entry?.name; - const isFile = typeof entry === "string" ? !entry.endsWith("/") : entry?.isFile === true; - if (typeof name !== "string" || name.length === 0) { - contractError(label, "archive inventory contains an invalid member name"); - } - const normalizedName = name.replace(/\/$/u, ""); - if (seen.has(normalizedName)) { - contractError(label, `archive inventory repeats member ${normalizedName}`); - } - seen.add(normalizedName); - normalized.push({ name: normalizedName, isFile }); - } - return normalized; -} - -function isAtOrBelow(member, root) { - return member === root || member.startsWith(`${root}/`); -} - -function archiveFileManifest(entries, root, label) { - const rows = entries instanceof Map - ? [...entries].map(([name, entry]) => ({ ...entry, name })) - : [...entries]; - const manifest = []; - const seen = new Set(); - for (const entry of rows) { - const name = entry?.name; - if (typeof name !== "string" || !isAtOrBelow(name.replace(/\/$/u, ""), root)) { - continue; - } - const normalizedName = name.replace(/\/$/u, ""); - if (normalizedName === root || entry?.isFile !== true) { - continue; - } - const relative = normalizedName.slice(`${root}/`.length); - if (!relative || seen.has(relative)) { - contractError(label, `contains an invalid or repeated ICU data file ${relative || normalizedName}`); - } - seen.add(relative); - const value = typeof entry.data === "function" ? entry.data() : entry.data; - if (!(Buffer.isBuffer(value) || value instanceof Uint8Array)) { - contractError(label, `cannot read ICU data file ${normalizedName}`); - } - const bytes = Buffer.from(value); - if (entry.size !== undefined && entry.size !== bytes.length) { - contractError( - label, - `ICU data file ${normalizedName} declares ${entry.size} bytes but contains ${bytes.length}`, - ); - } - manifest.push({ - path: relative, - sha256: createHash("sha256").update(bytes).digest("hex"), - size: bytes.length, - type: "file", - }); - } - if (manifest.length === 0) { - contractError(label, `contains no readable ICU data files below ${root}`); - } - return manifest.sort((left, right) => Buffer.from(left.path).compare(Buffer.from(right.path))); -} - -export function assertIcuPackedDataMatchesSource({ - packedEntries, - sourceEntries, - label = "@oliphaunt/icu npm tarball", - sourceLabel = "liboliphaunt ICU data release asset", -}) { - const packed = archiveFileManifest(packedEntries, PACKED_DATA_ROOT, label); - const source = archiveFileManifest(sourceEntries, "share/icu", sourceLabel); - if (JSON.stringify(packed) === JSON.stringify(source)) { - return; - } - - const packedByPath = new Map(packed.map((entry) => [entry.path, entry])); - const sourceByPath = new Map(source.map((entry) => [entry.path, entry])); - const missing = source.filter((entry) => !packedByPath.has(entry.path)).map((entry) => entry.path); - const unexpected = packed.filter((entry) => !sourceByPath.has(entry.path)).map((entry) => entry.path); - const changed = source - .filter((entry) => { - const candidate = packedByPath.get(entry.path); - return candidate !== undefined - && (candidate.size !== entry.size || candidate.sha256 !== entry.sha256); - }) - .map((entry) => entry.path); - contractError( - label, - `ICU data differs from ${sourceLabel}` - + ` (missing=${JSON.stringify(missing.slice(0, 5))}` - + `, unexpected=${JSON.stringify(unexpected.slice(0, 5))}` - + `, changed=${JSON.stringify(changed.slice(0, 5))})`, - ); -} - -export function assertIcuPackedClosureMatchesSource({ - packedEntries, - sourceEntries, - packageJson, - label = "@oliphaunt/icu npm tarball", - sourceLabel = "liboliphaunt ICU data release asset", -}) { - assertIcuPackedDataMatchesSource({ packedEntries, sourceEntries, label, sourceLabel }); - const packedManifest = packedEntries.get(`${PACKED_ROOT}/${ICU_MANIFEST_RELATIVE_PATH}`)?.data(); - const sourceManifest = sourceEntries.get("manifest.properties")?.data(); - if (packedManifest === undefined || sourceManifest === undefined) { - contractError(label, "ICU data closure is missing its manifest"); - } - if (!Buffer.from(packedManifest).equals(Buffer.from(sourceManifest))) { - contractError(label, `ICU data manifest differs from ${sourceLabel}`); - } - try { - const sourceDataRows = [...sourceEntries] - .filter(([name, entry]) => entry.isFile === true && name.startsWith("share/icu/")) - .map(([name, entry]) => ({ - path: name.slice("share/icu/".length), - bytes: entry.data(), - })); - const receipt = validateNativeIcuDataManifestRows( - packedManifest, - sourceDataRows, - `${label} ${ICU_MANIFEST_RELATIVE_PATH}`, - ); - if (packageJson?.oliphaunt?.icuDataTreeSha256 !== receipt.icuDataTreeSha256) { - contractError(label, "package metadata and ICU data manifest identify different logical trees"); - } - } catch (error) { - contractError(label, error instanceof Error ? error.message : String(error)); - } -} - -function icuTreeRoots(member) { - const segments = member.split("/").filter(Boolean); - const roots = []; - for (let index = 0; index + 1 < segments.length; index += 1) { - if (segments[index] === "share" && segments[index + 1] === "icu") { - roots.push(segments.slice(0, index + 2).join("/")); - } - } - return roots; -} - -export function assertIcuPackedInventory(entries, label = "@oliphaunt/icu npm tarball") { - const inventory = normalizeEntries(entries, label); - const byName = new Map(inventory.map((entry) => [entry.name, entry])); - for (const member of [ - `${PACKED_ROOT}/package.json`, - `${PACKED_ROOT}/${ICU_PODSPEC}`, - `${PACKED_ROOT}/${ICU_REACT_NATIVE_CONFIG}`, - ]) { - if (byName.get(member)?.isFile !== true) { - contractError(label, `is missing file ${member}`); - } - } - - for (const { name } of inventory) { - if (isAtOrBelow(name, LEGACY_PACKED_DATA_ROOT)) { - contractError(label, `contains forbidden legacy ICU data member ${name}`); - } - for (const root of icuTreeRoots(name)) { - if (root !== PACKED_DATA_ROOT) { - contractError(label, `contains unexpected additional ICU data tree ${root}`); - } - } - } - - const dataFiles = inventory.filter(({ name, isFile }) => - isFile && name.startsWith(`${PACKED_DATA_ROOT}/`), - ); - if (dataFiles.length === 0) { - contractError(label, `is missing ICU data files under ${PACKED_DATA_ROOT}`); - } - if (!dataFiles.some(({ name }) => { - const relative = name.slice(`${PACKED_DATA_ROOT}/`.length).split("/").filter(Boolean); - return relative.length > 0 && relative[0].startsWith("icudt"); - })) { - contractError(label, `is missing ${PACKED_DATA_ROOT}/icudt* data files`); - } - const manifest = `${PACKED_ROOT}/${ICU_MANIFEST_RELATIVE_PATH}`; - if (byName.get(manifest)?.isFile !== true) { - contractError(label, `is missing ICU data manifest ${manifest}`); - } - const seedMembers = inventory.filter(({ name }) => /(?:^|\/)cluster-seed(?:\/|$)/u.test(name)); - if (seedMembers.length > 0) { - contractError(label, `must not contain a target-specific cluster seed: ${seedMembers[0].name}`); - } -} - -function assertSameBytes(actual, expected, label) { - const actualBytes = Buffer.isBuffer(actual) ? actual : Buffer.from(actual); - const expectedBytes = Buffer.isBuffer(expected) ? expected : Buffer.from(expected); - if (!actualBytes.equals(expectedBytes)) { - contractError(label, "packed bytes differ from the reviewed source descriptor"); - } -} - -export function assertPackedIcuCarrier({ - entries, - packageJson, - packedConfig, - packedPodspec, - sourceConfig, - sourcePodspec, - label = "@oliphaunt/icu npm tarball", -}) { - assertIcuPackageManifest(packageJson, `${label} package/package.json`); - assertIcuPackedInventory(entries, label); - assertIcuReactNativeConfig(sourceConfig, `source ${ICU_REACT_NATIVE_CONFIG}`); - assertIcuPodspec(sourcePodspec, `source ${ICU_PODSPEC}`); - assertSameBytes(packedConfig, sourceConfig, `${label} package/${ICU_REACT_NATIVE_CONFIG}`); - assertSameBytes(packedPodspec, sourcePodspec, `${label} package/${ICU_PODSPEC}`); - assertIcuReactNativeConfig(packedConfig, `${label} package/${ICU_REACT_NATIVE_CONFIG}`); - assertIcuPodspec(packedPodspec, `${label} package/${ICU_PODSPEC}`); -} diff --git a/tools/release/icu-npm-carrier-contract.test.mjs b/tools/release/icu-npm-carrier-contract.test.mjs deleted file mode 100644 index 85cb5d5f0..000000000 --- a/tools/release/icu-npm-carrier-contract.test.mjs +++ /dev/null @@ -1,270 +0,0 @@ -import assert from "node:assert/strict"; -import { - cpSync, - mkdtempSync, - mkdirSync, - readFileSync, - realpathSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { performance } from "node:perf_hooks"; -import test from "node:test"; -import { gzipSync, gunzipSync } from "node:zlib"; - -import { - ICU_DATA_RELATIVE_PATH, - ICU_MANIFEST_RELATIVE_PATH, - assertIcuPackedDataMatchesSource, - assertIcuPackageManifest, - assertIcuPackedInventory, - assertIcuPodspec, - assertIcuReactNativeConfig, - assertPackedIcuCarrier, -} from "./icu-npm-carrier-contract.mjs"; -import { nativeIcuDataManifest } from "./native-icu-data-contract.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -const ICU_PACKAGE_ROOT = path.join(ROOT, "src/runtimes/liboliphaunt/native/icu-npm"); -const PNPM = process.platform === "win32" ? "pnpm.cmd" : "pnpm"; -const manifest = JSON.parse(readFileSync(path.join(ICU_PACKAGE_ROOT, "package.json"), "utf8")); -const stagedManifest = { - ...manifest, - oliphaunt: { ...manifest.oliphaunt, icuDataTreeSha256: "a".repeat(64) }, -}; -const config = readFileSync(path.join(ICU_PACKAGE_ROOT, "react-native.config.js")); -const podspec = readFileSync(path.join(ICU_PACKAGE_ROOT, "OliphauntICU.podspec")); -const canonicalEntries = [ - { name: "package/package.json", isFile: true }, - { name: "package/react-native.config.js", isFile: true }, - { name: "package/OliphauntICU.podspec", isFile: true }, - { name: "package/OliphauntICU.bundle/", isFile: false }, - { name: "package/OliphauntICU.bundle/share/icu/icudt77l/root.res", isFile: true }, - { name: "package/OliphauntICU.bundle/manifest.properties", isFile: true }, -]; - -function stageIcuReceipt(root) { - const data = path.join(root, ...ICU_DATA_RELATIVE_PATH.split("/")); - const receipt = nativeIcuDataManifest(data); - writeFileSync(path.join(root, ...ICU_MANIFEST_RELATIVE_PATH.split("/")), receipt); - const packageJson = JSON.parse(readFileSync(path.join(root, "package.json"), "utf8")); - packageJson.oliphaunt.icuDataTreeSha256 = /^icuDataTreeSha256=([0-9a-f]{64})$/mu.exec(receipt.toString("utf8"))[1]; - writeFileSync(path.join(root, "package.json"), `${JSON.stringify(packageJson, null, 2)}\n`); -} - -test("ICU npm source descriptors encode the autolink-excluded, structure-preserving carrier contract", () => { - assert.equal(manifest.oliphaunt.dataRelativePath, ICU_DATA_RELATIVE_PATH); - assert.doesNotThrow(() => assertIcuPackageManifest( - manifest, - "@oliphaunt/icu source package.json", - { allowUnstagedDigest: true }, - )); - assert.doesNotThrow(() => assertIcuReactNativeConfig(config)); - assert.doesNotThrow(() => assertIcuPodspec(podspec)); - assert.equal(manifest.oliphaunt.manifestRelativePath, ICU_MANIFEST_RELATIVE_PATH); -}); - -test("ICU npm pack includes one canonical bundle and preserves both native descriptors byte-for-byte", (t) => { - const root = realpathSync(mkdtempSync(path.join(os.tmpdir(), "oliphaunt-icu-npm-contract-"))); - t.after(() => rmSync(root, { recursive: true, force: true })); - const stage = path.join(root, "stage"); - const output = path.join(root, "packed"); - cpSync(ICU_PACKAGE_ROOT, stage, { recursive: true }); - mkdirSync(path.join(stage, ...ICU_DATA_RELATIVE_PATH.split("/"), "icudt-test"), { recursive: true }); - writeFileSync( - path.join(stage, ...ICU_DATA_RELATIVE_PATH.split("/"), "icudt-test", "root.res"), - "fixture\n", - ); - stageIcuReceipt(stage); - stageReleaseNotices(stage, { profile: "native-icu-data" }); - mkdirSync(output); - const packed = spawnSync( - PNPM, - ["pack", "--pack-destination", output, "--json"], - { cwd: stage, encoding: "utf8" }, - ); - assert.equal(packed.status, 0, `${packed.stdout}\n${packed.stderr}`); - const packedRows = JSON.parse(packed.stdout); - const row = Array.isArray(packedRows) ? packedRows[0] : packedRows; - const tarball = path.isAbsolute(row.filename) - ? row.filename - : path.join(output, path.basename(row.filename)); - const entries = readPortableArchiveEntries(tarball); - assert.equal(entries.has("package/share/icu/icudt-test/root.res"), false); - assert.equal(entries.has("package/OliphauntICU.bundle/share/icu/icudt-test/root.res"), true); - assertPackedIcuCarrier({ - entries: [...entries].map(([name, entry]) => ({ name, isFile: entry.isFile })), - packageJson: JSON.parse(Buffer.from(entries.get("package/package.json").data()).toString("utf8")), - packedConfig: Buffer.from(entries.get("package/react-native.config.js").data()), - packedPodspec: Buffer.from(entries.get("package/OliphauntICU.podspec").data()), - sourceConfig: config, - sourcePodspec: podspec, - }); - const sourceEntries = new Map([ - [ - "share/icu/icudt-test/root.res", - { - data: () => Buffer.from("fixture\n"), - isFile: true, - size: Buffer.byteLength("fixture\n"), - }, - ], - ]); - assert.doesNotThrow(() => assertIcuPackedDataMatchesSource({ - packedEntries: entries, - sourceEntries, - })); - assert.throws( - () => assertIcuPackedDataMatchesSource({ - packedEntries: entries, - sourceEntries: new Map([ - [ - "share/icu/icudt-test/root.res", - { data: () => Buffer.from("changed\n"), isFile: true, size: Buffer.byteLength("changed\n") }, - ], - ]), - }), - /ICU data differs/u, - ); - - const tar = gunzipSync(readFileSync(tarball)); - const firstSize = Number.parseInt( - tar.subarray(124, 136).toString("ascii").replace(/\0.*$/u, "").trim() || "0", - 8, - ); - const firstSpan = 512 + Math.ceil(firstSize / 512) * 512; - let endOffset = 0; - while (endOffset + 512 <= tar.length) { - const header = tar.subarray(endOffset, endOffset + 512); - if (header.every((byte) => byte === 0)) break; - const size = Number.parseInt( - header.subarray(124, 136).toString("ascii").replace(/\0.*$/u, "").trim() || "0", - 8, - ); - endOffset += 512 + Math.ceil(size / 512) * 512; - } - const duplicateArchive = path.join(root, "duplicate-member.tgz"); - writeFileSync( - duplicateArchive, - gzipSync(Buffer.concat([ - tar.subarray(0, endOffset), - tar.subarray(0, firstSpan), - tar.subarray(endOffset), - ])), - ); - assert.throws( - () => readPortableArchiveEntries(duplicateArchive), - /repeats archive member/u, - ); -}); - -test("ICU npm manifest rejects ESM autolinking and the legacy payload selector", () => { - assert.throws( - () => assertIcuPackageManifest({ ...stagedManifest, type: "module" }), - /type must be "commonjs"/u, - ); - assert.throws( - () => assertIcuPackageManifest({ ...stagedManifest, files: [...manifest.files, "share"] }), - /must not include the legacy ICU tree/u, - ); -}); - -test("ICU native descriptors fail closed on partial autolinking or flattened CocoaPods resources", () => { - assert.throws( - () => assertIcuReactNativeConfig("module.exports = { dependency: { platforms: { ios: null } } };\n"), - /must exactly match the canonical/u, - ); - assert.throws( - () => assertIcuPodspec("s.resource_bundles = { 'OliphauntICU' => ['share/icu/**/*'] }\n"), - /preassembled OliphauntICU\.bundle/u, - ); -}); - -test("ICU config validation rejects executable changes and full inventory comparison remains bounded", () => { - for (const changed of [ - Buffer.concat([config, Buffer.from("\n")]), - Buffer.from(config.toString("utf8").replace("ios: null,\n android", "android: null,\n ios")), - Buffer.from(`${config.toString("utf8")}process.exit(0);\n`), - ]) { - assert.throws( - () => assertIcuReactNativeConfig(changed), - /must exactly match the canonical/u, - ); - } - - const packedEntries = new Map(); - const sourceEntries = new Map(); - for (let index = 0; index < 4_148; index += 1) { - const relative = `locales/${index.toString().padStart(4, "0")}.res`; - const data = Buffer.from(`locale-${index}\n`); - packedEntries.set(`package/${ICU_DATA_RELATIVE_PATH}/${relative}`, { - data: () => data, - isFile: true, - size: data.length, - }); - sourceEntries.set(`share/icu/${relative}`, { - data: () => data, - isFile: true, - size: data.length, - }); - } - assert.doesNotThrow(() => assertIcuReactNativeConfig(config)); - const startedAt = performance.now(); - assert.doesNotThrow(() => assertIcuPackedDataMatchesSource({ packedEntries, sourceEntries })); - assert.ok( - performance.now() - startedAt < 5_000, - "4,148-file ICU byte-closure validation must finish within five seconds", - ); -}); - -test("ICU packed inventory accepts one data-only bundle and rejects legacy, additional, or duplicate trees", () => { - assert.doesNotThrow(() => assertIcuPackedInventory(canonicalEntries)); - assert.throws( - () => assertIcuPackedInventory([ - ...canonicalEntries, - { name: "package/share/icu/icudt77l/root.res", isFile: true }, - ]), - /forbidden legacy ICU data member/u, - ); - assert.throws( - () => assertIcuPackedInventory([ - ...canonicalEntries, - { name: "package/duplicate/share/icu/icudt77l/root.res", isFile: true }, - ]), - /unexpected additional ICU data tree/u, - ); - assert.throws( - () => assertIcuPackedInventory([...canonicalEntries, canonicalEntries.at(-1)]), - /repeats member/u, - ); -}); - -test("ICU packed carrier preserves the reviewed config and podspec bytes exactly", () => { - assert.throws( - () => assertPackedIcuCarrier({ - entries: canonicalEntries, - packageJson: stagedManifest, - packedConfig: Buffer.concat([config, Buffer.from("\n")]), - packedPodspec: podspec, - sourceConfig: config, - sourcePodspec: podspec, - }), - /packed bytes differ from the reviewed source descriptor/u, - ); - assert.throws( - () => assertPackedIcuCarrier({ - entries: canonicalEntries, - packageJson: stagedManifest, - packedConfig: config, - packedPodspec: Buffer.concat([podspec, Buffer.from("\n")]), - sourceConfig: config, - sourcePodspec: podspec, - }), - /packed bytes differ from the reviewed source descriptor/u, - ); -}); diff --git a/tools/release/install-node-fallback.sh b/tools/release/install-node-fallback.sh deleted file mode 100644 index b86675537..000000000 --- a/tools/release/install-node-fallback.sh +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env sh -set -eu - -die() { - echo "Node fallback install failed: $*" >&2 - exit 1 -} - -require() { - command -v "$1" >/dev/null 2>&1 || die "missing required command: $1" -} - -root="${OLIPHAUNT_NODE_FALLBACK_ROOT:-}" -if [ -z "$root" ]; then - root="$(git rev-parse --show-toplevel 2>/dev/null)" || die "must run inside the Oliphaunt git checkout" -fi -manifest="${OLIPHAUNT_NODE_FALLBACK_MANIFEST:-$root/src/sources/toolchains/node.toml}" -extractor="${OLIPHAUNT_NODE_HEADERS_EXTRACTOR:-$root/tools/release/extract-node-headers.mjs}" -curl_platform_flags="$root/tools/dev/curl-platform-flags.sh" -cache_root="${OLIPHAUNT_NODE_FALLBACK_CACHE_ROOT:-$root/target/oliphaunt-node-direct}" - -[ -f "$manifest" ] || die "missing Node toolchain manifest: $manifest" -[ -f "$extractor" ] || die "missing Node headers extractor: $extractor" -if [ ! -f "$curl_platform_flags" ] || [ -L "$curl_platform_flags" ]; then - die "missing regular curl platform policy: $curl_platform_flags" -fi -# shellcheck source=tools/dev/curl-platform-flags.sh -. "$curl_platform_flags" - -manifest_values="$({ - awk ' - function reject(message) { - print "invalid Node toolchain manifest at line " NR ": " message > "/dev/stderr" - invalid = 1 - exit 1 - } - function quoted_value(line, value) { - value = line - sub(/^[^=]*=[[:space:]]*"/, "", value) - sub(/"[[:space:]]*$/, "", value) - return value - } - { - sub(/\r$/, "") - line = $0 - trimmed = line - sub(/^[[:space:]]+/, "", trimmed) - sub(/[[:space:]]+$/, "", trimmed) - if (trimmed == "" || trimmed ~ /^#/) next - if (trimmed ~ /^\[/) { - if (trimmed != "[toolchain]" && trimmed != "[headers]" && trimmed != "[windows.x64]") { - reject("unexpected section " trimmed) - } - section = trimmed - sections[section]++ - if (sections[section] != 1) reject("duplicate section " section) - next - } - if (section == "[toolchain]" && trimmed ~ /^version[[:space:]]*=[[:space:]]*"[^"]+"[[:space:]]*$/) { - counts["version"]++ - values["version"] = quoted_value(trimmed) - next - } - if (section == "[headers]" && trimmed ~ /^url[[:space:]]*=[[:space:]]*"[^"]+"[[:space:]]*$/) { - counts["headers_url"]++ - values["headers_url"] = quoted_value(trimmed) - next - } - if (section == "[headers]" && trimmed ~ /^sha256[[:space:]]*=[[:space:]]*"[^"]+"[[:space:]]*$/) { - counts["headers_sha"]++ - values["headers_sha"] = quoted_value(trimmed) - next - } - if (section == "[windows.x64]" && trimmed ~ /^url[[:space:]]*=[[:space:]]*"[^"]+"[[:space:]]*$/) { - counts["windows_url"]++ - values["windows_url"] = quoted_value(trimmed) - next - } - if (section == "[windows.x64]" && trimmed ~ /^sha256[[:space:]]*=[[:space:]]*"[^"]+"[[:space:]]*$/) { - counts["windows_sha"]++ - values["windows_sha"] = quoted_value(trimmed) - next - } - reject("unexpected or non-quoted assignment") - } - END { - if (invalid) exit 1 - if (sections["[toolchain]"] != 1 || sections["[headers]"] != 1 || sections["[windows.x64]"] != 1) { - print "invalid Node toolchain manifest: every required section must occur exactly once" > "/dev/stderr" - exit 1 - } - if (counts["version"] != 1 || counts["headers_url"] != 1 || counts["headers_sha"] != 1 || - counts["windows_url"] != 1 || counts["windows_sha"] != 1) { - print "invalid Node toolchain manifest: every required value must occur exactly once" > "/dev/stderr" - exit 1 - } - print values["version"] - print values["headers_url"] - print values["headers_sha"] - print values["windows_url"] - print values["windows_sha"] - } - ' "$manifest" -})" || die "could not parse $manifest" - -manifest_value() { - printf '%s\n' "$manifest_values" | sed -n "$1"p -} - -node_version="$(manifest_value 1)" -headers_url="$(manifest_value 2)" -headers_sha256="$(manifest_value 3)" -windows_x64_url="$(manifest_value 4)" -windows_x64_sha256="$(manifest_value 5)" - -case "$node_version" in - ''|.*|*.|*..*|*[!0-9.]*) die "manifest Node version must have numeric major.minor.patch form" ;; -esac -[ "$(printf '%s\n' "$node_version" | awk -F. 'NF == 3 && $1 != "" && $2 != "" && $3 != "" { print "valid" }')" = "valid" ] || - die "manifest Node version must have numeric major.minor.patch form" - -validate_sha256() { - value="$1" - label="$2" - [ "${#value}" -eq 64 ] || die "$label must contain exactly 64 hexadecimal characters" - case "$value" in - *[!0-9a-f]*) die "$label must contain exactly 64 lowercase hexadecimal characters" ;; - esac -} - -validate_sha256 "$headers_sha256" "headers sha256" -validate_sha256 "$windows_x64_sha256" "Windows x64 node.lib sha256" - -expected_headers_url="https://nodejs.org/download/release/v$node_version/node-v$node_version-headers.tar.gz" -expected_windows_x64_url="https://nodejs.org/download/release/v$node_version/win-x64/node.lib" -[ "$headers_url" = "$expected_headers_url" ] || die "headers URL must be $expected_headers_url" -[ "$windows_x64_url" = "$expected_windows_x64_url" ] || die "Windows x64 node.lib URL must be $expected_windows_x64_url" - -operation="${1:-}" -case "$operation" in - headers) - [ "$#" -eq 1 ] || die "usage: install-node-fallback.sh headers" - ;; - windows-lib) - [ "$#" -eq 2 ] || die "usage: install-node-fallback.sh windows-lib x64" - [ "$2" = "x64" ] || die "only the pinned Windows x64 node.lib fallback is supported" - ;; - *) die "usage: install-node-fallback.sh [x64]" ;; -esac -require node -runtime_version="$(node -p 'process.versions.node')" || die "could not read the active Node runtime version" -[ "$runtime_version" = "$node_version" ] || - die "fallback requires Node $node_version, but the active runtime is Node ${runtime_version:-}" - -if command -v sha256sum >/dev/null 2>&1; then - sha256_file() { - sha256sum "$1" | awk '{print $1}' - } -elif command -v shasum >/dev/null 2>&1; then - sha256_file() { - shasum -a 256 "$1" | awk '{print $1}' - } -else - die "missing required command: sha256sum or shasum" -fi - -partial='' -stage='' -backup='' -final='' -old_moved=0 - -cleanup() { - status=$? - trap - 0 1 2 15 - [ -z "$partial" ] || rm -f "$partial" - [ -z "$stage" ] || rm -rf "$stage" - if [ "$old_moved" -eq 1 ] && [ -n "$backup" ] && [ -e "$backup" ]; then - if [ -n "$final" ] && [ ! -e "$final" ]; then - if ! mv "$backup" "$final"; then - echo "Node fallback install failed: could not restore cache from $backup" >&2 - status=1 - fi - else - rm -rf "$backup" - fi - elif [ -n "$backup" ]; then - rm -rf "$backup" - fi - exit "$status" -} -trap cleanup 0 -trap 'exit 129' 1 -trap 'exit 130' 2 -trap 'exit 143' 15 - -download() { - url="$1" - output="$2" - max_bytes="$3" - curl_command="${OLIPHAUNT_NODE_FALLBACK_CURL:-curl}" - require "$curl_command" - curl_platform_tls_flag="$(oliphaunt_curl_platform_tls_flag)" - # The expansion is either absent or the single literal emitted by the - # repository-owned platform policy. - # shellcheck disable=SC2086 - "$curl_command" \ - --fail \ - --location \ - --silent \ - --show-error \ - --proto '=https' \ - --proto-redir '=https' \ - --retry 5 \ - --retry-all-errors \ - --retry-delay 2 \ - --retry-max-time 120 \ - --connect-timeout 20 \ - --max-time 180 \ - --max-filesize "$max_bytes" \ - ${curl_platform_tls_flag:+"$curl_platform_tls_flag"} \ - --remove-on-error \ - --output "$output" \ - "$url" -} - -headers_cache_valid() { - candidate="$1" - marker="$candidate/.oliphaunt-source.sha256" - [ -d "$candidate/include/node" ] && [ ! -L "$candidate/include/node" ] || return 1 - for required_header in node_api.h node.h v8.h; do - required_path="$candidate/include/node/$required_header" - [ -f "$required_path" ] && [ ! -L "$required_path" ] && [ -s "$required_path" ] || return 1 - done - [ -f "$marker" ] && [ ! -L "$marker" ] || return 1 - [ "$(awk 'END { print NR }' "$marker")" = "2" ] || return 1 - marker_contents="$(cat "$marker")" || return 1 - expected_marker="$(printf 'version=%s\narchive_sha256=%s\n' "$node_version" "$headers_sha256")" - [ "$marker_contents" = "$expected_marker" ] || return 1 -} - -install_headers() { - parent="$cache_root/node-headers" - final="$parent/v$node_version" - if headers_cache_valid "$final"; then - printf '%s\n' "$final/include/node" - return - fi - - require mktemp - mkdir -p "$parent" - partial="$(mktemp "$parent/.node-v$node_version-headers.partial.XXXXXX")" - stage="$(mktemp -d "$parent/.node-v$node_version-headers.stage.XXXXXX")" - download "$headers_url" "$partial" 67108864 - actual_sha256="$(sha256_file "$partial")" - [ "$actual_sha256" = "$headers_sha256" ] || - die "Node headers checksum mismatch: expected $headers_sha256, received $actual_sha256" - node "$extractor" "$partial" "$stage" "node-v$node_version" - printf 'version=%s\narchive_sha256=%s\n' "$node_version" "$headers_sha256" >"$stage/.oliphaunt-source.sha256" - headers_cache_valid "$stage" || die "staged Node headers cache failed validation" - - if [ -e "$final" ] || [ -L "$final" ]; then - backup="$(mktemp -d "$parent/.node-v$node_version-headers.backup.XXXXXX")" - rmdir "$backup" - mv "$final" "$backup" - old_moved=1 - fi - mv "$stage" "$final" - stage='' - if [ "$old_moved" -eq 1 ]; then - rm -rf "$backup" - backup='' - old_moved=0 - fi - rm -f "$partial" - partial='' - printf '%s\n' "$final/include/node" -} - -install_windows_lib() { - parent="$cache_root/node-lib/v$node_version-win-x64" - final="$parent/node.lib" - mkdir -p "$parent" - if [ -f "$final" ] && [ ! -L "$final" ]; then - actual_sha256="$(sha256_file "$final")" - if [ "$actual_sha256" = "$windows_x64_sha256" ]; then - printf '%s\n' "$final" - return - fi - fi - if [ -e "$final" ] || [ -L "$final" ]; then - rm -rf "$final" - fi - - require mktemp - partial="$(mktemp "$parent/.node.lib.partial.XXXXXX")" - download "$windows_x64_url" "$partial" 134217728 - actual_sha256="$(sha256_file "$partial")" - [ "$actual_sha256" = "$windows_x64_sha256" ] || - die "Windows x64 node.lib checksum mismatch: expected $windows_x64_sha256, received $actual_sha256" - [ -s "$partial" ] || die "downloaded Windows x64 node.lib is empty" - mv "$partial" "$final" - partial='' - printf '%s\n' "$final" -} - -case "$operation" in - headers) install_headers ;; - windows-lib) install_windows_lib ;; -esac diff --git a/tools/release/install-node-fallback.test.sh b/tools/release/install-node-fallback.test.sh deleted file mode 100644 index 54bcc7bc5..000000000 --- a/tools/release/install-node-fallback.test.sh +++ /dev/null @@ -1,433 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel)" -installer="$root/tools/release/install-node-fallback.sh" -extractor="$root/tools/release/extract-node-headers.mjs" -production_manifest="$root/src/sources/toolchains/node.toml" -test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-node-fallback-test.XXXXXX")" -trap 'rm -rf "$test_root"' EXIT - -fail() { - echo "install-node-fallback.test.sh: $*" >&2 - exit 1 -} - -sha256_file() { - if command -v sha256sum >/dev/null 2>&1; then - sha256sum "$1" | awk '{print $1}' - else - shasum -a 256 "$1" | awk '{print $1}' - fi -} - -assert_contains() { - local path="$1" - local expected="$2" - grep -F -- "$expected" "$path" >/dev/null || fail "$path did not contain: $expected" -} - -assert_curl_arg() { - local expected="$1" - grep -Fx -- "$expected" "$CASE_CURL_LOG" >/dev/null || fail "curl did not receive argument: $expected" -} - -assert_no_install_debris() { - local leftover - leftover="$(find "$CASE_CACHE" -type d \( -name '*.stage.*' -o -name '*.backup.*' \) -print -quit)" - [ -z "$leftover" ] || fail "$CASE_NAME left staging/backup directory behind: $leftover" - leftover="$(find "$CASE_CACHE" -type f -name '*.partial.*' -print -quit)" - [ -z "$leftover" ] || fail "$CASE_NAME left partial download behind: $leftover" -} - -fixtures="$test_root/fixtures" -mkdir -p "$fixtures" -node - "$fixtures" <<'JS' -const {writeFileSync} = require('node:fs'); -const path = require('node:path'); -const {gzipSync} = require('node:zlib'); - -const output = process.argv[2]; -const blockSize = 512; -const root = 'node-v22.22.3'; - -function writeString(block, offset, length, value) { - const bytes = Buffer.from(value, 'ascii'); - if (bytes.length > length) throw new Error(`field is too long: ${value}`); - bytes.copy(block, offset); -} - -function writeOctal(block, offset, length, value) { - const encoded = `${value.toString(8).padStart(length - 1, '0')}\0`; - writeString(block, offset, length, encoded); -} - -function header(name, size, type = '0', linkName = '') { - const block = Buffer.alloc(blockSize); - writeString(block, 0, 100, name); - writeOctal(block, 100, 8, type === '5' ? 0o755 : 0o644); - writeOctal(block, 108, 8, 0); - writeOctal(block, 116, 8, 0); - writeOctal(block, 124, 12, size); - writeOctal(block, 136, 12, 0); - block.fill(0x20, 148, 156); - block[156] = type.charCodeAt(0); - writeString(block, 157, 100, linkName); - writeString(block, 257, 6, 'ustar'); - writeString(block, 263, 2, '00'); - let checksum = 0; - for (const byte of block) checksum += byte; - writeString(block, 148, 8, `${checksum.toString(8).padStart(6, '0')}\0 `); - return block; -} - -function entry(name, contents = '', type = '0', options = {}) { - const data = Buffer.isBuffer(contents) ? contents : Buffer.from(contents); - const declaredSize = options.declaredSize ?? data.length; - const blocks = [header(name, declaredSize, type, options.linkName ?? '')]; - if (!options.omitPayload && data.length > 0) { - blocks.push(data, Buffer.alloc((blockSize - (data.length % blockSize)) % blockSize)); - } - return blocks; -} - -function archive(name, entries) { - writeFileSync(path.join(output, name), gzipSync(Buffer.concat([...entries.flat(), Buffer.alloc(blockSize * 2)]))); -} - -const required = [ - ...entry(`${root}/`, '', '5'), - ...entry(`${root}/include/`, '', '5'), - ...entry(`${root}/include/node/`, '', '5'), - ...entry(`${root}/include/node/node_api.h`, 'node api\n'), - ...entry(`${root}/include/node/node.h`, 'node\n'), - ...entry(`${root}/include/node/v8.h`, 'v8\n'), -]; -const longName = `${root}/include/node/openssl/archs/solaris64-x86_64-gcc/asm_avx2/providers/common/include/prov/der_digests.h`; -const longNameRecord = entry('././@LongLink', Buffer.from(`${longName}\0`), 'L'); -const longNameFile = entry(longName.slice(0, 100), 'long name\n'); -archive('valid.tar.gz', [...required, ...longNameRecord, ...longNameFile]); -archive('duplicate.tar.gz', [...required, ...entry(`${root}/include/node/node.h`, 'duplicate\n')]); -archive('traversal.tar.gz', [...required, ...entry(`${root}/../../escaped`, 'escape\n')]); -archive('symlink.tar.gz', [...required, ...entry(`${root}/include/node/link`, '', '2', {linkName: '../../escape'})]); -archive('oversized.tar.gz', [ - ...required, - ...entry(`${root}/include/node/oversized.h`, '', '0', {declaredSize: 32 * 1024 * 1024 + 1, omitPayload: true}), -]); -archive('missing-layout.tar.gz', [ - ...entry(`${root}/`, '', '5'), - ...entry(`${root}/include/node/node_api.h`, 'node api\n'), - ...entry(`${root}/include/node/node.h`, 'node\n'), -]); - -const valid = require('node:fs').readFileSync(path.join(output, 'valid.tar.gz')); -writeFileSync(path.join(output, 'truncated.tar.gz'), valid.subarray(0, Math.floor(valid.length / 2))); -writeFileSync(path.join(output, 'node.lib'), Buffer.from('mock pinned Windows import library\n')); -JS - -valid_archive="$fixtures/valid.tar.gz" -lib_fixture="$fixtures/node.lib" -valid_headers_sha="$(sha256_file "$valid_archive")" -valid_lib_sha="$(sha256_file "$lib_fixture")" - -fake_bin="$test_root/fake-bin" -mkdir -p "$fake_bin" -cat >"$fake_bin/node" <<'SH' -#!/usr/bin/env bash -set -euo pipefail -if [ "$#" -eq 2 ] && [ "$1" = "-p" ] && [ "$2" = "process.versions.node" ]; then - printf '%s\n' "$NODE_FALLBACK_TEST_RUNTIME_VERSION" - exit 0 -fi -exec "$NODE_FALLBACK_TEST_REAL_NODE" "$@" -SH -cat >"$fake_bin/curl" <<'SH' -#!/usr/bin/env bash -set -euo pipefail -printf '%s\n' "$@" >>"$NODE_FALLBACK_TEST_CURL_LOG" -output='' -while [ "$#" -gt 0 ]; do - case "$1" in - --output) - output="$2" - shift 2 - ;; - *) shift ;; - esac -done -[ -n "$output" ] || exit 64 -if [ -n "${NODE_FALLBACK_TEST_FINAL_MUST_BE_ABSENT:-}" ] && [ -e "$NODE_FALLBACK_TEST_FINAL_MUST_BE_ABSENT" ]; then - echo "final cache path became visible before download completed" >&2 - exit 75 -fi -case "${NODE_FALLBACK_TEST_CURL_MODE:-success}" in - success) - cp "$NODE_FALLBACK_TEST_CURL_SOURCE" "$output" - ;; - transport) - printf 'partial transport bytes\n' >"$output" - exit 56 - ;; - interrupt) - printf 'partial interrupted bytes\n' >"$output" - kill -TERM "$PPID" - sleep 1 - exit 143 - ;; - *) exit 64 ;; -esac -SH -cat >"$fake_bin/mv" <<'SH' -#!/usr/bin/env bash -set -euo pipefail -if [ -n "${NODE_FALLBACK_TEST_MV_FAIL_DEST:-}" ] && [ "$#" -eq 2 ] && - [ "$2" = "$NODE_FALLBACK_TEST_MV_FAIL_DEST" ] && [[ "$1" == *.stage.* ]]; then - exit 73 -fi -exec /bin/mv "$@" -SH -chmod 0755 "$fake_bin"/* -real_node="$(command -v node)" - -write_manifest() { - local path="$1" - local headers_sha="$2" - local lib_sha="$3" - local version="${4:-22.22.3}" - cat >"$path" <"$CASE_CURL_LOG" - write_manifest "$CASE_MANIFEST" "$valid_headers_sha" "$valid_lib_sha" -} - -run_installer() { - local source="$1" - local mode="$2" - local final_must_be_absent="$3" - shift 3 - if env \ - PATH="$fake_bin:$PATH" \ - NODE_FALLBACK_TEST_REAL_NODE="$real_node" \ - NODE_FALLBACK_TEST_RUNTIME_VERSION="${CASE_RUNTIME_VERSION:-22.22.3}" \ - NODE_FALLBACK_TEST_CURL_LOG="$CASE_CURL_LOG" \ - NODE_FALLBACK_TEST_CURL_SOURCE="$source" \ - NODE_FALLBACK_TEST_CURL_MODE="$mode" \ - NODE_FALLBACK_TEST_FINAL_MUST_BE_ABSENT="$final_must_be_absent" \ - NODE_FALLBACK_TEST_MV_FAIL_DEST="${CASE_MV_FAIL_DEST:-}" \ - RUNNER_OS="${CASE_RUNNER_OS:-Linux}" \ - OLIPHAUNT_NODE_FALLBACK_ROOT="$root" \ - OLIPHAUNT_NODE_FALLBACK_MANIFEST="$CASE_MANIFEST" \ - OLIPHAUNT_NODE_FALLBACK_CACHE_ROOT="$CASE_CACHE" \ - OLIPHAUNT_NODE_HEADERS_EXTRACTOR="$extractor" \ - sh "$installer" "$@" >"$CASE_STDOUT" 2>"$CASE_STDERR"; then - CASE_STATUS=0 - else - CASE_STATUS=$? - fi -} - -new_case runtime-mismatch -CASE_RUNTIME_VERSION="22.22.2" -run_installer "$valid_archive" success '' headers -[ "$CASE_STATUS" -ne 0 ] || fail "runtime mismatch unexpectedly succeeded" -assert_contains "$CASE_STDERR" "active runtime is Node 22.22.2" -[ ! -s "$CASE_CURL_LOG" ] || fail "runtime mismatch reached curl" -unset CASE_RUNTIME_VERSION - -new_case invalid-manifest -printf '\nunexpected = "metadata"\n' >>"$CASE_MANIFEST" -run_installer "$valid_archive" success '' headers -[ "$CASE_STATUS" -ne 0 ] || fail "unexpected manifest metadata was accepted" -[ ! -s "$CASE_CURL_LOG" ] || fail "invalid manifest reached curl" - -new_case invalid-manifest-sha -write_manifest "$CASE_MANIFEST" "not-a-sha256" "$valid_lib_sha" -run_installer "$valid_archive" success '' headers -[ "$CASE_STATUS" -ne 0 ] || fail "invalid manifest SHA-256 was accepted" -[ ! -s "$CASE_CURL_LOG" ] || fail "invalid manifest SHA-256 reached curl" - -new_case incomplete-manifest -sed '$d' "$CASE_MANIFEST" >"$CASE_MANIFEST.next" -mv "$CASE_MANIFEST.next" "$CASE_MANIFEST" -run_installer "$valid_archive" success '' headers -[ "$CASE_STATUS" -ne 0 ] || fail "incomplete manifest was accepted" -[ ! -s "$CASE_CURL_LOG" ] || fail "incomplete manifest reached curl" - -new_case duplicate-manifest-section -printf '\n[headers]\nurl = "https://nodejs.org/download/release/v22.22.3/node-v22.22.3-headers.tar.gz"\nsha256 = "%s"\n' \ - "$valid_headers_sha" >>"$CASE_MANIFEST" -run_installer "$valid_archive" success '' headers -[ "$CASE_STATUS" -ne 0 ] || fail "duplicate manifest section was accepted" -[ ! -s "$CASE_CURL_LOG" ] || fail "duplicate manifest section reached curl" - -new_case invalid-manifest-version -write_manifest "$CASE_MANIFEST" "$valid_headers_sha" "$valid_lib_sha" "22.latest.3" -run_installer "$valid_archive" success '' headers -[ "$CASE_STATUS" -ne 0 ] || fail "invalid manifest version was accepted" -[ ! -s "$CASE_CURL_LOG" ] || fail "invalid manifest version reached curl" - -new_case wrong-url -sed 's#https://nodejs.org/download/release/#https://example.invalid/#' "$CASE_MANIFEST" >"$CASE_MANIFEST.next" -mv "$CASE_MANIFEST.next" "$CASE_MANIFEST" -run_installer "$valid_archive" success '' headers -[ "$CASE_STATUS" -ne 0 ] || fail "wrong manifest URL was accepted" -[ ! -s "$CASE_CURL_LOG" ] || fail "wrong manifest URL reached curl" - -new_case headers-success -headers_final="$CASE_CACHE/node-headers/v22.22.3" -run_installer "$valid_archive" success "$headers_final" headers -[ "$CASE_STATUS" -eq 0 ] || fail "valid headers install failed: $(cat "$CASE_STDERR")" -[ "$(cat "$CASE_STDOUT")" = "$headers_final/include/node" ] || fail "headers install returned the wrong include directory" -for header in node_api.h node.h v8.h; do - [ -s "$headers_final/include/node/$header" ] || fail "headers install omitted $header" -done -assert_contains "$headers_final/.oliphaunt-source.sha256" "archive_sha256=$valid_headers_sha" -assert_no_install_debris -for argument in \ - --fail \ - --location \ - --retry-all-errors \ - --retry-max-time \ - --connect-timeout \ - --max-time \ - --max-filesize \ - --remove-on-error \ - --proto \ - --proto-redir \ - '=https' \ - 'https://nodejs.org/download/release/v22.22.3/node-v22.22.3-headers.tar.gz'; do - assert_curl_arg "$argument" -done -if grep -Fx -- '--ssl-revoke-best-effort' "$CASE_CURL_LOG" >/dev/null; then - fail "Linux Node headers transport unexpectedly used the Windows Schannel flag" -fi - -: >"$CASE_CURL_LOG" -run_installer "$fixtures/does-not-exist" transport '' headers -[ "$CASE_STATUS" -eq 0 ] || fail "valid headers cache hit failed" -[ ! -s "$CASE_CURL_LOG" ] || fail "valid headers cache hit reached curl" - -new_case corrupt-headers-cache -headers_final="$CASE_CACHE/node-headers/v22.22.3" -mkdir -p "$headers_final/include/node" -printf 'old corrupt cache\n' >"$headers_final/old-sentinel" -printf 'broken\n' >"$headers_final/include/node/node_api.h" -printf 'version=22.22.3\narchive_sha256=%s\n' "$valid_headers_sha" >"$headers_final/.oliphaunt-source.sha256" -run_installer "$valid_archive" success '' headers -[ "$CASE_STATUS" -eq 0 ] || fail "corrupt headers cache was not repaired: $(cat "$CASE_STDERR")" -[ ! -e "$headers_final/old-sentinel" ] || fail "corrupt headers cache contents survived promotion" -[ -s "$headers_final/include/node/v8.h" ] || fail "repaired headers cache is incomplete" -assert_no_install_debris - -new_case headers-checksum-mismatch -write_manifest "$CASE_MANIFEST" "0000000000000000000000000000000000000000000000000000000000000000" "$valid_lib_sha" -headers_final="$CASE_CACHE/node-headers/v22.22.3" -run_installer "$valid_archive" success "$headers_final" headers -[ "$CASE_STATUS" -ne 0 ] || fail "headers checksum mismatch unexpectedly succeeded" -assert_contains "$CASE_STDERR" "headers checksum mismatch" -[ ! -e "$headers_final" ] || fail "checksum mismatch exposed a final headers cache" -assert_no_install_debris - -for fixture_name in truncated traversal duplicate symlink oversized missing-layout; do - new_case "headers-$fixture_name" - fixture="$fixtures/$fixture_name.tar.gz" - write_manifest "$CASE_MANIFEST" "$(sha256_file "$fixture")" "$valid_lib_sha" - headers_final="$CASE_CACHE/node-headers/v22.22.3" - run_installer "$fixture" success "$headers_final" headers - [ "$CASE_STATUS" -ne 0 ] || fail "$fixture_name headers archive unexpectedly succeeded" - [ ! -e "$headers_final" ] || fail "$fixture_name headers archive exposed a final cache" - [ ! -e "$CASE_CACHE/escaped" ] || fail "$fixture_name headers archive escaped its staging root" - assert_no_install_debris -done - -new_case headers-transport-failure -headers_final="$CASE_CACHE/node-headers/v22.22.3" -run_installer "$valid_archive" transport "$headers_final" headers -[ "$CASE_STATUS" -ne 0 ] || fail "headers transport failure unexpectedly succeeded" -[ ! -e "$headers_final" ] || fail "transport failure exposed a final headers cache" -assert_no_install_debris - -new_case headers-interruption -headers_final="$CASE_CACHE/node-headers/v22.22.3" -run_installer "$valid_archive" interrupt "$headers_final" headers -[ "$CASE_STATUS" -ne 0 ] || fail "interrupted headers download unexpectedly succeeded" -[ ! -e "$headers_final" ] || fail "interrupted download exposed a final headers cache" -assert_no_install_debris - -new_case headers-promotion-rollback -headers_final="$CASE_CACHE/node-headers/v22.22.3" -mkdir -p "$headers_final" -printf 'previous cache\n' >"$headers_final/previous-sentinel" -CASE_MV_FAIL_DEST="$headers_final" -run_installer "$valid_archive" success '' headers -[ "$CASE_STATUS" -ne 0 ] || fail "forced headers promotion failure unexpectedly succeeded" -[ -f "$headers_final/previous-sentinel" ] || fail "headers promotion failure did not restore the previous cache" -assert_no_install_debris -unset CASE_MV_FAIL_DEST - -new_case windows-lib-repair -CASE_RUNNER_OS=Windows -lib_final="$CASE_CACHE/node-lib/v22.22.3-win-x64/node.lib" -mkdir -p "$(dirname "$lib_final")" -printf 'corrupt import library\n' >"$lib_final" -run_installer "$lib_fixture" success "$lib_final" windows-lib x64 -[ "$CASE_STATUS" -eq 0 ] || fail "corrupt node.lib cache was not repaired: $(cat "$CASE_STDERR")" -[ "$(sha256_file "$lib_final")" = "$valid_lib_sha" ] || fail "promoted node.lib has the wrong checksum" -[ "$(cat "$CASE_STDOUT")" = "$lib_final" ] || fail "node.lib install returned the wrong path" -assert_no_install_debris -assert_curl_arg --ssl-revoke-best-effort -if grep -E -x -- '--insecure|-k' "$CASE_CURL_LOG" >/dev/null; then - fail "Windows node.lib transport disabled TLS validation" -fi - -: >"$CASE_CURL_LOG" -run_installer "$fixtures/does-not-exist" transport '' windows-lib x64 -[ "$CASE_STATUS" -eq 0 ] || fail "valid node.lib cache hit failed" -[ ! -s "$CASE_CURL_LOG" ] || fail "valid node.lib cache hit reached curl" - -new_case windows-lib-checksum-mismatch -write_manifest "$CASE_MANIFEST" "$valid_headers_sha" "0000000000000000000000000000000000000000000000000000000000000000" -lib_final="$CASE_CACHE/node-lib/v22.22.3-win-x64/node.lib" -run_installer "$lib_fixture" success "$lib_final" windows-lib x64 -[ "$CASE_STATUS" -ne 0 ] || fail "node.lib checksum mismatch unexpectedly succeeded" -[ ! -e "$lib_final" ] || fail "node.lib checksum mismatch exposed a final cache file" -assert_no_install_debris - -new_case windows-lib-transport-failure -lib_final="$CASE_CACHE/node-lib/v22.22.3-win-x64/node.lib" -run_installer "$lib_fixture" transport "$lib_final" windows-lib x64 -[ "$CASE_STATUS" -ne 0 ] || fail "node.lib transport failure unexpectedly succeeded" -[ ! -e "$lib_final" ] || fail "node.lib transport failure exposed a final cache file" -assert_no_install_debris - -new_case unsupported-windows-arch -run_installer "$lib_fixture" success '' windows-lib arm64 -[ "$CASE_STATUS" -ne 0 ] || fail "unpinned Windows arm64 node.lib fallback was accepted" -[ ! -s "$CASE_CURL_LOG" ] || fail "unsupported Windows architecture reached curl" -unset CASE_RUNNER_OS - -[ -s "$production_manifest" ] || fail "production Node manifest is missing" - -printf 'Node fallback installer fault tests passed\n' diff --git a/tools/release/ios-carrier-manifest.mjs b/tools/release/ios-carrier-manifest.mjs deleted file mode 100644 index 1849bdc68..000000000 --- a/tools/release/ios-carrier-manifest.mjs +++ /dev/null @@ -1,1178 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { - existsSync, - lstatSync, - mkdirSync, - readFileSync, - readdirSync, - statSync, - writeFileSync, -} from "node:fs"; -import { pathToFileURL } from "node:url"; -import path from "node:path"; - -import { - ROOT, - compareText, - tagPrefix, -} from "./release-graph.mjs"; -import { - currentProductVersionSync, - extensionProductForSqlName, - extensionReleaseProductForSqlName, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { - extensionCarrierLegalContract, - extensionUpstreamLicenseRow, -} from "./extension-upstream-licenses.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - releaseNoticeRows, - releaseProfilePackageLicense, -} from "./release-notices.mjs"; - -export const IOS_CARRIER_SCHEMA = "oliphaunt-react-native-ios-carrier-v1"; -export const IOS_CARRIER_FILENAME = "oliphaunt-react-native-ios-carriers.json"; -export const SWIFT_EXTENSION_CARRIER_SCHEMA = "oliphaunt-swift-extension-carrier-v1"; -export const DEFAULT_IOS_CARRIER = path.join( - ROOT, - "target/release/ios-carriers", - IOS_CARRIER_FILENAME, -); - -const DEFAULT_REPOSITORY = "f0rr0/oliphaunt"; -const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; -const PORTABLE_IDENTIFIER = /^[A-Za-z0-9._-]{1,128}$/u; -const C_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u; -const MAX_ARCHIVE_BYTES = 2 * 1024 * 1024 * 1024; -const MAX_ARCHIVE_ENTRIES = 32_768; -const IOS_CARRIER_ARCHIVE_LIMITS = Object.freeze({ - maxArchiveBytes: MAX_ARCHIVE_BYTES, - maxEntries: MAX_ARCHIVE_ENTRIES, - maxEntryBytes: MAX_ARCHIVE_BYTES, - maxExpandedBytes: MAX_ARCHIVE_BYTES, -}); -const BASE_LEGAL_PROFILES = Object.freeze([ - Object.freeze({ - assetRole: "base-xcframework", - memberPrefix: "liboliphaunt.xcframework", - profile: "native-runtime", - }), - Object.freeze({ - assetRole: "runtime-resources", - memberPrefix: "", - profile: "native-runtime-resources", - }), - Object.freeze({ - assetRole: "icu-data", - memberPrefix: "", - profile: "native-icu-data", - }), -]); - -function error(message) { - return new Error(`ios-carrier-manifest: ${message}`); -} - -function stableVersion(value, label) { - if (typeof value !== "string" || !STABLE_SEMVER.test(value)) { - throw error(`${label} must be a stable SemVer X.Y.Z version`); - } - return value; -} - -function exactObjectKeys(value, expected, label) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(`${label} must be an object`); - } - const actual = Object.keys(value).sort(compareText); - const canonical = [...expected].sort(compareText); - if (JSON.stringify(actual) !== JSON.stringify(canonical)) { - throw error(`${label} fields must be exactly ${canonical.join(",")}; got ${actual.join(",")}`); - } - return value; -} - -function portableIdentifier(value, label) { - if (typeof value !== "string" || !PORTABLE_IDENTIFIER.test(value)) { - throw error(`${label} must be a portable identifier`); - } - return value; -} - -function canonicalStringList(value, label, validate = portableIdentifier) { - if (!Array.isArray(value)) throw error(`${label} must be an array`); - const rows = value.map((item, index) => validate(item, `${label}[${index}]`)); - if (new Set(rows).size !== rows.length) throw error(`${label} must not contain duplicates`); - const canonical = [...rows].sort(compareText); - if (JSON.stringify(value) !== JSON.stringify(canonical)) { - throw error(`${label} must be sorted in ordinal order`); - } - return canonical; -} - -function compatibilityMetadata(value, label) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(`${label} must be an object`); - } - const expectedKeys = [ - "extensionRuntimeContract", - "nativeRuntimeProduct", - "nativeRuntimeVersion", - "postgresMajor", - "wasixRuntimeProduct", - "wasixRuntimeVersion", - ]; - const actualKeys = Object.keys(value).sort(compareText); - if (JSON.stringify(actualKeys) !== JSON.stringify([...expectedKeys].sort(compareText))) { - throw error(`${label} must contain the exact stable compatibility fields`); - } - if (value.postgresMajor !== "18") throw error(`${label}.postgresMajor must be 18`); - if (value.nativeRuntimeProduct !== "liboliphaunt-native") { - throw error(`${label}.nativeRuntimeProduct must be liboliphaunt-native`); - } - if (value.wasixRuntimeProduct !== "liboliphaunt-wasix") { - throw error(`${label}.wasixRuntimeProduct must be liboliphaunt-wasix`); - } - if ( - typeof value.extensionRuntimeContract !== "string" || - value.extensionRuntimeContract.length === 0 - ) { - throw error(`${label}.extensionRuntimeContract must be a non-empty path`); - } - return { - extensionRuntimeContract: value.extensionRuntimeContract, - nativeRuntimeProduct: value.nativeRuntimeProduct, - nativeRuntimeVersion: stableVersion( - value.nativeRuntimeVersion, - `${label}.nativeRuntimeVersion`, - ), - postgresMajor: value.postgresMajor, - wasixRuntimeProduct: value.wasixRuntimeProduct, - wasixRuntimeVersion: stableVersion( - value.wasixRuntimeVersion, - `${label}.wasixRuntimeVersion`, - ), - }; -} - -function validateRepository(repository) { - if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository)) { - throw error(`invalid GitHub repository ${repository}`); - } - return repository; -} - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function requireFile(file, label) { - let fileStat; - try { - fileStat = lstatSync(file); - } catch { - throw error(`missing ${label}: ${path.relative(ROOT, file)}`); - } - if (!fileStat.isFile()) { - throw error(`${label} must be a regular file: ${path.relative(ROOT, file)}`); - } - return file; -} - -function stable(value) { - if (Array.isArray(value)) return value.map(stable); - if (value !== null && typeof value === "object") { - return Object.fromEntries(Object.keys(value).sort(compareText).map((key) => [key, stable(value[key])])); - } - return value; -} - -function archiveStat(file) { - const stat = lstatSync(file, { bigint: true }); - if (!stat.isFile() || stat.size <= 0n || stat.size > BigInt(MAX_ARCHIVE_BYTES)) { - throw error(`${path.basename(file)} must be a non-empty regular archive no larger than ${MAX_ARCHIVE_BYTES} bytes`); - } - return stat; -} - -function archiveCacheKey(file, format, stat, includeDigests) { - return [ - format, - includeDigests ? "digests" : "metadata", - path.resolve(file), - stat.dev, - stat.ino, - stat.size, - stat.mtimeNs, - stat.ctimeNs, - ].join("\0"); -} - -function archiveIndex(file, format, cache = new Map(), { includeDigests = false } = {}) { - if (format !== "zip" && format !== "tar.gz") throw error(`unsupported archive listing format ${format}`); - const stat = archiveStat(file); - const key = archiveCacheKey(file, format, stat, includeDigests); - const cached = cache.get(key); - if (cached !== undefined) return cached; - const portableEntries = readPortableArchiveEntries(file, { - ...IOS_CARRIER_ARCHIVE_LIMITS, - format, - }); - // The portable reader's lazy ZIP payload closures retain the whole archive, - // and tar payload closures retain the inflated tar buffer. Cache only inert - // metadata (plus one digest per aggregate member) so a complete manifest - // build never keeps dozens of carrier archives resident. - const entries = [...portableEntries.values()].map((entry) => Object.freeze({ - ...(includeDigests && entry.type === "file" - ? { sha256: createHash("sha256").update(entry.data()).digest("hex") } - : {}), - name: entry.name, - mode: entry.mode, - size: entry.size, - type: entry.type, - })); - portableEntries.clear(); - const index = Object.freeze({ - byName: new Map(entries.map((entry) => [entry.name, entry])), - entries: Object.freeze(entries), - }); - cache.set(key, index); - return index; -} - -function listArchive(file, format, cache) { - return archiveIndex(file, format, cache).entries.map(({ name }) => name); -} - -function verifyMember(file, format, member, cache) { - const members = listArchive(file, format, cache); - if (member === ".") return; - if (!members.some((value) => value === member || value.startsWith(`${member}/`))) { - throw error(`${path.basename(file)} is missing declared archive member ${member}`); - } -} - -function verifyFileMember(file, format, member, expected, cache) { - if (format !== "tar.gz") { - throw error(`${path.basename(file)} aggregate carrier must be a tar.gz archive`); - } - if ( - !Number.isSafeInteger(expected.bytes) - || expected.bytes <= 0 - || expected.bytes > MAX_ARCHIVE_BYTES - || typeof expected.sha256 !== "string" - || !/^[0-9a-f]{64}$/u.test(expected.sha256) - ) { - throw error(`${path.basename(file)} declares invalid nested payload metadata for ${member}`); - } - const index = archiveIndex(file, format, cache, { includeDigests: true }); - const entry = index.byName.get(member); - if (entry?.type !== "file") { - throw error(`${path.basename(file)} is missing or cannot read declared archive file ${member}`); - } - if (entry.size !== expected.bytes || entry.sha256 !== expected.sha256) { - throw error(`${path.basename(file)} nested payload ${member} does not match its declared bytes/SHA-256`); - } -} - -function portableAssetName(value, label = "release asset name") { - if ( - typeof value !== "string" - || value.length === 0 - || path.posix.basename(value) !== value - || /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) - || /[ .]$/u.test(value) - || /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value) - ) { - throw error(`${label} is not a portable release asset filename: ${JSON.stringify(value)}`); - } - return value; -} - -function archiveFormat(name, label = "release asset") { - portableAssetName(name, `${label} name`); - if (name.endsWith(".zip")) return "zip"; - if (name.endsWith(".tar.gz")) return "tar.gz"; - throw error(`${label} ${name} must be a .zip or .tar.gz archive`); -} - -function safeArchivePath(value, label) { - if ( - typeof value !== "string" - || value.length === 0 - || value.includes("\\") - || value.startsWith("/") - || /^[A-Za-z]:/u.test(value) - || /[\u0000-\u001f\u007f]/u.test(value) - ) { - throw error(`${label} must be a safe POSIX archive path`); - } - const parts = value.replace(/^\.\//u, "").split("/"); - if (parts.some((part) => part.length === 0 || part === "." || part === "..")) { - throw error(`${label} must be a safe POSIX archive path`); - } - return parts.join("/"); -} - -function legalKind(member, declared = undefined) { - if (declared !== undefined) return declared; - return path.posix.basename(member).includes("NOTICE") ? "notice" : "license"; -} - -function prefixedMember(prefix, member) { - return prefix ? `${prefix}/${member}` : member; -} - -function canonicalLegalFileSpecs(profile, memberPrefix = "") { - return releaseNoticeRows({ profile }).map((row) => ({ - bytes: statSync(row.source).size, - kind: legalKind(row.member), - member: prefixedMember(memberPrefix, row.member), - sha256: sha256(row.source), - })); -} - -function legalGroupShape({ assetRole, files, profile, spdx }) { - const canonical = [...files].sort((left, right) => compareText(left.member, right.member)); - if (new Set(canonical.map(({ member }) => member)).size !== canonical.length) { - throw error(`${assetRole} legal metadata repeats an archive member`); - } - return { - assetRole, - files: canonical, - profile, - spdx, - }; -} - -/** - * Canonical legal locators for the three native Apple base assets. The - * locators remain archive-relative; a consumer chooses the applicable groups - * (the ICU sidecar is optional) and never needs this repository to stage them. - */ -export function iosBaseLegalMetadata() { - return BASE_LEGAL_PROFILES.map(({ assetRole, memberPrefix, profile }) => - legalGroupShape({ - assetRole, - files: canonicalLegalFileSpecs(profile, memberPrefix), - profile, - spdx: releaseProfilePackageLicense(profile).spdx, - })); -} - -function assertLegalGroupArchiveBytes(file, format, group, archiveCache, label) { - const index = archiveIndex(file, format, archiveCache, { includeDigests: true }); - return legalGroupShape({ - ...group, - files: group.files.map((expected) => { - const member = safeArchivePath(expected.member, `${label} legal member`); - const entry = index.byName.get(member); - if (entry?.type !== "file") { - throw error(`${label} is missing regular legal file ${member}`); - } - if ((entry.mode & 0o777) !== 0o644) { - throw error(`${label} legal file ${member} must have mode 0644`); - } - if (entry.sha256 !== expected.sha256) { - throw error(`${label} legal file ${member} does not match its canonical SHA-256`); - } - if (expected.bytes !== undefined && entry.size !== expected.bytes) { - throw error(`${label} legal file ${member} does not match its canonical byte count`); - } - if (entry.size <= 0) throw error(`${label} legal file ${member} must be non-empty`); - return { - bytes: entry.size, - kind: expected.kind, - member, - sha256: entry.sha256, - }; - }), - }); -} - -function extensionLegalGroup({ - archiveCache, - file, - format, - product, - sqlName, -}) { - const contract = extensionCarrierLegalContract(product, [sqlName], { - family: "native", - target: "ios-xcframework", - }); - const noticeFiles = canonicalLegalFileSpecs(contract.profile); - const upstreamFiles = contract.upstreamMembers.flatMap((member) => - extensionUpstreamLicenseRow(member).files.map((row) => ({ - kind: legalKind(row.destination, row.role), - member: `files/${row.destination}`, - sha256: row.sha256, - })) - ); - const contractedDestinations = upstreamFiles - .map(({ member }) => member.replace(/^files\//u, "")) - .sort(compareText); - if (JSON.stringify(contractedDestinations) !== JSON.stringify([...contract.licenseFiles])) { - throw error(`${product}/${sqlName} iOS legal files disagree with the canonical upstream contract`); - } - return assertLegalGroupArchiveBytes( - file, - format, - legalGroupShape({ - assetRole: "runtime-resources", - files: [...noticeFiles, ...upstreamFiles], - profile: contract.profile, - spdx: contract.packageSpdx, - }), - archiveCache, - `${product}/${sqlName} iOS runtime carrier`, - ); -} - -function validateFrozenBaseLegalMetadata(value, label) { - if (!Array.isArray(value)) throw error(`${label} must be an array`); - const expected = iosBaseLegalMetadata(); - if (JSON.stringify(stable(value)) !== JSON.stringify(stable(expected))) { - throw error(`${label} does not match the canonical native Apple legal locators`); - } - return expected; -} - -function assetUrl({ file, name, tag, repository, localUrls }) { - if (localUrls) return pathToFileURL(file).href; - return `https://github.com/${repository}/releases/download/${encodeURIComponent(tag)}/${encodeURIComponent(name)}`; -} - -function asset({ file, role, member, tag, repository, localUrls, verifyMembers, archiveCache }) { - requireFile(file, `${role} asset`); - const name = portableAssetName(path.basename(file), `${role} asset name`); - const format = archiveFormat(name, `${role} asset`); - if (verifyMembers) verifyMember(file, format, member, archiveCache); - return { - role, - name, - url: assetUrl({ file, name, tag, repository, localUrls }), - sha256: sha256(file), - bytes: statSync(file).size, - format, - member, - }; -} - -function carrierEnvelope({ file, tag, repository, localUrls }) { - requireFile(file, "carrier archive"); - const name = portableAssetName(path.basename(file), "carrier archive name"); - return { - name, - url: assetUrl({ file, name, tag, repository, localUrls }), - sha256: sha256(file), - bytes: statSync(file).size, - format: archiveFormat(name, "carrier archive"), - }; -} - -function baseCarrier({ baseAssetDir, repository, localUrls, verifyMembers, archiveCache }) { - const product = "liboliphaunt-native"; - const version = currentProductVersionSync(product, "ios-carrier-manifest"); - const tag = `${tagPrefix(product, "ios-carrier-manifest")}${version}`; - const rows = [ - { - role: "base-xcframework", - name: `liboliphaunt-${version}-apple-spm-xcframework.zip`, - member: "liboliphaunt.xcframework", - }, - { - role: "runtime-resources", - name: `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`, - member: "oliphaunt", - }, - { - role: "icu-data", - name: `liboliphaunt-${version}-icu-data.tar.gz`, - member: ".", - }, - ]; - const assets = rows.map((row) => asset({ - ...row, - file: path.join(baseAssetDir, row.name), - tag, - repository, - localUrls, - verifyMembers, - archiveCache, - })); - const legal = iosBaseLegalMetadata().map((group) => { - const selected = rows.find(({ role }) => role === group.assetRole); - if (selected === undefined) throw error(`base legal group references unknown asset role ${group.assetRole}`); - return assertLegalGroupArchiveBytes( - path.join(baseAssetDir, selected.name), - archiveFormat(selected.name, `${selected.role} asset`), - group, - archiveCache, - `${product} ${selected.role}`, - ); - }); - return { - base: { product, version, tag, assets }, - legal, - }; -} - -function frozenBaseCarrier(file) { - let manifest; - try { - manifest = JSON.parse(readFileSync(requireFile(path.resolve(file), "base carrier manifest"), "utf8")); - } catch (cause) { - throw error(`cannot read base carrier manifest ${file}: ${cause.message}`); - } - const base = manifest?.schema === IOS_CARRIER_SCHEMA ? manifest.base : manifest; - const legal = manifest?.schema === IOS_CARRIER_SCHEMA ? manifest.legal?.base : manifest?.legal; - const product = "liboliphaunt-native"; - const version = currentProductVersionSync(product, "ios-carrier-manifest"); - const tag = `${tagPrefix(product, "ios-carrier-manifest")}${version}`; - if (base?.product !== product || base.version !== version || base.tag !== tag || !Array.isArray(base.assets)) { - throw error(`${file} does not freeze the current ${product} base carrier`); - } - const expectedRoles = ["base-xcframework", "runtime-resources", "icu-data"]; - if (JSON.stringify(base.assets.map(({ role }) => role)) !== JSON.stringify(expectedRoles)) { - throw error(`${file} base carrier roles must be exactly ${expectedRoles.join(", ")}`); - } - for (const [index, row] of base.assets.entries()) { - if ( - typeof row.name !== "string" - || typeof row.url !== "string" || !row.url.startsWith("https://") - || typeof row.sha256 !== "string" || !/^[0-9a-f]{64}$/u.test(row.sha256) - || !Number.isSafeInteger(row.bytes) || row.bytes <= 0 - || !["zip", "tar.gz"].includes(row.format) - || typeof row.member !== "string" || row.member.length === 0 - ) { - throw error(`${file} contains invalid base asset ${index}`); - } - portableAssetName(row.name, `${file} base asset ${index} name`); - if (archiveFormat(row.name, `${file} base asset ${index}`) !== row.format) { - throw error(`${file} base asset ${index} name does not match its archive format`); - } - } - return { - base: stable(base), - legal: validateFrozenBaseLegalMetadata(legal, `${file} base legal metadata`), - }; -} - -function validateRegistration( - value, - manifestPath, - { nativeModuleStem: expectedNativeModuleStem, sqlName: expectedSqlName }, -) { - exactObjectKeys( - value, - ["initSymbol", "magicSymbol", "nativeModuleStem", "schema", "sqlName", "symbols"], - `${manifestPath} iOS registration`, - ); - const { schema, sqlName, nativeModuleStem, magicSymbol, initSymbol, symbols } = value; - if ( - schema !== "oliphaunt-ios-extension-registration-v1" - || sqlName !== expectedSqlName - || nativeModuleStem !== expectedNativeModuleStem - || typeof magicSymbol !== "string" || !C_IDENTIFIER.test(magicSymbol) - || !(initSymbol === null || (typeof initSymbol === "string" && C_IDENTIFIER.test(initSymbol))) - || !Array.isArray(symbols) - ) { - throw error(`${manifestPath} contains invalid iOS registration metadata`); - } - const canonicalSymbols = symbols.map((row, index) => { - exactObjectKeys(row, ["address", "name"], `${manifestPath} iOS registration symbol ${index}`); - if (!C_IDENTIFIER.test(row.name) || !C_IDENTIFIER.test(row.address)) { - throw error(`${manifestPath} iOS registration symbol ${index} must use C identifiers`); - } - return { name: row.name, address: row.address }; - }).sort((left, right) => compareText( - `${left.name}\0${left.address}`, - `${right.name}\0${right.address}`, - )); - if (new Set(canonicalSymbols.map(({ name }) => name)).size !== canonicalSymbols.length) { - throw error(`${manifestPath} iOS registration repeats a SQL symbol name`); - } - return { - magicSymbol, - initSymbol, - symbols: canonicalSymbols, - }; -} - -function extensionCarrier( - manifest, - manifestPath, - { aggregateCarriers, artifactProduct, repository, localUrls, release, verifyMembers, archiveCache, includeLegal }, -) { - if ( - typeof manifest.product !== "string" - || typeof manifest.version !== "string" - || typeof manifest.sqlName !== "string" - || !Array.isArray(manifest.assets) - ) { - throw error(`${manifestPath} is not an exact-extension CI artifact manifest`); - } - if (manifest.product !== artifactProduct || manifest.version !== release.version) { - throw error(`${manifestPath} extension member identity does not match its artifact product/release version`); - } - const sqlName = portableIdentifier(manifest.sqlName, `${manifestPath}.sqlName`); - if (typeof manifest.createsExtension !== "boolean") { - throw error(`${manifestPath} ${sqlName}.createsExtension must be boolean`); - } - const dependencies = canonicalStringList( - manifest.dependencies, - `${manifestPath} ${sqlName}.dependencies`, - ); - if (dependencies.includes(sqlName)) { - throw error(`${manifestPath} ${sqlName}.dependencies must not include itself`); - } - const dataFiles = canonicalStringList( - manifest.dataFiles, - `${manifestPath} ${sqlName}.dataFiles`, - (value, label) => { - const relative = safeArchivePath(value, label); - if (relative === ".") throw error(`${label} must name a file`); - return relative; - }, - ); - const extensionSqlFileNames = canonicalStringList( - manifest.extensionSqlFileNames, - `${manifestPath} ${sqlName}.extensionSqlFileNames`, - (value, label) => { - const name = portableIdentifier(value, label); - if (!name.endsWith(".sql")) throw error(`${label} must name a SQL file`); - return name; - }, - ); - const extensionSqlFilePrefixes = canonicalStringList( - manifest.extensionSqlFilePrefixes, - `${manifestPath} ${sqlName}.extensionSqlFilePrefixes`, - (value, label) => { - if (typeof value !== "string" || !/^[A-Za-z0-9_-]{1,128}$/u.test(value)) { - throw error(`${label} must be a dot-free portable SQL basename prefix`); - } - return value; - }, - ); - const sharedPreloadLibraries = canonicalStringList( - manifest.sharedPreloadLibraries, - `${manifestPath} ${sqlName}.sharedPreloadLibraries`, - ); - const tag = release.tag; - const iOS = manifest.assets.filter((row) => row?.family === "native" && row.target === "ios-xcframework"); - const allowedKinds = new Set(["runtime", "ios-xcframework", "ios-dependency-xcframework"]); - if (iOS.some((row) => !allowedKinds.has(row.kind))) { - throw error(`${manifestPath} contains an unsupported iOS asset role`); - } - const carriers = new Map(); - const rows = iOS.map((row) => { - const file = path.resolve(ROOT, row.path); - requireFile(file, `${manifest.product} ${row.kind}`); - const logicalName = portableAssetName(row.name, `${manifest.product} ${row.kind} name`); - const logicalFormat = archiveFormat(logicalName, `${manifest.product} ${row.kind}`); - if (statSync(file).size !== row.bytes || sha256(file) !== row.sha256 || path.basename(file) !== logicalName) { - throw error(`${manifestPath} metadata does not match ${row.path}`); - } - let envelope; - let memberPath; - if (row.carrierAsset === undefined) { - if (aggregateCarriers.size > 0) { - throw error(`${manifestPath} bundle member ${manifest.sqlName} lacks an aggregate carrier locator`); - } - envelope = carrierEnvelope({ file, tag, repository, localUrls }); - memberPath = "."; - } else { - const carrierName = portableAssetName(row.carrierAsset, `${manifest.product} carrierAsset`); - const aggregate = aggregateCarriers.get(carrierName); - if (aggregate === undefined) { - throw error(`${manifestPath} references undeclared aggregate carrier ${carrierName}`); - } - if (aggregate.family !== row.family || aggregate.target !== row.target) { - throw error(`${manifestPath} ${manifest.sqlName}/${row.kind} references a carrier for the wrong family/target`); - } - const carrierRoot = safeArchivePath(row.carrierRoot, `${manifestPath} carrierRoot`); - const nestedPath = safeArchivePath(row.memberPath, `${manifestPath} memberPath`); - memberPath = `${carrierRoot}/${nestedPath}`; - envelope = aggregate.envelope; - if (verifyMembers) verifyFileMember(aggregate.file, envelope.format, memberPath, row, archiveCache); - } - const prior = carriers.get(envelope.name); - if (prior !== undefined && JSON.stringify(prior) !== JSON.stringify(envelope)) { - throw error(`${manifestPath} has conflicting carrier envelopes named ${envelope.name}`); - } - carriers.set(envelope.name, envelope); - if (row.kind === "runtime") { - return { row, logicalFormat, envelope, role: "runtime-resources", member: ".", memberPath }; - } - if (row.kind === "ios-xcframework") { - return { - row, - logicalFormat, - envelope, - role: "extension-xcframework", - member: `liboliphaunt_extension_${row.identity}.xcframework`, - memberPath, - }; - } - return { - row, - logicalFormat, - envelope, - role: "dependency-xcframework", - member: `liboliphaunt_dependency_${row.identity}.xcframework`, - memberPath, - }; - }); - const assets = rows.map(({ row, logicalFormat, envelope, role, member, memberPath }) => { - if (verifyMembers) verifyMember(path.resolve(ROOT, row.path), logicalFormat, member, archiveCache); - return { - role, - carrier: envelope.name, - path: memberPath, - sha256: row.sha256, - bytes: row.bytes, - format: logicalFormat, - member, - }; - }).sort((left, right) => compareText( - `${left.role}\0${left.member}\0${left.path}`, - `${right.role}\0${right.member}\0${right.path}`, - )); - const runtimeCount = assets.filter(({ role }) => role === "runtime-resources").length; - const nativeModuleStem = manifest.nativeModuleStem === null - ? null - : portableIdentifier(manifest.nativeModuleStem, `${manifestPath} ${sqlName}.nativeModuleStem`); - const nativeDependencies = canonicalStringList( - manifest.iosNativeDependencies, - `${manifestPath} ${sqlName}.iosNativeDependencies`, - ); - if (runtimeCount !== 1) throw error(`${manifestPath} must contain exactly one iOS runtime-resources asset`); - if (nativeModuleStem === null) { - if (assets.some(({ role }) => role !== "runtime-resources") || nativeDependencies.length > 0 || manifest.iosRegistration !== null) { - throw error(`${manifestPath} SQL-only extension fabricates iOS native roles`); - } - } else { - const primary = rows.filter(({ row }) => row.kind === "ios-xcframework"); - const dependencies = rows - .filter(({ row }) => row.kind === "ios-dependency-xcframework") - .map(({ row }) => row.identity) - .sort(compareText); - if (primary.length !== 1 || primary[0].row.identity !== nativeModuleStem) { - throw error(`${manifestPath} lacks its canonical primary iOS XCFramework`); - } - if (JSON.stringify(dependencies) !== JSON.stringify(nativeDependencies)) { - throw error(`${manifestPath} iOS dependency assets do not match iosNativeDependencies`); - } - } - const registration = nativeModuleStem === null - ? null - : validateRegistration(manifest.iosRegistration, manifestPath, { nativeModuleStem, sqlName }); - const runtimeRow = rows.find(({ row }) => row.kind === "runtime"); - if (runtimeRow === undefined) throw error(`${manifestPath} lacks its iOS runtime legal carrier`); - const legal = includeLegal !== false - ? extensionLegalGroup({ - archiveCache, - file: path.resolve(ROOT, runtimeRow.row.path), - format: runtimeRow.logicalFormat, - product: artifactProduct, - sqlName, - }) - : undefined; - return { - carriers: [...carriers.values()].sort((left, right) => compareText(left.name, right.name)), - extension: { - product: artifactProduct, - releaseProduct: release.product, - version: release.version, - tag, - sqlName, - createsExtension: manifest.createsExtension, - dataFiles, - dependencies, - extensionSqlFileNames, - extensionSqlFilePrefixes, - nativeDependencies, - nativeModuleStem, - sharedPreloadLibraries, - registration, - assets, - }, - legal, - }; -} - -function extensionArtifactDocument(manifestPath) { - const document = JSON.parse(readFileSync(manifestPath, "utf8")); - if ( - document?.schema === "oliphaunt-extension-ci-artifacts-v1" - && typeof document.product === "string" - && typeof document.version === "string" - ) { - if (document.carrierAssets !== undefined) { - throw error(`${manifestPath} singleton manifest must not declare carrierAssets`); - } - return { - schema: document.schema, - product: document.product, - version: document.version, - compatibility: compatibilityMetadata( - document.compatibility, - `${manifestPath}.compatibility`, - ), - carrierAssets: [], - rows: [document], - }; - } - if ( - document?.schema === "oliphaunt-extension-ci-artifacts-v2" - && typeof document.product === "string" - && typeof document.version === "string" - && Array.isArray(document.extensions) - && document.extensions.length > 0 - ) { - return { - schema: document.schema, - product: document.product, - version: document.version, - compatibility: compatibilityMetadata( - document.compatibility, - `${manifestPath}.compatibility`, - ), - carrierAssets: document.carrierAssets, - rows: document.extensions.map((row, index) => { - if (row === null || Array.isArray(row) || typeof row !== "object") { - throw error(`${manifestPath}.extensions[${index}] must be an object`); - } - return { ...row, product: document.product, version: document.version }; - }), - }; - } - throw error(`${manifestPath} has unsupported exact-extension CI artifact schema`); -} - -function aggregateCarrierMap(document, manifestPath, { repository, localUrls, release }) { - if (document.schema === "oliphaunt-extension-ci-artifacts-v1") return new Map(); - if (!Array.isArray(document.carrierAssets) || document.carrierAssets.length === 0) { - throw error(`${manifestPath} bundle manifest must declare aggregate carrierAssets`); - } - const result = new Map(); - const groups = new Set(); - const expectedMemberCount = extensionSqlNames(document.product, "ios-carrier-manifest").length; - for (const [index, row] of document.carrierAssets.entries()) { - if ( - row === null - || Array.isArray(row) - || typeof row !== "object" - || row.kind !== "extension-bundle" - || typeof row.family !== "string" - || row.family.length === 0 - || typeof row.target !== "string" - || row.target.length === 0 - || typeof row.path !== "string" - || typeof row.sha256 !== "string" - || !/^[0-9a-f]{64}$/u.test(row.sha256) - || !Number.isSafeInteger(row.bytes) - || row.bytes <= 0 - || row.memberCount !== expectedMemberCount - ) { - throw error(`${manifestPath}.carrierAssets[${index}] is not an exact aggregate carrier row`); - } - const name = portableAssetName(row.name, `${manifestPath}.carrierAssets[${index}].name`); - const file = requireFile(path.resolve(ROOT, row.path), `${document.product} aggregate carrier`); - if (path.basename(file) !== name || statSync(file).size !== row.bytes || sha256(file) !== row.sha256) { - throw error(`${manifestPath}.carrierAssets[${index}] metadata does not match ${row.path}`); - } - const group = `${row.family}\0${row.target}`; - if (result.has(name) || groups.has(group)) { - throw error(`${manifestPath} repeats an aggregate carrier name or family/target`); - } - groups.add(group); - result.set(name, { - envelope: carrierEnvelope({ file, tag: release.tag, repository, localUrls }), - family: row.family, - file, - target: row.target, - }); - } - return result; -} - -function extensionCarriers(manifestPath, options) { - const document = extensionArtifactDocument(manifestPath); - stableVersion(document.version, `${document.product} version`); - const releaseProducts = new Set(document.rows.map((row) => - extensionReleaseProductForSqlName(row.sqlName, "native", "ios-carrier-manifest"))); - if (releaseProducts.size !== 1) { - throw error(`${manifestPath} members do not share one native release owner`); - } - const releaseProduct = [...releaseProducts][0]; - const expectedReleaseVersion = currentProductVersionSync(releaseProduct, "ios-carrier-manifest"); - if (document.version !== expectedReleaseVersion) { - throw error( - `${manifestPath} version ${document.version} does not match ${releaseProduct} ${expectedReleaseVersion}`, - ); - } - if (options.nativeRuntimeVersion !== undefined) { - const requested = stableVersion( - options.nativeRuntimeVersion, - "caller-supplied liboliphaunt-native version", - ); - if (requested !== document.compatibility.nativeRuntimeVersion) { - throw error( - `${manifestPath} pins liboliphaunt-native ${document.compatibility.nativeRuntimeVersion}, ` + - `but caller supplied ${requested}`, - ); - } - } - const release = { - product: releaseProduct, - tag: `${tagPrefix(releaseProduct, "ios-carrier-manifest")}${document.version}`, - version: document.version, - }; - const aggregateCarriers = aggregateCarrierMap(document, manifestPath, { ...options, release }); - const built = document.rows.map((row) => extensionCarrier(row, manifestPath, { - ...options, - aggregateCarriers, - artifactProduct: document.product, - release, - })); - const rows = built.map(({ extension }) => extension); - const legal = options.includeLegal === false - ? [] - : built - .map(({ extension, legal: group }) => ({ ...group, sqlName: extension.sqlName })) - .sort((left, right) => compareText(left.sqlName, right.sqlName)); - if (new Set(rows.map(({ sqlName }) => sqlName)).size !== rows.length) { - throw error(`${manifestPath} repeats an extension SQL name`); - } - const actualSqlNames = rows.map(({ sqlName }) => sqlName).sort(compareText); - const expectedSqlNames = extensionSqlNames(document.product, "ios-carrier-manifest"); - if (JSON.stringify(actualSqlNames) !== JSON.stringify(expectedSqlNames)) { - throw error(`${manifestPath} does not contain the exact ${document.product} extension member set`); - } - const carriers = new Map(); - for (const carrier of built.flatMap((row) => row.carriers)) { - const existing = carriers.get(carrier.name); - if (existing !== undefined && JSON.stringify(existing) !== JSON.stringify(carrier)) { - throw error(`${manifestPath} has conflicting carrier envelopes named ${carrier.name}`); - } - carriers.set(carrier.name, carrier); - } - return { - carriers: [...carriers.values()].sort((left, right) => compareText(left.name, right.name)), - nativeRuntimeVersion: document.compatibility.nativeRuntimeVersion, - legal, - release, - rows, - }; -} - -export function swiftExtensionCarrierAssetName(product, version) { - if (typeof product !== "string" || !/^oliphaunt-extension-[A-Za-z0-9._-]+$/u.test(product)) { - throw error(`invalid exact-extension product ${product}`); - } - stableVersion(version, `${product} version`); - return `${product}-${version}-swift-extension-carrier.json`; -} - -function dependencyCarrierReference(sqlName) { - const product = extensionProductForSqlName(sqlName, "ios-carrier-manifest"); - const releaseProduct = extensionReleaseProductForSqlName( - sqlName, - "native", - "ios-carrier-manifest", - ); - const version = currentProductVersionSync(releaseProduct, "ios-carrier-manifest"); - stableVersion(version, `${product} version`); - return { - product, - releaseProduct, - sqlName, - tag: `${tagPrefix(releaseProduct, "ios-carrier-manifest")}${version}`, - version, - }; -} - -/** - * Build the immutable extension carrier published on its native release owner. - * It references, rather than duplicates, the compatible native base. - */ -export function buildSwiftExtensionCarrierManifest({ - extensionManifest, - nativeRuntimeVersion = undefined, - repository = DEFAULT_REPOSITORY, - localUrls = false, - verifyMembers = true, -} = {}) { - validateRepository(repository); - if (typeof extensionManifest !== "string" || extensionManifest.length === 0) { - throw error("extensionManifest must be an exact-extension CI artifact manifest path"); - } - const archiveCache = new Map(); - const resolved = extensionCarriers(path.resolve(extensionManifest), { - archiveCache, - includeLegal: false, - repository, - localUrls, - nativeRuntimeVersion, - verifyMembers, - }); - const { carriers, release, rows } = resolved; - const version = resolved.nativeRuntimeVersion; - return stable({ - schema: SWIFT_EXTENSION_CARRIER_SCHEMA, - release, - base: { - product: "liboliphaunt-native", - tag: `${tagPrefix("liboliphaunt-native", "ios-carrier-manifest")}${version}`, - version, - }, - carriers, - entries: rows.map((extension) => ({ - dependencyCarriers: extension.dependencies.map(dependencyCarrierReference), - extension, - })), - }); -} - -export function writeSwiftExtensionCarrierManifest(output, options = {}) { - const manifest = buildSwiftExtensionCarrierManifest(options); - mkdirSync(path.dirname(output), { recursive: true }); - writeFileSync(output, `${JSON.stringify(manifest, null, 2)}\n`, "utf8"); - return manifest; -} - -export function discoveredExtensionManifests(root) { - if (!existsSync(root)) return []; - const manifests = []; - const visit = (directory) => { - const manifest = path.join(directory, "extension-artifacts.json"); - if (existsSync(manifest)) { - manifests.push(manifest); - return; - } - for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => - compareText(left.name, right.name))) { - if (entry.isDirectory()) visit(path.join(directory, entry.name)); - } - }; - visit(root); - return manifests.sort(compareText); -} - -export function buildIosCarrierManifest({ - baseAssetDir = path.join(ROOT, "target/liboliphaunt/release-assets"), - baseCarrierManifest = undefined, - extensionManifests = discoveredExtensionManifests(path.join(ROOT, "target/extension-artifacts")), - repository = DEFAULT_REPOSITORY, - localUrls = false, - verifyMembers = true, -} = {}) { - validateRepository(repository); - const archiveCache = new Map(); - const frozenBase = baseCarrierManifest === undefined - ? baseCarrier({ - archiveCache, - baseAssetDir: path.resolve(baseAssetDir), - repository, - localUrls, - verifyMembers, - }) - : frozenBaseCarrier(baseCarrierManifest); - const { base, legal: baseLegal } = frozenBase; - const documents = extensionManifests.map((file) => { - const document = extensionCarriers(path.resolve(file), { - archiveCache, - repository, - localUrls, - verifyMembers, - }); - if (document.nativeRuntimeVersion !== base.version) { - throw error( - `${file} pins liboliphaunt-native ${document.nativeRuntimeVersion}, ` + - `but the selected base carrier is ${base.version}`, - ); - } - return document; - }); - const extensions = documents - .flatMap(({ rows }) => rows) - .sort((left, right) => compareText(left.sqlName, right.sqlName)); - if (new Set(extensions.map(({ sqlName }) => sqlName)).size !== extensions.length) { - throw error("extension carrier set contains duplicate SQL names"); - } - const carriers = new Map(); - for (const carrier of documents.flatMap((document) => document.carriers)) { - const existing = carriers.get(carrier.name); - if (existing !== undefined && JSON.stringify(existing) !== JSON.stringify(carrier)) { - throw error(`extension carrier set has conflicting envelopes named ${carrier.name}`); - } - carriers.set(carrier.name, carrier); - } - return stable({ - schema: IOS_CARRIER_SCHEMA, - base, - carriers: [...carriers.values()].sort((left, right) => compareText(left.name, right.name)), - extensions, - legal: { - base: baseLegal, - extensions: documents - .flatMap(({ legal }) => legal) - .sort((left, right) => compareText(left.sqlName, right.sqlName)), - }, - }); -} - -export function writeIosCarrierManifest(output, options = {}) { - const manifest = buildIosCarrierManifest(options); - mkdirSync(path.dirname(output), { recursive: true }); - writeFileSync(output, `${JSON.stringify(manifest, null, 2)}\n`, "utf8"); - return manifest; -} - -function parseArgs(argv) { - const options = { extensionManifests: [] }; - let output = DEFAULT_IOS_CARRIER; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--local-urls") { - options.localUrls = true; - continue; - } - if (arg === "--help" || arg === "-h") { - console.log( - `usage: ${path.basename(import.meta.path)} [--base-asset-dir DIR] [--extension-manifest FILE ...] ` + - `[--base-carrier FILE] [--extension-root DIR] [--repository OWNER/REPO] [--output FILE] [--local-urls]`, - ); - process.exit(0); - } - const value = argv[index + 1]; - if (value === undefined) throw error(`${arg} requires a value`); - index += 1; - if (arg === "--base-asset-dir") options.baseAssetDir = value; - else if (arg === "--base-carrier") options.baseCarrierManifest = value; - else if (arg === "--extension-manifest") options.extensionManifests.push(value); - else if (arg === "--extension-root") options.extensionManifests.push(...discoveredExtensionManifests(path.resolve(value))); - else if (arg === "--repository") options.repository = value; - else if (arg === "--output") output = path.resolve(value); - else throw error(`unknown argument ${arg}`); - } - if (options.extensionManifests.length === 0) delete options.extensionManifests; - return { options, output }; -} - -if (import.meta.main) { - try { - const { options, output } = parseArgs(process.argv.slice(2)); - const manifest = writeIosCarrierManifest(output, options); - console.log(`${path.relative(ROOT, output)}\t${manifest.extensions.length} extensions`); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/ios-carrier-manifest.test.mjs b/tools/release/ios-carrier-manifest.test.mjs deleted file mode 100644 index 7bdea6632..000000000 --- a/tools/release/ios-carrier-manifest.test.mjs +++ /dev/null @@ -1,471 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { - chmodSync, - mkdirSync, - mkdtempSync, - readFileSync, - renameSync, - rmSync, - statSync, - symlinkSync, - unlinkSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { - currentProductVersionSync, - extensionReleaseProduct, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { stageExtensionUpstreamLicenses } from "./extension-upstream-licenses.mjs"; -import { - buildIosCarrierManifest, - buildSwiftExtensionCarrierManifest, - discoveredExtensionManifests, - swiftExtensionCarrierAssetName, -} from "./ios-carrier-manifest.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); - -test("discovers flat extensions and nested runtime-owned contrib carriers", () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "ios-carrier-discovery-test-")); - try { - const flat = path.join(root, "oliphaunt-extension-vector", "extension-artifacts.json"); - const nested = path.join( - root, - "liboliphaunt-native", - "oliphaunt-extension-contrib-pg18", - "extension-artifacts.json", - ); - mkdirSync(path.dirname(flat), { recursive: true }); - mkdirSync(path.dirname(nested), { recursive: true }); - writeFileSync(flat, "{}\n"); - writeFileSync(nested, "{}\n"); - - assert.deepEqual(discoveredExtensionManifests(root), [nested, flat].sort()); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function portableTar(args) { - execFileSync("tar", ["--format=ustar", ...args], { - env: { ...process.env, COPYFILE_DISABLE: "1" }, - }); -} - -function archive(root, name, member, format, legal = undefined) { - const staging = path.join(root, `stage-${name}`); - const leaf = path.join(staging, member); - mkdirSync(leaf, { recursive: true }); - writeFileSync(path.join(leaf, "payload.txt"), `${name}\n`); - if (legal !== undefined) { - const noticeRoot = legal.insideMember ? leaf : staging; - stageReleaseNotices(noticeRoot, { profile: legal.profile }); - if (legal.sqlName !== undefined) { - stageExtensionUpstreamLicenses(legal.sqlName, path.join(noticeRoot, "files")); - } - } - const output = path.join(root, name); - if (format === "zip") { - execFileSync("zip", ["-qry", output, legal?.insideMember === false ? "." : member], { cwd: staging }); - } else { - portableTar(["-czf", output, "-C", staging, legal?.insideMember === false ? "." : member]); - } - return output; -} - -function assetRow(file, kind, identity = null) { - return { - family: "native", - target: "ios-xcframework", - kind, - identity, - name: path.basename(file), - path: path.relative(ROOT, file).split(path.sep).join("/"), - bytes: statSync(file).size, - sha256: sha256(file), - }; -} - -function compatibility(nativeRuntimeVersion = currentProductVersionSync( - "liboliphaunt-native", - "ios-carrier-manifest.test", -)) { - return { - extensionRuntimeContract: "src/shared/extension-runtime-contract/contract.toml", - nativeRuntimeProduct: "liboliphaunt-native", - nativeRuntimeVersion, - postgresMajor: "18", - wasixRuntimeProduct: "liboliphaunt-wasix", - wasixRuntimeVersion: currentProductVersionSync( - "liboliphaunt-wasix", - "ios-carrier-manifest.test", - ), - }; -} - -function nextStableVersion(version) { - const [major, minor, patch] = version.split(".").map(Number); - return `${major}.${minor}.${patch + 1}`; -} - -function writeManifest(root, product, body) { - const directory = path.join(root, product); - mkdirSync(directory, { recursive: true }); - const file = path.join(directory, "extension-artifacts.json"); - writeFileSync(file, `${JSON.stringify({ - schema: "oliphaunt-extension-ci-artifacts-v1", - product, - version: currentProductVersionSync(product, "ios-carrier-manifest.test"), - compatibility: compatibility(), - createsExtension: true, - dataFiles: [], - dependencies: [], - extensionSqlFileNames: [], - extensionSqlFilePrefixes: [], - nativeDependencies: [], - sharedPreloadLibraries: [], - ...body, - }, null, 2)}\n`); - return file; -} - -function withTruncatedArchiveTools(root, callback) { - const bin = path.join(root, "truncated-archive-tools"); - mkdirSync(bin, { recursive: true }); - for (const name of ["tar", "unzip"]) { - const executable = path.join(bin, name); - writeFileSync(executable, "#!/bin/sh\nprintf 'truncated-success-output\\n'\nexit 0\n"); - chmodSync(executable, 0o755); - writeFileSync(`${executable}.cmd`, "@echo truncated-success-output\r\n@exit /b 0\r\n"); - } - const previous = process.env.PATH; - try { - process.env.PATH = `${bin}${path.delimiter}${previous ?? ""}`; - return callback(); - } finally { - if (previous === undefined) delete process.env.PATH; - else process.env.PATH = previous; - } -} - -test("produces exact local and GitHub carrier envelopes without consulting truncated tar/unzip output", () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "ios-carrier-test-")); - try { - const version = currentProductVersionSync("liboliphaunt-native", "ios-carrier-manifest.test"); - const base = path.join(root, "base"); - mkdirSync(base, { recursive: true }); - archive(base, `liboliphaunt-${version}-apple-spm-xcframework.zip`, "liboliphaunt.xcframework", "zip", { - insideMember: true, - profile: "native-runtime", - }); - archive(base, `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`, "oliphaunt", "tar.gz", { - insideMember: false, - profile: "native-runtime-resources", - }); - archive(base, `liboliphaunt-${version}-icu-data.tar.gz`, "share/icu", "tar.gz", { - insideMember: false, - profile: "native-icu-data", - }); - - const pgtapRuntime = archive(root, "pgtap-runtime.tar.gz", "oliphaunt", "tar.gz", { - insideMember: false, - profile: "external-native", - sqlName: "pgtap", - }); - const pgtap = writeManifest(root, "oliphaunt-extension-pgtap", { - sqlName: "pgtap", - extensionSqlFileNames: ["uninstall_pgtap.sql"], - extensionSqlFilePrefixes: ["pgtap-core", "pgtap-schema"], - nativeModuleStem: null, - iosNativeDependencies: [], - iosRegistration: null, - assets: [assetRow(pgtapRuntime, "runtime")], - }); - - const postgisRuntime = archive(root, "postgis-runtime.tar.gz", "oliphaunt", "tar.gz", { - insideMember: false, - profile: "external-native", - sqlName: "postgis", - }); - const postgisPrimary = archive(root, "postgis-primary.zip", "liboliphaunt_extension_postgis-3.xcframework", "zip"); - const postgisGeos = archive(root, "postgis-geos.zip", "liboliphaunt_dependency_geos.xcframework", "zip"); - const postgis = writeManifest(root, "oliphaunt-extension-postgis", { - sqlName: "postgis", - nativeModuleStem: "postgis-3", - iosNativeDependencies: ["geos"], - iosRegistration: { - schema: "oliphaunt-ios-extension-registration-v1", - sqlName: "postgis", - nativeModuleStem: "postgis-3", - magicSymbol: "oliphaunt_static_postgis_3_Pg_magic_func", - initSymbol: "oliphaunt_static_postgis_3__PG_init", - symbols: [], - }, - assets: [ - assetRow(postgisRuntime, "runtime"), - assetRow(postgisPrimary, "ios-xcframework", "postgis-3"), - assetRow(postgisGeos, "ios-dependency-xcframework", "geos"), - ], - }); - - const local = withTruncatedArchiveTools(root, () => buildIosCarrierManifest({ - baseAssetDir: base, - extensionManifests: [postgis, pgtap], - localUrls: true, - })); - assert.deepEqual(local.base.assets.map(({ role }) => role), ["base-xcframework", "runtime-resources", "icu-data"]); - assert.deepEqual(local.legal.base.map(({ assetRole }) => assetRole), ["base-xcframework", "runtime-resources", "icu-data"]); - assert.deepEqual(local.legal.base.map(({ spdx }) => spdx), [ - "MIT AND PostgreSQL AND Unicode-3.0", - "MIT AND PostgreSQL", - "MIT AND Unicode-3.0", - ]); - assert.deepEqual(local.extensions.map(({ sqlName }) => sqlName), ["pgtap", "postgis"]); - assert.deepEqual(local.legal.extensions.map(({ sqlName }) => sqlName), ["pgtap", "postgis"]); - assert.ok(local.legal.extensions.every(({ files }) => files.every(({ bytes, sha256 }) => bytes > 0 && /^[0-9a-f]{64}$/u.test(sha256)))); - assert.ok(local.legal.extensions.find(({ sqlName }) => sqlName === "postgis").files.some(({ member }) => member === "files/share/licenses/postgis/COPYING")); - const sqlOnly = local.extensions[0]; - assert.equal(sqlOnly.nativeModuleStem, null); - assert.equal(sqlOnly.registration, null); - assert.deepEqual(sqlOnly.dataFiles, []); - assert.deepEqual(sqlOnly.extensionSqlFileNames, ["uninstall_pgtap.sql"]); - assert.deepEqual(sqlOnly.extensionSqlFilePrefixes, ["pgtap-core", "pgtap-schema"]); - assert.deepEqual(sqlOnly.assets.map(({ role }) => role), ["runtime-resources"]); - const native = local.extensions[1]; - assert.deepEqual(native.nativeDependencies, ["geos"]); - assert.deepEqual(native.assets.map(({ role }) => role).sort(), ["dependency-xcframework", "extension-xcframework", "runtime-resources"]); - assert.ok(local.base.assets.every(({ url }) => url.startsWith("file:"))); - - const publicManifest = buildIosCarrierManifest({ - baseAssetDir: base, - extensionManifests: [pgtap], - repository: "f0rr0/oliphaunt", - }); - assert.ok(publicManifest.base.assets.every(({ url }) => url.startsWith(`https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v${version}/`))); - - const baseXcframework = path.join( - base, - `liboliphaunt-${version}-apple-spm-xcframework.zip`, - ); - const realBaseXcframework = `${baseXcframework}.real`; - renameSync(baseXcframework, realBaseXcframework); - symlinkSync(path.basename(realBaseXcframework), baseXcframework); - assert.throws( - () => buildIosCarrierManifest({ - baseAssetDir: base, - extensionManifests: [pgtap], - localUrls: true, - }), - /base-xcframework asset must be a regular file/u, - ); - unlinkSync(baseXcframework); - renameSync(realBaseXcframework, baseXcframework); - - const swiftCarrier = buildSwiftExtensionCarrierManifest({ - extensionManifest: pgtap, - nativeRuntimeVersion: version, - }); - const pgtapVersion = currentProductVersionSync("oliphaunt-extension-pgtap", "ios-carrier-manifest.test"); - assert.equal(swiftCarrier.schema, "oliphaunt-swift-extension-carrier-v1"); - assert.deepEqual(swiftCarrier.release, { - product: "oliphaunt-extension-pgtap", - tag: `oliphaunt-extension-pgtap-v${pgtapVersion}`, - version: pgtapVersion, - }); - assert.equal(swiftCarrier.entries.length, 1); - assert.equal(swiftCarrier.entries[0].extension.sqlName, "pgtap"); - assert.deepEqual(swiftCarrier.entries[0].dependencyCarriers, []); - assert.equal( - swiftExtensionCarrierAssetName("oliphaunt-extension-pgtap", pgtapVersion), - `oliphaunt-extension-pgtap-${pgtapVersion}-swift-extension-carrier.json`, - ); - - const canonicalPgtap = JSON.parse(readFileSync(pgtap, "utf8")); - for (const [label, mutate, pattern] of [ - [ - "self dependency", - (document) => { document.dependencies = ["pgtap"]; }, - /dependencies must not include itself/u, - ], - [ - "dot-bearing SQL prefix", - (document) => { document.extensionSqlFilePrefixes = ["pgtap.core"]; }, - /dot-free portable SQL basename prefix/u, - ], - [ - "non-portable SQL name", - (document) => { document.extensionSqlFileNames = ["foreign name.sql"]; }, - /portable identifier/u, - ], - [ - "non-canonical SQL-name order", - (document) => { document.extensionSqlFileNames = ["z.sql", "a.sql"]; }, - /sorted in ordinal order/u, - ], - ]) { - const candidate = structuredClone(canonicalPgtap); - mutate(candidate); - writeFileSync(pgtap, `${JSON.stringify(candidate, null, 2)}\n`); - assert.throws( - () => buildIosCarrierManifest({ - baseAssetDir: base, - extensionManifests: [pgtap], - localUrls: true, - }), - pattern, - label, - ); - } - writeFileSync(pgtap, `${JSON.stringify(canonicalPgtap, null, 2)}\n`); - - const incompatibleVersion = nextStableVersion(version); - assert.throws( - () => buildSwiftExtensionCarrierManifest({ - extensionManifest: pgtap, - nativeRuntimeVersion: incompatibleVersion, - }), - new RegExp(`pins liboliphaunt-native ${version.replaceAll(".", "\\.")}, but caller supplied ${incompatibleVersion.replaceAll(".", "\\.")}`, "u"), - ); - const incompatiblePgtap = JSON.parse(readFileSync(pgtap, "utf8")); - incompatiblePgtap.compatibility.nativeRuntimeVersion = incompatibleVersion; - writeFileSync(pgtap, `${JSON.stringify(incompatiblePgtap, null, 2)}\n`); - assert.throws( - () => buildIosCarrierManifest({ - baseAssetDir: base, - extensionManifests: [pgtap], - localUrls: true, - }), - new RegExp(`pins liboliphaunt-native ${incompatibleVersion.replaceAll(".", "\\.")}, but the selected base carrier is ${version.replaceAll(".", "\\.")}`, "u"), - ); - - const malformed = JSON.parse(readFileSync(postgis, "utf8")); - malformed.iosNativeDependencies = ["geos", "proj"]; - writeFileSync(postgis, `${JSON.stringify(malformed, null, 2)}\n`); - assert.throws( - () => buildIosCarrierManifest({ baseAssetDir: base, extensionManifests: [postgis], localUrls: true }), - /dependency assets do not match/u, - ); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("bundle carriers verify exact nested bytes without consulting truncated tar output", () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "ios-bundle-carrier-test-")); - try { - const product = "oliphaunt-extension-contrib-pg18"; - const releaseProduct = extensionReleaseProduct( - product, - "native", - "ios-carrier-manifest.test", - ); - const version = currentProductVersionSync(releaseProduct, "ios-carrier-manifest.test"); - const sqlNames = extensionSqlNames(product, "ios-carrier-manifest.test"); - const carrierRoot = `${product}-${version}-native-ios-xcframework-bundle`; - const carrierName = `${carrierRoot}.tar.gz`; - const carrierStage = path.join(root, "carrier-stage", carrierRoot); - const extensions = []; - for (const sqlName of sqlNames) { - const logicalRoot = path.join(root, "logical", sqlName); - mkdirSync(logicalRoot, { recursive: true }); - const logicalName = `${product}-${version}-native-ios-runtime.tar.gz`; - const logicalFile = archive(logicalRoot, logicalName, "oliphaunt", "tar.gz", { - insideMember: false, - profile: "contrib-native", - }); - const memberPath = `extensions/${sqlName}/${logicalName}`; - const nested = path.join(carrierStage, ...memberPath.split("/")); - mkdirSync(path.dirname(nested), { recursive: true }); - writeFileSync(nested, readFileSync(logicalFile)); - extensions.push({ - sqlName, - createsExtension: true, - dataFiles: [], - dependencies: [], - extensionSqlFileNames: [], - extensionSqlFilePrefixes: [], - nativeDependencies: [], - nativeModuleStem: null, - iosNativeDependencies: [], - iosRegistration: null, - sharedPreloadLibraries: [], - assets: [{ - family: "native", - target: "ios-xcframework", - kind: "runtime", - identity: null, - name: logicalName, - path: path.relative(ROOT, logicalFile).split(path.sep).join("/"), - bytes: statSync(logicalFile).size, - sha256: sha256(logicalFile), - carrierAsset: carrierName, - carrierRoot, - memberPath, - }], - }); - } - writeFileSync(path.join(carrierStage, "bundle-manifest.json"), "{}\n"); - const releaseAssets = path.join(root, "release-assets"); - mkdirSync(releaseAssets, { recursive: true }); - const carrierFile = path.join(releaseAssets, carrierName); - portableTar(["-czf", carrierFile, "-C", path.dirname(carrierStage), carrierRoot]); - const manifestFile = path.join(root, "extension-artifacts.json"); - const writeBundle = () => writeFileSync(manifestFile, `${JSON.stringify({ - schema: "oliphaunt-extension-ci-artifacts-v2", - product, - version, - compatibility: compatibility(), - extensions, - carrierAssets: [{ - name: carrierName, - path: path.relative(ROOT, carrierFile).split(path.sep).join("/"), - sha256: sha256(carrierFile), - bytes: statSync(carrierFile).size, - family: "native", - target: "ios-xcframework", - kind: "extension-bundle", - memberCount: sqlNames.length, - }], - }, null, 2)}\n`); - writeBundle(); - - const carrier = withTruncatedArchiveTools(root, () => buildSwiftExtensionCarrierManifest({ - extensionManifest: manifestFile, - localUrls: true, - })); - assert.equal(carrier.carriers.length, 1); - assert.equal(carrier.entries.length, sqlNames.length); - assert.ok(carrier.entries.every(({ extension }) => - extension.product === product - && extension.releaseProduct === releaseProduct - && extension.assets.length === 1 - && extension.assets[0].carrier === carrierName - && extension.assets[0].path.startsWith(`${carrierRoot}/extensions/${extension.sqlName}/`))); - - const tampered = path.join(carrierStage, "extensions", sqlNames[0], extensions[0].assets[0].name); - writeFileSync(tampered, "repacked bytes that do not match the logical row\n"); - portableTar(["-czf", carrierFile, "-C", path.dirname(carrierStage), carrierRoot]); - writeBundle(); - assert.throws( - () => buildSwiftExtensionCarrierManifest({ extensionManifest: manifestFile, localUrls: true }), - /nested payload .* does not match its declared bytes\/SHA-256/u, - ); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/ios-extension-registration.mjs b/tools/release/ios-extension-registration.mjs deleted file mode 100755 index 285e956da..000000000 --- a/tools/release/ios-extension-registration.mjs +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env bun - -import { - existsSync, - mkdirSync, - readFileSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { compareText } from "./release-artifact-targets.mjs"; - -const PREFIX = "ios-extension-registration.mjs"; -const SCHEMA = "oliphaunt-ios-extension-registration-v1"; -const PORTABLE_RE = /^[A-Za-z0-9._-]{1,128}$/u; -const C_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/u; - -function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(1); -} - -function parseArgs(argv) { - const result = {}; - for (let index = 0; index < argv.length; index += 1) { - const key = argv[index]; - if (key === "--help" || key === "-h") { - console.log( - `usage: ${PREFIX} --sql-name NAME --native-module-stem STEM ` + - "--simulator-out DIR --device-out DIR --macos-out DIR --output FILE", - ); - process.exit(0); - } - const field = new Map([ - ["--sql-name", "sqlName"], - ["--native-module-stem", "nativeModuleStem"], - ["--simulator-out", "simulatorOut"], - ["--device-out", "deviceOut"], - ["--macos-out", "macosOut"], - ["--output", "output"], - ]).get(key); - if (field === undefined || argv[index + 1] === undefined) { - fail(`unknown or incomplete argument ${key}`); - } - result[field] = argv[index + 1]; - index += 1; - } - for (const field of ["sqlName", "nativeModuleStem", "simulatorOut", "deviceOut", "macosOut", "output"]) { - if (typeof result[field] !== "string" || result[field].length === 0) { - fail(`--${field.replace(/[A-Z]/gu, (value) => `-${value.toLowerCase()}`)} is required`); - } - } - for (const field of ["sqlName", "nativeModuleStem"]) { - if (!PORTABLE_RE.test(result[field])) { - fail(`${field} must be a portable identifier`); - } - } - return result; -} - -function lines(file) { - return readFileSync(file, "utf8") - .split(/\r?\n/u) - .map((line) => line.trim()) - .filter(Boolean); -} - -export function readRegistrationSymbols(out, stem) { - const root = path.join(out, "extensions", stem); - const exported = lines(path.join(root, "symbols.list")).map((name) => ({ name, address: name })); - const aliasFile = path.join(root, "symbol-aliases.list"); - const aliases = (existsSync(aliasFile) ? lines(aliasFile) : []).map((line) => { - const fields = line.split("\t"); - if (fields.length !== 2) { - fail(`${aliasFile} contains an invalid alias row`); - } - return { name: fields[0], address: fields[1] }; - }); - const result = [...exported, ...aliases].sort((left, right) => compareText( - `${left.name}\0${left.address}`, - `${right.name}\0${right.address}`, - )); - for (const row of result) { - if (!C_IDENTIFIER_RE.test(row.name) || !C_IDENTIFIER_RE.test(row.address)) { - fail(`${root} contains a non-C registration symbol`); - } - } - if (new Set(result.map(({ name }) => name)).size !== result.length) { - fail(`${root} repeats a SQL-visible registration symbol`); - } - return result; -} - -export function assertDefinedRegistrationAddresses(symbols, defined, label) { - const missing = [...new Set( - symbols - .map(({ address }) => address) - .filter((address) => !defined.has(address)), - )].sort(compareText); - if (missing.length > 0) { - throw new Error( - `${label} registration address(es) are not defined by its extension objects: ${missing.join(",")}`, - ); - } -} - -function objectFiles(out, stem) { - const file = path.join(out, "extensions", stem, "objects.list"); - const result = lines(file); - if (result.length === 0) { - fail(`${file} is empty`); - } - return result; -} - -function definedSymbols(out, stem) { - const objects = objectFiles(out, stem); - const result = captureCommandOutput("nm", ["-g", ...objects], { - label: `nm -g ${objects.join(" ")}`, - maxOutputBytes: 64 * 1024 * 1024, - }); - if (result.error !== undefined || result.status !== 0) { - fail(`nm failed for ${out}/${stem}: ${(result.stderr || result.error?.message || "").trim()}`); - } - const names = new Set(); - for (const raw of result.stdout.split(/\r?\n/u)) { - const fields = raw.trim().split(/\s+/u); - if (fields.length < 2) continue; - const type = fields.at(-2); - const rawName = fields.at(-1); - if (!/^[A-Za-z]$/u.test(type) || type.toUpperCase() === "U") continue; - names.add(rawName.startsWith("_") ? rawName.slice(1) : rawName); - } - return names; -} - -function registration(out, sqlName, stem) { - const prefix = `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`; - const names = definedSymbols(out, stem); - const magicSymbol = `${prefix}_Pg_magic_func`; - if (!names.has(magicSymbol)) { - fail(`${out} ${sqlName} archive does not export required ${magicSymbol}`); - } - const init = `${prefix}__PG_init`; - const symbols = readRegistrationSymbols(out, stem); - try { - assertDefinedRegistrationAddresses(symbols, names, `${out} ${sqlName}`); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - return { - initSymbol: names.has(init) ? init : null, - magicSymbol, - symbols, - }; -} - -function stable(value) { - if (Array.isArray(value)) return value.map(stable); - if (value !== null && typeof value === "object") { - return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])])); - } - return value; -} - -if (import.meta.main) { - const args = parseArgs(process.argv.slice(2)); - const simulator = registration(args.simulatorOut, args.sqlName, args.nativeModuleStem); - const device = registration(args.deviceOut, args.sqlName, args.nativeModuleStem); - const macos = registration(args.macosOut, args.sqlName, args.nativeModuleStem); - if ( - JSON.stringify(simulator) !== JSON.stringify(device) || - JSON.stringify(simulator) !== JSON.stringify(macos) - ) { - fail(`${args.sqlName} macOS, iOS simulator, and iOS device registration metadata differ`); - } - const output = stable({ - schema: SCHEMA, - sqlName: args.sqlName, - nativeModuleStem: args.nativeModuleStem, - ...simulator, - }); - mkdirSync(path.dirname(args.output), { recursive: true }); - writeFileSync(args.output, `${JSON.stringify(output, null, 2)}\n`, "utf8"); -} diff --git a/tools/release/ios-extension-registration.test.mjs b/tools/release/ios-extension-registration.test.mjs deleted file mode 100644 index 75dd4d884..000000000 --- a/tools/release/ios-extension-registration.test.mjs +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - assertDefinedRegistrationAddresses, - readRegistrationSymbols, -} from "./ios-extension-registration.mjs"; - -test("iOS extension registration accepts an absent optional symbol alias list", () => { - const out = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-ios-registration-")); - try { - const extension = path.join(out, "extensions", "amcheck"); - mkdirSync(extension, { recursive: true }); - writeFileSync(path.join(extension, "symbols.list"), "verify_nbtree\n"); - - assert.deepEqual(readRegistrationSymbols(out, "amcheck"), [ - { name: "verify_nbtree", address: "verify_nbtree" }, - ]); - assert.throws( - () => readRegistrationSymbols(out, "missing"), - /symbols\.list/u, - "the required exported-symbol list must remain mandatory", - ); - } finally { - rmSync(out, { recursive: true, force: true }); - } -}); - -test("iOS extension registration merges and sorts explicit symbol aliases", () => { - const out = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-ios-registration-")); - try { - const extension = path.join(out, "extensions", "postgis-3"); - mkdirSync(extension, { recursive: true }); - writeFileSync(path.join(extension, "symbols.list"), "zeta\n"); - writeFileSync( - path.join(extension, "symbol-aliases.list"), - "difference\toliphaunt_static_postgis_3_difference\n", - ); - - assert.deepEqual(readRegistrationSymbols(out, "postgis-3"), [ - { name: "difference", address: "oliphaunt_static_postgis_3_difference" }, - { name: "zeta", address: "zeta" }, - ]); - } finally { - rmSync(out, { recursive: true, force: true }); - } -}); - -test("iOS extension registration uses locale-independent ordinal ordering for mixed-case symbols", () => { - const out = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-ios-registration-")); - try { - const extension = path.join(out, "extensions", "bloom"); - mkdirSync(extension, { recursive: true }); - writeFileSync( - path.join(extension, "symbols.list"), - "blbeginscan\nBloomFillMetapage\nblinsert\n", - ); - - assert.deepEqual(readRegistrationSymbols(out, "bloom"), [ - { name: "BloomFillMetapage", address: "BloomFillMetapage" }, - { name: "blbeginscan", address: "blbeginscan" }, - { name: "blinsert", address: "blinsert" }, - ]); - } finally { - rmSync(out, { recursive: true, force: true }); - } -}); - -test("iOS extension registration rejects an exported-symbol address absent from the built slice", () => { - assert.throws( - () => assertDefinedRegistrationAddresses( - [{ name: "ellipsoid_in", address: "ellipsoid_in" }], - new Set(["oliphaunt_static_postgis_3_Pg_magic_func"]), - "ios-simulator postgis", - ), - /ios-simulator postgis registration address\(es\).*ellipsoid_in/u, - ); -}); - -test("iOS extension registration rejects an alias whose linked address is absent from the built slice", () => { - assert.throws( - () => assertDefinedRegistrationAddresses( - [ - { - name: "difference", - address: "oliphaunt_static_postgis_3_difference", - }, - ], - new Set(["difference"]), - "ios-device postgis", - ), - /ios-device postgis registration address\(es\).*oliphaunt_static_postgis_3_difference/u, - ); -}); diff --git a/tools/release/isolated-github-test-environment.test.mjs b/tools/release/isolated-github-test-environment.test.mjs deleted file mode 100644 index 5a110acab..000000000 --- a/tools/release/isolated-github-test-environment.test.mjs +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import test from "node:test"; - -import { isolatedGitHubTestEnvironment } from "../test/isolated-github-test-environment.mjs"; - -test("synthetic GitHub fixtures discard hostile credentials, state, lineage, and tuning", () => { - const inherited = { - ACTIONS_ID_TOKEN_REQUEST_TOKEN: "live-oidc-token", - BOOTSTRAP_LEDGER_PATH: "/live/bootstrap-ledger", - CI_RUN_ID: "30358387218", - GH_TOKEN: "live-gh-token", - GITHUB_OUTPUT: "/live/github-output", - GITHUB_REPOSITORY: "live/repository", - GITHUB_RUN_ATTEMPT: "7", - GITHUB_RUN_ID: "123", - GITHUB_SHA: "a".repeat(40), - GITHUB_TOKEN: "live-github-token", - KEEP_ME: "preserved", - OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH: "/live/pacer.json", - OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE: "true", - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: "/live/journal.json", - OLIPHAUNT_GITHUB_READ_ATTEMPT_TIMEOUT_MS: "1", - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "2", - OLIPHAUNT_GITHUB_READ_DEADLINE_MS: "3", - OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: "4", - OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: "5", - OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR: "/live/snapshots", - OLIPHAUNT_RELEASE_FUTURE_CONTROL: "live-future-control", - OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: "true", - RELEASE_FUTURE_CONTROL: "live-future-control", - RELEASE_HEAD_SHA: "a".repeat(40), - RELEASE_JOB_HARD_WINDOW_SECONDS: "21180", - RELEASE_OPERATION: "publish", - RELEASE_PR_TOKEN: "live-release-token", - RELEASE_ROOT_RUN_ID: "123", - RELEASE_TRANSPORT_CONTENT_WRITE_ADMISSION: "pre-reserved", - }; - const environment = isolatedGitHubTestEnvironment( - { - BOOTSTRAP_LEDGER_PATH: "/fixture/bootstrap-ledger", - GH_TOKEN: "fixture-token", - GITHUB_RUN_ID: "900", - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "0", - RELEASE_HEAD_SHA: "b".repeat(40), - }, - inherited, - ); - - assert.deepEqual(environment, { - BOOTSTRAP_LEDGER_PATH: "/fixture/bootstrap-ledger", - GH_TOKEN: "fixture-token", - GITHUB_RUN_ID: "900", - KEEP_ME: "preserved", - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "0", - RELEASE_HEAD_SHA: "b".repeat(40), - }); - assert.deepEqual(inherited.GH_TOKEN, "live-gh-token", "the inherited environment must not be mutated"); -}); - -test("future GitHub and release namespace entries are isolated without an enumerated denylist", () => { - const inherited = { - ACTIONS_FUTURE_CREDENTIAL: "live", - GH_FUTURE_CREDENTIAL: "live", - GITHUB_FUTURE_IDENTITY: "live", - OLIPHAUNT_GITHUB_FUTURE_STATE: "live", - OLIPHAUNT_RELEASE_FUTURE_STATE: "live", - RELEASE_FUTURE_STATE: "live", - RUNNER_TEMP: "/preserved/runner-temp", - }; - - assert.deepEqual( - isolatedGitHubTestEnvironment({}, inherited), - { RUNNER_TEMP: "/preserved/runner-temp" }, - ); -}); - -test("environment isolation rejects non-object inputs instead of silently widening inheritance", () => { - assert.throws(() => isolatedGitHubTestEnvironment([], {}), /environment overrides/u); - assert.throws(() => isolatedGitHubTestEnvironment({}, null), /inherited environment/u); -}); diff --git a/tools/release/isolated-github-test-environment.test.mts b/tools/release/isolated-github-test-environment.test.mts new file mode 100644 index 000000000..7944e5cc5 --- /dev/null +++ b/tools/release/isolated-github-test-environment.test.mts @@ -0,0 +1,85 @@ +#!/usr/bin/env bun + +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { isolatedGitHubTestEnvironment } from './testdata/isolated-github-test-environment.mts'; + +test('synthetic GitHub fixtures discard hostile credentials, state, lineage, and tuning', () => { + const inherited = { + ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'live-oidc-token', + BOOTSTRAP_LEDGER_PATH: '/live/bootstrap-ledger', + CI_RUN_ID: '30358387218', + GH_TOKEN: 'live-gh-token', + GITHUB_OUTPUT: '/live/github-output', + GITHUB_REPOSITORY: 'live/repository', + GITHUB_RUN_ATTEMPT: '7', + GITHUB_RUN_ID: '123', + GITHUB_SHA: 'a'.repeat(40), + GITHUB_TOKEN: 'live-github-token', + KEEP_ME: 'preserved', + OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH: '/live/pacer.json', + OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_TEST_MODE: 'true', + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: '/live/journal.json', + OLIPHAUNT_GITHUB_READ_ATTEMPT_TIMEOUT_MS: '1', + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: '2', + OLIPHAUNT_GITHUB_READ_DEADLINE_MS: '3', + OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: '4', + OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: '5', + OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR: '/live/snapshots', + OLIPHAUNT_RELEASE_FUTURE_CONTROL: 'live-future-control', + OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: 'true', + RELEASE_FUTURE_CONTROL: 'live-future-control', + RELEASE_HEAD_SHA: 'a'.repeat(40), + RELEASE_JOB_HARD_WINDOW_SECONDS: '21180', + RELEASE_OPERATION: 'publish', + RELEASE_PR_TOKEN: 'live-release-token', + RELEASE_ROOT_RUN_ID: '123', + RELEASE_TRANSPORT_CONTENT_WRITE_ADMISSION: 'pre-reserved', + }; + const environment = isolatedGitHubTestEnvironment( + { + BOOTSTRAP_LEDGER_PATH: '/fixture/bootstrap-ledger', + GH_TOKEN: 'fixture-token', + GITHUB_RUN_ID: '900', + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: '0', + RELEASE_HEAD_SHA: 'b'.repeat(40), + }, + inherited, + ); + + assert.deepEqual(environment, { + BOOTSTRAP_LEDGER_PATH: '/fixture/bootstrap-ledger', + GH_TOKEN: 'fixture-token', + GITHUB_RUN_ID: '900', + KEEP_ME: 'preserved', + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: '0', + RELEASE_HEAD_SHA: 'b'.repeat(40), + }); + assert.deepEqual( + inherited.GH_TOKEN, + 'live-gh-token', + 'the inherited environment must not be mutated', + ); +}); + +test('future GitHub and release namespace entries are isolated without an enumerated denylist', () => { + const inherited = { + ACTIONS_FUTURE_CREDENTIAL: 'live', + GH_FUTURE_CREDENTIAL: 'live', + GITHUB_FUTURE_IDENTITY: 'live', + OLIPHAUNT_GITHUB_FUTURE_STATE: 'live', + OLIPHAUNT_RELEASE_FUTURE_STATE: 'live', + RELEASE_FUTURE_STATE: 'live', + RUNNER_TEMP: '/preserved/runner-temp', + }; + + assert.deepEqual(isolatedGitHubTestEnvironment({}, inherited), { + RUNNER_TEMP: '/preserved/runner-temp', + }); +}); + +test('environment isolation rejects non-object inputs instead of silently widening inheritance', () => { + assert.throws(() => isolatedGitHubTestEnvironment([], {}), /environment overrides/u); + assert.throws(() => isolatedGitHubTestEnvironment({}, null), /inherited environment/u); +}); diff --git a/tools/release/kotlin-maven-staging.mjs b/tools/release/kotlin-maven-staging.mjs deleted file mode 100644 index 4444abb61..000000000 --- a/tools/release/kotlin-maven-staging.mjs +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/env bun - -import { - lstatSync, - readFileSync, - readdirSync, - statSync, -} from "node:fs"; -import path from "node:path"; - -import { validateMavenCentralPublication } from "./maven-central-contract.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const TOOL = "kotlin-maven-staging.mjs"; -const PRODUCT = "oliphaunt-kotlin"; -const DEFAULT_STAGING_ROOT = path.join(ROOT, "target/sdk-artifacts/oliphaunt-kotlin/maven"); -const VERSION_TOKEN = /^[A-Za-z0-9_.-]+$/u; - -function error(message) { - return new Error(`${TOOL}: ${message}`); -} - -function ordinalCompare(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function normalizedRelative(root, file) { - return path.relative(root, file).split(path.sep).join("/"); -} - -function repositoryRelative(file) { - const relative = path.relative(ROOT, file); - return relative.startsWith("..") ? file : relative.split(path.sep).join("/"); -} - -function requireDirectory(directory, label) { - let stat; - try { - stat = lstatSync(directory); - } catch (cause) { - throw error(`${label} is missing: ${cause.message}`); - } - if (!stat.isDirectory() || stat.isSymbolicLink()) { - throw error(`${label} must be a real non-symlink directory`); - } -} - -function walkRegularFiles(root) { - const files = []; - const visit = (directory) => { - for (const entry of readdirSync(directory, { withFileTypes: true })) { - const file = path.join(directory, entry.name); - if (entry.isSymbolicLink()) { - throw error(`staged Maven repository must not contain symlink ${repositoryRelative(file)}`); - } - if (entry.isDirectory()) { - visit(file); - } else if (entry.isFile()) { - files.push(file); - } else { - throw error(`staged Maven repository must contain only regular files and directories: ${repositoryRelative(file)}`); - } - } - }; - visit(root); - return files.sort((left, right) => ordinalCompare( - normalizedRelative(root, left), - normalizedRelative(root, right), - )); -} - -function coordinate(groupId, artifactId, version, packaging, companions) { - const directory = `${groupId.replaceAll(".", "/")}/${artifactId}/${version}`; - const prefix = `${artifactId}-${version}`; - return Object.freeze({ - artifactId, - directory, - files: Object.freeze(companions.map((suffix) => `${directory}/${prefix}${suffix}`)), - groupId, - packaging, - version, - }); -} - -export function kotlinMavenCentralCoordinates(version) { - if (typeof version !== "string" || !VERSION_TOKEN.test(version)) { - throw error(`Kotlin product version must be a safe Maven token, got ${JSON.stringify(version)}`); - } - return Object.freeze([ - coordinate("dev.oliphaunt", "oliphaunt-android", version, "aar", [ - ".aar", - ".pom", - "-sources.jar", - "-javadoc.jar", - ]), - coordinate("dev.oliphaunt", "oliphaunt-android-gradle-plugin", version, "jar", [ - ".jar", - ".pom", - ".module", - "-sources.jar", - "-javadoc.jar", - ]), - coordinate("dev.oliphaunt.android", "dev.oliphaunt.android.gradle.plugin", version, "pom", [ - ".pom", - ]), - ]); -} - -export function kotlinMavenCentralRelativeFiles(version) { - return kotlinMavenCentralCoordinates(version) - .flatMap(({ files }) => files) - .sort(); -} - -function localMetadataRelativeFiles(version) { - return kotlinMavenCentralCoordinates(version) - .map(({ directory }) => `${path.posix.dirname(directory)}/maven-metadata-local.xml`) - .sort(); -} - -export function currentKotlinProductVersion() { - const file = path.join(ROOT, "src/sdks/kotlin/gradle.properties"); - const versions = readFileSync(file, "utf8") - .split(/\r?\n/u) - .map((line) => line.match(/^VERSION_NAME=(.+)$/u)?.[1]?.trim()) - .filter(Boolean); - if (versions.length !== 1 || !VERSION_TOKEN.test(versions[0])) { - throw error(`${repositoryRelative(file)} must declare exactly one safe VERSION_NAME`); - } - return versions[0]; -} - -/** - * Validate the complete unsigned Maven Central input staged by the Kotlin SDK. - * Gradle's three maven-metadata-local.xml files are permitted because the - * producer uses publishToMavenLocal, but they are explicitly excluded from the - * immutable ten-file Central closure returned by this function. - */ -export function validateKotlinMavenStagingClosure( - root, - version, - { allowLocalMetadata = true, label = repositoryRelative(root) } = {}, -) { - const stagingRoot = path.resolve(root); - requireDirectory(stagingRoot, `${label} staged Maven repository`); - - const coordinates = kotlinMavenCentralCoordinates(version); - const expected = new Set(kotlinMavenCentralRelativeFiles(version)); - const permittedMetadata = new Set(allowLocalMetadata ? localMetadataRelativeFiles(version) : []); - const files = walkRegularFiles(stagingRoot); - const actual = new Map(files.map((file) => [normalizedRelative(stagingRoot, file), file])); - const missing = [...expected].filter((file) => !actual.has(file)).sort(); - const unexpected = [...actual.keys()] - .filter((file) => !expected.has(file) && !permittedMetadata.has(file)) - .sort(); - if (missing.length > 0 || unexpected.length > 0) { - throw error( - `${label} must contain the exact ${expected.size}-file Maven Central companion closure; ` - + `missing=${JSON.stringify(missing)}, unexpected=${JSON.stringify(unexpected)}`, - ); - } - - for (const [relative, file] of actual) { - if (statSync(file).size <= 0) { - throw error(`${label} contains empty file ${relative}`); - } - } - - for (const expectedCoordinate of coordinates) { - const pomRelative = expectedCoordinate.files.find((file) => file.endsWith(".pom")); - const pom = actual.get(pomRelative); - const publicationFiles = expectedCoordinate.files.map((relative) => { - const file = actual.get(relative); - return { name: path.basename(file), size: statSync(file).size }; - }); - const validated = validateMavenCentralPublication({ - context: `${label}/${pomRelative}`, - files: publicationFiles, - pomText: readFileSync(pom, "utf8"), - }); - for (const field of ["artifactId", "groupId", "packaging", "version"]) { - if (validated[field] !== expectedCoordinate[field]) { - throw error( - `${label}/${pomRelative} ${field} must be ${expectedCoordinate[field]}, got ${validated[field]}`, - ); - } - } - } - - return Object.freeze({ - coordinates: coordinates.map(({ artifactId, groupId, packaging }) => ({ artifactId, groupId, packaging })), - localMetadataFiles: [...actual.keys()].filter((file) => permittedMetadata.has(file)).sort(), - publicationFiles: [...expected].sort(), - root: stagingRoot, - version, - }); -} - -export function stagedKotlinMavenRepo({ - root = DEFAULT_STAGING_ROOT, - version = currentKotlinProductVersion(), -} = {}) { - const result = validateKotlinMavenStagingClosure(root, version); - console.log( - `validated exact ${result.publicationFiles.length}-file Kotlin Maven Central staging closure: ${repositoryRelative(result.root)}`, - ); - return result.root; -} - -if (import.meta.main) { - if (Bun.argv.length !== 2) { - console.error(`usage: ${TOOL}`); - process.exit(2); - } - try { - stagedKotlinMavenRepo(); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/kotlin-maven-staging.test.mjs b/tools/release/kotlin-maven-staging.test.mjs deleted file mode 100644 index 9d4b47d87..000000000 --- a/tools/release/kotlin-maven-staging.test.mjs +++ /dev/null @@ -1,108 +0,0 @@ -import { afterEach, expect, test } from "bun:test"; -import { mkdirSync, mkdtempSync, rmSync, unlinkSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { - kotlinMavenCentralCoordinates, - kotlinMavenCentralRelativeFiles, - validateKotlinMavenStagingClosure, -} from "./kotlin-maven-staging.mjs"; - -const VERSION = "1.2.3"; -const temporaryDirectories = []; - -function pom({ artifactId, groupId, packaging, version = VERSION }) { - return ` - - 4.0.0 - ${groupId} - ${artifactId} - ${version} - ${packaging} - Oliphaunt ${artifactId} - Exact Kotlin Maven staging fixture. - https://github.com/f0rr0/oliphaunt - MIThttps://opensource.org/license/mit - Oliphaunt Maintainershttps://github.com/f0rr0 - - scm:git:https://github.com/f0rr0/oliphaunt.git - scm:git:ssh://git@github.com/f0rr0/oliphaunt.git - https://github.com/f0rr0/oliphaunt - - -`; -} - -function write(relative, bytes, root) { - const file = path.join(root, ...relative.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, bytes); - return file; -} - -function fixture({ localMetadata = true } = {}) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-kotlin-maven-staging-")); - temporaryDirectories.push(root); - for (const coordinate of kotlinMavenCentralCoordinates(VERSION)) { - for (const relative of coordinate.files) { - write( - relative, - relative.endsWith(".pom") ? pom(coordinate) : `fixture ${path.basename(relative)}\n`, - root, - ); - } - if (localMetadata) { - write(`${path.posix.dirname(coordinate.directory)}/maven-metadata-local.xml`, "\n", root); - } - } - return root; -} - -afterEach(() => { - while (temporaryDirectories.length > 0) { - rmSync(temporaryDirectories.pop(), { force: true, recursive: true }); - } -}); - -test("validates the exact ten-file Kotlin Maven Central companion closure", () => { - const result = validateKotlinMavenStagingClosure(fixture(), VERSION); - expect(result.publicationFiles).toEqual(kotlinMavenCentralRelativeFiles(VERSION)); - expect(result.publicationFiles).toHaveLength(10); - expect(result.coordinates).toEqual([ - { artifactId: "oliphaunt-android", groupId: "dev.oliphaunt", packaging: "aar" }, - { artifactId: "oliphaunt-android-gradle-plugin", groupId: "dev.oliphaunt", packaging: "jar" }, - { artifactId: "dev.oliphaunt.android.gradle.plugin", groupId: "dev.oliphaunt.android", packaging: "pom" }, - ]); - expect(result.localMetadataFiles).toHaveLength(3); -}); - -test("rejects missing companions and undeclared staging files", () => { - const missing = fixture(); - unlinkSync(path.join(missing, kotlinMavenCentralRelativeFiles(VERSION)[0])); - expect(() => validateKotlinMavenStagingClosure(missing, VERSION)).toThrow(/exact 10-file.*missing=/u); - - const unexpected = fixture(); - write("dev/oliphaunt/oliphaunt-android/1.2.3/resolver.lock", "forbidden\n", unexpected); - expect(() => validateKotlinMavenStagingClosure(unexpected, VERSION)).toThrow(/unexpected=.*resolver[.]lock/u); -}); - -test("permits only the known local metadata outside the Central closure", () => { - const root = fixture(); - expect(() => validateKotlinMavenStagingClosure(root, VERSION, { allowLocalMetadata: false })).toThrow( - /unexpected=.*maven-metadata-local[.]xml/u, - ); - - const withoutMetadata = fixture({ localMetadata: false }); - expect(validateKotlinMavenStagingClosure(withoutMetadata, VERSION).localMetadataFiles).toEqual([]); -}); - -test("validates each staged POM against the canonical Maven Central contract", () => { - const root = fixture(); - const coordinate = kotlinMavenCentralCoordinates(VERSION)[0]; - const pomFile = path.join(root, coordinate.files.find((file) => file.endsWith(".pom"))); - writeFileSync(pomFile, pom(coordinate).replace(/\s*[\s\S]*?<\/developers>/u, "")); - expect(() => validateKotlinMavenStagingClosure(root, VERSION)).toThrow( - /maven-central-contract:.*must define /u, - ); -}); diff --git a/tools/release/liboliphaunt-extension-guard.test.mjs b/tools/release/liboliphaunt-extension-guard.test.mjs deleted file mode 100644 index 184a0569f..000000000 --- a/tools/release/liboliphaunt-extension-guard.test.mjs +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { - chmodSync, - mkdtempSync, - mkdirSync, - rmSync, - symlinkSync, - unlinkSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import test from "node:test"; - -import { - requiredCoreRuntimePaths, - requiredRuntimeTools, -} from "./optimize_native_runtime_payload.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const GUARD = path.join(ROOT, "tools/release/liboliphaunt-extension-guard.sh"); - -function runEmbeddedInventoryGuard(moduleDirectory, suffix) { - return spawnSync( - "bash", - [ - "-c", - 'source "$1"; oliphaunt_assert_base_embedded_modules_exact "$2" "$3"', - "oliphaunt-embedded-inventory-test", - GUARD, - moduleDirectory, - suffix, - ], - { cwd: ROOT, encoding: "utf8" }, - ); -} - -test("base embedded-module guard accepts exactly the two regular core carriers", () => { - const fixture = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-embedded-modules-")); - const modules = path.join(fixture, "modules"); - try { - assert.notEqual(runEmbeddedInventoryGuard(modules, "so").status, 0); - - mkdirSync(modules); - const dictSnowball = path.join(modules, "dict_snowball.so"); - const plpgsql = path.join(modules, "plpgsql.so"); - writeFileSync(dictSnowball, "dict_snowball\n"); - assert.notEqual(runEmbeddedInventoryGuard(modules, "so").status, 0); - writeFileSync(plpgsql, "plpgsql\n"); - assert.equal(runEmbeddedInventoryGuard(modules, "so").status, 0); - - const stale = path.join(modules, ".stale-extension.so"); - writeFileSync(stale, "stale\n"); - assert.notEqual(runEmbeddedInventoryGuard(modules, "so").status, 0); - unlinkSync(stale); - - unlinkSync(plpgsql); - const target = path.join(fixture, "plpgsql-target.so"); - writeFileSync(target, "linked\n"); - symlinkSync(target, plpgsql); - assert.notEqual(runEmbeddedInventoryGuard(modules, "so").status, 0); - - unlinkSync(plpgsql); - writeFileSync(plpgsql, "plpgsql\n"); - unlinkSync(dictSnowball); - const dictTarget = path.join(fixture, "dict-snowball-target.so"); - writeFileSync(dictTarget, "linked\n"); - symlinkSync(dictTarget, dictSnowball); - assert.notEqual(runEmbeddedInventoryGuard(modules, "so").status, 0); - } finally { - rmSync(fixture, { recursive: true, force: true }); - } -}); - -test("native runtime optimization executes and validates the complete core Snowball closure", () => { - const fixture = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-runtime-optimizer-")); - const runtime = path.join(fixture, "runtime"); - const target = "linux-x64-gnu"; - try { - for (const tool of requiredRuntimeTools(target)) { - const toolPath = path.join(runtime, "bin", tool); - mkdirSync(path.dirname(toolPath), { recursive: true }); - writeFileSync(toolPath, "#!/bin/sh\nexit 0\n"); - chmodSync(toolPath, 0o755); - } - for (const relativePath of requiredCoreRuntimePaths(target, runtime)) { - const file = path.join(runtime, ...relativePath.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, `${relativePath}\n`); - } - - const optimize = spawnSync( - process.execPath, - [ - path.join(ROOT, "tools/release/optimize_native_runtime_payload.mjs"), - fixture, - "--target", - target, - "--tool-set", - "runtime", - "--no-strip", - ], - { cwd: ROOT, encoding: "utf8" }, - ); - assert.equal(optimize.status, 0, optimize.stderr); - - unlinkSync(path.join(runtime, "share/postgresql/tsearch_data/english.stop")); - const incomplete = spawnSync( - process.execPath, - [ - path.join(ROOT, "tools/release/optimize_native_runtime_payload.mjs"), - fixture, - "--target", - target, - "--tool-set", - "runtime", - "--check", - ], - { cwd: ROOT, encoding: "utf8" }, - ); - assert.notEqual(incomplete.status, 0); - assert.match(incomplete.stderr, /missing required core runtime file .*english\.stop/u); - } finally { - rmSync(fixture, { recursive: true, force: true }); - } -}); diff --git a/tools/release/linux-abi-baseline.test.mjs b/tools/release/linux-abi-baseline.test.mjs deleted file mode 100644 index c76be2f28..000000000 --- a/tools/release/linux-abi-baseline.test.mjs +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env bun - -import { strict as assert } from "node:assert"; -import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { ROOT } from "./release-graph.mjs"; - -const RUST_IMAGE = "rust@sha256:5b9332190bb3b9ece73b810cd1f1e9f06343b294ce184bcb067f0747d7d333ea"; -const FEDORA_IMAGE = "fedora@sha256:d63d63fe593749a5e8dbc8152427d40bbe0ece53d884e00e5f3b44859efa5077"; - -function fakeDocker(directory) { - const script = path.join(directory, "docker"); - writeFileSync( - script, - `#!/usr/bin/env bash -set -euo pipefail -printf '%s\\n' "$*" >>"$FAKE_DOCKER_LOG" -if [ "\${1:-}" = image ] && [ "\${2:-}" = inspect ]; then - case "$*" in - *rust@sha256:*) printf '%s\\n' '${RUST_IMAGE}' ;; - *fedora@sha256:*) printf '%s\\n' '${FEDORA_IMAGE}' ;; - esac - exit 0 -fi -if [ "\${1:-}" = run ]; then - case "$*" in - *'cargo build -p oliphaunt-broker'*) - mkdir -p "$FAKE_TARGET_DIR/release" - printf '#!/usr/bin/env sh\\nexit 0\\n' >"$FAKE_TARGET_DIR/release/oliphaunt-broker" - chmod 0755 "$FAKE_TARGET_DIR/release/oliphaunt-broker" - ;; - *'cargo build --locked --offline --manifest-path /workspace/src/runtimes/wasix-napi/Cargo.toml'*) - mkdir -p "$FAKE_TARGET_DIR/$FAKE_RUST_HOST/release" - printf 'node-api-fixture\\n' >"$FAKE_TARGET_DIR/$FAKE_RUST_HOST/release/liboliphaunt_wasix_napi.so" - ;; - esac - exit 0 -fi -exit 1 -`, - ); - chmodSync(script, 0o755); - return script; -} - -test("Linux broker build is exact, isolated, offline, and non-privileged", () => { - if (process.platform !== "linux") return; - const fixture = path.join(ROOT, "target", `linux-abi-build-test-${process.pid}`); - const fakeBin = path.join(fixture, "bin"); - const cargoHome = path.join(fixture, "cargo-home"); - const targetDir = path.join(fixture, "output"); - const log = path.join(fixture, "docker.log"); - mkdirSync(fakeBin, { recursive: true }); - fakeDocker(fakeBin); - try { - const result = spawnSync( - "bash", - [path.join(ROOT, "tools/release/build-linux-broker-baseline.sh"), targetDir], - { - cwd: ROOT, - encoding: "utf8", - env: { - ...process.env, - PATH: `${fakeBin}:${process.env.PATH}`, - CARGO_HOME: cargoHome, - FAKE_DOCKER_LOG: log, - FAKE_TARGET_DIR: targetDir, - }, - }, - ); - assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`); - const calls = readFileSync(log, "utf8"); - assert.match(calls, new RegExp(RUST_IMAGE.replaceAll(".", "\\."), "u")); - assert.match(calls, /--pull never/u); - assert.match(calls, /--network none/u); - assert.match(calls, /--read-only/u); - assert.match(calls, /--cap-drop ALL/u); - assert.match(calls, /--security-opt no-new-privileges/u); - assert.match(calls, /:\/workspace:ro/u); - assert.match(calls, /CARGO_NET_OFFLINE=true/u); - assert.match(calls, /RUSTUP_TOOLCHAIN=1\.93\.1-/u); - assert.match(calls, /OLIPHAUNT_BROKER_AUTH_TOKEN=abi-probe/u); - assert.doesNotMatch(calls, /docker\.sock|credentials|config\.json/u); - } finally { - rmSync(fixture, { recursive: true, force: true }); - } -}); - -test("Linux WASIX Node-API build uses the pinned baseline with exact payload mounts", () => { - if (process.platform !== "linux") return; - const fixture = path.join(ROOT, "target", `linux-wasix-napi-build-test-${process.pid}`); - const fakeBin = path.join(fixture, "bin"); - const cargoHome = path.join(fixture, "cargo-home"); - const targetDir = path.join(fixture, "output"); - const inputRoot = path.join(fixture, "inputs"); - const buildInputs = path.join(inputRoot, "build-inputs.json"); - const log = path.join(fixture, "docker.log"); - const rustHost = os.arch() === "arm64" - ? "aarch64-unknown-linux-gnu" - : "x86_64-unknown-linux-gnu"; - const inputs = { - OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR: path.join(inputRoot, "portable"), - OLIPHAUNT_WASM_GENERATED_AOT_DIR: path.join(inputRoot, "aot"), - OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT: path.join(inputRoot, "extensions"), - OLIPHAUNT_ICU_DATA_DIR: path.join(inputRoot, "icu"), - }; - mkdirSync(fakeBin, { recursive: true }); - for (const input of Object.values(inputs)) mkdirSync(input, { recursive: true }); - writeFileSync(buildInputs, "{}\n"); - fakeDocker(fakeBin); - try { - const result = spawnSync( - "bash", - [ - path.join(ROOT, "tools/release/build-linux-wasix-napi-baseline.sh"), - targetDir, - rustHost, - "release", - ], - { - cwd: ROOT, - encoding: "utf8", - env: { - ...process.env, - ...inputs, - PATH: `${fakeBin}:${process.env.PATH}`, - CARGO_HOME: cargoHome, - FAKE_DOCKER_LOG: log, - FAKE_RUST_HOST: rustHost, - FAKE_TARGET_DIR: targetDir, - OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS: buildInputs, - }, - }, - ); - assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`); - const calls = readFileSync(log, "utf8"); - assert.match(calls, new RegExp(RUST_IMAGE.replaceAll(".", "\\."), "u")); - assert.match(calls, /--pull never/u); - assert.match(calls, /--network none/u); - assert.match(calls, /--read-only/u); - assert.match(calls, /--cap-drop ALL/u); - assert.match(calls, /--security-opt no-new-privileges/u); - assert.match(calls, /EXPECTED_BUILDER_GLIBC=glibc 2\.36/u); - assert.match(calls, /CARGO_NET_OFFLINE=true/u); - assert.match(calls, /OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR=\/workspace\/target\//u); - assert.match(calls, /OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS=\/workspace\/target\//u); - assert.match(calls, /cargo build --locked --offline/u); - assert.match(calls, /--features release/u); - assert.doesNotMatch(calls, /docker\.sock|credentials|config\.json/u); - } finally { - rmSync(fixture, { recursive: true, force: true }); - } -}); - -test("Linux ABI rehearsal pins Fedora and executes without network or privilege", () => { - if (process.platform !== "linux") return; - const fixture = path.join(ROOT, "target", `linux-abi-consumer-test-${process.pid}`); - const fakeBin = path.join(fixture, "bin"); - const consumer = path.join(fixture, "consumer"); - const log = path.join(fixture, "docker.log"); - mkdirSync(fakeBin, { recursive: true }); - mkdirSync(consumer, { recursive: true }); - fakeDocker(fakeBin); - try { - const result = spawnSync( - "bash", - [ - path.join(ROOT, "tools/release/check-linux-consumer-baseline.sh"), - "--target", - os.arch() === "arm64" ? "linux-arm64-gnu" : "linux-x64-gnu", - "--root", - consumer, - ], - { - cwd: ROOT, - encoding: "utf8", - env: { - ...process.env, - PATH: `${fakeBin}:${process.env.PATH}`, - FAKE_DOCKER_LOG: log, - FAKE_TARGET_DIR: path.join(fixture, "unused"), - }, - }, - ); - assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`); - const calls = readFileSync(log, "utf8"); - assert.match(calls, new RegExp(FEDORA_IMAGE.replaceAll(".", "\\."), "u")); - assert.match(calls, /EXPECTED_GLIBC=glibc 2\.38/u); - assert.match(calls, /OLIPHAUNT_BROKER_AUTH_TOKEN=abi-probe/u); - assert.match(calls, /--pull never/u); - assert.match(calls, /--network none/u); - assert.match(calls, /--read-only/u); - assert.match(calls, /--cap-drop ALL/u); - assert.match(calls, /--security-opt no-new-privileges/u); - assert.match(calls, /:\/consumer:ro/u); - } finally { - rmSync(fixture, { recursive: true, force: true }); - } -}); - -test("baseline scripts reject arbitrary host mounts", () => { - if (process.platform !== "linux") return; - for (const [script, args] of [ - ["build-linux-broker-baseline.sh", [path.join(os.tmpdir(), "oliphaunt-outside-build")]], - [ - "build-linux-wasix-napi-baseline.sh", - [ - path.join(os.tmpdir(), "oliphaunt-outside-napi-build"), - os.arch() === "arm64" ? "aarch64-unknown-linux-gnu" : "x86_64-unknown-linux-gnu", - "release", - ], - ], - [ - "check-linux-consumer-baseline.sh", - ["--target", os.arch() === "arm64" ? "linux-arm64-gnu" : "linux-x64-gnu", "--root", os.tmpdir()], - ], - ]) { - const result = spawnSync("bash", [path.join(ROOT, "tools/release", script), ...args], { - cwd: ROOT, - encoding: "utf8", - }); - assert.notEqual(result.status, 0, `${script} unexpectedly accepted an outside mount`); - assert.match(result.stderr, /must be below/u); - } -}); diff --git a/tools/release/linux-native-compiler-contract.test.mjs b/tools/release/linux-native-compiler-contract.test.mjs deleted file mode 100644 index 27da43d6d..000000000 --- a/tools/release/linux-native-compiler-contract.test.mjs +++ /dev/null @@ -1,220 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { ROOT } from "./release-graph.mjs"; - -const CACHE = path.join( - ROOT, - "src/runtimes/liboliphaunt/native/bin/postgis-dependency-cache.sh", -); -const temporaryDirectories = []; - -afterEach(() => { - for (const directory of temporaryDirectories.splice(0)) { - rmSync(directory, { force: true, recursive: true }); - } -}); - -function temporaryDirectory() { - const directory = mkdtempSync(path.join(tmpdir(), "oliphaunt-postgis-cache-")); - temporaryDirectories.push(directory); - return directory; -} - -function cacheOperation(operation, dependencyRoot, fingerprint, operationPaths = []) { - return spawnSync( - "bash", - [ - "-c", - String.raw` -set -euo pipefail -. "$1" -operation="$2" -dependency_root="$3" -fingerprint="$4" -shift 4 -case "$operation" in - prepare) - oliphaunt_postgis_dependency_cache_prepare "$dependency_root" "$fingerprint" "$@" - ;; - commit) - oliphaunt_postgis_dependency_cache_commit "$dependency_root" "$fingerprint" "$@" - ;; - *) - exit 64 - ;; -esac -`, - "postgis-cache-test", - CACHE, - operation, - dependencyRoot, - fingerprint, - ...operationPaths, - ], - { encoding: "utf8" }, - ); -} - -describe("PostGIS native dependency cache", () => { - test("retains an exact-fingerprint cache and atomically records completion", () => { - const root = temporaryDirectory(); - const dependencyRoot = path.join(root, "dependencies"); - const buildRoot = path.join(root, "geos-build"); - const fingerprint = "a".repeat(64); - mkdirSync(dependencyRoot, { recursive: true }); - mkdirSync(buildRoot, { recursive: true }); - writeFileSync(path.join(dependencyRoot, "archive.a"), "valid"); - writeFileSync(path.join(buildRoot, "object.o"), "valid"); - - const committed = cacheOperation("commit", dependencyRoot, fingerprint); - expect(committed.status, committed.stderr).toBe(0); - const prepared = cacheOperation("prepare", dependencyRoot, fingerprint, [buildRoot]); - expect(prepared.status, prepared.stderr).toBe(0); - expect(readFileSync(path.join(dependencyRoot, "archive.a"), "utf8")).toBe("valid"); - expect(readFileSync(path.join(buildRoot, "object.o"), "utf8")).toBe("valid"); - expect( - existsSync(path.join(dependencyRoot, ".oliphaunt-postgis-native-dependencies.sha256")), - ).toBe(false); - expect( - existsSync(path.join(dependencyRoot, ".oliphaunt-postgis-native-dependencies.manifest")), - ).toBe(true); - - const recommitted = cacheOperation("commit", dependencyRoot, fingerprint, [ - path.join(dependencyRoot, "archive.a"), - ]); - expect(recommitted.status, recommitted.stderr).toBe(0); - expect( - readFileSync( - path.join(dependencyRoot, ".oliphaunt-postgis-native-dependencies.sha256"), - "utf8", - ).trim(), - ).toBe(fingerprint); - }); - - test("removes stale installed dependencies and build trees before reuse", () => { - const root = temporaryDirectory(); - const dependencyRoot = path.join(root, "dependencies"); - const buildRoots = [path.join(root, "geos-build"), path.join(root, "proj-build")]; - const previous = "b".repeat(64); - const wanted = "c".repeat(64); - mkdirSync(dependencyRoot, { recursive: true }); - for (const buildRoot of buildRoots) mkdirSync(buildRoot, { recursive: true }); - writeFileSync(path.join(dependencyRoot, "libgeos.a"), "compiled-with-old-g++"); - for (const buildRoot of buildRoots) writeFileSync(path.join(buildRoot, "stale.o"), "stale"); - expect(cacheOperation("commit", dependencyRoot, previous).status).toBe(0); - - const prepared = cacheOperation("prepare", dependencyRoot, wanted, buildRoots); - expect(prepared.status, prepared.stderr).toBe(0); - expect(existsSync(path.join(dependencyRoot, "libgeos.a"))).toBe(false); - for (const buildRoot of buildRoots) expect(existsSync(buildRoot)).toBe(false); - expect( - existsSync(path.join(dependencyRoot, ".oliphaunt-postgis-native-dependencies.sha256")), - ).toBe(false); - - writeFileSync(path.join(dependencyRoot, "libgeos.a"), "rebuilt-with-current-g++"); - const committed = cacheOperation("commit", dependencyRoot, wanted, [ - path.join(dependencyRoot, "libgeos.a"), - ]); - expect(committed.status, committed.stderr).toBe(0); - expect( - readFileSync( - path.join(dependencyRoot, ".oliphaunt-postgis-native-dependencies.sha256"), - "utf8", - ).trim(), - ).toBe(wanted); - }); - - test("discards an interrupted dependency cache that has no completion stamp", () => { - const root = temporaryDirectory(); - const dependencyRoot = path.join(root, "dependencies"); - const buildRoot = path.join(root, "proj-build"); - const wanted = "e".repeat(64); - mkdirSync(dependencyRoot, { recursive: true }); - mkdirSync(buildRoot, { recursive: true }); - writeFileSync(path.join(dependencyRoot, "partial.a"), "interrupted"); - writeFileSync(path.join(buildRoot, "partial.o"), "interrupted"); - - const prepared = cacheOperation("prepare", dependencyRoot, wanted, [buildRoot]); - expect(prepared.status, prepared.stderr).toBe(0); - expect(existsSync(path.join(dependencyRoot, "partial.a"))).toBe(false); - expect(existsSync(buildRoot)).toBe(false); - expect( - existsSync(path.join(dependencyRoot, ".oliphaunt-postgis-native-dependencies.sha256")), - ).toBe(false); - }); - - test("purges a matching-fingerprint cache when any committed output is tampered", () => { - const root = temporaryDirectory(); - const dependencyRoot = path.join(root, "dependencies"); - const buildRoot = path.join(root, "geos-build"); - const archive = path.join(dependencyRoot, "libgeos.a"); - const fingerprint = "f".repeat(64); - mkdirSync(dependencyRoot, { recursive: true }); - mkdirSync(buildRoot, { recursive: true }); - writeFileSync(archive, "exact-output"); - writeFileSync(path.join(buildRoot, "object.o"), "reusable-object"); - const committed = cacheOperation("commit", dependencyRoot, fingerprint, [archive]); - expect(committed.status, committed.stderr).toBe(0); - - writeFileSync(archive, "tampered-output"); - const prepared = cacheOperation("prepare", dependencyRoot, fingerprint, [buildRoot]); - expect(prepared.status, prepared.stderr).toBe(0); - expect(existsSync(archive)).toBe(false); - expect(existsSync(buildRoot)).toBe(false); - }); - - test("never commits an empty required output or reuses an interrupted repair", () => { - const root = temporaryDirectory(); - const dependencyRoot = path.join(root, "dependencies"); - const archive = path.join(dependencyRoot, "libproj.a"); - const fingerprint = "9".repeat(64); - mkdirSync(dependencyRoot, { recursive: true }); - writeFileSync(archive, ""); - const emptyCommit = cacheOperation("commit", dependencyRoot, fingerprint, [archive]); - expect(emptyCommit.status).toBe(1); - expect( - existsSync(path.join(dependencyRoot, ".oliphaunt-postgis-native-dependencies.sha256")), - ).toBe(false); - - writeFileSync(archive, "partial-repair"); - const firstPrepare = cacheOperation("prepare", dependencyRoot, fingerprint); - expect(firstPrepare.status, firstPrepare.stderr).toBe(0); - expect(existsSync(archive)).toBe(false); - writeFileSync(archive, "interrupted-again"); - const secondPrepare = cacheOperation("prepare", dependencyRoot, fingerprint); - expect(secondPrepare.status, secondPrepare.stderr).toBe(0); - expect(existsSync(archive)).toBe(false); - }); - - test("fails closed without deleting data for an invalid fingerprint or root", () => { - const root = temporaryDirectory(); - const dependencyRoot = path.join(root, "dependencies"); - const buildRoot = path.join(root, "geos-build"); - mkdirSync(dependencyRoot, { recursive: true }); - mkdirSync(buildRoot, { recursive: true }); - writeFileSync(path.join(dependencyRoot, "keep"), "keep"); - writeFileSync(path.join(buildRoot, "keep"), "keep"); - - const invalidFingerprint = cacheOperation("prepare", dependencyRoot, "not-a-hash", [ - buildRoot, - ]); - expect(invalidFingerprint.status).toBe(2); - expect(existsSync(path.join(dependencyRoot, "keep"))).toBe(true); - expect(existsSync(path.join(buildRoot, "keep"))).toBe(true); - - const unsafeRoot = cacheOperation("prepare", "/", "d".repeat(64), [buildRoot]); - expect(unsafeRoot.status).toBe(2); - expect(existsSync(path.join(buildRoot, "keep"))).toBe(true); - }); -}); diff --git a/tools/release/locked-attestation-subjects.mjs b/tools/release/locked-attestation-subjects.mjs deleted file mode 100644 index 56339f596..000000000 --- a/tools/release/locked-attestation-subjects.mjs +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/env bun - -import { appendFileSync } from "node:fs"; -import path from "node:path"; - -import { - DEFAULT_PUBLICATION_LOCK, - loadPublicationLock, - lockedProductArtifactPaths, -} from "./publication-lock.mjs"; -import { ROOT, compareText } from "./release-graph.mjs"; - -const ATTESTED_ROLES = Object.freeze([ - "github-release-asset", - "github-release-metadata", -]); -export const EXTENSION_ATTESTATION_SHARD_COUNT = 2; -export const MAX_ATTESTATION_SUBJECTS_PER_BUNDLE = 1_024; - -function error(message) { - return new Error(`locked-attestation-subjects: ${message}`); -} - -function selectedProducts(value) { - if ( - !Array.isArray(value) - || value.length === 0 - || value.some((product) => typeof product !== "string" || product.length === 0) - || new Set(value).size !== value.length - ) { - throw error("products must be a non-empty unique string list"); - } - return value; -} - -/** - * Resolve the exact local subject set frozen for the selected products. - * - * `lockedProductArtifactPaths` re-hashes every returned path. This makes the - * action input both selection-exact and byte-exact: downloading a broad CI - * artifact cannot accidentally add another independently-versioned product to - * the attestation bundle. - */ -export function lockedAttestationSubjects(lock, products) { - const selected = selectedProducts(products); - if (!Array.isArray(lock?.products) || !Array.isArray(lock?.productArtifacts)) { - throw error("publication lock must contain products and productArtifacts lists"); - } - const lockedProducts = new Set(lock.products.map(({ id }) => id)); - const unknown = selected.filter((product) => !lockedProducts.has(product)); - if (unknown.length > 0) { - throw error(`selected products are absent from the publication lock: ${unknown.join(", ")}`); - } - - const subjects = []; - for (const product of selected) { - const productSubjects = ATTESTED_ROLES.flatMap((role) => - lockedProductArtifactPaths(lock, product, { role })); - if (productSubjects.length === 0) { - throw error(`${product} has no frozen GitHub release asset or metadata subjects`); - } - for (const subject of productSubjects) { - if (subject.type !== "file") { - throw error(`${product}:${subject.artifact.id} attestation subject must be a regular file`); - } - const relative = path.relative(ROOT, subject.path); - if ( - relative === "" - || relative.startsWith(`..${path.sep}`) - || path.isAbsolute(relative) - || /[\r\n\u0000]/u.test(relative) - ) { - throw error(`${product}:${subject.artifact.id} has an unsafe action subject path`); - } - subjects.push(relative.split(path.sep).join("/")); - } - } - - subjects.sort(compareText); - if (new Set(subjects).size !== subjects.length) { - throw error("selected products reuse a GitHub release attestation subject path"); - } - const folded = subjects.map((subject) => subject.toLocaleLowerCase("en-US")); - if (new Set(folded).size !== folded.length) { - throw error("selected GitHub release attestation subject paths collide by case"); - } - return subjects; -} - -/** - * Partition the exact subject union into stable, count-balanced action inputs. - * - * GitHub's attestation action accepts at most 1,024 subjects per invocation. - * Round-robin assignment over the sorted exact-lock paths keeps the two bundle - * sizes within one subject of each other without weakening selection or byte - * verification. Empty trailing shards are intentional for very small partial - * releases and are exposed to the workflow through explicit nonempty flags. - */ -export function lockedAttestationSubjectShards(lock, products, { - maxSubjectsPerShard = MAX_ATTESTATION_SUBJECTS_PER_BUNDLE, - shardCount = EXTENSION_ATTESTATION_SHARD_COUNT, -} = {}) { - if (!Number.isSafeInteger(shardCount) || shardCount <= 0) { - throw error("attestation shard count must be a positive safe integer"); - } - if (!Number.isSafeInteger(maxSubjectsPerShard) || maxSubjectsPerShard <= 0) { - throw error("maximum subjects per attestation shard must be a positive safe integer"); - } - const capacity = shardCount * maxSubjectsPerShard; - if (!Number.isSafeInteger(capacity)) { - throw error("attestation shard capacity exceeds the safe integer range"); - } - - const subjects = lockedAttestationSubjects(lock, products); - if (subjects.length > capacity) { - throw error( - `${subjects.length} selected subjects exceed ${shardCount} attestation shards ` - + `at the ${maxSubjectsPerShard}-subject per-bundle limit`, - ); - } - const shards = Array.from({ length: shardCount }, () => []); - for (const [index, subject] of subjects.entries()) { - shards[index % shardCount].push(subject); - } - if (shards.some((shard) => shard.length > maxSubjectsPerShard)) { - throw error(`an attestation shard exceeds the ${maxSubjectsPerShard}-subject per-bundle limit`); - } - - const flattened = shards.flat(); - if ( - flattened.length !== subjects.length - || new Set(flattened).size !== subjects.length - || [...flattened].sort(compareText).some((subject, index) => subject !== subjects[index]) - ) { - throw error("attestation shards do not form the exact disjoint selected subject union"); - } - return shards; -} - -export function githubOutputForAttestationSubjectShards(shards) { - if ( - !Array.isArray(shards) - || shards.length !== EXTENSION_ATTESTATION_SHARD_COUNT - || shards.some((shard) => !Array.isArray(shard)) - ) { - throw error(`GitHub output requires exactly ${EXTENSION_ATTESTATION_SHARD_COUNT} subject shards`); - } - if (shards.some((shard) => shard.length > MAX_ATTESTATION_SUBJECTS_PER_BUNDLE)) { - throw error( - `GitHub output shard exceeds the ${MAX_ATTESTATION_SUBJECTS_PER_BUNDLE}-subject per-bundle limit`, - ); - } - const flattened = shards.flat(); - if ( - flattened.some((subject) => - typeof subject !== "string" - || subject.length === 0 - || /[\r\n\u0000]/u.test(subject)) - || new Set(flattened).size !== flattened.length - ) { - throw error("GitHub output subject shards must contain unique safe paths"); - } - - const lines = [`total_count=${flattened.length}`]; - const subjects = new Set(flattened); - for (const [index, shard] of shards.entries()) { - const number = index + 1; - let delimiter = `OLIPHAUNT_EXTENSION_ATTESTATION_SUBJECTS_${number}`; - while (subjects.has(delimiter)) delimiter += "_END"; - lines.push( - `count_${number}=${shard.length}`, - `nonempty_${number}=${shard.length > 0 ? "true" : "false"}`, - `paths_${number}<<${delimiter}`, - ...shard, - delimiter, - ); - } - return `${lines.join("\n")}\n`; -} - -function parseArgs(argv) { - const values = new Map(); - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg !== "--publication-lock" && arg !== "--products-json" && arg !== "--github-output") { - throw error(`unknown argument ${arg}`); - } - const value = argv[index + 1]; - if (value === undefined || value.length === 0 || value.startsWith("--")) { - throw error(`${arg} requires a value`); - } - if (values.has(arg)) throw error(`${arg} may be specified only once`); - values.set(arg, value); - index += 1; - } - if (!values.has("--products-json")) { - throw error( - "usage: locked-attestation-subjects.mjs --publication-lock FILE --products-json JSON [--github-output FILE]", - ); - } - let products; - try { - products = JSON.parse(values.get("--products-json")); - } catch (cause) { - throw error(`--products-json must be strict JSON: ${cause.message}`); - } - return { - githubOutput: values.get("--github-output"), - lockFile: path.resolve(ROOT, values.get("--publication-lock") ?? DEFAULT_PUBLICATION_LOCK), - products: selectedProducts(products), - }; -} - -if (import.meta.main) { - try { - const args = parseArgs(Bun.argv.slice(2)); - const lock = loadPublicationLock(args.lockFile); - if (args.githubOutput !== undefined) { - const shards = lockedAttestationSubjectShards(lock, args.products); - appendFileSync(args.githubOutput, githubOutputForAttestationSubjectShards(shards), { - encoding: "utf8", - }); - } else { - for (const subject of lockedAttestationSubjects(lock, args.products)) console.log(subject); - } - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/locked-attestation-subjects.mts b/tools/release/locked-attestation-subjects.mts new file mode 100644 index 000000000..b65eedc3c --- /dev/null +++ b/tools/release/locked-attestation-subjects.mts @@ -0,0 +1,234 @@ +#!/usr/bin/env bun + +import { appendFileSync } from 'node:fs'; +import path from 'node:path'; + +import { + DEFAULT_PUBLICATION_LOCK, + loadPublicationLock, + lockedProductArtifactPaths, +} from './publication-lock.mts'; +import { ROOT, compareText } from './release-graph.mts'; + +const ATTESTED_ROLES = Object.freeze(['github-release-asset', 'github-release-metadata']); +export const EXTENSION_ATTESTATION_SHARD_COUNT = 2; +export const MAX_ATTESTATION_SUBJECTS_PER_BUNDLE = 1_024; + +function error(message) { + return new Error(`locked-attestation-subjects: ${message}`); +} + +function selectedProducts(value) { + if ( + !Array.isArray(value) || + value.length === 0 || + value.some((product) => typeof product !== 'string' || product.length === 0) || + new Set(value).size !== value.length + ) { + throw error('products must be a non-empty unique string list'); + } + return value; +} + +/** + * Resolve the exact local subject set frozen for the selected products. + * + * `lockedProductArtifactPaths` re-hashes every returned path. This makes the + * action input both selection-exact and byte-exact: downloading a broad CI + * artifact cannot accidentally add another independently-versioned product to + * the attestation bundle. + */ +export function lockedAttestationSubjects(lock, products) { + const selected = selectedProducts(products); + if (!Array.isArray(lock?.products) || !Array.isArray(lock?.productArtifacts)) { + throw error('publication lock must contain products and productArtifacts lists'); + } + const lockedProducts = new Set(lock.products.map(({ id }) => id)); + const unknown = selected.filter((product) => !lockedProducts.has(product)); + if (unknown.length > 0) { + throw error(`selected products are absent from the publication lock: ${unknown.join(', ')}`); + } + + const subjects = []; + for (const product of selected) { + const productSubjects = ATTESTED_ROLES.flatMap((role) => + lockedProductArtifactPaths(lock, product, { role }), + ); + if (productSubjects.length === 0) { + throw error(`${product} has no frozen GitHub release asset or metadata subjects`); + } + for (const subject of productSubjects) { + if (subject.type !== 'file') { + throw error(`${product}:${subject.artifact.id} attestation subject must be a regular file`); + } + const relative = path.relative(ROOT, subject.path); + if ( + relative === '' || + relative.startsWith(`..${path.sep}`) || + path.isAbsolute(relative) || + /[\r\n\u0000]/u.test(relative) + ) { + throw error(`${product}:${subject.artifact.id} has an unsafe action subject path`); + } + subjects.push(relative.split(path.sep).join('/')); + } + } + + subjects.sort(compareText); + if (new Set(subjects).size !== subjects.length) { + throw error('selected products reuse a GitHub release attestation subject path'); + } + const folded = subjects.map((subject) => subject.toLocaleLowerCase('en-US')); + if (new Set(folded).size !== folded.length) { + throw error('selected GitHub release attestation subject paths collide by case'); + } + return subjects; +} + +/** + * Partition the exact subject union into stable, count-balanced action inputs. + * + * GitHub's attestation action accepts at most 1,024 subjects per invocation. + * Round-robin assignment over the sorted exact-lock paths keeps the two bundle + * sizes within one subject of each other without weakening selection or byte + * verification. Empty trailing shards are intentional for very small partial + * releases and are exposed to the workflow through explicit nonempty flags. + */ +export function lockedAttestationSubjectShards( + lock, + products, + { + maxSubjectsPerShard = MAX_ATTESTATION_SUBJECTS_PER_BUNDLE, + shardCount = EXTENSION_ATTESTATION_SHARD_COUNT, + } = {}, +) { + if (!Number.isSafeInteger(shardCount) || shardCount <= 0) { + throw error('attestation shard count must be a positive safe integer'); + } + if (!Number.isSafeInteger(maxSubjectsPerShard) || maxSubjectsPerShard <= 0) { + throw error('maximum subjects per attestation shard must be a positive safe integer'); + } + const capacity = shardCount * maxSubjectsPerShard; + if (!Number.isSafeInteger(capacity)) { + throw error('attestation shard capacity exceeds the safe integer range'); + } + + const subjects = lockedAttestationSubjects(lock, products); + if (subjects.length > capacity) { + throw error( + `${subjects.length} selected subjects exceed ${shardCount} attestation shards ` + + `at the ${maxSubjectsPerShard}-subject per-bundle limit`, + ); + } + const shards = Array.from({ length: shardCount }, () => []); + for (const [index, subject] of subjects.entries()) { + shards[index % shardCount].push(subject); + } + if (shards.some((shard) => shard.length > maxSubjectsPerShard)) { + throw error(`an attestation shard exceeds the ${maxSubjectsPerShard}-subject per-bundle limit`); + } + + const flattened = shards.flat(); + if ( + flattened.length !== subjects.length || + new Set(flattened).size !== subjects.length || + [...flattened].sort(compareText).some((subject, index) => subject !== subjects[index]) + ) { + throw error('attestation shards do not form the exact disjoint selected subject union'); + } + return shards; +} + +export function githubOutputForAttestationSubjectShards(shards) { + if ( + !Array.isArray(shards) || + shards.length !== EXTENSION_ATTESTATION_SHARD_COUNT || + shards.some((shard) => !Array.isArray(shard)) + ) { + throw error( + `GitHub output requires exactly ${EXTENSION_ATTESTATION_SHARD_COUNT} subject shards`, + ); + } + if (shards.some((shard) => shard.length > MAX_ATTESTATION_SUBJECTS_PER_BUNDLE)) { + throw error( + `GitHub output shard exceeds the ${MAX_ATTESTATION_SUBJECTS_PER_BUNDLE}-subject per-bundle limit`, + ); + } + const flattened = shards.flat(); + if ( + flattened.some( + (subject) => + typeof subject !== 'string' || subject.length === 0 || /[\r\n\u0000]/u.test(subject), + ) || + new Set(flattened).size !== flattened.length + ) { + throw error('GitHub output subject shards must contain unique safe paths'); + } + + const lines = [`total_count=${flattened.length}`]; + const subjects = new Set(flattened); + for (const [index, shard] of shards.entries()) { + const number = index + 1; + let delimiter = `OLIPHAUNT_EXTENSION_ATTESTATION_SUBJECTS_${number}`; + while (subjects.has(delimiter)) delimiter += '_END'; + lines.push( + `count_${number}=${shard.length}`, + `nonempty_${number}=${shard.length > 0 ? 'true' : 'false'}`, + `paths_${number}<<${delimiter}`, + ...shard, + delimiter, + ); + } + return `${lines.join('\n')}\n`; +} + +function parseArgs(argv) { + const values = new Map(); + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg !== '--publication-lock' && arg !== '--products-json' && arg !== '--github-output') { + throw error(`unknown argument ${arg}`); + } + const value = argv[index + 1]; + if (value === undefined || value.length === 0 || value.startsWith('--')) { + throw error(`${arg} requires a value`); + } + if (values.has(arg)) throw error(`${arg} may be specified only once`); + values.set(arg, value); + index += 1; + } + if (!values.has('--products-json')) { + throw error( + 'usage: locked-attestation-subjects.mts --publication-lock FILE --products-json JSON [--github-output FILE]', + ); + } + let products; + try { + products = JSON.parse(values.get('--products-json')); + } catch (cause) { + throw error(`--products-json must be strict JSON: ${cause.message}`); + } + return { + githubOutput: values.get('--github-output'), + lockFile: path.resolve(ROOT, values.get('--publication-lock') ?? DEFAULT_PUBLICATION_LOCK), + products: selectedProducts(products), + }; +} + +if (import.meta.main) { + try { + const args = parseArgs(Bun.argv.slice(2)); + const lock = loadPublicationLock(args.lockFile); + if (args.githubOutput !== undefined) { + const shards = lockedAttestationSubjectShards(lock, args.products); + appendFileSync(args.githubOutput, githubOutputForAttestationSubjectShards(shards), { + encoding: 'utf8', + }); + } else { + for (const subject of lockedAttestationSubjects(lock, args.products)) console.log(subject); + } + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/locked-attestation-subjects.test.mjs b/tools/release/locked-attestation-subjects.test.mjs deleted file mode 100644 index 53581250f..000000000 --- a/tools/release/locked-attestation-subjects.test.mjs +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { mkdir, rm, writeFile } from "node:fs/promises"; -import path from "node:path"; -import test from "node:test"; -import assert from "node:assert/strict"; - -import { - githubOutputForAttestationSubjectShards, - lockedAttestationSubjects, - lockedAttestationSubjectShards, -} from "./locked-attestation-subjects.mjs"; -import { ROOT, compareText } from "./release-graph.mjs"; - -function digest(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -async function fixture(productCounts) { - const root = path.join( - ROOT, - "target", - "release", - `locked-attestation-subjects-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`, - ); - const productArtifacts = []; - for (const [product, count] of Object.entries(productCounts)) { - for (let index = 0; index < count; index += 1) { - const id = `subject-${index + 1}`; - const role = index % 2 === 0 ? "github-release-asset" : "github-release-metadata"; - const file = path.join(root, product, "release-assets", `${id}.bin`); - const bytes = Buffer.from(`${product}:${id}\n`); - await mkdir(path.dirname(file), { recursive: true }); - await writeFile(file, bytes); - productArtifacts.push({ - product, - id, - role, - path: path.relative(ROOT, file).split(path.sep).join("/"), - sha256: digest(bytes), - size: bytes.length, - }); - } - } - return { - lock: { - products: Object.keys(productCounts).map((id) => ({ id })), - productArtifacts, - }, - root, - }; -} - -test("a single external-extension selection excludes every downloaded unselected extension subject", async () => { - const { lock, root } = await fixture({ - "extension-pgvector": 2, - "extension-postgis": 2, - }); - try { - const subjects = lockedAttestationSubjects(lock, ["extension-pgvector"]); - assert.equal(subjects.length, 2); - assert.ok(subjects.every((subject) => subject.includes("/extension-pgvector/"))); - assert.ok(subjects.every((subject) => !subject.includes("/extension-postgis/"))); - - await writeFile(path.resolve(ROOT, subjects[0]), "tampered\n"); - assert.throws( - () => lockedAttestationSubjects(lock, ["extension-pgvector"]), - /bytes do not match the publication lock/u, - ); - assert.throws( - () => lockedAttestationSubjects(lock, ["extension-pgvector", "extension-pgvector"]), - /unique string list/u, - ); - assert.throws( - () => lockedAttestationSubjects(lock, ["extension-unknown"]), - /absent from the publication lock/u, - ); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); - -test("two deterministic balanced shards form the exact disjoint selected subject union", async () => { - const { lock, root } = await fixture({ - "extension-pgvector": 5, - "extension-postgis": 4, - "extension-unselected": 3, - }); - try { - const products = ["extension-postgis", "extension-pgvector"]; - const exact = lockedAttestationSubjects(lock, products); - const shards = lockedAttestationSubjectShards(lock, products); - - assert.deepEqual(lockedAttestationSubjectShards(lock, products), shards); - assert.equal(shards.length, 2); - assert.ok(shards.every((shard) => shard.length <= 1_024)); - assert.ok(Math.abs(shards[0].length - shards[1].length) <= 1); - assert.deepEqual(shards.flat().sort(compareText), exact); - assert.equal(new Set(shards.flat()).size, exact.length); - assert.ok(shards[0].every((subject) => !new Set(shards[1]).has(subject))); - assert.ok(shards.flat().every((subject) => !subject.includes("/extension-unselected/"))); - - assert.throws( - () => lockedAttestationSubjectShards(lock, products, { maxSubjectsPerShard: 4 }), - /exceed 2 attestation shards at the 4-subject per-bundle limit/u, - ); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); - -test("a one-subject partial release skips the empty shard through explicit count and nonempty outputs", async () => { - const { lock, root } = await fixture({ "extension-single": 1 }); - try { - const exact = lockedAttestationSubjects(lock, ["extension-single"]); - const shards = lockedAttestationSubjectShards(lock, ["extension-single"]); - assert.deepEqual(shards, [exact, []]); - - const output = githubOutputForAttestationSubjectShards(shards); - assert.match(output, /^total_count=1$/mu); - assert.match(output, /^count_1=1$/mu); - assert.match(output, /^nonempty_1=true$/mu); - assert.match(output, /^count_2=0$/mu); - assert.match(output, /^nonempty_2=false$/mu); - assert.equal(output.split(exact[0]).length - 1, 1); - assert.throws( - () => githubOutputForAttestationSubjectShards([[exact[0]], [exact[0]]]), - /unique safe paths/u, - ); - const delimiterCollision = githubOutputForAttestationSubjectShards([ - ["OLIPHAUNT_EXTENSION_ATTESTATION_SUBJECTS_1"], - [], - ]); - assert.match( - delimiterCollision, - /^paths_1< githubOutputForAttestationSubjectShards([ - Array.from({ length: 1_025 }, (_, index) => `subject-${index}`), - [], - ]), - /1024-subject per-bundle limit/u, - ); - } finally { - await rm(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/locked-attestation-subjects.test.mts b/tools/release/locked-attestation-subjects.test.mts new file mode 100644 index 000000000..01d0121ca --- /dev/null +++ b/tools/release/locked-attestation-subjects.test.mts @@ -0,0 +1,147 @@ +#!/usr/bin/env bun + +import { createHash } from 'node:crypto'; +import { mkdir, rm, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import test from 'node:test'; +import assert from 'node:assert/strict'; + +import { + githubOutputForAttestationSubjectShards, + lockedAttestationSubjects, + lockedAttestationSubjectShards, +} from './locked-attestation-subjects.mts'; +import { ROOT, compareText } from './release-graph.mts'; + +function digest(bytes) { + return createHash('sha256').update(bytes).digest('hex'); +} + +async function fixture(productCounts) { + const root = path.join( + ROOT, + 'target', + 'release', + `locked-attestation-subjects-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`, + ); + const productArtifacts = []; + for (const [product, count] of Object.entries(productCounts)) { + for (let index = 0; index < count; index += 1) { + const id = `subject-${index + 1}`; + const role = index % 2 === 0 ? 'github-release-asset' : 'github-release-metadata'; + const file = path.join(root, product, 'release-assets', `${id}.bin`); + const bytes = Buffer.from(`${product}:${id}\n`); + await mkdir(path.dirname(file), { recursive: true }); + await writeFile(file, bytes); + productArtifacts.push({ + product, + id, + role, + path: path.relative(ROOT, file).split(path.sep).join('/'), + sha256: digest(bytes), + size: bytes.length, + }); + } + } + return { + lock: { + products: Object.keys(productCounts).map((id) => ({ id })), + productArtifacts, + }, + root, + }; +} + +test('a single external-extension selection excludes every downloaded unselected extension subject', async () => { + const { lock, root } = await fixture({ + 'extension-pgvector': 2, + 'extension-postgis': 2, + }); + try { + const subjects = lockedAttestationSubjects(lock, ['extension-pgvector']); + assert.equal(subjects.length, 2); + assert.ok(subjects.every((subject) => subject.includes('/extension-pgvector/'))); + assert.ok(subjects.every((subject) => !subject.includes('/extension-postgis/'))); + + await writeFile(path.resolve(ROOT, subjects[0]), 'tampered\n'); + assert.throws( + () => lockedAttestationSubjects(lock, ['extension-pgvector']), + /bytes do not match the publication lock/u, + ); + assert.throws( + () => lockedAttestationSubjects(lock, ['extension-pgvector', 'extension-pgvector']), + /unique string list/u, + ); + assert.throws( + () => lockedAttestationSubjects(lock, ['extension-unknown']), + /absent from the publication lock/u, + ); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + +test('two deterministic balanced shards form the exact disjoint selected subject union', async () => { + const { lock, root } = await fixture({ + 'extension-pgvector': 5, + 'extension-postgis': 4, + 'extension-unselected': 3, + }); + try { + const products = ['extension-postgis', 'extension-pgvector']; + const exact = lockedAttestationSubjects(lock, products); + const shards = lockedAttestationSubjectShards(lock, products); + + assert.deepEqual(lockedAttestationSubjectShards(lock, products), shards); + assert.equal(shards.length, 2); + assert.ok(shards.every((shard) => shard.length <= 1_024)); + assert.ok(Math.abs(shards[0].length - shards[1].length) <= 1); + assert.deepEqual(shards.flat().sort(compareText), exact); + assert.equal(new Set(shards.flat()).size, exact.length); + assert.ok(shards[0].every((subject) => !new Set(shards[1]).has(subject))); + assert.ok(shards.flat().every((subject) => !subject.includes('/extension-unselected/'))); + + assert.throws( + () => lockedAttestationSubjectShards(lock, products, { maxSubjectsPerShard: 4 }), + /exceed 2 attestation shards at the 4-subject per-bundle limit/u, + ); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); + +test('a one-subject partial release skips the empty shard through explicit count and nonempty outputs', async () => { + const { lock, root } = await fixture({ 'extension-single': 1 }); + try { + const exact = lockedAttestationSubjects(lock, ['extension-single']); + const shards = lockedAttestationSubjectShards(lock, ['extension-single']); + assert.deepEqual(shards, [exact, []]); + + const output = githubOutputForAttestationSubjectShards(shards); + assert.match(output, /^total_count=1$/mu); + assert.match(output, /^count_1=1$/mu); + assert.match(output, /^nonempty_1=true$/mu); + assert.match(output, /^count_2=0$/mu); + assert.match(output, /^nonempty_2=false$/mu); + assert.equal(output.split(exact[0]).length - 1, 1); + assert.throws( + () => githubOutputForAttestationSubjectShards([[exact[0]], [exact[0]]]), + /unique safe paths/u, + ); + const delimiterCollision = githubOutputForAttestationSubjectShards([ + ['OLIPHAUNT_EXTENSION_ATTESTATION_SUBJECTS_1'], + [], + ]); + assert.match(delimiterCollision, /^paths_1< + githubOutputForAttestationSubjectShards([ + Array.from({ length: 1_025 }, (_, index) => `subject-${index}`), + [], + ]), + /1024-subject per-bundle limit/u, + ); + } finally { + await rm(root, { recursive: true, force: true }); + } +}); diff --git a/tools/release/maintainer-tool-install.test.mjs b/tools/release/maintainer-tool-install.test.mjs deleted file mode 100644 index f5cb3f52a..000000000 --- a/tools/release/maintainer-tool-install.test.mjs +++ /dev/null @@ -1,476 +0,0 @@ -#!/usr/bin/env bun - -import assert from 'node:assert/strict'; -import {spawnSync} from '../test/fd-backed-spawn-sync.mjs'; -import {createHash} from 'node:crypto'; -import { - accessSync, - appendFileSync, - chmodSync, - constants, - cpSync, - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - statSync, - symlinkSync, - writeFileSync, -} from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import {after, test} from 'node:test'; - -import {ROOT} from './release-graph.mjs'; - -const installer = path.join(ROOT, 'tools/dev/install-pinned-maintainer-tool.sh'); -const bootstrap = path.join(ROOT, 'tools/dev/bootstrap-tools.sh'); -const actionlintInstaller = path.join(ROOT, 'tools/dev/install-actionlint.sh'); -const temporaryRoots = []; - -after(() => { - for (const root of temporaryRoots) rmSync(root, {recursive: true, force: true}); -}); - -function sha256(file) { - return createHash('sha256').update(readFileSync(file)).digest('hex'); -} - -function executable(file, contents) { - writeFileSync(file, contents, 'utf8'); - chmodSync(file, 0o755); -} - -function pathExecutable(commandName) { - const extensions = process.platform === 'win32' - ? ['', ...(process.env.PATHEXT ?? '.EXE;.CMD;.BAT;.COM').split(';')] - : ['']; - for (const directory of (process.env.PATH ?? '').split(path.delimiter).filter(Boolean)) { - for (const extension of extensions) { - const candidate = path.join(directory, `${commandName}${extension}`); - try { - accessSync(candidate, constants.X_OK); - if (statSync(candidate).isFile()) return candidate; - } catch { - // Keep searching the ambient PATH captured before the fixture prepends - // its fault-injection shims. - } - } - } - assert.fail(`test host PATH has no executable ${commandName}`); -} - -function command(commandName, args, options = {}) { - const result = spawnSync(commandName, args, {encoding: 'utf8', ...options}); - if (result.error !== undefined) throw result.error; - return result; -} - -function requireSuccess(result, context) { - assert.equal( - result.status, - 0, - `${context} failed\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`, - ); -} - -function createTar(archive, source, members) { - const result = command('tar', ['-czf', archive, '-C', source, ...members]); - requireSuccess(result, `creating ${path.basename(archive)}`); -} - -function writeManifest(fixture, overrides = {}) { - const cargoArchiveSha = overrides.cargoArchiveSha ?? fixture.cargoArchiveSha; - const cargoBinarySha = overrides.cargoBinarySha ?? fixture.cargoBinarySha; - const actionArchiveSha = overrides.actionArchiveSha ?? fixture.actionArchiveSha; - const actionBinarySha = overrides.actionBinarySha ?? fixture.actionBinarySha; - const cargoMaxArchive = overrides.cargoMaxArchive ?? '1048576'; - writeFileSync( - fixture.manifest, - `[cargo-binstall]\nversion = "1.19.1"\nsource_fallback = "cargo install cargo-binstall --version 1.19.1 --locked"\n\n` + - `[cargo-binstall.assets.x86_64-unknown-linux-musl]\n` + - `url = "https://github.com/cargo-bins/cargo-binstall/releases/download/v1.19.1/cargo-binstall-x86_64-unknown-linux-musl.tgz"\n` + - `sha256 = "${cargoArchiveSha}"\nbinary_sha256 = "${cargoBinarySha}"\nformat = "tgz"\n` + - `binary_path = "cargo-binstall"\nentry_count = "1"\nmax_archive_bytes = "${cargoMaxArchive}"\nmax_binary_bytes = "1048576"\n\n` + - `[actionlint]\nversion = "1.7.12"\nsource_fallback = "none"\n\n` + - `[actionlint.assets.linux-amd64]\n` + - `url = "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz"\n` + - `sha256 = "${actionArchiveSha}"\nbinary_sha256 = "${actionBinarySha}"\nformat = "tgz"\n` + - `binary_path = "actionlint"\nentry_count = "11"\nmax_archive_bytes = "1048576"\nmax_binary_bytes = "1048576"\n`, - 'utf8', - ); -} - -function makeFixture() { - const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-maintainer-tools-test-')); - temporaryRoots.push(root); - const fixture = { - root, - bin: path.join(root, 'bin'), - fakeBin: path.join(root, 'fake-bin'), - archives: path.join(root, 'archives'), - manifest: path.join(root, 'maintainer-tools.toml'), - curlLog: path.join(root, 'curl.log'), - cargoLog: path.join(root, 'cargo.log'), - goLog: path.join(root, 'go.log'), - mvFailureMarker: path.join(root, 'mv-failed-once'), - realMv: pathExecutable('mv'), - }; - mkdirSync(fixture.bin); - mkdirSync(fixture.fakeBin); - mkdirSync(fixture.archives); - - const cargoSource = path.join(root, 'cargo-source'); - mkdirSync(cargoSource); - const cargoBinary = path.join(cargoSource, 'cargo-binstall'); - executable( - cargoBinary, - '#!/usr/bin/env bash\nif [ "${1:-}" = -V ]; then printf "%s\\n" "cargo-binstall 1.19.1"; else exit 0; fi\n', - ); - fixture.cargoArchive = path.join(fixture.archives, 'cargo.tgz'); - createTar(fixture.cargoArchive, cargoSource, ['cargo-binstall']); - fixture.cargoArchiveSha = sha256(fixture.cargoArchive); - fixture.cargoBinarySha = sha256(cargoBinary); - - const actionSource = path.join(root, 'action-source'); - for (const directory of ['docs', 'man']) mkdirSync(path.join(actionSource, directory), {recursive: true}); - const actionMembers = [ - 'LICENSE.txt', - 'README.md', - 'actionlint', - 'docs/README.md', - 'docs/api.md', - 'docs/checks.md', - 'docs/config.md', - 'docs/install.md', - 'docs/reference.md', - 'docs/usage.md', - 'man/actionlint.1', - ]; - for (const member of actionMembers) { - const target = path.join(actionSource, member); - if (member === 'actionlint') { - executable( - target, - '#!/usr/bin/env bash\nif [ "${1:-}" = -version ]; then printf "%s\\n" "actionlint version 1.7.12"; else exit 0; fi\n', - ); - } else { - writeFileSync(target, `${member}\n`, 'utf8'); - } - } - fixture.actionArchive = path.join(fixture.archives, 'actionlint.tar.gz'); - createTar(fixture.actionArchive, actionSource, actionMembers); - fixture.actionArchiveSha = sha256(fixture.actionArchive); - fixture.actionBinarySha = sha256(path.join(actionSource, 'actionlint')); - - const badCargoSource = path.join(root, 'bad-cargo-source'); - mkdirSync(badCargoSource); - writeFileSync(path.join(badCargoSource, 'cargo-binstall'), readFileSync(cargoBinary)); - writeFileSync(path.join(badCargoSource, 'unexpected'), 'not allowed\n'); - fixture.badCargoArchive = path.join(fixture.archives, 'bad-cargo.tgz'); - createTar(fixture.badCargoArchive, badCargoSource, ['cargo-binstall', 'unexpected']); - - const linkCargoSource = path.join(root, 'link-cargo-source'); - mkdirSync(linkCargoSource); - symlinkSync( - path.join(root, 'oliphaunt-must-not-be-read'), - path.join(linkCargoSource, 'cargo-binstall'), - ); - fixture.linkCargoArchive = path.join(fixture.archives, 'link-cargo.tgz'); - createTar(fixture.linkCargoArchive, linkCargoSource, ['cargo-binstall']); - - const badActionSource = path.join(root, 'bad-action-source'); - cpSync(actionSource, badActionSource, {recursive: true}); - writeFileSync(path.join(badActionSource, 'unexpected'), 'not allowed\n'); - fixture.badActionArchive = path.join(fixture.archives, 'bad-actionlint.tar.gz'); - createTar(fixture.badActionArchive, badActionSource, [...actionMembers, 'unexpected']); - - executable( - path.join(fixture.fakeBin, 'uname'), - '#!/usr/bin/env bash\ncase "${1:-}" in -s) printf "%s\\n" "${FAKE_UNAME_OS:-Linux}";; -m) printf "%s\\n" "${FAKE_UNAME_ARCH:-x86_64}";; *) exit 2;; esac\n', - ); - executable( - path.join(fixture.fakeBin, 'curl'), - `#!/usr/bin/env bash\nset -eu\nprintf '%s\\n' "$@" >>"$FAKE_CURL_LOG"\noutput=\nprevious=\nfor argument in "$@"; do\n if [ "$previous" = --output ]; then output="$argument"; fi\n previous="$argument"\ndone\n[ -n "$output" ] || exit 2\ncase "\${FAKE_CURL_MODE:-success}" in\n success) cp "$FAKE_CURL_SOURCE" "$output";;\n transport) printf partial >"$output"; exit 28;;\n http) exit 22;;\n oversized) printf partial >"$output"; exit 63;;\n interrupt) printf partial >"$output"; kill -TERM "$PPID"; sleep 0.1; exit 143;;\n *) exit 2;;\nesac\n`, - ); - executable( - path.join(fixture.fakeBin, 'cargo'), - `#!/usr/bin/env bash\nset -eu\nprintf '%s\\n' "$*" >>"$FAKE_CARGO_LOG"\n[ "\${FAKE_CARGO_MODE:-success}" = success ] || exit 42\nroot=\nprevious=\nfor argument in "$@"; do\n if [ "$previous" = --root ]; then root="$argument"; fi\n previous="$argument"\ndone\n[ -n "$root" ] || exit 2\nmkdir -p "$root/bin"\nprintf '%s\\n' '#!/usr/bin/env bash' 'if [ "\${1:-}" = -V ]; then printf "%s\\n" "cargo-binstall 1.19.1"; else exit 0; fi' >"$root/bin/cargo-binstall"\nchmod 0755 "$root/bin/cargo-binstall"\n`, - ); - executable( - path.join(fixture.fakeBin, 'go'), - '#!/usr/bin/env bash\nprintf "%s\\n" "$*" >>"$FAKE_GO_LOG"\nexit 99\n', - ); - executable( - path.join(fixture.fakeBin, 'mv'), - `#!/usr/bin/env bash\nset -eu\nlast=\nfor argument in "$@"; do last="$argument"; done\nif [ -n "\${FAKE_MV_FAIL_TARGET:-}" ] && [ "$last" = "$FAKE_MV_FAIL_TARGET" ] && [ ! -e "$FAKE_MV_FAILURE_MARKER" ]; then\n : >"$FAKE_MV_FAILURE_MARKER"\n exit 91\nfi\nexec "$FAKE_REAL_MV" "$@"\n`, - ); - - writeManifest(fixture); - return fixture; -} - -function environment(fixture, extra = {}) { - return { - ...process.env, - PATH: `${fixture.fakeBin}:${process.env.PATH}`, - HOME: fixture.root, - CARGO_HOME: path.join(fixture.root, 'cargo-home'), - OLIPHAUNT_MAINTAINER_TOOLS_ROOT: fixture.root, - OLIPHAUNT_MAINTAINER_TOOLS_MANIFEST: fixture.manifest, - OLIPHAUNT_MAINTAINER_BIN_DIR: fixture.bin, - OLIPHAUNT_MAINTAINER_TOOLS_CURL: path.join(fixture.fakeBin, 'curl'), - FAKE_CURL_LOG: fixture.curlLog, - FAKE_CARGO_LOG: fixture.cargoLog, - FAKE_GO_LOG: fixture.goLog, - FAKE_MV_FAILURE_MARKER: fixture.mvFailureMarker, - FAKE_REAL_MV: fixture.realMv, - ...extra, - }; -} - -function runInstaller(fixture, tool, extra = {}) { - const source = tool === 'cargo-binstall' ? fixture.cargoArchive : fixture.actionArchive; - return command('bash', [installer, tool], { - cwd: ROOT, - env: environment(fixture, {FAKE_CURL_SOURCE: source, ...extra}), - }); -} - -function assertNoInstallerDebris(fixture) { - assert.deepEqual( - readdirSync(fixture.bin).filter((entry) => /^\.(?:cargo-binstall|actionlint)\.(?:download|install)\./u.test(entry)), - [], - ); -} - -test('release archives are bounded, verified, identity-cached, and corruption-repaired', () => { - const fixture = makeFixture(); - requireSuccess(runInstaller(fixture, 'cargo-binstall'), 'cargo-binstall binary install'); - const final = path.join(fixture.bin, 'cargo-binstall'); - assert.equal(sha256(final), fixture.cargoBinarySha); - const marker = readFileSync(path.join(fixture.bin, '.cargo-binstall.oliphaunt-source'), 'utf8'); - assert.match(marker, /source=release-asset/u); - assert.match(marker, new RegExp(`archive_sha256=${fixture.cargoArchiveSha}`, 'u')); - const flags = readFileSync(fixture.curlLog, 'utf8'); - for (const required of [ - '--max-time', - '--max-filesize', - '--proto', - '=https', - '--proto-redir', - '--tlsv1.2', - '--remove-on-error', - ]) assert.match(flags, new RegExp(`^${required.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}$`, 'mu')); - - const firstCurlLog = readFileSync(fixture.curlLog, 'utf8'); - requireSuccess(runInstaller(fixture, 'cargo-binstall'), 'identity cache hit'); - assert.equal(readFileSync(fixture.curlLog, 'utf8'), firstCurlLog); - - appendFileSync(final, '\n# same version string, different identity\n'); - assert.match(command(final, ['-V']).stdout, /1\.19\.1/u); - requireSuccess(runInstaller(fixture, 'cargo-binstall'), 'corrupt cache repair'); - assert.equal(sha256(final), fixture.cargoBinarySha); - assertNoInstallerDebris(fixture); -}); - -test('checksum, size, member-layout, and member-type failures preserve the prior install', () => { - const fixture = makeFixture(); - requireSuccess(runInstaller(fixture, 'cargo-binstall'), 'initial cargo-binstall install'); - const final = path.join(fixture.bin, 'cargo-binstall'); - const marker = path.join(fixture.bin, '.cargo-binstall.oliphaunt-source'); - const originalBinary = readFileSync(final); - const originalMarker = readFileSync(marker); - - let result = runInstaller(fixture, 'cargo-binstall', { - FAKE_CURL_SOURCE: path.join(fixture.root, 'not-used'), - }); - requireSuccess(result, 'valid cache before faults'); - - appendFileSync(final, '\n# force refresh\n'); - const priorCorruptBinary = readFileSync(final); - const mismatch = path.join(fixture.archives, 'checksum-mismatch'); - writeFileSync(mismatch, 'not the pinned archive'); - result = runInstaller(fixture, 'cargo-binstall', {FAKE_CURL_SOURCE: mismatch}); - assert.notEqual(result.status, 0); - assert.deepEqual(readFileSync(final), priorCorruptBinary); - assert.deepEqual(readFileSync(marker), originalMarker); - - writeManifest(fixture, {cargoArchiveSha: sha256(fixture.badCargoArchive)}); - result = runInstaller(fixture, 'cargo-binstall', {FAKE_CURL_SOURCE: fixture.badCargoArchive}); - assert.notEqual(result.status, 0); - assert.match(result.stderr, /unexpected member layout/u); - assert.deepEqual(readFileSync(final), priorCorruptBinary); - - writeManifest(fixture, {cargoArchiveSha: sha256(fixture.linkCargoArchive)}); - result = runInstaller(fixture, 'cargo-binstall', {FAKE_CURL_SOURCE: fixture.linkCargoArchive}); - assert.notEqual(result.status, 0); - assert.match(result.stderr, /not a regular file/u); - assert.deepEqual(readFileSync(final), priorCorruptBinary); - - writeManifest(fixture, {cargoMaxArchive: '1'}); - result = runInstaller(fixture, 'cargo-binstall'); - assert.notEqual(result.status, 0); - assert.match(result.stderr, /exceeds its maximum size/u); - assert.deepEqual(readFileSync(final), priorCorruptBinary); - assertNoInstallerDebris(fixture); - assert.notDeepEqual(priorCorruptBinary, originalBinary); -}); - -test('transport failure, interruption, and promotion failure clean up and roll back', () => { - const fixture = makeFixture(); - let result = runInstaller(fixture, 'cargo-binstall', {FAKE_CURL_MODE: 'transport'}); - assert.equal(result.status, 75); - assert.equal(existsSync(path.join(fixture.bin, 'cargo-binstall')), false); - assertNoInstallerDebris(fixture); - - result = runInstaller(fixture, 'cargo-binstall', {FAKE_CURL_MODE: 'interrupt'}); - assert.notEqual(result.status, 0); - assert.equal(existsSync(path.join(fixture.bin, 'cargo-binstall')), false); - assertNoInstallerDebris(fixture); - - requireSuccess(runInstaller(fixture, 'cargo-binstall'), 'install before rollback fault'); - const final = path.join(fixture.bin, 'cargo-binstall'); - const marker = path.join(fixture.bin, '.cargo-binstall.oliphaunt-source'); - appendFileSync(final, '\n# force promotion\n'); - const previousBinary = readFileSync(final); - const previousMarker = readFileSync(marker); - result = runInstaller(fixture, 'cargo-binstall', {FAKE_MV_FAIL_TARGET: marker}); - assert.notEqual(result.status, 0); - assert.deepEqual(readFileSync(final), previousBinary); - assert.deepEqual(readFileSync(marker), previousMarker); - assertNoInstallerDebris(fixture); -}); - -test('Cargo fallback is exact, locked, isolated, atomic, and never reuses a partial download', () => { - const fixture = makeFixture(); - const cargoHome = path.join(fixture.root, 'cargo-home'); - const env = environment(fixture, { - CARGO_HOME: cargoHome, - OLIPHAUNT_MAINTAINER_BIN_DIR: path.join(cargoHome, 'bin'), - OLIPHAUNT_BOOTSTRAP_CARGO_BINSTALL_ONLY: '1', - FAKE_CURL_SOURCE: fixture.cargoArchive, - FAKE_CURL_MODE: 'transport', - }); - const result = command('bash', [bootstrap], {cwd: ROOT, env}); - requireSuccess(result, 'locked cargo-binstall source fallback'); - const final = path.join(cargoHome, 'bin', 'cargo-binstall'); - assert.match(command(final, ['-V']).stdout, /1\.19\.1/u); - const cargoArgs = readFileSync(fixture.cargoLog, 'utf8'); - assert.match(cargoArgs, /^install cargo-binstall --version 1\.19\.1 --locked --root \/.+/mu); - const marker = readFileSync(path.join(cargoHome, 'bin', '.cargo-binstall.oliphaunt-source'), 'utf8'); - assert.match(marker, /source=locked-cargo-install/u); - assert.match(marker, /source_ref=cargo-binstall@1\.19\.1/u); - assert.doesNotMatch(readFileSync(final, 'utf8'), /partial/u); - assertNoInstallerDebris({...fixture, bin: path.join(cargoHome, 'bin')}); - - const curlBefore = readFileSync(fixture.curlLog, 'utf8'); - requireSuccess( - command('bash', [installer, 'cargo-binstall'], {cwd: ROOT, env}), - 'locked source identity cache hit', - ); - assert.equal(readFileSync(fixture.curlLog, 'utf8'), curlBefore); -}); - -test('permanent asset and integrity failures cannot bypass pinning through a source build', () => { - for (const mode of ['http', 'oversized', 'checksum']) { - const fixture = makeFixture(); - const mismatch = path.join(fixture.archives, 'mismatch'); - writeFileSync(mismatch, 'not the pinned release archive', 'utf8'); - const result = command('bash', [bootstrap], { - cwd: ROOT, - env: environment(fixture, { - CARGO_HOME: path.join(fixture.root, 'cargo-home'), - OLIPHAUNT_MAINTAINER_BIN_DIR: path.join(fixture.root, 'cargo-home', 'bin'), - OLIPHAUNT_BOOTSTRAP_CARGO_BINSTALL_ONLY: '1', - FAKE_CURL_SOURCE: mode === 'checksum' ? mismatch : fixture.cargoArchive, - FAKE_CURL_MODE: mode === 'checksum' ? 'success' : mode, - }), - }); - assert.notEqual(result.status, 0); - assert.equal(existsSync(fixture.cargoLog), false); - assertNoInstallerDebris({...fixture, bin: path.join(fixture.root, 'cargo-home', 'bin')}); - } -}); - -test('failed locked source fallback preserves prior state', () => { - const fixture = makeFixture(); - const cargoHome = path.join(fixture.root, 'cargo-home'); - const bin = path.join(cargoHome, 'bin'); - mkdirSync(bin, {recursive: true}); - const final = path.join(bin, 'cargo-binstall'); - const marker = path.join(bin, '.cargo-binstall.oliphaunt-source'); - executable(final, '#!/usr/bin/env bash\nprintf "%s\\n" "old install"\n'); - writeFileSync(marker, 'old marker\n'); - const previousBinary = readFileSync(final); - const previousMarker = readFileSync(marker); - const result = command('bash', [bootstrap], { - cwd: ROOT, - env: environment(fixture, { - CARGO_HOME: cargoHome, - OLIPHAUNT_MAINTAINER_BIN_DIR: bin, - OLIPHAUNT_BOOTSTRAP_CARGO_BINSTALL_ONLY: '1', - FAKE_CURL_SOURCE: fixture.cargoArchive, - FAKE_CURL_MODE: 'transport', - FAKE_CARGO_MODE: 'fail', - }), - }); - assert.notEqual(result.status, 0); - assert.deepEqual(readFileSync(final), previousBinary); - assert.deepEqual(readFileSync(marker), previousMarker); - assertNoInstallerDebris({...fixture, bin}); -}); - -test('actionlint uses the same verified path and has no unpinned Go fallback', () => { - const fixture = makeFixture(); - let result = runInstaller(fixture, 'actionlint'); - requireSuccess(result, 'actionlint binary install'); - const final = path.join(fixture.bin, 'actionlint'); - assert.equal(sha256(final), fixture.actionBinarySha); - appendFileSync(final, '\n# force refresh\n'); - const previousBinary = readFileSync(final); - writeManifest(fixture, {actionArchiveSha: sha256(fixture.badActionArchive)}); - result = runInstaller(fixture, 'actionlint', {FAKE_CURL_SOURCE: fixture.badActionArchive}); - assert.notEqual(result.status, 0); - assert.match(result.stderr, /unexpected member layout/u); - assert.deepEqual(readFileSync(final), previousBinary); - assertNoInstallerDebris(fixture); - - const cleanFixture = makeFixture(); - result = command('bash', [actionlintInstaller], { - cwd: ROOT, - env: environment(cleanFixture, { - FAKE_CURL_SOURCE: cleanFixture.actionArchive, - FAKE_CURL_MODE: 'transport', - }), - }); - assert.equal(result.status, 75); - assert.equal(existsSync(cleanFixture.goLog), false); - assertNoInstallerDebris(cleanFixture); -}); - -test('unsupported hosts fail before network access', () => { - const fixture = makeFixture(); - const result = runInstaller(fixture, 'cargo-binstall', {FAKE_UNAME_OS: 'FreeBSD'}); - assert.equal(result.status, 69); - assert.equal(existsSync(fixture.curlLog), false); - assertNoInstallerDebris(fixture); -}); - -test('Taplo uses its locked source directly without probing cargo-quickinstall', () => { - const text = readFileSync(bootstrap, 'utf8'); - assert.match( - text, - /install_cargo_tool taplo-cli taplo "\$TAPLO_VERSION" source-only/u, - ); - assert.match( - text, - /if \[ "\$install_mode" = binary-first \] && has_command cargo-binstall; then/u, - ); - assert.match( - text, - /elif \[ "\$install_mode" = source-only \]; then[\s\S]*no declared binary asset/u, - ); -}); diff --git a/tools/release/manage-release-drafts.test.mjs b/tools/release/manage-release-drafts.test.mjs deleted file mode 100644 index 5dc4897b7..000000000 --- a/tools/release/manage-release-drafts.test.mjs +++ /dev/null @@ -1,1083 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - assertResumableReleaseMetadata, - createReleaseDraftOperationBudget, - exactReleaseMetadata, - exactTagRefPayload, - GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS, - GITHUB_RELEASE_PROMOTION_MUTATION_TIMEOUT_MS, - GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS, - promoteExactReleaseSync, - readSelectedRemoteTagMapSync, - reconcileSelectedReleasesSync, - releaseNotesForVersion, - stageExactDraftReleaseSync, - stageExactTagSync, -} from "../../.github/scripts/manage-release-drafts.mjs"; -import { - GitHubReleaseSnapshotRaceError, - GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS, - GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS, - GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS, -} from "./github-release-mutations.mjs"; - -function budget() { - return { deadlineMs: 180_000, environment: {}, now: () => 0, startedAtMs: 0 }; -} - -function expectedRelease() { - return exactReleaseMetadata({ - body: "### Features\n\n* immutable notes", - headRef: "b".repeat(40), - product: "oliphaunt-js", - tag: "oliphaunt-js-v0.2.0", - version: "0.2.0", - }); -} - -const mutationOptions = { - baseDelayMs: 0, - maxAttempts: 3, - sleep: () => {}, -}; - -test("exact-SHA draft staging never represents a moving branch", () => { - const sha = "a".repeat(40); - assert.deepEqual(exactTagRefPayload("oliphaunt-js-v0.1.0", sha), { - ref: "refs/tags/oliphaunt-js-v0.1.0", - sha, - }); - assert.throws( - () => exactTagRefPayload("oliphaunt-js-v0.1.0", "main"), - /full lowercase commit SHA/u, - ); -}); - -test("release notes select only the exact version section", () => { - const changelog = `# Changelog - -## [0.2.0](https://example.invalid/compare) (2026-07-14) - -### Features - -* exact release notes - -## 0.1.0 (2026-07-01) - -* older notes -`; - assert.equal( - releaseNotesForVersion(changelog, "0.2.0"), - "### Features\n\n* exact release notes", - ); - assert.throws(() => releaseNotesForVersion(changelog, "0.3.0"), /no release heading/u); -}); - -test("existing exact-tag releases are resumable only with exact frozen metadata", () => { - const expected = expectedRelease(); - const release = { - id: 42, - draft: true, - ...expected, - }; - assert.equal(assertResumableReleaseMetadata(release, expected), release); - assert.doesNotThrow(() => assertResumableReleaseMetadata({ ...release, draft: false }, expected)); - - for (const [field, value] of [ - ["tag_name", "oliphaunt-js-v0.1.0"], - ["name", "Oliphaunt JS"], - ["body", "stale notes"], - ["prerelease", true], - ["target_commitish", "main"], - ]) { - assert.throws( - () => assertResumableReleaseMetadata({ ...release, [field]: value }, expected), - new RegExp(`${field}=`, "u"), - ); - } -}); - -test("tag creation accepts an applied-but-timed-out exact full-SHA mutation without replay", () => { - const headRef = "a".repeat(40); - const tag = "oliphaunt-js-v0.2.0"; - let ref = null; - let mutationCalls = 0; - const result = stageExactTagSync( - { budget: budget(), environment: {}, headRef, repo: "o/r", tag }, - { - createTag: () => { - mutationCalls += 1; - ref = { ref: `refs/tags/${tag}`, sha: headRef, type: "commit" }; - throw new Error("response timed out"); - }, - mutationOptions, - readTagRef: () => ref, - }, - ); - assert.equal(mutationCalls, 1); - assert.deepEqual(result, { mutationAttempts: 1, recovered: true }); -}); - -test("tag creation treats another SHA or annotated-tag object as a terminal conflict", () => { - let mutationCalls = 0; - assert.throws( - () => stageExactTagSync( - { - budget: budget(), - environment: {}, - headRef: "a".repeat(40), - repo: "o/r", - tag: "oliphaunt-js-v0.2.0", - }, - { - createTag: () => { - mutationCalls += 1; - }, - mutationOptions, - readTagRef: () => ({ - ref: "refs/tags/oliphaunt-js-v0.2.0", - sha: "c".repeat(40), - type: "tag", - }), - }, - ), - /not commit:/u, - ); - assert.equal(mutationCalls, 0); -}); - -test("draft creation reconciles frozen metadata after an ambiguous response", () => { - const metadata = expectedRelease(); - let release = null; - let mutationCalls = 0; - const result = stageExactDraftReleaseSync( - { - budget: budget(), - environment: {}, - metadata, - repo: "o/r", - tag: metadata.tag_name, - }, - { - createRelease: () => { - mutationCalls += 1; - release = { ...metadata, draft: true, id: 42 }; - throw new Error("timeout after request acceptance"); - }, - mutationOptions, - readRelease: () => release, - }, - ); - assert.equal(mutationCalls, 1); - assert.deepEqual(result, { mutationAttempts: 1, recovered: true }); -}); - -test("draft creation never overwrites malformed or conflicting release metadata", () => { - const metadata = expectedRelease(); - let mutationCalls = 0; - assert.throws( - () => stageExactDraftReleaseSync( - { - budget: budget(), - environment: {}, - metadata, - repo: "o/r", - tag: metadata.tag_name, - }, - { - createRelease: () => { - mutationCalls += 1; - }, - mutationOptions, - readRelease: () => ({ ...metadata, body: "different", draft: true, id: 42 }), - }, - ), - /conflicts with frozen release metadata/u, - ); - assert.equal(mutationCalls, 0); -}); - -test("promotion binds the original release id and reconciles applied timeout", () => { - const metadata = expectedRelease(); - let release = { ...metadata, draft: true, id: 42 }; - let mutationCalls = 0; - const result = promoteExactReleaseSync( - { - budget: budget(), - environment: {}, - expectedId: 42, - metadata, - repo: "o/r", - tag: metadata.tag_name, - }, - { - mutationOptions, - promoteRelease: () => { - mutationCalls += 1; - release = { ...release, draft: false }; - throw new Error("PATCH response timed out"); - }, - readRelease: () => release, - }, - ); - assert.equal(mutationCalls, 1); - assert.deepEqual(result, { mutationAttempts: 1, recovered: true }); -}); - -test("promotion refuses missing or replaced release ids without issuing PATCH", () => { - const metadata = expectedRelease(); - for (const release of [null, { ...metadata, draft: true, id: 99 }]) { - let mutationCalls = 0; - assert.throws( - () => promoteExactReleaseSync( - { - budget: budget(), - environment: {}, - expectedId: 42, - metadata, - repo: "o/r", - tag: metadata.tag_name, - }, - { - mutationOptions, - promoteRelease: () => { - mutationCalls += 1; - }, - readRelease: () => release, - }, - ), - /disappeared|id changed/u, - ); - assert.equal(mutationCalls, 0); - } -}); - -test("batch promotion resumes an exact partially public release set without replaying completed mutations", () => { - const selected = selection(3); - const headRef = "d".repeat(40); - const tags = new Map(selected.map(({ tag }) => [ - tag, - { ref: `refs/tags/${tag}`, sha: headRef, type: "commit" }, - ])); - const releases = new Map(selected.map(({ metadata, tag }, index) => [ - tag, - { ...metadata, draft: true, id: index + 1 }, - ])); - const interruptedTag = selected[1].tag; - const mutations = []; - let interrupted = true; - const dependencies = { - mutationOptions, - mutatePromotion: ({ expectedId, metadata }) => { - const tag = metadata.tag_name; - mutations.push(tag); - const release = releases.get(tag); - assert.equal(release.id, expectedId); - if (interrupted && tag === interruptedTag) { - throw new Error("simulated runner interruption before PATCH"); - } - const promoted = { ...release, draft: false }; - releases.set(tag, promoted); - return JSON.stringify(promoted); - }, - readRelease: (tag) => releases.get(tag) ?? null, - readReleaseMap: () => new Map(releases), - readTagMap: () => new Map(tags), - releaseSnapshotSleep: () => {}, - }; - const reconcile = () => reconcileSelectedReleasesSync({ - budget: budget(), - command: "promote", - environment: {}, - expectedState: "public", - headRef, - repo: "o/r", - selected, - }, dependencies); - - assert.throws( - reconcile, - (cause) => - cause.cause instanceof Error - && cause.cause.message === "simulated runner interruption before PATCH" - && /did not converge to public state/u.test(cause.message) - && /first failure for/u.test(cause.message), - ); - assert.equal(releases.get(selected[0].tag).draft, false); - assert.equal(releases.get(interruptedTag).draft, true); - assert.equal(releases.get(selected[2].tag).draft, false); - - interrupted = false; - assert.doesNotThrow(reconcile); - assert.ok([...releases.values()].every(({ draft }) => draft === false)); - assert.equal(mutations.filter((tag) => tag === selected[0].tag).length, 1); - assert.equal(mutations.filter((tag) => tag === interruptedTag).length, 2); - assert.equal(mutations.filter((tag) => tag === selected[2].tag).length, 1); -}); - -function selection(count = 49) { - const headRef = "d".repeat(40); - return Array.from({ length: count }, (_, index) => { - const product = `product-${String(index).padStart(2, "0")}`; - const tag = `${product}-v1.0.0`; - return { - metadata: exactReleaseMetadata({ - body: `release notes ${index}`, - headRef, - product, - tag, - version: "1.0.0", - }), - product, - tag, - version: "1.0.0", - }; - }); -} - -function releaseState(selected, { draft = true } = {}) { - return new Map(selected.map(({ metadata, tag }, index) => [ - tag, - { ...metadata, draft, id: index + 1 }, - ])); -} - -function tagState(selected, headRef) { - return new Map(selected.map(({ tag }) => [ - tag, - { ref: `refs/tags/${tag}`, sha: headRef, type: "commit" }, - ])); -} - -test("one remote advertisement returns an exact selected tag snapshot", () => { - const selected = selection(3); - const headRef = "d".repeat(40); - const expectedRefs = selected.map(({ tag }) => `refs/tags/${tag}`); - let args; - const snapshot = readSelectedRemoteTagMapSync("o/r", selected, { - budget: budget(), - environment: {}, - spawn: (_command, commandArgs) => { - args = commandArgs; - return { - status: 0, - stderr: "", - stdout: `${headRef}\t${expectedRefs[0]}\n${headRef}\t${expectedRefs[2]}\n`, - }; - }, - }); - assert.ok(args.includes("https://github.com/o/r.git")); - for (const ref of expectedRefs) assert.ok(args.includes(ref)); - assert.equal(snapshot.get(selected[0].tag).sha, headRef); - assert.equal(snapshot.get(selected[1].tag), null); - assert.equal(snapshot.get(selected[2].tag).sha, headRef); - assert.throws( - () => readSelectedRemoteTagMapSync("o/r", selected, { - budget: budget(), - environment: {}, - spawn: () => ({ - status: 0, - stderr: "", - stdout: `${headRef}\trefs/tags/unrequested-v1.0.0\n`, - }), - }), - /unexpected/u, - ); - assert.throws( - () => readSelectedRemoteTagMapSync("o/r", selected, { - budget: budget(), - environment: {}, - spawn: () => ({ - status: 0, - stderr: "", - stdout: `${headRef}\t${expectedRefs[0]}`, - }), - }), - /partial record/u, - ); -}); - -test("remote tag capture retains delayed records and accepts a complete empty first-release snapshot", (t) => { - const selected = selection(3); - const headRef = "d".repeat(40); - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-tag-capture-")); - t.after(() => rmSync(root, { force: true, recursive: true })); - const git = path.join(root, "git"); - writeFileSync(git, [ - `#!${process.execPath}`, - `process.stdout.write(${JSON.stringify(`${headRef}\trefs/tags/${selected[0].tag}\n`)});`, - `setImmediate(() => process.stdout.write(${JSON.stringify(`${headRef}\trefs/tags/${selected[2].tag}\n`)}));`, - "", - ].join("\n")); - chmodSync(git, 0o755); - - const snapshot = readSelectedRemoteTagMapSync("o/r", selected, { - budget: budget(), - cwd: root, - environment: { - ...process.env, - PATH: `${root}${path.delimiter}${process.env.PATH ?? ""}`, - }, - }); - assert.equal(snapshot.get(selected[0].tag).sha, headRef); - assert.equal(snapshot.get(selected[1].tag), null); - assert.equal(snapshot.get(selected[2].tag).sha, headRef); - - writeFileSync(git, `#!${process.execPath}\n`); - chmodSync(git, 0o755); - const emptySnapshot = readSelectedRemoteTagMapSync("o/r", selected, { - budget: budget(), - cwd: root, - environment: { - ...process.env, - PATH: `${root}${path.delimiter}${process.env.PATH ?? ""}`, - }, - }); - assert.deepEqual([...emptySnapshot.values()], [null, null, null]); -}); - -test("the batch lifecycle mutates each exact tag, draft, and promotion once", () => { - const selected = selection(3); - const headRef = "d".repeat(40); - const tags = new Map(selected.map(({ tag }) => [tag, null])); - let releases = new Map(); - let restRequests = 0; - let tagSnapshots = 0; - const dependencies = { - mutationOptions, - mutateRelease: ({ metadata }) => { - restRequests += 1; - const release = { ...metadata, draft: true, id: releases.size + 1 }; - releases.set(metadata.tag_name, release); - return JSON.stringify(release); - }, - mutateTag: ({ headRef: target, tag }) => { - restRequests += 1; - const ref = { ref: `refs/tags/${tag}`, sha: target, type: "commit" }; - tags.set(tag, ref); - return JSON.stringify({ ref: ref.ref, object: { sha: ref.sha, type: ref.type } }); - }, - readRelease: (tag) => releases.get(tag) ?? null, - readReleaseMap: () => { - restRequests += 1; - return new Map(releases); - }, - readTagMap: () => { - tagSnapshots += 1; - return new Map(tags); - }, - readTagRef: (tag) => tags.get(tag) ?? null, - }; - reconcileSelectedReleasesSync({ - budget: budget(), - command: "preflight", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }, dependencies); - assert.equal(restRequests, 1); - assert.equal(tagSnapshots, 1); - - reconcileSelectedReleasesSync({ - budget: budget(), - command: "stage", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }, dependencies); - assert.equal(restRequests, 9, "stage adds two release snapshots plus six exact mutations"); - assert.equal(tagSnapshots, 4); - - reconcileSelectedReleasesSync({ - budget: budget(), - command: "verify", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }, dependencies); - assert.equal(restRequests, 10); - assert.equal(tagSnapshots, 5); - - dependencies.mutatePromotion = ({ expectedId, metadata }) => { - restRequests += 1; - const release = { ...releases.get(metadata.tag_name), draft: false }; - assert.equal(release.id, expectedId); - releases.set(metadata.tag_name, release); - return JSON.stringify(release); - }; - reconcileSelectedReleasesSync({ - budget: budget(), - command: "promote", - environment: {}, - expectedState: "public", - headRef, - repo: "o/r", - selected, - }, dependencies); - assert.equal(restRequests, 15); - assert.equal(tagSnapshots, 7); -}); - -test("batch staging waits for the complete draft list without replaying successful POSTs", () => { - const selected = selection(2); - const headRef = "d".repeat(40); - const tags = new Map(selected.map(({ tag }) => [tag, null])); - const releases = new Map(); - const mutations = []; - const sleeps = []; - let releaseListReads = 0; - const dependencies = { - mutationOptions, - mutateRelease: ({ metadata }) => { - mutations.push(metadata.tag_name); - const release = { ...metadata, draft: true, id: releases.size + 1 }; - releases.set(metadata.tag_name, release); - return JSON.stringify(release); - }, - mutateTag: ({ headRef: target, tag }) => { - const ref = { ref: `refs/tags/${tag}`, sha: target, type: "commit" }; - tags.set(tag, ref); - return JSON.stringify({ ref: ref.ref, object: { sha: ref.sha, type: ref.type } }); - }, - readReleaseMap: () => { - releaseListReads += 1; - if (releaseListReads === 1) return new Map(); - if (releaseListReads <= 4) { - return new Map([...releases].filter(([tag]) => tag !== selected.at(-1).tag)); - } - return new Map(releases); - }, - readTagMap: () => new Map(tags), - releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), - }; - - reconcileSelectedReleasesSync({ - budget: budget(), - command: "stage", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }, dependencies); - - assert.deepEqual(mutations, selected.map(({ tag }) => tag)); - assert.equal(releaseListReads, 5); - assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 3)); -}); - -test("an applied draft POST with a lost response is observed before any replay", () => { - const selected = selection(1); - const headRef = "d".repeat(40); - const tag = selected[0].tag; - const metadata = selected[0].metadata; - const tags = new Map([[tag, null]]); - const releases = new Map(); - const sleeps = []; - let releaseListReads = 0; - let releaseMutations = 0; - const dependencies = { - mutationOptions, - mutateRelease: () => { - releaseMutations += 1; - releases.set(tag, { ...metadata, draft: true, id: 1 }); - throw new Error("response lost after draft creation"); - }, - mutateTag: ({ headRef: target }) => { - const ref = { ref: `refs/tags/${tag}`, sha: target, type: "commit" }; - tags.set(tag, ref); - return JSON.stringify({ ref: ref.ref, object: { sha: ref.sha, type: ref.type } }); - }, - readRelease: () => { - throw new Error("draft recovery must not use the by-tag REST endpoint"); - }, - readReleaseMap: () => { - releaseListReads += 1; - if (releaseListReads <= 3) return new Map(); - return new Map(releases); - }, - readTagMap: () => new Map(tags), - releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), - }; - - reconcileSelectedReleasesSync({ - budget: budget(), - command: "stage", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }, dependencies); - - assert.equal(releaseMutations, 1); - assert.equal(releaseListReads, 5); - assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 2)); -}); - -test("failed draft visibility preserves the original mutation cause without replay", () => { - const selected = selection(1); - const headRef = "d".repeat(40); - const tag = selected[0].tag; - const tags = new Map([[tag, null]]); - const mutationFailure = new Error("HTTP 503 after draft POST"); - let releaseMutations = 0; - const dependencies = { - mutationOptions, - mutateRelease: () => { - releaseMutations += 1; - throw mutationFailure; - }, - mutateTag: ({ headRef: target }) => { - const ref = { ref: `refs/tags/${tag}`, sha: target, type: "commit" }; - tags.set(tag, ref); - return JSON.stringify({ ref: ref.ref, object: { sha: ref.sha, type: ref.type } }); - }, - readReleaseMap: () => new Map(), - readTagMap: () => new Map(tags), - releaseSnapshotSleep: () => {}, - }; - - assert.throws( - () => reconcileSelectedReleasesSync({ - budget: budget(), - command: "stage", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }, dependencies), - (cause) => - cause.cause === mutationFailure - && /original draft mutation failure: HTTP 503 after draft POST/u.test(cause.message) - && /did not converge to staged state/u.test(cause.message), - ); - assert.equal(releaseMutations, 1); -}); - -test("required snapshots retry only a recognized duplicate-across-pagination race", () => { - const selected = selection(1); - const headRef = "d".repeat(40); - const releases = releaseState(selected); - const tags = tagState(selected, headRef); - const sleeps = []; - let reads = 0; - - reconcileSelectedReleasesSync({ - budget: budget(), - command: "verify", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }, { - readReleaseMap: () => { - reads += 1; - if (reads === 1) { - throw new GitHubReleaseSnapshotRaceError( - "GitHub release list repeated release 1 across one paginated snapshot", - ); - } - return new Map(releases); - }, - readTagMap: () => new Map(tags), - releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), - }); - - assert.equal(reads, 2); - assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 1)); -}); - -test("release-list snapshots receive a strict complete-read budget", () => { - const selected = selection(1); - const headRef = "d".repeat(40); - const releases = releaseState(selected); - const tags = tagState(selected, headRef); - const readOptions = []; - - reconcileSelectedReleasesSync({ - budget: budget(), - command: "verify", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }, { - readReleaseMap: (_repo, options) => { - readOptions.push(options); - return new Map(releases); - }, - readTagMap: () => new Map(tags), - }); - - assert.equal(GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS, 645_000); - assert.equal( - createReleaseDraftOperationBudget("promote", { - environment: { OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: "3600000" }, - now: () => 0, - }).deadlineMs, - GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS, - ); - assert.equal( - createReleaseDraftOperationBudget("promote", { - environment: { OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: "123000" }, - now: () => 0, - }).deadlineMs, - 123_000, - ); - assert.equal(readOptions.length, 1); - assert.equal(readOptions[0].deadlineMs, GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS); - assert.equal(readOptions[0].attemptTimeoutMs, 4_000); - assert.equal( - readOptions[0].maxAttempts, - GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS, - ); - assert.equal(GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS, 1); -}); - -test("promotion uses one bounded precondition snapshot and does not wait before mutation", () => { - const selected = selection(1); - const headRef = "d".repeat(40); - let releaseListReads = 0; - let promotionMutations = 0; - let sleeps = 0; - - assert.throws( - () => reconcileSelectedReleasesSync({ - budget: budget(), - command: "promote", - environment: {}, - expectedState: "public", - headRef, - repo: "o/r", - selected, - }, { - mutatePromotion: () => { - promotionMutations += 1; - }, - readReleaseMap: () => { - releaseListReads += 1; - return new Map(); - }, - readTagMap: () => tagState(selected, headRef), - releaseSnapshotSleep: () => { - sleeps += 1; - }, - }), - /does not exist/u, - ); - - assert.equal(releaseListReads, 1); - assert.equal(promotionMutations, 0); - assert.equal(sleeps, 0); -}); - -test("promotion mutation and tag snapshot transports use their conservative sub-bounds", () => { - const selected = selection(1); - const headRef = "d".repeat(40); - const releases = releaseState(selected); - const observedMutationTimeouts = []; - const observedTagTimeouts = []; - - reconcileSelectedReleasesSync({ - budget: budget(), - command: "promote", - environment: {}, - expectedState: "public", - headRef, - repo: "o/r", - selected, - }, { - mutatePromotion: ({ metadata, timeoutMs }) => { - observedMutationTimeouts.push(timeoutMs); - const promoted = { ...releases.get(metadata.tag_name), draft: false }; - releases.set(metadata.tag_name, promoted); - return JSON.stringify(promoted); - }, - readReleaseMap: () => new Map(releases), - readTagMap: (_repo, _selected, options) => { - observedTagTimeouts.push(options?.timeoutMs); - return tagState(selected, headRef); - }, - }); - - assert.deepEqual(observedMutationTimeouts, [ - GITHUB_RELEASE_PROMOTION_MUTATION_TIMEOUT_MS, - ]); - assert.deepEqual(observedTagTimeouts, [ - GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS, - GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS, - ]); - assert.equal(GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS, 30_000); -}); - -test("verification waits for a semantically complete release snapshot without mutation", () => { - const selected = selection(2); - const headRef = "d".repeat(40); - const releases = releaseState(selected); - const tags = tagState(selected, headRef); - const sleeps = []; - let releaseListReads = 0; - - reconcileSelectedReleasesSync({ - budget: budget(), - command: "verify", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }, { - readReleaseMap: () => { - releaseListReads += 1; - if (releaseListReads <= 2) { - return new Map([...releases].filter(([tag]) => tag !== selected.at(-1).tag)); - } - return new Map(releases); - }, - readTagMap: () => new Map(tags), - releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), - }); - - assert.equal(releaseListReads, 3); - assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 2)); -}); - -test("promotion waits for stale draft rows to become public without replaying PATCH", () => { - const selected = selection(2); - const headRef = "d".repeat(40); - const tags = tagState(selected, headRef); - const releases = releaseState(selected); - const mutations = []; - const sleeps = []; - let releaseListReads = 0; - const dependencies = { - mutationOptions, - mutatePromotion: ({ expectedId, metadata }) => { - const release = releases.get(metadata.tag_name); - assert.equal(release.id, expectedId); - mutations.push(metadata.tag_name); - const promoted = { ...release, draft: false }; - releases.set(metadata.tag_name, promoted); - return JSON.stringify(promoted); - }, - readReleaseMap: () => { - releaseListReads += 1; - if (releaseListReads === 1 || releaseListReads >= 4) return new Map(releases); - const stale = new Map(releases); - const finalTag = selected.at(-1).tag; - stale.set(finalTag, { ...stale.get(finalTag), draft: true }); - return stale; - }, - readTagMap: () => new Map(tags), - releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), - }; - - reconcileSelectedReleasesSync({ - budget: budget(), - command: "promote", - environment: {}, - expectedState: "public", - headRef, - repo: "o/r", - selected, - }, dependencies); - - assert.deepEqual(mutations, selected.map(({ tag }) => tag)); - assert.equal(releaseListReads, 4); - assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 2)); -}); - -test("promotion rejects a same-metadata release id replacement before lifecycle closure", () => { - const selected = selection(1); - const headRef = "d".repeat(40); - const original = releaseState(selected); - const replacement = new Map([[ - selected[0].tag, - { ...original.get(selected[0].tag), draft: false, id: 99 }, - ]]); - let releaseListReads = 0; - let promotionMutations = 0; - let sleeps = 0; - - assert.throws( - () => reconcileSelectedReleasesSync({ - budget: budget(), - command: "promote", - environment: {}, - expectedState: "public", - headRef, - repo: "o/r", - selected, - }, { - mutatePromotion: ({ expectedId, metadata }) => { - promotionMutations += 1; - return JSON.stringify({ - ...original.get(metadata.tag_name), - draft: false, - id: expectedId, - }); - }, - readReleaseMap: () => { - releaseListReads += 1; - return releaseListReads === 1 ? new Map(original) : new Map(replacement); - }, - readTagMap: () => tagState(selected, headRef), - releaseSnapshotSleep: () => { - sleeps += 1; - }, - }), - /release id changed from 1 to 99/u, - ); - - assert.equal(releaseListReads, 2); - assert.equal(promotionMutations, 1); - assert.equal(sleeps, 0); -}); - -test("required release snapshots fail boundedly when state never becomes visible", () => { - const selected = selection(1); - const sleeps = []; - let releaseListReads = 0; - assert.throws( - () => reconcileSelectedReleasesSync({ - budget: budget(), - command: "verify", - environment: {}, - expectedState: "staged", - headRef: "d".repeat(40), - repo: "o/r", - selected, - }, { - readReleaseMap: () => { - releaseListReads += 1; - return new Map(); - }, - readTagMap: () => tagState(selected, "d".repeat(40)), - releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), - }), - new RegExp( - `did not converge to staged state.*${selected[0].tag} \\(missing\\)`, - "u", - ), - ); - assert.equal(releaseListReads, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.length + 1); - assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS); -}); - -test("required release snapshots reject conflicting metadata without waiting", () => { - const selected = selection(1); - let sleeps = 0; - assert.throws( - () => reconcileSelectedReleasesSync({ - budget: budget(), - command: "verify", - environment: {}, - expectedState: "staged", - headRef: "d".repeat(40), - repo: "o/r", - selected, - }, { - readReleaseMap: () => new Map([[ - selected[0].tag, - { ...selected[0].metadata, body: "conflict", draft: true, id: 1 }, - ]]), - readTagMap: () => tagState(selected, "d".repeat(40)), - releaseSnapshotSleep: () => { - sleeps += 1; - }, - }), - /conflicts with frozen release metadata/u, - ); - assert.equal(sleeps, 0); - - assert.throws( - () => reconcileSelectedReleasesSync({ - budget: budget(), - command: "verify", - environment: {}, - expectedState: "staged", - headRef: "d".repeat(40), - repo: "o/r", - selected, - }, { - readReleaseMap: () => { - const observedRelease = { - ...selected[0].metadata, - body: "conflict", - draft: true, - id: 1, - }; - throw new GitHubReleaseSnapshotRaceError( - "duplicate across pages", - { observedRelease }, - ); - }, - readTagMap: () => tagState(selected, "d".repeat(40)), - releaseSnapshotSleep: () => { - sleeps += 1; - }, - }), - /conflicts with frozen release metadata/u, - ); - assert.equal(sleeps, 0); -}); - -test("batch staging reconciles ambiguous responses once and exact reruns issue no mutations", () => { - const selected = selection(1); - const headRef = "d".repeat(40); - const tag = selected[0].tag; - const metadata = selected[0].metadata; - const tags = new Map([[tag, null]]); - let releases = new Map(); - let tagMutations = 0; - let releaseMutations = 0; - const dependencies = { - mutationOptions, - mutateRelease: () => { - releaseMutations += 1; - releases.set(tag, { ...metadata, draft: true, id: 1 }); - throw new Error("response lost after draft creation"); - }, - mutateTag: () => { - tagMutations += 1; - tags.set(tag, { ref: `refs/tags/${tag}`, sha: headRef, type: "commit" }); - throw new Error("response lost after tag creation"); - }, - readRelease: (value) => releases.get(value) ?? null, - readReleaseMap: () => new Map(releases), - readTagMap: () => new Map(tags), - readTagRef: (value) => tags.get(value) ?? null, - }; - const context = { - budget: budget(), - command: "stage", - environment: {}, - expectedState: "staged", - headRef, - repo: "o/r", - selected, - }; - reconcileSelectedReleasesSync(context, dependencies); - assert.equal(tagMutations, 1); - assert.equal(releaseMutations, 1); - - reconcileSelectedReleasesSync(context, dependencies); - assert.equal(tagMutations, 1, "an exact rerun does not replay tag creation"); - assert.equal(releaseMutations, 1, "an exact rerun does not replay release creation"); -}); diff --git a/tools/release/manage-release-drafts.test.mts b/tools/release/manage-release-drafts.test.mts new file mode 100644 index 000000000..384c0be93 --- /dev/null +++ b/tools/release/manage-release-drafts.test.mts @@ -0,0 +1,1111 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + assertResumableReleaseMetadata, + createReleaseDraftOperationBudget, + exactReleaseMetadata, + exactTagRefPayload, + GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS, + GITHUB_RELEASE_PROMOTION_MUTATION_TIMEOUT_MS, + GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS, + promoteExactRelease, + readSelectedRemoteTagMap, + reconcileSelectedReleases, + releaseNotesForVersion, + stageExactDraftRelease, + stageExactTag, +} from '../../.github/scripts/manage-release-drafts.mts'; +import { + GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS, + GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS, + GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS, + GitHubReleaseSnapshotRaceError, +} from './github-release-mutations.mts'; + +function budget() { + return { deadlineMs: 180_000, environment: {}, now: () => 0, startedAtMs: 0 }; +} + +function expectedRelease() { + return exactReleaseMetadata({ + body: '### Features\n\n* immutable notes', + headRef: 'b'.repeat(40), + product: 'oliphaunt-js', + tag: 'oliphaunt-js-v0.2.0', + version: '0.2.0', + }); +} + +const mutationOptions = { + baseDelayMs: 0, + maxAttempts: 3, + sleep: () => {}, +}; + +test('exact-SHA draft staging never represents a moving branch', () => { + const sha = 'a'.repeat(40); + assert.deepEqual(exactTagRefPayload('oliphaunt-js-v0.1.0', sha), { + ref: 'refs/tags/oliphaunt-js-v0.1.0', + sha, + }); + assert.throws( + () => exactTagRefPayload('oliphaunt-js-v0.1.0', 'main'), + /full lowercase commit SHA/u, + ); +}); + +test('release notes select only the exact version section', () => { + const changelog = `# Changelog + +## [0.2.0](https://example.invalid/compare) (2026-07-14) + +### Features + +* exact release notes + +## 0.1.0 (2026-07-01) + +* older notes +`; + assert.equal(releaseNotesForVersion(changelog, '0.2.0'), '### Features\n\n* exact release notes'); + assert.throws(() => releaseNotesForVersion(changelog, '0.3.0'), /no release heading/u); +}); + +test('existing exact-tag releases are resumable only with exact frozen metadata', () => { + const expected = expectedRelease(); + const release = { + id: 42, + draft: true, + ...expected, + }; + assert.equal(assertResumableReleaseMetadata(release, expected), release); + assert.doesNotThrow(() => assertResumableReleaseMetadata({ ...release, draft: false }, expected)); + + for (const [field, value] of [ + ['tag_name', 'oliphaunt-js-v0.1.0'], + ['name', 'Oliphaunt JS'], + ['body', 'stale notes'], + ['prerelease', true], + ['target_commitish', 'main'], + ]) { + assert.throws( + () => assertResumableReleaseMetadata({ ...release, [field]: value }, expected), + new RegExp(`${field}=`, 'u'), + ); + } +}); + +test('tag creation accepts an applied-but-timed-out exact full-SHA mutation without replay', async () => { + const headRef = 'a'.repeat(40); + const tag = 'oliphaunt-js-v0.2.0'; + let ref = null; + let mutationCalls = 0; + const result = await stageExactTag( + { budget: budget(), environment: {}, headRef, repo: 'o/r', tag }, + { + createTag: () => { + mutationCalls += 1; + ref = { ref: `refs/tags/${tag}`, sha: headRef, type: 'commit' }; + throw new Error('response timed out'); + }, + mutationOptions, + readTagRef: () => ref, + }, + ); + assert.equal(mutationCalls, 1); + assert.deepEqual(result, { mutationAttempts: 1, recovered: true }); +}); + +test('tag creation treats another SHA or annotated-tag object as a terminal conflict', async () => { + let mutationCalls = 0; + await assert.rejects( + async () => + await stageExactTag( + { + budget: budget(), + environment: {}, + headRef: 'a'.repeat(40), + repo: 'o/r', + tag: 'oliphaunt-js-v0.2.0', + }, + { + createTag: () => { + mutationCalls += 1; + }, + mutationOptions, + readTagRef: () => ({ + ref: 'refs/tags/oliphaunt-js-v0.2.0', + sha: 'c'.repeat(40), + type: 'tag', + }), + }, + ), + /not commit:/u, + ); + assert.equal(mutationCalls, 0); +}); + +test('draft creation reconciles frozen metadata after an ambiguous response', async () => { + const metadata = expectedRelease(); + let release = null; + let mutationCalls = 0; + const result = await stageExactDraftRelease( + { + budget: budget(), + environment: {}, + metadata, + repo: 'o/r', + tag: metadata.tag_name, + }, + { + createRelease: () => { + mutationCalls += 1; + release = { ...metadata, draft: true, id: 42 }; + throw new Error('timeout after request acceptance'); + }, + mutationOptions, + readRelease: () => release, + }, + ); + assert.equal(mutationCalls, 1); + assert.deepEqual(result, { mutationAttempts: 1, recovered: true }); +}); + +test('draft creation never overwrites malformed or conflicting release metadata', async () => { + const metadata = expectedRelease(); + let mutationCalls = 0; + await assert.rejects( + async () => + await stageExactDraftRelease( + { + budget: budget(), + environment: {}, + metadata, + repo: 'o/r', + tag: metadata.tag_name, + }, + { + createRelease: () => { + mutationCalls += 1; + }, + mutationOptions, + readRelease: () => ({ ...metadata, body: 'different', draft: true, id: 42 }), + }, + ), + /conflicts with frozen release metadata/u, + ); + assert.equal(mutationCalls, 0); +}); + +test('promotion binds the original release id and reconciles applied timeout', async () => { + const metadata = expectedRelease(); + let release = { ...metadata, draft: true, id: 42 }; + let mutationCalls = 0; + const result = await promoteExactRelease( + { + budget: budget(), + environment: {}, + expectedId: 42, + metadata, + repo: 'o/r', + tag: metadata.tag_name, + }, + { + mutationOptions, + promoteRelease: () => { + mutationCalls += 1; + release = { ...release, draft: false }; + throw new Error('PATCH response timed out'); + }, + readRelease: () => release, + }, + ); + assert.equal(mutationCalls, 1); + assert.deepEqual(result, { mutationAttempts: 1, recovered: true }); +}); + +test('promotion refuses missing or replaced release ids without issuing PATCH', async () => { + const metadata = expectedRelease(); + for (const release of [null, { ...metadata, draft: true, id: 99 }]) { + let mutationCalls = 0; + await assert.rejects( + async () => + await promoteExactRelease( + { + budget: budget(), + environment: {}, + expectedId: 42, + metadata, + repo: 'o/r', + tag: metadata.tag_name, + }, + { + mutationOptions, + promoteRelease: () => { + mutationCalls += 1; + }, + readRelease: () => release, + }, + ), + /disappeared|id changed/u, + ); + assert.equal(mutationCalls, 0); + } +}); + +test('batch promotion resumes an exact partially public release set without replaying completed mutations', async () => { + const selected = selection(3); + const headRef = 'd'.repeat(40); + const tags = new Map( + selected.map(({ tag }) => [tag, { ref: `refs/tags/${tag}`, sha: headRef, type: 'commit' }]), + ); + const releases = new Map( + selected.map(({ metadata, tag }, index) => [tag, { ...metadata, draft: true, id: index + 1 }]), + ); + const interruptedTag = selected[1].tag; + const mutations = []; + let interrupted = true; + const dependencies = { + mutationOptions, + mutatePromotion: ({ expectedId, metadata }) => { + const tag = metadata.tag_name; + mutations.push(tag); + const release = releases.get(tag); + assert.equal(release.id, expectedId); + if (interrupted && tag === interruptedTag) { + throw new Error('simulated runner interruption before PATCH'); + } + const promoted = { ...release, draft: false }; + releases.set(tag, promoted); + return JSON.stringify(promoted); + }, + readRelease: (tag) => releases.get(tag) ?? null, + readReleaseMap: () => new Map(releases), + readTagMap: () => new Map(tags), + releaseSnapshotSleep: () => {}, + }; + const reconcile = async () => + await reconcileSelectedReleases( + { + budget: budget(), + command: 'promote', + environment: {}, + expectedState: 'public', + headRef, + repo: 'o/r', + selected, + }, + dependencies, + ); + + await assert.rejects( + reconcile, + (cause) => + cause.cause instanceof Error && + cause.cause.message === 'simulated runner interruption before PATCH' && + /did not converge to public state/u.test(cause.message) && + /first failure for/u.test(cause.message), + ); + assert.equal(releases.get(selected[0].tag).draft, false); + assert.equal(releases.get(interruptedTag).draft, true); + assert.equal(releases.get(selected[2].tag).draft, false); + + interrupted = false; + await reconcile(); + assert.ok([...releases.values()].every(({ draft }) => draft === false)); + assert.equal(mutations.filter((tag) => tag === selected[0].tag).length, 1); + assert.equal(mutations.filter((tag) => tag === interruptedTag).length, 2); + assert.equal(mutations.filter((tag) => tag === selected[2].tag).length, 1); +}); + +function selection(count = 49) { + const headRef = 'd'.repeat(40); + return Array.from({ length: count }, (_, index) => { + const product = `product-${String(index).padStart(2, '0')}`; + const tag = `${product}-v1.0.0`; + return { + metadata: exactReleaseMetadata({ + body: `release notes ${index}`, + headRef, + product, + tag, + version: '1.0.0', + }), + product, + tag, + version: '1.0.0', + }; + }); +} + +function releaseState(selected, { draft = true } = {}) { + return new Map( + selected.map(({ metadata, tag }, index) => [tag, { ...metadata, draft, id: index + 1 }]), + ); +} + +function tagState(selected, headRef) { + return new Map( + selected.map(({ tag }) => [tag, { ref: `refs/tags/${tag}`, sha: headRef, type: 'commit' }]), + ); +} + +test('one native query preserves exact tag identities, absence, and target type', async () => { + const selected = selection(3); + const headRef = 'd'.repeat(40); + const repository = { + nameWithOwner: 'o/r', + tag0: { + prefix: 'refs/tags/', + name: selected[0].tag, + target: { __typename: 'Commit', oid: headRef }, + }, + tag1: null, + tag2: { + prefix: 'refs/tags/', + name: selected[2].tag, + target: { __typename: 'Tag', oid: headRef }, + }, + }; + let calls = 0; + const snapshot = await readSelectedRemoteTagMap('o/r', selected, { + budget: budget(), + environment: {}, + fetchImpl: async (url, init) => { + calls++; + assert.equal(url, 'https://api.github.com/graphql'); + assert.equal(init.method, 'POST'); + assert.equal(init.redirect, 'error'); + const body = JSON.parse(init.body); + for (const [index, { tag }] of selected.entries()) + assert.equal(body.variables['tag' + index], 'refs/tags/' + tag); + return Response.json({ data: { repository } }); + }, + }); + assert.equal(calls, 1); + assert.deepEqual(snapshot.get(selected[0].tag), { + ref: 'refs/tags/' + selected[0].tag, + sha: headRef, + type: 'commit', + }); + assert.equal(snapshot.get(selected[1].tag), null); + assert.equal(snapshot.get(selected[2].tag).type, 'tag'); + for (const response of [ + { data: { repository }, errors: [{ message: 'partial result' }] }, + { data: { repository: { ...repository, nameWithOwner: 'other/repo' } } }, + { data: { repository: { ...repository, tag0: undefined } } }, + { data: { repository: { ...repository, tag0: { ...repository.tag0, name: 'unrequested' } } } }, + { data: { repository: { ...repository, tag0: { ...repository.tag0, target: null } } } }, + ]) { + await assert.rejects( + readSelectedRemoteTagMap('o/r', selected, { + budget: budget(), + environment: {}, + fetchImpl: async () => Response.json(response), + }), + /incomplete|unexpected|malformed/u, + ); + } + await assert.rejects( + readSelectedRemoteTagMap('o/r', selected, { + budget: { ...budget(), deadlineMs: 0 }, + fetchImpl: () => { + throw Error('must not fetch'); + }, + }), + /deadline/u, + ); +}); + +test('the batch lifecycle mutates each exact tag, draft, and promotion once', async () => { + const selected = selection(3); + const headRef = 'd'.repeat(40); + const tags = new Map(selected.map(({ tag }) => [tag, null])); + let releases = new Map(); + let restRequests = 0; + let tagSnapshots = 0; + const dependencies = { + mutationOptions, + mutateRelease: ({ metadata }) => { + restRequests += 1; + const release = { ...metadata, draft: true, id: releases.size + 1 }; + releases.set(metadata.tag_name, release); + return JSON.stringify(release); + }, + mutateTag: ({ headRef: target, tag }) => { + restRequests += 1; + const ref = { ref: `refs/tags/${tag}`, sha: target, type: 'commit' }; + tags.set(tag, ref); + return JSON.stringify({ ref: ref.ref, object: { sha: ref.sha, type: ref.type } }); + }, + readRelease: (tag) => releases.get(tag) ?? null, + readReleaseMap: () => { + restRequests += 1; + return new Map(releases); + }, + readTagMap: () => { + tagSnapshots += 1; + return new Map(tags); + }, + readTagRef: (tag) => tags.get(tag) ?? null, + }; + await reconcileSelectedReleases( + { + budget: budget(), + command: 'preflight', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }, + dependencies, + ); + assert.equal(restRequests, 1); + assert.equal(tagSnapshots, 1); + + await reconcileSelectedReleases( + { + budget: budget(), + command: 'stage', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }, + dependencies, + ); + assert.equal(restRequests, 9, 'stage adds two release snapshots plus six exact mutations'); + assert.equal(tagSnapshots, 4); + + await reconcileSelectedReleases( + { + budget: budget(), + command: 'verify', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }, + dependencies, + ); + assert.equal(restRequests, 10); + assert.equal(tagSnapshots, 5); + + dependencies.mutatePromotion = ({ expectedId, metadata }) => { + restRequests += 1; + const release = { ...releases.get(metadata.tag_name), draft: false }; + assert.equal(release.id, expectedId); + releases.set(metadata.tag_name, release); + return JSON.stringify(release); + }; + await reconcileSelectedReleases( + { + budget: budget(), + command: 'promote', + environment: {}, + expectedState: 'public', + headRef, + repo: 'o/r', + selected, + }, + dependencies, + ); + assert.equal(restRequests, 15); + assert.equal(tagSnapshots, 7); +}); + +test('batch staging waits for the complete draft list without replaying successful POSTs', async () => { + const selected = selection(2); + const headRef = 'd'.repeat(40); + const tags = new Map(selected.map(({ tag }) => [tag, null])); + const releases = new Map(); + const mutations = []; + const sleeps = []; + let releaseListReads = 0; + const dependencies = { + mutationOptions, + mutateRelease: ({ metadata }) => { + mutations.push(metadata.tag_name); + const release = { ...metadata, draft: true, id: releases.size + 1 }; + releases.set(metadata.tag_name, release); + return JSON.stringify(release); + }, + mutateTag: ({ headRef: target, tag }) => { + const ref = { ref: `refs/tags/${tag}`, sha: target, type: 'commit' }; + tags.set(tag, ref); + return JSON.stringify({ ref: ref.ref, object: { sha: ref.sha, type: ref.type } }); + }, + readReleaseMap: () => { + releaseListReads += 1; + if (releaseListReads === 1) return new Map(); + if (releaseListReads <= 4) { + return new Map([...releases].filter(([tag]) => tag !== selected.at(-1).tag)); + } + return new Map(releases); + }, + readTagMap: () => new Map(tags), + releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), + }; + + await reconcileSelectedReleases( + { + budget: budget(), + command: 'stage', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }, + dependencies, + ); + + assert.deepEqual( + mutations, + selected.map(({ tag }) => tag), + ); + assert.equal(releaseListReads, 5); + assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 3)); +}); + +test('an applied draft POST with a lost response is observed before any replay', async () => { + const selected = selection(1); + const headRef = 'd'.repeat(40); + const tag = selected[0].tag; + const metadata = selected[0].metadata; + const tags = new Map([[tag, null]]); + const releases = new Map(); + const sleeps = []; + let releaseListReads = 0; + let releaseMutations = 0; + const dependencies = { + mutationOptions, + mutateRelease: () => { + releaseMutations += 1; + releases.set(tag, { ...metadata, draft: true, id: 1 }); + throw new Error('response lost after draft creation'); + }, + mutateTag: ({ headRef: target }) => { + const ref = { ref: `refs/tags/${tag}`, sha: target, type: 'commit' }; + tags.set(tag, ref); + return JSON.stringify({ ref: ref.ref, object: { sha: ref.sha, type: ref.type } }); + }, + readRelease: () => { + throw new Error('draft recovery must not use the by-tag REST endpoint'); + }, + readReleaseMap: () => { + releaseListReads += 1; + if (releaseListReads <= 3) return new Map(); + return new Map(releases); + }, + readTagMap: () => new Map(tags), + releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), + }; + + await reconcileSelectedReleases( + { + budget: budget(), + command: 'stage', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }, + dependencies, + ); + + assert.equal(releaseMutations, 1); + assert.equal(releaseListReads, 5); + assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 2)); +}); + +test('failed draft visibility preserves the original mutation cause without replay', async () => { + const selected = selection(1); + const headRef = 'd'.repeat(40); + const tag = selected[0].tag; + const tags = new Map([[tag, null]]); + const mutationFailure = new Error('HTTP 503 after draft POST'); + let releaseMutations = 0; + const dependencies = { + mutationOptions, + mutateRelease: () => { + releaseMutations += 1; + throw mutationFailure; + }, + mutateTag: ({ headRef: target }) => { + const ref = { ref: `refs/tags/${tag}`, sha: target, type: 'commit' }; + tags.set(tag, ref); + return JSON.stringify({ ref: ref.ref, object: { sha: ref.sha, type: ref.type } }); + }, + readReleaseMap: () => new Map(), + readTagMap: () => new Map(tags), + releaseSnapshotSleep: () => {}, + }; + + await assert.rejects( + async () => + await reconcileSelectedReleases( + { + budget: budget(), + command: 'stage', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }, + dependencies, + ), + (cause) => + cause.cause === mutationFailure && + /original draft mutation failure: HTTP 503 after draft POST/u.test(cause.message) && + /did not converge to staged state/u.test(cause.message), + ); + assert.equal(releaseMutations, 1); +}); + +test('required snapshots retry only a recognized duplicate-across-pagination race', async () => { + const selected = selection(1); + const headRef = 'd'.repeat(40); + const releases = releaseState(selected); + const tags = tagState(selected, headRef); + const sleeps = []; + let reads = 0; + + await reconcileSelectedReleases( + { + budget: budget(), + command: 'verify', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }, + { + readReleaseMap: () => { + reads += 1; + if (reads === 1) { + throw new GitHubReleaseSnapshotRaceError( + 'GitHub release list repeated release 1 across one paginated snapshot', + ); + } + return new Map(releases); + }, + readTagMap: () => new Map(tags), + releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), + }, + ); + + assert.equal(reads, 2); + assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 1)); +}); + +test('release-list snapshots receive a strict complete-read budget', async () => { + const selected = selection(1); + const headRef = 'd'.repeat(40); + const releases = releaseState(selected); + const tags = tagState(selected, headRef); + const readOptions = []; + + await reconcileSelectedReleases( + { + budget: budget(), + command: 'verify', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }, + { + readReleaseMap: (_repo, options) => { + readOptions.push(options); + return new Map(releases); + }, + readTagMap: () => new Map(tags), + }, + ); + + assert.equal(GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS, 645_000); + assert.equal( + createReleaseDraftOperationBudget('promote', { + environment: { OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: '3600000' }, + now: () => 0, + }).deadlineMs, + GITHUB_RELEASE_PROMOTION_COMMAND_WINDOW_MS, + ); + assert.equal( + createReleaseDraftOperationBudget('promote', { + environment: { OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: '123000' }, + now: () => 0, + }).deadlineMs, + 123_000, + ); + assert.equal(readOptions.length, 1); + assert.equal(readOptions[0].deadlineMs, GITHUB_RELEASE_SNAPSHOT_READ_WINDOW_MS); + assert.equal(readOptions[0].attemptTimeoutMs, 4_000); + assert.equal(readOptions[0].maxAttempts, GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS); + assert.equal(GITHUB_RELEASE_SNAPSHOT_MAX_READ_ATTEMPTS, 1); +}); + +test('promotion uses one bounded precondition snapshot and does not wait before mutation', async () => { + const selected = selection(1); + const headRef = 'd'.repeat(40); + let releaseListReads = 0; + let promotionMutations = 0; + let sleeps = 0; + + await assert.rejects( + async () => + await reconcileSelectedReleases( + { + budget: budget(), + command: 'promote', + environment: {}, + expectedState: 'public', + headRef, + repo: 'o/r', + selected, + }, + { + mutatePromotion: () => { + promotionMutations += 1; + }, + readReleaseMap: () => { + releaseListReads += 1; + return new Map(); + }, + readTagMap: () => tagState(selected, headRef), + releaseSnapshotSleep: () => { + sleeps += 1; + }, + }, + ), + /does not exist/u, + ); + + assert.equal(releaseListReads, 1); + assert.equal(promotionMutations, 0); + assert.equal(sleeps, 0); +}); + +test('promotion mutation and tag snapshot transports use their conservative sub-bounds', async () => { + const selected = selection(1); + const headRef = 'd'.repeat(40); + const releases = releaseState(selected); + const observedMutationTimeouts = []; + const observedTagTimeouts = []; + + await reconcileSelectedReleases( + { + budget: budget(), + command: 'promote', + environment: {}, + expectedState: 'public', + headRef, + repo: 'o/r', + selected, + }, + { + mutatePromotion: ({ metadata, timeoutMs }) => { + observedMutationTimeouts.push(timeoutMs); + const promoted = { ...releases.get(metadata.tag_name), draft: false }; + releases.set(metadata.tag_name, promoted); + return JSON.stringify(promoted); + }, + readReleaseMap: () => new Map(releases), + readTagMap: (_repo, _selected, options) => { + observedTagTimeouts.push(options?.timeoutMs); + return tagState(selected, headRef); + }, + }, + ); + + assert.deepEqual(observedMutationTimeouts, [GITHUB_RELEASE_PROMOTION_MUTATION_TIMEOUT_MS]); + assert.deepEqual(observedTagTimeouts, [ + GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS, + GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS, + ]); + assert.equal(GITHUB_RELEASE_PROMOTION_TAG_SNAPSHOT_TIMEOUT_MS, 30_000); +}); + +test('verification waits for a semantically complete release snapshot without mutation', async () => { + const selected = selection(2); + const headRef = 'd'.repeat(40); + const releases = releaseState(selected); + const tags = tagState(selected, headRef); + const sleeps = []; + let releaseListReads = 0; + + await reconcileSelectedReleases( + { + budget: budget(), + command: 'verify', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }, + { + readReleaseMap: () => { + releaseListReads += 1; + if (releaseListReads <= 2) { + return new Map([...releases].filter(([tag]) => tag !== selected.at(-1).tag)); + } + return new Map(releases); + }, + readTagMap: () => new Map(tags), + releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), + }, + ); + + assert.equal(releaseListReads, 3); + assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 2)); +}); + +test('promotion waits for stale draft rows to become public without replaying PATCH', async () => { + const selected = selection(2); + const headRef = 'd'.repeat(40); + const tags = tagState(selected, headRef); + const releases = releaseState(selected); + const mutations = []; + const sleeps = []; + let releaseListReads = 0; + const dependencies = { + mutationOptions, + mutatePromotion: ({ expectedId, metadata }) => { + const release = releases.get(metadata.tag_name); + assert.equal(release.id, expectedId); + mutations.push(metadata.tag_name); + const promoted = { ...release, draft: false }; + releases.set(metadata.tag_name, promoted); + return JSON.stringify(promoted); + }, + readReleaseMap: () => { + releaseListReads += 1; + if (releaseListReads === 1 || releaseListReads >= 4) return new Map(releases); + const stale = new Map(releases); + const finalTag = selected.at(-1).tag; + stale.set(finalTag, { ...stale.get(finalTag), draft: true }); + return stale; + }, + readTagMap: () => new Map(tags), + releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), + }; + + await reconcileSelectedReleases( + { + budget: budget(), + command: 'promote', + environment: {}, + expectedState: 'public', + headRef, + repo: 'o/r', + selected, + }, + dependencies, + ); + + assert.deepEqual( + mutations, + selected.map(({ tag }) => tag), + ); + assert.equal(releaseListReads, 4); + assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.slice(0, 2)); +}); + +test('promotion rejects a same-metadata release id replacement before lifecycle closure', async () => { + const selected = selection(1); + const headRef = 'd'.repeat(40); + const original = releaseState(selected); + const replacement = new Map([ + [selected[0].tag, { ...original.get(selected[0].tag), draft: false, id: 99 }], + ]); + let releaseListReads = 0; + let promotionMutations = 0; + let sleeps = 0; + + await assert.rejects( + async () => + await reconcileSelectedReleases( + { + budget: budget(), + command: 'promote', + environment: {}, + expectedState: 'public', + headRef, + repo: 'o/r', + selected, + }, + { + mutatePromotion: ({ expectedId, metadata }) => { + promotionMutations += 1; + return JSON.stringify({ + ...original.get(metadata.tag_name), + draft: false, + id: expectedId, + }); + }, + readReleaseMap: () => { + releaseListReads += 1; + return releaseListReads === 1 ? new Map(original) : new Map(replacement); + }, + readTagMap: () => tagState(selected, headRef), + releaseSnapshotSleep: () => { + sleeps += 1; + }, + }, + ), + /release id changed from 1 to 99/u, + ); + + assert.equal(releaseListReads, 2); + assert.equal(promotionMutations, 1); + assert.equal(sleeps, 0); +}); + +test('required release snapshots fail boundedly when state never becomes visible', async () => { + const selected = selection(1); + const sleeps = []; + let releaseListReads = 0; + await assert.rejects( + async () => + await reconcileSelectedReleases( + { + budget: budget(), + command: 'verify', + environment: {}, + expectedState: 'staged', + headRef: 'd'.repeat(40), + repo: 'o/r', + selected, + }, + { + readReleaseMap: () => { + releaseListReads += 1; + return new Map(); + }, + readTagMap: () => tagState(selected, 'd'.repeat(40)), + releaseSnapshotSleep: (milliseconds) => sleeps.push(milliseconds), + }, + ), + new RegExp(`did not converge to staged state.*${selected[0].tag} \\(missing\\)`, 'u'), + ); + assert.equal(releaseListReads, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS.length + 1); + assert.deepEqual(sleeps, GITHUB_RELEASE_SNAPSHOT_VISIBILITY_DELAYS_MS); +}); + +test('required release snapshots reject conflicting metadata without waiting', async () => { + const selected = selection(1); + let sleeps = 0; + await assert.rejects( + async () => + await reconcileSelectedReleases( + { + budget: budget(), + command: 'verify', + environment: {}, + expectedState: 'staged', + headRef: 'd'.repeat(40), + repo: 'o/r', + selected, + }, + { + readReleaseMap: () => + new Map([ + [selected[0].tag, { ...selected[0].metadata, body: 'conflict', draft: true, id: 1 }], + ]), + readTagMap: () => tagState(selected, 'd'.repeat(40)), + releaseSnapshotSleep: () => { + sleeps += 1; + }, + }, + ), + /conflicts with frozen release metadata/u, + ); + assert.equal(sleeps, 0); + + await assert.rejects( + async () => + await reconcileSelectedReleases( + { + budget: budget(), + command: 'verify', + environment: {}, + expectedState: 'staged', + headRef: 'd'.repeat(40), + repo: 'o/r', + selected, + }, + { + readReleaseMap: () => { + const observedRelease = { + ...selected[0].metadata, + body: 'conflict', + draft: true, + id: 1, + }; + throw new GitHubReleaseSnapshotRaceError('duplicate across pages', { observedRelease }); + }, + readTagMap: () => tagState(selected, 'd'.repeat(40)), + releaseSnapshotSleep: () => { + sleeps += 1; + }, + }, + ), + /conflicts with frozen release metadata/u, + ); + assert.equal(sleeps, 0); +}); + +test('batch staging reconciles ambiguous responses once and exact reruns issue no mutations', async () => { + const selected = selection(1); + const headRef = 'd'.repeat(40); + const tag = selected[0].tag; + const metadata = selected[0].metadata; + const tags = new Map([[tag, null]]); + let releases = new Map(); + let tagMutations = 0; + let releaseMutations = 0; + const dependencies = { + mutationOptions, + mutateRelease: () => { + releaseMutations += 1; + releases.set(tag, { ...metadata, draft: true, id: 1 }); + throw new Error('response lost after draft creation'); + }, + mutateTag: () => { + tagMutations += 1; + tags.set(tag, { ref: `refs/tags/${tag}`, sha: headRef, type: 'commit' }); + throw new Error('response lost after tag creation'); + }, + readRelease: (value) => releases.get(value) ?? null, + readReleaseMap: () => new Map(releases), + readTagMap: () => new Map(tags), + readTagRef: (value) => tags.get(value) ?? null, + }; + const context = { + budget: budget(), + command: 'stage', + environment: {}, + expectedState: 'staged', + headRef, + repo: 'o/r', + selected, + }; + await reconcileSelectedReleases(context, dependencies); + assert.equal(tagMutations, 1); + assert.equal(releaseMutations, 1); + + await reconcileSelectedReleases(context, dependencies); + assert.equal(tagMutations, 1, 'an exact rerun does not replay tag creation'); + assert.equal(releaseMutations, 1, 'an exact rerun does not replay release creation'); +}); diff --git a/tools/release/maven-artifact-manifest-publication-lock.test.mjs b/tools/release/maven-artifact-manifest-publication-lock.test.mjs deleted file mode 100644 index 2639a80f7..000000000 --- a/tools/release/maven-artifact-manifest-publication-lock.test.mjs +++ /dev/null @@ -1,263 +0,0 @@ -import { afterEach, expect, test } from "bun:test"; -import { chmodSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { execFileSync, spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { stageExtensionUpstreamLicenses } from "./extension-upstream-licenses.mjs"; -import { canonicalGzipSync } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { discoverPublicationArtifacts } from "./publication-lock.mjs"; -import { - currentProductVersionSync, - extensionReleaseVersion, -} from "./release-artifact-targets.mjs"; -import { ROOT } from "./release-graph.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; - -const temporaryRoots = []; - -afterEach(() => { - for (const root of temporaryRoots.splice(0)) { - rmSync(root, { recursive: true, force: true }); - } -}); - -function temporaryDirectory() { - const directory = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-maven-manifest-lock-")); - temporaryRoots.push(directory); - return directory; -} - -function run(script, args) { - const result = spawnSync(process.execPath, [script, ...args], { - cwd: ROOT, - encoding: "utf8", - env: process.env, - }); - expect( - result.status, - `${script} failed\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`, - ).toBe(0); -} - -function contribAndroidBundle(root, target, { archiveRoot } = {}) { - const product = "oliphaunt-extension-contrib-pg18"; - const version = extensionReleaseVersion(product, "native"); - const canonicalRoot = `${product}-${version}-native-${target}-bundle`; - const stage = path.join(root, "bundle-stage", target); - const output = path.join(root, "liboliphaunt-native", product, "release-assets", `${canonicalRoot}.tar.gz`); - mkdirSync(stage, { recursive: true }); - mkdirSync(path.dirname(output), { recursive: true }); - stageReleaseNotices(stage, { profile: "contrib-native-openssl" }); - writeFileSync(path.join(stage, "bundle-manifest.json"), "{}\n"); - writeFileSync(output, canonicalGzipSync(createDeterministicTar(stage, archiveRoot ?? canonicalRoot, { - fail(message) { - throw new Error(message); - }, - fixedFileMode: 0o644, - }))); - return output; -} - -function singletonAndroidRuntime(root, target, { mutateUpstream = false, upstreamRoot = "files" } = {}) { - const product = "oliphaunt-extension-pg-hashids"; - const version = currentProductVersionSync(product); - const name = `${product}-${version}-native-${target}-runtime.tar.gz`; - const stage = path.join(root, "singleton-stage", target); - const output = path.join(root, product, "release-assets", name); - rmSync(stage, { recursive: true, force: true }); - mkdirSync(stage, { recursive: true }); - chmodSync(stage, 0o755); - mkdirSync(path.dirname(output), { recursive: true }); - stageReleaseNotices(stage, { profile: "external-native" }); - if (upstreamRoot !== null) { - const staged = stageExtensionUpstreamLicenses("pg_hashids", path.join(stage, upstreamRoot)); - for (const directory of [ - upstreamRoot, - `${upstreamRoot}/share`, - `${upstreamRoot}/share/licenses`, - `${upstreamRoot}/share/licenses/pg_hashids`, - ]) chmodSync(path.join(stage, directory), 0o755); - if (mutateUpstream) { - writeFileSync(path.join(stage, upstreamRoot, staged[0]), "substituted upstream license\n"); - } - } - writeFileSync(path.join(stage, "manifest.properties"), "packageLayout=fixture\n"); - execFileSync("tar", ["--format=ustar", "-czf", output, "-C", stage, "."]); - return output; -} - -test("the real Maven manifest builder feeds the canonical ten-field schema into publication locking", { - timeout: 30_000, -}, () => { - const root = temporaryDirectory(); - const assets = path.join(root, "assets"); - const manifestDirectory = path.join(root, "maven-artifacts"); - const manifest = path.join(manifestDirectory, "runtime.tsv"); - const version = currentProductVersionSync("liboliphaunt-native"); - mkdirSync(manifestDirectory, { recursive: true }); - - run("tools/test/create-liboliphaunt-release-fixture.mjs", [ - "--asset-dir", - assets, - "--version", - version, - ]); - run("tools/release/build_maven_artifact_manifest.mjs", [ - "--output", - manifest, - "--runtime", - "--runtime-asset-root", - assets, - ]); - - const original = readFileSync(manifest, "utf8"); - const rows = original.trimEnd().split("\n"); - expect(rows).toHaveLength(4); - expect(rows.every((row) => row.split("\t").length === 10)).toBe(true); - - const records = discoverPublicationArtifacts([manifest]); - expect(records.map(({ name }) => name).sort()).toEqual([ - "dev.oliphaunt.runtime:liboliphaunt-android-arm64-v8a", - "dev.oliphaunt.runtime:liboliphaunt-android-x86_64", - "dev.oliphaunt.runtime:liboliphaunt-runtime-resources-android-datum64", - "dev.oliphaunt.runtime:oliphaunt-icu", - ]); - expect(records.every((record) => - record.version === version - && record.artifacts.length === 1 - && record.artifacts[0].path.endsWith(".tar.gz") - && record.artifacts[0].sha256.length === 64)).toBe(true); - - const first = rows[0].split("\t"); - const mutations = [ - ["legacy field count", first.slice(0, 8), /ten Maven publication fields/u], - ["missing display name", first.with(4, ""), /display name/u], - ["half runtime binding", first.with(6, "liboliphaunt-native"), /both runtime product and version/u], - ["missing SPDX expression", first.with(8, ""), /SPDX expression/u], - ["non-array licenses", first.with(9, "{}"), /non-empty JSON array/u], - [ - "non-canonical license entry", - first.with(9, JSON.stringify([{ name: "MIT", url: "https://example.invalid/MIT", distribution: "repo", extra: true }])), - /must contain exactly name, url, distribution/u, - ], - [ - "insecure license URL", - first.with(9, JSON.stringify([{ name: "MIT", url: "http://example.invalid/MIT", distribution: "repo" }])), - /must use HTTPS/u, - ], - ]; - for (const [label, mutated, pattern] of mutations) { - writeFileSync(manifest, `${mutated.join("\t")}\n${rows.slice(1).join("\n")}\n`); - expect(() => discoverPublicationArtifacts([manifest]), label).toThrow(pattern); - } -}); - -test("the Maven manifest builder validates notices beneath an exact bundle archive root", { - timeout: 30_000, -}, () => { - const root = temporaryDirectory(); - const manifest = path.join(root, "maven-artifacts", "contrib.tsv"); - for (const target of ["android-arm64-v8a", "android-x86_64"]) { - contribAndroidBundle(root, target); - } - - run("tools/release/build_maven_artifact_manifest.mjs", [ - "--output", - manifest, - "--extensions", - "--extension-product", - "oliphaunt-extension-contrib-pg18", - "--extension-artifact-root", - root, - ]); - const contribRows = readFileSync(manifest, "utf8").trimEnd().split("\n"); - expect(contribRows).toHaveLength(2); - const nativeVersion = currentProductVersionSync("liboliphaunt-native"); - expect(contribRows.map((row) => row.split("\t").slice(0, 8))).toEqual([ - [ - "dev.oliphaunt.extensions", - "oliphaunt-extension-contrib-pg18-android-arm64-v8a", - nativeVersion, - expect.any(String), - expect.any(String), - expect.any(String), - "liboliphaunt-native", - nativeVersion, - ], - [ - "dev.oliphaunt.extensions", - "oliphaunt-extension-contrib-pg18-android-x86_64", - nativeVersion, - expect.any(String), - expect.any(String), - expect.any(String), - "liboliphaunt-native", - nativeVersion, - ], - ]); - - contribAndroidBundle(root, "android-arm64-v8a", { archiveRoot: "substituted-root" }); - const result = spawnSync(process.execPath, [ - "tools/release/build_maven_artifact_manifest.mjs", - "--output", - manifest, - "--extensions", - "--extension-product", - "oliphaunt-extension-contrib-pg18", - "--extension-artifact-root", - root, - ], { - cwd: ROOT, - encoding: "utf8", - env: process.env, - }); - expect(result.status).not.toBe(0); - expect(`${result.stdout}\n${result.stderr}`).toMatch(/canonical single archive root/u); -}); - -test("the Maven manifest builder validates singleton upstream licenses in the runtime files namespace", { - timeout: 30_000, -}, () => { - const root = temporaryDirectory(); - const manifest = path.join(root, "maven-artifacts", "pg-hashids.tsv"); - for (const target of ["android-arm64-v8a", "android-x86_64"]) { - singletonAndroidRuntime(root, target); - } - - run("tools/release/build_maven_artifact_manifest.mjs", [ - "--output", - manifest, - "--extensions", - "--extension-product", - "oliphaunt-extension-pg-hashids", - "--extension-artifact-root", - root, - ]); - expect(readFileSync(manifest, "utf8").trimEnd().split("\n")).toHaveLength(2); - - for (const [label, options, pattern] of [ - ["missing files namespace", { upstreamRoot: null }, /packed upstream license members differ/u], - ["substituted files namespace", { upstreamRoot: "substituted-files" }, /packed upstream license members differ/u], - ["substituted upstream bytes", { mutateUpstream: true }, /packed upstream license bytes changed/u], - ]) { - singletonAndroidRuntime(root, "android-arm64-v8a", options); - const result = spawnSync(process.execPath, [ - "tools/release/build_maven_artifact_manifest.mjs", - "--output", - manifest, - "--extensions", - "--extension-product", - "oliphaunt-extension-pg-hashids", - "--extension-artifact-root", - root, - ], { - cwd: ROOT, - encoding: "utf8", - env: process.env, - }); - expect(result.status, label).not.toBe(0); - expect(`${result.stdout}\n${result.stderr}`, label).toMatch(pattern); - } -}); diff --git a/tools/release/maven-artifact-staging.mjs b/tools/release/maven-artifact-staging.mjs deleted file mode 100644 index b5df3b5c0..000000000 --- a/tools/release/maven-artifact-staging.mjs +++ /dev/null @@ -1,334 +0,0 @@ -#!/usr/bin/env bun - -import { - chmodSync, - copyFileSync, - existsSync, - lstatSync, - mkdirSync, - readFileSync, - readdirSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { createDeterministicZip } from "../../src/shared/artifact-packaging/archive-directory.mjs"; -import { - createSiblingStage, - promoteDirectory, - removeTemporaryPath, -} from "./atomic-directory.mjs"; -import { validateMavenCentralPublication } from "./maven-central-contract.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const TOOL = "maven-artifact-staging.mjs"; -const TOKEN = /^[A-Za-z0-9_.-]+$/u; -const GROUP_SEGMENT = /^[A-Za-z0-9_-]+$/u; -const CONTROL = /[\u0000-\u001f\u007f]/u; -const MANIFEST = "Manifest-Version: 1.0\r\n\r\n"; - -function error(message) { - return new Error(`${TOOL}: ${message}`); -} - -function relative(file) { - const value = path.relative(ROOT, file); - return value.startsWith("..") || path.isAbsolute(value) - ? file.split(path.sep).join("/") - : value.split(path.sep).join("/"); -} - -function requiredText(value, label) { - if (typeof value !== "string" || value.length === 0 || CONTROL.test(value)) { - throw error(`${label} must be non-empty text without control characters`); - } - return value; -} - -function token(value, label) { - requiredText(value, label); - if (!TOKEN.test(value) || value === "." || value === "..") { - throw error(`${label} must be a portable non-dot Maven coordinate token`); - } - return value; -} - -function mavenGroupId(value, label) { - requiredText(value, label); - const segments = value.split("."); - if (segments.some((segment) => !GROUP_SEGMENT.test(segment))) { - throw error(`${label} must contain non-empty dot-separated portable Maven coordinate segments`); - } - return value; -} - -function xml(value) { - return String(value) - .replaceAll("&", "&") - .replaceAll("<", "<") - .replaceAll(">", ">") - .replaceAll('"', """) - .replaceAll("'", "'"); -} - -function parseLicenses(raw, label) { - let value; - try { - value = JSON.parse(raw); - } catch (cause) { - throw error(`${label} must be valid JSON: ${cause.message}`); - } - if (!Array.isArray(value) || value.length === 0) { - throw error(`${label} must be a non-empty JSON array`); - } - for (const [index, license] of value.entries()) { - const entry = `${label} entry ${index + 1}`; - if ( - license === null - || Array.isArray(license) - || typeof license !== "object" - || JSON.stringify(Object.keys(license)) !== JSON.stringify(["name", "url", "distribution"]) - ) { - throw error(`${entry} must contain exactly name, url, distribution in canonical order`); - } - requiredText(license.name, `${entry}.name`); - const url = requiredText(license.url, `${entry}.url`); - if (!url.startsWith("https://")) throw error(`${entry}.url must use HTTPS`); - if (license.distribution !== "repo") throw error(`${entry}.distribution must be repo`); - } - if (raw !== JSON.stringify(value)) { - throw error(`${label} must use canonical compact JSON`); - } - return value; -} - -function requireArtifact(file, label) { - let metadata; - try { - metadata = lstatSync(file); - } catch (cause) { - throw error(`${label} is missing: ${cause.message}`); - } - if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) { - throw error(`${label} must be a non-empty regular non-symlink file`); - } -} - -export function parseMavenArtifactManifest(file) { - requireArtifact(file, `${relative(file)} Maven artifact manifest`); - const rows = readFileSync(file, "utf8").split(/\r?\n/u).filter((line) => line.length > 0); - if (rows.length === 0) throw error(`${relative(file)} Maven artifact manifest is empty`); - const coordinates = new Set(); - return rows.map((line, index) => { - const label = `${relative(file)} line ${index + 1}`; - const fields = line.split("\t"); - if (fields.length !== 10) throw error(`${label} must contain exactly ten tab-separated fields`); - const [ - groupId, - artifactId, - version, - rawArtifact, - name, - description, - runtimeProduct, - runtimeVersion, - licenseSpdx, - licensesJson, - ] = fields; - mavenGroupId(groupId, `${label} groupId`); - token(artifactId, `${label} artifactId`); - token(version, `${label} version`); - const coordinate = `${groupId}:${artifactId}:${version}`; - if (coordinates.has(coordinate)) throw error(`${label} repeats Maven coordinate ${coordinate}`); - coordinates.add(coordinate); - requiredText(rawArtifact, `${label} artifact path`); - if (!rawArtifact.endsWith(".tar.gz")) throw error(`${label} artifact must be a .tar.gz payload`); - const artifact = path.isAbsolute(rawArtifact) ? rawArtifact : path.resolve(ROOT, rawArtifact); - requireArtifact(artifact, `${label} artifact ${relative(artifact)}`); - requiredText(name, `${label} name`); - requiredText(description, `${label} description`); - if ((runtimeProduct.length === 0) !== (runtimeVersion.length === 0)) { - throw error(`${label} must declare both runtime product and version or neither`); - } - if (runtimeProduct.length > 0) { - token(runtimeProduct, `${label} runtime product`); - token(runtimeVersion, `${label} runtime version`); - } - requiredText(licenseSpdx, `${label} SPDX expression`); - const licenses = parseLicenses(licensesJson, `${label} licenses`); - return Object.freeze({ - artifact, - artifactId, - description, - groupId, - licenses, - licenseSpdx, - name, - runtimeProduct: runtimeProduct || null, - runtimeVersion: runtimeVersion || null, - version, - }); - }); -} - -export function renderMavenArtifactPom(row) { - const licenses = row.licenses.map((license) => ` - ${xml(license.name)} - ${xml(license.url)} - ${xml(license.distribution)} - `).join("\n"); - const runtimeProperties = row.runtimeProduct === null ? "" : ` - ${xml(row.runtimeProduct)} - ${xml(row.runtimeVersion)}`; - return ` - - 4.0.0 - ${xml(row.groupId)} - ${xml(row.artifactId)} - ${xml(row.version)} - tar.gz - ${xml(row.name)} - ${xml(row.description)} - https://github.com/f0rr0/oliphaunt - 2026 - -${licenses} - - - - f0rr0 - Oliphaunt Maintainers - https://github.com/f0rr0 - - - - scm:git:https://github.com/f0rr0/oliphaunt.git - scm:git:ssh://git@github.com:f0rr0/oliphaunt.git - https://github.com/f0rr0/oliphaunt - - ${runtimeProperties} - ${xml(row.licenseSpdx)} - - -`; -} - -function exactFiles(directory, expected, label) { - const actual = readdirSync(directory, { withFileTypes: true }); - if (actual.some((entry) => !entry.isFile() || entry.isSymbolicLink())) { - throw error(`${label} must contain only regular files`); - } - const names = actual.map((entry) => entry.name).sort(); - const wanted = [...expected].sort(); - if (JSON.stringify(names) !== JSON.stringify(wanted)) { - throw error(`${label} file closure differs: expected ${JSON.stringify(wanted)}, got ${JSON.stringify(names)}`); - } - return names; -} - -async function writeCompanionJar(stageRoot, row, classifier) { - const coordinate = `${row.groupId}:${row.artifactId}:${row.version}`; - const root = path.join(stageRoot, `${classifier}-stage`); - mkdirSync(path.join(root, "META-INF"), { recursive: true }); - stageReleaseNotices(path.join(root, "META-INF"), { profile: "source-sdk" }); - writeFileSync(path.join(root, "META-INF/MANIFEST.MF"), MANIFEST, { mode: 0o644 }); - if (classifier === "sources") { - writeFileSync( - path.join(root, "README.md"), - `# ${coordinate}\n\nThis binary carrier has no source API. See https://github.com/f0rr0/oliphaunt.\n`, - { mode: 0o644 }, - ); - } else { - writeFileSync( - path.join(root, "index.html"), - `${xml(coordinate)}

This binary carrier has no Java API.

\n`, - { mode: 0o644 }, - ); - } - return createDeterministicZip(root); -} - -/** - * Materialize the immutable, unsigned Maven Central input closure without - * Gradle, Java, registry access, credentials, or dependency resolution. - */ -export async function stageMavenArtifactManifest(manifest, outputRoot) { - const rows = parseMavenArtifactManifest(path.resolve(manifest)); - const destination = path.resolve(outputRoot); - const stage = createSiblingStage(destination, "maven-artifacts"); - try { - const staged = []; - for (const row of rows) { - const directory = path.join(stage, ...row.groupId.split("."), row.artifactId, row.version); - const prefix = `${row.artifactId}-${row.version}`; - mkdirSync(directory, { recursive: true }); - const primary = path.join(directory, `${prefix}.tar.gz`); - const pom = path.join(directory, `${prefix}.pom`); - const sources = path.join(directory, `${prefix}-sources.jar`); - const javadoc = path.join(directory, `${prefix}-javadoc.jar`); - copyFileSync(row.artifact, primary); - chmodSync(primary, 0o644); - writeFileSync(pom, renderMavenArtifactPom(row), { mode: 0o644 }); - const companionRoot = path.join(stage, ".companion-stage", row.artifactId, row.version); - writeFileSync(sources, await writeCompanionJar(companionRoot, row, "sources"), { mode: 0o644 }); - writeFileSync(javadoc, await writeCompanionJar(companionRoot, row, "javadoc"), { mode: 0o644 }); - rmSync(companionRoot, { recursive: true, force: true }); - const files = exactFiles(directory, [ - path.basename(javadoc), - path.basename(pom), - path.basename(sources), - path.basename(primary), - ], `${row.groupId}:${row.artifactId}:${row.version}`); - const publication = validateMavenCentralPublication({ - context: `${row.groupId}:${row.artifactId}:${row.version}`, - files: files.map((name) => ({ name, size: statSync(path.join(directory, name)).size })), - pomText: readFileSync(pom, "utf8"), - }); - staged.push(Object.freeze({ - ...publication, - directory: path.join(destination, ...row.groupId.split("."), row.artifactId, row.version), - files: Object.freeze(files), - })); - } - rmSync(path.join(stage, ".companion-stage"), { recursive: true, force: true }); - promoteDirectory(stage, destination); - return Object.freeze(staged); - } catch (cause) { - if (existsSync(stage)) removeTemporaryPath(stage); - throw cause; - } -} - -function parseArgs(argv) { - let manifest = null; - let output = null; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--manifest") { - manifest = argv[++index] ?? null; - } else if (arg === "--output") { - output = argv[++index] ?? null; - } else { - throw error(`unknown argument ${JSON.stringify(arg)}`); - } - } - if (manifest === null || output === null) { - throw error("usage: maven-artifact-staging.mjs --manifest FILE --output DIRECTORY"); - } - return { manifest, output }; -} - -if (import.meta.main) { - try { - const args = parseArgs(Bun.argv.slice(2)); - const staged = await stageMavenArtifactManifest(args.manifest, args.output); - console.log(`Staged and validated ${staged.length} local Maven Central carrier(s) under ${relative(args.output)}.`); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/maven-artifact-staging.test.mjs b/tools/release/maven-artifact-staging.test.mjs deleted file mode 100644 index bc12ffe9c..000000000 --- a/tools/release/maven-artifact-staging.test.mjs +++ /dev/null @@ -1,229 +0,0 @@ -import { afterEach, expect, test } from "bun:test"; -import { - createHash, -} from "node:crypto"; -import { - lstatSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { preflightMavenCentralBundle } from "./preflight-maven-central-bundle.mjs"; -import { - parseMavenArtifactManifest, - stageMavenArtifactManifest, -} from "./maven-artifact-staging.mjs"; -import { validateMavenCentralPublication } from "./maven-central-contract.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -const roots = []; -const ROOT = path.resolve(import.meta.dir, "../.."); - -afterEach(() => { - for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); -}); - -function fixture() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-maven-carrier-")); - roots.push(root); - const artifact = path.join(root, "runtime.tar.gz"); - const manifest = path.join(root, "manifest.tsv"); - const output = path.join(root, "maven"); - writeFileSync(artifact, "exact runtime carrier\n"); - const licenses = [{ - name: "MIT & PostgreSQL", - url: "https://example.invalid/license?a=1&b=2", - distribution: "repo", - }]; - writeFileSync(manifest, [ - "dev.oliphaunt.extensions", - "oliphaunt-extension-example-android-arm64-v8a", - "1.2.3", - artifact, - "Oliphaunt ", - "Exact extension & runtime carrier.", - "liboliphaunt-native", - "4.5.6", - "MIT AND PostgreSQL", - JSON.stringify(licenses), - ].join("\t") + "\n"); - return { artifact, manifest, output, root }; -} - -function digest(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function files(directory) { - return readdirSync(directory).sort().map((name) => path.join(directory, name)); -} - -test("stages a deterministic exact Maven Central carrier closure without Gradle", async () => { - const value = fixture(); - const first = await stageMavenArtifactManifest(value.manifest, value.output); - expect(first).toHaveLength(1); - const directory = first[0].directory; - const stagedFiles = files(directory); - expect(stagedFiles.map((file) => path.basename(file))).toEqual([ - "oliphaunt-extension-example-android-arm64-v8a-1.2.3-javadoc.jar", - "oliphaunt-extension-example-android-arm64-v8a-1.2.3-sources.jar", - "oliphaunt-extension-example-android-arm64-v8a-1.2.3.pom", - "oliphaunt-extension-example-android-arm64-v8a-1.2.3.tar.gz", - ]); - expect(readFileSync(stagedFiles.find((file) => file.endsWith(".tar.gz")), "utf8")) - .toBe("exact runtime carrier\n"); - - const pom = stagedFiles.find((file) => file.endsWith(".pom")); - expect(readFileSync(pom, "utf8")).toContain("Oliphaunt <example>"); - expect(readFileSync(pom, "utf8")).toContain("MIT & PostgreSQL"); - expect(validateMavenCentralPublication({ - context: "fixture", - files: stagedFiles.map((file) => ({ name: path.basename(file), size: lstatSync(file).size })), - pomText: readFileSync(pom, "utf8"), - })).toEqual({ - artifactId: "oliphaunt-extension-example-android-arm64-v8a", - groupId: "dev.oliphaunt.extensions", - packaging: "tar.gz", - version: "1.2.3", - }); - - for (const jar of stagedFiles.filter((file) => file.endsWith(".jar"))) { - const entries = readPortableArchiveEntries(jar); - expect(entries.has("META-INF/MANIFEST.MF")).toBe(true); - expect(entries.has("META-INF/LICENSE")).toBe(true); - expect(entries.has("META-INF/THIRD_PARTY_NOTICES.md")).toBe(true); - expect([...entries.values()].every((entry) => entry.isSymbolicLink === false)).toBe(true); - } - - const firstDigests = Object.fromEntries(stagedFiles.map((file) => [path.basename(file), digest(file)])); - await stageMavenArtifactManifest(value.manifest, value.output); - expect(Object.fromEntries(files(directory).map((file) => [path.basename(file), digest(file)]))) - .toEqual(firstDigests); -}); - -test("rejects duplicate coordinates, malformed licenses, missing artifacts, and symlinks", () => { - const value = fixture(); - const row = readFileSync(value.manifest, "utf8"); - writeFileSync(value.manifest, row + row); - expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/repeats Maven coordinate/u); - - const fields = row.trimEnd().split("\t"); - writeFileSync(value.manifest, `${fields.with(9, "{}").join("\t")}\n`); - expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/non-empty JSON array/u); - - writeFileSync(value.manifest, `${fields.with(3, path.join(value.root, "missing.tar.gz")).join("\t")}\n`); - expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/is missing/u); - - const link = path.join(value.root, "linked.tar.gz"); - symlinkSync(value.artifact, link); - writeFileSync(value.manifest, `${fields.with(3, link).join("\t")}\n`); - expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/non-symlink/u); -}); - -test("rejects coordinate dot segments before staging any path", async () => { - const value = fixture(); - const fields = readFileSync(value.manifest, "utf8").trimEnd().split("\t"); - for (const [field, invalid] of [ - [0, "."], - [0, ".."], - [0, ".dev.oliphaunt"], - [0, "dev..oliphaunt"], - [0, "dev.oliphaunt."], - [1, "."], - [1, ".."], - [2, "."], - [2, ".."], - ]) { - writeFileSync(value.manifest, `${fields.with(field, invalid).join("\t")}\n`); - expect(() => parseMavenArtifactManifest(value.manifest)).toThrow(/non-dot|dot-separated/u); - await expect(stageMavenArtifactManifest(value.manifest, value.output)).rejects.toThrow(/non-dot|dot-separated/u); - } - expect(() => lstatSync(value.output)).toThrow(); -}); - -test("failed staging leaves the last complete output untouched", async () => { - const value = fixture(); - await stageMavenArtifactManifest(value.manifest, value.output); - const marker = path.join(value.output, "complete.marker"); - writeFileSync(marker, "keep\n"); - const fields = readFileSync(value.manifest, "utf8").trimEnd().split("\t"); - writeFileSync(value.manifest, `${fields.with(3, path.join(value.root, "missing.tar.gz")).join("\t")}\n`); - await expect(stageMavenArtifactManifest(value.manifest, value.output)).rejects.toThrow(/is missing/u); - expect(readFileSync(marker, "utf8")).toBe("keep\n"); -}); - -test("the release preflight freezes and bundles the exact locally staged Maven bytes", async () => { - const root = mkdtempSync(path.join(ROOT, "target/maven-artifact-publication-preflight-")); - roots.push(root); - const artifact = path.join(root, "runtime.tar.gz"); - const manifest = path.join(root, "manifest.tsv"); - const output = path.join(root, "maven"); - writeFileSync(artifact, "exact frozen runtime carrier\n"); - writeFileSync(manifest, [ - "dev.oliphaunt.runtime", - "fixture-runtime", - "1.2.3", - path.relative(ROOT, artifact).split(path.sep).join("/"), - "Oliphaunt fixture runtime", - "Exact frozen publication-path fixture.", - "", - "", - "MIT", - JSON.stringify([{ - name: "MIT License (Oliphaunt)", - url: "https://github.com/f0rr0/oliphaunt/blob/fixture/LICENSE", - distribution: "repo", - }]), - ].join("\t") + "\n"); - const [coordinate] = await stageMavenArtifactManifest(manifest, output); - const stagedFiles = files(coordinate.directory); - const envelope = (file) => ({ - path: path.relative(ROOT, file).split(path.sep).join("/"), - sha256: digest(file), - size: lstatSync(file).size, - }); - const git = (ref) => { - const result = spawnSync("git", ["rev-parse", ref], { cwd: ROOT, encoding: "utf8" }); - expect(result.status).toBe(0); - return result.stdout.trim(); - }; - const releaseCommit = git("HEAD^{commit}"); - const lock = { - lockDigest: "a".repeat(64), - source: { commit: releaseCommit, tree: git("HEAD^{tree}") }, - carriers: [{ - artifacts: stagedFiles.map(envelope), - ecosystem: "maven", - id: "maven:dev.oliphaunt.runtime:fixture-runtime", - name: "dev.oliphaunt.runtime:fixture-runtime", - product: "fixture-product", - publishOrder: 0, - version: "1.2.3", - }], - }; - const result = preflightMavenCentralBundle({ - lock, - outputRoot: path.join(root, "preflight"), - products: ["fixture-product"], - releaseCommit, - signFile(file, signature) { - writeFileSync(signature, `fixture-signature:${digest(file)}\n`); - }, - }); - expect(result.payloads).toHaveLength(4); - for (const source of stagedFiles) { - const frozen = result.payloads.find(({ frozenPath }) => frozenPath === path.relative(ROOT, source).split(path.sep).join("/")); - expect(frozen).toBeDefined(); - expect(readFileSync(frozen.staged)).toEqual(readFileSync(source)); - expect(frozen.sha256).toBe(digest(source)); - } - expect(lstatSync(result.bundle).size).toBeGreaterThan(0); -}); diff --git a/tools/release/maven-central-auth.mjs b/tools/release/maven-central-auth.mjs deleted file mode 100644 index 0d15174ff..000000000 --- a/tools/release/maven-central-auth.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { Buffer } from "node:buffer"; - -export function mavenCentralAuthorization(username, password) { - if (typeof username !== "string" || username.length === 0) { - throw new TypeError("Maven Central username must be a non-empty string"); - } - if (typeof password !== "string" || password.length === 0) { - throw new TypeError("Maven Central password must be a non-empty string"); - } - return `Bearer ${Buffer.from(`${username}:${password}`, "utf8").toString("base64")}`; -} diff --git a/tools/release/maven-central-auth.mts b/tools/release/maven-central-auth.mts new file mode 100644 index 000000000..7636198b4 --- /dev/null +++ b/tools/release/maven-central-auth.mts @@ -0,0 +1,11 @@ +import { Buffer } from 'node:buffer'; + +export function mavenCentralAuthorization(username, password) { + if (typeof username !== 'string' || username.length === 0) { + throw new TypeError('Maven Central username must be a non-empty string'); + } + if (typeof password !== 'string' || password.length === 0) { + throw new TypeError('Maven Central password must be a non-empty string'); + } + return `Bearer ${Buffer.from(`${username}:${password}`, 'utf8').toString('base64')}`; +} diff --git a/tools/release/maven-central-auth.test.mjs b/tools/release/maven-central-auth.test.mjs deleted file mode 100644 index 6ef53a213..000000000 --- a/tools/release/maven-central-auth.test.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { mavenCentralAuthorization } from "./maven-central-auth.mjs"; - -describe("Maven Central Portal authorization", () => { - test("uses the Portal Bearer credential format", () => { - expect(mavenCentralAuthorization("publisher", "s3cr3t:with-colon")).toBe( - "Bearer cHVibGlzaGVyOnMzY3IzdDp3aXRoLWNvbG9u", - ); - }); - - test("rejects absent credentials instead of constructing an ambiguous header", () => { - expect(() => mavenCentralAuthorization("", "secret")).toThrow("username"); - expect(() => mavenCentralAuthorization("publisher", "")).toThrow("password"); - }); -}); diff --git a/tools/release/maven-central-auth.test.mts b/tools/release/maven-central-auth.test.mts new file mode 100644 index 000000000..b32e54039 --- /dev/null +++ b/tools/release/maven-central-auth.test.mts @@ -0,0 +1,16 @@ +import { describe, expect, test } from 'bun:test'; + +import { mavenCentralAuthorization } from './maven-central-auth.mts'; + +describe('Maven Central Portal authorization', () => { + test('uses the Portal Bearer credential format', () => { + expect(mavenCentralAuthorization('publisher', 's3cr3t:with-colon')).toBe( + 'Bearer cHVibGlzaGVyOnMzY3IzdDp3aXRoLWNvbG9u', + ); + }); + + test('rejects absent credentials instead of constructing an ambiguous header', () => { + expect(() => mavenCentralAuthorization('', 'secret')).toThrow('username'); + expect(() => mavenCentralAuthorization('publisher', '')).toThrow('password'); + }); +}); diff --git a/tools/release/maven-central-contract.mjs b/tools/release/maven-central-contract.mjs deleted file mode 100644 index 69fa341fc..000000000 --- a/tools/release/maven-central-contract.mjs +++ /dev/null @@ -1,156 +0,0 @@ -import path from "node:path"; - -function error(message) { - return new Error(`maven-central-contract: ${message}`); -} - -function xmlBlock(block, tag) { - const match = block.match(new RegExp(`<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)`, "u")); - return match?.[1] ?? null; -} - -function xmlText(block, tag) { - const inner = xmlBlock(block, tag); - if (inner === null) return null; - return inner - .replace(//gu, "$1") - .replace(/<[^>]+>/gu, "") - .replaceAll("<", "<") - .replaceAll(">", ">") - .replaceAll(""", "\"") - .replaceAll("'", "'") - .replaceAll("&", "&") - .trim(); -} - -function uniqueXmlText(block, tag, context, { required = true } = {}) { - const matches = [...block.matchAll(new RegExp(`<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)`, "gu"))]; - if (matches.length === 0 && !required) return null; - if (matches.length !== 1) { - throw error(`${context} must define exactly one <${tag}>, found ${matches.length}`); - } - return xmlText(matches[0][0], tag); -} - -function xmlBlocks(block, tag) { - return [...block.matchAll(new RegExp(`<${tag}(?:\\s[^>]*)?>([\\s\\S]*?)`, "gu"))] - .map((match) => match[1]); -} - -function requireText(block, tag, context) { - const value = xmlText(block, tag); - if (value === null || value.length === 0) { - throw error(`${context} must define a nonempty <${tag}>`); - } - return value; -} - -function requireSafeCoordinate(value, context) { - if (!/^[A-Za-z0-9_.-]+$/u.test(value)) { - throw error(`${context} is not a safe Maven coordinate segment: ${JSON.stringify(value)}`); - } - return value; -} - -function normalizedFiles(files, context) { - if (!Array.isArray(files) || files.length === 0) { - throw error(`${context} must provide the complete publication file set`); - } - const names = new Map(); - for (const entry of files) { - const name = typeof entry === "string" ? path.basename(entry) : path.basename(entry?.name ?? entry?.path ?? ""); - const size = typeof entry === "string" ? undefined : entry?.size; - if (name.length === 0 || name === "." || name === "..") { - throw error(`${context} contains an invalid publication filename`); - } - if (names.has(name)) { - throw error(`${context} contains duplicate publication filename ${name}`); - } - if (size !== undefined && (!Number.isSafeInteger(size) || size <= 0)) { - throw error(`${context} file ${name} must be nonempty`); - } - names.set(name, { name, size }); - } - return names; -} - -function requireMetadata(project, context) { - const header = project.replace( - /<(parent|dependencies|dependencyManagement|licenses|developers|scm|properties|build|profiles|repositories|distributionManagement)(?:\s[^>]*)?>[\s\S]*?<\/\1>/gu, - "", - ); - for (const tag of ["name", "description", "url"]) { - const value = uniqueXmlText(header, tag, context); - if (value === null || value.length === 0) throw error(`${context} must define a nonempty <${tag}>`); - } - - const licenses = xmlBlock(project, "licenses"); - if (licenses === null) throw error(`${context} must define `); - const validLicense = xmlBlocks(licenses, "license").some((license) => - (xmlText(license, "name")?.length ?? 0) > 0 && (xmlText(license, "url")?.length ?? 0) > 0 - ); - if (!validLicense) { - throw error(`${context} must define at least one license with nonempty name and url`); - } - - const developers = xmlBlock(project, "developers"); - if (developers === null) throw error(`${context} must define `); - const validDeveloper = xmlBlocks(developers, "developer").some((developer) => - (xmlText(developer, "name")?.length ?? 0) > 0 - && ((xmlText(developer, "email")?.length ?? 0) > 0 || (xmlText(developer, "url")?.length ?? 0) > 0) - ); - if (!validDeveloper) { - throw error(`${context} must define at least one developer with a nonempty name and email or url`); - } - - const scm = xmlBlock(project, "scm"); - if (scm === null) throw error(`${context} must define `); - for (const tag of ["connection", "developerConnection", "url"]) { - requireText(scm, tag, `${context} `); - } -} - -/** - * Validate the immutable files for one Maven Central coordinate before any - * signing, upload, or GitHub release mutation occurs. - */ -export function validateMavenCentralPublication({ pomText, files, context = "Maven publication" }) { - if (typeof pomText !== "string" || pomText.length === 0) { - throw error(`${context} POM must be nonempty UTF-8 text`); - } - if (/]*)?>([\s\S]*?)<\/project>/gu)]; - if (projectMatches.length !== 1) { - throw error(`${context} POM must contain exactly one document, found ${projectMatches.length}`); - } - const project = projectMatches[0][1]; - const coordinates = project.replace( - /<(parent|dependencies|dependencyManagement|properties|build|profiles|repositories|distributionManagement)(?:\s[^>]*)?>[\s\S]*?<\/\1>/gu, - "", - ); - const modelVersion = uniqueXmlText(coordinates, "modelVersion", context); - if (modelVersion !== "4.0.0") { - throw error(`${context} must use Maven modelVersion 4.0.0`); - } - const groupId = requireSafeCoordinate(uniqueXmlText(coordinates, "groupId", context), `${context} groupId`); - const artifactId = requireSafeCoordinate(uniqueXmlText(coordinates, "artifactId", context), `${context} artifactId`); - const version = requireSafeCoordinate(uniqueXmlText(coordinates, "version", context), `${context} version`); - const packaging = requireSafeCoordinate(uniqueXmlText(coordinates, "packaging", context, { required: false }) ?? "jar", `${context} packaging`); - requireMetadata(project, context); - - const names = normalizedFiles(files, context); - const prefix = `${artifactId}-${version}`; - const required = [`${prefix}.pom`]; - if (packaging !== "pom") { - required.push(`${prefix}.${packaging}`, `${prefix}-sources.jar`, `${prefix}-javadoc.jar`); - } - for (const name of required) { - if (!names.has(name)) { - throw error(`${context} (${groupId}:${artifactId}:${version}, packaging ${packaging}) is missing required file ${name}`); - } - } - - return { artifactId, groupId, packaging, version }; -} diff --git a/tools/release/maven-central-contract.test.mjs b/tools/release/maven-central-contract.test.mjs deleted file mode 100644 index 2b6121172..000000000 --- a/tools/release/maven-central-contract.test.mjs +++ /dev/null @@ -1,72 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { validateMavenCentralPublication } from "./maven-central-contract.mjs"; - -function pom({ packaging = "tar.gz", metadata = true } = {}) { - return ` - - 4.0.0 - dev.oliphaunt.extensions - vector-android-arm64 - 1.2.3 - ${packaging} - ${metadata ? `Oliphaunt vector Android arm64 - Exact native extension carrier. - https://github.com/f0rr0/oliphaunt - PostgreSQLhttps://opensource.org/license/postgresql - Oliphaunt Maintainershttps://github.com/f0rr0 - scm:git:https://github.com/f0rr0/oliphaunt.gitscm:git:ssh://git@github.com/f0rr0/oliphaunt.githttps://github.com/f0rr0/oliphaunt` : ""} -`; -} - -const complete = [ - { name: "vector-android-arm64-1.2.3.pom", size: 10 }, - { name: "vector-android-arm64-1.2.3.tar.gz", size: 20 }, - { name: "vector-android-arm64-1.2.3-sources.jar", size: 30 }, - { name: "vector-android-arm64-1.2.3-javadoc.jar", size: 40 }, -]; - -describe("Maven Central immutable publication contract", () => { - test("accepts complete non-jar coordinates with Central metadata and placeholders", () => { - expect(validateMavenCentralPublication({ pomText: pom(), files: complete })).toEqual({ - artifactId: "vector-android-arm64", - groupId: "dev.oliphaunt.extensions", - packaging: "tar.gz", - version: "1.2.3", - }); - }); - - test("permits a metadata-complete POM-only Gradle marker", () => { - expect(validateMavenCentralPublication({ - pomText: pom({ packaging: "pom" }), - files: [{ name: "vector-android-arm64-1.2.3.pom", size: 10 }], - }).packaging).toBe("pom"); - }); - - for (const missing of ["vector-android-arm64-1.2.3.tar.gz", "vector-android-arm64-1.2.3-sources.jar", "vector-android-arm64-1.2.3-javadoc.jar"]) { - test(`rejects a non-POM coordinate missing ${missing}`, () => { - expect(() => validateMavenCentralPublication({ - pomText: pom(), - files: complete.filter(({ name }) => name !== missing), - })).toThrow(`missing required file ${missing}`); - }); - } - - test("rejects incomplete required Central POM metadata", () => { - expect(() => validateMavenCentralPublication({ pomText: pom({ metadata: false }), files: complete })).toThrow("exactly one , found 0"); - }); - - test("rejects duplicate root packaging emitted by an unsafe Gradle XML append", () => { - const duplicate = pom().replace("tar.gz", "tar.gztar.gz"); - expect(() => validateMavenCentralPublication({ pomText: duplicate, files: complete })).toThrow( - "exactly one , found 2", - ); - }); - - test("rejects empty publication files", () => { - expect(() => validateMavenCentralPublication({ - pomText: pom(), - files: complete.map((entry) => entry.name.endsWith("-sources.jar") ? { ...entry, size: 0 } : entry), - })).toThrow("must be nonempty"); - }); -}); diff --git a/tools/release/merge-product-release-assets.mjs b/tools/release/merge-product-release-assets.mjs deleted file mode 100644 index 348fe3907..000000000 --- a/tools/release/merge-product-release-assets.mjs +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env bun - -import { createHash, randomUUID } from "node:crypto"; -import { - chmodSync, - createReadStream, - linkSync, - lstatSync, - readdirSync, - unlinkSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { compareText, expectedAssetRows } from "./release-artifact-targets.mjs"; - -const TOOL = "merge-product-release-assets.mjs"; - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function parseOptions(argv) { - const options = {}; - for (let index = 0; index < argv.length; index += 1) { - const flag = argv[index]; - if (!["--asset-dir", "--product", "--version"].includes(flag) || index + 1 >= argv.length) { - fail(`usage: ${TOOL} --product PRODUCT --version VERSION --asset-dir DIR`); - } - const field = flag.slice(2).replace("-", "_"); - if (options[field] !== undefined) { - fail(`${flag} may only be provided once`); - } - options[field] = argv[index + 1]; - index += 1; - } - for (const field of ["asset_dir", "product", "version"]) { - if (typeof options[field] !== "string" || options[field].length === 0) { - fail(`--${field.replace("_", "-")} is required`); - } - } - return options; -} - -async function sha256File(file) { - const hash = createHash("sha256"); - for await (const chunk of createReadStream(file)) { - hash.update(chunk); - } - return hash.digest("hex"); -} - -function exactRegularFiles(directory) { - const directoryEntry = lstatSync(directory); - if (!directoryEntry.isDirectory() || directoryEntry.isSymbolicLink()) { - fail(`asset directory must be a regular directory: ${directory}`); - } - return readdirSync(directory).map((name) => { - const file = path.join(directory, name); - const entry = lstatSync(file); - if (!entry.isFile() || entry.isSymbolicLink()) { - fail(`asset directory contains a non-regular entry: ${file}`); - } - return name; - }).sort(compareText); -} - -function canonicalAssetNames(rows, product) { - const names = rows.map(({ assetName }) => assetName); - for (const name of names) { - if ( - typeof name !== "string" - || name.length === 0 - || name === "." - || name === ".." - || name.includes("/") - || name.includes("\\") - || path.basename(name) !== name - ) { - fail(`${product} declares a non-canonical release asset name: ${JSON.stringify(name)}`); - } - } - if (new Set(names).size !== names.length) { - fail(`${product} declares duplicate release asset names`); - } -} - -export async function mergeProductReleaseAssets({ assetDir, product, version }) { - const directory = path.resolve(assetDir); - const expected = expectedAssetRows({ product, version }, TOOL); - canonicalAssetNames(expected, product); - const checksumRows = expected.filter(({ kind }) => kind === "checksums"); - if (checksumRows.length !== 1) { - fail(`${product} must declare exactly one checksum release asset`); - } - const checksumName = checksumRows[0].assetName; - const payloadNames = expected - .filter(({ assetName }) => assetName !== checksumName) - .map(({ assetName }) => assetName) - .sort(compareText); - const actualNames = exactRegularFiles(directory); - if (JSON.stringify(actualNames) !== JSON.stringify(payloadNames)) { - fail( - `${product} release payload set differs: expected=${JSON.stringify(payloadNames)}, actual=${JSON.stringify(actualNames)}`, - ); - } - - const checksum = path.join(directory, checksumName); - const temporary = path.join(directory, `.${checksumName}.tmp-${randomUUID()}`); - const lines = []; - for (const name of payloadNames) { - lines.push(`${await sha256File(path.join(directory, name))} ./${name}`); - } - try { - writeFileSync(temporary, `${lines.join("\n")}\n`, { encoding: "utf8", flag: "wx", mode: 0o444 }); - linkSync(temporary, checksum); - } finally { - try { - unlinkSync(temporary); - } catch (error) { - if (error?.code !== "ENOENT") throw error; - } - } - chmodSync(checksum, 0o444); - return checksum; -} - -if (import.meta.main) { - const options = parseOptions(Bun.argv.slice(2)); - const checksum = await mergeProductReleaseAssets({ - assetDir: options.asset_dir, - product: options.product, - version: options.version, - }); - console.log(`merged ${options.product} release assets: ${checksum}`); -} diff --git a/tools/release/merge-product-release-assets.test.mjs b/tools/release/merge-product-release-assets.test.mjs deleted file mode 100644 index 36f7c81ee..000000000 --- a/tools/release/merge-product-release-assets.test.mjs +++ /dev/null @@ -1,108 +0,0 @@ -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { - chmodSync, - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { test } from "node:test"; - -import { mergeProductReleaseAssets } from "./merge-product-release-assets.mjs"; -import { expectedAssetRows } from "./release-artifact-targets.mjs"; - -function sha256(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function fixture() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-postmaster-release-assets-")); - const product = "liboliphaunt-wasix-postmaster"; - const version = "0.0.0"; - const rows = expectedAssetRows({ product, version }, "merge-product-release-assets.test.mjs"); - const checksumName = rows.find(({ kind }) => kind === "checksums").assetName; - const payloadRows = rows.filter(({ assetName }) => assetName !== checksumName); - return { root, assetDir: root, product, version, checksumName, payloadRows }; -} - -function writePayloads(root, rows) { - for (const row of rows) { - writeFileSync(path.join(root, row.assetName), `${row.target}\n`, "utf8"); - } -} - -function cleanup(root) { - chmodSync(root, 0o755); - rmSync(root, { recursive: true, force: true }); -} - -test("postmaster aggregation uses the catalog and canonical checksum format", async () => { - const { root, product, version, checksumName, payloadRows } = fixture(); - try { - assert.deepEqual( - payloadRows.map(({ target }) => target).sort(), - ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64"], - ); - assert.equal( - payloadRows.every(({ assetName }) => assetName.endsWith(".tar.zst")), - true, - "published WASIX postmaster carriers must use the normal WASIX Zstandard format", - ); - writePayloads(root, payloadRows); - - const checksum = await mergeProductReleaseAssets({ assetDir: root, product, version }); - assert.equal(path.basename(checksum), checksumName); - assert.equal( - readFileSync(checksum, "utf8"), - payloadRows - .map(({ assetName, target }) => `${sha256(`${target}\n`)} ./${assetName}`) - .join("\n") + "\n", - ); - await assert.rejects( - mergeProductReleaseAssets({ assetDir: root, product, version }), - /release payload set differs/u, - ); - } finally { - cleanup(root); - } -}); - -test("postmaster aggregation rejects missing and extra payloads", async () => { - const missing = fixture(); - const extra = fixture(); - try { - writePayloads(missing.root, missing.payloadRows.slice(1)); - await assert.rejects( - mergeProductReleaseAssets(missing), - /release payload set differs/u, - ); - - writePayloads(extra.root, extra.payloadRows); - writeFileSync(path.join(extra.root, "unexpected.tar.zst"), "unexpected\n", "utf8"); - await assert.rejects( - mergeProductReleaseAssets(extra), - /release payload set differs/u, - ); - } finally { - cleanup(missing.root); - cleanup(extra.root); - } -}); - -test("postmaster aggregation rejects non-regular entries", async () => { - const release = fixture(); - try { - writePayloads(release.root, release.payloadRows); - mkdirSync(path.join(release.root, "nested")); - await assert.rejects( - mergeProductReleaseAssets(release), - /asset directory contains a non-regular entry/u, - ); - } finally { - cleanup(release.root); - } -}); diff --git a/tools/release/mobile-extension-artifact-paths.test.mjs b/tools/release/mobile-extension-artifact-paths.test.mjs deleted file mode 100644 index 384aef2ab..000000000 --- a/tools/release/mobile-extension-artifact-paths.test.mjs +++ /dev/null @@ -1,1098 +0,0 @@ -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { spawnSync } from "node:child_process"; -import { - appendFileSync, - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - statSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; -import { fileURLToPath } from "node:url"; -import { gunzipSync } from "node:zlib"; - -import { - extensionCarrierLegalContract, - extensionCarrierLegalFileInventory, -} from "./extension-upstream-licenses.mjs"; -import { canonicalGzipSync } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; - -const SCRIPT = fileURLToPath( - new URL("../../src/sdks/react-native/tools/mobile-extension-artifact-paths.mjs", import.meta.url), -); -const repositoryResult = spawnSync("git", ["rev-parse", "--show-toplevel"], { - cwd: path.dirname(SCRIPT), - encoding: "utf8", -}); -assert.equal(repositoryResult.status, 0, repositoryResult.stderr); -const REPOSITORY_ROOT = repositoryResult.stdout.trim(); -const VERSION = "1.2.3"; -const NATIVE_RUNTIME_VERSION = readFileSync( - path.join(REPOSITORY_ROOT, "src/runtimes/liboliphaunt/native/VERSION"), - "utf8", -).trim(); -const WASIX_RUNTIME_VERSION = readFileSync( - path.join(REPOSITORY_ROOT, "src/runtimes/liboliphaunt/wasix/VERSION"), - "utf8", -).trim(); -const CONTRIB_VERSION = NATIVE_RUNTIME_VERSION; -const REACT_NATIVE_EXTENSIONS = JSON.parse(readFileSync( - path.join(REPOSITORY_ROOT, "src/extensions/generated/sdk/extensions.json"), - "utf8", -)).extensions; -const REACT_NATIVE_EXTENSION_BY_SQL_NAME = new Map( - REACT_NATIVE_EXTENSIONS.map((row) => [row["sql-name"], row]), -); -const IOS_OVERLAY_BY_SQL_NAME = new Map(JSON.parse(readFileSync( - path.join(REPOSITORY_ROOT, "src/extensions/generated/sdk/ios-static-dependencies.json"), - "utf8", -)).extensions.map((row) => [row["sql-name"], row["static-dependencies"]])); -const NATIVE_RELEASE_PRODUCT_BY_ARTIFACT_PRODUCT = new Map( - REACT_NATIVE_EXTENSIONS.map((row) => [row["artifact-product"], row["release-product"]]), -); -const STATIC_EXTENSION_LINES = readFileSync( - path.join(REPOSITORY_ROOT, "src/extensions/generated/mobile/static-extensions.tsv"), - "utf8", -).split(/\r?\n/u).filter((line) => line.length > 0 && !line.startsWith("#")); -const STATIC_EXTENSION_HEADER = STATIC_EXTENSION_LINES[0].split("\t"); -const STATIC_SQL_INDEX = STATIC_EXTENSION_HEADER.indexOf("sql-name"); -const STATIC_IOS_DEPENDENCY_INDEX = STATIC_EXTENSION_HEADER.indexOf("ios-static-dependencies"); -assert(STATIC_SQL_INDEX >= 0 && STATIC_IOS_DEPENDENCY_INDEX >= 0); -const IOS_DEPENDENCIES_BY_SQL_NAME = new Map( - STATIC_EXTENSION_LINES.slice(1).map((line) => { - const fields = line.split("\t"); - return [ - fields[STATIC_SQL_INDEX], - (fields[STATIC_IOS_DEPENDENCY_INDEX] ?? "").split(",").filter(Boolean).sort(), - ]; - }), -); -const COMPATIBILITY = { - extensionRuntimeContract: "src/shared/extension-runtime-contract/contract.toml", - nativeRuntimeProduct: "liboliphaunt-native", - nativeRuntimeVersion: NATIVE_RUNTIME_VERSION, - postgresMajor: "18", - wasixRuntimeProduct: "liboliphaunt-wasix", - wasixRuntimeVersion: WASIX_RUNTIME_VERSION, -}; -const CONTRIB = "oliphaunt-extension-contrib-pg18"; -const VECTOR = "oliphaunt-extension-vector"; -const TARGETS = ["android-arm64-v8a", "android-x86_64", "ios-xcframework"]; -const CONTRIB_SQL_NAMES = REACT_NATIVE_EXTENSIONS - .filter((row) => row["artifact-product"] === CONTRIB) - .map((row) => row["sql-name"]) - .sort(); - -function sha256(value) { - return createHash("sha256").update(value).digest("hex"); -} - -function sha256File(file) { - return sha256(readFileSync(file)); -} - -function writeJson(file, value) { - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`); -} - -function sortValue(value) { - if (Array.isArray(value)) return value.map(sortValue); - if (value !== null && !Array.isArray(value) && typeof value === "object") { - return Object.fromEntries(Object.keys(value).sort().map((key) => [key, sortValue(value[key])])); - } - return value; -} - -function canonicalJson(value) { - return `${JSON.stringify(sortValue(value), null, 2)}\n`; -} - -function tarPathParts(archivePath) { - if (Buffer.byteLength(archivePath) <= 100) { - return { name: archivePath, prefix: "" }; - } - const parts = archivePath.split("/"); - for (let index = 1; index < parts.length; index += 1) { - const prefix = parts.slice(0, index).join("/"); - const name = parts.slice(index).join("/"); - if (Buffer.byteLength(prefix) <= 155 && Buffer.byteLength(name) <= 100) { - return { name, prefix }; - } - } - throw new Error(`fixture path is too long for ustar: ${archivePath}`); -} - -function writeTarString(buffer, offset, length, value) { - const bytes = Buffer.from(value); - assert(bytes.length <= length, `fixture ustar field overflow: ${value}`); - bytes.copy(buffer, offset); -} - -function writeTarOctal(buffer, offset, length, value) { - const text = value.toString(8); - assert(text.length <= length - 1, `fixture ustar octal overflow: ${value}`); - writeTarString(buffer, offset, length, `${text.padStart(length - 1, "0")}\0`); -} - -function tarHeader(archivePath, size) { - const header = Buffer.alloc(512); - const { name, prefix } = tarPathParts(archivePath); - writeTarString(header, 0, 100, name); - writeTarOctal(header, 100, 8, 0o644); - writeTarOctal(header, 108, 8, 0); - writeTarOctal(header, 116, 8, 0); - writeTarOctal(header, 124, 12, size); - writeTarOctal(header, 136, 12, 0); - header.fill(0x20, 148, 156); - writeTarString(header, 156, 1, "0"); - writeTarString(header, 257, 6, "ustar\0"); - writeTarString(header, 263, 2, "00"); - writeTarString(header, 345, 155, prefix); - const checksum = [...header].reduce((total, byte) => total + byte, 0).toString(8); - assert(checksum.length <= 6); - writeTarString(header, 148, 8, `${checksum.padStart(6, "0")}\0 `); - return header; -} - -function writeCanonicalTarGzip(output, stage, archiveNames) { - const chunks = []; - for (const archiveName of [...archiveNames].sort()) { - const data = readFileSync(path.join(stage, ...archiveName.split("/"))); - chunks.push(tarHeader(archiveName, data.length), data); - const remainder = data.length % 512; - if (remainder !== 0) { - chunks.push(Buffer.alloc(512 - remainder)); - } - } - chunks.push(Buffer.alloc(1024)); - writeFileSync(output, canonicalGzipSync(Buffer.concat(chunks))); -} - -function rewriteFirstTarMode(output, mode) { - const tar = gunzipSync(readFileSync(output)); - writeTarOctal(tar, 100, 8, mode); - tar.fill(0x20, 148, 156); - const checksum = [...tar.subarray(0, 512)].reduce((total, byte) => total + byte, 0).toString(8); - assert(checksum.length <= 6); - writeTarString(tar, 148, 8, `${checksum.padStart(6, "0")}\0 `); - writeFileSync(output, canonicalGzipSync(tar)); -} - -function extensionMember(sqlName, stagesIos = true) { - const row = REACT_NATIVE_EXTENSION_BY_SQL_NAME.get(sqlName); - assert(row, `missing generated React Native fixture metadata for ${sqlName}`); - const nativeModuleStem = row["native-module-stem"]; - const generatedIosDependencies = [...(IOS_OVERLAY_BY_SQL_NAME.get(sqlName) ?? [])].sort(); - assert.deepEqual( - generatedIosDependencies, - IOS_DEPENDENCIES_BY_SQL_NAME.get(sqlName) ?? [], - `${sqlName} generated RN and mobile-static iOS dependency contracts must agree`, - ); - const iosNativeDependencies = stagesIos && nativeModuleStem !== null - ? generatedIosDependencies - : []; - const prefix = nativeModuleStem === null - ? null - : `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`; - return { - sqlName, - createsExtension: row["creates-extension"], - dependencies: [...row["selected-extension-dependencies"]].sort(), - dataFiles: [...row["runtime-share-data-files"]].sort(), - extensionSqlFileNames: [...row["extension-sql-file-names"]].sort(), - extensionSqlFilePrefixes: [...row["extension-sql-file-prefixes"]].sort(), - nativeModuleStem, - iosNativeDependencies, - iosRegistration: nativeModuleStem === null || !stagesIos - ? null - : { - initSymbol: null, - magicSymbol: `${prefix}_Pg_magic_func`, - nativeModuleStem, - schema: "oliphaunt-ios-extension-registration-v1", - sqlName, - symbols: [], - }, - wasixInstall: null, - sharedPreloadLibraries: [...row["shared-preload-libraries"]].sort(), - assets: [], - }; -} - -function fixture(t) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-mobile-extension-artifacts-")); - const artifactRoot = path.join(root, "extension-artifacts"); - const materializeRoot = path.join(root, "materialized"); - mkdirSync(artifactRoot, { recursive: true }); - t.after(() => rmSync(root, { recursive: true, force: true })); - - function productRoot(product) { - const releaseProduct = NATIVE_RELEASE_PRODUCT_BY_ARTIFACT_PRODUCT.get(product); - assert(releaseProduct, `fixture requires a native release owner for ${product}`); - return path.join(artifactRoot, ...(releaseProduct === product ? [product] : [releaseProduct, product])); - } - - function publishedProductRoot(product) { - const releaseProduct = NATIVE_RELEASE_PRODUCT_BY_ARTIFACT_PRODUCT.get(product); - assert(releaseProduct, `fixture requires a native release owner for ${product}`); - return ["target/extension-artifacts", ...(releaseProduct === product - ? [product] - : [releaseProduct, product])].join("/"); - } - - function manifestPath(product) { - return path.join(productRoot(product), "extension-artifacts.json"); - } - - function writeManifest(product, value) { - writeJson(manifestPath(product), value); - } - - function run({ extensions, assetKind, assetTarget, required = "1", extraArgs = [] }) { - return spawnSync( - process.execPath, - [ - SCRIPT, - "--root", REPOSITORY_ROOT, - "--artifact-root", artifactRoot, - "--materialize-root", materializeRoot, - "--extensions", extensions, - "--asset-kind", assetKind, - "--asset-target", assetTarget, - "--required", required, - ...extraArgs, - ], - { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }, - ); - } - - function installAggregate({ - targets = TARGETS, - embeddedMutator = (value) => value, - tamperNested = null, - tamperLegal = null, - omitLegal = null, - extraArchiveMember = null, - duplicatePhysicalRolePath = false, - } = {}) { - const members = CONTRIB_SQL_NAMES.map((sqlName) => - extensionMember(sqlName, targets.includes("ios-xcframework")) - ); - const manifest = { - schema: "oliphaunt-extension-ci-artifacts-v2", - product: CONTRIB, - releaseProduct: "liboliphaunt-native", - family: "native", - version: CONTRIB_VERSION, - compatibility: COMPATIBILITY, - extensions: members, - carrierAssets: [], - }; - const carriersByTarget = new Map(); - const declaredContents = new Map(); - - for (const target of targets) { - const carrierRoot = `${CONTRIB}-${CONTRIB_VERSION}-native-${target}-bundle`; - const carrierName = `${carrierRoot}.tar.gz`; - const rows = []; - const stage = path.join(root, "bundle-stage", target); - rmSync(stage, { recursive: true, force: true }); - mkdirSync(stage, { recursive: true }); - - for (const member of members) { - const roles = [ - { identity: null, kind: "runtime" }, - ...(target === "ios-xcframework" && member.nativeModuleStem !== null - ? [ - { identity: member.nativeModuleStem, kind: "ios-xcframework" }, - ...member.iosNativeDependencies.map((identity) => ({ - identity, - kind: "ios-dependency-xcframework", - })), - ] - : []), - ]; - for (const { identity, kind } of roles) { - const duplicatesRuntimePath = duplicatePhysicalRolePath - && target === "ios-xcframework" - && member.sqlName === "cube" - && kind === "ios-xcframework"; - const name = kind === "runtime" || duplicatesRuntimePath - ? target === "ios-xcframework" - ? `${CONTRIB}-${CONTRIB_VERSION}-native-ios-runtime.tar.gz` - : `${CONTRIB}-${CONTRIB_VERSION}-native-${target}-runtime.tar.gz` - : kind === "ios-xcframework" - ? `${CONTRIB}-${CONTRIB_VERSION}-native-ios-xcframework.zip` - : `${CONTRIB}-${CONTRIB_VERSION}-native-ios-dependency-${identity}-xcframework.zip`; - const memberPath = `extensions/${member.sqlName}/${name}`; - const declaredKind = duplicatesRuntimePath ? "runtime" : kind; - const declared = Buffer.from(`declared:${target}:${member.sqlName}:${declaredKind}\n`); - const nestedKey = `${target}:${member.sqlName}:${kind}` + - (kind === "ios-dependency-xcframework" ? `:${identity}` : ""); - const archived = tamperNested === nestedKey - ? Buffer.from(`tampered:${target}:${member.sqlName}:${kind}\n`) - : declared; - const asset = { - name, - path: `${publishedProductRoot(CONTRIB)}/member-assets/${member.sqlName}/${name}`, - source: `target/extensions/native/release-assets/${target}/${name}`, - sha256: sha256(declared), - bytes: declared.length, - family: "native", - kind, - target, - identity, - carrierAsset: carrierName, - carrierRoot, - memberPath, - }; - member.assets.push(asset); - rows.push({ - sqlName: member.sqlName, - kind, - identity, - path: memberPath, - sha256: asset.sha256, - bytes: asset.bytes, - }); - declaredContents.set(nestedKey, declared); - const stagedMember = path.join(stage, carrierRoot, ...memberPath.split("/")); - mkdirSync(path.dirname(stagedMember), { recursive: true }); - writeFileSync(stagedMember, archived); - } - } - - rows.sort((left, right) => { - const leftKey = `${left.sqlName}\0${left.kind}\0${left.identity ?? ""}`; - const rightKey = `${right.sqlName}\0${right.kind}\0${right.identity ?? ""}`; - return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0; - }); - const legal = extensionCarrierLegalContract(CONTRIB, CONTRIB_SQL_NAMES, { - family: "native", - target, - }); - const embedded = embeddedMutator({ - schema: "oliphaunt-extension-bundle-v1", - product: CONTRIB, - version: CONTRIB_VERSION, - compatibility: COMPATIBILITY, - family: "native", - target, - licenseProfile: legal.profile, - licenseFiles: legal.licenseFiles, - members: rows, - }, target); - const embeddedPath = path.join(stage, carrierRoot, "bundle-manifest.json"); - mkdirSync(path.dirname(embeddedPath), { recursive: true }); - writeFileSync(embeddedPath, canonicalJson(embedded)); - stageReleaseNotices(path.join(stage, carrierRoot), { profile: legal.profile }); - const legalFiles = extensionCarrierLegalFileInventory(CONTRIB, CONTRIB_SQL_NAMES, { - family: "native", - target, - }); - if (tamperLegal !== null) { - const legalPath = path.join(stage, carrierRoot, ...tamperLegal.split("/")); - const bytes = readFileSync(legalPath); - assert(bytes.length > 0, `${tamperLegal} fixture must not be empty`); - bytes[0] ^= 0xff; - writeFileSync(legalPath, bytes); - } - if (extraArchiveMember !== null) { - const extraPath = path.join(stage, carrierRoot, ...extraArchiveMember.split("/")); - mkdirSync(path.dirname(extraPath), { recursive: true }); - writeFileSync(extraPath, "undeclared bundle member\n"); - } - - const releaseAssets = path.join(productRoot(CONTRIB), "release-assets"); - mkdirSync(releaseAssets, { recursive: true }); - const carrierPath = path.join(releaseAssets, carrierName); - const archiveNames = [ - `${carrierRoot}/bundle-manifest.json`, - ...rows.map((row) => `${carrierRoot}/${row.path}`), - ...legalFiles.map((file) => `${carrierRoot}/${file.path}`), - ...(extraArchiveMember === null ? [] : [`${carrierRoot}/${extraArchiveMember}`]), - ].filter((name) => name !== `${carrierRoot}/${omitLegal}`); - const uniqueArchiveNames = [...new Set(archiveNames)].sort(); - writeCanonicalTarGzip(carrierPath, stage, uniqueArchiveNames); - const carrier = { - name: carrierName, - path: `${publishedProductRoot(CONTRIB)}/release-assets/${carrierName}`, - sha256: sha256File(carrierPath), - bytes: statSync(carrierPath).size, - family: "native", - target, - kind: "extension-bundle", - memberCount: members.length, - }; - manifest.carrierAssets.push(carrier); - carriersByTarget.set(target, { carrier, carrierPath }); - rmSync(stage, { recursive: true, force: true }); - } - rmSync(path.join(root, "bundle-stage"), { recursive: true, force: true }); - writeManifest(CONTRIB, manifest); - return { manifest, carriersByTarget, declaredContents }; - } - - function installLeaf() { - const assets = []; - const contents = new Map(); - const releaseAssets = path.join(productRoot(VECTOR), "release-assets"); - mkdirSync(releaseAssets, { recursive: true }); - for (const target of TARGETS) { - const kinds = target === "ios-xcframework" ? ["runtime", "ios-xcframework"] : ["runtime"]; - for (const kind of kinds) { - const name = kind === "runtime" - ? target === "ios-xcframework" - ? `${VECTOR}-${VERSION}-native-ios-runtime.tar.gz` - : `${VECTOR}-${VERSION}-native-${target}-runtime.tar.gz` - : `${VECTOR}-${VERSION}-native-ios-xcframework.zip`; - const file = path.join(releaseAssets, name); - const content = Buffer.from(`leaf:${target}:${kind}\n`); - writeFileSync(file, content); - assets.push({ - name, - path: `${publishedProductRoot(VECTOR)}/release-assets/${name}`, - source: `target/extensions/native/release-assets/${target}/${name}`, - sha256: sha256(content), - bytes: content.length, - family: "native", - kind, - target, - identity: kind === "runtime" ? null : "vector", - }); - contents.set(`${target}:${kind}`, content); - } - } - const manifest = { - schema: "oliphaunt-extension-ci-artifacts-v1", - product: VECTOR, - version: VERSION, - compatibility: COMPATIBILITY, - ...extensionMember("vector"), - assets, - }; - writeManifest(VECTOR, manifest); - return { manifest, contents, releaseAssets }; - } - - return { - artifactRoot, - installAggregate, - installLeaf, - manifestPath, - materializeRoot, - productRoot, - root, - run, - writeManifest, - }; -} - -function outputPaths(result) { - assert.equal(result.status, 0, result.stderr); - return result.stdout.trim().split(/\r?\n/u).filter(Boolean); -} - -function assertContents(files, expected) { - assert.equal(files.length, expected.length); - for (const [index, file] of files.entries()) { - assert.deepEqual(readFileSync(file), expected[index]); - } -} - -test("materializes aggregate and singleton assets into immutable content-addressed paths", (t) => { - const value = fixture(t); - const aggregate = value.installAggregate(); - const leaf = value.installLeaf(); - assert.equal(existsSync(path.join(value.productRoot(CONTRIB), "member-assets")), false); - - for (const target of ["android-arm64-v8a", "android-x86_64"]) { - const files = outputPaths(value.run({ - extensions: "amcheck,cube,vector", - assetKind: "runtime", - assetTarget: target, - })); - assertContents(files, [ - aggregate.declaredContents.get(`${target}:amcheck:runtime`), - aggregate.declaredContents.get(`${target}:cube:runtime`), - leaf.contents.get(`${target}:runtime`), - ]); - assert(files[0].startsWith(value.materializeRoot)); - assert(files[1].startsWith(value.materializeRoot)); - assert(files[2].startsWith(value.materializeRoot)); - assert(!files[2].startsWith(path.join(value.productRoot(VECTOR), "release-assets"))); - assert(files.every((file) => !file.includes("member-assets"))); - const directAsset = leaf.manifest.assets.find((asset) => - asset.target === target && asset.kind === "runtime"); - writeFileSync(path.join(leaf.releaseAssets, directAsset.name), "mutated published source\n"); - assert.deepEqual( - readFileSync(files[2]), - leaf.contents.get(`${target}:runtime`), - "resolved singleton path must not alias mutable release-assets input", - ); - } - - const iosRuntime = outputPaths(value.run({ - extensions: "amcheck,cube,vector", - assetKind: "runtime", - assetTarget: "ios-xcframework", - })); - assertContents(iosRuntime, [ - aggregate.declaredContents.get("ios-xcframework:amcheck:runtime"), - aggregate.declaredContents.get("ios-xcframework:cube:runtime"), - leaf.contents.get("ios-xcframework:runtime"), - ]); - - const iosFrameworks = outputPaths(value.run({ - extensions: "cube,vector", - assetKind: "ios-xcframework", - assetTarget: "ios-xcframework", - })); - assertContents(iosFrameworks, [ - aggregate.declaredContents.get("ios-xcframework:cube:ios-xcframework"), - leaf.contents.get("ios-xcframework:ios-xcframework"), - ]); -}); - -test("rejects outer and nested carrier tampering independently", (t) => { - const outer = fixture(t); - const outerAggregate = outer.installAggregate({ targets: ["android-arm64-v8a"] }); - appendFileSync(outerAggregate.carriersByTarget.get("android-arm64-v8a").carrierPath, "tamper"); - const outerResult = outer.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(outerResult.status, 1); - assert.match(outerResult.stderr, /aggregate carrier .* does not match its frozen size\/digest/u); - - const nested = fixture(t); - nested.installAggregate({ - targets: ["android-arm64-v8a"], - tamperNested: "android-arm64-v8a:amcheck:runtime", - }); - const nestedResult = nested.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(nestedResult.status, 1); - assert.match(nestedResult.stderr, /member .* does not match its canonical SHA-256/u); -}); - -test("binds the production bundle manifest and exact legal-file closure", (t) => { - const valid = fixture(t); - valid.installAggregate({ targets: ["android-arm64-v8a"] }); - outputPaths(valid.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - })); - - const tampered = fixture(t); - tampered.installAggregate({ - targets: ["android-arm64-v8a"], - tamperLegal: "LICENSE", - }); - const tamperedResult = tampered.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(tamperedResult.status, 1); - assert.match(tamperedResult.stderr, /LICENSE.*does not match its canonical SHA-256/u); - - const missing = fixture(t); - missing.installAggregate({ - targets: ["android-arm64-v8a"], - omitLegal: "THIRD_PARTY_NOTICES.md", - }); - const missingResult = missing.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(missingResult.status, 1); - assert.match(missingResult.stderr, /exact two-block ustar marker/u); - - const extra = fixture(t); - extra.installAggregate({ - targets: ["android-arm64-v8a"], - extraArchiveMember: "UNDECLARED-LEGAL.txt", - }); - const extraResult = extra.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(extraResult.status, 1); - assert.match(extraResult.stderr, /UNDECLARED-LEGAL\.txt.*undeclared/u); - - const staleManifest = fixture(t); - staleManifest.installAggregate({ - targets: ["android-arm64-v8a"], - embeddedMutator: (value) => { - const { licenseProfile: _licenseProfile, ...legacy } = value; - return legacy; - }, - }); - const staleManifestResult = staleManifest.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(staleManifestResult.status, 1); - assert.match(staleManifestResult.stderr, /bundle-manifest\.json.*wrong ustar size/u); -}); - -test("rejects unsupported outer and embedded bundle schemas", (t) => { - const outer = fixture(t); - outer.writeManifest(VECTOR, { - schema: "oliphaunt-extension-ci-artifacts-v3", - product: "bad-extension", - version: VERSION, - compatibility: COMPATIBILITY, - sqlName: "bad", - assets: [], - }); - const outerResult = outer.run({ - extensions: "bad", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(outerResult.status, 1); - assert.match(outerResult.stderr, /unsupported extension artifact schema/u); - - const embedded = fixture(t); - embedded.installAggregate({ - targets: ["android-arm64-v8a"], - embeddedMutator: (value) => ({ ...value, schema: "oliphaunt-extension-bundle-v2" }), - }); - const embeddedResult = embedded.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(embeddedResult.status, 1); - assert.match(embeddedResult.stderr, /bundle-manifest\.json.*canonical SHA-256/u); -}); - -test("rejects noncanonical public evidence-envelope key sets", (t) => { - const bundleRoot = fixture(t); - const bundleRootAggregate = bundleRoot.installAggregate({ targets: ["android-arm64-v8a"] }); - bundleRootAggregate.manifest.unexpected = true; - bundleRoot.writeManifest(CONTRIB, bundleRootAggregate.manifest); - const bundleRootResult = bundleRoot.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(bundleRootResult.status, 1); - assert.match(bundleRootResult.stderr, /fields must be exactly .* got .*unexpected/u); - - const bundleMember = fixture(t); - const bundleMemberAggregate = bundleMember.installAggregate({ targets: ["android-arm64-v8a"] }); - delete bundleMemberAggregate.manifest.extensions[0].sharedPreloadLibraries; - bundleMember.writeManifest(CONTRIB, bundleMemberAggregate.manifest); - const bundleMemberResult = bundleMember.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(bundleMemberResult.status, 1); - assert.match(bundleMemberResult.stderr, /extension member 0 fields must be exactly/u); - - const bundleAsset = fixture(t); - const bundleAssetAggregate = bundleAsset.installAggregate({ targets: ["android-arm64-v8a"] }); - bundleAssetAggregate.manifest.extensions[0].assets[0].unexpected = "value"; - bundleAsset.writeManifest(CONTRIB, bundleAssetAggregate.manifest); - const bundleAssetResult = bundleAsset.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(bundleAssetResult.status, 1); - assert.match(bundleAssetResult.stderr, /extension member 0 asset 0 fields must be exactly/u); - - const bundleCarrier = fixture(t); - const bundleCarrierAggregate = bundleCarrier.installAggregate({ targets: ["android-arm64-v8a"] }); - delete bundleCarrierAggregate.manifest.carrierAssets[0].memberCount; - bundleCarrier.writeManifest(CONTRIB, bundleCarrierAggregate.manifest); - const bundleCarrierResult = bundleCarrier.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(bundleCarrierResult.status, 1); - assert.match(bundleCarrierResult.stderr, /aggregate carrier 0 fields must be exactly/u); - - const directRoot = fixture(t); - const directRootLeaf = directRoot.installLeaf(); - directRootLeaf.manifest.unexpected = true; - directRoot.writeManifest(VECTOR, directRootLeaf.manifest); - const directRootResult = directRoot.run({ - extensions: "vector", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(directRootResult.status, 1); - assert.match(directRootResult.stderr, /fields must be exactly .* got .*unexpected/u); - - const directAsset = fixture(t); - const directAssetLeaf = directAsset.installLeaf(); - directAssetLeaf.manifest.assets[0].unexpected = "value"; - directAsset.writeManifest(VECTOR, directAssetLeaf.manifest); - const directAssetResult = directAsset.run({ - extensions: "vector", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(directAssetResult.status, 1); - assert.match(directAssetResult.stderr, /asset 0 fields must be exactly/u); -}); - -test("rejects duplicate extension, carrier, and nested member identities", (t) => { - const extensionDuplicate = fixture(t); - const duplicateManifest = { - schema: "oliphaunt-extension-ci-artifacts-v2", - product: CONTRIB, - releaseProduct: "liboliphaunt-native", - family: "native", - version: CONTRIB_VERSION, - compatibility: COMPATIBILITY, - extensions: [extensionMember("amcheck", false), extensionMember("amcheck", false)], - carrierAssets: [], - }; - extensionDuplicate.writeManifest(CONTRIB, duplicateManifest); - const extensionResult = extensionDuplicate.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(extensionResult.status, 1); - assert.match(extensionResult.stderr, /repeats an extension SQL identity/u); - - const carrierDuplicate = fixture(t); - const carrierAggregate = carrierDuplicate.installAggregate({ targets: ["android-arm64-v8a"] }); - carrierAggregate.manifest.carrierAssets.push({ ...carrierAggregate.manifest.carrierAssets[0] }); - carrierDuplicate.writeManifest(CONTRIB, carrierAggregate.manifest); - const carrierResult = carrierDuplicate.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(carrierResult.status, 1); - assert.match(carrierResult.stderr, /exactly one native extension-bundle carrier/u); - - const memberDuplicate = fixture(t); - const memberAggregate = memberDuplicate.installAggregate({ targets: ["android-arm64-v8a"] }); - const amcheck = memberAggregate.manifest.extensions.find((member) => member.sqlName === "amcheck"); - amcheck.assets.push({ ...amcheck.assets[0] }); - memberDuplicate.writeManifest(CONTRIB, memberAggregate.manifest); - const memberResult = memberDuplicate.run({ - extensions: "cube", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(memberResult.status, 1); - assert.match(memberResult.stderr, /mobile artifact roles are not exact and dependency-closed/u); - - const physicalPathDuplicate = fixture(t); - physicalPathDuplicate.installAggregate({ - targets: ["ios-xcframework"], - duplicatePhysicalRolePath: true, - }); - const physicalPathResult = physicalPathDuplicate.run({ - extensions: "cube", - assetKind: "ios-xcframework", - assetTarget: "ios-xcframework", - }); - assert.equal(physicalPathResult.status, 1); - assert.match(physicalPathResult.stderr, /repeats nested member path/u); -}); - -test("binds aggregate ownership and compatibility to generated repository metadata", (t) => { - for (const [field, value] of [["releaseProduct", "liboliphaunt-wasix"], ["family", "wasix"]]) { - const ownership = fixture(t); - const aggregate = ownership.installAggregate({ targets: ["android-arm64-v8a"] }); - aggregate.manifest[field] = value; - ownership.writeManifest(CONTRIB, aggregate.manifest); - const result = ownership.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(result.status, 1); - assert.match(result.stderr, /must be owned by liboliphaunt-native\/native/u); - } - - const subset = fixture(t); - const subsetAggregate = subset.installAggregate({ targets: ["android-arm64-v8a"] }); - subsetAggregate.manifest.extensions.pop(); - subset.writeManifest(CONTRIB, subsetAggregate.manifest); - const subsetResult = subset.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(subsetResult.status, 1); - assert.match(subsetResult.stderr, /member set must exactly match generated owner/u); - - const compatibility = fixture(t); - const compatibilityAggregate = compatibility.installAggregate({ targets: ["android-arm64-v8a"] }); - compatibilityAggregate.manifest.compatibility = { - ...compatibilityAggregate.manifest.compatibility, - nativeRuntimeVersion: "9.9.9", - }; - compatibility.writeManifest(CONTRIB, compatibilityAggregate.manifest); - const compatibilityResult = compatibility.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(compatibilityResult.status, 1); - assert.match(compatibilityResult.stderr, /compatibility metadata must exactly match/u); - - const semantics = fixture(t); - const semanticsAggregate = semantics.installAggregate({ targets: ["android-arm64-v8a"] }); - semanticsAggregate.manifest.extensions.find(({ sqlName }) => sqlName === "amcheck") - .dataFiles.push("forged/catalog.dat"); - semantics.writeManifest(CONTRIB, semanticsAggregate.manifest); - const semanticsResult = semantics.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(semanticsResult.status, 1); - assert.match(semanticsResult.stderr, /\.dataFiles must exactly match generated React Native extension metadata/u); - - for (const [field, forgedValue] of [ - ["extensionSqlFileNames", "forged-install.sql"], - ["extensionSqlFilePrefixes", "forged-prefix"], - ]) { - const sqlOwnership = fixture(t); - const sqlOwnershipAggregate = sqlOwnership.installAggregate({ targets: ["android-arm64-v8a"] }); - sqlOwnershipAggregate.manifest.extensions - .find(({ sqlName }) => sqlName === "amcheck")[field].push(forgedValue); - sqlOwnership.writeManifest(CONTRIB, sqlOwnershipAggregate.manifest); - const sqlOwnershipResult = sqlOwnership.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(sqlOwnershipResult.status, 1); - assert.match( - sqlOwnershipResult.stderr, - new RegExp(`\\.${field} must exactly match generated React Native extension metadata`, "u"), - ); - } - - const dependencyClosure = fixture(t); - const dependencyAggregate = dependencyClosure.installAggregate({ targets: ["ios-xcframework"] }); - const pgcrypto = dependencyAggregate.manifest.extensions.find(({ sqlName }) => sqlName === "pgcrypto"); - assert.deepEqual(pgcrypto.iosNativeDependencies, ["openssl"]); - pgcrypto.assets = pgcrypto.assets.filter((asset) => - !(asset.kind === "ios-dependency-xcframework" && asset.identity === "openssl")); - dependencyClosure.writeManifest(CONTRIB, dependencyAggregate.manifest); - const dependencyResult = dependencyClosure.run({ - extensions: "pgcrypto", - assetKind: "runtime", - assetTarget: "ios-xcframework", - }); - assert.equal(dependencyResult.status, 1); - assert.match(dependencyResult.stderr, /mobile artifact roles are not exact and dependency-closed/u); - - const registration = fixture(t); - const registrationAggregate = registration.installAggregate({ targets: ["ios-xcframework"] }); - registrationAggregate.manifest.extensions.find(({ sqlName }) => sqlName === "cube") - .iosRegistration.schema = "unfrozen-registration-v2"; - registration.writeManifest(CONTRIB, registrationAggregate.manifest); - const registrationResult = registration.run({ - extensions: "cube", - assetKind: "ios-xcframework", - assetTarget: "ios-xcframework", - }); - assert.equal(registrationResult.status, 1); - assert.match(registrationResult.stderr, /does not match canonical native module identity/u); -}); - -test("rejects cache path escapes, noncanonical ustar metadata, and invalid CLI flags", (t) => { - const escape = fixture(t); - const escapeAggregate = escape.installAggregate({ targets: ["android-arm64-v8a"] }); - const escapeCarrier = escapeAggregate.manifest.carrierAssets[0]; - const escapedName = `${CONTRIB}-${CONTRIB_VERSION}-native-..-bundle.tar.gz`; - escapeCarrier.target = ".."; - escapeCarrier.name = escapedName; - escapeCarrier.path = `${escapeCarrier.path.slice(0, escapeCarrier.path.lastIndexOf("/") + 1)}${escapedName}`; - for (const member of escapeAggregate.manifest.extensions) { - for (const asset of member.assets) { - asset.target = ".."; - asset.carrierAsset = escapedName; - asset.carrierRoot = escapedName.replace(/\.tar\.gz$/u, ""); - } - } - escape.writeManifest(CONTRIB, escapeAggregate.manifest); - const escapeResult = escape.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "*", - }); - assert.equal(escapeResult.status, 1); - assert.match(escapeResult.stderr, /aggregate carrier target must be a safe non-empty path component/u); - - const canonical = fixture(t); - const canonicalAggregate = canonical.installAggregate({ targets: ["android-arm64-v8a"] }); - const canonicalCarrier = canonicalAggregate.carriersByTarget.get("android-arm64-v8a"); - rewriteFirstTarMode(canonicalCarrier.carrierPath, 0o600); - canonicalCarrier.carrier.bytes = statSync(canonicalCarrier.carrierPath).size; - canonicalCarrier.carrier.sha256 = sha256File(canonicalCarrier.carrierPath); - canonical.writeManifest(CONTRIB, canonicalAggregate.manifest); - const canonicalResult = canonical.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(canonicalResult.status, 1); - assert.match(canonicalResult.stderr, /must use mode=0644 uid=0 gid=0 mtime=0/u); - - const gzip = fixture(t); - const gzipAggregate = gzip.installAggregate({ targets: ["android-arm64-v8a"] }); - const gzipCarrier = gzipAggregate.carriersByTarget.get("android-arm64-v8a"); - const gzipBytes = readFileSync(gzipCarrier.carrierPath); - gzipBytes[9] = 0; - writeFileSync(gzipCarrier.carrierPath, gzipBytes); - gzipCarrier.carrier.bytes = statSync(gzipCarrier.carrierPath).size; - gzipCarrier.carrier.sha256 = sha256File(gzipCarrier.carrierPath); - gzip.writeManifest(CONTRIB, gzipAggregate.manifest); - const gzipResult = gzip.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(gzipResult.status, 1); - assert.match(gzipResult.stderr, /canonical gzip method, flags, mtime, XFL, and OS header/u); - - const oversized = fixture(t); - const oversizedLeaf = oversized.installLeaf(); - oversizedLeaf.manifest.assets.find((asset) => - asset.target === "android-arm64-v8a" && asset.kind === "runtime").bytes = - 2 * 1024 * 1024 * 1024 + 1; - oversized.writeManifest(VECTOR, oversizedLeaf.manifest); - const oversizedResult = oversized.run({ - extensions: "vector", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(oversizedResult.status, 1); - assert.match(oversizedResult.stderr, /exceeds the maximum supported size/u); - - const flags = fixture(t); - const unknownFlag = flags.run({ - extensions: "missing", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - extraArgs: ["--unknown", "value"], - }); - assert.equal(unknownFlag.status, 2); - assert.match(unknownFlag.stderr, /unknown option: --unknown/u); - const duplicateFlag = flags.run({ - extensions: "missing", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - extraArgs: ["--required", "1"], - }); - assert.equal(duplicateFlag.status, 2); - assert.match(duplicateFlag.stderr, /duplicate option: --required/u); -}); - -test("rejects pre-existing materialization-cache symlink redirection", (t) => { - const component = fixture(t); - component.installAggregate({ targets: ["android-arm64-v8a"] }); - const redirected = path.join(component.root, "redirected-component"); - mkdirSync(component.materializeRoot, { recursive: true }); - mkdirSync(redirected, { recursive: true }); - symlinkSync(redirected, path.join(component.materializeRoot, CONTRIB), "dir"); - const componentResult = component.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(componentResult.status, 1); - assert.match(componentResult.stderr, /cache path component must be a real directory, not a symlink/u); - assert.deepEqual(readdirSync(redirected), [], "a rejected cache symlink must not receive materialized bytes"); - - const rootLink = fixture(t); - rootLink.installAggregate({ targets: ["android-arm64-v8a"] }); - const redirectedRoot = path.join(rootLink.root, "redirected-root"); - mkdirSync(redirectedRoot, { recursive: true }); - symlinkSync(redirectedRoot, rootLink.materializeRoot, "dir"); - const rootResult = rootLink.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(rootResult.status, 1); - assert.match(rootResult.stderr, /cache root must be a real directory, not a symlink/u); - assert.deepEqual(readdirSync(redirectedRoot), [], "a rejected cache-root symlink must not receive extraction state"); - - const direct = fixture(t); - const leaf = direct.installLeaf(); - const asset = leaf.manifest.assets.find((row) => - row.kind === "runtime" && row.target === "android-arm64-v8a"); - const destination = path.join( - direct.materializeRoot, - VECTOR, - "direct", - "native", - "android-arm64-v8a", - asset.sha256, - "vector", - asset.name, - ); - const redirectedFile = path.join(direct.root, "redirected-direct-file"); - mkdirSync(path.dirname(destination), { recursive: true }); - writeFileSync(redirectedFile, "must remain unchanged\n"); - symlinkSync(redirectedFile, destination, "file"); - const directResult = direct.run({ - extensions: "vector", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - }); - assert.equal(directResult.status, 1); - assert.match(directResult.stderr, /cache destination must not be a symlink/u); - assert.equal(readFileSync(redirectedFile, "utf8"), "must remain unchanged\n"); -}); - -test("preserves optional missing-artifact exit status", (t) => { - const value = fixture(t); - const result = value.run({ - extensions: "missing", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - required: "0", - }); - assert.equal(result.status, 3); - assert.match(result.stderr, /missing exact-extension artifact\(s\): missing: package/u); - - const carrier = fixture(t); - const aggregate = carrier.installAggregate({ targets: ["android-arm64-v8a"] }); - rmSync(aggregate.carriersByTarget.get("android-arm64-v8a").carrierPath); - const carrierResult = carrier.run({ - extensions: "amcheck", - assetKind: "runtime", - assetTarget: "android-arm64-v8a", - required: "0", - }); - assert.equal(carrierResult.status, 3); - assert.match(carrierResult.stderr, /missing exact-extension artifact\(s\): oliphaunt-extension-contrib-pg18:/u); -}); diff --git a/tools/release/moon-command-resolution.test.mjs b/tools/release/moon-command-resolution.test.mjs deleted file mode 100644 index 0e0cfa5b9..000000000 --- a/tools/release/moon-command-resolution.test.mjs +++ /dev/null @@ -1,204 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { randomUUID } from "node:crypto"; -import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { moonCommand, moonEnvironment } from "../dev/moon-command.mjs"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const CHECK = path.join(ROOT, "tools/release/check_release_please_config.mjs"); -const RELEASE_PLAN = path.join(ROOT, "tools/release/release_plan.mjs"); -const roots = []; - -async function fixture(name) { - const root = await mkdtemp(path.join(tmpdir(), `oliphaunt-moon-command-${name}-`)); - roots.push(root); - return root; -} - -async function writeMoonStub(bin, script) { - await mkdir(bin, { recursive: true }); - await writeFile( - script, - [ - 'import { appendFileSync } from "node:fs";', - 'const args = process.argv.slice(2).join(" ");', - 'if (args === "--version") { process.stdout.write(`moon ${process.env.MOON_STUB_VERSION ?? "2.5.4"}\\n`); process.exit(0); }', - 'if (args !== "query projects") process.exit(41);', - 'appendFileSync(process.env.MOON_STUB_MARKER, "path-stub\\n");', - 'process.stdout.write(process.env.MOON_PROJECTS_JSON);', - "", - ].join("\n"), - ); - if (process.platform === "win32") { - await writeFile( - path.join(bin, "moon.cmd"), - `@echo off\r\n"%MOON_STUB_RUNTIME%" "%MOON_STUB_SCRIPT%" %*\r\n`, - ); - } else { - const launcher = path.join(bin, "moon"); - await writeFile(launcher, '#!/bin/sh\nexec "$MOON_STUB_RUNTIME" "$MOON_STUB_SCRIPT" "$@"\n'); - await chmod(launcher, 0o755); - } -} - -async function moonProjectsJson() { - const config = JSON.parse(await readFile(path.join(ROOT, "release-please-config.json"), "utf8")); - return JSON.stringify({ - projects: Object.entries(config.packages).map(([packagePath, packageConfig]) => ({ - id: packageConfig.component, - config: { - tags: ["release-product"], - project: { - metadata: { - release: { - component: packageConfig.component, - packagePath, - }, - }, - }, - }, - })), - }); -} - -afterEach(async () => { - await Promise.all(roots.splice(0).map((root) => rm(root, { force: true, recursive: true }))); -}); - -describe("Moon command resolution", () => { - test("release graph separates Moon dependencies from published compatibility", async () => { - const root = await fixture("resolved-dependencies"); - const bin = path.join(root, "bin"); - const script = path.join(root, "moon-stub.mjs"); - await writeMoonStub(bin, script); - - const projects = [ - { id: "runtime", source: "packages/runtime", config: { project: {}, tags: [] } }, - { - id: "consumer-production", - source: "packages/consumer-production", - dependencies: [{ id: "runtime", scope: "production" }], - config: { dependsOn: [{ id: "runtime", scope: "build" }], project: {}, tags: [] }, - }, - { - id: "consumer-build", - source: "packages/consumer-build", - dependencies: [{ id: "runtime", scope: "build" }], - config: { dependsOn: [{ id: "runtime", scope: "production" }], project: {}, tags: [] }, - }, - ]; - const environment = { - ...process.env, - PATH: `${bin}${path.delimiter}${process.env.PATH ?? ""}`, - MOON_PROJECTS_JSON: JSON.stringify({ projects }), - MOON_STUB_MARKER: path.join(root, "moon.marker"), - MOON_STUB_RUNTIME: process.execPath, - MOON_STUB_SCRIPT: script, - }; - delete environment.MOON_BIN; - const probe = [ - 'import { moonProjectsById, releaseOrder } from "./tools/release/release-graph.mjs";', - 'const projects = moonProjectsById("moon-query-test");', - 'const graph = Object.fromEntries(projects);', - 'const products = {', - ' runtime: { path: "packages/runtime" },', - ' "consumer-production": { path: "packages/consumer-production", compatibility_versions: { runtime: { source_product: "runtime" } } },', - ' "consumer-build": { path: "packages/consumer-build" },', - '};', - 'process.stdout.write(JSON.stringify({', - ' productionScope: graph["consumer-production"].dependencies[0].scope,', - ' buildScope: graph["consumer-build"].dependencies[0].scope,', - ' order: releaseOrder(products, graph, new Set(Object.keys(products)), "moon-query-test"),', - '}));', - ].join("\n"); - const result = spawnSync(process.execPath, ["-e", probe], { - cwd: ROOT, - env: environment, - stdio: ["ignore", "pipe", "pipe"], - }); - expect(new TextDecoder().decode(result.stderr)).toBe(""); - expect(result.status).toBe(0); - expect(JSON.parse(new TextDecoder().decode(result.stdout))).toEqual({ - productionScope: "production", - buildScope: "build", - order: ["consumer-build", "runtime", "consumer-production"], - }); - }); - - test("uses PATH by default and ignores poison home-directory installations", async () => { - const root = await fixture("path"); - const home = path.join(root, "home"); - const bin = path.join(root, "bin"); - const script = path.join(root, "moon-stub.mjs"); - const marker = path.join(root, "moon.marker"); - await mkdir(path.join(home, ".proto", "bin"), { recursive: true }); - const poison = path.join(home, ".proto", "bin", "moon"); - await writeFile(poison, "#!/bin/sh\nexit 99\n"); - await chmod(poison, 0o755); - await writeMoonStub(bin, script); - - const environment = { - ...process.env, - HOME: home, - PATH: `${bin}${path.delimiter}${process.env.PATH ?? ""}`, - MOON_PROJECTS_JSON: await moonProjectsJson(), - MOON_STUB_MARKER: marker, - MOON_STUB_RUNTIME: process.execPath, - MOON_STUB_SCRIPT: script, - }; - delete environment.MOON_BIN; - const result = spawnSync(process.execPath, [CHECK], { - cwd: ROOT, - env: environment, - stdio: ["ignore", "pipe", "pipe"], - }); - - expect(new TextDecoder().decode(result.stderr)).toBe(""); - expect(result.status).toBe(0); - expect(await readFile(marker, "utf8")).toBe("path-stub\n"); - }); - - test("reports a missing Moon command cleanly", () => { - expect(moonEnvironment({ PATH: "/verified", PROTO_VERSION: "poison" })).toEqual({ - PATH: "/verified", - }); - - const missing = path.join(tmpdir(), `missing-moon-${randomUUID()}`); - const result = spawnSync(process.execPath, [CHECK], { - cwd: ROOT, - env: { ...process.env, MOON_BIN: missing }, - stdio: ["ignore", "pipe", "pipe"], - }); - expect(result.status).toBe(2); - expect(new TextDecoder().decode(result.stderr)).toContain("Moon 2.5.4 is required"); - - const graphResult = spawnSync(process.execPath, [RELEASE_PLAN, "--changed-file", "README.md", "--format", "json"], { - cwd: ROOT, - env: { ...process.env, MOON_BIN: missing }, - stdio: ["ignore", "pipe", "pipe"], - }); - expect(graphResult.status).toBe(1); - expect(new TextDecoder().decode(graphResult.stderr)).toContain(`${missing} failed to start`); - }); - - test("rejects an ambient Moon version that differs from .prototools", async () => { - const root = await fixture("wrong-version"); - const bin = path.join(root, "bin"); - const script = path.join(root, "moon-stub.mjs"); - await writeMoonStub(bin, script); - const environment = { - ...process.env, - PATH: `${bin}${path.delimiter}${process.env.PATH ?? ""}`, - MOON_STUB_RUNTIME: process.execPath, - MOON_STUB_SCRIPT: script, - MOON_STUB_VERSION: "2.4.0", - }; - delete environment.MOON_BIN; - - expect(() => moonCommand(environment)).toThrow("Moon 2.5.4 is required, but moon reported 2.4.0"); - }); - -}); diff --git a/tools/release/moon-producer-receipt.test.mts b/tools/release/moon-producer-receipt.test.mts new file mode 100644 index 000000000..43d53db59 --- /dev/null +++ b/tools/release/moon-producer-receipt.test.mts @@ -0,0 +1,62 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + producerHashes, + producerTypescriptVersion, +} from '../../.github/scripts/moon-producer-receipt.mts'; + +test('producer compiler identity resolves from its isolated workspace dependencies', () => { + const root = mkdtempSync(path.join(tmpdir(), 'moon-producer-toolchain-')); + try { + const owner = path.join(root, 'sdks', 'query'); + const compiler = path.join(owner, 'node_modules', 'typescript'); + mkdirSync(compiler, { recursive: true }); + writeFileSync(path.join(owner, 'package.json'), '{"name":"query"}'); + writeFileSync(path.join(compiler, 'package.json'), '{"name":"typescript","version":"6.0.3"}'); + assert.equal(producerTypescriptVersion(owner), '6.0.3'); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('producer receipts require complete Moon ancestry and retain actual cache behavior', () => { + const root = mkdtempSync(path.join(tmpdir(), 'moon-producer-receipt-')); + try { + mkdirSync(path.join(root, 'hashes')); + const producer = 'a'.repeat(64), + dependency = 'b'.repeat(64); + const report = { + actions: [ + { + node: { action: 'run-task', params: { target: 'sdk:package' } }, + status: 'passed', + operations: [{ meta: { type: 'hash-generation', hash: producer } }], + }, + ], + }; + const manifest = (hash, target, deps) => + writeFileSync( + path.join(root, 'hashes', `${hash}.json`), + JSON.stringify([{ target, deps, toolchains: ['bun'] }]), + ); + manifest(producer, 'sdk:package', { 'sdk:build': dependency }); + manifest(dependency, 'sdk:build', {}); + const fresh = producerHashes(report, root, 'sdk:package'); + assert.equal(fresh.eligible, true); + assert.equal(fresh.cacheHit, false); + assert.equal(fresh.hashes.length, 2); + report.actions[0].status = 'cached'; + assert.equal(producerHashes(report, root, 'sdk:package').cacheHit, true); + manifest(producer, 'sdk:package', { 'sdk:build': 'passthrough' }); + assert.match(producerHashes(report, root, 'sdk:package').reason, /incomplete producer hash/); + report.actions[0].operations = []; + assert.match(producerHashes(report, root, 'sdk:package').reason, /hashing is disabled/); + report.actions[0].status = 'failed'; + assert.match(producerHashes(report, root, 'sdk:package').reason, /did not complete/); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/tools/release/moon.yml b/tools/release/moon.yml index 5208756d7..87dd9d9c6 100644 --- a/tools/release/moon.yml +++ b/tools/release/moon.yml @@ -1,749 +1,214 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "release-tools" -language: "javascript" -layer: "tool" -stack: "infrastructure" -tags: ["tools", "release"] +$schema: https://moonrepo.dev/schemas/project.json +id: release-tools +language: typescript +layer: tool +stack: infrastructure +tags: + - javascript-quality + - tools + - release dependsOn: - - id: "artifact-packaging" - scope: "build" - - id: "shared-test-fixtures" - scope: "development" - - id: "extension-runtime-contract" - scope: "build" - - id: "extensions" - scope: "build" - - id: "extension-artifacts-wasix" - scope: "build" - - id: "extension-artifacts-native" - scope: "build" - - id: "liboliphaunt-native" - scope: "build" - - id: "liboliphaunt-wasix" - scope: "build" - - "oliphaunt-broker" - - "oliphaunt-js" - - "oliphaunt-kotlin" - - "oliphaunt-node-direct" - - "oliphaunt-react-native" - - "oliphaunt-rust" - - "oliphaunt-swift" - - "oliphaunt-wasix-rust" - - "oliphaunt-wasix-ts" - - "oliphaunt-wasix-tools-ts" - - "oliphaunt-wasix-napi" - + - id: shared-test-fixtures + scope: development + - id: extension-runtime-contract + scope: build + - id: extensions + scope: build + - id: extension-artifacts-wasix + scope: build + - id: extension-artifacts-native + scope: build + - id: liboliphaunt-native + scope: build + - id: liboliphaunt-wasix + scope: build + - oliphaunt-broker + - oliphaunt-js + - oliphaunt-kotlin + - oliphaunt-node-direct + - oliphaunt-react-native + - oliphaunt-rust + - oliphaunt-query + - liboliphaunt-native-bindings + - oliphaunt-query-ts + - oliphaunt-swift + - oliphaunt-wasix-rust + - oliphaunt-wasix-ts + - oliphaunt-wasix-tools-ts + - oliphaunt-wasix-napi project: - title: "Release Tools" + title: Release Tools description: "Release-please identity, product-local metadata, packaging gates, and release workflow helpers." - owner: "oliphaunt" - + owner: oliphaunt owners: defaultOwner: "@oliphaunt/core" paths: - "**/*": ["@oliphaunt/core"] - + "**/*": + - "@oliphaunt/core" +fileGroups: + source: + - "*.{mts,sh}" + - "!*.test.mts" tasks: - js-sdk-package: - tags: ["release", "artifact-package", "ci-js-sdk-package"] - command: "tools/dev/bun.sh tools/release/build-sdk-ci-artifacts.mjs oliphaunt-js" - deps: - - "oliphaunt-js:package" - inputs: - - "@group(legal-files)" - - "@group(pnpm-workspace)" - - "@group(release-archive-contract)" - - "/tools/release/build-sdk-ci-artifacts.mjs" - - "/tools/release/check-staged-artifacts.mjs" - - "/tools/release/sdk-artifacts/js.mjs" - - "/tools/release/sdk-artifacts/npm.mjs" - - "/tools/release/sdk-artifacts/shared.mjs" - - "/tools/release/source-only-sdk-package.mjs" - - "/src/shared/js-core/tools/stage-package.mjs" - - "/tools/dev/bun.sh" - - "/src/sources/tools/source-fetch-core.mjs" - outputs: - - "/target/sdk-artifacts/oliphaunt-js/**/*" - options: - cache: true - runFromWorkspaceRoot: true - rust-sdk-package: - tags: ["release", "artifact-package", "ci-rust-sdk-package"] - command: "tools/dev/bun.sh tools/release/build-cargo-sdk-ci-artifacts.mjs oliphaunt-rust" - deps: - - "oliphaunt-rust:package" - env: - CARGO_TARGET_DIR: "target/moon/release-tools/rust-sdk-package" - inputs: - - "@group(legal-files)" - - "@group(cargo-workspace)" - - "@group(release-archive-contract)" - - "@group(release-target-contract)" - - "/tools/release/build-cargo-sdk-ci-artifacts.mjs" - - "/tools/release/build-sdk-ci-artifacts.mjs" - - project: "artifact-packaging" - group: "source" - - "/tools/release/cargo-source-package.mjs" - - "/tools/release/check-cargo-package-test-closure.mjs" - - "/tools/release/check-staged-artifacts.mjs" - - "/tools/release/contrib-carriers.mjs" - - "/tools/release/prepare-rust-release-source.mjs" - - "/tools/release/release-graph.mjs" - - "/tools/release/rust-native-targets.mjs" - - "/tools/release/sdk-artifacts/rust.mjs" - - "/tools/release/sdk-artifacts/shared.mjs" - - "/tools/dev/bun.sh" - - "/src/sources/tools/source-fetch-core.mjs" - outputs: - - "/target/sdk-artifacts/oliphaunt-rust/**/*" - options: - cache: true - runFromWorkspaceRoot: true - rust-sdk-consumer: - tags: ["release", "runtime", "ci-rust-sdk-package"] - command: >- - src/sdks/rust/tools/check-release-consumer.sh build - target/sdk-artifacts/oliphaunt-rust - target/native-extension-proof/oliphaunt-rust-release-consumer - deps: - - "release-tools:rust-sdk-package" - env: - CARGO_TARGET_DIR: "target/moon/release-tools/rust-sdk-consumer" - inputs: - - "/rust-toolchain.toml" - - "/src/sdks/rust/tests/release-consumer/**/*" - - "/src/sdks/rust/tools/check-release-consumer.sh" - - "/tools/dev/bun.sh" - outputs: - - "/target/native-extension-proof/oliphaunt-rust-release-consumer" - options: - cache: true - runFromWorkspaceRoot: true - kotlin-sdk-package: - tags: ["release", "artifact-package", "ci-kotlin-sdk-package"] - command: "tools/dev/bun.sh tools/release/build-sdk-ci-artifacts.mjs oliphaunt-kotlin" - deps: - - "oliphaunt-kotlin:package" - inputs: - - "@group(legal-files)" - - "@group(release-archive-contract)" - - "/tools/release/build-sdk-ci-artifacts.mjs" - - "/tools/release/check-staged-artifacts.mjs" - - "/tools/release/sdk-artifacts/kotlin.mjs" - - "/tools/release/sdk-artifacts/shared.mjs" - - "/tools/dev/bun.sh" - - "/src/sources/tools/source-fetch-core.mjs" - outputs: - - "/target/sdk-artifacts/oliphaunt-kotlin/**/*" - options: - cache: local - runFromWorkspaceRoot: true - kotlin-maven-staging: - tags: ["release", "artifact-package", "ci-kotlin-maven-staging"] - command: "tools/dev/bun.sh tools/release/kotlin-maven-staging.mjs" - deps: - - "release-tools:kotlin-sdk-package" - inputs: - - "/src/sdks/kotlin/gradle.properties" - - "/tools/release/kotlin-maven-staging.mjs" - - "/tools/release/maven-central-contract.mjs" - - "/target/sdk-artifacts/oliphaunt-kotlin/maven/**/*" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: true - swift-sdk-package: - tags: ["release", "artifact-package", "ci-swift-sdk-package"] - command: "tools/dev/bun.sh tools/release/build-sdk-ci-artifacts.mjs oliphaunt-swift" - env: - OLIPHAUNT_SWIFT_RELEASE_ASSET_DIR: "target/liboliphaunt/abi-compatible-release-assets/ios-datum64" - deps: - - "oliphaunt-swift:package" - - "liboliphaunt-native:finalize-runtime-ios-abi" - inputs: - - "@group(legal-files)" - - "@group(release-archive-contract)" - - "@group(release-target-contract)" - - "/tools/release/build-sdk-ci-artifacts.mjs" - - "/tools/release/check-staged-artifacts.mjs" - - "/tools/release/contrib-carriers.mjs" - - "/tools/release/ios-carrier-manifest.mjs" - - "/tools/release/prepare-swift-release-consumer.mjs" - - "/tools/release/release-graph.mjs" - - "/tools/release/sdk-artifacts/shared.mjs" - - "/tools/release/sdk-artifacts/swift.mjs" - - "/tools/release/swift-source-carrier-contract.mjs" - - "/Package.swift" - - "/src/extensions/generated/sdk/extensions.json" - - "/target/liboliphaunt/abi-compatible-release-assets/ios-datum64/**/*" - - "/tools/dev/bun.sh" - - "/src/sources/tools/source-fetch-core.mjs" - outputs: - - "/target/sdk-artifacts/oliphaunt-swift/**/*" - options: - cache: local - runFromWorkspaceRoot: true - react-native-sdk-package: - tags: ["release", "artifact-package", "ci-react-native-sdk-package"] - command: "tools/dev/bun.sh tools/release/build-sdk-ci-artifacts.mjs oliphaunt-react-native" - env: - OLIPHAUNT_REACT_NATIVE_IOS_RELEASE_ASSET_DIR: "target/liboliphaunt/abi-compatible-release-assets/ios-datum64" - deps: - - "oliphaunt-react-native:package" - - "liboliphaunt-native:finalize-runtime-ios-abi" - inputs: - - "@group(legal-files)" - - "@group(pnpm-workspace)" - - "@group(release-archive-contract)" - - "@group(release-target-contract)" - - "/tools/release/build-sdk-ci-artifacts.mjs" - - "/tools/release/check-staged-artifacts.mjs" - - "/tools/release/contrib-carriers.mjs" - - "/tools/release/ios-carrier-manifest.mjs" - - "/tools/release/release-graph.mjs" - - "/tools/release/sdk-artifacts/npm.mjs" - - "/tools/release/sdk-artifacts/react-native.mjs" - - "/tools/release/sdk-artifacts/shared.mjs" - - "/tools/release/source-only-sdk-package.mjs" - - "/src/shared/js-core/tools/stage-package.mjs" - - "/src/runtimes/liboliphaunt/native/icu-npm/**/*" - - "/examples/react-native-expo/package.json" - - "/src/sdks/react-native/tools/ios-icu-autolinking.test.mjs" - - "/target/liboliphaunt/abi-compatible-release-assets/ios-datum64/**/*" - - "/tools/dev/bun.sh" - - "/src/sources/tools/source-fetch-core.mjs" - outputs: - - "/target/sdk-artifacts/oliphaunt-react-native/**/*" - options: - cache: true - runFromWorkspaceRoot: true - wasix-rust-package: - tags: ["release", "artifact-package", "ci-wasix-rust-package"] - command: "tools/dev/bun.sh tools/release/build-cargo-sdk-ci-artifacts.mjs oliphaunt-wasix-rust" - deps: - - "oliphaunt-wasix-rust:package" - env: - CARGO_TARGET_DIR: "target/moon/release-tools/wasix-rust-package" - inputs: - - "@group(legal-files)" - - "@group(cargo-workspace)" - - "@group(release-archive-contract)" - - "@group(release-target-contract)" - - "/tools/release/build-cargo-sdk-ci-artifacts.mjs" - - "/tools/release/build-sdk-ci-artifacts.mjs" - - project: "artifact-packaging" - group: "source" - - "/tools/release/cargo-source-package.mjs" - - "/tools/release/check-cargo-package-test-closure.mjs" - - "/tools/release/check-staged-artifacts.mjs" - - "/tools/release/contrib-carriers.mjs" - - "/tools/release/package_oliphaunt_wasix_sdk_crate.mjs" - - "/tools/release/release-graph.mjs" - - "/tools/release/sdk-artifacts/shared.mjs" - - "/tools/release/sdk-artifacts/wasix-rust.mjs" - - "/tools/release/wasix-cargo-toolchain-policy.mjs" - - "/src/runtimes/liboliphaunt/icu/**/*" - - project: "liboliphaunt-wasix" - group: "crates" - - "/src/sources/toolchains/wasix.toml" - - "/tools/dev/bun.sh" - - "/src/sources/tools/source-fetch-core.mjs" - outputs: - - "/target/sdk-artifacts/oliphaunt-wasix-rust/**/*" - options: - cache: true - runFromWorkspaceRoot: true - wasix-ts-sdk-package: - tags: ["release", "artifact-package", "ci-wasix-ts-sdk-package"] - command: "tools/dev/bun.sh tools/release/build-sdk-ci-artifacts.mjs oliphaunt-wasix-ts" - deps: - - "oliphaunt-wasix-ts:package" - - "oliphaunt-wasix-tools-ts:package" - - "liboliphaunt-wasix:runtime-portable" - inputs: - - "@group(legal-files)" - - "@group(pnpm-workspace)" - - "@group(release-archive-contract)" - - "/tools/release/build-sdk-ci-artifacts.mjs" - - "/tools/release/check-staged-artifacts.mjs" - - "/tools/release/npm-trusted-publishing.mjs" - - "/tools/release/sdk-artifacts/shared.mjs" - - "/tools/release/sdk-artifacts/wasix-tools-ts.mjs" - - "/tools/release/sdk-artifacts/wasix-ts.mjs" - - "/tools/release/wasix-tools-typescript-package.mjs" - - "/tools/release/wasix-typescript-package.mjs" - - "/src/shared/js-core/tools/stage-package.mjs" - - "/tools/dev/bun.sh" - outputs: - - "/target/sdk-artifacts/oliphaunt-wasix-ts/**/*" - options: - cache: true - runFromWorkspaceRoot: true - native-extension-lifecycle: - tags: ["release", "integration", "ci-native-extension-lifecycle"] - command: "tools/release/run-native-extension-lifecycle-proof.sh" - deps: - - "extension-artifacts-native:build-target" - - "liboliphaunt-native:build-runtime-desktop-target" - - "release-tools:broker-runtime" - - "release-tools:rust-sdk-package" - inputs: - - "/src/runtimes/liboliphaunt/wasix-postmaster/lib/process-supervision.sh" - - "/tools/native-extension-proof/**/*" - - "/tools/release/run-native-extension-lifecycle-proof.sh" - options: - cache: false - runFromWorkspaceRoot: true metadata: - tags: ["policy", "assertion", "quality", "static"] - command: "tools/dev/bun.sh tools/release/release-metadata-check.mjs" - inputs: - - "/.moon/workspace.yml" - - "/.moon/toolchains.yml" - - "/.github/workflows/ci.yml" - - "/.github/workflows/release.yml" - - "/.release-please-manifest.json" - - "/benchmarks/moon.yml" - - "/Cargo.lock" - - "/Cargo.toml" - - "/coverage/baseline.toml" - - "/examples/moon.yml" - - "/examples/**/Cargo.toml" - - "/moon.yml" - - "/Package.swift" - - "@group(pnpm-workspace)" - - "/release-please-config.json" - - "/src/**/CHANGELOG.md" - - "/src/**/Cargo.toml" - - "/src/**/LIBOLIPHAUNT_VERSION" - - "/src/**/Package.swift" - - "/src/**/VERSION" - - "/src/**/gradle.properties" - - "/src/**/moon.yml" - - "/src/**/package.json" - - "/src/**/release.toml" - - "/src/**/targets/**/*.toml" - - "/src/extensions/catalog/**/*" - - "/src/extensions/contrib/*.toml" - - "/src/extensions/evidence/**/*.toml" - - "/src/extensions/external/**/recipe.toml" - - "/src/extensions/external/**/source.toml" - - "/src/extensions/external/**/tools/**/*" - - "/src/extensions/external/**/upstream-license-data.json" - - "/src/extensions/generated/**/*" - - "/src/extensions/model/**/*" - - "/src/extensions/schemas/**/*" - - "/src/extensions/tools/**/*" - - "/src/postgres/versions/*/source.toml" - - "/src/runtimes/liboliphaunt/licenses/**/*" - - "/src/runtimes/wasix-napi/tools/build-native.sh" - - project: "shared-test-fixtures" - group: "fixtures" - - "/src/sources/**/*.toml" - - "/tools/**/moon.yml" - - "/tools/graph/**/*" + tags: + - policy + - assertion + - quality + - static + command: bash tools/release/release-metadata-check.sh + inputs: + - /tools/packaging/**/* + - /src/database-resources/contracts/**/* + - /tools/release/**/* + - /.moon/workspace.yml + - /.moon/toolchains.yml + - /.github/workflows/ci.yml + - /.github/workflows/release.yml + - /.release-please-manifest.json + - /src/benchmarks/moon.yml + - /Cargo.lock + - /Cargo.toml + - /src/examples/moon.yml + - /src/examples/**/Cargo.toml + - /moon.yml + - /Package.swift + - "@group(bun-workspace)" + - /release-please-config.json + - /**/CHANGELOG.md + - /**/Cargo.toml + - /**/LIBOLIPHAUNT_VERSION + - /**/Package.swift + - /**/VERSION + - /**/gradle.properties + - /**/moon.yml + - /**/package.json + - /**/release.toml + - /**/targets/**/*.toml + - /src/extensions/catalog/**/* + - /src/extensions/contrib/*.toml + - /src/extensions/evidence/**/*.toml + - /src/extensions/external/**/recipe.toml + - /src/extensions/external/**/source.toml + - /src/extensions/external/**/tools/**/* + - /src/extensions/external/**/upstream-license-data.json + - /src/extensions/generated/**/* + - /src/extensions/model/**/* + - /src/extensions/schemas/**/* + - /src/extensions/tools/**/* + - /src/third-party/postgres/source.toml + - "@group(upstream-licenses)" + - /src/sdks/ts-wasix/node-addon/tools/build-native.sh + - project: shared-test-fixtures + group: fixtures + - /src/third-party/**/source.toml + - /src/runtimes/*/sources/*.toml + - /src/runtimes/*/toolchain.toml + - /tools/dev/*.toml + - /tools/release/npm-publisher.toml + - /tools/**/moon.yml + - /tools/ci/**/* - "**/*" - - "!/tools/release/**/*.test.mjs" + - "!/tools/release/**/*.test.{mjs,mts}" - "!/tools/release/**/*.md" - - "/tools/test/create-broker-release-fixture.mjs" - - "/tools/test/create-liboliphaunt-release-fixture.mjs" - - "/tools/test/release-fixture-utils.mjs" options: cache: false runFromWorkspaceRoot: true runInCI: true - unit: - tags: ["quality", "unit", "requires-rust"] - command: "tools/dev/bun.sh tools/release/release-check.mjs --mutation-tests-only --mutation-scope=release" - inputs: - - "/.github/scripts/bootstrap-registry-*" - - "/.github/scripts/download-bootstrap-*" - - "/.github/scripts/download-build-artifacts*" - - "/.github/scripts/download-wasix-runtime-*" - - "/.github/scripts/manage-release-*" - - "/.github/scripts/merge-checksum-*" - - "/.github/scripts/normalize-release-*" - - "/.github/scripts/registry-bootstrap-*" - - "/.github/scripts/*release*.mjs" - - "/.github/scripts/require-workflow-success*" - - "/.github/scripts/setup-native-build-tools*" - - "/.github/scripts/verify-github-oidc-*" - - "/tools/dev/bun.sh" - - "/tools/dev/capture-command-output.mjs" - - "/tools/dev/moon-command.mjs" + test: + tags: + - quality + - unit + - requires-rust + command: bash tools/release/release-check.sh --mutation-tests-only + inputs: + - /src/runtimes/liboliphaunt-wasix/tools/download-assets.sh + - /src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts + - /tools/packaging/**/* + - /src/database-resources/contracts/**/* + - /tools/release/**/* + - /.github/scripts/bootstrap-registry-* + - /.github/scripts/download-bootstrap-* + - /.github/scripts/download-completed-bootstrap* + - /.github/scripts/download-build-artifacts* + - /.github/scripts/download-wasix-runtime-* + - /.github/scripts/manage-release-* + - /.github/scripts/merge-checksum-* + - /.github/scripts/normalize-release-* + - /.github/scripts/registry-bootstrap-* + - "/.github/scripts/*release*.{mts,sh}" + - /.github/scripts/require-workflow-success* + - /.github/scripts/workflow-run-metadata.mts + - /.github/scripts/setup-native-build-tools* + - /.github/scripts/verify-github-oidc-* + - /tools/ci/with-projects.sh + - /.prototools + - /tools/dev/bun.sh + - /src/sdks/kotlin/tools/kotlin-maven-staging.mts - "**/*" - "!/tools/release/**/*.md" - - "/tools/test/**/*" options: cache: false runFromWorkspaceRoot: true graph-unit: - tags: ["quality", "unit"] - command: "tools/dev/bun.sh test --isolate --max-concurrency=1 --timeout=30000 tools/release/native-extension-lifecycle-receipts.test.mjs tools/release/product-task-model.test.mjs tools/release/release-candidate-sync.test.mjs" - inputs: - - "/.moon/tasks/**/*" - - "/.moon/toolchains.yml" - - "/.moon/workspace.yml" - - "/benchmarks/moon.yml" - - "/examples/moon.yml" - - "/moon.yml" - - "/.release-please-manifest.json" - - "/Cargo.toml" - - "/Package.swift" - - "/package.json" - - "/release-please-config.json" - - "/src/**/release.toml" - - "/src/**/targets/**/*.toml" - - "/src/**/moon.yml" - - "/tools/graph/**/*" - - "/tools/**/moon.yml" - - "/tools/dev/capture-command-output.mjs" - - "/tools/dev/moon-command.mjs" - - "/src/sources/tools/source-fetch-core.mjs" - - "/tools/release/artifact_target_matrix.mjs" - - "/tools/release/contrib-carriers.mjs" - - "/tools/release/extension-artifact-archive-policy.mjs" - - project: "extension-runtime-contract" - group: "contract" - - "/tools/release/extension-artifact-inventory.mjs" - - "/tools/release/extension-registry-packages.mjs" - - "/src/shared/extension-runtime-contract/extension-target-profiles.mjs" - - "/tools/release/extension-upstream-licenses.mjs" - - "/tools/release/native-extension-asset-index-contract.mjs" - - "/tools/release/native-extension-lifecycle-receipts.test.mjs" - - "/tools/release/optimize_native_runtime_payload.mjs" - - "/tools/release/platform-compatibility-policy.mjs" - - "/tools/release/product-task-model.test.mjs" - - "/tools/release/release-artifact-targets.mjs" - - "/tools/release/release-candidate-sync.mjs" - - "/tools/release/release-candidate-sync.test.mjs" + tags: + - quality + - unit + inputs: + - /.moon/tasks/**/* + - /.moon/toolchains.yml + - /.moon/workspace.yml + - /src/benchmarks/moon.yml + - /src/examples/moon.yml + - /moon.yml + - /.release-please-manifest.json + - /Cargo.toml + - /Package.swift + - /package.json + - /release-please-config.json + - /**/release.toml + - /**/targets/**/*.toml + - /**/moon.yml + - /tools/ci/**/* + - /tools/**/moon.yml + - /src/third-party/tools/source-fetch-core.mts + - /tools/release/artifact-target-matrix.mts + - /src/extensions/artifacts/packages/tools/contrib-carriers.mts + - /src/extensions/tools/extension-artifact-archive-policy.mts + - project: extension-runtime-contract + group: contract + - /src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts + - /src/extensions/artifacts/packages/tools/extension-registry-packages.mts + - /src/extensions/contracts/extension-target-profiles.mts + - /src/extensions/tools/extension-upstream-licenses.mts + - /src/extensions/artifacts/native/tools/native-extension-asset-index-contract.mts + - /src/runtimes/liboliphaunt-native/tools/native-runtime-payload.mts + - /tools/release/platform-compatibility-policy.mts + - /tools/release/release-artifact-targets.mts + - /tools/release/prepare-release-candidate.mts + - /tools/release/prepare-release-candidate.test.mts - "@group(release-archive-contract)" - - "/tools/release/release-graph.mjs" - - "/tools/release/stage-native-extension-lifecycle.mjs" - - "/tools/release/verify-native-extension-lifecycle-receipts.mjs" - - "/tools/release/wasix-cargo-artifact-contract.mjs" - - "/tools/release/windows-vc-runtime-closure.mjs" - - "/tools/release/write-native-extension-lifecycle-receipt.mjs" - - "/tools/test/fd-backed-spawn-sync.mjs" + - /tools/release/release-graph.mts + - /src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts + - /tools/packaging/windows-vc-runtime-closure.mts + - package.json + - /bun.lock options: cache: true runFromWorkspaceRoot: true + command: bash tools/ci/with-projects.sh test --timeout=30000 ./tools/release/prepare-release-candidate.test.mts check: - tags: ["policy", "aggregate", "quality"] - command: "true" - deps: - - "release-tools:metadata" - - "release-tools:unit" - - "policy-tools:unit" - inputs: [] - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false - broker-dependency-license-audit: - tags: ["policy", "assertion", "quality", "static", "requires-rust"] - command: "tools/dev/bun.sh tools/release/broker-dependency-license-contract.mjs audit-contract" - inputs: - - "@group(cargo-workspace)" - - "/benchmarks/**/Cargo.toml" - - "/examples/**/Cargo.toml" - - "/src/**/Cargo.toml" - - "/tools/**/Cargo.toml" - - "/src/runtimes/broker/dependency-licenses.json" - - "/src/runtimes/broker/dependency-license-blobs/**/*" - - "/tools/dev/capture-command-output.mjs" - - "/tools/release/broker-dependency-license-contract.mjs" - - "/tools/release/release-directory-safety.mjs" - options: - cache: false - runFromWorkspaceRoot: true - - broker-runtime: - tags: ["release", "artifact", "in-place-finalizer-input", "ci-broker-runtime"] - command: "bash tools/release/package-broker-assets.sh" - env: - CARGO_TARGET_DIR: "target/moon/release-tools/broker-runtime" - OLIPHAUNT_RELEASE_ASSET_PARTIAL: "1" - inputs: - - "@group(legal-files)" - - "@group(cargo-workspace)" - - project: "oliphaunt-broker" - group: "code" - - project: "oliphaunt-rust" - group: "code" - - "/tools/release/build-linux-broker-baseline.sh" - - "/tools/release/broker-dependency-license-contract.mjs" - - "/tools/release/check-linux-consumer-baseline.sh" - - "/tools/release/linux-abi-baseline.test.mjs" - - "/tools/release/package-broker-assets.sh" - - "/tools/release/check-broker-release-assets.mjs" - - "/tools/release/platform-compatibility-policy.mjs" - - "/tools/release/platform-compatibility-policy.test.mjs" - - "/tools/release/platform-binary-contract.mjs" - - "/tools/release/platform-binary-contract.test.mjs" - - "/tools/release/release-asset-validation.mjs" - - "/src/shared/extension-runtime-contract/extension-target-profiles.mjs" - - "/tools/release/release-artifact-targets.mjs" - - "@group(release-archive-contract)" - - "/tools/policy/moon.mjs" - - "/tools/release/artifact_target_matrix.mjs" - - "/release-please-config.json" - outputs: - - "/target/oliphaunt-broker/release-assets/**/*" - options: - cache: false - runFromWorkspaceRoot: true - - broker-release-assets: - tags: ["release", "artifact-package", "in-place-finalizer", "ci-broker-release-assets"] - command: "tools/dev/bun.sh tools/release/check-native-helper-aggregate-assets.mjs --product oliphaunt-broker" - deps: - - "release-tools:broker-runtime" - inputs: - - "@group(legal-files)" - - "@group(cargo-workspace)" - - project: "oliphaunt-broker" - group: "code" - - project: "oliphaunt-rust" - group: "code" - - "/tools/release/artifact_target_matrix.mjs" - - "/tools/release/broker-dependency-license-contract.mjs" - - "/tools/release/build-linux-broker-baseline.sh" - - "/tools/release/check-broker-release-assets.mjs" - - "/tools/release/check-linux-consumer-baseline.sh" - - "/tools/release/check-native-helper-aggregate-assets.mjs" - - "/tools/release/linux-abi-baseline.test.mjs" - - "/tools/release/package-broker-assets.sh" - - "/tools/release/platform-compatibility-policy.mjs" - - "/tools/release/platform-compatibility-policy.test.mjs" - - "/tools/release/platform-binary-contract.mjs" - - "/tools/release/platform-binary-contract.test.mjs" - - "/tools/release/release-asset-validation.mjs" - - "/src/shared/extension-runtime-contract/extension-target-profiles.mjs" - - "/tools/release/release-artifact-targets.mjs" - - "@group(release-archive-contract)" - - "/tools/release/write_checksum_manifest.mjs" - - "/tools/policy/moon.mjs" - - "/release-please-config.json" - - "/target/oliphaunt-broker/release-assets/**/*" - outputs: - - "/target/oliphaunt-broker/release-assets/**/*" - options: - cache: false - runFromWorkspaceRoot: true - - node-direct-runtime: - tags: ["release", "artifact", "in-place-finalizer-input", "ci-node-direct"] - command: "bash tools/release/package-node-direct-runtime.sh" - inputs: - - project: "oliphaunt-node-direct" - group: "code" - - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h" - - "/src/sources/toolchains/node.toml" - - "@group(legal-files)" - - "@group(release-archive-contract)" - - "/tools/release/artifact_target_matrix.mjs" - - "/tools/release/check-node-direct-release-assets.mjs" - - "/tools/release/check-linux-consumer-baseline.sh" - - "/tools/release/linux-abi-baseline.test.mjs" - - "/tools/release/platform-compatibility-policy.mjs" - - "/tools/release/platform-compatibility-policy.test.mjs" - - "/tools/release/platform-binary-contract.mjs" - - "/tools/release/platform-binary-contract.test.mjs" - - "/tools/release/extract-node-headers.mjs" - - "/tools/release/install-node-fallback.sh" - - "/tools/release/package-node-direct-runtime.sh" - - "/tools/release/release-asset-validation.mjs" - - "/src/shared/extension-runtime-contract/extension-target-profiles.mjs" - - "/tools/release/release-artifact-targets.mjs" - - "/tools/release/release_graph_query.mjs" - - "/tools/policy/moon.mjs" - - "/release-please-config.json" - outputs: - - "/target/oliphaunt-node-direct/release-assets/**/*" - - "/target/oliphaunt-node-direct/npm-packages/**/*" - options: - cache: false - runFromWorkspaceRoot: true - - node-direct-release-assets: - tags: ["release", "artifact-package", "in-place-finalizer", "ci-node-direct-release-assets"] - command: "tools/dev/bun.sh tools/release/check-native-helper-aggregate-assets.mjs --product oliphaunt-node-direct" - deps: - - "release-tools:node-direct-runtime" - inputs: - - "@group(legal-files)" - - "/pnpm-workspace.yaml" - - project: "oliphaunt-node-direct" - group: "code" - - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h" - - "/src/sources/toolchains/node.toml" - - "/tools/policy/moon.mjs" - - "/tools/release/artifact_target_matrix.mjs" - - "/tools/release/check-linux-consumer-baseline.sh" - - "/tools/release/check-native-helper-aggregate-assets.mjs" - - "/tools/release/check-node-direct-release-assets.mjs" - - "/tools/release/linux-abi-baseline.test.mjs" - - "/tools/release/platform-compatibility-policy.mjs" - - "/tools/release/platform-compatibility-policy.test.mjs" - - "/tools/release/platform-binary-contract.mjs" - - "/tools/release/platform-binary-contract.test.mjs" - - "/tools/release/release-asset-validation.mjs" - - "/src/shared/extension-runtime-contract/extension-target-profiles.mjs" - - "/tools/release/release-artifact-targets.mjs" - - "@group(release-archive-contract)" - - "/tools/release/release_graph_query.mjs" - - "/tools/release/write_checksum_manifest.mjs" - - "/release-please-config.json" - - "/target/oliphaunt-node-direct/npm-packages/**/*" - - "/target/oliphaunt-node-direct/release-assets/**/*" - outputs: - - "/target/oliphaunt-node-direct/npm-packages/**/*" - - "/target/oliphaunt-node-direct/release-assets/**/*" - options: - cache: false - runFromWorkspaceRoot: true - - wasix-napi-runtime: - tags: ["release", "artifact", "in-place-finalizer-input", "ci-wasix-napi"] - command: "bash -c 'set -e; tools/dev/bun.sh tools/release/build-extension-ci-artifacts.mjs --all --family wasix --require-wasix; exec bash src/runtimes/wasix-napi/tools/build-native.sh'" - deps: - - "liboliphaunt-wasix:runtime-aot" - - "extension-artifacts-wasix:build-target" - inputs: - - "@group(cargo-workspace)" - - "@group(legal-files)" - - project: "extensions" - group: "package" - - project: "liboliphaunt-wasix" - group: "release-metadata" - - project: "extension-runtime-contract" - group: "contract" - - "/src/runtimes/wasix-napi/Cargo.toml" - - "/src/runtimes/wasix-napi/build.rs" - - "/src/runtimes/wasix-napi/package.json" - - "/src/runtimes/wasix-napi/packages/**/*" - - "/src/runtimes/wasix-napi/src/**/*" - - "/src/runtimes/wasix-napi/tools/build-native.sh" - - "/src/runtimes/wasix-napi/tools/check-build-inputs.mjs" - - "/src/runtimes/wasix-napi/tools/detect-linux-libc.mjs" - - "/src/runtimes/wasix-napi/tools/package-platform.mjs" - - "/src/runtimes/wasix-napi/tools/portable-command.mjs" - - "/src/runtimes/wasix-napi/tools/smoke-packaged-addon.mjs" - - "/src/bindings/wasix-ts/tools/pgwire-client.mjs" - - project: "oliphaunt-wasix-rust" - group: "code" - - project: "liboliphaunt-wasix" - group: "crates" - - "/src/runtimes/liboliphaunt/icu/**/*" - - "/target/oliphaunt-wasix/assets/**/*" - - "/target/oliphaunt-wasix/aot/**/*" - - "/target/oliphaunt-wasix/wasix-build/work/icu-wasix/share/icu/**/*" - - "/target/extensions/wasix/release-assets/**/*" - - "/target/extensions/wasix/aot-artifacts/**/*" - - "/target/extension-artifacts/**/*" - - "/tools/xtask/**/*" - - "/.prototools" - - "/src/extensions/contrib/carriers.toml" - - "/src/extensions/generated/extensions.catalog.json" - - "/src/sources/toolchains/bun.toml" - - "/src/sources/toolchains/deno.toml" - - "/tools/dev/bun.sh" - - "/tools/dev/capture-command-output.mjs" - - "/tools/dev/deno.sh" - - "/tools/dev/install-pinned-js-runtime.sh" - - "/tools/dev/moon-command.mjs" - - project: "artifact-packaging" - group: "source" - - "/tools/release/check-wasix-napi-release-assets.mjs" - - "/tools/release/build-extension-ci-artifacts.mjs" - - "/tools/release/cargo-source-package.mjs" - - "/tools/release/extension-runtime-asset-contract.mjs" - - "/tools/release/extension-upstream-licenses.mjs" - - "/tools/release/release-artifact-targets.mjs" - - "/tools/release/build-linux-wasix-napi-baseline.sh" - - "/tools/release/check-linux-consumer-baseline.sh" - - "/tools/release/contrib-carriers.mjs" - - "/tools/release/extension-registry-packages.mjs" - - "/tools/release/platform-binary-contract.mjs" - - "@group(release-target-contract)" - - "/tools/release/release-asset-validation.mjs" - - "/tools/release/release-graph.mjs" - - "@group(release-archive-contract)" - - "/tools/release/native-runtime-payload-policy.json" - - "/tools/release/tar-command.mjs" - - "/tools/release/wasix-aot-manifest.mjs" - - "/tools/release/windows-vc-runtime-closure.mjs" - outputs: - - "/target/oliphaunt-wasix-napi/release-assets/**/*" - - "/target/oliphaunt-wasix-napi/npm-packages/**/*" - options: - cache: false - runFromWorkspaceRoot: true - - postmaster-release-assets: - tags: ["release", "artifact-package", "in-place-finalizer", "ci-wasix-postmaster"] - script: | - set -eu - version="$(tr -d '\r\n' < src/runtimes/liboliphaunt/wasix-postmaster/VERSION)" - bun tools/release/merge-product-release-assets.mjs \ - --product liboliphaunt-wasix-postmaster \ - --version "$version" \ - --asset-dir target/oliphaunt-wasix-postmaster/release-assets + tags: + - policy + - aggregate + - quality deps: - - "liboliphaunt-wasix-postmaster:release-assets" + - release-tools:metadata + - release-tools:test + - release-tools:graph-unit inputs: - - "/src/runtimes/liboliphaunt/wasix-postmaster/VERSION" - - "/src/runtimes/liboliphaunt/wasix-postmaster/moon.yml" - - "/tools/release/merge-product-release-assets.mjs" - - "/tools/release/platform-compatibility-policy.mjs" - - "/tools/release/release-artifact-targets.mjs" - - "/tools/release/release-graph.mjs" - - "/target/oliphaunt-wasix-postmaster/release-assets/**/*" - outputs: - - "/target/oliphaunt-wasix-postmaster/release-assets/**/*" - options: - cache: false - runFromWorkspaceRoot: true - runInCI: true - - wasix-napi-release-assets: - tags: ["release", "artifact-package", "in-place-finalizer", "ci-wasix-napi-release-assets"] - command: "tools/dev/bun.sh tools/release/check-native-helper-aggregate-assets.mjs --product oliphaunt-wasix-napi" - deps: - - "release-tools:wasix-napi-runtime" - inputs: - - "@group(legal-files)" - - "/pnpm-workspace.yaml" - - "/src/runtimes/wasix-napi/moon.yml" - - "/src/runtimes/wasix-napi/package.json" - - "/src/runtimes/wasix-napi/packages/**/*" - - "/src/runtimes/wasix-napi/release.toml" - - project: "oliphaunt-wasix-rust" - group: "code" - - project: "liboliphaunt-wasix" - group: "crates" - - "/src/runtimes/liboliphaunt/icu/**/*" - - project: "artifact-packaging" - group: "source" - - "/tools/release/check-native-helper-aggregate-assets.mjs" - - "/tools/release/check-wasix-napi-release-assets.mjs" - - "/tools/release/build-linux-wasix-napi-baseline.sh" - - "/tools/release/check-linux-consumer-baseline.sh" - - "/tools/release/platform-binary-contract.mjs" - - "/tools/release/platform-compatibility-policy.mjs" - - "/tools/release/release-artifact-targets.mjs" - - "/tools/release/release-asset-validation.mjs" - - "@group(release-archive-contract)" - - "/tools/release/write_checksum_manifest.mjs" - - "/tools/release/native-runtime-payload-policy.json" - - "/tools/release/windows-vc-runtime-closure.mjs" - - "/target/oliphaunt-wasix-napi/npm-packages/**/*" - - "/target/oliphaunt-wasix-napi/release-assets/**/*" - outputs: - - "/target/oliphaunt-wasix-napi/npm-packages/**/*" - - "/target/oliphaunt-wasix-napi/release-assets/**/*" + [] options: cache: false runFromWorkspaceRoot: true + runInCI: false diff --git a/tools/release/native-cluster-seed-contract.mjs b/tools/release/native-cluster-seed-contract.mjs deleted file mode 100644 index 3db4dceb7..000000000 --- a/tools/release/native-cluster-seed-contract.mjs +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { lstatSync, readFileSync, readdirSync } from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -const CONTRACT = JSON.parse(readFileSync( - new URL("../../src/shared/cluster-seed-contract/contract.json", import.meta.url), - "utf8", -)); -const SHA256 = /^[0-9a-f]{64}$/u; -const CACHE_KEY = new RegExp(CONTRACT.manifests.native.cacheKeyPattern, "u"); -const DISALLOWED_CACHE_KEYS = new Set(CONTRACT.manifests.native.cacheKeyDisallowedValues); - -export function validNativeCacheKey(value) { - return CACHE_KEY.test(value) && !DISALLOWED_CACHE_KEYS.has(value); -} - -export const NATIVE_CLUSTER_SEED_TARGETS = Object.freeze( - Object.keys(CONTRACT.compatibilityKeys.native).sort(), -); - -export const NATIVE_CLUSTER_SEED_MANIFEST_KEYS = Object.freeze([ - "schema", - "layout", - "artifactRole", - "catalogProfile", - "target", - "postgresMajor", - "physicalFormat", - "compatibilityKey", - "initialSuperuser", - "icuDataVersion", - "icuDataForm", - "icuDataTreeSha256", - "runtimeFeatures", - "cacheKey", -]); - -export function nativeClusterSeedCompatibilityKey(target) { - const key = CONTRACT.compatibilityKeys.native[target]; - if (typeof key !== "string") { - throw new Error(`unsupported native cluster-seed target ${JSON.stringify(target)}`); - } - return key; -} - -export function bindNativeClusterSeedManifest(bytes, target, profile) { - const source = parseProperties(bytes, "native cluster seed producer manifest"); - const profileContract = CONTRACT.profiles[profile]; - if (profileContract === undefined) { - throw new Error(`native cluster seed producer manifest: unsupported profile ${profile}`); - } - const expectedSource = new Map([ - ["schema", CONTRACT.manifests.native.schema], - ["layout", CONTRACT.manifests.native.layout], - ["artifactRole", profileContract.artifactRole], - ["catalogProfile", profile], - ["postgresMajor", "18"], - ["physicalFormat", CONTRACT.physicalFormats.native], - ["initialSuperuser", "postgres"], - ["icuDataVersion", profile === "icu" ? CONTRACT.icu.dataVersion : ""], - ["icuDataForm", profile === "icu" ? CONTRACT.icu.dataForm : ""], - ["runtimeFeatures", profileContract.requiredRuntimeFeatures.join(",")], - ]); - const expectedSourceKeys = new Set([ - ...expectedSource.keys(), - "icuDataTreeSha256", - "cacheKey", - ]); - if (source.size !== expectedSourceKeys.size - || [...source.keys()].some((key) => !expectedSourceKeys.has(key))) { - throw new Error("native cluster seed producer manifest: expected the exact unbound producer field set"); - } - for (const [key, value] of expectedSource) { - if (source.get(key) !== value) { - throw new Error(`native cluster seed producer manifest: ${key} must be ${JSON.stringify(value)}`); - } - } - const cacheKey = source.get("cacheKey"); - if (typeof cacheKey !== "string" || !validNativeCacheKey(cacheKey)) { - throw new Error("native cluster seed producer manifest: cacheKey must be a portable identifier"); - } - const values = new Map([ - ...expectedSource, - ["target", target], - ["compatibilityKey", nativeClusterSeedCompatibilityKey(target)], - ["icuDataTreeSha256", source.get("icuDataTreeSha256") ?? ""], - ["cacheKey", cacheKey], - ]); - return Buffer.from(`${NATIVE_CLUSTER_SEED_MANIFEST_KEYS.map((key) => `${key}=${values.get(key)}`).join("\n")}\n`); -} - -export function parseProperties(bytes, label) { - const text = Buffer.from(bytes).toString("utf8"); - if (!Buffer.from(text, "utf8").equals(Buffer.from(bytes))) { - throw new Error(`${label} is not canonical UTF-8`); - } - const values = new Map(); - for (const [index, line] of text.split(/\r?\n/u).entries()) { - if (line.length === 0) continue; - const separator = line.indexOf("="); - if (separator <= 0) throw new Error(`${label}:${index + 1} is not key=value`); - const key = line.slice(0, separator); - if (values.has(key)) throw new Error(`${label}:${index + 1} repeats ${key}`); - values.set(key, line.slice(separator + 1)); - } - return values; -} - -export function validateNativeClusterSeedManifest(bytes, profile, options = {}) { - const label = options.label ?? `${profile} native cluster seed manifest`; - const target = options.target; - const compatibilityKey = nativeClusterSeedCompatibilityKey(target); - const profileContract = CONTRACT.profiles[profile]; - if (profileContract === undefined) throw new Error(`${label}: unsupported profile ${profile}`); - const values = parseProperties(bytes, label); - const expected = new Map([ - ["schema", CONTRACT.manifests.native.schema], - ["layout", CONTRACT.manifests.native.layout], - ["artifactRole", profileContract.artifactRole], - ["catalogProfile", profile], - ["postgresMajor", "18"], - ["physicalFormat", CONTRACT.physicalFormats.native], - ["target", target], - ["compatibilityKey", compatibilityKey], - ["initialSuperuser", "postgres"], - ["runtimeFeatures", profileContract.requiredRuntimeFeatures.join(",")], - ["icuDataVersion", profile === "icu" ? CONTRACT.icu.dataVersion : ""], - ["icuDataForm", profile === "icu" ? CONTRACT.icu.dataForm : ""], - ["icuDataTreeSha256", profile === "icu" ? options.icuDataTreeSha256 : ""], - ]); - if (values.size !== NATIVE_CLUSTER_SEED_MANIFEST_KEYS.length - || NATIVE_CLUSTER_SEED_MANIFEST_KEYS.some((key) => !values.has(key))) { - throw new Error(`${label}: fields must be exactly ${NATIVE_CLUSTER_SEED_MANIFEST_KEYS.join(",")}`); - } - if (!validNativeCacheKey(values.get("cacheKey") ?? "")) { - throw new Error(`${label}: cacheKey must be a portable identifier`); - } - if (profile === "icu" && !SHA256.test(options.icuDataTreeSha256 ?? "")) { - throw new Error(`${label}: requires the exact lowercase ICU data tree SHA-256`); - } - for (const [key, value] of expected) { - if (values.get(key) !== value) { - throw new Error(`${label}: ${key} must be ${JSON.stringify(value)}, got ${JSON.stringify(values.get(key))}`); - } - } - return values; -} - -export function logicalTreeSha256(rows) { - const normalized = [...rows].map(({ path: relative, bytes }) => { - if (typeof relative !== "string" || relative.length === 0 || relative.includes("\0")) { - throw new Error(`logical tree contains an invalid path: ${JSON.stringify(relative)}`); - } - const normalizedPath = relative.replaceAll("\\", "/"); - const components = normalizedPath.split("/"); - if (normalizedPath.startsWith("/") - || components.some((component) => component.length === 0 || component === "." || component === "..")) { - throw new Error(`logical tree contains an unsafe path: ${JSON.stringify(relative)}`); - } - return { path: normalizedPath, bytes: Buffer.from(bytes) }; - }); - normalized.sort((left, right) => Buffer.compare(Buffer.from(left.path), Buffer.from(right.path))); - for (let index = 1; index < normalized.length; index += 1) { - if (normalized[index - 1].path === normalized[index].path) { - throw new Error(`logical tree repeats path ${JSON.stringify(normalized[index].path)}`); - } - } - const digest = createHash("sha256"); - for (const row of normalized) { - digest.update(row.path); - digest.update(Buffer.of(0)); - digest.update(String(row.bytes.length)); - digest.update(Buffer.of(0)); - digest.update(row.bytes); - digest.update("\n"); - } - return digest.digest("hex"); -} - -export function filesystemTreeRows(root) { - const absoluteRoot = path.resolve(root); - const rows = []; - visitRegularFileTree(absoluteRoot, "logical tree", (file) => { - rows.push({ - path: path.relative(absoluteRoot, file).split(path.sep).join("/"), - bytes: readFileSync(file), - }); - }); - return rows; -} - -function visitRegularFileTree(root, label, onFile) { - const visit = (entry) => { - const metadata = lstatSync(entry); - if (metadata.isSymbolicLink()) throw new Error(`${label} contains a symlink: ${entry}`); - if (metadata.isFile()) { - onFile(entry); - return; - } - if (!metadata.isDirectory()) throw new Error(`${label} contains a special file: ${entry}`); - for (const name of readdirSync(entry).sort()) visit(path.join(entry, name)); - }; - visit(root); -} - -export function validateNativeClusterSeedDirectory(seed, profile, options = {}) { - for (const relative of [ - "files", - "files/global", - "files/pg_wal", - "files/PG_VERSION", - "files/global/pg_control", - "manifest.properties", - ]) { - const file = path.join(seed, ...relative.split("/")); - const expectedDirectory = relative === "files" - || relative === "files/global" - || relative === "files/pg_wal"; - const metadata = lstatSync(file); - if (metadata.isSymbolicLink() - || (expectedDirectory ? !metadata.isDirectory() : !metadata.isFile())) { - throw new Error(`${seed} has an unsafe or missing ${relative}`); - } - } - const pgVersion = readFileSync(path.join(seed, "files/PG_VERSION"), "utf8").trim(); - if (pgVersion !== "18") throw new Error(`${seed} has PostgreSQL ${JSON.stringify(pgVersion)}, expected 18`); - if (lstatSync(path.join(seed, "files/global/pg_control")).size === 0) { - throw new Error(`${seed} has an empty files/global/pg_control`); - } - const files = path.join(seed, "files"); - const rootEntries = new Set(readdirSync(files)); - for (const transient of ["postmaster.pid", "postmaster.opts"]) { - if (rootEntries.has(transient)) throw new Error(`${seed} contains transient ${transient}`); - } - visitRegularFileTree(files, "native cluster seed", () => {}); - const icuDataTreeSha256 = options.icuData === undefined - ? undefined - : logicalTreeSha256(filesystemTreeRows(options.icuData)); - validateNativeClusterSeedManifest(readFileSync(path.join(seed, "manifest.properties")), profile, { - target: options.target, - icuDataTreeSha256, - label: path.join(seed, "manifest.properties"), - }); - return { icuDataTreeSha256 }; -} - -function main(args) { - const values = new Map(); - for (let index = 0; index < args.length; index += 2) { - const key = args[index]; - const value = args[index + 1]; - if (!key?.startsWith("--") || value === undefined) { - throw new Error("usage: native-cluster-seed-contract.mjs --profile standard|icu --target TARGET --seed DIR [--icu-data DIR]"); - } - values.set(key.slice(2), value); - } - const profile = values.get("profile"); - const target = values.get("target"); - const seed = values.get("seed"); - if (!(profile === "standard" || profile === "icu") || target === undefined || seed === undefined) { - throw new Error("usage: native-cluster-seed-contract.mjs --profile standard|icu --target TARGET --seed DIR [--icu-data DIR]"); - } - const icuData = values.get("icu-data"); - const { icuDataTreeSha256 } = validateNativeClusterSeedDirectory(seed, profile, { icuData, target }); - process.stdout.write(`profile=${profile}\ntarget=${target}\nicuDataTreeSha256=${icuDataTreeSha256 ?? ""}\n`); -} - -if (import.meta.main) { - try { - main(process.argv.slice(2)); - } catch (error) { - console.error(`native-cluster-seed-contract.mjs: ${error instanceof Error ? error.message : String(error)}`); - process.exit(2); - } -} diff --git a/tools/release/native-cluster-seed-contract.test.mjs b/tools/release/native-cluster-seed-contract.test.mjs deleted file mode 100644 index 5cb527a66..000000000 --- a/tools/release/native-cluster-seed-contract.test.mjs +++ /dev/null @@ -1,145 +0,0 @@ -import { expect, test } from "bun:test"; -import { - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { - bindNativeClusterSeedManifest, - logicalTreeSha256, - validateNativeClusterSeedDirectory, - validateNativeClusterSeedManifest, -} from "./native-cluster-seed-contract.mjs"; - -function fixture(name) { - return readFileSync(new URL(`../../src/shared/cluster-seed-contract/fixtures/${name}`, import.meta.url)); -} - -test("keeps process-argument profile probes independent of the host code page", () => { - const probe = readFileSync( - new URL("../../src/shared/cluster-seed-contract/profile-probe.json", import.meta.url), - ); - expect(probe.every((byte) => byte <= 0x7f)).toBe(true); -}); - -test("validates independent standard and ICU native cluster seed roles", () => { - const target = "linux-x64-gnu"; - const digest = logicalTreeSha256([ - { path: "icudt76l/coll/en.res", bytes: Buffer.from("en\n") }, - { path: "icudt76l/root.res", bytes: Buffer.from("root\n") }, - ]); - expect(() => validateNativeClusterSeedManifest(fixture("native-standard.valid.properties"), "standard", { target })).not.toThrow(); - expect(() => validateNativeClusterSeedManifest(fixture("native-icu.valid.properties"), "icu", { - target, - icuDataTreeSha256: "a".repeat(64), - })).not.toThrow(); - expect(() => validateNativeClusterSeedManifest(fixture("native-icu.valid.properties"), "icu", { - target, - icuDataTreeSha256: digest, - })).toThrow(/icuDataTreeSha256/u); -}); - -test("rejects the shared malformed, extra-field, cache-key, target, and profile vectors", () => { - for (const name of [ - "native-malformed.invalid.properties", - "native-whitespace.invalid.properties", - "native-cache-key.invalid.properties", - "native-dot-cache-key.invalid.properties", - "native-dotdot-cache-key.invalid.properties", - "native-extra-field.invalid.properties", - "native-target-mismatch.invalid.properties", - "native-profile-mismatch.invalid.properties", - ]) { - expect(() => validateNativeClusterSeedManifest(fixture(name), "standard", { - target: "linux-x64-gnu", - }), name).toThrow(); - } -}); - -test("canonicalizes producer manifests and rejects extra public fields", () => { - const producer = Buffer.from([ - "schema=oliphaunt-runtime-resources-v1", - "layout=oliphaunt-cluster-seed-v1", - "artifactRole=cluster-seed-standard", - "catalogProfile=standard", - "postgresMajor=18", - "physicalFormat=native-pg18-v1", - "initialSuperuser=postgres", - "icuDataVersion=", - "icuDataForm=", - "icuDataTreeSha256=", - "runtimeFeatures=", - "cacheKey=0123456789abcdef", - "", - ].join("\n")); - const canonical = bindNativeClusterSeedManifest(producer, "ios-datum64", "standard"); - expect(() => validateNativeClusterSeedManifest(canonical, "standard", { - target: "ios-datum64", - })).not.toThrow(); - expect(canonical.toString("utf8")).not.toContain("mode="); - expect(() => bindNativeClusterSeedManifest( - Buffer.concat([producer, Buffer.from("mode=native-server\n")]), - "ios-datum64", - "standard", - )).toThrow(/exact unbound producer field set/u); - expect(() => validateNativeClusterSeedManifest(Buffer.concat([canonical, Buffer.from("extra=value\n")]), "standard", { - target: "ios-datum64", - })).toThrow(/fields must be exactly/u); -}); - -test("logical ICU digest is metadata-independent and path-sensitive", () => { - const one = logicalTreeSha256([{ path: "a.res", bytes: Buffer.from("x") }]); - const reordered = logicalTreeSha256([ - { path: "b.res", bytes: Buffer.from("y") }, - { path: "a.res", bytes: Buffer.from("x") }, - ]); - const canonical = logicalTreeSha256([ - { path: "a.res", bytes: Buffer.from("x") }, - { path: "b.res", bytes: Buffer.from("y") }, - ]); - expect(reordered).toBe(canonical); - expect(one).not.toBe(canonical); - expect(() => logicalTreeSha256([ - { path: "a/b", bytes: Buffer.from("x") }, - { path: "a\\b", bytes: Buffer.from("x") }, - ])).toThrow(/repeats path/u); - expect(() => logicalTreeSha256([ - { path: "../outside", bytes: Buffer.from("x") }, - ])).toThrow(/unsafe path/u); -}); - -test("requires a complete regular native PGDATA seed tree", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-seed-contract-")); - const seed = path.join(root, "seed"); - try { - mkdirSync(path.join(seed, "files/global"), { recursive: true }); - mkdirSync(path.join(seed, "files/pg_wal")); - writeFileSync(path.join(seed, "files/PG_VERSION"), "18\n"); - writeFileSync(path.join(seed, "files/global/pg_control"), "control\n"); - writeFileSync(path.join(seed, "manifest.properties"), fixture("native-standard.valid.properties")); - expect(() => validateNativeClusterSeedDirectory(seed, "standard", { - target: "linux-x64-gnu", - })).not.toThrow(); - - writeFileSync(path.join(seed, "files/postmaster.pid"), "1\n"); - expect(() => validateNativeClusterSeedDirectory(seed, "standard", { - target: "linux-x64-gnu", - })).toThrow(/transient postmaster[.]pid/u); - rmSync(path.join(seed, "files/postmaster.pid")); - - if (process.platform !== "win32") { - symlinkSync("PG_VERSION", path.join(seed, "files/linked-version")); - expect(() => validateNativeClusterSeedDirectory(seed, "standard", { - target: "linux-x64-gnu", - })).toThrow(/symlink/u); - } - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/native-extension-asset-index-contract.mjs b/tools/release/native-extension-asset-index-contract.mjs deleted file mode 100644 index eba25645e..000000000 --- a/tools/release/native-extension-asset-index-contract.mjs +++ /dev/null @@ -1,52 +0,0 @@ -export const NATIVE_EXTENSION_ASSET_INDEX_HEADER = Object.freeze([ - "sql_name", - "target", - "kind", - "identity", - "artifact", - "artifact_bytes", - "registration_artifact", -]); - -export const NATIVE_EXTENSION_RUNTIME_KIND = "runtime"; - -export function nativeExtensionAssetIndexHeaderTsv() { - return NATIVE_EXTENSION_ASSET_INDEX_HEADER.join("\t"); -} - -export function nativeExtensionRuntimeKind() { - return NATIVE_EXTENSION_RUNTIME_KIND; -} - -export function isCanonicalNativeExtensionRuntimeIndexRow(row, target) { - return row?.target === target - && row.kind === NATIVE_EXTENSION_RUNTIME_KIND - && row.identity === "-" - && row.registration_artifact === "-"; -} - -function main(args) { - const [command, ...rest] = args; - if (rest.length !== 0) { - throw new Error(`${command ?? "command"} does not accept arguments`); - } - switch (command) { - case "header": - process.stdout.write(`${nativeExtensionAssetIndexHeaderTsv()}\n`); - return; - case "runtime-kind": - process.stdout.write(`${nativeExtensionRuntimeKind()}\n`); - return; - default: - throw new Error("usage: native-extension-asset-index-contract.mjs "); - } -} - -if (import.meta.main) { - try { - main(process.argv.slice(2)); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exitCode = 1; - } -} diff --git a/tools/release/native-extension-asset-index-contract.test.mjs b/tools/release/native-extension-asset-index-contract.test.mjs deleted file mode 100644 index a1ef1d790..000000000 --- a/tools/release/native-extension-asset-index-contract.test.mjs +++ /dev/null @@ -1,56 +0,0 @@ -import { expect, test } from "bun:test"; -import path from "node:path"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -import { - NATIVE_EXTENSION_ASSET_INDEX_HEADER, - NATIVE_EXTENSION_RUNTIME_KIND, - isCanonicalNativeExtensionRuntimeIndexRow, - nativeExtensionAssetIndexHeaderTsv, - nativeExtensionRuntimeKind, -} from "./native-extension-asset-index-contract.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const CONTRACT = path.join(ROOT, "tools/release/native-extension-asset-index-contract.mjs"); - -test("the raw native extension index uses the canonical runtime carrier kind", () => { - expect(NATIVE_EXTENSION_ASSET_INDEX_HEADER).toEqual([ - "sql_name", - "target", - "kind", - "identity", - "artifact", - "artifact_bytes", - "registration_artifact", - ]); - expect(NATIVE_EXTENSION_RUNTIME_KIND).toBe("runtime"); - const canonical = { - sql_name: "amcheck", - target: "linux-x64-gnu", - kind: "runtime", - identity: "-", - artifact: "amcheck.tar.gz", - artifact_bytes: "1", - registration_artifact: "-", - }; - expect(isCanonicalNativeExtensionRuntimeIndexRow(canonical, "linux-x64-gnu")).toBe(true); - expect(isCanonicalNativeExtensionRuntimeIndexRow({ - ...canonical, - kind: "runtime-extension", - }, "linux-x64-gnu")).toBe(false); -}); - -test("the canonical contract exposes its header and runtime kind through the CLI", () => { - expect(nativeExtensionAssetIndexHeaderTsv()).toBe(NATIVE_EXTENSION_ASSET_INDEX_HEADER.join("\t")); - expect(nativeExtensionRuntimeKind()).toBe(NATIVE_EXTENSION_RUNTIME_KIND); - - for (const [command, expected] of [ - ["header", `${nativeExtensionAssetIndexHeaderTsv()}\n`], - ["runtime-kind", `${nativeExtensionRuntimeKind()}\n`], - ]) { - const execution = spawnSync(process.execPath, [CONTRACT, command], { encoding: "utf8" }); - expect(execution.status).toBe(0); - expect(execution.stderr).toBe(""); - expect(execution.stdout).toBe(expected); - } -}); diff --git a/tools/release/native-extension-lifecycle-receipts.test.mjs b/tools/release/native-extension-lifecycle-receipts.test.mjs deleted file mode 100644 index a253f481b..000000000 --- a/tools/release/native-extension-lifecycle-receipts.test.mjs +++ /dev/null @@ -1,352 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { - existsSync, - mkdtempSync, - readFileSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT, - nativeExtensionLifecycleShardPlan, -} from "../graph/ci_plan.mjs"; -import { - compareText, - exactExtensionProducts, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { - assertExactFiles, - selectedExtensionDependencies, - stageExtensionCarrier, -} from "./stage-native-extension-lifecycle.mjs"; -import { verifyReceipts } from "./verify-native-extension-lifecycle-receipts.mjs"; -import { writeReceipt } from "./write-native-extension-lifecycle-receipt.mjs"; - -const CANDIDATE_SHA = "a".repeat(40); -const CANDIDATE_TREE = "b".repeat(40); - -function sha256(value) { - return createHash("sha256").update(value).digest("hex"); -} - -function canonicalExtensions() { - return exactExtensionProducts("native-extension-lifecycle-receipts.test") - .flatMap((product) => extensionSqlNames(product, "native-extension-lifecycle-receipts.test")) - .sort(compareText); -} - -function inputEnvelope(extensions = canonicalExtensions()) { - const identities = [ - "broker", - "broker-checksum", - "native-extension-index", - "native-extension-legacy-index", - "native-extension-proof-runner", - "native-runtime", - "native-tools", - ...extensions.map((name) => `native-extension:${name}`), - ].sort(compareText); - const core = { - schema: "oliphaunt-native-extension-lifecycle-inputs-v1", - candidateSha: CANDIDATE_SHA, - candidateTree: CANDIDATE_TREE, - target: "linux-x64-gnu", - extensionCount: extensions.length, - extensions, - modes: ["direct", "broker", "server"], - lifecycle: ["install", "load", "restart", "backup", "restore"], - consumedArtifacts: identities.map((identity, index) => ({ - identity, - file: `artifact-${index}.tar.gz`, - bytes: index + 1, - sha256: sha256(identity), - })), - }; - return { ...core, inputEnvelopeSha256: sha256(JSON.stringify(core)) }; -} - -function proofLog(inputs, shardIndex, shardCount) { - const selected = inputs.extensions.filter((_, index) => index % shardCount === shardIndex); - const lines = [ - `OLIPHAUNT_NATIVE_EXTENSION_PROOF_START shard=${shardIndex}/${shardCount} selected=${selected.length} planned=${inputs.extensions.length} modes=direct,broker,server`, - ]; - for (const extension of selected) { - lines.push( - `OLIPHAUNT_NATIVE_EXTENSION_PROOF_EXTENSION_PASS shard=${shardIndex}/${shardCount} extension=${extension} modes=direct,broker,server lifecycle=install-load-restart-backup-restore`, - ); - } - lines.push( - `OLIPHAUNT_NATIVE_EXTENSION_PROOF_PASS shard=${shardIndex}/${shardCount} planned=${inputs.extensions.length} modes=direct,broker,server`, - ); - return `${lines.join("\n")}\n`; -} - -function fixture(extensions) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-extension-receipts-")); - const input = path.join(root, "inputs.json"); - const inputs = inputEnvelope(extensions); - writeFileSync(input, `${JSON.stringify(inputs, null, 2)}\n`); - return { input, inputs, root }; -} - -function carrierEntries(files) { - return new Map([ - [ - "manifest.properties", - { data: Buffer.from("packageLayout=oliphaunt-extension-artifact-v1\n"), isDirectory: false, mode: 0o644 }, - ], - ...files.map(([name, data, mode = 0o644]) => [ - `files/${name}`, - { data: Buffer.from(data), isDirectory: false, mode }, - ]), - ]); -} - -function writeShard(value, shardIndex, { - shardCount = NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT, - logOverride, -} = {}) { - const log = path.join(value.root, `proof-shard-${shardIndex}.log`); - const output = path.join(value.root, `receipt-shard-${shardIndex}.json`); - writeFileSync(log, logOverride ?? proofLog(value.inputs, shardIndex, shardCount)); - writeReceipt({ - inputs: value.input, - log, - output, - "shard-index": String(shardIndex), - "shard-count": String(shardCount), - }); - return output; -} - -test("the current first-release extension catalog contains 39 products", () => { - assert.equal(canonicalExtensions().length, 39); -}); - -test("native lifecycle CI labels describe each partition's actual extension work", () => { - const products = exactExtensionProducts("native-extension-lifecycle-receipts.test"); - const plan = nativeExtensionLifecycleShardPlan(products); - assert.equal(plan.matrix.include.length, NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT); - assert.ok(plan.matrix.include.every(({ label }) => /^13 Extensions \(.+\)$/u.test(label))); - assert.equal(plan.matrix.include.some(({ label }) => label.includes("shard")), false); -}); - -test("native staging excludes built-in dependencies from packaged extension dependency edges", () => { - assert.equal(selectedExtensionDependencies({ - dependencies: ["plpgsql"], - "selected-extension-dependencies": [], - }), ""); - assert.equal(selectedExtensionDependencies({ - dependencies: ["plpgsql", "postgis"], - "selected-extension-dependencies": ["postgis"], - }), "postgis"); -}); - -test("exact lifecycle input diagnostics report basenames without masking inventory drift", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-extension-inputs-")); - try { - writeFileSync(path.join(root, "unexpected.tar.gz"), "unexpected"); - assert.throws( - () => assertExactFiles(root, [path.join(root, "expected.tar.gz")], "lifecycle input"), - /expected=expected\.tar\.gz; actual=unexpected\.tar\.gz/u, - ); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("native lifecycle staging flattens carrier envelopes and merges members by artifact product", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-extension-staging-")); - try { - const contrib = { - "artifact-product": "oliphaunt-extension-contrib-pg18", - "release-product": "liboliphaunt-native", - }; - stageExtensionCarrier(carrierEntries([ - ["share/postgresql/extension/amcheck.control", "default_version = '1.5'\n"], - ["share/postgresql/extension/amcheck--1.4.sql", "SELECT 1;\n"], - ["share/postgresql/extension/amcheck--1.4--1.5.sql", "SELECT 2;\n"], - ["lib/postgresql/amcheck.so", "amcheck-module", 0o755], - ]), root, contrib, "amcheck carrier"); - stageExtensionCarrier(carrierEntries([ - ["lib/postgresql/auto_explain.so", "auto-explain-module", 0o755], - ]), root, contrib, "auto_explain carrier"); - stageExtensionCarrier(carrierEntries([ - ["share/postgresql/extension/vector.control", "default_version = '0.8.0'\n"], - ["lib/postgresql/vector.so", "vector-module", 0o755], - ]), root, { - "artifact-product": "oliphaunt-extension-vector", - "release-product": "oliphaunt-extension-vector", - }, "vector carrier"); - - const extensionRoot = path.join(root, "resources/extension"); - const contribRoot = path.join(extensionRoot, "oliphaunt-extension-contrib-pg18"); - assert.equal( - readFileSync(path.join(contribRoot, "share/postgresql/extension/amcheck.control"), "utf8"), - "default_version = '1.5'\n", - ); - assert.equal( - readFileSync( - path.join(contribRoot, "share/postgresql/extension/amcheck--1.4--1.5.sql"), - "utf8", - ), - "SELECT 2;\n", - ); - assert.equal( - readFileSync(path.join(contribRoot, "lib/postgresql/auto_explain.so"), "utf8"), - "auto-explain-module", - ); - assert.ok((statSync(path.join(contribRoot, "lib/postgresql/auto_explain.so")).mode & 0o111) !== 0); - assert.equal( - readFileSync( - path.join(extensionRoot, "oliphaunt-extension-vector/lib/postgresql/vector.so"), - "utf8", - ), - "vector-module", - ); - assert.equal(existsSync(path.join(contribRoot, "manifest.properties")), false); - assert.equal(existsSync(path.join(contribRoot, "files")), false); - assert.equal(existsSync(path.join(extensionRoot, "amcheck")), false); - assert.equal(existsSync(path.join(extensionRoot, "auto_explain")), false); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("native lifecycle product merges accept identical files and reject differing bytes", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-extension-merge-")); - const product = { - "artifact-product": "oliphaunt-extension-contrib-pg18", - "release-product": "liboliphaunt-native", - }; - const relative = "share/postgresql/extension/shared--1.0.sql"; - try { - stageExtensionCarrier(carrierEntries([[relative, "same\n"]]), root, product, "first carrier"); - stageExtensionCarrier(carrierEntries([[relative, "same\n"]]), root, product, "identical carrier"); - assert.throws( - () => stageExtensionCarrier(carrierEntries([[relative, "different\n"]]), root, product, "conflicting carrier"), - /payload conflicts .* with different bytes/u, - ); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("three machine shard receipts aggregate to the exact artifact-bound public catalog", () => { - const value = fixture(); - try { - for ( - let shardIndex = 0; - shardIndex < NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT; - shardIndex += 1 - ) writeShard(value, shardIndex); - const output = path.join(value.root, "aggregate-receipt.json"); - verifyReceipts({ - receipts: value.root, - "candidate-sha": CANDIDATE_SHA, - "candidate-tree": CANDIDATE_TREE, - "expected-extensions-csv": value.inputs.extensions.join(","), - "expected-shard-count": String(NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT), - output, - }); - const aggregate = JSON.parse(readFileSync(output, "utf8")); - assert.equal(aggregate.extensionCount, value.inputs.extensions.length); - assert.deepEqual(aggregate.extensions, value.inputs.extensions); - assert.deepEqual( - aggregate.shardReceipts.map((receipt) => receipt.shardIndex), - Array.from( - { length: NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT }, - (_, shardIndex) => shardIndex, - ), - ); - assert.match(aggregate.aggregateSha256, /^[0-9a-f]{64}$/u); - } finally { - rmSync(value.root, { force: true, recursive: true }); - } -}); - -test("focused dependency-closure proof uses one nonempty shard and aggregates exactly the selected subset", () => { - const value = fixture(["cube", "earthdistance"]); - try { - writeShard(value, 0, { shardCount: 1 }); - const output = path.join(value.root, "aggregate-receipt.json"); - verifyReceipts({ - receipts: value.root, - "candidate-sha": CANDIDATE_SHA, - "candidate-tree": CANDIDATE_TREE, - "expected-extensions-csv": value.inputs.extensions.join(","), - "expected-shard-count": "1", - output, - }); - const aggregate = JSON.parse(readFileSync(output, "utf8")); - assert.deepEqual(aggregate.extensions, ["cube", "earthdistance"]); - assert.equal(aggregate.extensionCount, 2); - assert.equal(aggregate.shardCount, 1); - assert.deepEqual(aggregate.shardReceipts.map((receipt) => receipt.shardIndex), [0]); - } finally { - rmSync(value.root, { force: true, recursive: true }); - } -}); - -test("shard receipt generation rejects omitted extension PASS records and incomplete artifact evidence", () => { - const value = fixture(); - try { - const incompleteLog = proofLog(value.inputs, 0, NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT) - .split("\n") - .filter((line) => !line.includes(`extension=${value.inputs.extensions[0]} `)) - .join("\n"); - assert.throws(() => writeShard(value, 0, { logOverride: incompleteLog }), /unique extension PASS records/u); - - const { inputEnvelopeSha256: ignored, ...core } = value.inputs; - core.consumedArtifacts = core.consumedArtifacts.slice(1); - const incomplete = { ...core, inputEnvelopeSha256: sha256(JSON.stringify(core)) }; - writeFileSync(value.input, `${JSON.stringify(incomplete, null, 2)}\n`); - assert.throws(() => writeShard(value, 0), /enumerate all \d+ consumed artifacts/u); - } finally { - rmSync(value.root, { force: true, recursive: true }); - } -}); - -test("aggregate verification rejects candidate, shard, and PASS-record drift even with recomputed receipts", () => { - const mutations = [ - (receipt) => { receipt.candidateSha = "c".repeat(40); }, - (receipt) => { receipt.extensions = receipt.extensions.slice(1); receipt.extensionCount -= 1; }, - (receipt) => { receipt.passRecords[0].modes = ["direct", "broker"]; }, - ]; - for (const mutate of mutations) { - const value = fixture(); - try { - const files = Array.from( - { length: NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT }, - (_, shardIndex) => writeShard(value, shardIndex), - ); - const receipt = JSON.parse(readFileSync(files[0], "utf8")); - mutate(receipt); - const { receiptSha256: ignored, ...core } = receipt; - receipt.receiptSha256 = sha256(JSON.stringify(core)); - writeFileSync(files[0], `${JSON.stringify(receipt, null, 2)}\n`); - assert.throws( - () => verifyReceipts({ - receipts: value.root, - "candidate-sha": CANDIDATE_SHA, - "candidate-tree": CANDIDATE_TREE, - "expected-extensions-csv": value.inputs.extensions.join(","), - "expected-shard-count": String(NATIVE_EXTENSION_LIFECYCLE_EXHAUSTIVE_SHARD_COUNT), - output: path.join(value.root, "aggregate-receipt.json"), - }), - /candidate identity mismatch|PASS record count drift|malformed or misordered/u, - ); - } finally { - rmSync(value.root, { force: true, recursive: true }); - } - } -}); diff --git a/tools/release/native-icu-data-contract.mjs b/tools/release/native-icu-data-contract.mjs deleted file mode 100644 index 2050172ab..000000000 --- a/tools/release/native-icu-data-contract.mjs +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env bun - -import { readFileSync, writeFileSync } from "node:fs"; -import path from "node:path"; - -import { - filesystemTreeRows, - logicalTreeSha256, - parseProperties, -} from "./native-cluster-seed-contract.mjs"; - -export const NATIVE_ICU_DATA_SCHEMA = "oliphaunt-icu-data-v1"; -export const ICU_DATA_VERSION = "76.1"; -export const ICU_DATA_FORM = "files-le"; - -const LOWER_SHA256 = /^[0-9a-f]{64}$/u; - -export function parseNativeIcuDataIdentity(bytes, label = "native ICU data manifest") { - const actual = parseProperties(bytes, label); - const expected = new Map([ - ["schema", NATIVE_ICU_DATA_SCHEMA], - ["artifactRole", "icu-data"], - ["icuDataVersion", ICU_DATA_VERSION], - ["icuDataForm", ICU_DATA_FORM], - ]); - if (actual.size !== expected.size + 1) throw new Error(`${label}: unexpected fields`); - for (const [key, value] of expected) { - if (actual.get(key) !== value) { - throw new Error(`${label}: ${key} must be ${JSON.stringify(value)}, got ${JSON.stringify(actual.get(key))}`); - } - } - const dataTreeSha256 = actual.get("icuDataTreeSha256"); - if (!LOWER_SHA256.test(dataTreeSha256 ?? "")) { - throw new Error(`${label}: icuDataTreeSha256 must be a lowercase SHA-256 digest`); - } - return Object.freeze({ - dataVersion: ICU_DATA_VERSION, - dataForm: ICU_DATA_FORM, - dataTreeSha256, - }); -} - -export function nativeIcuDataManifestFromRows(rows) { - const entries = [...rows]; - if (entries.length === 0) throw new Error("native ICU data tree is empty"); - const digest = logicalTreeSha256(entries); - return Buffer.from([ - `schema=${NATIVE_ICU_DATA_SCHEMA}`, - "artifactRole=icu-data", - `icuDataVersion=${ICU_DATA_VERSION}`, - `icuDataForm=${ICU_DATA_FORM}`, - `icuDataTreeSha256=${digest}`, - "", - ].join("\n")); -} - -export function nativeIcuDataManifest(icuData) { - return nativeIcuDataManifestFromRows(filesystemTreeRows(icuData)); -} - -export function validateNativeIcuDataManifestRows(bytes, rows, label = "native ICU data manifest") { - const identity = parseNativeIcuDataIdentity(bytes, label); - const expected = logicalTreeSha256([...rows]); - if (identity.dataTreeSha256 !== expected) { - throw new Error( - `${label}: icuDataTreeSha256 must be ${JSON.stringify(expected)}, got ${JSON.stringify(identity.dataTreeSha256)}`, - ); - } - return Object.freeze({ icuDataTreeSha256: identity.dataTreeSha256 }); -} - -export function validateNativeIcuDataManifest(bytes, icuData, label = "native ICU data manifest") { - return validateNativeIcuDataManifestRows(bytes, filesystemTreeRows(icuData), label); -} - -if (import.meta.main) { - const [icuData, output] = process.argv.slice(2); - if (!icuData || !output || process.argv.length !== 4) { - throw new Error("usage: native-icu-data-contract.mjs ICU_DATA_DIR OUTPUT"); - } - const manifest = nativeIcuDataManifest(path.resolve(icuData)); - writeFileSync(path.resolve(output), manifest); - validateNativeIcuDataManifest(readFileSync(path.resolve(output)), path.resolve(icuData), output); -} diff --git a/tools/release/native-icu-data-contract.test.mjs b/tools/release/native-icu-data-contract.test.mjs deleted file mode 100644 index 1cd950318..000000000 --- a/tools/release/native-icu-data-contract.test.mjs +++ /dev/null @@ -1,31 +0,0 @@ -import { expect, test } from "bun:test"; -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { - nativeIcuDataManifest, - nativeIcuDataManifestFromRows, - validateNativeIcuDataManifest, -} from "./native-icu-data-contract.mjs"; - -test("binds the data-only native ICU carrier to its logical tree", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-icu-contract-")); - try { - mkdirSync(path.join(root, "icudt76l")); - writeFileSync(path.join(root, "icudt76l/root.res"), "root\n"); - const manifest = nativeIcuDataManifest(root); - expect(manifest.toString("utf8")).toMatch( - /^schema=oliphaunt-icu-data-v1\nartifactRole=icu-data\nicuDataVersion=76[.]1\nicuDataForm=files-le\nicuDataTreeSha256=[0-9a-f]{64}\n$/u, - ); - expect(validateNativeIcuDataManifest(manifest, root).icuDataTreeSha256).toHaveLength(64); - writeFileSync(path.join(root, "icudt76l/root.res"), "changed\n"); - expect(() => validateNativeIcuDataManifest(manifest, root)).toThrow(/icuDataTreeSha256/u); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("rejects an empty ICU data identity", () => { - expect(() => nativeIcuDataManifestFromRows([])).toThrow(/tree is empty/u); -}); diff --git a/tools/release/native-mobile-abi-contract.mjs b/tools/release/native-mobile-abi-contract.mjs deleted file mode 100644 index a32c7a73d..000000000 --- a/tools/release/native-mobile-abi-contract.mjs +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env node - -import { readFileSync, writeFileSync } from "node:fs"; -import path from "node:path"; - -const SCHEMA = "oliphaunt-native-mobile-abi-v1"; -export const NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN = Object.freeze({ - "android-datum64": Object.freeze([ - "android-arm64-v8a", - "android-x86_64", - "linux-x64-gnu", - ]), - "ios-datum64": Object.freeze([ - "ios-arm64", - "ios-arm64-simulator", - "macos-arm64", - ]), -}); -export const NATIVE_MOBILE_ABI_RECEIPT_KEYS = Object.freeze([ - "schema", - "target", - "byteOrder", - "datumBytes", - "maximumAlignof", - "float8ByVal", - "blockSize", - "walBlockSize", - "relationSegmentSize", - "nameDataLength", - "indexMaxKeys", - "catalogVersion", - "pgControlVersion", -]); - -function fail(message) { - throw new Error(`native-mobile-abi-contract.mjs: ${message}`); -} - -function parseProperties(text, label) { - const values = new Map(); - for (const [index, line] of text.split(/\r?\n/u).entries()) { - if (line.length === 0) continue; - const separator = line.indexOf("="); - if (separator <= 0) fail(`${label}:${index + 1} is not key=value`); - const key = line.slice(0, separator); - if (values.has(key)) fail(`${label}:${index + 1} repeats ${key}`); - values.set(key, line.slice(separator + 1)); - } - return values; -} - -function defineValue(text, name, label) { - const match = text.match(new RegExp(`^\\s*#define\\s+${name}\\s+([^\\s/]+)`, "mu")); - if (match === null) fail(`${label} does not define ${name}`); - return match[1].replace(/^\((.*)\)$/u, "$1"); -} - -function integerDefine(text, name, label) { - const raw = defineValue(text, name, label).replace(/[uUlL]+$/u, ""); - if (!/^(?:0[xX][0-9a-fA-F]+|[0-9]+)$/u.test(raw)) { - fail(`${label} has invalid ${name}=${raw}`); - } - const value = Number.parseInt(raw, /^0[xX]/u.test(raw) ? 16 : 10); - if (!Number.isSafeInteger(value) || value <= 0) fail(`${label} has invalid ${name}=${raw}`); - return String(value); -} - -function header(buildRoot, relative) { - const file = path.join(buildRoot, ...relative.split("/")); - try { - return { file, text: readFileSync(file, "utf8") }; - } catch (error) { - fail(`cannot read ${file}: ${error instanceof Error ? error.message : String(error)}`); - } -} - -export function nativeMobileAbiReceipt(buildRoot, target) { - const pgConfig = header(buildRoot, "src/include/pg_config.h"); - const pgConfigManual = header(buildRoot, "src/include/pg_config_manual.h"); - const catversion = header(buildRoot, "src/include/catalog/catversion.h"); - const pgControl = header(buildRoot, "src/include/catalog/pg_control.h"); - const datumBytes = integerDefine(pgConfig.text, "SIZEOF_VOID_P", pgConfig.file); - if (datumBytes !== "8") fail(`${target} is not a Datum64 target`); - const maximumAlignof = integerDefine(pgConfig.text, "MAXIMUM_ALIGNOF", pgConfig.file); - const byteOrder = /^\s*#define\s+WORDS_BIGENDIAN\s+1\b/mu.test(pgConfig.text) - ? "big" - : "little"; - const float8ByVal = /^\s*#define\s+USE_FLOAT8_BYVAL(?:\s+1)?\s*$/mu.test(pgConfigManual.text) - ? "1" - : "0"; - const values = new Map([ - ["schema", SCHEMA], - ["target", target], - ["byteOrder", byteOrder], - ["datumBytes", datumBytes], - ["maximumAlignof", maximumAlignof], - ["float8ByVal", float8ByVal], - ["blockSize", integerDefine(pgConfig.text, "BLCKSZ", pgConfig.file)], - ["walBlockSize", integerDefine(pgConfig.text, "XLOG_BLCKSZ", pgConfig.file)], - ["relationSegmentSize", integerDefine(pgConfig.text, "RELSEG_SIZE", pgConfig.file)], - ["nameDataLength", integerDefine(pgConfigManual.text, "NAMEDATALEN", pgConfigManual.file)], - ["indexMaxKeys", integerDefine(pgConfigManual.text, "INDEX_MAX_KEYS", pgConfigManual.file)], - ["catalogVersion", integerDefine(catversion.text, "CATALOG_VERSION_NO", catversion.file)], - ["pgControlVersion", integerDefine(pgControl.text, "PG_CONTROL_VERSION", pgControl.file)], - ]); - return `${NATIVE_MOBILE_ABI_RECEIPT_KEYS.map((key) => `${key}=${values.get(key)}`).join("\n")}\n`; -} - -export function parseNativeMobileAbiReceipt(text, label = "native mobile ABI receipt") { - const values = parseProperties(text, label); - if ( - values.size !== NATIVE_MOBILE_ABI_RECEIPT_KEYS.length - || NATIVE_MOBILE_ABI_RECEIPT_KEYS.some((key) => !values.has(key)) - ) { - fail(`${label} fields must be exactly ${NATIVE_MOBILE_ABI_RECEIPT_KEYS.join(",")}`); - } - if (values.get("schema") !== SCHEMA) fail(`${label} has unsupported schema`); - if (!/^[a-z0-9][a-z0-9_-]*$/u.test(values.get("target"))) { - fail(`${label} has invalid target`); - } - if (!new Set(["little", "big"]).has(values.get("byteOrder"))) { - fail(`${label} has invalid byteOrder`); - } - for (const key of [ - "datumBytes", - "maximumAlignof", - "blockSize", - "walBlockSize", - "relationSegmentSize", - "nameDataLength", - "indexMaxKeys", - "catalogVersion", - "pgControlVersion", - ]) { - if (!/^[1-9][0-9]*$/u.test(values.get(key))) fail(`${label} has invalid ${key}`); - } - if (!new Set(["0", "1"]).has(values.get("float8ByVal"))) { - fail(`${label} has invalid float8ByVal`); - } - if (values.get("datumBytes") !== "8") fail(`${label} is not a Datum64 receipt`); - return values; -} - -export function compareNativeMobileAbiReceipts(domain, receipts) { - const expectedTargets = NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[domain]; - if (expectedTargets === undefined) fail(`unsupported compatibility domain ${domain}`); - if (receipts.length !== expectedTargets.length) { - fail(`${domain} requires receipts for ${expectedTargets.join(", ")}`); - } - const rows = receipts.map(({ text, label }) => ({ - values: parseNativeMobileAbiReceipt(text, label), - label, - })); - const actualTargets = rows.map(({ values }) => values.get("target")).sort(); - if (JSON.stringify(actualTargets) !== JSON.stringify([...expectedTargets].sort())) { - fail(`${domain} receipts must target exactly ${expectedTargets.join(", ")}`); - } - const baseline = rows[0]; - for (const row of rows.slice(1)) { - for (const key of NATIVE_MOBILE_ABI_RECEIPT_KEYS) { - if (key === "target") continue; - if (row.values.get(key) !== baseline.values.get(key)) { - fail(`${domain} ABI mismatch for ${key}: ${baseline.label}=${baseline.values.get(key)}, ${row.label}=${row.values.get(key)}`); - } - } - } - return Object.freeze({ domain, targets: Object.freeze([...expectedTargets]) }); -} - -function parseArgs(argv) { - const command = argv[0]; - if (command === "write" && argv.length === 7 && argv[1] === "--build-root" && argv[3] === "--target" && argv[5] === "--output") { - return { command, buildRoot: path.resolve(argv[2]), target: argv[4], output: path.resolve(argv[6]) }; - } - if (command === "compare" && argv.length >= 6 && argv[1] === "--domain" && argv[3] === "--receipt") { - const receiptFiles = []; - for (let index = 3; index < argv.length; index += 2) { - if (argv[index] !== "--receipt" || argv[index + 1] === undefined) fail("compare accepts repeated --receipt FILE"); - receiptFiles.push(path.resolve(argv[index + 1])); - } - return { command, domain: argv[2], receiptFiles }; - } - fail("usage: write --build-root DIR --target TARGET --output FILE | compare --domain DOMAIN --receipt FILE --receipt FILE"); -} - -if (import.meta.main) { - try { - const args = parseArgs(process.argv.slice(2)); - if (args.command === "write") { - writeFileSync(args.output, nativeMobileAbiReceipt(args.buildRoot, args.target)); - console.log(`nativeMobileAbiReceipt=${args.output}`); - } else { - const receipts = args.receiptFiles.map((file) => ({ text: readFileSync(file, "utf8"), label: file })); - const result = compareNativeMobileAbiReceipts(args.domain, receipts); - console.log(`nativeMobileAbiDomain=${result.domain}`); - } - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(2); - } -} diff --git a/tools/release/native-mobile-abi-contract.test.mjs b/tools/release/native-mobile-abi-contract.test.mjs deleted file mode 100644 index 455b20818..000000000 --- a/tools/release/native-mobile-abi-contract.test.mjs +++ /dev/null @@ -1,77 +0,0 @@ -import { expect, test } from "bun:test"; -import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { - compareNativeMobileAbiReceipts, - nativeMobileAbiReceipt, - parseNativeMobileAbiReceipt, -} from "./native-mobile-abi-contract.mjs"; - -function fixture(target, overrides = {}) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-mobile-abi-")); - const include = path.join(root, "src/include"); - mkdirSync(path.join(include, "catalog"), { recursive: true }); - writeFileSync(path.join(include, "pg_config.h"), [ - `#define SIZEOF_VOID_P ${overrides.pointerBytes ?? 8}`, - `#define MAXIMUM_ALIGNOF ${overrides.alignment ?? 8}`, - "#define BLCKSZ 8192", - "#define XLOG_BLCKSZ 8192", - "#define RELSEG_SIZE 131072", - overrides.bigEndian ? "#define WORDS_BIGENDIAN 1" : "/* #undef WORDS_BIGENDIAN */", - "", - ].join("\n")); - writeFileSync(path.join(include, "pg_config_manual.h"), [ - "#define USE_FLOAT8_BYVAL 1", - `#define NAMEDATALEN ${overrides.nameDataLength ?? 64}`, - "#define INDEX_MAX_KEYS 32", - "", - ].join("\n")); - writeFileSync(path.join(include, "catalog/catversion.h"), "#define CATALOG_VERSION_NO 202506291\n"); - writeFileSync(path.join(include, "catalog/pg_control.h"), "#define PG_CONTROL_VERSION 1800\n"); - return { text: nativeMobileAbiReceipt(root, target), label: target }; -} - -test("qualifies matching Android Datum64 ABI receipts", () => { - expect(compareNativeMobileAbiReceipts("android-datum64", [ - fixture("android-arm64-v8a"), - fixture("android-x86_64"), - fixture("linux-x64-gnu"), - ]).domain).toBe("android-datum64"); -}); - -test("rejects ABI differences and incorrect domain membership", () => { - expect(() => compareNativeMobileAbiReceipts("ios-datum64", [ - fixture("ios-arm64"), - fixture("ios-arm64-simulator", { alignment: 16 }), - fixture("macos-arm64"), - ])).toThrow(/ABI mismatch for maximumAlignof/u); - expect(() => compareNativeMobileAbiReceipts("android-datum64", [ - fixture("android-arm64-v8a"), - fixture("ios-arm64"), - fixture("linux-x64-gnu"), - ])).toThrow(/target exactly/u); - expect(() => compareNativeMobileAbiReceipts("android-datum64", [ - fixture("android-arm64-v8a"), - fixture("android-x86_64", { nameDataLength: 128 }), - fixture("linux-x64-gnu"), - ])).toThrow(/ABI mismatch for nameDataLength/u); -}); - -test("rejects non-Datum64 producer headers", () => { - expect(() => fixture("android-x86_64", { pointerBytes: 4 })).toThrow(/not a Datum64/u); - expect(() => fixture("android-x86_64", { pointerBytes: "8garbage" })).toThrow( - /invalid SIZEOF_VOID_P/u, - ); -}); - -test("rejects malformed or internally inconsistent receipts", () => { - const valid = fixture("android-x86_64").text; - expect(() => parseNativeMobileAbiReceipt( - valid.replace("byteOrder=little", "byteOrder=sideways"), - )).toThrow(/invalid byteOrder/u); - expect(() => parseNativeMobileAbiReceipt( - valid.replace("datumBytes=8", "datumBytes=4"), - )).toThrow(/not a Datum64 receipt/u); -}); diff --git a/tools/release/native-npm-archive-extraction.test.mjs b/tools/release/native-npm-archive-extraction.test.mjs deleted file mode 100644 index 327ddcb9a..000000000 --- a/tools/release/native-npm-archive-extraction.test.mjs +++ /dev/null @@ -1,109 +0,0 @@ -import { expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { extractReleaseArchiveTree } from "./package-release-carriers.mjs"; -import { ROOT } from "./release-cli-utils.mjs"; - -const ARCHIVER = path.join(ROOT, "src/shared/artifact-packaging/archive-directory.mjs"); -const NATIVE_PACKAGE_ROOT = path.join(ROOT, "src/runtimes/liboliphaunt/native/packages"); -const REQUIRED_LEGAL_FILES = [ - "LICENSE", - "THIRD_PARTY_NOTICES.md", - "THIRD_PARTY_NOTICES.liboliphaunt-native.md", - "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", - "THIRD_PARTY_LICENSES/ICU-LICENSE", -]; - -function writeFixtureFile(root, relativePath, contents) { - const file = path.join(root, ...relativePath.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, contents); -} - -test("native npm ZIP assembly preserves complete nested runtime trees", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-npm-zip-tree-")); - try { - const source = path.join(root, "source"); - const archive = path.join(root, "native.zip"); - const runtimeFiles = new Map([ - ["bin/initdb.exe", "initdb\n"], - ["bin/pg_ctl.exe", "pg_ctl\n"], - ["bin/postgres.exe", "postgres\n"], - ["lib/postgresql/plpgsql.dll", "plpgsql\n"], - ["share/postgresql/postgres.bki", "catalog\n"], - ["share/postgresql/timezone/Africa/Abidjan", "timezone\n"], - ]); - for (const [relativePath, contents] of runtimeFiles) { - writeFixtureFile(path.join(source, "runtime"), relativePath, contents); - } - writeFixtureFile(source, "lib/modules/dict_snowball.dll", "embedded dict_snowball\n"); - writeFixtureFile(source, "lib/modules/plpgsql.dll", "embedded plpgsql\n"); - writeFixtureFile(source, "outside/not-packaged.txt", "outside\n"); - - const packed = spawnSync(process.execPath, [ARCHIVER, source, archive], { - encoding: "utf8", - stdio: ["ignore", "pipe", "pipe"], - }); - expect(packed.status, packed.stderr || packed.stdout).toBe(0); - - const stages = [["release-package", extractReleaseArchiveTree]]; - for (const [name, extract] of stages) { - const stage = path.join(root, name, "runtime"); - extract(archive, "runtime", stage); - for (const [relativePath, contents] of runtimeFiles) { - expect(readFileSync(path.join(stage, ...relativePath.split("/")), "utf8")).toBe(contents); - } - const modules = path.join(root, name, "lib/modules"); - extract(archive, "lib/modules", modules); - expect(readFileSync(path.join(modules, "dict_snowball.dll"), "utf8")).toBe( - "embedded dict_snowball\n", - ); - expect(readFileSync(path.join(modules, "plpgsql.dll"), "utf8")).toBe("embedded plpgsql\n"); - expect(existsSync(path.join(root, name, "outside", "not-packaged.txt"))).toBe(false); - } - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("native npm descriptors publish every staged payload root", () => { - const descriptors = readdirSync(NATIVE_PACKAGE_ROOT, { withFileTypes: true }) - .filter((entry) => entry.isDirectory()) - .map((entry) => path.join(NATIVE_PACKAGE_ROOT, entry.name, "package.json")) - .filter(existsSync) - .sort(); - - expect(descriptors.length).toBe(4); - for (const descriptor of descriptors) { - const packageJson = JSON.parse(readFileSync(descriptor, "utf8")); - const libraryRoot = packageJson.oliphaunt?.libraryRelativePath?.split("/")[0]; - const runtimeRoot = packageJson.oliphaunt?.runtimeRelativePath?.split("/")[0]; - const clusterSeedRoot = packageJson.oliphaunt?.clusterSeedRelativePath?.split("/")[0]; - const icuClusterSeedRoot = packageJson.oliphaunt?.icuClusterSeedRelativePath?.split("/")[0]; - expect(packageJson.oliphaunt?.clusterSeedTarget).toBe(packageJson.oliphaunt?.target); - const expected = [ - ...new Set([ - libraryRoot, - "lib", - runtimeRoot, - clusterSeedRoot, - icuClusterSeedRoot, - "manifest.properties", - "README.md", - ...REQUIRED_LEGAL_FILES, - ]), - ].sort(); - expect(packageJson.files?.slice().sort(), descriptor).toEqual(expected); - } -}); diff --git a/tools/release/native-npm-carrier-notice-contract.test.mjs b/tools/release/native-npm-carrier-notice-contract.test.mjs deleted file mode 100644 index dc147c27a..000000000 --- a/tools/release/native-npm-carrier-notice-contract.test.mjs +++ /dev/null @@ -1,90 +0,0 @@ -import assert from "node:assert/strict"; -import { - cpSync, - mkdtempSync, - mkdirSync, - readFileSync, - readdirSync, - realpathSync, - rmSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - assertReleaseNoticesInArchive, - releaseNoticeRows, - releaseProfilePackageLicense, - stageReleaseNotices, -} from "./release-notices.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -const NATIVE_ROOT = path.join(ROOT, "src/runtimes/liboliphaunt/native"); - -function platformPackages(relativeRoot, profile) { - const root = path.join(NATIVE_ROOT, relativeRoot); - return readdirSync(root, { withFileTypes: true }) - .filter((entry) => entry.isDirectory()) - .map((entry) => ({ directory: path.join(root, entry.name), profile })) - .sort((left, right) => left.directory.localeCompare(right.directory)); -} - -const CARRIERS = [ - ...platformPackages("packages", "native-runtime"), - ...platformPackages("tools-packages", "native-tools"), - { directory: path.join(NATIVE_ROOT, "icu-npm"), profile: "native-icu-data" }, -]; - -function pack(directory, output) { - const result = spawnSync( - "pnpm", - ["pack", "--pack-destination", output, "--json"], - { cwd: directory, encoding: "utf8" }, - ); - assert.equal(result.status, 0, `${directory} failed to pack:\n${result.stdout}\n${result.stderr}`); - const rows = JSON.parse(result.stdout); - const filename = (Array.isArray(rows) ? rows[0] : rows)?.filename; - assert.equal(typeof filename, "string", `${directory} pack output must identify its tarball`); - return path.isAbsolute(filename) ? filename : path.join(output, path.basename(filename)); -} - -test("every native npm payload carrier declares and physically packs its exact legal profile", (t) => { - const root = realpathSync(mkdtempSync(path.join(tmpdir(), "native-npm-notices-"))); - t.after(() => rmSync(root, { recursive: true, force: true })); - const output = path.join(root, "tarballs"); - mkdirSync(output); - - for (const [index, carrier] of CARRIERS.entries()) { - const manifest = JSON.parse(readFileSync(path.join(carrier.directory, "package.json"), "utf8")); - const noticeMembers = releaseNoticeRows({ profile: carrier.profile }).map((row) => row.member); - assert.equal( - manifest.license, - releaseProfilePackageLicense(carrier.profile).spdx, - `${manifest.name} must declare its exact ${carrier.profile} SPDX expression`, - ); - for (const member of noticeMembers) { - assert.ok(manifest.files.includes(member), `${manifest.name} files must include ${member}`); - } - const selectedLegalMembers = manifest.files.filter((member) => - member === "LICENSE" - || member === "THIRD_PARTY_NOTICES.md" - || /^THIRD_PARTY_NOTICES\.[^/]+\.md$/u.test(member) - || member.startsWith("THIRD_PARTY_LICENSES/") - ); - assert.deepEqual(selectedLegalMembers, noticeMembers, `${manifest.name} files must select no stale legal members`); - - const stage = path.join(root, `stage-${index}`); - cpSync(carrier.directory, stage, { recursive: true }); - stageReleaseNotices(stage, { profile: carrier.profile }); - const tarball = pack(stage, output); - assertReleaseNoticesInArchive(tarball, { profile: carrier.profile, prefix: "package" }); - const packedManifest = JSON.parse( - Buffer.from(readPortableArchiveEntries(tarball).get("package/package.json").data()).toString("utf8"), - ); - assert.equal(packedManifest.name, manifest.name); - assert.equal(packedManifest.license, releaseProfilePackageLicense(carrier.profile).spdx); - } -}); diff --git a/tools/release/native-readiness-probes.test.mjs b/tools/release/native-readiness-probes.test.mjs deleted file mode 100644 index a61c4f348..000000000 --- a/tools/release/native-readiness-probes.test.mjs +++ /dev/null @@ -1,114 +0,0 @@ -import { expect, test } from "bun:test"; -import path from "node:path"; - -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { ROOT } from "./release-graph.mjs"; - -const commonPath = path.join( - ROOT, - "src/runtimes/liboliphaunt/native/bin/common.sh", -); -const mobileStaticExtensionsPath = path.join( - ROOT, - "src/runtimes/liboliphaunt/native/bin/mobile-static-extensions.sh", -); - -test("large Snowball symbol tables remain deterministic under pipefail", () => { - const probe = String.raw` -set -euo pipefail -. "$1" -. "$2" - -required_symbols='oliphaunt_builtin_dict_snowball_Pg_magic_func -dsnowball_init -pg_finfo_dsnowball_init -dsnowball_lexize -pg_finfo_dsnowball_lexize' - -for symbol_prefix in '' '_'; do - symbols="$({ - while IFS= read -r symbol; do - printf '0000000000000000 T %s%s\n' "$symbol_prefix" "$symbol" - done <&2 - exit 1 - fi -done < { - const probe = String.raw` -set -euo pipefail -. "$1" -dynamic_section=' 0x0000000000000001 (NEEDED) Shared library: [liboliphaunt.so]' -oliphaunt_text_matches_ere "$dynamic_section" 'Shared library: [[]liboliphaunt[.]so[]]' -if oliphaunt_text_matches_ere "$dynamic_section" 'Shared library: [[]libother[.]so[]]'; then - echo "native text probe accepted the wrong shared library" >&2 - exit 1 -fi -device_metadata=' platform IOS' -simulator_metadata=' platform IOSSIMULATOR' -ios_device_pattern='(^|[[:space:]])platform[[:space:]]+IOS([[:space:]]|$)' -ios_simulator_pattern='(^|[[:space:]])platform[[:space:]]+IOSSIMULATOR([[:space:]]|$)' -oliphaunt_text_matches_ere "$device_metadata" "$ios_device_pattern" -oliphaunt_text_matches_ere "$simulator_metadata" "$ios_simulator_pattern" -if oliphaunt_text_matches_ere "$simulator_metadata" "$ios_device_pattern"; then - echo "iOS device probe accepted an iOS simulator slice" >&2 - exit 1 -fi -`; - const result = spawnSync("bash", ["-c", probe, "bash", commonPath], { - encoding: "utf8", - }); - - expect(result.status, result.stderr).toBe(0); -}); - -test("native log excerpts are line- and width-bounded", () => { - const probe = String.raw` -set -euo pipefail -. "$1" -log="$2" -trap 'rm -f "$log"' EXIT -awk 'BEGIN { for (i = 1; i <= 100; i++) { printf "%03d ", i; for (j = 0; j < 5000; j++) printf "x"; printf "\n" } }' > "$log" -excerpt="$(oliphaunt_tail_log_excerpt "$log" 10 200)" -[ "$(printf '%s\n' "$excerpt" | awk 'END { print NR }')" -eq 10 ] -printf '%s\n' "$excerpt" | awk 'length($0) > 221 { exit 1 }' -`; - const logPath = path.join( - process.env.RUNNER_TEMP ?? process.env.TMPDIR ?? "/tmp", - `oliphaunt-native-readiness-${process.pid}.log`, - ); - const result = spawnSync("bash", ["-c", probe, "bash", commonPath, logPath], { - encoding: "utf8", - }); - - expect(result.status, result.stderr).toBe(0); -}); diff --git a/tools/release/native-release-fixtures.test.mjs b/tools/release/native-release-fixtures.test.mjs deleted file mode 100644 index 39342e32e..000000000 --- a/tools/release/native-release-fixtures.test.mjs +++ /dev/null @@ -1,73 +0,0 @@ -import { afterEach, expect, test } from 'bun:test'; -import { spawnSync } from '../test/fd-backed-spawn-sync.mjs'; -import { mkdtempSync, rmSync } from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; - -import { currentProductVersionSync } from './release-artifact-targets.mjs'; -import { ROOT } from './release-graph.mjs'; - -const temporaryRoots = []; - -afterEach(() => { - for (const root of temporaryRoots.splice(0)) { - rmSync(root, { recursive: true, force: true }); - } -}); - -function temporaryDirectory(label) { - const directory = mkdtempSync(path.join(os.tmpdir(), `oliphaunt-${label}-`)); - temporaryRoots.push(directory); - return directory; -} - -function run(script, args) { - return spawnSync(process.execPath, [script, ...args], { - cwd: ROOT, - encoding: 'utf8', - env: process.env, - }); -} - -function expectSuccess(result, label) { - expect( - result.status, - `${label} failed\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`, - ).toBe(0); -} - -test('release-shaped native fixtures satisfy the same binary and archive contracts as publish assets', { - timeout: 30_000, -}, () => { - const liboliphauntAssets = temporaryDirectory('liboliphaunt-native-fixture'); - const brokerAssets = temporaryDirectory('broker-native-fixture'); - const liboliphauntVersion = currentProductVersionSync('liboliphaunt-native'); - const brokerVersion = currentProductVersionSync('oliphaunt-broker'); - - expectSuccess( - run('tools/test/create-liboliphaunt-release-fixture.mjs', [ - '--asset-dir', liboliphauntAssets, - '--version', liboliphauntVersion, - ]), - 'creating liboliphaunt release fixture', - ); - expectSuccess( - run('tools/release/check-liboliphaunt-release-assets.mjs', [ - '--asset-dir', liboliphauntAssets, - ]), - 'validating liboliphaunt release fixture', - ); - expectSuccess( - run('tools/test/create-broker-release-fixture.mjs', [ - '--asset-dir', brokerAssets, - '--version', brokerVersion, - ]), - 'creating broker release fixture', - ); - expectSuccess( - run('tools/release/check-broker-release-assets.mjs', [ - '--asset-dir', brokerAssets, - ]), - 'validating broker release fixture', - ); -}); diff --git a/tools/release/native-runtime-carrier-contract.mjs b/tools/release/native-runtime-carrier-contract.mjs deleted file mode 100644 index b5ad01566..000000000 --- a/tools/release/native-runtime-carrier-contract.mjs +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env bun - -import { readFileSync, writeFileSync } from "node:fs"; -import path from "node:path"; - -import { - NATIVE_CLUSTER_SEED_TARGETS, - parseProperties, - validNativeCacheKey, - validateNativeClusterSeedDirectory, -} from "./native-cluster-seed-contract.mjs"; - -export const NATIVE_RUNTIME_CARRIER_SCHEMA = "oliphaunt-native-runtime-carrier-v1"; -export const NATIVE_RUNTIME_RESOURCE_MANIFEST_KEYS = Object.freeze([ - "schema", - "layout", - "artifactRole", - "catalogProfile", - "clusterSeedTarget", - "icuDataTreeSha256", - "mode", - "cacheKey", - "selectedExtensions", - "extensions", - "runtimeFeatures", - "sharedPreloadLibraries", - "mobileStaticRegistryState", - "mobileStaticRegistryRegistered", - "mobileStaticRegistryPending", - "nativeModuleStems", - "mobileStaticRegistrySource", -]); - -function requireTarget(target) { - if (!NATIVE_CLUSTER_SEED_TARGETS.includes(target)) { - throw new Error(`unsupported native cluster-seed target ${JSON.stringify(target)}`); - } - return target; -} - -export function nativeRuntimeCarrierManifest(target) { - requireTarget(target); - return Buffer.from([ - `schema=${NATIVE_RUNTIME_CARRIER_SCHEMA}`, - `clusterSeedTarget=${target}`, - "clusterSeedRelativePath=cluster-seed", - "icuClusterSeedRelativePath=cluster-seed-icu", - "", - ].join("\n")); -} - -export function bindNativeRuntimeResourceManifest(bytes, target) { - requireTarget(target); - const fields = parseProperties(bytes, "native runtime resource manifest"); - const expectedKeys = new Set(NATIVE_RUNTIME_RESOURCE_MANIFEST_KEYS); - if (fields.size !== expectedKeys.size - || [...fields.keys()].some((key) => !expectedKeys.has(key))) { - throw new Error("native runtime resource manifest must contain its exact canonical field set"); - } - if (fields.get("schema") !== "oliphaunt-runtime-resources-v1" - || fields.get("layout") !== "postgres-runtime-files-v1" - || fields.get("artifactRole") !== "runtime" - || fields.get("catalogProfile") !== "" - || !["", target].includes(fields.get("clusterSeedTarget")) - || fields.get("mode") !== "native-direct" - || !validNativeCacheKey(fields.get("cacheKey") ?? "")) { - throw new Error("native runtime resource manifest has an incompatible native-direct contract"); - } - const registryState = fields.get("mobileStaticRegistryState"); - const expectedSource = registryState === "complete" - ? "static-registry/oliphaunt_static_registry.c" - : ""; - if (fields.get("mobileStaticRegistrySource") !== expectedSource) { - throw new Error("native runtime resource manifest has inconsistent mobileStaticRegistrySource"); - } - fields.set("clusterSeedTarget", target); - return Buffer.from(`${NATIVE_RUNTIME_RESOURCE_MANIFEST_KEYS.map((key) => `${key}=${fields.get(key)}`).join("\n")}\n`); -} - -export function validateNativeRuntimeCarrier(root, { icuData } = {}) { - const manifestPath = path.join(root, "manifest.properties"); - const fields = parseProperties(readFileSync(manifestPath), manifestPath); - if (fields.get("schema") !== NATIVE_RUNTIME_CARRIER_SCHEMA) { - throw new Error(`${manifestPath}: unsupported schema`); - } - const target = fields.get("clusterSeedTarget"); - requireTarget(target); - if (fields.size !== 4 - || fields.get("clusterSeedRelativePath") !== "cluster-seed" - || fields.get("icuClusterSeedRelativePath") !== "cluster-seed-icu") { - throw new Error(`${manifestPath}: single-target seed paths are invalid`); - } - const runtimeManifestPath = path.join(root, "runtime/manifest.properties"); - const runtimeManifest = readFileSync(runtimeManifestPath); - const canonicalRuntimeManifest = bindNativeRuntimeResourceManifest(runtimeManifest, target); - if (!runtimeManifest.equals(canonicalRuntimeManifest)) { - throw new Error(`${runtimeManifestPath}: runtime resource manifest is not canonical for ${target}`); - } - validateNativeClusterSeedDirectory(path.join(root, "cluster-seed"), "standard", { target }); - validateNativeClusterSeedDirectory(path.join(root, "cluster-seed-icu"), "icu", { target, icuData }); - return Object.freeze({ target }); -} - -function parseArgs(argv) { - const values = new Map(); - for (let index = 0; index < argv.length; index += 2) { - const key = argv[index]; - const value = argv[index + 1]; - if (!key?.startsWith("--") || value === undefined || value.startsWith("--") || values.has(key)) { - throw new Error("usage: native-runtime-carrier-contract.mjs --root DIR --target TARGET --icu-data DIR"); - } - values.set(key, value); - } - const root = values.get("--root"); - const target = values.get("--target"); - const icuData = values.get("--icu-data"); - if (!root || !icuData || !target || values.size !== 3) { - throw new Error("usage: native-runtime-carrier-contract.mjs --root DIR --target TARGET --icu-data DIR"); - } - return { root: path.resolve(root), target, icuData: path.resolve(icuData) }; -} - -if (import.meta.main) { - try { - const args = parseArgs(process.argv.slice(2)); - const manifest = nativeRuntimeCarrierManifest(args.target); - writeFileSync(path.join(args.root, "manifest.properties"), manifest); - const result = validateNativeRuntimeCarrier(args.root, { icuData: args.icuData }); - console.log(`clusterSeedTarget=${result.target}`); - } catch (error) { - console.error(`native-runtime-carrier-contract.mjs: ${error instanceof Error ? error.message : String(error)}`); - process.exit(2); - } -} diff --git a/tools/release/native-runtime-carrier-contract.test.mjs b/tools/release/native-runtime-carrier-contract.test.mjs deleted file mode 100644 index f559df9b6..000000000 --- a/tools/release/native-runtime-carrier-contract.test.mjs +++ /dev/null @@ -1,33 +0,0 @@ -import { expect, test } from "bun:test"; - -import { - bindNativeRuntimeResourceManifest, - nativeRuntimeCarrierManifest, -} from "./native-runtime-carrier-contract.mjs"; -import { nativeRuntimeResourceManifestFixture } from "../test/native-runtime-fixture.mjs"; - -test("renders the minimal single-target native runtime carrier receipt", () => { - expect(nativeRuntimeCarrierManifest("linux-x64-gnu").toString("utf8")).toBe( - "schema=oliphaunt-native-runtime-carrier-v1\n" - + "clusterSeedTarget=linux-x64-gnu\n" - + "clusterSeedRelativePath=cluster-seed\n" - + "icuClusterSeedRelativePath=cluster-seed-icu\n", - ); -}); - -test("binds only the exact native-direct runtime resource contract", () => { - const bound = bindNativeRuntimeResourceManifest(nativeRuntimeResourceManifestFixture(), "android-datum64"); - expect(bound.toString("utf8")).toContain("clusterSeedTarget=android-datum64\n"); - expect(() => bindNativeRuntimeResourceManifest( - nativeRuntimeResourceManifestFixture({ extra: { legacy: "value" } }), - "android-datum64", - )).toThrow(/exact canonical field set/u); - expect(() => bindNativeRuntimeResourceManifest( - nativeRuntimeResourceManifestFixture({ overrides: { cacheKey: ".." } }), - "android-datum64", - )).toThrow(/native-direct contract/u); - expect(() => bindNativeRuntimeResourceManifest( - nativeRuntimeResourceManifestFixture({ overrides: { mode: "native-server" } }), - "android-datum64", - )).toThrow(/native-direct contract/u); -}); diff --git a/tools/release/native-script-self-identity.test.mjs b/tools/release/native-script-self-identity.test.mjs deleted file mode 100644 index a0a3ae2fd..000000000 --- a/tools/release/native-script-self-identity.test.mjs +++ /dev/null @@ -1,50 +0,0 @@ -import { expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import path from "node:path"; - -import { ROOT } from "./release-graph.mjs"; - -const commonScript = path.join( - ROOT, - "src/runtimes/liboliphaunt/native/bin/common.sh", -); - -test("native extension identities use the canonical generated source checkout mapping", () => { - for (const [extension, expected] of [ - ["pg_hashids", "target/oliphaunt-sources/checkouts/pg_hashids"], - ["vector", "target/oliphaunt-sources/checkouts/pgvector"], - ["pgvector", "target/oliphaunt-sources/checkouts/pgvector"], - ["postgis", "target/oliphaunt-sources/checkouts/postgis"], - ]) { - const result = spawnSync( - "sh", - [ - "-c", - '. "$1"; oliphaunt_native_external_extension_source_rel "$2" "$3"', - "native-extension-source-map-test", - commonScript, - ROOT, - extension, - ], - { encoding: "utf8", cwd: path.dirname(ROOT) }, - ); - expect(result.status, result.stderr).toBe(0); - expect(result.stdout.trim()).toBe(expected); - } - - const unknown = spawnSync( - "sh", - [ - "-c", - '. "$1"; oliphaunt_native_external_extension_source_rel "$2" "$3"', - "native-extension-source-map-test", - commonScript, - ROOT, - "unknown-extension", - ], - { encoding: "utf8", cwd: path.dirname(ROOT) }, - ); - expect(unknown.status).not.toBe(0); - expect(unknown.stdout).toBe(""); - -}); diff --git a/tools/release/native-tools-npm-facade.test.mjs b/tools/release/native-tools-npm-facade.test.mjs deleted file mode 100644 index 1e1eb66ee..000000000 --- a/tools/release/native-tools-npm-facade.test.mjs +++ /dev/null @@ -1,114 +0,0 @@ -import assert from 'node:assert/strict'; -import { readFile } from 'node:fs/promises'; -import test from 'node:test'; - -import { - PostgresToolError, - pgDump, - psql, -} from '../../src/runtimes/liboliphaunt/native/tools-npm/index.js'; - -const fixture = JSON.parse( - await readFile( - new URL('../../src/shared/fixtures/postgres/logical-tools.json', import.meta.url), - 'utf8', - ), -); - -test('native npm tools accept every shared ordinary argument before process startup', async () => { - for (const argument of fixture.pgDump.acceptedArgs) { - await assert.rejects( - pgDump('postgresql://postgres@127.0.0.1:1/postgres', { args: [argument] }), - (error) => error instanceof PostgresToolError && error.tool === 'pg_dump', - argument, - ); - } - for (const args of fixture.pgDump.acceptedArgv) { - await assert.rejects( - pgDump('postgresql://postgres@127.0.0.1:1/postgres', { args }), - (error) => error instanceof PostgresToolError && error.tool === 'pg_dump', - args.join(' '), - ); - } - for (const argument of fixture.psql.acceptedArgs) { - await assert.rejects( - psql('postgresql://postgres@127.0.0.1:1/postgres', { - args: [argument], - command: 'SELECT 1', - }), - (error) => error instanceof PostgresToolError && error.tool === 'psql', - argument, - ); - } - for (const args of fixture.psql.acceptedArgv) { - await assert.rejects( - psql('postgresql://postgres@127.0.0.1:1/postgres', { - args, - command: 'SELECT 1', - }), - (error) => error instanceof PostgresToolError && error.tool === 'psql', - args.join(' '), - ); - } -}); - -test('native npm tools reject every shared managed pg_dump argument', async () => { - for (const argument of fixture.pgDump.rejectedArgs) { - await assert.rejects( - pgDump('postgresql://postgres@127.0.0.1/postgres', { args: [argument] }), - /conflicts with Oliphaunt's managed/u, - argument, - ); - } - for (const args of fixture.pgDump.rejectedArgv) { - await assert.rejects( - pgDump('postgresql://postgres@127.0.0.1/postgres', { args }), - /conflicts with Oliphaunt's managed|requires a value/u, - args.join(' '), - ); - } -}); - -test('native npm tools reject every shared managed psql argument', async () => { - for (const argument of fixture.psql.rejectedArgs) { - await assert.rejects( - psql('postgresql://postgres@127.0.0.1/postgres', { - args: [argument], - command: 'SELECT 1', - }), - /conflicts with Oliphaunt's managed/u, - argument, - ); - } - for (const args of fixture.psql.rejectedArgv) { - await assert.rejects( - psql('postgresql://postgres@127.0.0.1/postgres', { - args, - command: 'SELECT 1', - }), - /conflicts with Oliphaunt's managed|requires a value/u, - args.join(' '), - ); - } -}); - -test('native npm psql requires one non-interactive input form', async () => { - await assert.rejects( - psql('postgresql://postgres@127.0.0.1/postgres'), - /requires non-interactive input/u, - ); - await assert.rejects( - psql('postgresql://postgres@127.0.0.1/postgres', { - command: 'SELECT 1', - script: 'SELECT 2;', - }), - /command or script, not both/u, - ); -}); - -test('native npm tools preserve a structured process failure', async () => { - await assert.rejects( - pgDump('postgresql://postgres@127.0.0.1:1/postgres'), - (error) => error instanceof PostgresToolError && error.tool === 'pg_dump', - ); -}); diff --git a/tools/release/native-tools-npm-facade.test.mts b/tools/release/native-tools-npm-facade.test.mts new file mode 100644 index 000000000..260130039 --- /dev/null +++ b/tools/release/native-tools-npm-facade.test.mts @@ -0,0 +1,110 @@ +import assert from 'node:assert/strict'; +import { readFile } from 'node:fs/promises'; +import test from 'node:test'; + +import { PostgresToolError, pgDump, psql } from '../../src/postgres-tools/native/npm/index.mts'; + +const fixture = JSON.parse( + await readFile( + new URL('../../src/test-fixtures/postgres/logical-tools.json', import.meta.url), + 'utf8', + ), +); + +test('native npm tools accept every shared ordinary argument before process startup', async () => { + for (const argument of fixture.pgDump.acceptedArgs) { + await assert.rejects( + pgDump('postgresql://postgres@127.0.0.1:1/postgres', { args: [argument] }), + (error) => error instanceof PostgresToolError && error.tool === 'pg_dump', + argument, + ); + } + for (const args of fixture.pgDump.acceptedArgv) { + await assert.rejects( + pgDump('postgresql://postgres@127.0.0.1:1/postgres', { args }), + (error) => error instanceof PostgresToolError && error.tool === 'pg_dump', + args.join(' '), + ); + } + for (const argument of fixture.psql.acceptedArgs) { + await assert.rejects( + psql('postgresql://postgres@127.0.0.1:1/postgres', { + args: [argument], + command: 'SELECT 1', + }), + (error) => error instanceof PostgresToolError && error.tool === 'psql', + argument, + ); + } + for (const args of fixture.psql.acceptedArgv) { + await assert.rejects( + psql('postgresql://postgres@127.0.0.1:1/postgres', { + args, + command: 'SELECT 1', + }), + (error) => error instanceof PostgresToolError && error.tool === 'psql', + args.join(' '), + ); + } +}); + +test('native npm tools reject every shared managed pg_dump argument', async () => { + for (const argument of fixture.pgDump.rejectedArgs) { + await assert.rejects( + pgDump('postgresql://postgres@127.0.0.1/postgres', { args: [argument] }), + /conflicts with Oliphaunt's managed/u, + argument, + ); + } + for (const args of fixture.pgDump.rejectedArgv) { + await assert.rejects( + pgDump('postgresql://postgres@127.0.0.1/postgres', { args }), + /conflicts with Oliphaunt's managed|requires a value/u, + args.join(' '), + ); + } +}); + +test('native npm tools reject every shared managed psql argument', async () => { + for (const argument of fixture.psql.rejectedArgs) { + await assert.rejects( + psql('postgresql://postgres@127.0.0.1/postgres', { + args: [argument], + command: 'SELECT 1', + }), + /conflicts with Oliphaunt's managed/u, + argument, + ); + } + for (const args of fixture.psql.rejectedArgv) { + await assert.rejects( + psql('postgresql://postgres@127.0.0.1/postgres', { + args, + command: 'SELECT 1', + }), + /conflicts with Oliphaunt's managed|requires a value/u, + args.join(' '), + ); + } +}); + +test('native npm psql requires one non-interactive input form', async () => { + await assert.rejects( + psql('postgresql://postgres@127.0.0.1/postgres'), + /requires non-interactive input/u, + ); + await assert.rejects( + psql('postgresql://postgres@127.0.0.1/postgres', { + command: 'SELECT 1', + script: 'SELECT 2;', + }), + /command or script, not both/u, + ); +}); + +test('native npm tools preserve a structured process failure', async () => { + await assert.rejects( + pgDump('postgresql://postgres@127.0.0.1:1/postgres'), + (error) => error instanceof PostgresToolError && error.tool === 'pg_dump', + ); +}); diff --git a/tools/release/node-fallback-install.test.mjs b/tools/release/node-fallback-install.test.mjs deleted file mode 100644 index 0098ef670..000000000 --- a/tools/release/node-fallback-install.test.mjs +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bun - -import {spawnSync} from '../test/fd-backed-spawn-sync.mjs'; -import path from 'node:path'; -import {test} from 'node:test'; - -import {ROOT} from './release-graph.mjs'; - -const NODE_FALLBACK_PROCESS_TIMEOUT_MS = 15_000; - -test('Node fallback downloads fail closed before cache promotion', () => { - const script = path.join( - ROOT, - 'tools/release/install-node-fallback.test.sh', - ); - const result = spawnSync('bash', [script], { - cwd: ROOT, - encoding: 'utf8', - timeout: NODE_FALLBACK_PROCESS_TIMEOUT_MS, - }); - if (result.error !== undefined) { - throw result.error; - } - if (result.status !== 0) { - throw new Error( - `Node fallback fault suite failed\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`, - ); - } -}); diff --git a/tools/release/normal-publication-executor.mjs b/tools/release/normal-publication-executor.mjs deleted file mode 100644 index ace82787a..000000000 --- a/tools/release/normal-publication-executor.mjs +++ /dev/null @@ -1,325 +0,0 @@ -import { - CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE, - CRATES_IO_TRUSTED_TOKEN_MAX_BATCH_AGE_MS, - withCratesIoTrustedPublishingToken, -} from "./crates-io-trusted-publishing.mjs"; - -const ECOSYSTEMS = ["cargo", "npm", "maven"]; - -function error(message) { - return new Error(`normal-publication-executor: ${message}`); -} - -function validatePlan(plan) { - if (plan === null || typeof plan !== "object" || !Array.isArray(plan.operations)) { - throw error("plan must contain an operations list"); - } - const operationIds = new Set(); - const carrierIds = new Set(); - for (const [index, operation] of plan.operations.entries()) { - if (operation?.operationOrder !== index || typeof operation.id !== "string" || operation.id.length === 0) { - throw error(`operation ${index} is not in a contiguous canonical order`); - } - if (operationIds.has(operation.id)) { - throw error(`operation id ${operation.id} is duplicated`); - } - operationIds.add(operation.id); - if ( - !Array.isArray(operation.dependencies) - || new Set(operation.dependencies).size !== operation.dependencies.length - || operation.dependencies.some((dependency) => typeof dependency !== "string" || dependency.length === 0) - ) { - throw error(`operation ${operation.id} dependencies must be a unique string list`); - } - if (operation.kind === "carrier") { - if ( - !new Set(["cargo", "npm"]).has(operation.ecosystem) - || typeof operation.carrierId !== "string" - || !operation.carrierId.startsWith(`${operation.ecosystem}:`) - || carrierIds.has(operation.carrierId) - ) { - throw error(`carrier operation ${operation.id} is invalid`); - } - carrierIds.add(operation.carrierId); - } else if (operation.kind === "maven-atomic-deployment") { - if ( - operation.ecosystem !== "maven" - || !Array.isArray(operation.carrierIds) - || operation.carrierIds.length === 0 - || new Set(operation.carrierIds).size !== operation.carrierIds.length - || operation.carrierIds.some((id) => typeof id !== "string" || !id.startsWith("maven:") || carrierIds.has(id)) - ) { - throw error(`Maven operation ${operation.id} is invalid`); - } - for (const id of operation.carrierIds) carrierIds.add(id); - } else { - throw error(`operation ${operation.id} has unsupported kind ${JSON.stringify(operation.kind)}`); - } - } - const positions = new Map(plan.operations.map((operation, index) => [operation.id, index])); - for (const [index, operation] of plan.operations.entries()) { - for (const dependency of operation.dependencies) { - const dependencyPosition = positions.get(dependency); - if (dependencyPosition === undefined) { - throw error(`operation ${operation.id} refers to unknown dependency ${dependency}`); - } - if (dependencyPosition >= index) { - throw error(`operation ${operation.id} is not ordered after dependency ${dependency}`); - } - } - } -} - -function receiptList(value) { - return value === undefined ? [] : Array.isArray(value) ? value : [value]; -} - -function requireReceipt(receipt, context) { - if (receipt === null || Array.isArray(receipt) || typeof receipt !== "object" || typeof receipt.id !== "string") { - throw error(`${context} contains an invalid registry receipt`); - } -} - -/** - * Merge immutable bootstrap receipts with the exact receipts returned by each - * operation. Coverage is checked against the frozen plan before the caller - * writes evidence; no callback may omit, add, duplicate, or replace a carrier. - */ -export function collectNormalPublicationReceipts({ - plan, - initialReceipts = [], - operationResults, -}) { - validatePlan(plan); - if (!Array.isArray(initialReceipts)) throw error("initial registry receipts must be a list"); - if (!Array.isArray(operationResults) || operationResults.length !== plan.operations.length) { - throw error("operation results must exactly cover the canonical publication plan"); - } - const carrierOperation = new Map(); - for (const operation of plan.operations) { - for (const id of operation.kind === "carrier" ? [operation.carrierId] : operation.carrierIds) { - carrierOperation.set(id, operation); - } - } - const collected = new Map(); - for (const receipt of initialReceipts) { - requireReceipt(receipt, "initial registry receipts"); - const operation = carrierOperation.get(receipt.id); - if (operation === undefined || !new Set(["cargo", "npm"]).has(operation.ecosystem)) { - throw error(`initial registry receipt ${receipt.id} is not a selected Cargo/npm bootstrap carrier`); - } - if (collected.has(receipt.id)) throw error(`initial registry receipt ${receipt.id} is duplicated`); - collected.set(receipt.id, receipt); - } - const initialIds = new Set(collected.keys()); - for (const [index, operation] of plan.operations.entries()) { - const expectedIds = (operation.kind === "carrier" ? [operation.carrierId] : operation.carrierIds) - .filter((id) => !initialIds.has(id)); - const receipts = receiptList(operationResults[index]); - const observedIds = new Set(); - for (const receipt of receipts) { - requireReceipt(receipt, `operation ${operation.id}`); - if (observedIds.has(receipt.id)) throw error(`operation ${operation.id} returned duplicate registry receipt ${receipt.id}`); - observedIds.add(receipt.id); - } - if (observedIds.size !== expectedIds.length || expectedIds.some((id) => !observedIds.has(id))) { - throw error( - `operation ${operation.id} did not return receipts for its exact non-bootstrap carrier set: expected ${expectedIds.join(", ") || "none"}`, - ); - } - for (const receipt of receipts) { - if (collected.has(receipt.id)) throw error(`operation ${operation.id} attempted to replace registry receipt ${receipt.id}`); - collected.set(receipt.id, receipt); - } - } - return collected; -} - -function strictBatchSize(value) { - const raw = value ?? CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE; - const parsed = typeof raw === "number" ? raw : Number(raw); - if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE) { - throw error(`Cargo trusted-publishing batch size must be an integer from 1 through ${CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE}`); - } - return parsed; -} - -function deferred() { - let resolve; - const promise = new Promise((accept) => { - resolve = accept; - }); - return { promise, resolve }; -} - -function cargoBatches(operations, operationById, batchSize) { - const batches = []; - let batch = []; - for (const operation of operations) { - const hasCrossEcosystemDependency = operation.dependencies.some( - (dependency) => operationById.get(dependency).ecosystem !== "cargo", - ); - if (batch.length >= batchSize || (batch.length > 0 && hasCrossEcosystemDependency)) { - batches.push(batch); - batch = []; - } - batch.push(operation); - } - if (batch.length > 0) batches.push(batch); - return batches; -} - -/** - * Execute the exact topology plan with one bounded lane per registry. The - * frozen operation order is a topological order; each lane preserves its - * projection of that order and awaits arbitrary cross-ecosystem dependencies. - * Independent registries therefore overlap without allowing two mutations in - * one ecosystem at once. Cargo additionally retains bounded temporary-token - * batches and mandatory revocation on success, failure, or peer-lane abort. - * - * Callback return values are preserved in canonical operation order so the - * caller can assemble immutable receipts without downloading every registry - * payload a second time. - */ -export async function executeNormalPublicationPlan({ - plan, - cargoVersionPublished, - publishCarrier, - publishMaven, - tokenOptions = {}, - batchSize = CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE, - nowImpl = Date.now, -}) { - validatePlan(plan); - if (typeof cargoVersionPublished !== "function" || typeof publishCarrier !== "function" || typeof publishMaven !== "function") { - throw error("cargoVersionPublished, publishCarrier, and publishMaven callbacks are required"); - } - const boundedBatchSize = strictBatchSize(batchSize); - const operations = plan.operations; - const operationById = new Map(operations.map((operation) => [operation.id, operation])); - const completions = new Map(operations.map((operation) => [operation.id, deferred()])); - const results = new Array(operations.length); - let firstFailure; - let aborted = false; - let signalAbort; - const abortSignal = new Promise((resolve) => { - signalAbort = resolve; - }); - - function failAll(cause) { - const failure = cause instanceof Error ? cause : error(String(cause)); - if (firstFailure === undefined) firstFailure = failure; - if (!aborted) { - aborted = true; - signalAbort(); - } - } - - function requireActive() { - if (aborted) throw firstFailure ?? error("publication aborted"); - } - - async function waitForDependencies(operation) { - requireActive(); - const dependencies = Promise.all( - operation.dependencies.map((dependency) => completions.get(dependency).promise), - ); - await Promise.race([dependencies, abortSignal]); - requireActive(); - } - - async function complete(operation, value) { - results[operation.operationOrder] = value; - completions.get(operation.id).resolve(); - } - - async function runSimpleLane(ecosystem) { - try { - for (const operation of operations.filter( - (candidate) => candidate.ecosystem === ecosystem, - )) { - await waitForDependencies(operation); - requireActive(); - const value = operation.kind === "maven-atomic-deployment" - ? await publishMaven(operation) - : await publishCarrier(operation, { alreadyPublished: undefined }); - await complete(operation, value); - } - } catch (cause) { - failAll(cause); - } - } - - async function runCargoLane() { - const cargo = operations.filter( - (operation) => operation.ecosystem === "cargo", - ); - try { - for (const operationsBatch of cargoBatches(cargo, operationById, boundedBatchSize)) { - // A batch starts at every cross-registry dependency boundary. Later - // operations in the batch can therefore depend only on earlier Cargo - // operations, which this lane completes in order under one token. - await waitForDependencies(operationsBatch[0]); - const batch = []; - for (const operation of operationsBatch) { - requireActive(); - batch.push({ - operation, - alreadyPublished: await cargoVersionPublished(operation), - }); - } - const pending = batch.filter(({ alreadyPublished }) => !alreadyPublished); - if (pending.length === 0) { - for (const item of batch) { - requireActive(); - await complete( - item.operation, - await publishCarrier(item.operation, { alreadyPublished: true }), - ); - } - continue; - } - - requireActive(); - await withCratesIoTrustedPublishingToken(async (session) => { - const tokenDeadlineEpochMs = Math.min( - session.expiresAt, - session.acquiredAt + CRATES_IO_TRUSTED_TOKEN_MAX_BATCH_AGE_MS, - session.publicationDeadlineEpochMs, - ); - for (const item of batch) { - requireActive(); - if (item.alreadyPublished) { - await complete( - item.operation, - await publishCarrier(item.operation, { alreadyPublished: true }), - ); - continue; - } - const operationNow = nowImpl(); - if (operationNow >= tokenDeadlineEpochMs) { - throw error(`temporary Cargo token batch expired before ${item.operation.carrierId}`); - } - await complete( - item.operation, - await publishCarrier(item.operation, { - alreadyPublished: false, - cargoToken: session.token, - tokenDeadlineEpochMs, - }), - ); - } - }, { ...tokenOptions, nowImpl }); - } - } catch (cause) { - failAll(cause); - } - } - - await Promise.all([ - runCargoLane(), - ...ECOSYSTEMS.filter((ecosystem) => ecosystem !== "cargo").map(runSimpleLane), - ]); - if (firstFailure !== undefined) throw firstFailure; - return { operationResults: results }; -} diff --git a/tools/release/normal-publication-executor.mts b/tools/release/normal-publication-executor.mts new file mode 100644 index 000000000..382b5e3c3 --- /dev/null +++ b/tools/release/normal-publication-executor.mts @@ -0,0 +1,246 @@ +import { + CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE, + CRATES_IO_TRUSTED_TOKEN_MAX_BATCH_AGE_MS, + withCratesIoTrustedPublishingToken, +} from './crates-io-trusted-publishing.mts'; + +function error(message) { + return new Error(`normal-publication-executor: ${message}`); +} + +function validatePlan(plan) { + if (plan === null || typeof plan !== 'object' || !Array.isArray(plan.operations)) { + throw error('plan must contain an operations list'); + } + const operationIds = new Set(); + const carrierIds = new Set(); + for (const [index, operation] of plan.operations.entries()) { + if ( + operation?.operationOrder !== index || + typeof operation.id !== 'string' || + operation.id.length === 0 + ) { + throw error(`operation ${index} is not in a contiguous canonical order`); + } + if (operationIds.has(operation.id)) { + throw error(`operation id ${operation.id} is duplicated`); + } + operationIds.add(operation.id); + if ( + !Array.isArray(operation.dependencies) || + new Set(operation.dependencies).size !== operation.dependencies.length || + operation.dependencies.some( + (dependency) => typeof dependency !== 'string' || dependency.length === 0, + ) + ) { + throw error(`operation ${operation.id} dependencies must be a unique string list`); + } + if (operation.kind === 'carrier') { + if ( + !new Set(['cargo', 'npm']).has(operation.ecosystem) || + typeof operation.carrierId !== 'string' || + !operation.carrierId.startsWith(`${operation.ecosystem}:`) || + carrierIds.has(operation.carrierId) + ) { + throw error(`carrier operation ${operation.id} is invalid`); + } + carrierIds.add(operation.carrierId); + } else if (operation.kind === 'maven-atomic-deployment') { + if ( + operation.ecosystem !== 'maven' || + !Array.isArray(operation.carrierIds) || + operation.carrierIds.length === 0 || + new Set(operation.carrierIds).size !== operation.carrierIds.length || + operation.carrierIds.some( + (id) => typeof id !== 'string' || !id.startsWith('maven:') || carrierIds.has(id), + ) + ) { + throw error(`Maven operation ${operation.id} is invalid`); + } + for (const id of operation.carrierIds) carrierIds.add(id); + } else { + throw error( + `operation ${operation.id} has unsupported kind ${JSON.stringify(operation.kind)}`, + ); + } + } + const positions = new Map(plan.operations.map((operation, index) => [operation.id, index])); + for (const [index, operation] of plan.operations.entries()) { + for (const dependency of operation.dependencies) { + const dependencyPosition = positions.get(dependency); + if (dependencyPosition === undefined) { + throw error(`operation ${operation.id} refers to unknown dependency ${dependency}`); + } + if (dependencyPosition >= index) { + throw error(`operation ${operation.id} is not ordered after dependency ${dependency}`); + } + } + } +} + +function receiptList(value) { + return value === undefined ? [] : Array.isArray(value) ? value : [value]; +} + +function requireReceipt(receipt, context) { + if ( + receipt === null || + Array.isArray(receipt) || + typeof receipt !== 'object' || + typeof receipt.id !== 'string' + ) { + throw error(`${context} contains an invalid registry receipt`); + } +} + +/** + * Merge immutable bootstrap receipts with the exact receipts returned by each + * operation. Coverage is checked against the frozen plan before the caller + * writes evidence; no callback may omit, add, duplicate, or replace a carrier. + */ +export function collectNormalPublicationReceipts({ plan, initialReceipts = [], operationResults }) { + validatePlan(plan); + if (!Array.isArray(initialReceipts)) throw error('initial registry receipts must be a list'); + if (!Array.isArray(operationResults) || operationResults.length !== plan.operations.length) { + throw error('operation results must exactly cover the canonical publication plan'); + } + const carrierOperation = new Map(); + for (const operation of plan.operations) { + for (const id of operation.kind === 'carrier' ? [operation.carrierId] : operation.carrierIds) { + carrierOperation.set(id, operation); + } + } + const collected = new Map(); + for (const receipt of initialReceipts) { + requireReceipt(receipt, 'initial registry receipts'); + const operation = carrierOperation.get(receipt.id); + if (operation === undefined || !new Set(['cargo', 'npm']).has(operation.ecosystem)) { + throw error( + `initial registry receipt ${receipt.id} is not a selected Cargo/npm bootstrap carrier`, + ); + } + if (collected.has(receipt.id)) + throw error(`initial registry receipt ${receipt.id} is duplicated`); + collected.set(receipt.id, receipt); + } + const initialIds = new Set(collected.keys()); + for (const [index, operation] of plan.operations.entries()) { + const expectedIds = ( + operation.kind === 'carrier' ? [operation.carrierId] : operation.carrierIds + ).filter((id) => !initialIds.has(id)); + const receipts = receiptList(operationResults[index]); + const observedIds = new Set(); + for (const receipt of receipts) { + requireReceipt(receipt, `operation ${operation.id}`); + if (observedIds.has(receipt.id)) + throw error(`operation ${operation.id} returned duplicate registry receipt ${receipt.id}`); + observedIds.add(receipt.id); + } + if (observedIds.size !== expectedIds.length || expectedIds.some((id) => !observedIds.has(id))) { + throw error( + `operation ${operation.id} did not return receipts for its exact non-bootstrap carrier set: expected ${expectedIds.join(', ') || 'none'}`, + ); + } + for (const receipt of receipts) { + if (collected.has(receipt.id)) + throw error( + `operation ${operation.id} attempted to replace registry receipt ${receipt.id}`, + ); + collected.set(receipt.id, receipt); + } + } + return collected; +} + +function strictBatchSize(value) { + const raw = value ?? CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE; + const parsed = typeof raw === 'number' ? raw : Number(raw); + if ( + !Number.isSafeInteger(parsed) || + parsed < 1 || + parsed > CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE + ) { + throw error( + `Cargo trusted-publishing batch size must be an integer from 1 through ${CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE}`, + ); + } + return parsed; +} + +function cargoBatches(operations, operationById, batchSize) { + const batches = []; + let batch = []; + for (const operation of operations) { + const hasCrossEcosystemDependency = operation.dependencies.some( + (dependency) => operationById.get(dependency).ecosystem !== 'cargo', + ); + if (batch.length >= batchSize || (batch.length > 0 && hasCrossEcosystemDependency)) { + batches.push(batch); + batch = []; + } + batch.push(operation); + } + if (batch.length > 0) batches.push(batch); + return batches; +} + +export function normalPublicationSchedule(plan, batchSize) { + validatePlan(plan); + const byId = new Map(plan.operations.map((operation) => [operation.id, operation])); + return { + cargoBatches: cargoBatches( + plan.operations.filter((operation) => operation.ecosystem === 'cargo'), + byId, + strictBatchSize(batchSize), + ).map((batch) => batch.map((operation) => operation.operationOrder)), + dependencies: plan.operations.map((operation) => + operation.dependencies.map((id) => byId.get(id).operationOrder), + ), + }; +} + +export async function executeCargoPublicationBatch({ + operations, + cargoVersionPublished, + publishCarrier, + isAborted, + tokenOptions = {}, + nowImpl = Date.now, +}) { + const active = () => { + if (isAborted()) throw error('peer registry lane failed; stopping Cargo admission'); + }; + if ( + !operations.length || + operations.length > CRATES_IO_TRUSTED_TOKEN_DEFAULT_BATCH_SIZE || + operations.some((operation) => operation.ecosystem !== 'cargo') + ) + throw error('invalid Cargo publication batch'); + const batch = []; + for (const operation of operations) { + active(); + batch.push({ operation, alreadyPublished: await cargoVersionPublished(operation) }); + } + const publish = async (session) => { + const tokenDeadlineEpochMs = + session && + Math.min( + session.expiresAt, + session.acquiredAt + CRATES_IO_TRUSTED_TOKEN_MAX_BATCH_AGE_MS, + session.publicationDeadlineEpochMs, + ); + for (const { operation, alreadyPublished } of batch) { + active(); + if (!alreadyPublished && nowImpl() >= tokenDeadlineEpochMs) + throw error('temporary Cargo token batch expired before ' + operation.carrierId); + await publishCarrier(operation, { + alreadyPublished, + cargoToken: session?.token, + tokenDeadlineEpochMs, + }); + } + }; + active(); + if (batch.every((item) => item.alreadyPublished)) await publish(); + else await withCratesIoTrustedPublishingToken(publish, { ...tokenOptions, nowImpl }); +} diff --git a/tools/release/normal-publication-executor.test.mjs b/tools/release/normal-publication-executor.test.mjs deleted file mode 100644 index ae20a3daf..000000000 --- a/tools/release/normal-publication-executor.test.mjs +++ /dev/null @@ -1,431 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { - collectNormalPublicationReceipts, - executeNormalPublicationPlan, -} from "./normal-publication-executor.mjs"; -import { runOrThrow } from "./release-cli-utils.mjs"; - -function operation(ecosystem, index, carrierId = `${ecosystem}:package-${index}`) { - return { - id: `carrier:${carrierId}`, - kind: "carrier", - ecosystem, - carrierId, - dependencies: [], - operationOrder: index, - }; -} - -function deferred() { - let resolve; - const promise = new Promise((accept) => { - resolve = accept; - }); - return { promise, resolve }; -} - -function tokenFetch(methods, tokens = ["cargo-token"]) { - let tokenIndex = 0; - return async (_url, init) => { - methods.push(init.method); - if (init.method === "GET") return Response.json({ value: `jwt-${tokenIndex}` }); - if (init.method === "POST") return Response.json({ token: tokens[tokenIndex++] ?? `token-${tokenIndex}` }); - return new Response("", { status: 200 }); - }; -} - -const tokenEnvironment = { - GITHUB_ACTIONS: "true", - ACTIONS_ID_TOKEN_REQUEST_URL: "https://pipelines.actions.example/token", - ACTIONS_ID_TOKEN_REQUEST_TOKEN: "request-token", -}; - -describe("normal publication executor", () => { - test("collects exact per-operation receipts without omission, addition, duplication, or bootstrap replacement", () => { - const cargo = operation("cargo", 0); - const npm = operation("npm", 1); - const maven = { - id: "maven:atomic-deployment", - kind: "maven-atomic-deployment", - ecosystem: "maven", - carrierIds: ["maven:a", "maven:b"], - dependencies: [], - operationOrder: 2, - }; - const cargoReceipt = { id: cargo.carrierId, proof: "bootstrap" }; - const npmReceipt = { id: npm.carrierId, proof: "npm" }; - const mavenReceipts = maven.carrierIds.map((id) => ({ id, proof: "maven" })); - const plan = { operations: [cargo, npm, maven] }; - const collected = collectNormalPublicationReceipts({ - plan, - initialReceipts: [cargoReceipt], - operationResults: [undefined, npmReceipt, mavenReceipts], - }); - expect([...collected.values()]).toEqual([cargoReceipt, npmReceipt, ...mavenReceipts]); - expect(() => collectNormalPublicationReceipts({ - plan, - initialReceipts: [cargoReceipt], - operationResults: [undefined, undefined, mavenReceipts], - })).toThrow(/exact non-bootstrap carrier set/u); - expect(() => collectNormalPublicationReceipts({ - plan, - initialReceipts: [cargoReceipt], - operationResults: [cargoReceipt, npmReceipt, mavenReceipts], - })).toThrow(/exact non-bootstrap carrier set/u); - expect(() => collectNormalPublicationReceipts({ - plan, - initialReceipts: [cargoReceipt], - operationResults: [undefined, npmReceipt, [mavenReceipts[0], mavenReceipts[0]]], - })).toThrow(/duplicate registry receipt/u); - }); - - test("executes lock-derived operations and gives Maven one atomic callback", async () => { - const calls = []; - const plan = { - operations: [ - operation("npm", 0), - { - id: "maven:atomic-deployment", - kind: "maven-atomic-deployment", - ecosystem: "maven", - carrierIds: ["maven:a", "maven:b"], - dependencies: [], - operationOrder: 1, - }, - ], - }; - const results = await executeNormalPublicationPlan({ - plan, - cargoVersionPublished: () => { throw new Error("must not inspect Cargo"); }, - publishCarrier: async ({ carrierId }) => { - calls.push(carrierId); - return `receipt:${carrierId}`; - }, - publishMaven: async ({ carrierIds }) => { - calls.push(carrierIds.join("+")); - return carrierIds.map((carrierId) => `receipt:${carrierId}`); - }, - }); - expect(calls.toSorted()).toEqual(["maven:a+maven:b", "npm:package-0"]); - expect(results.operationResults).toEqual([ - "receipt:npm:package-0", - ["receipt:maven:a", "receipt:maven:b"], - ]); - }); - - test("overlaps independent lanes while serializing operations within each registry", async () => { - const npmStarted = deferred(); - const cargoStarted = deferred(); - const releaseNpm = deferred(); - const releaseCargo = deferred(); - let secondNpmStarted = false; - const run = executeNormalPublicationPlan({ - plan: { - operations: [ - operation("npm", 0), - operation("cargo", 1), - operation("npm", 2), - ], - }, - cargoVersionPublished: async () => true, - publishCarrier: async ({ carrierId }) => { - if (carrierId === "npm:package-0") { - npmStarted.resolve(); - await releaseNpm.promise; - } else if (carrierId === "cargo:package-1") { - cargoStarted.resolve(); - await releaseCargo.promise; - } else { - secondNpmStarted = true; - } - return carrierId; - }, - publishMaven: () => { throw new Error("must not publish Maven"); }, - tokenOptions: { fetchImpl: () => { throw new Error("must not acquire token"); } }, - }); - - await Promise.all([npmStarted.promise, cargoStarted.promise]); - expect(secondNpmStarted).toBe(false); - releaseNpm.resolve(); - releaseCargo.resolve(); - const result = await run; - expect(result.operationResults).toEqual(["npm:package-0", "cargo:package-1", "npm:package-2"]); - expect(secondNpmStarted).toBe(true); - }); - - test("honors cross-registry dependencies without serializing independent lanes", async () => { - const npmStarted = deferred(); - const cargoStarted = deferred(); - const mavenStarted = deferred(); - const releaseNpm = deferred(); - const releaseMaven = deferred(); - const events = []; - const npm = operation("npm", 0); - const cargo = operation("cargo", 1); - const maven = { - id: "maven:atomic-deployment", - kind: "maven-atomic-deployment", - ecosystem: "maven", - carrierIds: ["maven:a"], - dependencies: [npm.id], - operationOrder: 2, - }; - const output = { - ...operation("npm", 3, "npm:output"), - dependencies: [maven.id], - }; - const run = executeNormalPublicationPlan({ - plan: { operations: [npm, cargo, maven, output] }, - cargoVersionPublished: async () => true, - publishCarrier: async ({ carrierId }) => { - events.push(`start:${carrierId}`); - if (carrierId === npm.carrierId) { - npmStarted.resolve(); - await releaseNpm.promise; - } else if (carrierId === cargo.carrierId) { - cargoStarted.resolve(); - } - events.push(`finish:${carrierId}`); - return carrierId; - }, - publishMaven: async () => { - events.push("start:maven"); - mavenStarted.resolve(); - await releaseMaven.promise; - events.push("finish:maven"); - return ["maven:a"]; - }, - tokenOptions: { fetchImpl: () => { throw new Error("must not acquire token"); } }, - }); - - await Promise.all([npmStarted.promise, cargoStarted.promise]); - expect(events).not.toContain("start:maven"); - releaseNpm.resolve(); - await mavenStarted.promise; - expect(events).not.toContain(`start:${output.carrierId}`); - releaseMaven.resolve(); - await run; - expect(events.indexOf(`finish:${npm.carrierId}`)).toBeLessThan(events.indexOf("start:maven")); - expect(events.indexOf("finish:maven")).toBeLessThan(events.indexOf(`start:${output.carrierId}`)); - }); - - test("splits Cargo token batches at cross-registry dependency barriers", async () => { - const events = []; - const cargoBefore = operation("cargo", 0); - const npm = { - ...operation("npm", 1), - dependencies: [cargoBefore.id], - }; - const cargoAfter = { - ...operation("cargo", 2), - dependencies: [npm.id], - }; - await executeNormalPublicationPlan({ - plan: { operations: [cargoBefore, npm, cargoAfter] }, - cargoVersionPublished: async () => true, - publishCarrier: async ({ carrierId }) => { - events.push(carrierId); - return carrierId; - }, - publishMaven: () => { throw new Error("must not publish Maven"); }, - tokenOptions: { fetchImpl: () => { throw new Error("must not acquire token"); } }, - }); - expect(events).toEqual([cargoBefore.carrierId, npm.carrierId, cargoAfter.carrierId]); - }); - - test("does not acquire a token for lock-matching published Cargo carriers", async () => { - const calls = []; - const results = await executeNormalPublicationPlan({ - plan: { operations: [operation("cargo", 0), operation("cargo", 1)] }, - cargoVersionPublished: async () => true, - publishCarrier: async ({ carrierId }, context) => { - calls.push({ carrierId, context }); - return { id: carrierId, proof: "recovered-public-bytes" }; - }, - publishMaven: () => { throw new Error("must not publish Maven"); }, - tokenOptions: { fetchImpl: () => { throw new Error("must not acquire token"); } }, - }); - expect(calls).toEqual([ - { carrierId: "cargo:package-0", context: { alreadyPublished: true } }, - { carrierId: "cargo:package-1", context: { alreadyPublished: true } }, - ]); - expect(results.operationResults).toEqual([ - { id: "cargo:package-0", proof: "recovered-public-bytes" }, - { id: "cargo:package-1", proof: "recovered-public-bytes" }, - ]); - }); - - test("a root rerun reconciles a published carrier and continues its missing dependent", async () => { - const cargo = operation("cargo", 0); - const npm = { ...operation("npm", 1), dependencies: [cargo.id] }; - const calls = []; - const result = await executeNormalPublicationPlan({ - plan: { operations: [cargo, npm] }, - cargoVersionPublished: async () => true, - publishCarrier: async ({ carrierId }, context) => { - calls.push({ carrierId, context }); - return { id: carrierId, proof: context.alreadyPublished ? "reconciled" : "published" }; - }, - publishMaven: () => { throw new Error("must not publish Maven"); }, - tokenOptions: { fetchImpl: () => { throw new Error("must not acquire token"); } }, - }); - - expect(calls).toEqual([ - { carrierId: cargo.carrierId, context: { alreadyPublished: true } }, - { carrierId: npm.carrierId, context: { alreadyPublished: undefined } }, - ]); - expect(result.operationResults).toEqual([ - { id: cargo.carrierId, proof: "reconciled" }, - { id: npm.carrierId, proof: "published" }, - ]); - }); - - test("uses fresh masked and revoked tokens for bounded contiguous Cargo batches", async () => { - const methods = []; - const masks = []; - const calls = []; - await executeNormalPublicationPlan({ - plan: { operations: [0, 1, 2, 3, 4].map((index) => operation("cargo", index)) }, - cargoVersionPublished: async () => false, - publishCarrier: async ({ carrierId }, context) => calls.push({ carrierId, ...context }), - publishMaven: () => { throw new Error("must not publish Maven"); }, - batchSize: 2, - nowImpl: () => 1000, - tokenOptions: { - env: tokenEnvironment, - fetchImpl: tokenFetch(methods, ["token-a", "token-b", "token-c"]), - maskImpl: (value) => masks.push(value), - }, - }); - expect(methods).toEqual(["GET", "POST", "DELETE", "GET", "POST", "DELETE", "GET", "POST", "DELETE"]); - expect(masks).toEqual(["::add-mask::token-a\n", "::add-mask::token-b\n", "::add-mask::token-c\n"]); - expect(calls.map(({ cargoToken }) => cargoToken)).toEqual(["token-a", "token-a", "token-b", "token-b", "token-c"]); - expect(new Set(calls.map(({ tokenDeadlineEpochMs }) => tokenDeadlineEpochMs))).toEqual(new Set([1_201_000])); - }); - - test("releases the temporary token after a carrier failure", async () => { - const methods = []; - await expect(executeNormalPublicationPlan({ - plan: { operations: [operation("cargo", 0)] }, - cargoVersionPublished: async () => false, - publishCarrier: async () => { throw new Error("upload failed"); }, - publishMaven: () => { throw new Error("must not publish Maven"); }, - tokenOptions: { - env: tokenEnvironment, - fetchImpl: tokenFetch(methods), - maskImpl: () => {}, - }, - })).rejects.toThrow("upload failed"); - expect(methods).toEqual(["GET", "POST", "DELETE"]); - }); - - test("drains an in-flight Cargo mutation and revokes its token after a peer-lane failure", async () => { - const methods = []; - const cargoStarted = deferred(); - const releaseCargo = deferred(); - const npmMayFail = deferred(); - const run = executeNormalPublicationPlan({ - plan: { operations: [operation("cargo", 0), operation("npm", 1)] }, - cargoVersionPublished: async () => false, - publishCarrier: async ({ ecosystem }) => { - if (ecosystem === "cargo") { - cargoStarted.resolve(); - await releaseCargo.promise; - return; - } - await cargoStarted.promise; - await npmMayFail.promise; - throw new Error("npm peer failed"); - }, - publishMaven: () => { throw new Error("must not publish Maven"); }, - tokenOptions: { - env: tokenEnvironment, - fetchImpl: tokenFetch(methods), - maskImpl: () => {}, - }, - }); - await cargoStarted.promise; - npmMayFail.resolve(); - await Promise.resolve(); - releaseCargo.resolve(); - await expect(run).rejects.toThrow("npm peer failed"); - expect(methods).toEqual(["GET", "POST", "DELETE"]); - }); - - test("turns a real peer command exit into a drained failure before Cargo token revocation", async () => { - const methods = []; - const cargoStarted = deferred(); - const releaseCargo = deferred(); - const peerFailed = deferred(); - const run = executeNormalPublicationPlan({ - plan: { operations: [operation("cargo", 0), operation("npm", 1)] }, - cargoVersionPublished: async () => false, - publishCarrier: async ({ ecosystem }) => { - if (ecosystem === "cargo") { - cargoStarted.resolve(); - await releaseCargo.promise; - return; - } - await cargoStarted.promise; - try { - runOrThrow("normal-publication-executor.test", [ - process.execPath, - "-e", - "process.exit(23)", - ]); - } finally { - peerFailed.resolve(); - } - }, - publishMaven: () => { throw new Error("must not publish Maven"); }, - tokenOptions: { - env: tokenEnvironment, - fetchImpl: tokenFetch(methods), - maskImpl: () => {}, - }, - }); - await peerFailed.promise; - expect(methods).toEqual(["GET", "POST"]); - releaseCargo.resolve(); - await expect(run).rejects.toThrow("exited with status 23"); - expect(methods).toEqual(["GET", "POST", "DELETE"]); - }); - - test("treats mandatory token revocation time as unavailable to Cargo publication", async () => { - const methods = []; - const contexts = []; - await executeNormalPublicationPlan({ - plan: { operations: [operation("cargo", 0)] }, - cargoVersionPublished: async () => false, - publishCarrier: async (_operation, context) => contexts.push(context), - publishMaven: () => { throw new Error("must not publish Maven"); }, - nowImpl: () => 800_000, - tokenOptions: { - env: tokenEnvironment, - deadlineEpochMs: 1_000_000, - fetchImpl: tokenFetch(methods), - maskImpl: () => {}, - }, - }); - expect(methods).toEqual(["GET", "POST", "DELETE"]); - expect(contexts[0].tokenDeadlineEpochMs).toBe(940_000); - }); - - test("rejects malformed plans and oversized batches before mutation", async () => { - const callbacks = { - cargoVersionPublished: () => { throw new Error("must not inspect"); }, - publishCarrier: () => { throw new Error("must not publish"); }, - publishMaven: () => { throw new Error("must not publish"); }, - }; - await expect(executeNormalPublicationPlan({ - plan: { operations: [{ ...operation("cargo", 0), operationOrder: 2 }] }, - ...callbacks, - })).rejects.toThrow("contiguous canonical order"); - await expect(executeNormalPublicationPlan({ - plan: { operations: [] }, - batchSize: 21, - ...callbacks, - })).rejects.toThrow("from 1 through 20"); - }); -}); diff --git a/tools/release/normal-publication-executor.test.mts b/tools/release/normal-publication-executor.test.mts new file mode 100644 index 000000000..e19515867 --- /dev/null +++ b/tools/release/normal-publication-executor.test.mts @@ -0,0 +1,171 @@ +import { describe, expect, test } from 'bun:test'; + +import { + collectNormalPublicationReceipts, + executeCargoPublicationBatch, + normalPublicationSchedule, +} from './normal-publication-executor.mts'; + +function operation(ecosystem, index, carrierId = `${ecosystem}:package-${index}`) { + return { + id: `carrier:${carrierId}`, + kind: 'carrier', + ecosystem, + carrierId, + dependencies: [], + operationOrder: index, + }; +} + +function deferred() { + let resolve; + const promise = new Promise((accept) => { + resolve = accept; + }); + return { promise, resolve }; +} + +function tokenFetch(methods, tokens = ['cargo-token']) { + let tokenIndex = 0; + return async (_url, init) => { + methods.push(init.method); + if (init.method === 'GET') return Response.json({ value: `jwt-${tokenIndex}` }); + if (init.method === 'POST') + return Response.json({ token: tokens[tokenIndex++] ?? `token-${tokenIndex}` }); + return new Response('', { status: 200 }); + }; +} + +const tokenEnvironment = { + GITHUB_ACTIONS: 'true', + ACTIONS_ID_TOKEN_REQUEST_URL: 'https://pipelines.actions.example/token', + ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'request-token', +}; + +describe('normal publication executor', () => { + test('collects exact per-operation receipts without omission, addition, duplication, or bootstrap replacement', () => { + const cargo = operation('cargo', 0); + const npm = operation('npm', 1); + const maven = { + id: 'maven:atomic-deployment', + kind: 'maven-atomic-deployment', + ecosystem: 'maven', + carrierIds: ['maven:a', 'maven:b'], + dependencies: [], + operationOrder: 2, + }; + const cargoReceipt = { id: cargo.carrierId, proof: 'bootstrap' }; + const npmReceipt = { id: npm.carrierId, proof: 'npm' }; + const mavenReceipts = maven.carrierIds.map((id) => ({ id, proof: 'maven' })); + const plan = { operations: [cargo, npm, maven] }; + const collected = collectNormalPublicationReceipts({ + plan, + initialReceipts: [cargoReceipt], + operationResults: [undefined, npmReceipt, mavenReceipts], + }); + expect([...collected.values()]).toEqual([cargoReceipt, npmReceipt, ...mavenReceipts]); + expect(() => + collectNormalPublicationReceipts({ + plan, + initialReceipts: [cargoReceipt], + operationResults: [undefined, undefined, mavenReceipts], + }), + ).toThrow(/exact non-bootstrap carrier set/u); + expect(() => + collectNormalPublicationReceipts({ + plan, + initialReceipts: [cargoReceipt], + operationResults: [cargoReceipt, npmReceipt, mavenReceipts], + }), + ).toThrow(/exact non-bootstrap carrier set/u); + expect(() => + collectNormalPublicationReceipts({ + plan, + initialReceipts: [cargoReceipt], + operationResults: [undefined, npmReceipt, [mavenReceipts[0], mavenReceipts[0]]], + }), + ).toThrow(/duplicate registry receipt/u); + }); + + test('Cargo batches retain tokens until active uploads drain and stop peer-failure admission', async () => { + const methods = []; + const entered = deferred(); + const release = deferred(); + let aborted = false; + const calls = []; + const run = executeCargoPublicationBatch({ + operations: [operation('cargo', 0), operation('cargo', 1)], + cargoVersionPublished: async () => false, + isAborted: () => aborted, + publishCarrier: async (operation, context) => { + calls.push(operation.carrierId); + expect(context.cargoToken).toBe('cargo-token'); + entered.resolve(); + await release.promise; + }, + nowImpl: () => 1_000_000, + tokenOptions: { + env: tokenEnvironment, + fetchImpl: tokenFetch(methods), + maskImpl: () => {}, + }, + }); + await entered.promise; + aborted = true; + expect(methods).not.toContain('DELETE'); + release.resolve(); + await expect(run).rejects.toThrow('stopping Cargo admission'); + expect(calls).toEqual(['cargo:package-0']); + expect(methods).toEqual(['GET', 'POST', 'DELETE']); + }); + + test('Cargo skips tokens for exact published carriers and enforces the token deadline', async () => { + await executeCargoPublicationBatch({ + operations: [operation('cargo', 0)], + cargoVersionPublished: async () => true, + isAborted: () => false, + publishCarrier: async (_operation, context) => expect(context.alreadyPublished).toBe(true), + tokenOptions: { + fetchImpl: () => { + throw new Error('unexpected token request'); + }, + }, + }); + let now = 1_000_000; + const methods = []; + let published = 0; + await expect( + executeCargoPublicationBatch({ + operations: [operation('cargo', 0), operation('cargo', 1)], + cargoVersionPublished: async () => false, + isAborted: () => false, + nowImpl: () => now, + publishCarrier: async (_operation, context) => { + published++; + now = context.tokenDeadlineEpochMs; + }, + tokenOptions: { + env: tokenEnvironment, + fetchImpl: tokenFetch(methods), + maskImpl: () => {}, + }, + }), + ).rejects.toThrow('batch expired'); + expect(published).toBe(1); + expect(methods.at(-1)).toBe('DELETE'); + }); + + test('the frozen schedule splits at cross-registry dependencies and rejects invalid bounds', () => { + const cargo = operation('cargo', 0); + const npm = { ...operation('npm', 1), dependencies: [cargo.id] }; + const next = { ...operation('cargo', 2), dependencies: [npm.id] }; + expect(normalPublicationSchedule({ operations: [cargo, npm, next] }).cargoBatches).toEqual([ + [0], + [2], + ]); + expect(() => normalPublicationSchedule({ operations: [cargo] }, 0)).toThrow('batch size'); + expect(() => + normalPublicationSchedule({ operations: [{ ...cargo, dependencies: ['missing'] }] }), + ).toThrow('unknown dependency'); + }); +}); diff --git a/tools/release/normal-publication-plan.mjs b/tools/release/normal-publication-plan.mjs deleted file mode 100644 index 048c329d3..000000000 --- a/tools/release/normal-publication-plan.mjs +++ /dev/null @@ -1,207 +0,0 @@ -#!/usr/bin/env bun -import path from "node:path"; - -import { - DEFAULT_PUBLICATION_LOCK, - loadPublicationLock, - lockedCarriers, -} from "./publication-lock.mjs"; -import { ROOT } from "./release-cli-utils.mjs"; - -const SUPPORTED_ECOSYSTEMS = new Set(["cargo", "npm", "maven"]); -const MAVEN_UNIT = "maven:atomic-deployment"; - -function error(message) { - return new Error(`normal-publication-plan: ${message}`); -} - -function compareText(left, right) { - const a = String(left); - const b = String(right); - return a < b ? -1 : a > b ? 1 : 0; -} - -function selectedProductSet(lock, products) { - if ( - !Array.isArray(products) - || products.length === 0 - || products.some((product) => typeof product !== "string" || product.length === 0) - || new Set(products).size !== products.length - ) { - throw error("products must be a non-empty unique string list"); - } - const locked = new Set((lock.products ?? []).map(({ id }) => id)); - const unknown = products.filter((product) => !locked.has(product)); - if (unknown.length > 0) { - throw error(`selected products are absent from the publication lock: ${unknown.join(", ")}`); - } - return new Set(products); -} - -function carrierUnitId(carrier) { - return carrier.ecosystem === "maven" ? MAVEN_UNIT : `carrier:${carrier.id}`; -} - -function validateCarrier(carrier) { - if (typeof carrier?.id !== "string" || carrier.id !== `${carrier.ecosystem}:${carrier.name}`) { - throw error(`invalid carrier identity ${JSON.stringify(carrier?.id)}`); - } - if (!SUPPORTED_ECOSYSTEMS.has(carrier.ecosystem)) { - throw error(`${carrier.id} uses unsupported ecosystem ${JSON.stringify(carrier.ecosystem)}`); - } - if (!Number.isSafeInteger(carrier.publishOrder) || carrier.publishOrder < 0) { - throw error(`${carrier.id} has invalid publishOrder ${JSON.stringify(carrier.publishOrder)}`); - } - if (!Array.isArray(carrier.dependencies) || carrier.dependencies.some((dependency) => typeof dependency !== "string" || dependency.length === 0)) { - throw error(`${carrier.id}.dependencies must be a string list`); - } -} - -function operationEnvelope(unit) { - const carriers = unit.carriers - .slice() - .sort((left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id)); - const carrierIds = carriers.map(({ id }) => id); - const products = [...new Set(carriers.map(({ product }) => product))].sort(compareText); - const publishOrders = carriers.map(({ publishOrder }) => publishOrder); - if (unit.id === MAVEN_UNIT) { - return { - id: unit.id, - kind: "maven-atomic-deployment", - ecosystem: "maven", - products, - carrierIds, - firstPublishOrder: Math.min(...publishOrders), - lastPublishOrder: Math.max(...publishOrders), - dependencies: [...unit.dependencies].sort(compareText), - }; - } - const [carrier] = carriers; - return { - id: unit.id, - kind: "carrier", - ecosystem: carrier.ecosystem, - product: carrier.product, - carrierId: carrier.id, - products, - carrierIds, - firstPublishOrder: carrier.publishOrder, - lastPublishOrder: carrier.publishOrder, - dependencies: [...unit.dependencies].sort(compareText), - }; -} - -/** - * Turn an exact frozen publication lock into the mutation sequence used by the - * normal release. Cargo and npm identities remain independent mutations. - * Maven identities are one unit because Maven Central validates and publishes - * the signed bundle atomically; dependency edges inside that bundle therefore - * do not require separate deployments. - */ -export function normalPublicationPlan(lock, products) { - const selected = selectedProductSet(lock, products); - const allCarriers = lockedCarriers(lock) - .slice() - .sort((left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id)); - const allById = new Map(allCarriers.map((carrier) => [carrier.id, carrier])); - if (allById.size !== allCarriers.length) { - throw error("publication lock contains duplicate carrier identities"); - } - const carriers = allCarriers.filter((carrier) => selected.has(carrier.product)); - for (const carrier of carriers) validateCarrier(carrier); - const selectedIds = new Set(carriers.map(({ id }) => id)); - for (const carrier of carriers) { - const omitted = carrier.dependencies.filter((dependency) => allById.has(dependency) && !selectedIds.has(dependency)); - if (omitted.length > 0) { - throw error(`${carrier.id} selection omits locked dependencies: ${omitted.join(", ")}`); - } - const unknown = carrier.dependencies.filter((dependency) => !allById.has(dependency)); - if (unknown.length > 0) { - throw error(`${carrier.id} refers to unknown locked dependencies: ${unknown.join(", ")}`); - } - } - - const units = new Map(); - for (const carrier of carriers) { - const id = carrierUnitId(carrier); - const unit = units.get(id) ?? { id, carriers: [], dependencies: new Set() }; - unit.carriers.push(carrier); - units.set(id, unit); - } - for (const unit of units.values()) { - for (const carrier of unit.carriers) { - for (const dependency of carrier.dependencies) { - const dependencyUnit = carrierUnitId(allById.get(dependency)); - if (dependencyUnit !== unit.id) unit.dependencies.add(dependencyUnit); - } - } - } - - const remaining = new Set(units.keys()); - const completed = new Set(); - const operations = []; - while (remaining.size > 0) { - const ready = [...remaining] - .map((id) => operationEnvelope(units.get(id))) - .filter((operation) => operation.dependencies.every((dependency) => completed.has(dependency))) - .sort((left, right) => left.firstPublishOrder - right.firstPublishOrder || compareText(left.id, right.id)); - if (ready.length === 0) { - throw error(`publication unit dependency cycle: ${[...remaining].sort(compareText).join(", ")}`); - } - // Select exactly one operation before recomputing readiness. An earlier - // operation can unlock another unit whose frozen publishOrder precedes a - // unit that was already ready; scheduling a whole readiness "wave" would - // be topologically valid but would drift from the lock's global priority. - const [operation] = ready; - operations.push({ ...operation, operationOrder: operations.length }); - completed.add(operation.id); - remaining.delete(operation.id); - } - - const operationPosition = new Map(operations.map((operation, index) => [operation.id, index])); - for (const [index, operation] of operations.entries()) { - for (const dependency of operation.dependencies) { - if ((operationPosition.get(dependency) ?? Number.POSITIVE_INFINITY) >= index) { - throw error(`${operation.id} is scheduled before dependency unit ${dependency}`); - } - } - } - return { - products: [...selected], - carrierCount: carriers.length, - operations, - }; -} - -function parseArgs(argv) { - let lockFile = DEFAULT_PUBLICATION_LOCK; - let productsJson = ""; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - const value = argv[index + 1]; - if (arg === "--lock") lockFile = value ?? ""; - else if (arg === "--products-json") productsJson = value ?? ""; - else throw error(`unknown argument ${arg}`); - index += 1; - } - if (!lockFile || !productsJson) { - throw error("usage: normal-publication-plan.mjs --lock FILE --products-json JSON"); - } - let products; - try { - products = JSON.parse(productsJson); - } catch (cause) { - throw error(`--products-json must be strict JSON: ${cause.message}`); - } - return { lockFile: path.resolve(ROOT, lockFile), products }; -} - -if (import.meta.main) { - try { - const args = parseArgs(Bun.argv.slice(2)); - console.log(JSON.stringify(normalPublicationPlan(loadPublicationLock(args.lockFile), args.products), null, 2)); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/normal-publication-plan.mts b/tools/release/normal-publication-plan.mts new file mode 100644 index 000000000..0f4141e60 --- /dev/null +++ b/tools/release/normal-publication-plan.mts @@ -0,0 +1,231 @@ +#!/usr/bin/env bun +import path from 'node:path'; + +import { + DEFAULT_PUBLICATION_LOCK, + loadPublicationLock, + lockedCarriers, +} from './publication-lock.mts'; +import { ROOT } from './release-cli-utils.mts'; + +const SUPPORTED_ECOSYSTEMS = new Set(['cargo', 'npm', 'maven']); +const MAVEN_UNIT = 'maven:atomic-deployment'; + +function error(message) { + return new Error(`normal-publication-plan: ${message}`); +} + +function compareText(left, right) { + const a = String(left); + const b = String(right); + return a < b ? -1 : a > b ? 1 : 0; +} + +function selectedProductSet(lock, products) { + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string' || product.length === 0) || + new Set(products).size !== products.length + ) { + throw error('products must be a non-empty unique string list'); + } + const locked = new Set((lock.products ?? []).map(({ id }) => id)); + const unknown = products.filter((product) => !locked.has(product)); + if (unknown.length > 0) { + throw error(`selected products are absent from the publication lock: ${unknown.join(', ')}`); + } + return new Set(products); +} + +function carrierUnitId(carrier) { + return carrier.ecosystem === 'maven' ? MAVEN_UNIT : `carrier:${carrier.id}`; +} + +function validateCarrier(carrier) { + if (typeof carrier?.id !== 'string' || carrier.id !== `${carrier.ecosystem}:${carrier.name}`) { + throw error(`invalid carrier identity ${JSON.stringify(carrier?.id)}`); + } + if (!SUPPORTED_ECOSYSTEMS.has(carrier.ecosystem)) { + throw error(`${carrier.id} uses unsupported ecosystem ${JSON.stringify(carrier.ecosystem)}`); + } + if (!Number.isSafeInteger(carrier.publishOrder) || carrier.publishOrder < 0) { + throw error(`${carrier.id} has invalid publishOrder ${JSON.stringify(carrier.publishOrder)}`); + } + if ( + !Array.isArray(carrier.dependencies) || + carrier.dependencies.some( + (dependency) => typeof dependency !== 'string' || dependency.length === 0, + ) + ) { + throw error(`${carrier.id}.dependencies must be a string list`); + } +} + +function operationEnvelope(unit) { + const carriers = unit.carriers + .slice() + .sort( + (left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id), + ); + const carrierIds = carriers.map(({ id }) => id); + const products = [...new Set(carriers.map(({ product }) => product))].sort(compareText); + const publishOrders = carriers.map(({ publishOrder }) => publishOrder); + if (unit.id === MAVEN_UNIT) { + return { + id: unit.id, + kind: 'maven-atomic-deployment', + ecosystem: 'maven', + products, + carrierIds, + firstPublishOrder: Math.min(...publishOrders), + lastPublishOrder: Math.max(...publishOrders), + dependencies: [...unit.dependencies].sort(compareText), + }; + } + const [carrier] = carriers; + return { + id: unit.id, + kind: 'carrier', + ecosystem: carrier.ecosystem, + product: carrier.product, + carrierId: carrier.id, + products, + carrierIds, + firstPublishOrder: carrier.publishOrder, + lastPublishOrder: carrier.publishOrder, + dependencies: [...unit.dependencies].sort(compareText), + }; +} + +/** + * Turn an exact frozen publication lock into the mutation sequence used by the + * normal release. Cargo and npm identities remain independent mutations. + * Maven identities are one unit because Maven Central validates and publishes + * the signed bundle atomically; dependency edges inside that bundle therefore + * do not require separate deployments. + */ +export function normalPublicationPlan(lock, products) { + const selected = selectedProductSet(lock, products); + const allCarriers = lockedCarriers(lock) + .slice() + .sort( + (left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id), + ); + const allById = new Map(allCarriers.map((carrier) => [carrier.id, carrier])); + if (allById.size !== allCarriers.length) { + throw error('publication lock contains duplicate carrier identities'); + } + const carriers = allCarriers.filter((carrier) => selected.has(carrier.product)); + for (const carrier of carriers) validateCarrier(carrier); + const selectedIds = new Set(carriers.map(({ id }) => id)); + for (const carrier of carriers) { + const omitted = carrier.dependencies.filter( + (dependency) => allById.has(dependency) && !selectedIds.has(dependency), + ); + if (omitted.length > 0) { + throw error(`${carrier.id} selection omits locked dependencies: ${omitted.join(', ')}`); + } + const unknown = carrier.dependencies.filter((dependency) => !allById.has(dependency)); + if (unknown.length > 0) { + throw error(`${carrier.id} refers to unknown locked dependencies: ${unknown.join(', ')}`); + } + } + + const units = new Map(); + for (const carrier of carriers) { + const id = carrierUnitId(carrier); + const unit = units.get(id) ?? { id, carriers: [], dependencies: new Set() }; + unit.carriers.push(carrier); + units.set(id, unit); + } + for (const unit of units.values()) { + for (const carrier of unit.carriers) { + for (const dependency of carrier.dependencies) { + const dependencyUnit = carrierUnitId(allById.get(dependency)); + if (dependencyUnit !== unit.id) unit.dependencies.add(dependencyUnit); + } + } + } + + const remaining = new Set(units.keys()); + const completed = new Set(); + const operations = []; + while (remaining.size > 0) { + const ready = [...remaining] + .map((id) => operationEnvelope(units.get(id))) + .filter((operation) => + operation.dependencies.every((dependency) => completed.has(dependency)), + ) + .sort( + (left, right) => + left.firstPublishOrder - right.firstPublishOrder || compareText(left.id, right.id), + ); + if (ready.length === 0) { + throw error( + `publication unit dependency cycle: ${[...remaining].sort(compareText).join(', ')}`, + ); + } + // Select exactly one operation before recomputing readiness. An earlier + // operation can unlock another unit whose frozen publishOrder precedes a + // unit that was already ready; scheduling a whole readiness "wave" would + // be topologically valid but would drift from the lock's global priority. + const [operation] = ready; + operations.push({ ...operation, operationOrder: operations.length }); + completed.add(operation.id); + remaining.delete(operation.id); + } + + const operationPosition = new Map(operations.map((operation, index) => [operation.id, index])); + for (const [index, operation] of operations.entries()) { + for (const dependency of operation.dependencies) { + if ((operationPosition.get(dependency) ?? Number.POSITIVE_INFINITY) >= index) { + throw error(`${operation.id} is scheduled before dependency unit ${dependency}`); + } + } + } + return { + products: [...selected], + carrierCount: carriers.length, + operations, + }; +} + +function parseArgs(argv) { + let lockFile = DEFAULT_PUBLICATION_LOCK; + let productsJson = ''; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + const value = argv[index + 1]; + if (arg === '--lock') lockFile = value ?? ''; + else if (arg === '--products-json') productsJson = value ?? ''; + else throw error(`unknown argument ${arg}`); + index += 1; + } + if (!lockFile || !productsJson) { + throw error('usage: normal-publication-plan.mts --lock FILE --products-json JSON'); + } + let products; + try { + products = JSON.parse(productsJson); + } catch (cause) { + throw error(`--products-json must be strict JSON: ${cause.message}`); + } + return { lockFile: path.resolve(ROOT, lockFile), products }; +} + +if (import.meta.main) { + try { + const args = parseArgs(Bun.argv.slice(2)); + console.log( + JSON.stringify( + normalPublicationPlan(loadPublicationLock(args.lockFile), args.products), + null, + 2, + ), + ); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/normal-publication-plan.test.mjs b/tools/release/normal-publication-plan.test.mjs deleted file mode 100644 index 5ec54ba97..000000000 --- a/tools/release/normal-publication-plan.test.mjs +++ /dev/null @@ -1,183 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { normalPublicationPlan } from "./normal-publication-plan.mjs"; -import { loadPublicationCatalog } from "./publication-catalog.mjs"; -import { extensionSqlNames } from "./release-artifact-targets.mjs"; -import { buildPlan, loadGraph } from "./release-graph.mjs"; - -function carrier({ - id, - product, - publishOrder, - dependencies = [], -}) { - const separator = id.indexOf(":"); - return { - id, - product, - ecosystem: id.slice(0, separator), - name: id.slice(separator + 1), - version: "1.0.0", - publishOrder, - dependencies, - }; -} - -function lock(carriers) { - return { - products: [...new Set(carriers.map(({ product }) => product))].map((id) => ({ id })), - carriers, - }; -} - -function realSelection(changedFile) { - const graph = loadGraph("normal-publication-plan.test"); - const release = buildPlan(graph, [changedFile], "normal-publication-plan.test"); - const publicationProducts = release.releaseProducts; - const catalog = loadPublicationCatalog("normal-publication-plan.test", { products: publicationProducts }); - const frozen = { - products: catalog.products, - carriers: catalog.carriers.map((value, publishOrder) => ({ - ...value, - publishOrder, - dependencies: [], - })), - }; - return { - release, - catalog, - topology: normalPublicationPlan(frozen, publicationProducts), - }; -} - -describe("normal publication plan", () => { - test("executes exact frozen carriers in lock-derived dependency order", () => { - const value = lock([ - carrier({ id: "cargo:runtime", product: "runtime", publishOrder: 0 }), - carrier({ id: "npm:@example/runtime", product: "runtime", publishOrder: 1 }), - carrier({ id: "cargo:sdk", product: "sdk", publishOrder: 2, dependencies: ["cargo:runtime"] }), - carrier({ id: "npm:@example/sdk", product: "sdk", publishOrder: 3, dependencies: ["npm:@example/runtime"] }), - ]); - const plan = normalPublicationPlan(value, ["runtime", "sdk"]); - expect(plan.carrierCount).toBe(4); - expect(plan.operations.map(({ carrierId }) => carrierId)).toEqual([ - "cargo:runtime", - "npm:@example/runtime", - "cargo:sdk", - "npm:@example/sdk", - ]); - expect(plan.operations.map(({ operationOrder }) => operationOrder)).toEqual([0, 1, 2, 3]); - }); - - test("recomputes readiness after every operation to preserve global lock priority", () => { - const value = lock([ - carrier({ id: "cargo:root", product: "root", publishOrder: 0 }), - carrier({ id: "cargo:unlocked", product: "unlocked", publishOrder: 1, dependencies: ["cargo:root"] }), - carrier({ id: "npm:already-ready", product: "ready", publishOrder: 2 }), - ]); - const plan = normalPublicationPlan(value, ["root", "unlocked", "ready"]); - expect(plan.operations.map(({ carrierId }) => carrierId)).toEqual([ - "cargo:root", - "cargo:unlocked", - "npm:already-ready", - ]); - }); - - test("collapses Maven coordinates into one atomic lock-derived deployment", () => { - const value = lock([ - carrier({ id: "maven:dev.example:runtime", product: "runtime", publishOrder: 0 }), - carrier({ id: "npm:@example/runtime", product: "runtime", publishOrder: 1 }), - carrier({ - id: "maven:dev.example:sdk", - product: "sdk", - publishOrder: 2, - dependencies: ["maven:dev.example:runtime"], - }), - ]); - const plan = normalPublicationPlan(value, ["runtime", "sdk"]); - expect(plan.operations).toHaveLength(2); - expect(plan.operations[0]).toMatchObject({ - id: "maven:atomic-deployment", - kind: "maven-atomic-deployment", - carrierIds: ["maven:dev.example:runtime", "maven:dev.example:sdk"], - products: ["runtime", "sdk"], - firstPublishOrder: 0, - lastPublishOrder: 2, - }); - expect(plan.operations.map(({ id }) => id)).toEqual([ - "maven:atomic-deployment", - "carrier:npm:@example/runtime", - ]); - }); - - test("preserves dependencies into and out of the Maven atomic unit", () => { - const value = lock([ - carrier({ id: "npm:@example/input", product: "input", publishOrder: 0 }), - carrier({ id: "maven:dev.example:sdk", product: "sdk", publishOrder: 1, dependencies: ["npm:@example/input"] }), - carrier({ id: "npm:@example/output", product: "output", publishOrder: 2, dependencies: ["maven:dev.example:sdk"] }), - ]); - const plan = normalPublicationPlan(value, ["input", "sdk", "output"]); - expect(plan.operations.map(({ id }) => id)).toEqual([ - "carrier:npm:@example/input", - "maven:atomic-deployment", - "carrier:npm:@example/output", - ]); - }); - - test("fails closed when a selected carrier omits a locked dependency", () => { - const value = lock([ - carrier({ id: "cargo:runtime", product: "runtime", publishOrder: 0 }), - carrier({ id: "cargo:sdk", product: "sdk", publishOrder: 1, dependencies: ["cargo:runtime"] }), - ]); - expect(() => normalPublicationPlan(value, ["sdk"])) - .toThrow(/selection omits locked dependencies: cargo:runtime/u); - }); - - test("fails closed on cycles instead of inventing an execution order", () => { - const value = lock([ - carrier({ id: "npm:a", product: "a", publishOrder: 0, dependencies: ["npm:b"] }), - carrier({ id: "npm:b", product: "b", publishOrder: 1, dependencies: ["npm:a"] }), - ]); - expect(() => normalPublicationPlan(value, ["a", "b"])) - .toThrow(/dependency cycle/u); - }); - - test("real release selections include exact embedded consumers without unrelated products", () => { - const external = realSelection("src/extensions/external/vector/CHANGELOG.md"); - expect(external.release.directProducts).toEqual(["oliphaunt-extension-vector"]); - expect(external.release.releaseProducts).toEqual(["oliphaunt-extension-vector"]); - expect(external.catalog.products.map(({ id }) => id)).toEqual(external.release.releaseProducts); - expect(external.topology.carrierCount).toBe(external.catalog.carriers.length); - - const runtime = realSelection("src/runtimes/liboliphaunt/native/CHANGELOG.md"); - expect(runtime.release.directProducts).toEqual(["liboliphaunt-native"]); - expect(runtime.release.releaseProducts).toContain("liboliphaunt-native"); - expect(runtime.release.releaseProducts).not.toContain("liboliphaunt-wasix"); - expect(runtime.release.releaseProducts).not.toContain("oliphaunt-extension-contrib-pg18"); - expect(extensionSqlNames("oliphaunt-extension-contrib-pg18", "normal-publication-plan.test")) - .toContain("amcheck"); - const contribCarriers = runtime.catalog.carriers - .filter(({ name }) => name.includes("extension-contrib-pg18")); - expect(contribCarriers).toHaveLength(12); - expect(contribCarriers.every(({ product }) => product === "liboliphaunt-native")).toBe(true); - expect(runtime.release.releaseProducts).not.toContain("oliphaunt-extension-vector"); - expect(runtime.release.releaseProducts).toEqual(["liboliphaunt-native"]); - expect(runtime.catalog.products.map(({ id }) => id)).toEqual(runtime.release.releaseProducts); - expect(runtime.topology.carrierCount).toBe(runtime.catalog.carriers.length); - - const contrib = realSelection("src/extensions/contrib/postgres18.toml"); - expect(contrib.release.directProducts).toEqual(["liboliphaunt-native", "liboliphaunt-wasix"]); - expect(contrib.release.releaseProducts).toEqual(["liboliphaunt-native", "liboliphaunt-wasix"]); - expect(contrib.release.releaseProducts).not.toContain("oliphaunt-wasix-napi"); - - const icu = realSelection("src/runtimes/liboliphaunt/icu/src/lib.rs"); - expect(icu.release.directProducts).toEqual(["liboliphaunt-wasix"]); - expect(icu.release.releaseProducts).toEqual(["liboliphaunt-wasix"]); - - const sdk = realSelection("src/sdks/react-native/CHANGELOG.md"); - expect(sdk.release.directProducts).toEqual(["oliphaunt-react-native"]); - expect(sdk.release.releaseProducts).toEqual(["oliphaunt-react-native"]); - expect(sdk.catalog.products.map(({ id }) => id)).toEqual(sdk.release.releaseProducts); - expect(sdk.topology.carrierCount).toBe(sdk.catalog.carriers.length); - }); -}); diff --git a/tools/release/normal-publication-plan.test.mts b/tools/release/normal-publication-plan.test.mts new file mode 100644 index 000000000..c60a8587d --- /dev/null +++ b/tools/release/normal-publication-plan.test.mts @@ -0,0 +1,211 @@ +import { describe, expect, test } from 'bun:test'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { extensionSqlNames } from './release-artifact-targets.mts'; +import { buildPlan, loadGraph } from './release-graph.mts'; +import { normalPublicationPlan } from './normal-publication-plan.mts'; + +function carrier({ id, product, publishOrder, dependencies = [] }) { + const separator = id.indexOf(':'); + return { + id, + product, + ecosystem: id.slice(0, separator), + name: id.slice(separator + 1), + version: '1.0.0', + publishOrder, + dependencies, + }; +} + +function lock(carriers) { + return { + products: [...new Set(carriers.map(({ product }) => product))].map((id) => ({ id })), + carriers, + }; +} + +function realSelection(changedFile) { + const graph = loadGraph('normal-publication-plan.test'); + const release = buildPlan(graph, [changedFile], 'normal-publication-plan.test'); + const publicationProducts = release.releaseProducts; + const catalog = loadPublicationCatalog('normal-publication-plan.test', { + products: publicationProducts, + }); + const frozen = { + products: catalog.products, + carriers: catalog.carriers.map((value, publishOrder) => ({ + ...value, + publishOrder, + dependencies: [], + })), + }; + return { + release, + catalog, + topology: normalPublicationPlan(frozen, publicationProducts), + }; +} + +describe('normal publication plan', () => { + test('executes exact frozen carriers in lock-derived dependency order', () => { + const value = lock([ + carrier({ id: 'cargo:runtime', product: 'runtime', publishOrder: 0 }), + carrier({ id: 'npm:@example/runtime', product: 'runtime', publishOrder: 1 }), + carrier({ + id: 'cargo:sdk', + product: 'sdk', + publishOrder: 2, + dependencies: ['cargo:runtime'], + }), + carrier({ + id: 'npm:@example/sdk', + product: 'sdk', + publishOrder: 3, + dependencies: ['npm:@example/runtime'], + }), + ]); + const plan = normalPublicationPlan(value, ['runtime', 'sdk']); + expect(plan.carrierCount).toBe(4); + expect(plan.operations.map(({ carrierId }) => carrierId)).toEqual([ + 'cargo:runtime', + 'npm:@example/runtime', + 'cargo:sdk', + 'npm:@example/sdk', + ]); + expect(plan.operations.map(({ operationOrder }) => operationOrder)).toEqual([0, 1, 2, 3]); + }); + + test('recomputes readiness after every operation to preserve global lock priority', () => { + const value = lock([ + carrier({ id: 'cargo:root', product: 'root', publishOrder: 0 }), + carrier({ + id: 'cargo:unlocked', + product: 'unlocked', + publishOrder: 1, + dependencies: ['cargo:root'], + }), + carrier({ id: 'npm:already-ready', product: 'ready', publishOrder: 2 }), + ]); + const plan = normalPublicationPlan(value, ['root', 'unlocked', 'ready']); + expect(plan.operations.map(({ carrierId }) => carrierId)).toEqual([ + 'cargo:root', + 'cargo:unlocked', + 'npm:already-ready', + ]); + }); + + test('collapses Maven coordinates into one atomic lock-derived deployment', () => { + const value = lock([ + carrier({ id: 'maven:dev.example:runtime', product: 'runtime', publishOrder: 0 }), + carrier({ id: 'npm:@example/runtime', product: 'runtime', publishOrder: 1 }), + carrier({ + id: 'maven:dev.example:sdk', + product: 'sdk', + publishOrder: 2, + dependencies: ['maven:dev.example:runtime'], + }), + ]); + const plan = normalPublicationPlan(value, ['runtime', 'sdk']); + expect(plan.operations).toHaveLength(2); + expect(plan.operations[0]).toMatchObject({ + id: 'maven:atomic-deployment', + kind: 'maven-atomic-deployment', + carrierIds: ['maven:dev.example:runtime', 'maven:dev.example:sdk'], + products: ['runtime', 'sdk'], + firstPublishOrder: 0, + lastPublishOrder: 2, + }); + expect(plan.operations.map(({ id }) => id)).toEqual([ + 'maven:atomic-deployment', + 'carrier:npm:@example/runtime', + ]); + }); + + test('preserves dependencies into and out of the Maven atomic unit', () => { + const value = lock([ + carrier({ id: 'npm:@example/input', product: 'input', publishOrder: 0 }), + carrier({ + id: 'maven:dev.example:sdk', + product: 'sdk', + publishOrder: 1, + dependencies: ['npm:@example/input'], + }), + carrier({ + id: 'npm:@example/output', + product: 'output', + publishOrder: 2, + dependencies: ['maven:dev.example:sdk'], + }), + ]); + const plan = normalPublicationPlan(value, ['input', 'sdk', 'output']); + expect(plan.operations.map(({ id }) => id)).toEqual([ + 'carrier:npm:@example/input', + 'maven:atomic-deployment', + 'carrier:npm:@example/output', + ]); + }); + + test('fails closed when a selected carrier omits a locked dependency', () => { + const value = lock([ + carrier({ id: 'cargo:runtime', product: 'runtime', publishOrder: 0 }), + carrier({ + id: 'cargo:sdk', + product: 'sdk', + publishOrder: 1, + dependencies: ['cargo:runtime'], + }), + ]); + expect(() => normalPublicationPlan(value, ['sdk'])).toThrow( + /selection omits locked dependencies: cargo:runtime/u, + ); + }); + + test('fails closed on cycles instead of inventing an execution order', () => { + const value = lock([ + carrier({ id: 'npm:a', product: 'a', publishOrder: 0, dependencies: ['npm:b'] }), + carrier({ id: 'npm:b', product: 'b', publishOrder: 1, dependencies: ['npm:a'] }), + ]); + expect(() => normalPublicationPlan(value, ['a', 'b'])).toThrow(/dependency cycle/u); + }); + + test('real release selections include exact embedded consumers without unrelated products', () => { + const external = realSelection('src/extensions/external/vector/CHANGELOG.md'); + expect(external.release.directProducts).toEqual(['oliphaunt-extension-vector']); + expect(external.release.releaseProducts).toEqual(['oliphaunt-extension-vector']); + expect(external.catalog.products.map(({ id }) => id)).toEqual(external.release.releaseProducts); + expect(external.topology.carrierCount).toBe(external.catalog.carriers.length); + + const runtime = realSelection('src/runtimes/liboliphaunt-native/CHANGELOG.md'); + expect(runtime.release.directProducts).toEqual(['liboliphaunt-native']); + expect(runtime.release.releaseProducts).toContain('liboliphaunt-native'); + expect(runtime.release.releaseProducts).not.toContain('liboliphaunt-wasix'); + expect(runtime.release.releaseProducts).not.toContain('oliphaunt-extension-contrib-pg18'); + expect( + extensionSqlNames('oliphaunt-extension-contrib-pg18', 'normal-publication-plan.test'), + ).toContain('amcheck'); + const contribCarriers = runtime.catalog.carriers.filter(({ name }) => + name.includes('extension-contrib-pg18'), + ); + expect(contribCarriers.length).toBeGreaterThan(0); + expect(contribCarriers.every(({ product }) => product === 'liboliphaunt-native')).toBe(true); + expect(runtime.release.releaseProducts).not.toContain('oliphaunt-extension-vector'); + expect(runtime.release.releaseProducts).toEqual(['liboliphaunt-native']); + expect(runtime.catalog.products.map(({ id }) => id)).toEqual(runtime.release.releaseProducts); + expect(runtime.topology.carrierCount).toBe(runtime.catalog.carriers.length); + + const contrib = realSelection('src/extensions/contrib/postgres18.toml'); + expect(contrib.release.directProducts).toEqual(['liboliphaunt-native', 'liboliphaunt-wasix']); + expect(contrib.release.releaseProducts).toEqual(['liboliphaunt-native', 'liboliphaunt-wasix']); + expect(contrib.release.releaseProducts).not.toContain('oliphaunt-wasix-napi'); + + const icu = realSelection('src/database-resources/icu/cargo/src/lib.rs'); + expect(icu.release.directProducts).toEqual(['database-resources']); + expect(icu.release.releaseProducts).toEqual(['database-resources']); + + const sdk = realSelection('src/sdks/react-native/CHANGELOG.md'); + expect(sdk.release.directProducts).toEqual(['oliphaunt-react-native']); + expect(sdk.release.releaseProducts).toEqual(['oliphaunt-react-native']); + expect(sdk.catalog.products.map(({ id }) => id)).toEqual(sdk.release.releaseProducts); + expect(sdk.topology.carrierCount).toBe(sdk.catalog.carriers.length); + }); +}); diff --git a/tools/release/normalize-release-please-pr.test.mjs b/tools/release/normalize-release-please-pr.test.mjs deleted file mode 100644 index 269d95605..000000000 --- a/tools/release/normalize-release-please-pr.test.mjs +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -const SCRIPT = path.resolve(".github/scripts/normalize-release-please-pr.mjs"); -const BRANCH = "release-please--branches--main"; -const TITLE = "chore(release): prepare main releases"; - -function run(command, args, { cwd, check = true } = {}) { - const result = spawnSync(command, args, { cwd, encoding: "utf8" }); - if (check) assert.equal(result.status, 0, `${command} ${args.join(" ")}\n${result.stderr}`); - return result; -} - -function git(cwd, args, options = {}) { - return run("git", args, { cwd, ...options }); -} - -function gitText(cwd, args) { - return git(cwd, args).stdout.trim(); -} - -function commitFiles(cwd, prefix, count) { - for (let index = 1; index <= count; index += 1) { - const file = `${prefix}-${String(index).padStart(3, "0")}.txt`; - writeFileSync(path.join(cwd, file), `${file}\n`); - } - git(cwd, ["add", "."]); - git(cwd, ["commit", "-m", TITLE]); - return gitText(cwd, ["rev-parse", "HEAD"]); -} - -function fixture(t) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-pr-normalize-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const remote = path.join(root, "remote.git"); - const seed = path.join(root, "seed"); - const work = path.join(root, "work"); - mkdirSync(seed); - git(root, ["init", "--bare", remote]); - git(seed, ["init"]); - git(seed, ["config", "user.name", "Release Test"]); - git(seed, ["config", "user.email", "release-test@example.invalid"]); - writeFileSync(path.join(seed, "release-please-config.json"), `${JSON.stringify({ - "group-pull-request-title-pattern": "chore(release): prepare ${branch} releases", - }, null, 2)}\n`); - writeFileSync(path.join(seed, "seed.txt"), "main\n"); - git(seed, ["add", "."]); - git(seed, ["commit", "-m", "feat: introduce oliphaunt"]); - git(seed, ["branch", "-M", "main"]); - git(seed, ["remote", "add", "origin", remote]); - git(seed, ["push", "-u", "origin", "main"]); - git(remote, ["symbolic-ref", "HEAD", "refs/heads/main"]); - const mainSha = gitText(seed, ["rev-parse", "HEAD"]); - git(seed, ["switch", "-c", BRANCH]); - const firstChunk = commitFiles(seed, "first", 100); - const secondChunk = commitFiles(seed, "second", 35); - git(seed, ["push", "-u", "origin", BRANCH]); - const headSha = secondChunk; - git(root, ["clone", remote, work]); - return { root, remote, seed, work, mainSha, headSha, firstChunk, secondChunk }; -} - -function identity(f, overrides = {}) { - const values = { - prNumber: "123", - observedPrNumber: "123", - base: "main", - head: BRANCH, - headSha: f.headSha, - headRepository: "f0rr0/oliphaunt", - crossRepository: "false", - state: "OPEN", - title: TITLE, - mainSha: f.mainSha, - remote: "origin", - ...overrides, - }; - return [ - "--pr-number", values.prNumber, - "--observed-pr-number", values.observedPrNumber, - "--base", values.base, - "--head", values.head, - "--head-sha", values.headSha, - "--head-repository", values.headRepository, - "--cross-repository", values.crossRepository, - "--state", values.state, - "--title", values.title, - "--main-sha", values.mainSha, - "--remote", values.remote, - ]; -} - -function invoke(f, command, overrides = {}) { - return run(process.execPath, [SCRIPT, command, ...identity(f, overrides)], { cwd: f.work, check: false }); -} - -test("normalizes the historical 100+35 file Release Please shape to one tree-identical exact-parent commit and pushes it", (t) => { - const f = fixture(t); - assert.equal(gitText(f.seed, ["diff-tree", "--no-commit-id", "--name-only", "-r", f.firstChunk]).split("\n").length, 100); - assert.equal(gitText(f.seed, ["diff-tree", "--no-commit-id", "--name-only", "-r", f.secondChunk]).split("\n").length, 35); - const generatedTree = gitText(f.seed, ["rev-parse", `${f.headSha}^{tree}`]); - - const normalized = invoke(f, "normalize"); - assert.equal(normalized.status, 0, normalized.stderr); - assert.match(normalized.stdout, /normalized=true/u); - assert.equal(gitText(f.work, ["show", "-s", "--format=%ae", "HEAD"]), "326451763+oliphaunt-release-bot[bot]@users.noreply.github.com"); - assert.equal(gitText(f.work, ["branch", "--show-current"]), BRANCH); - assert.equal(gitText(f.work, ["rev-list", "--count", `${f.mainSha}..HEAD`]), "1"); - assert.equal(gitText(f.work, ["rev-parse", "HEAD^"]), f.mainSha); - assert.equal(gitText(f.work, ["rev-parse", "HEAD^{tree}"]), generatedTree); - assert.equal(gitText(f.work, ["show", "-s", "--format=%s", "HEAD"]), TITLE); - - const pushed = invoke(f, "push"); - assert.equal(pushed.status, 0, pushed.stderr); - const remoteHead = gitText(f.work, ["ls-remote", "--heads", "origin", `refs/heads/${BRANCH}`]).split(/\s+/u)[0]; - assert.equal(remoteHead, gitText(f.work, ["rev-parse", "HEAD"])); - assert.notEqual(remoteHead, f.headSha); -}); - -test("rejects wrong PR number, base, and branch identities before checkout", (t) => { - const f = fixture(t); - const cases = [ - [{ observedPrNumber: "124" }, /release PR identity changed/u], - [{ base: "develop" }, /release PR base must be main/u], - [{ head: "release-please--branches--develop" }, /release PR head must be/u], - ]; - for (const [overrides, pattern] of cases) { - const result = invoke(f, "normalize", overrides); - assert.equal(result.status, 1, result.stderr); - assert.match(result.stderr, pattern); - assert.equal(gitText(f.work, ["branch", "--show-current"]), "main"); - } -}); - -test("rebases a stale generated release branch onto exact current main", (t) => { - const f = fixture(t); - git(f.seed, ["switch", "main"]); - writeFileSync(path.join(f.seed, "main-only.txt"), "advanced main\n"); - git(f.seed, ["add", "main-only.txt"]); - git(f.seed, ["commit", "-m", "fix: advance main"]); - git(f.seed, ["push", "origin", "main"]); - const currentMain = gitText(f.seed, ["rev-parse", "HEAD"]); - - const result = invoke(f, "normalize", { mainSha: currentMain }); - assert.equal(result.status, 0, result.stderr); - assert.match(result.stdout, /normalized=true/u); - assert.equal(gitText(f.work, ["rev-parse", "HEAD^"]), currentMain); - assert.equal(readFileSync(path.join(f.work, "main-only.txt"), "utf8"), "advanced main\n"); - assert.equal(readFileSync(path.join(f.work, "second-035.txt"), "utf8"), "second-035.txt\n"); -}); - -test("rejects a canonical-looking release branch with unrelated history", (t) => { - const f = fixture(t); - git(f.seed, ["switch", "--orphan", "unrelated"]); - writeFileSync(path.join(f.seed, "release-please-config.json"), `${JSON.stringify({ - "group-pull-request-title-pattern": "chore(release): prepare ${branch} releases", - }, null, 2)}\n`); - writeFileSync(path.join(f.seed, "unrelated.txt"), "unrelated\n"); - git(f.seed, ["add", "."]); - git(f.seed, ["commit", "-m", TITLE]); - const unrelated = gitText(f.seed, ["rev-parse", "HEAD"]); - git(f.seed, ["push", "--force", "origin", `HEAD:refs/heads/${BRANCH}`]); - - const result = invoke(f, "normalize", { headSha: unrelated }); - assert.equal(result.status, 1, result.stderr); - assert.match(result.stderr, /does not share canonical main history/u); - assert.equal(gitText(f.work, ["branch", "--show-current"]), "main"); -}); - -test("an exact force-with-lease preserves a release PR head that moved after inspection", (t) => { - const f = fixture(t); - const normalized = invoke(f, "normalize"); - assert.equal(normalized.status, 0, normalized.stderr); - const localNormalized = gitText(f.work, ["rev-parse", "HEAD"]); - - writeFileSync(path.join(f.seed, "late.txt"), "late\n"); - git(f.seed, ["add", "late.txt"]); - git(f.seed, ["commit", "-m", TITLE]); - git(f.seed, ["push", "origin", BRANCH]); - const movedHead = gitText(f.seed, ["rev-parse", "HEAD"]); - - const pushed = invoke(f, "push"); - assert.equal(pushed.status, 1, pushed.stderr); - assert.match(pushed.stderr, /stale info|fetch first|failed to push/u); - const remoteHead = gitText(f.work, ["ls-remote", "--heads", "origin", `refs/heads/${BRANCH}`]).split(/\s+/u)[0]; - assert.equal(remoteHead, movedHead); - assert.notEqual(remoteHead, localNormalized); - assert.equal(readFileSync(path.join(f.work, "first-001.txt"), "utf8"), "first-001.txt\n"); -}); diff --git a/src/sources/toolchains/npm-publisher.toml b/tools/release/npm-publisher.toml similarity index 100% rename from src/sources/toolchains/npm-publisher.toml rename to tools/release/npm-publisher.toml diff --git a/tools/release/npm-trusted-publishing-runtime.mjs b/tools/release/npm-trusted-publishing-runtime.mjs deleted file mode 100644 index 96f011c96..000000000 --- a/tools/release/npm-trusted-publishing-runtime.mjs +++ /dev/null @@ -1,305 +0,0 @@ -#!/usr/bin/env node - -// Operational npm trusted-publisher validation; this module does not produce -// package or carrier bytes. - -import { lstatSync } from "node:fs"; -import path from "node:path"; -import process from "node:process"; -import { fileURLToPath } from "node:url"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; - -export const MINIMUM_TRUSTED_PUBLISHING_NODE_VERSION = "22.14.0"; -export const MINIMUM_TRUSTED_PUBLISHING_NPM_VERSION = "11.5.1"; -export const MINIMUM_NPM_TRUST_CLI_VERSION = "11.15.0"; - -const NPM_TRUST_HELP_TIMEOUT_MS = 30_000; -const NPM_TRUST_HELP_MAX_BYTES = 256 * 1024; -const NPM_TRUST_CONTRACT_PACKAGE = "@oliphaunt/oliphaunt-cli-contract-probe"; -const NPM_TRUST_CONTRACT_REGISTRY = "http://127.0.0.1:9/"; -const REQUIRED_NPM_TRUST_HELP_OPTIONS = Object.freeze({ - list: Object.freeze(["--json", "--registry"]), - github: Object.freeze([ - "--file", - "--repository", - "--environment", - "--allow-publish", - "--json", - "--registry", - "--yes", - ]), -}); - -function parsedVersion(value, label) { - if (typeof value !== "string") { - throw new TypeError(`${label} version must be a string`); - } - const match = value.trim().match(/^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/u); - if (match === null) { - throw new TypeError(`${label} version must be complete semver; got ${JSON.stringify(value)}`); - } - return match.slice(1).map((part) => Number.parseInt(part, 10)); -} - -function compareVersions(left, right) { - for (let index = 0; index < 3; index += 1) { - if (left[index] !== right[index]) { - return left[index] - right[index]; - } - } - return 0; -} - -function requireMinimumVersion(actual, minimum, label) { - if (compareVersions(parsedVersion(actual, label), parsedVersion(minimum, `${label} minimum`)) < 0) { - throw new Error(`${label} ${actual} is too old for npm trusted publishing; need >= ${minimum}`); - } -} - -export function validateNpmTrustedPublishingRuntime({ nodeVersion, npmVersion }) { - requireMinimumVersion(nodeVersion, MINIMUM_TRUSTED_PUBLISHING_NODE_VERSION, "Node.js"); - requireMinimumVersion(npmVersion, MINIMUM_TRUSTED_PUBLISHING_NPM_VERSION, "npm"); - return { nodeVersion, npmVersion }; -} - -export function validateNpmTrustCliRuntime(npmVersion) { - requireMinimumVersion(npmVersion, MINIMUM_NPM_TRUST_CLI_VERSION, "npm trust CLI"); - return npmVersion; -} - -export function validateNpmTrustCliHelp({ listHelp, githubHelp }) { - for (const [command, help] of Object.entries({ list: listHelp, github: githubHelp })) { - if (typeof help !== "string" || help.length === 0) { - throw new Error(`npm trust ${command} --help returned no text`); - } - for (const option of REQUIRED_NPM_TRUST_HELP_OPTIONS[command]) { - if (!help.includes(option)) { - throw new Error(`npm trust ${command} does not advertise required option ${option}`); - } - } - } - if (githubHelp.includes("--allow-stage-publish") && !githubHelp.includes("--allow-publish")) { - throw new Error("npm trust github advertises staged publication without ordinary publication"); - } - return { listHelp, githubHelp }; -} - -export function isFullyQualifiedNativePath(value, platform = process.platform) { - if (typeof value !== "string" || value.length === 0) return false; - if (platform === "win32") { - if (!path.win32.isAbsolute(value)) return false; - const root = path.win32.parse(value).root; - // Win32 treats `/d/...`, `\\d\\...`, `/...`, and `\\...` as absolute but - // drive-relative paths. Native filesystem identities must instead carry a - // drive, UNC share, or device-qualified root. - return root !== "/" && root !== "\\"; - } - return path.posix.isAbsolute(value); -} - -function capturedNpmCli(nodeExecutable, npmCli, args, captureImpl, context, env = process.env) { - const result = captureImpl(nodeExecutable, [npmCli, ...args], { - env, - label: context, - maxOutputBytes: NPM_TRUST_HELP_MAX_BYTES, - timeout: NPM_TRUST_HELP_TIMEOUT_MS, - windowsHide: true, - }); - if (result.error !== undefined || result.status !== 0) { - const detail = String(result.stderr ?? result.error?.message ?? "") - .replace(/[\r\n\t]+/gu, " ") - .trim() - .slice(0, 300); - throw new Error( - `${context} failed${Number.isInteger(result.status) ? ` with exit ${result.status}` : ""}` - + `${detail ? `: ${detail}` : ""}`, - ); - } - return String(result.stdout ?? ""); -} - -export function checkNpmTrustCliContract({ - nodeExecutable, - npmCli, - captureImpl = captureCommandOutput, -}) { - if (typeof nodeExecutable !== "string" || nodeExecutable.length === 0) { - throw new TypeError("Node.js executable must be a non-empty path"); - } - if (typeof npmCli !== "string" || npmCli.length === 0) { - throw new TypeError("npm CLI must be a non-empty path"); - } - const npmVersion = capturedNpmCli( - nodeExecutable, - npmCli, - ["--version"], - captureImpl, - "npm --version", - ).trim(); - validateNpmTrustCliRuntime(npmVersion); - const help = validateNpmTrustCliHelp({ - listHelp: capturedNpmCli( - nodeExecutable, - npmCli, - ["trust", "list", "--help"], - captureImpl, - "npm trust list --help", - ), - githubHelp: capturedNpmCli( - nodeExecutable, - npmCli, - ["trust", "github", "--help"], - captureImpl, - "npm trust github --help", - ), - }); - const probeText = capturedNpmCli( - nodeExecutable, - npmCli, - [ - "trust", "github", NPM_TRUST_CONTRACT_PACKAGE, - "--file", "release.yml", - "--repo", "f0rr0/oliphaunt", - "--env", "release-publish", - "--allow-publish", - "--yes", - "--json", - "--registry", NPM_TRUST_CONTRACT_REGISTRY, - "--dry-run", - ], - captureImpl, - "npm trust github dry-run contract probe", - { - ...process.env, - NPM_CONFIG_FETCH_RETRIES: "0", - NPM_CONFIG_FETCH_RETRY_MINTIMEOUT: "1000", - NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT: "5000", - NPM_CONFIG_FETCH_TIMEOUT: "20000", - }, - ); - let probe; - try { - probe = JSON.parse(probeText); - } catch { - throw new Error("npm trust github dry-run contract probe returned invalid JSON"); - } - const expectedProbe = { - package: NPM_TRUST_CONTRACT_PACKAGE, - file: "release.yml", - repository: "f0rr0/oliphaunt", - environment: "release-publish", - permissions: ["createPackage"], - }; - if (JSON.stringify(probe) !== JSON.stringify(expectedProbe)) { - throw new Error( - `npm trust github dry-run contract probe returned an unexpected plan: ${JSON.stringify(probe)}`, - ); - } - return { npmVersion, ...help, probe }; -} - -function parseRuntimeArgs(argv) { - const values = new Map(); - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg !== "--node" && arg !== "--npm") { - throw new Error(`unknown argument ${arg}`); - } - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) { - throw new Error(`${arg} requires a version`); - } - if (values.has(arg)) { - throw new Error(`${arg} may be specified only once`); - } - values.set(arg, value); - index += 1; - } - if (!values.has("--node") || !values.has("--npm")) { - throw new Error("check-runtime requires --node VERSION --npm VERSION"); - } - return { nodeVersion: values.get("--node"), npmVersion: values.get("--npm") }; -} - -function parseTrustCliArgs(argv) { - const allowed = new Set(["--npm-cli"]); - const values = new Map(); - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (!allowed.has(arg)) throw new Error(`unknown argument ${arg}`); - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) throw new Error(`${arg} requires a path`); - if (values.has(arg)) throw new Error(`${arg} may be specified only once`); - values.set(arg, value); - index += 1; - } - for (const arg of allowed) { - const value = values.get(arg); - if (value === undefined) { - throw new Error("check-trust-cli requires --npm-cli PATH"); - } - if (!isFullyQualifiedNativePath(value)) { - throw new Error(`${arg} must be a fully qualified native absolute path`); - } - let stat; - try { - stat = lstatSync(value); - } catch { - throw new Error(`${arg} does not identify a readable file`); - } - if (!stat.isFile() || stat.isSymbolicLink()) { - throw new Error(`${arg} must identify a regular, non-symlink file`); - } - } - const nodeExecutable = process.execPath; - let nodeStat; - try { - nodeStat = lstatSync(nodeExecutable); - } catch { - throw new Error("the active Node.js executable does not identify a readable file"); - } - if ( - !isFullyQualifiedNativePath(nodeExecutable) - || !nodeStat.isFile() - || nodeStat.isSymbolicLink() - ) { - throw new Error("the active Node.js executable must identify a regular, non-symlink absolute file"); - } - return { - nodeExecutable, - npmCli: values.get("--npm-cli"), - }; -} - -function main(argv) { - try { - const [command, ...rest] = argv; - if (command === "check-runtime") { - const versions = validateNpmTrustedPublishingRuntime(parseRuntimeArgs(rest)); - console.log(`npm trusted-publishing runtime passed: Node.js ${versions.nodeVersion}, npm ${versions.npmVersion}`); - return; - } - if (command === "check-trust-cli") { - const result = checkNpmTrustCliContract(parseTrustCliArgs(rest)); - console.log(`npm trust CLI contract passed: npm ${result.npmVersion}`); - return; - } - throw new Error( - "usage: npm-trusted-publishing-runtime.mjs " - + "check-runtime --node VERSION --npm VERSION | " - + "check-trust-cli --npm-cli PATH", - ); - } catch (error) { - console.error(`npm-trusted-publishing-runtime: ${error.message}`); - process.exit(1); - } -} - -if ( - import.meta.main === true - || (process.argv[1] !== undefined - && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) -) { - main(process.argv.slice(2)); -} diff --git a/tools/release/npm-trusted-publishing-runtime.mts b/tools/release/npm-trusted-publishing-runtime.mts new file mode 100644 index 000000000..ec58c8f9c --- /dev/null +++ b/tools/release/npm-trusted-publishing-runtime.mts @@ -0,0 +1,101 @@ +#!/usr/bin/env node + +// Operational npm trusted-publisher validation; this module does not produce +// package or carrier bytes. + +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; + +export const MINIMUM_TRUSTED_PUBLISHING_NODE_VERSION = '22.14.0'; +export const MINIMUM_TRUSTED_PUBLISHING_NPM_VERSION = '11.5.1'; +export const MINIMUM_NPM_TRUST_CLI_VERSION = '11.15.0'; + +function parsedVersion(value, label) { + if (typeof value !== 'string') { + throw new TypeError(`${label} version must be a string`); + } + const match = value.trim().match(/^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/u); + if (match === null) { + throw new TypeError(`${label} version must be complete semver; got ${JSON.stringify(value)}`); + } + return match.slice(1).map((part) => Number.parseInt(part, 10)); +} + +function compareVersions(left, right) { + for (let index = 0; index < 3; index += 1) { + if (left[index] !== right[index]) { + return left[index] - right[index]; + } + } + return 0; +} + +function requireMinimumVersion(actual, minimum, label) { + if ( + compareVersions(parsedVersion(actual, label), parsedVersion(minimum, `${label} minimum`)) < 0 + ) { + throw new Error(`${label} ${actual} is too old for npm trusted publishing; need >= ${minimum}`); + } +} + +export function validateNpmTrustedPublishingRuntime({ nodeVersion, npmVersion }) { + requireMinimumVersion(nodeVersion, MINIMUM_TRUSTED_PUBLISHING_NODE_VERSION, 'Node.js'); + requireMinimumVersion(npmVersion, MINIMUM_TRUSTED_PUBLISHING_NPM_VERSION, 'npm'); + return { nodeVersion, npmVersion }; +} + +export function validateNpmTrustCliRuntime(npmVersion) { + requireMinimumVersion(npmVersion, MINIMUM_NPM_TRUST_CLI_VERSION, 'npm trust CLI'); + return npmVersion; +} + +function parseRuntimeArgs(argv) { + const values = new Map(); + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg !== '--node' && arg !== '--npm') { + throw new Error(`unknown argument ${arg}`); + } + const value = argv[index + 1]; + if (value === undefined || value.startsWith('--')) { + throw new Error(`${arg} requires a version`); + } + if (values.has(arg)) { + throw new Error(`${arg} may be specified only once`); + } + values.set(arg, value); + index += 1; + } + if (!values.has('--node') || !values.has('--npm')) { + throw new Error('check-runtime requires --node VERSION --npm VERSION'); + } + return { nodeVersion: values.get('--node'), npmVersion: values.get('--npm') }; +} + +function main(argv) { + try { + const [command, ...rest] = argv; + if (command === 'check-runtime') { + const versions = validateNpmTrustedPublishingRuntime(parseRuntimeArgs(rest)); + console.log( + `npm trusted-publishing runtime passed: Node.js ${versions.nodeVersion}, npm ${versions.npmVersion}`, + ); + return; + } + throw new Error( + 'usage: npm-trusted-publishing-runtime.mts ' + 'check-runtime --node VERSION --npm VERSION', + ); + } catch (error) { + console.error(`npm-trusted-publishing-runtime: ${error.message}`); + process.exit(1); + } +} + +if ( + import.meta.main === true || + (process.argv[1] !== undefined && + fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) +) { + main(process.argv.slice(2)); +} diff --git a/tools/release/npm-trusted-publishing.mjs b/tools/release/npm-trusted-publishing.mjs deleted file mode 100644 index 50beaccb8..000000000 --- a/tools/release/npm-trusted-publishing.mjs +++ /dev/null @@ -1,46 +0,0 @@ -export const NPM_TRUSTED_PUBLISHING_REPOSITORY = - "git+https://github.com/f0rr0/oliphaunt.git"; - -function object(value) { - return value !== null && typeof value === "object" && !Array.isArray(value); -} - -// This validator defines the npm manifests accepted by deterministic carrier -// materialization. Operational -// runtime and registry trust checks live in npm-trusted-publishing-runtime.mjs -// so changes to release transport do not spuriously version package products. -export function validateNpmTrustedPublishingManifest(manifest, context = "npm package") { - if (!object(manifest)) { - throw new TypeError(`${context} package.json must be an object`); - } - if (typeof manifest.name !== "string" || !manifest.name.startsWith("@oliphaunt/")) { - throw new Error(`${context} must declare an @oliphaunt package name`); - } - if (typeof manifest.version !== "string" || manifest.version.length === 0) { - throw new Error(`${context} must declare a package version`); - } - if (!object(manifest.repository)) { - throw new Error(`${context} repository must be an object for npm trusted publishing`); - } - if (manifest.repository.type !== "git") { - throw new Error(`${context} repository.type must be "git" for npm trusted publishing`); - } - if (manifest.repository.url !== NPM_TRUSTED_PUBLISHING_REPOSITORY) { - throw new Error( - `${context} repository.url must exactly match ${NPM_TRUSTED_PUBLISHING_REPOSITORY}; got ${JSON.stringify(manifest.repository.url ?? null)}`, - ); - } - if (manifest.private === true) { - throw new Error(`${context} must not be private`); - } - if (manifest.publishConfig !== undefined && !object(manifest.publishConfig)) { - throw new Error(`${context} publishConfig must be an object when present`); - } - if (manifest.publishConfig?.provenance === false) { - throw new Error(`${context} must not disable npm provenance`); - } - if (manifest.publishConfig?.access !== undefined && manifest.publishConfig.access !== "public") { - throw new Error(`${context} publishConfig.access must be "public" when present`); - } - return manifest; -} diff --git a/tools/release/npm-trusted-publishing.test.mjs b/tools/release/npm-trusted-publishing.test.mjs deleted file mode 100644 index 37dc94b19..000000000 --- a/tools/release/npm-trusted-publishing.test.mjs +++ /dev/null @@ -1,284 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import test from "node:test"; - -import { - NPM_TRUSTED_PUBLISHING_REPOSITORY, - validateNpmTrustedPublishingManifest, -} from "./npm-trusted-publishing.mjs"; -import { - checkNpmTrustCliContract, - isFullyQualifiedNativePath, - validateNpmTrustCliHelp, - validateNpmTrustCliRuntime, - validateNpmTrustedPublishingRuntime, -} from "./npm-trusted-publishing-runtime.mjs"; - -const CLI = fileURLToPath(new URL("npm-trusted-publishing-runtime.mjs", import.meta.url)); - -function manifest(overrides = {}) { - return { - name: "@oliphaunt/example", - version: "1.2.3", - repository: { - type: "git", - url: NPM_TRUSTED_PUBLISHING_REPOSITORY, - }, - publishConfig: { - access: "public", - provenance: true, - }, - ...overrides, - }; -} - -test("accepts the minimum supported trusted-publishing runtime", () => { - assert.deepEqual( - validateNpmTrustedPublishingRuntime({ nodeVersion: "v22.14.0", npmVersion: "11.5.1" }), - { nodeVersion: "v22.14.0", npmVersion: "11.5.1" }, - ); - assert.doesNotThrow(() => - validateNpmTrustedPublishingRuntime({ nodeVersion: "24.1.0", npmVersion: "11.18.0" }) - ); -}); - -test("the runtime checker executes directly under Node without a Bun prerequisite", () => { - const accepted = spawnSync("node", [ - CLI, - "check-runtime", - "--node", "v22.22.3", - "--npm", "11.18.0", - ], { encoding: "utf8" }); - assert.equal(accepted.status, 0, accepted.stderr); - assert.match(accepted.stdout, /npm trusted-publishing runtime passed/u); - - const rejected = spawnSync("node", [ - CLI, - "check-runtime", - "--node", "v22.13.0", - "--npm", "11.18.0", - ], { encoding: "utf8" }); - assert.notEqual(rejected.status, 0); - assert.match(rejected.stderr, /Node[.]js v22[.]13[.]0 is too old/u); -}); - -test("the trust checker reuses active Node and preserves a spaced npm CLI path", () => { - const fixture = mkdtempSync(path.join(tmpdir(), "oliphaunt npm trust ")); - const npmCli = path.join(fixture, "npm cli.js"); - writeFileSync(npmCli, ` -const args = process.argv.slice(2); -if (args.length === 1 && args[0] === "--version") { - console.log("11.18.0"); -} else if (args.join(" ") === "trust list --help") { - console.log("Options: --json --registry"); -} else if (args.join(" ") === "trust github --help") { - console.log("Options: --file --repository --environment --allow-publish --json --registry --yes"); -} else if (args[0] === "trust" && args[1] === "github" && args.includes("--dry-run")) { - console.log(JSON.stringify({ - package: "@oliphaunt/oliphaunt-cli-contract-probe", - file: "release.yml", - repository: "f0rr0/oliphaunt", - environment: "release-publish", - permissions: ["createPackage"], - })); -} else { - console.error("unexpected fake npm invocation", JSON.stringify(args)); - process.exitCode = 2; -} -`, { mode: 0o600 }); - try { - const accepted = spawnSync("node", [ - CLI, - "check-trust-cli", - "--npm-cli", npmCli, - ], { encoding: "utf8" }); - assert.equal(accepted.status, 0, accepted.stderr); - assert.match(accepted.stdout, /npm trust CLI contract passed: npm 11[.]18[.]0/u); - - const redundantNodePath = spawnSync("node", [ - CLI, - "check-trust-cli", - "--node-executable", process.execPath, - "--npm-cli", npmCli, - ], { encoding: "utf8" }); - assert.notEqual(redundantNodePath.status, 0); - assert.match(redundantNodePath.stderr, /unknown argument --node-executable/u); - - const relativeNpmPath = spawnSync("node", [ - CLI, - "check-trust-cli", - "--npm-cli", "npm-cli.js", - ], { encoding: "utf8" }); - assert.notEqual(relativeNpmPath.status, 0); - assert.match(relativeNpmPath.stderr, /--npm-cli must be a fully qualified native absolute path/u); - - const missingNpmPath = spawnSync("node", [ - CLI, - "check-trust-cli", - "--npm-cli", path.join(fixture, "missing npm cli.js"), - ], { encoding: "utf8" }); - assert.notEqual(missingNpmPath.status, 0); - assert.match(missingNpmPath.stderr, /--npm-cli does not identify a readable file/u); - - const duplicateNpmPath = spawnSync("node", [ - CLI, - "check-trust-cli", - "--npm-cli", npmCli, - "--npm-cli", npmCli, - ], { encoding: "utf8" }); - assert.notEqual(duplicateNpmPath.status, 0); - assert.match(duplicateNpmPath.stderr, /--npm-cli may be specified only once/u); - } finally { - rmSync(fixture, { force: true, recursive: true }); - } -}); - -test("rejects MSYS and root-relative spellings as native Windows file identities", () => { - for (const candidate of [ - "/d/a/npm-cli.js", - String.raw`\d\a\npm-cli.js`, - "/npm-cli.js", - String.raw`\npm-cli.js`, - String.raw`D:npm-cli.js`, - ]) { - assert.equal(isFullyQualifiedNativePath(candidate, "win32"), false, candidate); - } - for (const candidate of [ - String.raw`D:\a\npm-cli.js`, - "D:/a/npm-cli.js", - String.raw`\\server\share\npm-cli.js`, - String.raw`\\?\D:\a\npm-cli.js`, - ]) { - assert.equal(isFullyQualifiedNativePath(candidate, "win32"), true, candidate); - } - assert.equal(isFullyQualifiedNativePath("/opt/node/bin/node", "linux"), true); - assert.equal(isFullyQualifiedNativePath("node", "linux"), false); -}); - -test("rejects old or malformed Node.js and npm versions", () => { - assert.throws( - () => validateNpmTrustedPublishingRuntime({ nodeVersion: "22.13.9", npmVersion: "11.5.1" }), - /Node\.js 22\.13\.9 is too old/u, - ); - assert.throws( - () => validateNpmTrustedPublishingRuntime({ nodeVersion: "22.14.0", npmVersion: "11.5.0" }), - /npm 11\.5\.0 is too old/u, - ); - assert.throws( - () => validateNpmTrustedPublishingRuntime({ nodeVersion: "22", npmVersion: "11.5.1" }), - /complete semver/u, - ); -}); - -test("requires npm 11.15 only for trust-configuration management", () => { - assert.equal(validateNpmTrustCliRuntime("11.15.0"), "11.15.0"); - assert.throws(() => validateNpmTrustCliRuntime("11.14.9"), /npm trust CLI 11\.14\.9 is too old/u); - assert.doesNotThrow(() => - validateNpmTrustedPublishingRuntime({ nodeVersion: "22.14.0", npmVersion: "11.5.1" }) - ); -}); - -test("checks the pinned npm trust command-specific help contract without network access", () => { - const calls = []; - const captureImpl = (command, args, options) => { - calls.push({ command, args, options }); - let stdout; - if (args.at(-1) === "--version") stdout = "11.18.0\n"; - else if (args.includes("list")) stdout = "Options: --json --registry\n"; - else if (args.includes("--dry-run")) { - stdout = JSON.stringify({ - package: "@oliphaunt/oliphaunt-cli-contract-probe", - file: "release.yml", - repository: "f0rr0/oliphaunt", - environment: "release-publish", - permissions: ["createPackage"], - }); - } - else { - stdout = - "Options: --file --repository --environment --allow-publish --json --registry --yes\n"; - } - return { status: 0, stdout, stderr: "" }; - }; - const result = checkNpmTrustCliContract({ - nodeExecutable: "/verified/node", - npmCli: "/verified/npm-cli.js", - captureImpl, - }); - assert.equal(result.npmVersion, "11.18.0"); - assert.deepEqual(calls.map(({ args }) => args), [ - ["/verified/npm-cli.js", "--version"], - ["/verified/npm-cli.js", "trust", "list", "--help"], - ["/verified/npm-cli.js", "trust", "github", "--help"], - [ - "/verified/npm-cli.js", - "trust", "github", "@oliphaunt/oliphaunt-cli-contract-probe", - "--file", "release.yml", - "--repo", "f0rr0/oliphaunt", - "--env", "release-publish", - "--allow-publish", - "--yes", - "--json", - "--registry", "http://127.0.0.1:9/", - "--dry-run", - ], - ]); - assert.ok(calls.every(({ options }) => options.timeout === 30_000)); - assert.ok(calls.every(({ options }) => options.maxOutputBytes === 256 * 1024)); - assert.ok(calls.every(({ options }) => typeof options.label === "string")); - assert.equal(calls[3].options.env.NPM_CONFIG_FETCH_RETRIES, "0"); - - assert.throws( - () => validateNpmTrustCliHelp({ - listHelp: "Options: --json", - githubHelp: - "Options: --file --repository --environment --allow-publish --json --registry --yes", - }), - /npm trust list does not advertise required option --registry/u, - ); - assert.throws( - () => checkNpmTrustCliContract({ - nodeExecutable: "/verified/node", - npmCli: "/verified/npm-cli.js", - captureImpl: (_command, args) => ({ - status: args.at(-1) === "--version" ? 0 : 1, - stdout: args.at(-1) === "--version" ? "11.18.0\n" : "", - stderr: args.at(-1) === "--version" ? "" : "unsupported command", - }), - }), - /npm trust list --help failed with exit 1/u, - ); -}); - -test("requires the exact repository URL and permits only publish-safe metadata", () => { - assert.doesNotThrow(() => validateNpmTrustedPublishingManifest(manifest())); - assert.doesNotThrow(() => - validateNpmTrustedPublishingManifest(manifest({ publishConfig: undefined })) - ); - assert.throws( - () => validateNpmTrustedPublishingManifest(manifest({ repository: undefined })), - /repository must be an object/u, - ); - assert.throws( - () => validateNpmTrustedPublishingManifest(manifest({ - repository: { type: "git", url: "https://github.com/f0rr0/oliphaunt" }, - })), - /repository\.url must exactly match/u, - ); - assert.throws( - () => validateNpmTrustedPublishingManifest(manifest({ - publishConfig: { access: "public", provenance: false }, - })), - /must not disable npm provenance/u, - ); - assert.throws( - () => validateNpmTrustedPublishingManifest(manifest({ private: true })), - /must not be private/u, - ); -}); diff --git a/tools/release/npm-trusted-publishing.test.mts b/tools/release/npm-trusted-publishing.test.mts new file mode 100644 index 000000000..eb244a1c7 --- /dev/null +++ b/tools/release/npm-trusted-publishing.test.mts @@ -0,0 +1,95 @@ +#!/usr/bin/env bun + +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + NPM_TRUSTED_PUBLISHING_REPOSITORY, + validateNpmTrustedPublishingManifest, +} from '../packaging/npm-trusted-publishing.mts'; +import { + validateNpmTrustCliRuntime, + validateNpmTrustedPublishingRuntime, +} from './npm-trusted-publishing-runtime.mts'; + +function manifest(overrides = {}) { + return { + name: '@oliphaunt/example', + version: '1.2.3', + repository: { + type: 'git', + url: NPM_TRUSTED_PUBLISHING_REPOSITORY, + }, + publishConfig: { + access: 'public', + provenance: true, + }, + ...overrides, + }; +} + +test('accepts the minimum supported trusted-publishing runtime', () => { + assert.deepEqual( + validateNpmTrustedPublishingRuntime({ nodeVersion: 'v22.14.0', npmVersion: '11.5.1' }), + { nodeVersion: 'v22.14.0', npmVersion: '11.5.1' }, + ); + assert.doesNotThrow(() => + validateNpmTrustedPublishingRuntime({ nodeVersion: '24.1.0', npmVersion: '11.18.0' }), + ); +}); + +test('rejects old or malformed Node.js and npm versions', () => { + assert.throws( + () => validateNpmTrustedPublishingRuntime({ nodeVersion: '22.13.9', npmVersion: '11.5.1' }), + /Node\.js 22\.13\.9 is too old/u, + ); + assert.throws( + () => validateNpmTrustedPublishingRuntime({ nodeVersion: '22.14.0', npmVersion: '11.5.0' }), + /npm 11\.5\.0 is too old/u, + ); + assert.throws( + () => validateNpmTrustedPublishingRuntime({ nodeVersion: '22', npmVersion: '11.5.1' }), + /complete semver/u, + ); +}); + +test('requires npm 11.15 only for trust-configuration management', () => { + assert.equal(validateNpmTrustCliRuntime('11.15.0'), '11.15.0'); + assert.throws(() => validateNpmTrustCliRuntime('11.14.9'), /npm trust CLI 11\.14\.9 is too old/u); + assert.doesNotThrow(() => + validateNpmTrustedPublishingRuntime({ nodeVersion: '22.14.0', npmVersion: '11.5.1' }), + ); +}); + +test('requires the exact repository URL and permits only publish-safe metadata', () => { + assert.doesNotThrow(() => validateNpmTrustedPublishingManifest(manifest())); + assert.doesNotThrow(() => + validateNpmTrustedPublishingManifest(manifest({ publishConfig: undefined })), + ); + assert.throws( + () => validateNpmTrustedPublishingManifest(manifest({ repository: undefined })), + /repository must be an object/u, + ); + assert.throws( + () => + validateNpmTrustedPublishingManifest( + manifest({ + repository: { type: 'git', url: 'https://github.com/f0rr0/oliphaunt' }, + }), + ), + /repository\.url must exactly match/u, + ); + assert.throws( + () => + validateNpmTrustedPublishingManifest( + manifest({ + publishConfig: { access: 'public', provenance: false }, + }), + ), + /must not disable npm provenance/u, + ); + assert.throws( + () => validateNpmTrustedPublishingManifest(manifest({ private: true })), + /must not be private/u, + ); +}); diff --git a/tools/release/npm-trusted-publishing.test.sh b/tools/release/npm-trusted-publishing.test.sh new file mode 100644 index 000000000..167b9b068 --- /dev/null +++ b/tools/release/npm-trusted-publishing.test.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/npm-trusted-publishing.test.mts +output="$(mktemp)" +trap 'rm -f "$output"' EXIT +# This bootstrap/runtime probe intentionally runs with Node: npm uses Node before Bun setup. +node tools/release/npm-trusted-publishing-runtime.mts check-runtime --node v22.22.3 --npm 11.18.0 > "$output" +rg -q 'npm trusted-publishing runtime passed' "$output" +if node tools/release/npm-trusted-publishing-runtime.mts check-runtime --node v22.13.0 --npm 11.18.0 > "$output" 2>&1; then + echo 'Unsupported npm host accepted' >&2; exit 1 +fi +rg -q 'Node.js v22.13.0 is too old' "$output" +echo 'npm bootstrap probe: real Node execution accepts and rejects runtime bounds' diff --git a/tools/release/optimize_native_runtime_payload.mjs b/tools/release/optimize_native_runtime_payload.mjs deleted file mode 100644 index 00f1f0b32..000000000 --- a/tools/release/optimize_native_runtime_payload.mjs +++ /dev/null @@ -1,685 +0,0 @@ -#!/usr/bin/env bun -import { - accessSync, - closeSync, - constants, - existsSync, - lstatSync, - openSync, - readFileSync, - readdirSync, - readSync, - rmSync, - rmdirSync, -} from "node:fs"; -import { dirname, join, relative, resolve, sep } from "node:path"; -import { spawnSync } from "node:child_process"; -import { platform } from "node:os"; -import { fileURLToPath } from "node:url"; - -import { - WINDOWS_VC_RUNTIME_RECEIPT, - verifyWindowsVcRuntimeClosure, -} from "./windows-vc-runtime-closure.mjs"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; - -const TOOL = "optimize_native_runtime_payload.mjs"; -const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); -const POLICY_PATH = join(ROOT, "tools/release/native-runtime-payload-policy.json"); -const POLICY = JSON.parse(readFileSync(POLICY_PATH, "utf8")); - -export const NATIVE_RUNTIME_TOOL_STEMS = Object.freeze([...POLICY.nativeRuntimeToolStems]); -export const NATIVE_TOOLS_TOOL_STEMS = Object.freeze([...POLICY.nativeToolsToolStems]); -export const WINDOWS_VC_RUNTIME_DLLS = Object.freeze([...POLICY.windowsVcRuntimeDlls]); -export const NATIVE_PACKAGED_TOOL_STEMS = Object.freeze([ - ...NATIVE_RUNTIME_TOOL_STEMS, - ...NATIVE_TOOLS_TOOL_STEMS, -]); -export const SNOWBALL_STOPWORD_LANGUAGES = Object.freeze([ - "danish", - "dutch", - "english", - "finnish", - "french", - "german", - "hungarian", - "italian", - "nepali", - "norwegian", - "portuguese", - "russian", - "spanish", - "swedish", - "turkish", -]); - -const DEV_RUNTIME_DIRS = Object.freeze([...POLICY.devRuntimeDirs]); -const DEV_RUNTIME_SUFFIXES = Object.freeze([...POLICY.devRuntimeSuffixes]); -const WINDOWS_DEV_RUNTIME_SUFFIXES = Object.freeze([...POLICY.windowsDevRuntimeSuffixes]); -const MACHO_MAGICS = new Set([ - "feedface", - "cefaedfe", - "feedfacf", - "cffaedfe", - "cafebabe", - "bebafeca", -]); -const ELF_DEBUG_SECTION = /\]\s+\.(debug_[^\s]+|symtab|strtab)\s/g; - -function fail(message) { - console.error(`${TOOL}: ${message}`); - process.exit(1); -} - -function rel(path) { - const resolved = resolve(String(path)); - const relativePath = relative(ROOT, resolved); - if (!relativePath || relativePath.startsWith("..") || relativePath === resolved) { - return resolved.split(sep).join("/"); - } - return relativePath.split(sep).join("/"); -} - -function exists(path) { - return existsSync(path); -} - -function isDirectory(path) { - try { - return lstatSync(path).isDirectory(); - } catch { - return false; - } -} - -function isFile(path) { - try { - return lstatSync(path).isFile(); - } catch { - return false; - } -} - -function readPrefix(path, size = 8) { - const buffer = Buffer.alloc(size); - let fd; - try { - fd = openSync(path, "r"); - const bytesRead = readSync(fd, buffer, 0, size, 0); - return buffer.subarray(0, bytesRead); - } catch (error) { - fail(`failed to read ${path}: ${error.message}`); - } finally { - if (fd !== undefined) { - closeSync(fd); - } - } -} - -function classifyNativeFile(path) { - const prefix = readPrefix(path); - if (prefix.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46]))) { - return { path, kind: "elf", archive: false }; - } - if (MACHO_MAGICS.has(prefix.subarray(0, 4).toString("hex"))) { - return { path, kind: "macho", archive: false }; - } - if (prefix.subarray(0, 2).toString("ascii") === "MZ") { - return { path, kind: "pe", archive: false }; - } - if (prefix.subarray(0, 8).toString("ascii") === "!\n") { - return { path, kind: "archive", archive: true }; - } - return null; -} - -export function isWindowsTarget(target, runtimeDir = null) { - if (target && target.startsWith("windows-")) { - return true; - } - if (!runtimeDir) { - return false; - } - const binDir = join(runtimeDir, "bin"); - return NATIVE_PACKAGED_TOOL_STEMS.some((stem) => isFile(join(binDir, `${stem}.exe`))); -} - -export function requiredRuntimeTools(target, runtimeDir = null) { - if (isWindowsTarget(target, runtimeDir)) { - return NATIVE_RUNTIME_TOOL_STEMS.map((stem) => `${stem}.exe`); - } - return [...NATIVE_RUNTIME_TOOL_STEMS]; -} - -export function requiredToolsPackageTools(target, runtimeDir = null) { - if (isWindowsTarget(target, runtimeDir)) { - return NATIVE_TOOLS_TOOL_STEMS.map((stem) => `${stem}.exe`); - } - return [...NATIVE_TOOLS_TOOL_STEMS]; -} - -export function packagedRuntimeTools(target, runtimeDir = null) { - if (isWindowsTarget(target, runtimeDir)) { - return NATIVE_PACKAGED_TOOL_STEMS.map((stem) => `${stem}.exe`); - } - return [...NATIVE_PACKAGED_TOOL_STEMS]; -} - -export function runtimeToolsForSet(target, runtimeDir = null, toolSet = "packaged") { - if (toolSet === "runtime") { - return requiredRuntimeTools(target, runtimeDir); - } - if (toolSet === "tools") { - return requiredToolsPackageTools(target, runtimeDir); - } - return packagedRuntimeTools(target, runtimeDir); -} - -export function requiredRuntimeMemberPaths(target, prefix) { - return requiredRuntimeTools(target).map((tool) => `${prefix.replace(/\/+$/, "")}/${tool}`); -} - -export function requiredToolsMemberPaths(target, prefix) { - return requiredToolsPackageTools(target).map((tool) => `${prefix.replace(/\/+$/, "")}/${tool}`); -} - -export function requiredCoreRuntimePaths(target, runtimeDir = null) { - const moduleSuffix = isWindowsTarget(target, runtimeDir) - ? ".dll" - : target?.startsWith("macos-") ? ".dylib" : ".so"; - return [ - `lib/postgresql/dict_snowball${moduleSuffix}`, - `lib/postgresql/plpgsql${moduleSuffix}`, - "share/postgresql/extension/plpgsql--1.0.sql", - "share/postgresql/extension/plpgsql.control", - "share/postgresql/snowball_create.sql", - ...SNOWBALL_STOPWORD_LANGUAGES.map( - (language) => `share/postgresql/tsearch_data/${language}.stop`, - ), - ]; -} - -function runtimeDirFor(root) { - for (const candidate of [ - join(root, "runtime"), - join(root, "oliphaunt", "runtime", "files"), - ]) { - if (isDirectory(candidate)) { - return candidate; - } - } - if (isDirectory(join(root, "bin")) && (isDirectory(join(root, "share")) || isDirectory(join(root, "lib")))) { - return root; - } - return null; -} - -function removePath(path) { - rmSync(path, { recursive: true, force: true }); -} - -function walk(root, { includeDirs = false } = {}) { - if (!isDirectory(root)) { - return []; - } - const results = []; - const visit = (current) => { - for (const name of readdirSync(current).sort()) { - const path = join(current, name); - let stat; - try { - stat = lstatSync(path); - } catch { - continue; - } - if (stat.isDirectory()) { - if (includeDirs) { - results.push(path); - } - visit(path); - } else if (stat.isFile()) { - results.push(path); - } - } - }; - visit(root); - return results.sort(); -} - -function pruneEmptyDirs(root) { - for (const path of walk(root, { includeDirs: true }).filter(isDirectory).sort().reverse()) { - try { - rmdirSync(path); - } catch { - // Directory is not empty or disappeared while pruning. - } - } -} - -function posixRelative(from, to) { - return relative(from, to).split(sep).join("/"); -} - -function isDevRuntimeFile(relativePath, { windows }) { - const name = relativePath.split("/").pop().toLowerCase(); - if (DEV_RUNTIME_SUFFIXES.some((suffix) => name.endsWith(suffix))) { - return true; - } - return windows && WINDOWS_DEV_RUNTIME_SUFFIXES.some((suffix) => name.endsWith(suffix)); -} - -function pruneTopLevelModuleDevFiles(root, { windows }) { - const moduleDir = join(root, "lib", "modules"); - if (!isDirectory(moduleDir)) { - return; - } - for (const path of walk(moduleDir)) { - const relativePath = posixRelative(moduleDir, path); - if (isDevRuntimeFile(relativePath, { windows })) { - removePath(path); - } - } - pruneEmptyDirs(moduleDir); -} - -export function pruneRuntimePayload(root, target = null, { toolSet = "packaged" } = {}) { - const runtimeDir = runtimeDirFor(root); - if (!runtimeDir) { - return; - } - - const windows = isWindowsTarget(target, runtimeDir); - const requiredTools = new Set(runtimeToolsForSet(target, runtimeDir, toolSet)); - const binDir = join(runtimeDir, "bin"); - if (isDirectory(binDir)) { - for (const name of readdirSync(binDir).sort()) { - const path = join(binDir, name); - if (windows) { - if (name.toLowerCase().endsWith(".exe") && !requiredTools.has(name)) { - removePath(path); - } - } else if (!requiredTools.has(name)) { - removePath(path); - } - } - } - - if (toolSet === "tools" && isDirectory(runtimeDir)) { - for (const name of readdirSync(runtimeDir).sort()) { - if (name !== "bin") { - removePath(join(runtimeDir, name)); - } - } - } - - for (const relativePath of DEV_RUNTIME_DIRS) { - removePath(join(runtimeDir, ...relativePath.split("/"))); - } - - for (const path of walk(runtimeDir, { includeDirs: true }).sort().reverse()) { - if (isDirectory(path) && path.endsWith(".dSYM")) { - removePath(path); - continue; - } - if (!isFile(path)) { - continue; - } - const relativePath = posixRelative(runtimeDir, path); - if (isDevRuntimeFile(relativePath, { windows })) { - removePath(path); - } - } - - pruneEmptyDirs(runtimeDir); - pruneTopLevelModuleDevFiles(root, { windows }); -} - -function which(command) { - const pathEnv = process.env.PATH ?? ""; - const extensions = platform() === "win32" ? ["", ".exe", ".cmd", ".bat"] : [""]; - for (const dir of pathEnv.split(platform() === "win32" ? ";" : ":")) { - if (!dir) { - continue; - } - for (const extension of extensions) { - const candidate = join(dir, `${command}${extension}`); - if (isFile(candidate)) { - return candidate; - } - } - } - return null; -} - -function stripSupportedForTarget(target) { - if (!target) { - return true; - } - if (target.startsWith("linux-") || target.startsWith("android-")) { - return platform() === "linux"; - } - if (target.startsWith("macos-") || target.startsWith("ios-")) { - return platform() === "darwin"; - } - if (target.startsWith("windows-")) { - return Boolean( - process.env.OLIPHAUNT_PE_STRIP || - process.env.OLIPHAUNT_STRIP || - which("llvm-strip") || - platform() === "win32", - ); - } - return true; -} - -function stripPayload(root, target) { - const command = ["tools/release/strip_native_release_binaries.mjs"]; - if (target) { - command.push("--target", target); - } - command.push(root); - const result = spawnSync(process.execPath, command, { - cwd: ROOT, - stdio: "inherit", - env: process.env, - }); - if (result.status !== 0) { - fail(`failed to strip native payload under ${rel(root)}`); - } -} - -function fileOutput(path) { - const fileTool = which("file"); - if (!fileTool) { - return null; - } - const result = captureCommandOutput(fileTool, [path], { - cwd: ROOT, - label: `${fileTool} ${path}`, - }); - if (result.status !== 0) { - return null; - } - return result.stdout; -} - -function elfDebugErrors(path) { - const readelf = which("readelf"); - if (readelf) { - const result = captureCommandOutput(readelf, ["-S", path], { - cwd: ROOT, - label: `${readelf} -S ${path}`, - }); - if (result.status !== 0) { - return [`${rel(path)} could not be inspected with readelf: ${result.stderr.trim()}`]; - } - const sections = new Set(); - for (const match of result.stdout.matchAll(ELF_DEBUG_SECTION)) { - sections.add(match[1]); - } - return [...sections].sort().map((section) => `${rel(path)} contains unstripped ELF section .${section}`); - } - - const output = fileOutput(path); - if (output && (output.includes("not stripped") || output.includes("with debug_info"))) { - return [`${rel(path)} appears to contain unstripped ELF debug/symbol data`]; - } - return []; -} - -function validateNativeFiles(root) { - const errors = []; - for (const path of walk(root)) { - const native = classifyNativeFile(path); - if (!native) { - continue; - } - if (native.kind === "elf" && !native.archive) { - errors.push(...elfDebugErrors(path)); - } - } - return errors; -} - -function validateTopLevelModuleDevFiles(root, { windows }) { - const errors = []; - const moduleDir = join(root, "lib", "modules"); - if (!isDirectory(moduleDir)) { - return errors; - } - for (const path of walk(moduleDir)) { - const relativePath = posixRelative(moduleDir, path); - if (isDevRuntimeFile(relativePath, { windows })) { - errors.push(`${rel(path)} is a development-only native module file`); - } - } - return errors; -} - -function validateRuntimeTree(root, target, requireRuntime, { toolSet = "packaged" } = {}) { - const errors = []; - const runtimeDir = runtimeDirFor(root); - if (!runtimeDir) { - if (requireRuntime) { - errors.push(`${rel(root)} is missing a runtime tree`); - } - return errors; - } - - const windows = isWindowsTarget(target, runtimeDir); - const requiredTools = new Set(runtimeToolsForSet(target, runtimeDir, toolSet)); - const binDir = join(runtimeDir, "bin"); - if (requireRuntime && !isDirectory(binDir)) { - errors.push(`${rel(runtimeDir)} is missing bin`); - } - if (isDirectory(binDir)) { - for (const tool of [...requiredTools].sort()) { - const path = join(binDir, tool); - if (!isFile(path)) { - errors.push(`${rel(runtimeDir)} is missing required runtime tool bin/${tool}`); - continue; - } - if (!windows) { - try { - accessSync(path, constants.X_OK); - } catch { - errors.push(`${rel(path)} must be executable`); - } - } - } - for (const name of readdirSync(binDir).sort()) { - const path = join(binDir, name); - if (windows) { - if (name.toLowerCase().endsWith(".exe") && !requiredTools.has(name)) { - errors.push(`${rel(path)} is an extra Windows runtime executable`); - } - } else if (!requiredTools.has(name)) { - errors.push(`${rel(path)} is an extra runtime tool`); - } - } - } - - if (requireRuntime && toolSet !== "tools") { - for (const relativePath of requiredCoreRuntimePaths(target, runtimeDir)) { - if (!isFile(join(runtimeDir, ...relativePath.split("/")))) { - errors.push(`${rel(runtimeDir)} is missing required core runtime file ${relativePath}`); - } - } - } - - if (toolSet === "tools" && isDirectory(runtimeDir)) { - const allowed = new Set([ - ...[...requiredTools].map((tool) => `bin/${tool}`), - ...(windows ? WINDOWS_VC_RUNTIME_DLLS.map((name) => `bin/${name}`) : []), - ...(windows ? [`bin/${WINDOWS_VC_RUNTIME_RECEIPT}`] : []), - ]); - for (const path of walk(runtimeDir)) { - const relativePath = posixRelative(runtimeDir, path); - if (!allowed.has(relativePath)) { - errors.push(`${rel(path)} is not part of the native tools payload`); - } - } - } - - for (const relativePath of DEV_RUNTIME_DIRS) { - const path = join(runtimeDir, ...relativePath.split("/")); - if (exists(path)) { - errors.push(`${rel(path)} is a development-only runtime path`); - } - } - - for (const path of walk(runtimeDir, { includeDirs: true })) { - if (isDirectory(path) && path.endsWith(".dSYM")) { - errors.push(`${rel(path)} is a development-only debug symbol bundle`); - continue; - } - if (!isFile(path)) { - continue; - } - const relativePath = posixRelative(runtimeDir, path); - if (isDevRuntimeFile(relativePath, { windows })) { - errors.push(`${rel(path)} is a development-only runtime file`); - } - } - - return errors; -} - -export function validatePayload(root, target = null, { requireRuntime = true, toolSet = "packaged" } = {}) { - const runtimeDir = runtimeDirFor(root); - const windows = isWindowsTarget(target, runtimeDir); - const errors = [ - ...validateRuntimeTree(root, target, requireRuntime, { toolSet }), - ...validateTopLevelModuleDevFiles(root, { windows }), - ...validateNativeFiles(root), - ]; - if (windows && runtimeDir !== null && isDirectory(join(runtimeDir, "bin"))) { - const searchRoots = [join(runtimeDir, "bin")]; - if (isFile(join(root, "bin", "oliphaunt.dll"))) { - searchRoots.push(join(root, "bin")); - } - try { - verifyWindowsVcRuntimeClosure({ - root, - searchRoots, - profile: toolSet === "tools" ? undefined : "provider", - }); - } catch (error) { - errors.push(error instanceof Error ? error.message : String(error)); - } - } - if (errors.length > 0) { - for (const error of errors) { - console.error(error); - } - fail(`${rel(root)} is not an optimized native runtime payload`); - } -} - -export function optimizePayload( - root, - target = null, - { strip = "auto", requireRuntime = true, toolSet = "packaged" } = {}, -) { - pruneRuntimePayload(root, target, { toolSet }); - const shouldStrip = strip === true || (strip === "auto" && stripSupportedForTarget(target)); - if (shouldStrip) { - stripPayload(root, target); - } - validatePayload(root, target, { requireRuntime, toolSet }); -} - -function usage() { - return `Usage: tools/release/optimize_native_runtime_payload.mjs [options] - -Prune, strip, and validate liboliphaunt native runtime payloads. - -Options: - --target Release target id. - --check Validate without mutating the payload. - --no-strip Prune but skip native binary stripping before validation. - --allow-missing-runtime Validate native files when the archive is library-only. - --tool-set packaged, runtime, or tools. Default: packaged. - --help Show this help. -`; -} - -function parseArgs(argv) { - const args = { - root: null, - target: null, - check: false, - noStrip: false, - allowMissingRuntime: false, - toolSet: "packaged", - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--help" || arg === "-h") { - console.log(usage()); - process.exit(0); - } - if (arg === "--target") { - args.target = argv[++index]; - if (!args.target) { - fail("--target requires a value"); - } - continue; - } - if (arg === "--check") { - args.check = true; - continue; - } - if (arg === "--no-strip") { - args.noStrip = true; - continue; - } - if (arg === "--allow-missing-runtime") { - args.allowMissingRuntime = true; - continue; - } - if (arg === "--tool-set") { - args.toolSet = argv[++index]; - if (!["packaged", "runtime", "tools"].includes(args.toolSet)) { - fail("--tool-set must be one of: packaged, runtime, tools"); - } - continue; - } - if (arg.startsWith("-")) { - fail(`unknown option: ${arg}`); - } - if (args.root) { - fail(`unexpected positional argument: ${arg}`); - } - args.root = arg; - } - if (!args.root) { - console.error(usage()); - process.exit(2); - } - return args; -} - -export function main(argv = process.argv.slice(2)) { - const args = parseArgs(argv); - const root = resolve(args.root); - if (!exists(root)) { - fail(`payload root does not exist: ${root}`); - } - if (args.check) { - validatePayload(root, args.target, { - requireRuntime: !args.allowMissingRuntime, - toolSet: args.toolSet, - }); - return; - } - optimizePayload(root, args.target, { - strip: args.noStrip ? false : "auto", - requireRuntime: !args.allowMissingRuntime, - toolSet: args.toolSet, - }); -} - -if (import.meta.main) { - main(); -} diff --git a/tools/release/package-extension-cargo-facades.mjs b/tools/release/package-extension-cargo-facades.mjs deleted file mode 100644 index c9890776e..000000000 --- a/tools/release/package-extension-cargo-facades.mjs +++ /dev/null @@ -1,216 +0,0 @@ -import { mkdirSync, rmSync, writeFileSync } from "node:fs"; -import path from "node:path"; - -import { manualCargoPackageSource } from "./cargo-source-package.mjs"; -import { - exactExtensionProducts, - extensionReleaseProduct, - extensionReleaseVersion, - extensionRegistryPackageTargetSets, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { compareText, ROOT } from "./release-graph.mjs"; -import { - nativeExtensionCargoPackageName, -} from "./extension-registry-packages.mjs"; -import { - expectedExtensionAotTargets, - wasixExtensionAotPackageName, - wasixExtensionPackageName, -} from "./wasix-cargo-artifact-contract.mjs"; -import { - renderUnsupportedNativeTargetGuard, - rustNativeTargetCfg, -} from "./rust-native-targets.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releaseNoticeRows, - releaseProfilePackageLicense, - stageReleaseNotices, -} from "./release-notices.mjs"; - -const FACADE_NOTICE_OPTIONS = Object.freeze({ profile: "code-facade" }); - -function fail(message) { - throw new Error(`package-extension-cargo-facades: ${message}`); -} - -function dependencyFeature(name) { - return `dep:${name}`; -} - -function facadeLinksName(product) { - return `oliphaunt_artifact_relay_extension_${product - .replace(/^oliphaunt-extension-/u, "") - .replaceAll("-", "_")}`; -} - -const FACADE_BUILD_RS = `use std::collections::BTreeMap; -use std::env; - -const PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_"; -const RELAY_PREFIX: &str = "DEP_OLIPHAUNT_ARTIFACT_RELAY_"; -const SUFFIX: &str = "_MANIFEST"; - -fn main() { - let mut manifests = BTreeMap::new(); - for (key, value) in env::vars() { - if value.is_empty() || key.starts_with(RELAY_PREFIX) { - continue; - } - let Some(stem) = key.strip_prefix(PREFIX).and_then(|value| value.strip_suffix(SUFFIX)) else { - continue; - }; - if stem.is_empty() { - panic!("empty Oliphaunt artifact metadata stem"); - } - if let Some(previous) = manifests.insert(stem.to_ascii_lowercase(), value.clone()) { - if previous != value { - panic!("conflicting Oliphaunt extension leaf manifests for {stem}"); - } - } - println!("cargo::rerun-if-changed={value}"); - } - if manifests.is_empty() && env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() { - panic!("extension facade resolved no target-leaf artifact manifest"); - } - for (stem, manifest) in manifests { - println!("cargo::metadata={stem}_manifest={manifest}"); - } -} -`; - -export function renderUnsupportedNativeGuard(product, nativeTargets, nativeCfgs) { - return renderUnsupportedNativeTargetGuard({ - product, - nativeTargets, - nativeCfgs, - feature: "native", - featureLabel: "default native feature", - guidance: "use a declared native target leaf, or depend on the WASIX carrier directly for WASIX builds.", - }); -} - -export function writeFacadeSource(product, outputRoot, { dependencyPaths = {} } = {}) { - if (!exactExtensionProducts("package-extension-cargo-facades").includes(product)) { - fail(`${product} is not an exact extension product`); - } - const nativeOwner = extensionReleaseProduct(product, "native", "package-extension-cargo-facades"); - const wasixOwner = extensionReleaseProduct(product, "wasix", "package-extension-cargo-facades"); - const nativeOnly = nativeOwner !== wasixOwner; - const version = extensionReleaseVersion(product, "native", "package-extension-cargo-facades"); - const sqlNames = extensionSqlNames(product, "package-extension-cargo-facades"); - const targets = extensionRegistryPackageTargetSets(product, "package-extension-cargo-facades"); - const wasixAotTargets = !nativeOnly && targets.includeWasixAot ? expectedExtensionAotTargets() : []; - const sourceDir = path.join(outputRoot, "sources", product); - mkdirSync(path.join(sourceDir, "src"), { recursive: true }); - - const nativeNames = targets.nativeCargoTargets.map((target) => nativeExtensionCargoPackageName(product, target)); - const wasixName = nativeOnly ? null : wasixExtensionPackageName(product); - const aotNames = wasixAotTargets.map((target) => wasixExtensionAotPackageName(product, target)); - const features = [ - `default = ["native"]`, - `native = [${nativeNames.map((name) => JSON.stringify(dependencyFeature(name))).join(", ")}]`, - ...(wasixName === null ? [] : [`wasix = [${JSON.stringify(dependencyFeature(wasixName))}]`]), - ...aotNames.map((name, index) => `${JSON.stringify(`wasix-aot-${wasixAotTargets[index]}`)} = [${JSON.stringify(dependencyFeature(wasixName))}, ${JSON.stringify(dependencyFeature(name))}]`), - ]; - const targetDependencies = []; - const nativeCfgs = []; - for (const target of targets.nativeCargoTargets) { - const cfg = rustNativeTargetCfg(target); - const name = nativeExtensionCargoPackageName(product, target); - nativeCfgs.push(cfg); - targetDependencies.push( - `[target.'cfg(${cfg})'.dependencies]\n${name} = { version = "=${version}", optional = true${dependencyPaths[name] ? `, path = ${JSON.stringify(dependencyPaths[name])}` : ""} }`, - ); - } - const optionalDependencies = [...(wasixName === null ? [] : [wasixName]), ...aotNames] - .map((name) => `${name} = { version = "=${version}", optional = true${dependencyPaths[name] ? `, path = ${JSON.stringify(dependencyPaths[name])}` : ""} }`) - .join("\n"); - const unsupportedNativeGuard = renderUnsupportedNativeGuard( - product, - targets.nativeCargoTargets, - nativeCfgs, - ); - const legalMembers = releaseNoticeRows(FACADE_NOTICE_OPTIONS).map((row) => row.member); - writeFileSync(path.join(sourceDir, "Cargo.toml"), `[package] -name = ${JSON.stringify(product)} -version = ${JSON.stringify(version)} -edition = "2024" -rust-version = "1.93" -description = ${JSON.stringify(`Target-selecting Cargo facade for ${sqlNames.length} Oliphaunt PostgreSQL extension member${sqlNames.length === 1 ? "" : "s"}.`)} -readme = "README.md" -repository = "https://github.com/f0rr0/oliphaunt" -homepage = "https://oliphaunt.dev" -license = ${JSON.stringify(releaseProfilePackageLicense("code-facade").spdx)} -links = ${JSON.stringify(facadeLinksName(product))} -build = "build.rs" -include = ${JSON.stringify(["Cargo.toml", "README.md", "build.rs", "src/**", ...legalMembers])} - -[lib] -path = "src/lib.rs" - -[features] -${features.join("\n")} - -[dependencies] -${optionalDependencies} - -${targetDependencies.join("\n\n")} - -[workspace] -`); - writeFileSync(path.join(sourceDir, "build.rs"), FACADE_BUILD_RS); - writeFileSync(path.join(sourceDir, "README.md"), `# ${product} - -Target-selecting Cargo facade for ${sqlNames.length === 1 ? `the \`${sqlNames[0]}\` PostgreSQL extension` : `the PostgreSQL 18 contrib bundle (${sqlNames.length} exact SQL members)`}. - -The default \`native\` feature selects the matching native artifact leaf.${nativeOnly ? "" : ` Use -\`default-features = false, features = ["wasix"]\` (or a host-specific -\`wasix-aot-*\` feature) for WASIX artifacts.`} -`); - writeFileSync(path.join(sourceDir, "src/lib.rs"), `#![forbid(unsafe_code)] - -${unsupportedNativeGuard} - -pub const PRODUCT: &str = ${JSON.stringify(product)}; -pub const VERSION: &str = env!("CARGO_PKG_VERSION"); -pub const EXTENSION_SQL_NAMES: &[&str] = &[${sqlNames.map((sqlName) => JSON.stringify(sqlName)).join(", ")}]; -${sqlNames.length === 1 ? `pub const EXTENSION_SQL_NAME: &str = ${JSON.stringify(sqlNames[0])};` : ""} -`); - stageReleaseNotices(sourceDir, FACADE_NOTICE_OPTIONS); - assertReleaseNoticesInDirectory(sourceDir, FACADE_NOTICE_OPTIONS); - return { product, releaseProduct: nativeOwner, version, sourceDir }; -} - -export function packageExtensionCargoFacades(products, outputRoot) { - const selected = [...new Set(products)].sort(compareText); - if (selected.length !== products.length || selected.length === 0) { - fail("products must be a non-empty duplicate-free list"); - } - rmSync(outputRoot, { recursive: true, force: true }); - mkdirSync(path.join(outputRoot, "crates"), { recursive: true }); - const packages = []; - for (const product of selected) { - const source = writeFacadeSource(product, outputRoot); - const cratePath = manualCargoPackageSource( - path.join(source.sourceDir, "Cargo.toml"), - path.join(outputRoot, "crates"), - { root: ROOT, fail: (_prefix, message) => { throw new Error(message); }, rel: String }, - ); - assertReleaseNoticesInArchive(cratePath, { - ...FACADE_NOTICE_OPTIONS, - prefix: path.basename(cratePath, ".crate"), - }); - packages.push({ - product, - name: product, - version: source.version, - cratePath, - manifestPath: path.join(source.sourceDir, "Cargo.toml"), - kind: "extension-facade", - }); - } - return packages; -} diff --git a/tools/release/package-extension-cargo-facades.test.mjs b/tools/release/package-extension-cargo-facades.test.mjs deleted file mode 100644 index a9a3b7119..000000000 --- a/tools/release/package-extension-cargo-facades.test.mjs +++ /dev/null @@ -1,288 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs"; -import path from "node:path"; - -import { - packageExtensionCargoFacades, - renderUnsupportedNativeGuard, - writeFacadeSource, -} from "./package-extension-cargo-facades.mjs"; -import { - extensionReleaseVersion, - extensionRegistryPackageTargetSets, -} from "./release-artifact-targets.mjs"; -import { loadGraph } from "./release-graph.mjs"; -import { - nativeExtensionCargoPackageName, -} from "./extension-registry-packages.mjs"; -import { - expectedExtensionAotTargets, - wasixExtensionAotPackageName, - wasixExtensionPackageName, -} from "./wasix-cargo-artifact-contract.mjs"; - -const directories = []; - -afterEach(() => { - while (directories.length > 0) rmSync(directories.pop(), { recursive: true, force: true }); -}); - -function sha256(value) { - return createHash("sha256").update(value).digest("hex"); -} - -function fakeCarrier(root, { name, version, header, members }) { - const directory = path.join(root, name); - mkdirSync(path.join(directory, "src"), { recursive: true }); - const links = `oliphaunt_artifact_fixture_${name.replaceAll("-", "_")}`; - writeFileSync(path.join(directory, "Cargo.toml"), `[package] -name = ${JSON.stringify(name)} -version = ${JSON.stringify(version)} -edition = "2024" -links = ${JSON.stringify(links)} -build = "build.rs" - -[lib] -path = "src/lib.rs" - -[workspace] -`); - writeFileSync(path.join(directory, "src/lib.rs"), "#![forbid(unsafe_code)]\n"); - const lines = [ - "use std::env;", - "use std::fs;", - "use std::path::PathBuf;", - "fn main() {", - ' let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR"));', - ` let mut manifest = ${JSON.stringify(`${header}\n`)}.to_owned();`, - ]; - for (const [memberIndex, member] of members.entries()) { - if (member.extension !== undefined) { - lines.push(` manifest.push_str(${JSON.stringify(`\n[[extensions]]\nextension = ${JSON.stringify(member.extension)}\ndependencies = ${JSON.stringify(member.dependencies ?? [])}\n`)});`); - } - for (const [fileIndex, file] of member.files.entries()) { - const variable = `file_${memberIndex}_${fileIndex}`; - lines.push( - ` let ${variable} = out.join(${JSON.stringify(`payload/${member.extension ?? "root"}/${file.relative}`)});`, - ` fs::create_dir_all(${variable}.parent().expect("parent")).expect("mkdir");`, - ` fs::write(&${variable}, ${JSON.stringify(file.contents)}).expect("write payload");`, - ` manifest.push_str(&format!(${JSON.stringify(`\n${member.extension === undefined ? "[[files]]" : "[[extensions.files]]"}\nsource = {:?}\nrelative = ${JSON.stringify(file.relative)}\nsha256 = ${JSON.stringify(sha256(file.contents))}\nexecutable = false\n`)}, ${variable}.display().to_string()));`, - ); - } - } - lines.push( - ' let path = out.join("oliphaunt-artifact.toml");', - ' fs::write(&path, manifest).expect("write manifest");', - ' println!("cargo::metadata=manifest={}", path.display());', - "}", - ); - writeFileSync(path.join(directory, "build.rs"), `${lines.join("\n")}\n`); - return directory; -} - -function findFile(root, basename) { - for (const entry of readdirSync(root)) { - const candidate = path.join(root, entry); - if (statSync(candidate).isDirectory()) { - const found = findFile(candidate, basename); - if (found !== null) return found; - } else if (entry === basename) { - return candidate; - } - } - return null; -} - -describe("exact extension Cargo facade", () => { - test("fails closed for unsupported default-native targets while WASIX opt-out compiles", () => { - const output = mkdtempSync(path.join(import.meta.dir, "../../target/extension-facade-test-")); - directories.push(output); - const [pkg] = packageExtensionCargoFacades(["oliphaunt-extension-pgtap"], output); - const source = path.join(output, "sources/oliphaunt-extension-pgtap/src/lib.rs"); - const text = readFileSync(source, "utf8"); - expect(text).toContain("compile_error!"); - expect(text).toContain('feature = "native"'); - expect(text).toContain('target_env = "gnu"'); - expect(text).toContain('target_env = "msvc"'); - - const forcedUnsupportedSource = path.join(output, "forced-unsupported.rs"); - writeFileSync(forcedUnsupportedSource, `#![forbid(unsafe_code)] -${renderUnsupportedNativeGuard("fixture-extension", ["fixture-unsupported"], ["any()"]) } -pub const FIXTURE: bool = true; -`); - const unsupported = spawnSync("rustc", [ - "--crate-name", "oliphaunt_extension_pgtap", - "--crate-type", "lib", - "--edition", "2024", - "--cfg", 'feature="native"', - forcedUnsupportedSource, - ], { encoding: "utf8" }); - expect(unsupported.status).not.toBe(0); - expect(unsupported.stderr).toContain("default native feature supports only"); - - const wasixOnly = spawnSync("rustc", [ - "--crate-name", "oliphaunt_extension_pgtap", - "--crate-type", "lib", - "--edition", "2024", - "--cfg", 'feature="wasix"', - "--emit", "metadata", - "-o", path.join(output, "wasix-only.rmeta"), - forcedUnsupportedSource, - ], { encoding: "utf8" }); - expect(wasixOnly.status).toBe(0); - - const manifest = Bun.TOML.parse(readFileSync(pkg.manifestPath, "utf8")); - expect(manifest.features.default).toEqual(["native"]); - expect(manifest.features.wasix).toEqual([`dep:oliphaunt-extension-pgtap-wasix`]); - expect(pkg.cratePath.endsWith(".crate")).toBe(true); - }); - - test("the native-owned contrib facade exposes every SQL member without WASIX carriers", () => { - const output = mkdtempSync(path.join(import.meta.dir, "../../target/extension-facade-bundle-test-")); - directories.push(output); - const [pkg] = packageExtensionCargoFacades(["oliphaunt-extension-contrib-pg18"], output); - const source = readFileSync(path.join(output, "sources/oliphaunt-extension-contrib-pg18/src/lib.rs"), "utf8"); - const manifest = Bun.TOML.parse(readFileSync(pkg.manifestPath, "utf8")); - expect(source).toContain('"amcheck"'); - expect(source).toContain('"uuid-ossp"'); - expect(source).not.toContain("EXTENSION_SQL_NAME: &str"); - expect(manifest.package.version).toBe(extensionReleaseVersion( - "oliphaunt-extension-contrib-pg18", - "native", - "package-extension-cargo-facades.test", - )); - expect(manifest.features.default).toEqual(["native"]); - expect(manifest.features.wasix).toBeUndefined(); - expect(Object.keys(manifest.dependencies ?? {})).toHaveLength(0); - }); - - test("real Cargo metadata relays exact bundle and external manifests into an app build", { - timeout: 60_000, - }, () => { - const root = mkdtempSync(path.join(import.meta.dir, "../../target/extension-facade-integration-")); - directories.push(root); - const leaves = path.join(root, "leaves"); - const generated = path.join(root, "generated"); - mkdirSync(leaves, { recursive: true }); - const rustcVersion = spawnSync("rustc", ["-vV"], { encoding: "utf8" }); - expect(rustcVersion.status, rustcVersion.stderr).toBe(0); - const host = rustcVersion.stdout.match(/^host: (.+)$/mu)?.[1]; - if (host === undefined) { - throw new Error(`rustc -vV did not report a host target:\n${rustcVersion.stdout}`); - } - expect(host).toMatch(/^[A-Za-z0-9_+.]+(?:-[A-Za-z0-9_+.]+){2,3}$/u); - const targetTriples = { - "linux-arm64-gnu": "aarch64-unknown-linux-gnu", - "linux-x64-gnu": "x86_64-unknown-linux-gnu", - "macos-arm64": "aarch64-apple-darwin", - "windows-x64-msvc": "x86_64-pc-windows-msvc", - }; - const graph = loadGraph("package-extension-cargo-facades.test"); - const nativeRuntimeVersion = graph.products["liboliphaunt-native"].version; - const products = ["oliphaunt-extension-contrib-pg18", "oliphaunt-extension-vector"]; - const dependencyPaths = {}; - for (const product of products) { - const productVersion = extensionReleaseVersion( - product, - "native", - "package-extension-cargo-facades.test", - ); - const targets = extensionRegistryPackageTargetSets(product, "extension-facade-integration"); - const nativeNames = targets.nativeCargoTargets.map((target) => [ - nativeExtensionCargoPackageName(product, target), - targetTriples[target], - ]); - const wasixNames = product === "oliphaunt-extension-contrib-pg18" - ? [] - : [ - [wasixExtensionPackageName(product), "portable"], - ...expectedExtensionAotTargets().map((target) => [wasixExtensionAotPackageName(product, target), target]), - ]; - for (const [name, target] of [...nativeNames, ...wasixNames]) { - const bundled = product === "oliphaunt-extension-contrib-pg18"; - const members = bundled - ? ["cube", "hstore", "pg_trgm"].map((extension) => ({ - extension, - dependencies: [], - files: [{ - relative: `share/postgresql/extension/${extension}.control`, - contents: `${extension} fixture`, - }], - })) - : [{ - files: [{ - relative: "share/postgresql/extension/vector.control", - contents: "vector fixture", - }], - }]; - const header = bundled - ? `schema = "oliphaunt-artifact-manifest-v2"\nproduct = ${JSON.stringify(product)}\nversion = ${JSON.stringify(productVersion)}\nkind = "extension"\ntarget = ${JSON.stringify(target)}\nruntime-product = "liboliphaunt-native"\nruntime-version = ${JSON.stringify(nativeRuntimeVersion)}` - : `schema = "oliphaunt-artifact-manifest-v1"\nproduct = ${JSON.stringify(product)}\nversion = ${JSON.stringify(productVersion)}\nkind = "extension"\ntarget = ${JSON.stringify(target)}\nruntime-product = "liboliphaunt-native"\nruntime-version = ${JSON.stringify(nativeRuntimeVersion)}\nextension = "vector"\ndependencies = []`; - dependencyPaths[name] = fakeCarrier(leaves, { name, version: productVersion, header, members }); - } - writeFacadeSource(product, generated, { dependencyPaths }); - } - - const genericCarrier = (name, product, version, kind, files) => fakeCarrier(leaves, { - name, - version, - header: `schema = "oliphaunt-artifact-manifest-v1"\nproduct = ${JSON.stringify(product)}\nversion = ${JSON.stringify(version)}\nkind = ${JSON.stringify(kind)}\ntarget = ${JSON.stringify(host)}`, - members: [{ files: files.map((relative) => ({ relative, contents: `${name}:${relative}` })) }], - }); - const runtime = genericCarrier("fixture-native-runtime", "liboliphaunt-native", nativeRuntimeVersion, "native-runtime", [ - "runtime/bin/postgres", "runtime/bin/initdb", "runtime/bin/pg_ctl", - "cluster-seed/manifest.properties", "cluster-seed/files/PG_VERSION", - "cluster-seed/files/global/pg_control", "cluster-seed-icu/manifest.properties", - "cluster-seed-icu/files/PG_VERSION", "cluster-seed-icu/files/global/pg_control", - ]); - const tools = genericCarrier("fixture-native-tools", "oliphaunt-tools", nativeRuntimeVersion, "native-tools", [ - "runtime/bin/pg_basebackup", "runtime/bin/pg_dump", "runtime/bin/psql", - ]); - const broker = genericCarrier("fixture-broker", "oliphaunt-broker", graph.products["oliphaunt-broker"].version, "broker-helper", [ - "bin/oliphaunt-broker", - ]); - const app = path.join(root, "app"); - mkdirSync(path.join(app, "src"), { recursive: true }); - writeFileSync(path.join(app, "src/lib.rs"), "#![forbid(unsafe_code)]\n"); - writeFileSync(path.join(app, "build.rs"), "fn main() { oliphaunt_build::configure(); }\n"); - writeFileSync(path.join(app, "Cargo.toml"), `[package] -name = "facade-app" -version = "0.0.0" -edition = "2024" -build = "build.rs" - -[package.metadata.oliphaunt] -runtime = "liboliphaunt-native" -runtime-version = ${JSON.stringify(nativeRuntimeVersion)} -extensions = ["cube", "pg_trgm", "vector"] - -[dependencies] -contrib = { package = "oliphaunt-extension-contrib-pg18", path = ${JSON.stringify(path.join(generated, "sources/oliphaunt-extension-contrib-pg18"))} } -vector = { package = "oliphaunt-extension-vector", path = ${JSON.stringify(path.join(generated, "sources/oliphaunt-extension-vector"))} } -fixture-native-runtime = { path = ${JSON.stringify(runtime)} } -fixture-native-tools = { path = ${JSON.stringify(tools)} } -fixture-broker = { path = ${JSON.stringify(broker)} } - -[build-dependencies] -oliphaunt-build = { path = ${JSON.stringify(path.join(import.meta.dir, "../../src/sdks/rust/crates/oliphaunt-build"))} } - -[workspace] -`); - const cargo = spawnSync("cargo", ["check", "--target-dir", path.join(root, "cargo-target")], { - cwd: app, - encoding: "utf8", - env: { ...process.env, OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD: "1" }, - maxBuffer: 20 * 1024 * 1024, - }); - expect(cargo.status, `${cargo.stdout}\n${cargo.stderr}`).toBe(0); - const lock = findFile(path.join(root, "cargo-target"), "oliphaunt-assets.lock"); - expect(lock).not.toBeNull(); - const text = readFileSync(lock, "utf8"); - expect(text).toContain('extension = "cube"'); - expect(text).toContain('extension = "pg_trgm"'); - expect(text).toContain('extension = "vector"'); - expect(text).not.toContain('extension = "hstore"'); - }); -}); diff --git a/tools/release/package-extension-release-carriers.mjs b/tools/release/package-extension-release-carriers.mjs deleted file mode 100644 index 86412d73e..000000000 --- a/tools/release/package-extension-release-carriers.mjs +++ /dev/null @@ -1,2986 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync as nodeSpawnSync } from "node:child_process"; -import { createHash } from "node:crypto"; -import { - chmodSync, - closeSync, - constants, - copyFileSync, - cpSync, - existsSync, - lstatSync, - mkdtempSync, - mkdirSync, - openSync, - readFileSync, - readSync, - readdirSync, - realpathSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { parseNpmExtensionLicenseFiles } from "../../src/sdks/js/src/native/extension-contract.ts"; -import { captureCommandBytes, captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { - manualCargoPackageSource, - readCargoPackageNameVersion, -} from "./cargo-source-package.mjs"; -import { RUST_BUILD_SCRIPT_SHA256 } from "./rust-build-script-sha256.mjs"; -import { - compareText, - extensionRegistryPackageTargetSets, -} from "./release-artifact-targets.mjs"; -import { localWindowsTarInvocation } from "./tar-command.mjs"; -import { - extensionNpmPackageForProduct, - extensionNpmTargetPackageForProduct, - extensionNpmWasixPackageForProduct, - nativeExtensionCargoLinksName, - nativeExtensionCargoPackageName, - nativeExtensionCargoPartPackageName, -} from "./extension-registry-packages.mjs"; -import { CORE_RUNTIME_ARCHIVE_FILES } from "./wasix-cargo-artifact-contract.mjs"; -import { - readPortableArchiveEntries, - readPortableTarZstdBufferEntries, -} from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - IOS_CARRIER_FILENAME, - buildIosCarrierManifest, -} from "./ios-carrier-manifest.mjs"; -import { - NPM_TRUSTED_PUBLISHING_REPOSITORY, - validateNpmTrustedPublishingManifest, -} from "./npm-trusted-publishing.mjs"; -import { validateExtensionArtifactArchive } from "./extension-artifact-inventory.mjs"; -import { extensionRuntimeAssetContract } from "./extension-runtime-asset-contract.mjs"; -import { - assertExtensionUpstreamLicensesInArchive, - assertExtensionUpstreamLicensesInDirectory, - extensionCarrierLegalContract, - extensionUpstreamLicenseFileInventory, - stageExtensionUpstreamLicenses, -} from "./extension-upstream-licenses.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releaseNoticeRows, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { - assertWasixExtensionArchiveInstall, - assertWasixExtensionInstall, - assertWasixExtensionMemberInstall, - EXTENSION_RUNTIME_CONTRACT_PATH, - EXTENSION_RUNTIME_CONTRACT_SCHEMA, - WASIX_EXTENSION_INSTALL_SCHEMA, - WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, -} from "../../src/shared/extension-runtime-contract/wasix-extension-install.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -const TOOL = "package-extension-release-carriers.mjs"; -// npm does not impose crates.io's 10 MiB package limit. Keep one deliberately -// generous guard against accidentally publishing an unbounded staging tree, -// but never manufacture package identities merely to satisfy a repository- -// local threshold. -const NPM_PACKAGE_SAFETY_LIMIT_BYTES = 100 * 1024 * 1024; -const CARGO_PACKAGE_SIZE_LIMIT_BYTES = 10 * 1024 * 1024; -const CARGO_EXTENSION_PART_BYTES = 7 * 1024 * 1024; -const CARGO_EXTENSION_SPLIT_THRESHOLD_BYTES = 9 * 1024 * 1024; -const NPM_EXTENSION_CONTRACT_FILENAME = "extension-contract.json"; -const MAX_COMMAND_CAPTURE_BYTES = 32 * 1024 * 1024; - -function fail(tool, message) { - throw new Error(`${tool}: ${message}`); -} - -function windowsCommandShim(command, platform = process.platform) { - return platform === "win32" && command === "pnpm" - ? `${command}.cmd` - : command; -} - -export function packageCommandInvocation( - command, - args, - { platform = process.platform, cwd = ROOT } = {}, -) { - const shimmed = windowsCommandShim(command, platform); - const tar = command === "tar" - ? localWindowsTarInvocation(args, { cwd, platform }) - : { args: [...args], cwd }; - return { - command: shimmed, - args: tar.args, - ...(platform === "win32" && command === "tar" ? { cwd: tar.cwd } : {}), - shell: platform === "win32" && shimmed.endsWith(".cmd"), - }; -} - -function capturePackageCommandOutput(command, args, options = {}) { - const cwd = options.cwd ?? ROOT; - const invocation = packageCommandInvocation(command, args, { cwd }); - return captureCommandOutput(invocation.command, invocation.args, { - ...options, - cwd: invocation.cwd ?? cwd, - shell: invocation.shell, - }); -} - -function capturePackageCommandBytes(command, args, options = {}) { - const cwd = options.cwd ?? ROOT; - const invocation = packageCommandInvocation(command, args, { cwd }); - return captureCommandBytes(invocation.command, invocation.args, { - ...options, - cwd: invocation.cwd ?? cwd, - shell: invocation.shell, - }); -} - -export function canonicalExtensionNpmTargets(product) { - return extensionRegistryPackageTargetSets(product, TOOL).npmTargets; -} - -function rel(file) { - const relative = path.relative(ROOT, file); - return relative && !relative.startsWith("..") && !path.isAbsolute(relative) - ? relative.split(path.sep).join("/") - : file.split(path.sep).join("/"); -} - -function walkFiles(root) { - const files = []; - const visit = (current) => { - const entries = readdirSync(current, { withFileTypes: true }) - .sort((left, right) => compareText(left.name, right.name)); - for (const entry of entries) { - const entryPath = path.join(current, entry.name); - if (entry.isDirectory()) { - visit(entryPath); - } else if (entry.isFile()) { - files.push(entryPath); - } - } - }; - visit(root); - return files; -} - -function isFile(file) { - try { - return statSync(file).isFile(); - } catch { - return false; - } -} - -function isDirectory(file) { - try { - return statSync(file).isDirectory(); - } catch { - return false; - } -} - -function safeNpmPackageFilenamePrefix(packageName) { - return packageName.replace(/^@/u, "").replaceAll("/", "-"); -} - -function readJsonFile(file) { - try { - return JSON.parse(readFileSync(file, "utf8")); - } catch (error) { - fail(TOOL, `${rel(file)} is not valid JSON: ${error.message}`); - } -} - -function extensionManifestIdentity(manifest) { - let data; - try { - data = JSON.parse(readFileSync(manifest, "utf8")); - } catch { - return ["path", realpathSync(manifest)]; - } - const { product, version, sqlName } = data; - if ([product, version, sqlName].every((value) => typeof value === "string" && value.length > 0)) { - return ["extension", product, version, sqlName]; - } - return ["path", realpathSync(manifest)]; -} - -function extensionManifestCandidates(root) { - if (!existsSync(root)) return []; - const metadata = lstatSync(root); - if (metadata.isSymbolicLink()) { - fail(TOOL, `extension manifest input must not be a symbolic link or junction: ${rel(root)}`); - } - if (metadata.isFile() && path.basename(root) === "extension-artifacts.json") return [root]; - if (metadata.isFile()) return []; - if (!metadata.isDirectory()) { - fail(TOOL, `extension manifest input has an unsupported filesystem type: ${rel(root)}`); - } - // Bun.Glob opens its cwd with a Windows access mask that is rejected by the - // deliberately read-only standard-user release token. The Node-compatible - // directory APIs use the narrower list/read contract already proven by the - // launcher. Keep this traversal explicit so a symlink, Windows junction, or - // special entry cannot be silently skipped while constructing release input. - const manifests = []; - const visit = (directory) => { - const entries = readdirSync(directory, { withFileTypes: true }) - .sort((left, right) => compareText(left.name, right.name)); - for (const entry of entries) { - const candidate = path.join(directory, entry.name); - const candidateMetadata = lstatSync(candidate); - if (candidateMetadata.isSymbolicLink()) { - fail(TOOL, `extension manifest input must not contain a symbolic link or junction: ${rel(candidate)}`); - } - if (candidateMetadata.isDirectory()) { - visit(candidate); - } else if (candidateMetadata.isFile()) { - if (entry.name === "extension-artifacts.json") manifests.push(candidate); - } else { - fail(TOOL, `extension manifest input contains an unsupported filesystem entry: ${rel(candidate)}`); - } - } - }; - visit(root); - return manifests; -} - -export function discoverExtensionManifests(roots) { - const manifests = new Map(); - const seenPaths = new Set(); - for (const root of roots) { - for (const manifest of extensionManifestCandidates(root)) { - const resolved = realpathSync(manifest); - if (seenPaths.has(resolved)) continue; - seenPaths.add(resolved); - const identity = JSON.stringify(extensionManifestIdentity(manifest)); - if (!manifests.has(identity)) manifests.set(identity, manifest); - } - } - return [...manifests.values()]; -} - -function runArchiveCommand(args, label) { - const result = capturePackageCommandOutput(args[0], args.slice(1), { - cwd: ROOT, - label, - maxOutputBytes: MAX_COMMAND_CAPTURE_BYTES, - }); - if (result.error) { - fail(TOOL, `${label} failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - const detail = (result.stderr || result.stdout || "").trim(); - fail(TOOL, `${label} failed${detail ? `: ${detail}` : ""}`); - } - return result.stdout; -} - -function archiveTempDir() { - const root = path.join(ROOT, "target", "extension-carrier-archive-extract"); - mkdirSync(root, { recursive: true }); - return mkdtempSync(path.join(root, "extract-")); -} - -function tarballPackageJson(tarball) { - const text = runArchiveCommand( - ["tar", "-xOzf", tarball, "package/package.json"], - `read package.json from ${rel(tarball)}`, - ); - try { - return JSON.parse(text); - } catch (error) { - fail(TOOL, `${rel(tarball)} package/package.json is not valid JSON: ${error.message}`); - } -} - -function pnpmPackForNpmPublish(packageDir, tarballRoot) { - const packageJson = readJsonFile(path.join(packageDir, "package.json")); - const packageName = packageJson.name; - const packageVersion = packageJson.version; - if (typeof packageName !== "string" || packageName.length === 0) { - fail(TOOL, `${rel(path.join(packageDir, "package.json"))} must declare a package name`); - } - if (typeof packageVersion !== "string" || packageVersion.length === 0) { - fail(TOOL, `${rel(path.join(packageDir, "package.json"))} must declare a package version`); - } - try { - validateNpmTrustedPublishingManifest(packageJson, rel(path.join(packageDir, "package.json"))); - } catch (error) { - fail(TOOL, error instanceof Error ? error.message : String(error)); - } - const packDir = path.join(tarballRoot, safeNpmPackageFilenamePrefix(packageName)); - rmSync(packDir, { recursive: true, force: true }); - mkdirSync(packDir, { recursive: true }); - // Keep Corepack's version selection rooted at the repository. Package staging - // may live under the system temporary directory, where invoking the pnpm shim - // directly would select Corepack's unrelated global default before pnpm ever - // sees the package directory. - const result = capturePackageCommandOutput( - "pnpm", - ["--dir", packageDir, "pack", "--pack-destination", packDir, "--json"], - { - cwd: ROOT, - label: `pnpm pack for ${packageName}`, - maxOutputBytes: MAX_COMMAND_CAPTURE_BYTES, - }, - ); - if (result.error) { - fail(TOOL, `pnpm pack for ${packageName} failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - const detail = (result.stderr || result.stdout || "").trim(); - fail(TOOL, `pnpm pack for ${packageName} failed${detail ? `: ${detail}` : ""}`); - } - let manifest; - try { - manifest = JSON.parse(result.stdout); - } catch (error) { - fail(TOOL, `pnpm pack for ${packageName} did not emit JSON: ${error.message}`); - } - const row = Array.isArray(manifest) ? manifest[0] : manifest; - const filename = row?.filename; - if (typeof filename !== "string" || !filename.endsWith(".tgz")) { - fail(TOOL, `pnpm pack for ${packageName} did not report a .tgz filename`); - } - const destinationTarball = path.isAbsolute(filename) - ? filename - : path.join(packDir, path.basename(filename)); - if (!isFile(destinationTarball)) { - fail(TOOL, `pnpm pack for ${packageName} did not create ${rel(destinationTarball)}`); - } - try { - validateNpmTrustedPublishingManifest( - tarballPackageJson(destinationTarball), - `${rel(destinationTarball)} package/package.json`, - ); - } catch (error) { - fail(TOOL, error instanceof Error ? error.message : String(error)); - } - return destinationTarball; -} - -function cargoTargetTriple(targetId) { - if (targetId === "linux-x64-gnu") return "x86_64-unknown-linux-gnu"; - if (targetId === "linux-arm64-gnu") return "aarch64-unknown-linux-gnu"; - if (targetId === "macos-arm64") return "aarch64-apple-darwin"; - if (targetId === "windows-x64-msvc") return "x86_64-pc-windows-msvc"; - return null; -} - -function rustCrateIdent(crateName) { - return crateName.replaceAll("-", "_"); -} - -function tomlString(value) { - return JSON.stringify(value); -} - -function localFail(message) { - fail(TOOL, message); -} - -export function nativeExtensionCarrierLegal(product, members, { target = null, carriesPayload }) { - if ( - typeof product !== "string" - || !Array.isArray(members) - || members.length === 0 - || members.some((member) => typeof member !== "string" || !member) - || new Set(members).size !== members.length - || typeof carriesPayload !== "boolean" - ) { - throw new Error(`${TOOL}: native extension carrier legal lookup requires a product, unique members, and carriesPayload`); - } - try { - return extensionCarrierLegalContract(product, members, { - family: "native", - target, - carriesPayload, - }); - } catch (cause) { - throw new Error( - `${TOOL}: cannot derive the canonical native extension carrier legal contract: ${cause.message}`, - { cause }, - ); - } -} - -export function wasixExtensionCarrierLegal(product, members) { - if ( - typeof product !== "string" - || !Array.isArray(members) - || members.length === 0 - || members.some((member) => typeof member !== "string" || !member) - || new Set(members).size !== members.length - ) { - throw new Error(`${TOOL}: WASIX extension carrier legal lookup requires a product and unique members`); - } - try { - return extensionCarrierLegalContract(product, members, { - family: "wasix", - target: WASIX_PORTABLE_TARGET, - carriesPayload: true, - }); - } catch (cause) { - throw new Error( - `${TOOL}: cannot derive the canonical WASIX extension carrier legal contract: ${cause.message}`, - { cause }, - ); - } -} - -function carrierLegalMembers(legal) { - return [ - ...releaseNoticeRows({ profile: legal.profile }).map((row) => row.member), - ...(legal.upstreamMembers.length > 0 ? ["share/licenses/**"] : []), - ]; -} - -function stageExtensionCarrierLegal(directory, legal) { - stageReleaseNotices(directory, { profile: legal.profile }); - const upstreamRoot = path.join(directory, "share/licenses"); - if (legal.upstreamMembers.length > 0) { - for (const sqlName of legal.upstreamMembers) { - stageExtensionUpstreamLicenses(sqlName, directory); - } - assertExtensionUpstreamLicensesInDirectory(legal.upstreamMembers, directory); - } else if (existsSync(upstreamRoot)) { - const stat = lstatSync(upstreamRoot); - if (!stat.isDirectory() || stat.isSymbolicLink()) { - fail(TOOL, `stale upstream license root must be a real directory: ${rel(upstreamRoot)}`); - } - rmSync(upstreamRoot, { recursive: true }); - } - assertReleaseNoticesInDirectory(directory, { profile: legal.profile }); -} - -function assertExtensionCarrierArchive(archive, legal, prefix) { - assertReleaseNoticesInArchive(archive, { profile: legal.profile, prefix }); - if (legal.upstreamMembers.length > 0) { - assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, archive, { prefix }); - } -} - -function assertNpmExtensionRuntimeLegalArchive(archive, { - product, - members, - target, - bundle, - memberRuntimeRelativePaths, -}) { - for (const sqlName of members) { - const legal = nativeExtensionCarrierLegal(product, [sqlName], { - carriesPayload: true, - target, - }); - if (legal.upstreamMembers.length === 0) continue; - const runtimeRelativePath = bundle - ? memberRuntimeRelativePaths?.[sqlName] - : "runtime"; - if (typeof runtimeRelativePath !== "string" || runtimeRelativePath.length === 0) { - fail(TOOL, `${product} ${target} is missing the runtime path for legal member ${sqlName}`); - } - assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, archive, { - prefix: `package/${runtimeRelativePath}`, - }); - } -} - -function sha256File(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function npmPlatformConstraints(target) { - if (target === "linux-x64-gnu") { - return { os: ["linux"], cpu: ["x64"], libc: ["glibc"] }; - } - if (target === "linux-arm64-gnu") { - return { os: ["linux"], cpu: ["arm64"], libc: ["glibc"] }; - } - if (target === "macos-arm64") { - return { os: ["darwin"], cpu: ["arm64"] }; - } - if (target === "windows-x64-msvc") { - return { os: ["win32"], cpu: ["x64"] }; - } - return {}; -} - -function writeJsonFile(file, value) { - writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`); -} - -export function renderNpmExtensionBundleManifest({ product, version, target, members }) { - return { - schema: "oliphaunt-npm-extension-bundle-v1", - product, - version, - family: "native", - target, - members, - }; -} - -export function npmExtensionMemberContract(product, version, target, member) { - const inventory = frozenExtensionMemberInventory(member, { product, version }); - const legal = nativeExtensionCarrierLegal(product, [inventory.sqlName], { - target, - carriesPayload: true, - }); - const licenseFiles = Object.freeze(parseNpmExtensionLicenseFiles( - legal.upstreamMembers.length === 0 - ? [] - : extensionUpstreamLicenseFileInventory([inventory.sqlName]), - `${product}@${version}/${inventory.sqlName} npm extension licenseFiles`, - ).map((file) => Object.freeze(file))); - if ( - JSON.stringify(licenseFiles.map(({ path: file }) => file)) - !== JSON.stringify([...legal.licenseFiles]) - ) { - fail( - TOOL, - `${product}@${version}/${inventory.sqlName} license file integrity rows disagree with the canonical carrier legal contract`, - ); - } - if ( - Object.hasOwn(member, "licenseFiles") - && JSON.stringify(member.licenseFiles) !== JSON.stringify(licenseFiles) - ) { - fail( - TOOL, - `${product}@${version}/${inventory.sqlName} supplied licenseFiles disagree with the canonical carrier legal contract`, - ); - } - return Object.freeze({ ...inventory, licenseFiles }); -} - -export function renderNpmExtensionContractManifest({ product, version, target, members }) { - return { - schema: "oliphaunt-npm-extension-contract-v1", - product, - version, - family: "native", - target, - members: members.map((member) => npmExtensionMemberContract(product, version, target, member)), - }; -} - -function extensionReleaseManifest(extensionDir, product, version) { - const manifestPath = path.join(extensionDir, "release-assets", `${product}-${version}-manifest.json`); - return isFile(manifestPath) ? readJsonFile(manifestPath) : {}; -} - -export function extensionManifestMembers(manifest) { - if (manifest?.schema === "oliphaunt-extension-ci-artifacts-v1") { - return typeof manifest.sqlName === "string" && manifest.sqlName - ? [manifest] - : []; - } - if (manifest?.schema === "oliphaunt-extension-ci-artifacts-v2") { - return Array.isArray(manifest.extensions) ? manifest.extensions : []; - } - return []; -} - -const FROZEN_EXTENSION_INVENTORY_LIST_FIELDS = Object.freeze([ - "dependencies", - "dataFiles", - "extensionSqlFileNames", - "extensionSqlFilePrefixes", - "sharedPreloadLibraries", -]); - -/** - * Return the exact desktop inventory frozen into one product/member release row. - * - * Registry materialization deliberately does not consult the repository-wide - * generated SDK catalog: independently versioned external products must remain - * bound to the metadata that was qualified and versioned with that product. - */ -export function frozenExtensionMemberInventory(member, { product, version } = {}) { - const owner = [product, version].every((value) => typeof value === "string" && value.length > 0) - ? `${product}@${version}` - : "extension release"; - const sqlName = member?.sqlName; - if (typeof sqlName !== "string" || sqlName.length === 0) { - throw new Error(`${TOOL}: ${owner} has an invalid frozen extension sqlName`); - } - if (typeof member.createsExtension !== "boolean") { - throw new Error(`${TOOL}: ${owner}/${sqlName} must freeze createsExtension as a boolean`); - } - if ( - member.nativeModuleStem !== null - && (typeof member.nativeModuleStem !== "string" || member.nativeModuleStem.length === 0) - ) { - throw new Error(`${TOOL}: ${owner}/${sqlName} must freeze nativeModuleStem as null or a non-empty string`); - } - const inventory = { - sqlName, - createsExtension: member.createsExtension, - nativeModuleStem: member.nativeModuleStem, - }; - for (const field of FROZEN_EXTENSION_INVENTORY_LIST_FIELDS) { - const values = member[field]; - if ( - !Array.isArray(values) - || values.some((value) => typeof value !== "string" || value.length === 0) - ) { - throw new Error(`${TOOL}: ${owner}/${sqlName} must freeze ${field} as a string array`); - } - const canonical = [...new Set(values)].sort(compareText); - if (JSON.stringify(values) !== JSON.stringify(canonical)) { - throw new Error(`${TOOL}: ${owner}/${sqlName} frozen ${field} must be sorted and unique`); - } - inventory[field] = canonical; - } - if (inventory.dependencies.includes(sqlName)) { - throw new Error(`${TOOL}: ${owner}/${sqlName} frozen dependencies must exclude itself`); - } - return Object.freeze(inventory); -} - -const FROZEN_EXTENSION_COMPATIBILITY_FIELDS = Object.freeze([ - "extensionRuntimeContract", - "nativeRuntimeProduct", - "nativeRuntimeVersion", - "postgresMajor", - "wasixRuntimeProduct", - "wasixRuntimeVersion", -]); - -function frozenExtensionCompatibility(value, label) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw new Error(`${TOOL}: ${label} must freeze extension compatibility as an object`); - } - const keys = Object.keys(value).sort(compareText); - if (JSON.stringify(keys) !== JSON.stringify([...FROZEN_EXTENSION_COMPATIBILITY_FIELDS].sort(compareText))) { - throw new Error(`${TOOL}: ${label} must freeze the exact extension compatibility fields`); - } - if ( - value.postgresMajor !== "18" - || value.nativeRuntimeProduct !== "liboliphaunt-native" - || value.wasixRuntimeProduct !== "liboliphaunt-wasix" - || value.extensionRuntimeContract !== EXTENSION_RUNTIME_CONTRACT_PATH - || !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(value.nativeRuntimeVersion ?? "") - || !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(value.wasixRuntimeVersion ?? "") - ) { - throw new Error(`${TOOL}: ${label} contains invalid frozen extension compatibility values`); - } - return Object.freeze(Object.fromEntries( - FROZEN_EXTENSION_COMPATIBILITY_FIELDS.map((field) => [field, value[field]]), - )); -} - -function extensionReleaseManifestMembers(manifest) { - if (manifest?.schema === "oliphaunt-extension-release-manifest-v1") { - return typeof manifest.sqlName === "string" && manifest.sqlName.length > 0 ? [manifest] : []; - } - if (manifest?.schema === "oliphaunt-extension-release-manifest-v2") { - return Array.isArray(manifest.extensions) ? manifest.extensions : []; - } - return []; -} - -function sameFrozenValue(left, right) { - const normalize = (value) => { - if (Array.isArray(value)) return value.map(normalize); - if (value !== null && typeof value === "object") { - return Object.fromEntries( - Object.keys(value).sort(compareText).map((key) => [key, normalize(value[key])]), - ); - } - return value; - }; - return JSON.stringify(normalize(left)) === JSON.stringify(normalize(right)); -} - -function frozenExtensionRelease(manifestPath, manifest, releaseManifest) { - const { product, version } = manifest; - const members = extensionManifestMembers(manifest); - const releaseMembers = extensionReleaseManifestMembers(releaseManifest); - const bundle = manifest?.schema === "oliphaunt-extension-ci-artifacts-v2"; - const expectedReleaseSchema = bundle - ? "oliphaunt-extension-release-manifest-v2" - : "oliphaunt-extension-release-manifest-v1"; - if ( - typeof product !== "string" - || !product - || typeof version !== "string" - || !version - || members.length === 0 - || releaseManifest?.schema !== expectedReleaseSchema - || releaseManifest.product !== product - || releaseManifest.version !== version - || releaseMembers.length !== members.length - ) { - return null; - } - const manifestCompatibility = frozenExtensionCompatibility( - manifest.compatibility, - `${product}@${version} CI manifest`, - ); - const releaseCompatibility = frozenExtensionCompatibility( - releaseManifest.compatibility, - `${product}@${version} release manifest`, - ); - if (!sameFrozenValue(manifestCompatibility, releaseCompatibility)) { - throw new Error(`${TOOL}: ${product}@${version} CI and release compatibility contracts differ`); - } - const memberNames = members.map((member) => member?.sqlName); - const releaseMemberNames = releaseMembers.map((member) => member?.sqlName); - const canonicalMemberNames = [...new Set(memberNames)].sort(compareText); - if ( - JSON.stringify(memberNames) !== JSON.stringify(canonicalMemberNames) - || JSON.stringify(releaseMemberNames) !== JSON.stringify(memberNames) - ) { - throw new Error( - `${TOOL}: ${rel(manifestPath)} and release manifest must freeze the same sorted unique members`, - ); - } - const frozenMembers = members.map((member, index) => { - const metadata = frozenExtensionMemberInventory(member, { product, version }); - const releaseMetadata = frozenExtensionMemberInventory(releaseMembers[index], { product, version }); - if (!sameFrozenValue(metadata, releaseMetadata)) { - throw new Error(`${TOOL}: ${product}@${version}/${member.sqlName} CI and release inventory contracts differ`); - } - return { sqlName: member.sqlName, metadata, member, releaseMember: releaseMembers[index] }; - }); - return { - bundle, - compatibility: manifestCompatibility, - members: frozenMembers, - product, - releaseManifest, - version, - versioning: releaseManifest.versioning, - }; -} - -function extensionRuntimeAssets(extensionDir, manifest, releaseManifest, target) { - const frozen = frozenExtensionRelease( - path.join(extensionDir, "extension-artifacts.json"), - manifest, - releaseManifest, - ); - if (frozen === null) return null; - const { product, version } = frozen; - const runtimeMembers = frozen.members.map(({ sqlName, metadata, member, releaseMember }) => { - const matches = Array.isArray(member.assets) - ? member.assets.filter((asset) => asset?.family === "native" && asset?.kind === "runtime" && asset?.target === target) - : []; - const releaseMatches = Array.isArray(releaseMember.assets) - ? releaseMember.assets.filter((asset) => asset?.family === "native" && asset?.kind === "runtime" && asset?.target === target) - : []; - if (matches.length !== 1) { - return null; - } - if ( - releaseMatches.length !== 1 - || !sameFrozenValue( - extensionRuntimeAssetContract(matches[0]), - extensionRuntimeAssetContract(releaseMatches[0]), - ) - ) { - throw new Error(`${TOOL}: ${product}@${version}/${member.sqlName} CI and release runtime asset contracts differ`); - } - return { sqlName, metadata, asset: matches[0] }; - }); - if (runtimeMembers.some((member) => member === null)) { - return null; - } - if (!frozen.bundle) { - const asset = runtimeMembers[0].asset; - const assetPath = path.join(extensionDir, "release-assets", asset.name); - if (!isFile(assetPath) || sha256File(assetPath) !== asset.sha256 || statSync(assetPath).size !== asset.bytes) { - fail(TOOL, `${product}@${version} ${target} runtime asset is missing or does not match its frozen digest`); - } - runtimeMembers[0].archive = assetPath; - return { - bundle: false, - members: runtimeMembers, - compatibility: frozen.compatibility, - versioning: frozen.versioning, - }; - } - - const carrierNames = new Set(runtimeMembers.map(({ asset }) => asset.carrierAsset)); - if (carrierNames.size !== 1 || carrierNames.has(undefined)) { - fail(TOOL, `${product}@${version} ${target} bundle runtime members must share one aggregate carrier`); - } - const carrierName = [...carrierNames][0]; - const carrierRows = Array.isArray(manifest.carrierAssets) - ? manifest.carrierAssets.filter((carrier) => carrier?.name === carrierName && carrier.family === "native" && carrier.target === target) - : []; - if (carrierRows.length !== 1) { - fail(TOOL, `${product}@${version} ${target} bundle must declare exactly one aggregate carrier row`); - } - const carrier = carrierRows[0]; - const releaseCarrierRows = Array.isArray(releaseManifest.assets) - ? releaseManifest.assets.filter((row) => row?.name === carrierName && row.family === "native" && row.target === target) - : []; - if ( - releaseCarrierRows.length !== 1 - || !sameFrozenValue( - extensionRuntimeAssetContract(carrier), - extensionRuntimeAssetContract(releaseCarrierRows[0]), - ) - ) { - throw new Error(`${TOOL}: ${product}@${version} CI and release aggregate carrier contracts differ`); - } - const carrierPath = path.join(extensionDir, "release-assets", carrierName); - if (!isFile(carrierPath) || statSync(carrierPath).size !== carrier.bytes || sha256File(carrierPath) !== carrier.sha256) { - fail(TOOL, `${product}@${version} ${target} aggregate carrier is missing or does not match its frozen outer digest`); - } - return { - bundle: true, - members: runtimeMembers, - carrier, - carrierPath, - compatibility: frozen.compatibility, - versioning: frozen.versioning, - }; -} - -const WASIX_PORTABLE_TARGET = "wasix-portable"; -const WASIX_EXTENSION_SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/u; -const WASIX_RUNTIME_SUPPORT_SQL_NAMES = new Set( - CORE_RUNTIME_ARCHIVE_FILES.flatMap((member) => { - const match = member.match(/^oliphaunt\/share\/postgresql\/extension\/([^/]+)[.]control$/u); - return match === null ? [] : [match[1]]; - }), -); - -function portableWasixMemberBytes(bytes, label) { - try { - readPortableTarZstdBufferEntries(bytes, { label }); - } catch (cause) { - throw new Error(`${TOOL}: ${cause.message}`, { cause }); - } - return bytes; -} - -function checkedPortableWasixMemberBytes(member, bytes, label) { - const portable = portableWasixMemberBytes(bytes, label); - try { - assertWasixExtensionArchiveInstall(portable, { - schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, - sqlName: member.sqlName, - archive: `extensions/${member.sqlName}.tar.zst`, - sha256: member.asset.sha256, - size: member.asset.bytes, - install: member.install, - }, { label }); - } catch (error) { - fail(TOOL, error instanceof Error ? error.message : String(error)); - } - return portable; -} - -function portableWasixExtensionAssets(extensionDir, manifest, releaseManifest) { - const manifestPath = path.join(extensionDir, "extension-artifacts.json"); - const frozen = frozenExtensionRelease(manifestPath, manifest, releaseManifest); - if (frozen === null) return null; - const { product, version } = frozen; - const members = frozen.members.map(({ sqlName, metadata, member, releaseMember }) => { - if (!WASIX_EXTENSION_SQL_NAME.test(sqlName)) { - fail(TOOL, `${product}@${version} has an invalid WASIX extension SQL name ${JSON.stringify(sqlName)}`); - } - const select = (row) => - row?.family === "wasix" - && row?.kind === "wasix-runtime" - && row?.target === WASIX_PORTABLE_TARGET; - const matches = Array.isArray(member.assets) ? member.assets.filter(select) : []; - const releaseMatches = Array.isArray(releaseMember.assets) - ? releaseMember.assets.filter(select) - : []; - let install; - let releaseInstall; - try { - install = assertWasixExtensionMemberInstall(member, { - label: `${product}@${version}/${sqlName} CI member`, - }); - releaseInstall = assertWasixExtensionMemberInstall(releaseMember, { - label: `${product}@${version}/${sqlName} release member`, - }); - } catch (error) { - fail(TOOL, error instanceof Error ? error.message : String(error)); - } - if (install === null && releaseInstall === null) return null; - if ( - install === null - || releaseInstall === null - || matches.length !== 1 - || releaseMatches.length !== 1 - || !sameFrozenValue( - extensionRuntimeAssetContract(matches[0]), - extensionRuntimeAssetContract(releaseMatches[0]), - ) - ) { - fail(TOOL, `${product}@${version}/${sqlName} CI and release portable WASIX asset contracts differ`); - } - const asset = matches[0]; - if (asset.identity !== null) { - fail(TOOL, `${product}@${version}/${sqlName} portable WASIX runtime asset must declare identity=null`); - } - if (!sameFrozenValue(install, releaseInstall)) { - fail(TOOL, `${product}@${version}/${sqlName} CI and release WASIX install contracts differ`); - } - if (install.dependencies.some((dependency) => dependency === sqlName)) { - fail(TOOL, `${product}@${version}/${sqlName} WASIX install dependencies must exclude itself`); - } - return { sqlName, metadata, asset, install }; - }); - if (members.every((member) => member === null)) return null; - if (members.some((member) => member === null)) { - fail(TOOL, `${product}@${version} has an incomplete portable WASIX extension member set`); - } - - const memberNames = new Set(members.map(({ sqlName }) => sqlName)); - for (const { sqlName, install } of members) { - for (const dependency of install.dependencies) { - if (memberNames.has(dependency) || WASIX_RUNTIME_SUPPORT_SQL_NAMES.has(dependency)) continue; - fail( - TOOL, - `${product}@${version}/${sqlName} has unsupported cross-product or unavailable WASIX dependency ${JSON.stringify(dependency)}`, - ); - } - } - - if (!frozen.bundle) { - const [member] = members; - const archive = path.join(extensionDir, "release-assets", member.asset.name); - if ( - !isFile(archive) - || statSync(archive).size !== member.asset.bytes - || sha256File(archive) !== member.asset.sha256 - ) { - fail(TOOL, `${product}@${version}/${member.sqlName} portable WASIX asset is missing or changed`); - } - const bytes = checkedPortableWasixMemberBytes( - member, - readFileSync(archive), - `${product}@${version}/${member.sqlName} portable WASIX archive`, - ); - return { - bundle: false, - compatibility: frozen.compatibility, - members: [{ ...member, bytes }], - versioning: frozen.versioning, - }; - } - - const carrierNames = new Set(members.map(({ asset }) => asset.carrierAsset)); - if (carrierNames.size !== 1 || carrierNames.has(undefined)) { - fail(TOOL, `${product}@${version} portable WASIX members must share one aggregate carrier`); - } - const carrierName = [...carrierNames][0]; - const selectCarrier = (row) => - row?.name === carrierName - && row?.family === "wasix" - && row?.kind === "extension-bundle" - && row?.target === WASIX_PORTABLE_TARGET; - const carrierRows = Array.isArray(manifest.carrierAssets) - ? manifest.carrierAssets.filter(selectCarrier) - : []; - const releaseCarrierRows = Array.isArray(releaseManifest.assets) - ? releaseManifest.assets.filter(selectCarrier) - : []; - if ( - carrierRows.length !== 1 - || releaseCarrierRows.length !== 1 - || !sameFrozenValue( - extensionRuntimeAssetContract(carrierRows[0]), - extensionRuntimeAssetContract(releaseCarrierRows[0]), - ) - ) { - fail(TOOL, `${product}@${version} CI and release portable WASIX aggregate carrier contracts differ`); - } - const carrier = carrierRows[0]; - const carrierPath = path.join(extensionDir, "release-assets", carrierName); - if ( - !isFile(carrierPath) - || statSync(carrierPath).size !== carrier.bytes - || sha256File(carrierPath) !== carrier.sha256 - ) { - fail(TOOL, `${product}@${version} portable WASIX aggregate carrier is missing or changed`); - } - let entries; - try { - entries = readPortableArchiveEntries(carrierPath, { format: "tar.gz" }); - } catch (cause) { - throw new Error(`${TOOL}: ${cause.message}`, { cause }); - } - return { - bundle: true, - compatibility: frozen.compatibility, - members: members.map((member) => { - const carrierRoot = carrierName.replace(/[.]tar[.]gz$/u, ""); - const expectedMember = `${carrierRoot}/extensions/${member.sqlName}/${member.asset.name}`; - if ( - member.asset.carrierRoot !== carrierRoot - || member.asset.memberPath !== `extensions/${member.sqlName}/${member.asset.name}` - ) { - fail(TOOL, `${product}@${version}/${member.sqlName} has a noncanonical portable WASIX carrier locator`); - } - const entry = entries.get(expectedMember); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink) { - fail(TOOL, `${rel(carrierPath)} must contain regular member ${expectedMember}`); - } - const bytes = entry.data(); - if (bytes.length !== member.asset.bytes || createHash("sha256").update(bytes).digest("hex") !== member.asset.sha256) { - fail(TOOL, `${product}@${version}/${member.sqlName} nested portable WASIX bytes do not match their frozen digest`); - } - return { - ...member, - bytes: checkedPortableWasixMemberBytes( - member, - bytes, - `${product}@${version}/${member.sqlName} nested portable WASIX archive`, - ), - }; - }), - versioning: frozen.versioning, - }; -} - -function checkedArchiveMemberPath(name, archive) { - const normalized = String(name).replaceAll("\\", "/"); - if (!normalized || normalized === "." || normalized === "./" || normalized.startsWith("/") || normalized.includes("\0")) { - fail(TOOL, `${rel(archive)} contains unsafe archive member ${JSON.stringify(name)}`); - } - const parts = normalized.split("/").filter((part) => part && part !== "."); - if (parts.length === 0 || parts.includes("..")) { - fail(TOOL, `${rel(archive)} contains unsafe archive member ${JSON.stringify(name)}`); - } - return parts.join("/"); -} - -function extractExtensionRuntime(asset, runtimeDir, { metadata, target, nativeRuntimeVersion }) { - // Native release assets are stripped and platform-validated on their target - // builders. Carrier assembly preserves those qualified bytes; host-side - // binary rewriting would make output coordinator-dependent. - let validated; - try { - validated = validateExtensionArtifactArchive({ - file: asset, - label: rel(asset), - metadata, - target, - nativeRuntimeVersion, - }); - } catch (error) { - throw new Error( - `${TOOL}: ${error instanceof Error ? error.message : String(error)}`, - { cause: error }, - ); - } - rmSync(runtimeDir, { recursive: true, force: true }); - for (const row of validated.runtimeFiles) { - const archivePath = `files/${row.path}`; - const entry = validated.entries.get(archivePath); - if (entry === undefined) { - fail(TOOL, `${rel(asset)} validated runtime inventory lost ${archivePath}`); - } - const destination = path.join(runtimeDir, ...row.path.split("/")); - mkdirSync(path.dirname(destination), { recursive: true }); - writeFileSync(destination, entry.data, { flag: "wx", mode: entry.mode }); - chmodSync(destination, entry.mode); - } - return validated.runtimeFiles; -} - -function assertRegularArchiveMember(archive, member) { - const result = capturePackageCommandOutput("tar", ["-tvf", archive, member], { - cwd: ROOT, - label: `inspect ${member} in ${rel(archive)}`, - maxOutputBytes: MAX_COMMAND_CAPTURE_BYTES, - }); - if (result.error) { - fail(TOOL, `inspect ${member} in ${rel(archive)} failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - const detail = String(result.stderr ?? result.stdout ?? "").trim(); - fail(TOOL, `inspect ${member} in ${rel(archive)} failed${detail ? `: ${detail}` : ""}`); - } - const entries = String(result.stdout ?? "").split(/\r?\n/u).filter(Boolean); - if (entries.length !== 1 || !entries[0].startsWith("-")) { - fail(TOOL, `${rel(archive)} member ${member} must be exactly one regular file`); - } -} - -function extractArchiveMemberToFile(archive, member, destination) { - assertRegularArchiveMember(archive, member); - mkdirSync(path.dirname(destination), { recursive: true }); - let descriptor; - let result; - let destinationCreated = false; - let extractionError; - try { - descriptor = openSync( - destination, - constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | (constants.O_NOFOLLOW ?? 0), - 0o600, - ); - destinationCreated = true; - result = capturePackageCommandBytes("tar", ["-xOf", archive, member], { - cwd: ROOT, - label: `read ${member} from ${rel(archive)}`, - maxOutputBytes: MAX_COMMAND_CAPTURE_BYTES, - stdoutDescriptor: descriptor, - }); - } catch (error) { - extractionError = error; - } finally { - if (descriptor !== undefined) closeSync(descriptor); - } - if (extractionError !== undefined) { - if (destinationCreated) rmSync(destination, { force: true }); - throw extractionError; - } - if (result?.error) { - rmSync(destination, { force: true }); - fail(TOOL, `read ${member} from ${rel(archive)} failed to start: ${result.error.message}`); - } - if (result?.status !== 0) { - const detail = Buffer.from(result?.stderr ?? "").toString("utf8").trim(); - rmSync(destination, { force: true }); - fail(TOOL, `read ${member} from ${rel(archive)} failed${detail ? `: ${detail}` : ""}`); - } - const metadata = lstatSync(destination); - if (!metadata.isFile() || metadata.isSymbolicLink()) { - rmSync(destination, { force: true }); - fail(TOOL, `extracted ${member} from ${rel(archive)} is not a regular non-symlink file`); - } -} - -function materializeBundleMemberArchive(runtimeSet, member, destination) { - const { asset, sqlName } = member; - const expectedRoot = runtimeSet.carrier.name.replace(/\.tar\.gz$/u, ""); - const expectedMemberPath = `extensions/${sqlName}/${asset.name}`; - if (asset.carrierRoot !== expectedRoot || asset.memberPath !== expectedMemberPath) { - fail(TOOL, `${runtimeSet.carrier.name} has a noncanonical nested locator for ${sqlName}`); - } - const composed = checkedArchiveMemberPath(`${asset.carrierRoot}/${asset.memberPath}`, runtimeSet.carrierPath); - const listed = runArchiveCommand(["tar", "-tf", runtimeSet.carrierPath], `list ${rel(runtimeSet.carrierPath)}`) - .split(/\r?\n/u) - .map((name) => name.trim()) - .filter(Boolean) - .map((name) => checkedArchiveMemberPath(name, runtimeSet.carrierPath)); - if (listed.filter((name) => name === composed).length !== 1) { - fail(TOOL, `${rel(runtimeSet.carrierPath)} must contain nested member ${composed} exactly once`); - } - extractArchiveMemberToFile(runtimeSet.carrierPath, composed, destination); - const bytes = statSync(destination).size; - const digest = sha256File(destination); - if (bytes !== asset.bytes || digest !== asset.sha256) { - rmSync(destination, { force: true }); - fail(TOOL, `${rel(runtimeSet.carrierPath)} nested member ${composed} does not match its frozen size/digest`); - } - chmodSync(destination, 0o644); - return destination; -} - -function wasixDescriptorClosure(runtimeSet, rootSqlName) { - const bySqlName = new Map(runtimeSet.members.map((member) => [member.sqlName, member])); - const visiting = new Set(); - const visited = new Set(); - const closure = []; - const visit = (sqlName) => { - if (visited.has(sqlName)) return; - if (!visiting.add(sqlName)) { - fail(TOOL, `portable WASIX extension dependency cycle involving ${JSON.stringify(sqlName)}`); - } - const member = bySqlName.get(sqlName); - if (member === undefined) { - fail(TOOL, `portable WASIX extension descriptor has no carrier for ${JSON.stringify(sqlName)}`); - } - for (const dependency of member.install.dependencies) { - if (bySqlName.has(dependency)) visit(dependency); - } - visiting.delete(sqlName); - visited.add(sqlName); - closure.push(member); - }; - visit(rootSqlName); - return closure; -} - -function descriptorAssetSource(descriptorPath, sqlName) { - const asset = `extensions/${sqlName}/extension.tar.zst`; - const relative = path.posix.relative(path.posix.dirname(descriptorPath), asset); - return relative.startsWith(".") ? relative : `./${relative}`; -} - -export function renderWasixExtensionDescriptorModule({ - product, - version, - sqlName, - carriers, - compatibility, - descriptorPath = "index.js", -}) { - let frozenCompatibility; - try { - frozenCompatibility = frozenExtensionCompatibility( - compatibility, - `${product}@${version} portable WASIX descriptor`, - ); - } catch { - throw new TypeError(`${TOOL}: invalid portable WASIX extension descriptor compatibility`); - } - if ( - ![product, version, sqlName, descriptorPath].every((value) => typeof value === "string" && value.length > 0) - || !Array.isArray(carriers) - || carriers.length === 0 - || carriers.some((carrier) => - typeof carrier?.sqlName !== "string" - || !WASIX_EXTENSION_SQL_NAME.test(carrier.sqlName) - || typeof carrier?.sha256 !== "string" - || !/^[0-9a-f]{64}$/u.test(carrier.sha256) - || !Number.isSafeInteger(carrier?.size) - || carrier.size <= 0 - || carrier?.install === null - || typeof carrier?.install !== "object" - ) - || new Set(carriers.map((carrier) => carrier.sqlName)).size !== carriers.length - || !carriers.some((carrier) => carrier.sqlName === sqlName) - ) { - throw new TypeError(`${TOOL}: invalid portable WASIX extension descriptor input`); - } - const checkedCarriers = carriers.map((carrier, index) => ({ - ...carrier, - install: assertWasixExtensionInstall(carrier.install, { - expectedSqlName: carrier.sqlName, - label: `${product}@${version} descriptor carrier ${index} install`, - }), - })); - const installRows = checkedCarriers.flatMap((carrier, index) => [ - `const install${index} = deepFreeze(${JSON.stringify(carrier.install, null, 2)});`, - ]); - const carrierRows = checkedCarriers.map((carrier, index) => [ - " {", - ` product: ${JSON.stringify(product)},`, - ` version: ${JSON.stringify(version)},`, - ` sqlName: ${JSON.stringify(carrier.sqlName)},`, - ` archive: ${JSON.stringify(`extensions/${carrier.sqlName}.tar.zst`)},`, - ` sha256: ${JSON.stringify(carrier.sha256)},`, - ` size: ${carrier.size},`, - ` source: new URL(${JSON.stringify(descriptorAssetSource(descriptorPath, carrier.sqlName))}, import.meta.url),`, - ` install: install${index},`, - " },", - ].join("\n")); - return [ - "function deepFreeze(value) {", - ' if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {', - " for (const child of Object.values(value)) deepFreeze(child);", - " Object.freeze(value);", - " }", - " return value;", - "}", - "", - ...installRows, - ...(installRows.length === 0 ? [] : [""]), - "const compatibility = deepFreeze({", - ` extensionRuntimeContract: ${JSON.stringify(EXTENSION_RUNTIME_CONTRACT_SCHEMA)},`, - ` postgresMajor: ${JSON.stringify(frozenCompatibility.postgresMajor)},`, - ` wasixRuntimeProduct: ${JSON.stringify(frozenCompatibility.wasixRuntimeProduct)},`, - ` wasixRuntimeVersion: ${JSON.stringify(frozenCompatibility.wasixRuntimeVersion)},`, - "});", - "", - "const carriers = deepFreeze([", - ...carrierRows, - "]);", - "", - "const descriptor = deepFreeze({", - ' schema: "oliphaunt-wasix-extension-v1",', - ' runtime: "wasix",', - ` product: ${JSON.stringify(product)},`, - ` version: ${JSON.stringify(version)},`, - " compatibility,", - ` sqlName: ${JSON.stringify(sqlName)},`, - " carriers,", - "});", - "", - "export { descriptor };", - "export default descriptor;", - "", - ].join("\n"); -} - -export function renderWasixExtensionDescriptorTypes() { - return `export type OliphauntWasixExtensionNativeModule = Readonly<{ - name: string; - path: string; - sha256: string; - moduleSha256: string; - size: number; -}>; - -export type OliphauntWasixExtensionImport = Readonly<{ - module: string; - name: string; - kind: string; -}>; - -export type OliphauntWasixExtensionLifecycle = Readonly<{ - createExtension: boolean; - createSchema: string | null; - loadSql: readonly string[]; - postCreateSql: readonly string[]; - startupConfig: readonly string[]; - preloadRequired: boolean; - restartRequired: boolean; - sharedMemoryRequired: boolean; -}>; - -export type OliphauntWasixExtensionInstall = Readonly<{ - schema: "${WASIX_EXTENSION_INSTALL_SCHEMA}"; - name: string; - nativeModule: string | null; - nativeModules: readonly OliphauntWasixExtensionNativeModule[]; - coreExportsRequired: readonly string[]; - dependencies: readonly string[]; - loadOrder: readonly string[]; - lifecycle: OliphauntWasixExtensionLifecycle; - installedFiles: readonly string[]; - unresolvedImports: readonly OliphauntWasixExtensionImport[]; -}>; - -export type OliphauntWasixExtensionCarrier = Readonly<{ - product: string; - version: string; - sqlName: string; - archive: string; - sha256: string; - size: number; - source: URL; - install: OliphauntWasixExtensionInstall; -}>; - -export type OliphauntWasixExtensionCompatibility = Readonly<{ - extensionRuntimeContract: "${EXTENSION_RUNTIME_CONTRACT_SCHEMA}"; - postgresMajor: string; - wasixRuntimeProduct: "liboliphaunt-wasix"; - wasixRuntimeVersion: string; -}>; - -export type OliphauntWasixExtensionDescriptor = Readonly<{ - schema: "oliphaunt-wasix-extension-v1"; - runtime: "wasix"; - product: string; - version: string; - compatibility: OliphauntWasixExtensionCompatibility; - sqlName: string; - carriers: readonly OliphauntWasixExtensionCarrier[]; -}>; - -declare const descriptor: OliphauntWasixExtensionDescriptor; -export { descriptor }; -export default descriptor; -`; -} - -function writeWasixExtensionReadme(packageDir, packageName, members, bundle) { - const selectedMembers = bundle ? members.slice(0, 2) : members; - const imports = selectedMembers.map((sqlName) => { - const localName = sqlName.replaceAll("-", "_"); - return `import ${localName} from '${packageName}${bundle ? `/${sqlName}` : ""}';`; - }); - const selectedDescriptors = selectedMembers.map((sqlName) => sqlName.replaceAll("-", "_")); - writeFileSync(path.join(packageDir, "README.md"), [ - `# ${packageName}`, - "", - "Host-neutral portable WASIX carrier for exact Oliphaunt PostgreSQL extension bytes.", - "The carrier does not itself claim qualification for any particular browser or Node host.", - "", - "Consumer API:", - "", - "```ts", - "import Oliphaunt from '@oliphaunt/wasix-ts';", - ...imports, - "", - "const database = await Oliphaunt.open({", - ` extensions: [${selectedDescriptors.join(", ")}],`, - "});", - "```", - "", - "Import only the extension descriptors your application needs. The WASIX runtime", - "carrier and package-relative archives are resolved and verified by the binding.", - "This carrier is selected by the binding and is not a standalone database host.", - "", - "The package version, tag, and changelog belong to the unsuffixed extension release product.", - "", - ].join("\n")); -} - -function writeWasixExtensionNpmPackage(packageDir, { - product, - version, - runtimeSet, -}) { - const members = runtimeSet.members.map(({ sqlName }) => sqlName); - const bundle = members.length > 1; - const packageName = extensionNpmWasixPackageForProduct(product); - const legal = wasixExtensionCarrierLegal(product, members); - mkdirSync(packageDir, { recursive: true }); - for (const member of runtimeSet.members) { - const output = path.join(packageDir, "extensions", member.sqlName, "extension.tar.zst"); - mkdirSync(path.dirname(output), { recursive: true }); - writeFileSync(output, member.bytes, { flag: "wx", mode: 0o644 }); - chmodSync(output, 0o644); - } - - const exports = {}; - const memberExports = {}; - for (const member of runtimeSet.members) { - const descriptorPath = bundle ? `descriptors/${member.sqlName}.js` : "index.js"; - const typesPath = descriptorPath.replace(/[.]js$/u, ".d.ts"); - const closure = wasixDescriptorClosure(runtimeSet, member.sqlName); - const module = renderWasixExtensionDescriptorModule({ - product, - version, - sqlName: member.sqlName, - compatibility: runtimeSet.compatibility, - carriers: closure.map((carrier) => ({ - sqlName: carrier.sqlName, - sha256: carrier.asset.sha256, - size: carrier.asset.bytes, - install: carrier.install, - })), - descriptorPath, - }); - const modulePath = path.join(packageDir, ...descriptorPath.split("/")); - mkdirSync(path.dirname(modulePath), { recursive: true }); - writeFileSync(modulePath, module); - writeFileSync(path.join(packageDir, ...typesPath.split("/")), renderWasixExtensionDescriptorTypes()); - const exportName = bundle ? `./${member.sqlName}` : "."; - memberExports[member.sqlName] = exportName; - exports[exportName] = { - types: `./${typesPath}`, - import: `./${descriptorPath}`, - default: `./${descriptorPath}`, - }; - } - exports["./package.json"] = "./package.json"; - - writeWasixExtensionReadme(packageDir, packageName, members, bundle); - writeJsonFile(path.join(packageDir, "package.json"), { - name: packageName, - version, - description: bundle - ? `Portable Oliphaunt WASIX carrier for ${members.length} exact PostgreSQL contrib extensions.` - : `Portable Oliphaunt WASIX carrier for PostgreSQL ${members[0]}.`, - license: legal.packageSpdx, - type: "module", - sideEffects: false, - repository: { type: "git", url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, - oliphaunt: { - product, - kind: bundle ? "exact-extension-wasix-bundle" : "exact-extension-wasix", - runtime: "wasix", - descriptorSchema: "oliphaunt-wasix-extension-v1", - members, - memberExports, - target: WASIX_PORTABLE_TARGET, - wasixRuntimeProduct: runtimeSet.compatibility.wasixRuntimeProduct, - wasixRuntimeVersion: runtimeSet.compatibility.wasixRuntimeVersion, - runtimeBound: runtimeSet.versioning === "runtime-bound", - }, - publishConfig: { access: "public", provenance: true }, - files: [ - "README.md", - ...(bundle ? ["descriptors"] : ["index.js", "index.d.ts"]), - "extensions", - ...carrierLegalMembers(legal), - ], - exports, - }); - stageExtensionCarrierLegal(packageDir, legal); - return { legal, packageName }; -} - -function extensionModuleDirectory(runtimeDir) { - for (const candidate of [ - path.join(runtimeDir, "lib", "modules"), - path.join(runtimeDir, "lib", "postgresql"), - ]) { - if (!isDirectory(candidate)) continue; - for (const file of readdirSync(candidate).sort(compareText)) { - const fullPath = path.join(candidate, file); - if (isFile(fullPath) && [".so", ".dylib", ".dll"].includes(path.extname(file).toLowerCase())) { - return candidate; - } - } - } - return null; -} - -function writeExtensionReadme(packageDir, packageName, members, target) { - const targetText = target === null ? "" : ` for \`${target}\``; - const memberText = members.length === 1 - ? `the \`${members[0]}\` PostgreSQL extension` - : `${members.length} PostgreSQL contrib extensions`; - const selectionExample = members.length === 1 ? members[0] : members.slice(0, 2).join("', '"); - writeFileSync( - path.join(packageDir, "README.md"), - [ - `# ${packageName}`, - "", - `Oliphaunt registry package for ${memberText}${targetText}.`, - "", - "This package is consumed by `@oliphaunt/ts` when an application opens a database with", - `\`extensions: ['${selectionExample}']\`.`, - "", - ].join("\n"), - ); -} - -function writeExtensionMetaPackage(packageDir, { - product, - version, - members, - target, - targets = [target], - iosCarrier, - liboliphauntVersion, - runtimeBound, - legal, -}) { - const bundle = members.length > 1; - const packageName = extensionNpmPackageForProduct(product); - const targetPackageNames = Object.fromEntries( - targets - .filter((item) => typeof item === "string" && item.length > 0) - .sort(compareText) - .map((item) => [item, extensionNpmTargetPackageForProduct(product, item)]), - ); - mkdirSync(packageDir, { recursive: true }); - writeExtensionReadme(packageDir, packageName, members, null); - writeJsonFile(path.join(packageDir, IOS_CARRIER_FILENAME), iosCarrier); - writeJsonFile(path.join(packageDir, "package.json"), { - name: packageName, - version, - description: bundle - ? `Oliphaunt PostgreSQL contrib extension bundle (${members.length} exact members).` - : `Oliphaunt extension package for PostgreSQL ${members[0]}.`, - license: legal.packageSpdx, - type: "module", - repository: { type: "git", url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, - optionalDependencies: Object.fromEntries(Object.values(targetPackageNames).map((name) => [name, version])), - oliphaunt: { - product, - kind: bundle ? "exact-extension-bundle" : "exact-extension", - ...(bundle ? {} : { sqlName: members[0] }), - members, - targetPackageNames, - iosCarrierManifest: `./${IOS_CARRIER_FILENAME}`, - liboliphauntVersion, - runtimeBound, - }, - publishConfig: { access: "public", provenance: true }, - files: ["README.md", IOS_CARRIER_FILENAME, ...carrierLegalMembers(legal)], - exports: { - "./ios-carriers": `./${IOS_CARRIER_FILENAME}`, - "./package.json": "./package.json", - }, - }); -} - -function writeExtensionTargetPackage(packageDir, { - product, - version, - members, - memberContracts, - target, - liboliphauntVersion, - memberRuntimeRelativePaths = null, - memberModuleRelativePaths = null, - legal, -}) { - const bundle = members.length > 1; - if ( - !Array.isArray(memberContracts) - || JSON.stringify(memberContracts.map((contract) => contract?.sqlName)) !== JSON.stringify(members) - ) { - fail(TOOL, `${product}@${version} target package member contracts must exactly match its members`); - } - const packageName = extensionNpmTargetPackageForProduct(product, target); - const runtimeDir = bundle ? null : path.join(packageDir, "runtime"); - const moduleDir = runtimeDir === null ? null : extensionModuleDirectory(runtimeDir); - const metadata = { - product, - kind: bundle ? "exact-extension-bundle-target" : "exact-extension-target", - ...(bundle ? {} : { sqlName: members[0] }), - members, - extensionContract: NPM_EXTENSION_CONTRACT_FILENAME, - target, - ...(bundle - ? { - bundleManifest: "bundle-manifest.json", - memberRuntimeRelativePaths, - ...(memberModuleRelativePaths !== null && Object.keys(memberModuleRelativePaths).length > 0 - ? { memberModuleRelativePaths } - : {}), - } - : { runtimeRelativePath: "runtime" }), - liboliphauntVersion, - }; - if (moduleDir !== null) { - metadata.moduleRelativePath = path.relative(packageDir, moduleDir).split(path.sep).join("/"); - } - mkdirSync(packageDir, { recursive: true }); - writeExtensionReadme(packageDir, packageName, members, target); - writeJsonFile( - path.join(packageDir, NPM_EXTENSION_CONTRACT_FILENAME), - renderNpmExtensionContractManifest({ product, version, target, members: memberContracts }), - ); - writeJsonFile(path.join(packageDir, "package.json"), { - name: packageName, - version, - description: bundle - ? `${target} Oliphaunt runtime bundle for ${members.length} exact PostgreSQL contrib extensions.` - : `${target} Oliphaunt extension runtime package for PostgreSQL ${members[0]}.`, - license: legal.packageSpdx, - type: "module", - repository: { type: "git", url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, - ...npmPlatformConstraints(target), - optional: true, - oliphaunt: metadata, - publishConfig: { access: "public", provenance: true }, - files: [ - ...(bundle - ? ["extensions", "bundle-manifest.json", NPM_EXTENSION_CONTRACT_FILENAME, "README.md"] - : ["runtime", NPM_EXTENSION_CONTRACT_FILENAME, "README.md"]), - ...carrierLegalMembers(legal), - ], - exports: { - ...(bundle ? { "./bundle-manifest": "./bundle-manifest.json" } : {}), - "./extension-contract": `./${NPM_EXTENSION_CONTRACT_FILENAME}`, - "./package.json": "./package.json", - }, - }); -} - -function npmPackageSizeSafe(tarball, result) { - const size = statSync(tarball).size; - if (size <= NPM_PACKAGE_SAFETY_LIMIT_BYTES) { - return true; - } - result.skipped.push(`${rel(tarball)} is ${size} bytes, exceeding the 100 MiB release safety limit`); - rmSync(tarball, { force: true }); - return false; -} - -export function stageExtensionNativeNpmPackages(roots, stagingRoot, target, result, options = {}) { - const manifests = discoverExtensionManifests(roots); - if (manifests.length === 0) { - result.skipped.push("no extension-artifacts.json manifests found for npm extension packages"); - return null; - } - if (target === null) { - result.skipped.push("current host does not map to a supported npm extension target"); - return null; - } - - rmSync(stagingRoot, { recursive: true, force: true }); - const packageRoot = path.join(stagingRoot, "packages"); - const tarballRoot = path.join(stagingRoot, "tarballs"); - let stagedAny = false; - const stagedIdentities = new Map(); - - for (const manifestPath of manifests) { - const manifest = readJsonFile(manifestPath); - const extensionDir = path.dirname(manifestPath); - const { product, version } = manifest; - const members = extensionManifestMembers(manifest).map((member) => member.sqlName); - if (![product, version].every((value) => typeof value === "string" && value.length > 0) || members.length === 0) { - result.skipped.push(`${rel(manifestPath)} is missing product, version, or exact member rows`); - continue; - } - const releaseManifest = extensionReleaseManifest(extensionDir, product, version); - const expectedReleaseSchema = members.length > 1 - ? "oliphaunt-extension-release-manifest-v2" - : "oliphaunt-extension-release-manifest-v1"; - if ( - releaseManifest.schema !== expectedReleaseSchema - || releaseManifest.product !== product - || releaseManifest.version !== version - ) { - result.skipped.push(`${product}@${version} is missing its exact ${expectedReleaseSchema} release manifest`); - continue; - } - const runtimeSet = extensionRuntimeAssets(extensionDir, manifest, releaseManifest, target); - if (runtimeSet === null) { - result.skipped.push(`${product}@${version} has no complete ${target} native runtime member set`); - continue; - } - const compatibility = runtimeSet.compatibility; - const liboliphauntVersion = compatibility.nativeRuntimeVersion; - const runtimeBound = runtimeSet.versioning === "runtime-bound"; - if (runtimeBound && version !== liboliphauntVersion) { - fail(TOOL, `${product}@${version} is runtime-bound but declares liboliphauntVersion=${liboliphauntVersion}`); - } - const identity = `${product}@${version}:${target}`; - const identityDigest = JSON.stringify({ - release: createHash("sha256").update(JSON.stringify(releaseManifest)).digest("hex"), - members: runtimeSet.members.map(({ metadata, asset }) => ({ - metadata, - sha256: asset.sha256, - bytes: asset.bytes, - })), - carrier: runtimeSet.carrier === undefined - ? null - : { sha256: runtimeSet.carrier.sha256, bytes: runtimeSet.carrier.bytes }, - }); - const previousIdentityDigest = stagedIdentities.get(identity); - if (previousIdentityDigest !== undefined) { - if (previousIdentityDigest !== identityDigest) { - fail(TOOL, `conflicting extension packages discovered for ${identity}`); - } - result.skipped.push(`deduplicated byte-identical extension package ${identity} from ${rel(manifestPath)}`); - continue; - } - stagedIdentities.set(identity, identityDigest); - - const metaDir = path.join(packageRoot, safeNpmPackageFilenamePrefix(extensionNpmPackageForProduct(product))); - const targetDir = path.join(packageRoot, safeNpmPackageFilenamePrefix(extensionNpmTargetPackageForProduct(product, target))); - const memberRuntimeRelativePaths = {}; - const memberModuleRelativePaths = {}; - const bundleManifestMembers = []; - if (runtimeSet.bundle) { - for (const member of runtimeSet.members) { - const archiveRelativePath = `extensions/${member.sqlName}/${member.asset.name}`; - const archive = materializeBundleMemberArchive( - runtimeSet, - member, - path.join(targetDir, ...archiveRelativePath.split("/")), - ); - const runtimeRelativePath = `extensions/${member.sqlName}/runtime`; - const runtimeDir = path.join(targetDir, ...runtimeRelativePath.split("/")); - extractExtensionRuntime(archive, runtimeDir, { - metadata: member.metadata, - target, - nativeRuntimeVersion: liboliphauntVersion, - }); - if (walkFiles(runtimeDir).length === 0) { - fail(TOOL, `${product}@${version} produced an empty ${target} npm runtime payload for ${member.sqlName}`); - } - memberRuntimeRelativePaths[member.sqlName] = runtimeRelativePath; - const moduleDir = extensionModuleDirectory(runtimeDir); - const moduleRelativePath = moduleDir === null - ? null - : path.relative(targetDir, moduleDir).split(path.sep).join("/"); - if (moduleRelativePath !== null) { - memberModuleRelativePaths[member.sqlName] = moduleRelativePath; - } - if (!Object.hasOwn(member.asset, "identity") || member.asset.identity !== null) { - fail( - TOOL, - `${product}@${version} ${target} runtime member ${member.sqlName} must declare identity=null`, - ); - } - bundleManifestMembers.push({ - sqlName: member.sqlName, - kind: member.asset.kind, - identity: null, - path: archiveRelativePath, - sha256: member.asset.sha256, - bytes: member.asset.bytes, - runtimeRelativePath, - ...(moduleRelativePath === null ? {} : { moduleRelativePath }), - }); - } - writeJsonFile( - path.join(targetDir, "bundle-manifest.json"), - renderNpmExtensionBundleManifest({ - product, - version, - target, - members: bundleManifestMembers, - }), - ); - } else { - const runtimeDir = path.join(targetDir, "runtime"); - extractExtensionRuntime(runtimeSet.members[0].archive, runtimeDir, { - metadata: runtimeSet.members[0].metadata, - target, - nativeRuntimeVersion: liboliphauntVersion, - }); - if (walkFiles(runtimeDir).length === 0) { - result.skipped.push(`${product}@${version} produced an empty ${target} npm runtime payload`); - continue; - } - } - const metaTargets = typeof options.metaTargetsForProduct === "function" - ? options.metaTargetsForProduct(product) - : options.metaTargets; - const iosCarrier = buildIosCarrierManifest({ - baseAssetDir: options.baseAssetDir - ?? path.join(ROOT, "target/liboliphaunt/release-assets"), - baseCarrierManifest: options.baseCarrierManifest, - extensionManifests: [manifestPath], - }); - const metaLegal = nativeExtensionCarrierLegal(product, members, { - carriesPayload: false, - }); - const targetLegal = nativeExtensionCarrierLegal(product, members, { - carriesPayload: true, - target, - }); - writeExtensionMetaPackage(metaDir, { - product, - version, - members, - target, - targets: metaTargets ?? [target], - iosCarrier, - liboliphauntVersion, - runtimeBound, - legal: metaLegal, - }); - writeExtensionTargetPackage(targetDir, { - product, - version, - members, - memberContracts: runtimeSet.members.map(({ metadata }) => metadata), - target, - liboliphauntVersion, - memberRuntimeRelativePaths: runtimeSet.bundle ? memberRuntimeRelativePaths : null, - memberModuleRelativePaths: runtimeSet.bundle ? memberModuleRelativePaths : null, - legal: targetLegal, - }); - stageExtensionCarrierLegal(metaDir, metaLegal); - stageExtensionCarrierLegal(targetDir, targetLegal); - const targetTarball = pnpmPackForNpmPublish(targetDir, tarballRoot); - assertExtensionCarrierArchive(targetTarball, targetLegal, "package"); - assertNpmExtensionRuntimeLegalArchive(targetTarball, { - product, - members, - target, - bundle: runtimeSet.bundle, - memberRuntimeRelativePaths, - }); - if (!npmPackageSizeSafe(targetTarball, result)) { - continue; - } - const metaTarball = pnpmPackForNpmPublish(metaDir, tarballRoot); - assertExtensionCarrierArchive(metaTarball, metaLegal, "package"); - if (!npmPackageSizeSafe(metaTarball, result)) { - rmSync(targetTarball, { force: true }); - continue; - } - result.staged.push(rel(targetTarball)); - result.staged.push(rel(metaTarball)); - stagedAny = true; - } - - return stagedAny ? tarballRoot : null; -} - -function assertWasixExtensionNpmArchive(archive, { - legal, - packageName, - product, - runtimeSet, - version, -}) { - assertExtensionCarrierArchive(archive, legal, "package"); - let entries; - try { - entries = readPortableArchiveEntries(archive, { format: "tar.gz" }); - } catch (cause) { - throw new Error(`${TOOL}: ${cause.message}`, { cause }); - } - const packageJsonEntry = entries.get("package/package.json"); - if (packageJsonEntry === undefined || !packageJsonEntry.isFile || packageJsonEntry.isSymbolicLink) { - fail(TOOL, `${rel(archive)} lacks a regular package/package.json`); - } - let packageJson; - try { - packageJson = JSON.parse(packageJsonEntry.data().toString("utf8")); - } catch (cause) { - fail(TOOL, `${rel(archive)} package/package.json is invalid JSON: ${cause.message}`); - } - if ( - packageJson.name !== packageName - || packageJson.version !== version - || packageJson.oliphaunt?.product !== product - || packageJson.oliphaunt?.runtime !== "wasix" - ) { - fail(TOOL, `${rel(archive)} does not preserve its exact WASIX extension package identity`); - } - for (const member of runtimeSet.members) { - const memberPath = `package/extensions/${member.sqlName}/extension.tar.zst`; - const entry = entries.get(memberPath); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink) { - fail(TOOL, `${rel(archive)} lacks regular WASIX carrier ${memberPath}`); - } - const bytes = entry.data(); - if ( - bytes.length !== member.asset.bytes - || createHash("sha256").update(bytes).digest("hex") !== member.asset.sha256 - ) { - fail(TOOL, `${rel(archive)} changed portable WASIX bytes for ${member.sqlName}`); - } - } -} - -export function stageExtensionWasixNpmPackages(roots, stagingRoot, result) { - const manifests = discoverExtensionManifests(roots); - if (manifests.length === 0) return null; - - rmSync(stagingRoot, { recursive: true, force: true }); - const packageRoot = path.join(stagingRoot, "packages"); - const tarballRoot = path.join(stagingRoot, "tarballs"); - const stagedIdentities = new Map(); - let stagedAny = false; - for (const manifestPath of manifests) { - const manifest = readJsonFile(manifestPath); - const extensionDir = path.dirname(manifestPath); - const { product, version } = manifest; - if (![product, version].every((value) => typeof value === "string" && value.length > 0)) continue; - const releaseManifest = extensionReleaseManifest(extensionDir, product, version); - const runtimeSet = portableWasixExtensionAssets(extensionDir, manifest, releaseManifest); - if (runtimeSet === null) continue; - const runtimeVersion = runtimeSet.compatibility.wasixRuntimeVersion; - if (runtimeSet.versioning === "runtime-bound" && version !== runtimeVersion) { - fail(TOOL, `${product}@${version} is runtime-bound but declares WASIX runtime version ${runtimeVersion}`); - } - const identity = `${extensionNpmWasixPackageForProduct(product)}@${version}`; - const digest = JSON.stringify({ - compatibility: runtimeSet.compatibility, - members: runtimeSet.members.map(({ metadata, asset, install }) => ({ - metadata, - sha256: asset.sha256, - bytes: asset.bytes, - install, - })), - versioning: runtimeSet.versioning, - }); - const previous = stagedIdentities.get(identity); - if (previous !== undefined) { - if (previous !== digest) { - fail(TOOL, `conflicting portable WASIX npm candidates discovered for ${identity}`); - } - result.skipped.push(`deduplicated byte-identical portable WASIX npm candidate ${identity}`); - continue; - } - stagedIdentities.set(identity, digest); - - const packageDir = path.join( - packageRoot, - safeNpmPackageFilenamePrefix(extensionNpmWasixPackageForProduct(product)), - ); - const { legal, packageName } = writeWasixExtensionNpmPackage(packageDir, { - product, - version, - runtimeSet, - }); - const tarball = pnpmPackForNpmPublish(packageDir, tarballRoot); - assertWasixExtensionNpmArchive(tarball, { - legal, - packageName, - product, - runtimeSet, - version, - }); - if (!npmPackageSizeSafe(tarball, result)) continue; - result.staged.push(rel(tarball)); - stagedAny = true; - } - return stagedAny ? tarballRoot : null; -} - -export function stageExtensionNpmPackages(roots, stagingRoot, target, result, options = {}) { - rmSync(stagingRoot, { recursive: true, force: true }); - const nativeRoot = stageExtensionNativeNpmPackages( - roots, - path.join(stagingRoot, "native"), - target, - result, - options, - ); - const wasixRoot = stageExtensionWasixNpmPackages( - roots, - path.join(stagingRoot, "wasix"), - result, - ); - return nativeRoot === null && wasixRoot === null ? null : stagingRoot; -} - -export function stageExtensionNpmPackagesForTargets( - roots, - stagingRoot, - targets, - result, - options = {}, -) { - if ( - !Array.isArray(targets) - || targets.length === 0 - || targets.some((target) => typeof target !== "string" || target.length === 0) - || new Set(targets).size !== targets.length - ) { - throw new TypeError(`${TOOL}: extension npm target-set staging requires a non-empty unique target list`); - } - const canonicalTargets = [...targets].sort(compareText); - rmSync(stagingRoot, { recursive: true, force: true }); - const nativeRoots = Object.fromEntries(canonicalTargets.map((target) => [ - target, - stageExtensionNativeNpmPackages( - roots, - path.join(stagingRoot, target), - target, - result, - { - ...options, - metaTargets: options.metaTargets ?? canonicalTargets, - }, - ), - ])); - const wasixRoot = stageExtensionWasixNpmPackages( - roots, - path.join(stagingRoot, "wasix"), - result, - ); - return Object.freeze({ - nativeRoots: Object.freeze(nativeRoots), - wasixRoot, - root: Object.values(nativeRoots).some((root) => root !== null) || wasixRoot !== null - ? stagingRoot - : null, - }); -} - - -function writeNativeExtensionCargoPartCrate(crateDir, { product, version, members, target, index, legal }) { - const name = nativeExtensionCargoPartPackageName(product, target, index); - const subject = members.length === 1 ? members[0] : `${members.length}-member bundle`; - mkdirSync(path.join(crateDir, "src"), { recursive: true }); - writeFileSync( - path.join(crateDir, "Cargo.toml"), - `[package] -name = "${name}" -version = "${version}" -edition = "2024" -rust-version = "1.93" -description = "Cargo payload part ${String(index).padStart(3, "0")} for the ${subject} Oliphaunt native extension carrier on ${target}." -readme = "README.md" -repository = "https://github.com/f0rr0/oliphaunt" -homepage = "https://oliphaunt.dev" -license = ${tomlString(legal.packageSpdx)} -include = ${tomlString(["Cargo.toml", "README.md", "src/**", "payload/**", ...carrierLegalMembers(legal)])} - -[lib] -path = "src/lib.rs" - -[workspace] -`, - ); - writeFileSync( - path.join(crateDir, "README.md"), - `# ${name} - -Cargo payload part for the ${subject} Oliphaunt native extension carrier on \`${target}\`. -Applications do not depend on this crate directly. -`, - ); - writeFileSync( - path.join(crateDir, "src/lib.rs"), - `pub const PRODUCT: &str = "${product}"; -pub const KIND: &str = "extension-part"; -pub const MEMBERS: &[&str] = &[${members.map((member) => JSON.stringify(member)).join(", ")}]; -pub const RELEASE_TARGET: &str = "${target}"; -pub const PART_INDEX: usize = ${index}; -pub const PAYLOAD_ROOT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/payload"); -`, - ); - stageExtensionCarrierLegal(crateDir, legal); -} - -function writeChunk(file, data) { - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, data); -} - -function copyPayloadFile(source, destination) { - mkdirSync(path.dirname(destination), { recursive: true }); - copyFileSync(source, destination); -} - -function buildNativeExtensionPartCrates(runtimeDir, sourceRoot, { - product, - version, - members, - target, - partBytes = CARGO_EXTENSION_PART_BYTES, -}) { - const legal = nativeExtensionCarrierLegal(product, members, { target, carriesPayload: true }); - const partDirs = []; - let currentDir = null; - let currentSize = 0; - - const startPart = () => { - const index = partDirs.length + 1; - if (index > 999) { - throw new Error(`${product}@${version} requires more than 999 Cargo payload parts for ${target}`); - } - const partDir = path.join(sourceRoot, nativeExtensionCargoPartPackageName(product, target, index)); - writeNativeExtensionCargoPartCrate(partDir, { product, version, members, target, index, legal }); - partDirs.push(partDir); - return partDir; - }; - - for (const source of walkFiles(runtimeDir)) { - const relative = path.relative(runtimeDir, source).split(path.sep).join("/"); - const size = statSync(source).size; - if (size > partBytes) { - currentDir = null; - currentSize = 0; - const fd = openSync(source, "r"); - try { - let partIndex = 0; - let offset = 0; - while (offset < size) { - const length = Math.min(partBytes, size - offset); - const buffer = Buffer.allocUnsafe(length); - const bytesRead = readSync(fd, buffer, 0, length, offset); - if (bytesRead <= 0) { - break; - } - const partDir = startPart(); - writeChunk( - path.join(partDir, "payload", "chunks", `${relative}.part${String(partIndex).padStart(3, "0")}`), - buffer.subarray(0, bytesRead), - ); - offset += bytesRead; - partIndex += 1; - } - } finally { - closeSync(fd); - } - continue; - } - if (currentDir === null || currentSize + size > partBytes) { - currentDir = startPart(); - currentSize = 0; - } - copyPayloadFile(source, path.join(currentDir, "payload", "files", relative)); - currentSize += size; - } - - if (partDirs.length === 0) { - throw new Error(`${product}@${version} generated no native extension Cargo part crates`); - } - return partDirs; -} - -const NATIVE_EXTENSION_AGGREGATOR_BUILD_RS = String.raw`use std::collections::BTreeMap; -use std::env; -use std::fs; -use std::io::{self, Read}; -use std::path::{Path, PathBuf}; - -const SCHEMA: &str = __SCHEMA__; -const PRODUCT: &str = __PRODUCT__; -const VERSION: &str = env!("CARGO_PKG_VERSION"); -const KIND: &str = "extension"; -const TARGET: &str = __TARGET__; -const RUNTIME_PRODUCT: &str = __RUNTIME_PRODUCT__; -const RUNTIME_VERSION: &str = __RUNTIME_VERSION__; -const EXTENSIONS: &[&str] = &[ -__EXTENSIONS__ -]; -const EXTENSION_DEPENDENCIES: &[(&str, &[&str])] = &[ -__EXTENSION_DEPENDENCIES__ -]; -const PART_ROOTS: &[&str] = &[ -__PART_ROOTS__ -]; - -fn main() { - emit_manifest(); -} - -fn emit_manifest() { - let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set")); - let payload = out_dir.join("payload"); - if payload.exists() { - fs::remove_dir_all(&payload).expect("remove stale Oliphaunt extension payload"); - } - fs::create_dir_all(&payload).expect("create Oliphaunt extension payload directory"); - - let part_roots = part_roots(); - if part_roots.is_empty() { - if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() { - panic!("missing Oliphaunt extension payload part crates"); - } - return; - } - - let mut chunk_files: BTreeMap> = BTreeMap::new(); - for root in part_roots { - println!("cargo::rerun-if-changed={}", root.display()); - copy_complete_files(&root.join("files"), &payload).expect("copy complete extension payload files"); - collect_chunks(&root.join("chunks"), &root.join("chunks"), &mut chunk_files) - .expect("collect extension payload chunks"); - } - - for (relative, mut chunks) in chunk_files { - chunks.sort_by_key(|(index, _)| *index); - for (expected, (actual, _)) in chunks.iter().enumerate() { - if *actual != expected { - panic!("non-contiguous Oliphaunt extension chunk indexes for {relative}"); - } - } - let output = payload.join(&relative); - if let Some(parent) = output.parent() { - fs::create_dir_all(parent).expect("create reconstructed extension file parent"); - } - let mut writer = fs::File::create(&output).expect("create reconstructed extension payload file"); - for (_, path) in chunks { - let mut reader = fs::File::open(&path).expect("open extension payload chunk"); - io::copy(&mut reader, &mut writer).expect("append extension payload chunk"); - } - } - - let files = collect_files(&payload).expect("collect reconstructed extension payload files"); - if files.is_empty() { - panic!("Oliphaunt extension payload part crates produced no files"); - } - let manifest = out_dir.join("oliphaunt-artifact.toml"); - let mut text = format!( - "schema = {SCHEMA:?}\nproduct = {PRODUCT:?}\nversion = {VERSION:?}\nkind = {KIND:?}\ntarget = {TARGET:?}\nruntime-product = {RUNTIME_PRODUCT:?}\nruntime-version = {RUNTIME_VERSION:?}\n" - ); - if SCHEMA == "oliphaunt-artifact-manifest-v1" { - if EXTENSIONS.len() != 1 { - panic!("v1 extension manifest requires exactly one member"); - } - text.push_str(&format!("extension = {:?}\n", EXTENSIONS[0])); - append_dependencies(&mut text, EXTENSIONS[0]); - append_manifest_files(&mut text, &payload, "[[files]]"); - } else if SCHEMA == "oliphaunt-artifact-manifest-v2" { - let extensions_root = payload.join("extensions"); - let actual_members = directory_names(&extensions_root).expect("read reconstructed extension bundle members"); - let expected_members: Vec = EXTENSIONS.iter().map(|value| (*value).to_owned()).collect(); - if actual_members != expected_members { - panic!("reconstructed extension bundle member set mismatch: expected {expected_members:?}, got {actual_members:?}"); - } - for extension in EXTENSIONS { - text.push_str(&format!("\n[[extensions]]\nextension = {extension:?}\n")); - append_dependencies(&mut text, extension); - append_manifest_files(&mut text, &extensions_root.join(extension), "[[extensions.files]]"); - } - } else { - panic!("unsupported extension artifact manifest schema {SCHEMA}"); - } - fs::write(&manifest, text).expect("write Oliphaunt extension artifact manifest"); - println!("cargo::metadata=manifest={}", manifest.display()); -} - -fn append_dependencies(text: &mut String, extension: &str) { - let dependencies = EXTENSION_DEPENDENCIES.iter() - .find(|(candidate, _)| *candidate == extension) - .map(|(_, dependencies)| *dependencies) - .unwrap_or_else(|| panic!("missing dependency metadata for extension {extension}")); - text.push_str(&format!("dependencies = {dependencies:?}\n")); -} - -fn append_manifest_files(text: &mut String, root: &Path, table: &str) { - let files = collect_files(root).expect("collect extension member payload files"); - if files.is_empty() { - panic!("Oliphaunt extension member payload produced no files under {}", root.display()); - } - for file in files { - let relative = file.strip_prefix(root) - .expect("payload file stays under member root") - .to_string_lossy() - .replace(std::path::MAIN_SEPARATOR, "/"); - let sha256 = sha256_file(&file).expect("hash extension payload file"); - text.push_str(&format!( - "\n{table}\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = false\n", - file.display().to_string(), relative, sha256, - )); - } -} - -fn directory_names(root: &Path) -> io::Result> { - let mut names = Vec::new(); - for entry in fs::read_dir(root)? { - let entry = entry?; - if entry.file_type()?.is_dir() { - names.push(entry.file_name().to_string_lossy().into_owned()); - } - } - names.sort(); - Ok(names) -} - -fn part_roots() -> Vec { - PART_ROOTS.iter().map(PathBuf::from).collect() -} - -fn copy_complete_files(source: &Path, destination: &Path) -> io::Result<()> { - if !source.is_dir() { - return Ok(()); - } - for entry in fs::read_dir(source)? { - let entry = entry?; - let path = entry.path(); - let output = destination.join(path.strip_prefix(source).unwrap_or(&path)); - copy_tree_entry(&path, &output)?; - } - Ok(()) -} - -fn copy_tree_entry(source: &Path, destination: &Path) -> io::Result<()> { - let metadata = fs::metadata(source)?; - if metadata.is_dir() { - fs::create_dir_all(destination)?; - for entry in fs::read_dir(source)? { - let entry = entry?; - copy_tree_entry(&entry.path(), &destination.join(entry.file_name()))?; - } - } else if metadata.is_file() { - if let Some(parent) = destination.parent() { - fs::create_dir_all(parent)?; - } - fs::copy(source, destination)?; - } - Ok(()) -} - -fn collect_chunks( - root: &Path, - current: &Path, - chunks: &mut BTreeMap>, -) -> io::Result<()> { - if !current.is_dir() { - return Ok(()); - } - for entry in fs::read_dir(current)? { - let entry = entry?; - let path = entry.path(); - let metadata = fs::metadata(&path)?; - if metadata.is_dir() { - collect_chunks(root, &path, chunks)?; - continue; - } - if !metadata.is_file() { - continue; - } - let relative = path.strip_prefix(root).unwrap_or(&path).to_string_lossy().replace(std::path::MAIN_SEPARATOR, "/"); - let (file_relative, part_index) = split_part_relative(&relative) - .unwrap_or_else(|| panic!("invalid Oliphaunt extension chunk file name {relative}")); - chunks.entry(file_relative).or_default().push((part_index, path)); - } - Ok(()) -} - -fn split_part_relative(relative: &str) -> Option<(String, usize)> { - let (file, index) = relative.rsplit_once(".part")?; - if file.is_empty() || index.len() != 3 || !index.bytes().all(|byte| byte.is_ascii_digit()) { - return None; - } - Some((file.to_owned(), index.parse().ok()?)) -} - -fn collect_files(root: &Path) -> io::Result> { - let mut files = Vec::new(); - collect_files_inner(root, &mut files)?; - files.sort(); - Ok(files) -} - -fn collect_files_inner(path: &Path, files: &mut Vec) -> io::Result<()> { - if !path.is_dir() { - return Ok(()); - } - for entry in fs::read_dir(path)? { - let entry = entry?; - let entry_path = entry.path(); - let metadata = fs::metadata(&entry_path)?; - if metadata.is_dir() { - collect_files_inner(&entry_path, files)?; - } else if metadata.is_file() { - files.push(entry_path); - } - } - Ok(()) -} - -${RUST_BUILD_SCRIPT_SHA256} -`; - -export function exactNativeExtensionMemberDependencies(members, memberDependencies) { - if ( - !Array.isArray(members) || - members.length === 0 || - members.some((member) => typeof member !== "string" || member.length === 0) || - new Set(members).size !== members.length - ) { - throw new Error(`${TOOL}: native extension members must be a non-empty, unique string list`); - } - if (memberDependencies === null || typeof memberDependencies !== "object" || Array.isArray(memberDependencies)) { - throw new Error(`${TOOL}: native extension member dependencies must be an object keyed by every exact member`); - } - - const expectedMembers = [...members].sort(compareText); - const actualMembers = Object.keys(memberDependencies).sort(compareText); - const missing = expectedMembers.filter((member) => !Object.hasOwn(memberDependencies, member)); - const extra = actualMembers.filter((member) => !expectedMembers.includes(member)); - if (missing.length > 0 || extra.length > 0) { - throw new Error( - `${TOOL}: native extension member dependency keys must exactly match members; missing=${JSON.stringify(missing)}, extra=${JSON.stringify(extra)}`, - ); - } - - return members.map((member) => { - const dependencies = memberDependencies[member]; - if ( - !Array.isArray(dependencies) || - dependencies.some((dependency) => typeof dependency !== "string" || dependency.length === 0) - ) { - throw new Error(`${TOOL}: native extension member ${member} dependencies must be a string list`); - } - const normalized = [...new Set(dependencies)].sort(compareText); - if (JSON.stringify(normalized) !== JSON.stringify(dependencies) || dependencies.includes(member)) { - throw new Error(`${TOOL}: native extension member ${member} dependencies must be sorted, unique, and exclude itself`); - } - return [member, normalized]; - }); -} - -function writeNativeExtensionSplitAggregatorCrate(crateDir, { - product, - version, - members, - memberDependencies, - target, - triple, - runtimeProduct, - runtimeVersion, - partDirs, -}) { - const legal = nativeExtensionCarrierLegal(product, members, { carriesPayload: false }); - const name = nativeExtensionCargoPackageName(product, target); - const links = nativeExtensionCargoLinksName(product, target); - const subject = members.length === 1 ? members[0] : `${members.length}-member bundle`; - const dependencyRows = exactNativeExtensionMemberDependencies(members, memberDependencies); - rmSync(path.join(crateDir, "payload"), { recursive: true, force: true }); - const dependencyLines = []; - const partRoots = []; - for (let offset = 0; offset < partDirs.length; offset += 1) { - const dependencyName = nativeExtensionCargoPartPackageName(product, target, offset + 1); - const dependencyPath = path.relative(crateDir, partDirs[offset]).split(path.sep).join("/"); - dependencyLines.push(`${dependencyName} = { version = "=${version}", path = "${dependencyPath}" }`); - partRoots.push(` ${rustCrateIdent(dependencyName)}::PAYLOAD_ROOT,`); - } - writeFileSync( - path.join(crateDir, "Cargo.toml"), - `[package] -name = "${name}" -version = "${version}" -edition = "2024" -rust-version = "1.93" -description = "Cargo artifact crate for the ${subject} Oliphaunt native extension carrier on ${target}." -readme = "README.md" -repository = "https://github.com/f0rr0/oliphaunt" -homepage = "https://oliphaunt.dev" -license = ${tomlString(legal.packageSpdx)} -links = "${links}" -build = "build.rs" -include = ${tomlString(["Cargo.toml", "README.md", "build.rs", "src/**", ...carrierLegalMembers(legal)])} - -[lib] -path = "src/lib.rs" - -[build-dependencies] -${dependencyLines.join("\n")} - -[workspace] -`, - ); - writeFileSync( - path.join(crateDir, "build.rs"), - NATIVE_EXTENSION_AGGREGATOR_BUILD_RS - .replace("__SCHEMA__", tomlString(members.length > 1 ? "oliphaunt-artifact-manifest-v2" : "oliphaunt-artifact-manifest-v1")) - .replace("__PRODUCT__", tomlString(product)) - .replace("__TARGET__", tomlString(triple)) - .replace("__RUNTIME_PRODUCT__", tomlString(runtimeProduct)) - .replace("__RUNTIME_VERSION__", tomlString(runtimeVersion)) - .replace("__EXTENSIONS__", members.map((member) => ` ${tomlString(member)},`).join("\n")) - .replace("__EXTENSION_DEPENDENCIES__", dependencyRows.map(([member, dependencies]) => ` (${tomlString(member)}, &[${dependencies.map((dependency) => tomlString(dependency)).join(", ")}]),`).join("\n")) - .replace("__PART_ROOTS__", partRoots.join("\n")), - ); - stageExtensionCarrierLegal(crateDir, legal); - return legal; -} - -function cargoPackage(crateDir, targetDir, legal, { noVerify = false } = {}) { - const manifest = path.join(crateDir, "Cargo.toml"); - const { name, version } = readCargoPackageNameVersion(manifest, { fail: localFail, rel }); - const command = [ - "cargo", - "package", - "--manifest-path", - manifest, - "--target-dir", - targetDir, - "--allow-dirty", - ]; - if (noVerify) { - command.push("--no-verify"); - } - const invocation = packageCommandInvocation(command[0], command.slice(1), { cwd: ROOT }); - const result = nodeSpawnSync(invocation.command, invocation.args, { - cwd: invocation.cwd ?? ROOT, - env: { ...process.env, OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD: "1" }, - shell: invocation.shell, - stdio: "inherit", - }); - if (result.error) { - fail(TOOL, `${command[0]} failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - fail(TOOL, `${command[0]} failed with exit code ${result.status ?? 1}`); - } - const cargoCratePath = path.join(targetDir, "package", `${name}-${version}.crate`); - if (!isFile(cargoCratePath)) { - fail(TOOL, `cargo package did not create ${rel(cargoCratePath)}`); - } - // Cargo's tar writer may choose GNU LongLink records for paths that fit in - // ustar's prefix/name fields. Re-materialize the already verified source as - // the repository's strict deterministic ustar so the final carrier can be - // parsed and validated without accepting link-like extension records. - let cratePath; - try { - cratePath = manualCargoPackageSource( - manifest, - path.join(targetDir, "strict-package", name), - { - root: ROOT, - fail: localFail, - rel, - // The caller uses the strict package's actual size to decide whether to - // split. Do not let the generic 10 MiB guard preempt that role-aware path. - packageSizeLimitBytes: Number.MAX_SAFE_INTEGER, - }, - ); - assertExtensionCarrierArchive(cratePath, legal, `${name}-${version}`); - } finally { - // `cargo package` is the verifier here, while `cratePath` is the one - // deterministic archive eligible for publication. Cargo also retains a - // byte-distinct copy under package/tmp-crate in addition to its ordinary - // package archive and expanded verification tree. The complete package - // subtree is transient and dedicated to this target directory, so remove - // it rather than trying to enumerate Cargo's internal paths. - rmSync(path.join(targetDir, "package"), { recursive: true, force: true }); - } - return cratePath; -} - -function discardCargoPackageArtifact(cratePath) { - // manualCargoPackageSource gives each generated crate a dedicated output - // directory containing the archive and its verification stage. - rmSync(path.dirname(cratePath), { recursive: true, force: true }); -} - -function stageNativeExtensionCargoPayload(crateDir, runtimeSet, { target, nativeRuntimeVersion }) { - const payload = path.join(crateDir, "payload"); - rmSync(payload, { recursive: true, force: true }); - if (!runtimeSet.bundle) { - extractExtensionRuntime(runtimeSet.members[0].archive, payload, { - metadata: runtimeSet.members[0].metadata, - target, - nativeRuntimeVersion, - }); - return payload; - } - const temp = archiveTempDir(); - try { - for (const member of runtimeSet.members) { - const archive = materializeBundleMemberArchive( - runtimeSet, - member, - path.join(temp, `${member.sqlName}.tar.gz`), - ); - extractExtensionRuntime(archive, path.join(payload, "extensions", member.sqlName), { - metadata: member.metadata, - target, - nativeRuntimeVersion, - }); - } - } finally { - rmSync(temp, { recursive: true, force: true }); - } - return payload; -} - -function writeNativeExtensionCargoCrate(crateDir, { - product, - version, - members, - memberDependencies, - target, - triple, - runtimeProduct, - runtimeVersion, - runtimeSet, -}) { - const legal = nativeExtensionCarrierLegal(product, members, { target, carriesPayload: true }); - const name = nativeExtensionCargoPackageName(product, target); - const links = nativeExtensionCargoLinksName(product, target); - const subject = members.length === 1 ? members[0] : `${members.length}-member bundle`; - const dependencyRows = exactNativeExtensionMemberDependencies(members, memberDependencies); - const runtimeDir = stageNativeExtensionCargoPayload(crateDir, runtimeSet, { - target, - nativeRuntimeVersion: runtimeVersion, - }); - if (walkFiles(runtimeDir).length === 0) { - throw new Error(`${product}@${version} did not contain extension runtime files`); - } - mkdirSync(path.join(crateDir, "src"), { recursive: true }); - writeFileSync( - path.join(crateDir, "README.md"), - `# ${name} - -Cargo artifact crate for the ${subject} Oliphaunt native extension carrier on \`${target}\`. -`, - ); - writeFileSync( - path.join(crateDir, "Cargo.toml"), - `[package] -name = "${name}" -version = "${version}" -edition = "2024" -rust-version = "1.93" -description = "Cargo artifact crate for the ${subject} Oliphaunt native extension carrier on ${target}." -readme = "README.md" -repository = "https://github.com/f0rr0/oliphaunt" -homepage = "https://oliphaunt.dev" -license = ${tomlString(legal.packageSpdx)} -links = "${links}" -build = "build.rs" -include = ${tomlString(["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**", ...carrierLegalMembers(legal)])} - -[lib] -path = "src/lib.rs" - -[workspace] -`, - ); - writeFileSync( - path.join(crateDir, "src/lib.rs"), - `pub const PRODUCT: &str = "${product}"; -pub const KIND: &str = "extension"; -pub const MEMBERS: &[&str] = &[${members.map((member) => JSON.stringify(member)).join(", ")}]; -pub const RELEASE_TARGET: &str = "${target}"; -pub const CARGO_TARGET: &str = "${triple}"; -`, - ); - writeFileSync( - path.join(crateDir, "build.rs"), - `use std::env; -use std::fs; -use std::io::{self, Read}; -use std::path::{Path, PathBuf}; - -const SCHEMA: &str = ${JSON.stringify(members.length > 1 ? "oliphaunt-artifact-manifest-v2" : "oliphaunt-artifact-manifest-v1")}; -const PRODUCT: &str = ${JSON.stringify(product)}; -const VERSION: &str = env!("CARGO_PKG_VERSION"); -const KIND: &str = "extension"; -const TARGET: &str = ${JSON.stringify(triple)}; -const RUNTIME_PRODUCT: &str = ${JSON.stringify(runtimeProduct)}; -const RUNTIME_VERSION: &str = ${JSON.stringify(runtimeVersion)}; -const EXTENSIONS: &[&str] = &[${members.map((member) => JSON.stringify(member)).join(", ")}]; -const EXTENSION_DEPENDENCIES: &[(&str, &[&str])] = &[${dependencyRows.map(([member, dependencies]) => `(${JSON.stringify(member)}, &[${dependencies.map((dependency) => JSON.stringify(dependency)).join(", ")}])`).join(", ")}]; - -fn main() { - let manifest_dir = - PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set")); - let payload = manifest_dir.join("payload"); - println!("cargo::rerun-if-changed={}", payload.display()); - if !payload.is_dir() { - if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() { - panic!("missing packaged extension payload under {}", payload.display()); - } - return; - } - let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set")); - let manifest = out_dir.join("oliphaunt-artifact.toml"); - let mut text = format!( - "schema = {SCHEMA:?}\\nproduct = {PRODUCT:?}\\nversion = {VERSION:?}\\nkind = {KIND:?}\\ntarget = {TARGET:?}\\nruntime-product = {RUNTIME_PRODUCT:?}\\nruntime-version = {RUNTIME_VERSION:?}\\n" - ); - if SCHEMA == "oliphaunt-artifact-manifest-v1" { - if EXTENSIONS.len() != 1 { panic!("v1 extension manifest requires exactly one member"); } - text.push_str(&format!("extension = {:?}\\n", EXTENSIONS[0])); - append_dependencies(&mut text, EXTENSIONS[0]); - append_manifest_files(&mut text, &payload, "[[files]]"); - } else { - let extensions_root = payload.join("extensions"); - let mut actual_members: Vec = fs::read_dir(&extensions_root) - .expect("read extension bundle members") - .filter_map(|entry| entry.ok()) - .filter(|entry| entry.file_type().map(|kind| kind.is_dir()).unwrap_or(false)) - .map(|entry| entry.file_name().to_string_lossy().into_owned()) - .collect(); - actual_members.sort(); - let expected_members: Vec = EXTENSIONS.iter().map(|value| (*value).to_owned()).collect(); - if actual_members != expected_members { - panic!("extension bundle member set mismatch: expected {expected_members:?}, got {actual_members:?}"); - } - for extension in EXTENSIONS { - text.push_str(&format!("\\n[[extensions]]\\nextension = {extension:?}\\n")); - append_dependencies(&mut text, extension); - append_manifest_files(&mut text, &extensions_root.join(extension), "[[extensions.files]]"); - } - } - fs::write(&manifest, text).expect("write Oliphaunt extension artifact manifest"); - println!("cargo::metadata=manifest={}", manifest.display()); -} - -fn append_dependencies(text: &mut String, extension: &str) { - let dependencies = EXTENSION_DEPENDENCIES.iter() - .find(|(candidate, _)| *candidate == extension) - .map(|(_, dependencies)| *dependencies) - .unwrap_or_else(|| panic!("missing dependency metadata for extension {extension}")); - text.push_str(&format!("dependencies = {dependencies:?}\\n")); -} - -fn append_manifest_files(text: &mut String, root: &Path, table: &str) { - let files = payload_files(root); - if files.is_empty() { panic!("empty extension payload under {}", root.display()); } - for file in files { - let relative = file - .strip_prefix(root) - .expect("payload file stays under member root") - .to_string_lossy() - .replace(std::path::MAIN_SEPARATOR, "/"); - let sha256 = sha256_file(&file).expect("hash payload file"); - text.push_str(&format!( - "\\n{table}\\nsource = {:?}\\nrelative = {:?}\\nsha256 = {sha256:?}\\nexecutable = false\\n", - file.display().to_string(), - relative, - )); - } -} - -fn payload_files(root: &Path) -> Vec { - let mut files = Vec::new(); - collect_payload_files(root, &mut files); - files.sort(); - files -} - -fn collect_payload_files(root: &Path, files: &mut Vec) { - for entry in fs::read_dir(root).expect("read payload directory") { - let path = entry.expect("read payload entry").path(); - if path.is_dir() { - collect_payload_files(&path, files); - } else if path.is_file() { - files.push(path); - } - } -} - -${RUST_BUILD_SCRIPT_SHA256} -`, - ); - stageExtensionCarrierLegal(crateDir, legal); - return legal; -} - -export function packageNativeExtensionCargoCrates(roots, stagingRoot, target, strict, result) { - if (target === null) { - result.skipped.push("current host does not map to a supported native extension Cargo target"); - return []; - } - const triple = cargoTargetTriple(target); - if (triple === null) { - result.skipped.push(`unsupported native extension Cargo target ${target}`); - return []; - } - const manifests = discoverExtensionManifests(roots); - if (manifests.length === 0) { - result.skipped.push("no extension-artifacts.json manifests found for native extension Cargo crates"); - return []; - } - - const sourceRoot = path.join(stagingRoot, "native-extension-sources"); - const outputDir = path.join(stagingRoot, "native-extension-crates"); - const cargoTargetDir = path.join(stagingRoot, "native-extension-cargo-target"); - rmSync(sourceRoot, { recursive: true, force: true }); - rmSync(outputDir, { recursive: true, force: true }); - rmSync(cargoTargetDir, { recursive: true, force: true }); - mkdirSync(sourceRoot, { recursive: true }); - mkdirSync(outputDir, { recursive: true }); - - const outputs = []; - const packageOptions = { root: ROOT, fail: localFail, rel }; - const stagedIdentities = new Map(); - try { - for (const manifestPath of manifests) { - const manifest = readJsonFile(manifestPath); - const extensionDir = path.dirname(manifestPath); - const { product, version } = manifest; - const memberRows = extensionManifestMembers(manifest); - const members = memberRows.map((member) => member.sqlName); - if (![product, version].every((value) => typeof value === "string" && value.length > 0) || members.length === 0) { - result.skipped.push(`${rel(manifestPath)} is missing product, version, or exact member rows`); - continue; - } - const memberDependencies = Object.fromEntries(memberRows.map((member) => { - if (!Array.isArray(member.dependencies) || member.dependencies.some((dependency) => typeof dependency !== "string" || !dependency)) { - fail(TOOL, `${product}@${version} member ${member.sqlName} has invalid dependency metadata`); - } - const dependencies = [...new Set(member.dependencies)].sort(compareText); - if (JSON.stringify(dependencies) !== JSON.stringify(member.dependencies) || dependencies.includes(member.sqlName)) { - fail(TOOL, `${product}@${version} member ${member.sqlName} dependencies must be sorted, unique, and exclude itself`); - } - return [member.sqlName, dependencies]; - })); - const releaseManifest = extensionReleaseManifest(extensionDir, product, version); - const runtimeSet = extensionRuntimeAssets( - extensionDir, - manifest, - releaseManifest, - target, - ); - if (runtimeSet === null) { - result.skipped.push(`${product}@${version} has no complete ${target} native runtime member set`); - continue; - } - const runtimeProduct = runtimeSet.compatibility.nativeRuntimeProduct; - const runtimeVersion = runtimeSet.compatibility.nativeRuntimeVersion; - const identity = `${product}@${version}:${target}`; - const digest = JSON.stringify({ - compatibility: runtimeSet.compatibility, - members: runtimeSet.members.map(({ metadata: inventory, asset }) => ({ - inventory, - sha256: asset.sha256, - bytes: asset.bytes, - })), - carrier: runtimeSet.carrier === undefined - ? null - : { sha256: runtimeSet.carrier.sha256, bytes: runtimeSet.carrier.bytes }, - }); - if (stagedIdentities.has(identity)) { - if (stagedIdentities.get(identity) !== digest) { - fail(TOOL, `conflicting native extension Cargo packages discovered for ${identity}`); - } - result.skipped.push(`deduplicated byte-identical native extension Cargo package ${identity}`); - continue; - } - stagedIdentities.set(identity, digest); - const name = nativeExtensionCargoPackageName(product, target); - const crateDir = path.join(sourceRoot, name); - try { - const crateLegal = writeNativeExtensionCargoCrate(crateDir, { - product, - version, - members, - memberDependencies, - target, - triple, - runtimeProduct, - runtimeVersion, - runtimeSet, - }); - let cratePath = cargoPackage(crateDir, cargoTargetDir, crateLegal); - let size = statSync(cratePath).size; - if (size > CARGO_EXTENSION_SPLIT_THRESHOLD_BYTES) { - discardCargoPackageArtifact(cratePath); - const partDirs = buildNativeExtensionPartCrates(path.join(crateDir, "payload"), sourceRoot, { - product, - version, - members, - memberDependencies, - target, - }); - const partLegal = nativeExtensionCarrierLegal(product, members, { target, carriesPayload: true }); - const aggregatorLegal = writeNativeExtensionSplitAggregatorCrate(crateDir, { - product, - version, - members, - memberDependencies, - target, - triple, - runtimeProduct, - runtimeVersion, - partDirs, - }); - let partFailed = false; - for (const partDir of partDirs) { - const partCratePath = cargoPackage(partDir, cargoTargetDir, partLegal); - const partSize = statSync(partCratePath).size; - if (partSize > CARGO_PACKAGE_SIZE_LIMIT_BYTES) { - const message = `${rel(partCratePath)} is ${partSize} bytes, above the crates.io 10 MiB package limit`; - result.skipped.push(message); - if (strict) { - fail(TOOL, message); - } - partFailed = true; - continue; - } - const output = path.join(outputDir, path.basename(partCratePath)); - copyFileSync(partCratePath, output); - outputs.push(output); - } - if (partFailed) { - continue; - } - cratePath = manualCargoPackageSource( - path.join(crateDir, "Cargo.toml"), - path.join(cargoTargetDir, "manual-package"), - packageOptions, - ); - assertExtensionCarrierArchive( - cratePath, - aggregatorLegal, - path.basename(cratePath, ".crate"), - ); - size = statSync(cratePath).size; - if (size > CARGO_PACKAGE_SIZE_LIMIT_BYTES) { - const message = `${rel(cratePath)} is ${size} bytes after splitting, above the crates.io 10 MiB package limit`; - result.skipped.push(message); - if (strict) { - fail(TOOL, message); - } - continue; - } - if (partDirs.length === 0 || partDirs.length > 999) { - fail(TOOL, `${product}@${version} generated invalid Cargo payload part count ${partDirs.length}`); - } - } - if (size > CARGO_PACKAGE_SIZE_LIMIT_BYTES) { - fail(TOOL, `${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit`); - } - const output = path.join(outputDir, path.basename(cratePath)); - copyFileSync(cratePath, output); - outputs.push(output); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - result.skipped.push(message); - if (strict) { - throw error; - } - } - } - result.staged.push(...outputs.map(rel)); - return outputs; - } finally { - // Only native-extension-crates is a publication surface. Source and Cargo - // work roots can contain verifier-created .crate files, including - // package/tmp-crate copies whose bytes differ from the deterministic final - // carrier. Removing both work roots in finally keeps success and failure - // staging trees fail-closed for recursive artifact discovery. - rmSync(sourceRoot, { recursive: true, force: true }); - rmSync(cargoTargetDir, { recursive: true, force: true }); - } -} diff --git a/tools/release/package-liboliphaunt-cargo-artifacts.mjs b/tools/release/package-liboliphaunt-cargo-artifacts.mjs deleted file mode 100644 index 936ed0e2f..000000000 --- a/tools/release/package-liboliphaunt-cargo-artifacts.mjs +++ /dev/null @@ -1,1258 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "node:child_process"; -import { createHash } from "node:crypto"; -import { - closeSync, - copyFileSync, - cpSync, - existsSync, - mkdirSync, - openSync, - readdirSync, - readFileSync, - readSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { manualCargoPackageSource } from "./cargo-source-package.mjs"; -import { - ROOT, - allArtifactTargets, - compareText, - currentProductVersion, -} from "./release-artifact-targets.mjs"; -import { - renderUnsupportedNativeTargetGuard, - rustNativeTargetCfg, -} from "./rust-native-targets.mjs"; -import { localWindowsTarInvocation } from "./tar-command.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releaseNoticeRows, - releaseProfilePackageLicense, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { validateNativeIcuDataManifest } from "./native-icu-data-contract.mjs"; -import { validateNativeRuntimeCarrier } from "./native-runtime-carrier-contract.mjs"; - -const PREFIX = "package-liboliphaunt-cargo-artifacts.mjs"; -const PRODUCT = "liboliphaunt-native"; -const KIND = "native-runtime"; -const TOOLS_PRODUCT = "oliphaunt-tools"; -const TOOLS_KIND = "native-tools"; -const TOOLS_FACADE_TEMPLATE = path.join(ROOT, "src/runtimes/liboliphaunt/native/crates/tools"); -const SURFACE = "rust-native-direct"; -const CRATES_IO_MAX_BYTES = 10 * 1024 * 1024; -const DEFAULT_PART_BYTES = 7 * 1024 * 1024; -export const NATIVE_CARGO_CARRIER_LICENSES = Object.freeze({ - "native-runtime": releaseProfilePackageLicense("native-runtime").spdx, - "native-tools": releaseProfilePackageLicense("native-tools").spdx, - "code-facade": releaseProfilePackageLicense("code-facade").spdx, -}); - -const AGGREGATOR_BUILD_RS = String.raw`use std::collections::BTreeMap; -use std::env; -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; - -const SCHEMA: &str = __SCHEMA__; -const PRODUCT: &str = __PRODUCT__; -const VERSION: &str = __VERSION__; -const KIND: &str = __KIND__; -const TARGET: &str = __TARGET__; -const PART_ROOTS: &[&str] = &[ -__PART_ROOTS__ -]; -const FILE_SHA256: &[(&str, &str)] = &[ -__FILE_SHA256__ -]; - -fn main() { - emit_manifest(); -} - -fn emit_manifest() { - let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set")); - let payload = out_dir.join("payload"); - if payload.exists() { - fs::remove_dir_all(&payload).expect("remove stale liboliphaunt native payload"); - } - fs::create_dir_all(&payload).expect("create liboliphaunt native payload directory"); - - let part_roots = part_roots(); - if part_roots.is_empty() { - if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() { - panic!("missing liboliphaunt native payload part crates"); - } - return; - } - - let mut chunk_files: BTreeMap> = BTreeMap::new(); - for root in part_roots { - println!("cargo::rerun-if-changed={}", root.display()); - copy_complete_files(&root.join("files"), &payload).expect("copy complete payload files"); - collect_chunks(&root.join("chunks"), &root.join("chunks"), &mut chunk_files) - .expect("collect payload chunks"); - } - - for (relative, mut chunks) in chunk_files { - chunks.sort_by_key(|(index, _)| *index); - for (expected, (actual, _)) in chunks.iter().enumerate() { - if *actual != expected { - panic!("non-contiguous liboliphaunt chunk indexes for {relative}"); - } - } - let output = payload.join(&relative); - if let Some(parent) = output.parent() { - fs::create_dir_all(parent).expect("create reconstructed file parent"); - } - let mut writer = fs::File::create(&output).expect("create reconstructed payload file"); - for (_, path) in chunks { - let mut reader = fs::File::open(&path).expect("open payload chunk"); - io::copy(&mut reader, &mut writer).expect("append payload chunk"); - } - } - - let files = collect_files(&payload).expect("collect reconstructed liboliphaunt payload files"); - if files.is_empty() { - panic!("liboliphaunt native payload part crates produced no files"); - } - let manifest = out_dir.join("oliphaunt-artifact.toml"); - let mut text = format!( - "schema = {SCHEMA:?}\nproduct = {PRODUCT:?}\nversion = {VERSION:?}\nkind = {KIND:?}\ntarget = {TARGET:?}\n" - ); - if files.len() != FILE_SHA256.len() { - panic!("reconstructed liboliphaunt payload file count does not match the frozen inventory"); - } - for file in files { - let relative = file.strip_prefix(&payload) - .expect("payload file stays under payload root") - .to_string_lossy() - .replace('\\', "/"); - let sha256 = FILE_SHA256.iter() - .find_map(|(candidate, digest)| (*candidate == relative).then_some(*digest)) - .unwrap_or_else(|| panic!("reconstructed liboliphaunt payload has undeclared file {relative}")); - text.push_str(&format!( - "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = {}\n", - file.display().to_string(), - relative, - sha256, - is_executable_relative(&relative), - )); - } - fs::write(&manifest, text).expect("write liboliphaunt native artifact manifest"); - println!("cargo::metadata=manifest={}", manifest.display()); -} - -fn part_roots() -> Vec { - PART_ROOTS.iter().map(PathBuf::from).collect() -} - -fn copy_complete_files(source: &Path, destination: &Path) -> io::Result<()> { - if !source.is_dir() { - return Ok(()); - } - for entry in fs::read_dir(source)? { - let entry = entry?; - let path = entry.path(); - let output = destination.join(path.strip_prefix(source).unwrap_or(&path)); - copy_tree_entry(&path, &output)?; - } - Ok(()) -} - -fn copy_tree_entry(source: &Path, destination: &Path) -> io::Result<()> { - let metadata = fs::metadata(source)?; - if metadata.is_dir() { - fs::create_dir_all(destination)?; - for entry in fs::read_dir(source)? { - let entry = entry?; - copy_tree_entry(&entry.path(), &destination.join(entry.file_name()))?; - } - } else if metadata.is_file() { - if let Some(parent) = destination.parent() { - fs::create_dir_all(parent)?; - } - fs::copy(source, destination)?; - } - Ok(()) -} - -fn collect_chunks( - root: &Path, - current: &Path, - chunks: &mut BTreeMap>, -) -> io::Result<()> { - if !current.is_dir() { - return Ok(()); - } - for entry in fs::read_dir(current)? { - let entry = entry?; - let path = entry.path(); - let metadata = fs::metadata(&path)?; - if metadata.is_dir() { - collect_chunks(root, &path, chunks)?; - continue; - } - if !metadata.is_file() { - continue; - } - let relative = path.strip_prefix(root).unwrap_or(&path).to_string_lossy().replace('\\', "/"); - let (file_relative, part_index) = split_part_relative(&relative) - .unwrap_or_else(|| panic!("invalid liboliphaunt chunk file name {relative}")); - chunks.entry(file_relative).or_default().push((part_index, path)); - } - Ok(()) -} - -fn split_part_relative(relative: &str) -> Option<(String, usize)> { - let (file, index) = relative.rsplit_once(".part")?; - if file.is_empty() || index.len() != 3 || !index.bytes().all(|byte| byte.is_ascii_digit()) { - return None; - } - Some((file.to_owned(), index.parse().ok()?)) -} - -fn collect_files(root: &Path) -> io::Result> { - let mut files = Vec::new(); - collect_files_inner(root, &mut files)?; - files.sort(); - Ok(files) -} - -fn collect_files_inner(path: &Path, files: &mut Vec) -> io::Result<()> { - if !path.is_dir() { - return Ok(()); - } - for entry in fs::read_dir(path)? { - let entry = entry?; - let entry_path = entry.path(); - let metadata = fs::metadata(&entry_path)?; - if metadata.is_dir() { - collect_files_inner(&entry_path, files)?; - } else if metadata.is_file() { - files.push(entry_path); - } - } - Ok(()) -} - -fn is_executable_relative(relative: &str) -> bool { - relative.starts_with("runtime/bin/") || relative.starts_with("bin/") -} -`; - -function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(1); -} - -function rel(file) { - const relative = path.relative(ROOT, String(file)); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - return String(file).split(path.sep).join("/"); - } - return relative.split(path.sep).join("/"); -} - -function repoPath(value) { - return path.isAbsolute(value) ? value : path.join(ROOT, value); -} - -function run(args, { env = process.env, capture = false, cwd = ROOT } = {}) { - const invocation = args[0] === "tar" - ? localWindowsTarInvocation(args.slice(1), { cwd }) - : { args: args.slice(1), cwd }; - console.log(`\n==> ${args.join(" ")}`); - const result = capture - ? captureCommandOutput(args[0], invocation.args, { - cwd: invocation.cwd, - env, - label: args.join(" "), - maxOutputBytes: 256 * 1024 * 1024, - }) - : spawnSync(args[0], invocation.args, { - cwd: invocation.cwd, - env, - stdio: "inherit", - }); - if (result.error !== undefined) { - fail(`${args[0]} failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - if (capture) { - process.stderr.write(result.stderr ?? ""); - } - process.exit(result.status ?? 1); - } - return capture ? result.stdout : ""; -} - -function isFile(file) { - try { - return statSync(file).isFile(); - } catch { - return false; - } -} - -function isDirectory(file) { - try { - return statSync(file).isDirectory(); - } catch { - return false; - } -} - -function cargoPackageName(targetId, { packageBase = PRODUCT } = {}) { - return `${packageBase}-${targetId}`; -} - -function cargoLinksName(targetId, { artifactProduct = PRODUCT } = {}) { - return `oliphaunt_artifact_${artifactProduct.replaceAll("-", "_")}_${targetId.replaceAll("-", "_")}`; -} - -function partPackageName(targetId, index, { packageBase = PRODUCT } = {}) { - if (!Number.isSafeInteger(index) || index < 1 || index > 999) { - fail(`Cargo payload part number must be an integer from 1 through 999, got ${JSON.stringify(index)}`); - } - return `${cargoPackageName(targetId, { packageBase })}-part-${String(index).padStart(3, "0")}`; -} - -function partLinksName(targetId, index, { artifactProduct = PRODUCT } = {}) { - if (!Number.isSafeInteger(index) || index < 1 || index > 999) { - fail(`Cargo payload part number must be an integer from 1 through 999, got ${JSON.stringify(index)}`); - } - return `oliphaunt_artifact_part_${artifactProduct.replaceAll("-", "_")}_${targetId.replaceAll("-", "_")}_${String(index).padStart(3, "0")}`; -} - -function rustCrateIdent(crateName) { - return crateName.replaceAll("-", "_"); -} - -function tomlString(value) { - return JSON.stringify(value); -} - -function cargoIncludeMembers(profile, baseMembers) { - return JSON.stringify([ - ...baseMembers, - ...releaseNoticeRows({ profile }).map((row) => row.member), - ]); -} - -function artifactAssetName(target, version) { - return target.asset.replaceAll("{version}", version); -} - -function checkedMemberPath(name, archive) { - const normalized = name.replaceAll("\\", "/"); - if (!normalized || normalized === "." || normalized === "./" || normalized.startsWith("/") || normalized.includes("\0")) { - fail(`${rel(archive)} contains unsafe archive member ${JSON.stringify(name)}`); - } - const parts = normalized.split("/").filter((part) => part && part !== "."); - if (parts.length === 0 || parts.includes("..")) { - fail(`${rel(archive)} contains unsafe archive member ${JSON.stringify(name)}`); - } - return parts.join("/"); -} - -function archiveNames(archive) { - const command = archive.endsWith(".zip") ? ["unzip", "-Z1", archive] : ["tar", "-tf", archive]; - const output = run(command, { capture: true }); - return output.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean); -} - -function extractArchive(archive, destination) { - rmSync(destination, { recursive: true, force: true }); - mkdirSync(destination, { recursive: true }); - for (const name of archiveNames(archive)) { - if (name === "." || name === "./" || name.endsWith("/")) { - continue; - } - checkedMemberPath(name, archive); - } - const command = archive.endsWith(".zip") - ? ["unzip", "-qq", archive, "-d", destination] - : ["tar", "-xf", archive, "-C", destination]; - run(command); -} - -export function nativePayloadPlatformCommand(payloadRoot, target, { toolSet }) { - const platformCommand = [ - process.execPath, - "tools/release/platform-binary-contract.mjs", - "--target", - target, - "--root", - payloadRoot, - ]; - if (target === "windows-x64-msvc" && toolSet === "runtime") { - platformCommand.push( - "--require-windows-runtime-import-library", - "--windows-vc-runtime-profile", - "provider", - ); - } - return platformCommand; -} - -function validateNativePayload(payloadRoot, target, { toolSet }) { - run(nativePayloadPlatformCommand(payloadRoot, target, { toolSet })); - run([ - process.execPath, - "tools/release/optimize_native_runtime_payload.mjs", - payloadRoot, - "--target", - target, - "--tool-set", - toolSet, - "--check", - ]); -} - -function validateNativeCargoRuntimeClosure(runtimeRoot, target, icuRoot) { - const icuData = path.join(icuRoot, "share/icu"); - try { - const { target: actualTarget } = validateNativeRuntimeCarrier(runtimeRoot, { icuData }); - if (actualTarget !== target) { - fail(`${rel(runtimeRoot)} carries ${actualTarget} cluster seeds, expected ${target}`); - } - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} - -function writePartCrate( - crateDir, - { - targetId, - index, - version, - packageBase, - artifactProduct, - artifactLabel, - noticeProfile, - }, -) { - rmSync(crateDir, { recursive: true, force: true }); - const name = partPackageName(targetId, index, { packageBase }); - const links = partLinksName(targetId, index, { artifactProduct }); - mkdirSync(path.join(crateDir, "src"), { recursive: true }); - writeFileSync( - path.join(crateDir, "Cargo.toml"), - `[package] -name = "${name}" -version = "${version}" -edition = "2024" -rust-version = "1.93" -description = "Cargo payload part ${String(index).padStart(3, "0")} for the ${targetId} ${artifactLabel}." -readme = "README.md" -repository = "https://github.com/f0rr0/oliphaunt" -homepage = "https://oliphaunt.dev" -license = "${NATIVE_CARGO_CARRIER_LICENSES[noticeProfile]}" -links = "${links}" -build = "build.rs" -include = ${cargoIncludeMembers(noticeProfile, ["Cargo.toml", "README.md", "build.rs", "src/**", "payload/**"])} - -[lib] -path = "src/lib.rs" - -[workspace] -`, - ); - writeFileSync( - path.join(crateDir, "README.md"), - `# ${name} - -Cargo payload part for the \`${targetId}\` ${artifactLabel}. -Applications do not depend on this crate directly. -`, - ); - writeFileSync( - path.join(crateDir, "src/lib.rs"), - `pub const RELEASE_TARGET: &str = "${targetId}"; -pub const PART_INDEX: usize = ${index}; -pub const PAYLOAD_ROOT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/payload"); -`, - ); - writeFileSync( - path.join(crateDir, "build.rs"), - `use std::env; -use std::path::PathBuf; - -fn main() { - let manifest_dir = - PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set")); - let root = manifest_dir.join("payload"); - println!("cargo::rerun-if-changed={}", root.display()); - if !root.is_dir() { - if env::var_os("OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD").is_some() { - panic!("missing packaged Oliphaunt artifact payload under {}", root.display()); - } - return; - } - println!("cargo::metadata=root={}", root.display()); -} -`, - ); - stageReleaseNotices(crateDir, { profile: noticeProfile }); - assertReleaseNoticesInDirectory(crateDir, { profile: noticeProfile }); -} - -function writeAggregatorCrate( - crateDir, - { - target, - version, - partCount, - packageBase, - artifactProduct, - artifactKind, - artifactLabel, - payloadFiles, - }, -) { - rmSync(crateDir, { recursive: true, force: true }); - if (typeof target.triple !== "string" || !target.triple) { - fail(`${target.id} must declare Cargo target triple`); - } - const name = cargoPackageName(target.target, { packageBase }); - const links = cargoLinksName(target.target, { artifactProduct }); - mkdirSync(path.join(crateDir, "src"), { recursive: true }); - const dependencyLines = []; - const partRoots = []; - for (let offset = 0; offset < partCount; offset += 1) { - const partName = partPackageName(target.target, offset + 1, { packageBase }); - dependencyLines.push(`${partName} = { version = "=${version}", path = "../${partName}" }`); - partRoots.push(` ${rustCrateIdent(partName)}::PAYLOAD_ROOT,`); - } - const libraryRelativePath = target.libraryRelativePath ?? ""; - writeFileSync( - path.join(crateDir, "Cargo.toml"), - `[package] -name = "${name}" -version = "${version}" -edition = "2024" -rust-version = "1.93" -description = "Cargo artifact crate for the ${target.target} ${artifactLabel}." -readme = "README.md" -repository = "https://github.com/f0rr0/oliphaunt" -homepage = "https://oliphaunt.dev" -license = "${NATIVE_CARGO_CARRIER_LICENSES["code-facade"]}" -links = "${links}" -build = "build.rs" -include = ${cargoIncludeMembers("code-facade", ["Cargo.toml", "README.md", "build.rs", "src/**"])} - -[lib] -path = "src/lib.rs" - -[build-dependencies] -${dependencyLines.join("\n")} - -[workspace] -`, - ); - writeFileSync( - path.join(crateDir, "README.md"), - `# ${name} - -Cargo artifact crate for the \`${target.target}\` ${artifactLabel}. -Applications do not depend on this crate directly; \`oliphaunt\` selects it for -matching Cargo targets. -`, - ); - writeFileSync( - path.join(crateDir, "src/lib.rs"), - `pub const PRODUCT: &str = "${artifactProduct}"; -pub const KIND: &str = "${artifactKind}"; -pub const RELEASE_TARGET: &str = "${target.target}"; -pub const CARGO_TARGET: &str = "${target.triple}"; -pub const LIBRARY_RELATIVE_PATH: &str = "${libraryRelativePath}"; -`, - ); - writeFileSync( - path.join(crateDir, "build.rs"), - AGGREGATOR_BUILD_RS - .replace("__SCHEMA__", tomlString("oliphaunt-artifact-manifest-v1")) - .replace("__PRODUCT__", tomlString(artifactProduct)) - .replace("__VERSION__", tomlString(version)) - .replace("__KIND__", tomlString(artifactKind)) - .replace("__TARGET__", tomlString(target.triple)) - .replace("__PART_ROOTS__", partRoots.join("\n")) - .replace("__FILE_SHA256__", payloadFiles.map(({ relative, sha256 }) => ` (${tomlString(relative)}, ${tomlString(sha256)}),`).join("\n")), - ); - stageReleaseNotices(crateDir, { profile: "code-facade" }); - assertReleaseNoticesInDirectory(crateDir, { profile: "code-facade" }); -} - -function walkFiles(root) { - const files = []; - const visit = (current) => { - if (!existsSync(current)) { - return; - } - for (const entry of readdirSync(current, { withFileTypes: true })) { - const file = path.join(current, entry.name); - if (entry.isDirectory()) { - visit(file); - } else if (entry.isFile()) { - files.push(file); - } - } - }; - visit(root); - return files.sort(compareText); -} - -function frozenPayloadFiles(root) { - return walkFiles(root).map((file) => ({ - relative: path.relative(root, file).split(path.sep).join("/"), - sha256: createHash("sha256").update(readFileSync(file)).digest("hex"), - })); -} - -function nextPartDir( - sourceRoot, - targetId, - index, - version, - { - packageBase, - artifactProduct, - artifactLabel, - noticeProfile, - }, -) { - const crateDir = path.join(sourceRoot, partPackageName(targetId, index, { packageBase })); - writePartCrate(crateDir, { - targetId, - index, - version, - packageBase, - artifactProduct, - artifactLabel, - noticeProfile, - }); - return crateDir; -} - -function writeChunk(file, data) { - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, data); -} - -function copyPayloadFile(source, destination) { - mkdirSync(path.dirname(destination), { recursive: true }); - copyFileSync(source, destination); -} - -function buildPartCrates( - extractedRoot, - sourceRoot, - { - targetId, - version, - partBytes, - packageBase, - artifactProduct, - artifactLabel, - noticeProfile, - }, -) { - const partDirs = []; - let currentDir; - let currentSize = 0; - const startPart = () => { - const partNumber = partDirs.length + 1; - if (partNumber > 999) { - fail(`${targetId} requires more than 999 ${artifactLabel} part crates`); - } - const partDir = nextPartDir(sourceRoot, targetId, partNumber, version, { - packageBase, - artifactProduct, - artifactLabel, - noticeProfile, - }); - partDirs.push(partDir); - return partDir; - }; - - for (const source of walkFiles(extractedRoot)) { - const relative = path.relative(extractedRoot, source).split(path.sep).join("/"); - const size = statSync(source).size; - if (size > partBytes) { - currentDir = undefined; - currentSize = 0; - const fd = openSync(source, "r"); - try { - let partIndex = 0; - let offset = 0; - while (offset < size) { - const length = Math.min(partBytes, size - offset); - const buffer = Buffer.allocUnsafe(length); - const bytesRead = readSync(fd, buffer, 0, length, offset); - if (bytesRead <= 0) { - break; - } - const partDir = startPart(); - writeChunk( - path.join(partDir, "payload/chunks", `${relative}.part${String(partIndex).padStart(3, "0")}`), - buffer.subarray(0, bytesRead), - ); - offset += bytesRead; - partIndex += 1; - } - } finally { - closeSync(fd); - } - continue; - } - if (currentDir === undefined || currentSize + size > partBytes) { - currentDir = startPart(); - currentSize = 0; - } - copyPayloadFile(source, path.join(currentDir, "payload/files", relative)); - currentSize += size; - } - if (partDirs.length === 0) { - fail(`${targetId} generated no ${artifactLabel} part crates`); - } - return partDirs; -} - -function cargoPackage( - crateDir, - targetDir, - { noVerify = false, index = null, noticeProfile = "code-facade" } = {}, -) { - const manifest = path.join(crateDir, "Cargo.toml"); - const metadata = Bun.TOML.parse(readFileSync(manifest, "utf8")); - const name = metadata?.package?.name; - const version = metadata?.package?.version; - if (typeof name !== "string" || typeof version !== "string") { - fail(`${rel(manifest)} must declare package.name and package.version`); - } - const command = [ - "cargo", - "package", - "--manifest-path", - manifest, - "--target-dir", - targetDir, - "--allow-dirty", - ]; - if (noVerify) { - command.push("--no-verify"); - } - if (index !== null) { - command.push( - "--config", - 'source.crates-io.replace-with="oliphaunt-package-deps"', - "--config", - `source.oliphaunt-package-deps.registry=${JSON.stringify(index)}`, - ); - } - run(command, { env: { ...process.env, OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD: "1" } }); - const cargoCratePath = path.join(targetDir, "package", `${name}-${version}.crate`); - if (!isFile(cargoCratePath)) { - fail(`cargo package did not create ${rel(cargoCratePath)}`); - } - const cratePath = manualCargoPackageSource( - manifest, - path.join(targetDir, "strict-package", name), - { root: ROOT, fail, rel }, - ); - assertReleaseNoticesInArchive(cratePath, { - prefix: `${name}-${version}`, - profile: noticeProfile, - }); - return cratePath; -} - -function validateCrateSize(cratePath) { - const size = statSync(cratePath).size; - if (size > CRATES_IO_MAX_BYTES) { - fail(`${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit`); - } -} - -function crateIndexPath(name) { - const lower = name.toLowerCase(); - if (lower.length === 1) return path.join("1", lower); - if (lower.length === 2) return path.join("2", lower); - if (lower.length === 3) return path.join("3", lower[0], lower); - return path.join(lower.slice(0, 2), lower.slice(2, 4), lower); -} - -function temporaryCargoIndex(packages, directory) { - rmSync(directory, { recursive: true, force: true }); - const cratesDir = path.join(directory, "crates"); - const indexDir = path.join(directory, "index"); - mkdirSync(cratesDir, { recursive: true }); - mkdirSync(indexDir, { recursive: true }); - writeFileSync(path.join(indexDir, "config.json"), `${JSON.stringify({ dl: `file://${cratesDir}/{crate}-{version}.crate` })}\n`); - for (const packageData of packages) { - const crateName = `${packageData.name}-${packageData.version}.crate`; - copyFileSync(packageData.cratePath, path.join(cratesDir, crateName)); - const entry = { - name: packageData.name, - vers: packageData.version, - deps: (packageData.localDependencies ?? []).map((dependency) => ({ - name: dependency.name, - req: dependency.req, - features: [], - optional: false, - default_features: true, - target: dependency.target ?? null, - kind: dependency.kind ?? "normal", - registry: null, - package: null, - })), - features: {}, - features2: null, - cksum: createHash("sha256").update(readFileSync(packageData.cratePath)).digest("hex"), - yanked: false, - links: packageData.links ?? null, - rust_version: "1.93", - v: 2, - }; - const indexFile = path.join(indexDir, crateIndexPath(packageData.name)); - mkdirSync(path.dirname(indexFile), { recursive: true }); - writeFileSync(indexFile, `${JSON.stringify(entry)}\n`); - } - run(["git", "init", "--quiet"], { env: process.env, cwd: indexDir }); - run(["git", "config", "user.name", "Oliphaunt Package Fixture"], { env: process.env, cwd: indexDir }); - run(["git", "config", "user.email", "packages@oliphaunt.invalid"], { env: process.env, cwd: indexDir }); - run(["git", "add", "."], { env: process.env, cwd: indexDir }); - run(["git", "commit", "--quiet", "-m", "package dependency index"], { env: process.env, cwd: indexDir }); - return `file://${indexDir}`; -} - -function freezeSourceCrate(packageData, outputDir, cargoTargetDir, dependencyPackages) { - const index = temporaryCargoIndex( - dependencyPackages, - path.join(cargoTargetDir, "dependency-index", packageData.name), - ); - const generated = cargoPackage(path.dirname(packageData.manifestPath), cargoTargetDir, { - noVerify: true, - index, - noticeProfile: packageData.noticeProfile, - }); - validateCrateSize(generated); - const cratePath = path.join(outputDir, path.basename(generated)); - copyFileSync(generated, cratePath); - return { ...packageData, cratePath }; -} - -function validateToolsTargetPair(runtimeTarget, toolsTarget) { - if (toolsTarget.target !== runtimeTarget.target) { - fail(`${toolsTarget.id} must use target ${runtimeTarget.target}`); - } - if (toolsTarget.triple !== runtimeTarget.triple) { - fail(`${toolsTarget.id} must use Cargo target triple ${runtimeTarget.triple}`); - } -} - -export function renderUnsupportedToolsTargetGuard(nativeTargets, nativeCfgs) { - return renderUnsupportedNativeTargetGuard({ - product: TOOLS_PRODUCT, - nativeTargets, - nativeCfgs, - guidance: "use one of these declared native targets; this package has no portable fallback.", - }); -} - -function writeToolsFacadeCrate(sourceRoot, { version, toolsTargets }) { - const crateDir = path.join(sourceRoot, TOOLS_PRODUCT); - if (existsSync(crateDir)) { - fail(`duplicate generated ${TOOLS_PRODUCT} source crate: ${rel(crateDir)}`); - } - cpSync(TOOLS_FACADE_TEMPLATE, crateDir, { - recursive: true, - filter: (source) => path.basename(source) !== "target", - }); - const cargoToml = path.join(crateDir, "Cargo.toml"); - let text = readFileSync(cargoToml, "utf8"); - text = text - .replace("repository.workspace = true", 'repository = "https://github.com/f0rr0/oliphaunt"') - .replace("homepage.workspace = true", 'homepage = "https://oliphaunt.dev"'); - const versionMatches = text.match(/^version = "[^"]+"$/gm) ?? []; - if (versionMatches.length !== 1) { - fail(`${rel(cargoToml)} must declare exactly one package version`); - } - text = text.replace(/^version = "[^"]+"$/m, `version = "${version}"`); - const dependencyBlocks = []; - const sortedToolsTargets = [...toolsTargets].sort((left, right) => compareText(left.target, right.target)); - const nativeTargets = sortedToolsTargets.map((target) => target.target); - const nativeCfgs = sortedToolsTargets.map((target) => rustNativeTargetCfg(target)); - for (let index = 0; index < sortedToolsTargets.length; index += 1) { - const target = sortedToolsTargets[index]; - const packageName = cargoPackageName(target.target, { packageBase: TOOLS_PRODUCT }); - dependencyBlocks.push( - [ - "", - `[target.'cfg(${nativeCfgs[index]})'.dependencies]`, - `${packageName} = { version = "=${version}", path = "../${packageName}" }`, - ].join("\n"), - ); - } - if (!text.includes("\n[workspace]")) { - text = `${text.trimEnd()}\n\n[workspace]\n`; - } - writeFileSync(cargoToml, `${text.trimEnd()}\n${dependencyBlocks.join("\n")}\n`); - const libRs = path.join(crateDir, "src/lib.rs"); - const releaseOnlyGuard = renderUnsupportedToolsTargetGuard(nativeTargets, nativeCfgs); - writeFileSync( - libRs, - `${readFileSync(libRs, "utf8").trimEnd()}\n\n// Generated release-only native target guard.\n${releaseOnlyGuard}\n`, - ); - stageReleaseNotices(crateDir, { profile: "code-facade" }); - assertReleaseNoticesInDirectory(crateDir, { profile: "code-facade" }); - return { - name: TOOLS_PRODUCT, - version, - manifestPath: cargoToml, - cratePath: null, - target: "portable", - product: TOOLS_PRODUCT, - kind: TOOLS_KIND, - role: "facade", - noticeProfile: "code-facade", - index: null, - links: "oliphaunt_artifact_oliphaunt_tools_relay", - localDependencies: [...toolsTargets].map((target) => ({ - name: cargoPackageName(target.target, { packageBase: TOOLS_PRODUCT }), - req: `=${version}`, - target: `cfg(${rustNativeTargetCfg(target)})`, - })), - }; -} - -function packagePayload( - payloadRoot, - sourceRoot, - outputDir, - cargoTargetDir, - { - target, - version, - partBytes, - packageBase, - artifactProduct, - artifactKind, - artifactLabel, - noticeProfile, - }, -) { - const partDirs = buildPartCrates(payloadRoot, sourceRoot, { - targetId: target.target, - version, - partBytes, - packageBase, - artifactProduct, - artifactLabel, - noticeProfile, - }); - const aggregatorDir = path.join(sourceRoot, cargoPackageName(target.target, { packageBase })); - writeAggregatorCrate(aggregatorDir, { - target, - version, - partCount: partDirs.length, - packageBase, - artifactProduct, - artifactKind, - artifactLabel, - payloadFiles: frozenPayloadFiles(payloadRoot), - }); - - const packages = []; - for (let offset = 0; offset < partDirs.length; offset += 1) { - const partNumber = offset + 1; - const partDir = partDirs[offset]; - const cratePath = cargoPackage(partDir, cargoTargetDir, { noticeProfile }); - validateCrateSize(cratePath); - const output = path.join(outputDir, path.basename(cratePath)); - copyFileSync(cratePath, output); - packages.push({ - name: partPackageName(target.target, partNumber, { packageBase }), - version, - manifestPath: path.join(partDir, "Cargo.toml"), - cratePath: output, - target: target.target, - product: artifactProduct, - kind: artifactKind, - role: "part", - noticeProfile, - index: partNumber, - links: partLinksName(target.target, partNumber, { artifactProduct }), - localDependencies: [], - }); - } - packages.push(freezeSourceCrate({ - name: cargoPackageName(target.target, { packageBase }), - version, - manifestPath: path.join(aggregatorDir, "Cargo.toml"), - target: target.target, - product: artifactProduct, - kind: artifactKind, - role: "aggregator", - noticeProfile: "code-facade", - index: null, - links: cargoLinksName(target.target, { artifactProduct }), - localDependencies: Array.from({ length: partDirs.length }, (_, offset) => ({ - name: partPackageName(target.target, offset + 1, { packageBase }), - req: `=${version}`, - kind: "build", - })), - }, outputDir, cargoTargetDir, packages)); - return packages; -} - -function packageTarget( - target, - { - toolsTarget, - version, - assetDir, - sourceRoot, - outputDir, - cargoTargetDir, - partBytes, - icuRoot, - }, -) { - validateToolsTargetPair(target, toolsTarget); - const archive = path.join(assetDir, artifactAssetName(target, version)); - if (!isFile(archive)) { - fail(`missing liboliphaunt native release asset: ${rel(archive)}`); - } - const toolsArchive = path.join(assetDir, artifactAssetName(toolsTarget, version)); - if (!isFile(toolsArchive)) { - fail(`missing oliphaunt-tools native release asset: ${rel(toolsArchive)}`); - } - assertReleaseNoticesInArchive(archive, { profile: "native-runtime" }); - assertReleaseNoticesInArchive(toolsArchive, { profile: "native-tools" }); - const extractedRoot = path.join(sourceRoot, `${target.target}-extracted`); - extractArchive(archive, extractedRoot); - validateNativeCargoRuntimeClosure(extractedRoot, target.target, icuRoot); - const toolsRoot = path.join(sourceRoot, `${target.target}-tools-extracted`); - extractArchive(toolsArchive, toolsRoot); - validateNativePayload(extractedRoot, target.target, { toolSet: "runtime" }); - validateNativePayload(toolsRoot, target.target, { toolSet: "tools" }); - return [ - ...packagePayload(extractedRoot, sourceRoot, outputDir, cargoTargetDir, { - target, - version, - partBytes, - packageBase: PRODUCT, - artifactProduct: PRODUCT, - artifactKind: KIND, - artifactLabel: "liboliphaunt native runtime", - noticeProfile: "native-runtime", - }), - ...packagePayload(toolsRoot, sourceRoot, outputDir, cargoTargetDir, { - target: toolsTarget, - version, - partBytes, - packageBase: TOOLS_PRODUCT, - artifactProduct: TOOLS_PRODUCT, - artifactKind: TOOLS_KIND, - artifactLabel: "Oliphaunt native tools", - noticeProfile: "native-tools", - }), - ]; -} - -function writePackagesManifest(packages, outputDir) { - const unfrozen = packages.filter((item) => item.cratePath === null); - if (unfrozen.length > 0) { - fail(`all registry Cargo packages must have frozen .crate bytes: ${unfrozen.map((item) => item.name).join(", ")}`); - } - const data = { - schema: "oliphaunt-liboliphaunt-cargo-artifacts-v1", - product: PRODUCT, - packages: packages.map((item) => ({ - name: item.name, - target: item.target, - product: item.product, - kind: item.kind, - role: item.role, - noticeProfile: item.noticeProfile, - index: item.index, - manifestPath: rel(item.manifestPath), - cratePath: rel(item.cratePath), - })), - }; - writeFileSync(path.join(outputDir, "packages.json"), `${JSON.stringify(data, null, 2)}\n`); -} - -function usage() { - fail( - "usage: tools/release/package-liboliphaunt-cargo-artifacts.mjs [--asset-dir DIR] [--output-dir DIR] [--work-dir DIR] [--version VERSION] [--target TARGET]... [--part-bytes BYTES]", - ); -} - -function help() { - console.log(`usage: tools/release/package-liboliphaunt-cargo-artifacts.mjs [options] - -Options: - --asset-dir DIR directory containing checked liboliphaunt native release assets - --output-dir DIR directory where generated .crate files are written - --work-dir DIR isolated generated Cargo source/target workspace - --version VERSION release version to package - --target TARGET release target id to package; may be repeated - --part-bytes BYTES maximum raw payload bytes per generated part crate - -h, --help show this help -`); -} - -function optionValue(argv, index) { - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) { - usage(); - } - return value; -} - -async function parseArgs(argv) { - const args = { - assetDir: "target/liboliphaunt/release-assets", - outputDir: "target/liboliphaunt/cargo-artifacts", - workDir: "target/liboliphaunt", - version: undefined, - targets: [], - partBytes: DEFAULT_PART_BYTES, - }; - for (let index = 0; index < argv.length;) { - const arg = argv[index]; - if (arg === "--asset-dir") { - args.assetDir = optionValue(argv, index); - index += 2; - } else if (arg === "--output-dir") { - args.outputDir = optionValue(argv, index); - index += 2; - } else if (arg === "--work-dir") { - args.workDir = optionValue(argv, index); - index += 2; - } else if (arg === "--version") { - args.version = optionValue(argv, index); - index += 2; - } else if (arg === "--target") { - args.targets.push(optionValue(argv, index)); - index += 2; - } else if (arg === "--part-bytes") { - const parsed = Number.parseInt(optionValue(argv, index), 10); - if (!Number.isInteger(parsed)) { - usage(); - } - args.partBytes = parsed; - index += 2; - } else if (arg === "-h" || arg === "--help") { - help(); - process.exit(0); - } else { - usage(); - } - } - return { - assetDir: repoPath(args.assetDir), - outputDir: repoPath(args.outputDir), - workDir: repoPath(args.workDir), - version: args.version ?? await currentProductVersion(PRODUCT, PREFIX), - targets: args.targets, - partBytes: args.partBytes, - }; -} - -async function main(argv) { - const args = await parseArgs(argv); - if (!isDirectory(args.assetDir)) { - fail(`liboliphaunt release asset directory does not exist: ${rel(args.assetDir)}`); - } - if (args.partBytes <= 0 || args.partBytes > DEFAULT_PART_BYTES) { - fail(`--part-bytes must be between 1 and ${DEFAULT_PART_BYTES}`); - } - const selected = new Set(args.targets); - const sourceRoot = path.join(args.workDir, "cargo-package-sources"); - const cargoTargetDir = path.join(args.workDir, "cargo-package-target"); - rmSync(sourceRoot, { recursive: true, force: true }); - rmSync(args.outputDir, { recursive: true, force: true }); - rmSync(cargoTargetDir, { recursive: true, force: true }); - mkdirSync(sourceRoot, { recursive: true }); - mkdirSync(args.outputDir, { recursive: true }); - - let targets = allArtifactTargets( - { product: PRODUCT, kind: KIND, surface: SURFACE }, - PREFIX, - ); - const toolsTargets = new Map( - allArtifactTargets( - { product: PRODUCT, kind: TOOLS_KIND, surface: SURFACE }, - PREFIX, - ).map((target) => [target.target, target]), - ); - if (selected.size > 0) { - const known = new Set(targets.map((target) => target.target)); - const unknown = [...selected].filter((target) => !known.has(target)).sort(compareText); - if (unknown.length > 0) { - fail(`unknown liboliphaunt native Rust target(s): ${unknown.join(", ")}`); - } - targets = targets.filter((target) => selected.has(target.target)); - } - - const packages = []; - const icuArchive = path.join(args.assetDir, `liboliphaunt-${args.version}-icu-data.tar.gz`); - if (!isFile(icuArchive)) { - fail(`missing liboliphaunt native ICU data release asset: ${rel(icuArchive)}`); - } - assertReleaseNoticesInArchive(icuArchive, { profile: "native-icu-data" }); - const icuRoot = path.join(sourceRoot, "icu-data-extracted"); - extractArchive(icuArchive, icuRoot); - try { - validateNativeIcuDataManifest( - readFileSync(path.join(icuRoot, "manifest.properties")), - path.join(icuRoot, "share/icu"), - `${rel(icuArchive)} manifest.properties`, - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - const selectedToolsTargets = []; - for (const target of targets) { - const toolsTarget = toolsTargets.get(target.target); - if (toolsTarget === undefined) { - fail(`missing oliphaunt-tools Cargo artifact target for ${target.target}`); - } - selectedToolsTargets.push(toolsTarget); - packages.push(...packageTarget(target, { - toolsTarget, - version: args.version, - assetDir: args.assetDir, - sourceRoot, - outputDir: args.outputDir, - cargoTargetDir, - partBytes: args.partBytes, - icuRoot, - })); - } - packages.push(freezeSourceCrate(writeToolsFacadeCrate(sourceRoot, { - version: args.version, - toolsTargets: selectedToolsTargets, - }), args.outputDir, cargoTargetDir, packages)); - writePackagesManifest(packages, args.outputDir); - console.log("generated liboliphaunt native Cargo artifact crates:"); - for (const item of packages) { - console.log(`${item.name} ${item.role} ${rel(item.cratePath)}`); - } -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/package-liboliphaunt-cargo-artifacts.test.mjs b/tools/release/package-liboliphaunt-cargo-artifacts.test.mjs deleted file mode 100644 index 966422548..000000000 --- a/tools/release/package-liboliphaunt-cargo-artifacts.test.mjs +++ /dev/null @@ -1,301 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { chmodSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { - NATIVE_CARGO_CARRIER_LICENSES, - nativePayloadPlatformCommand, - renderUnsupportedToolsTargetGuard, -} from "./package-liboliphaunt-cargo-artifacts.mjs"; -import { assertLockedArtifactSet, discoverPublicationArtifacts } from "./publication-lock.mjs"; -import { elfFixture } from "../test/release-fixture-utils.mjs"; -import { nativeRuntimeResourceManifestFixture } from "../test/native-runtime-fixture.mjs"; -import { - assertReleaseNoticesInArchive, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { requiredCoreRuntimePaths } from "./optimize_native_runtime_payload.mjs"; -import { logicalTreeSha256 } from "./native-cluster-seed-contract.mjs"; -import { nativeIcuDataManifest } from "./native-icu-data-contract.mjs"; -import { nativeRuntimeCarrierManifest } from "./native-runtime-carrier-contract.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); - -function run(command, args, { env = process.env } = {}) { - const result = spawnSync(command, args, { cwd: ROOT, encoding: "utf8", env, stdio: ["ignore", "pipe", "pipe"] }); - assert.equal(result.status, 0, `${command} ${args.join(" ")} failed:\n${result.stdout}\n${result.stderr}`); -} - -function commandOutput(command, args) { - const result = spawnSync(command, args, { cwd: ROOT, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }); - assert.equal(result.status, 0, `${command} ${args.join(" ")} failed:\n${result.stdout}\n${result.stderr}`); - return result.stdout; -} - -function writeExecutable(file, contents) { - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, contents); - chmodSync(file, 0o755); -} - -function archiveFixture(source, archive) { - run("tar", ["--format", "ustar", "-czf", archive, "-C", source, "."], { - env: { ...process.env, COPYFILE_DISABLE: "1" }, - }); -} - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function stageClusterSeed(root, directory, profile, target, icuDataTreeSha256 = "") { - const seed = path.join(root, directory); - mkdirSync(path.join(seed, "files/global"), { recursive: true }); - mkdirSync(path.join(seed, "files/pg_wal"), { recursive: true }); - writeFileSync(path.join(seed, "files/PG_VERSION"), "18\n"); - writeFileSync(path.join(seed, "files/global/pg_control"), `${profile}\n`); - writeFileSync(path.join(seed, "manifest.properties"), [ - "schema=oliphaunt-runtime-resources-v1", - "layout=oliphaunt-cluster-seed-v1", - `artifactRole=cluster-seed-${profile}`, - `catalogProfile=${profile}`, - "postgresMajor=18", - "physicalFormat=native-pg18-v1", - `target=${target}`, - `compatibilityKey=native-pg18-${target}-v1`, - "initialSuperuser=postgres", - `runtimeFeatures=${profile === "icu" ? "icu" : ""}`, - `icuDataVersion=${profile === "icu" ? "76.1" : ""}`, - `icuDataForm=${profile === "icu" ? "files-le" : ""}`, - `icuDataTreeSha256=${icuDataTreeSha256}`, - "cacheKey=0123456789abcdef", - "", - ].join("\n")); -} - -test("requires the exact Windows runtime import library when packaging the runtime carrier", () => { - const runtime = nativePayloadPlatformCommand("C:/fixture/runtime", "windows-x64-msvc", { - toolSet: "runtime", - }); - assert.deepEqual(runtime.slice(-3), [ - "--require-windows-runtime-import-library", - "--windows-vc-runtime-profile", - "provider", - ]); - - const tools = nativePayloadPlatformCommand("C:/fixture/tools", "windows-x64-msvc", { - toolSet: "tools", - }); - assert.ok(!tools.includes("--require-windows-runtime-import-library")); - assert.ok(!tools.includes("--windows-vc-runtime-profile")); -}); - -test("freezes .crate bytes for native parts, aggregators, and facade and rejects substituted bytes", () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "native-cargo-freeze-test-")); - try { - const assets = path.join(root, "assets"); - const runtime = path.join(root, "runtime-fixture"); - const tools = path.join(root, "tools-fixture"); - const output = path.join(root, "output"); - const work = path.join(root, "work"); - const forbiddenStrip = path.join(root, "forbidden-strip"); - writeExecutable(forbiddenStrip, "#!/bin/sh\necho carrier assembly must not strip frozen release assets >&2\nexit 99\n"); - const fixtureElf = elfFixture({ machine: 62, requiredVersions: ["GLIBC_2.17"] }); - mkdirSync(path.join(runtime, "runtime/lib"), { recursive: true }); - writeFileSync(path.join(runtime, "runtime/lib/liboliphaunt.so"), fixtureElf); - for (const name of ["initdb", "pg_ctl", "postgres"]) { - writeExecutable(path.join(runtime, "runtime/bin", name), fixtureElf); - } - for (const relativePath of requiredCoreRuntimePaths( - "linux-x64-gnu", - path.join(runtime, "runtime"), - )) { - const file = path.join(runtime, "runtime", ...relativePath.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync( - file, - relativePath.startsWith("lib/postgresql/") ? fixtureElf : `${relativePath}\n`, - ); - } - for (const name of ["pg_basebackup", "pg_dump", "psql"]) { - writeExecutable(path.join(tools, "runtime/bin", name), fixtureElf); - } - const icu = path.join(root, "icu-fixture"); - const icuData = path.join(icu, "share/icu"); - mkdirSync(icuData, { recursive: true }); - const icuBytes = Buffer.from("fixture ICU data\n"); - writeFileSync(path.join(icuData, "icudt76l.dat"), icuBytes); - const icuDigest = logicalTreeSha256([{ path: "icudt76l.dat", bytes: icuBytes }]); - stageClusterSeed(runtime, "cluster-seed", "standard", "linux-x64-gnu"); - stageClusterSeed(runtime, "cluster-seed-icu", "icu", "linux-x64-gnu", icuDigest); - writeFileSync(path.join(runtime, "manifest.properties"), nativeRuntimeCarrierManifest("linux-x64-gnu")); - writeFileSync(path.join(runtime, "runtime/manifest.properties"), nativeRuntimeResourceManifestFixture({ - cacheKey: "fixture-runtime", - target: "linux-x64-gnu", - })); - writeFileSync(path.join(icu, "manifest.properties"), nativeIcuDataManifest(icuData)); - stageReleaseNotices(runtime, { profile: "native-runtime" }); - stageReleaseNotices(tools, { profile: "native-tools" }); - stageReleaseNotices(icu, { profile: "native-icu-data" }); - mkdirSync(assets, { recursive: true }); - archiveFixture(runtime, path.join(assets, "liboliphaunt-9.8.7-linux-x64-gnu.tar.gz")); - archiveFixture(tools, path.join(assets, "oliphaunt-tools-9.8.7-linux-x64-gnu.tar.gz")); - archiveFixture(icu, path.join(assets, "liboliphaunt-9.8.7-icu-data.tar.gz")); - - const packageArgs = [ - "tools/release/package-liboliphaunt-cargo-artifacts.mjs", - "--asset-dir", assets, - "--output-dir", output, - "--work-dir", work, - "--version", "9.8.7", - "--target", "linux-x64-gnu", - "--part-bytes", "65536", - ]; - run(process.execPath, packageArgs, { - env: { - ...process.env, - OLIPHAUNT_ELF_STRIP: forbiddenStrip, - OLIPHAUNT_STRIP: forbiddenStrip, - }, - }); - - const manifest = JSON.parse(readFileSync(path.join(output, "packages.json"), "utf8")); - assert.ok(manifest.packages.length >= 5); - assert.deepEqual(new Set(manifest.packages.map(({ role }) => role)), new Set(["part", "aggregator", "facade"])); - assert.ok(manifest.packages.every(({ cratePath }) => typeof cratePath === "string" && cratePath.endsWith(".crate"))); - assert.equal(readdirSync(output).filter((name) => name.endsWith(".crate")).length, manifest.packages.length); - const runtimeParts = manifest.packages.filter(({ role, kind }) => role === "part" && kind === "native-runtime"); - assert.ok(runtimeParts.some(({ cratePath, name }) => commandOutput("tar", [ - "-tzf", - path.resolve(ROOT, cratePath), - ]).includes(`${name}-9.8.7/payload/files/cluster-seed-icu/manifest.properties`))); - for (const item of manifest.packages) { - const expectedProfile = item.role === "part" ? item.kind : "code-facade"; - assert.equal(item.noticeProfile, expectedProfile, `${item.name} must freeze its carrier notice profile`); - const packedManifest = commandOutput("tar", [ - "-xOzf", - path.resolve(ROOT, item.cratePath), - `${item.name}-9.8.7/Cargo.toml`, - ]); - assert.equal( - Bun.TOML.parse(packedManifest).package.license, - NATIVE_CARGO_CARRIER_LICENSES[expectedProfile], - `${item.name} must declare its exact role license closure`, - ); - assertReleaseNoticesInArchive(path.resolve(ROOT, item.cratePath), { - prefix: `${item.name}-9.8.7`, - profile: expectedProfile, - }); - } - - const records = discoverPublicationArtifacts([output]); - assert.equal(records.length, manifest.packages.length); - assert.ok(records.every((record) => record.artifacts.length === 1 && record.artifacts[0].path.endsWith(".crate"))); - const lock = { - carriers: records.map((record, publishOrder) => ({ - ...record, - id: `cargo:${record.name}`, - product: "fixture", - publishOrder, - })), - }; - assert.doesNotThrow(() => assertLockedArtifactSet(lock, records, { product: "fixture", ecosystem: "cargo" })); - - const packedAggregator = manifest.packages.find(({ role }) => role === "aggregator"); - const packedManifest = commandOutput("tar", [ - "-xOzf", - path.resolve(ROOT, packedAggregator.cratePath), - `${packedAggregator.name}-9.8.7/Cargo.toml`, - ]); - assert.doesNotMatch(packedManifest, /oliphaunt-package-deps|registry\s*=/u); - assert.doesNotMatch( - packedManifest, - /\[build-dependencies[.]liboliphaunt-native-linux-x64-gnu-part-001\][\s\S]*?path\s*=/u, - ); - assert.match(packedManifest, /version\s*=\s*"=9[.]8[.]7"/u); - - const facade = manifest.packages.find(({ role }) => role === "facade"); - assert.ok(facade); - const facadeRoot = path.dirname(path.resolve(ROOT, facade.manifestPath)); - const facadeManifestText = readFileSync(path.join(facadeRoot, "Cargo.toml"), "utf8"); - assert.doesNotMatch(facadeManifestText, /\[dev-dependencies\]|serde_json/u); - const facadeSource = path.join(facadeRoot, "src/lib.rs"); - const facadeText = readFileSync(facadeSource, "utf8"); - assert.match(facadeText, /Generated release-only native target guard[.]/u); - assert.match(facadeText, /compile_error!/u); - assert.match(facadeText, /linux-x64-gnu/u); - assert.match(facadeText, /mod arguments;/u); - const packedFacadeSource = commandOutput("tar", [ - "-xOzf", - path.resolve(ROOT, facade.cratePath), - `${facade.name}-9.8.7/src/lib.rs`, - ]); - assert.equal(packedFacadeSource, facadeText); - const repositoryFacadeText = readFileSync( - path.join(ROOT, "src/runtimes/liboliphaunt/native/crates/tools/src/lib.rs"), - "utf8", - ); - assert.doesNotMatch( - repositoryFacadeText, - /Generated release-only native target guard|compile_error!/u, - ); - - const forcedUnsupported = path.join(root, "forced-unsupported-tools.rs"); - writeFileSync(forcedUnsupported, `#![forbid(unsafe_code)] -${renderUnsupportedToolsTargetGuard(["fixture-unsupported"], ["any()"])} -pub const FIXTURE: bool = true; -`); - const unsupported = spawnSync("rustc", [ - "--crate-name", "oliphaunt_tools", - "--crate-type", "lib", - "--edition", "2024", - forcedUnsupported, - ], { cwd: ROOT, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }); - assert.notEqual(unsupported.status, 0); - assert.match(unsupported.stderr, /has no portable fallback/u); - - const forcedSupported = path.join(root, "forced-supported-tools.rs"); - writeFileSync(forcedSupported, `#![forbid(unsafe_code)] -${renderUnsupportedToolsTargetGuard(["fixture-supported"], ["all()"])} -pub const FIXTURE: bool = true; -`); - const supported = spawnSync("rustc", [ - "--crate-name", "oliphaunt_tools", - "--crate-type", "lib", - "--edition", "2024", - "--emit", "metadata", - "-o", path.join(root, "forced-supported-tools.rmeta"), - forcedSupported, - ], { cwd: ROOT, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }); - assert.equal(supported.status, 0, supported.stderr); - - const firstDigests = new Map(records.map((record) => [record.name, record.artifacts[0].sha256])); - run(process.execPath, packageArgs); - const regenerated = discoverPublicationArtifacts([output]); - assert.deepEqual(new Map(regenerated.map((record) => [record.name, record.artifacts[0].sha256])), firstDigests); - - const aggregator = manifest.packages.find(({ role }) => role === "aggregator"); - const frozenDigest = records.find((record) => record.name === aggregator.name).artifacts[0].sha256; - const substituted = path.resolve(ROOT, aggregator.cratePath); - const substitutedBytes = readFileSync(substituted); - assert.equal(substitutedBytes[0], 0x1f); - assert.equal(substitutedBytes[1], 0x8b); - substitutedBytes[4] ^= 1; // Change only the gzip mtime header; the packaged Cargo contents and identity remain valid. - writeFileSync(substituted, substitutedBytes); - const changed = discoverPublicationArtifacts([output]); - const changedDigest = changed.find((record) => record.name === aggregator.name).artifacts[0].sha256; - assert.notEqual(changedDigest, frozenDigest); - assert.equal(changedDigest, sha256(substituted)); - assert.throws( - () => assertLockedArtifactSet(lock, changed, { product: "fixture", ecosystem: "cargo" }), - /frozen artifact bytes mismatch/u, - ); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/package-liboliphaunt-icu-data.sh b/tools/release/package-liboliphaunt-icu-data.sh deleted file mode 100755 index 8bc758608..000000000 --- a/tools/release/package-liboliphaunt-icu-data.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "package-liboliphaunt-icu-data.sh: must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -fail() { - echo "package-liboliphaunt-icu-data.sh: $*" >&2 - exit 1 -} - -require() { - command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1" -} - -source_dir="${1:-}" -out_dir="${2:-}" -[ -n "$source_dir" ] && [ -n "$out_dir" ] || - fail "usage: tools/release/package-liboliphaunt-icu-data.sh SOURCE_DIR OUTPUT_DIR" -[ -d "$source_dir" ] || fail "missing portable ICU data directory: $source_dir" - -require mktemp -require bun - -source "$root/src/runtimes/liboliphaunt/native/bin/icu.sh" -if find "$source_dir" -type l -print -quit | grep -q .; then - fail "portable ICU data directory must not contain symbolic links: $source_dir" -fi -oliphaunt_icu_files_data_ready "$source_dir" || - fail "portable ICU data directory has no ICU files payload: $source_dir" -version="$(tools/dev/bun.sh tools/release/product-version.mjs version liboliphaunt-native)" -asset="liboliphaunt-${version}-icu-data.tar.gz" -mkdir -p "$out_dir" - -stage_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-icu-data.XXXXXX")" -partial="$out_dir/.${asset}.tmp.$$.tar.gz" -cleanup() { - rm -rf "$stage_root" - rm -f "$partial" -} -trap cleanup EXIT INT TERM HUP - -# macOS exposes its per-user temporary directory through /var, which is a -# system-owned symlink to /private/var. Resolve only the fresh directory that -# mktemp created for this process; release-notices can then retain its strict -# rejection of arbitrary symlink ancestors supplied by callers. -stage_root="$(cd "$stage_root" && pwd -P)" -stage="$stage_root/liboliphaunt-${version}-icu-data" - -oliphaunt_icu_copy_files_data "$source_dir" "$stage/share/icu" || - fail "portable ICU data directory does not contain one canonical files-data payload" -oliphaunt_icu_files_data_ready "$stage/share/icu" || - fail "staged portable ICU data payload is incomplete" -tools/dev/bun.sh tools/release/native-icu-data-contract.mjs \ - "$stage/share/icu" \ - "$stage/manifest.properties" -tools/dev/bun.sh tools/release/write-icu-package-size-report.mjs \ - "$stage/share/icu" \ - "$stage/package-size.tsv" - -tools/dev/bun.sh tools/release/release-notices.mjs stage "$stage" --profile native-icu-data - -src/shared/artifact-packaging/archive-directory.mjs "$stage" "$partial" -tools/dev/bun.sh tools/release/release-notices.mjs check-archive "$partial" --profile native-icu-data -mv -f "$partial" "$out_dir/$asset" -echo "liboliphauntIcuDataReleaseAsset=$out_dir/$asset" diff --git a/tools/release/package-liboliphaunt-icu-data.test.mjs b/tools/release/package-liboliphaunt-icu-data.test.mjs deleted file mode 100644 index ce0ac7635..000000000 --- a/tools/release/package-liboliphaunt-icu-data.test.mjs +++ /dev/null @@ -1,127 +0,0 @@ -import { afterEach, expect, test } from "bun:test"; -import { createHash } from "node:crypto"; -import { - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -import { currentProductVersionSync } from "./release-artifact-targets.mjs"; -import { ROOT } from "./release-graph.mjs"; -import { parseProperties } from "./native-cluster-seed-contract.mjs"; - -const SCRIPT = path.join(ROOT, "tools/release/package-liboliphaunt-icu-data.sh"); -const scratch = []; - -afterEach(() => { - for (const directory of scratch.splice(0)) rmSync(directory, { recursive: true, force: true }); -}); - -function temporaryRoot() { - const directory = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-icu-package-test-")); - scratch.push(directory); - return directory; -} - -function run(source, output, { env = process.env } = {}) { - return spawnSync("bash", [SCRIPT, source, output], { - cwd: ROOT, - encoding: "utf8", - env, - }); -} - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -test("packages the portable ICU payload deterministically outside platform release artifacts", () => { - const root = temporaryRoot(); - const source = path.join(root, "source", "icudt76l"); - const output = path.join(root, "output"); - mkdirSync(path.join(source, "coll"), { recursive: true }); - mkdirSync(path.join(root, "source", "76.1", "config"), { recursive: true }); - writeFileSync(path.join(source, "root.res"), "root\n"); - writeFileSync(path.join(source, "coll", "en.res"), "en\n"); - writeFileSync(path.join(root, "source", "76.1", "config", "mh-darwin"), "build-only\n"); - writeFileSync(path.join(root, "source", "LICENSE"), "install-scaffolding\n"); - - const first = run(path.dirname(source), output); - expect(first.status, first.stderr).toBe(0); - const version = currentProductVersionSync("liboliphaunt-native"); - const archive = path.join(output, `liboliphaunt-${version}-icu-data.tar.gz`); - const firstDigest = sha256(archive); - - const listing = spawnSync("tar", ["-tzf", archive], { encoding: "utf8" }); - expect(listing.status, listing.stderr).toBe(0); - const members = listing.stdout.split(/\r?\n/u).filter(Boolean); - expect(members).toContain("share/icu/icudt76l/root.res"); - expect(members.some((member) => member.startsWith("share/icu/76.1"))).toBe(false); - expect(members).not.toContain("share/icu/LICENSE"); - expect(members).toContain("manifest.properties"); - expect(members.some((member) => member.startsWith("cluster-seed"))).toBe(false); - expect(members).toContain("package-size.tsv"); - expect(members).not.toContain("THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"); - expect(members).toContain("THIRD_PARTY_LICENSES/ICU-LICENSE"); - const receipt = spawnSync("tar", ["-xOzf", archive, "manifest.properties"], { encoding: "utf8" }); - expect(receipt.status, receipt.stderr).toBe(0); - const fields = parseProperties(receipt.stdout, "portable ICU data receipt"); - expect(Object.fromEntries(fields)).toEqual({ - schema: "oliphaunt-icu-data-v1", - artifactRole: "icu-data", - icuDataVersion: "76.1", - icuDataForm: "files-le", - icuDataTreeSha256: expect.stringMatching(/^[0-9a-f]{64}$/u), - }); - const sizeReport = spawnSync("tar", ["-xOzf", archive, "package-size.tsv"], { encoding: "utf8" }); - expect(sizeReport.status, sizeReport.stderr).toBe(0); - expect(sizeReport.stdout).toMatch(/^kind\tid\textensions\tfiles\tbytes\npackage\ttotal\t-\t-\t[0-9]+\npackage\ticu-data\t-\t-\t[0-9]+\n$/u); - - const second = run(path.dirname(source), output); - expect(second.status, second.stderr).toBe(0); - expect(sha256(archive)).toBe(firstDigest); -}); - -test("rejects empty or symlinked portable ICU inputs", () => { - const root = temporaryRoot(); - const empty = path.join(root, "empty"); - const linked = path.join(root, "linked"); - const output = path.join(root, "output"); - mkdirSync(empty); - expect(run(empty, output).status).not.toBe(0); - - mkdirSync(path.join(linked, "icudt76l"), { recursive: true }); - writeFileSync(path.join(linked, "payload.res"), "payload\n"); - symlinkSync(path.join(linked, "payload.res"), path.join(linked, "icudt76l", "payload.res")); - const result = run(linked, output); - expect(result.status).not.toBe(0); - expect(result.stderr).toContain("must not contain symbolic links"); -}); - -test("canonicalizes only its mktemp-owned stage below a symlinked OS temp alias", () => { - if (process.platform === "win32") return; - - const root = temporaryRoot(); - const source = path.join(root, "source", "icudt76l"); - const output = path.join(root, "output"); - const realTemp = path.join(root, "real-temp"); - const linkedTemp = path.join(root, "linked-temp"); - mkdirSync(source, { recursive: true }); - mkdirSync(realTemp); - writeFileSync(path.join(source, "root.res"), "root\n"); - symlinkSync(realTemp, linkedTemp); - - const result = run(path.dirname(source), output, { - env: { ...process.env, TMPDIR: linkedTemp }, - }); - expect(result.status, result.stderr).toBe(0); - - const version = currentProductVersionSync("liboliphaunt-native"); - expect(readFileSync(path.join(output, `liboliphaunt-${version}-icu-data.tar.gz`)).length).toBeGreaterThan(0); -}); diff --git a/tools/release/package-liboliphaunt-linux-assets.sh b/tools/release/package-liboliphaunt-linux-assets.sh deleted file mode 100755 index 93102d41d..000000000 --- a/tools/release/package-liboliphaunt-linux-assets.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -fail() { - echo "package-liboliphaunt-linux-assets.sh: $*" >&2 - exit 1 -} - -require() { - command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1" -} - -source "$root/tools/release/liboliphaunt-extension-guard.sh" - -fetch_release_source_assets() { - if [ "${OLIPHAUNT_RELEASE_FETCH_ASSETS:-1}" = "0" ]; then - return 0 - fi - echo "==> Fetching pinned source assets" - bun src/sources/tools/fetch-sources.mjs native-runtime >/tmp/liboliphaunt-release-linux-assets-fetch.log -} - -if [ "$(uname -s)" != "Linux" ]; then - fail "Linux liboliphaunt release assets must be built on Linux" -fi - -case "$(uname -m)" in - x86_64|amd64) target_id="linux-x64-gnu" ;; - aarch64|arm64) target_id="linux-arm64-gnu" ;; - *) fail "unsupported Linux architecture $(uname -m)" ;; -esac - -require cargo -require bun - -version="$(tools/dev/bun.sh tools/release/product-version.mjs version liboliphaunt-native)" -out_dir="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS:-$root/target/liboliphaunt/release-assets}" -stage_root="$root/target/liboliphaunt/release-stage-$target_id" -work_root="${OLIPHAUNT_LINUX_WORK_ROOT:-$root/target/liboliphaunt-pg18-$target_id}" -headers_dir="$root/src/runtimes/liboliphaunt/native/include" -lib="$work_root/out/liboliphaunt.so" -embedded_modules="$work_root/out/modules" -runtime="$work_root/install" -stage="$stage_root/liboliphaunt-${version}-${target_id}" -asset="liboliphaunt-${version}-${target_id}.tar.gz" -tools_stage="$stage_root/oliphaunt-tools-${version}-${target_id}" -tools_asset="oliphaunt-tools-${version}-${target_id}.tar.gz" -catalog_file="$stage_root/extension-catalog.tsv" - -rm -rf "$stage_root" -mkdir -p "$out_dir" "$stage/include" "$stage/lib" "$stage/runtime" "$tools_stage/runtime/bin" - -fetch_release_source_assets - -if [ "${OLIPHAUNT_RELEASE_BUILD_RUNTIME:-1}" = "1" ]; then - echo "==> Building liboliphaunt $target_id" - src/runtimes/liboliphaunt/native/bin/build-postgres18-linux.sh >/tmp/liboliphaunt-release-"$target_id".log -fi - -[ -f "$lib" ] || fail "missing Linux liboliphaunt shared library at $lib" -oliphaunt_assert_base_embedded_modules_exact "$embedded_modules" so || - fail "base $target_id embedded module inventory must contain only regular dict_snowball.so and plpgsql.so modules" -for tool in initdb pg_basebackup pg_ctl pg_dump postgres psql; do - [ -x "$runtime/bin/$tool" ] || fail "missing Linux $tool at $runtime/bin/$tool" -done - -echo "==> Verifying base liboliphaunt $target_id runtime is extension-clean" -cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked -- --list-extensions >"$catalog_file" -oliphaunt_assert_base_runtime_has_no_optional_extensions "$catalog_file" "$runtime" || - fail "base $target_id runtime must not ship optional extension assets" - -rsync -a --delete "$headers_dir/" "$stage/include/" -cp "$lib" "$stage/lib/" -rsync -a --delete "$embedded_modules/" "$stage/lib/modules/" -rsync -a --delete \ - --exclude '/bin/pg_dump' \ - --exclude '/bin/pg_basebackup' \ - --exclude '/bin/psql' \ - --exclude 'share/icu/***' \ - "$runtime/" "$stage/runtime/" -tools/dev/bun.sh tools/release/stage-native-cluster-seed.mjs \ - --runtime "$runtime" \ - --destination "$stage/cluster-seed" \ - --target "$target_id" \ - --profile standard -tools/dev/bun.sh tools/release/stage-native-cluster-seed.mjs \ - --runtime "$runtime" \ - --destination "$stage/cluster-seed-icu" \ - --target "$target_id" \ - --profile icu \ - --icu-data "$work_root/icu/share/icu" -tools/dev/bun.sh tools/release/finalize-native-runtime-carrier.mjs \ - --root "$stage" \ - --target "$target_id" \ - --icu-data "$work_root/icu/share/icu" \ - --runtime-source "$runtime" \ - --embedded-modules "$embedded_modules" -for tool in pg_basebackup pg_dump psql; do - cp -p "$runtime/bin/$tool" "$tools_stage/runtime/bin/" -done - -# PostgreSQL installs versioned shared-library aliases as symlinks. Release -# archives are link-free consumer inputs, so materialize only validated, -# relative aliases that remain inside the staged tree. -tools/dev/bun.sh src/shared/artifact-packaging/materialize-release-symlinks.mjs "$stage" - -echo "==> Optimizing staged liboliphaunt $target_id release payload" -tools/dev/bun.sh tools/release/optimize_native_runtime_payload.mjs "$stage" --target "$target_id" --tool-set runtime - -echo "==> Optimizing staged oliphaunt-tools $target_id release payload" -tools/dev/bun.sh tools/release/optimize_native_runtime_payload.mjs "$tools_stage" --target "$target_id" --tool-set tools - -echo "==> Verifying staged $target_id binary compatibility" -tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target_id" --root "$stage" -tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target_id" --root "$tools_stage" -tools/release/check-linux-consumer-baseline.sh --target "$target_id" --root "$stage" -tools/release/check-linux-consumer-baseline.sh \ - --target "$target_id" \ - --root "$tools_stage" \ - --library-root "$stage" - -tools/dev/bun.sh tools/release/release-notices.mjs stage "$stage" --profile native-runtime -tools/dev/bun.sh tools/release/release-notices.mjs stage "$tools_stage" --profile native-tools - -echo "==> Smoke testing staged liboliphaunt $target_id release layout" -env \ - OLIPHAUNT_WORK_ROOT="$work_root" \ - LIBOLIPHAUNT_PATH="$stage/lib/liboliphaunt.so" \ - OLIPHAUNT_INSTALL_DIR="$stage/runtime" \ - OLIPHAUNT_SMOKE_BIN_DIR="$stage_root/smoke-bin-$target_id" \ - OLIPHAUNT_SMOKE_ROOT="$stage_root/smoke-root-$target_id" \ - OLIPHAUNT_STANDARD_CLUSTER_SEED="$stage/cluster-seed" \ - OLIPHAUNT_ICU_CLUSTER_SEED="$stage/cluster-seed-icu" \ - OLIPHAUNT_ICU_DATA_DIR="$work_root/icu/share/icu" \ - node src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs --cluster-seeds - -src/shared/artifact-packaging/archive-directory.mjs "$stage" "$out_dir/$asset" -src/shared/artifact-packaging/archive-directory.mjs "$tools_stage" "$out_dir/$tools_asset" -tools/dev/bun.sh tools/release/release-notices.mjs check-archive "$out_dir/$asset" --profile native-runtime -tools/dev/bun.sh tools/release/release-notices.mjs check-archive "$out_dir/$tools_asset" --profile native-tools -echo "liboliphauntLinuxReleaseAsset=$out_dir/$asset" -echo "oliphauntToolsLinuxReleaseAsset=$out_dir/$tools_asset" diff --git a/tools/release/package-liboliphaunt-macos-assets.sh b/tools/release/package-liboliphaunt-macos-assets.sh deleted file mode 100755 index 407934f5f..000000000 --- a/tools/release/package-liboliphaunt-macos-assets.sh +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" -source "$root/tools/release/liboliphaunt-extension-guard.sh" - -fail() { - echo "package-liboliphaunt-macos-assets.sh: $*" >&2 - exit 1 -} - -fetch_release_source_assets() { - if [ "${OLIPHAUNT_RELEASE_FETCH_ASSETS:-1}" = "0" ]; then - return 0 - fi - echo "==> Fetching pinned source assets" - bun src/sources/tools/fetch-sources.mjs native-runtime >/tmp/liboliphaunt-release-macos-assets-fetch.log -} - -if [ "$(uname -s)" != "Darwin" ]; then - fail "macOS liboliphaunt release assets must be built on macOS" -fi - -case "$(uname -m)" in - arm64|aarch64) target_id="macos-arm64" ;; - *) fail "unsupported macOS architecture $(uname -m)" ;; -esac - -version="$(tools/dev/bun.sh tools/release/product-version.mjs version liboliphaunt-native)" -command -v bun >/dev/null 2>&1 || fail "missing required command: bun" -out_dir="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS:-$root/target/liboliphaunt/release-assets}" -stage_root="$root/target/liboliphaunt/release-stage-$target_id" -work_root="${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18}" -headers_dir="$root/src/runtimes/liboliphaunt/native/include" -lib="$work_root/out/liboliphaunt.dylib" -embedded_modules="$work_root/out/modules" -runtime="$work_root/install" -stage="$stage_root/liboliphaunt-${version}-${target_id}" -asset="liboliphaunt-${version}-${target_id}.tar.gz" -tools_stage="$stage_root/oliphaunt-tools-${version}-${target_id}" -tools_asset="oliphaunt-tools-${version}-${target_id}.tar.gz" -catalog_file="$stage_root/extension-catalog.tsv" - -rm -rf "$stage_root" -mkdir -p "$out_dir" "$stage/include" "$stage/lib" "$stage/runtime" "$tools_stage/runtime/bin" - -fetch_release_source_assets - -if [ "${OLIPHAUNT_RELEASE_BUILD_RUNTIME:-1}" = "1" ]; then - echo "==> Building liboliphaunt $target_id" - OLIPHAUNT_BUILD_EXTENSIONS="${OLIPHAUNT_BUILD_EXTENSIONS:-0}" \ - src/runtimes/liboliphaunt/native/bin/build-postgres18-macos.sh >/tmp/liboliphaunt-release-"$target_id".log -fi - -[ -f "$lib" ] || fail "missing macOS liboliphaunt dylib at $lib" -oliphaunt_assert_base_embedded_modules_exact "$embedded_modules" dylib || - fail "base $target_id embedded module inventory must contain only regular dict_snowball.dylib and plpgsql.dylib modules" -for tool in initdb pg_basebackup pg_ctl pg_dump postgres psql; do - [ -x "$runtime/bin/$tool" ] || fail "missing macOS $tool at $runtime/bin/$tool" -done - -echo "==> Verifying base liboliphaunt $target_id runtime is extension-clean" -cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked -- --list-extensions >"$catalog_file" -oliphaunt_assert_base_runtime_has_no_optional_extensions "$catalog_file" "$runtime" || - fail "base $target_id runtime must not ship optional extension assets" - -rsync -a --delete "$headers_dir/" "$stage/include/" -cp "$lib" "$stage/lib/" -rsync -a --delete "$embedded_modules/" "$stage/lib/modules/" -rsync -a --delete \ - --exclude '/bin/pg_dump' \ - --exclude '/bin/pg_basebackup' \ - --exclude '/bin/psql' \ - --exclude 'share/icu/***' \ - "$runtime/" "$stage/runtime/" -tools/dev/bun.sh tools/release/stage-native-cluster-seed.mjs \ - --runtime "$runtime" \ - --destination "$stage/cluster-seed" \ - --target "$target_id" \ - --profile standard -tools/dev/bun.sh tools/release/stage-native-cluster-seed.mjs \ - --runtime "$runtime" \ - --destination "$stage/cluster-seed-icu" \ - --target "$target_id" \ - --profile icu \ - --icu-data "$work_root/icu/share/icu" -tools/dev/bun.sh tools/release/finalize-native-runtime-carrier.mjs \ - --root "$stage" \ - --target "$target_id" \ - --icu-data "$work_root/icu/share/icu" \ - --runtime-source "$runtime" \ - --embedded-modules "$embedded_modules" -for tool in pg_basebackup pg_dump psql; do - cp -p "$runtime/bin/$tool" "$tools_stage/runtime/bin/" -done - -# PostgreSQL installs versioned shared-library aliases as symlinks. Release -# archives are link-free consumer inputs, so materialize only validated, -# relative aliases that remain inside the staged tree. -tools/dev/bun.sh src/shared/artifact-packaging/materialize-release-symlinks.mjs "$stage" - -echo "==> Optimizing staged liboliphaunt $target_id release payload" -tools/dev/bun.sh tools/release/optimize_native_runtime_payload.mjs "$stage" --target "$target_id" --tool-set runtime - -echo "==> Optimizing staged oliphaunt-tools $target_id release payload" -tools/dev/bun.sh tools/release/optimize_native_runtime_payload.mjs "$tools_stage" --target "$target_id" --tool-set tools - -echo "==> Verifying staged $target_id binary compatibility" -tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target_id" --root "$stage" -tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target_id" --root "$tools_stage" - -tools/dev/bun.sh tools/release/release-notices.mjs stage "$stage" --profile native-runtime -tools/dev/bun.sh tools/release/release-notices.mjs stage "$tools_stage" --profile native-tools - -echo "==> Smoke testing staged liboliphaunt $target_id release layout" -env \ - OLIPHAUNT_WORK_ROOT="$work_root" \ - LIBOLIPHAUNT_PATH="$stage/lib/liboliphaunt.dylib" \ - OLIPHAUNT_INSTALL_DIR="$stage/runtime" \ - OLIPHAUNT_SMOKE_BIN_DIR="$stage_root/smoke-bin-$target_id" \ - OLIPHAUNT_SMOKE_ROOT="$stage_root/smoke-root-$target_id" \ - OLIPHAUNT_STANDARD_CLUSTER_SEED="$stage/cluster-seed" \ - OLIPHAUNT_ICU_CLUSTER_SEED="$stage/cluster-seed-icu" \ - OLIPHAUNT_ICU_DATA_DIR="$work_root/icu/share/icu" \ - node src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs --cluster-seeds - -src/shared/artifact-packaging/archive-directory.mjs "$stage" "$out_dir/$asset" -src/shared/artifact-packaging/archive-directory.mjs "$tools_stage" "$out_dir/$tools_asset" -tools/dev/bun.sh tools/release/release-notices.mjs check-archive "$out_dir/$asset" --profile native-runtime -tools/dev/bun.sh tools/release/release-notices.mjs check-archive "$out_dir/$tools_asset" --profile native-tools -echo "liboliphauntMacosReleaseAsset=$out_dir/$asset" -echo "oliphauntToolsMacosReleaseAsset=$out_dir/$tools_asset" diff --git a/tools/release/package-liboliphaunt-mobile-assets.sh b/tools/release/package-liboliphaunt-mobile-assets.sh deleted file mode 100755 index 981eae1da..000000000 --- a/tools/release/package-liboliphaunt-mobile-assets.sh +++ /dev/null @@ -1,235 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -fail() { - echo "package-liboliphaunt-mobile-assets.sh: $*" >&2 - exit 1 -} - -require() { - command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1" -} - -source "$root/tools/release/liboliphaunt-extension-guard.sh" - -require cargo -require bun -require rsync - -target_id="${1:-}" -case "$target_id" in - android-arm64-v8a|android-x86_64|ios-xcframework) - ;; - *) - fail "usage: tools/release/package-liboliphaunt-mobile-assets.sh [android-arm64-v8a|android-x86_64|ios-xcframework]" - ;; -esac - -version="$(tools/dev/bun.sh tools/release/product-version.mjs version liboliphaunt-native)" -out_dir="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS:-$root/target/liboliphaunt/release-assets}" -stage_root="${OLIPHAUNT_LIBOLIPHAUNT_RELEASE_STAGE_ROOT:-$root/target/liboliphaunt/release-stage-$target_id}" -headers_dir="$root/src/runtimes/liboliphaunt/native/include" - -rm -rf "$stage_root" -mkdir -p "$out_dir" "$stage_root" - -archive_staged_dir() { - local staged="$1" - local profile="$2" - local name - name="$(basename "$staged")" - src/shared/artifact-packaging/archive-directory.mjs "$staged" "$out_dir/${name}.tar.gz" - tools/dev/bun.sh tools/release/release-notices.mjs check-archive \ - "$out_dir/${name}.tar.gz" \ - --profile "$profile" -} - -archive_swiftpm_xcframework() { - local xcframework="$1" - local output="$2" - [ -d "$xcframework" ] || fail "missing SwiftPM XCFramework input at $xcframework" - rm -f "$output" - tools/dev/bun.sh src/shared/artifact-packaging/archive-directory.mjs --keep-parent "$xcframework" "$output" -} - -stage_runtime_resource_closure() { - local runtime="$1" - local icu_data="$2" - local seed_target="$3" - local stage="$4" - - env \ - OLIPHAUNT_INSTALL_DIR="$runtime" \ - cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked -- \ - --output "$stage" \ - --mode native-direct \ - --force >/tmp/liboliphaunt-release-mobile-runtime-resources.log - local closure="$stage/oliphaunt" - [ -d "$closure/runtime/files" ] || fail "runtime-resource package did not create $closure/runtime/files" - tools/dev/bun.sh tools/release/stage-native-cluster-seed.mjs \ - --runtime "$runtime" \ - --destination "$closure/cluster-seed" \ - --target "$seed_target" \ - --profile standard - tools/dev/bun.sh tools/release/stage-native-cluster-seed.mjs \ - --runtime "$runtime" \ - --destination "$closure/cluster-seed-icu" \ - --target "$seed_target" \ - --profile icu \ - --icu-data "$icu_data" - tools/dev/bun.sh tools/release/finalize-native-runtime-carrier.mjs \ - --root "$closure" \ - --target "$seed_target" \ - --icu-data "$icu_data" -} - -package_android() { - local abi="$1" - local work_root="$2" - local lib="$work_root/out/liboliphaunt.so" - local static_registry="$work_root/out/liboliphaunt_mobile_static_registry.c" - local stage="$stage_root/liboliphaunt-${version}-android-${abi}" - local host_work_root="${OLIPHAUNT_LINUX_X64_ROOT:-$root/target/liboliphaunt-pg18-linux-x64-gnu}" - local host_runtime="$host_work_root/install" - local icu_source="$host_work_root/icu/share/icu" - local runtime_stage="$stage_root/liboliphaunt-${version}-runtime-resources-android-datum64" - - [ -f "$lib" ] || fail "missing Android $abi liboliphaunt shared library at $lib" - [ ! -f "$static_registry" ] || - fail "base Android $abi release asset must not include mobile static extension registry $static_registry" - [ -d "$host_runtime" ] || fail "missing native host runtime at $host_runtime" - [ -d "$icu_source" ] || fail "missing portable ICU data at $icu_source" - - tools/dev/bun.sh tools/release/native-mobile-abi-contract.mjs write \ - --build-root "$work_root/postgresql-18.4" \ - --target "$target_id" \ - --output "$work_root/out/native-mobile-abi.properties" - - mkdir -p "$stage/include" "$stage/jni/$abi" - rsync -a --delete "$headers_dir/" "$stage/include/" - cp "$lib" "$stage/jni/$abi/" - echo "==> Stripping staged liboliphaunt Android $abi release binaries" - tools/dev/bun.sh tools/release/strip_native_release_binaries.mjs --target "$target_id" "$stage" - echo "==> Verifying staged liboliphaunt Android $abi binary compatibility" - tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target_id" --root "$stage" - tools/dev/bun.sh tools/release/release-notices.mjs stage \ - "$stage" \ - --profile native-runtime - archive_staged_dir "$stage" native-runtime - if [ "$target_id" = "android-x86_64" ]; then - stage_runtime_resource_closure \ - "$host_runtime" \ - "$icu_source" \ - android-datum64 \ - "$runtime_stage" - tools/dev/bun.sh tools/release/release-notices.mjs stage \ - "$runtime_stage" \ - --profile native-runtime-resources - archive_staged_dir "$runtime_stage" native-runtime-resources - fi -} - -package_ios() { - local ios_work_root="${OLIPHAUNT_IOS_XCFRAMEWORK_ROOT:-$root/target/liboliphaunt-ios-xcframework}" - local macos_work_root="${OLIPHAUNT_WORK_ROOT:-$root/target/liboliphaunt-pg18}" - local ios_xcframework="$ios_work_root/out/liboliphaunt.xcframework" - local packaged_ios_work_root="$stage_root/packaged-ios-xcframework" - local packaged_ios_xcframework="$packaged_ios_work_root/out/liboliphaunt.xcframework" - local macos_runtime="$macos_work_root/install" - local catalog_file="$stage_root/extension-catalog.tsv" - local macos_runtime_stage="$stage_root/liboliphaunt-${version}-runtime-resources-macos-arm64" - local ios_runtime_stage="$stage_root/liboliphaunt-${version}-runtime-resources-ios-datum64" - local stage_ios="$stage_root/liboliphaunt-${version}-ios-xcframework" - local static_registry="$ios_work_root/out/liboliphaunt_mobile_static_registry.c" - local icu_source="$macos_work_root/icu/share/icu" - local ios_device_receipt="${OLIPHAUNT_IOS_DEVICE_ROOT:-$root/target/liboliphaunt-ios-device}/out/native-mobile-abi.properties" - local ios_simulator_receipt="${OLIPHAUNT_IOS_SIMULATOR_ROOT:-$root/target/liboliphaunt-ios-simulator}/out/native-mobile-abi.properties" - local macos_producer_receipt="$ios_work_root/out/native-mobile-abi-producer.properties" - - [ -d "$ios_xcframework" ] || fail "missing iOS XCFramework at $ios_xcframework" - [ -d "$macos_runtime" ] || fail "missing macOS PostgreSQL runtime at $macos_runtime" - [ -d "$icu_source" ] || fail "missing portable ICU data sidecar at $icu_source" - [ ! -f "$static_registry" ] || - fail "base iOS release asset must not include mobile static extension registry $static_registry" - - cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked -- --list-extensions >"$catalog_file" - oliphaunt_assert_base_runtime_has_no_optional_extensions "$catalog_file" "$macos_runtime" || - fail "base iOS release runtime must not ship optional extension assets; selected extensions belong in exact extension artifacts" - - tools/dev/bun.sh tools/release/native-mobile-abi-contract.mjs write \ - --build-root "${OLIPHAUNT_IOS_DEVICE_ROOT:-$root/target/liboliphaunt-ios-device}/postgresql-18.4" \ - --target ios-arm64 \ - --output "$ios_device_receipt" - tools/dev/bun.sh tools/release/native-mobile-abi-contract.mjs write \ - --build-root "${OLIPHAUNT_IOS_SIMULATOR_ROOT:-$root/target/liboliphaunt-ios-simulator}/postgresql-18.4" \ - --target ios-arm64-simulator \ - --output "$ios_simulator_receipt" - tools/dev/bun.sh tools/release/native-mobile-abi-contract.mjs write \ - --build-root "$macos_work_root/postgresql-18.4" \ - --target macos-arm64 \ - --output "$macos_producer_receipt" - tools/dev/bun.sh tools/release/native-mobile-abi-contract.mjs compare \ - --domain ios-datum64 \ - --receipt "$ios_device_receipt" \ - --receipt "$ios_simulator_receipt" \ - --receipt "$macos_producer_receipt" - - stage_runtime_resource_closure "$macos_runtime" "$icu_source" macos-arm64 "$macos_runtime_stage" - stage_runtime_resource_closure "$macos_runtime" "$icu_source" ios-datum64 "$ios_runtime_stage" - local ios_proof="$ios_runtime_stage/oliphaunt/provenance/native-mobile-abi" - mkdir -p "$ios_proof" - cp "$ios_device_receipt" "$ios_proof/ios-arm64.properties" - cp "$ios_simulator_receipt" "$ios_proof/ios-arm64-simulator.properties" - cp "$macos_producer_receipt" "$ios_proof/macos-arm64.properties" - OLIPHAUNT_MACOS_RUNTIME_RESOURCES_ROOT="$macos_runtime_stage/oliphaunt" \ - OLIPHAUNT_IOS_RUNTIME_RESOURCES_ROOT="$ios_runtime_stage/oliphaunt" \ - OLIPHAUNT_IOS_XCFRAMEWORK_ROOT="$packaged_ios_work_root" \ - src/runtimes/liboliphaunt/native/bin/build-ios-xcframework.sh >/tmp/liboliphaunt-release-ios-xcframework-resources.log - mkdir -p "$stage_ios" - rsync -a --delete "$packaged_ios_xcframework" "$stage_ios/" - echo "==> Stripping staged liboliphaunt iOS release binaries" - tools/dev/bun.sh tools/release/strip_native_release_binaries.mjs --target "$target_id" "$stage_ios" - echo "==> Verifying staged liboliphaunt iOS binary compatibility" - tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target_id" --root "$stage_ios" - - tools/dev/bun.sh tools/release/release-notices.mjs stage \ - "$stage_ios" \ - --profile native-runtime - tools/dev/bun.sh tools/release/release-notices.mjs stage \ - "$stage_ios/liboliphaunt.xcframework" \ - --profile native-runtime - - archive_staged_dir "$stage_ios" native-runtime - archive_swiftpm_xcframework \ - "$stage_ios/liboliphaunt.xcframework" \ - "$out_dir/liboliphaunt-${version}-apple-spm-xcframework.zip" - tools/dev/bun.sh tools/release/release-notices.mjs check-archive \ - "$out_dir/liboliphaunt-${version}-apple-spm-xcframework.zip" \ - --prefix liboliphaunt.xcframework \ - --profile native-runtime - tools/dev/bun.sh tools/release/release-notices.mjs stage \ - "$ios_runtime_stage" \ - --profile native-runtime-resources - archive_staged_dir "$ios_runtime_stage" native-runtime-resources - tools/release/package-liboliphaunt-icu-data.sh "$icu_source" "$out_dir" -} - -case "$target_id" in - android-arm64-v8a) - package_android arm64-v8a "${OLIPHAUNT_ANDROID_ARM64_ROOT:-$root/target/liboliphaunt-pg18-android-arm64}" - ;; - android-x86_64) - package_android x86_64 "${OLIPHAUNT_ANDROID_X86_64_ROOT:-$root/target/liboliphaunt-pg18-android-x86_64}" - ;; - ios-xcframework) - package_ios - ;; -esac - -echo "liboliphauntMobileReleaseAssetDir=$out_dir" diff --git a/tools/release/package-liboliphaunt-wasix-cargo-artifacts.test.mjs b/tools/release/package-liboliphaunt-wasix-cargo-artifacts.test.mjs deleted file mode 100644 index 8de430186..000000000 --- a/tools/release/package-liboliphaunt-wasix-cargo-artifacts.test.mjs +++ /dev/null @@ -1,539 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { - chmodSync, - cpSync, - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import { afterAll, describe, expect, test } from "bun:test"; -import { gzipSync, zstdCompressSync } from "node:zlib"; - -import { - extensionReleaseProduct, - extensionReleaseVersion, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { - extractArchiveMemberToFile, - extractTarZstd, - injectRuntimeExtensionDependencies, - validateRuntimePayload, -} from "./package_liboliphaunt_wasix_cargo_artifacts.mjs"; -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { - AOT_TARGET_TRIPLES, - CORE_RUNTIME_ARCHIVE_FILES, - wasixExtensionAotPackageName, -} from "./wasix-cargo-artifact-contract.mjs"; -import { canonicalWasixAotMetadata } from "./wasix-aot-manifest.mjs"; -import { canonicalGzipSync } from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const directories = []; - -afterAll(() => { - for (const directory of directories) rmSync(directory, { recursive: true, force: true }); -}); - -function run(command, args, { cwd = ROOT, env = process.env } = {}) { - const result = spawnSync(command, args, { - cwd, - env, - encoding: "utf8", - maxBuffer: 200 * 1024 * 1024, - stdio: ["ignore", "pipe", "pipe"], - }); - expect(result.status, `${command} ${args.join(" ")} failed:\n${result.stdout}\n${result.stderr}`).toBe(0); - return result; -} - -function supportedRustcHostTriple() { - const { stdout } = run("rustc", ["--print", "host-tuple"]); - const outputLines = stdout - .split(/\r?\n/u) - .map((line) => line.trim()) - .filter((line) => line.length > 0); - if (outputLines.length !== 1) { - throw new Error(`rustc --print host-tuple returned unexpected output:\n${stdout}`); - } - const [hostTriple] = outputLines; - const supportedTriples = [...new Set(Object.values(AOT_TARGET_TRIPLES))].sort(); - if (!supportedTriples.includes(hostTriple)) { - throw new Error( - `rustc host triple ${JSON.stringify(hostTriple)} is not a supported WASIX AOT target; expected one of ${supportedTriples.join(", ")}`, - ); - } - return hostTriple; -} - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function sha256Bytes(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function tarOctal(value, length) { - return Buffer.from(`${value.toString(8).padStart(length - 1, "0")}\0`, "ascii"); -} - -function adversarialTar(rows) { - const records = []; - for (const row of rows) { - const data = Buffer.from(row.data ?? ""); - const header = Buffer.alloc(512); - Buffer.from(row.name).copy(header, 0); - tarOctal(row.mode ?? 0o644, 8).copy(header, 100); - tarOctal(0, 8).copy(header, 108); - tarOctal(0, 8).copy(header, 116); - tarOctal(data.length, 12).copy(header, 124); - tarOctal(0, 12).copy(header, 136); - header.fill(0x20, 148, 156); - header[156] = (row.type ?? "0").charCodeAt(0); - if (row.link) Buffer.from(`${row.link}\0`).copy(header, 157); - Buffer.from("ustar\0", "binary").copy(header, 257); - Buffer.from("00").copy(header, 263); - const checksum = header.reduce((sum, byte) => sum + byte, 0); - Buffer.from(`${checksum.toString(8).padStart(6, "0")}\0 `, "ascii").copy(header, 148); - records.push(header, data, Buffer.alloc((512 - (data.length % 512)) % 512)); - } - return Buffer.concat([...records, Buffer.alloc(1024)]); -} - -function adversarialTarGz(rows) { - return gzipSync(adversarialTar(rows), { mtime: 0 }); -} - -function aggregateFixture(root, { nestedOwner = false } = {}) { - const product = "oliphaunt-extension-contrib-pg18"; - const version = extensionReleaseVersion(product, "wasix", "package-liboliphaunt-wasix-cargo-artifacts.test"); - const releaseProduct = extensionReleaseProduct(product, "wasix", "package-liboliphaunt-wasix-cargo-artifacts.test"); - const productRoot = path.join(root, ...(nestedOwner ? [releaseProduct, product] : [product])); - const releaseAssets = path.join(productRoot, "release-assets"); - const archiveRoot = `${product}-${version}-wasix-wasix-portable-bundle`; - const carrierName = `${archiveRoot}.tar.gz`; - const stage = path.join(root, "stage", archiveRoot); - const extensions = []; - const sqlNames = extensionSqlNames(product, "package-liboliphaunt-wasix-cargo-artifacts.test"); - for (const sqlName of sqlNames) { - const name = `${product}-${version}-wasix-portable.tar.zst`; - const memberPath = `extensions/${sqlName}/${name}`; - const file = path.join(stage, ...memberPath.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, Buffer.from(`${sqlName}:`.repeat(20))); - extensions.push({ - sqlName, - dependencies: sqlName === "earthdistance" ? ["cube"] : [], - nativeModuleStem: ["cube", "earthdistance"].includes(sqlName) ? sqlName : null, - assets: [{ - name, - family: "wasix", - target: "wasix-portable", - kind: "wasix-runtime", - identity: null, - path: file, - sha256: sha256(file), - bytes: statSync(file).size, - carrierAsset: carrierName, - carrierRoot: archiveRoot, - memberPath, - }], - }); - } - mkdirSync(releaseAssets, { recursive: true }); - const carrier = path.join(releaseAssets, carrierName); - writeFileSync(carrier, canonicalGzipSync(createDeterministicTar(stage, archiveRoot, { - fail(message) { - throw new Error(message); - }, - fixedFileMode: 0o644, - }))); - writeFileSync(path.join(productRoot, "extension-artifacts.json"), `${JSON.stringify({ - schema: "oliphaunt-extension-ci-artifacts-v2", - product, - releaseProduct, - family: "wasix", - version, - extensions, - carrierAssets: [{ - name: carrierName, - family: "wasix", - target: "wasix-portable", - kind: "extension-bundle", - sha256: sha256(carrier), - bytes: statSync(carrier).size, - memberCount: sqlNames.length, - }], - }, null, 2)}\n`); - const canonicalAot = canonicalWasixAotMetadata(); - for (const [targetId, targetTriple] of Object.entries(AOT_TARGET_TRIPLES)) { - for (const sqlName of ["cube", "earthdistance"]) { - const directory = path.join(productRoot, "wasix-aot", targetId, sqlName); - const artifactName = `${sqlName}.bin.zst`; - const artifact = path.join(directory, artifactName); - const raw = Buffer.concat(Array.from( - { length: 64 }, - (_, index) => createHash("sha256").update(`${targetTriple}:${sqlName}:${index}`).digest(), - )); - const compressed = zstdCompressSync(raw); - mkdirSync(directory, { recursive: true }); - writeFileSync(artifact, compressed); - writeFileSync(path.join(directory, "manifest.json"), `${JSON.stringify({ - "format-version": 1, - "source-lane": canonicalAot.sourceLane, - "engine": canonicalAot.engine, - "wasmer-version": canonicalAot.wasmerVersion, - "wasmer-wasix-version": canonicalAot.wasmerWasixVersion, - "target-triple": targetTriple, - artifacts: [{ - name: `extension:${sqlName}`, - path: artifactName, - sha256: sha256(artifact), - "raw-sha256": sha256Bytes(raw), - "raw-size": raw.length, - "module-sha256": sha256Bytes(Buffer.from(`module:${sqlName}`)), - compressed: true, - }], - }, null, 2)}\n`); - } - } - return productRoot; -} - -describe("aggregate WASIX Cargo artifact packaging", () => { - test("runtime source build resolves runtime-owned contrib archives and AOT under the WASIX owner", { - timeout: 180_000, - }, () => { - const root = mkdtempSync(path.join(ROOT, "target/wasix-nested-owner-build-test-")); - directories.push(root); - const productRoot = aggregateFixture(root, { nestedOwner: true }); - const manifest = JSON.parse(readFileSync(path.join(productRoot, "extension-artifacts.json"), "utf8")); - const cube = manifest.extensions.find((row) => row.sqlName === "cube"); - const archive = path.join(productRoot, "member-assets", "cube", cube.assets[0].name); - mkdirSync(path.dirname(archive), { recursive: true }); - cpSync(cube.assets[0].path, archive); - - const hostTriple = supportedRustcHostTriple(); - const app = path.join(root, "app"); - mkdirSync(path.join(app, "src"), { recursive: true }); - writeFileSync(path.join(app, "Cargo.toml"), `[package] -name = "wasix-nested-owner-proof" -version = "0.0.0" -edition = "2024" - -[dependencies] -liboliphaunt-wasix-portable = { path = ${JSON.stringify(path.join(ROOT, "src/runtimes/liboliphaunt/wasix/crates/assets"))}, features = ["extension-cube"] } - -[workspace] -`); - writeFileSync(path.join(app, "src/main.rs"), `fn main() { - assert!(liboliphaunt_wasix_portable::extension_archive("cube").is_some()); - assert!(liboliphaunt_wasix_portable::extension_aot_manifest_json(${JSON.stringify(hostTriple)}, "cube").is_some()); -} -`); - run("cargo", ["run", "--manifest-path", path.join(app, "Cargo.toml")], { - env: { - ...process.env, - CARGO_TARGET_DIR: path.join(root, "cargo-target"), - OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT: root, - }, - }); - }); - - test("streams nested portable archives larger than spawnSync's default buffer", () => { - const root = mkdtempSync(path.join(ROOT, "target/wasix-aggregate-stream-test-")); - directories.push(root); - const carrierRoot = "aggregate-carrier"; - const member = `${carrierRoot}/extensions/pgcrypto/extension.tar.zst`; - const source = path.join(root, "stage", ...member.split("/")); - const expected = Buffer.alloc(2 * 1024 * 1024 + 17, 0x5a); - mkdirSync(path.dirname(source), { recursive: true }); - writeFileSync(source, expected); - const carrier = path.join(root, "carrier.tar.gz"); - run("tar", ["--format", "ustar", "-czf", carrier, "-C", path.join(root, "stage"), carrierRoot], { - env: { ...process.env, COPYFILE_DISABLE: "1" }, - }); - - const destination = path.join(root, "materialized", "extension.tar.zst"); - extractArchiveMemberToFile(carrier, member, destination); - expect(readFileSync(destination)).toEqual(expected); - }); - - test("rejects duplicate and symlink carrier entries before materializing a member", () => { - const root = mkdtempSync(path.join(ROOT, "target/wasix-aggregate-adversarial-test-")); - directories.push(root); - - const duplicate = path.join(root, "duplicate.tar.gz"); - writeFileSync(duplicate, adversarialTarGz([ - { name: "payload.bin", data: "first\n" }, - { name: "payload.bin", data: "second\n" }, - ])); - const duplicateDestination = path.join(root, "duplicate-output.bin"); - expect(() => extractArchiveMemberToFile(duplicate, "payload.bin", duplicateDestination)) - .toThrow(/repeats archive member payload[.]bin/u); - expect(() => statSync(duplicateDestination)).toThrow(); - - const linked = path.join(root, "linked.tar.gz"); - writeFileSync(linked, adversarialTarGz([ - { name: "payload-link", type: "2", link: "payload.bin" }, - ])); - const linkedDestination = path.join(root, "linked-output.bin"); - expect(() => extractArchiveMemberToFile(linked, "payload-link", linkedDestination)) - .toThrow(/link or special ustar entry/u); - expect(() => statSync(linkedDestination)).toThrow(); - }); - - test("direct tar.zst materialization preserves exact modes despite umask and read-only directories", () => { - if (process.platform === "win32") return; - const root = mkdtempSync(path.join(ROOT, "target/wasix-materialization-mode-test-")); - directories.push(root); - const archive = path.join(root, "payload.tar.zst"); - const expected = Buffer.from("executable payload\n"); - writeFileSync(archive, zstdCompressSync(adversarialTar([ - { name: "payload/", type: "5", mode: 0o555 }, - { name: "payload/read-only/", type: "5", mode: 0o500 }, - { name: "payload/read-only/tool", mode: 0o751, data: expected }, - ]))); - - const destination = path.join(root, "extracted"); - const previousUmask = process.umask(0o077); - try { - extractTarZstd(archive, destination); - } finally { - process.umask(previousUmask); - } - - const payload = path.join(destination, "payload"); - const readOnly = path.join(payload, "read-only"); - const executable = path.join(readOnly, "tool"); - expect(statSync(payload).mode & 0o777).toBe(0o555); - expect(statSync(readOnly).mode & 0o777).toBe(0o500); - expect(statSync(executable).mode & 0o777).toBe(0o751); - expect(readFileSync(executable)).toEqual(expected); - - // Restore cleanup access after proving the final archived modes. - chmodSync(payload, 0o755); - chmodSync(readOnly, 0o755); - }); - - test("package-side runtime validation binds the manifest to strict nested bytes", () => { - const root = mkdtempSync(path.join(ROOT, "target/wasix-runtime-validation-test-")); - directories.push(root); - const runtimeSource = path.join(root, "runtime-source", "oliphaunt"); - for (const member of CORE_RUNTIME_ARCHIVE_FILES) { - const relative = member.replace(/^oliphaunt\//u, ""); - const file = path.join(runtimeSource, relative); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, `${relative}\n`); - } - const runtimeBytes = zstdCompressSync(createDeterministicTar(runtimeSource, "oliphaunt", { - fail(message) { - throw new Error(message); - }, - fixedFileMode: 0o644, - })); - - const payload = path.join(root, "payload"); - mkdirSync(path.join(payload, "bin"), { recursive: true }); - mkdirSync(path.join(payload, "cluster-seeds"), { recursive: true }); - writeFileSync(path.join(payload, "bin/initdb.wasix.wasm"), "initdb-wasm\n"); - for (const profile of ["standard", "icu"]) { - writeFileSync(path.join(payload, `cluster-seeds/${profile}.tar.zst`), `${profile}\n`); - writeFileSync(path.join(payload, `cluster-seeds/${profile}.json`), "{}\n"); - } - writeFileSync(path.join(payload, "oliphaunt.wasix.tar.zst"), runtimeBytes); - const manifestPath = path.join(payload, "manifest.json"); - const manifest = { - runtime: { - archive: "oliphaunt.wasix.tar.zst", - sha256: sha256Bytes(runtimeBytes), - }, - extensions: [], - }; - writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); - expect(() => validateRuntimePayload(payload)).not.toThrow(); - - manifest.runtime.sha256 = "0".repeat(64); - writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); - expect(() => validateRuntimePayload(payload)).toThrow(/runtime[.]sha256 mismatch/u); - - const concatenated = Buffer.concat([runtimeBytes, runtimeBytes]); - writeFileSync(path.join(payload, "oliphaunt.wasix.tar.zst"), concatenated); - manifest.runtime.sha256 = sha256Bytes(concatenated); - writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); - expect(() => validateRuntimePayload(payload)) - .toThrow(/trailing data or multiple Zstandard frames/u); - }); - - test("extension packaging rejects AOT raw-digest tampering before Cargo packaging", () => { - const root = mkdtempSync(path.join(ROOT, "target/wasix-extension-aot-tamper-test-")); - directories.push(root); - const extensionRoot = aggregateFixture(root); - const targetId = Object.keys(AOT_TARGET_TRIPLES).sort()[0]; - const manifestPath = path.join( - extensionRoot, - "wasix-aot", - targetId, - "cube", - "manifest.json", - ); - const manifest = JSON.parse(readFileSync(manifestPath, "utf8")); - manifest.artifacts[0]["raw-sha256"] = "0".repeat(64); - writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); - - const result = spawnSync("bun", [ - "tools/release/package_liboliphaunt_wasix_cargo_artifacts.mjs", - "--extensions-only", - "--extension-artifact-root", extensionRoot, - "--output-dir", path.join(root, "output"), - "--work-dir", path.join(root, "work"), - "--version", "0.1.0", - ], { - cwd: ROOT, - encoding: "utf8", - stdio: ["ignore", "pipe", "pipe"], - }); - expect(result.status).not.toBe(0); - expect(`${result.stdout}\n${result.stderr}`).toMatch(/raw SHA-256 mismatch/u); - }); - - test("splits from part-001 and a single carrier feature selects earthdistance plus cube only", { - timeout: 180_000, - }, () => { - const root = mkdtempSync(path.join(ROOT, "target/wasix-aggregate-cargo-test-")); - directories.push(root); - const extensionRoot = aggregateFixture(root); - const output = path.join(root, "output"); - const work = path.join(root, "work"); - const cargoHome = path.join(root, "empty-cargo-home"); - mkdirSync(cargoHome); - run("bun", [ - "tools/release/package_liboliphaunt_wasix_cargo_artifacts.mjs", - "--extensions-only", - "--extension-artifact-root", extensionRoot, - "--extension-part-bytes", "256", - "--output-dir", output, - "--work-dir", work, - "--version", "0.1.0", - ], { - env: { - ...process.env, - CARGO_HOME: cargoHome, - CARGO_NET_OFFLINE: "true", - }, - }); - - const sources = path.join(work, "cargo-package-sources"); - expect(statSync(path.join(work, "cargo-package-extracted")).isDirectory()).toBe(true); - expect(statSync(path.join(work, "cargo-package-target")).isDirectory()).toBe(true); - const carrierName = "oliphaunt-extension-contrib-pg18-wasix"; - const extensionVersion = extensionReleaseVersion( - "oliphaunt-extension-contrib-pg18", - "wasix", - "package-liboliphaunt-wasix-cargo-artifacts.test", - ); - const carrierManifest = Bun.TOML.parse(readFileSync(path.join(sources, carrierName, "Cargo.toml"), "utf8")); - expect(carrierManifest["build-dependencies"].sha2).toBeUndefined(); - const carrierBuildScript = readFileSync(path.join(sources, carrierName, "build.rs"), "utf8"); - expect(carrierBuildScript).not.toContain("use sha2"); - expect(carrierBuildScript).toContain("fn sha256_compress"); - const partNames = Object.keys(carrierManifest["build-dependencies"]) - .filter((name) => name.startsWith(`${carrierName}-part-`)) - .sort(); - expect(partNames.length).toBeGreaterThan(1); - expect(partNames[0]).toBe(`${carrierName}-part-001`); - expect(partNames).toEqual(partNames.map((_, index) => `${carrierName}-part-${String(index + 1).padStart(3, "0")}`)); - expect(partNames.every((name) => name.length <= 64)).toBe(true); - - const runtimeName = "liboliphaunt-wasix-portable"; - const runtimeSource = path.join(sources, runtimeName); - cpSync(path.join(ROOT, "src/runtimes/liboliphaunt/wasix/crates/assets"), runtimeSource, { - recursive: true, - filter: (source) => !["target", "payload", "artifacts"].includes(path.basename(source)), - }); - const members = extensionSqlNames("oliphaunt-extension-contrib-pg18", "package-liboliphaunt-wasix-cargo-artifacts.test") - .map((sqlName) => ({ sqlName, dependencies: sqlName === "earthdistance" ? ["cube"] : [] })); - const runtimeCargoToml = path.join(runtimeSource, "Cargo.toml"); - const aotSources = Object.values(AOT_TARGET_TRIPLES).map((target) => ({ spec: { - name: wasixExtensionAotPackageName("oliphaunt-extension-contrib-pg18", target), - product: "oliphaunt-extension-contrib-pg18", - target, - dependencyRequirement: `=${extensionVersion}`, - } })); - writeFileSync(runtimeCargoToml, injectRuntimeExtensionDependencies( - readFileSync(runtimeCargoToml, "utf8"), - [{ spec: { - name: carrierName, - product: "oliphaunt-extension-contrib-pg18", - dependencyRequirement: `=${extensionVersion}`, - members, - } }], - aotSources, - )); - const runtimeManifest = Bun.TOML.parse(readFileSync(runtimeCargoToml, "utf8")); - expect(Object.keys(runtimeManifest.dependencies).filter((name) => name === carrierName)).toEqual([carrierName]); - expect(runtimeManifest.features["extension-earthdistance"]).toEqual([ - "extension-cube", - `dep:${carrierName}`, - ...aotSources.map((source) => `dep:${source.spec.name}`).sort(), - ]); - expect(runtimeManifest.features["extension-cube"]).toEqual([ - `dep:${carrierName}`, - ...aotSources.map((source) => `dep:${source.spec.name}`).sort(), - ]); - expect(runtimeManifest.features["extension-hstore"]).toEqual([ - `dep:${carrierName}`, - ...aotSources.map((source) => `dep:${source.spec.name}`).sort(), - ]); - - const hostTriple = supportedRustcHostTriple(); - const app = path.join(root, "app"); - mkdirSync(path.join(app, "src"), { recursive: true }); - writeFileSync(path.join(app, "Cargo.toml"), `[package] -name = "wasix-selection-proof" -version = "0.0.0" -edition = "2024" - -[dependencies] -liboliphaunt-wasix-portable = { path = ${JSON.stringify(path.join(sources, runtimeName))}, features = ["extension-earthdistance"] } - -[workspace] -`); - writeFileSync(path.join(app, "src/main.rs"), `fn main() { - let selected = liboliphaunt_wasix_portable::SELECTED_EXTENSION_SQL_NAMES; - assert!(selected.contains(&"earthdistance")); - assert!(selected.contains(&"cube")); - assert!(!selected.contains(&"hstore")); - assert!(liboliphaunt_wasix_portable::extension_archive("earthdistance").is_some()); - assert!(liboliphaunt_wasix_portable::extension_archive("cube").is_some()); - assert!(liboliphaunt_wasix_portable::extension_archive("hstore").is_none()); - assert!(liboliphaunt_wasix_portable::SELECTED_EXTENSION_AOT_SQL_NAMES.contains(&"earthdistance")); - assert!(liboliphaunt_wasix_portable::SELECTED_EXTENSION_AOT_SQL_NAMES.contains(&"cube")); - assert!(!liboliphaunt_wasix_portable::SELECTED_EXTENSION_AOT_SQL_NAMES.contains(&"hstore")); - assert!(liboliphaunt_wasix_portable::extension_aot_manifest_json(${JSON.stringify(hostTriple)}, "earthdistance").is_some()); - assert!(liboliphaunt_wasix_portable::extension_aot_manifest_json(${JSON.stringify(hostTriple)}, "cube").is_some()); - assert!(liboliphaunt_wasix_portable::extension_aot_manifest_json(${JSON.stringify(hostTriple)}, "hstore").is_none()); -} -`); - run("cargo", ["run", "--manifest-path", path.join(app, "Cargo.toml")], { - env: { ...process.env, CARGO_TARGET_DIR: path.join(root, "cargo-target") }, - }); - - const packages = JSON.parse(readFileSync(path.join(output, "packages.json"), "utf8")).packages; - expect(packages.filter((row) => row.name.startsWith(`${carrierName}-part-`)).length).toBe(partNames.length); - for (const target of Object.values(AOT_TARGET_TRIPLES)) { - const parent = wasixExtensionAotPackageName("oliphaunt-extension-contrib-pg18", target); - expect(packages.some((row) => row.name === parent)).toBe(true); - expect(packages.some((row) => row.name === `${parent}-part-001`)).toBe(true); - } - expect(packages.every((row) => row.size <= 10 * 1024 * 1024)).toBe(true); - }); -}); diff --git a/tools/release/package-liboliphaunt-windows-assets.ps1 b/tools/release/package-liboliphaunt-windows-assets.ps1 deleted file mode 100644 index e83cbbbec..000000000 --- a/tools/release/package-liboliphaunt-windows-assets.ps1 +++ /dev/null @@ -1,289 +0,0 @@ -param() - -$ErrorActionPreference = "Stop" -Set-StrictMode -Version Latest - -$Root = git rev-parse --show-toplevel -if ($LASTEXITCODE -ne 0 -or -not $Root) { - $Root = (Get-Location).Path -} -Set-Location $Root - -function Fail($Message) { - Write-Error "package-liboliphaunt-windows-assets.ps1: $Message" - exit 1 -} - -function Assert-BaseRuntimeHasNoOptionalExtensions($CatalogFile, $RuntimeRoot) { - $extensionDir = Join-Path $RuntimeRoot "share/postgresql/extension" - $moduleDir = Join-Path $RuntimeRoot "lib/postgresql" - $failures = New-Object System.Collections.Generic.List[string] - $rows = Get-Content $CatalogFile | Select-Object -Skip 1 - foreach ($row in $rows) { - if (-not $row) { - continue - } - $columns = $row -split "`t", 12 - if ($columns.Count -lt 12) { - Fail "malformed extension catalog row in $CatalogFile`: $row" - } - $sqlName = $columns[0] - $stem = $columns[3] - $dataFiles = $columns[10] - if (Test-Path (Join-Path $extensionDir "$sqlName.control")) { - $failures.Add("control:$sqlName") | Out-Null - } - if ($stem -and $stem -ne "-") { - foreach ($suffix in @("dll", "so", "dylib")) { - if (Test-Path (Join-Path $moduleDir "$stem.$suffix")) { - $failures.Add("module:$stem.$suffix") | Out-Null - } - } - } - if ($dataFiles -and $dataFiles -ne "-") { - foreach ($dataFile in $dataFiles.Split(",")) { - if ($dataFile -and (Test-Path (Join-Path (Join-Path $RuntimeRoot "share/postgresql") $dataFile))) { - $failures.Add("data:$dataFile") | Out-Null - } - } - } - } - if ($failures.Count -gt 0) { - $joined = [string]::Join(", ", $failures) - Fail "base Windows liboliphaunt runtime contains optional extension artifact(s): $joined" - } -} - -if (-not $IsWindows) { - Fail "Windows liboliphaunt release assets must be built on Windows" -} - -if (-not (Get-Command bun -ErrorAction SilentlyContinue)) { - Fail "missing required command: bun" -} - -if ($env:OLIPHAUNT_RELEASE_FETCH_ASSETS -ne "0") { - Write-Output "==> Fetching pinned source assets" - bun src/sources/tools/fetch-sources.mjs native-runtime *> "$env:TEMP\liboliphaunt-release-windows-assets-fetch.log" - if ($LASTEXITCODE -ne 0) { - Fail "failed to fetch pinned source assets" - } -} - -$Version = bun tools/release/product-version.mjs version liboliphaunt-native -if ($LASTEXITCODE -ne 0 -or -not $Version) { - Fail "failed to read liboliphaunt version" -} -$Version = $Version.Trim() -$TargetId = "windows-x64-msvc" -$OutDir = if ($env:OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS) { - $env:OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSETS -} else { - Join-Path $Root "target/liboliphaunt/release-assets" -} -$StageRoot = Join-Path $Root "target/liboliphaunt/release-stage-$TargetId" -$CatalogFile = Join-Path $StageRoot "extension-catalog.tsv" -$WorkRoot = if ($env:OLIPHAUNT_WINDOWS_WORK_ROOT) { - $env:OLIPHAUNT_WINDOWS_WORK_ROOT -} elseif ($env:OLIPHAUNT_WORK_ROOT) { - $env:OLIPHAUNT_WORK_ROOT -} else { - Join-Path $Root "target/liboliphaunt-pg18-$TargetId" -} -$HeadersDir = Join-Path $Root "src/runtimes/liboliphaunt/native/include" -$Dll = Join-Path $WorkRoot "out/bin/oliphaunt.dll" -$ImportLib = Join-Path $WorkRoot "out/lib/oliphaunt.lib" -$EmbeddedModules = Join-Path $WorkRoot "out/modules" -$Runtime = Join-Path $WorkRoot "install" -$Stage = Join-Path $StageRoot "liboliphaunt-$Version-$TargetId" -$Asset = "liboliphaunt-$Version-$TargetId.zip" -$ToolsStage = Join-Path $StageRoot "oliphaunt-tools-$Version-$TargetId" -$ToolsAsset = "oliphaunt-tools-$Version-$TargetId.zip" -$VcRuntimeClosureTool = Join-Path $Root "tools/release/windows-vc-runtime-closure.mjs" - -Remove-Item -Recurse -Force $StageRoot -ErrorAction SilentlyContinue -New-Item -ItemType Directory -Force -Path $OutDir, (Join-Path $Stage "include"), (Join-Path $Stage "bin"), (Join-Path $Stage "lib"), (Join-Path $Stage "lib/modules"), (Join-Path $Stage "runtime"), (Join-Path $ToolsStage "runtime/bin") | Out-Null - -if ($env:OLIPHAUNT_RELEASE_BUILD_RUNTIME -ne "0") { - Write-Output "==> Building liboliphaunt $TargetId" - pwsh -NoProfile -ExecutionPolicy Bypass -File src/runtimes/liboliphaunt/native/bin/build-postgres18-windows.ps1 *> "$env:TEMP\liboliphaunt-release-$TargetId.log" - if ($LASTEXITCODE -ne 0) { - Get-Content "$env:TEMP\liboliphaunt-release-$TargetId.log" -Tail 160 | Write-Error - Fail "failed to build liboliphaunt $TargetId" - } -} - -if (-not (Test-Path $Dll)) { - Fail "missing Windows liboliphaunt DLL at $Dll" -} -if (-not (Test-Path $ImportLib)) { - Fail "missing Windows liboliphaunt import library at $ImportLib" -} -if (-not (Test-Path -LiteralPath $EmbeddedModules -PathType Container)) { - Fail "missing Windows embedded module directory at $EmbeddedModules" -} -$EmbeddedModulesInfo = Get-Item -LiteralPath $EmbeddedModules -if (($EmbeddedModulesInfo.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) { - Fail "Windows embedded module directory must not be a reparse point: $EmbeddedModules" -} -$EmbeddedModuleEntries = @(Get-ChildItem -LiteralPath $EmbeddedModules -Force) -$EmbeddedModuleNames = @($EmbeddedModuleEntries | ForEach-Object { $_.Name } | Sort-Object) -$ExpectedEmbeddedModuleNames = @("dict_snowball.dll", "plpgsql.dll") -$EmbeddedModuleDifferences = @( - Compare-Object -ReferenceObject $ExpectedEmbeddedModuleNames -DifferenceObject $EmbeddedModuleNames -CaseSensitive -) -if ($EmbeddedModuleNames.Count -ne $ExpectedEmbeddedModuleNames.Count -or - $EmbeddedModuleDifferences.Count -ne 0) { - $EmbeddedModuleNames = [string]::Join(", ", @($EmbeddedModuleEntries | ForEach-Object { $_.Name })) - Fail "base Windows embedded module inventory must contain exactly dict_snowball.dll and plpgsql.dll; found: $EmbeddedModuleNames" -} -foreach ($EmbeddedModule in $EmbeddedModuleEntries) { - if (-not ($EmbeddedModule -is [System.IO.FileInfo]) -or - ($EmbeddedModule.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) { - Fail "Windows embedded module must be a regular non-link file: $($EmbeddedModule.FullName)" - } -} -foreach ($Tool in @("initdb.exe", "pg_basebackup.exe", "pg_ctl.exe", "pg_dump.exe", "postgres.exe", "psql.exe")) { - $ToolPath = Join-Path (Join-Path $Runtime "bin") $Tool - if (-not (Test-Path $ToolPath)) { - Fail "missing Windows $Tool at $ToolPath" - } -} - -Write-Output "==> Verifying base liboliphaunt $TargetId runtime is extension-clean" -cargo run -p oliphaunt-native-packaging --bin oliphaunt-resources --locked -- --list-extensions > $CatalogFile -if ($LASTEXITCODE -ne 0) { - Fail "failed to read exact extension catalog" -} -Assert-BaseRuntimeHasNoOptionalExtensions $CatalogFile $Runtime - -Copy-Item -Recurse -Force (Join-Path $HeadersDir "*") (Join-Path $Stage "include") -Copy-Item -Force $Dll (Join-Path $Stage "bin") -foreach ($IcuDll in @("icudt76.dll", "icuin76.dll", "icuuc76.dll")) { - $IcuDllPath = Join-Path $WorkRoot "out/bin/$IcuDll" - if (-not (Test-Path -LiteralPath $IcuDllPath -PathType Leaf)) { - Fail "missing Windows ICU runtime DLL at $IcuDllPath" - } - Copy-Item -LiteralPath $IcuDllPath -Destination (Join-Path $Stage "bin/$IcuDll") -Force -} -Copy-Item -Force $ImportLib (Join-Path $Stage "lib") -Copy-Item -Recurse -Force (Join-Path $EmbeddedModules "*") (Join-Path $Stage "lib/modules") -Copy-Item -Recurse -Force (Join-Path $Runtime "*") (Join-Path $Stage "runtime") -& bun $VcRuntimeClosureTool stage ` - --root $Stage ` - --source-dir (Join-Path $WorkRoot "out/bin") ` - --profile provider ` - --destination (Join-Path $Stage "bin") ` - --destination (Join-Path $Stage "runtime/bin") -if ($LASTEXITCODE -ne 0) { - Fail "failed to stage the app-local VC runtime beside oliphaunt.dll" -} -foreach ($Tool in @("pg_basebackup.exe", "pg_dump.exe", "psql.exe")) { - Copy-Item -Force (Join-Path (Join-Path $Runtime "bin") $Tool) (Join-Path (Join-Path $ToolsStage "runtime/bin") $Tool) - Remove-Item -Force (Join-Path (Join-Path $Stage "runtime/bin") $Tool) -} -& bun $VcRuntimeClosureTool stage ` - --root $ToolsStage ` - --source-dir (Join-Path $Runtime "bin") ` - --destination (Join-Path $ToolsStage "runtime/bin") -if ($LASTEXITCODE -ne 0) { - Fail "failed to stage the app-local VC runtime beside the split client tools" -} -$StagedIcu = Join-Path $Stage "runtime/share/icu" -if (Test-Path $StagedIcu) { - Remove-Item -Recurse -Force $StagedIcu -} -& bun tools/release/stage-native-cluster-seed.mjs ` - --runtime $Runtime ` - --destination (Join-Path $Stage "cluster-seed") ` - --target $TargetId ` - --profile standard -if ($LASTEXITCODE -ne 0) { - Fail "failed to stage the standard native cluster seed" -} -$IcuData = Join-Path $WorkRoot "icu/share/icu" -& bun tools/release/stage-native-cluster-seed.mjs ` - --runtime $Runtime ` - --destination (Join-Path $Stage "cluster-seed-icu") ` - --target $TargetId ` - --profile icu ` - --icu-data $IcuData -if ($LASTEXITCODE -ne 0) { - Fail "failed to stage the ICU native cluster seed" -} -& bun tools/release/finalize-native-runtime-carrier.mjs ` - --root $Stage ` - --target $TargetId ` - --icu-data $IcuData ` - --runtime-source $Runtime ` - --embedded-modules $EmbeddedModules -if ($LASTEXITCODE -ne 0) { - Fail "failed to validate the native runtime carrier" -} - -Write-Output "==> Optimizing staged liboliphaunt $TargetId release payload" -bun tools/release/optimize_native_runtime_payload.mjs $Stage --target $TargetId --tool-set runtime -if ($LASTEXITCODE -ne 0) { - Fail "failed to optimize staged Windows liboliphaunt release payload" -} - -Write-Output "==> Optimizing staged oliphaunt-tools $TargetId release payload" -bun tools/release/optimize_native_runtime_payload.mjs $ToolsStage --target $TargetId --tool-set tools -if ($LASTEXITCODE -ne 0) { - Fail "failed to optimize staged Windows oliphaunt-tools release payload" -} - -Write-Output "==> Verifying staged $TargetId binary compatibility" -bun tools/release/platform-binary-contract.mjs --target $TargetId --root $Stage --require-windows-runtime-import-library --windows-vc-runtime-profile provider -if ($LASTEXITCODE -ne 0) { - Fail "staged Windows liboliphaunt binaries violate the release compatibility contract" -} -bun tools/release/platform-binary-contract.mjs --target $TargetId --root $ToolsStage -if ($LASTEXITCODE -ne 0) { - Fail "staged Windows oliphaunt-tools binaries violate the release compatibility contract" -} - -Write-Output "==> Smoke testing staged liboliphaunt $TargetId release layout" -$SmokeRoot = Join-Path $env:TEMP "liboliphaunt-release-smoke-$TargetId" -Remove-Item -Recurse -Force $SmokeRoot -ErrorAction SilentlyContinue -New-Item -ItemType Directory -Force -Path $SmokeRoot | Out-Null -$env:OLIPHAUNT_WORK_ROOT = $WorkRoot -$env:LIBOLIPHAUNT_PATH = Join-Path $Stage "bin/oliphaunt.dll" -$env:OLIPHAUNT_INSTALL_DIR = Join-Path $Stage "runtime" -$env:OLIPHAUNT_SMOKE_BIN_DIR = Join-Path $StageRoot "smoke-bin-$TargetId" -$env:OLIPHAUNT_SMOKE_ROOT = $SmokeRoot -$env:OLIPHAUNT_STANDARD_CLUSTER_SEED = Join-Path $Stage "cluster-seed" -$env:OLIPHAUNT_ICU_CLUSTER_SEED = Join-Path $Stage "cluster-seed-icu" -$env:OLIPHAUNT_ICU_DATA_DIR = $IcuData -node src/runtimes/liboliphaunt/native/tools/run-host-c-smoke.mjs --cluster-seeds -if ($LASTEXITCODE -ne 0) { - Fail "staged Windows liboliphaunt release smoke failed" -} - -bun tools/release/release-notices.mjs stage $Stage --profile native-runtime -if ($LASTEXITCODE -ne 0) { - Fail "failed to stage release notices in the Windows liboliphaunt asset" -} -bun tools/release/release-notices.mjs stage $ToolsStage --profile native-tools -if ($LASTEXITCODE -ne 0) { - Fail "failed to stage release notices in the Windows tools asset" -} - -bun src/shared/artifact-packaging/archive-directory.mjs $Stage (Join-Path $OutDir $Asset) -if ($LASTEXITCODE -ne 0) { - Fail "failed to archive Windows liboliphaunt asset" -} -bun src/shared/artifact-packaging/archive-directory.mjs $ToolsStage (Join-Path $OutDir $ToolsAsset) -if ($LASTEXITCODE -ne 0) { - Fail "failed to archive Windows oliphaunt-tools asset" -} -bun tools/release/release-notices.mjs check-archive (Join-Path $OutDir $Asset) --profile native-runtime -if ($LASTEXITCODE -ne 0) { - Fail "Windows liboliphaunt asset release notices failed validation" -} -bun tools/release/release-notices.mjs check-archive (Join-Path $OutDir $ToolsAsset) --profile native-tools -if ($LASTEXITCODE -ne 0) { - Fail "Windows tools asset release notices failed validation" -} -Write-Output "liboliphauntWindowsReleaseAsset=$(Join-Path $OutDir $Asset)" -Write-Output "oliphauntToolsWindowsReleaseAsset=$(Join-Path $OutDir $ToolsAsset)" diff --git a/tools/release/package-node-direct-runtime.sh b/tools/release/package-node-direct-runtime.sh deleted file mode 100644 index 44f42bd46..000000000 --- a/tools/release/package-node-direct-runtime.sh +++ /dev/null @@ -1,383 +0,0 @@ -#!/usr/bin/env sh -set -eu - -root="$(git rev-parse --show-toplevel 2>/dev/null)" || { - echo "must run inside the Oliphaunt git checkout" >&2 - exit 1 -} -cd "$root" - -require() { - if ! command -v "$1" >/dev/null 2>&1; then - echo "missing required command: $1" >&2 - exit 1 - fi -} - -require node -require pnpm -require bun -require tar - -case "$(uname -s)" in - Darwin) platform="macos" ;; - Linux) platform="linux" ;; - MINGW*|MSYS*|CYGWIN*) platform="windows" ;; - *) echo "unsupported Node direct adapter platform: $(uname -s)" >&2; exit 2 ;; -esac - -case "$(uname -m)" in - arm64|aarch64) arch="arm64" ;; - x86_64|amd64) arch="x64" ;; - *) echo "unsupported Node direct adapter architecture: $(uname -m)" >&2; exit 2 ;; -esac - -case "$platform:$arch" in - macos:arm64) target="macos-arm64" ;; - linux:x64) target="linux-x64-gnu" ;; - linux:arm64) target="linux-arm64-gnu" ;; - windows:x64) target="windows-x64-msvc" ;; - *) echo "unsupported Node direct adapter target: $platform/$arch" >&2; exit 2 ;; -esac - -if [ "$platform" = "macos" ]; then - MACOSX_DEPLOYMENT_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" - case "$MACOSX_DEPLOYMENT_TARGET" in - ""|*[!0-9.]*) - echo "MACOSX_DEPLOYMENT_TARGET must be a numeric dotted version" >&2 - exit 2 - ;; - esac - export MACOSX_DEPLOYMENT_TARGET -fi - -to_shell_path() { - if [ "$platform" = "windows" ] && command -v cygpath >/dev/null 2>&1; then - normalized="$(node -e 'process.stdout.write(process.argv[1].replace(/\\/g, "/"))' "$1")" - cygpath -u "$normalized" - else - printf '%s\n' "$1" - fi -} - -resolve_output_path() { - raw="$1" - case "$raw" in - /*|[A-Za-z]:/*|[A-Za-z]:\\*|\\\\*) ;; - *) raw="$root/$raw" ;; - esac - if [ "$platform" = "windows" ] && command -v cygpath >/dev/null 2>&1; then - cygpath -am "$raw" - else - printf '%s\n' "$raw" - fi -} - -tar_list_gzip() { - if [ "$platform" = "windows" ]; then - tar --force-local -tzf "$1" - else - tar -tzf "$1" - fi -} - -version="$(node -e "console.log(require('./src/runtimes/node-direct/package.json').version)")" -node_exec="$(to_shell_path "$(node -p "process.execPath")")" -node_bin_dir="$(dirname "$node_exec")" -node_root="$(dirname "$node_bin_dir")" -node_include="${NODE_INCLUDE_DIR:-}" -if [ -n "$node_include" ]; then - node_include="$(to_shell_path "$node_include")" -fi -if [ -z "$node_include" ]; then - for candidate in "$node_root/include/node" "$node_root/include"; do - if [ -f "$candidate/node_api.h" ]; then - node_include="$candidate" - break - fi - done -fi -if [ -z "$node_include" ]; then - node_include="$( - node -e ' -const path = require("node:path"); -try { - process.stdout.write(path.dirname(require.resolve("node-api-headers/include/node_api.h", { - paths: [process.cwd(), path.join(process.cwd(), "src/runtimes/node-direct")] - }))); -} catch { - process.exit(1); -} -' 2>/dev/null || true - )" - if [ -n "$node_include" ]; then - node_include="$(to_shell_path "$node_include")" - fi -fi -if [ -z "$node_include" ]; then - node_include="$( - sh tools/release/install-node-fallback.sh headers - )" - node_include="$(to_shell_path "$node_include")" -fi - -if [ ! -f "$node_include/node_api.h" ]; then - echo "missing node_api.h; set NODE_INCLUDE_DIR or install node-api-headers" >&2 - exit 2 -fi - -out_dir="$(resolve_output_path "${OLIPHAUNT_NODE_ADDON_OUT_DIR:-$root/target/oliphaunt-artifacts/node-direct/$target}")" -asset_dir="$(resolve_output_path "${OLIPHAUNT_NODE_ADDON_ASSET_OUT_DIR:-$root/target/oliphaunt-node-direct/release-assets}")" -npm_package_dir="$(resolve_output_path "${OLIPHAUNT_NODE_ADDON_NPM_PACKAGE_OUT_DIR:-$root/target/oliphaunt-node-direct/npm-packages}")" -npm_package_work_root="$(resolve_output_path "${OLIPHAUNT_NODE_ADDON_NPM_PACKAGE_WORK_DIR:-$root/target/oliphaunt-node-direct/npm-package-work/$target}")" -lifecycle_test_build_dir="$(resolve_output_path "${OLIPHAUNT_NODE_LIFECYCLE_ADDON_OUT_DIR:-$root/target/oliphaunt-node-direct/lifecycle-test-addon/$target}")" -src="src/runtimes/node-direct/native/node-addon/oliphaunt_node.cc" -addon="$out_dir/oliphaunt_node.node" -addon_file="$addon" -lifecycle_test_addon="$lifecycle_test_build_dir/oliphaunt_node.node" -lifecycle_test_addon_file="$lifecycle_test_addon" - -mkdir -p "$out_dir" "$asset_dir" "$npm_package_dir" "$lifecycle_test_build_dir" - -cxx="${CXX:-c++}" -oliphaunt_include="$root/src/runtimes/liboliphaunt/native/include" - -case "$platform" in - macos) - compile_addon() { - output="$1" - shift - "$cxx" -std=c++17 -O3 -DNAPI_VERSION=8 -DNODE_GYP_MODULE_NAME=oliphaunt_node \ - "$@" "-I$node_include" "-I$oliphaunt_include" -fPIC \ - "-mmacosx-version-min=$MACOSX_DEPLOYMENT_TARGET" -bundle -undefined dynamic_lookup \ - "$src" -o "$output" - } - compile_addon "$addon" - compile_addon "$lifecycle_test_addon" -DOLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING=1 - ;; - linux) - compile_addon() { - output="$1" - shift - "$cxx" -std=c++17 -O3 -DNAPI_VERSION=8 -DNODE_GYP_MODULE_NAME=oliphaunt_node \ - "$@" "-I$node_include" "-I$oliphaunt_include" -fPIC -shared \ - "$src" -ldl -o "$output" - } - compile_addon "$addon" - compile_addon "$lifecycle_test_addon" -DOLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING=1 - ;; - windows) - node_lib="${NODE_LIB:-}" - if [ -n "$node_lib" ]; then - node_lib="$(to_shell_path "$node_lib")" - fi - if [ -z "$node_lib" ]; then - for candidate in "$node_bin_dir/node.lib" "$node_root/x64/node.lib" "$node_root/lib/node.lib" "$node_root/node.lib"; do - if [ -f "$candidate" ]; then - node_lib="$candidate" - break - fi - done - fi - if [ -z "$node_lib" ]; then - case "$arch" in - x64) node_dist_arch="x64" ;; - arm64) node_dist_arch="arm64" ;; - *) echo "unsupported Node direct Windows architecture for node.lib: $arch" >&2; exit 2 ;; - esac - node_lib="$( - sh tools/release/install-node-fallback.sh windows-lib "$node_dist_arch" - )" - node_lib="$(to_shell_path "$node_lib")" - fi - if [ ! -f "$node_lib" ]; then - echo "missing node.lib; set NODE_LIB" >&2 - exit 2 - fi - cxx="${CXX:-cl}" - windows_build_dir="$root/target/oliphaunt-node-direct/native-build/$target" - rm -rf "$windows_build_dir" - mkdir -p "$windows_build_dir" - addon_object="$windows_build_dir/oliphaunt_node.obj" - addon_import_library="$windows_build_dir/oliphaunt_node.lib" - lifecycle_test_addon_object="$windows_build_dir/oliphaunt_node_lifecycle_test.obj" - lifecycle_test_addon_import_library="$windows_build_dir/oliphaunt_node_lifecycle_test.lib" - if command -v cygpath >/dev/null 2>&1; then - node_include="$(cygpath -w "$node_include")" - oliphaunt_include="$(cygpath -w "$oliphaunt_include")" - node_lib="$(cygpath -w "$node_lib")" - src="$(cygpath -w "$src")" - addon="$(cygpath -w "$addon")" - lifecycle_test_addon="$(cygpath -w "$lifecycle_test_addon")" - addon_object="$(cygpath -w "$addon_object")" - addon_import_library="$(cygpath -w "$addon_import_library")" - lifecycle_test_addon_object="$(cygpath -w "$lifecycle_test_addon_object")" - lifecycle_test_addon_import_library="$(cygpath -w "$lifecycle_test_addon_import_library")" - fi - compile_addon() { - output="$1" - object="$2" - import_library="$3" - shift 3 - "$cxx" //nologo //std:c++17 //O2 //EHsc //LD //DNAPI_VERSION=8 \ - //DNODE_GYP_MODULE_NAME=oliphaunt_node "$@" \ - "-I$node_include" "-I$oliphaunt_include" "$src" //Fo:"$object" \ - //link "$node_lib" //OUT:"$output" //IMPLIB:"$import_library" - } - compile_addon "$addon" "$addon_object" "$addon_import_library" - compile_addon \ - "$lifecycle_test_addon" \ - "$lifecycle_test_addon_object" \ - "$lifecycle_test_addon_import_library" \ - //DOLIPHAUNT_NODE_ADDON_LIFECYCLE_TESTING=1 - ;; -esac - -tools/dev/bun.sh tools/release/strip_native_release_binaries.mjs "$addon_file" - -node - "$addon_file" "$lifecycle_test_addon_file" <<'JS' -const { readFileSync } = require('node:fs'); -const addonPath = process.argv[2]; -const lifecycleTestAddonPath = process.argv[3]; -const addon = require(addonPath); -const expected = [ - 'version', - 'open', - 'execProtocolRaw', - 'execSimpleQuery', - 'execProtocolRawStream', - 'backup', - 'restore', - 'cancel', - 'detach', - 'createForgottenHandleRecoveryToken', - 'queueForgottenHandleRecovery', -].sort(); -const actual = Object.getOwnPropertyNames(addon).sort(); -if (JSON.stringify(actual) !== JSON.stringify(expected)) { - throw new Error( - `compiled Node direct addon exports ${JSON.stringify(actual)}; expected ${JSON.stringify(expected)}`, - ); -} -for (const name of expected) { - if (typeof addon[name] !== 'function') { - throw new Error(`Node direct export ${name} is not a function`); - } -} - -const productionBytes = readFileSync(addonPath); -const lifecycleTestBytes = readFileSync(lifecycleTestAddonPath); -const testPrefix = Buffer.from('OLIPHAUNT_NODE_CLEANUP_TEST_'); -if (productionBytes.includes(testPrefix)) { - throw new Error('production Node direct addon contains lifecycle-test controls'); -} -for (const control of [ - 'OLIPHAUNT_NODE_CLEANUP_TEST_DELAY_OPERATION_START', - 'OLIPHAUNT_NODE_CLEANUP_TEST_PAUSE_NATIVE_CALL_ENTRY', - 'OLIPHAUNT_NODE_CLEANUP_TEST_PREFILL_STREAM_QUEUE', -]) { - if (!lifecycleTestBytes.includes(Buffer.from(control))) { - throw new Error(`instrumented Node direct addon is missing ${control}`); - } -} -JS - -bash src/runtimes/node-direct/tools/test-node-addon-cleanup-lifecycle.sh \ - "$addon_file" \ - "$lifecycle_test_addon_file" - -if [ "$platform" = "windows" ]; then - asset="oliphaunt-node-direct-$version-$target.zip" -else - asset="oliphaunt-node-direct-$version-$target.tar.gz" -fi -asset_stage="$root/target/oliphaunt-node-direct/release-stage/$target" -rm -rf "$asset_stage" -mkdir -p "$asset_stage" -cp "$addon_file" "$asset_stage/oliphaunt_node.node" -tools/dev/bun.sh tools/release/release-notices.mjs stage "$asset_stage" --profile source-sdk -tools/dev/bun.sh tools/release/platform-binary-contract.mjs --target "$target" --root "$asset_stage" -if [ "$platform" = "linux" ]; then - tools/release/check-linux-consumer-baseline.sh --target "$target" --root "$asset_stage" -fi -src/shared/artifact-packaging/archive-directory.mjs "$asset_stage" "$asset_dir/$asset" - -input_dirs="${OLIPHAUNT_NODE_ADDON_ASSET_INPUT_DIRS:-${OLIPHAUNT_RELEASE_ASSET_INPUT_DIRS:-}}" -if [ -n "$input_dirs" ]; then - old_ifs="$IFS" - if [ "$platform" = "windows" ]; then - input_delimiter=';' - else - input_delimiter=':' - fi - IFS="$input_delimiter" - for input_dir in $input_dirs; do - IFS="$old_ifs" - [ -n "$input_dir" ] || continue - input_dir="$(to_shell_path "$input_dir")" - [ -d "$input_dir" ] || { - echo "release asset input directory does not exist: $input_dir" >&2 - exit 1 - } - find "$input_dir" -maxdepth 1 -type f \( -name 'oliphaunt-node-direct-*.tar.gz' -o -name 'oliphaunt-node-direct-*.zip' \) -print | - sort | - while IFS= read -r input_asset; do - [ -n "$input_asset" ] || continue - cp -p "$input_asset" "$asset_dir/" - done - IFS="$input_delimiter" - done - IFS="$old_ifs" -fi - -tools/release/write_checksum_manifest.mjs \ - --asset-dir "$asset_dir" \ - --output "oliphaunt-node-direct-$version-release-assets.sha256" \ - --pattern 'oliphaunt-node-direct-*.tar.gz' \ - --pattern 'oliphaunt-node-direct-*.zip' - -printf 'Node direct addon built and validated: %s\n' "$addon" -case "$target" in - macos-arm64) optional_package="darwin-arm64" ;; - linux-x64-gnu) optional_package="linux-x64-gnu" ;; - linux-arm64-gnu) optional_package="linux-arm64-gnu" ;; - windows-x64-msvc) optional_package="win32-x64-msvc" ;; - *) echo "unsupported Node direct optional npm package target: $target" >&2; exit 2 ;; -esac -package_source="$root/src/runtimes/node-direct/packages/$optional_package" -package_work="$npm_package_work_root/$optional_package" -rm -rf "$package_work" -mkdir -p "$package_work/prebuilds" -cp -R "$package_source/." "$package_work/" -rm -rf "$package_work/prebuilds" -mkdir -p "$package_work/prebuilds" -cp "$addon_file" "$package_work/prebuilds/oliphaunt_node.node" -tools/dev/bun.sh tools/release/release-notices.mjs stage "$package_work" --profile source-sdk -pack_json="$(pnpm --dir "$package_work" pack --pack-destination "$npm_package_dir" --json)" -printf '%s\n' "$pack_json" >"$npm_package_dir/$optional_package.pnpm-pack.json" -tarball="$( - PACK_JSON="$pack_json" PACK_DIR="$npm_package_dir" node <<'JS' -const path = require('node:path'); -const raw = JSON.parse(process.env.PACK_JSON || '[]'); -const entry = Array.isArray(raw) ? raw[0] : raw; -if (!entry || typeof entry.filename !== 'string' || !entry.filename.endsWith('.tgz')) { - throw new Error('pnpm pack did not report a .tgz filename'); -} -process.stdout.write(path.isAbsolute(entry.filename) ? entry.filename : path.join(process.env.PACK_DIR, entry.filename)); -JS -)" -tarball="$(to_shell_path "$tarball")" -[ -f "$tarball" ] || { - echo "pnpm pack did not create $tarball" >&2 - exit 1 -} -if ! tar_list_gzip "$tarball" | grep -Fxq "package/prebuilds/oliphaunt_node.node"; then - echo "Node direct optional npm package is missing prebuilds/oliphaunt_node.node: $tarball" >&2 - exit 1 -fi -tools/dev/bun.sh tools/release/check-node-direct-release-assets.mjs \ - --asset-dir "$asset_dir" \ - --allow-partial \ - --npm-package "$tarball" -printf 'Node direct optional npm package staged: %s\n' "$tarball" -printf '%s\n' "$asset_dir/$asset" diff --git a/tools/release/package-release-carriers.mjs b/tools/release/package-release-carriers.mjs deleted file mode 100644 index b36671e7d..000000000 --- a/tools/release/package-release-carriers.mjs +++ /dev/null @@ -1,1917 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import { - chmodSync, - copyFileSync, - cpSync, - existsSync, - mkdirSync, - mkdtempSync, - readdirSync, - readFileSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import { gunzipSync } from "node:zlib"; - -import { captureCommandBytes, captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { ROOT, run } from "./release-cli-utils.mjs"; -import { - artifactTargets, - compareText, - contribCarrierDescriptor, - currentProductVersionSync, - exactExtensionReleaseProducts, - extensionArtifactProductRoot, - extensionRegistryPackageTargetSets, - registryPackageRows, -} from "./release-artifact-targets.mjs"; -import { - packageNativeExtensionCargoCrates, - stageExtensionNpmPackagesForTargets, -} from "./package-extension-release-carriers.mjs"; -import { packageExtensionCargoFacades } from "./package-extension-cargo-facades.mjs"; -import { - WASIX_CARGO_ARTIFACT_SCHEMA, - publicCargoPackageNames as wasixPublicCargoPackageNames, -} from "./wasix-cargo-artifact-contract.mjs"; -import { - expectedWasixExtensionPackageInventory, - isExpectedWasixExtensionPackage, - validateWasixExtensionArtifactInventory, -} from "./wasix-extension-cargo-artifact-inventory.mjs"; -import { - requiredCoreRuntimePaths, - requiredRuntimeMemberPaths, - requiredToolsMemberPaths, - requiredToolsPackageTools, -} from "./optimize_native_runtime_payload.mjs"; -import { validateNpmTrustedPublishingManifest } from "./npm-trusted-publishing.mjs"; -import { - WINDOWS_VC_RUNTIME_RECEIPT, - parseWindowsVcRuntimeReceipt, - windowsVcRuntimeProfileNames, -} from "./windows-vc-runtime-closure.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releaseNoticeRows, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { - assertBrokerDependencyLicensesInArchive, - assertBrokerDependencyLicensesInDirectory, - brokerDependencyLicenseMembers, - normalizeBrokerDependencyLicenseModes, -} from "./broker-dependency-license-contract.mjs"; -import { - ICU_DATA_RELATIVE_PATH, - ICU_MANIFEST_RELATIVE_PATH, - ICU_PODSPEC, - ICU_REACT_NATIVE_CONFIG, - assertIcuPackedClosureMatchesSource, - assertIcuPackageManifest, - assertIcuPodspec, - assertIcuReactNativeConfig, - assertPackedIcuCarrier, -} from "./icu-npm-carrier-contract.mjs"; -import { stageMavenArtifactManifest } from "./maven-artifact-staging.mjs"; -import { buildMavenArtifactManifest } from "./build_maven_artifact_manifest.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { assertWasixNapiNpmArchive } from "./check-wasix-napi-release-assets.mjs"; -import { packWasixRuntimeNpmCarrier } from "./wasix-runtime-npm-carrier.mjs"; -import { packWasixIcuNpmCarrier } from "./wasix-icu-npm-carrier.mjs"; -import { packWasixToolsNpmCarrier } from "./wasix-tools-npm-carrier.mjs"; - -const TOOL = "package-release-carriers.mjs"; -const LIBOLIPHAUNT_NATIVE_PRODUCT = "liboliphaunt-native"; -const LIBOLIPHAUNT_NATIVE_KIND = "native-runtime"; -const LIBOLIPHAUNT_NATIVE_TOOLS_PRODUCT = "oliphaunt-tools"; -const LIBOLIPHAUNT_NATIVE_TOOLS_KIND = "native-tools"; -const LIBOLIPHAUNT_NATIVE_PACKAGE_ROOT = path.join(ROOT, "src/runtimes/liboliphaunt/native/packages"); -const LIBOLIPHAUNT_NATIVE_TOOLS_PACKAGE_ROOT = path.join(ROOT, "src/runtimes/liboliphaunt/native/tools-packages"); -const LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_PACKAGE = "@oliphaunt/tools"; -const LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_ROOT = path.join(ROOT, "src/runtimes/liboliphaunt/native/tools-npm"); -const LIBOLIPHAUNT_ICU_PACKAGE_NAME = "@oliphaunt/icu"; -const LIBOLIPHAUNT_ICU_PACKAGE_ROOT = path.join(ROOT, "src/runtimes/liboliphaunt/native/icu-npm"); -const BROKER_PRODUCT = "oliphaunt-broker"; -const BROKER_KIND = "broker-helper"; -const BROKER_PACKAGE_ROOT = path.join(ROOT, "src/runtimes/broker/packages"); -const WASIX_PRODUCT = "liboliphaunt-wasix"; -const NODE_DIRECT_PRODUCT = "oliphaunt-node-direct"; -const NODE_DIRECT_KIND = "node-direct-addon"; -const NODE_DIRECT_PACKAGE_ROOT = path.join(ROOT, "src/runtimes/node-direct/packages"); -const WASIX_NAPI_PRODUCT = "oliphaunt-wasix-napi"; -const WASIX_NAPI_KIND = "wasix-napi-addon"; -const WASIX_NAPI_PACKAGE_ROOT = path.join(ROOT, "src/runtimes/wasix-napi/packages"); - -export const RELEASE_CARRIER_PRODUCTS = new Set([ - ...exactExtensionReleaseProducts(TOOL), - LIBOLIPHAUNT_NATIVE_PRODUCT, - BROKER_PRODUCT, - WASIX_PRODUCT, - NODE_DIRECT_PRODUCT, - WASIX_NAPI_PRODUCT, -]); - -function fail(message, exitCode = 1) { - console.error(`${TOOL}: ${message}`); - process.exit(exitCode); -} - -function rel(file) { - return path.relative(ROOT, file).split(path.sep).join("/"); -} - -function sortedStrings(values) { - return [...values].sort(compareText); -} - -function assertSameStringSet(label, actual, expected) { - const actualSorted = sortedStrings(actual); - const expectedSorted = sortedStrings(expected); - if (JSON.stringify(actualSorted) !== JSON.stringify(expectedSorted)) { - fail(`${label}: expected=${JSON.stringify(expectedSorted)}, actual=${JSON.stringify(actualSorted)}`); - } -} - -function isFile(file) { - try { - return statSync(file).isFile(); - } catch { - return false; - } -} - -function isDirectory(file) { - try { - return statSync(file).isDirectory(); - } catch { - return false; - } -} - -function sha256File(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function commandOutput(command, args, { cwd = ROOT } = {}) { - const result = captureCommandOutput(command, args, { - cwd, - label: `${command} ${args.join(" ")}`, - maxOutputBytes: 100 * 1024 * 1024, - }); - if (result.error !== undefined) { - fail(`${command} failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - const stderr = Buffer.isBuffer(result.stderr) ? result.stderr.toString("utf8") : result.stderr; - fail(`${command} ${args.join(" ")} failed${stderr ? `: ${stderr.trim()}` : ""}`); - } - return result.stdout; -} - -function stagedRuntimeInputDirs(envName) { - const raw = process.env[envName] ?? process.env.OLIPHAUNT_RELEASE_ASSET_INPUT_DIRS ?? ""; - return raw - .split(path.delimiter) - .filter(Boolean) - .map((item) => { - const expanded = item === "~" || item.startsWith("~/") - ? path.join(process.env.HOME ?? "", item.slice(1)) - : item; - return path.isAbsolute(expanded) ? expanded : path.join(ROOT, expanded); - }); -} - -function globRegex(pattern) { - return new RegExp(`^${pattern.split("*").map(escapeRegExp).join(".*")}$`, "u"); -} - -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"); -} - -function copyStagedRuntimeAssets({ - product, - destination, - envName, - patterns, -}) { - const sourceDirs = stagedRuntimeInputDirs(envName); - if (sourceDirs.length === 0) { - fail( - `${product} requires staged runtime artifacts; set ${envName} or OLIPHAUNT_RELEASE_ASSET_INPUT_DIRS to the downloaded CI artifact directory`, - ); - } - mkdirSync(destination, { recursive: true }); - const regexes = patterns.map(globRegex); - let copied = 0; - for (const sourceDir of sourceDirs) { - if (!isDirectory(sourceDir)) { - fail(`${product} release asset input directory does not exist: ${sourceDir}`); - } - for (const name of readdirSync(sourceDir).sort(compareText)) { - if (!regexes.some((regex) => regex.test(name))) { - continue; - } - const source = path.join(sourceDir, name); - if (!isFile(source)) { - continue; - } - const output = path.join(destination, name); - if (isFile(output)) { - if (sha256File(output) !== sha256File(source)) { - fail(`${product} release asset input collision for ${name}: ${rel(output)} and ${rel(source)} have different bytes`); - } - continue; - } - copyFileSync(source, output); - copied += 1; - } - } - if (copied === 0) { - fail(`${product} found no staged runtime artifacts matching ${JSON.stringify(patterns)} under ${JSON.stringify(sourceDirs)}`); - } -} - -function hasNodeDirectReleaseArchive(assetDir) { - if (!isDirectory(assetDir)) { - return false; - } - return readdirSync(assetDir).some((name) => - name.startsWith("oliphaunt-node-direct-") && (name.endsWith(".tar.gz") || name.endsWith(".zip")), - ); -} - -function hasWasixNapiReleaseArchive(assetDir) { - if (!isDirectory(assetDir)) { - return false; - } - return readdirSync(assetDir).some((name) => - name.startsWith("oliphaunt-wasix-napi-") && (name.endsWith(".tar.gz") || name.endsWith(".zip")), - ); -} - -function hasBrokerReleaseArchive(assetDir) { - if (!isDirectory(assetDir)) { - return false; - } - return readdirSync(assetDir).some((name) => - name.startsWith("oliphaunt-broker-") && (name.endsWith(".tar.gz") || name.endsWith(".zip")), - ); -} - -function hasWasixReleaseArchive(assetDir) { - if (!isDirectory(assetDir)) { - return false; - } - return readdirSync(assetDir).some((name) => - name.startsWith("liboliphaunt-wasix-") && name.endsWith(".tar.zst"), - ); -} - -function hasLiboliphauntReleaseArchive(assetDir) { - if (!isDirectory(assetDir)) { - return false; - } - return readdirSync(assetDir).some((name) => - ( - name.startsWith("liboliphaunt-") || - name.startsWith("oliphaunt-tools-") - ) && (name.endsWith(".tar.gz") || name.endsWith(".zip") || name.endsWith(".tsv")), - ); -} - -export function ensureLiboliphauntReleaseAssets() { - const assetDir = path.join(ROOT, "target/liboliphaunt/release-assets"); - if (!hasLiboliphauntReleaseArchive(assetDir)) { - copyStagedRuntimeAssets({ - product: LIBOLIPHAUNT_NATIVE_PRODUCT, - destination: assetDir, - envName: "OLIPHAUNT_LIBOLIPHAUNT_RELEASE_ASSET_INPUT_DIRS", - patterns: [ - "liboliphaunt-*.tar.gz", - "liboliphaunt-*.zip", - "liboliphaunt-*.tsv", - "liboliphaunt-*.sha256", - "oliphaunt-tools-*.tar.gz", - "oliphaunt-tools-*.zip", - ], - }); - } - const version = currentProductVersionSync(LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL); - run(TOOL, [ - process.execPath, - "tools/release/write_checksum_manifest.mjs", - "--asset-dir", - rel(assetDir), - "--output", - `liboliphaunt-${version}-release-assets.sha256`, - "--pattern", - "liboliphaunt-*.tar.gz", - "--pattern", - "liboliphaunt-*.zip", - "--pattern", - "liboliphaunt-*.tsv", - "--pattern", - "oliphaunt-tools-*.tar.gz", - "--pattern", - "oliphaunt-tools-*.zip", - ]); - run(TOOL, [ - process.execPath, - "tools/release/check-liboliphaunt-release-assets.mjs", - "--asset-dir", - rel(assetDir), - ]); -} - -export function ensureBrokerReleaseAssets() { - const assetDir = path.join(ROOT, "target/oliphaunt-broker/release-assets"); - if (!hasBrokerReleaseArchive(assetDir)) { - copyStagedRuntimeAssets({ - product: BROKER_PRODUCT, - destination: assetDir, - envName: "OLIPHAUNT_BROKER_RELEASE_ASSET_INPUT_DIRS", - patterns: ["oliphaunt-broker-*.tar.gz", "oliphaunt-broker-*.zip"], - }); - } - const version = currentProductVersionSync(BROKER_PRODUCT, TOOL); - run(TOOL, [ - process.execPath, - "tools/release/write_checksum_manifest.mjs", - "--asset-dir", - rel(assetDir), - "--output", - `oliphaunt-broker-${version}-release-assets.sha256`, - "--pattern", - "oliphaunt-broker-*.tar.gz", - "--pattern", - "oliphaunt-broker-*.zip", - ]); - run(TOOL, [ - process.execPath, - "tools/release/check-broker-release-assets.mjs", - "--asset-dir", - rel(assetDir), - ]); -} - -export function ensureWasixReleaseAssets() { - const assetDir = path.join(ROOT, "target/oliphaunt-wasix/release-assets"); - if (!hasWasixReleaseArchive(assetDir)) { - copyStagedRuntimeAssets({ - product: WASIX_PRODUCT, - destination: assetDir, - envName: "OLIPHAUNT_WASIX_RELEASE_ASSET_INPUT_DIRS", - patterns: ["liboliphaunt-wasix-*.tar.zst"], - }); - } - const version = currentProductVersionSync(WASIX_PRODUCT, TOOL); - run(TOOL, [ - process.execPath, - "tools/release/write_checksum_manifest.mjs", - "--asset-dir", - rel(assetDir), - "--output", - `liboliphaunt-wasix-${version}-release-assets.sha256`, - "--pattern", - "liboliphaunt-wasix-*.tar.zst", - ]); - run(TOOL, [ - process.execPath, - "tools/release/check-liboliphaunt-wasix-release-assets.mjs", - "--asset-dir", - rel(assetDir), - "--version", - version, - ]); -} - -export function ensureNodeDirectReleaseAssets() { - const assetDir = path.join(ROOT, "target/oliphaunt-node-direct/release-assets"); - if (!hasNodeDirectReleaseArchive(assetDir)) { - copyStagedRuntimeAssets({ - product: NODE_DIRECT_PRODUCT, - destination: assetDir, - envName: "OLIPHAUNT_NODE_ADDON_ASSET_INPUT_DIRS", - patterns: ["oliphaunt-node-direct-*.tar.gz", "oliphaunt-node-direct-*.zip"], - }); - } - const version = currentProductVersionSync(NODE_DIRECT_PRODUCT, TOOL); - run(TOOL, [ - process.execPath, - "tools/release/write_checksum_manifest.mjs", - "--asset-dir", - rel(assetDir), - "--output", - `oliphaunt-node-direct-${version}-release-assets.sha256`, - "--pattern", - "oliphaunt-node-direct-*.tar.gz", - "--pattern", - "oliphaunt-node-direct-*.zip", - ]); - run(TOOL, [ - process.execPath, - "tools/release/check-node-direct-release-assets.mjs", - "--asset-dir", - rel(assetDir), - ]); -} - -export function ensureWasixNapiReleaseAssets() { - const assetDir = path.join(ROOT, "target/oliphaunt-wasix-napi/release-assets"); - if (!hasWasixNapiReleaseArchive(assetDir)) { - copyStagedRuntimeAssets({ - product: WASIX_NAPI_PRODUCT, - destination: assetDir, - envName: "OLIPHAUNT_WASIX_NAPI_ASSET_INPUT_DIRS", - patterns: ["oliphaunt-wasix-napi-*.tar.gz", "oliphaunt-wasix-napi-*.zip"], - }); - } - const version = currentProductVersionSync(WASIX_NAPI_PRODUCT, TOOL); - run(TOOL, [ - process.execPath, - "tools/release/write_checksum_manifest.mjs", - "--asset-dir", - rel(assetDir), - "--output", - `oliphaunt-wasix-napi-${version}-release-assets.sha256`, - "--pattern", - "oliphaunt-wasix-napi-*.tar.gz", - "--pattern", - "oliphaunt-wasix-napi-*.zip", - ]); - run(TOOL, [ - process.execPath, - "tools/release/check-wasix-napi-release-assets.mjs", - "--asset-dir", - rel(assetDir), - ]); -} - -function npmPackageDirsUnder(packageRoot) { - const packages = new Map(); - if (!isDirectory(packageRoot)) { - fail(`${rel(packageRoot)} does not contain npm package descriptors`); - } - for (const packageDirName of readdirSync(packageRoot).sort(compareText)) { - const packageDir = path.join(packageRoot, packageDirName); - const packageJsonPath = path.join(packageDir, "package.json"); - if (!isFile(packageJsonPath)) { - continue; - } - let packageJson; - try { - packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")); - } catch (error) { - fail(`${rel(packageJsonPath)} is not valid JSON: ${error.message}`); - } - const packageName = packageJson.name; - if (typeof packageName !== "string" || packageName.length === 0) { - fail(`${rel(packageJsonPath)} must declare name`); - } - if (packages.has(packageName)) { - fail(`duplicate npm package name ${packageName} in ${rel(packages.get(packageName))} and ${rel(packageDir)}`); - } - packages.set(packageName, packageDir); - } - if (packages.size === 0) { - fail(`${rel(packageRoot)} does not contain npm package descriptors`); - } - return packages; -} - -function artifactNpmPackageTargets({ - product, - kind, - surface, - packageRoot, - version, -}) { - const packageDirs = npmPackageDirsUnder(packageRoot); - const packages = []; - for (const target of artifactTargets(product, kind, TOOL).filter((candidate) => candidate.surfaces.includes(surface))) { - const packageName = target.npm_package; - if (typeof packageName !== "string" || packageName.length === 0) { - fail(`${target.id} must declare npm_package for npm artifact package publication`); - } - const packageDir = packageDirs.get(packageName); - if (packageDir === undefined) { - fail(`${target.id} declares unknown npm package ${packageName}`); - } - const packageJson = JSON.parse(readFileSync(path.join(packageDir, "package.json"), "utf8")); - if (packageJson.name !== packageName) { - fail(`${rel(packageDir)}/package.json name must be ${packageName}`); - } - if (packageJson.version !== version) { - fail(`${packageName} package version must match ${product} ${version}`); - } - packages.push([packageName, packageDir, target]); - } - const expected = packages.map(([packageName]) => packageName).sort(compareText); - const actual = [...packageDirs.keys()].sort(compareText); - if (JSON.stringify(actual) !== JSON.stringify(expected)) { - fail(`${rel(packageRoot)} package descriptors must match published ${product} npm artifact targets for ${surface}`); - } - return packages.sort((left, right) => compareText(left[0], right[0])); -} - -function nodeDirectOptionalPackageTargets(version) { - return artifactNpmPackageTargets({ - product: NODE_DIRECT_PRODUCT, - kind: NODE_DIRECT_KIND, - surface: "npm-optional", - packageRoot: NODE_DIRECT_PACKAGE_ROOT, - version, - }); -} - -function wasixNapiOptionalPackageTargets(version) { - return artifactNpmPackageTargets({ - product: WASIX_NAPI_PRODUCT, - kind: WASIX_NAPI_KIND, - surface: "npm-optional", - packageRoot: WASIX_NAPI_PACKAGE_ROOT, - version, - }); -} - -function brokerNpmPackageTargets(version) { - return artifactNpmPackageTargets({ - product: BROKER_PRODUCT, - kind: BROKER_KIND, - surface: "typescript-broker", - packageRoot: BROKER_PACKAGE_ROOT, - version, - }); -} - -function safeNpmPackageFilenamePrefix(packageName) { - return packageName.replace(/^@/u, "").replace("/", "-"); -} - -function nodeDirectNpmPackageDir() { - return path.join(ROOT, "target/oliphaunt-node-direct/npm-packages"); -} - -function expectedNodeDirectNpmTarball(packageName, version) { - return path.join(nodeDirectNpmPackageDir(), `${safeNpmPackageFilenamePrefix(packageName)}-${version}.tgz`); -} - -function parseTarString(buffer, start, length) { - const end = buffer.indexOf(0, start); - return buffer - .subarray(start, end >= start && end < start + length ? end : start + length) - .toString("utf8") - .trim(); -} - -function parseTarOctal(buffer, start, length) { - const text = parseTarString(buffer, start, length).replaceAll("\0", "").trim(); - return text ? Number.parseInt(text, 8) : 0; -} - -function readTarGzMember(file, expectedName) { - const buffer = gunzipSync(readFileSync(file)); - for (let offset = 0; offset + 512 <= buffer.length;) { - const header = buffer.subarray(offset, offset + 512); - if (header.every((byte) => byte === 0)) { - break; - } - const rawName = parseTarString(header, 0, 100); - const prefix = parseTarString(header, 345, 155); - const name = prefix ? `${prefix}/${rawName}` : rawName; - const size = parseTarOctal(header, 124, 12); - const dataOffset = offset + 512; - if (name === expectedName) { - return buffer.subarray(dataOffset, dataOffset + size); - } - offset = dataOffset + Math.ceil(size / 512) * 512; - } - return null; -} - -function readTarGzEntries(file) { - const buffer = gunzipSync(readFileSync(file)); - const entries = new Map(); - for (let offset = 0; offset + 512 <= buffer.length;) { - const header = buffer.subarray(offset, offset + 512); - if (header.every((byte) => byte === 0)) { - break; - } - const rawName = parseTarString(header, 0, 100); - const prefix = parseTarString(header, 345, 155); - const name = prefix ? `${prefix}/${rawName}` : rawName; - const mode = parseTarOctal(header, 100, 8); - const size = parseTarOctal(header, 124, 12); - const type = header.subarray(156, 157).toString("utf8"); - entries.set(name, { mode, size, isFile: type === "" || type === "0" }); - offset += 512 + Math.ceil(size / 512) * 512; - } - return entries; -} - -function validateNoConsumerInstallScripts(packageJson, context) { - const scripts = packageJson.scripts; - if (scripts === undefined) { - return; - } - if (scripts === null || typeof scripts !== "object" || Array.isArray(scripts)) { - fail(`${context} scripts must be an object when present`); - } - for (const scriptName of ["preinstall", "install", "postinstall", "prepare"]) { - if (Object.hasOwn(scripts, scriptName)) { - fail(`${context} must not declare consumer install lifecycle script ${scriptName}`); - } - } -} - -function npmPackageSourceStageDir(packageName) { - return path.join(ROOT, "target/release/npm-package-sources", safeNpmPackageFilenamePrefix(packageName)); -} - -function stageNpmPackageDescriptor( - packageName, - sourceDir, - version, - { - extraDescriptors = [], - target = null, - } = {}, -) { - const stageDir = npmPackageSourceStageDir(packageName); - rmSync(stageDir, { recursive: true, force: true }); - mkdirSync(stageDir, { recursive: true }); - for (const descriptor of ["package.json", "README.md", ...extraDescriptors]) { - const source = path.join(sourceDir, descriptor); - if (!isFile(source)) { - fail(`${rel(sourceDir)} is missing ${descriptor}`); - } - copyFileSync(source, path.join(stageDir, descriptor)); - } - const packageJsonPath = path.join(stageDir, "package.json"); - const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")); - if (packageJson.name !== packageName) { - fail(`${rel(packageJsonPath)} name must be ${packageName}`); - } - if (packageJson.version !== version) { - fail(`${packageName} package version must match ${version}`); - } - if (target !== null && packageJson.oliphaunt?.target !== target) { - fail(`${packageName} package oliphaunt.target must be ${target}`); - } - validateNoConsumerInstallScripts(packageJson, `${packageName} npm package`); - return stageDir; -} - -function readReleaseArchiveMember(archive, memberName) { - if (archive.endsWith(".tar.gz")) { - for (const candidate of [memberName, `./${memberName}`]) { - const data = readTarGzMember(archive, candidate); - if (data !== null) { - return data; - } - } - fail(`${rel(archive)} is missing ${memberName}`); - } - if (path.extname(archive) === ".zip") { - for (const candidate of [memberName, `./${memberName}`]) { - const result = captureCommandBytes("unzip", ["-p", archive, candidate], { - cwd: ROOT, - label: `read ${candidate} from ${rel(archive)}`, - maxOutputBytes: 100 * 1024 * 1024, - }); - if (result.error !== undefined) { - fail(`unzip failed to start: ${result.error.message}`); - } - if (result.status === 0) { - return result.stdout; - } - } - fail(`${rel(archive)} is missing ${memberName}`); - } - fail(`${rel(archive)} has unsupported release archive extension`); -} - -function extractReleaseArchiveFile(archive, memberName, destination, { mode = null } = {}) { - const data = readReleaseArchiveMember(archive, memberName); - mkdirSync(path.dirname(destination), { recursive: true }); - writeFileSync(destination, data); - if (mode !== null) { - chmodSync(destination, mode); - } -} - -function archiveTempDir() { - const root = path.join(ROOT, "target/release/archive-extract"); - mkdirSync(root, { recursive: true }); - return mkdtempSync(path.join(root, "extract-")); -} - -function runArchiveCommand(args, label) { - const result = captureCommandOutput(args[0], args.slice(1), { - cwd: ROOT, - label, - maxOutputBytes: 100 * 1024 * 1024, - }); - if (result.error !== undefined) { - fail(`${label} failed to start: ${result.error.message}`); - } - return result; -} - -function copyExtractedTree(source, destination) { - if (!isDirectory(source)) { - fail(`release archive is missing extracted tree ${source}`); - } - rmSync(destination, { recursive: true, force: true }); - cpSync(source, destination, { recursive: true }); -} - -export function extractReleaseArchiveTree(archive, sourcePrefix, destination) { - const temp = archiveTempDir(); - const prefix = sourcePrefix.replace(/\/+$/u, ""); - try { - if (archive.endsWith(".zip")) { - // Info-ZIP wildcard recursion differs between Unix and Windows builds. - // Extract into isolated scratch and copy only the requested tree into - // the package stage below. - const result = runArchiveCommand( - ["unzip", "-q", archive, "-d", temp], - `extract ${prefix} from ${rel(archive)}`, - ); - const extracted = path.join(temp, ...prefix.split("/")); - if (result.status === 0 && isDirectory(extracted)) { - copyExtractedTree(extracted, destination); - return; - } - } else { - for (const candidate of [prefix, `./${prefix}`]) { - const result = runArchiveCommand( - ["tar", "-xf", archive, "-C", temp, candidate], - `extract ${candidate} from ${rel(archive)}`, - ); - const extracted = path.join(temp, ...candidate.replace(/^\.\//u, "").split("/")); - if (result.status === 0 && isDirectory(extracted)) { - copyExtractedTree(extracted, destination); - return; - } - } - } - } finally { - rmSync(temp, { recursive: true, force: true }); - } - fail(`${rel(archive)} is missing ${prefix}`); -} - -export function nativePayloadOptimizerArgs(stage, target, toolSet) { - return [ - process.execPath, - "tools/release/optimize_native_runtime_payload.mjs", - rel(stage), - "--target", - target, - "--tool-set", - toolSet, - "--check", - ]; -} - -function runNativePayloadOptimizer(stage, target, toolSet) { - run(TOOL, nativePayloadOptimizerArgs(stage, target, toolSet)); -} - -function ensureNativeToolsAbsentFromRuntime(stage, target) { - const runtimeDir = path.join(stage, "runtime"); - const leaked = []; - for (const tool of requiredToolsPackageTools(target, runtimeDir)) { - if (existsSync(path.join(runtimeDir, "bin", tool))) { - leaked.push(`runtime/bin/${tool}`); - } - } - if (leaked.length > 0) { - fail(`${rel(stage)} root runtime package must not contain split native tools: ${leaked.join(", ")}`); - } -} - -function pnpmPackForNpmPublish(packageDir) { - const packageJson = JSON.parse(readFileSync(path.join(packageDir, "package.json"), "utf8")); - const packageName = packageJson.name; - if (typeof packageName !== "string" || packageName.length === 0) { - fail(`${rel(packageDir)}/package.json must declare a package name`); - } - try { - validateNpmTrustedPublishingManifest(packageJson, `${rel(packageDir)}/package.json`); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - const packDir = path.join(ROOT, "target/release/npm-packages", safeNpmPackageFilenamePrefix(packageName)); - rmSync(packDir, { recursive: true, force: true }); - mkdirSync(packDir, { recursive: true }); - const rendered = commandOutput("pnpm", ["pack", "--pack-destination", packDir, "--json"], { cwd: packageDir }); - let manifest; - try { - manifest = JSON.parse(rendered); - } catch (error) { - fail(`pnpm pack for ${packageName} did not emit JSON: ${error.message}`); - } - const filename = Array.isArray(manifest) ? manifest[0]?.filename : manifest?.filename; - if (typeof filename !== "string" || !filename.endsWith(".tgz")) { - fail(`pnpm pack for ${packageName} did not report a .tgz filename`); - } - const tarball = path.isAbsolute(filename) ? filename : path.join(packDir, filename); - if (!isFile(tarball)) { - fail(`pnpm pack for ${packageName} did not create ${rel(tarball)}`); - } - try { - const packed = readTarGzMember(tarball, "package/package.json"); - if (packed === null) { - fail(`${rel(tarball)} is missing package/package.json`); - } - validateNpmTrustedPublishingManifest( - JSON.parse(packed.toString("utf8")), - `${rel(tarball)} package/package.json`, - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - return tarball; -} - -function validatePackedNpmPackage({ - packageName, - version, - tarball, - requiredMembers, - executableMembers = [], -}) { - let entries; - try { - entries = readTarGzEntries(tarball); - } catch (error) { - fail(`${rel(tarball)} is not a valid npm tarball: ${error.message}`); - } - if (!entries.has("package/package.json")) { - fail(`${rel(tarball)} is missing package/package.json`); - } - let packageJson; - try { - const packageData = readTarGzMember(tarball, "package/package.json"); - if (packageData === null) { - fail(`${rel(tarball)} package/package.json could not be read`); - } - packageJson = JSON.parse(packageData.toString("utf8")); - } catch (error) { - fail(`${rel(tarball)} package/package.json is not valid JSON: ${error.message}`); - } - if (packageJson.name !== packageName) { - fail(`${rel(tarball)} package name must be ${packageName}, got ${JSON.stringify(packageJson.name)}`); - } - if (packageJson.version !== version) { - fail(`${rel(tarball)} package version must be ${version}, got ${JSON.stringify(packageJson.version)}`); - } - try { - validateNpmTrustedPublishingManifest(packageJson, `${rel(tarball)} package/package.json`); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - for (const member of requiredMembers) { - const entry = entries.get(member); - if (entry === undefined) { - fail(`${rel(tarball)} is missing ${member}`); - } - if (!entry.isFile || entry.size <= 0) { - fail(`${rel(tarball)} ${member} must be a non-empty regular file`); - } - } - for (const member of executableMembers) { - const entry = entries.get(member); - if (entry === undefined) { - fail(`${rel(tarball)} is missing executable ${member}`); - } - if (!entry.isFile || entry.size <= 0 || (entry.mode & 0o111) === 0) { - fail(`${rel(tarball)} ${member} must be a non-empty executable file`); - } - } -} - -function liboliphauntRuntimeNpmPackageTargets(version) { - return artifactNpmPackageTargets({ - product: LIBOLIPHAUNT_NATIVE_PRODUCT, - kind: LIBOLIPHAUNT_NATIVE_KIND, - surface: "typescript-native-direct", - packageRoot: LIBOLIPHAUNT_NATIVE_PACKAGE_ROOT, - version, - }); -} - -function liboliphauntToolsNpmPackageTargets(version) { - return artifactNpmPackageTargets({ - product: LIBOLIPHAUNT_NATIVE_PRODUCT, - kind: LIBOLIPHAUNT_NATIVE_TOOLS_KIND, - surface: "typescript-native-direct", - packageRoot: LIBOLIPHAUNT_NATIVE_TOOLS_PACKAGE_ROOT, - version, - }); -} - -function embeddedCoreModuleMembers(target, prefix) { - const suffix = target === "windows-x64-msvc" - ? ".dll" - : target === "macos-arm64" - ? ".dylib" - : ".so"; - const normalizedPrefix = prefix.replace(/\/+$/u, ""); - return ["dict_snowball", "plpgsql"].map((stem) => `${normalizedPrefix}/${stem}${suffix}`); -} - -export function stageWindowsVcRuntimeMembers( - archive, - stage, - target, - prefix, - { alreadyExtracted = false, profile } = {}, -) { - if (target !== "windows-x64-msvc") return []; - const normalizedPrefix = prefix.replace(/\/+$/u, ""); - const receiptMember = `${normalizedPrefix}/${WINDOWS_VC_RUNTIME_RECEIPT}`; - const receiptPath = path.join(stage, ...receiptMember.split("/")); - extractReleaseArchiveFile(archive, receiptMember, receiptPath); - const receipt = parseWindowsVcRuntimeReceipt(readFileSync(receiptPath), `${rel(archive)}:${receiptMember}`); - const names = [...receipt.keys()].sort(compareText); - if (profile !== undefined) { - assertSameStringSet( - `${rel(archive)} ${normalizedPrefix} ${profile} VC runtime profile`, - names, - windowsVcRuntimeProfileNames(profile), - ); - } - for (const name of names) { - const member = `${normalizedPrefix}/${name}`; - const destination = path.join(stage, ...member.split("/")); - const expectedDigest = receipt.get(name); - if ( - !alreadyExtracted - || !isFile(destination) - || sha256File(destination) !== expectedDigest - ) { - extractReleaseArchiveFile(archive, member, destination); - } - if (!isFile(destination) || sha256File(destination) !== expectedDigest) { - fail(`${rel(archive)} exact VC runtime member ${member} does not match ${receiptMember}`); - } - } - return [receiptMember, ...names.map((name) => `${normalizedPrefix}/${name}`)]; -} - -function stageLiboliphauntNpmPayloads(version) { - const assetDir = path.join(ROOT, "target/liboliphaunt/release-assets"); - const stages = new Map(); - for (const [packageName, packageDir, target] of liboliphauntRuntimeNpmPackageTargets(version)) { - const libraryRelativePath = target.libraryRelativePath ?? target.library_relative_path; - if (typeof libraryRelativePath !== "string" || libraryRelativePath.length === 0) { - fail(`${target.id} must declare library_relative_path for npm artifact package publication`); - } - const stage = stageNpmPackageDescriptor(packageName, packageDir, version, { target: target.target }); - stageReleaseNotices(stage, { profile: "native-runtime" }); - const archive = path.join(assetDir, target.asset.replaceAll("{version}", version)); - extractReleaseArchiveFile(archive, libraryRelativePath, path.join(stage, libraryRelativePath)); - extractReleaseArchiveTree(archive, "lib/modules", path.join(stage, "lib/modules")); - extractReleaseArchiveTree(archive, "runtime", path.join(stage, "runtime")); - extractReleaseArchiveTree(archive, "cluster-seed", path.join(stage, "cluster-seed")); - extractReleaseArchiveTree(archive, "cluster-seed-icu", path.join(stage, "cluster-seed-icu")); - extractReleaseArchiveFile(archive, "manifest.properties", path.join(stage, "manifest.properties")); - const vcRuntimeMembers = [ - ...stageWindowsVcRuntimeMembers(archive, stage, target.target, "bin", { profile: "provider" }), - ...stageWindowsVcRuntimeMembers(archive, stage, target.target, "runtime/bin", { - alreadyExtracted: true, - profile: "provider", - }), - ]; - ensureNativeToolsAbsentFromRuntime(stage, target.target); - runNativePayloadOptimizer(stage, target.target, "runtime"); - assertReleaseNoticesInDirectory(stage, { profile: "native-runtime" }); - stages.set(packageName, { stage, vcRuntimeMembers }); - } - return stages; -} - -function selectedLiboliphauntToolsNpmPackageTargets(version, targetIds) { - const targets = liboliphauntToolsNpmPackageTargets(version); - if (targetIds === undefined) return targets; - const selected = new Set(targetIds); - const filtered = targets.filter(([, , target]) => selected.has(target.target)); - const actual = new Set(filtered.map(([, , target]) => target.target)); - const missing = [...selected].filter((target) => !actual.has(target)).sort(compareText); - if (missing.length > 0) { - fail(`unknown native tools npm target(s): ${missing.join(", ")}`); - } - return filtered; -} - -function stageLiboliphauntToolsNpmPayloads( - version, - { - assetDir = path.join(ROOT, "target/liboliphaunt/release-assets"), - targetIds, - } = {}, -) { - const stages = new Map(); - for (const [packageName, packageDir, target] of selectedLiboliphauntToolsNpmPackageTargets( - version, - targetIds, - )) { - const stage = stageNpmPackageDescriptor(packageName, packageDir, version, { target: target.target }); - stageReleaseNotices(stage, { profile: "native-tools" }); - const archive = path.join(assetDir, target.asset.replaceAll("{version}", version)); - for (const member of requiredToolsMemberPaths(target.target, "runtime/bin")) { - extractReleaseArchiveFile(archive, member, path.join(stage, member), { - mode: 0o755, - }); - } - const vcRuntimeMembers = stageWindowsVcRuntimeMembers(archive, stage, target.target, "runtime/bin"); - runNativePayloadOptimizer(stage, target.target, "tools"); - assertReleaseNoticesInDirectory(stage, { profile: "native-tools" }); - stages.set(packageName, { stage, vcRuntimeMembers }); - } - return stages; -} - -function stageLiboliphauntToolsNpmFacade(version) { - const stage = stageNpmPackageDescriptor( - LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_PACKAGE, - LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_ROOT, - version, - ); - for (const descriptor of ["index.js", "index.d.ts"]) { - copyFileSync( - path.join(LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_ROOT, descriptor), - path.join(stage, descriptor), - ); - } - const manifestFile = path.join(stage, "package.json"); - const manifest = JSON.parse(readFileSync(manifestFile, "utf8")); - manifest.optionalDependencies = Object.fromEntries( - Object.keys(manifest.optionalDependencies ?? {}) - .sort(compareText) - .map((name) => [name, version]), - ); - writeFileSync(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`); - stageReleaseNotices(stage, { profile: "source-sdk" }); - assertReleaseNoticesInDirectory(stage, { profile: "source-sdk" }); - return stage; -} - -function stageLiboliphauntIcuNpmPayload(version) { - const stage = stageNpmPackageDescriptor( - LIBOLIPHAUNT_ICU_PACKAGE_NAME, - LIBOLIPHAUNT_ICU_PACKAGE_ROOT, - version, - { - extraDescriptors: [ICU_PODSPEC, ICU_REACT_NATIVE_CONFIG], - target: "portable", - }, - ); - const sourceArchive = path.join( - ROOT, - "target/liboliphaunt/release-assets", - `liboliphaunt-${version}-icu-data.tar.gz`, - ); - extractReleaseArchiveTree( - sourceArchive, - "share/icu", - path.join(stage, ...ICU_DATA_RELATIVE_PATH.split("/")), - ); - extractReleaseArchiveFile( - sourceArchive, - "manifest.properties", - path.join(stage, ...ICU_MANIFEST_RELATIVE_PATH.split("/")), - ); - const manifestFile = path.join(stage, "package.json"); - const packageJson = JSON.parse(readFileSync(manifestFile, "utf8")); - const icuReceipt = readFileSync(path.join(stage, ...ICU_MANIFEST_RELATIVE_PATH.split("/")), "utf8"); - const digest = /^icuDataTreeSha256=([0-9a-f]{64})$/mu.exec(icuReceipt)?.[1]; - if (digest === undefined) { - fail(`${rel(sourceArchive)} has no canonical ICU data tree digest`); - } - packageJson.oliphaunt.icuDataTreeSha256 = digest; - writeFileSync(manifestFile, `${JSON.stringify(packageJson, null, 2)}\n`); - stageReleaseNotices(stage, { profile: "native-icu-data" }); - assertReleaseNoticesInDirectory(stage, { profile: "native-icu-data" }); - try { - assertIcuPackageManifest( - JSON.parse(readFileSync(path.join(stage, "package.json"), "utf8")), - `${rel(stage)} package.json`, - ); - assertIcuReactNativeConfig( - readFileSync(path.join(stage, ICU_REACT_NATIVE_CONFIG)), - `${rel(stage)} ${ICU_REACT_NATIVE_CONFIG}`, - ); - assertIcuPodspec( - readFileSync(path.join(stage, ICU_PODSPEC)), - `${rel(stage)} ${ICU_PODSPEC}`, - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - return stage; -} - -function validatePackedIcuPackage(packageName, version, tarball, sourceArchive) { - let entries; - let sourceEntries; - try { - entries = readPortableArchiveEntries(tarball); - sourceEntries = readPortableArchiveEntries(sourceArchive); - } catch (error) { - fail(`ICU carrier archives are invalid: ${error.message}`); - } - if (!entries.has("package/package.json")) { - fail(`${rel(tarball)} is missing package/package.json`); - } - let packageJson; - try { - const packageData = entries.get("package/package.json")?.data(); - if (packageData === undefined) { - fail(`${rel(tarball)} package/package.json could not be read`); - } - packageJson = JSON.parse(Buffer.from(packageData).toString("utf8")); - } catch (error) { - fail(`${rel(tarball)} package/package.json is not valid JSON: ${error.message}`); - } - if (packageJson.name !== packageName) { - fail(`${rel(tarball)} package name must be ${packageName}, got ${JSON.stringify(packageJson.name)}`); - } - if (packageJson.version !== version) { - fail(`${rel(tarball)} package version must be ${version}, got ${JSON.stringify(packageJson.version)}`); - } - try { - assertPackedIcuCarrier({ - entries: [...entries].map(([name, entry]) => ({ name, isFile: entry.isFile })), - packageJson, - packedConfig: entries.get(`package/${ICU_REACT_NATIVE_CONFIG}`)?.data(), - packedPodspec: entries.get(`package/${ICU_PODSPEC}`)?.data(), - sourceConfig: readFileSync(path.join(LIBOLIPHAUNT_ICU_PACKAGE_ROOT, ICU_REACT_NATIVE_CONFIG)), - sourcePodspec: readFileSync(path.join(LIBOLIPHAUNT_ICU_PACKAGE_ROOT, ICU_PODSPEC)), - label: rel(tarball), - }); - assertIcuPackedClosureMatchesSource({ - packedEntries: entries, - sourceEntries, - packageJson, - label: rel(tarball), - sourceLabel: rel(sourceArchive), - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - assertReleaseNoticesInArchive(tarball, { profile: "native-icu-data", prefix: "package" }); -} - -export function liboliphauntNpmTarballs(version) { - const packages = []; - const runtimeStages = stageLiboliphauntNpmPayloads(version); - for (const [packageName, , target] of liboliphauntRuntimeNpmPackageTargets(version)) { - const payload = runtimeStages.get(packageName); - const libraryRelativePath = target.libraryRelativePath ?? target.library_relative_path; - const runtimeMembers = requiredRuntimeMemberPaths(target.target, "package/runtime/bin"); - const coreRuntimeMembers = requiredCoreRuntimePaths(target.target).map( - (member) => `package/runtime/${member}`, - ); - const requiredMembers = [ - `package/${libraryRelativePath}`, - "package/cluster-seed/manifest.properties", - "package/cluster-seed/files/PG_VERSION", - "package/cluster-seed/files/global/pg_control", - "package/cluster-seed-icu/manifest.properties", - "package/cluster-seed-icu/files/PG_VERSION", - "package/cluster-seed-icu/files/global/pg_control", - "package/manifest.properties", - ...embeddedCoreModuleMembers(target.target, "package/lib/modules"), - ...runtimeMembers, - ...coreRuntimeMembers, - ...payload.vcRuntimeMembers.map((member) => `package/${member}`), - ...releaseNoticeRows({ profile: "native-runtime" }).map((row) => `package/${row.member}`), - ]; - const tarball = pnpmPackForNpmPublish(payload.stage); - validatePackedNpmPackage({ - packageName, - version, - tarball, - requiredMembers, - executableMembers: runtimeMembers, - }); - assertReleaseNoticesInArchive(tarball, { profile: "native-runtime", prefix: "package" }); - packages.push([packageName, tarball]); - } - packages.push(...liboliphauntToolsNpmTarballs(version)); - const icuStage = stageLiboliphauntIcuNpmPayload(version); - const icuTarball = pnpmPackForNpmPublish(icuStage); - validatePackedIcuPackage( - LIBOLIPHAUNT_ICU_PACKAGE_NAME, - version, - icuTarball, - path.join(ROOT, "target/liboliphaunt/release-assets", `liboliphaunt-${version}-icu-data.tar.gz`), - ); - packages.push([LIBOLIPHAUNT_ICU_PACKAGE_NAME, icuTarball]); - return packages; -} - -export function liboliphauntToolsNpmTarballs(version, options = {}) { - const packages = []; - const toolsStages = stageLiboliphauntToolsNpmPayloads(version, options); - for (const [packageName, , target] of selectedLiboliphauntToolsNpmPackageTargets( - version, - options.targetIds, - )) { - const payload = toolsStages.get(packageName); - const runtimeMembers = requiredToolsMemberPaths(target.target, "package/runtime/bin"); - const tarball = pnpmPackForNpmPublish(payload.stage); - validatePackedNpmPackage({ - packageName, - version, - tarball, - requiredMembers: [ - ...runtimeMembers, - ...payload.vcRuntimeMembers.map((member) => `package/${member}`), - ...releaseNoticeRows({ profile: "native-tools" }).map((row) => `package/${row.member}`), - ], - executableMembers: runtimeMembers, - }); - assertReleaseNoticesInArchive(tarball, { profile: "native-tools", prefix: "package" }); - packages.push([packageName, tarball]); - } - const toolsFacadeStage = stageLiboliphauntToolsNpmFacade(version); - const toolsFacadeTarball = pnpmPackForNpmPublish(toolsFacadeStage); - validatePackedNpmPackage({ - packageName: LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_PACKAGE, - version, - tarball: toolsFacadeTarball, - requiredMembers: [ - "package/index.js", - "package/index.d.ts", - ...releaseNoticeRows({ profile: "source-sdk" }).map((row) => `package/${row.member}`), - ], - }); - assertReleaseNoticesInArchive(toolsFacadeTarball, { - profile: "source-sdk", - prefix: "package", - }); - packages.push([LIBOLIPHAUNT_NATIVE_TOOLS_FACADE_PACKAGE, toolsFacadeTarball]); - return packages; -} - -export function brokerNpmTarballs( - version, - { assetDir = path.join(ROOT, "target/oliphaunt-broker/release-assets") } = {}, -) { - const tarballs = []; - for (const [packageName, packageDir, target] of brokerNpmPackageTargets(version)) { - const executableRelativePath = target.executable_relative_path; - if (typeof executableRelativePath !== "string" || executableRelativePath.length === 0) { - fail(`${target.id} must declare executable_relative_path for npm artifact package publication`); - } - const stageDir = stageNpmPackageDescriptor(packageName, packageDir, version, { target: target.target }); - stageReleaseNotices(stageDir, { profile: "broker" }); - assertReleaseNoticesInDirectory(stageDir, { profile: "broker" }); - const archive = path.join(assetDir, target.asset.replaceAll("{version}", version)); - assertBrokerDependencyLicensesInArchive(archive, { target: target.target }); - extractReleaseArchiveFile(archive, executableRelativePath, path.join(stageDir, executableRelativePath), { mode: 0o755 }); - extractReleaseArchiveTree( - archive, - "THIRD_PARTY_LICENSES/rust", - path.join(stageDir, "THIRD_PARTY_LICENSES/rust"), - ); - normalizeBrokerDependencyLicenseModes(stageDir, target.target); - assertBrokerDependencyLicensesInDirectory(stageDir, { target: target.target }); - const vcRuntimeMembers = stageWindowsVcRuntimeMembers(archive, stageDir, target.target, "bin"); - const tarball = pnpmPackForNpmPublish(stageDir); - const requiredMembers = [ - `package/${executableRelativePath}`, - ...vcRuntimeMembers.map((member) => `package/${member}`), - ...releaseNoticeRows({ profile: "broker" }).map((row) => `package/${row.member}`), - ...brokerDependencyLicenseMembers(target.target, { prefix: "package" }), - ]; - validatePackedNpmPackage({ - packageName, - version, - tarball, - requiredMembers, - executableMembers: [`package/${executableRelativePath}`], - }); - assertBrokerDependencyLicensesInArchive(tarball, { target: target.target, prefix: "package" }); - tarballs.push([packageName, tarball]); - } - return tarballs; -} - -async function validateNodeDirectOptionalTarball(packageName, version, tarball) { - if (!isFile(tarball)) { - fail(`missing Node direct optional npm package artifact: ${rel(tarball)}`); - } - let entries; - try { - entries = readTarGzEntries(tarball); - } catch (error) { - fail(`${rel(tarball)} is not a valid Node direct optional npm tarball: ${error.message}`); - } - for (const required of ["package/package.json", "package/prebuilds/oliphaunt_node.node"]) { - if (!entries.has(required)) { - fail(`${rel(tarball)} is missing ${required}`); - } - } - const prebuild = entries.get("package/prebuilds/oliphaunt_node.node"); - if (!prebuild.isFile || prebuild.size <= 0) { - fail(`${rel(tarball)} prebuilt addon must be a non-empty regular file`); - } - let packageJson; - try { - const packageData = readTarGzMember(tarball, "package/package.json"); - if (packageData === null) { - fail(`${rel(tarball)} package/package.json could not be read`); - } - packageJson = JSON.parse(packageData.toString("utf8")); - } catch (error) { - fail(`${rel(tarball)} package/package.json is not valid JSON: ${error.message}`); - } - if (packageJson.name !== packageName) { - fail(`${rel(tarball)} package name must be ${packageName}, got ${JSON.stringify(packageJson.name)}`); - } - if (packageJson.version !== version) { - fail(`${rel(tarball)} package version must be ${version}, got ${JSON.stringify(packageJson.version)}`); - } -} - -export async function nodeDirectOptionalNpmTarballs(version) { - const tarballs = []; - for (const [packageName] of nodeDirectOptionalPackageTargets(version)) { - const tarball = expectedNodeDirectNpmTarball(packageName, version); - await validateNodeDirectOptionalTarball(packageName, version, tarball); - tarballs.push([packageName, tarball]); - } - const expected = new Set(tarballs.map(([, tarball]) => path.resolve(tarball))); - const unexpected = isDirectory(nodeDirectNpmPackageDir()) - ? readdirSync(nodeDirectNpmPackageDir()) - .filter((name) => name.endsWith(".tgz")) - .map((name) => path.join(nodeDirectNpmPackageDir(), name)) - .filter((file) => !expected.has(path.resolve(file))) - .map((file) => path.basename(file)) - .sort(compareText) - : []; - if (unexpected.length > 0) { - fail(`unexpected Node direct optional npm package artifact(s): ${unexpected.join(", ")}`); - } - return tarballs; -} - -export async function wasixNapiOptionalNpmTarballs(version) { - const targets = artifactTargets(WASIX_NAPI_PRODUCT, WASIX_NAPI_KIND, TOOL); - const tarballs = []; - const packageDir = path.join(ROOT, "target/oliphaunt-wasix-napi/npm-packages"); - for (const [packageName] of wasixNapiOptionalPackageTargets(version)) { - const tarball = path.join( - packageDir, - `${safeNpmPackageFilenamePrefix(packageName)}-${version}.tgz`, - ); - if (!isFile(tarball)) { - fail(`missing WASIX Node-API optional npm package artifact: ${rel(tarball)}`); - } - try { - assertWasixNapiNpmArchive(tarball, targets, version); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - tarballs.push([packageName, tarball]); - } - const expected = new Set(tarballs.map(([, tarball]) => path.resolve(tarball))); - const unexpected = isDirectory(packageDir) - ? readdirSync(packageDir) - .filter((name) => name.endsWith(".tgz")) - .map((name) => path.join(packageDir, name)) - .filter((file) => !expected.has(path.resolve(file))) - .map((file) => path.basename(file)) - .sort(compareText) - : []; - if (unexpected.length > 0) { - fail(`unexpected WASIX Node-API optional npm package artifact(s): ${unexpected.join(", ")}`); - } - return tarballs; -} - -async function packageNodeDirectCarriers() { - ensureNodeDirectReleaseAssets(); - await nodeDirectOptionalNpmTarballs(currentProductVersionSync(NODE_DIRECT_PRODUCT, TOOL)); -} - -async function packageWasixNapiCarriers() { - ensureWasixNapiReleaseAssets(); - await wasixNapiOptionalNpmTarballs(currentProductVersionSync(WASIX_NAPI_PRODUCT, TOOL)); -} - -function packageBrokerCarriers() { - const version = currentProductVersionSync(BROKER_PRODUCT, TOOL); - ensureBrokerReleaseAssets(); - brokerNpmTarballs(version); - run(TOOL, [ - process.execPath, - "tools/release/package_broker_cargo_artifacts.mjs", - "--version", - version, - "--output-dir", - "target/oliphaunt-broker/cargo-artifacts", - ]); -} - -function nativeCargoArtifactTargets(kind) { - return artifactTargets(LIBOLIPHAUNT_NATIVE_PRODUCT, kind, TOOL) - .filter((target) => target.surfaces.includes("rust-native-direct")) - .sort((left, right) => compareText(left.target, right.target)); -} - -function validateNativeCargoArtifacts(outputDir) { - const manifestPath = path.join(outputDir, "packages.json"); - if (!isFile(manifestPath)) { - fail(`missing generated ${LIBOLIPHAUNT_NATIVE_PRODUCT} Cargo artifact manifest: ${rel(manifestPath)}`); - } - let data; - try { - data = JSON.parse(readFileSync(manifestPath, "utf8")); - } catch (error) { - fail(`${rel(manifestPath)} is not valid JSON: ${error.message}`); - } - if (data?.schema !== "oliphaunt-liboliphaunt-cargo-artifacts-v1" || !Array.isArray(data.packages)) { - fail(`${rel(manifestPath)} has an invalid liboliphaunt native Cargo artifact schema`); - } - - const expectedAggregators = new Set([ - ...nativeCargoArtifactTargets(LIBOLIPHAUNT_NATIVE_KIND) - .map((target) => `${LIBOLIPHAUNT_NATIVE_PRODUCT}-${target.target}`), - ...nativeCargoArtifactTargets(LIBOLIPHAUNT_NATIVE_TOOLS_KIND) - .map((target) => `${LIBOLIPHAUNT_NATIVE_TOOLS_PRODUCT}-${target.target}`), - ]); - const expectedRegistryCrates = new Set([...expectedAggregators, LIBOLIPHAUNT_NATIVE_TOOLS_PRODUCT]); - const contribArtifactProduct = contribCarrierDescriptor(TOOL).artifactProduct; - const configuredCrates = new Set( - registryPackageRows({ product: LIBOLIPHAUNT_NATIVE_PRODUCT, packageKind: "crates" }, TOOL) - .map((row) => row.packageName) - .filter((name) => name !== contribArtifactProduct && !name.startsWith(`${contribArtifactProduct}-`)), - ); - assertSameStringSet( - `${LIBOLIPHAUNT_NATIVE_PRODUCT} crates.io packages must match native runtime/tool artifact packages`, - configuredCrates, - expectedRegistryCrates, - ); - const aggregators = new Set(); - const facades = new Set(); - const expectedCratePaths = new Set(); - const packages = []; - - for (const item of data.packages) { - if (item === null || Array.isArray(item) || typeof item !== "object") { - fail(`${rel(manifestPath)} package entries must be objects`); - } - const { name, role, manifestPath: rawManifest, cratePath: rawCrate } = item; - if (![name, role, rawManifest].every((value) => typeof value === "string" && value.length > 0)) { - fail(`${rel(manifestPath)} has an invalid package row: ${JSON.stringify(item)}`); - } - const sourceManifest = path.join(ROOT, rawManifest); - if (!isFile(sourceManifest)) { - fail(`missing generated ${LIBOLIPHAUNT_NATIVE_PRODUCT} Cargo source manifest: ${rawManifest}`); - } - if (typeof rawCrate !== "string" || rawCrate.length === 0) { - fail(`generated ${LIBOLIPHAUNT_NATIVE_PRODUCT} registry crate ${name} must freeze a .crate archive`); - } - const cratePath = path.join(ROOT, rawCrate); - if (!isFile(cratePath) || !cratePath.endsWith(".crate")) { - fail(`missing generated ${LIBOLIPHAUNT_NATIVE_PRODUCT} Cargo archive for ${name}: ${rawCrate}`); - } - expectedCratePaths.add(path.resolve(cratePath)); - if (role === "part") { - const aggregator = name.replace(/-part-\d{3}$/u, ""); - if (aggregator === name || !expectedAggregators.has(aggregator)) { - fail(`unexpected ${LIBOLIPHAUNT_NATIVE_PRODUCT} Cargo part crate ${name}`); - } - packages.push({ name, cratePath, manifestPath: sourceManifest, role }); - continue; - } - if (role === "aggregator") { - if (!expectedAggregators.has(name)) { - fail(`unexpected ${LIBOLIPHAUNT_NATIVE_PRODUCT} Cargo aggregator crate ${name}`); - } - aggregators.add(name); - packages.push({ name, cratePath, manifestPath: sourceManifest, role }); - continue; - } - if (role === "facade") { - if (name !== LIBOLIPHAUNT_NATIVE_TOOLS_PRODUCT) { - fail(`unexpected ${LIBOLIPHAUNT_NATIVE_PRODUCT} Cargo facade crate ${name}`); - } - facades.add(name); - packages.push({ name, cratePath, manifestPath: sourceManifest, role }); - continue; - } - fail(`${rel(manifestPath)} has unsupported Cargo artifact role ${JSON.stringify(role)}`); - } - - const missingAggregators = [...expectedAggregators] - .filter((name) => !aggregators.has(name)) - .sort(compareText); - if (missingAggregators.length > 0) { - fail(`generated ${LIBOLIPHAUNT_NATIVE_PRODUCT} Cargo artifacts are missing aggregator crates: ${missingAggregators.join(", ")}`); - } - if (!facades.has(LIBOLIPHAUNT_NATIVE_TOOLS_PRODUCT)) { - fail(`generated ${LIBOLIPHAUNT_NATIVE_PRODUCT} Cargo artifacts are missing ${LIBOLIPHAUNT_NATIVE_TOOLS_PRODUCT} facade crate`); - } - const unexpected = readdirSync(outputDir) - .filter((name) => name.endsWith(".crate")) - .map((name) => path.join(outputDir, name)) - .filter((file) => !expectedCratePaths.has(path.resolve(file))) - .map((file) => path.basename(file)) - .sort(compareText); - if (unexpected.length > 0) { - fail(`unexpected ${LIBOLIPHAUNT_NATIVE_PRODUCT} Cargo artifact crate(s): ${unexpected.join(", ")}`); - } - const roleOrder = new Map([ - ["part", 0], - ["aggregator", 1], - ["facade", 2], - ]); - return packages.sort((left, right) => - (roleOrder.get(left.role) ?? 99) - (roleOrder.get(right.role) ?? 99) || - compareText(left.name, right.name), - ); -} - -export function liboliphauntNativeCargoArtifactPackages(version = currentProductVersionSync(LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL)) { - const outputDir = path.join(ROOT, "target/liboliphaunt/cargo-artifacts"); - ensureLiboliphauntReleaseAssets(); - run(TOOL, [ - process.execPath, - "tools/release/package-liboliphaunt-cargo-artifacts.mjs", - "--version", - version, - "--output-dir", - rel(outputDir), - ]); - return validateNativeCargoArtifacts(outputDir); -} - -async function packageLiboliphauntNativeCarriers() { - const version = currentProductVersionSync(LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL); - liboliphauntNativeCargoArtifactPackages(version); - liboliphauntNpmTarballs(version); - const contribProduct = contribCarrierDescriptor(TOOL).artifactProduct; - const manifest = await buildMavenArtifactManifest( - "target/release/maven-manifests/liboliphaunt-native.tsv", - { - runtime: true, - extensions: true, - extensionProducts: [contribProduct], - }, - ); - await stageMavenArtifactManifest( - manifest, - path.join(ROOT, "target/release/maven-staging/liboliphaunt-native"), - ); -} - -export function validateWasixCargoArtifacts(outputDir) { - const manifestPath = path.join(outputDir, "packages.json"); - if (!isFile(manifestPath)) { - fail(`missing generated ${WASIX_PRODUCT} Cargo artifact manifest: ${rel(manifestPath)}`); - } - let data; - try { - data = JSON.parse(readFileSync(manifestPath, "utf8")); - } catch (error) { - fail(`${rel(manifestPath)} is not valid JSON: ${error.message}`); - } - if (data?.schema !== WASIX_CARGO_ARTIFACT_SCHEMA || !Array.isArray(data.packages)) { - fail(`${rel(manifestPath)} has an invalid WASIX Cargo artifact schema`); - } - - const contribProduct = contribCarrierDescriptor(TOOL).artifactProduct; - const expectedBaseCrates = new Set(wasixPublicCargoPackageNames()); - const expectedExtensionInventory = expectedWasixExtensionPackageInventory(TOOL, [contribProduct]); - const expectedConfiguredCrates = new Set([ - ...expectedBaseCrates, - ...expectedExtensionInventory.expectedPackageKinds.keys(), - ]); - const configuredCrates = new Set( - registryPackageRows({ product: WASIX_PRODUCT, packageKind: "crates" }, TOOL) - .map((row) => row.packageName), - ); - assertSameStringSet( - `${WASIX_PRODUCT} crates.io packages must match WASIX runtime/AOT artifact packages`, - configuredCrates, - expectedConfiguredCrates, - ); - const generatedCrates = new Set(); - const expectedCratePaths = new Set(); - try { - validateWasixExtensionArtifactInventory( - data.packages, - expectedExtensionInventory, - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - const packages = []; - const allowedKinds = new Set([ - "wasix-runtime", - "wasix-tools", - "wasix-aot", - "wasix-tools-aot", - "icu-data", - "wasix-extension", - "wasix-extension-aot", - ]); - for (const item of data.packages) { - if (item === null || Array.isArray(item) || typeof item !== "object") { - fail(`${rel(manifestPath)} package entries must be objects`); - } - const { name, role, kind, manifestPath: rawManifest, cratePath: rawCrate } = item; - if (![name, role, kind, rawManifest].every((value) => typeof value === "string" && value.length > 0)) { - fail(`${rel(manifestPath)} has an invalid package row: ${JSON.stringify(item)}`); - } - if (role !== "artifact") { - fail(`${rel(manifestPath)} must contain direct WASIX artifact packages, got role ${JSON.stringify(role)}`); - } - if (!allowedKinds.has(kind)) { - fail(`${rel(manifestPath)} has unsupported WASIX Cargo artifact kind ${JSON.stringify(kind)}`); - } - if ( - !expectedBaseCrates.has(name) - && !isExpectedWasixExtensionPackage(name, kind, expectedExtensionInventory) - ) { - fail(`unexpected ${WASIX_PRODUCT} Cargo artifact crate ${name}`); - } - const sourceManifest = path.join(ROOT, rawManifest); - if (!isFile(sourceManifest)) { - fail(`missing generated ${WASIX_PRODUCT} Cargo source manifest: ${rawManifest}`); - } - if (typeof rawCrate !== "string" || rawCrate.length === 0) { - fail(`generated ${WASIX_PRODUCT} Cargo artifact ${name} must have a cratePath`); - } - const cratePath = path.join(ROOT, rawCrate); - if (!isFile(cratePath)) { - fail(`missing generated ${WASIX_PRODUCT} Cargo artifact crate for ${name}: ${rawCrate}`); - } - generatedCrates.add(name); - expectedCratePaths.add(path.resolve(cratePath)); - packages.push({ name, cratePath, manifestPath: sourceManifest }); - } - - const missingBaseCrates = [...expectedBaseCrates] - .filter((name) => !generatedCrates.has(name)) - .sort(compareText); - if (missingBaseCrates.length > 0) { - fail(`generated ${WASIX_PRODUCT} Cargo artifacts are missing configured runtime crates: ${missingBaseCrates.join(", ")}`); - } - const unexpected = readdirSync(outputDir) - .filter((name) => name.endsWith(".crate")) - .map((name) => path.join(outputDir, name)) - .filter((file) => !expectedCratePaths.has(path.resolve(file))) - .map((file) => path.basename(file)) - .sort(compareText); - if (unexpected.length > 0) { - fail(`unexpected ${WASIX_PRODUCT} Cargo artifact crate(s): ${unexpected.join(", ")}`); - } - return packages.sort((left, right) => compareText(left.name, right.name)); -} - -export function liboliphauntWasixCargoArtifactPackages( - version = currentProductVersionSync(WASIX_PRODUCT, TOOL), - { extensionArtifactRoots = [] } = {}, -) { - const outputDir = path.join(ROOT, "target/oliphaunt-wasix/cargo-artifacts"); - ensureWasixReleaseAssets(); - const args = [ - process.execPath, - "tools/release/package_liboliphaunt_wasix_cargo_artifacts.mjs", - "--version", - version, - "--output-dir", - rel(outputDir), - ]; - for (const root of extensionArtifactRoots) { - args.push("--extension-artifact-root", rel(root)); - } - run(TOOL, args); - return validateWasixCargoArtifacts(outputDir); -} - -function packageWasixRuntimeCarriers() { - const contrib = contribCarrierDescriptor(TOOL); - const version = currentProductVersionSync(WASIX_PRODUCT, TOOL); - liboliphauntWasixCargoArtifactPackages(version, { - extensionArtifactRoots: [extensionPackageDir(contrib.artifactProduct, "wasix")], - }); - const portableReleaseArchive = path.join( - ROOT, - `target/oliphaunt-wasix/release-assets/liboliphaunt-wasix-${version}-runtime-portable.tar.zst`, - ); - packWasixRuntimeNpmCarrier({ - version, - portableReleaseArchive, - }); - packWasixIcuNpmCarrier({ - version, - portableReleaseArchive, - icuDataReleaseArchive: path.join( - ROOT, - `target/oliphaunt-wasix/release-assets/liboliphaunt-wasix-${version}-icu-data.tar.zst`, - ), - }); - packWasixToolsNpmCarrier({ version, portableReleaseArchive }); - packageExtensionNpmCarriers(contrib.artifactProduct, { family: "wasix" }); -} - -function extensionPackageDir(product, family = "native") { - return extensionArtifactProductRoot( - product, - family, - path.join(ROOT, "target/extension-artifacts"), - TOOL, - ); -} - -function releaseSurfaceResult(surface) { - return { surface, staged: [], skipped: [] }; -} - -function requireExtensionAssets(product) { - run(TOOL, [ - process.execPath, - "tools/release/check-staged-artifacts.mjs", - "--require-extension-product", - product, - "--require-full-extension-targets", - ]); -} - -async function packageExtensionMavenCarriers(product) { - const manifest = await buildMavenArtifactManifest( - `target/release/maven-manifests/${product}.tsv`, - { - extensions: true, - extensionProducts: [product], - }, - ); - await stageMavenArtifactManifest( - manifest, - path.join(ROOT, "target/release/maven-staging", product), - ); -} - -function packageExtensionNpmCarriers(product, { family = null } = {}) { - const roots = [extensionPackageDir(product, family ?? "native")]; - const targetSets = extensionRegistryPackageTargetSets(product, TOOL); - const targets = targetSets.npmTargets; - const result = releaseSurfaceResult(`${product}-npm${family === null ? "" : `-${family}`}`); - const staged = stageExtensionNpmPackagesForTargets( - roots, - path.join(ROOT, "target/release/extension-carriers/npm", product, family ?? "all"), - targets, - result, - { metaTargets: targets }, - ); - const missingNativeTargets = family === "wasix" - ? [] - : targets.filter((target) => staged.nativeRoots[target] === null); - const missingWasix = family === "native" - ? false - : targetSets.includeWasixNpm && staged.wasixRoot === null; - if (missingNativeTargets.length > 0 || missingWasix || result.staged.length === 0) { - fail( - `${product} npm carrier packaging failed: missing native targets=${missingNativeTargets.join(",") || "none"}; ` - + `missing portable WASIX=${missingWasix ? "yes" : "no"}; ` - + `details=${result.skipped.join("; ") || "none"}`, - ); - } -} - -function packageExtensionNativeCargoCarriers(product) { - for (const target of extensionRegistryPackageTargetSets(product, TOOL).nativeCargoTargets) { - const result = releaseSurfaceResult(`${product}-cargo-${target}`); - const crates = packageNativeExtensionCargoCrates( - [extensionPackageDir(product, "native")], - path.join(ROOT, "target/release/extension-carriers/cargo", product, `native-${target}`), - target, - true, - result, - ); - if (crates.length === 0) { - fail(`${product} native Cargo carrier packaging failed for ${target}: ${result.skipped.join("; ")}`); - } - } -} - -function packageExtensionWasixCargoCarriers(product) { - const outputDir = path.join(ROOT, "target/release/extension-carriers/cargo", product, "wasix"); - run(TOOL, [ - process.execPath, - "tools/release/package_liboliphaunt_wasix_cargo_artifacts.mjs", - "--extensions-only", - "--output-dir", - rel(outputDir), - "--extension-artifact-root", - rel(extensionPackageDir(product, "wasix")), - ]); - const manifestPath = path.join(outputDir, "packages.json"); - if (!isFile(manifestPath)) { - fail(`${product} WASIX Cargo packaging did not generate ${rel(manifestPath)}`); - } - const manifest = JSON.parse(readFileSync(manifestPath, "utf8")); - if (manifest?.schema !== WASIX_CARGO_ARTIFACT_SCHEMA || !Array.isArray(manifest.packages)) { - fail(`${product} WASIX Cargo packaging generated an invalid package manifest`); - } - try { - validateWasixExtensionArtifactInventory( - manifest.packages, - expectedWasixExtensionPackageInventory(TOOL, [product]), - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} - -function packageExtensionFacade(product) { - const packages = packageExtensionCargoFacades( - [product], - path.join(ROOT, "target/release/extension-carriers/cargo", product, "facade"), - ); - if (packages.length !== 1 || packages[0].name !== product) { - fail(`${product} Cargo facade packaging did not generate its canonical package`); - } -} - -async function packageExtensionCarriers(product) { - requireExtensionAssets(product); - await packageExtensionMavenCarriers(product); - packageExtensionNpmCarriers(product); - packageExtensionNativeCargoCarriers(product); - packageExtensionWasixCargoCarriers(product); - packageExtensionFacade(product); -} - -async function packageContribNativeCarriers() { - const product = contribCarrierDescriptor(TOOL).artifactProduct; - const manifest = path.join(extensionPackageDir(product, "native"), "extension-artifacts.json"); - if (!isFile(manifest)) { - fail(`${LIBOLIPHAUNT_NATIVE_PRODUCT} requires staged contrib native artifacts at ${rel(manifest)}`); - } - packageExtensionNpmCarriers(product, { family: "native" }); - packageExtensionNativeCargoCarriers(product); - packageExtensionFacade(product); -} - -export async function packageReleaseCarriers(products) { - const selected = new Set(products); - if (selected.has(LIBOLIPHAUNT_NATIVE_PRODUCT)) { - await packageLiboliphauntNativeCarriers(); - await packageContribNativeCarriers(); - } - if (selected.has(BROKER_PRODUCT)) { - packageBrokerCarriers(); - } - if (selected.has(WASIX_PRODUCT)) { - packageWasixRuntimeCarriers(); - } - if (selected.has(NODE_DIRECT_PRODUCT)) { - await packageNodeDirectCarriers(); - } - if (selected.has(WASIX_NAPI_PRODUCT)) { - await packageWasixNapiCarriers(); - } - for (const product of exactExtensionReleaseProducts(TOOL)) { - if (selected.has(product)) { - await packageExtensionCarriers(product); - } - } -} - -function parseProducts(argv) { - const index = argv.indexOf("--products-json"); - if (index < 0 || !argv[index + 1]) { - fail("usage: package-release-carriers.mjs --products-json JSON", 2); - } - let products; - try { - products = JSON.parse(argv[index + 1]); - } catch (error) { - fail(`--products-json must be valid JSON: ${error.message}`, 2); - } - if (!Array.isArray(products) || !products.every((product) => typeof product === "string")) { - fail("--products-json must be a JSON string array", 2); - } - return products; -} - -if (import.meta.main) { - await packageReleaseCarriers(parseProducts(Bun.argv.slice(2))); -} diff --git a/tools/release/package-release-carriers.mts b/tools/release/package-release-carriers.mts new file mode 100644 index 000000000..4953b4a1b --- /dev/null +++ b/tools/release/package-release-carriers.mts @@ -0,0 +1,80 @@ +#!/usr/bin/env bun +import { packageBrokerCargoArtifacts } from '../../src/broker/tools/package_broker_cargo_artifacts.mts'; +import { BROKER_PRODUCT, packageBrokerCarriers } from '../../src/broker/tools/package-carriers.mts'; +import { packageDatabaseResourceCarriers } from '../../src/database-resources/tools/package-carriers.mts'; +import { packageExtensionCarriers } from '../../src/extensions/artifacts/packages/tools/package-carriers.mts'; +import { packageNativeToolsCarriers } from '../../src/postgres-tools/native/tools/package-carriers.mts'; +import { packageWasixToolsCarriers } from '../../src/postgres-tools/wasix/tools/package-carriers.mts'; +import { + LIBOLIPHAUNT_NATIVE_PRODUCT, + packageLiboliphauntNativeCarriers, +} from '../../src/runtimes/liboliphaunt-native/tools/package-carriers.mts'; +import { + packageWasixRuntimeCarriers, + WASIX_PRODUCT, +} from '../../src/runtimes/liboliphaunt-wasix/tools/package-carriers.mts'; +import { + NODE_DIRECT_PRODUCT, + packageNodeDirectCarriers, +} from '../../src/sdks/ts/node-addon/tools/check-carriers.mts'; +import { + packageWasixNapiCarriers, + WASIX_NAPI_PRODUCT, +} from '../../src/sdks/ts-wasix/node-addon/tools/check-carriers.mts'; +import { fail, TOOL } from '../packaging/release-carrier.mts'; +import { exactExtensionReleaseProducts } from './release-artifact-targets.mts'; + +async function packageReleaseCarriers(products) { + const selected = new Set(products); + if (selected.has('database-resources')) { + await packageDatabaseResourceCarriers(); + } + if (selected.has('postgres-tools-native')) { + await packageNativeToolsCarriers(); + } + if (selected.has('postgres-tools-wasix')) { + await packageWasixToolsCarriers(); + } + if (selected.has(LIBOLIPHAUNT_NATIVE_PRODUCT)) { + await packageLiboliphauntNativeCarriers(); + } + if (selected.has(BROKER_PRODUCT)) { + await packageBrokerCarriers(); + await packageBrokerCargoArtifacts(); + } + if (selected.has(WASIX_PRODUCT)) { + await packageWasixRuntimeCarriers(); + } + if (selected.has(NODE_DIRECT_PRODUCT)) { + await packageNodeDirectCarriers(); + } + if (selected.has(WASIX_NAPI_PRODUCT)) { + await packageWasixNapiCarriers(); + } + for (const product of exactExtensionReleaseProducts(TOOL)) { + if (selected.has(product)) { + await packageExtensionCarriers(product); + } + } +} + +function parseProducts(argv) { + const index = argv.indexOf('--products-json'); + if (index < 0 || !argv[index + 1]) { + fail('usage: package-release-carriers.mts --products-json JSON', 2); + } + let products; + try { + products = JSON.parse(argv[index + 1]); + } catch (error) { + fail(`--products-json must be valid JSON: ${error.message}`, 2); + } + if (!Array.isArray(products) || !products.every((product) => typeof product === 'string')) { + fail('--products-json must be a JSON string array', 2); + } + return products; +} + +if (import.meta.main) { + await packageReleaseCarriers(parseProducts(Bun.argv.slice(2))); +} diff --git a/tools/release/package-release-carriers.sh b/tools/release/package-release-carriers.sh new file mode 100644 index 000000000..28cd9145b --- /dev/null +++ b/tools/release/package-release-carriers.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +if [[ $# != 2 || "$1" != --products-json ]]; then + echo 'usage: package-release-carriers.sh --products-json JSON' >&2 + exit 2 +fi +bash tools/ci/with-projects.sh tools/release/package-release-carriers.mts "$@" diff --git a/tools/release/package.json b/tools/release/package.json new file mode 100644 index 000000000..4b2f9ce02 --- /dev/null +++ b/tools/release/package.json @@ -0,0 +1,8 @@ +{ + "name": "@oliphaunt/release-tools", + "private": true, + "type": "module", + "dependencies": { + "release-please": "17.3.0" + } +} diff --git a/tools/release/package_broker_cargo_artifacts.mjs b/tools/release/package_broker_cargo_artifacts.mjs deleted file mode 100644 index ff14b79db..000000000 --- a/tools/release/package_broker_cargo_artifacts.mjs +++ /dev/null @@ -1,426 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "node:child_process"; -import { createHash } from "node:crypto"; -import { chmod, copyFile, mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises"; -import path from "node:path"; -import { captureCommandBytes, captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { - WINDOWS_VC_RUNTIME_RECEIPT, - parseWindowsVcRuntimeReceipt, -} from "./windows-vc-runtime-closure.mjs"; -import { localWindowsTarInvocation } from "./tar-command.mjs"; -import { - assertReleaseNoticesInDirectory, - releaseNoticeRows, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { - BROKER_PAYLOAD_LICENSE, - assertBrokerDependencyLicensesInArchive, - assertBrokerDependencyLicensesInDirectory, - brokerDependencyLicenseMembers, - normalizeBrokerDependencyLicenseModes, -} from "./broker-dependency-license-contract.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const PRODUCT = "oliphaunt-broker"; -const BROKER_CARRIER_LICENSE = BROKER_PAYLOAD_LICENSE; -const BROKER_NOTICE_OPTIONS = Object.freeze({ profile: "broker" }); -const CRATES_IO_MAX_BYTES = 10 * 1024 * 1024; -const TARGETS = ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"]; - -function fail(message) { - throw new Error(`package_broker_cargo_artifacts.mjs: ${message}`); -} - -function rel(file) { - const relative = path.relative(ROOT, file); - return relative.startsWith("..") ? file : relative; -} - -function usage() { - fail( - "usage: package_broker_cargo_artifacts.mjs [--asset-dir DIR] [--output-dir DIR] [--source-output-dir DIR] [--target TARGET]... [--version VERSION]", - ); -} - -function optionValue(argv, index) { - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) { - usage(); - } - return value; -} - -async function parseArgs(argv) { - const args = { - assetDir: "target/oliphaunt-broker/release-assets", - outputDir: "target/oliphaunt-broker/cargo-artifacts", - sourceOutputDir: undefined, - targets: [], - version: undefined, - }; - let index = 0; - while (index < argv.length) { - const arg = argv[index]; - if (arg === "--asset-dir") { - args.assetDir = optionValue(argv, index); - index += 2; - } else if (arg === "--output-dir") { - args.outputDir = optionValue(argv, index); - index += 2; - } else if (arg === "--source-output-dir") { - args.sourceOutputDir = optionValue(argv, index); - index += 2; - } else if (arg === "--target") { - args.targets.push(optionValue(argv, index)); - index += 2; - } else if (arg === "--version") { - args.version = optionValue(argv, index); - index += 2; - } else { - usage(); - } - } - return { - assetDir: repoPath(args.assetDir), - outputDir: repoPath(args.outputDir), - sourceOutputDir: args.sourceOutputDir === undefined ? undefined : repoPath(args.sourceOutputDir), - targets: args.targets, - version: args.version ?? (await currentVersion()), - }; -} - -function repoPath(value) { - return path.isAbsolute(value) ? value : path.join(ROOT, value); -} - -async function currentVersion() { - const manifest = JSON.parse(await readFile(path.join(ROOT, ".release-please-manifest.json"), "utf8")); - const version = manifest["src/runtimes/broker"]; - if (typeof version !== "string" || version.length === 0) { - fail(".release-please-manifest.json is missing src/runtimes/broker"); - } - return version; -} - -function cargoPackageName(targetId) { - return `${PRODUCT}-${targetId}`; -} - -function cargoLinksName(targetId) { - return `oliphaunt_artifact_broker_${targetId.replaceAll("-", "_")}`; -} - -function sourceCrateDir(targetId) { - return path.join(ROOT, "src/runtimes/broker/crates", targetId); -} - -async function isDirectory(file) { - try { - return (await stat(file)).isDirectory(); - } catch { - return false; - } -} - -async function isFile(file) { - try { - return (await stat(file)).isFile(); - } catch { - return false; - } -} - -function run(args, options = {}) { - const cwd = options.cwd ?? ROOT; - const invocation = args[0] === "tar" - ? localWindowsTarInvocation(args.slice(1), { cwd }) - : { args: args.slice(1), cwd }; - console.log(`\n==> ${args.join(" ")}`); - const result = options.capture - ? captureCommandOutput(args[0], invocation.args, { - cwd: invocation.cwd, - env: options.env ?? process.env, - label: args.join(" "), - }) - : spawnSync(args[0], invocation.args, { - cwd: invocation.cwd, - env: options.env ?? process.env, - stdio: "inherit", - }); - if (result.error !== undefined) { - fail(`${args[0]} failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - if (options.capture) { - process.stderr.write(result.stderr); - } - fail(`${args.join(" ")} failed with status ${result.status ?? "signal"}`); - } - return result.stdout ?? ""; -} - -async function extractMember(archivePath, memberName, destination) { - const candidates = [memberName, `./${memberName}`]; - let data; - for (const candidate of candidates) { - const command = archivePath.endsWith(".zip") - ? ["unzip", "-p", archivePath, candidate] - : ["tar", "-xOf", archivePath, candidate]; - const invocation = command[0] === "tar" - ? localWindowsTarInvocation(command.slice(1), { cwd: ROOT }) - : { args: command.slice(1), cwd: ROOT }; - const result = captureCommandBytes(command[0], invocation.args, { - cwd: invocation.cwd, - label: command.join(" "), - maxOutputBytes: 32 * 1024 * 1024, - }); - if (result.error !== undefined) { - fail(`${command[0]} failed to start: ${result.error.message}`); - } - if (result.status === 0) { - data = result.stdout; - break; - } - } - if (data === undefined) { - fail(`${rel(archivePath)} is missing ${memberName}`); - } - await mkdir(path.dirname(destination), { recursive: true }); - await writeFile(destination, data); -} - -function targetFromSource(targetId, version) { - return { - target: targetId, - packageName: cargoPackageName(targetId), - sourceDir: sourceCrateDir(targetId), - archiveName: `${PRODUCT}-${version}-${targetId}.${targetId === "windows-x64-msvc" ? "zip" : "tar.gz"}`, - }; -} - -async function copySourceCrate(target, crateDir, version) { - if (!(await isDirectory(target.sourceDir))) { - fail(`${target.target} source Cargo artifact crate is missing: ${rel(target.sourceDir)}`); - } - await rm(crateDir, { recursive: true, force: true }); - run(["cp", "-R", target.sourceDir, crateDir]); - const cargoTomlPath = path.join(crateDir, "Cargo.toml"); - const cargoToml = await readFile(cargoTomlPath, "utf8"); - const metadata = Bun.TOML.parse(cargoToml); - const expectedLinks = cargoLinksName(target.target); - if (metadata?.package?.name !== target.packageName) { - fail(`${rel(path.join(target.sourceDir, "Cargo.toml"))} has package.name=${JSON.stringify(metadata?.package?.name)}, expected ${target.packageName}`); - } - if (metadata?.package?.version !== version) { - fail(`${rel(path.join(target.sourceDir, "Cargo.toml"))} has package.version=${JSON.stringify(metadata?.package?.version)}, expected ${version}`); - } - if (metadata?.package?.license !== BROKER_CARRIER_LICENSE) { - fail( - `${rel(path.join(target.sourceDir, "Cargo.toml"))} has package.license=${JSON.stringify(metadata?.package?.license)}, ` - + `expected ${BROKER_CARRIER_LICENSE}`, - ); - } - if (metadata?.package?.links !== expectedLinks) { - fail(`${rel(path.join(target.sourceDir, "Cargo.toml"))} has package.links=${JSON.stringify(metadata?.package?.links)}, expected ${expectedLinks}`); - } - if (metadata?.package?.build !== "build.rs") { - fail(`${rel(path.join(target.sourceDir, "Cargo.toml"))} must declare build = "build.rs"`); - } - const requiredIncludes = [ - "payload/**", - "THIRD_PARTY_LICENSES/**", - ...releaseNoticeRows(BROKER_NOTICE_OPTIONS).map((row) => row.member), - ]; - if ( - !Array.isArray(metadata?.package?.include) - || requiredIncludes.some((member) => !metadata.package.include.includes(member)) - ) { - fail(`${rel(path.join(target.sourceDir, "Cargo.toml"))} must include ${requiredIncludes.join(", ")}`); - } - - const libRsPath = path.join(crateDir, "src/lib.rs"); - const libRs = await readFile(libRsPath, "utf8"); - const constants = Object.fromEntries( - [...libRs.matchAll(/pub const ([A-Z_]+): &str = "([^"]+)";/g)].map((match) => [match[1], match[2]]), - ); - for (const [key, value] of Object.entries({ - PRODUCT, - KIND: "broker-helper", - RELEASE_TARGET: target.target, - })) { - if (constants[key] !== value) { - fail(`${rel(path.join(target.sourceDir, "src/lib.rs"))} has ${key}=${JSON.stringify(constants[key])}, expected ${value}`); - } - } - if (typeof constants.CARGO_TARGET !== "string" || constants.CARGO_TARGET.length === 0) { - fail(`${rel(path.join(target.sourceDir, "src/lib.rs"))} must declare CARGO_TARGET`); - } - if (typeof constants.EXECUTABLE_RELATIVE_PATH !== "string" || constants.EXECUTABLE_RELATIVE_PATH.length === 0) { - fail(`${rel(path.join(target.sourceDir, "src/lib.rs"))} must declare EXECUTABLE_RELATIVE_PATH`); - } - target.executableRelativePath = constants.EXECUTABLE_RELATIVE_PATH; - stageReleaseNotices(crateDir, BROKER_NOTICE_OPTIONS); - assertReleaseNoticesInDirectory(crateDir, BROKER_NOTICE_OPTIONS); -} - -async function sha256File(file) { - const digest = createHash("sha256"); - for await (const chunk of Bun.file(file).stream()) { - digest.update(chunk); - } - return digest.digest("hex"); -} - -async function validateCrate(cratePath, packageName, version, payloadMembers, targetId) { - if (!(await isFile(cratePath))) { - fail(`missing generated Cargo crate ${rel(cratePath)}`); - } - const size = (await stat(cratePath)).size; - if (size > CRATES_IO_MAX_BYTES) { - fail(`${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit`); - } - const expected = new Set([ - `${packageName}-${version}/Cargo.toml`, - `${packageName}-${version}/README.md`, - `${packageName}-${version}/build.rs`, - `${packageName}-${version}/src/lib.rs`, - `${packageName}-${version}/payload/sha256`, - ...releaseNoticeRows(BROKER_NOTICE_OPTIONS).map((row) => `${packageName}-${version}/${row.member}`), - ...brokerDependencyLicenseMembers(targetId, { prefix: `${packageName}-${version}` }), - ...payloadMembers.map((member) => `${packageName}-${version}/payload/${member}`), - ]); - const names = new Set(run(["tar", "-tzf", cratePath], { capture: true }).split(/\r?\n/).filter(Boolean)); - const missing = [...expected].filter((name) => !names.has(name)).sort(); - if (missing.length > 0) { - fail(`${rel(cratePath)} is missing package members: ${missing.join(", ")}`); - } - assertBrokerDependencyLicensesInArchive(cratePath, { - target: targetId, - prefix: `${packageName}-${version}`, - }); -} - -async function packageTarget(target, { version, assetDir, sourceRoot, outputDir, cargoTargetDir }) { - const crateDir = path.join(sourceRoot, target.packageName); - await copySourceCrate(target, crateDir, version); - const archive = path.join(assetDir, target.archiveName); - if (!(await isFile(archive))) { - fail(`missing broker release asset: ${rel(archive)}`); - } - assertBrokerDependencyLicensesInArchive(archive, { target: target.target }); - for (const member of brokerDependencyLicenseMembers(target.target)) { - const destination = path.join(crateDir, ...member.split("/")); - await extractMember(archive, member, destination); - await chmod(destination, 0o644); - } - normalizeBrokerDependencyLicenseModes(crateDir, target.target); - assertBrokerDependencyLicensesInDirectory(crateDir, { target: target.target }); - const payload = path.join(crateDir, "payload", target.executableRelativePath); - await extractMember(archive, target.executableRelativePath, payload); - if ((await stat(payload)).size <= 0) { - fail(`${rel(payload)} must be a non-empty broker helper payload`); - } - await chmod(payload, 0o755); - const payloadMembers = [target.executableRelativePath]; - if (target.target === "windows-x64-msvc") { - const receiptRelativePath = `bin/${WINDOWS_VC_RUNTIME_RECEIPT}`; - const receiptPath = path.join(crateDir, "payload", receiptRelativePath); - await extractMember(archive, receiptRelativePath, receiptPath); - const receipt = parseWindowsVcRuntimeReceipt( - await readFile(receiptPath), - `${rel(archive)}:${receiptRelativePath}`, - ); - payloadMembers.push(receiptRelativePath); - for (const [name, digest] of receipt) { - const relativePath = `bin/${name}`; - const destination = path.join(crateDir, "payload", relativePath); - await extractMember(archive, relativePath, destination); - if (await sha256File(destination) !== digest) { - fail(`${rel(archive)} ${relativePath} does not match ${receiptRelativePath}`); - } - payloadMembers.push(relativePath); - } - } - payloadMembers.sort(); - const checksumText = target.target === "windows-x64-msvc" - ? `${(await Promise.all(payloadMembers.map(async (member) => `${await sha256File(path.join(crateDir, "payload", member))} ${member}`))).join("\n")}\n` - : `${await sha256File(payload)}\n`; - await writeFile(path.join(crateDir, "payload/sha256"), checksumText, "utf8"); - run( - [ - "cargo", - "package", - "--manifest-path", - path.join(crateDir, "Cargo.toml"), - "--target-dir", - cargoTargetDir, - "--allow-dirty", - ], - { env: { ...process.env, OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD: "1" } }, - ); - const packaged = path.join(cargoTargetDir, "package", `${target.packageName}-${version}.crate`); - const output = path.join(outputDir, path.basename(packaged)); - await copyFile(packaged, output); - await validateCrate(output, target.packageName, version, payloadMembers, target.target); - return output; -} - -async function main() { - const args = await parseArgs(Bun.argv.slice(2)); - if (!(await isDirectory(args.assetDir))) { - fail(`broker release asset directory does not exist: ${rel(args.assetDir)}`); - } - const runParent = path.join(ROOT, "target/oliphaunt-broker/cargo-package-runs"); - await mkdir(runParent, { recursive: true }); - const workRoot = await mkdtemp(path.join(runParent, "run-")); - const sourceRoot = args.sourceOutputDir ?? path.join(workRoot, "sources"); - const cargoTargetDir = path.join(workRoot, "cargo-target"); - try { - await rm(args.outputDir, { recursive: true, force: true }); - if (args.sourceOutputDir !== undefined) { - await rm(args.sourceOutputDir, { recursive: true, force: true }); - } - await mkdir(sourceRoot, { recursive: true }); - await mkdir(args.outputDir, { recursive: true }); - - let targets = TARGETS.map((target) => targetFromSource(target, args.version)); - if (args.targets.length > 0) { - const selected = new Set(args.targets); - const known = new Set(TARGETS); - const unknown = [...selected].filter((target) => !known.has(target)).sort(); - if (unknown.length > 0) { - fail(`unsupported broker target(s): ${unknown.join(", ")}`); - } - targets = targets.filter((target) => selected.has(target.target)); - } - - const outputs = []; - for (const target of targets) { - outputs.push( - await packageTarget(target, { - version: args.version, - assetDir: args.assetDir, - sourceRoot, - outputDir: args.outputDir, - cargoTargetDir, - }), - ); - } - - console.log("generated broker Cargo artifact crates:"); - for (const output of outputs) { - console.log(rel(output)); - } - } finally { - await rm(workRoot, { recursive: true, force: true }); - } -} - -try { - await main(); -} catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exitCode = 1; -} diff --git a/tools/release/package_liboliphaunt_wasix_cargo_artifacts.mjs b/tools/release/package_liboliphaunt_wasix_cargo_artifacts.mjs deleted file mode 100755 index 6820e70af..000000000 --- a/tools/release/package_liboliphaunt_wasix_cargo_artifacts.mjs +++ /dev/null @@ -1,1972 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "node:child_process"; -import { createHash } from "node:crypto"; -import { - chmodSync, - copyFileSync, - cpSync, - existsSync, - lstatSync, - mkdirSync, - readFileSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import fs from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { - createDeterministicTar, - manualCargoPackageSource, -} from "./cargo-source-package.mjs"; -import { RUST_BUILD_SCRIPT_SHA256 } from "./rust-build-script-sha256.mjs"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { assertWasixAotArtifactPayloads } from "./check-liboliphaunt-wasix-release-assets.mjs"; -import { - canonicalGzipSync, - portableMemberName, - readPortableArchiveEntries, - readPortableTarZstdBufferEntries, - releaseZstdCompressSync, -} from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { compareText } from "./release-graph.mjs"; -import { - currentProductVersionSync, - extensionMetadata, - extensionReleaseProduct, - extensionReleaseVersion, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { - AOT_PACKAGES, - AOT_TARGET_CFGS, - AOT_TARGET_TRIPLES, - CORE_RUNTIME_ARCHIVE_FILES, - FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES, - ICU_PACKAGE, - ICU_PAYLOAD_ARCHIVE, - RUNTIME_PACKAGE, - TOOLS_AOT_ARTIFACTS, - TOOLS_AOT_PACKAGES, - TOOLS_PACKAGE, - TOOLS_PAYLOAD_FILES, - WASIX_CARGO_ARTIFACT_SCHEMA, - expectedExtensionAotTargets, - wasixExtensionAotPackageName, - wasixExtensionPackageName, -} from "./wasix-cargo-artifact-contract.mjs"; -import { assertCanonicalWasixAotManifest } from "./wasix-aot-manifest.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releaseNoticeRows, - releaseProfilePackageLicense, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { - assertExtensionUpstreamLicensesInArchive, - assertExtensionUpstreamLicensesInDirectory, - extensionRegistryLicense, - stageExtensionUpstreamLicenses, -} from "./extension-upstream-licenses.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const PRODUCT = "liboliphaunt-wasix"; -const PREFIX = "package_liboliphaunt_wasix_cargo_artifacts.mjs"; -const CRATES_IO_MAX_BYTES = 10 * 1024 * 1024; -const DEFAULT_EXTENSION_PART_BYTES = 8 * 1024 * 1024; -const EXPECTED_EXTENSION_AOT_TARGETS = new Set(expectedExtensionAotTargets()); - -function fail(message) { - throw new Error(`${PREFIX}: ${message}`); -} - -function rel(file) { - const relative = path.relative(ROOT, String(file)); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - return String(file).split(path.sep).join("/"); - } - return relative.split(path.sep).join("/"); -} - -function isFile(file) { - try { - const metadata = lstatSync(file); - return metadata.isFile() && !metadata.isSymbolicLink(); - } catch { - return false; - } -} - -function isDirectory(file) { - try { - const metadata = lstatSync(file); - return metadata.isDirectory() && !metadata.isSymbolicLink(); - } catch { - return false; - } -} - -function run(args, { cwd = ROOT, env = process.env, capture = false, label = args.join(" ") } = {}) { - if (!capture) { - console.log(`\n==> ${args.join(" ")}`); - } - const result = capture - ? captureCommandOutput(args[0], args.slice(1), { - cwd, - env, - label, - maxOutputBytes: 200 * 1024 * 1024, - }) - : spawnSync(args[0], args.slice(1), { - cwd, - env, - stdio: "inherit", - }); - if (result.error) { - fail(`${label} failed: ${result.error.message}`); - } - if (result.status !== 0) { - const stderr = capture && result.stderr ? result.stderr.trim() : ""; - fail(`${label} failed${stderr ? `: ${stderr}` : ""}`); - } - return capture ? result.stdout : ""; -} - -function sha256File(file) { - const digest = createHash("sha256"); - const data = readFileSync(file); - digest.update(data); - return digest.digest("hex"); -} - -function checkedTarMember(name, archive) { - if (typeof name !== "string" || name.length === 0) { - fail(`${rel(archive)} contains an empty archive member path`); - } - let normalized; - try { - normalized = portableMemberName(name, "file", rel(archive)); - } catch (error) { - fail(error.message); - } - if (normalized !== name) { - fail(`${rel(archive)} archive member path must already be normalized: ${JSON.stringify(name)}`); - } - return normalized; -} - -function tarZstdMembers(archive) { - try { - return [...readPortableArchiveEntries(archive, { format: "tar.zst" }).keys()]; - } catch (error) { - fail(error.message); - } -} - -export function extractTarZstd(archive, destination) { - let entries; - try { - entries = readPortableArchiveEntries(archive, { format: "tar.zst" }); - } catch (error) { - fail(error.message); - } - rmSync(destination, { recursive: true, force: true }); - const root = path.resolve(destination); - mkdirSync(root, { recursive: true, mode: 0o700 }); - chmodSync(root, 0o700); - - const outputPath = (member) => { - const output = path.resolve(root, ...member.split("/")); - if (!output.startsWith(`${root}${path.sep}`)) { - fail(`${rel(archive)} resolved outside its extraction destination: ${member}`); - } - return output; - }; - const directoryModes = new Map(); - for (const entry of entries.values()) { - const parts = entry.name.split("/"); - const parentLength = entry.isDirectory ? parts.length : parts.length - 1; - for (let length = 1; length <= parentLength; length += 1) { - const member = parts.slice(0, length).join("/"); - if (!directoryModes.has(member)) directoryModes.set(member, 0o755); - } - if (entry.isDirectory) directoryModes.set(entry.name, entry.mode & 0o777); - } - const directories = [...directoryModes].sort(([left], [right]) => { - const depth = left.split("/").length - right.split("/").length; - return depth || compareText(left, right); - }); - for (const [member, finalMode] of directories) { - const output = outputPath(member); - mkdirSync(output, { recursive: true, mode: finalMode | 0o700 }); - // Creation modes are filtered by the process umask. Keep the complete - // tree owner-writable/traversable until every descendant has been staged. - chmodSync(output, finalMode | 0o700); - } - - const files = [...entries.values()] - .filter((entry) => !entry.isDirectory) - .sort((left, right) => compareText(left.name, right.name)); - for (const entry of files) { - const output = outputPath(entry.name); - if (!entry.isFile || entry.isSymbolicLink) { - fail(`${rel(archive)} contains a non-regular extraction member ${entry.name}`); - } - writeFileSync(output, entry.data(), { flag: "wx", mode: 0o600 }); - // chmod after creation makes the archive contract independent of umask. - chmodSync(output, entry.mode & 0o777); - } - - for (const [member, finalMode] of directories.reverse()) { - chmodSync(outputPath(member), finalMode); - } -} - -function writeTarZstdArchive(sourceRoot, output, archiveRoot) { - mkdirSync(path.dirname(output), { recursive: true }); - rmSync(output, { force: true }); - const tar = createDeterministicTar(sourceRoot, archiveRoot, { fail }); - writeFileSync(output, releaseZstdCompressSync(tar)); -} - -function payloadFiles(sourceRoot) { - const files = []; - if (!existsSync(sourceRoot)) { - return files; - } - for (const entry of fs.readdirSync(sourceRoot, { withFileTypes: true })) { - const fullPath = path.join(sourceRoot, entry.name); - if (entry.isDirectory()) { - files.push(...payloadFiles(fullPath)); - } else if (entry.isFile()) { - files.push(fullPath); - } - } - return files.sort(compareText); -} - -function targetAssetRoot(extracted) { - const root = path.join(extracted, "target/oliphaunt-wasix/assets"); - if (!isFile(path.join(root, "manifest.json"))) { - fail(`${rel(extracted)} does not contain target/oliphaunt-wasix/assets/manifest.json`); - } - return root; -} - -function targetAotRoot(extracted, triple) { - const root = path.join(extracted, "target/oliphaunt-wasix/aot", triple); - if (!isFile(path.join(root, "manifest.json"))) { - fail(`${rel(extracted)} does not contain target/oliphaunt-wasix/aot/${triple}/manifest.json`); - } - return root; -} - -function targetIcuRoot(extracted) { - const root = path.join(extracted, "target/oliphaunt-wasix/icu/share/icu"); - if (!isDirectory(root)) { - fail(`${rel(extracted)} does not contain target/oliphaunt-wasix/icu/share/icu`); - } - return root; -} - -function readJson(file) { - try { - return JSON.parse(readFileSync(file, "utf8")); - } catch (error) { - fail(`${rel(file)} is not valid JSON: ${error.message}`); - } -} - -function validateCanonicalAotManifest(manifest, manifestPath, expectedTarget) { - try { - assertCanonicalWasixAotManifest(manifest, { - context: rel(manifestPath), - expectedTarget, - }); - } catch (error) { - fail(error.message); - } -} - -export function validateRuntimePayload(root) { - const extensionRoot = path.join(root, "extensions"); - const extensionFiles = isDirectory(extensionRoot) ? payloadFiles(extensionRoot) : []; - if (extensionFiles.length > 0) { - fail(`WASIX runtime Cargo payload must not contain extension archives: ${extensionFiles.slice(0, 5).map(rel).join(", ")}`); - } - const manifestPath = path.join(root, "manifest.json"); - const manifest = readJson(manifestPath); - if (JSON.stringify(manifest.extensions) !== "[]") { - fail(`${rel(manifestPath)} must have an empty extensions array`); - } - for (const toolKey of ["pg-dump", "psql"]) { - if (Object.hasOwn(manifest, toolKey)) { - fail(`${rel(manifestPath)} must not contain split WASIX tool entry ${toolKey}`); - } - } - for (const required of [ - "oliphaunt.wasix.tar.zst", - "bin/initdb.wasix.wasm", - "cluster-seeds/standard.tar.zst", - "cluster-seeds/standard.json", - "cluster-seeds/icu.tar.zst", - "cluster-seeds/icu.json", - ]) { - if (!isFile(path.join(root, required))) { - fail(`WASIX runtime Cargo payload is missing ${required}`); - } - } - if (manifest.runtime === null || Array.isArray(manifest.runtime) || typeof manifest.runtime !== "object") { - fail(`${rel(manifestPath)} is missing runtime metadata`); - } - if (manifest.runtime.archive !== "oliphaunt.wasix.tar.zst") { - fail(`${rel(manifestPath)} runtime.archive must be oliphaunt.wasix.tar.zst`); - } - if (typeof manifest.runtime.sha256 !== "string" || !/^[0-9a-f]{64}$/u.test(manifest.runtime.sha256)) { - fail(`${rel(manifestPath)} runtime.sha256 must be a lowercase SHA-256 digest`); - } - const runtimeArchivePath = path.join(root, "oliphaunt.wasix.tar.zst"); - const runtimeBytes = readFileSync(runtimeArchivePath); - const runtimeSha256 = createHash("sha256").update(runtimeBytes).digest("hex"); - if (runtimeSha256 !== manifest.runtime.sha256) { - fail( - `${rel(manifestPath)} runtime.sha256 mismatch: expected ${manifest.runtime.sha256}, got ${runtimeSha256}`, - ); - } - let runtimeEntries; - try { - runtimeEntries = readPortableTarZstdBufferEntries(runtimeBytes, { - label: `${rel(manifestPath)} runtime archive`, - }); - } catch (error) { - fail(error.message); - } - const runtimeMembers = [...runtimeEntries.keys()]; - const missingCoreRuntimeFiles = CORE_RUNTIME_ARCHIVE_FILES.filter((member) => { - const entry = runtimeEntries.get(member); - return entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0; - }).sort(compareText); - if (missingCoreRuntimeFiles.length > 0) { - fail(`WASIX runtime Cargo payload must bundle the core runtime closure inside oliphaunt.wasix.tar.zst; missing ${missingCoreRuntimeFiles.join(", ")}`); - } - const bundledIcu = runtimeMembers.filter((member) => member === "oliphaunt/share/icu" || member.startsWith("oliphaunt/share/icu/")); - if (bundledIcu.length > 0) { - fail(`WASIX runtime Cargo payload must not bundle ICU data; found ${bundledIcu[0]} in oliphaunt.wasix.tar.zst`); - } - const bundledTools = runtimeMembers.filter((member) => FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES.includes(member)).sort(compareText); - if (bundledTools.length > 0) { - fail(`WASIX runtime Cargo payload must not bundle standalone tools inside oliphaunt.wasix.tar.zst; found ${bundledTools[0]}`); - } -} - -function validateToolsPayload(root) { - const actual = new Set(payloadFiles(root).map((file) => relPath(root, file))); - const expected = new Set(TOOLS_PAYLOAD_FILES); - if (!sameSet(actual, expected)) { - fail(`WASIX tools Cargo payload file set mismatch for ${rel(root)}: expected ${JSON.stringify([...expected].sort(compareText))}, got ${JSON.stringify([...actual].sort(compareText))}`); - } -} - -function relPath(root, file) { - return path.relative(root, file).split(path.sep).join("/"); -} - -function sameSet(left, right) { - if (left.size !== right.size) { - return false; - } - for (const item of left) { - if (!right.has(item)) { - return false; - } - } - return true; -} - -function pruneEmptyDirs(root) { - if (!isDirectory(root)) { - return; - } - const dirs = []; - for (const item of fs.readdirSync(root, { withFileTypes: true })) { - const fullPath = path.join(root, item.name); - if (item.isDirectory()) { - pruneEmptyDirs(fullPath); - dirs.push(fullPath); - } - } - for (const dir of dirs.sort(compareText).reverse()) { - try { - fs.rmdirSync(dir); - } catch { - // Directory still has payload files. - } - } -} - -function pruneRuntimeArchiveTools(archive, scratch) { - const runtimeMembers = tarZstdMembers(archive); - if (!runtimeMembers.some((member) => FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES.includes(member))) { - return; - } - extractTarZstd(archive, scratch); - for (const member of FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES) { - const file = path.join(scratch, member); - if (existsSync(file)) { - fs.unlinkSync(file); - } - } - pruneEmptyDirs(scratch); - const replacement = `${archive}.tmp`; - writeTarZstdArchive(path.join(scratch, "oliphaunt"), replacement, "oliphaunt"); - fs.renameSync(replacement, archive); -} - -function rewriteRuntimeCoreManifest(root) { - const manifestPath = path.join(root, "manifest.json"); - const manifest = readJson(manifestPath); - if (!manifest.runtime || typeof manifest.runtime !== "object" || Array.isArray(manifest.runtime)) { - fail(`${rel(manifestPath)} is missing runtime metadata`); - } - manifest.runtime.sha256 = sha256File(path.join(root, "oliphaunt.wasix.tar.zst")); - manifest.extensions = []; - delete manifest["pg-dump"]; - delete manifest.psql; - writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); -} - -function splitRuntimeToolsPayload(runtimeRoot, extractRoot) { - const coreRoot = path.join(extractRoot, "runtime-core-payload"); - const toolsRoot = path.join(extractRoot, "tools-payload"); - rmSync(coreRoot, { recursive: true, force: true }); - rmSync(toolsRoot, { recursive: true, force: true }); - cpSync(runtimeRoot, coreRoot, { recursive: true }); - rmSync(path.join(coreRoot, "extensions"), { recursive: true, force: true }); - const missing = []; - for (const relative of TOOLS_PAYLOAD_FILES) { - const source = path.join(runtimeRoot, relative); - if (!isFile(source)) { - missing.push(relative); - continue; - } - const destination = path.join(toolsRoot, relative); - mkdirSync(path.dirname(destination), { recursive: true }); - copyFileSync(source, destination); - const coreFile = path.join(coreRoot, relative); - if (existsSync(coreFile)) { - fs.unlinkSync(coreFile); - } - } - if (missing.length > 0) { - fail(`WASIX tools Cargo payload is missing ${missing.join(", ")}`); - } - pruneRuntimeArchiveTools( - path.join(coreRoot, "oliphaunt.wasix.tar.zst"), - path.join(extractRoot, "runtime-archive-core-pruned"), - ); - rewriteRuntimeCoreManifest(coreRoot); - pruneEmptyDirs(coreRoot); - return [coreRoot, toolsRoot]; -} - -function icuRootContainsData(root) { - if (!isDirectory(root)) { - return false; - } - for (const name of fs.readdirSync(root).sort(compareText)) { - const child = path.join(root, name); - if (isFile(child) && name.startsWith("icudt") && name.endsWith(".dat")) { - return true; - } - if (isDirectory(child) && name.startsWith("icudt") && payloadFiles(child).length > 0) { - return true; - } - } - return false; -} - -function canonicalIcuRoot(root) { - if (icuRootContainsData(root)) { - return root; - } - const candidates = fs.readdirSync(root) - .map((name) => path.join(root, name)) - .filter((child) => isDirectory(child) && icuRootContainsData(child)) - .sort(compareText); - if (candidates.length !== 1) { - fail(`${rel(root)} must contain exactly one ICU data directory, found ${candidates.length}`); - } - return candidates[0]; -} - -function validateIcuPayload(root) { - if (!icuRootContainsData(root)) { - fail(`ICU Cargo payload is missing icudt data under ${rel(root)}`); - } -} - -function writeIcuPayloadArchive(root, payloadRoot) { - const stage = path.join(path.dirname(payloadRoot), "icu-payload-stage"); - rmSync(stage, { recursive: true, force: true }); - rmSync(payloadRoot, { recursive: true, force: true }); - mkdirSync(path.join(stage, "share"), { recursive: true }); - mkdirSync(payloadRoot, { recursive: true }); - cpSync(root, path.join(stage, "share/icu"), { recursive: true }); - const archive = path.join(payloadRoot, ICU_PAYLOAD_ARCHIVE); - writeTarZstdArchive(path.join(stage, "share/icu"), archive, "share/icu"); - const members = tarZstdMembers(archive); - const unexpected = []; - let hasIcuData = false; - for (const member of members) { - if (member === "share/icu") { - continue; - } - if (!member.startsWith("share/icu/")) { - unexpected.push(member); - continue; - } - const relative = member.slice("share/icu/".length).split("/"); - if (relative.length >= 2 && relative[0].startsWith("icudt")) { - hasIcuData = true; - } - } - if (!hasIcuData) { - fail(`${rel(archive)} is missing share/icu/icudt* data`); - } - if (unexpected.length > 0) { - fail(`${rel(archive)} must contain only share/icu data, found ${unexpected[0]}`); - } - return payloadRoot; -} - -export function validateAotPayload(root, expectedTarget) { - const manifestPath = path.join(root, "manifest.json"); - const manifest = readJson(manifestPath); - validateCanonicalAotManifest(manifest, manifestPath, expectedTarget); - let artifactRows; - try { - artifactRows = assertWasixAotArtifactPayloads(manifest, { - context: rel(manifestPath), - readArtifact(artifactPath) { - const file = path.join(root, ...artifactPath.split("/")); - if (!isFile(file) || statSync(file).size <= 0) { - throw new Error(`${rel(manifestPath)} AOT artifact ${artifactPath} must be a non-empty regular file`); - } - return readFileSync(file); - }, - }); - } catch (error) { - fail(error.message); - } - const expected = new Set([ - "manifest.json", - ...releaseNoticeRows({ profile: "wasix-aot" }).map((row) => row.member), - ]); - for (const row of artifactRows) { - if (row.name.startsWith("extension:")) { - fail(`WASIX AOT Cargo payload must not contain extension artifact ${row.name}`); - } - expected.add(row.path); - } - assertReleaseNoticesInDirectory(root, { profile: "wasix-aot" }); - const actual = new Set(payloadFiles(root).map((file) => relPath(root, file))); - if (!sameSet(actual, expected)) { - fail(`WASIX AOT Cargo payload file set mismatch for ${rel(root)}: expected ${JSON.stringify([...expected].sort(compareText))}, got ${JSON.stringify([...actual].sort(compareText))}`); - } -} - -function splitAotToolsPayload(aotRoot, extractRoot, targetId) { - const manifestPath = path.join(aotRoot, "manifest.json"); - const manifest = readJson(manifestPath); - if (!Array.isArray(manifest.artifacts)) { - fail(`${rel(manifestPath)} must contain an artifacts array`); - } - const coreRoot = path.join(extractRoot, `${targetId}-aot-core-payload`); - const toolsRoot = path.join(extractRoot, `${targetId}-aot-tools-payload`); - rmSync(coreRoot, { recursive: true, force: true }); - rmSync(toolsRoot, { recursive: true, force: true }); - const coreArtifacts = []; - const toolsArtifacts = []; - for (const artifact of manifest.artifacts) { - if (!artifact || typeof artifact !== "object" || Array.isArray(artifact)) { - fail(`${rel(manifestPath)} contains a non-object artifact`); - } - const name = artifact.name; - const artifactPath = artifact.path; - if (typeof name !== "string" || typeof artifactPath !== "string") { - fail(`${rel(manifestPath)} contains an artifact without name/path`); - } - const targetRoot = TOOLS_AOT_ARTIFACTS.includes(name) ? toolsRoot : coreRoot; - const targetArtifacts = TOOLS_AOT_ARTIFACTS.includes(name) ? toolsArtifacts : coreArtifacts; - const source = path.join(aotRoot, artifactPath); - if (!isFile(source)) { - fail(`${rel(manifestPath)} references missing AOT artifact ${artifactPath}`); - } - const destination = path.join(targetRoot, artifactPath); - mkdirSync(path.dirname(destination), { recursive: true }); - copyFileSync(source, destination); - targetArtifacts.push(artifact); - } - const missing = TOOLS_AOT_ARTIFACTS.filter((name) => !toolsArtifacts.some((item) => item.name === name)).sort(compareText); - if (missing.length > 0) { - fail(`${rel(manifestPath)} is missing WASIX tools AOT artifacts: ${missing.join(", ")}`); - } - if (coreArtifacts.length === 0) { - fail(`${rel(manifestPath)} generated no core WASIX AOT artifacts`); - } - for (const [targetRoot, targetArtifacts] of [[coreRoot, coreArtifacts], [toolsRoot, toolsArtifacts]]) { - mkdirSync(targetRoot, { recursive: true }); - writeFileSync( - path.join(targetRoot, "manifest.json"), - `${JSON.stringify({ ...manifest, artifacts: targetArtifacts }, null, 2)}\n`, - ); - } - return [coreRoot, toolsRoot]; -} - -function patchToolsAotTemplate(crateDir, target) { - const manifest = path.join(crateDir, "Cargo.toml"); - let text = readFileSync(manifest, "utf8"); - const links = `oliphaunt_artifact_oliphaunt_wasix_tools_aot_${target.replaceAll("-", "_")}`; - text = text.replace(/^links = "[^"]+"$/mu, `links = "${links}"`); - text = text.replace( - /^description = "[^"]+"$/mu, - `description = "Wasmer AOT pg_dump and psql artifacts for oliphaunt-wasix on ${target}"`, - ); - writeFileSync(manifest, text); - - const buildRs = path.join(crateDir, "build.rs"); - text = readFileSync(buildRs, "utf8"); - text = text - .replace('const ARTIFACT_PRODUCT: &str = "liboliphaunt-wasix";', 'const ARTIFACT_PRODUCT: &str = "oliphaunt-wasix-tools";') - .replace('const ARTIFACT_KIND: &str = "wasix-aot";', 'const ARTIFACT_KIND: &str = "wasix-tools-aot";') - .replace('.strip_prefix("liboliphaunt-wasix-aot-")', '.strip_prefix("oliphaunt-wasix-tools-aot-")') - .replace("AOT crate name starts with liboliphaunt-wasix-aot-", "AOT crate name starts with oliphaunt-wasix-tools-aot-"); - writeFileSync(buildRs, text); -} - -function noticeProfileForSpec(spec) { - if (spec.kind === "icu-data") return "wasix-icu-data-crate"; - if (spec.kind === "wasix-runtime") return "wasix-runtime"; - if (spec.kind === "wasix-tools") return "wasix-tools"; - if (spec.kind === "wasix-aot" || spec.kind === "wasix-tools-aot") return "wasix-aot"; - fail(`WASIX Cargo package ${spec.name} has no release notice profile for kind ${spec.kind}`); -} - -function injectCargoNoticeIncludes(text, profile) { - const members = releaseNoticeRows({ profile }).map((row) => row.member); - const match = text.match(/^include = \[(?[\s\S]*?)^\]$/mu) - ?? text.match(/^include = \[(?[^\n]*?)\]$/mu); - if (!match?.groups) fail("Cargo package template must declare one include array"); - const existing = [...match.groups.body.matchAll(/"([^"]+)"/gu)].map((item) => item[1]); - const values = [...new Set([...existing, ...members])]; - const replacement = `include = [\n${values.map((value) => ` ${JSON.stringify(value)},`).join("\n")}\n]`; - return text.slice(0, match.index) + replacement + text.slice(match.index + match[0].length); -} - -function rewriteCargoManifest(manifest, { packageName, version, extensionSources, extensionAotSources, noticeProfile }) { - let text = readFileSync(manifest, "utf8"); - text = text.replace(/^name = "[^"]+"$/mu, `name = "${packageName}"`); - text = text.replace(/^version = "[^"]+"$/mu, `version = "${version}"`); - text = text.replace(/^publish = false\n?/gmu, ""); - text = text.replace( - /^license = "[^"]+"$/mu, - `license = ${JSON.stringify(releaseProfilePackageLicense(noticeProfile).spdx)}`, - ); - text = injectCargoNoticeIncludes(text, noticeProfile); - if (packageName === RUNTIME_PACKAGE && extensionSources.length > 0) { - text = injectRuntimeExtensionDependencies(text, extensionSources, extensionAotSources); - } - if (!text.includes("\n[workspace]")) { - text = `${text.trimEnd()}\n\n[workspace]\n`; - } - writeFileSync(manifest, text); - const packageData = cargoMetadataPackage(manifest); - if (packageData.name !== packageName || packageData.version !== version) { - fail(`${rel(manifest)} generated the wrong package metadata: name=${JSON.stringify(packageData.name)}, version=${JSON.stringify(packageData.version)}`); - } -} - -function extensionSqlFeatureName(sqlName) { - if (typeof sqlName !== "string" || !/^[a-z0-9][a-z0-9_-]*$/u.test(sqlName)) { - fail(`invalid extension SQL feature name ${JSON.stringify(sqlName)}`); - } - return `extension-${sqlName.replaceAll("_", "-")}`; -} - -export function extensionDependencyRequirement(version, versioning) { - const match = version.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)$/u); - if (match === null) { - fail(`extension dependency version must be stable x.y.z, got ${JSON.stringify(version)}`); - } - if (versioning !== "upstream-bound") { - return `=${version}`; - } - const major = Number.parseInt(match[1], 10); - const minor = Number.parseInt(match[2], 10); - const upper = major >= 1 ? `${major + 1}.0.0` : `0.${minor + 1}.0`; - return `>=${version},<${upper}`; -} - -export function injectRuntimeExtensionDependencies(text, extensionSources, extensionAotSources) { - const dependencyLines = []; - const targetDependencyLines = new Map(); - const aotByExtension = new Map(); - for (const source of extensionAotSources) { - const list = aotByExtension.get(source.spec.product) ?? []; - list.push(source); - aotByExtension.set(source.spec.product, list); - } - for (const source of extensionSources) { - const packageName = source.spec.name; - dependencyLines.push(`${packageName} = { version = "${source.spec.dependencyRequirement}", path = "../${packageName}", optional = true }`); - const carrierDependencies = [`dep:${packageName}`]; - for (const aotSource of (aotByExtension.get(source.spec.product) ?? []).sort((left, right) => compareText(left.spec.name, right.spec.name))) { - carrierDependencies.push(`dep:${aotSource.spec.name}`); - } - for (const member of source.spec.members) { - const feature = extensionSqlFeatureName(member.sqlName); - const closureFeatures = member.dependencies.map(extensionSqlFeatureName); - const featureDeps = [...new Set([...closureFeatures, ...carrierDependencies])]; - const replacement = `${feature} = [${featureDeps.map((dep) => JSON.stringify(dep)).join(", ")}]`; - const pattern = new RegExp(`^${escapeRegExp(feature)} = \\[[^\\n]*\\]$`, "mu"); - if (pattern.test(text)) { - text = text.replace(pattern, replacement); - } else { - text = text.replace("[features]\n", `[features]\n${replacement}\n`); - } - } - } - for (const source of extensionAotSources) { - const cfg = AOT_TARGET_CFGS[source.spec.target]; - if (cfg === undefined) { - fail(`unsupported extension AOT target ${source.spec.target}`); - } - const line = `${source.spec.name} = { version = "${source.spec.dependencyRequirement}", path = "../${source.spec.name}", optional = true }`; - const lines = targetDependencyLines.get(cfg) ?? []; - lines.push(line); - targetDependencyLines.set(cfg, lines); - } - if (dependencyLines.length > 0) { - text = text.replace("\n[build-dependencies]", `\n${dependencyLines.join("\n")}\n\n[build-dependencies]`); - } - if (targetDependencyLines.size > 0) { - const blocks = [...targetDependencyLines.entries()] - .sort(([left], [right]) => compareText(left, right)) - .map(([cfg, lines]) => `[target.'${cfg}'.dependencies]\n${lines.sort(compareText).join("\n")}`); - text = text.replace("\n[build-dependencies]", `\n${blocks.join("\n\n")}\n\n[build-dependencies]`); - } - return text; -} - -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"); -} - -function copyPackageSource(spec, sourceRoot, version, extensionSources, extensionAotSources) { - const crateDir = path.join(sourceRoot, spec.name); - if (existsSync(crateDir)) { - fail(`duplicate generated WASIX Cargo package source: ${rel(crateDir)}`); - } - cpSync(spec.templateDir, crateDir, { - recursive: true, - filter: (source) => !["target", "payload", "artifacts"].includes(path.basename(source)), - }); - if (spec.kind === "wasix-tools-aot") { - patchToolsAotTemplate(crateDir, spec.target); - } - cpSync(spec.payloadRoot, path.join(crateDir, spec.payloadDirName), { recursive: true }); - const noticeProfile = noticeProfileForSpec(spec); - stageReleaseNotices(crateDir, { profile: noticeProfile }); - rewriteCargoManifest(path.join(crateDir, "Cargo.toml"), { - packageName: spec.name, - version, - extensionSources, - extensionAotSources, - noticeProfile, - }); - assertReleaseNoticesInDirectory(crateDir, { profile: noticeProfile }); - return crateDir; -} - -function cargoMetadataPackage(manifest) { - const stdout = run(["cargo", "metadata", "--no-deps", "--format-version", "1", "--manifest-path", manifest], { - capture: true, - label: `cargo metadata ${rel(manifest)}`, - }); - const data = JSON.parse(stdout); - if (!Array.isArray(data.packages) || data.packages.length !== 1 || typeof data.packages[0] !== "object") { - fail(`cargo metadata for ${rel(manifest)} did not return exactly one package`); - } - return data.packages[0]; -} - -function cargoPackage(crateDir, targetDir, { noVerify = false } = {}) { - const manifest = path.join(crateDir, "Cargo.toml"); - const packageData = cargoMetadataPackage(manifest); - const command = [ - "cargo", - "package", - "--manifest-path", - manifest, - "--target-dir", - targetDir, - "--allow-dirty", - ]; - if (noVerify) { - command.push("--no-verify"); - } - run(command, { - env: { ...process.env, OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD: "1" }, - }); - const cargoCratePath = path.join(targetDir, "package", `${packageData.name}-${packageData.version}.crate`); - if (!isFile(cargoCratePath)) { - fail(`cargo package did not create ${rel(cargoCratePath)}`); - } - return manualCargoPackageSource( - manifest, - path.join(targetDir, "strict-package", packageData.name), - { root: ROOT, fail, rel }, - ); -} - -function packagedManifestText(text) { - return text.replace(/, path = "\.\.\/[^"]+"/gu, ""); -} - -function cargoPackageWithoutDependencyResolution(crateDir, targetDir) { - const manifest = path.join(crateDir, "Cargo.toml"); - const packageData = cargoMetadataPackage(manifest); - const packageRoot = `${packageData.name}-${packageData.version}`; - const stageRoot = path.join(targetDir, "manual-package-stage"); - const stageDir = path.join(stageRoot, packageRoot); - const cratePath = path.join(targetDir, "package", `${packageRoot}.crate`); - rmSync(stageDir, { recursive: true, force: true }); - mkdirSync(path.dirname(cratePath), { recursive: true }); - cpSync(crateDir, stageDir, { - recursive: true, - filter: (source) => !["target", ".git"].includes(path.basename(source)), - }); - const stagedManifest = path.join(stageDir, "Cargo.toml"); - writeFileSync(stagedManifest, packagedManifestText(readFileSync(stagedManifest, "utf8"))); - cargoMetadataPackage(stagedManifest); - rmSync(cratePath, { force: true }); - writeFileSync(cratePath, canonicalGzipSync(createDeterministicTar(stageDir, packageRoot, { fail }))); - if (!isFile(cratePath)) { - fail(`manual package did not create ${rel(cratePath)}`); - } - return cratePath; -} - -function validateCrateSize(cratePath) { - const size = statSync(cratePath).size; - if (size > CRATES_IO_MAX_BYTES) { - fail(`${rel(cratePath)} is ${size} bytes, above the crates.io 10 MiB package limit; reduce the WASIX Cargo payload before publishing`); - } -} - -function packageSpec(spec, { version, sourceRoot, outputDir, cargoTargetDir, extensionSources, extensionAotSources }) { - const crateDir = copyPackageSource(spec, sourceRoot, version, extensionSources, extensionAotSources); - const cratePath = spec.name === RUNTIME_PACKAGE && extensionSources.length > 0 - ? cargoPackageWithoutDependencyResolution(crateDir, cargoTargetDir) - : cargoPackage(crateDir, cargoTargetDir); - validateCrateSize(cratePath); - const output = path.join(outputDir, path.basename(cratePath)); - copyFileSync(cratePath, output); - const noticeProfile = noticeProfileForSpec(spec); - assertReleaseNoticesInArchive(output, { - prefix: `${spec.name}-${version}`, - profile: noticeProfile, - }); - return { - name: spec.name, - manifestPath: path.join(crateDir, "Cargo.toml"), - cratePath: output, - target: spec.target, - kind: spec.kind, - size: statSync(output).size, - sha256: sha256File(output), - }; -} - -function wasixExtensionPartPackageName(packageName, index) { - if (!Number.isSafeInteger(index) || index < 1 || index > 999) { - fail(`WASIX extension Cargo part index must be 1-based in the range 1..999, got ${JSON.stringify(index)}`); - } - return `${packageName}-part-${String(index).padStart(3, "0")}`; -} - -function rustCrateIdent(packageName) { - return packageName.replaceAll("-", "_"); -} - -function extensionCarrierLegal(spec, carriesBytes) { - if (!carriesBytes) { - return { profile: "code-facade", packageSpdx: "MIT", upstreamMembers: [] }; - } - const sqlNames = spec.members.map((member) => member.sqlName); - const registry = extensionRegistryLicense(spec.product, sqlNames); - const contrib = spec.product === "oliphaunt-extension-contrib-pg18"; - const profile = contrib - ? sqlNames.includes("pgcrypto") ? "contrib-wasix-openssl" : "contrib-wasix" - : "external-wasix"; - return { - profile, - packageSpdx: contrib ? releaseProfilePackageLicense(profile).spdx : registry.packageSpdx, - upstreamMembers: contrib ? [] : sqlNames, - }; -} - -function stageExtensionCarrierLegal(crateDir, spec, carriesBytes) { - const legal = extensionCarrierLegal(spec, carriesBytes); - stageReleaseNotices(crateDir, { profile: legal.profile }); - if (legal.upstreamMembers.length > 0) { - for (const sqlName of legal.upstreamMembers) stageExtensionUpstreamLicenses(sqlName, crateDir); - assertExtensionUpstreamLicensesInDirectory(legal.upstreamMembers, crateDir); - } - assertReleaseNoticesInDirectory(crateDir, { profile: legal.profile }); - return legal; -} - -function extensionCargoIncludes(crateDir, profile, values) { - const legal = releaseNoticeRows({ profile }).map((row) => row.member); - if (isDirectory(path.join(crateDir, "share/licenses"))) legal.push("share/licenses/**"); - return [...new Set([...values, ...legal])]; -} - -function writeExtensionPayloadPartSources({ parentName, product, version, target, subject, members, files, sourceRoot, partBytes }) { - if (!Number.isSafeInteger(partBytes) || partBytes < 1 || partBytes > DEFAULT_EXTENSION_PART_BYTES) { - fail(`extension Cargo --part-bytes must be an integer in 1..${DEFAULT_EXTENSION_PART_BYTES}, got ${JSON.stringify(partBytes)}`); - } - const sortedFiles = [...files].sort((left, right) => compareText(left.payloadRelative, right.payloadRelative)); - if (new Set(sortedFiles.map((file) => file.payloadRelative)).size !== sortedFiles.length) { - fail(`${product} ${target} extension Cargo payload repeats a relative file path`); - } - const parts = []; - let current = null; - const startPart = () => { - const index = parts.length + 1; - const name = wasixExtensionPartPackageName(parentName, index); - if (name.length > 64) fail(`generated crates.io package name exceeds 64 characters: ${name}`); - const sourceDir = path.join(sourceRoot, name); - if (existsSync(sourceDir)) fail(`duplicate generated WASIX extension Cargo part source: ${rel(sourceDir)}`); - mkdirSync(path.join(sourceDir, "src"), { recursive: true }); - current = { index, name, sourceDir, size: 0, target, version }; - parts.push(current); - return current; - }; - for (const file of sortedFiles) { - checkedTarMember(file.payloadRelative, file.source); - const size = statSync(file.source).size; - if (size > partBytes) { - current = null; - const bytes = readFileSync(file.source); - for (let offset = 0, chunk = 0; offset < bytes.length; offset += partBytes, chunk += 1) { - const part = startPart(); - const destination = path.join( - part.sourceDir, - "payload/chunks", - `${file.payloadRelative}.part${String(chunk).padStart(6, "0")}`, - ); - mkdirSync(path.dirname(destination), { recursive: true }); - writeFileSync(destination, bytes.subarray(offset, Math.min(offset + partBytes, bytes.length))); - part.size = Math.min(partBytes, bytes.length - offset); - } - current = null; - continue; - } - if (current === null || current.size + size > partBytes) startPart(); - const destination = path.join(current.sourceDir, "payload/files", file.payloadRelative); - mkdirSync(path.dirname(destination), { recursive: true }); - copyFileSync(file.source, destination); - current.size += size; - } - if (parts.length > 999) fail(`${product}@${version} requires more than 999 Cargo payload parts for ${target}`); - for (const part of parts) { - const spec = { product, members }; - const legal = stageExtensionCarrierLegal(part.sourceDir, spec, true); - part.noticeProfile = legal.profile; - part.upstreamMembers = legal.upstreamMembers; - const includes = extensionCargoIncludes(part.sourceDir, legal.profile, ["Cargo.toml", "README.md", "src/**", "payload/**"]); - writeFileSync(path.join(part.sourceDir, "README.md"), [ - `# ${part.name}`, - "", - `Cargo payload part ${String(part.index).padStart(3, "0")} for the ${subject} on \`${target}\`.`, - "Applications do not depend on this crate directly.", - "", - ].join("\n")); - writeFileSync(path.join(part.sourceDir, "Cargo.toml"), [ - "[package]", - `name = ${JSON.stringify(part.name)}`, - `version = ${JSON.stringify(version)}`, - 'edition = "2024"', - 'rust-version = "1.93"', - `description = ${JSON.stringify(`Cargo payload part for the ${subject} on ${target}`)}`, - 'repository = "https://github.com/f0rr0/oliphaunt"', - 'homepage = "https://oliphaunt.dev"', - `license = ${JSON.stringify(legal.packageSpdx)}`, - `include = [${includes.map((value) => JSON.stringify(value)).join(", ")}]`, - "", - "[lib]", - 'path = "src/lib.rs"', - "", - "[workspace]", - "", - ].join("\n")); - writeFileSync(path.join(part.sourceDir, "src/lib.rs"), [ - "#![deny(unsafe_code)]", - `pub const PRODUCT: &str = ${JSON.stringify(product)};`, - `pub const TARGET: &str = ${JSON.stringify(target)};`, - `pub const PART_INDEX: usize = ${part.index};`, - 'pub const PAYLOAD_ROOT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/payload");', - "", - ].join("\n")); - } - return parts; -} - -function extensionArtifactBuildRs(spec, files, partSources) { - const schema = spec.members.length > 1 - ? "oliphaunt-artifact-manifest-v2" - : "oliphaunt-artifact-manifest-v1"; - const extensionRows = spec.members.map((member) => - ` (${JSON.stringify(member.sqlName)}, &[${member.dependencies.map((dependency) => JSON.stringify(dependency)).join(", ")}]),`).join("\n"); - const fileRows = files.map((file) => - ` (${JSON.stringify(file.sqlName)}, ${JSON.stringify(file.payloadRelative)}, ${JSON.stringify(file.artifactRelative)}, ${JSON.stringify(file.sha256)}),`).join("\n"); - const partRoots = partSources.map((part) => ` ${rustCrateIdent(part.name)}::PAYLOAD_ROOT,`).join("\n"); - return `use std::collections::{BTreeMap, BTreeSet}; -use std::env; -use std::fs; -use std::io::{self, Read}; -use std::path::{Path, PathBuf}; - -const SCHEMA: &str = ${JSON.stringify(schema)}; -const PRODUCT: &str = ${JSON.stringify(spec.product)}; -const VERSION: &str = env!("CARGO_PKG_VERSION"); -const TARGET: &str = ${JSON.stringify(spec.target ?? "portable")}; -const RUNTIME_PRODUCT: &str = ${JSON.stringify(spec.runtimeProduct)}; -const RUNTIME_VERSION: &str = ${JSON.stringify(spec.runtimeVersion)}; -const EXTENSIONS: &[(&str, &[&str])] = &[ -${extensionRows} -]; -const FILES: &[(&str, &str, &str, &str)] = &[ -${fileRows} -]; -const PART_ROOTS: &[&str] = &[ -${partRoots} -]; - -fn main() { - let manifest_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR")); - let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR")); - let payload = out.join("payload"); - if payload.exists() { fs::remove_dir_all(&payload).expect("remove stale extension payload"); } - fs::create_dir_all(&payload).expect("create extension payload"); - let roots: Vec = if PART_ROOTS.is_empty() { - vec![manifest_dir.join("payload")] - } else { - PART_ROOTS.iter().map(PathBuf::from).collect() - }; - let mut chunks: BTreeMap> = BTreeMap::new(); - for root in roots { - println!("cargo::rerun-if-changed={}", root.display()); - copy_complete_files(&root.join("files"), &payload).expect("copy extension payload files"); - collect_chunks(&root.join("chunks"), &root.join("chunks"), &mut chunks).expect("collect extension payload chunks"); - } - for (relative, mut rows) in chunks { - rows.sort_by_key(|(index, _)| *index); - for (expected, (actual, _)) in rows.iter().enumerate() { - if *actual != expected { panic!("non-contiguous extension chunks for {relative}"); } - } - let destination = payload.join(&relative); - fs::create_dir_all(destination.parent().expect("payload parent")).expect("create payload parent"); - let mut writer = fs::File::create(&destination).expect("create reconstructed payload"); - for (_, chunk) in rows { - let mut reader = fs::File::open(chunk).expect("open payload chunk"); - io::copy(&mut reader, &mut writer).expect("append payload chunk"); - } - } - let actual: BTreeSet = collect_files(&payload).expect("collect payload") - .into_iter().map(|file| file.strip_prefix(&payload).expect("payload relative").to_string_lossy().replace(std::path::MAIN_SEPARATOR, "/")).collect(); - let expected: BTreeSet = FILES.iter().map(|(_, relative, _, _)| (*relative).to_owned()).collect(); - if actual != expected { panic!("extension Cargo payload file set mismatch: expected {expected:?}, got {actual:?}"); } - let mut text = format!("schema = {SCHEMA:?}\\nproduct = {PRODUCT:?}\\nversion = {VERSION:?}\\nkind = \\"extension\\"\\ntarget = {TARGET:?}\\nruntime-product = {RUNTIME_PRODUCT:?}\\nruntime-version = {RUNTIME_VERSION:?}\\n"); - for (extension, dependencies) in EXTENSIONS { - if SCHEMA == "oliphaunt-artifact-manifest-v1" { - text.push_str(&format!("extension = {extension:?}\\ndependencies = {dependencies:?}\\n")); - } else { - text.push_str(&format!("\\n[[extensions]]\\nextension = {extension:?}\\ndependencies = {dependencies:?}\\n")); - } - for (_, payload_relative, artifact_relative, expected_sha256) in FILES.iter().filter(|(owner, _, _, _)| owner == extension) { - let source = payload.join(payload_relative); - let actual_sha256 = sha256_file(&source).expect("hash extension payload"); - if actual_sha256 != *expected_sha256 { panic!("extension payload digest mismatch for {}", source.display()); } - let table = if SCHEMA == "oliphaunt-artifact-manifest-v1" { "[[files]]" } else { "[[extensions.files]]" }; - text.push_str(&format!("\\n{table}\\nsource = {:?}\\nrelative = {artifact_relative:?}\\nsha256 = {expected_sha256:?}\\nexecutable = false\\n", source.display().to_string())); - } - } - let manifest = out.join("oliphaunt-artifact.toml"); - fs::write(&manifest, text).expect("write extension artifact manifest"); - println!("cargo::metadata=manifest={}", manifest.display()); -} - -fn copy_complete_files(source: &Path, destination: &Path) -> io::Result<()> { - if !source.is_dir() { return Ok(()); } - for entry in fs::read_dir(source)? { - let entry = entry?; - let path = entry.path(); - let target = destination.join(entry.file_name()); - if entry.file_type()?.is_dir() { copy_complete_files(&path, &target)?; } - else { fs::create_dir_all(target.parent().expect("file parent"))?; fs::copy(path, target)?; } - } - Ok(()) -} - -fn collect_chunks(root: &Path, current: &Path, output: &mut BTreeMap>) -> io::Result<()> { - if !current.is_dir() { return Ok(()); } - for entry in fs::read_dir(current)? { - let entry = entry?; - let path = entry.path(); - if entry.file_type()?.is_dir() { collect_chunks(root, &path, output)?; continue; } - let relative = path.strip_prefix(root).expect("chunk relative").to_string_lossy().replace(std::path::MAIN_SEPARATOR, "/"); - let (name, suffix) = relative.rsplit_once(".part").unwrap_or_else(|| panic!("invalid extension chunk {relative}")); - let index = suffix.parse::().unwrap_or_else(|_| panic!("invalid extension chunk index {relative}")); - output.entry(name.to_owned()).or_default().push((index, path)); - } - Ok(()) -} - -fn collect_files(root: &Path) -> io::Result> { - fn visit(root: &Path, output: &mut Vec) -> io::Result<()> { - for entry in fs::read_dir(root)? { - let entry = entry?; - let path = entry.path(); - if entry.file_type()?.is_dir() { visit(&path, output)?; } else { output.push(path); } - } - Ok(()) - } - let mut output = Vec::new(); - visit(root, &mut output)?; - output.sort(); - Ok(output) -} - -${RUST_BUILD_SCRIPT_SHA256} -`; -} - -function discoverExtensionManifests(roots) { - const manifests = []; - for (const root of roots) { - if (isFile(root) && path.basename(root) === "extension-artifacts.json") { - manifests.push(root); - continue; - } - if (isDirectory(root)) { - for (const file of payloadFiles(root)) { - if (path.basename(file) === "extension-artifacts.json") { - manifests.push(file); - } - } - } - } - return [...new Set(manifests)].sort(compareText); -} - -function extensionManifestMembers(manifest) { - if (manifest?.schema === "oliphaunt-extension-ci-artifacts-v1") { - return typeof manifest.sqlName === "string" && manifest.sqlName ? [manifest] : []; - } - if (manifest?.schema === "oliphaunt-extension-ci-artifacts-v2") { - return Array.isArray(manifest.extensions) ? manifest.extensions : []; - } - return []; -} - -export function extractArchiveMemberToFile(archive, member, destination) { - const normalized = checkedTarMember(member, archive); - let entries; - try { - entries = readPortableArchiveEntries(archive); - } catch (error) { - fail(error.message); - } - const entry = entries.get(normalized); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${rel(archive)} member ${normalized} must be exactly one non-empty regular file`); - } - mkdirSync(path.dirname(destination), { recursive: true }); - try { - writeFileSync(destination, entry.data(), { flag: "wx", mode: 0o600 }); - } catch (error) { - fail(`cannot materialize ${normalized} from ${rel(archive)}: ${error.message}`); - } - const metadata = lstatSync(destination); - if (!metadata.isFile() || metadata.isSymbolicLink()) { - rmSync(destination, { force: true }); - fail(`extracted ${normalized} from ${rel(archive)} is not a regular non-symlink file`); - } - return destination; -} - -function extensionWasixMembers(extensionDir, manifest, materializeRoot) { - const members = extensionManifestMembers(manifest); - if (members.length === 0) return []; - const rows = members.map((member) => { - const matches = Array.isArray(member.assets) - ? member.assets.filter((asset) => - asset?.family === "wasix" - && asset.kind === "wasix-runtime" - && asset.target === "wasix-portable" - ) - : []; - if (matches.length !== 1) { - fail(`${manifest.product}/${member.sqlName} must declare exactly one portable WASIX runtime asset`); - } - return { member, asset: matches[0] }; - }); - if (manifest.schema === "oliphaunt-extension-ci-artifacts-v1") { - const [{ member, asset }] = rows; - const archive = path.join(extensionDir, "release-assets", asset.name); - if (!isFile(archive) || sha256File(archive) !== asset.sha256 || statSync(archive).size !== asset.bytes) { - fail(`${manifest.product}/${member.sqlName} portable WASIX asset is missing or changed`); - } - return [{ - sqlName: member.sqlName, - dependencies: [...(member.dependencies ?? [])], - nativeModuleStem: member.nativeModuleStem, - archive, - sha256: asset.sha256, - size: asset.bytes, - }]; - } - - const carrierNames = new Set(rows.map(({ asset }) => asset.carrierAsset)); - if (carrierNames.size !== 1 || carrierNames.has(undefined)) { - fail(`${manifest.product} portable WASIX members must share one aggregate carrier`); - } - const carrierName = [...carrierNames][0]; - const carrierRows = Array.isArray(manifest.carrierAssets) - ? manifest.carrierAssets.filter((carrier) => - carrier?.name === carrierName - && carrier.family === "wasix" - && carrier.target === "wasix-portable" - && carrier.kind === "extension-bundle" - ) - : []; - if (carrierRows.length !== 1) { - fail(`${manifest.product} must declare exactly one portable WASIX aggregate carrier row`); - } - const carrier = carrierRows[0]; - const carrierPath = path.join(extensionDir, "release-assets", carrierName); - if (!isFile(carrierPath) || sha256File(carrierPath) !== carrier.sha256 || statSync(carrierPath).size !== carrier.bytes) { - fail(`${manifest.product} portable WASIX aggregate carrier is missing or changed`); - } - return rows.map(({ member, asset }) => { - const expectedRoot = carrierName.replace(/\.tar\.gz$/u, ""); - if (asset.carrierRoot !== expectedRoot || typeof asset.memberPath !== "string") { - fail(`${manifest.product}/${member.sqlName} has an invalid aggregate carrier locator`); - } - const archive = path.join(materializeRoot, manifest.product, member.sqlName, "extension.tar.zst"); - extractArchiveMemberToFile(carrierPath, `${asset.carrierRoot}/${asset.memberPath}`, archive); - if (statSync(archive).size !== asset.bytes || sha256File(archive) !== asset.sha256) { - rmSync(archive, { force: true }); - fail(`${manifest.product}/${member.sqlName} nested portable WASIX bytes do not match the frozen member digest`); - } - return { - sqlName: member.sqlName, - dependencies: [...(member.dependencies ?? [])], - nativeModuleStem: member.nativeModuleStem, - archive, - sha256: asset.sha256, - size: asset.bytes, - }; - }); -} - -function extensionAotSpecs(extensionDir, { product, version, members, versioning, dependencyRequirement, runtimeProduct, runtimeVersion }) { - const aotRoot = path.join(extensionDir, "wasix-aot"); - if (!isDirectory(aotRoot)) { - return []; - } - const specs = []; - const seenTargets = new Set(); - for (const targetDir of fs.readdirSync(aotRoot).map((name) => path.join(aotRoot, name)).filter(isDirectory).sort(compareText)) { - const targetId = path.basename(targetDir); - const expectedTarget = AOT_TARGET_TRIPLES[targetId]; - if (expectedTarget === undefined) { - fail(`${rel(aotRoot)} contains unknown extension AOT target id ${targetId}`); - } - const aotMembers = []; - for (const member of members.filter((candidate) => candidate.requiresAot)) { - const sourceDir = isFile(path.join(targetDir, "manifest.json")) - ? targetDir - : path.join(targetDir, member.sqlName); - const manifestPath = path.join(sourceDir, "manifest.json"); - if (!isFile(manifestPath)) { - fail(`${product}/${member.sqlName} is missing WASIX AOT manifest for ${targetId}`); - } - const data = readJson(manifestPath); - validateCanonicalAotManifest(data, manifestPath, expectedTarget); - let artifactRows; - try { - artifactRows = assertWasixAotArtifactPayloads(data, { - context: rel(manifestPath), - readArtifact(artifactPath) { - const file = path.join(sourceDir, ...artifactPath.split("/")); - if (!isFile(file) || statSync(file).size <= 0) { - throw new Error(`${rel(manifestPath)} references missing or empty AOT artifact ${artifactPath}`); - } - return readFileSync(file); - }, - }); - } catch (error) { - fail(error.message); - } - const expectedPrefix = `extension:${member.sqlName}`; - for (const artifact of artifactRows) { - const { name, path: artifactPath } = artifact; - if (typeof name !== "string" || !(name === expectedPrefix || name.startsWith(`${expectedPrefix}:`))) { - fail(`${rel(manifestPath)} contains AOT artifact ${JSON.stringify(name)} for ${member.sqlName}`); - } - } - aotMembers.push({ - sqlName: member.sqlName, - dependencies: member.dependencies, - sourceDir, - }); - } - if (aotMembers.length === 0) continue; - if (seenTargets.has(expectedTarget)) fail(`${rel(aotRoot)} has duplicate extension AOT target ${expectedTarget}`); - seenTargets.add(expectedTarget); - specs.push({ - name: wasixExtensionAotPackageName(product, expectedTarget), - product, - version, - members: aotMembers, - target: expectedTarget, - versioning, - dependencyRequirement, - runtimeProduct, - runtimeVersion, - }); - } - return specs.sort((left, right) => compareText(left.target, right.target)); -} - -function extensionCargoSpecs(extensionRoots, materializeRoot) { - const specs = []; - for (const manifestPath of discoverExtensionManifests(extensionRoots)) { - const manifest = readJson(manifestPath); - if (manifest.family === "native") { - continue; - } - const product = manifest.artifactProduct ?? manifest.product; - const { version } = manifest; - if (![product, version].every((value) => typeof value === "string" && value)) { - fail(`${rel(manifestPath)} is missing artifactProduct/product or version`); - } - const releaseProduct = extensionReleaseProduct(product, "wasix", PREFIX); - const expectedVersion = extensionReleaseVersion(product, "wasix", PREFIX); - if ((manifest.releaseProduct ?? product) !== releaseProduct || version !== expectedVersion) { - fail( - `${rel(manifestPath)} must bind ${product} WASIX carriers to ${releaseProduct}@${expectedVersion}`, - ); - } - if (releaseProduct !== product && manifest.family !== "wasix") { - fail(`${rel(manifestPath)} runtime-owned WASIX carrier manifest must declare family=wasix`); - } - const metadata = extensionMetadata(product, PREFIX); - const expectedMembers = extensionSqlNames(product, PREFIX); - const manifestMembers = extensionManifestMembers(manifest).map((member) => member.sqlName); - if (JSON.stringify(manifestMembers) !== JSON.stringify(expectedMembers)) { - fail(`${rel(manifestPath)} member set does not match ${product} release metadata`); - } - const runtimeProduct = metadata.compatibility.wasixRuntimeProduct; - const runtimeVersion = metadata.compatibility.wasixRuntimeVersion; - const members = extensionWasixMembers(path.dirname(manifestPath), manifest, materializeRoot) - .map((member) => ({ ...member, requiresAot: typeof member.nativeModuleStem === "string" && Boolean(member.nativeModuleStem) })); - const dependencyRequirement = extensionDependencyRequirement(version, metadata.versioning); - const spec = { - name: wasixExtensionPackageName(product), - product, - version, - members, - versioning: metadata.versioning, - dependencyRequirement, - runtimeProduct, - runtimeVersion, - }; - spec.aotTargets = extensionAotSpecs(path.dirname(manifestPath), { - ...spec, - versioning: metadata.versioning, - dependencyRequirement, - }); - specs.push(spec); - } - return specs.sort((left, right) => compareText(left.name, right.name)); -} - -function validateExtensionAotCoverage(extensionSpecs) { - for (const spec of extensionSpecs) { - if (!spec.members.some((member) => member.requiresAot)) { - continue; - } - const actualTargets = new Set(spec.aotTargets.map((aotSpec) => aotSpec.target)); - if (!sameSet(actualTargets, EXPECTED_EXTENSION_AOT_TARGETS)) { - fail(`${spec.product} has a WASIX native module but incomplete extension AOT artifacts; expected=${JSON.stringify([...EXPECTED_EXTENSION_AOT_TARGETS].sort(compareText))}, actual=${JSON.stringify([...actualTargets].sort(compareText))}`); - } - } -} - -function writeExtensionCargoSource(spec, sourceRoot, partBytes) { - const crateDir = path.join(sourceRoot, spec.name); - if (existsSync(crateDir)) { - fail(`duplicate generated WASIX extension Cargo package source: ${rel(crateDir)}`); - } - mkdirSync(path.join(crateDir, "src"), { recursive: true }); - const subject = spec.members.length === 1 - ? spec.members[0].sqlName - : `${spec.members.length}-member PostgreSQL 18 contrib bundle`; - const files = spec.members.map((member) => ({ - sqlName: member.sqlName, - source: member.archive, - payloadRelative: `extensions/${member.sqlName}/extension.tar.zst`, - artifactRelative: `extensions/${member.sqlName}.tar.zst`, - sha256: member.sha256, - })); - const split = files.reduce((sum, file) => sum + statSync(file.source).size, 0) > partBytes; - const partSources = split - ? writeExtensionPayloadPartSources({ - parentName: spec.name, - product: spec.product, - version: spec.version, - target: "portable", - subject: `${subject} Oliphaunt WASIX extension carrier`, - members: spec.members, - files, - sourceRoot, - partBytes, - }) - : []; - if (!split) { - for (const file of files) { - const destination = path.join(crateDir, "payload/files", file.payloadRelative); - mkdirSync(path.dirname(destination), { recursive: true }); - copyFileSync(file.source, destination); - } - } - const legal = stageExtensionCarrierLegal(crateDir, spec, !split); - const includes = extensionCargoIncludes( - crateDir, - legal.profile, - ["Cargo.toml", "README.md", "build.rs", "src/**", ...(split ? [] : ["payload/**"])], - ); - const links = `oliphaunt_artifact_extension_${spec.product.replace(/^oliphaunt-extension-/u, "").replaceAll("-", "_")}_wasix`; - writeFileSync(path.join(crateDir, "README.md"), [ - `# ${spec.name}`, - "", - `Cargo artifact package for the ${subject} Oliphaunt WASIX extension carrier.`, - "", - ].join("\n")); - writeFileSync(path.join(crateDir, "Cargo.toml"), [ - "[package]", - `name = "${spec.name}"`, - `version = "${spec.version}"`, - 'edition = "2024"', - 'rust-version = "1.93"', - `description = "Oliphaunt WASIX artifact package for the ${subject}"`, - 'repository = "https://github.com/f0rr0/oliphaunt"', - 'homepage = "https://oliphaunt.dev"', - `license = ${JSON.stringify(legal.packageSpdx)}`, - `links = "${links}"`, - 'build = "build.rs"', - `include = [${includes.map((value) => JSON.stringify(value)).join(", ")}]`, - "", - "[lib]", - 'path = "src/lib.rs"', - "", - "[build-dependencies]", - ...partSources.map((part) => `${part.name} = { version = "=${spec.version}", path = "../${part.name}" }`), - "", - "[workspace]", - "", - ].join("\n")); - writeFileSync(path.join(crateDir, "src/lib.rs"), [ - "#![deny(unsafe_code)]", - "", - `pub const SQL_NAMES: &[&str] = &[${spec.members.map((member) => JSON.stringify(member.sqlName)).join(", ")}];`, - ...(spec.members.length === 1 ? [`pub const SQL_NAME: &str = ${JSON.stringify(spec.members[0].sqlName)};`] : []), - "", - "pub fn archive(sql_name: &str) -> Option<&'static [u8]> {", - " match sql_name {", - ...spec.members.map((member) => ` ${JSON.stringify(member.sqlName)} => Some(include_bytes!(concat!(env!("OUT_DIR"), "/payload/extensions/${member.sqlName}/extension.tar.zst"))),`), - " _ => None,", - " }", - "}", - "", - "pub fn archive_sha256(sql_name: &str) -> Option<&'static str> {", - " match sql_name {", - ...spec.members.map((member) => ` ${JSON.stringify(member.sqlName)} => Some(${JSON.stringify(member.sha256)}),`), - " _ => None,", - " }", - "}", - "", - ].join("\n")); - writeFileSync(path.join(crateDir, "build.rs"), extensionArtifactBuildRs({ ...spec, target: "portable" }, files, partSources)); - return { - spec, - sourceDir: crateDir, - partSources, - noticeProfile: legal.profile, - upstreamMembers: legal.upstreamMembers, - }; -} - -function writeExtensionAotCargoSource(spec, sourceRoot, partBytes) { - const crateDir = path.join(sourceRoot, spec.name); - if (existsSync(crateDir)) { - fail(`duplicate generated WASIX extension AOT Cargo package source: ${rel(crateDir)}`); - } - mkdirSync(path.join(crateDir, "src"), { recursive: true }); - const artifacts = []; - for (const member of spec.members) { - const manifestPath = path.join(member.sourceDir, "manifest.json"); - const manifest = readJson(manifestPath); - const manifestDestination = path.join(crateDir, "manifests", `${member.sqlName}.json`); - mkdirSync(path.dirname(manifestDestination), { recursive: true }); - copyFileSync(manifestPath, manifestDestination); - for (const artifact of [...(manifest.artifacts ?? [])].sort((left, right) => compareText(left?.name ?? "", right?.name ?? ""))) { - const name = artifact?.name; - const artifactPath = artifact?.path; - if (typeof name !== "string" || typeof artifactPath !== "string") { - fail(`${rel(manifestPath)} contains an AOT artifact without name/path`); - } - const source = path.join(member.sourceDir, artifactPath); - if (!isFile(source)) fail(`${rel(manifestPath)} references missing AOT artifact ${artifactPath}`); - artifacts.push({ - sqlName: member.sqlName, - name, - source, - payloadRelative: `extensions/${member.sqlName}/${artifactPath}`, - artifactRelative: `extensions/${member.sqlName}/${artifactPath}`, - sha256: sha256File(source), - }); - } - } - if (artifacts.length === 0) { - fail(`${spec.product} ${spec.target} must contain extension AOT artifacts`); - } - if (new Set(artifacts.map((artifact) => artifact.name)).size !== artifacts.length) { - fail(`${spec.product} ${spec.target} repeats an extension AOT artifact name`); - } - const split = artifacts.reduce((sum, artifact) => sum + statSync(artifact.source).size, 0) > partBytes; - const partSources = split - ? writeExtensionPayloadPartSources({ - parentName: spec.name, - product: spec.product, - version: spec.version, - target: spec.target, - subject: `${spec.members.length}-member Oliphaunt WASIX extension AOT carrier`, - members: spec.members, - files: artifacts, - sourceRoot, - partBytes, - }) - : []; - if (!split) { - for (const artifact of artifacts) { - const destination = path.join(crateDir, "payload/files", artifact.payloadRelative); - mkdirSync(path.dirname(destination), { recursive: true }); - copyFileSync(artifact.source, destination); - } - } - const legal = stageExtensionCarrierLegal(crateDir, spec, !split); - const includes = extensionCargoIncludes( - crateDir, - legal.profile, - ["Cargo.toml", "README.md", "build.rs", "src/**", "manifests/**", ...(split ? [] : ["payload/**"])], - ); - const subject = spec.members.length === 1 ? spec.members[0].sqlName : `${spec.members.length}-member bundle`; - const links = `oliphaunt_artifact_extension_${spec.product.replace(/^oliphaunt-extension-/u, "").replaceAll("-", "_")}_aot_${spec.target.replaceAll("-", "_")}`; - writeFileSync(path.join(crateDir, "README.md"), [ - `# ${spec.name}`, - "", - `Cargo artifact package for the ${subject} Oliphaunt WASIX AOT artifacts on \`${spec.target}\`.`, - "", - ].join("\n")); - writeFileSync(path.join(crateDir, "Cargo.toml"), [ - "[package]", - `name = "${spec.name}"`, - `version = "${spec.version}"`, - 'edition = "2024"', - 'rust-version = "1.93"', - `description = "Oliphaunt WASIX AOT artifact package for the ${subject} on ${spec.target}"`, - 'repository = "https://github.com/f0rr0/oliphaunt"', - 'homepage = "https://oliphaunt.dev"', - `license = ${JSON.stringify(legal.packageSpdx)}`, - `links = ${JSON.stringify(links)}`, - 'build = "build.rs"', - `include = [${includes.map((value) => JSON.stringify(value)).join(", ")}]`, - "", - "[lib]", - 'path = "src/lib.rs"', - "", - "[build-dependencies]", - ...partSources.map((part) => `${part.name} = { version = "=${spec.version}", path = "../${part.name}" }`), - "", - "[workspace]", - "", - ].join("\n")); - writeFileSync(path.join(crateDir, "src/lib.rs"), [ - "#![deny(unsafe_code)]", - "", - `pub const SQL_NAMES: &[&str] = &[${spec.members.map((member) => JSON.stringify(member.sqlName)).join(", ")}];`, - ...(spec.members.length === 1 ? [`pub const SQL_NAME: &str = ${JSON.stringify(spec.members[0].sqlName)};`] : []), - `pub const TARGET_TRIPLE: &str = "${spec.target}";`, - "", - "pub fn aot_manifest_json(sql_name: &str) -> Option<&'static str> {", - " match sql_name {", - ...spec.members.map((member) => ` ${JSON.stringify(member.sqlName)} => Some(include_str!("../manifests/${member.sqlName}.json")),`), - " _ => None,", - " }", - "}", - "", - "pub fn aot_artifact_bytes(name: &str) -> Option<&'static [u8]> {", - " match name {", - ...artifacts.map((artifact) => ` ${JSON.stringify(artifact.name)} => Some(include_bytes!(concat!(env!("OUT_DIR"), "/payload/${artifact.payloadRelative}"))),`), - " _ => None,", - " }", - "}", - "", - ].join("\n")); - writeFileSync(path.join(crateDir, "build.rs"), extensionArtifactBuildRs(spec, artifacts, partSources)); - return { - spec, - sourceDir: crateDir, - partSources, - noticeProfile: legal.profile, - upstreamMembers: legal.upstreamMembers, - }; -} - -function assertPackedExtensionLegal(output, carrier) { - const prefix = `${carrier.name ?? carrier.spec.name}-${carrier.version ?? carrier.spec.version}`; - assertReleaseNoticesInArchive(output, { - prefix, - profile: carrier.noticeProfile, - }); - if (carrier.upstreamMembers.length > 0) { - assertExtensionUpstreamLicensesInArchive(carrier.upstreamMembers, output, { prefix }); - } -} - -function packageExtensionSource(source, { outputDir, cargoTargetDir }) { - const packages = []; - for (const part of source.partSources ?? []) { - const cratePath = cargoPackage(part.sourceDir, cargoTargetDir); - validateCrateSize(cratePath); - const output = path.join(outputDir, path.basename(cratePath)); - copyFileSync(cratePath, output); - assertPackedExtensionLegal(output, part); - packages.push({ - name: part.name, - manifestPath: path.join(part.sourceDir, "Cargo.toml"), - cratePath: output, - target: "wasix-portable", - kind: "wasix-extension", - size: statSync(output).size, - sha256: sha256File(output), - versioning: source.spec.versioning, - dependencyRequirement: source.spec.dependencyRequirement, - }); - } - const cratePath = source.partSources?.length > 0 - ? cargoPackageWithoutDependencyResolution(source.sourceDir, cargoTargetDir) - : cargoPackage(source.sourceDir, cargoTargetDir); - validateCrateSize(cratePath); - const output = path.join(outputDir, path.basename(cratePath)); - copyFileSync(cratePath, output); - assertPackedExtensionLegal(output, source); - packages.push({ - name: source.spec.name, - manifestPath: path.join(source.sourceDir, "Cargo.toml"), - cratePath: output, - target: "wasix-portable", - kind: "wasix-extension", - size: statSync(output).size, - sha256: sha256File(output), - versioning: source.spec.versioning, - dependencyRequirement: source.spec.dependencyRequirement, - }); - return packages; -} - -function packageExtensionAotSource(source, { outputDir, cargoTargetDir }) { - const packages = []; - for (const part of source.partSources ?? []) { - const cratePath = cargoPackage(part.sourceDir, cargoTargetDir); - validateCrateSize(cratePath); - const output = path.join(outputDir, path.basename(cratePath)); - copyFileSync(cratePath, output); - assertPackedExtensionLegal(output, part); - packages.push({ - name: part.name, - manifestPath: path.join(part.sourceDir, "Cargo.toml"), - cratePath: output, - target: part.target, - kind: "wasix-extension-aot", - size: statSync(output).size, - sha256: sha256File(output), - versioning: source.spec.versioning, - dependencyRequirement: source.spec.dependencyRequirement, - }); - } - const cratePath = source.partSources?.length > 0 - ? cargoPackageWithoutDependencyResolution(source.sourceDir, cargoTargetDir) - : cargoPackage(source.sourceDir, cargoTargetDir); - validateCrateSize(cratePath); - const output = path.join(outputDir, path.basename(cratePath)); - copyFileSync(cratePath, output); - assertPackedExtensionLegal(output, source); - packages.push({ - name: source.spec.name, - manifestPath: path.join(source.sourceDir, "Cargo.toml"), - cratePath: output, - target: source.spec.target, - kind: "wasix-extension-aot", - size: statSync(output).size, - sha256: sha256File(output), - versioning: source.spec.versioning, - dependencyRequirement: source.spec.dependencyRequirement, - }); - return packages; -} - -function packageSpecs(assetDir, extractRoot, version) { - const specs = []; - const runtimeArchive = path.join(assetDir, `liboliphaunt-wasix-${version}-runtime-portable.tar.zst`); - if (!isFile(runtimeArchive)) { - fail(`missing WASIX portable runtime release asset: ${rel(runtimeArchive)}`); - } - const runtimeExtract = path.join(extractRoot, "runtime-extracted"); - extractTarZstd(runtimeArchive, runtimeExtract); - const runtimeRoot = targetAssetRoot(runtimeExtract); - validateRuntimePayload(runtimeRoot); - const [runtimeCoreRoot, toolsRoot] = splitRuntimeToolsPayload(runtimeRoot, extractRoot); - validateRuntimePayload(runtimeCoreRoot); - validateToolsPayload(toolsRoot); - specs.push({ - name: RUNTIME_PACKAGE, - target: "portable", - kind: "wasix-runtime", - templateDir: path.join(ROOT, "src/runtimes/liboliphaunt/wasix/crates/assets"), - payloadRoot: runtimeCoreRoot, - payloadDirName: "payload", - }); - specs.push({ - name: TOOLS_PACKAGE, - target: "portable", - kind: "wasix-tools", - templateDir: path.join(ROOT, "src/runtimes/liboliphaunt/wasix/crates/tools"), - payloadRoot: toolsRoot, - payloadDirName: "payload", - }); - - const icuArchive = path.join(assetDir, `liboliphaunt-wasix-${version}-icu-data.tar.zst`); - if (!isFile(icuArchive)) { - fail(`missing WASIX ICU data release asset: ${rel(icuArchive)}`); - } - const icuExtract = path.join(extractRoot, "icu-extracted"); - extractTarZstd(icuArchive, icuExtract); - const icuRoot = canonicalIcuRoot(targetIcuRoot(icuExtract)); - validateIcuPayload(icuRoot); - const icuPayloadRoot = writeIcuPayloadArchive(icuRoot, path.join(extractRoot, "icu-payload")); - specs.push({ - name: ICU_PACKAGE, - target: "portable", - kind: "icu-data", - templateDir: path.join(ROOT, "src/runtimes/liboliphaunt/icu"), - payloadRoot: icuPayloadRoot, - payloadDirName: "payload", - }); - - for (const [targetId, packageName] of Object.entries(AOT_PACKAGES).sort(([left], [right]) => compareText(left, right))) { - const archive = path.join(assetDir, `liboliphaunt-wasix-${version}-runtime-aot-${targetId}.tar.zst`); - if (!isFile(archive)) { - fail(`missing WASIX AOT release asset: ${rel(archive)}`); - } - const extracted = path.join(extractRoot, `${targetId}-extracted`); - extractTarZstd(archive, extracted); - const triple = AOT_TARGET_TRIPLES[targetId]; - const aotRoot = targetAotRoot(extracted, triple); - validateAotPayload(aotRoot, triple); - const [aotCoreRoot, toolsAotRoot] = splitAotToolsPayload(aotRoot, extractRoot, targetId); - specs.push({ - name: packageName, - target: triple, - kind: "wasix-aot", - templateDir: path.join(ROOT, "src/runtimes/liboliphaunt/wasix/crates/aot", triple), - payloadRoot: aotCoreRoot, - payloadDirName: "artifacts", - }); - specs.push({ - name: TOOLS_AOT_PACKAGES[targetId], - target: triple, - kind: "wasix-tools-aot", - templateDir: path.join(ROOT, "src/runtimes/liboliphaunt/wasix/crates/tools-aot", triple), - payloadRoot: toolsAotRoot, - payloadDirName: "artifacts", - }); - } - return specs; -} - -function writePackagesManifest(packages, outputDir) { - const data = { - schema: WASIX_CARGO_ARTIFACT_SCHEMA, - product: PRODUCT, - packages: packages.map((packageData) => ({ - name: packageData.name, - target: packageData.target, - kind: packageData.kind, - role: "artifact", - manifestPath: rel(packageData.manifestPath), - cratePath: rel(packageData.cratePath), - size: packageData.size, - sha256: packageData.sha256, - ...(packageData.dependencyRequirement === undefined ? {} : { - versioning: packageData.versioning, - dependencyRequirement: packageData.dependencyRequirement, - }), - })), - }; - writeFileSync(path.join(outputDir, "packages.json"), `${JSON.stringify(data, null, 2)}\n`); -} - -function parseArgs(argv) { - const args = { - assetDir: "target/oliphaunt-wasix/release-assets", - extensionsOnly: false, - outputDir: "target/oliphaunt-wasix/cargo-artifacts", - workDir: "target/oliphaunt-wasix", - version: null, - extensionArtifactRoots: [], - extensionPartBytes: DEFAULT_EXTENSION_PART_BYTES, - }; - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - if (value === "--help" || value === "-h") { - console.log("usage: tools/release/package_liboliphaunt_wasix_cargo_artifacts.mjs [--asset-dir DIR] [--extensions-only] [--extension-part-bytes BYTES] [--output-dir DIR] [--work-dir DIR] [--version VERSION] [--extension-artifact-root DIR...]"); - process.exit(0); - } else if (value === "--asset-dir") { - args.assetDir = requiredValue(argv, ++index, value); - } else if (value.startsWith("--asset-dir=")) { - args.assetDir = value.slice("--asset-dir=".length); - } else if (value === "--extensions-only") { - args.extensionsOnly = true; - } else if (value === "--output-dir") { - args.outputDir = requiredValue(argv, ++index, value); - } else if (value.startsWith("--output-dir=")) { - args.outputDir = value.slice("--output-dir=".length); - } else if (value === "--work-dir") { - args.workDir = requiredValue(argv, ++index, value); - } else if (value.startsWith("--work-dir=")) { - args.workDir = value.slice("--work-dir=".length); - } else if (value === "--version") { - args.version = requiredValue(argv, ++index, value); - } else if (value.startsWith("--version=")) { - args.version = value.slice("--version=".length); - } else if (value === "--extension-artifact-root") { - args.extensionArtifactRoots.push(requiredValue(argv, ++index, value)); - } else if (value.startsWith("--extension-artifact-root=")) { - args.extensionArtifactRoots.push(value.slice("--extension-artifact-root=".length)); - } else if (value === "--extension-part-bytes") { - args.extensionPartBytes = Number(requiredValue(argv, ++index, value)); - } else if (value.startsWith("--extension-part-bytes=")) { - args.extensionPartBytes = Number(value.slice("--extension-part-bytes=".length)); - } else { - fail(`unknown argument ${value}`); - } - } - if (args.extensionArtifactRoots.length === 0) { - args.extensionArtifactRoots.push("target/extension-artifacts"); - } - if (!Number.isSafeInteger(args.extensionPartBytes) || args.extensionPartBytes < 1 || args.extensionPartBytes > DEFAULT_EXTENSION_PART_BYTES) { - fail(`--extension-part-bytes must be an integer in 1..${DEFAULT_EXTENSION_PART_BYTES}`); - } - args.version ??= currentProductVersionSync(PRODUCT, PREFIX); - return args; -} - -function requiredValue(argv, index, option) { - const value = argv[index]; - if (value === undefined || value.startsWith("--")) { - fail(`${option} requires a value`); - } - return value; -} - -function repoPath(value) { - return path.isAbsolute(value) ? value : path.join(ROOT, value); -} - -function main(argv) { - const args = parseArgs(argv); - const assetDir = repoPath(args.assetDir); - const outputDir = repoPath(args.outputDir); - const workDir = repoPath(args.workDir); - const extensionRoots = args.extensionArtifactRoots.map(repoPath); - if (!args.extensionsOnly && !isDirectory(assetDir)) { - fail(`WASIX release asset directory does not exist: ${rel(assetDir)}`); - } - - const sourceRoot = path.join(workDir, "cargo-package-sources"); - const extractRoot = path.join(workDir, "cargo-package-extracted"); - const cargoTargetDir = path.join(workDir, "cargo-package-target"); - rmSync(sourceRoot, { recursive: true, force: true }); - rmSync(extractRoot, { recursive: true, force: true }); - rmSync(outputDir, { recursive: true, force: true }); - rmSync(cargoTargetDir, { recursive: true, force: true }); - mkdirSync(sourceRoot, { recursive: true }); - mkdirSync(extractRoot, { recursive: true }); - mkdirSync(outputDir, { recursive: true }); - - const extensionSpecs = extensionCargoSpecs(extensionRoots, extractRoot); - validateExtensionAotCoverage(extensionSpecs); - const extensionSources = extensionSpecs.map((spec) => writeExtensionCargoSource(spec, sourceRoot, args.extensionPartBytes)); - const extensionAotSources = extensionSpecs.flatMap((spec) => spec.aotTargets.map((aotSpec) => writeExtensionAotCargoSource(aotSpec, sourceRoot, args.extensionPartBytes))); - const specs = args.extensionsOnly ? [] : packageSpecs(assetDir, extractRoot, args.version); - const packages = [ - ...extensionSources.flatMap((source) => packageExtensionSource(source, { outputDir, cargoTargetDir })), - ...extensionAotSources.flatMap((source) => packageExtensionAotSource(source, { outputDir, cargoTargetDir })), - ...specs.map((spec) => packageSpec(spec, { - version: args.version, - sourceRoot, - outputDir, - cargoTargetDir, - extensionSources, - extensionAotSources, - })), - ]; - writePackagesManifest(packages, outputDir); - console.log(args.extensionsOnly - ? "generated WASIX extension Cargo artifact crates:" - : "generated liboliphaunt-wasix Cargo artifact crates:"); - for (const packageData of packages) { - console.log(`${packageData.name} ${rel(packageData.cratePath)} ${packageData.size} bytes`); - } -} - -if (import.meta.main) { - try { - main(Bun.argv.slice(2)); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - console.error(message.startsWith(`${PREFIX}:`) ? message : `${PREFIX}: ${message}`); - process.exitCode = 1; - } -} diff --git a/tools/release/package_oliphaunt_wasix_sdk_crate.mjs b/tools/release/package_oliphaunt_wasix_sdk_crate.mjs deleted file mode 100755 index 8115cd40d..000000000 --- a/tools/release/package_oliphaunt_wasix_sdk_crate.mjs +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env bun -import fs from 'node:fs/promises'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { stageWasixRustPackageSource } from '../../src/bindings/wasix-rust/tools/package-source.mjs'; - -import { - compareText, - manualCargoPackageSource, - packagedCargoManifestText, -} from './cargo-source-package.mjs'; -import { - canonicalWasixCargoToolchainVersions, - validateWasixConsumerDependencyPins, -} from './wasix-cargo-toolchain-policy.mjs'; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - stageReleaseNotices, -} from './release-notices.mjs'; -import { productCompatibilityVersion } from './release-graph.mjs'; - -const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); -const SOURCE_NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' }); - -function fail(message) { - console.error(`package_oliphaunt_wasix_sdk_crate.mjs: ${message}`); - process.exit(2); -} - -function rel(target) { - const relative = path.relative(root, target); - return relative.startsWith('..') || path.isAbsolute(relative) - ? target - : relative.split(path.sep).join('/'); -} - -async function readText(relativePath) { - return await fs.readFile(path.join(root, relativePath), 'utf8'); -} - -function parseCargoPackageNameVersion(text, context) { - let inPackage = false; - let name = null; - let version = null; - for (const rawLine of text.split(/\r?\n/u)) { - const line = rawLine.trim(); - if (line === '[package]') { - inPackage = true; - continue; - } - if (inPackage && line.startsWith('[')) { - break; - } - if (!inPackage) { - continue; - } - name ??= line.match(/^name\s*=\s*"([^"]+)"/u)?.[1] ?? null; - version ??= line.match(/^version\s*=\s*"([^"]+)"/u)?.[1] ?? null; - } - if (!name || !version) { - fail(`${context} must declare package.name and package.version`); - } - return { name, version }; -} - -export async function currentOliphauntWasixSdkVersion() { - const text = await readText('src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml'); - return parseCargoPackageNameVersion( - text, - 'src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml', - ).version; -} - -async function wasixCargoRegistryPackages() { - const text = await readText('src/runtimes/liboliphaunt/wasix/release.toml'); - const match = text.match(/^registry_packages\s*=\s*\[([\s\S]*?)^\]/mu); - if (!match) { - fail('src/runtimes/liboliphaunt/wasix/release.toml must declare registry_packages'); - } - const packages = [...match[1].matchAll(/"crates:([^"]+)"/gu)].map((item) => item[1]); - if (packages.length === 0) { - fail('liboliphaunt-wasix registry_packages must include Cargo packages'); - } - return packages.sort(); -} - -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&'); -} - -function renderOliphauntWasixReleaseCargoToml(source, runtimeVersion, registryPackages) { - let text = packagedCargoManifestText(source); - for (const crate of registryPackages) { - const pattern = new RegExp( - `^(${escapeRegExp(crate)}\\s*=\\s*\\{[^}\\n]*version\\s*=\\s*")[^"]+("[^}\\n]*\\})$`, - 'mu', - ); - if (!pattern.test(text)) { - fail(`generated oliphaunt-wasix release source is missing dependency ${crate}`); - } - text = text.replace(pattern, `$1=${runtimeVersion}$2`); - } - return text; -} - -function validateGeneratedOliphauntWasixReleaseArtifactCoverage( - manifestText, - runtimeVersion, - registryPackages, -) { - if (/=\s*\{[^}\n]*path\s*=/u.test(manifestText)) { - fail('generated oliphaunt-wasix release source must not contain local path dependencies'); - } - const missing = registryPackages.filter( - (crate) => !manifestText.includes(`${crate} = { version = "=${runtimeVersion}"`), - ); - if (missing.length > 0) { - fail( - `generated oliphaunt-wasix release source is missing WASIX artifact dependency pins: ${missing.join(', ')}`, - ); - } - const toolchainVersions = canonicalWasixCargoToolchainVersions(root); - const toolchainFailures = validateWasixConsumerDependencyPins( - Bun.TOML.parse(manifestText), - { - manifestPath: 'generated oliphaunt-wasix release source', - toolchainVersions, - }, - ); - if (toolchainFailures.length > 0) { - fail(toolchainFailures.join('\n')); - } -} - -export async function prepareOliphauntWasixReleaseSource(version) { - const runtimeVersion = productCompatibilityVersion( - 'oliphaunt-wasix-rust', - 'liboliphaunt-wasix', - 'package_oliphaunt_wasix_sdk_crate.mjs', - ); - const registryPackages = await wasixCargoRegistryPackages(); - const stageDir = path.join(root, 'target/release/cargo-package-sources/oliphaunt-wasix'); - await stageWasixRustPackageSource(stageDir); - const cargoToml = path.join(stageDir, 'Cargo.toml'); - const rendered = renderOliphauntWasixReleaseCargoToml( - await fs.readFile(cargoToml, 'utf8'), - runtimeVersion, - registryPackages, - ); - const generatedPackage = parseCargoPackageNameVersion(rendered, rel(cargoToml)); - if (generatedPackage.version !== version) { - fail(`generated oliphaunt-wasix release source must keep SDK version ${version}`); - } - validateGeneratedOliphauntWasixReleaseArtifactCoverage( - rendered, - runtimeVersion, - registryPackages, - ); - await fs.writeFile(cargoToml, rendered); - stageReleaseNotices(stageDir, SOURCE_NOTICE_OPTIONS); - assertReleaseNoticesInDirectory(stageDir, SOURCE_NOTICE_OPTIONS); - return cargoToml; -} - -function parseArgs(argv) { - let outputDir = null; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === '--output-dir') { - outputDir = argv[index + 1] ?? null; - index += 1; - continue; - } - fail(`unknown argument: ${arg}`); - } - if (!outputDir) { - fail('usage: tools/release/package_oliphaunt_wasix_sdk_crate.mjs --output-dir '); - } - return { - outputDir: path.isAbsolute(outputDir) ? outputDir : path.join(root, outputDir), - }; -} - -if (import.meta.main) { - const { outputDir } = parseArgs(Bun.argv.slice(2)); - const version = await currentOliphauntWasixSdkVersion(); - const manifest = await prepareOliphauntWasixReleaseSource(version); - const cratePath = manualCargoPackageSource(manifest, outputDir, { root, fail, rel }); - assertReleaseNoticesInArchive(cratePath, { - ...SOURCE_NOTICE_OPTIONS, - prefix: path.basename(cratePath, '.crate'), - }); - console.log(rel(cratePath)); -} diff --git a/tools/release/platform-binary-contract.mjs b/tools/release/platform-binary-contract.mjs deleted file mode 100644 index 34f2004e8..000000000 --- a/tools/release/platform-binary-contract.mjs +++ /dev/null @@ -1,1249 +0,0 @@ -#!/usr/bin/env bun - -import { lstat, readFile, readdir } from "node:fs/promises"; -import path from "node:path"; - -import { - APPLE_PLATFORM_COMPATIBILITY, - platformCompatibilityContract, -} from "./platform-compatibility-policy.mjs"; -import { - WINDOWS_VC_RUNTIME_DLLS, - inspectPortableExecutable, -} from "./windows-vc-runtime-closure.mjs"; - -const MACHO_LC_BUILD_VERSION = 0x32; -const ELF_TYPE_REL = 1; -const ELF_TYPE_EXEC = 2; -const ELF_TYPE_DYN = 3; -const ELF_SECTION_NOTE = 7; -const APPLE_PLATFORM_BY_ID = new Map( - Object.values(APPLE_PLATFORM_COMPATIBILITY).map((platform) => [platform.id, platform]), -); -const APPLE_PLATFORM_BY_CLI_NAME = new Map( - Object.values(APPLE_PLATFORM_COMPATIBILITY).map((platform) => [platform.cliName, platform]), -); -const WINDOWS_VC_RUNTIME_PROFILES = - platformCompatibilityContract("windows-x64-msvc").windowsVcRuntime.profiles; - -const EXPECTED_BINARY_PATH = /(?:\.dylib|\.dll|\.exe|\.node|\.so(?:\.[0-9]+)*)$/iu; -const STATIC_ARCHIVE_PATH = /\.a$/iu; -const MSVC_LIBRARY_PATH = /\.lib$/iu; -// Exact extension artifacts carry declared upstream grant text in this namespace. -// Only UTF-8 text at the canonical COPYING.LIB identity is metadata; detected -// formats and non-text bytes fail closed. -const WINDOWS_EXTENSION_LEGAL_TEXT_LIBRARY_PATH = - /(?:^|\/)files\/share\/licenses\/[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?\/COPYING\.LIB$/iu; -const MSVC_RUNTIME_IMPORT = /^(?:CONCRT|MSVCP|VCRUNTIME)[0-9A-Z_]*\.DLL$/iu; -const WINDOWS_VC_RUNTIME_DLL_SET = new Set(WINDOWS_VC_RUNTIME_DLLS); -const WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH = "lib/oliphaunt.lib"; -const WINDOWS_RUNTIME_IMPORT_DLL = "oliphaunt.dll"; -const WINDOWS_RUNTIME_IMPORT_SYMBOLS = Object.freeze([ - "oliphaunt_init", - "oliphaunt_logical_generation", - "oliphaunt_close_if_generation", - "oliphaunt_exec_protocol", - "oliphaunt_exec_simple_query", - "oliphaunt_exec_protocol_raw_stream", - "oliphaunt_backup", - "oliphaunt_restore", - "oliphaunt_init_with_error", - "oliphaunt_exec_protocol_with_error", - "oliphaunt_exec_simple_query_with_error", - "oliphaunt_exec_protocol_raw_stream_with_error", - "oliphaunt_backup_with_error", - "oliphaunt_restore_with_error", - "oliphaunt_detach_with_error", - "oliphaunt_cancel", - "oliphaunt_detach", - "oliphaunt_close", - "oliphaunt_register_static_extensions", - "oliphaunt_copy_last_error", - "oliphaunt_version", - "oliphaunt_free_response", -]); -const COFF_ARCHIVE_HEADER_SIZE = 60; -const COFF_OBJECT_HEADER_SIZE = 20; -const COFF_SECTION_HEADER_SIZE = 40; -const COFF_SYMBOL_SIZE = 18; -const COFF_RELOCATION_SIZE = 10; -const COFF_LINE_NUMBER_SIZE = 6; -const COFF_IMPORT_OBJECT_SIGNATURE = 0xffff; -const COFF_IMPORT_OBJECT_NAME_EXPORT_AS = 4; - -export class PlatformBinaryContractError extends Error { - constructor(message) { - super(message); - this.name = "PlatformBinaryContractError"; - } -} - -function fail(label, message) { - throw new PlatformBinaryContractError(`${label}: ${message}`); -} - -function requireRange(buffer, offset, length, label, description) { - if ( - !Number.isSafeInteger(offset) || - !Number.isSafeInteger(length) || - offset < 0 || - length < 0 || - offset > buffer.length || - length > buffer.length - offset - ) { - fail(label, `${description} is outside the ${buffer.length}-byte file`); - } -} - -function safeNumber(value, label, description) { - if (value > BigInt(Number.MAX_SAFE_INTEGER)) { - fail(label, `${description} exceeds the safe parser range`); - } - return Number(value); -} - -function contractFor(target, label) { - const contract = platformCompatibilityContract(target); - if (contract === undefined) { - fail(label, `unsupported platform-binary target ${JSON.stringify(target)}`); - } - return contract; -} - -function compareVersion(left, right) { - for (let index = 0; index < Math.max(left.length, right.length); index += 1) { - const difference = (left[index] ?? 0) - (right[index] ?? 0); - if (difference !== 0) return difference; - } - return 0; -} - -function formatVersion(version) { - return version.length > 2 && version[2] !== 0 - ? `${version[0]}.${version[1]}.${version[2]}` - : `${version[0]}.${version[1]}`; -} - -function packedAppleVersion(value) { - return [(value >>> 16) & 0xffff, (value >>> 8) & 0xff, value & 0xff]; -} - -function detectFormat(buffer) { - if (buffer.length >= 8 && buffer.subarray(0, 8).equals(Buffer.from("!\n", "ascii"))) { - return "ar"; - } - if (buffer.length >= 4 && buffer.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46]))) { - return "elf"; - } - if (buffer.length >= 2 && buffer[0] === 0x4d && buffer[1] === 0x5a) { - return "pe"; - } - if (buffer.length >= 4) { - const magic = buffer.readUInt32BE(0); - if ( - magic === 0xfeedfacf || - magic === 0xcffaedfe || - magic === 0xcafebabe || - magic === 0xbebafeca || - magic === 0xcafebabf || - magic === 0xbfbafeca || - magic === 0xfeedface || - magic === 0xcefaedfe - ) { - return "macho"; - } - } - return null; -} - -function isPlainText(buffer) { - if (buffer.length === 0) return false; - const text = buffer.toString("utf8"); - return ( - Buffer.from(text, "utf8").equals(buffer) && - !/[\u0000-\u0008\u000b\u000e-\u001f\u007f]/u.test(text) - ); -} - -function isWindowsExtensionLegalTextLibrary(name, buffer, format) { - return ( - format === null && - WINDOWS_EXTENSION_LEGAL_TEXT_LIBRARY_PATH.test(name) && - isPlainText(buffer) - ); -} - -function parseArchiveDecimal(buffer, offset, length, label, description) { - requireRange(buffer, offset, length, label, description); - const text = buffer.subarray(offset, offset + length).toString("ascii").trim(); - if (!/^[0-9]+$/u.test(text)) fail(label, `${description} is not an unsigned decimal integer`); - const value = Number(text); - if (!Number.isSafeInteger(value)) fail(label, `${description} exceeds the safe parser range`); - return value; -} - -function parseArArchiveMembers(buffer, label) { - requireRange(buffer, 0, 8, label, "ar global header"); - if (!buffer.subarray(0, 8).equals(Buffer.from("!\n", "ascii"))) { - fail(label, "ar global header is invalid"); - } - let cursor = 8; - let longNames = null; - const members = []; - while (cursor < buffer.length) { - const headerOffset = cursor; - requireRange(buffer, cursor, COFF_ARCHIVE_HEADER_SIZE, label, "ar member header"); - if (buffer.subarray(cursor + 58, cursor + 60).toString("ascii") !== "`\n") { - fail(label, `ar member at offset ${cursor} has an invalid header trailer`); - } - const rawName = buffer.subarray(cursor, cursor + 16).toString("ascii").trim(); - const size = parseArchiveDecimal(buffer, cursor + 48, 10, label, "ar member size"); - const dataOffset = cursor + COFF_ARCHIVE_HEADER_SIZE; - requireRange(buffer, dataOffset, size, label, `ar member ${rawName || ""}`); - let name = rawName.replace(/\/$/u, ""); - let payloadOffset = dataOffset; - let payloadSize = size; - if (rawName.startsWith("#1/")) { - const nameLengthText = rawName.slice(3).trim(); - if (!/^[0-9]+$/u.test(nameLengthText)) fail(label, `ar BSD member name length is invalid: ${rawName}`); - const nameLength = Number(nameLengthText); - if (!Number.isSafeInteger(nameLength) || nameLength <= 0 || nameLength > size) { - fail(label, `ar BSD member name length ${nameLengthText} exceeds its member`); - } - name = buffer.subarray(dataOffset, dataOffset + nameLength).toString("utf8").replace(/\x00+$/u, ""); - payloadOffset += nameLength; - payloadSize -= nameLength; - } else if (rawName === "//") { - longNames = buffer.subarray(dataOffset, dataOffset + size); - } else if (/^\/[0-9]+$/u.test(rawName)) { - if (longNames === null) fail(label, `ar member ${rawName} refers to a missing long-name table`); - const nameOffset = Number(rawName.slice(1)); - if (!Number.isSafeInteger(nameOffset) || nameOffset < 0 || nameOffset >= longNames.length) { - fail(label, `ar member long-name offset ${nameOffset} is out of range`); - } - const gnuNameEnd = longNames.indexOf(Buffer.from("/\n", "ascii"), nameOffset); - const coffNameEnd = longNames.indexOf(0, nameOffset); - const nameEnd = [gnuNameEnd, coffNameEnd] - .filter((offset) => offset >= nameOffset) - .sort((left, right) => left - right)[0]; - if (nameEnd === undefined) fail(label, `ar member long name at offset ${nameOffset} is unterminated`); - name = longNames.subarray(nameOffset, nameEnd).toString("utf8"); - } - - const special = - rawName === "/" || - rawName === "//" || - rawName === "/SYM64/" || - name.startsWith("__.SYMDEF") || - name === "SYM64"; - members.push({ - headerOffset, - name, - payload: buffer.subarray(payloadOffset, payloadOffset + payloadSize), - rawName, - special, - }); - cursor = dataOffset + size + (size % 2); - } - if (cursor !== buffer.length) fail(label, "ar archive has a truncated alignment byte"); - return members; -} - -function parseArArchive(buffer, label, contract) { - const slices = []; - for (const { name, payload, special } of parseArArchiveMembers(buffer, label)) { - if (!special) { - if (payload.length === 0) fail(label, `ar object member ${JSON.stringify(name)} is empty`); - const format = detectFormat(payload); - if (format === "macho" && contract.format === "macho") { - slices.push(...parseMacho(payload, `${label}(${name})`, contract)); - } else if (format === "elf" && contract.format === "elf") { - slices.push(parseElf(payload, `${label}(${name})`, contract)); - } else { - fail( - label, - `ar member ${JSON.stringify(name)} is not a ${contract.format.toUpperCase()} object for this carrier`, - ); - } - } - } - if (slices.length === 0) fail(label, "ar archive contains no inspectable native object members"); - return slices; -} - -function parseNullTerminatedStrings(buffer, offset, count, label, description) { - const values = []; - let cursor = offset; - for (let index = 0; index < count; index += 1) { - if (cursor >= buffer.length) { - fail(label, `${description} is missing string ${index + 1} of ${count}`); - } - const end = buffer.indexOf(0, cursor); - if (end < 0) fail(label, `${description} string ${index + 1} is unterminated`); - if (end === cursor) fail(label, `${description} string ${index + 1} is empty`); - values.push(buffer.subarray(cursor, end).toString("latin1")); - cursor = end + 1; - } - if (cursor !== buffer.length) { - fail(label, `${description} has ${buffer.length - cursor} trailing byte(s)`); - } - return values; -} - -function parseWindowsFirstLinkerMember(member, objectOffsets, label) { - const memberLabel = `${label} [first linker member]`; - requireRange(member.payload, 0, 4, memberLabel, "symbol count"); - const count = member.payload.readUInt32BE(0); - if (count === 0 || count > 1_000_000) { - fail(memberLabel, `symbol count ${count} is invalid`); - } - requireRange(member.payload, 4, count * 4, memberLabel, "member-offset table"); - const offsets = []; - for (let index = 0; index < count; index += 1) { - const offset = member.payload.readUInt32BE(4 + index * 4); - if (!objectOffsets.has(offset)) { - fail(memberLabel, `symbol ${index} refers to non-object archive offset ${offset}`); - } - offsets.push(offset); - } - const names = parseNullTerminatedStrings( - member.payload, - 4 + count * 4, - count, - memberLabel, - "symbol-name table", - ); - return { names, offsets }; -} - -function parseWindowsSecondLinkerMember(member, objectMembers, label) { - const memberLabel = `${label} [second linker member]`; - requireRange(member.payload, 0, 4, memberLabel, "archive-member count"); - const memberCount = member.payload.readUInt32LE(0); - if (memberCount === 0 || memberCount > 1_000_000) { - fail(memberLabel, `archive-member count ${memberCount} is invalid`); - } - requireRange(member.payload, 4, memberCount * 4 + 4, memberLabel, "member-offset and symbol-count tables"); - const offsets = []; - const seenOffsets = new Set(); - for (let index = 0; index < memberCount; index += 1) { - const offset = member.payload.readUInt32LE(4 + index * 4); - if (seenOffsets.has(offset)) fail(memberLabel, `archive-member offset ${offset} is repeated`); - seenOffsets.add(offset); - offsets.push(offset); - } - const expectedOffsets = new Set(objectMembers.map(({ headerOffset }) => headerOffset)); - if ( - offsets.length !== expectedOffsets.size || - offsets.some((offset) => !expectedOffsets.has(offset)) - ) { - fail(memberLabel, "archive-member offsets do not exactly cover the COFF object members"); - } - const symbolCountOffset = 4 + memberCount * 4; - const symbolCount = member.payload.readUInt32LE(symbolCountOffset); - if (symbolCount === 0 || symbolCount > 1_000_000) { - fail(memberLabel, `symbol count ${symbolCount} is invalid`); - } - const indicesOffset = symbolCountOffset + 4; - requireRange(member.payload, indicesOffset, symbolCount * 2, memberLabel, "symbol-index table"); - for (let index = 0; index < symbolCount; index += 1) { - const memberIndex = member.payload.readUInt16LE(indicesOffset + index * 2); - if (memberIndex === 0 || memberIndex > memberCount) { - fail(memberLabel, `symbol ${index} has out-of-range archive-member index ${memberIndex}`); - } - } - const names = parseNullTerminatedStrings( - member.payload, - indicesOffset + symbolCount * 2, - symbolCount, - memberLabel, - "symbol-name table", - ); - for (let index = 1; index < names.length; index += 1) { - if (Buffer.compare(Buffer.from(names[index - 1], "latin1"), Buffer.from(names[index], "latin1")) >= 0) { - fail(memberLabel, "symbol names must be unique and in ascending lexical order"); - } - } - return names; -} - -function requireCoffPointer(buffer, pointer, size, headerEnd, label, description) { - if (size === 0) return; - if (pointer < headerEnd) fail(label, `${description} overlaps the COFF headers`); - requireRange(buffer, pointer, size, label, description); -} - -function parseCoffObjectMember(buffer, label, contract) { - requireRange(buffer, 0, COFF_OBJECT_HEADER_SIZE, label, "COFF object header"); - const machine = buffer.readUInt16LE(0); - if (machine !== contract.pe.machine) { - fail(label, `COFF object machine 0x${machine.toString(16)} is not ${contract.architecture}`); - } - const sectionCount = buffer.readUInt16LE(2); - if (sectionCount === 0 || sectionCount > 96) { - fail(label, `COFF object section count ${sectionCount} is invalid`); - } - const symbolTable = buffer.readUInt32LE(8); - const symbolCount = buffer.readUInt32LE(12); - const optionalHeaderSize = buffer.readUInt16LE(16); - if (optionalHeaderSize !== 0) { - fail(label, `COFF archive object has unexpected ${optionalHeaderSize}-byte optional header`); - } - const sectionTable = COFF_OBJECT_HEADER_SIZE; - const headerEnd = sectionTable + sectionCount * COFF_SECTION_HEADER_SIZE; - requireRange(buffer, sectionTable, sectionCount * COFF_SECTION_HEADER_SIZE, label, "COFF section table"); - for (let index = 0; index < sectionCount; index += 1) { - const section = sectionTable + index * COFF_SECTION_HEADER_SIZE; - const rawSize = buffer.readUInt32LE(section + 16); - const rawPointer = buffer.readUInt32LE(section + 20); - const relocationPointer = buffer.readUInt32LE(section + 24); - const lineNumberPointer = buffer.readUInt32LE(section + 28); - const relocationCount = buffer.readUInt16LE(section + 32); - const lineNumberCount = buffer.readUInt16LE(section + 34); - requireCoffPointer(buffer, rawPointer, rawSize, headerEnd, label, `COFF section ${index} raw data`); - requireCoffPointer( - buffer, - relocationPointer, - relocationCount * COFF_RELOCATION_SIZE, - headerEnd, - label, - `COFF section ${index} relocations`, - ); - requireCoffPointer( - buffer, - lineNumberPointer, - lineNumberCount * COFF_LINE_NUMBER_SIZE, - headerEnd, - label, - `COFF section ${index} line numbers`, - ); - } - if (symbolCount === 0) { - if (symbolTable !== 0) fail(label, "COFF object has a symbol-table pointer but zero symbols"); - } else { - requireCoffPointer( - buffer, - symbolTable, - symbolCount * COFF_SYMBOL_SIZE, - headerEnd, - label, - "COFF symbol table", - ); - let symbolIndex = 0; - while (symbolIndex < symbolCount) { - const symbol = symbolTable + symbolIndex * COFF_SYMBOL_SIZE; - const auxiliaryCount = buffer[symbol + 17]; - if (auxiliaryCount > symbolCount - symbolIndex - 1) { - fail(label, `COFF symbol ${symbolIndex} has ${auxiliaryCount} out-of-range auxiliary record(s)`); - } - symbolIndex += auxiliaryCount + 1; - } - const stringTable = symbolTable + symbolCount * COFF_SYMBOL_SIZE; - requireRange(buffer, stringTable, 4, label, "COFF string-table size"); - const stringTableSize = buffer.readUInt32LE(stringTable); - if (stringTableSize < 4) fail(label, `COFF string-table size ${stringTableSize} is invalid`); - requireRange(buffer, stringTable, stringTableSize, label, "COFF string table"); - if (stringTable + stringTableSize !== buffer.length) { - fail(label, "COFF string table does not end at the object-member boundary"); - } - } - return { kind: "coff-object", machine: contract.architecture }; -} - -function parseCoffImportObjectMember(buffer, label, contract) { - requireRange(buffer, 0, COFF_OBJECT_HEADER_SIZE, label, "COFF import-object header"); - if (buffer.readUInt16LE(0) !== 0 || buffer.readUInt16LE(2) !== COFF_IMPORT_OBJECT_SIGNATURE) { - fail(label, "COFF import-object signature is invalid"); - } - const version = buffer.readUInt16LE(4); - if (version !== 0) { - fail(label, `unsupported anonymous COFF object version ${version}; expected a short import object`); - } - const machine = buffer.readUInt16LE(6); - if (machine !== contract.pe.machine) { - fail(label, `COFF import-object machine 0x${machine.toString(16)} is not ${contract.architecture}`); - } - const sizeOfData = buffer.readUInt32LE(12); - if (sizeOfData !== buffer.length - COFF_OBJECT_HEADER_SIZE) { - fail( - label, - `COFF import-object data size ${sizeOfData} does not match its ${buffer.length - COFF_OBJECT_HEADER_SIZE}-byte payload`, - ); - } - const typeInfo = buffer.readUInt16LE(18); - const importType = typeInfo & 0x3; - const nameType = (typeInfo >>> 2) & 0x7; - if (importType > 2) fail(label, `COFF import-object type ${importType} is invalid`); - if (nameType > COFF_IMPORT_OBJECT_NAME_EXPORT_AS) { - fail(label, `COFF import-object name type ${nameType} is invalid`); - } - if ((typeInfo & 0xffe0) !== 0) fail(label, "COFF import-object reserved type bits are nonzero"); - const strings = parseNullTerminatedStrings( - buffer, - COFF_OBJECT_HEADER_SIZE, - nameType === COFF_IMPORT_OBJECT_NAME_EXPORT_AS ? 3 : 2, - label, - "COFF import-object data", - ); - return { - dll: strings[1], - kind: "coff-import-object", - machine: contract.architecture, - symbol: strings[0], - }; -} - -function parseWindowsRuntimeImportLibrary(buffer, label, contract) { - const members = parseArArchiveMembers(buffer, label); - if (members.length < 3 || members[0].rawName !== "/" || members[1].rawName !== "/") { - fail(label, "MSVC import library must begin with its first and second linker members"); - } - const objectMembers = members.filter(({ special }) => !special); - if (objectMembers.length === 0) fail(label, "MSVC import library contains no COFF object members"); - const unexpectedSpecial = members - .slice(2) - .find(({ rawName, special }) => special && rawName !== "//" && rawName !== "/"); - if (unexpectedSpecial !== undefined) { - fail(label, `MSVC import library contains unsupported special member ${JSON.stringify(unexpectedSpecial.rawName)}`); - } - if (members.slice(2).some(({ rawName }) => rawName === "/")) { - fail(label, "MSVC import library contains an unexpected additional linker member"); - } - if (members.filter(({ rawName }) => rawName === "//").length > 1) { - fail(label, "MSVC import library repeats its long-name member"); - } - const objectOffsets = new Set(objectMembers.map(({ headerOffset }) => headerOffset)); - parseWindowsFirstLinkerMember(members[0], objectOffsets, label); - const linkerSymbols = parseWindowsSecondLinkerMember(members[1], objectMembers, label); - - const slices = []; - const imports = []; - for (const member of objectMembers) { - if (member.payload.length === 0) { - fail(label, `MSVC import-library member ${JSON.stringify(member.name)} is empty`); - } - const memberLabel = `${label}(${member.name})`; - const shortImport = - member.payload.length >= 4 && - member.payload.readUInt16LE(0) === 0 && - member.payload.readUInt16LE(2) === COFF_IMPORT_OBJECT_SIGNATURE; - const parsed = shortImport - ? parseCoffImportObjectMember(member.payload, memberLabel, contract) - : parseCoffObjectMember(member.payload, memberLabel, contract); - slices.push(parsed); - if (parsed.kind === "coff-import-object") imports.push(parsed); - } - if (imports.length === 0) fail(label, "MSVC import library contains no short import-object members"); - const wrongDll = imports.find(({ dll }) => dll.toLowerCase() !== WINDOWS_RUNTIME_IMPORT_DLL); - if (wrongDll !== undefined) { - fail( - label, - `MSVC import object for ${JSON.stringify(wrongDll.symbol)} names unexpected DLL ${JSON.stringify(wrongDll.dll)}`, - ); - } - const importSymbols = new Set(imports.map(({ symbol }) => symbol)); - for (const requiredSymbol of WINDOWS_RUNTIME_IMPORT_SYMBOLS) { - if (!importSymbols.has(requiredSymbol)) { - fail(label, `MSVC import library does not expose required symbol ${requiredSymbol}`); - } - if (!linkerSymbols.includes(requiredSymbol)) { - fail(label, `MSVC second linker member does not index required symbol ${requiredSymbol}`); - } - } - return { - archived: true, - format: "pe", - platforms: [], - slices, - }; -} - -function machoEndianAndWidth(buffer, offset, label) { - requireRange(buffer, offset, 4, label, "Mach-O magic"); - const magic = buffer.readUInt32BE(offset); - if (magic === 0xfeedfacf) return { endian: "be", bits: 64 }; - if (magic === 0xcffaedfe) return { endian: "le", bits: 64 }; - if (magic === 0xfeedface || magic === 0xcefaedfe) { - fail(label, "Mach-O image is 32-bit; release binaries must be 64-bit arm64"); - } - fail(label, "Mach-O slice has an invalid thin-image magic"); -} - -function readMachoUInt32(buffer, offset, endian) { - return endian === "le" ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); -} - -function parseMachoSlice(buffer, sliceOffset, sliceSize, label, contract) { - requireRange(buffer, sliceOffset, sliceSize, label, "Mach-O slice"); - if (sliceSize < 32) fail(label, "Mach-O 64-bit header is truncated"); - const { endian } = machoEndianAndWidth(buffer, sliceOffset, label); - const read32 = (relative) => { - requireRange(buffer, sliceOffset + relative, 4, label, "Mach-O header field"); - return readMachoUInt32(buffer, sliceOffset + relative, endian); - }; - const cpuType = read32(4); - if (cpuType !== contract.macho.cpuType) { - fail(label, `Mach-O cpu type 0x${cpuType.toString(16)} is not arm64`); - } - const cpuSubtype = read32(8); - if (cpuSubtype !== contract.macho.cpuSubtype) { - fail( - label, - `Mach-O arm64 cpu subtype 0x${cpuSubtype.toString(16)} is not generic ARM64_ALL (arm64e-only slices are not portable arm64 carriers)`, - ); - } - const commandCount = read32(16); - const commandsSize = read32(20); - if (commandCount > 65_536) fail(label, `Mach-O declares unreasonable load-command count ${commandCount}`); - requireRange(buffer, sliceOffset + 32, commandsSize, label, "Mach-O load-command table"); - if (commandsSize > sliceSize - 32) fail(label, "Mach-O load-command table exceeds its fat slice"); - - let cursor = sliceOffset + 32; - const commandsEnd = cursor + commandsSize; - const buildVersions = []; - for (let index = 0; index < commandCount; index += 1) { - requireRange(buffer, cursor, 8, label, `Mach-O load command ${index}`); - if (cursor + 8 > commandsEnd) fail(label, `Mach-O load command ${index} exceeds sizeofcmds`); - const command = readMachoUInt32(buffer, cursor, endian); - const commandSize = readMachoUInt32(buffer, cursor + 4, endian); - if (commandSize < 8 || commandSize % 4 !== 0) { - fail(label, `Mach-O load command ${index} has invalid cmdsize ${commandSize}`); - } - if (commandSize > commandsEnd - cursor) { - fail(label, `Mach-O load command ${index} exceeds sizeofcmds`); - } - if (command === MACHO_LC_BUILD_VERSION) { - if (commandSize < 24) fail(label, "Mach-O LC_BUILD_VERSION is truncated"); - buildVersions.push({ - platform: readMachoUInt32(buffer, cursor + 8, endian), - minos: packedAppleVersion(readMachoUInt32(buffer, cursor + 12, endian)), - }); - } - cursor += commandSize; - } - if (cursor !== commandsEnd) { - fail(label, `Mach-O load commands consume ${cursor - (sliceOffset + 32)} bytes, expected ${commandsSize}`); - } - if (buildVersions.length !== 1) { - fail(label, `Mach-O slice must contain exactly one LC_BUILD_VERSION, found ${buildVersions.length}`); - } - const [{ platform, minos }] = buildVersions; - const platformMetadata = APPLE_PLATFORM_BY_ID.get(platform); - if (platformMetadata === undefined) { - fail(label, `Mach-O LC_BUILD_VERSION platform ${platform} is not macOS, iOS, or iOS Simulator`); - } - const platformContract = Object.values(contract.apple.platforms).find( - (candidate) => candidate.id === platform, - ); - if (platformContract === undefined) { - fail( - label, - `${contract.apple.carrier} contains unsupported ${platformMetadata.name} Mach-O content`, - ); - } - const maximum = platformContract.maximumMinimumOs; - if (compareVersion(minos, maximum) > 0) { - fail( - label, - `${platformMetadata.name} minimum OS ${formatVersion(minos)} exceeds the carrier contract ${formatVersion(maximum)}`, - ); - } - return { - platform, - platformName: platformMetadata.name, - minos, - machine: "arm64", - cpuType, - cpuSubtype, - }; -} - -function parseMacho(buffer, label, contract) { - requireRange(buffer, 0, 4, label, "Mach-O magic"); - const magic = buffer.readUInt32BE(0); - if (![0xcafebabe, 0xbebafeca, 0xcafebabf, 0xbfbafeca].includes(magic)) { - return [parseMachoSlice(buffer, 0, buffer.length, label, contract)]; - } - const littleEndian = magic === 0xbebafeca || magic === 0xbfbafeca; - const fat64 = magic === 0xcafebabf || magic === 0xbfbafeca; - const read32 = (offset) => (littleEndian ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset)); - const read64 = (offset) => - safeNumber(littleEndian ? buffer.readBigUInt64LE(offset) : buffer.readBigUInt64BE(offset), label, "fat Mach-O offset or size"); - requireRange(buffer, 0, 8, label, "fat Mach-O header"); - const count = read32(4); - if (count === 0 || count > 64) fail(label, `fat Mach-O declares invalid slice count ${count}`); - const entrySize = fat64 ? 32 : 20; - requireRange(buffer, 8, count * entrySize, label, "fat Mach-O architecture table"); - const tableEnd = 8 + count * entrySize; - const ranges = []; - const identities = new Set(); - const results = []; - for (let index = 0; index < count; index += 1) { - const entry = 8 + index * entrySize; - const cpuType = read32(entry); - if (cpuType !== contract.macho.cpuType) { - fail(label, `fat Mach-O slice ${index} cpu type 0x${cpuType.toString(16)} is not arm64`); - } - const cpuSubtype = read32(entry + 4); - if (cpuSubtype !== contract.macho.cpuSubtype) { - fail( - label, - `fat Mach-O slice ${index} arm64 cpu subtype 0x${cpuSubtype.toString(16)} is not generic ARM64_ALL`, - ); - } - const identity = `${cpuType}:${cpuSubtype}`; - if (identities.has(identity)) { - fail(label, `fat Mach-O slice ${index} duplicates architecture identity arm64/ARM64_ALL`); - } - identities.add(identity); - const offset = fat64 ? read64(entry + 8) : read32(entry + 8); - const size = fat64 ? read64(entry + 16) : read32(entry + 12); - const alignment = fat64 ? read32(entry + 24) : read32(entry + 16); - if (size === 0) fail(label, `fat Mach-O slice ${index} is empty`); - if (alignment > 31) fail(label, `fat Mach-O slice ${index} has unsafe alignment exponent ${alignment}`); - if (offset < tableEnd) fail(label, `fat Mach-O slice ${index} overlaps its architecture table`); - if (offset % 2 ** alignment !== 0) fail(label, `fat Mach-O slice ${index} offset is not aligned`); - requireRange(buffer, offset, size, label, `fat Mach-O slice ${index}`); - for (const range of ranges) { - if (offset < range.end && range.start < offset + size) { - fail(label, `fat Mach-O slice ${index} overlaps another slice`); - } - } - ranges.push({ start: offset, end: offset + size }); - const slice = parseMachoSlice(buffer, offset, size, `${label} [slice ${index}]`, contract); - if (slice.cpuType !== cpuType || slice.cpuSubtype !== cpuSubtype) { - fail(label, `fat Mach-O slice ${index} architecture table identity does not match its thin header`); - } - results.push(slice); - } - return results; -} - -function scanRequiredElfVersions(buffer) { - const text = buffer.toString("latin1"); - const versions = []; - const pattern = /(?:^|(?<=\x00))(GLIBC(?:XX)?_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?)(?=\x00)/gu; - for (const match of text.matchAll(pattern)) { - versions.push({ - name: match[1], - family: match[1].startsWith("GLIBCXX_") ? "GLIBCXX" : "GLIBC", - version: [Number(match[2]), Number(match[3]), Number(match[4] ?? 0)], - }); - } - return versions; -} - -function validateElfTable(buffer, offset, entrySize, count, minimumSize, label, name) { - if (count === 0) return; - if (offset === 0) fail(label, `ELF ${name} count is nonzero but its offset is zero`); - if (entrySize < minimumSize) fail(label, `ELF ${name} entry size ${entrySize} is below ${minimumSize}`); - if (count > 65_536) fail(label, `ELF ${name} count ${count} is unreasonable`); - requireRange(buffer, offset, entrySize * count, label, `ELF ${name}`); -} - -function alignFour(value) { - return (value + 3) & ~3; -} - -function androidApiNotes(buffer, sectionOffset, sectionEntrySize, sectionCount, label) { - const values = []; - for (let index = 0; index < sectionCount; index += 1) { - const section = sectionOffset + index * sectionEntrySize; - if (buffer.readUInt32LE(section + 4) !== ELF_SECTION_NOTE) continue; - const noteOffset = safeNumber(buffer.readBigUInt64LE(section + 24), label, `ELF note section ${index} offset`); - const noteSize = safeNumber(buffer.readBigUInt64LE(section + 32), label, `ELF note section ${index} size`); - requireRange(buffer, noteOffset, noteSize, label, `ELF note section ${index}`); - let cursor = noteOffset; - const end = noteOffset + noteSize; - while (cursor < end) { - if (end - cursor < 12) { - if (buffer.subarray(cursor, end).every((byte) => byte === 0)) break; - fail(label, `ELF note section ${index} has a truncated note header`); - } - const nameSize = buffer.readUInt32LE(cursor); - const descriptionSize = buffer.readUInt32LE(cursor + 4); - const type = buffer.readUInt32LE(cursor + 8); - if (nameSize === 0 || nameSize > 256 || descriptionSize > 1024 * 1024) { - fail(label, `ELF note section ${index} has unreasonable note sizes`); - } - const nameOffset = cursor + 12; - const descriptionOffset = nameOffset + alignFour(nameSize); - const next = descriptionOffset + alignFour(descriptionSize); - if (next > end) fail(label, `ELF note section ${index} contains a truncated note payload`); - const owner = buffer.subarray(nameOffset, nameOffset + nameSize).toString("ascii").replace(/\x00+$/u, ""); - if (owner === "Android" && type === 1) { - if (descriptionSize < 4) fail(label, ".note.android.ident NT_VERSION description is truncated"); - values.push(buffer.readUInt32LE(descriptionOffset)); - } - cursor = next; - } - } - return values; -} - -function parseElf(buffer, label, contract) { - requireRange(buffer, 0, 64, label, "ELF64 header"); - if (contract.elf.bits !== 64 || buffer[4] !== 2) { - fail(label, `ELF class ${buffer[4]} is not ELF${contract.elf.bits}`); - } - if (contract.elf.endianness !== "little" || buffer[5] !== 1) { - fail(label, `ELF data encoding ${buffer[5]} is not ${contract.elf.endianness}-endian`); - } - if (buffer[6] !== 1) fail(label, `ELF identification version ${buffer[6]} is invalid`); - const elfType = buffer.readUInt16LE(16); - if (![ELF_TYPE_REL, ELF_TYPE_EXEC, ELF_TYPE_DYN].includes(elfType)) { - fail(label, `ELF type ${elfType} is not a relocatable object, executable, or shared library`); - } - const machine = buffer.readUInt16LE(18); - if (machine !== contract.elf.machine) { - fail(label, `ELF machine ${machine} does not match ${contract.architecture}`); - } - const headerSize = buffer.readUInt16LE(52); - if (headerSize < 64 || headerSize > buffer.length) fail(label, `ELF header size ${headerSize} is invalid`); - const programOffset = safeNumber(buffer.readBigUInt64LE(32), label, "ELF program-header offset"); - const sectionOffset = safeNumber(buffer.readBigUInt64LE(40), label, "ELF section-header offset"); - const programEntrySize = buffer.readUInt16LE(54); - const programCount = buffer.readUInt16LE(56); - const sectionEntrySize = buffer.readUInt16LE(58); - const sectionCount = buffer.readUInt16LE(60); - const sectionNames = buffer.readUInt16LE(62); - if (programCount === 0xffff) fail(label, "ELF extended program-header counts are not accepted"); - if (sectionCount === 0 && sectionOffset !== 0) fail(label, "ELF extended section-header counts are not accepted"); - if (sectionCount > 0 && sectionNames !== 0 && sectionNames >= sectionCount) { - fail(label, `ELF section-name table index ${sectionNames} is out of range`); - } - validateElfTable(buffer, programOffset, programEntrySize, programCount, 56, label, "program-header table"); - validateElfTable(buffer, sectionOffset, sectionEntrySize, sectionCount, 64, label, "section-header table"); - - const requiredVersions = scanRequiredElfVersions(buffer); - let androidApi = null; - if (Number.isSafeInteger(contract.elf.androidApiLevel)) { - const forbiddenFamilies = new Set(contract.elf.forbiddenRequiredVersionFamilies); - const forbidden = requiredVersions.find(({ family }) => forbiddenFamilies.has(family)); - if (forbidden !== undefined) { - fail(label, `Android ELF requires forbidden GNU desktop runtime version ${forbidden.name}`); - } - if (elfType === ELF_TYPE_EXEC || elfType === ELF_TYPE_DYN) { - const apiNotes = androidApiNotes(buffer, sectionOffset, sectionEntrySize, sectionCount, label); - if (apiNotes.length !== 1) { - fail(label, `Android ELF must contain exactly one .note.android.ident API record, found ${apiNotes.length}`); - } - androidApi = apiNotes[0]; - if (androidApi !== contract.elf.androidApiLevel) { - fail( - label, - `Android ELF API level ${androidApi} does not match the release contract ${contract.elf.androidApiLevel}`, - ); - } - } - } else { - for (const required of requiredVersions) { - const ceiling = contract.elf.maximumRequiredVersions[required.family]; - if (ceiling === undefined) continue; - if (compareVersion(required.version, ceiling) > 0) { - fail( - label, - `${required.name} exceeds the ${required.family} compatibility ceiling ${formatVersion(ceiling)}`, - ); - } - } - } - return { - machine: contract.architecture, - androidApi, - requiredVersions: requiredVersions.map(({ name }) => name).sort(), - }; -} - -function parsePe(buffer, label, contract) { - requireRange(buffer, 0, 64, label, "DOS header"); - if (buffer[0] !== 0x4d || buffer[1] !== 0x5a) fail(label, "DOS signature is invalid"); - const peOffset = buffer.readUInt32LE(0x3c); - requireRange(buffer, peOffset, 24, label, "PE signature and COFF header"); - if (!buffer.subarray(peOffset, peOffset + 4).equals(Buffer.from([0x50, 0x45, 0, 0]))) { - fail(label, "PE signature is invalid"); - } - const coff = peOffset + 4; - const machine = buffer.readUInt16LE(coff); - if (machine !== contract.pe.machine) { - fail(label, `PE machine 0x${machine.toString(16)} is not ${contract.architecture}`); - } - const sectionCount = buffer.readUInt16LE(coff + 2); - if (sectionCount === 0 || sectionCount > 96) fail(label, `PE section count ${sectionCount} is invalid`); - const optionalSize = buffer.readUInt16LE(coff + 16); - const optional = coff + 20; - requireRange(buffer, optional, optionalSize, label, "PE optional header"); - if (optionalSize < 112) fail(label, `PE32+ optional header is only ${optionalSize} bytes`); - if (buffer.readUInt16LE(optional) !== contract.pe.optionalHeaderMagic) { - fail(label, "PE optional header is not PE32+"); - } - const sizeOfHeaders = buffer.readUInt32LE(optional + 60); - if (sizeOfHeaders === 0 || sizeOfHeaders > buffer.length) fail(label, `PE SizeOfHeaders ${sizeOfHeaders} is invalid`); - const directoryCount = buffer.readUInt32LE(optional + 108); - const availableDirectories = Math.floor((optionalSize - 112) / 8); - if (directoryCount > availableDirectories) { - fail( - label, - `PE optional header declares ${directoryCount} data directories but contains space for ${availableDirectories}`, - ); - } - const sectionTable = optional + optionalSize; - requireRange(buffer, sectionTable, sectionCount * 40, label, "PE section table"); - const sections = []; - for (let index = 0; index < sectionCount; index += 1) { - const entry = sectionTable + index * 40; - const virtualSize = buffer.readUInt32LE(entry + 8); - const virtualAddress = buffer.readUInt32LE(entry + 12); - const rawSize = buffer.readUInt32LE(entry + 16); - const rawOffset = buffer.readUInt32LE(entry + 20); - if (rawSize > 0) requireRange(buffer, rawOffset, rawSize, label, `PE section ${index} raw data`); - sections.push({ virtualSize, virtualAddress, rawSize, rawOffset }); - } - let imports; - try { - const portableExecutable = inspectPortableExecutable(buffer, label); - if (portableExecutable.machine !== contract.pe.machine) { - fail( - label, - `PE machine 0x${portableExecutable.machine.toString(16)} is not ${contract.architecture}`, - ); - } - imports = portableExecutable.imports; - } catch (error) { - if (error instanceof PlatformBinaryContractError) throw error; - fail(label, `PE dependency inspection failed: ${error.message}`); - } - const msvcRuntimeImports = imports.filter((name) => MSVC_RUNTIME_IMPORT.test(name)); - const undeclaredRuntime = msvcRuntimeImports.find( - (name) => !WINDOWS_VC_RUNTIME_DLL_SET.has(name.toLowerCase()), - ); - if (undeclaredRuntime !== undefined) { - fail(label, `release PE imports undeclared or debug VC runtime ${undeclaredRuntime}`); - } - return { - machine: "x64", - imports, - msvcRuntimeImports, - }; -} - -export function inspectPlatformBinaryBuffer(input, { target, label = "binary" }) { - const buffer = Buffer.isBuffer(input) ? input : Buffer.from(input); - const contract = contractFor(target, label); - const format = detectFormat(buffer); - if (format === null) fail(label, "file does not contain a recognized Mach-O, ELF, or PE image"); - if (format === "ar") { - if (!["macho", "elf"].includes(contract.format)) { - fail(label, `static ar archive is not a valid ${target} release binary`); - } - const slices = parseArArchive(buffer, label, contract); - return { - format: contract.format, - archived: true, - slices, - platforms: contract.format === "macho" ? [...new Set(slices.map(({ platform }) => platform))] : [], - }; - } - if (format !== contract.format) { - fail(label, `${format.toUpperCase()} content does not match target ${target} (${contract.format.toUpperCase()})`); - } - if (format === "macho") { - const slices = parseMacho(buffer, label, contract); - return { format, slices, platforms: [...new Set(slices.map(({ platform }) => platform))] }; - } - if (format === "elf") return { format, slices: [parseElf(buffer, label, contract)], platforms: [] }; - return { format, slices: [parsePe(buffer, label, contract)], platforms: [] }; -} - -function finalizeInspection( - target, - inspected, - labels, - requiredApplePlatforms, - windowsVcRuntimeProfile, -) { - const contract = contractFor(target, "platform-binary contract"); - if (inspected.length === 0) { - fail("platform-binary contract", `no ${contract.format.toUpperCase()} binaries were found for ${target}`); - } - const platforms = new Set(inspected.flatMap(({ result }) => result.platforms)); - if (contract.apple !== undefined) { - if (requiredApplePlatforms !== undefined && !contract.apple.allowPlatformOverride) { - fail( - "platform-binary contract", - `${contract.apple.carrier} does not allow a required-platform override`, - ); - } - const required = - requiredApplePlatforms ?? - contract.apple.requiredPlatforms.map((key) => contract.apple.platforms[key].id); - const missing = required.filter((platform) => !platforms.has(platform)); - if (missing.length > 0) { - fail( - "platform-binary contract", - `${contract.apple.carrier} is missing ${missing.map((platform) => APPLE_PLATFORM_BY_ID.get(platform).name).join(" and ")} Mach-O content`, - ); - } - } - if (contract.windowsVcRuntime !== undefined) { - const profile = windowsVcRuntimeProfile ?? "direct"; - if (!contract.windowsVcRuntime.profiles.includes(profile)) { - fail( - "platform-binary contract", - `unknown Windows VC runtime profile ${JSON.stringify(profile)}; expected ${contract.windowsVcRuntime.profiles.join(" or ")}`, - ); - } - const bundledRuntimeNames = labels - .map((name) => path.basename(name)) - .filter((name) => MSVC_RUNTIME_IMPORT.test(name)); - const undeclaredPayload = bundledRuntimeNames.find( - (name) => !WINDOWS_VC_RUNTIME_DLL_SET.has(name.toLowerCase()), - ); - if (undeclaredPayload !== undefined) { - fail( - "platform-binary contract", - `Windows carrier bundles undeclared or debug VC runtime ${undeclaredPayload}`, - ); - } - const bundled = new Set(bundledRuntimeNames.map((name) => name.toLowerCase())); - const required = new Set(); - for (const { result, label } of inspected) { - for (const slice of result.slices) { - for (const imported of slice.msvcRuntimeImports ?? []) { - const normalized = imported.toLowerCase(); - required.add(normalized); - if (!bundled.has(normalized)) { - fail( - label, - `imports MSVC runtime ${imported}, but the exact DLL is not bundled in the same carrier closure`, - ); - } - } - } - } - const expected = profile === "provider" ? WINDOWS_VC_RUNTIME_DLL_SET : required; - const missing = [...expected].filter((name) => !bundled.has(name)); - if (missing.length > 0) { - fail( - "platform-binary contract", - `Windows ${profile} VC runtime profile is missing ${missing.sort().join(", ")}`, - ); - } - const extra = [...bundled].filter((name) => !expected.has(name)); - if (extra.length > 0) { - fail( - "platform-binary contract", - `Windows carrier bundles unneeded VC runtime closure member${extra.length === 1 ? "" : "s"} ${extra.sort().join(", ")}`, - ); - } - } - return { - target, - binaries: inspected.length, - slices: inspected.reduce((sum, { result }) => sum + result.slices.length, 0), - platforms: [...platforms].sort((left, right) => left - right), - files: labels, - }; -} - -export function inspectPlatformBinaryEntries( - entries, - { - target, - rootLabel = "staged release tree", - requiredApplePlatforms, - requireWindowsRuntimeImportLibrary = false, - windowsVcRuntimeProfile, - }, -) { - contractFor(target, rootLabel); - if (requireWindowsRuntimeImportLibrary && target !== "windows-x64-msvc") { - fail(rootLabel, "the Windows runtime import library can only be required for windows-x64-msvc"); - } - const inspected = []; - const labels = []; - let windowsRuntimeImportLibrarySeen = false; - for (const entry of entries) { - if (entry === null || entry === undefined) continue; - const name = String(entry.name ?? ""); - if (entry.isSymbolicLink === true) { - fail(name || rootLabel, "staged release tree contains a symbolic link"); - } - if (entry.isDirectory === true) continue; - if (entry.isFile === false) { - fail(name || rootLabel, "staged release tree contains a non-regular special entry"); - } - const data = typeof entry.data === "function" ? entry.data() : entry.data; - if (data === undefined) fail(name || rootLabel, "binary entry has no readable data"); - const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data); - const format = detectFormat(buffer); - const windowsRuntimeImportLibrary = name === WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH; - const windowsExtensionLegalTextLibrary = - target === "windows-x64-msvc" && - isWindowsExtensionLegalTextLibrary(name, buffer, format); - const msvcLibraryPath = - target === "windows-x64-msvc" && - MSVC_LIBRARY_PATH.test(name) && - !windowsExtensionLegalTextLibrary; - const expectedPath = - EXPECTED_BINARY_PATH.test(name) || - STATIC_ARCHIVE_PATH.test(name) || - msvcLibraryPath; - if (format === null && !expectedPath) continue; - if (format === null) fail(name || rootLabel, "expected native binary is malformed or truncated"); - const label = name ? `${rootLabel}/${name}` : rootLabel; - if (!windowsRuntimeImportLibrary && msvcLibraryPath) { - fail(label, `only the exact ${WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH} runtime import library is permitted`); - } - if (target === "windows-x64-msvc" && STATIC_ARCHIVE_PATH.test(name)) { - fail(label, "static .a archives are not permitted in a Windows release carrier"); - } - let result; - if (windowsRuntimeImportLibrary) { - if (!requireWindowsRuntimeImportLibrary) { - fail( - label, - `MSVC import library is only permitted when the exact ${WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH} runtime contract is required`, - ); - } - if (windowsRuntimeImportLibrarySeen) { - fail(label, `staged release tree repeats ${WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH}`); - } - if (format !== "ar") fail(label, "required MSVC import library is not an ar-format COFF archive"); - windowsRuntimeImportLibrarySeen = true; - result = parseWindowsRuntimeImportLibrary(buffer, label, contractFor(target, label)); - } else { - result = inspectPlatformBinaryBuffer(buffer, { target, label }); - } - inspected.push({ result, label }); - labels.push(name); - } - if (requireWindowsRuntimeImportLibrary && !windowsRuntimeImportLibrarySeen) { - fail( - `${rootLabel}/${WINDOWS_RUNTIME_IMPORT_LIBRARY_PATH}`, - "required Windows runtime import library is missing", - ); - } - return finalizeInspection( - target, - inspected, - labels.sort(), - requiredApplePlatforms, - windowsVcRuntimeProfile, - ); -} - -async function walkTree(root, relative = "") { - const directory = path.join(root, relative); - const names = await readdir(directory); - names.sort(); - const entries = []; - for (const name of names) { - const childRelative = relative ? path.join(relative, name) : name; - const child = path.join(root, childRelative); - const stat = await lstat(child); - if (stat.isSymbolicLink()) { - fail(child, "staged release tree contains a symbolic link"); - } else if (stat.isDirectory()) { - entries.push(...(await walkTree(root, childRelative))); - } else if (stat.isFile()) { - entries.push({ name: childRelative.split(path.sep).join("/"), data: await readFile(child), isFile: true }); - } else { - fail(child, "staged release tree contains a non-regular special entry"); - } - } - return entries; -} - -export async function inspectPlatformBinaryTree( - root, - { - target, - requiredApplePlatforms, - requireWindowsRuntimeImportLibrary = false, - windowsVcRuntimeProfile, - }, -) { - const absolute = path.resolve(root); - const stat = await lstat(absolute).catch(() => null); - if (stat === null || !stat.isDirectory()) { - fail(absolute, "staged release tree is missing or is not a directory"); - } - return inspectPlatformBinaryEntries(await walkTree(absolute), { - target, - rootLabel: absolute, - requiredApplePlatforms, - requireWindowsRuntimeImportLibrary, - windowsVcRuntimeProfile, - }); -} - -function usage() { - return "usage: tools/release/platform-binary-contract.mjs --target TARGET --root STAGED_RELEASE_TREE [--required-apple-platforms macos,ios,ios-simulator] [--require-windows-runtime-import-library] [--windows-vc-runtime-profile direct|provider]\n"; -} - -async function main(argv) { - let target = ""; - let root = ""; - let requiredApplePlatforms; - let requireWindowsRuntimeImportLibrary = false; - let windowsVcRuntimeProfile; - for (let index = 0; index < argv.length; index += 1) { - if (argv[index] === "--target") { - target = argv[++index] ?? ""; - } else if (argv[index] === "--root") { - root = argv[++index] ?? ""; - } else if (argv[index] === "--required-apple-platforms") { - const raw = argv[++index] ?? ""; - const names = raw.split(",").filter(Boolean); - if (names.length === 0 || new Set(names).size !== names.length) { - fail("platform-binary-contract.mjs", "--required-apple-platforms must be a nonempty unique CSV"); - } - requiredApplePlatforms = names.map((name) => { - const platform = APPLE_PLATFORM_BY_CLI_NAME.get(name); - if (platform === undefined) { - fail("platform-binary-contract.mjs", `unknown Apple platform ${JSON.stringify(name)}`); - } - return platform.id; - }); - } else if (argv[index] === "--require-windows-runtime-import-library") { - requireWindowsRuntimeImportLibrary = true; - } else if (argv[index] === "--windows-vc-runtime-profile") { - windowsVcRuntimeProfile = argv[++index] ?? ""; - if (!WINDOWS_VC_RUNTIME_PROFILES.includes(windowsVcRuntimeProfile)) { - fail( - "platform-binary-contract.mjs", - `--windows-vc-runtime-profile must be ${WINDOWS_VC_RUNTIME_PROFILES.join(" or ")}`, - ); - } - } else if (argv[index] === "--help" || argv[index] === "-h") { - process.stdout.write(usage()); - return; - } else { - fail("platform-binary-contract.mjs", `unknown argument ${JSON.stringify(argv[index])}`); - } - } - if (!target || !root) { - process.stderr.write(usage()); - process.exitCode = 2; - return; - } - const result = await inspectPlatformBinaryTree(root, { - target, - requiredApplePlatforms, - requireWindowsRuntimeImportLibrary, - windowsVcRuntimeProfile, - }); - console.log( - `platform binary contract passed: target=${result.target} binaries=${result.binaries} slices=${result.slices}`, - ); -} - -if (import.meta.main) { - try { - await main(Bun.argv.slice(2)); - } catch (error) { - console.error(`platform-binary-contract.mjs: ${error.message}`); - process.exit(1); - } -} diff --git a/tools/release/platform-binary-contract.test.mjs b/tools/release/platform-binary-contract.test.mjs deleted file mode 100644 index b8bc82209..000000000 --- a/tools/release/platform-binary-contract.test.mjs +++ /dev/null @@ -1,756 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtemp, mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { - inspectPlatformBinaryBuffer, - inspectPlatformBinaryEntries, - inspectPlatformBinaryTree, -} from "./platform-binary-contract.mjs"; -import { - OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS, - windowsImportLibraryFixture, -} from "../test/release-fixture-utils.mjs"; - -const temporaryRoots = []; - -afterEach(async () => { - await Promise.all(temporaryRoots.splice(0).map((root) => rm(root, { recursive: true, force: true }))); -}); - -function packedVersion(major, minor = 0, patch = 0) { - return (major << 16) | (minor << 8) | patch; -} - -function macho({ - platform = 1, - minos = [11, 0, 0], - cpu = 0x0100000c, - cpuSubtype = 0, - commandSize = 24, - commands = 1, -} = {}) { - const buffer = Buffer.alloc(32 + commandSize); - buffer.writeUInt32LE(0xfeedfacf, 0); - buffer.writeUInt32LE(cpu, 4); - buffer.writeUInt32LE(cpuSubtype, 8); - buffer.writeUInt32LE(6, 12); - buffer.writeUInt32LE(commands, 16); - buffer.writeUInt32LE(commandSize, 20); - buffer.writeUInt32LE(0, 24); - buffer.writeUInt32LE(0, 28); - if (commands > 0 && commandSize >= 8) { - buffer.writeUInt32LE(0x32, 32); - buffer.writeUInt32LE(commandSize, 36); - if (commandSize >= 24) { - buffer.writeUInt32LE(platform, 40); - buffer.writeUInt32LE(packedVersion(...minos), 44); - buffer.writeUInt32LE(packedVersion(...minos), 48); - buffer.writeUInt32LE(0, 52); - } - } - return buffer; -} - -function fatMacho(slices) { - const tableSize = 8 + slices.length * 20; - let cursor = tableSize; - const offsets = []; - for (const slice of slices) { - while (cursor % 4 !== 0) cursor += 1; - offsets.push(cursor); - cursor += slice.length; - } - const buffer = Buffer.alloc(cursor); - buffer.writeUInt32BE(0xcafebabe, 0); - buffer.writeUInt32BE(slices.length, 4); - for (let index = 0; index < slices.length; index += 1) { - const entry = 8 + index * 20; - buffer.writeUInt32BE(0x0100000c, entry); - buffer.writeUInt32BE(slices[index].readUInt32LE(8), entry + 4); - buffer.writeUInt32BE(offsets[index], entry + 8); - buffer.writeUInt32BE(slices[index].length, entry + 12); - buffer.writeUInt32BE(2, entry + 16); - slices[index].copy(buffer, offsets[index]); - } - return buffer; -} - -function ar(members) { - const chunks = [Buffer.from("!\n", "ascii")]; - for (const [name, data] of members) { - const encodedName = `${name}/`.padEnd(16, " "); - const header = Buffer.from( - `${encodedName}${"0".padEnd(12, " ")}${"0".padEnd(6, " ")}${"0".padEnd(6, " ")}${"100644".padEnd(8, " ")}${String(data.length).padEnd(10, " ")}\`\n`, - "ascii", - ); - chunks.push(header, data); - if (data.length % 2 !== 0) chunks.push(Buffer.from("\n", "ascii")); - } - return Buffer.concat(chunks); -} - -function elf({ - machine = 62, - bits = 64, - littleEndian = true, - versions = [], - truncateSectionTable = false, - androidApi = null, - type = 3, -} = {}) { - const versionBytes = Buffer.from(`\0${versions.join("\0")}\0`, "ascii"); - const note = androidApi === null ? null : Buffer.alloc(24); - if (note !== null) { - note.writeUInt32LE(8, 0); - note.writeUInt32LE(4, 4); - note.writeUInt32LE(1, 8); - note.write("Android\0", 12, "ascii"); - note.writeUInt32LE(androidApi, 20); - } - const noteOffset = align(64 + versionBytes.length, 4); - const sectionOffset = note === null ? 0 : align(noteOffset + note.length, 8); - const buffer = Buffer.alloc(note === null ? 64 + versionBytes.length : sectionOffset + 128); - Buffer.from([0x7f, 0x45, 0x4c, 0x46]).copy(buffer, 0); - buffer[4] = bits === 64 ? 2 : 1; - buffer[5] = littleEndian ? 1 : 2; - buffer[6] = 1; - buffer.writeUInt16LE(type, 16); - buffer.writeUInt16LE(machine, 18); - buffer.writeUInt32LE(1, 20); - buffer.writeUInt16LE(64, 52); - if (truncateSectionTable) { - buffer.writeBigUInt64LE(64n, 40); - buffer.writeUInt16LE(64, 58); - buffer.writeUInt16LE(2, 60); - } - versionBytes.copy(buffer, 64); - if (note !== null) { - note.copy(buffer, noteOffset); - buffer.writeBigUInt64LE(BigInt(sectionOffset), 40); - buffer.writeUInt16LE(64, 58); - buffer.writeUInt16LE(2, 60); - const noteSection = sectionOffset + 64; - buffer.writeUInt32LE(7, noteSection + 4); - buffer.writeBigUInt64LE(BigInt(noteOffset), noteSection + 24); - buffer.writeBigUInt64LE(BigInt(note.length), noteSection + 32); - buffer.writeBigUInt64LE(4n, noteSection + 48); - } - return buffer; -} - -function align(value, alignment) { - return Math.ceil(value / alignment) * alignment; -} - -function pe({ - machine = 0x8664, - optionalMagic = 0x20b, - imports = ["KERNEL32.dll"], - delayImports = [], -} = {}) { - const peOffset = 0x80; - const optionalSize = 240; - const sectionTable = peOffset + 24 + optionalSize; - const rawOffset = 0x200; - const rawSize = 0x400; - const virtualAddress = 0x1000; - const buffer = Buffer.alloc(rawOffset + rawSize); - buffer.write("MZ", 0, "ascii"); - buffer.writeUInt32LE(peOffset, 0x3c); - buffer.write("PE\0\0", peOffset, "ascii"); - const coff = peOffset + 4; - buffer.writeUInt16LE(machine, coff); - buffer.writeUInt16LE(1, coff + 2); - buffer.writeUInt16LE(optionalSize, coff + 16); - buffer.writeUInt16LE(0x2022, coff + 18); - const optional = coff + 20; - buffer.writeUInt16LE(optionalMagic, optional); - buffer.writeBigUInt64LE(0x140000000n, optional + 24); - buffer.writeUInt32LE(rawOffset, optional + 60); - buffer.writeUInt32LE(16, optional + 108); - const descriptorBytes = (imports.length + 1) * 20; - buffer.writeUInt32LE(virtualAddress, optional + 120); - buffer.writeUInt32LE(descriptorBytes, optional + 124); - if (delayImports.length > 0) { - const delayDescriptorOffset = rawOffset + 0x100; - buffer.writeUInt32LE(virtualAddress + (delayDescriptorOffset - rawOffset), optional + 216); - buffer.writeUInt32LE((delayImports.length + 1) * 32, optional + 220); - } - buffer.write(".rdata\0\0", sectionTable, "ascii"); - buffer.writeUInt32LE(rawSize, sectionTable + 8); - buffer.writeUInt32LE(virtualAddress, sectionTable + 12); - buffer.writeUInt32LE(rawSize, sectionTable + 16); - buffer.writeUInt32LE(rawOffset, sectionTable + 20); - let nameOffset = rawOffset + 0x200; - for (let index = 0; index < imports.length; index += 1) { - const descriptor = rawOffset + index * 20; - buffer.writeUInt32LE(virtualAddress + (nameOffset - rawOffset), descriptor + 12); - buffer.write(`${imports[index]}\0`, nameOffset, "ascii"); - nameOffset += Buffer.byteLength(imports[index]) + 1; - } - for (let index = 0; index < delayImports.length; index += 1) { - const descriptor = rawOffset + 0x100 + index * 32; - buffer.writeUInt32LE(1, descriptor); - buffer.writeUInt32LE(virtualAddress + (nameOffset - rawOffset), descriptor + 4); - buffer.write(`${delayImports[index]}\0`, nameOffset, "ascii"); - nameOffset += Buffer.byteLength(delayImports[index]) + 1; - } - return buffer; -} - -function entry(name, data) { - return { name, data, isFile: true }; -} - -describe("Mach-O platform compatibility", () => { - test("accepts a thin arm64 direct macOS binary at the 11.0 floor", () => { - const result = inspectPlatformBinaryBuffer(macho(), { target: "macos-arm64", label: "lib.dylib" }); - expect(result.slices[0].platformName).toBe("macOS"); - expect(result.slices[0].minos).toEqual([11, 0, 0]); - }); - - test("rejects the observed accidental macOS 26.0 floor", () => { - expect(() => - inspectPlatformBinaryBuffer(macho({ minos: [26, 0, 0] }), { - target: "macos-arm64", - label: "lib.dylib", - }), - ).toThrow(/minimum OS 26\.0 exceeds.*11\.0/u); - }); - - test("rejects x64, missing build metadata, and truncated load commands", () => { - expect(() => - inspectPlatformBinaryBuffer(macho({ cpu: 0x01000007 }), { target: "macos-arm64", label: "wrong.dylib" }), - ).toThrow(/not arm64/u); - expect(() => - inspectPlatformBinaryBuffer(macho({ cpuSubtype: 2 }), { - target: "macos-arm64", - label: "arm64e.dylib", - }), - ).toThrow(/not generic ARM64_ALL.*arm64e-only/u); - expect(() => - inspectPlatformBinaryBuffer(macho({ commands: 0, commandSize: 0 }), { - target: "macos-arm64", - label: "missing.dylib", - }), - ).toThrow(/exactly one LC_BUILD_VERSION/u); - expect(() => - inspectPlatformBinaryBuffer(macho({ commandSize: 12 }), { target: "macos-arm64", label: "short.dylib" }), - ).toThrow(/LC_BUILD_VERSION is truncated/u); - }); - - test("bounds-checks fat slices and validates every embedded slice", () => { - const valid = fatMacho([macho()]); - expect(inspectPlatformBinaryBuffer(valid, { target: "macos-arm64", label: "fat" }).slices).toHaveLength(1); - const outside = Buffer.from(valid); - outside.writeUInt32BE(outside.length - 4, 16); - expect(() => inspectPlatformBinaryBuffer(outside, { target: "macos-arm64", label: "fat" })).toThrow( - /outside the .*file/u, - ); - const highFloor = fatMacho([macho({ minos: [14, 0, 0] })]); - expect(() => inspectPlatformBinaryBuffer(highFloor, { target: "macos-arm64", label: "fat" })).toThrow( - /exceeds.*11\.0/u, - ); - expect(() => - inspectPlatformBinaryBuffer(fatMacho([macho(), macho()]), { - target: "macos-arm64", - label: "duplicate-fat", - }), - ).toThrow(/duplicates architecture identity arm64\/ARM64_ALL/u); - }); - - test("requires iOS device and simulator and permits macOS only through 14.0", () => { - const entries = [ - entry("device/lib", macho({ platform: 2, minos: [17, 0, 0] })), - entry("simulator/lib", macho({ platform: 7, minos: [17, 0, 0] })), - entry("macos/lib", macho({ platform: 1, minos: [14, 0, 0] })), - ]; - expect(inspectPlatformBinaryEntries(entries, { target: "ios-xcframework" }).platforms).toEqual([1, 2, 7]); - expect(() => inspectPlatformBinaryEntries(entries.slice(0, 1), { target: "ios-xcframework" })).toThrow( - /missing macOS and iOS Simulator/u, - ); - expect(() => - inspectPlatformBinaryEntries( - [...entries.slice(0, 2), entry("macos/lib", macho({ platform: 1, minos: [14, 1, 0] }))], - { target: "ios-xcframework" }, - ), - ).toThrow(/macOS minimum OS 14\.1 exceeds.*14\.0/u); - }); - - test("inspects Mach-O object members in static XCFramework archives", () => { - const entries = [ - entry("macos/libextension.a", ar([["macos.o", macho({ platform: 1, minos: [11, 0, 0] })]])), - entry("device/libextension.a", ar([["device.o", macho({ platform: 2, minos: [17, 0, 0] })]])), - entry("simulator/libextension.a", ar([["sim.o", macho({ platform: 7, minos: [17, 0, 0] })]])), - ]; - expect( - inspectPlatformBinaryEntries(entries, { - target: "ios-xcframework", - requiredApplePlatforms: [1, 2, 7], - }).slices, - ).toBe(3); - const malformed = Buffer.from(entries[1].data); - malformed[8 + 58] = 0; - expect(() => - inspectPlatformBinaryEntries([entries[0], entry("device/libextension.a", malformed), entries[2]], { - target: "ios-xcframework", - requiredApplePlatforms: [1, 2, 7], - }), - ).toThrow(/invalid header trailer/u); - expect(() => - inspectPlatformBinaryEntries( - [entries[0], entry("device/libextension.a", ar([["readme", Buffer.from("not an object")]])), entries[2]], - { target: "ios-xcframework", requiredApplePlatforms: [1, 2, 7] }, - ), - ).toThrow(/not a MACHO object/u); - expect(() => - inspectPlatformBinaryEntries(entries.slice(1), { - target: "ios-xcframework", - requiredApplePlatforms: [1, 2, 7], - }), - ).toThrow(/missing macOS/u); - }); -}); - -describe("ELF platform and GNU symbol-version compatibility", () => { - test("accepts the Linux x64 and arm64 ceilings", () => { - const x64 = inspectPlatformBinaryBuffer(elf({ versions: ["GLIBC_2.38", "GLIBCXX_3.4.30"] }), { - target: "linux-x64-gnu", - label: "postgres", - }); - expect(x64.slices[0].requiredVersions).toEqual(["GLIBCXX_3.4.30", "GLIBC_2.38"]); - expect(() => - inspectPlatformBinaryBuffer(elf({ machine: 183, versions: ["GLIBC_2.17"] }), { - target: "linux-arm64-gnu", - label: "postgres", - }), - ).not.toThrow(); - }); - - test("rejects GLIBC and GLIBCXX requirements above the contract", () => { - expect(() => - inspectPlatformBinaryBuffer(elf({ versions: ["GLIBC_2.39"] }), { - target: "linux-x64-gnu", - label: "new-glibc.so", - }), - ).toThrow(/GLIBC_2\.39 exceeds.*2\.38/u); - expect(() => - inspectPlatformBinaryBuffer(elf({ versions: ["GLIBCXX_3.4.31"] }), { - target: "linux-x64-gnu", - label: "new-libstdcxx.so", - }), - ).toThrow(/GLIBCXX_3\.4\.31 exceeds.*3\.4\.30/u); - }); - - test("rejects wrong architecture, class, byte order, and truncated tables", () => { - expect(() => - inspectPlatformBinaryBuffer(elf({ machine: 183 }), { target: "linux-x64-gnu", label: "wrong.so" }), - ).toThrow(/does not match x64/u); - expect(() => - inspectPlatformBinaryBuffer(elf({ bits: 32 }), { target: "linux-x64-gnu", label: "32.so" }), - ).toThrow(/not ELF64/u); - expect(() => - inspectPlatformBinaryBuffer(elf({ littleEndian: false }), { target: "linux-x64-gnu", label: "be.so" }), - ).toThrow(/not little-endian/u); - expect(() => - inspectPlatformBinaryBuffer(elf({ truncateSectionTable: true }), { - target: "linux-x64-gnu", - label: "truncated.so", - }), - ).toThrow(/section-header table.*outside/u); - }); - - test("accepts Android without GNU desktop versions and rejects GLIBC leakage", () => { - expect(() => - inspectPlatformBinaryBuffer(elf({ machine: 183, androidApi: 24 }), { - target: "android-arm64-v8a", - label: "liboliphaunt.so", - }), - ).not.toThrow(); - expect(() => - inspectPlatformBinaryBuffer(elf({ machine: 183, versions: ["GLIBC_2.17"], androidApi: 24 }), { - target: "android-arm64-v8a", - label: "host-leak.so", - }), - ).toThrow(/Android ELF requires forbidden.*GLIBC_2\.17/u); - expect(() => - inspectPlatformBinaryBuffer(elf({ machine: 183 }), { - target: "android-arm64-v8a", - label: "missing-note.so", - }), - ).toThrow(/exactly one \.note\.android\.ident API record/u); - expect(() => - inspectPlatformBinaryBuffer(elf({ machine: 183, androidApi: 26 }), { - target: "android-arm64-v8a", - label: "wrong-api.so", - }), - ).toThrow(/API level 26 does not match.*24/u); - }); -}); - -describe("PE32+ architecture and self-contained runtime imports", () => { - test("accepts x64 PE32+ system imports", () => { - const result = inspectPlatformBinaryBuffer(pe({ imports: ["node.exe", "KERNEL32.dll"] }), { - target: "windows-x64-msvc", - label: "oliphaunt_node.node", - }); - expect(result.slices[0].imports).toEqual(["KERNEL32.dll", "node.exe"]); - }); - - test("requires app-local production MSVC runtime closure and rejects debug CRT", () => { - const main = pe({ imports: ["VCRUNTIME140.dll"], delayImports: ["MSVCP140.dll"] }); - expect(() => - inspectPlatformBinaryEntries([entry("bin/oliphaunt.dll", main)], { target: "windows-x64-msvc" }), - ).toThrow(/MSVCP140\.dll.*not bundled/u); - expect(() => - inspectPlatformBinaryEntries( - [ - entry("bin/oliphaunt.dll", main), - entry("bin/VCRUNTIME140.dll", pe()), - entry("bin/MSVCP140.dll", pe({ imports: ["VCRUNTIME140.dll"] })), - ], - { target: "windows-x64-msvc" }, - ), - ).not.toThrow(); - expect(() => - inspectPlatformBinaryBuffer(pe({ imports: ["VCRUNTIME140D.dll"] }), { - target: "windows-x64-msvc", - label: "debug.exe", - }), - ).toThrow(/undeclared or debug VC runtime/u); - expect(() => - inspectPlatformBinaryBuffer(pe({ imports: ["CONCRT140.dll"] }), { - target: "windows-x64-msvc", - label: "undeclared.exe", - }), - ).toThrow(/undeclared or debug VC runtime CONCRT140\.dll/u); - expect(() => - inspectPlatformBinaryEntries( - [entry("bin/oliphaunt.dll", pe()), entry("bin/vcruntime140.dll", pe())], - { target: "windows-x64-msvc" }, - ), - ).toThrow(/unneeded VC runtime closure member vcruntime140\.dll/u); - expect(() => - inspectPlatformBinaryEntries( - [ - entry("bin/oliphaunt.dll", pe()), - entry("bin/msvcp140.dll", pe()), - entry("bin/vcruntime140.dll", pe()), - entry("bin/vcruntime140_1.dll", pe()), - ], - { target: "windows-x64-msvc", windowsVcRuntimeProfile: "provider" }, - ), - ).not.toThrow(); - expect(() => - inspectPlatformBinaryEntries( - [entry("bin/oliphaunt.dll", pe()), entry("bin/vcruntime140.dll", pe())], - { target: "windows-x64-msvc", windowsVcRuntimeProfile: "provider" }, - ), - ).toThrow(/provider VC runtime profile is missing msvcp140\.dll, vcruntime140_1\.dll/u); - }); - - test("rejects x86, PE32, malformed import descriptors, and truncated files", () => { - expect(() => - inspectPlatformBinaryBuffer(pe({ machine: 0x14c }), { target: "windows-x64-msvc", label: "x86.exe" }), - ).toThrow(/not x64/u); - expect(() => - inspectPlatformBinaryBuffer(pe({ optionalMagic: 0x10b }), { - target: "windows-x64-msvc", - label: "pe32.exe", - }), - ).toThrow(/not PE32\+/u); - const unterminated = pe({ imports: ["KERNEL32.dll"] }); - const optional = 0x80 + 24; - unterminated.writeUInt32LE(20, optional + 124); - expect(() => - inspectPlatformBinaryBuffer(unterminated, { target: "windows-x64-msvc", label: "bad.exe" }), - ).toThrow(/unterminated/u); - expect(() => - inspectPlatformBinaryBuffer(Buffer.from("MZ"), { target: "windows-x64-msvc", label: "short.exe" }), - ).toThrow(/DOS header.*outside/u); - }); - - test("validates the exported Windows contract through the standalone CLI", async () => { - const root = await mkdtemp(path.join(tmpdir(), "platform-binary-windows-cli-")); - temporaryRoots.push(root); - await writeFile(path.join(root, "oliphaunt_node.node"), pe()); - const result = spawnSync( - process.execPath, - [ - path.join(import.meta.dir, "platform-binary-contract.mjs"), - "--target", - "windows-x64-msvc", - "--root", - root, - ], - { encoding: "utf8" }, - ); - expect(result.status, `${result.stderr}${result.stdout}`).toBe(0); - expect(result.stdout).toContain("platform binary contract passed: target=windows-x64-msvc"); - }); - - test("accepts only the required lib/oliphaunt.lib import-library identity behind an explicit runtime opt-in", async () => { - const importLibrary = windowsImportLibraryFixture(); - const runtimeEntries = [ - entry("bin/oliphaunt.dll", pe()), - entry("lib/oliphaunt.lib", importLibrary), - ]; - const result = inspectPlatformBinaryEntries(runtimeEntries, { - target: "windows-x64-msvc", - requireWindowsRuntimeImportLibrary: true, - }); - expect(result.files).toEqual(["bin/oliphaunt.dll", "lib/oliphaunt.lib"]); - expect(result.binaries).toBe(2); - expect(result.slices).toBe(2 + OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS.length); - - expect(() => - inspectPlatformBinaryEntries(runtimeEntries, { target: "windows-x64-msvc" }), - ).toThrow(/only permitted when the exact lib\/oliphaunt\.lib runtime contract is required/u); - expect(() => - inspectPlatformBinaryEntries( - [entry("bin/oliphaunt.dll", pe()), entry("lib/renamed.lib", importLibrary)], - { target: "windows-x64-msvc", requireWindowsRuntimeImportLibrary: true }, - ), - ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); - expect(() => - inspectPlatformBinaryEntries([entry("bin/oliphaunt.dll", pe())], { - target: "windows-x64-msvc", - requireWindowsRuntimeImportLibrary: true, - }), - ).toThrow(/lib\/oliphaunt\.lib.*required Windows runtime import library is missing/u); - expect(() => - inspectPlatformBinaryEntries([...runtimeEntries, entry("lib/oliphaunt.lib", importLibrary)], { - target: "windows-x64-msvc", - requireWindowsRuntimeImportLibrary: true, - }), - ).toThrow(/repeats lib\/oliphaunt\.lib/u); - - const root = await mkdtemp(path.join(tmpdir(), "platform-binary-windows-import-library-cli-")); - temporaryRoots.push(root); - await mkdir(path.join(root, "bin"), { recursive: true }); - await mkdir(path.join(root, "lib"), { recursive: true }); - await writeFile(path.join(root, "bin/oliphaunt.dll"), pe()); - await writeFile(path.join(root, "lib/oliphaunt.lib"), importLibrary); - const cli = spawnSync( - process.execPath, - [ - path.join(import.meta.dir, "platform-binary-contract.mjs"), - "--target", - "windows-x64-msvc", - "--root", - root, - "--require-windows-runtime-import-library", - ], - { encoding: "utf8" }, - ); - expect(cli.status, `${cli.stderr}${cli.stdout}`).toBe(0); - }); - - test("keeps PostGIS COPYING.LIB legal text out of Windows binary discovery without admitting stray libraries", () => { - const legalText = Buffer.from( - "GNU LIBRARY GENERAL PUBLIC LICENSE\n\fTERMS AND CONDITIONS\n", - "utf8", - ); - const entries = [ - entry("bin/oliphaunt.dll", pe()), - entry("files/lib/postgresql/postgis-3.dll", pe()), - entry("files/lib/modules/postgis-3.dll", pe()), - entry("lib/oliphaunt.lib", windowsImportLibraryFixture()), - entry("files/share/licenses/libcharset/COPYING.LIB", legalText), - entry("files/share/licenses/libiconv/COPYING.LIB", legalText), - ]; - const result = inspectPlatformBinaryEntries(entries, { - target: "windows-x64-msvc", - requireWindowsRuntimeImportLibrary: true, - }); - expect(result.files).toEqual([ - "bin/oliphaunt.dll", - "files/lib/modules/postgis-3.dll", - "files/lib/postgresql/postgis-3.dll", - "lib/oliphaunt.lib", - ]); - expect(result.binaries).toBe(4); - - expect(() => - inspectPlatformBinaryEntries( - [...entries, entry("files/lib/arbitrary.lib", windowsImportLibraryFixture())], - { target: "windows-x64-msvc", requireWindowsRuntimeImportLibrary: true }, - ), - ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); - expect(() => - inspectPlatformBinaryEntries( - [...entries, entry("files/lib/malformed.lib", Buffer.from("not an import library\n"))], - { target: "windows-x64-msvc", requireWindowsRuntimeImportLibrary: true }, - ), - ).toThrow(/files\/lib\/malformed\.lib.*expected native binary is malformed or truncated/u); - expect(() => - inspectPlatformBinaryEntries( - [...entries, entry("files/share/uncontracted/COPYING.LIB", legalText)], - { target: "windows-x64-msvc", requireWindowsRuntimeImportLibrary: true }, - ), - ).toThrow(/files\/share\/uncontracted\/COPYING\.LIB.*expected native binary is malformed or truncated/u); - expect(() => - inspectPlatformBinaryEntries( - entries.map((candidate) => - candidate.name === "files/share/licenses/libcharset/COPYING.LIB" - ? entry(candidate.name, windowsImportLibraryFixture()) - : candidate, - ), - { target: "windows-x64-msvc", requireWindowsRuntimeImportLibrary: true }, - ), - ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); - expect(() => - inspectPlatformBinaryEntries( - entries.map((candidate) => - candidate.name === "files/share/licenses/libcharset/COPYING.LIB" - ? entry(candidate.name, Buffer.from([0x47, 0x50, 0x4c, 0x00, 0xff])) - : candidate, - ), - { target: "windows-x64-msvc", requireWindowsRuntimeImportLibrary: true }, - ), - ).toThrow(/COPYING\.LIB.*expected native binary is malformed or truncated/u); - }); - - test("rejects malformed, wrong-machine, wrong-DLL, and arbitrary Windows libraries", () => { - const inspectImportLibrary = (data) => - inspectPlatformBinaryEntries( - [entry("bin/oliphaunt.dll", pe()), entry("lib/oliphaunt.lib", data)], - { target: "windows-x64-msvc", requireWindowsRuntimeImportLibrary: true }, - ); - - expect(() => - inspectImportLibrary(windowsImportLibraryFixture({ objectMachine: 0x14c })), - ).toThrow(/COFF object machine 0x14c is not x64/u); - expect(() => - inspectImportLibrary(windowsImportLibraryFixture({ importMachine: 0x14c })), - ).toThrow(/COFF import-object machine 0x14c is not x64/u); - expect(() => - inspectImportLibrary(windowsImportLibraryFixture({ dllName: "unrelated.dll" })), - ).toThrow(/names unexpected DLL "unrelated\.dll"/u); - expect(() => - inspectImportLibrary(windowsImportLibraryFixture({ symbol: "unrelated_symbol" })), - ).toThrow(/does not expose required symbol oliphaunt_init/u); - expect(() => - inspectImportLibrary(windowsImportLibraryFixture({ importSymbols: ["oliphaunt_init"] })), - ).toThrow(/does not expose required symbol oliphaunt_logical_generation/u); - expect(() => - inspectImportLibrary( - windowsImportLibraryFixture({ - importSymbols: [ - "oliphaunt_init", - "oliphaunt_logical_generation", - ], - }), - ), - ).toThrow(/does not expose required symbol oliphaunt_close_if_generation/u); - expect(() => - inspectImportLibrary( - windowsImportLibraryFixture({ - importSymbols: OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS.filter( - (symbol) => symbol !== "oliphaunt_copy_last_error", - ), - }), - ), - ).toThrow(/does not expose required symbol oliphaunt_copy_last_error/u); - - const invalidOffset = Buffer.from(windowsImportLibraryFixture()); - invalidOffset.writeUInt32BE(0, 8 + 60 + 4); - expect(() => inspectImportLibrary(invalidOffset)).toThrow(/refers to non-object archive offset 0/u); - expect(() => inspectImportLibrary(Buffer.from("not an import library\n"))).toThrow( - /expected native binary is malformed or truncated/u, - ); - expect(() => - inspectPlatformBinaryEntries( - [entry("bin/oliphaunt.dll", pe()), entry("lib/arbitrary.lib", windowsImportLibraryFixture())], - { target: "windows-x64-msvc" }, - ), - ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); - expect(() => - inspectPlatformBinaryEntries( - [entry("bin/oliphaunt.dll", pe()), entry("lib/arbitrary.lib", pe())], - { target: "windows-x64-msvc" }, - ), - ).toThrow(/only the exact lib\/oliphaunt\.lib runtime import library is permitted/u); - expect(() => - inspectPlatformBinaryEntries( - [entry("bin/oliphaunt.dll", pe()), entry("lib/development.a", windowsImportLibraryFixture())], - { target: "windows-x64-msvc" }, - ), - ).toThrow(/static \.a archives are not permitted in a Windows release carrier/u); - expect(() => - inspectPlatformBinaryEntries( - [entry("bin/oliphaunt.dll", pe()), entry("lib/development.a", pe())], - { target: "windows-x64-msvc" }, - ), - ).toThrow(/static \.a archives are not permitted in a Windows release carrier/u); - }); - - test("keeps the real Windows package shape and hosted C link smoke behind the same validator", async () => { - const packager = await readFile( - path.join(import.meta.dir, "package-liboliphaunt-windows-assets.ps1"), - "utf8", - ); - expect(packager).toContain('$ImportLib = Join-Path $WorkRoot "out/lib/oliphaunt.lib"'); - expect(packager).toContain('Copy-Item -Force $ImportLib (Join-Path $Stage "lib")'); - const validation = packager.indexOf("--require-windows-runtime-import-library"); - const linkSmoke = packager.indexOf("run-host-c-smoke.mjs"); - expect(validation).toBeGreaterThan(0); - expect(linkSmoke).toBeGreaterThan(validation); - }); -}); - -describe("staged-tree discovery", () => { - test("requires a binary and rejects malformed expected binary names", () => { - expect(() => inspectPlatformBinaryEntries([entry("README.md", Buffer.from("text"))], { target: "linux-x64-gnu" })).toThrow( - /no ELF binaries/u, - ); - expect(() => - inspectPlatformBinaryEntries( - [entry("lib/good.so", elf()), entry("lib/truncated.dylib", Buffer.from([0xcf, 0xfa]))], - { target: "linux-x64-gnu" }, - ), - ).toThrow(/truncated\.dylib.*malformed or truncated/u); - expect(() => - inspectPlatformBinaryEntries([entry("lib/wrong.so", macho())], { target: "linux-x64-gnu" }), - ).toThrow(/MACHO content does not match/u); - }); - - test("walks a staged release tree without executing platform tools", async () => { - const root = await mkdtemp(path.join(tmpdir(), "oliphaunt-platform-binary-")); - temporaryRoots.push(root); - await mkdir(path.join(root, "lib"), { recursive: true }); - await writeFile(path.join(root, "README.md"), "fixture"); - await writeFile(path.join(root, "lib", "liboliphaunt.so"), elf({ versions: ["GLIBC_2.38"] })); - const result = await inspectPlatformBinaryTree(root, { target: "linux-x64-gnu" }); - expect(result.binaries).toBe(1); - expect(result.files).toEqual(["lib/liboliphaunt.so"]); - }); - - test("fails closed on symbolic links and non-regular archive entries", async () => { - expect(() => - inspectPlatformBinaryEntries( - [entry("lib/libok.so", elf()), { name: "lib/redirect.so", isFile: false, isSymbolicLink: true }], - { target: "linux-x64-gnu" }, - ), - ).toThrow(/redirect\.so.*symbolic link/u); - expect(() => - inspectPlatformBinaryEntries( - [entry("lib/libok.so", elf()), { name: "lib/device", isFile: false }], - { target: "linux-x64-gnu" }, - ), - ).toThrow(/device.*non-regular special entry/u); - - const root = await mkdtemp(path.join(tmpdir(), "platform-binary-link-")); - temporaryRoots.push(root); - await mkdir(path.join(root, "lib")); - await writeFile(path.join(root, "lib/libok.so"), elf()); - await writeFile(path.join(root, "target"), "outside"); - await symlink("target", path.join(root, "redirect")); - await expect(inspectPlatformBinaryTree(root, { target: "linux-x64-gnu" })).rejects.toThrow( - /redirect.*symbolic link/u, - ); - }); -}); diff --git a/tools/release/platform-compatibility-policy.mjs b/tools/release/platform-compatibility-policy.mjs deleted file mode 100644 index 3b037a3e4..000000000 --- a/tools/release/platform-compatibility-policy.mjs +++ /dev/null @@ -1,153 +0,0 @@ -const version = (...parts) => Object.freeze(parts); - -export const APPLE_PLATFORM_COMPATIBILITY = Object.freeze({ - macos: Object.freeze({ id: 1, name: "macOS", cliName: "macos" }), - ios: Object.freeze({ id: 2, name: "iOS", cliName: "ios" }), - iosSimulator: Object.freeze({ - id: 7, - name: "iOS Simulator", - cliName: "ios-simulator", - }), -}); - -const MACHO_ARM64 = Object.freeze({ cpuType: 0x0100000c, cpuSubtype: 0 }); -const ELF64_LITTLE_ENDIAN = Object.freeze({ bits: 64, endianness: "little" }); -const GNU_REQUIRED_VERSION_MAXIMUMS = Object.freeze({ - GLIBC: version(2, 38, 0), - GLIBCXX: version(3, 4, 30), -}); -const FORBIDDEN_ANDROID_VERSION_FAMILIES = Object.freeze(["GLIBC", "GLIBCXX"]); - -function applePlatform(key, maximumMinimumOs) { - const platform = APPLE_PLATFORM_COMPATIBILITY[key]; - return Object.freeze({ ...platform, maximumMinimumOs }); -} - -function machoArm64Contract({ carrier, platforms, requiredPlatforms, allowPlatformOverride }) { - const allowed = Object.freeze( - Object.fromEntries( - platforms.map(([key, maximumMinimumOs]) => [key, applePlatform(key, maximumMinimumOs)]), - ), - ); - return Object.freeze({ - format: "macho", - architecture: "arm64", - macho: MACHO_ARM64, - apple: Object.freeze({ - carrier, - platforms: allowed, - requiredPlatforms: Object.freeze([...requiredPlatforms]), - allowPlatformOverride, - }), - }); -} - -function desktopElfContract(architecture, machine) { - return Object.freeze({ - format: "elf", - architecture, - elf: Object.freeze({ - ...ELF64_LITTLE_ENDIAN, - machine, - maximumRequiredVersions: GNU_REQUIRED_VERSION_MAXIMUMS, - }), - }); -} - -function androidElfContract(architecture, machine) { - return Object.freeze({ - format: "elf", - architecture, - elf: Object.freeze({ - ...ELF64_LITTLE_ENDIAN, - machine, - androidApiLevel: 24, - forbiddenRequiredVersionFamilies: FORBIDDEN_ANDROID_VERSION_FAMILIES, - }), - }); -} - -export const PLATFORM_COMPATIBILITY_POLICY = Object.freeze({ - "macos-arm64": machoArm64Contract({ - carrier: "direct macOS carrier", - platforms: [["macos", version(11, 0, 0)]], - requiredPlatforms: ["macos"], - allowPlatformOverride: false, - }), - "linux-x64-gnu": desktopElfContract("x64", 62), - "linux-arm64-gnu": desktopElfContract("arm64", 183), - "android-arm64-v8a": androidElfContract("arm64", 183), - "android-x86_64": androidElfContract("x64", 62), - "ios-xcframework": machoArm64Contract({ - carrier: "iOS XCFramework tree", - platforms: [ - ["macos", version(14, 0, 0)], - ["ios", version(17, 0, 0)], - ["iosSimulator", version(17, 0, 0)], - ], - requiredPlatforms: ["macos", "ios", "iosSimulator"], - allowPlatformOverride: true, - }), - "windows-x64-msvc": Object.freeze({ - format: "pe", - architecture: "x64", - pe: Object.freeze({ machine: 0x8664, optionalHeaderMagic: 0x20b }), - windowsVcRuntime: Object.freeze({ - profiles: Object.freeze(["direct", "provider"]), - }), - }), -}); - -export function platformCompatibilityContract(target) { - return PLATFORM_COMPATIBILITY_POLICY[target]; -} - -export function platformCompatibilityTargets() { - return Object.freeze(Object.keys(PLATFORM_COMPATIBILITY_POLICY).sort()); -} - -function displayVersion(parts) { - const values = [...parts]; - while (values.length > 2 && values.at(-1) === 0) values.pop(); - return values.join("."); -} - -function sameVersion(left, right) { - return left.length === right.length && left.every((part, index) => part === right[index]); -} - -export const PUBLIC_PLATFORM_COMPATIBILITY_BLOCK = Object.freeze({ - start: "{/* BEGIN GENERATED PLATFORM COMPATIBILITY */}", - end: "{/* END GENERATED PLATFORM COMPATIBILITY */}", -}); - -/** - * Render the consumer-facing compatibility table from the same contract used - * to inspect release binaries. The public release reference keeps this block - * byte-for-byte synchronized in platform-compatibility-policy.test.mjs. - */ -export function renderPublicPlatformCompatibilityTable() { - const linuxX64 = PLATFORM_COMPATIBILITY_POLICY["linux-x64-gnu"].elf.maximumRequiredVersions; - const linuxArm64 = PLATFORM_COMPATIBILITY_POLICY["linux-arm64-gnu"].elf.maximumRequiredVersions; - for (const family of ["GLIBC", "GLIBCXX"]) { - if (!sameVersion(linuxX64[family], linuxArm64[family])) { - throw new Error(`published Linux targets disagree on the ${family} compatibility ceiling`); - } - } - const androidArm64 = PLATFORM_COMPATIBILITY_POLICY["android-arm64-v8a"].elf.androidApiLevel; - const androidX64 = PLATFORM_COMPATIBILITY_POLICY["android-x86_64"].elf.androidApiLevel; - if (androidArm64 !== androidX64) { - throw new Error("published Android targets disagree on the minimum API level"); - } - const directMacos = PLATFORM_COMPATIBILITY_POLICY["macos-arm64"].apple.platforms.macos; - const xcframework = PLATFORM_COMPATIBILITY_POLICY["ios-xcframework"].apple.platforms; - return [ - "| Published carrier | Enforced consumer compatibility contract |", - "| --- | --- |", - `| Linux x64/arm64 GNU | Required symbol versions do not exceed \`GLIBC_${displayVersion(linuxX64.GLIBC)}\` or \`GLIBCXX_${displayVersion(linuxX64.GLIBCXX)}\`. |`, - `| Direct macOS arm64 runtime | Minimum deployment target is macOS ${displayVersion(directMacos.maximumMinimumOs)}. |`, - `| Android \`arm64-v8a\` and \`x86_64\` | Minimum Android API level is ${androidArm64}; Android binaries must not require GLIBC/GLIBCXX symbol families. |`, - `| Apple XCFramework | Contains macOS arm64, iOS device arm64, and iOS Simulator arm64 slices; minimum targets are macOS ${displayVersion(xcframework.macos.maximumMinimumOs)}, iOS ${displayVersion(xcframework.ios.maximumMinimumOs)}, and iOS Simulator ${displayVersion(xcframework.iosSimulator.maximumMinimumOs)}. |`, - "| Windows x64 MSVC | Requires the x64 PE/COFF contract and the declared app-local Visual C++ runtime profile; Windows ARM64 is not published. |", - ].join("\n"); -} diff --git a/tools/release/platform-compatibility-policy.mts b/tools/release/platform-compatibility-policy.mts new file mode 100644 index 000000000..3223dd729 --- /dev/null +++ b/tools/release/platform-compatibility-policy.mts @@ -0,0 +1,153 @@ +const version = (...parts) => Object.freeze(parts); + +export const APPLE_PLATFORM_COMPATIBILITY = Object.freeze({ + macos: Object.freeze({ id: 1, name: 'macOS', cliName: 'macos' }), + ios: Object.freeze({ id: 2, name: 'iOS', cliName: 'ios' }), + iosSimulator: Object.freeze({ + id: 7, + name: 'iOS Simulator', + cliName: 'ios-simulator', + }), +}); + +const MACHO_ARM64 = Object.freeze({ cpuType: 0x0100000c, cpuSubtype: 0 }); +const ELF64_LITTLE_ENDIAN = Object.freeze({ bits: 64, endianness: 'little' }); +const GNU_REQUIRED_VERSION_MAXIMUMS = Object.freeze({ + GLIBC: version(2, 38, 0), + GLIBCXX: version(3, 4, 30), +}); +const FORBIDDEN_ANDROID_VERSION_FAMILIES = Object.freeze(['GLIBC', 'GLIBCXX']); + +function applePlatform(key, maximumMinimumOs) { + const platform = APPLE_PLATFORM_COMPATIBILITY[key]; + return Object.freeze({ ...platform, maximumMinimumOs }); +} + +function machoArm64Contract({ carrier, platforms, requiredPlatforms, allowPlatformOverride }) { + const allowed = Object.freeze( + Object.fromEntries( + platforms.map(([key, maximumMinimumOs]) => [key, applePlatform(key, maximumMinimumOs)]), + ), + ); + return Object.freeze({ + format: 'macho', + architecture: 'arm64', + macho: MACHO_ARM64, + apple: Object.freeze({ + carrier, + platforms: allowed, + requiredPlatforms: Object.freeze([...requiredPlatforms]), + allowPlatformOverride, + }), + }); +} + +function desktopElfContract(architecture, machine) { + return Object.freeze({ + format: 'elf', + architecture, + elf: Object.freeze({ + ...ELF64_LITTLE_ENDIAN, + machine, + maximumRequiredVersions: GNU_REQUIRED_VERSION_MAXIMUMS, + }), + }); +} + +function androidElfContract(architecture, machine) { + return Object.freeze({ + format: 'elf', + architecture, + elf: Object.freeze({ + ...ELF64_LITTLE_ENDIAN, + machine, + androidApiLevel: 24, + forbiddenRequiredVersionFamilies: FORBIDDEN_ANDROID_VERSION_FAMILIES, + }), + }); +} + +export const PLATFORM_COMPATIBILITY_POLICY = Object.freeze({ + 'macos-arm64': machoArm64Contract({ + carrier: 'direct macOS carrier', + platforms: [['macos', version(11, 0, 0)]], + requiredPlatforms: ['macos'], + allowPlatformOverride: false, + }), + 'linux-x64-gnu': desktopElfContract('x64', 62), + 'linux-arm64-gnu': desktopElfContract('arm64', 183), + 'android-arm64-v8a': androidElfContract('arm64', 183), + 'android-x86_64': androidElfContract('x64', 62), + 'ios-xcframework': machoArm64Contract({ + carrier: 'iOS XCFramework tree', + platforms: [ + ['macos', version(14, 0, 0)], + ['ios', version(17, 0, 0)], + ['iosSimulator', version(17, 0, 0)], + ], + requiredPlatforms: ['macos', 'ios', 'iosSimulator'], + allowPlatformOverride: true, + }), + 'windows-x64-msvc': Object.freeze({ + format: 'pe', + architecture: 'x64', + pe: Object.freeze({ machine: 0x8664, optionalHeaderMagic: 0x20b }), + windowsVcRuntime: Object.freeze({ + profiles: Object.freeze(['direct', 'provider']), + }), + }), +}); + +export function platformCompatibilityContract(target) { + return PLATFORM_COMPATIBILITY_POLICY[target]; +} + +export function platformCompatibilityTargets() { + return Object.freeze(Object.keys(PLATFORM_COMPATIBILITY_POLICY).sort()); +} + +function displayVersion(parts) { + const values = [...parts]; + while (values.length > 2 && values.at(-1) === 0) values.pop(); + return values.join('.'); +} + +function sameVersion(left, right) { + return left.length === right.length && left.every((part, index) => part === right[index]); +} + +export const PUBLIC_PLATFORM_COMPATIBILITY_BLOCK = Object.freeze({ + start: '{/* BEGIN GENERATED PLATFORM COMPATIBILITY */}', + end: '{/* END GENERATED PLATFORM COMPATIBILITY */}', +}); + +/** + * Render the consumer-facing compatibility table from the same contract used + * to inspect release binaries. The public release reference keeps this block + * byte-for-byte synchronized in platform-compatibility-policy.test.mts. + */ +export function renderPublicPlatformCompatibilityTable() { + const linuxX64 = PLATFORM_COMPATIBILITY_POLICY['linux-x64-gnu'].elf.maximumRequiredVersions; + const linuxArm64 = PLATFORM_COMPATIBILITY_POLICY['linux-arm64-gnu'].elf.maximumRequiredVersions; + for (const family of ['GLIBC', 'GLIBCXX']) { + if (!sameVersion(linuxX64[family], linuxArm64[family])) { + throw new Error(`published Linux targets disagree on the ${family} compatibility ceiling`); + } + } + const androidArm64 = PLATFORM_COMPATIBILITY_POLICY['android-arm64-v8a'].elf.androidApiLevel; + const androidX64 = PLATFORM_COMPATIBILITY_POLICY['android-x86_64'].elf.androidApiLevel; + if (androidArm64 !== androidX64) { + throw new Error('published Android targets disagree on the minimum API level'); + } + const directMacos = PLATFORM_COMPATIBILITY_POLICY['macos-arm64'].apple.platforms.macos; + const xcframework = PLATFORM_COMPATIBILITY_POLICY['ios-xcframework'].apple.platforms; + return [ + '| Published carrier | Enforced consumer compatibility contract |', + '| --- | --- |', + `| Linux x64/arm64 GNU | Required symbol versions do not exceed \`GLIBC_${displayVersion(linuxX64.GLIBC)}\` or \`GLIBCXX_${displayVersion(linuxX64.GLIBCXX)}\`. |`, + `| Direct macOS arm64 runtime | Minimum deployment target is macOS ${displayVersion(directMacos.maximumMinimumOs)}. |`, + `| Android \`arm64-v8a\` and \`x86_64\` | Minimum Android API level is ${androidArm64}; Android binaries must not require GLIBC/GLIBCXX symbol families. |`, + `| Apple XCFramework | Contains macOS arm64, iOS device arm64, and iOS Simulator arm64 slices; minimum targets are macOS ${displayVersion(xcframework.macos.maximumMinimumOs)}, iOS ${displayVersion(xcframework.ios.maximumMinimumOs)}, and iOS Simulator ${displayVersion(xcframework.iosSimulator.maximumMinimumOs)}. |`, + '| Windows x64 MSVC | Requires the x64 PE/COFF contract and the declared app-local Visual C++ runtime profile; Windows ARM64 is not published. |', + ].join('\n'); +} diff --git a/tools/release/platform-compatibility-policy.test.mjs b/tools/release/platform-compatibility-policy.test.mjs deleted file mode 100644 index 76c9e0e41..000000000 --- a/tools/release/platform-compatibility-policy.test.mjs +++ /dev/null @@ -1,100 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { PLATFORM_COMPATIBILITY_POLICY } from "./platform-compatibility-policy.mjs"; -import { - allArtifactTargets, - extensionArtifactTargets, -} from "./release-artifact-targets.mjs"; - -const BINARY_ARTIFACT_KINDS = new Set([ - "native-runtime", - "native-tools", - "broker-helper", - "node-direct-addon", - "wasix-napi-addon", -]); - -const artifacts = allArtifactTargets().filter((target) => - BINARY_ARTIFACT_KINDS.has(target.kind), -); -const extensions = extensionArtifactTargets({ family: "native" }); - -function validateCoverage(policy, artifacts, extensions) { - const uses = new Map(); - const addUse = (target, label, boundContract) => { - const contract = policy[target]; - if (contract === undefined) { - throw new Error(`${label} uses ${target} without a platform compatibility contract`); - } - if (boundContract !== contract) { - throw new Error(`${label} does not consume the authoritative ${target} contract`); - } - const labels = uses.get(target) ?? []; - labels.push(label); - uses.set(target, labels); - }; - - for (const artifact of artifacts) { - addUse(artifact.target, artifact.id, artifact.binaryCompatibility); - } - for (const extension of extensions) { - addUse( - extension.target, - `${extension.product}/${extension.family}/${extension.kind}`, - extension.binaryCompatibility, - ); - } - - const unused = Object.keys(policy).filter((target) => !uses.has(target)).sort(); - if (unused.length > 0) { - throw new Error(`platform compatibility contract(s) are not used by a carrier: ${unused.join(", ")}`); - } - return uses; -} - -describe("platform compatibility policy", () => { - test("is an exact bidirectional map of native, broker, Node, and extension carriers", () => { - const uses = validateCoverage( - PLATFORM_COMPATIBILITY_POLICY, - artifacts, - extensions, - ); - expect([...uses.keys()].sort()).toEqual(Object.keys(PLATFORM_COMPATIBILITY_POLICY).sort()); - }); - - test("rejects both an uncovered target and an unused contract", () => { - const missing = { ...PLATFORM_COMPATIBILITY_POLICY }; - delete missing["linux-x64-gnu"]; - expect(() => validateCoverage(missing, artifacts, extensions)).toThrow( - /uses linux-x64-gnu without a platform compatibility contract/u, - ); - - const unused = { - ...PLATFORM_COMPATIBILITY_POLICY, - "unused-test-target": PLATFORM_COMPATIBILITY_POLICY["linux-x64-gnu"], - }; - expect(() => validateCoverage(unused, artifacts, extensions)).toThrow( - /not used by a carrier: unused-test-target/u, - ); - }); - - test("owns the release compatibility floors and ABI ceilings", () => { - expect( - PLATFORM_COMPATIBILITY_POLICY["macos-arm64"].apple.platforms.macos.maximumMinimumOs, - ).toEqual([11, 0, 0]); - expect( - PLATFORM_COMPATIBILITY_POLICY["ios-xcframework"].apple.platforms.macos.maximumMinimumOs, - ).toEqual([14, 0, 0]); - expect( - PLATFORM_COMPATIBILITY_POLICY["ios-xcframework"].apple.platforms.ios.maximumMinimumOs, - ).toEqual([17, 0, 0]); - expect(PLATFORM_COMPATIBILITY_POLICY["android-arm64-v8a"].elf.androidApiLevel).toBe(24); - expect( - PLATFORM_COMPATIBILITY_POLICY["linux-x64-gnu"].elf.maximumRequiredVersions.GLIBC, - ).toEqual([2, 38, 0]); - expect( - PLATFORM_COMPATIBILITY_POLICY["linux-x64-gnu"].elf.maximumRequiredVersions.GLIBCXX, - ).toEqual([3, 4, 30]); - }); - -}); diff --git a/tools/release/platform-compatibility-policy.test.mts b/tools/release/platform-compatibility-policy.test.mts new file mode 100644 index 000000000..1bbef2916 --- /dev/null +++ b/tools/release/platform-compatibility-policy.test.mts @@ -0,0 +1,94 @@ +import { describe, expect, test } from 'bun:test'; + +import { PLATFORM_COMPATIBILITY_POLICY } from './platform-compatibility-policy.mts'; +import { allArtifactTargets, extensionArtifactTargets } from './release-artifact-targets.mts'; + +const BINARY_ARTIFACT_KINDS = new Set([ + 'native-runtime', + 'native-tools', + 'broker-helper', + 'node-direct-addon', + 'wasix-napi-addon', +]); + +const artifacts = allArtifactTargets().filter((target) => BINARY_ARTIFACT_KINDS.has(target.kind)); +const extensions = extensionArtifactTargets({ family: 'native' }); + +function validateCoverage(policy, artifacts, extensions) { + const uses = new Map(); + const addUse = (target, label, boundContract) => { + const contract = policy[target]; + if (contract === undefined) { + throw new Error(`${label} uses ${target} without a platform compatibility contract`); + } + if (boundContract !== contract) { + throw new Error(`${label} does not consume the authoritative ${target} contract`); + } + const labels = uses.get(target) ?? []; + labels.push(label); + uses.set(target, labels); + }; + + for (const artifact of artifacts) { + addUse(artifact.target, artifact.id, artifact.binaryCompatibility); + } + for (const extension of extensions) { + addUse( + extension.target, + `${extension.product}/${extension.family}/${extension.kind}`, + extension.binaryCompatibility, + ); + } + + const unused = Object.keys(policy) + .filter((target) => !uses.has(target)) + .sort(); + if (unused.length > 0) { + throw new Error( + `platform compatibility contract(s) are not used by a carrier: ${unused.join(', ')}`, + ); + } + return uses; +} + +describe('platform compatibility policy', () => { + test('is an exact bidirectional map of native, broker, Node, and extension carriers', () => { + const uses = validateCoverage(PLATFORM_COMPATIBILITY_POLICY, artifacts, extensions); + expect([...uses.keys()].sort()).toEqual(Object.keys(PLATFORM_COMPATIBILITY_POLICY).sort()); + }); + + test('rejects both an uncovered target and an unused contract', () => { + const missing = { ...PLATFORM_COMPATIBILITY_POLICY }; + delete missing['linux-x64-gnu']; + expect(() => validateCoverage(missing, artifacts, extensions)).toThrow( + /uses linux-x64-gnu without a platform compatibility contract/u, + ); + + const unused = { + ...PLATFORM_COMPATIBILITY_POLICY, + 'unused-test-target': PLATFORM_COMPATIBILITY_POLICY['linux-x64-gnu'], + }; + expect(() => validateCoverage(unused, artifacts, extensions)).toThrow( + /not used by a carrier: unused-test-target/u, + ); + }); + + test('owns the release compatibility floors and ABI ceilings', () => { + expect( + PLATFORM_COMPATIBILITY_POLICY['macos-arm64'].apple.platforms.macos.maximumMinimumOs, + ).toEqual([11, 0, 0]); + expect( + PLATFORM_COMPATIBILITY_POLICY['ios-xcframework'].apple.platforms.macos.maximumMinimumOs, + ).toEqual([14, 0, 0]); + expect( + PLATFORM_COMPATIBILITY_POLICY['ios-xcframework'].apple.platforms.ios.maximumMinimumOs, + ).toEqual([17, 0, 0]); + expect(PLATFORM_COMPATIBILITY_POLICY['android-arm64-v8a'].elf.androidApiLevel).toBe(24); + expect( + PLATFORM_COMPATIBILITY_POLICY['linux-x64-gnu'].elf.maximumRequiredVersions.GLIBC, + ).toEqual([2, 38, 0]); + expect( + PLATFORM_COMPATIBILITY_POLICY['linux-x64-gnu'].elf.maximumRequiredVersions.GLIBCXX, + ).toEqual([3, 4, 30]); + }); +}); diff --git a/tools/release/preflight-maven-central-bundle.mjs b/tools/release/preflight-maven-central-bundle.mjs deleted file mode 100644 index 95ab15e16..000000000 --- a/tools/release/preflight-maven-central-bundle.mjs +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env bun -import { mkdtempSync, rmSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { - createGpgSigner, - prepareFrozenMavenBundle, -} from "./frozen-maven-publish.mjs"; -import { - assertPublicationLockSource, - loadPublicationLock, - lockedCarriers, -} from "./publication-lock.mjs"; - -function error(message) { - return new Error(`preflight-maven-central-bundle: ${message}`); -} -function requiredValue(value, context) { - if (typeof value !== "string" || value.trim().length === 0) { - throw error(`${context} is required`); - } - return value.trim(); -} - -export function parseMavenBundlePreflightArgs(argv) { - const values = new Map(); - for (let index = 0; index < argv.length; index += 1) { - const flag = argv[index]; - if (!["--publication-lock", "--products-json", "--release-commit"].includes(flag)) { - throw error(`unknown argument ${flag}`); - } - if (values.has(flag)) throw error(`${flag} may be supplied only once`); - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) throw error(`${flag} requires a value`); - values.set(flag, value); - index += 1; - } - const publicationLock = requiredValue(values.get("--publication-lock"), "--publication-lock"); - const releaseCommit = requiredValue(values.get("--release-commit"), "--release-commit"); - if (!/^[0-9a-f]{40}$/iu.test(releaseCommit)) { - throw error("--release-commit must be a full 40-character Git SHA"); - } - let products; - try { - products = JSON.parse(requiredValue(values.get("--products-json"), "--products-json")); - } catch (cause) { - throw error(`--products-json must be valid JSON: ${cause.message}`); - } - if (!Array.isArray(products) || products.length === 0 || products.some((product) => typeof product !== "string" || product.length === 0)) { - throw error("--products-json must be a nonempty JSON array of product IDs"); - } - if (new Set(products).size !== products.length) { - throw error("--products-json must not contain duplicate product IDs"); - } - return { products, publicationLock: path.resolve(publicationLock), releaseCommit: releaseCommit.toLowerCase() }; -} - -export function preflightMavenCentralBundle({ lock, products, releaseCommit, outputRoot, signFile }) { - assertPublicationLockSource(lock, releaseCommit); - const carriers = lockedCarriers(lock, { products, ecosystem: "maven" }); - if (carriers.length === 0) { - throw error(`selected products contain no frozen Maven carriers: ${products.join(",")}`); - } - return prepareFrozenMavenBundle({ lock, products, outputRoot, signFile }); -} - -function env(name) { - return requiredValue(process.env[name], name); -} - -if (import.meta.main) { - let temporaryRoot; - try { - const args = parseMavenBundlePreflightArgs(process.argv.slice(2)); - const lock = loadPublicationLock(args.publicationLock); - const base = process.env.RUNNER_TEMP?.trim() || tmpdir(); - temporaryRoot = mkdtempSync(path.join(base, "oliphaunt-maven-bundle-preflight-")); - const signFile = createGpgSigner({ - privateKey: env("ORG_GRADLE_PROJECT_signingInMemoryKey"), - keyId: env("ORG_GRADLE_PROJECT_signingInMemoryKeyId"), - passphrase: env("ORG_GRADLE_PROJECT_signingInMemoryKeyPassword"), - home: path.join(temporaryRoot, "gpg"), - }); - const result = preflightMavenCentralBundle({ - lock, - products: args.products, - releaseCommit: args.releaseCommit, - outputRoot: path.join(temporaryRoot, "bundle"), - signFile, - }); - console.log(`preflighted ${result.carriers.length} exact Maven carriers in a ${result.bundleSize}-byte Central bundle before release mutation`); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exitCode = 1; - } finally { - if (temporaryRoot !== undefined) rmSync(temporaryRoot, { recursive: true, force: true }); - } -} diff --git a/tools/release/preflight-maven-central-bundle.mts b/tools/release/preflight-maven-central-bundle.mts new file mode 100644 index 000000000..4d62a2fc8 --- /dev/null +++ b/tools/release/preflight-maven-central-bundle.mts @@ -0,0 +1,95 @@ +#!/usr/bin/env bun +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +import { recordPreparedMavenBundle, stageFrozenMavenBundle } from './frozen-maven-publish.mts'; +import { loadPublicationLock } from './publication-lock.mts'; + +function error(message) { + return new Error(`preflight-maven-central-bundle: ${message}`); +} +function requiredValue(value, context) { + if (typeof value !== 'string' || value.trim().length === 0) { + throw error(`${context} is required`); + } + return value.trim(); +} + +export function parseMavenBundlePreflightArgs(argv) { + const values = new Map(); + for (let index = 0; index < argv.length; index += 1) { + const flag = argv[index]; + if (!['--publication-lock', '--products-json', '--release-commit'].includes(flag)) { + throw error(`unknown argument ${flag}`); + } + if (values.has(flag)) throw error(`${flag} may be supplied only once`); + const value = argv[index + 1]; + if (value === undefined || value.startsWith('--')) throw error(`${flag} requires a value`); + values.set(flag, value); + index += 1; + } + const publicationLock = requiredValue(values.get('--publication-lock'), '--publication-lock'); + const releaseCommit = requiredValue(values.get('--release-commit'), '--release-commit'); + if (!/^[0-9a-f]{40}$/iu.test(releaseCommit)) { + throw error('--release-commit must be a full 40-character Git SHA'); + } + let products; + try { + products = JSON.parse(requiredValue(values.get('--products-json'), '--products-json')); + } catch (cause) { + throw error(`--products-json must be valid JSON: ${cause.message}`); + } + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string' || product.length === 0) + ) { + throw error('--products-json must be a nonempty JSON array of product IDs'); + } + if (new Set(products).size !== products.length) { + throw error('--products-json must not contain duplicate product IDs'); + } + return { + products, + publicationLock: path.resolve(publicationLock), + releaseCommit: releaseCommit.toLowerCase(), + }; +} + +if (import.meta.main) { + try { + const [phase, directory, ...argv] = process.argv.slice(2); + const contextPath = path.join(directory, 'context.json'); + if (phase === '--stage') { + const args = parseMavenBundlePreflightArgs(argv); + const lock = loadPublicationLock(args.publicationLock); + const prepared = stageFrozenMavenBundle({ + lock, + products: args.products, + outputRoot: directory, + }); + writeFileSync( + contextPath, + JSON.stringify({ + prepared, + lockDigest: lock.lockDigest, + source: lock.source, + releaseCommit: args.releaseCommit, + }), + ); + } else if (phase === '--record') { + const { prepared, lockDigest } = JSON.parse(readFileSync(contextPath, 'utf8')); + const receipt = recordPreparedMavenBundle(prepared, lockDigest); + console.log( + 'Prepared ' + + receipt.carriers.length + + ' exact Maven carriers in a ' + + receipt.size + + '-byte signed bundle', + ); + } else throw error('unknown Maven bundle data phase'); + } catch (cause) { + console.error(cause.message); + process.exitCode = 1; + } +} diff --git a/tools/release/preflight-maven-central-bundle.sh b/tools/release/preflight-maven-central-bundle.sh new file mode 100644 index 000000000..a8cc356fc --- /dev/null +++ b/tools/release/preflight-maven-central-bundle.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$root" +: "${ORG_GRADLE_PROJECT_signingInMemoryKey:?Maven signing key is required}" +: "${ORG_GRADLE_PROJECT_signingInMemoryKeyId:?Maven signing key ID is required}" +: "${ORG_GRADLE_PROJECT_signingInMemoryKeyPassword:?Maven signing passphrase is required}" +key_id="$(bash tools/dev/bun.sh tools/release/verify-maven-signing-readiness.mts --key-id "$ORG_GRADLE_PROJECT_signingInMemoryKeyId")" +output="$root/target/release/maven-central/normal-registry-plan" +mkdir -p "$output" +# --sign-staged is also usable locally after stageFrozenMavenBundle. Publication +# still requires a matching lock digest, carrier set, size and bundle hash. +if [[ "${1:-}" == --sign-staged ]]; then + [[ "$#" == 2 ]] || exit 2 + output="$(cd "$2" && pwd)" +else + bash tools/dev/bun.sh tools/release/preflight-maven-central-bundle.mts --stage "$output" "$@" + release_commit="$(jq -r .releaseCommit "$output/context.json")" + commit="$(git rev-parse --verify --end-of-options "$release_commit^{commit}")" + tree="$(git rev-parse "$commit^{tree}")" + [[ "$commit" == "$(jq -r .source.commit "$output/context.json")" && "$tree" == "$(jq -r .source.tree "$output/context.json")" ]] || { echo 'Maven source commit/tree differs from the frozen lock' >&2; exit 1; } +fi +rm -f "$output/prepared.json" "$output/central-bundle.zip" +work="$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/oliphaunt-maven-bundle-signing.XXXXXX")" +trap 'gpgconf --homedir "$work" --kill all >/dev/null 2>&1 || true; rm -rf "$work"' EXIT +chmod 700 "$work" +printf '%s' "$ORG_GRADLE_PROJECT_signingInMemoryKey" | gpg --batch --homedir "$work" --import +jq -j '.prepared.payloads[].staged + "\u0000"' "$output/context.json" > "$work/files" +while IFS= read -r -d '' file; do + printf '%s\n' "$ORG_GRADLE_PROJECT_signingInMemoryKeyPassword" | \ + gpg --batch --yes --no-tty --pinentry-mode loopback --passphrase-fd 0 --homedir "$work" \ + --local-user "$key_id" --armor --detach-sign --output "$file.asc" "$file" + gpg --batch --no-auto-key-retrieve --homedir "$work" --status-fd 1 --verify "$file.asc" "$file" > "$work/status" + bash tools/dev/bun.sh tools/release/verify-maven-signing-readiness.mts --signature "$work/status" "$key_id" >/dev/null +done < "$work/files" +(cd "$output/layout" && zip -q -X -r "$output/central-bundle.zip" .) +bash tools/dev/bun.sh tools/release/preflight-maven-central-bundle.mts --record "$output" diff --git a/tools/release/preflight-maven-central-bundle.test.mjs b/tools/release/preflight-maven-central-bundle.test.mjs deleted file mode 100644 index 236924d81..000000000 --- a/tools/release/preflight-maven-central-bundle.test.mjs +++ /dev/null @@ -1,32 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { parseMavenBundlePreflightArgs } from "./preflight-maven-central-bundle.mjs"; - -const sha = "A".repeat(40); - -describe("preflight Maven Central bundle CLI", () => { - test("requires exact lock, product, and release identities", () => { - expect(parseMavenBundlePreflightArgs([ - "--publication-lock", "target/release/publication-lock.json", - "--products-json", '["oliphaunt-kotlin"]', - "--release-commit", sha, - ])).toEqual({ - products: ["oliphaunt-kotlin"], - publicationLock: `${process.cwd()}/target/release/publication-lock.json`, - releaseCommit: sha.toLowerCase(), - }); - }); - - test("rejects unknown, duplicate, missing, malformed, and ambiguous inputs", () => { - for (const args of [ - [], - ["--unknown", "value"], - ["--publication-lock", "a", "--publication-lock", "b", "--products-json", '["p"]', "--release-commit", sha], - ["--publication-lock", "a", "--products-json", "{}", "--release-commit", sha], - ["--publication-lock", "a", "--products-json", '["p","p"]', "--release-commit", sha], - ["--publication-lock", "a", "--products-json", '["p"]', "--release-commit", "short"], - ]) { - expect(() => parseMavenBundlePreflightArgs(args)).toThrow(); - } - }); -}); diff --git a/tools/release/preflight-maven-central-bundle.test.mts b/tools/release/preflight-maven-central-bundle.test.mts new file mode 100644 index 000000000..4957ade61 --- /dev/null +++ b/tools/release/preflight-maven-central-bundle.test.mts @@ -0,0 +1,46 @@ +import { describe, expect, test } from 'bun:test'; + +import { parseMavenBundlePreflightArgs } from './preflight-maven-central-bundle.mts'; + +const sha = 'A'.repeat(40); + +describe('preflight Maven Central bundle CLI', () => { + test('requires exact lock, product, and release identities', () => { + expect( + parseMavenBundlePreflightArgs([ + '--publication-lock', + 'target/release/publication-lock.json', + '--products-json', + '["oliphaunt-kotlin"]', + '--release-commit', + sha, + ]), + ).toEqual({ + products: ['oliphaunt-kotlin'], + publicationLock: `${process.cwd()}/target/release/publication-lock.json`, + releaseCommit: sha.toLowerCase(), + }); + }); + + test('rejects unknown, duplicate, missing, malformed, and ambiguous inputs', () => { + for (const args of [ + [], + ['--unknown', 'value'], + [ + '--publication-lock', + 'a', + '--publication-lock', + 'b', + '--products-json', + '["p"]', + '--release-commit', + sha, + ], + ['--publication-lock', 'a', '--products-json', '{}', '--release-commit', sha], + ['--publication-lock', 'a', '--products-json', '["p","p"]', '--release-commit', sha], + ['--publication-lock', 'a', '--products-json', '["p"]', '--release-commit', 'short'], + ]) { + expect(() => parseMavenBundlePreflightArgs(args)).toThrow(); + } + }); +}); diff --git a/tools/release/preflight-swiftpm-source-tag.mjs b/tools/release/preflight-swiftpm-source-tag.mjs deleted file mode 100644 index c3b7369f5..000000000 --- a/tools/release/preflight-swiftpm-source-tag.mjs +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bun -import path from "node:path"; - -import { - assertPublicationLockSource, - loadPublicationLock, - lockedProductArtifactPaths, -} from "./publication-lock.mjs"; -import { ensureTag } from "./publish_swiftpm_source_tag.mjs"; - -function error(message) { - return new Error(`preflight-swiftpm-source-tag: ${message}`); -} -export function parseSwiftpmPreflightArgs(argv) { - const values = new Map(); - for (let index = 0; index < argv.length; index += 1) { - const flag = argv[index]; - if (!["--publication-lock", "--release-commit"].includes(flag)) throw error(`unknown argument ${flag}`); - if (values.has(flag)) throw error(`${flag} may be supplied only once`); - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) throw error(`${flag} requires a value`); - values.set(flag, value); - index += 1; - } - const publicationLock = values.get("--publication-lock")?.trim() ?? ""; - const releaseCommit = values.get("--release-commit")?.trim() ?? ""; - if (publicationLock.length === 0) throw error("--publication-lock is required"); - if (!/^[0-9a-f]{40}$/iu.test(releaseCommit)) { - throw error("--release-commit must be a full 40-character Git SHA"); - } - return { publicationLock: path.resolve(publicationLock), releaseCommit: releaseCommit.toLowerCase() }; -} - -export async function preflightLockedSwiftpmSourceTag({ lock, releaseCommit, ensureTagImpl = ensureTag }) { - assertPublicationLockSource(lock, releaseCommit); - const inputs = lockedProductArtifactPaths(lock, "oliphaunt-swift"); - const manifests = inputs.filter(({ artifact, type }) => artifact.kind === "swiftpm-release-manifest" && type === "file"); - const trees = inputs.filter(({ artifact, type }) => artifact.kind === "swiftpm-release-tree" && type === "directory"); - if (manifests.length !== 1 || trees.length !== 1) { - throw error(`publication lock must contain exactly one SwiftPM release manifest and tree, found ${manifests.length}/${trees.length}`); - } - return await ensureTagImpl({ - target: releaseCommit, - manifest: manifests[0].path, - includeTrees: [trees[0].path], - preflight: true, - }); -} - -if (import.meta.main) { - try { - const args = parseSwiftpmPreflightArgs(process.argv.slice(2)); - await preflightLockedSwiftpmSourceTag({ - lock: loadPublicationLock(args.publicationLock), - releaseCommit: args.releaseCommit, - }); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exitCode = 1; - } -} diff --git a/tools/release/preflight-swiftpm-source-tag.test.mjs b/tools/release/preflight-swiftpm-source-tag.test.mjs deleted file mode 100644 index b9307cba8..000000000 --- a/tools/release/preflight-swiftpm-source-tag.test.mjs +++ /dev/null @@ -1,20 +0,0 @@ -import { expect, test } from "bun:test"; - -import { parseSwiftpmPreflightArgs } from "./preflight-swiftpm-source-tag.mjs"; - -test("requires one exact lock and release commit for SwiftPM preflight", () => { - const sha = "A".repeat(40); - expect(parseSwiftpmPreflightArgs([ - "--publication-lock", "target/release/publication-lock.json", - "--release-commit", sha, - ])).toEqual({ - publicationLock: `${process.cwd()}/target/release/publication-lock.json`, - releaseCommit: sha.toLowerCase(), - }); - for (const argv of [ - [], - ["--unknown", "x"], - ["--publication-lock", "a", "--publication-lock", "b", "--release-commit", sha], - ["--publication-lock", "a", "--release-commit", "short"], - ]) expect(() => parseSwiftpmPreflightArgs(argv)).toThrow(); -}); diff --git a/tools/release/prepare-release-candidate.mts b/tools/release/prepare-release-candidate.mts new file mode 100644 index 000000000..f0a215eb5 --- /dev/null +++ b/tools/release/prepare-release-candidate.mts @@ -0,0 +1,142 @@ +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import path from 'node:path'; +import { GitHub, Manifest, registerChangelogNotes } from 'release-please'; +import { ManifestPlugin } from 'release-please/build/src/plugin.js'; +import { DefaultChangelogNotes } from 'release-please/build/src/changelog-notes/default.js'; +import { mergeUpdates } from 'release-please/build/src/updaters/composite.js'; +import { buildPlan, loadGraph } from './release-graph.mts'; + +// Only ownership is supplied here. Release Please remains responsible for +// conventional commits, version policy, changelog text and ecosystem updaters. +export function includeOwnedSourceCommits(manifest, github, graph) { + const observed = []; + const iterate = github.mergeCommitIterator.bind(github); + github.mergeCommitIterator = async function* (...args) { + for await (const commit of iterate(...args)) { + observed.push(commit); + yield commit; + } + }; + manifest.plugins.unshift( + new (class extends ManifestPlugin { + async preconfigure(strategies, commitsByPath, releasesByPath) { + const owners = new Map( + observed.map((commit) => [ + commit.sha, + new Set( + buildPlan(graph, commit.files ?? [], 'prepare-release-candidate').releaseProducts, + ), + ]), + ); + for (const [ownerPath, config] of Object.entries(manifest.repositoryConfig)) { + const boundary = releasesByPath[ownerPath]?.sha; + const selected = new Map( + (commitsByPath[ownerPath] ?? []).map((commit) => [commit.sha, commit]), + ); + for (const commit of observed) { + if (commit.sha === boundary) break; + if (owners.get(commit.sha).has(config.component)) selected.set(commit.sha, commit); + } + commitsByPath[ownerPath] = observed.filter((commit) => selected.has(commit.sha)); + } + return strategies; + } + })(github, 'main', manifest.repositoryConfig), + ); +} + +export function useSourceDate(sourceDate) { + if (!/^\d{4}-\d{2}-\d{2}$/u.test(sourceDate)) throw new Error('source date must be YYYY-MM-DD'); + const require = createRequire(import.meta.url); + const releaseRequire = createRequire(require.resolve('release-please')); + const header = readFileSync( + releaseRequire.resolve('conventional-changelog-conventionalcommits/templates/header.hbs'), + 'utf8', + ); + registerChangelogNotes( + 'default', + (options) => + new DefaultChangelogNotes({ + ...options, + headerPartial: (options.headerPartial ?? header).replaceAll('{{date}}', sourceDate), + }), + ); +} + +export function applyCandidate(root, candidate) { + const changed = []; + for (const update of mergeUpdates(candidate.updates)) { + const destination = path.resolve(root, update.path); + if (!destination.startsWith(`${path.resolve(root)}${path.sep}`)) + throw new Error(`unsafe release update path ${update.path}`); + const before = existsSync(destination) ? readFileSync(destination, 'utf8') : undefined; + if (before === undefined && !update.createIfMissing) continue; + const after = update.updater.updateContent(before); + if (after && after !== before) { + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, after); + changed.push(update.path); + } + } + return changed; +} + +async function main() { + const root = process.cwd(); + const destination = process.argv[2]; + const sha = process.env.RELEASE_SOURCE_SHA; + const repository = process.env.GITHUB_REPOSITORY; + if (!destination || !/^[0-9a-f]{40}$/u.test(sha ?? '') || repository !== 'f0rr0/oliphaunt') + throw new Error('candidate generation requires an exact canonical source and output directory'); + useSourceDate(process.env.RELEASE_SOURCE_DATE); + const [owner, repo] = repository.split('/'); + const github = await GitHub.create({ + owner, + repo, + defaultBranch: 'main', + token: process.env.GH_TOKEN, + fetch: (url, options = {}) => + fetch(url, { + ...options, + signal: options.signal + ? AbortSignal.any([options.signal, AbortSignal.timeout(30_000)]) + : AbortSignal.timeout(30_000), + }), + }); + // File reads use the exact source even if main advances during API pagination. + const getFile = github.getFileContentsOnBranch.bind(github); + github.getFileContentsOnBranch = (file) => getFile(file, sha); + const iterate = github.mergeCommitIterator.bind(github); + github.mergeCommitIterator = async function* (...args) { + let first = true; + for await (const commit of iterate(...args)) { + if (first && commit.sha !== sha) + throw new Error('main changed before Release Please history capture'); + first = false; + yield commit; + } + if (first) throw new Error('Release Please returned no source history'); + }; + const manifest = await Manifest.fromManifest(github, 'main'); + includeOwnedSourceCommits(manifest, github, loadGraph('prepare-release-candidate')); + const candidates = await manifest.buildPullRequests(); + if (candidates.length > 1) throw new Error('expected one grouped Release Please candidate'); + mkdirSync(destination, { recursive: true }); + if (!candidates.length) { + writeFileSync(path.join(destination, 'required'), 'false\n'); + return; + } + const candidate = candidates[0]; + if ( + candidate.headRefName !== 'release-please--branches--main' || + candidate.title.toString() !== 'chore(release): prepare main releases' + ) + throw new Error('unexpected Release Please branch/title'); + applyCandidate(root, candidate); + writeFileSync(path.join(destination, 'required'), 'true\n'); + writeFileSync(path.join(destination, 'title'), `${candidate.title.toString()}\n`); + writeFileSync(path.join(destination, 'body.md'), `${candidate.body.toString()}\n`); +} + +if (import.meta.main) await main(); diff --git a/tools/release/prepare-release-candidate.test.mts b/tools/release/prepare-release-candidate.test.mts new file mode 100644 index 000000000..b5bef3f76 --- /dev/null +++ b/tools/release/prepare-release-candidate.test.mts @@ -0,0 +1,231 @@ +import { test, expect } from 'bun:test'; +import { Manifest } from 'release-please'; +import { Version } from 'release-please/build/src/version.js'; +import { loadGraph } from './release-graph.mts'; +import { + includeOwnedSourceCommits, + useSourceDate, + applyCandidate, +} from './prepare-release-candidate.mts'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import os from 'node:os'; + +const graph = loadGraph('prepare-release-candidate.test'); +const native = 'src/runtimes/liboliphaunt-native'; +const wasix = 'src/runtimes/liboliphaunt-wasix'; +const shared = 'src/extensions/contrib/postgres18.toml'; +const first = 'a'.repeat(40); +const second = 'b'.repeat(40); +const head = 'c'.repeat(40); + +async function generate(commits, baselines = { [native]: first, [wasix]: first }) { + useSourceDate('2026-09-11'); + const config = Object.fromEntries( + [native, wasix].map((owner) => [ + owner, + { + releaseType: 'simple', + component: owner.split('/').at(-1), + packageName: owner.split('/').at(-1), + versionFile: 'VERSION', + changelogPath: 'CHANGELOG.md', + includeVInTag: true, + tagSeparator: '-', + bumpMinorPreMajor: true, + bumpPatchForMinorPreMajor: true, + }, + ]), + ); + const github = { + repository: { owner: 'f0rr0', repo: 'oliphaunt', defaultBranch: 'main' }, + async *releaseIterator() { + for (const owner of [native, wasix]) + yield { + tagName: `${config[owner].component}-v0.2.0`, + sha: baselines[owner], + notes: 'Previous release', + }; + }, + async *mergeCommitIterator() { + yield* commits; + }, + async getFileContentsOnBranch(file) { + const parsedContent = file.endsWith('/VERSION') + ? '0.2.0\n' + : '# Changelog\n\n## 0.2.0\n\nPrevious release\n'; + return { parsedContent, content: Buffer.from(parsedContent).toString('base64') }; + }, + async getFileContents(file) { + return this.getFileContentsOnBranch(file); + }, + }; + const manifest = new Manifest( + github, + 'main', + config, + { + [native]: Version.parse('0.2.0'), + [wasix]: Version.parse('0.2.0'), + }, + { + separatePullRequests: false, + groupPullRequestTitlePattern: 'chore(release): prepare ${branch} releases', + }, + ); + includeOwnedSourceCommits(manifest, github, graph); + return manifest.buildPullRequests(); +} + +test('Release Please alone versions and describes shared shipped changes exactly once', async () => { + const commits = [ + { + sha: head, + message: 'feat: improve shared extension behavior', + files: [shared, `${native}/src/liboliphaunt.c`], + }, + { + sha: first, + message: 'chore(release): previous releases', + files: [`${native}/VERSION`, `${wasix}/VERSION`], + }, + ]; + const [candidate] = await generate(commits); + expect(candidate.headRefName).toBe('release-please--branches--main'); + expect(candidate.title.toString()).toBe('chore(release): prepare main releases'); + const versions = candidate.updates.filter((update) => update.path.endsWith('/VERSION')); + expect( + versions.map((update) => [update.path, update.updater.updateContent('0.2.0\n').trim()]).sort(), + ).toEqual([ + [`${native}/VERSION`, '0.2.1'], + [`${wasix}/VERSION`, '0.2.1'], + ]); + for (const update of candidate.updates.filter((update) => + update.path.endsWith('/CHANGELOG.md'), + )) { + const text = update.updater.updateContent('# Changelog\n'); + expect(text.match(/improve shared extension behavior/gu)).toHaveLength(1); + expect(text).toContain('2026-09-11'); + } + const [repeat] = await generate(commits); + expect(repeat.body.toString()).toBe(candidate.body.toString()); + const render = (update) => [ + update.path, + update.updater.updateContent( + update.path === '.release-please-manifest.json' + ? JSON.stringify({ [native]: '0.2.0', [wasix]: '0.2.0' }) + : update.path.endsWith('/VERSION') + ? '0.2.0\n' + : '# Changelog\n', + ), + ]; + expect(repeat.updates.map(render)).toEqual(candidate.updates.map(render)); +}); + +test('shared source qualification respects each owner release boundary and ignores nonrelease prose', async () => { + const candidates = await generate( + [ + { sha: head, message: 'docs: clarify maintenance instructions', files: [shared] }, + { + sha: second, + message: 'chore(release): WASIX already includes this change', + files: [`${wasix}/VERSION`], + }, + { sha: 'd'.repeat(40), message: 'fix: repair shared extension behavior', files: [shared] }, + { sha: first, message: 'chore(release): native baseline', files: [`${native}/VERSION`] }, + ], + { [native]: first, [wasix]: second }, + ); + expect(candidates).toHaveLength(1); + expect( + candidates[0].updates + .filter((update) => update.path.endsWith('/VERSION')) + .map((update) => update.path), + ).toEqual([`${native}/VERSION`]); +}); + +test('actual Rust, npm, Swift and Gradle strategy updates apply to one local candidate', async () => { + const root = path.resolve(import.meta.dir, '../..'); + const selected = ['src/sdks/rust/sdk', 'src/sdks/ts/sdk', 'src/sdks/swift', 'src/sdks/kotlin']; + const config = JSON.parse(readFileSync(path.join(root, 'release-please-config.json'), 'utf8')); + const versions = JSON.parse( + readFileSync(path.join(root, '.release-please-manifest.json'), 'utf8'), + ); + config.packages = Object.fromEntries(selected.map((owner) => [owner, config.packages[owner]])); + const current = Object.fromEntries(selected.map((owner) => [owner, versions[owner]])); + const github = { + repository: { owner: 'f0rr0', repo: 'oliphaunt', defaultBranch: 'main' }, + async *releaseIterator() { + for (const owner of selected) + yield { + tagName: `${config.packages[owner].component}-v${versions[owner]}`, + sha: first, + notes: 'Existing release', + }; + }, + async *mergeCommitIterator() { + yield { + sha: head, + message: 'fix: correct the selected SDK behavior', + files: selected.map((owner) => `${owner}/src/implementation`), + }; + yield { sha: first, message: 'chore(release): previous versions', files: [] }; + }, + async getFileContentsOnBranch(file) { + const local = path.join(root, file); + const parsedContent = + file === 'release-please-config.json' + ? JSON.stringify(config) + : file === '.release-please-manifest.json' + ? JSON.stringify(current) + : existsSync(local) + ? readFileSync(local, 'utf8') + : undefined; + if (parsedContent === undefined) + throw Object.assign(new Error(`missing ${file}`), { status: 404 }); + return { parsedContent, content: Buffer.from(parsedContent).toString('base64') }; + }, + async getFileContents(file) { + return this.getFileContentsOnBranch(file); + }, + async getFileJson(file) { + return JSON.parse((await this.getFileContentsOnBranch(file)).parsedContent); + }, + }; + const manifest = await Manifest.fromManifest(github, 'main'); + useSourceDate('2026-09-11'); + includeOwnedSourceCommits(manifest, github, graph); + const [candidate] = await manifest.buildPullRequests(); + const scratch = mkdtempSync(path.join(os.tmpdir(), 'release-please-ecosystems-')); + try { + for (const update of candidate.updates) { + const input = path.join(root, update.path); + if (existsSync(input)) { + const destination = path.join(scratch, update.path); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, readFileSync(input)); + } + } + applyCandidate(scratch, candidate); + const after = JSON.parse( + readFileSync(path.join(scratch, '.release-please-manifest.json'), 'utf8'), + ); + const read = (file) => readFileSync(path.join(scratch, file), 'utf8'); + expect(Bun.TOML.parse(read('src/sdks/rust/sdk/Cargo.toml')).package.version).toBe( + after['src/sdks/rust/sdk'], + ); + expect( + Bun.TOML.parse(read('src/sdks/rust/sdk/crates/oliphaunt-build/Cargo.toml')).package.version, + ).toBe(after['src/sdks/rust/sdk']); + expect(JSON.parse(read('src/sdks/ts/sdk/package.json')).version).toBe(after['src/sdks/ts/sdk']); + expect(read('src/sdks/swift/VERSION').trim()).toBe(after['src/sdks/swift']); + expect(read('src/sdks/kotlin/VERSION').trim()).toBe(after['src/sdks/kotlin']); + expect(read('src/sdks/kotlin/gradle.properties')).toContain( + `VERSION_NAME=${after['src/sdks/kotlin']}`, + ); + expect(existsSync(path.join(scratch, 'src/sdks/rust/sdk/Cargo.lock'))).toBe(false); + for (const owner of selected) expect(after[owner]).not.toBe(versions[owner]); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); diff --git a/tools/release/prepare-release-pr.sh b/tools/release/prepare-release-pr.sh new file mode 100644 index 000000000..a6c557248 --- /dev/null +++ b/tools/release/prepare-release-pr.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(git rev-parse --show-toplevel)" +cd "$root" +[[ $# == 1 ]] || { + echo 'usage: prepare-release-pr.sh OUTPUT_DIRECTORY' >&2 + exit 2 +} +[[ -z "$(git status --porcelain --untracked-files=all)" ]] || { + echo 'release preparation requires a clean source checkout' >&2 + exit 1 +} +export RELEASE_SOURCE_SHA RELEASE_SOURCE_DATE +RELEASE_SOURCE_SHA="$(git rev-parse HEAD)" +RELEASE_SOURCE_DATE="$(git show -s --format=%cs HEAD)" +bash tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mts assert-clean --base main +bash tools/ci/with-projects.sh tools/release/prepare-release-candidate.mts "$1" +if [[ -n "${GITHUB_OUTPUT:-}" ]]; then + printf 'required=%s\n' "$(cat "$1/required")" >>"$GITHUB_OUTPUT" +fi diff --git a/tools/release/prepare-rust-release-source.mjs b/tools/release/prepare-rust-release-source.mjs deleted file mode 100644 index bc8fc16cf..000000000 --- a/tools/release/prepare-rust-release-source.mjs +++ /dev/null @@ -1,235 +0,0 @@ -#!/usr/bin/env bun -import { cpSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import path from "node:path"; -import { stageRustPackageSource } from "../../src/sdks/rust/tools/package-source.mjs"; -import { - allArtifactTargets, - compareText, - currentProductVersionSync, - registryPackageRows, -} from "./release-artifact-targets.mjs"; -import { productCompatibilityVersion } from "./release-graph.mjs"; -import { packagedCargoManifestText } from "./cargo-source-package.mjs"; -import { ROOT } from "./release-cli-utils.mjs"; -import { - assertReleaseNoticesInDirectory, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { - assertSameNativeTargetSet, - renderUnsupportedNativeTargetGuard, - rustNativeTargetCfg, -} from "./rust-native-targets.mjs"; - -const TOOL = "prepare-rust-release-source.mjs"; -const LIBOLIPHAUNT_NATIVE_PRODUCT = "liboliphaunt-native"; -const BROKER_PRODUCT = "oliphaunt-broker"; -const RUST_PRODUCT = "oliphaunt-rust"; -const DEFAULT_STAGE_DIR = path.join(ROOT, "target/release/cargo-package-sources/oliphaunt"); -const DEFAULT_BUILD_STAGE_DIR = path.join(ROOT, "target/release/cargo-package-sources/oliphaunt-build"); -const SOURCE_NOTICE_OPTIONS = Object.freeze({ profile: "source-sdk" }); - -function fail(message) { - console.error(`${TOOL}: ${message}`); - process.exit(2); -} - -function rel(file) { - return path.relative(ROOT, file).split(path.sep).join("/"); -} - -function liboliphauntCargoPackageName(targetId, packageBase = LIBOLIPHAUNT_NATIVE_PRODUCT) { - return `${packageBase}-${targetId}`; -} - -function brokerCargoPackageName(targetId) { - return `${BROKER_PRODUCT}-${targetId}`; -} - -function packageSection(text) { - const parts = text.split("[package]"); - if (parts.length < 2) { - fail("generated oliphaunt release source is missing [package]"); - } - return parts[1].split("\n[", 1)[0]; -} - -function artifactTargets({ product, kind, surface }) { - return allArtifactTargets({ product, kind, surface }, TOOL); -} - -function nativeSdkArtifactTargets() { - const nativeTargets = artifactTargets({ - product: LIBOLIPHAUNT_NATIVE_PRODUCT, - kind: "native-runtime", - surface: "rust-native-direct", - }); - const brokerTargets = artifactTargets({ - product: BROKER_PRODUCT, - kind: "broker-helper", - surface: "rust-broker", - }); - const nativeTargetIds = nativeTargets.map((target) => target.target); - assertSameNativeTargetSet( - "oliphaunt Rust SDK native runtime/broker", - nativeTargetIds, - brokerTargets.map((target) => target.target), - ); - return { nativeTargets, brokerTargets }; -} - -export function renderRustSdkNativeTargetGuard(nativeTargets) { - const targetIds = nativeTargets.map((target) => typeof target === "string" ? target : target.target); - return renderUnsupportedNativeTargetGuard({ - product: "oliphaunt", - nativeTargets: targetIds, - nativeCfgs: targetIds.map((target) => rustNativeTargetCfg(target)), - guidance: "use the separately versioned oliphaunt-wasix crate for WASIX environments.", - }); -} - -function renderReleaseCargoToml(source, nativeVersion, brokerVersion, artifactTargets) { - let text = source - .replace("repository.workspace = true", 'repository = "https://github.com/f0rr0/oliphaunt"') - .replace("homepage.workspace = true", 'homepage = "https://oliphaunt.dev"'); - if (!text.includes("[workspace]")) { - text = `${text.trimEnd()}\n\n[workspace]\n`; - } - - const lines = [ - "", - "# Generated for crates.io publishing. Source checkouts keep native runtime", - "# and broker artifact crates out of the local dependency graph until those", - "# artifacts are published and indexed.", - ]; - const targetDependencies = new Map(); - const addTargetDependency = (cfg, dependency) => { - const dependencies = targetDependencies.get(cfg) ?? []; - dependencies.push(dependency); - targetDependencies.set(cfg, dependencies); - }; - - for (const target of artifactTargets.nativeTargets) { - const cfg = rustNativeTargetCfg(target); - addTargetDependency(cfg, `${liboliphauntCargoPackageName(target.target)} = { version = "=${nativeVersion}" }`); - } - for (const target of artifactTargets.brokerTargets) { - const cfg = rustNativeTargetCfg(target); - addTargetDependency(cfg, `${brokerCargoPackageName(target.target)} = { version = "=${brokerVersion}" }`); - } - - for (const cfg of [...targetDependencies.keys()].sort(compareText)) { - lines.push("", `[target.'cfg(${cfg})'.dependencies]`); - lines.push(...targetDependencies.get(cfg).sort(compareText)); - } - return `${text.trimEnd()}\n${lines.join("\n")}\n`; -} - -function validateReleaseArtifactCoverage(manifest, nativeVersion, nativeTargets) { - const brokerCrates = registryPackageRows({ product: BROKER_PRODUCT, packageKind: "crates" }, TOOL) - .map((row) => row.packageName); - const missingBroker = brokerCrates.filter((crate) => !manifest.includes(`${crate} = `)); - if (missingBroker.length > 0) { - fail(`generated oliphaunt release source is missing broker Cargo artifact dependencies: ${missingBroker.join(", ")}`); - } - - const nativeRuntimeCrates = nativeTargets.map((target) => liboliphauntCargoPackageName(target.target)); - const nativeCrates = registryPackageRows({ product: LIBOLIPHAUNT_NATIVE_PRODUCT, packageKind: "crates" }, TOOL) - .map((row) => row.packageName); - if (nativeCrates.length === 0) { - fail( - "oliphaunt-rust cannot publish a working native Cargo consumer path: " - + "oliphaunt-build requires Cargo-resolved liboliphaunt-native native-runtime " - + `artifacts for ${nativeTargets.map((target) => target.target).join(", ")}, but liboliphaunt-native declares no crates.io ` - + "artifact packages. Split/size native runtime artifacts into crates.io-sized packages before publishing oliphaunt-rust.", - ); - } - - const missingNative = nativeRuntimeCrates.filter( - (crate) => !manifest.includes(`${crate} = { version = "=${nativeVersion}" }`), - ); - if (missingNative.length > 0) { - fail(`generated oliphaunt release source is missing native runtime Cargo artifact dependencies: ${missingNative.join(", ")}`); - } -} - -function releaseStageDir(stageDir) { - const resolved = path.resolve(ROOT, stageDir); - const relative = path.relative(ROOT, resolved); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - fail(`generated Rust release stage must be a repository-contained directory, got ${stageDir}`); - } - return resolved; -} - -export function prepareRustReleaseSource({ stageDir = DEFAULT_STAGE_DIR, log = true } = {}) { - const version = currentProductVersionSync(RUST_PRODUCT, TOOL); - const nativeVersion = productCompatibilityVersion(RUST_PRODUCT, LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL); - const brokerVersion = productCompatibilityVersion(RUST_PRODUCT, BROKER_PRODUCT, TOOL); - const artifactTargets = nativeSdkArtifactTargets(); - const outputDir = releaseStageDir(stageDir); - stageRustPackageSource(outputDir); - - const cargoToml = path.join(outputDir, "Cargo.toml"); - const rendered = renderReleaseCargoToml( - readFileSync(cargoToml, "utf8"), - nativeVersion, - brokerVersion, - artifactTargets, - ); - writeFileSync(cargoToml, rendered, "utf8"); - if (!packageSection(rendered).includes(`version = "${version}"`)) { - fail(`generated oliphaunt release source must keep SDK version ${version}`); - } - validateReleaseArtifactCoverage(rendered, nativeVersion, artifactTargets.nativeTargets); - const libRs = path.join(outputDir, "src/lib.rs"); - writeFileSync( - libRs, - `${readFileSync(libRs, "utf8").trimEnd()}\n\n// Generated release-only native target guard.\n` - + `${renderRustSdkNativeTargetGuard(artifactTargets.nativeTargets)}\n`, - "utf8", - ); - stageReleaseNotices(outputDir, SOURCE_NOTICE_OPTIONS); - assertReleaseNoticesInDirectory(outputDir, SOURCE_NOTICE_OPTIONS); - if (log) console.log(rel(cargoToml)); - return cargoToml; -} - -export function prepareOliphauntBuildReleaseSource({ - stageDir = DEFAULT_BUILD_STAGE_DIR, - log = true, -} = {}) { - const version = currentProductVersionSync(RUST_PRODUCT, TOOL); - const sourceDir = path.join(ROOT, "src/sdks/rust/crates/oliphaunt-build"); - const outputDir = releaseStageDir(stageDir); - rmSync(outputDir, { recursive: true, force: true }); - cpSync(sourceDir, outputDir, { - recursive: true, - filter: (source) => path.basename(source) !== "target", - }); - const cargoToml = path.join(outputDir, "Cargo.toml"); - const rendered = packagedCargoManifestText(readFileSync(cargoToml, "utf8")); - writeFileSync(cargoToml, rendered, "utf8"); - if (!packageSection(rendered).includes(`version = "${version}"`)) { - fail(`generated oliphaunt-build release source must keep SDK version ${version}`); - } - stageReleaseNotices(outputDir, SOURCE_NOTICE_OPTIONS); - assertReleaseNoticesInDirectory(outputDir, SOURCE_NOTICE_OPTIONS); - if (log) console.log(rel(cargoToml)); - return cargoToml; -} - -function main(argv) { - if (argv.includes("-h") || argv.includes("--help")) { - console.log("usage: tools/release/prepare-rust-release-source.mjs"); - process.exit(0); - } - if (argv.length > 0) { - fail(`prepare-rust-release-source does not accept extra arguments: ${argv.join(" ")}`); - } - prepareRustReleaseSource(); -} - -if (import.meta.main) { - main(Bun.argv.slice(2)); -} diff --git a/tools/release/prepare-rust-release-source.test.mjs b/tools/release/prepare-rust-release-source.test.mjs deleted file mode 100644 index bc5ca9bac..000000000 --- a/tools/release/prepare-rust-release-source.test.mjs +++ /dev/null @@ -1,200 +0,0 @@ -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdirSync, mkdtempSync, readFileSync, rmSync } from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { manualCargoPackageSource } from "./cargo-source-package.mjs"; -import { - allArtifactTargets, - currentProductVersionSync, -} from "./release-artifact-targets.mjs"; -import { - prepareOliphauntBuildReleaseSource, - prepareRustReleaseSource, -} from "./prepare-rust-release-source.mjs"; -import { productCompatibilityVersion } from "./release-graph.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, -} from "./release-notices.mjs"; -import { normalPublicationPlan } from "./normal-publication-plan.mjs"; -import { - discoverPublicationArtifacts, - projectInternalDependencyIds, -} from "./publication-lock.mjs"; -import { rustNativeTargetCfg } from "./rust-native-targets.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); - -function commandOutput(command, args) { - const result = spawnSync(command, args, { - cwd: ROOT, - encoding: "utf8", - stdio: ["ignore", "pipe", "pipe"], - }); - assert.equal(result.status, 0, `${command} ${args.join(" ")} failed:\n${result.stdout}\n${result.stderr}`); - return result.stdout; -} - -test("freezes the generated target-wired Rust SDK source instead of the workspace facade", () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "rust-release-source-test-")); - try { - const manifestPath = prepareRustReleaseSource({ - stageDir: path.join(root, "source"), - log: false, - }); - const manifest = readFileSync(manifestPath, "utf8"); - const source = readFileSync(path.join(root, "source/src/lib.rs"), "utf8"); - const queryCore = readFileSync(path.join(root, "source/src/query_core.rs"), "utf8"); - const canonicalQueryCore = readFileSync( - path.join(ROOT, "src/shared/rust-query-core/query_core.rs"), - "utf8", - ); - const workspaceSource = readFileSync(path.join(ROOT, "src/sdks/rust/src/lib.rs"), "utf8"); - const nativeVersion = productCompatibilityVersion( - "oliphaunt-rust", - "liboliphaunt-native", - "prepare-rust-release-source.test.mjs", - ); - const brokerVersion = productCompatibilityVersion( - "oliphaunt-rust", - "oliphaunt-broker", - "prepare-rust-release-source.test.mjs", - ); - const sdkVersion = currentProductVersionSync("oliphaunt-rust", "prepare-rust-release-source.test.mjs"); - const targets = allArtifactTargets({ - product: "liboliphaunt-native", - kind: "native-runtime", - surface: "rust-native-direct", - }, "prepare-rust-release-source.test.mjs"); - assert.equal(targets.length, 4); - assert.match(manifest, /^license = "MIT"$/mu); - assertReleaseNoticesInDirectory(path.join(root, "source"), { profile: "source-sdk" }); - - for (const target of targets) { - const cfg = rustNativeTargetCfg(target); - assert.ok(manifest.includes(`[target.'cfg(${cfg})'.dependencies]`)); - assert.ok(manifest.includes(`liboliphaunt-native-${target.target} = { version = "=${nativeVersion}" }`)); - assert.ok(manifest.includes(`oliphaunt-broker-${target.target} = { version = "=${brokerVersion}" }`)); - assert.ok(source.includes(target.target)); - } - assert.doesNotMatch(manifest, /^oliphaunt-tools = /mu); - assert.match(source, /Generated release-only native target guard[.]/u); - assert.match(source, /compile_error!/u); - assert.match(source, /separately versioned oliphaunt-wasix crate/u); - assert.doesNotMatch(workspaceSource, /Generated release-only native target guard|compile_error!/u); - assert.equal(queryCore, canonicalQueryCore); - - const cratePath = manualCargoPackageSource( - manifestPath, - path.join(root, "crate"), - { root: ROOT, fail: (message) => assert.fail(message), rel: String }, - ); - assert.equal(path.basename(cratePath), `oliphaunt-${sdkVersion}.crate`); - const packageRoot = `oliphaunt-${sdkVersion}`; - assertReleaseNoticesInArchive(cratePath, { - profile: "source-sdk", - prefix: packageRoot, - }); - const packedManifest = commandOutput("tar", ["-xOzf", cratePath, `${packageRoot}/Cargo.toml`]); - const packedSource = commandOutput("tar", ["-xOzf", cratePath, `${packageRoot}/src/lib.rs`]); - const packedQueryCore = commandOutput( - "tar", - ["-xOzf", cratePath, `${packageRoot}/src/query_core.rs`], - ); - const packedNames = commandOutput("tar", ["-tzf", cratePath]); - assert.equal(packedManifest, manifest); - assert.equal(packedSource, source); - assert.equal(packedQueryCore, canonicalQueryCore); - assert.doesNotMatch(packedManifest, /=\s*\{[^}\n]*\bpath\s*=/u); - assert.doesNotMatch(packedNames, /crates\/oliphaunt-build/u); - const [packagedCarrier] = discoverPublicationArtifacts([cratePath]); - const repeatedToolsRows = packagedCarrier.dependencies.filter( - ({ ecosystem, name }) => ecosystem === "cargo" && name === "oliphaunt-tools", - ); - assert.equal(repeatedToolsRows.length, 0); - assert.deepEqual( - projectInternalDependencyIds( - [{ id: "cargo:oliphaunt" }, { id: "cargo:oliphaunt-tools" }], - packagedCarrier.dependencies, - ), - [], - ); - - // The product metadata intentionally points the Rust SDK at the broker - // version while the broker executable is built from the SDK source. That - // is not a registry cycle: published broker carriers are dependency-free - // payload leaves, and only the generated SDK facade depends on them. - const brokerCarriers = targets.map((target, publishOrder) => { - const name = `oliphaunt-broker-${target.target}`; - const brokerManifest = Bun.TOML.parse(readFileSync( - path.join(ROOT, `src/runtimes/broker/crates/${target.target}/Cargo.toml`), - "utf8", - )); - assert.equal(brokerManifest.dependencies, undefined, `${name} must not depend back on oliphaunt`); - return { - id: `cargo:${name}`, - product: "oliphaunt-broker", - ecosystem: "cargo", - name, - version: brokerVersion, - publishOrder, - dependencies: [], - }; - }); - const brokerIds = brokerCarriers.map(({ id }) => id); - const topology = normalPublicationPlan({ - products: [{ id: "oliphaunt-broker" }, { id: "oliphaunt-rust" }], - carriers: [ - ...brokerCarriers, - { - id: "cargo:oliphaunt", - product: "oliphaunt-rust", - ecosystem: "cargo", - name: "oliphaunt", - version: sdkVersion, - publishOrder: brokerCarriers.length, - dependencies: brokerIds, - }, - ], - }, ["oliphaunt-broker", "oliphaunt-rust"]); - const positions = new Map(topology.operations.map(({ carrierId }, index) => [carrierId, index])); - for (const brokerId of brokerIds) { - assert.ok(positions.get(brokerId) < positions.get("cargo:oliphaunt")); - assert.match(packedManifest, new RegExp(`^${brokerId.slice("cargo:".length)} = \\{ version = "=${brokerVersion}" \\}$`, "mu")); - } - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("freezes oliphaunt-build with truthful metadata and canonical notices", () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "rust-build-release-source-test-")); - try { - const manifestPath = prepareOliphauntBuildReleaseSource({ - stageDir: path.join(root, "source"), - log: false, - }); - const manifest = readFileSync(manifestPath, "utf8"); - const version = currentProductVersionSync("oliphaunt-rust", "prepare-rust-release-source.test.mjs"); - assert.match(manifest, /^license = "MIT"$/mu); - assert.doesNotMatch(manifest, /\.workspace\s*=\s*true/u); - assertReleaseNoticesInDirectory(path.join(root, "source"), { profile: "source-sdk" }); - - const cratePath = manualCargoPackageSource( - manifestPath, - path.join(root, "crate"), - { root: ROOT, fail: (message) => assert.fail(message), rel: String }, - ); - assert.equal(path.basename(cratePath), `oliphaunt-build-${version}.crate`); - assertReleaseNoticesInArchive(cratePath, { - profile: "source-sdk", - prefix: `oliphaunt-build-${version}`, - }); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/prepare-swift-release-consumer.mjs b/tools/release/prepare-swift-release-consumer.mjs deleted file mode 100755 index f7150eed2..000000000 --- a/tools/release/prepare-swift-release-consumer.mjs +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; -import path from "node:path"; - -const TOOL = "prepare-swift-release-consumer.mjs"; -const LOCAL_XCFRAMEWORK_PATH = "Artifacts/liboliphaunt.xcframework"; -const BINARY_TARGET = /\.binaryTarget\(\s*name:\s*"liboliphaunt"\s*,\s*url:\s*"([^"]+)"\s*,\s*checksum:\s*"([0-9a-f]{64})"\s*\)/gmu; - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function releaseAssetIdentity(assetFile) { - const basename = path.basename(assetFile); - const match = /^liboliphaunt-(.+)-apple-spm-xcframework\.zip$/u.exec(basename); - if (!match || !match[1]) { - throw new Error( - `Apple XCFramework asset must be named liboliphaunt--apple-spm-xcframework.zip: ${basename}`, - ); - } - return { basename, version: match[1] }; -} - -export function parseSwiftReleaseBinaryTarget( - manifest, - label = "release manifest", -) { - if (typeof manifest !== "string") { - throw new Error(`${label} must be text`); - } - const matches = [...manifest.matchAll(BINARY_TARGET)]; - if (matches.length !== 1) { - throw new Error( - `${label} must contain exactly one checksum-pinned liboliphaunt binary target; found ${matches.length}`, - ); - } - const [match] = matches; - return { - checksum: match[2], - end: match.index + match[0].length, - index: match.index, - url: match[1], - }; -} - -export function localizeSwiftReleaseManifest({ manifestFile, assetFile, outputFile }) { - const manifest = readFileSync(manifestFile, "utf8"); - const { checksum, end, index, url } = parseSwiftReleaseBinaryTarget(manifest); - const { basename, version } = releaseAssetIdentity(assetFile); - const expectedUrl = - `https://github.com/f0rr0/oliphaunt/releases/download/` + - `liboliphaunt-native-v${version}/${basename}`; - if (url !== expectedUrl) { - throw new Error( - `release manifest binary URL is not the canonical ${expectedUrl}: ${url}`, - ); - } - const actualChecksum = sha256(assetFile); - if (checksum !== actualChecksum) { - throw new Error( - `release manifest checksum ${checksum} does not match ${basename} SHA-256 ${actualChecksum}`, - ); - } - - const replacement = `.binaryTarget(\n` + - ` name: "liboliphaunt",\n` + - ` path: "${LOCAL_XCFRAMEWORK_PATH}"\n` + - ` )`; - const localized = manifest.slice(0, index) + replacement + manifest.slice(end); - if (localized.includes("file://")) { - throw new Error("localized release manifest must not contain a file URL"); - } - if (!localized.includes(`path: "${LOCAL_XCFRAMEWORK_PATH}"`)) { - throw new Error("localized release manifest did not retain the exact local XCFramework projection"); - } - mkdirSync(path.dirname(outputFile), { recursive: true }); - writeFileSync(outputFile, localized, "utf8"); - return { - asset: basename, - checksum: actualChecksum, - publicUrl: expectedUrl, - xcframeworkPath: LOCAL_XCFRAMEWORK_PATH, - }; -} - -function parseArgs(argv) { - const values = new Map(); - for (let index = 0; index < argv.length; index += 1) { - const key = argv[index]; - if (!["--manifest", "--asset", "--output"].includes(key)) { - throw new Error(`unknown argument ${key}`); - } - const value = argv[index + 1]; - if (!value || value.startsWith("--")) { - throw new Error(`${key} requires a value`); - } - if (values.has(key)) { - throw new Error(`${key} may be specified only once`); - } - values.set(key, value); - index += 1; - } - for (const key of ["--manifest", "--asset", "--output"]) { - if (!values.has(key)) { - throw new Error(`${key} is required`); - } - } - return { - assetFile: path.resolve(values.get("--asset")), - manifestFile: path.resolve(values.get("--manifest")), - outputFile: path.resolve(values.get("--output")), - }; -} - -if (import.meta.main) { - try { - const result = localizeSwiftReleaseManifest(parseArgs(Bun.argv.slice(2))); - console.log(JSON.stringify(result)); - } catch (error) { - console.error(`${TOOL}: ${error.message}`); - process.exit(1); - } -} diff --git a/tools/release/prepare-swift-release-consumer.test.mjs b/tools/release/prepare-swift-release-consumer.test.mjs deleted file mode 100644 index a665d3e03..000000000 --- a/tools/release/prepare-swift-release-consumer.test.mjs +++ /dev/null @@ -1,83 +0,0 @@ -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { mkdtempSync, readFileSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { localizeSwiftReleaseManifest } from "./prepare-swift-release-consumer.mjs"; - -function fixture() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-swift-release-consumer-")); - const version = "1.2.3"; - const asset = path.join(root, `liboliphaunt-${version}-apple-spm-xcframework.zip`); - writeFileSync(asset, "xcframework bytes\n"); - const checksum = createHash("sha256").update(readFileSync(asset)).digest("hex"); - const url = - `https://github.com/f0rr0/oliphaunt/releases/download/` + - `liboliphaunt-native-v${version}/${path.basename(asset)}`; - const binaryTarget = `.binaryTarget(\n` + - ` name: "liboliphaunt",\n` + - ` url: "${url}",\n` + - ` checksum: "${checksum}"\n` + - ` )`; - const manifest = path.join(root, "Package.swift.release"); - const output = path.join(root, "consumer", "Package.swift"); - writeFileSync(manifest, `// swift-tools-version: 6.0\nlet target = ${binaryTarget}\n`); - return { asset, binaryTarget, checksum, manifest, output, url }; -} - -test("localizes only the exact checksum-bound canonical Apple binary target", () => { - const value = fixture(); - const result = localizeSwiftReleaseManifest({ - manifestFile: value.manifest, - assetFile: value.asset, - outputFile: value.output, - }); - assert.deepEqual(result, { - asset: path.basename(value.asset), - checksum: value.checksum, - publicUrl: value.url, - xcframeworkPath: "Artifacts/liboliphaunt.xcframework", - }); - const output = readFileSync(value.output, "utf8"); - assert.match(output, /path: "Artifacts\/liboliphaunt\.xcframework"/u); - assert.doesNotMatch(output, /url:|checksum:|file:\/\//u); -}); - -test("rejects checksum drift instead of projecting substituted bytes", () => { - const value = fixture(); - writeFileSync(value.asset, "substituted bytes\n"); - assert.throws( - () => localizeSwiftReleaseManifest({ - manifestFile: value.manifest, - assetFile: value.asset, - outputFile: value.output, - }), - /does not match .* SHA-256/u, - ); -}); - -test("rejects noncanonical and duplicate binary target identities", () => { - const value = fixture(); - writeFileSync(value.manifest, readFileSync(value.manifest, "utf8").replace(value.url, "https://example.invalid/runtime.zip")); - assert.throws( - () => localizeSwiftReleaseManifest({ - manifestFile: value.manifest, - assetFile: value.asset, - outputFile: value.output, - }), - /is not the canonical/u, - ); - - const duplicate = fixture(); - writeFileSync(duplicate.manifest, `${readFileSync(duplicate.manifest, "utf8")}\n${duplicate.binaryTarget}\n`); - assert.throws( - () => localizeSwiftReleaseManifest({ - manifestFile: duplicate.manifest, - assetFile: duplicate.asset, - outputFile: duplicate.output, - }), - /exactly one .* found 2/u, - ); -}); diff --git a/tools/release/product-tags.mts b/tools/release/product-tags.mts new file mode 100644 index 000000000..07922162d --- /dev/null +++ b/tools/release/product-tags.mts @@ -0,0 +1,44 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; + +// Tags depend on release-please's canonical version files, not the build task graph. +const config = JSON.parse(readFileSync('release-please-config.json', 'utf8')); +if (config['include-v-in-tag'] !== true || config['tag-separator'] !== '-') + throw new Error('release-please must use product-vVERSION tags'); +const argv = process.argv.slice(2); +const products = argv[0] === '--products-json' && argv.length === 2 ? JSON.parse(argv[1]) : argv; +if ( + !Array.isArray(products) || + !products.every((product) => typeof product === 'string' && product) +) + throw new Error('products must be a non-empty JSON string array'); +if (!products.length) throw new Error('at least one release product is required'); +for (const product of [...new Set(products)].sort()) { + const entry = Object.entries(config.packages).find(([, value]) => value.component === product); + if (!entry) throw new Error(`unknown release product ${JSON.stringify(product)}`); + const [packagePath, metadata] = entry; + const versionFile = + metadata['version-file'] ?? + (metadata['release-type'] === 'rust' + ? 'Cargo.toml' + : ['node', 'expo'].includes(metadata['release-type']) + ? 'package.json' + : undefined); + if (!versionFile || path.isAbsolute(versionFile) || versionFile.split(/[\\/]/u).includes('..')) + throw new Error(`${product} must declare a version file inside its package`); + const text = readFileSync(path.join(packagePath, versionFile), 'utf8'); + const basename = path.basename(versionFile); + const version = + basename === 'Cargo.toml' + ? Bun.TOML.parse(text).package.version + : basename === 'package.json' + ? JSON.parse(text).version + : basename === 'gradle.properties' + ? text.match(/^VERSION_NAME\s*=\s*(\S+)\s*$/mu)?.[1] + : ['VERSION', 'LIBOLIPHAUNT_VERSION'].includes(basename) + ? text.trim() + : undefined; + if (!/^[a-z0-9][a-z0-9-]*$/u.test(product) || !/^\d+\.\d+\.\d+$/u.test(version)) + throw new Error(`${product} must have a stable x.y.z release version`); + process.stdout.write(`${product}-v${version}\n`); +} diff --git a/tools/release/product-task-model.test.mjs b/tools/release/product-task-model.test.mjs deleted file mode 100644 index ebeda7ac5..000000000 --- a/tools/release/product-task-model.test.mjs +++ /dev/null @@ -1,267 +0,0 @@ -import assert from "node:assert/strict"; -import { test } from "node:test"; - -import { moonCommand, moonEnvironment } from "../dev/moon-command.mjs"; -import { BROAD_EXTENSION_INPUT_PROJECTS } from "../graph/ci_plan.mjs"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; - -function moonJson(args) { - return JSON.parse(execFileSync(moonCommand(), args, { - encoding: "utf8", - env: moonEnvironment(), - maxBuffer: 64 * 1024 * 1024, - })); -} - -test("release product tasks use semantic names and keep package independent", () => { - const projects = moonJson(["query", "projects"]).projects; - const tasks = moonJson(["query", "tasks"]).tasks; - const releaseProducts = projects.filter((project) => project.config?.tags?.includes("release-product")); - const forbidden = new Set(["test", "release-check", "assemble-release"]); - - assert.ok(releaseProducts.length > 0); - for (const project of releaseProducts) { - const productTasks = tasks[project.id] ?? {}; - assert.deepEqual( - Object.keys(productTasks).filter((task) => forbidden.has(task)), - [], - `${project.id} exposes a deceptive legacy task`, - ); - for (const dependency of productTasks.package?.deps ?? []) { - assert.ok( - !/:(?:check|format-check|lint|test|unit)$/u.test(dependency.target), - `${project.id}:package hides unrelated quality task ${dependency.target}`, - ); - } - } - - const sdkProducts = [ - "oliphaunt-js", - "oliphaunt-kotlin", - "oliphaunt-react-native", - "oliphaunt-rust", - "oliphaunt-swift", - "oliphaunt-wasix-rust", - "oliphaunt-wasix-ts", - ]; - for (const project of sdkProducts) { - assert.deepEqual( - Object.values(tasks[project]).filter((task) => task.tags?.includes("artifact-package")), - [], - `${project} must not own repository release orchestration`, - ); - } - - const releaseTasks = tasks["release-tools"]; - for (const [task, product] of [ - ["js-sdk-package", "oliphaunt-js"], - ["react-native-sdk-package", "oliphaunt-react-native"], - ["rust-sdk-package", "oliphaunt-rust"], - ["swift-sdk-package", "oliphaunt-swift"], - ["wasix-rust-package", "oliphaunt-wasix-rust"], - ["wasix-ts-sdk-package", "oliphaunt-wasix-ts"], - ]) { - assert.equal( - releaseTasks[task].deps.some( - ({ target }) => target === `${product}:package`, - ), - true, - `release-tools:${task} must consume ${product}:package output`, - ); - } -}); - -test("task edges distinguish artifact data from ordering gates", () => { - const tasks = Object.values(moonJson(["task-graph", "--json"]).data); - const byTarget = new Map(tasks.map((task) => [task.target, task])); - const projectSources = new Map( - moonJson(["query", "projects"]).projects.map(({ id, source }) => [id, source]), - ); - const outputs = []; - - for (const consumer of tasks) { - const consumerTags = new Set(consumer.tags ?? []); - const isProducer = ["artifact-builder", "artifact-package", "build", "package"] - .some((tag) => consumerTags.has(tag)); - const isQualificationAggregate = consumer.id === "qualify" || consumerTags.has("aggregate"); - const project = consumer.target.split(":", 1)[0]; - const projectSource = projectSources.get(project); - const resolvePath = (value) => value.startsWith("/") ? value : `${projectSource}/${value}`; - const inputs = new Set( - (consumer.inputs ?? []) - .map((input) => input.file ?? input.glob) - .filter((input) => typeof input === "string") - .map(resolvePath), - ); - for (const output of consumer.outputs ?? []) { - const path = output.file ?? output.glob; - const resolvedPath = resolvePath(path); - outputs.push({ path: resolvedPath, task: consumer }); - if (inputs.has(resolvedPath)) { - assert.equal( - consumer.options?.cache, - false, - `${consumer.target} caches a path declared as both input and output`, - ); - } - } - for (const dependency of consumer.deps ?? []) { - const producer = byTarget.get(dependency.target); - assert.ok(producer, `${consumer.target} has missing dependency ${dependency.target}`); - const carriesOutputs = (producer.outputs ?? []).length > 0; - assert.equal( - carriesOutputs ? dependency.cacheStrategy !== "ignored" : dependency.cacheStrategy === "ignored", - true, - `${consumer.target} -> ${producer.target} misclassifies ${carriesOutputs ? "artifact data" : "ordering"}`, - ); - if (isProducer && !isQualificationAggregate && !carriesOutputs) { - assert.equal( - (producer.tags ?? []).some((tag) => ["assertion", "quality", "static", "unit"].includes(tag)), - false, - `${consumer.target} hides quality gate ${producer.target} inside a producer task`, - ); - } - } - } - - const staticRoot = (value) => value.slice(0, value.search(/[?*[{]/u) < 0 ? value.length : value.search(/[?*[{]/u)); - const overlaps = (left, right) => { - const leftRoot = staticRoot(left); - const rightRoot = staticRoot(right); - return leftRoot === rightRoot || leftRoot.startsWith(rightRoot) || rightRoot.startsWith(leftRoot); - }; - for (let left = 0; left < outputs.length; left += 1) { - for (let right = left + 1; right < outputs.length; right += 1) { - const first = outputs[left]; - const second = outputs[right]; - if (first.task.target === second.task.target || !overlaps(first.path, second.path)) continue; - const pair = [first.task, second.task]; - const finalizer = pair.find((task) => task.tags?.includes("in-place-finalizer")); - const input = pair.find((task) => task.tags?.includes("in-place-finalizer-input")); - assert.equal( - Boolean(finalizer && input), - true, - `${first.path} and ${second.path} have overlapping owners without an explicit ownership contract: ${pair.map(({ target }) => target).join(", ")}`, - ); - assert.equal( - pair.every((task) => task.options?.cache === false), - true, - `overlapping output owners must not be cached: ${pair.map(({ target }) => target).join(", ")}`, - ); - if (finalizer && input) { - assert.equal( - finalizer.deps.some(({ target }) => target === input.target), - true, - `${finalizer.target} must directly finalize ${input.target}`, - ); - } - } - } -}); - -test("WASIX Postmaster qualification includes its packaged runtime behavior", () => { - const tasks = moonJson(["query", "tasks"]).tasks["liboliphaunt-wasix-postmaster"]; - assert.deepEqual( - tasks["runtime-patch-tests"].deps.map(({target}) => target), - ["liboliphaunt-wasix-postmaster:prepare-runtime"], - ); - assert.deepEqual( - tasks.qualify.deps.map(({target}) => target).sort(), - [ - "liboliphaunt-wasix-postmaster:immediate-recovery", - "liboliphaunt-wasix-postmaster:linear-memory-integration", - "liboliphaunt-wasix-postmaster:lint", - "liboliphaunt-wasix-postmaster:regression", - "liboliphaunt-wasix-postmaster:release-assets", - "liboliphaunt-wasix-postmaster:runtime-patch-tests", - "liboliphaunt-wasix-postmaster:unit", - ], - ); -}); - -test("WASIX TypeScript products build packages and root integration consumes them", () => { - const tasks = moonJson(["query", "tasks"]).tasks; - const integration = tasks["wasix-ts-integration"].runtime; - const dependencies = new Set(integration.deps.map(({ target }) => target)); - - assert.deepEqual( - [...dependencies].sort(), - [ - "liboliphaunt-wasix:runtime-portable", - "oliphaunt-wasix-tools-ts:package", - "oliphaunt-wasix-ts:package", - "release-tools:wasix-napi-runtime", - ], - ); - assert.deepEqual(integration.outputs ?? [], []); - assert.equal(integration.options.cache, false); - assert.equal( - tasks["release-tools"]["wasix-ts-sdk-package"].deps.some( - ({ target }) => target === integration.target, - ), - false, - ); -}); - -test("WASIX Node-API release build consumes its runtime and extension artifacts", () => { - const task = moonJson(["query", "tasks"]).tasks["release-tools"]["wasix-napi-runtime"]; - assert.equal(task.command, "bash"); - assert.deepEqual(task.deps.map(({ target }) => target).sort(), [ - "extension-artifacts-wasix:build-target", - "liboliphaunt-wasix:runtime-aot", - ]); -}); - -test("CI planner project selectors resolve to Moon projects", () => { - const projects = moonJson(["query", "projects"]).projects; - const projectIds = new Set(projects.map(({ id }) => id)); - for (const project of BROAD_EXTENSION_INPUT_PROJECTS) { - assert.equal(projectIds.has(project), true, `unknown CI planner project ${project}`); - } -}); - -test("Moon projects do not duplicate inferred dependency edges", () => { - for (const project of moonJson(["query", "projects"]).projects) { - const configured = project.config.dependsOn ?? []; - const dependencies = configured - .filter((dependency) => typeof dependency === "string" || dependency.source !== "implicit") - .map((dependency) => typeof dependency === "string" ? dependency : dependency.id); - const inferred = new Set( - configured - .filter((dependency) => typeof dependency !== "string" && dependency.source === "implicit") - .map((dependency) => dependency.id), - ); - assert.equal( - new Set(dependencies).size, - dependencies.length, - `${project.id} duplicates a project dependency already inferred by Moon`, - ); - assert.deepEqual( - dependencies.filter((dependency) => inferred.has(dependency)), - [], - `${project.id} explicitly repeats an inferred project dependency`, - ); - assert.equal( - dependencies.includes(project.id), - false, - `${project.id} depends on itself`, - ); - } -}); - -test("Moon project metadata has no source-to-tool dependency edges", () => { - const projects = moonJson(["query", "projects"]).projects; - const tooling = new Set( - projects.filter(({ source }) => source.startsWith("tools/")).map(({ id }) => id), - ); - for (const project of projects.filter(({ source }) => source.startsWith("src/"))) { - const dependencies = (project.config.dependsOn ?? []).map((dependency) => - typeof dependency === "string" ? dependency : dependency.id - ); - assert.deepEqual( - dependencies.filter((dependency) => tooling.has(dependency)), - [], - `${project.id} depends on repository tooling`, - ); - } -}); diff --git a/tools/release/product-version.mjs b/tools/release/product-version.mjs deleted file mode 100644 index 89a61d9fa..000000000 --- a/tools/release/product-version.mjs +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bun -import { currentProductVersion } from "./release-artifact-targets.mjs"; - -const TOOL = "product-version.mjs"; - -function fail(message) { - console.error(`${TOOL}: ${message}`); - process.exit(2); -} - -function usage() { - fail("usage: tools/release/product-version.mjs version "); -} - -function ensureSemver(product, version) { - if (!/^[0-9]+[.][0-9]+[.][0-9]+(?:[-+][0-9A-Za-z][0-9A-Za-z.-]*)?$/.test(version)) { - fail(`${product} version is not semver-like: ${JSON.stringify(version)}`); - } - return version; -} - -export async function currentVersion(product) { - if (typeof product !== "string" || product.length === 0) { - fail("product id must be a non-empty string"); - } - return ensureSemver(product, await currentProductVersion(product, TOOL)); -} - -async function main(argv) { - if (argv.length !== 2 || argv[0] !== "version") { - usage(); - } - console.log(await currentVersion(argv[1])); -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/product-version.mts b/tools/release/product-version.mts new file mode 100644 index 000000000..207ec68d9 --- /dev/null +++ b/tools/release/product-version.mts @@ -0,0 +1,38 @@ +#!/usr/bin/env bun +import { currentProductVersion } from './release-artifact-targets.mts'; + +const TOOL = 'product-version.mts'; + +function fail(message) { + console.error(`${TOOL}: ${message}`); + process.exit(2); +} + +function usage() { + fail('usage: tools/release/product-version.mts version '); +} + +function ensureSemver(product, version) { + if (!/^[0-9]+[.][0-9]+[.][0-9]+(?:[-+][0-9A-Za-z][0-9A-Za-z.-]*)?$/.test(version)) { + fail(`${product} version is not semver-like: ${JSON.stringify(version)}`); + } + return version; +} + +export async function currentVersion(product) { + if (typeof product !== 'string' || product.length === 0) { + fail('product id must be a non-empty string'); + } + return ensureSemver(product, await currentProductVersion(product, TOOL)); +} + +async function main(argv) { + if (argv.length !== 2 || argv[0] !== 'version') { + usage(); + } + console.log(await currentVersion(argv[1])); +} + +if (import.meta.main) { + await main(Bun.argv.slice(2)); +} diff --git a/tools/release/public-consumer-smoke.mjs b/tools/release/public-consumer-smoke.mjs deleted file mode 100644 index c34901f1a..000000000 --- a/tools/release/public-consumer-smoke.mjs +++ /dev/null @@ -1,1441 +0,0 @@ -#!/usr/bin/env bun - -import { spawn } from "node:child_process"; -import { createHash, randomUUID } from "node:crypto"; -import { - linkSync, - lstatSync, - mkdirSync, - mkdtempSync, - readFileSync, - realpathSync, - rmSync, - statSync, - unlinkSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import process from "node:process"; - -import { - DEFAULT_PUBLICATION_LOCK, - loadPublicationLock, -} from "./publication-lock.mjs"; -import { - registryRetryDelaySeconds, - registryStatusRetryable, -} from "./registry-http-retry.mjs"; -import { ROOT, compareText, loadGraph } from "./release-graph.mjs"; -import { validateRegistryReceiptEvidence } from "./registry-integrity.mjs"; -import { validateGithubAttestationReceipt } from "./verify_github_release_attestations.mjs"; - -export const PUBLIC_CONSUMER_EVIDENCE_SCHEMA = "oliphaunt-public-consumer-smoke-v1"; - -const TOOL = "public-consumer-smoke"; -const REGISTRY_ECOSYSTEMS = ["cargo", "maven", "npm"]; -const SUPPORTED_PUBLISH_TARGETS = new Set([ - "crates-io", - "github-release", - "github-release-assets", - "maven-central", - "npm", - "swift-package-source-tag", -]); -const TARGET_ECOSYSTEM = new Map([ - ["crates-io", "cargo"], - ["maven-central", "maven"], - ["npm", "npm"], -]); -const CONSUMER_DEPENDENCY_SCOPES = Object.freeze({ - cargo: new Set(["build", "runtime"]), - maven: new Set(["compile", "runtime"]), - npm: new Set(["optional", "peer", "runtime"]), -}); -const DEFAULT_REPOSITORY = "f0rr0/oliphaunt"; -const DEFAULT_OUTPUT = path.join(ROOT, "target/release/public-consumer-smoke.json"); -const DEFAULT_OVERALL_TIMEOUT_SECONDS = 780; -const DEFAULT_POST_SMOKE_RESERVE_SECONDS = 600; -const MAX_SURFACE_ATTEMPTS = 8; -const MAX_COMMAND_ATTEMPT_MILLISECONDS = 240_000; -const RETRY_DELAYS_MILLISECONDS = [5_000, 10_000, 20_000, 30_000, 45_000, 60_000, 60_000]; -const MAX_COMMAND_OUTPUT_BYTES = 16 * 1024 * 1024; -const MAX_RECEIPT_BYTES = 64 * 1024 * 1024; -const MAX_EVIDENCE_BYTES = 8 * 1024 * 1024; -const MAX_CRATES_IO_METADATA_BYTES = 1024 * 1024; -const CRATES_IO_API = "https://crates.io/api/v1"; -const CRATES_IO_FEATURE_ATTEMPTS = 4; -const CRATES_IO_REQUEST_TIMEOUT_MILLISECONDS = 20_000; -const CRATES_IO_USER_AGENT = "oliphaunt-public-consumer-smoke (https://github.com/f0rr0/oliphaunt)"; -const SHA256_RE = /^[0-9a-f]{64}$/u; -const FULL_SHA_RE = /^[0-9a-f]{40}$/u; -const EXACT_RUST_TOOLCHAIN_RE = /^[1-9][0-9]*\.[0-9]+\.[0-9]+$/u; - -class PublicCommandError extends Error { - constructor(message, { retryable = false } = {}) { - super(message); - this.retryable = retryable; - } -} - -function error(message) { - return new Error(`${TOOL}: ${message}`); -} - -function stableJson(value) { - if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`; - if (value !== null && typeof value === "object") { - return `{${Object.keys(value).sort(compareText).map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`; - } - return JSON.stringify(value); -} - -function sha256Bytes(value) { - return createHash("sha256").update(value).digest("hex"); -} - -function sortedUniqueStrings(values, context, { allowEmpty = true } = {}) { - if ( - !Array.isArray(values) - || values.some((value) => typeof value !== "string" || value.length === 0 || /[\0\r\n]/u.test(value)) - ) { - throw error(`${context} must be a list of non-empty single-line strings`); - } - const result = [...new Set(values)].sort(compareText); - if (result.length !== values.length) throw error(`${context} must not contain duplicates`); - if (!allowEmpty && result.length === 0) throw error(`${context} must not be empty`); - return result; -} - -function sameStrings(left, right) { - return stableJson([...left].sort(compareText)) === stableJson([...right].sort(compareText)); -} - -function requirePositiveInteger(raw, context, fallback) { - const value = raw === undefined || raw === null || String(raw).trim() === "" - ? fallback - : Number(String(raw).trim()); - if (!Number.isSafeInteger(value) || value <= 0) { - throw error(`${context} must be a positive safe integer`); - } - return value; -} - -function selectedProductRows(lock, products) { - const requested = sortedUniqueStrings(products, "products", { allowEmpty: false }); - const locked = lock.products.map(({ id }) => id).sort(compareText); - if (!sameStrings(requested, locked)) { - throw error(`requested products must exactly match the frozen publication lock: requested=${JSON.stringify(requested)}, locked=${JSON.stringify(locked)}`); - } - const byId = new Map(lock.products.map((product) => [product.id, product])); - return requested.map((id) => byId.get(id)); -} - -function assertCarrier(carrier, productIds) { - if ( - carrier === null - || Array.isArray(carrier) - || typeof carrier !== "object" - || typeof carrier.id !== "string" - || carrier.id !== `${carrier.ecosystem}:${carrier.name}` - || !REGISTRY_ECOSYSTEMS.includes(carrier.ecosystem) - || typeof carrier.name !== "string" - || carrier.name.length === 0 - || typeof carrier.version !== "string" - || carrier.version.length === 0 - || !productIds.has(carrier.product) - || !Array.isArray(carrier.dependencies) - ) { - throw error(`publication lock contains an invalid selected carrier ${JSON.stringify(carrier?.id)}`); - } - sortedUniqueStrings(carrier.dependencies, `${carrier.id}.dependencies`); -} - -function entryCarrierIds(carriers) { - const carrierIds = new Set(carriers.map(({ id }) => id)); - const dependedOn = new Set(); - for (const carrier of carriers) { - for (const dependency of carrier.dependencies) { - if (carrierIds.has(dependency)) dependedOn.add(dependency); - } - } - return carriers.filter(({ id }) => !dependedOn.has(id)).map(({ id }) => id).sort(compareText); -} - -function consumerDependencyIds(carrier, selectedCarrierIds) { - if (!Array.isArray(carrier.packageDependencies)) { - // Synthetic plan tests and callers predating the frozen artifact envelope - // can still exercise graph behavior. A validated publication lock always - // carries packageDependencies and therefore always takes the scope-aware - // branch below. - return carrier.dependencies.filter((id) => selectedCarrierIds.has(id)).sort(compareText); - } - const scopes = CONSUMER_DEPENDENCY_SCOPES[carrier.ecosystem]; - if (scopes === undefined) throw error(`no public consumer dependency-scope policy for ${carrier.ecosystem}`); - return [...new Set(carrier.packageDependencies - .filter((dependency) => scopes.has(dependency.scope)) - .map((dependency) => `${dependency.ecosystem}:${dependency.name}`) - .filter((id) => selectedCarrierIds.has(id)))] - .sort(compareText); -} - -function lockedEntryClosures(carriers, entries, ecosystem) { - if (carriers.length === 0) return []; - if (entries.length === 0) { - throw error(`${ecosystem} selected carrier graph has no public consumer entry root`); - } - const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); - const covered = new Set(); - const closures = entries.map((entryCarrierId) => { - const closure = new Set(); - const pending = [entryCarrierId]; - while (pending.length > 0) { - const id = pending.pop(); - if (closure.has(id)) continue; - const carrier = byId.get(id); - if (carrier === undefined) throw error(`${ecosystem} public entry closure refers to unknown carrier ${id}`); - closure.add(id); - covered.add(id); - for (const dependency of carrier.dependencies) { - // Cross-registry edges order publication, but this registry's clean - // consumer cannot resolve them. The selected-lock validation above - // still requires those carriers, and their own surfaces prove them. - if (byId.has(dependency)) pending.push(dependency); - } - } - return { entryCarrierId, carrierIds: [...closure].sort(compareText) }; - }); - const missing = carriers.map(({ id }) => id).filter((id) => !covered.has(id)).sort(compareText); - if (missing.length > 0) { - throw error(`${ecosystem} public consumer roots omit locked carrier dependencies: ${missing.join(", ")}`); - } - return closures; -} - -function repositoryUrl(repository) { - if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository)) { - throw error(`repository must use owner/name, got ${JSON.stringify(repository)}`); - } - return `https://github.com/${repository}.git`; -} - -/** - * Derive the complete public-consumer surface from the same selected frozen - * lock used for publication. Registry byte receipts already prove every - * payload. This plan chooses dependency-graph roots for real consumer install - * probes while retaining the complete transitive carrier set as a fail-closed - * resolution assertion. - */ -export function publicConsumerPlan(lock, products, graph, { - repository = process.env.GITHUB_REPOSITORY || DEFAULT_REPOSITORY, -} = {}) { - if (lock === null || Array.isArray(lock) || typeof lock !== "object") { - throw error("publication lock must be an object"); - } - if (!SHA256_RE.test(lock.lockDigest ?? "") || !FULL_SHA_RE.test(lock.source?.commit ?? "") || !FULL_SHA_RE.test(lock.source?.tree ?? "")) { - throw error("publication lock must contain an exact digest and source commit/tree"); - } - const productRows = selectedProductRows(lock, products); - const productIds = new Set(productRows.map(({ id }) => id)); - for (const product of productRows) { - const targets = sortedUniqueStrings(product.publishTargets, `${product.id}.publishTargets`); - const unsupported = targets.filter((target) => !SUPPORTED_PUBLISH_TARGETS.has(target)); - if (unsupported.length > 0) { - throw error(`${product.id} has unsupported public consumer targets: ${unsupported.join(", ")}`); - } - } - const carriers = lock.carriers - .filter(({ product }) => productIds.has(product)) - .slice() - .sort((left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id)); - for (const carrier of carriers) assertCarrier(carrier, productIds); - if (new Set(carriers.map(({ id }) => id)).size !== carriers.length) { - throw error("publication lock contains duplicate selected carrier identities"); - } - const selectedCarrierIds = new Set(carriers.map(({ id }) => id)); - const allCarriersById = new Map(lock.carriers.map((carrier) => [carrier.id, carrier])); - for (const carrier of carriers) { - const omitted = carrier.dependencies.filter((dependency) => { - const locked = allCarriersById.get(dependency); - return locked !== undefined && !selectedCarrierIds.has(dependency); - }); - if (omitted.length > 0) { - throw error(`${carrier.id} public consumer selection omits locked dependencies: ${omitted.join(", ")}`); - } - } - const surfaces = []; - for (const ecosystem of REGISTRY_ECOSYSTEMS) { - const ecosystemCarriers = carriers.filter((carrier) => carrier.ecosystem === ecosystem); - const targetProducts = productRows - .filter((product) => product.publishTargets.some((target) => TARGET_ECOSYSTEM.get(target) === ecosystem)) - .map(({ id }) => id) - .sort(compareText); - const carrierProducts = [...new Set(ecosystemCarriers.map(({ product }) => product))].sort(compareText); - if (!sameStrings(targetProducts, carrierProducts)) { - throw error(`${ecosystem} publish targets and frozen carrier products disagree: targets=${JSON.stringify(targetProducts)}, carriers=${JSON.stringify(carrierProducts)}`); - } - if (ecosystemCarriers.length === 0) continue; - const consumerCarriers = ecosystemCarriers.map((carrier) => ({ - ...carrier, - dependencies: consumerDependencyIds(carrier, selectedCarrierIds), - })); - const entries = entryCarrierIds(consumerCarriers); - const entryClosures = lockedEntryClosures(consumerCarriers, entries, ecosystem); - surfaces.push({ - ecosystem, - carrierIds: ecosystemCarriers.map(({ id }) => id).sort(compareText), - entryCarrierIds: entries, - entryClosures, - dependencyScopes: [...CONSUMER_DEPENDENCY_SCOPES[ecosystem]].sort(compareText), - }); - } - - const productTags = productRows.map((product) => { - const config = graph?.products?.[product.id]; - if (typeof config?.tag_prefix !== "string" || config.tag_prefix.length === 0 || config.version !== product.version) { - throw error(`${product.id} release graph tag/version does not match the frozen publication lock`); - } - return { product: product.id, tag: `${config.tag_prefix}${product.version}`, commit: lock.source.commit }; - }).sort((left, right) => compareText(left.product, right.product)); - - const swiftProducts = productRows.filter((product) => product.publishTargets.includes("swift-package-source-tag")); - if (swiftProducts.length > 1) throw error("only one selected SwiftPM source-tag product is supported"); - const swift = swiftProducts.length === 0 ? null : { - product: swiftProducts[0].id, - version: swiftProducts[0].version, - tag: swiftProducts[0].version, - parentCommit: lock.source.commit, - }; - return { - repository, - repositoryUrl: repositoryUrl(repository), - products: productRows.map(({ id }) => id).sort(compareText), - surfaces, - github: { productTags, swift }, - }; -} - -function boundedRegularJson(file, maximum, context) { - const absolute = path.resolve(file); - const stat = lstatSync(absolute); - if (stat.isSymbolicLink() || !stat.isFile() || stat.size > maximum) { - throw error(`${context} must be a regular non-symlink file no larger than ${maximum} bytes`); - } - try { - const bytes = readFileSync(absolute); - return { absolute, bytes, value: JSON.parse(bytes.toString("utf8")) }; - } catch (cause) { - throw error(`${context} is not valid JSON: ${cause.message}`); - } -} - -export function sanitizedPublicEnvironment(overrides = {}, inherited = process.env) { - const env = { ...inherited }; - for (const name of Object.keys(env)) { - if ( - /(?:^|_)(?:AUTH|PASSWORD|PASSPHRASE|SECRET|TOKEN|USERNAME)(?:_|$)/iu.test(name) - || /^CARGO_(?:REGISTRIES|REGISTRY|SOURCE)_/iu.test(name) - || /^GIT_/iu.test(name) - || /^NPM_CONFIG_/iu.test(name) - || /^ORG_GRADLE_PROJECT_/iu.test(name) - || /^(?:DENO_CONFIG|DENO_DIR|DENO_IMPORT_MAP|DENO_LOCK|GRADLE_OPTS|JAVA_OPTS|JAVA_TOOL_OPTIONS|JDK_JAVA_OPTIONS|_JAVA_OPTIONS)$/iu.test(name) - ) delete env[name]; - } - for (const name of [ - "CARGO_REGISTRY_TOKEN", - "CARGO_REGISTRIES_CRATES_IO_TOKEN", - "CRATES_IO_BOOTSTRAP_TOKEN", - "DENO_AUTH_TOKENS", - "GH_TOKEN", - "GITHUB_TOKEN", - "NODE_AUTH_TOKEN", - "NPM_CONFIG__AUTH", - "NPM_CONFIG__AUTHTOKEN", - "NPM_TOKEN", - "ORG_GRADLE_PROJECT_mavenCentralPassword", - "ORG_GRADLE_PROJECT_mavenCentralUsername", - ]) { - delete env[name]; - } - return { ...env, ...overrides }; -} - -function publicCargoToolchainEnvironment(inherited = process.env, { - root = ROOT, -} = {}) { - const manifestFile = path.join(root, "rust-toolchain.toml"); - let manifest; - try { - const stat = lstatSync(manifestFile); - if (stat.isSymbolicLink() || !stat.isFile()) { - throw new Error("manifest is not a regular non-symlink file"); - } - manifest = Bun.TOML.parse(readFileSync(manifestFile, "utf8")); - } catch (cause) { - throw error(`cannot load the pinned Cargo consumer toolchain from ${manifestFile}: ${cause.message}`); - } - const toolchain = manifest?.toolchain?.channel; - if (typeof toolchain !== "string" || !EXACT_RUST_TOOLCHAIN_RE.test(toolchain)) { - throw error("rust-toolchain.toml must pin an exact stable Rust toolchain for public Cargo consumers"); - } - - const configuredRustupHome = typeof inherited.RUSTUP_HOME === "string" - ? inherited.RUSTUP_HOME.trim() - : ""; - const inheritedHome = typeof inherited.HOME === "string" && inherited.HOME.trim() !== "" - ? inherited.HOME.trim() - : typeof inherited.USERPROFILE === "string" - ? inherited.USERPROFILE.trim() - : ""; - const rustupHome = configuredRustupHome !== "" - ? configuredRustupHome - : inheritedHome === "" - ? "" - : path.join(inheritedHome, ".rustup"); - if ( - rustupHome === "" - || !path.isAbsolute(rustupHome) - || /[\0\r\n]/u.test(rustupHome) - ) { - throw error("public Cargo consumers require an absolute installed RUSTUP_HOME"); - } - let canonicalRustupHome; - try { - const stat = lstatSync(rustupHome); - if (!stat.isDirectory()) throw new Error("path is not a directory"); - canonicalRustupHome = realpathSync(rustupHome); - } catch (cause) { - throw error(`public Cargo consumer RUSTUP_HOME is unavailable at ${rustupHome}: ${cause.message}`); - } - return { - RUSTUP_HOME: canonicalRustupHome, - RUSTUP_TOOLCHAIN: toolchain, - }; -} - -export function publicCargoEnvironment(consumerRoot, inherited = process.env, { - repositoryRoot = ROOT, -} = {}) { - if ( - typeof consumerRoot !== "string" - || !path.isAbsolute(consumerRoot) - || /[\0\r\n]/u.test(consumerRoot) - ) { - throw error("public Cargo consumer root must be an absolute path"); - } - return sanitizedPublicEnvironment({ - ...publicCargoToolchainEnvironment(inherited, { root: repositoryRoot }), - CARGO_HOME: path.join(consumerRoot, "cargo-home"), - CARGO_NET_GIT_FETCH_WITH_CLI: "true", - CARGO_REGISTRIES_CRATES_IO_PROTOCOL: "sparse", - HOME: path.join(consumerRoot, "cargo-user-home"), - }, inherited); -} - -function commandText(command, args) { - return [command, ...args].map((part) => /[^A-Za-z0-9_./:@=+-]/u.test(part) ? JSON.stringify(part) : part).join(" "); -} - -function looksLikeTransientPublicVisibilityFailure(detail) { - return /(?:\b(?:404|408|425|429|500|502|503|504)\b|eai_again|econnreset|econnrefused|enotfound|etimedout|could(?:\s+not|n't)\s+find(?:\s+remote\s+ref)?|failed\s+to\s+(?:download|fetch|resolve)|no\s+matching\s+package|not\s+found|network\s+error|registry\s+index.*(?:unavailable|update)|remote\s+end\s+hung\s+up|spurious\s+network\s+error|temporary\s+failure|timed?\s*out|tls\s+(?:error|handshake))/iu.test(detail); -} - -export async function runBoundedCommand(command, args, { - cwd, - env, - deadlineMilliseconds, - input, - signal, -} = {}) { - if (signal?.aborted) { - throw error(`${commandText(command, args)} was cancelled before it could access a public endpoint`); - } - const sharedRemaining = deadlineMilliseconds - Date.now(); - if (!Number.isSafeInteger(deadlineMilliseconds) || sharedRemaining <= 0) { - throw error(`shared public-consumer deadline reached before ${commandText(command, args)}`); - } - const commandWindow = Math.min(sharedRemaining, MAX_COMMAND_ATTEMPT_MILLISECONDS); - const commandWindowIsSharedRemainder = commandWindow === sharedRemaining; - return await new Promise((resolve, reject) => { - let stdout = Buffer.alloc(0); - let stderr = Buffer.alloc(0); - let outputExceeded = false; - let timedOut = false; - const child = spawn(command, args, { - cwd, - env, - stdio: [input === undefined ? "ignore" : "pipe", "pipe", "pipe"], - }); - const append = (current, chunk) => { - if (current.length + chunk.length > MAX_COMMAND_OUTPUT_BYTES) { - outputExceeded = true; - child.kill("SIGTERM"); - return current; - } - return Buffer.concat([current, chunk]); - }; - child.stdout.on("data", (chunk) => { stdout = append(stdout, Buffer.from(chunk)); }); - child.stderr.on("data", (chunk) => { stderr = append(stderr, Buffer.from(chunk)); }); - if (input !== undefined) child.stdin.end(input); - const terminate = () => { - if (child.exitCode === null && child.signalCode === null) child.kill("SIGTERM"); - }; - let abortKillTimer; - const abort = () => { - terminate(); - abortKillTimer ??= setTimeout(() => { - if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL"); - }, 5_000); - }; - signal?.addEventListener("abort", abort, { once: true }); - const timer = setTimeout(() => { - timedOut = true; - terminate(); - }, commandWindow); - const killTimer = setTimeout(() => { - if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL"); - }, commandWindow + 5_000); - child.on("error", (cause) => { - clearTimeout(timer); - clearTimeout(killTimer); - clearTimeout(abortKillTimer); - signal?.removeEventListener("abort", abort); - reject(new PublicCommandError(`${TOOL}: ${commandText(command, args)} could not start: ${cause.message}`)); - }); - child.on("close", (status, childSignal) => { - clearTimeout(timer); - clearTimeout(killTimer); - clearTimeout(abortKillTimer); - signal?.removeEventListener("abort", abort); - if (status === 0 && !timedOut && !outputExceeded && !signal?.aborted) { - resolve({ stdout: stdout.toString("utf8"), stderr: stderr.toString("utf8") }); - return; - } - const detail = stderr.toString("utf8").trim() || stdout.toString("utf8").trim(); - const reason = outputExceeded - ? `exceeded ${MAX_COMMAND_OUTPUT_BYTES} output bytes` - : timedOut - ? "reached the shared public-consumer deadline" - : signal?.aborted - ? "was cancelled after a peer consumer probe failed" - : `failed with status ${status ?? ``}`; - const rendered = `${commandText(command, args)} ${reason}${detail ? `: ${detail.slice(-8_192)}` : ""}`; - reject(new PublicCommandError(`${TOOL}: ${rendered}`, { - retryable: !signal?.aborted && ( - (timedOut && !commandWindowIsSharedRemainder) - || (!timedOut && looksLikeTransientPublicVisibilityFailure(detail)) - ), - })); - }); - }); -} - -async function boundedRetryDelay(milliseconds, deadlineMilliseconds, signal) { - if (signal?.aborted) throw error("public consumer retry cancelled after a peer surface failed"); - if (deadlineMilliseconds - Date.now() <= milliseconds + 30_000) { - throw error("public consumer retry would cross the shared deadline"); - } - await new Promise((resolve, reject) => { - const finish = () => { - signal?.removeEventListener("abort", abort); - resolve(); - }; - const timer = setTimeout(finish, milliseconds); - const abort = () => { - clearTimeout(timer); - signal?.removeEventListener("abort", abort); - reject(error("public consumer retry cancelled after a peer surface failed")); - }; - signal?.addEventListener("abort", abort, { once: true }); - }); -} - -export async function runSurfaceWithRetries( - surface, - parentRoot, - deadlineMilliseconds, - signal, - execute, - { - maxAttempts = MAX_SURFACE_ATTEMPTS, - retryDelays = RETRY_DELAYS_MILLISECONDS, - } = {}, -) { - if (!Number.isSafeInteger(maxAttempts) || maxAttempts < 1 || !Array.isArray(retryDelays) || retryDelays.length < maxAttempts - 1) { - throw error("public consumer retry policy must provide one bounded non-negative delay per retry"); - } - if (retryDelays.some((delay) => !Number.isSafeInteger(delay) || delay < 0)) { - throw error("public consumer retry delays must be non-negative safe integers"); - } - let last; - for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { - const root = path.join(parentRoot, `${surface}-attempt-${String(attempt).padStart(2, "0")}`); - rmSync(root, { recursive: true, force: true }); - mkdirSync(root, { recursive: true }); - try { - return await execute(root); - } catch (cause) { - last = cause; - rmSync(root, { recursive: true, force: true }); - if (!(cause instanceof PublicCommandError) || !cause.retryable || attempt >= maxAttempts || signal?.aborted) { - throw cause; - } - const delay = retryDelays[attempt - 1]; - console.warn(`${TOOL}: ${surface} public visibility attempt ${attempt} was transient; retrying from an empty consumer/cache in ${delay / 1_000}s.`); - await boundedRetryDelay(delay, deadlineMilliseconds, signal); - } - } - throw last; -} - -function carrierRows(lock, surface) { - const ids = new Set(surface.carrierIds); - return lock.carriers.filter(({ id }) => ids.has(id)).sort((left, right) => compareText(left.id, right.id)); -} - -function resolvedSurfaceCoverage(surface, entries, rows) { - const closureByEntry = new Map(surface.entryClosures.map((entry) => [entry.entryCarrierId, entry.carrierIds])); - if (!sameStrings(entries.map(({ entryCarrierId }) => entryCarrierId), surface.entryCarrierIds)) { - throw error(`${surface.ecosystem} consumer probes omit one or more exact-lock entry roots`); - } - const merged = new Map(); - for (const row of rows.flat()) { - const prior = merged.get(row.id); - if (prior !== undefined && stableJson(prior) !== stableJson(row)) { - throw error(`${surface.ecosystem} consumer probes returned conflicting resolution evidence for ${row.id}`); - } - merged.set(row.id, row); - } - const carrierIds = new Set(surface.carrierIds); - const normalizedEntries = entries.map((entry) => { - const planned = new Set(closureByEntry.get(entry.entryCarrierId) ?? []); - const resolvedCarrierIds = sortedUniqueStrings(entry.resolvedCarrierIds, `${surface.ecosystem} ${entry.entryCarrierId} resolvedCarrierIds`); - if (!resolvedCarrierIds.includes(entry.entryCarrierId)) { - throw error(`${surface.ecosystem} public consumer entry ${entry.entryCarrierId} did not resolve itself exactly`); - } - const outside = resolvedCarrierIds.filter((id) => !planned.has(id)); - if (outside.length > 0) { - throw error(`${surface.ecosystem} public consumer entry ${entry.entryCarrierId} resolved selected carriers outside its frozen dependency closure: ${outside.join(", ")}`); - } - const missing = [...planned].filter((id) => !resolvedCarrierIds.includes(id)).sort(compareText); - if (missing.length > 0) { - throw error(`${surface.ecosystem} public consumer entry ${entry.entryCarrierId} omitted frozen platform-independent lock dependencies: ${missing.join(", ")}`); - } - return { entryCarrierId: entry.entryCarrierId, resolvedCarrierIds }; - }).sort((left, right) => compareText(left.entryCarrierId, right.entryCarrierId)); - const resolved = [...merged.values()].sort((left, right) => compareText(left.id, right.id)); - const unknown = resolved.map(({ id }) => id).filter((id) => !carrierIds.has(id)); - if (unknown.length > 0) throw error(`${surface.ecosystem} consumer probes returned unknown selected carriers: ${unknown.join(", ")}`); - if (!sameStrings(resolved.map(({ id }) => id), surface.carrierIds)) { - throw error(`${surface.ecosystem} public entry lock closures do not resolve the exhaustive frozen carrier set`); - } - return { - carrierIds: surface.carrierIds, - dependencyScopes: surface.dependencyScopes, - entryCarrierIds: surface.entryCarrierIds, - plannedEntryClosures: surface.entryClosures, - entries: normalizedEntries, - resolved, - }; -} - -function tomlString(value) { - return JSON.stringify(value); -} - -export function cargoEntryFeatureNames(metadata, carrier) { - const artifacts = Array.isArray(carrier?.artifacts) - ? carrier.artifacts.filter(({ path: artifactPath }) => typeof artifactPath === "string" && artifactPath.endsWith(".crate")) - : []; - if ( - metadata === null - || Array.isArray(metadata) - || typeof metadata !== "object" - || artifacts.length !== 1 - || !SHA256_RE.test(artifacts[0].sha256 ?? "") - || !Number.isSafeInteger(artifacts[0].size) - || artifacts[0].size <= 0 - || metadata.version?.crate !== carrier?.name - || metadata.version?.num !== carrier?.version - || metadata.version?.checksum !== artifacts[0].sha256 - || metadata.version?.crate_size !== artifacts[0].size - || metadata.version?.yanked !== false - ) { - throw error(`${carrier?.id ?? "Cargo entry"} crates.io version metadata does not match its exact frozen carrier`); - } - const merged = new Map(); - for (const [label, table] of [ - ["features", metadata.version.features], - ["features2", metadata.version.features2 ?? {}], - ]) { - if (table === null || Array.isArray(table) || typeof table !== "object") { - throw error(`${carrier.id} crates.io ${label} must be a feature table`); - } - for (const [name, members] of Object.entries(table)) { - if ( - typeof name !== "string" - || name.length === 0 - || /[\0\r\n]/u.test(name) - || !Array.isArray(members) - || members.some((member) => typeof member !== "string" || member.length === 0 || /[\0\r\n]/u.test(member)) - ) { - throw error(`${carrier.id} crates.io metadata contains an invalid Cargo feature declaration`); - } - const prior = merged.get(name); - if (prior !== undefined && stableJson(prior) !== stableJson(members)) { - throw error(`${carrier.id} crates.io features and features2 disagree for ${name}`); - } - merged.set(name, members); - } - } - // Cargo resolves target-specific dependencies for every target into the - // lockfile, but it deliberately omits optional dependencies whose features - // are not enabled. Resolve every public opt-in feature so the anonymous lock - // probe covers the complete frozen carrier closure. The crates.io checksum - // above binds this feature metadata to the same immutable .crate bytes - // already proven by the exhaustive registry receipt. - return [...merged.keys()].filter((name) => name !== "default").sort(compareText); -} - -async function boundedResponseJson(response, label) { - const declared = response.headers.get("content-length"); - if (declared !== null) { - const bytes = Number(declared); - if (!Number.isSafeInteger(bytes) || bytes < 0 || bytes > MAX_CRATES_IO_METADATA_BYTES) { - await response.body?.cancel?.().catch(() => {}); - throw error(`${label} returned an invalid or oversized Content-Length`); - } - } - const reader = response.body?.getReader?.(); - if (reader === undefined) { - throw error(`${label} returned no bounded response body`); - } - const chunks = []; - let size = 0; - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > MAX_CRATES_IO_METADATA_BYTES) { - await reader.cancel().catch(() => {}); - throw error(`${label} response exceeds ${MAX_CRATES_IO_METADATA_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - } finally { - reader.releaseLock(); - } - try { - return JSON.parse(Buffer.concat(chunks, size).toString("utf8")); - } catch (cause) { - throw error(`${label} returned invalid JSON: ${cause.message}`); - } -} - -async function cratesIoEntryFeatureNames(carrier, deadlineMilliseconds, signal) { - const crate = encodeURIComponent(carrier.name); - const version = encodeURIComponent(carrier.version); - const url = `${CRATES_IO_API}/crates/${crate}/${version}`; - let lastFailure = ""; - for (let attempt = 0; attempt < CRATES_IO_FEATURE_ATTEMPTS; attempt += 1) { - if (signal?.aborted) throw error(`${carrier.id} crates.io feature lookup was cancelled`); - const remaining = deadlineMilliseconds - Date.now(); - if (remaining <= 0) throw error(`shared public-consumer deadline reached before resolving ${carrier.id} features`); - const controller = new AbortController(); - const timeout = setTimeout( - () => controller.abort(), - Math.min(remaining, CRATES_IO_REQUEST_TIMEOUT_MILLISECONDS), - ); - const abort = () => controller.abort(); - signal?.addEventListener("abort", abort, { once: true }); - let retryHeaders; - try { - const response = await fetch(url, { - headers: { - Accept: "application/json", - "User-Agent": CRATES_IO_USER_AGENT, - }, - redirect: "follow", - signal: controller.signal, - }); - if (response.ok) { - return cargoEntryFeatureNames(await boundedResponseJson(response, carrier.id), carrier); - } - retryHeaders = response.headers; - await response.body?.cancel?.().catch(() => {}); - if (!registryStatusRetryable(response.status)) { - throw new PublicCommandError(`${TOOL}: crates.io returned HTTP ${response.status} for exact carrier ${carrier.id}`); - } - lastFailure = `HTTP ${response.status}`; - } catch (cause) { - if (cause instanceof PublicCommandError || (cause instanceof Error && cause.message.startsWith(`${TOOL}:`))) { - throw cause; - } - if (signal?.aborted) throw error(`${carrier.id} crates.io feature lookup was cancelled`); - lastFailure = cause instanceof Error ? cause.message : String(cause); - } finally { - clearTimeout(timeout); - signal?.removeEventListener("abort", abort); - } - if (attempt + 1 < CRATES_IO_FEATURE_ATTEMPTS) { - const seconds = registryRetryDelaySeconds({ - attempt, - baseSeconds: 1, - headers: retryHeaders, - }); - await boundedRetryDelay(Math.ceil(seconds * 1_000), deadlineMilliseconds, signal); - } - } - throw new PublicCommandError( - `${TOOL}: failed to resolve checksum-bound crates.io features for ${carrier.id}: ${lastFailure}`, - { retryable: true }, - ); -} - -export function validateCargoResolution(lockText, carriers, requiredCarrierIds = carriers.map(({ id }) => id)) { - let parsed; - try { - parsed = Bun.TOML.parse(lockText); - } catch (cause) { - throw error(`clean Cargo.lock is invalid: ${cause.message}`); - } - const packages = Array.isArray(parsed.package) ? parsed.package : []; - const byName = new Map(carriers.map((carrier) => [carrier.name, carrier])); - const rows = []; - for (const entry of packages) { - const carrier = byName.get(entry?.name); - if (carrier === undefined) continue; - if (entry.version !== carrier.version) { - throw error(`${carrier.id} resolved substituted Cargo version ${entry.version}, expected exact ${carrier.version}`); - } - if (entry.source !== "registry+https://github.com/rust-lang/crates.io-index") { - throw error(`${carrier.id}@${carrier.version} resolved through non-public or substituted Cargo source ${JSON.stringify(entry.source)}`); - } - if (!SHA256_RE.test(entry.checksum ?? "")) { - throw error(`${carrier.id}@${carrier.version} clean resolution has no crates.io checksum`); - } - rows.push({ id: carrier.id, version: carrier.version, checksum: entry.checksum }); - } - const ids = rows.map(({ id }) => id); - if (new Set(ids).size !== ids.length) throw error("clean Cargo resolution contains duplicate exact selected carrier identities"); - const missing = requiredCarrierIds.filter((id) => !ids.includes(id)); - if (missing.length > 0) throw error(`clean Cargo resolution omitted required exact carriers: ${missing.join(", ")}`); - return rows.sort((left, right) => compareText(left.id, right.id)); -} - -async function runCargoSurface({ lock, surface, root, deadlineMilliseconds, signal }) { - const directory = path.join(root, "cargo"); - const home = path.join(root, "cargo-home"); - mkdirSync(home, { recursive: true }); - const carriers = carrierRows(lock, surface); - const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); - const env = publicCargoEnvironment(root); - const entries = []; - const rows = []; - for (const [index, entryCarrierId] of surface.entryCarrierIds.entries()) { - const carrier = byId.get(entryCarrierId); - const features = await cratesIoEntryFeatureNames(carrier, deadlineMilliseconds, signal); - const featureClause = features.length === 0 ? "" : `, features = ${tomlString(features)}`; - const consumer = path.join(directory, `entry-${String(index).padStart(3, "0")}`); - mkdirSync(path.join(consumer, "src"), { recursive: true }); - writeFileSync( - path.join(consumer, "Cargo.toml"), - `[package]\nname = "oliphaunt-public-consumer-smoke-${String(index).padStart(3, "0")}"\nversion = "0.0.0"\nedition = "2021"\npublish = false\n\n[dependencies]\nlocked_entry = { package = ${tomlString(carrier.name)}, version = ${tomlString(`=${carrier.version}`)}${featureClause} }\n`, - ); - writeFileSync(path.join(consumer, "src/lib.rs"), "// dependency resolution only; immutable receipts prove target payload bytes.\n"); - await runBoundedCommand("cargo", ["generate-lockfile"], { cwd: consumer, env, deadlineMilliseconds, signal }); - const resolved = validateCargoResolution( - readFileSync(path.join(consumer, "Cargo.lock"), "utf8"), - carriers, - [entryCarrierId], - ); - rows.push(resolved); - entries.push({ entryCarrierId, resolvedCarrierIds: resolved.map(({ id }) => id) }); - } - return { - surface: "cargo", - mode: "anonymous-public-independent-entry-all-feature-resolution-no-compile", - registry: "https://crates.io", - ...resolvedSurfaceCoverage(surface, entries, rows), - receiptCoveredWithoutPayloadFetchCarrierIds: surface.carrierIds, - }; -} - -function npmPackagePath(root, packageName) { - return path.join(root, "node_modules", ...packageName.split("/")); -} - -export function validateNpmResolution(packageLock, carriers, requiredEntryIds, nodeModules) { - if (packageLock === null || Array.isArray(packageLock) || typeof packageLock !== "object" || packageLock.lockfileVersion < 3) { - throw error("clean npm install must emit package-lock v3 or newer"); - } - const packages = packageLock.packages; - if (packages === null || Array.isArray(packages) || typeof packages !== "object") { - throw error("clean npm package lock has no packages map"); - } - const entries = new Set(requiredEntryIds); - const resolved = []; - for (const carrier of carriers) { - const suffix = `node_modules/${carrier.name}`; - const matches = Object.entries(packages).filter(([key]) => key === suffix || key.endsWith(`/${suffix}`)); - if (matches.length === 0) { - if (entries.has(carrier.id)) throw error(`${carrier.id}@${carrier.version} is missing from the clean npm lock`); - continue; - } - if (matches.length !== 1 || matches[0][1]?.version !== carrier.version) { - throw error(`${carrier.id}@${carrier.version} must be the only selected version in the clean npm lock; found ${matches.length}`); - } - const row = matches[0][1]; - if ( - row.link === true - || typeof row.resolved !== "string" - || !row.resolved.startsWith("https://registry.npmjs.org/") - || typeof row.integrity !== "string" - || !row.integrity.startsWith("sha512-") - ) { - throw error(`${carrier.id}@${carrier.version} resolved through a non-public, linked, or integrity-free npm source`); - } - if (entries.has(carrier.id)) { - const manifestFile = path.join(npmPackagePath(nodeModules, carrier.name), "package.json"); - let installed; - try { installed = JSON.parse(readFileSync(manifestFile, "utf8")); } catch (cause) { - throw error(`${carrier.id}@${carrier.version} entry package was not installed from the public registry: ${cause.message}`); - } - if (installed.name !== carrier.name || installed.version !== carrier.version) { - throw error(`${carrier.id} installed package identity does not match ${carrier.name}@${carrier.version}`); - } - } - resolved.push({ id: carrier.id, version: carrier.version, integrity: row.integrity }); - } - resolved.sort((left, right) => compareText(left.id, right.id)); - const installedCarrierIds = carriers - .filter((carrier) => { - try { return statSync(path.join(npmPackagePath(nodeModules, carrier.name), "package.json")).isFile(); } catch { return false; } - }) - .map(({ id }) => id) - .sort(compareText); - return { resolved, installedCarrierIds }; -} - -async function runNpmSurface({ lock, surface, root, deadlineMilliseconds, signal }) { - const directory = path.join(root, "npm"); - const home = path.join(root, "npm-home"); - mkdirSync(directory, { recursive: true }); - mkdirSync(home, { recursive: true }); - const carriers = carrierRows(lock, surface); - const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); - const userConfig = path.join(home, ".npmrc"); - const globalConfig = path.join(home, "global.npmrc"); - writeFileSync(userConfig, "registry=https://registry.npmjs.org/\nalways-auth=false\n"); - writeFileSync(globalConfig, "registry=https://registry.npmjs.org/\nalways-auth=false\n"); - const env = sanitizedPublicEnvironment({ - HOME: home, - NPM_CONFIG_CACHE: path.join(root, "npm-cache"), - NPM_CONFIG_GLOBALCONFIG: globalConfig, - NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/", - NPM_CONFIG_USERCONFIG: userConfig, - }); - const entries = []; - const rows = []; - const installed = new Set(); - for (const [index, entryCarrierId] of surface.entryCarrierIds.entries()) { - const carrier = byId.get(entryCarrierId); - const consumer = path.join(directory, `entry-${String(index).padStart(3, "0")}`); - mkdirSync(consumer, { recursive: true }); - writeFileSync(path.join(consumer, "package.json"), `${JSON.stringify({ - name: `oliphaunt-public-consumer-smoke-${String(index).padStart(3, "0")}`, - version: "0.0.0", - private: true, - dependencies: { [carrier.name]: carrier.version }, - }, null, 2)}\n`); - await runBoundedCommand("npm", [ - "install", - "--ignore-scripts", - "--no-audit", - "--no-fund", - "--omit=peer", - "--registry=https://registry.npmjs.org/", - ], { cwd: consumer, env, deadlineMilliseconds, signal }); - const lockJson = JSON.parse(readFileSync(path.join(consumer, "package-lock.json"), "utf8")); - const result = validateNpmResolution(lockJson, carriers, [entryCarrierId], consumer); - rows[index] = result.resolved; - entries[index] = { entryCarrierId, resolvedCarrierIds: result.resolved.map(({ id }) => id) }; - for (const id of result.installedCarrierIds) installed.add(id); - } - return { - surface: "npm", - mode: "anonymous-public-independent-entry-host-install-and-lock-resolution", - registry: "https://registry.npmjs.org", - host: `${process.platform}-${process.arch}`, - ...resolvedSurfaceCoverage(surface, entries, rows), - installedCarrierIds: [...installed].sort(compareText), - receiptCoveredNotHostInstalledCarrierIds: surface.carrierIds.filter((id) => !installed.has(id)).sort(compareText), - }; -} - -function mavenCoordinate(name, version) { - const parts = name.split(":"); - if (parts.length !== 2 || parts.some((value) => value.length === 0)) { - throw error(`invalid locked Maven coordinate ${JSON.stringify(name)}`); - } - return `${name}:${version}`; -} - -export function validateMavenResolution(output, carriers, entryCarrierIds = carriers.map(({ id }) => id)) { - const prefix = "OLIPHAUNT_PUBLIC_COMPONENT\t"; - const rows = output.split(/\r?\n/u) - .filter((line) => line.startsWith(prefix)) - .map((line) => line.slice(prefix.length).split("\t")); - if (rows.some((parts) => parts.length !== 4)) throw error("clean Maven resolution emitted malformed component evidence"); - const byName = new Map(carriers.map((carrier) => [carrier.name, carrier])); - const resolvedByEntry = new Map(entryCarrierIds.map((id) => [id, new Map()])); - for (const [entryCarrierId, group, artifact, version] of rows) { - const entry = resolvedByEntry.get(entryCarrierId); - if (entry === undefined) throw error(`clean Maven resolution emitted unknown entry root ${entryCarrierId}`); - const carrier = byName.get(`${group}:${artifact}`); - if (carrier === undefined) continue; - if (version !== carrier.version) { - throw error(`${carrier.id} resolved substituted Maven version ${version}, expected exact ${carrier.version}`); - } - entry.set(carrier.id, { id: carrier.id, version: carrier.version }); - } - const entries = entryCarrierIds.map((entryCarrierId) => { - const resolved = resolvedByEntry.get(entryCarrierId); - if (!resolved.has(entryCarrierId)) { - throw error(`${entryCarrierId} was omitted from its independent clean Maven Central resolution`); - } - return { entryCarrierId, resolvedCarrierIds: [...resolved.keys()].sort(compareText) }; - }); - const resolved = new Map(); - for (const values of resolvedByEntry.values()) { - for (const [id, row] of values) resolved.set(id, row); - } - return { entries, resolved: [...resolved.values()].sort((left, right) => compareText(left.id, right.id)) }; -} - -export async function runMavenSurface({ lock, surface, root, deadlineMilliseconds, signal }) { - const directory = path.join(root, "maven"); - mkdirSync(directory, { recursive: true }); - const carriers = carrierRows(lock, surface); - const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); - writeFileSync(path.join(directory, "settings.gradle"), "rootProject.name = 'oliphaunt-public-consumer-smoke'\n"); - const probes = surface.entryCarrierIds.map((entryCarrierId, index) => ({ - carrier: byId.get(entryCarrierId), - configuration: `smoke${String(index).padStart(3, "0")}`, - entryCarrierId, - })); - const configurations = probes.map(({ configuration }) => ` ${configuration} {\n canBeConsumed = false\n canBeResolved = true\n }`); - const dependencies = probes.map(({ carrier, configuration }) => - ` ${configuration}(${JSON.stringify(mavenCoordinate(carrier.name, carrier.version))}) { version { strictly(${JSON.stringify(carrier.version)}) } }`); - const probeRows = probes.map(({ configuration, entryCarrierId }) => - ` [${JSON.stringify(entryCarrierId)}, ${JSON.stringify(configuration)}]`).join(",\n"); - writeFileSync(path.join(directory, "build.gradle"), ` -repositories { - mavenCentral() - google() -} - -configurations { -${configurations.join("\n")} -} - -dependencies { -${dependencies.join("\n")} -} - -tasks.register("resolveOliphauntPublicConsumers") { - doLast { - def probes = [ -${probeRows} - ] - probes.each { probe -> - def entryCarrierId = probe[0] - def configuration = configurations.getByName(probe[1]) - configuration.files - def ids = configuration.incoming.resolutionResult.allComponents - .collect { it.id } - .findAll { it instanceof org.gradle.api.artifacts.component.ModuleComponentIdentifier } - .collect { "${"$"}{it.group}\\t${"$"}{it.module}\\t${"$"}{it.version}" } - .toSorted() - ids.each { println("OLIPHAUNT_PUBLIC_COMPONENT\\t" + entryCarrierId + "\\t" + it) } - } - } -} -`); - const wrapper = path.join(ROOT, "src/sdks/kotlin/gradlew"); - if (!statSync(wrapper, { throwIfNoEntry: false })?.isFile()) throw error("Gradle wrapper is unavailable"); - const env = sanitizedPublicEnvironment({ - GRADLE_USER_HOME: path.join(root, "gradle-home"), - HOME: path.join(root, "gradle-user-home"), - }); - const result = await runBoundedCommand(wrapper, [ - "--no-daemon", - "--console=plain", - "--project-dir", - directory, - "resolveOliphauntPublicConsumers", - ], { cwd: directory, env, deadlineMilliseconds, signal }); - const resolution = validateMavenResolution(result.stdout, carriers, surface.entryCarrierIds); - return { - surface: "maven", - mode: "anonymous-public-independent-entry-coordinate-resolution-no-compile", - registries: ["https://repo1.maven.org/maven2", "https://dl.google.com/dl/android/maven2"], - ...resolvedSurfaceCoverage(surface, resolution.entries, [resolution.resolved]), - }; -} - -function gitEnvironment(root) { - const home = path.join(root, "git-home"); - mkdirSync(home, { recursive: true }); - return sanitizedPublicEnvironment({ - GIT_ASKPASS: "", - GIT_CONFIG_GLOBAL: path.join(root, "empty-gitconfig"), - GIT_CONFIG_NOSYSTEM: "1", - GIT_TERMINAL_PROMPT: "0", - HOME: home, - SSH_ASKPASS: "", - }); -} - -async function git(commandArgs, options) { - return await runBoundedCommand("git", [ - "-c", "credential.helper=", - "-c", "http.extraHeader=", - ...commandArgs, - ], options); -} - -async function runGithubSurface({ plan, root, deadlineMilliseconds, signal }) { - const directory = path.join(root, "github.git"); - const env = gitEnvironment(root); - await git(["init", "--bare", directory], { cwd: root, env, deadlineMilliseconds, signal }); - const tags = [...plan.github.productTags.map(({ tag }) => tag)]; - if (plan.github.swift !== null) tags.push(plan.github.swift.tag); - const uniqueTags = [...new Set(tags)].sort(compareText); - await git([ - "--git-dir", directory, - "fetch", "--no-tags", "--force", plan.repositoryUrl, - ...uniqueTags.map((tag) => `refs/tags/${tag}:refs/tags/${tag}`), - ], { cwd: root, env, deadlineMilliseconds, signal }); - const resolvedProductTags = []; - for (const row of plan.github.productTags) { - const result = await git(["--git-dir", directory, "rev-parse", `${row.tag}^{commit}`], { - cwd: root, env, deadlineMilliseconds, signal, - }); - const commit = result.stdout.trim(); - if (commit !== row.commit) throw error(`anonymous public tag ${row.tag} resolves to ${commit}, not exact ${row.commit}`); - resolvedProductTags.push(row); - } - let swift = null; - if (plan.github.swift !== null) { - const row = plan.github.swift; - const commitResult = await git(["--git-dir", directory, "rev-parse", `${row.tag}^{commit}`], { - cwd: root, env, deadlineMilliseconds, signal, - }); - const commit = commitResult.stdout.trim(); - const parentsResult = await git(["--git-dir", directory, "rev-list", "--parents", "-n", "1", commit], { - cwd: root, env, deadlineMilliseconds, signal, - }); - const parents = parentsResult.stdout.trim().split(/\s+/u).slice(1); - if (parents.length !== 1 || parents[0] !== row.parentCommit) { - throw error(`SwiftPM source tag ${row.tag} must be a single synthetic child of exact ${row.parentCommit}`); - } - const checkout = path.join(root, "swift-source"); - mkdirSync(checkout, { recursive: true }); - await git(["--git-dir", directory, "--work-tree", checkout, "checkout", "--force", commit, "--", "."], { - cwd: root, env, deadlineMilliseconds, signal, - }); - const swiftEnv = sanitizedPublicEnvironment({ - CLANG_MODULE_CACHE_PATH: path.join(root, "swift-module-cache"), - HOME: path.join(root, "swift-home"), - SWIFTPM_MODULECACHE_OVERRIDE: path.join(root, "swift-module-cache"), - }); - const manifest = await runBoundedCommand("swift", ["package", "dump-package"], { - cwd: checkout, env: swiftEnv, deadlineMilliseconds, signal, - }); - let packageDescription; - try { packageDescription = JSON.parse(manifest.stdout); } catch (cause) { - throw error(`SwiftPM source tag ${row.tag} package manifest is invalid: ${cause.message}`); - } - if (typeof packageDescription.name !== "string" || packageDescription.name.length === 0) { - throw error(`SwiftPM source tag ${row.tag} has no package name`); - } - const treeResult = await git(["--git-dir", directory, "rev-parse", `${commit}^{tree}`], { - cwd: root, env, deadlineMilliseconds, signal, - }); - swift = { - ...row, - commit, - tree: treeResult.stdout.trim(), - packageName: packageDescription.name, - proofScope: "anonymous-source-tag-and-manifest-only", - }; - } - return { - surface: "github", - mode: "anonymous-public-exact-tag-resolution", - repository: plan.repository, - productTags: resolvedProductTags, - swift, - limitation: plan.github.swift === null - ? null - : "Draft GitHub binaryTarget assets are not anonymously public before promotion; their exact bytes are covered by the bound immutable GitHub receipt, not this source-tag probe.", - }; -} - -export function publicConsumerEvidence({ lock, plan, registryReceiptSha256, githubReceiptDigest, surfaces }) { - const result = { - schema: PUBLIC_CONSUMER_EVIDENCE_SCHEMA, - lockDigest: lock.lockDigest, - source: lock.source, - products: plan.products, - repository: plan.repository, - proofScope: { - host: `${process.platform}-${process.arch}`, - statement: "Anonymous public dependency resolution/install on the publish host; same-SHA CI and immutable receipts cover the complete supported platform artifact matrix.", - }, - receiptBindings: { - githubReceiptDigest, - registryReceiptSha256, - }, - surfaces: surfaces.slice().sort((left, right) => compareText(left.surface, right.surface)), - }; - result.evidenceDigest = sha256Bytes(stableJson(result)); - return result; -} - -export function validatePublicConsumerEvidence(evidence, lock, plan) { - if (evidence === null || Array.isArray(evidence) || typeof evidence !== "object") throw error("public consumer evidence must be an object"); - if (evidence.schema !== PUBLIC_CONSUMER_EVIDENCE_SCHEMA) throw error(`public consumer evidence schema must be ${PUBLIC_CONSUMER_EVIDENCE_SCHEMA}`); - if (evidence.lockDigest !== lock.lockDigest || stableJson(evidence.source) !== stableJson(lock.source)) { - throw error("public consumer evidence is not bound to the active publication lock"); - } - if (!sameStrings(evidence.products ?? [], plan.products)) throw error("public consumer evidence products differ from the exact lock selection"); - if (!SHA256_RE.test(evidence.receiptBindings?.registryReceiptSha256 ?? "") || !SHA256_RE.test(evidence.receiptBindings?.githubReceiptDigest ?? "")) { - throw error("public consumer evidence has invalid immutable receipt bindings"); - } - const expectedSurfaces = [...plan.surfaces.map(({ ecosystem }) => ecosystem), "github"].sort(compareText); - const actualSurfaces = Array.isArray(evidence.surfaces) ? evidence.surfaces.map(({ surface }) => surface) : []; - if (!sameStrings(actualSurfaces, expectedSurfaces)) { - throw error(`public consumer evidence surface coverage mismatch: expected=${JSON.stringify(expectedSurfaces)}, actual=${JSON.stringify(actualSurfaces)}`); - } - for (const surface of plan.surfaces) { - const observed = evidence.surfaces.find(({ surface: name }) => name === surface.ecosystem); - if (!sameStrings(observed?.carrierIds ?? [], surface.carrierIds) || !sameStrings(observed?.entryCarrierIds ?? [], surface.entryCarrierIds)) { - throw error(`${surface.ecosystem} public consumer evidence omits exact-lock carriers or entry roots`); - } - if (stableJson(observed?.plannedEntryClosures) !== stableJson(surface.entryClosures)) { - throw error(`${surface.ecosystem} public consumer evidence changed the frozen entry dependency closures`); - } - if (stableJson(observed?.dependencyScopes) !== stableJson(surface.dependencyScopes)) { - throw error(`${surface.ecosystem} public consumer evidence changed the package-manager dependency scope policy`); - } - const coverage = resolvedSurfaceCoverage(surface, observed?.entries ?? [], [observed?.resolved ?? []]); - for (const field of [ - "carrierIds", - "dependencyScopes", - "entryCarrierIds", - "plannedEntryClosures", - "entries", - "resolved", - ]) { - if (stableJson(observed?.[field]) !== stableJson(coverage[field])) { - throw error(`${surface.ecosystem} public consumer evidence has non-canonical ${field} coverage`); - } - } - if (surface.ecosystem === "npm") { - const installed = sortedUniqueStrings(observed?.installedCarrierIds ?? [], "npm installedCarrierIds"); - const resolved = new Set(coverage.resolved.map(({ id }) => id)); - if (installed.some((id) => !resolved.has(id)) || stableJson(installed) !== stableJson(observed.installedCarrierIds)) { - throw error("npm host-installed carriers must be a canonical subset of its exact public resolution"); - } - const notInstalled = surface.carrierIds.filter((id) => !installed.includes(id)).sort(compareText); - if (stableJson(observed.receiptCoveredNotHostInstalledCarrierIds) !== stableJson(notInstalled)) { - throw error("npm evidence must explicitly distinguish exhaustive lock resolution from the publish-host installed subset"); - } - } - if ( - surface.ecosystem === "cargo" - && stableJson(observed.receiptCoveredWithoutPayloadFetchCarrierIds) !== stableJson(surface.carrierIds) - ) { - throw error("Cargo evidence must explicitly distinguish registry resolution from receipt-proved payload bytes"); - } - } - const github = evidence.surfaces.find(({ surface }) => surface === "github"); - if (stableJson(github?.productTags) !== stableJson(plan.github.productTags)) { - throw error("GitHub public consumer evidence does not resolve every exact product tag"); - } - if (plan.github.swift === null ? github?.swift !== null : github?.swift?.tag !== plan.github.swift.tag) { - throw error("GitHub public consumer evidence SwiftPM source-tag coverage mismatch"); - } - const withoutDigest = structuredClone(evidence); - delete withoutDigest.evidenceDigest; - const expectedDigest = sha256Bytes(stableJson(withoutDigest)); - if (evidence.evidenceDigest !== expectedDigest) throw error(`public consumer evidence digest mismatch: expected ${expectedDigest}`); - return evidence; -} - -export function writeImmutablePublicConsumerEvidence(file, evidence) { - const absolute = path.resolve(file); - const body = `${JSON.stringify(evidence, null, 2)}\n`; - if (Buffer.byteLength(body) > MAX_EVIDENCE_BYTES) throw error(`public consumer evidence exceeds ${MAX_EVIDENCE_BYTES} bytes`); - mkdirSync(path.dirname(absolute), { recursive: true }); - const temporary = `${absolute}.tmp-${process.pid}-${randomUUID()}`; - try { - writeFileSync(temporary, body, { flag: "wx", mode: 0o644 }); - try { - linkSync(temporary, absolute); - } catch (cause) { - if (cause?.code !== "EEXIST") throw cause; - const stat = lstatSync(absolute); - if (stat.isSymbolicLink() || !stat.isFile() || stat.size > MAX_EVIDENCE_BYTES) { - throw error(`refusing to replace unsafe existing public consumer evidence ${file}`); - } - if (readFileSync(absolute, "utf8") !== body) { - throw error(`refusing to replace non-identical immutable public consumer evidence ${file}`); - } - } - } finally { - try { unlinkSync(temporary); } catch {} - } - return absolute; -} - -function parseArgs(argv) { - const options = { - githubReceipt: "", - lock: DEFAULT_PUBLICATION_LOCK, - output: DEFAULT_OUTPUT, - productsJson: "", - registryReceipts: "", - repository: process.env.GITHUB_REPOSITORY || DEFAULT_REPOSITORY, - }; - for (let index = 0; index < argv.length; index += 1) { - const argument = argv[index]; - if (argument === "--help" || argument === "-h") return { help: true }; - const separator = argument.indexOf("="); - const flag = separator === -1 ? argument : argument.slice(0, separator); - const value = separator === -1 ? argv[++index] : argument.slice(separator + 1); - if (value === undefined || value.length === 0) throw error(`${flag} requires a value`); - if (flag === "--github-release-receipt") options.githubReceipt = value; - else if (flag === "--publication-lock") options.lock = value; - else if (flag === "--output") options.output = value; - else if (flag === "--products-json") options.productsJson = value; - else if (flag === "--registry-receipts") options.registryReceipts = value; - else if (flag === "--repository") options.repository = value; - else throw error(`unknown argument ${argument}`); - } - if (!options.productsJson || !options.registryReceipts || !options.githubReceipt) { - throw error("--products-json, --registry-receipts, and --github-release-receipt are required"); - } - let products; - try { products = JSON.parse(options.productsJson); } catch (cause) { throw error(`--products-json is invalid: ${cause.message}`); } - return { ...options, products }; -} - -function usage() { - console.log("usage: tools/release/public-consumer-smoke.mjs --publication-lock FILE --products-json JSON --registry-receipts FILE --github-release-receipt FILE --output FILE"); -} - -function sharedDeadlineMilliseconds() { - const timeoutSeconds = requirePositiveInteger( - process.env.PUBLIC_CONSUMER_SMOKE_TIMEOUT_SECONDS, - "PUBLIC_CONSUMER_SMOKE_TIMEOUT_SECONDS", - DEFAULT_OVERALL_TIMEOUT_SECONDS, - ); - const reserveSeconds = requirePositiveInteger( - process.env.PUBLIC_CONSUMER_FINALIZATION_RESERVE_SECONDS, - "PUBLIC_CONSUMER_FINALIZATION_RESERVE_SECONDS", - DEFAULT_POST_SMOKE_RESERVE_SECONDS, - ); - let deadline = Date.now() + timeoutSeconds * 1_000; - const hardRaw = process.env.REGISTRY_JOB_HARD_DEADLINE_EPOCH?.trim(); - if (hardRaw) { - if (!/^[1-9][0-9]*$/u.test(hardRaw)) throw error("REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp"); - const hard = Number(hardRaw) * 1_000; - if (!Number.isSafeInteger(hard)) throw error("REGISTRY_JOB_HARD_DEADLINE_EPOCH exceeds the safe timestamp range"); - deadline = Math.min(deadline, hard - reserveSeconds * 1_000); - } - if (deadline - Date.now() < 30_000) { - throw error("less than 30 seconds remain before the shared public-consumer deadline after preserving final promotion reserve"); - } - return deadline; -} - -async function main(argv) { - const args = parseArgs(argv); - if (args.help) { - usage(); - return; - } - const lock = loadPublicationLock(path.resolve(ROOT, args.lock)); - const graph = loadGraph(TOOL); - const plan = publicConsumerPlan(lock, args.products, graph, { repository: args.repository }); - const registryEvidence = validateRegistryReceiptEvidence(args.registryReceipts, lock, { - products: plan.products, - ecosystems: REGISTRY_ECOSYSTEMS, - receiptMode: "sealed", - }); - const githubFile = boundedRegularJson(args.githubReceipt, MAX_RECEIPT_BYTES, "GitHub release receipt"); - const githubReceipt = validateGithubAttestationReceipt(githubFile.value, lock, { repo: plan.repository }); - const registryFile = boundedRegularJson(args.registryReceipts, MAX_RECEIPT_BYTES, "registry receipt evidence"); - if (registryFile.value.lockDigest !== registryEvidence.lockDigest) throw error("registry receipt changed during public consumer setup"); - - const scratch = mkdtempSync(path.join(realpathSync(tmpdir()), "oliphaunt-public-consumer-")); - const deadlineMilliseconds = sharedDeadlineMilliseconds(); - const controller = new AbortController(); - const tasks = plan.surfaces.map((surface) => runSurfaceWithRetries( - surface.ecosystem, - scratch, - deadlineMilliseconds, - controller.signal, - (root) => { - const options = { lock, plan, surface, root, deadlineMilliseconds, signal: controller.signal }; - if (surface.ecosystem === "cargo") return runCargoSurface(options); - if (surface.ecosystem === "npm") return runNpmSurface(options); - if (surface.ecosystem === "maven") return runMavenSurface(options); - throw error(`no public consumer runner for ${surface.ecosystem}`); - }, - )); - tasks.push(runSurfaceWithRetries( - "github", - scratch, - deadlineMilliseconds, - controller.signal, - (root) => runGithubSurface({ plan, root, deadlineMilliseconds, signal: controller.signal }), - )); - let surfaces; - try { - const guarded = tasks.map(async (task) => { - try { return await task; } catch (cause) { controller.abort(); throw cause; } - }); - const settled = await Promise.allSettled(guarded); - const failures = settled.filter(({ status }) => status === "rejected").map(({ reason }) => reason); - if (failures.length > 0) throw failures.length === 1 ? failures[0] : new AggregateError(failures, `${TOOL}: multiple public consumer surfaces failed`); - surfaces = settled.map(({ value }) => value); - } finally { - rmSync(scratch, { recursive: true, force: true }); - } - const evidence = publicConsumerEvidence({ - lock, - plan, - registryReceiptSha256: sha256Bytes(registryFile.bytes), - githubReceiptDigest: githubReceipt.receiptDigest, - surfaces, - }); - validatePublicConsumerEvidence(evidence, lock, plan); - writeImmutablePublicConsumerEvidence(path.resolve(ROOT, args.output), evidence); - console.log(`Verified ${plan.products.length} products across ${surfaces.length} anonymous public consumer surfaces; immutable evidence: ${path.relative(ROOT, args.output)} (${evidence.evidenceDigest}).`); -} - -if (import.meta.main) { - try { - await main(Bun.argv.slice(2)); - } catch (cause) { - console.error(cause instanceof AggregateError - ? `${cause.message}\n${cause.errors.map((item) => `- ${item instanceof Error ? item.message : String(item)}`).join("\n")}` - : cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/public-consumer-smoke.mts b/tools/release/public-consumer-smoke.mts new file mode 100644 index 000000000..be36e6cfa --- /dev/null +++ b/tools/release/public-consumer-smoke.mts @@ -0,0 +1,1542 @@ +#!/usr/bin/env bun + +import { createHash, randomUUID } from 'node:crypto'; +import { + linkSync, + lstatSync, + mkdirSync, + readFileSync, + realpathSync, + statSync, + unlinkSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { DEFAULT_PUBLICATION_LOCK, loadPublicationLock } from './publication-lock.mts'; +import { registryRetryDelaySeconds, registryStatusRetryable } from './registry-http-retry.mts'; +import { validateRegistryReceiptEvidence } from './registry-integrity.mts'; +import { compareText, loadProducts, ROOT } from './release-graph.mts'; +import { validateGithubAttestationReceipt } from './verify_github_release_attestations.mts'; + +export const PUBLIC_CONSUMER_EVIDENCE_SCHEMA = 'oliphaunt-public-consumer-smoke-v1'; + +const TOOL = 'public-consumer-smoke'; +const REGISTRY_ECOSYSTEMS = ['cargo', 'maven', 'npm']; +const SUPPORTED_PUBLISH_TARGETS = new Set([ + 'crates-io', + 'github-release', + 'github-release-assets', + 'maven-central', + 'npm', + 'swift-package-source-tag', +]); +const TARGET_ECOSYSTEM = new Map([ + ['crates-io', 'cargo'], + ['maven-central', 'maven'], + ['npm', 'npm'], +]); +const CONSUMER_DEPENDENCY_SCOPES = Object.freeze({ + cargo: new Set(['build', 'runtime']), + maven: new Set(['compile', 'runtime']), + npm: new Set(['optional', 'peer', 'runtime']), +}); +const DEFAULT_REPOSITORY = 'f0rr0/oliphaunt'; +const DEFAULT_OUTPUT = path.join(ROOT, 'target/release/public-consumer-smoke.json'); +const DEFAULT_OVERALL_TIMEOUT_SECONDS = 780; +const DEFAULT_POST_SMOKE_RESERVE_SECONDS = 600; +const MAX_RECEIPT_BYTES = 64 * 1024 * 1024; +const MAX_EVIDENCE_BYTES = 8 * 1024 * 1024; +const MAX_CRATES_IO_METADATA_BYTES = 1024 * 1024; +const CRATES_IO_API = 'https://crates.io/api/v1'; +const CRATES_IO_FEATURE_ATTEMPTS = 4; +const CRATES_IO_REQUEST_TIMEOUT_MILLISECONDS = 20_000; +const CRATES_IO_USER_AGENT = 'oliphaunt-public-consumer-smoke (https://github.com/f0rr0/oliphaunt)'; +const SHA256_RE = /^[0-9a-f]{64}$/u; +const FULL_SHA_RE = /^[0-9a-f]{40}$/u; +const EXACT_RUST_TOOLCHAIN_RE = /^[1-9][0-9]*\.[0-9]+\.[0-9]+$/u; + +class PublicCommandError extends Error { + constructor(message, { retryable = false } = {}) { + super(message); + this.retryable = retryable; + } +} + +function error(message) { + return new Error(`${TOOL}: ${message}`); +} + +function stableJson(value) { + if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`; + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort(compareText) + .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +function sha256Bytes(value) { + return createHash('sha256').update(value).digest('hex'); +} + +function sortedUniqueStrings(values, context, { allowEmpty = true } = {}) { + if ( + !Array.isArray(values) || + values.some( + (value) => typeof value !== 'string' || value.length === 0 || /[\0\r\n]/u.test(value), + ) + ) { + throw error(`${context} must be a list of non-empty single-line strings`); + } + const result = [...new Set(values)].sort(compareText); + if (result.length !== values.length) throw error(`${context} must not contain duplicates`); + if (!allowEmpty && result.length === 0) throw error(`${context} must not be empty`); + return result; +} + +function sameStrings(left, right) { + return stableJson([...left].sort(compareText)) === stableJson([...right].sort(compareText)); +} + +function requirePositiveInteger(raw, context, fallback) { + const value = + raw === undefined || raw === null || String(raw).trim() === '' + ? fallback + : Number(String(raw).trim()); + if (!Number.isSafeInteger(value) || value <= 0) { + throw error(`${context} must be a positive safe integer`); + } + return value; +} + +function selectedProductRows(lock, products) { + const requested = sortedUniqueStrings(products, 'products', { allowEmpty: false }); + const locked = lock.products.map(({ id }) => id).sort(compareText); + if (!sameStrings(requested, locked)) { + throw error( + `requested products must exactly match the frozen publication lock: requested=${JSON.stringify(requested)}, locked=${JSON.stringify(locked)}`, + ); + } + const byId = new Map(lock.products.map((product) => [product.id, product])); + return requested.map((id) => byId.get(id)); +} + +function assertCarrier(carrier, productIds) { + if ( + carrier === null || + Array.isArray(carrier) || + typeof carrier !== 'object' || + typeof carrier.id !== 'string' || + carrier.id !== `${carrier.ecosystem}:${carrier.name}` || + !REGISTRY_ECOSYSTEMS.includes(carrier.ecosystem) || + typeof carrier.name !== 'string' || + carrier.name.length === 0 || + typeof carrier.version !== 'string' || + carrier.version.length === 0 || + !productIds.has(carrier.product) || + !Array.isArray(carrier.dependencies) + ) { + throw error( + `publication lock contains an invalid selected carrier ${JSON.stringify(carrier?.id)}`, + ); + } + sortedUniqueStrings(carrier.dependencies, `${carrier.id}.dependencies`); +} + +function entryCarrierIds(carriers) { + const carrierIds = new Set(carriers.map(({ id }) => id)); + const dependedOn = new Set(); + for (const carrier of carriers) { + for (const dependency of carrier.dependencies) { + if (carrierIds.has(dependency)) dependedOn.add(dependency); + } + } + return carriers + .filter(({ id }) => !dependedOn.has(id)) + .map(({ id }) => id) + .sort(compareText); +} + +function consumerDependencyIds(carrier, selectedCarrierIds) { + if (!Array.isArray(carrier.packageDependencies)) { + // Synthetic plan tests and callers predating the frozen artifact envelope + // can still exercise graph behavior. A validated publication lock always + // carries packageDependencies and therefore always takes the scope-aware + // branch below. + return carrier.dependencies.filter((id) => selectedCarrierIds.has(id)).sort(compareText); + } + const scopes = CONSUMER_DEPENDENCY_SCOPES[carrier.ecosystem]; + if (scopes === undefined) + throw error(`no public consumer dependency-scope policy for ${carrier.ecosystem}`); + return [ + ...new Set( + carrier.packageDependencies + .filter((dependency) => scopes.has(dependency.scope)) + .map((dependency) => `${dependency.ecosystem}:${dependency.name}`) + .filter((id) => selectedCarrierIds.has(id)), + ), + ].sort(compareText); +} + +function lockedEntryClosures(carriers, entries, ecosystem) { + if (carriers.length === 0) return []; + if (entries.length === 0) { + throw error(`${ecosystem} selected carrier graph has no public consumer entry root`); + } + const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); + const covered = new Set(); + const closures = entries.map((entryCarrierId) => { + const closure = new Set(); + const pending = [entryCarrierId]; + while (pending.length > 0) { + const id = pending.pop(); + if (closure.has(id)) continue; + const carrier = byId.get(id); + if (carrier === undefined) + throw error(`${ecosystem} public entry closure refers to unknown carrier ${id}`); + closure.add(id); + covered.add(id); + for (const dependency of carrier.dependencies) { + // Cross-registry edges order publication, but this registry's clean + // consumer cannot resolve them. The selected-lock validation above + // still requires those carriers, and their own surfaces prove them. + if (byId.has(dependency)) pending.push(dependency); + } + } + return { entryCarrierId, carrierIds: [...closure].sort(compareText) }; + }); + const missing = carriers + .map(({ id }) => id) + .filter((id) => !covered.has(id)) + .sort(compareText); + if (missing.length > 0) { + throw error( + `${ecosystem} public consumer roots omit locked carrier dependencies: ${missing.join(', ')}`, + ); + } + return closures; +} + +function repositoryUrl(repository) { + if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository)) { + throw error(`repository must use owner/name, got ${JSON.stringify(repository)}`); + } + return `https://github.com/${repository}.git`; +} + +/** + * Derive the complete public-consumer surface from the same selected frozen + * lock used for publication. Registry byte receipts already prove every + * payload. This plan chooses dependency-graph roots for real consumer install + * probes while retaining the complete transitive carrier set as a fail-closed + * resolution assertion. + */ +export function publicConsumerPlan( + lock, + products, + graph, + { repository = process.env.GITHUB_REPOSITORY || DEFAULT_REPOSITORY } = {}, +) { + if (lock === null || Array.isArray(lock) || typeof lock !== 'object') { + throw error('publication lock must be an object'); + } + if ( + !SHA256_RE.test(lock.lockDigest ?? '') || + !FULL_SHA_RE.test(lock.source?.commit ?? '') || + !FULL_SHA_RE.test(lock.source?.tree ?? '') + ) { + throw error('publication lock must contain an exact digest and source commit/tree'); + } + const productRows = selectedProductRows(lock, products); + const productIds = new Set(productRows.map(({ id }) => id)); + for (const product of productRows) { + const targets = sortedUniqueStrings(product.publishTargets, `${product.id}.publishTargets`); + const unsupported = targets.filter((target) => !SUPPORTED_PUBLISH_TARGETS.has(target)); + if (unsupported.length > 0) { + throw error( + `${product.id} has unsupported public consumer targets: ${unsupported.join(', ')}`, + ); + } + } + const carriers = lock.carriers + .filter(({ product }) => productIds.has(product)) + .slice() + .sort( + (left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id), + ); + for (const carrier of carriers) assertCarrier(carrier, productIds); + if (new Set(carriers.map(({ id }) => id)).size !== carriers.length) { + throw error('publication lock contains duplicate selected carrier identities'); + } + const selectedCarrierIds = new Set(carriers.map(({ id }) => id)); + const allCarriersById = new Map(lock.carriers.map((carrier) => [carrier.id, carrier])); + for (const carrier of carriers) { + const omitted = carrier.dependencies.filter((dependency) => { + const locked = allCarriersById.get(dependency); + return locked !== undefined && !selectedCarrierIds.has(dependency); + }); + if (omitted.length > 0) { + throw error( + `${carrier.id} public consumer selection omits locked dependencies: ${omitted.join(', ')}`, + ); + } + } + const surfaces = []; + for (const ecosystem of REGISTRY_ECOSYSTEMS) { + const ecosystemCarriers = carriers.filter((carrier) => carrier.ecosystem === ecosystem); + const targetProducts = productRows + .filter((product) => + product.publishTargets.some((target) => TARGET_ECOSYSTEM.get(target) === ecosystem), + ) + .map(({ id }) => id) + .sort(compareText); + const carrierProducts = [...new Set(ecosystemCarriers.map(({ product }) => product))].sort( + compareText, + ); + if (!sameStrings(targetProducts, carrierProducts)) { + throw error( + `${ecosystem} publish targets and frozen carrier products disagree: targets=${JSON.stringify(targetProducts)}, carriers=${JSON.stringify(carrierProducts)}`, + ); + } + if (ecosystemCarriers.length === 0) continue; + const consumerCarriers = ecosystemCarriers.map((carrier) => ({ + ...carrier, + dependencies: consumerDependencyIds(carrier, selectedCarrierIds), + })); + const entries = entryCarrierIds(consumerCarriers); + const entryClosures = lockedEntryClosures(consumerCarriers, entries, ecosystem); + surfaces.push({ + ecosystem, + carrierIds: ecosystemCarriers.map(({ id }) => id).sort(compareText), + entryCarrierIds: entries, + entryClosures, + dependencyScopes: [...CONSUMER_DEPENDENCY_SCOPES[ecosystem]].sort(compareText), + }); + } + + const productTags = productRows + .map((product) => { + const config = graph?.products?.[product.id]; + if ( + typeof config?.tag_prefix !== 'string' || + config.tag_prefix.length === 0 || + config.version !== product.version + ) { + throw error( + `${product.id} release graph tag/version does not match the frozen publication lock`, + ); + } + return { + product: product.id, + tag: `${config.tag_prefix}${product.version}`, + commit: lock.source.commit, + }; + }) + .sort((left, right) => compareText(left.product, right.product)); + + const swiftProducts = productRows.filter((product) => + product.publishTargets.includes('swift-package-source-tag'), + ); + if (swiftProducts.length > 1) + throw error('only one selected SwiftPM source-tag product is supported'); + const swift = + swiftProducts.length === 0 + ? null + : { + product: swiftProducts[0].id, + version: swiftProducts[0].version, + tag: swiftProducts[0].version, + parentCommit: lock.source.commit, + }; + return { + repository, + repositoryUrl: repositoryUrl(repository), + products: productRows.map(({ id }) => id).sort(compareText), + surfaces, + github: { productTags, swift }, + }; +} + +function boundedRegularJson(file, maximum, context) { + const absolute = path.resolve(file); + const stat = lstatSync(absolute); + if (stat.isSymbolicLink() || !stat.isFile() || stat.size > maximum) { + throw error(`${context} must be a regular non-symlink file no larger than ${maximum} bytes`); + } + try { + const bytes = readFileSync(absolute); + return { absolute, bytes, value: JSON.parse(bytes.toString('utf8')) }; + } catch (cause) { + throw error(`${context} is not valid JSON: ${cause.message}`); + } +} + +export function sanitizedPublicEnvironment(overrides = {}, inherited = process.env) { + const env = { ...inherited }; + for (const name of Object.keys(env)) { + if ( + /(?:^|_)(?:AUTH|PASSWORD|PASSPHRASE|SECRET|TOKEN|USERNAME)(?:_|$)/iu.test(name) || + /^CARGO_/iu.test(name) || + /^(?:RUSTC|RUSTC_WRAPPER|RUSTC_WORKSPACE_WRAPPER|RUSTFLAGS|RUSTDOC|RUSTDOCFLAGS)$/u.test( + name, + ) || + /^GIT_/iu.test(name) || + /^NPM_CONFIG_/iu.test(name) || + /^ORG_GRADLE_PROJECT_/iu.test(name) || + /^(?:OLIPHAUNT_|LIBOLIPHAUNT_|DYLD_)/u.test(name) || + /^(?:NODE_OPTIONS|NODE_PATH|LD_LIBRARY_PATH)$/u.test(name) || + /^(?:DENO_CONFIG|DENO_DIR|DENO_IMPORT_MAP|DENO_LOCK|GRADLE_OPTS|JAVA_OPTS|JAVA_TOOL_OPTIONS|JDK_JAVA_OPTIONS|_JAVA_OPTIONS)$/iu.test( + name, + ) + ) + delete env[name]; + } + for (const name of [ + 'CARGO_REGISTRY_TOKEN', + 'CARGO_REGISTRIES_CRATES_IO_TOKEN', + 'CRATES_IO_BOOTSTRAP_TOKEN', + 'DENO_AUTH_TOKENS', + 'GH_TOKEN', + 'GITHUB_TOKEN', + 'NODE_AUTH_TOKEN', + 'NPM_CONFIG__AUTH', + 'NPM_CONFIG__AUTHTOKEN', + 'NPM_TOKEN', + 'ORG_GRADLE_PROJECT_mavenCentralPassword', + 'ORG_GRADLE_PROJECT_mavenCentralUsername', + ]) { + delete env[name]; + } + return { ...env, ...overrides }; +} + +function publicCargoToolchainEnvironment(inherited = process.env, { root = ROOT } = {}) { + const manifestFile = path.join(root, 'rust-toolchain.toml'); + let manifest; + try { + const stat = lstatSync(manifestFile); + if (stat.isSymbolicLink() || !stat.isFile()) { + throw new Error('manifest is not a regular non-symlink file'); + } + manifest = Bun.TOML.parse(readFileSync(manifestFile, 'utf8')); + } catch (cause) { + throw error( + `cannot load the pinned Cargo consumer toolchain from ${manifestFile}: ${cause.message}`, + ); + } + const toolchain = manifest?.toolchain?.channel; + if (typeof toolchain !== 'string' || !EXACT_RUST_TOOLCHAIN_RE.test(toolchain)) { + throw error( + 'rust-toolchain.toml must pin an exact stable Rust toolchain for public Cargo consumers', + ); + } + + const configuredRustupHome = + typeof inherited.RUSTUP_HOME === 'string' ? inherited.RUSTUP_HOME.trim() : ''; + const inheritedHome = + typeof inherited.HOME === 'string' && inherited.HOME.trim() !== '' + ? inherited.HOME.trim() + : typeof inherited.USERPROFILE === 'string' + ? inherited.USERPROFILE.trim() + : ''; + const rustupHome = + configuredRustupHome !== '' + ? configuredRustupHome + : inheritedHome === '' + ? '' + : path.join(inheritedHome, '.rustup'); + if (rustupHome === '' || !path.isAbsolute(rustupHome) || /[\0\r\n]/u.test(rustupHome)) { + throw error('public Cargo consumers require an absolute installed RUSTUP_HOME'); + } + let canonicalRustupHome; + try { + const stat = lstatSync(rustupHome); + if (!stat.isDirectory()) throw new Error('path is not a directory'); + canonicalRustupHome = realpathSync(rustupHome); + } catch (cause) { + throw error( + `public Cargo consumer RUSTUP_HOME is unavailable at ${rustupHome}: ${cause.message}`, + ); + } + return { + RUSTUP_HOME: canonicalRustupHome, + RUSTUP_TOOLCHAIN: toolchain, + }; +} + +export function publicCargoEnvironment( + consumerRoot, + inherited = process.env, + { repositoryRoot = ROOT } = {}, +) { + if ( + typeof consumerRoot !== 'string' || + !path.isAbsolute(consumerRoot) || + /[\0\r\n]/u.test(consumerRoot) + ) { + throw error('public Cargo consumer root must be an absolute path'); + } + return sanitizedPublicEnvironment( + { + ...publicCargoToolchainEnvironment(inherited, { root: repositoryRoot }), + CARGO_HOME: path.join(consumerRoot, 'cargo-home'), + CARGO_NET_GIT_FETCH_WITH_CLI: 'true', + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: 'sparse', + HOME: path.join(consumerRoot, 'cargo-user-home'), + }, + inherited, + ); +} + +function carrierRows(lock, surface) { + const ids = new Set(surface.carrierIds); + return lock.carriers + .filter(({ id }) => ids.has(id)) + .sort((left, right) => compareText(left.id, right.id)); +} + +function resolvedSurfaceCoverage(surface, entries, rows) { + const closureByEntry = new Map( + surface.entryClosures.map((entry) => [entry.entryCarrierId, entry.carrierIds]), + ); + if ( + !sameStrings( + entries.map(({ entryCarrierId }) => entryCarrierId), + surface.entryCarrierIds, + ) + ) { + throw error(`${surface.ecosystem} consumer probes omit one or more exact-lock entry roots`); + } + const merged = new Map(); + for (const row of rows.flat()) { + const prior = merged.get(row.id); + if (prior !== undefined && stableJson(prior) !== stableJson(row)) { + throw error( + `${surface.ecosystem} consumer probes returned conflicting resolution evidence for ${row.id}`, + ); + } + merged.set(row.id, row); + } + const carrierIds = new Set(surface.carrierIds); + const normalizedEntries = entries + .map((entry) => { + const planned = new Set(closureByEntry.get(entry.entryCarrierId) ?? []); + const resolvedCarrierIds = sortedUniqueStrings( + entry.resolvedCarrierIds, + `${surface.ecosystem} ${entry.entryCarrierId} resolvedCarrierIds`, + ); + if (!resolvedCarrierIds.includes(entry.entryCarrierId)) { + throw error( + `${surface.ecosystem} public consumer entry ${entry.entryCarrierId} did not resolve itself exactly`, + ); + } + const outside = resolvedCarrierIds.filter((id) => !planned.has(id)); + if (outside.length > 0) { + throw error( + `${surface.ecosystem} public consumer entry ${entry.entryCarrierId} resolved selected carriers outside its frozen dependency closure: ${outside.join(', ')}`, + ); + } + const missing = [...planned] + .filter((id) => !resolvedCarrierIds.includes(id)) + .sort(compareText); + if (missing.length > 0) { + throw error( + `${surface.ecosystem} public consumer entry ${entry.entryCarrierId} omitted frozen platform-independent lock dependencies: ${missing.join(', ')}`, + ); + } + return { entryCarrierId: entry.entryCarrierId, resolvedCarrierIds }; + }) + .sort((left, right) => compareText(left.entryCarrierId, right.entryCarrierId)); + const resolved = [...merged.values()].sort((left, right) => compareText(left.id, right.id)); + const unknown = resolved.map(({ id }) => id).filter((id) => !carrierIds.has(id)); + if (unknown.length > 0) + throw error( + `${surface.ecosystem} consumer probes returned unknown selected carriers: ${unknown.join(', ')}`, + ); + if ( + !sameStrings( + resolved.map(({ id }) => id), + surface.carrierIds, + ) + ) { + throw error( + `${surface.ecosystem} public entry lock closures do not resolve the exhaustive frozen carrier set`, + ); + } + return { + carrierIds: surface.carrierIds, + dependencyScopes: surface.dependencyScopes, + entryCarrierIds: surface.entryCarrierIds, + plannedEntryClosures: surface.entryClosures, + entries: normalizedEntries, + resolved, + }; +} + +function tomlString(value) { + return JSON.stringify(value); +} + +export function cargoEntryFeatureNames(metadata, carrier) { + const artifacts = Array.isArray(carrier?.artifacts) + ? carrier.artifacts.filter( + ({ path: artifactPath }) => + typeof artifactPath === 'string' && artifactPath.endsWith('.crate'), + ) + : []; + if ( + metadata === null || + Array.isArray(metadata) || + typeof metadata !== 'object' || + artifacts.length !== 1 || + !SHA256_RE.test(artifacts[0].sha256 ?? '') || + !Number.isSafeInteger(artifacts[0].size) || + artifacts[0].size <= 0 || + metadata.version?.crate !== carrier?.name || + metadata.version?.num !== carrier?.version || + metadata.version?.checksum !== artifacts[0].sha256 || + metadata.version?.crate_size !== artifacts[0].size || + metadata.version?.yanked !== false + ) { + throw error( + `${carrier?.id ?? 'Cargo entry'} crates.io version metadata does not match its exact frozen carrier`, + ); + } + const merged = new Map(); + for (const [label, table] of [ + ['features', metadata.version.features], + ['features2', metadata.version.features2 ?? {}], + ]) { + if (table === null || Array.isArray(table) || typeof table !== 'object') { + throw error(`${carrier.id} crates.io ${label} must be a feature table`); + } + for (const [name, members] of Object.entries(table)) { + if ( + typeof name !== 'string' || + name.length === 0 || + /[\0\r\n]/u.test(name) || + !Array.isArray(members) || + members.some( + (member) => typeof member !== 'string' || member.length === 0 || /[\0\r\n]/u.test(member), + ) + ) { + throw error( + `${carrier.id} crates.io metadata contains an invalid Cargo feature declaration`, + ); + } + const prior = merged.get(name); + if (prior !== undefined && stableJson(prior) !== stableJson(members)) { + throw error(`${carrier.id} crates.io features and features2 disagree for ${name}`); + } + merged.set(name, members); + } + } + // Cargo resolves target-specific dependencies for every target into the + // lockfile, but it deliberately omits optional dependencies whose features + // are not enabled. Resolve every public opt-in feature so the anonymous lock + // probe covers the complete frozen carrier closure. The crates.io checksum + // above binds this feature metadata to the same immutable .crate bytes + // already proven by the exhaustive registry receipt. + return [...merged.keys()].filter((name) => name !== 'default').sort(compareText); +} + +async function boundedResponseJson(response, label) { + const declared = response.headers.get('content-length'); + if (declared !== null) { + const bytes = Number(declared); + if (!Number.isSafeInteger(bytes) || bytes < 0 || bytes > MAX_CRATES_IO_METADATA_BYTES) { + await response.body?.cancel?.().catch(() => {}); + throw error(`${label} returned an invalid or oversized Content-Length`); + } + } + const reader = response.body?.getReader?.(); + if (reader === undefined) { + throw error(`${label} returned no bounded response body`); + } + const chunks = []; + let size = 0; + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > MAX_CRATES_IO_METADATA_BYTES) { + await reader.cancel().catch(() => {}); + throw error(`${label} response exceeds ${MAX_CRATES_IO_METADATA_BYTES} bytes`); + } + chunks.push(Buffer.from(value)); + } + } finally { + reader.releaseLock(); + } + try { + return JSON.parse(Buffer.concat(chunks, size).toString('utf8')); + } catch (cause) { + throw error(`${label} returned invalid JSON: ${cause.message}`); + } +} + +async function cratesIoEntryFeatureNames(carrier, deadlineMilliseconds) { + const crate = encodeURIComponent(carrier.name); + const version = encodeURIComponent(carrier.version); + const url = `${CRATES_IO_API}/crates/${crate}/${version}`; + let lastFailure = ''; + for (let attempt = 0; attempt < CRATES_IO_FEATURE_ATTEMPTS; attempt += 1) { + const remaining = deadlineMilliseconds - Date.now(); + if (remaining <= 0) + throw error( + `shared public-consumer deadline reached before resolving ${carrier.id} features`, + ); + const controller = new AbortController(); + const timeout = setTimeout( + () => controller.abort(), + Math.min(remaining, CRATES_IO_REQUEST_TIMEOUT_MILLISECONDS), + ); + let retryHeaders; + try { + const response = await fetch(url, { + headers: { + Accept: 'application/json', + 'User-Agent': CRATES_IO_USER_AGENT, + }, + redirect: 'follow', + signal: controller.signal, + }); + if (response.ok) { + return cargoEntryFeatureNames(await boundedResponseJson(response, carrier.id), carrier); + } + retryHeaders = response.headers; + await response.body?.cancel?.().catch(() => {}); + if (!registryStatusRetryable(response.status)) { + throw new PublicCommandError( + `${TOOL}: crates.io returned HTTP ${response.status} for exact carrier ${carrier.id}`, + ); + } + lastFailure = `HTTP ${response.status}`; + } catch (cause) { + if ( + cause instanceof PublicCommandError || + (cause instanceof Error && cause.message.startsWith(`${TOOL}:`)) + ) { + throw cause; + } + lastFailure = cause instanceof Error ? cause.message : String(cause); + } finally { + clearTimeout(timeout); + } + if (attempt + 1 < CRATES_IO_FEATURE_ATTEMPTS) { + const seconds = registryRetryDelaySeconds({ + attempt, + baseSeconds: 1, + headers: retryHeaders, + }); + const milliseconds = Math.ceil(seconds * 1_000); + if (deadlineMilliseconds - Date.now() <= milliseconds + 30_000) + throw error('public metadata retry would cross the shared deadline'); + await new Promise((resolve) => setTimeout(resolve, milliseconds)); + } + } + throw new PublicCommandError( + `${TOOL}: failed to resolve checksum-bound crates.io features for ${carrier.id}: ${lastFailure}`, + { retryable: true }, + ); +} + +export function validateCargoResolution( + lockText, + carriers, + requiredCarrierIds = carriers.map(({ id }) => id), +) { + let parsed; + try { + parsed = Bun.TOML.parse(lockText); + } catch (cause) { + throw error(`clean Cargo.lock is invalid: ${cause.message}`); + } + const packages = Array.isArray(parsed.package) ? parsed.package : []; + const byName = new Map(carriers.map((carrier) => [carrier.name, carrier])); + const rows = []; + for (const entry of packages) { + const carrier = byName.get(entry?.name); + if (carrier === undefined) continue; + if (entry.version !== carrier.version) { + throw error( + `${carrier.id} resolved substituted Cargo version ${entry.version}, expected exact ${carrier.version}`, + ); + } + if (entry.source !== 'registry+https://github.com/rust-lang/crates.io-index') { + throw error( + `${carrier.id}@${carrier.version} resolved through non-public or substituted Cargo source ${JSON.stringify(entry.source)}`, + ); + } + if (!SHA256_RE.test(entry.checksum ?? '')) { + throw error(`${carrier.id}@${carrier.version} clean resolution has no crates.io checksum`); + } + rows.push({ id: carrier.id, version: carrier.version, checksum: entry.checksum }); + } + const ids = rows.map(({ id }) => id); + if (new Set(ids).size !== ids.length) + throw error('clean Cargo resolution contains duplicate exact selected carrier identities'); + const missing = requiredCarrierIds.filter((id) => !ids.includes(id)); + if (missing.length > 0) + throw error(`clean Cargo resolution omitted required exact carriers: ${missing.join(', ')}`); + return rows.sort((left, right) => compareText(left.id, right.id)); +} + +async function cargoSurface({ lock, surface, root, deadlineMilliseconds }, prepare) { + const directory = path.join(root, 'cargo'); + const home = path.join(root, 'cargo-home'); + mkdirSync(home, { recursive: true }); + const carriers = carrierRows(lock, surface); + const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); + const env = publicCargoEnvironment(root); + const entries = []; + const rows = []; + for (const [index, entryCarrierId] of surface.entryCarrierIds.entries()) { + const carrier = byId.get(entryCarrierId); + const consumer = path.join(directory, `entry-${String(index).padStart(3, '0')}`); + if (prepare) { + const features = await cratesIoEntryFeatureNames(carrier, deadlineMilliseconds); + const featureClause = features.length === 0 ? '' : `, features = ${tomlString(features)}`; + mkdirSync(path.join(consumer, 'src'), { recursive: true }); + writeFileSync( + path.join(consumer, 'Cargo.toml'), + `[package]\nname = "oliphaunt-public-consumer-smoke-${String(index).padStart(3, '0')}"\nversion = "0.0.0"\nedition = "2021"\npublish = false\n\n[dependencies]\nlocked_entry = { package = ${tomlString(carrier.name)}, version = ${tomlString(`=${carrier.version}`)}${featureClause} }\n\n[workspace]\n`, + ); + writeFileSync( + path.join(consumer, 'src/lib.rs'), + '// dependency resolution only; immutable receipts prove target payload bytes.\n', + ); + continue; + } + const resolved = validateCargoResolution( + readFileSync(path.join(consumer, 'Cargo.lock'), 'utf8'), + carriers, + [entryCarrierId], + ); + rows.push(resolved); + entries.push({ entryCarrierId, resolvedCarrierIds: resolved.map(({ id }) => id) }); + } + if (prepare) return env; + return { + surface: 'cargo', + mode: 'anonymous-public-independent-entry-all-feature-resolution-no-compile', + registry: 'https://crates.io', + ...resolvedSurfaceCoverage(surface, entries, rows), + receiptCoveredWithoutPayloadFetchCarrierIds: surface.carrierIds, + }; +} + +function npmPackagePath(root, packageName) { + return path.join(root, 'node_modules', ...packageName.split('/')); +} + +export function validateNpmResolution(packageLock, carriers, requiredEntryIds, nodeModules) { + if ( + packageLock === null || + Array.isArray(packageLock) || + typeof packageLock !== 'object' || + packageLock.lockfileVersion < 3 + ) { + throw error('clean npm install must emit package-lock v3 or newer'); + } + const packages = packageLock.packages; + if (packages === null || Array.isArray(packages) || typeof packages !== 'object') { + throw error('clean npm package lock has no packages map'); + } + const entries = new Set(requiredEntryIds); + const resolved = []; + for (const carrier of carriers) { + const suffix = `node_modules/${carrier.name}`; + const matches = Object.entries(packages).filter( + ([key]) => key === suffix || key.endsWith(`/${suffix}`), + ); + if (matches.length === 0) { + if (entries.has(carrier.id)) + throw error(`${carrier.id}@${carrier.version} is missing from the clean npm lock`); + continue; + } + if (matches.length !== 1 || matches[0][1]?.version !== carrier.version) { + throw error( + `${carrier.id}@${carrier.version} must be the only selected version in the clean npm lock; found ${matches.length}`, + ); + } + const row = matches[0][1]; + if ( + row.link === true || + typeof row.resolved !== 'string' || + !row.resolved.startsWith('https://registry.npmjs.org/') || + typeof row.integrity !== 'string' || + !row.integrity.startsWith('sha512-') + ) { + throw error( + `${carrier.id}@${carrier.version} resolved through a non-public, linked, or integrity-free npm source`, + ); + } + if (entries.has(carrier.id)) { + const manifestFile = path.join(npmPackagePath(nodeModules, carrier.name), 'package.json'); + let installed; + try { + installed = JSON.parse(readFileSync(manifestFile, 'utf8')); + } catch (cause) { + throw error( + `${carrier.id}@${carrier.version} entry package was not installed from the public registry: ${cause.message}`, + ); + } + if (installed.name !== carrier.name || installed.version !== carrier.version) { + throw error( + `${carrier.id} installed package identity does not match ${carrier.name}@${carrier.version}`, + ); + } + } + resolved.push({ id: carrier.id, version: carrier.version, integrity: row.integrity }); + } + resolved.sort((left, right) => compareText(left.id, right.id)); + const installedCarrierIds = carriers + .filter((carrier) => { + try { + return statSync( + path.join(npmPackagePath(nodeModules, carrier.name), 'package.json'), + ).isFile(); + } catch { + return false; + } + }) + .map(({ id }) => id) + .sort(compareText); + return { resolved, installedCarrierIds }; +} + +function npmSurface({ lock, surface, root }, prepare) { + const directory = path.join(root, 'npm'); + const home = path.join(root, 'npm-home'); + mkdirSync(directory, { recursive: true }); + mkdirSync(home, { recursive: true }); + const carriers = carrierRows(lock, surface); + const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); + const userConfig = path.join(home, '.npmrc'); + const globalConfig = path.join(home, 'global.npmrc'); + writeFileSync(userConfig, 'registry=https://registry.npmjs.org/\nalways-auth=false\n'); + writeFileSync(globalConfig, 'registry=https://registry.npmjs.org/\nalways-auth=false\n'); + const env = sanitizedPublicEnvironment({ + HOME: home, + NPM_CONFIG_CACHE: path.join(root, 'npm-cache'), + NPM_CONFIG_GLOBALCONFIG: globalConfig, + NPM_CONFIG_REGISTRY: 'https://registry.npmjs.org/', + NPM_CONFIG_USERCONFIG: userConfig, + }); + const entries = []; + const rows = []; + const installed = new Set(); + for (const [index, entryCarrierId] of surface.entryCarrierIds.entries()) { + const carrier = byId.get(entryCarrierId); + const consumer = path.join(directory, `entry-${String(index).padStart(3, '0')}`); + if (prepare) { + mkdirSync(consumer, { recursive: true }); + writeFileSync( + path.join(consumer, 'package.json'), + `${JSON.stringify( + { + name: `oliphaunt-public-consumer-smoke-${String(index).padStart(3, '0')}`, + version: '0.0.0', + private: true, + dependencies: { [carrier.name]: carrier.version }, + }, + null, + 2, + )}\n`, + ); + continue; + } + const lockJson = JSON.parse(readFileSync(path.join(consumer, 'package-lock.json'), 'utf8')); + const result = validateNpmResolution(lockJson, carriers, [entryCarrierId], consumer); + rows[index] = result.resolved; + entries[index] = { entryCarrierId, resolvedCarrierIds: result.resolved.map(({ id }) => id) }; + for (const id of result.installedCarrierIds) installed.add(id); + } + if (prepare) return env; + return { + surface: 'npm', + mode: 'anonymous-public-independent-entry-host-install-and-lock-resolution', + registry: 'https://registry.npmjs.org', + host: `${process.platform}-${process.arch}`, + ...resolvedSurfaceCoverage(surface, entries, rows), + installedCarrierIds: [...installed].sort(compareText), + receiptCoveredNotHostInstalledCarrierIds: surface.carrierIds + .filter((id) => !installed.has(id)) + .sort(compareText), + }; +} + +function mavenCoordinate(name, version) { + const parts = name.split(':'); + if (parts.length !== 2 || parts.some((value) => value.length === 0)) { + throw error(`invalid locked Maven coordinate ${JSON.stringify(name)}`); + } + return `${name}:${version}`; +} + +export function validateMavenResolution( + output, + carriers, + entryCarrierIds = carriers.map(({ id }) => id), +) { + const prefix = 'OLIPHAUNT_PUBLIC_COMPONENT\t'; + const rows = output + .split(/\r?\n/u) + .filter((line) => line.startsWith(prefix)) + .map((line) => line.slice(prefix.length).split('\t')); + if (rows.some((parts) => parts.length !== 4)) + throw error('clean Maven resolution emitted malformed component evidence'); + const byName = new Map(carriers.map((carrier) => [carrier.name, carrier])); + const resolvedByEntry = new Map(entryCarrierIds.map((id) => [id, new Map()])); + for (const [entryCarrierId, group, artifact, version] of rows) { + const entry = resolvedByEntry.get(entryCarrierId); + if (entry === undefined) + throw error(`clean Maven resolution emitted unknown entry root ${entryCarrierId}`); + const carrier = byName.get(`${group}:${artifact}`); + if (carrier === undefined) continue; + if (version !== carrier.version) { + throw error( + `${carrier.id} resolved substituted Maven version ${version}, expected exact ${carrier.version}`, + ); + } + entry.set(carrier.id, { id: carrier.id, version: carrier.version }); + } + const entries = entryCarrierIds.map((entryCarrierId) => { + const resolved = resolvedByEntry.get(entryCarrierId); + if (!resolved.has(entryCarrierId)) { + throw error( + `${entryCarrierId} was omitted from its independent clean Maven Central resolution`, + ); + } + return { entryCarrierId, resolvedCarrierIds: [...resolved.keys()].sort(compareText) }; + }); + const resolved = new Map(); + for (const values of resolvedByEntry.values()) { + for (const [id, row] of values) resolved.set(id, row); + } + return { + entries, + resolved: [...resolved.values()].sort((left, right) => compareText(left.id, right.id)), + }; +} + +function mavenSurface({ lock, surface, root }, prepare) { + const directory = path.join(root, 'maven'); + mkdirSync(directory, { recursive: true }); + const carriers = carrierRows(lock, surface); + const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); + if (prepare) { + writeFileSync( + path.join(directory, 'settings.gradle'), + "rootProject.name = 'oliphaunt-public-consumer-smoke'\n", + ); + const probes = surface.entryCarrierIds.map((entryCarrierId, index) => ({ + carrier: byId.get(entryCarrierId), + configuration: `smoke${String(index).padStart(3, '0')}`, + entryCarrierId, + })); + const configurations = probes.map( + ({ configuration }) => + ` ${configuration} {\n canBeConsumed = false\n canBeResolved = true\n }`, + ); + const dependencies = probes.map( + ({ carrier, configuration }) => + ` ${configuration}(${JSON.stringify(mavenCoordinate(carrier.name, carrier.version))}) { version { strictly(${JSON.stringify(carrier.version)}) } }`, + ); + const probeRows = probes + .map( + ({ configuration, entryCarrierId }) => + ` [${JSON.stringify(entryCarrierId)}, ${JSON.stringify(configuration)}]`, + ) + .join(',\n'); + writeFileSync( + path.join(directory, 'build.gradle'), + ` +repositories { + mavenCentral() + google() +} + +configurations { +${configurations.join('\n')} +} + +dependencies { +${dependencies.join('\n')} +} + +tasks.register("resolveOliphauntPublicConsumers") { + doLast { + def probes = [ +${probeRows} + ] + probes.each { probe -> + def entryCarrierId = probe[0] + def configuration = configurations.getByName(probe[1]) + configuration.files + def ids = configuration.incoming.resolutionResult.allComponents + .collect { it.id } + .findAll { it instanceof org.gradle.api.artifacts.component.ModuleComponentIdentifier } + .collect { "${'$'}{it.group}\\t${'$'}{it.module}\\t${'$'}{it.version}" } + .toSorted() + ids.each { println("OLIPHAUNT_PUBLIC_COMPONENT\\t" + entryCarrierId + "\\t" + it) } + } + } +} +`, + ); + const env = sanitizedPublicEnvironment({ + GRADLE_USER_HOME: path.join(root, 'gradle-home'), + HOME: path.join(root, 'gradle-user-home'), + }); + return env; + } + const result = boundedCommandOutput(path.join(root, 'gradle-output')); + const resolution = validateMavenResolution(result, carriers, surface.entryCarrierIds); + return { + surface: 'maven', + mode: 'anonymous-public-independent-entry-coordinate-resolution-no-compile', + registries: ['https://repo1.maven.org/maven2', 'https://dl.google.com/dl/android/maven2'], + ...resolvedSurfaceCoverage(surface, resolution.entries, [resolution.resolved]), + }; +} + +function gitEnvironment(root) { + const home = path.join(root, 'git-home'); + mkdirSync(home, { recursive: true }); + return sanitizedPublicEnvironment({ + GIT_ASKPASS: '', + GIT_CONFIG_GLOBAL: path.join(root, 'empty-gitconfig'), + GIT_CONFIG_NOSYSTEM: '1', + GIT_TERMINAL_PROMPT: '0', + HOME: home, + SSH_ASKPASS: '', + }); +} + +function githubSurface({ plan, root }, prepare) { + if (prepare) return gitEnvironment(root); + const read = (name) => boundedCommandOutput(path.join(root, name)).trim(); + for (const [index, row] of plan.github.productTags.entries()) { + const commit = read('tag-' + index); + if (commit !== row.commit) + throw error(`anonymous public tag ${row.tag} resolves to ${commit}, not exact ${row.commit}`); + } + let swift = null; + if (plan.github.swift !== null) { + const row = plan.github.swift; + const commit = read('swift-commit'); + const parents = read('swift-parents').split(/\s+/u); + if (parents.length !== 2 || parents[0] !== commit || parents[1] !== row.parentCommit) + throw error( + `SwiftPM source tag ${row.tag} must be a single synthetic child of exact ${row.parentCommit}`, + ); + const packageDescription = JSON.parse(read('swift-package.json')); + if (typeof packageDescription.name !== 'string' || packageDescription.name.length === 0) + throw error(`SwiftPM source tag ${row.tag} has no package name`); + swift = { + ...row, + commit, + tree: read('swift-tree'), + packageName: packageDescription.name, + proofScope: 'anonymous-source-tag-and-manifest-only', + }; + } + return { + surface: 'github', + mode: 'anonymous-public-exact-tag-resolution', + repository: plan.repository, + productTags: plan.github.productTags, + swift, + limitation: + plan.github.swift === null + ? null + : 'Draft GitHub binaryTarget assets are not anonymously public before promotion; their exact bytes are covered by the bound immutable GitHub receipt, not this source-tag probe.', + }; +} + +function boundedCommandOutput(file) { + const stat = lstatSync(file); + if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 16 * 1024 * 1024) + throw error('consumer command output must be a bounded regular file'); + return readFileSync(file, 'utf8'); +} + +export function publicConsumerEvidence({ + lock, + plan, + registryReceiptSha256, + githubReceiptDigest, + surfaces, +}) { + const result = { + schema: PUBLIC_CONSUMER_EVIDENCE_SCHEMA, + lockDigest: lock.lockDigest, + source: lock.source, + products: plan.products, + repository: plan.repository, + proofScope: { + host: `${process.platform}-${process.arch}`, + statement: + 'Anonymous public dependency resolution/install on the publish host; same-SHA CI and immutable receipts cover the complete supported platform artifact matrix.', + }, + receiptBindings: { + githubReceiptDigest, + registryReceiptSha256, + }, + surfaces: surfaces.slice().sort((left, right) => compareText(left.surface, right.surface)), + }; + result.evidenceDigest = sha256Bytes(stableJson(result)); + return result; +} + +export function validatePublicConsumerEvidence(evidence, lock, plan) { + if (evidence === null || Array.isArray(evidence) || typeof evidence !== 'object') + throw error('public consumer evidence must be an object'); + if (evidence.schema !== PUBLIC_CONSUMER_EVIDENCE_SCHEMA) + throw error(`public consumer evidence schema must be ${PUBLIC_CONSUMER_EVIDENCE_SCHEMA}`); + if ( + evidence.lockDigest !== lock.lockDigest || + stableJson(evidence.source) !== stableJson(lock.source) + ) { + throw error('public consumer evidence is not bound to the active publication lock'); + } + if (!sameStrings(evidence.products ?? [], plan.products)) + throw error('public consumer evidence products differ from the exact lock selection'); + if ( + !SHA256_RE.test(evidence.receiptBindings?.registryReceiptSha256 ?? '') || + !SHA256_RE.test(evidence.receiptBindings?.githubReceiptDigest ?? '') + ) { + throw error('public consumer evidence has invalid immutable receipt bindings'); + } + const expectedSurfaces = [...plan.surfaces.map(({ ecosystem }) => ecosystem), 'github'].sort( + compareText, + ); + const actualSurfaces = Array.isArray(evidence.surfaces) + ? evidence.surfaces.map(({ surface }) => surface) + : []; + if (!sameStrings(actualSurfaces, expectedSurfaces)) { + throw error( + `public consumer evidence surface coverage mismatch: expected=${JSON.stringify(expectedSurfaces)}, actual=${JSON.stringify(actualSurfaces)}`, + ); + } + for (const surface of plan.surfaces) { + const observed = evidence.surfaces.find(({ surface: name }) => name === surface.ecosystem); + if ( + !sameStrings(observed?.carrierIds ?? [], surface.carrierIds) || + !sameStrings(observed?.entryCarrierIds ?? [], surface.entryCarrierIds) + ) { + throw error( + `${surface.ecosystem} public consumer evidence omits exact-lock carriers or entry roots`, + ); + } + if (stableJson(observed?.plannedEntryClosures) !== stableJson(surface.entryClosures)) { + throw error( + `${surface.ecosystem} public consumer evidence changed the frozen entry dependency closures`, + ); + } + if (stableJson(observed?.dependencyScopes) !== stableJson(surface.dependencyScopes)) { + throw error( + `${surface.ecosystem} public consumer evidence changed the package-manager dependency scope policy`, + ); + } + const coverage = resolvedSurfaceCoverage(surface, observed?.entries ?? [], [ + observed?.resolved ?? [], + ]); + for (const field of [ + 'carrierIds', + 'dependencyScopes', + 'entryCarrierIds', + 'plannedEntryClosures', + 'entries', + 'resolved', + ]) { + if (stableJson(observed?.[field]) !== stableJson(coverage[field])) { + throw error( + `${surface.ecosystem} public consumer evidence has non-canonical ${field} coverage`, + ); + } + } + if (surface.ecosystem === 'npm') { + const installed = sortedUniqueStrings( + observed?.installedCarrierIds ?? [], + 'npm installedCarrierIds', + ); + const resolved = new Set(coverage.resolved.map(({ id }) => id)); + if ( + installed.some((id) => !resolved.has(id)) || + stableJson(installed) !== stableJson(observed.installedCarrierIds) + ) { + throw error( + 'npm host-installed carriers must be a canonical subset of its exact public resolution', + ); + } + const notInstalled = surface.carrierIds + .filter((id) => !installed.includes(id)) + .sort(compareText); + if ( + stableJson(observed.receiptCoveredNotHostInstalledCarrierIds) !== stableJson(notInstalled) + ) { + throw error( + 'npm evidence must explicitly distinguish exhaustive lock resolution from the publish-host installed subset', + ); + } + } + if ( + surface.ecosystem === 'cargo' && + stableJson(observed.receiptCoveredWithoutPayloadFetchCarrierIds) !== + stableJson(surface.carrierIds) + ) { + throw error( + 'Cargo evidence must explicitly distinguish registry resolution from receipt-proved payload bytes', + ); + } + } + const github = evidence.surfaces.find(({ surface }) => surface === 'github'); + if (stableJson(github?.productTags) !== stableJson(plan.github.productTags)) { + throw error('GitHub public consumer evidence does not resolve every exact product tag'); + } + if ( + plan.github.swift === null + ? github?.swift !== null + : github?.swift?.tag !== plan.github.swift.tag + ) { + throw error('GitHub public consumer evidence SwiftPM source-tag coverage mismatch'); + } + const withoutDigest = structuredClone(evidence); + delete withoutDigest.evidenceDigest; + const expectedDigest = sha256Bytes(stableJson(withoutDigest)); + if (evidence.evidenceDigest !== expectedDigest) + throw error(`public consumer evidence digest mismatch: expected ${expectedDigest}`); + return evidence; +} + +export function writeImmutablePublicConsumerEvidence(file, evidence) { + const absolute = path.resolve(file); + const body = `${JSON.stringify(evidence, null, 2)}\n`; + if (Buffer.byteLength(body) > MAX_EVIDENCE_BYTES) + throw error(`public consumer evidence exceeds ${MAX_EVIDENCE_BYTES} bytes`); + mkdirSync(path.dirname(absolute), { recursive: true }); + const temporary = `${absolute}.tmp-${process.pid}-${randomUUID()}`; + try { + writeFileSync(temporary, body, { flag: 'wx', mode: 0o644 }); + try { + linkSync(temporary, absolute); + } catch (cause) { + if (cause?.code !== 'EEXIST') throw cause; + const stat = lstatSync(absolute); + if (stat.isSymbolicLink() || !stat.isFile() || stat.size > MAX_EVIDENCE_BYTES) { + throw error(`refusing to replace unsafe existing public consumer evidence ${file}`); + } + if (readFileSync(absolute, 'utf8') !== body) { + throw error(`refusing to replace non-identical immutable public consumer evidence ${file}`); + } + } + } finally { + try { + unlinkSync(temporary); + } catch {} + } + return absolute; +} + +function parseArgs(argv) { + const options = { + githubReceipt: '', + lock: DEFAULT_PUBLICATION_LOCK, + output: DEFAULT_OUTPUT, + productsJson: '', + registryReceipts: '', + repository: process.env.GITHUB_REPOSITORY || DEFAULT_REPOSITORY, + }; + for (let index = 0; index < argv.length; index += 1) { + const argument = argv[index]; + if (argument === '--help' || argument === '-h') return { help: true }; + const separator = argument.indexOf('='); + const flag = separator === -1 ? argument : argument.slice(0, separator); + const value = separator === -1 ? argv[++index] : argument.slice(separator + 1); + if (value === undefined || value.length === 0) throw error(`${flag} requires a value`); + if (flag === '--github-release-receipt') options.githubReceipt = value; + else if (flag === '--publication-lock') options.lock = value; + else if (flag === '--output') options.output = value; + else if (flag === '--products-json') options.productsJson = value; + else if (flag === '--registry-receipts') options.registryReceipts = value; + else if (flag === '--repository') options.repository = value; + else throw error(`unknown argument ${argument}`); + } + if (!options.productsJson || !options.registryReceipts || !options.githubReceipt) { + throw error('--products-json, --registry-receipts, and --github-release-receipt are required'); + } + let products; + try { + products = JSON.parse(options.productsJson); + } catch (cause) { + throw error(`--products-json is invalid: ${cause.message}`); + } + return { ...options, products }; +} + +function usage() { + console.log( + 'usage: bash tools/release/public-consumer-smoke.sh --publication-lock FILE --products-json JSON --registry-receipts FILE --github-release-receipt FILE --output FILE', + ); +} + +function sharedDeadlineMilliseconds() { + const timeoutSeconds = requirePositiveInteger( + process.env.PUBLIC_CONSUMER_SMOKE_TIMEOUT_SECONDS, + 'PUBLIC_CONSUMER_SMOKE_TIMEOUT_SECONDS', + DEFAULT_OVERALL_TIMEOUT_SECONDS, + ); + const reserveSeconds = requirePositiveInteger( + process.env.PUBLIC_CONSUMER_FINALIZATION_RESERVE_SECONDS, + 'PUBLIC_CONSUMER_FINALIZATION_RESERVE_SECONDS', + DEFAULT_POST_SMOKE_RESERVE_SECONDS, + ); + let deadline = Date.now() + timeoutSeconds * 1_000; + const hardRaw = process.env.REGISTRY_JOB_HARD_DEADLINE_EPOCH?.trim(); + if (hardRaw) { + if (!/^[1-9][0-9]*$/u.test(hardRaw)) + throw error('REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp'); + const hard = Number(hardRaw) * 1_000; + if (!Number.isSafeInteger(hard)) + throw error('REGISTRY_JOB_HARD_DEADLINE_EPOCH exceeds the safe timestamp range'); + deadline = Math.min(deadline, hard - reserveSeconds * 1_000); + } + if (deadline - Date.now() < 30_000) { + throw error( + 'less than 30 seconds remain before the shared public-consumer deadline after preserving final promotion reserve', + ); + } + return deadline; +} + +async function prepare(scratch, argv) { + const args = parseArgs(argv); + if (args.help) { + usage(); + return; + } + const lock = loadPublicationLock(path.resolve(ROOT, args.lock)); + const graph = { products: loadProducts(TOOL) }; + const plan = publicConsumerPlan(lock, args.products, graph, { repository: args.repository }); + const registryEvidence = validateRegistryReceiptEvidence(args.registryReceipts, lock, { + products: plan.products, + ecosystems: REGISTRY_ECOSYSTEMS, + receiptMode: 'sealed', + }); + const githubFile = boundedRegularJson( + args.githubReceipt, + MAX_RECEIPT_BYTES, + 'GitHub release receipt', + ); + const githubReceipt = validateGithubAttestationReceipt(githubFile.value, lock, { + repo: plan.repository, + }); + const registryFile = boundedRegularJson( + args.registryReceipts, + MAX_RECEIPT_BYTES, + 'registry receipt evidence', + ); + if (registryFile.value.lockDigest !== registryEvidence.lockDigest) + throw error('registry receipt changed during public consumer setup'); + + const deadlineMilliseconds = sharedDeadlineMilliseconds(); + writeFileSync( + path.join(scratch, 'context.json'), + JSON.stringify({ + args, + lock, + plan, + deadlineMilliseconds, + registryReceiptSha256: sha256Bytes(registryFile.bytes), + githubReceiptDigest: githubReceipt.receiptDigest, + }), + { flag: 'wx', mode: 0o600 }, + ); +} + +async function main(argv) { + const [phase, scratch, ecosystem] = argv; + if (phase === '--prepare' && scratch) return prepare(scratch, argv.slice(2)); + if (!scratch || !['--stage', '--finish', '--report'].includes(phase)) + throw error('use bash tools/release/public-consumer-smoke.sh [options]'); + const context = boundedRegularJson( + path.join(scratch, 'context.json'), + MAX_RECEIPT_BYTES, + 'consumer context', + ).value; + const { args, lock, plan } = context; + if (phase === '--report') { + const surfaces = [...plan.surfaces.map(({ ecosystem }) => ecosystem), 'github'].map( + (name) => + boundedRegularJson(path.join(scratch, name + '.json'), MAX_EVIDENCE_BYTES, 'surface result') + .value, + ); + const evidence = publicConsumerEvidence({ ...context, surfaces }); + validatePublicConsumerEvidence(evidence, lock, plan); + writeImmutablePublicConsumerEvidence(path.resolve(ROOT, args.output), evidence); + console.log( + `Verified ${plan.products.length} products across ${surfaces.length} anonymous public consumer surfaces; immutable evidence: ${path.relative(ROOT, args.output)} (${evidence.evidenceDigest}).`, + ); + return; + } + const runner = { + cargo: cargoSurface, + npm: npmSurface, + maven: mavenSurface, + github: githubSurface, + }[ecosystem]; + if ( + !runner || + (ecosystem !== 'github' && !plan.surfaces.some((row) => row.ecosystem === ecosystem)) + ) + throw error('unknown public consumer surface'); + const root = path.join(scratch, ecosystem); + mkdirSync(root, { recursive: true }); + const result = await runner( + { ...context, root, surface: plan.surfaces.find((row) => row.ecosystem === ecosystem) }, + phase === '--stage', + ); + if (phase === '--stage') { + writeFileSync( + path.join(root, 'environment'), + Object.entries(result) + .map(([name, value]) => name + '=' + value + '\0') + .join(''), + { mode: 0o600 }, + ); + if (ecosystem === 'github' && plan.github.swift !== null) { + const env = sanitizedPublicEnvironment({ + CLANG_MODULE_CACHE_PATH: path.join(root, 'swift-module-cache'), + HOME: path.join(root, 'swift-home'), + SWIFTPM_MODULECACHE_OVERRIDE: path.join(root, 'swift-module-cache'), + }); + writeFileSync( + path.join(root, 'swift-environment'), + Object.entries(env) + .map(([name, value]) => name + '=' + value + '\0') + .join(''), + { mode: 0o600 }, + ); + } + } else + writeFileSync(path.join(scratch, ecosystem + '.json'), JSON.stringify(result), { + flag: 'wx', + mode: 0o600, + }); +} + +if (import.meta.main) { + try { + await main(Bun.argv.slice(2)); + } catch (cause) { + console.error(cause.message); + process.exitCode = cause instanceof PublicCommandError && cause.retryable ? 75 : 1; + } +} diff --git a/tools/release/public-consumer-smoke.sh b/tools/release/public-consumer-smoke.sh new file mode 100644 index 000000000..f128862d8 --- /dev/null +++ b/tools/release/public-consumer-smoke.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env bash +set -euo pipefail +set -m +ulimit -Sn "$(ulimit -Hn)" +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$root" +tool="$root/tools/release/public-consumer-smoke.mts" +deadline="$(command -v gtimeout || command -v timeout)" +command -v jq >/dev/null + +if [ "${1:-}" = --surface ]; then + scratch="$2" + ecosystem="$3" + surface="$scratch/$ecosystem" + mkdir -p "$surface" + end="$(jq -r '.deadlineMilliseconds / 1000 | floor' "$scratch/context.json")" + command_pid='' + # shellcheck disable=SC2317 + stop_command() { + if [ -n "$command_pid" ]; then + kill -TERM -- "-$command_pid" 2>/dev/null || true + sleep 1 + kill -KILL -- "-$command_pid" 2>/dev/null || true + wait "$command_pid" 2>/dev/null || true + fi + } + trap stop_command EXIT + trap 'exit 130' INT TERM + capture() { + local output="$1" directory="$2" environment="$3" seconds status entry + shift 3 + seconds=$((end - $(date +%s))) + [ "$seconds" -gt 0 ] || { echo 'shared public-consumer deadline reached' >&2; return 1; } + [ "$seconds" -le 240 ] || seconds=240 + local command=("$@") + if [ -n "$environment" ]; then + local clean=(env -i) + while IFS= read -r -d '' entry; do clean+=("$entry"); done < "$environment" + command=("${clean[@]}" "${command[@]}") + fi + (cd "$directory"; exec "$deadline" --kill-after=5s "${seconds}s" "${command[@]}") > "$output" 2> "$surface/command-error" & + command_pid=$! + status=0 + wait "$command_pid" || status=$? + kill -KILL -- "-$command_pid" 2>/dev/null || true + command_pid='' + if [ "$status" != 0 ]; then + tail -c 8192 "$output" >&2 + tail -c 8192 "$surface/command-error" >&2 + return "$status" + fi + } + capture "$surface/stage.log" "$root" '' bash tools/dev/bun.sh "$tool" --stage "$scratch" "$ecosystem" + environment="$surface/environment" + case "$ecosystem" in + cargo) + for consumer in "$surface"/cargo/entry-*; do + capture "$consumer/command-output" "$consumer" "$environment" cargo generate-lockfile + done ;; + npm) + for consumer in "$surface"/npm/entry-*; do + capture "$consumer/command-output" "$consumer" "$environment" npm install --ignore-scripts --no-audit --no-fund --omit=peer --registry=https://registry.npmjs.org/ + done ;; + maven) + capture "$surface/gradle-output" "$surface/maven" "$environment" "$root/src/sdks/kotlin/gradlew" --no-daemon --console=plain --project-dir "$surface/maven" resolveOliphauntPublicConsumers ;; + github) + git_args=(git -c credential.helper= -c http.extraHeader= --git-dir "$surface/github.git") + capture "$surface/init.log" "$surface" "$environment" git -c credential.helper= -c http.extraHeader= init --bare "$surface/github.git" + refs=() + while IFS= read -r tag; do refs+=("refs/tags/$tag:refs/tags/$tag"); done < <(jq -r '[.plan.github.productTags[].tag, (.plan.github.swift.tag // empty)] | unique[]' "$scratch/context.json") + repository="$(jq -r '.plan.repositoryUrl' "$scratch/context.json")" + capture "$surface/fetch.log" "$surface" "$environment" "${git_args[@]}" fetch --no-tags --force "$repository" "${refs[@]}" + index=0 + while IFS= read -r tag; do + capture "$surface/tag-$index" "$surface" "$environment" "${git_args[@]}" rev-parse "$tag^{commit}" + expected="$(jq -r --argjson index "$index" '.plan.github.productTags[$index].commit' "$scratch/context.json")" + [ "$(cat "$surface/tag-$index")" = "$expected" ] || { echo "public tag $tag differs from the frozen commit" >&2; exit 1; } + index=$((index + 1)) + done < <(jq -r '.plan.github.productTags[].tag' "$scratch/context.json") + swift_tag="$(jq -r '.plan.github.swift.tag // empty' "$scratch/context.json")" + if [ -n "$swift_tag" ]; then + capture "$surface/swift-commit" "$surface" "$environment" "${git_args[@]}" rev-parse "$swift_tag^{commit}" + commit="$(cat "$surface/swift-commit")" + capture "$surface/swift-parents" "$surface" "$environment" "${git_args[@]}" rev-list --parents -n 1 "$commit" + parent="$(jq -r '.plan.github.swift.parentCommit' "$scratch/context.json")" + [ "$(cat "$surface/swift-parents")" = "$commit $parent" ] || { echo 'SwiftPM source tag has the wrong parent' >&2; exit 1; } + mkdir "$surface/swift-source" + capture "$surface/checkout.log" "$surface" "$environment" "${git_args[@]}" --work-tree "$surface/swift-source" checkout --force "$commit" -- . + capture "$surface/swift-package.json" "$surface/swift-source" "$surface/swift-environment" swift package dump-package + capture "$surface/swift-tree" "$surface" "$environment" "${git_args[@]}" rev-parse "$commit^{tree}" + fi ;; + *) echo "unknown public consumer surface: $ecosystem" >&2; exit 2 ;; + esac + capture "$surface/finish.log" "$root" '' bash tools/dev/bun.sh "$tool" --finish "$scratch" "$ecosystem" + exit 0 +fi + +scratch="$(mktemp -d)" +pids=() +# shellcheck disable=SC2317 +cleanup() { + status=$? + trap - EXIT + for pid in "${pids[@]}"; do kill -TERM -- "-$pid" 2>/dev/null || true; done + if [ "${#pids[@]}" -gt 0 ]; then sleep 2; fi + for pid in "${pids[@]}"; do kill -KILL -- "-$pid" 2>/dev/null || true; wait "$pid" 2>/dev/null || true; done + if [ "$status" != 0 ]; then + for log in "$scratch"/*.log; do [ ! -f "$log" ] || tail -c 16384 "$log" >&2; done + fi + rm -rf "$scratch" + exit "$status" +} +trap cleanup EXIT +trap 'exit 130' INT TERM +bash tools/dev/bun.sh "$tool" --prepare "$scratch" "$@" +# Help does not prepare a run. +[ -f "$scratch/context.json" ] || exit 0 +end="$(jq -r '.deadlineMilliseconds / 1000 | floor' "$scratch/context.json")" +while IFS= read -r ecosystem; do + seconds=$((end - $(date +%s))) + [ "$seconds" -gt 0 ] || { echo 'shared public-consumer deadline reached' >&2; exit 1; } + "$deadline" --kill-after=5s "${seconds}s" bash "$root/tools/release/public-consumer-smoke.sh" --surface "$scratch" "$ecosystem" > "$scratch/$ecosystem.log" 2>&1 & + pids+=("$!") +done < <(jq -r '.plan.surfaces[].ecosystem, "github"' "$scratch/context.json") +while [ "${#pids[@]}" -gt 0 ]; do + active=() + for pid in "${pids[@]}"; do + if kill -0 "$pid" 2>/dev/null; then active+=("$pid"); else wait "$pid"; fi + done + pids=("${active[@]}") + [ "${#pids[@]}" = 0 ] || sleep 0.2 +done +bash tools/dev/bun.sh "$tool" --report "$scratch" diff --git a/tools/release/public-consumer-smoke.test.mjs b/tools/release/public-consumer-smoke.test.mjs deleted file mode 100644 index 57170f9a9..000000000 --- a/tools/release/public-consumer-smoke.test.mjs +++ /dev/null @@ -1,539 +0,0 @@ -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - PUBLIC_CONSUMER_EVIDENCE_SCHEMA, - cargoEntryFeatureNames, - publicCargoEnvironment, - publicConsumerEvidence, - publicConsumerPlan, - runBoundedCommand, - runSurfaceWithRetries, - sanitizedPublicEnvironment, - validateCargoResolution, - validateMavenResolution, - validateNpmResolution, - validatePublicConsumerEvidence, - writeImmutablePublicConsumerEvidence, -} from "./public-consumer-smoke.mjs"; - -const digest = (value) => createHash("sha256").update(value).digest("hex"); - -function product(id, publishTargets, version = "1.2.3") { - return { id, version, publishTargets, dependencies: [], kind: "sdk", path: `src/${id}` }; -} - -function carrier(id, productId, publishOrder, dependencies = []) { - const separator = id.indexOf(":"); - return { - id, - product: productId, - ecosystem: id.slice(0, separator), - name: id.slice(separator + 1), - version: "1.2.3", - publishOrder, - dependencies, - }; -} - -function lock(products, carriers) { - return { - lockDigest: "a".repeat(64), - source: { commit: "b".repeat(40), tree: "c".repeat(40) }, - products, - carriers, - }; -} - -function graph(products) { - return { - products: Object.fromEntries(products.map((row) => [row.id, { - tag_prefix: `${row.id}-v`, - version: row.version, - }])), - }; -} - -test("derives every registry surface and graph-root entry from the exact selected lock", () => { - const products = [product("runtime", ["crates-io", "maven-central", "npm"]), product("sdk", ["crates-io", "maven-central", "npm"])]; - const frozen = lock(products, [ - carrier("cargo:runtime-leaf", "runtime", 0), - carrier("npm:@example/runtime-leaf", "runtime", 1), - carrier("maven:dev.example:runtime", "runtime", 2), - carrier("cargo:sdk", "sdk", 3, ["cargo:runtime-leaf"]), - carrier("npm:@example/sdk", "sdk", 4, ["npm:@example/runtime-leaf"]), - carrier("maven:dev.example:sdk", "sdk", 5, ["maven:dev.example:runtime"]), - ]); - const plan = publicConsumerPlan(frozen, ["runtime", "sdk"], graph(products)); - assert.deepEqual(plan.surfaces.map(({ ecosystem }) => ecosystem), ["cargo", "maven", "npm"]); - assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === "cargo").entryCarrierIds, ["cargo:sdk"]); - assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === "cargo").entryClosures, [{ - entryCarrierId: "cargo:sdk", - carrierIds: ["cargo:runtime-leaf", "cargo:sdk"], - }]); - assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === "npm").entryCarrierIds, ["npm:@example/sdk"]); - assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === "maven").entryCarrierIds, ["maven:dev.example:sdk"]); - assert.deepEqual(plan.github.productTags, [ - { product: "runtime", tag: "runtime-v1.2.3", commit: "b".repeat(40) }, - { product: "sdk", tag: "sdk-v1.2.3", commit: "b".repeat(40) }, - ]); -}); - -test("supports source-only selections and records the exact Swift source tag separately", () => { - const products = [product("oliphaunt-swift", ["github-release", "swift-package-source-tag"], "0.6.0")]; - const plan = publicConsumerPlan(lock(products, []), ["oliphaunt-swift"], graph(products)); - assert.deepEqual(plan.surfaces, []); - assert.deepEqual(plan.github.swift, { - product: "oliphaunt-swift", - version: "0.6.0", - tag: "0.6.0", - parentCommit: "b".repeat(40), - }); -}); - -test("derives consumer closures from package-manager scopes instead of publication-only dev edges", () => { - const products = [product("alpha", ["crates-io"])]; - const leaf = carrier("cargo:leaf", "alpha", 0); - leaf.packageDependencies = []; - const facade = carrier("cargo:facade", "alpha", 1, ["cargo:leaf"]); - facade.packageDependencies = [{ ecosystem: "cargo", name: "leaf", requirement: "=1.2.3", scope: "development" }]; - const developmentPlan = publicConsumerPlan(lock(products, [leaf, facade]), ["alpha"], graph(products)); - assert.deepEqual(developmentPlan.surfaces[0].entryClosures, [ - { entryCarrierId: "cargo:facade", carrierIds: ["cargo:facade"] }, - { entryCarrierId: "cargo:leaf", carrierIds: ["cargo:leaf"] }, - ]); - - facade.packageDependencies[0].scope = "runtime"; - const runtimePlan = publicConsumerPlan(lock(products, [leaf, facade]), ["alpha"], graph(products)); - assert.deepEqual(runtimePlan.surfaces[0].entryClosures, [{ - entryCarrierId: "cargo:facade", - carrierIds: ["cargo:facade", "cargo:leaf"], - }]); -}); - -test("projects cross-registry publication edges out of each public consumer closure", () => { - const products = [product("sdk", ["maven-central", "npm"])]; - const frozen = lock(products, [ - carrier("npm:@example/sdk", "sdk", 0), - carrier("maven:dev.example:sdk", "sdk", 1, ["npm:@example/sdk"]), - ]); - const plan = publicConsumerPlan(frozen, ["sdk"], graph(products)); - assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === "npm").entryClosures, [ - { entryCarrierId: "npm:@example/sdk", carrierIds: ["npm:@example/sdk"] }, - ]); - assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === "maven").entryClosures, [ - { entryCarrierId: "maven:dev.example:sdk", carrierIds: ["maven:dev.example:sdk"] }, - ]); -}); - -test("fails closed on product, target, carrier, and dependency-closure omissions", () => { - const products = [product("alpha", ["npm"]), product("beta", ["npm"])]; - const frozen = lock(products, [ - carrier("npm:@example/alpha", "alpha", 0), - carrier("npm:@example/beta", "beta", 1, ["npm:@example/alpha"]), - ]); - assert.throws(() => publicConsumerPlan(frozen, ["beta"], graph(products)), /exactly match the frozen publication lock/u); - - const unsupported = [product("alpha", ["invented-registry"])]; - assert.throws(() => publicConsumerPlan(lock(unsupported, []), ["alpha"], graph(unsupported)), /unsupported public consumer targets/u); - - const mismatch = [product("alpha", ["npm"])]; - assert.throws(() => publicConsumerPlan(lock(mismatch, []), ["alpha"], graph(mismatch)), /publish targets and frozen carrier products disagree/u); - - const omitted = lock(products, [carrier("npm:@example/beta", "beta", 0, ["npm:@example/alpha"])]); - assert.throws(() => publicConsumerPlan(omitted, ["alpha", "beta"], graph(products)), /publish targets and frozen carrier products disagree|omits locked dependencies/u); - - const cycleProducts = [product("cycle", ["npm"])]; - const cycle = lock(cycleProducts, [ - carrier("npm:a", "cycle", 0, ["npm:b"]), - carrier("npm:b", "cycle", 1, ["npm:a"]), - ]); - assert.throws(() => publicConsumerPlan(cycle, ["cycle"], graph(cycleProducts)), /no public consumer entry root/u); -}); - -test("validates exact public Cargo, npm, and Maven resolution records", () => { - const cargo = [carrier("cargo:alpha", "alpha", 0)]; - assert.deepEqual(validateCargoResolution(`version = 4 - -[[package]] -name = "alpha" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "${"d".repeat(64)}" -`, cargo), [{ id: "cargo:alpha", version: "1.2.3", checksum: "d".repeat(64) }]); - assert.throws(() => validateCargoResolution(`version = 4 -[[package]] -name = "alpha" -version = "1.2.3" -source = "path+file:///workspace" -checksum = "${"d".repeat(64)}" -`, cargo), /non-public or substituted Cargo source/u); - assert.throws(() => validateCargoResolution(`version = 4 -[[package]] -name = "alpha" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index-substitute" -checksum = "${"d".repeat(64)}" -`, cargo), /non-public or substituted Cargo source/u); - - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-public-consumer-test-")); - try { - const packageRoot = path.join(root, "node_modules", "@example", "alpha"); - mkdirSync(packageRoot, { recursive: true }); - writeFileSync(path.join(packageRoot, "package.json"), '{"name":"@example/alpha","version":"1.2.3"}\n'); - const npmCarrier = [carrier("npm:@example/alpha", "alpha", 0)]; - const npm = validateNpmResolution({ - lockfileVersion: 3, - packages: { - "": { name: "consumer", version: "0.0.0" }, - "node_modules/@example/alpha": { - version: "1.2.3", - resolved: "https://registry.npmjs.org/@example/alpha/-/alpha-1.2.3.tgz", - integrity: "sha512-exact", - }, - }, - }, npmCarrier, ["npm:@example/alpha"], root); - assert.deepEqual(npm.installedCarrierIds, ["npm:@example/alpha"]); - assert.throws(() => validateNpmResolution({ - lockfileVersion: 3, - packages: { "node_modules/@example/alpha": { version: "1.2.3", resolved: "file:../alpha", integrity: "sha512-exact" } }, - }, npmCarrier, ["npm:@example/alpha"], root), /non-public, linked, or integrity-free/u); - } finally { - rmSync(root, { recursive: true, force: true }); - } - - const mavenCarrier = [carrier("maven:dev.example:alpha", "alpha", 0)]; - assert.deepEqual( - validateMavenResolution("OLIPHAUNT_PUBLIC_COMPONENT\tmaven:dev.example:alpha\tdev.example\talpha\t1.2.3\n", mavenCarrier), - { - entries: [{ entryCarrierId: "maven:dev.example:alpha", resolvedCarrierIds: ["maven:dev.example:alpha"] }], - resolved: [{ id: "maven:dev.example:alpha", version: "1.2.3" }], - }, - ); - assert.throws(() => validateMavenResolution("", mavenCarrier), /omitted from its independent clean Maven Central resolution/u); -}); - -test("selects every opt-in Cargo entry feature for exhaustive carrier resolution", () => { - const entry = carrier("cargo:facade", "alpha", 1); - entry.artifacts = [{ - path: "target/cargo/facade-1.2.3.crate", - sha256: "d".repeat(64), - size: 1, - }]; - assert.deepEqual(cargoEntryFeatureNames({ - version: { - crate: "facade", - num: "1.2.3", - checksum: "d".repeat(64), - crate_size: 1, - yanked: false, - features: { - wasix: ["dep:facade-wasix"], - default: ["native"], - native: ["dep:facade-linux"], - }, - features2: { - "wasix-aot-x86_64-unknown-linux-gnu": ["dep:facade-wasix", "dep:facade-aot-linux"], - }, - }, - }, entry), [ - "native", - "wasix", - "wasix-aot-x86_64-unknown-linux-gnu", - ]); - assert.throws( - () => cargoEntryFeatureNames({ - version: { - crate: "facade", - num: "9.9.9", - checksum: "d".repeat(64), - crate_size: 1, - yanked: false, - features: {}, - }, - }, entry), - /metadata does not match/u, - ); - assert.throws( - () => cargoEntryFeatureNames({ - version: { - crate: "facade", - num: "1.2.3", - checksum: "d".repeat(64), - crate_size: 1, - yanked: false, - features: { broken: [null] }, - }, - }, entry), - /invalid Cargo feature declaration/u, - ); - assert.throws( - () => cargoEntryFeatureNames({ - version: { - crate: "facade", - num: "1.2.3", - checksum: "d".repeat(64), - crate_size: 2, - yanked: false, - features: {}, - }, - }, entry), - /metadata does not match/u, - ); - assert.throws( - () => cargoEntryFeatureNames({ - version: { - crate: "facade", - num: "1.2.3", - checksum: "d".repeat(64), - crate_size: 1, - yanked: true, - features: {}, - }, - }, entry), - /metadata does not match/u, - ); - assert.throws( - () => cargoEntryFeatureNames({ - version: { - crate: "facade", - num: "1.2.3", - checksum: "d".repeat(64), - crate_size: 1, - yanked: false, - features: { wasix: ["dep:facade-wasix"] }, - features2: { wasix: ["dep:substituted"] }, - }, - }, entry), - /features and features2 disagree/u, - ); -}); - -test("public probes discard inherited credentials and package-manager substitution settings", () => { - const env = sanitizedPublicEnvironment({ - NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/", - }, { - PATH: "/usr/bin", - CARGO_SOURCE_CRATES_IO_REPLACE_WITH: "local-mirror", - DENO_CONFIG: "/workspace/deno.json", - GIT_CONFIG_COUNT: "1", - GIT_CONFIG_KEY_0: "url.file:///workspace/.insteadOf", - GIT_CONFIG_VALUE_0: "https://github.com/", - GRADLE_OPTS: "-I /workspace/substitute.gradle", - NPM_CONFIG_REGISTRY: "https://private.invalid/", - npm_config_userconfig: "/workspace/.npmrc", - ORG_GRADLE_PROJECT_repositoryPassword: "secret", - RELEASE_TOKEN: "secret", - }); - assert.deepEqual(env, { - PATH: "/usr/bin", - NPM_CONFIG_REGISTRY: "https://registry.npmjs.org/", - }); -}); - -test("clean Cargo consumers retain only the exact installed Rust toolchain context", async () => { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-public-cargo-toolchain-test-")); - try { - const consumerHome = path.join(root, "consumer-home"); - const cargoHome = path.join(root, "cargo-home"); - mkdirSync(consumerHome, { recursive: true }); - mkdirSync(cargoHome, { recursive: true }); - const env = publicCargoEnvironment(root, { - ...process.env, - CARGO_REGISTRY_TOKEN: "must-not-survive", - CARGO_SOURCE_CRATES_IO_REPLACE_WITH: "must-not-survive", - RUSTUP_TOOLCHAIN: "nightly", - }); - assert.equal(env.CARGO_HOME, cargoHome); - assert.equal(env.HOME, path.join(root, "cargo-user-home")); - assert.equal(env.RUSTUP_TOOLCHAIN, "1.93.1"); - assert.notEqual(env.RUSTUP_HOME, path.join(env.HOME, ".rustup")); - assert.equal(env.CARGO_REGISTRY_TOKEN, undefined); - assert.equal(env.CARGO_SOURCE_CRATES_IO_REPLACE_WITH, undefined); - writeFileSync( - path.join(root, "Cargo.toml"), - '[package]\nname = "clean-cargo-toolchain-probe"\nversion = "0.0.0"\nedition = "2021"\n', - ); - mkdirSync(path.join(root, "src")); - writeFileSync(path.join(root, "src", "lib.rs"), ""); - await runBoundedCommand("cargo", ["generate-lockfile"], { - cwd: root, - env, - deadlineMilliseconds: Date.now() + 30_000, - }); - assert.equal(existsSync(path.join(root, "Cargo.lock")), true); - const version = await runBoundedCommand("cargo", ["--version"], { - cwd: root, - env, - deadlineMilliseconds: Date.now() + 30_000, - }); - assert.match(version.stdout, /^cargo 1\.93\.1\b/u); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("Cargo consumer toolchain context fails closed on unpinned or unavailable inputs", () => { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-public-cargo-toolchain-policy-test-")); - try { - const rustupHome = path.join(root, "rustup"); - mkdirSync(rustupHome, { recursive: true }); - writeFileSync(path.join(root, "rust-toolchain.toml"), '[toolchain]\nchannel = "stable"\n'); - assert.throws( - () => publicCargoEnvironment(path.join(root, "consumer"), { RUSTUP_HOME: rustupHome }, { repositoryRoot: root }), - /must pin an exact stable Rust toolchain/u, - ); - writeFileSync(path.join(root, "rust-toolchain.toml"), '[toolchain]\nchannel = "1.93.1"\n'); - assert.throws( - () => publicCargoEnvironment( - path.join(root, "consumer"), - { RUSTUP_HOME: path.join(root, "missing") }, - { repositoryRoot: root }, - ), - /RUSTUP_HOME is unavailable/u, - ); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("builds canonical lock/receipt-bound evidence and writes it immutably", () => { - const products = [product("alpha", ["npm"])]; - const frozen = lock(products, [carrier("npm:@example/alpha", "alpha", 0)]); - const plan = publicConsumerPlan(frozen, ["alpha"], graph(products)); - const surfaces = [{ - surface: "npm", - mode: "anonymous-public-independent-entry-host-install-and-lock-resolution", - carrierIds: ["npm:@example/alpha"], - dependencyScopes: ["optional", "peer", "runtime"], - entryCarrierIds: ["npm:@example/alpha"], - plannedEntryClosures: [{ entryCarrierId: "npm:@example/alpha", carrierIds: ["npm:@example/alpha"] }], - entries: [{ entryCarrierId: "npm:@example/alpha", resolvedCarrierIds: ["npm:@example/alpha"] }], - installedCarrierIds: ["npm:@example/alpha"], - resolved: [{ id: "npm:@example/alpha", version: "1.2.3", integrity: "sha512-exact" }], - receiptCoveredNotHostInstalledCarrierIds: [], - }, { - surface: "github", - mode: "anonymous-public-exact-tag-resolution", - productTags: plan.github.productTags, - swift: null, - }]; - const evidence = publicConsumerEvidence({ - lock: frozen, - plan, - registryReceiptSha256: "e".repeat(64), - githubReceiptDigest: "f".repeat(64), - surfaces, - }); - assert.equal(evidence.schema, PUBLIC_CONSUMER_EVIDENCE_SCHEMA); - assert.equal(validatePublicConsumerEvidence(evidence, frozen, plan), evidence); - const changed = structuredClone(evidence); - changed.surfaces.find(({ surface }) => surface === "github").productTags = []; - assert.throws(() => validatePublicConsumerEvidence(changed, frozen, plan), /every exact product tag/u); - - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-public-evidence-test-")); - try { - const file = path.join(root, "evidence.json"); - writeImmutablePublicConsumerEvidence(file, evidence); - writeImmutablePublicConsumerEvidence(file, evidence); - assert.equal(JSON.parse(readFileSync(file, "utf8")).evidenceDigest, evidence.evidenceDigest); - const conflict = { ...evidence, evidenceDigest: digest("different") }; - assert.throws(() => writeImmutablePublicConsumerEvidence(file, conflict), /non-identical immutable/u); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("cannot silently relabel a frozen entry dependency as receipt-only", () => { - const products = [product("alpha", ["npm"])]; - const frozen = lock(products, [ - carrier("npm:@example/leaf", "alpha", 0), - carrier("npm:@example/alpha", "alpha", 1, ["npm:@example/leaf"]), - ]); - const plan = publicConsumerPlan(frozen, ["alpha"], graph(products)); - const evidence = publicConsumerEvidence({ - lock: frozen, - plan, - registryReceiptSha256: "e".repeat(64), - githubReceiptDigest: "f".repeat(64), - surfaces: [{ - surface: "npm", - mode: "anonymous-public-independent-entry-host-install-and-lock-resolution", - carrierIds: ["npm:@example/alpha", "npm:@example/leaf"], - dependencyScopes: ["optional", "peer", "runtime"], - entryCarrierIds: ["npm:@example/alpha"], - plannedEntryClosures: [{ - entryCarrierId: "npm:@example/alpha", - carrierIds: ["npm:@example/alpha", "npm:@example/leaf"], - }], - entries: [{ entryCarrierId: "npm:@example/alpha", resolvedCarrierIds: ["npm:@example/alpha"] }], - installedCarrierIds: ["npm:@example/alpha"], - receiptCoveredNotHostInstalledCarrierIds: ["npm:@example/leaf"], - resolved: [{ id: "npm:@example/alpha", version: "1.2.3", integrity: "sha512-exact" }], - }, { - surface: "github", - mode: "anonymous-public-exact-tag-resolution", - productTags: plan.github.productTags, - swift: null, - }], - }); - assert.throws( - () => validatePublicConsumerEvidence(evidence, frozen, plan), - /omitted frozen platform-independent lock dependencies/u, - ); -}); - -test("subprocesses share one hard deadline and honor peer cancellation", async () => { - const ok = await runBoundedCommand(process.execPath, ["-e", "process.stdout.write('ok')"], { - deadlineMilliseconds: Date.now() + 5_000, - }); - assert.equal(ok.stdout, "ok"); - await assert.rejects( - () => runBoundedCommand(process.execPath, ["-e", "0"], { deadlineMilliseconds: Date.now() - 1 }), - /shared public-consumer deadline reached/u, - ); - const controller = new AbortController(); - controller.abort(); - await assert.rejects( - () => runBoundedCommand(process.execPath, ["-e", "0"], { - deadlineMilliseconds: Date.now() + 5_000, - signal: controller.signal, - }), - /cancelled before it could access/u, - ); -}); - -test("transient registry visibility failures retry from an empty workspace and cache", async () => { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-public-retry-test-")); - const attempts = []; - try { - const result = await runSurfaceWithRetries( - "npm", - root, - Date.now() + 60_000, - new AbortController().signal, - async (attemptRoot) => { - attempts.push(attemptRoot); - if (attempts.length === 1) { - writeFileSync(path.join(attemptRoot, "partial-install"), "must not survive\n"); - await runBoundedCommand(process.execPath, ["-e", "console.error('npm E404 Not Found'); process.exit(1)"], { - deadlineMilliseconds: Date.now() + 5_000, - }); - } - assert.equal(existsSync(path.join(attemptRoot, "partial-install")), false); - return "resolved"; - }, - { maxAttempts: 2, retryDelays: [1] }, - ); - assert.equal(result, "resolved"); - assert.equal(attempts.length, 2); - assert.notEqual(attempts[0], attempts[1]); - assert.equal(existsSync(attempts[0]), false); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/public-consumer-smoke.test.mts b/tools/release/public-consumer-smoke.test.mts new file mode 100644 index 000000000..2017f69da --- /dev/null +++ b/tools/release/public-consumer-smoke.test.mts @@ -0,0 +1,685 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; + +import { + cargoEntryFeatureNames, + PUBLIC_CONSUMER_EVIDENCE_SCHEMA, + publicCargoEnvironment, + publicConsumerEvidence, + publicConsumerPlan, + sanitizedPublicEnvironment, + validateCargoResolution, + validateMavenResolution, + validateNpmResolution, + validatePublicConsumerEvidence, + writeImmutablePublicConsumerEvidence, +} from './public-consumer-smoke.mts'; + +const digest = (value) => createHash('sha256').update(value).digest('hex'); + +function product(id, publishTargets, version = '1.2.3') { + return { id, version, publishTargets, dependencies: [], kind: 'sdk', path: `src/${id}` }; +} + +function carrier(id, productId, publishOrder, dependencies = []) { + const separator = id.indexOf(':'); + return { + id, + product: productId, + ecosystem: id.slice(0, separator), + name: id.slice(separator + 1), + version: '1.2.3', + publishOrder, + dependencies, + }; +} + +function lock(products, carriers) { + return { + lockDigest: 'a'.repeat(64), + source: { commit: 'b'.repeat(40), tree: 'c'.repeat(40) }, + products, + carriers, + }; +} + +function graph(products) { + return { + products: Object.fromEntries( + products.map((row) => [ + row.id, + { + tag_prefix: `${row.id}-v`, + version: row.version, + }, + ]), + ), + }; +} + +const [fixtureMode, fixtureRoot, scenario] = process.argv.slice(2); +if (fixtureMode === 'prepare-cargo') { + const environment = publicCargoEnvironment(fixtureRoot, { + ...process.env, + CARGO_REGISTRY_TOKEN: 'must-not-survive', + CARGO_SOURCE_CRATES_IO_REPLACE_WITH: 'must-not-survive', + RUSTUP_TOOLCHAIN: 'nightly', + }); + assert.equal(environment.CARGO_HOME, path.join(fixtureRoot, 'cargo-home')); + assert.equal(environment.HOME, path.join(fixtureRoot, 'cargo-user-home')); + assert.equal( + environment.RUSTUP_TOOLCHAIN, + Bun.TOML.parse(readFileSync('rust-toolchain.toml', 'utf8')).toolchain.channel, + ); + assert.notEqual(environment.RUSTUP_HOME, path.join(environment.HOME, '.rustup')); + assert.equal(environment.CARGO_REGISTRY_TOKEN, undefined); + assert.equal(environment.CARGO_SOURCE_CRATES_IO_REPLACE_WITH, undefined); + writeFileSync( + path.join(fixtureRoot, 'environment'), + Object.entries(environment) + .map(([key, value]) => `${key}=${value}\0`) + .join(''), + ); + writeFileSync( + path.join(fixtureRoot, 'Cargo.toml'), + '[package]\nname="clean-cargo-toolchain-probe"\nversion="0.0.0"\nedition="2021"\n', + ); + mkdirSync(path.join(fixtureRoot, 'src')); + writeFileSync(path.join(fixtureRoot, 'src/lib.rs'), ''); + process.exit(0); +} +if (fixtureMode === 'prepare-npm') { + const products = [product('sdk', ['npm'])]; + const frozen = lock(products, [carrier('npm:@example/sdk', 'sdk', 0)]); + writeFileSync( + path.join(fixtureRoot, 'context.json'), + JSON.stringify({ + lock: frozen, + plan: publicConsumerPlan(frozen, ['sdk'], graph(products)), + deadlineMilliseconds: Date.now() + (scenario === 'timeout' ? 2000 : 30000), + }), + ); + process.exit(0); +} +if (fixtureMode === 'install-npm') { + const manifest = JSON.parse(readFileSync('package.json', 'utf8')); + const [[name, version]] = Object.entries(manifest.dependencies); + mkdirSync(`node_modules/${name}`, { recursive: true }); + writeFileSync(`node_modules/${name}/package.json`, JSON.stringify({ name, version })); + writeFileSync( + 'package-lock.json', + JSON.stringify({ + lockfileVersion: 3, + packages: { + [`node_modules/${name}`]: { + version, + resolved: `https://registry.npmjs.org/${name}/-/sdk.tgz`, + integrity: 'sha512-smoke', + }, + }, + }), + ); + process.exit(0); +} +if (fixtureMode === 'assert-npm') { + if (scenario === 'success') { + const result = JSON.parse(readFileSync(path.join(fixtureRoot, 'npm.json'), 'utf8')); + assert.deepEqual(result.installedCarrierIds, ['npm:@example/sdk']); + assert.deepEqual( + result.resolved.map(({ id }) => id), + ['npm:@example/sdk'], + ); + } else assert.equal(existsSync(path.join(fixtureRoot, 'npm.json')), false); + process.exit(0); +} + +test('derives every registry surface and graph-root entry from the exact selected lock', () => { + const products = [ + product('runtime', ['crates-io', 'maven-central', 'npm']), + product('sdk', ['crates-io', 'maven-central', 'npm']), + ]; + const frozen = lock(products, [ + carrier('cargo:runtime-leaf', 'runtime', 0), + carrier('npm:@example/runtime-leaf', 'runtime', 1), + carrier('maven:dev.example:runtime', 'runtime', 2), + carrier('cargo:sdk', 'sdk', 3, ['cargo:runtime-leaf']), + carrier('npm:@example/sdk', 'sdk', 4, ['npm:@example/runtime-leaf']), + carrier('maven:dev.example:sdk', 'sdk', 5, ['maven:dev.example:runtime']), + ]); + const plan = publicConsumerPlan(frozen, ['runtime', 'sdk'], graph(products)); + assert.deepEqual( + plan.surfaces.map(({ ecosystem }) => ecosystem), + ['cargo', 'maven', 'npm'], + ); + assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === 'cargo').entryCarrierIds, [ + 'cargo:sdk', + ]); + assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === 'cargo').entryClosures, [ + { + entryCarrierId: 'cargo:sdk', + carrierIds: ['cargo:runtime-leaf', 'cargo:sdk'], + }, + ]); + assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === 'npm').entryCarrierIds, [ + 'npm:@example/sdk', + ]); + assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === 'maven').entryCarrierIds, [ + 'maven:dev.example:sdk', + ]); + assert.deepEqual(plan.github.productTags, [ + { product: 'runtime', tag: 'runtime-v1.2.3', commit: 'b'.repeat(40) }, + { product: 'sdk', tag: 'sdk-v1.2.3', commit: 'b'.repeat(40) }, + ]); +}); + +test('supports source-only selections and records the exact Swift source tag separately', () => { + const products = [ + product('oliphaunt-swift', ['github-release', 'swift-package-source-tag'], '0.6.0'), + ]; + const plan = publicConsumerPlan(lock(products, []), ['oliphaunt-swift'], graph(products)); + assert.deepEqual(plan.surfaces, []); + assert.deepEqual(plan.github.swift, { + product: 'oliphaunt-swift', + version: '0.6.0', + tag: '0.6.0', + parentCommit: 'b'.repeat(40), + }); +}); + +test('derives consumer closures from package-manager scopes instead of publication-only dev edges', () => { + const products = [product('alpha', ['crates-io'])]; + const leaf = carrier('cargo:leaf', 'alpha', 0); + leaf.packageDependencies = []; + const facade = carrier('cargo:facade', 'alpha', 1, ['cargo:leaf']); + facade.packageDependencies = [ + { ecosystem: 'cargo', name: 'leaf', requirement: '=1.2.3', scope: 'development' }, + ]; + const developmentPlan = publicConsumerPlan( + lock(products, [leaf, facade]), + ['alpha'], + graph(products), + ); + assert.deepEqual(developmentPlan.surfaces[0].entryClosures, [ + { entryCarrierId: 'cargo:facade', carrierIds: ['cargo:facade'] }, + { entryCarrierId: 'cargo:leaf', carrierIds: ['cargo:leaf'] }, + ]); + + facade.packageDependencies[0].scope = 'runtime'; + const runtimePlan = publicConsumerPlan( + lock(products, [leaf, facade]), + ['alpha'], + graph(products), + ); + assert.deepEqual(runtimePlan.surfaces[0].entryClosures, [ + { + entryCarrierId: 'cargo:facade', + carrierIds: ['cargo:facade', 'cargo:leaf'], + }, + ]); +}); + +test('projects cross-registry publication edges out of each public consumer closure', () => { + const products = [product('sdk', ['maven-central', 'npm'])]; + const frozen = lock(products, [ + carrier('npm:@example/sdk', 'sdk', 0), + carrier('maven:dev.example:sdk', 'sdk', 1, ['npm:@example/sdk']), + ]); + const plan = publicConsumerPlan(frozen, ['sdk'], graph(products)); + assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === 'npm').entryClosures, [ + { entryCarrierId: 'npm:@example/sdk', carrierIds: ['npm:@example/sdk'] }, + ]); + assert.deepEqual(plan.surfaces.find(({ ecosystem }) => ecosystem === 'maven').entryClosures, [ + { entryCarrierId: 'maven:dev.example:sdk', carrierIds: ['maven:dev.example:sdk'] }, + ]); +}); + +test('fails closed on product, target, carrier, and dependency-closure omissions', () => { + const products = [product('alpha', ['npm']), product('beta', ['npm'])]; + const frozen = lock(products, [ + carrier('npm:@example/alpha', 'alpha', 0), + carrier('npm:@example/beta', 'beta', 1, ['npm:@example/alpha']), + ]); + assert.throws( + () => publicConsumerPlan(frozen, ['beta'], graph(products)), + /exactly match the frozen publication lock/u, + ); + + const unsupported = [product('alpha', ['invented-registry'])]; + assert.throws( + () => publicConsumerPlan(lock(unsupported, []), ['alpha'], graph(unsupported)), + /unsupported public consumer targets/u, + ); + + const mismatch = [product('alpha', ['npm'])]; + assert.throws( + () => publicConsumerPlan(lock(mismatch, []), ['alpha'], graph(mismatch)), + /publish targets and frozen carrier products disagree/u, + ); + + const omitted = lock(products, [carrier('npm:@example/beta', 'beta', 0, ['npm:@example/alpha'])]); + assert.throws( + () => publicConsumerPlan(omitted, ['alpha', 'beta'], graph(products)), + /publish targets and frozen carrier products disagree|omits locked dependencies/u, + ); + + const cycleProducts = [product('cycle', ['npm'])]; + const cycle = lock(cycleProducts, [ + carrier('npm:a', 'cycle', 0, ['npm:b']), + carrier('npm:b', 'cycle', 1, ['npm:a']), + ]); + assert.throws( + () => publicConsumerPlan(cycle, ['cycle'], graph(cycleProducts)), + /no public consumer entry root/u, + ); +}); + +test('validates exact public Cargo, npm, and Maven resolution records', () => { + const cargo = [carrier('cargo:alpha', 'alpha', 0)]; + assert.deepEqual( + validateCargoResolution( + `version = 4 + +[[package]] +name = "alpha" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "${'d'.repeat(64)}" +`, + cargo, + ), + [{ id: 'cargo:alpha', version: '1.2.3', checksum: 'd'.repeat(64) }], + ); + assert.throws( + () => + validateCargoResolution( + `version = 4 +[[package]] +name = "alpha" +version = "1.2.3" +source = "path+file:///workspace" +checksum = "${'d'.repeat(64)}" +`, + cargo, + ), + /non-public or substituted Cargo source/u, + ); + assert.throws( + () => + validateCargoResolution( + `version = 4 +[[package]] +name = "alpha" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index-substitute" +checksum = "${'d'.repeat(64)}" +`, + cargo, + ), + /non-public or substituted Cargo source/u, + ); + + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-public-consumer-test-')); + try { + const packageRoot = path.join(root, 'node_modules', '@example', 'alpha'); + mkdirSync(packageRoot, { recursive: true }); + writeFileSync( + path.join(packageRoot, 'package.json'), + '{"name":"@example/alpha","version":"1.2.3"}\n', + ); + const npmCarrier = [carrier('npm:@example/alpha', 'alpha', 0)]; + const npm = validateNpmResolution( + { + lockfileVersion: 3, + packages: { + '': { name: 'consumer', version: '0.0.0' }, + 'node_modules/@example/alpha': { + version: '1.2.3', + resolved: 'https://registry.npmjs.org/@example/alpha/-/alpha-1.2.3.tgz', + integrity: 'sha512-exact', + }, + }, + }, + npmCarrier, + ['npm:@example/alpha'], + root, + ); + assert.deepEqual(npm.installedCarrierIds, ['npm:@example/alpha']); + assert.throws( + () => + validateNpmResolution( + { + lockfileVersion: 3, + packages: { + 'node_modules/@example/alpha': { + version: '1.2.3', + resolved: 'file:../alpha', + integrity: 'sha512-exact', + }, + }, + }, + npmCarrier, + ['npm:@example/alpha'], + root, + ), + /non-public, linked, or integrity-free/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } + + const mavenCarrier = [carrier('maven:dev.example:alpha', 'alpha', 0)]; + assert.deepEqual( + validateMavenResolution( + 'OLIPHAUNT_PUBLIC_COMPONENT\tmaven:dev.example:alpha\tdev.example\talpha\t1.2.3\n', + mavenCarrier, + ), + { + entries: [ + { + entryCarrierId: 'maven:dev.example:alpha', + resolvedCarrierIds: ['maven:dev.example:alpha'], + }, + ], + resolved: [{ id: 'maven:dev.example:alpha', version: '1.2.3' }], + }, + ); + assert.throws( + () => validateMavenResolution('', mavenCarrier), + /omitted from its independent clean Maven Central resolution/u, + ); +}); + +test('selects every opt-in Cargo entry feature for exhaustive carrier resolution', () => { + const entry = carrier('cargo:facade', 'alpha', 1); + entry.artifacts = [ + { + path: 'target/cargo/facade-1.2.3.crate', + sha256: 'd'.repeat(64), + size: 1, + }, + ]; + assert.deepEqual( + cargoEntryFeatureNames( + { + version: { + crate: 'facade', + num: '1.2.3', + checksum: 'd'.repeat(64), + crate_size: 1, + yanked: false, + features: { + wasix: ['dep:facade-wasix'], + default: ['native'], + native: ['dep:facade-linux'], + }, + features2: { + 'wasix-aot-x86_64-unknown-linux-gnu': ['dep:facade-wasix', 'dep:facade-aot-linux'], + }, + }, + }, + entry, + ), + ['native', 'wasix', 'wasix-aot-x86_64-unknown-linux-gnu'], + ); + assert.throws( + () => + cargoEntryFeatureNames( + { + version: { + crate: 'facade', + num: '9.9.9', + checksum: 'd'.repeat(64), + crate_size: 1, + yanked: false, + features: {}, + }, + }, + entry, + ), + /metadata does not match/u, + ); + assert.throws( + () => + cargoEntryFeatureNames( + { + version: { + crate: 'facade', + num: '1.2.3', + checksum: 'd'.repeat(64), + crate_size: 1, + yanked: false, + features: { broken: [null] }, + }, + }, + entry, + ), + /invalid Cargo feature declaration/u, + ); + assert.throws( + () => + cargoEntryFeatureNames( + { + version: { + crate: 'facade', + num: '1.2.3', + checksum: 'd'.repeat(64), + crate_size: 2, + yanked: false, + features: {}, + }, + }, + entry, + ), + /metadata does not match/u, + ); + assert.throws( + () => + cargoEntryFeatureNames( + { + version: { + crate: 'facade', + num: '1.2.3', + checksum: 'd'.repeat(64), + crate_size: 1, + yanked: true, + features: {}, + }, + }, + entry, + ), + /metadata does not match/u, + ); + assert.throws( + () => + cargoEntryFeatureNames( + { + version: { + crate: 'facade', + num: '1.2.3', + checksum: 'd'.repeat(64), + crate_size: 1, + yanked: false, + features: { wasix: ['dep:facade-wasix'] }, + features2: { wasix: ['dep:substituted'] }, + }, + }, + entry, + ), + /features and features2 disagree/u, + ); +}); + +test('public probes discard inherited credentials and package-manager substitution settings', () => { + const env = sanitizedPublicEnvironment( + { + NPM_CONFIG_REGISTRY: 'https://registry.npmjs.org/', + }, + { + PATH: '/usr/bin', + CARGO_SOURCE_CRATES_IO_REPLACE_WITH: 'local-mirror', + CARGO_TARGET_DIR: '/workspace/target', + CARGO_BUILD_RUSTC_WRAPPER: '/workspace/wrapper', + RUSTFLAGS: '--cfg local_only', + RUSTC_WRAPPER: '/workspace/wrapper', + OLIPHAUNT_NATIVE_ARTIFACT_DIR: '/workspace/target/native', + LIBOLIPHAUNT_RUNTIME_DIR: '/workspace/target/runtime', + NODE_OPTIONS: '--require=/workspace/substitute.cjs', + NODE_PATH: '/workspace/node_modules', + LD_LIBRARY_PATH: '/workspace/lib', + DYLD_LIBRARY_PATH: '/workspace/lib', + DENO_CONFIG: '/workspace/deno.json', + GIT_CONFIG_COUNT: '1', + GIT_CONFIG_KEY_0: 'url.file:///workspace/.insteadOf', + GIT_CONFIG_VALUE_0: 'https://github.com/', + GRADLE_OPTS: '-I /workspace/substitute.gradle', + NPM_CONFIG_REGISTRY: 'https://private.invalid/', + npm_config_userconfig: '/workspace/.npmrc', + ORG_GRADLE_PROJECT_repositoryPassword: 'secret', + RELEASE_TOKEN: 'secret', + }, + ); + assert.deepEqual(env, { + PATH: '/usr/bin', + NPM_CONFIG_REGISTRY: 'https://registry.npmjs.org/', + }); +}); + +test('Cargo consumer toolchain context fails closed on unpinned or unavailable inputs', () => { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-public-cargo-toolchain-policy-test-')); + try { + const rustupHome = path.join(root, 'rustup'); + mkdirSync(rustupHome, { recursive: true }); + writeFileSync(path.join(root, 'rust-toolchain.toml'), '[toolchain]\nchannel = "stable"\n'); + assert.throws( + () => + publicCargoEnvironment( + path.join(root, 'consumer'), + { RUSTUP_HOME: rustupHome }, + { repositoryRoot: root }, + ), + /must pin an exact stable Rust toolchain/u, + ); + writeFileSync(path.join(root, 'rust-toolchain.toml'), '[toolchain]\nchannel = "1.93.1"\n'); + assert.throws( + () => + publicCargoEnvironment( + path.join(root, 'consumer'), + { RUSTUP_HOME: path.join(root, 'missing') }, + { repositoryRoot: root }, + ), + /RUSTUP_HOME is unavailable/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('builds canonical lock/receipt-bound evidence and writes it immutably', () => { + const products = [product('alpha', ['npm'])]; + const frozen = lock(products, [carrier('npm:@example/alpha', 'alpha', 0)]); + const plan = publicConsumerPlan(frozen, ['alpha'], graph(products)); + const surfaces = [ + { + surface: 'npm', + mode: 'anonymous-public-independent-entry-host-install-and-lock-resolution', + carrierIds: ['npm:@example/alpha'], + dependencyScopes: ['optional', 'peer', 'runtime'], + entryCarrierIds: ['npm:@example/alpha'], + plannedEntryClosures: [ + { entryCarrierId: 'npm:@example/alpha', carrierIds: ['npm:@example/alpha'] }, + ], + entries: [ + { entryCarrierId: 'npm:@example/alpha', resolvedCarrierIds: ['npm:@example/alpha'] }, + ], + installedCarrierIds: ['npm:@example/alpha'], + resolved: [{ id: 'npm:@example/alpha', version: '1.2.3', integrity: 'sha512-exact' }], + receiptCoveredNotHostInstalledCarrierIds: [], + }, + { + surface: 'github', + mode: 'anonymous-public-exact-tag-resolution', + productTags: plan.github.productTags, + swift: null, + }, + ]; + const evidence = publicConsumerEvidence({ + lock: frozen, + plan, + registryReceiptSha256: 'e'.repeat(64), + githubReceiptDigest: 'f'.repeat(64), + surfaces, + }); + assert.equal(evidence.schema, PUBLIC_CONSUMER_EVIDENCE_SCHEMA); + assert.equal(validatePublicConsumerEvidence(evidence, frozen, plan), evidence); + const changed = structuredClone(evidence); + changed.surfaces.find(({ surface }) => surface === 'github').productTags = []; + assert.throws( + () => validatePublicConsumerEvidence(changed, frozen, plan), + /every exact product tag/u, + ); + + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-public-evidence-test-')); + try { + const file = path.join(root, 'evidence.json'); + writeImmutablePublicConsumerEvidence(file, evidence); + writeImmutablePublicConsumerEvidence(file, evidence); + assert.equal(JSON.parse(readFileSync(file, 'utf8')).evidenceDigest, evidence.evidenceDigest); + const conflict = { ...evidence, evidenceDigest: digest('different') }; + assert.throws( + () => writeImmutablePublicConsumerEvidence(file, conflict), + /non-identical immutable/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('cannot silently relabel a frozen entry dependency as receipt-only', () => { + const products = [product('alpha', ['npm'])]; + const frozen = lock(products, [ + carrier('npm:@example/leaf', 'alpha', 0), + carrier('npm:@example/alpha', 'alpha', 1, ['npm:@example/leaf']), + ]); + const plan = publicConsumerPlan(frozen, ['alpha'], graph(products)); + const evidence = publicConsumerEvidence({ + lock: frozen, + plan, + registryReceiptSha256: 'e'.repeat(64), + githubReceiptDigest: 'f'.repeat(64), + surfaces: [ + { + surface: 'npm', + mode: 'anonymous-public-independent-entry-host-install-and-lock-resolution', + carrierIds: ['npm:@example/alpha', 'npm:@example/leaf'], + dependencyScopes: ['optional', 'peer', 'runtime'], + entryCarrierIds: ['npm:@example/alpha'], + plannedEntryClosures: [ + { + entryCarrierId: 'npm:@example/alpha', + carrierIds: ['npm:@example/alpha', 'npm:@example/leaf'], + }, + ], + entries: [ + { entryCarrierId: 'npm:@example/alpha', resolvedCarrierIds: ['npm:@example/alpha'] }, + ], + installedCarrierIds: ['npm:@example/alpha'], + receiptCoveredNotHostInstalledCarrierIds: ['npm:@example/leaf'], + resolved: [{ id: 'npm:@example/alpha', version: '1.2.3', integrity: 'sha512-exact' }], + }, + { + surface: 'github', + mode: 'anonymous-public-exact-tag-resolution', + productTags: plan.github.productTags, + swift: null, + }, + ], + }); + assert.throws( + () => validatePublicConsumerEvidence(evidence, frozen, plan), + /omitted frozen platform-independent lock dependencies/u, + ); +}); diff --git a/tools/release/public-consumer-smoke.test.sh b/tools/release/public-consumer-smoke.test.sh new file mode 100644 index 000000000..3812c8c73 --- /dev/null +++ b/tools/release/public-consumer-smoke.test.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/public-consumer-smoke.test.mts +source_root="$PWD" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +mkdir "$scratch/cargo" +bun tools/release/public-consumer-smoke.test.mts prepare-cargo "$scratch/cargo" +clean=(env -i) +while IFS= read -r -d '' entry; do clean+=("$entry"); done < "$scratch/cargo/environment" +(cd "$scratch/cargo"; "${clean[@]}" cargo generate-lockfile) +[[ -f "$scratch/cargo/Cargo.lock" ]] +mkdir "$scratch/bin" +cat > "$scratch/bin/npm" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +[[ -z "${SENSITIVE_TOKEN:-}${CARGO_REGISTRY_TOKEN:-}" ]] || { echo 'credentials leaked' >&2; exit 99; } +printf 'attempt\n' >> "$PUBLIC_PROBE_COUNTER" +[[ -z "${FAIL_PUBLIC_PROBE:-}" ]] || exit 7 +if [[ -n "${HANG_PUBLIC_PROBE:-}" ]]; then + sleep 30 & + printf '%s' "$!" > "$PUBLIC_PROBE_CHILD" + wait "$!" +fi +bun "$PUBLIC_PROBE_FIXTURE" install-npm +SH +chmod +x "$scratch/bin/npm" +export PATH="$scratch/bin:$PATH" SENSITIVE_TOKEN=must-not-survive CARGO_REGISTRY_TOKEN=must-not-survive +export PUBLIC_PROBE_COUNTER="$scratch/attempts" PUBLIC_PROBE_FIXTURE="$source_root/tools/release/public-consumer-smoke.test.mts" +for mode in success fail timeout; do + mkdir "$scratch/$mode" + bun tools/release/public-consumer-smoke.test.mts prepare-npm "$scratch/$mode" "$mode" + unset FAIL_PUBLIC_PROBE HANG_PUBLIC_PROBE PUBLIC_PROBE_CHILD + expected=0 + if [[ "$mode" == fail ]]; then export FAIL_PUBLIC_PROBE=1; expected=7; fi + if [[ "$mode" == timeout ]]; then export HANG_PUBLIC_PROBE=1 PUBLIC_PROBE_CHILD="$scratch/child-pid"; expected=124; fi + status=0 + bash tools/release/public-consumer-smoke.sh --surface "$scratch/$mode" npm > "$scratch/$mode/output" 2>&1 || status=$? + if [[ "$status" != "$expected" ]]; then cat "$scratch/$mode/output" >&2; exit 1; fi + bun tools/release/public-consumer-smoke.test.mts assert-npm "$scratch/$mode" "$mode" +done +[[ "$(wc -l < "$scratch/attempts")" -eq 3 ]] +pid="$(cat "$scratch/child-pid")" +status=0 +state="$(ps -o stat= -p "$pid")" || status=$? +[[ "$status" == 1 || "$state" == Z* || -z "$state" ]] +echo 'Public consumers: clean Cargo context, npm resolution, no retry on failure and descendant timeout passed' diff --git a/tools/release/publication-catalog.mjs b/tools/release/publication-catalog.mjs deleted file mode 100644 index 1afd2eff3..000000000 --- a/tools/release/publication-catalog.mjs +++ /dev/null @@ -1,292 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; - -import { - compareText, - loadGraph, - releaseOrder, -} from "./release-graph.mjs"; -import { registryPackageRows } from "./release-artifact-targets.mjs"; -import { - EXTENSION_AOT_PACKAGE_SUFFIXES, - EXTENSION_PORTABLE_TARGET, -} from "./wasix-cargo-artifact-contract.mjs"; -import { extensionNpmWasixPackageForProduct } from "./extension-registry-packages.mjs"; -import { - WASIX_RUNTIME_NPM_PACKAGE, - WASIX_RUNTIME_NPM_TARGET, - WASIX_RUNTIME_PRODUCT, -} from "./wasix-runtime-npm-contract.mjs"; -import { WASIX_ICU_NPM_PACKAGE } from "./wasix-icu-npm-contract.mjs"; - -export const PUBLICATION_CATALOG_SCHEMA = "oliphaunt-publication-catalog-v1"; - -export const REGISTRY_KIND_TO_ECOSYSTEM = Object.freeze({ - crates: "cargo", - npm: "npm", - maven: "maven", -}); - -const TARGET_MARKERS = [ - "aarch64-unknown-linux-gnu", - "x86_64-unknown-linux-gnu", - "aarch64-apple-darwin", - "x86_64-pc-windows-msvc", - "android-arm64-v8a", - "android-x86_64", - "linux-arm64-gnu", - "linux-x64-gnu", - "macos-arm64", - "windows-x64-msvc", - "darwin-arm64", - "win32-x64-msvc", - "portable", -]; -const SPLITTABLE_CARGO_ROLES = new Set([ - "platform-leaf", - "aot-leaf", - "portable-leaf", -]); -const EXTENSION_AOT_TARGET_SUFFIXES = Object.entries(EXTENSION_AOT_PACKAGE_SUFFIXES) - .map(([target, suffix]) => ({ target, suffix: `-aot-${suffix}` })) - .sort((left, right) => right.suffix.length - left.suffix.length || compareText(left.suffix, right.suffix)); - -function fail(prefix, message) { - throw new Error(`${prefix}: ${message}`); -} - -function sortedUniqueStrings(value, context, prefix) { - if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item.length === 0)) { - fail(prefix, `${context} must be a list of non-empty strings`); - } - const sorted = [...new Set(value)].sort(compareText); - if (sorted.length !== value.length) { - fail(prefix, `${context} must not contain duplicates`); - } - return sorted; -} - -function parseRegistryIdentity(raw, product, prefix) { - if (typeof raw !== "string") { - fail(prefix, `${product}.registry_packages entries must be strings`); - } - const separator = raw.indexOf(":"); - if (separator <= 0 || separator === raw.length - 1) { - fail(prefix, `${product}.registry_packages entry ${JSON.stringify(raw)} must use kind:name`); - } - const kind = raw.slice(0, separator); - const ecosystem = REGISTRY_KIND_TO_ECOSYSTEM[kind]; - if (ecosystem === undefined) { - fail(prefix, `${product}.registry_packages entry ${JSON.stringify(raw)} uses unsupported kind ${kind}`); - } - const name = raw.slice(separator + 1); - if (ecosystem === "cargo" && name.length > 64) { - fail(prefix, `${product} Cargo carrier ${JSON.stringify(name)} is ${name.length} characters; crates.io allows at most 64`); - } - return { ecosystem, name }; -} - -function carrierTarget(product, ecosystem, name) { - if ( - product === WASIX_RUNTIME_PRODUCT - && ecosystem === "npm" - && (name === WASIX_RUNTIME_NPM_PACKAGE || name === WASIX_ICU_NPM_PACKAGE) - ) { - return WASIX_RUNTIME_NPM_TARGET; - } - if ( - ecosystem === "npm" - && product.startsWith("oliphaunt-extension-") - && name === extensionNpmWasixPackageForProduct(product) - ) { - return EXTENSION_PORTABLE_TARGET; - } - if ( - ecosystem === "cargo" - && name.startsWith("oliphaunt-extension-") - && name.endsWith("-wasix") - ) { - return EXTENSION_PORTABLE_TARGET; - } - const extensionAot = EXTENSION_AOT_TARGET_SUFFIXES.find(({ suffix }) => name.endsWith(suffix)); - if (extensionAot !== undefined) return extensionAot.target; - return TARGET_MARKERS.find((target) => name.includes(target)) ?? null; -} - -function carrierRole(product, ecosystem, name, target) { - if (/-part-[0-9]{3}$/u.test(name)) { - return "payload-part"; - } - if (ecosystem === "maven" && (name.includes("gradle-plugin") || name.endsWith(".gradle.plugin"))) { - return "plugin"; - } - if (name.includes("icu") || name.includes("resources")) { - return "resource"; - } - if (name.includes("tools") || name.includes("broker")) { - return target === null ? "tool-facade" : "tool-leaf"; - } - if (target === EXTENSION_PORTABLE_TARGET) { - return "portable-leaf"; - } - if (target !== null) { - return name.includes("aot-") ? "aot-leaf" : "platform-leaf"; - } - if (product.startsWith("oliphaunt-extension-")) { - return name.endsWith("-wasix") ? "portable-leaf" : "facade"; - } - return "facade"; -} - -function isSplittableCargoCarrier({ ecosystem, name, product, role }) { - return ecosystem === "cargo" && ( - SPLITTABLE_CARGO_ROLES.has(role) - || ( - product === "liboliphaunt-native" - && role === "tool-leaf" - && name.startsWith("oliphaunt-tools-") - ) - ); -} - -function productDependencies(product, config, graph) { - const dependencies = new Set(); - const compatibility = config.compatibility_versions ?? {}; - if (compatibility !== null && !Array.isArray(compatibility) && typeof compatibility === "object") { - for (const entry of Object.values(compatibility)) { - if ( - entry !== null - && !Array.isArray(entry) - && typeof entry === "object" - && typeof entry.source_product === "string" - && entry.source_product in graph.products - && entry.source_product !== product - ) { - dependencies.add(entry.source_product); - } - } - } - return [...dependencies].sort(compareText); -} - -function stableJson(value) { - if (Array.isArray(value)) { - return `[${value.map(stableJson).join(",")}]`; - } - if (value !== null && typeof value === "object") { - return `{${Object.keys(value).sort(compareText).map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`; - } - return JSON.stringify(value); -} - -export function publicationCatalogDigest(catalog) { - return createHash("sha256").update(stableJson(catalog)).digest("hex"); -} - -export function loadPublicationCatalog(prefix = "publication-catalog", { products = undefined } = {}) { - const graph = loadGraph(prefix); - const known = new Set(Object.keys(graph.products)); - const selected = products === undefined ? [...known] : sortedUniqueStrings(products, "products", prefix); - const unknown = selected.filter((product) => !known.has(product)); - if (unknown.length > 0) { - fail(prefix, `unknown release products: ${unknown.join(", ")}`); - } - const ordered = releaseOrder(graph.products, graph.moon_projects, new Set(selected), prefix); - const productRows = []; - const carriers = []; - const identities = new Map(); - for (const product of ordered) { - const config = graph.products[product]; - const publishTargets = sortedUniqueStrings(config.publish_targets ?? [], `${product}.publish_targets`, prefix); - const registryPackages = registryPackageRows({ product }, prefix).map((row) => row.raw); - productRows.push({ - id: product, - kind: config.kind, - path: config.path, - version: config.version, - publishTargets, - dependencies: productDependencies(product, config, graph), - }); - for (const raw of registryPackages) { - const { ecosystem, name } = parseRegistryIdentity(raw, product, prefix); - const id = `${ecosystem}:${name}`; - const previous = identities.get(id); - if (previous !== undefined) { - fail(prefix, `registry carrier ${id} is declared by both ${previous} and ${product}`); - } - identities.set(id, product); - const target = carrierTarget(product, ecosystem, name); - const role = carrierRole(product, ecosystem, name, target); - if (isSplittableCargoCarrier({ ecosystem, name, product, role }) && `${name}-part-001`.length > 64) { - fail(prefix, `${product} splittable Cargo carrier ${JSON.stringify(name)} leaves no room for the required -part-001 suffix`); - } - carriers.push({ - id, - product, - version: config.version, - ecosystem, - name, - role, - target, - declared: true, - }); - } - } - carriers.sort((left, right) => compareText(left.id, right.id)); - return { - schema: PUBLICATION_CATALOG_SCHEMA, - products: productRows, - carriers, - }; -} - -export function declaredCarrierMap(catalog) { - return new Map(catalog.carriers.map((carrier) => [carrier.id, carrier])); -} - -export function resolveActualCarrier(catalog, ecosystem, name, prefix = "publication-catalog") { - const id = `${ecosystem}:${name}`; - const declared = declaredCarrierMap(catalog).get(id); - if (declared !== undefined) { - return declared; - } - if (ecosystem !== "cargo") { - fail(prefix, `artifact identity ${id} is not declared; dynamic identities are permitted only for Cargo payload part crates`); - } - const match = name.match(/^(.*)-part-([0-9]{3})$/u); - if (match === null) { - fail(prefix, `artifact identity ${id} is not declared and is not a Cargo payload part crate`); - } - const parent = declaredCarrierMap(catalog).get(`cargo:${match[1]}`); - if (parent === undefined) { - fail(prefix, `Cargo payload part ${id} has no declared parent carrier cargo:${match[1]}`); - } - if (!isSplittableCargoCarrier(parent)) { - fail(prefix, `Cargo payload part ${id} has non-splittable parent role ${parent.role}`); - } - const part = Number.parseInt(match[2], 10); - if (part < 1 || part > 999) { - fail(prefix, `Cargo payload part ${id} must use a 1-based -part-001 through -part-999 suffix`); - } - if (name.length > 64) { - fail(prefix, `Cargo payload part ${id} exceeds crates.io's 64-character name limit`); - } - return { - ...parent, - id, - name, - role: "payload-part", - declared: false, - parentCarrier: parent.id, - part, - }; -} - -function main() { - const catalog = loadPublicationCatalog("publication-catalog.mjs"); - console.log(`${JSON.stringify({ ...catalog, digest: publicationCatalogDigest(catalog) }, null, 2)}\n`); -} - -if (import.meta.main) { - main(); -} diff --git a/tools/release/publication-catalog.mts b/tools/release/publication-catalog.mts new file mode 100644 index 000000000..f277b3f28 --- /dev/null +++ b/tools/release/publication-catalog.mts @@ -0,0 +1,319 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; + +import { compareText, loadProducts, releaseOrder } from './release-graph.mts'; +import { registryPackageRows } from './release-artifact-targets.mts'; +import { + EXTENSION_AOT_PACKAGE_SUFFIXES, + EXTENSION_PORTABLE_TARGET, +} from '../../src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts'; +import { extensionNpmWasixPackageForProduct } from '../../src/extensions/artifacts/packages/tools/extension-registry-packages.mts'; +import { + WASIX_RUNTIME_NPM_PACKAGE, + WASIX_RUNTIME_NPM_TARGET, + WASIX_RUNTIME_PRODUCT, +} from '../../src/runtimes/liboliphaunt-wasix/tools/wasix-runtime-npm-contract.mts'; + +export const PUBLICATION_CATALOG_SCHEMA = 'oliphaunt-publication-catalog-v1'; + +export const REGISTRY_KIND_TO_ECOSYSTEM = Object.freeze({ + crates: 'cargo', + npm: 'npm', + maven: 'maven', +}); + +const TARGET_MARKERS = [ + 'aarch64-unknown-linux-gnu', + 'x86_64-unknown-linux-gnu', + 'aarch64-apple-darwin', + 'x86_64-pc-windows-msvc', + 'android-arm64-v8a', + 'android-x86_64', + 'linux-arm64-gnu', + 'linux-x64-gnu', + 'macos-arm64', + 'windows-x64-msvc', + 'darwin-arm64', + 'win32-x64-msvc', + 'portable', +]; +const SPLITTABLE_CARGO_ROLES = new Set(['platform-leaf', 'aot-leaf', 'portable-leaf']); +const EXTENSION_AOT_TARGET_SUFFIXES = Object.entries(EXTENSION_AOT_PACKAGE_SUFFIXES) + .map(([target, suffix]) => ({ target, suffix: `-aot-${suffix}` })) + .sort( + (left, right) => + right.suffix.length - left.suffix.length || compareText(left.suffix, right.suffix), + ); + +function fail(prefix, message) { + throw new Error(`${prefix}: ${message}`); +} + +function sortedUniqueStrings(value, context, prefix) { + if ( + !Array.isArray(value) || + value.some((item) => typeof item !== 'string' || item.length === 0) + ) { + fail(prefix, `${context} must be a list of non-empty strings`); + } + const sorted = [...new Set(value)].sort(compareText); + if (sorted.length !== value.length) { + fail(prefix, `${context} must not contain duplicates`); + } + return sorted; +} + +function parseRegistryIdentity(raw, product, prefix) { + if (typeof raw !== 'string') { + fail(prefix, `${product}.registry_packages entries must be strings`); + } + const separator = raw.indexOf(':'); + if (separator <= 0 || separator === raw.length - 1) { + fail(prefix, `${product}.registry_packages entry ${JSON.stringify(raw)} must use kind:name`); + } + const kind = raw.slice(0, separator); + const ecosystem = REGISTRY_KIND_TO_ECOSYSTEM[kind]; + if (ecosystem === undefined) { + fail( + prefix, + `${product}.registry_packages entry ${JSON.stringify(raw)} uses unsupported kind ${kind}`, + ); + } + const name = raw.slice(separator + 1); + if (ecosystem === 'cargo' && name.length > 64) { + fail( + prefix, + `${product} Cargo carrier ${JSON.stringify(name)} is ${name.length} characters; crates.io allows at most 64`, + ); + } + return { ecosystem, name }; +} + +function carrierTarget(product, ecosystem, name) { + if ( + product === WASIX_RUNTIME_PRODUCT && + ecosystem === 'npm' && + name === WASIX_RUNTIME_NPM_PACKAGE + ) { + return WASIX_RUNTIME_NPM_TARGET; + } + if ( + ecosystem === 'npm' && + product.startsWith('oliphaunt-extension-') && + name === extensionNpmWasixPackageForProduct(product) + ) { + return EXTENSION_PORTABLE_TARGET; + } + if (ecosystem === 'cargo' && name.startsWith('oliphaunt-extension-') && name.endsWith('-wasix')) { + return EXTENSION_PORTABLE_TARGET; + } + const extensionAot = EXTENSION_AOT_TARGET_SUFFIXES.find(({ suffix }) => name.endsWith(suffix)); + if (extensionAot !== undefined) return extensionAot.target; + return TARGET_MARKERS.find((target) => name.includes(target)) ?? null; +} + +function carrierRole(product, ecosystem, name, target) { + if (/-part-[0-9]{3}$/u.test(name)) { + return 'payload-part'; + } + if ( + ecosystem === 'maven' && + (name.includes('gradle-plugin') || name.endsWith('.gradle.plugin')) + ) { + return 'plugin'; + } + if (product === 'database-resources' || name.includes('icu') || name.includes('resources')) { + return 'resource'; + } + if (name.includes('tools') || name.includes('broker')) { + return target === null ? 'tool-facade' : 'tool-leaf'; + } + if (target === EXTENSION_PORTABLE_TARGET) { + return 'portable-leaf'; + } + if (target !== null) { + return name.includes('aot-') ? 'aot-leaf' : 'platform-leaf'; + } + if (product.startsWith('oliphaunt-extension-')) { + return name.endsWith('-wasix') ? 'portable-leaf' : 'facade'; + } + return 'facade'; +} + +function isSplittableCargoCarrier({ ecosystem, name, product, role }) { + return ( + ecosystem === 'cargo' && + (SPLITTABLE_CARGO_ROLES.has(role) || + (product === 'postgres-tools-native' && + role === 'tool-leaf' && + name.startsWith('oliphaunt-tools-'))) + ); +} + +function productDependencies(product, config, graph) { + const dependencies = new Set(); + const compatibility = config.compatibility_versions ?? {}; + if ( + compatibility !== null && + !Array.isArray(compatibility) && + typeof compatibility === 'object' + ) { + for (const entry of Object.values(compatibility)) { + if ( + entry !== null && + !Array.isArray(entry) && + typeof entry === 'object' && + typeof entry.source_product === 'string' && + entry.source_product in graph.products && + entry.source_product !== product + ) { + dependencies.add(entry.source_product); + } + } + } + return [...dependencies].sort(compareText); +} + +function stableJson(value) { + if (Array.isArray(value)) { + return `[${value.map(stableJson).join(',')}]`; + } + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort(compareText) + .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +export function publicationCatalogDigest(catalog) { + return createHash('sha256').update(stableJson(catalog)).digest('hex'); +} + +export function loadPublicationCatalog( + prefix = 'publication-catalog', + { products = undefined } = {}, +) { + const graph = { products: loadProducts(prefix) }; + const known = new Set(Object.keys(graph.products)); + const selected = + products === undefined ? [...known] : sortedUniqueStrings(products, 'products', prefix); + const unknown = selected.filter((product) => !known.has(product)); + if (unknown.length > 0) { + fail(prefix, `unknown release products: ${unknown.join(', ')}`); + } + const ordered = releaseOrder(graph.products, undefined, new Set(selected), prefix); + const productRows = []; + const carriers = []; + const identities = new Map(); + for (const product of ordered) { + const config = graph.products[product]; + const publishTargets = sortedUniqueStrings( + config.publish_targets ?? [], + `${product}.publish_targets`, + prefix, + ); + const registryPackages = registryPackageRows({ product }, prefix).map((row) => row.raw); + productRows.push({ + id: product, + kind: config.kind, + path: config.path, + version: config.version, + publishTargets, + dependencies: productDependencies(product, config, graph), + }); + for (const raw of registryPackages) { + const { ecosystem, name } = parseRegistryIdentity(raw, product, prefix); + const id = `${ecosystem}:${name}`; + const previous = identities.get(id); + if (previous !== undefined) { + fail(prefix, `registry carrier ${id} is declared by both ${previous} and ${product}`); + } + identities.set(id, product); + const target = carrierTarget(product, ecosystem, name); + const role = carrierRole(product, ecosystem, name, target); + if ( + isSplittableCargoCarrier({ ecosystem, name, product, role }) && + `${name}-part-001`.length > 64 + ) { + fail( + prefix, + `${product} splittable Cargo carrier ${JSON.stringify(name)} leaves no room for the required -part-001 suffix`, + ); + } + carriers.push({ + id, + product, + version: config.version, + ecosystem, + name, + role, + target, + declared: true, + }); + } + } + carriers.sort((left, right) => compareText(left.id, right.id)); + return { + schema: PUBLICATION_CATALOG_SCHEMA, + products: productRows, + carriers, + }; +} + +export function declaredCarrierMap(catalog) { + return new Map(catalog.carriers.map((carrier) => [carrier.id, carrier])); +} + +export function resolveActualCarrier(catalog, ecosystem, name, prefix = 'publication-catalog') { + const id = `${ecosystem}:${name}`; + const declared = declaredCarrierMap(catalog).get(id); + if (declared !== undefined) { + return declared; + } + if (ecosystem !== 'cargo') { + fail( + prefix, + `artifact identity ${id} is not declared; dynamic identities are permitted only for Cargo payload part crates`, + ); + } + const match = name.match(/^(.*)-part-([0-9]{3})$/u); + if (match === null) { + fail(prefix, `artifact identity ${id} is not declared and is not a Cargo payload part crate`); + } + const parent = declaredCarrierMap(catalog).get(`cargo:${match[1]}`); + if (parent === undefined) { + fail(prefix, `Cargo payload part ${id} has no declared parent carrier cargo:${match[1]}`); + } + if (!isSplittableCargoCarrier(parent)) { + fail(prefix, `Cargo payload part ${id} has non-splittable parent role ${parent.role}`); + } + const part = Number.parseInt(match[2], 10); + if (part < 1 || part > 999) { + fail(prefix, `Cargo payload part ${id} must use a 1-based -part-001 through -part-999 suffix`); + } + if (name.length > 64) { + fail(prefix, `Cargo payload part ${id} exceeds crates.io's 64-character name limit`); + } + return { + ...parent, + id, + name, + role: 'payload-part', + declared: false, + parentCarrier: parent.id, + part, + }; +} + +function main() { + const catalog = loadPublicationCatalog('publication-catalog.mts'); + console.log( + `${JSON.stringify({ ...catalog, digest: publicationCatalogDigest(catalog) }, null, 2)}\n`, + ); +} + +if (import.meta.main) { + main(); +} diff --git a/tools/release/publication-catalog.schema.json b/tools/release/publication-catalog.schema.json index 58ddf0cf4..9fad5a2a5 100644 --- a/tools/release/publication-catalog.schema.json +++ b/tools/release/publication-catalog.schema.json @@ -2,7 +2,7 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://oliphaunt.dev/schemas/publication-catalog-v1.json", "title": "Oliphaunt publication catalog", - "description": "Canonical Product and Carrier model. Product metadata remains colocated in each release.toml and is normalized exclusively by publication-catalog.mjs.", + "description": "Canonical Product and Carrier model. Product metadata remains colocated in each release.toml and is normalized exclusively by publication-catalog.mts.", "type": "object", "required": ["schema", "products", "carriers"], "additionalProperties": false, @@ -19,8 +19,16 @@ "kind": { "type": "string", "minLength": 1 }, "path": { "type": "string", "minLength": 1 }, "version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(?:[-+].+)?$" }, - "publishTargets": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true }, - "dependencies": { "type": "array", "items": { "type": "string", "minLength": 1 }, "uniqueItems": true } + "publishTargets": { + "type": "array", + "items": { "type": "string", "minLength": 1 }, + "uniqueItems": true + }, + "dependencies": { + "type": "array", + "items": { "type": "string", "minLength": 1 }, + "uniqueItems": true + } } } }, diff --git a/tools/release/publication-catalog.test.mjs b/tools/release/publication-catalog.test.mjs deleted file mode 100644 index a038bfa8c..000000000 --- a/tools/release/publication-catalog.test.mjs +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env bun -import { describe, expect, test } from "bun:test"; - -import { loadPublicationCatalog, resolveActualCarrier } from "./publication-catalog.mjs"; -import { - exactExtensionProducts, - extensionReleaseProduct, - extensionWasixAotMemberSqlNames, -} from "./release-artifact-targets.mjs"; -import { - EXTENSION_AOT_PACKAGE_SUFFIXES, - EXTENSION_PORTABLE_TARGET, - wasixExtensionAotPackageName, - wasixExtensionPackageName, -} from "./wasix-cargo-artifact-contract.mjs"; - -function catalogForArtifactProducts(products) { - return loadPublicationCatalog("publication-catalog.test", { - products: [...new Set(products.map((product) => - extensionReleaseProduct(product, "wasix", "publication-catalog.test")))], - }); -} - -test("the live publication catalog includes PostGIS and the WASIX Node-API carriers", () => { - const catalog = loadPublicationCatalog("publication-catalog.test"); - expect(catalog.products).toHaveLength(20); - expect(catalog.carriers).toHaveLength(203); - expect(catalog.products.some(({ id }) => id === "oliphaunt-extension-postgis")).toBe(true); - expect(catalog.carriers.filter(({ product }) => product === "oliphaunt-extension-postgis")).toHaveLength(18); - expect(catalog.products.some(({ id }) => id === "oliphaunt-wasix-napi")).toBe(true); - expect(catalog.carriers.filter(({ product }) => product === "oliphaunt-wasix-napi")).toHaveLength(4); - - const extensionProducts = exactExtensionProducts("publication-catalog.test"); - expect(extensionProducts).toHaveLength(8); - expect(extensionProducts).toContain("oliphaunt-extension-postgis"); -}); - -test("native tool target leaves admit exact payload parts while facades remain non-splittable", () => { - const catalog = loadPublicationCatalog("publication-catalog.test"); - const toolLeaves = catalog.carriers - .filter(({ ecosystem, name, role }) => - ecosystem === "cargo" && name.startsWith("oliphaunt-tools-") && role === "tool-leaf") - .sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0); - expect(toolLeaves.map(({ name }) => name)).toEqual([ - "oliphaunt-tools-linux-arm64-gnu", - "oliphaunt-tools-linux-x64-gnu", - "oliphaunt-tools-macos-arm64", - "oliphaunt-tools-windows-x64-msvc", - ]); - for (const parent of toolLeaves) { - expect(resolveActualCarrier( - catalog, - "cargo", - `${parent.name}-part-001`, - "publication-catalog.test", - )).toMatchObject({ - declared: false, - parentCarrier: parent.id, - part: 1, - role: "payload-part", - target: parent.target, - }); - } - expect(() => resolveActualCarrier( - catalog, - "cargo", - "oliphaunt-tools-part-001", - "publication-catalog.test", - )).toThrow(/non-splittable parent role tool-facade/u); - - const otherToolLeaves = catalog.carriers - .filter(({ ecosystem, product, role }) => - ecosystem === "cargo" && product !== "liboliphaunt-native" && role === "tool-leaf") - .map(({ name }) => name) - .sort((left, right) => left < right ? -1 : left > right ? 1 : 0); - expect(otherToolLeaves).toEqual([ - "oliphaunt-broker-linux-arm64-gnu", - "oliphaunt-broker-linux-x64-gnu", - "oliphaunt-broker-macos-arm64", - "oliphaunt-broker-windows-x64-msvc", - "oliphaunt-wasix-tools-aot-aarch64-apple-darwin", - "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu", - "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc", - "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", - ]); - for (const name of otherToolLeaves) { - expect(() => resolveActualCarrier( - catalog, - "cargo", - `${name}-part-001`, - "publication-catalog.test", - )).toThrow(/non-splittable parent role tool-leaf/u); - } -}); - -describe("WASIX extension portable publication carriers", () => { - test("assigns every independently versioned portable carrier an explicit canonical target", () => { - const products = exactExtensionProducts("publication-catalog.test"); - const catalog = catalogForArtifactProducts(products); - for (const product of products) { - const owner = extensionReleaseProduct(product, "wasix", "publication-catalog.test"); - const name = wasixExtensionPackageName(product); - const carrier = catalog.carriers.find((candidate) => candidate.name === name); - expect(carrier).toMatchObject({ - ecosystem: "cargo", - product: owner, - role: "portable-leaf", - target: EXTENSION_PORTABLE_TARGET, - }); - const part = resolveActualCarrier( - catalog, - "cargo", - `${name}-part-001`, - "publication-catalog.test", - ); - expect(part).toMatchObject({ - role: "payload-part", - parentCarrier: `cargo:${name}`, - part: 1, - target: EXTENSION_PORTABLE_TARGET, - }); - } - }); -}); - -describe("WASIX extension AOT publication carriers", () => { - test("declares the exact host set only for products with native-module members", () => { - const products = exactExtensionProducts("publication-catalog.test"); - const catalog = catalogForArtifactProducts(products); - const expectedTargets = Object.keys(EXTENSION_AOT_PACKAGE_SUFFIXES).sort(); - for (const product of products) { - const aotMembers = extensionWasixAotMemberSqlNames(product, "publication-catalog.test"); - const actualTargets = catalog.carriers - .filter((carrier) => - carrier.ecosystem === "cargo" - && carrier.role === "aot-leaf" - && carrier.name.startsWith(`${product}-aot-`)) - .map((carrier) => carrier.target) - .sort(); - expect(actualTargets, `${product} AOT members: ${aotMembers.join(", ") || "none"}`).toEqual( - aotMembers.length === 0 ? [] : expectedTargets, - ); - } - }); - - test("classifies every compact AOT suffix as a splittable canonical target leaf", () => { - const product = "oliphaunt-extension-pg-textsearch"; - const catalog = loadPublicationCatalog("publication-catalog.test", { products: [product] }); - for (const target of Object.keys(EXTENSION_AOT_PACKAGE_SUFFIXES).sort()) { - const name = wasixExtensionAotPackageName(product, target); - const carrier = catalog.carriers.find((candidate) => candidate.name === name); - expect(carrier).toMatchObject({ ecosystem: "cargo", role: "aot-leaf", target }); - const part = resolveActualCarrier(catalog, "cargo", `${name}-part-001`, "publication-catalog.test"); - expect(part).toMatchObject({ role: "payload-part", parentCarrier: `cargo:${name}`, part: 1, target }); - expect(part.name.length).toBeLessThanOrEqual(64); - } - }); -}); diff --git a/tools/release/publication-catalog.test.mts b/tools/release/publication-catalog.test.mts new file mode 100644 index 000000000..378762692 --- /dev/null +++ b/tools/release/publication-catalog.test.mts @@ -0,0 +1,154 @@ +#!/usr/bin/env bun +import { describe, expect, test } from 'bun:test'; + +import { loadProducts } from './release-graph.mts'; +import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; +import { + exactExtensionProducts, + extensionReleaseProduct, + extensionWasixAotMemberSqlNames, +} from './release-artifact-targets.mts'; +import { + EXTENSION_AOT_PACKAGE_SUFFIXES, + EXTENSION_PORTABLE_TARGET, + wasixExtensionAotPackageName, + wasixExtensionPackageName, +} from '../../src/runtimes/liboliphaunt-wasix/tools/wasix-cargo-artifact-contract.mts'; + +function catalogForArtifactProducts(products) { + return loadPublicationCatalog('publication-catalog.test', { + products: [ + ...new Set( + products.map((product) => + extensionReleaseProduct(product, 'wasix', 'publication-catalog.test'), + ), + ), + ], + }); +} + +test('normalizes every declared product into uniquely owned versioned carriers', () => { + const products = loadProducts('publication-catalog.test'); + const catalog = loadPublicationCatalog('publication-catalog.test'); + expect(catalog.products.map(({ id }) => id).sort()).toEqual(Object.keys(products).sort()); + expect(new Set(catalog.carriers.map(({ id }) => id)).size).toBe(catalog.carriers.length); + for (const carrier of catalog.carriers) { + expect(carrier.declared).toBe(true); + expect(carrier.version).toBe(products[carrier.product].version); + } +}); + +test('native tool target leaves admit exact payload parts while facades remain non-splittable', () => { + const catalog = loadPublicationCatalog('publication-catalog.test'); + const toolLeaves = catalog.carriers + .filter( + ({ ecosystem, name, role }) => + ecosystem === 'cargo' && name.startsWith('oliphaunt-tools-') && role === 'tool-leaf', + ) + .sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0)); + expect(toolLeaves.length).toBeGreaterThan(0); + for (const parent of toolLeaves) { + expect( + resolveActualCarrier(catalog, 'cargo', `${parent.name}-part-001`, 'publication-catalog.test'), + ).toMatchObject({ + declared: false, + parentCarrier: parent.id, + part: 1, + role: 'payload-part', + target: parent.target, + }); + } + expect(() => + resolveActualCarrier(catalog, 'cargo', 'oliphaunt-tools-part-001', 'publication-catalog.test'), + ).toThrow(/non-splittable parent role tool-facade/u); + + const otherToolLeaves = catalog.carriers + .filter( + ({ ecosystem, product, role }) => + ecosystem === 'cargo' && product !== 'postgres-tools-native' && role === 'tool-leaf', + ) + .map(({ name }) => name) + .sort((left, right) => (left < right ? -1 : left > right ? 1 : 0)); + expect(otherToolLeaves.length).toBeGreaterThan(0); + for (const name of otherToolLeaves) { + expect(() => + resolveActualCarrier(catalog, 'cargo', `${name}-part-001`, 'publication-catalog.test'), + ).toThrow(/non-splittable parent role tool-leaf/u); + } +}); + +describe('WASIX extension portable publication carriers', () => { + test('assigns every independently versioned portable carrier an explicit canonical target', () => { + const products = exactExtensionProducts('publication-catalog.test'); + const catalog = catalogForArtifactProducts(products); + for (const product of products) { + const owner = extensionReleaseProduct(product, 'wasix', 'publication-catalog.test'); + const name = wasixExtensionPackageName(product); + const carrier = catalog.carriers.find((candidate) => candidate.name === name); + expect(carrier).toMatchObject({ + ecosystem: 'cargo', + product: owner, + role: 'portable-leaf', + target: EXTENSION_PORTABLE_TARGET, + }); + const part = resolveActualCarrier( + catalog, + 'cargo', + `${name}-part-001`, + 'publication-catalog.test', + ); + expect(part).toMatchObject({ + role: 'payload-part', + parentCarrier: `cargo:${name}`, + part: 1, + target: EXTENSION_PORTABLE_TARGET, + }); + } + }); +}); + +describe('WASIX extension AOT publication carriers', () => { + test('declares the exact host set only for products with native-module members', () => { + const products = exactExtensionProducts('publication-catalog.test'); + const catalog = catalogForArtifactProducts(products); + const expectedTargets = Object.keys(EXTENSION_AOT_PACKAGE_SUFFIXES).sort(); + for (const product of products) { + const aotMembers = extensionWasixAotMemberSqlNames(product, 'publication-catalog.test'); + const actualTargets = catalog.carriers + .filter( + (carrier) => + carrier.ecosystem === 'cargo' && + carrier.role === 'aot-leaf' && + carrier.name.startsWith(`${product}-aot-`), + ) + .map((carrier) => carrier.target) + .sort(); + expect(actualTargets, `${product} AOT members: ${aotMembers.join(', ') || 'none'}`).toEqual( + aotMembers.length === 0 ? [] : expectedTargets, + ); + } + }); + + test('classifies every compact AOT suffix as a splittable canonical target leaf', () => { + const product = 'oliphaunt-extension-pg-textsearch'; + const catalog = loadPublicationCatalog('publication-catalog.test', { products: [product] }); + for (const target of Object.keys(EXTENSION_AOT_PACKAGE_SUFFIXES).sort()) { + const name = wasixExtensionAotPackageName(product, target); + const carrier = catalog.carriers.find((candidate) => candidate.name === name); + expect(carrier).toMatchObject({ ecosystem: 'cargo', role: 'aot-leaf', target }); + const part = resolveActualCarrier( + catalog, + 'cargo', + `${name}-part-001`, + 'publication-catalog.test', + ); + expect(part).toMatchObject({ + role: 'payload-part', + parentCarrier: `cargo:${name}`, + part: 1, + target, + }); + expect(part.name.length).toBeLessThanOrEqual(64); + } + }); +}); diff --git a/tools/release/publication-controller.mjs b/tools/release/publication-controller.mjs deleted file mode 100644 index f4eb9ba4a..000000000 --- a/tools/release/publication-controller.mjs +++ /dev/null @@ -1,64 +0,0 @@ -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { assertQualifiedReplaySourceState } from "./qualified-release-replay.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -// Only publication execution may differ. In particular, tools/release also -// contains packagers: allowing that directory wholesale would change bytes. -const CONTROL_FILES = new Set([ - ".github/workflows/release.yml", - ".github/scripts/resolve-release-head.sh", - ".github/scripts/validate-release-workflow-inputs.sh", - ".github/scripts/release-transport-ref.mjs", - ".github/scripts/download-bootstrap-ledger.mjs", - ".github/scripts/download-bootstrap-ledger.test.mjs", - ".github/scripts/download-completed-bootstrap.mjs", - ".github/scripts/normalize-release-please-pr.mjs", - "tools/release/publication-controller.mjs", - "tools/release/release-bot.json", - "tools/release/publish_swiftpm_source_tag.mjs", - "tools/release/audit-github-release-controls.mjs", - "tools/release/fixtures/github-release-controls/desired-solo.json", - "tools/release/fixtures/github-release-controls/desired-team.json", - "tools/release/crates-io-bootstrap-capacity.mjs", - "tools/release/frozen-cargo-publish.mjs", - "tools/release/verify_github_release_attestations.mjs", -]); - -export function assertPublicationController({ source, controller, root = ROOT }) { - assertQualifiedReplaySourceState({ repo: root, headRef: controller, expectedSha: controller }); - return assertPublicationChanges({ source, controller, root }); -} - -export function assertPublicationChanges({ source, controller, root = ROOT }) { - for (const sha of [source, controller]) { - if (!/^[0-9a-f]{40}$/u.test(sha ?? "")) throw new Error("publication source and controller must be full commit SHAs"); - } - const git = (...args) => { - const result = captureCommandOutput("git", args, { - cwd: root, label: "publication controller source comparison", allowEmptyOutput: true, - stdoutTerminator: args.includes("-z") ? "\0" : "\n", - }); - if (result.error || result.status !== 0) throw new Error(result.stderr || "publication source must be an ancestor of the controller"); - return result.stdout; - }; - git("merge-base", "--is-ancestor", source, controller); - const changed = git("diff", "--no-renames", "--name-only", "-z", source, controller).split("\0").filter(Boolean); - const rejected = changed.filter((file) => !CONTROL_FILES.has(file) - && !/^tools\/(?:release|policy)\/[^/]+[.]test[.]mjs$/u.test(file) - && !/^docs\/maintainers\/release(?:-setup)?[.]md$/u.test(file)); - if (rejected.length) throw new Error(`approved candidate cannot be reused after non-publication changes:\n${rejected.join("\n")}`); - return { source, controller }; -} - -if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { - try { - const [source, controller] = process.argv.slice(2); - assertPublicationController({ source, controller }); - console.log(`verified publication controller ${controller} for frozen source ${source}`); - } catch (error) { - console.error(error.message); - process.exitCode = 1; - } -} diff --git a/tools/release/publication-controller.mts b/tools/release/publication-controller.mts new file mode 100644 index 000000000..b16d55551 --- /dev/null +++ b/tools/release/publication-controller.mts @@ -0,0 +1,84 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +// Only publication execution may differ. In particular, tools/release also +// contains packagers: allowing that directory wholesale would change bytes. +const CONTROL_FILES = new Set([ + '.github/workflows/release.yml', + '.github/scripts/resolve-release-head.sh', + '.github/scripts/validate-release-workflow-inputs.sh', + '.github/scripts/release-transport-ref.mts', + '.github/scripts/download-bootstrap-ledger.mts', + '.github/scripts/download-completed-bootstrap.mts', + '.github/scripts/download-completed-bootstrap.sh', + 'tools/release/publication-controller.mts', + 'tools/release/publication-controller.sh', + 'tools/release/release-bot.json', + 'tools/release/publish_swiftpm_source_tag.mts', + 'tools/release/publish-swiftpm-source-tag.sh', + 'tools/release/audit-github-release-controls.mts', + 'tools/release/fixtures/github-release-controls/desired-solo.json', + 'tools/release/fixtures/github-release-controls/desired-team.json', + 'tools/release/crates-io-bootstrap-capacity.mts', + 'tools/release/frozen-cargo-publish.mts', + 'tools/release/verify_github_release_attestations.mts', + 'tools/release/verify-github-release-attestations.sh', +]); + +export function assertPublicationController({ source, controller, environment = process.env }) { + return assertPublicationChanges({ source, controller, environment, checkout: true }); +} + +export function assertPublicationChanges({ + source, + controller, + environment = process.env, + checkout = false, +}) { + const proof = JSON.parse(environment.OLIPHAUNT_PUBLICATION_CONTROLLER_JSON || 'null'); + if ( + !proof || + proof.source !== source || + proof.controller !== controller || + !['checkout', 'changes'].includes(proof.mode) || + (checkout && proof.mode !== 'checkout') + ) + throw new Error( + 'publication controller requires matching proof from publication-controller.sh', + ); + return { source, controller }; +} + +function validateChanges(source, controller, mode, diff) { + for (const sha of [source, controller]) { + if (!/^[0-9a-f]{40}$/u.test(sha ?? '')) + throw new Error('publication source and controller must be full commit SHAs'); + } + if (!['checkout', 'changes'].includes(mode) || (diff && !diff.endsWith('\0'))) + throw new Error('invalid publication controller diff'); + const changed = diff.split('\0').filter(Boolean); + const rejected = changed.filter( + (file) => + !CONTROL_FILES.has(file) && + !/^tools\/release\/[^/]+[.]test[.](?:mts|sh)$/u.test(file) && + !/^docs\/maintainers\/release(?:-setup)?[.]md$/u.test(file), + ); + if (rejected.length) + throw new Error( + `approved candidate cannot be reused after non-publication changes:\n${rejected.join('\n')}`, + ); + return { source, controller, mode }; +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + try { + const [source, controller, mode, file] = process.argv.slice(2); + console.log( + JSON.stringify(validateChanges(source, controller, mode, readFileSync(file, 'utf8'))), + ); + } catch (error) { + console.error(error.message); + process.exitCode = 1; + } +} diff --git a/tools/release/publication-controller.sh b/tools/release/publication-controller.sh new file mode 100644 index 000000000..7aca9e607 --- /dev/null +++ b/tools/release/publication-controller.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +owner="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +mode=checkout +if [[ "${1:-}" == --changes-only ]]; then mode=changes; shift; fi +[[ "$#" -ge 2 ]] || { echo 'usage: publication-controller.sh [--changes-only] SOURCE_SHA CONTROLLER_SHA [COMMAND ...]' >&2; exit 2; } +source_sha="$1"; controller_sha="$2"; shift 2 +[[ "$source_sha" =~ ^[0-9a-f]{40}$ && "$controller_sha" =~ ^[0-9a-f]{40}$ ]] || { echo 'publication source and controller must be full commit SHAs' >&2; exit 2; } +if [[ "$mode" == checkout ]]; then bash "$owner/qualified-release-replay.sh" "$controller_sha" "$controller_sha"; fi +git merge-base --is-ancestor "$source_sha" "$controller_sha" || { echo 'publication source must be an ancestor of the controller' >&2; exit 2; } +scratch="$(mktemp)" +trap 'rm -f "$scratch"' EXIT +git diff --no-renames --name-only -z "$source_sha" "$controller_sha" > "$scratch" +OLIPHAUNT_PUBLICATION_CONTROLLER_JSON="$(node "$owner/publication-controller.mts" "$source_sha" "$controller_sha" "$mode" "$scratch")" +export OLIPHAUNT_PUBLICATION_CONTROLLER_JSON +rm -f "$scratch" +trap - EXIT +if [[ "$#" -gt 0 ]]; then exec "$@"; fi +echo "verified publication controller $controller_sha for frozen source $source_sha" diff --git a/tools/release/publication-controller.test.mjs b/tools/release/publication-controller.test.mjs deleted file mode 100644 index d49a92c08..000000000 --- a/tools/release/publication-controller.test.mjs +++ /dev/null @@ -1,40 +0,0 @@ -import assert from "node:assert/strict"; -import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { assertPublicationChanges, assertPublicationController } from "./publication-controller.mjs"; - -test("only clean publication-only descendants can execute an older frozen candidate", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "publication-controller-")); - const git = (...args) => execFileSync("git", args, { cwd: root, encoding: "utf8" }).trim(); - const write = (file, value) => { - mkdirSync(path.dirname(path.join(root, file)), { recursive: true }); - writeFileSync(path.join(root, file), value); - }; - const commit = () => { git("add", "."); git("commit", "-qm", "fixture"); return git("rev-parse", "HEAD"); }; - try { - git("init", "-q"); git("config", "user.name", "Fixture"); git("config", "user.email", "fixture@example.invalid"); - write("product", "original"); - const source = commit(); - assertPublicationController({ source, controller: source, root }); - write("tools/release/crates-io-bootstrap-capacity.mjs", "fixed publisher"); - const controller = commit(); - assert.deepEqual(assertPublicationController({ source, controller, root }), { source, controller }); - write(".github/scripts/download-completed-bootstrap.mjs", "newer publisher"); - const newer = commit(); - assertPublicationController({ source, controller: newer, root }); - assert.deepEqual(assertPublicationChanges({ source, controller, root }), { source, controller }); - assert.throws(() => assertPublicationController({ source, controller, root }), /checkout|HEAD/u); - for (const file of ["product", "tools/release/package-extension-release-carriers.mjs", "Cargo.lock", ".github/workflows/ci.yml", "tools/release/moon.yml"]) { - git("checkout", "--detach", controller); - write(file, "changed"); - assert.throws(() => assertPublicationController({ source, controller, root }), /clean source checkout/u); - const changed = commit(); - assert.throws(() => assertPublicationController({ source, controller: changed, root }), /non-publication changes/u); - } - git("checkout", "--detach", source); - assert.throws(() => assertPublicationController({ source: controller, controller: source, root }), /ancestor/u); - } finally { rmSync(root, { recursive: true, force: true }); } -}); diff --git a/tools/release/publication-controller.test.mts b/tools/release/publication-controller.test.mts new file mode 100644 index 000000000..551a68918 --- /dev/null +++ b/tools/release/publication-controller.test.mts @@ -0,0 +1,27 @@ +import assert from 'node:assert/strict'; +import { assertPublicationController } from './publication-controller.mts'; + +const [mode, source, controller] = process.argv.slice(2); +if (mode === 'inherited') { + assert.deepEqual(assertPublicationController({ source, controller }), { source, controller }); +} else if (mode === 'proof') { + const proof = { source, controller, mode: 'checkout' }; + assert.deepEqual( + assertPublicationController({ + source, + controller, + environment: { OLIPHAUNT_PUBLICATION_CONTROLLER_JSON: JSON.stringify(proof) }, + }), + { source, controller }, + ); + for (const changed of [null, { ...proof, source: controller }, { ...proof, mode: 'changes' }]) + assert.throws( + () => + assertPublicationController({ + source, + controller, + environment: { OLIPHAUNT_PUBLICATION_CONTROLLER_JSON: JSON.stringify(changed) }, + }), + /matching proof/u, + ); +} else throw Error('expected inherited or proof'); diff --git a/tools/release/publication-controller.test.sh b/tools/release/publication-controller.test.sh new file mode 100644 index 000000000..78fb0bea5 --- /dev/null +++ b/tools/release/publication-controller.test.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail +owner="$(git rev-parse --show-toplevel)/tools/release" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +mkdir "$scratch/repo" +cd "$scratch/repo" +git init -q +git config user.name Fixture +git config user.email fixture@example.invalid +commit() { git add .; git commit -qm fixture; git rev-parse HEAD; } +reject() { + local message="$1"; shift + if bash "$owner/publication-controller.sh" "$@" > "$scratch/result" 2>&1; then echo 'Invalid controller accepted' >&2; exit 1; fi + rg -q "$message" "$scratch/result" +} +printf original > product +source="$(commit)" +bash "$owner/publication-controller.sh" "$source" "$source" +mkdir -p tools/release +printf 'fixed publisher' > tools/release/crates-io-bootstrap-capacity.mts +controller="$(commit)" +bun "$owner/publication-controller.test.mts" proof "$source" "$controller" +bash "$owner/publication-controller.sh" "$source" "$controller" \ + bun "$owner/publication-controller.test.mts" inherited "$source" "$controller" +mkdir -p .github/scripts +printf 'newer publisher' > .github/scripts/download-completed-bootstrap.mts +newer="$(commit)" +bash "$owner/publication-controller.sh" "$source" "$newer" +bash "$owner/publication-controller.sh" --changes-only "$source" "$controller" +reject 'checkout|HEAD' "$source" "$controller" +for file in product src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts Cargo.lock .github/workflows/ci.yml tools/release/moon.yml; do + git checkout --quiet --detach "$controller" + mkdir -p "$(dirname "$file")" + printf changed > "$file" + reject 'clean source checkout' "$source" "$controller" + changed="$(commit)" + reject 'non-publication changes' "$source" "$changed" +done +git checkout --quiet --detach "$source" +reject ancestor "$controller" "$source" +echo 'Publication controller: clean descendant, explicit proof and publication-only changes passed' diff --git a/tools/release/publication-lock.mjs b/tools/release/publication-lock.mjs deleted file mode 100644 index 5e4fcec75..000000000 --- a/tools/release/publication-lock.mjs +++ /dev/null @@ -1,2546 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import { - existsSync, - lstatSync, - mkdirSync, - readFileSync, - readdirSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { - PUBLICATION_CATALOG_SCHEMA, - loadPublicationCatalog, - publicationCatalogDigest, - resolveActualCarrier, -} from "./publication-catalog.mjs"; -import { - allArtifactTargets, - contribCarrierDescriptor, - currentProductVersionSync, - extensionArtifactTargets, - extensionMetadata, - extensionSourceIdentity, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { ROOT, compareText, productCompatibilityVersion } from "./release-graph.mjs"; -import { extensionRuntimeAssetContract } from "./extension-runtime-asset-contract.mjs"; -import { validateNpmTrustedPublishingManifest } from "./npm-trusted-publishing.mjs"; -import { - buildSwiftExtensionCarrierManifest, - swiftExtensionCarrierAssetName, -} from "./ios-carrier-manifest.mjs"; -import { - validateSelectionNeutralSwiftSourceCarrier, - validateSwiftSourceReleaseContract, -} from "./swift-source-carrier-contract.mjs"; -import { validateMavenCentralPublication } from "./maven-central-contract.mjs"; -import { - extensionCarrierLegalContract, - extensionCarrierLegalFileInventory, -} from "./extension-upstream-licenses.mjs"; -import { readCanonicalTarGzipEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { assertWasixExtensionMemberInstall } from "../../src/shared/extension-runtime-contract/wasix-extension-install.mjs"; - -export { validateSelectionNeutralSwiftSourceCarrier }; - -export const PUBLICATION_CANDIDATE_SCHEMA = "oliphaunt-publication-candidate-v1"; -export const PUBLICATION_LOCK_SCHEMA = "oliphaunt-publication-lock-v1"; -export const DEFAULT_PUBLICATION_LOCK = path.join(ROOT, "target/release/publication-lock.json"); - -const IGNORED_DIRECTORIES = new Set([".git", "node_modules", "target"]); -const EXTENSION_PRODUCT_KINDS = new Set(["exact-extension-artifact", "exact-extension-bundle"]); -const ECOSYSTEM_ORDER = new Map([["cargo", 0], ["maven", 1], ["npm", 2]]); -const ROLE_ORDER = new Map([ - ["payload-part", 0], - ["resource", 1], - ["platform-leaf", 2], - ["aot-leaf", 2], - ["portable-leaf", 2], - ["tool-leaf", 2], - ["plugin", 3], - ["tool-facade", 4], - ["facade", 5], -]); - -function error(message) { - return new Error(`publication-lock: ${message}`); -} - -function requireObject(value, context) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(`${context} must be an object`); - } - return value; -} - -function stableJson(value) { - if (Array.isArray(value)) { - return `[${value.map(stableJson).join(",")}]`; - } - if (value !== null && typeof value === "object") { - return `{${Object.keys(value).sort(compareText).map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`; - } - return JSON.stringify(value); -} - -function canonicalJsonText(value) { - return `${JSON.stringify(canonicalJsonTextValue(value), null, 2)}\n`; -} - -function canonicalJsonTextValue(value) { - if (Array.isArray(value)) return value.map((item) => canonicalJsonTextValue(item)); - if (value !== null && typeof value === "object") { - return Object.fromEntries( - Object.keys(value).sort(compareText) - .map((key) => [key, canonicalJsonTextValue(value[key])]), - ); - } - return value; -} - -function digestValue(value) { - return createHash("sha256").update(stableJson(value)).digest("hex"); -} - -function sha256File(file) { - const hash = createHash("sha256"); - hash.update(readFileSync(file)); - return hash.digest("hex"); -} - -function rel(file) { - const relative = path.relative(ROOT, file); - return relative.startsWith("..") || path.isAbsolute(relative) - ? path.resolve(file).split(path.sep).join("/") - : relative.split(path.sep).join("/"); -} - -function isFile(file) { - try { - return statSync(file).isFile(); - } catch { - return false; - } -} - -function isDirectory(file) { - try { - return statSync(file).isDirectory(); - } catch { - return false; - } -} - -function walkFiles(root, { ignoreBuildDirectories = false } = {}) { - if (isFile(root)) { - return [root]; - } - if (!isDirectory(root)) { - throw error(`artifact root does not exist or is not a file/directory: ${rel(root)}`); - } - const files = []; - const visit = (directory) => { - for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareText(left.name, right.name))) { - const fullPath = path.join(directory, entry.name); - if (entry.isSymbolicLink()) { - throw error(`artifact roots must not contain symlinks: ${rel(fullPath)}`); - } - if (entry.isDirectory()) { - if (ignoreBuildDirectories && IGNORED_DIRECTORIES.has(entry.name)) { - continue; - } - visit(fullPath); - } else if (entry.isFile()) { - files.push(fullPath); - } - } - }; - visit(root); - return files; -} - -function commandOutput(args, context) { - const result = captureCommandOutput(args[0], args.slice(1), { - cwd: ROOT, - label: context, - maxOutputBytes: 100 * 1024 * 1024, - }); - if (result.error !== undefined || result.status !== 0) { - const detail = (result.stderr || result.stdout || result.error?.message || "").trim(); - throw error(`${context} failed${detail ? `: ${detail}` : ""}`); - } - return result.stdout; -} - -function archiveMemberText(file, suffix, { exact = false } = {}) { - const listing = commandOutput(["tar", "-tzf", file], `list ${rel(file)}`) - .split(/\r?\n/u) - .filter(Boolean); - const members = listing.filter((name) => exact ? name === suffix : name.endsWith(suffix)); - if (members.length !== 1) { - throw error(`${rel(file)} must contain exactly one ${suffix}, found ${members.length}`); - } - return commandOutput(["tar", "-xOzf", file, members[0]], `read ${suffix} from ${rel(file)}`); -} - -function canonicalExtensionBundleEntries(file) { - let entries; - try { - entries = readCanonicalTarGzipEntries(file, { fileMode: 0o644 }); - } catch (cause) { - throw error(`${rel(file)} is not an exact canonical tar.gz bundle: ${cause.message}`); - } - return entries; -} - -function safeArchiveMember(value, context) { - if ( - typeof value !== "string" - || value.length === 0 - || value.includes("\\") - || value.startsWith("/") - || /^[A-Za-z]:/u.test(value) - || /[\u0000-\u001f\u007f]/u.test(value) - ) { - throw error(`${context} must be a safe POSIX archive path`); - } - const parts = value.replace(/^\.\//u, "").split("/"); - if (parts.some((part) => !part || part === "." || part === "..")) { - throw error(`${context} must be a safe POSIX archive path`); - } - return parts.join("/"); -} - - -function dependencyRows(ecosystem, tables) { - const rows = []; - for (const [scope, table] of tables) { - if (table === null || Array.isArray(table) || typeof table !== "object") { - continue; - } - for (const [name, raw] of Object.entries(table)) { - const requirement = typeof raw === "string" - ? raw - : raw !== null && !Array.isArray(raw) && typeof raw === "object" - ? String(raw.version ?? "*") - : "*"; - rows.push({ ecosystem, name, requirement, scope }); - } - } - return rows.sort((left, right) => compareText(`${left.ecosystem}:${left.name}:${left.scope}`, `${right.ecosystem}:${right.name}:${right.scope}`)); -} - -function npmArtifact(file) { - let manifest; - try { - manifest = JSON.parse(archiveMemberText(file, "package/package.json", { exact: true })); - } catch (cause) { - throw error(`invalid npm tarball ${rel(file)}: ${cause.message}`); - } - if (typeof manifest.name !== "string" || typeof manifest.version !== "string") { - throw error(`${rel(file)} npm package manifest must define name and version`); - } - try { - validateNpmTrustedPublishingManifest(manifest, `${rel(file)} package/package.json`); - } catch (cause) { - throw error(cause instanceof Error ? cause.message : String(cause)); - } - return { - ecosystem: "npm", - name: manifest.name, - version: manifest.version, - dependencies: dependencyRows("npm", [ - ["runtime", manifest.dependencies], - ["optional", manifest.optionalDependencies], - ["peer", manifest.peerDependencies], - ]), - artifacts: [{ path: rel(file), sha256: sha256File(file), size: statSync(file).size }], - }; -} - -function cargoDependencyTables(manifest) { - const tables = [["runtime", manifest.dependencies], ["build", manifest["build-dependencies"]], ["development", manifest["dev-dependencies"]]]; - for (const target of Object.values(manifest.target ?? {})) { - if (target !== null && !Array.isArray(target) && typeof target === "object") { - tables.push(["runtime", target.dependencies], ["build", target["build-dependencies"]]); - } - } - return tables; -} - -function cargoArtifact(file) { - let manifest; - try { - manifest = Bun.TOML.parse(archiveMemberText(file, "/Cargo.toml")); - } catch (cause) { - throw error(`invalid Cargo crate ${rel(file)}: ${cause.message}`); - } - if (typeof manifest.package?.name !== "string" || typeof manifest.package?.version !== "string") { - throw error(`${rel(file)} Cargo package manifest must define package.name and package.version`); - } - return { - ecosystem: "cargo", - name: manifest.package.name, - version: manifest.package.version, - dependencies: dependencyRows("cargo", cargoDependencyTables(manifest)), - artifacts: [{ path: rel(file), sha256: sha256File(file), size: statSync(file).size }], - }; -} - -function xmlText(block, tag) { - const match = block.match(new RegExp(`<${tag}>([^<]+)`, "u")); - return match?.[1]?.trim() ?? null; -} - -function mavenArtifact(file) { - const text = readFileSync(file, "utf8"); - const prefix = path.basename(file, ".pom"); - const artifactFiles = readdirSync(path.dirname(file)) - .filter((entry) => entry === `${prefix}.pom` || entry.startsWith(`${prefix}.` ) || entry.startsWith(`${prefix}-`)) - .map((entry) => path.join(path.dirname(file), entry)) - .filter(isFile) - .sort(compareText); - const publication = validateMavenCentralPublication({ - pomText: text, - files: artifactFiles.map((artifact) => ({ name: path.basename(artifact), size: statSync(artifact).size })), - context: rel(file), - }); - const group = publication.groupId; - const name = publication.artifactId; - const version = publication.version; - const dependencies = []; - for (const match of text.matchAll(/([\s\S]*?)<\/dependency>/gu)) { - const dependencyGroup = xmlText(match[1], "groupId"); - const dependencyName = xmlText(match[1], "artifactId"); - if (dependencyGroup === null || dependencyName === null) { - continue; - } - dependencies.push({ - ecosystem: "maven", - name: `${dependencyGroup}:${dependencyName}`, - requirement: xmlText(match[1], "version") ?? "*", - scope: xmlText(match[1], "scope") ?? "runtime", - }); - } - const artifacts = artifactFiles - .map((artifact) => ({ path: rel(artifact), sha256: sha256File(artifact), size: statSync(artifact).size })); - return { - ecosystem: "maven", - name: `${group}:${name}`, - version, - dependencies: dependencies.sort((left, right) => compareText(left.name, right.name)), - artifacts, - }; -} - -const MAVEN_MANIFEST_TOKEN = /^[A-Za-z0-9_.-]+$/u; -const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; -const CONTROL_CHARACTER = /[\u0000-\u001f\u007f]/u; - -function requiredMavenManifestText(value, label) { - if (typeof value !== "string" || value.length === 0 || CONTROL_CHARACTER.test(value)) { - throw error(`${label} must be a non-empty string without control characters`); - } - return value; -} - -function mavenManifestLicenses(value, label) { - let licenses; - try { - licenses = JSON.parse(value); - } catch (cause) { - throw error(`${label} must be valid JSON: ${cause.message}`); - } - if (!Array.isArray(licenses) || licenses.length === 0) { - throw error(`${label} must be a non-empty JSON array`); - } - const expectedKeys = ["name", "url", "distribution"]; - for (const [index, license] of licenses.entries()) { - const entryLabel = `${label} entry ${index + 1}`; - if (license === null || Array.isArray(license) || typeof license !== "object") { - throw error(`${entryLabel} must be an object`); - } - if (stableJson(Object.keys(license)) !== stableJson(expectedKeys)) { - throw error(`${entryLabel} must contain exactly ${expectedKeys.join(", ")} in canonical order`); - } - requiredMavenManifestText(license.name, `${entryLabel}.name`); - const url = requiredMavenManifestText(license.url, `${entryLabel}.url`); - if (!url.startsWith("https://")) { - throw error(`${entryLabel}.url must use HTTPS`); - } - if (license.distribution !== "repo") { - throw error(`${entryLabel}.distribution must be repo`); - } - } - if (value !== JSON.stringify(licenses)) { - throw error(`${label} must use canonical compact JSON`); - } - return licenses; -} - -function mavenManifestArtifacts(file) { - if (!rel(file).includes("/maven-artifacts/")) { - return []; - } - const records = []; - const coordinates = new Set(); - for (const [index, line] of readFileSync(file, "utf8").split(/\r?\n/u).filter(Boolean).entries()) { - const values = line.split("\t"); - const label = `${rel(file)} line ${index + 1}`; - if (values.length !== 10) { - throw error(`${label} must contain ten Maven publication fields`); - } - const [ - group, - name, - version, - artifactPath, - displayName, - description, - runtimeProduct, - runtimeVersion, - licenseSpdx, - licensesJson, - ] = values; - for (const [field, value] of [["groupId", group], ["artifactId", name], ["version", version]]) { - requiredMavenManifestText(value, `${label} ${field}`); - if (!MAVEN_MANIFEST_TOKEN.test(value)) { - throw error(`${label} ${field} contains non-portable Maven characters`); - } - } - requiredMavenManifestText(artifactPath, `${label} artifact path`); - requiredMavenManifestText(displayName, `${label} display name`); - requiredMavenManifestText(description, `${label} description`); - if ((runtimeProduct.length === 0) !== (runtimeVersion.length === 0)) { - throw error(`${label} must declare both runtime product and version or neither`); - } - if (runtimeProduct.length > 0) { - requiredMavenManifestText(runtimeProduct, `${label} runtime product`); - requiredMavenManifestText(runtimeVersion, `${label} runtime version`); - } - requiredMavenManifestText(licenseSpdx, `${label} SPDX expression`); - mavenManifestLicenses(licensesJson, `${label} licenses`); - if ( - group === "dev.oliphaunt.extensions" - && (runtimeProduct !== "liboliphaunt-native" || !STABLE_SEMVER.test(runtimeVersion)) - ) { - throw error(`${label} extension carrier must bind an exact stable liboliphaunt-native runtime version`); - } - const coordinate = `${group}:${name}:${version}`; - if (coordinates.has(coordinate)) { - throw error(`${rel(file)} contains duplicate Maven coordinate ${coordinate}`); - } - coordinates.add(coordinate); - const artifact = path.resolve(ROOT, artifactPath); - if (!artifactPath.endsWith(".tar.gz") || !isFile(artifact)) { - throw error(`${label} references a missing or non-tar.gz Maven artifact ${artifactPath}`); - } - records.push({ - ecosystem: "maven", - name: `${group}:${name}`, - version, - dependencies: [], - artifacts: [{ path: rel(artifact), sha256: sha256File(artifact), size: statSync(artifact).size }], - }); - } - return records; -} - -function directoryEnvelope(directory) { - const files = walkFiles(directory, { ignoreBuildDirectories: true }); - const hash = createHash("sha256"); - let size = 0; - for (const file of files) { - const relative = path.relative(directory, file).split(path.sep).join("/"); - const bytes = readFileSync(file); - hash.update(`${relative}\0${bytes.length}\0`); - hash.update(bytes); - size += bytes.length; - } - return { path: rel(directory), sha256: hash.digest("hex"), size }; -} - -function mergeArtifactRecord(records, record) { - const id = `${record.ecosystem}:${record.name}@${record.version}`; - const existing = records.get(id); - if (existing === undefined) { - records.set(id, record); - return; - } - if (stableJson(existing.dependencies) !== stableJson(record.dependencies)) { - throw error(`duplicate artifact identity ${id} has conflicting dependency metadata`); - } - if (record.ecosystem !== "maven") { - const variants = new Map( - [...existing.artifacts, ...record.artifacts] - .map((artifact) => [`${artifact.sha256}:${artifact.size}`, artifact]), - ); - if (variants.size !== 1) { - const candidates = [...existing.artifacts, ...record.artifacts] - .map((artifact) => `${artifact.path} (${artifact.sha256}, ${artifact.size} bytes)`) - .sort(compareText); - throw error( - `duplicate artifact identity ${id} has conflicting candidate bytes: ${candidates.join(", ")}`, - ); - } - existing.artifacts = [[...variants.values()][0], ...existing.artifacts, ...record.artifacts] - .sort((left, right) => compareText(left.path, right.path)) - .slice(0, 1); - return; - } - const byHash = new Map(existing.artifacts.map((artifact) => [artifact.sha256, artifact])); - for (const artifact of record.artifacts) { - const previous = byHash.get(artifact.sha256); - if (previous !== undefined && previous.size !== artifact.size) { - throw error(`duplicate artifact hash ${artifact.sha256} has conflicting sizes`); - } - byHash.set(artifact.sha256, artifact); - } - existing.artifacts = [...byHash.values()].sort((left, right) => compareText(left.path, right.path)); -} - -function discoverPublicationArtifactsMatching(roots, includeRecord) { - if (!Array.isArray(roots) || roots.length === 0) { - throw error("at least one artifact root is required"); - } - const files = [...new Set(roots.flatMap((root) => walkFiles(path.resolve(ROOT, root))))].sort(compareText); - const records = new Map(); - const mavenPoms = new Set(); - const addRecord = (record) => { - if (includeRecord(record)) { - mergeArtifactRecord(records, record); - } - }; - for (const file of files) { - if (file.endsWith(".tgz")) { - addRecord(npmArtifact(file)); - } else if (file.endsWith(".crate")) { - addRecord(cargoArtifact(file)); - } else if (file.endsWith(".pom") && !file.endsWith("-sources.pom") && !file.endsWith("-javadoc.pom")) { - const record = mavenArtifact(file); - const key = `${record.name}@${record.version}`; - if (!mavenPoms.has(key)) { - mavenPoms.add(key); - addRecord(record); - } - } else if (file.endsWith(".tsv")) { - for (const record of mavenManifestArtifacts(file)) { - addRecord(record); - } - } - } - return [...records.values()].sort((left, right) => compareText(`${left.ecosystem}:${left.name}`, `${right.ecosystem}:${right.name}`)); -} - -export function discoverPublicationArtifacts(roots) { - return discoverPublicationArtifactsMatching(roots, () => true); -} - -function discoverSelectedPublicationArtifacts(roots, fullCatalog, selectedProducts) { - return discoverPublicationArtifactsMatching(roots, (artifact) => { - const resolved = resolveActualCarrier( - fullCatalog, - artifact.ecosystem, - artifact.name, - "publication-lock artifact classification", - ); - return selectedProducts.has(resolved.product); - }); -} - -function productArtifact({ product, id, role, kind, target = null, identity = null, name, file }) { - return { - id, - product, - role, - kind, - target, - identity, - name, - path: rel(file), - sha256: sha256File(file), - size: statSync(file).size, - }; -} - -function productDirectoryArtifact({ product, id, role, kind, target = null, identity = null, name, directory }) { - const envelope = directoryEnvelope(directory); - return { - id, - product, - role, - kind, - target, - identity, - name, - path: envelope.path, - sha256: envelope.sha256, - size: envelope.size, - }; -} - -function exactDirectFileSet(directory, expectedNames, context) { - if (!isDirectory(directory)) { - throw error(`${context} release asset directory does not exist: ${rel(directory)}`); - } - const actual = readdirSync(directory, { withFileTypes: true }) - .filter((entry) => entry.isFile()) - .map((entry) => entry.name) - .sort(compareText); - const expected = [...expectedNames].sort(compareText); - if (stableJson(actual) !== stableJson(expected)) { - const expectedSet = new Set(expected); - const actualSet = new Set(actual); - const missing = expected.filter((name) => !actualSet.has(name)); - const extra = actual.filter((name) => !expectedSet.has(name)); - throw error(`${context} public release asset set mismatch: missing=${JSON.stringify(missing)}, extra=${JSON.stringify(extra)}`); - } -} - -function validateChecksumManifest(file, payloadFiles, context) { - const declared = new Map(); - for (const [index, rawLine] of readFileSync(file, "utf8").split(/\r?\n/u).entries()) { - if (rawLine.length === 0) { - continue; - } - const match = rawLine.match(/^([0-9a-f]{64}) \.\/([^/\0]+)$/u); - if (match === null) { - throw error(`${context} checksum line ${index + 1} must be ' ./'`); - } - const [, digest, name] = match; - if (declared.has(name)) { - throw error(`${context} checksum manifest declares ${name} more than once`); - } - declared.set(name, digest); - } - const expected = new Map(payloadFiles.map((payload) => [path.basename(payload), sha256File(payload)])); - const declaredNames = [...declared.keys()].sort(compareText); - const expectedNames = [...expected.keys()].sort(compareText); - if (stableJson(declaredNames) !== stableJson(expectedNames)) { - throw error(`${context} checksum entries do not exactly cover public payloads: expected=${JSON.stringify(expectedNames)}, actual=${JSON.stringify(declaredNames)}`); - } - for (const [name, digest] of expected) { - if (declared.get(name) !== digest) { - throw error(`${context} checksum for ${name} does not match its frozen bytes`); - } - } -} - -function fixedGithubReleaseArtifacts(files, product) { - const targets = allArtifactTargets({ - product: product.id, - surface: "github-release", - }, "publication-lock"); - if (targets.length === 0) { - return []; - } - const expected = targets.map((target) => ({ - target, - name: target.asset.replaceAll("{version}", product.version), - })); - const matches = new Map(); - for (const row of expected) { - const found = files.filter((file) => path.basename(file) === row.name); - if (found.length !== 1) { - throw error(`${product.id} requires exactly one public GitHub asset ${row.name}, found ${found.length}`); - } - matches.set(row.name, found[0]); - } - const directories = new Set([...matches.values()].map((file) => path.dirname(file))); - if (directories.size !== 1) { - throw error(`${product.id} public GitHub assets must share one release-assets directory`); - } - const directory = [...directories][0]; - if (path.basename(directory) !== "release-assets") { - throw error(`${product.id} public GitHub assets must be staged directly in a release-assets directory, got ${rel(directory)}`); - } - exactDirectFileSet(directory, expected.map((row) => row.name), product.id); - const checksumRows = expected.filter((row) => row.target.kind === "checksums"); - if (checksumRows.length !== 1) { - throw error(`${product.id} must declare exactly one canonical GitHub checksum asset, found ${checksumRows.length}`); - } - const checksum = matches.get(checksumRows[0].name); - validateChecksumManifest( - checksum, - expected.filter((row) => row.name !== checksumRows[0].name).map((row) => matches.get(row.name)), - `${product.id}/${checksumRows[0].name}`, - ); - return expected.map(({ target, name }) => productArtifact({ - product: product.id, - id: `github-release:${name}`, - role: "github-release-asset", - kind: target.kind, - target: target.target, - name, - file: matches.get(name), - })); -} - -function extensionAssetKindAllowed(family, target, kind) { - if (family === "wasix") { - return target === "wasix-portable" && kind === "wasix-runtime"; - } - if (family !== "native") { - return false; - } - if (target === "ios-xcframework") { - return kind === "runtime" || kind === "ios-xcframework" || kind === "ios-dependency-xcframework"; - } - if (target.startsWith("android-")) { - return kind === "runtime"; - } - return kind === "runtime"; -} - -function parseTsv(file) { - const lines = readFileSync(file, "utf8").split(/\r?\n/u).filter((line) => line.length > 0 && !line.startsWith("#")); - const header = lines[0].split("\t"); - return lines.slice(1).map((line) => { - const values = line.split("\t"); - return Object.fromEntries(header.map((column, index) => [column, values[index] ?? ""])); - }); -} - -function exactExtensionIosContract(product, sqlName) { - if (!extensionSqlNames(product, "publication-lock").includes(sqlName)) { - throw error(`${product} does not own extension SQL name ${sqlName}`); - } - const generated = JSON.parse(readFileSync(path.join(ROOT, "src/extensions/generated/sdk/extensions.json"), "utf8")); - const row = generated.extensions?.find((item) => item?.["sql-name"] === sqlName); - if (row === undefined) { - throw error(`${product} is absent from generated React Native extension metadata`); - } - const nativeModuleStem = typeof row["native-module-stem"] === "string" && row["native-module-stem"].length > 0 - ? row["native-module-stem"] - : null; - if (nativeModuleStem === null) { - return { sqlName, nativeModuleStem, dependencies: [], metadata: row }; - } - const staticRows = parseTsv(path.join(ROOT, "src/extensions/generated/mobile/static-extensions.tsv")); - const staticRow = staticRows.find((item) => item["sql-name"] === sqlName); - if (staticRow === undefined || staticRow["native-module-stem"] !== nativeModuleStem) { - throw error(`${product} native module ${nativeModuleStem} is absent from generated mobile static metadata`); - } - const dependencies = (staticRow["ios-static-dependencies"] || "") - .split(",") - .map((value) => value.trim()) - .filter(Boolean) - .sort(compareText); - if (new Set(dependencies).size !== dependencies.length) { - throw error(`${product} generated iOS dependency closure contains duplicates`); - } - return { sqlName, nativeModuleStem, dependencies, metadata: row }; -} - -function extensionRequiredArtifactRows(product) { - const rows = []; - for (const target of extensionArtifactTargets({ product }, "publication-lock")) { - const sqlName = target.sqlName ?? target.sql_name; - const ios = exactExtensionIosContract(product, sqlName); - if (target.family === "wasix") { - rows.push({ sqlName, family: target.family, target: target.target, kind: "wasix-runtime", identity: null }); - } else if (target.target === "ios-xcframework") { - rows.push({ sqlName, family: target.family, target: target.target, kind: "runtime", identity: null }); - if (ios.nativeModuleStem !== null) { - rows.push({ sqlName, family: target.family, target: target.target, kind: "ios-xcframework", identity: ios.nativeModuleStem }); - for (const dependency of ios.dependencies) { - rows.push({ sqlName, family: target.family, target: target.target, kind: "ios-dependency-xcframework", identity: dependency }); - } - } - } else if (target.target.startsWith("android-")) { - rows.push({ sqlName, family: target.family, target: target.target, kind: "runtime", identity: null }); - } else { - rows.push({ sqlName, family: target.family, target: target.target, kind: "runtime", identity: null }); - } - } - return rows.sort((left, right) => compareText( - `${left.sqlName}:${left.family}:${left.target}:${left.kind}:${left.identity ?? ""}`, - `${right.sqlName}:${right.family}:${right.target}:${right.kind}:${right.identity ?? ""}`, - )); -} - -export function extensionRequiredAssetKeys(product) { - if (extensionSqlNames(product, "publication-lock").length > 1) { - return extensionBundleCarrierRows(product).map(({ family, target }) => - `bundle:${family}:${target}`); - } - return extensionRequiredArtifactRows(product).map((row) => - `${row.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? "" : `:${row.identity}`}`); -} - -function extensionBundleCarrierRows(product, family = null) { - const groups = new Map(); - for (const row of extensionArtifactTargets({ product }, "publication-lock")) { - if (family !== null && row.family !== family) continue; - const key = `${row.family}\0${row.target}`; - if (!groups.has(key)) { - groups.set(key, { family: row.family, target: row.target, kind: "extension-bundle" }); - } - } - return [...groups.values()].sort((left, right) => - compareText(`${left.family}\0${left.target}`, `${right.family}\0${right.target}`)); -} - -function extensionPublicationOwner(product) { - return product.releaseProduct ?? product.id; -} - -function extensionCarrierFamily(product) { - return product.family ?? null; -} - -export function expectedExtensionGithubReleaseAssetCount(product) { - // Singleton releases publish each target payload directly. Multi-member - // contrib releases publish one deterministic carrier per family/target; - // exact member locators and checksums remain frozen in the control manifest. - return extensionRequiredAssetKeys(product).length + 4; -} - -function canonicalExtensionAssetName(product, row) { - const prefix = `${product.id}-${product.version}`; - if (row.family === "wasix") { - return `${prefix}-wasix-portable.tar.zst`; - } - if (row.kind === "ios-xcframework") { - return `${prefix}-native-ios-xcframework.zip`; - } - if (row.kind === "ios-dependency-xcframework") { - return `${prefix}-native-ios-dependency-${row.identity}-xcframework.zip`; - } - if (row.target === "ios-xcframework") { - return `${prefix}-native-ios-runtime.tar.gz`; - } - return `${prefix}-native-${row.target}-runtime.tar.gz`; -} - -function canonicalExtensionBundleAssetName(product, { family, target }) { - return `${product.id}-${product.version}-${family}-${target}-bundle.tar.gz`; -} - -function expectedExtensionGithubReleaseAssetRows(product) { - if (extensionSqlNames(product.id, "publication-lock").length > 1) { - return extensionBundleCarrierRows(product.id, extensionCarrierFamily(product)).map((row) => ({ - ...row, - identity: row.family, - name: canonicalExtensionBundleAssetName(product, row), - })); - } - return extensionRequiredArtifactRows(product.id).map((row) => ({ - ...row, - name: canonicalExtensionAssetName(product, row), - })); -} - -function exactExtensionManifestRows(product, manifest, manifestPath) { - const expectedSqlNames = extensionSqlNames(product.id, "publication-lock"); - const metadata = extensionMetadata(product.id, "publication-lock"); - const family = extensionCarrierFamily(product); - if ( - (manifest.artifactProduct ?? manifest.product) !== product.id - || (manifest.releaseProduct ?? manifest.product) !== extensionPublicationOwner(product) - || (family !== null && manifest.family !== family) - || manifest.version !== product.version - || stableJson(manifest.compatibility) !== stableJson(metadata.compatibility) - ) { - throw error(`${rel(manifestPath)} does not describe ${product.id}@${product.version}`); - } - if (expectedSqlNames.length === 1) { - if (manifest.schema !== "oliphaunt-extension-ci-artifacts-v1" || !Array.isArray(manifest.assets)) { - throw error(`${rel(manifestPath)} must be a singleton exact-extension CI artifact manifest`); - } - return [manifest]; - } - if (manifest.schema !== "oliphaunt-extension-ci-artifacts-v2" || !Array.isArray(manifest.extensions)) { - throw error(`${rel(manifestPath)} must be an exact-extension bundle CI artifact manifest`); - } - const actualSqlNames = manifest.extensions.map((row) => row?.sqlName); - if (stableJson(actualSqlNames) !== stableJson(expectedSqlNames)) { - throw error(`${rel(manifestPath)} must contain the exact sorted bundle member set`); - } - return manifest.extensions; -} - -function validateExtensionManifestRow(product, manifestPath, member) { - const iosContract = exactExtensionIosContract(product.id, member.sqlName); - const stagesIos = Array.isArray(member.assets) - && member.assets.some((asset) => asset?.target === "ios-xcframework"); - const iosDependencies = stagesIos ? iosContract.dependencies : []; - const sortedStrings = (value) => Array.isArray(value) - && value.every((item) => typeof item === "string" && item.length > 0) - && new Set(value).size === value.length - && stableJson(value) === stableJson([...value].sort(compareText)) - ? value - : null; - if ( - member.nativeModuleStem !== iosContract.nativeModuleStem - || member.createsExtension !== (iosContract.metadata["creates-extension"] !== false) - || stableJson(sortedStrings(member.dependencies)) !== stableJson([...(iosContract.metadata["selected-extension-dependencies"] ?? [])].sort(compareText)) - || stableJson(sortedStrings(member.dataFiles)) !== stableJson([...(iosContract.metadata["runtime-share-data-files"] ?? [])].sort(compareText)) - || stableJson(sortedStrings(member.extensionSqlFileNames)) !== stableJson([...(iosContract.metadata["extension-sql-file-names"] ?? [])].sort(compareText)) - || stableJson(sortedStrings(member.extensionSqlFilePrefixes)) !== stableJson([...(iosContract.metadata["extension-sql-file-prefixes"] ?? [])].sort(compareText)) - || stableJson(sortedStrings(member.sharedPreloadLibraries)) !== stableJson([...(iosContract.metadata["shared-preload-libraries"] ?? [])].sort(compareText)) - || stableJson(sortedStrings(member.iosNativeDependencies)) !== stableJson(iosDependencies) - ) { - throw error(`${rel(manifestPath)} ${member.sqlName} semantic extension metadata is not canonical generated metadata`); - } - if (iosContract.nativeModuleStem === null) { - if (member.iosRegistration !== null) { - throw error(`${rel(manifestPath)} SQL-only extension ${member.sqlName} must not carry iOS registration`); - } - } else if (stagesIos && ( - member.iosRegistration === null - || Array.isArray(member.iosRegistration) - || typeof member.iosRegistration !== "object" - || member.iosRegistration.schema !== "oliphaunt-ios-extension-registration-v1" - || member.iosRegistration.sqlName !== member.sqlName - || member.iosRegistration.nativeModuleStem !== iosContract.nativeModuleStem - )) { - throw error(`${rel(manifestPath)} native extension ${member.sqlName} lacks matching build-derived iOS registration`); - } else if (!stagesIos && member.iosRegistration !== null) { - throw error(`${rel(manifestPath)} native extension ${member.sqlName} claims iOS registration without an iOS carrier`); - } - return iosContract; -} - -function publicExtensionAsset(row) { - return extensionRuntimeAssetContract(row); -} - -function publicExtensionMember(member) { - const wasixInstall = assertWasixExtensionMemberInstall(member, { - label: `${member.sqlName} extension member`, - }); - return { - sqlName: member.sqlName, - createsExtension: member.createsExtension, - dependencies: member.dependencies, - dataFiles: member.dataFiles, - extensionSqlFileNames: member.extensionSqlFileNames, - extensionSqlFilePrefixes: member.extensionSqlFilePrefixes, - nativeModuleStem: member.nativeModuleStem, - iosNativeDependencies: member.iosNativeDependencies, - iosRegistration: member.iosRegistration, - wasixInstall, - sharedPreloadLibraries: member.sharedPreloadLibraries, - assets: member.assets.map(publicExtensionAsset), - }; -} - -function extensionBundleGithubReleaseArtifacts({ directory, manifest, manifestPath, members, product }) { - const expectedSqlNames = extensionSqlNames(product.id, "publication-lock"); - const family = extensionCarrierFamily(product); - const expectedGroups = extensionBundleCarrierRows(product.id, family); - if (!Array.isArray(manifest.carrierAssets) || manifest.carrierAssets.length !== expectedGroups.length) { - throw error(`${rel(manifestPath)} must declare exactly ${expectedGroups.length} aggregate carrier assets`); - } - const carriersByGroup = new Map(); - const carriersByName = new Map(); - for (const [index, row] of manifest.carrierAssets.entries()) { - if ( - row === null - || Array.isArray(row) - || typeof row !== "object" - || row.kind !== "extension-bundle" - || typeof row.family !== "string" - || typeof row.target !== "string" - || typeof row.name !== "string" - || path.basename(row.name) !== row.name - || typeof row.path !== "string" - || typeof row.sha256 !== "string" - || !/^[0-9a-f]{64}$/u.test(row.sha256) - || !Number.isSafeInteger(row.bytes) - || row.bytes <= 0 - || row.memberCount !== expectedSqlNames.length - ) { - throw error(`${rel(manifestPath)} carrierAssets[${index}] is invalid`); - } - const group = `${row.family}\0${row.target}`; - const canonicalName = canonicalExtensionBundleAssetName(product, row); - const file = path.resolve(ROOT, row.path); - if ( - row.name !== canonicalName - || file !== path.join(directory, canonicalName) - || !isFile(file) - || statSync(file).size !== row.bytes - || sha256File(file) !== row.sha256 - || carriersByGroup.has(group) - || carriersByName.has(row.name) - ) { - throw error(`${rel(manifestPath)} aggregate carrier ${row.name} is non-canonical, duplicated, missing, or byte-skewed`); - } - carriersByGroup.set(group, { row, file, members: [] }); - carriersByName.set(row.name, { row, file, members: [] }); - } - if (stableJson([...carriersByGroup.keys()].sort(compareText)) !== stableJson( - expectedGroups.map(({ family, target }) => `${family}\0${target}`).sort(compareText), - )) { - throw error(`${product.id} aggregate carriers do not exactly cover every published family/target`); - } - - const logicalRows = new Map(); - for (const member of members) { - const iosContract = validateExtensionManifestRow(product, manifestPath, member); - if (!Array.isArray(member.assets) || member.assets.length === 0) { - throw error(`${rel(manifestPath)} ${member.sqlName} must declare at least one logical artifact`); - } - for (const row of member.assets) { - if ( - row === null - || Array.isArray(row) - || typeof row !== "object" - || ![row.family, row.target, row.kind, row.name, row.path, row.sha256, row.carrierAsset, row.carrierRoot, row.memberPath] - .every((value) => typeof value === "string" && value.length > 0) - || !(row.identity === null || typeof row.identity === "string" && row.identity.length > 0) - || !Number.isSafeInteger(row.bytes) - || row.bytes <= 0 - || !/^[0-9a-f]{64}$/u.test(row.sha256) - || path.basename(row.name) !== row.name - ) { - throw error(`${rel(manifestPath)} ${member.sqlName} contains an invalid bundle member asset row`); - } - if (row.kind === "ios-dependency-xcframework" && row.identity === null) { - throw error(`${rel(manifestPath)} iOS dependency XCFramework ${row.name} lacks identity`); - } - if (row.kind === "ios-xcframework" && row.identity !== iosContract.nativeModuleStem) { - throw error(`${rel(manifestPath)} primary iOS XCFramework identity must be ${iosContract.nativeModuleStem}`); - } - if (row.kind !== "ios-dependency-xcframework" && row.kind !== "ios-xcframework" && row.identity !== null) { - throw error(`${rel(manifestPath)} asset ${row.name} must not carry identity for ${row.kind}`); - } - if (!extensionAssetKindAllowed(row.family, row.target, row.kind)) { - throw error(`${rel(manifestPath)} contains invalid logical asset role ${member.sqlName}/${row.family}/${row.target}/${row.kind}`); - } - const canonicalName = canonicalExtensionAssetName(product, row); - if (row.name !== canonicalName) { - throw error(`${rel(manifestPath)} logical asset ${row.name} is not canonical ${canonicalName}`); - } - const logicalFile = path.resolve(ROOT, row.path); - const expectedLogicalFile = path.join(path.dirname(manifestPath), "member-assets", member.sqlName, row.name); - if ( - logicalFile !== expectedLogicalFile - || !isFile(logicalFile) - || statSync(logicalFile).size !== row.bytes - || sha256File(logicalFile) !== row.sha256 - ) { - throw error(`${rel(manifestPath)} logical asset metadata does not match ${rel(expectedLogicalFile)}`); - } - const key = `${member.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? "" : `:${row.identity}`}`; - if (logicalRows.has(key)) throw error(`${rel(manifestPath)} contains duplicate logical asset role ${key}`); - const carrier = carriersByName.get(row.carrierAsset); - if (carrier === undefined || carrier.row.family !== row.family || carrier.row.target !== row.target) { - throw error(`${rel(manifestPath)} ${key} references a missing or wrong-family aggregate carrier`); - } - const expectedRoot = carrier.row.name.replace(/\.tar\.gz$/u, ""); - const expectedMemberPath = `extensions/${member.sqlName}/${row.name}`; - if (row.carrierRoot !== expectedRoot || row.memberPath !== expectedMemberPath) { - throw error(`${rel(manifestPath)} ${key} has a non-canonical aggregate member locator`); - } - const manifestMember = { - sqlName: member.sqlName, - kind: row.kind, - identity: row.identity, - path: row.memberPath, - sha256: row.sha256, - bytes: row.bytes, - }; - carrier.members.push({ logicalFile, manifestMember, row }); - logicalRows.set(key, { row, file: logicalFile }); - } - } - const expectedLogicalKeys = extensionRequiredArtifactRows(product.id) - .filter((row) => family === null || row.family === family) - .map((row) => - `${row.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? "" : `:${row.identity}`}`); - if (stableJson([...logicalRows.keys()].sort(compareText)) !== stableJson(expectedLogicalKeys)) { - throw error(`${product.id} logical bundle rows do not exactly cover every member target/role`); - } - - for (const { row, file, members: carrierMembers } of carriersByName.values()) { - carrierMembers.sort((left, right) => compareText( - `${left.manifestMember.sqlName}\0${left.manifestMember.kind}\0${left.manifestMember.identity ?? ""}`, - `${right.manifestMember.sqlName}\0${right.manifestMember.kind}\0${right.manifestMember.identity ?? ""}`, - )); - const manifestMembers = carrierMembers.map(({ manifestMember }) => manifestMember); - const carrierRoot = row.name.replace(/\.tar\.gz$/u, ""); - const bundleManifestPath = `${carrierRoot}/bundle-manifest.json`; - const memberNames = [...new Set(manifestMembers.map((member) => member.sqlName))].sort(compareText); - if (stableJson(memberNames) !== stableJson(expectedSqlNames)) { - throw error(`${rel(file)} aggregate carrier does not contain every exact bundle member`); - } - const legal = extensionCarrierLegalContract(product.id, memberNames, { - family: row.family, - target: row.target, - }); - const expectedBundleManifest = { - schema: "oliphaunt-extension-bundle-v1", - product: product.id, - version: product.version, - compatibility: extensionMetadata(product.id, "publication-lock").compatibility, - family: row.family, - target: row.target, - licenseProfile: legal.profile, - licenseFiles: legal.licenseFiles, - members: manifestMembers, - }; - const entries = canonicalExtensionBundleEntries(file); - const legalFiles = extensionCarrierLegalFileInventory(product.id, memberNames, { - family: row.family, - target: row.target, - }); - const expectedArchiveFiles = [ - bundleManifestPath, - ...manifestMembers.map((member) => `${carrierRoot}/${member.path}`), - ...legalFiles.map(({ path: legalPath }) => `${carrierRoot}/${legalPath}`), - ].sort(compareText); - const archiveFiles = [...entries.keys()].sort(compareText); - if (stableJson(archiveFiles) !== stableJson(expectedArchiveFiles)) { - throw error(`${rel(file)} contains undeclared or missing regular bundle members`); - } - for (const archiveFile of expectedArchiveFiles) safeArchiveMember(archiveFile, `${rel(file)} member`); - const manifestEntry = entries.get(bundleManifestPath); - const expectedBundleManifestBytes = Buffer.from(canonicalJsonText(expectedBundleManifest)); - const actualBundleManifestBytes = Buffer.from(manifestEntry.data()); - let bundleManifest; - try { - bundleManifest = JSON.parse(actualBundleManifestBytes.toString("utf8")); - } catch (cause) { - throw error(`${rel(file)} has invalid bundle-manifest.json: ${cause.message}`); - } - if (stableJson(bundleManifest) !== stableJson(expectedBundleManifest)) { - throw error(`${rel(file)} bundle-manifest.json does not exactly freeze its nested member and legal locators`); - } - if (!actualBundleManifestBytes.equals(expectedBundleManifestBytes)) { - throw error(`${rel(file)} bundle-manifest.json must use the exact canonical bytes for its nested member and legal locators`); - } - for (const { logicalFile, manifestMember, row: logicalRow } of carrierMembers) { - const archivePath = `${carrierRoot}/${manifestMember.path}`; - const entry = entries.get(archivePath); - const payload = Buffer.from(entry.data()); - if ( - entry.size !== logicalRow.bytes - || payload.length !== logicalRow.bytes - || createHash("sha256").update(payload).digest("hex") !== logicalRow.sha256 - || !payload.equals(readFileSync(logicalFile)) - ) { - throw error(`${rel(file)} nested payload ${archivePath} does not match its staged logical bytes`); - } - } - for (const legalFile of legalFiles) { - const archivePath = `${carrierRoot}/${legalFile.path}`; - const entry = entries.get(archivePath); - const payload = Buffer.from(entry.data()); - if ( - legalFile.mode !== "0644" - || entry.mode !== 0o644 - || entry.size !== legalFile.bytes - || payload.length !== legalFile.bytes - || createHash("sha256").update(payload).digest("hex") !== legalFile.sha256 - ) { - throw error(`${rel(file)} legal member ${archivePath} does not match its canonical bytes and mode`); - } - } - } - - const manifestName = `${product.id}-${product.version}-manifest.json`; - const publicManifestFile = path.join(directory, manifestName); - let publicManifest; - try { - publicManifest = JSON.parse(readFileSync(publicManifestFile, "utf8")); - } catch (cause) { - throw error(`${rel(publicManifestFile)} is invalid JSON: ${cause.message}`); - } - const metadata = extensionMetadata(product.id, "publication-lock"); - const expectedPublicManifest = { - schema: "oliphaunt-extension-release-manifest-v2", - product: product.id, - ...(manifest.releaseProduct === undefined ? {} : { - releaseProduct: extensionPublicationOwner(product), - family: family ?? "combined", - }), - version: product.version, - extensionClass: metadata.class, - versioning: metadata.versioning, - sourceIdentity: extensionSourceIdentity(product.id, "publication-lock"), - compatibility: metadata.compatibility, - extensions: members.map(publicExtensionMember), - assets: [...carriersByName.values()] - .map(({ row }) => publicExtensionAsset(row)) - .sort((left, right) => compareText(left.name, right.name)), - }; - if (stableJson(publicManifest) !== stableJson(expectedPublicManifest)) { - throw error(`${rel(publicManifestFile)} does not exactly expose the frozen aggregate member/carrier inventory`); - } - - const includeSwiftCarrier = family === null || family === "native"; - const swiftCarrierName = includeSwiftCarrier - ? swiftExtensionCarrierAssetName(product.id, product.version) - : null; - if (swiftCarrierName !== null) { - const swiftCarrierFile = path.join(directory, swiftCarrierName); - let actualSwiftCarrier; - try { - actualSwiftCarrier = JSON.parse(readFileSync(swiftCarrierFile, "utf8")); - } catch (cause) { - throw error(`invalid Swift iOS carrier ${rel(swiftCarrierFile)}: ${cause.message}`); - } - const expectedSwiftCarrier = buildSwiftExtensionCarrierManifest({ - extensionManifest: manifestPath, - nativeRuntimeVersion: extensionMetadata(product.id, "publication-lock").compatibility.nativeRuntimeVersion, - verifyMembers: false, - }); - if (stableJson(actualSwiftCarrier) !== stableJson(expectedSwiftCarrier)) { - throw error(`${rel(swiftCarrierFile)} does not exactly describe ${product.id} and its compatible native base`); - } - } - const controlFiles = [ - ["manifest-json", manifestName], - ["manifest-properties", `${product.id}-${product.version}-manifest.properties`], - ...(swiftCarrierName === null ? [] : [["swift-extension-carrier", swiftCarrierName]]), - ["checksums", `${product.id}-${product.version}-release-assets.sha256`], - ]; - const expectedNames = [ - ...[...carriersByName.keys()], - ...controlFiles.map(([, name]) => name), - ]; - exactDirectFileSet(directory, expectedNames, product.id); - const checksumName = controlFiles.find(([kind]) => kind === "checksums")[1]; - validateChecksumManifest( - path.join(directory, checksumName), - expectedNames.filter((name) => name !== checksumName).map((name) => path.join(directory, name)), - `${product.id}/${checksumName}`, - ); - return [ - ...[...carriersByName.values()].map(({ row, file }) => productArtifact({ - product: extensionPublicationOwner(product), - id: `github-release:${row.name}`, - role: "github-release-asset", - kind: row.kind, - target: row.target, - identity: row.family, - name: row.name, - file, - })), - ...controlFiles.map(([kind, name]) => productArtifact({ - product: extensionPublicationOwner(product), - id: `github-release:${name}`, - role: "github-release-metadata", - kind, - target: "portable", - name, - file: path.join(directory, name), - })), - ]; -} - -function extensionGithubReleaseArtifacts(files, product) { - const candidates = files.filter((file) => path.basename(file) === "extension-artifacts.json"); - const manifests = []; - for (const file of candidates) { - let value; - try { - value = JSON.parse(readFileSync(file, "utf8")); - } catch (cause) { - throw error(`invalid extension artifact manifest ${rel(file)}: ${cause.message}`); - } - if ( - (value?.artifactProduct ?? value?.product) === product.id - && (value?.releaseProduct ?? value?.product) === extensionPublicationOwner(product) - && (extensionCarrierFamily(product) === null || value?.family === extensionCarrierFamily(product)) - ) { - manifests.push([file, value]); - } - } - if (manifests.length !== 1) { - throw error(`${product.id} requires exactly one extension-artifacts.json in the staged roots, found ${manifests.length}`); - } - const [manifestPath, manifest] = manifests[0]; - const members = exactExtensionManifestRows(product, manifest, manifestPath); - const directory = path.join(path.dirname(manifestPath), "release-assets"); - if (members.length > 1) { - return extensionBundleGithubReleaseArtifacts({ directory, manifest, manifestPath, members, product }); - } - const rows = new Map(); - for (const member of members) { - const iosContract = validateExtensionManifestRow(product, manifestPath, member); - if (!Array.isArray(member.assets) || member.assets.length === 0) { - throw error(`${rel(manifestPath)} ${member.sqlName} must declare at least one artifact`); - } - for (const row of member.assets) { - if ( - row === null - || Array.isArray(row) - || typeof row !== "object" - || ![row.family, row.target, row.kind, row.name, row.path, row.sha256].every((value) => typeof value === "string" && value.length > 0) - || !(row.identity === null || typeof row.identity === "string" && row.identity.length > 0) - || !Number.isSafeInteger(row.bytes) - || row.bytes <= 0 - || !/^[0-9a-f]{64}$/u.test(row.sha256) - || path.basename(row.name) !== row.name - ) { - throw error(`${rel(manifestPath)} ${member.sqlName} contains an invalid public extension asset row`); - } - if (row.kind === "ios-dependency-xcframework" && row.identity === null) { - throw error(`${rel(manifestPath)} iOS dependency XCFramework ${row.name} lacks identity`); - } - if (row.kind === "ios-xcframework" && row.identity !== iosContract.nativeModuleStem) { - throw error(`${rel(manifestPath)} primary iOS XCFramework identity must be ${iosContract.nativeModuleStem}`); - } - if (row.kind !== "ios-dependency-xcframework" && row.kind !== "ios-xcframework" && row.identity !== null) { - throw error(`${rel(manifestPath)} asset ${row.name} must not carry identity for ${row.kind}`); - } - const key = `${member.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? "" : `:${row.identity}`}`; - if (rows.has(key)) { - throw error(`${rel(manifestPath)} contains duplicate extension asset role ${key}`); - } - if (!extensionAssetKindAllowed(row.family, row.target, row.kind)) { - throw error(`${rel(manifestPath)} contains invalid extension asset role ${key}`); - } - const canonicalName = canonicalExtensionAssetName(product, { ...row, sqlName: member.sqlName }); - if (row.name !== canonicalName) { - throw error(`${rel(manifestPath)} asset ${row.name} is not the canonical name ${canonicalName}`); - } - const file = path.resolve(ROOT, row.path); - if (file !== path.join(directory, row.name) || !isFile(file)) { - throw error(`${rel(manifestPath)} asset ${row.name} must exist directly under ${rel(directory)}`); - } - if (statSync(file).size !== row.bytes || sha256File(file) !== row.sha256) { - throw error(`${rel(manifestPath)} asset metadata does not match ${rel(file)}`); - } - rows.set(key, { row, file, sqlName: member.sqlName }); - } - } - const family = extensionCarrierFamily(product); - const expectedKeys = extensionRequiredArtifactRows(product.id) - .filter((row) => family === null || row.family === family) - .map((row) => - `${row.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? "" : `:${row.identity}`}`) - .sort(compareText); - const actualKeys = [...rows.keys()].sort(compareText); - if (stableJson(expectedKeys) !== stableJson(actualKeys)) { - throw error(`${product.id} extension asset roles do not exactly cover declared targets: expected=${JSON.stringify(expectedKeys)}, actual=${JSON.stringify(actualKeys)}`); - } - const publicManifestFile = path.join(directory, `${product.id}-${product.version}-manifest.json`); - let publicManifest; - try { - publicManifest = JSON.parse(readFileSync(publicManifestFile, "utf8")); - } catch (cause) { - throw error(`${rel(publicManifestFile)} is invalid JSON: ${cause.message}`); - } - const metadata = extensionMetadata(product.id, "publication-lock"); - const publicMember = publicExtensionMember(members[0]); - const expectedPublicManifest = { - schema: "oliphaunt-extension-release-manifest-v1", - product: product.id, - ...(manifest.releaseProduct === undefined ? {} : { - releaseProduct: extensionPublicationOwner(product), - family: family ?? "combined", - }), - version: product.version, - sqlName: publicMember.sqlName, - extensionClass: metadata.class, - versioning: metadata.versioning, - sourceIdentity: extensionSourceIdentity(product.id, "publication-lock"), - compatibility: metadata.compatibility, - createsExtension: publicMember.createsExtension, - dependencies: publicMember.dependencies, - dataFiles: publicMember.dataFiles, - extensionSqlFileNames: publicMember.extensionSqlFileNames, - extensionSqlFilePrefixes: publicMember.extensionSqlFilePrefixes, - nativeModuleStem: publicMember.nativeModuleStem, - iosNativeDependencies: publicMember.iosNativeDependencies, - iosRegistration: publicMember.iosRegistration, - wasixInstall: publicMember.wasixInstall, - sharedPreloadLibraries: publicMember.sharedPreloadLibraries, - assets: publicMember.assets, - }; - if (stableJson(publicManifest) !== stableJson(expectedPublicManifest)) { - throw error(`${rel(publicManifestFile)} does not exactly expose the canonical extension identity and frozen asset inventory`); - } - const includeSwiftCarrier = family === null || family === "native"; - const swiftCarrierName = includeSwiftCarrier - ? swiftExtensionCarrierAssetName(product.id, product.version) - : null; - if (swiftCarrierName !== null) { - const swiftCarrierFile = path.join(directory, swiftCarrierName); - if (!isFile(swiftCarrierFile)) { - throw error(`${product.id} requires independently consumable Swift iOS carrier ${swiftCarrierName}`); - } - let actualSwiftCarrier; - try { - actualSwiftCarrier = JSON.parse(readFileSync(swiftCarrierFile, "utf8")); - } catch (cause) { - throw error(`invalid Swift iOS carrier ${rel(swiftCarrierFile)}: ${cause.message}`); - } - const expectedSwiftCarrier = buildSwiftExtensionCarrierManifest({ - extensionManifest: manifestPath, - nativeRuntimeVersion: extensionMetadata(product.id, "publication-lock").compatibility.nativeRuntimeVersion, - verifyMembers: false, - }); - if (stableJson(actualSwiftCarrier) !== stableJson(expectedSwiftCarrier)) { - throw error(`${rel(swiftCarrierFile)} does not exactly describe ${product.id} and its compatible native base`); - } - } - const controlFiles = [ - ["manifest-json", `${product.id}-${product.version}-manifest.json`], - ["manifest-properties", `${product.id}-${product.version}-manifest.properties`], - ...(swiftCarrierName === null ? [] : [["swift-extension-carrier", swiftCarrierName]]), - ["checksums", `${product.id}-${product.version}-release-assets.sha256`], - ]; - const expectedNames = [ - ...[...rows.values()].map(({ row }) => row.name), - ...controlFiles.map(([, name]) => name), - ]; - if (new Set(expectedNames).size !== expectedNames.length) { - throw error(`${product.id} extension release assets contain duplicate public basenames`); - } - exactDirectFileSet(directory, expectedNames, product.id); - const checksumName = controlFiles.find(([kind]) => kind === "checksums")[1]; - const checksum = path.join(directory, checksumName); - validateChecksumManifest( - checksum, - expectedNames.filter((name) => name !== checksumName).map((name) => path.join(directory, name)), - `${product.id}/${checksumName}`, - ); - return [ - ...[...rows.values()].map(({ row, file }) => productArtifact({ - product: extensionPublicationOwner(product), - id: `github-release:${row.name}`, - role: "github-release-asset", - kind: row.kind, - target: row.target, - identity: row.identity, - name: row.name, - file, - })), - ...controlFiles.map(([kind, name]) => productArtifact({ - product: extensionPublicationOwner(product), - id: `github-release:${name}`, - role: "github-release-metadata", - kind, - target: "portable", - name, - file: path.join(directory, name), - })), - ]; -} - -function swiftReleaseInputs(files, product, { requireExtensionFixture }) { - const expectedFiles = [ - ["Oliphaunt-source.zip", "swiftpm-source-archive"], - ["Package.swift.release", "swiftpm-release-manifest"], - ["extension-owner-catalog.json", "swiftpm-extension-owner-catalog"], - ["extension-resource-inventory.mjs", "swiftpm-extension-resource-inventory"], - ["render-extension-products.mjs", "swiftpm-extension-generator"], - ["swift-carrier-resolver.mjs", "swiftpm-carrier-resolver"], - ]; - const artifacts = expectedFiles.map(([name, kind]) => { - const generatorInput = !["Oliphaunt-source.zip", "Package.swift.release"].includes(name); - const matches = files.filter((file) => - path.basename(file) === name - && (!generatorInput || rel(file).includes("/extension-generator/"))); - if (matches.length !== 1) { - throw error(`${product.id} requires exactly one ${name} in the staged artifact roots, found ${matches.length}`); - } - return productArtifact({ - product: product.id, - id: `release-input:${name}`, - role: "release-input", - kind, - target: "portable", - name, - file: matches[0], - }); - }); - const ownerCatalogArtifact = artifacts.find(({ kind }) => kind === "swiftpm-extension-owner-catalog"); - const canonicalOwnerCatalog = path.join(ROOT, "src/extensions/generated/sdk/extensions.json"); - if ( - ownerCatalogArtifact === undefined - || !readFileSync(path.resolve(ROOT, ownerCatalogArtifact.path)).equals(readFileSync(canonicalOwnerCatalog)) - ) { - throw error(`${product.id} frozen extension-owner-catalog.json must exactly match src/extensions/generated/sdk/extensions.json`); - } - const resourceInventoryArtifact = artifacts.find(({ kind }) => kind === "swiftpm-extension-resource-inventory"); - const canonicalResourceInventory = path.join(ROOT, "src/sdks/swift/tools/extension-resource-inventory.mjs"); - if ( - resourceInventoryArtifact === undefined - || !readFileSync(path.resolve(ROOT, resourceInventoryArtifact.path)).equals(readFileSync(canonicalResourceInventory)) - ) { - throw error(`${product.id} frozen extension-resource-inventory.mjs must exactly match src/sdks/swift/tools/extension-resource-inventory.mjs`); - } - const carrierName = "oliphaunt-react-native-ios-carriers.json"; - const carrierMatches = files.filter((file) => - path.basename(file) === carrierName - && rel(file).includes("/release-tree/src/sdks/swift/Carriers/")); - if (carrierMatches.length !== 1) { - throw error(`${product.id} requires exactly one source-tag carrier ${carrierName}, found ${carrierMatches.length}`); - } - const carrierFile = carrierMatches[0]; - artifacts.push(productArtifact({ - product: product.id, - id: `release-input:${carrierName}`, - role: "release-input", - kind: "swiftpm-ios-carrier-manifest", - target: "portable", - name: carrierName, - file: carrierFile, - })); - const releaseTree = path.join(path.dirname(carrierFile), "../../../.."); - artifacts.push(productDirectoryArtifact({ - product: product.id, - id: "release-input:swiftpm-release-tree", - role: "release-input", - kind: "swiftpm-release-tree", - target: "portable", - name: "release-tree", - directory: path.resolve(releaseTree), - })); - let carrier; - try { - carrier = JSON.parse(readFileSync(carrierFile, "utf8")); - } catch (cause) { - throw error(`${rel(carrierFile)} is not valid JSON: ${cause.message}`); - } - try { - validateSelectionNeutralSwiftSourceCarrier(carrier, rel(carrierFile)); - const manifestArtifact = artifacts.find(({ kind }) => kind === "swiftpm-release-manifest"); - if (manifestArtifact === undefined) { - throw new Error(`${product.id} is missing its frozen Package.swift.release artifact`); - } - validateSwiftSourceReleaseContract({ - carrier, - expectedNativeVersion: productCompatibilityVersion( - "oliphaunt-swift", - "liboliphaunt-native", - "publication-lock", - ), - label: `${product.id} frozen source release`, - manifestText: readFileSync(path.resolve(ROOT, manifestArtifact.path), "utf8"), - }); - } catch (cause) { - throw error(cause instanceof Error ? cause.message : String(cause)); - } - const fixtureManifests = files.filter((file) => - path.basename(file) === "extension-products.json" - && (rel(file).startsWith("target/release/swiftpm-extension-consumer-fixture/") - || rel(file).includes("/release/swiftpm-extension-consumer-fixture/"))); - const expectedFixtureCount = requireExtensionFixture ? 1 : 0; - if (fixtureManifests.length !== expectedFixtureCount) { - const selection = requireExtensionFixture - ? "selects extension products and requires exactly one" - : "selects no extension products and requires no"; - throw error(`${product.id} ${selection} frozen Swift consumer fixture, found ${fixtureManifests.length}`); - } - if (requireExtensionFixture) { - const fixture = path.dirname(fixtureManifests[0]); - if (!isFile(path.join(fixture, "Package.swift"))) { - throw error(`${rel(fixture)} is missing generated Package.swift`); - } - artifacts.push(productDirectoryArtifact({ - product: product.id, - id: "release-input:swiftpm-extension-consumer-fixture", - role: "release-input", - kind: "swiftpm-extension-consumer-fixture", - target: "portable", - name: "swiftpm-extension-consumer-fixture", - directory: fixture, - })); - } - return artifacts; -} - -function reactNativeReleaseInputs(files, product) { - const name = "oliphaunt-react-native-ios-carriers.json"; - const matches = files.filter((file) => - path.basename(file) === name - && (rel(file).startsWith("target/release/ios-carriers/") - || rel(file).includes("/release/ios-carriers/"))); - if (matches.length !== 1) { - throw error(`${product.id} requires exactly one canonical aggregate iOS carrier manifest, found ${matches.length}`); - } - return [productArtifact({ - product: product.id, - id: `release-input:${name}`, - role: "release-input", - kind: "react-native-ios-carrier-manifest", - target: "portable", - name, - file: matches[0], - })]; -} - -function runtimeOwnedExtensionGithubReleaseArtifacts(files, product) { - const contrib = contribCarrierDescriptor("publication-lock"); - const families = [ - ...(product.id === contrib.nativeOwner ? ["native"] : []), - ...(product.id === contrib.wasixOwner ? ["wasix"] : []), - ]; - return families.flatMap((family) => extensionGithubReleaseArtifacts(files, { - id: contrib.artifactProduct, - releaseProduct: product.id, - family, - version: product.version, - })); -} - -function discoverProductArtifactsForSelection(roots, products, selectedProducts) { - const files = [...new Set(roots.flatMap((root) => walkFiles(path.resolve(ROOT, root))))].sort(compareText); - const artifacts = []; - const contrib = contribCarrierDescriptor("publication-lock"); - const hasSelectedExtensionProducts = selectedProducts.some((product) => - EXTENSION_PRODUCT_KINDS.has(product?.kind) - || product?.id === contrib.nativeOwner - || product?.id === contrib.wasixOwner); - for (const product of products) { - if (typeof product?.id !== "string" || typeof product?.version !== "string") { - throw error("product artifact discovery requires canonical product rows with id and version"); - } - if (EXTENSION_PRODUCT_KINDS.has(product.kind)) { - artifacts.push(...extensionGithubReleaseArtifacts(files, product)); - } else { - artifacts.push(...fixedGithubReleaseArtifacts(files, product)); - artifacts.push(...runtimeOwnedExtensionGithubReleaseArtifacts(files, product)); - } - if (product.id === "oliphaunt-swift") { - artifacts.push(...swiftReleaseInputs(files, product, { - requireExtensionFixture: hasSelectedExtensionProducts, - })); - } else if (product.id === "oliphaunt-react-native") { - artifacts.push(...reactNativeReleaseInputs(files, product)); - } - } - const ids = artifacts.map((artifact) => `${artifact.product}:${artifact.id}`); - if (new Set(ids).size !== ids.length) { - throw error("product artifact discovery produced duplicate identities"); - } - return artifacts.sort((left, right) => compareText(`${left.product}:${left.id}`, `${right.product}:${right.id}`)); -} - -export function discoverProductArtifacts(roots, products) { - return discoverProductArtifactsForSelection(roots, products, products); -} - -function sourceIdentity(headRef) { - const commit = commandOutput(["git", "rev-parse", `${headRef}^{commit}`], `resolve ${headRef}`).trim(); - const tree = commandOutput(["git", "show", "-s", "--format=%T", commit], `resolve tree for ${commit}`).trim(); - if (!/^[0-9a-f]{40}$/u.test(commit) || !/^[0-9a-f]{40}$/u.test(tree)) { - throw error(`git returned invalid source identity for ${headRef}`); - } - return { commit, tree }; -} - -export function projectInternalDependencyIds(carriers, dependencies) { - const ids = new Set(carriers.map((carrier) => carrier.id)); - return [...new Set( - dependencies - .map((dependency) => `${dependency.ecosystem}:${dependency.name}`) - .filter((id) => ids.has(id)), - )].sort(compareText); -} - -export function validateCargoPayloadPartSets(carriers) { - const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); - const partsByParent = new Map(); - for (const carrier of carriers) { - if (carrier.role !== "payload-part") { - continue; - } - if (carrier.declared || carrier.ecosystem !== "cargo" || typeof carrier.parentCarrier !== "string") { - throw error(`${carrier.id} has invalid dynamic Cargo payload-part metadata`); - } - const list = partsByParent.get(carrier.parentCarrier) ?? []; - list.push(carrier); - partsByParent.set(carrier.parentCarrier, list); - } - - const parents = new Set(partsByParent.keys()); - for (const carrier of carriers) { - if (carrier.ecosystem !== "cargo" || carrier.role === "payload-part") { - continue; - } - if ((carrier.packageDependencies ?? []).some((dependency) => - dependency.ecosystem === "cargo" && dependency.name.startsWith(`${carrier.name}-part-`) - )) { - parents.add(carrier.id); - } - } - - for (const parentId of [...parents].sort(compareText)) { - const parent = byId.get(parentId); - if (parent === undefined || parent.ecosystem !== "cargo" || !parent.declared) { - throw error(`dynamic Cargo payload parts require their declared parent carrier ${parentId}`); - } - const parts = [...(partsByParent.get(parentId) ?? [])].sort((left, right) => left.part - right.part); - if (parts.length === 0 || parts.length > 999) { - throw error(`${parentId} must have between 1 and 999 Cargo payload parts`); - } - const actualNumbers = parts.map((part) => part.part); - const expectedNumbers = Array.from({ length: parts.length }, (_, index) => index + 1); - if (stableJson(actualNumbers) !== stableJson(expectedNumbers)) { - throw error(`${parentId} Cargo payload parts must be contiguous from part-001; found ${actualNumbers.map((part) => String(part).padStart(3, "0")).join(", ")}`); - } - const actualIds = parts.map((part) => part.id).sort(compareText); - const dependencyIds = (parent.packageDependencies ?? []) - .filter((dependency) => dependency.ecosystem === "cargo" && dependency.name.startsWith(`${parent.name}-part-`)) - .map((dependency) => `cargo:${dependency.name}`) - .sort(compareText); - if (stableJson(actualIds) !== stableJson(dependencyIds)) { - throw error(`${parentId} must depend on exactly its complete Cargo payload part set`); - } - } -} - -function assignPublishOrder(carriers, products) { - const productOrder = new Map(products.map((product, index) => [product.id, index])); - const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); - const remaining = new Set(byId.keys()); - const ordered = []; - const fallbackCompare = (leftId, rightId) => { - const left = byId.get(leftId); - const right = byId.get(rightId); - return (productOrder.get(left.product) ?? 9999) - (productOrder.get(right.product) ?? 9999) - || (ECOSYSTEM_ORDER.get(left.ecosystem) ?? 99) - (ECOSYSTEM_ORDER.get(right.ecosystem) ?? 99) - || (ROLE_ORDER.get(left.role) ?? 99) - (ROLE_ORDER.get(right.role) ?? 99) - || compareText(left.id, right.id); - }; - while (remaining.size > 0) { - const ready = [...remaining] - .filter((id) => byId.get(id).dependencies.every((dependency) => !remaining.has(dependency))) - .sort(fallbackCompare); - if (ready.length === 0) { - throw error(`carrier dependency cycle: ${[...remaining].sort(compareText).join(", ")}`); - } - for (const id of ready) { - ordered.push(id); - remaining.delete(id); - } - } - for (const [index, id] of ordered.entries()) { - byId.get(id).publishOrder = index; - } - return carriers.sort((left, right) => left.publishOrder - right.publishOrder); -} - -function carrierEnvelope(carrier) { - return { - id: carrier.id, - product: carrier.product, - version: carrier.version, - ecosystem: carrier.ecosystem, - name: carrier.name, - role: carrier.role, - target: carrier.target, - declared: carrier.declared, - parentCarrier: carrier.parentCarrier ?? null, - part: carrier.part ?? null, - publishOrder: carrier.publishOrder, - dependencies: carrier.dependencies, - packageDependencies: carrier.packageDependencies, - artifacts: carrier.artifacts.map(({ path: artifactPath, sha256, size }) => ({ - path: artifactPath, - sha256, - size, - })), - }; -} - -function productArtifactEnvelope(artifact) { - return { - id: artifact.id, - product: artifact.product, - role: artifact.role, - kind: artifact.kind, - target: artifact.target, - identity: artifact.identity, - name: artifact.name, - path: artifact.path, - sha256: artifact.sha256, - size: artifact.size, - }; -} - -export function buildPublicationCandidate({ - products, - artifactRoots, - headRef = "HEAD", - allowMissing = false, -} = {}) { - const catalog = loadPublicationCatalog("publication-lock", { products }); - const fullCatalog = loadPublicationCatalog("publication-lock artifact classification"); - const selectedProducts = new Set(catalog.products.map((product) => product.id)); - const artifacts = discoverSelectedPublicationArtifacts( - artifactRoots, - fullCatalog, - selectedProducts, - ); - const productArtifacts = discoverProductArtifacts(artifactRoots, catalog.products); - const carriers = []; - const seenStableIds = new Set(); - for (const artifact of artifacts) { - // Artifact roots may intentionally contain packages for more products than - // this release selected. Classify every identity against the full catalog - // so unknown or ambiguous carriers still fail closed, then project only - // canonical carriers owned by the selected products into the candidate. - const resolved = resolveActualCarrier( - fullCatalog, - artifact.ecosystem, - artifact.name, - "publication-lock artifact classification", - ); - if (!selectedProducts.has(resolved.product)) { - continue; - } - if (artifact.version !== resolved.version) { - throw error(`${artifact.ecosystem}:${artifact.name} artifact version ${artifact.version} does not match ${resolved.product} version ${resolved.version}`); - } - if (resolved.declared) { - seenStableIds.add(resolved.id); - } - carriers.push({ - ...resolved, - dependencies: [], - packageDependencies: artifact.dependencies, - artifacts: artifact.artifacts, - }); - } - const missing = catalog.carriers - .filter((carrier) => !seenStableIds.has(carrier.id)) - .map((carrier) => carrier.id) - .sort(compareText); - if (!allowMissing && missing.length > 0) { - throw error(`artifact set is missing ${missing.length} declared carrier(s): ${missing.join(", ")}`); - } - for (const carrier of carriers) { - carrier.dependencies = projectInternalDependencyIds(carriers, carrier.packageDependencies); - } - validateCargoPayloadPartSets(carriers); - assignPublishOrder(carriers, catalog.products); - const packageEnvelopeDigest = digestValue({ - carriers: carriers.map(carrierEnvelope), - productArtifacts: productArtifacts.map(productArtifactEnvelope), - }); - return { - schema: PUBLICATION_CANDIDATE_SCHEMA, - catalogSchema: PUBLICATION_CATALOG_SCHEMA, - catalogDigest: publicationCatalogDigest(catalog), - source: sourceIdentity(headRef), - products: catalog.products, - carriers, - productArtifacts, - missing, - packageEnvelopeDigest, - }; -} - -function withoutDigest(value) { - const copy = structuredClone(value); - delete copy.lockDigest; - return copy; -} - -export function freezePublicationCandidate(candidate) { - validatePublicationCandidate(candidate); - if (candidate.missing.length > 0) { - throw error(`cannot freeze candidate with missing carriers: ${candidate.missing.join(", ")}`); - } - const frozen = { - ...structuredClone(candidate), - schema: PUBLICATION_LOCK_SCHEMA, - }; - delete frozen.missing; - frozen.lockDigest = digestValue(withoutDigest(frozen)); - return frozen; -} - -function assertHash(value, context) { - if (typeof value !== "string" || !/^[0-9a-f]{64}$/u.test(value)) { - throw error(`${context} must be a lowercase SHA-256 digest`); - } -} - -function assertNonEmptyString(value, context) { - if (typeof value !== "string" || value.length === 0 || /[\0\r\n]/u.test(value)) { - throw error(`${context} must be a non-empty single-line string`); - } -} - -function assertSortedUniqueStrings(value, context) { - if (!Array.isArray(value)) { - throw error(`${context} must be a list`); - } - for (const [index, item] of value.entries()) { - assertNonEmptyString(item, `${context}[${index}]`); - } - const canonical = [...new Set(value)].sort(compareText); - if (stableJson(value) !== stableJson(canonical)) { - throw error(`${context} must be sorted and contain no duplicates`); - } -} - -function validateCandidateCatalog(candidate) { - const requestedProducts = candidate.products.map((product) => product.id); - const catalog = loadPublicationCatalog("publication-lock validation", { products: requestedProducts }); - const expectedDigest = publicationCatalogDigest(catalog); - if (candidate.catalogDigest !== expectedDigest) { - throw error(`candidate catalogDigest mismatch: expected ${expectedDigest}, got ${candidate.catalogDigest}`); - } - if (stableJson(candidate.products) !== stableJson(catalog.products)) { - throw error("candidate products do not exactly match the checked-out publication catalog"); - } - - const presentDeclared = new Set(); - for (const carrier of candidate.carriers) { - const expected = resolveActualCarrier(catalog, carrier.ecosystem, carrier.name, "publication-lock validation"); - const actualIdentity = { - id: carrier.id, - product: carrier.product, - version: carrier.version, - ecosystem: carrier.ecosystem, - name: carrier.name, - role: carrier.role, - target: carrier.target, - declared: carrier.declared, - parentCarrier: carrier.parentCarrier ?? null, - part: carrier.part ?? null, - }; - const expectedIdentity = { - id: expected.id, - product: expected.product, - version: expected.version, - ecosystem: expected.ecosystem, - name: expected.name, - role: expected.role, - target: expected.target, - declared: expected.declared, - parentCarrier: expected.parentCarrier ?? null, - part: expected.part ?? null, - }; - if (stableJson(actualIdentity) !== stableJson(expectedIdentity)) { - throw error(`carrier ${carrier.id} identity metadata does not match the publication catalog`); - } - if (carrier.declared) { - presentDeclared.add(carrier.id); - } - } - const expectedMissing = catalog.carriers - .map((carrier) => carrier.id) - .filter((id) => !presentDeclared.has(id)) - .sort(compareText); - if (stableJson(candidate.missing) !== stableJson(expectedMissing)) { - throw error(`candidate missing carrier set mismatch: expected=${JSON.stringify(expectedMissing)}, actual=${JSON.stringify(candidate.missing)}`); - } -} - -function expectedExtensionMetadataNames(product) { - const family = extensionCarrierFamily(product); - return [ - `${product.id}-${product.version}-manifest.json`, - `${product.id}-${product.version}-manifest.properties`, - ...(family === null || family === "native" - ? [swiftExtensionCarrierAssetName(product.id, product.version)] - : []), - `${product.id}-${product.version}-release-assets.sha256`, - ].sort(compareText); -} - -function validateExtensionProductArtifactInventory(product, artifacts) { - const expectedMetadata = expectedExtensionMetadataNames(product); - const metadata = artifacts - .filter((artifact) => artifact.role === "github-release-metadata") - .map((artifact) => artifact.name) - .sort(compareText); - if (stableJson(expectedMetadata) !== stableJson(metadata)) { - throw error(`${product.id} frozen release metadata set is incomplete or contains extras`); - } - const publicAssets = artifacts.filter((artifact) => artifact.role === "github-release-asset"); - const expectedAssets = new Map(expectedExtensionGithubReleaseAssetRows(product).map((row) => [ - row.name, - row, - ])); - const actualNames = publicAssets.map(({ name }) => name).sort(compareText); - const expectedNames = [...expectedAssets.keys()].sort(compareText); - if (stableJson(expectedNames) !== stableJson(actualNames)) { - throw error(`${product.id} frozen release assets do not cover every declared target role exactly`); - } - for (const artifact of publicAssets) { - const expected = expectedAssets.get(artifact.name); - if ( - expected === undefined - || artifact.target !== expected.target - || artifact.kind !== expected.kind - || artifact.identity !== expected.identity - ) { - throw error(`${product.id} frozen release asset ${artifact.name} has incorrect target, kind, or identity metadata`); - } - } - if (artifacts.length !== metadata.length + publicAssets.length) { - throw error(`${product.id} frozen product artifact inventory contains an unsupported role`); - } -} - -function validateProductArtifactInventory(product, artifacts, { hasSelectedExtensionProducts }) { - if (EXTENSION_PRODUCT_KINDS.has(product.kind)) { - validateExtensionProductArtifactInventory(product, artifacts); - return; - } - - const targets = allArtifactTargets({ - product: product.id, - surface: "github-release", - }, "publication-lock"); - const expected = targets.map((target) => `github-release:${target.asset.replaceAll("{version}", product.version)}`); - if (product.id === "oliphaunt-swift") { - expected.push( - "release-input:Oliphaunt-source.zip", - "release-input:Package.swift.release", - "release-input:extension-owner-catalog.json", - "release-input:extension-resource-inventory.mjs", - "release-input:oliphaunt-react-native-ios-carriers.json", - "release-input:render-extension-products.mjs", - "release-input:swift-carrier-resolver.mjs", - "release-input:swiftpm-release-tree", - ); - if (hasSelectedExtensionProducts) { - expected.push("release-input:swiftpm-extension-consumer-fixture"); - } - } - if (product.id === "oliphaunt-react-native") { - expected.push("release-input:oliphaunt-react-native-ios-carriers.json"); - } - const contrib = contribCarrierDescriptor("publication-lock"); - for (const family of ["native", "wasix"]) { - const owner = family === "native" ? contrib.nativeOwner : contrib.wasixOwner; - if (product.id !== owner) continue; - const extensionProduct = { - id: contrib.artifactProduct, - version: product.version, - releaseProduct: product.id, - family, - }; - const names = [ - ...expectedExtensionMetadataNames(extensionProduct), - ...expectedExtensionGithubReleaseAssetRows(extensionProduct).map((row) => row.name), - ]; - const nameSet = new Set(names); - const extensionArtifacts = artifacts.filter((artifact) => nameSet.has(artifact.name)); - validateExtensionProductArtifactInventory(extensionProduct, extensionArtifacts); - expected.push(...names.map((name) => `github-release:${name}`)); - } - expected.sort(compareText); - const actual = artifacts.map((artifact) => artifact.id).sort(compareText); - if (stableJson(expected) !== stableJson(actual)) { - throw error(`${product.id} frozen product artifact inventory mismatch: expected=${JSON.stringify(expected)}, actual=${JSON.stringify(actual)}`); - } -} - -export function validatePublicationCandidate(candidate) { - requireObject(candidate, "candidate"); - if (candidate.schema !== PUBLICATION_CANDIDATE_SCHEMA) { - throw error(`candidate schema must be ${PUBLICATION_CANDIDATE_SCHEMA}`); - } - if (candidate.catalogSchema !== PUBLICATION_CATALOG_SCHEMA) { - throw error(`candidate catalogSchema must be ${PUBLICATION_CATALOG_SCHEMA}`); - } - assertHash(candidate.catalogDigest, "candidate.catalogDigest"); - assertHash(candidate.packageEnvelopeDigest, "candidate.packageEnvelopeDigest"); - requireObject(candidate.source, "candidate.source"); - if (!/^[0-9a-f]{40}$/u.test(candidate.source.commit) || !/^[0-9a-f]{40}$/u.test(candidate.source.tree)) { - throw error("candidate source must contain full commit and tree SHAs"); - } - if (!Array.isArray(candidate.products) || !Array.isArray(candidate.carriers) || !Array.isArray(candidate.productArtifacts) || !Array.isArray(candidate.missing)) { - throw error("candidate products, carriers, productArtifacts, and missing must be lists"); - } - const products = new Map(); - for (const [index, product] of candidate.products.entries()) { - requireObject(product, `candidate product ${index}`); - assertNonEmptyString(product.id, `candidate product ${index}.id`); - assertNonEmptyString(product.kind, `${product.id}.kind`); - assertNonEmptyString(product.path, `${product.id}.path`); - assertNonEmptyString(product.version, `${product.id}.version`); - assertSortedUniqueStrings(product.publishTargets, `${product.id}.publishTargets`); - assertSortedUniqueStrings(product.dependencies, `${product.id}.dependencies`); - if (products.has(product.id)) { - throw error(`candidate contains duplicate product ${product.id}`); - } - products.set(product.id, product); - } - assertSortedUniqueStrings(candidate.missing, "candidate.missing"); - const identities = new Set(); - for (const carrier of candidate.carriers) { - requireObject(carrier, "candidate carrier"); - assertNonEmptyString(carrier.id, "candidate carrier.id"); - assertNonEmptyString(carrier.product, `${carrier.id}.product`); - assertNonEmptyString(carrier.version, `${carrier.id}.version`); - assertNonEmptyString(carrier.ecosystem, `${carrier.id}.ecosystem`); - assertNonEmptyString(carrier.name, `${carrier.id}.name`); - assertNonEmptyString(carrier.role, `${carrier.id}.role`); - if (!ECOSYSTEM_ORDER.has(carrier.ecosystem)) { - throw error(`${carrier.id} has unsupported ecosystem ${carrier.ecosystem}`); - } - if (!ROLE_ORDER.has(carrier.role)) { - throw error(`${carrier.id} has unsupported role ${carrier.role}`); - } - if (carrier.id !== `${carrier.ecosystem}:${carrier.name}`) { - throw error(`${carrier.id} is not the canonical ${carrier.ecosystem}:${carrier.name} identity`); - } - if (!(carrier.target === null || typeof carrier.target === "string" && carrier.target.length > 0)) { - throw error(`${carrier.id}.target must be null or a non-empty string`); - } - if (typeof carrier.declared !== "boolean") { - throw error(`${carrier.id}.declared must be boolean`); - } - if (!Number.isSafeInteger(carrier.publishOrder) || carrier.publishOrder < 0) { - throw error(`${carrier.id}.publishOrder must be a non-negative safe integer`); - } - if (identities.has(carrier.id)) { - throw error(`candidate contains duplicate carrier ${carrier.id}`); - } - identities.add(carrier.id); - if (!products.has(carrier.product)) { - throw error(`carrier ${carrier.id} refers to unknown product ${carrier.product}`); - } - if (carrier.version !== products.get(carrier.product).version) { - throw error(`carrier ${carrier.id} version does not match product ${carrier.product}`); - } - if (!Array.isArray(carrier.dependencies) || !Array.isArray(carrier.packageDependencies) || !Array.isArray(carrier.artifacts) || carrier.artifacts.length === 0) { - throw error(`carrier ${carrier.id} must contain dependency and artifact lists`); - } - assertSortedUniqueStrings(carrier.dependencies, `${carrier.id}.dependencies`); - for (const [index, dependency] of carrier.packageDependencies.entries()) { - requireObject(dependency, `${carrier.id}.packageDependencies[${index}]`); - assertNonEmptyString(dependency.ecosystem, `${carrier.id}.packageDependencies[${index}].ecosystem`); - assertNonEmptyString(dependency.name, `${carrier.id}.packageDependencies[${index}].name`); - assertNonEmptyString(dependency.requirement, `${carrier.id}.packageDependencies[${index}].requirement`); - assertNonEmptyString(dependency.scope, `${carrier.id}.packageDependencies[${index}].scope`); - if (!ECOSYSTEM_ORDER.has(dependency.ecosystem)) { - throw error(`${carrier.id}.packageDependencies[${index}] has unsupported ecosystem ${dependency.ecosystem}`); - } - } - const artifactPaths = new Set(); - for (const artifact of carrier.artifacts) { - requireObject(artifact, `${carrier.id} artifact`); - assertHash(artifact.sha256, `${carrier.id} artifact sha256`); - if (!Number.isSafeInteger(artifact.size) || artifact.size < 0 || typeof artifact.path !== "string" || artifact.path.length === 0) { - throw error(`${carrier.id} contains invalid artifact metadata`); - } - if (artifactPaths.has(artifact.path)) { - throw error(`${carrier.id} contains duplicate artifact path ${artifact.path}`); - } - artifactPaths.add(artifact.path); - } - } - const publishOrders = candidate.carriers.map((carrier) => carrier.publishOrder); - const expectedPublishOrders = candidate.carriers.map((_, index) => index); - if (stableJson(publishOrders) !== stableJson(expectedPublishOrders)) { - throw error("candidate carriers must be stored in one contiguous, unique publishOrder sequence"); - } - const carrierPosition = new Map(candidate.carriers.map((carrier, index) => [carrier.id, index])); - for (const [index, carrier] of candidate.carriers.entries()) { - const expectedDependencies = projectInternalDependencyIds(candidate.carriers, carrier.packageDependencies); - if (stableJson(carrier.dependencies) !== stableJson(expectedDependencies)) { - throw error(`${carrier.id}.dependencies do not match its internal package dependency identities`); - } - for (const dependency of carrier.dependencies) { - const position = carrierPosition.get(dependency); - if (position === undefined) { - throw error(`${carrier.id} refers to unknown carrier dependency ${dependency}`); - } - if (position >= index) { - throw error(`${carrier.id} publishOrder precedes dependency ${dependency}`); - } - } - } - validateCargoPayloadPartSets(candidate.carriers); - validateCandidateCatalog(candidate); - const productArtifactIds = new Set(); - for (const artifact of candidate.productArtifacts) { - const id = `${artifact.product}:${artifact.id}`; - if (productArtifactIds.has(id) || !products.has(artifact.product)) { - throw error(`candidate contains duplicate or unknown product artifact ${id}`); - } - productArtifactIds.add(id); - if ( - typeof artifact.id !== "string" - || artifact.id.length === 0 - || typeof artifact.role !== "string" - || artifact.role.length === 0 - || typeof artifact.kind !== "string" - || artifact.kind.length === 0 - || !((typeof artifact.target === "string" && artifact.target.length > 0) || artifact.target === null) - || !(artifact.identity === null || typeof artifact.identity === "string" && artifact.identity.length > 0) - || typeof artifact.name !== "string" - || artifact.name.length === 0 - || path.basename(artifact.name) !== artifact.name - ) { - throw error(`${id} contains invalid canonical product artifact metadata`); - } - assertHash(artifact.sha256, `${id} sha256`); - if (!Number.isSafeInteger(artifact.size) || artifact.size < 0 || typeof artifact.path !== "string" || artifact.path.length === 0) { - throw error(`${id} contains invalid artifact metadata`); - } - } - const hasSelectedExtensionProducts = candidate.products.some((product) => - EXTENSION_PRODUCT_KINDS.has(product.kind)); - for (const product of candidate.products) { - validateProductArtifactInventory( - product, - candidate.productArtifacts.filter((artifact) => artifact.product === product.id), - { hasSelectedExtensionProducts }, - ); - } - const expectedEnvelope = digestValue({ - carriers: candidate.carriers.map(carrierEnvelope), - productArtifacts: candidate.productArtifacts.map(productArtifactEnvelope), - }); - if (candidate.packageEnvelopeDigest !== expectedEnvelope) { - throw error(`candidate packageEnvelopeDigest mismatch: expected ${expectedEnvelope}, got ${candidate.packageEnvelopeDigest}`); - } - return candidate; -} - -export function validatePublicationLock(lock) { - requireObject(lock, "publication lock"); - if (lock.schema !== PUBLICATION_LOCK_SCHEMA) { - throw error(`publication lock schema must be ${PUBLICATION_LOCK_SCHEMA}`); - } - const candidate = { ...structuredClone(lock), schema: PUBLICATION_CANDIDATE_SCHEMA, missing: [] }; - delete candidate.lockDigest; - validatePublicationCandidate(candidate); - assertHash(lock.lockDigest, "publication lock lockDigest"); - const expected = digestValue(withoutDigest(lock)); - if (lock.lockDigest !== expected) { - throw error(`publication lock digest mismatch: expected ${expected}, got ${lock.lockDigest}`); - } - return lock; -} - -export function loadPublicationLock(file = DEFAULT_PUBLICATION_LOCK) { - let lock; - try { - lock = JSON.parse(readFileSync(file, "utf8")); - } catch (cause) { - throw error(`cannot read publication lock ${rel(file)}: ${cause.message}`); - } - return validatePublicationLock(lock); -} - -export function assertPublicationLockSource(lock, headRef = "HEAD") { - const source = sourceIdentity(headRef); - if (lock.source.commit !== source.commit || lock.source.tree !== source.tree) { - throw error(`publication lock source ${lock.source.commit}/${lock.source.tree} does not match ${headRef} ${source.commit}/${source.tree}`); - } - return source; -} - -export function lockedCarriers(lock, { product = undefined, products = undefined, ecosystem = undefined } = {}) { - const productSet = products === undefined ? undefined : new Set(products); - return lock.carriers.filter((carrier) => - (product === undefined || carrier.product === product) - && (productSet === undefined || productSet.has(carrier.product)) - && (ecosystem === undefined || carrier.ecosystem === ecosystem)); -} - -function lockedWorkspaceFile(artifact, context) { - const file = path.resolve(ROOT, artifact.path); - const relative = path.relative(ROOT, file); - if (relative === "" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { - throw error(`${context} artifact path must remain inside the repository: ${artifact.path}`); - } - let metadata; - try { - metadata = lstatSync(file); - } catch (cause) { - throw error(`${context} frozen artifact is missing: ${artifact.path}: ${cause.message}`); - } - if (metadata.isSymbolicLink() || !metadata.isFile()) { - throw error(`${context} frozen artifact must be a regular non-symlink file: ${artifact.path}`); - } - if (metadata.size !== artifact.size || sha256File(file) !== artifact.sha256) { - throw error(`${context} frozen artifact bytes do not match the publication lock: ${artifact.path}`); - } - return file; -} - -export function lockedCarrierFiles(lock, ecosystem, name) { - const matches = lockedCarriers(lock, { ecosystem }).filter((carrier) => carrier.name === name); - if (matches.length !== 1) { - throw error(`expected exactly one frozen ${ecosystem}:${name} carrier, found ${matches.length}`); - } - const carrier = matches[0]; - return { - carrier, - files: carrier.artifacts.map((artifact) => ({ - artifact, - file: lockedWorkspaceFile(artifact, carrier.id), - })), - }; -} - -export function lockedCarrierFile(lock, ecosystem, name, suppliedPath = undefined) { - const { carrier, files } = lockedCarrierFiles(lock, ecosystem, name); - if (carrier.artifacts.length !== 1) { - throw error(`${carrier.id} must have exactly one publishable file, found ${carrier.artifacts.length}`); - } - const file = files[0].file; - if (suppliedPath !== undefined && path.resolve(ROOT, suppliedPath) !== file) { - throw error( - `${carrier.id} publisher attempted to substitute ${rel(path.resolve(ROOT, suppliedPath))} for frozen ${carrier.artifacts[0].path}`, - ); - } - return { carrier, file }; -} - -export function lockedCarrierDirectory(lock, ecosystem, name, suppliedPath = undefined) { - const matches = lockedCarriers(lock, { ecosystem }).filter((carrier) => carrier.name === name); - if (matches.length !== 1) { - throw error(`expected exactly one frozen ${ecosystem}:${name} carrier, found ${matches.length}`); - } - const carrier = matches[0]; - if (carrier.artifacts.length !== 1) { - throw error(`${carrier.id} must have exactly one publishable directory, found ${carrier.artifacts.length}`); - } - const artifact = carrier.artifacts[0]; - const directory = path.resolve(ROOT, artifact.path); - const relative = path.relative(ROOT, directory); - if (relative === "" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { - throw error(`${carrier.id} artifact path must remain inside the repository: ${artifact.path}`); - } - let stat; - try { - stat = lstatSync(directory); - } catch (cause) { - throw error(`${carrier.id} frozen directory is missing: ${artifact.path}: ${cause.message}`); - } - if (stat.isSymbolicLink() || !stat.isDirectory()) { - throw error(`${carrier.id} frozen artifact must be a regular non-symlink directory: ${artifact.path}`); - } - const observed = directoryEnvelope(directory); - if (observed.sha256 !== artifact.sha256 || observed.size !== artifact.size) { - throw error(`${carrier.id} frozen directory bytes do not match the publication lock: ${artifact.path}`); - } - if (suppliedPath !== undefined && path.resolve(ROOT, suppliedPath) !== directory) { - throw error(`${carrier.id} publisher attempted to substitute ${rel(path.resolve(ROOT, suppliedPath))} for frozen ${artifact.path}`); - } - return { carrier, directory }; -} - -export function assertLockedIdentitySet(lock, actual, { product, products, ecosystem } = {}) { - const expected = lockedCarriers(lock, { product, products, ecosystem }).map((carrier) => `${carrier.ecosystem}:${carrier.name}@${carrier.version}`).sort(compareText); - const observed = actual.map((item) => `${item.ecosystem ?? ecosystem}:${item.name}@${item.version}`).sort(compareText); - if (stableJson(expected) !== stableJson(observed)) { - throw error(`frozen carrier set mismatch for ${product ?? products?.join(",") ?? "all products"}/${ecosystem ?? "all ecosystems"}: expected=${JSON.stringify(expected)}, actual=${JSON.stringify(observed)}`); - } -} - -export function assertLockedArtifactSet(lock, actual, { product, products, ecosystem } = {}) { - assertLockedIdentitySet(lock, actual, { product, products, ecosystem }); - const expected = new Map(lockedCarriers(lock, { product, products, ecosystem }).map((carrier) => [carrier.id, carrier])); - for (const record of actual) { - const id = `${record.ecosystem}:${record.name}`; - const frozen = expected.get(id); - if (frozen === undefined || !Array.isArray(record.artifacts)) { - throw error(`actual artifact record ${id} is absent from the frozen lock or has no byte envelope`); - } - const frozenBytes = frozen.artifacts.map(({ sha256, size }) => `${sha256}:${size}`).sort(compareText); - const actualBytes = record.artifacts.map(({ sha256, size }) => `${sha256}:${size}`).sort(compareText); - if (stableJson(frozenBytes) !== stableJson(actualBytes)) { - throw error(`frozen artifact bytes mismatch for ${id}: expected=${JSON.stringify(frozenBytes)}, actual=${JSON.stringify(actualBytes)}`); - } - } -} - -export function assertLockedProductArtifacts(lock, product, roots) { - const expected = lock.productArtifacts.filter((artifact) => artifact.product === product); - const productRow = lock.products.find((row) => row.id === product); - if (productRow === undefined) { - throw error(`publication lock does not select product ${product}`); - } - const actual = discoverProductArtifactsForSelection(roots, [productRow], lock.products); - const envelope = (artifacts) => artifacts - .map(({ product: owner, id, role, kind, target, identity, name, sha256, size }) => - `${owner}:${id}:${role}:${kind}:${target ?? ""}:${identity ?? ""}:${name}:${sha256}:${size}`) - .sort(compareText); - if (stableJson(envelope(expected)) !== stableJson(envelope(actual))) { - throw error(`frozen product artifact bytes mismatch for ${product}: expected=${JSON.stringify(envelope(expected))}, actual=${JSON.stringify(envelope(actual))}`); - } -} - -export function lockedProductArtifactPaths(lock, product, { role = undefined, kind = undefined } = {}) { - const selected = lock.productArtifacts.filter((artifact) => - artifact.product === product - && (role === undefined || artifact.role === role) - && (kind === undefined || artifact.kind === kind)); - return selected.map((artifact) => { - const value = path.resolve(ROOT, artifact.path); - const relative = path.relative(ROOT, value); - if (relative === "" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { - throw error(`${product}:${artifact.id} path must remain inside the repository: ${artifact.path}`); - } - let stat; - try { - stat = lstatSync(value); - } catch (cause) { - throw error(`${product}:${artifact.id} is missing: ${artifact.path}: ${cause.message}`); - } - if (stat.isSymbolicLink()) { - throw error(`${product}:${artifact.id} must not be a symlink: ${artifact.path}`); - } - const observed = stat.isFile() - ? { sha256: sha256File(value), size: stat.size } - : stat.isDirectory() - ? directoryEnvelope(value) - : null; - if (observed === null || observed.sha256 !== artifact.sha256 || observed.size !== artifact.size) { - throw error(`${product}:${artifact.id} bytes do not match the publication lock: ${artifact.path}`); - } - return { artifact, path: value, type: stat.isFile() ? "file" : "directory" }; - }); -} - -export function lockedPublicationFiles(lock, { products, workspaceRoot = ROOT } = {}) { - const selected = products === undefined ? lock.products.map(({ id }) => id) : products; - const selectedSet = new Set(selected); - const lockedProducts = lock.products.map(({ id }) => id).sort(compareText); - if ( - selected.length !== selectedSet.size - || stableJson([...selectedSet].sort(compareText)) !== stableJson(lockedProducts) - ) { - throw error("publication file selection must exactly match the lock products"); - } - - const artifacts = [ - ...lockedCarriers(lock, { products: selected }).flatMap((carrier) => - carrier.artifacts.map((artifact) => ({ artifact, context: carrier.id }))), - ...lock.productArtifacts - .filter((artifact) => selectedSet.has(artifact.product)) - .map((artifact) => ({ artifact, context: `${artifact.product}:${artifact.id}` })), - ]; - const files = new Map(); - for (const { artifact, context } of artifacts) { - const value = path.resolve(workspaceRoot, ...artifact.path.split("/")); - const relative = path.relative(path.resolve(workspaceRoot), value); - if (relative === "" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { - throw error(`${context} artifact path must remain inside the workspace: ${artifact.path}`); - } - let metadata; - try { - metadata = lstatSync(value); - } catch (cause) { - throw error(`${context} frozen artifact is missing: ${artifact.path}: ${cause.message}`); - } - if (metadata.isSymbolicLink() || !(metadata.isFile() || metadata.isDirectory())) { - throw error(`${context} frozen artifact must be a regular file or directory: ${artifact.path}`); - } - const observed = metadata.isFile() - ? { sha256: sha256File(value), size: metadata.size } - : directoryEnvelope(value); - if (observed.sha256 !== artifact.sha256 || observed.size !== artifact.size) { - throw error(`${context} frozen artifact bytes do not match the publication lock: ${artifact.path}`); - } - const concrete = metadata.isFile() ? [value] : walkFiles(value, { ignoreBuildDirectories: true }); - for (const file of concrete) { - const filePath = path.relative(workspaceRoot, file).split(path.sep).join("/"); - const envelope = { path: filePath, size: statSync(file).size, sha256: sha256File(file) }; - const prior = files.get(filePath); - if (prior !== undefined && stableJson(prior) !== stableJson(envelope)) { - throw error(`overlapping frozen artifacts disagree for ${filePath}`); - } - files.set(filePath, envelope); - } - } - return [...files.values()].sort((left, right) => compareText(left.path, right.path)); -} - -function parseArgs(argv) { - const command = argv.shift(); - const values = new Map(); - const repeated = new Map(); - const booleans = new Set(); - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--allow-missing") { - booleans.add("allow-missing"); - continue; - } - if (!arg.startsWith("--")) { - throw error(`unexpected positional argument ${arg}`); - } - const separator = arg.indexOf("="); - const key = arg.slice(2, separator === -1 ? undefined : separator); - const value = separator === -1 ? argv[++index] : arg.slice(separator + 1); - if (value === undefined) { - throw error(`--${key} requires a value`); - } - if (key === "artifact-root") { - repeated.set(key, [...(repeated.get(key) ?? []), value]); - } else { - values.set(key, value); - } - } - return { command, values, repeated, booleans }; -} - -function productsFlag(values) { - const raw = values.get("products-json"); - if (raw === undefined) { - return undefined; - } - const value = JSON.parse(raw); - if (!Array.isArray(value) || value.length === 0 || value.some((item) => typeof item !== "string" || item.length === 0)) { - throw error("--products-json must be a non-empty JSON string list"); - } - return value; -} - -function writeJson(file, value) { - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`); -} - -function main(argv) { - const { command, values, repeated, booleans } = parseArgs([...argv]); - if (command === "candidate" || command === "create") { - const candidate = buildPublicationCandidate({ - products: productsFlag(values), - artifactRoots: repeated.get("artifact-root") ?? [], - headRef: values.get("head-ref") ?? "HEAD", - allowMissing: command === "candidate" && booleans.has("allow-missing"), - }); - const output = path.resolve(ROOT, values.get("output") ?? (command === "create" ? DEFAULT_PUBLICATION_LOCK : "target/release/publication-candidate.json")); - const value = command === "create" ? freezePublicationCandidate(candidate) : candidate; - writeJson(output, value); - console.log(`${rel(output)}\t${value.packageEnvelopeDigest}\t${value.lockDigest ?? "candidate"}`); - return; - } - if (command === "freeze") { - const input = path.resolve(ROOT, values.get("candidate") ?? "target/release/publication-candidate.json"); - const candidate = JSON.parse(readFileSync(input, "utf8")); - const lock = freezePublicationCandidate(candidate); - const output = path.resolve(ROOT, values.get("output") ?? DEFAULT_PUBLICATION_LOCK); - writeJson(output, lock); - console.log(`${rel(output)}\t${lock.packageEnvelopeDigest}\t${lock.lockDigest}`); - return; - } - if (command === "verify") { - const file = path.resolve(ROOT, values.get("lock") ?? DEFAULT_PUBLICATION_LOCK); - const lock = loadPublicationLock(file); - assertPublicationLockSource(lock, values.get("head-ref") ?? "HEAD"); - console.log(`${rel(file)} publication lock verified (${lock.carriers.length} carriers, envelope ${lock.packageEnvelopeDigest})`); - return; - } - console.log("usage: tools/release/publication-lock.mjs [--products-json JSON] [--artifact-root PATH ...] [--head-ref REF] [--output PATH] [--allow-missing]"); - process.exit(command === "-h" || command === "--help" ? 0 : 2); -} - -if (import.meta.main) { - try { - main(Bun.argv.slice(2)); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/publication-lock.mts b/tools/release/publication-lock.mts new file mode 100644 index 000000000..1aa73b251 --- /dev/null +++ b/tools/release/publication-lock.mts @@ -0,0 +1,2951 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { + existsSync, + lstatSync, + mkdirSync, + readdirSync, + readFileSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { extensionRuntimeAssetContract } from '../../src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts'; +import { assertWasixExtensionMemberInstall } from '../../src/extensions/contracts/wasix-extension-install.mts'; +import { + extensionCarrierLegalContract, + extensionCarrierLegalFileInventory, +} from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { + buildSwiftExtensionCarrierManifest, + swiftExtensionCarrierAssetName, +} from '../../src/sdks/swift/tools/ios-carrier-manifest.mts'; +import { + validateSelectionNeutralSwiftSourceCarrier, + validateSwiftSourceReleaseContract, +} from '../../src/sdks/swift/tools/swift-source-carrier-contract.mts'; +import { releaseJavaScript } from '../packaging/emit-javascript.mts'; +import { parseMavenArtifactManifest } from '../packaging/maven-artifact-manifest.mts'; +import { validateMavenCentralPublication } from '../packaging/maven-central-contract.mts'; +import { validateNpmTrustedPublishingManifest } from '../packaging/npm-trusted-publishing.mts'; +import { + readFileOnlyTarGzipEntries, + readPortableArchiveEntries, +} from '../packaging/portable-archive.mts'; +import { + loadPublicationCatalog, + PUBLICATION_CATALOG_SCHEMA, + publicationCatalogDigest, + resolveActualCarrier, +} from './publication-catalog.mts'; +import { + allArtifactTargets, + contribCarrierDescriptor, + currentProductVersionSync, + extensionArtifactTargets, + extensionMetadata, + extensionSourceIdentity, + extensionSqlNames, +} from './release-artifact-targets.mts'; +import { compareText, productCompatibilityVersion, ROOT } from './release-graph.mts'; + +export { validateSelectionNeutralSwiftSourceCarrier }; + +export const PUBLICATION_CANDIDATE_SCHEMA = 'oliphaunt-publication-candidate-v1'; +export const PUBLICATION_LOCK_SCHEMA = 'oliphaunt-publication-lock-v1'; +export const DEFAULT_PUBLICATION_LOCK = path.join(ROOT, 'target/release/publication-lock.json'); + +const IGNORED_DIRECTORIES = new Set(['.git', 'node_modules', 'target']); +const EXTENSION_PRODUCT_KINDS = new Set(['exact-extension-artifact', 'exact-extension-bundle']); +const ECOSYSTEM_ORDER = new Map([ + ['cargo', 0], + ['maven', 1], + ['npm', 2], +]); +const ROLE_ORDER = new Map([ + ['payload-part', 0], + ['resource', 1], + ['platform-leaf', 2], + ['aot-leaf', 2], + ['portable-leaf', 2], + ['tool-leaf', 2], + ['plugin', 3], + ['tool-facade', 4], + ['facade', 5], +]); + +function error(message) { + return new Error(`publication-lock: ${message}`); +} + +function requireObject(value, context) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw error(`${context} must be an object`); + } + return value; +} + +function stableJson(value) { + if (Array.isArray(value)) { + return `[${value.map(stableJson).join(',')}]`; + } + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort(compareText) + .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +function canonicalJsonText(value) { + return `${JSON.stringify(canonicalJsonTextValue(value), null, 2)}\n`; +} + +function canonicalJsonTextValue(value) { + if (Array.isArray(value)) return value.map((item) => canonicalJsonTextValue(item)); + if (value !== null && typeof value === 'object') { + return Object.fromEntries( + Object.keys(value) + .sort(compareText) + .map((key) => [key, canonicalJsonTextValue(value[key])]), + ); + } + return value; +} + +function digestValue(value) { + return createHash('sha256').update(stableJson(value)).digest('hex'); +} + +function sha256File(file) { + const hash = createHash('sha256'); + hash.update(readFileSync(file)); + return hash.digest('hex'); +} + +function rel(file) { + const relative = path.relative(ROOT, file); + return relative.startsWith('..') || path.isAbsolute(relative) + ? path.resolve(file).split(path.sep).join('/') + : relative.split(path.sep).join('/'); +} + +function isFile(file) { + try { + return statSync(file).isFile(); + } catch { + return false; + } +} + +function isDirectory(file) { + try { + return statSync(file).isDirectory(); + } catch { + return false; + } +} + +function walkFiles(root, { ignoreBuildDirectories = false } = {}) { + if (isFile(root)) { + return [root]; + } + if (!isDirectory(root)) { + throw error(`artifact root does not exist or is not a file/directory: ${rel(root)}`); + } + const files = []; + const visit = (directory) => { + for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => + compareText(left.name, right.name), + )) { + const fullPath = path.join(directory, entry.name); + if (entry.isSymbolicLink()) { + throw error(`artifact roots must not contain symlinks: ${rel(fullPath)}`); + } + if (entry.isDirectory()) { + if (ignoreBuildDirectories && IGNORED_DIRECTORIES.has(entry.name)) { + continue; + } + visit(fullPath); + } else if (entry.isFile()) { + files.push(fullPath); + } + } + }; + visit(root); + return files; +} + +function archiveMemberText(file, suffix, { exact = false } = {}) { + const entries = [...readPortableArchiveEntries(file).values()].filter( + (entry) => entry.isFile && (exact ? entry.name === suffix : entry.name.endsWith(suffix)), + ); + if (entries.length !== 1) { + throw error(`${rel(file)} must contain exactly one ${suffix}, found ${entries.length}`); + } + return new TextDecoder('utf-8', { fatal: true }).decode(entries[0].data()); +} + +function extensionBundleEntries(file) { + let entries; + try { + entries = readFileOnlyTarGzipEntries(file, { fileMode: 0o644 }); + } catch (cause) { + throw error(`${rel(file)} is not a consumer-compatible tar.gz bundle: ${cause.message}`); + } + return entries; +} + +function safeArchiveMember(value, context) { + if ( + typeof value !== 'string' || + value.length === 0 || + value.includes('\\') || + value.startsWith('/') || + /^[A-Za-z]:/u.test(value) || + /[\u0000-\u001f\u007f]/u.test(value) + ) { + throw error(`${context} must be a safe POSIX archive path`); + } + const parts = value.replace(/^\.\//u, '').split('/'); + if (parts.some((part) => !part || part === '.' || part === '..')) { + throw error(`${context} must be a safe POSIX archive path`); + } + return parts.join('/'); +} + +function dependencyRows(ecosystem, tables) { + const rows = []; + for (const [scope, table] of tables) { + if (table === null || Array.isArray(table) || typeof table !== 'object') { + continue; + } + for (const [name, raw] of Object.entries(table)) { + const requirement = + typeof raw === 'string' + ? raw + : raw !== null && !Array.isArray(raw) && typeof raw === 'object' + ? String(raw.version ?? '*') + : '*'; + rows.push({ ecosystem, name, requirement, scope }); + } + } + return rows.sort((left, right) => + compareText( + `${left.ecosystem}:${left.name}:${left.scope}`, + `${right.ecosystem}:${right.name}:${right.scope}`, + ), + ); +} + +function npmArtifact(file) { + let manifest; + try { + manifest = JSON.parse(archiveMemberText(file, 'package/package.json', { exact: true })); + } catch (cause) { + throw error(`invalid npm tarball ${rel(file)}: ${cause.message}`); + } + if (typeof manifest.name !== 'string' || typeof manifest.version !== 'string') { + throw error(`${rel(file)} npm package manifest must define name and version`); + } + try { + validateNpmTrustedPublishingManifest(manifest, `${rel(file)} package/package.json`); + } catch (cause) { + throw error(cause instanceof Error ? cause.message : String(cause)); + } + return { + ecosystem: 'npm', + name: manifest.name, + version: manifest.version, + dependencies: dependencyRows('npm', [ + ['runtime', manifest.dependencies], + ['optional', manifest.optionalDependencies], + ['peer', manifest.peerDependencies], + ]), + artifacts: [{ path: rel(file), sha256: sha256File(file), size: statSync(file).size }], + }; +} + +function cargoDependencyTables(manifest) { + const tables = [ + ['runtime', manifest.dependencies], + ['build', manifest['build-dependencies']], + ['development', manifest['dev-dependencies']], + ]; + for (const target of Object.values(manifest.target ?? {})) { + if (target !== null && !Array.isArray(target) && typeof target === 'object') { + tables.push(['runtime', target.dependencies], ['build', target['build-dependencies']]); + } + } + return tables; +} + +function cargoArtifact(file) { + let manifest; + try { + manifest = Bun.TOML.parse(archiveMemberText(file, '/Cargo.toml')); + } catch (cause) { + throw error(`invalid Cargo crate ${rel(file)}: ${cause.message}`); + } + if (typeof manifest.package?.name !== 'string' || typeof manifest.package?.version !== 'string') { + throw error(`${rel(file)} Cargo package manifest must define package.name and package.version`); + } + return { + ecosystem: 'cargo', + name: manifest.package.name, + version: manifest.package.version, + dependencies: dependencyRows('cargo', cargoDependencyTables(manifest)), + artifacts: [{ path: rel(file), sha256: sha256File(file), size: statSync(file).size }], + }; +} + +function xmlText(block, tag) { + const match = block.match(new RegExp(`<${tag}>([^<]+)`, 'u')); + return match?.[1]?.trim() ?? null; +} + +function mavenArtifact(file) { + const text = readFileSync(file, 'utf8'); + const prefix = path.basename(file, '.pom'); + const artifactFiles = readdirSync(path.dirname(file)) + .filter( + (entry) => + entry === `${prefix}.pom` || + entry.startsWith(`${prefix}.`) || + entry.startsWith(`${prefix}-`), + ) + .map((entry) => path.join(path.dirname(file), entry)) + .filter(isFile) + .sort(compareText); + const publication = validateMavenCentralPublication({ + pomText: text, + files: artifactFiles.map((artifact) => ({ + name: path.basename(artifact), + size: statSync(artifact).size, + })), + context: rel(file), + }); + const group = publication.groupId; + const name = publication.artifactId; + const version = publication.version; + const dependencies = []; + for (const match of text.matchAll(/([\s\S]*?)<\/dependency>/gu)) { + const dependencyGroup = xmlText(match[1], 'groupId'); + const dependencyName = xmlText(match[1], 'artifactId'); + if (dependencyGroup === null || dependencyName === null) { + continue; + } + dependencies.push({ + ecosystem: 'maven', + name: `${dependencyGroup}:${dependencyName}`, + requirement: xmlText(match[1], 'version') ?? '*', + scope: xmlText(match[1], 'scope') ?? 'runtime', + }); + } + const artifacts = artifactFiles.map((artifact) => ({ + path: rel(artifact), + sha256: sha256File(artifact), + size: statSync(artifact).size, + })); + return { + ecosystem: 'maven', + name: `${group}:${name}`, + version, + dependencies: dependencies.sort((left, right) => compareText(left.name, right.name)), + artifacts, + }; +} + +function mavenManifestArtifacts(file) { + if (!rel(file).includes('/maven-artifacts/')) return []; + return parseMavenArtifactManifest(file).map(({ groupId, artifactId, version, artifact }) => ({ + ecosystem: 'maven', + name: groupId + ':' + artifactId, + version, + dependencies: [], + artifacts: [ + { path: rel(artifact), sha256: sha256File(artifact), size: statSync(artifact).size }, + ], + })); +} + +function directoryEnvelope(directory) { + const files = walkFiles(directory, { ignoreBuildDirectories: true }); + const hash = createHash('sha256'); + let size = 0; + for (const file of files) { + const relative = path.relative(directory, file).split(path.sep).join('/'); + const bytes = readFileSync(file); + hash.update(`${relative}\0${bytes.length}\0`); + hash.update(bytes); + size += bytes.length; + } + return { path: rel(directory), sha256: hash.digest('hex'), size }; +} + +function mergeArtifactRecord(records, record) { + const id = `${record.ecosystem}:${record.name}@${record.version}`; + const existing = records.get(id); + if (existing === undefined) { + records.set(id, record); + return; + } + if (stableJson(existing.dependencies) !== stableJson(record.dependencies)) { + throw error(`duplicate artifact identity ${id} has conflicting dependency metadata`); + } + if (record.ecosystem !== 'maven') { + const variants = new Map( + [...existing.artifacts, ...record.artifacts].map((artifact) => [ + `${artifact.sha256}:${artifact.size}`, + artifact, + ]), + ); + if (variants.size !== 1) { + const candidates = [...existing.artifacts, ...record.artifacts] + .map((artifact) => `${artifact.path} (${artifact.sha256}, ${artifact.size} bytes)`) + .sort(compareText); + throw error( + `duplicate artifact identity ${id} has conflicting candidate bytes: ${candidates.join(', ')}`, + ); + } + existing.artifacts = [[...variants.values()][0], ...existing.artifacts, ...record.artifacts] + .sort((left, right) => compareText(left.path, right.path)) + .slice(0, 1); + return; + } + const byHash = new Map(existing.artifacts.map((artifact) => [artifact.sha256, artifact])); + for (const artifact of record.artifacts) { + const previous = byHash.get(artifact.sha256); + if (previous !== undefined && previous.size !== artifact.size) { + throw error(`duplicate artifact hash ${artifact.sha256} has conflicting sizes`); + } + byHash.set(artifact.sha256, artifact); + } + existing.artifacts = [...byHash.values()].sort((left, right) => + compareText(left.path, right.path), + ); +} + +function discoverPublicationArtifactsMatching(roots, includeRecord) { + if (!Array.isArray(roots) || roots.length === 0) { + throw error('at least one artifact root is required'); + } + const files = [...new Set(roots.flatMap((root) => walkFiles(path.resolve(ROOT, root))))].sort( + compareText, + ); + const records = new Map(); + const mavenPoms = new Set(); + const addRecord = (record) => { + if (includeRecord(record)) { + mergeArtifactRecord(records, record); + } + }; + for (const file of files) { + if (file.endsWith('.tgz')) { + addRecord(npmArtifact(file)); + } else if (file.endsWith('.crate')) { + addRecord(cargoArtifact(file)); + } else if ( + file.endsWith('.pom') && + !file.endsWith('-sources.pom') && + !file.endsWith('-javadoc.pom') + ) { + const record = mavenArtifact(file); + const key = `${record.name}@${record.version}`; + if (!mavenPoms.has(key)) { + mavenPoms.add(key); + addRecord(record); + } + } else if (file.endsWith('.tsv')) { + for (const record of mavenManifestArtifacts(file)) { + addRecord(record); + } + } + } + return [...records.values()].sort((left, right) => + compareText(`${left.ecosystem}:${left.name}`, `${right.ecosystem}:${right.name}`), + ); +} + +export function discoverPublicationArtifacts(roots) { + return discoverPublicationArtifactsMatching(roots, () => true); +} + +function discoverSelectedPublicationArtifacts(roots, fullCatalog, selectedProducts) { + return discoverPublicationArtifactsMatching(roots, (artifact) => { + const resolved = resolveActualCarrier( + fullCatalog, + artifact.ecosystem, + artifact.name, + 'publication-lock artifact classification', + ); + return selectedProducts.has(resolved.product); + }); +} + +function productArtifact({ product, id, role, kind, target = null, identity = null, name, file }) { + return { + id, + product, + role, + kind, + target, + identity, + name, + path: rel(file), + sha256: sha256File(file), + size: statSync(file).size, + }; +} + +function productDirectoryArtifact({ + product, + id, + role, + kind, + target = null, + identity = null, + name, + directory, +}) { + const envelope = directoryEnvelope(directory); + return { + id, + product, + role, + kind, + target, + identity, + name, + path: envelope.path, + sha256: envelope.sha256, + size: envelope.size, + }; +} + +function exactDirectFileSet(directory, expectedNames, context) { + if (!isDirectory(directory)) { + throw error(`${context} release asset directory does not exist: ${rel(directory)}`); + } + const actual = readdirSync(directory, { withFileTypes: true }) + .filter((entry) => entry.isFile()) + .map((entry) => entry.name) + .sort(compareText); + const expected = [...expectedNames].sort(compareText); + if (stableJson(actual) !== stableJson(expected)) { + const expectedSet = new Set(expected); + const actualSet = new Set(actual); + const missing = expected.filter((name) => !actualSet.has(name)); + const extra = actual.filter((name) => !expectedSet.has(name)); + throw error( + `${context} public release asset set mismatch: missing=${JSON.stringify(missing)}, extra=${JSON.stringify(extra)}`, + ); + } +} + +function validateChecksumManifest(file, payloadFiles, context) { + const declared = new Map(); + for (const [index, rawLine] of readFileSync(file, 'utf8').split(/\r?\n/u).entries()) { + if (rawLine.length === 0) { + continue; + } + const match = rawLine.match(/^([0-9a-f]{64}) {2}\.\/([^/\0]+)$/u); + if (match === null) { + throw error(`${context} checksum line ${index + 1} must be ' ./'`); + } + const [, digest, name] = match; + if (declared.has(name)) { + throw error(`${context} checksum manifest declares ${name} more than once`); + } + declared.set(name, digest); + } + const expected = new Map( + payloadFiles.map((payload) => [path.basename(payload), sha256File(payload)]), + ); + const declaredNames = [...declared.keys()].sort(compareText); + const expectedNames = [...expected.keys()].sort(compareText); + if (stableJson(declaredNames) !== stableJson(expectedNames)) { + throw error( + `${context} checksum entries do not exactly cover public payloads: expected=${JSON.stringify(expectedNames)}, actual=${JSON.stringify(declaredNames)}`, + ); + } + for (const [name, digest] of expected) { + if (declared.get(name) !== digest) { + throw error(`${context} checksum for ${name} does not match its frozen bytes`); + } + } +} + +function fixedGithubReleaseArtifacts(files, product) { + const targets = allArtifactTargets( + { + product: product.id, + surface: 'github-release', + }, + 'publication-lock', + ); + if (targets.length === 0) { + return []; + } + const expected = targets.map((target) => ({ + target, + name: target.asset.replaceAll('{version}', product.version), + })); + const matches = new Map(); + for (const row of expected) { + const found = files.filter((file) => path.basename(file) === row.name); + if (found.length !== 1) { + throw error( + `${product.id} requires exactly one public GitHub asset ${row.name}, found ${found.length}`, + ); + } + matches.set(row.name, found[0]); + } + const directories = new Set([...matches.values()].map((file) => path.dirname(file))); + if (directories.size !== 1) { + throw error(`${product.id} public GitHub assets must share one release-assets directory`); + } + const directory = [...directories][0]; + if (path.basename(directory) !== 'release-assets') { + throw error( + `${product.id} public GitHub assets must be staged directly in a release-assets directory, got ${rel(directory)}`, + ); + } + exactDirectFileSet( + directory, + expected.map((row) => row.name), + product.id, + ); + const checksumRows = expected.filter((row) => row.target.kind === 'checksums'); + if (checksumRows.length !== 1) { + throw error( + `${product.id} must declare exactly one canonical GitHub checksum asset, found ${checksumRows.length}`, + ); + } + const checksum = matches.get(checksumRows[0].name); + validateChecksumManifest( + checksum, + expected.filter((row) => row.name !== checksumRows[0].name).map((row) => matches.get(row.name)), + `${product.id}/${checksumRows[0].name}`, + ); + return expected.map(({ target, name }) => + productArtifact({ + product: product.id, + id: `github-release:${name}`, + role: 'github-release-asset', + kind: target.kind, + target: target.target, + name, + file: matches.get(name), + }), + ); +} + +function extensionAssetKindAllowed(family, target, kind) { + if (family === 'wasix') { + return target === 'wasix-portable' && kind === 'wasix-runtime'; + } + if (family !== 'native') { + return false; + } + if (target === 'ios-xcframework') { + return ( + kind === 'runtime' || kind === 'ios-xcframework' || kind === 'ios-dependency-xcframework' + ); + } + if (target.startsWith('android-')) { + return kind === 'runtime'; + } + return kind === 'runtime'; +} + +function parseTsv(file) { + const lines = readFileSync(file, 'utf8') + .split(/\r?\n/u) + .filter((line) => line.length > 0 && !line.startsWith('#')); + const header = lines[0].split('\t'); + return lines.slice(1).map((line) => { + const values = line.split('\t'); + return Object.fromEntries(header.map((column, index) => [column, values[index] ?? ''])); + }); +} + +function exactExtensionIosContract(product, sqlName) { + if (!extensionSqlNames(product, 'publication-lock').includes(sqlName)) { + throw error(`${product} does not own extension SQL name ${sqlName}`); + } + const generated = JSON.parse( + readFileSync(path.join(ROOT, 'src/extensions/generated/sdk/extensions.json'), 'utf8'), + ); + const row = generated.extensions?.find((item) => item?.['sql-name'] === sqlName); + if (row === undefined) { + throw error(`${product} is absent from generated React Native extension metadata`); + } + const nativeModuleStem = + typeof row['native-module-stem'] === 'string' && row['native-module-stem'].length > 0 + ? row['native-module-stem'] + : null; + if (nativeModuleStem === null) { + return { sqlName, nativeModuleStem, dependencies: [], metadata: row }; + } + const staticRows = parseTsv( + path.join(ROOT, 'src/extensions/generated/mobile/static-extensions.tsv'), + ); + const staticRow = staticRows.find((item) => item['sql-name'] === sqlName); + if (staticRow === undefined || staticRow['native-module-stem'] !== nativeModuleStem) { + throw error( + `${product} native module ${nativeModuleStem} is absent from generated mobile static metadata`, + ); + } + const dependencies = (staticRow['ios-static-dependencies'] || '') + .split(',') + .map((value) => value.trim()) + .filter(Boolean) + .sort(compareText); + if (new Set(dependencies).size !== dependencies.length) { + throw error(`${product} generated iOS dependency closure contains duplicates`); + } + return { sqlName, nativeModuleStem, dependencies, metadata: row }; +} + +function extensionRequiredArtifactRows(product) { + const rows = []; + for (const target of extensionArtifactTargets({ product }, 'publication-lock')) { + const sqlName = target.sqlName ?? target.sql_name; + const ios = exactExtensionIosContract(product, sqlName); + if (target.family === 'wasix') { + rows.push({ + sqlName, + family: target.family, + target: target.target, + kind: 'wasix-runtime', + identity: null, + }); + } else if (target.target === 'ios-xcframework') { + rows.push({ + sqlName, + family: target.family, + target: target.target, + kind: 'runtime', + identity: null, + }); + if (ios.nativeModuleStem !== null) { + rows.push({ + sqlName, + family: target.family, + target: target.target, + kind: 'ios-xcframework', + identity: ios.nativeModuleStem, + }); + for (const dependency of ios.dependencies) { + rows.push({ + sqlName, + family: target.family, + target: target.target, + kind: 'ios-dependency-xcframework', + identity: dependency, + }); + } + } + } else if (target.target.startsWith('android-')) { + rows.push({ + sqlName, + family: target.family, + target: target.target, + kind: 'runtime', + identity: null, + }); + } else { + rows.push({ + sqlName, + family: target.family, + target: target.target, + kind: 'runtime', + identity: null, + }); + } + } + return rows.sort((left, right) => + compareText( + `${left.sqlName}:${left.family}:${left.target}:${left.kind}:${left.identity ?? ''}`, + `${right.sqlName}:${right.family}:${right.target}:${right.kind}:${right.identity ?? ''}`, + ), + ); +} + +export function extensionRequiredAssetKeys(product) { + if (extensionSqlNames(product, 'publication-lock').length > 1) { + return extensionBundleCarrierRows(product).map( + ({ family, target }) => `bundle:${family}:${target}`, + ); + } + return extensionRequiredArtifactRows(product).map( + (row) => + `${row.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? '' : `:${row.identity}`}`, + ); +} + +function extensionBundleCarrierRows(product, family = null) { + const groups = new Map(); + for (const row of extensionArtifactTargets({ product }, 'publication-lock')) { + if (family !== null && row.family !== family) continue; + const key = `${row.family}\0${row.target}`; + if (!groups.has(key)) { + groups.set(key, { family: row.family, target: row.target, kind: 'extension-bundle' }); + } + } + return [...groups.values()].sort((left, right) => + compareText(`${left.family}\0${left.target}`, `${right.family}\0${right.target}`), + ); +} + +function extensionPublicationOwner(product) { + return product.releaseProduct ?? product.id; +} + +function extensionCarrierFamily(product) { + return product.family ?? null; +} + +export function expectedExtensionGithubReleaseAssetCount(product) { + // Singleton releases publish each target payload directly. Multi-member + // contrib releases publish one deterministic carrier per family/target; + // exact member locators and checksums remain frozen in the control manifest. + return extensionRequiredAssetKeys(product).length + 4; +} + +function canonicalExtensionAssetName(product, row) { + const prefix = `${product.id}-${product.version}`; + if (row.family === 'wasix') { + return `${prefix}-wasix-portable.tar.zst`; + } + if (row.kind === 'ios-xcframework') { + return `${prefix}-native-ios-xcframework.zip`; + } + if (row.kind === 'ios-dependency-xcframework') { + return `${prefix}-native-ios-dependency-${row.identity}-xcframework.zip`; + } + if (row.target === 'ios-xcframework') { + return `${prefix}-native-ios-runtime.tar.gz`; + } + return `${prefix}-native-${row.target}-runtime.tar.gz`; +} + +function canonicalExtensionBundleAssetName(product, { family, target }) { + return `${product.id}-${product.version}-${family}-${target}-bundle.tar.gz`; +} + +function expectedExtensionGithubReleaseAssetRows(product) { + if (extensionSqlNames(product.id, 'publication-lock').length > 1) { + return extensionBundleCarrierRows(product.id, extensionCarrierFamily(product)).map((row) => ({ + ...row, + identity: row.family, + name: canonicalExtensionBundleAssetName(product, row), + })); + } + return extensionRequiredArtifactRows(product.id).map((row) => ({ + ...row, + name: canonicalExtensionAssetName(product, row), + })); +} + +function exactExtensionManifestRows(product, manifest, manifestPath) { + const expectedSqlNames = extensionSqlNames(product.id, 'publication-lock'); + const metadata = extensionMetadata(product.id, 'publication-lock'); + const family = extensionCarrierFamily(product); + if ( + (manifest.artifactProduct ?? manifest.product) !== product.id || + (manifest.releaseProduct ?? manifest.product) !== extensionPublicationOwner(product) || + (family !== null && manifest.family !== family) || + manifest.version !== product.version || + stableJson(manifest.compatibility) !== stableJson(metadata.compatibility) + ) { + throw error(`${rel(manifestPath)} does not describe ${product.id}@${product.version}`); + } + if (expectedSqlNames.length === 1) { + if ( + manifest.schema !== 'oliphaunt-extension-ci-artifacts-v1' || + !Array.isArray(manifest.assets) + ) { + throw error(`${rel(manifestPath)} must be a singleton exact-extension CI artifact manifest`); + } + return [manifest]; + } + if ( + manifest.schema !== 'oliphaunt-extension-ci-artifacts-v2' || + !Array.isArray(manifest.extensions) + ) { + throw error(`${rel(manifestPath)} must be an exact-extension bundle CI artifact manifest`); + } + const actualSqlNames = manifest.extensions.map((row) => row?.sqlName); + if (stableJson(actualSqlNames) !== stableJson(expectedSqlNames)) { + throw error(`${rel(manifestPath)} must contain the exact sorted bundle member set`); + } + return manifest.extensions; +} + +function validateExtensionManifestRow(product, manifestPath, member) { + const iosContract = exactExtensionIosContract(product.id, member.sqlName); + const stagesIos = + Array.isArray(member.assets) && + member.assets.some((asset) => asset?.target === 'ios-xcframework'); + const iosDependencies = stagesIos ? iosContract.dependencies : []; + const sortedStrings = (value) => + Array.isArray(value) && + value.every((item) => typeof item === 'string' && item.length > 0) && + new Set(value).size === value.length && + stableJson(value) === stableJson([...value].sort(compareText)) + ? value + : null; + if ( + member.nativeModuleStem !== iosContract.nativeModuleStem || + member.createsExtension !== (iosContract.metadata['creates-extension'] !== false) || + stableJson(sortedStrings(member.dependencies)) !== + stableJson( + [...(iosContract.metadata['selected-extension-dependencies'] ?? [])].sort(compareText), + ) || + stableJson(sortedStrings(member.dataFiles)) !== + stableJson([...(iosContract.metadata['runtime-share-data-files'] ?? [])].sort(compareText)) || + stableJson(sortedStrings(member.extensionSqlFileNames)) !== + stableJson([...(iosContract.metadata['extension-sql-file-names'] ?? [])].sort(compareText)) || + stableJson(sortedStrings(member.extensionSqlFilePrefixes)) !== + stableJson( + [...(iosContract.metadata['extension-sql-file-prefixes'] ?? [])].sort(compareText), + ) || + stableJson(sortedStrings(member.sharedPreloadLibraries)) !== + stableJson([...(iosContract.metadata['shared-preload-libraries'] ?? [])].sort(compareText)) || + stableJson(sortedStrings(member.iosNativeDependencies)) !== stableJson(iosDependencies) + ) { + throw error( + `${rel(manifestPath)} ${member.sqlName} semantic extension metadata is not canonical generated metadata`, + ); + } + if (iosContract.nativeModuleStem === null) { + if (member.iosRegistration !== null) { + throw error( + `${rel(manifestPath)} SQL-only extension ${member.sqlName} must not carry iOS registration`, + ); + } + } else if ( + stagesIos && + (member.iosRegistration === null || + Array.isArray(member.iosRegistration) || + typeof member.iosRegistration !== 'object' || + member.iosRegistration.schema !== 'oliphaunt-ios-extension-registration-v1' || + member.iosRegistration.sqlName !== member.sqlName || + member.iosRegistration.nativeModuleStem !== iosContract.nativeModuleStem) + ) { + throw error( + `${rel(manifestPath)} native extension ${member.sqlName} lacks matching build-derived iOS registration`, + ); + } else if (!stagesIos && member.iosRegistration !== null) { + throw error( + `${rel(manifestPath)} native extension ${member.sqlName} claims iOS registration without an iOS carrier`, + ); + } + return iosContract; +} + +function publicExtensionAsset(row) { + return extensionRuntimeAssetContract(row); +} + +function publicExtensionMember(member) { + const wasixInstall = assertWasixExtensionMemberInstall(member, { + label: `${member.sqlName} extension member`, + }); + return { + sqlName: member.sqlName, + createsExtension: member.createsExtension, + dependencies: member.dependencies, + dataFiles: member.dataFiles, + extensionSqlFileNames: member.extensionSqlFileNames, + extensionSqlFilePrefixes: member.extensionSqlFilePrefixes, + nativeModuleStem: member.nativeModuleStem, + iosNativeDependencies: member.iosNativeDependencies, + iosRegistration: member.iosRegistration, + wasixInstall, + sharedPreloadLibraries: member.sharedPreloadLibraries, + assets: member.assets.map(publicExtensionAsset), + }; +} + +function extensionBundleGithubReleaseArtifacts({ + directory, + manifest, + manifestPath, + members, + product, +}) { + const expectedSqlNames = extensionSqlNames(product.id, 'publication-lock'); + const family = extensionCarrierFamily(product); + const expectedGroups = extensionBundleCarrierRows(product.id, family); + if ( + !Array.isArray(manifest.carrierAssets) || + manifest.carrierAssets.length !== expectedGroups.length + ) { + throw error( + `${rel(manifestPath)} must declare exactly ${expectedGroups.length} aggregate carrier assets`, + ); + } + const carriersByGroup = new Map(); + const carriersByName = new Map(); + for (const [index, row] of manifest.carrierAssets.entries()) { + if ( + row === null || + Array.isArray(row) || + typeof row !== 'object' || + row.kind !== 'extension-bundle' || + typeof row.family !== 'string' || + typeof row.target !== 'string' || + typeof row.name !== 'string' || + path.basename(row.name) !== row.name || + typeof row.path !== 'string' || + typeof row.sha256 !== 'string' || + !/^[0-9a-f]{64}$/u.test(row.sha256) || + !Number.isSafeInteger(row.bytes) || + row.bytes <= 0 || + row.memberCount !== expectedSqlNames.length + ) { + throw error(`${rel(manifestPath)} carrierAssets[${index}] is invalid`); + } + const group = `${row.family}\0${row.target}`; + const canonicalName = canonicalExtensionBundleAssetName(product, row); + const file = path.resolve(ROOT, row.path); + if ( + row.name !== canonicalName || + file !== path.join(directory, canonicalName) || + !isFile(file) || + statSync(file).size !== row.bytes || + sha256File(file) !== row.sha256 || + carriersByGroup.has(group) || + carriersByName.has(row.name) + ) { + throw error( + `${rel(manifestPath)} aggregate carrier ${row.name} is non-canonical, duplicated, missing, or byte-skewed`, + ); + } + carriersByGroup.set(group, { row, file, members: [] }); + carriersByName.set(row.name, { row, file, members: [] }); + } + if ( + stableJson([...carriersByGroup.keys()].sort(compareText)) !== + stableJson(expectedGroups.map(({ family, target }) => `${family}\0${target}`).sort(compareText)) + ) { + throw error( + `${product.id} aggregate carriers do not exactly cover every published family/target`, + ); + } + + const logicalRows = new Map(); + for (const member of members) { + const iosContract = validateExtensionManifestRow(product, manifestPath, member); + if (!Array.isArray(member.assets) || member.assets.length === 0) { + throw error( + `${rel(manifestPath)} ${member.sqlName} must declare at least one logical artifact`, + ); + } + for (const row of member.assets) { + if ( + row === null || + Array.isArray(row) || + typeof row !== 'object' || + ![ + row.family, + row.target, + row.kind, + row.name, + row.path, + row.sha256, + row.carrierAsset, + row.carrierRoot, + row.memberPath, + ].every((value) => typeof value === 'string' && value.length > 0) || + !(row.identity === null || (typeof row.identity === 'string' && row.identity.length > 0)) || + !Number.isSafeInteger(row.bytes) || + row.bytes <= 0 || + !/^[0-9a-f]{64}$/u.test(row.sha256) || + path.basename(row.name) !== row.name + ) { + throw error( + `${rel(manifestPath)} ${member.sqlName} contains an invalid bundle member asset row`, + ); + } + if (row.kind === 'ios-dependency-xcframework' && row.identity === null) { + throw error(`${rel(manifestPath)} iOS dependency XCFramework ${row.name} lacks identity`); + } + if (row.kind === 'ios-xcframework' && row.identity !== iosContract.nativeModuleStem) { + throw error( + `${rel(manifestPath)} primary iOS XCFramework identity must be ${iosContract.nativeModuleStem}`, + ); + } + if ( + row.kind !== 'ios-dependency-xcframework' && + row.kind !== 'ios-xcframework' && + row.identity !== null + ) { + throw error( + `${rel(manifestPath)} asset ${row.name} must not carry identity for ${row.kind}`, + ); + } + if (!extensionAssetKindAllowed(row.family, row.target, row.kind)) { + throw error( + `${rel(manifestPath)} contains invalid logical asset role ${member.sqlName}/${row.family}/${row.target}/${row.kind}`, + ); + } + const canonicalName = canonicalExtensionAssetName(product, row); + if (row.name !== canonicalName) { + throw error( + `${rel(manifestPath)} logical asset ${row.name} is not canonical ${canonicalName}`, + ); + } + const logicalFile = path.resolve(ROOT, row.path); + const expectedLogicalFile = path.join( + path.dirname(manifestPath), + 'member-assets', + member.sqlName, + row.name, + ); + if ( + logicalFile !== expectedLogicalFile || + !isFile(logicalFile) || + statSync(logicalFile).size !== row.bytes || + sha256File(logicalFile) !== row.sha256 + ) { + throw error( + `${rel(manifestPath)} logical asset metadata does not match ${rel(expectedLogicalFile)}`, + ); + } + const key = `${member.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? '' : `:${row.identity}`}`; + if (logicalRows.has(key)) + throw error(`${rel(manifestPath)} contains duplicate logical asset role ${key}`); + const carrier = carriersByName.get(row.carrierAsset); + if ( + carrier === undefined || + carrier.row.family !== row.family || + carrier.row.target !== row.target + ) { + throw error( + `${rel(manifestPath)} ${key} references a missing or wrong-family aggregate carrier`, + ); + } + const expectedRoot = carrier.row.name.replace(/\.tar\.gz$/u, ''); + const expectedMemberPath = `extensions/${member.sqlName}/${row.name}`; + if (row.carrierRoot !== expectedRoot || row.memberPath !== expectedMemberPath) { + throw error(`${rel(manifestPath)} ${key} has a non-canonical aggregate member locator`); + } + const manifestMember = { + sqlName: member.sqlName, + kind: row.kind, + identity: row.identity, + path: row.memberPath, + sha256: row.sha256, + bytes: row.bytes, + }; + carrier.members.push({ logicalFile, manifestMember, row }); + logicalRows.set(key, { row, file: logicalFile }); + } + } + const expectedLogicalKeys = extensionRequiredArtifactRows(product.id) + .filter((row) => family === null || row.family === family) + .map( + (row) => + `${row.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? '' : `:${row.identity}`}`, + ); + if (stableJson([...logicalRows.keys()].sort(compareText)) !== stableJson(expectedLogicalKeys)) { + throw error(`${product.id} logical bundle rows do not exactly cover every member target/role`); + } + + for (const { row, file, members: carrierMembers } of carriersByName.values()) { + carrierMembers.sort((left, right) => + compareText( + `${left.manifestMember.sqlName}\0${left.manifestMember.kind}\0${left.manifestMember.identity ?? ''}`, + `${right.manifestMember.sqlName}\0${right.manifestMember.kind}\0${right.manifestMember.identity ?? ''}`, + ), + ); + const manifestMembers = carrierMembers.map(({ manifestMember }) => manifestMember); + const carrierRoot = row.name.replace(/\.tar\.gz$/u, ''); + const bundleManifestPath = `${carrierRoot}/bundle-manifest.json`; + const memberNames = [...new Set(manifestMembers.map((member) => member.sqlName))].sort( + compareText, + ); + if (stableJson(memberNames) !== stableJson(expectedSqlNames)) { + throw error(`${rel(file)} aggregate carrier does not contain every exact bundle member`); + } + const legal = extensionCarrierLegalContract(product.id, memberNames, { + family: row.family, + target: row.target, + }); + const expectedBundleManifest = { + schema: 'oliphaunt-extension-bundle-v1', + product: product.id, + version: product.version, + compatibility: extensionMetadata(product.id, 'publication-lock').compatibility, + family: row.family, + target: row.target, + licenseProfile: legal.profile, + licenseFiles: legal.licenseFiles, + members: manifestMembers, + }; + const entries = extensionBundleEntries(file); + const legalFiles = extensionCarrierLegalFileInventory(product.id, memberNames, { + family: row.family, + target: row.target, + }); + const expectedArchiveFiles = [ + bundleManifestPath, + ...manifestMembers.map((member) => `${carrierRoot}/${member.path}`), + ...legalFiles.map(({ path: legalPath }) => `${carrierRoot}/${legalPath}`), + ].sort(compareText); + const archiveFiles = [...entries.keys()].sort(compareText); + if (stableJson(archiveFiles) !== stableJson(expectedArchiveFiles)) { + throw error(`${rel(file)} contains undeclared or missing regular bundle members`); + } + for (const archiveFile of expectedArchiveFiles) + safeArchiveMember(archiveFile, `${rel(file)} member`); + const manifestEntry = entries.get(bundleManifestPath); + const expectedBundleManifestBytes = Buffer.from(canonicalJsonText(expectedBundleManifest)); + const actualBundleManifestBytes = Buffer.from(manifestEntry.data()); + let bundleManifest; + try { + bundleManifest = JSON.parse(actualBundleManifestBytes.toString('utf8')); + } catch (cause) { + throw error(`${rel(file)} has invalid bundle-manifest.json: ${cause.message}`); + } + if (stableJson(bundleManifest) !== stableJson(expectedBundleManifest)) { + throw error( + `${rel(file)} bundle-manifest.json does not exactly freeze its nested member and legal locators`, + ); + } + if (!actualBundleManifestBytes.equals(expectedBundleManifestBytes)) { + throw error( + `${rel(file)} bundle-manifest.json must use the exact canonical bytes for its nested member and legal locators`, + ); + } + for (const { logicalFile, manifestMember, row: logicalRow } of carrierMembers) { + const archivePath = `${carrierRoot}/${manifestMember.path}`; + const entry = entries.get(archivePath); + const payload = Buffer.from(entry.data()); + if ( + entry.size !== logicalRow.bytes || + payload.length !== logicalRow.bytes || + createHash('sha256').update(payload).digest('hex') !== logicalRow.sha256 || + !payload.equals(readFileSync(logicalFile)) + ) { + throw error( + `${rel(file)} nested payload ${archivePath} does not match its staged logical bytes`, + ); + } + } + for (const legalFile of legalFiles) { + const archivePath = `${carrierRoot}/${legalFile.path}`; + const entry = entries.get(archivePath); + const payload = Buffer.from(entry.data()); + if ( + legalFile.mode !== '0644' || + entry.mode !== 0o644 || + entry.size !== legalFile.bytes || + payload.length !== legalFile.bytes || + createHash('sha256').update(payload).digest('hex') !== legalFile.sha256 + ) { + throw error( + `${rel(file)} legal member ${archivePath} does not match its canonical bytes and mode`, + ); + } + } + } + + const manifestName = `${product.id}-${product.version}-manifest.json`; + const publicManifestFile = path.join(directory, manifestName); + let publicManifest; + try { + publicManifest = JSON.parse(readFileSync(publicManifestFile, 'utf8')); + } catch (cause) { + throw error(`${rel(publicManifestFile)} is invalid JSON: ${cause.message}`); + } + const metadata = extensionMetadata(product.id, 'publication-lock'); + const expectedPublicManifest = { + schema: 'oliphaunt-extension-release-manifest-v2', + product: product.id, + ...(manifest.releaseProduct === undefined + ? {} + : { + releaseProduct: extensionPublicationOwner(product), + family: family ?? 'combined', + }), + version: product.version, + extensionClass: metadata.class, + versioning: metadata.versioning, + sourceIdentity: extensionSourceIdentity(product.id, 'publication-lock'), + compatibility: metadata.compatibility, + extensions: members.map(publicExtensionMember), + assets: [...carriersByName.values()] + .map(({ row }) => publicExtensionAsset(row)) + .sort((left, right) => compareText(left.name, right.name)), + }; + if (stableJson(publicManifest) !== stableJson(expectedPublicManifest)) { + throw error( + `${rel(publicManifestFile)} does not exactly expose the frozen aggregate member/carrier inventory`, + ); + } + + const includeSwiftCarrier = family === null || family === 'native'; + const swiftCarrierName = includeSwiftCarrier + ? swiftExtensionCarrierAssetName(product.id, product.version) + : null; + if (swiftCarrierName !== null) { + const swiftCarrierFile = path.join(directory, swiftCarrierName); + let actualSwiftCarrier; + try { + actualSwiftCarrier = JSON.parse(readFileSync(swiftCarrierFile, 'utf8')); + } catch (cause) { + throw error(`invalid Swift iOS carrier ${rel(swiftCarrierFile)}: ${cause.message}`); + } + const expectedSwiftCarrier = buildSwiftExtensionCarrierManifest({ + extensionManifest: manifestPath, + nativeRuntimeVersion: extensionMetadata(product.id, 'publication-lock').compatibility + .nativeRuntimeVersion, + verifyMembers: false, + }); + if (stableJson(actualSwiftCarrier) !== stableJson(expectedSwiftCarrier)) { + throw error( + `${rel(swiftCarrierFile)} does not exactly describe ${product.id} and its compatible native base`, + ); + } + } + const controlFiles = [ + ['manifest-json', manifestName], + ['manifest-properties', `${product.id}-${product.version}-manifest.properties`], + ...(swiftCarrierName === null ? [] : [['swift-extension-carrier', swiftCarrierName]]), + ['checksums', `${product.id}-${product.version}-release-assets.sha256`], + ]; + const expectedNames = [...[...carriersByName.keys()], ...controlFiles.map(([, name]) => name)]; + exactDirectFileSet(directory, expectedNames, product.id); + const checksumName = controlFiles.find(([kind]) => kind === 'checksums')[1]; + validateChecksumManifest( + path.join(directory, checksumName), + expectedNames.filter((name) => name !== checksumName).map((name) => path.join(directory, name)), + `${product.id}/${checksumName}`, + ); + return [ + ...[...carriersByName.values()].map(({ row, file }) => + productArtifact({ + product: extensionPublicationOwner(product), + id: `github-release:${row.name}`, + role: 'github-release-asset', + kind: row.kind, + target: row.target, + identity: row.family, + name: row.name, + file, + }), + ), + ...controlFiles.map(([kind, name]) => + productArtifact({ + product: extensionPublicationOwner(product), + id: `github-release:${name}`, + role: 'github-release-metadata', + kind, + target: 'portable', + name, + file: path.join(directory, name), + }), + ), + ]; +} + +function extensionGithubReleaseArtifacts(files, product) { + const candidates = files.filter((file) => path.basename(file) === 'extension-artifacts.json'); + const manifests = []; + for (const file of candidates) { + let value; + try { + value = JSON.parse(readFileSync(file, 'utf8')); + } catch (cause) { + throw error(`invalid extension artifact manifest ${rel(file)}: ${cause.message}`); + } + if ( + (value?.artifactProduct ?? value?.product) === product.id && + (value?.releaseProduct ?? value?.product) === extensionPublicationOwner(product) && + (extensionCarrierFamily(product) === null || + value?.family === extensionCarrierFamily(product)) + ) { + manifests.push([file, value]); + } + } + if (manifests.length !== 1) { + throw error( + `${product.id} requires exactly one extension-artifacts.json in the staged roots, found ${manifests.length}`, + ); + } + const [manifestPath, manifest] = manifests[0]; + const members = exactExtensionManifestRows(product, manifest, manifestPath); + const directory = path.join(path.dirname(manifestPath), 'release-assets'); + if (members.length > 1) { + return extensionBundleGithubReleaseArtifacts({ + directory, + manifest, + manifestPath, + members, + product, + }); + } + const rows = new Map(); + for (const member of members) { + const iosContract = validateExtensionManifestRow(product, manifestPath, member); + if (!Array.isArray(member.assets) || member.assets.length === 0) { + throw error(`${rel(manifestPath)} ${member.sqlName} must declare at least one artifact`); + } + for (const row of member.assets) { + if ( + row === null || + Array.isArray(row) || + typeof row !== 'object' || + ![row.family, row.target, row.kind, row.name, row.path, row.sha256].every( + (value) => typeof value === 'string' && value.length > 0, + ) || + !(row.identity === null || (typeof row.identity === 'string' && row.identity.length > 0)) || + !Number.isSafeInteger(row.bytes) || + row.bytes <= 0 || + !/^[0-9a-f]{64}$/u.test(row.sha256) || + path.basename(row.name) !== row.name + ) { + throw error( + `${rel(manifestPath)} ${member.sqlName} contains an invalid public extension asset row`, + ); + } + if (row.kind === 'ios-dependency-xcframework' && row.identity === null) { + throw error(`${rel(manifestPath)} iOS dependency XCFramework ${row.name} lacks identity`); + } + if (row.kind === 'ios-xcframework' && row.identity !== iosContract.nativeModuleStem) { + throw error( + `${rel(manifestPath)} primary iOS XCFramework identity must be ${iosContract.nativeModuleStem}`, + ); + } + if ( + row.kind !== 'ios-dependency-xcframework' && + row.kind !== 'ios-xcframework' && + row.identity !== null + ) { + throw error( + `${rel(manifestPath)} asset ${row.name} must not carry identity for ${row.kind}`, + ); + } + const key = `${member.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? '' : `:${row.identity}`}`; + if (rows.has(key)) { + throw error(`${rel(manifestPath)} contains duplicate extension asset role ${key}`); + } + if (!extensionAssetKindAllowed(row.family, row.target, row.kind)) { + throw error(`${rel(manifestPath)} contains invalid extension asset role ${key}`); + } + const canonicalName = canonicalExtensionAssetName(product, { + ...row, + sqlName: member.sqlName, + }); + if (row.name !== canonicalName) { + throw error( + `${rel(manifestPath)} asset ${row.name} is not the canonical name ${canonicalName}`, + ); + } + const file = path.resolve(ROOT, row.path); + if (file !== path.join(directory, row.name) || !isFile(file)) { + throw error( + `${rel(manifestPath)} asset ${row.name} must exist directly under ${rel(directory)}`, + ); + } + if (statSync(file).size !== row.bytes || sha256File(file) !== row.sha256) { + throw error(`${rel(manifestPath)} asset metadata does not match ${rel(file)}`); + } + rows.set(key, { row, file, sqlName: member.sqlName }); + } + } + const family = extensionCarrierFamily(product); + const expectedKeys = extensionRequiredArtifactRows(product.id) + .filter((row) => family === null || row.family === family) + .map( + (row) => + `${row.sqlName}:${row.family}:${row.target}:${row.kind}${row.identity === null ? '' : `:${row.identity}`}`, + ) + .sort(compareText); + const actualKeys = [...rows.keys()].sort(compareText); + if (stableJson(expectedKeys) !== stableJson(actualKeys)) { + throw error( + `${product.id} extension asset roles do not exactly cover declared targets: expected=${JSON.stringify(expectedKeys)}, actual=${JSON.stringify(actualKeys)}`, + ); + } + const publicManifestFile = path.join(directory, `${product.id}-${product.version}-manifest.json`); + let publicManifest; + try { + publicManifest = JSON.parse(readFileSync(publicManifestFile, 'utf8')); + } catch (cause) { + throw error(`${rel(publicManifestFile)} is invalid JSON: ${cause.message}`); + } + const metadata = extensionMetadata(product.id, 'publication-lock'); + const publicMember = publicExtensionMember(members[0]); + const expectedPublicManifest = { + schema: 'oliphaunt-extension-release-manifest-v1', + product: product.id, + ...(manifest.releaseProduct === undefined + ? {} + : { + releaseProduct: extensionPublicationOwner(product), + family: family ?? 'combined', + }), + version: product.version, + sqlName: publicMember.sqlName, + extensionClass: metadata.class, + versioning: metadata.versioning, + sourceIdentity: extensionSourceIdentity(product.id, 'publication-lock'), + compatibility: metadata.compatibility, + createsExtension: publicMember.createsExtension, + dependencies: publicMember.dependencies, + dataFiles: publicMember.dataFiles, + extensionSqlFileNames: publicMember.extensionSqlFileNames, + extensionSqlFilePrefixes: publicMember.extensionSqlFilePrefixes, + nativeModuleStem: publicMember.nativeModuleStem, + iosNativeDependencies: publicMember.iosNativeDependencies, + iosRegistration: publicMember.iosRegistration, + wasixInstall: publicMember.wasixInstall, + sharedPreloadLibraries: publicMember.sharedPreloadLibraries, + assets: publicMember.assets, + }; + if (stableJson(publicManifest) !== stableJson(expectedPublicManifest)) { + throw error( + `${rel(publicManifestFile)} does not exactly expose the canonical extension identity and frozen asset inventory`, + ); + } + const includeSwiftCarrier = family === null || family === 'native'; + const swiftCarrierName = includeSwiftCarrier + ? swiftExtensionCarrierAssetName(product.id, product.version) + : null; + if (swiftCarrierName !== null) { + const swiftCarrierFile = path.join(directory, swiftCarrierName); + if (!isFile(swiftCarrierFile)) { + throw error( + `${product.id} requires independently consumable Swift iOS carrier ${swiftCarrierName}`, + ); + } + let actualSwiftCarrier; + try { + actualSwiftCarrier = JSON.parse(readFileSync(swiftCarrierFile, 'utf8')); + } catch (cause) { + throw error(`invalid Swift iOS carrier ${rel(swiftCarrierFile)}: ${cause.message}`); + } + const expectedSwiftCarrier = buildSwiftExtensionCarrierManifest({ + extensionManifest: manifestPath, + nativeRuntimeVersion: extensionMetadata(product.id, 'publication-lock').compatibility + .nativeRuntimeVersion, + verifyMembers: false, + }); + if (stableJson(actualSwiftCarrier) !== stableJson(expectedSwiftCarrier)) { + throw error( + `${rel(swiftCarrierFile)} does not exactly describe ${product.id} and its compatible native base`, + ); + } + } + const controlFiles = [ + ['manifest-json', `${product.id}-${product.version}-manifest.json`], + ['manifest-properties', `${product.id}-${product.version}-manifest.properties`], + ...(swiftCarrierName === null ? [] : [['swift-extension-carrier', swiftCarrierName]]), + ['checksums', `${product.id}-${product.version}-release-assets.sha256`], + ]; + const expectedNames = [ + ...[...rows.values()].map(({ row }) => row.name), + ...controlFiles.map(([, name]) => name), + ]; + if (new Set(expectedNames).size !== expectedNames.length) { + throw error(`${product.id} extension release assets contain duplicate public basenames`); + } + exactDirectFileSet(directory, expectedNames, product.id); + const checksumName = controlFiles.find(([kind]) => kind === 'checksums')[1]; + const checksum = path.join(directory, checksumName); + validateChecksumManifest( + checksum, + expectedNames.filter((name) => name !== checksumName).map((name) => path.join(directory, name)), + `${product.id}/${checksumName}`, + ); + return [ + ...[...rows.values()].map(({ row, file }) => + productArtifact({ + product: extensionPublicationOwner(product), + id: `github-release:${row.name}`, + role: 'github-release-asset', + kind: row.kind, + target: row.target, + identity: row.identity, + name: row.name, + file, + }), + ), + ...controlFiles.map(([kind, name]) => + productArtifact({ + product: extensionPublicationOwner(product), + id: `github-release:${name}`, + role: 'github-release-metadata', + kind, + target: 'portable', + name, + file: path.join(directory, name), + }), + ), + ]; +} + +function swiftReleaseInputs(files, product, { requireExtensionFixture }) { + const expectedFiles = [ + ['Oliphaunt-source.zip', 'swiftpm-source-archive'], + ['Package.swift.release', 'swiftpm-release-manifest'], + ['extension-owner-catalog.json', 'swiftpm-extension-owner-catalog'], + ['extension-resource-inventory.mjs', 'swiftpm-extension-resource-inventory'], + ['render-extension-products.mjs', 'swiftpm-extension-generator'], + ['swift-carrier-resolver.mjs', 'swiftpm-carrier-resolver'], + ]; + const artifacts = expectedFiles.map(([name, kind]) => { + const generatorInput = !['Oliphaunt-source.zip', 'Package.swift.release'].includes(name); + const matches = files.filter( + (file) => + path.basename(file) === name && + (!generatorInput || rel(file).includes('/extension-generator/')), + ); + if (matches.length !== 1) { + throw error( + `${product.id} requires exactly one ${name} in the staged artifact roots, found ${matches.length}`, + ); + } + return productArtifact({ + product: product.id, + id: `release-input:${name}`, + role: 'release-input', + kind, + target: 'portable', + name, + file: matches[0], + }); + }); + const ownerCatalogArtifact = artifacts.find( + ({ kind }) => kind === 'swiftpm-extension-owner-catalog', + ); + const canonicalOwnerCatalog = path.join(ROOT, 'src/extensions/generated/sdk/extensions.json'); + if ( + ownerCatalogArtifact === undefined || + !readFileSync(path.resolve(ROOT, ownerCatalogArtifact.path)).equals( + readFileSync(canonicalOwnerCatalog), + ) + ) { + throw error( + `${product.id} frozen extension-owner-catalog.json must exactly match src/extensions/generated/sdk/extensions.json`, + ); + } + const resourceInventoryArtifact = artifacts.find( + ({ kind }) => kind === 'swiftpm-extension-resource-inventory', + ); + const canonicalResourceInventory = path.join( + ROOT, + 'src/sdks/swift/tools/extension-resource-inventory.mts', + ); + if ( + resourceInventoryArtifact === undefined || + !readFileSync(path.resolve(ROOT, resourceInventoryArtifact.path)).equals( + releaseJavaScript(canonicalResourceInventory), + ) + ) { + throw error( + `${product.id} frozen extension-resource-inventory.mjs must exactly match src/sdks/swift/tools/extension-resource-inventory.mjs`, + ); + } + const carrierName = 'oliphaunt-react-native-ios-carriers.json'; + const carrierMatches = files.filter( + (file) => + path.basename(file) === carrierName && + rel(file).includes('/release-tree/src/sdks/swift/Carriers/'), + ); + if (carrierMatches.length !== 1) { + throw error( + `${product.id} requires exactly one source-tag carrier ${carrierName}, found ${carrierMatches.length}`, + ); + } + const carrierFile = carrierMatches[0]; + artifacts.push( + productArtifact({ + product: product.id, + id: `release-input:${carrierName}`, + role: 'release-input', + kind: 'swiftpm-ios-carrier-manifest', + target: 'portable', + name: carrierName, + file: carrierFile, + }), + ); + const releaseTree = path.join(path.dirname(carrierFile), '../../../..'); + artifacts.push( + productDirectoryArtifact({ + product: product.id, + id: 'release-input:swiftpm-release-tree', + role: 'release-input', + kind: 'swiftpm-release-tree', + target: 'portable', + name: 'release-tree', + directory: path.resolve(releaseTree), + }), + ); + let carrier; + try { + carrier = JSON.parse(readFileSync(carrierFile, 'utf8')); + } catch (cause) { + throw error(`${rel(carrierFile)} is not valid JSON: ${cause.message}`); + } + try { + validateSelectionNeutralSwiftSourceCarrier(carrier, rel(carrierFile)); + const manifestArtifact = artifacts.find(({ kind }) => kind === 'swiftpm-release-manifest'); + if (manifestArtifact === undefined) { + throw new Error(`${product.id} is missing its frozen Package.swift.release artifact`); + } + validateSwiftSourceReleaseContract({ + carrier, + expectedNativeVersion: productCompatibilityVersion( + 'oliphaunt-swift', + 'liboliphaunt-native', + 'publication-lock', + ), + label: `${product.id} frozen source release`, + manifestText: readFileSync(path.resolve(ROOT, manifestArtifact.path), 'utf8'), + }); + } catch (cause) { + throw error(cause instanceof Error ? cause.message : String(cause)); + } + const fixtureManifests = files.filter( + (file) => + path.basename(file) === 'extension-products.json' && + (rel(file).startsWith('target/release/swiftpm-extension-consumer-fixture/') || + rel(file).includes('/release/swiftpm-extension-consumer-fixture/')), + ); + const expectedFixtureCount = requireExtensionFixture ? 1 : 0; + if (fixtureManifests.length !== expectedFixtureCount) { + const selection = requireExtensionFixture + ? 'selects extension products and requires exactly one' + : 'selects no extension products and requires no'; + throw error( + `${product.id} ${selection} frozen Swift consumer fixture, found ${fixtureManifests.length}`, + ); + } + if (requireExtensionFixture) { + const fixture = path.dirname(fixtureManifests[0]); + if (!isFile(path.join(fixture, 'Package.swift'))) { + throw error(`${rel(fixture)} is missing generated Package.swift`); + } + artifacts.push( + productDirectoryArtifact({ + product: product.id, + id: 'release-input:swiftpm-extension-consumer-fixture', + role: 'release-input', + kind: 'swiftpm-extension-consumer-fixture', + target: 'portable', + name: 'swiftpm-extension-consumer-fixture', + directory: fixture, + }), + ); + } + return artifacts; +} + +function reactNativeReleaseInputs(files, product) { + const name = 'oliphaunt-react-native-ios-carriers.json'; + const matches = files.filter( + (file) => + path.basename(file) === name && + (rel(file).startsWith('target/release/ios-carriers/') || + rel(file).includes('/release/ios-carriers/')), + ); + if (matches.length !== 1) { + throw error( + `${product.id} requires exactly one canonical aggregate iOS carrier manifest, found ${matches.length}`, + ); + } + return [ + productArtifact({ + product: product.id, + id: `release-input:${name}`, + role: 'release-input', + kind: 'react-native-ios-carrier-manifest', + target: 'portable', + name, + file: matches[0], + }), + ]; +} + +function runtimeOwnedExtensionGithubReleaseArtifacts(files, product) { + const contrib = contribCarrierDescriptor('publication-lock'); + const families = [ + ...(product.id === contrib.nativeOwner ? ['native'] : []), + ...(product.id === contrib.wasixOwner ? ['wasix'] : []), + ]; + return families.flatMap((family) => + extensionGithubReleaseArtifacts(files, { + id: contrib.artifactProduct, + releaseProduct: product.id, + family, + version: product.version, + }), + ); +} + +function discoverProductArtifactsForSelection(roots, products, selectedProducts) { + const files = [...new Set(roots.flatMap((root) => walkFiles(path.resolve(ROOT, root))))].sort( + compareText, + ); + const artifacts = []; + const contrib = contribCarrierDescriptor('publication-lock'); + const hasSelectedExtensionProducts = selectedProducts.some( + (product) => + EXTENSION_PRODUCT_KINDS.has(product?.kind) || + product?.id === contrib.nativeOwner || + product?.id === contrib.wasixOwner, + ); + for (const product of products) { + if (typeof product?.id !== 'string' || typeof product?.version !== 'string') { + throw error('product artifact discovery requires canonical product rows with id and version'); + } + if (EXTENSION_PRODUCT_KINDS.has(product.kind)) { + artifacts.push(...extensionGithubReleaseArtifacts(files, product)); + } else { + artifacts.push(...fixedGithubReleaseArtifacts(files, product)); + artifacts.push(...runtimeOwnedExtensionGithubReleaseArtifacts(files, product)); + } + if (product.id === 'oliphaunt-swift') { + artifacts.push( + ...swiftReleaseInputs(files, product, { + requireExtensionFixture: hasSelectedExtensionProducts, + }), + ); + } else if (product.id === 'oliphaunt-react-native') { + artifacts.push(...reactNativeReleaseInputs(files, product)); + } + } + const ids = artifacts.map((artifact) => `${artifact.product}:${artifact.id}`); + if (new Set(ids).size !== ids.length) { + throw error('product artifact discovery produced duplicate identities'); + } + return artifacts.sort((left, right) => + compareText(`${left.product}:${left.id}`, `${right.product}:${right.id}`), + ); +} + +export function discoverProductArtifacts(roots, products) { + return discoverProductArtifactsForSelection(roots, products, products); +} + +function sourceIdentity(headRef) { + const snapshot = JSON.parse(process.env.OLIPHAUNT_GIT_SOURCE_JSON || '{}'); + if ( + ![snapshot.commit, snapshot.tree, snapshot.checkout].every((value) => + /^[0-9a-f]{40}$/u.test(value ?? ''), + ) || + !( + headRef === snapshot.ref || + headRef === snapshot.commit || + (headRef === 'HEAD' && snapshot.checkout === snapshot.commit) + ) + ) { + throw error( + 'source identity for ' + + headRef + + ' requires a matching Git snapshot from bash tools/release/with-source.sh', + ); + } + return { commit: snapshot.commit, tree: snapshot.tree }; +} + +export function projectInternalDependencyIds(carriers, dependencies) { + const ids = new Set(carriers.map((carrier) => carrier.id)); + return [ + ...new Set( + dependencies + .map((dependency) => `${dependency.ecosystem}:${dependency.name}`) + .filter((id) => ids.has(id)), + ), + ].sort(compareText); +} + +export function validateCargoPayloadPartSets(carriers) { + const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); + const partsByParent = new Map(); + for (const carrier of carriers) { + if (carrier.role !== 'payload-part') { + continue; + } + if ( + carrier.declared || + carrier.ecosystem !== 'cargo' || + typeof carrier.parentCarrier !== 'string' + ) { + throw error(`${carrier.id} has invalid dynamic Cargo payload-part metadata`); + } + const list = partsByParent.get(carrier.parentCarrier) ?? []; + list.push(carrier); + partsByParent.set(carrier.parentCarrier, list); + } + + const parents = new Set(partsByParent.keys()); + for (const carrier of carriers) { + if (carrier.ecosystem !== 'cargo' || carrier.role === 'payload-part') { + continue; + } + if ( + (carrier.packageDependencies ?? []).some( + (dependency) => + dependency.ecosystem === 'cargo' && dependency.name.startsWith(`${carrier.name}-part-`), + ) + ) { + parents.add(carrier.id); + } + } + + for (const parentId of [...parents].sort(compareText)) { + const parent = byId.get(parentId); + if (parent === undefined || parent.ecosystem !== 'cargo' || !parent.declared) { + throw error(`dynamic Cargo payload parts require their declared parent carrier ${parentId}`); + } + const parts = [...(partsByParent.get(parentId) ?? [])].sort( + (left, right) => left.part - right.part, + ); + if (parts.length === 0 || parts.length > 999) { + throw error(`${parentId} must have between 1 and 999 Cargo payload parts`); + } + const actualNumbers = parts.map((part) => part.part); + const expectedNumbers = Array.from({ length: parts.length }, (_, index) => index + 1); + if (stableJson(actualNumbers) !== stableJson(expectedNumbers)) { + throw error( + `${parentId} Cargo payload parts must be contiguous from part-001; found ${actualNumbers.map((part) => String(part).padStart(3, '0')).join(', ')}`, + ); + } + const actualIds = parts.map((part) => part.id).sort(compareText); + const dependencyIds = (parent.packageDependencies ?? []) + .filter( + (dependency) => + dependency.ecosystem === 'cargo' && dependency.name.startsWith(`${parent.name}-part-`), + ) + .map((dependency) => `cargo:${dependency.name}`) + .sort(compareText); + if (stableJson(actualIds) !== stableJson(dependencyIds)) { + throw error(`${parentId} must depend on exactly its complete Cargo payload part set`); + } + } +} + +function assignPublishOrder(carriers, products) { + const productOrder = new Map(products.map((product, index) => [product.id, index])); + const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); + const remaining = new Set(byId.keys()); + const ordered = []; + const fallbackCompare = (leftId, rightId) => { + const left = byId.get(leftId); + const right = byId.get(rightId); + return ( + (productOrder.get(left.product) ?? 9999) - (productOrder.get(right.product) ?? 9999) || + (ECOSYSTEM_ORDER.get(left.ecosystem) ?? 99) - (ECOSYSTEM_ORDER.get(right.ecosystem) ?? 99) || + (ROLE_ORDER.get(left.role) ?? 99) - (ROLE_ORDER.get(right.role) ?? 99) || + compareText(left.id, right.id) + ); + }; + while (remaining.size > 0) { + const ready = [...remaining] + .filter((id) => byId.get(id).dependencies.every((dependency) => !remaining.has(dependency))) + .sort(fallbackCompare); + if (ready.length === 0) { + throw error(`carrier dependency cycle: ${[...remaining].sort(compareText).join(', ')}`); + } + for (const id of ready) { + ordered.push(id); + remaining.delete(id); + } + } + for (const [index, id] of ordered.entries()) { + byId.get(id).publishOrder = index; + } + return carriers.sort((left, right) => left.publishOrder - right.publishOrder); +} + +function carrierEnvelope(carrier) { + return { + id: carrier.id, + product: carrier.product, + version: carrier.version, + ecosystem: carrier.ecosystem, + name: carrier.name, + role: carrier.role, + target: carrier.target, + declared: carrier.declared, + parentCarrier: carrier.parentCarrier ?? null, + part: carrier.part ?? null, + publishOrder: carrier.publishOrder, + dependencies: carrier.dependencies, + packageDependencies: carrier.packageDependencies, + artifacts: carrier.artifacts.map(({ path: artifactPath, sha256, size }) => ({ + path: artifactPath, + sha256, + size, + })), + }; +} + +function productArtifactEnvelope(artifact) { + return { + id: artifact.id, + product: artifact.product, + role: artifact.role, + kind: artifact.kind, + target: artifact.target, + identity: artifact.identity, + name: artifact.name, + path: artifact.path, + sha256: artifact.sha256, + size: artifact.size, + }; +} + +export function buildPublicationCandidate({ + products, + artifactRoots, + headRef = 'HEAD', + allowMissing = false, +} = {}) { + const catalog = loadPublicationCatalog('publication-lock', { products }); + const fullCatalog = loadPublicationCatalog('publication-lock artifact classification'); + const selectedProducts = new Set(catalog.products.map((product) => product.id)); + const artifacts = discoverSelectedPublicationArtifacts( + artifactRoots, + fullCatalog, + selectedProducts, + ); + const productArtifacts = discoverProductArtifacts(artifactRoots, catalog.products); + const carriers = []; + const seenStableIds = new Set(); + for (const artifact of artifacts) { + // Artifact roots may intentionally contain packages for more products than + // this release selected. Classify every identity against the full catalog + // so unknown or ambiguous carriers still fail closed, then project only + // canonical carriers owned by the selected products into the candidate. + const resolved = resolveActualCarrier( + fullCatalog, + artifact.ecosystem, + artifact.name, + 'publication-lock artifact classification', + ); + if (!selectedProducts.has(resolved.product)) { + continue; + } + if (artifact.version !== resolved.version) { + throw error( + `${artifact.ecosystem}:${artifact.name} artifact version ${artifact.version} does not match ${resolved.product} version ${resolved.version}`, + ); + } + if (resolved.declared) { + seenStableIds.add(resolved.id); + } + carriers.push({ + ...resolved, + dependencies: [], + packageDependencies: artifact.dependencies, + artifacts: artifact.artifacts, + }); + } + const missing = catalog.carriers + .filter((carrier) => !seenStableIds.has(carrier.id)) + .map((carrier) => carrier.id) + .sort(compareText); + if (!allowMissing && missing.length > 0) { + throw error( + `artifact set is missing ${missing.length} declared carrier(s): ${missing.join(', ')}`, + ); + } + for (const carrier of carriers) { + carrier.dependencies = projectInternalDependencyIds(carriers, carrier.packageDependencies); + } + validateCargoPayloadPartSets(carriers); + assignPublishOrder(carriers, catalog.products); + const packageEnvelopeDigest = digestValue({ + carriers: carriers.map(carrierEnvelope), + productArtifacts: productArtifacts.map(productArtifactEnvelope), + }); + return { + schema: PUBLICATION_CANDIDATE_SCHEMA, + catalogSchema: PUBLICATION_CATALOG_SCHEMA, + catalogDigest: publicationCatalogDigest(catalog), + source: sourceIdentity(headRef), + products: catalog.products, + carriers, + productArtifacts, + missing, + packageEnvelopeDigest, + }; +} + +function withoutDigest(value) { + const copy = structuredClone(value); + delete copy.lockDigest; + return copy; +} + +export function freezePublicationCandidate(candidate) { + validatePublicationCandidate(candidate); + if (candidate.missing.length > 0) { + throw error(`cannot freeze candidate with missing carriers: ${candidate.missing.join(', ')}`); + } + const frozen = { + ...structuredClone(candidate), + schema: PUBLICATION_LOCK_SCHEMA, + }; + delete frozen.missing; + frozen.lockDigest = digestValue(withoutDigest(frozen)); + return frozen; +} + +function assertHash(value, context) { + if (typeof value !== 'string' || !/^[0-9a-f]{64}$/u.test(value)) { + throw error(`${context} must be a lowercase SHA-256 digest`); + } +} + +function assertNonEmptyString(value, context) { + if (typeof value !== 'string' || value.length === 0 || /[\0\r\n]/u.test(value)) { + throw error(`${context} must be a non-empty single-line string`); + } +} + +function assertSortedUniqueStrings(value, context) { + if (!Array.isArray(value)) { + throw error(`${context} must be a list`); + } + for (const [index, item] of value.entries()) { + assertNonEmptyString(item, `${context}[${index}]`); + } + const canonical = [...new Set(value)].sort(compareText); + if (stableJson(value) !== stableJson(canonical)) { + throw error(`${context} must be sorted and contain no duplicates`); + } +} + +function validateCandidateCatalog(candidate) { + const requestedProducts = candidate.products.map((product) => product.id); + const catalog = loadPublicationCatalog('publication-lock validation', { + products: requestedProducts, + }); + const expectedDigest = publicationCatalogDigest(catalog); + if (candidate.catalogDigest !== expectedDigest) { + throw error( + `candidate catalogDigest mismatch: expected ${expectedDigest}, got ${candidate.catalogDigest}`, + ); + } + if (stableJson(candidate.products) !== stableJson(catalog.products)) { + throw error('candidate products do not exactly match the checked-out publication catalog'); + } + + const presentDeclared = new Set(); + for (const carrier of candidate.carriers) { + const expected = resolveActualCarrier( + catalog, + carrier.ecosystem, + carrier.name, + 'publication-lock validation', + ); + const actualIdentity = { + id: carrier.id, + product: carrier.product, + version: carrier.version, + ecosystem: carrier.ecosystem, + name: carrier.name, + role: carrier.role, + target: carrier.target, + declared: carrier.declared, + parentCarrier: carrier.parentCarrier ?? null, + part: carrier.part ?? null, + }; + const expectedIdentity = { + id: expected.id, + product: expected.product, + version: expected.version, + ecosystem: expected.ecosystem, + name: expected.name, + role: expected.role, + target: expected.target, + declared: expected.declared, + parentCarrier: expected.parentCarrier ?? null, + part: expected.part ?? null, + }; + if (stableJson(actualIdentity) !== stableJson(expectedIdentity)) { + throw error(`carrier ${carrier.id} identity metadata does not match the publication catalog`); + } + if (carrier.declared) { + presentDeclared.add(carrier.id); + } + } + const expectedMissing = catalog.carriers + .map((carrier) => carrier.id) + .filter((id) => !presentDeclared.has(id)) + .sort(compareText); + if (stableJson(candidate.missing) !== stableJson(expectedMissing)) { + throw error( + `candidate missing carrier set mismatch: expected=${JSON.stringify(expectedMissing)}, actual=${JSON.stringify(candidate.missing)}`, + ); + } +} + +function expectedExtensionMetadataNames(product) { + const family = extensionCarrierFamily(product); + return [ + `${product.id}-${product.version}-manifest.json`, + `${product.id}-${product.version}-manifest.properties`, + ...(family === null || family === 'native' + ? [swiftExtensionCarrierAssetName(product.id, product.version)] + : []), + `${product.id}-${product.version}-release-assets.sha256`, + ].sort(compareText); +} + +function validateExtensionProductArtifactInventory(product, artifacts) { + const expectedMetadata = expectedExtensionMetadataNames(product); + const metadata = artifacts + .filter((artifact) => artifact.role === 'github-release-metadata') + .map((artifact) => artifact.name) + .sort(compareText); + if (stableJson(expectedMetadata) !== stableJson(metadata)) { + throw error(`${product.id} frozen release metadata set is incomplete or contains extras`); + } + const publicAssets = artifacts.filter((artifact) => artifact.role === 'github-release-asset'); + const expectedAssets = new Map( + expectedExtensionGithubReleaseAssetRows(product).map((row) => [row.name, row]), + ); + const actualNames = publicAssets.map(({ name }) => name).sort(compareText); + const expectedNames = [...expectedAssets.keys()].sort(compareText); + if (stableJson(expectedNames) !== stableJson(actualNames)) { + throw error( + `${product.id} frozen release assets do not cover every declared target role exactly`, + ); + } + for (const artifact of publicAssets) { + const expected = expectedAssets.get(artifact.name); + if ( + expected === undefined || + artifact.target !== expected.target || + artifact.kind !== expected.kind || + artifact.identity !== expected.identity + ) { + throw error( + `${product.id} frozen release asset ${artifact.name} has incorrect target, kind, or identity metadata`, + ); + } + } + if (artifacts.length !== metadata.length + publicAssets.length) { + throw error(`${product.id} frozen product artifact inventory contains an unsupported role`); + } +} + +function validateProductArtifactInventory(product, artifacts, { hasSelectedExtensionProducts }) { + if (EXTENSION_PRODUCT_KINDS.has(product.kind)) { + validateExtensionProductArtifactInventory(product, artifacts); + return; + } + + const targets = allArtifactTargets( + { + product: product.id, + surface: 'github-release', + }, + 'publication-lock', + ); + const expected = targets.map( + (target) => `github-release:${target.asset.replaceAll('{version}', product.version)}`, + ); + if (product.id === 'oliphaunt-swift') { + expected.push( + 'release-input:Oliphaunt-source.zip', + 'release-input:Package.swift.release', + 'release-input:extension-owner-catalog.json', + 'release-input:extension-resource-inventory.mjs', + 'release-input:oliphaunt-react-native-ios-carriers.json', + 'release-input:render-extension-products.mjs', + 'release-input:swift-carrier-resolver.mjs', + 'release-input:swiftpm-release-tree', + ); + if (hasSelectedExtensionProducts) { + expected.push('release-input:swiftpm-extension-consumer-fixture'); + } + } + if (product.id === 'oliphaunt-react-native') { + expected.push('release-input:oliphaunt-react-native-ios-carriers.json'); + } + const contrib = contribCarrierDescriptor('publication-lock'); + for (const family of ['native', 'wasix']) { + const owner = family === 'native' ? contrib.nativeOwner : contrib.wasixOwner; + if (product.id !== owner) continue; + const extensionProduct = { + id: contrib.artifactProduct, + version: product.version, + releaseProduct: product.id, + family, + }; + const names = [ + ...expectedExtensionMetadataNames(extensionProduct), + ...expectedExtensionGithubReleaseAssetRows(extensionProduct).map((row) => row.name), + ]; + const nameSet = new Set(names); + const extensionArtifacts = artifacts.filter((artifact) => nameSet.has(artifact.name)); + validateExtensionProductArtifactInventory(extensionProduct, extensionArtifacts); + expected.push(...names.map((name) => `github-release:${name}`)); + } + expected.sort(compareText); + const actual = artifacts.map((artifact) => artifact.id).sort(compareText); + if (stableJson(expected) !== stableJson(actual)) { + throw error( + `${product.id} frozen product artifact inventory mismatch: expected=${JSON.stringify(expected)}, actual=${JSON.stringify(actual)}`, + ); + } +} + +export function validatePublicationCandidate(candidate) { + requireObject(candidate, 'candidate'); + if (candidate.schema !== PUBLICATION_CANDIDATE_SCHEMA) { + throw error(`candidate schema must be ${PUBLICATION_CANDIDATE_SCHEMA}`); + } + if (candidate.catalogSchema !== PUBLICATION_CATALOG_SCHEMA) { + throw error(`candidate catalogSchema must be ${PUBLICATION_CATALOG_SCHEMA}`); + } + assertHash(candidate.catalogDigest, 'candidate.catalogDigest'); + assertHash(candidate.packageEnvelopeDigest, 'candidate.packageEnvelopeDigest'); + requireObject(candidate.source, 'candidate.source'); + if ( + !/^[0-9a-f]{40}$/u.test(candidate.source.commit) || + !/^[0-9a-f]{40}$/u.test(candidate.source.tree) + ) { + throw error('candidate source must contain full commit and tree SHAs'); + } + if ( + !Array.isArray(candidate.products) || + !Array.isArray(candidate.carriers) || + !Array.isArray(candidate.productArtifacts) || + !Array.isArray(candidate.missing) + ) { + throw error('candidate products, carriers, productArtifacts, and missing must be lists'); + } + const products = new Map(); + for (const [index, product] of candidate.products.entries()) { + requireObject(product, `candidate product ${index}`); + assertNonEmptyString(product.id, `candidate product ${index}.id`); + assertNonEmptyString(product.kind, `${product.id}.kind`); + assertNonEmptyString(product.path, `${product.id}.path`); + assertNonEmptyString(product.version, `${product.id}.version`); + assertSortedUniqueStrings(product.publishTargets, `${product.id}.publishTargets`); + assertSortedUniqueStrings(product.dependencies, `${product.id}.dependencies`); + if (products.has(product.id)) { + throw error(`candidate contains duplicate product ${product.id}`); + } + products.set(product.id, product); + } + assertSortedUniqueStrings(candidate.missing, 'candidate.missing'); + const identities = new Set(); + for (const carrier of candidate.carriers) { + requireObject(carrier, 'candidate carrier'); + assertNonEmptyString(carrier.id, 'candidate carrier.id'); + assertNonEmptyString(carrier.product, `${carrier.id}.product`); + assertNonEmptyString(carrier.version, `${carrier.id}.version`); + assertNonEmptyString(carrier.ecosystem, `${carrier.id}.ecosystem`); + assertNonEmptyString(carrier.name, `${carrier.id}.name`); + assertNonEmptyString(carrier.role, `${carrier.id}.role`); + if (!ECOSYSTEM_ORDER.has(carrier.ecosystem)) { + throw error(`${carrier.id} has unsupported ecosystem ${carrier.ecosystem}`); + } + if (!ROLE_ORDER.has(carrier.role)) { + throw error(`${carrier.id} has unsupported role ${carrier.role}`); + } + if (carrier.id !== `${carrier.ecosystem}:${carrier.name}`) { + throw error( + `${carrier.id} is not the canonical ${carrier.ecosystem}:${carrier.name} identity`, + ); + } + if ( + !( + carrier.target === null || + (typeof carrier.target === 'string' && carrier.target.length > 0) + ) + ) { + throw error(`${carrier.id}.target must be null or a non-empty string`); + } + if (typeof carrier.declared !== 'boolean') { + throw error(`${carrier.id}.declared must be boolean`); + } + if (!Number.isSafeInteger(carrier.publishOrder) || carrier.publishOrder < 0) { + throw error(`${carrier.id}.publishOrder must be a non-negative safe integer`); + } + if (identities.has(carrier.id)) { + throw error(`candidate contains duplicate carrier ${carrier.id}`); + } + identities.add(carrier.id); + if (!products.has(carrier.product)) { + throw error(`carrier ${carrier.id} refers to unknown product ${carrier.product}`); + } + if (carrier.version !== products.get(carrier.product).version) { + throw error(`carrier ${carrier.id} version does not match product ${carrier.product}`); + } + if ( + !Array.isArray(carrier.dependencies) || + !Array.isArray(carrier.packageDependencies) || + !Array.isArray(carrier.artifacts) || + carrier.artifacts.length === 0 + ) { + throw error(`carrier ${carrier.id} must contain dependency and artifact lists`); + } + assertSortedUniqueStrings(carrier.dependencies, `${carrier.id}.dependencies`); + for (const [index, dependency] of carrier.packageDependencies.entries()) { + requireObject(dependency, `${carrier.id}.packageDependencies[${index}]`); + assertNonEmptyString( + dependency.ecosystem, + `${carrier.id}.packageDependencies[${index}].ecosystem`, + ); + assertNonEmptyString(dependency.name, `${carrier.id}.packageDependencies[${index}].name`); + assertNonEmptyString( + dependency.requirement, + `${carrier.id}.packageDependencies[${index}].requirement`, + ); + assertNonEmptyString(dependency.scope, `${carrier.id}.packageDependencies[${index}].scope`); + if (!ECOSYSTEM_ORDER.has(dependency.ecosystem)) { + throw error( + `${carrier.id}.packageDependencies[${index}] has unsupported ecosystem ${dependency.ecosystem}`, + ); + } + } + const artifactPaths = new Set(); + for (const artifact of carrier.artifacts) { + requireObject(artifact, `${carrier.id} artifact`); + assertHash(artifact.sha256, `${carrier.id} artifact sha256`); + if ( + !Number.isSafeInteger(artifact.size) || + artifact.size < 0 || + typeof artifact.path !== 'string' || + artifact.path.length === 0 + ) { + throw error(`${carrier.id} contains invalid artifact metadata`); + } + if (artifactPaths.has(artifact.path)) { + throw error(`${carrier.id} contains duplicate artifact path ${artifact.path}`); + } + artifactPaths.add(artifact.path); + } + } + const publishOrders = candidate.carriers.map((carrier) => carrier.publishOrder); + const expectedPublishOrders = candidate.carriers.map((_, index) => index); + if (stableJson(publishOrders) !== stableJson(expectedPublishOrders)) { + throw error( + 'candidate carriers must be stored in one contiguous, unique publishOrder sequence', + ); + } + const carrierPosition = new Map(candidate.carriers.map((carrier, index) => [carrier.id, index])); + for (const [index, carrier] of candidate.carriers.entries()) { + const expectedDependencies = projectInternalDependencyIds( + candidate.carriers, + carrier.packageDependencies, + ); + if (stableJson(carrier.dependencies) !== stableJson(expectedDependencies)) { + throw error( + `${carrier.id}.dependencies do not match its internal package dependency identities`, + ); + } + for (const dependency of carrier.dependencies) { + const position = carrierPosition.get(dependency); + if (position === undefined) { + throw error(`${carrier.id} refers to unknown carrier dependency ${dependency}`); + } + if (position >= index) { + throw error(`${carrier.id} publishOrder precedes dependency ${dependency}`); + } + } + } + validateCargoPayloadPartSets(candidate.carriers); + validateCandidateCatalog(candidate); + const productArtifactIds = new Set(); + for (const artifact of candidate.productArtifacts) { + const id = `${artifact.product}:${artifact.id}`; + if (productArtifactIds.has(id) || !products.has(artifact.product)) { + throw error(`candidate contains duplicate or unknown product artifact ${id}`); + } + productArtifactIds.add(id); + if ( + typeof artifact.id !== 'string' || + artifact.id.length === 0 || + typeof artifact.role !== 'string' || + artifact.role.length === 0 || + typeof artifact.kind !== 'string' || + artifact.kind.length === 0 || + !( + (typeof artifact.target === 'string' && artifact.target.length > 0) || + artifact.target === null + ) || + !( + artifact.identity === null || + (typeof artifact.identity === 'string' && artifact.identity.length > 0) + ) || + typeof artifact.name !== 'string' || + artifact.name.length === 0 || + path.basename(artifact.name) !== artifact.name + ) { + throw error(`${id} contains invalid canonical product artifact metadata`); + } + assertHash(artifact.sha256, `${id} sha256`); + if ( + !Number.isSafeInteger(artifact.size) || + artifact.size < 0 || + typeof artifact.path !== 'string' || + artifact.path.length === 0 + ) { + throw error(`${id} contains invalid artifact metadata`); + } + } + const hasSelectedExtensionProducts = candidate.products.some((product) => + EXTENSION_PRODUCT_KINDS.has(product.kind), + ); + for (const product of candidate.products) { + validateProductArtifactInventory( + product, + candidate.productArtifacts.filter((artifact) => artifact.product === product.id), + { hasSelectedExtensionProducts }, + ); + } + const expectedEnvelope = digestValue({ + carriers: candidate.carriers.map(carrierEnvelope), + productArtifacts: candidate.productArtifacts.map(productArtifactEnvelope), + }); + if (candidate.packageEnvelopeDigest !== expectedEnvelope) { + throw error( + `candidate packageEnvelopeDigest mismatch: expected ${expectedEnvelope}, got ${candidate.packageEnvelopeDigest}`, + ); + } + return candidate; +} + +export function validatePublicationLock(lock) { + requireObject(lock, 'publication lock'); + if (lock.schema !== PUBLICATION_LOCK_SCHEMA) { + throw error(`publication lock schema must be ${PUBLICATION_LOCK_SCHEMA}`); + } + const candidate = { ...structuredClone(lock), schema: PUBLICATION_CANDIDATE_SCHEMA, missing: [] }; + delete candidate.lockDigest; + validatePublicationCandidate(candidate); + assertHash(lock.lockDigest, 'publication lock lockDigest'); + const expected = digestValue(withoutDigest(lock)); + if (lock.lockDigest !== expected) { + throw error(`publication lock digest mismatch: expected ${expected}, got ${lock.lockDigest}`); + } + return lock; +} + +export function loadPublicationLock(file = DEFAULT_PUBLICATION_LOCK) { + let lock; + try { + lock = JSON.parse(readFileSync(file, 'utf8')); + } catch (cause) { + throw error(`cannot read publication lock ${rel(file)}: ${cause.message}`); + } + return validatePublicationLock(lock); +} + +export function assertPublicationLockSource(lock, headRef = 'HEAD') { + const source = sourceIdentity(headRef); + if (lock.source.commit !== source.commit || lock.source.tree !== source.tree) { + throw error( + `publication lock source ${lock.source.commit}/${lock.source.tree} does not match ${headRef} ${source.commit}/${source.tree}`, + ); + } + return source; +} + +export function lockedCarriers( + lock, + { product = undefined, products = undefined, ecosystem = undefined } = {}, +) { + const productSet = products === undefined ? undefined : new Set(products); + return lock.carriers.filter( + (carrier) => + (product === undefined || carrier.product === product) && + (productSet === undefined || productSet.has(carrier.product)) && + (ecosystem === undefined || carrier.ecosystem === ecosystem), + ); +} + +function lockedWorkspaceFile(artifact, context) { + const file = path.resolve(ROOT, artifact.path); + const relative = path.relative(ROOT, file); + if (relative === '' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { + throw error(`${context} artifact path must remain inside the repository: ${artifact.path}`); + } + let metadata; + try { + metadata = lstatSync(file); + } catch (cause) { + throw error(`${context} frozen artifact is missing: ${artifact.path}: ${cause.message}`); + } + if (metadata.isSymbolicLink() || !metadata.isFile()) { + throw error(`${context} frozen artifact must be a regular non-symlink file: ${artifact.path}`); + } + if (metadata.size !== artifact.size || sha256File(file) !== artifact.sha256) { + throw error( + `${context} frozen artifact bytes do not match the publication lock: ${artifact.path}`, + ); + } + return file; +} + +export function lockedCarrierFiles(lock, ecosystem, name) { + const matches = lockedCarriers(lock, { ecosystem }).filter((carrier) => carrier.name === name); + if (matches.length !== 1) { + throw error( + `expected exactly one frozen ${ecosystem}:${name} carrier, found ${matches.length}`, + ); + } + const carrier = matches[0]; + return { + carrier, + files: carrier.artifacts.map((artifact) => ({ + artifact, + file: lockedWorkspaceFile(artifact, carrier.id), + })), + }; +} + +export function lockedCarrierFile(lock, ecosystem, name, suppliedPath = undefined) { + const { carrier, files } = lockedCarrierFiles(lock, ecosystem, name); + if (carrier.artifacts.length !== 1) { + throw error( + `${carrier.id} must have exactly one publishable file, found ${carrier.artifacts.length}`, + ); + } + const file = files[0].file; + if (suppliedPath !== undefined && path.resolve(ROOT, suppliedPath) !== file) { + throw error( + `${carrier.id} publisher attempted to substitute ${rel(path.resolve(ROOT, suppliedPath))} for frozen ${carrier.artifacts[0].path}`, + ); + } + return { carrier, file }; +} + +export function lockedCarrierDirectory(lock, ecosystem, name, suppliedPath = undefined) { + const matches = lockedCarriers(lock, { ecosystem }).filter((carrier) => carrier.name === name); + if (matches.length !== 1) { + throw error( + `expected exactly one frozen ${ecosystem}:${name} carrier, found ${matches.length}`, + ); + } + const carrier = matches[0]; + if (carrier.artifacts.length !== 1) { + throw error( + `${carrier.id} must have exactly one publishable directory, found ${carrier.artifacts.length}`, + ); + } + const artifact = carrier.artifacts[0]; + const directory = path.resolve(ROOT, artifact.path); + const relative = path.relative(ROOT, directory); + if (relative === '' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { + throw error(`${carrier.id} artifact path must remain inside the repository: ${artifact.path}`); + } + let stat; + try { + stat = lstatSync(directory); + } catch (cause) { + throw error(`${carrier.id} frozen directory is missing: ${artifact.path}: ${cause.message}`); + } + if (stat.isSymbolicLink() || !stat.isDirectory()) { + throw error( + `${carrier.id} frozen artifact must be a regular non-symlink directory: ${artifact.path}`, + ); + } + const observed = directoryEnvelope(directory); + if (observed.sha256 !== artifact.sha256 || observed.size !== artifact.size) { + throw error( + `${carrier.id} frozen directory bytes do not match the publication lock: ${artifact.path}`, + ); + } + if (suppliedPath !== undefined && path.resolve(ROOT, suppliedPath) !== directory) { + throw error( + `${carrier.id} publisher attempted to substitute ${rel(path.resolve(ROOT, suppliedPath))} for frozen ${artifact.path}`, + ); + } + return { carrier, directory }; +} + +export function assertLockedIdentitySet(lock, actual, { product, products, ecosystem } = {}) { + const expected = lockedCarriers(lock, { product, products, ecosystem }) + .map((carrier) => `${carrier.ecosystem}:${carrier.name}@${carrier.version}`) + .sort(compareText); + const observed = actual + .map((item) => `${item.ecosystem ?? ecosystem}:${item.name}@${item.version}`) + .sort(compareText); + if (stableJson(expected) !== stableJson(observed)) { + throw error( + `frozen carrier set mismatch for ${product ?? products?.join(',') ?? 'all products'}/${ecosystem ?? 'all ecosystems'}: expected=${JSON.stringify(expected)}, actual=${JSON.stringify(observed)}`, + ); + } +} + +export function assertLockedArtifactSet(lock, actual, { product, products, ecosystem } = {}) { + assertLockedIdentitySet(lock, actual, { product, products, ecosystem }); + const expected = new Map( + lockedCarriers(lock, { product, products, ecosystem }).map((carrier) => [carrier.id, carrier]), + ); + for (const record of actual) { + const id = `${record.ecosystem}:${record.name}`; + const frozen = expected.get(id); + if (frozen === undefined || !Array.isArray(record.artifacts)) { + throw error( + `actual artifact record ${id} is absent from the frozen lock or has no byte envelope`, + ); + } + const frozenBytes = frozen.artifacts + .map(({ sha256, size }) => `${sha256}:${size}`) + .sort(compareText); + const actualBytes = record.artifacts + .map(({ sha256, size }) => `${sha256}:${size}`) + .sort(compareText); + if (stableJson(frozenBytes) !== stableJson(actualBytes)) { + throw error( + `frozen artifact bytes mismatch for ${id}: expected=${JSON.stringify(frozenBytes)}, actual=${JSON.stringify(actualBytes)}`, + ); + } + } +} + +export function assertLockedProductArtifacts(lock, product, roots) { + const expected = lock.productArtifacts.filter((artifact) => artifact.product === product); + const productRow = lock.products.find((row) => row.id === product); + if (productRow === undefined) { + throw error(`publication lock does not select product ${product}`); + } + const actual = discoverProductArtifactsForSelection(roots, [productRow], lock.products); + const envelope = (artifacts) => + artifacts + .map( + ({ product: owner, id, role, kind, target, identity, name, sha256, size }) => + `${owner}:${id}:${role}:${kind}:${target ?? ''}:${identity ?? ''}:${name}:${sha256}:${size}`, + ) + .sort(compareText); + if (stableJson(envelope(expected)) !== stableJson(envelope(actual))) { + throw error( + `frozen product artifact bytes mismatch for ${product}: expected=${JSON.stringify(envelope(expected))}, actual=${JSON.stringify(envelope(actual))}`, + ); + } +} + +export function lockedProductArtifactPaths( + lock, + product, + { role = undefined, kind = undefined } = {}, +) { + const selected = lock.productArtifacts.filter( + (artifact) => + artifact.product === product && + (role === undefined || artifact.role === role) && + (kind === undefined || artifact.kind === kind), + ); + return selected.map((artifact) => { + const value = path.resolve(ROOT, artifact.path); + const relative = path.relative(ROOT, value); + if (relative === '' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { + throw error( + `${product}:${artifact.id} path must remain inside the repository: ${artifact.path}`, + ); + } + let stat; + try { + stat = lstatSync(value); + } catch (cause) { + throw error(`${product}:${artifact.id} is missing: ${artifact.path}: ${cause.message}`); + } + if (stat.isSymbolicLink()) { + throw error(`${product}:${artifact.id} must not be a symlink: ${artifact.path}`); + } + const observed = stat.isFile() + ? { sha256: sha256File(value), size: stat.size } + : stat.isDirectory() + ? directoryEnvelope(value) + : null; + if ( + observed === null || + observed.sha256 !== artifact.sha256 || + observed.size !== artifact.size + ) { + throw error( + `${product}:${artifact.id} bytes do not match the publication lock: ${artifact.path}`, + ); + } + return { artifact, path: value, type: stat.isFile() ? 'file' : 'directory' }; + }); +} + +export function lockedPublicationFiles(lock, { products, workspaceRoot = ROOT } = {}) { + const selected = products === undefined ? lock.products.map(({ id }) => id) : products; + const selectedSet = new Set(selected); + const lockedProducts = lock.products.map(({ id }) => id).sort(compareText); + if ( + selected.length !== selectedSet.size || + stableJson([...selectedSet].sort(compareText)) !== stableJson(lockedProducts) + ) { + throw error('publication file selection must exactly match the lock products'); + } + + const artifacts = [ + ...lockedCarriers(lock, { products: selected }).flatMap((carrier) => + carrier.artifacts.map((artifact) => ({ artifact, context: carrier.id })), + ), + ...lock.productArtifacts + .filter((artifact) => selectedSet.has(artifact.product)) + .map((artifact) => ({ artifact, context: `${artifact.product}:${artifact.id}` })), + ]; + const files = new Map(); + for (const { artifact, context } of artifacts) { + const value = path.resolve(workspaceRoot, ...artifact.path.split('/')); + const relative = path.relative(path.resolve(workspaceRoot), value); + if (relative === '' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { + throw error(`${context} artifact path must remain inside the workspace: ${artifact.path}`); + } + let metadata; + try { + metadata = lstatSync(value); + } catch (cause) { + throw error(`${context} frozen artifact is missing: ${artifact.path}: ${cause.message}`); + } + if (metadata.isSymbolicLink() || !(metadata.isFile() || metadata.isDirectory())) { + throw error( + `${context} frozen artifact must be a regular file or directory: ${artifact.path}`, + ); + } + const observed = metadata.isFile() + ? { sha256: sha256File(value), size: metadata.size } + : directoryEnvelope(value); + if (observed.sha256 !== artifact.sha256 || observed.size !== artifact.size) { + throw error( + `${context} frozen artifact bytes do not match the publication lock: ${artifact.path}`, + ); + } + const concrete = metadata.isFile() + ? [value] + : walkFiles(value, { ignoreBuildDirectories: true }); + for (const file of concrete) { + const filePath = path.relative(workspaceRoot, file).split(path.sep).join('/'); + const envelope = { path: filePath, size: statSync(file).size, sha256: sha256File(file) }; + const prior = files.get(filePath); + if (prior !== undefined && stableJson(prior) !== stableJson(envelope)) { + throw error(`overlapping frozen artifacts disagree for ${filePath}`); + } + files.set(filePath, envelope); + } + } + return [...files.values()].sort((left, right) => compareText(left.path, right.path)); +} + +function parseArgs(argv) { + const command = argv.shift(); + const values = new Map(); + const repeated = new Map(); + const booleans = new Set(); + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--allow-missing') { + booleans.add('allow-missing'); + continue; + } + if (!arg.startsWith('--')) { + throw error(`unexpected positional argument ${arg}`); + } + const separator = arg.indexOf('='); + const key = arg.slice(2, separator === -1 ? undefined : separator); + const value = separator === -1 ? argv[++index] : arg.slice(separator + 1); + if (value === undefined) { + throw error(`--${key} requires a value`); + } + if (key === 'artifact-root') { + repeated.set(key, [...(repeated.get(key) ?? []), value]); + } else { + values.set(key, value); + } + } + return { command, values, repeated, booleans }; +} + +function productsFlag(values) { + const raw = values.get('products-json'); + if (raw === undefined) { + return undefined; + } + const value = JSON.parse(raw); + if ( + !Array.isArray(value) || + value.length === 0 || + value.some((item) => typeof item !== 'string' || item.length === 0) + ) { + throw error('--products-json must be a non-empty JSON string list'); + } + return value; +} + +function writeJson(file, value) { + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`); +} + +function main(argv) { + const { command, values, repeated, booleans } = parseArgs([...argv]); + if (command === 'candidate' || command === 'create') { + const candidate = buildPublicationCandidate({ + products: productsFlag(values), + artifactRoots: repeated.get('artifact-root') ?? [], + headRef: values.get('head-ref') ?? 'HEAD', + allowMissing: command === 'candidate' && booleans.has('allow-missing'), + }); + const output = path.resolve( + ROOT, + values.get('output') ?? + (command === 'create' + ? DEFAULT_PUBLICATION_LOCK + : 'target/release/publication-candidate.json'), + ); + const value = command === 'create' ? freezePublicationCandidate(candidate) : candidate; + writeJson(output, value); + console.log( + `${rel(output)}\t${value.packageEnvelopeDigest}\t${value.lockDigest ?? 'candidate'}`, + ); + return; + } + if (command === 'freeze') { + const input = path.resolve( + ROOT, + values.get('candidate') ?? 'target/release/publication-candidate.json', + ); + const candidate = JSON.parse(readFileSync(input, 'utf8')); + const lock = freezePublicationCandidate(candidate); + const output = path.resolve(ROOT, values.get('output') ?? DEFAULT_PUBLICATION_LOCK); + writeJson(output, lock); + console.log(`${rel(output)}\t${lock.packageEnvelopeDigest}\t${lock.lockDigest}`); + return; + } + if (command === 'verify') { + const file = path.resolve(ROOT, values.get('lock') ?? DEFAULT_PUBLICATION_LOCK); + const lock = loadPublicationLock(file); + assertPublicationLockSource(lock, values.get('head-ref') ?? 'HEAD'); + console.log( + `${rel(file)} publication lock verified (${lock.carriers.length} carriers, envelope ${lock.packageEnvelopeDigest})`, + ); + return; + } + console.log( + 'usage: tools/release/publication-lock.mts [--products-json JSON] [--artifact-root PATH ...] [--head-ref REF] [--output PATH] [--allow-missing]', + ); + process.exit(command === '-h' || command === '--help' ? 0 : 2); +} + +if (import.meta.main) { + try { + main(Bun.argv.slice(2)); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/publication-lock.test.mjs b/tools/release/publication-lock.test.mjs deleted file mode 100644 index 2e70a4ade..000000000 --- a/tools/release/publication-lock.test.mjs +++ /dev/null @@ -1,1179 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { chmodSync, mkdtempSync, mkdirSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { gunzipSync } from "node:zlib"; - -import { - assertLockedProductArtifacts, - buildPublicationCandidate, - discoverPublicationArtifacts, - discoverProductArtifacts, - freezePublicationCandidate, - lockedCarrierFile, - projectInternalDependencyIds, - validateCargoPayloadPartSets, - validatePublicationCandidate, - validatePublicationLock, -} from "./publication-lock.mjs"; -import { - loadPublicationCatalog, - resolveActualCarrier, -} from "./publication-catalog.mjs"; -import { extensionDependencyRequirement } from "./package_liboliphaunt_wasix_cargo_artifacts.mjs"; -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { - extensionCarrierLegalContract, - stageExtensionUpstreamLicenses, -} from "./extension-upstream-licenses.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; -import { - allArtifactTargets, - currentProductVersionSync, - extensionArtifactProductRoot, - extensionArtifactTargets, - extensionMetadata, - extensionSourceIdentity, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { productCompatibilityVersion } from "./release-graph.mjs"; -import { - buildSwiftExtensionCarrierManifest, - iosBaseLegalMetadata, - swiftExtensionCarrierAssetName, -} from "./ios-carrier-manifest.mjs"; -import { canonicalGzipSync } from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -const temporaryDirectories = []; - -function sortJsonValue(value) { - if (Array.isArray(value)) return value.map(sortJsonValue); - if (value !== null && typeof value === "object") { - return Object.fromEntries( - Object.keys(value).sort().map((key) => [key, sortJsonValue(value[key])]), - ); - } - return value; -} - -function canonicalJson(value) { - return `${JSON.stringify(sortJsonValue(value), null, 2)}\n`; -} - -function wasixInstall(sqlName, dependencies, createsExtension) { - return { - schema: "oliphaunt-wasix-extension-install-v1", - name: sqlName, - nativeModule: null, - nativeModules: [], - coreExportsRequired: [], - dependencies, - loadOrder: [], - lifecycle: { - createExtension: createsExtension, - createSchema: "pg_catalog", - loadSql: [], - postCreateSql: [], - startupConfig: [], - preloadRequired: false, - restartRequired: false, - sharedMemoryRequired: false, - }, - installedFiles: [`share/postgresql/extension/${sqlName}.control`], - unresolvedImports: [], - }; -} - -function refreshTarHeaderChecksum(tar, offset = 0) { - tar.fill(0x20, offset + 148, offset + 156); - const checksum = tar.subarray(offset, offset + 512) - .reduce((total, byte) => total + byte, 0); - Buffer.from(`${checksum.toString(8).padStart(6, "0")}\0 `, "ascii") - .copy(tar, offset + 148); -} - -function temporaryDirectory() { - const directory = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-publication-lock-")); - temporaryDirectories.push(directory); - return directory; -} - -function selectionNeutralSwiftSourceCarrier(version = "1.2.3") { - const product = "liboliphaunt-native"; - const tag = `${product}-v${version}`; - const assets = [ - ["base-xcframework", `liboliphaunt-${version}-apple-spm-xcframework.zip`, "zip", "liboliphaunt.xcframework", "1"], - ["runtime-resources", `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`, "tar.gz", "oliphaunt", "2"], - ["icu-data", `liboliphaunt-${version}-icu-data.tar.gz`, "tar.gz", ".", "3"], - ].map(([role, name, format, member, digestDigit], index) => ({ - bytes: index + 1, - format, - member, - name, - role, - sha256: digestDigit.repeat(64), - url: `https://github.com/f0rr0/oliphaunt/releases/download/${tag}/${name}`, - })); - return { - base: { assets, product, tag, version }, - carriers: [], - extensions: [], - legal: { base: iosBaseLegalMetadata(), extensions: [] }, - schema: "oliphaunt-react-native-ios-carrier-v1", - }; -} - -function tarGzip(output, cwd, member) { - const result = spawnSync("tar", ["--format=ustar", "-czf", output, "-C", cwd, member], { encoding: "utf8" }); - if (result.status !== 0) { - throw new Error(result.stderr || `tar exited ${result.status}`); - } -} - -function npmFixture(root, name, version, overrides = {}, bundledManifest = null) { - const stage = path.join(root, "npm-stage", "package"); - mkdirSync(stage, { recursive: true }); - writeFileSync(path.join(stage, "package.json"), `${JSON.stringify({ - name, - version, - repository: { - type: "git", - url: "git+https://github.com/f0rr0/oliphaunt.git", - }, - publishConfig: { - access: "public", - provenance: true, - }, - optionalDependencies: { "@oliphaunt/optional-test": version }, - ...overrides, - }, null, 2)}\n`); - if (bundledManifest !== null) { - const bundled = path.join(stage, "node_modules", "@oliphaunt", "js-core"); - mkdirSync(bundled, { recursive: true }); - writeFileSync(path.join(bundled, "package.json"), `${JSON.stringify(bundledManifest)}\n`); - } - const output = path.join(root, "package.tgz"); - tarGzip(output, path.dirname(stage), "package"); - return output; -} - -function cargoFixture(root, name, version, { manifestSuffix = "" } = {}) { - const directoryName = `${name}-${version}`; - const stage = path.join(root, "cargo-stage", directoryName); - mkdirSync(path.join(stage, "src"), { recursive: true }); - writeFileSync( - path.join(stage, "Cargo.toml"), - `[package]\nname = ${JSON.stringify(name)}\nversion = ${JSON.stringify(version)}\nedition = "2024"\n\n[dependencies]\nserde = "1"\n${manifestSuffix}`, - ); - writeFileSync(path.join(stage, "src/lib.rs"), "pub const FIXTURE: bool = true;\n"); - const output = path.join(root, `${directoryName}.crate`); - tarGzip(output, path.dirname(stage), directoryName); - return output; -} - -function mavenFixture(root, group, artifact, version) { - const directory = path.join(root, "maven", ...group.split("."), artifact, version); - mkdirSync(directory, { recursive: true }); - const pom = path.join(directory, `${artifact}-${version}.pom`); - writeFileSync(pom, `4.0.0${group}${artifact}${version}FixtureFixture publicationhttps://github.com/f0rr0/oliphauntMIThttps://opensource.org/license/mitFixture Maintainerhttps://github.com/f0rr0scm:git:https://github.com/f0rr0/oliphaunt.gitscm:git:ssh://git@github.com/f0rr0/oliphaunt.githttps://github.com/f0rr0/oliphauntexampledependency1\n`); - writeFileSync(path.join(directory, `${artifact}-${version}.jar`), "fixture"); - writeFileSync(path.join(directory, `${artifact}-${version}-sources.jar`), "fixture sources"); - writeFileSync(path.join(directory, `${artifact}-${version}-javadoc.jar`), "fixture javadocs"); - return pom; -} - -function sha256File(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function githubReleaseFixture(root, product) { - const directory = path.join(root, product.id, "release-assets"); - mkdirSync(directory, { recursive: true }); - const rows = allArtifactTargets({ - product: product.id, - surface: "github-release", - }, "publication-lock.test").map((target) => ({ - target, - name: target.asset.replaceAll("{version}", product.version), - })); - const checksum = rows.find((row) => row.target.kind === "checksums"); - for (const row of rows.filter((item) => item !== checksum)) { - writeFileSync(path.join(directory, row.name), `fixture:${row.name}\n`); - } - const checksumLines = rows - .filter((item) => item !== checksum) - .map((row) => `${sha256File(path.join(directory, row.name))} ./${row.name}\n`) - .sort(); - writeFileSync(path.join(directory, checksum.name), checksumLines.join("")); - return { checksum, directory, rows }; -} - -function extensionGithubReleaseFixture( - root, - product, - { - artifactProduct = product.id, - family = null, - mutateBundleArchive = undefined, - mutateBundleStage = undefined, - bundleFixedFileMode = 0o644, - } = {}, -) { - const productRoot = extensionArtifactProductRoot( - artifactProduct, - family ?? "native", - path.join(root, "target", "extension-artifacts"), - "publication-lock.test", - ); - const directory = path.join(productRoot, "release-assets"); - rmSync(productRoot, { recursive: true, force: true }); - mkdirSync(directory, { recursive: true }); - const sqlNames = extensionSqlNames(artifactProduct, "publication-lock.test"); - const bundled = sqlNames.length > 1; - const releaseMetadata = extensionMetadata(artifactProduct, "publication-lock.test"); - const ownership = artifactProduct === product.id - ? {} - : { releaseProduct: product.id, family: family ?? "combined" }; - const compatibility = releaseMetadata.compatibility; - const generated = JSON.parse(readFileSync(path.join(import.meta.dir, "../../src/extensions/generated/sdk/extensions.json"), "utf8")); - const staticLines = readFileSync(path.join(import.meta.dir, "../../src/extensions/generated/mobile/static-extensions.tsv"), "utf8") - .split(/\r?\n/u) - .filter((line) => line.length > 0 && !line.startsWith("#")); - const staticHeader = staticLines[0].split("\t"); - const staticRows = staticLines.slice(1).map((line) => Object.fromEntries( - staticHeader.map((column, index) => [column, line.split("\t")[index] ?? ""]), - )); - const assets = []; - const extensions = []; - for (const sqlName of sqlNames) { - const extension = generated.extensions.find((row) => row["sql-name"] === sqlName); - const nativeModuleStem = extension["native-module-stem"]; - const staticRow = staticRows.find((row) => row["sql-name"] === sqlName); - const iosNativeDependencies = nativeModuleStem === null - ? [] - : (staticRow?.["ios-static-dependencies"] ?? "").split(",").filter(Boolean).sort(); - const memberAssets = []; - for (const target of extensionArtifactTargets({ product: artifactProduct }, "publication-lock.test") - .filter((row) => row.sqlName === sqlName && (family === null || row.family === family))) { - const roles = target.family === "wasix" - ? ["wasix-runtime"] - : target.target === "ios-xcframework" - ? ["runtime", ...(nativeModuleStem === null ? [] : ["ios-xcframework", ...iosNativeDependencies.map((dependency) => `ios-dependency-xcframework:${dependency}`)])] - : ["runtime"]; - for (const role of roles) { - const [kind, dependencyIdentity] = role.split(":"); - const identity = kind === "ios-xcframework" - ? nativeModuleStem - : kind === "ios-dependency-xcframework" - ? dependencyIdentity - : null; - const prefix = `${artifactProduct}-${product.version}`; - const name = target.family === "wasix" - ? `${prefix}-wasix-portable.tar.zst` - : kind === "ios-xcframework" - ? `${prefix}-native-ios-xcframework.zip` - : kind === "ios-dependency-xcframework" - ? `${prefix}-native-ios-dependency-${identity}-xcframework.zip` - : target.target === "ios-xcframework" - ? `${prefix}-native-ios-runtime.tar.gz` - : `${prefix}-native-${target.target}-runtime.tar.gz`; - const file = path.join( - bundled ? path.join(productRoot, "member-assets", sqlName) : directory, - name, - ); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, `fixture:${name}\n`); - const asset = { - name, - family: target.family, - target: target.target, - kind, - identity, - path: file, - sha256: sha256File(file), - bytes: readFileSync(file).length, - }; - assets.push(asset); - memberAssets.push(asset); - } - } - const dependencies = [...extension["selected-extension-dependencies"]].sort(); - const createsExtension = extension["creates-extension"] !== false; - const stagesIos = memberAssets.some((asset) => asset.target === "ios-xcframework"); - extensions.push({ - sqlName, - createsExtension, - dependencies, - dataFiles: [...extension["runtime-share-data-files"]].sort(), - extensionSqlFileNames: [...extension["extension-sql-file-names"]].sort(), - extensionSqlFilePrefixes: [...extension["extension-sql-file-prefixes"]].sort(), - nativeModuleStem, - iosNativeDependencies: stagesIos ? iosNativeDependencies : [], - iosRegistration: nativeModuleStem === null || !stagesIos ? null : { - schema: "oliphaunt-ios-extension-registration-v1", - sqlName, - nativeModuleStem, - magicSymbol: `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}_Pg_magic_func`, - initSymbol: null, - symbols: [], - }, - wasixInstall: memberAssets.some((asset) => asset.family === "wasix") - ? wasixInstall(sqlName, dependencies, createsExtension) - : null, - sharedPreloadLibraries: [...extension["shared-preload-libraries"]].sort(), - assets: memberAssets, - }); - } - const carrierAssets = []; - if (bundled) { - const groups = new Map(); - for (const extension of extensions) { - for (const asset of extension.assets) { - const key = `${asset.family}\0${asset.target}`; - const group = groups.get(key) ?? { family: asset.family, target: asset.target, rows: [] }; - group.rows.push({ sqlName: extension.sqlName, asset }); - groups.set(key, group); - } - } - for (const group of [...groups.values()].sort((left, right) => - `${left.family}\0${left.target}`.localeCompare(`${right.family}\0${right.target}`))) { - const archiveRoot = `${artifactProduct}-${product.version}-${group.family}-${group.target}-bundle`; - const stage = path.join(productRoot, "bundle-stage", archiveRoot); - rmSync(stage, { recursive: true, force: true }); - mkdirSync(stage, { recursive: true }); - const manifestMembers = []; - for (const { sqlName, asset } of group.rows.sort((left, right) => - `${left.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ""}`.localeCompare( - `${right.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ""}`, - ))) { - const memberPath = `extensions/${sqlName}/${asset.name}`; - const destination = path.join(stage, ...memberPath.split("/")); - mkdirSync(path.dirname(destination), { recursive: true }); - writeFileSync(destination, readFileSync(asset.path)); - asset.carrierAsset = `${archiveRoot}.tar.gz`; - asset.carrierRoot = archiveRoot; - asset.memberPath = memberPath; - manifestMembers.push({ - sqlName, - kind: asset.kind, - identity: asset.identity, - path: memberPath, - sha256: asset.sha256, - bytes: asset.bytes, - }); - } - const memberNames = [...new Set(manifestMembers.map(({ sqlName }) => sqlName))].sort(); - const legal = extensionCarrierLegalContract(artifactProduct, memberNames, { - family: group.family, - target: group.target, - }); - for (const sqlName of memberNames) stageExtensionUpstreamLicenses(sqlName, stage); - const bundleManifest = path.join(stage, "bundle-manifest.json"); - writeFileSync(bundleManifest, canonicalJson({ - schema: "oliphaunt-extension-bundle-v1", - product: artifactProduct, - version: product.version, - compatibility, - family: group.family, - target: group.target, - licenseProfile: legal.profile, - licenseFiles: legal.licenseFiles, - members: manifestMembers, - })); - stageReleaseNotices(stage, { profile: legal.profile }); - mutateBundleStage?.({ - archiveRoot, - bundleManifest, - family: group.family, - legal, - stage, - target: group.target, - }); - const output = path.join(directory, `${archiveRoot}.tar.gz`); - const tarOptions = { - fail(message) { - throw new Error(`publication lock fixture: ${message}`); - }, - }; - if (bundleFixedFileMode !== null) tarOptions.fixedFileMode = bundleFixedFileMode; - writeFileSync(output, canonicalGzipSync(createDeterministicTar(stage, archiveRoot, tarOptions))); - mutateBundleArchive?.({ - archiveRoot, - family: group.family, - output, - target: group.target, - }); - carrierAssets.push({ - name: path.basename(output), - path: output, - sha256: sha256File(output), - bytes: readFileSync(output).length, - family: group.family, - target: group.target, - kind: "extension-bundle", - memberCount: sqlNames.length, - }); - } - } - const extensionManifestPath = path.join(productRoot, "extension-artifacts.json"); - const extensionManifest = bundled - ? { - schema: "oliphaunt-extension-ci-artifacts-v2", - product: artifactProduct, - ...ownership, - version: product.version, - compatibility, - extensions, - carrierAssets, - } - : { - schema: "oliphaunt-extension-ci-artifacts-v1", - product: artifactProduct, - ...ownership, - version: product.version, - compatibility, - ...extensions[0], - }; - writeFileSync(extensionManifestPath, `${JSON.stringify(extensionManifest, null, 2)}\n`); - const manifestName = `${artifactProduct}-${product.version}-manifest.json`; - const propertiesName = `${artifactProduct}-${product.version}-manifest.properties`; - const swiftCarrierName = swiftExtensionCarrierAssetName(artifactProduct, product.version); - const checksumName = `${artifactProduct}-${product.version}-release-assets.sha256`; - const directAssets = bundled ? carrierAssets : assets; - writeFileSync(path.join(directory, manifestName), `${JSON.stringify({ - schema: bundled ? "oliphaunt-extension-release-manifest-v2" : "oliphaunt-extension-release-manifest-v1", - product: artifactProduct, - ...ownership, - version: product.version, - extensionClass: releaseMetadata.class, - versioning: releaseMetadata.versioning, - sourceIdentity: extensionSourceIdentity(artifactProduct, "publication-lock.test"), - compatibility, - ...(bundled - ? { - extensions: extensions.map((row) => ({ - ...row, - assets: row.assets.map(({ - name, - family, - target, - kind, - identity, - sha256, - bytes, - carrierAsset, - carrierRoot, - memberPath, - }) => ({ - name, - family, - target, - kind, - identity, - sha256, - bytes, - carrierAsset, - carrierRoot, - memberPath, - })), - })), - assets: carrierAssets.map(({ name, family, target, kind, sha256, bytes, memberCount }) => ({ - name, - family, - target, - kind, - sha256, - bytes, - memberCount, - })), - } - : { - sqlName: extensions[0].sqlName, - createsExtension: extensions[0].createsExtension, - dependencies: extensions[0].dependencies, - dataFiles: extensions[0].dataFiles, - extensionSqlFileNames: extensions[0].extensionSqlFileNames, - extensionSqlFilePrefixes: extensions[0].extensionSqlFilePrefixes, - nativeModuleStem: extensions[0].nativeModuleStem, - iosNativeDependencies: extensions[0].iosNativeDependencies, - iosRegistration: extensions[0].iosRegistration, - wasixInstall: extensions[0].wasixInstall, - sharedPreloadLibraries: extensions[0].sharedPreloadLibraries, - assets: assets.map(({ name, family, target, kind, identity, sha256, bytes }) => ({ - name, - family, - target, - kind, - identity, - sha256, - bytes, - })), - }), - }, null, 2)}\n`); - writeFileSync(path.join(directory, propertiesName), `schema=oliphaunt-extension-release-manifest-v${bundled ? "2" : "1"}\nproduct=${artifactProduct}\n${artifactProduct === product.id ? "" : `releaseProduct=${product.id}\ncarrierFamily=${family ?? "combined"}\n`}version=${product.version}\n`); - writeFileSync( - path.join(directory, swiftCarrierName), - `${JSON.stringify(buildSwiftExtensionCarrierManifest({ - extensionManifest: extensionManifestPath, - verifyMembers: false, - }), null, 2)}\n`, - ); - const payloadNames = [...directAssets.map((asset) => asset.name), manifestName, propertiesName, swiftCarrierName].sort(); - writeFileSync( - path.join(directory, checksumName), - payloadNames.map((name) => `${sha256File(path.join(directory, name))} ./${name}\n`).join(""), - ); - return { assets: directAssets, directory, manifestPath: extensionManifestPath, swiftCarrierName }; -} - -afterEach(() => { - while (temporaryDirectories.length > 0) { - rmSync(temporaryDirectories.pop(), { recursive: true, force: true }); - } -}); - -describe("canonical publication catalog", () => { - test("projects repeated package dependencies to one sorted internal carrier edge", () => { - const carriers = [ - { id: "npm:@oliphaunt/zeta" }, - { id: "cargo:oliphaunt-tools" }, - { id: "cargo:oliphaunt" }, - ]; - const packageDependencies = [ - { ecosystem: "cargo", name: "oliphaunt-tools", requirement: "=0.1.0", scope: "runtime" }, - { ecosystem: "npm", name: "@oliphaunt/zeta", requirement: "0.1.0", scope: "optional" }, - { ecosystem: "cargo", name: "serde", requirement: "1", scope: "runtime" }, - { ecosystem: "cargo", name: "oliphaunt-tools", requirement: "=0.1.0", scope: "build" }, - { ecosystem: "cargo", name: "oliphaunt-tools", requirement: "=0.1.0", scope: "runtime" }, - ]; - expect(projectInternalDependencyIds(carriers, packageDependencies)).toEqual([ - "cargo:oliphaunt-tools", - "npm:@oliphaunt/zeta", - ]); - }); - - test("normalizes products and stable carriers without duplicate identities", () => { - const catalog = loadPublicationCatalog("publication-lock.test"); - expect(catalog.products).toHaveLength(20); - expect(catalog.carriers).toHaveLength(203); - expect(catalog.carriers.reduce((counts, { ecosystem }) => ({ - ...counts, - [ecosystem]: (counts[ecosystem] ?? 0) + 1, - }), {})).toEqual({ cargo: 103, npm: 77, maven: 23 }); - expect(catalog.products.some(({ id }) => id === "oliphaunt-extension-postgis")).toBe(true); - expect(catalog.carriers.filter(({ product }) => product === "oliphaunt-extension-postgis")).toHaveLength(18); - expect(new Set(catalog.carriers.map((carrier) => carrier.id)).size).toBe(catalog.carriers.length); - expect(catalog.carriers.every((carrier) => carrier.declared && carrier.product && carrier.version)).toBe(true); - }); - - test("permits only Cargo part identities as dynamic carriers", () => { - const catalog = loadPublicationCatalog("publication-lock.test", { products: ["liboliphaunt-native"] }); - const part = resolveActualCarrier(catalog, "cargo", "liboliphaunt-native-linux-x64-gnu-part-001"); - expect(part.declared).toBe(false); - expect(part.parentCarrier).toBe("cargo:liboliphaunt-native-linux-x64-gnu"); - expect(part.part).toBe(1); - expect(() => resolveActualCarrier(catalog, "cargo", "liboliphaunt-native-linux-x64-gnu-part-000")).toThrow("1-based"); - expect(() => resolveActualCarrier(catalog, "cargo", "liboliphaunt-native-linux-x64-gnu-part-1000")).toThrow("is not a Cargo payload part crate"); - expect(() => resolveActualCarrier(catalog, "npm", "@oliphaunt/liboliphaunt-linux-x64-gnu-payload-0")).toThrow("dynamic identities are permitted only for Cargo"); - }); - - test("requires every split carrier to use one complete contiguous 1-based part set", () => { - const parent = { - id: "cargo:fixture-linux-x64-gnu", - ecosystem: "cargo", - name: "fixture-linux-x64-gnu", - role: "platform-leaf", - declared: true, - packageDependencies: [ - { ecosystem: "cargo", name: "fixture-linux-x64-gnu-part-001" }, - { ecosystem: "cargo", name: "fixture-linux-x64-gnu-part-002" }, - ], - }; - const part = (number) => ({ - id: `cargo:fixture-linux-x64-gnu-part-${String(number).padStart(3, "0")}`, - ecosystem: "cargo", - name: `fixture-linux-x64-gnu-part-${String(number).padStart(3, "0")}`, - role: "payload-part", - declared: false, - parentCarrier: parent.id, - part: number, - packageDependencies: [], - }); - expect(() => validateCargoPayloadPartSets([part(1), part(2), parent])).not.toThrow(); - expect(() => validateCargoPayloadPartSets([part(1), part(3), { - ...parent, - packageDependencies: [ - { ecosystem: "cargo", name: "fixture-linux-x64-gnu-part-001" }, - { ecosystem: "cargo", name: "fixture-linux-x64-gnu-part-003" }, - ], - }])).toThrow("contiguous from part-001"); - expect(() => validateCargoPayloadPartSets([part(1), parent])).toThrow( - "exactly its complete Cargo payload part set", - ); - }); - - test("keeps contrib WASIX dependencies exact and external dependencies patch-compatible", () => { - expect(extensionDependencyRequirement("0.1.2", "runtime-bound")).toBe("=0.1.2"); - expect(extensionDependencyRequirement("0.3.4", "upstream-bound")).toBe(">=0.3.4,<0.4.0"); - expect(extensionDependencyRequirement("2.3.4", "upstream-bound")).toBe(">=2.3.4,<3.0.0"); - }); -}); - -describe("publication artifact discovery and freezing", () => { - test("publish resolution rejects regenerated paths and mutations", () => { - const root = mkdtempSync(path.join(import.meta.dir, "../../target/publication-lock-publish-")); - temporaryDirectories.push(root); - const frozen = npmFixture(root, "@oliphaunt/test", "1.2.3"); - const artifact = { - path: path.relative(path.join(import.meta.dir, "../.."), frozen).split(path.sep).join("/"), - sha256: sha256File(frozen), - size: readFileSync(frozen).length, - }; - const lock = { - carriers: [{ - id: "npm:@oliphaunt/test", - ecosystem: "npm", - name: "@oliphaunt/test", - version: "1.2.3", - artifacts: [artifact], - }], - }; - - expect(lockedCarrierFile(lock, "npm", "@oliphaunt/test", frozen).file).toBe(frozen); - const regenerated = path.join(root, "regenerated.tgz"); - writeFileSync(regenerated, readFileSync(frozen)); - expect(() => lockedCarrierFile(lock, "npm", "@oliphaunt/test", regenerated)).toThrow( - "attempted to substitute", - ); - writeFileSync(frozen, "regenerated bytes"); - expect(() => lockedCarrierFile(lock, "npm", "@oliphaunt/test", frozen)).toThrow( - "bytes do not match", - ); - }); - - test("reads npm, Cargo, and Maven identities, bytes, and dependencies", () => { - const root = temporaryDirectory(); - npmFixture(root, "@oliphaunt/test", "1.2.3"); - cargoFixture(root, "oliphaunt-test", "1.2.3"); - mavenFixture(root, "dev.oliphaunt", "test", "1.2.3"); - const records = discoverPublicationArtifacts([root]); - expect(records.map((record) => `${record.ecosystem}:${record.name}`).sort()).toEqual([ - "cargo:oliphaunt-test", - "maven:dev.oliphaunt:test", - "npm:@oliphaunt/test", - ]); - expect(records.every((record) => record.artifacts.every((artifact) => artifact.size > 0 && artifact.sha256.length === 64))).toBe(true); - expect(records.find((record) => record.ecosystem === "cargo").dependencies[0].name).toBe("serde"); - }); - - test("freezes repeated target-specific Cargo package rows as one internal carrier edge", () => { - const root = temporaryDirectory(); - const catalog = loadPublicationCatalog("publication-lock.test", { products: ["oliphaunt-rust"] }); - const version = catalog.products[0].version; - cargoFixture(root, "oliphaunt-build", version); - cargoFixture(root, "oliphaunt", version, { - manifestSuffix: [ - "", - "[target.'cfg(target_os = \"linux\")'.dependencies]", - `oliphaunt-build = \"=${version}\"`, - "", - "[target.'cfg(target_os = \"macos\")'.dependencies]", - `oliphaunt-build = \"=${version}\"`, - "", - "[target.'cfg(target_os = \"windows\")'.dependencies]", - `oliphaunt-build = \"=${version}\"`, - "", - ].join("\n"), - }); - - const candidate = buildPublicationCandidate({ - products: ["oliphaunt-rust"], - artifactRoots: [root], - }); - const facade = candidate.carriers.find(({ id }) => id === "cargo:oliphaunt"); - expect(facade.packageDependencies.filter(({ name }) => name === "oliphaunt-build")).toHaveLength(3); - expect(facade.dependencies).toEqual(["cargo:oliphaunt-build"]); - expect(() => freezePublicationCandidate(candidate)).not.toThrow(); - - const duplicatedEdge = structuredClone(candidate); - duplicatedEdge.carriers.find(({ id }) => id === "cargo:oliphaunt").dependencies.push("cargo:oliphaunt-build"); - expect(() => validatePublicationCandidate(duplicatedEdge)).toThrow( - "cargo:oliphaunt.dependencies must be sorted and contain no duplicates", - ); - }); - - test("rejects frozen npm tarballs that cannot use trusted publishing", () => { - for (const [label, overrides, pattern] of [ - ["missing-repository", { repository: undefined }, /repository must be an object/u], - [ - "wrong-repository", - { repository: { type: "git", url: "https://github.com/example/other" } }, - /repository\.url must exactly match/u, - ], - [ - "provenance-disabled", - { publishConfig: { access: "public", provenance: false } }, - /must not disable npm provenance/u, - ], - ]) { - const root = temporaryDirectory(); - npmFixture(root, `@oliphaunt/${label}`, "1.2.3", overrides); - expect(() => discoverPublicationArtifacts([root])).toThrow(pattern); - } - }); - - test("reads the root npm manifest when a dependency is bundled", () => { - const root = temporaryDirectory(); - npmFixture(root, "@oliphaunt/ts", "1.2.3", {}, { - name: "@oliphaunt/js-core", - version: "0.0.0", - }); - expect(discoverPublicationArtifacts([root])).toMatchObject([{ - ecosystem: "npm", - name: "@oliphaunt/ts", - version: "1.2.3", - }]); - }); - - test("freezes an exhaustive product carrier set and detects tampering", () => { - const root = temporaryDirectory(); - const catalog = loadPublicationCatalog("publication-lock.test", { products: ["oliphaunt-js"] }); - const version = catalog.products[0].version; - npmFixture(root, "@oliphaunt/ts", version); - const candidate = buildPublicationCandidate({ - products: ["oliphaunt-js"], - artifactRoots: [root], - }); - expect(candidate.missing).toEqual([]); - expect(candidate.carriers).toHaveLength(1); - expect(candidate.packageEnvelopeDigest).toHaveLength(64); - const unknownDependency = structuredClone(candidate); - unknownDependency.carriers[0].dependencies = ["npm:@oliphaunt/not-frozen"]; - expect(() => validatePublicationCandidate(unknownDependency)).toThrow(/internal package dependency identities/u); - const nonCanonicalIdentity = structuredClone(candidate); - nonCanonicalIdentity.carriers[0].id = "npm:wrong-name"; - expect(() => validatePublicationCandidate(nonCanonicalIdentity)).toThrow(/canonical/u); - const lock = freezePublicationCandidate(candidate); - expect(validatePublicationLock(lock)).toBe(lock); - const tampered = structuredClone(lock); - tampered.carriers[0].artifacts[0].size += 1; - expect(() => validatePublicationLock(tampered)).toThrow(/Digest mismatch|digest mismatch|packageEnvelopeDigest/u); - }); - - test("structural lock verification remains valid after registry payload handoff cleanup", () => { - const root = temporaryDirectory(); - const catalog = loadPublicationCatalog("publication-lock.test", { products: ["oliphaunt-js"] }); - const version = catalog.products[0].version; - const npm = npmFixture(root, "@oliphaunt/ts", version); - const lock = freezePublicationCandidate(buildPublicationCandidate({ - products: ["oliphaunt-js"], - artifactRoots: [root], - })); - const lockFile = path.join(root, "publication-lock.json"); - writeFileSync(lockFile, `${JSON.stringify(lock, null, 2)}\n`); - rmSync(npm, { force: true }); - - const result = spawnSync(process.execPath, [ - "tools/release/publication-lock.mjs", - "verify", - "--lock", - lockFile, - "--head-ref", - "HEAD", - ], { cwd: path.resolve(import.meta.dir, "../.."), encoding: "utf8" }); - expect(result.status).toBe(0); - expect(result.stdout).toContain("publication lock verified"); - }); - - test("projects broad artifact roots through the full catalog onto selected products", () => { - const root = temporaryDirectory(); - const selectedCatalog = loadPublicationCatalog("publication-lock.test", { - products: ["oliphaunt-js"], - }); - const selectedVersion = selectedCatalog.products[0].version; - npmFixture(root, "@oliphaunt/ts", selectedVersion); - - const fullCatalog = loadPublicationCatalog("publication-lock.test"); - const unselected = fullCatalog.carriers.find((carrier) => - carrier.ecosystem === "cargo" - && carrier.product === "oliphaunt-rust" - && carrier.name === "oliphaunt"); - expect(unselected).toBeDefined(); - cargoFixture(root, unselected.name, unselected.version); - cargoFixture(root, unselected.name, "999.0.0"); - const unselectedNpm = fullCatalog.carriers.find((carrier) => - carrier.ecosystem === "npm" - && carrier.product === "oliphaunt-broker"); - expect(unselectedNpm).toBeDefined(); - npmFixture( - path.join(root, "unselected-a"), - unselectedNpm.name, - unselectedNpm.version, - { description: "first unselected carrier bytes" }, - ); - npmFixture( - path.join(root, "unselected-b"), - unselectedNpm.name, - unselectedNpm.version, - { description: "second unselected carrier bytes" }, - ); - - const candidate = buildPublicationCandidate({ - products: ["oliphaunt-js"], - artifactRoots: [root], - }); - expect(candidate.carriers.map((carrier) => `${carrier.ecosystem}:${carrier.name}`)).toEqual([ - "npm:@oliphaunt/ts", - ]); - expect(candidate.carriers.every((carrier) => carrier.product === "oliphaunt-js")).toBe(true); - - const conflictingSelected = npmFixture( - path.join(root, "selected-conflict"), - "@oliphaunt/ts", - selectedVersion, - { description: "ambiguous selected carrier bytes" }, - ); - expect(() => buildPublicationCandidate({ - products: ["oliphaunt-js"], - artifactRoots: [root], - })).toThrow(/duplicate artifact identity npm:@oliphaunt\/ts@.+ conflicting candidate bytes/u); - unlinkSync(conflictingSelected); - - cargoFixture(root, "undeclared-publication-carrier", "1.2.3"); - expect(() => buildPublicationCandidate({ - products: ["oliphaunt-js"], - artifactRoots: [root], - })).toThrow(/artifact identity cargo:undeclared-publication-carrier is not declared/u); - }); - - test("freezes exact GitHub assets and rejects tampering, missing assets, and extras", () => { - const root = temporaryDirectory(); - const product = loadPublicationCatalog("publication-lock.test", { products: ["oliphaunt-broker"] }).products[0]; - const { checksum, directory, rows } = githubReleaseFixture(root, product); - const artifacts = discoverProductArtifacts([root], [product]); - expect(artifacts).toHaveLength(rows.length); - expect(artifacts.every((artifact) => artifact.role === "github-release-asset" && artifact.sha256.length === 64)).toBe(true); - - const payload = rows.find((row) => row !== checksum); - const payloadPath = path.join(directory, payload.name); - writeFileSync(payloadPath, "tampered\n"); - expect(() => discoverProductArtifacts([root], [product])).toThrow("checksum"); - writeFileSync(payloadPath, `fixture:${payload.name}\n`); - - unlinkSync(payloadPath); - expect(() => discoverProductArtifacts([root], [product])).toThrow(/requires exactly one|asset set mismatch/u); - writeFileSync(payloadPath, `fixture:${payload.name}\n`); - - writeFileSync(path.join(directory, "undeclared.zip"), "extra\n"); - expect(() => discoverProductArtifacts([root], [product])).toThrow("extra"); - }); - - test("freezes every declared extension OS target plus public metadata", () => { - const root = temporaryDirectory(); - const product = loadPublicationCatalog("publication-lock.test", { products: ["oliphaunt-extension-vector"] }).products[0]; - const { assets, directory, manifestPath, swiftCarrierName } = extensionGithubReleaseFixture(root, product); - const artifacts = discoverProductArtifacts([root], [product]); - expect(artifacts).toHaveLength(assets.length + 4); - expect(new Set(artifacts.filter((artifact) => artifact.role === "github-release-asset").map((artifact) => artifact.target))).toEqual( - new Set(extensionArtifactTargets({ product: product.id }, "publication-lock.test").map((target) => target.target)), - ); - - const swiftCarrierPath = path.join(directory, swiftCarrierName); - const incompatibleCarrier = JSON.parse(readFileSync(swiftCarrierPath, "utf8")); - incompatibleCarrier.base.version = "9.9.9"; - incompatibleCarrier.base.tag = "liboliphaunt-native-v9.9.9"; - writeFileSync(swiftCarrierPath, `${JSON.stringify(incompatibleCarrier, null, 2)}\n`); - expect(() => discoverProductArtifacts([root], [product])).toThrow("compatible native base"); - - extensionGithubReleaseFixture(root, product); - - const manifest = JSON.parse(readFileSync(manifestPath, "utf8")); - const missingRole = manifest.assets.find((asset) => asset.kind === "ios-xcframework"); - manifest.assets = manifest.assets.filter((asset) => asset !== missingRole); - writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); - unlinkSync(path.join(directory, missingRole.name)); - expect(() => discoverProductArtifacts([root], [product])).toThrow("roles"); - - extensionGithubReleaseFixture(root, product); - writeFileSync(path.join(directory, "undeclared-extension-asset.tar.gz"), "extra\n"); - expect(() => discoverProductArtifacts([root], [product])).toThrow("extra"); - - extensionGithubReleaseFixture(root, product); - const publicManifestPath = path.join(directory, `${product.id}-${product.version}-manifest.json`); - const forgedPublicManifest = JSON.parse(readFileSync(publicManifestPath, "utf8")); - forgedPublicManifest.versioning = "independent"; - forgedPublicManifest.sourceIdentity = { kind: "external", name: "forged", url: "https://invalid.example", branch: "main", commit: "0".repeat(40) }; - writeFileSync(publicManifestPath, `${JSON.stringify(forgedPublicManifest, null, 2)}\n`); - expect(() => discoverProductArtifacts([root], [product])).toThrow(/canonical extension identity/u); - - extensionGithubReleaseFixture(root, product); - const forgedCiManifest = JSON.parse(readFileSync(manifestPath, "utf8")); - forgedCiManifest.compatibility.nativeRuntimeVersion = "9.9.9"; - writeFileSync(manifestPath, `${JSON.stringify(forgedCiManifest, null, 2)}\n`); - expect(() => discoverProductArtifacts([root], [product])).toThrow(/does not describe/u); - - extensionGithubReleaseFixture(root, product); - const forgedInventoryManifest = JSON.parse(readFileSync(manifestPath, "utf8")); - forgedInventoryManifest.dataFiles = [...forgedInventoryManifest.dataFiles, "undeclared/foreign.sql"].sort(); - writeFileSync(manifestPath, `${JSON.stringify(forgedInventoryManifest, null, 2)}\n`); - expect(() => discoverProductArtifacts([root], [product])).toThrow(/semantic extension metadata is not canonical generated metadata/u); - }); - - test("freezes the exact contrib bundle member set under one release owner", { timeout: 20_000 }, () => { - const root = temporaryDirectory(); - const artifactProduct = "oliphaunt-extension-contrib-pg18"; - const product = loadPublicationCatalog("publication-lock.test", { products: ["liboliphaunt-native"] }).products[0]; - const fixtureOptions = { artifactProduct, family: "native" }; - const { rows: runtimeAssets } = githubReleaseFixture(root, product); - const { assets, manifestPath } = extensionGithubReleaseFixture(root, product, fixtureOptions); - const artifacts = discoverProductArtifacts([root], [product]); - expect(artifacts).toHaveLength(runtimeAssets.length + assets.length + 4); - expect(assets.every(({ name }) => /^oliphaunt-extension-contrib-pg18-[^-]+/u.test(name))).toBe(true); - const candidate = buildPublicationCandidate({ - products: [product.id], - artifactRoots: [root], - allowMissing: true, - }); - expect(candidate.missing.length).toBeGreaterThan(0); - expect(() => validatePublicationCandidate(candidate)).not.toThrow(); - - const wrongCarrierIdentity = structuredClone(candidate); - wrongCarrierIdentity.productArtifacts.find(({ role }) => role === "github-release-asset").identity = - "wrong-family"; - expect(() => validatePublicationCandidate(wrongCarrierIdentity)).toThrow( - /packageEnvelopeDigest mismatch|incorrect target, kind, or identity metadata/u, - ); - - const manifest = JSON.parse(readFileSync(manifestPath, "utf8")); - manifest.extensions.pop(); - writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); - expect(() => discoverProductArtifacts([root], [product])).toThrow("exact sorted bundle member set"); - - extensionGithubReleaseFixture(root, product, fixtureOptions); - const forgedMemberInventory = JSON.parse(readFileSync(manifestPath, "utf8")); - forgedMemberInventory.extensions[0].extensionSqlFilePrefixes = [ - ...forgedMemberInventory.extensions[0].extensionSqlFilePrefixes, - "undeclared-prefix", - ].sort(); - writeFileSync(manifestPath, `${JSON.stringify(forgedMemberInventory, null, 2)}\n`); - expect(() => discoverProductArtifacts([root], [product])).toThrow(/semantic extension metadata is not canonical generated metadata/u); - - extensionGithubReleaseFixture(root, product, fixtureOptions); - const publicManifestPath = path.join(path.dirname(manifestPath), "release-assets", `${artifactProduct}-${product.version}-manifest.json`); - const forgedPublicManifest = JSON.parse(readFileSync(publicManifestPath, "utf8")); - forgedPublicManifest.compatibility.wasixRuntimeVersion = "9.9.9"; - writeFileSync(publicManifestPath, `${JSON.stringify(forgedPublicManifest, null, 2)}\n`); - expect(() => discoverProductArtifacts([root], [product])).toThrow(/frozen aggregate member\/carrier inventory/u); - }); - - test("rejects stale, missing, extra, substituted, or wrongly-moded aggregate bundle legal material", { timeout: 60_000 }, () => { - const artifactProduct = "oliphaunt-extension-contrib-pg18"; - const product = loadPublicationCatalog("publication-lock.test", { - products: ["liboliphaunt-native"], - }).products[0]; - const reject = (options, expected) => { - const root = temporaryDirectory(); - githubReleaseFixture(root, product); - extensionGithubReleaseFixture(root, product, { ...options, artifactProduct, family: "native" }); - expect(() => discoverProductArtifacts([root], [product])).toThrow(expected); - }; - - reject({ - mutateBundleStage({ bundleManifest }) { - const manifest = JSON.parse(readFileSync(bundleManifest, "utf8")); - delete manifest.licenseProfile; - writeFileSync(bundleManifest, `${JSON.stringify(manifest, null, 2)}\n`); - }, - }, /bundle-manifest\.json does not exactly freeze its nested member and legal locators/u); - - reject({ - mutateBundleStage({ stage }) { - unlinkSync(path.join(stage, "LICENSE")); - }, - }, /contains undeclared or missing regular bundle members/u); - - reject({ - mutateBundleStage({ stage }) { - writeFileSync(path.join(stage, "UNDECLARED.txt"), "undeclared\n"); - }, - }, /contains undeclared or missing regular bundle members/u); - - reject({ - mutateBundleStage({ stage }) { - writeFileSync(path.join(stage, "LICENSE"), "substituted legal bytes\n"); - }, - }, /legal member .*\/LICENSE does not match its canonical bytes and mode/u); - - reject({ - bundleFixedFileMode: null, - mutateBundleStage({ stage }) { - chmodSync(path.join(stage, "LICENSE"), 0o600); - }, - }, /member .*\/LICENSE must be a canonical regular mode=0644 uid=0 gid=0 mtime=0 file/u); - }); - - test("rejects bundle encodings that supported mobile consumers reject", { timeout: 60_000 }, () => { - const artifactProduct = "oliphaunt-extension-contrib-pg18"; - const product = loadPublicationCatalog("publication-lock.test", { - products: ["liboliphaunt-native"], - }).products[0]; - const reject = (options, expected) => { - const root = temporaryDirectory(); - githubReleaseFixture(root, product); - extensionGithubReleaseFixture(root, product, { ...options, artifactProduct, family: "native" }); - expect(() => discoverProductArtifacts([root], [product])).toThrow(expected); - }; - - reject({ - mutateBundleStage({ bundleManifest }) { - const manifest = JSON.parse(readFileSync(bundleManifest, "utf8")); - writeFileSync(bundleManifest, `${JSON.stringify(manifest)}\n`); - }, - }, /bundle-manifest\.json must use the exact canonical bytes/u); - - reject({ - mutateBundleArchive({ output }) { - const bytes = readFileSync(output); - bytes[9] = 0; - writeFileSync(output, bytes); - }, - }, /canonical gzip method, flags, mtime, XFL, and OS header/u); - - reject({ - mutateBundleArchive({ output }) { - const tar = gunzipSync(readFileSync(output)); - Buffer.from("builder\0", "ascii").copy(tar, 265); - refreshTarHeaderChecksum(tar); - writeFileSync(output, canonicalGzipSync(tar)); - }, - }, /exact deterministic POSIX ustar file encoding/u); - }); - - test("keeps SQL-only mobile extensions resource-only", () => { - const root = temporaryDirectory(); - const product = loadPublicationCatalog("publication-lock.test", { products: ["oliphaunt-extension-pgtap"] }).products[0]; - extensionGithubReleaseFixture(root, product); - const artifacts = discoverProductArtifacts([root], [product]); - const mobile = artifacts.filter((artifact) => artifact.role === "github-release-asset" && ( - artifact.target === "ios-xcframework" || artifact.target.startsWith("android-") - )); - expect(mobile.every((artifact) => artifact.kind === "runtime" && artifact.identity === null)).toBe(true); - }); - - test("freezes a selection-neutral Swift source carrier and separately composed dependency-closed output", () => { - const workspaceRoot = mkdtempSync(path.join(import.meta.dir, "../../target/publication-lock-swift-")); - temporaryDirectories.push(workspaceRoot); - const sdk = path.join(workspaceRoot, "sdk-artifacts/oliphaunt-swift"); - const fixture = path.join(workspaceRoot, "release/swiftpm-extension-consumer-fixture"); - mkdirSync(path.join(sdk, "extension-generator"), { recursive: true }); - mkdirSync(path.join(sdk, "release-tree/src/sdks/swift/Carriers"), { recursive: true }); - mkdirSync(path.join(fixture, "Sources/OliphauntExtensionPgtap/Resources/extension-artifact"), { recursive: true }); - writeFileSync(path.join(sdk, "Oliphaunt-source.zip"), "source archive\n"); - writeFileSync(path.join(sdk, "Package.swift.release"), "// release manifest fixture\n"); - for (const name of [ - "extension-owner-catalog.json", - "extension-resource-inventory.mjs", - "render-extension-products.mjs", - "swift-carrier-resolver.mjs", - "swiftpm-extension-input.schema.json", - ]) { - writeFileSync( - path.join(sdk, "extension-generator", name), - name === "extension-owner-catalog.json" - ? readFileSync(path.join(import.meta.dir, "../../src/extensions/generated/sdk/extensions.json")) - : name === "extension-resource-inventory.mjs" - ? readFileSync(path.join(import.meta.dir, "../../src/sdks/swift/tools/extension-resource-inventory.mjs")) - : `${name}\n`, - ); - } - const sourceCarrier = path.join( - sdk, - "release-tree/src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json", - ); - const canonicalSourceCarrier = selectionNeutralSwiftSourceCarrier( - productCompatibilityVersion( - "oliphaunt-swift", - "liboliphaunt-native", - "publication-lock.test", - ), - ); - writeFileSync(sourceCarrier, `${JSON.stringify(canonicalSourceCarrier)}\n`); - const baseXcframework = canonicalSourceCarrier.base.assets.find(({ role }) => role === "base-xcframework"); - writeFileSync( - path.join(sdk, "Package.swift.release"), - `.binaryTarget(\n name: "liboliphaunt",\n url: "${baseXcframework.url}",\n checksum: "${baseXcframework.sha256}"\n)\n`, - ); - writeFileSync(path.join(fixture, "Package.swift"), "// generated consumer\n"); - writeFileSync(path.join(fixture, "extension-products.json"), '{"schema":"oliphaunt-swiftpm-extension-products-v1"}\n'); - writeFileSync(path.join(fixture, "Sources/OliphauntExtensionPgtap/Resources/extension-artifact/pgtap.control"), "default_version='1.0'\n"); - - const catalog = loadPublicationCatalog("publication-lock.test", { - products: ["oliphaunt-swift", "oliphaunt-extension-pgtap"], - }); - const product = catalog.products.find(({ id }) => id === "oliphaunt-swift"); - const extensionProduct = catalog.products.find(({ id }) => id === "oliphaunt-extension-pgtap"); - expect(product).toBeDefined(); - expect(extensionProduct).toBeDefined(); - const { manifestPath } = extensionGithubReleaseFixture(workspaceRoot, extensionProduct); - const extensionRoot = path.dirname(manifestPath); - const selectedRoots = [sdk, fixture, extensionRoot]; - - expect(() => discoverProductArtifacts([sdk, fixture], [product])).toThrow( - /selects no extension products and requires no frozen Swift consumer fixture/u, - ); - expect(() => discoverProductArtifacts([sdk, extensionRoot], catalog.products)).toThrow( - /selects extension products and requires exactly one frozen Swift consumer fixture/u, - ); - - const artifacts = discoverProductArtifacts(selectedRoots, catalog.products); - const swiftArtifacts = artifacts.filter((artifact) => artifact.product === product.id); - expect(swiftArtifacts.map(({ id }) => id).sort()).toEqual([ - "release-input:Oliphaunt-source.zip", - "release-input:Package.swift.release", - "release-input:extension-owner-catalog.json", - "release-input:extension-resource-inventory.mjs", - "release-input:oliphaunt-react-native-ios-carriers.json", - "release-input:render-extension-products.mjs", - "release-input:swift-carrier-resolver.mjs", - "release-input:swiftpm-extension-consumer-fixture", - "release-input:swiftpm-release-tree", - ]); - expect(() => assertLockedProductArtifacts( - { productArtifacts: artifacts, products: catalog.products }, - product.id, - [sdk, fixture], - )).not.toThrow(); - const frozenFixture = swiftArtifacts.find(({ id }) => id === "release-input:swiftpm-extension-consumer-fixture"); - writeFileSync(path.join(fixture, "Sources/OliphauntExtensionPgtap/Resources/extension-artifact/pgtap.control"), "tampered\n"); - const tamperedFixture = discoverProductArtifacts(selectedRoots, catalog.products) - .find(({ id, product: artifactProduct }) => - artifactProduct === product.id - && id === "release-input:swiftpm-extension-consumer-fixture"); - expect(tamperedFixture.sha256).not.toBe(frozenFixture.sha256); - - const selectedSourceCarrier = structuredClone(canonicalSourceCarrier); - selectedSourceCarrier.extensions.push({ sqlName: "pgtap" }); - writeFileSync(sourceCarrier, `${JSON.stringify(selectedSourceCarrier)}\n`); - expect(() => discoverProductArtifacts(selectedRoots, catalog.products)).toThrow( - /ios-carriers\.json\.extensions.*selection-neutral/u, - ); - - const malformedSourceCarrier = structuredClone(canonicalSourceCarrier); - delete malformedSourceCarrier.carriers; - writeFileSync(sourceCarrier, `${JSON.stringify(malformedSourceCarrier)}\n`); - expect(() => discoverProductArtifacts(selectedRoots, catalog.products)).toThrow( - /ios-carriers\.json.*fields must be exactly/u, - ); - writeFileSync(sourceCarrier, `${JSON.stringify(canonicalSourceCarrier)}\n`); - - writeFileSync( - path.join(sdk, "extension-generator/extension-resource-inventory.mjs"), - "// forged inventory validator\n", - ); - expect(() => discoverProductArtifacts(selectedRoots, catalog.products)).toThrow( - /frozen extension-resource-inventory\.mjs must exactly match/u, - ); - }); -}); diff --git a/tools/release/publication-lock.test.mts b/tools/release/publication-lock.test.mts new file mode 100644 index 000000000..6a63dac8f --- /dev/null +++ b/tools/release/publication-lock.test.mts @@ -0,0 +1,1479 @@ +import { afterEach, describe, expect, test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + unlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { gunzipSync } from 'node:zlib'; +import { + extensionCarrierLegalContract, + stageExtensionUpstreamLicenses, +} from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { extensionDependencyRequirement } from '../../src/runtimes/liboliphaunt-wasix/tools/package_liboliphaunt_wasix_cargo_artifacts.mts'; +import { + buildSwiftExtensionCarrierManifest, + iosBaseLegalMetadata, + swiftExtensionCarrierAssetName, +} from '../../src/sdks/swift/tools/ios-carrier-manifest.mts'; +import { createDeterministicTar } from '../packaging/cargo-source-package.mts'; +import { releaseJavaScript } from '../packaging/emit-javascript.mts'; +import { canonicalGzipSync } from '../packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../packaging/release-notices.mts'; +import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; +import { + assertLockedArtifactSet, + assertLockedProductArtifacts, + assertPublicationLockSource, + buildPublicationCandidate, + discoverProductArtifacts, + discoverPublicationArtifacts, + freezePublicationCandidate, + lockedCarrierFile, + projectInternalDependencyIds, + validateCargoPayloadPartSets, + validatePublicationCandidate, + validatePublicationLock, +} from './publication-lock.mts'; +import { + allArtifactTargets, + currentProductVersionSync, + extensionArtifactProductRoot, + extensionArtifactTargets, + extensionMetadata, + extensionSourceIdentity, + extensionSqlNames, +} from './release-artifact-targets.mts'; +import { productCompatibilityVersion } from './release-graph.mts'; + +const temporaryDirectories = []; + +if (process.argv[2] === 'prepare-handoff') { + const root = process.argv[3]; + const catalog = loadPublicationCatalog('publication-lock.test', { products: ['oliphaunt-js'] }); + const npm = npmFixture(root, '@oliphaunt/ts', catalog.products[0].version); + const lock = freezePublicationCandidate( + buildPublicationCandidate({ products: ['oliphaunt-js'], artifactRoots: [root] }), + ); + writeFileSync(path.join(root, 'publication-lock.json'), `${JSON.stringify(lock, null, 2)}\n`); + rmSync(npm); + process.exit(0); +} +if (process.argv[2] === 'assert-source') { + const snapshot = JSON.parse(process.env.OLIPHAUNT_GIT_SOURCE_JSON); + const lock = { source: { commit: snapshot.commit, tree: snapshot.tree } }; + assert.deepEqual(assertPublicationLockSource(lock, snapshot.ref), lock.source); + assert.deepEqual(assertPublicationLockSource(lock, snapshot.commit), lock.source); + assert.throws( + () => + assertPublicationLockSource( + { source: { ...lock.source, tree: 'f'.repeat(40) } }, + snapshot.ref, + ), + /does not match/, + ); + if (snapshot.checkout === snapshot.commit) { + assert.deepEqual(assertPublicationLockSource(lock, 'HEAD'), lock.source); + } else { + assert.throws(() => assertPublicationLockSource(lock, 'HEAD'), /matching Git snapshot/); + } + process.exit(0); +} + +test('frozen Cargo bytes reject a changed archive header with unchanged package identity', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-frozen-cargo-')); + temporaryDirectories.push(root); + const file = cargoFixture(root, 'fixture', '1.2.3'); + const records = discoverPublicationArtifacts([file]); + const lock = { + carriers: records.map((record) => ({ + ...record, + id: 'cargo:' + record.name, + product: 'fixture', + })), + }; + expect(() => assertLockedArtifactSet(lock, records, { product: 'fixture' })).not.toThrow(); + const bytes = readFileSync(file); + bytes[4] ^= 1; + writeFileSync(file, bytes); + expect(() => + assertLockedArtifactSet(lock, discoverPublicationArtifacts([file]), { product: 'fixture' }), + ).toThrow(/frozen artifact bytes mismatch/u); +}); + +function sortJsonValue(value) { + if (Array.isArray(value)) return value.map(sortJsonValue); + if (value !== null && typeof value === 'object') { + return Object.fromEntries( + Object.keys(value) + .sort() + .map((key) => [key, sortJsonValue(value[key])]), + ); + } + return value; +} + +function canonicalJson(value) { + return `${JSON.stringify(sortJsonValue(value), null, 2)}\n`; +} + +function wasixInstall(sqlName, dependencies, createsExtension) { + return { + schema: 'oliphaunt-wasix-extension-install-v1', + name: sqlName, + nativeModule: null, + nativeModules: [], + coreExportsRequired: [], + dependencies, + loadOrder: [], + lifecycle: { + createExtension: createsExtension, + createSchema: 'pg_catalog', + loadSql: [], + postCreateSql: [], + startupConfig: [], + preloadRequired: false, + restartRequired: false, + sharedMemoryRequired: false, + }, + installedFiles: [`share/postgresql/extension/${sqlName}.control`], + unresolvedImports: [], + }; +} + +function refreshTarHeaderChecksum(tar, offset = 0) { + tar.fill(0x20, offset + 148, offset + 156); + const checksum = tar.subarray(offset, offset + 512).reduce((total, byte) => total + byte, 0); + Buffer.from(`${checksum.toString(8).padStart(6, '0')}\0 `, 'ascii').copy(tar, offset + 148); +} + +function temporaryDirectory() { + const directory = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-publication-lock-')); + temporaryDirectories.push(directory); + return directory; +} + +function selectionNeutralSwiftSourceCarrier(version = '1.2.3') { + const product = 'liboliphaunt-native'; + const tag = `${product}-v${version}`; + const assets = [ + [ + 'base-xcframework', + `liboliphaunt-${version}-apple-spm-xcframework.zip`, + 'zip', + 'liboliphaunt.xcframework', + '1', + ], + [ + 'runtime-resources', + `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`, + 'tar.gz', + 'oliphaunt', + '2', + ], + ].map(([role, name, format, member, digestDigit], index) => ({ + bytes: index + 1, + format, + member, + name, + role, + sha256: digestDigit.repeat(64), + url: `https://github.com/f0rr0/oliphaunt/releases/download/${tag}/${name}`, + })); + return { + base: { assets, product, tag, version }, + carriers: [], + extensions: [], + legal: { base: iosBaseLegalMetadata(), extensions: [] }, + schema: 'oliphaunt-react-native-ios-carrier-v1', + }; +} + +function tarGzip(output, cwd, member) { + writeFileSync( + output, + canonicalGzipSync(createDeterministicTar(path.join(cwd, member), member, {})), + ); +} + +function npmFixture(root, name, version, overrides = {}, bundledManifest = null) { + const stage = path.join(root, 'npm-stage', 'package'); + mkdirSync(stage, { recursive: true }); + writeFileSync( + path.join(stage, 'package.json'), + `${JSON.stringify( + { + name, + version, + repository: { + type: 'git', + url: 'git+https://github.com/f0rr0/oliphaunt.git', + }, + publishConfig: { + access: 'public', + provenance: true, + }, + optionalDependencies: { '@oliphaunt/optional-test': version }, + ...overrides, + }, + null, + 2, + )}\n`, + ); + if (bundledManifest !== null) { + const bundled = path.join(stage, 'node_modules', '@oliphaunt', 'js-core'); + mkdirSync(bundled, { recursive: true }); + writeFileSync(path.join(bundled, 'package.json'), `${JSON.stringify(bundledManifest)}\n`); + } + const output = path.join(root, 'package.tgz'); + tarGzip(output, path.dirname(stage), 'package'); + return output; +} + +function cargoFixture(root, name, version, { manifestSuffix = '' } = {}) { + const directoryName = `${name}-${version}`; + const stage = path.join(root, 'cargo-stage', directoryName); + mkdirSync(path.join(stage, 'src'), { recursive: true }); + writeFileSync( + path.join(stage, 'Cargo.toml'), + `[package]\nname = ${JSON.stringify(name)}\nversion = ${JSON.stringify(version)}\nedition = "2024"\n\n[dependencies]\nserde = "1"\n${manifestSuffix}`, + ); + writeFileSync(path.join(stage, 'src/lib.rs'), 'pub const FIXTURE: bool = true;\n'); + const output = path.join(root, `${directoryName}.crate`); + tarGzip(output, path.dirname(stage), directoryName); + return output; +} + +function mavenFixture(root, group, artifact, version) { + const directory = path.join(root, 'maven', ...group.split('.'), artifact, version); + mkdirSync(directory, { recursive: true }); + const pom = path.join(directory, `${artifact}-${version}.pom`); + writeFileSync( + pom, + `4.0.0${group}${artifact}${version}FixtureFixture publicationhttps://github.com/f0rr0/oliphauntMIThttps://opensource.org/license/mitFixture Maintainerhttps://github.com/f0rr0scm:git:https://github.com/f0rr0/oliphaunt.gitscm:git:ssh://git@github.com/f0rr0/oliphaunt.githttps://github.com/f0rr0/oliphauntexampledependency1\n`, + ); + writeFileSync(path.join(directory, `${artifact}-${version}.jar`), 'fixture'); + writeFileSync(path.join(directory, `${artifact}-${version}-sources.jar`), 'fixture sources'); + writeFileSync(path.join(directory, `${artifact}-${version}-javadoc.jar`), 'fixture javadocs'); + return pom; +} + +function sha256File(file) { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} + +function githubReleaseFixture(root, product) { + const directory = path.join(root, product.id, 'release-assets'); + mkdirSync(directory, { recursive: true }); + const rows = allArtifactTargets( + { + product: product.id, + surface: 'github-release', + }, + 'publication-lock.test', + ).map((target) => ({ + target, + name: target.asset.replaceAll('{version}', product.version), + })); + const checksum = rows.find((row) => row.target.kind === 'checksums'); + for (const row of rows.filter((item) => item !== checksum)) { + writeFileSync(path.join(directory, row.name), `fixture:${row.name}\n`); + } + const checksumLines = rows + .filter((item) => item !== checksum) + .map((row) => `${sha256File(path.join(directory, row.name))} ./${row.name}\n`) + .sort(); + writeFileSync(path.join(directory, checksum.name), checksumLines.join('')); + return { checksum, directory, rows }; +} + +function extensionGithubReleaseFixture( + root, + product, + { + artifactProduct = product.id, + family = null, + mutateBundleArchive = undefined, + mutateBundleStage = undefined, + bundleFixedFileMode = 0o644, + } = {}, +) { + const productRoot = extensionArtifactProductRoot( + artifactProduct, + family ?? 'native', + path.join(root, 'target', 'extension-artifacts'), + 'publication-lock.test', + ); + const directory = path.join(productRoot, 'release-assets'); + rmSync(productRoot, { recursive: true, force: true }); + mkdirSync(directory, { recursive: true }); + const sqlNames = extensionSqlNames(artifactProduct, 'publication-lock.test'); + const bundled = sqlNames.length > 1; + const releaseMetadata = extensionMetadata(artifactProduct, 'publication-lock.test'); + const ownership = + artifactProduct === product.id + ? {} + : { releaseProduct: product.id, family: family ?? 'combined' }; + const compatibility = releaseMetadata.compatibility; + const generated = JSON.parse( + readFileSync( + path.join(import.meta.dir, '../../src/extensions/generated/sdk/extensions.json'), + 'utf8', + ), + ); + const staticLines = readFileSync( + path.join(import.meta.dir, '../../src/extensions/generated/mobile/static-extensions.tsv'), + 'utf8', + ) + .split(/\r?\n/u) + .filter((line) => line.length > 0 && !line.startsWith('#')); + const staticHeader = staticLines[0].split('\t'); + const staticRows = staticLines + .slice(1) + .map((line) => + Object.fromEntries( + staticHeader.map((column, index) => [column, line.split('\t')[index] ?? '']), + ), + ); + const assets = []; + const extensions = []; + for (const sqlName of sqlNames) { + const extension = generated.extensions.find((row) => row['sql-name'] === sqlName); + const nativeModuleStem = extension['native-module-stem']; + const staticRow = staticRows.find((row) => row['sql-name'] === sqlName); + const iosNativeDependencies = + nativeModuleStem === null + ? [] + : (staticRow?.['ios-static-dependencies'] ?? '').split(',').filter(Boolean).sort(); + const memberAssets = []; + for (const target of extensionArtifactTargets( + { product: artifactProduct }, + 'publication-lock.test', + ).filter((row) => row.sqlName === sqlName && (family === null || row.family === family))) { + const roles = + target.family === 'wasix' + ? ['wasix-runtime'] + : target.target === 'ios-xcframework' + ? [ + 'runtime', + ...(nativeModuleStem === null + ? [] + : [ + 'ios-xcframework', + ...iosNativeDependencies.map( + (dependency) => `ios-dependency-xcframework:${dependency}`, + ), + ]), + ] + : ['runtime']; + for (const role of roles) { + const [kind, dependencyIdentity] = role.split(':'); + const identity = + kind === 'ios-xcframework' + ? nativeModuleStem + : kind === 'ios-dependency-xcframework' + ? dependencyIdentity + : null; + const prefix = `${artifactProduct}-${product.version}`; + const name = + target.family === 'wasix' + ? `${prefix}-wasix-portable.tar.zst` + : kind === 'ios-xcframework' + ? `${prefix}-native-ios-xcframework.zip` + : kind === 'ios-dependency-xcframework' + ? `${prefix}-native-ios-dependency-${identity}-xcframework.zip` + : target.target === 'ios-xcframework' + ? `${prefix}-native-ios-runtime.tar.gz` + : `${prefix}-native-${target.target}-runtime.tar.gz`; + const file = path.join( + bundled ? path.join(productRoot, 'member-assets', sqlName) : directory, + name, + ); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, `fixture:${name}\n`); + const asset = { + name, + family: target.family, + target: target.target, + kind, + identity, + path: file, + sha256: sha256File(file), + bytes: readFileSync(file).length, + }; + assets.push(asset); + memberAssets.push(asset); + } + } + const dependencies = [...extension['selected-extension-dependencies']].sort(); + const createsExtension = extension['creates-extension'] !== false; + const stagesIos = memberAssets.some((asset) => asset.target === 'ios-xcframework'); + extensions.push({ + sqlName, + createsExtension, + dependencies, + dataFiles: [...extension['runtime-share-data-files']].sort(), + extensionSqlFileNames: [...extension['extension-sql-file-names']].sort(), + extensionSqlFilePrefixes: [...extension['extension-sql-file-prefixes']].sort(), + nativeModuleStem, + iosNativeDependencies: stagesIos ? iosNativeDependencies : [], + iosRegistration: + nativeModuleStem === null || !stagesIos + ? null + : { + schema: 'oliphaunt-ios-extension-registration-v1', + sqlName, + nativeModuleStem, + magicSymbol: `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}_Pg_magic_func`, + initSymbol: null, + symbols: [], + }, + wasixInstall: memberAssets.some((asset) => asset.family === 'wasix') + ? wasixInstall(sqlName, dependencies, createsExtension) + : null, + sharedPreloadLibraries: [...extension['shared-preload-libraries']].sort(), + assets: memberAssets, + }); + } + const carrierAssets = []; + if (bundled) { + const groups = new Map(); + for (const extension of extensions) { + for (const asset of extension.assets) { + const key = `${asset.family}\0${asset.target}`; + const group = groups.get(key) ?? { family: asset.family, target: asset.target, rows: [] }; + group.rows.push({ sqlName: extension.sqlName, asset }); + groups.set(key, group); + } + } + for (const group of [...groups.values()].sort((left, right) => + `${left.family}\0${left.target}`.localeCompare(`${right.family}\0${right.target}`), + )) { + const archiveRoot = `${artifactProduct}-${product.version}-${group.family}-${group.target}-bundle`; + const stage = path.join(productRoot, 'bundle-stage', archiveRoot); + rmSync(stage, { recursive: true, force: true }); + mkdirSync(stage, { recursive: true }); + const manifestMembers = []; + for (const { sqlName, asset } of group.rows.sort((left, right) => + `${left.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ''}`.localeCompare( + `${right.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ''}`, + ), + )) { + const memberPath = `extensions/${sqlName}/${asset.name}`; + const destination = path.join(stage, ...memberPath.split('/')); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, readFileSync(asset.path)); + asset.carrierAsset = `${archiveRoot}.tar.gz`; + asset.carrierRoot = archiveRoot; + asset.memberPath = memberPath; + manifestMembers.push({ + sqlName, + kind: asset.kind, + identity: asset.identity, + path: memberPath, + sha256: asset.sha256, + bytes: asset.bytes, + }); + } + const memberNames = [...new Set(manifestMembers.map(({ sqlName }) => sqlName))].sort(); + const legal = extensionCarrierLegalContract(artifactProduct, memberNames, { + family: group.family, + target: group.target, + }); + for (const sqlName of memberNames) stageExtensionUpstreamLicenses(sqlName, stage); + const bundleManifest = path.join(stage, 'bundle-manifest.json'); + writeFileSync( + bundleManifest, + canonicalJson({ + schema: 'oliphaunt-extension-bundle-v1', + product: artifactProduct, + version: product.version, + compatibility, + family: group.family, + target: group.target, + licenseProfile: legal.profile, + licenseFiles: legal.licenseFiles, + members: manifestMembers, + }), + ); + stageReleaseNotices(stage, { profile: legal.profile }); + mutateBundleStage?.({ + archiveRoot, + bundleManifest, + family: group.family, + legal, + stage, + target: group.target, + }); + const output = path.join(directory, `${archiveRoot}.tar.gz`); + const tarOptions = { + includeDirectories: false, + fail(message) { + throw new Error(`publication lock fixture: ${message}`); + }, + }; + if (bundleFixedFileMode !== null) tarOptions.fixedFileMode = bundleFixedFileMode; + writeFileSync( + output, + canonicalGzipSync(createDeterministicTar(stage, archiveRoot, tarOptions)), + ); + mutateBundleArchive?.({ + archiveRoot, + family: group.family, + output, + target: group.target, + }); + carrierAssets.push({ + name: path.basename(output), + path: output, + sha256: sha256File(output), + bytes: readFileSync(output).length, + family: group.family, + target: group.target, + kind: 'extension-bundle', + memberCount: sqlNames.length, + }); + } + } + const extensionManifestPath = path.join(productRoot, 'extension-artifacts.json'); + const extensionManifest = bundled + ? { + schema: 'oliphaunt-extension-ci-artifacts-v2', + product: artifactProduct, + ...ownership, + version: product.version, + compatibility, + extensions, + carrierAssets, + } + : { + schema: 'oliphaunt-extension-ci-artifacts-v1', + product: artifactProduct, + ...ownership, + version: product.version, + compatibility, + ...extensions[0], + }; + writeFileSync(extensionManifestPath, `${JSON.stringify(extensionManifest, null, 2)}\n`); + const manifestName = `${artifactProduct}-${product.version}-manifest.json`; + const propertiesName = `${artifactProduct}-${product.version}-manifest.properties`; + const swiftCarrierName = swiftExtensionCarrierAssetName(artifactProduct, product.version); + const checksumName = `${artifactProduct}-${product.version}-release-assets.sha256`; + const directAssets = bundled ? carrierAssets : assets; + writeFileSync( + path.join(directory, manifestName), + `${JSON.stringify( + { + schema: bundled + ? 'oliphaunt-extension-release-manifest-v2' + : 'oliphaunt-extension-release-manifest-v1', + product: artifactProduct, + ...ownership, + version: product.version, + extensionClass: releaseMetadata.class, + versioning: releaseMetadata.versioning, + sourceIdentity: extensionSourceIdentity(artifactProduct, 'publication-lock.test'), + compatibility, + ...(bundled + ? { + extensions: extensions.map((row) => ({ + ...row, + assets: row.assets.map( + ({ + name, + family, + target, + kind, + identity, + sha256, + bytes, + carrierAsset, + carrierRoot, + memberPath, + }) => ({ + name, + family, + target, + kind, + identity, + sha256, + bytes, + carrierAsset, + carrierRoot, + memberPath, + }), + ), + })), + assets: carrierAssets.map( + ({ name, family, target, kind, sha256, bytes, memberCount }) => ({ + name, + family, + target, + kind, + sha256, + bytes, + memberCount, + }), + ), + } + : { + sqlName: extensions[0].sqlName, + createsExtension: extensions[0].createsExtension, + dependencies: extensions[0].dependencies, + dataFiles: extensions[0].dataFiles, + extensionSqlFileNames: extensions[0].extensionSqlFileNames, + extensionSqlFilePrefixes: extensions[0].extensionSqlFilePrefixes, + nativeModuleStem: extensions[0].nativeModuleStem, + iosNativeDependencies: extensions[0].iosNativeDependencies, + iosRegistration: extensions[0].iosRegistration, + wasixInstall: extensions[0].wasixInstall, + sharedPreloadLibraries: extensions[0].sharedPreloadLibraries, + assets: assets.map(({ name, family, target, kind, identity, sha256, bytes }) => ({ + name, + family, + target, + kind, + identity, + sha256, + bytes, + })), + }), + }, + null, + 2, + )}\n`, + ); + writeFileSync( + path.join(directory, propertiesName), + `schema=oliphaunt-extension-release-manifest-v${bundled ? '2' : '1'}\nproduct=${artifactProduct}\n${artifactProduct === product.id ? '' : `releaseProduct=${product.id}\ncarrierFamily=${family ?? 'combined'}\n`}version=${product.version}\n`, + ); + writeFileSync( + path.join(directory, swiftCarrierName), + `${JSON.stringify( + buildSwiftExtensionCarrierManifest({ + extensionManifest: extensionManifestPath, + verifyMembers: false, + }), + null, + 2, + )}\n`, + ); + const payloadNames = [ + ...directAssets.map((asset) => asset.name), + manifestName, + propertiesName, + swiftCarrierName, + ].sort(); + writeFileSync( + path.join(directory, checksumName), + payloadNames.map((name) => `${sha256File(path.join(directory, name))} ./${name}\n`).join(''), + ); + return { assets: directAssets, directory, manifestPath: extensionManifestPath, swiftCarrierName }; +} + +afterEach(() => { + while (temporaryDirectories.length > 0) { + rmSync(temporaryDirectories.pop(), { recursive: true, force: true }); + } +}); + +describe('canonical publication catalog', () => { + test('projects repeated package dependencies to one sorted internal carrier edge', () => { + const carriers = [ + { id: 'npm:@oliphaunt/zeta' }, + { id: 'cargo:oliphaunt-tools' }, + { id: 'cargo:oliphaunt' }, + ]; + const packageDependencies = [ + { ecosystem: 'cargo', name: 'oliphaunt-tools', requirement: '=0.1.0', scope: 'runtime' }, + { ecosystem: 'npm', name: '@oliphaunt/zeta', requirement: '0.1.0', scope: 'optional' }, + { ecosystem: 'cargo', name: 'serde', requirement: '1', scope: 'runtime' }, + { ecosystem: 'cargo', name: 'oliphaunt-tools', requirement: '=0.1.0', scope: 'build' }, + { ecosystem: 'cargo', name: 'oliphaunt-tools', requirement: '=0.1.0', scope: 'runtime' }, + ]; + expect(projectInternalDependencyIds(carriers, packageDependencies)).toEqual([ + 'cargo:oliphaunt-tools', + 'npm:@oliphaunt/zeta', + ]); + }); + + test('permits only Cargo part identities as dynamic carriers', () => { + const catalog = loadPublicationCatalog('publication-lock.test', { + products: ['liboliphaunt-native'], + }); + const part = resolveActualCarrier( + catalog, + 'cargo', + 'liboliphaunt-native-linux-x64-gnu-part-001', + ); + expect(part.declared).toBe(false); + expect(part.parentCarrier).toBe('cargo:liboliphaunt-native-linux-x64-gnu'); + expect(part.part).toBe(1); + expect(() => + resolveActualCarrier(catalog, 'cargo', 'liboliphaunt-native-linux-x64-gnu-part-000'), + ).toThrow('1-based'); + expect(() => + resolveActualCarrier(catalog, 'cargo', 'liboliphaunt-native-linux-x64-gnu-part-1000'), + ).toThrow('is not a Cargo payload part crate'); + expect(() => + resolveActualCarrier(catalog, 'npm', '@oliphaunt/liboliphaunt-linux-x64-gnu-payload-0'), + ).toThrow('dynamic identities are permitted only for Cargo'); + }); + + test('requires every split carrier to use one complete contiguous 1-based part set', () => { + const parent = { + id: 'cargo:fixture-linux-x64-gnu', + ecosystem: 'cargo', + name: 'fixture-linux-x64-gnu', + role: 'platform-leaf', + declared: true, + packageDependencies: [ + { ecosystem: 'cargo', name: 'fixture-linux-x64-gnu-part-001' }, + { ecosystem: 'cargo', name: 'fixture-linux-x64-gnu-part-002' }, + ], + }; + const part = (number) => ({ + id: `cargo:fixture-linux-x64-gnu-part-${String(number).padStart(3, '0')}`, + ecosystem: 'cargo', + name: `fixture-linux-x64-gnu-part-${String(number).padStart(3, '0')}`, + role: 'payload-part', + declared: false, + parentCarrier: parent.id, + part: number, + packageDependencies: [], + }); + expect(() => validateCargoPayloadPartSets([part(1), part(2), parent])).not.toThrow(); + expect(() => + validateCargoPayloadPartSets([ + part(1), + part(3), + { + ...parent, + packageDependencies: [ + { ecosystem: 'cargo', name: 'fixture-linux-x64-gnu-part-001' }, + { ecosystem: 'cargo', name: 'fixture-linux-x64-gnu-part-003' }, + ], + }, + ]), + ).toThrow('contiguous from part-001'); + expect(() => validateCargoPayloadPartSets([part(1), parent])).toThrow( + 'exactly its complete Cargo payload part set', + ); + }); + + test('keeps contrib WASIX dependencies exact and external dependencies patch-compatible', () => { + expect(extensionDependencyRequirement('0.1.2', 'runtime-bound')).toBe('=0.1.2'); + expect(extensionDependencyRequirement('0.3.4', 'upstream-bound')).toBe('>=0.3.4,<0.4.0'); + expect(extensionDependencyRequirement('2.3.4', 'upstream-bound')).toBe('>=2.3.4,<3.0.0'); + }); +}); + +describe('publication artifact discovery and freezing', () => { + test('publish resolution rejects regenerated paths and mutations', () => { + const root = mkdtempSync(path.join(import.meta.dir, '../../target/publication-lock-publish-')); + temporaryDirectories.push(root); + const frozen = npmFixture(root, '@oliphaunt/test', '1.2.3'); + const artifact = { + path: path + .relative(path.join(import.meta.dir, '../..'), frozen) + .split(path.sep) + .join('/'), + sha256: sha256File(frozen), + size: readFileSync(frozen).length, + }; + const lock = { + carriers: [ + { + id: 'npm:@oliphaunt/test', + ecosystem: 'npm', + name: '@oliphaunt/test', + version: '1.2.3', + artifacts: [artifact], + }, + ], + }; + + expect(lockedCarrierFile(lock, 'npm', '@oliphaunt/test', frozen).file).toBe(frozen); + const regenerated = path.join(root, 'regenerated.tgz'); + writeFileSync(regenerated, readFileSync(frozen)); + expect(() => lockedCarrierFile(lock, 'npm', '@oliphaunt/test', regenerated)).toThrow( + 'attempted to substitute', + ); + writeFileSync(frozen, 'regenerated bytes'); + expect(() => lockedCarrierFile(lock, 'npm', '@oliphaunt/test', frozen)).toThrow( + 'bytes do not match', + ); + }); + + test('reads npm, Cargo, and Maven identities, bytes, and dependencies', () => { + const root = temporaryDirectory(); + npmFixture(root, '@oliphaunt/test', '1.2.3'); + cargoFixture(root, 'oliphaunt-test', '1.2.3'); + mavenFixture(root, 'dev.oliphaunt', 'test', '1.2.3'); + const records = discoverPublicationArtifacts([root]); + expect(records.map((record) => `${record.ecosystem}:${record.name}`).sort()).toEqual([ + 'cargo:oliphaunt-test', + 'maven:dev.oliphaunt:test', + 'npm:@oliphaunt/test', + ]); + expect( + records.every((record) => + record.artifacts.every((artifact) => artifact.size > 0 && artifact.sha256.length === 64), + ), + ).toBe(true); + expect(records.find((record) => record.ecosystem === 'cargo').dependencies[0].name).toBe( + 'serde', + ); + }); + + test('freezes repeated target-specific Cargo package rows as one internal carrier edge', () => { + const root = temporaryDirectory(); + const catalog = loadPublicationCatalog('publication-lock.test', { + products: ['oliphaunt-rust'], + }); + const version = catalog.products[0].version; + cargoFixture(root, 'oliphaunt-build', version); + cargoFixture(root, 'oliphaunt', version, { + manifestSuffix: [ + '', + '[target.\'cfg(target_os = "linux")\'.dependencies]', + `oliphaunt-build = "=${version}"`, + '', + '[target.\'cfg(target_os = "macos")\'.dependencies]', + `oliphaunt-build = "=${version}"`, + '', + '[target.\'cfg(target_os = "windows")\'.dependencies]', + `oliphaunt-build = "=${version}"`, + '', + ].join('\n'), + }); + + const candidate = buildPublicationCandidate({ + products: ['oliphaunt-rust'], + artifactRoots: [root], + }); + const facade = candidate.carriers.find(({ id }) => id === 'cargo:oliphaunt'); + expect( + facade.packageDependencies.filter(({ name }) => name === 'oliphaunt-build'), + ).toHaveLength(3); + expect(facade.dependencies).toEqual(['cargo:oliphaunt-build']); + expect(() => freezePublicationCandidate(candidate)).not.toThrow(); + + const duplicatedEdge = structuredClone(candidate); + duplicatedEdge.carriers + .find(({ id }) => id === 'cargo:oliphaunt') + .dependencies.push('cargo:oliphaunt-build'); + expect(() => validatePublicationCandidate(duplicatedEdge)).toThrow( + 'cargo:oliphaunt.dependencies must be sorted and contain no duplicates', + ); + }); + + test('rejects frozen npm tarballs that cannot use trusted publishing', () => { + for (const [label, overrides, pattern] of [ + ['missing-repository', { repository: undefined }, /repository must be an object/u], + [ + 'wrong-repository', + { repository: { type: 'git', url: 'https://github.com/example/other' } }, + /repository\.url must exactly match/u, + ], + [ + 'provenance-disabled', + { publishConfig: { access: 'public', provenance: false } }, + /must not disable npm provenance/u, + ], + ]) { + const root = temporaryDirectory(); + npmFixture(root, `@oliphaunt/${label}`, '1.2.3', overrides); + expect(() => discoverPublicationArtifacts([root])).toThrow(pattern); + } + }); + + test('reads the root npm manifest when a dependency is bundled', () => { + const root = temporaryDirectory(); + npmFixture( + root, + '@oliphaunt/ts', + '1.2.3', + {}, + { + name: '@oliphaunt/ts-query', + version: '0.0.0', + }, + ); + expect(discoverPublicationArtifacts([root])).toMatchObject([ + { + ecosystem: 'npm', + name: '@oliphaunt/ts', + version: '1.2.3', + }, + ]); + }); + + test('freezes an exhaustive product carrier set and detects tampering', () => { + const root = temporaryDirectory(); + const catalog = loadPublicationCatalog('publication-lock.test', { products: ['oliphaunt-js'] }); + const version = catalog.products[0].version; + npmFixture(root, '@oliphaunt/ts', version); + const candidate = buildPublicationCandidate({ + products: ['oliphaunt-js'], + artifactRoots: [root], + }); + expect(candidate.missing).toEqual([]); + expect(candidate.carriers).toHaveLength(1); + expect(candidate.packageEnvelopeDigest).toHaveLength(64); + const unknownDependency = structuredClone(candidate); + unknownDependency.carriers[0].dependencies = ['npm:@oliphaunt/not-frozen']; + expect(() => validatePublicationCandidate(unknownDependency)).toThrow( + /internal package dependency identities/u, + ); + const nonCanonicalIdentity = structuredClone(candidate); + nonCanonicalIdentity.carriers[0].id = 'npm:wrong-name'; + expect(() => validatePublicationCandidate(nonCanonicalIdentity)).toThrow(/canonical/u); + const lock = freezePublicationCandidate(candidate); + expect(validatePublicationLock(lock)).toBe(lock); + const tampered = structuredClone(lock); + tampered.carriers[0].artifacts[0].size += 1; + expect(() => validatePublicationLock(tampered)).toThrow( + /Digest mismatch|digest mismatch|packageEnvelopeDigest/u, + ); + }); + + test('projects broad artifact roots through the full catalog onto selected products', () => { + const root = temporaryDirectory(); + const selectedCatalog = loadPublicationCatalog('publication-lock.test', { + products: ['oliphaunt-js'], + }); + const selectedVersion = selectedCatalog.products[0].version; + npmFixture(root, '@oliphaunt/ts', selectedVersion); + + const fullCatalog = loadPublicationCatalog('publication-lock.test'); + const unselected = fullCatalog.carriers.find( + (carrier) => + carrier.ecosystem === 'cargo' && + carrier.product === 'oliphaunt-rust' && + carrier.name === 'oliphaunt', + ); + expect(unselected).toBeDefined(); + cargoFixture(root, unselected.name, unselected.version); + cargoFixture(root, unselected.name, '999.0.0'); + const unselectedNpm = fullCatalog.carriers.find( + (carrier) => carrier.ecosystem === 'npm' && carrier.product === 'oliphaunt-broker', + ); + expect(unselectedNpm).toBeDefined(); + npmFixture(path.join(root, 'unselected-a'), unselectedNpm.name, unselectedNpm.version, { + description: 'first unselected carrier bytes', + }); + npmFixture(path.join(root, 'unselected-b'), unselectedNpm.name, unselectedNpm.version, { + description: 'second unselected carrier bytes', + }); + + const candidate = buildPublicationCandidate({ + products: ['oliphaunt-js'], + artifactRoots: [root], + }); + expect(candidate.carriers.map((carrier) => `${carrier.ecosystem}:${carrier.name}`)).toEqual([ + 'npm:@oliphaunt/ts', + ]); + expect(candidate.carriers.every((carrier) => carrier.product === 'oliphaunt-js')).toBe(true); + + const conflictingSelected = npmFixture( + path.join(root, 'selected-conflict'), + '@oliphaunt/ts', + selectedVersion, + { description: 'ambiguous selected carrier bytes' }, + ); + expect(() => + buildPublicationCandidate({ + products: ['oliphaunt-js'], + artifactRoots: [root], + }), + ).toThrow(/duplicate artifact identity npm:@oliphaunt\/ts@.+ conflicting candidate bytes/u); + unlinkSync(conflictingSelected); + + cargoFixture(root, 'undeclared-publication-carrier', '1.2.3'); + expect(() => + buildPublicationCandidate({ + products: ['oliphaunt-js'], + artifactRoots: [root], + }), + ).toThrow(/artifact identity cargo:undeclared-publication-carrier is not declared/u); + }); + + test('freezes exact GitHub assets and rejects tampering, missing assets, and extras', () => { + const root = temporaryDirectory(); + const product = loadPublicationCatalog('publication-lock.test', { + products: ['oliphaunt-broker'], + }).products[0]; + const { checksum, directory, rows } = githubReleaseFixture(root, product); + const artifacts = discoverProductArtifacts([root], [product]); + expect(artifacts).toHaveLength(rows.length); + expect( + artifacts.every( + (artifact) => artifact.role === 'github-release-asset' && artifact.sha256.length === 64, + ), + ).toBe(true); + + const payload = rows.find((row) => row !== checksum); + const payloadPath = path.join(directory, payload.name); + writeFileSync(payloadPath, 'tampered\n'); + expect(() => discoverProductArtifacts([root], [product])).toThrow('checksum'); + writeFileSync(payloadPath, `fixture:${payload.name}\n`); + + unlinkSync(payloadPath); + expect(() => discoverProductArtifacts([root], [product])).toThrow( + /requires exactly one|asset set mismatch/u, + ); + writeFileSync(payloadPath, `fixture:${payload.name}\n`); + + writeFileSync(path.join(directory, 'undeclared.zip'), 'extra\n'); + expect(() => discoverProductArtifacts([root], [product])).toThrow('extra'); + }); + + test('freezes every declared extension OS target plus public metadata', () => { + const root = temporaryDirectory(); + const product = loadPublicationCatalog('publication-lock.test', { + products: ['oliphaunt-extension-vector'], + }).products[0]; + const { assets, directory, manifestPath, swiftCarrierName } = extensionGithubReleaseFixture( + root, + product, + ); + const artifacts = discoverProductArtifacts([root], [product]); + expect(artifacts).toHaveLength(assets.length + 4); + expect( + new Set( + artifacts + .filter((artifact) => artifact.role === 'github-release-asset') + .map((artifact) => artifact.target), + ), + ).toEqual( + new Set( + extensionArtifactTargets({ product: product.id }, 'publication-lock.test').map( + (target) => target.target, + ), + ), + ); + + const swiftCarrierPath = path.join(directory, swiftCarrierName); + const incompatibleCarrier = JSON.parse(readFileSync(swiftCarrierPath, 'utf8')); + incompatibleCarrier.base.version = '9.9.9'; + incompatibleCarrier.base.tag = 'liboliphaunt-native-v9.9.9'; + writeFileSync(swiftCarrierPath, `${JSON.stringify(incompatibleCarrier, null, 2)}\n`); + expect(() => discoverProductArtifacts([root], [product])).toThrow('compatible native base'); + + extensionGithubReleaseFixture(root, product); + + const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')); + const missingRole = manifest.assets.find((asset) => asset.kind === 'ios-xcframework'); + manifest.assets = manifest.assets.filter((asset) => asset !== missingRole); + writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); + unlinkSync(path.join(directory, missingRole.name)); + expect(() => discoverProductArtifacts([root], [product])).toThrow('roles'); + + extensionGithubReleaseFixture(root, product); + writeFileSync(path.join(directory, 'undeclared-extension-asset.tar.gz'), 'extra\n'); + expect(() => discoverProductArtifacts([root], [product])).toThrow('extra'); + + extensionGithubReleaseFixture(root, product); + const publicManifestPath = path.join( + directory, + `${product.id}-${product.version}-manifest.json`, + ); + const forgedPublicManifest = JSON.parse(readFileSync(publicManifestPath, 'utf8')); + forgedPublicManifest.versioning = 'independent'; + forgedPublicManifest.sourceIdentity = { + kind: 'external', + name: 'forged', + url: 'https://invalid.example', + branch: 'main', + commit: '0'.repeat(40), + }; + writeFileSync(publicManifestPath, `${JSON.stringify(forgedPublicManifest, null, 2)}\n`); + expect(() => discoverProductArtifacts([root], [product])).toThrow( + /canonical extension identity/u, + ); + + extensionGithubReleaseFixture(root, product); + const forgedCiManifest = JSON.parse(readFileSync(manifestPath, 'utf8')); + forgedCiManifest.compatibility.nativeRuntimeVersion = '9.9.9'; + writeFileSync(manifestPath, `${JSON.stringify(forgedCiManifest, null, 2)}\n`); + expect(() => discoverProductArtifacts([root], [product])).toThrow(/does not describe/u); + + extensionGithubReleaseFixture(root, product); + const forgedInventoryManifest = JSON.parse(readFileSync(manifestPath, 'utf8')); + forgedInventoryManifest.dataFiles = [ + ...forgedInventoryManifest.dataFiles, + 'undeclared/foreign.sql', + ].sort(); + writeFileSync(manifestPath, `${JSON.stringify(forgedInventoryManifest, null, 2)}\n`); + expect(() => discoverProductArtifacts([root], [product])).toThrow( + /semantic extension metadata is not canonical generated metadata/u, + ); + }); + + test('freezes the exact contrib bundle member set under one release owner', { + timeout: 20_000, + }, () => { + const root = temporaryDirectory(); + const artifactProduct = 'oliphaunt-extension-contrib-pg18'; + const product = loadPublicationCatalog('publication-lock.test', { + products: ['liboliphaunt-native'], + }).products[0]; + const fixtureOptions = { artifactProduct, family: 'native' }; + const { rows: runtimeAssets } = githubReleaseFixture(root, product); + const { assets, manifestPath } = extensionGithubReleaseFixture(root, product, fixtureOptions); + const artifacts = discoverProductArtifacts([root], [product]); + expect(artifacts).toHaveLength(runtimeAssets.length + assets.length + 4); + expect(assets.every(({ name }) => /^oliphaunt-extension-contrib-pg18-[^-]+/u.test(name))).toBe( + true, + ); + const candidate = buildPublicationCandidate({ + products: [product.id], + artifactRoots: [root], + allowMissing: true, + }); + expect(candidate.missing.length).toBeGreaterThan(0); + expect(() => validatePublicationCandidate(candidate)).not.toThrow(); + + const wrongCarrierIdentity = structuredClone(candidate); + wrongCarrierIdentity.productArtifacts.find( + ({ role }) => role === 'github-release-asset', + ).identity = 'wrong-family'; + expect(() => validatePublicationCandidate(wrongCarrierIdentity)).toThrow( + /packageEnvelopeDigest mismatch|incorrect target, kind, or identity metadata/u, + ); + + const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')); + manifest.extensions.pop(); + writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`); + expect(() => discoverProductArtifacts([root], [product])).toThrow( + 'exact sorted bundle member set', + ); + + extensionGithubReleaseFixture(root, product, fixtureOptions); + const forgedMemberInventory = JSON.parse(readFileSync(manifestPath, 'utf8')); + forgedMemberInventory.extensions[0].extensionSqlFilePrefixes = [ + ...forgedMemberInventory.extensions[0].extensionSqlFilePrefixes, + 'undeclared-prefix', + ].sort(); + writeFileSync(manifestPath, `${JSON.stringify(forgedMemberInventory, null, 2)}\n`); + expect(() => discoverProductArtifacts([root], [product])).toThrow( + /semantic extension metadata is not canonical generated metadata/u, + ); + + extensionGithubReleaseFixture(root, product, fixtureOptions); + const publicManifestPath = path.join( + path.dirname(manifestPath), + 'release-assets', + `${artifactProduct}-${product.version}-manifest.json`, + ); + const forgedPublicManifest = JSON.parse(readFileSync(publicManifestPath, 'utf8')); + forgedPublicManifest.compatibility.wasixRuntimeVersion = '9.9.9'; + writeFileSync(publicManifestPath, `${JSON.stringify(forgedPublicManifest, null, 2)}\n`); + expect(() => discoverProductArtifacts([root], [product])).toThrow( + /frozen aggregate member\/carrier inventory/u, + ); + }); + + test('rejects stale, missing, extra, substituted, or wrongly-moded aggregate bundle legal material', { + timeout: 60_000, + }, () => { + const artifactProduct = 'oliphaunt-extension-contrib-pg18'; + const product = loadPublicationCatalog('publication-lock.test', { + products: ['liboliphaunt-native'], + }).products[0]; + const reject = (options, expected) => { + const root = temporaryDirectory(); + githubReleaseFixture(root, product); + extensionGithubReleaseFixture(root, product, { + ...options, + artifactProduct, + family: 'native', + }); + expect(() => discoverProductArtifacts([root], [product])).toThrow(expected); + }; + + reject( + { + mutateBundleStage({ bundleManifest }) { + const manifest = JSON.parse(readFileSync(bundleManifest, 'utf8')); + delete manifest.licenseProfile; + writeFileSync(bundleManifest, `${JSON.stringify(manifest, null, 2)}\n`); + }, + }, + /bundle-manifest\.json does not exactly freeze its nested member and legal locators/u, + ); + + reject( + { + mutateBundleStage({ stage }) { + unlinkSync(path.join(stage, 'LICENSE')); + }, + }, + /contains undeclared or missing regular bundle members/u, + ); + + reject( + { + mutateBundleStage({ stage }) { + writeFileSync(path.join(stage, 'UNDECLARED.txt'), 'undeclared\n'); + }, + }, + /contains undeclared or missing regular bundle members/u, + ); + + reject( + { + mutateBundleStage({ stage }) { + writeFileSync(path.join(stage, 'LICENSE'), 'substituted legal bytes\n'); + }, + }, + /legal member .*\/LICENSE does not match its canonical bytes and mode/u, + ); + + reject( + { + bundleFixedFileMode: null, + mutateBundleStage({ stage }) { + chmodSync(path.join(stage, 'LICENSE'), 0o600); + }, + }, + /member .*\/LICENSE must be a regular mode=644 file/u, + ); + }); + + test('rejects bundle encodings that supported mobile consumers reject', { + timeout: 60_000, + }, () => { + const artifactProduct = 'oliphaunt-extension-contrib-pg18'; + const product = loadPublicationCatalog('publication-lock.test', { + products: ['liboliphaunt-native'], + }).products[0]; + const reject = (options, expected) => { + const root = temporaryDirectory(); + githubReleaseFixture(root, product); + extensionGithubReleaseFixture(root, product, { + ...options, + artifactProduct, + family: 'native', + }); + expect(() => discoverProductArtifacts([root], [product])).toThrow(expected); + }; + + reject( + { + mutateBundleStage({ bundleManifest }) { + const manifest = JSON.parse(readFileSync(bundleManifest, 'utf8')); + writeFileSync(bundleManifest, `${JSON.stringify(manifest)}\n`); + }, + }, + /bundle-manifest\.json must use the exact canonical bytes/u, + ); + + reject( + { + mutateBundleArchive({ output }) { + const bytes = readFileSync(output); + bytes[3] = 8; + writeFileSync(output, bytes); + }, + }, + /without optional header sections/u, + ); + + reject( + { + mutateBundleArchive({ output }) { + const tar = gunzipSync(readFileSync(output)); + Buffer.from('ustar \0', 'ascii').copy(tar, 257); + refreshTarHeaderChecksum(tar); + writeFileSync(output, canonicalGzipSync(tar)); + }, + }, + /non-POSIX-ustar/u, + ); + }); + + test('keeps SQL-only mobile extensions resource-only', () => { + const root = temporaryDirectory(); + const product = loadPublicationCatalog('publication-lock.test', { + products: ['oliphaunt-extension-pgtap'], + }).products[0]; + extensionGithubReleaseFixture(root, product); + const artifacts = discoverProductArtifacts([root], [product]); + const mobile = artifacts.filter( + (artifact) => + artifact.role === 'github-release-asset' && + (artifact.target === 'ios-xcframework' || artifact.target.startsWith('android-')), + ); + expect( + mobile.every((artifact) => artifact.kind === 'runtime' && artifact.identity === null), + ).toBe(true); + }); + + test('freezes a selection-neutral Swift source carrier and separately composed dependency-closed output', () => { + const workspaceRoot = mkdtempSync( + path.join(import.meta.dir, '../../target/publication-lock-swift-'), + ); + temporaryDirectories.push(workspaceRoot); + const sdk = path.join(workspaceRoot, 'sdk-artifacts/oliphaunt-swift'); + const fixture = path.join(workspaceRoot, 'release/swiftpm-extension-consumer-fixture'); + mkdirSync(path.join(sdk, 'extension-generator'), { recursive: true }); + mkdirSync(path.join(sdk, 'release-tree/src/sdks/swift/Carriers'), { recursive: true }); + mkdirSync(path.join(fixture, 'Sources/OliphauntExtensionPgtap/Resources/extension-artifact'), { + recursive: true, + }); + writeFileSync(path.join(sdk, 'Oliphaunt-source.zip'), 'source archive\n'); + writeFileSync(path.join(sdk, 'Package.swift.release'), '// release manifest fixture\n'); + for (const name of [ + 'extension-owner-catalog.json', + 'extension-resource-inventory.mjs', + 'render-extension-products.mjs', + 'swift-carrier-resolver.mjs', + 'swiftpm-extension-input.schema.json', + ]) { + writeFileSync( + path.join(sdk, 'extension-generator', name), + name === 'extension-owner-catalog.json' + ? readFileSync( + path.join(import.meta.dir, '../../src/extensions/generated/sdk/extensions.json'), + ) + : name === 'extension-resource-inventory.mjs' + ? releaseJavaScript( + path.join( + import.meta.dir, + '../../src/sdks/swift/tools/extension-resource-inventory.mts', + ), + ) + : `${name}\n`, + ); + } + const sourceCarrier = path.join( + sdk, + 'release-tree/src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + ); + const canonicalSourceCarrier = selectionNeutralSwiftSourceCarrier( + productCompatibilityVersion( + 'oliphaunt-swift', + 'liboliphaunt-native', + 'publication-lock.test', + ), + ); + writeFileSync(sourceCarrier, `${JSON.stringify(canonicalSourceCarrier)}\n`); + const baseXcframework = canonicalSourceCarrier.base.assets.find( + ({ role }) => role === 'base-xcframework', + ); + writeFileSync( + path.join(sdk, 'Package.swift.release'), + `.binaryTarget(\n name: "liboliphaunt",\n url: "${baseXcframework.url}",\n checksum: "${baseXcframework.sha256}"\n)\n`, + ); + writeFileSync(path.join(fixture, 'Package.swift'), '// generated consumer\n'); + writeFileSync( + path.join(fixture, 'extension-products.json'), + '{"schema":"oliphaunt-swiftpm-extension-products-v1"}\n', + ); + writeFileSync( + path.join( + fixture, + 'Sources/OliphauntExtensionPgtap/Resources/extension-artifact/pgtap.control', + ), + "default_version='1.0'\n", + ); + + const catalog = loadPublicationCatalog('publication-lock.test', { + products: ['oliphaunt-swift', 'oliphaunt-extension-pgtap'], + }); + const product = catalog.products.find(({ id }) => id === 'oliphaunt-swift'); + const extensionProduct = catalog.products.find(({ id }) => id === 'oliphaunt-extension-pgtap'); + expect(product).toBeDefined(); + expect(extensionProduct).toBeDefined(); + const bindingsName = `oliphaunt-swift-${product.version}-bindings.xcframework.zip`; + const checksumName = `oliphaunt-swift-${product.version}-release-assets.sha256`; + const releaseAssets = path.join(sdk, 'release-assets'); + mkdirSync(releaseAssets); + const bindingsBytes = Buffer.from('Swift bindings artifact fixture\n'); + writeFileSync(path.join(releaseAssets, bindingsName), bindingsBytes); + writeFileSync( + path.join(releaseAssets, checksumName), + `${createHash('sha256').update(bindingsBytes).digest('hex')} ./${bindingsName}\n`, + ); + const { manifestPath } = extensionGithubReleaseFixture(workspaceRoot, extensionProduct); + const extensionRoot = path.dirname(manifestPath); + const selectedRoots = [sdk, fixture, extensionRoot]; + + expect(() => discoverProductArtifacts([sdk, fixture], [product])).toThrow( + /selects no extension products and requires no frozen Swift consumer fixture/u, + ); + expect(() => discoverProductArtifacts([sdk, extensionRoot], catalog.products)).toThrow( + /selects extension products and requires exactly one frozen Swift consumer fixture/u, + ); + + const artifacts = discoverProductArtifacts(selectedRoots, catalog.products); + const swiftArtifacts = artifacts.filter((artifact) => artifact.product === product.id); + expect(swiftArtifacts.map(({ id }) => id).sort()).toEqual([ + `github-release:${bindingsName}`, + `github-release:${checksumName}`, + 'release-input:Oliphaunt-source.zip', + 'release-input:Package.swift.release', + 'release-input:extension-owner-catalog.json', + 'release-input:extension-resource-inventory.mjs', + 'release-input:oliphaunt-react-native-ios-carriers.json', + 'release-input:render-extension-products.mjs', + 'release-input:swift-carrier-resolver.mjs', + 'release-input:swiftpm-extension-consumer-fixture', + 'release-input:swiftpm-release-tree', + ]); + expect(() => + assertLockedProductArtifacts( + { productArtifacts: artifacts, products: catalog.products }, + product.id, + [sdk, fixture], + ), + ).not.toThrow(); + const frozenFixture = swiftArtifacts.find( + ({ id }) => id === 'release-input:swiftpm-extension-consumer-fixture', + ); + writeFileSync( + path.join( + fixture, + 'Sources/OliphauntExtensionPgtap/Resources/extension-artifact/pgtap.control', + ), + 'tampered\n', + ); + const tamperedFixture = discoverProductArtifacts(selectedRoots, catalog.products).find( + ({ id, product: artifactProduct }) => + artifactProduct === product.id && id === 'release-input:swiftpm-extension-consumer-fixture', + ); + expect(tamperedFixture.sha256).not.toBe(frozenFixture.sha256); + + const selectedSourceCarrier = structuredClone(canonicalSourceCarrier); + selectedSourceCarrier.extensions.push({ sqlName: 'pgtap' }); + writeFileSync(sourceCarrier, `${JSON.stringify(selectedSourceCarrier)}\n`); + expect(() => discoverProductArtifacts(selectedRoots, catalog.products)).toThrow( + /ios-carriers\.json\.extensions.*selection-neutral/u, + ); + + const malformedSourceCarrier = structuredClone(canonicalSourceCarrier); + delete malformedSourceCarrier.carriers; + writeFileSync(sourceCarrier, `${JSON.stringify(malformedSourceCarrier)}\n`); + expect(() => discoverProductArtifacts(selectedRoots, catalog.products)).toThrow( + /ios-carriers\.json.*fields must be exactly/u, + ); + writeFileSync(sourceCarrier, `${JSON.stringify(canonicalSourceCarrier)}\n`); + + writeFileSync( + path.join(sdk, 'extension-generator/extension-resource-inventory.mjs'), + '// forged inventory validator\n', + ); + expect(() => discoverProductArtifacts(selectedRoots, catalog.products)).toThrow( + /frozen extension-resource-inventory\.mjs must exactly match/u, + ); + }); +}); diff --git a/tools/release/publication-lock.test.sh b/tools/release/publication-lock.test.sh new file mode 100644 index 000000000..f922b3c17 --- /dev/null +++ b/tools/release/publication-lock.test.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/../.." +if [[ "${1:-}" != --context ]]; then + exec bash tools/release/release-please-state.sh "$PWD" HEAD \ + bash tools/release/with-source.sh HEAD bash tools/ci/with-projects.sh --exec \ + bash tools/release/publication-lock.test.sh --context +fi +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +bun test ./tools/release/publication-lock.test.mts +bun tools/release/publication-lock.test.mts prepare-handoff "$scratch" +bun tools/release/publication-lock.mts verify --lock "$scratch/publication-lock.json" --head-ref HEAD +for ref in HEAD HEAD^; do + bash tools/release/with-source.sh "$ref" bun tools/release/publication-lock.test.mts assert-source +done +echo 'Publication lock verifies after payload handoff and binds actual Git source snapshots' diff --git a/tools/release/publish-registries.sh b/tools/release/publish-registries.sh new file mode 100644 index 000000000..65a0e2ecf --- /dev/null +++ b/tools/release/publish-registries.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$root" +if [[ "${1:-}" == --help || "${1:-}" == -h ]]; then + echo 'usage: publish-registries.sh --products-json JSON [--head-ref REF] [--publication-lock FILE] [--bootstrap-ledger DIRECTORY]' + exit 0 +fi +state="$(mktemp -d)" +pids=() +cleanup() { rm -rf "$state"; } +trap cleanup EXIT +args=("$@") +source_ref="${RELEASE_HEAD_SHA:-HEAD}" +for ((index=0; index<${#args[@]}; index++)); do + case "${args[index]}" in + --head-ref) source_ref="${args[index+1]:?--head-ref requires a value}" ;; + --head-ref=*) source_ref="${args[index]#*=}" ;; + esac +done +native() { bash tools/release/with-source.sh "$source_ref" bash tools/dev/bun.sh tools/release/release-publish.mts "$1" "$state" "${@:2}" "${args[@]}"; } +native registry-prepare +if jq -e 'any(.plan.operations[]; .ecosystem == "npm")' "$state/context.json" >/dev/null; then + transport_timeout="$(command -v timeout || command -v gtimeout)" || { echo 'GNU timeout is required for npm publication' >&2; exit 1; } +fi +wait_dependencies() { + local dependency + for dependency in $(jq -r --argjson index "$1" '.schedule.dependencies[$index][]' "$state/context.json"); do + until [[ -f "$state/operation-$dependency.json" ]]; do + [[ ! -f "$state/abort" ]] || return 1 + sleep 0.1 + done + done + [[ ! -f "$state/abort" ]] +} +lane() ( + trap 'status=$?; if [[ "$status" != 0 ]]; then : > "$state/abort"; fi; exit "$status"' EXIT + if [[ "$1" == cargo ]]; then + for batch in $(jq -r '.schedule.cargoBatches | keys[]' "$state/context.json"); do + first="$(jq -r --argjson batch "$batch" '.schedule.cargoBatches[$batch][0]' "$state/context.json")" + wait_dependencies "$first" + native registry-cargo "$batch" + done + else + for index in $(jq -r --arg ecosystem "$1" '.plan.operations[] | select(.ecosystem == $ecosystem) | .operationOrder' "$state/context.json"); do + wait_dependencies "$index" + if [[ "$1" == maven ]]; then + native registry-maven "$index" + else + native registry-npm-before "$index" + [[ ! -f "$state/abort" ]] || exit 1 + [[ ! -f "$state/operation-$index.json" ]] || continue + admission="$state/npm-$index.json" + tarball="$(jq -r .tarball "$admission")" + registry="$(jq -r .registry "$admission")" + seconds="$(jq -r '.timeout / 1000 | floor' "$admission")" + status=0 + NPM_CONFIG_FETCH_RETRIES=0 "$transport_timeout" --kill-after=5s "${seconds}s" \ + npm publish "$tarball" --access public --provenance --registry "$registry" || status=$? + native registry-npm-after "$index" + if [[ "$status" != 0 ]]; then echo "npm operation $index reconciled after exit $status"; fi + fi + done + fi +) +# A failed lane stops new admissions. Existing mutations finish and reconcile; +# Cargo's native batch retains its token until its in-flight upload has drained. +for ecosystem in cargo npm maven; do lane "$ecosystem" & pids+=("$!"); done +result=0 +for pid in "${pids[@]}"; do wait "$pid" || result=$?; done +[[ "$result" == 0 ]] || exit "$result" +native registry-finish diff --git a/tools/release/publish-registries.test.mts b/tools/release/publish-registries.test.mts new file mode 100644 index 000000000..6daa6a40b --- /dev/null +++ b/tools/release/publish-registries.test.mts @@ -0,0 +1,36 @@ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { normalPublicationSchedule } from './normal-publication-executor.mts'; + +const [mode, root, scenario] = process.argv.slice(2); +if (mode === 'prepare') { + const operations = ['cargo', 'npm', 'cargo', 'maven', 'npm'].map((ecosystem, operationOrder) => ({ + id: `op${operationOrder}`, + ecosystem, + operationOrder, + dependencies: [[], ['op0'], ['op1'], ['op1'], ['op2', 'op3']][operationOrder], + ...(ecosystem === 'maven' + ? { kind: 'maven-atomic-deployment', carrierIds: ['maven:fixture'] } + : { kind: 'carrier', carrierId: `${ecosystem}:fixture-${operationOrder}` }), + })); + const plan = { operations }; + writeFileSync( + path.join(root, 'plan.json'), + JSON.stringify({ plan, schedule: normalPublicationSchedule(plan) }), + ); +} else if (mode === 'assert') { + const events = readFileSync(path.join(root, `events-${scenario}`), 'utf8') + .trim() + .split('\n'); + assert(events.indexOf('cargo-0') < events.indexOf('npm-before-1')); + assert(events.indexOf('npm-reconciled-1') < events.indexOf('maven-start')); + assert(events.indexOf('maven-start') < events.indexOf('cargo-drained')); + assert(events.includes('cargo-drained')); + assert.equal(events.includes('npm-before-4'), scenario === 'success'); + assert.equal(events.includes('finish'), scenario === 'success'); + assert.equal( + events.filter((event) => event === 'npm-push').length, + scenario === 'success' ? 2 : 1, + ); +} else throw Error('expected prepare or assert'); diff --git a/tools/release/publish-registries.test.sh b/tools/release/publish-registries.test.sh new file mode 100644 index 000000000..0855b0a37 --- /dev/null +++ b/tools/release/publish-registries.test.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +source_root="$PWD" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +mkdir -p "$scratch/tools/release" "$scratch/tools/dev" "$scratch/bin" +cp tools/release/publish-registries.sh "$scratch/tools/release/" +printf '#!/usr/bin/env bash\nshift\nexec "$@"\n' > "$scratch/tools/release/with-source.sh" +bun tools/release/publish-registries.test.mts prepare "$scratch" +cat > "$scratch/tools/dev/bun.sh" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +phase="$2"; state="$3"; index="${4:-}" +event() { echo "$*" >> "$REGISTRY_FIXTURE_LOG"; } +case "$phase" in + registry-prepare) cp "$REGISTRY_FIXTURE_ROOT/plan.json" "$state/context.json" ;; + registry-cargo) + if [[ "$index" == 0 ]]; then echo '[]' > "$state/operation-0.json"; event cargo-0; else + [[ -f "$state/operation-1.json" ]] + event cargo-start; : > "$state/cargo-start" + until [[ -f "$state/maven-start" ]]; do sleep 0.05; done + sleep 0.15 + echo '[]' > "$state/operation-2.json"; event cargo-drained + fi ;; + registry-npm-before) + event "npm-before-$index" + jq -n '{tarball:"frozen.tgz",registry:"https://registry.npmjs.org",timeout:2000}' > "$state/npm-$index.json" ;; + registry-npm-after) event "npm-reconciled-$index"; echo '[]' > "$state/operation-$index.json" ;; + registry-maven) + [[ -f "$state/operation-1.json" ]] + until [[ -f "$state/cargo-start" ]]; do sleep 0.05; done + event maven-start; : > "$state/maven-start" + [[ "$REGISTRY_FIXTURE_FAIL" != true ]] || exit 9 + echo '[]' > "$state/operation-3.json" ;; + registry-finish) event finish ;; + *) exit 20 ;; +esac +SH +cat > "$scratch/bin/npm" <<'SH' +#!/usr/bin/env bash +[[ "$*" == 'publish frozen.tgz --access public --provenance --registry https://registry.npmjs.org' ]] || exit 21 +[[ "$NPM_CONFIG_FETCH_RETRIES" == 0 ]] || exit 22 +echo npm-push >> "$REGISTRY_FIXTURE_LOG" +exit 7 +SH +chmod +x "$scratch/bin/npm" +deadline="$(command -v gtimeout || command -v timeout)" +for scenario in success failure; do + fail=false + [[ "$scenario" != failure ]] || fail=true + status=0 + PATH="$scratch/bin:$PATH" REGISTRY_FIXTURE_ROOT="$scratch" REGISTRY_FIXTURE_LOG="$scratch/events-$scenario" REGISTRY_FIXTURE_FAIL="$fail" \ + "$deadline" 10 bash "$scratch/tools/release/publish-registries.sh" --products-json '["fixture"]' > "$scratch/result" 2>&1 || status=$? + if [[ "$scenario" == success ]]; then [[ "$status" == 0 ]] || { cat "$scratch/result" >&2; exit 1; }; + else [[ "$status" != 0 && "$status" != 124 ]]; fi + bun "$source_root/tools/release/publish-registries.test.mts" assert "$scratch" "$scenario" +done +echo 'Registry lanes: dependency ordering, one npm attempt, reconciliation and peer draining passed' diff --git a/tools/release/publish-release-pr.test.sh b/tools/release/publish-release-pr.test.sh new file mode 100644 index 000000000..007baeb7f --- /dev/null +++ b/tools/release/publish-release-pr.test.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(git rev-parse --show-toplevel)" +scratch="$(mktemp -d "${TMPDIR:-/tmp}/release-pr-publish.XXXXXX")" +trap 'rm -rf "$scratch"' EXIT +mkdir -p "$scratch/work/.github/scripts" "$scratch/bin" "$scratch/metadata" +git init -q --bare "$scratch/remote" +git init -q -b main "$scratch/work" +cd "$scratch/work" +git config user.name 'Release Fixture' +git config user.email 'release@example.invalid' +cp "$root/.github/scripts/require-current-main.sh" .github/scripts/ +echo 0.1.0 >VERSION +git add . +git commit -qm 'feat: source baseline' +git remote add origin "$scratch/remote" +git push -q origin main +export GITHUB_SHA GITHUB_REF=refs/heads/main GITHUB_REPOSITORY=f0rr0/oliphaunt +GITHUB_SHA="$(git rev-parse HEAD)" +export RELEASE_PR_FIXTURE="$scratch" +cat >"$scratch/bin/gh" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +case "$1 $2" in + 'auth setup-git') exit 0 ;; + 'pr list') + if [[ -f "$RELEASE_PR_FIXTURE/pr.json" ]]; then cat "$RELEASE_PR_FIXTURE/pr.json"; else echo '[]'; fi ;; + 'pr create'|'pr edit') + sha="$(git --git-dir="$RELEASE_PR_FIXTURE/remote" rev-parse refs/heads/release-please--branches--main)" + jq -nc --arg sha "$sha" '[{number:42, headRefOid:$sha, headRepository:{nameWithOwner:"f0rr0/oliphaunt"}, isCrossRepository:false, title:"chore(release): prepare main releases", labels:[{name:"autorelease: pending"}]}]' > "$RELEASE_PR_FIXTURE/pr.json" + if [[ "$2" == create ]]; then + echo created >> "$RELEASE_PR_FIXTURE/creates" + if [[ -f "$RELEASE_PR_FIXTURE/ambiguous" ]]; then rm "$RELEASE_PR_FIXTURE/ambiguous"; exit 1; fi + fi ;; + *) echo "unexpected gh command: $*" >&2; exit 1 ;; +esac +SH +chmod +x "$scratch/bin/gh" +export PATH="$scratch/bin:$PATH" +title='chore(release): prepare main releases' +printf '%s\n' "$title" >"$scratch/metadata/title" +echo true >"$scratch/metadata/required" +echo 'Release Please fixture notes' >"$scratch/metadata/body.md" +candidate() { + git checkout -q --detach "$GITHUB_SHA" + echo 0.1.1 >VERSION + git add VERSION + GIT_COMMITTER_DATE="$1" GIT_AUTHOR_DATE="$1" git commit -qm "$title" +} +publish() { bash "$root/.github/scripts/publish-release-pr.sh" "$scratch/metadata"; } +remote_head() { git --git-dir="$scratch/remote" rev-parse refs/heads/release-please--branches--main; } + +candidate '2026-09-11T12:00:00Z' +touch "$scratch/ambiguous" +if publish >"$scratch/first.log" 2>&1; then + echo 'ambiguous create must report failure' >&2 + exit 1 +fi +first="$(remote_head)" +publish >"$scratch/recovery.log" 2>&1 +[[ "$(wc -l <"$scratch/creates")" == 1 && "$(remote_head)" == "$first" ]] + +candidate '2026-09-12T12:00:00Z' +[[ "$(git rev-parse HEAD)" != "$first" ]] +publish >"$scratch/repeat.log" 2>&1 +[[ "$(remote_head)" == "$first" ]] + +git checkout -q main +echo 'new source' >README.md +git add README.md +git commit -qm 'docs: source update' +git push -q origin main +GITHUB_SHA="$(git rev-parse HEAD)" +candidate '2026-09-13T12:00:00Z' +publish >"$scratch/update.log" 2>&1 +[[ "$(remote_head)" == "$(git rev-parse HEAD)" && "$(wc -l <"$scratch/creates")" == 1 ]] + +# A branch changed outside the inspected PR is never overwritten. +echo 'unrelated work' >unrelated +git add unrelated +git commit -qm 'feat: unrelated branch work' +git push -q origin HEAD:refs/heads/release-please--branches--main +unexpected="$(remote_head)" +candidate '2026-09-14T12:00:00Z' +if publish >"$scratch/conflict.log" 2>&1; then + echo 'unrelated remote work must be rejected' >&2 + exit 1 +fi +[[ "$(remote_head)" == "$unexpected" ]] +echo 'release PR publication converges across retries and new main; unrelated work is preserved' diff --git a/tools/release/publish-swiftpm-source-tag.sh b/tools/release/publish-swiftpm-source-tag.sh new file mode 100644 index 000000000..ac4cc3900 --- /dev/null +++ b/tools/release/publish-swiftpm-source-tag.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +set -euo pipefail +tool_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +repo="$(git rev-parse --show-toplevel)" +cd "$repo" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +data() { bash "$tool_root/tools/dev/bun.sh" --cwd "$repo" "$tool_root/tools/release/publish_swiftpm_source_tag.mts" "$1" "$scratch" "${@:2}"; } +fail() { echo "$*" >&2; exit 1; } +data --prepare "$@" +[[ -f "$scratch/context.json" ]] || exit 0 +export GIT_ASKPASS='' GIT_TERMINAL_PROMPT=0 SSH_ASKPASS='' +version="$(jq -r .version "$scratch/context.json")" +product="$(jq -r .product "$scratch/context.json")" +remote="$(jq -r .remote "$scratch/context.json")" +source_only="$(jq -r .projectSourceOnly "$scratch/context.json")" +ref="refs/tags/$version" +local_ref="$ref" +if [[ "$source_only" == true ]]; then local_ref="refs/oliphaunt-swiftpm/$product/$version"; fi +target="$(jq -r .target "$scratch/context.json")" +source_commit="$(git rev-parse --verify --end-of-options "$target^{commit}")" +source_tree="$(git rev-parse "$source_commit^{tree}")" +if jq -e '.source != null' "$scratch/context.json" >/dev/null; then + [[ "$source_commit" == "$(jq -r .source.commit "$scratch/context.json")" && + "$source_tree" == "$(jq -r .source.tree "$scratch/context.json")" ]] || fail 'SwiftPM source commit/tree differs from the frozen lock' +fi +tag_target="$source_commit" +expected_tree="$source_tree" +if jq -e '.manifest != null' "$scratch/context.json" >/dev/null; then + expected_tree="$( + export GIT_INDEX_FILE="$scratch/index" + if [[ "$source_only" == true ]]; then git read-tree --empty; else git read-tree "$source_tree"; fi + while IFS= read -r -d '' file && IFS= read -r -d '' git_path; do + blob="$(git hash-object -w --stdin < "$file")" + git update-index --add --cacheinfo "100644,$blob,$git_path" + done < "$scratch/files" + if [[ "$source_only" == true ]]; then + jq -n --arg product "$product" --arg version "$version" --arg commit "$source_commit" --arg tree "$source_tree" '{product:$product,version:$version,source:{commit:$commit,tree:$tree}}' > "$scratch/provenance.json" + blob="$(git hash-object -w --stdin < "$scratch/provenance.json")" + git update-index --add --cacheinfo "100644,$blob,oliphaunt-source.json" + fi + git write-tree + )" + timestamp="$(git show -s --format=%ct "$source_commit")" + [[ "$timestamp" =~ ^[0-9]+$ ]] || fail 'invalid source timestamp' + identity_path='tools/release/release-bot.json' + identity="$(git ls-tree --name-only "$source_commit" -- "$identity_path")" + if [[ -n "$identity" ]]; then git show "$source_commit:$identity_path" > "$scratch/identity"; else : > "$scratch/identity"; fi + data --identity + export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE + GIT_AUTHOR_NAME="$(jq -r .name "$scratch/identity.json")" + GIT_AUTHOR_EMAIL="$(jq -r .email "$scratch/identity.json")" + GIT_AUTHOR_DATE="$timestamp +0000" + GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" + GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL" + GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" + parents=(-p "$source_commit") + commit_message="Release Oliphaunt Swift $version SwiftPM manifest" + if [[ "$source_only" == true ]]; then parents=(); commit_message="Release $product $version SwiftPM source"; fi + tag_target="$(git commit-tree "$expected_tree" "${parents[@]}" -m "$commit_message")" +fi +if jq -e '.preflight or .push' "$scratch/context.json" >/dev/null; then + transport_timeout="$(command -v timeout || command -v gtimeout)" || fail 'GNU timeout is required for bounded Git transport' +fi +if jq -e .preflight "$scratch/context.json" >/dev/null; then + "$transport_timeout" --kill-after=5s 60s git ls-remote --refs --tags "$remote" "$ref" > "$scratch/remote" + data --remote "$tag_target" + exit 0 +fi +if existing="$(git rev-parse --verify --quiet "$local_ref^{commit}")"; then + if jq -e '.manifest != null' "$scratch/context.json" >/dev/null; then + expected_parent="$source_commit" + if [[ "$source_only" == true ]]; then expected_parent=''; fi + [[ "$(git show -s --format=%P "$existing")" == "$expected_parent" && + "$(git rev-parse "$existing^{tree}")" == "$expected_tree" ]] || fail 'existing SwiftPM tag has a different source or release tree' + tag_target="$existing" + else + [[ "$existing" == "$tag_target" ]] || fail 'existing SwiftPM tag has a different source' + fi +else + if [[ "$source_only" == true ]]; then git update-ref "$local_ref" "$tag_target" ''; else git tag "$version" "$tag_target"; fi +fi +if jq -e .push "$scratch/context.json" >/dev/null; then + data --admit + push_status=0 + "$transport_timeout" --kill-after=5s 60s git push --porcelain "$remote" "$local_ref:$ref" || push_status=$? + data --reconcile-ready + "$transport_timeout" --kill-after=5s 60s git ls-remote --refs --tags "$remote" "$ref" > "$scratch/remote" + data --remote "$tag_target" + if [[ "$push_status" != 0 ]]; then echo 'SwiftPM push failure reconciled to the exact remote tag'; fi +fi diff --git a/tools/release/publish_swiftpm_source_tag.mjs b/tools/release/publish_swiftpm_source_tag.mjs deleted file mode 100644 index a84dcf818..000000000 --- a/tools/release/publish_swiftpm_source_tag.mjs +++ /dev/null @@ -1,500 +0,0 @@ -#!/usr/bin/env bun -import { - mkdtempSync, - readdirSync, - readFileSync, - rmSync, - statSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { reserveGitHubContentWriteSync } from "./github-content-write-pacer.mjs"; -import { createGitHubOperationBudget } from "./github-release-mutations.mjs"; -import { currentVersion } from "./product-version.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const SEMVER_RE = /^(0|[1-9][0-9]*)[.](0|[1-9][0-9]*)[.](0|[1-9][0-9]*)(?:[-+][0-9A-Za-z.-]+)?$/u; -const FULL_SHA = /^[0-9a-f]{40}$/u; -const FIRST_OLIPHAUNT_SWIFTPM_VERSION = [0, 6, 0]; -const RELEASE_BOT_NAME = "oliphaunt-release-bot"; -const RELEASE_BOT_EMAIL = "oliphaunt-release-bot@users.noreply.github.com"; -export const SWIFTPM_PUSH_ATTEMPT_TIMEOUT_MS = 60_000; -export const SWIFTPM_PUSH_OPERATION_WINDOW_MS = 5 * 60_000; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function fail(message) { - console.error(`publish_swiftpm_source_tag.mjs: ${message}`); - process.exit(1); -} - -function usage(status = 1) { - const message = - "usage: tools/release/publish_swiftpm_source_tag.mjs [--target COMMITISH] [--manifest PACKAGE_SWIFT] [--include-tree TREE]... [--preflight|--push]"; - if (status === 0) { - console.log(message); - process.exit(0); - } - fail(message); -} - -function valueArg(argv, index, name) { - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) { - fail(`${name} requires a value`); - } - return value; -} - -function parseArgs(argv) { - const args = { - target: process.env.GITHUB_SHA || "HEAD", - manifest: undefined, - includeTrees: [], - preflight: false, - push: false, - }; - for (let index = 0; index < argv.length; ) { - const arg = argv[index]; - if (arg === "--target") { - args.target = valueArg(argv, index, arg); - index += 2; - } else if (arg === "--manifest") { - args.manifest = valueArg(argv, index, arg); - index += 2; - } else if (arg === "--include-tree") { - args.includeTrees.push(valueArg(argv, index, arg)); - index += 2; - } else if (arg === "--push") { - args.push = true; - index += 1; - } else if (arg === "--preflight") { - args.preflight = true; - index += 1; - } else if (arg === "--help" || arg === "-h") { - usage(0); - } else { - usage(); - } - } - if (!args.target) { - fail("--target must not be empty"); - } - if (args.preflight && args.push) { - fail("--preflight and --push are mutually exclusive"); - } - return args; -} - -function git(args, { - root = ROOT, - env = process.env, - check = true, - input = undefined, - timeoutMs = undefined, -} = {}) { - const nonInteractiveEnvironment = { - ...env, - GIT_ASKPASS: "", - GIT_TERMINAL_PROMPT: "0", - SSH_ASKPASS: "", - }; - const result = captureCommandOutput("git", args, { - cwd: root, - env: nonInteractiveEnvironment, - input, - label: `git ${args.join(" ")}`, - timeout: timeoutMs, - windowsHide: true, - }); - if (check && (result.error !== undefined || result.status !== 0)) { - const stderr = result.stderr.trim(); - const detail = stderr || result.error?.message || "unknown transport failure"; - fail(`git ${args.join(" ")} failed: ${detail}`); - } - return { - error: result.error, - status: result.status ?? (result.error === undefined ? 0 : 1), - stderr: result.stderr.trim(), - stdout: result.stdout.trim(), - }; -} - -function commitForRef(ref, root) { - return git(["rev-parse", `${ref}^{commit}`], { root }).stdout; -} - -function tagRef(tag) { - return `refs/tags/${tag}`; -} - -function tagCommit(tag, root) { - const result = git(["rev-parse", "--verify", "--quiet", `${tagRef(tag)}^{commit}`], { - root, - check: false, - }); - return result.status === 0 ? result.stdout : null; -} - -function stableVersionCore(version) { - const match = SEMVER_RE.exec(version); - return match === null ? null : match.slice(1, 4).map(Number); -} - -function compareVersionCore(left, right) { - for (let index = 0; index < left.length; index += 1) { - if (left[index] !== right[index]) { - return left[index] - right[index]; - } - } - return 0; -} - -async function swiftpmTag(versionOverride) { - const version = versionOverride ?? await currentVersion("oliphaunt-swift"); - if (!SEMVER_RE.test(version)) { - fail(`SwiftPM requires a semantic version tag; oliphaunt-swift version is ${JSON.stringify(version)}`); - } - if (compareVersionCore(stableVersionCore(version), FIRST_OLIPHAUNT_SWIFTPM_VERSION) < 0) { - fail( - `SwiftPM version tag ${version} collides with the legacy unscoped tag range; ` + - "the first Oliphaunt SwiftPM version is 0.6.0", - ); - } - return version; -} - -function commitParents(commit, root) { - const parts = git(["rev-list", "--parents", "-n", "1", commit], { root }).stdout.split(/\s+/u).filter(Boolean); - return parts.slice(1); -} - -function treeForCommit(commit, root) { - return git(["rev-parse", `${commit}^{tree}`], { root }).stdout; -} - -function syntheticCommitMatches(commit, parent, expectedTree, root) { - const parents = commitParents(commit, root); - return parents.length === 1 && parents[0] === parent && treeForCommit(commit, root) === expectedTree; -} - -function iterTreeFiles(root) { - const files = []; - function visit(directory) { - for (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) => compareText(a.name, b.name))) { - const file = path.join(directory, entry.name); - if (entry.isDirectory()) { - visit(file); - } else if (entry.isFile()) { - files.push(file); - } else { - fail(`SwiftPM generated release tree contains unsupported file type: ${file}`); - } - } - } - visit(root); - return files.sort(); -} - -function addBlobToIndex(root, env, indexPath, data) { - const result = git(["hash-object", "-w", "--stdin"], { root, env, input: data }); - git(["update-index", "--add", "--cacheinfo", `100644,${result.stdout},${indexPath}`], { root, env }); -} - -export function createSwiftpmReleaseTree(targetCommit, manifest, includeTrees, { root = ROOT } = {}) { - const baseTree = treeForCommit(targetCommit, root); - const tempRoot = mkdtempSync(path.join(tmpdir(), "oliphaunt-swiftpm-index.")); - try { - const env = { ...process.env, GIT_INDEX_FILE: path.join(tempRoot, "index") }; - git(["read-tree", baseTree], { root, env }); - addBlobToIndex(root, env, "Package.swift", manifest); - for (const includeTree of includeTrees) { - const includeRoot = path.resolve(root, includeTree); - if (!statSync(includeRoot, { throwIfNoEntry: false })?.isDirectory()) { - fail(`SwiftPM generated release tree does not exist: ${includeTree}`); - } - for (const file of iterTreeFiles(includeRoot)) { - const relative = path.relative(includeRoot, file).split(path.sep).join("/"); - if (relative === "Package.swift" || relative.startsWith(".git/") || relative.includes("/.git/")) { - fail(`SwiftPM generated release tree contains forbidden path: ${relative}`); - } - addBlobToIndex(root, env, relative, readFileSync(file)); - } - } - return git(["write-tree"], { root, env }).stdout; - } finally { - rmSync(tempRoot, { recursive: true, force: true }); - } -} - -function commitTimestamp(commit, root) { - const timestamp = git(["show", "-s", "--format=%ct", commit], { root }).stdout; - if (!/^[0-9]+$/u.test(timestamp)) { - fail(`could not derive a deterministic timestamp from release commit ${commit}`); - } - return `${timestamp} +0000`; -} - -export function createSwiftpmManifestCommit( - targetCommit, - tree, - version, - { root = ROOT, ambientEnv = process.env } = {}, -) { - const date = commitTimestamp(targetCommit, root); - // Freeze Git authorship with the source candidate, just like its tree and - // timestamp. Older approved candidates must retain their exact commit IDs. - const identityPath = "tools/release/release-bot.json"; - const identity = git(["ls-tree", "--name-only", targetCommit, "--", identityPath], { root }).stdout; - const bot = identity ? JSON.parse(git(["show", `${targetCommit}:${identityPath}`], { root }).stdout) - : { name: RELEASE_BOT_NAME, email: RELEASE_BOT_EMAIL }; - if (!bot || typeof bot.name !== "string" || !bot.name || typeof bot.email !== "string" || !bot.email || /[\r\n\0]/u.test(bot.name + bot.email)) { - throw new Error("invalid source-bound release bot identity"); - } - const env = { - ...ambientEnv, - GIT_AUTHOR_NAME: bot.name, - GIT_AUTHOR_EMAIL: bot.email, - GIT_AUTHOR_DATE: date, - GIT_COMMITTER_NAME: bot.name, - GIT_COMMITTER_EMAIL: bot.email, - GIT_COMMITTER_DATE: date, - }; - return git([ - "commit-tree", - tree, - "-p", - targetCommit, - "-m", - `Release Oliphaunt Swift ${version} SwiftPM manifest`, - ], { root, env }).stdout; -} - -function inspectExactRemoteTag({ environment, gitRunner, root, tag, timeoutMs }) { - const ref = tagRef(tag); - const result = gitRunner(["ls-remote", "--refs", "--tags", "origin", ref], { - root, - env: environment, - check: false, - timeoutMs, - }); - if (result.error !== undefined || result.status !== 0) { - throw new Error(`could not reconcile exact remote SwiftPM tag ${tag} within ${timeoutMs}ms`); - } - if (result.stdout === "") return null; - const rows = result.stdout.split(/\r?\n/u).filter(Boolean); - if (rows.length !== 1) { - throw new Error(`remote returned an ambiguous result for exact SwiftPM tag ${tag}`); - } - const match = /^([0-9a-f]{40})\t([^\s]+)$/u.exec(rows[0]); - if (match === null || match[2] !== ref) { - throw new Error(`remote returned malformed metadata for exact SwiftPM tag ${tag}`); - } - return match[1]; -} - -export function preflightSwiftpmSourceTagExactly({ - environment = process.env, - gitRunner = git, - root = ROOT, - tag, - tagTarget, - timeoutMs = SWIFTPM_PUSH_ATTEMPT_TIMEOUT_MS, -}) { - if (!SEMVER_RE.test(tag) || !FULL_SHA.test(tagTarget)) { - throw new TypeError("exact SwiftPM source-tag preflight requires a semantic version and full commit SHA"); - } - if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1) { - throw new TypeError("exact SwiftPM source-tag preflight requires a positive bounded read timeout"); - } - const remoteTarget = inspectExactRemoteTag({ - environment, - gitRunner, - root, - tag, - timeoutMs, - }); - if (remoteTarget === null) { - return { state: "absent", tag, tagTarget }; - } - if (remoteTarget !== tagTarget) { - throw new Error( - `SwiftPM source tag ${tag} points at ${remoteTarget}, not expected release commit ${tagTarget}`, - ); - } - return { state: "exact", tag, tagTarget }; -} - -export function pushSwiftpmSourceTagExactly({ - budget, - environment = process.env, - gitRunner = git, - pacerOptions = {}, - reserveContentWrite = reserveGitHubContentWriteSync, - root = ROOT, - tag, - tagTarget, - timeoutMs = SWIFTPM_PUSH_ATTEMPT_TIMEOUT_MS, -}) { - if (!SEMVER_RE.test(tag) || !FULL_SHA.test(tagTarget)) { - throw new TypeError("exact SwiftPM source-tag push requires a semantic version and full commit SHA"); - } - if ( - budget === null - || typeof budget !== "object" - || !Number.isSafeInteger(budget.deadlineMs) - || typeof budget.now !== "function" - || !Number.isSafeInteger(timeoutMs) - || timeoutMs < 1 - ) { - throw new TypeError("exact SwiftPM source-tag push requires a valid bounded operation budget"); - } - reserveContentWrite({ - environment, - label: `SwiftPM source tag ${tag} push`, - now: budget.now, - ...pacerOptions, - }); - // One complete interval is reserved for the push and another for the exact - // remote read used to resolve success, rejection, disconnect, or timeout. - const remainingAfterPacingMs = budget.deadlineMs - budget.now(); - if (remainingAfterPacingMs < (2 * timeoutMs)) { - throw new Error( - `SwiftPM source tag ${tag} push requires two complete ${timeoutMs}ms transport intervals after pacing; ` - + `${Math.max(0, remainingAfterPacingMs)}ms remains`, - ); - } - const ref = tagRef(tag); - const pushResult = gitRunner(["push", "--porcelain", "origin", `${ref}:${ref}`], { - root, - env: environment, - check: false, - timeoutMs, - }); - const remainingBeforeReconciliationMs = budget.deadlineMs - budget.now(); - if (remainingBeforeReconciliationMs < timeoutMs) { - throw new Error( - `SwiftPM source tag ${tag} push exhausted the deadline before exact remote reconciliation`, - ); - } - const remoteTarget = inspectExactRemoteTag({ - environment, - gitRunner, - root, - tag, - timeoutMs, - }); - if (remoteTarget === tagTarget) { - return { - reconciledAfterFailure: pushResult.error !== undefined || pushResult.status !== 0, - tag, - tagTarget, - }; - } - if (remoteTarget === null) { - throw new Error( - `SwiftPM source tag ${tag} is absent after the bounded push attempt`, - ); - } - throw new Error( - `SwiftPM source tag ${tag} points at ${remoteTarget}, not expected release commit ${tagTarget}`, - ); -} - -export async function ensureTag( - { target, manifest, includeTrees = [], preflight = false, push = false }, - { - reserveContentWrite = reserveGitHubContentWriteSync, - environment = process.env, - gitRunner = git, - now = Date.now, - operationBudget = undefined, - pacerOptions = {}, - pushTimeoutMs = SWIFTPM_PUSH_ATTEMPT_TIMEOUT_MS, - root = ROOT, - version: versionOverride, - } = {}, -) { - if (preflight && push) { - throw new TypeError("--preflight and --push are mutually exclusive"); - } - const version = await swiftpmTag(versionOverride); - const tag = version; - const targetCommit = commitForRef(target, root); - let tagTarget = targetCommit; - let expectedTree = treeForCommit(targetCommit, root); - let manifestText = null; - - if (manifest !== undefined) { - manifestText = readFileSync(path.resolve(root, manifest), "utf8"); - if (!manifestText.includes("binaryTarget(") || !manifestText.includes("liboliphaunt-native-v")) { - fail("SwiftPM release manifest must contain a checksum-pinned liboliphaunt binaryTarget"); - } - expectedTree = createSwiftpmReleaseTree(targetCommit, manifestText, includeTrees, { root }); - tagTarget = createSwiftpmManifestCommit(targetCommit, expectedTree, version, { root }); - } - - if (preflight) { - const outcome = preflightSwiftpmSourceTagExactly({ - environment, - gitRunner, - root, - tag, - tagTarget, - timeoutMs: pushTimeoutMs, - }); - if (outcome.state === "absent") { - console.log(`SwiftPM version tag ${tag} is absent on origin and available for exact publication at ${tagTarget}`); - } else { - console.log(`SwiftPM version tag ${tag} already points at exact release commit ${tagTarget} on origin`); - } - return tag; - } - - const existing = tagCommit(tag, root); - if (existing !== null) { - if (manifestText !== null && syntheticCommitMatches(existing, targetCommit, expectedTree, root)) { - console.log(`SwiftPM version tag ${tag} already points at a release manifest commit for ${targetCommit}`); - tagTarget = existing; - } else if (existing !== tagTarget) { - fail(`SwiftPM version tag ${tag} already points at ${existing}, not expected SwiftPM release commit ${tagTarget}`); - } else { - console.log(`SwiftPM version tag ${tag} already points at ${tagTarget}`); - } - } else { - git(["tag", tag, tagTarget], { root }); - console.log(`created SwiftPM version tag ${tag} at ${tagTarget}`); - } - - if (push) { - const budget = operationBudget ?? createGitHubOperationBudget({ - defaultWindowMs: SWIFTPM_PUSH_OPERATION_WINDOW_MS, - environment, - now, - }); - const outcome = pushSwiftpmSourceTagExactly({ - budget, - environment, - gitRunner, - pacerOptions, - reserveContentWrite, - root, - tag, - tagTarget, - timeoutMs: pushTimeoutMs, - }); - if (outcome.reconciledAfterFailure) { - console.log(`reconciled SwiftPM version tag ${tag} at ${tagTarget} after an ambiguous push result`); - } - console.log(`pushed SwiftPM version tag ${tag} to origin`); - } - return tag; -} - -if (import.meta.main) { - await ensureTag(parseArgs(Bun.argv.slice(2))); -} diff --git a/tools/release/publish_swiftpm_source_tag.mts b/tools/release/publish_swiftpm_source_tag.mts new file mode 100644 index 000000000..b8694bedc --- /dev/null +++ b/tools/release/publish_swiftpm_source_tag.mts @@ -0,0 +1,238 @@ +import { lstatSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { readSelectedRemoteTagMap } from '../../.github/scripts/manage-release-drafts.mts'; +import { currentVersion } from './product-version.mts'; +import { reserveGitHubContentWrite } from './github-content-write-pacer.mts'; +import { createGitHubOperationBudget } from './github-release-mutations.mts'; +import { loadPublicationLock, lockedProductArtifactPaths } from './publication-lock.mts'; +import { extractPortableArchiveTree } from '../packaging/portable-archive.mts'; + +const SEMVER = /^(0|[1-9][0-9]*)[.](0|[1-9][0-9]*)[.](0|[1-9][0-9]*)(?:[-+][0-9A-Za-z.-]+)?$/u; +const SHA = /^[0-9a-f]{40}$/u; +export const SWIFTPM_PUSH_ATTEMPT_TIMEOUT_MS = 60_000; + +function readJson(file) { + return JSON.parse(readFileSync(file, 'utf8')); +} + +async function prepare(scratch, argv) { + const args = { + target: process.env.GITHUB_SHA || 'HEAD', + includeTrees: [], + preflight: false, + push: false, + product: 'oliphaunt-swift', + }; + const seen = new Set(); + for (let index = 0; index < argv.length; index++) { + const flag = argv[index]; + if (flag === '--help' || flag === '-h') { + console.log( + 'usage: publish-swiftpm-source-tag.sh [--target REF] [--publication-lock FILE | --manifest FILE --include-tree TREE...] [--preflight | --push]', + ); + return; + } + if (flag === '--preflight' || flag === '--push') { + args[flag.slice(2)] = true; + continue; + } + const key = { + '--target': 'target', + '--release-commit': 'target', + '--publication-lock': 'lock', + '--manifest': 'manifest', + '--include-tree': 'includeTrees', + '--product': 'product', + '--repository': 'repository', + '--source-archive': 'sourceArchive', + }[flag]; + const value = argv[++index]; + if (!key || !value || value.startsWith('--')) + throw new Error('unknown or incomplete SwiftPM argument: ' + flag); + if (key === 'includeTrees') args.includeTrees.push(value); + else { + if (seen.has(key)) throw new Error('duplicate SwiftPM argument: ' + flag); + seen.add(key); + args[key] = value; + } + } + if (args.preflight && args.push) throw new Error('--preflight and --push are mutually exclusive'); + if (!['oliphaunt-swift', 'database-resources'].includes(args.product)) + throw new Error('unsupported SwiftPM product'); + if (args.repository && !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(args.repository)) + throw new Error('SwiftPM repository must be an owner/name'); + const resource = args.product === 'database-resources'; + if ( + resource && + (!args.repository || args.repository === (process.env.GITHUB_REPOSITORY ?? 'f0rr0/oliphaunt')) + ) + throw new Error('SwiftPM resources require a distinct distribution repository identity'); + args.remote = args.repository ? `https://github.com/${args.repository}.git` : 'origin'; + args.projectSourceOnly = resource; + const version = await currentVersion(args.product); + const core = SEMVER.exec(version); + if (!core || (!resource && Number(core[1]) === 0 && Number(core[2]) < 6)) + throw new Error( + 'SwiftPM requires a semantic version at least 0.6.0; older unscoped tags belong to legacy releases', + ); + if (args.lock) { + if (args.manifest || args.includeTrees.length || args.sourceArchive) + throw new Error('locked SwiftPM inputs cannot be overridden'); + const lock = loadPublicationLock(path.resolve(args.lock)); + if (lock.products.find((row) => row.id === args.product)?.version !== version) + throw new Error('SwiftPM version differs from the frozen lock'); + args.source = lock.source; + const inputs = lockedProductArtifactPaths(lock, args.product); + if (resource) { + const archives = inputs.filter( + ({ artifact, type }) => artifact.kind === 'swift-source' && type === 'file', + ); + if (archives.length !== 1) + throw new Error('resource publication lock must contain exactly one Swift source archive'); + args.sourceArchive = archives[0].path; + } else { + const manifests = inputs.filter( + ({ artifact, type }) => artifact.kind === 'swiftpm-release-manifest' && type === 'file', + ); + const trees = inputs.filter( + ({ artifact, type }) => artifact.kind === 'swiftpm-release-tree' && type === 'directory', + ); + if (manifests.length !== 1 || trees.length !== 1) + throw new Error( + 'publication lock must contain exactly one SwiftPM release manifest and tree', + ); + args.manifest = manifests[0].path; + args.includeTrees = [trees[0].path]; + } + } + if (resource) { + if (!args.sourceArchive || args.manifest || args.includeTrees.length) + throw new Error('resource SwiftPM publication requires one frozen source archive'); + const tree = path.join(scratch, 'resource-source'); + extractPortableArchiveTree(path.resolve(args.sourceArchive), tree); + args.manifest = path.join(tree, 'Package.swift'); + args.includeTrees = [tree]; + } else if (args.sourceArchive) + throw new Error('--source-archive is only for the resource product'); + const files = []; + if (args.manifest) { + const manifest = path.resolve(args.manifest); + const text = readFileSync(manifest, 'utf8'); + if (!resource && (!text.includes('binaryTarget(') || !text.includes('liboliphaunt-native-v'))) + throw new Error( + 'SwiftPM release manifest must contain a checksum-pinned liboliphaunt binaryTarget', + ); + files.push(manifest, 'Package.swift'); + for (const tree of args.includeTrees) { + const root = path.resolve(tree); + if (!lstatSync(root).isDirectory()) + throw new Error('SwiftPM generated release tree must be a directory'); + const visit = (directory) => { + for (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) => + a.name < b.name ? -1 : a.name > b.name ? 1 : 0, + )) { + const file = path.join(directory, entry.name); + const relative = path.relative(root, file).split(path.sep).join('/'); + if (resource && relative === 'Package.swift') continue; + if (relative === 'Package.swift' || relative.split('/').includes('.git')) + throw new Error('forbidden SwiftPM generated path: ' + relative); + if (entry.isDirectory()) visit(file); + else if (entry.isFile()) files.push(file, relative); + else throw new Error('unsupported SwiftPM generated file type: ' + relative); + } + }; + visit(root); + } + } else if (args.includeTrees.length) + throw new Error('--include-tree requires a release manifest'); + writeFileSync(path.join(scratch, 'files'), files.length ? files.join('\0') + '\0' : ''); + writeFileSync(path.join(scratch, 'context.json'), JSON.stringify({ ...args, version })); +} + +export function inspectSwiftpmRemoteTag(text, tag, expected, { allowMissing = false } = {}) { + if (!SEMVER.test(tag) || !SHA.test(expected)) + throw new Error('SwiftPM requires a semantic tag and full commit SHA'); + if (Buffer.byteLength(text) > 4 * 1024 * 1024) + throw new Error('oversized SwiftPM remote tag response'); + if (text === '') { + if (allowMissing) return 'absent'; + throw new Error('SwiftPM source tag is absent after the bounded push attempt'); + } + if (text !== expected + '\trefs/tags/' + tag + '\n') + throw new Error('SwiftPM remote tag is conflicting, malformed, or ambiguous'); + return 'exact'; +} + +async function main([phase, scratch, ...argv]) { + if (phase === '--prepare') return await prepare(scratch, argv); + if (phase === '--identity') { + const text = readFileSync(path.join(scratch, 'identity'), 'utf8'); + const bot = + text === '' + ? { name: 'oliphaunt-release-bot', email: 'oliphaunt-release-bot@users.noreply.github.com' } + : JSON.parse(text); + if ( + !bot || + typeof bot.name !== 'string' || + !bot.name || + typeof bot.email !== 'string' || + !bot.email || + /[\r\n\0]/u.test(bot.name + bot.email) + ) + throw new Error('invalid source-bound release bot identity'); + writeFileSync(path.join(scratch, 'identity.json'), JSON.stringify(bot)); + return; + } + const context = readJson(path.join(scratch, 'context.json')); + if (phase === '--admit') { + const budget = createGitHubOperationBudget({ + defaultWindowMs: 5 * 60_000, + environment: process.env, + now: Date.now, + }); + if (context.source) { + const tag = context.product + '-v' + context.version; + const tags = await readSelectedRemoteTagMap(process.env.GITHUB_REPOSITORY, [{ tag }], { + environment: process.env, + budget, + }); + const remote = tags.get(tag); + if (remote?.type !== 'commit' || remote.sha !== context.source.commit) + throw new Error('Swift product tag is not bound to the frozen source commit'); + } + await reserveGitHubContentWrite({ + environment: process.env, + label: 'SwiftPM source tag ' + context.version + ' push', + now: budget.now, + }); + if (budget.deadlineMs - budget.now() < 2 * (SWIFTPM_PUSH_ATTEMPT_TIMEOUT_MS + 5_000)) + throw new Error( + 'SwiftPM push requires two complete 60000ms transport intervals after pacing', + ); + writeFileSync(path.join(scratch, 'deadline'), String(budget.deadlineMs)); + } else if (phase === '--reconcile-ready') { + if ( + Number(readFileSync(path.join(scratch, 'deadline'), 'utf8')) - Date.now() < + SWIFTPM_PUSH_ATTEMPT_TIMEOUT_MS + 5_000 + ) + throw new Error('SwiftPM push exhausted the deadline before exact remote reconciliation'); + } else if (phase === '--remote') { + console.log( + inspectSwiftpmRemoteTag( + readFileSync(path.join(scratch, 'remote'), 'utf8'), + context.version, + argv[0], + { allowMissing: context.preflight }, + ), + ); + } else throw new Error('unknown SwiftPM data phase: ' + phase); +} + +if (import.meta.main) { + try { + await main(process.argv.slice(2)); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exitCode = 1; + } +} diff --git a/tools/release/publish_swiftpm_source_tag.test.mjs b/tools/release/publish_swiftpm_source_tag.test.mjs deleted file mode 100644 index 4f9c8173f..000000000 --- a/tools/release/publish_swiftpm_source_tag.test.mjs +++ /dev/null @@ -1,331 +0,0 @@ -import { expect, test } from "bun:test"; -import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import releaseBot from "./release-bot.json" with { type: "json" }; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -import { - createSwiftpmManifestCommit, - createSwiftpmReleaseTree, - ensureTag, - preflightSwiftpmSourceTagExactly, - pushSwiftpmSourceTagExactly, - SWIFTPM_PUSH_ATTEMPT_TIMEOUT_MS, -} from "./publish_swiftpm_source_tag.mjs"; - -function git(root, args, { env = process.env } = {}) { - const result = spawnSync("git", args, { - cwd: root, - env, - encoding: "utf8", - stdio: ["ignore", "pipe", "pipe"], - }); - if (result.status !== 0) { - throw new Error(`git ${args.join(" ")} failed: ${result.stderr.trim()}`); - } - return result.stdout.trim(); -} - -test("SwiftPM source tag is deterministic, resumable, and exact-release-tree bound", async () => { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-swiftpm-tag-test.")); - const remote = mkdtempSync(path.join(tmpdir(), "oliphaunt-swiftpm-tag-remote-test.")); - try { - git(root, ["init", "--quiet"]); - git(remote, ["init", "--quiet", "--bare"]); - git(root, ["remote", "add", "origin", remote]); - git(root, ["config", "user.name", "fixture"]); - git(root, ["config", "user.email", "fixture@example.invalid"]); - mkdirSync(path.join(root, "Sources"), { recursive: true }); - writeFileSync(path.join(root, "Package.swift"), "// development manifest\n", "utf8"); - writeFileSync(path.join(root, "Sources/Base.swift"), "public let base = true\n", "utf8"); - git(root, ["add", "."]); - git(root, ["commit", "--quiet", "-m", "release source"], { - env: { - ...process.env, - GIT_AUTHOR_DATE: "1700000000 +0000", - GIT_COMMITTER_DATE: "1700000000 +0000", - }, - }); - const releaseCommit = git(root, ["rev-parse", "HEAD^{commit}"]); - - const manifest = [ - "// swift-tools-version: 6.0", - "import PackageDescription", - "let package = Package(name: \"Oliphaunt\", targets: [", - " .binaryTarget(name: \"COliphaunt\", url: \"https://example.invalid/liboliphaunt-native-v0.1.0/apple-spm-xcframework.zip\", checksum: \"abc\")", - "])", - "", - ].join("\n"); - writeFileSync(path.join(root, "Package.swift.release"), manifest, "utf8"); - mkdirSync(path.join(root, "frozen-tree/generated/swiftpm"), { recursive: true }); - writeFileSync( - path.join(root, "frozen-tree/generated/swiftpm/Frozen.swift"), - "public let frozen = true\n", - "utf8", - ); - - const tree = createSwiftpmReleaseTree( - releaseCommit, - manifest, - ["frozen-tree"], - { root }, - ); - const firstSyntheticCommit = createSwiftpmManifestCommit( - releaseCommit, - tree, - "0.6.0", - { - root, - ambientEnv: { - ...process.env, - GIT_AUTHOR_DATE: "946684800 +0000", - GIT_COMMITTER_DATE: "946684800 +0000", - }, - }, - ); - const secondSyntheticCommit = createSwiftpmManifestCommit( - releaseCommit, - tree, - "0.6.0", - { - root, - ambientEnv: { - ...process.env, - GIT_AUTHOR_DATE: "1893456000 +0000", - GIT_COMMITTER_DATE: "1893456000 +0000", - }, - }, - ); - expect(secondSyntheticCommit).toBe(firstSyntheticCommit); - - await ensureTag( - { - target: releaseCommit, - manifest: "Package.swift.release", - includeTrees: ["frozen-tree"], - push: false, - }, - { root, version: "0.6.0" }, - ); - const tagCommit = git(root, ["rev-parse", "refs/tags/0.6.0^{commit}"]); - expect(tagCommit).toBe(firstSyntheticCommit); - expect(git(root, ["rev-parse", `${tagCommit}^`])).toBe(releaseCommit); - expect(git(root, ["rev-parse", `${tagCommit}^{tree}`])).toBe(tree); - expect(git(root, ["show", `${tagCommit}:Package.swift`])).toBe(manifest.trim()); - expect(git(root, ["show", `${tagCommit}:Sources/Base.swift`])).toBe("public let base = true"); - expect(git(root, ["show", `${tagCommit}:generated/swiftpm/Frozen.swift`])).toBe( - "public let frozen = true", - ); - - await ensureTag( - { - target: releaseCommit, - manifest: "Package.swift.release", - includeTrees: ["frozen-tree"], - push: false, - }, - { root, version: "0.6.0" }, - ); - expect(git(root, ["rev-parse", "refs/tags/0.6.0^{commit}"])).toBe(tagCommit); - - const reservations = []; - await ensureTag( - { - target: releaseCommit, - manifest: "Package.swift.release", - includeTrees: ["frozen-tree"], - push: true, - }, - { - reserveContentWrite: ({ label }) => { - expect(git(root, ["ls-remote", "--tags", "origin", "refs/tags/0.6.0"])).toBe(""); - reservations.push(label); - }, - root, - version: "0.6.0", - }, - ); - expect(reservations).toEqual(["SwiftPM source tag 0.6.0 push"]); - expect(git(root, ["ls-remote", "--tags", "origin", "refs/tags/0.6.0"])).toContain(tagCommit); - - writeFileSync( - path.join(root, "frozen-tree/generated/swiftpm/Frozen.swift"), - "public let frozen = false\n", - "utf8", - ); - const changedTree = createSwiftpmReleaseTree( - releaseCommit, - readFileSync(path.join(root, "Package.swift.release"), "utf8"), - ["frozen-tree"], - { root }, - ); - expect(changedTree).not.toBe(tree); - - expect(git(root, ["show", "-s", "--format=%an <%ae>", firstSyntheticCommit])).toBe( - "oliphaunt-release-bot ", - ); - mkdirSync(path.join(root, "tools/release"), { recursive: true }); - writeFileSync(path.join(root, "tools/release/release-bot.json"), JSON.stringify(releaseBot)); - git(root, ["add", "tools/release/release-bot.json"]); - git(root, ["commit", "-qm", "configure App identity"]); - const newSource = git(root, ["rev-parse", "HEAD"]); - const newCommit = createSwiftpmManifestCommit(newSource, tree, "0.7.0", { root }); - expect(git(root, ["show", "-s", "--format=%an <%ae>", newCommit])).toBe(`${releaseBot.name} <${releaseBot.email}>`); - // A publisher/working-tree identity change cannot alter an approved candidate. - writeFileSync(path.join(root, "tools/release/release-bot.json"), "invalid ambient identity"); - expect(createSwiftpmManifestCommit(newSource, tree, "0.7.0", { root })).toBe(newCommit); - expect(createSwiftpmManifestCommit(releaseCommit, tree, "0.6.0", { root })).toBe(firstSyntheticCommit); - } finally { - rmSync(root, { recursive: true, force: true }); - rmSync(remote, { recursive: true, force: true }); - } -}); - -test("SwiftPM push refuses to start unless pacing leaves two complete bounded attempts", () => { - let nowMs = 0; - let gitCalls = 0; - expect(() => pushSwiftpmSourceTagExactly({ - budget: { deadlineMs: (2 * SWIFTPM_PUSH_ATTEMPT_TIMEOUT_MS), now: () => nowMs }, - gitRunner: () => { gitCalls += 1; return { status: 0, stderr: "", stdout: "" }; }, - reserveContentWrite: () => { nowMs = 1; }, - tag: "0.6.0", - tagTarget: "a".repeat(40), - })).toThrow(/requires two complete 60000ms transport intervals after pacing/u); - expect(gitCalls).toBe(0); -}); - -test("SwiftPM push reconciles an applied timeout to one exact remote tag", () => { - const target = "a".repeat(40); - const calls = []; - const outcome = pushSwiftpmSourceTagExactly({ - budget: { deadlineMs: 180_000, now: () => 0 }, - gitRunner: (args, options) => { - calls.push({ args, timeoutMs: options.timeoutMs }); - if (args[0] === "push") { - return { - error: Object.assign(new Error("timed out"), { code: "ETIMEDOUT" }), - status: 1, - stderr: "", - stdout: "", - }; - } - return { status: 0, stderr: "", stdout: `${target}\trefs/tags/0.6.0` }; - }, - reserveContentWrite: () => {}, - tag: "0.6.0", - tagTarget: target, - }); - expect(outcome.reconciledAfterFailure).toBe(true); - expect(calls.map(({ timeoutMs }) => timeoutMs)).toEqual([60_000, 60_000]); - expect(calls[0].args).toEqual([ - "push", - "--porcelain", - "origin", - "refs/tags/0.6.0:refs/tags/0.6.0", - ]); - expect(calls[1].args).toEqual([ - "ls-remote", - "--refs", - "--tags", - "origin", - "refs/tags/0.6.0", - ]); -}); - -test("SwiftPM push rejects absent and conflicting reconciled remote state", () => { - const invoke = (remoteOutput) => pushSwiftpmSourceTagExactly({ - budget: { deadlineMs: 180_000, now: () => 0 }, - gitRunner: (args) => args[0] === "push" - ? { status: 1, stderr: "rejected", stdout: "" } - : { status: 0, stderr: "", stdout: remoteOutput }, - reserveContentWrite: () => {}, - tag: "0.6.0", - tagTarget: "a".repeat(40), - }); - expect(() => invoke("")).toThrow(/is absent after the bounded push attempt/u); - expect(() => invoke(`${"b".repeat(40)}\trefs/tags/0.6.0`)).toThrow( - /points at .* not expected release commit/u, - ); -}); - -test("SwiftPM preflight computes the exact release commit without creating a local tag or writing remotely", async () => { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-swiftpm-preflight-test.")); - const remote = mkdtempSync(path.join(tmpdir(), "oliphaunt-swiftpm-preflight-remote-test.")); - try { - git(root, ["init", "--quiet"]); - git(remote, ["init", "--quiet", "--bare"]); - git(root, ["remote", "add", "origin", remote]); - git(root, ["config", "user.name", "fixture"]); - git(root, ["config", "user.email", "fixture@example.invalid"]); - writeFileSync(path.join(root, "Package.swift"), "// development manifest\n", "utf8"); - git(root, ["add", "."]); - git(root, ["commit", "--quiet", "-m", "release source"], { - env: { - ...process.env, - GIT_AUTHOR_DATE: "1700000000 +0000", - GIT_COMMITTER_DATE: "1700000000 +0000", - }, - }); - const releaseCommit = git(root, ["rev-parse", "HEAD^{commit}"]); - const manifest = [ - "// swift-tools-version: 6.0", - "import PackageDescription", - "let package = Package(name: \"Oliphaunt\", targets: [", - " .binaryTarget(name: \"COliphaunt\", url: \"https://example.invalid/liboliphaunt-native-v0.1.0/apple-spm-xcframework.zip\", checksum: \"abc\")", - "])", - "", - ].join("\n"); - writeFileSync(path.join(root, "Package.swift.release"), manifest, "utf8"); - const tree = createSwiftpmReleaseTree(releaseCommit, manifest, [], { root }); - const expected = createSwiftpmManifestCommit(releaseCommit, tree, "0.6.0", { root }); - - await ensureTag({ - target: releaseCommit, - manifest: "Package.swift.release", - includeTrees: [], - preflight: true, - }, { root, version: "0.6.0" }); - expect(git(root, ["tag", "--list", "0.6.0"])).toBe(""); - expect(git(root, ["ls-remote", "--refs", "--tags", "origin", "refs/tags/0.6.0"])).toBe(""); - - git(root, ["push", "--quiet", "origin", `${expected}:refs/tags/0.6.0`]); - await ensureTag({ - target: releaseCommit, - manifest: "Package.swift.release", - includeTrees: [], - preflight: true, - }, { root, version: "0.6.0" }); - expect(git(root, ["tag", "--list", "0.6.0"])).toBe(""); - expect(git(root, ["ls-remote", "--refs", "--tags", "origin", "refs/tags/0.6.0"])).toBe( - `${expected}\trefs/tags/0.6.0`, - ); - } finally { - rmSync(root, { recursive: true, force: true }); - rmSync(remote, { recursive: true, force: true }); - } -}); - -test("SwiftPM preflight rejects conflicting, malformed, and ambiguous exact remote tag metadata", () => { - const tagTarget = "a".repeat(40); - const invoke = (stdout) => preflightSwiftpmSourceTagExactly({ - gitRunner: () => ({ status: 0, stderr: "", stdout }), - tag: "0.6.0", - tagTarget, - }); - expect(() => invoke(`${"b".repeat(40)}\trefs/tags/0.6.0`)).toThrow( - /points at .* not expected release commit/u, - ); - expect(() => invoke(`not-a-sha\trefs/tags/0.6.0`)).toThrow(/malformed metadata/u); - expect(() => invoke( - `${tagTarget}\trefs/tags/0.6.0\n${tagTarget}\trefs/tags/0.6.0`, - )).toThrow(/ambiguous result/u); -}); - -test("SwiftPM preflight and push modes are mutually exclusive", async () => { - await expect(ensureTag({ - target: "HEAD", - preflight: true, - push: true, - }, { version: "0.6.0" })).rejects.toThrow(/mutually exclusive/u); -}); diff --git a/tools/release/publish_swiftpm_source_tag.test.mts b/tools/release/publish_swiftpm_source_tag.test.mts new file mode 100644 index 000000000..cb839ff3c --- /dev/null +++ b/tools/release/publish_swiftpm_source_tag.test.mts @@ -0,0 +1,49 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import test from 'node:test'; +import { createDeterministicZip } from '../packaging/archive-directory.mts'; +import { inspectSwiftpmRemoteTag } from './publish_swiftpm_source_tag.mts'; +import { currentProductVersionSync } from './release-artifact-targets.mts'; +import releaseBot from './release-bot.json' with { type: 'json' }; + +const [mode, root] = process.argv.slice(2); +if (mode === 'prepare') { + const source = path.join(root, 'resource-package'); + mkdirSync(path.join(source, 'Sources/Resources'), { recursive: true }); + writeFileSync( + path.join(source, 'Package.swift'), + '// swift-tools-version: 6.0\nimport PackageDescription\nlet package = Package(name: "Resources", targets: [.target(name: "Resources")])\n', + ); + writeFileSync( + path.join(source, 'Sources/Resources/Resources.swift'), + 'public let resource = true\n', + ); + writeFileSync(path.join(source, 'LICENSE'), 'fixture license'); + writeFileSync(path.join(root, 'source.zip'), await createDeterministicZip(source)); + writeFileSync( + path.join(root, 'versions.json'), + JSON.stringify({ + resources: currentProductVersionSync('database-resources'), + swift: currentProductVersionSync('oliphaunt-swift'), + }), + ); + writeFileSync(path.join(root, 'release-bot.json'), JSON.stringify(releaseBot)); + process.exit(0); +} +test('SwiftPM reconciliation accepts only a complete single exact remote ref', () => { + const version = '1.2.3', + sha = 'a'.repeat(40), + ref = `refs/tags/${version}`, + exact = `${sha}\t${ref}\n`; + assert.equal(inspectSwiftpmRemoteTag(exact, version, sha), 'exact'); + assert.equal(inspectSwiftpmRemoteTag('', version, sha, { allowMissing: true }), 'absent'); + for (const text of [ + '', + exact.trim(), + exact + exact, + exact.replace(sha, 'b'.repeat(40)), + `not-a-sha\t${ref}\n`, + ]) + assert.throws(() => inspectSwiftpmRemoteTag(text, version, sha)); +}); diff --git a/tools/release/publish_swiftpm_source_tag.test.sh b/tools/release/publish_swiftpm_source_tag.test.sh new file mode 100644 index 000000000..2e8a5cb18 --- /dev/null +++ b/tools/release/publish_swiftpm_source_tag.test.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +if [[ "${1:-}" != --with-projects ]]; then + exec bash tools/ci/with-projects.sh --exec bash "$0" --with-projects +fi +source_root="$PWD" +bun test ./tools/release/publish_swiftpm_source_tag.test.mts +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +bun tools/release/publish_swiftpm_source_tag.test.mts prepare "$scratch" +publisher="$source_root/tools/release/publish-swiftpm-source-tag.sh" +export GITHUB_ACTIONS=false GITHUB_SHA='' OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH='' REGISTRY_JOB_HARD_DEADLINE_EPOCH='' +mkdir "$scratch/resource-repo" +cd "$scratch/resource-repo" +git init -q +git init -q --bare "$scratch/resource-remote" +git config user.name fixture +git config user.email fixture@example.invalid +git config "url.$scratch/resource-remote.insteadOf" https://github.com/fixture/resources.git +printf 'must not be distributed' > unrelated-monorepo-file +git add . +git commit -qm source +commit="$(git rev-parse HEAD)" +resource_version="$(jq -r .resources "$scratch/versions.json")" +local_ref="refs/oliphaunt-swiftpm/database-resources/$resource_version" +resource() { bash "$publisher" --target HEAD --product database-resources --repository fixture/resources --source-archive "$scratch/source.zip" "$@" > "$scratch/result" 2>&1; } +resource +projected="$(git rev-parse "$local_ref")" +[[ -z "$(git show -s --format=%P "$projected")" ]] +if git ls-tree --name-only "$projected" | rg -q unrelated-monorepo-file; then exit 1; fi +[[ "$(git show "$projected:oliphaunt-source.json" | jq -r .source.commit)" == "$commit" ]] +[[ "$(git show "$projected:LICENSE")" == 'fixture license' ]] +resource --push +[[ "$(git ls-remote --refs --tags https://github.com/fixture/resources.git "refs/tags/$resource_version")" == "$projected"$'\t'"refs/tags/$resource_version" ]] +resource +[[ "$(git rev-parse "$local_ref")" == "$projected" ]] +mkdir "$scratch/repo" +cd "$scratch/repo" +git init -q +git init -q --bare "$scratch/remote" +git remote add origin "$scratch/remote" +git config user.name fixture +git config user.email fixture@example.invalid +mkdir Sources +printf '// development manifest\n' > Package.swift +printf 'public let base = true\n' > Sources/Base.swift +git add . +GIT_AUTHOR_DATE='1700000000 +0000' GIT_COMMITTER_DATE='1700000000 +0000' git commit -qm 'release source' +source="$(git rev-parse HEAD)" +cat > Package.swift.release <<'SWIFT' +// swift-tools-version: 6.0 +import PackageDescription +let package = Package(name: "Oliphaunt", targets: [ + .binaryTarget(name: "COliphaunt", url: "https://example.invalid/liboliphaunt-native-v0.1.0/apple-spm-xcframework.zip", checksum: "abc") +]) +SWIFT +mkdir -p frozen-tree/generated/swiftpm +frozen=frozen-tree/generated/swiftpm/Frozen.swift +printf 'public let frozen = true\n' > "$frozen" +cp .git/index "$scratch/index" +version="$(jq -r .swift "$scratch/versions.json")" +ref="refs/tags/$version" +invoke() { bash "$publisher" --target HEAD --manifest Package.swift.release --include-tree frozen-tree "$@" > "$scratch/result" 2>&1; } +invoke --preflight +[[ -z "$(git tag --list "$version")" && -z "$(git ls-remote --refs --tags origin "$ref")" ]] +GIT_AUTHOR_DATE='946684800 +0000' GIT_COMMITTER_DATE='946684800 +0000' GIT_AUTHOR_NAME=ambient invoke +first="$(git rev-parse "$ref")" +[[ "$(git show -s --format=%P "$first")" == "$source" ]] +git show "$first:Package.swift" > "$scratch/manifest" +cmp Package.swift.release "$scratch/manifest" +[[ "$(git show "$first:Sources/Base.swift")" == 'public let base = true' ]] +[[ "$(git show "$first:generated/swiftpm/Frozen.swift")" == 'public let frozen = true' ]] +[[ "$(git show -s '--format=%an <%ae>' "$first")" == 'oliphaunt-release-bot ' ]] +cmp .git/index "$scratch/index" +git tag -d "$version" > /dev/null +GIT_AUTHOR_DATE='1893456000 +0000' GIT_COMMITTER_DATE='1893456000 +0000' invoke +[[ "$(git rev-parse "$ref")" == "$first" ]] +invoke +mkdir "$scratch/bin" +export SWIFT_REAL_GIT="$(command -v git)" SWIFT_PUSH_LOG="$scratch/pushes" +cat > "$scratch/bin/git" <<'SH' +#!/usr/bin/env bash +if [[ "$1" == push ]]; then + echo push >> "$SWIFT_PUSH_LOG" + "$SWIFT_REAL_GIT" "$@" + exit 7 +fi +exec "$SWIFT_REAL_GIT" "$@" +SH +chmod +x "$scratch/bin/git" +if PATH="$scratch/bin:$PATH" REGISTRY_JOB_HARD_DEADLINE_EPOCH="$(( $(date +%s)+90 ))" invoke --push; then exit 1; fi +rg -q 'requires two complete' "$scratch/result" +[[ -z "$(git ls-remote --refs --tags origin "$ref")" ]] +PATH="$scratch/bin:$PATH" invoke --push +rg -q 'failure reconciled' "$scratch/result" +[[ "$(cat "$scratch/pushes")" == push ]] +[[ "$(git ls-remote --refs --tags origin "$ref")" == "$first"$'\t'"$ref" ]] +git tag -d "$version" > /dev/null +invoke --preflight +[[ -z "$(git tag --list "$version")" ]] +invoke +printf 'public let frozen = false\n' > "$frozen" +if invoke; then exit 1; fi +if invoke --preflight; then exit 1; fi +[[ "$(git rev-parse "$ref")" == "$first" ]] +printf 'public let frozen = true\n' > "$frozen" +mkdir -p tools/release +cp "$scratch/release-bot.json" tools/release/release-bot.json +git add tools/release/release-bot.json +git commit -qm 'configure App identity' +git tag -d "$version" > /dev/null +printf 'invalid ambient identity' > tools/release/release-bot.json +invoke +[[ "$(git show -s '--format=%an <%ae>' "$ref")" == "$(jq -r '.name+" <"+.email+">"' "$scratch/release-bot.json")" ]] +if invoke --preflight --push; then exit 1; fi +echo 'SwiftPM: isolated resources, deterministic projection, exact tags and lost-response reconciliation passed' diff --git a/tools/release/qualified-release-replay.mjs b/tools/release/qualified-release-replay.mjs deleted file mode 100644 index 0509896f8..000000000 --- a/tools/release/qualified-release-replay.mjs +++ /dev/null @@ -1,83 +0,0 @@ -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; - -const EXACT_SHA = /^[0-9a-f]{40}$/u; -const POSITIVE_INTEGER = /^[1-9][0-9]*$/u; - -export function qualifiedReplayCandidateBinding({ - releaseSha, - runId, -}) { - const sha = String(releaseSha ?? "").toLowerCase(); - const normalizedRunId = String(runId ?? ""); - if (!EXACT_SHA.test(sha)) { - throw new Error("qualified release replay candidate binding requires an exact release SHA"); - } - if (!POSITIVE_INTEGER.test(normalizedRunId)) { - throw new Error("qualified release replay candidate binding requires a positive CI run ID"); - } - return Object.freeze({ - candidateRoot: "target/release-candidate", - candidateSha: sha, - qualificationMode: "full-payload", - runId: normalizedRunId, - }); -} - -function git(repo, args, { allowEmptyOutput = false, stdoutTerminator = undefined } = {}) { - const result = captureCommandOutput("git", args, { - allowEmptyOutput, - cwd: repo, - label: `git ${args.join(" ")}`, - stdoutTerminator, - }); - if (result.error || result.status !== 0) { - throw new Error( - result.stderr?.trim() - || result.error?.message - || `git ${args.join(" ")} failed`, - ); - } - return result.stdout.trim(); -} - -export function assertQualifiedReplaySourceState({ - repo, - headRef, - expectedSha, -}) { - const normalizedExpected = String(expectedSha ?? "").toLowerCase(); - if (!EXACT_SHA.test(normalizedExpected)) { - throw new Error("qualified release replay requires an exact 40-character RELEASE_HEAD_SHA"); - } - const checkoutHead = git(repo, ["rev-parse", "HEAD^{commit}"]).toLowerCase(); - if (checkoutHead !== normalizedExpected) { - throw new Error( - `qualified release replay checkout HEAD mismatch: expected ${normalizedExpected}, got ${checkoutHead}`, - ); - } - const resolved = git(repo, ["rev-parse", `${headRef}^{commit}`]).toLowerCase(); - if (resolved !== normalizedExpected) { - throw new Error(`qualified release replay head mismatch: expected ${normalizedExpected}, got ${resolved}`); - } - const suppressedIndexEntries = git(repo, ["ls-files", "-v", "-z"], { - allowEmptyOutput: true, - stdoutTerminator: "\0", - }) - .split("\0") - .filter((entry) => entry && (entry[0] === "S" || /[a-z]/u.test(entry[0]))); - if (suppressedIndexEntries.length > 0) { - const paths = suppressedIndexEntries.map((entry) => entry.slice(2)).join("\n"); - throw new Error( - `qualified release replay rejects index suppression flags (assume-unchanged or skip-worktree):\n${paths}`, - ); - } - const dirty = git(repo, ["status", "--porcelain=v1", "-z", "--untracked-files=all"], { - allowEmptyOutput: true, - stdoutTerminator: "\0", - }); - if (dirty) { - const paths = dirty.split("\0").filter(Boolean).join("\n"); - throw new Error(`qualified release replay requires a clean source checkout:\n${paths}`); - } - return { sha: resolved }; -} diff --git a/tools/release/qualified-release-replay.sh b/tools/release/qualified-release-replay.sh new file mode 100644 index 000000000..044d303e6 --- /dev/null +++ b/tools/release/qualified-release-replay.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +fail() { echo "$*" >&2; exit 2; } +[[ "$#" == 2 ]] || fail 'usage: qualified-release-replay.sh HEAD_REF EXPECTED_SHA' +head_ref="$1" +expected="$2" +[[ "$expected" =~ ^[0-9a-f]{40}$ ]] || fail 'qualified release replay requires an exact 40-character RELEASE_HEAD_SHA' +[[ "$(git rev-parse --verify 'HEAD^{commit}')" == "$expected" ]] || fail 'qualified release replay checkout HEAD mismatch' +[[ "$(git rev-parse --verify "$head_ref^{commit}")" == "$expected" ]] || fail 'qualified release replay head mismatch' +scratch="$(mktemp)" +trap 'rm -f "$scratch"' EXIT +git ls-files -v -z > "$scratch" +while IFS= read -r -d '' entry; do + case "${entry:0:1}" in + S|[a-z]) fail "qualified release replay rejects index suppression flags (assume-unchanged or skip-worktree): ${entry:2}" ;; + esac +done < "$scratch" +git status --porcelain=v1 -z --untracked-files=all > "$scratch" +if [[ -s "$scratch" ]]; then + echo 'qualified release replay requires a clean source checkout:' >&2 + while IFS= read -r -d '' entry; do printf '%s\n' "$entry" >&2; done < "$scratch" + exit 2 +fi diff --git a/tools/release/qualified-release-replay.test.mjs b/tools/release/qualified-release-replay.test.mjs deleted file mode 100644 index 96f598e9d..000000000 --- a/tools/release/qualified-release-replay.test.mjs +++ /dev/null @@ -1,142 +0,0 @@ -import assert from "node:assert/strict"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { test } from "node:test"; - -import { - assertQualifiedReplaySourceState, - qualifiedReplayCandidateBinding, -} from "./qualified-release-replay.mjs"; - -function git(repo, ...args) { - return execFileSync("git", args, { cwd: repo, encoding: "utf8" }).trim(); -} - -function fixture() { - const repo = mkdtempSync(path.join(tmpdir(), "oliphaunt-qualified-replay-")); - git(repo, "init", "--quiet"); - git(repo, "config", "user.name", "Oliphaunt Test"); - git(repo, "config", "user.email", "test@oliphaunt.dev"); - writeFileSync(path.join(repo, "tracked.txt"), "clean\n"); - git(repo, "add", "tracked.txt"); - git(repo, "commit", "--quiet", "-m", "test: fixture"); - return { repo, sha: git(repo, "rev-parse", "HEAD") }; -} - -test("qualified replay binds a clean checkout to one exact commit", () => { - const { repo, sha } = fixture(); - try { - assert.deepEqual( - assertQualifiedReplaySourceState({ repo, headRef: "HEAD", expectedSha: sha }), - { sha }, - ); - assert.throws( - () => assertQualifiedReplaySourceState({ repo, headRef: "HEAD", expectedSha: "0".repeat(40) }), - /head mismatch/iu, - ); - assert.throws( - () => assertQualifiedReplaySourceState({ repo, headRef: "HEAD", expectedSha: "abc" }), - /exact 40-character/u, - ); - } finally { - rmSync(repo, { recursive: true, force: true }); - } -}); - -test("qualified replay selects exact release evidence", () => { - const source = "1".repeat(40); - assert.deepEqual( - qualifiedReplayCandidateBinding({ - releaseSha: source, - runId: "123", - }), - { - candidateRoot: "target/release-candidate", - candidateSha: source, - qualificationMode: "full-payload", - runId: "123", - }, - ); - for (const fixture of [ - { - releaseSha: "not-a-sha", - runId: "123", - }, - { - releaseSha: source, - runId: "0", - }, - ]) { - assert.throws(() => qualifiedReplayCandidateBinding(fixture), /replay/u); - } -}); - -test("qualified replay rejects tracked, staged, and untracked source changes", () => { - for (const mutate of [ - (repo) => writeFileSync(path.join(repo, "tracked.txt"), "modified\n"), - (repo) => { - writeFileSync(path.join(repo, "tracked.txt"), "staged\n"); - git(repo, "add", "tracked.txt"); - }, - (repo) => writeFileSync(path.join(repo, "untracked.txt"), "untracked\n"), - ]) { - const { repo, sha } = fixture(); - try { - mutate(repo); - assert.throws( - () => assertQualifiedReplaySourceState({ repo, headRef: "HEAD", expectedSha: sha }), - /clean source checkout/u, - ); - } finally { - rmSync(repo, { recursive: true, force: true }); - } - } -}); - -test("qualified replay treats a newline-bearing untracked path as one complete dirty record", () => { - const { repo, sha } = fixture(); - try { - writeFileSync(path.join(repo, "untracked\nrecord.txt"), "untracked\n"); - assert.throws( - () => assertQualifiedReplaySourceState({ repo, headRef: "HEAD", expectedSha: sha }), - (error) => /clean source checkout/u.test(error.message) - && error.message.includes("untracked\nrecord.txt"), - ); - } finally { - rmSync(repo, { recursive: true, force: true }); - } -}); - -test("qualified replay rejects a clean checkout whose actual HEAD is not the qualified commit", () => { - const { repo, sha } = fixture(); - try { - writeFileSync(path.join(repo, "tracked.txt"), "second commit\n"); - git(repo, "add", "tracked.txt"); - git(repo, "commit", "--quiet", "-m", "test: move checkout head"); - assert.throws( - () => assertQualifiedReplaySourceState({ repo, headRef: sha, expectedSha: sha }), - /checkout HEAD mismatch/u, - ); - } finally { - rmSync(repo, { recursive: true, force: true }); - } -}); - -test("qualified replay rejects index flags that suppress tracked modifications", () => { - for (const flag of ["--assume-unchanged", "--skip-worktree"]) { - const { repo, sha } = fixture(); - try { - git(repo, "update-index", flag, "tracked.txt"); - writeFileSync(path.join(repo, "tracked.txt"), `${flag}\n`); - assert.equal(git(repo, "status", "--porcelain=v1", "--untracked-files=all"), ""); - assert.throws( - () => assertQualifiedReplaySourceState({ repo, headRef: "HEAD", expectedSha: sha }), - /index suppression flags/u, - ); - } finally { - rmSync(repo, { recursive: true, force: true }); - } - } -}); diff --git a/tools/release/qualified-release-replay.test.sh b/tools/release/qualified-release-replay.test.sh new file mode 100644 index 000000000..77b6d64dc --- /dev/null +++ b/tools/release/qualified-release-replay.test.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -euo pipefail +verifier="$(git rev-parse --show-toplevel)/tools/release/qualified-release-replay.sh" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +prepare() { + mkdir "$scratch/$1" + cd "$scratch/$1" + git init --quiet + git config user.name Fixture + git config user.email fixture@example.invalid + printf 'clean\n' > tracked.txt + git add tracked.txt + git commit --quiet -m fixture + sha="$(git rev-parse HEAD)" +} +reject() { + local message="$1"; shift + if bash "$verifier" "$@" > "$scratch/result" 2>&1; then echo 'Unqualified source accepted' >&2; exit 1; fi + rg -i -q "$message" "$scratch/result" +} +prepare clean +bash "$verifier" HEAD "$sha" +reject 'head mismatch' HEAD 0000000000000000000000000000000000000000 +reject 'exact 40-character' HEAD abc +for mode in tracked staged untracked newline; do + prepare "$mode" + case "$mode" in + tracked) printf 'modified\n' > tracked.txt ;; + staged) printf 'staged\n' > tracked.txt; git add tracked.txt ;; + untracked) printf 'untracked\n' > untracked.txt ;; + newline) printf 'untracked\n' > $'untracked\nrecord.txt' ;; + esac + reject 'clean source checkout' HEAD "$sha" + if [[ "$mode" == newline ]]; then rg -U -q $'untracked\nrecord.txt' "$scratch/result"; fi +done +prepare moved-head +printf 'second commit\n' > tracked.txt +git add tracked.txt +git commit --quiet -m next +reject 'checkout HEAD mismatch' "$sha" "$sha" +for flag in assume-unchanged skip-worktree; do + prepare "$flag" + git update-index "--$flag" tracked.txt + printf '%s\n' "$flag" > tracked.txt + [[ -z "$(git status --porcelain=v1 --untracked-files=all)" ]] + reject 'index suppression flags' HEAD "$sha" +done +echo 'Qualified replay: exact clean commit, dirty records and index suppression checks passed' diff --git a/tools/release/query.mts b/tools/release/query.mts new file mode 100644 index 000000000..54ab7f06d --- /dev/null +++ b/tools/release/query.mts @@ -0,0 +1,239 @@ +#!/usr/bin/env bun +import { parseArgs } from 'node:util'; + +import { + ciNpmPackageArtifactRows, + ciReleaseAssetArtifactRows, + extensionArtifactProductRoot, + extensionArtifactProductsForReleaseProducts, + extensionMemberPath, + extensionMetadata, + extensionReleaseProduct, + extensionSqlNames, + extensionSourceIdentity, + exactExtensionProducts, + sdkPackageProducts, +} from './release-artifact-targets.mts'; +import { compareText, loadProducts, releaseOrder } from './release-graph.mts'; +import { extensionNpmPackageForProduct } from '../../src/extensions/artifacts/packages/tools/extension-registry-packages.mts'; + +const TOOL = 'release_graph_query.mts'; + +function fail(message) { + console.error(`${TOOL}: ${message}`); + process.exit(2); +} + +function commandOptions(argv, options) { + try { + return parseArgs({ args: argv, options, strict: true, allowPositionals: false }).values; + } catch (error) { + fail(error.message); + } +} + +function sortedValue(value) { + if (Array.isArray(value)) return value.map(sortedValue); + if (value !== null && typeof value === 'object') { + return Object.fromEntries( + Object.keys(value) + .sort(compareText) + .map((key) => [key, sortedValue(value[key])]), + ); + } + return value; +} + +function printJson(value) { + console.log(JSON.stringify(sortedValue(value), null, 2)); +} + +function output(rows, format, field) { + if (format === 'lines') { + for (const value of new Set(rows.map((row) => row[field]))) console.log(value); + } else if (format === 'json') { + printJson(rows); + } else { + fail('--format must be json or lines'); + } +} + +function stringList(raw, flag) { + let value; + try { + value = JSON.parse(raw); + } catch (error) { + fail(`${flag} must be valid JSON: ${error.message}`); + } + if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) { + fail(`${flag} must be a JSON string list`); + } + return value; +} + +function orderedReleaseProducts(raw) { + const selected = stringList(raw, '--products-json'); + const products = loadProducts(TOOL); + const unknown = [...new Set(selected)] + .filter((product) => !(product in products)) + .sort(compareText); + if (unknown.length > 0) fail(`unknown release products: ${unknown.join(', ')}`); + return releaseOrder(products, undefined, selected, TOOL); +} + +function runCiArtifactNames(argv) { + const values = commandOptions(argv, { + family: { type: 'string' }, + product: { type: 'string' }, + kind: { type: 'string' }, + format: { type: 'string', default: 'json' }, + }); + if (!values.family) fail('--family is required'); + if (!values.product) fail('--product is required'); + + let rows; + if (values.family === 'release-assets') { + if (!values.kind) fail('--kind is required for release-assets artifacts'); + rows = ciReleaseAssetArtifactRows(values.product, values.kind, TOOL); + } else if (values.family === 'npm-package') { + if (!values.kind) fail('--kind is required for npm-package artifacts'); + rows = ciNpmPackageArtifactRows(values.product, values.kind, TOOL); + } else if (values.family === 'sdk-package') { + if (values.kind) fail('--kind is not accepted for sdk-package artifacts'); + rows = sdkPackageProducts(TOOL).filter((row) => row.product === values.product); + if (rows.length !== 1) fail(`${values.product} does not declare a source package artifact`); + } else { + fail('--family must be release-assets, npm-package, or sdk-package'); + } + output(rows, values.format, 'artifactName'); +} + +function runCiProducts(argv) { + const values = commandOptions(argv, { + family: { type: 'string' }, + 'carrier-family': { type: 'string' }, + field: { type: 'string', default: 'product' }, + 'products-json': { type: 'string' }, + format: { type: 'string', default: 'json' }, + }); + const carrierFamily = values['carrier-family']; + if (carrierFamily !== undefined && !['native', 'wasix'].includes(carrierFamily)) { + fail('--carrier-family must be native or wasix'); + } + if (!['product', 'artifact-root'].includes(values.field)) { + fail('--field must be product or artifact-root'); + } + if ( + values.family !== 'extension-artifacts' && + (carrierFamily !== undefined || values.field !== 'product') + ) { + fail('--carrier-family and non-product --field values require --family extension-artifacts'); + } + if (values.field !== 'product' && values.format !== 'lines') { + fail('non-product --field values require --format lines'); + } + + let availableRows; + if (values.family === 'sdk-package') { + availableRows = sdkPackageProducts(TOOL); + } else if (values.family === 'extension-artifacts') { + availableRows = exactExtensionProducts(TOOL).map((product) => ({ product })); + } else { + fail('--family must be sdk-package or extension-artifacts'); + } + + const rowsByProduct = new Map(availableRows.map((row) => [row.product, row])); + const selectedReleaseProducts = + values['products-json'] === undefined + ? undefined + : orderedReleaseProducts(values['products-json']); + const products = + selectedReleaseProducts === undefined + ? availableRows.map((row) => row.product) + : values.family === 'extension-artifacts' + ? extensionArtifactProductsForReleaseProducts(selectedReleaseProducts, { + family: carrierFamily, + prefix: TOOL, + }) + : selectedReleaseProducts.filter((product) => rowsByProduct.has(product)); + + if (values.field === 'product') { + output( + products.map((product) => rowsByProduct.get(product)), + values.format, + 'product', + ); + return; + } + + const selectedSet = + selectedReleaseProducts === undefined ? null : new Set(selectedReleaseProducts); + const roots = products.flatMap((product) => { + const families = carrierFamily === undefined ? ['native', 'wasix'] : [carrierFamily]; + return families + .filter( + (family) => + selectedSet === null || selectedSet.has(extensionReleaseProduct(product, family, TOOL)), + ) + .map((family) => + extensionArtifactProductRoot(product, family, 'target/extension-artifacts', TOOL), + ); + }); + for (const root of [...new Set(roots)]) console.log(root); +} + +function runExtensionArtifactRoot(argv) { + const values = commandOptions(argv, { + product: { type: 'string' }, + family: { type: 'string', default: 'native' }, + }); + if (!values.product) fail('--product is required'); + if (!['native', 'wasix'].includes(values.family)) fail('--family must be native or wasix'); + console.log( + extensionArtifactProductRoot(values.product, values.family, 'target/extension-artifacts', TOOL), + ); +} + +function runExtensionMetadata(argv) { + const values = commandOptions(argv, { product: { type: 'string' } }); + const products = values.product === undefined ? exactExtensionProducts(TOOL) : [values.product]; + printJson( + products.flatMap((product) => { + const metadata = extensionMetadata(product, TOOL); + return extensionSqlNames(product, TOOL).map((sqlName) => ({ + product, + cargoPackage: product, + npmPackage: extensionNpmPackageForProduct(product), + mavenGroup: 'dev.oliphaunt.extensions', + mavenArtifact: product, + ...metadata, + sqlName, + memberPath: extensionMemberPath(product, sqlName, TOOL), + sourceIdentity: extensionSourceIdentity(product, TOOL), + })); + }), + ); +} + +function usage() { + return `usage: tools/release/query.mts [options] + +Commands: + ci-artifact-names --family release-assets|npm-package|sdk-package --product PRODUCT [--kind KIND] [--format json|lines] + ci-products --family sdk-package|extension-artifacts [--products-json JSON] [--carrier-family native|wasix] [--field product|artifact-root] [--format json|lines] + extension-artifact-root --product PRODUCT [--family native|wasix] + extension-metadata [--product PRODUCT] +`; +} + +function main(argv) { + const [command, ...rest] = argv; + if (command === 'ci-artifact-names') runCiArtifactNames(rest); + else if (command === 'ci-products') runCiProducts(rest); + else if (command === 'extension-artifact-root') runExtensionArtifactRoot(rest); + else if (command === 'extension-metadata') runExtensionMetadata(rest); + else if (command === '--help' || command === '-h') console.log(usage()); + else fail(command ? `unknown command ${command}` : 'missing command'); +} + +if (import.meta.main) main(Bun.argv.slice(2)); diff --git a/tools/release/read-workflow.mjs b/tools/release/read-workflow.mjs deleted file mode 100644 index 138a96b7d..000000000 --- a/tools/release/read-workflow.mjs +++ /dev/null @@ -1,18 +0,0 @@ -import { readFileSync } from "node:fs"; -import path from "node:path"; - -export function parseWorkflow(root, relativePath) { - let workflow; - try { - workflow = Bun.YAML.parse(readFileSync(path.join(root, relativePath), "utf8")); - } catch (cause) { - throw new Error(`cannot parse ${relativePath}: ${cause.message}`); - } - if (workflow === null || typeof workflow !== "object" || Array.isArray(workflow)) { - throw new Error(`${relativePath} must contain a YAML object`); - } - if (workflow.jobs === null || typeof workflow.jobs !== "object" || Array.isArray(workflow.jobs)) { - throw new Error(`${relativePath} must declare jobs`); - } - return workflow; -} diff --git a/tools/release/registry-bootstrap-ledger-state.test.mjs b/tools/release/registry-bootstrap-ledger-state.test.mjs deleted file mode 100644 index 42737ea0e..000000000 --- a/tools/release/registry-bootstrap-ledger-state.test.mjs +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - classifyLedgerRequirement, - collectLedgerRows, -} from "../../.github/scripts/registry-bootstrap-ledger-state.mjs"; - -test("requires a ledger only for pre-tag current-version registry publications", () => { - assert.deepEqual(classifyLedgerRequirement([ - { product: "new", ecosystem: "npm", published: 0, tagState: "missing" }, - { product: "retry", ecosystem: "cargo", published: 1, tagState: "exact" }, - ]), { needsLedger: false, requiring: [] }); - - const bootstrap = classifyLedgerRequirement([ - { product: "bootstrap", ecosystem: "npm", published: 2, tagState: "missing" }, - ]); - assert.equal(bootstrap.needsLedger, true); - assert.deepEqual(bootstrap.requiring, [{ product: "bootstrap", ecosystem: "npm", published: 2 }]); - - assert.throws( - () => classifyLedgerRequirement([{ product: "conflict", ecosystem: "npm", published: 1, tagState: "wrong" }]), - /another commit/u, - ); -}); - -test("resolves product tags before registry reads and records exact-tag skips explicitly", () => { - const lock = { - products: [ - { id: "exact", version: "1.0.0" }, - { id: "missing", version: "2.0.0" }, - ], - }; - const queries = []; - const rows = collectLedgerRows({ - lock, - lockFile: "publication-lock.json", - products: ["exact", "missing"], - headCommit: "a".repeat(40), - }, { - carriersFor: (_lock, { product, ecosystem }) => - ecosystem === "cargo" || product === "exact" ? [{ id: `${product}:${ecosystem}` }] : [], - queryPublication: (_lock, product, ecosystem) => { - queries.push(`${product}:${ecosystem}`); - return { published: [{ id: "published" }], missing: [] }; - }, - resolveTagState: (product) => product === "exact" ? "exact" : "missing", - }); - - assert.deepEqual(queries, ["missing:cargo"]); - assert.deepEqual(rows, [ - { - product: "exact", - ecosystem: "cargo", - published: null, - missing: null, - queryState: "skipped-exact-tag", - tagState: "exact", - }, - { - product: "exact", - ecosystem: "npm", - published: null, - missing: null, - queryState: "skipped-exact-tag", - tagState: "exact", - }, - { - product: "missing", - ecosystem: "cargo", - published: 1, - missing: 0, - queryState: "queried", - tagState: "missing", - }, - ]); - assert.deepEqual(classifyLedgerRequirement(rows), { - needsLedger: true, - requiring: [{ product: "missing", ecosystem: "cargo", published: 1 }], - }); -}); - -test("rejects a wrong product tag before any registry query", () => { - let queries = 0; - assert.throws( - () => collectLedgerRows({ - lock: { products: [{ id: "conflict", version: "1.0.0" }] }, - lockFile: "publication-lock.json", - products: ["conflict"], - headCommit: "a".repeat(40), - }, { - carriersFor: () => [{ id: "must-not-be-read" }], - queryPublication: () => { - queries += 1; - return { published: [], missing: [] }; - }, - resolveTagState: () => "wrong", - }), - /another commit/u, - ); - assert.equal(queries, 0); -}); diff --git a/tools/release/registry-bootstrap-ledger-state.test.mts b/tools/release/registry-bootstrap-ledger-state.test.mts new file mode 100644 index 000000000..5c9fc1287 --- /dev/null +++ b/tools/release/registry-bootstrap-ledger-state.test.mts @@ -0,0 +1,129 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + classifyLedgerRequirement, + collectLedgerRows, + parseTagRefs, + tagState, +} from '../../.github/scripts/registry-bootstrap-ledger-state.mts'; + +test('requires a ledger only for pre-tag current-version registry publications', () => { + assert.deepEqual( + classifyLedgerRequirement([ + { product: 'new', ecosystem: 'npm', published: 0, tagState: 'missing' }, + { product: 'retry', ecosystem: 'cargo', published: 1, tagState: 'exact' }, + ]), + { needsLedger: false, requiring: [] }, + ); + + const bootstrap = classifyLedgerRequirement([ + { product: 'bootstrap', ecosystem: 'npm', published: 2, tagState: 'missing' }, + ]); + assert.equal(bootstrap.needsLedger, true); + assert.deepEqual(bootstrap.requiring, [{ product: 'bootstrap', ecosystem: 'npm', published: 2 }]); + + assert.throws( + () => + classifyLedgerRequirement([ + { product: 'conflict', ecosystem: 'npm', published: 1, tagState: 'wrong' }, + ]), + /another commit/u, + ); +}); + +test('resolves product tags before registry reads and records exact-tag skips explicitly', async () => { + const lock = { + products: [ + { id: 'exact', version: '1.0.0' }, + { id: 'missing', version: '2.0.0' }, + ], + }; + const queries = []; + const rows = await collectLedgerRows( + { + lock, + products: ['exact', 'missing'], + headCommit: 'a'.repeat(40), + }, + { + carriersFor: (_lock, { product, ecosystem }) => + ecosystem === 'cargo' || product === 'exact' ? [{ id: `${product}:${ecosystem}` }] : [], + queryPublication: (_lock, product, ecosystem) => { + queries.push(`${product}:${ecosystem}`); + return { published: [{ id: 'published' }], missing: [] }; + }, + resolveTagState: (product) => (product === 'exact' ? 'exact' : 'missing'), + }, + ); + + assert.deepEqual(queries, ['missing:cargo']); + assert.deepEqual(rows, [ + { + product: 'exact', + ecosystem: 'cargo', + published: null, + missing: null, + queryState: 'skipped-exact-tag', + tagState: 'exact', + }, + { + product: 'exact', + ecosystem: 'npm', + published: null, + missing: null, + queryState: 'skipped-exact-tag', + tagState: 'exact', + }, + { + product: 'missing', + ecosystem: 'cargo', + published: 1, + missing: 0, + queryState: 'queried', + tagState: 'missing', + }, + ]); + assert.deepEqual(classifyLedgerRequirement(rows), { + needsLedger: true, + requiring: [{ product: 'missing', ecosystem: 'cargo', published: 1 }], + }); +}); + +test('rejects a wrong product tag before any registry query', async () => { + let queries = 0; + await assert.rejects( + () => + collectLedgerRows( + { + lock: { products: [{ id: 'conflict', version: '1.0.0' }] }, + products: ['conflict'], + headCommit: 'a'.repeat(40), + }, + { + carriersFor: () => [{ id: 'must-not-be-read' }], + queryPublication: () => { + queries += 1; + return { published: [], missing: [] }; + }, + resolveTagState: () => 'wrong', + }, + ), + /another commit/u, + ); + assert.equal(queries, 0); +}); + +test('tag inventory prefers peeled annotations and distinguishes missing tags from wrong objects', () => { + const commit = 'a'.repeat(40), + object = 'b'.repeat(40); + const refs = parseTagRefs( + `${commit} refs/tags/direct-v1.0.0\n${object} refs/tags/annotated-v1.0.0\n${commit} refs/tags/annotated-v1.0.0^{}\n${object} refs/tags/wrong-v1.0.0\n`, + ); + assert.equal(tagState('direct', '1.0.0', commit, refs), 'exact'); + assert.equal(tagState('annotated', '1.0.0', commit, refs), 'exact'); + assert.equal(tagState('wrong', '1.0.0', commit, refs), 'wrong'); + assert.equal(tagState('absent', '1.0.0', commit, refs), 'missing'); + assert.throws(() => parseTagRefs('bad refs/tags/direct-v1.0.0'), /invalid/); +}); diff --git a/tools/release/registry-http-retry.mjs b/tools/release/registry-http-retry.mjs deleted file mode 100644 index 27fd0f8f3..000000000 --- a/tools/release/registry-http-retry.mjs +++ /dev/null @@ -1,108 +0,0 @@ -const RETRYABLE_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504]); -export const CRATES_IO_READ_START_INTERVAL_MILLISECONDS = 250; - -function readGateError(message) { - return new Error(`registry-http-retry: ${message}`); -} - -export function createCratesIoReadGate({ - nowImpl = () => Date.now() / 1000, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - intervalMilliseconds = CRATES_IO_READ_START_INTERVAL_MILLISECONDS, - deadlineReserveMilliseconds = 5_000, -} = {}) { - if (!Number.isSafeInteger(intervalMilliseconds) || intervalMilliseconds < 1) { - throw readGateError("crates.io read-start interval must be a positive integer number of milliseconds"); - } - if (!Number.isSafeInteger(deadlineReserveMilliseconds) || deadlineReserveMilliseconds < 0) { - throw readGateError("crates.io read deadline reserve must be a non-negative integer number of milliseconds"); - } - let nextStartMilliseconds = 0; - let notBeforeMilliseconds = 0; - let observedMilliseconds = 0; - let queue = Promise.resolve(); - - return { - defer(seconds) { - if (!Number.isFinite(seconds) || seconds < 0) { - throw readGateError("crates.io shared read deferral must be a non-negative number of seconds"); - } - notBeforeMilliseconds = Math.max( - notBeforeMilliseconds, - Math.max(nowImpl() * 1000, observedMilliseconds) + Math.ceil(seconds * 1000), - ); - }, - - async beforeRequest(label, deadlineEpochSeconds = null) { - if ( - deadlineEpochSeconds !== null - && (!Number.isFinite(deadlineEpochSeconds) || deadlineEpochSeconds <= 0) - ) { - throw readGateError("crates.io read deadline must be a positive Unix timestamp or null"); - } - let release; - const predecessor = queue; - queue = new Promise((resolve) => { - release = resolve; - }); - await predecessor; - try { - for (;;) { - const nowMilliseconds = Math.max(nowImpl() * 1000, observedMilliseconds); - const admittedStartMilliseconds = Math.max( - nextStartMilliseconds, - notBeforeMilliseconds, - ); - const delayMilliseconds = Math.max( - 0, - Math.ceil(admittedStartMilliseconds - nowMilliseconds), - ); - const remainingMilliseconds = deadlineEpochSeconds === null - ? Number.POSITIVE_INFINITY - : (deadlineEpochSeconds * 1000) - nowMilliseconds - deadlineReserveMilliseconds; - if (delayMilliseconds >= remainingMilliseconds) { - throw readGateError(`read-only existence check for ${label} cannot start before the registry mutation deadline`); - } - if (delayMilliseconds === 0) { - observedMilliseconds = nowMilliseconds; - nextStartMilliseconds = nowMilliseconds + intervalMilliseconds; - return nowMilliseconds / 1000; - } - await sleepImpl(delayMilliseconds); - observedMilliseconds = nowMilliseconds + delayMilliseconds; - } - } finally { - release(); - } - }, - }; -} - -export function registryStatusRetryable(status) { - return RETRYABLE_STATUSES.has(status); -} - -export function retryAfterSeconds(headers, now = Date.now()) { - const value = headers?.get?.("retry-after")?.trim(); - if (!value) return null; - if (/^\d+(?:\.\d+)?$/u.test(value)) { - return Math.max(0, Number(value)); - } - const date = Date.parse(value); - return Number.isFinite(date) ? Math.max(0, (date - now) / 1000) : null; -} - -export function registryRetryDelaySeconds({ - headers = undefined, - attempt, - baseSeconds = 1, - random = Math.random, - now = Date.now(), -}) { - const requested = retryAfterSeconds(headers, now); - if (requested !== null) { - return Math.min(300, requested); - } - const exponential = Math.min(60, Math.max(0, baseSeconds) * (2 ** attempt)); - return exponential * (0.75 + random() * 0.5); -} diff --git a/tools/release/registry-http-retry.mts b/tools/release/registry-http-retry.mts new file mode 100644 index 000000000..0d2feddb8 --- /dev/null +++ b/tools/release/registry-http-retry.mts @@ -0,0 +1,114 @@ +const RETRYABLE_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504]); +export const CRATES_IO_READ_START_INTERVAL_MILLISECONDS = 250; + +function readGateError(message) { + return new Error(`registry-http-retry: ${message}`); +} + +export function createCratesIoReadGate({ + nowImpl = () => Date.now() / 1000, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + intervalMilliseconds = CRATES_IO_READ_START_INTERVAL_MILLISECONDS, + deadlineReserveMilliseconds = 5_000, +} = {}) { + if (!Number.isSafeInteger(intervalMilliseconds) || intervalMilliseconds < 1) { + throw readGateError( + 'crates.io read-start interval must be a positive integer number of milliseconds', + ); + } + if (!Number.isSafeInteger(deadlineReserveMilliseconds) || deadlineReserveMilliseconds < 0) { + throw readGateError( + 'crates.io read deadline reserve must be a non-negative integer number of milliseconds', + ); + } + let nextStartMilliseconds = 0; + let notBeforeMilliseconds = 0; + let observedMilliseconds = 0; + let queue = Promise.resolve(); + + return { + defer(seconds) { + if (!Number.isFinite(seconds) || seconds < 0) { + throw readGateError( + 'crates.io shared read deferral must be a non-negative number of seconds', + ); + } + notBeforeMilliseconds = Math.max( + notBeforeMilliseconds, + Math.max(nowImpl() * 1000, observedMilliseconds) + Math.ceil(seconds * 1000), + ); + }, + + async beforeRequest(label, deadlineEpochSeconds = null) { + if ( + deadlineEpochSeconds !== null && + (!Number.isFinite(deadlineEpochSeconds) || deadlineEpochSeconds <= 0) + ) { + throw readGateError('crates.io read deadline must be a positive Unix timestamp or null'); + } + let release; + const predecessor = queue; + queue = new Promise((resolve) => { + release = resolve; + }); + await predecessor; + try { + for (;;) { + const nowMilliseconds = Math.max(nowImpl() * 1000, observedMilliseconds); + const admittedStartMilliseconds = Math.max(nextStartMilliseconds, notBeforeMilliseconds); + const delayMilliseconds = Math.max( + 0, + Math.ceil(admittedStartMilliseconds - nowMilliseconds), + ); + const remainingMilliseconds = + deadlineEpochSeconds === null + ? Number.POSITIVE_INFINITY + : deadlineEpochSeconds * 1000 - nowMilliseconds - deadlineReserveMilliseconds; + if (delayMilliseconds >= remainingMilliseconds) { + throw readGateError( + `read-only existence check for ${label} cannot start before the registry mutation deadline`, + ); + } + if (delayMilliseconds === 0) { + observedMilliseconds = nowMilliseconds; + nextStartMilliseconds = nowMilliseconds + intervalMilliseconds; + return nowMilliseconds / 1000; + } + await sleepImpl(delayMilliseconds); + observedMilliseconds = nowMilliseconds + delayMilliseconds; + } + } finally { + release(); + } + }, + }; +} + +export function registryStatusRetryable(status) { + return RETRYABLE_STATUSES.has(status); +} + +export function retryAfterSeconds(headers, now = Date.now()) { + const value = headers?.get?.('retry-after')?.trim(); + if (!value) return null; + if (/^\d+(?:\.\d+)?$/u.test(value)) { + return Math.max(0, Number(value)); + } + const date = Date.parse(value); + return Number.isFinite(date) ? Math.max(0, (date - now) / 1000) : null; +} + +export function registryRetryDelaySeconds({ + headers = undefined, + attempt, + baseSeconds = 1, + random = Math.random, + now = Date.now(), +}) { + const requested = retryAfterSeconds(headers, now); + if (requested !== null) { + return Math.min(300, requested); + } + const exponential = Math.min(60, Math.max(0, baseSeconds) * 2 ** attempt); + return exponential * (0.75 + random() * 0.5); +} diff --git a/tools/release/registry-http-retry.test.mjs b/tools/release/registry-http-retry.test.mjs deleted file mode 100644 index 79b00acc1..000000000 --- a/tools/release/registry-http-retry.test.mjs +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { - registryRetryDelaySeconds, - registryStatusRetryable, - retryAfterSeconds, -} from "./registry-http-retry.mjs"; - -describe("registry HTTP backoff", () => { - test("honors Retry-After seconds and dates", () => { - expect(retryAfterSeconds(new Headers({ "Retry-After": "42" }))).toBe(42); - expect(retryAfterSeconds( - new Headers({ "Retry-After": "Wed, 21 Oct 2015 07:28:00 GMT" }), - Date.parse("Wed, 21 Oct 2015 07:27:00 GMT"), - )).toBe(60); - expect(registryRetryDelaySeconds({ headers: new Headers({ "Retry-After": "999" }), attempt: 0 })).toBe(300); - }); - - test("uses bounded exponential jitter without a server delay", () => { - expect(registryRetryDelaySeconds({ attempt: 3, baseSeconds: 2, random: () => 0.5 })).toBe(16); - expect(registryRetryDelaySeconds({ attempt: 20, baseSeconds: 2, random: () => 0.5 })).toBe(60); - }); - - test("retries only transient registry statuses", () => { - for (const status of [408, 425, 429, 500, 502, 503, 504]) expect(registryStatusRetryable(status)).toBe(true); - for (const status of [400, 401, 403, 404, 409, 501]) expect(registryStatusRetryable(status)).toBe(false); - }); -}); diff --git a/tools/release/registry-http-retry.test.mts b/tools/release/registry-http-retry.test.mts new file mode 100644 index 000000000..74c148cf5 --- /dev/null +++ b/tools/release/registry-http-retry.test.mts @@ -0,0 +1,34 @@ +import { describe, expect, test } from 'bun:test'; + +import { + registryRetryDelaySeconds, + registryStatusRetryable, + retryAfterSeconds, +} from './registry-http-retry.mts'; + +describe('registry HTTP backoff', () => { + test('honors Retry-After seconds and dates', () => { + expect(retryAfterSeconds(new Headers({ 'Retry-After': '42' }))).toBe(42); + expect( + retryAfterSeconds( + new Headers({ 'Retry-After': 'Wed, 21 Oct 2015 07:28:00 GMT' }), + Date.parse('Wed, 21 Oct 2015 07:27:00 GMT'), + ), + ).toBe(60); + expect( + registryRetryDelaySeconds({ headers: new Headers({ 'Retry-After': '999' }), attempt: 0 }), + ).toBe(300); + }); + + test('uses bounded exponential jitter without a server delay', () => { + expect(registryRetryDelaySeconds({ attempt: 3, baseSeconds: 2, random: () => 0.5 })).toBe(16); + expect(registryRetryDelaySeconds({ attempt: 20, baseSeconds: 2, random: () => 0.5 })).toBe(60); + }); + + test('retries only transient registry statuses', () => { + for (const status of [408, 425, 429, 500, 502, 503, 504]) + expect(registryStatusRetryable(status)).toBe(true); + for (const status of [400, 401, 403, 404, 409, 501]) + expect(registryStatusRetryable(status)).toBe(false); + }); +}); diff --git a/tools/release/registry-integrity.mjs b/tools/release/registry-integrity.mjs deleted file mode 100644 index 7251e348d..000000000 --- a/tools/release/registry-integrity.mjs +++ /dev/null @@ -1,827 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import { - lstatSync, - linkSync, - mkdirSync, - readFileSync, - statSync, - unlinkSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import process from "node:process"; - -import { createCratesIoReadGate } from "./registry-http-retry.mjs"; -import { loadPublicationLock } from "./publication-lock.mjs"; -import { ROOT, compareText } from "./release-graph.mjs"; -const CRATES_IO_API = process.env.CRATES_IO_API || "https://crates.io/api/v1"; -const DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org"; -const MAVEN_CENTRAL_BASE = process.env.MAVEN_CENTRAL_BASE || "https://repo1.maven.org/maven2"; -const USER_AGENT = "oliphaunt-release-integrity (https://github.com/f0rr0/oliphaunt)"; -const SUPPORTED_ECOSYSTEMS = new Set(["cargo", "npm", "maven"]); -const RETRYABLE_HTTP_STATUS = new Set([408, 425, 429, 500, 502, 503, 504]); -const REQUEST_ATTEMPTS = 8; -const REQUEST_TIMEOUT_MS = 45_000; -const DEADLINE_RESERVE_MS = 5_000; -const MAX_TRANSIENT_RETRY_DELAY_MS = 30_000; -const MAX_RATE_LIMIT_RETRY_DELAY_MS = 5 * 60_000; -const MAX_RETRY_DELAY_BUDGET_MS = 10 * 60_000; -const MAX_METADATA_RESPONSE_BYTES = 8 * 1024 * 1024; -const MAX_REGISTRY_RECEIPT_EVIDENCE_BYTES = 64 * 1024 * 1024; -export const REGISTRY_RECEIPT_EVIDENCE_SCHEMA = "oliphaunt-registry-integrity-receipts-v1"; -const DEFAULT_CRATES_IO_READ_GATE = createCratesIoReadGate(); - -class RegistryHttpError extends Error { - constructor(url, status, retryAfter) { - super(`registry returned HTTP ${status} for ${url}`); - this.status = status; - this.retryAfter = retryAfter; - } -} - -class RegistryResponseError extends Error {} - -function mutationDeadlineEpochSeconds() { - const raw = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH?.trim(); - if (!raw) return null; - if (!/^[1-9][0-9]*$/u.test(raw)) { - throw new RegistryResponseError("REGISTRY_MUTATION_DEADLINE_EPOCH must be a positive Unix timestamp"); - } - const deadline = Number(raw); - if (!Number.isSafeInteger(deadline) || !Number.isSafeInteger(deadline * 1000)) { - throw new RegistryResponseError("REGISTRY_MUTATION_DEADLINE_EPOCH exceeds the safe timestamp range"); - } - return deadline; -} - -function mutationDeadlineRemainingMilliseconds(context) { - const deadlineEpochSeconds = mutationDeadlineEpochSeconds(); - if (deadlineEpochSeconds === null) return null; - const deadline = deadlineEpochSeconds * 1000; - const remaining = deadline - Date.now() - DEADLINE_RESERVE_MS; - if (remaining <= 0) { - throw new RegistryResponseError(`${context} refused because the shared registry mutation deadline has been reached`); - } - return remaining; -} - -function error(message) { - return new Error(`registry-integrity: ${message}`); -} - -function canonicalNpmRegistry() { - const raw = (process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY).trim(); - let parsed; - try { - parsed = new URL(raw); - } catch { - throw error(`npm registry must be the canonical public registry ${DEFAULT_NPM_REGISTRY}`); - } - const normalizedPath = parsed.pathname.replace(/\/+$/u, "") || "/"; - if ( - parsed.protocol !== "https:" - || parsed.hostname !== "registry.npmjs.org" - || (parsed.port !== "" && parsed.port !== "443") - || normalizedPath !== "/" - || parsed.username !== "" - || parsed.password !== "" - || parsed.search !== "" - || parsed.hash !== "" - ) { - throw error(`npm registry must be the canonical public registry ${DEFAULT_NPM_REGISTRY}`); - } - return DEFAULT_NPM_REGISTRY; -} - -function hashFile(file, algorithm, encoding = "hex") { - return createHash(algorithm).update(readFileSync(file)).digest(encoding); -} - -function stableJson(value) { - if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`; - if (value !== null && typeof value === "object") { - return `{${Object.keys(value).sort(compareText).map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`; - } - return JSON.stringify(value); -} - -function exactKeys(value, keys, context) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(`${context} must be an object`); - } - const observed = Object.keys(value).sort(compareText); - const expected = [...keys].sort(compareText); - if (stableJson(observed) !== stableJson(expected)) { - throw error(`${context} keys must be exactly ${expected.join(", ")}`); - } -} - -function digestValue(value) { - return createHash("sha256").update(stableJson(value)).digest("hex"); -} - -function requireLockedFile(artifact, suffix, carrier) { - if (!artifact.path.endsWith(suffix)) { - throw error(`${carrier.id} locked artifact ${artifact.path} is not a ${suffix} publication archive`); - } - const file = path.resolve(ROOT, artifact.path); - let stat; - try { - stat = statSync(file); - } catch { - throw error(`${carrier.id} locked artifact is unavailable: ${artifact.path}`); - } - if (!stat.isFile() || stat.size !== artifact.size || hashFile(file, "sha256") !== artifact.sha256) { - throw error(`${carrier.id} local publication archive no longer matches the frozen lock: ${artifact.path}`); - } - return file; -} - -function retryAfterMilliseconds(value) { - if (typeof value !== "string" || value.trim().length === 0) return null; - const seconds = Number(value); - if (Number.isFinite(seconds) && seconds >= 0) return Math.ceil(seconds * 1000); - const timestamp = Date.parse(value); - if (Number.isNaN(timestamp)) return null; - return Math.max(0, timestamp - Date.now()); -} - -function retryDelay(attempt, cause) { - if (cause instanceof RegistryHttpError && cause.retryAfter !== null) return cause.retryAfter; - if (cause instanceof RegistryHttpError && cause.status === 429) { - return Math.min(60_000 * (2 ** attempt), MAX_RATE_LIMIT_RETRY_DELAY_MS); - } - const exponential = Math.min(500 * (2 ** attempt), MAX_TRANSIENT_RETRY_DELAY_MS); - return Math.round(exponential * (0.75 + Math.random() * 0.5)); -} - -function retryable(cause) { - if (cause instanceof RegistryResponseError) return false; - return !(cause instanceof RegistryHttpError) || RETRYABLE_HTTP_STATUS.has(cause.status); -} - -function declaredResponseLength(response, context) { - const contentLength = response.headers?.get?.("content-length"); - if (contentLength === null || contentLength === undefined) return null; - const declared = Number(contentLength); - if (!Number.isSafeInteger(declared) || declared < 0) { - throw new RegistryResponseError(`${context} returned an invalid Content-Length`); - } - return declared; -} - -async function boundedResponseBytes(response, maximum, context) { - const declared = declaredResponseLength(response, context); - if (declared !== null && declared > maximum) { - await response.body?.cancel?.().catch(() => {}); - throw new RegistryResponseError(`${context} response exceeds ${maximum} bytes`); - } - const reader = response.body?.getReader?.(); - if (reader === undefined) { - const bytes = Buffer.from(await response.arrayBuffer()); - if (bytes.length > maximum) { - throw new RegistryResponseError(`${context} response exceeds ${maximum} bytes`); - } - return bytes; - } - const chunks = []; - let size = 0; - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > maximum) { - await reader.cancel().catch(() => {}); - throw new RegistryResponseError(`${context} response exceeds ${maximum} bytes`); - } - chunks.push(Buffer.from(value)); - } - } finally { - reader.releaseLock(); - } - return Buffer.concat(chunks, size); -} - -function cratesIoRequest(url) { - return url.startsWith(`${CRATES_IO_API.replace(/\/+$/u, "")}/`); -} - -async function request(url, accept, fetchImpl, consume, cratesIoReadGate = null) { - let last; - let usedAttempts = 0; - let retryDelaySpentMilliseconds = 0; - for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { - usedAttempts = attempt + 1; - const controller = new AbortController(); - let deadlineRemaining = mutationDeadlineRemainingMilliseconds(`registry request for ${url}`); - if (cratesIoReadGate !== null && cratesIoRequest(url)) { - await cratesIoReadGate.beforeRequest(url, mutationDeadlineEpochSeconds()); - deadlineRemaining = mutationDeadlineRemainingMilliseconds(`registry request for ${url}`); - } - const timeoutMs = deadlineRemaining === null - ? REQUEST_TIMEOUT_MS - : Math.max(1, Math.min(REQUEST_TIMEOUT_MS, deadlineRemaining)); - const timeout = setTimeout(() => controller.abort(new Error(`registry request timed out after ${timeoutMs}ms`)), timeoutMs); - try { - const response = await fetchImpl(url, { - headers: { accept, "user-agent": USER_AGENT }, - redirect: "follow", - signal: controller.signal, - }); - if (!response.ok) { - const retryAfter = retryAfterMilliseconds(response.headers?.get?.("retry-after")); - await response.body?.cancel?.().catch?.(() => {}); - throw new RegistryHttpError(url, response.status, retryAfter); - } - return await consume(response); - } catch (cause) { - clearTimeout(timeout); - last = cause; - if (attempt + 1 >= REQUEST_ATTEMPTS || !retryable(cause)) break; - const delay = retryDelay(attempt, cause); - const retryDelayRemainingMilliseconds = MAX_RETRY_DELAY_BUDGET_MS - retryDelaySpentMilliseconds; - if (delay > retryDelayRemainingMilliseconds) { - throw error(`registry retry for ${url} exceeds its bounded 600s retry-delay budget`); - } - const retryRemaining = mutationDeadlineRemainingMilliseconds(`registry retry for ${url}`); - if (retryRemaining !== null && delay >= retryRemaining) { - throw error(`registry retry for ${url} cannot complete before the shared registry mutation deadline`); - } - retryDelaySpentMilliseconds += delay; - if (cratesIoReadGate !== null && cratesIoRequest(url)) { - cratesIoReadGate.defer(delay / 1000); - } else { - await new Promise((resolve) => setTimeout(resolve, delay)); - } - } finally { - clearTimeout(timeout); - } - } - throw error(`${last instanceof Error ? last.message : String(last)} after ${usedAttempts} attempt(s)`); -} - -async function requestJson(url, fetchImpl, cratesIoReadGate = null) { - return request(url, "application/json", fetchImpl, async (response) => { - const bytes = await boundedResponseBytes(response, MAX_METADATA_RESPONSE_BYTES, url); - try { - return JSON.parse(bytes.toString("utf8")); - } catch (cause) { - throw new RegistryResponseError(`registry returned invalid JSON for ${url}: ${cause.message}`); - } - }, cratesIoReadGate); -} - -async function responseSha256(response, maximum, context) { - const declared = declaredResponseLength(response, context); - if (declared !== null && declared > maximum) { - await response.body?.cancel?.().catch(() => {}); - throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); - } - const hash = createHash("sha256"); - let size = 0; - if (response.body?.getReader !== undefined) { - const reader = response.body.getReader(); - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - const bytes = Buffer.from(value); - size += bytes.length; - if (size > maximum) { - await reader.cancel().catch(() => {}); - throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); - } - hash.update(bytes); - } - } finally { - reader.releaseLock(); - } - } else { - const bytes = Buffer.from(await response.arrayBuffer()); - if (bytes.length > maximum) { - throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); - } - hash.update(bytes); - size = bytes.length; - } - return { sha256: hash.digest("hex"), size }; -} - -async function requestSha256(url, fetchImpl, maximum) { - return request(url, "application/octet-stream", fetchImpl, (response) => responseSha256(response, maximum, url)); -} - -function lockedArtifactEnvelope(carrier) { - return carrier.artifacts - .map(({ sha256, size }) => ({ sha256, size })) - .sort((left, right) => compareText(left.sha256, right.sha256)); -} - -function expectedCargoReceipt(carrier) { - if (carrier.artifacts.length !== 1) { - throw error(`${carrier.id} must freeze exactly one .crate archive for byte-level registry verification`); - } - const file = requireLockedFile(carrier.artifacts[0], ".crate", carrier); - const digest = hashFile(file, "sha256"); - const url = `${CRATES_IO_API.replace(/\/+$/u, "")}/crates/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; - return { - id: carrier.id, - product: carrier.product, - ecosystem: carrier.ecosystem, - name: carrier.name, - version: carrier.version, - lockedArtifacts: lockedArtifactEnvelope(carrier), - registryProof: { - algorithm: "sha256", - digest, - source: "crates.io-version-checksum", - url, - }, - }; -} - -async function cargoReceipt(carrier, fetchImpl, cratesIoReadGate) { - const receipt = expectedCargoReceipt(carrier); - const metadata = await requestJson(receipt.registryProof.url, fetchImpl, cratesIoReadGate); - const observed = metadata?.version?.checksum; - if (observed !== receipt.registryProof.digest) { - throw error(`${carrier.id} registry checksum mismatch: locked=${receipt.registryProof.digest}, registry=${String(observed)}`); - } - return receipt; -} - -function expectedNpmReceipt(carrier) { - if (carrier.artifacts.length !== 1) { - throw error(`${carrier.id} must freeze exactly one npm .tgz archive for byte-level registry verification`); - } - const file = requireLockedFile(carrier.artifacts[0], ".tgz", carrier); - const digest = hashFile(file, "sha512", "base64"); - const url = `${canonicalNpmRegistry()}/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; - return { - id: carrier.id, - product: carrier.product, - ecosystem: carrier.ecosystem, - name: carrier.name, - version: carrier.version, - lockedArtifacts: lockedArtifactEnvelope(carrier), - registryProof: { - algorithm: "sha512", - digest, - source: "npm-dist-integrity", - url, - }, - }; -} - -async function npmReceipt(carrier, fetchImpl) { - const receipt = expectedNpmReceipt(carrier); - const expectedIntegrity = `sha512-${receipt.registryProof.digest}`; - const metadata = await requestJson(receipt.registryProof.url, fetchImpl); - const integrity = metadata?.dist?.integrity; - const tokens = typeof integrity === "string" ? integrity.trim().split(/\s+/u) : []; - if (!tokens.includes(expectedIntegrity)) { - throw error(`${carrier.id} registry integrity mismatch: locked=${expectedIntegrity}, registry=${String(integrity)}`); - } - return receipt; -} - -function mavenCoordinate(carrier) { - const separator = carrier.name.lastIndexOf(":"); - const group = separator > 0 ? carrier.name.slice(0, separator) : ""; - const artifact = separator > 0 ? carrier.name.slice(separator + 1) : ""; - if (!/^[A-Za-z0-9_.-]+$/u.test(group) || !/^[A-Za-z0-9_.-]+$/u.test(artifact)) { - throw error(`${carrier.id} has invalid Maven coordinates ${JSON.stringify(carrier.name)}`); - } - if (!/^[A-Za-z0-9_.-]+$/u.test(carrier.version)) { - throw error(`${carrier.id} has invalid Maven version ${JSON.stringify(carrier.version)}`); - } - const groupPath = group.split(".").map(encodeURIComponent).join("/"); - return { artifact, base: `${MAVEN_CENTRAL_BASE.replace(/\/+$/u, "")}/${groupPath}/${encodeURIComponent(artifact)}/${encodeURIComponent(carrier.version)}` }; -} - -function mavenRemoteFilename(carrier, artifact, artifactName) { - const localName = path.basename(artifact.path); - const prefix = `${artifactName}-${carrier.version}`; - if (localName.startsWith(prefix) && localName.length > prefix.length) return localName; - const compound = [".tar.gz", ".tar.zst"].find((suffix) => localName.endsWith(suffix)); - const suffix = compound ?? path.extname(localName); - if (!suffix) throw error(`${carrier.id} cannot determine the Maven publication extension for ${artifact.path}`); - return `${prefix}${suffix}`; -} - -function expectedMavenReceipt(carrier) { - if (carrier.artifacts.length === 0) throw error(`${carrier.id} freezes no Maven publication payloads`); - const { artifact: artifactName, base } = mavenCoordinate(carrier); - const proofs = []; - const remoteNames = new Set(); - for (const artifact of carrier.artifacts) { - const file = requireLockedFile(artifact, "", carrier); - const remoteName = mavenRemoteFilename(carrier, artifact, artifactName); - if (remoteNames.has(remoteName)) throw error(`${carrier.id} maps multiple locked payloads to Maven file ${remoteName}`); - remoteNames.add(remoteName); - const url = `${base}/${encodeURIComponent(remoteName)}`; - proofs.push({ algorithm: "sha256", digest: hashFile(file, "sha256"), size: statSync(file).size, url }); - } - return { - id: carrier.id, - product: carrier.product, - ecosystem: carrier.ecosystem, - name: carrier.name, - version: carrier.version, - lockedArtifacts: lockedArtifactEnvelope(carrier), - registryProof: { - algorithm: "sha256", - digest: digestValue(proofs), - files: proofs, - source: "maven-central-payload-bytes", - }, - }; -} - -async function mavenReceipt(carrier, fetchImpl) { - const receipt = expectedMavenReceipt(carrier); - for (const proof of receipt.registryProof.files) { - const observed = await requestSha256(proof.url, fetchImpl, proof.size); - if (observed.sha256 !== proof.digest || observed.size !== proof.size) { - throw error( - `${carrier.id} Maven payload mismatch for ${path.basename(new URL(proof.url).pathname)}: ` - + `locked=${proof.digest}/${proof.size}, registry=${observed.sha256}/${observed.size}`, - ); - } - } - return receipt; -} - -function expectedLockedCarrierReceipt(carrier, lock) { - if (carrier.ecosystem === "cargo") return expectedCargoReceipt(carrier); - if (carrier.ecosystem === "npm") return expectedNpmReceipt(carrier); - if (carrier.ecosystem === "maven") return expectedMavenReceipt(carrier); - throw error(`${carrier.id} byte-level registry verification is unsupported for ${carrier.ecosystem}`); -} - -function assertSealedReceiptCommon(receipt, carrier) { - exactKeys( - receipt, - ["id", "product", "ecosystem", "name", "version", "lockedArtifacts", "registryProof"], - `${carrier.id} sealed registry receipt`, - ); - for (const field of ["id", "product", "ecosystem", "name", "version"]) { - if (receipt[field] !== carrier[field]) { - throw error(`${carrier.id} sealed registry receipt changed ${field}`); - } - } - if (stableJson(receipt.lockedArtifacts) !== stableJson(lockedArtifactEnvelope(carrier))) { - throw error(`${carrier.id} sealed registry receipt changed its frozen artifact envelope`); - } - exactKeys(receipt.registryProof, carrier.ecosystem === "maven" - ? ["algorithm", "digest", "files", "source"] - : ["algorithm", "digest", "source", "url"], `${carrier.id} sealed registry proof`); -} - -function assertCanonicalSha512Base64(value, context) { - if (typeof value !== "string" || value.length === 0 || /[^A-Za-z0-9+/=]/u.test(value)) { - throw error(`${context} is not a canonical SHA-512 base64 digest`); - } - const decoded = Buffer.from(value, "base64"); - if (decoded.length !== 64 || decoded.toString("base64") !== value) { - throw error(`${context} is not a canonical SHA-512 base64 digest`); - } -} - -function validateSealedLockedCarrierReceipt(receipt, carrier) { - assertSealedReceiptCommon(receipt, carrier); - const proof = receipt.registryProof; - if (carrier.ecosystem === "cargo") { - if (carrier.artifacts.length !== 1 || !carrier.artifacts[0].path.endsWith(".crate")) { - throw error(`${carrier.id} must freeze exactly one .crate archive`); - } - const expectedUrl = `${CRATES_IO_API.replace(/\/+$/u, "")}/crates/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; - if ( - proof.algorithm !== "sha256" - || proof.digest !== carrier.artifacts[0].sha256 - || proof.source !== "crates.io-version-checksum" - || proof.url !== expectedUrl - ) { - throw error(`${carrier.id} sealed Cargo proof changed its exact registry identity or checksum`); - } - return receipt; - } - if (carrier.ecosystem === "npm") { - if (carrier.artifacts.length !== 1 || !carrier.artifacts[0].path.endsWith(".tgz")) { - throw error(`${carrier.id} must freeze exactly one npm .tgz archive`); - } - const expectedUrl = `${canonicalNpmRegistry()}/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; - assertCanonicalSha512Base64(proof.digest, `${carrier.id} sealed npm proof digest`); - if (proof.algorithm !== "sha512" || proof.source !== "npm-dist-integrity" || proof.url !== expectedUrl) { - throw error(`${carrier.id} sealed npm proof changed its exact registry identity`); - } - return receipt; - } - if (carrier.ecosystem === "maven") { - const { artifact: artifactName, base } = mavenCoordinate(carrier); - const expectedFiles = carrier.artifacts.map((artifact) => ({ - algorithm: "sha256", - digest: artifact.sha256, - size: artifact.size, - url: `${base}/${encodeURIComponent(mavenRemoteFilename(carrier, artifact, artifactName))}`, - })); - for (const [index, file] of (Array.isArray(proof.files) ? proof.files : []).entries()) { - exactKeys(file, ["algorithm", "digest", "size", "url"], `${carrier.id} sealed Maven proof files[${index}]`); - } - if ( - carrier.artifacts.length === 0 - || proof.algorithm !== "sha256" - || proof.source !== "maven-central-payload-bytes" - || stableJson(proof.files) !== stableJson(expectedFiles) - || proof.digest !== digestValue(expectedFiles) - ) { - throw error(`${carrier.id} sealed Maven proof changed its exact payload identities`); - } - return receipt; - } - throw error(`${carrier.id} sealed registry receipt uses an unsupported ecosystem`); -} - -function selectedLockedRegistryCarriers(lock, { - products, - ecosystems = ["cargo", "npm", "maven"], - carrierIds, -} = {}) { - if (!Array.isArray(lock?.carriers)) throw error("publication lock has no carriers list"); - const productSet = products === undefined ? null : new Set(products); - if (products !== undefined && ( - !Array.isArray(products) - || products.length === 0 - || products.some((product) => typeof product !== "string" || product.length === 0) - || productSet.size !== products.length - )) { - throw error("products must be a nonempty unique string list"); - } - const ecosystemSet = new Set(ecosystems); - if (!Array.isArray(ecosystems) || ecosystemSet.size !== ecosystems.length) { - throw error("ecosystems must be a unique list"); - } - for (const ecosystem of ecosystemSet) { - if (!SUPPORTED_ECOSYSTEMS.has(ecosystem)) throw error(`unsupported registry ecosystem ${JSON.stringify(ecosystem)}`); - } - const idSet = carrierIds === undefined ? null : new Set(carrierIds); - if (carrierIds !== undefined && ( - !Array.isArray(carrierIds) - || carrierIds.some((id) => typeof id !== "string" || id.length === 0) - || idSet.size !== carrierIds.length - )) { - throw error("carrierIds must be a unique string list"); - } - const carriers = lock.carriers.filter((carrier) => - ecosystemSet.has(carrier.ecosystem) - && (productSet === null || productSet.has(carrier.product)) - && (idSet === null || idSet.has(carrier.id))) - .sort((left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id)); - if (idSet !== null && carriers.length !== idSet.size) { - throw error("one or more requested carrier IDs are absent from the publication lock"); - } - return carriers; -} - -export function validateLockedRegistryReceipts(lock, { - products, - ecosystems = ["cargo", "npm", "maven"], - carrierIds, - receipts, - receiptMode = "local", -} = {}) { - if (!new Set(["local", "sealed"]).has(receiptMode)) { - throw error(`registry receipt mode must be local or sealed, got ${JSON.stringify(receiptMode)}`); - } - if (!Array.isArray(receipts)) throw error("registry receipts must be a list"); - const carriers = selectedLockedRegistryCarriers(lock, { products, ecosystems, carrierIds }); - const expectedById = receiptMode === "local" - ? new Map(carriers.map((carrier) => [carrier.id, expectedLockedCarrierReceipt(carrier, lock)])) - : new Map(carriers.map((carrier) => [carrier.id, carrier])); - const observedById = new Map(); - for (const receipt of receipts) { - if (receipt === null || Array.isArray(receipt) || typeof receipt !== "object" || typeof receipt.id !== "string") { - throw error("every registry receipt must be an object with an id"); - } - if (observedById.has(receipt.id)) throw error(`duplicate registry receipt ${receipt.id}`); - if (!expectedById.has(receipt.id)) throw error(`unexpected registry receipt ${receipt.id}`); - observedById.set(receipt.id, receipt); - } - const missing = carriers.filter(({ id }) => !observedById.has(id)).map(({ id }) => id); - if (missing.length > 0) { - throw error(`registry receipt evidence is incomplete; missing ${missing.slice(0, 8).join(", ")}${missing.length > 8 ? ` and ${missing.length - 8} more` : ""}`); - } - for (const [id, expected] of expectedById) { - const observed = observedById.get(id); - if (receiptMode === "sealed") { - validateSealedLockedCarrierReceipt(observed, expected); - } else if (stableJson(observed) !== stableJson(expected)) { - throw error(`${id} registry receipt does not exactly prove its frozen local bytes and canonical registry identity`); - } - } - return carriers.map(({ id }) => observedById.get(id)); -} - -export function registryReceiptEvidence(lock, { - products, - ecosystems = ["cargo", "npm", "maven"], - receipts, -} = {}) { - const validated = validateLockedRegistryReceipts(lock, { products, ecosystems, receipts }); - return { - schema: REGISTRY_RECEIPT_EVIDENCE_SCHEMA, - lockDigest: lock.lockDigest, - source: lock.source, - products: [...products].sort(compareText), - ecosystems: [...ecosystems].sort(compareText), - receipts: validated, - }; -} - -export function writeRegistryReceiptEvidence(file, lock, options) { - const evidence = registryReceiptEvidence(lock, options); - const absolute = path.resolve(ROOT, file); - mkdirSync(path.dirname(absolute), { recursive: true }); - const temporary = `${absolute}.tmp-${process.pid}-${Date.now()}`; - const body = `${JSON.stringify(evidence, null, 2)}\n`; - try { - writeFileSync(temporary, body, { flag: "wx", mode: 0o644 }); - try { - linkSync(temporary, absolute); - } catch (cause) { - if (cause?.code !== "EEXIST") throw cause; - const stat = lstatSync(absolute); - if (stat.isSymbolicLink() || !stat.isFile() || stat.size > MAX_REGISTRY_RECEIPT_EVIDENCE_BYTES) { - throw error(`refusing to replace unsafe existing registry receipt evidence ${file}`); - } - if (readFileSync(absolute, "utf8") !== body) { - throw error(`refusing to replace non-identical immutable registry receipt evidence ${file}`); - } - } - } finally { - try { unlinkSync(temporary); } catch {} - } - return evidence; -} - -export function validateRegistryReceiptEvidence(file, lock, { - products, - ecosystems, - receiptMode = "local", -} = {}) { - let evidence; - try { - const absolute = path.resolve(ROOT, file); - const stat = lstatSync(absolute); - if (stat.isSymbolicLink() || !stat.isFile() || stat.size > MAX_REGISTRY_RECEIPT_EVIDENCE_BYTES) { - throw new Error(`must be a regular file no larger than ${MAX_REGISTRY_RECEIPT_EVIDENCE_BYTES} bytes`); - } - evidence = JSON.parse(readFileSync(absolute, "utf8")); - } catch (cause) { - throw error(`cannot read registry receipt evidence ${file}: ${cause.message}`); - } - if (evidence === null || Array.isArray(evidence) || typeof evidence !== "object") { - throw error("registry receipt evidence must be an object"); - } - if (evidence.schema !== REGISTRY_RECEIPT_EVIDENCE_SCHEMA) { - throw error(`registry receipt evidence schema must be ${REGISTRY_RECEIPT_EVIDENCE_SCHEMA}`); - } - if (evidence.lockDigest !== lock.lockDigest || stableJson(evidence.source) !== stableJson(lock.source)) { - throw error("registry receipt evidence is not bound to the active publication lock source/digest"); - } - const expectedProducts = [...products].sort(compareText); - const expectedEcosystems = [...(ecosystems ?? ["cargo", "npm", "maven"])].sort(compareText); - if (stableJson(evidence.products) !== stableJson(expectedProducts) || stableJson(evidence.ecosystems) !== stableJson(expectedEcosystems)) { - throw error("registry receipt evidence product/ecosystem selection does not match the requested release"); - } - validateLockedRegistryReceipts(lock, { - products, - ecosystems: expectedEcosystems, - receipts: evidence.receipts, - receiptMode, - }); - return evidence; -} - -export async function verifyLockedCarrierIntegrity(lock, carrierId, { - fetchImpl = fetch, - cratesIoReadGate = DEFAULT_CRATES_IO_READ_GATE, -} = {}) { - const carrier = lock.carriers.find((entry) => entry.id === carrierId); - if (carrier === undefined) throw error(`publication lock has no carrier ${carrierId}`); - if (carrier.ecosystem === "cargo") return cargoReceipt(carrier, fetchImpl, cratesIoReadGate); - if (carrier.ecosystem === "npm") return npmReceipt(carrier, fetchImpl); - if (carrier.ecosystem === "maven") return mavenReceipt(carrier, fetchImpl); - throw error(`${carrier.id} byte-level registry verification is unsupported for ${carrier.ecosystem}`); -} - -export async function verifyLockedRegistryIntegrity(lock, { - products, - ecosystems = ["cargo", "npm", "maven"], - carrierIds, - fetchImpl = fetch, - concurrency = Number(process.env.REGISTRY_INTEGRITY_CONCURRENCY ?? 8), - cratesIoReadGate = DEFAULT_CRATES_IO_READ_GATE, -} = {}) { - if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) { - throw error(`concurrency must be an integer from 1 through 32, got ${JSON.stringify(concurrency)}`); - } - const carriers = selectedLockedRegistryCarriers(lock, { products, ecosystems, carrierIds }); - const receipts = new Array(carriers.length); - let next = 0; - const worker = async () => { - for (;;) { - const index = next; - next += 1; - if (index >= carriers.length) return; - receipts[index] = await verifyLockedCarrierIntegrity(lock, carriers[index].id, { - fetchImpl, - cratesIoReadGate, - }); - } - }; - await Promise.all(Array.from({ length: Math.min(concurrency, carriers.length) }, worker)); - return receipts; -} - -function parseArgs(argv) { - let lockFile = ""; - let carrierId = ""; - let productsJson = ""; - let verifyReceipts = ""; - let sealedReceipts = false; - let concurrency = 8; - const ecosystems = []; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - const value = argv[index + 1]; - if (arg === "--sealed-receipts") { - sealedReceipts = true; - continue; - } - if (arg === "--lock") lockFile = value ?? ""; - else if (arg === "--carrier-id") carrierId = value ?? ""; - else if (arg === "--products-json") productsJson = value ?? ""; - else if (arg === "--verify-receipts") verifyReceipts = value ?? ""; - else if (arg === "--ecosystem") ecosystems.push(value ?? ""); - else if (arg === "--concurrency") concurrency = Number(value); - else throw error(`unknown argument ${arg}`); - index += 1; - } - if ( - !lockFile - || Boolean(carrierId) === Boolean(productsJson) - || (verifyReceipts && !productsJson) - || (sealedReceipts && !verifyReceipts) - ) { - throw error("usage: registry-integrity.mjs --lock FILE (--carrier-id ID | --products-json JSON) [--ecosystem cargo|npm|maven|jsr] [--concurrency 1..32] [--verify-receipts FILE --sealed-receipts]"); - } - let products; - if (productsJson) { - try { products = JSON.parse(productsJson); } catch (cause) { throw error(`invalid --products-json: ${cause.message}`); } - if (!Array.isArray(products) || products.length === 0 || products.some((item) => typeof item !== "string" || item.length === 0) || new Set(products).size !== products.length) { - throw error("--products-json must be a nonempty unique string list"); - } - } - for (const ecosystem of ecosystems) { - if (!SUPPORTED_ECOSYSTEMS.has(ecosystem)) throw error(`unsupported --ecosystem ${JSON.stringify(ecosystem)}`); - } - if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) throw error("--concurrency must be an integer from 1 through 32"); - return { - lockFile: path.resolve(ROOT, lockFile), - carrierId, - products, - ecosystems, - concurrency, - sealedReceipts, - verifyReceipts: verifyReceipts ? path.resolve(ROOT, verifyReceipts) : "", - }; -} - -if (import.meta.main) { - try { - const args = parseArgs(Bun.argv.slice(2)); - const lock = loadPublicationLock(args.lockFile); - if (args.verifyReceipts) { - const evidence = validateRegistryReceiptEvidence(args.verifyReceipts, lock, { - products: args.products, - ecosystems: args.ecosystems.length > 0 ? args.ecosystems : ["cargo", "npm", "maven"], - receiptMode: args.sealedReceipts ? "sealed" : "local", - }); - console.log(`Verified ${evidence.receipts.length} immutable registry receipts against the frozen publication lock.`); - process.exit(0); - } - const receipts = await verifyLockedRegistryIntegrity(lock, { - products: args.products, - ecosystems: args.ecosystems.length > 0 ? args.ecosystems : ["cargo", "npm", "maven"], - carrierIds: args.carrierId ? [args.carrierId] : undefined, - concurrency: args.concurrency, - }); - console.log(JSON.stringify({ schema: REGISTRY_RECEIPT_EVIDENCE_SCHEMA, receipts }, null, 2)); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/registry-integrity.mts b/tools/release/registry-integrity.mts new file mode 100644 index 000000000..b4b1debd8 --- /dev/null +++ b/tools/release/registry-integrity.mts @@ -0,0 +1,970 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { + lstatSync, + linkSync, + mkdirSync, + readFileSync, + statSync, + unlinkSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; + +import { createCratesIoReadGate } from './registry-http-retry.mts'; +import { loadPublicationLock } from './publication-lock.mts'; +import { ROOT, compareText } from './release-graph.mts'; +const CRATES_IO_API = process.env.CRATES_IO_API || 'https://crates.io/api/v1'; +const DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org'; +const MAVEN_CENTRAL_BASE = process.env.MAVEN_CENTRAL_BASE || 'https://repo1.maven.org/maven2'; +const USER_AGENT = 'oliphaunt-release-integrity (https://github.com/f0rr0/oliphaunt)'; +const SUPPORTED_ECOSYSTEMS = new Set(['cargo', 'npm', 'maven']); +const RETRYABLE_HTTP_STATUS = new Set([408, 425, 429, 500, 502, 503, 504]); +const REQUEST_ATTEMPTS = 8; +const REQUEST_TIMEOUT_MS = 45_000; +const DEADLINE_RESERVE_MS = 5_000; +const MAX_TRANSIENT_RETRY_DELAY_MS = 30_000; +const MAX_RATE_LIMIT_RETRY_DELAY_MS = 5 * 60_000; +const MAX_RETRY_DELAY_BUDGET_MS = 10 * 60_000; +const MAX_METADATA_RESPONSE_BYTES = 8 * 1024 * 1024; +const MAX_REGISTRY_RECEIPT_EVIDENCE_BYTES = 64 * 1024 * 1024; +export const REGISTRY_RECEIPT_EVIDENCE_SCHEMA = 'oliphaunt-registry-integrity-receipts-v1'; +const DEFAULT_CRATES_IO_READ_GATE = createCratesIoReadGate(); + +class RegistryHttpError extends Error { + constructor(url, status, retryAfter) { + super(`registry returned HTTP ${status} for ${url}`); + this.status = status; + this.retryAfter = retryAfter; + } +} + +class RegistryResponseError extends Error {} + +function mutationDeadlineEpochSeconds() { + const raw = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH?.trim(); + if (!raw) return null; + if (!/^[1-9][0-9]*$/u.test(raw)) { + throw new RegistryResponseError( + 'REGISTRY_MUTATION_DEADLINE_EPOCH must be a positive Unix timestamp', + ); + } + const deadline = Number(raw); + if (!Number.isSafeInteger(deadline) || !Number.isSafeInteger(deadline * 1000)) { + throw new RegistryResponseError( + 'REGISTRY_MUTATION_DEADLINE_EPOCH exceeds the safe timestamp range', + ); + } + return deadline; +} + +function mutationDeadlineRemainingMilliseconds(context) { + const deadlineEpochSeconds = mutationDeadlineEpochSeconds(); + if (deadlineEpochSeconds === null) return null; + const deadline = deadlineEpochSeconds * 1000; + const remaining = deadline - Date.now() - DEADLINE_RESERVE_MS; + if (remaining <= 0) { + throw new RegistryResponseError( + `${context} refused because the shared registry mutation deadline has been reached`, + ); + } + return remaining; +} + +function error(message) { + return new Error(`registry-integrity: ${message}`); +} + +function canonicalNpmRegistry() { + const raw = (process.env.NPM_REGISTRY ?? DEFAULT_NPM_REGISTRY).trim(); + let parsed; + try { + parsed = new URL(raw); + } catch { + throw error(`npm registry must be the canonical public registry ${DEFAULT_NPM_REGISTRY}`); + } + const normalizedPath = parsed.pathname.replace(/\/+$/u, '') || '/'; + if ( + parsed.protocol !== 'https:' || + parsed.hostname !== 'registry.npmjs.org' || + (parsed.port !== '' && parsed.port !== '443') || + normalizedPath !== '/' || + parsed.username !== '' || + parsed.password !== '' || + parsed.search !== '' || + parsed.hash !== '' + ) { + throw error(`npm registry must be the canonical public registry ${DEFAULT_NPM_REGISTRY}`); + } + return DEFAULT_NPM_REGISTRY; +} + +function hashFile(file, algorithm, encoding = 'hex') { + return createHash(algorithm).update(readFileSync(file)).digest(encoding); +} + +function stableJson(value) { + if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`; + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort(compareText) + .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +function exactKeys(value, keys, context) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw error(`${context} must be an object`); + } + const observed = Object.keys(value).sort(compareText); + const expected = [...keys].sort(compareText); + if (stableJson(observed) !== stableJson(expected)) { + throw error(`${context} keys must be exactly ${expected.join(', ')}`); + } +} + +function digestValue(value) { + return createHash('sha256').update(stableJson(value)).digest('hex'); +} + +function requireLockedFile(artifact, suffix, carrier) { + if (!artifact.path.endsWith(suffix)) { + throw error( + `${carrier.id} locked artifact ${artifact.path} is not a ${suffix} publication archive`, + ); + } + const file = path.resolve(ROOT, artifact.path); + let stat; + try { + stat = statSync(file); + } catch { + throw error(`${carrier.id} locked artifact is unavailable: ${artifact.path}`); + } + if ( + !stat.isFile() || + stat.size !== artifact.size || + hashFile(file, 'sha256') !== artifact.sha256 + ) { + throw error( + `${carrier.id} local publication archive no longer matches the frozen lock: ${artifact.path}`, + ); + } + return file; +} + +function retryAfterMilliseconds(value) { + if (typeof value !== 'string' || value.trim().length === 0) return null; + const seconds = Number(value); + if (Number.isFinite(seconds) && seconds >= 0) return Math.ceil(seconds * 1000); + const timestamp = Date.parse(value); + if (Number.isNaN(timestamp)) return null; + return Math.max(0, timestamp - Date.now()); +} + +function retryDelay(attempt, cause) { + if (cause instanceof RegistryHttpError && cause.retryAfter !== null) return cause.retryAfter; + if (cause instanceof RegistryHttpError && cause.status === 429) { + return Math.min(60_000 * 2 ** attempt, MAX_RATE_LIMIT_RETRY_DELAY_MS); + } + const exponential = Math.min(500 * 2 ** attempt, MAX_TRANSIENT_RETRY_DELAY_MS); + return Math.round(exponential * (0.75 + Math.random() * 0.5)); +} + +function retryable(cause) { + if (cause instanceof RegistryResponseError) return false; + return !(cause instanceof RegistryHttpError) || RETRYABLE_HTTP_STATUS.has(cause.status); +} + +function declaredResponseLength(response, context) { + const contentLength = response.headers?.get?.('content-length'); + if (contentLength === null || contentLength === undefined) return null; + const declared = Number(contentLength); + if (!Number.isSafeInteger(declared) || declared < 0) { + throw new RegistryResponseError(`${context} returned an invalid Content-Length`); + } + return declared; +} + +async function boundedResponseBytes(response, maximum, context) { + const declared = declaredResponseLength(response, context); + if (declared !== null && declared > maximum) { + await response.body?.cancel?.().catch(() => {}); + throw new RegistryResponseError(`${context} response exceeds ${maximum} bytes`); + } + const reader = response.body?.getReader?.(); + if (reader === undefined) { + const bytes = Buffer.from(await response.arrayBuffer()); + if (bytes.length > maximum) { + throw new RegistryResponseError(`${context} response exceeds ${maximum} bytes`); + } + return bytes; + } + const chunks = []; + let size = 0; + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > maximum) { + await reader.cancel().catch(() => {}); + throw new RegistryResponseError(`${context} response exceeds ${maximum} bytes`); + } + chunks.push(Buffer.from(value)); + } + } finally { + reader.releaseLock(); + } + return Buffer.concat(chunks, size); +} + +function cratesIoRequest(url) { + return url.startsWith(`${CRATES_IO_API.replace(/\/+$/u, '')}/`); +} + +async function request(url, accept, fetchImpl, consume, cratesIoReadGate = null) { + let last; + let usedAttempts = 0; + let retryDelaySpentMilliseconds = 0; + for (let attempt = 0; attempt < REQUEST_ATTEMPTS; attempt += 1) { + usedAttempts = attempt + 1; + const controller = new AbortController(); + let deadlineRemaining = mutationDeadlineRemainingMilliseconds(`registry request for ${url}`); + if (cratesIoReadGate !== null && cratesIoRequest(url)) { + await cratesIoReadGate.beforeRequest(url, mutationDeadlineEpochSeconds()); + deadlineRemaining = mutationDeadlineRemainingMilliseconds(`registry request for ${url}`); + } + const timeoutMs = + deadlineRemaining === null + ? REQUEST_TIMEOUT_MS + : Math.max(1, Math.min(REQUEST_TIMEOUT_MS, deadlineRemaining)); + const timeout = setTimeout( + () => controller.abort(new Error(`registry request timed out after ${timeoutMs}ms`)), + timeoutMs, + ); + try { + const response = await fetchImpl(url, { + headers: { accept, 'user-agent': USER_AGENT }, + redirect: 'follow', + signal: controller.signal, + }); + if (!response.ok) { + const retryAfter = retryAfterMilliseconds(response.headers?.get?.('retry-after')); + await response.body?.cancel?.().catch?.(() => {}); + throw new RegistryHttpError(url, response.status, retryAfter); + } + return await consume(response); + } catch (cause) { + clearTimeout(timeout); + last = cause; + if (attempt + 1 >= REQUEST_ATTEMPTS || !retryable(cause)) break; + const delay = retryDelay(attempt, cause); + const retryDelayRemainingMilliseconds = + MAX_RETRY_DELAY_BUDGET_MS - retryDelaySpentMilliseconds; + if (delay > retryDelayRemainingMilliseconds) { + throw error(`registry retry for ${url} exceeds its bounded 600s retry-delay budget`); + } + const retryRemaining = mutationDeadlineRemainingMilliseconds(`registry retry for ${url}`); + if (retryRemaining !== null && delay >= retryRemaining) { + throw error( + `registry retry for ${url} cannot complete before the shared registry mutation deadline`, + ); + } + retryDelaySpentMilliseconds += delay; + if (cratesIoReadGate !== null && cratesIoRequest(url)) { + cratesIoReadGate.defer(delay / 1000); + } else { + await new Promise((resolve) => setTimeout(resolve, delay)); + } + } finally { + clearTimeout(timeout); + } + } + throw error( + `${last instanceof Error ? last.message : String(last)} after ${usedAttempts} attempt(s)`, + ); +} + +async function requestJson(url, fetchImpl, cratesIoReadGate = null) { + return request( + url, + 'application/json', + fetchImpl, + async (response) => { + const bytes = await boundedResponseBytes(response, MAX_METADATA_RESPONSE_BYTES, url); + try { + return JSON.parse(bytes.toString('utf8')); + } catch (cause) { + throw new RegistryResponseError( + `registry returned invalid JSON for ${url}: ${cause.message}`, + ); + } + }, + cratesIoReadGate, + ); +} + +async function responseSha256(response, maximum, context) { + const declared = declaredResponseLength(response, context); + if (declared !== null && declared > maximum) { + await response.body?.cancel?.().catch(() => {}); + throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); + } + const hash = createHash('sha256'); + let size = 0; + if (response.body?.getReader !== undefined) { + const reader = response.body.getReader(); + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + const bytes = Buffer.from(value); + size += bytes.length; + if (size > maximum) { + await reader.cancel().catch(() => {}); + throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); + } + hash.update(bytes); + } + } finally { + reader.releaseLock(); + } + } else { + const bytes = Buffer.from(await response.arrayBuffer()); + if (bytes.length > maximum) { + throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); + } + hash.update(bytes); + size = bytes.length; + } + return { sha256: hash.digest('hex'), size }; +} + +async function requestSha256(url, fetchImpl, maximum) { + return request(url, 'application/octet-stream', fetchImpl, (response) => + responseSha256(response, maximum, url), + ); +} + +function lockedArtifactEnvelope(carrier) { + return carrier.artifacts + .map(({ sha256, size }) => ({ sha256, size })) + .sort((left, right) => compareText(left.sha256, right.sha256)); +} + +function expectedCargoReceipt(carrier) { + if (carrier.artifacts.length !== 1) { + throw error( + `${carrier.id} must freeze exactly one .crate archive for byte-level registry verification`, + ); + } + const file = requireLockedFile(carrier.artifacts[0], '.crate', carrier); + const digest = hashFile(file, 'sha256'); + const url = `${CRATES_IO_API.replace(/\/+$/u, '')}/crates/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; + return { + id: carrier.id, + product: carrier.product, + ecosystem: carrier.ecosystem, + name: carrier.name, + version: carrier.version, + lockedArtifacts: lockedArtifactEnvelope(carrier), + registryProof: { + algorithm: 'sha256', + digest, + source: 'crates.io-version-checksum', + url, + }, + }; +} + +async function cargoReceipt(carrier, fetchImpl, cratesIoReadGate) { + const receipt = expectedCargoReceipt(carrier); + const metadata = await requestJson(receipt.registryProof.url, fetchImpl, cratesIoReadGate); + const observed = metadata?.version?.checksum; + if (observed !== receipt.registryProof.digest) { + throw error( + `${carrier.id} registry checksum mismatch: locked=${receipt.registryProof.digest}, registry=${String(observed)}`, + ); + } + return receipt; +} + +function expectedNpmReceipt(carrier) { + if (carrier.artifacts.length !== 1) { + throw error( + `${carrier.id} must freeze exactly one npm .tgz archive for byte-level registry verification`, + ); + } + const file = requireLockedFile(carrier.artifacts[0], '.tgz', carrier); + const digest = hashFile(file, 'sha512', 'base64'); + const url = `${canonicalNpmRegistry()}/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; + return { + id: carrier.id, + product: carrier.product, + ecosystem: carrier.ecosystem, + name: carrier.name, + version: carrier.version, + lockedArtifacts: lockedArtifactEnvelope(carrier), + registryProof: { + algorithm: 'sha512', + digest, + source: 'npm-dist-integrity', + url, + }, + }; +} + +async function npmReceipt(carrier, fetchImpl) { + const receipt = expectedNpmReceipt(carrier); + const expectedIntegrity = `sha512-${receipt.registryProof.digest}`; + const metadata = await requestJson(receipt.registryProof.url, fetchImpl); + const integrity = metadata?.dist?.integrity; + const tokens = typeof integrity === 'string' ? integrity.trim().split(/\s+/u) : []; + if (!tokens.includes(expectedIntegrity)) { + throw error( + `${carrier.id} registry integrity mismatch: locked=${expectedIntegrity}, registry=${String(integrity)}`, + ); + } + return receipt; +} + +function mavenCoordinate(carrier) { + const separator = carrier.name.lastIndexOf(':'); + const group = separator > 0 ? carrier.name.slice(0, separator) : ''; + const artifact = separator > 0 ? carrier.name.slice(separator + 1) : ''; + if (!/^[A-Za-z0-9_.-]+$/u.test(group) || !/^[A-Za-z0-9_.-]+$/u.test(artifact)) { + throw error(`${carrier.id} has invalid Maven coordinates ${JSON.stringify(carrier.name)}`); + } + if (!/^[A-Za-z0-9_.-]+$/u.test(carrier.version)) { + throw error(`${carrier.id} has invalid Maven version ${JSON.stringify(carrier.version)}`); + } + const groupPath = group.split('.').map(encodeURIComponent).join('/'); + return { + artifact, + base: `${MAVEN_CENTRAL_BASE.replace(/\/+$/u, '')}/${groupPath}/${encodeURIComponent(artifact)}/${encodeURIComponent(carrier.version)}`, + }; +} + +function mavenRemoteFilename(carrier, artifact, artifactName) { + const localName = path.basename(artifact.path); + const prefix = `${artifactName}-${carrier.version}`; + if (localName.startsWith(prefix) && localName.length > prefix.length) return localName; + const compound = ['.tar.gz', '.tar.zst'].find((suffix) => localName.endsWith(suffix)); + const suffix = compound ?? path.extname(localName); + if (!suffix) + throw error( + `${carrier.id} cannot determine the Maven publication extension for ${artifact.path}`, + ); + return `${prefix}${suffix}`; +} + +function expectedMavenReceipt(carrier) { + if (carrier.artifacts.length === 0) + throw error(`${carrier.id} freezes no Maven publication payloads`); + const { artifact: artifactName, base } = mavenCoordinate(carrier); + const proofs = []; + const remoteNames = new Set(); + for (const artifact of carrier.artifacts) { + const file = requireLockedFile(artifact, '', carrier); + const remoteName = mavenRemoteFilename(carrier, artifact, artifactName); + if (remoteNames.has(remoteName)) + throw error(`${carrier.id} maps multiple locked payloads to Maven file ${remoteName}`); + remoteNames.add(remoteName); + const url = `${base}/${encodeURIComponent(remoteName)}`; + proofs.push({ + algorithm: 'sha256', + digest: hashFile(file, 'sha256'), + size: statSync(file).size, + url, + }); + } + return { + id: carrier.id, + product: carrier.product, + ecosystem: carrier.ecosystem, + name: carrier.name, + version: carrier.version, + lockedArtifacts: lockedArtifactEnvelope(carrier), + registryProof: { + algorithm: 'sha256', + digest: digestValue(proofs), + files: proofs, + source: 'maven-central-payload-bytes', + }, + }; +} + +async function mavenReceipt(carrier, fetchImpl) { + const receipt = expectedMavenReceipt(carrier); + for (const proof of receipt.registryProof.files) { + const observed = await requestSha256(proof.url, fetchImpl, proof.size); + if (observed.sha256 !== proof.digest || observed.size !== proof.size) { + throw error( + `${carrier.id} Maven payload mismatch for ${path.basename(new URL(proof.url).pathname)}: ` + + `locked=${proof.digest}/${proof.size}, registry=${observed.sha256}/${observed.size}`, + ); + } + } + return receipt; +} + +function expectedLockedCarrierReceipt(carrier, lock) { + if (carrier.ecosystem === 'cargo') return expectedCargoReceipt(carrier); + if (carrier.ecosystem === 'npm') return expectedNpmReceipt(carrier); + if (carrier.ecosystem === 'maven') return expectedMavenReceipt(carrier); + throw error( + `${carrier.id} byte-level registry verification is unsupported for ${carrier.ecosystem}`, + ); +} + +function assertSealedReceiptCommon(receipt, carrier) { + exactKeys( + receipt, + ['id', 'product', 'ecosystem', 'name', 'version', 'lockedArtifacts', 'registryProof'], + `${carrier.id} sealed registry receipt`, + ); + for (const field of ['id', 'product', 'ecosystem', 'name', 'version']) { + if (receipt[field] !== carrier[field]) { + throw error(`${carrier.id} sealed registry receipt changed ${field}`); + } + } + if (stableJson(receipt.lockedArtifacts) !== stableJson(lockedArtifactEnvelope(carrier))) { + throw error(`${carrier.id} sealed registry receipt changed its frozen artifact envelope`); + } + exactKeys( + receipt.registryProof, + carrier.ecosystem === 'maven' + ? ['algorithm', 'digest', 'files', 'source'] + : ['algorithm', 'digest', 'source', 'url'], + `${carrier.id} sealed registry proof`, + ); +} + +function assertCanonicalSha512Base64(value, context) { + if (typeof value !== 'string' || value.length === 0 || /[^A-Za-z0-9+/=]/u.test(value)) { + throw error(`${context} is not a canonical SHA-512 base64 digest`); + } + const decoded = Buffer.from(value, 'base64'); + if (decoded.length !== 64 || decoded.toString('base64') !== value) { + throw error(`${context} is not a canonical SHA-512 base64 digest`); + } +} + +function validateSealedLockedCarrierReceipt(receipt, carrier) { + assertSealedReceiptCommon(receipt, carrier); + const proof = receipt.registryProof; + if (carrier.ecosystem === 'cargo') { + if (carrier.artifacts.length !== 1 || !carrier.artifacts[0].path.endsWith('.crate')) { + throw error(`${carrier.id} must freeze exactly one .crate archive`); + } + const expectedUrl = `${CRATES_IO_API.replace(/\/+$/u, '')}/crates/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; + if ( + proof.algorithm !== 'sha256' || + proof.digest !== carrier.artifacts[0].sha256 || + proof.source !== 'crates.io-version-checksum' || + proof.url !== expectedUrl + ) { + throw error( + `${carrier.id} sealed Cargo proof changed its exact registry identity or checksum`, + ); + } + return receipt; + } + if (carrier.ecosystem === 'npm') { + if (carrier.artifacts.length !== 1 || !carrier.artifacts[0].path.endsWith('.tgz')) { + throw error(`${carrier.id} must freeze exactly one npm .tgz archive`); + } + const expectedUrl = `${canonicalNpmRegistry()}/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; + assertCanonicalSha512Base64(proof.digest, `${carrier.id} sealed npm proof digest`); + if ( + proof.algorithm !== 'sha512' || + proof.source !== 'npm-dist-integrity' || + proof.url !== expectedUrl + ) { + throw error(`${carrier.id} sealed npm proof changed its exact registry identity`); + } + return receipt; + } + if (carrier.ecosystem === 'maven') { + const { artifact: artifactName, base } = mavenCoordinate(carrier); + const expectedFiles = carrier.artifacts.map((artifact) => ({ + algorithm: 'sha256', + digest: artifact.sha256, + size: artifact.size, + url: `${base}/${encodeURIComponent(mavenRemoteFilename(carrier, artifact, artifactName))}`, + })); + for (const [index, file] of (Array.isArray(proof.files) ? proof.files : []).entries()) { + exactKeys( + file, + ['algorithm', 'digest', 'size', 'url'], + `${carrier.id} sealed Maven proof files[${index}]`, + ); + } + if ( + carrier.artifacts.length === 0 || + proof.algorithm !== 'sha256' || + proof.source !== 'maven-central-payload-bytes' || + stableJson(proof.files) !== stableJson(expectedFiles) || + proof.digest !== digestValue(expectedFiles) + ) { + throw error(`${carrier.id} sealed Maven proof changed its exact payload identities`); + } + return receipt; + } + throw error(`${carrier.id} sealed registry receipt uses an unsupported ecosystem`); +} + +function selectedLockedRegistryCarriers( + lock, + { products, ecosystems = ['cargo', 'npm', 'maven'], carrierIds } = {}, +) { + if (!Array.isArray(lock?.carriers)) throw error('publication lock has no carriers list'); + const productSet = products === undefined ? null : new Set(products); + if ( + products !== undefined && + (!Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string' || product.length === 0) || + productSet.size !== products.length) + ) { + throw error('products must be a nonempty unique string list'); + } + const ecosystemSet = new Set(ecosystems); + if (!Array.isArray(ecosystems) || ecosystemSet.size !== ecosystems.length) { + throw error('ecosystems must be a unique list'); + } + for (const ecosystem of ecosystemSet) { + if (!SUPPORTED_ECOSYSTEMS.has(ecosystem)) + throw error(`unsupported registry ecosystem ${JSON.stringify(ecosystem)}`); + } + const idSet = carrierIds === undefined ? null : new Set(carrierIds); + if ( + carrierIds !== undefined && + (!Array.isArray(carrierIds) || + carrierIds.some((id) => typeof id !== 'string' || id.length === 0) || + idSet.size !== carrierIds.length) + ) { + throw error('carrierIds must be a unique string list'); + } + const carriers = lock.carriers + .filter( + (carrier) => + ecosystemSet.has(carrier.ecosystem) && + (productSet === null || productSet.has(carrier.product)) && + (idSet === null || idSet.has(carrier.id)), + ) + .sort( + (left, right) => left.publishOrder - right.publishOrder || compareText(left.id, right.id), + ); + if (idSet !== null && carriers.length !== idSet.size) { + throw error('one or more requested carrier IDs are absent from the publication lock'); + } + return carriers; +} + +export function validateLockedRegistryReceipts( + lock, + { + products, + ecosystems = ['cargo', 'npm', 'maven'], + carrierIds, + receipts, + receiptMode = 'local', + } = {}, +) { + if (!new Set(['local', 'sealed']).has(receiptMode)) { + throw error( + `registry receipt mode must be local or sealed, got ${JSON.stringify(receiptMode)}`, + ); + } + if (!Array.isArray(receipts)) throw error('registry receipts must be a list'); + const carriers = selectedLockedRegistryCarriers(lock, { products, ecosystems, carrierIds }); + const expectedById = + receiptMode === 'local' + ? new Map( + carriers.map((carrier) => [carrier.id, expectedLockedCarrierReceipt(carrier, lock)]), + ) + : new Map(carriers.map((carrier) => [carrier.id, carrier])); + const observedById = new Map(); + for (const receipt of receipts) { + if ( + receipt === null || + Array.isArray(receipt) || + typeof receipt !== 'object' || + typeof receipt.id !== 'string' + ) { + throw error('every registry receipt must be an object with an id'); + } + if (observedById.has(receipt.id)) throw error(`duplicate registry receipt ${receipt.id}`); + if (!expectedById.has(receipt.id)) throw error(`unexpected registry receipt ${receipt.id}`); + observedById.set(receipt.id, receipt); + } + const missing = carriers.filter(({ id }) => !observedById.has(id)).map(({ id }) => id); + if (missing.length > 0) { + throw error( + `registry receipt evidence is incomplete; missing ${missing.slice(0, 8).join(', ')}${missing.length > 8 ? ` and ${missing.length - 8} more` : ''}`, + ); + } + for (const [id, expected] of expectedById) { + const observed = observedById.get(id); + if (receiptMode === 'sealed') { + validateSealedLockedCarrierReceipt(observed, expected); + } else if (stableJson(observed) !== stableJson(expected)) { + throw error( + `${id} registry receipt does not exactly prove its frozen local bytes and canonical registry identity`, + ); + } + } + return carriers.map(({ id }) => observedById.get(id)); +} + +export function registryReceiptEvidence( + lock, + { products, ecosystems = ['cargo', 'npm', 'maven'], receipts } = {}, +) { + const validated = validateLockedRegistryReceipts(lock, { products, ecosystems, receipts }); + return { + schema: REGISTRY_RECEIPT_EVIDENCE_SCHEMA, + lockDigest: lock.lockDigest, + source: lock.source, + products: [...products].sort(compareText), + ecosystems: [...ecosystems].sort(compareText), + receipts: validated, + }; +} + +export function writeRegistryReceiptEvidence(file, lock, options) { + const evidence = registryReceiptEvidence(lock, options); + const absolute = path.resolve(ROOT, file); + mkdirSync(path.dirname(absolute), { recursive: true }); + const temporary = `${absolute}.tmp-${process.pid}-${Date.now()}`; + const body = `${JSON.stringify(evidence, null, 2)}\n`; + try { + writeFileSync(temporary, body, { flag: 'wx', mode: 0o644 }); + try { + linkSync(temporary, absolute); + } catch (cause) { + if (cause?.code !== 'EEXIST') throw cause; + const stat = lstatSync(absolute); + if ( + stat.isSymbolicLink() || + !stat.isFile() || + stat.size > MAX_REGISTRY_RECEIPT_EVIDENCE_BYTES + ) { + throw error(`refusing to replace unsafe existing registry receipt evidence ${file}`); + } + if (readFileSync(absolute, 'utf8') !== body) { + throw error( + `refusing to replace non-identical immutable registry receipt evidence ${file}`, + ); + } + } + } finally { + try { + unlinkSync(temporary); + } catch {} + } + return evidence; +} + +export function validateRegistryReceiptEvidence( + file, + lock, + { products, ecosystems, receiptMode = 'local' } = {}, +) { + let evidence; + try { + const absolute = path.resolve(ROOT, file); + const stat = lstatSync(absolute); + if ( + stat.isSymbolicLink() || + !stat.isFile() || + stat.size > MAX_REGISTRY_RECEIPT_EVIDENCE_BYTES + ) { + throw new Error( + `must be a regular file no larger than ${MAX_REGISTRY_RECEIPT_EVIDENCE_BYTES} bytes`, + ); + } + evidence = JSON.parse(readFileSync(absolute, 'utf8')); + } catch (cause) { + throw error(`cannot read registry receipt evidence ${file}: ${cause.message}`); + } + if (evidence === null || Array.isArray(evidence) || typeof evidence !== 'object') { + throw error('registry receipt evidence must be an object'); + } + if (evidence.schema !== REGISTRY_RECEIPT_EVIDENCE_SCHEMA) { + throw error(`registry receipt evidence schema must be ${REGISTRY_RECEIPT_EVIDENCE_SCHEMA}`); + } + if ( + evidence.lockDigest !== lock.lockDigest || + stableJson(evidence.source) !== stableJson(lock.source) + ) { + throw error( + 'registry receipt evidence is not bound to the active publication lock source/digest', + ); + } + const expectedProducts = [...products].sort(compareText); + const expectedEcosystems = [...(ecosystems ?? ['cargo', 'npm', 'maven'])].sort(compareText); + if ( + stableJson(evidence.products) !== stableJson(expectedProducts) || + stableJson(evidence.ecosystems) !== stableJson(expectedEcosystems) + ) { + throw error( + 'registry receipt evidence product/ecosystem selection does not match the requested release', + ); + } + validateLockedRegistryReceipts(lock, { + products, + ecosystems: expectedEcosystems, + receipts: evidence.receipts, + receiptMode, + }); + return evidence; +} + +export async function verifyLockedCarrierIntegrity( + lock, + carrierId, + { fetchImpl = fetch, cratesIoReadGate = DEFAULT_CRATES_IO_READ_GATE } = {}, +) { + const carrier = lock.carriers.find((entry) => entry.id === carrierId); + if (carrier === undefined) throw error(`publication lock has no carrier ${carrierId}`); + if (carrier.ecosystem === 'cargo') return cargoReceipt(carrier, fetchImpl, cratesIoReadGate); + if (carrier.ecosystem === 'npm') return npmReceipt(carrier, fetchImpl); + if (carrier.ecosystem === 'maven') return mavenReceipt(carrier, fetchImpl); + throw error( + `${carrier.id} byte-level registry verification is unsupported for ${carrier.ecosystem}`, + ); +} + +export async function verifyLockedRegistryIntegrity( + lock, + { + products, + ecosystems = ['cargo', 'npm', 'maven'], + carrierIds, + fetchImpl = fetch, + concurrency = Number(process.env.REGISTRY_INTEGRITY_CONCURRENCY ?? 8), + cratesIoReadGate = DEFAULT_CRATES_IO_READ_GATE, + } = {}, +) { + if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) { + throw error( + `concurrency must be an integer from 1 through 32, got ${JSON.stringify(concurrency)}`, + ); + } + const carriers = selectedLockedRegistryCarriers(lock, { products, ecosystems, carrierIds }); + const receipts = new Array(carriers.length); + let next = 0; + const worker = async () => { + for (;;) { + const index = next; + next += 1; + if (index >= carriers.length) return; + receipts[index] = await verifyLockedCarrierIntegrity(lock, carriers[index].id, { + fetchImpl, + cratesIoReadGate, + }); + } + }; + await Promise.all(Array.from({ length: Math.min(concurrency, carriers.length) }, worker)); + return receipts; +} + +function parseArgs(argv) { + let lockFile = ''; + let carrierId = ''; + let productsJson = ''; + let verifyReceipts = ''; + let sealedReceipts = false; + let concurrency = 8; + const ecosystems = []; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + const value = argv[index + 1]; + if (arg === '--sealed-receipts') { + sealedReceipts = true; + continue; + } + if (arg === '--lock') lockFile = value ?? ''; + else if (arg === '--carrier-id') carrierId = value ?? ''; + else if (arg === '--products-json') productsJson = value ?? ''; + else if (arg === '--verify-receipts') verifyReceipts = value ?? ''; + else if (arg === '--ecosystem') ecosystems.push(value ?? ''); + else if (arg === '--concurrency') concurrency = Number(value); + else throw error(`unknown argument ${arg}`); + index += 1; + } + if ( + !lockFile || + Boolean(carrierId) === Boolean(productsJson) || + (verifyReceipts && !productsJson) || + (sealedReceipts && !verifyReceipts) + ) { + throw error( + 'usage: registry-integrity.mts --lock FILE (--carrier-id ID | --products-json JSON) [--ecosystem cargo|npm|maven|jsr] [--concurrency 1..32] [--verify-receipts FILE --sealed-receipts]', + ); + } + let products; + if (productsJson) { + try { + products = JSON.parse(productsJson); + } catch (cause) { + throw error(`invalid --products-json: ${cause.message}`); + } + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((item) => typeof item !== 'string' || item.length === 0) || + new Set(products).size !== products.length + ) { + throw error('--products-json must be a nonempty unique string list'); + } + } + for (const ecosystem of ecosystems) { + if (!SUPPORTED_ECOSYSTEMS.has(ecosystem)) + throw error(`unsupported --ecosystem ${JSON.stringify(ecosystem)}`); + } + if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) + throw error('--concurrency must be an integer from 1 through 32'); + return { + lockFile: path.resolve(ROOT, lockFile), + carrierId, + products, + ecosystems, + concurrency, + sealedReceipts, + verifyReceipts: verifyReceipts ? path.resolve(ROOT, verifyReceipts) : '', + }; +} + +if (import.meta.main) { + try { + const args = parseArgs(Bun.argv.slice(2)); + const lock = loadPublicationLock(args.lockFile); + if (args.verifyReceipts) { + const evidence = validateRegistryReceiptEvidence(args.verifyReceipts, lock, { + products: args.products, + ecosystems: args.ecosystems.length > 0 ? args.ecosystems : ['cargo', 'npm', 'maven'], + receiptMode: args.sealedReceipts ? 'sealed' : 'local', + }); + console.log( + `Verified ${evidence.receipts.length} immutable registry receipts against the frozen publication lock.`, + ); + process.exit(0); + } + const receipts = await verifyLockedRegistryIntegrity(lock, { + products: args.products, + ecosystems: args.ecosystems.length > 0 ? args.ecosystems : ['cargo', 'npm', 'maven'], + carrierIds: args.carrierId ? [args.carrierId] : undefined, + concurrency: args.concurrency, + }); + console.log(JSON.stringify({ schema: REGISTRY_RECEIPT_EVIDENCE_SCHEMA, receipts }, null, 2)); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/registry-integrity.test.mjs b/tools/release/registry-integrity.test.mjs deleted file mode 100644 index e5192a396..000000000 --- a/tools/release/registry-integrity.test.mjs +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { mkdirSync, mkdtempSync, rmSync, statSync, writeFileSync } from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { - validateLockedRegistryReceipts, - validateRegistryReceiptEvidence, - verifyLockedCarrierIntegrity, - verifyLockedRegistryIntegrity, - writeRegistryReceiptEvidence, -} from "./registry-integrity.mjs"; -import { createCratesIoReadGate } from "./registry-http-retry.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const sha = (bytes, algorithm, encoding = "hex") => createHash(algorithm).update(bytes).digest(encoding); - -test("proves Cargo checksum and npm SRI against frozen archive bytes and rejects same-version byte conflicts", async () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "registry-integrity-test-")); - try { - const crateBytes = Buffer.from("exact crate bytes\n"); - const npmBytes = Buffer.from("exact npm tarball bytes\n"); - const crateFile = path.join(root, "alpha-1.0.0.crate"); - const npmFile = path.join(root, "alpha-1.0.0.tgz"); - writeFileSync(crateFile, crateBytes); - writeFileSync(npmFile, npmBytes); - const lock = { - lockDigest: "a".repeat(64), - source: { commit: "b".repeat(40), tree: "c".repeat(40) }, - carriers: [ - { id: "cargo:alpha", product: "alpha", ecosystem: "cargo", name: "alpha", version: "1.0.0", publishOrder: 0, artifacts: [{ path: path.relative(ROOT, crateFile), sha256: sha(crateBytes, "sha256"), size: statSync(crateFile).size }] }, - { id: "npm:@example/alpha", product: "alpha", ecosystem: "npm", name: "@example/alpha", version: "1.0.0", publishOrder: 1, artifacts: [{ path: path.relative(ROOT, npmFile), sha256: sha(npmBytes, "sha256"), size: statSync(npmFile).size }] }, - ], - }; - const requestedUrls = []; - const goodFetch = async (url) => { - requestedUrls.push(url); - return Response.json( - url.includes("crates") - ? { version: { checksum: sha(crateBytes, "sha256") } } - : { dist: { integrity: `sha512-${sha(npmBytes, "sha512", "base64")}` } }, - ); - }; - const cargo = await verifyLockedCarrierIntegrity(lock, "cargo:alpha", { fetchImpl: goodFetch }); - const npm = await verifyLockedCarrierIntegrity(lock, "npm:@example/alpha", { fetchImpl: goodFetch }); - assert.equal(cargo.registryProof.digest, sha(crateBytes, "sha256")); - assert.equal(npm.registryProof.digest, sha(npmBytes, "sha512", "base64")); - assert.equal(npm.registryProof.url, "https://registry.npmjs.org/%40example%2Falpha/1.0.0"); - assert.ok(requestedUrls.includes("https://registry.npmjs.org/%40example%2Falpha/1.0.0")); - const cargoReadStarts = []; - const bulk = await verifyLockedRegistryIntegrity(lock, { - products: ["alpha"], ecosystems: ["cargo", "npm"], fetchImpl: goodFetch, concurrency: 2, - cratesIoReadGate: { - beforeRequest: async (label) => cargoReadStarts.push(label), - defer: () => {}, - }, - }); - assert.deepEqual(bulk.map((receipt) => receipt.id), ["cargo:alpha", "npm:@example/alpha"]); - assert.deepEqual(cargoReadStarts, ["https://crates.io/api/v1/crates/alpha/1.0.0"]); - assert.deepEqual(validateLockedRegistryReceipts(lock, { - products: ["alpha"], - ecosystems: ["cargo", "npm"], - receipts: bulk, - }), bulk); - const evidenceFile = path.join(root, "registry-receipts.json"); - writeRegistryReceiptEvidence(evidenceFile, lock, { - products: ["alpha"], - ecosystems: ["cargo", "npm"], - receipts: bulk, - }); - assert.equal(validateRegistryReceiptEvidence(evidenceFile, lock, { - products: ["alpha"], - ecosystems: ["cargo", "npm"], - }).receipts.length, 2); - const conflicting = structuredClone(bulk); - conflicting[0].registryProof.digest = "0".repeat(64); - assert.throws(() => validateLockedRegistryReceipts(lock, { - products: ["alpha"], ecosystems: ["cargo", "npm"], receipts: conflicting, - }), /does not exactly prove/u); - await assert.rejects( - () => verifyLockedRegistryIntegrity(lock, { products: ["alpha"], ecosystems: ["cargo"], fetchImpl: goodFetch, concurrency: 0 }), - /concurrency/u, - ); - - const badFetch = async (url) => Response.json( - url.includes("crates") - ? { version: { checksum: "0".repeat(64) } } - : { dist: { integrity: `sha512-${Buffer.alloc(64).toString("base64")}` } }, - ); - await assert.rejects(() => verifyLockedCarrierIntegrity(lock, "cargo:alpha", { fetchImpl: badFetch }), /checksum mismatch/u); - await assert.rejects(() => verifyLockedCarrierIntegrity(lock, "npm:@example/alpha", { fetchImpl: badFetch }), /integrity mismatch/u); - - let rateLimitedAttempts = 0; - const rateLimitedThenGood = async () => { - rateLimitedAttempts += 1; - if (rateLimitedAttempts === 1) { - return { - ok: false, - status: 429, - headers: { get: (name) => name === "retry-after" ? "0" : null }, - body: { cancel: async () => {} }, - }; - } - return Response.json({ version: { checksum: sha(crateBytes, "sha256") } }); - }; - await verifyLockedCarrierIntegrity(lock, "cargo:alpha", { fetchImpl: rateLimitedThenGood }); - assert.equal(rateLimitedAttempts, 2); - - let authoritativeRetryAttempts = 0; - const authoritativeDeferrals = []; - const authoritativeRetryGate = { - beforeRequest: async () => {}, - defer: (seconds) => authoritativeDeferrals.push(seconds), - }; - await verifyLockedCarrierIntegrity(lock, "cargo:alpha", { - cratesIoReadGate: authoritativeRetryGate, - fetchImpl: async () => { - authoritativeRetryAttempts += 1; - if (authoritativeRetryAttempts === 1) { - return { - ok: false, - status: 429, - headers: { get: (name) => name === "retry-after" ? "45" : null }, - body: { cancel: async () => {} }, - }; - } - return Response.json({ version: { checksum: sha(crateBytes, "sha256") } }); - }, - }); - assert.equal(authoritativeRetryAttempts, 2); - assert.deepEqual(authoritativeDeferrals, [45]); - - let excessiveRetryAttempts = 0; - await assert.rejects( - () => verifyLockedCarrierIntegrity(lock, "cargo:alpha", { - cratesIoReadGate: { - beforeRequest: async () => {}, - defer: () => assert.fail("an excessive Retry-After must fail before deferring the read gate"), - }, - fetchImpl: async () => { - excessiveRetryAttempts += 1; - return { - ok: false, - status: 429, - headers: { get: (name) => name === "retry-after" ? "601" : null }, - body: { cancel: async () => {} }, - }; - }, - }), - /bounded 600s retry-delay budget/u, - ); - assert.equal(excessiveRetryAttempts, 1); - - let logicalNowSeconds = 1_000; - const sharedGateSleeps = []; - const sharedGate = createCratesIoReadGate({ - nowImpl: () => logicalNowSeconds, - sleepImpl: async (milliseconds) => { - sharedGateSleeps.push(milliseconds); - logicalNowSeconds += milliseconds / 1000; - }, - }); - await verifyLockedCarrierIntegrity(lock, "cargo:alpha", { fetchImpl: goodFetch, cratesIoReadGate: sharedGate }); - await verifyLockedCarrierIntegrity(lock, "cargo:alpha", { fetchImpl: goodFetch, cratesIoReadGate: sharedGate }); - assert.deepEqual(sharedGateSleeps, [250]); - - let notFoundAttempts = 0; - const notFound = async () => { - notFoundAttempts += 1; - return { ok: false, status: 404, headers: { get: () => null } }; - }; - await assert.rejects(() => verifyLockedCarrierIntegrity(lock, "cargo:alpha", { fetchImpl: notFound }), /HTTP 404.*after 1 attempt/u); - assert.equal(notFoundAttempts, 1); - - let oversizedAttempts = 0; - const oversizedMetadata = async () => { - oversizedAttempts += 1; - return new Response("{}", { - headers: { "content-length": String(8 * 1024 * 1024 + 1) }, - }); - }; - await assert.rejects( - () => verifyLockedCarrierIntegrity(lock, "cargo:alpha", { fetchImpl: oversizedMetadata }), - /response exceeds 8388608 bytes.*after 1 attempt/u, - ); - assert.equal(oversizedAttempts, 1); - - const previousDeadline = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; - let afterDeadlineRequests = 0; - try { - process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = String(Math.floor(Date.now() / 1000) - 1); - await assert.rejects( - () => verifyLockedCarrierIntegrity(lock, "npm:@example/alpha", { - fetchImpl: async () => { - afterDeadlineRequests += 1; - return goodFetch("npm"); - }, - }), - /shared registry mutation deadline has been reached/u, - ); - assert.equal(afterDeadlineRequests, 0); - } finally { - if (previousDeadline === undefined) delete process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; - else process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = previousDeadline; - } - - rmSync(crateFile); - rmSync(npmFile); - assert.equal(validateRegistryReceiptEvidence(evidenceFile, lock, { - products: ["alpha"], - ecosystems: ["cargo", "npm"], - receiptMode: "sealed", - }).receipts.length, 2); - assert.throws(() => validateRegistryReceiptEvidence(evidenceFile, lock, { - products: ["alpha"], - ecosystems: ["cargo", "npm"], - }), /locked artifact is unavailable/u); - - const changedCargo = structuredClone(bulk); - changedCargo[0].registryProof.digest = "0".repeat(64); - assert.throws(() => validateLockedRegistryReceipts(lock, { - products: ["alpha"], - ecosystems: ["cargo", "npm"], - receiptMode: "sealed", - receipts: changedCargo, - }), /sealed Cargo proof changed/u); - const changedNpm = structuredClone(bulk); - changedNpm[1].registryProof.digest = "not-base64"; - assert.throws(() => validateLockedRegistryReceipts(lock, { - products: ["alpha"], - ecosystems: ["cargo", "npm"], - receiptMode: "sealed", - receipts: changedNpm, - }), /canonical SHA-512 base64/u); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("proves every frozen Maven payload before an immutable-version skip", async () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "registry-integrity-maven-test-")); - try { - const mavenBytes = Buffer.from("exact Maven payload bytes\n"); - const mavenFile = path.join(root, "native-runtime.tar.gz"); - writeFileSync(mavenFile, mavenBytes); - - const lock = { - carriers: [ - { - id: "maven:dev.example:alpha-native", - product: "alpha", - ecosystem: "maven", - name: "dev.example:alpha-native", - version: "1.0.0", - publishOrder: 0, - artifacts: [{ path: path.relative(ROOT, mavenFile), sha256: sha(mavenBytes, "sha256"), size: mavenBytes.length }], - }, - ], - }; - const goodFetch = async () => new Response(mavenBytes); - - const maven = await verifyLockedCarrierIntegrity(lock, "maven:dev.example:alpha-native", { fetchImpl: goodFetch }); - assert.equal(maven.registryProof.files[0].digest, sha(mavenBytes, "sha256")); - - const wrongMavenFetch = async () => new Response(Buffer.from("different immutable bytes\n")); - await assert.rejects( - () => verifyLockedCarrierIntegrity(lock, "maven:dev.example:alpha-native", { fetchImpl: wrongMavenFetch }), - /Maven payload mismatch/u, - ); - let oversizedPayloadAttempts = 0; - const oversizedMavenFetch = async () => { - oversizedPayloadAttempts += 1; - return new Response(mavenBytes, { - headers: { "content-length": String(mavenBytes.length + 1) }, - }); - }; - await assert.rejects( - () => verifyLockedCarrierIntegrity(lock, "maven:dev.example:alpha-native", { fetchImpl: oversizedMavenFetch }), - /response exceeds locked size.*after 1 attempt/u, - ); - assert.equal(oversizedPayloadAttempts, 1); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("writes and revalidates exhaustive empty evidence for a selected source-only release", () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target", "registry-integrity-empty-test-")); - try { - const lock = { - lockDigest: "d".repeat(64), - source: { commit: "e".repeat(40), tree: "f".repeat(40) }, - carriers: [], - }; - const file = path.join(root, "empty-receipts.json"); - const ecosystems = ["cargo", "npm", "maven"]; - const written = writeRegistryReceiptEvidence(file, lock, { - products: ["oliphaunt-swift"], - ecosystems, - receipts: [], - }); - assert.deepEqual(written.receipts, []); - const verified = validateRegistryReceiptEvidence(file, lock, { - products: ["oliphaunt-swift"], - ecosystems, - }); - assert.deepEqual(verified.products, ["oliphaunt-swift"]); - assert.deepEqual(verified.receipts, []); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/registry-integrity.test.mts b/tools/release/registry-integrity.test.mts new file mode 100644 index 000000000..edfc2c30a --- /dev/null +++ b/tools/release/registry-integrity.test.mts @@ -0,0 +1,420 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, rmSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import test from 'node:test'; + +import { + validateLockedRegistryReceipts, + validateRegistryReceiptEvidence, + verifyLockedCarrierIntegrity, + verifyLockedRegistryIntegrity, + writeRegistryReceiptEvidence, +} from './registry-integrity.mts'; +import { createCratesIoReadGate } from './registry-http-retry.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); +const sha = (bytes, algorithm, encoding = 'hex') => + createHash(algorithm).update(bytes).digest(encoding); + +test('proves Cargo checksum and npm SRI against frozen archive bytes and rejects same-version byte conflicts', async () => { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target', 'registry-integrity-test-')); + try { + const crateBytes = Buffer.from('exact crate bytes\n'); + const npmBytes = Buffer.from('exact npm tarball bytes\n'); + const crateFile = path.join(root, 'alpha-1.0.0.crate'); + const npmFile = path.join(root, 'alpha-1.0.0.tgz'); + writeFileSync(crateFile, crateBytes); + writeFileSync(npmFile, npmBytes); + const lock = { + lockDigest: 'a'.repeat(64), + source: { commit: 'b'.repeat(40), tree: 'c'.repeat(40) }, + carriers: [ + { + id: 'cargo:alpha', + product: 'alpha', + ecosystem: 'cargo', + name: 'alpha', + version: '1.0.0', + publishOrder: 0, + artifacts: [ + { + path: path.relative(ROOT, crateFile), + sha256: sha(crateBytes, 'sha256'), + size: statSync(crateFile).size, + }, + ], + }, + { + id: 'npm:@example/alpha', + product: 'alpha', + ecosystem: 'npm', + name: '@example/alpha', + version: '1.0.0', + publishOrder: 1, + artifacts: [ + { + path: path.relative(ROOT, npmFile), + sha256: sha(npmBytes, 'sha256'), + size: statSync(npmFile).size, + }, + ], + }, + ], + }; + const requestedUrls = []; + const goodFetch = async (url) => { + requestedUrls.push(url); + return Response.json( + url.includes('crates') + ? { version: { checksum: sha(crateBytes, 'sha256') } } + : { dist: { integrity: `sha512-${sha(npmBytes, 'sha512', 'base64')}` } }, + ); + }; + const cargo = await verifyLockedCarrierIntegrity(lock, 'cargo:alpha', { fetchImpl: goodFetch }); + const npm = await verifyLockedCarrierIntegrity(lock, 'npm:@example/alpha', { + fetchImpl: goodFetch, + }); + assert.equal(cargo.registryProof.digest, sha(crateBytes, 'sha256')); + assert.equal(npm.registryProof.digest, sha(npmBytes, 'sha512', 'base64')); + assert.equal(npm.registryProof.url, 'https://registry.npmjs.org/%40example%2Falpha/1.0.0'); + assert.ok(requestedUrls.includes('https://registry.npmjs.org/%40example%2Falpha/1.0.0')); + const cargoReadStarts = []; + const bulk = await verifyLockedRegistryIntegrity(lock, { + products: ['alpha'], + ecosystems: ['cargo', 'npm'], + fetchImpl: goodFetch, + concurrency: 2, + cratesIoReadGate: { + beforeRequest: async (label) => cargoReadStarts.push(label), + defer: () => {}, + }, + }); + assert.deepEqual( + bulk.map((receipt) => receipt.id), + ['cargo:alpha', 'npm:@example/alpha'], + ); + assert.deepEqual(cargoReadStarts, ['https://crates.io/api/v1/crates/alpha/1.0.0']); + assert.deepEqual( + validateLockedRegistryReceipts(lock, { + products: ['alpha'], + ecosystems: ['cargo', 'npm'], + receipts: bulk, + }), + bulk, + ); + const evidenceFile = path.join(root, 'registry-receipts.json'); + writeRegistryReceiptEvidence(evidenceFile, lock, { + products: ['alpha'], + ecosystems: ['cargo', 'npm'], + receipts: bulk, + }); + assert.equal( + validateRegistryReceiptEvidence(evidenceFile, lock, { + products: ['alpha'], + ecosystems: ['cargo', 'npm'], + }).receipts.length, + 2, + ); + const conflicting = structuredClone(bulk); + conflicting[0].registryProof.digest = '0'.repeat(64); + assert.throws( + () => + validateLockedRegistryReceipts(lock, { + products: ['alpha'], + ecosystems: ['cargo', 'npm'], + receipts: conflicting, + }), + /does not exactly prove/u, + ); + await assert.rejects( + () => + verifyLockedRegistryIntegrity(lock, { + products: ['alpha'], + ecosystems: ['cargo'], + fetchImpl: goodFetch, + concurrency: 0, + }), + /concurrency/u, + ); + + const badFetch = async (url) => + Response.json( + url.includes('crates') + ? { version: { checksum: '0'.repeat(64) } } + : { dist: { integrity: `sha512-${Buffer.alloc(64).toString('base64')}` } }, + ); + await assert.rejects( + () => verifyLockedCarrierIntegrity(lock, 'cargo:alpha', { fetchImpl: badFetch }), + /checksum mismatch/u, + ); + await assert.rejects( + () => verifyLockedCarrierIntegrity(lock, 'npm:@example/alpha', { fetchImpl: badFetch }), + /integrity mismatch/u, + ); + + let rateLimitedAttempts = 0; + const rateLimitedThenGood = async () => { + rateLimitedAttempts += 1; + if (rateLimitedAttempts === 1) { + return { + ok: false, + status: 429, + headers: { get: (name) => (name === 'retry-after' ? '0' : null) }, + body: { cancel: async () => {} }, + }; + } + return Response.json({ version: { checksum: sha(crateBytes, 'sha256') } }); + }; + await verifyLockedCarrierIntegrity(lock, 'cargo:alpha', { fetchImpl: rateLimitedThenGood }); + assert.equal(rateLimitedAttempts, 2); + + let authoritativeRetryAttempts = 0; + const authoritativeDeferrals = []; + const authoritativeRetryGate = { + beforeRequest: async () => {}, + defer: (seconds) => authoritativeDeferrals.push(seconds), + }; + await verifyLockedCarrierIntegrity(lock, 'cargo:alpha', { + cratesIoReadGate: authoritativeRetryGate, + fetchImpl: async () => { + authoritativeRetryAttempts += 1; + if (authoritativeRetryAttempts === 1) { + return { + ok: false, + status: 429, + headers: { get: (name) => (name === 'retry-after' ? '45' : null) }, + body: { cancel: async () => {} }, + }; + } + return Response.json({ version: { checksum: sha(crateBytes, 'sha256') } }); + }, + }); + assert.equal(authoritativeRetryAttempts, 2); + assert.deepEqual(authoritativeDeferrals, [45]); + + let excessiveRetryAttempts = 0; + await assert.rejects( + () => + verifyLockedCarrierIntegrity(lock, 'cargo:alpha', { + cratesIoReadGate: { + beforeRequest: async () => {}, + defer: () => + assert.fail('an excessive Retry-After must fail before deferring the read gate'), + }, + fetchImpl: async () => { + excessiveRetryAttempts += 1; + return { + ok: false, + status: 429, + headers: { get: (name) => (name === 'retry-after' ? '601' : null) }, + body: { cancel: async () => {} }, + }; + }, + }), + /bounded 600s retry-delay budget/u, + ); + assert.equal(excessiveRetryAttempts, 1); + + let logicalNowSeconds = 1_000; + const sharedGateSleeps = []; + const sharedGate = createCratesIoReadGate({ + nowImpl: () => logicalNowSeconds, + sleepImpl: async (milliseconds) => { + sharedGateSleeps.push(milliseconds); + logicalNowSeconds += milliseconds / 1000; + }, + }); + await verifyLockedCarrierIntegrity(lock, 'cargo:alpha', { + fetchImpl: goodFetch, + cratesIoReadGate: sharedGate, + }); + await verifyLockedCarrierIntegrity(lock, 'cargo:alpha', { + fetchImpl: goodFetch, + cratesIoReadGate: sharedGate, + }); + assert.deepEqual(sharedGateSleeps, [250]); + + let notFoundAttempts = 0; + const notFound = async () => { + notFoundAttempts += 1; + return { ok: false, status: 404, headers: { get: () => null } }; + }; + await assert.rejects( + () => verifyLockedCarrierIntegrity(lock, 'cargo:alpha', { fetchImpl: notFound }), + /HTTP 404.*after 1 attempt/u, + ); + assert.equal(notFoundAttempts, 1); + + let oversizedAttempts = 0; + const oversizedMetadata = async () => { + oversizedAttempts += 1; + return new Response('{}', { + headers: { 'content-length': String(8 * 1024 * 1024 + 1) }, + }); + }; + await assert.rejects( + () => verifyLockedCarrierIntegrity(lock, 'cargo:alpha', { fetchImpl: oversizedMetadata }), + /response exceeds 8388608 bytes.*after 1 attempt/u, + ); + assert.equal(oversizedAttempts, 1); + + const previousDeadline = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; + let afterDeadlineRequests = 0; + try { + process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = String(Math.floor(Date.now() / 1000) - 1); + await assert.rejects( + () => + verifyLockedCarrierIntegrity(lock, 'npm:@example/alpha', { + fetchImpl: async () => { + afterDeadlineRequests += 1; + return goodFetch('npm'); + }, + }), + /shared registry mutation deadline has been reached/u, + ); + assert.equal(afterDeadlineRequests, 0); + } finally { + if (previousDeadline === undefined) delete process.env.REGISTRY_MUTATION_DEADLINE_EPOCH; + else process.env.REGISTRY_MUTATION_DEADLINE_EPOCH = previousDeadline; + } + + rmSync(crateFile); + rmSync(npmFile); + assert.equal( + validateRegistryReceiptEvidence(evidenceFile, lock, { + products: ['alpha'], + ecosystems: ['cargo', 'npm'], + receiptMode: 'sealed', + }).receipts.length, + 2, + ); + assert.throws( + () => + validateRegistryReceiptEvidence(evidenceFile, lock, { + products: ['alpha'], + ecosystems: ['cargo', 'npm'], + }), + /locked artifact is unavailable/u, + ); + + const changedCargo = structuredClone(bulk); + changedCargo[0].registryProof.digest = '0'.repeat(64); + assert.throws( + () => + validateLockedRegistryReceipts(lock, { + products: ['alpha'], + ecosystems: ['cargo', 'npm'], + receiptMode: 'sealed', + receipts: changedCargo, + }), + /sealed Cargo proof changed/u, + ); + const changedNpm = structuredClone(bulk); + changedNpm[1].registryProof.digest = 'not-base64'; + assert.throws( + () => + validateLockedRegistryReceipts(lock, { + products: ['alpha'], + ecosystems: ['cargo', 'npm'], + receiptMode: 'sealed', + receipts: changedNpm, + }), + /canonical SHA-512 base64/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('proves every frozen Maven payload before an immutable-version skip', async () => { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target', 'registry-integrity-maven-test-')); + try { + const mavenBytes = Buffer.from('exact Maven payload bytes\n'); + const mavenFile = path.join(root, 'native-runtime.tar.gz'); + writeFileSync(mavenFile, mavenBytes); + + const lock = { + carriers: [ + { + id: 'maven:dev.example:alpha-native', + product: 'alpha', + ecosystem: 'maven', + name: 'dev.example:alpha-native', + version: '1.0.0', + publishOrder: 0, + artifacts: [ + { + path: path.relative(ROOT, mavenFile), + sha256: sha(mavenBytes, 'sha256'), + size: mavenBytes.length, + }, + ], + }, + ], + }; + const goodFetch = async () => new Response(mavenBytes); + + const maven = await verifyLockedCarrierIntegrity(lock, 'maven:dev.example:alpha-native', { + fetchImpl: goodFetch, + }); + assert.equal(maven.registryProof.files[0].digest, sha(mavenBytes, 'sha256')); + + const wrongMavenFetch = async () => new Response(Buffer.from('different immutable bytes\n')); + await assert.rejects( + () => + verifyLockedCarrierIntegrity(lock, 'maven:dev.example:alpha-native', { + fetchImpl: wrongMavenFetch, + }), + /Maven payload mismatch/u, + ); + let oversizedPayloadAttempts = 0; + const oversizedMavenFetch = async () => { + oversizedPayloadAttempts += 1; + return new Response(mavenBytes, { + headers: { 'content-length': String(mavenBytes.length + 1) }, + }); + }; + await assert.rejects( + () => + verifyLockedCarrierIntegrity(lock, 'maven:dev.example:alpha-native', { + fetchImpl: oversizedMavenFetch, + }), + /response exceeds locked size.*after 1 attempt/u, + ); + assert.equal(oversizedPayloadAttempts, 1); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('writes and revalidates exhaustive empty evidence for a selected source-only release', () => { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target', 'registry-integrity-empty-test-')); + try { + const lock = { + lockDigest: 'd'.repeat(64), + source: { commit: 'e'.repeat(40), tree: 'f'.repeat(40) }, + carriers: [], + }; + const file = path.join(root, 'empty-receipts.json'); + const ecosystems = ['cargo', 'npm', 'maven']; + const written = writeRegistryReceiptEvidence(file, lock, { + products: ['oliphaunt-swift'], + ecosystems, + receipts: [], + }); + assert.deepEqual(written.receipts, []); + const verified = validateRegistryReceiptEvidence(file, lock, { + products: ['oliphaunt-swift'], + ecosystems, + }); + assert.deepEqual(verified.products, ['oliphaunt-swift']); + assert.deepEqual(verified.receipts, []); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/tools/release/registry-publication-deferral.mjs b/tools/release/registry-publication-deferral.mjs deleted file mode 100644 index f3508d476..000000000 --- a/tools/release/registry-publication-deferral.mjs +++ /dev/null @@ -1,139 +0,0 @@ -const REASONS = new Set(["deadline", "rate-limit"]); -const RECORD_KEYS = ["context", "notBeforeEpochSeconds", "reason", "schema"]; - -export const REGISTRY_PUBLICATION_DEFERRAL_SCHEMA = "oliphaunt-registry-publication-deferral-v1"; -export const REGISTRY_PUBLICATION_DEFERRAL_PREFIX = "OLIPHAUNT_REGISTRY_PUBLICATION_DEFERRED="; -export const REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE = 75; - -function error(message) { - return new Error(`registry-publication-deferral: ${message}`); -} - -/** - * Narrow, dependency-neutral control-flow signal for a known-safe registry - * pause. Callers may construct it only before any mutation request - * starts, or after an explicit HTTP 429 proves that a registry rejected the - * mutation without accepting its payload. - */ -export class RegistryPublicationDeferredError extends Error { - constructor({ reason, notBeforeEpochSeconds, context }) { - if (!REASONS.has(reason)) { - throw error(`reason must be one of ${[...REASONS].join(", ")}`); - } - if (!Number.isSafeInteger(notBeforeEpochSeconds) || notBeforeEpochSeconds <= 0) { - throw error("notBeforeEpochSeconds must be a positive Unix timestamp"); - } - if (typeof context !== "string" || context.length === 0) { - throw error("context must be a non-empty string"); - } - super(`registry publication deferred (${reason}) until ${notBeforeEpochSeconds}: ${context}`); - this.name = "RegistryPublicationDeferredError"; - this.code = "OLIPHAUNT_REGISTRY_PUBLICATION_DEFERRED"; - this.reason = reason; - this.notBeforeEpochSeconds = notBeforeEpochSeconds; - this.context = context; - } -} - -export function isRegistryPublicationDeferredError(cause) { - return cause instanceof RegistryPublicationDeferredError; -} - -/** - * Admit an operation immediately before its first remote mutation. A caller - * must not use this helper after an upload or state-changing request starts: - * at that point deadline exhaustion is ambiguous and must remain terminal - * until exact remote state has been reconciled. - */ -export function requirePreMutationRegistryWindow({ - deadlineEpochSeconds, - minimumMilliseconds, - context, - reserveMilliseconds = 0, - nowEpochMilliseconds = Date.now(), -}) { - if ( - !Number.isSafeInteger(deadlineEpochSeconds) - || deadlineEpochSeconds < 1 - || deadlineEpochSeconds > Math.floor(Number.MAX_SAFE_INTEGER / 1000) - ) { - throw error("deadlineEpochSeconds must be a positive safe Unix timestamp"); - } - for (const [value, label] of [ - [minimumMilliseconds, "minimumMilliseconds"], - [reserveMilliseconds, "reserveMilliseconds"], - [nowEpochMilliseconds, "nowEpochMilliseconds"], - ]) { - if (!Number.isSafeInteger(value) || value < 0) { - throw error(`${label} must be a non-negative safe integer`); - } - } - if (minimumMilliseconds < 1) { - throw error("minimumMilliseconds must be positive"); - } - if (typeof context !== "string" || context.length === 0) { - throw error("pre-mutation window context must be a non-empty string"); - } - const availableMilliseconds = (deadlineEpochSeconds * 1000) - - nowEpochMilliseconds - - reserveMilliseconds; - if (availableMilliseconds < minimumMilliseconds) { - throw new RegistryPublicationDeferredError({ - reason: "deadline", - notBeforeEpochSeconds: Math.floor(nowEpochMilliseconds / 1000) + 1, - context: `${context} requires ${Math.ceil(minimumMilliseconds / 1000)}s before its first remote mutation; ` - + `${Math.max(0, Math.floor(availableMilliseconds / 1000))}s remain`, - }); - } - return availableMilliseconds; -} - -export function encodeRegistryPublicationDeferral(cause) { - if (!isRegistryPublicationDeferredError(cause)) { - throw error("only a RegistryPublicationDeferredError can cross the safe child-process boundary"); - } - const record = { - schema: REGISTRY_PUBLICATION_DEFERRAL_SCHEMA, - reason: cause.reason, - notBeforeEpochSeconds: cause.notBeforeEpochSeconds, - context: cause.context, - }; - return `${REGISTRY_PUBLICATION_DEFERRAL_PREFIX}${Buffer.from(JSON.stringify(record), "utf8").toString("base64url")}`; -} - -export function decodeRegistryPublicationDeferral(stderrTail) { - if (typeof stderrTail !== "string") throw error("child stderr tail must be a string"); - const encoded = stderrTail - .split(/\r?\n/u) - .filter((line) => line.startsWith(REGISTRY_PUBLICATION_DEFERRAL_PREFIX)) - .map((line) => line.slice(REGISTRY_PUBLICATION_DEFERRAL_PREFIX.length)); - if (encoded.length !== 1 || !/^[A-Za-z0-9_-]+$/u.test(encoded[0])) { - throw error("safe-deferral exit requires exactly one canonical typed deferral record"); - } - const bytes = Buffer.from(encoded[0], "base64url"); - if (bytes.toString("base64url") !== encoded[0]) { - throw error("typed deferral record is not canonical base64url"); - } - let value; - try { - value = JSON.parse(bytes.toString("utf8")); - } catch (cause) { - throw error(`typed deferral record is not strict JSON: ${cause.message}`); - } - if ( - value === null - || Array.isArray(value) - || typeof value !== "object" - || JSON.stringify(Object.keys(value).sort()) !== JSON.stringify(RECORD_KEYS) - ) { - throw error(`typed deferral record keys must be exactly ${RECORD_KEYS.join(", ")}`); - } - if (value.schema !== REGISTRY_PUBLICATION_DEFERRAL_SCHEMA) { - throw error(`typed deferral record schema must be ${REGISTRY_PUBLICATION_DEFERRAL_SCHEMA}`); - } - return new RegistryPublicationDeferredError({ - reason: value.reason, - notBeforeEpochSeconds: value.notBeforeEpochSeconds, - context: value.context, - }); -} diff --git a/tools/release/registry-publication-deferral.mts b/tools/release/registry-publication-deferral.mts new file mode 100644 index 000000000..13d7b478f --- /dev/null +++ b/tools/release/registry-publication-deferral.mts @@ -0,0 +1,141 @@ +const REASONS = new Set(['deadline', 'rate-limit']); +const RECORD_KEYS = ['context', 'notBeforeEpochSeconds', 'reason', 'schema']; + +export const REGISTRY_PUBLICATION_DEFERRAL_SCHEMA = 'oliphaunt-registry-publication-deferral-v1'; +export const REGISTRY_PUBLICATION_DEFERRAL_PREFIX = 'OLIPHAUNT_REGISTRY_PUBLICATION_DEFERRED='; +export const REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE = 75; + +function error(message) { + return new Error(`registry-publication-deferral: ${message}`); +} + +/** + * Narrow, dependency-neutral control-flow signal for a known-safe registry + * pause. Callers may construct it only before any mutation request + * starts, or after an explicit HTTP 429 proves that a registry rejected the + * mutation without accepting its payload. + */ +export class RegistryPublicationDeferredError extends Error { + constructor({ reason, notBeforeEpochSeconds, context }) { + if (!REASONS.has(reason)) { + throw error(`reason must be one of ${[...REASONS].join(', ')}`); + } + if (!Number.isSafeInteger(notBeforeEpochSeconds) || notBeforeEpochSeconds <= 0) { + throw error('notBeforeEpochSeconds must be a positive Unix timestamp'); + } + if (typeof context !== 'string' || context.length === 0) { + throw error('context must be a non-empty string'); + } + super(`registry publication deferred (${reason}) until ${notBeforeEpochSeconds}: ${context}`); + this.name = 'RegistryPublicationDeferredError'; + this.code = 'OLIPHAUNT_REGISTRY_PUBLICATION_DEFERRED'; + this.reason = reason; + this.notBeforeEpochSeconds = notBeforeEpochSeconds; + this.context = context; + } +} + +export function isRegistryPublicationDeferredError(cause) { + return cause instanceof RegistryPublicationDeferredError; +} + +/** + * Admit an operation immediately before its first remote mutation. A caller + * must not use this helper after an upload or state-changing request starts: + * at that point deadline exhaustion is ambiguous and must remain terminal + * until exact remote state has been reconciled. + */ +export function requirePreMutationRegistryWindow({ + deadlineEpochSeconds, + minimumMilliseconds, + context, + reserveMilliseconds = 0, + nowEpochMilliseconds = Date.now(), +}) { + if ( + !Number.isSafeInteger(deadlineEpochSeconds) || + deadlineEpochSeconds < 1 || + deadlineEpochSeconds > Math.floor(Number.MAX_SAFE_INTEGER / 1000) + ) { + throw error('deadlineEpochSeconds must be a positive safe Unix timestamp'); + } + for (const [value, label] of [ + [minimumMilliseconds, 'minimumMilliseconds'], + [reserveMilliseconds, 'reserveMilliseconds'], + [nowEpochMilliseconds, 'nowEpochMilliseconds'], + ]) { + if (!Number.isSafeInteger(value) || value < 0) { + throw error(`${label} must be a non-negative safe integer`); + } + } + if (minimumMilliseconds < 1) { + throw error('minimumMilliseconds must be positive'); + } + if (typeof context !== 'string' || context.length === 0) { + throw error('pre-mutation window context must be a non-empty string'); + } + const availableMilliseconds = + deadlineEpochSeconds * 1000 - nowEpochMilliseconds - reserveMilliseconds; + if (availableMilliseconds < minimumMilliseconds) { + throw new RegistryPublicationDeferredError({ + reason: 'deadline', + notBeforeEpochSeconds: Math.floor(nowEpochMilliseconds / 1000) + 1, + context: + `${context} requires ${Math.ceil(minimumMilliseconds / 1000)}s before its first remote mutation; ` + + `${Math.max(0, Math.floor(availableMilliseconds / 1000))}s remain`, + }); + } + return availableMilliseconds; +} + +export function encodeRegistryPublicationDeferral(cause) { + if (!isRegistryPublicationDeferredError(cause)) { + throw error( + 'only a RegistryPublicationDeferredError can cross the safe child-process boundary', + ); + } + const record = { + schema: REGISTRY_PUBLICATION_DEFERRAL_SCHEMA, + reason: cause.reason, + notBeforeEpochSeconds: cause.notBeforeEpochSeconds, + context: cause.context, + }; + return `${REGISTRY_PUBLICATION_DEFERRAL_PREFIX}${Buffer.from(JSON.stringify(record), 'utf8').toString('base64url')}`; +} + +export function decodeRegistryPublicationDeferral(stderrTail) { + if (typeof stderrTail !== 'string') throw error('child stderr tail must be a string'); + const encoded = stderrTail + .split(/\r?\n/u) + .filter((line) => line.startsWith(REGISTRY_PUBLICATION_DEFERRAL_PREFIX)) + .map((line) => line.slice(REGISTRY_PUBLICATION_DEFERRAL_PREFIX.length)); + if (encoded.length !== 1 || !/^[A-Za-z0-9_-]+$/u.test(encoded[0])) { + throw error('safe-deferral exit requires exactly one canonical typed deferral record'); + } + const bytes = Buffer.from(encoded[0], 'base64url'); + if (bytes.toString('base64url') !== encoded[0]) { + throw error('typed deferral record is not canonical base64url'); + } + let value; + try { + value = JSON.parse(bytes.toString('utf8')); + } catch (cause) { + throw error(`typed deferral record is not strict JSON: ${cause.message}`); + } + if ( + value === null || + Array.isArray(value) || + typeof value !== 'object' || + JSON.stringify(Object.keys(value).sort()) !== JSON.stringify(RECORD_KEYS) + ) { + throw error(`typed deferral record keys must be exactly ${RECORD_KEYS.join(', ')}`); + } + if (value.schema !== REGISTRY_PUBLICATION_DEFERRAL_SCHEMA) { + throw error(`typed deferral record schema must be ${REGISTRY_PUBLICATION_DEFERRAL_SCHEMA}`); + } + return new RegistryPublicationDeferredError({ + reason: value.reason, + notBeforeEpochSeconds: value.notBeforeEpochSeconds, + context: value.context, + }); +} diff --git a/tools/release/registry-publication-deferral.test.mjs b/tools/release/registry-publication-deferral.test.mjs deleted file mode 100644 index 854741e19..000000000 --- a/tools/release/registry-publication-deferral.test.mjs +++ /dev/null @@ -1,93 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { - decodeRegistryPublicationDeferral, - encodeRegistryPublicationDeferral, - isRegistryPublicationDeferredError, - requirePreMutationRegistryWindow, - RegistryPublicationDeferredError, - REGISTRY_PUBLICATION_DEFERRAL_PREFIX, -} from "./registry-publication-deferral.mjs"; - -describe("registry publication deferral child boundary", () => { - test("round-trips one canonical typed record embedded in ordinary stderr", () => { - const original = new RegistryPublicationDeferredError({ - reason: "rate-limit", - notBeforeEpochSeconds: 1_800_000_000, - context: "explicit crates.io 429 with valid Retry-After", - }); - const encoded = encodeRegistryPublicationDeferral(original); - expect(encoded).toStartWith(REGISTRY_PUBLICATION_DEFERRAL_PREFIX); - const decoded = decodeRegistryPublicationDeferral(`ordinary diagnostic\n${encoded}\n`); - expect(isRegistryPublicationDeferredError(decoded)).toBe(true); - expect(decoded).toMatchObject({ - reason: original.reason, - notBeforeEpochSeconds: original.notBeforeEpochSeconds, - context: original.context, - }); - }); - - test("rejects lookalikes, duplicate markers, noncanonical bytes, extra keys, and schemas", () => { - expect(() => encodeRegistryPublicationDeferral(Object.assign(new Error("lookalike"), { - reason: "deadline", - notBeforeEpochSeconds: 1_800_000_000, - }))).toThrow(/only a RegistryPublicationDeferredError/u); - expect(() => decodeRegistryPublicationDeferral("ordinary failure only")).toThrow(/exactly one/u); - - const valid = encodeRegistryPublicationDeferral(new RegistryPublicationDeferredError({ - reason: "deadline", - notBeforeEpochSeconds: 1_800_000_000, - context: "no upload started", - })); - expect(() => decodeRegistryPublicationDeferral(`${valid}\n${valid}\n`)).toThrow(/exactly one/u); - expect(() => decodeRegistryPublicationDeferral(`${REGISTRY_PUBLICATION_DEFERRAL_PREFIX}***\n`)).toThrow(/exactly one/u); - - for (const record of [ - { - schema: "oliphaunt-registry-publication-deferral-v1", - reason: "deadline", - notBeforeEpochSeconds: 1_800_000_000, - context: "no upload started", - extra: true, - }, - { - schema: "future-schema", - reason: "deadline", - notBeforeEpochSeconds: 1_800_000_000, - context: "no upload started", - }, - ]) { - const line = `${REGISTRY_PUBLICATION_DEFERRAL_PREFIX}${Buffer.from(JSON.stringify(record)).toString("base64url")}`; - expect(() => decodeRegistryPublicationDeferral(line)).toThrow(/keys must be exactly|schema must be/u); - } - }); - - test("types only a pre-mutation operation that cannot fit its reserved window", () => { - expect(requirePreMutationRegistryWindow({ - deadlineEpochSeconds: 1_100, - minimumMilliseconds: 30_000, - reserveMilliseconds: 5_000, - nowEpochMilliseconds: 1_000_000, - context: "npm publish for @example/package@1.0.0", - })).toBe(95_000); - - let observed; - try { - requirePreMutationRegistryWindow({ - deadlineEpochSeconds: 1_030, - minimumMilliseconds: 30_000, - reserveMilliseconds: 5_000, - nowEpochMilliseconds: 1_000_000, - context: "npm publish for @example/package@1.0.0", - }); - } catch (cause) { - observed = cause; - } - expect(isRegistryPublicationDeferredError(observed)).toBe(true); - expect(observed).toMatchObject({ - reason: "deadline", - notBeforeEpochSeconds: 1_001, - }); - expect(observed.context).toContain("requires 30s before its first remote mutation"); - }); -}); diff --git a/tools/release/registry-publication-deferral.test.mts b/tools/release/registry-publication-deferral.test.mts new file mode 100644 index 000000000..9e36346d4 --- /dev/null +++ b/tools/release/registry-publication-deferral.test.mts @@ -0,0 +1,107 @@ +import { describe, expect, test } from 'bun:test'; + +import { + decodeRegistryPublicationDeferral, + encodeRegistryPublicationDeferral, + isRegistryPublicationDeferredError, + requirePreMutationRegistryWindow, + RegistryPublicationDeferredError, + REGISTRY_PUBLICATION_DEFERRAL_PREFIX, +} from './registry-publication-deferral.mts'; + +describe('registry publication deferral child boundary', () => { + test('round-trips one canonical typed record embedded in ordinary stderr', () => { + const original = new RegistryPublicationDeferredError({ + reason: 'rate-limit', + notBeforeEpochSeconds: 1_800_000_000, + context: 'explicit crates.io 429 with valid Retry-After', + }); + const encoded = encodeRegistryPublicationDeferral(original); + expect(encoded).toStartWith(REGISTRY_PUBLICATION_DEFERRAL_PREFIX); + const decoded = decodeRegistryPublicationDeferral(`ordinary diagnostic\n${encoded}\n`); + expect(isRegistryPublicationDeferredError(decoded)).toBe(true); + expect(decoded).toMatchObject({ + reason: original.reason, + notBeforeEpochSeconds: original.notBeforeEpochSeconds, + context: original.context, + }); + }); + + test('rejects lookalikes, duplicate markers, noncanonical bytes, extra keys, and schemas', () => { + expect(() => + encodeRegistryPublicationDeferral( + Object.assign(new Error('lookalike'), { + reason: 'deadline', + notBeforeEpochSeconds: 1_800_000_000, + }), + ), + ).toThrow(/only a RegistryPublicationDeferredError/u); + expect(() => decodeRegistryPublicationDeferral('ordinary failure only')).toThrow( + /exactly one/u, + ); + + const valid = encodeRegistryPublicationDeferral( + new RegistryPublicationDeferredError({ + reason: 'deadline', + notBeforeEpochSeconds: 1_800_000_000, + context: 'no upload started', + }), + ); + expect(() => decodeRegistryPublicationDeferral(`${valid}\n${valid}\n`)).toThrow(/exactly one/u); + expect(() => + decodeRegistryPublicationDeferral(`${REGISTRY_PUBLICATION_DEFERRAL_PREFIX}***\n`), + ).toThrow(/exactly one/u); + + for (const record of [ + { + schema: 'oliphaunt-registry-publication-deferral-v1', + reason: 'deadline', + notBeforeEpochSeconds: 1_800_000_000, + context: 'no upload started', + extra: true, + }, + { + schema: 'future-schema', + reason: 'deadline', + notBeforeEpochSeconds: 1_800_000_000, + context: 'no upload started', + }, + ]) { + const line = `${REGISTRY_PUBLICATION_DEFERRAL_PREFIX}${Buffer.from(JSON.stringify(record)).toString('base64url')}`; + expect(() => decodeRegistryPublicationDeferral(line)).toThrow( + /keys must be exactly|schema must be/u, + ); + } + }); + + test('types only a pre-mutation operation that cannot fit its reserved window', () => { + expect( + requirePreMutationRegistryWindow({ + deadlineEpochSeconds: 1_100, + minimumMilliseconds: 30_000, + reserveMilliseconds: 5_000, + nowEpochMilliseconds: 1_000_000, + context: 'npm publish for @example/package@1.0.0', + }), + ).toBe(95_000); + + let observed; + try { + requirePreMutationRegistryWindow({ + deadlineEpochSeconds: 1_030, + minimumMilliseconds: 30_000, + reserveMilliseconds: 5_000, + nowEpochMilliseconds: 1_000_000, + context: 'npm publish for @example/package@1.0.0', + }); + } catch (cause) { + observed = cause; + } + expect(isRegistryPublicationDeferredError(observed)).toBe(true); + expect(observed).toMatchObject({ + reason: 'deadline', + notBeforeEpochSeconds: 1_001, + }); + expect(observed.context).toContain('requires 30s before its first remote mutation'); + }); +}); diff --git a/tools/release/release-artifact-targets.mjs b/tools/release/release-artifact-targets.mjs deleted file mode 100644 index 381c433f2..000000000 --- a/tools/release/release-artifact-targets.mjs +++ /dev/null @@ -1,1654 +0,0 @@ -import { existsSync, readFileSync } from "node:fs"; -import path from "node:path"; - -import { - PLATFORM_COMPATIBILITY_POLICY, - platformCompatibilityContract, -} from "./platform-compatibility-policy.mjs"; -import { - extensionNativeRegistryPackageStrings, - extensionWasixRegistryPackageStrings, -} from "./extension-registry-packages.mjs"; -import { loadContribCarriers } from "./contrib-carriers.mjs"; -import { - EXTENSION_TARGET_PROFILES_RELATIVE_PATH, - loadExtensionTargetProfiles, -} from "../../src/shared/extension-runtime-contract/extension-target-profiles.mjs"; -import { loadGraph } from "./release-graph.mjs"; - -export { PLATFORM_COMPATIBILITY_POLICY }; - -export const ROOT = path.resolve(import.meta.dir, "../.."); - -export const DESKTOP_TARGETS = { - "linux-arm64-gnu": { - triple: "aarch64-unknown-linux-gnu", - runner: "ubuntu-24.04-arm", - archive: "tar.gz", - npmOs: "linux", - npmCpu: "arm64", - npmLibc: "glibc", - liboliphauntNpmPackage: "@oliphaunt/liboliphaunt-linux-arm64-gnu", - liboliphauntToolsNpmPackage: "@oliphaunt/tools-linux-arm64-gnu", - brokerNpmPackage: "@oliphaunt/broker-linux-arm64-gnu", - nodePackage: "@oliphaunt/node-direct-linux-arm64-gnu", - wasixNapiPackage: "@oliphaunt/wasix-napi-linux-arm64-gnu", - wasixLlvmUrl: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-linux-aarch64.tar.xz", - wasixLlvmSha256: "1fddcf5b30f9d3e073eb161509220b4136ea8e2f114f23084bdec33e40fa87c1", - wasixLlvmBytes: 668873496, - }, - "linux-x64-gnu": { - triple: "x86_64-unknown-linux-gnu", - runner: "ubuntu-24.04", - archive: "tar.gz", - npmOs: "linux", - npmCpu: "x64", - npmLibc: "glibc", - liboliphauntNpmPackage: "@oliphaunt/liboliphaunt-linux-x64-gnu", - liboliphauntToolsNpmPackage: "@oliphaunt/tools-linux-x64-gnu", - brokerNpmPackage: "@oliphaunt/broker-linux-x64-gnu", - nodePackage: "@oliphaunt/node-direct-linux-x64-gnu", - wasixNapiPackage: "@oliphaunt/wasix-napi-linux-x64-gnu", - wasixLlvmUrl: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-linux-amd64.tar.xz", - wasixLlvmSha256: "5fb1c687c5e895d517a23e7aabea9ec3557e3a3e33f8a8d3a8d21395157b3906", - wasixLlvmBytes: 741670068, - }, - "macos-arm64": { - triple: "aarch64-apple-darwin", - runner: "macos-26", - archive: "tar.gz", - npmOs: "darwin", - npmCpu: "arm64", - liboliphauntNpmPackage: "@oliphaunt/liboliphaunt-darwin-arm64", - liboliphauntToolsNpmPackage: "@oliphaunt/tools-darwin-arm64", - brokerNpmPackage: "@oliphaunt/broker-darwin-arm64", - nodePackage: "@oliphaunt/node-direct-darwin-arm64", - wasixNapiPackage: "@oliphaunt/wasix-napi-darwin-arm64", - wasixLlvmUrl: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-darwin-aarch64.tar.xz", - wasixLlvmSha256: "f64460f6c8a28876737402542fc5b28bb1f4262cef85f799b65ce2a7ee6f8847", - wasixLlvmBytes: 479103872, - }, - "macos-x64": { - triple: "x86_64-apple-darwin", - runner: "macos-26", - archive: "tar.gz", - }, - "windows-x64-msvc": { - triple: "x86_64-pc-windows-msvc", - runner: "windows-2025-vs2026", - archive: "zip", - npmOs: "win32", - npmCpu: "x64", - liboliphauntNpmPackage: "@oliphaunt/liboliphaunt-win32-x64-msvc", - liboliphauntToolsNpmPackage: "@oliphaunt/tools-win32-x64-msvc", - brokerNpmPackage: "@oliphaunt/broker-win32-x64-msvc", - nodePackage: "@oliphaunt/node-direct-win32-x64-msvc", - wasixNapiPackage: "@oliphaunt/wasix-napi-win32-x64-msvc", - wasixLlvmUrl: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-windows-amd64.tar.xz", - wasixLlvmSha256: "19ff22b0cf74b53dad2fc717db2209f8162b768fc6dede9e2caa6a83c724496e", - wasixLlvmBytes: 757929860, - }, -}; - -export const MOBILE_TARGETS = { - "android-arm64-v8a": { - triple: "aarch64-linux-android", - runner: "ubuntu-24.04", - androidAbi: "arm64-v8a", - }, - "android-x86_64": { - triple: "x86_64-linux-android", - runner: "ubuntu-24.04", - androidAbi: "x86_64", - }, - "ios-xcframework": { - triple: "ios-xcframework", - runner: "macos-26", - }, -}; - -const NATIVE_RUNTIME_TARGETS = { ...DESKTOP_TARGETS, ...MOBILE_TARGETS }; -const RELEASE_HOST_TARGETS = Object.freeze([ - "linux-arm64-gnu", - "linux-x64-gnu", - "macos-arm64", - "windows-x64-msvc", -]); -const WASIX_TARGETS = new Set(["portable", ...RELEASE_HOST_TARGETS]); -const WASIX_POSTMASTER_TARGETS = new Set(RELEASE_HOST_TARGETS); -const BROKER_TARGETS = new Set(RELEASE_HOST_TARGETS); -const NODE_DIRECT_TARGETS = BROKER_TARGETS; -const WASIX_NAPI_TARGETS = BROKER_TARGETS; -const PRODUCT_PRESETS = { - "liboliphaunt-native": "liboliphaunt-native", - "liboliphaunt-wasix": "liboliphaunt-wasix", - "liboliphaunt-wasix-postmaster": "liboliphaunt-wasix-postmaster", - "oliphaunt-broker": "broker-helper", - "oliphaunt-node-direct": "node-direct-addon", - "oliphaunt-wasix-napi": "wasix-napi-addon", -}; -const EXTENSION_FAMILIES = new Set(["native", "wasix"]); -const EXTENSION_KINDS = new Set(["native-dynamic", "native-static-registry", "wasix-runtime"]); -const EXTENSION_VERSIONING_BY_CLASS = { - contrib: "runtime-bound", - external: "upstream-bound", - "first-party": "repo-bound", -}; -const EXTENSION_PRODUCT_KINDS = new Set(["exact-extension-artifact", "exact-extension-bundle"]); -const EXTENSION_CATALOG_PATH = path.join(ROOT, "src/extensions/generated/extensions.catalog.json"); - -const graphCache = new Map(); -let extensionCatalogRowsCache; -let contribCarriersCache; - -export function fail(prefix, message) { - console.error(`${prefix}: ${message}`); - process.exit(1); -} - -function requiredBinaryCompatibility(target, use, prefix) { - const contract = platformCompatibilityContract(target); - if (contract === undefined) { - fail(prefix, `${use} publishes ${target} without a platform compatibility contract`); - } - return contract; -} - -export function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -export function rel(file) { - const relative = path.relative(ROOT, file); - return relative.startsWith("..") ? file : relative.split(path.sep).join("/"); -} - -function graph(prefix) { - if (!graphCache.has(prefix)) { - graphCache.set(prefix, loadGraph(prefix)); - } - return graphCache.get(prefix); -} - -export function contribCarrierDescriptor(prefix = "release-artifact-targets.mjs") { - if (contribCarriersCache !== undefined) return contribCarriersCache; - let value; - try { - value = loadContribCarriers(ROOT, prefix); - } catch (error) { - fail(prefix, error instanceof Error ? error.message.replace(`${prefix}: `, "") : String(error)); - } - const descriptor = { - ...value, - sourcePath: value.source, - runtimeContract: value.contract, - }; - if (!descriptor.artifactProduct.startsWith("oliphaunt-extension-")) { - fail(prefix, "contrib logical_product must be an extension artifact product"); - } - for (const [family, owner] of [["native", descriptor.nativeOwner], ["wasix", descriptor.wasixOwner]]) { - if (graph(prefix).products[owner] === undefined) { - fail(prefix, `contrib ${family}_owner references unknown release product ${owner}`); - } - } - contribCarriersCache = Object.freeze(descriptor); - return contribCarriersCache; -} - -export function extensionReleaseProduct(product, family, prefix = "release-artifact-targets.mjs") { - if (!EXTENSION_FAMILIES.has(family)) { - fail(prefix, `extension carrier family must be native or wasix, got ${JSON.stringify(family)}`); - } - const contrib = contribCarrierDescriptor(prefix); - if (product === contrib.artifactProduct) { - return family === "native" ? contrib.nativeOwner : contrib.wasixOwner; - } - if (!exactExtensionProducts(prefix).includes(product)) { - fail(prefix, `${product} is not an exact-extension artifact product`); - } - return product; -} - -export function extensionReleaseVersion(product, family, prefix = "release-artifact-targets.mjs") { - return currentProductVersionSync(extensionReleaseProduct(product, family, prefix), prefix); -} - -export function extensionArtifactProductRoot( - product, - family = "native", - root = "target/extension-artifacts", - prefix = "release-artifact-targets.mjs", -) { - const releaseProduct = extensionReleaseProduct(product, family, prefix); - return path.join(root, ...(releaseProduct === product ? [product] : [releaseProduct, product])); -} - -export function extensionArtifactProductsForReleaseProducts( - releaseProducts, - { family = null, prefix = "release-artifact-targets.mjs" } = {}, -) { - if (!Array.isArray(releaseProducts) || releaseProducts.some((product) => typeof product !== "string" || !product)) { - fail(prefix, "release products must be a string list"); - } - if (family !== null && !EXTENSION_FAMILIES.has(family)) { - fail(prefix, `extension carrier family must be native or wasix, got ${JSON.stringify(family)}`); - } - const selected = new Set(releaseProducts); - const products = exactExtensionReleaseProducts(prefix).filter((product) => selected.has(product)); - const contrib = contribCarrierDescriptor(prefix); - const selectedOwner = family === "native" - ? selected.has(contrib.nativeOwner) - : family === "wasix" - ? selected.has(contrib.wasixOwner) - : selected.has(contrib.nativeOwner) || selected.has(contrib.wasixOwner); - if (selectedOwner) products.push(contrib.artifactProduct); - return [...new Set(products)].sort(compareText); -} - -function archiveAsset(productPrefix, target, archive) { - return `${productPrefix}-{version}-${target}.${archive}`; -} - -function assertStringList(value, label, prefix) { - if (!Array.isArray(value) || !value.every((item) => typeof item === "string" && item)) { - fail(prefix, `${label} must be a non-empty string list`); - } - return value; -} - -function artifactTargetConfig(product, expectedPreset, prefix) { - const release = releaseMetadata(product, prefix); - const config = release.artifactTargets; - if (typeof config !== "object" || config === null || Array.isArray(config)) { - fail(prefix, `Moon release metadata for ${product} must declare artifactTargets`); - } - if (config.preset !== expectedPreset) { - fail(prefix, `Moon release metadata for ${product} artifactTargets.preset must be ${expectedPreset}`); - } - return config; -} - -function productTargets(product, expectedPreset, knownTargets, prefix) { - const config = artifactTargetConfig(product, expectedPreset, prefix); - const targets = assertStringList(config.targets ?? [], `${product}.targets`, prefix); - const duplicates = [...new Set(targets.filter((target, index) => targets.indexOf(target) !== index))]; - if (duplicates.length > 0) { - fail(prefix, `Moon release metadata for ${product} artifactTargets.targets contains duplicates`); - } - const unknown = targets.filter((target) => !knownTargets.has(target)).sort(compareText); - if (unknown.length > 0) { - fail(prefix, `Moon release metadata for ${product} declares unknown artifact target(s): ${unknown.join(", ")}`); - } - return targets; -} - -function nativeLibraryRelativePath(target) { - if (target.startsWith("android-")) { - return `jni/${MOBILE_TARGETS[target].androidAbi}/liboliphaunt.so`; - } - if (target === "ios-xcframework") { - return "liboliphaunt.xcframework"; - } - if (target.startsWith("macos-")) { - return "lib/liboliphaunt.dylib"; - } - if (target.startsWith("linux-")) { - return "lib/liboliphaunt.so"; - } - if (target === "windows-x64-msvc") { - return "bin/oliphaunt.dll"; - } - fail("release-artifact-targets.mjs", `unsupported liboliphaunt native target ${target}`); -} - -function nativeSurfaces(target) { - if (target.startsWith("android-")) { - return ["github-release", "maven", "react-native-android"]; - } - if (target === "ios-xcframework") { - return ["github-release", "swiftpm", "react-native-ios"]; - } - return ["github-release", "rust-native-direct", "typescript-native-direct"]; -} - -export function liboliphauntNativeBuildRoot(target) { - if (!(target in NATIVE_RUNTIME_TARGETS)) { - fail("release-artifact-targets.mjs", `unknown liboliphaunt-native target ${target}`); - } - const roots = { - "macos-arm64": "target/liboliphaunt-pg18", - "android-arm64-v8a": "target/liboliphaunt-pg18-android-arm64", - "android-x86_64": "target/liboliphaunt-pg18-android-x86_64", - "ios-xcframework": "target/liboliphaunt-ios-xcframework", - }; - return roots[target] ?? `target/liboliphaunt-pg18-${target}`; -} - -export function liboliphauntNativeCiArtifactRoot(target) { - if (!(target in NATIVE_RUNTIME_TARGETS)) { - fail("release-artifact-targets.mjs", `unknown liboliphaunt-native target ${target}`); - } - return `target/liboliphaunt-native-ci/${target}`; -} - -export function liboliphauntAndroidAbi(target) { - const abi = MOBILE_TARGETS[target]?.androidAbi; - if (!abi) { - fail("release-artifact-targets.mjs", `unsupported React Native Android runtime target ${target}`); - } - return abi; -} - -function liboliphauntNativeRows(prefix) { - const product = "liboliphaunt-native"; - const targets = new Set( - productTargets(product, PRODUCT_PRESETS[product], new Set(Object.keys(NATIVE_RUNTIME_TARGETS)), prefix), - ); - const rows = []; - for (const target of [...targets].sort(compareText)) { - const platform = NATIVE_RUNTIME_TARGETS[target]; - const row = { - id: `${product}.${target}`, - product, - kind: "native-runtime", - target, - triple: platform.triple, - runner: platform.runner, - asset: archiveAsset("liboliphaunt", target, platform.archive ?? "tar.gz"), - library_relative_path: nativeLibraryRelativePath(target), - npm_package: platform.liboliphauntNpmPackage, - npm_os: platform.npmOs, - npm_cpu: platform.npmCpu, - npm_libc: platform.npmLibc, - surfaces: nativeSurfaces(target), - binary_compatibility: requiredBinaryCompatibility(target, `${product} native runtime`, prefix), - _source_file: "Moon release metadata", - }; - rows.push(row); - } - rows.push( - { - id: `${product}.apple-spm-xcframework`, - product, - kind: "apple-swiftpm-binary", - target: "apple-spm-xcframework", - triple: "apple-xcframework", - runner: "macos-26", - asset: "liboliphaunt-{version}-apple-spm-xcframework.zip", - surfaces: ["github-release", "swiftpm"], - _source_file: "Moon release metadata", - }, - { - id: `${product}.runtime-resources-ios-datum64`, - product, - kind: "runtime-resources", - target: "ios-datum64", - asset: "liboliphaunt-{version}-runtime-resources-ios-datum64.tar.gz", - surfaces: ["github-release", "react-native-ios"], - _source_file: "Moon release metadata", - }, - { - id: `${product}.runtime-resources-android-datum64`, - product, - kind: "runtime-resources", - target: "android-datum64", - asset: "liboliphaunt-{version}-runtime-resources-android-datum64.tar.gz", - surfaces: ["github-release", "maven", "react-native-android"], - _source_file: "Moon release metadata", - }, - { - id: `${product}.icu-data`, - product, - kind: "icu-data", - target: "portable", - asset: "liboliphaunt-{version}-icu-data.tar.gz", - npm_package: "@oliphaunt/icu", - surfaces: [ - "github-release", - "rust-native-direct", - "typescript-native-direct", - "swiftpm", - "maven", - "react-native-ios", - "react-native-android", - ], - _source_file: "Moon release metadata", - }, - { - id: `${product}.checksums`, - product, - kind: "checksums", - target: "portable", - asset: "liboliphaunt-{version}-release-assets.sha256", - surfaces: ["github-release"], - _source_file: "Moon release metadata", - }, - ); - for (const target of [...targets].filter((item) => item in DESKTOP_TARGETS).sort(compareText)) { - const platform = DESKTOP_TARGETS[target]; - rows.push({ - id: `${product}.tools-${target}`, - product, - kind: "native-tools", - target, - triple: platform.triple, - runner: platform.runner, - asset: archiveAsset("oliphaunt-tools", target, platform.archive), - npm_package: platform.liboliphauntToolsNpmPackage, - npm_os: platform.npmOs, - npm_cpu: platform.npmCpu, - npm_libc: platform.npmLibc, - surfaces: ["github-release", "rust-native-direct", "typescript-native-direct"], - binary_compatibility: requiredBinaryCompatibility( - target, - `${product} native tools`, - prefix, - ), - _source_file: "Moon release metadata", - }); - } - return rows; -} - -function liboliphauntWasixRows(prefix) { - const product = "liboliphaunt-wasix"; - const targets = new Set(productTargets(product, PRODUCT_PRESETS[product], WASIX_TARGETS, prefix)); - if (!targets.has("portable")) { - fail(prefix, `Moon release metadata for ${product} must include the portable runtime target`); - } - const rows = [ - { - id: `${product}.runtime-portable`, - product, - kind: "wasix-runtime", - target: "portable", - asset: "liboliphaunt-wasix-{version}-runtime-portable.tar.zst", - surfaces: ["github-release"], - _source_file: "Moon release metadata", - }, - { - id: `${product}.icu-data`, - product, - kind: "icu-data", - target: "portable", - asset: "liboliphaunt-wasix-{version}-icu-data.tar.zst", - surfaces: ["github-release"], - _source_file: "Moon release metadata", - }, - ]; - for (const target of [...targets].filter((item) => item !== "portable").sort(compareText)) { - const platform = DESKTOP_TARGETS[target]; - rows.push({ - id: `${product}.aot-${target}`, - product, - kind: "wasix-aot-runtime", - target, - triple: platform.triple, - runner: platform.runner, - llvm_url: platform.wasixLlvmUrl, - llvm_sha256: platform.wasixLlvmSha256, - llvm_bytes: platform.wasixLlvmBytes, - asset: `liboliphaunt-wasix-{version}-runtime-aot-${target}.tar.zst`, - surfaces: ["github-release"], - _source_file: "Moon release metadata", - }); - } - rows.push({ - id: `${product}.checksums`, - product, - kind: "checksums", - target: "portable", - asset: "liboliphaunt-wasix-{version}-release-assets.sha256", - surfaces: ["github-release"], - _source_file: "Moon release metadata", - }); - return rows; -} - -function liboliphauntWasixPostmasterRows(prefix) { - const product = "liboliphaunt-wasix-postmaster"; - const rows = []; - for (const target of productTargets( - product, - PRODUCT_PRESETS[product], - WASIX_POSTMASTER_TARGETS, - prefix, - ).sort(compareText)) { - const platform = DESKTOP_TARGETS[target]; - rows.push({ - id: `${product}.${target}`, - product, - kind: "wasix-postmaster-runtime", - target, - triple: platform.triple, - runner: platform.runner, - llvm_url: platform.wasixLlvmUrl, - llvm_sha256: platform.wasixLlvmSha256, - llvm_bytes: platform.wasixLlvmBytes, - asset: `${product}-{version}-${target}.tar.zst`, - surfaces: ["github-release"], - binary_compatibility: requiredBinaryCompatibility( - target, - `${product} runtime`, - prefix, - ), - extension_artifacts: false, - _source_file: "Moon release metadata", - }); - } - rows.push({ - id: `${product}.checksums`, - product, - kind: "checksums", - target: "portable", - asset: `${product}-{version}-release-assets.sha256`, - surfaces: ["github-release"], - extension_artifacts: false, - _source_file: "Moon release metadata", - }); - return rows; -} - -function brokerRows(prefix) { - const product = "oliphaunt-broker"; - const rows = []; - for (const target of productTargets(product, PRODUCT_PRESETS[product], BROKER_TARGETS, prefix).sort(compareText)) { - const platform = DESKTOP_TARGETS[target]; - rows.push({ - id: `${product}.${target}`, - product, - kind: "broker-helper", - target, - triple: platform.triple, - runner: platform.runner, - asset: archiveAsset(product, target, platform.archive), - executable_relative_path: target === "windows-x64-msvc" ? "bin/oliphaunt-broker.exe" : "bin/oliphaunt-broker", - npm_package: platform.brokerNpmPackage, - npm_os: platform.npmOs, - npm_cpu: platform.npmCpu, - npm_libc: platform.npmLibc, - surfaces: ["github-release", "rust-broker", "typescript-broker"], - binary_compatibility: requiredBinaryCompatibility(target, `${product} broker`, prefix), - _source_file: "Moon release metadata", - }); - } - rows.push({ - id: `${product}.checksums`, - product, - kind: "checksums", - target: "portable", - asset: "oliphaunt-broker-{version}-release-assets.sha256", - surfaces: ["github-release", "rust-broker", "typescript-broker"], - _source_file: "Moon release metadata", - }); - return rows; -} - -function nodeDirectRows(prefix) { - const product = "oliphaunt-node-direct"; - const rows = []; - for (const target of productTargets(product, PRODUCT_PRESETS[product], NODE_DIRECT_TARGETS, prefix).sort(compareText)) { - const platform = DESKTOP_TARGETS[target]; - rows.push({ - id: `${product}.${target}`, - product, - kind: "node-direct-addon", - target, - triple: platform.triple, - runner: platform.runner, - asset: archiveAsset(product, target, platform.archive), - library_relative_path: "oliphaunt_node.node", - npm_package: platform.nodePackage, - npm_os: platform.npmOs, - npm_cpu: platform.npmCpu, - npm_libc: platform.npmLibc, - surfaces: ["github-release", "npm-optional"], - binary_compatibility: requiredBinaryCompatibility(target, `${product} Node addon`, prefix), - _source_file: "Moon release metadata", - }); - } - rows.push({ - id: `${product}.checksums`, - product, - kind: "checksums", - target: "portable", - asset: "oliphaunt-node-direct-{version}-release-assets.sha256", - surfaces: ["github-release"], - _source_file: "Moon release metadata", - }); - return rows; -} - -function wasixNapiRows(prefix) { - const product = "oliphaunt-wasix-napi"; - const rows = []; - for (const target of productTargets(product, PRODUCT_PRESETS[product], WASIX_NAPI_TARGETS, prefix).sort(compareText)) { - const platform = DESKTOP_TARGETS[target]; - rows.push({ - id: `${product}.${target}`, - product, - kind: "wasix-napi-addon", - target, - triple: platform.triple, - runner: platform.runner, - asset: archiveAsset(product, target, platform.archive), - library_relative_path: "oliphaunt_wasix_napi.node", - npm_package: platform.wasixNapiPackage, - npm_os: platform.npmOs, - npm_cpu: platform.npmCpu, - npm_libc: platform.npmLibc, - surfaces: ["github-release", "npm-optional"], - binary_compatibility: requiredBinaryCompatibility(target, `${product} Node-API addon`, prefix), - extension_artifacts: false, - _source_file: "Moon release metadata", - }); - } - rows.push({ - id: `${product}.checksums`, - product, - kind: "checksums", - target: "portable", - asset: "oliphaunt-wasix-napi-{version}-release-assets.sha256", - surfaces: ["github-release"], - extension_artifacts: false, - _source_file: "Moon release metadata", - }); - return rows; -} - -export function rawArtifactTargetRows(prefix = "release-artifact-targets.mjs") { - return [ - ...liboliphauntNativeRows(prefix), - ...liboliphauntWasixRows(prefix), - ...liboliphauntWasixPostmasterRows(prefix), - ...brokerRows(prefix), - ...nodeDirectRows(prefix), - ...wasixNapiRows(prefix), - ]; -} - -function stringField(row, key, id, required, prefix) { - const value = row[key]; - if (typeof value === "string" && value.length > 0) { - return value; - } - if (required) { - fail(prefix, `artifact target ${id}.${key} must be a non-empty string`); - } - if (value !== undefined && value !== null) { - fail(prefix, `artifact target ${id}.${key} must be a string`); - } - return undefined; -} - -function positiveIntegerField(row, key, id, required, prefix) { - const value = row[key]; - if (Number.isSafeInteger(value) && value > 0) return value; - if (required || (value !== undefined && value !== null)) { - fail(prefix, `artifact target ${id}.${key} must be a positive safe integer`); - } - return undefined; -} - -function normalizeArtifactTarget(row, prefix) { - const id = stringField(row, "id", "", true, prefix); - const libraryRelativePath = stringField(row, "library_relative_path", id, false, prefix); - const executableRelativePath = stringField(row, "executable_relative_path", id, false, prefix); - const npmPackage = stringField(row, "npm_package", id, false, prefix); - const npmOs = stringField(row, "npm_os", id, false, prefix); - const npmCpu = stringField(row, "npm_cpu", id, false, prefix); - const npmLibc = stringField(row, "npm_libc", id, false, prefix); - const llvmUrl = stringField(row, "llvm_url", id, false, prefix); - const llvmSha256 = stringField(row, "llvm_sha256", id, false, prefix); - const llvmBytes = positiveIntegerField(row, "llvm_bytes", id, false, prefix); - const sourceFile = - stringField(row, "_source_file", id, false, prefix) ?? - stringField(row, "source_file", id, false, prefix); - const unsupportedReason = stringField(row, "unsupported_reason", id, false, prefix); - const binaryCompatibility = row.binary_compatibility; - if ( - binaryCompatibility !== undefined && - (binaryCompatibility === null || - typeof binaryCompatibility !== "object" || - Array.isArray(binaryCompatibility)) - ) { - fail(prefix, `artifact target ${id}.binary_compatibility must be an object`); - } - const target = { - id, - product: stringField(row, "product", id, true, prefix), - kind: stringField(row, "kind", id, true, prefix), - target: stringField(row, "target", id, true, prefix), - asset: stringField(row, "asset", id, true, prefix), - surfaces: assertStringList(row.surfaces, `${id}.surfaces`, prefix), - triple: stringField(row, "triple", id, false, prefix), - runner: stringField(row, "runner", id, false, prefix), - libraryRelativePath, - executableRelativePath, - npmPackage, - npmOs, - npmCpu, - npmLibc, - llvmUrl, - llvmSha256, - llvmBytes, - binaryCompatibility, - extensionArtifacts: row.extension_artifacts ?? true, - sourceFile, - tier: stringField(row, "tier", id, false, prefix), - unsupportedReason, - library_relative_path: libraryRelativePath, - executable_relative_path: executableRelativePath, - npm_package: npmPackage, - npm_os: npmOs, - npm_cpu: npmCpu, - npm_libc: npmLibc, - llvm_url: llvmUrl, - llvm_sha256: llvmSha256, - llvm_bytes: llvmBytes, - binary_compatibility: binaryCompatibility, - extension_artifacts: row.extension_artifacts ?? true, - source_file: sourceFile, - unsupported_reason: unsupportedReason, - }; - if (typeof target.extensionArtifacts !== "boolean") { - fail(prefix, `artifact target ${id}.extension_artifacts must be true or false`); - } - return target; -} - -export function allArtifactTargets( - { - product = undefined, - kind = undefined, - surface = undefined, - } = {}, - prefix = "release-artifact-targets.mjs", -) { - const products = graph(prefix).products; - const seen = new Set(); - return rawArtifactTargetRows(prefix) - .map((row) => normalizeArtifactTarget(row, prefix)) - .filter((target) => { - if (seen.has(target.id)) { - fail(prefix, `duplicate artifact target id ${target.id}`); - } - seen.add(target.id); - if (!products[target.product]) { - fail(prefix, `artifact target ${target.id} references unknown product ${target.product}`); - } - if (product !== undefined && target.product !== product) { - return false; - } - if (kind !== undefined && target.kind !== kind) { - return false; - } - if (surface !== undefined && !target.surfaces.includes(surface)) { - return false; - } - return true; - }); -} - -export function typescriptOptionalRuntimePackageProducts(prefix = "release-artifact-targets.mjs") { - const selected = allArtifactTargets({}, prefix).filter((target) => { - if (target.product === "oliphaunt-broker" && target.kind === "broker-helper") { - return target.surfaces.includes("typescript-broker"); - } - if (target.product === "liboliphaunt-native" && target.kind === "native-runtime") { - return target.surfaces.includes("typescript-native-direct"); - } - if (target.product === "oliphaunt-node-direct" && target.kind === "node-direct-addon") { - return target.surfaces.includes("npm-optional"); - } - return false; - }); - if (selected.length === 0) { - fail(prefix, "no TypeScript optional runtime package targets found"); - } - const rows = []; - const seen = new Set(); - for (const target of selected) { - if (typeof target.npmPackage !== "string" || !target.npmPackage) { - fail(prefix, `${target.id} must declare npmPackage for TypeScript optional dependencies`); - } - if (seen.has(target.npmPackage)) { - fail(prefix, `duplicate TypeScript optional package target ${target.npmPackage}`); - } - seen.add(target.npmPackage); - rows.push({ - packageName: target.npmPackage, - product: target.product, - target: target.target, - kind: target.kind, - artifactTarget: target.id, - }); - } - return rows.sort((left, right) => compareText(left.packageName, right.packageName)); -} - -export function nativeToolsOptionalPackageProducts(prefix = "release-artifact-targets.mjs") { - const selected = allArtifactTargets( - { product: "liboliphaunt-native", kind: "native-tools" }, - prefix, - ); - if (selected.length === 0) { - fail(prefix, "no native tools optional package targets found"); - } - return selected - .map((target) => { - if (typeof target.npmPackage !== "string" || !target.npmPackage) { - fail(prefix, `${target.id} must declare npmPackage for the native tools facade`); - } - return { - packageName: target.npmPackage, - product: target.product, - target: target.target, - kind: target.kind, - artifactTarget: target.id, - }; - }) - .sort((left, right) => compareText(left.packageName, right.packageName)); -} - -export function artifactTargets(product, kind, prefix) { - return allArtifactTargets({ product, kind }, prefix); -} - -function ciArtifactRows({ product, kind, surface, family, name }, prefix) { - const targets = allArtifactTargets({ product, kind, surface }, prefix); - if (targets.length === 0) { - fail(prefix, `${product} has no ${kind} CI ${family} artifact targets`); - } - return targets - .map((target) => ({ - family, - product, - target: target.target, - kind: target.kind, - artifactTarget: target.id, - artifactName: name(target), - })) - .sort((left, right) => compareText(left.artifactName, right.artifactName)); -} - -export function ciReleaseAssetArtifactRows(product, kind, prefix = "release-artifact-targets.mjs") { - return ciArtifactRows({ - product, - kind, - surface: "github-release", - family: "release-assets", - name: (target) => `${product}-release-assets-${target.target}`, - }, prefix); -} - -export function ciNpmPackageArtifactRows(product, kind, prefix = "release-artifact-targets.mjs") { - return ciArtifactRows({ - product, - kind, - surface: "npm-optional", - family: "npm-package", - name: (target) => `${product}-npm-package-${target.target}`, - }, prefix); -} - -export function expectedAssetRows( - { - product, - version, - surface = "github-release", - kinds = undefined, - } = {}, - prefix = "release-artifact-targets.mjs", -) { - if (typeof product !== "string" || product.length === 0) { - fail(prefix, "expected asset rows require a product"); - } - if (typeof version !== "string" || version.length === 0) { - fail(prefix, "expected asset rows require a version"); - } - const kindSet = kinds === undefined ? undefined : new Set(kinds); - if ( - kindSet !== undefined - && (kindSet.size === 0 || [...kindSet].some((kind) => typeof kind !== "string" || kind.length === 0)) - ) { - fail(prefix, "expected asset row kinds must be a non-empty string list"); - } - const rows = allArtifactTargets({ product, surface }, prefix) - .filter((target) => kindSet === undefined || kindSet.has(target.kind)) - .map((target) => ({ - product: target.product, - kind: target.kind, - target: target.target, - surface, - artifactTarget: target.id, - assetName: target.asset.replaceAll("{version}", version), - })) - .sort((left, right) => compareText(left.assetName, right.assetName)); - if (rows.length === 0) { - fail(prefix, `${product} has no artifact targets for surface ${surface}`); - } - const names = rows.map((row) => row.assetName); - const duplicates = [...new Set(names.filter((name, index) => names.indexOf(name) !== index))].sort(compareText); - if (duplicates.length > 0) { - fail(prefix, `${product} has duplicate expected asset names: ${duplicates.join(", ")}`); - } - return rows; -} - -export function registryPackageRows( - { - product, - packageKind = undefined, - } = {}, - prefix = "release-artifact-targets.mjs", -) { - if (typeof product !== "string" || product.length === 0) { - fail(prefix, "registry package rows require a product"); - } - if ( - packageKind !== undefined - && (typeof packageKind !== "string" || packageKind.length === 0) - ) { - fail(prefix, "registry package kind must be a non-empty string"); - } - const config = productConfig(product, prefix); - const declaredEntries = config.registry_packages ?? []; - if (!Array.isArray(declaredEntries) || declaredEntries.some((entry) => typeof entry !== "string")) { - fail(prefix, `${product}.registry_packages must be a string list`); - } - const entries = [...declaredEntries]; - const contrib = contribCarrierDescriptor(prefix); - if (product === contrib.nativeOwner || product === contrib.wasixOwner) { - const targets = extensionRegistryPackageTargetSets(contrib.artifactProduct, prefix); - if (product === contrib.nativeOwner) { - entries.push(...extensionNativeRegistryPackageStrings({ - product: contrib.artifactProduct, - androidTargets: targets.androidTargets, - npmTargets: targets.npmTargets, - nativeCargoTargets: targets.nativeCargoTargets, - })); - } - if (product === contrib.wasixOwner) { - entries.push(...extensionWasixRegistryPackageStrings({ - product: contrib.artifactProduct, - includeAot: targets.includeWasixAot, - })); - } - } - const rows = []; - const seen = new Set(); - for (const raw of entries) { - const separator = raw.indexOf(":"); - if (separator <= 0 || separator === raw.length - 1) { - fail(prefix, `${product}.registry_packages entry ${JSON.stringify(raw)} must use kind:name`); - } - const kind = raw.slice(0, separator); - const packageName = raw.slice(separator + 1); - const key = `${kind}\0${packageName}`; - if (seen.has(key)) { - fail(prefix, `${product} declares duplicate ${kind} registry package ${packageName}`); - } - seen.add(key); - if (packageKind !== undefined && kind !== packageKind) { - continue; - } - rows.push({ - product, - packageKind: kind, - packageName, - raw, - }); - } - return rows.sort((left, right) => - compareText(left.packageKind, right.packageKind) - || compareText(left.packageName, right.packageName) - ); -} - -export function releaseMetadata(product, prefix) { - const release = graph(prefix).moon_projects?.[product]?.config?.project?.metadata?.release; - if (!release) { - fail(prefix, `Moon release metadata does not include ${product}`); - } - if (release.component !== product) { - fail(prefix, `Moon release metadata for ${product} must use matching component`); - } - if (typeof release.packagePath !== "string" || !release.packagePath) { - fail(prefix, `Moon release metadata for ${product} must declare packagePath`); - } - const expectedPreset = PRODUCT_PRESETS[product]; - if (expectedPreset !== undefined) { - const artifactTargets = release.artifactTargets; - if ( - typeof artifactTargets !== "object" || - artifactTargets === null || - artifactTargets.preset !== expectedPreset - ) { - fail(prefix, `Moon release metadata for ${product} must use artifactTargets preset ${expectedPreset}`); - } - } - return release; -} - -function parseCargoVersion(text, file, prefix) { - let inPackage = false; - for (const rawLine of text.split(/\r?\n/u)) { - const line = rawLine.trim(); - if (line === "[package]") { - inPackage = true; - continue; - } - if (inPackage && line.startsWith("[")) { - break; - } - if (!inPackage) { - continue; - } - const match = line.match(/^version\s*=\s*"([^"]+)"/u); - if (match) { - return match[1]; - } - } - fail(prefix, `${rel(file)} does not define a package version`); -} - -const versionCache = new Map(); - -export function currentProductVersionSync(product, prefix = "release-artifact-targets.mjs") { - const key = `${prefix}\0${product}`; - if (!versionCache.has(key)) { - const versionFile = productConfig(product, prefix).version_files?.[0]; - if (typeof versionFile !== "string" || !versionFile) { - fail(prefix, `${product} does not declare a canonical version file`); - } - const file = path.join(ROOT, versionFile); - const text = readFileSync(file, "utf8"); - const name = path.basename(file); - let version = ""; - if (name === "Cargo.toml") { - version = parseCargoVersion(text, file, prefix); - } else if (name === "package.json") { - const data = JSON.parse(text); - version = typeof data.version === "string" ? data.version : ""; - } else if (name === "gradle.properties") { - for (const rawLine of text.split(/\r?\n/u)) { - const line = rawLine.trim(); - if (!line || line.startsWith("#") || !line.includes("=")) { - continue; - } - const [property, ...rest] = line.split("="); - if (property.trim() === "VERSION_NAME") { - version = rest.join("=").trim(); - break; - } - } - } else if (name === "VERSION" || name === "LIBOLIPHAUNT_VERSION") { - version = text.trim(); - } else { - fail(prefix, `${product}.version_files has unsupported version file type: ${versionFile}`); - } - if (!version) { - fail(prefix, `${versionFile} does not define a release version for ${product}`); - } - versionCache.set(key, version); - } - return versionCache.get(key); -} - -export async function currentProductVersion(product, prefix = "release-artifact-targets.mjs") { - return currentProductVersionSync(product, prefix); -} - -export function expectedAssets(product, kind, version, prefix) { - const assets = expectedAssetRows({ product, version, kinds: [kind] }, prefix) - .map((row) => row.assetName); - assets.push(`${product}-${version}-release-assets.sha256`); - return assets.sort(compareText); -} - -function productConfig(product, prefix) { - const config = graph(prefix).products[product]; - if (!config) { - fail(prefix, `unknown release product ${product}`); - } - return config; -} - -export function exactExtensionProducts(prefix = "release-artifact-targets.mjs") { - const products = Object.entries(graph(prefix).products) - .filter(([, config]) => EXTENSION_PRODUCT_KINDS.has(config.kind)) - .map(([product]) => product); - products.push(contribCarrierDescriptor(prefix).artifactProduct); - return [...new Set(products)].sort(compareText); -} - -export function exactExtensionReleaseProducts(prefix = "release-artifact-targets.mjs") { - return Object.entries(graph(prefix).products) - .filter(([, config]) => EXTENSION_PRODUCT_KINDS.has(config.kind)) - .map(([product]) => product) - .sort(compareText); -} - -export function sdkPackageProducts(prefix = "release-artifact-targets.mjs") { - const rows = Object.entries(graph(prefix).products) - .filter(([, config]) => config.kind === "sdk") - .map(([product]) => ({ - product, - artifactName: product === "oliphaunt-wasix-rust" - ? `${product}-package-artifacts` - : `${product}-sdk-package-artifacts`, - })) - .sort((left, right) => compareText(left.product, right.product)); - if (rows.length === 0) { - fail(prefix, "release graph contains no SDK package products"); - } - return rows; -} - -export function extensionSqlName(product, prefix = "release-artifact-targets.mjs") { - const names = extensionSqlNames(product, prefix); - if (names.length !== 1) { - fail(prefix, `${product} owns ${names.length} exact extension members; use extensionSqlNames(product)`); - } - return names[0]; -} - -function contribMemberRows(product, prefix) { - const descriptor = contribCarrierDescriptor(prefix); - if (product !== descriptor.artifactProduct) { - fail(prefix, `${product} is not the shared PostgreSQL contrib artifact product`); - } - const manifestPath = descriptor.memberManifest; - const memberRoot = path.posix.dirname(manifestPath); - const rows = []; - const seenSqlNames = new Set(); - const seenIds = new Set(); - for (const [index, row] of descriptor.members.entries()) { - if (row === null || Array.isArray(row) || typeof row !== "object") { - fail(prefix, `${manifestPath}.extensions[${index}] must be a table`); - } - const id = nonEmptyString(row.id, `${manifestPath}.extensions[${index}].id`, prefix); - const sqlName = nonEmptyString(row["sql-name"], `${manifestPath}.extensions[${index}].sql-name`, prefix); - if (seenIds.has(id) || seenSqlNames.has(sqlName)) { - fail(prefix, `${manifestPath} contains duplicate contrib member id or SQL name: ${id}/${sqlName}`); - } - seenIds.add(id); - seenSqlNames.add(sqlName); - rows.push({ id, sqlName, path: memberRoot }); - } - return rows; -} - -export function extensionSqlNames(product, prefix = "release-artifact-targets.mjs") { - const contrib = contribCarrierDescriptor(prefix); - if (product === contrib.artifactProduct) { - return contribMemberRows(product, prefix).map((row) => row.sqlName).sort(compareText); - } - const config = productConfig(product, prefix); - if (config.kind === "exact-extension-artifact") { - const value = config.extension_sql_name; - if (typeof value !== "string" || !value) { - fail(prefix, `${product} release.toml must declare extension_sql_name`); - } - if (config.extension_sql_names !== undefined) { - fail(prefix, `${product} singleton release metadata must not declare extension_sql_names`); - } - return [value]; - } - if (config.kind !== "exact-extension-bundle") { - fail(prefix, `${product} is not an exact-extension product`); - } - const values = config.extension_sql_names; - if (!Array.isArray(values) || values.length < 2 || values.some((value) => typeof value !== "string" || !value)) { - fail(prefix, `${product} exact-extension bundle must declare at least two extension_sql_names`); - } - const sorted = [...values].sort(compareText); - if (new Set(sorted).size !== sorted.length || JSON.stringify(values) !== JSON.stringify(sorted)) { - fail(prefix, `${product}.extension_sql_names must be unique and sorted`); - } - const manifestNames = contribMemberRows(product, prefix).map((row) => row.sqlName).sort(compareText); - if (JSON.stringify(sorted) !== JSON.stringify(manifestNames)) { - fail(prefix, `${product}.extension_sql_names must exactly match ${config.extension.member_manifest}`); - } - return sorted; -} - -function extensionCatalogRows(prefix) { - if (extensionCatalogRowsCache !== undefined) return extensionCatalogRowsCache; - let catalog; - try { - catalog = JSON.parse(readFileSync(EXTENSION_CATALOG_PATH, "utf8")); - } catch (error) { - fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} is not readable JSON: ${error.message}`); - } - if (catalog?.["format-version"] !== 1 || !Array.isArray(catalog.extensions)) { - fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} must use format-version 1 and define extension rows`); - } - const bySqlName = new Map(); - for (const [index, row] of catalog.extensions.entries()) { - const sqlName = row?.["sql-name"]; - if (typeof sqlName !== "string" || !sqlName) { - fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} extension row ${index} has no SQL name`); - } - if (bySqlName.has(sqlName)) { - fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} repeats SQL extension ${sqlName}`); - } - const moduleFile = row["native-module-file"]; - if (moduleFile !== undefined && (typeof moduleFile !== "string" || !moduleFile)) { - fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} ${sqlName}.native-module-file must be a non-empty string when present`); - } - bySqlName.set(sqlName, row); - } - extensionCatalogRowsCache = bySqlName; - return extensionCatalogRowsCache; -} - -export function extensionPublicDependencySqlNames( - sqlName, - prefix = "release-artifact-targets.mjs", -) { - nonEmptyString(sqlName, "extension SQL name", prefix); - const rows = extensionCatalogRows(prefix); - const row = rows.get(sqlName); - if (row === undefined) { - fail(prefix, `${sqlName} is absent from ${rel(EXTENSION_CATALOG_PATH)}`); - } - const dependencies = row.dependencies ?? []; - if (!Array.isArray(dependencies) || dependencies.some((value) => typeof value !== "string" || !value)) { - fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} ${sqlName}.dependencies must be an array of SQL names`); - } - return [...new Set(dependencies.filter((dependency) => rows.has(dependency)))].sort(compareText); -} - -export function extensionWasixAotMemberSqlNames(product, prefix = "release-artifact-targets.mjs") { - const rows = extensionCatalogRows(prefix); - return extensionSqlNames(product, prefix).filter((sqlName) => { - const row = rows.get(sqlName); - if (row === undefined) { - fail(prefix, `${product} member ${sqlName} is absent from ${rel(EXTENSION_CATALOG_PATH)}`); - } - return typeof row["native-module-file"] === "string"; - }); -} - -export function extensionProductForSqlName(sqlName, prefix = "release-artifact-targets.mjs") { - nonEmptyString(sqlName, "extension SQL name", prefix); - const owners = exactExtensionProducts(prefix).filter((product) => extensionSqlNames(product, prefix).includes(sqlName)); - if (owners.length !== 1) { - fail(prefix, `extension SQL name ${JSON.stringify(sqlName)} must have exactly one release product owner, found ${owners.join(", ") || "none"}`); - } - return owners[0]; -} - -export function extensionReleaseProductForSqlName( - sqlName, - family = "native", - prefix = "release-artifact-targets.mjs", -) { - return extensionReleaseProduct(extensionProductForSqlName(sqlName, prefix), family, prefix); -} - -export function extensionMemberPath(product, sqlName, prefix = "release-artifact-targets.mjs") { - if (!extensionSqlNames(product, prefix).includes(sqlName)) { - fail(prefix, `${product} does not own extension SQL name ${JSON.stringify(sqlName)}`); - } - const contrib = contribCarrierDescriptor(prefix); - if (product === contrib.artifactProduct) { - const row = contribMemberRows(product, prefix).find((candidate) => candidate.sqlName === sqlName); - if (row === undefined) { - fail(prefix, `${product} member manifest has no row for ${JSON.stringify(sqlName)}`); - } - return releaseMetadataRelativePath(row.path, `${product} member ${sqlName}`, prefix); - } - const config = productConfig(product, prefix); - if (config.kind === "exact-extension-artifact") { - return packagePath(product, prefix); - } - fail(prefix, `${product} exact-extension bundle has no shared member descriptor`); -} - -function releaseMetadataRelativePath(value, context, prefix) { - const candidate = path.normalize(value).split(path.sep).join("/"); - if (path.isAbsolute(value) || candidate.split("/").includes("..")) { - fail(prefix, `${context} must be a repository-relative path: ${JSON.stringify(value)}`); - } - if (!existsSync(path.join(ROOT, candidate))) { - fail(prefix, `${context} path does not exist: ${candidate}`); - } - return candidate; -} - -function packagePath(product, prefix) { - return releaseMetadataRelativePath( - nonEmptyString(productConfig(product, prefix).path, `${product}.path`, prefix), - `${product}.path`, - prefix, - ); -} - -export function extensionMetadata(product, prefix = "release-artifact-targets.mjs") { - const contrib = contribCarrierDescriptor(prefix); - if (product === contrib.artifactProduct) { - const source = Bun.TOML.parse(readFileSync(path.join(ROOT, contrib.sourcePath), "utf8")); - const postgresVersion = nonEmptyString( - source?.postgresql?.version, - `${contrib.sourcePath}.postgresql.version`, - prefix, - ); - const postgresMajor = postgresVersion.split(".")[0]; - if (!/^[1-9][0-9]*$/u.test(postgresMajor)) { - fail(prefix, `${contrib.sourcePath}.postgresql.version must begin with a stable major version`); - } - return { - sqlName: undefined, - sqlNames: extensionSqlNames(product, prefix), - class: "contrib", - versioning: "runtime-bound", - sourcePath: contrib.sourcePath, - artifactProduct: contrib.artifactProduct, - compatibility: { - postgresMajor, - extensionRuntimeContract: contrib.runtimeContract, - nativeRuntimeProduct: contrib.nativeOwner, - nativeRuntimeVersion: currentProductVersionSync(contrib.nativeOwner, prefix), - wasixRuntimeProduct: contrib.wasixOwner, - wasixRuntimeVersion: currentProductVersionSync(contrib.wasixOwner, prefix), - }, - }; - } - const config = productConfig(product, prefix); - if (!EXTENSION_PRODUCT_KINDS.has(config.kind)) { - fail(prefix, `${product} is not an exact-extension product`); - } - const sqlNames = extensionSqlNames(product, prefix); - const metadata = config.extension; - if (metadata === null || Array.isArray(metadata) || typeof metadata !== "object") { - fail(prefix, `${product} release metadata must declare [extension]`); - } - let sqlName; - if (config.kind === "exact-extension-artifact") { - sqlName = nonEmptyString(metadata.sql_name, `${product}.extension.sql_name`, prefix); - if (sqlName !== sqlNames[0]) { - fail(prefix, `${product}.extension.sql_name ${JSON.stringify(sqlName)} must match extension_sql_name ${JSON.stringify(sqlNames[0])}`); - } - if (metadata.member_manifest !== undefined) { - fail(prefix, `${product} singleton extension metadata must not declare member_manifest`); - } - } else { - if (metadata.sql_name !== undefined) { - fail(prefix, `${product} extension bundle must not declare extension.sql_name`); - } - fail(prefix, `${product} extension bundle has no shared member descriptor`); - } - const extensionClass = nonEmptyString(metadata.class, `${product}.extension.class`, prefix); - if (!(extensionClass in EXTENSION_VERSIONING_BY_CLASS)) { - fail(prefix, `${product}.extension.class must be one of ${Object.keys(EXTENSION_VERSIONING_BY_CLASS).sort(compareText).join(", ")}`); - } - const versioning = nonEmptyString(metadata.versioning, `${product}.extension.versioning`, prefix); - const expectedVersioning = EXTENSION_VERSIONING_BY_CLASS[extensionClass]; - if (versioning !== expectedVersioning) { - fail(prefix, `${product}.extension.versioning must be ${JSON.stringify(expectedVersioning)} for class ${JSON.stringify(extensionClass)}, got ${JSON.stringify(versioning)}`); - } - const source = metadata.source; - if (source === null || Array.isArray(source) || typeof source !== "object") { - fail(prefix, `${product}.extension must declare [extension.source]`); - } - const sourcePath = releaseMetadataRelativePath( - nonEmptyString(source.path, `${product}.extension.source.path`, prefix), - `${product}.extension.source.path`, - prefix, - ); - const packageRoot = packagePath(product, prefix); - if (extensionClass === "contrib" && sourcePath !== contrib.sourcePath) { - fail(prefix, `${product}.extension.source.path must match the shared contrib source ${JSON.stringify(contrib.sourcePath)}`); - } - if (extensionClass === "external" && sourcePath !== `${packageRoot}/source.toml`) { - fail(prefix, `${product}.extension.source.path must be ${packageRoot}/source.toml for external extensions`); - } - if (extensionClass === "first-party" && !(sourcePath === packageRoot || sourcePath.startsWith(`${packageRoot}/`))) { - fail(prefix, `${product}.extension.source.path must stay inside ${packageRoot}/ for first-party extensions`); - } - - const compatibility = metadata.compatibility; - if (compatibility === null || Array.isArray(compatibility) || typeof compatibility !== "object") { - fail(prefix, `${product}.extension must declare [extension.compatibility]`); - } - const postgresMajor = nonEmptyString(compatibility.postgres_major, `${product}.extension.compatibility.postgres_major`, prefix); - if (postgresMajor !== "18") { - fail(prefix, `${product}.extension.compatibility.postgres_major must be '18', got ${JSON.stringify(postgresMajor)}`); - } - const contractPath = releaseMetadataRelativePath( - nonEmptyString(compatibility.extension_runtime_contract, `${product}.extension.compatibility.extension_runtime_contract`, prefix), - `${product}.extension.compatibility.extension_runtime_contract`, - prefix, - ); - if (contractPath !== contrib.runtimeContract) { - fail(prefix, `${product}.extension.compatibility.extension_runtime_contract must match ${JSON.stringify(contrib.runtimeContract)}`); - } - const nativeProduct = nonEmptyString(compatibility.native_runtime_product, `${product}.extension.compatibility.native_runtime_product`, prefix); - const wasixProduct = nonEmptyString(compatibility.wasix_runtime_product, `${product}.extension.compatibility.wasix_runtime_product`, prefix); - if (nativeProduct !== "liboliphaunt-native") { - fail(prefix, `${product}.extension.compatibility.native_runtime_product must be 'liboliphaunt-native'`); - } - if (wasixProduct !== "liboliphaunt-wasix") { - fail(prefix, `${product}.extension.compatibility.wasix_runtime_product must be 'liboliphaunt-wasix'`); - } - const nativeVersion = nonEmptyString(compatibility.native_runtime_version, `${product}.extension.compatibility.native_runtime_version`, prefix); - const wasixVersion = nonEmptyString(compatibility.wasix_runtime_version, `${product}.extension.compatibility.wasix_runtime_version`, prefix); - return { - sqlName, - sqlNames, - artifactProduct: product, - class: extensionClass, - versioning, - sourcePath, - compatibility: { - postgresMajor, - extensionRuntimeContract: contractPath, - nativeRuntimeProduct: nativeProduct, - nativeRuntimeVersion: nativeVersion, - wasixRuntimeProduct: wasixProduct, - wasixRuntimeVersion: wasixVersion, - }, - }; -} - -export function extensionSourceIdentity(product, prefix = "release-artifact-targets.mjs") { - const metadata = extensionMetadata(product, prefix); - const source = Bun.TOML.parse(readFileSync(path.join(ROOT, metadata.sourcePath), "utf8")); - if (metadata.class === "contrib") { - const postgresql = source.postgresql; - if (postgresql === null || Array.isArray(postgresql) || typeof postgresql !== "object") { - fail(prefix, `${metadata.sourcePath} must declare [postgresql] for contrib extension products`); - } - return { - kind: "postgres-contrib", - name: "postgresql", - version: nonEmptyString(postgresql.version, `${metadata.sourcePath}.postgresql.version`, prefix), - url: nonEmptyString(postgresql.url, `${metadata.sourcePath}.postgresql.url`, prefix), - sha256: nonEmptyString(postgresql.sha256, `${metadata.sourcePath}.postgresql.sha256`, prefix), - }; - } - if (metadata.class === "external") { - return { - kind: "external", - name: nonEmptyString(source.name, `${metadata.sourcePath}.name`, prefix), - url: nonEmptyString(source.url, `${metadata.sourcePath}.url`, prefix), - branch: nonEmptyString(source.branch, `${metadata.sourcePath}.branch`, prefix), - commit: nonEmptyString(source.commit, `${metadata.sourcePath}.commit`, prefix), - }; - } - if (metadata.class === "first-party") { - return { - kind: "repo", - name: metadata.sqlName ?? product, - path: metadata.sourcePath, - version: currentProductVersionSync(product, prefix), - }; - } - fail(prefix, `${product}.extension.class has unsupported source identity class ${JSON.stringify(metadata.class)}`); -} - -function wasixExtensionTargetId(runtimeTarget) { - return runtimeTarget === "portable" ? "wasix-portable" : runtimeTarget; -} - -function runtimeExtensionTargetRows(prefix) { - const rows = []; - for (const target of allArtifactTargets( - { product: "liboliphaunt-native", kind: "native-runtime" }, - prefix, - )) { - if (!target.extensionArtifacts) { - continue; - } - rows.push({ - target: target.target, - family: "native", - kind: target.target === "ios-xcframework" || target.target.startsWith("android-") - ? "native-static-registry" - : "native-dynamic", - }); - } - for (const target of allArtifactTargets( - { product: "liboliphaunt-wasix", kind: "wasix-runtime" }, - prefix, - )) { - rows.push({ - target: wasixExtensionTargetId(target.target), - family: "wasix", - kind: "wasix-runtime", - }); - } - if (rows.length === 0) { - fail(prefix, "could not derive any exact-extension artifact targets from runtime products"); - } - return rows; -} - -function readExtensionTargetRows(prefix) { - const relative = EXTENSION_TARGET_PROFILES_RELATIVE_PATH; - const allowed = new Set(runtimeExtensionTargetRows(prefix).map((row) => `${row.target}\0${row.family}\0${row.kind}`)); - const rows = loadExtensionTargetProfiles().targets; - for (const row of rows) { - if (!allowed.has(`${row.target}\0${row.family}\0${row.kind}`)) { - fail(prefix, `${relative} target row ${row.target}/${row.family}/${row.kind} is not backed by runtime artifact metadata`); - } - } - return rows; -} - -function nonEmptyString(value, label, prefix) { - if (typeof value === "string" && value.length > 0) { - return value; - } - fail(prefix, `${label} must be a non-empty string`); -} - -export function extensionArtifactTargets( - { - product = undefined, - family = undefined, - } = {}, - prefix = "release-artifact-targets.mjs", -) { - const products = product === undefined ? exactExtensionProducts(prefix) : [product]; - const parsed = []; - for (const productId of products) { - if (!exactExtensionProducts(prefix).includes(productId)) { - fail(prefix, `${productId} is not an exact-extension artifact product`); - } - for (const sqlName of extensionSqlNames(productId, prefix)) { - const seen = new Set(); - for (const [index, row] of readExtensionTargetRows(prefix).entries()) { - const source = EXTENSION_TARGET_PROFILES_RELATIVE_PATH; - const target = nonEmptyString(row.target, `${source} targets[${index}].target`, prefix); - const targetFamily = nonEmptyString(row.family, `${source} targets[${index}].family`, prefix); - const kind = nonEmptyString(row.kind, `${source} targets[${index}].kind`, prefix); - if (!EXTENSION_FAMILIES.has(targetFamily)) { - fail(prefix, `${source} target ${target} has invalid family ${targetFamily}`); - } - if (!EXTENSION_KINDS.has(kind)) { - fail(prefix, `${source} target ${target} has invalid kind ${kind}`); - } - if (targetFamily === "wasix" && kind !== "wasix-runtime") { - fail(prefix, `${source} target ${target} must use kind wasix-runtime for wasix family`); - } - if (targetFamily === "native" && kind === "wasix-runtime") { - fail(prefix, `${source} target ${target} cannot use wasix-runtime for native family`); - } - const key = `${target}\0${targetFamily}\0${kind}`; - if (seen.has(key)) { - fail(prefix, `${source} has duplicate target row ${target}/${targetFamily}/${kind}`); - } - seen.add(key); - if (family !== undefined && targetFamily !== family) { - continue; - } - const binaryCompatibility = - targetFamily === "native" - ? requiredBinaryCompatibility(target, `${productId} native extension`, prefix) - : undefined; - parsed.push({ - product: productId, - sqlName, - sql_name: sqlName, - target, - family: targetFamily, - kind, - source_file: source, - binaryCompatibility, - binary_compatibility: binaryCompatibility, - }); - } - } - } - return parsed; -} - -export function extensionTargetIds({ family }, prefix = "release-artifact-targets.mjs") { - return [...new Set(extensionArtifactTargets({ family }, prefix).map((target) => target.target))] - .sort(compareText); -} - -function extensionPublishedTargets(product, family, kind, prefix) { - return [...new Set( - extensionArtifactTargets({ product, family }, prefix) - .filter((target) => target.kind === kind) - .map((target) => target.target), - )].sort(compareText); -} - -export function extensionRegistryPackageTargetSets(product, prefix = "release-artifact-targets.mjs") { - const memberSignatures = extensionSqlNames(product, prefix).map((sqlName) => { - const rows = extensionArtifactTargets({ product }, prefix) - .filter((row) => row.sqlName === sqlName) - .map((row) => `${row.target}\0${row.family}\0${row.kind}`) - .sort(compareText); - return { sqlName, rows }; - }); - const baseline = JSON.stringify(memberSignatures[0]?.rows ?? []); - const mismatched = memberSignatures.filter(({ rows }) => JSON.stringify(rows) !== baseline).map(({ sqlName }) => sqlName); - if (mismatched.length > 0) { - fail(prefix, `${product} bundle members must publish an identical target carrier set; mismatched members: ${mismatched.join(", ")}`); - } - const nativeDynamicTargets = extensionPublishedTargets(product, "native", "native-dynamic", prefix); - if (nativeDynamicTargets.length === 0) { - fail(prefix, `${product} has no native dynamic extension registry targets`); - } - const androidTargets = extensionPublishedTargets(product, "native", "native-static-registry", prefix) - .filter((target) => target.startsWith("android-")); - const wasixRuntimeTargets = extensionPublishedTargets(product, "wasix", "wasix-runtime", prefix); - const wasixAotMembers = extensionWasixAotMemberSqlNames(product, prefix); - return { - androidTargets, - npmTargets: nativeDynamicTargets, - nativeCargoTargets: nativeDynamicTargets, - includeWasixNpm: wasixRuntimeTargets.includes("wasix-portable"), - // An AOT carrier is meaningful only when at least one exact SQL member has - // a native module to precompile. SQL/resource-only products still publish - // their portable archive but must not reserve empty host-AOT identities. - includeWasixAot: wasixRuntimeTargets.includes("wasix-portable") && wasixAotMembers.length > 0, - }; -} diff --git a/tools/release/release-artifact-targets.mts b/tools/release/release-artifact-targets.mts new file mode 100644 index 000000000..6bca3731f --- /dev/null +++ b/tools/release/release-artifact-targets.mts @@ -0,0 +1,1955 @@ +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { seedCarrierIdentities } from '../../src/database-resources/seeds/carrier-identities.mts'; +import { RUST_PAYLOAD_LICENSE as MOBILE_BINDINGS_LICENSE } from '../../src/sdks/rust/mobile-bindings/tools/dependency-license-contract.mts'; + +import { + PLATFORM_COMPATIBILITY_POLICY, + platformCompatibilityContract, +} from './platform-compatibility-policy.mts'; +import { + extensionNativeRegistryPackageStrings, + extensionWasixRegistryPackageStrings, +} from '../../src/extensions/artifacts/packages/tools/extension-registry-packages.mts'; +import { loadContribCarriers } from '../../src/extensions/artifacts/packages/tools/contrib-carriers.mts'; +import { + EXTENSION_TARGET_PROFILES_RELATIVE_PATH, + loadExtensionTargetProfiles, +} from '../../src/extensions/contracts/extension-target-profiles.mts'; +import { loadProducts, versionFiles } from './release-graph.mts'; + +export { PLATFORM_COMPATIBILITY_POLICY }; + +export const ROOT = path.resolve(import.meta.dir, '../..'); + +export const DESKTOP_TARGETS = { + 'linux-arm64-gnu': { + triple: 'aarch64-unknown-linux-gnu', + runner: 'ubuntu-24.04-arm', + archive: 'tar.gz', + npmOs: 'linux', + npmCpu: 'arm64', + npmLibc: 'glibc', + liboliphauntNpmPackage: '@oliphaunt/liboliphaunt-linux-arm64-gnu', + liboliphauntToolsNpmPackage: '@oliphaunt/tools-linux-arm64-gnu', + brokerNpmPackage: '@oliphaunt/broker-linux-arm64-gnu', + nodePackage: '@oliphaunt/node-direct-linux-arm64-gnu', + wasixNapiPackage: '@oliphaunt/wasix-napi-linux-arm64-gnu', + wasixLlvmUrl: + 'https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-linux-aarch64.tar.xz', + wasixLlvmSha256: '1fddcf5b30f9d3e073eb161509220b4136ea8e2f114f23084bdec33e40fa87c1', + wasixLlvmBytes: 668873496, + }, + 'linux-x64-gnu': { + triple: 'x86_64-unknown-linux-gnu', + runner: 'ubuntu-24.04', + archive: 'tar.gz', + npmOs: 'linux', + npmCpu: 'x64', + npmLibc: 'glibc', + liboliphauntNpmPackage: '@oliphaunt/liboliphaunt-linux-x64-gnu', + liboliphauntToolsNpmPackage: '@oliphaunt/tools-linux-x64-gnu', + brokerNpmPackage: '@oliphaunt/broker-linux-x64-gnu', + nodePackage: '@oliphaunt/node-direct-linux-x64-gnu', + wasixNapiPackage: '@oliphaunt/wasix-napi-linux-x64-gnu', + wasixLlvmUrl: + 'https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-linux-amd64.tar.xz', + wasixLlvmSha256: '5fb1c687c5e895d517a23e7aabea9ec3557e3a3e33f8a8d3a8d21395157b3906', + wasixLlvmBytes: 741670068, + }, + 'macos-arm64': { + triple: 'aarch64-apple-darwin', + runner: 'macos-26', + archive: 'tar.gz', + npmOs: 'darwin', + npmCpu: 'arm64', + liboliphauntNpmPackage: '@oliphaunt/liboliphaunt-darwin-arm64', + liboliphauntToolsNpmPackage: '@oliphaunt/tools-darwin-arm64', + brokerNpmPackage: '@oliphaunt/broker-darwin-arm64', + nodePackage: '@oliphaunt/node-direct-darwin-arm64', + wasixNapiPackage: '@oliphaunt/wasix-napi-darwin-arm64', + wasixLlvmUrl: + 'https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-darwin-aarch64.tar.xz', + wasixLlvmSha256: 'f64460f6c8a28876737402542fc5b28bb1f4262cef85f799b65ce2a7ee6f8847', + wasixLlvmBytes: 479103872, + }, + 'macos-x64': { + triple: 'x86_64-apple-darwin', + runner: 'macos-26', + archive: 'tar.gz', + }, + 'windows-x64-msvc': { + triple: 'x86_64-pc-windows-msvc', + runner: 'windows-2025-vs2026', + archive: 'zip', + npmOs: 'win32', + npmCpu: 'x64', + liboliphauntNpmPackage: '@oliphaunt/liboliphaunt-win32-x64-msvc', + liboliphauntToolsNpmPackage: '@oliphaunt/tools-win32-x64-msvc', + brokerNpmPackage: '@oliphaunt/broker-win32-x64-msvc', + nodePackage: '@oliphaunt/node-direct-win32-x64-msvc', + wasixNapiPackage: '@oliphaunt/wasix-napi-win32-x64-msvc', + wasixLlvmUrl: + 'https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-windows-amd64.tar.xz', + wasixLlvmSha256: '19ff22b0cf74b53dad2fc717db2209f8162b768fc6dede9e2caa6a83c724496e', + wasixLlvmBytes: 757929860, + }, +}; + +export const MOBILE_TARGETS = { + 'android-arm64-v8a': { + triple: 'aarch64-linux-android', + runner: 'ubuntu-24.04', + androidAbi: 'arm64-v8a', + }, + 'android-x86_64': { + triple: 'x86_64-linux-android', + runner: 'ubuntu-24.04', + androidAbi: 'x86_64', + }, + 'ios-xcframework': { + triple: 'ios-xcframework', + runner: 'macos-26', + }, +}; + +const NATIVE_RUNTIME_TARGETS = { ...DESKTOP_TARGETS, ...MOBILE_TARGETS }; +const RELEASE_HOST_TARGETS = Object.freeze([ + 'linux-arm64-gnu', + 'linux-x64-gnu', + 'macos-arm64', + 'windows-x64-msvc', +]); +const WASIX_TARGETS = new Set(['portable', ...RELEASE_HOST_TARGETS]); +const WASIX_POSTMASTER_TARGETS = new Set(RELEASE_HOST_TARGETS); +const BROKER_TARGETS = new Set(RELEASE_HOST_TARGETS); +const NODE_DIRECT_TARGETS = BROKER_TARGETS; +const WASIX_NAPI_TARGETS = BROKER_TARGETS; +const PRODUCT_PRESETS = { + 'postgres-tools-native': 'postgres-tools-native', + 'postgres-tools-wasix': 'postgres-tools-wasix', + 'liboliphaunt-native': 'liboliphaunt-native', + 'liboliphaunt-wasix': 'liboliphaunt-wasix', + 'liboliphaunt-wasix-postmaster': 'liboliphaunt-wasix-postmaster', + 'oliphaunt-broker': 'broker-helper', + 'oliphaunt-node-direct': 'node-direct-addon', + 'oliphaunt-wasix-napi': 'wasix-napi-addon', +}; +const EXTENSION_FAMILIES = new Set(['native', 'wasix']); +const EXTENSION_KINDS = new Set(['native-dynamic', 'native-static-registry', 'wasix-runtime']); +const EXTENSION_VERSIONING_BY_CLASS = { + contrib: 'runtime-bound', + external: 'upstream-bound', + 'first-party': 'repo-bound', +}; +const EXTENSION_PRODUCT_KINDS = new Set(['exact-extension-artifact', 'exact-extension-bundle']); +const EXTENSION_CATALOG_PATH = path.join(ROOT, 'src/extensions/generated/extensions.catalog.json'); + +const productsCache = new Map(); +let extensionCatalogRowsCache; +let contribCarriersCache; + +export function fail(prefix, message) { + console.error(`${prefix}: ${message}`); + process.exit(1); +} + +function requiredBinaryCompatibility(target, use, prefix) { + const contract = platformCompatibilityContract(target); + if (contract === undefined) { + fail(prefix, `${use} publishes ${target} without a platform compatibility contract`); + } + return contract; +} + +export function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +export function rel(file) { + const relative = path.relative(ROOT, file); + return relative.startsWith('..') ? file : relative.split(path.sep).join('/'); +} + +function productConfigs(prefix) { + if (!productsCache.has(prefix)) productsCache.set(prefix, loadProducts(prefix)); + return productsCache.get(prefix); +} + +export function contribCarrierDescriptor(prefix = 'release-artifact-targets.mts') { + if (contribCarriersCache !== undefined) return contribCarriersCache; + let value; + try { + value = loadContribCarriers(ROOT, prefix); + } catch (error) { + fail(prefix, error instanceof Error ? error.message.replace(`${prefix}: `, '') : String(error)); + } + const descriptor = { + ...value, + sourcePath: value.source, + runtimeContract: value.contract, + }; + if (!descriptor.artifactProduct.startsWith('oliphaunt-extension-')) { + fail(prefix, 'contrib logical_product must be an extension artifact product'); + } + for (const [family, owner] of [ + ['native', descriptor.nativeOwner], + ['wasix', descriptor.wasixOwner], + ]) { + if (productConfigs(prefix)[owner] === undefined) { + fail(prefix, `contrib ${family}_owner references unknown release product ${owner}`); + } + } + contribCarriersCache = Object.freeze(descriptor); + return contribCarriersCache; +} + +export function extensionReleaseProduct(product, family, prefix = 'release-artifact-targets.mts') { + if (!EXTENSION_FAMILIES.has(family)) { + fail(prefix, `extension carrier family must be native or wasix, got ${JSON.stringify(family)}`); + } + const contrib = contribCarrierDescriptor(prefix); + if (product === contrib.artifactProduct) { + return family === 'native' ? contrib.nativeOwner : contrib.wasixOwner; + } + if (!exactExtensionProducts(prefix).includes(product)) { + fail(prefix, `${product} is not an exact-extension artifact product`); + } + return product; +} + +export function extensionReleaseVersion(product, family, prefix = 'release-artifact-targets.mts') { + return currentProductVersionSync(extensionReleaseProduct(product, family, prefix), prefix); +} + +export function extensionArtifactProductRoot( + product, + family = 'native', + root = 'target/extension-artifacts', + prefix = 'release-artifact-targets.mts', +) { + const releaseProduct = extensionReleaseProduct(product, family, prefix); + return path.join(root, ...(releaseProduct === product ? [product] : [releaseProduct, product])); +} + +export function extensionArtifactProductsForReleaseProducts( + releaseProducts, + { family = null, prefix = 'release-artifact-targets.mts' } = {}, +) { + if ( + !Array.isArray(releaseProducts) || + releaseProducts.some((product) => typeof product !== 'string' || !product) + ) { + fail(prefix, 'release products must be a string list'); + } + if (family !== null && !EXTENSION_FAMILIES.has(family)) { + fail(prefix, `extension carrier family must be native or wasix, got ${JSON.stringify(family)}`); + } + const selected = new Set(releaseProducts); + const products = exactExtensionReleaseProducts(prefix).filter((product) => selected.has(product)); + const contrib = contribCarrierDescriptor(prefix); + const selectedOwner = + family === 'native' + ? selected.has(contrib.nativeOwner) + : family === 'wasix' + ? selected.has(contrib.wasixOwner) + : selected.has(contrib.nativeOwner) || selected.has(contrib.wasixOwner); + if (selectedOwner) products.push(contrib.artifactProduct); + return [...new Set(products)].sort(compareText); +} + +function archiveAsset(productPrefix, target, archive) { + return `${productPrefix}-{version}-${target}.${archive}`; +} + +function assertStringList(value, label, prefix) { + if (!Array.isArray(value) || !value.every((item) => typeof item === 'string' && item)) { + fail(prefix, `${label} must be a non-empty string list`); + } + return value; +} + +function artifactTargetConfig(product, expectedPreset, prefix) { + const release = releaseMetadata(product, prefix); + const config = release.artifactTargets; + if (typeof config !== 'object' || config === null || Array.isArray(config)) { + fail(prefix, `Moon release metadata for ${product} must declare artifactTargets`); + } + if (config.preset !== expectedPreset) { + fail( + prefix, + `Moon release metadata for ${product} artifactTargets.preset must be ${expectedPreset}`, + ); + } + return config; +} + +function productTargets(product, expectedPreset, knownTargets, prefix) { + const config = artifactTargetConfig(product, expectedPreset, prefix); + const targets = assertStringList(config.targets ?? [], `${product}.targets`, prefix); + const duplicates = [ + ...new Set(targets.filter((target, index) => targets.indexOf(target) !== index)), + ]; + if (duplicates.length > 0) { + fail( + prefix, + `Moon release metadata for ${product} artifactTargets.targets contains duplicates`, + ); + } + const unknown = targets.filter((target) => !knownTargets.has(target)).sort(compareText); + if (unknown.length > 0) { + fail( + prefix, + `Moon release metadata for ${product} declares unknown artifact target(s): ${unknown.join(', ')}`, + ); + } + return targets; +} + +function nativeLibraryRelativePath(target) { + if (target.startsWith('android-')) { + return `jni/${MOBILE_TARGETS[target].androidAbi}/liboliphaunt.so`; + } + if (target === 'ios-xcframework') { + return 'liboliphaunt.xcframework'; + } + if (target.startsWith('macos-')) { + return 'lib/liboliphaunt.dylib'; + } + if (target.startsWith('linux-')) { + return 'lib/liboliphaunt.so'; + } + if (target === 'windows-x64-msvc') { + return 'bin/oliphaunt.dll'; + } + fail('release-artifact-targets.mts', `unsupported liboliphaunt native target ${target}`); +} + +function nativeSurfaces(target) { + if (target.startsWith('android-')) { + return ['github-release', 'maven', 'react-native-android']; + } + if (target === 'ios-xcframework') { + return ['github-release', 'swiftpm', 'react-native-ios']; + } + return ['github-release', 'rust-native-direct', 'typescript-native-direct']; +} + +export function liboliphauntNativeBuildRoot(target) { + if (!(target in NATIVE_RUNTIME_TARGETS)) { + fail('release-artifact-targets.mts', `unknown liboliphaunt-native target ${target}`); + } + const roots = { + 'macos-arm64': 'target/liboliphaunt-pg18', + 'android-arm64-v8a': 'target/liboliphaunt-pg18-android-arm64', + 'android-x86_64': 'target/liboliphaunt-pg18-android-x86_64', + 'ios-xcframework': 'target/liboliphaunt-ios-xcframework', + }; + return roots[target] ?? `target/liboliphaunt-pg18-${target}`; +} + +export function liboliphauntNativeCiArtifactRoot(target) { + if (!(target in NATIVE_RUNTIME_TARGETS)) { + fail('release-artifact-targets.mts', `unknown liboliphaunt-native target ${target}`); + } + return `target/liboliphaunt-native-ci/${target}`; +} + +export function liboliphauntAndroidAbi(target) { + const abi = MOBILE_TARGETS[target]?.androidAbi; + if (!abi) { + fail( + 'release-artifact-targets.mts', + `unsupported React Native Android runtime target ${target}`, + ); + } + return abi; +} + +function liboliphauntNativeRows(prefix) { + const product = 'liboliphaunt-native'; + const targets = new Set( + productTargets( + product, + PRODUCT_PRESETS[product], + new Set(Object.keys(NATIVE_RUNTIME_TARGETS)), + prefix, + ), + ); + const rows = []; + for (const target of [...targets].sort(compareText)) { + const platform = NATIVE_RUNTIME_TARGETS[target]; + const row = { + id: `${product}.${target}`, + product, + kind: 'native-runtime', + target, + triple: platform.triple, + runner: platform.runner, + asset: archiveAsset('liboliphaunt', target, platform.archive ?? 'tar.gz'), + library_relative_path: nativeLibraryRelativePath(target), + npm_package: platform.liboliphauntNpmPackage, + npm_os: platform.npmOs, + npm_cpu: platform.npmCpu, + npm_libc: platform.npmLibc, + surfaces: nativeSurfaces(target), + binary_compatibility: requiredBinaryCompatibility( + target, + `${product} native runtime`, + prefix, + ), + _source_file: 'Moon release metadata', + }; + rows.push(row); + } + rows.push( + { + id: `${product}.apple-spm-xcframework`, + product, + kind: 'apple-swiftpm-binary', + target: 'apple-spm-xcframework', + triple: 'apple-xcframework', + runner: 'macos-26', + asset: 'liboliphaunt-{version}-apple-spm-xcframework.zip', + surfaces: ['github-release', 'swiftpm'], + _source_file: 'Moon release metadata', + }, + { + id: `${product}.runtime-resources-ios-datum64`, + product, + kind: 'runtime-resources', + target: 'ios-datum64', + asset: 'liboliphaunt-{version}-runtime-resources-ios-datum64.tar.gz', + surfaces: ['github-release', 'react-native-ios'], + _source_file: 'Moon release metadata', + }, + { + id: `${product}.runtime-resources-android-datum64`, + product, + kind: 'runtime-resources', + target: 'android-datum64', + asset: 'liboliphaunt-{version}-runtime-resources-android-datum64.tar.gz', + surfaces: ['github-release', 'maven', 'react-native-android'], + _source_file: 'Moon release metadata', + }, + { + id: `${product}.checksums`, + product, + kind: 'checksums', + target: 'portable', + asset: 'liboliphaunt-{version}-release-assets.sha256', + surfaces: ['github-release'], + _source_file: 'Moon release metadata', + }, + ); + return rows; +} + +function postgresToolsNativeRows(prefix) { + const product = 'postgres-tools-native'; + const targets = new Set( + productTargets( + product, + PRODUCT_PRESETS[product], + new Set(Object.keys(DESKTOP_TARGETS)), + prefix, + ), + ); + const rows = []; + for (const target of [...targets].filter((item) => item in DESKTOP_TARGETS).sort(compareText)) { + const platform = DESKTOP_TARGETS[target]; + rows.push({ + id: `${product}.tools-${target}`, + product, + kind: 'native-tools', + target, + triple: platform.triple, + runner: platform.runner, + asset: archiveAsset('oliphaunt-tools', target, platform.archive), + npm_package: platform.liboliphauntToolsNpmPackage, + npm_os: platform.npmOs, + npm_cpu: platform.npmCpu, + npm_libc: platform.npmLibc, + surfaces: ['github-release', 'rust-native-direct', 'typescript-native-direct'], + binary_compatibility: requiredBinaryCompatibility(target, `${product} native tools`, prefix), + _source_file: 'Moon release metadata', + }); + } + return rows; +} + +function postgresToolsWasixRows(prefix) { + const product = 'postgres-tools-wasix'; + const targets = productTargets(product, PRODUCT_PRESETS[product], WASIX_TARGETS, prefix); + return targets.map((target) => { + const portable = target === 'portable'; + const platform = DESKTOP_TARGETS[target]; + return { + id: `${product}.${portable ? 'portable' : `aot-${target}`}`, + product, + kind: portable ? 'wasix-tools' : 'wasix-tools-aot', + target, + ...(portable + ? {} + : { + triple: platform.triple, + runner: platform.runner, + npm_package: `@oliphaunt/liboliphaunt-wasix-tools-${target === 'macos-arm64' ? 'darwin-arm64' : target === 'windows-x64-msvc' ? 'win32-x64-msvc' : target}`, + npm_os: platform.npmOs, + npm_cpu: platform.npmCpu, + npm_libc: platform.npmLibc, + }), + asset: portable + ? 'postgres-tools-wasix-{version}-portable.tar.gz' + : `postgres-tools-wasix-{version}-aot-${target}.tar.gz`, + surfaces: portable ? ['github-release'] : ['github-release', 'npm-optional'], + _source_file: 'Moon release metadata', + }; + }); +} + +function liboliphauntWasixRows(prefix) { + const product = 'liboliphaunt-wasix'; + const targets = new Set(productTargets(product, PRODUCT_PRESETS[product], WASIX_TARGETS, prefix)); + if (!targets.has('portable')) { + fail(prefix, `Moon release metadata for ${product} must include the portable runtime target`); + } + const rows = [ + { + id: `${product}.runtime-portable`, + product, + kind: 'wasix-runtime', + target: 'portable', + asset: 'liboliphaunt-wasix-{version}-runtime-portable.tar.zst', + surfaces: ['github-release'], + _source_file: 'Moon release metadata', + }, + ]; + for (const target of [...targets].filter((item) => item !== 'portable').sort(compareText)) { + const platform = DESKTOP_TARGETS[target]; + rows.push({ + id: `${product}.aot-${target}`, + product, + kind: 'wasix-aot-runtime', + target, + triple: platform.triple, + runner: platform.runner, + llvm_url: platform.wasixLlvmUrl, + llvm_sha256: platform.wasixLlvmSha256, + llvm_bytes: platform.wasixLlvmBytes, + asset: `liboliphaunt-wasix-{version}-runtime-aot-${target}.tar.zst`, + surfaces: ['github-release'], + _source_file: 'Moon release metadata', + }); + } + rows.push({ + id: `${product}.checksums`, + product, + kind: 'checksums', + target: 'portable', + asset: 'liboliphaunt-wasix-{version}-release-assets.sha256', + surfaces: ['github-release'], + _source_file: 'Moon release metadata', + }); + return rows; +} + +function liboliphauntWasixPostmasterRows(prefix) { + const product = 'liboliphaunt-wasix-postmaster'; + const rows = []; + for (const target of productTargets( + product, + PRODUCT_PRESETS[product], + WASIX_POSTMASTER_TARGETS, + prefix, + ).sort(compareText)) { + const platform = DESKTOP_TARGETS[target]; + rows.push({ + id: `${product}.${target}`, + product, + kind: 'wasix-postmaster-runtime', + target, + triple: platform.triple, + runner: platform.runner, + llvm_url: platform.wasixLlvmUrl, + llvm_sha256: platform.wasixLlvmSha256, + llvm_bytes: platform.wasixLlvmBytes, + asset: `${product}-{version}-${target}.tar.zst`, + surfaces: ['github-release'], + binary_compatibility: requiredBinaryCompatibility(target, `${product} runtime`, prefix), + extension_artifacts: false, + _source_file: 'Moon release metadata', + }); + } + rows.push({ + id: `${product}.checksums`, + product, + kind: 'checksums', + target: 'portable', + asset: `${product}-{version}-release-assets.sha256`, + surfaces: ['github-release'], + extension_artifacts: false, + _source_file: 'Moon release metadata', + }); + return rows; +} + +function brokerRows(prefix) { + const product = 'oliphaunt-broker'; + const rows = []; + for (const target of productTargets( + product, + PRODUCT_PRESETS[product], + BROKER_TARGETS, + prefix, + ).sort(compareText)) { + const platform = DESKTOP_TARGETS[target]; + rows.push({ + id: `${product}.${target}`, + product, + kind: 'broker-helper', + target, + triple: platform.triple, + runner: platform.runner, + asset: archiveAsset(product, target, platform.archive), + executable_relative_path: + target === 'windows-x64-msvc' ? 'bin/oliphaunt-broker.exe' : 'bin/oliphaunt-broker', + npm_package: platform.brokerNpmPackage, + npm_os: platform.npmOs, + npm_cpu: platform.npmCpu, + npm_libc: platform.npmLibc, + surfaces: ['github-release', 'rust-broker', 'typescript-broker'], + binary_compatibility: requiredBinaryCompatibility(target, `${product} broker`, prefix), + _source_file: 'Moon release metadata', + }); + } + rows.push({ + id: `${product}.checksums`, + product, + kind: 'checksums', + target: 'portable', + asset: 'oliphaunt-broker-{version}-release-assets.sha256', + surfaces: ['github-release', 'rust-broker', 'typescript-broker'], + _source_file: 'Moon release metadata', + }); + return rows; +} + +function nodeDirectRows(prefix) { + const product = 'oliphaunt-node-direct'; + const rows = []; + for (const target of productTargets( + product, + PRODUCT_PRESETS[product], + NODE_DIRECT_TARGETS, + prefix, + ).sort(compareText)) { + const platform = DESKTOP_TARGETS[target]; + rows.push({ + id: `${product}.${target}`, + product, + kind: 'node-direct-addon', + target, + triple: platform.triple, + runner: platform.runner, + asset: archiveAsset(product, target, platform.archive), + library_relative_path: 'oliphaunt_node.node', + npm_package: platform.nodePackage, + npm_os: platform.npmOs, + npm_cpu: platform.npmCpu, + npm_libc: platform.npmLibc, + surfaces: ['github-release', 'npm-optional'], + binary_compatibility: requiredBinaryCompatibility(target, `${product} Node addon`, prefix), + _source_file: 'Moon release metadata', + }); + } + rows.push({ + id: `${product}.checksums`, + product, + kind: 'checksums', + target: 'portable', + asset: 'oliphaunt-node-direct-{version}-release-assets.sha256', + surfaces: ['github-release'], + _source_file: 'Moon release metadata', + }); + return rows; +} + +function wasixNapiRows(prefix) { + const product = 'oliphaunt-wasix-napi'; + const rows = []; + for (const target of productTargets( + product, + PRODUCT_PRESETS[product], + WASIX_NAPI_TARGETS, + prefix, + ).sort(compareText)) { + const platform = DESKTOP_TARGETS[target]; + rows.push({ + id: `${product}.${target}`, + product, + kind: 'wasix-napi-addon', + target, + triple: platform.triple, + runner: platform.runner, + asset: archiveAsset(product, target, platform.archive), + library_relative_path: 'oliphaunt_wasix_napi.node', + npm_package: platform.wasixNapiPackage, + npm_os: platform.npmOs, + npm_cpu: platform.npmCpu, + npm_libc: platform.npmLibc, + surfaces: ['github-release', 'npm-optional'], + binary_compatibility: requiredBinaryCompatibility( + target, + `${product} Node-API addon`, + prefix, + ), + extension_artifacts: false, + _source_file: 'Moon release metadata', + }); + } + rows.push({ + id: `${product}.checksums`, + product, + kind: 'checksums', + target: 'portable', + asset: 'oliphaunt-wasix-napi-{version}-release-assets.sha256', + surfaces: ['github-release'], + extension_artifacts: false, + _source_file: 'Moon release metadata', + }); + return rows; +} + +function databaseResourceRows() { + const rows = [ + { + id: 'database-resources.swift-source', + product: 'database-resources', + kind: 'swift-source', + target: 'portable', + asset: 'database-resources-{version}-swift.zip', + surfaces: ['github-release', 'swiftpm'], + _source_file: 'src/database-resources/seeds/package-mobile-carriers.mts', + }, + { + id: 'database-resources.icu-data', + product: 'database-resources', + kind: 'icu-data', + target: 'portable', + asset: 'database-resources-{version}-icu-data.tar.gz', + npm_package: '@oliphaunt/icu', + surfaces: ['github-release', 'maven', 'swiftpm', 'react-native-ios', 'react-native-android'], + _source_file: 'Moon release metadata', + }, + ]; + for (const { family, target, profile, suffix } of seedCarrierIdentities()) { + for (const extension of ['tar.zst', 'json']) { + rows.push({ + id: `database-resources.${family}.${target}.${profile}.${extension}`, + product: 'database-resources', + kind: `${family}-seeds`, + target, + asset: `database-resources-{version}-seed-${suffix}.${extension}`, + surfaces: ['github-release'], + _source_file: 'src/database-resources/contracts/contract.json', + }); + } + } + rows.push({ + id: 'database-resources.checksums', + product: 'database-resources', + kind: 'checksums', + target: 'portable', + asset: 'database-resources-{version}-release-assets.sha256', + surfaces: ['github-release'], + _source_file: 'Moon release metadata', + }); + return rows; +} + +export function rawArtifactTargetRows(prefix = 'release-artifact-targets.mts') { + return [ + { + id: 'oliphaunt-swift.bindings', + product: 'oliphaunt-swift', + kind: 'swift-bindings', + target: 'apple-xcframework', + asset: 'oliphaunt-swift-{version}-bindings.xcframework.zip', + surfaces: ['github-release', 'swiftpm'], + license: MOBILE_BINDINGS_LICENSE, + _source_file: 'src/sdks/swift/tools/build-bindings-xcframework.sh', + }, + { + id: 'oliphaunt-swift.checksums', + product: 'oliphaunt-swift', + kind: 'checksums', + target: 'portable', + asset: 'oliphaunt-swift-{version}-release-assets.sha256', + surfaces: ['github-release'], + _source_file: 'src/sdks/swift/tools/build-bindings-xcframework.sh', + }, + ...databaseResourceRows(), + ...liboliphauntNativeRows(prefix), + ...postgresToolsNativeRows(prefix), + ...postgresToolsWasixRows(prefix), + ...liboliphauntWasixRows(prefix), + ...liboliphauntWasixPostmasterRows(prefix), + ...brokerRows(prefix), + ...nodeDirectRows(prefix), + ...wasixNapiRows(prefix), + ]; +} + +function stringField(row, key, id, required, prefix) { + const value = row[key]; + if (typeof value === 'string' && value.length > 0) { + return value; + } + if (required) { + fail(prefix, `artifact target ${id}.${key} must be a non-empty string`); + } + if (value !== undefined && value !== null) { + fail(prefix, `artifact target ${id}.${key} must be a string`); + } + return undefined; +} + +function positiveIntegerField(row, key, id, required, prefix) { + const value = row[key]; + if (Number.isSafeInteger(value) && value > 0) return value; + if (required || (value !== undefined && value !== null)) { + fail(prefix, `artifact target ${id}.${key} must be a positive safe integer`); + } + return undefined; +} + +function normalizeArtifactTarget(row, prefix) { + const id = stringField(row, 'id', '', true, prefix); + const libraryRelativePath = stringField(row, 'library_relative_path', id, false, prefix); + const executableRelativePath = stringField(row, 'executable_relative_path', id, false, prefix); + const npmPackage = stringField(row, 'npm_package', id, false, prefix); + const npmOs = stringField(row, 'npm_os', id, false, prefix); + const npmCpu = stringField(row, 'npm_cpu', id, false, prefix); + const npmLibc = stringField(row, 'npm_libc', id, false, prefix); + const llvmUrl = stringField(row, 'llvm_url', id, false, prefix); + const llvmSha256 = stringField(row, 'llvm_sha256', id, false, prefix); + const llvmBytes = positiveIntegerField(row, 'llvm_bytes', id, false, prefix); + const sourceFile = + stringField(row, '_source_file', id, false, prefix) ?? + stringField(row, 'source_file', id, false, prefix); + const unsupportedReason = stringField(row, 'unsupported_reason', id, false, prefix); + const binaryCompatibility = row.binary_compatibility; + if ( + binaryCompatibility !== undefined && + (binaryCompatibility === null || + typeof binaryCompatibility !== 'object' || + Array.isArray(binaryCompatibility)) + ) { + fail(prefix, `artifact target ${id}.binary_compatibility must be an object`); + } + const target = { + id, + product: stringField(row, 'product', id, true, prefix), + kind: stringField(row, 'kind', id, true, prefix), + target: stringField(row, 'target', id, true, prefix), + asset: stringField(row, 'asset', id, true, prefix), + surfaces: assertStringList(row.surfaces, `${id}.surfaces`, prefix), + triple: stringField(row, 'triple', id, false, prefix), + runner: stringField(row, 'runner', id, false, prefix), + libraryRelativePath, + executableRelativePath, + npmPackage, + npmOs, + npmCpu, + npmLibc, + llvmUrl, + llvmSha256, + llvmBytes, + binaryCompatibility, + extensionArtifacts: row.extension_artifacts ?? true, + sourceFile, + tier: stringField(row, 'tier', id, false, prefix), + unsupportedReason, + library_relative_path: libraryRelativePath, + executable_relative_path: executableRelativePath, + npm_package: npmPackage, + npm_os: npmOs, + npm_cpu: npmCpu, + npm_libc: npmLibc, + llvm_url: llvmUrl, + llvm_sha256: llvmSha256, + llvm_bytes: llvmBytes, + binary_compatibility: binaryCompatibility, + extension_artifacts: row.extension_artifacts ?? true, + source_file: sourceFile, + unsupported_reason: unsupportedReason, + }; + if (typeof target.extensionArtifacts !== 'boolean') { + fail(prefix, `artifact target ${id}.extension_artifacts must be true or false`); + } + return target; +} + +export function allArtifactTargets( + { product = undefined, kind = undefined, surface = undefined } = {}, + prefix = 'release-artifact-targets.mts', +) { + const products = productConfigs(prefix); + const seen = new Set(); + return rawArtifactTargetRows(prefix) + .map((row) => normalizeArtifactTarget(row, prefix)) + .filter((target) => { + if (seen.has(target.id)) { + fail(prefix, `duplicate artifact target id ${target.id}`); + } + seen.add(target.id); + if (!products[target.product]) { + fail(prefix, `artifact target ${target.id} references unknown product ${target.product}`); + } + if (product !== undefined && target.product !== product) { + return false; + } + if (kind !== undefined && target.kind !== kind) { + return false; + } + if (surface !== undefined && !target.surfaces.includes(surface)) { + return false; + } + return true; + }); +} + +export function typescriptOptionalRuntimePackageProducts(prefix = 'release-artifact-targets.mts') { + const selected = allArtifactTargets({}, prefix).filter((target) => { + if (target.product === 'oliphaunt-broker' && target.kind === 'broker-helper') { + return target.surfaces.includes('typescript-broker'); + } + if (target.product === 'liboliphaunt-native' && target.kind === 'native-runtime') { + return target.surfaces.includes('typescript-native-direct'); + } + if (target.product === 'oliphaunt-node-direct' && target.kind === 'node-direct-addon') { + return target.surfaces.includes('npm-optional'); + } + return false; + }); + if (selected.length === 0) { + fail(prefix, 'no TypeScript optional runtime package targets found'); + } + const rows = []; + const seen = new Set(); + for (const target of selected) { + if (typeof target.npmPackage !== 'string' || !target.npmPackage) { + fail(prefix, `${target.id} must declare npmPackage for TypeScript optional dependencies`); + } + if (seen.has(target.npmPackage)) { + fail(prefix, `duplicate TypeScript optional package target ${target.npmPackage}`); + } + seen.add(target.npmPackage); + rows.push({ + packageName: target.npmPackage, + product: target.product, + target: target.target, + kind: target.kind, + artifactTarget: target.id, + }); + } + return rows.sort((left, right) => compareText(left.packageName, right.packageName)); +} + +export function nativeToolsOptionalPackageProducts(prefix = 'release-artifact-targets.mts') { + const selected = allArtifactTargets( + { product: 'postgres-tools-native', kind: 'native-tools' }, + prefix, + ); + if (selected.length === 0) { + fail(prefix, 'no native tools optional package targets found'); + } + return selected + .map((target) => { + if (typeof target.npmPackage !== 'string' || !target.npmPackage) { + fail(prefix, `${target.id} must declare npmPackage for the native tools facade`); + } + return { + packageName: target.npmPackage, + product: target.product, + target: target.target, + kind: target.kind, + artifactTarget: target.id, + }; + }) + .sort((left, right) => compareText(left.packageName, right.packageName)); +} + +export function artifactTargets(product, kind, prefix) { + return allArtifactTargets({ product, kind }, prefix); +} + +function ciArtifactRows({ product, kind, surface, family, name }, prefix) { + const targets = allArtifactTargets({ product, kind, surface }, prefix); + if (targets.length === 0) { + fail(prefix, `${product} has no ${kind} CI ${family} artifact targets`); + } + return targets + .map((target) => ({ + family, + product, + target: target.target, + kind: target.kind, + artifactTarget: target.id, + artifactName: name(target), + })) + .sort((left, right) => compareText(left.artifactName, right.artifactName)); +} + +export function ciReleaseAssetArtifactRows(product, kind, prefix = 'release-artifact-targets.mts') { + return ciArtifactRows( + { + product, + kind, + surface: 'github-release', + family: 'release-assets', + name: (target) => + product === 'database-resources' + ? `${product}-${kind}-${target.target}` + : `${product}-release-assets-${target.target}`, + }, + prefix, + ); +} + +export function ciNpmPackageArtifactRows(product, kind, prefix = 'release-artifact-targets.mts') { + return ciArtifactRows( + { + product, + kind, + surface: 'npm-optional', + family: 'npm-package', + name: (target) => `${product}-npm-package-${target.target}`, + }, + prefix, + ); +} + +export function expectedAssetRows( + { product, version, surface = 'github-release', kinds = undefined } = {}, + prefix = 'release-artifact-targets.mts', +) { + if (typeof product !== 'string' || product.length === 0) { + fail(prefix, 'expected asset rows require a product'); + } + if (typeof version !== 'string' || version.length === 0) { + fail(prefix, 'expected asset rows require a version'); + } + const kindSet = kinds === undefined ? undefined : new Set(kinds); + if ( + kindSet !== undefined && + (kindSet.size === 0 || + [...kindSet].some((kind) => typeof kind !== 'string' || kind.length === 0)) + ) { + fail(prefix, 'expected asset row kinds must be a non-empty string list'); + } + const rows = allArtifactTargets({ product, surface }, prefix) + .filter((target) => kindSet === undefined || kindSet.has(target.kind)) + .map((target) => ({ + product: target.product, + kind: target.kind, + target: target.target, + surface, + artifactTarget: target.id, + assetName: target.asset.replaceAll('{version}', version), + })) + .sort((left, right) => compareText(left.assetName, right.assetName)); + if (rows.length === 0) { + fail(prefix, `${product} has no artifact targets for surface ${surface}`); + } + const names = rows.map((row) => row.assetName); + const duplicates = [ + ...new Set(names.filter((name, index) => names.indexOf(name) !== index)), + ].sort(compareText); + if (duplicates.length > 0) { + fail(prefix, `${product} has duplicate expected asset names: ${duplicates.join(', ')}`); + } + return rows; +} + +export function registryPackageRows( + { product, packageKind = undefined } = {}, + prefix = 'release-artifact-targets.mts', +) { + if (typeof product !== 'string' || product.length === 0) { + fail(prefix, 'registry package rows require a product'); + } + if (packageKind !== undefined && (typeof packageKind !== 'string' || packageKind.length === 0)) { + fail(prefix, 'registry package kind must be a non-empty string'); + } + const config = productConfig(product, prefix); + const declaredEntries = config.registry_packages ?? []; + if ( + !Array.isArray(declaredEntries) || + declaredEntries.some((entry) => typeof entry !== 'string') + ) { + fail(prefix, `${product}.registry_packages must be a string list`); + } + const entries = [...declaredEntries]; + const contrib = contribCarrierDescriptor(prefix); + if (product === contrib.nativeOwner || product === contrib.wasixOwner) { + const targets = extensionRegistryPackageTargetSets(contrib.artifactProduct, prefix); + if (product === contrib.nativeOwner) { + entries.push( + ...extensionNativeRegistryPackageStrings({ + product: contrib.artifactProduct, + androidTargets: targets.androidTargets, + npmTargets: targets.npmTargets, + nativeCargoTargets: targets.nativeCargoTargets, + }), + ); + } + if (product === contrib.wasixOwner) { + entries.push( + ...extensionWasixRegistryPackageStrings({ + product: contrib.artifactProduct, + includeAot: targets.includeWasixAot, + }), + ); + } + } + const rows = []; + const seen = new Set(); + for (const raw of entries) { + const separator = raw.indexOf(':'); + if (separator <= 0 || separator === raw.length - 1) { + fail(prefix, `${product}.registry_packages entry ${JSON.stringify(raw)} must use kind:name`); + } + const kind = raw.slice(0, separator); + const packageName = raw.slice(separator + 1); + const key = `${kind}\0${packageName}`; + if (seen.has(key)) { + fail(prefix, `${product} declares duplicate ${kind} registry package ${packageName}`); + } + seen.add(key); + if (packageKind !== undefined && kind !== packageKind) { + continue; + } + rows.push({ + product, + packageKind: kind, + packageName, + raw, + }); + } + return rows.sort( + (left, right) => + compareText(left.packageKind, right.packageKind) || + compareText(left.packageName, right.packageName), + ); +} + +const releaseMetadataCache = new Map(); + +export function releaseMetadata(product, prefix) { + const key = `${prefix}\0${product}`; + if (releaseMetadataCache.has(key)) return releaseMetadataCache.get(key); + const config = productConfig(product, prefix); + let directory = path.join(ROOT, config.path); + let release; + // Only literal product metadata is needed here. Dependency resolution stays in Moon. + while (directory !== ROOT) { + const file = path.join(directory, 'moon.yml'); + if (existsSync(file)) { + const project = Bun.YAML.parse(readFileSync(file, 'utf8')); + if (project.id !== product) + fail(prefix, `Moon project at ${rel(file)} does not own ${product}`); + release = project.project?.release; + break; + } + directory = path.dirname(directory); + if (!directory.startsWith(ROOT + path.sep)) break; + } + if (!release) { + fail(prefix, `Moon release metadata does not include ${product}`); + } + if (release.component !== product) { + fail(prefix, `Moon release metadata for ${product} must use matching component`); + } + if (release.packagePath !== config.path) { + fail(prefix, `Moon release metadata for ${product} must match package path ${config.path}`); + } + const expectedPreset = PRODUCT_PRESETS[product]; + if (expectedPreset !== undefined) { + const artifactTargets = release.artifactTargets; + if ( + typeof artifactTargets !== 'object' || + artifactTargets === null || + artifactTargets.preset !== expectedPreset + ) { + fail( + prefix, + `Moon release metadata for ${product} must use artifactTargets preset ${expectedPreset}`, + ); + } + } + releaseMetadataCache.set(key, release); + return release; +} + +const versionCache = new Map(); + +export function currentProductVersionSync(product, prefix = 'release-artifact-targets.mts') { + const key = `${prefix}\0${product}`; + if (!versionCache.has(key)) { + const versionFile = versionFiles(product, prefix)[0]; + if (typeof versionFile !== 'string' || !versionFile) { + fail(prefix, `${product} does not declare a canonical version file`); + } + const file = path.join(ROOT, versionFile); + const text = readFileSync(file, 'utf8'); + const name = path.basename(file); + let version = ''; + if (name === 'Cargo.toml') { + version = Bun.TOML.parse(text).package?.version ?? ''; + } else if (name === 'package.json') { + const data = JSON.parse(text); + version = typeof data.version === 'string' ? data.version : ''; + } else if (name === 'gradle.properties') { + for (const rawLine of text.split(/\r?\n/u)) { + const line = rawLine.trim(); + if (!line || line.startsWith('#') || !line.includes('=')) { + continue; + } + const [property, ...rest] = line.split('='); + if (property.trim() === 'VERSION_NAME') { + version = rest.join('=').trim(); + break; + } + } + } else if (name === 'VERSION' || name === 'LIBOLIPHAUNT_VERSION') { + version = text.trim(); + } else { + fail(prefix, `${product}.version_files has unsupported version file type: ${versionFile}`); + } + if (typeof version !== 'string' || !version) { + fail(prefix, `${versionFile} does not define a release version for ${product}`); + } + versionCache.set(key, version); + } + return versionCache.get(key); +} + +export async function currentProductVersion(product, prefix = 'release-artifact-targets.mts') { + return currentProductVersionSync(product, prefix); +} + +export function expectedAssets(product, kind, version, prefix) { + const assets = expectedAssetRows({ product, version, kinds: [kind] }, prefix).map( + (row) => row.assetName, + ); + assets.push(`${product}-${version}-release-assets.sha256`); + return assets.sort(compareText); +} + +function productConfig(product, prefix) { + const config = productConfigs(prefix)[product]; + if (!config) { + fail(prefix, `unknown release product ${product}`); + } + return config; +} + +export function exactExtensionProducts(prefix = 'release-artifact-targets.mts') { + const products = Object.entries(productConfigs(prefix)) + .filter(([, config]) => EXTENSION_PRODUCT_KINDS.has(config.kind)) + .map(([product]) => product); + products.push(contribCarrierDescriptor(prefix).artifactProduct); + return [...new Set(products)].sort(compareText); +} + +export function exactExtensionReleaseProducts(prefix = 'release-artifact-targets.mts') { + return Object.entries(productConfigs(prefix)) + .filter(([, config]) => EXTENSION_PRODUCT_KINDS.has(config.kind)) + .map(([product]) => product) + .sort(compareText); +} + +export function sdkPackageProducts(prefix = 'release-artifact-targets.mts') { + const rows = Object.entries(productConfigs(prefix)) + .filter( + ([, config]) => + config.kind === 'sdk' || + config.release_artifacts?.includes('cargo-crate') || + config.release_artifacts?.includes('npm-package'), + ) + .map(([product]) => ({ + product, + artifactName: + product === 'oliphaunt-wasix-rust' || product === 'postgres-tools-wasix' + ? `${product}-package-artifacts` + : `${product}-sdk-package-artifacts`, + })) + .sort((left, right) => compareText(left.product, right.product)); + if (rows.length === 0) { + fail(prefix, 'release graph contains no SDK package products'); + } + return rows; +} + +export function extensionSqlName(product, prefix = 'release-artifact-targets.mts') { + const names = extensionSqlNames(product, prefix); + if (names.length !== 1) { + fail( + prefix, + `${product} owns ${names.length} exact extension members; use extensionSqlNames(product)`, + ); + } + return names[0]; +} + +function contribMemberRows(product, prefix) { + const descriptor = contribCarrierDescriptor(prefix); + if (product !== descriptor.artifactProduct) { + fail(prefix, `${product} is not the shared PostgreSQL contrib artifact product`); + } + const manifestPath = descriptor.memberManifest; + const memberRoot = path.posix.dirname(manifestPath); + const rows = []; + const seenSqlNames = new Set(); + const seenIds = new Set(); + for (const [index, row] of descriptor.members.entries()) { + if (row === null || Array.isArray(row) || typeof row !== 'object') { + fail(prefix, `${manifestPath}.extensions[${index}] must be a table`); + } + const id = nonEmptyString(row.id, `${manifestPath}.extensions[${index}].id`, prefix); + const sqlName = nonEmptyString( + row['sql-name'], + `${manifestPath}.extensions[${index}].sql-name`, + prefix, + ); + if (seenIds.has(id) || seenSqlNames.has(sqlName)) { + fail( + prefix, + `${manifestPath} contains duplicate contrib member id or SQL name: ${id}/${sqlName}`, + ); + } + seenIds.add(id); + seenSqlNames.add(sqlName); + rows.push({ id, sqlName, path: memberRoot }); + } + return rows; +} + +export function extensionSqlNamesForProducts(products, prefix = 'release-artifact-targets.mts') { + const rows = [...products].flatMap((product) => + extensionSqlNames(product, prefix).map((sqlName) => ({ product, sqlName })), + ); + const productsBySqlName = new Map(); + for (const { product, sqlName } of rows) { + const existing = productsBySqlName.get(sqlName); + if (existing !== undefined) { + throw new Error( + `exact extension products ${existing} and ${product} share SQL name ${sqlName}`, + ); + } + productsBySqlName.set(sqlName, product); + } + return rows.map(({ sqlName }) => sqlName).sort(compareText); +} + +export function extensionSqlNames(product, prefix = 'release-artifact-targets.mts') { + const contrib = contribCarrierDescriptor(prefix); + if (product === contrib.artifactProduct) { + return contribMemberRows(product, prefix) + .map((row) => row.sqlName) + .sort(compareText); + } + const config = productConfig(product, prefix); + if (config.kind === 'exact-extension-artifact') { + const value = config.extension_sql_name; + if (typeof value !== 'string' || !value) { + fail(prefix, `${product} release.toml must declare extension_sql_name`); + } + if (config.extension_sql_names !== undefined) { + fail(prefix, `${product} singleton release metadata must not declare extension_sql_names`); + } + return [value]; + } + if (config.kind !== 'exact-extension-bundle') { + fail(prefix, `${product} is not an exact-extension product`); + } + const values = config.extension_sql_names; + if ( + !Array.isArray(values) || + values.length < 2 || + values.some((value) => typeof value !== 'string' || !value) + ) { + fail(prefix, `${product} exact-extension bundle must declare at least two extension_sql_names`); + } + const sorted = [...values].sort(compareText); + if (new Set(sorted).size !== sorted.length || JSON.stringify(values) !== JSON.stringify(sorted)) { + fail(prefix, `${product}.extension_sql_names must be unique and sorted`); + } + const manifestNames = contribMemberRows(product, prefix) + .map((row) => row.sqlName) + .sort(compareText); + if (JSON.stringify(sorted) !== JSON.stringify(manifestNames)) { + fail( + prefix, + `${product}.extension_sql_names must exactly match ${config.extension.member_manifest}`, + ); + } + return sorted; +} + +function extensionCatalogRows(prefix) { + if (extensionCatalogRowsCache !== undefined) return extensionCatalogRowsCache; + let catalog; + try { + catalog = JSON.parse(readFileSync(EXTENSION_CATALOG_PATH, 'utf8')); + } catch (error) { + fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} is not readable JSON: ${error.message}`); + } + if (catalog?.['format-version'] !== 1 || !Array.isArray(catalog.extensions)) { + fail( + prefix, + `${rel(EXTENSION_CATALOG_PATH)} must use format-version 1 and define extension rows`, + ); + } + const bySqlName = new Map(); + for (const [index, row] of catalog.extensions.entries()) { + const sqlName = row?.['sql-name']; + if (typeof sqlName !== 'string' || !sqlName) { + fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} extension row ${index} has no SQL name`); + } + if (bySqlName.has(sqlName)) { + fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} repeats SQL extension ${sqlName}`); + } + const moduleFile = row['native-module-file']; + if (moduleFile !== undefined && (typeof moduleFile !== 'string' || !moduleFile)) { + fail( + prefix, + `${rel(EXTENSION_CATALOG_PATH)} ${sqlName}.native-module-file must be a non-empty string when present`, + ); + } + bySqlName.set(sqlName, row); + } + extensionCatalogRowsCache = bySqlName; + return extensionCatalogRowsCache; +} + +export function extensionPublicDependencySqlNames( + sqlName, + prefix = 'release-artifact-targets.mts', +) { + nonEmptyString(sqlName, 'extension SQL name', prefix); + const rows = extensionCatalogRows(prefix); + const row = rows.get(sqlName); + if (row === undefined) { + fail(prefix, `${sqlName} is absent from ${rel(EXTENSION_CATALOG_PATH)}`); + } + const dependencies = row.dependencies ?? []; + if ( + !Array.isArray(dependencies) || + dependencies.some((value) => typeof value !== 'string' || !value) + ) { + fail( + prefix, + `${rel(EXTENSION_CATALOG_PATH)} ${sqlName}.dependencies must be an array of SQL names`, + ); + } + return [...new Set(dependencies.filter((dependency) => rows.has(dependency)))].sort(compareText); +} + +export function extensionWasixAotMemberSqlNames(product, prefix = 'release-artifact-targets.mts') { + const rows = extensionCatalogRows(prefix); + return extensionSqlNames(product, prefix).filter((sqlName) => { + const row = rows.get(sqlName); + if (row === undefined) { + fail(prefix, `${product} member ${sqlName} is absent from ${rel(EXTENSION_CATALOG_PATH)}`); + } + return typeof row['native-module-file'] === 'string'; + }); +} + +export function extensionProductForSqlName(sqlName, prefix = 'release-artifact-targets.mts') { + nonEmptyString(sqlName, 'extension SQL name', prefix); + const owners = exactExtensionProducts(prefix).filter((product) => + extensionSqlNames(product, prefix).includes(sqlName), + ); + if (owners.length !== 1) { + fail( + prefix, + `extension SQL name ${JSON.stringify(sqlName)} must have exactly one release product owner, found ${owners.join(', ') || 'none'}`, + ); + } + return owners[0]; +} + +export function extensionReleaseProductForSqlName( + sqlName, + family = 'native', + prefix = 'release-artifact-targets.mts', +) { + return extensionReleaseProduct(extensionProductForSqlName(sqlName, prefix), family, prefix); +} + +export function extensionMemberPath(product, sqlName, prefix = 'release-artifact-targets.mts') { + if (!extensionSqlNames(product, prefix).includes(sqlName)) { + fail(prefix, `${product} does not own extension SQL name ${JSON.stringify(sqlName)}`); + } + const contrib = contribCarrierDescriptor(prefix); + if (product === contrib.artifactProduct) { + const row = contribMemberRows(product, prefix).find( + (candidate) => candidate.sqlName === sqlName, + ); + if (row === undefined) { + fail(prefix, `${product} member manifest has no row for ${JSON.stringify(sqlName)}`); + } + return releaseMetadataRelativePath(row.path, `${product} member ${sqlName}`, prefix); + } + const config = productConfig(product, prefix); + if (config.kind === 'exact-extension-artifact') { + return packagePath(product, prefix); + } + fail(prefix, `${product} exact-extension bundle has no shared member descriptor`); +} + +function releaseMetadataRelativePath(value, context, prefix) { + const candidate = path.normalize(value).split(path.sep).join('/'); + if (path.isAbsolute(value) || candidate.split('/').includes('..')) { + fail(prefix, `${context} must be a repository-relative path: ${JSON.stringify(value)}`); + } + if (!existsSync(path.join(ROOT, candidate))) { + fail(prefix, `${context} path does not exist: ${candidate}`); + } + return candidate; +} + +function packagePath(product, prefix) { + return releaseMetadataRelativePath( + nonEmptyString(productConfig(product, prefix).path, `${product}.path`, prefix), + `${product}.path`, + prefix, + ); +} + +export function extensionMetadata(product, prefix = 'release-artifact-targets.mts') { + const contrib = contribCarrierDescriptor(prefix); + if (product === contrib.artifactProduct) { + const source = Bun.TOML.parse(readFileSync(path.join(ROOT, contrib.sourcePath), 'utf8')); + const postgresVersion = nonEmptyString( + source?.postgresql?.version, + `${contrib.sourcePath}.postgresql.version`, + prefix, + ); + const postgresMajor = postgresVersion.split('.')[0]; + if (!/^[1-9][0-9]*$/u.test(postgresMajor)) { + fail( + prefix, + `${contrib.sourcePath}.postgresql.version must begin with a stable major version`, + ); + } + return { + sqlName: undefined, + sqlNames: extensionSqlNames(product, prefix), + class: 'contrib', + versioning: 'runtime-bound', + sourcePath: contrib.sourcePath, + artifactProduct: contrib.artifactProduct, + compatibility: { + postgresMajor, + extensionRuntimeContract: contrib.runtimeContract, + nativeRuntimeProduct: contrib.nativeOwner, + nativeRuntimeVersion: currentProductVersionSync(contrib.nativeOwner, prefix), + wasixRuntimeProduct: contrib.wasixOwner, + wasixRuntimeVersion: currentProductVersionSync(contrib.wasixOwner, prefix), + }, + }; + } + const config = productConfig(product, prefix); + if (!EXTENSION_PRODUCT_KINDS.has(config.kind)) { + fail(prefix, `${product} is not an exact-extension product`); + } + const sqlNames = extensionSqlNames(product, prefix); + const metadata = config.extension; + if (metadata === null || Array.isArray(metadata) || typeof metadata !== 'object') { + fail(prefix, `${product} release metadata must declare [extension]`); + } + let sqlName; + if (config.kind === 'exact-extension-artifact') { + sqlName = nonEmptyString(metadata.sql_name, `${product}.extension.sql_name`, prefix); + if (sqlName !== sqlNames[0]) { + fail( + prefix, + `${product}.extension.sql_name ${JSON.stringify(sqlName)} must match extension_sql_name ${JSON.stringify(sqlNames[0])}`, + ); + } + if (metadata.member_manifest !== undefined) { + fail(prefix, `${product} singleton extension metadata must not declare member_manifest`); + } + } else { + if (metadata.sql_name !== undefined) { + fail(prefix, `${product} extension bundle must not declare extension.sql_name`); + } + fail(prefix, `${product} extension bundle has no shared member descriptor`); + } + const extensionClass = nonEmptyString(metadata.class, `${product}.extension.class`, prefix); + if (!(extensionClass in EXTENSION_VERSIONING_BY_CLASS)) { + fail( + prefix, + `${product}.extension.class must be one of ${Object.keys(EXTENSION_VERSIONING_BY_CLASS).sort(compareText).join(', ')}`, + ); + } + const versioning = nonEmptyString(metadata.versioning, `${product}.extension.versioning`, prefix); + const expectedVersioning = EXTENSION_VERSIONING_BY_CLASS[extensionClass]; + if (versioning !== expectedVersioning) { + fail( + prefix, + `${product}.extension.versioning must be ${JSON.stringify(expectedVersioning)} for class ${JSON.stringify(extensionClass)}, got ${JSON.stringify(versioning)}`, + ); + } + const source = metadata.source; + if (source === null || Array.isArray(source) || typeof source !== 'object') { + fail(prefix, `${product}.extension must declare [extension.source]`); + } + const sourcePath = releaseMetadataRelativePath( + nonEmptyString(source.path, `${product}.extension.source.path`, prefix), + `${product}.extension.source.path`, + prefix, + ); + const packageRoot = packagePath(product, prefix); + if (extensionClass === 'contrib' && sourcePath !== contrib.sourcePath) { + fail( + prefix, + `${product}.extension.source.path must match the shared contrib source ${JSON.stringify(contrib.sourcePath)}`, + ); + } + if (extensionClass === 'external' && sourcePath !== `${packageRoot}/source.toml`) { + fail( + prefix, + `${product}.extension.source.path must be ${packageRoot}/source.toml for external extensions`, + ); + } + if ( + extensionClass === 'first-party' && + !(sourcePath === packageRoot || sourcePath.startsWith(`${packageRoot}/`)) + ) { + fail( + prefix, + `${product}.extension.source.path must stay inside ${packageRoot}/ for first-party extensions`, + ); + } + + const compatibility = metadata.compatibility; + if (compatibility === null || Array.isArray(compatibility) || typeof compatibility !== 'object') { + fail(prefix, `${product}.extension must declare [extension.compatibility]`); + } + const postgresMajor = nonEmptyString( + compatibility.postgres_major, + `${product}.extension.compatibility.postgres_major`, + prefix, + ); + if (postgresMajor !== '18') { + fail( + prefix, + `${product}.extension.compatibility.postgres_major must be '18', got ${JSON.stringify(postgresMajor)}`, + ); + } + const contractPath = releaseMetadataRelativePath( + nonEmptyString( + compatibility.extension_runtime_contract, + `${product}.extension.compatibility.extension_runtime_contract`, + prefix, + ), + `${product}.extension.compatibility.extension_runtime_contract`, + prefix, + ); + if (contractPath !== contrib.runtimeContract) { + fail( + prefix, + `${product}.extension.compatibility.extension_runtime_contract must match ${JSON.stringify(contrib.runtimeContract)}`, + ); + } + const nativeProduct = nonEmptyString( + compatibility.native_runtime_product, + `${product}.extension.compatibility.native_runtime_product`, + prefix, + ); + const wasixProduct = nonEmptyString( + compatibility.wasix_runtime_product, + `${product}.extension.compatibility.wasix_runtime_product`, + prefix, + ); + if (nativeProduct !== 'liboliphaunt-native') { + fail( + prefix, + `${product}.extension.compatibility.native_runtime_product must be 'liboliphaunt-native'`, + ); + } + if (wasixProduct !== 'liboliphaunt-wasix') { + fail( + prefix, + `${product}.extension.compatibility.wasix_runtime_product must be 'liboliphaunt-wasix'`, + ); + } + const nativeVersion = nonEmptyString( + compatibility.native_runtime_version, + `${product}.extension.compatibility.native_runtime_version`, + prefix, + ); + const wasixVersion = nonEmptyString( + compatibility.wasix_runtime_version, + `${product}.extension.compatibility.wasix_runtime_version`, + prefix, + ); + return { + sqlName, + sqlNames, + artifactProduct: product, + class: extensionClass, + versioning, + sourcePath, + compatibility: { + postgresMajor, + extensionRuntimeContract: contractPath, + nativeRuntimeProduct: nativeProduct, + nativeRuntimeVersion: nativeVersion, + wasixRuntimeProduct: wasixProduct, + wasixRuntimeVersion: wasixVersion, + }, + }; +} + +export function extensionSourceIdentity(product, prefix = 'release-artifact-targets.mts') { + const metadata = extensionMetadata(product, prefix); + const source = Bun.TOML.parse(readFileSync(path.join(ROOT, metadata.sourcePath), 'utf8')); + if (metadata.class === 'contrib') { + const postgresql = source.postgresql; + if (postgresql === null || Array.isArray(postgresql) || typeof postgresql !== 'object') { + fail( + prefix, + `${metadata.sourcePath} must declare [postgresql] for contrib extension products`, + ); + } + return { + kind: 'postgres-contrib', + name: 'postgresql', + version: nonEmptyString( + postgresql.version, + `${metadata.sourcePath}.postgresql.version`, + prefix, + ), + url: nonEmptyString(postgresql.url, `${metadata.sourcePath}.postgresql.url`, prefix), + sha256: nonEmptyString(postgresql.sha256, `${metadata.sourcePath}.postgresql.sha256`, prefix), + }; + } + if (metadata.class === 'external') { + return { + kind: 'external', + name: nonEmptyString(source.name, `${metadata.sourcePath}.name`, prefix), + url: nonEmptyString(source.url, `${metadata.sourcePath}.url`, prefix), + branch: nonEmptyString(source.branch, `${metadata.sourcePath}.branch`, prefix), + commit: nonEmptyString(source.commit, `${metadata.sourcePath}.commit`, prefix), + }; + } + if (metadata.class === 'first-party') { + return { + kind: 'repo', + name: metadata.sqlName ?? product, + path: metadata.sourcePath, + version: currentProductVersionSync(product, prefix), + }; + } + fail( + prefix, + `${product}.extension.class has unsupported source identity class ${JSON.stringify(metadata.class)}`, + ); +} + +function wasixExtensionTargetId(runtimeTarget) { + return runtimeTarget === 'portable' ? 'wasix-portable' : runtimeTarget; +} + +function runtimeExtensionTargetRows(prefix) { + const rows = []; + for (const target of allArtifactTargets( + { product: 'liboliphaunt-native', kind: 'native-runtime' }, + prefix, + )) { + if (!target.extensionArtifacts) { + continue; + } + rows.push({ + target: target.target, + family: 'native', + kind: + target.target === 'ios-xcframework' || target.target.startsWith('android-') + ? 'native-static-registry' + : 'native-dynamic', + }); + } + for (const target of allArtifactTargets( + { product: 'liboliphaunt-wasix', kind: 'wasix-runtime' }, + prefix, + )) { + rows.push({ + target: wasixExtensionTargetId(target.target), + family: 'wasix', + kind: 'wasix-runtime', + }); + } + if (rows.length === 0) { + fail(prefix, 'could not derive any exact-extension artifact targets from runtime products'); + } + return rows; +} + +function readExtensionTargetRows(prefix) { + const relative = EXTENSION_TARGET_PROFILES_RELATIVE_PATH; + const allowed = new Set( + runtimeExtensionTargetRows(prefix).map((row) => `${row.target}\0${row.family}\0${row.kind}`), + ); + const rows = loadExtensionTargetProfiles().targets; + for (const row of rows) { + if (!allowed.has(`${row.target}\0${row.family}\0${row.kind}`)) { + fail( + prefix, + `${relative} target row ${row.target}/${row.family}/${row.kind} is not backed by runtime artifact metadata`, + ); + } + } + return rows; +} + +function nonEmptyString(value, label, prefix) { + if (typeof value === 'string' && value.length > 0) { + return value; + } + fail(prefix, `${label} must be a non-empty string`); +} + +export function extensionArtifactTargets( + { product = undefined, family = undefined } = {}, + prefix = 'release-artifact-targets.mts', +) { + const products = product === undefined ? exactExtensionProducts(prefix) : [product]; + const parsed = []; + for (const productId of products) { + if (!exactExtensionProducts(prefix).includes(productId)) { + fail(prefix, `${productId} is not an exact-extension artifact product`); + } + for (const sqlName of extensionSqlNames(productId, prefix)) { + const seen = new Set(); + for (const [index, row] of readExtensionTargetRows(prefix).entries()) { + const source = EXTENSION_TARGET_PROFILES_RELATIVE_PATH; + const target = nonEmptyString(row.target, `${source} targets[${index}].target`, prefix); + const targetFamily = nonEmptyString( + row.family, + `${source} targets[${index}].family`, + prefix, + ); + const kind = nonEmptyString(row.kind, `${source} targets[${index}].kind`, prefix); + if (!EXTENSION_FAMILIES.has(targetFamily)) { + fail(prefix, `${source} target ${target} has invalid family ${targetFamily}`); + } + if (!EXTENSION_KINDS.has(kind)) { + fail(prefix, `${source} target ${target} has invalid kind ${kind}`); + } + if (targetFamily === 'wasix' && kind !== 'wasix-runtime') { + fail(prefix, `${source} target ${target} must use kind wasix-runtime for wasix family`); + } + if (targetFamily === 'native' && kind === 'wasix-runtime') { + fail(prefix, `${source} target ${target} cannot use wasix-runtime for native family`); + } + const key = `${target}\0${targetFamily}\0${kind}`; + if (seen.has(key)) { + fail(prefix, `${source} has duplicate target row ${target}/${targetFamily}/${kind}`); + } + seen.add(key); + if (family !== undefined && targetFamily !== family) { + continue; + } + const binaryCompatibility = + targetFamily === 'native' + ? requiredBinaryCompatibility(target, `${productId} native extension`, prefix) + : undefined; + parsed.push({ + product: productId, + sqlName, + sql_name: sqlName, + target, + family: targetFamily, + kind, + source_file: source, + binaryCompatibility, + binary_compatibility: binaryCompatibility, + }); + } + } + } + return parsed; +} + +export function extensionTargetIds({ family }, prefix = 'release-artifact-targets.mts') { + return [ + ...new Set(extensionArtifactTargets({ family }, prefix).map((target) => target.target)), + ].sort(compareText); +} + +function extensionPublishedTargets(product, family, kind, prefix) { + return [ + ...new Set( + extensionArtifactTargets({ product, family }, prefix) + .filter((target) => target.kind === kind) + .map((target) => target.target), + ), + ].sort(compareText); +} + +export function extensionRegistryPackageTargetSets( + product, + prefix = 'release-artifact-targets.mts', +) { + const memberSignatures = extensionSqlNames(product, prefix).map((sqlName) => { + const rows = extensionArtifactTargets({ product }, prefix) + .filter((row) => row.sqlName === sqlName) + .map((row) => `${row.target}\0${row.family}\0${row.kind}`) + .sort(compareText); + return { sqlName, rows }; + }); + const baseline = JSON.stringify(memberSignatures[0]?.rows ?? []); + const mismatched = memberSignatures + .filter(({ rows }) => JSON.stringify(rows) !== baseline) + .map(({ sqlName }) => sqlName); + if (mismatched.length > 0) { + fail( + prefix, + `${product} bundle members must publish an identical target carrier set; mismatched members: ${mismatched.join(', ')}`, + ); + } + const nativeDynamicTargets = extensionPublishedTargets( + product, + 'native', + 'native-dynamic', + prefix, + ); + if (nativeDynamicTargets.length === 0) { + fail(prefix, `${product} has no native dynamic extension registry targets`); + } + const androidTargets = extensionPublishedTargets( + product, + 'native', + 'native-static-registry', + prefix, + ).filter((target) => target.startsWith('android-')); + const wasixRuntimeTargets = extensionPublishedTargets(product, 'wasix', 'wasix-runtime', prefix); + const wasixAotMembers = extensionWasixAotMemberSqlNames(product, prefix); + return { + androidTargets, + npmTargets: nativeDynamicTargets, + nativeCargoTargets: nativeDynamicTargets, + includeWasixNpm: wasixRuntimeTargets.includes('wasix-portable'), + // An AOT carrier is meaningful only when at least one exact SQL member has + // a native module to precompile. SQL/resource-only products still publish + // their portable archive but must not reserve empty host-AOT identities. + includeWasixAot: wasixRuntimeTargets.includes('wasix-portable') && wasixAotMembers.length > 0, + }; +} diff --git a/tools/release/release-asset-validation.mjs b/tools/release/release-asset-validation.mjs deleted file mode 100644 index e8d15ecea..000000000 --- a/tools/release/release-asset-validation.mjs +++ /dev/null @@ -1,39 +0,0 @@ -import { createHash } from "node:crypto"; -import fs from "node:fs/promises"; -import path from "node:path"; - -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -export async function assertFileExists(file) { - const stat = await fs.stat(file).catch(() => null); - return stat?.isFile() === true; -} - -export async function sha256(file) { - return createHash("sha256").update(await fs.readFile(file)).digest("hex"); -} - -export async function checksumManifest(file, fail, prefix) { - const values = new Map(); - const lines = (await fs.readFile(file, "utf8")).split(/\r?\n/u); - for (const [index, rawLine] of lines.entries()) { - const line = rawLine.trim(); - if (!line) { - continue; - } - const parts = line.split(/\s+/u); - if (parts.length < 2 || parts[0].length !== 64) { - fail(prefix, `malformed checksum line ${index + 1}: ${rawLine}`); - } - values.set(parts.slice(1).join(" ").replace(/^\.\//u, ""), parts[0].toLowerCase()); - } - return values; -} - -export async function readArchiveEntries(file, fail, prefix, productLabel) { - try { - return readPortableArchiveEntries(file); - } catch (error) { - fail(prefix, `${path.basename(file)} is not a valid ${productLabel} archive: ${error.message}`); - } -} diff --git a/tools/release/release-candidate-lib.test.mjs b/tools/release/release-candidate-lib.test.mjs deleted file mode 100644 index f1a48e601..000000000 --- a/tools/release/release-candidate-lib.test.mjs +++ /dev/null @@ -1,289 +0,0 @@ -import { expect, test } from "bun:test"; -import { - mkdtempSync, - mkdirSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { - affectedPlanBinding, - assertBindingMatches, - assertCandidateBindingShape, - candidateQualificationMode, - wasixEvidenceBinding, -} from "../../.github/scripts/release-candidate-lib.mjs"; - -function fixture() { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-release-candidate-")); - const cleanup = () => rmSync(root, { recursive: true, force: true }); - return { root, cleanup }; -} - -function publicExtensions() { - const catalog = JSON.parse(readFileSync("src/extensions/generated/extensions.catalog.json", "utf8")); - return catalog.extensions - .map((extension) => extension.id) - .sort(); -} - -function writeEvidence( - root, - { - extensions = publicExtensions(), - runAttempt = 1, - job = "wasix-release-regression", - } = {}, -) { - const runDirectory = path.join(root, "src/extensions/evidence/runs"); - mkdirSync(runDirectory, { recursive: true }); - const run = { - schema: "oliphaunt-extension-evidence-v1", - id: "2026-07-14T120000Z-ci-123456789-1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - evidenceTier: "wasix-full-lifecycle-v1", - status: "passed", - sourceDigest: `sha256:${"b".repeat(64)}`, - sourceDigestInputs: ["z-input", "a-input"], - sourceCommit: "a".repeat(40), - sourceTree: "c".repeat(40), - observedAt: "2026-07-14T12:00:00Z", - collector: "src/extensions/tools/collect-wasix-evidence.sh", - github: { - repository: "f0rr0/oliphaunt", - workflow: "CI", - runId: 123456789, - runAttempt, - job, - }, - results: extensions.map((extension) => ({ - extension, - sqlName: extension, - postgresMajor: 18, - artifactFamily: "wasix-runtime", - platformTarget: "portable", - runtimeModeStatuses: { - direct: "passed", - server: "passed", - restart: "passed", - "dump-restore": "passed", - }, - })), - }; - writeFileSync(path.join(runDirectory, `${run.id}.json`), `${JSON.stringify(run, null, 2)}\n`); -} - -test("binds the canonical affected plan and conditional WASIX evidence", () => { - const { root, cleanup } = fixture(); - try { - const planPath = path.join(root, "ci-plan.json"); - writeFileSync(planPath, `${JSON.stringify({ - projects: ["liboliphaunt-wasix"], - jobs: ["affected", "liboliphaunt-wasix-runtime"], - extension_package_products: [], - reason: "test", - }, null, 2)}\n`); - const plan = affectedPlanBinding(planPath, true); - writeEvidence(root); - const evidence = wasixEvidenceBinding(root, { - repository: "f0rr0/oliphaunt", - workflow: "CI", - runId: "123456789", - runAttempt: 1, - sha: "a".repeat(40), - tree: "c".repeat(40), - }); - const candidate = { - schemaVersion: 2, - affectedPlan: plan, - evidenceRequirements: { - wasixReleaseRegression: true, - artifacts: ["wasix-release-regression-evidence"], - }, - evidence: { wasixReleaseRegression: evidence }, - }; - expect(() => assertCandidateBindingShape(candidate)).not.toThrow(); - expect(evidence.github.runId).toBe(123456789); - expect(evidence.resultCount).toBe(publicExtensions().length); - } finally { - cleanup(); - } -}); - -test("rejects an incomplete WASIX evidence result set", () => { - const { root, cleanup } = fixture(); - try { - writeEvidence(root, { extensions: publicExtensions().slice(1) }); - expect(() => wasixEvidenceBinding(root, { - repository: "f0rr0/oliphaunt", - workflow: "CI", - runId: "123456789", - runAttempt: 1, - sha: "a".repeat(40), - tree: "c".repeat(40), - })).toThrow("every and only public extension"); - } finally { - cleanup(); - } -}); - -test("rejects a plan requirement that disagrees with selected jobs", () => { - const { root, cleanup } = fixture(); - try { - const planPath = path.join(root, "ci-plan.json"); - writeFileSync(planPath, JSON.stringify({ - projects: ["oliphaunt-js"], - jobs: ["affected", "js-sdk-package"], - extension_package_products: [], - })); - expect(() => affectedPlanBinding(planPath, true)).toThrow("jobs imply false"); - } finally { - cleanup(); - } -}); - -test("rejects substituted evidence bytes even when provenance fields still match", () => { - const { root, cleanup } = fixture(); - try { - writeEvidence(root); - const expected = wasixEvidenceBinding(root, { - repository: "f0rr0/oliphaunt", - workflow: "CI", - runId: "123456789", - runAttempt: 1, - sha: "a".repeat(40), - tree: "c".repeat(40), - }); - const evidencePath = path.join(root, expected.file); - const substituted = JSON.parse(readFileSync(evidencePath, "utf8")); - substituted.notes = "substituted bytes with otherwise matching provenance"; - writeFileSync(evidencePath, `${JSON.stringify(substituted, null, 2)}\n`); - const actual = wasixEvidenceBinding(root, { - repository: "f0rr0/oliphaunt", - workflow: "CI", - runId: "123456789", - runAttempt: 1, - sha: "a".repeat(40), - tree: "c".repeat(40), - }); - expect(() => assertBindingMatches(expected, actual, "WASIX evidence")).toThrow("does not match"); - } finally { - cleanup(); - } -}); - -test("accepts WASIX evidence from an earlier attempt of the same run and source", () => { - const { root, cleanup } = fixture(); - try { - writeEvidence(root, { runAttempt: 1 }); - const evidence = wasixEvidenceBinding(root, { - repository: "f0rr0/oliphaunt", - workflow: "CI", - runId: "123456789", - runAttempt: 2, - sha: "a".repeat(40), - tree: "c".repeat(40), - }); - expect(evidence.github.runAttempt).toBe(1); - } finally { - cleanup(); - } -}); - -test("rejects newer-attempt or provenance-mismatched WASIX evidence", () => { - const attemptFixture = fixture(); - try { - writeEvidence(attemptFixture.root, { runAttempt: 2 }); - expect(() => wasixEvidenceBinding(attemptFixture.root, { - repository: "f0rr0/oliphaunt", - workflow: "CI", - runId: "123456789", - runAttempt: 1, - sha: "a".repeat(40), - tree: "c".repeat(40), - })).toThrow("must not be newer than the candidate attempt"); - } finally { - attemptFixture.cleanup(); - } - - const provenanceFixture = fixture(); - try { - writeEvidence(provenanceFixture.root); - const expected = { - repository: "f0rr0/oliphaunt", - workflow: "CI", - runId: "123456789", - runAttempt: 1, - sha: "a".repeat(40), - tree: "c".repeat(40), - }; - expect(() => wasixEvidenceBinding(provenanceFixture.root, { - ...expected, - runId: "987654321", - })).toThrow("GitHub runId mismatch"); - expect(() => wasixEvidenceBinding(provenanceFixture.root, { - ...expected, - sha: "d".repeat(40), - })).toThrow("sourceCommit mismatch"); - expect(() => wasixEvidenceBinding(provenanceFixture.root, { - ...expected, - tree: "d".repeat(40), - })).toThrow("sourceTree mismatch"); - } finally { - provenanceFixture.cleanup(); - } -}); - -test("rejects a changed selected-product set even when WASIX remains required", () => { - const { root, cleanup } = fixture(); - try { - const firstPath = path.join(root, "first-plan.json"); - const secondPath = path.join(root, "second-plan.json"); - const base = { - projects: ["extensions"], - jobs: ["affected", "liboliphaunt-wasix-runtime"], - }; - writeFileSync(firstPath, JSON.stringify({ - ...base, - extension_package_products: ["oliphaunt-extension-vector"], - })); - writeFileSync(secondPath, JSON.stringify({ - ...base, - extension_package_products: ["oliphaunt-extension-postgis"], - })); - const expected = affectedPlanBinding(firstPath, true); - const actual = affectedPlanBinding(secondPath, true); - expect(() => assertBindingMatches(expected, actual, "affected plan")).toThrow("does not match"); - } finally { - cleanup(); - } -}); - -test("keeps legacy F4 qualification plans backward-compatible as full-payload", () => { - const { root, cleanup } = fixture(); - try { - const planPath = path.join(root, "legacy-plan.json"); - writeFileSync(planPath, JSON.stringify({ - projects: [], - jobs: ["affected"], - extension_package_products: [], - })); - const affectedPlan = affectedPlanBinding(planPath, false); - const candidate = { - schemaVersion: 2, - affectedPlan, - evidenceRequirements: { - wasixReleaseRegression: false, - artifacts: [], - }, - evidence: { wasixReleaseRegression: null }, - }; - expect(affectedPlan.qualification).toBeUndefined(); - expect(candidateQualificationMode(candidate)).toBe("full-payload"); - expect(() => assertCandidateBindingShape(candidate)).not.toThrow(); - } finally { - cleanup(); - } -}); diff --git a/tools/release/release-candidate-lib.test.mts b/tools/release/release-candidate-lib.test.mts new file mode 100644 index 000000000..0b2ac5a58 --- /dev/null +++ b/tools/release/release-candidate-lib.test.mts @@ -0,0 +1,414 @@ +import { expect, test } from 'bun:test'; +import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; + +import { + affectedPlanBinding, + assertBindingMatches, + assertCandidateBindingShape, + candidateQualificationMode, + assertQualificationProductCoverage, + wasixEvidenceBinding, +} from '../../.github/scripts/release-candidate-lib.mts'; + +function fixture() { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-release-candidate-')); + const cleanup = () => rmSync(root, { recursive: true, force: true }); + return { root, cleanup }; +} + +test('selected-product evidence binds scope and candidate SHA and rejects uncovered publication', () => { + const { root, cleanup } = fixture(); + try { + const planPath = path.join(root, 'plan.json'); + const sha = 'a'.repeat(40); + writeFileSync( + planPath, + JSON.stringify({ + qualification_mode: 'selected-products', + qualification_base_sha: null, + qualification_head_sha: sha, + qualification_products: ['oliphaunt-js'], + tasks: ['oliphaunt-js:package', 'oliphaunt-query-ts:package'], + projects: ['oliphaunt-js'], + jobs: ['affected', 'js-sdk-package'], + extension_package_products: [], + }), + ); + const candidate = { + schemaVersion: 2, + sha, + affectedPlan: affectedPlanBinding(planPath, false), + evidenceRequirements: { wasixReleaseRegression: false, artifacts: [] }, + evidence: { wasixReleaseRegression: null }, + }; + expect(() => assertCandidateBindingShape(candidate)).not.toThrow(); + expect(() => assertQualificationProductCoverage(candidate, ['oliphaunt-js'])).not.toThrow(); + expect(() => assertQualificationProductCoverage(candidate, ['liboliphaunt-native'])).toThrow( + /missing qualification/, + ); + expect(() => assertQualificationProductCoverage(candidate, [])).toThrow(/non-empty/); + expect(() => assertCandidateBindingShape({ ...candidate, sha: 'b'.repeat(40) })).toThrow( + /candidate SHA/, + ); + const receipt = { + target: 'oliphaunt-query-ts:package', + eligible: true, + cacheHit: true, + taskHash: 'c'.repeat(64), + hashes: [{ target: 'oliphaunt-query-ts:package', hash: 'c'.repeat(64), dependencies: {} }], + producer: { sha, runId: '77', runAttempt: 2 }, + artifact: { id: 901, name: 'query', size: 42, digest: `sha256:${'d'.repeat(64)}` }, + toolchain: { + moon: 'moon 2.5.4', + bun: '1.4.2', + typescript: '6.0.3', + target: 'portable-typescript', + }, + }; + const recorded = { ...candidate, runId: '77', runAttempt: 2, producers: [receipt] }; + expect(() => assertCandidateBindingShape(recorded)).not.toThrow(); + expect(() => + assertCandidateBindingShape({ + ...recorded, + producers: [{ ...receipt, taskHash: undefined, hashes: [] }], + }), + ).toThrow(/producer hash chain is inconsistent/); + expect(() => assertCandidateBindingShape({ ...recorded, runAttempt: 3 })).toThrow( + /qualification run and attempt/, + ); + receipt.hashes[0].dependencies = { 'query:build': 'passthrough' }; + expect(() => assertCandidateBindingShape(recorded)).toThrow(/dependency hash is incomplete/); + } finally { + cleanup(); + } +}); + +function publicExtensions() { + const catalog = JSON.parse( + readFileSync('src/extensions/generated/extensions.catalog.json', 'utf8'), + ); + return catalog.extensions.map((extension) => extension.id).sort(); +} + +function writeEvidence( + root, + { + extensions = publicExtensions(), + runAttempt = 1, + job = 'wasix-release-regression', + runtimeModeStatuses = { + direct: 'passed', + server: 'passed', + restart: 'passed', + 'dump-restore': 'passed', + }, + } = {}, +) { + const runDirectory = path.join(root, 'src/extensions/evidence/runs'); + mkdirSync(runDirectory, { recursive: true }); + const run = { + schema: 'oliphaunt-extension-evidence-v1', + id: '2026-07-14T120000Z-ci-123456789-1-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + evidenceTier: 'wasix-full-lifecycle-v1', + status: 'passed', + sourceDigest: `sha256:${'b'.repeat(64)}`, + sourceDigestInputs: ['z-input', 'a-input'], + sourceCommit: 'a'.repeat(40), + sourceTree: 'c'.repeat(40), + observedAt: '2026-07-14T12:00:00Z', + collector: 'src/extensions/tools/collect-wasix-evidence.sh', + github: { + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + runId: 123456789, + runAttempt, + job, + }, + results: extensions.map((extension) => ({ + extension, + sqlName: extension, + postgresMajor: 18, + artifactFamily: 'wasix-runtime', + platformTarget: 'portable', + runtimeModeStatuses, + })), + }; + writeFileSync(path.join(runDirectory, `${run.id}.json`), `${JSON.stringify(run, null, 2)}\n`); +} + +test('binds the canonical affected plan and conditional WASIX evidence', () => { + const { root, cleanup } = fixture(); + try { + const planPath = path.join(root, 'ci-plan.json'); + writeFileSync( + planPath, + `${JSON.stringify( + { + projects: ['liboliphaunt-wasix'], + jobs: ['affected', 'liboliphaunt-wasix-runtime'], + extension_package_products: [], + reason: 'test', + }, + null, + 2, + )}\n`, + ); + const plan = affectedPlanBinding(planPath, true); + writeEvidence(root); + const evidence = wasixEvidenceBinding(root, { + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + runId: '123456789', + runAttempt: 1, + sha: 'a'.repeat(40), + tree: 'c'.repeat(40), + }); + const candidate = { + schemaVersion: 2, + affectedPlan: plan, + evidenceRequirements: { + wasixReleaseRegression: true, + artifacts: ['wasix-release-regression-evidence'], + }, + evidence: { wasixReleaseRegression: evidence }, + }; + expect(() => assertCandidateBindingShape(candidate)).not.toThrow(); + expect(evidence.github.runId).toBe(123456789); + expect(evidence.resultCount).toBe(publicExtensions().length); + } finally { + cleanup(); + } +}); + +test('physical backup evidence requires both restoration and materialization to pass', () => { + const { root, cleanup } = fixture(); + const provenance = { + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + runId: '123456789', + runAttempt: 1, + sha: 'a'.repeat(40), + tree: 'c'.repeat(40), + }; + const modes = { + direct: 'passed', + server: 'passed', + restart: 'passed', + 'backup-restore': 'passed', + materialization: 'passed', + }; + try { + writeEvidence(root, { runtimeModeStatuses: modes }); + expect(wasixEvidenceBinding(root, provenance).resultCount).toBe(publicExtensions().length); + for (const mode of ['backup-restore', 'materialization']) { + for (const status of ['failed', undefined]) { + writeEvidence(root, { runtimeModeStatuses: { ...modes, [mode]: status } }); + expect(() => wasixEvidenceBinding(root, provenance)).toThrow('status mismatch'); + } + } + } finally { + cleanup(); + } +}); + +test('rejects an incomplete WASIX evidence result set', () => { + const { root, cleanup } = fixture(); + try { + writeEvidence(root, { extensions: publicExtensions().slice(1) }); + expect(() => + wasixEvidenceBinding(root, { + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + runId: '123456789', + runAttempt: 1, + sha: 'a'.repeat(40), + tree: 'c'.repeat(40), + }), + ).toThrow('every and only public extension'); + } finally { + cleanup(); + } +}); + +test('rejects a plan requirement that disagrees with selected jobs', () => { + const { root, cleanup } = fixture(); + try { + const planPath = path.join(root, 'ci-plan.json'); + writeFileSync( + planPath, + JSON.stringify({ + projects: ['oliphaunt-js'], + jobs: ['affected', 'js-sdk-package'], + extension_package_products: [], + }), + ); + expect(() => affectedPlanBinding(planPath, true)).toThrow('jobs imply false'); + } finally { + cleanup(); + } +}); + +test('rejects substituted evidence bytes even when provenance fields still match', () => { + const { root, cleanup } = fixture(); + try { + writeEvidence(root); + const expected = wasixEvidenceBinding(root, { + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + runId: '123456789', + runAttempt: 1, + sha: 'a'.repeat(40), + tree: 'c'.repeat(40), + }); + const evidencePath = path.join(root, expected.file); + const substituted = JSON.parse(readFileSync(evidencePath, 'utf8')); + substituted.notes = 'substituted bytes with otherwise matching provenance'; + writeFileSync(evidencePath, `${JSON.stringify(substituted, null, 2)}\n`); + const actual = wasixEvidenceBinding(root, { + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + runId: '123456789', + runAttempt: 1, + sha: 'a'.repeat(40), + tree: 'c'.repeat(40), + }); + expect(() => assertBindingMatches(expected, actual, 'WASIX evidence')).toThrow( + 'does not match', + ); + } finally { + cleanup(); + } +}); + +test('accepts WASIX evidence from an earlier attempt of the same run and source', () => { + const { root, cleanup } = fixture(); + try { + writeEvidence(root, { runAttempt: 1 }); + const evidence = wasixEvidenceBinding(root, { + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + runId: '123456789', + runAttempt: 2, + sha: 'a'.repeat(40), + tree: 'c'.repeat(40), + }); + expect(evidence.github.runAttempt).toBe(1); + } finally { + cleanup(); + } +}); + +test('rejects newer-attempt or provenance-mismatched WASIX evidence', () => { + const attemptFixture = fixture(); + try { + writeEvidence(attemptFixture.root, { runAttempt: 2 }); + expect(() => + wasixEvidenceBinding(attemptFixture.root, { + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + runId: '123456789', + runAttempt: 1, + sha: 'a'.repeat(40), + tree: 'c'.repeat(40), + }), + ).toThrow('must not be newer than the candidate attempt'); + } finally { + attemptFixture.cleanup(); + } + + const provenanceFixture = fixture(); + try { + writeEvidence(provenanceFixture.root); + const expected = { + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + runId: '123456789', + runAttempt: 1, + sha: 'a'.repeat(40), + tree: 'c'.repeat(40), + }; + expect(() => + wasixEvidenceBinding(provenanceFixture.root, { + ...expected, + runId: '987654321', + }), + ).toThrow('GitHub runId mismatch'); + expect(() => + wasixEvidenceBinding(provenanceFixture.root, { + ...expected, + sha: 'd'.repeat(40), + }), + ).toThrow('sourceCommit mismatch'); + expect(() => + wasixEvidenceBinding(provenanceFixture.root, { + ...expected, + tree: 'd'.repeat(40), + }), + ).toThrow('sourceTree mismatch'); + } finally { + provenanceFixture.cleanup(); + } +}); + +test('rejects a changed selected-product set even when WASIX remains required', () => { + const { root, cleanup } = fixture(); + try { + const firstPath = path.join(root, 'first-plan.json'); + const secondPath = path.join(root, 'second-plan.json'); + const base = { + projects: ['extensions'], + jobs: ['affected', 'liboliphaunt-wasix-runtime'], + }; + writeFileSync( + firstPath, + JSON.stringify({ + ...base, + extension_package_products: ['oliphaunt-extension-vector'], + }), + ); + writeFileSync( + secondPath, + JSON.stringify({ + ...base, + extension_package_products: ['oliphaunt-extension-postgis'], + }), + ); + const expected = affectedPlanBinding(firstPath, true); + const actual = affectedPlanBinding(secondPath, true); + expect(() => assertBindingMatches(expected, actual, 'affected plan')).toThrow('does not match'); + } finally { + cleanup(); + } +}); + +test('keeps legacy F4 qualification plans backward-compatible as full-payload', () => { + const { root, cleanup } = fixture(); + try { + const planPath = path.join(root, 'legacy-plan.json'); + writeFileSync( + planPath, + JSON.stringify({ + projects: [], + jobs: ['affected'], + extension_package_products: [], + }), + ); + const affectedPlan = affectedPlanBinding(planPath, false); + const candidate = { + schemaVersion: 2, + affectedPlan, + evidenceRequirements: { + wasixReleaseRegression: false, + artifacts: [], + }, + evidence: { wasixReleaseRegression: null }, + }; + expect(affectedPlan.qualification).toBeUndefined(); + expect(candidateQualificationMode(candidate)).toBe('full-payload'); + expect(() => assertCandidateBindingShape(candidate)).not.toThrow(); + } finally { + cleanup(); + } +}); diff --git a/tools/release/release-candidate-lib.test.sh b/tools/release/release-candidate-lib.test.sh new file mode 100644 index 000000000..2de0d1556 --- /dev/null +++ b/tools/release/release-candidate-lib.test.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +source_root="$PWD" +bun test ./tools/release/release-candidate-lib.test.mts +repo="$(mktemp -d)" +trap 'rm -rf "$repo"' EXIT +cd "$repo" +git init --quiet +git -c user.name=Fixture -c user.email=fixture@example.invalid commit --quiet --allow-empty -m fixture +sha="$(git rev-parse HEAD)" +tree="$(git rev-parse 'HEAD^{tree}')" +plan="$repo/plan.json" +candidate="$repo/candidate.json" +printf '%s\n' '{"projects":[],"jobs":["affected"],"extension_package_products":[]}' > "$plan" +run() { + env -i PATH="$PATH" HOME="$HOME" CI_HEAD_SHA="${head_sha:-$sha}" RELEASE_HEAD_SHA="${release_sha:-$sha}" \ + CI_PLAN_PATH="$plan" CI_QUALIFICATION_MODE="${qualification:-full-payload}" WASIX_RELEASE_REGRESSION_REQUIRED=false \ + GITHUB_REPOSITORY=f0rr0/oliphaunt GITHUB_WORKFLOW=CI \ + GITHUB_WORKFLOW_REF=f0rr0/oliphaunt/.github/workflows/ci.yml@refs/heads/main \ + GITHUB_RUN_ID=123 CI_RUN_ID=123 GITHUB_RUN_ATTEMPT=1 GITHUB_EVENT_NAME=push GITHUB_REF=refs/heads/main \ + CI_CHECKED_OUT_SHA=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb CI_SOURCE_TREE=cccccccccccccccccccccccccccccccccccccccc \ + bash "$source_root/.github/scripts/release-candidate.sh" "$@" > "$repo/result" 2>&1 +} +reject() { if run "$@"; then echo 'Invalid candidate accepted' >&2; exit 1; fi; } +run write "$candidate" +jq -e --arg sha "$sha" --arg tree "$tree" '.sha==$sha and .tree==$tree' "$candidate" > /dev/null +verify=(verify "$candidate" --plan "$plan" --wasix-evidence-required false) +run "${verify[@]}" +head_sha=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa reject write "$candidate" +release_sha=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa reject "${verify[@]}" +jq -n --arg sha "$sha" '{projects:["oliphaunt-js"],jobs:["affected","js-sdk-package"],extension_package_products:[],qualification_mode:"selected-products",qualification_base_sha:null,qualification_head_sha:$sha,qualification_products:["oliphaunt-js"],tasks:["oliphaunt-js:package"]}' > "$plan" +qualification=selected-products run write "$candidate" +run "${verify[@]}" --qualification-mode release --products-json '["oliphaunt-js"]' +reject "${verify[@]}" --qualification-mode release --products-json '["oliphaunt-js","liboliphaunt-native"]' +rg -q 'missing qualification' "$repo/result" +printf '%s\n' '{"projects":["changed"],"jobs":["affected"],"extension_package_products":[]}' > "$plan" +reject "${verify[@]}" +echo 'Candidate commands: actual Git identity, selected scope and changed plan rejection passed' diff --git a/tools/release/release-candidate-sync.mjs b/tools/release/release-candidate-sync.mjs deleted file mode 100644 index e34bb210b..000000000 --- a/tools/release/release-candidate-sync.mjs +++ /dev/null @@ -1,461 +0,0 @@ -import { existsSync, readFileSync, writeFileSync } from "node:fs"; -import path from "node:path"; - -const VERSION_IN_MARKER = /(?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)/gu; -const TOML_TABLE = /^\s*\[([^\]]+)\]\s*(?:#.*)?$/u; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function error(prefix, message) { - return new Error(`${prefix}: ${message}`); -} - -function object(value, context, prefix) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(prefix, `${context} must be an object`); - } - return value; -} - -function packageRelative(packagePath, relativePath, context, prefix) { - if ( - typeof packagePath !== "string" || packagePath.length === 0 || path.posix.isAbsolute(packagePath) || - typeof relativePath !== "string" || relativePath.length === 0 || path.posix.isAbsolute(relativePath) - ) { - throw error(prefix, `${context} must use non-empty relative package paths`); - } - const packageRoot = path.posix.normalize(packagePath.replaceAll("\\", "/")); - const file = path.posix.normalize(path.posix.join(packageRoot, relativePath.replaceAll("\\", "/"))); - if (file !== packageRoot && !file.startsWith(`${packageRoot}/`)) { - throw error(prefix, `${context} must stay inside ${packageRoot}`); - } - return file; -} - -function jsonPathParts(expression, context, prefix) { - if (typeof expression !== "string" || !/^[$][.][A-Za-z0-9_.-]+$/u.test(expression)) { - throw error(prefix, `${context} must use a simple $.path JSONPath`); - } - return expression.slice(2).split("."); -} - -function packageDescriptors(product, graphProduct, packagePath, config, prefix) { - const releaseType = config["release-type"]; - const versionFile = config["version-file"]; - let canonical; - if (typeof versionFile === "string" && versionFile.length > 0) { - canonical = { path: packageRelative(packagePath, versionFile, `${product}.version-file`, prefix), type: "raw" }; - } else if (releaseType === "rust") { - canonical = { - path: packageRelative(packagePath, "Cargo.toml", `${product}.Cargo.toml`, prefix), - type: "toml", - parts: ["package", "version"], - }; - } else if (releaseType === "node" || releaseType === "expo") { - canonical = { - path: packageRelative(packagePath, "package.json", `${product}.package.json`, prefix), - type: "json", - parts: ["version"], - }; - } else { - throw error(prefix, `${product} has no supported canonical version file declaration`); - } - - const rawExtraFiles = config["extra-files"] ?? []; - if (!Array.isArray(rawExtraFiles)) { - throw error(prefix, `${product}.extra-files must be a list`); - } - const extra = rawExtraFiles.map((entry, index) => { - const context = `${product}.extra-files[${index}]`; - if (typeof entry === "string") { - return { path: packageRelative(packagePath, entry, context, prefix), type: "generic" }; - } - object(entry, context, prefix); - const type = entry.type ?? "generic"; - if (!["generic", "json", "toml"].includes(type)) { - throw error(prefix, `${context}.type ${JSON.stringify(type)} is unsupported`); - } - return { - path: packageRelative(packagePath, entry.path, `${context}.path`, prefix), - type, - ...((type === "json" || type === "toml") - ? { parts: jsonPathParts(entry.jsonpath, `${context}.jsonpath`, prefix) } - : {}), - }; - }); - const descriptors = [canonical, ...extra]; - const paths = descriptors.map((descriptor) => descriptor.path); - if (new Set(paths).size !== paths.length) { - throw error(prefix, `${product} release-please version files must not contain duplicates`); - } - const graphPaths = graphProduct.version_files; - if (!Array.isArray(graphPaths) || graphPaths.some((file) => typeof file !== "string")) { - throw error(prefix, `${product}.version_files must be a string list`); - } - if ( - JSON.stringify([...paths].sort(compareText)) !== - JSON.stringify([...graphPaths].sort(compareText)) - ) { - throw error( - prefix, - `${product} graph version files must exactly match release-please declarations: ` + - `graph=${JSON.stringify([...graphPaths].sort(compareText))} ` + - `releasePlease=${JSON.stringify([...paths].sort(compareText))}`, - ); - } - return descriptors; -} - -function replaceRaw(text, before, after, context, prefix) { - if (text.trim() !== before) { - throw error(prefix, `${context} contains ${JSON.stringify(text.trim())}, expected ${before}`); - } - const index = text.indexOf(before); - if (index < 0 || text.indexOf(before, index + before.length) >= 0) { - throw error(prefix, `${context} must contain its current version exactly once`); - } - return `${text.slice(0, index)}${after}${text.slice(index + before.length)}`; -} - -function setObjectPath(value, parts, before, after, context, prefix) { - let cursor = object(value, context, prefix); - for (const part of parts.slice(0, -1)) { - if (!(part in cursor)) throw error(prefix, `${context} is missing path ${parts.join(".")}`); - cursor = object(cursor[part], `${context}.${part}`, prefix); - } - const key = parts.at(-1); - if (cursor[key] !== before) { - throw error(prefix, `${context}.${parts.join(".")} contains ${JSON.stringify(cursor[key])}, expected ${before}`); - } - cursor[key] = after; -} - -function replaceJson(text, parts, before, after, context, prefix) { - let value; - try { - value = JSON.parse(text); - } catch (cause) { - throw error(prefix, `${context} is invalid JSON: ${cause.message}`); - } - setObjectPath(value, parts, before, after, context, prefix); - return `${JSON.stringify(value, null, 2)}\n`; -} - -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"); -} - -function replaceToml(text, parts, before, after, context, prefix) { - if (parts.length < 2) { - throw error(prefix, `${context} TOML path must include a table and key`); - } - const table = parts.slice(0, -1).join("."); - const key = parts.at(-1); - const pattern = new RegExp( - `^(\\s*${escapeRegExp(key)}\\s*=\\s*)(["'])${escapeRegExp(before)}\\2(\\s*(?:#.*)?)$`, - "u", - ); - const lines = text.split(/(?<=\n)/u); - let currentTable = ""; - let matched = 0; - for (const [index, line] of lines.entries()) { - const newline = line.endsWith("\r\n") ? "\r\n" : line.endsWith("\n") ? "\n" : ""; - const body = line.slice(0, line.length - newline.length); - const tableMatch = TOML_TABLE.exec(body); - if (tableMatch !== null) { - currentTable = tableMatch[1].trim(); - continue; - } - if (currentTable !== table) continue; - const match = pattern.exec(body); - if (match === null) { - if (new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`, "u").test(body)) { - throw error(prefix, `${context}.${parts.join(".")} does not equal ${before}`); - } - continue; - } - matched += 1; - lines[index] = `${match[1]}${match[2]}${after}${match[2]}${match[3]}${newline}`; - } - if (matched !== 1) { - throw error(prefix, `${context} must contain exactly one TOML string at ${parts.join(".")}`); - } - return lines.join(""); -} - -function replaceGeneric(text, before, after, context, prefix) { - const markedLines = text.split(/\r?\n/u).filter((line) => line.includes("x-release-please-version")); - if (markedLines.length === 1) { - const versions = markedLines[0].match(VERSION_IN_MARKER) ?? []; - if (versions.length !== 1 || versions[0] !== before) { - throw error(prefix, `${context} version marker must own exactly the current version ${before}`); - } - return text.replace(markedLines[0], markedLines[0].replace(before, after)); - } - const blockMatch = /x-release-please-start-version(?[\s\S]*?)x-release-please-end/u.exec(text); - const body = blockMatch?.groups?.body; - const versions = body?.match(VERSION_IN_MARKER) ?? []; - if (markedLines.length !== 0 || body === undefined || versions.length !== 1 || versions[0] !== before) { - throw error(prefix, `${context} must have one Release Please marker or marker block owning ${before}`); - } - return text.replace(body, body.replace(before, after)); -} - -function changelogHeadingVersion(line) { - return line.match(/^##[ \t]+(?:\[)?([^\] (]+)(?:\])?(?:[ \t(]|$)/u)?.[1]; -} - -function reasonText(reason) { - if (reason.kind === "shared-source") { - return `shared contrib carrier source: ${reason.summary} (${reason.commit.slice(0, 8)})`; - } - throw error("release-candidate-sync", `unsupported release reason ${reason.kind}`); -} - -function changelogContent(candidate) { - const sharedSource = candidate.reasons.every((reason) => reason.kind === "shared-source"); - const section = sharedSource ? (candidate.changelogSection ?? "Bug Fixes") : "Dependencies"; - const label = sharedSource ? "contrib" : "dependencies"; - const bullets = candidate.reasons.map((reason) => `* **${label}:** ${reasonText(reason)}`); - return { bullets, section }; -} - -function updateChangelog(text, candidate, context, prefix) { - const lines = text.split(/\r?\n/u); - if (lines.some((line) => changelogHeadingVersion(line) === candidate.after)) { - throw error(prefix, `${context} already contains release heading ${candidate.after}`); - } - if (!lines.some((line) => changelogHeadingVersion(line) === candidate.before)) { - throw error( - prefix, - `${context} has no prior release heading for ${candidate.before}; candidate synchronization is post-first-release only`, - ); - } - const newline = text.includes("\r\n") ? "\r\n" : "\n"; - const { bullets, section } = changelogContent(candidate); - const entry = [`## ${candidate.after}`, "", `### ${section}`, "", ...bullets].join(newline); - const heading = /^# [^\r\n]+(?:\r?\n|$)/u.exec(text); - if (heading === null) { - return `${entry}${newline}${newline}${text}`; - } - const remainder = text.slice(heading[0].length).replace(/^(?:\r?\n)*/u, ""); - return `${heading[0]}${newline}${entry}${newline}${newline}${remainder}`; -} - -function mergeExistingChangelog(text, candidate, context, prefix) { - const newline = text.includes("\r\n") ? "\r\n" : "\n"; - const lines = text.split(/\r?\n/u); - const releaseHeadings = lines - .map((line, index) => ({ index, version: changelogHeadingVersion(line) })) - .filter(({ version }) => version !== undefined); - const matches = releaseHeadings.filter(({ version }) => version === candidate.before); - if (matches.length !== 1) { - throw error(prefix, `${context} must contain exactly one release heading for ${candidate.before}`); - } - if ( - candidate.before !== candidate.after - && releaseHeadings.some(({ version }) => version === candidate.after) - ) { - throw error(prefix, `${context} already contains release heading ${candidate.after}`); - } - - const releaseStart = matches[0].index; - const releaseEnd = releaseHeadings.find(({ index }) => index > releaseStart)?.index ?? lines.length; - if (candidate.before !== candidate.after) { - lines[releaseStart] = lines[releaseStart].replaceAll(candidate.before, candidate.after); - } - - const { bullets, section } = changelogContent(candidate); - const releaseLines = lines.slice(releaseStart, releaseEnd); - const missingBullets = bullets.filter((bullet) => !releaseLines.includes(bullet)); - if (missingBullets.length === 0) return lines.join(newline); - - const sectionHeading = `### ${section}`; - const sectionMatches = lines - .slice(releaseStart + 1, releaseEnd) - .map((line, index) => ({ index: releaseStart + index + 1, line })) - .filter(({ line }) => line === sectionHeading); - if (sectionMatches.length > 1) { - throw error(prefix, `${context} release ${candidate.before} contains duplicate ${sectionHeading} sections`); - } - if (sectionMatches.length === 1) { - let insertAt = sectionMatches[0].index + 1; - while (insertAt < releaseEnd && lines[insertAt] === "") insertAt += 1; - lines.splice(insertAt, 0, ...missingBullets); - return lines.join(newline); - } - - let insertAt = releaseEnd; - while (insertAt > releaseStart + 1 && lines[insertAt - 1] === "") insertAt -= 1; - lines.splice(insertAt, 0, "", sectionHeading, "", ...missingBullets); - return lines.join(newline); -} - -function stageFileIfChanged(root, relativePath, updated, detail, changes, prefix) { - const absoluteRoot = path.resolve(root); - const absolute = path.resolve(root, relativePath); - if (absolute !== absoluteRoot && !absolute.startsWith(`${absoluteRoot}${path.sep}`)) { - throw error(prefix, `${relativePath} escapes the repository root`); - } - if (!existsSync(absolute)) throw error(prefix, `missing ${relativePath}`); - const before = readFileSync(absolute, "utf8"); - const next = updated(before); - if (next === before) return false; - changes.push({ path: absolute, detail, text: next }); - return true; -} - -function stageFile(root, relativePath, updated, detail, changes, prefix) { - if (!stageFileIfChanged(root, relativePath, updated, detail, changes, prefix)) { - throw error(prefix, `${relativePath} did not change while applying ${detail}`); - } -} - -function packagesByProduct(releasePleaseConfig, prefix) { - const packages = object(releasePleaseConfig?.packages, "release-please packages", prefix); - const byProduct = new Map(); - for (const [packagePath, packageConfig] of Object.entries(packages).sort(([left], [right]) => compareText(left, right))) { - object(packageConfig, `release-please package ${packagePath}`, prefix); - const product = packageConfig.component; - if (typeof product !== "string" || product.length === 0 || byProduct.has(product)) { - throw error(prefix, `release-please package ${packagePath} has a missing or duplicate component`); - } - byProduct.set(product, { packagePath, packageConfig }); - } - return byProduct; -} - -/** - * Apply (or report in check mode) candidate manifest, version-file, extra-file, - * and changelog updates using only the declarations Release Please already owns. - */ -export function synchronizeReleaseCandidates({ - root, - graph, - candidates, - releasePleaseConfig, - manifest, - write = false, - prefix = "release-candidate-sync", -}) { - if (typeof root !== "string" || root.length === 0) throw error(prefix, "root must be a path"); - if (!Array.isArray(candidates)) throw error(prefix, "release candidates must be a list"); - const manifestObject = object(manifest, ".release-please-manifest.json", prefix); - const packages = packagesByProduct(releasePleaseConfig, prefix); - const changes = []; - if (candidates.length === 0) return changes; - - const nextManifest = { ...manifestObject }; - const manifestDetails = []; - for (const candidate of candidates) { - const mergeExisting = candidate.changelogMode === "merge-existing"; - if (candidate.changelogMode !== undefined && !mergeExisting) { - throw error( - prefix, - `${candidate.product} has unsupported changelog mode ${JSON.stringify(candidate.changelogMode)}`, - ); - } - if (candidate.before === candidate.after && !mergeExisting) { - throw error(prefix, `${candidate.product} release candidate does not advance from ${candidate.before}`); - } - const packageInfo = packages.get(candidate.product); - if (packageInfo === undefined) { - throw error(prefix, `${candidate.product} is missing from release-please-config.json`); - } - const { packagePath, packageConfig } = packageInfo; - if (packagePath !== candidate.packagePath) { - throw error( - prefix, - `${candidate.product} graph path ${JSON.stringify(candidate.packagePath)} does not match ` + - `release-please path ${JSON.stringify(packagePath)}`, - ); - } - if (nextManifest[packagePath] !== candidate.before) { - throw error( - prefix, - `${candidate.product} manifest contains ${JSON.stringify(nextManifest[packagePath])}, expected ${candidate.before}`, - ); - } - if (candidate.before !== candidate.after) { - nextManifest[packagePath] = candidate.after; - manifestDetails.push(`${candidate.product} ${candidate.before} -> ${candidate.after}`); - - const descriptors = packageDescriptors( - candidate.product, - graph.products[candidate.product], - packagePath, - packageConfig, - prefix, - ); - for (const descriptor of descriptors) { - const detail = `${candidate.product} release candidate ${candidate.before} -> ${candidate.after}`; - stageFile( - root, - descriptor.path, - (text) => { - if (descriptor.type === "raw") { - return replaceRaw(text, candidate.before, candidate.after, descriptor.path, prefix); - } - if (descriptor.type === "json") { - return replaceJson(text, descriptor.parts, candidate.before, candidate.after, descriptor.path, prefix); - } - if (descriptor.type === "toml") { - return replaceToml(text, descriptor.parts, candidate.before, candidate.after, descriptor.path, prefix); - } - return replaceGeneric(text, candidate.before, candidate.after, descriptor.path, prefix); - }, - detail, - changes, - prefix, - ); - } - } - - const changelog = packageRelative( - packagePath, - packageConfig["changelog-path"] ?? "CHANGELOG.md", - `${candidate.product}.changelog-path`, - prefix, - ); - if (graph.products[candidate.product].changelog_path !== changelog) { - throw error( - prefix, - `${candidate.product} graph changelog ${JSON.stringify(graph.products[candidate.product].changelog_path)} ` + - `does not match release-please changelog ${JSON.stringify(changelog)}`, - ); - } - const update = mergeExisting - ? (text) => mergeExistingChangelog(text, candidate, changelog, prefix) - : (text) => updateChangelog(text, candidate, changelog, prefix); - const detail = `${candidate.product} ${mergeExisting ? "shared-source" : "dependency-only"} changelog ` + - `for ${candidate.after}`; - if (mergeExisting) { - stageFileIfChanged(root, changelog, update, detail, changes, prefix); - } else { - stageFile(root, changelog, update, detail, changes, prefix); - } - } - - if (manifestDetails.length > 0) { - stageFile( - root, - ".release-please-manifest.json", - () => `${JSON.stringify(nextManifest, null, 2)}\n`, - manifestDetails.join("; "), - changes, - prefix, - ); - } - const duplicatePaths = changes - .map(({ path: file }) => file) - .filter((file, index, files) => files.indexOf(file) !== index); - if (duplicatePaths.length > 0) { - throw error(prefix, `release candidate outputs overlap: ${[...new Set(duplicatePaths)].join(", ")}`); - } - if (write) { - for (const change of changes) writeFileSync(change.path, change.text, "utf8"); - } - return changes.map(({ path: file, detail }) => ({ path: file, detail })); -} diff --git a/tools/release/release-candidate-sync.test.mjs b/tools/release/release-candidate-sync.test.mjs deleted file mode 100644 index 103b04220..000000000 --- a/tools/release/release-candidate-sync.test.mjs +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { synchronizeReleaseCandidates } from "./release-candidate-sync.mjs"; - -const PRODUCT = "liboliphaunt-native"; -const PACKAGE_PATH = "packages/native"; - -function write(root, relative, contents) { - const file = path.join(root, relative); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, contents, "utf8"); -} - -function fixture(t) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-candidate-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const graph = { - products: { - [PRODUCT]: { - path: PACKAGE_PATH, - version: "1.0.0", - version_files: [`${PACKAGE_PATH}/VERSION`], - changelog_path: `${PACKAGE_PATH}/CHANGELOG.md`, - }, - }, - }; - const releasePleaseConfig = { - packages: { - [PACKAGE_PATH]: { - component: PRODUCT, - "release-type": "simple", - "version-file": "VERSION", - "changelog-path": "CHANGELOG.md", - }, - }, - }; - const manifest = { [PACKAGE_PATH]: "1.0.0" }; - write(root, `${PACKAGE_PATH}/VERSION`, "1.0.0\n"); - write(root, `${PACKAGE_PATH}/CHANGELOG.md`, "# Changelog\n\n## 1.0.0\n"); - write(root, ".release-please-manifest.json", `${JSON.stringify(manifest, null, 2)}\n`); - return { root, graph, releasePleaseConfig, manifest }; -} - -test("shared-source release candidates update only their declared release files", (t) => { - const state = fixture(t); - const changes = synchronizeReleaseCandidates({ - ...state, - candidates: [{ - product: PRODUCT, - packagePath: PACKAGE_PATH, - before: "1.0.0", - after: "1.0.1", - changelogSection: "Bug Fixes", - reasons: [{ - kind: "shared-source", - commit: "1234567890abcdef", - summary: "update PostgreSQL source baseline", - }], - }], - write: true, - prefix: "release-candidate-test", - }); - - assert.deepEqual( - changes.map(({ path: file }) => path.relative(state.root, file)).sort(), - [ - ".release-please-manifest.json", - `${PACKAGE_PATH}/CHANGELOG.md`, - `${PACKAGE_PATH}/VERSION`, - ], - ); - assert.equal(readFileSync(path.join(state.root, `${PACKAGE_PATH}/VERSION`), "utf8"), "1.0.1\n"); - assert.equal( - JSON.parse(readFileSync(path.join(state.root, ".release-please-manifest.json"), "utf8"))[PACKAGE_PATH], - "1.0.1", - ); - assert.match( - readFileSync(path.join(state.root, `${PACKAGE_PATH}/CHANGELOG.md`), "utf8"), - /shared contrib carrier source: update PostgreSQL source baseline \(12345678\)/u, - ); -}); diff --git a/tools/release/release-check-registries.mjs b/tools/release/release-check-registries.mjs deleted file mode 100644 index c00179029..000000000 --- a/tools/release/release-check-registries.mjs +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bun -import { fail, run } from "./release-cli-utils.mjs"; - -const TOOL = "release-check-registries.mjs"; - -function productsJsonArg(args) { - for (let index = 0; index < args.length; index += 1) { - const value = args[index]; - if (value === "--products-json") { - if (index + 1 >= args.length) { - fail(TOOL, "--products-json requires a value", 2); - } - return args[index + 1]; - } - if (value.startsWith("--products-json=")) { - return value.slice("--products-json=".length); - } - } - return null; -} - -function main(argv) { - if (argv.includes("-h") || argv.includes("--help")) { - console.log( - "usage: tools/release/release-check-registries.mjs " - + "[--products-json JSON] [--head-ref REF] " - + "[--registry-inventory-output FILE] [--require-identities]", - ); - process.exit(0); - } - - const requireIdentities = argv.includes("--require-identities"); - const passthrough = argv.filter((value) => value !== "--require-identities"); - if (passthrough.length === 0) { - console.log("No release products selected; registry publication checks skipped."); - return; - } - - run(TOOL, [process.execPath, "tools/release/check_release_versions.mjs", ...passthrough, "--check-registries"], { failExitCode: 2 }); - if (!requireIdentities) { - return; - } - - const productsJson = productsJsonArg(passthrough); - if (productsJson === null) { - fail(TOOL, "check-registries --require-identities requires --products-json", 2); - } - run(TOOL, [ - process.execPath, - "tools/release/check_registry_publication.mjs", - "--products-json", - productsJson, - "--require-identities", - ], { failExitCode: 2 }); -} - -main(Bun.argv.slice(2)); diff --git a/tools/release/release-check-registries.sh b/tools/release/release-check-registries.sh new file mode 100644 index 000000000..67efab975 --- /dev/null +++ b/tools/release/release-check-registries.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +require_identities=false +products_json='' +args=() +while [ "$#" -gt 0 ]; do + case "$1" in + -h|--help) + echo 'usage: release-check-registries.sh [--products-json JSON] [--head-ref REF] [--registry-inventory-output FILE] [--require-identities]' + exit 0 ;; + --require-identities) require_identities=true; shift ;; + --products-json) + [ "$#" -ge 2 ] || { echo '--products-json requires a value' >&2; exit 2; } + products_json="$2"; args+=("$1" "$2"); shift 2 ;; + --products-json=*) products_json="${1#*=}"; args+=("$1"); shift ;; + *) args+=("$1"); shift ;; + esac +done +if [ "${#args[@]}" -eq 0 ]; then + echo 'No release products selected; registry publication checks skipped.' + exit 0 +fi +if [ "$require_identities" = true ] && [ -z "$products_json" ]; then + echo 'check-registries --require-identities requires --products-json' >&2; exit 2 +fi +bash "$(dirname "${BASH_SOURCE[0]}")/check-release-versions.sh" "${args[@]}" --check-registries || exit 2 +if [ "$require_identities" = true ]; then + bun tools/release/check_registry_publication.mts --products-json "$products_json" --require-identities || exit 2 +fi diff --git a/tools/release/release-check.mjs b/tools/release/release-check.mjs deleted file mode 100644 index e96e16ee3..000000000 --- a/tools/release/release-check.mjs +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env bun -import { spawn } from "node:child_process"; -import { lstatSync } from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { isolatedGitHubTestEnvironment } from "../test/isolated-github-test-environment.mjs"; -import { run } from "./release-cli-utils.mjs"; - -const TOOL = "release-check.mjs"; -const ROOT = path.resolve(import.meta.dir, "../.."); -export const DEDICATED_GATE_TESTS = new Set([ - "tools/policy/assertions/workflow-security.test.mjs", - "tools/policy/ci-plan-node-products.test.mjs", - "tools/policy/ci-plan-wasix-postmaster-release.test.mjs", - "tools/policy/workflow-moon-transfers.test.mjs", - "tools/release/native-extension-lifecycle-receipts.test.mjs", - "tools/release/product-task-model.test.mjs", - "tools/release/release-candidate-sync.test.mjs", - "tools/release/toolchain-bootstrap.test.mjs", -]); -export const MUTATION_TEST_PROCESS_CONCURRENCY = 4; -export const MUTATION_TEST_MAX_CONCURRENCY = 1; -export const MUTATION_TEST_TIMEOUT_MS = 30_000; - -export function mutationTestEnvironment(inheritedEnvironment = process.env) { - return isolatedGitHubTestEnvironment({}, inheritedEnvironment); -} - -export function mutationTests( - root, - { gitCommand = "git", gitCommandArgs = [], repositoryRoot = ROOT } = {}, -) { - const normalizedRoot = root.split(path.sep).join("/").replace(/^[/]+|[/]+$/gu, ""); - if (!normalizedRoot || path.isAbsolute(root) || normalizedRoot.split("/").includes("..")) { - throw new Error(`${TOOL}: mutation test root must be a repository-relative path`); - } - const result = captureCommandOutput( - gitCommand, - [ - ...gitCommandArgs, - "ls-files", - "-z", - "--cached", - "--others", - "--exclude-standard", - "--", - normalizedRoot, - ], - { - cwd: repositoryRoot, - label: `git ls-files ${normalizedRoot}`, - maxOutputBytes: 16 * 1024 * 1024, - stdoutTerminator: "\0", - }, - ); - if (result.error !== undefined || result.status !== 0) { - throw new Error( - `${TOOL}: cannot inventory repository-owned mutation tests: ` - + (result.error?.message || result.stderr.trim() || `git exited ${result.status}`), - ); - } - if (result.stdout.length === 0) { - throw new Error(`${TOOL}: cannot inventory repository-owned mutation tests: git returned an empty inventory`); - } - const tests = result.stdout - .split("\0") - .filter(Boolean) - .filter((file) => file.endsWith(".test.mjs")) - .filter((file) => !DEDICATED_GATE_TESTS.has(file)) - .filter((file) => { - try { - const entry = lstatSync(path.join(repositoryRoot, ...file.split("/"))); - return entry.isFile() && !entry.isSymbolicLink(); - } catch { - // A tracked deletion must not become an attempted test invocation. - return false; - } - }) - .sort(); - if (tests.length === 0) { - throw new Error(`${TOOL}: ${normalizedRoot} contains no repository-owned mutation tests`); - } - return tests; -} - -export function mutationTestWaves(tests, concurrency = MUTATION_TEST_PROCESS_CONCURRENCY) { - if (!Number.isSafeInteger(concurrency) || concurrency < 1) { - throw new Error(`${TOOL}: mutation test process concurrency must be a positive integer`); - } - const waves = []; - for (let offset = 0; offset < tests.length; offset += concurrency) { - waves.push(tests.slice(offset, offset + concurrency)); - } - return waves; -} - -export function mutationTestCommand(test) { - return [ - process.execPath, - "test", - // Positional paths are filters, so Bun still discovers recursively from - // the workspace root. Generated build trees are never mutation tests and - // can contain hundreds of thousands of files after local qualification. - "--path-ignore-patterns=target/**", - "--isolate", - `--max-concurrency=${MUTATION_TEST_MAX_CONCURRENCY}`, - `--timeout=${MUTATION_TEST_TIMEOUT_MS}`, - test, - ]; -} - -function runMutationTest(test, environment) { - const command = mutationTestCommand(test); - console.log(`\n==> ${command.join(" ")}`); - return new Promise((resolve) => { - let settled = false; - const finish = (result) => { - if (settled) return; - settled = true; - resolve(result); - }; - const child = spawn(command[0], command.slice(1), { - cwd: ROOT, - env: environment, - stdio: "inherit", - }); - child.once("error", (error) => finish({ error, status: null, signal: null, test })); - child.once("close", (status, signal) => finish({ error: null, status, signal, test })); - }); -} - -export function releaseCheckPlan(argv) { - const mutationTestsOnly = argv.includes("--mutation-tests-only"); - const scopeArguments = argv.filter((arg) => arg.startsWith("--mutation-scope=")); - if (scopeArguments.length > 1) { - throw new Error(`${TOOL}: --mutation-scope may be provided only once`); - } - const mutationScope = scopeArguments[0]?.slice("--mutation-scope=".length) || "all"; - if (!new Set(["all", "policy", "release"]).has(mutationScope)) { - throw new Error(`${TOOL}: --mutation-scope must be all, policy, or release`); - } - const unexpected = argv.filter( - (arg) => arg !== "--mutation-tests-only" && !arg.startsWith("--mutation-scope="), - ); - if (unexpected.length > 0) { - throw new Error(`${TOOL}: unexpected argument ${unexpected[0]}`); - } - return { mutationScope, mutationTestsOnly }; -} - -function parseArgs(argv) { - for (const arg of argv) { - if (arg === "-h" || arg === "--help") { - console.log(`usage: tools/release/release-check.mjs [--mutation-tests-only] [--mutation-scope=all|policy|release] - -Runs release metadata gates followed by release mutation unit tests. -`); - process.exit(0); - } - } - return releaseCheckPlan(argv); -} - -async function main(argv) { - const plan = parseArgs(argv); - if (!plan.mutationTestsOnly) { - run(TOOL, [process.execPath, "tools/release/release-metadata-check.mjs"]); - } - const roots = plan.mutationScope === "all" - ? ["tools/policy", "tools/release"] - : [`tools/${plan.mutationScope}`]; - const tests = roots.flatMap((root) => mutationTests(root)); - // Bun 1.3 can retain stale epoll registrations while moving between test - // files. Give every file a fresh process, and preserve bounded throughput by - // draining a fixed-size wave before starting the next one. - const environment = mutationTestEnvironment(); - for (const wave of mutationTestWaves(tests)) { - const results = await Promise.all(wave.map((test) => runMutationTest(test, environment))); - const failure = results.find(({ error, status }) => error !== null || status !== 0); - if (failure !== undefined) { - if (failure.error !== null) { - throw new Error(`${TOOL}: ${failure.test} failed to start: ${failure.error.message}`); - } - if (failure.signal !== null) { - throw new Error(`${TOOL}: ${failure.test} terminated by ${failure.signal}`); - } - process.exit(failure.status ?? 1); - } - } -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/release-check.sh b/tools/release/release-check.sh new file mode 100644 index 000000000..081c97e9f --- /dev/null +++ b/tools/release/release-check.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" + +metadata=1 +for argument in "$@"; do + case "$argument" in + --mutation-tests-only) metadata=0 ;; + -h|--help) echo 'usage: release-check.sh [--mutation-tests-only]'; exit 0 ;; + *) echo "unexpected argument: $argument" >&2; exit 2 ;; + esac +done +if [ "$metadata" = 1 ]; then bash tools/release/release-metadata-check.sh; fi + +# Synthetic fixtures must not inherit live publication credentials or state. +while IFS= read -r name; do + case "$name" in + ACTIONS_*|GH_*|GITHUB_*|OLIPHAUNT_GITHUB_*|OLIPHAUNT_RELEASE_*|RELEASE_*|BOOTSTRAP_LEDGER_PATH|CI_RUN_ID|OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL) + unset "$name" ;; + esac +done < <(compgen -e) + +inventory="$(mktemp)" +trap 'rm -f "$inventory"' EXIT +git ls-files -z --cached --others --exclude-standard -- tools/release > "$inventory" +test_files=() +shell_tests=() +while IFS= read -r -d '' test_file; do + case "$test_file" in + tools/release/prepare-release-candidate.test.*) continue ;; + *.test.sh|*.test.mjs|*.test.mts) ;; + *) continue ;; + esac + if [ ! -f "$test_file" ] || [ -L "$test_file" ]; then continue; fi + if [[ "$test_file" == *.test.sh ]]; then + shell_tests+=("$test_file") + continue + fi + if [[ -f "${test_file%.*}.sh" ]]; then + continue + fi + test_files+=("./$test_file") +done < "$inventory" +[ "${#test_files[@]}" -gt 0 ] || { echo 'No release tests found' >&2; exit 1; } + +bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-source.sh HEAD bash tools/ci/with-projects.sh test --timeout=30000 "${test_files[@]}" +for shell_test in "${shell_tests[@]}"; do bash "$shell_test"; done diff --git a/tools/release/release-cli-utils.mjs b/tools/release/release-cli-utils.mjs deleted file mode 100644 index 677b1994d..000000000 --- a/tools/release/release-cli-utils.mjs +++ /dev/null @@ -1,88 +0,0 @@ -import { spawnSync } from "node:child_process"; -import path from "node:path"; - -export const ROOT = path.resolve(import.meta.dir, "../.."); - -export function uniqueValueFlag(args, flag) { - let found = false; - let selected = null; - for (let index = 0; index < args.length; index += 1) { - const argument = args[index]; - if (argument !== flag && !argument.startsWith(`${flag}=`)) continue; - if (found) { - throw new Error(`${flag} must be provided at most once`); - } - found = true; - if (argument === flag) { - if (index + 1 >= args.length) { - throw new Error(`${flag} requires a value`); - } - const next = args[index + 1]; - if (next === flag || next.startsWith(`${flag}=`)) { - throw new Error(`${flag} must be provided at most once`); - } - selected = next; - index += 1; - } else { - selected = argument.slice(flag.length + 1); - } - } - return selected; -} - -export function fail(tool, message, exitCode = 1) { - console.error(`${tool}: ${message}`); - process.exit(exitCode); -} - -export function run( - tool, - args, - { - failExitCode = 1, - cwd = ROOT, - environment = undefined, - timeout = undefined, - } = {}, -) { - console.log(`\n==> ${args.join(" ")}`); - const result = spawnSync(args[0], args.slice(1), { - cwd, - env: environment, - stdio: "inherit", - timeout, - }); - if (result.error) { - const context = result.error.code === "ETIMEDOUT" ? "timed out" : "failed to start"; - fail(tool, `${args[0]} ${context}: ${result.error.message}`, failExitCode); - } - if (result.status !== 0) { - process.exit(result.status ?? 1); - } -} - -/** - * Run a synchronous CLI command without terminating the current process. - * - * Publication executors use this variant inside concurrent registry lanes so - * a peer failure remains an ordinary rejection. That lets the executor drain - * mutations already in flight and run mandatory credential cleanup before its - * top-level caller chooses the process exit status. - */ -export function runOrThrow(tool, args, { cwd = ROOT, timeout = undefined } = {}) { - console.log(`\n==> ${args.join(" ")}`); - const result = spawnSync(args[0], args.slice(1), { - cwd, - stdio: "inherit", - timeout, - }); - if (result.error) { - const context = result.error.code === "ETIMEDOUT" ? "timed out" : "failed to start"; - throw new Error(`${tool}: ${args[0]} ${context}: ${result.error.message}`); - } - if (result.status !== 0) { - throw new Error( - `${tool}: ${args[0]} exited with ${result.signal == null ? `status ${String(result.status)}` : `signal ${result.signal}`}`, - ); - } -} diff --git a/tools/release/release-cli-utils.mts b/tools/release/release-cli-utils.mts new file mode 100644 index 000000000..6dbf9a422 --- /dev/null +++ b/tools/release/release-cli-utils.mts @@ -0,0 +1,35 @@ +import path from 'node:path'; + +export const ROOT = path.resolve(import.meta.dir, '../..'); + +export function uniqueValueFlag(args, flag) { + let found = false; + let selected = null; + for (let index = 0; index < args.length; index += 1) { + const argument = args[index]; + if (argument !== flag && !argument.startsWith(`${flag}=`)) continue; + if (found) { + throw new Error(`${flag} must be provided at most once`); + } + found = true; + if (argument === flag) { + if (index + 1 >= args.length) { + throw new Error(`${flag} requires a value`); + } + const next = args[index + 1]; + if (next === flag || next.startsWith(`${flag}=`)) { + throw new Error(`${flag} must be provided at most once`); + } + selected = next; + index += 1; + } else { + selected = argument.slice(flag.length + 1); + } + } + return selected; +} + +export function fail(tool, message, exitCode = 1) { + console.error(`${tool}: ${message}`); + process.exit(exitCode); +} diff --git a/tools/release/release-cli-utils.test.mts b/tools/release/release-cli-utils.test.mts new file mode 100644 index 000000000..15e94e647 --- /dev/null +++ b/tools/release/release-cli-utils.test.mts @@ -0,0 +1,29 @@ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; +import { uniqueValueFlag } from './release-cli-utils.mts'; + +test('release CLI value flags reject ambiguous duplicate identities', () => { + assert.equal(uniqueValueFlag(['--head-ref', 'a'.repeat(40)], '--head-ref'), 'a'.repeat(40)); + assert.equal(uniqueValueFlag(['--products-json=["sdk"]'], '--products-json'), '["sdk"]'); + assert.throws( + () => + uniqueValueFlag(['--head-ref', 'a'.repeat(40), `--head-ref=${'b'.repeat(40)}`], '--head-ref'), + /--head-ref must be provided at most once/u, + ); + assert.throws( + () => + uniqueValueFlag( + ['--products-json=["sdk"]', '--products-json', '["extension"]'], + '--products-json', + ), + /--products-json must be provided at most once/u, + ); + assert.throws( + () => uniqueValueFlag(['--head-ref', `--head-ref=${'b'.repeat(40)}`], '--head-ref'), + /--head-ref must be provided at most once/u, + ); + assert.throws( + () => uniqueValueFlag(['--head-ref'], '--head-ref'), + /--head-ref requires a value/u, + ); +}); diff --git a/tools/release/release-directory-safety.mjs b/tools/release/release-directory-safety.mjs deleted file mode 100644 index 0613ed0d9..000000000 --- a/tools/release/release-directory-safety.mjs +++ /dev/null @@ -1,121 +0,0 @@ -import { lstatSync, mkdirSync, statSync } from "node:fs"; -import path from "node:path"; - -const DARWIN_ROOT_DIRECTORY_ALIASES = Object.freeze(new Map([ - ["etc", "private/etc"], - ["tmp", "private/tmp"], - ["var", "private/var"], -])); - -function hasStableDirectoryIdentity(metadata) { - return ( - metadata?.isDirectory?.() === true - && typeof metadata.dev === "bigint" - && metadata.dev > 0n - && typeof metadata.ino === "bigint" - && metadata.ino > 0n - ); -} - -/** - * Canonicalize only Darwin's fixed root-level system directory aliases. - * - * The alias and canonical target must dereference to the same stable device - * and inode. Any inspection failure or mismatch returns the lexical path so - * the caller's lstat-based directory-chain validation fails closed. - * Caller-created aliases outside this fixed set are never followed. - */ -export function canonicalSystemDirectoryPath( - directory, - { - platform = process.platform, - lstat = lstatSync, - stat = statSync, - } = {}, -) { - if (typeof directory !== "string" || directory.length === 0) { - throw new TypeError("system directory canonicalization requires a nonempty path"); - } - const resolved = path.resolve(directory); - if (platform !== "darwin") return resolved; - if (!path.posix.isAbsolute(resolved)) { - throw new Error("Darwin system directory canonicalization requires an absolute POSIX path"); - } - - const relative = path.posix.relative("/", resolved); - const [aliasName, ...suffix] = relative ? relative.split("/") : []; - const canonicalRelative = DARWIN_ROOT_DIRECTORY_ALIASES.get(aliasName); - if (!canonicalRelative) return resolved; - - const alias = path.posix.join("/", aliasName); - const canonicalAlias = path.posix.join("/", canonicalRelative); - let aliasEntry; - let aliasIdentity; - let canonicalIdentity; - try { - aliasEntry = lstat(alias, { bigint: true }); - aliasIdentity = stat(alias, { bigint: true }); - canonicalIdentity = stat(canonicalAlias, { bigint: true }); - } catch { - return resolved; - } - if ( - !aliasEntry.isSymbolicLink() - || !hasStableDirectoryIdentity(aliasIdentity) - || !hasStableDirectoryIdentity(canonicalIdentity) - || aliasIdentity.dev !== canonicalIdentity.dev - || aliasIdentity.ino !== canonicalIdentity.ino - ) { - return resolved; - } - return path.posix.join(canonicalAlias, ...suffix); -} - -/** - * Resolve and validate a complete directory chain without following arbitrary - * symlinks. Missing suffix directories may be created one at a time and are - * always re-inspected before use. - */ -export function requireSafeDirectoryChain( - directory, - { - create = false, - label = "directory", - mode = 0o755, - platform = process.platform, - lstat = lstatSync, - stat = statSync, - mkdir = mkdirSync, - } = {}, -) { - const resolved = canonicalSystemDirectoryPath(directory, { platform, lstat, stat }); - const filesystemRoot = path.parse(resolved).root; - let cursor = filesystemRoot; - const inspect = (candidate, { allowCreate = false } = {}) => { - let metadata; - try { - metadata = lstat(candidate); - } catch (cause) { - if (cause?.code !== "ENOENT" || !allowCreate) { - throw new Error(`${label} cannot be inspected: ${candidate}: ${cause.message}`); - } - try { - mkdir(candidate, { mode }); - metadata = lstat(candidate); - } catch (createCause) { - throw new Error(`${label} cannot be created safely: ${candidate}: ${createCause.message}`); - } - } - if (!metadata.isDirectory() || metadata.isSymbolicLink()) { - throw new Error(`${label} must not have a symlink or non-directory ancestor: ${candidate}`); - } - }; - - inspect(cursor); - const relative = path.relative(filesystemRoot, resolved); - for (const part of relative ? relative.split(path.sep) : []) { - cursor = path.join(cursor, part); - inspect(cursor, { allowCreate: create }); - } - return resolved; -} diff --git a/tools/release/release-directory-safety.test.mjs b/tools/release/release-directory-safety.test.mjs deleted file mode 100644 index 9bd8e5768..000000000 --- a/tools/release/release-directory-safety.test.mjs +++ /dev/null @@ -1,203 +0,0 @@ -import assert from "node:assert/strict"; -import { - lstatSync, - mkdtempSync, - mkdirSync, - realpathSync, - rmSync, - symlinkSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - canonicalSystemDirectoryPath, - requireSafeDirectoryChain, -} from "./release-directory-safety.mjs"; - -function directoryIdentity(device, inode) { - return { - dev: BigInt(device), - ino: BigInt(inode), - isDirectory: () => true, - }; -} - -function symbolicLinkMetadata() { - return { - isDirectory: () => false, - isSymbolicLink: () => true, - }; -} - -test("canonicalizes only identity-matching Darwin root directory aliases", () => { - const aliases = new Map([ - ["/etc", { canonical: "/private/etc", identity: directoryIdentity(1, 11) }], - ["/tmp", { canonical: "/private/tmp", identity: directoryIdentity(1, 12) }], - ["/var", { canonical: "/private/var", identity: directoryIdentity(1, 13) }], - ]); - const canonicalIdentities = new Map( - [...aliases.values()].map(({ canonical, identity }) => [canonical, identity]), - ); - const lstat = (file, options) => { - assert.deepEqual(options, { bigint: true }); - if (!aliases.has(file)) throw Object.assign(new Error(`missing ${file}`), { code: "ENOENT" }); - return symbolicLinkMetadata(); - }; - const stat = (file, options) => { - assert.deepEqual(options, { bigint: true }); - const identity = aliases.get(file)?.identity ?? canonicalIdentities.get(file); - if (!identity) throw Object.assign(new Error(`missing ${file}`), { code: "ENOENT" }); - return identity; - }; - - assert.equal( - canonicalSystemDirectoryPath("/var/folders/user/stage", { - platform: "darwin", - lstat, - stat, - }), - "/private/var/folders/user/stage", - ); - assert.equal( - canonicalSystemDirectoryPath("/tmp/stage", { platform: "darwin", lstat, stat }), - "/private/tmp/stage", - ); - assert.equal( - canonicalSystemDirectoryPath("/etc/oliphaunt", { platform: "darwin", lstat, stat }), - "/private/etc/oliphaunt", - ); - assert.equal( - canonicalSystemDirectoryPath("/Users/runner/stage", { - platform: "darwin", - lstat: () => assert.fail("an unrecognized root path must not be inspected as an alias"), - stat: () => assert.fail("an unrecognized root path must not be inspected as an alias"), - }), - "/Users/runner/stage", - ); - assert.equal( - canonicalSystemDirectoryPath("/var/folders/user/stage", { - platform: "linux", - lstat: () => assert.fail("non-Darwin paths must not inspect system aliases"), - stat: () => assert.fail("non-Darwin paths must not inspect system aliases"), - }), - "/var/folders/user/stage", - ); - - const mismatchedStat = (file, options) => { - if (file === "/var") return stat(file, options); - if (file === "/private/var") return directoryIdentity(1, 99); - throw Object.assign(new Error(`missing ${file}`), { code: "ENOENT" }); - }; - assert.equal( - canonicalSystemDirectoryPath("/var/folders/user/stage", { - platform: "darwin", - lstat, - stat: mismatchedStat, - }), - "/var/folders/user/stage", - ); - assert.equal( - canonicalSystemDirectoryPath("/var/folders/user/stage", { - platform: "darwin", - lstat: () => { - throw Object.assign(new Error("unavailable"), { code: "EACCES" }); - }, - stat, - }), - "/var/folders/user/stage", - ); - assert.equal( - canonicalSystemDirectoryPath("/var/folders/user/stage", { - platform: "darwin", - lstat, - stat: (file, options) => file === "/var" - ? stat(file, options) - : directoryIdentity(0, 0), - }), - "/var/folders/user/stage", - ); -}); - -test("creates only missing real suffixes and rejects caller-created aliases", (t) => { - const root = realpathSync(mkdtempSync(path.join(tmpdir(), "release-directory-safety-"))); - t.after(() => rmSync(root, { recursive: true, force: true })); - const created = path.join(root, "created", "suffix"); - assert.equal( - requireSafeDirectoryChain(created, { create: true, label: "shared test root" }), - created, - ); - assert.equal(lstatSync(created).isDirectory(), true); - - const missing = path.join(root, "missing", "suffix"); - assert.throws( - () => requireSafeDirectoryChain(missing, { label: "shared test root" }), - /cannot be inspected/u, - ); - - const outside = path.join(root, "outside"); - mkdirSync(outside); - const alias = path.join(root, "alias"); - symlinkSync(outside, alias, process.platform === "win32" ? "junction" : "dir"); - assert.throws( - () => requireSafeDirectoryChain(path.join(alias, "suffix"), { - create: true, - label: "shared test root", - }), - /symlink or non-directory ancestor/u, - ); -}); - -test("re-inspects created suffixes and rejects a changed canonical target", () => { - const existing = new Set(["/", "/private", "/private/var"]); - const inspections = new Map(); - const lstat = (file, options) => { - if (options?.bigint === true && file === "/var") return symbolicLinkMetadata(); - inspections.set(file, (inspections.get(file) ?? 0) + 1); - if (!existing.has(file)) throw Object.assign(new Error(`missing ${file}`), { code: "ENOENT" }); - return { - isDirectory: () => true, - isSymbolicLink: () => file === "/private/var" && inspections.get(file) > 1, - }; - }; - const stat = () => directoryIdentity(1, 13); - const mkdir = (file, options) => { - assert.deepEqual(options, { mode: 0o755 }); - existing.add(file); - }; - assert.equal( - requireSafeDirectoryChain("/var/new/suffix", { - create: true, - label: "injected chain", - platform: "darwin", - lstat, - stat, - mkdir, - }), - "/private/var/new/suffix", - ); - assert.equal(inspections.get("/private/var/new"), 2); - assert.equal(inspections.get("/private/var/new/suffix"), 2); - - assert.throws( - () => requireSafeDirectoryChain("/var/unsafe", { - create: true, - label: "injected chain", - platform: "darwin", - lstat, - stat, - mkdir, - }), - /symlink or non-directory ancestor/u, - ); -}); - -test("accepts the verified Darwin temporary-directory alias", { - skip: process.platform !== "darwin", -}, (t) => { - const raw = mkdtempSync(path.join(tmpdir(), "release-directory-safety-darwin-")); - const canonical = realpathSync(raw); - t.after(() => rmSync(canonical, { recursive: true, force: true })); - assert.equal(requireSafeDirectoryChain(raw), canonical); -}); diff --git a/tools/release/release-gate-topology.test.mjs b/tools/release/release-gate-topology.test.mjs deleted file mode 100644 index 3d057c978..000000000 --- a/tools/release/release-gate-topology.test.mjs +++ /dev/null @@ -1,207 +0,0 @@ -import assert from "node:assert/strict"; -import { execFileSync, spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { - chmodSync, - mkdirSync, - mkdtempSync, - rmSync, - unlinkSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { test } from "node:test"; - -import { - MUTATION_TEST_PROCESS_CONCURRENCY, - mutationTestCommand, - mutationTestEnvironment, - mutationTests, - mutationTestWaves, - releaseCheckPlan, -} from "./release-check.mjs"; -import { releaseMetadataCheckPlan } from "./release-metadata-check.mjs"; -import { uniqueValueFlag } from "./release-cli-utils.mjs"; - -test("release gates reject ignored arguments", () => { - assert.deepEqual(releaseCheckPlan(["--mutation-tests-only"]), { - mutationScope: "all", - mutationTestsOnly: true, - }); - assert.deepEqual(releaseCheckPlan(["--mutation-scope=release"]), { - mutationScope: "release", - mutationTestsOnly: false, - }); - assert.throws(() => releaseCheckPlan(["--mutation-scope=other"]), /must be all, policy, or release/u); - assert.throws(() => releaseCheckPlan(["--head-ref", "abc"]), /unexpected argument/u); - assert.throws(() => releaseMetadataCheckPlan(["--head-ref", "abc"]), /unexpected argument/u); -}); - -test("release CLI value flags reject ambiguous duplicate identities", () => { - assert.equal( - uniqueValueFlag(["--head-ref", "a".repeat(40)], "--head-ref"), - "a".repeat(40), - ); - assert.equal( - uniqueValueFlag(["--products-json=[\"sdk\"]"], "--products-json"), - "[\"sdk\"]", - ); - assert.throws( - () => uniqueValueFlag( - ["--head-ref", "a".repeat(40), `--head-ref=${"b".repeat(40)}`], - "--head-ref", - ), - /--head-ref must be provided at most once/u, - ); - assert.throws( - () => uniqueValueFlag( - ["--products-json=[\"sdk\"]", "--products-json", "[\"extension\"]"], - "--products-json", - ), - /--products-json must be provided at most once/u, - ); - assert.throws( - () => uniqueValueFlag( - ["--head-ref", `--head-ref=${"b".repeat(40)}`], - "--head-ref", - ), - /--head-ref must be provided at most once/u, - ); - assert.throws( - () => uniqueValueFlag(["--head-ref"], "--head-ref"), - /--head-ref requires a value/u, - ); -}); - -test("deleted product registry routes fail before publication lock access", () => { - for (const step of ["crates-io", "npm", "maven-central"]) { - const result = spawnSync( - process.execPath, - ["tools/release/release-publish.mjs", "publish", "--product", "oliphaunt-js", "--step", step], - { - cwd: path.resolve(import.meta.dirname, "../.."), - encoding: "utf8", - env: { ...process.env, OLIPHAUNT_PUBLICATION_LOCK: "/does/not/exist" }, - }, - ); - assert.notEqual(result.status, 0); - assert.match(`${result.stdout}${result.stderr}`, /normal product\/ecosystem registry steps are disabled/u); - assert.doesNotMatch(`${result.stdout}${result.stderr}`, /cannot read publication lock/u); - } -}); - -test("mutation test discovery includes repository sources but excludes ignored dependency trees", () => { - const repository = mkdtempSync(path.join(tmpdir(), "oliphaunt-release-test-inventory-")); - try { - execFileSync("git", ["init", "--quiet"], { cwd: repository }); - mkdirSync(path.join(repository, "tools/release/node_modules/dependency"), { recursive: true }); - writeFileSync(path.join(repository, ".gitignore"), "node_modules/\n"); - writeFileSync(path.join(repository, "tools/release/owned.test.mjs"), "// tracked\n"); - writeFileSync(path.join(repository, "tools/release/deleted.test.mjs"), "// deleted\n"); - writeFileSync(path.join(repository, "tools/release/new.test.mjs"), "// untracked\n"); - writeFileSync( - path.join(repository, "tools/release/node_modules/dependency/upstream.test.mjs"), - "// ignored dependency\n", - ); - execFileSync( - "git", - ["add", ".gitignore", "tools/release/owned.test.mjs", "tools/release/deleted.test.mjs"], - { cwd: repository }, - ); - unlinkSync(path.join(repository, "tools/release/deleted.test.mjs")); - - assert.deepEqual(mutationTests("tools/release", { repositoryRoot: repository }), [ - "tools/release/new.test.mjs", - "tools/release/owned.test.mjs", - ]); - } finally { - rmSync(repository, { recursive: true, force: true }); - } -}); - -test("mutation test waves preserve the exact ordered inventory across single-file processes", () => { - const inventory = Array.from( - { length: (MUTATION_TEST_PROCESS_CONCURRENCY * 2) + 3 }, - (_, index) => `tools/release/fixture-${String(index).padStart(2, "0")}.test.mjs`, - ); - const waves = mutationTestWaves(inventory); - - assert.deepEqual(waves.map((wave) => wave.length), [ - MUTATION_TEST_PROCESS_CONCURRENCY, - MUTATION_TEST_PROCESS_CONCURRENCY, - 3, - ]); - assert.deepEqual(waves.flat(), inventory); - assert.deepEqual(mutationTestWaves([]), []); - assert.throws( - () => mutationTestWaves(inventory, 0), - /process concurrency must be a positive integer/u, - ); - for (const testFile of inventory) { - const command = mutationTestCommand(testFile); - assert.equal(command.at(-1), testFile); - assert.equal(command.filter((argument) => argument.endsWith(".test.mjs")).length, 1); - } -}); - -test("mutation test discovery retains a successful child's final inventory write", () => { - const repository = mkdtempSync(path.join(tmpdir(), "oliphaunt-release-test-capture-")); - try { - mkdirSync(path.join(repository, "tools/release"), { recursive: true }); - writeFileSync(path.join(repository, "tools/release/first.test.mjs"), "// first\n"); - writeFileSync(path.join(repository, "tools/release/last.test.mjs"), "// last\n"); - const stub = path.join(repository, "git-stub.mjs"); - writeFileSync( - stub, - [ - "process.stdout.write('tools/release/first.test.mjs\\0');", - "setImmediate(() => process.stdout.write('tools/release/last.test.mjs\\0'));", - "", - ].join("\n"), - ); - chmodSync(stub, 0o755); - assert.deepEqual( - mutationTests("tools/release", { - gitCommand: process.execPath, - gitCommandArgs: [stub], - repositoryRoot: repository, - }), - ["tools/release/first.test.mjs", "tools/release/last.test.mjs"], - ); - } finally { - rmSync(repository, { recursive: true, force: true }); - } -}); - -test("mutation test discovery rejects a successful partial NUL inventory", () => { - const repository = mkdtempSync(path.join(tmpdir(), "oliphaunt-release-test-partial-")); - try { - const stub = path.join(repository, "git-stub.mjs"); - writeFileSync(stub, "process.stdout.write('tools/release/partial.test.mjs');\n"); - assert.throws( - () => mutationTests("tools/release", { - gitCommand: process.execPath, - gitCommandArgs: [stub], - repositoryRoot: repository, - }), - /missing its required terminal/u, - ); - } finally { - rmSync(repository, { recursive: true, force: true }); - } -}); - -test("release mutation tests cannot consume a live publish request journal", () => { - assert.deepEqual( - mutationTestEnvironment({ - GITHUB_ACTIONS: "true", - GITHUB_REPOSITORY: "f0rr0/oliphaunt", - GITHUB_RUN_ID: "30593859032", - KEEP_ME: "preserved", - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: "/live/journal.json", - OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: "true", - RELEASE_HEAD_SHA: "a".repeat(40), - }), - { KEEP_ME: "preserved" }, - ); -}); diff --git a/tools/release/release-graph.mjs b/tools/release/release-graph.mjs deleted file mode 100644 index b4914aed6..000000000 --- a/tools/release/release-graph.mjs +++ /dev/null @@ -1,1456 +0,0 @@ -import { spawnSync } from "node:child_process"; -import { existsSync, readFileSync } from "node:fs"; -import path from "node:path"; - -import { moonCommand, moonEnvironment } from "../dev/moon-command.mjs"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { CONTRIB_CARRIERS_PATH, loadContribCarriers } from "./contrib-carriers.mjs"; - -export const ROOT = path.resolve(import.meta.dir, "../.."); -export const EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"; -const GENERATED_PATH_PARTS = new Set([ - ".build", - ".cxx", - ".expo", - ".gradle", - ".kotlin", - ".moon", - ".next", - ".source", - "DerivedData", - "Pods", - "__pycache__", - "dist", - "lib", - "node_modules", - "out", - "target", -]); - -// A release-tool process operates on one checkout. Cache only Moon's resolved -// topology; loadGraph still rereads version files and release manifests. -let moonProjectsSnapshot; -let moonProjectsSnapshotCommand; - -function cloneMoonProjects(projects) { - return new Map([...projects].map(([id, project]) => [id, structuredClone(project)])); -} - -export function fail(prefix, message) { - console.error(`${prefix}: ${message}`); - process.exit(1); -} - -export function rel(file) { - const relative = path.relative(ROOT, file); - return relative.startsWith("..") ? file : relative.split(path.sep).join("/"); -} - -export function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -export function readJson(relativePath, prefix) { - const value = JSON.parse(readFileSync(path.join(ROOT, relativePath), "utf8")); - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(prefix, `${relativePath} must contain a JSON object`); - } - return value; -} - -export function readToml(relativePath, prefix) { - const file = path.join(ROOT, relativePath); - if (!existsSync(file)) { - fail(prefix, `missing ${relativePath}`); - } - const value = Bun.TOML.parse(readFileSync(file, "utf8")); - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(prefix, `${relativePath} must contain a TOML table`); - } - return value; -} - -export function commandJson(args, prefix, options = {}) { - const result = captureCommandOutput(args[0], args.slice(1), { - cwd: ROOT, - label: args.join(" "), - maxOutputBytes: 100 * 1024 * 1024, - ...options, - }); - if (result.error !== undefined || result.status !== 0) { - const detail = result.error?.message || result.stderr.trim() || `exit ${result.status}`; - fail(prefix, `${args[0]} failed: ${detail}`); - } - const value = JSON.parse(result.stdout); - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(prefix, `${args[0]} did not return a JSON object`); - } - return value; -} - -export function gitSucceeds(args) { - const result = spawnSync("git", args, { cwd: ROOT, stdio: "ignore" }); - return result.status === 0; -} - -export function gitOutput(args) { - const result = captureCommandOutput("git", args, { - cwd: ROOT, - label: `git ${args.join(" ")}`, - }); - if (result.error !== undefined || result.status !== 0) { - throw new Error(result.error?.message || result.stderr.trim() || `git exited ${result.status}`); - } - return result.stdout.trim(); -} - -export function runGit(args) { - const result = captureCommandOutput("git", args, { - cwd: ROOT, - label: `git ${args.join(" ")}`, - }); - if (result.error !== undefined || result.status !== 0) { - throw new Error(result.error?.message || result.stderr.trim() || `git exited ${result.status}`); - } - return result.stdout; -} - -export function parseStableVersion(version, prefix = "release-graph") { - const match = /^([0-9]+)[.]([0-9]+)[.]([0-9]+)$/.exec(version); - if (!match) { - fail(prefix, `release version must be stable x.y.z for automated publish, got ${JSON.stringify(version)}`); - } - return match.slice(1).map((part) => Number.parseInt(part, 10)); -} - -export function compareVersion(left, right) { - for (let index = 0; index < 3; index += 1) { - if (left[index] !== right[index]) { - return left[index] - right[index]; - } - } - return 0; -} - -export function formatVersion(version) { - return version.join("."); -} - -export function assertStringList(value, context, prefix = "release-graph") { - if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) { - fail(prefix, `${context} must be a string list`); - } - return value; -} - -function releasePleasePackagesByComponent(prefix) { - const config = readJson("release-please-config.json", prefix); - const packages = config.packages; - if (packages === null || Array.isArray(packages) || typeof packages !== "object") { - fail(prefix, "release-please-config.json must define packages"); - } - const byComponent = new Map(); - for (const [packagePath, packageConfig] of Object.entries(packages)) { - if (packageConfig === null || Array.isArray(packageConfig) || typeof packageConfig !== "object") { - fail(prefix, `${packagePath} release-please config must be an object`); - } - const component = packageConfig.component; - if (typeof component !== "string" || component.length === 0) { - fail(prefix, `${packagePath}.component must be a non-empty string`); - } - if (byComponent.has(component)) { - fail(prefix, `duplicate release-please component ${component}`); - } - byComponent.set(component, { packagePath, packageConfig }); - } - return { config, byComponent }; -} - -export function moonProjectsById(prefix = "release-graph") { - const command = moonCommand(); - if (moonProjectsSnapshot !== undefined && moonProjectsSnapshotCommand === command) { - return cloneMoonProjects(moonProjectsSnapshot); - } - const result = commandJson([command, "query", "projects"], prefix, { - env: moonEnvironment(), - }); - if (!Array.isArray(result.projects)) { - fail(prefix, "moon query projects did not return a projects array"); - } - const parsed = new Map(); - for (const row of result.projects) { - assertObject(row, "Moon query project", prefix); - const { id, source } = row; - if (typeof id !== "string" || id.length === 0) { - fail(prefix, "moon query projects returned a project without an id"); - } - if (typeof source !== "string" || source.length === 0) { - fail(prefix, `Moon project ${id} does not have a source path`); - } - if (parsed.has(id)) { - fail(prefix, `duplicate Moon project id ${id}`); - } - const dependencies = row.dependencies ?? []; - if (!Array.isArray(dependencies)) { - fail(prefix, `Moon project ${id}.dependencies must be a list`); - } - const dependencyIds = new Set(); - for (const dependency of dependencies) { - assertObject(dependency, `Moon project ${id} dependency`, prefix); - if ( - typeof dependency.id !== "string" || dependency.id.length === 0 - || typeof dependency.scope !== "string" || dependency.scope.length === 0 - || dependencyIds.has(dependency.id) - ) { - fail(prefix, `Moon project ${id} dependencies require unique ids and resolved scopes`); - } - dependencyIds.add(dependency.id); - } - const config = assertObject(row.config, `Moon project ${id}.config`, prefix); - const tags = assertStringList(config.tags ?? [], `Moon project ${id}.config.tags`, prefix); - const project = assertObject(config.project ?? {}, `Moon project ${id}.config.project`, prefix); - parsed.set(id, { - id, - source, - dependencies: dependencies - .map((dependency) => ({ ...dependency })) - .sort((left, right) => compareText(left.id, right.id)), - config: { - tags: [...tags].sort(compareText), - project, - }, - }); - } - if (parsed.size === 0) { - fail(prefix, "moon query projects did not return any projects"); - } - for (const project of parsed.values()) { - for (const dependency of project.dependencies) { - if (!parsed.has(dependency.id)) { - fail(prefix, `Moon project ${project.id} depends on unknown project ${dependency.id}`); - } - } - } - moonProjectsSnapshot = parsed; - moonProjectsSnapshotCommand = command; - return cloneMoonProjects(parsed); -} - -function moonReleaseProjectsByComponent(projects, prefix) { - const products = new Map(); - for (const project of projects.values()) { - const config = project.config; - const metadata = - config.project.metadata && - typeof config.project.metadata === "object" && - !Array.isArray(config.project.metadata) - ? config.project.metadata - : {}; - const release = - metadata.release && typeof metadata.release === "object" && !Array.isArray(metadata.release) - ? metadata.release - : undefined; - if (!config.tags.includes("release-product")) { - if (release !== undefined) { - fail(prefix, `Moon project ${project.id} declares release metadata but is not tagged release-product`); - } - continue; - } - if (release === undefined) { - fail(prefix, `Moon release product ${project.id} must declare project.metadata.release`); - } - if (release.component !== project.id) { - fail(prefix, `Moon release product ${project.id} release.component must match the project id`); - } - if (typeof release.packagePath !== "string" || release.packagePath.length === 0) { - fail(prefix, `Moon release product ${project.id} must declare release.packagePath`); - } - if (products.has(release.component)) { - fail(prefix, `duplicate Moon release component ${release.component}`); - } - products.set(release.component, { - projectId: project.id, - projectSource: project.source, - path: release.packagePath, - release, - }); - } - if (products.size === 0) { - fail(prefix, "Moon project graph does not contain any release-product projects"); - } - return products; -} - -function releasePackagePaths(projects, prefix) { - const { byComponent } = releasePleasePackagesByComponent(prefix); - const moonProducts = moonReleaseProjectsByComponent(projects, prefix); - const moonComponents = [...moonProducts.keys()].sort(compareText); - const releaseComponents = [...byComponent.keys()].sort(compareText); - if (JSON.stringify(moonComponents) !== JSON.stringify(releaseComponents)) { - fail( - prefix, - `Moon release-product components must match release-please components: moon=${JSON.stringify( - moonComponents, - )}, release-please=${JSON.stringify(releaseComponents)}`, - ); - } - const paths = new Map(); - for (const component of moonComponents) { - const moonPath = moonProducts.get(component).path; - const releasePath = byComponent.get(component).packagePath; - if (moonPath !== releasePath) { - fail( - prefix, - `${component} Moon release.packagePath ${JSON.stringify(moonPath)} must match release-please package path ${JSON.stringify( - releasePath, - )}`, - ); - } - paths.set(component, moonPath); - } - return paths; -} - -function releasePleasePackage(product, prefix) { - const { byComponent } = releasePleasePackagesByComponent(prefix); - const packageInfo = byComponent.get(product); - if (!packageInfo) { - fail(prefix, `unknown release-please component ${product}`); - } - return packageInfo; -} - -function packageRelativePath(product, relativePath, context, prefix) { - if (typeof relativePath !== "string" || relativePath.length === 0) { - fail(prefix, `${context} must be a non-empty path string`); - } - const { packagePath } = releasePleasePackage(product, prefix); - const packageRoot = path.posix.normalize(packagePath.replaceAll("\\", "/")); - const relative = relativePath.replaceAll("\\", "/"); - const normalized = path.posix.normalize(path.posix.join(packageRoot, relative)); - if ( - path.posix.isAbsolute(relative) || - (normalized !== packageRoot && !normalized.startsWith(`${packageRoot}/`)) - ) { - fail(prefix, `${context} must stay within the product package path`); - } - return normalized; -} - -function requireExistingPath(relativePath, context, prefix) { - if (!existsSync(path.join(ROOT, relativePath))) { - fail(prefix, `${context} does not exist: ${relativePath}`); - } -} - -export function tagPrefix(product, prefix = "release-graph") { - const { config } = releasePleasePackagesByComponent(prefix); - const { packageConfig } = releasePleasePackage(product, prefix); - if (packageConfig.component !== product) { - fail(prefix, `${product} release-please component must match product id`); - } - if (config["include-v-in-tag"] !== true) { - fail(prefix, "release-please must include v in product tags"); - } - if (config["tag-separator"] !== "-") { - fail(prefix, "release-please tag-separator must be '-'"); - } - return `${product}-v`; -} - -export function versionFiles(product, prefix = "release-graph") { - const { packageConfig } = releasePleasePackage(product, prefix); - const releaseType = packageConfig["release-type"]; - const versionFile = packageConfig["version-file"]; - let canonical; - if (typeof versionFile === "string" && versionFile.length > 0) { - canonical = packageRelativePath(product, versionFile, `${product}.version-file`, prefix); - } else if (releaseType === "rust") { - canonical = packageRelativePath(product, "Cargo.toml", `${product}.rust`, prefix); - } else if (releaseType === "node" || releaseType === "expo") { - canonical = packageRelativePath(product, "package.json", `${product}.node`, prefix); - } else { - fail( - prefix, - `${product} release-please config must declare version-file for release type ${JSON.stringify(releaseType)}`, - ); - } - - const extraFiles = packageConfig["extra-files"] ?? []; - if (!Array.isArray(extraFiles)) { - fail(prefix, `${product}.extra-files must be a list`); - } - const files = [canonical]; - for (const [index, entry] of extraFiles.entries()) { - const context = `${product}.extra-files[${index}]`; - if (typeof entry === "string") { - files.push(packageRelativePath(product, entry, context, prefix)); - } else if (entry !== null && typeof entry === "object" && !Array.isArray(entry)) { - files.push(packageRelativePath(product, entry.path, `${context}.path`, prefix)); - } else { - fail(prefix, `${context} must be a path string or object`); - } - } - for (const file of files) { - requireExistingPath(file, `${product} version file`, prefix); - } - return files; -} - -export function changelogPath(product, prefix = "release-graph") { - const { packageConfig } = releasePleasePackage(product, prefix); - const relative = packageConfig["changelog-path"] ?? "CHANGELOG.md"; - const changelog = packageRelativePath(product, relative, `${product}.changelog-path`, prefix); - requireExistingPath(changelog, `${product} changelog`, prefix); - return changelog; -} - -function graphProducts(projects, prefix) { - const paths = releasePackagePaths(projects, prefix); - const manifest = readJson(".release-please-manifest.json", prefix); - const products = {}; - for (const [product, packagePath] of [...paths.entries()].sort(([left], [right]) => compareText(left, right))) { - const metadata = readToml(path.join(packagePath, "release.toml"), prefix); - const version = manifest[packagePath]; - if (metadata.id !== product) { - fail(prefix, `${packagePath}/release.toml must declare id = ${JSON.stringify(product)}`); - } - if (typeof version !== "string" || version.length === 0) { - fail(prefix, `.release-please-manifest.json is missing ${packagePath}`); - } - products[product] = { - ...metadata, - path: packagePath, - changelog_path: changelogPath(product, prefix), - derived_version_files: metadata.derived_version_files ?? [], - tag_prefix: tagPrefix(product, prefix), - version, - version_files: versionFiles(product, prefix), - }; - } - return products; -} - -function contribCarrierImpact(products, prefix) { - const carriers = loadContribCarriers(ROOT, prefix); - const owners = [carriers.nativeOwner, carriers.wasixOwner]; - if (owners.some((owner) => typeof owner !== "string" || !(owner in products))) { - fail(prefix, `${CONTRIB_CARRIERS_PATH} must name native and WASIX release-product owners`); - } - if (new Set(owners).size !== owners.length) { - fail(prefix, `${CONTRIB_CARRIERS_PATH} must name distinct runtime owners`); - } - return { - files: carriers.inputFiles, - products: owners, - }; -} - -function declaredSharedSourceImpacts(products, prefix) { - return Object.entries(products).flatMap(([product, config]) => { - const paths = config.shared_source_paths ?? []; - assertStringList(paths, `${product}.shared_source_paths`, prefix); - return paths.map((sourcePath) => { - if (!sourcePath || path.isAbsolute(sourcePath) || sourcePath.startsWith('../')) { - fail(prefix, `${product}.shared_source_paths must contain repository-relative paths`); - } - requireExistingPath(sourcePath, `${product} shared source`, prefix); - return {source_paths: [sourcePath.replace(/\/$/u, '')], products: [product]}; - }); - }); -} - -export function loadGraph(prefix = "release-graph") { - const moonProjects = moonProjectsById(prefix); - const products = graphProducts(moonProjects, prefix); - const graph = { - products, - moon_projects: Object.fromEntries(moonProjects), - shared_release_sources: [ - contribCarrierImpact(products, prefix), - ...declaredSharedSourceImpacts(products, prefix), - ], - }; - return graph; -} - -export function moonReleaseMetadataRows({ product = undefined } = {}, prefix = "release-graph") { - const graph = loadGraph(prefix); - const productIds = product === undefined ? Object.keys(graph.products).sort(compareText) : [product]; - if (product !== undefined && !(product in graph.products)) { - fail(prefix, `unknown release product ${product}`); - } - return productIds.map((productId) => { - const release = graph.moon_projects?.[productId]?.config?.project?.metadata?.release; - if (release === null || Array.isArray(release) || typeof release !== "object") { - fail(prefix, `Moon release metadata does not include ${productId}`); - } - if (release.component !== productId) { - fail(prefix, `Moon release metadata for ${productId} must use matching component`); - } - if (typeof release.packagePath !== "string" || release.packagePath.length === 0) { - fail(prefix, `Moon release metadata for ${productId} must declare packagePath`); - } - return { - product: productId, - ...release, - }; - }); -} - -export function wasixEvidenceProductsForRelease( - products, - projects, - selected, - prefix = "release-graph", -) { - const selectedProducts = new Set(selected); - const unknown = [...selectedProducts].filter((product) => !(product in products)).sort(compareText); - if (unknown.length > 0) { - fail(prefix, `unknown release products in WASIX evidence selection: ${unknown.join(", ")}`); - } - const required = []; - for (const product of [...selectedProducts].sort(compareText)) { - if (product === "liboliphaunt-wasix") { - required.push(product); - continue; - } - const config = products[product]; - const compatibility = config.compatibility_versions ?? {}; - const compatibilityRequiresWasix = Object.values(compatibility).some( - (entry) => entry !== null - && !Array.isArray(entry) - && typeof entry === "object" - && entry.source_product === "liboliphaunt-wasix", - ); - const projectId = releaseProductProjectId(product, products, projects, prefix); - const projectRequiresWasix = (projects[projectId]?.dependencies ?? []).some( - (dependency) => dependency.id === "liboliphaunt-wasix", - ); - if (compatibilityRequiresWasix || projectRequiresWasix) { - required.push(product); - } - } - return required; -} - -function assertObject(value, context, prefix) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(prefix, `${context} must be a table`); - } - return value; -} - -export function compatibilityVersionEntries( - products, - { requireSourceProduct = false, prefix = "release-graph", root = ROOT } = {}, -) { - const source = products ?? loadGraph(prefix).products; - const knownProducts = new Set(Object.keys(source)); - const entries = []; - for (const [product, config] of Object.entries(source).sort(([left], [right]) => compareText(left, right))) { - const rawSpecs = config.compatibility_versions ?? {}; - assertObject(rawSpecs, `${product}.compatibility_versions`, prefix); - for (const [specId, spec] of Object.entries(rawSpecs).sort(([left], [right]) => compareText(left, right))) { - if (!specId) { - fail(prefix, `${product}.compatibility_versions keys must be non-empty strings`); - } - assertObject(spec, `${product}.compatibility_versions.${specId}`, prefix); - const sourceProduct = spec.source_product; - if (requireSourceProduct) { - if (typeof sourceProduct !== "string" || sourceProduct.length === 0) { - fail(prefix, `${product}.compatibility_versions.${specId}.source_product must be a non-empty string`); - } - if (!knownProducts.has(sourceProduct)) { - fail( - prefix, - `${product}.compatibility_versions.${specId}.source_product must name a release product, got ${JSON.stringify( - sourceProduct, - )}`, - ); - } - } else if (sourceProduct !== undefined && typeof sourceProduct !== "string") { - fail(prefix, `${product}.compatibility_versions.${specId}.source_product must be a string when present`); - } - const specPath = spec.path; - const parser = spec.parser; - if (typeof specPath !== "string" || specPath.length === 0) { - fail(prefix, `${product}.compatibility_versions.${specId}.path must be a non-empty string`); - } - if (typeof parser !== "string" || parser.length === 0) { - fail(prefix, `${product}.compatibility_versions.${specId}.parser must be a non-empty string`); - } - if (!existsSync(path.join(root, specPath))) { - fail(prefix, `${product}.compatibility_versions.${specId} path does not exist: ${specPath}`); - } - entries.push({ - id: specId, - product, - sourceProduct: typeof sourceProduct === "string" ? sourceProduct : null, - path: specPath, - parser, - }); - } - } - return entries; -} - -export function compatibilityVersionValue( - entry, - { ref = null, root = ROOT, prefix = "release-graph", missingValue = undefined } = {}, -) { - const text = ref === null - ? readFileSync(path.join(root, entry.path), "utf8") - : fileAtRef(root, ref, entry.path); - if (text === null) { - if (missingValue !== undefined) return missingValue; - fail(prefix, `cannot read ${entry.path} at immutable compatibility ref ${ref}`); - } - if (entry.parser === "raw") return text.trim(); - if (entry.parser.startsWith("rust-const:")) { - const name = entry.parser.slice("rust-const:".length); - if (!/^[A-Z][A-Z0-9_]*$/u.test(name)) { - fail(prefix, `${entry.id} has an invalid Rust constant parser`); - } - const matches = [...text.matchAll(new RegExp( - `(?:pub\\s+)?const\\s+${name}\\s*:[^=]+?=\\s*"([^"]+)"\\s*;`, - "gu", - ))]; - if (matches.length !== 1) { - if (matches.length === 0 && missingValue !== undefined) return missingValue; - fail(prefix, `${entry.id} must name exactly one Rust string constant`); - } - return matches[0][1]; - } - const separator = entry.parser.indexOf(":"); - const type = entry.parser.slice(0, separator); - if (type !== "json" && type !== "toml") { - fail(prefix, `${entry.id} uses unsupported compatibility parser ${entry.parser}`); - } - const parts = entry.parser.slice(separator + 1).split("."); - let data; - try { - data = type === "json" ? JSON.parse(text) : type === "toml" ? Bun.TOML.parse(text) : null; - } catch (cause) { - fail(prefix, `${entry.path} is not valid ${type.toUpperCase()}: ${cause.message}`); - } - const value = valueAtPath(data, parts); - if (typeof value !== "string" || value.length === 0) { - if (value === undefined && missingValue !== undefined) return missingValue; - fail(prefix, `${entry.id} parser ${entry.parser} must resolve to a non-empty string`); - } - return value; -} - -export function productCompatibilityVersion( - product, - sourceProduct, - prefix = "release-graph", -) { - const graph = loadGraph(prefix); - const entries = compatibilityVersionEntries(graph.products, { - requireSourceProduct: true, - prefix, - }).filter((entry) => entry.product === product && entry.sourceProduct === sourceProduct); - if (entries.length === 0) { - fail(prefix, `${product} does not declare compatibility with ${sourceProduct}`); - } - const values = new Set(entries.map((entry) => compatibilityVersionValue(entry, { prefix }))); - if (values.size !== 1) { - fail(prefix, `${product} declares conflicting compatibility versions for ${sourceProduct}`); - } - return [...values][0]; -} - -export function tagMatchPattern(prefix) { - return prefix ? `${prefix}[0-9]*` : "[0-9]*"; -} - -export function tagPrefixes(config, prefix = "release-graph") { - if (typeof config.tag_prefix !== "string" || config.tag_prefix.length === 0) { - fail(prefix, "release products must declare tag_prefix"); - } - const legacyPrefixes = config.legacy_tag_prefixes ?? []; - assertStringList(legacyPrefixes, "legacy_tag_prefixes", prefix); - return [config.tag_prefix, ...legacyPrefixes]; -} - -export function latestTagForPrefix(prefix, headRef, root = ROOT) { - const args = ["describe", "--tags", "--abbrev=0", "--match", tagMatchPattern(prefix), headRef]; - const result = captureCommandOutput("git", args, { - allowEmptyOutput: true, - cwd: root, - label: `git ${args.join(" ")}`, - stdoutTerminator: "\n", - }); - if (result.error !== undefined) throw result.error; - return result.status === 0 ? result.stdout.trim() : ""; -} - -export function latestProductTag(productConfig, headRef, prefix = "release-graph", root = ROOT) { - for (const candidatePrefix of tagPrefixes(productConfig, prefix)) { - const tag = latestTagForPrefix(candidatePrefix, headRef, root); - if (tag) { - return tag; - } - } - return EMPTY_TREE; -} - -function gitAt( - root, - args, - { allowEmptyOutput = false, check = true, stdoutTerminator = undefined } = {}, -) { - const result = captureCommandOutput("git", args, { - allowEmptyOutput, - cwd: root, - label: `git ${args.join(" ")}`, - stdoutTerminator, - }); - if (result.error !== undefined) { - throw new Error(`git ${args.join(" ")} failed: ${result.error.message}`); - } - if (check && result.status !== 0) { - const detail = (result.stderr || result.stdout || "").trim(); - throw new Error(`git ${args.join(" ")} failed${detail ? `: ${detail}` : ""}`); - } - return { status: result.status, stdout: result.stdout.trim(), rawStdout: result.stdout }; -} - -function commitForRefAt(root, ref, { check = true } = {}) { - const result = gitAt( - root, - ["rev-parse", "--verify", "--quiet", `${ref}^{commit}`], - { allowEmptyOutput: !check, check, stdoutTerminator: "\n" }, - ); - return result.status === 0 ? result.stdout : null; -} - -export function commitForRef(ref, root = ROOT) { - return commitForRefAt(root, ref); -} - -export function changedFilesFromRefs(baseRef, headRef, prefix = "release-graph", root = ROOT) { - try { - const result = - baseRef === EMPTY_TREE - ? gitAt( - root, - ["diff", "--name-only", "-z", baseRef, headRef, "--"], - { allowEmptyOutput: true, stdoutTerminator: "\0" }, - ) - : gitAt( - root, - ["diff", "--name-only", "-z", `${baseRef}...${headRef}`, "--"], - { allowEmptyOutput: true, stdoutTerminator: "\0" }, - ); - return result.rawStdout.split("\0").filter(Boolean).sort(compareText); - } catch (error) { - fail(prefix, `failed to read changed files between ${baseRef} and ${headRef}: ${error.message}`); - } -} - -function manifestAtRef(root, ref, prefix) { - let value; - try { - value = JSON.parse(gitAt(root, ["show", `${ref}:.release-please-manifest.json`]).stdout); - } catch (error) { - throw new Error(`${prefix}: cannot read .release-please-manifest.json at ${ref}: ${error.message}`); - } - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw new Error(`${prefix}: .release-please-manifest.json at ${ref} must contain a JSON object`); - } - return value; -} - -function canonicalVersionAtRef(root, ref, product, config, prefix) { - const file = config?.version_files?.[0]; - if (typeof file !== "string" || file.length === 0) { - throw new Error(`${prefix}: ${product} is missing its canonical version file metadata`); - } - let text; - try { - text = gitAt(root, ["show", `${ref}:${file}`]).stdout; - } catch (error) { - throw new Error(`${prefix}: cannot read ${product} canonical version file ${file} at ${ref}: ${error.message}`); - } - const basename = path.posix.basename(file); - let version; - try { - if (basename === "Cargo.toml") { - version = Bun.TOML.parse(text)?.package?.version; - } else if (basename === "package.json") { - version = JSON.parse(text)?.version; - } else { - version = text.trim(); - } - } catch (error) { - throw new Error(`${prefix}: cannot parse ${product} canonical version file ${file} at ${ref}: ${error.message}`); - } - transitionVersion(version, `${product} canonical version in ${file} at ${ref}`, prefix); - return version; -} - -function transitionVersion(value, context, prefix) { - if (typeof value !== "string" || !/^(?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)$/u.test(value)) { - throw new Error(`${prefix}: ${context} must be a stable x.y.z version, got ${JSON.stringify(value)}`); - } - return value.split(".").map((part) => Number.parseInt(part, 10)); -} - -function manifestProductVersion(products, manifest, product, ref, prefix) { - const packagePath = products[product]?.path; - if (typeof packagePath !== "string" || packagePath.length === 0) { - throw new Error(`${prefix}: compatibility source product ${product} is missing its Release Please package path`); - } - const version = manifest[packagePath]; - transitionVersion(version, `${product} manifest version at ${ref}`, prefix); - return version; -} - -function fileAtRef(root, ref, file) { - const result = gitAt(root, ["show", `${ref}:${file}`], { check: false }); - return result.status === 0 ? result.rawStdout : null; -} - -function semanticDifferences(before, after, parts = []) { - if (Object.is(before, after)) return []; - const beforeObject = before !== null && typeof before === "object"; - const afterObject = after !== null && typeof after === "object"; - if (beforeObject && afterObject && Array.isArray(before) === Array.isArray(after)) { - const keys = new Set(Array.isArray(before) - ? Array.from({ length: Math.max(before.length, after.length) }, (_value, index) => index) - : [...Object.keys(before), ...Object.keys(after)]); - return [...keys].flatMap((key) => semanticDifferences(before[key], after[key], [...parts, key])); - } - return [{ parts, before, after }]; -} - -function compatibilityPathKey(parts) { - return parts.map(String).join("\0"); -} - -function valueAtPath(value, parts) { - let current = value; - for (const part of parts) { - if (current === null || typeof current !== "object") return undefined; - current = current[part]; - } - return current; -} - -function parseCompatibilityStructuredFile(text, type) { - try { - const value = type === "json" ? JSON.parse(text) : Bun.TOML.parse(text); - return value !== null && typeof value === "object" ? value : null; - } catch { - return null; - } -} - -function compatibilityParser(entry) { - const separator = entry.parser.indexOf(":"); - const type = separator === -1 ? entry.parser : entry.parser.slice(0, separator); - const expression = separator === -1 ? "" : entry.parser.slice(separator + 1); - if ((type === "json" || type === "toml") && /^[A-Za-z0-9_-]+(?:[.][A-Za-z0-9_-]+)*$/u.test(expression)) { - return { type, parts: expression.split(".") }; - } - if (type === "raw" && expression === "") return { type, parts: [] }; - if (type === "rust-const" && /^[A-Z][A-Z0-9_]*$/u.test(expression)) { - return { type, name: expression, parts: [] }; - } - return null; -} - -function maskRustCompatibilityConst(text, name, expected, token) { - const escaped = name.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"); - const pattern = new RegExp( - `(^|\\n)([\\t ]*(?:pub[\\t ]+)?const[\\t ]+${escaped}[\\t ]*:[\\t ]*&str[\\t ]*=[\\t ]*")([^"]+)("[\\t ]*;[^\\n]*)`, - "gu", - ); - const matches = [...text.matchAll(pattern)]; - if (matches.length !== 1 || matches[0][3] !== expected) return null; - return text.replace(pattern, `$1$2${token}$4`); -} - -function compatibilityFileHasOnlyExpectedChanges({ - beforeText, - afterText, - entries, - beforeManifest, - afterManifest, - products, - baseRef, - headRef, - prefix, -}) { - const rules = entries.map((entry) => { - const parser = compatibilityParser(entry); - if (parser === null) return null; - return { - entry, - parser, - before: manifestProductVersion(products, beforeManifest, entry.sourceProduct, baseRef, prefix), - after: manifestProductVersion(products, afterManifest, entry.sourceProduct, headRef, prefix), - }; - }); - if (rules.some((rule) => rule === null)) return false; - - const types = new Set(rules.map((rule) => rule.parser.type)); - if (types.size !== 1) return false; - const type = rules[0].parser.type; - if (type === "raw") { - return rules.length === 1 && beforeText.trim() === rules[0].before && afterText.trim() === rules[0].after; - } - if (type === "rust-const") { - let maskedBefore = beforeText; - let maskedAfter = afterText; - for (const rule of rules) { - const token = ``; - maskedBefore = maskRustCompatibilityConst(maskedBefore, rule.parser.name, rule.before, token); - maskedAfter = maskRustCompatibilityConst(maskedAfter, rule.parser.name, rule.after, token); - if (maskedBefore === null || maskedAfter === null) return false; - } - return maskedBefore === maskedAfter; - } - - const before = parseCompatibilityStructuredFile(beforeText, type); - const after = parseCompatibilityStructuredFile(afterText, type); - if (before === null || after === null) return false; - const allowed = new Map(); - for (const rule of rules) { - const key = compatibilityPathKey(rule.parser.parts); - const previous = allowed.get(key); - if ( - previous !== undefined && - (previous.before !== rule.before || previous.after !== rule.after || previous.entry.sourceProduct !== rule.entry.sourceProduct) - ) { - return false; - } - if ( - valueAtPath(before, rule.parser.parts) !== rule.before || - valueAtPath(after, rule.parser.parts) !== rule.after - ) { - return false; - } - allowed.set(key, rule); - } - return semanticDifferences(before, after).every((difference) => { - const rule = allowed.get(compatibilityPathKey(difference.parts)); - return rule !== undefined && difference.before === rule.before && difference.after === rule.after; - }); -} - -function compatibilityOnlyChangedFiles({ - product, - products, - entries, - files, - baseRef, - headRef, - prefix, - root, -}) { - const byFile = new Map(); - for (const entry of entries) { - if (entry.product !== product) continue; - byFile.set(entry.path, [...(byFile.get(entry.path) ?? []), entry]); - } - if (byFile.size === 0) return new Set(); - const beforeManifest = manifestAtRef(root, baseRef, prefix); - const afterManifest = manifestAtRef(root, headRef, prefix); - const ignored = new Set(); - for (const file of files) { - const fileEntries = byFile.get(file); - if (fileEntries === undefined) continue; - const beforeText = fileAtRef(root, baseRef, file); - const afterText = fileAtRef(root, headRef, file); - if ( - beforeText !== null && - afterText !== null && - compatibilityFileHasOnlyExpectedChanges({ - beforeText, - afterText, - entries: fileEntries, - beforeManifest, - afterManifest, - products, - baseRef, - headRef, - prefix, - }) - ) { - ignored.add(file); - } - } - return ignored; -} - -function versionFromProductTag(config, tag, prefix) { - for (const candidatePrefix of tagPrefixes(config, prefix)) { - if (!tag.startsWith(candidatePrefix)) continue; - const version = tag.slice(candidatePrefix.length); - transitionVersion(version, `product tag ${tag}`, prefix); - return version; - } - throw new Error(`${prefix}: product tag ${tag} does not use a declared tag prefix`); -} - -/** - * Classify one product's immutable release identity at headRef. - * - * Path impact is deliberately not considered here. A normal candidate must - * have advanced its own Release Please manifest version since its latest - * reachable product tag. An exact current-version tag is eligible only for an - * explicitly requested exact-commit rerun. - */ -export function productVersionTransitionStatus( - product, - config, - baseRef, - headRef, - { - includeCurrentTags = false, - prefix = "release-graph", - root = ROOT, - } = {}, -) { - const packagePath = config?.path; - if (typeof packagePath !== "string" || packagePath.length === 0) { - throw new Error(`${prefix}: ${product} is missing its Release Please package path`); - } - const headCommit = commitForRefAt(root, headRef); - const headVersion = manifestAtRef(root, headCommit, prefix)[packagePath]; - const headParts = transitionVersion(headVersion, `${product} manifest version at ${headCommit}`, prefix); - if (headVersion !== config.version) { - throw new Error( - `${prefix}: ${product} graph version ${JSON.stringify(config.version)} does not match ` + - `its manifest version ${JSON.stringify(headVersion)} at ${headCommit}`, - ); - } - const headCanonicalVersion = canonicalVersionAtRef(root, headCommit, product, config, prefix); - if (headCanonicalVersion !== headVersion) { - throw new Error( - `${prefix}: ${product} canonical version ${JSON.stringify(headCanonicalVersion)} does not match ` + - `its manifest version ${JSON.stringify(headVersion)} at ${headCommit}`, - ); - } - - let baseVersion = null; - let comparison = null; - if (baseRef !== EMPTY_TREE) { - baseVersion = versionFromProductTag(config, baseRef, prefix); - const taggedManifestVersion = manifestAtRef(root, baseRef, prefix)[packagePath]; - if (taggedManifestVersion !== baseVersion) { - throw new Error( - `${prefix}: ${product} base tag ${baseRef} names ${baseVersion}, but its manifest contains ` + - `${JSON.stringify(taggedManifestVersion)}`, - ); - } - const taggedCanonicalVersion = canonicalVersionAtRef(root, baseRef, product, config, prefix); - if (taggedCanonicalVersion !== baseVersion) { - throw new Error( - `${prefix}: ${product} base tag ${baseRef} names ${baseVersion}, but its canonical version file contains ` + - `${JSON.stringify(taggedCanonicalVersion)}`, - ); - } - comparison = compareVersion(headParts, transitionVersion(baseVersion, `${product} base tag version`, prefix)); - if (comparison < 0) { - throw new Error( - `${prefix}: ${product} manifest version ${headVersion} is older than tagged version ${baseVersion}`, - ); - } - } - - const currentTag = `${config.tag_prefix}${headVersion}`; - const currentTagCommit = commitForRefAt(root, `refs/tags/${currentTag}`, { check: false }); - if (currentTagCommit !== null) { - const taggedManifestVersion = manifestAtRef(root, currentTagCommit, prefix)[packagePath]; - if (taggedManifestVersion !== headVersion) { - throw new Error( - `${prefix}: ${product} current-version tag ${currentTag} points at ${currentTagCommit}, whose manifest ` + - `contains ${JSON.stringify(taggedManifestVersion)} instead of ${JSON.stringify(headVersion)}`, - ); - } - const taggedCanonicalVersion = canonicalVersionAtRef(root, currentTagCommit, product, config, prefix); - if (taggedCanonicalVersion !== headVersion) { - throw new Error( - `${prefix}: ${product} current-version tag ${currentTag} points at ${currentTagCommit}, whose canonical ` + - `version file contains ${JSON.stringify(taggedCanonicalVersion)} instead of ${JSON.stringify(headVersion)}`, - ); - } - if (currentTagCommit === headCommit) { - return { - eligible: includeCurrentTags, - rerun: includeCurrentTags, - firstRelease: false, - baseVersion: headVersion, - headVersion, - currentTag, - currentTagCommit, - }; - } - const ancestor = gitAt(root, ["merge-base", "--is-ancestor", currentTagCommit, headCommit], { check: false }).status === 0; - if (!ancestor) { - throw new Error( - `${prefix}: ${product} current-version tag ${currentTag} points at ${currentTagCommit}, ` + - `which is not an ancestor of release candidate ${headCommit}`, - ); - } - return { - eligible: false, - rerun: false, - firstRelease: false, - baseVersion: headVersion, - headVersion, - currentTag, - currentTagCommit, - }; - } - - if (baseRef === EMPTY_TREE) { - const firstRelease = compareVersion(headParts, [0, 0, 0]) > 0; - return { - eligible: firstRelease, - rerun: false, - firstRelease, - baseVersion: null, - headVersion, - currentTag, - currentTagCommit: null, - }; - } - return { - eligible: comparison > 0, - rerun: false, - firstRelease: false, - baseVersion, - headVersion, - currentTag, - currentTagCommit: null, - }; -} - -export function isGeneratedLocalState(candidate) { - if (candidate.startsWith("target/")) { - return true; - } - return candidate.split(/[\\/]/).some((part) => GENERATED_PATH_PARTS.has(part)); -} - -export function normalizeFiles(files) { - const normalized = new Set(); - for (const file of files) { - let candidate = file.trim().replaceAll("\\", "/"); - if (candidate.startsWith("./")) { - candidate = candidate.slice(2); - } - if (candidate && !isGeneratedLocalState(candidate)) { - normalized.add(candidate); - } - } - return [...normalized].sort(compareText); -} - -function splitPatterns(patterns) { - const includes = []; - const excludes = []; - for (const pattern of patterns) { - if (pattern.startsWith("!")) { - excludes.push(pattern.slice(1)); - } else { - includes.push(pattern); - } - } - return { includes, excludes }; -} - -function globPatternToRegExp(pattern) { - let text = ""; - for (const char of pattern) { - if (char === "*") { - text += ".*"; - } else if ("\\^$+?.()|{}[]".includes(char)) { - text += `\\${char}`; - } else { - text += char; - } - } - return new RegExp(`^${text}$`, "u"); -} - -function matchesAny(candidate, patterns) { - return patterns.some((pattern) => globPatternToRegExp(pattern).test(candidate)); -} - -export function productMatches(candidate, patterns) { - const { includes, excludes } = splitPatterns(patterns); - return matchesAny(candidate, includes) && !matchesAny(candidate, excludes); -} - -export function ownerProjectForPath(projects, candidate) { - if (isGeneratedLocalState(candidate)) { - return undefined; - } - const matches = Object.values(projects) - .filter( - (project) => - project.source === "." || candidate === project.source || candidate.startsWith(`${project.source}/`), - ) - .sort((left, right) => right.source.length - left.source.length); - return matches[0]?.id; -} - -export function releaseOwnerProjectsForPath(products, projects, candidate, prefix = "release-graph") { - if (isGeneratedLocalState(candidate)) { - return []; - } - return Object.entries(products) - .filter(([, config]) => { - const packagePath = config?.path; - return typeof packagePath === "string" - && packagePath.length > 0 - && (candidate === packagePath || candidate.startsWith(`${packagePath}/`)); - }) - .map(([product]) => releaseProductProjectId(product, products, projects, prefix)) - .filter((projectId, index, values) => values.indexOf(projectId) === index) - .sort(compareText); -} - -export function releaseProductProjectId(product, products, projects, prefix = "release-graph") { - if (product in projects) { - return product; - } - const packagePath = products[product]?.path; - if (typeof packagePath !== "string" || packagePath.length === 0) { - fail(prefix, `release product ${product} is missing package path metadata`); - } - const matches = Object.values(projects) - .filter((project) => packagePath === project.source || packagePath.startsWith(`${project.source}/`)) - .sort((left, right) => right.source.length - left.source.length); - if (matches.length === 0) { - fail(prefix, `release product ${product} has no owning Moon project for ${packagePath}`); - } - return matches[0].id; -} - -export function releaseProductsForProjects(products, projects, projectIds, prefix = "release-graph") { - const selectedProjects = new Set(projectIds); - const selected = new Set(); - for (const product of Object.keys(products)) { - const projectId = releaseProductProjectId(product, products, projects, prefix); - if (selectedProjects.has(projectId)) { - selected.add(product); - } - } - return selected; -} - -function releaseProductsForSourceProjects(products, projects, projectIds, prefix) { - const productByProject = new Map( - Object.keys(products).map((product) => [ - releaseProductProjectId(product, products, projects, prefix), - product, - ]), - ); - const dependents = new Map(); - for (const project of Object.values(projects)) { - for (const dependency of project.dependencies ?? []) { - if (dependency.scope === "development") continue; - dependents.set(dependency.id, [...(dependents.get(dependency.id) ?? []), project.id]); - } - } - - const selected = new Set(); - const visited = new Set(); - const queue = [...projectIds]; - while (queue.length > 0) { - const project = queue.shift(); - if (visited.has(project)) continue; - visited.add(project); - const product = productByProject.get(project); - if (product !== undefined) { - selected.add(product); - continue; - } - queue.push(...(dependents.get(project) ?? [])); - } - return selected; -} - -export function releaseOrder(products, _projects, selected, prefix = "release-graph") { - const selectedSet = new Set(selected); - const ordered = []; - const remaining = new Set(selectedSet); - while (remaining.size > 0) { - const ready = []; - for (const product of [...remaining].sort(compareText)) { - const deps = new Set( - Object.values(products[product]?.compatibility_versions ?? {}) - .map((dependency) => dependency?.source_product) - .filter((dependency) => typeof dependency === "string" && dependency !== product), - ); - const selectedDeps = [...deps].filter((dependency) => selectedSet.has(dependency)); - if (selectedDeps.every((dependency) => ordered.includes(dependency))) { - ready.push(product); - } - } - if (ready.length === 0) { - fail(prefix, `release compatibility graph has a dependency cycle: ${JSON.stringify([...remaining].sort(compareText))}`); - } - for (const product of ready) { - ordered.push(product); - remaining.delete(product); - } - } - return ordered; -} - -export function buildPlan(graph, files, prefix = "release-graph") { - const products = graph.products; - const projects = graph.moon_projects; - if (products === null || Array.isArray(products) || typeof products !== "object") { - fail(prefix, "release metadata must define [products.] entries"); - } - if (projects === null || Array.isArray(projects) || typeof projects !== "object") { - fail(prefix, "Moon project graph is missing from release plan metadata"); - } - const directProjects = new Set(); - for (const file of files) { - const sharedImpacts = (graph.shared_release_sources ?? []) - .filter((impact) => - (impact.files ?? []).includes(file) - || (impact.source_paths ?? []).some((sourcePath) => - file === sourcePath || file.startsWith(`${sourcePath}/`) - ) - ); - if (sharedImpacts.length > 0) { - for (const impact of sharedImpacts) { - for (const product of impact.products) { - directProjects.add(releaseProductProjectId(product, products, projects, prefix)); - } - } - // The explicit carrier mapping is authoritative. Traversing the shared - // source project's other consumers would fabricate downstream releases. - continue; - } - const owner = ownerProjectForPath(projects, file); - if (owner !== undefined) { - directProjects.add(owner); - } - // A nested Moon project may own CI work without being an independently - // versioned product. Preserve that precise CI owner while also selecting - // every enclosing release component (for example a contrib bundle). - for (const releaseOwner of releaseOwnerProjectsForPath(products, projects, file, prefix)) { - directProjects.add(releaseOwner); - } - } - // Follow owned source inputs to their first independently publishable - // boundary, then stop. A runtime change selects the runtime, not every SDK - // that can consume it; a private source-pin change still selects its runtime. - const releaseProductSet = releaseProductsForSourceProjects( - products, - projects, - directProjects, - prefix, - ); - const releaseProducts = releaseOrder(products, projects, releaseProductSet, prefix); - const direct = releaseOrder( - products, - projects, - releaseProductsForProjects(products, projects, directProjects, prefix), - prefix, - ); - return { - changedFiles: files, - directProducts: direct, - releaseProducts, - hasReleaseChanges: releaseProducts.length > 0, - }; -} - -export function buildPlanFromProductTags( - graph, - headRef, - { includeCurrentTags = false, prefix = "release-graph", root = ROOT } = {}, -) { - const products = graph.products; - const direct = new Set(); - const changed = new Set(); - const currentTaggedProducts = new Set(); - const compatibilityEntries = compatibilityVersionEntries(products, { - requireSourceProduct: true, - prefix, - root, - }); - - for (const [product, config] of Object.entries(products)) { - const baseRef = latestProductTag(config, headRef, prefix, root); - const transition = productVersionTransitionStatus(product, config, baseRef, headRef, { - includeCurrentTags, - prefix, - root, - }); - const productFiles = transition.eligible || baseRef !== EMPTY_TREE - ? changedFilesFromRefs(baseRef, headRef, prefix, root) - : []; - for (const file of productFiles) { - changed.add(file); - } - if (!transition.eligible) { - if (baseRef !== EMPTY_TREE && productFiles.length > 0) { - const ignored = compatibilityOnlyChangedFiles({ - product, - products, - entries: compatibilityEntries, - files: productFiles, - baseRef, - headRef, - prefix, - root, - }); - const impactFiles = productFiles.filter((file) => !ignored.has(file)); - const impactPlan = buildPlan(graph, normalizeFiles(impactFiles), prefix); - if (impactPlan.releaseProducts.includes(product)) { - const selectingFiles = impactFiles.filter((file) => - buildPlan(graph, normalizeFiles([file]), prefix).releaseProducts.includes(product) - ); - const relevantFiles = selectingFiles.length > 0 ? selectingFiles : impactFiles; - const shown = relevantFiles.slice(0, 12); - const suffix = relevantFiles.length > shown.length ? `, ... (${relevantFiles.length - shown.length} more)` : ""; - throw new Error( - `${prefix}: ${product} has release-affecting changes since ${baseRef}, but its manifest version ` + - `remains ${transition.headVersion}; bump the product version before publishing. ` + - `Non-compatibility changed paths: ${shown.join(", ")}${suffix}`, - ); - } - } - continue; - } - if (transition.rerun) { - direct.add(product); - currentTaggedProducts.add(product); - continue; - } - const productPlan = buildPlan(graph, normalizeFiles(productFiles), prefix); - if (!productPlan.releaseProducts.includes(product)) { - throw new Error( - `${prefix}: ${product} manifest advanced from ${transition.baseVersion ?? "first release"} to ` + - `${transition.headVersion}, but its changed paths do not select the product in the Moon release graph`, - ); - } - direct.add(product); - } - - const projects = graph.moon_projects; - const releaseProductSet = new Set(direct); - const releaseProducts = releaseOrder(products, projects, releaseProductSet, prefix); - return { - changedFiles: [...changed].sort(compareText), - directProducts: releaseOrder(products, projects, direct, prefix), - releaseProducts, - hasReleaseChanges: releaseProducts.length > 0, - currentTaggedProducts: [...currentTaggedProducts].sort(compareText), - }; -} diff --git a/tools/release/release-graph.mts b/tools/release/release-graph.mts new file mode 100644 index 000000000..000705243 --- /dev/null +++ b/tools/release/release-graph.mts @@ -0,0 +1,1425 @@ +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + CONTRIB_CARRIERS_PATH, + loadContribCarriers, +} from '../../src/extensions/artifacts/packages/tools/contrib-carriers.mts'; +import { + historyAncestor, + historyChanges, + historyCommit, + historyFile, + historyLatestTag, + historyManifest, +} from './release-history.mts'; + +export const ROOT = path.resolve(import.meta.dir, '../..'); +export const EMPTY_TREE = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'; +const GENERATED_PATH_PARTS = new Set([ + '.build', + '.cxx', + '.expo', + '.gradle', + '.kotlin', + '.moon', + '.next', + '.source', + 'DerivedData', + 'Pods', + '__pycache__', + 'dist', + 'lib', + 'node_modules', + 'out', + 'target', +]); + +export function fail(prefix, message) { + console.error(`${prefix}: ${message}`); + process.exit(1); +} + +export function rel(file) { + const relative = path.relative(ROOT, file); + return relative.startsWith('..') ? file : relative.split(path.sep).join('/'); +} + +export function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +export function readJson(relativePath, prefix) { + const value = JSON.parse(readFileSync(path.join(ROOT, relativePath), 'utf8')); + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(prefix, `${relativePath} must contain a JSON object`); + } + return value; +} + +export function readToml(relativePath, prefix) { + const file = path.join(ROOT, relativePath); + if (!existsSync(file)) { + fail(prefix, `missing ${relativePath}`); + } + const value = Bun.TOML.parse(readFileSync(file, 'utf8')); + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(prefix, `${relativePath} must contain a TOML table`); + } + return value; +} + +export function parseStableVersion(version, prefix = 'release-graph') { + const match = /^([0-9]+)[.]([0-9]+)[.]([0-9]+)$/.exec(version); + if (!match) { + fail( + prefix, + `release version must be stable x.y.z for automated publish, got ${JSON.stringify(version)}`, + ); + } + return match.slice(1).map((part) => Number.parseInt(part, 10)); +} + +export function compareVersion(left, right) { + for (let index = 0; index < 3; index += 1) { + if (left[index] !== right[index]) { + return left[index] - right[index]; + } + } + return 0; +} + +export function formatVersion(version) { + return version.join('.'); +} + +export function assertStringList(value, context, prefix = 'release-graph') { + if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) { + fail(prefix, `${context} must be a string list`); + } + return value; +} + +function releasePleasePackagesByComponent(prefix) { + const config = readJson('release-please-config.json', prefix); + const packages = config.packages; + if (packages === null || Array.isArray(packages) || typeof packages !== 'object') { + fail(prefix, 'release-please-config.json must define packages'); + } + const byComponent = new Map(); + for (const [packagePath, packageConfig] of Object.entries(packages)) { + if ( + packageConfig === null || + Array.isArray(packageConfig) || + typeof packageConfig !== 'object' + ) { + fail(prefix, `${packagePath} release-please config must be an object`); + } + const component = packageConfig.component; + if (typeof component !== 'string' || component.length === 0) { + fail(prefix, `${packagePath}.component must be a non-empty string`); + } + if (byComponent.has(component)) { + fail(prefix, `duplicate release-please component ${component}`); + } + byComponent.set(component, { packagePath, packageConfig }); + } + return { config, byComponent }; +} + +export function parseMoonProjects(result, prefix = 'release-graph') { + if (!Array.isArray(result?.projects) || result.projects.length === 0) { + fail(prefix, 'Moon snapshot must contain resolved projects'); + } + return new Map( + result.projects.map(({ id, source, dependencies = [], config }) => [ + id, + { + id, + source, + dependencies: [...dependencies].sort((left, right) => compareText(left.id, right.id)), + config: { tags: [...(config.tags ?? [])].sort(compareText), project: config.project ?? {} }, + }, + ]), + ); +} + +export function moonProjectsById(prefix = 'release-graph') { + const file = process.env.OLIPHAUNT_MOON_PROJECTS_FILE; + if (!file) + fail( + prefix, + 'resolved Moon projects are required; use the release-plan.sh or sync-release-pr.sh entry point', + ); + return parseMoonProjects(JSON.parse(readFileSync(file, 'utf8')), prefix); +} + +function moonReleaseProjectsByComponent(projects, prefix) { + const products = new Map(); + for (const project of projects.values()) { + const config = project.config; + const metadata = + config.project.metadata && + typeof config.project.metadata === 'object' && + !Array.isArray(config.project.metadata) + ? config.project.metadata + : {}; + const release = + metadata.release && typeof metadata.release === 'object' && !Array.isArray(metadata.release) + ? metadata.release + : undefined; + if (!config.tags.includes('release-product')) { + if (release !== undefined) { + fail( + prefix, + `Moon project ${project.id} declares release metadata but is not tagged release-product`, + ); + } + continue; + } + if (release === undefined) { + fail(prefix, `Moon release product ${project.id} must declare project.metadata.release`); + } + if (release.component !== project.id) { + fail( + prefix, + `Moon release product ${project.id} release.component must match the project id`, + ); + } + if (typeof release.packagePath !== 'string' || release.packagePath.length === 0) { + fail(prefix, `Moon release product ${project.id} must declare release.packagePath`); + } + if (products.has(release.component)) { + fail(prefix, `duplicate Moon release component ${release.component}`); + } + products.set(release.component, { + projectId: project.id, + projectSource: project.source, + path: release.packagePath, + release, + }); + } + if (products.size === 0) { + fail(prefix, 'Moon project graph does not contain any release-product projects'); + } + return products; +} + +function releasePackagePaths(projects, prefix) { + const { byComponent } = releasePleasePackagesByComponent(prefix); + const moonProducts = moonReleaseProjectsByComponent(projects, prefix); + const moonComponents = [...moonProducts.keys()].sort(compareText); + const releaseComponents = [...byComponent.keys()].sort(compareText); + if (JSON.stringify(moonComponents) !== JSON.stringify(releaseComponents)) { + fail( + prefix, + `Moon release-product components must match release-please components: moon=${JSON.stringify( + moonComponents, + )}, release-please=${JSON.stringify(releaseComponents)}`, + ); + } + const paths = new Map(); + for (const component of moonComponents) { + const moonPath = moonProducts.get(component).path; + const releasePath = byComponent.get(component).packagePath; + if (moonPath !== releasePath) { + fail( + prefix, + `${component} Moon release.packagePath ${JSON.stringify(moonPath)} must match release-please package path ${JSON.stringify( + releasePath, + )}`, + ); + } + paths.set(component, moonPath); + } + return paths; +} + +function releasePleasePackage(product, prefix) { + const { byComponent } = releasePleasePackagesByComponent(prefix); + const packageInfo = byComponent.get(product); + if (!packageInfo) { + fail(prefix, `unknown release-please component ${product}`); + } + return packageInfo; +} + +function packageRelativePath(product, relativePath, context, prefix) { + if (typeof relativePath !== 'string' || relativePath.length === 0) { + fail(prefix, `${context} must be a non-empty path string`); + } + const { packagePath } = releasePleasePackage(product, prefix); + const packageRoot = path.posix.normalize(packagePath.replaceAll('\\', '/')); + const relative = relativePath.replaceAll('\\', '/'); + const normalized = path.posix.normalize(path.posix.join(packageRoot, relative)); + if ( + path.posix.isAbsolute(relative) || + (normalized !== packageRoot && !normalized.startsWith(`${packageRoot}/`)) + ) { + fail(prefix, `${context} must stay within the product package path`); + } + return normalized; +} + +function requireExistingPath(relativePath, context, prefix) { + if (!existsSync(path.join(ROOT, relativePath))) { + fail(prefix, `${context} does not exist: ${relativePath}`); + } +} + +export function tagPrefix(product, prefix = 'release-graph') { + const { config } = releasePleasePackagesByComponent(prefix); + const { packageConfig } = releasePleasePackage(product, prefix); + if (packageConfig.component !== product) { + fail(prefix, `${product} release-please component must match product id`); + } + if (config['include-v-in-tag'] !== true) { + fail(prefix, 'release-please must include v in product tags'); + } + if (config['tag-separator'] !== '-') { + fail(prefix, "release-please tag-separator must be '-'"); + } + return `${product}-v`; +} + +export function versionFiles(product, prefix = 'release-graph') { + const { packageConfig } = releasePleasePackage(product, prefix); + const releaseType = packageConfig['release-type']; + const versionFile = packageConfig['version-file']; + let canonical; + if (typeof versionFile === 'string' && versionFile.length > 0) { + canonical = packageRelativePath(product, versionFile, `${product}.version-file`, prefix); + } else if (releaseType === 'rust') { + canonical = packageRelativePath(product, 'Cargo.toml', `${product}.rust`, prefix); + } else if (releaseType === 'node' || releaseType === 'expo') { + canonical = packageRelativePath(product, 'package.json', `${product}.node`, prefix); + } else { + fail( + prefix, + `${product} release-please config must declare version-file for release type ${JSON.stringify(releaseType)}`, + ); + } + + const extraFiles = packageConfig['extra-files'] ?? []; + if (!Array.isArray(extraFiles)) { + fail(prefix, `${product}.extra-files must be a list`); + } + const files = [canonical]; + for (const [index, entry] of extraFiles.entries()) { + const context = `${product}.extra-files[${index}]`; + if (typeof entry === 'string') { + files.push(packageRelativePath(product, entry, context, prefix)); + } else if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) { + files.push(packageRelativePath(product, entry.path, `${context}.path`, prefix)); + } else { + fail(prefix, `${context} must be a path string or object`); + } + } + for (const file of files) { + requireExistingPath(file, `${product} version file`, prefix); + } + return files; +} + +export function changelogPath(product, prefix = 'release-graph') { + const { packageConfig } = releasePleasePackage(product, prefix); + const relative = packageConfig['changelog-path'] ?? 'CHANGELOG.md'; + const changelog = packageRelativePath(product, relative, `${product}.changelog-path`, prefix); + requireExistingPath(changelog, `${product} changelog`, prefix); + return changelog; +} + +export function loadProducts(prefix = 'release-graph') { + const { byComponent } = releasePleasePackagesByComponent(prefix); + const paths = new Map( + [...byComponent].map(([component, { packagePath }]) => [component, packagePath]), + ); + const manifest = readJson('.release-please-manifest.json', prefix); + const products = {}; + for (const [product, packagePath] of [...paths.entries()].sort(([left], [right]) => + compareText(left, right), + )) { + const metadata = readToml(path.join(packagePath, 'release.toml'), prefix); + const version = manifest[packagePath]; + if (metadata.id !== product) { + fail(prefix, `${packagePath}/release.toml must declare id = ${JSON.stringify(product)}`); + } + if (typeof version !== 'string' || version.length === 0) { + fail(prefix, `.release-please-manifest.json is missing ${packagePath}`); + } + products[product] = { + ...metadata, + path: packagePath, + changelog_path: changelogPath(product, prefix), + tag_prefix: tagPrefix(product, prefix), + version, + version_files: versionFiles(product, prefix), + }; + } + return products; +} + +function contribCarrierImpact(products, prefix) { + const carriers = loadContribCarriers(ROOT, prefix); + const owners = [carriers.nativeOwner, carriers.wasixOwner]; + if (owners.some((owner) => typeof owner !== 'string' || !(owner in products))) { + fail(prefix, `${CONTRIB_CARRIERS_PATH} must name native and WASIX release-product owners`); + } + if (new Set(owners).size !== owners.length) { + fail(prefix, `${CONTRIB_CARRIERS_PATH} must name distinct runtime owners`); + } + return { + files: carriers.inputFiles, + products: owners, + }; +} + +function declaredSharedSourceImpacts(products, prefix) { + return Object.entries(products).flatMap(([product, config]) => { + const paths = config.shared_source_paths ?? []; + assertStringList(paths, `${product}.shared_source_paths`, prefix); + return paths.map((sourcePath) => { + if (!sourcePath || path.isAbsolute(sourcePath) || sourcePath.startsWith('../')) { + fail(prefix, `${product}.shared_source_paths must contain repository-relative paths`); + } + requireExistingPath(sourcePath, `${product} shared source`, prefix); + return { source_paths: [sourcePath.replace(/\/$/u, '')], products: [product] }; + }); + }); +} + +export function loadGraph(prefix = 'release-graph') { + const moonProjects = moonProjectsById(prefix); + releasePackagePaths(moonProjects, prefix); + const products = loadProducts(prefix); + const graph = { + products, + moon_projects: Object.fromEntries(moonProjects), + shared_release_sources: [ + contribCarrierImpact(products, prefix), + ...declaredSharedSourceImpacts(products, prefix), + ], + }; + return graph; +} + +export function wasixEvidenceProductsForRelease( + products, + projects, + selected, + prefix = 'release-graph', +) { + const selectedProducts = new Set(selected); + const unknown = [...selectedProducts] + .filter((product) => !(product in products)) + .sort(compareText); + if (unknown.length > 0) { + fail(prefix, `unknown release products in WASIX evidence selection: ${unknown.join(', ')}`); + } + const required = []; + for (const product of [...selectedProducts].sort(compareText)) { + if (product === 'liboliphaunt-wasix') { + required.push(product); + continue; + } + const config = products[product]; + const compatibility = config.compatibility_versions ?? {}; + const compatibilityRequiresWasix = Object.values(compatibility).some( + (entry) => + entry !== null && + !Array.isArray(entry) && + typeof entry === 'object' && + entry.source_product === 'liboliphaunt-wasix', + ); + const projectId = releaseProductProjectId(product, products, projects, prefix); + const projectRequiresWasix = (projects[projectId]?.dependencies ?? []).some( + (dependency) => dependency.id === 'liboliphaunt-wasix', + ); + if (compatibilityRequiresWasix || projectRequiresWasix) { + required.push(product); + } + } + return required; +} + +function assertObject(value, context, prefix) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(prefix, `${context} must be a table`); + } + return value; +} + +export function compatibilityVersionEntries( + products, + { requireSourceProduct = false, prefix = 'release-graph', root = ROOT } = {}, +) { + const source = products ?? loadProducts(prefix); + const knownProducts = new Set(Object.keys(source)); + const entries = []; + for (const [product, config] of Object.entries(source).sort(([left], [right]) => + compareText(left, right), + )) { + const rawSpecs = config.compatibility_versions ?? {}; + assertObject(rawSpecs, `${product}.compatibility_versions`, prefix); + for (const [specId, spec] of Object.entries(rawSpecs).sort(([left], [right]) => + compareText(left, right), + )) { + if (!specId) { + fail(prefix, `${product}.compatibility_versions keys must be non-empty strings`); + } + assertObject(spec, `${product}.compatibility_versions.${specId}`, prefix); + const sourceProduct = spec.source_product; + if (requireSourceProduct) { + if (typeof sourceProduct !== 'string' || sourceProduct.length === 0) { + fail( + prefix, + `${product}.compatibility_versions.${specId}.source_product must be a non-empty string`, + ); + } + if (!knownProducts.has(sourceProduct)) { + fail( + prefix, + `${product}.compatibility_versions.${specId}.source_product must name a release product, got ${JSON.stringify( + sourceProduct, + )}`, + ); + } + } else if (sourceProduct !== undefined && typeof sourceProduct !== 'string') { + fail( + prefix, + `${product}.compatibility_versions.${specId}.source_product must be a string when present`, + ); + } + const specPath = spec.path; + const parser = spec.parser; + if (typeof specPath !== 'string' || specPath.length === 0) { + fail(prefix, `${product}.compatibility_versions.${specId}.path must be a non-empty string`); + } + if (typeof parser !== 'string' || parser.length === 0) { + fail( + prefix, + `${product}.compatibility_versions.${specId}.parser must be a non-empty string`, + ); + } + if (!existsSync(path.join(root, specPath))) { + fail( + prefix, + `${product}.compatibility_versions.${specId} path does not exist: ${specPath}`, + ); + } + entries.push({ + id: specId, + product, + sourceProduct: typeof sourceProduct === 'string' ? sourceProduct : null, + path: specPath, + parser, + }); + } + } + return entries; +} + +export function compatibilityVersionValue( + entry, + { ref = null, root = ROOT, prefix = 'release-graph', missingValue = undefined } = {}, +) { + const text = + ref === null + ? readFileSync(path.join(root, entry.path), 'utf8') + : fileAtRef(root, ref, entry.path); + if (text === null) { + if (missingValue !== undefined) return missingValue; + fail(prefix, `cannot read ${entry.path} at immutable compatibility ref ${ref}`); + } + if (entry.parser === 'raw') return text.trim(); + if (entry.parser.startsWith('rust-const:')) { + const name = entry.parser.slice('rust-const:'.length); + if (!/^[A-Z][A-Z0-9_]*$/u.test(name)) { + fail(prefix, `${entry.id} has an invalid Rust constant parser`); + } + const matches = [ + ...text.matchAll( + new RegExp(`(?:pub\\s+)?const\\s+${name}\\s*:[^=]+?=\\s*"([^"]+)"\\s*;`, 'gu'), + ), + ]; + if (matches.length !== 1) { + if (matches.length === 0 && missingValue !== undefined) return missingValue; + fail(prefix, `${entry.id} must name exactly one Rust string constant`); + } + return matches[0][1]; + } + const separator = entry.parser.indexOf(':'); + const type = entry.parser.slice(0, separator); + if (type !== 'json' && type !== 'toml') { + fail(prefix, `${entry.id} uses unsupported compatibility parser ${entry.parser}`); + } + const parts = entry.parser.slice(separator + 1).split('.'); + let data; + try { + data = type === 'json' ? JSON.parse(text) : type === 'toml' ? Bun.TOML.parse(text) : null; + } catch (cause) { + fail(prefix, `${entry.path} is not valid ${type.toUpperCase()}: ${cause.message}`); + } + const value = valueAtPath(data, parts); + if (typeof value !== 'string' || value.length === 0) { + if (value === undefined && missingValue !== undefined) return missingValue; + fail(prefix, `${entry.id} parser ${entry.parser} must resolve to a non-empty string`); + } + return value; +} + +export function productCompatibilityVersion(product, sourceProduct, prefix = 'release-graph') { + const entries = compatibilityVersionEntries(loadProducts(prefix), { + requireSourceProduct: true, + prefix, + }).filter((entry) => entry.product === product && entry.sourceProduct === sourceProduct); + if (entries.length === 0) { + fail(prefix, `${product} does not declare compatibility with ${sourceProduct}`); + } + const values = new Set(entries.map((entry) => compatibilityVersionValue(entry, { prefix }))); + if (values.size !== 1) { + fail(prefix, `${product} declares conflicting compatibility versions for ${sourceProduct}`); + } + return [...values][0]; +} + +export function tagPrefixes(config, prefix = 'release-graph') { + if (typeof config.tag_prefix !== 'string' || config.tag_prefix.length === 0) { + fail(prefix, 'release products must declare tag_prefix'); + } + const legacyPrefixes = config.legacy_tag_prefixes ?? []; + assertStringList(legacyPrefixes, 'legacy_tag_prefixes', prefix); + return [config.tag_prefix, ...legacyPrefixes]; +} + +export function latestProductTag(productConfig, headRef, prefix = 'release-graph', root = ROOT) { + for (const candidatePrefix of tagPrefixes(productConfig, prefix)) { + const tag = historyLatestTag(root, candidatePrefix, headRef); + if (tag) { + return tag; + } + } + return EMPTY_TREE; +} + +const commitForRefAt = historyCommit; + +export function commitForRef(ref, root = ROOT) { + return commitForRefAt(root, ref); +} + +export function changedFilesFromRefs(baseRef, headRef, prefix = 'release-graph', root = ROOT) { + try { + return historyChanges(root, baseRef, headRef).sort(compareText); + } catch (error) { + fail( + prefix, + `failed to read changed files between ${baseRef} and ${headRef}: ${error.message}`, + ); + } +} + +function manifestAtRef(root, ref, prefix) { + let value; + try { + value = historyManifest(root, ref); + } catch (error) { + throw new Error( + `${prefix}: cannot read .release-please-manifest.json at ${ref}: ${error.message}`, + ); + } + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw new Error( + `${prefix}: .release-please-manifest.json at ${ref} must contain a JSON object`, + ); + } + return value; +} + +function canonicalVersionAtRef(root, ref, product, config, prefix) { + const file = config?.version_files?.[0]; + if (typeof file !== 'string' || file.length === 0) { + throw new Error(`${prefix}: ${product} is missing its canonical version file metadata`); + } + let text; + try { + text = historyFile(root, ref, file); + if (text === null) throw new Error('missing historical file'); + } catch (error) { + throw new Error( + `${prefix}: cannot read ${product} canonical version file ${file} at ${ref}: ${error.message}`, + ); + } + const basename = path.posix.basename(file); + let version; + try { + if (basename === 'Cargo.toml') { + version = Bun.TOML.parse(text)?.package?.version; + } else if (basename === 'package.json') { + version = JSON.parse(text)?.version; + } else { + version = text.trim(); + } + } catch (error) { + throw new Error( + `${prefix}: cannot parse ${product} canonical version file ${file} at ${ref}: ${error.message}`, + ); + } + transitionVersion(version, `${product} canonical version in ${file} at ${ref}`, prefix); + return version; +} + +function transitionVersion(value, context, prefix) { + if ( + typeof value !== 'string' || + !/^(?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)$/u.test(value) + ) { + throw new Error( + `${prefix}: ${context} must be a stable x.y.z version, got ${JSON.stringify(value)}`, + ); + } + return value.split('.').map((part) => Number.parseInt(part, 10)); +} + +function manifestProductVersion(products, manifest, product, ref, prefix) { + const packagePath = products[product]?.path; + if (typeof packagePath !== 'string' || packagePath.length === 0) { + throw new Error( + `${prefix}: compatibility source product ${product} is missing its Release Please package path`, + ); + } + const version = manifest[packagePath]; + transitionVersion(version, `${product} manifest version at ${ref}`, prefix); + return version; +} + +const fileAtRef = historyFile; + +function semanticDifferences(before, after, parts = []) { + if (Object.is(before, after)) return []; + const beforeObject = before !== null && typeof before === 'object'; + const afterObject = after !== null && typeof after === 'object'; + if (beforeObject && afterObject && Array.isArray(before) === Array.isArray(after)) { + const keys = new Set( + Array.isArray(before) + ? Array.from({ length: Math.max(before.length, after.length) }, (_value, index) => index) + : [...Object.keys(before), ...Object.keys(after)], + ); + return [...keys].flatMap((key) => + semanticDifferences(before[key], after[key], [...parts, key]), + ); + } + return [{ parts, before, after }]; +} + +function compatibilityPathKey(parts) { + return parts.map(String).join('\0'); +} + +function valueAtPath(value, parts) { + let current = value; + for (const part of parts) { + if (current === null || typeof current !== 'object') return undefined; + current = current[part]; + } + return current; +} + +function parseCompatibilityStructuredFile(text, type) { + try { + const value = type === 'json' ? JSON.parse(text) : Bun.TOML.parse(text); + return value !== null && typeof value === 'object' ? value : null; + } catch { + return null; + } +} + +function compatibilityParser(entry) { + const separator = entry.parser.indexOf(':'); + const type = separator === -1 ? entry.parser : entry.parser.slice(0, separator); + const expression = separator === -1 ? '' : entry.parser.slice(separator + 1); + if ( + (type === 'json' || type === 'toml') && + /^[A-Za-z0-9_-]+(?:[.][A-Za-z0-9_-]+)*$/u.test(expression) + ) { + return { type, parts: expression.split('.') }; + } + if (type === 'raw' && expression === '') return { type, parts: [] }; + if (type === 'rust-const' && /^[A-Z][A-Z0-9_]*$/u.test(expression)) { + return { type, name: expression, parts: [] }; + } + return null; +} + +function maskRustCompatibilityConst(text, name, expected, token) { + const escaped = name.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&'); + const pattern = new RegExp( + `(^|\\n)([\\t ]*(?:pub[\\t ]+)?const[\\t ]+${escaped}[\\t ]*:[\\t ]*&str[\\t ]*=[\\t ]*")([^"]+)("[\\t ]*;[^\\n]*)`, + 'gu', + ); + const matches = [...text.matchAll(pattern)]; + if (matches.length !== 1 || matches[0][3] !== expected) return null; + return text.replace(pattern, `$1$2${token}$4`); +} + +function compatibilityFileHasOnlyExpectedChanges({ + beforeText, + afterText, + entries, + beforeManifest, + afterManifest, + products, + baseRef, + headRef, + prefix, +}) { + const rules = entries.map((entry) => { + const parser = compatibilityParser(entry); + if (parser === null) return null; + return { + entry, + parser, + before: manifestProductVersion( + products, + beforeManifest, + entry.sourceProduct, + baseRef, + prefix, + ), + after: manifestProductVersion(products, afterManifest, entry.sourceProduct, headRef, prefix), + }; + }); + if (rules.some((rule) => rule === null)) return false; + + const types = new Set(rules.map((rule) => rule.parser.type)); + if (types.size !== 1) return false; + const type = rules[0].parser.type; + if (type === 'raw') { + return ( + rules.length === 1 && + beforeText.trim() === rules[0].before && + afterText.trim() === rules[0].after + ); + } + if (type === 'rust-const') { + let maskedBefore = beforeText; + let maskedAfter = afterText; + for (const rule of rules) { + const token = ``; + maskedBefore = maskRustCompatibilityConst(maskedBefore, rule.parser.name, rule.before, token); + maskedAfter = maskRustCompatibilityConst(maskedAfter, rule.parser.name, rule.after, token); + if (maskedBefore === null || maskedAfter === null) return false; + } + return maskedBefore === maskedAfter; + } + + const before = parseCompatibilityStructuredFile(beforeText, type); + const after = parseCompatibilityStructuredFile(afterText, type); + if (before === null || after === null) return false; + const allowed = new Map(); + for (const rule of rules) { + const key = compatibilityPathKey(rule.parser.parts); + const previous = allowed.get(key); + if ( + previous !== undefined && + (previous.before !== rule.before || + previous.after !== rule.after || + previous.entry.sourceProduct !== rule.entry.sourceProduct) + ) { + return false; + } + if ( + valueAtPath(before, rule.parser.parts) !== rule.before || + valueAtPath(after, rule.parser.parts) !== rule.after + ) { + return false; + } + allowed.set(key, rule); + } + return semanticDifferences(before, after).every((difference) => { + const rule = allowed.get(compatibilityPathKey(difference.parts)); + return ( + rule !== undefined && difference.before === rule.before && difference.after === rule.after + ); + }); +} + +function compatibilityOnlyChangedFiles({ + product, + products, + entries, + files, + baseRef, + headRef, + prefix, + root, +}) { + const byFile = new Map(); + for (const entry of entries) { + if (entry.product !== product) continue; + byFile.set(entry.path, [...(byFile.get(entry.path) ?? []), entry]); + } + if (byFile.size === 0) return new Set(); + const beforeManifest = manifestAtRef(root, baseRef, prefix); + const afterManifest = manifestAtRef(root, headRef, prefix); + const ignored = new Set(); + for (const file of files) { + const fileEntries = byFile.get(file); + if (fileEntries === undefined) continue; + const beforeText = fileAtRef(root, baseRef, file); + const afterText = fileAtRef(root, headRef, file); + if ( + beforeText !== null && + afterText !== null && + compatibilityFileHasOnlyExpectedChanges({ + beforeText, + afterText, + entries: fileEntries, + beforeManifest, + afterManifest, + products, + baseRef, + headRef, + prefix, + }) + ) { + ignored.add(file); + } + } + return ignored; +} + +function versionFromProductTag(config, tag, prefix) { + for (const candidatePrefix of tagPrefixes(config, prefix)) { + if (!tag.startsWith(candidatePrefix)) continue; + const version = tag.slice(candidatePrefix.length); + transitionVersion(version, `product tag ${tag}`, prefix); + return version; + } + throw new Error(`${prefix}: product tag ${tag} does not use a declared tag prefix`); +} + +/** + * Classify one product's immutable release identity at headRef. + * + * Path impact is deliberately not considered here. A normal candidate must + * have advanced its own Release Please manifest version since its latest + * reachable product tag. An exact current-version tag is eligible only for an + * explicitly requested exact-commit rerun. + */ +export function productVersionTransitionStatus( + product, + config, + baseRef, + headRef, + { includeCurrentTags = false, prefix = 'release-graph', root = ROOT } = {}, +) { + const packagePath = config?.path; + if (typeof packagePath !== 'string' || packagePath.length === 0) { + throw new Error(`${prefix}: ${product} is missing its Release Please package path`); + } + const headCommit = commitForRefAt(root, headRef); + const headVersion = manifestAtRef(root, headCommit, prefix)[packagePath]; + const headParts = transitionVersion( + headVersion, + `${product} manifest version at ${headCommit}`, + prefix, + ); + if (headVersion !== config.version) { + throw new Error( + `${prefix}: ${product} graph version ${JSON.stringify(config.version)} does not match ` + + `its manifest version ${JSON.stringify(headVersion)} at ${headCommit}`, + ); + } + const headCanonicalVersion = canonicalVersionAtRef(root, headCommit, product, config, prefix); + if (headCanonicalVersion !== headVersion) { + throw new Error( + `${prefix}: ${product} canonical version ${JSON.stringify(headCanonicalVersion)} does not match ` + + `its manifest version ${JSON.stringify(headVersion)} at ${headCommit}`, + ); + } + + let baseVersion = null; + let comparison = null; + if (baseRef !== EMPTY_TREE) { + baseVersion = versionFromProductTag(config, baseRef, prefix); + const taggedManifestVersion = manifestAtRef(root, baseRef, prefix)[packagePath]; + if (taggedManifestVersion !== baseVersion) { + throw new Error( + `${prefix}: ${product} base tag ${baseRef} names ${baseVersion}, but its manifest contains ` + + `${JSON.stringify(taggedManifestVersion)}`, + ); + } + const taggedCanonicalVersion = canonicalVersionAtRef(root, baseRef, product, config, prefix); + if (taggedCanonicalVersion !== baseVersion) { + throw new Error( + `${prefix}: ${product} base tag ${baseRef} names ${baseVersion}, but its canonical version file contains ` + + `${JSON.stringify(taggedCanonicalVersion)}`, + ); + } + comparison = compareVersion( + headParts, + transitionVersion(baseVersion, `${product} base tag version`, prefix), + ); + if (comparison < 0) { + throw new Error( + `${prefix}: ${product} manifest version ${headVersion} is older than tagged version ${baseVersion}`, + ); + } + } + + const currentTag = `${config.tag_prefix}${headVersion}`; + const currentTagCommit = commitForRefAt(root, `refs/tags/${currentTag}`, { check: false }); + if (currentTagCommit !== null) { + const taggedManifestVersion = manifestAtRef(root, currentTagCommit, prefix)[packagePath]; + if (taggedManifestVersion !== headVersion) { + throw new Error( + `${prefix}: ${product} current-version tag ${currentTag} points at ${currentTagCommit}, whose manifest ` + + `contains ${JSON.stringify(taggedManifestVersion)} instead of ${JSON.stringify(headVersion)}`, + ); + } + const taggedCanonicalVersion = canonicalVersionAtRef( + root, + currentTagCommit, + product, + config, + prefix, + ); + if (taggedCanonicalVersion !== headVersion) { + throw new Error( + `${prefix}: ${product} current-version tag ${currentTag} points at ${currentTagCommit}, whose canonical ` + + `version file contains ${JSON.stringify(taggedCanonicalVersion)} instead of ${JSON.stringify(headVersion)}`, + ); + } + if (currentTagCommit === headCommit) { + return { + eligible: includeCurrentTags, + rerun: includeCurrentTags, + firstRelease: false, + baseVersion: headVersion, + headVersion, + currentTag, + currentTagCommit, + }; + } + const ancestor = historyAncestor(root, currentTagCommit, headCommit); + if (!ancestor) { + throw new Error( + `${prefix}: ${product} current-version tag ${currentTag} points at ${currentTagCommit}, ` + + `which is not an ancestor of release candidate ${headCommit}`, + ); + } + return { + eligible: false, + rerun: false, + firstRelease: false, + baseVersion: headVersion, + headVersion, + currentTag, + currentTagCommit, + }; + } + + if (baseRef === EMPTY_TREE) { + const firstRelease = compareVersion(headParts, [0, 0, 0]) > 0; + return { + eligible: firstRelease, + rerun: false, + firstRelease, + baseVersion: null, + headVersion, + currentTag, + currentTagCommit: null, + }; + } + return { + eligible: comparison > 0, + rerun: false, + firstRelease: false, + baseVersion, + headVersion, + currentTag, + currentTagCommit: null, + }; +} + +export function isGeneratedLocalState(candidate) { + if (candidate.startsWith('target/')) { + return true; + } + return candidate.split(/[\\/]/).some((part) => GENERATED_PATH_PARTS.has(part)); +} + +export function normalizeFiles(files) { + const normalized = new Set(); + for (const file of files) { + let candidate = file.trim().replaceAll('\\', '/'); + if (candidate.startsWith('./')) { + candidate = candidate.slice(2); + } + if (candidate && !isGeneratedLocalState(candidate)) { + normalized.add(candidate); + } + } + return [...normalized].sort(compareText); +} + +function splitPatterns(patterns) { + const includes = []; + const excludes = []; + for (const pattern of patterns) { + if (pattern.startsWith('!')) { + excludes.push(pattern.slice(1)); + } else { + includes.push(pattern); + } + } + return { includes, excludes }; +} + +function globPatternToRegExp(pattern) { + let text = ''; + for (const char of pattern) { + if (char === '*') { + text += '.*'; + } else if ('\\^$+?.()|{}[]'.includes(char)) { + text += `\\${char}`; + } else { + text += char; + } + } + return new RegExp(`^${text}$`, 'u'); +} + +function matchesAny(candidate, patterns) { + return patterns.some((pattern) => globPatternToRegExp(pattern).test(candidate)); +} + +export function productMatches(candidate, patterns) { + const { includes, excludes } = splitPatterns(patterns); + return matchesAny(candidate, includes) && !matchesAny(candidate, excludes); +} + +export function ownerProjectForPath(projects, candidate) { + if (isGeneratedLocalState(candidate)) { + return undefined; + } + const matches = Object.values(projects) + .filter( + (project) => + project.source === '.' || + candidate === project.source || + candidate.startsWith(`${project.source}/`), + ) + .sort((left, right) => right.source.length - left.source.length); + return matches[0]?.id; +} + +export function releaseOwnerProjectsForPath( + products, + projects, + candidate, + prefix = 'release-graph', +) { + if (isGeneratedLocalState(candidate)) { + return []; + } + return Object.entries(products) + .filter(([, config]) => { + const packagePath = config?.path; + return ( + typeof packagePath === 'string' && + packagePath.length > 0 && + (candidate === packagePath || candidate.startsWith(`${packagePath}/`)) + ); + }) + .map(([product]) => releaseProductProjectId(product, products, projects, prefix)) + .filter((projectId, index, values) => values.indexOf(projectId) === index) + .sort(compareText); +} + +export function releaseProductProjectId(product, products, projects, prefix = 'release-graph') { + if (product in projects) { + return product; + } + const packagePath = products[product]?.path; + if (typeof packagePath !== 'string' || packagePath.length === 0) { + fail(prefix, `release product ${product} is missing package path metadata`); + } + const matches = Object.values(projects) + .filter( + (project) => packagePath === project.source || packagePath.startsWith(`${project.source}/`), + ) + .sort((left, right) => right.source.length - left.source.length); + if (matches.length === 0) { + fail(prefix, `release product ${product} has no owning Moon project for ${packagePath}`); + } + return matches[0].id; +} + +export function releaseProductsForProjects( + products, + projects, + projectIds, + prefix = 'release-graph', +) { + const selectedProjects = new Set(projectIds); + const selected = new Set(); + for (const product of Object.keys(products)) { + const projectId = releaseProductProjectId(product, products, projects, prefix); + if (selectedProjects.has(projectId)) { + selected.add(product); + } + } + return selected; +} + +function releaseProductsForSourceProjects(products, projects, projectIds, prefix) { + const productByProject = new Map( + Object.keys(products).map((product) => [ + releaseProductProjectId(product, products, projects, prefix), + product, + ]), + ); + const dependents = new Map(); + for (const project of Object.values(projects)) { + for (const dependency of project.dependencies ?? []) { + if (dependency.scope === 'development') continue; + dependents.set(dependency.id, [...(dependents.get(dependency.id) ?? []), project.id]); + } + } + + const selected = new Set(); + const visited = new Set(); + const queue = [...projectIds]; + while (queue.length > 0) { + const project = queue.shift(); + if (visited.has(project)) continue; + visited.add(project); + const product = productByProject.get(project); + if (product !== undefined) { + selected.add(product); + continue; + } + queue.push(...(dependents.get(project) ?? [])); + } + return selected; +} + +export function releaseOrder(products, _projects, selected, prefix = 'release-graph') { + const selectedSet = new Set(selected); + const ordered = []; + const remaining = new Set(selectedSet); + while (remaining.size > 0) { + const ready = []; + for (const product of [...remaining].sort(compareText)) { + const deps = new Set( + Object.values(products[product]?.compatibility_versions ?? {}) + .map((dependency) => dependency?.source_product) + .filter((dependency) => typeof dependency === 'string' && dependency !== product), + ); + const selectedDeps = [...deps].filter((dependency) => selectedSet.has(dependency)); + if (selectedDeps.every((dependency) => ordered.includes(dependency))) { + ready.push(product); + } + } + if (ready.length === 0) { + fail( + prefix, + `release compatibility graph has a dependency cycle: ${JSON.stringify([...remaining].sort(compareText))}`, + ); + } + for (const product of ready) { + ordered.push(product); + remaining.delete(product); + } + } + return ordered; +} + +export function buildPlan(graph, files, prefix = 'release-graph') { + const products = graph.products; + const projects = graph.moon_projects; + if (products === null || Array.isArray(products) || typeof products !== 'object') { + fail(prefix, 'release metadata must define [products.] entries'); + } + if (projects === null || Array.isArray(projects) || typeof projects !== 'object') { + fail(prefix, 'Moon project graph is missing from release plan metadata'); + } + const directProjects = new Set(); + for (const file of files) { + const sharedImpacts = (graph.shared_release_sources ?? []).filter( + (impact) => + (impact.files ?? []).includes(file) || + (impact.source_paths ?? []).some( + (sourcePath) => file === sourcePath || file.startsWith(`${sourcePath}/`), + ), + ); + if (sharedImpacts.length > 0) { + for (const impact of sharedImpacts) { + for (const product of impact.products) { + directProjects.add(releaseProductProjectId(product, products, projects, prefix)); + } + } + // The explicit carrier mapping is authoritative. Traversing the shared + // source project's other consumers would fabricate downstream releases. + continue; + } + const owner = ownerProjectForPath(projects, file); + if (owner !== undefined) { + directProjects.add(owner); + } + // A nested Moon project may own CI work without being an independently + // versioned product. Preserve that precise CI owner while also selecting + // every enclosing release component (for example a contrib bundle). + for (const releaseOwner of releaseOwnerProjectsForPath(products, projects, file, prefix)) { + directProjects.add(releaseOwner); + } + } + // Follow owned source inputs to their first independently publishable + // boundary, then stop. A runtime change selects the runtime, not every SDK + // that can consume it; a private source-pin change still selects its runtime. + const releaseProductSet = releaseProductsForSourceProjects( + products, + projects, + directProjects, + prefix, + ); + const releaseProducts = releaseOrder(products, projects, releaseProductSet, prefix); + const direct = releaseOrder( + products, + projects, + releaseProductsForProjects(products, projects, directProjects, prefix), + prefix, + ); + return { + changedFiles: files, + directProducts: direct, + releaseProducts, + hasReleaseChanges: releaseProducts.length > 0, + }; +} + +export function buildPlanFromProductTags( + graph, + headRef, + { includeCurrentTags = false, prefix = 'release-graph', root = ROOT } = {}, +) { + const products = graph.products; + const direct = new Set(); + const changed = new Set(); + const currentTaggedProducts = new Set(); + const compatibilityEntries = compatibilityVersionEntries(products, { + requireSourceProduct: true, + prefix, + root, + }); + + for (const [product, config] of Object.entries(products)) { + const baseRef = latestProductTag(config, headRef, prefix, root); + const transition = productVersionTransitionStatus(product, config, baseRef, headRef, { + includeCurrentTags, + prefix, + root, + }); + const productFiles = + transition.eligible || baseRef !== EMPTY_TREE + ? changedFilesFromRefs(baseRef, headRef, prefix, root) + : []; + for (const file of productFiles) { + changed.add(file); + } + if (!transition.eligible) { + if (baseRef !== EMPTY_TREE && productFiles.length > 0) { + const ignored = compatibilityOnlyChangedFiles({ + product, + products, + entries: compatibilityEntries, + files: productFiles, + baseRef, + headRef, + prefix, + root, + }); + const impactFiles = productFiles.filter((file) => !ignored.has(file)); + const impactPlan = buildPlan(graph, normalizeFiles(impactFiles), prefix); + if (impactPlan.releaseProducts.includes(product)) { + const selectingFiles = impactFiles.filter((file) => + buildPlan(graph, normalizeFiles([file]), prefix).releaseProducts.includes(product), + ); + const relevantFiles = selectingFiles.length > 0 ? selectingFiles : impactFiles; + const shown = relevantFiles.slice(0, 12); + const suffix = + relevantFiles.length > shown.length + ? `, ... (${relevantFiles.length - shown.length} more)` + : ''; + throw new Error( + `${prefix}: ${product} has release-affecting changes since ${baseRef}, but its manifest version ` + + `remains ${transition.headVersion}; bump the product version before publishing. ` + + `Non-compatibility changed paths: ${shown.join(', ')}${suffix}`, + ); + } + } + continue; + } + if (transition.rerun) { + direct.add(product); + currentTaggedProducts.add(product); + continue; + } + const productPlan = buildPlan(graph, normalizeFiles(productFiles), prefix); + if (!productPlan.releaseProducts.includes(product)) { + throw new Error( + `${prefix}: ${product} manifest advanced from ${transition.baseVersion ?? 'first release'} to ` + + `${transition.headVersion}, but its changed paths do not select the product in the Moon release graph`, + ); + } + direct.add(product); + } + + const projects = graph.moon_projects; + const releaseProductSet = new Set(direct); + const releaseProducts = releaseOrder(products, projects, releaseProductSet, prefix); + return { + changedFiles: [...changed].sort(compareText), + directProducts: releaseOrder(products, projects, direct, prefix), + releaseProducts, + hasReleaseChanges: releaseProducts.length > 0, + currentTaggedProducts: [...currentTaggedProducts].sort(compareText), + }; +} + +if (import.meta.main) { + const [mode, root, graphFile] = process.argv.slice(2); + if (mode !== '--history-inputs') + throw new Error('usage: release-graph.mts --history-inputs REPO GRAPH'); + const directory = process.env.OLIPHAUNT_PRODUCT_HISTORY; + if (!directory) throw new Error('missing product history destination'); + + const products = + graphFile === '@workspace' + ? loadProducts('release-history') + : JSON.parse(readFileSync(graphFile, 'utf8')).products; + const prefixes = new Set(Object.values(products).flatMap((config) => tagPrefixes(config))); + const files = new Set([ + 'release-please-config.json', + '.release-please-manifest.json', + ...Object.values(products).flatMap((config) => config.version_files ?? []), + ...compatibilityVersionEntries(products, { root, requireSourceProduct: true }).map( + (entry) => entry.path, + ), + ]); + const currentConfig = path.join(root, 'release-please-config.json'); + writeFileSync( + path.join(directory, 'current-config'), + existsSync(currentConfig) ? readFileSync(currentConfig, 'utf8') : '{}', + ); + for (const [name, values] of [ + ['prefixes', prefixes], + ['wanted-files', files], + [ + 'current-tags', + Object.values(products).map((config) => 'refs/tags/' + config.tag_prefix + config.version), + ], + ]) + writeFileSync(path.join(directory, name), [...values].map((value) => value + '\0').join('')); +} diff --git a/tools/release/release-history.mts b/tools/release/release-history.mts new file mode 100644 index 000000000..95a091ebb --- /dev/null +++ b/tools/release/release-history.mts @@ -0,0 +1,148 @@ +import { existsSync, readdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +function pairs(file) { + const fields = readFileSync(file, 'utf8').split('\0'); + fields.pop(); + const result = new Map(); + for (let index = 0; index < fields.length; index += 2) + result.set(fields[index], fields[index + 1]); + return result; +} +function history(root) { + const directory = process.env.OLIPHAUNT_PRODUCT_HISTORY; + if (!directory) throw new Error('run through with-product-history.sh'); + const [source, ref, commit] = readFileSync(path.join(directory, 'context'), 'utf8').split('\0'); + if (source !== realpathSync(root)) + throw new Error('product history belongs to another repository'); + return { directory, ref, commit }; +} +export function historyCommit(root, ref, { check = true } = {}) { + const { directory } = history(root); + const refs = pairs(path.join(directory, 'refs')); + if (!refs.has(ref)) throw new Error('product history does not include ref ' + ref); + const commit = refs.get(ref); + if (!commit && check) throw new Error('could not resolve product ref ' + ref); + return commit || null; +} +function atHead(root, ref) { + const state = history(root); + if (historyCommit(root, ref) !== state.commit) + throw new Error('product history belongs to another head'); + return state.directory; +} +export function historyLatestTag(root, prefix, head) { + const tags = pairs(path.join(atHead(root, head), 'latest')); + if (!tags.has(prefix)) throw new Error('product history does not include tag prefix ' + prefix); + return tags.get(prefix); +} +export function historyChanges(root, base, head) { + const directory = atHead(root, head); + return readFileSync(path.join(directory, 'changes', historyCommit(root, base)), 'utf8') + .split('\0') + .filter(Boolean); +} +function safePath(file) { + if ( + path.isAbsolute(file) || + file.split('/').some((part) => !part || part === '.' || part === '..') + ) + throw new Error('unsafe historical product path ' + file); + return file; +} + +function packagePaths(config) { + const result = new Map(); + for (const [directory, entry] of Object.entries(config.packages ?? {})) { + if (directory !== '.') safePath(directory); + if (typeof entry.component !== 'string' || !entry.component) + throw new Error('historical release package has no component: ' + directory); + if (result.has(entry.component)) + throw new Error('duplicate historical release component: ' + entry.component); + result.set(entry.component, directory); + } + return result; +} + +function mappedPath(directory, stage, file) { + const current = packagePaths( + JSON.parse(readFileSync(path.join(directory, 'current-config'), 'utf8')), + ); + const owner = [...current] + .sort((a, b) => b[1].length - a[1].length) + .find(([, folder]) => folder === '.' || file === folder || file.startsWith(folder + '/')); + if (!owner) return file; + const configFile = path.join(stage, 'blobs', 'release-please-config.json'); + if (!existsSync(configFile)) throw new Error('missing historical release-please-config.json'); + const old = packagePaths(JSON.parse(readFileSync(configFile, 'utf8'))).get(owner[0]); + if (old === undefined) return null; + const suffix = owner[1] === '.' ? file : file.slice(owner[1].length).replace(/^\//u, ''); + return old === '.' ? suffix : suffix ? old + '/' + suffix : old; +} + +export function historyManifest(root, ref) { + const { directory } = history(root); + const stage = path.join(directory, 'trees', historyCommit(root, ref)); + const manifest = JSON.parse(historyFile(root, ref, '.release-please-manifest.json')); + if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) + throw new Error('invalid historical release manifest'); + const current = packagePaths( + JSON.parse(readFileSync(path.join(directory, 'current-config'), 'utf8')), + ); + if (current.size === 0) return manifest; + const configFile = path.join(stage, 'blobs', 'release-please-config.json'); + if (!existsSync(configFile)) throw new Error('missing historical release-please-config.json'); + const old = packagePaths(JSON.parse(readFileSync(configFile, 'utf8'))); + return Object.fromEntries( + [...current].flatMap(([component, folder]) => + old.has(component) ? [[folder, manifest[old.get(component)]]] : [], + ), + ); +} + +export function historyFile(root, ref, file) { + safePath(file); + const { directory } = history(root); + const stage = path.join(directory, 'trees', historyCommit(root, ref)); + const mapped = + file === 'release-please-config.json' || file === '.release-please-manifest.json' + ? file + : mappedPath(directory, stage, file); + if (mapped === null) return null; + const location = path.join(stage, 'blobs', safePath(mapped)); + if (mapped !== file && !existsSync(location)) + throw new Error(`missing historical product file ${mapped} (current path ${file})`); + return existsSync(location) ? readFileSync(location, 'utf8') : null; +} +export function historyAncestor(root, commit, head) { + return readFileSync(path.join(atHead(root, head), 'ancestors'), 'utf8') + .split('\n') + .includes(commit); +} + +if (import.meta.main) { + const [mode] = process.argv.slice(2); + const directory = process.env.OLIPHAUNT_PRODUCT_HISTORY; + if (!directory) throw new Error('missing product history destination'); + if (mode === 'files') { + const wanted = new Set( + readFileSync(path.join(directory, 'wanted-files'), 'utf8').split('\0').filter(Boolean), + ); + for (const commit of readdirSync(path.join(directory, 'trees'))) { + const stage = path.join(directory, 'trees', commit); + const selected = new Set( + [...wanted].flatMap((file) => { + const mapped = + file === 'release-please-config.json' || file === '.release-please-manifest.json' + ? file + : mappedPath(directory, stage, file); + return mapped === null ? [] : [mapped]; + }), + ); + const files = readFileSync(path.join(stage, 'files'), 'utf8') + .split('\0') + .filter((file) => selected.has(file)); + writeFileSync(path.join(stage, 'selected'), files.map((file) => file + '\0').join('')); + } + } else throw new Error('usage: release-history.mts files'); +} diff --git a/tools/release/release-history.test.mts b/tools/release/release-history.test.mts new file mode 100644 index 000000000..81f46f394 --- /dev/null +++ b/tools/release/release-history.test.mts @@ -0,0 +1,53 @@ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { compatibilityVersionValue, productVersionTransitionStatus } from './release-graph.mts'; +import { historyFile, historyManifest } from './release-history.mts'; + +const [mode, repo] = process.argv.slice(2); +if (mode === 'prepare') { + const alpha = { + path: 'red', + tag_prefix: 'alpha-v', + version: '1.1.0', + version_files: ['red/VERSION'], + compatibility_versions: { + runtime: { path: 'red/PIN', parser: 'raw', source_product: 'beta' }, + introduced: { path: 'red/NEW_PIN', parser: 'raw', source_product: 'beta' }, + }, + }; + const graph = { + products: { + alpha, + beta: { + path: 'blue', + tag_prefix: 'beta-v', + version: '8.0.0', + version_files: ['blue/VERSION'], + }, + }, + }; + + writeFileSync(path.join(repo, 'graph.json'), JSON.stringify(graph)); +} else if (mode === 'assert') { + const root = repo; + const config = JSON.parse(readFileSync(path.join(repo, 'graph.json'), 'utf8')).products.alpha; + assert.equal(historyFile(root, 'alpha-v1.0.0', 'red/VERSION'), '1.0.0'); + assert.deepEqual(historyManifest(root, 'alpha-v1.0.0'), { red: '1.0.0', blue: '8.0.0' }); + assert.equal( + compatibilityVersionValue( + { path: 'red/PIN', parser: 'raw' }, + { root, ref: 'alpha-v1.0.0', missingValue: '0.6.0' }, + ), + '0.5.0', + ); + productVersionTransitionStatus('alpha', config, 'alpha-v1.0.0', 'HEAD', { root }); + assert.throws( + () => + compatibilityVersionValue( + { path: 'red/NEW_PIN', parser: 'raw' }, + { root, ref: 'alpha-v1.0.0', missingValue: '0.6.0' }, + ), + /missing historical product file/, + ); +} else throw Error('expected prepare or assert'); diff --git a/tools/release/release-history.test.sh b/tools/release/release-history.test.sh new file mode 100644 index 000000000..be1ee79a9 --- /dev/null +++ b/tools/release/release-history.test.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail +source_root="$(git rev-parse --show-toplevel)" +repo="$(mktemp -d)" +trap 'rm -rf "$repo"' EXIT +cd "$repo" +git init -q +git config user.name Fixture +git config user.email fixture@example.invalid +mkdir blue red +printf '%s' '{"packages":{"blue":{"component":"alpha"},"red":{"component":"beta"}}}' > release-please-config.json +printf '%s' '{"blue":"1.0.0","red":"8.0.0"}' > .release-please-manifest.json +printf 1.0.0 > blue/VERSION +printf 0.5.0 > blue/PIN +printf 8.0.0 > red/VERSION +printf 9.0.0 > red/PIN +git add . +git commit -qm fixture +git tag alpha-v1.0.0 +git tag beta-v8.0.0 +mv blue temp +mv red blue +mv temp red +printf '%s' '{"packages":{"red":{"component":"alpha"},"blue":{"component":"beta"}}}' > release-please-config.json +printf '%s' '{"red":"1.1.0","blue":"8.0.0"}' > .release-please-manifest.json +printf 1.1.0 > red/VERSION +printf 0.6.0 > red/PIN +printf 0.6.0 > red/NEW_PIN +git add . +git commit -qm fixture +cd "$source_root" +bun tools/release/release-history.test.mts prepare "$repo" +bash tools/release/with-product-history.sh "$repo" HEAD '' "$repo/graph.json" \ + bun tools/release/release-history.test.mts assert "$repo" +echo 'Release history: actual directory swap preserves tagged component versions and pins' diff --git a/tools/release/release-metadata-check.mjs b/tools/release/release-metadata-check.mjs deleted file mode 100644 index 3c4c6a685..000000000 --- a/tools/release/release-metadata-check.mjs +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bun - -import { run } from "./release-cli-utils.mjs"; - -const TOOL = "release-metadata-check.mjs"; - -export function releaseMetadataCheckPlan(argv) { - for (const arg of argv) { - if (arg === "-h" || arg === "--help") { - console.log(`usage: tools/release/release-metadata-check.mjs - -Runs Release Please, artifact-target, release-PR, publication metadata, -and generated-docs checks without replaying mutation unit tests. -This is an internal post-qualification or generated-metadata replay surface; -use release-check.mjs for the full local gate. -`); - process.exit(0); - } - throw new Error(`${TOOL}: unexpected argument ${arg}`); - } -} - -function main(argv) { - releaseMetadataCheckPlan(argv); - run(TOOL, [process.execPath, "tools/release/check_release_please_config.mjs"]); - run(TOOL, [process.execPath, "tools/release/check_artifact_targets.mjs"]); - run(TOOL, [process.execPath, "tools/release/sync-release-pr.mjs", "--check"]); - run(TOOL, [process.execPath, "tools/release/check_release_pr_coverage.mjs"]); - run(TOOL, [process.execPath, "tools/release/check-release-metadata.mjs"]); - run(TOOL, ["node", "src/docs/tools/check-docs-product.mjs"]); - run(TOOL, [process.execPath, "tools/release/example-cargo-policy.mjs", "--check"]); -} - -if (import.meta.main) { - main(Bun.argv.slice(2)); -} diff --git a/tools/release/release-metadata-check.sh b/tools/release/release-metadata-check.sh new file mode 100644 index 000000000..3c6042f34 --- /dev/null +++ b/tools/release/release-metadata-check.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +if [ "$#" -gt 1 ] || { [ "$#" -eq 1 ] && [ "$1" != --publication ]; }; then + echo 'usage: release-metadata-check.sh [--publication]' >&2 + exit 2 +fi +for check in check_release_please_config check_artifact_targets; do + bash tools/dev/bun.sh "tools/release/$check.mts" +done +if [ "${1:-}" = --publication ]; then + bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" HEAD bash tools/release/with-product-history.sh "$PWD" HEAD '' @workspace bash tools/dev/bun.sh tools/release/check-release-metadata.mts --publication +else + bash tools/dev/bun.sh tools/release/check-release-metadata.mts +fi +bash tools/release/sync-release-pr.sh --check diff --git a/tools/release/release-notices.mjs b/tools/release/release-notices.mjs deleted file mode 100644 index cf58e4e40..000000000 --- a/tools/release/release-notices.mjs +++ /dev/null @@ -1,665 +0,0 @@ -#!/usr/bin/env node - -import { createHash } from "node:crypto"; - -import { - chmodSync, - copyFileSync, - lstatSync, - mkdirSync, - readFileSync, - readdirSync, - rmSync, -} from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { requireSafeDirectoryChain as requireReleaseDirectoryChain } from "./release-directory-safety.mjs"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const PREFIX = "release-notices.mjs"; - -export const RELEASE_NOTICE_PRODUCTS = Object.freeze(["native", "wasix"]); -export const RELEASE_LICENSE_COMPONENTS = Object.freeze(["postgresql", "icu", "openssl"]); -export const RELEASE_CARRIER_PROFILES = Object.freeze({ - "source-sdk": Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), - "code-facade": Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), - "node-direct-addon": Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), - "wasix-napi-addon": Object.freeze({ products: Object.freeze(["wasix"]), components: Object.freeze(["postgresql", "icu", "openssl"]) }), - broker: Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), - "native-runtime": Object.freeze({ products: Object.freeze(["native"]), components: Object.freeze(["postgresql", "icu"]) }), - "native-tools": Object.freeze({ products: Object.freeze(["native"]), components: Object.freeze(["postgresql"]) }), - "native-runtime-resources": Object.freeze({ products: Object.freeze(["native"]), components: Object.freeze(["postgresql"]) }), - "native-icu-data": Object.freeze({ products: Object.freeze(["native"]), components: Object.freeze(["icu"]) }), - "wasix-runtime": Object.freeze({ products: Object.freeze(["wasix"]), components: Object.freeze(["postgresql", "icu"]) }), - "wasix-tools": Object.freeze({ products: Object.freeze(["wasix"]), components: Object.freeze(["postgresql", "icu"]) }), - "wasix-aot": Object.freeze({ products: Object.freeze(["wasix"]), components: Object.freeze(["postgresql", "icu"]) }), - "wasix-icu-data": Object.freeze({ products: Object.freeze(["wasix"]), components: Object.freeze(["postgresql", "icu"]) }), - "wasix-icu-data-crate": Object.freeze({ products: Object.freeze(["wasix"]), components: Object.freeze(["icu"]) }), - "contrib-native": Object.freeze({ products: Object.freeze([]), components: Object.freeze(["postgresql"]) }), - "contrib-native-openssl": Object.freeze({ products: Object.freeze([]), components: Object.freeze(["postgresql", "openssl"]) }), - "contrib-wasix": Object.freeze({ products: Object.freeze([]), components: Object.freeze(["postgresql"]) }), - "contrib-wasix-openssl": Object.freeze({ products: Object.freeze([]), components: Object.freeze(["postgresql", "openssl"]) }), - "external-native": Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), - "external-wasix": Object.freeze({ products: Object.freeze([]), components: Object.freeze([]) }), -}); - -const BASE_ROWS = Object.freeze([ - Object.freeze({ - member: "LICENSE", - source: path.join(ROOT, "LICENSE"), - }), - Object.freeze({ - member: "THIRD_PARTY_NOTICES.md", - source: path.join(ROOT, "THIRD_PARTY_NOTICES.md"), - }), -]); - -const PRODUCT_NOTICE_ROWS = Object.freeze({ - native: Object.freeze({ - member: "THIRD_PARTY_NOTICES.liboliphaunt-native.md", - source: path.join(ROOT, "src/runtimes/liboliphaunt/native/THIRD_PARTY_NOTICES.md"), - }), - wasix: Object.freeze({ - member: "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", - source: path.join(ROOT, "src/bindings/wasix-rust/THIRD_PARTY_NOTICES.md"), - }), -}); - -const LICENSE_COMPONENT_ROWS = Object.freeze({ - postgresql: Object.freeze({ - id: "postgresql", - spdx: "PostgreSQL", - name: "PostgreSQL License", - member: "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", - source: path.join(ROOT, "src/runtimes/liboliphaunt/licenses/postgresql-18.4-COPYRIGHT"), - sourceManifest: path.join(ROOT, "src/postgres/versions/18/source.toml"), - sourceVersion: "18.4", - sha256: "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd", - sourceUrl: "https://ftp.postgresql.org/pub/source/v18.4/postgresql-18.4.tar.bz2", - sourceIdentity: "sha256:81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094", - licenseUrl: "https://github.com/postgres/postgres/blob/REL_18_4/COPYRIGHT", - }), - icu: Object.freeze({ - id: "icu", - spdx: "Unicode-3.0", - name: "Unicode License v3", - member: "THIRD_PARTY_LICENSES/ICU-LICENSE", - source: path.join(ROOT, "src/runtimes/liboliphaunt/licenses/icu-76.1-LICENSE"), - sourceManifest: path.join(ROOT, "src/sources/third-party/shared/icu.toml"), - sourceVersion: "76.1", - sourceBranch: "release-76-1", - sourceCommit: "8eca245c7484ac6cc179e3e5f7c1ea7680810f39", - sha256: "01edac20612b1e590c1c1cfb02b7218c6adc7b0a944eda7a1e03aeee10725aed", - sourceUrl: "https://github.com/unicode-org/icu.git", - sourceIdentity: "git:8eca245c7484ac6cc179e3e5f7c1ea7680810f39", - licenseUrl: "https://github.com/unicode-org/icu/blob/8eca245c7484ac6cc179e3e5f7c1ea7680810f39/LICENSE", - }), - openssl: Object.freeze({ - id: "openssl", - spdx: "Apache-2.0", - name: "Apache License 2.0 (OpenSSL)", - member: "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt", - source: path.join(ROOT, "src/runtimes/liboliphaunt/licenses/openssl-3.5.6-LICENSE.txt"), - sourceManifest: path.join(ROOT, "src/sources/third-party/shared/openssl.toml"), - sourceVersion: "3.5.6", - sourceBranch: "openssl-3.5.6", - sourceCommit: "286ddeaac037533bbdce65b3c689e3f7ffebf0f6", - sha256: "7d5450cb2d142651b8afa315b5f238efc805dad827d91ba367d8516bc9d49e7a", - sourceUrl: "https://github.com/openssl/openssl.git", - sourceIdentity: "git:286ddeaac037533bbdce65b3c689e3f7ffebf0f6", - licenseUrl: "https://github.com/openssl/openssl/blob/286ddeaac037533bbdce65b3c689e3f7ffebf0f6/LICENSE.txt", - }), -}); - -const PRODUCT_NOTICE_NAMESPACE_PATTERN = /^THIRD_PARTY_NOTICES\.[^/]+\.md$/u; -const LICENSE_NAMESPACE_ROOT = "THIRD_PARTY_LICENSES"; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function checkedProducts(values = []) { - if (!Array.isArray(values)) { - throw new Error("release notices products must be an array"); - } - const result = [...new Set(values.map((value) => String(value)))].sort(compareText); - for (const product of result) { - if (!RELEASE_NOTICE_PRODUCTS.includes(product)) { - throw new Error( - `unsupported release notice product ${JSON.stringify(product)}; expected ${RELEASE_NOTICE_PRODUCTS.join(", ")}`, - ); - } - } - return result; -} - -function checkedComponents(values = []) { - const candidates = values; - if (!Array.isArray(candidates)) { - throw new Error("release license components must be an array"); - } - const selected = new Set(candidates.map((value) => String(value))); - for (const component of selected) { - if (!RELEASE_LICENSE_COMPONENTS.includes(component)) { - throw new Error( - `unsupported release license component ${JSON.stringify(component)}; expected ${RELEASE_LICENSE_COMPONENTS.join(", ")}`, - ); - } - } - return RELEASE_LICENSE_COMPONENTS.filter((component) => selected.has(component)); -} - -export function releaseCarrierProfile(name) { - const profile = RELEASE_CARRIER_PROFILES[name]; - if (!profile) { - throw new Error( - `unsupported release carrier profile ${JSON.stringify(name)}; expected ${Object.keys(RELEASE_CARRIER_PROFILES).join(", ")}`, - ); - } - return profile; -} - -function checkedSelection({ profile, products, components } = {}) { - if (profile !== undefined) { - if (products !== undefined || components !== undefined) { - throw new Error("release carrier profile cannot be combined with explicit products or components"); - } - return releaseCarrierProfile(profile); - } - return Object.freeze({ - products: Object.freeze(checkedProducts(products ?? [])), - components: Object.freeze(checkedComponents(components ?? [])), - }); -} - -function requireRealDirectory(directory, label) { - let stat; - try { - stat = lstatSync(directory); - } catch (cause) { - throw new Error(`${label} cannot be inspected: ${cause.message}`); - } - if (!stat.isDirectory() || stat.isSymbolicLink()) { - throw new Error(`${label} must be a real directory: ${directory}`); - } -} - -function requireCanonicalSource(row) { - let stat; - try { - stat = lstatSync(row.source); - } catch (cause) { - throw new Error(`canonical release notice ${row.source} cannot be inspected: ${cause.message}`); - } - if (!stat.isFile() || stat.isSymbolicLink()) { - throw new Error(`canonical release notice must be a regular non-symlink file: ${row.source}`); - } - const bytes = readFileSync(row.source); - if (bytes.length === 0) { - throw new Error(`canonical release notice must be non-empty: ${row.source}`); - } - if (row.sha256) { - const actual = createHash("sha256").update(bytes).digest("hex"); - if (actual !== row.sha256) { - throw new Error(`canonical release license digest changed for ${row.source}: expected ${row.sha256}, got ${actual}`); - } - } - return bytes; -} - -function validateRuntimeLicenseSource(row) { - let manifest; - try { - manifest = Bun.TOML.parse(readFileSync(row.sourceManifest, "utf8")); - } catch (cause) { - throw new Error(`runtime license source manifest ${row.sourceManifest} cannot be parsed: ${cause.message}`); - } - if (row.id === "postgresql") { - const source = manifest?.postgresql; - if ( - source?.version !== row.sourceVersion - || source?.url !== row.sourceUrl - || `sha256:${source?.sha256}` !== row.sourceIdentity - ) { - throw new Error(`PostgreSQL runtime license snapshot no longer matches ${row.sourceManifest}`); - } - if (!path.basename(row.source).startsWith(`postgresql-${source.version}-`)) { - throw new Error(`PostgreSQL runtime license snapshot name does not carry pinned version ${source.version}`); - } - } else { - if ( - manifest?.name !== row.id - || manifest?.url !== row.sourceUrl - || manifest?.branch !== row.sourceBranch - || manifest?.commit !== row.sourceCommit - || row.sourceIdentity !== `git:${manifest.commit}` - ) { - throw new Error(`${row.id} runtime license snapshot no longer matches ${row.sourceManifest}`); - } - if (!path.basename(row.source).includes(row.sourceVersion)) { - throw new Error(`${row.id} runtime license snapshot name does not carry pinned version ${row.sourceVersion}`); - } - } - requireCanonicalSource(row); - return row; -} - -function checkedPrefix(value = "") { - const raw = String(value); - if ( - raw.startsWith("/") - || raw.includes("\\") - || /^[A-Za-z]:/u.test(raw) - || /[\u0000-\u001f\u007f]/u.test(raw) - ) { - throw new Error(`unsafe release notice archive prefix: ${JSON.stringify(value)}`); - } - const prefix = raw.replace(/^\.\//u, "").replace(/\/$/u, ""); - if ( - prefix.startsWith("/") - || /^[A-Za-z]:/u.test(prefix) - || prefix.split("/").some((part) => !part || part === "." || part === "..") - ) { - if (prefix !== "") { - throw new Error(`unsafe release notice archive prefix: ${JSON.stringify(value)}`); - } - } - return prefix; -} - -function requireSafeDirectoryChain(directory, label) { - return requireReleaseDirectoryChain(directory, { create: true, label }); -} - -function requireSafeParent(root, destination, { create = false } = {}) { - const relative = path.relative(root, path.dirname(destination)); - if (relative.startsWith("..") || path.isAbsolute(relative)) { - throw new Error(`release notice destination escapes staging root: ${destination}`); - } - let cursor = root; - for (const part of relative ? relative.split(path.sep) : []) { - cursor = path.join(cursor, part); - let stat; - try { - stat = lstatSync(cursor); - } catch (cause) { - if (cause?.code !== "ENOENT") { - throw new Error(`release notice parent ${cursor} cannot be inspected: ${cause.message}`); - } - if (!create) { - throw new Error(`release notice parent is missing: ${cursor}`); - } - mkdirSync(cursor, { mode: 0o755 }); - stat = lstatSync(cursor); - } - if (!stat.isDirectory() || stat.isSymbolicLink()) { - throw new Error(`release notice parent must be a real directory: ${cursor}`); - } - } -} - -function prefixedMember(prefix, member) { - return prefix ? `${prefix}/${member}` : member; -} - -function isExpectedNamespaceDirectory(member, expectedMembers) { - if (member === LICENSE_NAMESPACE_ROOT) return true; - return [...expectedMembers].some((expected) => expected.startsWith(`${member}/`)); -} - -function directoryNoticeNamespaceEntries(root) { - const entries = []; - for (const name of readdirSync(root).sort(compareText)) { - if (!PRODUCT_NOTICE_NAMESPACE_PATTERN.test(name)) continue; - const file = path.join(root, name); - entries.push({ member: name, file, stat: lstatSync(file), namespace: "product notice" }); - } - - const licenses = path.join(root, LICENSE_NAMESPACE_ROOT); - let rootStat; - try { - rootStat = lstatSync(licenses); - } catch (cause) { - if (cause?.code === "ENOENT") return entries; - throw new Error(`release license namespace ${licenses} cannot be inspected: ${cause.message}`); - } - entries.push({ - member: LICENSE_NAMESPACE_ROOT, - file: licenses, - stat: rootStat, - namespace: "release license", - }); - if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) return entries; - - function walk(directory, memberPrefix) { - for (const name of readdirSync(directory).sort(compareText)) { - const file = path.join(directory, name); - const member = `${memberPrefix}/${name}`; - const stat = lstatSync(file); - entries.push({ member, file, stat, namespace: "release license" }); - if (stat.isDirectory() && !stat.isSymbolicLink()) walk(file, member); - } - } - walk(licenses, LICENSE_NAMESPACE_ROOT); - return entries; -} - -function archiveNoticeNamespaceEntries(entries, prefix) { - const namespaceEntries = []; - const prefixMarker = prefix ? `${prefix}/` : ""; - for (const [archiveMember, entry] of entries) { - if (prefixMarker && !archiveMember.startsWith(prefixMarker)) continue; - const member = prefixMarker ? archiveMember.slice(prefixMarker.length) : archiveMember; - if (PRODUCT_NOTICE_NAMESPACE_PATTERN.test(member)) { - namespaceEntries.push({ archiveMember, entry, member, namespace: "product notice" }); - } else if (member === LICENSE_NAMESPACE_ROOT || member.startsWith(`${LICENSE_NAMESPACE_ROOT}/`)) { - namespaceEntries.push({ archiveMember, entry, member, namespace: "release license" }); - } - } - return namespaceEntries.sort((left, right) => compareText(left.archiveMember, right.archiveMember)); -} - -function unexpectedNamespaceEntry(namespaceEntry, expectedMembers) { - if (expectedMembers.has(namespaceEntry.member)) return false; - if ( - namespaceEntry.namespace === "release license" - && isExpectedNamespaceDirectory(namespaceEntry.member, expectedMembers) - ) { - if (namespaceEntry.stat) { - return !namespaceEntry.stat.isDirectory() || namespaceEntry.stat.isSymbolicLink(); - } - return namespaceEntry.entry?.isDirectory !== true || namespaceEntry.entry?.isSymbolicLink === true; - } - return true; -} - -export function releaseNoticeRows(options = {}) { - const selection = checkedSelection(options); - const rows = [ - ...BASE_ROWS, - ...selection.products.map((product) => PRODUCT_NOTICE_ROWS[product]), - ...selection.components.map((component) => validateRuntimeLicenseSource(LICENSE_COMPONENT_ROWS[component])), - ]; - return Object.freeze(rows.map((row) => Object.freeze({ ...row }))); -} - -export function releaseNoticeInputPaths(options = { products: RELEASE_NOTICE_PRODUCTS, components: RELEASE_LICENSE_COMPONENTS }) { - return Object.freeze(releaseNoticeRows(options).map((row) => row.source)); -} - -export function releaseLicenseComponents(ids) { - return Object.freeze(checkedComponents(ids).map((id) => validateRuntimeLicenseSource(LICENSE_COMPONENT_ROWS[id]))); -} - -export function releasePackageLicense({ components = [], includeOliphaunt = true } = {}) { - const entries = []; - if (includeOliphaunt) { - entries.push(Object.freeze({ - id: "oliphaunt", - spdx: "MIT", - name: "MIT License (Oliphaunt)", - member: "LICENSE", - source: path.join(ROOT, "LICENSE"), - licenseUrl: "https://github.com/f0rr0/oliphaunt/blob/main/LICENSE", - })); - } - entries.push(...releaseLicenseComponents(components)); - return Object.freeze({ - spdx: entries.map((entry) => entry.spdx).join(" AND "), - entries: Object.freeze(entries), - }); -} - -export function releaseProfilePackageLicense(profile, options = {}) { - const selection = releaseCarrierProfile(profile); - return releasePackageLicense({ - components: selection.components, - includeOliphaunt: options.includeOliphaunt ?? true, - }); -} - -export function releaseMavenLicenses({ product, version, components = [], includeOliphaunt = true } = {}) { - if (typeof product !== "string" || !/^[a-z0-9][a-z0-9-]*$/u.test(product)) { - throw new Error("release Maven licenses require a canonical product id"); - } - if (typeof version !== "string" || !/^[0-9A-Za-z][0-9A-Za-z._-]*$/u.test(version)) { - throw new Error("release Maven licenses require a portable package version"); - } - return Object.freeze(releasePackageLicense({ components, includeOliphaunt }).entries.map((entry) => Object.freeze({ - name: entry.name, - url: entry.id === "oliphaunt" - ? `https://github.com/f0rr0/oliphaunt/blob/${product}-v${version}/LICENSE` - : entry.licenseUrl, - distribution: "repo", - }))); -} - -export function releaseProfileMavenLicenses(profile, { product, version, includeOliphaunt = true } = {}) { - const selection = releaseCarrierProfile(profile); - return releaseMavenLicenses({ - product, - version, - components: selection.components, - includeOliphaunt, - }); -} - -export function stageReleaseNotices(destination, options = {}) { - const directory = requireSafeDirectoryChain(destination, "release notice destination"); - const rows = releaseNoticeRows(options); - const expectedMembers = new Set(rows.map((row) => row.member)); - - // A reused package stage must not retain any unselected or unrecognized - // member in the canonical legal namespaces. Only regular files are safe to - // remove automatically; links, special files, and unexpected directory - // topology fail closed. - for (const entry of directoryNoticeNamespaceEntries(directory)) { - if (!unexpectedNamespaceEntry(entry, expectedMembers)) continue; - if (!entry.stat.isFile() || entry.stat.isSymbolicLink()) { - throw new Error( - `stale ${entry.namespace} path is not a regular non-symlink file: ${entry.file}`, - ); - } - rmSync(entry.file); - } - - for (const row of rows) { - requireCanonicalSource(row); - const destinationFile = path.join(directory, row.member); - requireSafeParent(directory, destinationFile, { create: true }); - let prior; - try { - prior = lstatSync(destinationFile); - } catch (cause) { - if (cause?.code !== "ENOENT") { - throw new Error(`release notice destination ${destinationFile} cannot be inspected: ${cause.message}`); - } - } - if (prior && (!prior.isFile() || prior.isSymbolicLink())) { - throw new Error(`release notice destination is not a regular file: ${destinationFile}`); - } - copyFileSync(row.source, destinationFile); - chmodSync(destinationFile, 0o644); - } - assertReleaseNoticesInDirectory(directory, options); - return rows.map((row) => path.join(directory, row.member)); -} - -export function hasCanonicalReleaseStagingMode(mode, platform = process.platform) { - // Windows exposes synthetic Unix permission bits through stat(2). chmod can - // toggle the read-only attribute, but it cannot establish a meaningful 0644 - // filesystem contract. Portable archives still carry and validate their - // explicit modes in assertReleaseNoticesInEntries. - return platform === "win32" || (mode & 0o777) === 0o644; -} - -export function assertReleaseNoticesInDirectory(directory, options = {}) { - const { exact = true } = options; - const root = path.resolve(directory); - requireRealDirectory(root, "release notice directory"); - const rows = releaseNoticeRows(options); - const expected = new Set(rows.map((row) => row.member)); - for (const row of rows) { - const file = path.join(root, row.member); - requireSafeParent(root, file); - let stat; - try { - stat = lstatSync(file); - } catch (cause) { - throw new Error(`missing release notice ${file}: ${cause.message}`); - } - if (!stat.isFile() || stat.isSymbolicLink()) { - throw new Error(`release notice must be a regular non-symlink file: ${file}`); - } - if (!hasCanonicalReleaseStagingMode(stat.mode)) { - throw new Error(`release notice must have mode 0644: ${file}`); - } - const canonical = requireCanonicalSource(row); - const actual = readFileSync(file); - if (!actual.equals(canonical)) { - throw new Error(`release notice differs byte-for-byte from ${row.source}: ${file}`); - } - } - if (exact) { - for (const entry of directoryNoticeNamespaceEntries(root)) { - if (!unexpectedNamespaceEntry(entry, expected)) continue; - throw new Error( - `release notice directory contains unexpected ${entry.namespace} member ${entry.member}`, - ); - } - } - return rows.map((row) => row.member); -} - -export function assertReleaseNoticesInEntries(entries, options = {}) { - const { - prefix = "", - exact = true, - label = "archive", - } = options; - if (!(entries instanceof Map)) { - throw new Error("release notice archive entries must be a Map"); - } - const checkedArchivePrefix = checkedPrefix(prefix); - const rows = releaseNoticeRows(options); - const expected = new Set(rows.map((row) => row.member)); - for (const row of rows) { - const member = prefixedMember(checkedArchivePrefix, row.member); - const entry = entries.get(member); - if (!entry?.isFile || entry.isSymbolicLink) { - throw new Error(`${label} is missing regular release notice member ${member}`); - } - if ((entry.mode & 0o777) !== 0o644) { - throw new Error(`${label} release notice member ${member} must have mode 0644`); - } - const canonical = requireCanonicalSource(row); - const actual = Buffer.from(entry.data()); - if (!actual.equals(canonical)) { - throw new Error(`${label} release notice member ${member} differs byte-for-byte from ${row.source}`); - } - } - if (exact) { - for (const entry of archiveNoticeNamespaceEntries(entries, checkedArchivePrefix)) { - if (!unexpectedNamespaceEntry(entry, expected)) continue; - throw new Error(`${label} contains unexpected ${entry.namespace} member ${entry.archiveMember}`); - } - } - return rows.map((row) => prefixedMember(checkedArchivePrefix, row.member)); -} - -export function assertReleaseNoticesInArchive(file, options = {}) { - const archive = path.resolve(file); - return assertReleaseNoticesInEntries(readPortableArchiveEntries(archive), { - ...options, - label: options.label ?? path.basename(archive), - }); -} - -function usage() { - return [ - "usage:", - " tools/release/release-notices.mjs stage --profile ", - " tools/release/release-notices.mjs check-directory --profile ", - " tools/release/release-notices.mjs check-archive --profile [--prefix ]", - " advanced: replace --profile with explicit --product and --component flags", - ].join("\n"); -} - -function parseCli(argv) { - const values = [...argv]; - const command = values.shift(); - const target = values.shift(); - if (!command || !target || !["stage", "check-directory", "check-archive"].includes(command)) { - throw new Error(usage()); - } - const products = []; - const components = []; - let componentsSupplied = false; - let prefix = ""; - let profile; - while (values.length > 0) { - const flag = values.shift(); - if (flag === "--profile") { - if (profile !== undefined) throw new Error("--profile may be supplied only once"); - profile = values.shift(); - if (!profile) throw new Error("--profile requires a value"); - releaseCarrierProfile(profile); - } else if (flag === "--product") { - const product = values.shift(); - if (!product) throw new Error("--product requires a value"); - products.push(product); - } else if (flag === "--component") { - const component = values.shift(); - if (!component) throw new Error("--component requires a value"); - components.push(component); - componentsSupplied = true; - } else if (flag === "--prefix" && command === "check-archive") { - const value = values.shift(); - if (value === undefined) throw new Error("--prefix requires a value"); - prefix = value; - } else { - throw new Error(`unsupported release notice argument ${JSON.stringify(flag)}\n${usage()}`); - } - } - if (profile !== undefined && (products.length > 0 || componentsSupplied)) { - throw new Error("--profile cannot be combined with --product or --component"); - } - const checkedProductValues = checkedProducts(products); - return { - command, - prefix, - noticeOptions: profile === undefined - ? { products: checkedProductValues, components: checkedComponents(componentsSupplied ? components : []) } - : { profile }, - target, - }; -} - -function main() { - let args; - try { - args = parseCli(process.argv.slice(2)); - if (args.command === "stage") { - stageReleaseNotices(args.target, args.noticeOptions); - } else if (args.command === "check-directory") { - assertReleaseNoticesInDirectory(args.target, args.noticeOptions); - } else { - assertReleaseNoticesInArchive(args.target, { - prefix: args.prefix, - ...args.noticeOptions, - }); - } - } catch (error) { - console.error(`${PREFIX}: ${error instanceof Error ? error.message : String(error)}`); - process.exitCode = 1; - return; - } - console.log(`${PREFIX}: ${args.command} passed for ${args.target}`); -} - -const invoked = process.argv[1] ? path.resolve(process.argv[1]) : ""; -if (invoked === fileURLToPath(import.meta.url)) { - main(); -} diff --git a/tools/release/release-notices.test.mjs b/tools/release/release-notices.test.mjs deleted file mode 100644 index 9f778b23c..000000000 --- a/tools/release/release-notices.test.mjs +++ /dev/null @@ -1,338 +0,0 @@ -import assert from "node:assert/strict"; -import { - chmodSync, - mkdtempSync, - mkdirSync, - readFileSync, - realpathSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import test from "node:test"; -import { zstdCompressSync } from "node:zlib"; - -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - assertReleaseNoticesInEntries, - hasCanonicalReleaseStagingMode, - releasePackageLicense, - releaseNoticeRows, - stageReleaseNotices, -} from "./release-notices.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); - -function fixture(t) { - const root = realpathSync(mkdtempSync(path.join(tmpdir(), "release-notices-test-"))); - t.after(() => rmSync(root, { recursive: true, force: true })); - const stage = path.join(root, "stage"); - mkdirSync(stage); - return { root, stage }; -} - -test("defines stable canonical member names in deterministic order", () => { - assert.deepEqual( - releaseNoticeRows({ products: ["wasix", "native", "native"] }).map((row) => [ - row.member, - path.relative(ROOT, row.source).split(path.sep).join("/"), - ]), - [ - ["LICENSE", "LICENSE"], - ["THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.md"], - ["THIRD_PARTY_NOTICES.liboliphaunt-native.md", "src/runtimes/liboliphaunt/native/THIRD_PARTY_NOTICES.md"], - ["THIRD_PARTY_NOTICES.oliphaunt-wasix.md", "src/bindings/wasix-rust/THIRD_PARTY_NOTICES.md"], - ], - ); - assert.throws(() => releaseNoticeRows({ products: ["unknown"] }), /unsupported release notice product/u); - assert.deepEqual( - releaseNoticeRows({ components: ["openssl", "postgresql", "icu"] }).map((row) => row.member), - [ - "LICENSE", - "THIRD_PARTY_NOTICES.md", - "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", - "THIRD_PARTY_LICENSES/ICU-LICENSE", - "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt", - ], - ); - assert.throws(() => releaseNoticeRows({ components: ["unknown"] }), /unsupported release license component/u); - assert.deepEqual(releasePackageLicense({ components: ["icu", "postgresql"] }), { - spdx: "MIT AND PostgreSQL AND Unicode-3.0", - entries: releasePackageLicense({ components: ["postgresql", "icu"] }).entries, - }); - assert.deepEqual( - releaseNoticeRows({ profile: "native-tools" }).map((row) => row.member), - [ - "LICENSE", - "THIRD_PARTY_NOTICES.md", - "THIRD_PARTY_NOTICES.liboliphaunt-native.md", - "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", - ], - ); -}); - -test("stages exact bytes and removes stale product notices", (t) => { - const { stage } = fixture(t); - stageReleaseNotices(stage, { products: ["native", "wasix"] }); - for (const row of releaseNoticeRows({ products: ["native", "wasix"] })) { - assert.deepEqual(readFileSync(path.join(stage, row.member)), readFileSync(row.source)); - } - stageReleaseNotices(stage, { products: ["native"] }); - assert.deepEqual( - assertReleaseNoticesInDirectory(stage, { products: ["native"] }), - ["LICENSE", "THIRD_PARTY_NOTICES.md", "THIRD_PARTY_NOTICES.liboliphaunt-native.md"], - ); - assert.throws( - () => assertReleaseNoticesInDirectory(stage, { products: [] }), - /unexpected product notice/u, - ); -}); - -test("rejects byte drift and POSIX directory mode drift", (t) => { - const { stage } = fixture(t); - stageReleaseNotices(stage); - writeFileSync(path.join(stage, "LICENSE"), "not the license\n"); - assert.throws(() => assertReleaseNoticesInDirectory(stage), /differs byte-for-byte/u); - if (process.platform !== "win32") { - stageReleaseNotices(stage); - chmodSync(path.join(stage, "LICENSE"), 0o600); - assert.throws(() => assertReleaseNoticesInDirectory(stage), /mode 0644/u); - } -}); - -test("treats directory modes as POSIX-only staging metadata", () => { - assert.equal(hasCanonicalReleaseStagingMode(0o666, "win32"), true); - assert.equal(hasCanonicalReleaseStagingMode(0o644, "linux"), true); - assert.equal(hasCanonicalReleaseStagingMode(0o666, "linux"), false); -}); - -test("keeps portable archive notice modes exact on every host", () => { - const entries = new Map(releaseNoticeRows().map((row) => [ - row.member, - { - isDirectory: false, - isFile: true, - isSymbolicLink: false, - mode: row.member === "LICENSE" ? 0o666 : 0o644, - data: () => readFileSync(row.source), - }, - ])); - assert.throws(() => assertReleaseNoticesInEntries(entries), /mode 0644/u); -}); - -test("exact validation rejects unknown legal namespace members and staging removes only safe stale files", (t) => { - const { root, stage } = fixture(t); - stageReleaseNotices(stage, { components: ["postgresql"] }); - const unknownProductNotice = path.join(stage, "THIRD_PARTY_NOTICES.unrecognized-runtime.md"); - const unknownLicense = path.join(stage, "THIRD_PARTY_LICENSES", "Unrecognized-LICENSE"); - writeFileSync(unknownProductNotice, "unknown product notice\n"); - writeFileSync(unknownLicense, "unknown component license\n"); - - assert.throws( - () => assertReleaseNoticesInDirectory(stage, { components: ["postgresql"] }), - /unexpected product notice member THIRD_PARTY_NOTICES\.unrecognized-runtime\.md/u, - ); - rmSync(unknownProductNotice); - assert.throws( - () => assertReleaseNoticesInDirectory(stage, { components: ["postgresql"] }), - /unexpected release license member THIRD_PARTY_LICENSES\/Unrecognized-LICENSE/u, - ); - - writeFileSync(unknownProductNotice, "unknown product notice\n"); - stageReleaseNotices(stage, { components: ["postgresql"] }); - assertReleaseNoticesInDirectory(stage, { components: ["postgresql"] }); - - const outside = path.join(root, "outside-license"); - writeFileSync(outside, "not safe to remove\n"); - symlinkSync(outside, unknownLicense); - assert.throws( - () => stageReleaseNotices(stage, { components: ["postgresql"] }), - /stale release license path is not a regular non-symlink file/u, - ); -}); - -test("rejects unsafe prefixes and unsafe staging destinations", (t) => { - const { root, stage } = fixture(t); - for (const prefix of ["/", "\\", "a\\b", "../escape", "C:/escape", "a//b", "./../escape"]) { - assert.throws( - () => assertReleaseNoticesInEntries(new Map(), { prefix }), - /unsafe release notice archive prefix/u, - prefix, - ); - } - - const nonDirectory = path.join(root, "not-a-directory"); - writeFileSync(nonDirectory, "file\n"); - assert.throws( - () => stageReleaseNotices(nonDirectory), - /real directory|cannot be inspected|symlink or non-directory ancestor/u, - ); - - const outside = path.join(root, "outside"); - mkdirSync(outside); - symlinkSync(outside, path.join(stage, "THIRD_PARTY_LICENSES")); - assert.throws( - () => stageReleaseNotices(stage, { components: ["postgresql"] }), - /stale release license path is not a regular non-symlink file/u, - ); - - const realAncestor = path.join(root, "real-ancestor"); - const existingStage = path.join(realAncestor, "existing-stage"); - mkdirSync(existingStage, { recursive: true }); - const linkedAncestor = path.join(root, "linked-ancestor"); - symlinkSync(realAncestor, linkedAncestor); - assert.throws( - () => stageReleaseNotices(path.join(linkedAncestor, "existing-stage")), - /symlink or non-directory ancestor/u, - ); - - const linkedStage = path.join(root, "linked-stage"); - symlinkSync(existingStage, linkedStage); - assert.throws( - () => stageReleaseNotices(linkedStage), - /symlink or non-directory ancestor/u, - ); -}); - -test("rejects caller-created directory aliases and non-directory ancestors", (t) => { - const { root } = fixture(t); - const outside = path.join(root, "outside"); - const stage = path.join(outside, "stage"); - mkdirSync(stage, { recursive: true }); - - const callerAlias = path.join(root, "var"); - symlinkSync(outside, callerAlias, process.platform === "win32" ? "junction" : "dir"); - assert.throws( - () => stageReleaseNotices(path.join(callerAlias, "stage")), - /symlink or non-directory ancestor/u, - ); - - const nonDirectory = path.join(root, "ordinary-file"); - writeFileSync(nonDirectory, "not a directory\n"); - assert.throws( - () => stageReleaseNotices(path.join(nonDirectory, "stage")), - /symlink or non-directory ancestor/u, - ); -}); - -test("validates exact archive members and canonical bytes", (t) => { - const { root, stage } = fixture(t); - stageReleaseNotices(stage, { products: ["native"] }); - writeFileSync(path.join(stage, "payload.txt"), "payload\n"); - const archive = path.join(root, "carrier.tar.gz"); - const result = spawnSync( - path.join(ROOT, "tools/dev/bun.sh"), - ["src/shared/artifact-packaging/archive-directory.mjs", "--keep-parent", stage, archive], - { cwd: ROOT, encoding: "utf8" }, - ); - assert.equal(result.status, 0, result.stderr); - assert.deepEqual( - assertReleaseNoticesInArchive(archive, { - prefix: path.basename(stage), - products: ["native"], - }), - [ - `${path.basename(stage)}/LICENSE`, - `${path.basename(stage)}/THIRD_PARTY_NOTICES.md`, - `${path.basename(stage)}/THIRD_PARTY_NOTICES.liboliphaunt-native.md`, - ], - ); - assert.throws( - () => assertReleaseNoticesInArchive(archive, { prefix: path.basename(stage) }), - /unexpected product notice/u, - ); -}); - -test("exact archive validation rejects unknown legal namespace members", (t) => { - const { root, stage } = fixture(t); - const prefix = "carrier"; - stageReleaseNotices(stage, { components: ["postgresql"] }); - - const productNotice = path.join(stage, "THIRD_PARTY_NOTICES.unknown-product.md"); - writeFileSync(productNotice, "unknown product notice\n"); - let archive = path.join(root, "unknown-product.tar.zst"); - writeFileSync(archive, zstdCompressSync(createDeterministicTar(stage, prefix, { - fail(message) { - throw new Error(message); - }, - }))); - assert.throws( - () => assertReleaseNoticesInArchive(archive, { prefix, components: ["postgresql"] }), - /unexpected product notice member carrier\/THIRD_PARTY_NOTICES\.unknown-product\.md/u, - ); - - rmSync(productNotice); - writeFileSync(path.join(stage, "THIRD_PARTY_LICENSES", "Unknown-LICENSE"), "unknown license\n"); - archive = path.join(root, "unknown-license.tar.zst"); - writeFileSync(archive, zstdCompressSync(createDeterministicTar(stage, prefix, { - fail(message) { - throw new Error(message); - }, - }))); - assert.throws( - () => assertReleaseNoticesInArchive(archive, { prefix, components: ["postgresql"] }), - /unexpected release license member carrier\/THIRD_PARTY_LICENSES\/Unknown-LICENSE/u, - ); -}); - -test("validates exact notices in a real zstd-compressed ustar carrier", (t) => { - const { root, stage } = fixture(t); - const profile = "wasix-runtime"; - const prefix = "liboliphaunt-wasix-runtime-portable"; - stageReleaseNotices(stage, { profile }); - writeFileSync(path.join(stage, "runtime.bin"), "runtime\n"); - const archive = path.join(root, `${prefix}.tar.zst`); - const tar = createDeterministicTar(stage, prefix, { - fail(message) { - throw new Error(message); - }, - }); - writeFileSync(archive, zstdCompressSync(tar)); - - assert.deepEqual( - assertReleaseNoticesInArchive(archive, { prefix, profile }), - releaseNoticeRows({ profile }).map((row) => `${prefix}/${row.member}`), - ); -}); - -test("rejects archive byte and mode drift", (t) => { - const { root, stage } = fixture(t); - stageReleaseNotices(stage, { components: ["postgresql"] }); - writeFileSync(path.join(stage, "LICENSE"), "not the license\n"); - const byteArchive = path.join(root, "byte-drift.tar.gz"); - let result = spawnSync( - path.join(ROOT, "tools/dev/bun.sh"), - ["src/shared/artifact-packaging/archive-directory.mjs", "--keep-parent", stage, byteArchive], - { cwd: ROOT, encoding: "utf8" }, - ); - assert.equal(result.status, 0, result.stderr); - assert.throws( - () => assertReleaseNoticesInArchive(byteArchive, { - prefix: path.basename(stage), - components: ["postgresql"], - }), - /differs byte-for-byte/u, - ); - - stageReleaseNotices(stage, { components: ["postgresql"] }); - chmodSync(path.join(stage, "LICENSE"), 0o755); - const modeArchive = path.join(root, "mode-drift.tar.gz"); - result = spawnSync( - path.join(ROOT, "tools/dev/bun.sh"), - ["src/shared/artifact-packaging/archive-directory.mjs", "--keep-parent", stage, modeArchive], - { cwd: ROOT, encoding: "utf8" }, - ); - assert.equal(result.status, 0, result.stderr); - assert.throws( - () => assertReleaseNoticesInArchive(modeArchive, { - prefix: path.basename(stage), - components: ["postgresql"], - }), - /mode 0644/u, - ); -}); diff --git a/tools/release/release-plan.sh b/tools/release/release-plan.sh new file mode 100644 index 000000000..7750d52d4 --- /dev/null +++ b/tools/release/release-plan.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +if [[ "${1:-}" != --with-graph ]]; then + exec bash tools/ci/with-projects.sh --exec bash tools/release/release-plan.sh --with-graph "$@" +fi +shift +request="$(mktemp -d)" +trap 'rm -rf "$request"' EXIT +bash tools/dev/bun.sh tools/release/release_plan.mts --history-inputs "$request" "$@" +{ IFS= read -r -d '' head; IFS= read -r -d '' base; } < "$request/refs" +if [[ -n "$head" ]]; then + bash tools/release/with-product-history.sh "$PWD" "$head" "$base" "$request/graph.json" bash tools/dev/bun.sh tools/release/release_plan.mts "$@" +else + bash tools/dev/bun.sh tools/release/release_plan.mts "$@" +fi diff --git a/tools/release/release-please-bootstrap.mjs b/tools/release/release-please-bootstrap.mjs deleted file mode 100644 index 946f401b8..000000000 --- a/tools/release/release-please-bootstrap.mjs +++ /dev/null @@ -1,45 +0,0 @@ -export const RELEASE_PLEASE_BOOTSTRAP_SHA = - "07a9054faa03d5737dc0193f7a77ed4a71920c05"; - -function isObject(value) { - return value !== null && !Array.isArray(value) && typeof value === "object"; -} - -export function isUnreleasedReleasePleaseManifest(manifest) { - if (!isObject(manifest)) { - throw new TypeError("release-please manifest must be an object"); - } - const versions = Object.values(manifest); - return versions.length > 0 && versions.every((version) => version === "0.0.0"); -} - -export function releasePleaseBootstrapLifecycleError(config, manifest) { - if (!isObject(config)) { - throw new TypeError("release-please config must be an object"); - } - if (isUnreleasedReleasePleaseManifest(manifest)) { - if (config["bootstrap-sha"] !== RELEASE_PLEASE_BOOTSTRAP_SHA) { - return ( - `release-please bootstrap-sha must be the full legacy-history boundary ` + - `${RELEASE_PLEASE_BOOTSTRAP_SHA} until the first generated release bump consumes it` - ); - } - return undefined; - } - if (Object.hasOwn(config, "bootstrap-sha")) { - return "release-please bootstrap-sha is one-time state and must be absent after the first generated release bump"; - } - return undefined; -} - -export function releasePleaseConfigAfterBootstrapConsumption(config, manifest) { - if (!isObject(config)) { - throw new TypeError("release-please config must be an object"); - } - if (isUnreleasedReleasePleaseManifest(manifest) || !Object.hasOwn(config, "bootstrap-sha")) { - return config; - } - const updated = { ...config }; - delete updated["bootstrap-sha"]; - return updated; -} diff --git a/tools/release/release-please-bootstrap.mts b/tools/release/release-please-bootstrap.mts new file mode 100644 index 000000000..7d329cae7 --- /dev/null +++ b/tools/release/release-please-bootstrap.mts @@ -0,0 +1,44 @@ +export const RELEASE_PLEASE_BOOTSTRAP_SHA = '07a9054faa03d5737dc0193f7a77ed4a71920c05'; + +function isObject(value) { + return value !== null && !Array.isArray(value) && typeof value === 'object'; +} + +export function isUnreleasedReleasePleaseManifest(manifest) { + if (!isObject(manifest)) { + throw new TypeError('release-please manifest must be an object'); + } + const versions = Object.values(manifest); + return versions.length > 0 && versions.every((version) => version === '0.0.0'); +} + +export function releasePleaseBootstrapLifecycleError(config, manifest) { + if (!isObject(config)) { + throw new TypeError('release-please config must be an object'); + } + if (isUnreleasedReleasePleaseManifest(manifest)) { + if (config['bootstrap-sha'] !== RELEASE_PLEASE_BOOTSTRAP_SHA) { + return ( + `release-please bootstrap-sha must be the full legacy-history boundary ` + + `${RELEASE_PLEASE_BOOTSTRAP_SHA} until the first generated release bump consumes it` + ); + } + return undefined; + } + if (Object.hasOwn(config, 'bootstrap-sha')) { + return 'release-please bootstrap-sha is one-time state and must be absent after the first generated release bump'; + } + return undefined; +} + +export function releasePleaseConfigAfterBootstrapConsumption(config, manifest) { + if (!isObject(config)) { + throw new TypeError('release-please config must be an object'); + } + if (isUnreleasedReleasePleaseManifest(manifest) || !Object.hasOwn(config, 'bootstrap-sha')) { + return config; + } + const updated = { ...config }; + delete updated['bootstrap-sha']; + return updated; +} diff --git a/tools/release/release-please-bootstrap.test.mjs b/tools/release/release-please-bootstrap.test.mjs deleted file mode 100644 index a42a72586..000000000 --- a/tools/release/release-please-bootstrap.test.mjs +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - RELEASE_PLEASE_BOOTSTRAP_SHA, - isUnreleasedReleasePleaseManifest, - releasePleaseBootstrapLifecycleError, - releasePleaseConfigAfterBootstrapConsumption, -} from "./release-please-bootstrap.mjs"; - -const seedManifest = { "packages/alpha": "0.0.0", "packages/beta": "0.0.0" }; -const releasedManifest = { ...seedManifest, "packages/alpha": "0.1.0" }; -const seedConfig = { "bootstrap-sha": RELEASE_PLEASE_BOOTSTRAP_SHA, packages: {} }; - -test("requires the exact full history boundary while every product is unreleased", () => { - assert.equal(isUnreleasedReleasePleaseManifest(seedManifest), true); - assert.equal(releasePleaseBootstrapLifecycleError(seedConfig, seedManifest), undefined); - assert.match( - releasePleaseBootstrapLifecycleError({ packages: {} }, seedManifest), - /bootstrap-sha must be the full legacy-history boundary/u, - ); - assert.match( - releasePleaseBootstrapLifecycleError({ ...seedConfig, "bootstrap-sha": "07a9054" }, seedManifest), - /bootstrap-sha must be the full legacy-history boundary/u, - ); -}); - -test("removes bootstrap-sha exactly once after a generated release bump", () => { - assert.equal(isUnreleasedReleasePleaseManifest(releasedManifest), false); - assert.match( - releasePleaseBootstrapLifecycleError(seedConfig, releasedManifest), - /one-time state/u, - ); - const updated = releasePleaseConfigAfterBootstrapConsumption(seedConfig, releasedManifest); - assert.deepEqual(updated, { packages: {} }); - assert.notEqual(updated, seedConfig); - assert.equal(releasePleaseBootstrapLifecycleError(updated, releasedManifest), undefined); - assert.equal(releasePleaseConfigAfterBootstrapConsumption(updated, releasedManifest), updated); -}); - -test("does not remove the boundary before release-please consumes it", () => { - assert.equal(releasePleaseConfigAfterBootstrapConsumption(seedConfig, seedManifest), seedConfig); -}); diff --git a/tools/release/release-please-bootstrap.test.mts b/tools/release/release-please-bootstrap.test.mts new file mode 100644 index 000000000..6d85acd4c --- /dev/null +++ b/tools/release/release-please-bootstrap.test.mts @@ -0,0 +1,47 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + RELEASE_PLEASE_BOOTSTRAP_SHA, + isUnreleasedReleasePleaseManifest, + releasePleaseBootstrapLifecycleError, + releasePleaseConfigAfterBootstrapConsumption, +} from './release-please-bootstrap.mts'; + +const seedManifest = { 'packages/alpha': '0.0.0', 'packages/beta': '0.0.0' }; +const releasedManifest = { ...seedManifest, 'packages/alpha': '0.1.0' }; +const seedConfig = { 'bootstrap-sha': RELEASE_PLEASE_BOOTSTRAP_SHA, packages: {} }; + +test('requires the exact full history boundary while every product is unreleased', () => { + assert.equal(isUnreleasedReleasePleaseManifest(seedManifest), true); + assert.equal(releasePleaseBootstrapLifecycleError(seedConfig, seedManifest), undefined); + assert.match( + releasePleaseBootstrapLifecycleError({ packages: {} }, seedManifest), + /bootstrap-sha must be the full legacy-history boundary/u, + ); + assert.match( + releasePleaseBootstrapLifecycleError( + { ...seedConfig, 'bootstrap-sha': '07a9054' }, + seedManifest, + ), + /bootstrap-sha must be the full legacy-history boundary/u, + ); +}); + +test('removes bootstrap-sha exactly once after a generated release bump', () => { + assert.equal(isUnreleasedReleasePleaseManifest(releasedManifest), false); + assert.match( + releasePleaseBootstrapLifecycleError(seedConfig, releasedManifest), + /one-time state/u, + ); + const updated = releasePleaseConfigAfterBootstrapConsumption(seedConfig, releasedManifest); + assert.deepEqual(updated, { packages: {} }); + assert.notEqual(updated, seedConfig); + assert.equal(releasePleaseBootstrapLifecycleError(updated, releasedManifest), undefined); + assert.equal(releasePleaseConfigAfterBootstrapConsumption(updated, releasedManifest), updated); +}); + +test('does not remove the boundary before release-please consumes it', () => { + assert.equal(releasePleaseConfigAfterBootstrapConsumption(seedConfig, seedManifest), seedConfig); +}); diff --git a/tools/release/release-please-package-identity.mjs b/tools/release/release-please-package-identity.mjs deleted file mode 100644 index c37799e21..000000000 --- a/tools/release/release-please-package-identity.mjs +++ /dev/null @@ -1,27 +0,0 @@ -const NODE_RELEASE_TYPES = new Set(['expo', 'node']); - -/** - * Release Please's package-name is the public registry identity for Node - * products, so it must not drift from the package manifest it versions. - */ -export function assertReleasePleasePackageIdentity(packagePath, packageConfig, packageManifest) { - if (!NODE_RELEASE_TYPES.has(packageConfig['release-type'])) { - return; - } - - const configuredName = packageConfig['package-name']; - if (typeof configuredName !== 'string' || configuredName.length === 0) { - throw new Error(`${packagePath}.package-name must be a non-empty string for a Node product`); - } - - const manifestName = packageManifest.name; - if (typeof manifestName !== 'string' || manifestName.length === 0) { - throw new Error(`${packagePath}/package.json must declare a non-empty name`); - } - if (configuredName !== manifestName) { - throw new Error( - `${packagePath}.package-name ${JSON.stringify(configuredName)} must match ` - + `${packagePath}/package.json name ${JSON.stringify(manifestName)}`, - ); - } -} diff --git a/tools/release/release-please-package-identity.mts b/tools/release/release-please-package-identity.mts new file mode 100644 index 000000000..d54769caf --- /dev/null +++ b/tools/release/release-please-package-identity.mts @@ -0,0 +1,27 @@ +const NODE_RELEASE_TYPES = new Set(['expo', 'node']); + +/** + * Release Please's package-name is the public registry identity for Node + * products, so it must not drift from the package manifest it versions. + */ +export function assertReleasePleasePackageIdentity(packagePath, packageConfig, packageManifest) { + if (!NODE_RELEASE_TYPES.has(packageConfig['release-type'])) { + return; + } + + const configuredName = packageConfig['package-name']; + if (typeof configuredName !== 'string' || configuredName.length === 0) { + throw new Error(`${packagePath}.package-name must be a non-empty string for a Node product`); + } + + const manifestName = packageManifest.name; + if (typeof manifestName !== 'string' || manifestName.length === 0) { + throw new Error(`${packagePath}/package.json must declare a non-empty name`); + } + if (configuredName !== manifestName) { + throw new Error( + `${packagePath}.package-name ${JSON.stringify(configuredName)} must match ` + + `${packagePath}/package.json name ${JSON.stringify(manifestName)}`, + ); + } +} diff --git a/tools/release/release-please-package-identity.test.mjs b/tools/release/release-please-package-identity.test.mjs deleted file mode 100644 index 0384b761a..000000000 --- a/tools/release/release-please-package-identity.test.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import { describe, expect, test } from 'bun:test'; - -import { assertReleasePleasePackageIdentity } from './release-please-package-identity.mjs'; - -const PACKAGE_PATH = 'packages/typescript'; - -describe('Release Please Node package identity', () => { - test('accepts an exact package-name and package.json name match', () => { - expect(() => assertReleasePleasePackageIdentity( - PACKAGE_PATH, - { 'release-type': 'node', 'package-name': '@oliphaunt/example' }, - { name: '@oliphaunt/example' }, - )).not.toThrow(); - }); - - test('rejects a registry identity that drifted from package.json', () => { - expect(() => assertReleasePleasePackageIdentity( - PACKAGE_PATH, - { 'release-type': 'node', 'package-name': '@oliphaunt/stale' }, - { name: '@oliphaunt/example' }, - )).toThrow( - 'packages/typescript.package-name "@oliphaunt/stale" must match ' - + 'packages/typescript/package.json name "@oliphaunt/example"', - ); - }); - - test('does not interpret non-Node product package names as npm identities', () => { - expect(() => assertReleasePleasePackageIdentity( - 'packages/rust', - { 'release-type': 'rust', 'package-name': 'example' }, - {}, - )).not.toThrow(); - }); -}); diff --git a/tools/release/release-please-package-identity.test.mts b/tools/release/release-please-package-identity.test.mts new file mode 100644 index 000000000..bb8453d1d --- /dev/null +++ b/tools/release/release-please-package-identity.test.mts @@ -0,0 +1,40 @@ +import { describe, expect, test } from 'bun:test'; + +import { assertReleasePleasePackageIdentity } from './release-please-package-identity.mts'; + +const PACKAGE_PATH = 'packages/typescript'; + +describe('Release Please Node package identity', () => { + test('accepts an exact package-name and package.json name match', () => { + expect(() => + assertReleasePleasePackageIdentity( + PACKAGE_PATH, + { 'release-type': 'node', 'package-name': '@oliphaunt/example' }, + { name: '@oliphaunt/example' }, + ), + ).not.toThrow(); + }); + + test('rejects a registry identity that drifted from package.json', () => { + expect(() => + assertReleasePleasePackageIdentity( + PACKAGE_PATH, + { 'release-type': 'node', 'package-name': '@oliphaunt/stale' }, + { name: '@oliphaunt/example' }, + ), + ).toThrow( + 'packages/typescript.package-name "@oliphaunt/stale" must match ' + + 'packages/typescript/package.json name "@oliphaunt/example"', + ); + }); + + test('does not interpret non-Node product package names as npm identities', () => { + expect(() => + assertReleasePleasePackageIdentity( + 'packages/rust', + { 'release-type': 'rust', 'package-name': 'example' }, + {}, + ), + ).not.toThrow(); + }); +}); diff --git a/tools/release/release-please-pr-lifecycle.mjs b/tools/release/release-please-pr-lifecycle.mjs deleted file mode 100644 index 5ff936ed8..000000000 --- a/tools/release/release-please-pr-lifecycle.mjs +++ /dev/null @@ -1,541 +0,0 @@ -#!/usr/bin/env bun -import path from "node:path"; -import process from "node:process"; -import { fileURLToPath } from "node:url"; - -import { - createGitHubOperationBudget, - githubJsonReadSync, - remainingGitHubReadOptions, - reconcileGitHubMutationSync, - runGitHubMutationSync, -} from "./github-release-mutations.mjs"; -import { runGitHubPaginatedJsonSync } from "./github-read.mjs"; - -const TOOL = "release-please-pr-lifecycle.mjs"; -const FULL_SHA = /^[0-9a-f]{40}$/u; -const PENDING_LABEL = "autorelease: pending"; -const TAGGED_LABEL = "autorelease: tagged"; -const RELEASE_BRANCH = "release-please--branches--main"; -const RELEASE_TITLE = "chore(release): prepare main releases"; -export const RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS = 45_000; -export const RELEASE_PLEASE_MARK_TAGGED_WINDOW_MS = 4 * 60_000; -export const RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS = 3; -const LIFECYCLE_READ_ATTEMPT_TIMEOUT_MS = 15_000; -const LIFECYCLE_MUTATION_ATTEMPT_TIMEOUT_MS = 30_000; - -function lifecycleError(message, options = {}) { - return new Error(`${TOOL}: ${message}`, options); -} - -function requiredRepository(environment) { - const repository = environment.GITHUB_REPOSITORY?.trim() ?? ""; - if ( - !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository) - || repository.split("/").some((part) => part === "." || part === "..") - ) { - throw lifecycleError("GITHUB_REPOSITORY must be a canonical OWNER/NAME"); - } - return repository; -} - -function lifecycleBudget({ - environment, - now = Date.now, - windowMs, -}) { - return createGitHubOperationBudget({ - defaultWindowMs: windowMs, - environment: { - ...environment, - OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: String(windowMs), - }, - now, - }); -} - -function lifecycleReadOptions(budget, overrides = {}) { - return remainingGitHubReadOptions(budget, { - attemptTimeoutMs: LIFECYCLE_READ_ATTEMPT_TIMEOUT_MS, - baseDelayMs: 500, - maxAttempts: 3, - maxDelayMs: 2_000, - ...overrides, - }); -} - -function requireBase(base) { - if (base !== "main") { - throw lifecycleError(`the Release Please lifecycle base must be main, got ${JSON.stringify(base)}`); - } - return base; -} - -function object(value, context) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw lifecycleError(`${context} must be an object`); - } - return value; -} - -function pullRequestLabels(pullRequest, context) { - object(pullRequest, context); - if (!Array.isArray(pullRequest.labels)) { - throw lifecycleError(`${context}.labels must be an array`); - } - const labels = pullRequest.labels.map((entry, index) => { - object(entry, `${context}.labels[${index}]`); - if ( - typeof entry.name !== "string" - || entry.name.length === 0 - || /[\u0000-\u001f\u007f]/u.test(entry.name) - ) { - throw lifecycleError(`${context}.labels[${index}].name must be a non-empty printable string`); - } - return entry.name; - }); - if (new Set(labels).size !== labels.length) { - throw lifecycleError(`${context}.labels contains duplicate names`); - } - return labels; -} - -function sameRepositoryPullRequest(pullRequest, repository, base) { - return pullRequest?.base?.ref === base - && pullRequest?.base?.repo?.full_name === repository - && pullRequest?.head?.repo?.full_name === repository; -} - -export function mergedPendingReleasePullRequests(pullRequests, { - base = "main", - repository, -} = {}) { - requireBase(base); - if (!Array.isArray(pullRequests)) { - throw lifecycleError("closed pull request response must be an array"); - } - const blockers = []; - for (const [index, pullRequest] of pullRequests.entries()) { - const context = `closed pull request response[${index}]`; - object(pullRequest, context); - const labels = pullRequestLabels(pullRequest, context); - if ( - pullRequest.merged_at === null - || pullRequest.merged_at === undefined - || !sameRepositoryPullRequest(pullRequest, repository, base) - || !labels.includes(PENDING_LABEL) - ) { - continue; - } - if ( - !Number.isSafeInteger(pullRequest.number) - || pullRequest.number <= 0 - || typeof pullRequest.html_url !== "string" - || pullRequest.html_url.length === 0 - ) { - throw lifecycleError(`${context} has malformed blocker identity`); - } - blockers.push({ number: pullRequest.number, url: pullRequest.html_url }); - } - return blockers.sort((left, right) => left.number - right.number); -} - -export function releasePleaseClosedPullRequestQuery(repository, base = "main") { - requireBase(base); - const [owner] = requiredRepository({ GITHUB_REPOSITORY: repository }).split("/"); - return new URLSearchParams({ - base, - direction: "desc", - head: `${owner}:${RELEASE_BRANCH}`, - sort: "updated", - state: "closed", - }); -} - -export function assertCleanReleasePleaseState({ - base = "main", - environment = process.env, - listPullRequests, -} = {}) { - requireBase(base); - const repository = requiredRepository(environment); - const list = listPullRequests ?? (() => { - const query = releasePleaseClosedPullRequestQuery(repository, base); - return runGitHubPaginatedJsonSync( - `repos/${repository}/pulls?${query.toString()}`, - { - attemptTimeoutMs: LIFECYCLE_READ_ATTEMPT_TIMEOUT_MS, - baseDelayMs: 500, - deadlineMs: RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS, - environment, - itemsField: null, - label: "merged Release Please lifecycle preflight", - maxAttempts: 3, - maxDelayMs: 2_000, - }, - ); - }); - const blockers = mergedPendingReleasePullRequests(list(), { base, repository }); - if (blockers.length > 0) { - throw lifecycleError( - "merged main Release Please PRs still have autorelease: pending: " - + blockers.map(({ number, url }) => `#${number} ${url}`).join(", ") - + "; finish publication before preparing another release", - ); - } - return { base, blockers: [], repository }; -} - -function exactReleasePullRequestIdentity(pullRequest, { - base, - number, - releaseSha, - repository, -} = {}) { - object(pullRequest, "associated release pull request"); - return pullRequest.merge_commit_sha === releaseSha - && pullRequest.merged_at !== null - && pullRequest.merged_at !== undefined - && pullRequest.state === "closed" - && sameRepositoryPullRequest(pullRequest, repository, base) - && pullRequest.head.ref === RELEASE_BRANCH - && pullRequest.title === RELEASE_TITLE - && (number === undefined || pullRequest.number === number); -} - -export function selectExactReleasePullRequest(pullRequests, { - base = "main", - releaseSha, - repository, -} = {}) { - requireBase(base); - if (!FULL_SHA.test(releaseSha ?? "")) { - throw lifecycleError("release SHA must be a full lowercase commit SHA"); - } - if (!Array.isArray(pullRequests)) { - throw lifecycleError("associated pull request response must be an array"); - } - const matches = pullRequests.filter((pullRequest) => - exactReleasePullRequestIdentity(pullRequest, { base, releaseSha, repository })); - if (matches.length !== 1) { - throw lifecycleError( - `release commit ${releaseSha} must have exactly one canonical merged Release Please PR; found ${matches.length}`, - ); - } - const [pullRequest] = matches; - if (!Number.isSafeInteger(pullRequest.number) || pullRequest.number <= 0) { - throw lifecycleError("associated release pull request number must be a positive integer"); - } - return pullRequest; -} - -export function releasePleaseLabelState(pullRequest, expectedIdentity) { - if (!exactReleasePullRequestIdentity(pullRequest, expectedIdentity)) { - return { detail: "the exact merged Release Please PR identity changed", kind: "conflict" }; - } - const labels = pullRequestLabels(pullRequest, `pull request #${pullRequest.number}`); - const pending = labels.includes(PENDING_LABEL); - const tagged = labels.includes(TAGGED_LABEL); - if (!pending && tagged) { - return { kind: "desired", labels }; - } - if (!pending && !tagged) { - return { - detail: `pull request #${pullRequest.number} has neither ${PENDING_LABEL} nor ${TAGGED_LABEL}`, - kind: "conflict", - }; - } - return { kind: "unchanged", labels }; -} - -function assertMarkableState(state, number) { - if (state.kind === "conflict") { - throw lifecycleError(state.detail); - } - if (state.kind !== "desired" && state.kind !== "unchanged") { - throw lifecycleError(`pull request #${number} returned an invalid lifecycle state`); - } - return state; -} - -function assertTaggedRepositoryLabel(label) { - object(label, `repository label ${TAGGED_LABEL}`); - if (label.name !== TAGGED_LABEL) { - throw lifecycleError(`repository label ${TAGGED_LABEL} returned malformed metadata`); - } - return label; -} - -function resolveExactReleasePleasePullRequest({ - base, - budget, - environment, - listAssociatedPullRequests, - readPullRequest, - readTaggedLabel, - releaseSha, -}) { - const repository = requiredRepository(environment); - const list = listAssociatedPullRequests ?? (() => - runGitHubPaginatedJsonSync( - `repos/${repository}/commits/${releaseSha}/pulls`, - { - ...lifecycleReadOptions(budget), - itemsField: null, - label: `pull requests associated with release ${releaseSha}`, - }, - )); - const selected = selectExactReleasePullRequest(list(), { - base, - releaseSha, - repository, - }); - const expectedIdentity = { base, number: selected.number, releaseSha, repository }; - const read = readPullRequest ?? (() => - githubJsonReadSync( - ["api", `repos/${repository}/pulls/${selected.number}`], - { - ...lifecycleReadOptions(budget), - label: `release pull request #${selected.number}`, - }, - )); - const current = read(); - const state = assertMarkableState( - releasePleaseLabelState(current, expectedIdentity), - selected.number, - ); - const readLabel = readTaggedLabel ?? (() => - githubJsonReadSync( - ["api", `repos/${repository}/labels/${encodeURIComponent(TAGGED_LABEL)}`], - { - ...lifecycleReadOptions(budget), - label: `repository label ${TAGGED_LABEL}`, - }, - )); - assertTaggedRepositoryLabel(readLabel()); - return { - current, - expectedIdentity, - number: selected.number, - read, - repository, - state, - }; -} - -export function assertExactReleasePleasePullRequestMarkable({ - base = "main", - environment = process.env, - listAssociatedPullRequests, - now = Date.now, - readPullRequest, - readTaggedLabel, - releaseSha, -} = {}) { - requireBase(base); - if (!FULL_SHA.test(releaseSha ?? "")) { - throw lifecycleError("release SHA must be a full lowercase commit SHA"); - } - const budget = lifecycleBudget({ - environment, - now, - windowMs: RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS, - }); - const resolved = resolveExactReleasePleasePullRequest({ - base, - budget, - environment: budget.environment, - listAssociatedPullRequests, - readPullRequest, - readTaggedLabel, - releaseSha, - }); - return { - number: resolved.number, - repository: resolved.repository, - state: resolved.state.kind, - }; -} - -function ensureTaggedState(pullRequest, expectedIdentity) { - const state = releasePleaseLabelState(pullRequest, expectedIdentity); - if (state.kind === "conflict") return state; - return { - kind: state.labels.includes(TAGGED_LABEL) ? "desired" : "unchanged", - }; -} - -function ensurePendingRemovedState(pullRequest, expectedIdentity) { - const state = releasePleaseLabelState(pullRequest, expectedIdentity); - if (state.kind === "conflict") return state; - const pending = state.labels.includes(PENDING_LABEL); - const tagged = state.labels.includes(TAGGED_LABEL); - if (!tagged) { - return { - detail: `pull request #${pullRequest.number} lost ${TAGGED_LABEL} before pending-label removal`, - kind: "conflict", - }; - } - return { kind: pending ? "unchanged" : "desired" }; -} - -export function markExactReleasePleasePullRequestTagged({ - addTaggedLabel, - base = "main", - environment = process.env, - listAssociatedPullRequests, - now = Date.now, - readTaggedLabel, - removePendingLabel, - readPullRequest, - releaseSha, - reconciliationOptions = {}, -} = {}) { - requireBase(base); - if (!FULL_SHA.test(releaseSha ?? "")) { - throw lifecycleError("release SHA must be a full lowercase commit SHA"); - } - const budget = reconciliationOptions.budget ?? lifecycleBudget({ - environment, - now, - windowMs: RELEASE_PLEASE_MARK_TAGGED_WINDOW_MS, - }); - const operationEnvironment = budget.environment ?? environment; - const resolved = resolveExactReleasePleasePullRequest({ - base, - budget, - environment: operationEnvironment, - listAssociatedPullRequests, - readPullRequest, - readTaggedLabel, - releaseSha, - }); - const reconciliation = { - ...reconciliationOptions, - attemptTimeoutMs: Math.min( - reconciliationOptions.attemptTimeoutMs ?? LIFECYCLE_MUTATION_ATTEMPT_TIMEOUT_MS, - LIFECYCLE_MUTATION_ATTEMPT_TIMEOUT_MS, - ), - budget, - environment: operationEnvironment, - maxAttempts: Math.min( - reconciliationOptions.maxAttempts - ?? RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS, - RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS, - ), - }; - const taggedResult = reconcileGitHubMutationSync({ - inspect: () => ensureTaggedState(resolved.read(), resolved.expectedIdentity), - label: `add ${TAGGED_LABEL} to Release Please PR #${resolved.number}`, - mutate: ({ deadlineMs, timeoutMs }) => { - const input = `${JSON.stringify({ labels: [TAGGED_LABEL] })}\n`; - if (addTaggedLabel !== undefined) { - addTaggedLabel({ deadlineMs, input, number: resolved.number, timeoutMs }); - return; - } - runGitHubMutationSync( - [ - "api", - `repos/${resolved.repository}/issues/${resolved.number}/labels`, - "-X", - "POST", - "--input", - "-", - ], - { - deadlineMs, - environment: operationEnvironment, - input, - pacerLabel: `add ${TAGGED_LABEL} to Release Please PR #${resolved.number}`, - timeoutMs, - }, - ); - }, - options: reconciliation, - }); - const pendingResult = reconcileGitHubMutationSync({ - inspect: () => ensurePendingRemovedState(resolved.read(), resolved.expectedIdentity), - label: `remove ${PENDING_LABEL} from Release Please PR #${resolved.number}`, - mutate: ({ deadlineMs, timeoutMs }) => { - if (removePendingLabel !== undefined) { - removePendingLabel({ deadlineMs, number: resolved.number, timeoutMs }); - return; - } - runGitHubMutationSync( - [ - "api", - `repos/${resolved.repository}/issues/${resolved.number}/labels/${encodeURIComponent(PENDING_LABEL)}`, - "-X", - "DELETE", - ], - { - deadlineMs, - environment: operationEnvironment, - pacerLabel: `remove ${PENDING_LABEL} from Release Please PR #${resolved.number}`, - timeoutMs, - }, - ); - }, - options: reconciliation, - }); - return { - mutationAttempts: taggedResult.mutationAttempts + pendingResult.mutationAttempts, - number: resolved.number, - recovered: taggedResult.recovered || pendingResult.recovered, - repository: resolved.repository, - }; -} - -function usage() { - return `${TOOL}: usage: ${TOOL} assert-clean --base main | ` - + `${TOOL} assert-markable --release-sha --base main | ` - + `${TOOL} mark-tagged --release-sha --base main`; -} - -function parseCli(args) { - const [operation, ...rest] = args; - if (operation === "assert-clean" && rest.length === 2 && rest[0] === "--base") { - return { base: rest[1], operation }; - } - if ( - (operation === "assert-markable" || operation === "mark-tagged") - && rest.length === 4 - && rest[0] === "--release-sha" - && rest[2] === "--base" - ) { - return { base: rest[3], operation, releaseSha: rest[1] }; - } - throw lifecycleError(usage()); -} - -function main() { - const options = parseCli(process.argv.slice(2)); - if (options.operation === "assert-clean") { - const result = assertCleanReleasePleaseState(options); - console.log(`Release Please lifecycle is clear for ${result.repository}:${result.base}`); - return; - } - if (options.operation === "assert-markable") { - const result = assertExactReleasePleasePullRequestMarkable(options); - console.log( - `Release Please PR #${result.number} is markable for ${result.repository} ` - + `(state: ${result.state})`, - ); - return; - } - const result = markExactReleasePleasePullRequestTagged(options); - console.log( - `Release Please PR #${result.number} is tagged and no longer pending ` - + `(mutation attempts: ${result.mutationAttempts})`, - ); -} - -const invokedPath = process.argv[1] === undefined ? "" : path.resolve(process.argv[1]); -if (invokedPath === fileURLToPath(import.meta.url)) { - try { - main(); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/release-please-pr-lifecycle.mts b/tools/release/release-please-pr-lifecycle.mts new file mode 100644 index 000000000..b97388052 --- /dev/null +++ b/tools/release/release-please-pr-lifecycle.mts @@ -0,0 +1,526 @@ +#!/usr/bin/env bun +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import { requestGithubPages, requestGithubRepositoryJson } from './github-read.mts'; +import { + createGitHubOperationBudget, + reconcileGitHubMutation, + remainingGitHubReadOptions, + requestGithubMutation, +} from './github-release-mutations.mts'; + +const TOOL = 'release-please-pr-lifecycle.mts'; +const FULL_SHA = /^[0-9a-f]{40}$/u; +const PENDING_LABEL = 'autorelease: pending'; +const TAGGED_LABEL = 'autorelease: tagged'; +const RELEASE_BRANCH = 'release-please--branches--main'; +const RELEASE_TITLE = 'chore(release): prepare main releases'; +export const RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS = 45_000; +export const RELEASE_PLEASE_MARK_TAGGED_WINDOW_MS = 4 * 60_000; +export const RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS = 3; +const LIFECYCLE_READ_ATTEMPT_TIMEOUT_MS = 15_000; +const LIFECYCLE_MUTATION_ATTEMPT_TIMEOUT_MS = 30_000; + +function lifecycleError(message, options = {}) { + return new Error(`${TOOL}: ${message}`, options); +} + +function requiredRepository(environment) { + const repository = environment.GITHUB_REPOSITORY?.trim() ?? ''; + if ( + !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repository) || + repository.split('/').some((part) => part === '.' || part === '..') + ) { + throw lifecycleError('GITHUB_REPOSITORY must be a canonical OWNER/NAME'); + } + return repository; +} + +function lifecycleBudget({ environment, now = Date.now, windowMs }) { + return createGitHubOperationBudget({ + defaultWindowMs: windowMs, + environment: { + ...environment, + OLIPHAUNT_GITHUB_MUTATION_WINDOW_MS: String(windowMs), + }, + now, + }); +} + +function lifecycleReadOptions(budget, overrides = {}) { + return remainingGitHubReadOptions(budget, { + attemptTimeoutMs: LIFECYCLE_READ_ATTEMPT_TIMEOUT_MS, + baseDelayMs: 500, + maxAttempts: 3, + maxDelayMs: 2_000, + ...overrides, + }); +} + +function requireBase(base) { + if (base !== 'main') { + throw lifecycleError( + `the Release Please lifecycle base must be main, got ${JSON.stringify(base)}`, + ); + } + return base; +} + +function object(value, context) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw lifecycleError(`${context} must be an object`); + } + return value; +} + +function pullRequestLabels(pullRequest, context) { + object(pullRequest, context); + if (!Array.isArray(pullRequest.labels)) { + throw lifecycleError(`${context}.labels must be an array`); + } + const labels = pullRequest.labels.map((entry, index) => { + object(entry, `${context}.labels[${index}]`); + if ( + typeof entry.name !== 'string' || + entry.name.length === 0 || + /[\u0000-\u001f\u007f]/u.test(entry.name) + ) { + throw lifecycleError(`${context}.labels[${index}].name must be a non-empty printable string`); + } + return entry.name; + }); + if (new Set(labels).size !== labels.length) { + throw lifecycleError(`${context}.labels contains duplicate names`); + } + return labels; +} + +function sameRepositoryPullRequest(pullRequest, repository, base) { + return ( + pullRequest?.base?.ref === base && + pullRequest?.base?.repo?.full_name === repository && + pullRequest?.head?.repo?.full_name === repository + ); +} + +export function mergedPendingReleasePullRequests(pullRequests, { base = 'main', repository } = {}) { + requireBase(base); + if (!Array.isArray(pullRequests)) { + throw lifecycleError('closed pull request response must be an array'); + } + const blockers = []; + for (const [index, pullRequest] of pullRequests.entries()) { + const context = `closed pull request response[${index}]`; + object(pullRequest, context); + const labels = pullRequestLabels(pullRequest, context); + if ( + pullRequest.merged_at === null || + pullRequest.merged_at === undefined || + !sameRepositoryPullRequest(pullRequest, repository, base) || + !labels.includes(PENDING_LABEL) + ) { + continue; + } + if ( + !Number.isSafeInteger(pullRequest.number) || + pullRequest.number <= 0 || + typeof pullRequest.html_url !== 'string' || + pullRequest.html_url.length === 0 + ) { + throw lifecycleError(`${context} has malformed blocker identity`); + } + blockers.push({ number: pullRequest.number, url: pullRequest.html_url }); + } + return blockers.sort((left, right) => left.number - right.number); +} + +export function releasePleaseClosedPullRequestQuery(repository, base = 'main') { + requireBase(base); + const [owner] = requiredRepository({ GITHUB_REPOSITORY: repository }).split('/'); + return new URLSearchParams({ + base, + direction: 'desc', + head: `${owner}:${RELEASE_BRANCH}`, + sort: 'updated', + state: 'closed', + }); +} + +export async function assertCleanReleasePleaseState({ + base = 'main', + environment = process.env, + listPullRequests, +} = {}) { + requireBase(base); + const repository = requiredRepository(environment); + const list = + listPullRequests ?? + (async () => { + const query = releasePleaseClosedPullRequestQuery(repository, base); + return await requestGithubPages(`repos/${repository}/pulls?${query.toString()}`, { + attemptTimeoutMs: LIFECYCLE_READ_ATTEMPT_TIMEOUT_MS, + baseDelayMs: 500, + deadlineMs: RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS, + environment, + itemsField: null, + label: 'merged Release Please lifecycle preflight', + maxAttempts: 3, + maxDelayMs: 2_000, + }); + }); + const blockers = mergedPendingReleasePullRequests(await list(), { base, repository }); + if (blockers.length > 0) { + throw lifecycleError( + 'merged main Release Please PRs still have autorelease: pending: ' + + blockers.map(({ number, url }) => `#${number} ${url}`).join(', ') + + '; finish publication before preparing another release', + ); + } + return { base, blockers: [], repository }; +} + +function exactReleasePullRequestIdentity( + pullRequest, + { base, number, releaseSha, repository } = {}, +) { + object(pullRequest, 'associated release pull request'); + return ( + pullRequest.merge_commit_sha === releaseSha && + pullRequest.merged_at !== null && + pullRequest.merged_at !== undefined && + pullRequest.state === 'closed' && + sameRepositoryPullRequest(pullRequest, repository, base) && + pullRequest.head.ref === RELEASE_BRANCH && + pullRequest.title === RELEASE_TITLE && + (number === undefined || pullRequest.number === number) + ); +} + +export function selectExactReleasePullRequest( + pullRequests, + { base = 'main', releaseSha, repository } = {}, +) { + requireBase(base); + if (!FULL_SHA.test(releaseSha ?? '')) { + throw lifecycleError('release SHA must be a full lowercase commit SHA'); + } + if (!Array.isArray(pullRequests)) { + throw lifecycleError('associated pull request response must be an array'); + } + const matches = pullRequests.filter((pullRequest) => + exactReleasePullRequestIdentity(pullRequest, { base, releaseSha, repository }), + ); + if (matches.length !== 1) { + throw lifecycleError( + `release commit ${releaseSha} must have exactly one canonical merged Release Please PR; found ${matches.length}`, + ); + } + const [pullRequest] = matches; + if (!Number.isSafeInteger(pullRequest.number) || pullRequest.number <= 0) { + throw lifecycleError('associated release pull request number must be a positive integer'); + } + return pullRequest; +} + +export function releasePleaseLabelState(pullRequest, expectedIdentity) { + if (!exactReleasePullRequestIdentity(pullRequest, expectedIdentity)) { + return { detail: 'the exact merged Release Please PR identity changed', kind: 'conflict' }; + } + const labels = pullRequestLabels(pullRequest, `pull request #${pullRequest.number}`); + const pending = labels.includes(PENDING_LABEL); + const tagged = labels.includes(TAGGED_LABEL); + if (!pending && tagged) { + return { kind: 'desired', labels }; + } + if (!pending && !tagged) { + return { + detail: `pull request #${pullRequest.number} has neither ${PENDING_LABEL} nor ${TAGGED_LABEL}`, + kind: 'conflict', + }; + } + return { kind: 'unchanged', labels }; +} + +function assertMarkableState(state, number) { + if (state.kind === 'conflict') { + throw lifecycleError(state.detail); + } + if (state.kind !== 'desired' && state.kind !== 'unchanged') { + throw lifecycleError(`pull request #${number} returned an invalid lifecycle state`); + } + return state; +} + +function assertTaggedRepositoryLabel(label) { + object(label, `repository label ${TAGGED_LABEL}`); + if (label.name !== TAGGED_LABEL) { + throw lifecycleError(`repository label ${TAGGED_LABEL} returned malformed metadata`); + } + return label; +} + +async function resolveExactReleasePleasePullRequest({ + base, + budget, + environment, + listAssociatedPullRequests, + readPullRequest, + readTaggedLabel, + releaseSha, +}) { + const repository = requiredRepository(environment); + const list = + listAssociatedPullRequests ?? + (async () => + await requestGithubPages(`repos/${repository}/commits/${releaseSha}/pulls`, { + ...lifecycleReadOptions(budget), + itemsField: null, + label: `pull requests associated with release ${releaseSha}`, + })); + const selected = selectExactReleasePullRequest(await list(), { + base, + releaseSha, + repository, + }); + const expectedIdentity = { base, number: selected.number, releaseSha, repository }; + const read = + readPullRequest ?? + (async () => + await requestGithubRepositoryJson(`repos/${repository}/pulls/${selected.number}`, { + ...lifecycleReadOptions(budget), + label: `release pull request #${selected.number}`, + })); + const current = await read(); + const state = assertMarkableState( + releasePleaseLabelState(current, expectedIdentity), + selected.number, + ); + const readLabel = + readTaggedLabel ?? + (async () => + await requestGithubRepositoryJson( + `repos/${repository}/labels/${encodeURIComponent(TAGGED_LABEL)}`, + { + ...lifecycleReadOptions(budget), + label: `repository label ${TAGGED_LABEL}`, + }, + )); + assertTaggedRepositoryLabel(await readLabel()); + return { + current, + expectedIdentity, + number: selected.number, + read, + repository, + state, + }; +} + +export async function assertExactReleasePleasePullRequestMarkable({ + base = 'main', + environment = process.env, + listAssociatedPullRequests, + now = Date.now, + readPullRequest, + readTaggedLabel, + releaseSha, +} = {}) { + requireBase(base); + if (!FULL_SHA.test(releaseSha ?? '')) { + throw lifecycleError('release SHA must be a full lowercase commit SHA'); + } + const budget = lifecycleBudget({ + environment, + now, + windowMs: RELEASE_PLEASE_ASSERT_MARKABLE_WINDOW_MS, + }); + const resolved = await resolveExactReleasePleasePullRequest({ + base, + budget, + environment: budget.environment, + listAssociatedPullRequests, + readPullRequest, + readTaggedLabel, + releaseSha, + }); + return { + number: resolved.number, + repository: resolved.repository, + state: resolved.state.kind, + }; +} + +function ensureTaggedState(pullRequest, expectedIdentity) { + const state = releasePleaseLabelState(pullRequest, expectedIdentity); + if (state.kind === 'conflict') return state; + return { + kind: state.labels.includes(TAGGED_LABEL) ? 'desired' : 'unchanged', + }; +} + +function ensurePendingRemovedState(pullRequest, expectedIdentity) { + const state = releasePleaseLabelState(pullRequest, expectedIdentity); + if (state.kind === 'conflict') return state; + const pending = state.labels.includes(PENDING_LABEL); + const tagged = state.labels.includes(TAGGED_LABEL); + if (!tagged) { + return { + detail: `pull request #${pullRequest.number} lost ${TAGGED_LABEL} before pending-label removal`, + kind: 'conflict', + }; + } + return { kind: pending ? 'unchanged' : 'desired' }; +} + +export async function markExactReleasePleasePullRequestTagged({ + addTaggedLabel, + base = 'main', + environment = process.env, + listAssociatedPullRequests, + now = Date.now, + readTaggedLabel, + removePendingLabel, + readPullRequest, + releaseSha, + reconciliationOptions = {}, +} = {}) { + requireBase(base); + if (!FULL_SHA.test(releaseSha ?? '')) { + throw lifecycleError('release SHA must be a full lowercase commit SHA'); + } + const budget = + reconciliationOptions.budget ?? + lifecycleBudget({ + environment, + now, + windowMs: RELEASE_PLEASE_MARK_TAGGED_WINDOW_MS, + }); + const operationEnvironment = budget.environment ?? environment; + const resolved = await resolveExactReleasePleasePullRequest({ + base, + budget, + environment: operationEnvironment, + listAssociatedPullRequests, + readPullRequest, + readTaggedLabel, + releaseSha, + }); + const reconciliation = { + ...reconciliationOptions, + attemptTimeoutMs: Math.min( + reconciliationOptions.attemptTimeoutMs ?? LIFECYCLE_MUTATION_ATTEMPT_TIMEOUT_MS, + LIFECYCLE_MUTATION_ATTEMPT_TIMEOUT_MS, + ), + budget, + environment: operationEnvironment, + maxAttempts: Math.min( + reconciliationOptions.maxAttempts ?? RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS, + RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS, + ), + }; + const taggedResult = await reconcileGitHubMutation({ + inspect: async () => ensureTaggedState(await resolved.read(), resolved.expectedIdentity), + label: `add ${TAGGED_LABEL} to Release Please PR #${resolved.number}`, + mutate: async ({ deadlineMs, timeoutMs }) => { + const input = `${JSON.stringify({ labels: [TAGGED_LABEL] })}\n`; + if (addTaggedLabel !== undefined) { + await addTaggedLabel({ deadlineMs, input, number: resolved.number, timeoutMs }); + return; + } + await requestGithubMutation(`repos/${resolved.repository}/issues/${resolved.number}/labels`, { + method: 'POST', + deadlineMs, + environment: operationEnvironment, + input, + pacerLabel: `add ${TAGGED_LABEL} to Release Please PR #${resolved.number}`, + timeoutMs, + }); + }, + options: reconciliation, + }); + const pendingResult = await reconcileGitHubMutation({ + inspect: async () => + ensurePendingRemovedState(await resolved.read(), resolved.expectedIdentity), + label: `remove ${PENDING_LABEL} from Release Please PR #${resolved.number}`, + mutate: async ({ deadlineMs, timeoutMs }) => { + if (removePendingLabel !== undefined) { + await removePendingLabel({ deadlineMs, number: resolved.number, timeoutMs }); + return; + } + await requestGithubMutation( + `repos/${resolved.repository}/issues/${resolved.number}/labels/${encodeURIComponent(PENDING_LABEL)}`, + { + method: 'DELETE', + deadlineMs, + environment: operationEnvironment, + pacerLabel: `remove ${PENDING_LABEL} from Release Please PR #${resolved.number}`, + timeoutMs, + }, + ); + }, + options: reconciliation, + }); + return { + mutationAttempts: taggedResult.mutationAttempts + pendingResult.mutationAttempts, + number: resolved.number, + recovered: taggedResult.recovered || pendingResult.recovered, + repository: resolved.repository, + }; +} + +function usage() { + return ( + `${TOOL}: usage: ${TOOL} assert-clean --base main | ` + + `${TOOL} assert-markable --release-sha --base main | ` + + `${TOOL} mark-tagged --release-sha --base main` + ); +} + +function parseCli(args) { + const [operation, ...rest] = args; + if (operation === 'assert-clean' && rest.length === 2 && rest[0] === '--base') { + return { base: rest[1], operation }; + } + if ( + (operation === 'assert-markable' || operation === 'mark-tagged') && + rest.length === 4 && + rest[0] === '--release-sha' && + rest[2] === '--base' + ) { + return { base: rest[3], operation, releaseSha: rest[1] }; + } + throw lifecycleError(usage()); +} + +async function main() { + const options = parseCli(process.argv.slice(2)); + if (options.operation === 'assert-clean') { + const result = await assertCleanReleasePleaseState(options); + console.log(`Release Please lifecycle is clear for ${result.repository}:${result.base}`); + return; + } + if (options.operation === 'assert-markable') { + const result = await assertExactReleasePleasePullRequestMarkable(options); + console.log( + `Release Please PR #${result.number} is markable for ${result.repository} ` + + `(state: ${result.state})`, + ); + return; + } + const result = await markExactReleasePleasePullRequestTagged(options); + console.log( + `Release Please PR #${result.number} is tagged and no longer pending ` + + `(mutation attempts: ${result.mutationAttempts})`, + ); +} + +const invokedPath = process.argv[1] === undefined ? '' : path.resolve(process.argv[1]); +if (invokedPath === fileURLToPath(import.meta.url)) { + try { + await main(); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/release-please-pr-lifecycle.test.mjs b/tools/release/release-please-pr-lifecycle.test.mjs deleted file mode 100644 index 04961829a..000000000 --- a/tools/release/release-please-pr-lifecycle.test.mjs +++ /dev/null @@ -1,339 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - assertCleanReleasePleaseState, - assertExactReleasePleasePullRequestMarkable, - markExactReleasePleasePullRequestTagged, - mergedPendingReleasePullRequests, - RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS, - releasePleaseClosedPullRequestQuery, - releasePleaseLabelState, - selectExactReleasePullRequest, -} from "./release-please-pr-lifecycle.mjs"; - -const REPOSITORY = "f0rr0/oliphaunt"; -const RELEASE_SHA = "a".repeat(40); -const ENVIRONMENT = { GITHUB_REPOSITORY: REPOSITORY }; - -function labels(...names) { - return names.map((name) => ({ name })); -} - -function pullRequest(overrides = {}) { - return { - base: { ref: "main", repo: { full_name: REPOSITORY } }, - head: { - ref: "release-please--branches--main", - repo: { full_name: REPOSITORY }, - }, - html_url: "https://github.com/f0rr0/oliphaunt/pull/99", - labels: labels("autorelease: pending"), - merge_commit_sha: RELEASE_SHA, - merged_at: "2026-07-28T00:00:00Z", - number: 99, - state: "closed", - title: "chore(release): prepare main releases", - ...overrides, - }; -} - -function taggedRepositoryLabel() { - return { name: "autorelease: tagged" }; -} - -function reconciliationOptions() { - return { - baseDelayMs: 0, - budget: { deadlineMs: 100_000, environment: ENVIRONMENT, now: () => 0, startedAtMs: 0 }, - maxAttempts: 2, - sleep: () => {}, - }; -} - -test("merged pending preflight uses exact current REST state", () => { - const blocker = pullRequest(); - assert.deepEqual( - mergedPendingReleasePullRequests([blocker], { base: "main", repository: REPOSITORY }), - [{ number: 99, url: blocker.html_url }], - ); - assert.throws( - () => assertCleanReleasePleaseState({ - base: "main", - environment: ENVIRONMENT, - listPullRequests: () => [blocker], - }), - /autorelease: pending: #99/u, - ); -}); - -test("preflight narrows exact REST pagination to the canonical Release Please head", () => { - const query = releasePleaseClosedPullRequestQuery(REPOSITORY); - assert.equal(query.get("base"), "main"); - assert.equal(query.get("head"), "f0rr0:release-please--branches--main"); - assert.equal(query.get("state"), "closed"); - assert.equal(query.has("labels"), false); -}); - -test("preflight ignores unmerged, other-base, cross-repository, and cleared PRs", () => { - const cases = [ - pullRequest({ merged_at: null }), - pullRequest({ base: { ref: "next", repo: { full_name: REPOSITORY } } }), - pullRequest({ head: { ref: "release-please--branches--main", repo: { full_name: "fork/repo" } } }), - pullRequest({ labels: [] }), - ]; - assert.deepEqual( - mergedPendingReleasePullRequests(cases, { base: "main", repository: REPOSITORY }), - [], - ); - assert.deepEqual( - assertCleanReleasePleaseState({ - base: "main", - environment: ENVIRONMENT, - listPullRequests: () => cases, - }), - { base: "main", blockers: [], repository: REPOSITORY }, - ); -}); - -test("preflight rejects malformed and duplicate label state", () => { - for (const candidate of [ - pullRequest({ labels: null }), - pullRequest({ labels: labels("autorelease: pending", "autorelease: pending") }), - pullRequest({ labels: [{ name: "bad\nlabel" }] }), - ]) { - assert.throws( - () => mergedPendingReleasePullRequests([candidate], { base: "main", repository: REPOSITORY }), - /labels/u, - ); - } -}); - -test("selects only one exact merged same-repository release PR", () => { - const selected = selectExactReleasePullRequest([pullRequest()], { - base: "main", - releaseSha: RELEASE_SHA, - repository: REPOSITORY, - }); - assert.equal(selected.number, 99); - for (const changed of [ - { merge_commit_sha: "b".repeat(40) }, - { merged_at: null }, - { state: "open" }, - { base: { ref: "next", repo: { full_name: REPOSITORY } } }, - { head: { ref: "other", repo: { full_name: REPOSITORY } } }, - { head: { ref: "release-please--branches--main", repo: { full_name: "fork/repo" } } }, - { title: "chore: unrelated" }, - ]) { - assert.throws( - () => selectExactReleasePullRequest([pullRequest(changed)], { - base: "main", - releaseSha: RELEASE_SHA, - repository: REPOSITORY, - }), - /exactly one/u, - ); - } - assert.throws( - () => selectExactReleasePullRequest([pullRequest(), pullRequest({ number: 100 })], { - base: "main", - releaseSha: RELEASE_SHA, - repository: REPOSITORY, - }), - /found 2/u, - ); -}); - -test("lifecycle state preserves unrelated labels and converges to tagged only", () => { - const state = releasePleaseLabelState( - pullRequest({ labels: labels("reviewed", "autorelease: pending") }), - { base: "main", releaseSha: RELEASE_SHA, repository: REPOSITORY }, - ); - assert.equal(state.kind, "unchanged"); - assert.deepEqual(state.labels, ["reviewed", "autorelease: pending"]); - assert.deepEqual( - releasePleaseLabelState( - pullRequest({ labels: labels("reviewed", "autorelease: tagged") }), - { base: "main", releaseSha: RELEASE_SHA, repository: REPOSITORY }, - ), - { kind: "desired", labels: ["reviewed", "autorelease: tagged"] }, - ); - assert.equal( - releasePleaseLabelState( - pullRequest({ labels: labels("reviewed") }), - { base: "main", releaseSha: RELEASE_SHA, repository: REPOSITORY }, - ).kind, - "conflict", - ); -}); - -test("assert-markable proves exact identity, current lifecycle state, and tagged-label existence", () => { - const result = assertExactReleasePleasePullRequestMarkable({ - environment: ENVIRONMENT, - listAssociatedPullRequests: () => [pullRequest()], - now: () => 0, - readPullRequest: () => pullRequest(), - readTaggedLabel: taggedRepositoryLabel, - releaseSha: RELEASE_SHA, - }); - assert.deepEqual(result, { - number: 99, - repository: REPOSITORY, - state: "unchanged", - }); - assert.throws( - () => assertExactReleasePleasePullRequestMarkable({ - environment: ENVIRONMENT, - listAssociatedPullRequests: () => [pullRequest()], - now: () => 0, - readPullRequest: () => pullRequest(), - readTaggedLabel: () => ({ name: "other" }), - releaseSha: RELEASE_SHA, - }), - /repository label .* malformed/u, - ); -}); - -test("mark-tagged adds then removes labels without replacing concurrent unrelated labels", () => { - let current = pullRequest({ labels: labels("reviewed", "autorelease: pending") }); - const mutations = []; - const result = markExactReleasePleasePullRequestTagged({ - addTaggedLabel: ({ input, number }) => { - mutations.push({ input, kind: "add", number }); - current = pullRequest({ - labels: labels("reviewed", "urgent", "autorelease: pending", "autorelease: tagged"), - }); - }, - base: "main", - environment: ENVIRONMENT, - listAssociatedPullRequests: () => [current], - readPullRequest: () => current, - readTaggedLabel: taggedRepositoryLabel, - reconciliationOptions: reconciliationOptions(), - releaseSha: RELEASE_SHA, - removePendingLabel: ({ number }) => { - mutations.push({ kind: "remove", number }); - current = pullRequest({ - labels: current.labels.filter(({ name }) => name !== "autorelease: pending"), - }); - }, - }); - assert.deepEqual(result, { - mutationAttempts: 2, - number: 99, - recovered: false, - repository: REPOSITORY, - }); - assert.deepEqual(mutations, [ - { - input: '{"labels":["autorelease: tagged"]}\n', - kind: "add", - number: 99, - }, - { kind: "remove", number: 99 }, - ]); - assert.deepEqual( - current.labels.map(({ name }) => name), - ["reviewed", "urgent", "autorelease: tagged"], - ); - - const rerun = markExactReleasePleasePullRequestTagged({ - addTaggedLabel: () => assert.fail("already-tagged state must not add a label"), - base: "main", - environment: ENVIRONMENT, - listAssociatedPullRequests: () => [current], - readPullRequest: () => current, - readTaggedLabel: taggedRepositoryLabel, - reconciliationOptions: reconciliationOptions(), - releaseSha: RELEASE_SHA, - removePendingLabel: () => assert.fail("already-tagged state must not remove a label"), - }); - assert.equal(rerun.mutationAttempts, 0); -}); - -test("ambiguous mutation success is recovered by exact fresh state", () => { - let current = pullRequest(); - let addCalls = 0; - let removeCalls = 0; - const result = markExactReleasePleasePullRequestTagged({ - addTaggedLabel: () => { - addCalls += 1; - current = pullRequest({ - labels: labels("autorelease: pending", "autorelease: tagged"), - }); - throw new Error("timeout after server accepted the additive label mutation"); - }, - environment: ENVIRONMENT, - listAssociatedPullRequests: () => [current], - readPullRequest: () => current, - readTaggedLabel: taggedRepositoryLabel, - reconciliationOptions: reconciliationOptions(), - releaseSha: RELEASE_SHA, - removePendingLabel: () => { - removeCalls += 1; - current = pullRequest({ labels: labels("autorelease: tagged") }); - }, - }); - assert.equal(addCalls, 1); - assert.equal(removeCalls, 1); - assert.equal(result.recovered, true); -}); - -test("lifecycle mutation retries are capped at the exact admission bound", () => { - let current = pullRequest(); - let addCalls = 0; - let removeCalls = 0; - const result = markExactReleasePleasePullRequestTagged({ - addTaggedLabel: () => { - addCalls += 1; - if (addCalls === RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS) { - current = pullRequest({ - labels: labels("autorelease: pending", "autorelease: tagged"), - }); - } - }, - environment: ENVIRONMENT, - listAssociatedPullRequests: () => [current], - readPullRequest: () => current, - readTaggedLabel: taggedRepositoryLabel, - reconciliationOptions: { - ...reconciliationOptions(), - maxAttempts: RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS + 2, - }, - releaseSha: RELEASE_SHA, - removePendingLabel: () => { - removeCalls += 1; - if (removeCalls === RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS) { - current = pullRequest({ labels: labels("autorelease: tagged") }); - } - }, - }); - assert.equal(addCalls, RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS); - assert.equal(removeCalls, RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS); - assert.equal( - result.mutationAttempts, - 2 * RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS, - ); -}); - -test("missing lifecycle labels and changed exact identity fail closed", () => { - for (const current of [ - pullRequest({ labels: [] }), - pullRequest({ merge_commit_sha: "b".repeat(40) }), - ]) { - assert.throws( - () => markExactReleasePleasePullRequestTagged({ - addTaggedLabel: () => assert.fail("conflicting state must not add a label"), - environment: ENVIRONMENT, - listAssociatedPullRequests: () => [pullRequest()], - readPullRequest: () => current, - readTaggedLabel: taggedRepositoryLabel, - reconciliationOptions: { ...reconciliationOptions(), maxAttempts: 1 }, - releaseSha: RELEASE_SHA, - removePendingLabel: () => assert.fail("conflicting state must not remove a label"), - }), - /neither|identity changed/u, - ); - } -}); diff --git a/tools/release/release-please-pr-lifecycle.test.mts b/tools/release/release-please-pr-lifecycle.test.mts new file mode 100644 index 000000000..5939995a0 --- /dev/null +++ b/tools/release/release-please-pr-lifecycle.test.mts @@ -0,0 +1,345 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + assertCleanReleasePleaseState, + assertExactReleasePleasePullRequestMarkable, + markExactReleasePleasePullRequestTagged, + mergedPendingReleasePullRequests, + RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS, + releasePleaseClosedPullRequestQuery, + releasePleaseLabelState, + selectExactReleasePullRequest, +} from './release-please-pr-lifecycle.mts'; + +const REPOSITORY = 'f0rr0/oliphaunt'; +const RELEASE_SHA = 'a'.repeat(40); +const ENVIRONMENT = { GITHUB_REPOSITORY: REPOSITORY }; + +function labels(...names) { + return names.map((name) => ({ name })); +} + +function pullRequest(overrides = {}) { + return { + base: { ref: 'main', repo: { full_name: REPOSITORY } }, + head: { + ref: 'release-please--branches--main', + repo: { full_name: REPOSITORY }, + }, + html_url: 'https://github.com/f0rr0/oliphaunt/pull/99', + labels: labels('autorelease: pending'), + merge_commit_sha: RELEASE_SHA, + merged_at: '2026-07-28T00:00:00Z', + number: 99, + state: 'closed', + title: 'chore(release): prepare main releases', + ...overrides, + }; +} + +function taggedRepositoryLabel() { + return { name: 'autorelease: tagged' }; +} + +function reconciliationOptions() { + return { + baseDelayMs: 0, + budget: { deadlineMs: 100_000, environment: ENVIRONMENT, now: () => 0, startedAtMs: 0 }, + maxAttempts: 2, + sleep: () => {}, + }; +} + +test('merged pending preflight uses exact current REST state', async () => { + const blocker = pullRequest(); + assert.deepEqual( + mergedPendingReleasePullRequests([blocker], { base: 'main', repository: REPOSITORY }), + [{ number: 99, url: blocker.html_url }], + ); + await assert.rejects( + async () => + await assertCleanReleasePleaseState({ + base: 'main', + environment: ENVIRONMENT, + listPullRequests: () => [blocker], + }), + /autorelease: pending: #99/u, + ); +}); + +test('preflight narrows exact REST pagination to the canonical Release Please head', () => { + const query = releasePleaseClosedPullRequestQuery(REPOSITORY); + assert.equal(query.get('base'), 'main'); + assert.equal(query.get('head'), 'f0rr0:release-please--branches--main'); + assert.equal(query.get('state'), 'closed'); + assert.equal(query.has('labels'), false); +}); + +test('preflight ignores unmerged, other-base, cross-repository, and cleared PRs', async () => { + const cases = [ + pullRequest({ merged_at: null }), + pullRequest({ base: { ref: 'next', repo: { full_name: REPOSITORY } } }), + pullRequest({ + head: { ref: 'release-please--branches--main', repo: { full_name: 'fork/repo' } }, + }), + pullRequest({ labels: [] }), + ]; + assert.deepEqual( + mergedPendingReleasePullRequests(cases, { base: 'main', repository: REPOSITORY }), + [], + ); + assert.deepEqual( + await assertCleanReleasePleaseState({ + base: 'main', + environment: ENVIRONMENT, + listPullRequests: () => cases, + }), + { base: 'main', blockers: [], repository: REPOSITORY }, + ); +}); + +test('preflight rejects malformed and duplicate label state', () => { + for (const candidate of [ + pullRequest({ labels: null }), + pullRequest({ labels: labels('autorelease: pending', 'autorelease: pending') }), + pullRequest({ labels: [{ name: 'bad\nlabel' }] }), + ]) { + assert.throws( + () => mergedPendingReleasePullRequests([candidate], { base: 'main', repository: REPOSITORY }), + /labels/u, + ); + } +}); + +test('selects only one exact merged same-repository release PR', () => { + const selected = selectExactReleasePullRequest([pullRequest()], { + base: 'main', + releaseSha: RELEASE_SHA, + repository: REPOSITORY, + }); + assert.equal(selected.number, 99); + for (const changed of [ + { merge_commit_sha: 'b'.repeat(40) }, + { merged_at: null }, + { state: 'open' }, + { base: { ref: 'next', repo: { full_name: REPOSITORY } } }, + { head: { ref: 'other', repo: { full_name: REPOSITORY } } }, + { head: { ref: 'release-please--branches--main', repo: { full_name: 'fork/repo' } } }, + { title: 'chore: unrelated' }, + ]) { + assert.throws( + () => + selectExactReleasePullRequest([pullRequest(changed)], { + base: 'main', + releaseSha: RELEASE_SHA, + repository: REPOSITORY, + }), + /exactly one/u, + ); + } + assert.throws( + () => + selectExactReleasePullRequest([pullRequest(), pullRequest({ number: 100 })], { + base: 'main', + releaseSha: RELEASE_SHA, + repository: REPOSITORY, + }), + /found 2/u, + ); +}); + +test('lifecycle state preserves unrelated labels and converges to tagged only', () => { + const state = releasePleaseLabelState( + pullRequest({ labels: labels('reviewed', 'autorelease: pending') }), + { base: 'main', releaseSha: RELEASE_SHA, repository: REPOSITORY }, + ); + assert.equal(state.kind, 'unchanged'); + assert.deepEqual(state.labels, ['reviewed', 'autorelease: pending']); + assert.deepEqual( + releasePleaseLabelState(pullRequest({ labels: labels('reviewed', 'autorelease: tagged') }), { + base: 'main', + releaseSha: RELEASE_SHA, + repository: REPOSITORY, + }), + { kind: 'desired', labels: ['reviewed', 'autorelease: tagged'] }, + ); + assert.equal( + releasePleaseLabelState(pullRequest({ labels: labels('reviewed') }), { + base: 'main', + releaseSha: RELEASE_SHA, + repository: REPOSITORY, + }).kind, + 'conflict', + ); +}); + +test('assert-markable proves exact identity, current lifecycle state, and tagged-label existence', async () => { + const result = await assertExactReleasePleasePullRequestMarkable({ + environment: ENVIRONMENT, + listAssociatedPullRequests: () => [pullRequest()], + now: () => 0, + readPullRequest: () => pullRequest(), + readTaggedLabel: taggedRepositoryLabel, + releaseSha: RELEASE_SHA, + }); + assert.deepEqual(result, { + number: 99, + repository: REPOSITORY, + state: 'unchanged', + }); + await assert.rejects( + async () => + await assertExactReleasePleasePullRequestMarkable({ + environment: ENVIRONMENT, + listAssociatedPullRequests: () => [pullRequest()], + now: () => 0, + readPullRequest: () => pullRequest(), + readTaggedLabel: () => ({ name: 'other' }), + releaseSha: RELEASE_SHA, + }), + /repository label .* malformed/u, + ); +}); + +test('mark-tagged adds then removes labels without replacing concurrent unrelated labels', async () => { + let current = pullRequest({ labels: labels('reviewed', 'autorelease: pending') }); + const mutations = []; + const result = await markExactReleasePleasePullRequestTagged({ + addTaggedLabel: ({ input, number }) => { + mutations.push({ input, kind: 'add', number }); + current = pullRequest({ + labels: labels('reviewed', 'urgent', 'autorelease: pending', 'autorelease: tagged'), + }); + }, + base: 'main', + environment: ENVIRONMENT, + listAssociatedPullRequests: () => [current], + readPullRequest: () => current, + readTaggedLabel: taggedRepositoryLabel, + reconciliationOptions: reconciliationOptions(), + releaseSha: RELEASE_SHA, + removePendingLabel: ({ number }) => { + mutations.push({ kind: 'remove', number }); + current = pullRequest({ + labels: current.labels.filter(({ name }) => name !== 'autorelease: pending'), + }); + }, + }); + assert.deepEqual(result, { + mutationAttempts: 2, + number: 99, + recovered: false, + repository: REPOSITORY, + }); + assert.deepEqual(mutations, [ + { + input: '{"labels":["autorelease: tagged"]}\n', + kind: 'add', + number: 99, + }, + { kind: 'remove', number: 99 }, + ]); + assert.deepEqual( + current.labels.map(({ name }) => name), + ['reviewed', 'urgent', 'autorelease: tagged'], + ); + + const rerun = await markExactReleasePleasePullRequestTagged({ + addTaggedLabel: () => assert.fail('already-tagged state must not add a label'), + base: 'main', + environment: ENVIRONMENT, + listAssociatedPullRequests: () => [current], + readPullRequest: () => current, + readTaggedLabel: taggedRepositoryLabel, + reconciliationOptions: reconciliationOptions(), + releaseSha: RELEASE_SHA, + removePendingLabel: () => assert.fail('already-tagged state must not remove a label'), + }); + assert.equal(rerun.mutationAttempts, 0); +}); + +test('ambiguous mutation success is recovered by exact fresh state', async () => { + let current = pullRequest(); + let addCalls = 0; + let removeCalls = 0; + const result = await markExactReleasePleasePullRequestTagged({ + addTaggedLabel: () => { + addCalls += 1; + current = pullRequest({ + labels: labels('autorelease: pending', 'autorelease: tagged'), + }); + throw new Error('timeout after server accepted the additive label mutation'); + }, + environment: ENVIRONMENT, + listAssociatedPullRequests: () => [current], + readPullRequest: () => current, + readTaggedLabel: taggedRepositoryLabel, + reconciliationOptions: reconciliationOptions(), + releaseSha: RELEASE_SHA, + removePendingLabel: () => { + removeCalls += 1; + current = pullRequest({ labels: labels('autorelease: tagged') }); + }, + }); + assert.equal(addCalls, 1); + assert.equal(removeCalls, 1); + assert.equal(result.recovered, true); +}); + +test('lifecycle mutation retries are capped at the exact admission bound', async () => { + let current = pullRequest(); + let addCalls = 0; + let removeCalls = 0; + const result = await markExactReleasePleasePullRequestTagged({ + addTaggedLabel: () => { + addCalls += 1; + if (addCalls === RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS) { + current = pullRequest({ + labels: labels('autorelease: pending', 'autorelease: tagged'), + }); + } + }, + environment: ENVIRONMENT, + listAssociatedPullRequests: () => [current], + readPullRequest: () => current, + readTaggedLabel: taggedRepositoryLabel, + reconciliationOptions: { + ...reconciliationOptions(), + maxAttempts: RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS + 2, + }, + releaseSha: RELEASE_SHA, + removePendingLabel: () => { + removeCalls += 1; + if (removeCalls === RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS) { + current = pullRequest({ labels: labels('autorelease: tagged') }); + } + }, + }); + assert.equal(addCalls, RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS); + assert.equal(removeCalls, RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS); + assert.equal(result.mutationAttempts, 2 * RELEASE_PLEASE_MARK_TAGGED_MAX_MUTATION_ATTEMPTS); +}); + +test('missing lifecycle labels and changed exact identity fail closed', async () => { + for (const current of [ + pullRequest({ labels: [] }), + pullRequest({ merge_commit_sha: 'b'.repeat(40) }), + ]) { + await assert.rejects( + async () => + await markExactReleasePleasePullRequestTagged({ + addTaggedLabel: () => assert.fail('conflicting state must not add a label'), + environment: ENVIRONMENT, + listAssociatedPullRequests: () => [pullRequest()], + readPullRequest: () => current, + readTaggedLabel: taggedRepositoryLabel, + reconciliationOptions: { ...reconciliationOptions(), maxAttempts: 1 }, + releaseSha: RELEASE_SHA, + removePendingLabel: () => assert.fail('conflicting state must not remove a label'), + }), + /neither|identity changed/u, + ); + } +}); diff --git a/tools/release/release-please-state.sh b/tools/release/release-please-state.sh new file mode 100644 index 000000000..3637a76c0 --- /dev/null +++ b/tools/release/release-please-state.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail +[[ "$#" -ge 3 ]] || { + echo 'usage: release-please-state.sh ROOT HEAD_REF COMMAND [ARGS...]' >&2 + exit 2 +} +cd -P "$1" +root="$PWD" +head_ref="$2" +shift 2 +state="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-release-please.XXXXXX")" +trap 'rm -rf "$state"' EXIT +export OLIPHAUNT_RELEASE_PLEASE_STATE="$state" +worktree_ref="$head_ref" +printf '%s\0%s\0' "$root" "$worktree_ref" >"$state/context" +git rev-list --parents -n 1 "$worktree_ref" >"$state/ancestry" +read -r _ parent extra <"$state/ancestry" +if [[ -n "$parent" && -z "$extra" ]]; then + git ls-tree --name-only -z "$parent" -- .release-please-manifest.json >"$state/prior-files" + if [[ -s "$state/prior-files" ]]; then git show "$parent:.release-please-manifest.json" >"$state/manifest.json"; fi + git ls-tree --name-only -z "$parent" -- release-please-config.json >"$state/prior-files" + if [[ -s "$state/prior-files" ]]; then git show "$parent:release-please-config.json" >"$state/parent-config.json"; fi +fi +git ls-files -z --cached --others --exclude-standard -- Cargo.toml ':(glob)**/Cargo.toml' >"$state/cargo-files" +if [[ -n "$parent" && -z "$extra" ]]; then + while IFS= read -r -d '' file; do + git ls-tree --name-only -z "$parent" -- ":(literal)$file" >"$state/prior-files" + if [[ -s "$state/prior-files" ]]; then + mkdir -p "$state/prior-cargo/$(dirname "$file")" + git show "$parent:$file" >"$state/prior-cargo/$file" + fi + done <"$state/cargo-files" +fi +"$@" diff --git a/tools/release/release-please-transition.mjs b/tools/release/release-please-transition.mjs deleted file mode 100644 index 3a1f69484..000000000 --- a/tools/release/release-please-transition.mjs +++ /dev/null @@ -1,333 +0,0 @@ -import { readFileSync } from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { - compareText, - EMPTY_TREE, - latestProductTag, -} from "./release-graph.mjs"; -import { CONTRIB_CARRIERS_PATH, loadContribCarriers } from "./contrib-carriers.mjs"; - -const STABLE_VERSION = /^(?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)$/u; -const INTENT_RANK = { patch: 1, minor: 2, major: 3 }; -const RETIRED_CONTRIB_RELEASE_PATH = path.posix.dirname(CONTRIB_CARRIERS_PATH); - -function transitionError(prefix, message) { - return new Error(`${prefix}: ${message}`); -} - -function object(value, context, prefix) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw transitionError(prefix, `${context} must contain a JSON object`); - } - return value; -} - -function stableVersion(value, context, prefix) { - if (typeof value !== "string" || !STABLE_VERSION.test(value)) { - throw transitionError(prefix, `${context} must be a stable x.y.z version, got ${JSON.stringify(value)}`); - } - return value.split(".").map((part) => Number.parseInt(part, 10)); -} - -function compareVersions(left, right) { - for (let index = 0; index < left.length; index += 1) { - if (left[index] !== right[index]) return left[index] - right[index]; - } - return 0; -} - -function bumpVersion(version, intent, context, prefix) { - const [major, minor, patch] = stableVersion(version, context, prefix); - if (version === "0.0.0") { - throw transitionError(prefix, `${context} has no released baseline; let Release Please create its first release`); - } - if (intent === "major") return `${major + 1}.0.0`; - if (intent === "minor") return `${major}.${minor + 1}.0`; - return `${major}.${minor}.${patch + 1}`; -} - -function transitionIntent(before, after, context, prefix) { - const left = stableVersion(before, `${context} before`, prefix); - const right = stableVersion(after, `${context} after`, prefix); - if (right[0] > left[0]) return "major"; - if (right[0] === left[0] && right[1] > left[1]) return "minor"; - if (right[0] === left[0] && right[1] === left[1] && right[2] > left[2]) return "patch"; - throw transitionError(prefix, `${context} does not advance from ${before} to ${after}`); -} - -function conventionalIntent(subject, body, version, commit, prefix) { - const match = /^(feat|fix|perf|refactor|revert)(?:\([^)]+\))?(!)?:[ \t]+(.+)$/u.exec(subject); - if (match === null) { - throw transitionError( - prefix, - `shared contrib source commit ${commit.slice(0, 8)} has unsupported release intent: ${JSON.stringify(subject)}`, - ); - } - const breaking = match[2] === "!" || /^BREAKING[ -]CHANGE:/mu.test(body); - const [major] = stableVersion(version, "shared contrib owner version", prefix); - const intent = breaking ? (major === 0 ? "minor" : "major") : match[1] === "feat" && major > 0 ? "minor" : "patch"; - return { intent, summary: match[3], type: match[1] }; -} - -function carrierDescriptor(root, prefix) { - const carriers = loadContribCarriers(root, prefix); - const owners = [carriers.nativeOwner, carriers.wasixOwner]; - if (owners.some((owner) => typeof owner !== "string" || owner.length === 0) || new Set(owners).size !== 2) { - throw transitionError(prefix, `${CONTRIB_CARRIERS_PATH} must name distinct native_owner and wasix_owner products`); - } - return { - inputs: carriers.inputFiles, - owners, - }; -} - -function commitsAffecting(root, baseRef, headRef, inputs, prefix) { - const result = git(root, ["rev-list", "--reverse", `${baseRef}..${headRef}`, "--", ...inputs], {}, prefix); - return result.stdout.trim().split(/\s+/u).filter(Boolean).map((commit) => { - const subject = git(root, ["show", "-s", "--format=%s", commit], {}, prefix).stdout.trim(); - const body = git(root, ["show", "-s", "--format=%b", commit], {}, prefix).stdout.trim(); - return { commit, subject, body }; - }); -} - -/** - * Bridge the one shared source tree that Release Please cannot assign to two - * package paths. Existing runtime candidates merge the shared-source reasons - * into their Release Please entry and are promoted when that bump is too - * small; missing owners receive the conventional-commit bump inferred from - * the shared byte inputs. - */ -export function sharedContribReleaseCandidates( - root, - graph, - transitions, - { headRef = "HEAD", prefix = "release-please-transition" } = {}, -) { - const { inputs, owners } = carrierDescriptor(root, prefix); - const transitionsByProduct = new Map(transitions.map((transition) => [transition.product, transition])); - const candidates = []; - for (const owner of owners) { - const product = graph.products?.[owner]; - if (product === undefined) { - throw transitionError(prefix, `${CONTRIB_CARRIERS_PATH} owner ${owner} is not a release product`); - } - const baseRef = latestProductTag(product, headRef, prefix, root); - if (baseRef === EMPTY_TREE) { - throw transitionError(prefix, `${owner} has no release tag from which to derive shared contrib intent`); - } - const commits = commitsAffecting(root, baseRef, headRef, inputs, prefix); - if (commits.length === 0) continue; - - const transition = transitionsByProduct.get(owner); - const before = transition?.before ?? product.version; - if (before === null) { - throw transitionError(prefix, `${owner} shared contrib bridge cannot replace a first-release candidate`); - } - const reasons = commits.map(({ commit, subject, body }) => ({ - commit, - kind: "shared-source", - ...conventionalIntent(subject, body, before, commit, prefix), - })); - const requiredIntent = reasons - .map(({ intent }) => intent) - .sort((left, right) => INTENT_RANK[right] - INTENT_RANK[left])[0]; - const changelogSection = reasons.some(({ type, intent }) => type === "feat" || intent !== "patch") - ? "Features" - : "Bug Fixes"; - const requiredAfter = bumpVersion(before, requiredIntent, `${owner} current version`, prefix); - - if (transition !== undefined) { - const actualIntent = transitionIntent(transition.before, transition.after, owner, prefix); - candidates.push({ - product: owner, - packagePath: product.path, - before: transition.after, - after: INTENT_RANK[actualIntent] < INTENT_RANK[requiredIntent] ? requiredAfter : transition.after, - changelogMode: "merge-existing", - changelogSection, - reasons, - }); - continue; - } - - candidates.push({ - product: owner, - packagePath: product.path, - before, - after: requiredAfter, - changelogSection, - reasons, - }); - } - return candidates.sort((left, right) => compareText(left.product, right.product)); -} - -function packageProducts(config, prefix) { - const packages = object(config.packages, "release-please-config.json packages", prefix); - const products = new Map(); - for (const [packagePath, packageConfig] of Object.entries(packages)) { - object(packageConfig, `release-please package ${packagePath}`, prefix); - const product = packageConfig.component; - if (typeof product !== "string" || product.length === 0) { - throw transitionError(prefix, `release-please package ${packagePath} must declare a component`); - } - if ([...products.values()].includes(product)) { - throw transitionError(prefix, `release-please component ${product} is declared more than once`); - } - products.set(packagePath, product); - } - if (products.size === 0) { - throw transitionError(prefix, "release-please config must declare at least one package"); - } - return products; -} - -function readJsonObject(file, context, prefix) { - let value; - try { - value = JSON.parse(readFileSync(file, "utf8")); - } catch (cause) { - throw transitionError(prefix, `${context} is unreadable: ${cause.message}`); - } - return object(value, context, prefix); -} - -function git(root, args, { check = true } = {}, prefix) { - const result = captureCommandOutput("git", args, { - cwd: root, - label: `git ${args.join(" ")}`, - }); - if (result.error !== undefined) { - throw transitionError(prefix, `git failed: ${result.error.message}`); - } - if (check && result.status !== 0) { - const detail = (result.stderr || result.stdout || "").trim(); - throw transitionError(prefix, `git ${args.join(" ")} failed${detail ? `: ${detail}` : ""}`); - } - return result; -} - -/** - * Derive the products whose Release Please manifest entries advanced. - * A newly introduced 0.0.0 entry is seed state, not a release transition. - */ -export function releasePleaseManifestTransitions( - config, - beforeManifest, - afterManifest, - { prefix = "release-please-transition" } = {}, -) { - object(config, "release-please-config.json", prefix); - const after = object(afterManifest, ".release-please-manifest.json", prefix); - const before = beforeManifest === null - ? null - : object(beforeManifest, "parent .release-please-manifest.json", prefix); - const products = packageProducts(config, prefix); - - const currentPaths = new Set(products.keys()); - const retiredParentPaths = before === null - ? [] - : Object.keys(before).filter((packagePath) => !currentPaths.has(packagePath)).sort(); - const unexpectedRetirements = retiredParentPaths.filter( - (packagePath) => packagePath !== RETIRED_CONTRIB_RELEASE_PATH, - ); - if (unexpectedRetirements.length > 0) { - throw transitionError( - prefix, - `release-please packages cannot disappear from both config and manifest: ${JSON.stringify(unexpectedRetirements)}`, - ); - } - const missing = [...currentPaths].filter((packagePath) => !Object.hasOwn(after, packagePath)).sort(); - const extra = Object.keys(after).filter((packagePath) => !currentPaths.has(packagePath)).sort(); - if (missing.length > 0 || extra.length > 0) { - throw transitionError( - prefix, - `release-please manifest paths must exactly match configured packages; missing=${JSON.stringify(missing)} extra=${JSON.stringify(extra)}`, - ); - } - - const transitions = []; - for (const [packagePath, product] of products) { - const afterVersion = after[packagePath]; - const parsedAfter = stableVersion(afterVersion, `${product} manifest version`, prefix); - const beforeVersion = before?.[packagePath]; - if (beforeVersion === undefined) { - if (afterVersion !== "0.0.0") { - transitions.push({ product, packagePath, before: null, after: afterVersion }); - } - continue; - } - const parsedBefore = stableVersion(beforeVersion, `${product} parent manifest version`, prefix); - const order = compareVersions(parsedAfter, parsedBefore); - if (order < 0) { - throw transitionError(prefix, `${product} manifest version regressed from ${beforeVersion} to ${afterVersion}`); - } - if (order > 0) { - transitions.push({ product, packagePath, before: beforeVersion, after: afterVersion }); - } - } - return transitions.sort((left, right) => compareText(left.product, right.product)); -} - -export function compatibilityEntriesForBumpedProducts(entries, transitions) { - const bumpedProducts = new Set(transitions.map(({ product }) => product)); - return entries.filter(({ product }) => bumpedProducts.has(product)); -} - -/** - * Read the worktree's normalized Release Please state against HEAD's sole - * parent. The introduction commit legitimately has no parent manifest. - */ -export function releasePleaseWorktreeTransitions( - root, - { headRef = "HEAD", prefix = "release-please-transition" } = {}, -) { - const config = readJsonObject( - path.join(root, "release-please-config.json"), - "release-please-config.json", - prefix, - ); - const after = readJsonObject( - path.join(root, ".release-please-manifest.json"), - ".release-please-manifest.json", - prefix, - ); - const ancestry = git(root, ["rev-list", "--parents", "-n", "1", headRef], {}, prefix) - .stdout.trim().split(/\s+/u); - if (ancestry.length !== 2) { - throw transitionError(prefix, `${headRef} must resolve to one commit with exactly one parent`); - } - const parent = ancestry[1]; - const prior = git( - root, - ["show", `${parent}:.release-please-manifest.json`], - { check: false }, - prefix, - ); - let before = null; - if (prior.status === 0) { - try { - before = object( - JSON.parse(prior.stdout), - `parent .release-please-manifest.json at ${parent}`, - prefix, - ); - } catch (cause) { - if (cause instanceof SyntaxError) { - throw transitionError(prefix, `parent .release-please-manifest.json at ${parent} is invalid JSON: ${cause.message}`); - } - throw cause; - } - } else { - const stderr = prior.stderr.trim(); - if (!/does not exist|exists on disk, but not in|path .* not in/u.test(stderr)) { - throw transitionError(prefix, `cannot read parent release-please manifest at ${parent}: ${stderr || `exit ${prior.status}`}`); - } - if (Object.values(after).some((version) => version !== "0.0.0")) { - throw transitionError(prefix, "a missing parent release-please manifest is valid only for the unreleased 0.0.0 introduction state"); - } - } - return releasePleaseManifestTransitions(config, before, after, { prefix }); -} diff --git a/tools/release/release-please-transition.mts b/tools/release/release-please-transition.mts new file mode 100644 index 000000000..3bfb4c104 --- /dev/null +++ b/tools/release/release-please-transition.mts @@ -0,0 +1,217 @@ +import { existsSync, readFileSync, realpathSync } from 'node:fs'; +import path from 'node:path'; +import { CONTRIB_CARRIERS_PATH } from '../../src/extensions/artifacts/packages/tools/contrib-carriers.mts'; +import { compareText, ROOT } from './release-graph.mts'; + +const STABLE_VERSION = /^(?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)$/u; +const RETIRED_CONTRIB_RELEASE_PATH = path.posix.dirname(CONTRIB_CARRIERS_PATH); + +function transitionError(prefix, message) { + return new Error(`${prefix}: ${message}`); +} + +function object(value, context, prefix) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw transitionError(prefix, `${context} must contain a JSON object`); + } + return value; +} + +function stableVersion(value, context, prefix) { + if (typeof value !== 'string' || !STABLE_VERSION.test(value)) { + throw transitionError( + prefix, + `${context} must be a stable x.y.z version, got ${JSON.stringify(value)}`, + ); + } + return value.split('.').map((part) => Number.parseInt(part, 10)); +} + +function compareVersions(left, right) { + for (let index = 0; index < left.length; index += 1) { + if (left[index] !== right[index]) return left[index] - right[index]; + } + return 0; +} + +export function releasePleaseState(root, headRef) { + const state = process.env.OLIPHAUNT_RELEASE_PLEASE_STATE; + if (!state) throw new Error('release history requires release-please-state.sh'); + const [capturedRoot, capturedRef, end] = readFileSync(path.join(state, 'context'), 'utf8').split( + '\0', + ); + if (end !== '' || realpathSync(root) !== capturedRoot || capturedRef !== headRef) + throw new Error('release history snapshot does not match the requested checkout/ref'); + return state; +} + +export function cargoManifestPaths({ root = ROOT } = {}) { + const state = releasePleaseState(root, 'HEAD'); + const inventory = readFileSync(path.join(state, 'cargo-files'), 'utf8'); + if (!inventory || !inventory.endsWith('\0')) + throw new Error('could not enumerate tracked Cargo manifests'); + return [...new Set(inventory.split('\0').filter(Boolean))] + .map((file) => path.join(root, file)) + .filter((file) => existsSync(file)) + .sort(compareText); +} + +function packageProducts(config, prefix) { + const packages = object(config.packages, 'release-please-config.json packages', prefix); + const products = new Map(); + for (const [packagePath, packageConfig] of Object.entries(packages)) { + object(packageConfig, `release-please package ${packagePath}`, prefix); + const product = packageConfig.component; + if (typeof product !== 'string' || product.length === 0) { + throw transitionError( + prefix, + `release-please package ${packagePath} must declare a component`, + ); + } + if ([...products.values()].includes(product)) { + throw transitionError( + prefix, + `release-please component ${product} is declared more than once`, + ); + } + products.set(packagePath, product); + } + if (products.size === 0) { + throw transitionError(prefix, 'release-please config must declare at least one package'); + } + return products; +} + +function readJsonObject(file, context, prefix) { + let value; + try { + value = JSON.parse(readFileSync(file, 'utf8')); + } catch (cause) { + throw transitionError(prefix, `${context} is unreadable: ${cause.message}`); + } + return object(value, context, prefix); +} + +/** + * Derive the products whose Release Please manifest entries advanced. + * A newly introduced 0.0.0 entry is seed state, not a release transition. + */ +export function releasePleaseManifestTransitions( + config, + beforeManifest, + afterManifest, + { prefix = 'release-please-transition', beforeConfig = config } = {}, +) { + object(config, 'release-please-config.json', prefix); + const after = object(afterManifest, '.release-please-manifest.json', prefix); + const before = + beforeManifest === null + ? null + : object(beforeManifest, 'parent .release-please-manifest.json', prefix); + const products = packageProducts(config, prefix); + const priorProducts = packageProducts(beforeConfig, prefix); + const priorPaths = new Map( + [...priorProducts].map(([packagePath, product]) => [product, packagePath]), + ); + const currentProducts = new Set(products.values()); + + const currentPaths = new Set(products.keys()); + const retiredParentPaths = + before === null + ? [] + : Object.keys(before) + .filter((packagePath) => !currentProducts.has(priorProducts.get(packagePath))) + .sort(); + const unexpectedRetirements = retiredParentPaths.filter( + (packagePath) => packagePath !== RETIRED_CONTRIB_RELEASE_PATH, + ); + if (unexpectedRetirements.length > 0) { + throw transitionError( + prefix, + `release-please packages cannot disappear from both config and manifest: ${JSON.stringify(unexpectedRetirements)}`, + ); + } + const missing = [...currentPaths] + .filter((packagePath) => !Object.hasOwn(after, packagePath)) + .sort(); + const extra = Object.keys(after) + .filter((packagePath) => !currentPaths.has(packagePath)) + .sort(); + if (missing.length > 0 || extra.length > 0) { + throw transitionError( + prefix, + `release-please manifest paths must exactly match configured packages; missing=${JSON.stringify(missing)} extra=${JSON.stringify(extra)}`, + ); + } + + const transitions = []; + for (const [packagePath, product] of products) { + const afterVersion = after[packagePath]; + const parsedAfter = stableVersion(afterVersion, `${product} manifest version`, prefix); + const priorPath = priorPaths.get(product); + const beforeVersion = priorPath === undefined ? undefined : before?.[priorPath]; + if (beforeVersion === undefined) { + if (afterVersion !== '0.0.0') { + transitions.push({ product, packagePath, before: null, after: afterVersion }); + } + continue; + } + const parsedBefore = stableVersion(beforeVersion, `${product} parent manifest version`, prefix); + const order = compareVersions(parsedAfter, parsedBefore); + if (order < 0) { + throw transitionError( + prefix, + `${product} manifest version regressed from ${beforeVersion} to ${afterVersion}`, + ); + } + if (order > 0) { + transitions.push({ product, packagePath, before: beforeVersion, after: afterVersion }); + } + } + return transitions.sort((left, right) => compareText(left.product, right.product)); +} + +export function compatibilityEntriesForBumpedProducts(entries, transitions) { + const bumpedProducts = new Set(transitions.map(({ product }) => product)); + return entries.filter(({ product }) => bumpedProducts.has(product)); +} + +/** + * Read the worktree's normalized Release Please state against HEAD's sole + * parent. The introduction commit legitimately has no parent manifest. + */ +export function releasePleaseWorktreeTransitions( + root, + { headRef = 'HEAD', prefix = 'release-please-transition' } = {}, +) { + const config = readJsonObject( + path.join(root, 'release-please-config.json'), + 'release-please-config.json', + prefix, + ); + const after = readJsonObject( + path.join(root, '.release-please-manifest.json'), + '.release-please-manifest.json', + prefix, + ); + const state = releasePleaseState(root, headRef); + const ancestry = readFileSync(path.join(state, 'ancestry'), 'utf8').trim().split(/\s+/u); + if (ancestry.length !== 2 || ancestry.some((sha) => !/^[0-9a-f]{40}$/u.test(sha))) { + throw transitionError(prefix, `${headRef} must resolve to one commit with exactly one parent`); + } + const prior = path.join(state, 'manifest.json'); + const before = existsSync(prior) + ? readJsonObject(prior, 'parent .release-please-manifest.json', prefix) + : null; + if (before === null && Object.values(after).some((version) => version !== '0.0.0')) { + throw transitionError( + prefix, + 'a missing parent release-please manifest is valid only for the unreleased 0.0.0 introduction state', + ); + } + const priorConfigFile = path.join(state, 'parent-config.json'); + const beforeConfig = existsSync(priorConfigFile) + ? readJsonObject(priorConfigFile, 'parent release-please-config.json', prefix) + : config; + return releasePleaseManifestTransitions(config, before, after, { prefix, beforeConfig }); +} diff --git a/tools/release/release-please-transition.test.mjs b/tools/release/release-please-transition.test.mjs deleted file mode 100644 index 8b3907236..000000000 --- a/tools/release/release-please-transition.test.mjs +++ /dev/null @@ -1,399 +0,0 @@ -import assert from "node:assert/strict"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - compatibilityEntriesForBumpedProducts, - releasePleaseManifestTransitions, - releasePleaseWorktreeTransitions, - sharedContribReleaseCandidates, -} from "./release-please-transition.mjs"; - -const PRODUCT_PATHS = { - "liboliphaunt-native": "packages/native", - "liboliphaunt-wasix": "packages/wasix", - "oliphaunt-extension-amcheck": "packages/amcheck", - "oliphaunt-extension-vector": "packages/vector", -}; - -function git(root, ...args) { - return execFileSync("git", args, { cwd: root, encoding: "utf8" }).trim(); -} - -function manifest(versions) { - return Object.fromEntries( - Object.entries(PRODUCT_PATHS).map(([product, packagePath]) => [packagePath, versions[product]]), - ); -} - -function writeReleaseState(root, versions) { - const config = { - packages: Object.fromEntries( - Object.entries(PRODUCT_PATHS).map(([product, packagePath]) => [packagePath, { component: product }]), - ), - }; - writeFileSync(path.join(root, "release-please-config.json"), `${JSON.stringify(config, null, 2)}\n`); - writeFileSync( - path.join(root, ".release-please-manifest.json"), - `${JSON.stringify(manifest(versions), null, 2)}\n`, - ); -} - -function commit(root, subject) { - git(root, "add", "."); - git(root, "commit", "-m", subject); - return git(root, "rev-parse", "HEAD"); -} - -function fixture(t, versions = null) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-please-transition-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - git(root, "init", "-q"); - git(root, "config", "user.name", "Release Test"); - git(root, "config", "user.email", "release-test@example.invalid"); - writeFileSync(path.join(root, "legacy.txt"), "legacy history\n"); - commit(root, "legacy history"); - if (versions !== null) { - for (const directory of Object.values(PRODUCT_PATHS)) mkdirSync(path.join(root, directory), { recursive: true }); - writeReleaseState(root, versions); - commit(root, "feat: introduce products"); - } - return root; -} - -const ZERO = Object.fromEntries(Object.keys(PRODUCT_PATHS).map((product) => [product, "0.0.0"])); -const V1 = Object.fromEntries(Object.keys(PRODUCT_PATHS).map((product) => [product, "1.0.0"])); - -function contribManifest(version) { - return `postgres-version = ${JSON.stringify(version)}\n\n[[extensions]]\nid = "amcheck"\n`; -} - -function writeCarrierDescriptor(root) { - mkdirSync(path.join(root, "src/extensions/contrib"), { recursive: true }); - mkdirSync(path.join(root, "tools/release"), { recursive: true }); - mkdirSync(path.join(root, "src/postgres/versions/18"), { recursive: true }); - mkdirSync(path.join(root, "src/shared/extension-runtime-contract"), { recursive: true }); - writeFileSync( - path.join(root, "src/extensions/contrib/carriers.toml"), - [ - 'logical_product = "oliphaunt-extension-contrib-pg18"', - 'member_manifest = "src/extensions/contrib/postgres18.toml"', - 'source = "src/postgres/versions/18/source.toml"', - 'contract = "src/shared/extension-runtime-contract/contract.toml"', - 'native_owner = "liboliphaunt-native"', - 'wasix_owner = "liboliphaunt-wasix"', - "", - ].join("\n"), - ); - writeFileSync( - path.join(root, "src/extensions/contrib/postgres18.toml"), - contribManifest("18.4"), - ); - writeFileSync( - path.join(root, "src/shared/extension-runtime-contract/extension-target-profiles.toml"), - 'schema = "oliphaunt-extension-artifact-target-profiles-v1"\n', - ); - writeFileSync(path.join(root, "src/postgres/versions/18/source.toml"), 'version = "18.4"\n'); - writeFileSync(path.join(root, "src/shared/extension-runtime-contract/contract.toml"), 'schema = "v1"\n'); -} - -function runtimeGraph(versions) { - return { - products: Object.fromEntries(["liboliphaunt-native", "liboliphaunt-wasix"].map((product) => [product, { - path: PRODUCT_PATHS[product], - tag_prefix: `${product}-v`, - version: versions[product], - }])), - }; -} - -test("the unreleased introduction may have no parent release manifest", (t) => { - const root = fixture(t); - for (const directory of Object.values(PRODUCT_PATHS)) mkdirSync(path.join(root, directory), { recursive: true }); - writeReleaseState(root, ZERO); - commit(root, "feat: introduce oliphaunt"); - - assert.deepEqual(releasePleaseWorktreeTransitions(root, { prefix: "transition-test" }), []); -}); - -test("a missing parent manifest cannot conceal already-released versions", (t) => { - const root = fixture(t); - for (const directory of Object.values(PRODUCT_PATHS)) mkdirSync(path.join(root, directory), { recursive: true }); - writeReleaseState(root, V1); - commit(root, "invalid introduction"); - - assert.throws( - () => releasePleaseWorktreeTransitions(root, { prefix: "transition-test" }), - /missing parent release-please manifest is valid only for the unreleased 0[.]0[.]0 introduction state/u, - ); -}); - -test("the first release reports every product that advanced", (t) => { - const root = fixture(t, ZERO); - const released = Object.fromEntries(Object.keys(PRODUCT_PATHS).map((product) => [product, "0.1.0"])); - writeReleaseState(root, released); - commit(root, "chore(release): first release"); - - const transitions = releasePleaseWorktreeTransitions(root, { prefix: "transition-test" }); - assert.deepEqual(transitions.map(({ product }) => product), Object.keys(PRODUCT_PATHS).sort()); -}); - -test("a post-first runtime release leaves an independently versioned external sink untouched", (t) => { - const root = fixture(t, V1); - const released = { - ...V1, - "liboliphaunt-native": "1.1.0", - "liboliphaunt-wasix": "1.1.0", - "oliphaunt-extension-amcheck": "1.1.0", - }; - writeReleaseState(root, released); - commit(root, "chore(release): runtime release"); - - const transitions = releasePleaseWorktreeTransitions(root, { prefix: "transition-test" }); - assert.deepEqual( - transitions.map(({ product }) => product), - ["liboliphaunt-native", "liboliphaunt-wasix", "oliphaunt-extension-amcheck"], - ); - const entries = [ - { - id: "contrib-native", - product: "oliphaunt-extension-amcheck", - sourceProduct: "liboliphaunt-native", - }, - { - id: "contrib-wasix", - product: "oliphaunt-extension-amcheck", - sourceProduct: "liboliphaunt-wasix", - }, - { - id: "external-native", - product: "oliphaunt-extension-vector", - sourceProduct: "liboliphaunt-native", - }, - ]; - assert.deepEqual( - compatibilityEntriesForBumpedProducts(entries, transitions).map(({ id }) => id), - ["contrib-native", "contrib-wasix"], - ); -}); - -test("a consumer-only bump advances its compatibility metadata", () => { - const entries = [{ id: "sdk-native", product: "sdk", sourceProduct: "native" }]; - const transitions = [{ product: "sdk", before: "1.0.0", after: "1.1.0" }]; - assert.deepEqual(compatibilityEntriesForBumpedProducts(entries, transitions), entries); -}); - -test("native can advance without WASIX or contrib", (t) => { - const root = fixture(t, V1); - writeReleaseState(root, { ...V1, "liboliphaunt-native": "1.1.0" }); - commit(root, "chore(release): incomplete runtime release"); - const transitions = releasePleaseWorktreeTransitions(root, { prefix: "transition-test" }); - - assert.deepEqual(transitions.map(({ product }) => product), ["liboliphaunt-native"]); -}); - -test("independent products can advance to divergent versions", (t) => { - const root = fixture(t, V1); - writeReleaseState(root, { - ...V1, - "liboliphaunt-native": "1.1.0", - "liboliphaunt-wasix": "1.2.0", - "oliphaunt-extension-amcheck": "1.2.0", - }); - commit(root, "chore(release): divergent runtime release"); - const transitions = releasePleaseWorktreeTransitions(root, { prefix: "transition-test" }); - - assert.deepEqual( - transitions.map(({ product, after }) => [product, after]), - [ - ["liboliphaunt-native", "1.1.0"], - ["liboliphaunt-wasix", "1.2.0"], - ["oliphaunt-extension-amcheck", "1.2.0"], - ], - ); -}); - -test("an external-only release remains independent", (t) => { - const root = fixture(t, V1); - writeReleaseState(root, { ...V1, "oliphaunt-extension-vector": "1.1.0" }); - commit(root, "chore(release): vector release"); - const transitions = releasePleaseWorktreeTransitions(root, { prefix: "transition-test" }); - - assert.deepEqual(transitions.map(({ product }) => product), ["oliphaunt-extension-vector"]); -}); - -test("a manifest regression fails closed", (t) => { - const root = fixture(t, V1); - writeReleaseState(root, { ...V1, "oliphaunt-extension-vector": "0.9.0" }); - commit(root, "regress vector"); - - assert.throws( - () => releasePleaseWorktreeTransitions(root, { prefix: "transition-test" }), - /oliphaunt-extension-vector manifest version regressed from 1[.]0[.]0 to 0[.]9[.]0/u, - ); -}); - -test("only the retired contrib release path may disappear without fabricating a transition", () => { - const config = { packages: { "packages/native": { component: "liboliphaunt-native" } } }; - assert.deepEqual( - releasePleaseManifestTransitions( - config, - { "packages/native": "1.0.0", "src/extensions/contrib": "1.0.0" }, - { "packages/native": "1.0.0" }, - { prefix: "transition-test" }, - ), - [], - ); - assert.throws( - () => releasePleaseManifestTransitions( - config, - { "packages/native": "1.0.0", "packages/accidentally-removed": "1.0.0" }, - { "packages/native": "1.0.0" }, - { prefix: "transition-test" }, - ), - /packages cannot disappear.*packages\/accidentally-removed/u, - ); -}); - -test("shared-only fixes with no Release Please transitions seed both runtime candidates", (t) => { - const root = fixture(t, V1); - writeCarrierDescriptor(root); - commit(root, "refactor(release): define runtime-owned contrib carriers"); - git(root, "tag", "liboliphaunt-native-v1.0.0"); - git(root, "tag", "liboliphaunt-wasix-v1.0.0"); - writeFileSync(path.join(root, "src/postgres/versions/18/source.toml"), 'version = "18.5"\n'); - commit(root, "fix(contrib): update PostgreSQL source baseline"); - - assert.deepEqual( - sharedContribReleaseCandidates(root, runtimeGraph(V1), [], { prefix: "transition-test" }) - .map(({ product, before, after, changelogSection }) => ({ product, before, after, changelogSection })), - [ - { product: "liboliphaunt-native", before: "1.0.0", after: "1.0.1", changelogSection: "Bug Fixes" }, - { product: "liboliphaunt-wasix", before: "1.0.0", after: "1.0.1", changelogSection: "Bug Fixes" }, - ], - ); -}); - -test("a pre-1.0 breaking contrib commit requires a minor runtime bump", (t) => { - const versions = { ...V1, "liboliphaunt-native": "0.2.3", "liboliphaunt-wasix": "0.2.3" }; - const root = fixture(t, versions); - writeCarrierDescriptor(root); - commit(root, "refactor(release): define runtime-owned contrib carriers"); - git(root, "tag", "liboliphaunt-native-v0.2.3"); - git(root, "tag", "liboliphaunt-wasix-v0.2.3"); - writeFileSync(path.join(root, "src/extensions/contrib/postgres18.toml"), contribManifest("18.5")); - commit(root, "feat(contrib)!: change bundled SQL surface"); - - assert.deepEqual( - sharedContribReleaseCandidates(root, runtimeGraph(versions), [], { prefix: "transition-test" }) - .map(({ product, after }) => [product, after]), - [ - ["liboliphaunt-native", "0.3.0"], - ["liboliphaunt-wasix", "0.3.0"], - ], - ); -}); - -test("an existing sufficient runtime bump is preserved and receives the shared reasons", (t) => { - const root = fixture(t, V1); - writeCarrierDescriptor(root); - commit(root, "refactor(release): define runtime-owned contrib carriers"); - git(root, "tag", "liboliphaunt-native-v1.0.0"); - git(root, "tag", "liboliphaunt-wasix-v1.0.0"); - writeFileSync(path.join(root, "src/extensions/contrib/postgres18.toml"), contribManifest("18.5")); - commit(root, "feat(contrib): add a bundled SQL capability"); - const versions = { ...V1, "liboliphaunt-native": "1.1.0" }; - - assert.deepEqual( - sharedContribReleaseCandidates( - root, - runtimeGraph(versions), - [{ - product: "liboliphaunt-native", - packagePath: PRODUCT_PATHS["liboliphaunt-native"], - before: "1.0.0", - after: "1.1.0", - }], - { prefix: "transition-test" }, - ).map(({ product, before, after, changelogMode, reasons }) => ({ - product, - before, - after, - changelogMode, - reasonSummaries: reasons.map(({ summary }) => summary), - })), - [ - { - product: "liboliphaunt-native", - before: "1.1.0", - after: "1.1.0", - changelogMode: "merge-existing", - reasonSummaries: ["add a bundled SQL capability"], - }, - { - product: "liboliphaunt-wasix", - before: "1.0.0", - after: "1.1.0", - changelogMode: undefined, - reasonSummaries: ["add a bundled SQL capability"], - }, - ], - ); -}); - -test("an insufficient runtime candidate is promoted to the shared-source intent", (t) => { - const root = fixture(t, V1); - writeCarrierDescriptor(root); - commit(root, "refactor(release): define runtime-owned contrib carriers"); - git(root, "tag", "liboliphaunt-native-v1.0.0"); - git(root, "tag", "liboliphaunt-wasix-v1.0.0"); - writeFileSync(path.join(root, "src/extensions/contrib/postgres18.toml"), contribManifest("18.5")); - commit(root, "feat(contrib): add a bundled SQL capability"); - const versions = { ...V1, "liboliphaunt-native": "1.0.1" }; - - assert.deepEqual( - sharedContribReleaseCandidates( - root, - runtimeGraph(versions), - [{ - product: "liboliphaunt-native", - packagePath: PRODUCT_PATHS["liboliphaunt-native"], - before: "1.0.0", - after: "1.0.1", - }], - { prefix: "transition-test" }, - ).map(({ product, before, after, changelogMode }) => ({ product, before, after, changelogMode })), - [ - { - product: "liboliphaunt-native", - before: "1.0.1", - after: "1.1.0", - changelogMode: "merge-existing", - }, - { - product: "liboliphaunt-wasix", - before: "1.0.0", - after: "1.1.0", - changelogMode: undefined, - }, - ], - ); -}); - -test("unsupported shared-source commit intent fails closed", (t) => { - const root = fixture(t, V1); - writeCarrierDescriptor(root); - commit(root, "refactor(release): define runtime-owned contrib carriers"); - git(root, "tag", "liboliphaunt-native-v1.0.0"); - git(root, "tag", "liboliphaunt-wasix-v1.0.0"); - writeFileSync(path.join(root, "src/extensions/contrib/postgres18.toml"), contribManifest("18.5")); - commit(root, "chore: ambiguous shared source update"); - - assert.throws( - () => sharedContribReleaseCandidates(root, runtimeGraph(V1), [], { prefix: "transition-test" }), - /shared contrib source commit .* unsupported release intent/u, - ); -}); diff --git a/tools/release/release-please-transition.test.mts b/tools/release/release-please-transition.test.mts new file mode 100644 index 000000000..2dc6b7980 --- /dev/null +++ b/tools/release/release-please-transition.test.mts @@ -0,0 +1,210 @@ +import assert from 'node:assert/strict'; +import { writeFileSync } from 'node:fs'; +import path from 'node:path'; +import test from 'node:test'; +import { + compatibilityEntriesForBumpedProducts, + releasePleaseManifestTransitions, + releasePleaseWorktreeTransitions, +} from './release-please-transition.mts'; + +const PRODUCT_PATHS = { + 'liboliphaunt-native': 'packages/native', + 'liboliphaunt-wasix': 'packages/wasix', + 'oliphaunt-extension-amcheck': 'packages/amcheck', + 'oliphaunt-extension-vector': 'packages/vector', +}; + +const config = { + packages: Object.fromEntries( + Object.entries(PRODUCT_PATHS).map(([component, packagePath]) => [packagePath, { component }]), + ), +}; +const manifest = (versions) => + Object.fromEntries( + Object.entries(PRODUCT_PATHS).map(([product, packagePath]) => [packagePath, versions[product]]), + ); +const ZERO = Object.fromEntries(Object.keys(PRODUCT_PATHS).map((product) => [product, '0.0.0'])); +const V1 = Object.fromEntries(Object.keys(PRODUCT_PATHS).map((product) => [product, '1.0.0'])); +const transitionsFor = (before, after) => + releasePleaseManifestTransitions(config, manifest(before), manifest(after)); +const [mode, root, value] = process.argv.slice(2); +if (mode === 'write-fixture') { + writeFileSync(path.join(root, 'release-please-config.json'), JSON.stringify(config)); + writeFileSync( + path.join(root, '.release-please-manifest.json'), + JSON.stringify( + manifest(Object.fromEntries(Object.keys(PRODUCT_PATHS).map((product) => [product, value]))), + ), + ); + process.exit(0); +} +if (mode === 'history') { + const read = () => releasePleaseWorktreeTransitions(root, { prefix: 'transition-test' }); + if (value === 'introduction') assert.deepEqual(read(), []); + else if (value === 'invalid-introduction') + assert.throws( + read, + /missing parent release-please manifest is valid only for the unreleased 0[.]0[.]0 introduction state/u, + ); + else if (value === 'first-release') + assert.deepEqual( + read().map(({ product }) => product), + Object.keys(PRODUCT_PATHS).sort(), + ); + else throw Error('unknown history assertion'); + process.exit(0); +} +test('the first release reports every product that advanced', () => { + const baseline = ZERO; + const released = Object.fromEntries( + Object.keys(PRODUCT_PATHS).map((product) => [product, '0.1.0']), + ); + + const transitions = transitionsFor(baseline, released); + assert.deepEqual( + transitions.map(({ product }) => product), + Object.keys(PRODUCT_PATHS).sort(), + ); +}); + +test('a post-first runtime release leaves an independently versioned external sink untouched', () => { + const baseline = V1; + const released = { + ...V1, + 'liboliphaunt-native': '1.1.0', + 'liboliphaunt-wasix': '1.1.0', + 'oliphaunt-extension-amcheck': '1.1.0', + }; + + const transitions = transitionsFor(baseline, released); + assert.deepEqual( + transitions.map(({ product }) => product), + ['liboliphaunt-native', 'liboliphaunt-wasix', 'oliphaunt-extension-amcheck'], + ); + const entries = [ + { + id: 'contrib-native', + product: 'oliphaunt-extension-amcheck', + sourceProduct: 'liboliphaunt-native', + }, + { + id: 'contrib-wasix', + product: 'oliphaunt-extension-amcheck', + sourceProduct: 'liboliphaunt-wasix', + }, + { + id: 'external-native', + product: 'oliphaunt-extension-vector', + sourceProduct: 'liboliphaunt-native', + }, + ]; + assert.deepEqual( + compatibilityEntriesForBumpedProducts(entries, transitions).map(({ id }) => id), + ['contrib-native', 'contrib-wasix'], + ); +}); + +test('a consumer-only bump advances its compatibility metadata', () => { + const entries = [{ id: 'sdk-native', product: 'sdk', sourceProduct: 'native' }]; + const transitions = [{ product: 'sdk', before: '1.0.0', after: '1.1.0' }]; + assert.deepEqual(compatibilityEntriesForBumpedProducts(entries, transitions), entries); +}); + +test('native can advance without WASIX or contrib', () => { + const baseline = V1; + const released = { ...V1, 'liboliphaunt-native': '1.1.0' }; + const transitions = transitionsFor(baseline, released); + + assert.deepEqual( + transitions.map(({ product }) => product), + ['liboliphaunt-native'], + ); +}); + +test('independent products can advance to divergent versions', () => { + const baseline = V1; + const released = { + ...V1, + 'liboliphaunt-native': '1.1.0', + 'liboliphaunt-wasix': '1.2.0', + 'oliphaunt-extension-amcheck': '1.2.0', + }; + const transitions = transitionsFor(baseline, released); + + assert.deepEqual( + transitions.map(({ product, after }) => [product, after]), + [ + ['liboliphaunt-native', '1.1.0'], + ['liboliphaunt-wasix', '1.2.0'], + ['oliphaunt-extension-amcheck', '1.2.0'], + ], + ); +}); + +test('an external-only release remains independent', () => { + const baseline = V1; + const released = { ...V1, 'oliphaunt-extension-vector': '1.1.0' }; + const transitions = transitionsFor(baseline, released); + + assert.deepEqual( + transitions.map(({ product }) => product), + ['oliphaunt-extension-vector'], + ); +}); + +test('a manifest regression fails closed', () => { + const baseline = V1; + const released = { ...V1, 'oliphaunt-extension-vector': '0.9.0' }; + + assert.throws( + () => transitionsFor(baseline, released), + /oliphaunt-extension-vector manifest version regressed from 1[.]0[.]0 to 0[.]9[.]0/u, + ); +}); + +test('only the retired contrib release path may disappear without fabricating a transition', () => { + const config = { packages: { 'packages/native': { component: 'liboliphaunt-native' } } }; + assert.deepEqual( + releasePleaseManifestTransitions( + config, + { 'packages/native': '1.0.0', 'src/extensions/contrib': '1.0.0' }, + { 'packages/native': '1.0.0' }, + { prefix: 'transition-test' }, + ), + [], + ); + assert.throws( + () => + releasePleaseManifestTransitions( + config, + { 'packages/native': '1.0.0', 'packages/accidentally-removed': '1.0.0' }, + { 'packages/native': '1.0.0' }, + { prefix: 'transition-test' }, + ), + /packages cannot disappear.*packages\/accidentally-removed/u, + ); +}); + +test('moving a release owner preserves its baseline and cannot hide a version regression', () => { + const beforeConfig = { packages: { 'old/sdk': { component: 'sdk' } } }; + const config = { packages: { 'src/sdks/sdk': { component: 'sdk' } } }; + const before = { 'old/sdk': '1.2.3' }; + const transitions = (version) => + releasePleaseManifestTransitions(config, before, { 'src/sdks/sdk': version }, { beforeConfig }); + assert.deepEqual(transitions('1.2.3'), []); + assert.deepEqual(transitions('1.2.4'), [ + { product: 'sdk', packagePath: 'src/sdks/sdk', before: '1.2.3', after: '1.2.4' }, + ]); + assert.throws(() => transitions('1.0.0'), /regressed/); + assert.throws( + () => + releasePleaseManifestTransitions( + { packages: { 'src/sdks/sdk': { component: 'replacement' } } }, + before, + { 'src/sdks/sdk': '1.2.3' }, + { beforeConfig }, + ), + /packages cannot disappear/, + ); +}); diff --git a/tools/release/release-please-transition.test.sh b/tools/release/release-please-transition.test.sh new file mode 100644 index 000000000..94fc3c366 --- /dev/null +++ b/tools/release/release-please-transition.test.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +source_root="$PWD" +bun test ./tools/release/release-please-transition.test.mts +repo="$(mktemp -d)" +trap 'rm -rf "$repo"' EXIT +cd "$repo" +git init -q +git config user.name Fixture +git config user.email fixture@example.invalid +printf 'legacy history\n' > legacy.txt +git add . +git commit -qm legacy +bun "$source_root/tools/release/release-please-transition.test.mts" write-fixture "$repo" 0.0.0 +git add . +git commit -qm introduction +observe() { + bash "$source_root/tools/release/release-please-state.sh" "$repo" HEAD \ + bun "$source_root/tools/release/release-please-transition.test.mts" history "$repo" "$1" +} +observe introduction +bun "$source_root/tools/release/release-please-transition.test.mts" write-fixture "$repo" 1.0.0 +observe invalid-introduction +git checkout -- .release-please-manifest.json +bun "$source_root/tools/release/release-please-transition.test.mts" write-fixture "$repo" 0.1.0 +git add . +git commit -qm 'first release' +observe first-release +echo 'Release transition: actual parent snapshots distinguish introduction and first release' diff --git a/tools/release/release-product-version-coverage.mjs b/tools/release/release-product-version-coverage.mjs deleted file mode 100644 index 1f1648a69..000000000 --- a/tools/release/release-product-version-coverage.mjs +++ /dev/null @@ -1,51 +0,0 @@ -import { buildPlan } from "./release-graph.mjs"; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -/** - * Prove that every version moved by Release Please is owned by the matching - * Moon product. Dependencies remain independently versioned release products. - */ -export function releaseProductVersionCoverage(graph, versionedProducts, prefix = "release-product-version-coverage") { - if (!Array.isArray(versionedProducts) || versionedProducts.some((product) => typeof product !== "string" || product.length === 0)) { - throw new Error(`${prefix}: versioned products must be a string list`); - } - const selected = [...new Set(versionedProducts)].sort(compareText); - if (selected.length !== versionedProducts.length) { - throw new Error(`${prefix}: versioned products must not contain duplicates`); - } - const unknownProducts = selected.filter((product) => !(product in graph.products)); - if (unknownProducts.length > 0) { - throw new Error(`${prefix}: versioned products are absent from the release graph: ${unknownProducts.join(", ")}`); - } - const canonicalVersionFiles = selected.map((product) => { - const file = graph.products[product]?.version_files?.[0]; - if (typeof file !== "string" || file.length === 0) { - throw new Error(`${prefix}: ${product} is missing canonical version file metadata`); - } - return file; - }); - const moonRequiredProducts = buildPlan(graph, canonicalVersionFiles, prefix).releaseProducts; - const versioned = new Set(selected); - const unselectedProducts = selected.filter((product) => !moonRequiredProducts.includes(product)); - if (unselectedProducts.length > 0) { - throw new Error( - `${prefix}: manifest-bumped product(s) are not selected by their canonical version files in the Moon graph: ` + - unselectedProducts.join(", "), - ); - } - const unexpectedProducts = moonRequiredProducts.filter((product) => !versioned.has(product)); - if (unexpectedProducts.length > 0) { - throw new Error( - `${prefix}: canonical version files selected unexpected product(s): ` + - unexpectedProducts.join(", "), - ); - } - return { - missingProducts: [], - requiredProducts: moonRequiredProducts, - versionedProducts: selected, - }; -} diff --git a/tools/release/release-product-version-coverage.test.mjs b/tools/release/release-product-version-coverage.test.mjs deleted file mode 100644 index a84ca8850..000000000 --- a/tools/release/release-product-version-coverage.test.mjs +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { buildPlan } from "./release-graph.mjs"; -import { releaseProductVersionCoverage } from "./release-product-version-coverage.mjs"; -import { verifyReleaseCommit } from "./verify-release-commit.mjs"; - -const NATIVE = "liboliphaunt-native"; -const WASIX = "liboliphaunt-wasix"; -const VECTOR = "oliphaunt-extension-vector"; -const PRODUCT_PATHS = { - [NATIVE]: "src/runtimes/liboliphaunt/native", - [WASIX]: "src/runtimes/liboliphaunt/wasix", - [VECTOR]: "src/extensions/external/vector", -}; -const VECTOR_RELEASE = `${PRODUCT_PATHS[VECTOR]}/release.toml`; -const VECTOR_SOURCE = `${PRODUCT_PATHS[VECTOR]}/source.toml`; - -function git(repo, ...args) { - return execFileSync("git", args, { cwd: repo, encoding: "utf8" }).trim(); -} - -function write(repo, file, contents) { - const destination = path.join(repo, file); - mkdirSync(path.dirname(destination), { recursive: true }); - writeFileSync(destination, contents); -} - -function commit(repo, subject) { - git(repo, "add", "."); - git(repo, "commit", "-m", subject); - return git(repo, "rev-parse", "HEAD"); -} - -function manifest(versions) { - return `${JSON.stringify(Object.fromEntries( - Object.entries(PRODUCT_PATHS).map(([product, packagePath]) => [packagePath, versions[product]]), - ), null, 2)}\n`; -} - -function releasePleaseConfig() { - return `${JSON.stringify({ - packages: Object.fromEntries(Object.entries(PRODUCT_PATHS).map(([product, packagePath]) => [ - packagePath, - { - "release-type": "simple", - component: product, - "version-file": "VERSION", - "changelog-path": "CHANGELOG.md", - }, - ])), - }, null, 2)}\n`; -} - -function vectorMetadata(nativeVersion, wasixVersion, { sqlName = "vector" } = {}) { - return [ - `id = ${JSON.stringify(VECTOR)}`, - "", - "[extension]", - `sql_name = ${JSON.stringify(sqlName)}`, - "", - "[extension.compatibility]", - `native_runtime_version = ${JSON.stringify(nativeVersion)}`, - `wasix_runtime_version = ${JSON.stringify(wasixVersion)}`, - "", - ].join("\n"); -} - -function writeBase(repo, versions) { - write(repo, "release-please-config.json", releasePleaseConfig()); - write(repo, ".release-please-manifest.json", manifest(versions)); - for (const [product, packagePath] of Object.entries(PRODUCT_PATHS)) { - write(repo, `${packagePath}/VERSION`, `${versions[product]}\n`); - write(repo, `${packagePath}/CHANGELOG.md`, "# Changelog\n"); - } - write(repo, VECTOR_RELEASE, vectorMetadata(versions[NATIVE], versions[WASIX])); - write(repo, VECTOR_SOURCE, 'commit = "vector-v1"\n'); -} - -function writeRuntimeRelease(repo, versions, options = {}) { - write(repo, ".release-please-manifest.json", manifest(versions)); - for (const product of [NATIVE, WASIX]) { - const packagePath = PRODUCT_PATHS[product]; - write(repo, `${packagePath}/VERSION`, `${versions[product]}\n`); - write(repo, `${packagePath}/CHANGELOG.md`, `# Changelog\n\n## ${versions[product]} (2026-07-15)\n`); - } - write(repo, VECTOR_RELEASE, vectorMetadata(versions[NATIVE], versions[WASIX], options)); -} - -function graph(versions) { - const product = (id, extra = {}) => ({ - path: PRODUCT_PATHS[id], - version: versions[id], - version_files: [`${PRODUCT_PATHS[id]}/VERSION`], - ...extra, - }); - const project = (id, dependencies = []) => ({ - id, - source: PRODUCT_PATHS[id], - dependencies, - }); - return { - policy: { versioning: "independent" }, - products: { - [NATIVE]: product(NATIVE), - [WASIX]: product(WASIX), - [VECTOR]: product(VECTOR, { - extension: { class: "external" }, - compatibility_versions: { - native_runtime_version: { source_product: NATIVE }, - wasix_runtime_version: { source_product: WASIX }, - }, - }), - }, - moon_projects: { - [NATIVE]: project(NATIVE), - [WASIX]: project(WASIX), - [VECTOR]: project( - VECTOR, - [ - { id: NATIVE, scope: "build", source: "explicit" }, - { id: WASIX, scope: "build", source: "explicit" }, - ], - ), - }, - }; -} - -test("runtime releases leave compatible extension versions independent", { timeout: 20_000 }, (t) => { - const repo = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-coverage-")); - t.after(() => rmSync(repo, { force: true, recursive: true })); - git(repo, "init", "-q"); - git(repo, "config", "user.name", "Release Coverage Test"); - git(repo, "config", "user.email", "release-coverage@example.invalid"); - - const v1 = { [NATIVE]: "1.0.0", [WASIX]: "1.0.0", [VECTOR]: "1.0.0" }; - const v2 = { ...v1, [NATIVE]: "2.0.0", [WASIX]: "2.0.0" }; - writeBase(repo, v1); - const base = commit(repo, "feat: introduce release coverage fixture"); - - writeRuntimeRelease(repo, v2); - const release = commit(repo, "chore(release): prepare runtime release"); - const verified = verifyReleaseCommit({ repo, headRef: release, products: [NATIVE, WASIX] }); - assert.deepEqual(verified.verifiedDerivedPaths, [VECTOR_RELEASE]); - assert.deepEqual( - releaseProductVersionCoverage(graph(v2), verified.products, "release-coverage-test"), - { - missingProducts: [], - requiredProducts: [NATIVE, WASIX], - versionedProducts: [NATIVE, WASIX], - }, - ); - - assert.deepEqual( - buildPlan(graph(v2), [VECTOR_SOURCE], "release-coverage-test").releaseProducts, - [VECTOR], - "a real external source change remains independently release-significant", - ); - - git(repo, "switch", "-q", "-c", "tainted-source", base); - writeRuntimeRelease(repo, v2); - write(repo, VECTOR_SOURCE, 'commit = "vector-v2"\n'); - const taintedSource = commit(repo, "chore(release): hide external source change"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: taintedSource, products: [NATIVE, WASIX] }), - /non-release-derived path.*src\/extensions\/external\/vector\/source[.]toml/u, - ); - - git(repo, "switch", "-q", "-c", "tainted-config", base); - writeRuntimeRelease(repo, v2, { sqlName: "not-vector" }); - const taintedConfig = commit(repo, "chore(release): hide external config change"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: taintedConfig, products: [NATIVE, WASIX] }), - /derived file.*release[.]toml contains a non-version semantic change at extension[.]sql_name/u, - ); -}); - -test("a manifest bump whose canonical version file has no Moon owner fails closed", () => { - const versions = { [NATIVE]: "2.0.0", [WASIX]: "2.0.0", [VECTOR]: "1.1.0" }; - const detached = graph(versions); - detached.products[VECTOR].version_files = ["metadata/vector-version"]; - - assert.throws( - () => releaseProductVersionCoverage(detached, [VECTOR], "release-coverage-test"), - /manifest-bumped product\(s\) are not selected by their canonical version files in the Moon graph: oliphaunt-extension-vector/u, - ); -}); diff --git a/tools/release/release-product-version-coverage.test.mts b/tools/release/release-product-version-coverage.test.mts new file mode 100644 index 000000000..601ff3c03 --- /dev/null +++ b/tools/release/release-product-version-coverage.test.mts @@ -0,0 +1,164 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import { mkdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +import { buildPlan } from './release-graph.mts'; +import { verifyReleaseCommit } from './verify-release-commit.mts'; + +const NATIVE = 'liboliphaunt-native'; +const WASIX = 'liboliphaunt-wasix'; +const VECTOR = 'oliphaunt-extension-vector'; +const PRODUCT_PATHS = { + [NATIVE]: 'src/runtimes/liboliphaunt-native', + [WASIX]: 'src/runtimes/liboliphaunt-wasix', + [VECTOR]: 'src/extensions/external/vector', +}; +const VECTOR_RELEASE = `${PRODUCT_PATHS[VECTOR]}/release.toml`; +const VECTOR_SOURCE = `${PRODUCT_PATHS[VECTOR]}/source.toml`; + +function write(repo, file, contents) { + const destination = path.join(repo, file); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, contents); +} + +function manifest(versions) { + return `${JSON.stringify( + Object.fromEntries( + Object.entries(PRODUCT_PATHS).map(([product, packagePath]) => [ + packagePath, + versions[product], + ]), + ), + null, + 2, + )}\n`; +} + +function releasePleaseConfig() { + return `${JSON.stringify( + { + packages: Object.fromEntries( + Object.entries(PRODUCT_PATHS).map(([product, packagePath]) => [ + packagePath, + { + 'release-type': 'simple', + component: product, + 'version-file': 'VERSION', + 'changelog-path': 'CHANGELOG.md', + }, + ]), + ), + }, + null, + 2, + )}\n`; +} + +function vectorMetadata(nativeVersion, wasixVersion, { sqlName = 'vector' } = {}) { + return [ + `id = ${JSON.stringify(VECTOR)}`, + '', + '[extension]', + `sql_name = ${JSON.stringify(sqlName)}`, + '', + '[extension.compatibility]', + `native_runtime_version = ${JSON.stringify(nativeVersion)}`, + `wasix_runtime_version = ${JSON.stringify(wasixVersion)}`, + '', + ].join('\n'); +} + +function writeBase(repo, versions) { + write(repo, 'release-please-config.json', releasePleaseConfig()); + write(repo, '.release-please-manifest.json', manifest(versions)); + for (const [product, packagePath] of Object.entries(PRODUCT_PATHS)) { + write(repo, `${packagePath}/VERSION`, `${versions[product]}\n`); + write(repo, `${packagePath}/CHANGELOG.md`, '# Changelog\n'); + } + write(repo, VECTOR_RELEASE, vectorMetadata(versions[NATIVE], versions[WASIX])); + write(repo, VECTOR_SOURCE, 'commit = "vector-v1"\n'); +} + +function writeRuntimeRelease(repo, versions, options = {}) { + write(repo, '.release-please-manifest.json', manifest(versions)); + for (const product of [NATIVE, WASIX]) { + const packagePath = PRODUCT_PATHS[product]; + write(repo, `${packagePath}/VERSION`, `${versions[product]}\n`); + write( + repo, + `${packagePath}/CHANGELOG.md`, + `# Changelog\n\n## ${versions[product]} (2026-07-15)\n`, + ); + } + write(repo, VECTOR_RELEASE, vectorMetadata(versions[NATIVE], versions[WASIX], options)); +} + +function graph(versions) { + const product = (id, extra = {}) => ({ + path: PRODUCT_PATHS[id], + version: versions[id], + version_files: [`${PRODUCT_PATHS[id]}/VERSION`], + ...extra, + }); + const project = (id, dependencies = []) => ({ + id, + source: PRODUCT_PATHS[id], + dependencies, + }); + return { + policy: { versioning: 'independent' }, + products: { + [NATIVE]: product(NATIVE), + [WASIX]: product(WASIX), + [VECTOR]: product(VECTOR, { + extension: { class: 'external' }, + compatibility_versions: { + native_runtime_version: { source_product: NATIVE }, + wasix_runtime_version: { source_product: WASIX }, + }, + }), + }, + moon_projects: { + [NATIVE]: project(NATIVE), + [WASIX]: project(WASIX), + [VECTOR]: project(VECTOR, [ + { id: NATIVE, scope: 'build', source: 'explicit' }, + { id: WASIX, scope: 'build', source: 'explicit' }, + ]), + }, + }; +} + +const [phase, repo, scenario, headRef] = process.argv.slice(2); +const v1 = { [NATIVE]: '1.0.0', [WASIX]: '1.0.0', [VECTOR]: '1.0.0' }; +const v2 = { ...v1, [NATIVE]: '2.0.0', [WASIX]: '2.0.0' }; +if (phase === 'base') { + writeBase(repo, v1); +} else if (phase === 'release') { + writeRuntimeRelease(repo, v2, scenario === 'config' ? { sqlName: 'not-vector' } : {}); + if (scenario === 'source') write(repo, VECTOR_SOURCE, 'commit = "vector-v2"\n'); +} else if (phase === 'assert') { + const verify = () => verifyReleaseCommit({ repo, headRef, products: [NATIVE, WASIX] }); + if (scenario === 'compatible') { + assert.deepEqual(verify().verifiedDerivedPaths, [VECTOR_RELEASE]); + assert.deepEqual( + buildPlan(graph(v2), [VECTOR_SOURCE], 'release-coverage-test').releaseProducts, + [VECTOR], + 'a real external source change remains independently release-significant', + ); + } else if (scenario === 'source') { + assert.throws( + verify, + (error) => + error.message.includes('non-release-derived path') && error.message.includes(VECTOR_SOURCE), + ); + } else if (scenario === 'config') { + assert.throws( + verify, + /derived file.*release[.]toml contains a non-version semantic change at extension[.]sql_name/u, + ); + } else throw new Error('unknown coverage scenario'); + console.log('release product coverage ' + scenario + ': passed'); +} else throw new Error('run through release-product-version-coverage.test.sh'); diff --git a/tools/release/release-product-version-coverage.test.sh b/tools/release/release-product-version-coverage.test.sh new file mode 100644 index 000000000..6e3201952 --- /dev/null +++ b/tools/release/release-product-version-coverage.test.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +if [[ -z "${OLIPHAUNT_RELEASE_PLEASE_STATE:-}" ]]; then + exec bash "$root/tools/release/release-please-state.sh" "$root" HEAD \ + bash "$root/tools/release/release-product-version-coverage.test.sh" +fi +scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-release-coverage.XXXXXX")" +trap 'rm -rf "$scratch"' EXIT +git init -q "$scratch" +git -C "$scratch" config user.name 'Release Coverage Test' +git -C "$scratch" config user.email release-coverage@example.invalid +bash "$root/tools/dev/bun.sh" "$root/tools/release/release-product-version-coverage.test.mts" base "$scratch" +git -C "$scratch" add . +git -C "$scratch" commit -qm 'feat: introduce release coverage fixture' +base="$(git -C "$scratch" rev-parse HEAD)" +git -C "$scratch" update-ref refs/remotes/origin/main "$base" +for scenario in compatible source config; do + git -C "$scratch" switch -qc "$scenario" "$base" + bash "$root/tools/dev/bun.sh" "$root/tools/release/release-product-version-coverage.test.mts" release "$scratch" "$scenario" + git -C "$scratch" add . + git -C "$scratch" commit -qm 'chore(release): prepare runtime release' + head="$(git -C "$scratch" rev-parse HEAD)" + bash "$root/tools/release/with-release-history.sh" "$scratch" "$head" \ + bash "$root/tools/dev/bun.sh" "$root/tools/release/release-product-version-coverage.test.mts" \ + assert "$scratch" "$scenario" "$head" +done diff --git a/tools/release/release-project-snapshot.test.mts b/tools/release/release-project-snapshot.test.mts new file mode 100644 index 000000000..1d879059f --- /dev/null +++ b/tools/release/release-project-snapshot.test.mts @@ -0,0 +1,37 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { parseMoonProjects, releaseOrder } from './release-graph.mts'; + +test('release planning consumes resolved dependency scopes independently of published compatibility', () => { + const graph = Object.fromEntries( + parseMoonProjects({ + projects: [ + { id: 'runtime', source: 'packages/runtime', config: {} }, + { + id: 'consumer-production', + source: 'packages/consumer-production', + dependencies: [{ id: 'runtime', scope: 'production' }], + config: { dependsOn: [{ id: 'runtime', scope: 'build' }] }, + }, + { + id: 'consumer-build', + source: 'packages/consumer-build', + dependencies: [{ id: 'runtime', scope: 'build' }], + config: { dependsOn: [{ id: 'runtime', scope: 'production' }] }, + }, + ], + }), + ); + assert.equal(graph['consumer-production'].dependencies[0].scope, 'production'); + assert.equal(graph['consumer-build'].dependencies[0].scope, 'build'); + const products = { + runtime: {}, + 'consumer-production': { compatibility_versions: { runtime: { source_product: 'runtime' } } }, + 'consumer-build': {}, + }; + assert.deepEqual(releaseOrder(products, graph, Object.keys(products)), [ + 'consumer-build', + 'runtime', + 'consumer-production', + ]); +}); diff --git a/tools/release/release-publish.mjs b/tools/release/release-publish.mjs deleted file mode 100755 index 9b00a9e68..000000000 --- a/tools/release/release-publish.mjs +++ /dev/null @@ -1,1153 +0,0 @@ -#!/usr/bin/env bun -import { spawn } from "node:child_process"; -import { - mkdirSync, - mkdtempSync, - renameSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { - ROOT, - run, - runOrThrow, - uniqueValueFlag, -} from "./release-cli-utils.mjs"; -import { - DEFAULT_PUBLICATION_LOCK, - assertLockedArtifactSet, - assertLockedProductArtifacts, - assertPublicationLockSource, - discoverPublicationArtifacts, - loadPublicationLock, - lockedCarrierFile, - lockedCarriers, - lockedProductArtifactPaths, -} from "./publication-lock.mjs"; -import { - inspectCratesIoVersionState, - parseRegistryMutationDeadline, -} from "./crates-io-bootstrap-capacity.mjs"; -import { uploadCargoOnceAndReconcileExactVersion } from "./cargo-upload-reconciliation.mjs"; -import { publishFrozenCargoCrate } from "./frozen-cargo-publish.mjs"; -import { - encodeRegistryPublicationDeferral, - isRegistryPublicationDeferredError, - requirePreMutationRegistryWindow, - REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE, -} from "./registry-publication-deferral.mjs"; -import { publishFrozenNpmPackage } from "./frozen-npm-publish.mjs"; -import { - createGpgSigner, - prepareFrozenMavenBundle, - publishFrozenMavenBundle, -} from "./frozen-maven-publish.mjs"; -import { stagedKotlinMavenRepo as validateStagedKotlinMavenRepo } from "./kotlin-maven-staging.mjs"; -import { - compareText, - currentProductVersionSync, -} from "./release-artifact-targets.mjs"; -import { - collectNormalPublicationReceipts, - executeNormalPublicationPlan, -} from "./normal-publication-executor.mjs"; -import { normalPublicationPlan } from "./normal-publication-plan.mjs"; -import { loadBootstrapLedger } from "./bootstrap-ledger.mjs"; -import { - verifyLockedCarrierIntegrity, - verifyLockedRegistryIntegrity, - writeRegistryReceiptEvidence, -} from "./registry-integrity.mjs"; -import { - assertQualifiedReplaySourceState, - qualifiedReplayCandidateBinding, -} from "./qualified-release-replay.mjs"; -import { concurrentGithubReleaseAssetUploadPlan } from "./github-release-asset-upload-plan.mjs"; -import { - executeConcurrentGithubReleaseAssetUploadPlan, - githubReleaseAssetUploadChildEnvironment, - writeConcurrentGithubReleaseAssetUploadReport, -} from "./concurrent-github-release-asset-upload.mjs"; -import { loadGraph, releaseOrder } from "./release-graph.mjs"; -import { readSelectedRemoteTagMapSync } from "../../.github/scripts/manage-release-drafts.mjs"; - -const TOOL = "release-publish.mjs"; -const COMMANDS = new Set(["publish", "publish-dry-run"]); -const REGISTRY_PUBLICATION_CHECK = [ - process.execPath, - "tools/release/check_registry_publication.mjs", -]; -const REGISTRY_DEADLINE_RESERVE_MS = 5_000; -const MAVEN_PUBLISH_MINIMUM_WINDOW_MS = 35 * 60_000; - -function usage() { - console.log(`usage: tools/release/release-publish.mjs [publish args] [--publication-lock FILE] - -Runs protected release publication and read-only release validation. The -protected workflow may pass --qualified-ci after downloading the exact-SHA -Qualified record. That mode -reverifies the fixed candidate/plan/evidence paths, binds a clean checkout to -RELEASE_HEAD_SHA and binds --head-ref to that same release commit for product identity -and tag checks, and then runs live registry checks without replaying the -already-proved mutation unit tests. --qualified-ci is incompatible with ---allow-dirty and is rejected outside GitHub Actions. - -Every real publish requires an exact-SHA frozen publication lock. Repeatable -identity bootstrap for newly generated Cargo/npm identities uses: - publish --bootstrap-identities --carrier-id cargo:NAME|npm:NAME \\ - --head-ref SHA --publication-lock FILE [--bootstrap-ledger FILE] -Bootstrap mode cannot publish GitHub releases/assets or Maven. - -Normal registry publication uses one lock-derived global topology: - publish --registry-plan --products-json JSON --head-ref SHA \ - --publication-lock FILE -`); -} - -function fail(message, exitCode = 2) { - console.error(`${TOOL}: ${message}`); - process.exit(exitCode); -} - -function exitTypedRegistryDeferral(cause) { - console.error(encodeRegistryPublicationDeferral(cause)); - process.exit(REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE); -} - -function removeValueFlag(args, name) { - const output = []; - let selected; - try { - selected = uniqueValueFlag(args, name); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - for (let index = 0; index < args.length; index += 1) { - const value = args[index]; - if (value === name) { - index += 1; - } else if (value.startsWith(`${name}=`)) { - continue; - } else { - output.push(value); - } - } - return { args: output, value: selected }; -} - -const lockArgs = removeValueFlag(Bun.argv.slice(2), "--publication-lock"); -const ledgerArgs = removeValueFlag(lockArgs.args, "--bootstrap-ledger"); -const argv = ledgerArgs.args.filter((arg) => arg !== "--bootstrap-identities"); -const command = argv[0]; -const BOOTSTRAP_IDENTITIES = ledgerArgs.args.includes("--bootstrap-identities"); -const PUBLICATION_LOCK_PATH = path.resolve( - ROOT, - lockArgs.value ?? process.env.OLIPHAUNT_PUBLICATION_LOCK ?? DEFAULT_PUBLICATION_LOCK, -); -const BOOTSTRAP_LEDGER_PATH = path.resolve( - ROOT, - ledgerArgs.value ?? process.env.OLIPHAUNT_BOOTSTRAP_LEDGER ?? "target/release/bootstrap-ledger", -); -const REGISTRY_RECEIPT_EVIDENCE_PATH = path.resolve( - ROOT, - process.env.OLIPHAUNT_REGISTRY_RECEIPTS ?? "target/release/registry-integrity-receipts.json", -); -let ACTIVE_PUBLICATION_LOCK = null; -function activePublicationSourceRef(environment = process.env) { - const configured = environment.RELEASE_HEAD_SHA?.trim(); - if (configured === undefined || configured === "") return "HEAD"; - if (!/^[0-9a-f]{40}$/u.test(configured)) { - fail("RELEASE_HEAD_SHA must be a full lowercase commit SHA when provided"); - } - return configured; -} - -if (command === "-h" || command === "--help") { - usage(); - process.exit(0); -} - -if (!COMMANDS.has(command)) { - usage(); - fail(`expected publish or publish-dry-run, got ${command ?? ""}`); -} - -for (const valueFlag of [ - "--carrier-id", - "--head-ref", - "--product", - "--products-json", - "--step", -]) { - flagValue(argv.slice(1), valueFlag); -} - -if ( - command === "publish" - && !argv.slice(1).includes("--registry-plan") - && new Set(["crates-io", "npm", "maven-central"]).has(flagValue(argv.slice(1), "--step")) -) { - fail("normal product/ecosystem registry steps are disabled; use the exact-lock --registry-plan executor"); -} - -if (BOOTSTRAP_IDENTITIES && command !== "publish") { - fail("--bootstrap-identities is valid only for publish"); -} -if (command === "publish") { - try { - ACTIVE_PUBLICATION_LOCK = loadPublicationLock(PUBLICATION_LOCK_PATH); - assertPublicationLockSource( - ACTIVE_PUBLICATION_LOCK, - activePublicationSourceRef(), - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - process.env.OLIPHAUNT_PUBLICATION_LOCK = PUBLICATION_LOCK_PATH; -} - -function isNoProductPublishDryRun(command, args) { - return command === "publish-dry-run" && noProductPublishDryRunPassthrough(args) !== null; -} - -function selectsProducts(args) { - return args.some((arg) => arg === "--products-json" || arg.startsWith("--products-json=")); -} - -function flagValue(args, flag) { - try { - return uniqueValueFlag(args, flag); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} - -function unexpectedValueFlagArguments(args, allowed) { - const unexpected = []; - for (let index = 0; index < args.length; index += 1) { - const value = args[index]; - const exact = allowed.has(value); - const inline = [...allowed].some((flag) => value.startsWith(`${flag}=`)); - if (inline) continue; - if (!exact) { - unexpected.push(value); - continue; - } - if (index + 1 >= args.length) { - unexpected.push(value); - continue; - } - index += 1; - } - return unexpected; -} - -function rel(file) { - return path.relative(ROOT, file).split(path.sep).join("/"); -} - -function isDirectory(file) { - try { - return statSync(file).isDirectory(); - } catch { - return false; - } -} - -function stagedKotlinMavenRepo() { - return validateStagedKotlinMavenRepo({ - version: currentProductVersionSync("oliphaunt-kotlin", TOOL), - }); -} - -function noProductPublishDryRunPassthrough(args) { - if (args.includes("--wasm") || selectsProducts(args)) { - return null; - } - return args.filter((arg) => arg !== "--allow-dirty"); -} - -function parseProductsJson(args) { - const productsJson = flagValue(args, "--products-json"); - if (productsJson === null) { - return null; - } - let requested; - try { - requested = JSON.parse(productsJson); - } catch (error) { - fail(`--products-json must be valid JSON: ${error.message}`); - } - if (!Array.isArray(requested) || requested.length === 0 || !requested.every((item) => typeof item === "string")) { - fail("--products-json must be a non-empty JSON string array"); - } - return requested; -} - -function releaseOrderedProducts(requested) { - const graph = loadGraph(TOOL); - return releaseOrder(graph.products, graph.moon_projects, requested, TOOL); -} - -function publishProductStepPlan(args) { - const product = flagValue(args, "--product"); - const step = flagValue(args, "--step"); - if (product === null && step === null) { - return null; - } - if (product === null || step === null) { - return null; - } - return { - headRef: flagValue(args, "--head-ref") ?? "HEAD", - product, - step, - }; -} - -function verifyReleaseTag(product, headRef) { - if (BOOTSTRAP_IDENTITIES) { - assertPublicationLockSource(ACTIVE_PUBLICATION_LOCK, headRef); - return; - } - run(TOOL, [process.execPath, "tools/release/verify_product_tag.mjs", product, "--target", headRef]); -} - -function verifyReleaseTagOrThrow(product, headRef) { - if (BOOTSTRAP_IDENTITIES) { - assertPublicationLockSource(ACTIVE_PUBLICATION_LOCK, headRef); - return; - } - runOrThrow(TOOL, [process.execPath, "tools/release/verify_product_tag.mjs", product, "--target", headRef]); -} - -function requireFrozenArtifacts(roots, { products, ecosystem }) { - let actual; - try { - actual = discoverPublicationArtifacts(roots) - .filter((artifact) => artifact.ecosystem === ecosystem); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - try { - assertLockedArtifactSet(ACTIVE_PUBLICATION_LOCK, actual, { products, ecosystem }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} - -function requireFrozenProductArtifacts(product, roots) { - try { - assertLockedProductArtifacts(ACTIVE_PUBLICATION_LOCK, product, roots); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} - -function githubReleaseAssetUploadCommand(product, assets) { - const command = [ - process.execPath, - "tools/release/upload_github_release_assets.mjs", - product, - "--publication-lock", - PUBLICATION_LOCK_PATH, - ]; - for (const asset of assets) { - command.push("--asset", asset); - } - return command; -} - -function uploadGithubReleaseAssetsAsync(product, assets, windowMs, abortPath) { - return new Promise((resolve, reject) => { - const command = githubReleaseAssetUploadCommand(product, assets); - const child = spawn(command[0], command.slice(1), { - cwd: ROOT, - env: githubReleaseAssetUploadChildEnvironment(process.env, { abortPath, windowMs }), - stdio: ["ignore", "pipe", "pipe"], - windowsHide: true, - }); - let spawnError = null; - let stderr = ""; - const appendStderr = (chunk) => { - process.stderr.write(chunk); - stderr = `${stderr}${String(chunk)}`; - if (stderr.length > 64 * 1024) stderr = stderr.slice(-(64 * 1024)); - }; - child.stdout.on("data", (chunk) => process.stdout.write(chunk)); - child.stderr.on("data", appendStderr); - child.once("error", (cause) => { - spawnError = cause; - }); - child.once("close", (code, signal) => { - if (spawnError !== null || code !== 0 || signal !== null) { - const detail = stderr.trim().split(/\r?\n/u).at(-1) - ?? spawnError?.message - ?? (signal === null ? `exit ${code ?? 1}` : `signal ${signal}`); - reject(new Error(detail)); - return; - } - resolve({ code: 0, product }); - }); - }); -} - -async function publishSelectedGithubReleaseAssetSets(products, headRef) { - const selected = [...new Set(products)].sort(compareText); - if (selected.length === 0 || selected.length !== products.length) { - fail("concurrent GitHub release asset publication requires a non-empty unique product selection"); - } - const repo = process.env.GITHUB_REPOSITORY?.trim() ?? ""; - const graph = loadGraph("release-publish-github-release-assets"); - const lockedProducts = new Map(ACTIVE_PUBLICATION_LOCK.products.map((row) => [row.id, row])); - const selectedTags = selected.map((product) => { - const config = graph.products[product]; - const locked = lockedProducts.get(product); - if (config === undefined || locked === undefined || config.version !== locked.version) { - fail(`${product} cannot derive an exact frozen remote tag identity`); - } - return { product, tag: `${config.tag_prefix}${locked.version}` }; - }); - let remoteTags; - try { - remoteTags = readSelectedRemoteTagMapSync(repo, selectedTags, { environment: process.env }); - } catch (cause) { - fail(cause instanceof Error ? cause.message : String(cause)); - } - for (const { product, tag } of selectedTags) { - const remote = remoteTags.get(tag); - if (remote?.type !== "commit" || remote.sha !== headRef) { - fail(`${product} tag ${tag} is not bound to exact release commit ${headRef}`); - } - } - const rows = new Map(); - const assetsByProduct = new Map(); - for (const product of selected) { - const assets = lockedProductArtifactPaths(ACTIVE_PUBLICATION_LOCK, product) - .filter(({ artifact }) => artifact.role === "github-release-asset" || artifact.role === "github-release-metadata"); - if (assets.some(({ type }) => type !== "file")) { - fail(`${product} publication lock contains a non-file GitHub release asset`); - } - rows.set(product, assets.length); - assetsByProduct.set(product, assets.map(({ path: file }) => rel(file))); - } - let plan; - try { - plan = concurrentGithubReleaseAssetUploadPlan(rows); - } catch (cause) { - fail(cause instanceof Error ? cause.message : String(cause)); - } - console.log( - `Publishing ${plan.assetCount} exact frozen GitHub release assets for ${plan.productCount} ` - + `asset-backed products in ${plan.waves.length} bounded concurrent wave(s); ` - + `${selected.length - plan.productCount} exact empty product asset sets are receipt-proven.`, - ); - const coordinationRoot = mkdtempSync(path.join(tmpdir(), "oliphaunt-github-release-asset-wave-")); - const abortPath = path.join(coordinationRoot, "abort.json"); - const reportPath = process.env.GITHUB_RELEASE_ASSET_UPLOAD_REPORT_PATH - ?? path.join(coordinationRoot, "report.json"); - try { - let execution; - try { - execution = await executeConcurrentGithubReleaseAssetUploadPlan(plan, { - abort: (outcome) => { - writeFileSync(abortPath, `${JSON.stringify({ - product: outcome.product, - reason: "peer product lane failed", - })}\n`, { flag: "wx", mode: 0o600 }); - }, - uploadProduct: ({ product }, { wave, waveIndex }) => { - console.log( - `Starting ${product} in GitHub release asset wave ${waveIndex + 1}/${plan.waves.length} ` - + `(${wave.assetCount} assets, ${wave.windowMs}ms bound).`, - ); - return uploadGithubReleaseAssetsAsync( - product, - assetsByProduct.get(product), - wave.windowMs, - abortPath, - ); - }, - }); - } catch (cause) { - if (cause?.report !== undefined) { - writeConcurrentGithubReleaseAssetUploadReport(reportPath, { - execution: cause.report, - plan, - sourceCommit: ACTIVE_PUBLICATION_LOCK.source.commit, - }); - } - throw cause; - } - writeConcurrentGithubReleaseAssetUploadReport(reportPath, { - execution, - plan, - sourceCommit: ACTIVE_PUBLICATION_LOCK.source.commit, - }); - } catch (cause) { - fail(cause instanceof Error ? cause.message : String(cause)); - } finally { - rmSync(coordinationRoot, { force: true, recursive: true }); - } -} - -function registryPublicationCheckOrThrow(args) { - runOrThrow(TOOL, [...REGISTRY_PUBLICATION_CHECK, ...args]); -} - -function requireProductRegistryPublishedOrThrow(product, registryKind) { - const args = [ - "--product", - product, - "--require-published", - "--retries", - "12", - "--retry-delay", - "10", - ]; - if (registryKind !== null) { - args.splice(2, 0, "--registry-kind", registryKind); - } - registryPublicationCheckOrThrow(args); -} - -function releaseEnvironment(name) { - const value = process.env[name]?.trim(); - if (!value) { - throw new Error(`${name} is required`); - } - return value; -} - -async function publishLockedMavenProducts(products, slug) { - const outputRoot = path.join(ROOT, "target/release/maven-central", slug); - const gpgHome = path.join(process.env.RUNNER_TEMP ?? "/tmp", `oliphaunt-maven-gpg-${process.pid}-${slug}`); - try { - const signFile = createGpgSigner({ - privateKey: releaseEnvironment("ORG_GRADLE_PROJECT_signingInMemoryKey"), - keyId: releaseEnvironment("ORG_GRADLE_PROJECT_signingInMemoryKeyId"), - passphrase: releaseEnvironment("ORG_GRADLE_PROJECT_signingInMemoryKeyPassword"), - home: gpgHome, - }); - const prepared = prepareFrozenMavenBundle({ - lock: ACTIVE_PUBLICATION_LOCK, - products, - outputRoot, - signFile, - }); - const deadlineEpochSeconds = registryMutationDeadlineSeconds(); - requirePreMutationRegistryWindow({ - deadlineEpochSeconds, - minimumMilliseconds: MAVEN_PUBLISH_MINIMUM_WINDOW_MS, - reserveMilliseconds: REGISTRY_DEADLINE_RESERVE_MS, - context: `Maven Central atomic deployment for ${products.slice().sort(compareText).join(",")}`, - }); - const result = await publishFrozenMavenBundle({ - bundle: prepared.bundle, - lockDigest: ACTIVE_PUBLICATION_LOCK.lockDigest, - deploymentScope: products.slice().sort(compareText).join(","), - namespace: releaseEnvironment("MAVEN_CENTRAL_NAMESPACE"), - username: releaseEnvironment("ORG_GRADLE_PROJECT_mavenCentralUsername"), - password: releaseEnvironment("ORG_GRADLE_PROJECT_mavenCentralPassword"), - deadlineEpochSeconds, - }); - console.log(`Maven Central deployment ${result.deploymentId} published exact frozen payloads for ${products.join(", ")}.`); - } finally { - rmSync(gpgHome, { recursive: true, force: true }); - } -} - -function registryMutationDeadlineSeconds() { - const raw = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH?.trim(); - if (!raw) { - throw new Error("REGISTRY_MUTATION_DEADLINE_EPOCH is required for protected registry mutation"); - } - return parseRegistryMutationDeadline(raw); -} - -function registryMutationRemainingMilliseconds(context, minimum = 1) { - const remaining = (registryMutationDeadlineSeconds() * 1000) - Date.now() - REGISTRY_DEADLINE_RESERVE_MS; - if (remaining < minimum) { - throw new Error( - `${context} refused with ${Math.max(0, Math.floor(remaining / 1000))}s remaining before the shared registry mutation deadline`, - ); - } - return remaining; -} - -async function boundedRegistrySleep(milliseconds, context) { - const remaining = registryMutationRemainingMilliseconds(context); - if (milliseconds >= remaining) { - throw new Error(`${context} cannot wait ${Math.ceil(milliseconds / 1000)}s before the shared registry mutation deadline`); - } - await Bun.sleep(milliseconds); -} - -async function exactCargoVersionPublished(crateName, version, { - allowMissingIdentity = false, - identityCreationOnly = false, -} = {}) { - const inventory = await inspectCratesIoVersionState({ - plan: [{ ecosystem: "cargo", name: crateName, version }], - deadlineEpochSeconds: registryMutationDeadlineSeconds(), - }); - if (inventory.publishedIdentities.length === 1) return true; - if (identityCreationOnly && inventory.pendingVersions.length > 0) { - throw new Error( - `identity bootstrap cannot publish ${crateName} ${version}: Cargo name ${crateName} already exists while the locked exact version is absent`, - ); - } - if (inventory.missingNames.length > 0) { - if (allowMissingIdentity) return false; - throw new Error( - `normal trusted publication cannot create missing Cargo identity ${crateName}; run the protected identity bootstrap first`, - ); - } - return false; -} - -async function cargoPublishLockedCrateExact(crateName, version, suppliedCratePath = undefined, { - alreadyPublished = undefined, - allowMissingIdentity = false, - identityCreationOnly = false, - token = process.env.CARGO_REGISTRY_TOKEN, - tokenDeadlineEpochMs = undefined, -} = {}) { - let locked; - locked = lockedCarrierFile(ACTIVE_PUBLICATION_LOCK, "cargo", crateName, suppliedCratePath); - if (locked.carrier.version !== version) { - throw new Error(`frozen cargo:${crateName} version ${locked.carrier.version} does not match requested ${version}`); - } - const present = alreadyPublished ?? await exactCargoVersionPublished(crateName, version, { - allowMissingIdentity, - identityCreationOnly, - }); - if (present) { - const receipt = await verifyLockedCarrierIntegrity(ACTIVE_PUBLICATION_LOCK, `cargo:${crateName}`); - console.log(`${crateName} ${version} is already published on crates.io with lock-matching bytes; skipping frozen upload.`); - return receipt; - } - const globalDeadlineEpochMs = registryMutationDeadlineSeconds() * 1000; - const deadlineEpochMs = tokenDeadlineEpochMs === undefined - ? globalDeadlineEpochMs - : Math.min(globalDeadlineEpochMs, tokenDeadlineEpochMs); - const result = await uploadCargoOnceAndReconcileExactVersion({ - crateName, - version, - upload: () => publishFrozenCargoCrate({ - cratePath: locked.file, - expectedName: crateName, - expectedVersion: version, - token, - deadlineEpochMs, - }), - // identityCreationOnly protects the pre-mutation TOCTOU check above. Once - // crates.io has received the immutable upload, the name can legitimately - // precede its exact version in registry views while indexing converges. - exactVersionPublished: () => exactCargoVersionPublished(crateName, version, { - allowMissingIdentity, - identityCreationOnly: false, - }), - waitBeforeNextProbe: () => boundedRegistrySleep( - 10_000, - `crates.io exact-version visibility wait for ${crateName}@${version}`, - ), - }); - const receipt = await verifyLockedCarrierIntegrity(ACTIVE_PUBLICATION_LOCK, `cargo:${crateName}`); - if (result.reconciledMutationFailure) { - console.log(`${crateName} ${version} became available after an ambiguous upload response; registry bytes match the lock.`); - } - return receipt; -} - -async function cargoPublishLockedCrate(crateName, version, suppliedCratePath = undefined) { - try { - await cargoPublishLockedCrateExact(crateName, version, suppliedCratePath, { - allowMissingIdentity: BOOTSTRAP_IDENTITIES, - identityCreationOnly: BOOTSTRAP_IDENTITIES, - }); - } catch (error) { - if (isRegistryPublicationDeferredError(error)) throw error; - fail(error instanceof Error ? error.message : String(error)); - } -} - -async function npmPublishTarball(packageName, tarball, version) { - const locked = lockedCarrierFile(ACTIVE_PUBLICATION_LOCK, "npm", packageName, tarball); - if (locked.carrier.version !== version) { - throw new Error(`frozen npm:${packageName} version ${locked.carrier.version} does not match requested ${version}`); - } - const result = await publishFrozenNpmPackage({ - packageName, - version, - tarball: locked.file, - cwd: ROOT, - deadlineEpochSeconds: registryMutationDeadlineSeconds(), - identityCreationOnly: BOOTSTRAP_IDENTITIES, - }); - if (result.skipped) { - console.log(`${packageName} ${version} is already published on npm with lock-matching bytes; skipping npm publish.`); - } else if (result.reconciledMutationFailure) { - console.log(`${packageName} ${version} became available after an ambiguous npm publish failure; registry SRI matches the lock.`); - } else { - console.log(`${packageName} ${version} is public on npm with registry SRI matching the frozen tarball.`); - } - return await verifyLockedCarrierIntegrity(ACTIVE_PUBLICATION_LOCK, locked.carrier.id); -} - -async function publishBootstrapCarrier(carrierId, headRef) { - assertPublicationLockSource(ACTIVE_PUBLICATION_LOCK, headRef); - const matches = lockedCarriers(ACTIVE_PUBLICATION_LOCK).filter(({ id }) => id === carrierId); - if (matches.length !== 1) { - fail(`publication lock contains ${matches.length} carriers for bootstrap identity ${carrierId}`); - } - const carrier = matches[0]; - if (!["cargo", "npm"].includes(carrier.ecosystem)) { - fail(`bootstrap identity ${carrierId} is ${carrier.ecosystem}; only Cargo and npm are allowed`); - } - let locked; - try { - locked = lockedCarrierFile(ACTIVE_PUBLICATION_LOCK, carrier.ecosystem, carrier.name); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - if (carrier.ecosystem === "cargo") { - await cargoPublishLockedCrate(carrier.name, carrier.version, locked.file); - return; - } - await npmPublishTarball(carrier.name, locked.file, carrier.version); -} - -function lockedSwiftSourceInputs(headRef) { - const product = "oliphaunt-swift"; - assertPublicationLockSource(ACTIVE_PUBLICATION_LOCK, headRef); - const roots = [path.join(ROOT, "target/sdk-artifacts", product)]; - const fixture = path.join(ROOT, "target/release/swiftpm-extension-consumer-fixture"); - if (isDirectory(fixture)) { - roots.push(fixture); - } - requireFrozenProductArtifacts(product, roots); - const inputs = lockedProductArtifactPaths(ACTIVE_PUBLICATION_LOCK, product); - const manifest = inputs.find(({ artifact }) => artifact.kind === "swiftpm-release-manifest"); - const releaseTree = inputs.find(({ artifact }) => artifact.kind === "swiftpm-release-tree"); - if (manifest?.type !== "file" || releaseTree?.type !== "directory") { - fail("oliphaunt-swift publication lock lacks its exact manifest or generated release tree"); - } - return { manifest, product, releaseTree }; -} - -function publishSwiftGithubRelease(headRef) { - verifyReleaseTag("oliphaunt-swift", headRef); - const { manifest, releaseTree } = lockedSwiftSourceInputs(headRef); - run(TOOL, [ - process.execPath, - "tools/release/publish_swiftpm_source_tag.mjs", - "--target", - headRef, - "--manifest", - manifest.path, - "--include-tree", - releaseTree.path, - "--push", - ]); -} - -function lockedCarrierById(carrierId) { - const matches = lockedCarriers(ACTIVE_PUBLICATION_LOCK).filter(({ id }) => id === carrierId); - if (matches.length !== 1) { - throw new Error(`publication lock contains ${matches.length} carriers for ${carrierId}`); - } - return matches[0]; -} - -function mavenProductPublicationState(product) { - const result = jsonOutput([ - "tools/release/check_registry_publication.mjs", - "query-product-publication", - "--product", - product, - "--registry-kind", - "maven", - ]); - if ( - result === null - || !Array.isArray(result.packages) - || result.packages.length === 0 - || !Array.isArray(result.missing) - || !Array.isArray(result.published) - || result.missing.length + result.published.length !== result.packages.length - ) { - throw new Error(`could not classify exact Maven publication state for ${product}`); - } - if (result.missing.length > 0 && result.published.length > 0) { - throw new Error( - `${product} has a partial Maven Central publication; refusing to upload a bundle that would overwrite immutable coordinates`, - ); - } - return result.missing.length === 0 ? "published" : "pending"; -} - -async function publishNormalMavenOperation(operation, headRef) { - const expected = new Set(operation.carrierIds); - const actual = lockedCarriers(ACTIVE_PUBLICATION_LOCK, { products: operation.products, ecosystem: "maven" }); - if (actual.length !== expected.size || actual.some(({ id }) => !expected.has(id))) { - throw new Error("normal Maven operation does not contain every selected frozen Maven carrier"); - } - const states = new Map(); - for (const product of operation.products) { - verifyReleaseTagOrThrow(product, headRef); - states.set(product, mavenProductPublicationState(product)); - } - const pendingProducts = operation.products.filter((product) => states.get(product) === "pending"); - if (pendingProducts.length === 0) { - const receipts = await verifyLockedRegistryIntegrity(ACTIVE_PUBLICATION_LOCK, { - carrierIds: operation.carrierIds, - }); - console.log("Every selected Maven coordinate is already published with lock-matching bytes; skipping Maven Central upload."); - return receipts; - } - if (pendingProducts.length !== operation.products.length) { - const published = operation.products.filter((product) => states.get(product) === "published"); - throw new Error( - `selected Maven topology is partially public across products (published: ${published.join(", ")}; pending: ${pendingProducts.join(", ")}); ` - + "refusing to replace the one atomic exact-lock deployment with product-specific phases", - ); - } - await publishLockedMavenProducts(operation.products, "normal-registry-plan"); - for (const product of operation.products) { - requireProductRegistryPublishedOrThrow(product, "maven"); - } - return await verifyLockedRegistryIntegrity(ACTIVE_PUBLICATION_LOCK, { - carrierIds: operation.carrierIds, - }); -} - -async function publishNormalCarrier(operation, headRef, context, provenReceipts) { - const carrier = lockedCarrierById(operation.carrierId); - if (carrier.product !== operation.product || carrier.ecosystem !== operation.ecosystem) { - throw new Error(`${operation.id} no longer matches its exact frozen carrier`); - } - if (provenReceipts.has(carrier.id)) { - console.log(`${carrier.id}@${carrier.version} is covered by the complete immutable bootstrap ledger; skipping redundant registry reconciliation.`); - return; - } - if (carrier.ecosystem === "cargo") { - const locked = lockedCarrierFile(ACTIVE_PUBLICATION_LOCK, "cargo", carrier.name); - return await cargoPublishLockedCrateExact(carrier.name, carrier.version, locked.file, { - alreadyPublished: context.alreadyPublished, - token: context.cargoToken, - tokenDeadlineEpochMs: context.tokenDeadlineEpochMs, - }); - } - if (carrier.ecosystem === "npm") { - const locked = lockedCarrierFile(ACTIVE_PUBLICATION_LOCK, "npm", carrier.name); - return await npmPublishTarball(carrier.name, locked.file, carrier.version); - } - throw new Error(`normal registry plan cannot publish unsupported carrier ${carrier.id}`); -} - -function requireNormalRegistryProductInputs(products) { - if (products.includes("oliphaunt-react-native")) { - requireFrozenProductArtifacts("oliphaunt-react-native", [ - path.join(ROOT, "target/sdk-artifacts/oliphaunt-react-native"), - path.join(ROOT, "target/release/ios-carriers"), - ]); - } - if (products.includes("oliphaunt-kotlin")) { - requireFrozenArtifacts([stagedKotlinMavenRepo()], { - products: ["oliphaunt-kotlin"], - ecosystem: "maven", - }); - } -} - -async function publishNormalRegistryPlan(products, headRef) { - assertPublicationLockSource(ACTIVE_PUBLICATION_LOCK, headRef); - const plan = normalPublicationPlan(ACTIVE_PUBLICATION_LOCK, products); - if (plan.carrierCount === 0) { - writeRegistryReceiptEvidence(REGISTRY_RECEIPT_EVIDENCE_PATH, ACTIVE_PUBLICATION_LOCK, { - products, - ecosystems: ["cargo", "npm", "maven"], - receipts: [], - }); - console.log("Selected release contains no registry carriers; preserved exact empty registry receipt evidence and skipped registry mutation."); - return; - } - requireNormalRegistryProductInputs(products); - const carrierProducts = [...new Set( - plan.operations.flatMap((operation) => operation.products), - )].sort(compareText); - for (const product of carrierProducts) verifyReleaseTag(product, headRef); - const bootstrapLedger = loadBootstrapLedger(BOOTSTRAP_LEDGER_PATH, ACTIVE_PUBLICATION_LOCK, products, { - allowEmpty: true, - requireComplete: true, - }); - const provenReceipts = new Map( - (bootstrapLedger?.receipts ?? []).map((receipt) => [receipt.id, receipt]), - ); - const selectedCarrierIds = new Set(plan.operations.flatMap((operation) => - operation.kind === "carrier" ? [operation.carrierId] : operation.carrierIds)); - for (const id of provenReceipts.keys()) { - if (!selectedCarrierIds.has(id)) { - throw new Error(`complete bootstrap ledger contains ${id}, which is absent from the exact normal publication plan`); - } - } - console.log( - `Reconciling all ${plan.operations.length} dependency-ordered registry operations ` - + `for ${plan.carrierCount} exact frozen carriers.`, - ); - if (provenReceipts.size > 0) { - console.log(`Reusing ${provenReceipts.size} lock-bound Cargo/npm receipts from the complete, preverified bootstrap ledger.`); - } - const execution = await executeNormalPublicationPlan({ - plan, - batchSize: process.env.CRATES_IO_TRUSTED_PUBLISH_BATCH_SIZE, - cargoVersionPublished: async (operation) => { - if (provenReceipts.has(operation.carrierId)) return true; - const carrier = lockedCarrierById(operation.carrierId); - return exactCargoVersionPublished(carrier.name, carrier.version); - }, - publishCarrier: (operation, context) => publishNormalCarrier(operation, headRef, context, provenReceipts), - publishMaven: (operation) => publishNormalMavenOperation(operation, headRef), - }); - const completeReceipts = collectNormalPublicationReceipts({ - plan, - initialReceipts: [...provenReceipts.values()], - operationResults: execution.operationResults, - }); - writeRegistryReceiptEvidence(REGISTRY_RECEIPT_EVIDENCE_PATH, ACTIVE_PUBLICATION_LOCK, { - products, - ecosystems: ["cargo", "npm", "maven"], - receipts: [...completeReceipts.values()], - }); - console.log(`Preserved ${completeReceipts.size} exact-lock registry receipts at ${path.relative(ROOT, REGISTRY_RECEIPT_EVIDENCE_PATH)}.`); -} - -function jsonOutput(args) { - const result = captureCommandOutput(process.execPath, args, { - cwd: ROOT, - label: `${process.execPath} ${args.join(" ")}`, - }); - if (result.status !== 0 || result.error !== undefined) { - return null; - } - try { - return JSON.parse(result.stdout); - } catch { - return null; - } -} - -function releaseValidationPlan(args) { - const requested = parseProductsJson(args); - if (requested === null) { - return null; - } - const qualifiedCi = args.includes("--qualified-ci"); - const allowDirty = args.includes("--allow-dirty"); - if (qualifiedCi && allowDirty) { - fail("--qualified-ci cannot be combined with --allow-dirty"); - } - releaseOrderedProducts(requested); - return { - qualifiedCi, - passthrough: args.filter((arg) => arg !== "--allow-dirty" && arg !== "--qualified-ci"), - }; -} - -function verifyQualifiedCiReplay(validationPlan) { - if (process.env.GITHUB_ACTIONS !== "true") { - fail("--qualified-ci is valid only inside the protected GitHub Actions release workflow"); - } - for (const name of [ - "CI_RUN_ID", - "GITHUB_REPOSITORY", - "RELEASE_HEAD_SHA", - "WASIX_EVIDENCE_REQUIRED", - ]) { - if (!process.env[name]?.trim()) { - fail(`--qualified-ci requires ${name}`); - } - } - if (!["true", "false"].includes(process.env.WASIX_EVIDENCE_REQUIRED)) { - fail("--qualified-ci requires WASIX_EVIDENCE_REQUIRED to be true or false"); - } - const headRef = flagValue( - validationPlan.passthrough, - "--head-ref", - ) ?? "HEAD"; - try { - assertQualifiedReplaySourceState({ - repo: ROOT, - headRef, - expectedSha: process.env.RELEASE_HEAD_SHA, - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - let replay; - try { - replay = qualifiedReplayCandidateBinding({ - releaseSha: process.env.RELEASE_HEAD_SHA, - runId: process.env.CI_RUN_ID, - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - run(TOOL, [ - "node", - ".github/scripts/verify-release-candidate.mjs", - `${replay.candidateRoot}/oliphaunt-release-candidate.json`, - "--plan", - `${replay.candidateRoot}/affected-plan/ci-plan.json`, - "--qualification-mode", - replay.qualificationMode, - "--wasix-evidence-required", - process.env.WASIX_EVIDENCE_REQUIRED, - "--wasix-evidence-root", - `${replay.candidateRoot}/wasix-evidence`, - ], { - environment: { - ...process.env, - CI_RUN_ID: replay.runId, - RELEASE_HEAD_SHA: replay.candidateSha, - }, - }); -} - -function runReleaseValidation(validationPlan) { - if (validationPlan.qualifiedCi) { - verifyQualifiedCiReplay(validationPlan); - } else { - run(TOOL, [process.execPath, "tools/release/release-check.mjs"]); - } - run(TOOL, [process.execPath, "tools/release/release-check-registries.mjs", ...validationPlan.passthrough]); -} - -async function publishNoProduct(args) { - const productsJson = flagValue(args, "--products-json"); - const validationPlan = releaseValidationPlan(args); - if (productsJson !== null) { - run(TOOL, ["tools/release/check_publish_environment.mjs", "--products-json", productsJson]); - } - if (validationPlan !== null) { - runReleaseValidation(validationPlan); - console.log("publish environment and release checks passed; package publishing runs in the Release workflow"); - return; - } - run(TOOL, [process.execPath, "tools/release/release-check.mjs"]); - const passthrough = args.filter((arg) => arg !== "--allow-dirty"); - if (passthrough.length > 0) { - run(TOOL, [process.execPath, "tools/release/release-check-registries.mjs", ...passthrough]); - } - console.log("No release products selected; publish environment and package publish steps skipped."); -} - -if (isNoProductPublishDryRun(command, argv.slice(1))) { - const passthrough = noProductPublishDryRunPassthrough(argv.slice(1)); - run(TOOL, [process.execPath, "tools/release/release-check.mjs"]); - if (passthrough.length > 0) { - run(TOOL, [process.execPath, "tools/release/release-check-registries.mjs", ...passthrough]); - } - process.exit(0); -} - -const validationPlan = command === "publish-dry-run" ? releaseValidationPlan(argv.slice(1)) : null; -if (validationPlan !== null) { - runReleaseValidation(validationPlan); - process.exit(0); -} - -if (command === "publish-dry-run") { - fail("publish-dry-run is Bun-owned; unsupported arguments must fail before any protected publication route"); -} - -const publishProductStep = command === "publish" ? publishProductStepPlan(argv.slice(1)) : null; -const bootstrapCarrierId = flagValue(argv.slice(1), "--carrier-id"); -const normalRegistryPlanSelected = argv.slice(1).includes("--registry-plan"); -if (BOOTSTRAP_IDENTITIES) { - const carrierSelection = bootstrapCarrierId !== null; - if (!carrierSelection || publishProductStep !== null) { - fail("--bootstrap-identities requires exactly one dependency-ordered --carrier-id; product-level bootstrap is forbidden"); - } - if (carrierSelection) { - const unexpected = unexpectedValueFlagArguments(argv.slice(1), new Set(["--carrier-id", "--head-ref"])); - if (unexpected.length > 0) { - fail(`unsupported carrier bootstrap arguments: ${unexpected.join(" ")}`); - } - } - try { - assertPublicationLockSource( - ACTIVE_PUBLICATION_LOCK, - bootstrapCarrierId !== null - ? (flagValue(argv.slice(1), "--head-ref") ?? "HEAD") - : publishProductStep.headRef, - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } -} else if (bootstrapCarrierId !== null) { - fail("--carrier-id is valid only with --bootstrap-identities"); -} -if (BOOTSTRAP_IDENTITIES && normalRegistryPlanSelected) { - fail("--registry-plan is forbidden during identity bootstrap"); -} -if (BOOTSTRAP_IDENTITIES && bootstrapCarrierId !== null) { - try { - await publishBootstrapCarrier( - bootstrapCarrierId, - flagValue(argv.slice(1), "--head-ref") ?? "HEAD", - ); - } catch (cause) { - if (isRegistryPublicationDeferredError(cause)) exitTypedRegistryDeferral(cause); - throw cause; - } - process.exit(0); -} -if (normalRegistryPlanSelected) { - const requested = parseProductsJson(argv.slice(1)); - if (requested === null || publishProductStep !== null) { - fail("--registry-plan requires --products-json and cannot be combined with --product/--step"); - } - const withoutMode = argv.slice(1).filter((value) => value !== "--registry-plan"); - const unexpected = unexpectedValueFlagArguments(withoutMode, new Set(["--products-json", "--head-ref"])); - if (unexpected.length > 0) { - fail(`unsupported normal registry-plan arguments: ${unexpected.join(" ")}`); - } - try { - await publishNormalRegistryPlan( - requested, - flagValue(argv.slice(1), "--head-ref") ?? "HEAD", - ); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - process.exit(0); -} -if (command === "publish" && flagValue(argv.slice(1), "--step") === "github-release-assets" && flagValue(argv.slice(1), "--product") === null) { - const requested = parseProductsJson(argv.slice(1)); - if (requested !== null) { - await publishSelectedGithubReleaseAssetSets( - releaseOrderedProducts(requested), - flagValue(argv.slice(1), "--head-ref") ?? "HEAD", - ); - process.exit(0); - } -} - -if (publishProductStep?.product === "oliphaunt-swift" && publishProductStep.step === "github-release") { - publishSwiftGithubRelease(publishProductStep.headRef); - process.exit(0); -} - -if (command === "publish" && publishProductStep === null && flagValue(argv.slice(1), "--product") === null && flagValue(argv.slice(1), "--step") === null) { - await publishNoProduct(argv.slice(1)); - process.exit(0); -} - -fail(`unsupported publish arguments: ${argv.slice(1).join(" ") || ""}`); diff --git a/tools/release/release-publish.mts b/tools/release/release-publish.mts new file mode 100755 index 000000000..b8faa4f66 --- /dev/null +++ b/tools/release/release-publish.mts @@ -0,0 +1,967 @@ +import { + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + renameSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { readSelectedRemoteTagMap } from '../../.github/scripts/manage-release-drafts.mts'; +import { stagedKotlinMavenRepo as validateStagedKotlinMavenRepo } from '../../src/sdks/kotlin/tools/kotlin-maven-staging.mts'; +import { compareText, currentProductVersionSync } from './release-artifact-targets.mts'; +import { loadProducts, releaseOrder } from './release-graph.mts'; +import { loadBootstrapLedger } from './bootstrap-ledger.mts'; +import { uploadCargoOnceAndReconcileExactVersion } from './cargo-upload-reconciliation.mts'; +import { queryRegistryPackages } from './check_registry_publication.mts'; +import { + executeConcurrentGithubReleaseAssetUploadPlan, + githubReleaseAssetUploadEnvironment, + writeConcurrentGithubReleaseAssetUploadReport, +} from './concurrent-github-release-asset-upload.mts'; +import { + inspectCratesIoVersionState, + parseRegistryMutationDeadline, +} from './crates-io-bootstrap-capacity.mts'; +import { publishFrozenCargoCrate } from './frozen-cargo-publish.mts'; +import { loadPreparedMavenBundle, publishFrozenMavenBundle } from './frozen-maven-publish.mts'; +import { + prepareFrozenNpmPublication, + reconcileFrozenNpmPublication, +} from './frozen-npm-publish.mts'; +import { concurrentGithubReleaseAssetUploadPlan } from './github-release-asset-upload-plan.mts'; +import { + collectNormalPublicationReceipts, + executeCargoPublicationBatch, + normalPublicationSchedule, +} from './normal-publication-executor.mts'; +import { normalPublicationPlan } from './normal-publication-plan.mts'; +import { + assertLockedArtifactSet, + assertLockedProductArtifacts, + assertPublicationLockSource, + DEFAULT_PUBLICATION_LOCK, + discoverPublicationArtifacts, + loadPublicationLock, + lockedCarrierFile, + lockedCarriers, + lockedProductArtifactPaths, +} from './publication-lock.mts'; +import { + verifyLockedCarrierIntegrity, + verifyLockedRegistryIntegrity, + writeRegistryReceiptEvidence, +} from './registry-integrity.mts'; +import { + encodeRegistryPublicationDeferral, + isRegistryPublicationDeferredError, + REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE, + requirePreMutationRegistryWindow, +} from './registry-publication-deferral.mts'; +import { ROOT, uniqueValueFlag } from './release-cli-utils.mts'; +import { frozenUploadPlan, uploadFrozenReleaseAssets } from './upload_github_release_assets.mts'; + +const TOOL = 'release-publish.mts'; +const REGISTRY_DEADLINE_RESERVE_MS = 5_000; +const MAVEN_PUBLISH_MINIMUM_WINDOW_MS = 35 * 60_000; + +function usage() { + console.log(`usage: tools/release/release-publish.mts publish [publish args] [--publication-lock FILE] + +Runs protected publication. Read-only registry preflight uses bash tools/release/release-check-registries.sh. + +Every real publish requires an exact-SHA frozen publication lock. Repeatable +identity bootstrap for newly generated Cargo/npm identities uses: + bash .github/scripts/bootstrap-registry-identities.sh +Bootstrap mode cannot publish GitHub releases/assets or Maven. + +Normal registry publication uses one lock-derived global topology: + bash tools/release/publish-registries.sh --products-json JSON --head-ref SHA \ + --publication-lock FILE +`); +} + +function fail(message, exitCode = 2) { + console.error(`${TOOL}: ${message}`); + process.exit(exitCode); +} + +function exitTypedRegistryDeferral(cause) { + console.error(encodeRegistryPublicationDeferral(cause)); + process.exit(REGISTRY_PUBLICATION_DEFERRAL_EXIT_CODE); +} + +function removeValueFlag(args, name) { + const output = []; + let selected; + try { + selected = uniqueValueFlag(args, name); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } + for (let index = 0; index < args.length; index += 1) { + const value = args[index]; + if (value === name) { + index += 1; + } else if (value.startsWith(`${name}=`)) { + continue; + } else { + output.push(value); + } + } + return { args: output, value: selected }; +} + +const lockArgs = removeValueFlag(Bun.argv.slice(2), '--publication-lock'); +const ledgerArgs = removeValueFlag(lockArgs.args, '--bootstrap-ledger'); +const argv = ledgerArgs.args.filter((arg) => arg !== '--bootstrap-identities'); +const command = argv[0]; +const BOOTSTRAP_IDENTITIES = ledgerArgs.args.includes('--bootstrap-identities'); +const PUBLICATION_LOCK_PATH = path.resolve( + ROOT, + lockArgs.value ?? process.env.OLIPHAUNT_PUBLICATION_LOCK ?? DEFAULT_PUBLICATION_LOCK, +); +const BOOTSTRAP_LEDGER_PATH = path.resolve( + ROOT, + ledgerArgs.value ?? process.env.OLIPHAUNT_BOOTSTRAP_LEDGER ?? 'target/release/bootstrap-ledger', +); +const REGISTRY_RECEIPT_EVIDENCE_PATH = path.resolve( + ROOT, + process.env.OLIPHAUNT_REGISTRY_RECEIPTS ?? 'target/release/registry-integrity-receipts.json', +); +let ACTIVE_PUBLICATION_LOCK = null; +function activePublicationSourceRef(environment = process.env) { + const configured = environment.RELEASE_HEAD_SHA?.trim(); + if (configured === undefined || configured === '') return 'HEAD'; + if (!/^[0-9a-f]{40}$/u.test(configured)) { + fail('RELEASE_HEAD_SHA must be a full lowercase commit SHA when provided'); + } + return configured; +} + +if (command === '-h' || command === '--help') { + usage(); + process.exit(0); +} + +const registryPhases = new Set([ + 'registry-prepare', + 'registry-cargo', + 'registry-npm-before', + 'registry-npm-after', + 'registry-maven', + 'registry-finish', +]); +const bootstrapPhases = new Set(['bootstrap-cargo', 'bootstrap-npm-before', 'bootstrap-npm-after']); +if (registryPhases.has(command) && BOOTSTRAP_IDENTITIES) + fail('normal registry phases are forbidden during identity bootstrap'); +if (command !== 'publish' && !registryPhases.has(command) && !bootstrapPhases.has(command)) { + usage(); + fail( + `expected publish (read-only registry checks use release-check-registries.sh), got ${command ?? ''}`, + ); +} + +for (const valueFlag of ['--carrier-id', '--head-ref', '--product', '--products-json', '--step']) { + flagValue(argv.slice(1), valueFlag); +} + +if ( + !argv.slice(1).includes('--registry-plan') && + new Set(['crates-io', 'npm', 'maven-central']).has(flagValue(argv.slice(1), '--step')) +) { + fail( + 'normal product/ecosystem registry steps are disabled; use bash tools/release/publish-registries.sh', + ); +} + +try { + ACTIVE_PUBLICATION_LOCK = loadPublicationLock(PUBLICATION_LOCK_PATH); + assertPublicationLockSource(ACTIVE_PUBLICATION_LOCK, activePublicationSourceRef()); +} catch (error) { + fail(error instanceof Error ? error.message : String(error)); +} +process.env.OLIPHAUNT_PUBLICATION_LOCK = PUBLICATION_LOCK_PATH; + +function flagValue(args, flag) { + try { + return uniqueValueFlag(args, flag); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } +} + +function unexpectedValueFlagArguments(args, allowed) { + const unexpected = []; + for (let index = 0; index < args.length; index += 1) { + const value = args[index]; + const exact = allowed.has(value); + const inline = [...allowed].some((flag) => value.startsWith(`${flag}=`)); + if (inline) continue; + if (!exact) { + unexpected.push(value); + continue; + } + if (index + 1 >= args.length) { + unexpected.push(value); + continue; + } + index += 1; + } + return unexpected; +} + +function rel(file) { + return path.relative(ROOT, file).split(path.sep).join('/'); +} + +function stagedKotlinMavenRepo() { + return validateStagedKotlinMavenRepo({ + version: currentProductVersionSync('oliphaunt-kotlin', TOOL), + }); +} + +function parseProductsJson(args) { + const productsJson = flagValue(args, '--products-json'); + if (productsJson === null) { + return null; + } + let requested; + try { + requested = JSON.parse(productsJson); + } catch (error) { + fail(`--products-json must be valid JSON: ${error.message}`); + } + if ( + !Array.isArray(requested) || + requested.length === 0 || + !requested.every((item) => typeof item === 'string') + ) { + fail('--products-json must be a non-empty JSON string array'); + } + return requested; +} + +function releaseOrderedProducts(requested) { + return releaseOrder(loadProducts(TOOL), undefined, requested, TOOL); +} + +function publishProductStepPlan(args) { + const product = flagValue(args, '--product'); + const step = flagValue(args, '--step'); + if (product === null && step === null) { + return null; + } + if (product === null || step === null) { + return null; + } + return { + headRef: flagValue(args, '--head-ref') ?? 'HEAD', + product, + step, + }; +} + +async function verifyReleaseTags(products, headRef) { + const source = assertPublicationLockSource(ACTIVE_PUBLICATION_LOCK, headRef); + if (BOOTSTRAP_IDENTITIES || products.length === 0) return; + const repo = process.env.GITHUB_REPOSITORY?.trim() ?? ''; + const productMetadata = loadProducts('release-publish-github-release-assets'); + const lockedProducts = new Map(ACTIVE_PUBLICATION_LOCK.products.map((row) => [row.id, row])); + const selectedTags = products.map((product) => { + const config = productMetadata[product]; + const locked = lockedProducts.get(product); + if (config === undefined || locked === undefined || config.version !== locked.version) { + throw new Error(`${product} cannot derive an exact frozen remote tag identity`); + } + return { product, tag: `${config.tag_prefix}${locked.version}` }; + }); + const remoteTags = await readSelectedRemoteTagMap(repo, selectedTags, { + environment: process.env, + }); + for (const { product, tag } of selectedTags) { + const remote = remoteTags.get(tag); + if (remote?.type !== 'commit' || remote.sha !== source.commit) { + throw new Error(`${product} tag ${tag} is not bound to exact release commit ${headRef}`); + } + } +} + +function requireFrozenArtifacts(roots, { products, ecosystem }) { + let actual; + try { + actual = discoverPublicationArtifacts(roots).filter( + (artifact) => artifact.ecosystem === ecosystem, + ); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } + try { + assertLockedArtifactSet(ACTIVE_PUBLICATION_LOCK, actual, { products, ecosystem }); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } +} + +function requireFrozenProductArtifacts(product, roots) { + try { + assertLockedProductArtifacts(ACTIVE_PUBLICATION_LOCK, product, roots); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } +} + +async function publishSelectedGithubReleaseAssetSets(products, headRef) { + const selected = [...new Set(products)].sort(compareText); + if (selected.length === 0 || selected.length !== products.length) { + fail( + 'concurrent GitHub release asset publication requires a non-empty unique product selection', + ); + } + await verifyReleaseTags(selected, headRef); + const repo = process.env.GITHUB_REPOSITORY?.trim() ?? ''; + const rows = new Map(); + const uploadPlans = new Map(); + for (const product of selected) { + const assets = lockedProductArtifactPaths(ACTIVE_PUBLICATION_LOCK, product).filter( + ({ artifact }) => + artifact.role === 'github-release-asset' || artifact.role === 'github-release-metadata', + ); + if (assets.some(({ type }) => type !== 'file')) { + fail(`${product} publication lock contains a non-file GitHub release asset`); + } + rows.set(product, assets.length); + uploadPlans.set( + product, + frozenUploadPlan({ + product, + assets: assets.map(({ path: file }) => rel(file)), + publicationLock: PUBLICATION_LOCK_PATH, + repo, + }), + ); + } + let plan; + try { + plan = concurrentGithubReleaseAssetUploadPlan(rows); + } catch (cause) { + fail(cause instanceof Error ? cause.message : String(cause)); + } + console.log( + `Publishing ${plan.assetCount} exact frozen GitHub release assets for ${plan.productCount} ` + + `asset-backed products in ${plan.waves.length} bounded concurrent wave(s); ` + + `${selected.length - plan.productCount} exact empty product asset sets are receipt-proven.`, + ); + const coordinationRoot = mkdtempSync(path.join(tmpdir(), 'oliphaunt-github-release-asset-wave-')); + const abortPath = path.join(coordinationRoot, 'abort.json'); + const reportPath = + process.env.GITHUB_RELEASE_ASSET_UPLOAD_REPORT_PATH ?? + path.join(coordinationRoot, 'report.json'); + try { + let execution; + try { + execution = await executeConcurrentGithubReleaseAssetUploadPlan(plan, { + abort: (outcome) => { + writeFileSync( + abortPath, + `${JSON.stringify({ + product: outcome.product, + reason: 'peer product lane failed', + })}\n`, + { flag: 'wx', mode: 0o600 }, + ); + }, + uploadProduct: ({ product }, { wave, waveIndex }) => { + console.log( + `Starting ${product} in GitHub release asset wave ${waveIndex + 1}/${plan.waves.length} ` + + `(${wave.assetCount} assets, ${wave.windowMs}ms bound).`, + ); + return uploadFrozenReleaseAssets(uploadPlans.get(product), { + environment: githubReleaseAssetUploadEnvironment(process.env, { + abortPath, + windowMs: wave.windowMs, + }), + }); + }, + }); + } catch (cause) { + if (cause?.report !== undefined) { + writeConcurrentGithubReleaseAssetUploadReport(reportPath, { + execution: cause.report, + plan, + sourceCommit: ACTIVE_PUBLICATION_LOCK.source.commit, + }); + } + throw cause; + } + writeConcurrentGithubReleaseAssetUploadReport(reportPath, { + execution, + plan, + sourceCommit: ACTIVE_PUBLICATION_LOCK.source.commit, + }); + } catch (cause) { + fail(cause instanceof Error ? cause.message : String(cause)); + } finally { + rmSync(coordinationRoot, { force: true, recursive: true }); + } +} + +function releaseEnvironment(name) { + const value = process.env[name]?.trim(); + if (!value) { + throw new Error(`${name} is required`); + } + return value; +} + +async function publishLockedMavenProducts(products) { + const prepared = loadPreparedMavenBundle({ + lock: ACTIVE_PUBLICATION_LOCK, + products, + outputRoot: path.join(ROOT, 'target/release/maven-central/normal-registry-plan'), + }); + const deadlineEpochSeconds = registryMutationDeadlineSeconds(); + requirePreMutationRegistryWindow({ + deadlineEpochSeconds, + minimumMilliseconds: MAVEN_PUBLISH_MINIMUM_WINDOW_MS, + reserveMilliseconds: REGISTRY_DEADLINE_RESERVE_MS, + context: `Maven Central atomic deployment for ${products.slice().sort(compareText).join(',')}`, + }); + const result = await publishFrozenMavenBundle({ + bundle: prepared.bundle, + lockDigest: ACTIVE_PUBLICATION_LOCK.lockDigest, + deploymentScope: products.slice().sort(compareText).join(','), + namespace: releaseEnvironment('MAVEN_CENTRAL_NAMESPACE'), + username: releaseEnvironment('ORG_GRADLE_PROJECT_mavenCentralUsername'), + password: releaseEnvironment('ORG_GRADLE_PROJECT_mavenCentralPassword'), + deadlineEpochSeconds, + }); + console.log( + `Maven Central deployment ${result.deploymentId} published exact frozen payloads for ${products.join(', ')}.`, + ); +} + +function registryMutationDeadlineSeconds() { + const raw = process.env.REGISTRY_MUTATION_DEADLINE_EPOCH?.trim(); + if (!raw) { + throw new Error('REGISTRY_MUTATION_DEADLINE_EPOCH is required for protected registry mutation'); + } + return parseRegistryMutationDeadline(raw); +} + +function registryMutationRemainingMilliseconds(context, minimum = 1) { + const remaining = + registryMutationDeadlineSeconds() * 1000 - Date.now() - REGISTRY_DEADLINE_RESERVE_MS; + if (remaining < minimum) { + throw new Error( + `${context} refused with ${Math.max(0, Math.floor(remaining / 1000))}s remaining before the shared registry mutation deadline`, + ); + } + return remaining; +} + +async function boundedRegistrySleep(milliseconds, context) { + const remaining = registryMutationRemainingMilliseconds(context); + if (milliseconds >= remaining) { + throw new Error( + `${context} cannot wait ${Math.ceil(milliseconds / 1000)}s before the shared registry mutation deadline`, + ); + } + await Bun.sleep(milliseconds); +} + +async function exactCargoVersionPublished( + crateName, + version, + { allowMissingIdentity = false, identityCreationOnly = false } = {}, +) { + const inventory = await inspectCratesIoVersionState({ + plan: [{ ecosystem: 'cargo', name: crateName, version }], + deadlineEpochSeconds: registryMutationDeadlineSeconds(), + }); + if (inventory.publishedIdentities.length === 1) return true; + if (identityCreationOnly && inventory.pendingVersions.length > 0) { + throw new Error( + `identity bootstrap cannot publish ${crateName} ${version}: Cargo name ${crateName} already exists while the locked exact version is absent`, + ); + } + if (inventory.missingNames.length > 0) { + if (allowMissingIdentity) return false; + throw new Error( + `normal trusted publication cannot create missing Cargo identity ${crateName}; run the protected identity bootstrap first`, + ); + } + return false; +} + +async function cargoPublishLockedCrateExact( + crateName, + version, + suppliedCratePath = undefined, + { + alreadyPublished = undefined, + allowMissingIdentity = false, + identityCreationOnly = false, + token = process.env.CARGO_REGISTRY_TOKEN, + tokenDeadlineEpochMs = undefined, + } = {}, +) { + let locked; + locked = lockedCarrierFile(ACTIVE_PUBLICATION_LOCK, 'cargo', crateName, suppliedCratePath); + if (locked.carrier.version !== version) { + throw new Error( + `frozen cargo:${crateName} version ${locked.carrier.version} does not match requested ${version}`, + ); + } + const present = + alreadyPublished ?? + (await exactCargoVersionPublished(crateName, version, { + allowMissingIdentity, + identityCreationOnly, + })); + if (present) { + const receipt = await verifyLockedCarrierIntegrity( + ACTIVE_PUBLICATION_LOCK, + `cargo:${crateName}`, + ); + console.log( + `${crateName} ${version} is already published on crates.io with lock-matching bytes; skipping frozen upload.`, + ); + return receipt; + } + const globalDeadlineEpochMs = registryMutationDeadlineSeconds() * 1000; + const deadlineEpochMs = + tokenDeadlineEpochMs === undefined + ? globalDeadlineEpochMs + : Math.min(globalDeadlineEpochMs, tokenDeadlineEpochMs); + const result = await uploadCargoOnceAndReconcileExactVersion({ + crateName, + version, + upload: () => + publishFrozenCargoCrate({ + cratePath: locked.file, + expectedName: crateName, + expectedVersion: version, + token, + deadlineEpochMs, + }), + // identityCreationOnly protects the pre-mutation TOCTOU check above. Once + // crates.io has received the immutable upload, the name can legitimately + // precede its exact version in registry views while indexing converges. + exactVersionPublished: () => + exactCargoVersionPublished(crateName, version, { + allowMissingIdentity, + identityCreationOnly: false, + }), + waitBeforeNextProbe: () => + boundedRegistrySleep( + 10_000, + `crates.io exact-version visibility wait for ${crateName}@${version}`, + ), + }); + const receipt = await verifyLockedCarrierIntegrity(ACTIVE_PUBLICATION_LOCK, `cargo:${crateName}`); + if (result.reconciledMutationFailure) { + console.log( + `${crateName} ${version} became available after an ambiguous upload response; registry bytes match the lock.`, + ); + } + return receipt; +} + +function lockedCarrierById(carrierId) { + const matches = lockedCarriers(ACTIVE_PUBLICATION_LOCK).filter(({ id }) => id === carrierId); + if (matches.length !== 1) { + throw new Error(`publication lock contains ${matches.length} carriers for ${carrierId}`); + } + return matches[0]; +} + +async function mavenProductPublicationState(product) { + const result = await queryRegistryPackages( + lockedCarriers(ACTIVE_PUBLICATION_LOCK, { product, ecosystem: 'maven' }).map( + ({ name, version }) => ({ kind: 'maven', name, version }), + ), + ); + if (result.packages.length === 0) throw new Error('no frozen Maven coordinates for ' + product); + if (result.missing.length > 0 && result.published.length > 0) { + throw new Error( + `${product} has a partial Maven Central publication; refusing to upload a bundle that would overwrite immutable coordinates`, + ); + } + return result.missing.length === 0 ? 'published' : 'pending'; +} + +async function publishNormalMavenOperation(operation) { + const expected = new Set(operation.carrierIds); + const actual = lockedCarriers(ACTIVE_PUBLICATION_LOCK, { + products: operation.products, + ecosystem: 'maven', + }); + if (actual.length !== expected.size || actual.some(({ id }) => !expected.has(id))) { + throw new Error('normal Maven operation does not contain every selected frozen Maven carrier'); + } + const states = new Map(); + for (const product of operation.products) { + states.set(product, await mavenProductPublicationState(product)); + } + const pendingProducts = operation.products.filter((product) => states.get(product) === 'pending'); + if (pendingProducts.length === 0) { + const receipts = await verifyLockedRegistryIntegrity(ACTIVE_PUBLICATION_LOCK, { + carrierIds: operation.carrierIds, + }); + console.log( + 'Every selected Maven coordinate is already published with lock-matching bytes; skipping Maven Central upload.', + ); + return receipts; + } + if (pendingProducts.length !== operation.products.length) { + const published = operation.products.filter((product) => states.get(product) === 'published'); + throw new Error( + `selected Maven topology is partially public across products (published: ${published.join(', ')}; pending: ${pendingProducts.join(', ')}); ` + + 'refusing to replace the one atomic exact-lock deployment with product-specific phases', + ); + } + await publishLockedMavenProducts(operation.products); + const visible = await queryRegistryPackages( + actual.map(({ name, version }) => ({ kind: 'maven', name, version })), + { retries: 12, retryDelay: 10 }, + ); + if (visible.missing.length > 0) { + throw new Error( + 'Maven Central publication is not visible: ' + + visible.missing.map(({ name }) => name).join(', '), + ); + } + return await verifyLockedRegistryIntegrity(ACTIVE_PUBLICATION_LOCK, { + carrierIds: operation.carrierIds, + }); +} + +async function publishNormalCarrier(operation, headRef, context, provenReceipts) { + const carrier = lockedCarrierById(operation.carrierId); + if (carrier.product !== operation.product || carrier.ecosystem !== operation.ecosystem) { + throw new Error(`${operation.id} no longer matches its exact frozen carrier`); + } + if (provenReceipts.has(carrier.id)) { + console.log( + `${carrier.id}@${carrier.version} is covered by the complete immutable bootstrap ledger; skipping redundant registry reconciliation.`, + ); + return; + } + if (carrier.ecosystem === 'cargo') { + const locked = lockedCarrierFile(ACTIVE_PUBLICATION_LOCK, 'cargo', carrier.name); + return await cargoPublishLockedCrateExact(carrier.name, carrier.version, locked.file, { + alreadyPublished: context.alreadyPublished, + token: context.cargoToken, + tokenDeadlineEpochMs: context.tokenDeadlineEpochMs, + }); + } + throw new Error(`normal registry plan cannot publish unsupported carrier ${carrier.id}`); +} + +function requireNormalRegistryProductInputs(products) { + if (products.includes('oliphaunt-react-native')) { + requireFrozenProductArtifacts('oliphaunt-react-native', [ + path.join(ROOT, 'target/sdk-artifacts/oliphaunt-react-native'), + path.join(ROOT, 'target/release/ios-carriers'), + ]); + } + if (products.includes('oliphaunt-kotlin')) { + requireFrozenArtifacts([stagedKotlinMavenRepo()], { + products: ['oliphaunt-kotlin'], + ecosystem: 'maven', + }); + } +} + +async function prepareNormalRegistryPlan(products, headRef) { + assertPublicationLockSource(ACTIVE_PUBLICATION_LOCK, headRef); + const plan = normalPublicationPlan(ACTIVE_PUBLICATION_LOCK, products); + if (plan.carrierCount === 0) { + writeRegistryReceiptEvidence(REGISTRY_RECEIPT_EVIDENCE_PATH, ACTIVE_PUBLICATION_LOCK, { + products, + ecosystems: ['cargo', 'npm', 'maven'], + receipts: [], + }); + console.log( + 'Selected release contains no registry carriers; preserved exact empty registry receipt evidence and skipped registry mutation.', + ); + return; + } + requireNormalRegistryProductInputs(products); + const carrierProducts = [ + ...new Set(plan.operations.flatMap((operation) => operation.products)), + ].sort(compareText); + await verifyReleaseTags(carrierProducts, headRef); + const bootstrapLedger = loadBootstrapLedger( + BOOTSTRAP_LEDGER_PATH, + ACTIVE_PUBLICATION_LOCK, + products, + { + allowEmpty: true, + requireComplete: true, + }, + ); + const provenReceipts = new Map( + (bootstrapLedger?.receipts ?? []).map((receipt) => [receipt.id, receipt]), + ); + const selectedCarrierIds = new Set( + plan.operations.flatMap((operation) => + operation.kind === 'carrier' ? [operation.carrierId] : operation.carrierIds, + ), + ); + for (const id of provenReceipts.keys()) { + if (!selectedCarrierIds.has(id)) { + throw new Error( + `complete bootstrap ledger contains ${id}, which is absent from the exact normal publication plan`, + ); + } + } + console.log( + `Reconciling all ${plan.operations.length} dependency-ordered registry operations ` + + `for ${plan.carrierCount} exact frozen carriers.`, + ); + if (provenReceipts.size > 0) { + console.log( + `Reusing ${provenReceipts.size} lock-bound Cargo/npm receipts from the complete, preverified bootstrap ledger.`, + ); + } + return { + plan, + products, + headRef, + lockDigest: ACTIVE_PUBLICATION_LOCK.lockDigest, + initialReceipts: [...provenReceipts.values()], + schedule: normalPublicationSchedule(plan, process.env.CRATES_IO_TRUSTED_PUBLISH_BATCH_SIZE), + }; +} + +function registryOperationResult(directory, operation, result) { + const file = path.join(directory, 'operation-' + operation.operationOrder + '.json'); + writeFileSync(file + '.tmp', JSON.stringify(result === undefined ? [] : result), { + flag: 'wx', + mode: 0o600, + }); + renameSync(file + '.tmp', file); +} + +async function registryPhase() { + const directory = path.resolve(argv[1]); + const contextFile = path.join(directory, 'context.json'); + if (command === 'registry-prepare') { + const unexpected = unexpectedValueFlagArguments( + argv.slice(2), + new Set(['--products-json', '--head-ref']), + ); + if (unexpected.length) + throw new Error('unsupported registry arguments: ' + unexpected.join(', ')); + const products = parseProductsJson(argv.slice(2)); + const headRef = flagValue(argv.slice(2), '--head-ref') ?? 'HEAD'; + const context = await prepareNormalRegistryPlan(products, headRef); + // Empty selections still leave a complete plan for the Shell entry point. + writeFileSync( + contextFile, + JSON.stringify( + context ?? { + plan: { operations: [], carrierCount: 0 }, + products, + headRef, + lockDigest: ACTIVE_PUBLICATION_LOCK.lockDigest, + initialReceipts: [], + schedule: { cargoBatches: [], dependencies: [] }, + }, + ), + { flag: 'wx', mode: 0o600 }, + ); + return; + } + const context = JSON.parse(readFileSync(contextFile, 'utf8')); + if (context.lockDigest !== ACTIVE_PUBLICATION_LOCK.lockDigest) + throw new Error('registry state belongs to a different publication lock'); + const { plan, products, headRef } = context; + const proven = new Map(context.initialReceipts.map((receipt) => [receipt.id, receipt])); + if (command === 'registry-finish') { + const receipts = collectNormalPublicationReceipts({ + plan, + initialReceipts: context.initialReceipts, + operationResults: plan.operations.map((operation) => + JSON.parse( + readFileSync( + path.join(directory, 'operation-' + operation.operationOrder + '.json'), + 'utf8', + ), + ), + ), + }); + writeRegistryReceiptEvidence(REGISTRY_RECEIPT_EVIDENCE_PATH, ACTIVE_PUBLICATION_LOCK, { + products, + ecosystems: ['cargo', 'npm', 'maven'], + receipts: [...receipts.values()], + }); + return; + } + const index = Number(argv[2]); + if (!Number.isSafeInteger(index) || index < 0) + throw new Error('registry operation index must be a nonnegative integer'); + if (command !== 'registry-npm-after' && existsSync(path.join(directory, 'abort'))) + throw new Error('peer registry lane failed; stopping admission'); + if (command === 'registry-cargo') { + const batch = context.schedule.cargoBatches[index]; + if (!batch) throw new Error('unknown Cargo batch'); + await executeCargoPublicationBatch({ + operations: batch.map((order) => plan.operations[order]), + isAborted: () => existsSync(path.join(directory, 'abort')), + cargoVersionPublished: async (operation) => { + if (proven.has(operation.carrierId)) return true; + const carrier = lockedCarrierById(operation.carrierId); + return await exactCargoVersionPublished(carrier.name, carrier.version); + }, + publishCarrier: async (operation, tokenContext) => + registryOperationResult( + directory, + operation, + await publishNormalCarrier(operation, headRef, tokenContext, proven), + ), + }); + return; + } + const operation = plan.operations[index]; + if (!operation) throw new Error('unknown registry operation'); + if (command === 'registry-maven') { + if (operation.ecosystem !== 'maven') throw new Error('expected a Maven operation'); + registryOperationResult(directory, operation, await publishNormalMavenOperation(operation)); + return; + } + if (operation.ecosystem !== 'npm') throw new Error('expected an npm operation'); + const carrier = lockedCarrierById(operation.carrierId); + const admissionFile = path.join(directory, 'npm-' + index + '.json'); + if (command === 'registry-npm-before') { + if (proven.has(carrier.id)) { + registryOperationResult(directory, operation); + return; + } + const locked = lockedCarrierFile(ACTIVE_PUBLICATION_LOCK, 'npm', carrier.name); + const prepared = await prepareFrozenNpmPublication({ + packageName: carrier.name, + version: carrier.version, + tarball: locked.file, + deadlineEpochSeconds: registryMutationDeadlineSeconds(), + }); + if (prepared.skipped) + registryOperationResult( + directory, + operation, + await verifyLockedCarrierIntegrity(ACTIVE_PUBLICATION_LOCK, carrier.id), + ); + else writeFileSync(admissionFile, JSON.stringify(prepared), { flag: 'wx', mode: 0o600 }); + } else { + // Reconciliation is mandatory even if npm returned an ambiguous failure. + const prepared = JSON.parse(readFileSync(admissionFile, 'utf8')); + await reconcileFrozenNpmPublication(prepared); + registryOperationResult( + directory, + operation, + await verifyLockedCarrierIntegrity(ACTIVE_PUBLICATION_LOCK, carrier.id), + ); + } +} + +if (registryPhases.has(command)) { + try { + await registryPhase(); + } catch (cause) { + if (isRegistryPublicationDeferredError(cause)) exitTypedRegistryDeferral(cause); + throw cause; + } + process.exit(0); +} + +async function bootstrapPhase() { + if (!BOOTSTRAP_IDENTITIES) + throw new Error('bootstrap phases require explicit identity bootstrap mode'); + const directory = path.resolve(argv[1]); + const context = JSON.parse(readFileSync(path.join(directory, 'context.json'), 'utf8')); + if (context.lockDigest !== ACTIVE_PUBLICATION_LOCK.lockDigest) + throw new Error('bootstrap state belongs to another publication lock'); + const index = Number(argv[2]); + if (!Number.isSafeInteger(index) || index < 0 || !context.admittedPlan[index]) + throw new Error('unknown bootstrap operation'); + if (command !== 'bootstrap-npm-after' && existsSync(path.join(directory, 'abort'))) + throw new Error('peer bootstrap lane stopped admission'); + const carrier = lockedCarrierById(context.admittedPlan[index].id); + const operation = { operationOrder: index }; + if (command === 'bootstrap-cargo') { + if (carrier.ecosystem !== 'cargo') throw new Error('expected a Cargo bootstrap operation'); + registryOperationResult( + directory, + operation, + await cargoPublishLockedCrateExact(carrier.name, carrier.version, undefined, { + allowMissingIdentity: true, + identityCreationOnly: true, + }), + ); + return; + } + if (carrier.ecosystem !== 'npm') throw new Error('expected an npm bootstrap operation'); + const admission = path.join(directory, 'npm-' + index + '.json'); + if (command === 'bootstrap-npm-before') { + const locked = lockedCarrierFile(ACTIVE_PUBLICATION_LOCK, 'npm', carrier.name); + const prepared = await prepareFrozenNpmPublication({ + packageName: carrier.name, + version: carrier.version, + tarball: locked.file, + deadlineEpochSeconds: registryMutationDeadlineSeconds(), + identityCreationOnly: true, + }); + if (prepared.skipped) + registryOperationResult( + directory, + operation, + await verifyLockedCarrierIntegrity(ACTIVE_PUBLICATION_LOCK, carrier.id), + ); + else writeFileSync(admission, JSON.stringify(prepared), { flag: 'wx', mode: 0o600 }); + } else { + await reconcileFrozenNpmPublication(JSON.parse(readFileSync(admission, 'utf8'))); + registryOperationResult( + directory, + operation, + await verifyLockedCarrierIntegrity(ACTIVE_PUBLICATION_LOCK, carrier.id), + ); + } +} + +if (bootstrapPhases.has(command)) { + try { + await bootstrapPhase(); + } catch (cause) { + if (isRegistryPublicationDeferredError(cause)) exitTypedRegistryDeferral(cause); + throw cause; + } + process.exit(0); +} + +const publishProductStep = publishProductStepPlan(argv.slice(1)); +const normalRegistryPlanSelected = argv.slice(1).includes('--registry-plan'); +if (BOOTSTRAP_IDENTITIES) + fail('use bash .github/scripts/bootstrap-registry-identities.sh for bootstrap'); +if (normalRegistryPlanSelected) { + fail('use bash tools/release/publish-registries.sh for registry publication'); +} +if ( + command === 'publish' && + flagValue(argv.slice(1), '--step') === 'github-release-assets' && + flagValue(argv.slice(1), '--product') === null +) { + const requested = parseProductsJson(argv.slice(1)); + if (requested !== null) { + await publishSelectedGithubReleaseAssetSets( + releaseOrderedProducts(requested), + flagValue(argv.slice(1), '--head-ref') ?? 'HEAD', + ); + process.exit(0); + } +} + +fail(`unsupported publish arguments: ${argv.slice(1).join(' ') || ''}`); diff --git a/tools/release/release-test-environment.test.mts b/tools/release/release-test-environment.test.mts new file mode 100644 index 000000000..ee2028809 --- /dev/null +++ b/tools/release/release-test-environment.test.mts @@ -0,0 +1,21 @@ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; +import { isolatedGitHubTestEnvironment as mutationTestEnvironment } from './testdata/isolated-github-test-environment.mts'; + +test('release mutation tests cannot consume a live publish request journal', () => { + assert.deepEqual( + mutationTestEnvironment( + {}, + { + GITHUB_ACTIONS: 'true', + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_RUN_ID: '30593859032', + KEEP_ME: 'preserved', + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: '/live/journal.json', + OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: 'true', + RELEASE_HEAD_SHA: 'a'.repeat(40), + }, + ), + { KEEP_ME: 'preserved' }, + ); +}); diff --git a/tools/release/release-transport-ref.test.mjs b/tools/release/release-transport-ref.test.mjs deleted file mode 100644 index 5cfd95518..000000000 --- a/tools/release/release-transport-ref.test.mjs +++ /dev/null @@ -1,345 +0,0 @@ -import assert from "node:assert/strict"; -import { readFileSync } from "node:fs"; -import test from "node:test"; - -import { - RELEASE_TRANSPORT_MAX_RESPONSE_BYTES, - RELEASE_TRANSPORT_TAG_PREFIX, - ensureReleaseTransportRef, - normalizeReleaseTransportCommit, - releaseTransportFullRef, - releaseTransportTagName, - validateReleaseTransportRef, - verifyReleaseTransportRef, -} from "../../.github/scripts/release-transport-ref.mjs"; - -const SHA = "84d90b9853530ab72e48a1aa6fb616aaed7a0dc6"; -const OTHER_SHA = "1111111111111111111111111111111111111111"; -const REPO = "f0rr0/oliphaunt"; -const TOKEN = "test-token"; -const FULL_REF = `refs/tags/${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}`; -const SOURCE = readFileSync( - new URL("../../.github/scripts/release-transport-ref.mjs", import.meta.url), - "utf8", -); - -function exactRef(sha = SHA) { - return { - ref: `refs/tags/${RELEASE_TRANSPORT_TAG_PREFIX}${sha}`, - object: { sha, type: "commit", url: `https://api.github.com/repos/${REPO}/git/commits/${sha}` }, - url: `https://api.github.com/repos/${REPO}/git/refs/tags/${RELEASE_TRANSPORT_TAG_PREFIX}${sha}`, - }; -} - -function jsonResponse(value, status = 200) { - return new Response(JSON.stringify(value), { - headers: { "Content-Type": "application/json" }, - status, - }); -} - -function environment(overrides = {}) { - return { - GH_REPO: REPO, - GH_TOKEN: TOKEN, - ...overrides, - }; -} - -function rootEnvironment(operation, runAttempt = 1, overrides = {}) { - return environment({ - GITHUB_ACTIONS: "true", - GITHUB_REF: "refs/heads/main", - GITHUB_RUN_ATTEMPT: String(runAttempt), - GITHUB_SHA: SHA, - RELEASE_OPERATION: operation, - ...overrides, - }); -} - -test("transport names normalize one exact full commit into an unambiguous lightweight-tag ref", () => { - assert.equal(normalizeReleaseTransportCommit(SHA.toUpperCase()), SHA); - assert.equal(releaseTransportTagName(SHA), `${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}`); - assert.equal(releaseTransportFullRef(SHA), FULL_REF); - assert.deepEqual(validateReleaseTransportRef(exactRef(), SHA), { - commit: SHA, - fullRef: FULL_REF, - tag: `${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}`, - }); - for (const invalid of [ - { ...exactRef(), ref: `${FULL_REF}-wrong` }, - { ...exactRef(), object: { sha: OTHER_SHA, type: "commit" } }, - { ...exactRef(), object: { sha: SHA, type: "tag" } }, - ]) { - assert.throws( - () => validateReleaseTransportRef(invalid, SHA), - /does not point directly to exact release commit/u, - ); - } - for (const invalid of ["", "abc", `${SHA}0`, "z".repeat(40)]) { - assert.throws(() => normalizeReleaseTransportCommit(invalid), /full lowercase-compatible 40-character SHA/u); - } -}); - -test("an exact existing transport bypasses moving main only for genuine root reruns", async () => { - for (const [contentWriteAdmission, operation] of [ - ["pre-reserved", "publish"], - ["isolated-bootstrap", "publish-bootstrap"], - ]) { - let firstAttemptProofs = 0; - const firstAttempt = await ensureReleaseTransportRef({ - commit: SHA, - contentWriteAdmission, - environment: rootEnvironment(operation), - fetchImpl: async () => jsonResponse(exactRef()), - proveCurrentMain: async () => { firstAttemptProofs += 1; }, - }); - assert.equal(firstAttempt.created, false); - assert.equal(firstAttemptProofs, 1); - - const calls = []; - const rerun = await ensureReleaseTransportRef({ - commit: SHA, - contentWriteAdmission, - environment: rootEnvironment(operation, 2), - fetchImpl: async (url, init) => { - calls.push({ init, url: String(url) }); - return jsonResponse(exactRef()); - }, - proveCurrentMain: async () => { - throw new Error("a genuine exact rerun must not re-evaluate moving main"); - }, - }); - assert.deepEqual(rerun, { - commit: SHA, - created: false, - fullRef: FULL_REF, - tag: `${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}`, - }); - assert.equal(calls.length, 1); - assert.equal(calls[0].init.method, "GET"); - assert.match(calls[0].url, new RegExp(`/git/ref/tags/${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}$`, "u")); - } - - const firstAttemptMethods = []; - await assert.rejects( - () => ensureReleaseTransportRef({ - commit: SHA, - contentWriteAdmission: "pre-reserved", - environment: rootEnvironment("publish"), - fetchImpl: async (_url, init) => { - firstAttemptMethods.push(init.method); - return jsonResponse(exactRef()); - }, - proveCurrentMain: async () => { - throw new Error("first attempt observed stale main"); - }, - }), - /first attempt observed stale main/u, - ); - assert.deepEqual(firstAttemptMethods, ["GET"]); -}); - -test("ensure creates one exact lightweight tag after proving it absent", async () => { - const calls = []; - const events = []; - const responses = [new Response("not found", { status: 404 }), jsonResponse(exactRef(), 201)]; - const result = await ensureReleaseTransportRef({ - commit: SHA.toUpperCase(), - contentWriteAdmission: "pre-reserved", - environment: rootEnvironment("publish"), - fetchImpl: async (url, init) => { - events.push(init.method); - calls.push({ init, url: String(url) }); - return responses.shift(); - }, - proveCurrentMain: async ({ commit, environment: proofEnvironment }) => { - events.push("PROVE_CURRENT_MAIN"); - assert.equal(commit, SHA); - assert.equal(proofEnvironment.GITHUB_SHA, SHA); - }, - }); - assert.equal(result.created, true); - assert.deepEqual(calls.map(({ init }) => init.method), ["GET", "POST"]); - assert.deepEqual(JSON.parse(calls[1].init.body), { ref: FULL_REF, sha: SHA }); - assert.equal(new Headers(calls[1].init.headers).get("authorization"), `Bearer ${TOKEN}`); - assert.ok(calls.every(({ init }) => init.redirect === "error" && init.signal instanceof AbortSignal)); - assert.deepEqual(events, ["GET", "PROVE_CURRENT_MAIN", "POST"]); -}); - -test("an absent transport fails closed before POST when current-main proof fails", async () => { - const methods = []; - await assert.rejects( - () => ensureReleaseTransportRef({ - commit: SHA, - contentWriteAdmission: "pre-reserved", - environment: rootEnvironment("publish", 3), - fetchImpl: async (_url, init) => { - methods.push(init.method); - return new Response("missing", { status: 404 }); - }, - proveCurrentMain: async () => { - throw new Error("main advanced"); - }, - }), - /main advanced/u, - ); - assert.deepEqual(methods, ["GET"]); -}); - -test("an ambiguous create response is reconciled by one exact read and never replayed", async () => { - for (const ambiguous of [ - () => new Response("temporarily unavailable", { status: 503 }), - () => { throw new TypeError("connection reset after upload"); }, - ]) { - const methods = []; - const fetchImpl = async (_url, init) => { - methods.push(init.method); - if (methods.length === 1) return new Response("missing", { status: 404 }); - if (methods.length === 2) return ambiguous(); - return jsonResponse(exactRef()); - }; - const result = await ensureReleaseTransportRef({ - commit: SHA, - contentWriteAdmission: "pre-reserved", - environment: rootEnvironment("publish"), - fetchImpl, - proveCurrentMain: async () => {}, - }); - assert.equal(result.created, true); - assert.deepEqual(methods, ["GET", "POST", "GET"]); - } -}); - -test("ensure rejects collisions and failed reconciliation without update, delete, or create replay", async () => { - let calls = 0; - let proofs = 0; - for (const invalid of [ - { ...exactRef(), object: { sha: OTHER_SHA, type: "commit" } }, - { ...exactRef(), object: { sha: SHA, type: "tag" } }, - ]) { - await assert.rejects( - () => ensureReleaseTransportRef({ - commit: SHA, - contentWriteAdmission: "pre-reserved", - environment: rootEnvironment("publish", 2), - fetchImpl: async () => { - calls += 1; - return jsonResponse(invalid); - }, - proveCurrentMain: async () => { proofs += 1; }, - }), - /does not point directly to exact release commit/u, - ); - } - assert.equal(calls, 2, "an occupied wrong or annotated ref must fail before mutation"); - assert.equal(proofs, 0, "an invalid existing ref must fail before any current-main bypass"); - - const methods = []; - await assert.rejects( - () => ensureReleaseTransportRef({ - commit: SHA, - contentWriteAdmission: "pre-reserved", - environment: rootEnvironment("publish"), - fetchImpl: async (_url, init) => { - methods.push(init.method); - return init.method === "POST" - ? new Response("unavailable", { status: 503 }) - : new Response("missing", { status: 404 }); - }, - proveCurrentMain: async () => {}, - }), - /create returned HTTP 503/u, - ); - assert.deepEqual(methods, ["GET", "POST", "GET"]); - assert.doesNotMatch(SOURCE, /method:\s*["'](?:PATCH|DELETE)["']/u); -}); - -test("verify accepts only an existing exact direct commit ref", async () => { - assert.equal((await verifyReleaseTransportRef({ - commit: SHA, - environment: environment(), - fetchImpl: async () => jsonResponse(exactRef()), - })).commit, SHA); - await assert.rejects( - () => verifyReleaseTransportRef({ - commit: SHA, - environment: environment(), - fetchImpl: async () => new Response("missing", { status: 404 }), - }), - /does not exist/u, - ); -}); - -test("pre-reserved and isolated-bootstrap admissions are exact root-run-only", async () => { - for (const [contentWriteAdmission, operation, wrongOperation] of [ - ["pre-reserved", "publish", "publish-bootstrap"], - ["isolated-bootstrap", "publish-bootstrap", "publish"], - ]) { - for (const overrides of [ - { GITHUB_ACTIONS: "false" }, - { GITHUB_REF: FULL_REF }, - { GITHUB_RUN_ATTEMPT: undefined }, - { GITHUB_RUN_ATTEMPT: "0" }, - { GITHUB_RUN_ATTEMPT: "01" }, - { GITHUB_RUN_ATTEMPT: "not-a-number" }, - { GITHUB_RUN_ATTEMPT: "9".repeat(100) }, - { GITHUB_SHA: OTHER_SHA }, - { RELEASE_OPERATION: wrongOperation }, - ]) { - let fetchCalls = 0; - await assert.rejects( - () => ensureReleaseTransportRef({ - commit: SHA, - contentWriteAdmission, - environment: rootEnvironment(operation, 1, overrides), - fetchImpl: async () => { - fetchCalls += 1; - return new Response("missing", { status: 404 }); - }, - proveCurrentMain: async () => {}, - }), - new RegExp(`${contentWriteAdmission} admission requires the exact root ${operation} GitHub run`, "u"), - ); - assert.equal(fetchCalls, 0); - } - } - - await assert.rejects( - () => ensureReleaseTransportRef({ - commit: SHA, - environment: rootEnvironment("publish"), - fetchImpl: async () => new Response("missing", { status: 404 }), - proveCurrentMain: async () => {}, - }), - /OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH is required/u, - ); -}); - -test("transport responses and credentials remain bounded and validated", async () => { - await assert.rejects( - () => verifyReleaseTransportRef({ - commit: SHA, - environment: environment(), - fetchImpl: async () => new Response("", { - headers: { "Content-Length": String(RELEASE_TRANSPORT_MAX_RESPONSE_BYTES + 1) }, - status: 200, - }), - }), - /oversized Content-Length/u, - ); - for (const options of [ - { repo: "not-a-repository", token: TOKEN }, - { repo: REPO, token: "bad\ntoken" }, - ]) { - await assert.rejects( - () => verifyReleaseTransportRef({ - commit: SHA, - environment: {}, - fetchImpl: async () => jsonResponse(exactRef()), - ...options, - }), - /GH_(?:REPO|TOKEN)/u, - ); - } -}); diff --git a/tools/release/release-transport-ref.test.mts b/tools/release/release-transport-ref.test.mts new file mode 100644 index 000000000..fbad3eaba --- /dev/null +++ b/tools/release/release-transport-ref.test.mts @@ -0,0 +1,406 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { + ensureReleaseTransportRef, + normalizeReleaseTransportCommit, + proveCurrentMain, + RELEASE_TRANSPORT_MAX_RESPONSE_BYTES, + RELEASE_TRANSPORT_TAG_PREFIX, + releaseTransportFullRef, + releaseTransportTagName, + validateReleaseTransportRef, + verifyReleaseTransportRef, +} from '../../.github/scripts/release-transport-ref.mts'; + +const SHA = '84d90b9853530ab72e48a1aa6fb616aaed7a0dc6'; +const OTHER_SHA = '1111111111111111111111111111111111111111'; +const REPO = 'f0rr0/oliphaunt'; +const TOKEN = 'test-token'; +const FULL_REF = `refs/tags/${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}`; +function exactRef(sha = SHA) { + return { + ref: `refs/tags/${RELEASE_TRANSPORT_TAG_PREFIX}${sha}`, + object: { sha, type: 'commit', url: `https://api.github.com/repos/${REPO}/git/commits/${sha}` }, + url: `https://api.github.com/repos/${REPO}/git/refs/tags/${RELEASE_TRANSPORT_TAG_PREFIX}${sha}`, + }; +} + +function jsonResponse(value, status = 200) { + return new Response(JSON.stringify(value), { + headers: { 'Content-Type': 'application/json' }, + status, + }); +} + +function environment(overrides = {}) { + return { + GH_REPO: REPO, + GH_TOKEN: TOKEN, + ...overrides, + }; +} + +function rootEnvironment(operation, runAttempt = 1, overrides = {}) { + return environment({ + GITHUB_ACTIONS: 'true', + GITHUB_REF: 'refs/heads/main', + GITHUB_RUN_ATTEMPT: String(runAttempt), + GITHUB_SHA: SHA, + RELEASE_OPERATION: operation, + ...overrides, + }); +} + +test('transport names normalize one exact full commit into an unambiguous lightweight-tag ref', () => { + assert.equal(normalizeReleaseTransportCommit(SHA.toUpperCase()), SHA); + assert.equal(releaseTransportTagName(SHA), `${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}`); + assert.equal(releaseTransportFullRef(SHA), FULL_REF); + assert.deepEqual(validateReleaseTransportRef(exactRef(), SHA), { + commit: SHA, + fullRef: FULL_REF, + tag: `${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}`, + }); + for (const invalid of [ + { ...exactRef(), ref: `${FULL_REF}-wrong` }, + { ...exactRef(), object: { sha: OTHER_SHA, type: 'commit' } }, + { ...exactRef(), object: { sha: SHA, type: 'tag' } }, + ]) { + assert.throws( + () => validateReleaseTransportRef(invalid, SHA), + /does not point directly to exact release commit/u, + ); + } + for (const invalid of ['', 'abc', `${SHA}0`, 'z'.repeat(40)]) { + assert.throws( + () => normalizeReleaseTransportCommit(invalid), + /full lowercase-compatible 40-character SHA/u, + ); + } +}); + +test('an exact existing transport bypasses moving main only for genuine root reruns', async () => { + for (const [contentWriteAdmission, operation] of [ + ['pre-reserved', 'publish'], + ['isolated-bootstrap', 'publish-bootstrap'], + ]) { + let firstAttemptProofs = 0; + const firstAttempt = await ensureReleaseTransportRef({ + commit: SHA, + contentWriteAdmission, + environment: rootEnvironment(operation), + fetchImpl: async () => jsonResponse(exactRef()), + proveCurrentMain: async () => { + firstAttemptProofs += 1; + }, + }); + assert.equal(firstAttempt.created, false); + assert.equal(firstAttemptProofs, 1); + + const calls = []; + const rerun = await ensureReleaseTransportRef({ + commit: SHA, + contentWriteAdmission, + environment: rootEnvironment(operation, 2), + fetchImpl: async (url, init) => { + calls.push({ init, url: String(url) }); + return jsonResponse(exactRef()); + }, + proveCurrentMain: async () => { + throw new Error('a genuine exact rerun must not re-evaluate moving main'); + }, + }); + assert.deepEqual(rerun, { + commit: SHA, + created: false, + fullRef: FULL_REF, + tag: `${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}`, + }); + assert.equal(calls.length, 1); + assert.equal(calls[0].init.method, 'GET'); + assert.match( + calls[0].url, + new RegExp(`/git/ref/tags/${RELEASE_TRANSPORT_TAG_PREFIX}${SHA}$`, 'u'), + ); + } + + const firstAttemptMethods = []; + await assert.rejects( + () => + ensureReleaseTransportRef({ + commit: SHA, + contentWriteAdmission: 'pre-reserved', + environment: rootEnvironment('publish'), + fetchImpl: async (_url, init) => { + firstAttemptMethods.push(init.method); + return jsonResponse(exactRef()); + }, + proveCurrentMain: async () => { + throw new Error('first attempt observed stale main'); + }, + }), + /first attempt observed stale main/u, + ); + assert.deepEqual(firstAttemptMethods, ['GET']); +}); + +test('ensure creates one exact lightweight tag after proving it absent', async () => { + const calls = []; + const events = []; + const responses = [new Response('not found', { status: 404 }), jsonResponse(exactRef(), 201)]; + const result = await ensureReleaseTransportRef({ + commit: SHA.toUpperCase(), + contentWriteAdmission: 'pre-reserved', + environment: rootEnvironment('publish'), + fetchImpl: async (url, init) => { + events.push(init.method); + calls.push({ init, url: String(url) }); + return responses.shift(); + }, + proveCurrentMain: async ({ commit, environment: proofEnvironment }) => { + events.push('PROVE_CURRENT_MAIN'); + assert.equal(commit, SHA); + assert.equal(proofEnvironment.GITHUB_SHA, SHA); + }, + }); + assert.equal(result.created, true); + assert.deepEqual( + calls.map(({ init }) => init.method), + ['GET', 'POST'], + ); + assert.deepEqual(JSON.parse(calls[1].init.body), { ref: FULL_REF, sha: SHA }); + assert.equal(new Headers(calls[1].init.headers).get('authorization'), `Bearer ${TOKEN}`); + assert.ok( + calls.every(({ init }) => init.redirect === 'error' && init.signal instanceof AbortSignal), + ); + assert.deepEqual(events, ['GET', 'PROVE_CURRENT_MAIN', 'POST']); +}); + +test('an absent transport fails closed before POST when current-main proof fails', async () => { + const methods = []; + await assert.rejects( + () => + ensureReleaseTransportRef({ + commit: SHA, + contentWriteAdmission: 'pre-reserved', + environment: rootEnvironment('publish', 3), + fetchImpl: async (_url, init) => { + methods.push(init.method); + return new Response('missing', { status: 404 }); + }, + proveCurrentMain: async () => { + throw new Error('main advanced'); + }, + }), + /main advanced/u, + ); + assert.deepEqual(methods, ['GET']); +}); + +test('an ambiguous create response is reconciled by one exact read and never replayed', async () => { + for (const ambiguous of [ + () => new Response('temporarily unavailable', { status: 503 }), + () => { + throw new TypeError('connection reset after upload'); + }, + ]) { + const methods = []; + const fetchImpl = async (_url, init) => { + methods.push(init.method); + if (methods.length === 1) return new Response('missing', { status: 404 }); + if (methods.length === 2) return ambiguous(); + return jsonResponse(exactRef()); + }; + const result = await ensureReleaseTransportRef({ + commit: SHA, + contentWriteAdmission: 'pre-reserved', + environment: rootEnvironment('publish'), + fetchImpl, + proveCurrentMain: async () => {}, + }); + assert.equal(result.created, true); + assert.deepEqual(methods, ['GET', 'POST', 'GET']); + } +}); + +test('ensure rejects collisions and failed reconciliation without update, delete, or create replay', async () => { + let calls = 0; + let proofs = 0; + for (const invalid of [ + { ...exactRef(), object: { sha: OTHER_SHA, type: 'commit' } }, + { ...exactRef(), object: { sha: SHA, type: 'tag' } }, + ]) { + await assert.rejects( + () => + ensureReleaseTransportRef({ + commit: SHA, + contentWriteAdmission: 'pre-reserved', + environment: rootEnvironment('publish', 2), + fetchImpl: async () => { + calls += 1; + return jsonResponse(invalid); + }, + proveCurrentMain: async () => { + proofs += 1; + }, + }), + /does not point directly to exact release commit/u, + ); + } + assert.equal(calls, 2, 'an occupied wrong or annotated ref must fail before mutation'); + assert.equal(proofs, 0, 'an invalid existing ref must fail before any current-main bypass'); + + const methods = []; + await assert.rejects( + () => + ensureReleaseTransportRef({ + commit: SHA, + contentWriteAdmission: 'pre-reserved', + environment: rootEnvironment('publish'), + fetchImpl: async (_url, init) => { + methods.push(init.method); + return init.method === 'POST' + ? new Response('unavailable', { status: 503 }) + : new Response('missing', { status: 404 }); + }, + proveCurrentMain: async () => {}, + }), + /create returned HTTP 503/u, + ); + assert.deepEqual(methods, ['GET', 'POST', 'GET']); +}); + +test('verify accepts only an existing exact direct commit ref', async () => { + assert.equal( + ( + await verifyReleaseTransportRef({ + commit: SHA, + environment: environment(), + fetchImpl: async () => jsonResponse(exactRef()), + }) + ).commit, + SHA, + ); + await assert.rejects( + () => + verifyReleaseTransportRef({ + commit: SHA, + environment: environment(), + fetchImpl: async () => new Response('missing', { status: 404 }), + }), + /does not exist/u, + ); +}); + +test('pre-reserved and isolated-bootstrap admissions are exact root-run-only', async () => { + for (const [contentWriteAdmission, operation, wrongOperation] of [ + ['pre-reserved', 'publish', 'publish-bootstrap'], + ['isolated-bootstrap', 'publish-bootstrap', 'publish'], + ]) { + for (const overrides of [ + { GITHUB_ACTIONS: 'false' }, + { GITHUB_REF: FULL_REF }, + { GITHUB_RUN_ATTEMPT: undefined }, + { GITHUB_RUN_ATTEMPT: '0' }, + { GITHUB_RUN_ATTEMPT: '01' }, + { GITHUB_RUN_ATTEMPT: 'not-a-number' }, + { GITHUB_RUN_ATTEMPT: '9'.repeat(100) }, + { GITHUB_SHA: OTHER_SHA }, + { RELEASE_OPERATION: wrongOperation }, + ]) { + let fetchCalls = 0; + await assert.rejects( + () => + ensureReleaseTransportRef({ + commit: SHA, + contentWriteAdmission, + environment: rootEnvironment(operation, 1, overrides), + fetchImpl: async () => { + fetchCalls += 1; + return new Response('missing', { status: 404 }); + }, + proveCurrentMain: async () => {}, + }), + new RegExp( + `${contentWriteAdmission} admission requires the exact root ${operation} GitHub run`, + 'u', + ), + ); + assert.equal(fetchCalls, 0); + } + } + + await assert.rejects( + () => + ensureReleaseTransportRef({ + commit: SHA, + environment: rootEnvironment('publish'), + fetchImpl: async () => new Response('missing', { status: 404 }), + proveCurrentMain: async () => {}, + }), + /OLIPHAUNT_GITHUB_CONTENT_WRITE_PACER_PATH is required/u, + ); +}); + +test('transport responses and credentials remain bounded and validated', async () => { + await assert.rejects( + () => + verifyReleaseTransportRef({ + commit: SHA, + environment: environment(), + fetchImpl: async () => + new Response('', { + headers: { 'Content-Length': String(RELEASE_TRANSPORT_MAX_RESPONSE_BYTES + 1) }, + status: 200, + }), + }), + /oversized Content-Length/u, + ); + for (const options of [ + { repo: 'not-a-repository', token: TOKEN }, + { repo: REPO, token: 'bad\ntoken' }, + ]) { + await assert.rejects( + () => + verifyReleaseTransportRef({ + commit: SHA, + environment: {}, + fetchImpl: async () => jsonResponse(exactRef()), + ...options, + }), + /GH_(?:REPO|TOKEN)/u, + ); + } +}); + +test('current-main proof checks the authenticated exact branch ref and fails closed', async () => { + const observed = []; + const invoke = (value, status = 200, env = rootEnvironment('publish')) => + proveCurrentMain({ + commit: SHA, + environment: env, + fetchImpl: async (url, init) => { + observed.push({ url, init }); + return jsonResponse(value, status); + }, + }); + const ref = { ref: 'refs/heads/main', object: { type: 'commit', sha: SHA } }; + await invoke(ref); + assert.equal(observed[0].url, `https://api.github.com/repos/${REPO}/git/ref/heads/main`); + assert.equal(observed[0].init.redirect, 'error'); + assert.equal(new Headers(observed[0].init.headers).get('authorization'), `Bearer ${TOKEN}`); + for (const value of [ + null, + { ...ref, ref: 'refs/heads/other' }, + { ...ref, object: { type: 'tag', sha: SHA } }, + { ...ref, object: { type: 'commit', sha: OTHER_SHA } }, + ]) { + await assert.rejects(() => invoke(value), /main moved|invalid commit ref/u); + } + await assert.rejects(() => invoke({}, 403), /HTTP 403/u); + const before = observed.length; + await assert.rejects( + () => invoke(ref, 200, environment({ GITHUB_REF: 'refs/heads/other' })), + /dispatched from main/u, + ); + assert.equal(observed.length, before); +}); diff --git a/tools/release/release-transport-ref.test.sh b/tools/release/release-transport-ref.test.sh new file mode 100644 index 000000000..9c48fd654 --- /dev/null +++ b/tools/release/release-transport-ref.test.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/release-transport-ref.test.mts +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +cat > "$scratch/fetch.mts" <<'TS' +globalThis.fetch = async () => Response.json(JSON.parse(process.env.TEST_REF!)); +TS +sha=84d90b9853530ab72e48a1aa6fb616aaed7a0dc6 +# Derive the current transport ref shape through its public helper. +bun -e 'import {releaseTransportFullRef} from "./.github/scripts/release-transport-ref.mts"; const sha=process.argv[1]; console.log(JSON.stringify({ref:releaseTransportFullRef(sha),object:{sha,type:"commit"}}))' "$sha" > "$scratch/ref" +run_cli() { + env -i PATH="$PATH" HOME="$HOME" GH_REPO=f0rr0/oliphaunt GH_TOKEN=test-token \ + TEST_REF="$1" bun --preload "$scratch/fetch.mts" \ + .github/scripts/release-transport-ref.mts verify "$sha" > "$scratch/result" 2>&1 +} +run_cli "$(cat "$scratch/ref")" +rg -q 'verified refs/tags' "$scratch/result" +if run_cli '{}'; then echo 'Invalid remote ref was accepted' >&2; exit 1; fi +rg -q 'does not point directly' "$scratch/result" +if rg -q 'TypeError|Unhandled' "$scratch/result"; then cat "$scratch/result" >&2; exit 1; fi +echo 'Release transport CLI: exact remote ref and rejected read passed' diff --git a/tools/release/release-verification-shell.test.sh b/tools/release/release-verification-shell.test.sh new file mode 100644 index 000000000..809bdd486 --- /dev/null +++ b/tools/release/release-verification-shell.test.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +export TEST_BUN_VERSION="$(bun --version)" CALL_LOG="$scratch/calls" +cat > "$scratch/bun" <<'SH' +#!/usr/bin/env bash +if [[ "${1:-}" == --version ]]; then echo "$TEST_BUN_VERSION"; exit 0; fi +printf '%s\0' "$@" >> "$CALL_LOG" +printf '\n' >> "$CALL_LOG" +[[ "$1" != "${FAIL_GATE:-}" ]] || exit 9 +SH +chmod +x "$scratch/bun" +export PATH="$scratch:$PATH" +products='["oliphaunt-js", "oliphaunt-rust"]' +head_commit="$(git rev-parse HEAD)" +args=(--products-json "$products" --head-ref "$head_commit" --publication-lock='lock file.json' \ + --registry-receipts 'registry file.json' --github-release-receipt 'github file.json') +run() { : > "$CALL_LOG"; bash "tools/release/$1" "${@:2}" > "$scratch/output" 2>&1; } +record() { printf '%s\0' "$@"; printf '\n'; } +run release-verify.sh "${args[@]}" +cp "$CALL_LOG" "$scratch/success" +record tools/release/registry-integrity.mts --lock 'lock file.json' --products-json "$products" \ + --verify-receipts 'registry file.json' --sealed-receipts > "$scratch/expected" +head -n 1 "$CALL_LOG" > "$scratch/actual" +cmp "$scratch/expected" "$scratch/actual" +record tools/release/verify_github_release_attestations.mts finalize --publication-lock 'lock file.json' \ + --products-json "$products" --head-ref "$head_commit" --receipt 'github file.json' > "$scratch/expected" +tail -n 1 "$CALL_LOG" > "$scratch/actual" +cmp "$scratch/expected" "$scratch/actual" +index=0 +while IFS= read -r gate; do + index=$((index+1)) + status=0 + FAIL_GATE="$gate" run release-verify.sh "${args[@]}" || status=$? + [[ "$status" == 2 ]] + head -n "$index" "$scratch/success" > "$scratch/expected" + cmp "$scratch/expected" "$CALL_LOG" +done < <(tr '\0' '\t' < "$scratch/success" | cut -f 1) +status=0 +run release-verify.sh "${args[@]:0:7}" || status=$? +[[ "$status" == 2 && ! -s "$CALL_LOG" ]] +run release-check-registries.sh --products-json "$products" --require-identities +cp "$CALL_LOG" "$scratch/registry-success" +record tools/release/check_registry_publication.mts --products-json "$products" --require-identities > "$scratch/expected" +tail -n 1 "$CALL_LOG" > "$scratch/actual" +cmp "$scratch/expected" "$scratch/actual" +first_gate="$(tr '\0' '\t' < "$scratch/registry-success" | head -n 1 | cut -f 1)" +status=0 +FAIL_GATE="$first_gate" run release-check-registries.sh --products-json "$products" --require-identities || status=$? +[[ "$status" == 2 ]] +head -n 1 "$scratch/registry-success" > "$scratch/expected" +cmp "$scratch/expected" "$CALL_LOG" +echo 'Release verification: receipt arguments preserved and failed gates stop subsequent work' diff --git a/tools/release/release-verify.mjs b/tools/release/release-verify.mjs deleted file mode 100644 index 45249f313..000000000 --- a/tools/release/release-verify.mjs +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env bun -import { fail, run } from "./release-cli-utils.mjs"; - -const TOOL = "release-verify.mjs"; - -function removeValueFlag(argv, flag) { - const output = []; - let value = ""; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === flag) { - if (index + 1 >= argv.length) fail(TOOL, `${flag} requires a value`); - value = argv[index + 1]; - index += 1; - } else if (arg.startsWith(`${flag}=`)) { - value = arg.slice(flag.length + 1); - } else { - output.push(arg); - } - } - return { argv: output, value }; -} - -function flagValue(argv, flag) { - for (let index = 0; index < argv.length; index += 1) { - if (argv[index] === flag) return argv[index + 1] ?? ""; - if (argv[index].startsWith(`${flag}=`)) return argv[index].slice(flag.length + 1); - } - return ""; -} - -function main(rawArgv) { - const githubReceipt = removeValueFlag(rawArgv, "--github-release-receipt"); - const receipts = removeValueFlag(githubReceipt.argv, "--registry-receipts"); - const lock = removeValueFlag(receipts.argv, "--publication-lock"); - const argv = lock.argv; - if (argv.includes("-h") || argv.includes("--help")) { - console.log("usage: tools/release/release-verify.mjs [--products-json JSON] [--head-ref REF] [--publication-lock FILE --registry-receipts FILE --github-release-receipt FILE]"); - process.exit(0); - } - if (new Set([Boolean(lock.value), Boolean(receipts.value), Boolean(githubReceipt.value)]).size !== 1) { - fail(TOOL, "--publication-lock, --registry-receipts, and --github-release-receipt must be supplied together"); - } - if (receipts.value) { - const productsJson = flagValue(argv, "--products-json"); - if (!productsJson) fail(TOOL, "--products-json is required with immutable registry receipt evidence"); - run(TOOL, [ - process.execPath, - "tools/release/registry-integrity.mjs", - "--lock", - lock.value, - "--products-json", - productsJson, - "--verify-receipts", - receipts.value, - "--sealed-receipts", - ], { failExitCode: 2 }); - run(TOOL, [process.execPath, "tools/release/check_release_versions.mjs", ...argv], { failExitCode: 2 }); - run(TOOL, [ - process.execPath, - "tools/release/verify_github_release_attestations.mjs", - "finalize", - "--publication-lock", - lock.value, - ...argv, - "--receipt", - githubReceipt.value, - ], { failExitCode: 2 }); - } else { - run(TOOL, [process.execPath, "tools/release/check_release_versions.mjs", ...argv, "--check-registries"], { failExitCode: 2 }); - run(TOOL, [process.execPath, "tools/release/verify_github_release_attestations.mjs", ...argv], { failExitCode: 2 }); - } -} - -main(Bun.argv.slice(2)); diff --git a/tools/release/release-verify.sh b/tools/release/release-verify.sh new file mode 100644 index 000000000..f949737c4 --- /dev/null +++ b/tools/release/release-verify.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail +lock='' +receipts='' +github_receipt='' +products_json='' +head_ref=HEAD +args=() +while [ "$#" -gt 0 ]; do + case "$1" in + -h|--help) + echo 'usage: release-verify.sh [--products-json JSON] [--head-ref REF] [--publication-lock FILE --registry-receipts FILE --github-release-receipt FILE]' + exit 0 ;; + --publication-lock|--registry-receipts|--github-release-receipt) + [ "$#" -ge 2 ] || { echo "$1 requires a value" >&2; exit 2; } + case "$1" in + --publication-lock) lock="$2" ;; + --registry-receipts) receipts="$2" ;; + --github-release-receipt) github_receipt="$2" ;; + esac + shift 2 ;; + --publication-lock=*) lock="${1#*=}"; shift ;; + --registry-receipts=*) receipts="${1#*=}"; shift ;; + --github-release-receipt=*) github_receipt="${1#*=}"; shift ;; + --head-ref) + head_ref="${2:?--head-ref requires a value}"; args+=("$1" "$2"); shift 2 ;; + --head-ref=*) head_ref="${1#*=}"; args+=("$1"); shift ;; + --products-json) + [ "$#" -ge 2 ] || { echo '--products-json requires a value' >&2; exit 2; } + products_json="$2"; args+=("$1" "$2"); shift 2 ;; + --products-json=*) products_json="${1#*=}"; args+=("$1"); shift ;; + *) args+=("$1"); shift ;; + esac +done +if [ -n "$lock$receipts$github_receipt" ]; then + if [ -z "$lock" ] || [ -z "$receipts" ] || [ -z "$github_receipt" ] || [ -z "$products_json" ]; then + echo '--publication-lock, --registry-receipts, --github-release-receipt and --products-json must be supplied together' >&2 + exit 2 + fi + bun tools/release/registry-integrity.mts --lock "$lock" --products-json "$products_json" \ + --verify-receipts "$receipts" --sealed-receipts || exit 2 + bash "$(dirname "${BASH_SOURCE[0]}")/check-release-versions.sh" "${args[@]}" || exit 2 + bash "$(dirname "${BASH_SOURCE[0]}")/with-source.sh" "$head_ref" bash tools/release/verify-github-release-attestations.sh finalize --publication-lock "$lock" \ + "${args[@]}" --receipt "$github_receipt" || exit 2 +else + bash "$(dirname "${BASH_SOURCE[0]}")/check-release-versions.sh" "${args[@]}" --check-registries || exit 2 + bash "$(dirname "${BASH_SOURCE[0]}")/with-source.sh" "$head_ref" bash tools/release/verify-github-release-attestations.sh "${args[@]}" || exit 2 +fi diff --git a/tools/release/release-version-tags.test.mts b/tools/release/release-version-tags.test.mts new file mode 100644 index 000000000..e06ae9e16 --- /dev/null +++ b/tools/release/release-version-tags.test.mts @@ -0,0 +1,61 @@ +import { expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { validateVersionTags } from './check_release_versions.mts'; +import { parseTagCommits, parseTagRefs } from './git-tag-state.mts'; + +test('real Git snapshots preserve nested tags, reject reused versions and bind Swift source parents', () => { + const root = process.env.TEST_TAG_ROOT; + if (!root) throw new Error('run release-version-tags.test.sh to capture actual Git observations'); + const first = readFileSync(path.join(root, 'first'), 'utf8').trim(); + const headCommit = readFileSync(path.join(root, 'expected-head'), 'utf8').trim(); + const state = { + headCommit: readFileSync(path.join(root, 'head'), 'utf8'), + refs: parseTagRefs(readFileSync(path.join(root, 'refs'), 'utf8')), + commits: parseTagCommits(readFileSync(path.join(root, 'commits'), 'utf8')), + }; + expect(state.headCommit).toBe(headCommit); + expect(readFileSync(path.join(root, 'contrib'), 'utf8').split('\0')).toEqual([ + 'liboliphaunt-native-v0.1.0', + 'false', + 'liboliphaunt-native-v0.2.0', + 'true', + 'liboliphaunt-native-v0.3.0', + 'true', + '', + ]); + expect(validateVersionTags('product', '0.2.0', { tag_prefix: 'product-v' }, state)).toBe(true); + expect(validateVersionTags('product', '0.4.0', { tag_prefix: 'product-v' }, state)).toBe(false); + expect(() => validateVersionTags('product', '0.1.5', { tag_prefix: 'product-v' }, state)).toThrow( + 'not newer', + ); + expect(() => + validateVersionTags( + 'product', + '0.2.0', + { tag_prefix: 'product-v' }, + { ...state, headCommit: first }, + ), + ).toThrow('not exact release commit'); + expect(() => validateVersionTags('product', '0.3.0', { tag_prefix: 'product-v' }, state)).toThrow( + 'not exact release commit', + ); + expect( + validateVersionTags('oliphaunt-swift', '0.7.0', { tag_prefix: 'oliphaunt-swift-v' }, state), + ).toBe(true); + const wrongParent = { + ...state, + headCommit: first, + refs: new Map(state.refs).set('refs/tags/oliphaunt-swift-v0.7.0', first), + }; + expect(() => + validateVersionTags( + 'oliphaunt-swift', + '0.7.0', + { tag_prefix: 'oliphaunt-swift-v' }, + wrongParent, + ), + ).toThrow('source parent'); + expect(() => parseTagCommits(`${headCommit}\n${headCommit}\n`)).toThrow('repeated'); + expect(() => parseTagCommits('invalid')).toThrow('invalid'); +}); diff --git a/tools/release/release-version-tags.test.sh b/tools/release/release-version-tags.test.sh new file mode 100644 index 000000000..3549dfe8e --- /dev/null +++ b/tools/release/release-version-tags.test.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail +source_root="$(git rev-parse --show-toplevel)" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +cd "$scratch" +git init -q +git config user.name Fixture +git config user.email fixture@example.invalid +git commit --allow-empty -qm first +git rev-parse HEAD > first +git tag product-v0.1.0 +git tag liboliphaunt-native-v0.1.0 +git commit --allow-empty -qm release +git rev-parse HEAD > expected-head +git tag -a inner -m release +git -c advice.nestedTag=false tag -a product-v0.2.0 -m nested inner +git tag oliphaunt-swift-v0.7.0 +git commit --allow-empty -qm 'SwiftPM projection' +git tag -a 0.7.0 -m SwiftPM +printf payload > blob +git tag product-v0.3.0 "$(git hash-object -w blob)" +mkdir -p extensions/contrib tools/release tools/dev +printf fixture > extensions/contrib/carriers.toml +git add extensions/contrib/carriers.toml +git commit -qm 'add contrib carrier' +git tag -a liboliphaunt-native-v0.2.0 -m 'with contrib' +mkdir src +git mv extensions src/extensions +git commit -qm 'move source under src' +git tag liboliphaunt-native-v0.3.0 +cp "$source_root/tools/release/with-release-tags.sh" tools/release/ +cp "$source_root/tools/release/check-release-versions.sh" check.sh +cat > tools/dev/bun.sh <<'SH' +#!/usr/bin/env bash +set -eu +printf '%s' "$RELEASE_HEAD_COMMIT" > head +cp "$RELEASE_TAG_REFS" refs +cp "$RELEASE_TAG_COMMITS" commits +cp "$RELEASE_TAG_CONTRIB" contrib +SH +RELEASE_HEAD_COMMIT="$(cat first)" bash check.sh --head-ref "$(cat expected-head)" +cd "$source_root" +TEST_TAG_ROOT="$scratch" bun test ./tools/release/release-version-tags.test.mts diff --git a/tools/release/release-version-transition.test.mjs b/tools/release/release-version-transition.test.mjs deleted file mode 100644 index 9e3bc7350..000000000 --- a/tools/release/release-version-transition.test.mjs +++ /dev/null @@ -1,409 +0,0 @@ -import assert from "node:assert/strict"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { buildPlanFromProductTags } from "./release-graph.mjs"; -import { releaseProductVersionCoverage } from "./release-product-version-coverage.mjs"; -import { selectedDependencySatisfiesPin } from "./check_release_versions.mjs"; - -const PRODUCTS = { - "liboliphaunt-native": "packages/native", - "liboliphaunt-wasix": "packages/wasix", - "oliphaunt-extension-vector": "packages/vector", -}; - -function git(root, ...args) { - return execFileSync("git", args, { cwd: root, encoding: "utf8" }).trim(); -} - -function writeSnapshot( - root, - versions, - { vectorCompatibility = "native=1.0.0,wasix=1.0.0", vectorSource = "vector" } = {}, -) { - writeFileSync( - path.join(root, ".release-please-manifest.json"), - `${JSON.stringify(Object.fromEntries(Object.entries(PRODUCTS).map(([product, packagePath]) => [packagePath, versions[product]])), null, 2)}\n`, - ); - for (const [product, packagePath] of Object.entries(PRODUCTS)) { - const directory = path.join(root, packagePath); - mkdirSync(directory, { recursive: true }); - writeFileSync(path.join(directory, "VERSION"), `${versions[product]}\n`); - writeFileSync(path.join(directory, "CHANGELOG.md"), `## ${versions[product]}\n`); - const compatibility = Object.fromEntries( - vectorCompatibility.split(",").map((entry) => entry.split("=", 2)), - ); - const body = product === "oliphaunt-extension-vector" - ? [ - `id = ${JSON.stringify(product)}`, - `source = ${JSON.stringify(vectorSource)}`, - "[extension]", - 'sql_name = "vector"', - "[extension.compatibility]", - `native_runtime_version = ${JSON.stringify(compatibility.native)}`, - `wasix_runtime_version = ${JSON.stringify(compatibility.wasix)}`, - "", - ].join("\n") - : `id = ${JSON.stringify(product)}\n`; - writeFileSync(path.join(directory, "release.toml"), body); - } -} - -function commit(root, subject) { - git(root, "add", "."); - git(root, "commit", "-m", subject); - return git(root, "rev-parse", "HEAD"); -} - -function fixture(t, versions) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-transition-")); - t.after(() => rmSync(root, { force: true, recursive: true })); - git(root, "init", "-q"); - git(root, "config", "user.email", "release-test@example.invalid"); - git(root, "config", "user.name", "Release Test"); - writeSnapshot(root, versions); - const head = commit(root, "initial products"); - return { root, head }; -} - -function graph(versions) { - return { - policy: { versioning: "independent" }, - products: { - "liboliphaunt-native": { - path: PRODUCTS["liboliphaunt-native"], - tag_prefix: "liboliphaunt-native-v", - version: versions["liboliphaunt-native"], - version_files: [`${PRODUCTS["liboliphaunt-native"]}/VERSION`], - }, - "liboliphaunt-wasix": { - path: PRODUCTS["liboliphaunt-wasix"], - tag_prefix: "liboliphaunt-wasix-v", - version: versions["liboliphaunt-wasix"], - version_files: [`${PRODUCTS["liboliphaunt-wasix"]}/VERSION`], - }, - "oliphaunt-extension-vector": { - extension: { class: "external" }, - path: PRODUCTS["oliphaunt-extension-vector"], - tag_prefix: "oliphaunt-extension-vector-v", - version: versions["oliphaunt-extension-vector"], - version_files: [`${PRODUCTS["oliphaunt-extension-vector"]}/VERSION`], - compatibility_versions: { - "vector-native-runtime": { - source_product: "liboliphaunt-native", - path: `${PRODUCTS["oliphaunt-extension-vector"]}/release.toml`, - parser: "toml:extension.compatibility.native_runtime_version", - }, - "vector-wasix-runtime": { - source_product: "liboliphaunt-wasix", - path: `${PRODUCTS["oliphaunt-extension-vector"]}/release.toml`, - parser: "toml:extension.compatibility.wasix_runtime_version", - }, - }, - }, - }, - moon_projects: { - "liboliphaunt-native": { - id: "liboliphaunt-native", - source: PRODUCTS["liboliphaunt-native"], - dependencies: [], - }, - "liboliphaunt-wasix": { - id: "liboliphaunt-wasix", - source: PRODUCTS["liboliphaunt-wasix"], - dependencies: [], - }, - "oliphaunt-extension-vector": { - id: "oliphaunt-extension-vector", - source: PRODUCTS["oliphaunt-extension-vector"], - dependencies: [ - { id: "liboliphaunt-native", scope: "build", source: "explicit" }, - { id: "liboliphaunt-wasix", scope: "build", source: "explicit" }, - ], - }, - }, - }; -} - -function tagVersions(root, versions) { - for (const product of Object.keys(PRODUCTS)) { - git(root, "tag", `${product}-v${versions[product]}`); - } -} - -const V1 = { - "liboliphaunt-native": "1.0.0", - "liboliphaunt-wasix": "1.0.0", - "oliphaunt-extension-vector": "1.0.0", -}; - -test("a selected dependency satisfies only its exact consumer pin", () => { - const selected = new Set(["liboliphaunt-native"]); - assert.equal(selectedDependencySatisfiesPin(selected, "liboliphaunt-native", "1.0.0", "1.0.0"), true); - assert.equal(selectedDependencySatisfiesPin(selected, "liboliphaunt-native", "1.0.0", "2.0.0"), false); -}); - -test("compatibility-only external sink edits cannot select its unchanged release identity", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - const versions = { ...V1, "liboliphaunt-native": "2.0.0", "liboliphaunt-wasix": "2.0.0" }; - writeSnapshot(f.root, versions, { vectorCompatibility: "native=2.0.0,wasix=2.0.0" }); - commit(f.root, "release runtimes"); - - const plan = buildPlanFromProductTags(graph(versions), "HEAD", { prefix: "transition-test", root: f.root }); - assert.deepEqual(plan.releaseProducts, ["liboliphaunt-native", "liboliphaunt-wasix"]); - assert.equal(plan.changedFiles.includes("packages/vector/release.toml"), true); - assert.equal(plan.releaseProducts.includes("oliphaunt-extension-vector"), false); - assert.deepEqual( - releaseProductVersionCoverage( - graph(versions), - ["liboliphaunt-native", "liboliphaunt-wasix"], - "transition-test", - ), - { - missingProducts: [], - requiredProducts: ["liboliphaunt-native", "liboliphaunt-wasix"], - versionedProducts: ["liboliphaunt-native", "liboliphaunt-wasix"], - }, - ); -}); - -test("an unchanged external product cannot hide a source edit beside compatibility fields", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - const versions = { ...V1, "liboliphaunt-native": "2.0.0", "liboliphaunt-wasix": "2.0.0" }; - writeSnapshot(f.root, versions, { - vectorCompatibility: "native=2.0.0,wasix=2.0.0", - vectorSource: "vector-v2", - }); - commit(f.root, "runtime release with omitted vector bump"); - - assert.throws( - () => buildPlanFromProductTags(graph(versions), "HEAD", { prefix: "transition-test", root: f.root }), - /oliphaunt-extension-vector has release-affecting changes .* manifest version remains 1[.]0[.]0.*packages\/vector\/release[.]toml/u, - ); -}); - -test("an unchanged external product cannot hide a changed source file", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - const versions = { ...V1, "liboliphaunt-native": "2.0.0", "liboliphaunt-wasix": "2.0.0" }; - writeSnapshot(f.root, versions, { vectorCompatibility: "native=2.0.0,wasix=2.0.0" }); - writeFileSync(path.join(f.root, PRODUCTS["oliphaunt-extension-vector"], "source.toml"), 'rev = "v2"\n'); - commit(f.root, "runtime release with changed vector source"); - - assert.throws( - () => buildPlanFromProductTags(graph(versions), "HEAD", { prefix: "transition-test", root: f.root }), - /oliphaunt-extension-vector has release-affecting changes .*packages\/vector\/source[.]toml/u, - ); -}); - -test("a compatibility edit with the wrong source-product version cannot be ignored", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - const versions = { ...V1, "liboliphaunt-native": "2.0.0", "liboliphaunt-wasix": "2.0.0" }; - writeSnapshot(f.root, versions, { vectorCompatibility: "native=9.9.9,wasix=2.0.0" }); - commit(f.root, "runtime release with invalid vector compatibility"); - - assert.throws( - () => buildPlanFromProductTags(graph(versions), "HEAD", { prefix: "transition-test", root: f.root }), - /oliphaunt-extension-vector has release-affecting changes .*packages\/vector\/release[.]toml/u, - ); -}); - -test("a native release does not require WASIX to advance", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - const versions = { ...V1, "liboliphaunt-native": "2.0.0" }; - writeSnapshot(f.root, versions, { vectorCompatibility: "native=2.0.0,wasix=1.0.0" }); - commit(f.root, "incomplete runtime release"); - - const plan = buildPlanFromProductTags(graph(versions), "HEAD", { - prefix: "transition-test", - root: f.root, - }); - assert.deepEqual(plan.releaseProducts, ["liboliphaunt-native"]); - assert.equal(plan.changedFiles.includes("packages/vector/release.toml"), true); -}); - -test("production dependencies do not version an unchanged downstream product", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - const versions = { ...V1, "liboliphaunt-native": "2.0.0", "liboliphaunt-wasix": "2.0.0" }; - writeSnapshot(f.root, versions, { vectorCompatibility: "native=2.0.0,wasix=2.0.0" }); - commit(f.root, "release runtimes"); - const releaseGraph = graph(versions); - releaseGraph.moon_projects["oliphaunt-extension-vector"].dependencies = - releaseGraph.moon_projects["oliphaunt-extension-vector"].dependencies.map((dependency) => ({ - ...dependency, - scope: "production", - })); - - assert.deepEqual( - buildPlanFromProductTags(releaseGraph, "HEAD", { prefix: "transition-test", root: f.root }).releaseProducts, - ["liboliphaunt-native", "liboliphaunt-wasix"], - ); -}); - -test("a real external manifest version bump selects the independent product", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - const runtimeVersions = { ...V1, "liboliphaunt-native": "2.0.0", "liboliphaunt-wasix": "2.0.0" }; - writeSnapshot(f.root, runtimeVersions, { vectorCompatibility: "native=2.0.0,wasix=2.0.0" }); - commit(f.root, "release runtimes"); - git(f.root, "tag", "liboliphaunt-native-v2.0.0"); - git(f.root, "tag", "liboliphaunt-wasix-v2.0.0"); - - const versions = { ...runtimeVersions, "oliphaunt-extension-vector": "1.1.0" }; - writeSnapshot(f.root, versions, { vectorCompatibility: "native=2.0.0,wasix=2.0.0", vectorSource: "vector-v1.1" }); - commit(f.root, "release vector"); - - const plan = buildPlanFromProductTags(graph(versions), "HEAD", { prefix: "transition-test", root: f.root }); - assert.deepEqual(plan.directProducts, ["oliphaunt-extension-vector"]); - assert.deepEqual(plan.releaseProducts, ["oliphaunt-extension-vector"]); -}); - -test("products without tags retain first-release selection", (t) => { - const versions = { - "liboliphaunt-native": "0.1.0", - "liboliphaunt-wasix": "0.1.0", - "oliphaunt-extension-vector": "0.1.0", - }; - const f = fixture(t, versions); - const plan = buildPlanFromProductTags(graph(versions), f.head, { prefix: "transition-test", root: f.root }); - assert.deepEqual(plan.releaseProducts, [ - "liboliphaunt-native", - "liboliphaunt-wasix", - "oliphaunt-extension-vector", - ]); -}); - -test("untagged bootstrap 0.0.0 products are not first-release candidates", (t) => { - const versions = { - "liboliphaunt-native": "0.0.0", - "liboliphaunt-wasix": "0.0.0", - "oliphaunt-extension-vector": "0.0.0", - }; - const f = fixture(t, versions); - const plan = buildPlanFromProductTags(graph(versions), f.head, { prefix: "transition-test", root: f.root }); - assert.deepEqual(plan.releaseProducts, []); -}); - -test("an exact existing current-version tag is selected only for an explicit rerun", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - const excluded = buildPlanFromProductTags(graph(V1), f.head, { prefix: "transition-test", root: f.root }); - assert.deepEqual(excluded.releaseProducts, []); - - const rerun = buildPlanFromProductTags(graph(V1), f.head, { - includeCurrentTags: true, - prefix: "transition-test", - root: f.root, - }); - assert.deepEqual(rerun.releaseProducts, [ - "liboliphaunt-native", - "liboliphaunt-wasix", - "oliphaunt-extension-vector", - ]); - assert.deepEqual(rerun.currentTaggedProducts, rerun.releaseProducts); -}); - -test("a tooling-only descendant cannot rerun an older same-version tag", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - mkdirSync(path.join(f.root, "tools/release"), { recursive: true }); - writeFileSync(path.join(f.root, "tools/release/rerun-note.mjs"), "export const rerun = true;\n"); - commit(f.root, "repair release tooling"); - - const plan = buildPlanFromProductTags(graph(V1), "HEAD", { - includeCurrentTags: true, - prefix: "transition-test", - root: f.root, - }); - assert.deepEqual(plan.releaseProducts, []); - assert.deepEqual(plan.currentTaggedProducts, []); -}); - -test("a regressed head manifest cannot rerun through an older current-version tag", (t) => { - const f = fixture(t, V1); - tagVersions(f.root, V1); - const v2 = { ...V1, "liboliphaunt-native": "2.0.0", "liboliphaunt-wasix": "2.0.0" }; - writeSnapshot(f.root, v2); - commit(f.root, "release runtimes v2"); - git(f.root, "tag", "liboliphaunt-native-v2.0.0"); - git(f.root, "tag", "liboliphaunt-wasix-v2.0.0"); - const regressed = { ...v2, "liboliphaunt-native": "1.0.0" }; - writeSnapshot(f.root, regressed); - commit(f.root, "regress native manifest"); - - assert.throws( - () => buildPlanFromProductTags(graph(regressed), "HEAD", { - includeCurrentTags: true, - prefix: "transition-test", - root: f.root, - }), - /manifest version 1[.]0[.]0 is older than tagged version 2[.]0[.]0/u, - ); -}); - -test("a tag whose canonical version file disagrees with its identity fails closed", (t) => { - const f = fixture(t, V1); - writeFileSync(path.join(f.root, PRODUCTS["oliphaunt-extension-vector"], "VERSION"), "9.9.9\n"); - commit(f.root, "corrupt tagged canonical version"); - tagVersions(f.root, V1); - - assert.throws( - () => buildPlanFromProductTags(graph(V1), "HEAD", { - includeCurrentTags: true, - prefix: "transition-test", - root: f.root, - }), - /canonical version "9[.]9[.]9" does not match its manifest version "1[.]0[.]0"/u, - ); -}); - -test("an eligible transition with no owning changed path fails instead of disappearing", (t) => { - const f = fixture(t, V1); - mkdirSync(path.join(f.root, "metadata"), { recursive: true }); - writeFileSync(path.join(f.root, "metadata/vector-version"), "1.0.0\n"); - commit(f.root, "add detached version metadata"); - tagVersions(f.root, V1); - - const versions = { ...V1, "oliphaunt-extension-vector": "1.1.0" }; - writeFileSync( - path.join(f.root, ".release-please-manifest.json"), - `${JSON.stringify(Object.fromEntries(Object.entries(PRODUCTS).map(([product, packagePath]) => [packagePath, versions[product]])), null, 2)}\n`, - ); - writeFileSync(path.join(f.root, "metadata/vector-version"), "1.1.0\n"); - commit(f.root, "detached vector version bump"); - const releaseGraph = graph(versions); - releaseGraph.products["oliphaunt-extension-vector"].version_files = ["metadata/vector-version"]; - - assert.throws( - () => buildPlanFromProductTags(releaseGraph, "HEAD", { prefix: "transition-test", root: f.root }), - /manifest advanced .* changed paths do not select the product/u, - ); -}); - -test("a current-version tag on a mismatched tree fails closed", (t) => { - const f = fixture(t, V1); - const candidate = f.head; - git(f.root, "checkout", "-q", "--orphan", "collision"); - git(f.root, "rm", "-q", "-rf", "."); - writeSnapshot(f.root, V1, { vectorSource: "different-tree" }); - commit(f.root, "conflicting vector identity"); - git(f.root, "tag", "oliphaunt-extension-vector-v1.0.0"); - git(f.root, "checkout", "-q", "--detach", candidate); - - assert.throws( - () => buildPlanFromProductTags(graph(V1), candidate, { - includeCurrentTags: true, - prefix: "transition-test", - root: f.root, - }), - /current-version tag .* is not an ancestor of release candidate/u, - ); -}); diff --git a/tools/release/release-version-transition.test.mts b/tools/release/release-version-transition.test.mts new file mode 100644 index 000000000..5093d26a9 --- /dev/null +++ b/tools/release/release-version-transition.test.mts @@ -0,0 +1,267 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +import { buildPlanFromProductTags } from './release-graph.mts'; +import { selectedDependencySatisfiesPin } from './check_release_versions.mts'; + +const PRODUCTS = { + 'liboliphaunt-native': 'packages/native', + 'liboliphaunt-wasix': 'packages/wasix', + 'oliphaunt-extension-vector': 'packages/vector', +}; + +function writeSnapshot( + root, + versions, + { vectorCompatibility = 'native=1.0.0,wasix=1.0.0', vectorSource = 'vector' } = {}, +) { + writeFileSync( + path.join(root, '.release-please-manifest.json'), + `${JSON.stringify(Object.fromEntries(Object.entries(PRODUCTS).map(([product, packagePath]) => [packagePath, versions[product]])), null, 2)}\n`, + ); + for (const [product, packagePath] of Object.entries(PRODUCTS)) { + const directory = path.join(root, packagePath); + mkdirSync(directory, { recursive: true }); + writeFileSync(path.join(directory, 'VERSION'), `${versions[product]}\n`); + writeFileSync(path.join(directory, 'CHANGELOG.md'), `## ${versions[product]}\n`); + const compatibility = Object.fromEntries( + vectorCompatibility.split(',').map((entry) => entry.split('=', 2)), + ); + const body = + product === 'oliphaunt-extension-vector' + ? [ + `id = ${JSON.stringify(product)}`, + `source = ${JSON.stringify(vectorSource)}`, + '[extension]', + 'sql_name = "vector"', + '[extension.compatibility]', + `native_runtime_version = ${JSON.stringify(compatibility.native)}`, + `wasix_runtime_version = ${JSON.stringify(compatibility.wasix)}`, + '', + ].join('\n') + : `id = ${JSON.stringify(product)}\n`; + writeFileSync(path.join(directory, 'release.toml'), body); + } +} + +function graph(versions) { + return { + policy: { versioning: 'independent' }, + products: { + 'liboliphaunt-native': { + path: PRODUCTS['liboliphaunt-native'], + tag_prefix: 'liboliphaunt-native-v', + version: versions['liboliphaunt-native'], + version_files: [`${PRODUCTS['liboliphaunt-native']}/VERSION`], + }, + 'liboliphaunt-wasix': { + path: PRODUCTS['liboliphaunt-wasix'], + tag_prefix: 'liboliphaunt-wasix-v', + version: versions['liboliphaunt-wasix'], + version_files: [`${PRODUCTS['liboliphaunt-wasix']}/VERSION`], + }, + 'oliphaunt-extension-vector': { + extension: { class: 'external' }, + path: PRODUCTS['oliphaunt-extension-vector'], + tag_prefix: 'oliphaunt-extension-vector-v', + version: versions['oliphaunt-extension-vector'], + version_files: [`${PRODUCTS['oliphaunt-extension-vector']}/VERSION`], + compatibility_versions: { + 'vector-native-runtime': { + source_product: 'liboliphaunt-native', + path: `${PRODUCTS['oliphaunt-extension-vector']}/release.toml`, + parser: 'toml:extension.compatibility.native_runtime_version', + }, + 'vector-wasix-runtime': { + source_product: 'liboliphaunt-wasix', + path: `${PRODUCTS['oliphaunt-extension-vector']}/release.toml`, + parser: 'toml:extension.compatibility.wasix_runtime_version', + }, + }, + }, + }, + moon_projects: { + 'liboliphaunt-native': { + id: 'liboliphaunt-native', + source: PRODUCTS['liboliphaunt-native'], + dependencies: [], + }, + 'liboliphaunt-wasix': { + id: 'liboliphaunt-wasix', + source: PRODUCTS['liboliphaunt-wasix'], + dependencies: [], + }, + 'oliphaunt-extension-vector': { + id: 'oliphaunt-extension-vector', + source: PRODUCTS['oliphaunt-extension-vector'], + dependencies: [ + { id: 'liboliphaunt-native', scope: 'build', source: 'explicit' }, + { id: 'liboliphaunt-wasix', scope: 'build', source: 'explicit' }, + ], + }, + }, + }; +} + +const V1 = { + 'liboliphaunt-native': '1.0.0', + 'liboliphaunt-wasix': '1.0.0', + 'oliphaunt-extension-vector': '1.0.0', +}; + +const [phase, root, scenario, stage, graphPath] = process.argv.slice(2); +const native = 'liboliphaunt-native'; +const wasix = 'liboliphaunt-wasix'; +const vector = 'oliphaunt-extension-vector'; +const runtimeVersions = { ...V1, [native]: '2.0.0', [wasix]: '2.0.0' }; +const runtimeCases = ['compatible', 'inline-source', 'source', 'invalid-pin', 'production']; +const versions = runtimeCases.includes(scenario) + ? runtimeVersions + : scenario === 'native' + ? { ...V1, [native]: '2.0.0' } + : scenario === 'external' + ? { ...runtimeVersions, [vector]: '1.1.0' } + : scenario === 'regressed' + ? { ...runtimeVersions, [native]: '1.0.0' } + : scenario === 'detached' + ? { ...V1, [vector]: '1.1.0' } + : ['first', 'zero'].includes(scenario) + ? Object.fromEntries( + Object.keys(PRODUCTS).map((id) => [id, scenario === 'first' ? '0.1.0' : '0.0.0']), + ) + : V1; +const releaseGraph = graph(versions); +if (scenario === 'production') + releaseGraph.moon_projects[vector].dependencies = releaseGraph.moon_projects[ + vector + ].dependencies.map((dependency) => ({ ...dependency, scope: 'production' })); +if (scenario === 'detached') + releaseGraph.products[vector].version_files = ['metadata/vector-version']; +if (phase === 'write') { + if (scenario === 'detached' && stage === 'release') { + writeFileSync( + path.join(root, '.release-please-manifest.json'), + JSON.stringify( + Object.fromEntries(Object.entries(PRODUCTS).map(([id, folder]) => [folder, versions[id]])), + ), + ); + writeFileSync(path.join(root, 'metadata/vector-version'), '1.1.0\n'); + } else { + const selected = + stage === 'base' + ? ['first', 'zero'].includes(scenario) + ? versions + : V1 + : stage === 'runtime' + ? runtimeVersions + : versions; + const options = {}; + if ( + stage !== 'base' && + (runtimeCases.includes(scenario) || ['native', 'external'].includes(scenario)) + ) { + options.vectorCompatibility = `native=${scenario === 'invalid-pin' ? '9.9.9' : selected[native]},wasix=${selected[wasix]}`; + } + if (stage === 'release' && scenario === 'inline-source') options.vectorSource = 'vector-v2'; + if (stage === 'release' && scenario === 'external') options.vectorSource = 'vector-v1.1'; + if (stage === 'different') options.vectorSource = 'different-tree'; + writeSnapshot(root, selected, options); + } + writeFileSync(graphPath, JSON.stringify(releaseGraph)); +} else if (phase === 'assert') { + const plan = (includeCurrentTags = false) => + buildPlanFromProductTags(releaseGraph, 'HEAD', { + prefix: 'transition-test', + root, + includeCurrentTags, + }); + switch (scenario) { + case 'compatible': { + const result = plan(); + assert.deepEqual(result.releaseProducts, [native, wasix]); + assert.equal(result.changedFiles.includes('packages/vector/release.toml'), true); + break; + } + case 'inline-source': + assert.throws( + () => plan(), + /oliphaunt-extension-vector has release-affecting changes .* manifest version remains 1[.]0[.]0.*packages\/vector\/release[.]toml/u, + ); + break; + case 'source': + assert.throws( + () => plan(), + /oliphaunt-extension-vector has release-affecting changes .*packages\/vector\/source[.]toml/u, + ); + break; + case 'invalid-pin': + assert.throws( + () => plan(), + /oliphaunt-extension-vector has release-affecting changes .*packages\/vector\/release[.]toml/u, + ); + break; + case 'native': { + const result = plan(); + assert.deepEqual(result.releaseProducts, [native]); + assert.equal(result.changedFiles.includes('packages/vector/release.toml'), true); + break; + } + case 'production': + assert.deepEqual(plan().releaseProducts, [native, wasix]); + break; + case 'external': { + const result = plan(); + assert.deepEqual(result.directProducts, [vector]); + assert.deepEqual(result.releaseProducts, [vector]); + break; + } + case 'first': + assert.deepEqual(plan().releaseProducts, [native, wasix, vector]); + break; + case 'zero': + assert.deepEqual(plan().releaseProducts, []); + break; + case 'rerun': { + assert.deepEqual(plan().releaseProducts, []); + const result = plan(true); + assert.deepEqual(result.releaseProducts, [native, wasix, vector]); + assert.deepEqual(result.currentTaggedProducts, result.releaseProducts); + break; + } + case 'tooling': { + const result = plan(true); + assert.deepEqual(result.releaseProducts, []); + assert.deepEqual(result.currentTaggedProducts, []); + break; + } + case 'regressed': + assert.throws( + () => plan(true), + /manifest version 1[.]0[.]0 is older than tagged version 2[.]0[.]0/u, + ); + break; + case 'canonical': + assert.throws( + () => plan(true), + /canonical version "9[.]9[.]9" does not match its manifest version "1[.]0[.]0"/u, + ); + break; + case 'detached': + assert.throws(() => plan(), /manifest advanced .* changed paths do not select the product/u); + break; + case 'unrelated': + assert.throws( + () => plan(true), + /current-version tag .* is not an ancestor of release candidate/u, + ); + break; + default: + throw new Error('unknown transition scenario'); + } + console.log(`release transition ${scenario}: passed`); +} else if (phase === 'pins') { + assert.equal(selectedDependencySatisfiesPin(new Set([native]), native, '1.0.0', '1.0.0'), true); + assert.equal(selectedDependencySatisfiesPin(new Set([native]), native, '1.0.0', '2.0.0'), false); + console.log('selected dependency requires exact pin: passed'); +} else throw new Error('run through release-version-transition.test.sh'); diff --git a/tools/release/release-version-transition.test.sh b/tools/release/release-version-transition.test.sh new file mode 100644 index 000000000..1788ee670 --- /dev/null +++ b/tools/release/release-version-transition.test.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +if [[ -z "${OLIPHAUNT_RELEASE_PLEASE_STATE:-}" ]]; then + exec bash "$root/tools/release/release-please-state.sh" "$root" HEAD \ + bash "$root/tools/release/release-version-transition.test.sh" +fi +scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-release-transition.XXXXXX")" +trap 'rm -rf "$scratch"' EXIT +fixture="$root/tools/release/release-version-transition.test.mts" +commit() { git -C "$repo" add .; git -C "$repo" commit -qm "$1"; } +write() { bash "$root/tools/dev/bun.sh" "$fixture" write "$repo" "$scenario" "$1" "$scratch/graph.json"; } +tag_v1() { + for product in liboliphaunt-native liboliphaunt-wasix oliphaunt-extension-vector; do + git -C "$repo" tag "$product-v1.0.0" + done +} +for scenario in compatible inline-source source invalid-pin native production external first zero rerun tooling regressed canonical detached unrelated; do + repo="$scratch/$scenario" + git init -q "$repo" + git -C "$repo" config user.name 'Release Test' + git -C "$repo" config user.email release-test@example.invalid + write base + commit 'initial products' + candidate="$(git -C "$repo" rev-parse HEAD)" + case "$scenario" in + first|zero) ;; + canonical) + printf '9.9.9\n' > "$repo/packages/vector/VERSION" + commit 'corrupt tagged canonical version' + tag_v1 ;; + detached) + mkdir -p "$repo/metadata" + printf '1.0.0\n' > "$repo/metadata/vector-version" + commit 'add detached version metadata' + tag_v1 + write release + commit 'detached vector version bump' ;; + unrelated) + git -C "$repo" checkout -q --orphan collision + git -C "$repo" rm -qrf . + write different + commit 'conflicting vector identity' + git -C "$repo" tag oliphaunt-extension-vector-v1.0.0 + git -C "$repo" checkout -q --detach "$candidate" ;; + *) + tag_v1 + case "$scenario" in + rerun) ;; + tooling) + mkdir -p "$repo/tools/release" + printf 'release tooling repair\n' > "$repo/tools/release/rerun-note.txt" + commit 'repair release tooling' ;; + external|regressed) + write runtime + commit 'release runtimes v2' + git -C "$repo" tag liboliphaunt-native-v2.0.0 + git -C "$repo" tag liboliphaunt-wasix-v2.0.0 + write release + commit 'advance release state' ;; + *) + write release + if [[ "$scenario" == source ]]; then printf 'rev = "v2"\n' > "$repo/packages/vector/source.toml"; fi + commit 'release runtimes' ;; + esac ;; + esac + bash "$root/tools/release/with-product-history.sh" "$repo" HEAD '' "$scratch/graph.json" \ + bash "$root/tools/dev/bun.sh" "$fixture" assert "$repo" "$scenario" +done +bash "$root/tools/dev/bun.sh" "$fixture" pins diff --git a/tools/release/release_graph_query.mjs b/tools/release/release_graph_query.mjs deleted file mode 100644 index cbb5f7ab4..000000000 --- a/tools/release/release_graph_query.mjs +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env bun -import { parseArgs } from "node:util"; - -import { - ciNpmPackageArtifactRows, - ciReleaseAssetArtifactRows, - extensionArtifactProductRoot, - extensionArtifactProductsForReleaseProducts, - extensionMemberPath, - extensionMetadata, - extensionReleaseProduct, - extensionSqlNames, - extensionSourceIdentity, - exactExtensionProducts, - sdkPackageProducts, -} from "./release-artifact-targets.mjs"; -import { compareText, loadGraph, releaseOrder } from "./release-graph.mjs"; -import { extensionNpmPackageForProduct } from "./extension-registry-packages.mjs"; - -const TOOL = "release_graph_query.mjs"; - -function fail(message) { - console.error(`${TOOL}: ${message}`); - process.exit(2); -} - -function commandOptions(argv, options) { - try { - return parseArgs({ args: argv, options, strict: true, allowPositionals: false }).values; - } catch (error) { - fail(error.message); - } -} - -function sortedValue(value) { - if (Array.isArray(value)) return value.map(sortedValue); - if (value !== null && typeof value === "object") { - return Object.fromEntries( - Object.keys(value).sort(compareText).map((key) => [key, sortedValue(value[key])]), - ); - } - return value; -} - -function printJson(value) { - console.log(JSON.stringify(sortedValue(value), null, 2)); -} - -function output(rows, format, field) { - if (format === "lines") { - for (const row of rows) console.log(row[field]); - } else if (format === "json") { - printJson(rows); - } else { - fail("--format must be json or lines"); - } -} - -function stringList(raw, flag) { - let value; - try { - value = JSON.parse(raw); - } catch (error) { - fail(`${flag} must be valid JSON: ${error.message}`); - } - if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) { - fail(`${flag} must be a JSON string list`); - } - return value; -} - -function orderedReleaseProducts(raw) { - const selected = stringList(raw, "--products-json"); - const graph = loadGraph(TOOL); - const unknown = [...new Set(selected)] - .filter((product) => !(product in graph.products)) - .sort(compareText); - if (unknown.length > 0) fail(`unknown release products: ${unknown.join(", ")}`); - return releaseOrder(graph.products, graph.moon_projects, selected, TOOL); -} - -function runCiArtifactNames(argv) { - const values = commandOptions(argv, { - family: { type: "string" }, - product: { type: "string" }, - kind: { type: "string" }, - format: { type: "string", default: "json" }, - }); - if (!values.family) fail("--family is required"); - if (!values.product) fail("--product is required"); - - let rows; - if (values.family === "release-assets") { - if (!values.kind) fail("--kind is required for release-assets artifacts"); - rows = ciReleaseAssetArtifactRows(values.product, values.kind, TOOL); - } else if (values.family === "npm-package") { - if (!values.kind) fail("--kind is required for npm-package artifacts"); - rows = ciNpmPackageArtifactRows(values.product, values.kind, TOOL); - } else if (values.family === "sdk-package") { - if (values.kind) fail("--kind is not accepted for sdk-package artifacts"); - rows = sdkPackageProducts(TOOL).filter((row) => row.product === values.product); - if (rows.length !== 1) fail(`${values.product} is not an SDK release product`); - } else { - fail("--family must be release-assets, npm-package, or sdk-package"); - } - output(rows, values.format, "artifactName"); -} - -function runCiProducts(argv) { - const values = commandOptions(argv, { - family: { type: "string" }, - "carrier-family": { type: "string" }, - field: { type: "string", default: "product" }, - "products-json": { type: "string" }, - format: { type: "string", default: "json" }, - }); - const carrierFamily = values["carrier-family"]; - if (carrierFamily !== undefined && !["native", "wasix"].includes(carrierFamily)) { - fail("--carrier-family must be native or wasix"); - } - if (!["product", "artifact-root"].includes(values.field)) { - fail("--field must be product or artifact-root"); - } - if (values.family !== "extension-artifacts" && (carrierFamily !== undefined || values.field !== "product")) { - fail("--carrier-family and non-product --field values require --family extension-artifacts"); - } - if (values.field !== "product" && values.format !== "lines") { - fail("non-product --field values require --format lines"); - } - - let availableRows; - if (values.family === "sdk-package") { - availableRows = sdkPackageProducts(TOOL); - } else if (values.family === "extension-artifacts") { - availableRows = exactExtensionProducts(TOOL).map((product) => ({ product })); - } else { - fail("--family must be sdk-package or extension-artifacts"); - } - - const rowsByProduct = new Map(availableRows.map((row) => [row.product, row])); - const selectedReleaseProducts = values["products-json"] === undefined - ? undefined - : orderedReleaseProducts(values["products-json"]); - const products = selectedReleaseProducts === undefined - ? availableRows.map((row) => row.product) - : values.family === "extension-artifacts" - ? extensionArtifactProductsForReleaseProducts(selectedReleaseProducts, { - family: carrierFamily, - prefix: TOOL, - }) - : selectedReleaseProducts.filter((product) => rowsByProduct.has(product)); - - if (values.field === "product") { - output(products.map((product) => rowsByProduct.get(product)), values.format, "product"); - return; - } - - const selectedSet = selectedReleaseProducts === undefined ? null : new Set(selectedReleaseProducts); - const roots = products.flatMap((product) => { - const families = carrierFamily === undefined ? ["native", "wasix"] : [carrierFamily]; - return families - .filter((family) => selectedSet === null - || selectedSet.has(extensionReleaseProduct(product, family, TOOL))) - .map((family) => extensionArtifactProductRoot( - product, - family, - "target/extension-artifacts", - TOOL, - )); - }); - for (const root of [...new Set(roots)]) console.log(root); -} - -function runExtensionArtifactRoot(argv) { - const values = commandOptions(argv, { - product: { type: "string" }, - family: { type: "string", default: "native" }, - }); - if (!values.product) fail("--product is required"); - if (!["native", "wasix"].includes(values.family)) fail("--family must be native or wasix"); - console.log(extensionArtifactProductRoot( - values.product, - values.family, - "target/extension-artifacts", - TOOL, - )); -} - -function runExtensionMetadata(argv) { - const values = commandOptions(argv, { product: { type: "string" } }); - const products = values.product === undefined ? exactExtensionProducts(TOOL) : [values.product]; - printJson(products.flatMap((product) => { - const metadata = extensionMetadata(product, TOOL); - return extensionSqlNames(product, TOOL).map((sqlName) => ({ - product, - cargoPackage: product, - npmPackage: extensionNpmPackageForProduct(product), - mavenGroup: "dev.oliphaunt.extensions", - mavenArtifact: product, - ...metadata, - sqlName, - memberPath: extensionMemberPath(product, sqlName, TOOL), - sourceIdentity: extensionSourceIdentity(product, TOOL), - })); - })); -} - -function usage() { - return `usage: tools/release/release_graph_query.mjs [options] - -Commands: - ci-artifact-names --family release-assets|npm-package|sdk-package --product PRODUCT [--kind KIND] [--format json|lines] - ci-products --family sdk-package|extension-artifacts [--products-json JSON] [--carrier-family native|wasix] [--field product|artifact-root] [--format json|lines] - extension-artifact-root --product PRODUCT [--family native|wasix] - extension-metadata [--product PRODUCT] -`; -} - -function main(argv) { - const [command, ...rest] = argv; - if (command === "ci-artifact-names") runCiArtifactNames(rest); - else if (command === "ci-products") runCiProducts(rest); - else if (command === "extension-artifact-root") runExtensionArtifactRoot(rest); - else if (command === "extension-metadata") runExtensionMetadata(rest); - else if (command === "--help" || command === "-h") console.log(usage()); - else fail(command ? `unknown command ${command}` : "missing command"); -} - -if (import.meta.main) main(Bun.argv.slice(2)); diff --git a/tools/release/release_plan.mjs b/tools/release/release_plan.mjs deleted file mode 100644 index 244cac382..000000000 --- a/tools/release/release_plan.mjs +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env bun -import { - buildPlan, - buildPlanFromProductTags, - changedFilesFromRefs, - compareText, - loadGraph, - normalizeFiles, - wasixEvidenceProductsForRelease, -} from "./release-graph.mjs"; -import { extensionArtifactProductsForReleaseProducts } from "./release-artifact-targets.mjs"; - -const TOOL = "release_plan.mjs"; - -function fail(message) { - console.error(`${TOOL}: ${message}`); - process.exit(2); -} - -function sortedValue(value) { - if (Array.isArray(value)) { - return value.map(sortedValue); - } - if (value !== null && typeof value === "object") { - return Object.fromEntries( - Object.keys(value) - .sort(compareText) - .map((key) => [key, sortedValue(value[key])]), - ); - } - return value; -} - -function printJson(plan) { - console.log(JSON.stringify(sortedValue(plan), null, 2)); -} - -function printGithubOutput(plan) { - const products = plan.releaseProducts; - const graph = loadGraph(TOOL); - const wasixEvidenceProducts = wasixEvidenceProductsForRelease( - graph.products, - graph.moon_projects, - products, - TOOL, - ); - const extensionProducts = products.filter((product) => product.startsWith("oliphaunt-extension-")).sort(compareText); - const extensionArtifactProducts = extensionArtifactProductsForReleaseProducts(products, { prefix: TOOL }); - console.log(`has_release_changes=${String(plan.hasReleaseChanges).toLowerCase()}`); - console.log(`has_extension_products=${String(extensionProducts.length > 0).toLowerCase()}`); - console.log(`has_extension_artifacts=${String(extensionArtifactProducts.length > 0).toLowerCase()}`); - console.log(`products_json=${JSON.stringify(products)}`); - console.log(`extension_products_json=${JSON.stringify(extensionProducts)}`); - console.log(`requires_wasix_release_regression_evidence=${String(wasixEvidenceProducts.length > 0).toLowerCase()}`); -} - -function printText(plan) { - const changedFiles = plan.changedFiles ?? []; - if (changedFiles.length === 0) { - console.log("No changed files were provided; no product release is planned."); - } else if (plan.hasReleaseChanges) { - console.log(`Release products: ${plan.releaseProducts.join(", ")}`); - console.log(`Direct products: ${plan.directProducts.join(", ")}`); - } else { - console.log("No product release is planned for these changes."); - } -} - -function parseArgs(argv) { - const args = { - baseRef: undefined, - headRef: "HEAD", - fromProductTags: false, - includeCurrentTags: false, - changedFiles: [], - format: "text", - }; - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - if (value === "--base-ref") { - if (index + 1 >= argv.length) { - fail("--base-ref requires a value"); - } - args.baseRef = argv[index + 1]; - index += 1; - } else if (value.startsWith("--base-ref=")) { - args.baseRef = value.slice("--base-ref=".length); - } else if (value === "--head-ref") { - if (index + 1 >= argv.length) { - fail("--head-ref requires a value"); - } - args.headRef = argv[index + 1]; - index += 1; - } else if (value.startsWith("--head-ref=")) { - args.headRef = value.slice("--head-ref=".length); - } else if (value === "--from-product-tags") { - args.fromProductTags = true; - } else if (value === "--include-current-tags") { - args.includeCurrentTags = true; - } else if (value === "--changed-file") { - if (index + 1 >= argv.length) { - fail("--changed-file requires a value"); - } - args.changedFiles.push(argv[index + 1]); - index += 1; - } else if (value.startsWith("--changed-file=")) { - args.changedFiles.push(value.slice("--changed-file=".length)); - } else if (value === "--format") { - if (index + 1 >= argv.length) { - fail("--format requires a value"); - } - args.format = argv[index + 1]; - index += 1; - } else if (value.startsWith("--format=")) { - args.format = value.slice("--format=".length); - } else if (value === "-h" || value === "--help") { - console.log("usage: tools/release/release_plan.mjs [--base-ref REF] [--head-ref REF] [--from-product-tags] [--include-current-tags] [--changed-file PATH...] [--format text|json|github-output]"); - process.exit(0); - } else { - fail(`unknown argument ${value}`); - } - } - if (!["text", "json", "github-output"].includes(args.format)) { - fail("--format must be one of: text, json, github-output"); - } - return args; -} - -function planForArgs(args) { - const graph = loadGraph(TOOL); - let plan; - if (args.changedFiles.length > 0) { - plan = buildPlan(graph, normalizeFiles(args.changedFiles), TOOL); - } else if (args.fromProductTags) { - plan = buildPlanFromProductTags(graph, args.headRef, { - includeCurrentTags: args.includeCurrentTags, - prefix: TOOL, - }); - } else if (args.baseRef) { - plan = buildPlan(graph, normalizeFiles(changedFilesFromRefs(args.baseRef, args.headRef, TOOL)), TOOL); - } else { - plan = buildPlan(graph, [], TOOL); - } - return plan; -} - -function main(argv) { - const args = parseArgs(argv); - const plan = planForArgs(args); - if (args.format === "json") { - printJson(plan); - } else if (args.format === "github-output") { - printGithubOutput(plan); - } else { - printText(plan); - } -} - -if (import.meta.main) { - main(Bun.argv.slice(2)); -} diff --git a/tools/release/release_plan.mts b/tools/release/release_plan.mts new file mode 100644 index 000000000..ca8ef94ae --- /dev/null +++ b/tools/release/release_plan.mts @@ -0,0 +1,193 @@ +#!/usr/bin/env bun +import { writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { extensionArtifactProductsForReleaseProducts } from './release-artifact-targets.mts'; +import { + buildPlan, + buildPlanFromProductTags, + changedFilesFromRefs, + compareText, + loadGraph, + normalizeFiles, + wasixEvidenceProductsForRelease, +} from './release-graph.mts'; + +const TOOL = 'release_plan.mts'; + +function fail(message) { + console.error(`${TOOL}: ${message}`); + process.exit(2); +} + +function sortedValue(value) { + if (Array.isArray(value)) { + return value.map(sortedValue); + } + if (value !== null && typeof value === 'object') { + return Object.fromEntries( + Object.keys(value) + .sort(compareText) + .map((key) => [key, sortedValue(value[key])]), + ); + } + return value; +} + +function printJson(plan) { + console.log(JSON.stringify(sortedValue(plan), null, 2)); +} + +function printGithubOutput(plan) { + const products = plan.releaseProducts; + const graph = loadGraph(TOOL); + const wasixEvidenceProducts = wasixEvidenceProductsForRelease( + graph.products, + graph.moon_projects, + products, + TOOL, + ); + const extensionProducts = products + .filter((product) => product.startsWith('oliphaunt-extension-')) + .sort(compareText); + const extensionArtifactProducts = extensionArtifactProductsForReleaseProducts(products, { + prefix: TOOL, + }); + console.log(`has_release_changes=${String(plan.hasReleaseChanges).toLowerCase()}`); + console.log(`has_extension_products=${String(extensionProducts.length > 0).toLowerCase()}`); + console.log( + `has_extension_artifacts=${String(extensionArtifactProducts.length > 0).toLowerCase()}`, + ); + console.log(`products_json=${JSON.stringify(products)}`); + console.log(`extension_products_json=${JSON.stringify(extensionProducts)}`); + console.log( + `requires_wasix_release_regression_evidence=${String(wasixEvidenceProducts.length > 0).toLowerCase()}`, + ); +} + +function printText(plan) { + const changedFiles = plan.changedFiles ?? []; + if (changedFiles.length === 0) { + console.log('No changed files were provided; no product release is planned.'); + } else if (plan.hasReleaseChanges) { + console.log(`Release products: ${plan.releaseProducts.join(', ')}`); + console.log(`Direct products: ${plan.directProducts.join(', ')}`); + } else { + console.log('No product release is planned for these changes.'); + } +} + +function parseArgs(argv) { + const args = { + baseRef: undefined, + headRef: 'HEAD', + fromProductTags: false, + includeCurrentTags: false, + changedFiles: [], + format: 'text', + }; + for (let index = 0; index < argv.length; index += 1) { + const value = argv[index]; + if (value === '--base-ref') { + if (index + 1 >= argv.length) { + fail('--base-ref requires a value'); + } + args.baseRef = argv[index + 1]; + index += 1; + } else if (value.startsWith('--base-ref=')) { + args.baseRef = value.slice('--base-ref='.length); + } else if (value === '--head-ref') { + if (index + 1 >= argv.length) { + fail('--head-ref requires a value'); + } + args.headRef = argv[index + 1]; + index += 1; + } else if (value.startsWith('--head-ref=')) { + args.headRef = value.slice('--head-ref='.length); + } else if (value === '--from-product-tags') { + args.fromProductTags = true; + } else if (value === '--include-current-tags') { + args.includeCurrentTags = true; + } else if (value === '--changed-file') { + if (index + 1 >= argv.length) { + fail('--changed-file requires a value'); + } + args.changedFiles.push(argv[index + 1]); + index += 1; + } else if (value.startsWith('--changed-file=')) { + args.changedFiles.push(value.slice('--changed-file='.length)); + } else if (value === '--format') { + if (index + 1 >= argv.length) { + fail('--format requires a value'); + } + args.format = argv[index + 1]; + index += 1; + } else if (value.startsWith('--format=')) { + args.format = value.slice('--format='.length); + } else if (value === '-h' || value === '--help') { + console.log( + 'usage: bash tools/release/release-plan.sh [--base-ref REF] [--head-ref REF] [--from-product-tags] [--include-current-tags] [--changed-file PATH...] [--format text|json|github-output]', + ); + process.exit(0); + } else { + fail(`unknown argument ${value}`); + } + } + if (!['text', 'json', 'github-output'].includes(args.format)) { + fail('--format must be one of: text, json, github-output'); + } + return args; +} + +function planForArgs(args) { + const graph = loadGraph(TOOL); + let plan; + if (args.changedFiles.length > 0) { + plan = buildPlan(graph, normalizeFiles(args.changedFiles), TOOL); + } else if (args.fromProductTags) { + plan = buildPlanFromProductTags(graph, args.headRef, { + includeCurrentTags: args.includeCurrentTags, + prefix: TOOL, + }); + } else if (args.baseRef) { + plan = buildPlan( + graph, + normalizeFiles(changedFilesFromRefs(args.baseRef, args.headRef, TOOL)), + TOOL, + ); + } else { + plan = buildPlan(graph, [], TOOL); + } + return plan; +} + +function main(argv) { + if (argv[0] === '--history-inputs') { + const directory = argv[1]; + const args = parseArgs(argv.slice(2)); + const needsHistory = args.changedFiles.length === 0 && (args.fromProductTags || args.baseRef); + writeFileSync( + path.join(directory, 'refs'), + [needsHistory ? args.headRef : '', args.fromProductTags ? '' : (args.baseRef ?? '')] + .map((value) => value + '\0') + .join(''), + ); + writeFileSync( + path.join(directory, 'graph.json'), + JSON.stringify({ products: args.fromProductTags ? loadGraph(TOOL).products : {} }), + ); + return; + } + const args = parseArgs(argv); + const plan = planForArgs(args); + if (args.format === 'json') { + printJson(plan); + } else if (args.format === 'github-output') { + printGithubOutput(plan); + } else { + printText(plan); + } +} + +if (import.meta.main) { + main(Bun.argv.slice(2)); +} diff --git a/tools/release/render_swiftpm_release_package.mjs b/tools/release/render_swiftpm_release_package.mjs deleted file mode 100755 index ecaaf92ce..000000000 --- a/tools/release/render_swiftpm_release_package.mjs +++ /dev/null @@ -1,577 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import fs from "node:fs/promises"; -import path from "node:path"; - -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { productCompatibilityVersion } from "./release-graph.mjs"; -import { validateNativeIcuDataManifest } from "./native-icu-data-contract.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const REPOSITORY = "f0rr0/oliphaunt"; -const MAX_REMOTE_CHECKSUM_MANIFEST_BYTES = 1024 * 1024; - -function fail(message) { - console.error(`render_swiftpm_release_package.mjs: ${message}`); - process.exit(1); -} - -async function fileStat(file) { - return fs.stat(file).catch(() => null); -} - -async function isFile(file) { - const stat = await fileStat(file); - return stat?.isFile() === true; -} - -async function sha256(file) { - return createHash("sha256").update(await fs.readFile(file)).digest("hex"); -} - -function checksumFromManifest(text, asset) { - for (const rawLine of text.split(/\r?\n/u)) { - const line = rawLine.trim(); - if (!line) { - continue; - } - const parts = line.split(/\s+/u); - if (parts.length !== 2) { - continue; - } - const [digest, filename] = parts; - if (filename === `./${asset}` || filename === asset) { - return digest; - } - } - return undefined; -} - -async function readZipArchive(file) { - const entries = readPortableArchiveEntries(file, { format: "zip" }); - return { - names: new Set(entries.keys()), - read(entryName) { - const entry = entries.get(entryName); - return entry?.isFile ? Buffer.from(entry.data()) : undefined; - }, - }; -} - -function xmlDecode(value) { - return value - .replaceAll(""", '"') - .replaceAll("'", "'") - .replaceAll("<", "<") - .replaceAll(">", ">") - .replaceAll("&", "&"); -} - -function tokenizeXml(text) { - return Array.from(text.matchAll(/<[^>]+>|[^<]+/gu), (match) => match[0]); -} - -function tagName(token) { - return token - .replace(/^<\//u, "") - .replace(/^$/u, "") - .trim() - .split(/\s+/u)[0]; -} - -class PlistParser { - constructor(text) { - this.tokens = tokenizeXml(text); - this.index = 0; - } - - parse() { - const token = this.nextToken(); - if (!this.isOpening(token, "plist")) { - throw new Error("plist root element is missing"); - } - const value = this.parseValue(); - const closing = this.nextToken(); - if (!this.isClosing(closing, "plist")) { - throw new Error("plist root element is not closed"); - } - return value; - } - - nextToken() { - while (this.index < this.tokens.length) { - const token = this.tokens[this.index]; - this.index += 1; - if (!token.startsWith("<") && token.trim() === "") { - continue; - } - if ( - token.startsWith(""); - } - - isClosing(token, name) { - return token.startsWith(""); - } - - parseValue() { - const token = this.nextToken(); - if (this.isOpening(token, "dict")) { - return this.parseDict(); - } - if (this.isOpening(token, "array")) { - return this.parseArray(); - } - if (this.isOpening(token, "string")) { - return this.parseTextElement("string"); - } - if (this.isSelfClosing(token, "string")) { - return ""; - } - if (this.isOpening(token, "integer")) { - return Number.parseInt(this.parseTextElement("integer"), 10); - } - if (this.isSelfClosing(token, "true")) { - return true; - } - if (this.isSelfClosing(token, "false")) { - return false; - } - throw new Error(`unsupported plist value ${token}`); - } - - parseDict() { - const result = {}; - while (true) { - const token = this.peekToken(); - if (this.isClosing(token, "dict")) { - this.nextToken(); - return result; - } - const keyOpen = this.nextToken(); - if (!this.isOpening(keyOpen, "key")) { - throw new Error(`expected plist dict key, got ${keyOpen}`); - } - const key = this.parseTextElement("key"); - result[key] = this.parseValue(); - } - } - - parseArray() { - const result = []; - while (true) { - const token = this.peekToken(); - if (this.isClosing(token, "array")) { - this.nextToken(); - return result; - } - result.push(this.parseValue()); - } - } - - parseTextElement(name) { - let text = ""; - while (true) { - const token = this.nextToken(); - if (this.isClosing(token, name)) { - return xmlDecode(text); - } - if (token.startsWith("<")) { - throw new Error(`unexpected tag in plist ${name}: ${token}`); - } - text += token; - } - } -} - -function parsePlist(buffer, source) { - const prefix = buffer.subarray(0, 6).toString("utf8"); - if (prefix === "bplist") { - fail(`SwiftPM Apple XCFramework Info.plist must be XML for release validation: ${source}`); - } - try { - return new PlistParser(buffer.toString("utf8")).parse(); - } catch (error) { - fail(`SwiftPM Apple XCFramework Info.plist is invalid in ${source}: ${error.message}`); - } -} - -async function validateAppleXcframeworkAsset(file) { - let archive; - try { - archive = await readZipArchive(file); - } catch (error) { - fail(`SwiftPM Apple XCFramework asset is not a readable zip file: ${file}: ${error.message}`); - } - const infoData = archive.read("liboliphaunt.xcframework/Info.plist"); - if (infoData === undefined) { - fail(`SwiftPM Apple XCFramework asset is missing liboliphaunt.xcframework/Info.plist: ${file}`); - } - const info = parsePlist(infoData, file); - if (info === null || Array.isArray(info) || typeof info !== "object") { - fail(`SwiftPM Apple XCFramework Info.plist must be a plist dictionary in ${file}`); - } - const libraries = info.AvailableLibraries; - if (!Array.isArray(libraries) || libraries.length === 0) { - fail(`SwiftPM Apple XCFramework Info.plist has no AvailableLibraries in ${file}`); - } - - const slices = new Set(); - for (const library of libraries) { - if (library === null || Array.isArray(library) || typeof library !== "object") { - continue; - } - const platform = library.SupportedPlatform; - const variant = library.SupportedPlatformVariant ?? ""; - const libraryPath = library.LibraryPath; - const identifier = library.LibraryIdentifier; - const architectures = library.SupportedArchitectures; - if ( - typeof platform !== "string" || - typeof libraryPath !== "string" || - typeof identifier !== "string" || - !Array.isArray(architectures) || - architectures.some((architecture) => typeof architecture !== "string") - ) { - continue; - } - for (const architecture of architectures) { - slices.add(`${platform}\0${typeof variant === "string" ? variant : ""}\0${architecture}`); - } - const candidate = `liboliphaunt.xcframework/${identifier}/${libraryPath}`; - if (!archive.names.has(candidate) && !Array.from(archive.names).some((name) => name.startsWith(`${candidate}/`))) { - fail(`SwiftPM Apple XCFramework is missing declared library ${candidate}`); - } - } - - const missing = missingRequiredAppleArm64Slices(slices); - if (missing.length > 0) { - fail(`SwiftPM Apple XCFramework asset ${file} is missing required arm64 slice(s): ${missing.join(", ")}`); - } -} - -export function missingRequiredAppleArm64Slices(slices) { - const required = [ - ["macos", "", "arm64"], - ["ios", "", "arm64"], - ["ios", "simulator", "arm64"], - ]; - return required - .filter(([platform, variant, architecture]) => !slices.has(`${platform}\0${variant}\0${architecture}`)) - .map(([platform, variant, architecture]) => - `${platform}${variant ? `-${variant}` : ""}-${architecture}`) - .sort(); -} - -function safeIcuRelativePath(memberName) { - const trimmed = memberName.replace(/^\.\//u, "").replace(/\/+$/u, ""); - if (trimmed === "share/icu" || !trimmed.startsWith("share/icu/")) { - return undefined; - } - const relative = trimmed.slice("share/icu/".length); - const parts = relative.split("/"); - if ( - relative.length === 0 || - path.posix.isAbsolute(relative) || - parts.some((part) => part.length === 0 || part === "." || part === "..") - ) { - fail(`SwiftPM ICU data asset contains unsafe path: ${memberName}`); - } - return relative; -} - -async function prepareIcuResourceTree(assetDir, version, generatedTree) { - if (generatedTree === undefined) { - return; - } - const archivePath = path.join(assetDir, `liboliphaunt-${version}-icu-data.tar.gz`); - if (!(await isFile(archivePath))) { - fail(`SwiftPM ICU resource product requires local ICU data asset: ${archivePath}`); - } - const target = path.join(generatedTree, "generated/swiftpm/OliphauntICU"); - await fs.rm(target, { recursive: true, force: true }); - await fs.mkdir(path.join(target, "share/icu"), { recursive: true }); - - let copied = 0; - let entries; - try { - entries = readPortableArchiveEntries(archivePath, { format: "tar.gz" }); - } catch (error) { - fail(`SwiftPM ICU data asset is not a strict portable tar archive: ${archivePath}: ${error.message}`); - } - - for (const [memberName, entry] of entries) { - const relative = safeIcuRelativePath(memberName); - if (relative !== undefined) { - const destination = path.join(target, "share/icu", ...relative.split("/")); - if (entry.isDirectory) { - await fs.mkdir(destination, { recursive: true }); - } else if (entry.isFile) { - await fs.mkdir(path.dirname(destination), { recursive: true }); - await fs.writeFile(destination, entry.data()); - copied += 1; - } else { - fail(`SwiftPM ICU data asset member must be a regular file or directory: ${memberName}`); - } - continue; - } - if (memberName.replace(/^\.\//u, "") === "manifest.properties" && entry.isFile) { - await fs.writeFile(path.join(target, "manifest.properties"), entry.data()); - } - } - - const icuEntries = await fs.readdir(path.join(target, "share/icu")).catch(() => []); - if (copied === 0 || !icuEntries.some((name) => name.startsWith("icudt"))) { - fail(`SwiftPM ICU resource product did not extract ICU icudt data from ${archivePath}`); - } - try { - validateNativeIcuDataManifest( - await fs.readFile(path.join(target, "manifest.properties")), - path.join(target, "share/icu"), - `${archivePath} manifest.properties`, - ); - } catch (error) { - fail(`SwiftPM ICU resource product did not extract its exact data receipt from ${archivePath}: ${error instanceof Error ? error.message : String(error)}`); - } - await fs.writeFile( - path.join(target, "OliphauntICU.swift"), - "public enum OliphauntICUResources {\n public static let bundled = true\n}\n", - "utf8", - ); -} - -export async function fetchText(url, { - fetchImpl = fetch, - timeoutMs = 20_000, -} = {}) { - const response = await fetchImpl(url, { - redirect: "follow", - signal: AbortSignal.timeout(timeoutMs), - }); - if (!response.ok) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`HTTP ${response.status}`); - } - const contentLength = response.headers?.get?.("content-length"); - if (contentLength !== null && contentLength !== undefined) { - const declared = Number(contentLength); - if (!Number.isSafeInteger(declared) || declared < 0) { - await response.body?.cancel?.().catch(() => {}); - throw new Error("checksum manifest returned an invalid Content-Length"); - } - if (declared > MAX_REMOTE_CHECKSUM_MANIFEST_BYTES) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`checksum manifest exceeds ${MAX_REMOTE_CHECKSUM_MANIFEST_BYTES} bytes`); - } - } - const reader = response.body?.getReader?.(); - if (reader === undefined) { - const text = await response.text(); - if (Buffer.byteLength(text) > MAX_REMOTE_CHECKSUM_MANIFEST_BYTES) { - throw new Error(`checksum manifest exceeds ${MAX_REMOTE_CHECKSUM_MANIFEST_BYTES} bytes`); - } - return text; - } - const chunks = []; - let size = 0; - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > MAX_REMOTE_CHECKSUM_MANIFEST_BYTES) { - await reader.cancel().catch(() => {}); - throw new Error(`checksum manifest exceeds ${MAX_REMOTE_CHECKSUM_MANIFEST_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - } finally { - reader.releaseLock(); - } - return Buffer.concat(chunks, size).toString("utf8"); -} - -async function resolveChecksum(assetDir, assetBaseUrl, asset, version) { - const localAsset = path.join(assetDir, asset); - const localAssetStat = await fileStat(localAsset); - if (localAssetStat?.isFile()) { - if (localAssetStat.size <= 0) { - fail(`SwiftPM Apple XCFramework asset is empty: ${localAsset}`); - } - await validateAppleXcframeworkAsset(localAsset); - return sha256(localAsset); - } - - const localManifest = path.join(assetDir, `liboliphaunt-${version}-release-assets.sha256`); - if (await isFile(localManifest)) { - const checksum = checksumFromManifest(await fs.readFile(localManifest, "utf8"), asset); - if (checksum) { - return checksum; - } - } - - const manifestUrl = `${assetBaseUrl.replace(/\/+$/u, "")}/liboliphaunt-${version}-release-assets.sha256`; - let text; - try { - text = await fetchText(manifestUrl); - } catch (error) { - fail( - `SwiftPM asset ${asset} is not present in ${assetDir}, and checksum ` + - `manifest could not be read from ${manifestUrl}: ${error.message}`, - ); - } - const checksum = checksumFromManifest(text, asset); - if (!checksum) { - fail(`checksum manifest ${manifestUrl} does not contain ${asset}`); - } - return checksum; -} - -function renderManifest(assetBaseUrl, liboliphauntVersion, checksum) { - const asset = `liboliphaunt-${liboliphauntVersion}-apple-spm-xcframework.zip`; - const url = `${assetBaseUrl.replace(/\/+$/u, "")}/${asset}`; - return `// swift-tools-version: 6.0 - -import PackageDescription - -// Generated by tools/release/render_swiftpm_release_package.mjs. -// This is the public SwiftPM release manifest. The source package under -// src/sdks/swift remains the local development package. -// Exact PostgreSQL extensions are released as separate opt-in extension -// artifacts. The base Swift package must not require or publish extension files. -let package = Package( - name: "Oliphaunt", - platforms: [ - .iOS(.v17), - .macOS(.v14) - ], - products: [ - .library(name: "COliphaunt", targets: ["COliphaunt"]), - .library(name: "Oliphaunt", targets: ["Oliphaunt"]), - .library(name: "OliphauntExtensionSupport", targets: ["OliphauntExtensionSupport"]), - .library(name: "OliphauntICU", targets: ["OliphauntICU"]) - ], - targets: [ - .binaryTarget( - name: "liboliphaunt", - url: "${url}", - checksum: "${checksum}" - ), - .target( - name: "COliphaunt", - dependencies: ["liboliphaunt"], - path: "src/sdks/swift/Sources/COliphaunt", - publicHeadersPath: "include" - ), - .target( - name: "Oliphaunt", - dependencies: ["COliphaunt"], - path: "src/sdks/swift/Sources/Oliphaunt" - ), - .target( - name: "OliphauntExtensionSupport", - dependencies: ["COliphaunt", "Oliphaunt"], - path: "src/sdks/swift/Sources/OliphauntExtensionSupport" - ), - .target( - name: "OliphauntICU", - path: "generated/swiftpm/OliphauntICU", - resources: [.copy("share"), .copy("manifest.properties")] - ) - ] -) -`; -} - -function parseArgs(argv) { - const usage = - "usage: tools/release/render_swiftpm_release_package.mjs [--asset-dir DIR] [--asset-base-url URL] [--output FILE] [--generated-tree DIR]"; - if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h")) { - console.log(usage); - process.exit(0); - } - const args = {}; - for (let index = 0; index < argv.length; index += 1) { - let arg = argv[index]; - if (!arg.startsWith("--")) { - fail(usage); - } - let value; - const equals = arg.indexOf("="); - if (equals >= 0) { - value = arg.slice(equals + 1); - arg = arg.slice(0, equals); - } else { - value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) { - fail(`${arg} requires a value`); - } - index += 1; - } - if (!["--asset-dir", "--asset-base-url", "--output", "--generated-tree"].includes(arg)) { - fail(`unknown argument ${arg}`); - } - args[arg.slice(2)] = value; - } - return { - assetBaseUrl: args["asset-base-url"], - assetDir: args["asset-dir"] ?? "target/liboliphaunt/release-assets", - generatedTree: args["generated-tree"], - output: args.output, - }; -} - -async function main(argv) { - const args = parseArgs(argv); - const liboliphauntVersion = productCompatibilityVersion( - "oliphaunt-swift", - "liboliphaunt-native", - "render_swiftpm_release_package.mjs", - ); - const assetDir = path.resolve(ROOT, args.assetDir); - const asset = `liboliphaunt-${liboliphauntVersion}-apple-spm-xcframework.zip`; - const assetBaseUrl = - args.assetBaseUrl ?? - `https://github.com/${REPOSITORY}/releases/download/liboliphaunt-native-v${liboliphauntVersion}`; - const checksum = await resolveChecksum(assetDir, assetBaseUrl, asset, liboliphauntVersion); - const generatedTree = args.generatedTree ? path.resolve(ROOT, args.generatedTree) : undefined; - if (generatedTree !== undefined) { - await fs.mkdir(generatedTree, { recursive: true }); - } - await prepareIcuResourceTree(assetDir, liboliphauntVersion, generatedTree); - const manifest = renderManifest(assetBaseUrl, liboliphauntVersion, checksum); - if (args.output) { - const output = path.resolve(ROOT, args.output); - await fs.mkdir(path.dirname(output), { recursive: true }); - await fs.writeFile(output, manifest, "utf8"); - } else { - process.stdout.write(manifest); - } -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/render_swiftpm_release_package.test.mjs b/tools/release/render_swiftpm_release_package.test.mjs deleted file mode 100644 index adbe90477..000000000 --- a/tools/release/render_swiftpm_release_package.test.mjs +++ /dev/null @@ -1,48 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { fetchText, missingRequiredAppleArm64Slices } from "./render_swiftpm_release_package.mjs"; - -describe("SwiftPM Apple carrier architecture contract", () => { - test("accepts the three published arm64 slices", () => { - expect(missingRequiredAppleArm64Slices(new Set([ - "macos\0\0arm64", - "ios\0\0arm64", - "ios\0simulator\0arm64", - ]))).toEqual([]); - }); - - test("does not mistake Intel-only slices for the published arm64 support", () => { - expect(missingRequiredAppleArm64Slices(new Set([ - "macos\0\0x86_64", - "ios\0simulator\0x86_64", - ]))).toEqual([ - "ios-arm64", - "ios-simulator-arm64", - "macos-arm64", - ]); - }); -}); - -describe("SwiftPM remote checksum manifest", () => { - test("uses a bounded, timed request that permits the release-asset redirect", async () => { - let request; - const text = await fetchText("https://github.example/release/checksums", { - fetchImpl: async (url, options) => { - request = { url, options }; - return new Response("a".repeat(64) + " ./asset.zip\n"); - }, - timeoutMs: 1_000, - }); - expect(text).toContain("./asset.zip"); - expect(request.options.redirect).toBe("follow"); - expect(request.options.signal).toBeInstanceOf(AbortSignal); - }); - - test("rejects an oversized checksum manifest before reading it", async () => { - await expect(fetchText("https://github.example/release/checksums", { - fetchImpl: async () => new Response("x", { - headers: { "content-length": String(1024 * 1024 + 1) }, - }), - })).rejects.toThrow("checksum manifest exceeds 1048576 bytes"); - }); -}); diff --git a/tools/release/require-workflow-success.test.mjs b/tools/release/require-workflow-success.test.mjs deleted file mode 100644 index b1ea33380..000000000 --- a/tools/release/require-workflow-success.test.mjs +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { isolatedGitHubTestEnvironment } from "../test/isolated-github-test-environment.mjs"; - -const SCRIPT = path.resolve(".github/scripts/require-workflow-success.sh"); -const SHA = "a".repeat(40); -const WORKFLOW_HELPER_PROCESS_TIMEOUT_MS = 15_000; - -function fixture(t) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-workflow-waiter-")); - t.after(() => rmSync(root, { force: true, recursive: true })); - const bin = path.join(root, "bin"); - const mkdir = spawnSync("mkdir", ["-p", bin]); - assert.equal(mkdir.status, 0); - const gh = path.join(bin, "gh"); - writeFileSync(gh, `#!/usr/bin/env node -const fs = require("node:fs"); -const args = process.argv.slice(2); -fs.appendFileSync(process.env.FAKE_LOG, JSON.stringify(args) + "\\n"); -if (args[0] === "run" && args[1] === "view") { - const jobs = [{ name: "Qualified", conclusion: "success" }]; - if (process.env.FAKE_MODE === "duplicate-job") jobs.push({ ...jobs[0] }); - process.stdout.write(JSON.stringify({ jobs })); - process.exit(0); -} -if (args[0] === "api") { - const endpoint = args.find((arg) => arg.startsWith("repos/")); - if (/actions\\/workflows[?]/.test(endpoint)) { - process.stdout.write("HTTP/2.0 200 OK\\n\\n" + JSON.stringify({ workflows: [{ id: 9, name: "CI" }] })); - process.exit(0); - } - if (/actions\\/workflows\\/9\\/runs[?]/.test(endpoint)) { - const state = process.env.FAKE_STATE; - const count = fs.existsSync(state) ? Number(fs.readFileSync(state, "utf8")) : 0; - fs.writeFileSync(state, String(count + 1)); - if (process.env.FAKE_MODE === "transient" && count === 0) { - process.stderr.write("HTTP 503 temporary failure\\n"); - process.exit(1); - } - if (process.env.FAKE_MODE === "permanent") { - process.stderr.write("HTTP 401 Bad credentials\\n"); - process.exit(1); - } - const selected = { - id: 77, - head_sha: "${SHA}", - status: "completed", - conclusion: "success", - run_attempt: 3, - html_url: "https://example.invalid/run/77", - event: "push", - }; - const page = new URL("https://api.github.com/" + endpoint).searchParams.get("page"); - const workflow_runs = process.env.FAKE_MODE === "beyond-first-page" - ? page === "1" - ? Array.from({ length: 100 }, (_, index) => ({ - ...selected, - id: 100 + index, - conclusion: "failure", - })) - : [selected] - : [selected]; - const link = process.env.FAKE_MODE === "beyond-first-page" && page === "1" - ? 'Link: ; rel="next", ; rel="last"\\n' - : ""; - process.stdout.write("HTTP/2.0 200 OK\\n" + link + "\\n" + JSON.stringify({ workflow_runs })); - process.exit(0); - } - if (/actions\\/runs\\/77\\/artifacts/.test(endpoint)) { - const artifact = { - id: 901, - name: "required-artifact", - size_in_bytes: 123, - digest: "sha256:" + "1".repeat(64), - expired: false, - }; - const gateArtifact = { - id: 903, - name: "gate-artifact", - size_in_bytes: 456, - digest: "sha256:" + "2".repeat(64), - expired: false, - }; - const artifacts = process.env.FAKE_MODE === "duplicate-artifact" - ? [artifact, { ...artifact, id: 902 }] - : process.env.FAKE_MODE === "expired-artifact" - ? [{ ...artifact, expired: true }] - : process.env.FAKE_MODE === "missing-gate-artifact" - ? [artifact] - : process.env.FAKE_MODE === "malformed-artifact-metadata" - ? [{ ...artifact, digest: undefined }] - : [artifact, gateArtifact]; - process.stdout.write("HTTP/2.0 200 OK\\n\\n" + JSON.stringify({ artifacts })); - process.exit(0); - } - if (/actions\\/runs\\/77$/.test(endpoint)) { - const sha = process.env.FAKE_MODE === "wrong-sha" - ? "${"b".repeat(40)}" - : process.env.FAKE_MODE === "upper-sha" - ? "${SHA.toUpperCase()}" - : "${SHA}"; - const status = process.env.FAKE_MODE === "in-progress-run" ? "in_progress" : "completed"; - const conclusion = process.env.FAKE_MODE === "in-progress-run" - ? "" - : process.env.FAKE_MODE === "failed-run" - ? "failure" - : "success"; - process.stdout.write(sha + "\\t9\\tpush\\t" + status + "\\t" + conclusion + "\\t3\\n"); - process.exit(0); - } - if (/actions\\/workflows\\/9$/.test(endpoint)) { - process.stdout.write("CI\\n"); - process.exit(0); - } -} -throw new Error("unexpected gh call " + JSON.stringify(args)); -`); - chmodSync(gh, 0o755); - const sleep = path.join(bin, "sleep"); - writeFileSync(sleep, "#!/bin/sh\nexit 0\n", { mode: 0o755 }); - chmodSync(sleep, 0o755); - const output = path.join(root, "output"); - writeFileSync(output, ""); - return { bin, log: path.join(root, "log"), output, root, state: path.join(root, "state") }; -} - -function invoke(f, mode, args = ["CI", SHA, "10", "--job", "Qualified", "--artifact", "required-artifact"]) { - return spawnSync("bash", [SCRIPT, ...args], { - cwd: process.cwd(), - encoding: "utf8", - env: isolatedGitHubTestEnvironment({ - PATH: `${f.bin}${path.delimiter}${process.env.PATH}`, - FAKE_LOG: f.log, - FAKE_MODE: mode, - FAKE_STATE: f.state, - GH_REPO: "f0rr0/oliphaunt", - GH_TOKEN: "test-token", - GITHUB_OUTPUT: f.output, - OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: "0", - OLIPHAUNT_GITHUB_READ_DEADLINE_MS: "1000", - OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: "1", - OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: "0", - }), - timeout: WORKFLOW_HELPER_PROCESS_TIMEOUT_MS, - }); -} - -test("a transient exact-SHA run-inventory failure does not abort the long-lived workflow waiter", (t) => { - const f = fixture(t); - const result = invoke(f, "transient"); - assert.equal(result.status, 0, result.stderr); - assert.match(result.stderr, /waiter remains active/u); - assert.match(result.stdout, /selected CI run 77/u); - assert.equal( - readFileSync(f.output, "utf8"), - `run_id=77\nrun_attempt=3\nartifact_metadata_json=${JSON.stringify([{ - digest: `sha256:${"1".repeat(64)}`, - id: 901, - name: "required-artifact", - size: 123, - }])}\ngate_artifact_metadata_json=[]\n`, - ); - assert.equal(readFileSync(f.state, "utf8"), "2"); -}); - -test("permanent authentication failures abort immediately with a distinct status", (t) => { - const f = fixture(t); - const result = invoke(f, "permanent"); - assert.equal(result.status, 64); - assert.match(result.stderr, /permanent GitHub read failure/u); - assert.equal(readFileSync(f.state, "utf8"), "1"); -}); - -test("exact-SHA REST pagination discovers a qualifying run beyond the first 100 newer failures", (t) => { - const f = fixture(t); - const result = invoke(f, "beyond-first-page"); - assert.equal(result.status, 0, result.stderr); - assert.match(result.stdout, /selected CI run 77/u); - const log = readFileSync(f.log, "utf8"); - assert.doesNotMatch(log, /\["run","list"|"--limit"/u); - assert.match(log, /actions\/workflows\/9\/runs/u); - assert.equal(readFileSync(f.state, "utf8"), "2"); -}); - -test("an explicitly selected run still fails closed on an exact-SHA mismatch", (t) => { - const f = fixture(t); - const result = invoke( - f, - "wrong-sha", - ["CI", SHA, "0", "--run-id", "77", "--job", "Qualified", "--artifact", "required-artifact"], - ); - assert.equal(result.status, 1); - assert.match(result.stderr, /belongs to .* not/u); - assert.equal(readFileSync(f.output, "utf8"), ""); -}); - -test("SHA comparison remains case-insensitive", (t) => { - const f = fixture(t); - const result = invoke( - f, - "upper-sha", - ["CI", SHA, "0", "--run-id", "77", "--job", "Qualified", "--artifact", "required-artifact"], - ); - assert.equal(result.status, 0, result.stderr); -}); - -test("successful named jobs cannot authorize a non-terminal or failed workflow run", (t) => { - for (const mode of ["in-progress-run", "failed-run"]) { - const f = fixture(t); - const result = invoke( - f, - mode, - ["CI", SHA, "0", "--run-id", "77", "--job", "Qualified", "--artifact", "required-artifact"], - ); - assert.equal(result.status, 1, `${mode}: ${result.stderr}`); - assert.match(result.stderr, /not completed\/success/u); - assert.equal(readFileSync(f.output, "utf8"), ""); - } -}); - -test("artifact gates require exactly one non-expired artifact identity", (t) => { - for (const mode of ["duplicate-artifact", "expired-artifact"]) { - const f = fixture(t); - const result = invoke( - f, - mode, - ["CI", SHA, "0", "--run-id", "77", "--job", "Qualified", "--artifact", "required-artifact"], - ); - assert.equal(result.status, 1, `${mode}: ${result.stderr}`); - assert.match(result.stderr, /exactly one non-expired artifact/u); - assert.equal(readFileSync(f.output, "utf8"), ""); - } -}); - -test("gate-only artifacts authorize a run without contaminating transfer metadata", (t) => { - const f = fixture(t); - const args = [ - "CI", - SHA, - "0", - "--artifact", - "required-artifact", - "--gate-artifact", - "gate-artifact", - ]; - const result = invoke(f, "", args); - assert.equal(result.status, 0, result.stderr); - assert.equal( - readFileSync(f.output, "utf8"), - `run_id=77\nrun_attempt=3\nartifact_metadata_json=${JSON.stringify([{ - digest: `sha256:${"1".repeat(64)}`, - id: 901, - name: "required-artifact", - size: 123, - }])}\ngate_artifact_metadata_json=${JSON.stringify([{ - digest: `sha256:${"2".repeat(64)}`, - id: 903, - name: "gate-artifact", - size: 456, - }])}\n`, - ); - - const missing = fixture(t); - const missingResult = invoke(missing, "missing-gate-artifact", args); - assert.equal(missingResult.status, 1, missingResult.stderr); - assert.match(missingResult.stderr, /gate-artifact.*found 0/u); - assert.equal(readFileSync(missing.output, "utf8"), ""); -}); - -test("transfer and gate artifact identities must be globally unique", (t) => { - const f = fixture(t); - const result = invoke( - f, - "", - [ - "CI", - SHA, - "0", - "--artifact", - "required-artifact", - "--gate-artifact", - "required-artifact", - ], - ); - assert.equal(result.status, 64, result.stderr); - assert.match(result.stderr, /artifact identity list is malformed/u); - assert.equal(readFileSync(f.output, "utf8"), ""); -}); - -test("malformed artifact metadata is a permanent protocol failure, not a retryable absence", (t) => { - const f = fixture(t); - const result = invoke(f, "malformed-artifact-metadata"); - assert.equal(result.status, 64, result.stderr); - assert.match(result.stderr, /artifact inventory contains malformed metadata/u); - assert.match(result.stderr, /permanent GitHub read failure/u); - assert.equal(readFileSync(f.state, "utf8"), "1"); - assert.equal(readFileSync(f.output, "utf8"), ""); -}); - -test("job gates require exactly one successful named job identity", (t) => { - const f = fixture(t); - const result = invoke( - f, - "duplicate-job", - ["CI", SHA, "0", "--run-id", "77", "--job", "Qualified", "--artifact", "required-artifact"], - ); - assert.equal(result.status, 1, result.stderr); - assert.match(result.stderr, /Qualified=count-2/u); - assert.equal(readFileSync(f.output, "utf8"), ""); -}); diff --git a/tools/release/require-workflow-success.test.mts b/tools/release/require-workflow-success.test.mts new file mode 100644 index 000000000..a4541859d --- /dev/null +++ b/tools/release/require-workflow-success.test.mts @@ -0,0 +1,70 @@ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { zipArchive } from '../packaging/testdata/zip-fixture.mts'; + +const [mode, root, scenario] = process.argv.slice(2); +const sha = 'a'.repeat(40); +if (mode === 'prepare') { + for (const id of [77, 88]) { + const products = scenario === 'uncovered' && id === 77 ? ['other-product'] : ['oliphaunt-js']; + const candidate = { + schemaVersion: 2, + sha, + runId: String(id), + runAttempt: 3, + repository: 'f0rr0/oliphaunt', + workflow: 'CI', + ref: 'refs/heads/main', + eventName: id === 88 ? 'workflow_dispatch' : 'push', + affectedPlan: { + digest: `sha256:${'1'.repeat(64)}`, + jobs: ['affected'], + projects: [], + extensionPackageProducts: [], + wasixReleaseRegressionRequired: false, + qualification: { + mode: 'selected-products', + baseSha: null, + headSha: sha, + products, + tasks: ['oliphaunt-js:package'], + }, + }, + evidenceRequirements: { wasixReleaseRegression: false, artifacts: [] }, + evidence: { wasixReleaseRegression: null }, + }; + writeFileSync( + path.join(root, `${id}.zip`), + zipArchive([ + { name: 'oliphaunt-release-candidate.json', data: Buffer.from(JSON.stringify(candidate)) }, + ]), + ); + } +} else if (mode === 'dispatch') { + const body = JSON.parse(readFileSync(path.join(root, 'dispatch.json'), 'utf8')); + assert.equal(body.ref, 'main'); + assert.equal(body.inputs.release_products_json, '["oliphaunt-js"]'); + assert(body.inputs.qualification_request.startsWith(sha)); +} else if (mode === 'output') { + const values = Object.fromEntries( + readFileSync(path.join(root, 'output'), 'utf8') + .trim() + .split('\n') + .map((line) => { + const index = line.indexOf('='); + return [line.slice(0, index), line.slice(index + 1)]; + }), + ); + assert.equal(values.run_id, '77'); + assert.equal(values.run_attempt, '3'); + assert.deepEqual(JSON.parse(values.artifact_metadata_json), [ + { digest: `sha256:${'1'.repeat(64)}`, id: 901, name: 'required-artifact', size: 123 }, + ]); + assert.deepEqual( + JSON.parse(values.gate_artifact_metadata_json), + scenario === 'gate' + ? [{ digest: `sha256:${'2'.repeat(64)}`, id: 903, name: 'gate-artifact', size: 456 }] + : [], + ); +} else throw Error('expected prepare, dispatch or output'); diff --git a/tools/release/require-workflow-success.test.sh b/tools/release/require-workflow-success.test.sh new file mode 100644 index 000000000..e12aeb5b2 --- /dev/null +++ b/tools/release/require-workflow-success.test.sh @@ -0,0 +1,134 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +source_root="$PWD" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +sha=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +deadline="$(command -v gtimeout || command -v timeout)" +mkdir "$scratch/bin" +printf '#!/bin/sh\nexit 0\n' > "$scratch/bin/sleep" +cat > "$scratch/bin/gh" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +[[ "$1" == api && "$2" == --method && "$3" == POST ]] || exit 93 +[[ ! -e "$FAKE_DISPATCH" ]] || exit 94 +while [[ $# -gt 0 ]]; do + if [[ "$1" == --input ]]; then cp "$2" "$FAKE_DISPATCH"; break; fi + shift +done +[[ "$FAKE_MODE" != qualification-ambiguous ]] || exit 95 +printf '{"workflow_run_id":88}\n' +SH +chmod +x "$scratch/bin/"* +prepare() { case_root="$scratch/$1"; mkdir "$case_root"; : > "$case_root/output"; } +invoke() { + local mode="$1"; shift + status=0 + env -i PATH="$scratch/bin:$PATH" HOME="$HOME" \ + BUN_OPTIONS="--preload=$source_root/tools/release/testdata/require-workflow-success-github.mts" \ + FAKE_LOG="$case_root/log" FAKE_STATE="$case_root/state" FAKE_MODE="$mode" \ + FAKE_RELEASE="$([[ "$1" == Release ]] && echo 1 || true)" \ + FAKE_DISPATCH="$case_root/dispatch.json" FAKE_ARCHIVE_ROOT="$case_root" \ + GH_REPO=f0rr0/oliphaunt GH_TOKEN=test-token GITHUB_OUTPUT="$case_root/output" \ + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS=0 OLIPHAUNT_GITHUB_READ_DEADLINE_MS=1000 \ + OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS=1 OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS=0 \ + "$deadline" 15 bash .github/scripts/require-workflow-success.sh "$@" > "$case_root/result" 2>&1 || status=$? +} +expect_status() { if [[ "$status" != "$1" ]]; then cat "$case_root/result" >&2; echo "Expected $1, got $status" >&2; exit 1; fi; } +selected=(CI "$sha" 0 --run-id 77 --job Qualified --artifact required-artifact) +standard=(CI "$sha" 10 --job Qualified --artifact required-artifact) +for mode in reuse active absent failed advanced ambiguous race uncovered; do + prepare "qualification-$mode" + bun tools/release/require-workflow-success.test.mts prepare "$case_root" "$mode" + scope=(CI "$sha" 10 --job Qualified --artifact oliphaunt-release-candidate) + invoke "qualification-$mode" "${scope[@]}" --plan-qualification '["oliphaunt-js"]' + [[ ! -e "$case_root/dispatch.json" ]] + if [[ "$status" == 0 ]] && rg -q 'qualification_request_required=true' "$case_root/output"; then + invoke "qualification-$mode" CI "$sha" 10 --dispatch-qualification '["oliphaunt-js"]' + if rg -q 'actions/runs/88/artifacts' "$case_root/log"; then echo 'Dispatch consumed candidate artifacts' >&2; exit 1; fi + fi + if [[ "$status" == 0 ]]; then invoke "qualification-$mode" "${scope[@]}" --qualification-products '["oliphaunt-js"]'; fi + case "$mode" in + reuse|active|absent|uncovered) expect_status 0 ;; + *) [[ "$status" != 0 ]] ;; + esac + case "$mode" in + absent|ambiguous|race|uncovered) + bun tools/release/require-workflow-success.test.mts dispatch "$case_root" + if [[ "$status" == 0 ]]; then + invoke "qualification-$mode" CI "$sha" 10 --dispatch-qualification '["oliphaunt-js"]' + expect_status 0 + fi ;; + *) [[ ! -e "$case_root/dispatch.json" ]] ;; + esac +done +prepare transient +invoke transient "${standard[@]}" +expect_status 0 +rg -q 'waiter remains active' "$case_root/result" +bun tools/release/require-workflow-success.test.mts output "$case_root" +[[ "$(cat "$case_root/state")" == 2 ]] +prepare permanent +invoke permanent "${standard[@]}" +expect_status 64 +rg -q 'permanent GitHub read failure' "$case_root/result" +[[ "$(cat "$case_root/state")" == 1 ]] +prepare pagination +invoke beyond-first-page "${standard[@]}" +expect_status 0 +rg -q 'selected CI run 77' "$case_root/result" +rg -q 'actions/workflows/9/runs' "$case_root/log" +[[ "$(cat "$case_root/state")" == 2 ]] +for mode in wrong-sha in-progress-run failed-run duplicate-artifact expired-artifact duplicate-job; do + prepare "$mode" + invoke "$mode" "${selected[@]}" + expect_status 1 + [[ ! -s "$case_root/output" ]] + case "$mode" in + wrong-sha) message='belongs to .* not' ;; + in-progress-run|failed-run) message='not completed/success' ;; + duplicate-artifact|expired-artifact) message='exactly one non-expired artifact' ;; + duplicate-job) message='Qualified=count-2' ;; + esac + rg -q "$message" "$case_root/result" +done +prepare upper-sha +invoke upper-sha "${selected[@]}" +expect_status 0 +gate=(CI "$sha" 0 --artifact required-artifact --gate-artifact gate-artifact) +prepare gate +invoke '' "${gate[@]}" +expect_status 0 +bun tools/release/require-workflow-success.test.mts output "$case_root" gate +prepare missing-gate +invoke missing-gate-artifact "${gate[@]}" +expect_status 1 +rg -q 'gate-artifact.*found 0' "$case_root/result" +[[ ! -s "$case_root/output" ]] +prepare duplicate-identities +invoke '' CI "$sha" 0 --artifact required-artifact --gate-artifact required-artifact +expect_status 64 +rg -q 'artifact identity list is malformed' "$case_root/result" +[[ ! -s "$case_root/output" ]] +prepare malformed-metadata +invoke malformed-artifact-metadata "${standard[@]}" +expect_status 64 +rg -q 'artifact inventory contains malformed metadata' "$case_root/result" +rg -q 'permanent GitHub read failure' "$case_root/result" +[[ "$(cat "$case_root/state")" == 1 && ! -s "$case_root/output" ]] +for mode in failed-run failed-candidate in-progress-run duplicate-job expired-artifact wrong-sha; do + prepare "recovery-$mode" + invoke "$mode" Release "$sha" 0 --run-id 77 --release-candidate --artifact required-artifact + if [[ "$mode" == failed-run ]]; then expect_status 0; else expect_status 1; [[ ! -s "$case_root/output" ]]; fi +done +prepare invalid-recovery +invoke failed-run CI "$sha" 0 --run-id 77 --release-candidate +expect_status 2 +for mode in metadata-auth metadata-transient; do + prepare "$mode" + invoke "$mode" CI "$sha" 0 --run-id 77 --job Qualified + if [[ "$mode" == metadata-auth ]]; then expect_status 64; else expect_status 75; fi + [[ ! -s "$case_root/output" ]] +done +echo 'Workflow waiter: qualification reuse/dispatch, exact evidence, retries and frozen recovery passed' diff --git a/tools/release/rust-build-script-sha256.mjs b/tools/release/rust-build-script-sha256.mjs deleted file mode 100644 index 5faf289a4..000000000 --- a/tools/release/rust-build-script-sha256.mjs +++ /dev/null @@ -1,135 +0,0 @@ -// Dependency-free SHA-256 used by generated Cargo build scripts. Keeping the -// implementation in the generated source avoids a registry lookup merely to -// validate payload bytes that are already frozen into a release carrier. -export const RUST_BUILD_SCRIPT_SHA256 = String.raw` -fn sha256_file(path: &Path) -> io::Result { - let mut file = fs::File::open(path)?; - let mut state = [ - 0x6a09e667_u32, - 0xbb67ae85, - 0x3c6ef372, - 0xa54ff53a, - 0x510e527f, - 0x9b05688c, - 0x1f83d9ab, - 0x5be0cd19, - ]; - let mut pending = [0_u8; 64]; - let mut pending_len = 0_usize; - let mut total_len = 0_u64; - let mut input = [0_u8; 64 * 1024]; - - loop { - let read = file.read(&mut input)?; - if read == 0 { - break; - } - total_len = total_len.wrapping_add(read as u64); - let mut offset = 0_usize; - if pending_len != 0 { - let copied = (64 - pending_len).min(read); - pending[pending_len..pending_len + copied].copy_from_slice(&input[..copied]); - pending_len += copied; - offset += copied; - if pending_len == 64 { - sha256_compress(&mut state, &pending); - pending_len = 0; - } - } - while offset + 64 <= read { - sha256_compress(&mut state, &input[offset..offset + 64]); - offset += 64; - } - if offset != read { - pending[..read - offset].copy_from_slice(&input[offset..read]); - pending_len = read - offset; - } - } - - pending[pending_len] = 0x80; - pending_len += 1; - if pending_len > 56 { - pending[pending_len..].fill(0); - sha256_compress(&mut state, &pending); - pending.fill(0); - } else { - pending[pending_len..56].fill(0); - } - pending[56..].copy_from_slice(&total_len.wrapping_mul(8).to_be_bytes()); - sha256_compress(&mut state, &pending); - - let mut output = String::with_capacity(64); - for word in state { - use std::fmt::Write as _; - write!(&mut output, "{word:08x}").expect("write SHA-256 hex digest"); - } - Ok(output) -} - -fn sha256_compress(state: &mut [u32; 8], block: &[u8]) { - const K: [u32; 64] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, - ]; - let mut schedule = [0_u32; 64]; - for (index, bytes) in block.chunks_exact(4).take(16).enumerate() { - schedule[index] = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]); - } - for index in 16..64 { - let s0 = schedule[index - 15].rotate_right(7) - ^ schedule[index - 15].rotate_right(18) - ^ (schedule[index - 15] >> 3); - let s1 = schedule[index - 2].rotate_right(17) - ^ schedule[index - 2].rotate_right(19) - ^ (schedule[index - 2] >> 10); - schedule[index] = schedule[index - 16] - .wrapping_add(s0) - .wrapping_add(schedule[index - 7]) - .wrapping_add(s1); - } - - let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h] = *state; - for index in 0..64 { - let sum1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25); - let choose = (e & f) ^ ((!e) & g); - let temporary1 = h - .wrapping_add(sum1) - .wrapping_add(choose) - .wrapping_add(K[index]) - .wrapping_add(schedule[index]); - let sum0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22); - let majority = (a & b) ^ (a & c) ^ (b & c); - let temporary2 = sum0.wrapping_add(majority); - h = g; - g = f; - f = e; - e = d.wrapping_add(temporary1); - d = c; - c = b; - b = a; - a = temporary1.wrapping_add(temporary2); - } - state[0] = state[0].wrapping_add(a); - state[1] = state[1].wrapping_add(b); - state[2] = state[2].wrapping_add(c); - state[3] = state[3].wrapping_add(d); - state[4] = state[4].wrapping_add(e); - state[5] = state[5].wrapping_add(f); - state[6] = state[6].wrapping_add(g); - state[7] = state[7].wrapping_add(h); -} -`; diff --git a/tools/release/rust-build-script-sha256.test.mjs b/tools/release/rust-build-script-sha256.test.mjs deleted file mode 100644 index f29e72fc5..000000000 --- a/tools/release/rust-build-script-sha256.test.mjs +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { - mkdirSync, - mkdtempSync, - rmSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import { expect, test } from "bun:test"; - -import { RUST_BUILD_SCRIPT_SHA256 } from "./rust-build-script-sha256.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); - -test("generated dependency-free Rust SHA-256 matches canonical known and boundary vectors", () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const root = mkdtempSync(path.join(ROOT, "target/rust-build-script-sha256-")); - try { - const source = path.join(root, "main.rs"); - const executable = path.join(root, process.platform === "win32" ? "sha256-fixture.exe" : "sha256-fixture"); - writeFileSync(source, `use std::fs; -use std::io::{self, Read}; -use std::path::Path; - -${RUST_BUILD_SCRIPT_SHA256} - -fn main() { - let input = std::env::args_os().nth(1).expect("input path"); - println!("{}", sha256_file(Path::new(&input)).expect("hash fixture")); -} -`); - const compiled = spawnSync("rustc", ["--edition", "2024", "-o", executable, source], { - cwd: ROOT, - encoding: "utf8", - stdio: ["ignore", "pipe", "pipe"], - }); - expect(compiled.status, compiled.stderr).toBe(0); - - const fixtures = [ - Buffer.alloc(0), - Buffer.from("abc"), - Buffer.alloc(55, 0x55), - Buffer.alloc(56, 0x56), - Buffer.alloc(63, 0x63), - Buffer.alloc(64, 0x64), - Buffer.alloc(65, 0x65), - Buffer.alloc(65_535, 0xa5), - Buffer.alloc(65_536, 0x5a), - Buffer.alloc(65_537, 0xc3), - ]; - for (const [index, bytes] of fixtures.entries()) { - const fixture = path.join(root, `fixture-${index}.bin`); - writeFileSync(fixture, bytes); - const result = spawnSync(executable, [fixture], { - cwd: ROOT, - encoding: "utf8", - stdio: ["ignore", "pipe", "pipe"], - }); - expect(result.status, result.stderr).toBe(0); - expect(result.stdout.trim()).toBe(createHash("sha256").update(bytes).digest("hex")); - } - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/release/rust-native-targets.mjs b/tools/release/rust-native-targets.mjs deleted file mode 100644 index 2ed65f643..000000000 --- a/tools/release/rust-native-targets.mjs +++ /dev/null @@ -1,79 +0,0 @@ -const NATIVE_TARGET_CFG = Object.freeze({ - "linux-arm64-gnu": 'all(target_os = "linux", target_arch = "aarch64", target_env = "gnu")', - "linux-x64-gnu": 'all(target_os = "linux", target_arch = "x86_64", target_env = "gnu")', - "macos-arm64": 'all(target_os = "macos", target_arch = "aarch64")', - "windows-x64-msvc": 'all(target_os = "windows", target_arch = "x86_64", target_env = "msvc")', -}); - -function fail(message) { - throw new Error(`rust-native-targets: ${message}`); -} - -function nonEmptyUniqueStrings(values, label) { - if (!Array.isArray(values) || values.length === 0) { - fail(`${label} must be a non-empty string list`); - } - if (!values.every((value) => typeof value === "string" && value.trim() === value && value.length > 0)) { - fail(`${label} must contain only non-empty, trimmed strings`); - } - if (new Set(values).size !== values.length) { - fail(`${label} must not contain duplicates`); - } - return values; -} - -export function rustNativeTargetCfg(target) { - const targetId = typeof target === "string" ? target : target?.target; - if (typeof targetId !== "string" || !(targetId in NATIVE_TARGET_CFG)) { - fail(`unsupported native Cargo target ${JSON.stringify(targetId)}`); - } - return NATIVE_TARGET_CFG[targetId]; -} - -export function assertSameNativeTargetSet(label, expected, actual) { - const expectedTargets = [...nonEmptyUniqueStrings(expected, `${label} expected targets`)].sort(); - const actualTargets = [...nonEmptyUniqueStrings(actual, `${label} actual targets`)].sort(); - if (JSON.stringify(expectedTargets) !== JSON.stringify(actualTargets)) { - fail( - `${label} target mismatch: expected=${JSON.stringify(expectedTargets)}, ` - + `actual=${JSON.stringify(actualTargets)}`, - ); - } -} - -export function renderUnsupportedNativeTargetGuard({ - product, - nativeTargets, - nativeCfgs, - feature = null, - featureLabel = null, - guidance, -}) { - if (typeof product !== "string" || product.trim() !== product || product.length === 0) { - fail("guard product must be a non-empty, trimmed string"); - } - const targets = nonEmptyUniqueStrings(nativeTargets, `${product} guard targets`); - const cfgs = nonEmptyUniqueStrings(nativeCfgs, `${product} guard cfgs`); - if (targets.length !== cfgs.length) { - fail(`${product} guard requires one cfg per declared target`); - } - if (feature !== null && (typeof feature !== "string" || feature.trim() !== feature || feature.length === 0)) { - fail(`${product} guard feature must be null or a non-empty, trimmed string`); - } - if (featureLabel !== null && feature === null) { - fail(`${product} guard cannot declare a feature label without a feature`); - } - if (typeof guidance !== "string" || guidance.trim() !== guidance || guidance.length === 0) { - fail(`${product} guard guidance must be a non-empty, trimmed string`); - } - - const unsupportedTarget = `not(any(${cfgs.join(", ")}))`; - const condition = feature === null - ? unsupportedTarget - : `all(feature = ${JSON.stringify(feature)}, ${unsupportedTarget})`; - const subject = feature === null - ? product - : `${product}'s ${featureLabel ?? `${feature} feature`}`; - const message = `${subject} supports only ${targets.join(", ")}; ${guidance}`; - return `#[cfg(${condition})]\ncompile_error!(${JSON.stringify(message)});`; -} diff --git a/tools/release/sdk-artifacts/js.mjs b/tools/release/sdk-artifacts/js.mjs deleted file mode 100644 index 1f2189e3c..000000000 --- a/tools/release/sdk-artifacts/js.mjs +++ /dev/null @@ -1,20 +0,0 @@ -import { cpSync } from "node:fs"; -import path from "node:path"; - -import { - assertSourceOnlyNpmArchive, - prepareSourceOnlyNpmPackage, - SOURCE_ONLY_NPM_PROFILES, -} from "../source-only-sdk-package.mjs"; -import { packageNpmWorkspace } from "./npm.mjs"; -import { ROOT, requireDir } from "./shared.mjs"; - -export function stageArtifacts(artifactRoot, workRoot) { - const packageShapeDir = path.join(ROOT, "target/liboliphaunt-sdk-check/oliphaunt-js/package-shape/src/sdks/js"); - requireDir(packageShapeDir); - const releasePackageDir = path.join(workRoot, "package"); - cpSync(packageShapeDir, releasePackageDir, { recursive: true }); - prepareSourceOnlyNpmPackage(releasePackageDir, SOURCE_ONLY_NPM_PROFILES.js); - const archive = packageNpmWorkspace(releasePackageDir, artifactRoot); - assertSourceOnlyNpmArchive(archive, SOURCE_ONLY_NPM_PROFILES.js); -} diff --git a/tools/release/sdk-artifacts/kotlin.mjs b/tools/release/sdk-artifacts/kotlin.mjs deleted file mode 100644 index 2c0186853..000000000 --- a/tools/release/sdk-artifacts/kotlin.mjs +++ /dev/null @@ -1,42 +0,0 @@ -import path from "node:path"; -import { readFileSync } from "node:fs"; - -import { assertReleaseNoticesInArchive } from "../release-notices.mjs"; -import { - ROOT, - copyDirContents, - fail, - filesUnder, - rel, - requireFile, -} from "./shared.mjs"; - -function kotlinVersion() { - const gradleProperties = readFileSync(path.join(ROOT, "src/sdks/kotlin/gradle.properties"), "utf8"); - const versions = gradleProperties - .split(/\r?\n/u) - .map((line) => line.match(/^VERSION_NAME=(.+)$/u)?.[1]?.trim()) - .filter(Boolean); - const version = versions.at(-1); - if (!version) { - fail("missing VERSION_NAME in src/sdks/kotlin/gradle.properties"); - } - return version; -} - -export function stageArtifacts(artifactRoot) { - const mavenRepo = path.join(ROOT, "target/moon/oliphaunt-kotlin/package/maven"); - const version = kotlinVersion(); - requireFile(path.join(mavenRepo, `dev/oliphaunt/oliphaunt-android/${version}/oliphaunt-android-${version}.aar`)); - requireFile(path.join(mavenRepo, `dev/oliphaunt/oliphaunt-android-gradle-plugin/${version}/oliphaunt-android-gradle-plugin-${version}.jar`)); - const publishedArchives = filesUnder(mavenRepo) - .filter((file) => file.endsWith(".aar") || file.endsWith(".jar")); - if (publishedArchives.length === 0) { - fail(`Kotlin SDK Maven repository contains no AAR or JAR artifacts: ${rel(mavenRepo)}`); - } - for (const archive of publishedArchives) { - assertReleaseNoticesInArchive(archive, { prefix: "META-INF" }); - } - const destination = path.join(artifactRoot, "maven"); - copyDirContents(mavenRepo, destination); -} diff --git a/tools/release/sdk-artifacts/npm.mjs b/tools/release/sdk-artifacts/npm.mjs deleted file mode 100644 index 3c01b76fc..000000000 --- a/tools/release/sdk-artifacts/npm.mjs +++ /dev/null @@ -1,132 +0,0 @@ -import { - mkdirSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { - fail, - isFile, - rel, - requireCommand, - run, -} from "./shared.mjs"; - -function pnpmPackManifest(envelope) { - const manifests = Array.isArray(envelope) ? envelope : [envelope]; - if (manifests.length !== 1) { - return null; - } - const [manifest] = manifests; - if ( - !manifest || - typeof manifest !== "object" || - typeof manifest.filename !== "string" || - !manifest.filename.endsWith(".tgz") - ) { - return null; - } - return manifest; -} - -function lineStartOffsets(text) { - const offsets = [0]; - for (let index = 0; index < text.length; index += 1) { - if (text[index] === "\n" && index + 1 < text.length) { - offsets.push(index + 1); - } - } - return offsets; -} - -function parsePackEnvelope(text) { - try { - const envelope = JSON.parse(text); - const manifest = pnpmPackManifest(envelope); - return manifest ? { envelope, manifest } : null; - } catch { - return null; - } -} - -function prefixContainsPackEnvelope(prefix) { - const starts = lineStartOffsets(prefix); - const ends = [...starts.slice(1).map((offset) => offset - 1), prefix.length]; - for (const start of starts) { - for (const end of ends) { - if (end <= start) { - continue; - } - const candidate = prefix.slice(start, end).trim(); - if ((candidate.startsWith("{") || candidate.startsWith("[")) && parsePackEnvelope(candidate)) { - return true; - } - } - } - return false; -} - -/** - * Parse the final machine-readable envelope from `pnpm pack --json` output. - * Lifecycle scripts are allowed to log before the envelope, but a second pack - * envelope is rejected so a stale or substituted filename cannot be selected. - */ -export function parsePnpmPackOutput(output) { - const text = String(output ?? "").trim(); - if (!text) { - throw new Error("pnpm pack produced no output"); - } - - const candidates = []; - for (const offset of lineStartOffsets(text)) { - const candidate = text.slice(offset).trimStart(); - if (!candidate.startsWith("{") && !candidate.startsWith("[")) { - continue; - } - const parsed = parsePackEnvelope(candidate); - if (parsed) { - candidates.push({ ...parsed, offset: text.length - candidate.length }); - } - } - const uniqueCandidates = [...new Map(candidates.map((candidate) => [candidate.offset, candidate])).values()]; - if (uniqueCandidates.length !== 1) { - throw new Error( - `pnpm pack output must end with exactly one JSON envelope containing one .tgz filename; found ${uniqueCandidates.length}`, - ); - } - - const [selected] = uniqueCandidates; - if (prefixContainsPackEnvelope(text.slice(0, selected.offset))) { - throw new Error("pnpm pack output contained more than one JSON package envelope"); - } - return { envelope: selected.envelope, manifest: selected.manifest }; -} - -export function packageNpmWorkspace(packageDir, destination) { - requireCommand("pnpm"); - mkdirSync(destination, { recursive: true }); - const packJson = run( - "pnpm", - ["--dir", packageDir, "pack", "--pack-destination", destination, "--json"], - { - capture: true, - env: { ...process.env, PNPM_CONFIG_NODE_LINKER: "hoisted" }, - label: "pnpm pack", - }, - ); - let parsed; - try { - parsed = parsePnpmPackOutput(packJson); - } catch (error) { - fail(`pnpm pack did not report an unambiguous JSON envelope: ${error.message}`); - } - const { envelope, manifest } = parsed; - writeFileSync(path.join(destination, "pnpm-pack.json"), `${JSON.stringify(envelope, null, 2)}\n`); - const packFile = path.isAbsolute(manifest.filename) - ? manifest.filename - : path.join(destination, manifest.filename); - if (!isFile(packFile)) { - fail(`pnpm pack did not create ${rel(packFile)}`); - } - return packFile; -} diff --git a/tools/release/sdk-artifacts/react-native.mjs b/tools/release/sdk-artifacts/react-native.mjs deleted file mode 100644 index ba6b60309..000000000 --- a/tools/release/sdk-artifacts/react-native.mjs +++ /dev/null @@ -1,78 +0,0 @@ -import { - cpSync, - mkdirSync, - readFileSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { - IOS_CARRIER_FILENAME, - buildIosCarrierManifest, -} from "../ios-carrier-manifest.mjs"; -import { - assertSourceOnlyNpmArchive, - prepareSourceOnlyNpmPackage, - SOURCE_ONLY_NPM_PROFILES, -} from "../source-only-sdk-package.mjs"; -import { packageNpmWorkspace } from "./npm.mjs"; -import { - ROOT, - fail, - requireCommand, - requireDir, - run, -} from "./shared.mjs"; - -export function stageArtifacts(artifactRoot, workRoot) { - const packageShapeDir = path.join(ROOT, "target/liboliphaunt-sdk-check/oliphaunt-react-native/package-shape/src/sdks/react-native"); - requireDir(packageShapeDir); - const releasePackageDir = path.join(workRoot, "package"); - cpSync(packageShapeDir, releasePackageDir, { recursive: true }); - const assetDir = process.env.OLIPHAUNT_REACT_NATIVE_IOS_RELEASE_ASSET_DIR; - if (!assetDir) { - fail("oliphaunt-react-native package artifacts require OLIPHAUNT_REACT_NATIVE_IOS_RELEASE_ASSET_DIR"); - } - const carrier = buildIosCarrierManifest({ - baseAssetDir: assetDir, - extensionManifests: [], - }); - writeFileSync( - path.join(releasePackageDir, IOS_CARRIER_FILENAME), - `${JSON.stringify(carrier, null, 2)}\n`, - "utf8", - ); - const packageJsonFile = path.join(releasePackageDir, "package.json"); - const packageJson = JSON.parse(readFileSync(packageJsonFile, "utf8")); - packageJson.oliphaunt = { - ...(packageJson.oliphaunt ?? {}), - iosCarrierManifest: `./${IOS_CARRIER_FILENAME}`, - }; - packageJson.files = [...new Set([...(packageJson.files ?? []), IOS_CARRIER_FILENAME])]; - packageJson.exports = { - ...(packageJson.exports ?? {}), - "./ios-carriers": `./${IOS_CARRIER_FILENAME}`, - }; - writeFileSync(packageJsonFile, `${JSON.stringify(packageJson, null, 2)}\n`, "utf8"); - requireCommand("node"); - run("node", [ - path.join(releasePackageDir, "tools/verify-ios-package.mjs"), - "--package-dir", - releasePackageDir, - ], { label: "React Native source-only package verification" }); - prepareSourceOnlyNpmPackage(releasePackageDir, SOURCE_ONLY_NPM_PROFILES["react-native"]); - const archive = packageNpmWorkspace(releasePackageDir, artifactRoot); - assertSourceOnlyNpmArchive(archive, SOURCE_ONLY_NPM_PROFILES["react-native"]); - run("node", [ - path.join(ROOT, "src/sdks/react-native/tools/ios-icu-autolinking.test.mjs"), - "--react-native-tarball", - archive, - "--icu-source", - path.join(ROOT, "src/runtimes/liboliphaunt/native/icu-npm"), - "--expo-project", - path.join(ROOT, "examples/react-native-expo"), - ], { label: "React Native and ICU autolinking contract" }); - const carrierEvidence = path.join(artifactRoot, "ios-carriers", IOS_CARRIER_FILENAME); - mkdirSync(path.dirname(carrierEvidence), { recursive: true }); - writeFileSync(carrierEvidence, `${JSON.stringify(carrier, null, 2)}\n`, "utf8"); -} diff --git a/tools/release/sdk-artifacts/rust.mjs b/tools/release/sdk-artifacts/rust.mjs deleted file mode 100644 index 9081b5f10..000000000 --- a/tools/release/sdk-artifacts/rust.mjs +++ /dev/null @@ -1,55 +0,0 @@ -import { copyFileSync } from "node:fs"; -import path from "node:path"; - -import { manualCargoPackageSource } from "../cargo-source-package.mjs"; -import { - prepareOliphauntBuildReleaseSource, - prepareRustReleaseSource, -} from "../prepare-rust-release-source.mjs"; -import { assertReleaseNoticesInArchive } from "../release-notices.mjs"; -import { - ROOT, - fail, - rel, - requireCommand, - requireFile, -} from "./shared.mjs"; - -export function stageArtifacts(artifactRoot, workRoot) { - requireCommand("cargo"); - const packageListing = path.join(ROOT, "target/liboliphaunt-sdk-check/rust-cargo-package-list.txt"); - requireFile(packageListing); - - const releaseManifest = prepareRustReleaseSource({ - stageDir: path.join(workRoot, "oliphaunt-release-source"), - log: false, - }); - const releaseCrate = manualCargoPackageSource( - releaseManifest, - path.join(workRoot, "oliphaunt-release-crate"), - { root: ROOT, fail, rel }, - ); - requireFile(releaseCrate); - assertReleaseNoticesInArchive(releaseCrate, { - profile: "source-sdk", - prefix: path.basename(releaseCrate, ".crate"), - }); - copyFileSync(releaseCrate, path.join(artifactRoot, path.basename(releaseCrate))); - - const buildManifest = prepareOliphauntBuildReleaseSource({ - stageDir: path.join(workRoot, "oliphaunt-build-release-source"), - log: false, - }); - const buildCrate = manualCargoPackageSource( - buildManifest, - path.join(workRoot, "oliphaunt-build-release-crate"), - { root: ROOT, fail, rel }, - ); - requireFile(buildCrate); - assertReleaseNoticesInArchive(buildCrate, { - profile: "source-sdk", - prefix: path.basename(buildCrate, ".crate"), - }); - copyFileSync(buildCrate, path.join(artifactRoot, path.basename(buildCrate))); - copyFileSync(packageListing, path.join(artifactRoot, "cargo-package-files.txt")); -} diff --git a/tools/release/sdk-artifacts/shared.mjs b/tools/release/sdk-artifacts/shared.mjs deleted file mode 100644 index 8de572f35..000000000 --- a/tools/release/sdk-artifacts/shared.mjs +++ /dev/null @@ -1,135 +0,0 @@ -import { spawnSync } from "node:child_process"; -import { - accessSync, - constants as fsConstants, - cpSync, - mkdirSync, - readdirSync, - statSync, -} from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../../dev/capture-command-output.mjs"; - -export const ROOT = path.resolve(import.meta.dir, "../../.."); -export const BUN = process.execPath; - -const PREFIX = "build-sdk-ci-artifacts.mjs"; - -export function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(1); -} - -export function rel(file) { - const relative = path.relative(ROOT, String(file)); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - return String(file).split(path.sep).join("/"); - } - return relative.split(path.sep).join("/"); -} - -export function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -export function isFile(file) { - try { - return statSync(file).isFile(); - } catch { - return false; - } -} - -export function isDirectory(file) { - try { - return statSync(file).isDirectory(); - } catch { - return false; - } -} - -export function requireFile(file) { - if (!isFile(file)) { - fail(`missing package-shape output: ${rel(file)}`); - } -} - -export function requireDir(file) { - if (!isDirectory(file)) { - fail(`missing package-shape output directory: ${rel(file)}`); - } -} - -function commandCandidates(command) { - if (command.includes("/") || command.includes("\\")) { - return [path.resolve(ROOT, command)]; - } - const pathEntries = (process.env.PATH ?? "").split(path.delimiter).filter(Boolean); - const extensions = process.platform === "win32" - ? ["", ...(process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";")] - : [""]; - return pathEntries.flatMap((entry) => extensions.map((extension) => path.join(entry, `${command}${extension}`))); -} - -export function requireCommand(command) { - for (const candidate of commandCandidates(command)) { - try { - if (!statSync(candidate).isFile()) { - continue; - } - accessSync(candidate, process.platform === "win32" ? fsConstants.F_OK : fsConstants.X_OK); - return; - } catch { - // Keep scanning PATH. - } - } - fail(`missing required command: ${command}`); -} - -export function copyDirContents(source, destination, { filter = () => true } = {}) { - mkdirSync(destination, { recursive: true }); - for (const entry of readdirSync(source, { withFileTypes: true }).sort((left, right) => compareText(left.name, right.name))) { - const sourcePath = path.join(source, entry.name); - const destinationPath = path.join(destination, entry.name); - cpSync(sourcePath, destinationPath, { - recursive: true, - filter, - }); - } -} - -export function filesUnder(root) { - const files = []; - const visit = (directory) => { - for (const entry of readdirSync(directory, { withFileTypes: true }).sort((left, right) => compareText(left.name, right.name))) { - const file = path.join(directory, entry.name); - if (entry.isDirectory()) { - visit(file); - } else if (entry.isFile()) { - files.push(file); - } - } - }; - visit(root); - return files; -} - -export function run(command, args, { cwd = ROOT, env = process.env, capture = false, label = command } = {}) { - const result = capture - ? captureCommandOutput(command, args, { - cwd, - env, - label, - maxOutputBytes: 100 * 1024 * 1024, - }) - : spawnSync(command, args, { cwd, env, stdio: "inherit" }); - if (result.error) { - fail(`${label} failed: ${result.error.message}`); - } - if (result.status !== 0) { - const stderr = capture && result.stderr ? result.stderr.trim() : ""; - fail(`${label} failed${stderr ? `: ${stderr}` : ""}`); - } - return capture ? result.stdout : ""; -} diff --git a/tools/release/sdk-artifacts/swift.mjs b/tools/release/sdk-artifacts/swift.mjs deleted file mode 100644 index 172057b20..000000000 --- a/tools/release/sdk-artifacts/swift.mjs +++ /dev/null @@ -1,117 +0,0 @@ -import { - copyFileSync, - mkdirSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { - IOS_CARRIER_FILENAME, - buildIosCarrierManifest, -} from "../ios-carrier-manifest.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - stageReleaseNotices, -} from "../release-notices.mjs"; -import { productCompatibilityVersion } from "../release-graph.mjs"; -import { validateSwiftSourceReleaseContract } from "../swift-source-carrier-contract.mjs"; -import { - BUN, - ROOT, - copyDirContents, - fail, - rel, - requireCommand, - requireFile, - run, -} from "./shared.mjs"; - -const PREFIX = "build-sdk-ci-artifacts.mjs"; - -export function stageArtifacts(artifactRoot, workRoot) { - requireCommand("swift"); - const swiftSourceArchive = path.join( - ROOT, - "target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/Oliphaunt-source.zip", - ); - requireFile(swiftSourceArchive); - const stagedSourceArchive = path.join(artifactRoot, "Oliphaunt-source.zip"); - copyFileSync(swiftSourceArchive, stagedSourceArchive); - assertReleaseNoticesInArchive(stagedSourceArchive, { prefix: "package" }); - const assetDir = process.env.OLIPHAUNT_SWIFT_RELEASE_ASSET_DIR; - if (!assetDir) { - fail("oliphaunt-swift package artifacts require OLIPHAUNT_SWIFT_RELEASE_ASSET_DIR"); - } - run(BUN, [ - "tools/release/render_swiftpm_release_package.mjs", - "--asset-dir", - assetDir, - "--output", - path.join(artifactRoot, "Package.swift.release"), - "--generated-tree", - path.join(workRoot, "swiftpm-release-tree"), - ], { label: "render SwiftPM release package" }); - const releaseTree = path.join(artifactRoot, "release-tree"); - rmSync(releaseTree, { recursive: true, force: true }); - copyDirContents(path.join(workRoot, "swiftpm-release-tree"), releaseTree); - stageReleaseNotices(releaseTree); - assertReleaseNoticesInDirectory(releaseTree); - const carrier = buildIosCarrierManifest({ - baseAssetDir: assetDir, - extensionManifests: [], - }); - const carrierFile = path.join( - releaseTree, - "src/sdks/swift/Carriers", - IOS_CARRIER_FILENAME, - ); - mkdirSync(path.dirname(carrierFile), { recursive: true }); - writeFileSync(carrierFile, `${JSON.stringify(carrier, null, 2)}\n`, "utf8"); - const manifest = readFileSync(path.join(artifactRoot, "Package.swift.release"), "utf8"); - try { - validateSwiftSourceReleaseContract({ - carrier, - expectedNativeVersion: productCompatibilityVersion( - "oliphaunt-swift", - "liboliphaunt-native", - PREFIX, - ), - label: `${rel(artifactRoot)} source release`, - manifestText: manifest, - }); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - for (const fragment of [ - "liboliphaunt-native-v", - '.library(name: "COliphaunt"', - '.library(name: "OliphauntExtensionSupport"', - 'path: "src/sdks/swift/Sources/OliphauntExtensionSupport"', - ]) { - if (!manifest.includes(fragment)) { - fail(`staged SwiftPM release manifest is missing ${JSON.stringify(fragment)}`); - } - } - if (manifest.includes("file://")) { - fail("staged SwiftPM release manifest must not contain local file URLs"); - } - const generatorRoot = path.join(artifactRoot, "extension-generator"); - mkdirSync(generatorRoot, { recursive: true }); - for (const name of [ - "extension-resource-inventory.mjs", - "render-extension-products.mjs", - "swift-carrier-resolver.mjs", - ]) { - copyFileSync( - path.join(ROOT, "src/sdks/swift/tools", name), - path.join(generatorRoot, name), - ); - } - copyFileSync( - path.join(ROOT, "src/extensions/generated/sdk/extensions.json"), - path.join(generatorRoot, "extension-owner-catalog.json"), - ); -} diff --git a/tools/release/sdk-artifacts/wasix-rust.mjs b/tools/release/sdk-artifacts/wasix-rust.mjs deleted file mode 100644 index e01ebdf2e..000000000 --- a/tools/release/sdk-artifacts/wasix-rust.mjs +++ /dev/null @@ -1,20 +0,0 @@ -import { copyFileSync } from "node:fs"; -import path from "node:path"; - -import { - BUN, - ROOT, - requireCommand, - requireFile, - run, -} from "./shared.mjs"; - -export function stageArtifacts(artifactRoot) { - requireCommand("cargo"); - const packageListing = path.join(ROOT, "target/oliphaunt-wasix-rust/package/oliphaunt-wasix.package-files.txt"); - requireFile(packageListing); - run(BUN, ["tools/release/package_oliphaunt_wasix_sdk_crate.mjs", "--output-dir", artifactRoot], { - label: "package oliphaunt-wasix SDK crate", - }); - copyFileSync(packageListing, path.join(artifactRoot, "cargo-package-files.txt")); -} diff --git a/tools/release/sdk-artifacts/wasix-tools-ts.mjs b/tools/release/sdk-artifacts/wasix-tools-ts.mjs deleted file mode 100644 index b29764213..000000000 --- a/tools/release/sdk-artifacts/wasix-tools-ts.mjs +++ /dev/null @@ -1,14 +0,0 @@ -import { copyFileSync } from 'node:fs'; -import path from 'node:path'; - -import { assertWasixToolsTypescriptNpmArchive } from '../wasix-tools-typescript-package.mjs'; -import { ROOT, fail, filesUnder } from './shared.mjs'; - -export function stageWasixToolsArtifact(artifactRoot) { - const archives = filesUnder(path.join(ROOT, 'target/oliphaunt-wasix-tools-ts/package/packages')) - .filter((file) => file.endsWith('.tgz')); - if (archives.length !== 1) fail(`expected one WASIX TypeScript tools package, found ${archives.length}`); - const archive = archives[0]; - assertWasixToolsTypescriptNpmArchive(archive); - copyFileSync(archive, path.join(artifactRoot, path.basename(archive))); -} diff --git a/tools/release/sdk-artifacts/wasix-ts.mjs b/tools/release/sdk-artifacts/wasix-ts.mjs deleted file mode 100644 index c16304823..000000000 --- a/tools/release/sdk-artifacts/wasix-ts.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import { copyFileSync } from 'node:fs'; -import path from 'node:path'; - -import { assertWasixTypescriptNpmArchive } from '../wasix-typescript-package.mjs'; -import { ROOT, fail, filesUnder } from './shared.mjs'; -import { stageWasixToolsArtifact } from './wasix-tools-ts.mjs'; - -export function stageArtifacts(artifactRoot) { - const archives = filesUnder(path.join(ROOT, 'target/oliphaunt-wasix-ts/package/packages')) - .filter((file) => file.endsWith('.tgz')); - if (archives.length !== 1) fail(`expected one WASIX TypeScript package, found ${archives.length}`); - const archive = archives[0]; - assertWasixTypescriptNpmArchive(archive); - copyFileSync(archive, path.join(artifactRoot, path.basename(archive))); - stageWasixToolsArtifact(artifactRoot); -} diff --git a/tools/policy/sdk-manifest.toml b/tools/release/sdk-manifest.toml similarity index 94% rename from tools/policy/sdk-manifest.toml rename to tools/release/sdk-manifest.toml index 2548d5671..52413badc 100644 --- a/tools/policy/sdk-manifest.toml +++ b/tools/release/sdk-manifest.toml @@ -2,7 +2,6 @@ # # This file is intentionally small and reviewed with SDK changes. It is the # repo-level registry for SDK ownership, target platforms, and delegation rules. -# `sdk-contracts:manifest` parses this schema and cross-checks release identities; # product tasks own behavior and package proof. # `calling_contract` records synchronous versus language-level asynchronous # completion. `execution_owner` independently records where an admitted public @@ -15,7 +14,7 @@ schema_version = 6 [sdks.rust] package_identity = "cargo:oliphaunt" -implementation_path = "src/sdks/rust" +implementation_path = "src/sdks/rust/sdk" documentation_path = "src/docs/content/sdk/rust" consumer_targets = ["tauri", "rust-desktop"] runtime_owner = true @@ -39,7 +38,7 @@ topologies = ["native-direct", "native-broker", "native-server"] [sdks.wasix-rust] package_identity = "cargo:oliphaunt-wasix" -implementation_path = "src/bindings/wasix-rust/crates/oliphaunt-wasix" +implementation_path = "src/sdks/rust-wasix" documentation_path = "src/docs/content/sdk/wasix-rust" consumer_targets = ["tauri", "rust-desktop"] runtime_owner = true @@ -63,7 +62,7 @@ topologies = ["wasix-direct", "wasix-server"] [sdks.wasix-typescript] package_identity = "npm:@oliphaunt/wasix-ts" -implementation_path = "src/bindings/wasix-ts" +implementation_path = "src/sdks/ts-wasix/sdk" documentation_path = "src/docs/content/sdk/wasix-typescript" consumer_targets = ["browser", "node", "bun", "deno", "electron"] runtime_owner = true @@ -169,7 +168,7 @@ topologies = ["native-direct"] [sdks.typescript] package_identity = "npm:@oliphaunt/ts" -implementation_path = "src/sdks/js" +implementation_path = "src/sdks/ts/sdk" documentation_path = "src/docs/content/sdk/typescript" consumer_targets = ["node", "bun", "deno"] runtime_owner = true diff --git a/tools/release/source-only-sdk-package.mjs b/tools/release/source-only-sdk-package.mjs deleted file mode 100644 index 9f87081ac..000000000 --- a/tools/release/source-only-sdk-package.mjs +++ /dev/null @@ -1,309 +0,0 @@ -#!/usr/bin/env node - -import { - chmodSync, - lstatSync, - readFileSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releasePackageLicense, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { requireSafeDirectoryChain } from "./release-directory-safety.mjs"; -import { - assertJsCoreBundleInventory, - JS_CORE_PACKAGE, -} from "../../src/shared/js-core/tools/stage-package.mjs"; - -const TOOL = "source-only-sdk-package.mjs"; -const SOURCE_NOTICE_OPTIONS = Object.freeze({ profile: "source-sdk" }); -const SOURCE_LICENSE = releasePackageLicense().spdx; -const NOTICE_FILES = Object.freeze(["LICENSE", "THIRD_PARTY_NOTICES.md"]); - -export const SOURCE_ONLY_NPM_PROFILES = Object.freeze({ - js: Object.freeze({ - name: "@oliphaunt/ts", - scripts: Object.freeze({}), - optionalDependencyVersions: Object.freeze({ - "@oliphaunt/broker-darwin-arm64": "brokerVersion", - "@oliphaunt/broker-linux-arm64-gnu": "brokerVersion", - "@oliphaunt/broker-linux-x64-gnu": "brokerVersion", - "@oliphaunt/broker-win32-x64-msvc": "brokerVersion", - "@oliphaunt/liboliphaunt-darwin-arm64": "liboliphauntVersion", - "@oliphaunt/liboliphaunt-linux-arm64-gnu": "liboliphauntVersion", - "@oliphaunt/liboliphaunt-linux-x64-gnu": "liboliphauntVersion", - "@oliphaunt/liboliphaunt-win32-x64-msvc": "liboliphauntVersion", - "@oliphaunt/node-direct-darwin-arm64": "nodeDirectAddonVersion", - "@oliphaunt/node-direct-linux-arm64-gnu": "nodeDirectAddonVersion", - "@oliphaunt/node-direct-linux-x64-gnu": "nodeDirectAddonVersion", - "@oliphaunt/node-direct-win32-x64-msvc": "nodeDirectAddonVersion", - }), - }), - "react-native": Object.freeze({ - name: "@oliphaunt/react-native", - scripts: Object.freeze({ - "package:verify-ios": "node ./tools/verify-ios-package.mjs --package-dir .", - }), - }), -}); - -function requireRegularFile(file, label) { - let stat; - try { - stat = lstatSync(file); - } catch (cause) { - throw new Error(`${label} cannot be inspected: ${cause.message}`); - } - if (!stat.isFile() || stat.isSymbolicLink()) { - throw new Error(`${label} must be a regular non-symlink file: ${file}`); - } - return stat; -} - -function readJson(file, label) { - requireRegularFile(file, label); - let parsed; - try { - parsed = JSON.parse(readFileSync(file, "utf8")); - } catch (cause) { - throw new Error(`${label} must contain valid JSON: ${cause.message}`); - } - if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) { - throw new Error(`${label} must contain a JSON object`); - } - return parsed; -} - -function checkedScripts(value, label) { - if (!value || typeof value !== "object" || Array.isArray(value)) { - throw new Error(`${label} scripts contract must be an object`); - } - const scripts = {}; - for (const name of Object.keys(value).sort()) { - const command = value[name]; - if (typeof command !== "string" || command.length === 0) { - throw new Error(`${label} script ${JSON.stringify(name)} must be a non-empty string`); - } - scripts[name] = command; - } - return scripts; -} - -function exactOptionalDependencies(manifest, fields, label) { - if (fields === undefined) return undefined; - const metadata = manifest.oliphaunt; - if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) { - throw new Error(`${label} must declare oliphaunt compatibility metadata`); - } - const dependencies = {}; - for (const [name, field] of Object.entries(fields)) { - const version = metadata[field]; - if (typeof version !== "string" || !/^\d+[.]\d+[.]\d+$/u.test(version)) { - throw new Error(`${label} oliphaunt.${field} must be an exact stable version`); - } - dependencies[name] = version; - } - return dependencies; -} - -function sameStringMap(left, right) { - const entries = Object.entries(left ?? {}); - return entries.length === Object.keys(right).length - && entries.every(([name, version]) => right[name] === version); -} - -function assertManifestContract(manifest, { name, scripts, optionalDependencyVersions }, label) { - if (manifest.name !== name) { - throw new Error(`${label} must identify ${name}, got ${JSON.stringify(manifest.name)}`); - } - if (manifest.license !== SOURCE_LICENSE) { - throw new Error(`${label} must declare the source-only license ${SOURCE_LICENSE}, got ${JSON.stringify(manifest.license)}`); - } - const expectedScripts = checkedScripts(scripts, label); - const actualScripts = manifest.scripts ?? {}; - if ( - !actualScripts - || typeof actualScripts !== "object" - || Array.isArray(actualScripts) - || JSON.stringify(actualScripts) !== JSON.stringify(expectedScripts) - ) { - throw new Error( - `${label} must contain only the publish-safe scripts ${JSON.stringify(expectedScripts)}, got ${JSON.stringify(actualScripts)}`, - ); - } - if (Object.hasOwn(manifest, "devDependencies")) { - throw new Error(`${label} must not publish development-only dependencies`); - } - const expectedOptional = exactOptionalDependencies(manifest, optionalDependencyVersions, label); - if ( - expectedOptional !== undefined - && !sameStringMap(manifest.optionalDependencies, expectedOptional) - ) { - throw new Error(`${label} must pin its optional runtime packages to its compatibility versions`); - } -} - -function requireNoticeAllowlist(manifest, label) { - if (!Array.isArray(manifest.files)) { - throw new Error(`${label} must declare an npm files allowlist`); - } - for (const member of NOTICE_FILES) { - if (!manifest.files.includes(member)) { - throw new Error(`${label} npm files allowlist must include ${member}`); - } - } -} - -function writeManifest(file, manifest) { - writeFileSync(file, `${JSON.stringify(manifest, null, 2)}\n`, "utf8"); - chmodSync(file, 0o644); -} - -export function prepareSourceOnlyNpmPackage(packageDir, contract) { - // Validate the complete lexical path before reading or rewriting package.json. - // Notice staging enforces the same boundary, but it runs after sanitation. - const directory = requireSafeDirectoryChain(packageDir, { - label: "source-only npm package directory", - }); - const packageJsonFile = path.join(directory, "package.json"); - const manifest = readJson(packageJsonFile, "source-only npm package manifest"); - const expectedScripts = checkedScripts(contract.scripts, contract.name); - if (manifest.name !== contract.name) { - throw new Error( - `source-only npm package manifest must identify ${contract.name}, got ${JSON.stringify(manifest.name)}`, - ); - } - if (manifest.license !== SOURCE_LICENSE) { - throw new Error( - `source-only npm package manifest must declare ${SOURCE_LICENSE}, got ${JSON.stringify(manifest.license)}`, - ); - } - requireNoticeAllowlist(manifest, "source-only npm package manifest"); - for (const [name, command] of Object.entries(expectedScripts)) { - if (manifest.scripts?.[name] !== command) { - throw new Error( - `source-only npm package manifest is missing publish-safe script ${name}=${JSON.stringify(command)}`, - ); - } - } - if (Object.keys(expectedScripts).length === 0) { - delete manifest.scripts; - } else { - manifest.scripts = expectedScripts; - } - const exactOptional = exactOptionalDependencies( - manifest, - contract.optionalDependencyVersions, - "source-only npm package manifest", - ); - if (exactOptional !== undefined) { - const sourceOptional = manifest.optionalDependencies ?? {}; - const sameNames = Object.keys(sourceOptional).length === Object.keys(exactOptional).length - && Object.keys(sourceOptional).every((name) => Object.hasOwn(exactOptional, name)); - const local = Object.values(sourceOptional).every((version) => version === "workspace:*"); - const staged = Object.entries(exactOptional).every(([name, version]) => sourceOptional[name] === version); - if (!sameNames || (!local && !staged)) { - throw new Error( - "source-only npm package manifest optional runtime packages must use workspace:* locally or exact compatibility versions when staged", - ); - } - manifest.optionalDependencies = exactOptional; - } - delete manifest.devDependencies; - writeManifest(packageJsonFile, manifest); - stageReleaseNotices(directory, SOURCE_NOTICE_OPTIONS); - assertReleaseNoticesInDirectory(directory, SOURCE_NOTICE_OPTIONS); - assertManifestContract(manifest, contract, "staged source-only npm package manifest"); - return packageJsonFile; -} - -function archiveJson(entries, member, label) { - const entry = entries.get(member); - if (!entry?.isFile || entry.isSymbolicLink) { - throw new Error(`${label} is missing regular member ${member}`); - } - if ((entry.mode & 0o777) !== 0o644) { - throw new Error(`${label} member ${member} must have mode 0644`); - } - let parsed; - try { - parsed = JSON.parse(Buffer.from(entry.data()).toString("utf8")); - } catch (cause) { - throw new Error(`${label} member ${member} must contain valid JSON: ${cause.message}`); - } - return parsed; -} - -export function assertSourceOnlyNpmArchive(archive, contract) { - const file = path.resolve(archive); - const label = path.basename(file); - assertReleaseNoticesInArchive(file, { - ...SOURCE_NOTICE_OPTIONS, - prefix: "package", - label, - }); - const entries = readPortableArchiveEntries(file); - const manifest = archiveJson(entries, "package/package.json", label); - assertManifestContract(manifest, contract, `${label} package.json`); - requireNoticeAllowlist(manifest, `${label} package.json`); - assertJsCoreBundleInventory(entries.keys(), "package/node_modules/@oliphaunt/js-core/"); - const coreManifest = archiveJson( - entries, - "package/node_modules/@oliphaunt/js-core/package.json", - label, - ); - if ( - coreManifest.name !== JS_CORE_PACKAGE - || coreManifest.private !== true - || manifest.dependencies?.[JS_CORE_PACKAGE] !== coreManifest.version - || JSON.stringify(manifest.bundledDependencies) !== JSON.stringify([JS_CORE_PACKAGE]) - ) { - throw new Error(`${label} must bundle the exact minimal ${JS_CORE_PACKAGE} workspace payload`); - } - return manifest; -} - -function usage() { - return [ - "usage:", - ` ${TOOL} prepare-npm `, - ` ${TOOL} check-npm-archive `, - ].join("\n"); -} - -function profile(name) { - const selected = SOURCE_ONLY_NPM_PROFILES[name]; - if (!selected) { - throw new Error(`unsupported source-only npm package profile ${JSON.stringify(name)}`); - } - return selected; -} - -function main(argv) { - const [command, first, second, ...extra] = argv; - if (command === "prepare-npm" && first && second && extra.length === 0) { - prepareSourceOnlyNpmPackage(second, profile(first)); - } else if (command === "check-npm-archive" && first && second && extra.length === 0) { - assertSourceOnlyNpmArchive(second, profile(first)); - } else { - throw new Error(usage()); - } - console.log(`${TOOL}: ${command} passed`); -} - -const invoked = process.argv[1] ? path.resolve(process.argv[1]) : ""; -if (invoked === fileURLToPath(import.meta.url)) { - try { - main(process.argv.slice(2)); - } catch (error) { - console.error(`${TOOL}: ${error instanceof Error ? error.message : String(error)}`); - process.exitCode = 1; - } -} diff --git a/tools/release/source-only-sdk-package.test.mjs b/tools/release/source-only-sdk-package.test.mjs deleted file mode 100644 index 114d079c4..000000000 --- a/tools/release/source-only-sdk-package.test.mjs +++ /dev/null @@ -1,167 +0,0 @@ -import assert from "node:assert/strict"; -import { - chmodSync, - existsSync, - mkdirSync, - mkdtempSync, - readFileSync, - readdirSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { - assertSourceOnlyNpmArchive, - prepareSourceOnlyNpmPackage, - SOURCE_ONLY_NPM_PROFILES, -} from "./source-only-sdk-package.mjs"; -import { - JS_CORE_BUNDLE_FILES, - JS_CORE_PACKAGE, -} from "../../src/shared/js-core/tools/stage-package.mjs"; -import { assertReleaseNoticesInDirectory } from "./release-notices.mjs"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); - -function writeJson(file, value) { - writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, "utf8"); -} - -function packageManifest(profile) { - const manifest = { - name: profile.name, - version: "1.2.3", - license: "MIT", - files: ["index.js", "LICENSE", "THIRD_PARTY_NOTICES.md"], - scripts: { - build: "false", - prepack: "false", - test: "false", - ...profile.scripts, - }, - dependencies: { [JS_CORE_PACKAGE]: "0.0.0" }, - bundledDependencies: [JS_CORE_PACKAGE], - devDependencies: { imaginary: "1.0.0" }, - }; - if (profile.optionalDependencyVersions !== undefined) { - manifest.oliphaunt = Object.fromEntries( - [...new Set(Object.values(profile.optionalDependencyVersions))].map((field) => [field, "1.2.0"]), - ); - manifest.optionalDependencies = Object.fromEntries( - Object.keys(profile.optionalDependencyVersions).map((name) => [name, "workspace:*"]), - ); - } - return manifest; -} - -function stageCoreFixture(packageDir) { - const coreDir = path.join(packageDir, "node_modules", "@oliphaunt", "js-core"); - for (const relative of JS_CORE_BUNDLE_FILES) { - const file = path.join(coreDir, relative); - mkdirSync(path.dirname(file), { recursive: true }); - if (relative === "package.json") { - writeJson(file, { - name: JS_CORE_PACKAGE, - version: "0.0.0", - private: true, - files: ["dist/module", "dist/commonjs"], - }); - } else if (relative.endsWith("/package.json")) { - writeJson(file, { type: relative.includes("/module/") ? "module" : "commonjs" }); - } else { - writeFileSync(file, relative === "README.md" ? "# Fixture\n" : "export {};\n", "utf8"); - } - } -} - -function pack(directory, destination) { - mkdirSync(destination, { recursive: true }); - const result = spawnSync( - "pnpm", - ["--dir", directory, "pack", "--pack-destination", destination], - { - cwd: ROOT, - encoding: "utf8", - env: { - ...process.env, - PNPM_CONFIG_IGNORE_SCRIPTS: "true", - PNPM_CONFIG_NODE_LINKER: "hoisted", - }, - }, - ); - assert.equal(result.status, 0, `pnpm pack failed:\n${result.stdout}\n${result.stderr}`); - const archives = readdirSync(destination).filter((entry) => entry.endsWith(".tgz")); - assert.equal(archives.length, 1); - return path.join(destination, archives[0]); -} - -for (const [profileName, profile] of Object.entries(SOURCE_ONLY_NPM_PROFILES)) { - test(`${profileName} final npm tarball has exact notices and publish-safe metadata`, () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const scratch = mkdtempSync(path.join(ROOT, "target", `source-only-${profileName}-`)); - const packageDir = path.join(scratch, "package"); - try { - mkdirSync(packageDir, { recursive: true }); - writeJson(path.join(packageDir, "package.json"), packageManifest(profile)); - writeFileSync(path.join(packageDir, "index.js"), "export {};\n", "utf8"); - stageCoreFixture(packageDir); - prepareSourceOnlyNpmPackage(packageDir, profile); - prepareSourceOnlyNpmPackage(packageDir, profile); - - const staged = JSON.parse(readFileSync(path.join(packageDir, "package.json"), "utf8")); - assert.equal(staged.license, "MIT"); - assert.deepEqual(staged.scripts ?? {}, profile.scripts); - assert.equal(staged.devDependencies, undefined); - if (profile.optionalDependencyVersions !== undefined) { - assert.deepEqual( - staged.optionalDependencies, - Object.fromEntries(Object.keys(profile.optionalDependencyVersions).map((name) => [name, "1.2.0"])), - ); - } - const archive = pack(packageDir, path.join(scratch, "packed")); - const packed = assertSourceOnlyNpmArchive(archive, profile); - assert.deepEqual(packed.scripts ?? {}, profile.scripts); - assert.equal(packed.devDependencies, undefined); - - writeFileSync(path.join(packageDir, "LICENSE"), "not canonical\n", "utf8"); - chmodSync(path.join(packageDir, "LICENSE"), 0o644); - assert.throws( - () => assertReleaseNoticesInDirectory(packageDir, { profile: "source-sdk" }), - /differs byte-for-byte/u, - ); - } finally { - rmSync(scratch, { recursive: true, force: true }); - } - }); -} - -test("rejects a symlinked package directory before rewriting its manifest", { - skip: process.platform === "win32", -}, () => { - mkdirSync(path.join(ROOT, "target"), { recursive: true }); - const scratch = mkdtempSync(path.join(ROOT, "target", "source-only-symlink-")); - try { - const packageDir = path.join(scratch, "real-package"); - const alias = path.join(scratch, "package-alias"); - mkdirSync(packageDir); - const manifestFile = path.join(packageDir, "package.json"); - writeJson(manifestFile, packageManifest(SOURCE_ONLY_NPM_PROFILES.js)); - writeFileSync(path.join(packageDir, "index.js"), "export {};\n", "utf8"); - const before = readFileSync(manifestFile); - symlinkSync(packageDir, alias, "dir"); - - assert.throws( - () => prepareSourceOnlyNpmPackage(alias, SOURCE_ONLY_NPM_PROFILES.js), - /symlink or non-directory ancestor/u, - ); - assert.deepEqual(readFileSync(manifestFile), before); - assert.equal(existsSync(path.join(packageDir, "LICENSE")), false); - assert.equal(existsSync(path.join(packageDir, "THIRD_PARTY_NOTICES.md")), false); - } finally { - rmSync(scratch, { recursive: true, force: true }); - } -}); diff --git a/tools/release/stage-native-cluster-seed.mjs b/tools/release/stage-native-cluster-seed.mjs deleted file mode 100644 index 7808f5efd..000000000 --- a/tools/release/stage-native-cluster-seed.mjs +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env node - -import { spawnSync } from "node:child_process"; -import { - cpSync, - existsSync, - mkdtempSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { - NATIVE_CLUSTER_SEED_TARGETS, - bindNativeClusterSeedManifest, - validateNativeClusterSeedDirectory, -} from "./native-cluster-seed-contract.mjs"; - -const TOOL = "stage-native-cluster-seed.mjs"; -const ROOT = path.resolve(import.meta.dirname, "../.."); -const SKIP_SYSTEM_COLLATION_DISCOVERY_ENV = - "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY"; -const SKIP_ICU_COLLATION_DISCOVERY_ENV = - "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY"; - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function parseArgs(argv) { - const values = new Map(); - for (let index = 0; index < argv.length; index += 2) { - const key = argv[index]; - const value = argv[index + 1]; - if (!key?.startsWith("--") || value === undefined || value.startsWith("--")) { - fail("usage: stage-native-cluster-seed.mjs --runtime DIR --destination DIR --target TARGET --profile standard|icu [--icu-data DIR]"); - } - if (values.has(key)) fail(`repeated argument ${key}`); - values.set(key, value); - } - const allowed = new Set(["--runtime", "--destination", "--target", "--profile", "--icu-data"]); - for (const key of values.keys()) if (!allowed.has(key)) fail(`unknown argument ${key}`); - const runtime = values.get("--runtime"); - const destination = values.get("--destination"); - const target = values.get("--target"); - const profile = values.get("--profile"); - const icuData = values.get("--icu-data"); - if (!runtime || !destination || !target || !["standard", "icu"].includes(profile)) { - fail("runtime, destination, target, and profile=standard|icu are required"); - } - if (profile === "icu" && !icuData) fail("profile=icu requires --icu-data DIR"); - if (profile === "standard" && icuData) fail("profile=standard must not receive --icu-data"); - return Object.freeze({ - runtime: path.resolve(runtime), - destination: path.resolve(destination), - target, - profile, - icuData: icuData === undefined ? undefined : path.resolve(icuData), - }); -} - -function requireDirectory(directory, label) { - if (!existsSync(directory)) fail(`${label} does not exist: ${directory}`); -} - -export function nativeClusterSeedProducerArgs(output, profile) { - const args = [ - "run", "-p", "oliphaunt-native-packaging", "--bin", "oliphaunt-resources", "--locked", "--", - "--output", output, - "--force", - "--mode", "native-server", - ]; - if (profile === "icu") args.push("--runtime-feature", "icu"); - return args; -} - -export function nativeClusterSeedProducerEnvironment(target, profile) { - if (!NATIVE_CLUSTER_SEED_TARGETS.includes(target)) { - fail(`unsupported native cluster-seed target ${JSON.stringify(target)}`); - } - if (!["standard", "icu"].includes(profile)) { - fail(`unsupported native cluster-seed profile ${JSON.stringify(profile)}`); - } - return Object.freeze({ - // Distributed seeds must not depend on the release runner's locale list. - skipSystemCollationDiscovery: true, - // The standard profile also omits optional ICU catalog rows. - skipIcuCollationDiscovery: profile === "standard", - }); -} - -export function stageNativeClusterSeed(argv) { - const args = parseArgs(argv); - requireDirectory(args.runtime, "native runtime"); - if (args.icuData !== undefined) requireDirectory(args.icuData, "ICU data"); - if (args.destination === path.parse(args.destination).root) fail("destination must not be a filesystem root"); - - const scratch = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-native-cluster-seed-")); - try { - const output = path.join(scratch, "resources"); - const commandArgs = nativeClusterSeedProducerArgs(output, args.profile); - const env = { - ...process.env, - OLIPHAUNT_INSTALL_DIR: args.runtime, - }; - delete env.OLIPHAUNT_EMBEDDED_MODULE_DIR; - delete env.ICU_DATA; - delete env.OLIPHAUNT_INTERNAL_ICU_READY; - delete env[SKIP_SYSTEM_COLLATION_DISCOVERY_ENV]; - delete env[SKIP_ICU_COLLATION_DISCOVERY_ENV]; - delete env.OLIPHAUNT_ICU_DATA_DIR; - if (args.icuData !== undefined) env.OLIPHAUNT_ICU_DATA_DIR = args.icuData; - const producerEnvironment = nativeClusterSeedProducerEnvironment(args.target, args.profile); - if (producerEnvironment.skipSystemCollationDiscovery) { - env[SKIP_SYSTEM_COLLATION_DISCOVERY_ENV] = "1"; - } - if (producerEnvironment.skipIcuCollationDiscovery) { - env[SKIP_ICU_COLLATION_DISCOVERY_ENV] = "1"; - } - const result = spawnSync("cargo", commandArgs, { - cwd: ROOT, - env, - encoding: "utf8", - maxBuffer: 64 * 1024 * 1024, - }); - if (result.status !== 0) { - fail(`native cluster-seed producer failed: ${(result.stderr || result.stdout || "").trim()}`); - } - const source = path.join(output, "oliphaunt/cluster-seed"); - const manifestPath = path.join(source, "manifest.properties"); - const manifest = bindNativeClusterSeedManifest(readFileSync(manifestPath), args.target, args.profile); - writeFileSync(manifestPath, manifest); - validateNativeClusterSeedDirectory(source, args.profile, { - target: args.target, - icuData: args.icuData, - }); - rmSync(args.destination, { recursive: true, force: true }); - cpSync(source, args.destination, { recursive: true, errorOnExist: true }); - return Object.freeze({ destination: args.destination, profile: args.profile, target: args.target }); - } finally { - rmSync(scratch, { recursive: true, force: true }); - } -} - -if (import.meta.main) { - const result = stageNativeClusterSeed(process.argv.slice(2)); - console.log(`clusterSeed=${result.destination}`); - console.log(`catalogProfile=${result.profile}`); - console.log(`target=${result.target}`); -} diff --git a/tools/release/stage-native-cluster-seed.test.mjs b/tools/release/stage-native-cluster-seed.test.mjs deleted file mode 100644 index c2513eb38..000000000 --- a/tools/release/stage-native-cluster-seed.test.mjs +++ /dev/null @@ -1,31 +0,0 @@ -import { expect, test } from "bun:test"; - -import { - nativeClusterSeedProducerArgs, - nativeClusterSeedProducerEnvironment, -} from "./stage-native-cluster-seed.mjs"; - -test("native cluster seeds use the ordinary PostgreSQL server bootstrap closure", () => { - const standard = nativeClusterSeedProducerArgs("/tmp/out", "standard"); - expect(standard).toContain("native-server"); - expect(standard).not.toContain("native-direct"); - expect(standard).not.toContain("--runtime-feature"); - - const icu = nativeClusterSeedProducerArgs("/tmp/out", "icu"); - expect(icu.slice(-2)).toEqual(["--runtime-feature", "icu"]); -}); - -test("suppresses release-runner locale discovery for every distributed seed", () => { - expect(nativeClusterSeedProducerEnvironment("ios-datum64", "standard")).toEqual({ - skipSystemCollationDiscovery: true, - skipIcuCollationDiscovery: true, - }); - expect(nativeClusterSeedProducerEnvironment("android-datum64", "icu")).toEqual({ - skipSystemCollationDiscovery: true, - skipIcuCollationDiscovery: false, - }); - expect(nativeClusterSeedProducerEnvironment("linux-x64-gnu", "standard").skipSystemCollationDiscovery).toBe(true); - expect(nativeClusterSeedProducerEnvironment("windows-x64-msvc", "icu").skipSystemCollationDiscovery).toBe(true); - expect(() => nativeClusterSeedProducerEnvironment("mobile", "standard")).toThrow(/unsupported/u); - expect(() => nativeClusterSeedProducerEnvironment("ios-datum64", "other")).toThrow(/profile/u); -}); diff --git a/tools/release/stage-native-extension-lifecycle.mjs b/tools/release/stage-native-extension-lifecycle.mjs deleted file mode 100755 index 67c3ae60a..000000000 --- a/tools/release/stage-native-extension-lifecycle.mjs +++ /dev/null @@ -1,578 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { gunzipSync } from "node:zlib"; -import { - chmodSync, - lstatSync, - mkdirSync, - readFileSync, - readdirSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { - ROOT, - compareText, - currentProductVersionSync, - exactExtensionProducts, - extensionReleaseProduct, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { - NATIVE_EXTENSION_ASSET_INDEX_HEADER, - isCanonicalNativeExtensionRuntimeIndexRow, -} from "./native-extension-asset-index-contract.mjs"; -import { - requiredRuntimeMemberPaths, - requiredToolsMemberPaths, -} from "./optimize_native_runtime_payload.mjs"; -import { - isCanonicalExtensionInstallSql, - validateExtensionArtifactArchive, - validateExtensionInstallSqlReachability, -} from "./extension-artifact-inventory.mjs"; - -const PREFIX = "stage-native-extension-lifecycle.mjs"; -const TARGET = "linux-x64-gnu"; -function fail(message) { - throw new Error(`${PREFIX}: ${message}`); -} - -function parseArgs(argv) { - const values = new Map(); - const pathArguments = new Set([ - "runtime-assets", - "extension-assets", - "broker-assets", - "proof-runner", - "output", - ]); - for (let index = 0; index < argv.length; index += 1) { - const name = argv[index]; - if (!name?.startsWith("--")) fail(`unknown argument ${name}`); - const value = argv[index + 1]; - if (!value || value.startsWith("--")) fail(`${name} requires a value`); - const key = name.slice(2); - values.set(key, pathArguments.has(key) ? path.resolve(value) : value); - index += 1; - } - for (const required of [ - "runtime-assets", - "extension-assets", - "broker-assets", - "proof-runner", - "candidate-sha", - "candidate-tree", - "extensions-csv", - "output", - ]) { - if (!values.has(required)) fail(`--${required} is required`); - } - return Object.fromEntries(values); -} - -function sha256Bytes(data) { - return createHash("sha256").update(data).digest("hex"); -} - -function artifactRecord(identity, file) { - const data = readFileSync(file); - return { - identity, - file: path.basename(file), - bytes: data.length, - sha256: sha256Bytes(data), - }; -} - -export function assertExactFiles(root, expected, label) { - const actual = regularFiles(root).map((file) => path.resolve(file)).sort(compareText); - const wanted = [...expected].map((file) => path.resolve(file)).sort(compareText); - if (actual.join("\0") !== wanted.join("\0")) { - fail( - `${label} has unindexed files: expected=${wanted.map((file) => path.basename(file)).join(",")}; ` + - `actual=${actual.map((file) => path.basename(file)).join(",")}`, - ); - } -} - -function regularFiles(root) { - const files = []; - const visit = (directory) => { - for (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) => compareText(a.name, b.name))) { - const file = path.join(directory, entry.name); - const stat = lstatSync(file); - if (stat.isSymbolicLink()) fail(`artifact input contains symbolic link: ${file}`); - if (stat.isDirectory()) visit(file); - else if (stat.isFile()) files.push(file); - else fail(`artifact input contains unsupported filesystem entry: ${file}`); - } - }; - if (!statSync(root).isDirectory()) fail(`artifact input is not a directory: ${root}`); - visit(root); - return files; -} - -function oneFile(root, basename) { - const matches = regularFiles(root).filter((file) => path.basename(file) === basename); - if (matches.length !== 1) { - fail(`${root} must contain exactly one ${basename}, found ${matches.length}`); - } - return matches[0]; -} - -function tarString(buffer, start, length) { - const end = buffer.indexOf(0, start); - return buffer - .subarray(start, end >= start && end < start + length ? end : start + length) - .toString("utf8") - .trim(); -} - -function tarOctal(buffer, start, length, label) { - const value = tarString(buffer, start, length).replaceAll("\0", "").trim(); - if (!value) return 0; - if (!/^[0-7]+$/u.test(value)) fail(`archive has malformed ${label}: ${JSON.stringify(value)}`); - return Number.parseInt(value, 8); -} - -function safeArchivePath(raw, archive) { - const normalized = raw.replaceAll("\\", "/").replace(/\/$/u, ""); - if (normalized === ".") return null; - const parts = normalized.split("/"); - if (!normalized || normalized.startsWith("/") || parts.some((part) => !part || part === "." || part === "..")) { - fail(`${archive} contains unsafe member ${JSON.stringify(raw)}`); - } - return parts.join("/"); -} - -export function readCanonicalTarGz(file) { - let buffer; - try { - buffer = gunzipSync(readFileSync(file)); - } catch (error) { - fail(`${file} is not a readable gzip tar archive: ${error.message}`); - } - const entries = new Map(); - let sawTerminator = false; - for (let offset = 0; offset + 512 <= buffer.length; ) { - const header = buffer.subarray(offset, offset + 512); - if (header.every((byte) => byte === 0)) { - sawTerminator = true; - break; - } - const rawName = tarString(header, 0, 100); - const prefix = tarString(header, 345, 155); - const fullName = prefix ? `${prefix}/${rawName}` : rawName; - const name = safeArchivePath(fullName, file); - const mode = tarOctal(header, 100, 8, "mode"); - const size = tarOctal(header, 124, 12, "size"); - const type = header.subarray(156, 157).toString("utf8"); - if (type !== "0" && type !== "5" && type !== "") { - fail(`${file} contains unsupported non-file member ${JSON.stringify(fullName)} type=${JSON.stringify(type)}`); - } - const isDirectory = type === "5"; - if (isDirectory !== fullName.endsWith("/") && name !== null) { - fail(`${file} contains non-canonical member marker ${JSON.stringify(fullName)}`); - } - const dataOffset = offset + 512; - if (dataOffset + size > buffer.length) fail(`${file} truncates member ${fullName}`); - if (name !== null) { - if (entries.has(name)) fail(`${file} contains duplicate member ${name}`); - entries.set(name, { - data: Buffer.from(buffer.subarray(dataOffset, dataOffset + size)), - isDirectory, - mode, - }); - } - offset = dataOffset + Math.ceil(size / 512) * 512; - } - if (!sawTerminator) fail(`${file} is missing the tar terminator`); - return entries; -} - -function extract(entries, destination) { - mkdirSync(destination, { recursive: true }); - for (const [name, entry] of [...entries].sort(([left], [right]) => compareText(left, right))) { - const output = path.join(destination, ...name.split("/")); - const relative = path.relative(destination, output); - if (relative.startsWith("..") || path.isAbsolute(relative)) fail(`unsafe extraction path ${name}`); - if (entry.isDirectory) { - mkdirSync(output, { recursive: true }); - chmodSync(output, 0o755); - } else { - mkdirSync(path.dirname(output), { recursive: true }); - writeFileSync(output, entry.data, { mode: entry.mode & 0o111 ? 0o755 : 0o644 }); - } - } -} - -function optionalLstat(file) { - try { - return lstatSync(file); - } catch (error) { - if (error?.code === "ENOENT") return null; - throw error; - } -} - -/** - * Stage one validated extension carrier into the product-owned resource layout - * emitted by oliphaunt-build. Carrier-only manifest.properties and files/ - * envelope paths are deliberately not exposed to the runtime locator. - */ -export function stageExtensionCarrier(entries, output, metadata, archive = "native extension carrier") { - const artifactProduct = metadata?.["artifact-product"]; - const releaseProduct = metadata?.["release-product"]; - if ( - typeof artifactProduct !== "string" - || !/^oliphaunt-extension-[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(artifactProduct) - ) { - fail(`${archive} has invalid generated artifact-product ${JSON.stringify(artifactProduct)}`); - } - const expectedReleaseProduct = extensionReleaseProduct(artifactProduct, "native", PREFIX); - if (releaseProduct !== expectedReleaseProduct) { - fail(`${archive} has invalid generated release-product ${JSON.stringify(releaseProduct)}`); - } - requireArchiveFile(entries, "manifest.properties", archive); - const destination = path.join(output, "resources/extension", artifactProduct); - mkdirSync(destination, { recursive: true }); - let stagedFiles = 0; - for (const [name, entry] of [...entries].sort(([left], [right]) => compareText(left, right))) { - if (name === "manifest.properties") continue; - if (name === "files") { - if (!entry.isDirectory) fail(`${archive} files carrier root must be a directory`); - continue; - } - if (!name.startsWith("files/")) { - fail(`${archive} contains unexpected carrier-root member ${name}`); - } - const relativeName = name.slice("files/".length); - if (!relativeName) fail(`${archive} contains an empty carrier payload path`); - const target = path.join(destination, ...relativeName.split("/")); - const relative = path.relative(destination, target); - if (relative.startsWith("..") || path.isAbsolute(relative)) { - fail(`${archive} contains unsafe carrier payload path ${name}`); - } - const existing = optionalLstat(target); - if (entry.isDirectory) { - if (existing !== null && !existing.isDirectory()) { - fail(`${archive} payload directory conflicts at ${target}`); - } - mkdirSync(target, { recursive: true }); - chmodSync(target, 0o755); - continue; - } - if (existing !== null) { - if (!existing.isFile() || existing.isSymbolicLink()) { - fail(`${archive} payload file conflicts at ${target}`); - } - const existingData = readFileSync(target); - if (!existingData.equals(entry.data)) { - fail( - `${archive} payload conflicts at ${target} with different bytes: ` - + `existing=${sha256Bytes(existingData)} incoming=${sha256Bytes(entry.data)}`, - ); - } - const executable = (existing.mode & 0o111) !== 0 || (entry.mode & 0o111) !== 0; - chmodSync(target, executable ? 0o755 : 0o644); - } else { - try { - mkdirSync(path.dirname(target), { recursive: true }); - } catch (error) { - fail(`${archive} cannot create payload parent for ${target}: ${error.message}`); - } - writeFileSync(target, entry.data, { mode: entry.mode & 0o111 ? 0o755 : 0o644 }); - } - stagedFiles += 1; - } - if (stagedFiles === 0) fail(`${archive} has no files/ payload files`); - return destination; -} - -function parseProperties(data, label) { - const properties = new Map(); - for (const [index, raw] of data.toString("utf8").split(/\r?\n/u).entries()) { - if (!raw) continue; - const separator = raw.indexOf("="); - if (separator <= 0) fail(`${label} has malformed properties line ${index + 1}`); - const key = raw.slice(0, separator); - if (properties.has(key)) fail(`${label} repeats property ${key}`); - properties.set(key, raw.slice(separator + 1)); - } - return properties; -} - -function parseTsv(file) { - const lines = readFileSync(file, "utf8").split(/\r?\n/u).filter(Boolean); - if (lines.length < 2) fail(`${file} has no artifact rows`); - const header = lines[0].split("\t"); - const expectedHeader = NATIVE_EXTENSION_ASSET_INDEX_HEADER; - if (header.join("\t") !== expectedHeader.join("\t")) fail(`${file} has a non-canonical header`); - return lines.slice(1).map((line, index) => { - const fields = line.split("\t"); - if (fields.length !== header.length) fail(`${file} row ${index + 2} has ${fields.length} fields`); - return Object.fromEntries(header.map((column, fieldIndex) => [column, fields[fieldIndex]])); - }); -} - -function canonicalExtensions(selectionCsv) { - const metadataFile = path.join(ROOT, "src/extensions/generated/sdk/extensions.json"); - const metadata = JSON.parse(readFileSync(metadataFile, "utf8")); - const byName = new Map((metadata.extensions ?? []).map((row) => [row["sql-name"], row])); - const canonicalNames = exactExtensionProducts(PREFIX) - .flatMap((product) => extensionSqlNames(product, PREFIX)) - .sort(compareText); - if (canonicalNames.length === 0 || new Set(canonicalNames).size !== canonicalNames.length) { - fail("canonical exact-extension products must resolve to a nonempty unique SQL-name set"); - } - const names = selectionCsv.split(",").filter(Boolean).sort(compareText); - if (names.length === 0 || new Set(names).size !== names.length) { - fail("planned native lifecycle extension selection must be nonempty and unique"); - } - const canonicalSet = new Set(canonicalNames); - const unknown = names.filter((name) => !canonicalSet.has(name)); - if (unknown.length > 0) fail(`planned native lifecycle selection contains unknown extensions: ${unknown.join(",")}`); - const rows = names.map((name) => { - const row = byName.get(name); - if (!row) fail(`generated extension metadata has no row for ${name}`); - return row; - }); - const selectedSet = new Set(names); - for (const row of rows) { - const missing = (row["selected-extension-dependencies"] ?? []) - .filter((dependency) => !selectedSet.has(dependency)); - if (missing.length > 0) { - fail(`${row["sql-name"]} planned native lifecycle selection omits dependencies: ${missing.join(",")}`); - } - } - return rows; -} - -function requireArchiveFile(entries, name, archive) { - const entry = entries.get(name); - if (!entry || entry.isDirectory || entry.data.length === 0) fail(`${archive} is missing non-empty ${name}`); - return entry; -} - -export function selectedExtensionDependencies(metadata) { - const selected = metadata?.["selected-extension-dependencies"]; - if (!Array.isArray(selected) || selected.some((name) => typeof name !== "string" || name.length === 0)) { - fail("generated extension metadata has invalid selected-extension-dependencies"); - } - const sorted = [...selected].sort(compareText); - if (new Set(sorted).size !== sorted.length) { - fail("generated extension metadata repeats a selected extension dependency"); - } - return sorted.join(","); -} - -function stageBaseRuntime(runtimeAssets, output, extensionRows) { - const version = currentProductVersionSync("liboliphaunt-native", PREFIX); - const runtimeArchive = oneFile(runtimeAssets, `liboliphaunt-${version}-${TARGET}.tar.gz`); - const toolsArchive = oneFile(runtimeAssets, `oliphaunt-tools-${version}-${TARGET}.tar.gz`); - const runtimeEntries = readCanonicalTarGz(runtimeArchive); - const toolsEntries = readCanonicalTarGz(toolsArchive); - for (const required of [ - "lib/liboliphaunt.so", - "lib/modules/dict_snowball.so", - "lib/modules/plpgsql.so", - ...requiredRuntimeMemberPaths(TARGET, "runtime/bin"), - ]) requireArchiveFile(runtimeEntries, required, runtimeArchive); - for (const required of requiredToolsMemberPaths(TARGET, "runtime/bin")) { - requireArchiveFile(toolsEntries, required, toolsArchive); - } - for (const row of extensionRows) { - const sqlName = row["sql-name"]; - if (runtimeEntries.has(`runtime/share/postgresql/extension/${sqlName}.control`)) { - fail(`base runtime artifact leaks optional extension ${sqlName}`); - } - } - extract(runtimeEntries, path.join(output, "resources/native-runtime/liboliphaunt-native")); - extract(toolsEntries, path.join(output, "resources/native-tools/oliphaunt-tools")); - assertExactFiles(runtimeAssets, [runtimeArchive, toolsArchive], "Linux runtime artifact download"); - return [ - artifactRecord("native-runtime", runtimeArchive), - artifactRecord("native-tools", toolsArchive), - ]; -} - -function stageBroker(brokerAssets, output) { - const version = currentProductVersionSync("oliphaunt-broker", PREFIX); - const archive = oneFile(brokerAssets, `oliphaunt-broker-${version}-${TARGET}.tar.gz`); - const checksum = oneFile(brokerAssets, `oliphaunt-broker-${version}-release-assets.sha256`); - const checksumLines = readFileSync(checksum, "utf8").split(/\r?\n/u).filter(Boolean); - if (checksumLines.length !== 1) fail(`${checksum} must cover exactly the one partial Linux broker artifact`); - const checksumMatch = checksumLines[0].match(/^([0-9a-f]{64})\s+\.\/(.+)$/u); - if (!checksumMatch || checksumMatch[2] !== path.basename(archive)) { - fail(`${checksum} does not bind the exact Linux broker artifact`); - } - const actualBrokerSha = artifactRecord("broker", archive).sha256; - if (checksumMatch[1] !== actualBrokerSha) fail(`${checksum} digest does not match ${archive}`); - const entries = readCanonicalTarGz(archive); - const binary = requireArchiveFile(entries, "bin/oliphaunt-broker", archive); - if ((binary.mode & 0o111) === 0) fail(`${archive} broker is not executable`); - const manifest = parseProperties(requireArchiveFile(entries, "manifest.properties", archive).data, archive); - for (const [key, expected] of [ - ["schema", "oliphaunt-broker-release-assets-v1"], - ["product", "oliphaunt-broker"], - ["version", version], - ["target", TARGET], - ["binary", "bin/oliphaunt-broker"], - ]) { - if (manifest.get(key) !== expected) fail(`${archive} ${key} must be ${expected}`); - } - extract(entries, path.join(output, "broker")); - assertExactFiles(brokerAssets, [archive, checksum], "Linux broker artifact download"); - return [artifactRecord("broker", archive), artifactRecord("broker-checksum", checksum)]; -} - -function stageExtensions(extensionAssets, output, extensionRows) { - const version = currentProductVersionSync("liboliphaunt-native", PREFIX); - const index = oneFile(extensionAssets, `liboliphaunt-${version}-native-extension-assets.tsv`); - const rows = parseTsv(index); - const expectedNames = extensionRows.map((row) => row["sql-name"]).sort(compareText); - const actualNames = rows.map((row) => row.sql_name).sort(compareText); - if (rows.length !== expectedNames.length || new Set(actualNames).size !== rows.length) { - fail(`native extension artifact index must contain ${expectedNames.length} unique rows, got ${rows.length}`); - } - if (actualNames.join("\0") !== expectedNames.join("\0")) { - fail(`native extension artifact index drift: expected=${expectedNames.join(",")}; actual=${actualNames.join(",")}`); - } - const metadataByName = new Map(extensionRows.map((row) => [row["sql-name"], row])); - const referenced = new Set(); - const consumed = [artifactRecord("native-extension-index", index)]; - for (const row of rows) { - if (!isCanonicalNativeExtensionRuntimeIndexRow(row, TARGET)) { - fail(`native extension artifact index has invalid carrier row for ${row.sql_name}`); - } - if (!/^[1-9][0-9]*$/u.test(row.artifact_bytes)) fail(`invalid artifact byte count for ${row.sql_name}`); - const archive = path.resolve(path.dirname(index), row.artifact); - const relative = path.relative(path.dirname(index), archive); - if (relative.startsWith("..") || path.isAbsolute(relative)) fail(`artifact path escapes index for ${row.sql_name}`); - if (statSync(archive).size !== Number(row.artifact_bytes)) fail(`artifact byte count drift for ${row.sql_name}`); - referenced.add(archive); - consumed.push(artifactRecord(`native-extension:${row.sql_name}`, archive)); - const metadata = metadataByName.get(row.sql_name); - const validated = validateExtensionArtifactArchive({ - file: archive, - metadata, - target: TARGET, - nativeRuntimeVersion: version, - label: archive, - }); - const { entries, properties: manifest } = validated; - const expectedDependencies = selectedExtensionDependencies(metadata); - for (const [key, expected] of [ - ["packageLayout", "oliphaunt-extension-artifact-v1"], - ["pgMajor", "18"], - ["sqlName", row.sql_name], - ["createsExtension", metadata["creates-extension"] === true ? "yes" : "no"], - ["nativeModuleStem", metadata["native-module-stem"] ?? ""], - ["nativeTarget", TARGET], - ["nativeRuntimeProduct", "liboliphaunt-native"], - ["nativeRuntimeVersion", version], - ["dependencies", expectedDependencies], - ["dataFiles", (metadata["runtime-share-data-files"] ?? []).join(",")], - ["extensionSqlFileNames", (metadata["extension-sql-file-names"] ?? []).join(",")], - ["extensionSqlFilePrefixes", (metadata["extension-sql-file-prefixes"] ?? []).join(",")], - ["sharedPreloadLibraries", (metadata["shared-preload-libraries"] ?? []).join(",")], - ["files", "files"], - ]) { - if (manifest.get(key) !== expected) fail(`${archive} ${key} must be ${expected}`); - } - if (!new Set(["yes", "no"]).has(manifest.get("mobilePrebuilt"))) { - fail(`${archive} mobilePrebuilt must be yes or no`); - } - if (metadata["creates-extension"] === true) { - const controlName = `files/share/postgresql/extension/${row.sql_name}.control`; - const control = requireArchiveFile(entries, controlName, archive); - const sqlPrefix = "files/share/postgresql/extension/"; - const sqlFileNames = [...entries.keys()] - .filter((name) => name.startsWith(sqlPrefix) && !entries.get(name).isDirectory) - .map((name) => name.slice(sqlPrefix.length)); - if (!sqlFileNames.some((name) => isCanonicalExtensionInstallSql(name, row.sql_name))) { - fail(`${archive} has no canonical base install SQL for ${row.sql_name}`); - } - validateExtensionInstallSqlReachability({ - sqlName: row.sql_name, - control: control.data.toString("utf8"), - fileNames: sqlFileNames, - label: archive, - }); - } - const stem = metadata["native-module-stem"]; - const expectedModuleFile = stem === null ? "" : `${stem}.so`; - if (manifest.get("nativeModuleFile") !== expectedModuleFile) { - fail(`${archive} nativeModuleFile must be ${expectedModuleFile}`); - } - if (expectedModuleFile !== "") { - requireArchiveFile(entries, `files/lib/postgresql/${expectedModuleFile}`, archive); - } - // Legal-envelope members are validated above but are not runtime resources. - // Flatten only manifest.properties + files/** into the lifecycle layout. - const runtimeEntries = new Map( - [...entries].filter(([name]) => name === "manifest.properties" || name.startsWith("files/")), - ); - stageExtensionCarrier(runtimeEntries, output, metadata, archive); - } - const unreferenced = regularFiles(path.dirname(index)) - .filter((file) => file.endsWith(".tar.gz") && !referenced.has(file)) - .map((file) => path.basename(file)); - if (unreferenced.length > 0) fail(`unindexed native extension artifacts: ${unreferenced.join(",")}`); - const legacyIndex = oneFile( - extensionAssets, - `liboliphaunt-${version}-extension-assets.tsv`, - ); - consumed.push(artifactRecord("native-extension-legacy-index", legacyIndex)); - assertExactFiles( - extensionAssets, - [index, legacyIndex, ...referenced], - "Linux exact-extension artifact download", - ); - return consumed; -} - -export function stageNativeExtensionLifecycle(args) { - if (!/^[0-9a-f]{40}$/u.test(args["candidate-sha"])) fail("--candidate-sha must be a full 40-character Git object ID"); - if (!/^[0-9a-f]{40}$/u.test(args["candidate-tree"])) fail("--candidate-tree must be a full 40-character Git tree ID"); - const extensionRows = canonicalExtensions(args["extensions-csv"]); - rmSync(args.output, { force: true, recursive: true }); - mkdirSync(args.output, { recursive: true }); - const consumedArtifacts = [ - ...stageBaseRuntime(args["runtime-assets"], args.output, extensionRows), - ...stageBroker(args["broker-assets"], args.output), - ...stageExtensions(args["extension-assets"], args.output, extensionRows), - artifactRecord("native-extension-proof-runner", args["proof-runner"]), - ].sort((left, right) => compareText(left.identity, right.identity)); - const evidenceCore = { - schema: "oliphaunt-native-extension-lifecycle-inputs-v1", - candidateSha: args["candidate-sha"], - candidateTree: args["candidate-tree"], - target: TARGET, - extensionCount: extensionRows.length, - extensions: extensionRows.map((row) => row["sql-name"]).sort(compareText), - modes: ["direct", "broker", "server"], - lifecycle: ["install", "load", "restart", "backup", "restore"], - consumedArtifacts, - }; - const evidence = { - ...evidenceCore, - inputEnvelopeSha256: sha256Bytes(Buffer.from(JSON.stringify(evidenceCore))), - }; - writeFileSync(path.join(args.output, "inputs.json"), `${JSON.stringify(evidence, null, 2)}\n`); - console.log(`native extension lifecycle inputs staged: ${args.output} (${extensionRows.length} extensions)`); -} - -if (import.meta.main) { - try { - stageNativeExtensionLifecycle(parseArgs(Bun.argv.slice(2))); - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(1); - } -} diff --git a/tools/release/strip_native_release_binaries.mjs b/tools/release/strip_native_release_binaries.mjs deleted file mode 100644 index 97510a304..000000000 --- a/tools/release/strip_native_release_binaries.mjs +++ /dev/null @@ -1,294 +0,0 @@ -#!/usr/bin/env bun -import { readdir, stat } from "node:fs/promises"; -import { accessSync, constants, existsSync } from "node:fs"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { WINDOWS_VC_RUNTIME_DLLS } from "./windows-vc-runtime-closure.mjs"; - -const MACHO_MAGICS = new Set([ - "feedface", - "cefaedfe", - "feedfacf", - "cffaedfe", - "cafebabe", - "bebafeca", -]); -const WINDOWS_VC_RUNTIME_SET = new Set(WINDOWS_VC_RUNTIME_DLLS); - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function fail(message) { - console.error(`strip_native_release_binaries.mjs: ${message}`); - process.exit(2); -} - -async function readPrefix(file, size = 8) { - try { - return Buffer.from(await Bun.file(file).slice(0, size).arrayBuffer()); - } catch (error) { - fail(`failed to read ${file}: ${error.message}`); - } -} - -async function classify(file) { - const prefix = await readPrefix(file); - if (prefix.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46]))) { - return { path: file, kind: "elf", archive: false }; - } - if (MACHO_MAGICS.has(prefix.subarray(0, 4).toString("hex"))) { - return { path: file, kind: "macho", archive: false }; - } - if (prefix.subarray(0, 2).toString("utf8") === "MZ") { - return { path: file, kind: "pe", archive: false }; - } - if (prefix.toString("utf8") === "!\n") { - return { path: file, kind: "archive", archive: true }; - } - return undefined; -} - -async function* iterFiles(roots) { - for (const root of roots) { - let info; - try { - info = await stat(root); - } catch { - fail(`input path does not exist: ${root}`); - } - if (info.isFile()) { - yield root; - continue; - } - if (!info.isDirectory()) { - fail(`input path does not exist: ${root}`); - } - yield* iterDirectory(root); - } -} - -async function* iterDirectory(root) { - const entries = (await readdir(root, { withFileTypes: true })).sort((left, right) => - compareText(left.name, right.name), - ); - for (const entry of entries) { - const entryPath = path.join(root, entry.name); - if (entry.isFile()) { - yield entryPath; - } else if (entry.isDirectory()) { - yield* iterDirectory(entryPath); - } - } -} - -function envTool(...names) { - for (const name of names) { - const value = process.env[name]; - if (value) { - return value; - } - } - return undefined; -} - -function isExecutable(file) { - try { - accessSync(file, constants.X_OK); - return true; - } catch { - return false; - } -} - -function findTool(...names) { - const paths = (process.env.PATH ?? "").split(path.delimiter).filter(Boolean); - const extensions = - process.platform === "win32" - ? ["", ...(process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";")] - : [""]; - for (const name of names) { - if (name.includes("/") || name.includes("\\")) { - if (isExecutable(name)) { - return name; - } - continue; - } - for (const directory of paths) { - for (const extension of extensions) { - const candidate = path.join(directory, `${name}${extension}`); - if (isExecutable(candidate)) { - return candidate; - } - } - } - } - return undefined; -} - -function darwinStripTool() { - const override = envTool("OLIPHAUNT_MACHO_STRIP", "OLIPHAUNT_STRIP"); - if (override) { - return override; - } - if (process.platform === "darwin") { - const result = captureCommandOutput("xcrun", ["--find", "strip"], { - label: "xcrun --find strip", - }); - if (result.status === 0 && result.stdout.trim()) { - return result.stdout.trim(); - } - } - return findTool("strip"); -} - -function androidStripTool() { - const override = envTool("OLIPHAUNT_ANDROID_STRIP", "OLIPHAUNT_ELF_STRIP", "OLIPHAUNT_STRIP"); - if (override) { - return override; - } - const ndk = process.env.ANDROID_NDK_HOME ?? process.env.ANDROID_NDK_ROOT; - if (!ndk) { - return undefined; - } - const hosts = { - linux: ["linux-x86_64"], - darwin: ["darwin-arm64", "darwin-x86_64"], - win32: ["windows-x86_64"], - }[process.platform] ?? []; - for (const host of hosts) { - const candidate = path.join( - ndk, - "toolchains", - "llvm", - "prebuilt", - host, - "bin", - process.platform === "win32" ? "llvm-strip.exe" : "llvm-strip", - ); - if (isExecutable(candidate)) { - return candidate; - } - } - return undefined; -} - -function stripToolFor(native, target) { - if (native.archive && path.extname(native.path).toLowerCase() === ".lib") { - console.error(`skippedMsvcImportLibrary=${native.path}`); - return undefined; - } - if (target?.startsWith("android-") && native.kind === "elf") { - const tool = androidStripTool(); - if (!tool) { - fail(`missing Android llvm-strip for ${native.path}; set ANDROID_NDK_HOME or OLIPHAUNT_ANDROID_STRIP`); - } - return { - tool, - flags: native.archive ? ["--strip-debug"] : ["--strip-unneeded"], - }; - } - if (native.kind === "macho") { - const tool = darwinStripTool(); - if (!tool) { - fail(`missing strip tool for Mach-O file ${native.path}`); - } - return { tool, flags: ["-S"] }; - } - if (native.kind === "pe") { - const tool = envTool("OLIPHAUNT_PE_STRIP", "OLIPHAUNT_STRIP") ?? findTool("llvm-strip", "strip"); - if (!tool) { - console.error(`skippedPeNativeFile=${native.path}`); - return undefined; - } - return { tool, flags: ["--strip-debug"] }; - } - if (native.archive && process.platform === "darwin") { - const tool = darwinStripTool(); - if (!tool) { - fail(`missing strip tool for archive ${native.path}`); - } - return { tool, flags: ["-S"] }; - } - const tool = envTool("OLIPHAUNT_ELF_STRIP", "OLIPHAUNT_STRIP") ?? findTool("llvm-strip", "strip"); - if (!tool) { - fail(`missing strip tool for ${native.kind} file ${native.path}`); - } - return { - tool, - flags: native.archive ? ["--strip-debug"] : ["--strip-unneeded"], - }; -} - -async function stripNative(native, target) { - if (native.kind === "pe" && WINDOWS_VC_RUNTIME_SET.has(path.basename(native.path).toLowerCase())) { - console.error(`preservedAppLocalVcRuntime=${native.path}`); - return false; - } - const before = (await stat(native.path)).size; - const command = stripToolFor(native, target); - if (command === undefined) { - return false; - } - const result = captureCommandOutput(command.tool, [...command.flags, native.path], { - label: `${command.tool} ${[...command.flags, native.path].join(" ")}`, - }); - if (result.error !== undefined) { - fail(`${command.tool} failed for ${native.path}: ${result.error.message}`); - } - if (result.status !== 0) { - const stderr = result.stderr.trim(); - fail(`${command.tool} failed for ${native.path}: ${stderr || `exit ${result.status}`}`); - } - return (await stat(native.path)).size !== before; -} - -function parseArgs(argv) { - const args = { - target: undefined, - roots: [], - }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--target") { - args.target = argv[++index]; - if (!args.target) { - fail("--target requires a value"); - } - continue; - } - if (arg === "--help" || arg === "-h") { - console.log("usage: strip_native_release_binaries.mjs [--target ] [path...]"); - process.exit(0); - } - if (arg.startsWith("-")) { - fail(`unknown option: ${arg}`); - } - args.roots.push(arg); - } - return args; -} - -const { target, roots } = parseArgs(Bun.argv.slice(2)); -if (roots.length === 0) { - fail("usage: strip_native_release_binaries.mjs [--target ] [path...]"); -} - -const nativeFiles = []; -for await (const file of iterFiles(roots)) { - const native = await classify(file); - if (native !== undefined) { - nativeFiles.push(native); - } -} - -let changed = 0; -for (const native of nativeFiles) { - if (await stripNative(native, target)) { - changed += 1; - } -} - -console.log(`strippedNativeFiles=${changed}`); -console.log(`checkedNativeFiles=${nativeFiles.length}`); diff --git a/tools/release/swift-extension-release-consumer-inputs.mjs b/tools/release/swift-extension-release-consumer-inputs.mjs deleted file mode 100644 index 6c404e5a7..000000000 --- a/tools/release/swift-extension-release-consumer-inputs.mjs +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env bun - -import { readFileSync } from "node:fs"; - -import { contribCarrierDescriptor } from "./release-artifact-targets.mjs"; -import { validateSelectionNeutralSwiftSourceCarrier } from "./swift-source-carrier-contract.mjs"; - -const PREFIX = "swift-extension-release-consumer-inputs.mjs"; -const EXTENSION_CARRIER_SCHEMA = "oliphaunt-swift-extension-carrier-v1"; -const PRODUCT = /^oliphaunt-extension-[A-Za-z0-9._-]+$/u; -const PORTABLE_IDENTIFIER = /^[A-Za-z0-9._-]+$/u; -const STABLE_SEMVER = /^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function fail(message) { - throw new Error(`${PREFIX}: ${message}`); -} - -function object(value, label) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(`${label} must be an object`); - } - return value; -} - -function exactKeys(value, expected, label) { - const actual = Object.keys(object(value, label)).sort(compareText); - const canonical = [...expected].sort(compareText); - if (JSON.stringify(actual) !== JSON.stringify(canonical)) { - fail(`${label} fields must be exactly ${canonical.join(",")}; got ${actual.join(",")}`); - } - return value; -} - -function stableVersion(value, label) { - if (typeof value !== "string" || !STABLE_SEMVER.test(value)) { - fail(`${label} must be a stable SemVer X.Y.Z version`); - } - return value; -} - -function releaseReference(value, label) { - const row = exactKeys(value, ["product", "tag", "version"], label); - const contrib = contribCarrierDescriptor(PREFIX); - if ( - typeof row.product !== "string" - || (!PRODUCT.test(row.product) && row.product !== contrib.nativeOwner) - ) { - fail(`${label}.product must be an exact-extension product or the native contrib owner`); - } - stableVersion(row.version, `${label}.version`); - const expectedTag = `${row.product}-v${row.version}`; - if (row.tag !== expectedTag) { - fail(`${label}.tag must be ${expectedTag}`); - } - return row; -} - -function baseReference(value, label) { - const row = exactKeys(value, ["product", "tag", "version"], label); - if (row.product !== "liboliphaunt-native") { - fail(`${label}.product must be liboliphaunt-native`); - } - stableVersion(row.version, `${label}.version`); - const expectedTag = `${row.product}-v${row.version}`; - if (row.tag !== expectedTag) { - fail(`${label}.tag must be ${expectedTag}`); - } - return row; -} - -function readJson(file, label) { - if (typeof file !== "string" || file.length === 0) { - fail(`${label} path must be a non-empty string`); - } - try { - return JSON.parse(readFileSync(file, "utf8")); - } catch (cause) { - fail(`cannot read ${label} ${file}: ${cause.message}`); - } -} - -export function extensionReleaseConsumerInputs({ sourceCarrierFile, extensionCarrierFiles }) { - const sourceCarrier = readJson(sourceCarrierFile, "source carrier"); - try { - validateSelectionNeutralSwiftSourceCarrier(sourceCarrier, sourceCarrierFile); - } catch (cause) { - fail(cause instanceof Error ? cause.message : String(cause)); - } - if ( - !Array.isArray(extensionCarrierFiles) - || extensionCarrierFiles.length === 0 - || extensionCarrierFiles.some((file) => typeof file !== "string" || file.length === 0) - ) { - fail("at least one independent extension carrier file is required"); - } - if (new Set(extensionCarrierFiles).size !== extensionCarrierFiles.length) { - fail("independent extension carrier paths must not repeat"); - } - - const releaseProducts = new Set(); - const extensions = []; - for (const file of extensionCarrierFiles) { - const carrier = exactKeys( - readJson(file, "extension carrier"), - ["base", "carriers", "entries", "release", "schema"], - file, - ); - if (carrier.schema !== EXTENSION_CARRIER_SCHEMA) { - fail(`${file}.schema must be ${EXTENSION_CARRIER_SCHEMA}`); - } - const base = baseReference(carrier.base, `${file}.base`); - if ( - base.product !== sourceCarrier.base.product - || base.version !== sourceCarrier.base.version - || base.tag !== sourceCarrier.base.tag - ) { - fail(`${file} requires ${base.tag}, but the selection-neutral source carrier provides ${sourceCarrier.base.tag}`); - } - const release = releaseReference(carrier.release, `${file}.release`); - if (releaseProducts.has(release.product)) { - fail(`independent extension carriers repeat release product ${release.product}`); - } - releaseProducts.add(release.product); - if (!Array.isArray(carrier.entries) || carrier.entries.length === 0) { - fail(`${file}.entries must be a non-empty array`); - } - for (const [index, rawEntry] of carrier.entries.entries()) { - const entry = exactKeys(rawEntry, ["dependencyCarriers", "extension"], `${file}.entries[${index}]`); - if (!Array.isArray(entry.dependencyCarriers)) { - fail(`${file}.entries[${index}].dependencyCarriers must be an array`); - } - const extension = object(entry.extension, `${file}.entries[${index}].extension`); - if (typeof extension.product !== "string" || !PRODUCT.test(extension.product)) { - fail(`${file}.entries[${index}].extension.product must be an exact-extension product id`); - } - if (typeof extension.sqlName !== "string" || !PORTABLE_IDENTIFIER.test(extension.sqlName)) { - fail(`${file}.entries[${index}].extension.sqlName must be a portable identifier`); - } - if ( - extension.nativeModuleStem !== null - && (typeof extension.nativeModuleStem !== "string" || !PORTABLE_IDENTIFIER.test(extension.nativeModuleStem)) - ) { - fail(`${file}.entries[${index}].extension.nativeModuleStem must be null or a portable identifier`); - } - const releaseProduct = extension.releaseProduct ?? extension.product; - const contrib = contribCarrierDescriptor(PREFIX); - const validOwnership = release.product === contrib.nativeOwner - ? extension.product === contrib.artifactProduct && releaseProduct === contrib.nativeOwner - : extension.product === release.product && releaseProduct === release.product; - if (!validOwnership || extension.version !== release.version || extension.tag !== release.tag) { - fail(`${file}.entries[${index}].extension must be owned by ${release.tag}`); - } - extensions.push({ - nativeModuleStem: extension.nativeModuleStem, - product: extension.product, - sqlName: extension.sqlName, - }); - } - } - - extensions.sort((left, right) => compareText(left.sqlName, right.sqlName)); - if (new Set(extensions.map(({ sqlName }) => sqlName)).size !== extensions.length) { - fail("independent extension carriers repeat an extension SQL name"); - } - const native = extensions.filter(({ nativeModuleStem }) => nativeModuleStem !== null); - const selectedNative = native.find(({ sqlName }) => sqlName === "postgis") - ?? native.find(({ sqlName }) => sqlName === "vector") - ?? native[0]; - return { - extensionCarrierCount: extensionCarrierFiles.length, - extensionProducts: [...new Set(extensions.map(({ product }) => product))].sort(compareText), - extensions: extensions.map(({ sqlName }) => sqlName), - extensionsCsv: extensions.map(({ sqlName }) => sqlName).join(","), - finalLink: { - kind: selectedNative === undefined ? "base-runtime" : "native-extension", - nativeExtension: selectedNative?.sqlName ?? null, - nativeModuleStem: selectedNative?.nativeModuleStem ?? null, - runtimeProduct: sourceCarrier.base.product, - runtimeVersion: sourceCarrier.base.version, - }, - schema: "oliphaunt-swift-extension-release-consumer-inputs-v1", - }; -} - -function parseArgs(argv) { - const args = { extensionCarrierFiles: [] }; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--help" || arg === "-h") { - console.log( - `usage: ${PREFIX} --source-carrier FILE --extension-carrier FILE [--extension-carrier FILE ...]`, - ); - process.exit(0); - } - if (arg !== "--source-carrier" && arg !== "--extension-carrier") { - fail(`unknown argument ${arg}`); - } - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) { - fail(`${arg} requires a value`); - } - index += 1; - if (arg === "--source-carrier") { - if (args.sourceCarrierFile !== undefined) fail("--source-carrier must be passed exactly once"); - args.sourceCarrierFile = value; - } else { - args.extensionCarrierFiles.push(value); - } - } - if (args.sourceCarrierFile === undefined) fail("--source-carrier is required"); - return args; -} - -if (import.meta.main) { - try { - process.stdout.write(`${JSON.stringify(extensionReleaseConsumerInputs(parseArgs(Bun.argv.slice(2))))}\n`); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/swift-extension-release-consumer-inputs.test.mjs b/tools/release/swift-extension-release-consumer-inputs.test.mjs deleted file mode 100644 index 7a8848d4a..000000000 --- a/tools/release/swift-extension-release-consumer-inputs.test.mjs +++ /dev/null @@ -1,207 +0,0 @@ -import assert from "node:assert/strict"; -import { mkdtempSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { iosBaseLegalMetadata } from "./ios-carrier-manifest.mjs"; -import { extensionReleaseConsumerInputs } from "./swift-extension-release-consumer-inputs.mjs"; - -const VERSION = "1.2.3"; -const BASE_TAG = `liboliphaunt-native-v${VERSION}`; - -function sourceCarrier() { - const asset = (role, name, format, member, bytes) => ({ - bytes, - format, - member, - name, - role, - sha256: String(bytes).padStart(64, "0"), - url: `https://github.com/f0rr0/oliphaunt/releases/download/${BASE_TAG}/${name}`, - }); - return { - base: { - assets: [ - asset("base-xcframework", `liboliphaunt-${VERSION}-apple-spm-xcframework.zip`, "zip", "liboliphaunt.xcframework", 1), - asset("runtime-resources", `liboliphaunt-${VERSION}-runtime-resources-ios-datum64.tar.gz`, "tar.gz", "oliphaunt", 2), - asset("icu-data", `liboliphaunt-${VERSION}-icu-data.tar.gz`, "tar.gz", ".", 3), - ], - product: "liboliphaunt-native", - tag: BASE_TAG, - version: VERSION, - }, - carriers: [], - extensions: [], - legal: { base: iosBaseLegalMetadata(), extensions: [] }, - schema: "oliphaunt-react-native-ios-carrier-v1", - }; -} - -function extensionCarrier(product, rows, { baseVersion = VERSION } = {}) { - const version = product.endsWith("pgtap") ? "2.0.0" : "3.0.0"; - const tag = `${product}-v${version}`; - return { - base: { - product: "liboliphaunt-native", - tag: `liboliphaunt-native-v${baseVersion}`, - version: baseVersion, - }, - carriers: [], - entries: rows.map(({ nativeModuleStem, sqlName }) => ({ - dependencyCarriers: [], - extension: { - nativeModuleStem, - product, - sqlName, - tag, - version, - }, - })), - release: { product, tag, version }, - schema: "oliphaunt-swift-extension-carrier-v1", - }; -} - -function runtimeOwnedContribCarrier(rows) { - const product = "oliphaunt-extension-contrib-pg18"; - const carrier = extensionCarrier(product, rows); - carrier.release = { product: "liboliphaunt-native", tag: BASE_TAG, version: VERSION }; - for (const { extension } of carrier.entries) { - extension.releaseProduct = "liboliphaunt-native"; - extension.tag = BASE_TAG; - extension.version = VERSION; - } - return carrier; -} - -function fixture(documents) { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-swift-consumer-carriers-")); - return documents.map((document, index) => { - const file = path.join(root, `carrier-${index}.json`); - writeFileSync(file, `${JSON.stringify(document, null, 2)}\n`); - return file; - }); -} - -test("plans every repeated independent carrier against a selection-neutral source carrier", () => { - const [source, pgtap, postgis, vector] = fixture([ - sourceCarrier(), - extensionCarrier("oliphaunt-extension-pgtap", [{ nativeModuleStem: null, sqlName: "pgtap" }]), - extensionCarrier("oliphaunt-extension-postgis", [{ nativeModuleStem: "postgis-3", sqlName: "postgis" }]), - extensionCarrier("oliphaunt-extension-vector", [{ nativeModuleStem: "vector", sqlName: "vector" }]), - ]); - assert.deepEqual( - extensionReleaseConsumerInputs({ - extensionCarrierFiles: [pgtap, postgis, vector], - sourceCarrierFile: source, - }), - { - extensionCarrierCount: 3, - extensionProducts: [ - "oliphaunt-extension-pgtap", - "oliphaunt-extension-postgis", - "oliphaunt-extension-vector", - ], - extensions: ["pgtap", "postgis", "vector"], - extensionsCsv: "pgtap,postgis,vector", - finalLink: { - kind: "native-extension", - nativeExtension: "postgis", - nativeModuleStem: "postgis-3", - runtimeProduct: "liboliphaunt-native", - runtimeVersion: VERSION, - }, - schema: "oliphaunt-swift-extension-release-consumer-inputs-v1", - }, - ); -}); - -test("rejects an aggregate or extension-bearing source carrier", () => { - const contaminated = sourceCarrier(); - contaminated.extensions.push({ sqlName: "vector" }); - const [source, vector] = fixture([ - contaminated, - extensionCarrier("oliphaunt-extension-vector", [{ nativeModuleStem: "vector", sqlName: "vector" }]), - ]); - assert.throws( - () => extensionReleaseConsumerInputs({ sourceCarrierFile: source, extensionCarrierFiles: [vector] }), - /source tags are selection-neutral/u, - ); - - const [neutralSource, aggregate] = fixture([sourceCarrier(), sourceCarrier()]); - assert.throws( - () => extensionReleaseConsumerInputs({ sourceCarrierFile: neutralSource, extensionCarrierFiles: [aggregate] }), - /fields must be exactly base,carriers,entries,release,schema/u, - ); -}); - -test("rejects base skew and repeated owners", () => { - const [source, skewed] = fixture([ - sourceCarrier(), - extensionCarrier( - "oliphaunt-extension-vector", - [{ nativeModuleStem: "vector", sqlName: "vector" }], - { baseVersion: "1.2.4" }, - ), - ]); - assert.throws( - () => extensionReleaseConsumerInputs({ sourceCarrierFile: source, extensionCarrierFiles: [skewed] }), - /requires liboliphaunt-native-v1\.2\.4.*provides liboliphaunt-native-v1\.2\.3/u, - ); - - const [neutral, first, second] = fixture([ - sourceCarrier(), - extensionCarrier("oliphaunt-extension-vector", [{ nativeModuleStem: "vector", sqlName: "vector" }]), - extensionCarrier("oliphaunt-extension-vector", [{ nativeModuleStem: "vector", sqlName: "vector2" }]), - ]); - assert.throws( - () => extensionReleaseConsumerInputs({ sourceCarrierFile: neutral, extensionCarrierFiles: [first, second] }), - /repeat release product oliphaunt-extension-vector/u, - ); -}); - -test("plans an explicit base-runtime final-link proof for an SQL-only selection", () => { - const [sqlSource, sqlOnly] = fixture([ - sourceCarrier(), - extensionCarrier("oliphaunt-extension-pgtap", [{ nativeModuleStem: null, sqlName: "pgtap" }]), - ]); - assert.deepEqual( - extensionReleaseConsumerInputs({ sourceCarrierFile: sqlSource, extensionCarrierFiles: [sqlOnly] }), - { - extensionCarrierCount: 1, - extensionProducts: ["oliphaunt-extension-pgtap"], - extensions: ["pgtap"], - extensionsCsv: "pgtap", - finalLink: { - kind: "base-runtime", - nativeExtension: null, - nativeModuleStem: null, - runtimeProduct: "liboliphaunt-native", - runtimeVersion: VERSION, - }, - schema: "oliphaunt-swift-extension-release-consumer-inputs-v1", - }, - ); -}); - -test("plans native-owned contrib under its logical extension identity", () => { - const [source, contrib] = fixture([ - sourceCarrier(), - runtimeOwnedContribCarrier([{ nativeModuleStem: null, sqlName: "amcheck" }]), - ]); - const plan = extensionReleaseConsumerInputs({ - sourceCarrierFile: source, - extensionCarrierFiles: [contrib], - }); - assert.deepEqual(plan.extensionProducts, ["oliphaunt-extension-contrib-pg18"]); - assert.deepEqual(plan.extensions, ["amcheck"]); - - const forged = runtimeOwnedContribCarrier([{ nativeModuleStem: null, sqlName: "amcheck" }]); - forged.entries[0].extension.releaseProduct = "oliphaunt-extension-contrib-pg18"; - const [forgedFile] = fixture([forged]); - assert.throws( - () => extensionReleaseConsumerInputs({ sourceCarrierFile: source, extensionCarrierFiles: [forgedFile] }), - /must be owned by liboliphaunt-native-v1[.]2[.]3/u, - ); -}); diff --git a/tools/release/swift-source-carrier-contract.mjs b/tools/release/swift-source-carrier-contract.mjs deleted file mode 100644 index 1f766727a..000000000 --- a/tools/release/swift-source-carrier-contract.mjs +++ /dev/null @@ -1,297 +0,0 @@ -import { readFileSync } from "node:fs"; -import path from "node:path"; - -import { - IOS_CARRIER_SCHEMA, - iosBaseLegalMetadata, -} from "./ios-carrier-manifest.mjs"; -import { parseSwiftReleaseBinaryTarget } from "./prepare-swift-release-consumer.mjs"; - -const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; -const CANONICAL_REPOSITORY = "https://github.com/f0rr0/oliphaunt"; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function error(label, message) { - return new Error(`${label}: ${message}`); -} - -function exactKeys(value, expected, label) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(label, "must be an object"); - } - const actual = Object.keys(value).sort(compareText); - const canonical = [...expected].sort(compareText); - if (JSON.stringify(actual) !== JSON.stringify(canonical)) { - throw error( - label, - `fields must be exactly ${canonical.join(",")}; got ${actual.join(",")}`, - ); - } - return value; -} - -function safeArchiveMember(value, label) { - if ( - typeof value !== "string" - || value.length === 0 - || value.includes("\\") - || value.startsWith("/") - || /^[A-Za-z]:/u.test(value) - || /[\u0000-\u001f\u007f]/u.test(value) - ) { - throw error(label, "must be a safe POSIX archive path"); - } - if (value === ".") return value; - const parts = value.split("/"); - if (parts.some((part) => part.length === 0 || part === "." || part === "..")) { - throw error(label, "must be a safe POSIX archive path"); - } - return value; -} - -function portableFilename(value, label) { - if ( - typeof value !== "string" - || value.length === 0 - || path.posix.basename(value) !== value - || /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) - || /[ .]$/u.test(value) - || /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value) - ) { - throw error(label, "must be a portable release asset filename"); - } - return value; -} - -/** - * Validate the carrier embedded in an Oliphaunt Swift source tag. - * - * Source tags intentionally freeze only the compatible native base. Optional - * extensions are supplied by their independently versioned release carriers, - * so both carrier and extension inventories must remain empty here. - */ -export function validateSelectionNeutralSwiftSourceCarrier( - document, - label = "oliphaunt-swift source-tag carrier", -) { - const root = exactKeys( - document, - ["base", "carriers", "extensions", "legal", "schema"], - label, - ); - if (root.schema !== IOS_CARRIER_SCHEMA) { - throw error(label, `schema must be ${IOS_CARRIER_SCHEMA}`); - } - if (!Array.isArray(root.carriers) || root.carriers.length !== 0) { - throw error( - `${label}.carriers`, - "must be an empty array; source tags do not own extension payload carriers", - ); - } - if (!Array.isArray(root.extensions) || root.extensions.length !== 0) { - throw error( - `${label}.extensions`, - "must be an empty array; source tags are selection-neutral", - ); - } - const legal = exactKeys(root.legal, ["base", "extensions"], `${label}.legal`); - if (!Array.isArray(legal.extensions) || legal.extensions.length !== 0) { - throw error(`${label}.legal.extensions`, "must be empty for a selection-neutral source carrier"); - } - if (JSON.stringify(legal.base) !== JSON.stringify(iosBaseLegalMetadata())) { - throw error(`${label}.legal.base`, "must match the canonical native Apple legal locators"); - } - - const base = exactKeys( - root.base, - ["assets", "product", "tag", "version"], - `${label}.base`, - ); - if (base.product !== "liboliphaunt-native") { - throw error(`${label}.base.product`, "must be liboliphaunt-native"); - } - if (typeof base.version !== "string" || !STABLE_SEMVER.test(base.version)) { - throw error(`${label}.base.version`, "must be a stable SemVer X.Y.Z version"); - } - const expectedTag = `${base.product}-v${base.version}`; - if (base.tag !== expectedTag) { - throw error(`${label}.base.tag`, `must be ${expectedTag}`); - } - - const assetContracts = [ - { - format: "zip", - member: "liboliphaunt.xcframework", - name: `liboliphaunt-${base.version}-apple-spm-xcframework.zip`, - role: "base-xcframework", - }, - { - format: "tar.gz", - member: "oliphaunt", - name: `liboliphaunt-${base.version}-runtime-resources-ios-datum64.tar.gz`, - role: "runtime-resources", - }, - { - format: "tar.gz", - member: ".", - name: `liboliphaunt-${base.version}-icu-data.tar.gz`, - role: "icu-data", - }, - ]; - if (!Array.isArray(base.assets) || base.assets.length !== assetContracts.length) { - throw error( - `${label}.base.assets`, - `must contain exactly ${assetContracts.length} native base assets`, - ); - } - for (const [index, contract] of assetContracts.entries()) { - const assetLabel = `${label}.base.assets[${index}]`; - const asset = exactKeys( - base.assets[index], - ["bytes", "format", "member", "name", "role", "sha256", "url"], - assetLabel, - ); - portableFilename(asset.name, `${assetLabel}.name`); - safeArchiveMember(asset.member, `${assetLabel}.member`); - for (const key of ["format", "member", "name", "role"]) { - if (asset[key] !== contract[key]) { - throw error(`${assetLabel}.${key}`, `must be ${contract[key]}`); - } - } - if (!Number.isSafeInteger(asset.bytes) || asset.bytes <= 0) { - throw error(`${assetLabel}.bytes`, "must be a positive safe integer"); - } - if (typeof asset.sha256 !== "string" || !/^[0-9a-f]{64}$/u.test(asset.sha256)) { - throw error(`${assetLabel}.sha256`, "must be a lowercase SHA-256 digest"); - } - let assetUrl; - try { - assetUrl = new URL(asset.url); - } catch { - throw error(`${assetLabel}.url`, "must be an absolute HTTPS URL"); - } - let urlName; - try { - urlName = decodeURIComponent(path.posix.basename(assetUrl.pathname)); - } catch { - throw error(`${assetLabel}.url`, "contains invalid percent encoding"); - } - if ( - assetUrl.protocol !== "https:" - || assetUrl.username !== "" - || assetUrl.password !== "" - || assetUrl.search !== "" - || assetUrl.hash !== "" - || urlName !== asset.name - ) { - throw error( - `${assetLabel}.url`, - `must be a credential-free HTTPS URL ending in ${asset.name}`, - ); - } - const urlParts = assetUrl.pathname.split("/").filter(Boolean).map((part) => { - try { - return decodeURIComponent(part); - } catch { - throw error(`${assetLabel}.url`, "contains invalid percent encoding"); - } - }); - if ( - urlParts.length < 4 - || JSON.stringify(urlParts.slice(-4)) - !== JSON.stringify(["releases", "download", expectedTag, asset.name]) - ) { - throw error( - `${assetLabel}.url`, - `must address ${asset.name} under release tag ${expectedTag}`, - ); - } - } - return root; -} - -export function validateSelectionNeutralSwiftSourceCarrierFile( - carrier, - label = String(carrier), -) { - let document; - try { - document = JSON.parse(readFileSync(carrier, "utf8")); - } catch (cause) { - throw error(label, `is not valid JSON: ${cause.message}`); - } - return validateSelectionNeutralSwiftSourceCarrier(document, label); -} - -/** - * Bind a selection-neutral Apple carrier to the public Oliphaunt release - * namespace and, when supplied, the exact native version selected by the - * release graph. This contract is shared by SwiftPM source tags and the - * carrier embedded in the React Native npm package. - */ -export function validateSelectionNeutralSwiftCarrierIdentity({ - carrier, - expectedNativeVersion, - repository = CANONICAL_REPOSITORY, - label = "selection-neutral Apple carrier", -}) { - if (repository !== CANONICAL_REPOSITORY) { - throw error(`${label}.repository`, `must be ${CANONICAL_REPOSITORY}`); - } - const validated = validateSelectionNeutralSwiftSourceCarrier( - carrier, - `${label}.carrier`, - ); - if ( - expectedNativeVersion !== undefined - && validated.base.version !== expectedNativeVersion - ) { - throw error( - `${label}.carrier.base.version`, - `must match liboliphaunt-native ${expectedNativeVersion}`, - ); - } - for (const asset of validated.base.assets) { - const expectedUrl = `${repository}/releases/download/${validated.base.tag}/${asset.name}`; - if (asset.url !== expectedUrl) { - throw error(`${label}.carrier.base.assets.${asset.role}.url`, `must be ${expectedUrl}`); - } - } - return validated; -} - -export function validateSwiftSourceReleaseContract({ - carrier, - manifestText, - expectedNativeVersion, - repository = CANONICAL_REPOSITORY, - label = "oliphaunt-swift source release", -}) { - const validated = validateSelectionNeutralSwiftCarrierIdentity({ - carrier, - expectedNativeVersion, - repository, - label, - }); - const binaryTarget = parseSwiftReleaseBinaryTarget( - manifestText, - `${label} Package.swift.release`, - ); - const xcframework = validated.base.assets.find(({ role }) => role === "base-xcframework"); - if (binaryTarget.url !== xcframework.url) { - throw error( - `${label} Package.swift.release binary target URL`, - `must match ${xcframework.url}`, - ); - } - if (binaryTarget.checksum !== xcframework.sha256) { - throw error( - `${label} Package.swift.release binary target checksum`, - `must match carrier SHA-256 ${xcframework.sha256}`, - ); - } - return { binaryTarget, carrier: validated }; -} diff --git a/tools/release/sync-release-pr.mjs b/tools/release/sync-release-pr.mjs deleted file mode 100644 index 19c984cdf..000000000 --- a/tools/release/sync-release-pr.mjs +++ /dev/null @@ -1,1260 +0,0 @@ -#!/usr/bin/env bun -import { - existsSync, - readFileSync, - realpathSync, - statSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; - -import { - ROOT, - compareText, - currentProductVersion, - exactExtensionReleaseProducts, - extensionRegistryPackageTargetSets, - nativeToolsOptionalPackageProducts, - typescriptOptionalRuntimePackageProducts, -} from "./release-artifact-targets.mjs"; -import { compatibilityVersionEntries, loadGraph } from "./release-graph.mjs"; -import { - compatibilityEntriesForBumpedProducts, - releasePleaseWorktreeTransitions, - sharedContribReleaseCandidates, -} from "./release-please-transition.mjs"; -import { extensionRegistryPackageStrings } from "./extension-registry-packages.mjs"; -import { - EXAMPLE_CARGO_POLICIES, - exampleCargoReleaseVersionBindings, -} from "./example-cargo-policy.mjs"; -import { - synchronizeReleaseCandidates, -} from "./release-candidate-sync.mjs"; -import { releasePleaseConfigAfterBootstrapConsumption } from "./release-please-bootstrap.mjs"; -import { electronReleaseDependencies } from "../../examples/tools/example-release-dependencies.mjs"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; - -const PREFIX = "sync-release-pr.mjs"; -const DEPENDENCY_TABLES = ["dependencies", "dev-dependencies", "build-dependencies"]; -const LOCKFILES = [ - path.join(ROOT, "Cargo.lock"), -]; -const PNPM_LOCKFILE = path.join(ROOT, "pnpm-lock.yaml"); -const RELEASE_PLEASE_CONFIG = path.join(ROOT, "release-please-config.json"); -const RELEASE_PLEASE_MANIFEST = path.join(ROOT, ".release-please-manifest.json"); -const ELECTRON_EXAMPLE_PACKAGE = path.join(ROOT, "examples/electron/package.json"); -const NATIVE_TOOLS_FACADE_PACKAGE = path.join( - ROOT, - "src/runtimes/liboliphaunt/native/tools-npm/package.json", -); -const WASIX_TOOLS_FACADE_PACKAGE = path.join( - ROOT, - "src/bindings/wasix-ts/tools-package/package.json", -); -const WASIX_TOOLS_CARRIER_PACKAGE = "@oliphaunt/liboliphaunt-wasix-tools"; -const WASIX_TYPESCRIPT_BINDING_PACKAGE = "@oliphaunt/wasix-ts"; -const PACKAGE_START_RE = /^\s*\[\[package\]\]\s*$/u; -const STRING_KEY_RE = /^\s*([A-Za-z0-9_-]+)\s*=\s*"([^"]*)"\s*(?:#.*)?$/u; -const VERSION_LINE_RE = /^(\s*version\s*=\s*)"[^"]*"(\s*(?:#.*)?)$/u; -const TOML_TABLE_RE = /^\s*\[([A-Za-z0-9_.-]+)\]\s*(?:#.*)?$/u; -const PNPM_TYPESCRIPT_OPTIONAL_RUNTIME_KEY_RE = - /^(\s*)'(@oliphaunt\/(?:(?:broker|liboliphaunt|node-direct|tools)-[^']+|wasix-ts))':\s*$/u; -const PNPM_SPECIFIER_RE = /^(\s*specifier:\s*)(\S+)(\s*)$/u; -const EXTENSION_EVIDENCE_SUMMARY_PATH = path.join( - ROOT, - "src/extensions/generated/docs/extension-evidence.json", -); -const EXTENSION_MODEL_CHECK_PATH = "src/extensions/tools/check-extension-model.mjs"; -export const SDK_INSTALL_VERSION_RULES = Object.freeze([ - { - product: "oliphaunt-swift", - file: "src/docs/content/sdk/swift/index.mdx", - prefix: '.package(url: "https://github.com/f0rr0/oliphaunt.git", from: "', - suffix: '")', - }, - { - product: "oliphaunt-swift", - file: "src/docs/content/sdk/swift/guide.mdx", - prefix: '.package(url: "https://github.com/f0rr0/oliphaunt.git", from: "', - suffix: '")', - }, - { - product: "oliphaunt-swift", - file: "src/sdks/swift/README.md", - prefix: '.package(url: "https://github.com/f0rr0/oliphaunt.git", exact: "', - suffix: '")', - }, - ...[ - "src/docs/content/sdk/kotlin/index.mdx", - "src/docs/content/sdk/kotlin/guide.mdx", - "src/sdks/kotlin/README.md", - ].map((file) => ({ - product: "oliphaunt-kotlin", - file, - prefix: 'implementation("dev.oliphaunt:oliphaunt-android:', - suffix: '")', - })), -]); - -function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(2); -} - -function rel(file) { - const relative = path.relative(ROOT, file); - if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { - return file.split(path.sep).join("/"); - } - return relative.split(path.sep).join("/"); -} - -function readText(file) { - return readFileSync(file, "utf8"); -} - -function readOptionalText(file) { - return existsSync(file) ? readText(file) : undefined; -} - -function readJsonObject(file) { - const value = JSON.parse(readText(file)); - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(`${rel(file)} must contain a JSON object`); - } - return value; -} - -function jsonText(value) { - return `${JSON.stringify(value, null, 2)}\n`; -} - -function writeTextIfChanged(file, text, changes, detail, { write }) { - const before = readText(file); - if (before === text) { - return; - } - changes.push({ path: file, detail }); - if (write) { - writeFileSync(file, text, "utf8"); - } -} - -function stripNewline(line) { - if (line.endsWith("\r\n")) { - return [line.slice(0, -2), "\r\n"]; - } - if (line.endsWith("\n")) { - return [line.slice(0, -1), "\n"]; - } - return [line, ""]; -} - -function graphProducts() { - return loadGraph(PREFIX).products; -} - -function productConfig(product) { - const products = graphProducts(); - const config = products[product]; - if (!config) { - fail(`unknown release product ${JSON.stringify(product)}`); - } - return config; -} - -function packagePath(product) { - return productConfig(product).path; -} - -function compatibilityVersionLinks() { - return compatibilityVersionEntries(graphProducts(), { requireSourceProduct: true, prefix: PREFIX }); -} - -function setJsonPath(data, dotted, expected, context) { - let current = data; - const parts = dotted.split("."); - for (const part of parts.slice(0, -1)) { - if (current === null || Array.isArray(current) || typeof current !== "object" || current[part] === null || Array.isArray(current[part]) || typeof current[part] !== "object") { - fail(`${context} is missing object path ${parts.slice(0, -1).join(".")}`); - } - current = current[part]; - } - if (current === null || Array.isArray(current) || typeof current !== "object") { - fail(`${context} is missing object path ${parts.slice(0, -1).join(".")}`); - } - const key = parts.at(-1); - const actual = current[key]; - if (actual === expected) { - return undefined; - } - current[key] = expected; - return `${context} ${JSON.stringify(actual)} -> ${JSON.stringify(expected)}`; -} - -function setTomlStringPath(file, dotted, expected, context) { - const parts = dotted.split("."); - if (parts.length < 2) { - fail(`${context} TOML parser must use table.key dotted syntax`); - } - const table = parts.slice(0, -1); - const key = parts.at(-1); - const lines = readText(file).split(/(?<=\n)/u); - let currentTable = []; - let sawTable = false; - const keyPattern = new RegExp(`^(\\s*${escapeRegExp(key)}\\s*=\\s*)"([^"]*)"(.*)$`, "u"); - - for (const [index, line] of lines.entries()) { - const [body, newline] = stripNewline(line); - const tableMatch = TOML_TABLE_RE.exec(body); - if (tableMatch) { - currentTable = tableMatch[1].split("."); - sawTable = arraysEqual(currentTable, table); - continue; - } - if (!arraysEqual(currentTable, table)) { - continue; - } - const keyMatch = keyPattern.exec(body); - if (!keyMatch) { - continue; - } - const actual = keyMatch[2]; - if (actual === expected) { - return [undefined, undefined]; - } - lines[index] = `${keyMatch[1]}"${expected}"${keyMatch[3]}${newline}`; - return [lines.join(""), `${context} ${JSON.stringify(actual)} -> ${JSON.stringify(expected)}`]; - } - - if (sawTable) { - fail(`${context} did not find TOML key ${JSON.stringify(key)} in ${rel(file)}`); - } - fail(`${context} did not find TOML table ${JSON.stringify(table.join("."))} in ${rel(file)}`); -} - -function setRustConstString(file, constName, expected, context) { - const lines = readText(file).split(/(?<=\n)/u); - const pattern = new RegExp(`^(\\s*(?:pub\\s+)?const\\s+${escapeRegExp(constName)}\\s*:\\s*&str\\s*=\\s*)"([^"]*)"(;.*)$`, "u"); - for (const [index, line] of lines.entries()) { - const [body, newline] = stripNewline(line); - const match = pattern.exec(body); - if (!match) { - continue; - } - const actual = match[2]; - if (actual === expected) { - return [undefined, undefined]; - } - lines[index] = `${match[1]}"${expected}"${match[3]}${newline}`; - return [lines.join(""), `${context} ${JSON.stringify(actual)} -> ${JSON.stringify(expected)}`]; - } - fail(`${context} did not find Rust const ${JSON.stringify(constName)} in ${rel(file)}`); -} - -function tomlArrayAssignment(key, values) { - if (values.length === 1) { - return `${key} = [${JSON.stringify(values[0])}]\n`; - } - return `${key} = [\n${values.map((value) => ` ${JSON.stringify(value)},\n`).join("")}]\n`; -} - -function replaceTopLevelArrayAssignment(text, key, values, context) { - const lines = text.split(/(?<=\n)/u); - const output = []; - let index = 0; - let replaced = false; - const pattern = new RegExp(`^${escapeRegExp(key)}\\s*=\\s*\\[`, "u"); - while (index < lines.length) { - const line = lines[index]; - if (!replaced && pattern.test(line)) { - output.push(tomlArrayAssignment(key, values)); - replaced = true; - if (!line.includes("]")) { - index += 1; - while (index < lines.length && !lines[index].includes("]")) { - index += 1; - } - } - index += 1; - continue; - } - output.push(line); - index += 1; - } - if (!replaced) { - fail(`${context} did not find top-level TOML array ${JSON.stringify(key)}`); - } - return output.join(""); -} - -function syncExtensionRegistryMetadata(changes, { write }) { - const expectedPublishTargets = ["github-release-assets", "npm", "maven-central", "crates-io"]; - for (const product of exactExtensionReleaseProducts(PREFIX)) { - const releaseToml = path.join(ROOT, packagePath(product), "release.toml"); - const expectedRegistryPackages = extensionRegistryPackageStrings({ - product, - ...extensionRegistryPackageTargetSets(product, PREFIX), - }); - const text = readText(releaseToml); - let updated = replaceTopLevelArrayAssignment(text, "publish_targets", expectedPublishTargets, product); - updated = replaceTopLevelArrayAssignment(updated, "registry_packages", expectedRegistryPackages, product); - if (updated !== text) { - writeTextIfChanged(releaseToml, updated, changes, "synced explicit extension registry metadata", { write }); - } - } -} - -function syncReleasePleaseBootstrapBoundary(changes, { write }) { - const config = readJsonObject(RELEASE_PLEASE_CONFIG); - const manifest = readJsonObject(RELEASE_PLEASE_MANIFEST); - const updated = releasePleaseConfigAfterBootstrapConsumption(config, manifest); - if (updated !== config) { - writeTextIfChanged( - RELEASE_PLEASE_CONFIG, - jsonText(updated), - changes, - "removed the consumed one-time bootstrap-sha history boundary", - { write }, - ); - } -} - -async function syncCompatibilityVersions(changes, { write, transitions }) { - const links = compatibilityEntriesForBumpedProducts(compatibilityVersionLinks(), transitions); - for (const { id: specId, sourceProduct, path: pathText, parser } of links) { - const file = path.join(ROOT, pathText); - const expected = await currentProductVersion(sourceProduct, PREFIX); - if (parser === "raw") { - writeTextIfChanged(file, `${expected}\n`, changes, `${specId} -> ${sourceProduct} ${expected}`, { write }); - continue; - } - if (parser.startsWith("json:")) { - const data = readJsonObject(file); - const detail = setJsonPath(data, parser.split(":", 2)[1], expected, specId); - if (detail !== undefined) { - writeTextIfChanged(file, jsonText(data), changes, detail, { write }); - } - continue; - } - if (parser.startsWith("toml:")) { - const [text, detail] = setTomlStringPath(file, parser.split(":", 2)[1], expected, specId); - if (text !== undefined && detail !== undefined) { - writeTextIfChanged(file, text, changes, detail, { write }); - } - continue; - } - if (parser.startsWith("rust-const:")) { - const [text, detail] = setRustConstString(file, parser.split(":", 2)[1], expected, specId); - if (text !== undefined && detail !== undefined) { - writeTextIfChanged(file, text, changes, detail, { write }); - } - continue; - } - fail(`${specId} uses unsupported sync parser ${JSON.stringify(parser)}`); - } -} - -async function expectedNativeToolsOptionalVersions() { - const versions = {}; - for (const { packageName, product } of nativeToolsOptionalPackageProducts(PREFIX)) { - versions[packageName] = `workspace:${await currentProductVersion(product, PREFIX)}`; - } - return versions; -} - -function typescriptOptionalRuntimePackages() { - return typescriptOptionalRuntimePackageProducts(PREFIX).map(({ packageName }) => packageName); -} - -function typescriptOptionalRuntimeVersionsFromPackage() { - return optionalRuntimeVersionsFromPackage( - path.join(ROOT, "src/sdks/js/package.json"), - typescriptOptionalRuntimePackages(), - ); -} - -function nativeToolsOptionalVersionsFromPackage() { - return optionalRuntimeVersionsFromPackage( - NATIVE_TOOLS_FACADE_PACKAGE, - nativeToolsOptionalPackageProducts(PREFIX).map(({ packageName }) => packageName), - ); -} - -function wasixToolsDependencyVersionsFromPackage() { - const data = readJsonObject(WASIX_TOOLS_FACADE_PACKAGE); - const dependencies = data.dependencies; - const peerDependencies = data.peerDependencies; - const devDependencies = data.devDependencies; - if ( - dependencies === null || - Array.isArray(dependencies) || - typeof dependencies !== "object" || - !setsEqual(new Set(Object.keys(dependencies)), new Set([WASIX_TOOLS_CARRIER_PACKAGE])) || - peerDependencies === null || - Array.isArray(peerDependencies) || - typeof peerDependencies !== "object" || - !setsEqual(new Set(Object.keys(peerDependencies)), new Set([WASIX_TYPESCRIPT_BINDING_PACKAGE])) || - devDependencies === null || - Array.isArray(devDependencies) || - typeof devDependencies !== "object" || - dependencies[WASIX_TOOLS_CARRIER_PACKAGE] !== "workspace:*" || - peerDependencies[WASIX_TYPESCRIPT_BINDING_PACKAGE] !== "workspace:*" || - devDependencies[WASIX_TYPESCRIPT_BINDING_PACKAGE] !== "workspace:*" - ) { - fail( - `${rel(WASIX_TOOLS_FACADE_PACKAGE)} must depend only on ${WASIX_TOOLS_CARRIER_PACKAGE}, peer only with ${WASIX_TYPESCRIPT_BINDING_PACKAGE}, and develop against that peer version`, - ); - } - return { - [WASIX_TOOLS_CARRIER_PACKAGE]: dependencies[WASIX_TOOLS_CARRIER_PACKAGE], - [WASIX_TYPESCRIPT_BINDING_PACKAGE]: peerDependencies[WASIX_TYPESCRIPT_BINDING_PACKAGE], - }; -} - -function optionalRuntimeVersionsFromPackage(file, expectedPackages) { - const data = readJsonObject(file); - const optional = data.optionalDependencies; - if (optional === null || Array.isArray(optional) || typeof optional !== "object") { - fail(`${rel(file)} must declare optionalDependencies`); - } - const expectedKeys = new Set(expectedPackages); - const actualKeys = new Set(Object.keys(optional)); - if (!setsEqual(actualKeys, expectedKeys)) { - fail(`${rel(file)} optionalDependencies must be exactly ${expectedPackages.join(", ")}`); - } - return Object.fromEntries(expectedPackages.map((packageName) => [packageName, optional[packageName]])); -} - -async function syncNativeToolsOptionalDependencies(changes, { write, transitions }) { - return syncOptionalRuntimeDependencies(changes, { - write, - transitions, - ownerProduct: "liboliphaunt-native", - packageFile: NATIVE_TOOLS_FACADE_PACKAGE, - runtimeVersions: await expectedNativeToolsOptionalVersions(), - }); -} - -async function syncOptionalRuntimeDependencies( - changes, - { write, transitions, ownerProduct, packageFile, runtimeVersions }, -) { - if (!transitions.some(({ product }) => product === ownerProduct)) { - return; - } - const file = packageFile; - const data = readJsonObject(file); - const optional = data.optionalDependencies; - const expectedVersions = runtimeVersions; - let changed = false; - const details = []; - for (const packageName of Object.keys(expectedVersions).sort(compareText)) { - const expectedVersion = expectedVersions[packageName]; - const actual = optional[packageName]; - if (actual !== expectedVersion) { - optional[packageName] = expectedVersion; - changed = true; - details.push(`${packageName} ${JSON.stringify(actual)} -> ${JSON.stringify(expectedVersion)}`); - } - } - if (changed) { - writeTextIfChanged(file, jsonText(data), changes, details.join("; "), { write }); - } -} - -function syncElectronExampleDependencies(changes, { write }) { - const data = readJsonObject(ELECTRON_EXAMPLE_PACKAGE); - const dependencies = data.dependencies; - if (dependencies === null || Array.isArray(dependencies) || typeof dependencies !== "object") { - fail(`${rel(ELECTRON_EXAMPLE_PACKAGE)} must declare dependencies`); - } - - let changed = false; - const details = []; - for (const { packageName, version } of electronReleaseDependencies(ROOT)) { - const actual = dependencies[packageName]; - if (actual === undefined) { - fail(`${rel(ELECTRON_EXAMPLE_PACKAGE)} is missing release dependency ${packageName}`); - } - if (actual !== version) { - dependencies[packageName] = version; - changed = true; - details.push(`${packageName} ${JSON.stringify(actual)} -> ${JSON.stringify(version)}`); - } - } - if (changed) { - writeTextIfChanged(ELECTRON_EXAMPLE_PACKAGE, jsonText(data), changes, details.join("; "), { write }); - } -} - -export function syncSdkInstallDocs(changes, { root = ROOT, write, transitions }) { - const transitionsByProduct = new Map(transitions.map((transition) => [transition.product, transition])); - for (const rule of SDK_INSTALL_VERSION_RULES) { - const transition = transitionsByProduct.get(rule.product); - if (transition === undefined) continue; - if (transition.before === null) fail(`${rule.product} install docs require a prior release version`); - const file = path.join(root, rule.file); - const before = `${rule.prefix}${transition.before}${rule.suffix}`; - const after = `${rule.prefix}${transition.after}${rule.suffix}`; - const text = readText(file); - const beforeCount = text.split(before).length - 1; - const afterCount = text.split(after).length - 1; - if (beforeCount === 0 && afterCount === 1) continue; - if (beforeCount !== 1 || afterCount !== 0) { - fail(`${rule.file} must contain exactly one ${rule.product} install contract for ${transition.before}`); - } - writeTextIfChanged( - file, - text.replace(before, after), - changes, - `${rule.product} install contract ${transition.before} -> ${transition.after}`, - { write }, - ); - } -} - -async function syncPnpmTypescriptOptionalRuntimeSpecifiers(changes, { write }) { - const expectedVersions = { - ...typescriptOptionalRuntimeVersionsFromPackage(), - ...nativeToolsOptionalVersionsFromPackage(), - ...wasixToolsDependencyVersionsFromPackage(), - }; - const lines = readText(PNPM_LOCKFILE).split(/(?<=\n)/u); - const expectedPackages = new Set(Object.keys(expectedVersions)); - const seen = new Set(); - const fileChanges = []; - - for (const [index, line] of lines.entries()) { - const [body] = stripNewline(line); - const packageMatch = PNPM_TYPESCRIPT_OPTIONAL_RUNTIME_KEY_RE.exec(body); - if (!packageMatch) { - continue; - } - const packageName = packageMatch[2]; - if (!expectedPackages.has(packageName)) { - fail(`${rel(PNPM_LOCKFILE)} contains unexpected managed TypeScript runtime dependency ${packageName}`); - } - seen.add(packageName); - const packageIndent = packageMatch[1].length; - const expectedVersion = expectedVersions[packageName]; - - let found = false; - for (let specifierIndex = index + 1; specifierIndex < lines.length; specifierIndex += 1) { - const [specifierBody, specifierNewline] = stripNewline(lines[specifierIndex]); - if (specifierBody.trim()) { - const specifierIndent = specifierBody.length - specifierBody.trimStart().length; - if (specifierIndent <= packageIndent) { - break; - } - } - const specifierMatch = PNPM_SPECIFIER_RE.exec(specifierBody); - if (!specifierMatch) { - continue; - } - found = true; - const actual = specifierMatch[2]; - if (actual !== expectedVersion) { - lines[specifierIndex] = `${specifierMatch[1]}${expectedVersion}${specifierMatch[3]}${specifierNewline}`; - fileChanges.push(`${packageName} ${JSON.stringify(actual)} -> ${JSON.stringify(expectedVersion)}`); - } - break; - } - if (!found) { - fail(`${rel(PNPM_LOCKFILE)} is missing a specifier for ${packageName}`); - } - } - - const missing = [...expectedPackages].filter((name) => !seen.has(name)).sort(compareText); - if (missing.length > 0) { - fail(`${rel(PNPM_LOCKFILE)} is missing managed TypeScript runtime dependency specifiers: ${missing.join(", ")}`); - } - if (fileChanges.length > 0) { - writeTextIfChanged(PNPM_LOCKFILE, lines.join(""), changes, fileChanges.join("; "), { write }); - } -} - -export function cargoManifestPaths({ - gitCommand = "git", - gitCommandArgs = [], - root = ROOT, -} = {}) { - const result = captureCommandOutput( - gitCommand, - [...gitCommandArgs, "ls-files", "-z", "--", "Cargo.toml", ":(glob)**/Cargo.toml"], - { - cwd: root, - label: "git ls-files Cargo manifests", - stdoutTerminator: "\0", - }, - ); - if (result.status !== 0 || result.error !== undefined) { - fail(`could not enumerate tracked Cargo manifests: ${commandOutputForError(result)}`); - } - if (result.stdout.length === 0) { - fail("could not enumerate tracked Cargo manifests: git returned an empty inventory"); - } - return result.stdout - .split("\0") - .filter(Boolean) - .map((file) => path.join(root, file)) - .filter((file) => existsSync(file)) - .sort(compareText); -} - -function localCargoPackagesByManifest() { - const packages = new Map(); - for (const manifest of cargoManifestPaths()) { - const data = Bun.TOML.parse(readText(manifest)); - const packageConfig = data.package; - if (packageConfig === null || Array.isArray(packageConfig) || typeof packageConfig !== "object") { - continue; - } - const name = packageConfig.name; - const version = packageConfig.version; - if (typeof name !== "string" || typeof version !== "string") { - continue; - } - packages.set(realpathSync(manifest), [name, version]); - } - return packages; -} - -function localCargoPackageVersions() { - const versions = new Map(); - for (const [manifest, [name, version]] of localCargoPackagesByManifest()) { - const existing = versions.get(name); - if (existing !== undefined && existing !== version) { - fail(`local Cargo package ${name} has conflicting versions including ${rel(manifest)}`); - } - versions.set(name, version); - } - return versions; -} - -function iterDependencyTables(manifest) { - const tables = []; - for (const tableName of DEPENDENCY_TABLES) { - const table = manifest[tableName]; - if (table !== null && !Array.isArray(table) && typeof table === "object") { - tables.push(table); - } - } - const targets = manifest.target; - if (targets !== null && !Array.isArray(targets) && typeof targets === "object") { - for (const target of Object.values(targets)) { - if (target === null || Array.isArray(target) || typeof target !== "object") { - continue; - } - for (const tableName of DEPENDENCY_TABLES) { - const table = target[tableName]; - if (table !== null && !Array.isArray(table) && typeof table === "object") { - tables.push(table); - } - } - } - } - return tables; -} - -export function desiredCargoPathDependencyVersion(current, packageVersion) { - if (current === "*") return current; - return current.startsWith("=") ? `=${packageVersion}` : packageVersion; -} - -function priorCargoPathDependencyVersions(manifestPath) { - const file = rel(manifestPath); - const result = captureCommandOutput("git", ["show", `HEAD^:${file}`], { - cwd: ROOT, - label: `git show HEAD^:${file}`, - }); - if (result.status !== 0 || result.error !== undefined) { - fail(`could not read prior Cargo manifest ${file}: ${commandOutputForError(result)}`); - } - const versions = new Map(); - for (const table of iterDependencyTables(Bun.TOML.parse(result.stdout))) { - for (const [name, dependency] of Object.entries(table)) { - if (dependency !== null && !Array.isArray(dependency) && typeof dependency === "object" && - typeof dependency.path === "string" && typeof dependency.version === "string") { - versions.set(name, dependency.version); - } - } - } - return versions; -} - -function desiredCargoPathDependencyVersions(manifestPath, localPackages, priorVersions) { - const manifest = Bun.TOML.parse(readText(manifestPath)); - const desired = new Map(); - for (const table of iterDependencyTables(manifest)) { - for (const [dependencyName, dependency] of Object.entries(table)) { - if (dependency === null || Array.isArray(dependency) || typeof dependency !== "object") { - continue; - } - const pathValue = dependency.path; - const versionValue = dependency.version; - if (typeof pathValue !== "string" || typeof versionValue !== "string") { - continue; - } - const dependencyManifest = path.resolve(path.dirname(manifestPath), pathValue, "Cargo.toml"); - const packageInfo = localPackages.get(realpathIfExists(dependencyManifest)); - if (packageInfo === undefined) { - continue; - } - const packageVersion = packageInfo[1]; - desired.set( - dependencyName, - desiredCargoPathDependencyVersion(priorVersions.get(dependencyName) ?? versionValue, packageVersion), - ); - } - } - return desired; -} - -function syncCargoPathDependencyPins(changes, { write, transitions }) { - const localPackages = localCargoPackagesByManifest(); - const selectedRoots = transitions - .map(({ product }) => path.join(ROOT, packagePath(product))) - .sort((left, right) => right.length - left.length || compareText(left, right)); - for (const manifestPath of cargoManifestPaths()) { - if (!selectedRoots.some((root) => manifestPath === root || manifestPath.startsWith(`${root}${path.sep}`))) { - continue; - } - const desired = desiredCargoPathDependencyVersions( - manifestPath, - localPackages, - priorCargoPathDependencyVersions(manifestPath), - ); - if (desired.size === 0) { - continue; - } - const lines = readText(manifestPath).split(/(?<=\n)/u); - const seen = new Set(); - const fileChanges = []; - for (const [index, line] of lines.entries()) { - const [body, newline] = stripNewline(line); - for (const [dependencyName, expected] of desired) { - const pattern = new RegExp(`^(\\s*${escapeRegExp(dependencyName)}\\s*=\\s*\\{[^}]*\\bversion\\s*=\\s*")([^"]+)(".*)$`, "u"); - const match = pattern.exec(body); - if (!match) { - continue; - } - seen.add(dependencyName); - const actual = match[2]; - if (actual !== expected) { - lines[index] = `${match[1]}${expected}${match[3]}${newline}`; - fileChanges.push(`${dependencyName} ${JSON.stringify(actual)} -> ${JSON.stringify(expected)}`); - } - } - } - const missing = [...desired.keys()].filter((name) => !seen.has(name)).sort(compareText); - if (missing.length > 0) { - fail(`${rel(manifestPath)} has non-inline local path dependency pins: ${missing.join(", ")}`); - } - if (fileChanges.length > 0) { - writeTextIfChanged(manifestPath, lines.join(""), changes, fileChanges.join("; "), { write }); - } - } -} - -function valueAt(root, parts) { - let current = root; - for (const part of parts) { - if (current === null || typeof current !== "object") return undefined; - current = current[part]; - } - return current; -} - -function tomlAssignmentMatchesAtPath(text, entryParts) { - const tableParts = entryParts.slice(0, -1); - const key = entryParts.at(-1); - const marker = "__oliphaunt_release_sync_table__"; - const keyPattern = new RegExp( - `^(\\s*(?:${escapeRegExp(key)}|"${escapeRegExp(key)}"|'${escapeRegExp(key)}')\\s*=\\s*)`, - "u", - ); - const matches = []; - let offset = 0; - let inTable = false; - - for (const line of text.split(/(?<=\n)/u)) { - const [body] = stripNewline(line); - const tableMatch = /^\s*\[([^\[\]]+)\]\s*(?:#.*)?$/u.exec(body); - if (tableMatch !== null) { - const parsed = Bun.TOML.parse(`[${tableMatch[1]}]\n${marker} = true\n`); - inTable = valueAt(parsed, [...tableParts, marker]) === true; - offset += line.length; - continue; - } - if (inTable) { - const assignment = keyPattern.exec(body); - if (assignment !== null) { - matches.push({ - assignmentStart: offset + assignment.index, - valueStart: offset + assignment.index + assignment[0].length, - }); - } - } - offset += line.length; - } - return matches; -} - -function quotedTomlStringEnd(text, start) { - const quote = text[start]; - let escaped = false; - for (let index = start + 1; index < text.length; index += 1) { - const character = text[index]; - if (quote === '"' && character === "\\" && !escaped) { - escaped = true; - continue; - } - if (character === quote && !escaped) return index; - escaped = false; - } - return -1; -} - -function inlineTomlTableEnd(text, start) { - let depth = 0; - let quote; - let escaped = false; - for (let index = start; index < text.length; index += 1) { - const character = text[index]; - if (quote !== undefined) { - if (quote === '"' && character === "\\" && !escaped) { - escaped = true; - continue; - } - if (character === quote && !escaped) quote = undefined; - escaped = false; - continue; - } - if (character === '"' || character === "'") { - quote = character; - } else if (character === "{") { - depth += 1; - } else if (character === "}") { - depth -= 1; - if (depth === 0) return index + 1; - } - } - return -1; -} - -function replaceUniqueDependencyVersion(text, binding, label) { - const matches = tomlAssignmentMatchesAtPath(text, binding.entryParts); - if (matches.length !== 1) { - throw new Error( - `${label} must declare ${binding.entryParts.join(".")} exactly once as a direct TOML assignment, found ${matches.length}`, - ); - } - const { valueStart } = matches[0]; - const first = text[valueStart]; - if (first === '"' || first === "'") { - const end = quotedTomlStringEnd(text, valueStart); - if (end === -1) throw new Error(`${label} has an unterminated version string for ${binding.name}`); - const actual = text.slice(valueStart + 1, end); - return { - text: actual === binding.expected - ? text - : `${text.slice(0, valueStart + 1)}${binding.expected}${text.slice(end)}`, - detail: actual === binding.expected - ? undefined - : `${binding.name} ${JSON.stringify(actual)} -> ${JSON.stringify(binding.expected)}`, - }; - } - if (first !== "{") { - throw new Error(`${label} ${binding.name} must use a string or inline-table dependency specification`); - } - const end = inlineTomlTableEnd(text, valueStart); - if (end === -1) throw new Error(`${label} has an unterminated inline table for ${binding.name}`); - const table = text.slice(valueStart, end); - const versionPattern = /(\bversion\s*=\s*)(?:"([^"]*)"|'([^']*)')/gu; - const versions = [...table.matchAll(versionPattern)]; - if (versions.length !== 1) { - throw new Error(`${label} ${binding.name} inline table must declare version exactly once, found ${versions.length}`); - } - const match = versions[0]; - const actual = match[2] ?? match[3]; - if (actual === binding.expected) return { text, detail: undefined }; - const quote = match[2] === undefined ? "'" : '"'; - const replacement = `${match[1]}${quote}${binding.expected}${quote}`; - const versionStart = valueStart + match.index; - return { - text: `${text.slice(0, versionStart)}${replacement}${text.slice(versionStart + match[0].length)}`, - detail: `${binding.name} ${JSON.stringify(actual)} -> ${JSON.stringify(binding.expected)}`, - }; -} - -function replaceUniqueStringAssignment(text, binding, label) { - const matches = tomlAssignmentMatchesAtPath(text, binding.entryParts); - if (matches.length !== 1) { - throw new Error(`${label} must declare ${binding.entryParts.join(".")} exactly once, found ${matches.length}`); - } - const { valueStart } = matches[0]; - const quote = text[valueStart]; - if (quote !== '"' && quote !== "'") { - throw new Error(`${label} ${binding.name} must be a TOML string`); - } - const end = quotedTomlStringEnd(text, valueStart); - if (end === -1) throw new Error(`${label} has an unterminated string for ${binding.name}`); - const actual = text.slice(valueStart + 1, end); - return { - text: actual === binding.expected - ? text - : `${text.slice(0, valueStart + 1)}${binding.expected}${text.slice(end)}`, - detail: actual === binding.expected - ? undefined - : `${binding.name} ${JSON.stringify(actual)} -> ${JSON.stringify(binding.expected)}`, - }; -} - -export function syncExampleCargoManifestText(text, { policy, bindings, label = `${policy.crateDir}/Cargo.toml` }) { - const manifest = Bun.TOML.parse(text); - const details = []; - let updated = text; - for (const binding of bindings) { - if (valueAt(manifest, binding.entryParts) === undefined) { - throw new Error(`${label} is missing release-bound TOML path ${binding.entryParts.join(".")}`); - } - const result = binding.kind === "dependency" - ? replaceUniqueDependencyVersion(updated, binding, label) - : replaceUniqueStringAssignment(updated, binding, label); - updated = result.text; - if (result.detail !== undefined) details.push(result.detail); - } - if (policy.runtime !== undefined) { - const actualProduct = valueAt(manifest, policy.runtime.productParts); - if (actualProduct !== policy.runtime.product) { - throw new Error( - `${label} runtime uses ${JSON.stringify(actualProduct)}; expected ${policy.runtime.product}`, - ); - } - } - return { text: updated, details }; -} - -function syncExampleCargoRegistryPins(changes, { write }) { - const bindings = exampleCargoReleaseVersionBindings(); - for (const policy of EXAMPLE_CARGO_POLICIES) { - const file = path.join(ROOT, policy.crateDir, "Cargo.toml"); - let result; - try { - result = syncExampleCargoManifestText(readText(file), { - policy, - bindings: bindings.filter(({ policyId }) => policyId === policy.id), - label: rel(file), - }); - } catch (cause) { - fail(cause.message); - } - if (result.details.length > 0) { - writeTextIfChanged(file, result.text, changes, result.details.join("; "), { write }); - } - } -} - -function stringKey(line, key) { - const [body] = stripNewline(line); - const match = STRING_KEY_RE.exec(body); - return match?.[1] === key ? match[2] : undefined; -} - -function packageBlockRanges(lines) { - const starts = lines.flatMap((line, index) => (PACKAGE_START_RE.test(line) ? [index] : [])); - return starts.map((start, index) => [start, index + 1 < starts.length ? starts[index + 1] : lines.length]); -} - -function replaceVersionLine(line, version) { - const [body, newline] = stripNewline(line); - const match = VERSION_LINE_RE.exec(body); - if (!match) { - fail(`cannot update Cargo.lock version line: ${line.trimEnd()}`); - } - return `${match[1]}"${version}"${match[2]}${newline}`; -} - -export function syncLockfile(lockfile, versions, changes, { write }) { - const data = Bun.TOML.parse(readText(lockfile)); - if (!Array.isArray(data.package)) { - fail(`${rel(lockfile)} is missing [[package]] entries`); - } - const lines = readText(lockfile).split(/(?<=\n)/u); - const fileChanges = []; - for (const [start, end] of packageBlockRanges(lines)) { - const block = lines.slice(start, end); - let name; - let versionIndex; - let currentVersion; - let hasSource = false; - for (const [offset, line] of block.entries()) { - if (stringKey(line, "source") !== undefined) { - hasSource = true; - } - const keyName = stringKey(line, "name"); - if (keyName !== undefined) { - name = keyName; - } - const keyVersion = stringKey(line, "version"); - if (keyVersion !== undefined) { - versionIndex = start + offset; - currentVersion = keyVersion; - } - } - if (!versions.has(name) || hasSource) { - continue; - } - if (versionIndex === undefined || currentVersion === undefined) { - fail(`${rel(lockfile)} package ${name} is missing version`); - } - const expectedVersion = versions.get(name); - if (currentVersion !== expectedVersion) { - lines[versionIndex] = replaceVersionLine(lines[versionIndex], expectedVersion); - fileChanges.push(`${name} ${currentVersion} -> ${expectedVersion}`); - } - } - if (fileChanges.length > 0) { - writeTextIfChanged(lockfile, lines.join(""), changes, fileChanges.join("; "), { write }); - } -} - -function syncLockfiles(changes, { write }) { - const versions = localCargoPackageVersions(); - for (const lockfile of LOCKFILES) { - syncLockfile(lockfile, versions, changes, { write }); - } -} - -function commandOutputForError(result) { - const parts = [result.error?.message, result.stdout, result.stderr] - .map((value) => String(value ?? "").trim()) - .filter(Boolean); - return parts.join("\n") || `exit ${result.status}`; -} - -export function extensionEvidenceSummaryCommand({ write }) { - return [ - process.execPath, - EXTENSION_MODEL_CHECK_PATH, - write ? "--write-evidence-summary" : "--check", - ]; -} - -function evidenceSummarySourceDigest(text) { - if (text === undefined) { - return ""; - } - try { - const parsed = JSON.parse(text); - return typeof parsed?.["source-digest"] === "string" - ? parsed["source-digest"] - : ""; - } catch { - return ""; - } -} - -function syncExtensionEvidenceSummary(changes, { write }) { - const command = extensionEvidenceSummaryCommand({ write }); - const before = readOptionalText(EXTENSION_EVIDENCE_SUMMARY_PATH); - const result = captureCommandOutput(command[0], command.slice(1), { - cwd: ROOT, - label: command.join(" "), - }); - const output = commandOutputForError(result); - if (result.status !== 0) { - const operation = write - ? "refreshing the deterministic extension evidence summary" - : "validating the extension model and deterministic evidence summary"; - fail( - `failed while ${operation}; summary regeneration reads but never rewrites the claim matrix ` + - `or immutable observed evidence runs:\n${output}`, - ); - } - if (!write) { - return; - } - const after = readOptionalText(EXTENSION_EVIDENCE_SUMMARY_PATH); - if (after === undefined) { - fail( - `${EXTENSION_MODEL_CHECK_PATH} --write-evidence-summary succeeded without creating ` + - rel(EXTENSION_EVIDENCE_SUMMARY_PATH), - ); - } - if (before !== after) { - changes.push({ - path: EXTENSION_EVIDENCE_SUMMARY_PATH, - detail: - `deterministic source digest ${evidenceSummarySourceDigest(before)} -> ` + - evidenceSummarySourceDigest(after), - }); - } -} - -function parseArgs(argv) { - const args = { - bootstrapSharedContrib: false, - check: false, - generatedReleaseCheck: false, - normalCheck: false, - sharedContribStatus: false, - }; - for (const arg of argv) { - if (arg === "--check") { - if (args.generatedReleaseCheck) { - fail("--check and --check-generated-release are mutually exclusive"); - } - args.check = true; - args.normalCheck = true; - } else if (arg === "--check-generated-release") { - if (args.check) { - fail("--check and --check-generated-release are mutually exclusive"); - } - args.check = true; - args.generatedReleaseCheck = true; - } else if (arg === "--bootstrap-shared-contrib") { - args.bootstrapSharedContrib = true; - } else if (arg === "--shared-contrib-status") { - args.check = true; - args.sharedContribStatus = true; - } else if (arg === "--help" || arg === "-h") { - console.log( - "usage: tools/release/sync-release-pr.mjs " + - "[--check|--check-generated-release|--bootstrap-shared-contrib|--shared-contrib-status]", - ); - process.exit(0); - } else { - fail(`unknown argument ${arg}`); - } - } - const modes = [ - args.generatedReleaseCheck, - args.bootstrapSharedContrib, - args.sharedContribStatus, - args.normalCheck, - ].filter(Boolean); - if (modes.length > 1) fail("release sync modes are mutually exclusive"); - return args; -} - -export function sharedContribBootstrapRequired(transitions, discoverCandidates) { - if (transitions.length > 0) return false; - return discoverCandidates().length > 0; -} - -async function main(argv) { - const args = parseArgs(argv); - const changes = []; - const write = !args.check; - let transitions = releasePleaseWorktreeTransitions(ROOT, { prefix: PREFIX }); - let graph = loadGraph(PREFIX); - if (args.bootstrapSharedContrib && transitions.length > 0) { - fail("--bootstrap-shared-contrib requires main release state with no existing manifest transition"); - } - if (args.sharedContribStatus) { - const required = sharedContribBootstrapRequired( - transitions, - () => sharedContribReleaseCandidates(ROOT, graph, [], { - headRef: "HEAD", - prefix: PREFIX, - }), - ); - console.log(`required=${String(required)}`); - return; - } - const bridgeSharedContrib = transitions.length > 0 - || args.bootstrapSharedContrib; - const sharedContribCandidates = bridgeSharedContrib - ? sharedContribReleaseCandidates(ROOT, graph, transitions, { - headRef: transitions.length > 0 ? "HEAD^" : "HEAD", - prefix: PREFIX, - }) - : []; - if (args.bootstrapSharedContrib && sharedContribCandidates.length === 0) { - fail("--bootstrap-shared-contrib found no unreleased shared contrib source change"); - } - if (sharedContribCandidates.length > 0) { - changes.push(...synchronizeReleaseCandidates({ - root: ROOT, - graph, - candidates: sharedContribCandidates, - releasePleaseConfig: readJsonObject(RELEASE_PLEASE_CONFIG), - manifest: readJsonObject(RELEASE_PLEASE_MANIFEST), - write, - prefix: PREFIX, - })); - if (write) { - transitions = releasePleaseWorktreeTransitions(ROOT, { prefix: PREFIX }); - graph = loadGraph(PREFIX); - } - } - syncReleasePleaseBootstrapBoundary(changes, { write }); - await syncCompatibilityVersions(changes, { write, transitions }); - syncExtensionRegistryMetadata(changes, { write }); - await syncNativeToolsOptionalDependencies(changes, { write, transitions }); - syncElectronExampleDependencies(changes, { write }); - syncSdkInstallDocs(changes, { write, transitions }); - await syncPnpmTypescriptOptionalRuntimeSpecifiers(changes, { write }); - syncCargoPathDependencyPins(changes, { write, transitions }); - syncExampleCargoRegistryPins(changes, { write }); - syncLockfiles(changes, { write }); - if (!args.generatedReleaseCheck) { - syncExtensionEvidenceSummary(changes, { write }); - } - if (changes.length === 0) { - console.log("release PR derived files are in sync"); - return; - } - for (const change of changes) { - console.error(`${rel(change.path)}: ${change.detail}`); - } - if (args.check) { - console.error("release PR derived files are stale; run `tools/release/sync-release-pr.mjs`"); - process.exit(1); - } - console.log("updated release PR derived files"); -} - -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"); -} - -function arraysEqual(left, right) { - return left.length === right.length && left.every((value, index) => value === right[index]); -} - -function setsEqual(left, right) { - return left.size === right.size && [...left].every((value) => right.has(value)); -} - -function realpathIfExists(file) { - try { - return realpathSync(file); - } catch { - return file; - } -} - -export function releaseDerivedPathInventory() { - return [...new Set([ - ...LOCKFILES, - PNPM_LOCKFILE, - RELEASE_PLEASE_CONFIG, - ELECTRON_EXAMPLE_PACKAGE, - EXTENSION_EVIDENCE_SUMMARY_PATH, - NATIVE_TOOLS_FACADE_PACKAGE, - WASIX_TOOLS_FACADE_PACKAGE, - ...SDK_INSTALL_VERSION_RULES.map(({ file }) => path.join(ROOT, file)), - ...compatibilityVersionLinks().map(({ path: pathText }) => path.join(ROOT, pathText)), - ...exactExtensionReleaseProducts(PREFIX).map((product) => path.join(ROOT, packagePath(product), "release.toml")), - path.join(ROOT, "src/sdks/js/package.json"), - ...cargoManifestPaths(), - ].map(rel))].sort(compareText); -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/sync-release-pr.mts b/tools/release/sync-release-pr.mts new file mode 100644 index 000000000..eb993bfd8 --- /dev/null +++ b/tools/release/sync-release-pr.mts @@ -0,0 +1,982 @@ +#!/usr/bin/env bun +import { existsSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { electronReleaseDependencies } from '../../src/examples/tools/example-release-dependencies.mts'; +import { extensionRegistryPackageStrings } from '../../src/extensions/artifacts/packages/tools/extension-registry-packages.mts'; +import { currentEvidenceTable } from '../../src/extensions/tools/extension-evidence.mts'; +import { catalogPath, readJson } from '../../src/extensions/tools/extension-projections.mts'; +import { + compareText, + currentProductVersion, + exactExtensionReleaseProducts, + extensionRegistryPackageTargetSets, + nativeToolsOptionalPackageProducts, + ROOT, +} from './release-artifact-targets.mts'; +import { compatibilityVersionEntries, loadGraph, loadProducts } from './release-graph.mts'; +import { + exampleCargoPolicies, + exampleCargoReleaseVersionBindings, +} from './example-cargo-versions.mts'; +import { releasePleaseConfigAfterBootstrapConsumption } from './release-please-bootstrap.mts'; +import { + cargoManifestPaths, + compatibilityEntriesForBumpedProducts, + releasePleaseState, + releasePleaseWorktreeTransitions, +} from './release-please-transition.mts'; + +export { cargoManifestPaths } from './release-please-transition.mts'; + +const PREFIX = 'sync-release-pr.mts'; +const DEPENDENCY_TABLES = ['dependencies', 'dev-dependencies', 'build-dependencies']; +const LOCKFILES = [path.join(ROOT, 'Cargo.lock')]; +const BUN_LOCKFILE = path.join(ROOT, 'bun.lock'); +const RELEASE_PLEASE_CONFIG = path.join(ROOT, 'release-please-config.json'); +const RELEASE_PLEASE_MANIFEST = path.join(ROOT, '.release-please-manifest.json'); +const ELECTRON_EXAMPLE_PACKAGE = path.join(ROOT, 'src/examples/electron/package.json'); +const NATIVE_TOOLS_FACADE_PACKAGE = path.join(ROOT, 'src/postgres-tools/native/npm/package.json'); +const WASIX_TOOLS_FACADE_PACKAGE = path.join(ROOT, 'src/postgres-tools/wasix/ts/package.json'); +const PACKAGE_START_RE = /^\s*\[\[package\]\]\s*$/u; +const STRING_KEY_RE = /^\s*([A-Za-z0-9_-]+)\s*=\s*"([^"]*)"\s*(?:#.*)?$/u; +const VERSION_LINE_RE = /^(\s*version\s*=\s*)"[^"]*"(\s*(?:#.*)?)$/u; +const EXTENSION_EVIDENCE_SUMMARY_PATH = path.join( + ROOT, + 'src/extensions/generated/docs/extension-evidence.json', +); +export const SDK_INSTALL_VERSION_RULES = Object.freeze([ + { + product: 'oliphaunt-swift', + file: 'src/sdks/swift/README.md', + prefix: '.package(url: "https://github.com/f0rr0/oliphaunt.git", exact: "', + suffix: '")', + }, + ...['src/sdks/kotlin/README.md'].map((file) => ({ + product: 'oliphaunt-kotlin', + file, + prefix: 'implementation("dev.oliphaunt:oliphaunt-android:', + suffix: '")', + })), +]); + +function fail(message) { + console.error(`${PREFIX}: ${message}`); + process.exit(2); +} + +function rel(file) { + const relative = path.relative(ROOT, file); + if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) { + return file.split(path.sep).join('/'); + } + return relative.split(path.sep).join('/'); +} + +function readText(file) { + return readFileSync(file, 'utf8'); +} + +function readJsonObject(file) { + const value = JSON.parse(readText(file)); + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(`${rel(file)} must contain a JSON object`); + } + return value; +} + +function jsonText(value) { + return `${JSON.stringify(value, null, 2)}\n`; +} + +function writeTextIfChanged(file, text, changes, detail, { write }) { + const before = readText(file); + if (before === text) { + return; + } + changes.push({ path: file, detail }); + if (write) { + writeFileSync(file, text, 'utf8'); + } +} + +function stripNewline(line) { + if (line.endsWith('\r\n')) { + return [line.slice(0, -2), '\r\n']; + } + if (line.endsWith('\n')) { + return [line.slice(0, -1), '\n']; + } + return [line, '']; +} + +function graphProducts() { + return loadProducts(PREFIX); +} + +function productConfig(product) { + const products = graphProducts(); + const config = products[product]; + if (!config) { + fail(`unknown release product ${JSON.stringify(product)}`); + } + return config; +} + +function packagePath(product) { + return productConfig(product).path; +} + +function compatibilityVersionLinks() { + return compatibilityVersionEntries(graphProducts(), { + requireSourceProduct: true, + prefix: PREFIX, + }); +} + +function setJsonPath(data, dotted, expected, context) { + let current = data; + const parts = dotted.split('.'); + for (const part of parts.slice(0, -1)) { + if ( + current === null || + Array.isArray(current) || + typeof current !== 'object' || + current[part] === null || + Array.isArray(current[part]) || + typeof current[part] !== 'object' + ) { + fail(`${context} is missing object path ${parts.slice(0, -1).join('.')}`); + } + current = current[part]; + } + if (current === null || Array.isArray(current) || typeof current !== 'object') { + fail(`${context} is missing object path ${parts.slice(0, -1).join('.')}`); + } + const key = parts.at(-1); + const actual = current[key]; + if (actual === expected) { + return undefined; + } + current[key] = expected; + return `${context} ${JSON.stringify(actual)} -> ${JSON.stringify(expected)}`; +} + +export function syncTomlStringPath(text, dotted, expected, context) { + const entryParts = dotted.split('.'); + if (entryParts.at(-1) === 'version' && DEPENDENCY_TABLES.includes(entryParts.at(-3))) { + return replaceUniqueDependencyVersion( + text, + { entryParts: entryParts.slice(0, -1), expected, name: context }, + context, + ); + } + return replaceUniqueStringAssignment(text, { entryParts, expected, name: context }, context); +} + +function setTomlStringPath(file, dotted, expected, context) { + const result = syncTomlStringPath(readText(file), dotted, expected, `${rel(file)} ${context}`); + return [result.detail === undefined ? undefined : result.text, result.detail]; +} + +function setRustConstString(file, constName, expected, context) { + const lines = readText(file).split(/(?<=\n)/u); + const pattern = new RegExp( + `^(\\s*(?:pub\\s+)?const\\s+${escapeRegExp(constName)}\\s*:\\s*&str\\s*=\\s*)"([^"]*)"(;.*)$`, + 'u', + ); + for (const [index, line] of lines.entries()) { + const [body, newline] = stripNewline(line); + const match = pattern.exec(body); + if (!match) { + continue; + } + const actual = match[2]; + if (actual === expected) { + return [undefined, undefined]; + } + lines[index] = `${match[1]}"${expected}"${match[3]}${newline}`; + return [lines.join(''), `${context} ${JSON.stringify(actual)} -> ${JSON.stringify(expected)}`]; + } + fail(`${context} did not find Rust const ${JSON.stringify(constName)} in ${rel(file)}`); +} + +function tomlArrayAssignment(key, values) { + if (values.length === 1) { + return `${key} = [${JSON.stringify(values[0])}]\n`; + } + return `${key} = [\n${values.map((value) => ` ${JSON.stringify(value)},\n`).join('')}]\n`; +} + +function replaceTopLevelArrayAssignment(text, key, values, context) { + const lines = text.split(/(?<=\n)/u); + const output = []; + let index = 0; + let replaced = false; + const pattern = new RegExp(`^${escapeRegExp(key)}\\s*=\\s*\\[`, 'u'); + while (index < lines.length) { + const line = lines[index]; + if (!replaced && pattern.test(line)) { + output.push(tomlArrayAssignment(key, values)); + replaced = true; + if (!line.includes(']')) { + index += 1; + while (index < lines.length && !lines[index].includes(']')) { + index += 1; + } + } + index += 1; + continue; + } + output.push(line); + index += 1; + } + if (!replaced) { + fail(`${context} did not find top-level TOML array ${JSON.stringify(key)}`); + } + return output.join(''); +} + +function syncExtensionRegistryMetadata(changes, { write }) { + const expectedPublishTargets = ['github-release-assets', 'npm', 'maven-central', 'crates-io']; + for (const product of exactExtensionReleaseProducts(PREFIX)) { + const releaseToml = path.join(ROOT, packagePath(product), 'release.toml'); + const expectedRegistryPackages = extensionRegistryPackageStrings({ + product, + ...extensionRegistryPackageTargetSets(product, PREFIX), + }); + const text = readText(releaseToml); + let updated = replaceTopLevelArrayAssignment( + text, + 'publish_targets', + expectedPublishTargets, + product, + ); + updated = replaceTopLevelArrayAssignment( + updated, + 'registry_packages', + expectedRegistryPackages, + product, + ); + if (updated !== text) { + writeTextIfChanged( + releaseToml, + updated, + changes, + 'synced explicit extension registry metadata', + { write }, + ); + } + } +} + +function syncReleasePleaseBootstrapBoundary(changes, { write }) { + const config = readJsonObject(RELEASE_PLEASE_CONFIG); + const manifest = readJsonObject(RELEASE_PLEASE_MANIFEST); + const updated = releasePleaseConfigAfterBootstrapConsumption(config, manifest); + if (updated !== config) { + writeTextIfChanged( + RELEASE_PLEASE_CONFIG, + jsonText(updated), + changes, + 'removed the consumed one-time bootstrap-sha history boundary', + { write }, + ); + } +} + +async function syncCompatibilityVersions(changes, { write, transitions }) { + const links = compatibilityEntriesForBumpedProducts(compatibilityVersionLinks(), transitions); + for (const { id: specId, sourceProduct, path: pathText, parser } of links) { + const file = path.join(ROOT, pathText); + const expected = await currentProductVersion(sourceProduct, PREFIX); + if (parser === 'raw') { + writeTextIfChanged( + file, + `${expected}\n`, + changes, + `${specId} -> ${sourceProduct} ${expected}`, + { write }, + ); + continue; + } + if (parser.startsWith('json:')) { + const data = readJsonObject(file); + const detail = setJsonPath(data, parser.split(':', 2)[1], expected, specId); + if (detail !== undefined) { + writeTextIfChanged(file, jsonText(data), changes, detail, { write }); + } + continue; + } + if (parser.startsWith('toml:')) { + const [text, detail] = setTomlStringPath(file, parser.split(':', 2)[1], expected, specId); + if (text !== undefined && detail !== undefined) { + writeTextIfChanged(file, text, changes, detail, { write }); + } + continue; + } + if (parser.startsWith('rust-const:')) { + const [text, detail] = setRustConstString(file, parser.split(':', 2)[1], expected, specId); + if (text !== undefined && detail !== undefined) { + writeTextIfChanged(file, text, changes, detail, { write }); + } + continue; + } + fail(`${specId} uses unsupported sync parser ${JSON.stringify(parser)}`); + } +} + +async function expectedNativeToolsOptionalVersions() { + const versions = {}; + for (const { packageName, product } of nativeToolsOptionalPackageProducts(PREFIX)) { + versions[packageName] = `workspace:${await currentProductVersion(product, PREFIX)}`; + } + return versions; +} + +async function syncNativeToolsOptionalDependencies(changes, { write, transitions }) { + return syncOptionalRuntimeDependencies(changes, { + write, + transitions, + ownerProduct: 'postgres-tools-native', + packageFile: NATIVE_TOOLS_FACADE_PACKAGE, + runtimeVersions: await expectedNativeToolsOptionalVersions(), + }); +} + +async function syncOptionalRuntimeDependencies( + changes, + { write, transitions, ownerProduct, packageFile, runtimeVersions }, +) { + if (!transitions.some(({ product }) => product === ownerProduct)) { + return; + } + const file = packageFile; + const data = readJsonObject(file); + const optional = data.optionalDependencies; + const expectedVersions = runtimeVersions; + let changed = false; + const details = []; + for (const packageName of Object.keys(expectedVersions).sort(compareText)) { + const expectedVersion = expectedVersions[packageName]; + const actual = optional[packageName]; + if (actual !== expectedVersion) { + optional[packageName] = expectedVersion; + changed = true; + details.push( + `${packageName} ${JSON.stringify(actual)} -> ${JSON.stringify(expectedVersion)}`, + ); + } + } + if (changed) { + writeTextIfChanged(file, jsonText(data), changes, details.join('; '), { write }); + } +} + +function syncElectronExampleDependencies(changes, { write }) { + const data = readJsonObject(ELECTRON_EXAMPLE_PACKAGE); + const dependencies = data.dependencies; + if (dependencies === null || Array.isArray(dependencies) || typeof dependencies !== 'object') { + fail(`${rel(ELECTRON_EXAMPLE_PACKAGE)} must declare dependencies`); + } + + let changed = false; + const details = []; + for (const { packageName, version } of electronReleaseDependencies(ROOT)) { + const actual = dependencies[packageName]; + if (actual === undefined) { + fail(`${rel(ELECTRON_EXAMPLE_PACKAGE)} is missing release dependency ${packageName}`); + } + if (actual !== version) { + dependencies[packageName] = version; + changed = true; + details.push(`${packageName} ${JSON.stringify(actual)} -> ${JSON.stringify(version)}`); + } + } + if (changed) { + writeTextIfChanged(ELECTRON_EXAMPLE_PACKAGE, jsonText(data), changes, details.join('; '), { + write, + }); + } +} + +export function syncSdkInstallDocs(changes, { root = ROOT, write, transitions }) { + const transitionsByProduct = new Map( + transitions.map((transition) => [transition.product, transition]), + ); + for (const rule of SDK_INSTALL_VERSION_RULES) { + const transition = transitionsByProduct.get(rule.product); + if (transition === undefined) continue; + if (transition.before === null) + fail(`${rule.product} install docs require a prior release version`); + const file = path.join(root, rule.file); + const before = `${rule.prefix}${transition.before}${rule.suffix}`; + const after = `${rule.prefix}${transition.after}${rule.suffix}`; + const text = readText(file); + const beforeCount = text.split(before).length - 1; + const afterCount = text.split(after).length - 1; + if (beforeCount === 0 && afterCount === 1) continue; + if (beforeCount !== 1 || afterCount !== 0) { + fail( + `${rule.file} must contain exactly one ${rule.product} install contract for ${transition.before}`, + ); + } + writeTextIfChanged( + file, + text.replace(before, after), + changes, + `${rule.product} install contract ${transition.before} -> ${transition.after}`, + { write }, + ); + } +} + +function localCargoPackagesByManifest() { + const packages = new Map(); + for (const manifest of cargoManifestPaths()) { + const data = Bun.TOML.parse(readText(manifest)); + const packageConfig = data.package; + if ( + packageConfig === null || + Array.isArray(packageConfig) || + typeof packageConfig !== 'object' + ) { + continue; + } + const name = packageConfig.name; + const version = packageConfig.version; + if (typeof name !== 'string' || typeof version !== 'string') { + continue; + } + packages.set(realpathSync(manifest), [name, version]); + } + return packages; +} + +function localCargoPackageVersions() { + const versions = new Map(); + for (const [manifest, [name, version]] of localCargoPackagesByManifest()) { + const existing = versions.get(name); + if (existing !== undefined && existing !== version) { + fail(`local Cargo package ${name} has conflicting versions including ${rel(manifest)}`); + } + versions.set(name, version); + } + return versions; +} + +function iterDependencyTables(manifest) { + const tables = []; + for (const [parts, owner] of [ + [[], manifest], + ...Object.entries(manifest.target ?? {}).map(([target, value]) => [['target', target], value]), + ]) { + for (const tableName of DEPENDENCY_TABLES) { + const table = owner?.[tableName]; + if (table && !Array.isArray(table) && typeof table === 'object') + tables.push([[...parts, tableName], table]); + } + } + return tables; +} + +export function desiredCargoPathDependencyVersion(current, packageVersion) { + if (current === '*') return current; + return current.startsWith('=') ? `=${packageVersion}` : packageVersion; +} + +export function priorCargoPathDependencyVersions(manifestPath, { root = ROOT } = {}) { + const file = path.relative(root, manifestPath).split(path.sep).join('/'); + const state = releasePleaseState(root, 'HEAD'); + if (file === '..' || file.startsWith('../') || path.isAbsolute(file)) + fail('prior Cargo manifest must remain inside its checkout'); + if (readFileSync(path.join(state, 'ancestry'), 'utf8').trim().split(/\s+/u).length !== 2) + fail('prior Cargo manifest requires one parent commit'); + const prior = path.join(state, 'prior-cargo', file); + if (!existsSync(prior)) return new Map(); + const versions = new Map(); + for (const [parts, table] of iterDependencyTables(Bun.TOML.parse(readFileSync(prior, 'utf8')))) { + for (const [name, dependency] of Object.entries(table)) { + if ( + dependency !== null && + !Array.isArray(dependency) && + typeof dependency === 'object' && + typeof dependency.path === 'string' && + typeof dependency.version === 'string' + ) { + versions.set(JSON.stringify([...parts, name]), dependency.version); + } + } + } + return versions; +} + +export function cargoPathDependencyBindings( + text, + manifestPath, + localPackages, + priorVersions = new Map(), +) { + const manifest = Bun.TOML.parse(text); + const desired = []; + for (const [parts, table] of iterDependencyTables(manifest)) { + for (const [dependencyName, dependency] of Object.entries(table)) { + if (dependency === null || Array.isArray(dependency) || typeof dependency !== 'object') { + continue; + } + const pathValue = dependency.path; + const versionValue = dependency.version; + if (typeof pathValue !== 'string' || typeof versionValue !== 'string') { + continue; + } + const dependencyManifest = path.resolve(path.dirname(manifestPath), pathValue, 'Cargo.toml'); + const packageInfo = localPackages.get(realpathIfExists(dependencyManifest)); + if (packageInfo === undefined) { + continue; + } + const packageVersion = packageInfo[1]; + const entryParts = [...parts, dependencyName]; + desired.push({ + kind: 'dependency', + name: dependencyName, + entryParts, + expected: desiredCargoPathDependencyVersion( + priorVersions.get(JSON.stringify(entryParts)) ?? versionValue, + packageVersion, + ), + }); + } + } + return desired; +} + +function syncCargoPathDependencyPins(changes, { write, transitions }) { + const localPackages = localCargoPackagesByManifest(); + const selectedRoots = transitions + .map(({ product }) => path.join(ROOT, packagePath(product))) + .sort((left, right) => right.length - left.length || compareText(left, right)); + for (const manifestPath of cargoManifestPaths()) { + if ( + !selectedRoots.some( + (root) => manifestPath === root || manifestPath.startsWith(`${root}${path.sep}`), + ) + ) { + continue; + } + const source = readText(manifestPath); + const bindings = cargoPathDependencyBindings( + source, + manifestPath, + localPackages, + priorCargoPathDependencyVersions(manifestPath), + ); + const result = syncExampleCargoManifestText(source, { + policy: { crateDir: path.dirname(manifestPath) }, + bindings, + label: rel(manifestPath), + }); + if (result.details.length) + writeTextIfChanged(manifestPath, result.text, changes, result.details.join('; '), { write }); + } +} + +function valueAt(root, parts) { + let current = root; + for (const part of parts) { + if (current === null || typeof current !== 'object') return undefined; + current = current[part]; + } + return current; +} + +function tomlAssignmentMatchesAtPath(text, entryParts) { + const tableParts = entryParts.slice(0, -1); + const key = entryParts.at(-1); + const marker = '__oliphaunt_release_sync_table__'; + const keyPattern = new RegExp( + `^(\\s*(?:${escapeRegExp(key)}|"${escapeRegExp(key)}"|'${escapeRegExp(key)}')\\s*=\\s*)`, + 'u', + ); + const matches = []; + let offset = 0; + let inTable = false; + + for (const line of text.split(/(?<=\n)/u)) { + const [body] = stripNewline(line); + const tableMatch = /^\s*\[([^[\]]+)\]\s*(?:#.*)?$/u.exec(body); + if (tableMatch !== null) { + const parsed = Bun.TOML.parse(`[${tableMatch[1]}]\n${marker} = true\n`); + inTable = valueAt(parsed, [...tableParts, marker]) === true; + offset += line.length; + continue; + } + if (inTable) { + const assignment = keyPattern.exec(body); + if (assignment !== null) { + matches.push({ + assignmentStart: offset + assignment.index, + valueStart: offset + assignment.index + assignment[0].length, + }); + } + } + offset += line.length; + } + return matches; +} + +function quotedTomlStringEnd(text, start) { + const quote = text[start]; + let escaped = false; + for (let index = start + 1; index < text.length; index += 1) { + const character = text[index]; + if (quote === '"' && character === '\\' && !escaped) { + escaped = true; + continue; + } + if (character === quote && !escaped) return index; + escaped = false; + } + return -1; +} + +function inlineTomlTableEnd(text, start) { + let depth = 0; + let quote; + let escaped = false; + for (let index = start; index < text.length; index += 1) { + const character = text[index]; + if (quote !== undefined) { + if (quote === '"' && character === '\\' && !escaped) { + escaped = true; + continue; + } + if (character === quote && !escaped) quote = undefined; + escaped = false; + continue; + } + if (character === '"' || character === "'") { + quote = character; + } else if (character === '{') { + depth += 1; + } else if (character === '}') { + depth -= 1; + if (depth === 0) return index + 1; + } + } + return -1; +} + +function replaceUniqueDependencyVersion(text, binding, label) { + const matches = tomlAssignmentMatchesAtPath(text, binding.entryParts); + if (matches.length === 0) { + return replaceUniqueStringAssignment( + text, + { ...binding, entryParts: [...binding.entryParts, 'version'] }, + label, + ); + } + if (matches.length !== 1) + throw new Error( + `${label} must declare ${binding.entryParts.join('.')} exactly once as a direct TOML assignment, found ${matches.length}`, + ); + const { valueStart } = matches[0]; + const first = text[valueStart]; + if (first === '"' || first === "'") return replaceUniqueStringAssignment(text, binding, label); + if (first !== '{') { + throw new Error( + `${label} ${binding.name} must use a string or inline-table dependency specification`, + ); + } + const end = inlineTomlTableEnd(text, valueStart); + if (end === -1) throw new Error(`${label} has an unterminated inline table for ${binding.name}`); + const table = text.slice(valueStart, end); + const versionPattern = /(\bversion\s*=\s*)(?:"([^"]*)"|'([^']*)')/gu; + const versions = [...table.matchAll(versionPattern)]; + if (versions.length !== 1) { + throw new Error( + `${label} ${binding.name} inline table must declare version exactly once, found ${versions.length}`, + ); + } + const match = versions[0]; + const actual = match[2] ?? match[3]; + if (actual === binding.expected) return { text, detail: undefined }; + const quote = match[2] === undefined ? "'" : '"'; + const replacement = `${match[1]}${quote}${binding.expected}${quote}`; + const versionStart = valueStart + match.index; + return { + text: `${text.slice(0, versionStart)}${replacement}${text.slice(versionStart + match[0].length)}`, + detail: `${binding.name} ${JSON.stringify(actual)} -> ${JSON.stringify(binding.expected)}`, + }; +} + +function replaceUniqueStringAssignment(text, binding, label) { + const matches = tomlAssignmentMatchesAtPath(text, binding.entryParts); + if (matches.length !== 1) { + throw new Error( + `${label} must declare ${binding.entryParts.join('.')} exactly once, found ${matches.length}`, + ); + } + const { valueStart } = matches[0]; + const quote = text[valueStart]; + if (quote !== '"' && quote !== "'") { + throw new Error(`${label} ${binding.name} must be a TOML string`); + } + const end = quotedTomlStringEnd(text, valueStart); + if (end === -1) throw new Error(`${label} has an unterminated string for ${binding.name}`); + const actual = text.slice(valueStart + 1, end); + return { + text: + actual === binding.expected + ? text + : `${text.slice(0, valueStart + 1)}${binding.expected}${text.slice(end)}`, + detail: + actual === binding.expected + ? undefined + : `${binding.name} ${JSON.stringify(actual)} -> ${JSON.stringify(binding.expected)}`, + }; +} + +export function syncExampleCargoManifestText( + text, + { policy, bindings, label = `${policy.crateDir}/Cargo.toml` }, +) { + const manifest = Bun.TOML.parse(text); + const details = []; + let updated = text; + for (const binding of bindings) { + if (valueAt(manifest, binding.entryParts) === undefined) { + throw new Error( + `${label} is missing release-bound TOML path ${binding.entryParts.join('.')}`, + ); + } + const result = + binding.kind === 'dependency' + ? replaceUniqueDependencyVersion(updated, binding, label) + : replaceUniqueStringAssignment(updated, binding, label); + updated = result.text; + if (result.detail !== undefined) details.push(result.detail); + } + if (policy.runtime !== undefined) { + const actualProduct = valueAt(manifest, policy.runtime.productParts); + if (actualProduct !== policy.runtime.product) { + throw new Error( + `${label} runtime uses ${JSON.stringify(actualProduct)}; expected ${policy.runtime.product}`, + ); + } + } + return { text: updated, details }; +} + +function syncExampleCargoRegistryPins(changes, { write }) { + const bindings = exampleCargoReleaseVersionBindings(); + for (const policy of exampleCargoPolicies()) { + const file = path.join(ROOT, policy.crateDir, 'Cargo.toml'); + let result; + try { + result = syncExampleCargoManifestText(readText(file), { + policy, + bindings: bindings.filter(({ policyId }) => policyId === policy.id), + label: rel(file), + }); + } catch (cause) { + fail(cause.message); + } + if (result.details.length > 0) { + writeTextIfChanged(file, result.text, changes, result.details.join('; '), { write }); + } + } +} + +function stringKey(line, key) { + const [body] = stripNewline(line); + const match = STRING_KEY_RE.exec(body); + return match?.[1] === key ? match[2] : undefined; +} + +function packageBlockRanges(lines) { + const starts = lines.flatMap((line, index) => (PACKAGE_START_RE.test(line) ? [index] : [])); + return starts.map((start, index) => [ + start, + index + 1 < starts.length ? starts[index + 1] : lines.length, + ]); +} + +function replaceVersionLine(line, version) { + const [body, newline] = stripNewline(line); + const match = VERSION_LINE_RE.exec(body); + if (!match) { + fail(`cannot update Cargo.lock version line: ${line.trimEnd()}`); + } + return `${match[1]}"${version}"${match[2]}${newline}`; +} + +export function syncLockfile(lockfile, versions, changes, { write }) { + const data = Bun.TOML.parse(readText(lockfile)); + if (!Array.isArray(data.package)) { + fail(`${rel(lockfile)} is missing [[package]] entries`); + } + const lines = readText(lockfile).split(/(?<=\n)/u); + const fileChanges = []; + for (const [start, end] of packageBlockRanges(lines)) { + const block = lines.slice(start, end); + let name; + let versionIndex; + let currentVersion; + let hasSource = false; + for (const [offset, line] of block.entries()) { + if (stringKey(line, 'source') !== undefined) { + hasSource = true; + } + const keyName = stringKey(line, 'name'); + if (keyName !== undefined) { + name = keyName; + } + const keyVersion = stringKey(line, 'version'); + if (keyVersion !== undefined) { + versionIndex = start + offset; + currentVersion = keyVersion; + } + } + if (!versions.has(name) || hasSource) { + continue; + } + if (versionIndex === undefined || currentVersion === undefined) { + fail(`${rel(lockfile)} package ${name} is missing version`); + } + const expectedVersion = versions.get(name); + if (currentVersion !== expectedVersion) { + lines[versionIndex] = replaceVersionLine(lines[versionIndex], expectedVersion); + fileChanges.push(`${name} ${currentVersion} -> ${expectedVersion}`); + } + } + if (fileChanges.length > 0) { + writeTextIfChanged(lockfile, lines.join(''), changes, fileChanges.join('; '), { write }); + } +} + +function syncLockfiles(changes, { write }) { + const versions = localCargoPackageVersions(); + for (const lockfile of LOCKFILES) { + syncLockfile(lockfile, versions, changes, { write }); + } +} + +function syncExtensionEvidenceSummary(changes, { write }) { + const identity = { + commit: process.env.OLIPHAUNT_EVIDENCE_COMMIT, + tree: process.env.OLIPHAUNT_EVIDENCE_TREE, + }; + if (![identity.commit, identity.tree].every((value) => /^[0-9a-f]{40}$/.test(value ?? ''))) { + fail('run bash tools/release/sync-release-pr.sh to supply the checkout identity'); + } + const expected = currentEvidenceTable(readJson(catalogPath), identity); + writeTextIfChanged( + EXTENSION_EVIDENCE_SUMMARY_PATH, + expected, + changes, + 'extension evidence summary', + { write }, + ); +} + +function parseArgs(argv) { + const args = { + check: false, + generatedReleaseCheck: false, + normalCheck: false, + }; + for (const arg of argv) { + if (arg === '--check') { + if (args.generatedReleaseCheck) { + fail('--check and --check-generated-release are mutually exclusive'); + } + args.check = true; + args.normalCheck = true; + } else if (arg === '--check-generated-release') { + if (args.check) { + fail('--check and --check-generated-release are mutually exclusive'); + } + args.check = true; + args.generatedReleaseCheck = true; + } else if (arg === '--help' || arg === '-h') { + console.log( + 'usage: tools/release/sync-release-pr.mts ' + '[--check|--check-generated-release]', + ); + process.exit(0); + } else { + fail(`unknown argument ${arg}`); + } + } + const modes = [args.generatedReleaseCheck, args.normalCheck].filter(Boolean); + if (modes.length > 1) fail('release sync modes are mutually exclusive'); + return args; +} + +async function main(argv) { + const args = parseArgs(argv); + const changes = []; + const write = !args.check; + const transitions = releasePleaseWorktreeTransitions(ROOT, { prefix: PREFIX }); + syncReleasePleaseBootstrapBoundary(changes, { write }); + await syncCompatibilityVersions(changes, { write, transitions }); + syncExtensionRegistryMetadata(changes, { write }); + await syncNativeToolsOptionalDependencies(changes, { write, transitions }); + syncElectronExampleDependencies(changes, { write }); + syncSdkInstallDocs(changes, { write, transitions }); + syncCargoPathDependencyPins(changes, { write, transitions }); + syncExampleCargoRegistryPins(changes, { write }); + syncLockfiles(changes, { write }); + if (!args.generatedReleaseCheck) { + syncExtensionEvidenceSummary(changes, { write }); + } + if (changes.length === 0) { + console.log('release PR derived files are in sync'); + return; + } + for (const change of changes) { + console.error(`${rel(change.path)}: ${change.detail}`); + } + if (args.check) { + console.error('release PR derived files are stale; run `tools/release/sync-release-pr.mts`'); + process.exit(1); + } + console.log('updated release PR derived files'); +} + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&'); +} + +function realpathIfExists(file) { + try { + return realpathSync(file); + } catch { + return file; + } +} + +export function releaseDerivedPathInventory() { + return [ + ...new Set( + [ + ...LOCKFILES, + BUN_LOCKFILE, + RELEASE_PLEASE_CONFIG, + ELECTRON_EXAMPLE_PACKAGE, + EXTENSION_EVIDENCE_SUMMARY_PATH, + NATIVE_TOOLS_FACADE_PACKAGE, + WASIX_TOOLS_FACADE_PACKAGE, + ...SDK_INSTALL_VERSION_RULES.map(({ file }) => path.join(ROOT, file)), + ...compatibilityVersionLinks().map(({ path: pathText }) => path.join(ROOT, pathText)), + ...exactExtensionReleaseProducts(PREFIX).map((product) => + path.join(ROOT, packagePath(product), 'release.toml'), + ), + path.join(ROOT, 'src/sdks/ts/sdk/package.json'), + ...cargoManifestPaths(), + ].map(rel), + ), + ].sort(compareText); +} + +if (import.meta.main) { + await main(Bun.argv.slice(2)); +} diff --git a/tools/release/sync-release-pr.sh b/tools/release/sync-release-pr.sh new file mode 100755 index 000000000..a2aba71da --- /dev/null +++ b/tools/release/sync-release-pr.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" +OLIPHAUNT_EVIDENCE_COMMIT="$(git rev-parse 'HEAD^{commit}')" +OLIPHAUNT_EVIDENCE_TREE="$(git rev-parse 'HEAD^{tree}')" +export OLIPHAUNT_EVIDENCE_COMMIT OLIPHAUNT_EVIDENCE_TREE +bash tools/ci/with-projects.sh --exec bash tools/release/release-please-state.sh "$PWD" HEAD \ + bash tools/dev/bun.sh tools/release/sync-release-pr.mts "$@" + +# Bun owns its lock format and workspace dependency resolution. +for argument in "$@"; do + if [[ "$argument" == "--check" || "$argument" == "--check-generated-release" ]]; then + test -f bun.lock + exec bash tools/dev/bun.sh install --frozen-lockfile --dry-run --ignore-scripts + fi +done +exec bash tools/dev/bun.sh install --lockfile-only --ignore-scripts diff --git a/tools/release/sync-release-pr.test.mjs b/tools/release/sync-release-pr.test.mjs deleted file mode 100644 index 8d6416f8e..000000000 --- a/tools/release/sync-release-pr.test.mjs +++ /dev/null @@ -1,328 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - cargoManifestPaths, - desiredCargoPathDependencyVersion, - extensionEvidenceSummaryCommand, - releaseDerivedPathInventory, - SDK_INSTALL_VERSION_RULES, - sharedContribBootstrapRequired, - syncSdkInstallDocs, - syncExampleCargoManifestText, - syncLockfile, -} from "./sync-release-pr.mjs"; -import { - EXAMPLE_CARGO_POLICIES, - exampleCargoReleaseVersionBindings, -} from "./example-cargo-policy.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const SUMMARY_PATH = "src/extensions/generated/docs/extension-evidence.json"; -const CHECKER_PATH = "src/extensions/tools/check-extension-model.mjs"; -const EVIDENCE_SELF_TEST_PROCESS_TIMEOUT_MS = 15_000; - -test("release sync preserves wildcard Cargo path dependencies", () => { - assert.equal(desiredCargoPathDependencyVersion("*", "0.2.0"), "*"); - assert.equal(desiredCargoPathDependencyVersion("0.1.0", "0.2.0"), "0.2.0"); - assert.equal(desiredCargoPathDependencyVersion("=0.1.0", "0.2.0"), "=0.2.0"); -}); - -test("release sync advances every SDK install contract with its product", (t) => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-sdk-install-docs-")); - t.after(() => rmSync(root, { recursive: true, force: true })); - const transitions = [ - { product: "oliphaunt-swift", before: "0.6.1", after: "0.7.0" }, - { product: "oliphaunt-kotlin", before: "0.1.1", after: "0.2.0" }, - ]; - for (const rule of SDK_INSTALL_VERSION_RULES) { - const transition = transitions.find(({ product }) => product === rule.product); - const file = path.join(root, rule.file); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, `${rule.prefix}${transition.before}${rule.suffix}\n`); - } - - const changes = []; - syncSdkInstallDocs(changes, { root, write: true, transitions }); - assert.deepEqual( - changes.map(({ path: file }) => path.relative(root, file)).sort(), - SDK_INSTALL_VERSION_RULES.map(({ file }) => file).sort(), - ); - for (const rule of SDK_INSTALL_VERSION_RULES) { - const transition = transitions.find(({ product }) => product === rule.product); - assert.equal(readFileSync(path.join(root, rule.file), "utf8"), `${rule.prefix}${transition.after}${rule.suffix}\n`); - } - const checkChanges = []; - syncSdkInstallDocs(checkChanges, { root, write: false, transitions }); - assert.deepEqual(checkChanges, []); -}); - -test("shared contrib bootstrap is allowed only from unreleased main state", () => { - assert.equal( - sharedContribBootstrapRequired([], () => [{ product: "liboliphaunt-native" }]), - true, - ); - assert.equal(sharedContribBootstrapRequired([], () => []), false); - let discoveries = 0; - assert.equal( - sharedContribBootstrapRequired( - [{ product: "liboliphaunt-native", before: "0.1.0", after: "0.1.1" }], - () => { - discoveries += 1; - throw new Error("released main must not run shared candidate discovery"); - }, - ), - false, - "a released or pending main transition must not seed another release PR", - ); - assert.equal(discoveries, 0); -}); - -test("release sync selects the narrow evidence-summary mutation", () => { - assert.deepEqual(extensionEvidenceSummaryCommand({ write: true }), [ - process.execPath, - CHECKER_PATH, - "--write-evidence-summary", - ]); - assert.deepEqual(extensionEvidenceSummaryCommand({ write: false }), [ - process.execPath, - CHECKER_PATH, - "--check", - ]); -}); - -test("release commit inventory owns the deterministic evidence summary", () => { - assert.equal(releaseDerivedPathInventory().includes(SUMMARY_PATH), true); -}); - -test("release commit inventory owns the workspace Cargo lock", () => { - const inventory = releaseDerivedPathInventory(); - assert.equal(inventory.includes("Cargo.lock"), true); -}); - -test("release commit inventory owns generated npm facade dependency versions", () => { - const inventory = new Set(releaseDerivedPathInventory()); - assert.ok(inventory.has("src/runtimes/liboliphaunt/native/tools-npm/package.json")); - assert.ok(inventory.has("src/bindings/wasix-ts/tools-package/package.json")); -}); - -test("Cargo manifest inventory retains a successful child's final NUL record", () => { - const directory = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-cargo-manifest-inventory-")); - try { - mkdirSync(path.join(directory, "nested"), { recursive: true }); - writeFileSync(path.join(directory, "Cargo.toml"), "[package]\nname = \"root\"\nversion = \"0.0.0\"\n"); - writeFileSync(path.join(directory, "nested/Cargo.toml"), "[package]\nname = \"nested\"\nversion = \"0.0.0\"\n"); - const stub = path.join(directory, "git-stub.mjs"); - writeFileSync( - stub, - [ - "process.stdout.write('Cargo.toml\\0');", - "setImmediate(() => process.stdout.write('nested/Cargo.toml\\0'));", - "", - ].join("\n"), - ); - assert.deepEqual( - cargoManifestPaths({ - gitCommand: process.execPath, - gitCommandArgs: [stub], - root: directory, - }), - [path.join(directory, "Cargo.toml"), path.join(directory, "nested/Cargo.toml")], - ); - } finally { - rmSync(directory, { recursive: true, force: true }); - } -}); - -test("Cargo manifest inventory rejects a successful partial NUL record", () => { - const directory = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-cargo-manifest-partial-")); - try { - const stub = path.join(directory, "git-stub.mjs"); - writeFileSync(stub, "process.stdout.write('Cargo.toml');\n"); - assert.throws( - () => cargoManifestPaths({ - gitCommand: process.execPath, - gitCommandArgs: [stub], - root: directory, - }), - /missing its required terminal/u, - ); - } finally { - rmSync(directory, { recursive: true, force: true }); - } -}); - -test("release sync updates only unsourced local packages in a nested Cargo lock", () => { - const directory = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-lock-")); - try { - const lockfile = path.join(directory, "Cargo.lock"); - const initial = `version = 4 - -[[package]] -name = "oliphaunt" -version = "0.0.0" - -[[package]] -name = "serde" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -`; - writeFileSync(lockfile, initial); - const versions = new Map([ - ["oliphaunt", "0.1.0"], - ["serde", "9.9.9"], - ]); - const checkChanges = []; - syncLockfile(lockfile, versions, checkChanges, { write: false }); - assert.equal(readFileSync(lockfile, "utf8"), initial); - assert.deepEqual(checkChanges.map(({ detail }) => detail), ["oliphaunt 0.0.0 -> 0.1.0"]); - - const writeChanges = []; - syncLockfile(lockfile, versions, writeChanges, { write: true }); - const updated = readFileSync(lockfile, "utf8"); - assert.match(updated, /name = "oliphaunt"\nversion = "0[.]1[.]0"/u); - assert.match(updated, /name = "serde"\nversion = "1[.]0[.]0"\nsource =/u); - assert.deepEqual(writeChanges.map(({ detail }) => detail), ["oliphaunt 0.0.0 -> 0.1.0"]); - } finally { - rmSync(directory, { recursive: true, force: true }); - } -}); - -test("release sync closes registry example pins and runtime metadata across Cargo scopes", () => { - const target = 'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'; - const policy = { - crateDir: "fixture", - runtime: { - product: "liboliphaunt-native", - productParts: ["package", "metadata", "oliphaunt", "runtime"], - }, - }; - const dependency = (name, entryParts) => ({ - kind: "dependency", - name, - entryParts, - expected: "=0.1.1", - }); - const bindings = [ - dependency("oliphaunt-build", ["build-dependencies", "oliphaunt-build"]), - dependency("oliphaunt", ["dependencies", "oliphaunt"]), - dependency("oliphaunt", ["dev-dependencies", "oliphaunt"]), - dependency("oliphaunt-target", ["target", target, "dependencies", "oliphaunt-target"]), - { - kind: "runtime", - name: "runtime-version", - entryParts: ["package", "metadata", "oliphaunt", "runtime-version"], - expected: "0.1.1", - }, - ]; - const initial = `[package] -name = "fixture" -version = "0.0.0" - -[package.metadata.oliphaunt] -runtime = "liboliphaunt-native" -runtime-version = "0.1.0" # exact native payload contract - -[build-dependencies] -oliphaunt-build = { version = "=0.1.0" } - -[dependencies] -oliphaunt = "=0.1.0" - -[dev-dependencies] -'oliphaunt' = { version = '=0.1.0', optional = false } - -[target.'${target}'.dependencies] -oliphaunt-target = { version = "=0.1.0", features = [ - "preserved-feature", -] } -`; - - const first = syncExampleCargoManifestText(initial, { policy, bindings, label: "fixture/Cargo.toml" }); - assert.equal(first.details.length, 5); - assert.equal((first.text.match(/0[.]1[.]1/gu) ?? []).length, 5); - assert.equal(first.text.includes("0.1.0"), false); - assert.match(first.text, /features = \[\n "preserved-feature",\n\]/u); - assert.match(first.text, /runtime-version = "0[.]1[.]1" # exact native payload contract/u); - - const second = syncExampleCargoManifestText(first.text, { policy, bindings, label: "fixture/Cargo.toml" }); - assert.equal(second.text, first.text); - assert.deepEqual(second.details, []); - - const unsupported = initial.replace('oliphaunt = "=0.1.0"', "oliphaunt = true"); - assert.throws( - () => syncExampleCargoManifestText(unsupported, { policy, bindings, label: "fixture/Cargo.toml" }), - /must use a string or inline-table dependency specification/u, - ); -}); - -test("release sync targets both WASIX example dependency scopes independently", () => { - const bindings = exampleCargoReleaseVersionBindings(); - for (const policyId of ["wasix-tauri", "wasix-electron-sidecar"]) { - const policy = EXAMPLE_CARGO_POLICIES.find(({ id }) => id === policyId); - assert.notEqual(policy, undefined); - const manifestPath = path.join(ROOT, policy.crateDir, "Cargo.toml"); - const initial = readFileSync(manifestPath, "utf8"); - const result = syncExampleCargoManifestText(initial, { - policy, - bindings: bindings.filter(({ policyId: candidate }) => candidate === policyId), - label: `${policy.crateDir}/Cargo.toml`, - }); - assert.equal(result.text, initial); - assert.deepEqual(result.details, []); - } -}); - -test("generated release readiness closes the cheap pre-fanout fixed point", () => { - const result = spawnSync( - process.execPath, - ["tools/release/sync-release-pr.mjs", "--check-generated-release"], - { - cwd: ROOT, - encoding: "utf8", - maxBuffer: 16 * 1024 * 1024, - timeout: 10_000, - }, - ); - assert.equal( - result.status, - 0, - [result.stdout, result.stderr].filter(Boolean).join("\n"), - ); - assert.match(result.stdout, /release PR derived files are in sync/u); - - const conflicting = spawnSync( - process.execPath, - [ - "tools/release/sync-release-pr.mjs", - "--check", - "--check-generated-release", - ], - { cwd: ROOT, encoding: "utf8", timeout: 10_000 }, - ); - assert.equal(conflicting.status, 2); - assert.match(conflicting.stderr, /mutually exclusive/u); -}); - -test("extension evidence self-test proves summary writes preserve immutable inputs", () => { - const result = spawnSync( - "python3", - ["src/extensions/tools/check-extension-model.py", "--self-test"], - { - cwd: ROOT, - encoding: "utf8", - maxBuffer: 16 * 1024 * 1024, - timeout: EVIDENCE_SELF_TEST_PROCESS_TIMEOUT_MS, - }, - ); - assert.equal( - result.status, - 0, - [result.stdout, result.stderr].filter(Boolean).join("\n"), - ); -}); diff --git a/tools/release/sync-release-pr.test.mts b/tools/release/sync-release-pr.test.mts new file mode 100644 index 000000000..03865a1ec --- /dev/null +++ b/tools/release/sync-release-pr.test.mts @@ -0,0 +1,239 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { + cargoManifestPaths, + cargoPathDependencyBindings, + desiredCargoPathDependencyVersion, + priorCargoPathDependencyVersions, + SDK_INSTALL_VERSION_RULES, + syncExampleCargoManifestText, + syncLockfile, + syncSdkInstallDocs, + syncTomlStringPath, +} from './sync-release-pr.mts'; + +const [mode, root, stage] = process.argv.slice(2); +if (mode === 'inventory') { + const existing = path.join(root, 'Cargo.toml'), + nested = path.join(root, 'nested/Cargo.toml'), + untracked = path.join(root, 'untracked/Cargo.toml'); + assert.deepEqual( + cargoManifestPaths({ root }), + stage === 'deleted' ? [existing, untracked] : [existing, nested, untracked], + ); + assert.equal( + priorCargoPathDependencyVersions(existing, { root }).get( + JSON.stringify(['dependencies', 'local']), + ), + '*', + ); + assert.deepEqual([...priorCargoPathDependencyVersions(nested, { root })], []); + assert.deepEqual([...priorCargoPathDependencyVersions(untracked, { root })], []); + process.exit(0); +} + +test('compatibility sync handles inline and table Cargo dependencies without changing other fields', () => { + for (const source of [ + `[dependencies]\nquery = { path = '../query', version = '0.1.0', features = ['one'] }\n`, + `[dependencies.query]\npath = '../query'\nversion = '0.1.0'\nfeatures = ['one']\n`, + ]) { + const result = syncTomlStringPath(source, 'dependencies.query.version', '0.2.0', 'consumer'); + const expected = Bun.TOML.parse(source); + expected.dependencies.query.version = '0.2.0'; + assert.deepEqual(Bun.TOML.parse(result.text), expected); + assert.equal( + syncTomlStringPath(result.text, 'dependencies.query.version', '0.2.0', 'consumer').detail, + undefined, + ); + } +}); + +test('release sync preserves wildcard Cargo path dependencies', () => { + assert.equal(desiredCargoPathDependencyVersion('*', '0.2.0'), '*'); + assert.equal(desiredCargoPathDependencyVersion('0.1.0', '0.2.0'), '0.2.0'); + assert.equal(desiredCargoPathDependencyVersion('=0.1.0', '0.2.0'), '=0.2.0'); +}); + +test('release sync updates table-form Cargo pins and keeps target-specific requirements distinct', () => { + const manifestPath = path.resolve('/release-fixture/client/Cargo.toml'); + const packages = new Map([ + [path.resolve('/release-fixture/native/Cargo.toml'), ['runtime', '0.2.0']], + ]); + const source = ` +[dependencies] +alias = { package = 'runtime', path = '../native', version = '=0.1.0', features = ['one'] } +[target.'cfg(unix)'.dependencies.alias] +package = 'runtime' +path = '../native' +version = '0.1.0' +[target.'cfg(windows)'.build-dependencies] +alias = { package = 'runtime', path = '../native', version = '*' } +`; + const policy = { crateDir: path.dirname(manifestPath) }; + const bindings = cargoPathDependencyBindings(source, manifestPath, packages); + const result = syncExampleCargoManifestText(source, { policy, bindings }); + const expected = Bun.TOML.parse(source); + expected.dependencies.alias.version = '=0.2.0'; + expected.target['cfg(unix)'].dependencies.alias.version = '0.2.0'; + assert.deepEqual(Bun.TOML.parse(result.text), expected); + assert.equal(result.details.length, 2); + assert.deepEqual(syncExampleCargoManifestText(result.text, { policy, bindings }), { + text: result.text, + details: [], + }); +}); + +test('release sync advances every SDK install contract with its product', (t) => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-sdk-install-docs-')); + t.after(() => rmSync(root, { recursive: true, force: true })); + const transitions = [ + { product: 'oliphaunt-swift', before: '0.6.1', after: '0.7.0' }, + { product: 'oliphaunt-kotlin', before: '0.1.1', after: '0.2.0' }, + ]; + for (const rule of SDK_INSTALL_VERSION_RULES) { + const transition = transitions.find(({ product }) => product === rule.product); + const file = path.join(root, rule.file); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, `${rule.prefix}${transition.before}${rule.suffix}\n`); + } + + const changes = []; + syncSdkInstallDocs(changes, { root, write: true, transitions }); + assert.deepEqual( + changes.map(({ path: file }) => path.relative(root, file)).sort(), + SDK_INSTALL_VERSION_RULES.map(({ file }) => file).sort(), + ); + for (const rule of SDK_INSTALL_VERSION_RULES) { + const transition = transitions.find(({ product }) => product === rule.product); + assert.equal( + readFileSync(path.join(root, rule.file), 'utf8'), + `${rule.prefix}${transition.after}${rule.suffix}\n`, + ); + } + const checkChanges = []; + syncSdkInstallDocs(checkChanges, { root, write: false, transitions }); + assert.deepEqual(checkChanges, []); +}); + +test('release sync updates only unsourced local packages in a nested Cargo lock', () => { + const directory = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-release-lock-')); + try { + const lockfile = path.join(directory, 'Cargo.lock'); + const initial = `version = 4 + +[[package]] +name = "oliphaunt" +version = "0.0.0" + +[[package]] +name = "serde" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +`; + writeFileSync(lockfile, initial); + const versions = new Map([ + ['oliphaunt', '0.1.0'], + ['serde', '9.9.9'], + ]); + const checkChanges = []; + syncLockfile(lockfile, versions, checkChanges, { write: false }); + assert.equal(readFileSync(lockfile, 'utf8'), initial); + assert.deepEqual( + checkChanges.map(({ detail }) => detail), + ['oliphaunt 0.0.0 -> 0.1.0'], + ); + + const writeChanges = []; + syncLockfile(lockfile, versions, writeChanges, { write: true }); + const updated = readFileSync(lockfile, 'utf8'); + assert.match(updated, /name = "oliphaunt"\nversion = "0[.]1[.]0"/u); + assert.match(updated, /name = "serde"\nversion = "1[.]0[.]0"\nsource =/u); + assert.deepEqual( + writeChanges.map(({ detail }) => detail), + ['oliphaunt 0.0.0 -> 0.1.0'], + ); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('release sync closes registry example pins and runtime metadata across Cargo scopes', () => { + const target = 'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'; + const policy = { + crateDir: 'fixture', + runtime: { + product: 'liboliphaunt-native', + productParts: ['package', 'metadata', 'oliphaunt', 'runtime'], + }, + }; + const dependency = (name, entryParts) => ({ + kind: 'dependency', + name, + entryParts, + expected: '=0.1.1', + }); + const bindings = [ + dependency('oliphaunt-build', ['build-dependencies', 'oliphaunt-build']), + dependency('oliphaunt', ['dependencies', 'oliphaunt']), + dependency('oliphaunt', ['dev-dependencies', 'oliphaunt']), + dependency('oliphaunt-target', ['target', target, 'dependencies', 'oliphaunt-target']), + { + kind: 'runtime', + name: 'runtime-version', + entryParts: ['package', 'metadata', 'oliphaunt', 'runtime-version'], + expected: '0.1.1', + }, + ]; + const initial = `[package] +name = "fixture" +version = "0.0.0" + +[package.metadata.oliphaunt] +runtime = "liboliphaunt-native" +runtime-version = "0.1.0" # exact native payload contract + +[build-dependencies] +oliphaunt-build = { version = "=0.1.0" } + +[dependencies] +oliphaunt = "=0.1.0" + +[dev-dependencies] +'oliphaunt' = { version = '=0.1.0', optional = false } + +[target.'${target}'.dependencies] +oliphaunt-target = { version = "=0.1.0", features = [ + "preserved-feature", +] } +`; + + const first = syncExampleCargoManifestText(initial, { + policy, + bindings, + label: 'fixture/Cargo.toml', + }); + assert.equal(first.details.length, 5); + assert.equal((first.text.match(/0[.]1[.]1/gu) ?? []).length, 5); + assert.equal(first.text.includes('0.1.0'), false); + assert.match(first.text, /features = \[\n {2}"preserved-feature",\n\]/u); + assert.match(first.text, /runtime-version = "0[.]1[.]1" # exact native payload contract/u); + + const second = syncExampleCargoManifestText(first.text, { + policy, + bindings, + label: 'fixture/Cargo.toml', + }); + assert.equal(second.text, first.text); + assert.deepEqual(second.details, []); + + const unsupported = initial.replace('oliphaunt = "=0.1.0"', 'oliphaunt = true'); + assert.throws( + () => + syncExampleCargoManifestText(unsupported, { policy, bindings, label: 'fixture/Cargo.toml' }), + /must use a string or inline-table dependency specification/u, + ); +}); diff --git a/tools/release/sync-release-pr.test.sh b/tools/release/sync-release-pr.test.sh new file mode 100644 index 000000000..09f19de3d --- /dev/null +++ b/tools/release/sync-release-pr.test.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +source_root="$PWD" +bun test ./tools/release/sync-release-pr.test.mts +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +mkdir "$scratch/repo" +repo="$scratch/repo" +cd "$repo" +git init -q +git config user.name Fixture +git config user.email fixture@example.invalid +printf 'ignored/\n' > .gitignore +cat > Cargo.toml <<'TOML' +[package] +name = "root" +version = "0.1.0" +[dependencies] +local = { path = "nested", version = "*" } +TOML +git add . +git commit -qm initial +mkdir nested ignored untracked +printf '[package]\nname="nested"\nversion="0.2.0"\n' > nested/Cargo.toml +cp nested/Cargo.toml ignored/Cargo.toml +git add nested +git commit -qm 'new package' +printf '[package]\nname="untracked"\nversion="0.1.0"\n' > untracked/Cargo.toml +observe() { + bash "$source_root/tools/release/release-please-state.sh" "$repo" HEAD \ + bun "$source_root/tools/release/sync-release-pr.test.mts" inventory "$repo" "$1" +} +observe added +rm nested/Cargo.toml +observe deleted +cd "$source_root" +status=0 +bun tools/release/sync-release-pr.mts --check --check-generated-release > "$scratch/result" 2>&1 || status=$? +[[ "$status" == 2 ]] +rg -q 'mutually exclusive' "$scratch/result" +echo 'Release sync: real tracked/untracked Cargo inventory and prior constraints passed' diff --git a/tools/release/tar-command.mjs b/tools/release/tar-command.mjs deleted file mode 100644 index 7f746950c..000000000 --- a/tools/release/tar-command.mjs +++ /dev/null @@ -1,127 +0,0 @@ -import path from "node:path"; - -function archiveArgumentIndex(args) { - for (let index = 0; index < args.length; index += 1) { - const argument = args[index]; - if (argument === "--file") return index + 1; - if (argument.startsWith("--file=")) return index; - if (!argument.startsWith("-") || argument.startsWith("--")) continue; - const options = argument.slice(1); - const fileOption = options.indexOf("f"); - if (fileOption === -1) continue; - if (fileOption !== options.length - 1) { - throw new Error(`tar archive option must provide its path as the next argument: ${argument}`); - } - return index + 1; - } - throw new Error("tar command does not contain an explicit archive file option"); -} - -function portableRelativeWindowsPath(from, to, pathApi, label) { - const relative = pathApi.relative(from, to); - if (pathApi.isAbsolute(relative) || relative.includes(":")) { - throw new Error( - `tar ${label} must be on the same Windows volume as the archive: ${to}`, - ); - } - return (relative || ".").split(pathApi.sep).join("/"); -} - -function localizeWindowsDirectoryOperands(args, { - originalCwd, - invocationCwd, - pathApi, -}) { - let originalDirectory = originalCwd; - let invocationDirectory = invocationCwd; - for (let index = 0; index < args.length; index += 1) { - const argument = args[index]; - let valueIndex = null; - let assignment = false; - if (argument === "-C" || argument === "--directory") { - valueIndex = index + 1; - } else if (argument.startsWith("--directory=")) { - valueIndex = index; - assignment = true; - } else { - continue; - } - if (valueIndex >= args.length) { - throw new Error(`tar ${argument} option is missing its path argument`); - } - const raw = args[valueIndex]; - const directory = assignment ? raw.slice("--directory=".length) : raw; - if (directory.length === 0) { - throw new Error(`tar ${argument} option is missing its path argument`); - } - if (!pathApi.isAbsolute(directory) && directory.includes(":")) { - throw new Error( - `tar directory path must not use a drive-relative or alternate-stream form: ${directory}`, - ); - } - const target = pathApi.isAbsolute(directory) - ? pathApi.normalize(directory) - : pathApi.resolve(originalDirectory, directory); - const localized = portableRelativeWindowsPath( - invocationDirectory, - target, - pathApi, - "directory path", - ); - args[valueIndex] = assignment ? `--directory=${localized}` : localized; - originalDirectory = target; - invocationDirectory = target; - if (!assignment) index += 1; - } -} - -export function localWindowsTarInvocation( - args, - { - cwd = process.cwd(), - platform = process.platform, - pathApi = platform === "win32" ? path.win32 : path, - } = {}, -) { - const invocation = { args: [...args], cwd }; - if (platform !== "win32") return invocation; - const index = archiveArgumentIndex(invocation.args); - if (index >= invocation.args.length) { - throw new Error("tar archive file option is missing its path argument"); - } - const value = invocation.args[index]; - const assignment = value.startsWith("--file="); - const archive = assignment ? value.slice("--file=".length) : value; - if (archive.length === 0) { - throw new Error("tar archive file option is missing its path argument"); - } - if (!pathApi.isAbsolute(archive)) { - if (platform === "win32" && archive.includes(":")) { - throw new Error(`tar archive path must not use a drive-relative or alternate-stream form: ${archive}`); - } - localizeWindowsDirectoryOperands(invocation.args, { - originalCwd: cwd, - invocationCwd: invocation.cwd, - pathApi, - }); - return invocation; - } - const directory = pathApi.dirname(archive); - const basename = pathApi.basename(archive); - if (basename.length === 0 || basename === pathApi.parse(archive).root) { - throw new Error(`tar archive path does not name a file: ${archive}`); - } - invocation.cwd = directory; - invocation.args[index] = assignment ? `--file=${basename}` : basename; - // Git for Windows' tar does not reliably accept native drive-letter paths - // as -C operands when it is launched directly by Node/Bun. Moving the - // process beside the archive protects the -f operand, but every directory - // operand must then be rebased as a colon-free, slash-separated relative - // path as well. Preserve tar's sequential -C semantics while doing so. - localizeWindowsDirectoryOperands(invocation.args, { - originalCwd: cwd, - invocationCwd: invocation.cwd, - pathApi, - }); - return invocation; -} diff --git a/tools/release/tar-command.test.mjs b/tools/release/tar-command.test.mjs deleted file mode 100644 index 48b83f8e0..000000000 --- a/tools/release/tar-command.test.mjs +++ /dev/null @@ -1,181 +0,0 @@ -import { expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { localWindowsTarInvocation } from "./tar-command.mjs"; - -test("localizes absolute Windows archive and extraction-directory operands", () => { - expect(localWindowsTarInvocation( - [ - "-xf", - String.raw`D:\a\oliphaunt\artifacts\runtime.tar.gz`, - "-C", - String.raw`D:\a\oliphaunt\target\extract`, - "files", - ], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toEqual({ - args: [ - "-xf", - "runtime.tar.gz", - "-C", - "../target/extract", - "files", - ], - cwd: String.raw`D:\a\oliphaunt\artifacts`, - }); - expect(localWindowsTarInvocation( - [`--file=${String.raw`E:\release\candidate.tgz`}`, "-tz"], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toEqual({ - args: ["--file=candidate.tgz", "-tz"], - cwd: String.raw`E:\release`, - }); -}); - -test("preserves the meaning of relative and sequential Windows directory operands", () => { - expect(localWindowsTarInvocation( - [ - "-xf", - String.raw`D:\a\oliphaunt\artifacts\runtime.tar.gz`, - "-C", - "target/extract", - "-C", - "nested", - "files", - ], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toEqual({ - args: [ - "-xf", - "runtime.tar.gz", - "-C", - "../target/extract", - "-C", - "nested", - "files", - ], - cwd: String.raw`D:\a\oliphaunt\artifacts`, - }); - expect(localWindowsTarInvocation( - [ - "-xf", - String.raw`D:\a\oliphaunt\artifacts\runtime.tar.gz`, - `--directory=${String.raw`D:\a\oliphaunt\target\extract`}`, - "files", - ], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - ).args).toEqual([ - "-xf", - "runtime.tar.gz", - "--directory=../target/extract", - "files", - ]); -}); - -test("preserves relative and non-Windows archive invocations", () => { - expect(localWindowsTarInvocation( - ["-tzf", "candidate.tgz"], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toEqual({ args: ["-tzf", "candidate.tgz"], cwd: String.raw`D:\a\oliphaunt` }); - expect(localWindowsTarInvocation( - ["-tzf", "/tmp/candidate.tgz"], - { platform: "linux", cwd: "/workspace" }, - )).toEqual({ args: ["-tzf", "/tmp/candidate.tgz"], cwd: "/workspace" }); -}); - -test("supports every archive option cluster used by release consumers", () => { - for (const option of ["-xOf", "-xOzf", "-tzf", "-xf", "-tvzf", "-tf", "-xzf"]) { - const invocation = localWindowsTarInvocation( - [option, String.raw`D:\a\oliphaunt\candidate.tgz`, "member"], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - ); - expect(invocation.args).toEqual([option, "candidate.tgz", "member"]); - expect(invocation.cwd).toBe(String.raw`D:\a\oliphaunt`); - } - expect(localWindowsTarInvocation( - ["--file", String.raw`D:\a\candidate.tgz`, "-tz"], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toEqual({ args: ["--file", "candidate.tgz", "-tz"], cwd: String.raw`D:\a` }); - expect(localWindowsTarInvocation( - ["--zstd", "-tf", String.raw`D:\a\candidate.tar.zst`], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toEqual({ args: ["--zstd", "-tf", "candidate.tar.zst"], cwd: String.raw`D:\a` }); -}); - -test("lists, reads, and extracts a local archive without exposing its colon-bearing path to tar", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-tar-local-")); - try { - const archiveDirectory = path.join(root, "drive:D"); - const payloadDirectory = path.join(root, "payload"); - const extractDirectory = path.join(root, "extract"); - mkdirSync(archiveDirectory); - mkdirSync(payloadDirectory); - mkdirSync(extractDirectory); - writeFileSync(path.join(payloadDirectory, "proof.txt"), "local archive\n"); - const archive = path.join(archiveDirectory, "candidate.tar.gz"); - const packed = spawnSync("tar", ["-czf", "candidate.tar.gz", "-C", payloadDirectory, "proof.txt"], { - cwd: archiveDirectory, - encoding: "utf8", - }); - expect(packed.status, packed.stderr).toBe(0); - - for (const args of [ - ["-tzf", archive], - ["-xOzf", archive, "proof.txt"], - ["-xzf", archive, "-C", extractDirectory, "proof.txt"], - ]) { - const invocation = localWindowsTarInvocation(args, { - platform: "win32", - cwd: root, - pathApi: path.posix, - }); - expect(invocation.args.join(" ")).not.toContain("drive:D"); - expect(invocation.args.join(" ")).not.toContain(extractDirectory); - const result = spawnSync("tar", invocation.args, { cwd: invocation.cwd, encoding: "utf8" }); - expect(result.status, result.stderr).toBe(0); - } - expect(readFileSync(path.join(extractDirectory, "proof.txt"), "utf8")).toBe("local archive\n"); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("fails closed for ambiguous or incomplete tar archive options", () => { - expect(() => localWindowsTarInvocation( - ["-tz"], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toThrow("explicit archive file option"); - expect(() => localWindowsTarInvocation( - ["-tzf"], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toThrow("missing its path argument"); - expect(() => localWindowsTarInvocation( - ["--file="], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toThrow("missing its path argument"); - expect(() => localWindowsTarInvocation( - ["-tzf", String.raw`D:candidate.tgz`], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toThrow("drive-relative or alternate-stream"); - expect(() => localWindowsTarInvocation( - ["-tfx", String.raw`D:\a\candidate.tgz`], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toThrow("path as the next argument"); - expect(() => localWindowsTarInvocation( - ["-xf", String.raw`D:\a\candidate.tgz`, "-C"], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toThrow("missing its path argument"); - expect(() => localWindowsTarInvocation( - ["-xf", String.raw`D:\a\candidate.tgz`, "-C", String.raw`E:\extract`], - { platform: "win32", cwd: String.raw`D:\a\oliphaunt` }, - )).toThrow("same Windows volume"); -}); diff --git a/tools/release/testdata/bootstrap-ledger-github.mts b/tools/release/testdata/bootstrap-ledger-github.mts new file mode 100644 index 000000000..6b84b040b --- /dev/null +++ b/tools/release/testdata/bootstrap-ledger-github.mts @@ -0,0 +1,76 @@ +import crypto from 'node:crypto'; +import fs from 'node:fs'; + +globalThis.fetch = async (input, options) => { + const url = new URL(input); + if (url.origin !== 'https://api.github.com') throw new Error('unexpected fixture origin'); + if (options.headers.Authorization !== 'Bearer test-token') + throw new Error('missing fixture authorization'); + const endpoint = url.pathname.slice(1) + url.search; + fs.appendFileSync(process.env.FAKE_GH_LOG, JSON.stringify(endpoint) + '\n'); + const attempt = /\/runs\/([0-9]+)\/attempts\/([0-9]+)$/.exec(endpoint); + if (attempt) { + return new Response(process.env.FAKE_ATTEMPT_METADATA); + } + const run = /\/actions\/runs\/([0-9]+)$/.exec(endpoint); + if (run) { + if (run[1] !== '900') throw new Error('unexpected run ' + run[1]); + return new Response(process.env.FAKE_CURRENT_RUN); + } + if (/\/actions\/artifacts[?]name=/.test(endpoint)) { + const url = new URL('https://api.github.com/' + endpoint); + const page = Number(url.searchParams.get('page')); + const zips = JSON.parse(process.env.FAKE_ZIPS_BY_ARTIFACT); + const all = Object.values(JSON.parse(process.env.FAKE_ARTIFACTS_BY_RUN)) + .flat() + .map((artifact) => { + const archive = zips[String(artifact.id)]; + const bytes = archive ? fs.readFileSync(archive) : null; + return { + ...artifact, + ...(bytes === null + ? {} + : { + size_in_bytes: bytes.length, + digest: 'sha256:' + crypto.createHash('sha256').update(bytes).digest('hex'), + }), + workflow_run: { + head_sha: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + ...artifact.workflow_run, + }, + }; + }); + const artifacts = all.slice((page - 1) * 100, page * 100); + let link = ''; + if (page * 100 < all.length) { + const next = new URL(url); + next.searchParams.set('page', String(page + 1)); + const last = new URL(url); + last.searchParams.set('page', String(Math.ceil(all.length / 100))); + link = `<${next}>; rel="next", <${last}>; rel="last"`; + } + return Response.json({ total_count: all.length, artifacts }, { headers: link ? { link } : {} }); + } + const download = /\/artifacts\/([0-9]+)\/zip$/.exec(endpoint); + if (download) { + const archive = JSON.parse(process.env.FAKE_ZIPS_BY_ARTIFACT)[download[1]]; + if (!archive) throw new Error('missing fake artifact ZIP ' + download[1]); + const state = process.env.FAKE_DOWNLOAD_STATE; + const count = fs.existsSync(state) ? Number(fs.readFileSync(state, 'utf8')) : 0; + fs.writeFileSync(state, String(count + 1)); + if (process.env.FAKE_DOWNLOAD_MODE === 'transient' && count === 0) { + return new Response('unavailable', { status: 503 }); + } + const bytes = fs.readFileSync(archive); + if (process.env.FAKE_DOWNLOAD_MODE === 'identity-mismatch') { + const altered = Buffer.from(bytes); + altered[Math.min(10, altered.length - 1)] ^= 0x01; + return new Response(altered); + } else { + return new Response( + process.env.FAKE_DOWNLOAD_MODE === 'truncated' ? bytes.subarray(0, 3) : bytes, + ); + } + } + throw new Error('unexpected gh api endpoint ' + endpoint); +}; diff --git a/tools/release/testdata/download-build-artifacts-github.mts b/tools/release/testdata/download-build-artifacts-github.mts new file mode 100644 index 000000000..5ecaf699c --- /dev/null +++ b/tools/release/testdata/download-build-artifacts-github.mts @@ -0,0 +1,80 @@ +import assert from 'node:assert/strict'; +import crypto from 'node:crypto'; +import fs from 'node:fs'; + +globalThis.fetch = async (input, options) => { + const url = new URL(input); + assert.equal(url.origin, 'https://api.github.com'); + assert.equal(options.headers.Authorization, 'Bearer test-token'); + assert.equal(options.headers.Accept, 'application/vnd.github+json'); + const endpoint = url.pathname.slice(1) + url.search; + fs.appendFileSync(process.env.FAKE_GH_LOG, JSON.stringify(endpoint) + '\n'); + if (/actions\/workflows[?]/.test(endpoint)) { + return Response.json({ workflows: [{ id: 9, name: 'CI' }] }); + } + if (/actions\/workflows\/9\/runs[?]/.test(endpoint)) { + const page = Number(url.searchParams.get('page')); + const selected = { + id: 77, + head_sha: 'a'.repeat(40), + workflow_id: 9, + status: 'completed', + conclusion: 'success', + }; + const more = process.env.FAKE_CANDIDATE_MODE === 'beyond-first-page' && page === 1; + const workflow_runs = more + ? Array.from({ length: 100 }, (_, index) => ({ + ...selected, + id: 100 + index, + conclusion: 'failure', + })) + : [selected]; + const next = new URL(url); + next.searchParams.set('page', '2'); + return Response.json( + { workflow_runs }, + { headers: more ? { link: `<${next}>; rel="next", <${next}>; rel="last"` } : {} }, + ); + } + if (/actions\/runs\/77\/artifacts/.test(endpoint)) { + const bytes = fs.readFileSync(process.env.FAKE_ARTIFACT_ARCHIVE); + const identity = { + id: Number(process.env.FAKE_ARTIFACT_ID || '101'), + name: 'exact-artifact', + size_in_bytes: bytes.length, + expired: false, + digest: 'sha256:' + crypto.createHash('sha256').update(bytes).digest('hex'), + }; + return Response.json({ + artifacts: [identity, { ...identity, id: 102, name: 'exact-artifact-near-match' }], + }); + } + if (/actions\/runs\/77\/jobs/.test(endpoint)) { + const jobs = [ + { id: 501, name: 'Qualified', status: 'completed', conclusion: 'success', run_attempt: 1 }, + ]; + if (process.env.FAKE_DUPLICATE_JOB === 'true') jobs.push({ ...jobs[0], id: 502 }); + return Response.json({ jobs }); + } + if (/actions\/runs\/77$/.test(endpoint)) { + return Response.json({ + id: 77, + head_sha: 'a'.repeat(40), + workflow_id: 9, + run_attempt: 1, + status: process.env.FAKE_RUN_STATUS || 'completed', + conclusion: process.env.FAKE_RUN_CONCLUSION || 'success', + }); + } + if (/actions\/workflows\/9$/.test(endpoint)) return Response.json({ id: 9, name: 'CI' }); + if (/actions\/artifacts\/101\/zip$/.test(endpoint)) { + const state = process.env.FAKE_GH_STATE; + const count = fs.existsSync(state) ? Number(fs.readFileSync(state, 'utf8')) : 0; + fs.writeFileSync(state, String(count + 1)); + if (process.env.FAKE_MODE === 'transient' && count === 0) + return new Response('unavailable', { status: 503 }); + if (process.env.FAKE_MODE === 'permanent') return new Response('not found', { status: 404 }); + return new Response(fs.readFileSync(process.env.FAKE_ARTIFACT_ARCHIVE)); + } + throw new Error('unexpected GitHub endpoint ' + endpoint); +}; diff --git a/tools/test/isolated-github-test-environment.mjs b/tools/release/testdata/isolated-github-test-environment.mts similarity index 100% rename from tools/test/isolated-github-test-environment.mjs rename to tools/release/testdata/isolated-github-test-environment.mts diff --git a/tools/release/testdata/require-workflow-success-github.mts b/tools/release/testdata/require-workflow-success-github.mts new file mode 100644 index 000000000..c061c31ea --- /dev/null +++ b/tools/release/testdata/require-workflow-success-github.mts @@ -0,0 +1,205 @@ +import fs from 'node:fs'; +import { createHash } from 'node:crypto'; + +globalThis.fetch = async (input, options) => { + const url = new URL(input); + if ( + url.origin !== 'https://api.github.com' || + options.headers.Authorization !== 'Bearer test-token' + ) + throw new Error('unexpected GitHub request'); + const endpoint = url.pathname.slice(1) + url.search; + fs.appendFileSync(process.env.FAKE_LOG, JSON.stringify(endpoint) + '\n'); + if (process.env.FAKE_MODE.startsWith('qualification-')) { + const mode = process.env.FAKE_MODE; + const dispatched = fs.existsSync(process.env.FAKE_DISPATCH); + const runId = dispatched ? 88 : 77; + const record = (id, status = 'completed', conclusion = 'success') => ({ + id, + head_sha: 'a'.repeat(40), + workflow_id: 9, + run_attempt: 3, + event: id === 88 ? 'workflow_dispatch' : 'push', + display_title: + id === 88 ? `CI / qualification / ${process.env.QUALIFICATION_REQUEST_KEY}` : 'CI / main', + head_branch: 'main', + status, + conclusion, + html_url: `https://github.com/f0rr0/oliphaunt/actions/runs/${id}`, + }); + if (/actions\/workflows[?]/.test(endpoint)) + return Response.json({ workflows: [{ id: 9, name: 'CI' }] }); + if (/actions\/workflows\/9$/.test(endpoint)) return Response.json({ id: 9, name: 'CI' }); + if (/git\/ref\/heads\/main$/.test(endpoint)) + return Response.json({ + object: { sha: (mode === 'qualification-advanced' ? 'b' : 'a').repeat(40) }, + }); + if (/actions\/workflows\/9\/runs[?]/.test(endpoint)) { + const count = fs.existsSync(process.env.FAKE_STATE) + ? Number(fs.readFileSync(process.env.FAKE_STATE, 'utf8')) + : 0; + fs.writeFileSync(process.env.FAKE_STATE, String(count + 1)); + if (mode === 'qualification-failed') + return Response.json({ workflow_runs: [record(77, 'completed', 'failure')] }); + if (mode === 'qualification-active' && count === 0) + return Response.json({ workflow_runs: [record(77, 'in_progress', '')] }); + const missing = + [ + 'qualification-absent', + 'qualification-advanced', + 'qualification-ambiguous', + 'qualification-race', + ].includes(mode) && !dispatched; + return Response.json({ workflow_runs: missing ? [] : [record(runId)] }); + } + const match = endpoint.match(/actions\/runs\/(77|88)(?:\/(jobs|artifacts))?(?:\?.*)?$/); + if (match) { + const id = Number(match[1]); + if (match[2] === 'jobs') + return Response.json({ + jobs: [ + { + id: 501, + name: 'Qualified', + status: 'completed', + conclusion: 'success', + run_attempt: 3, + }, + ], + }); + if (match[2] === 'artifacts') { + const bytes = fs.readFileSync(`${process.env.FAKE_ARCHIVE_ROOT}/${id}.zip`); + return Response.json({ + artifacts: [ + { + id, + name: 'oliphaunt-release-candidate', + size_in_bytes: bytes.length, + expired: false, + digest: 'sha256:' + createHash('sha256').update(bytes).digest('hex'), + }, + ], + }); + } + return Response.json({ + ...record(id), + ...(mode === 'qualification-race' && id === 88 ? { head_sha: 'b'.repeat(40) } : {}), + }); + } + const archive = endpoint.match(/actions\/artifacts\/(77|88)\/zip$/); + if (archive) + return new Response(fs.readFileSync(`${process.env.FAKE_ARCHIVE_ROOT}/${archive[1]}.zip`)); + throw new Error('unexpected qualification endpoint ' + endpoint); + } + if (/actions\/runs\/77\/jobs/.test(endpoint)) { + const jobs = [ + { + name: process.env.FAKE_RELEASE ? 'Prepare frozen publication candidate' : 'Qualified', + conclusion: process.env.FAKE_MODE === 'failed-candidate' ? 'failure' : 'success', + }, + ]; + if (process.env.FAKE_MODE === 'duplicate-job') jobs.push({ ...jobs[0] }); + return Response.json({ jobs }); + } + if (/actions\/workflows[?]/.test(endpoint)) { + return Response.json({ workflows: [{ id: 9, name: 'CI' }] }); + } + if (/actions\/workflows\/9\/runs[?]/.test(endpoint)) { + const state = process.env.FAKE_STATE; + const count = fs.existsSync(state) ? Number(fs.readFileSync(state, 'utf8')) : 0; + fs.writeFileSync(state, String(count + 1)); + if (process.env.FAKE_MODE === 'transient' && count === 0) { + return new Response('unavailable', { status: 503 }); + } + if (process.env.FAKE_MODE === 'permanent') { + return new Response('bad credentials', { status: 401 }); + } + const selected = { + id: 77, + head_sha: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + status: 'completed', + conclusion: 'success', + run_attempt: 3, + html_url: 'https://example.invalid/run/77', + event: 'push', + }; + const page = new URL('https://api.github.com/' + endpoint).searchParams.get('page'); + const workflow_runs = + process.env.FAKE_MODE === 'beyond-first-page' + ? page === '1' + ? Array.from({ length: 100 }, (_, index) => ({ + ...selected, + id: 100 + index, + conclusion: 'failure', + })) + : [selected] + : [selected]; + const link = + process.env.FAKE_MODE === 'beyond-first-page' && page === '1' + ? '; rel="next", ; rel="last"' + : ''; + return Response.json({ workflow_runs }, { headers: link ? { link } : {} }); + } + if (/actions\/runs\/77\/artifacts/.test(endpoint)) { + const artifact = { + id: 901, + name: 'required-artifact', + size_in_bytes: 123, + digest: 'sha256:' + '1'.repeat(64), + expired: false, + }; + const gateArtifact = { + id: 903, + name: 'gate-artifact', + size_in_bytes: 456, + digest: 'sha256:' + '2'.repeat(64), + expired: false, + }; + const artifacts = + process.env.FAKE_MODE === 'duplicate-artifact' + ? [artifact, { ...artifact, id: 902 }] + : process.env.FAKE_MODE === 'expired-artifact' + ? [{ ...artifact, expired: true }] + : process.env.FAKE_MODE === 'missing-gate-artifact' + ? [artifact] + : process.env.FAKE_MODE === 'malformed-artifact-metadata' + ? [{ ...artifact, digest: undefined }] + : [artifact, gateArtifact]; + return Response.json({ artifacts }); + } + if (/actions\/runs\/77$/.test(endpoint)) { + if (process.env.FAKE_MODE === 'metadata-auth') + return new Response('bad credentials', { status: 401 }); + if (process.env.FAKE_MODE === 'metadata-transient') + return new Response('unavailable', { status: 503 }); + const sha = + process.env.FAKE_MODE === 'wrong-sha' + ? 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' + : process.env.FAKE_MODE === 'upper-sha' + ? 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + : 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; + const status = process.env.FAKE_MODE === 'in-progress-run' ? 'in_progress' : 'completed'; + const conclusion = + process.env.FAKE_MODE === 'in-progress-run' + ? '' + : process.env.FAKE_MODE === 'failed-run' || + (process.env.FAKE_RELEASE && + ['failed-candidate', 'duplicate-job', 'expired-artifact', 'wrong-sha'].includes( + process.env.FAKE_MODE, + )) + ? 'failure' + : 'success'; + return Response.json({ + head_sha: sha, + workflow_id: 9, + event: process.env.FAKE_RELEASE ? 'workflow_dispatch' : 'push', + status, + conclusion, + run_attempt: 3, + }); + } + if (/actions\/workflows\/9$/.test(endpoint)) { + return Response.json({ name: process.env.FAKE_RELEASE ? 'Release' : 'CI' }); + } + throw new Error('unexpected GitHub endpoint ' + endpoint); +}; diff --git a/tools/release/toolchain-bootstrap.test.mjs b/tools/release/toolchain-bootstrap.test.mjs deleted file mode 100644 index 64a0e1a66..000000000 --- a/tools/release/toolchain-bootstrap.test.mjs +++ /dev/null @@ -1,256 +0,0 @@ -import assert from 'node:assert/strict'; -import {spawn} from 'node:child_process'; -import {EventEmitter} from 'node:events'; -import {test} from 'node:test'; - -const LOCAL_SCRIPT_TIMEOUT_MS = 55_000; -const TERMINATION_GRACE_MS = 5_000; -const WINDOWS_TASKKILL_TIMEOUT_MS = 5_000; -const MAX_CAPTURE_BYTES = 4 * 1024 * 1024; -const INSTALLER_FAULT_SUITES = [ - {script: 'tools/dev/extract-pinned-zip.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: 'tools/dev/install-pinned-js-runtime.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: 'tools/dev/install-pinned-winflexbison.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: 'tools/dev/setup-android-sdk.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: 'tools/dev/setup-maestro.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: 'tools/dev/start-android-emulator-ci.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: '.github/actions/setup-moon/install-pinned-node.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: '.github/actions/setup-moon/install-pinned-toolchain.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: '.github/actions/setup-node-pnpm/install-pinned-pnpm.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: '.github/actions/setup-npm-publisher/install.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, - {script: '.github/scripts/setup-native-build-tools.test.sh', timeoutMs: LOCAL_SCRIPT_TIMEOUT_MS}, -]; - -function appendBounded(chunks, state, chunk, label) { - state.bytes += chunk.length; - if (state.bytes > MAX_CAPTURE_BYTES) { - throw new Error(`${label} exceeded the ${MAX_CAPTURE_BYTES}-byte diagnostic bound`); - } - chunks.push(chunk); -} - -function processExists(pid) { - try { - process.kill(pid, 0); - return true; - } catch (error) { - if (error?.code === 'ESRCH') return false; - throw error; - } -} - -export function forceWindowsProcessTree(pid, { - spawnImpl = spawn, - timeoutMs = WINDOWS_TASKKILL_TIMEOUT_MS, -} = {}) { - return new Promise((resolve, reject) => { - const killer = spawnImpl('taskkill.exe', ['/PID', String(pid), '/T', '/F'], { - stdio: ['ignore', 'ignore', 'pipe'], - windowsHide: true, - }); - const stderr = []; - let stderrBytes = 0; - let settled = false; - const settle = (callback) => { - if (settled) return; - settled = true; - clearTimeout(timer); - callback(); - }; - killer.stderr.on('data', (chunk) => { - stderrBytes += chunk.length; - if (stderrBytes <= 64 * 1024) { - stderr.push(chunk); - return; - } - killer.kill('SIGKILL'); - settle(() => reject(new Error('taskkill.exe exceeded its 65536-byte diagnostic bound'))); - }); - killer.on('error', (error) => settle(() => reject(error))); - killer.on('close', (code) => settle(() => { - if (code === 0) { - resolve(); - return; - } - reject(new Error( - `taskkill.exe failed with code ${code}: ${Buffer.concat(stderr).toString('utf8').trim()}`, - )); - })); - const timer = setTimeout(() => { - let killDetail = ''; - try { - killer.kill('SIGKILL'); - } catch (error) { - killDetail = `; could not kill taskkill.exe: ${error.message}`; - } - settle(() => reject(new Error( - `taskkill.exe did not close within ${timeoutMs}ms${killDetail}`, - ))); - }, timeoutMs); - }); -} - -function signalTree(child, signal) { - if (child.pid === undefined) return Promise.resolve(); - if (process.platform === 'win32') { - // Node cannot deliver POSIX signals to a Windows process group. taskkill's - // /T /F boundary atomically targets Bash and its descendants while the - // parent PID is still live. Awaiting the bounded taskkill process prevents - // a parent-only close event from being mistaken for complete tree cleanup. - return forceWindowsProcessTree(child.pid); - } - try { - process.kill(-child.pid, signal); - } catch (error) { - if (error?.code !== 'ESRCH') throw error; - } - return Promise.resolve(); -} - -test('Windows process-tree termination bounds a non-closing taskkill process', {timeout: 2_000}, async () => { - const killer = new EventEmitter(); - killer.stderr = new EventEmitter(); - let killedWith; - killer.kill = (signal) => { - killedWith = signal; - return true; - }; - await assert.rejects( - forceWindowsProcessTree(4242, {spawnImpl: () => killer, timeoutMs: 25}), - /taskkill[.]exe did not close within 25ms/u, - ); - assert.equal(killedWith, 'SIGKILL'); -}); - -export function runBoundedBash(args, { - label = `bash ${args.join(' ')}`, - timeoutMs, - terminationGraceMs = TERMINATION_GRACE_MS, -} = {}) { - return new Promise((resolve, reject) => { - const child = spawn('bash', args, { - detached: true, - stdio: ['ignore', 'pipe', 'pipe'], - windowsHide: true, - }); - const stdout = []; - const stderr = []; - const stdoutState = {bytes: 0}; - const stderrState = {bytes: 0}; - let failure; - let completed = false; - let closeTimer; - let pendingClose; - let terminationComplete = false; - - const diagnostics = () => [ - `stdout:\n${Buffer.concat(stdout).toString('utf8')}`, - `stderr:\n${Buffer.concat(stderr).toString('utf8')}`, - ].join('\n'); - const finish = (callback) => { - if (completed) return; - completed = true; - clearTimeout(timeoutTimer); - clearTimeout(closeTimer); - callback(); - }; - const completeClose = ({code, signal}) => finish(() => { - if (failure !== undefined) { - reject(new Error(`${failure.message}\n${diagnostics()}`, {cause: failure})); - } else if (code !== 0) { - reject(new Error(`${label} exited with code ${code} and signal ${signal}\n${diagnostics()}`)); - } else { - resolve(); - } - }); - const terminate = (reason) => { - if (failure !== undefined) return; - failure = reason; - void (async () => { - try { - if (process.platform === 'win32') { - await signalTree(child, 'SIGKILL'); - } else { - await signalTree(child, 'SIGTERM'); - await new Promise((resolveDelay) => setTimeout(resolveDelay, terminationGraceMs)); - await signalTree(child, 'SIGKILL'); - } - } catch (error) { - failure = new Error(`${reason.message}; could not terminate process tree: ${error.message}`, {cause: reason}); - } - terminationComplete = true; - if (pendingClose !== undefined) { - completeClose(pendingClose); - return; - } - closeTimer = setTimeout(() => finish(() => reject(new Error( - `${failure.message}; process tree did not close after forced termination\n${diagnostics()}`, - {cause: failure}, - ))), terminationGraceMs); - })(); - }; - const timeoutTimer = setTimeout(() => terminate( - new Error(`${label} did not complete within ${timeoutMs}ms`), - ), timeoutMs); - - child.stdout.on('data', (chunk) => { - try { - appendBounded(stdout, stdoutState, chunk, `${label} stdout`); - } catch (error) { - terminate(error); - } - }); - child.stderr.on('data', (chunk) => { - try { - appendBounded(stderr, stderrState, chunk, `${label} stderr`); - } catch (error) { - terminate(error); - } - }); - child.on('error', (error) => finish(() => reject(new Error( - `${label} failed to start: ${error.message}`, - {cause: error}, - )))); - child.on('close', (code, signal) => { - const result = {code, signal}; - if (failure !== undefined && !terminationComplete) { - pendingClose = result; - return; - } - completeClose(result); - }); - }); -} - -test('bounded bootstrap runner kills a TERM-ignoring foreground process group', {timeout: 8_000}, async () => { - const started = Date.now(); - let observed; - try { - await runBoundedBash(['-c', `trap '' TERM; node -e 'console.log("descendant=" + process.pid); process.on("SIGTERM", () => {}); setInterval(() => {}, 1000)'`], { - label: 'TERM-ignoring bootstrap fixture', - // Node startup can be delayed by the other cold bootstrap suites. The - // short termination grace below, descendant liveness assertion, and - // outer test deadline prove cleanup independently of startup latency. - timeoutMs: 2_000, - terminationGraceMs: 200, - }); - } catch (error) { - observed = error; - } - assert(observed instanceof Error, 'TERM-ignoring process fixture unexpectedly succeeded'); - assert.match(observed.message, /did not complete within 2000ms/u); - const descendant = /descendant=(\d+)/u.exec(observed.message); - assert(descendant !== null, `timeout diagnostics omitted the descendant PID: ${observed.message}`); - const descendantPid = Number.parseInt(descendant[1], 10); - for (let attempt = 0; attempt < 20 && processExists(descendantPid); attempt += 1) { - await new Promise((resolveDelay) => setTimeout(resolveDelay, 25)); - } - assert(!processExists(descendantPid), 'TERM-ignoring descendant remained alive after process-tree termination'); - assert(Date.now() - started < 5_000, 'TERM-ignoring process group was not killed promptly'); -}); - -for (const {script, timeoutMs} of INSTALLER_FAULT_SUITES) { - test(`pinned toolchain bootstrap path fails closed: ${script}`, { - timeout: timeoutMs + (TERMINATION_GRACE_MS * 2) + 5_000, - }, async () => runBoundedBash([script], {label: script, timeoutMs})); -} diff --git a/tools/release/trusted-publisher-config.mjs b/tools/release/trusted-publisher-config.mjs deleted file mode 100644 index fe5f725e3..000000000 --- a/tools/release/trusted-publisher-config.mjs +++ /dev/null @@ -1,920 +0,0 @@ -#!/usr/bin/env bun - -import { spawnSync } from "node:child_process"; -import { randomUUID } from "node:crypto"; -import { link, lstat, open, unlink } from "node:fs/promises"; -import process from "node:process"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { - DEFAULT_PUBLICATION_LOCK, - loadPublicationLock, - lockedCarriers, -} from "./publication-lock.mjs"; -import { - validateNpmTrustCliHelp, - validateNpmTrustCliRuntime, -} from "./npm-trusted-publishing-runtime.mjs"; -import { registryRetryDelaySeconds, registryStatusRetryable } from "./registry-http-retry.mjs"; -import { ROOT } from "./release-graph.mjs"; - -export const TRUSTED_PUBLISHER_PLAN_SCHEMA = "oliphaunt-trusted-publisher-plan-v1"; -export const TRUSTED_PUBLISHER_REPORT_SCHEMA = "oliphaunt-trusted-publisher-report-v1"; -export const NPM_TRUST_BATCH_SIZE = 25; -export const NPM_TRUST_REQUEST_SPACING_MS = 2_000; -export const CRATES_IO_TRUST_REQUEST_SPACING_MS = 250; - -export const EXPECTED_TRUSTED_PUBLISHER = Object.freeze({ - repository: "f0rr0/oliphaunt", - repositoryOwner: "f0rr0", - repositoryName: "oliphaunt", - workflowFilename: "release.yml", - environment: "release-publish", - npmPermissions: Object.freeze(["createPackage"]), -}); - -const CRATES_IO_CONFIG_ENDPOINT = "https://crates.io/api/v1/trusted_publishing/github_configs"; -const MAX_RESPONSE_BYTES = 256 * 1024; -const REQUEST_TIMEOUT_MS = 30_000; -const NPM_TRUST_MUTATION_TIMEOUT_MS = 5 * 60_000; -const MAX_READ_ATTEMPTS = 3; -const NPM_REGISTRY = "https://registry.npmjs.org/"; -const NPM_READ_NETWORK_ENV = Object.freeze({ - NPM_CONFIG_FETCH_RETRIES: "3", - NPM_CONFIG_FETCH_RETRY_MINTIMEOUT: "1000", - NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT: "5000", - NPM_CONFIG_FETCH_TIMEOUT: "20000", -}); -const NPM_NO_REPLAY_NETWORK_ENV = Object.freeze({ - NPM_CONFIG_FETCH_RETRIES: "0", - NPM_CONFIG_FETCH_RETRY_MINTIMEOUT: "1000", - NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT: "5000", - NPM_CONFIG_FETCH_TIMEOUT: "20000", -}); - -function error(message) { - return new Error(`trusted-publisher-config: ${message}`); -} - -function compareText(left, right) { - const leftText = String(left); - const rightText = String(right); - return leftText < rightText ? -1 : leftText > rightText ? 1 : 0; -} - -function stableJson(value) { - if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`; - if (value !== null && typeof value === "object") { - return `{${Object.keys(value).sort(compareText).map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`; - } - return JSON.stringify(value); -} - -function selectedProducts(lock, products) { - if (products === undefined) return undefined; - if ( - !Array.isArray(products) - || products.length === 0 - || products.some((product) => typeof product !== "string" || product.length === 0) - || new Set(products).size !== products.length - ) { - throw error("products must be a non-empty unique string list"); - } - const known = new Set(lock.products.map(({ id }) => id)); - const unknown = products.filter((product) => !known.has(product)); - if (unknown.length > 0) throw error(`products are absent from the exact lock: ${unknown.join(", ")}`); - return new Set(products); -} - -function batchRows(identities, size = NPM_TRUST_BATCH_SIZE) { - const batches = []; - for (let start = 0; start < identities.length; start += size) { - const rows = identities.slice(start, start + size); - batches.push({ - number: batches.length + 1, - count: rows.length, - first: rows[0].id, - last: rows.at(-1).id, - }); - } - return batches; -} - -export function buildTrustedPublisherPlan(lock, { products = undefined } = {}) { - const selected = selectedProducts(lock, products); - const identities = lockedCarriers(lock) - .filter((carrier) => selected === undefined || selected.has(carrier.product)) - .filter((carrier) => carrier.ecosystem === "cargo" || carrier.ecosystem === "npm") - .map(({ id, ecosystem, name, product, version }) => ({ id, ecosystem, name, product, version })) - .sort((left, right) => compareText(left.id, right.id)); - const unique = new Set(identities.map(({ id }) => id)); - if (unique.size !== identities.length) throw error("exact lock contains duplicate npm/Cargo identities"); - const npm = identities.filter(({ ecosystem }) => ecosystem === "npm"); - const cargo = identities.filter(({ ecosystem }) => ecosystem === "cargo"); - return { - schema: TRUSTED_PUBLISHER_PLAN_SCHEMA, - lockDigest: lock.lockDigest, - catalogDigest: lock.catalogDigest, - source: lock.source, - products: lock.products.filter(({ id }) => selected === undefined || selected.has(id)).map(({ id, version }) => ({ id, version })), - expected: EXPECTED_TRUSTED_PUBLISHER, - counts: { cargo: cargo.length, npm: npm.length, total: identities.length }, - npmBatchSize: NPM_TRUST_BATCH_SIZE, - npmBatches: batchRows(npm), - identities, - }; -} - -export function selectTrustedPublisherIdentities(plan, ecosystem, batch = undefined) { - if (ecosystem !== "cargo" && ecosystem !== "npm") { - throw error("--ecosystem must be cargo or npm for audit/apply"); - } - const identities = plan.identities.filter((identity) => identity.ecosystem === ecosystem); - if (identities.length === 0) throw error(`exact lock selects no ${ecosystem} identities`); - if (ecosystem === "cargo") { - if (batch !== undefined) throw error("--batch is used only for npm's bounded 2FA windows"); - return { identities, batch: null, batches: 1 }; - } - const batches = batchRows(identities); - if (!Number.isSafeInteger(batch) || batch < 1 || batch > batches.length) { - throw error(`npm audit/apply requires --batch N from 1 through ${batches.length}`); - } - const start = (batch - 1) * NPM_TRUST_BATCH_SIZE; - return { - identities: identities.slice(start, start + NPM_TRUST_BATCH_SIZE), - batch, - batches: batches.length, - }; -} - -function relevantNpmConfig(config) { - return { - type: config?.type ?? null, - repository: config?.repository ?? null, - file: config?.file ?? null, - environment: config?.environment ?? null, - permissions: Array.isArray(config?.permissions) ? [...config.permissions].sort(compareText) : null, - }; -} - -function relevantCratesConfig(config) { - return { - crate: config?.crate ?? null, - repository_owner: config?.repository_owner ?? null, - repository_name: config?.repository_name ?? null, - workflow_filename: config?.workflow_filename ?? null, - environment: config?.environment ?? null, - }; -} - -function exactNpmConfig(config) { - const expected = { - type: "github", - repository: EXPECTED_TRUSTED_PUBLISHER.repository, - file: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, - environment: EXPECTED_TRUSTED_PUBLISHER.environment, - permissions: [...EXPECTED_TRUSTED_PUBLISHER.npmPermissions], - }; - return stableJson(relevantNpmConfig(config)) === stableJson(expected); -} - -function exactCratesConfig(config, name) { - const expected = { - crate: name, - repository_owner: EXPECTED_TRUSTED_PUBLISHER.repositoryOwner, - repository_name: EXPECTED_TRUSTED_PUBLISHER.repositoryName, - workflow_filename: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, - environment: EXPECTED_TRUSTED_PUBLISHER.environment, - }; - return stableJson(relevantCratesConfig(config)) === stableJson(expected); -} - -export function classifyNpmTrustConfigs(configs) { - if (!Array.isArray(configs)) throw error("npm trust list output must be a JSON object, array, or empty output"); - if (configs.length === 0) return { state: "missing" }; - if (configs.length === 1 && exactNpmConfig(configs[0])) return { state: "exact" }; - return { - state: "conflict", - reason: `expected exactly one publish-only GitHub configuration; observed ${JSON.stringify(configs.map(relevantNpmConfig))}`, - }; -} - -export function classifyCratesIoTrustConfigs(configs, name) { - if (!Array.isArray(configs)) throw error("crates.io github_configs must be an array"); - if (configs.length === 0) return { state: "missing" }; - if (configs.length === 1 && exactCratesConfig(configs[0], name)) return { state: "exact" }; - return { - state: "conflict", - reason: `expected exactly one GitHub configuration; observed ${JSON.stringify(configs.map(relevantCratesConfig))}`, - }; -} - -function parseNpmJson(text, context) { - const value = text.trim(); - if (value === "") return []; - let parsed; - try { - parsed = JSON.parse(value); - } catch { - throw error(`${context} returned invalid JSON`); - } - return Array.isArray(parsed) ? parsed : [parsed]; -} - -function npmPackageName(name) { - if ( - typeof name !== "string" - || name.length === 0 - || name.length > 214 - || /[\u0000-\u0020\u007f]/u.test(name) - || !/^@oliphaunt\/[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/u.test(name) - ) { - throw error("npm package name must be a canonical bounded @oliphaunt identity"); - } - return name; -} - -export function npmTrustListArgs(name) { - return [ - "trust", "list", npmPackageName(name), - "--json", - "--registry", NPM_REGISTRY, - ]; -} - -export function npmTrustGithubArgs(name) { - return [ - "trust", "github", npmPackageName(name), - "--file", EXPECTED_TRUSTED_PUBLISHER.workflowFilename, - "--repo", EXPECTED_TRUSTED_PUBLISHER.repository, - "--env", EXPECTED_TRUSTED_PUBLISHER.environment, - "--allow-publish", - "--yes", - "--json", - "--registry", NPM_REGISTRY, - ]; -} - -function sameArguments(left, right) { - return left.length === right.length && left.every((value, index) => value === right[index]); -} - -function npmCommandPolicy(args, { interactiveAudit = false } = {}) { - if (!Array.isArray(args) || args.some((arg) => typeof arg !== "string")) { - throw error("npm command arguments must be a string list"); - } - if (args.length === 1 && args[0] === "--version") { - if (interactiveAudit) throw error("interactive audit mode is valid only for npm trust list"); - return { - interactive: false, - networkEnv: NPM_NO_REPLAY_NETWORK_ENV, - timeout: REQUEST_TIMEOUT_MS, - }; - } - if ( - sameArguments(args, ["trust", "list", "--help"]) - || sameArguments(args, ["trust", "github", "--help"]) - ) { - if (interactiveAudit) throw error("interactive audit mode is valid only for npm trust list"); - return { - interactive: false, - networkEnv: NPM_NO_REPLAY_NETWORK_ENV, - timeout: REQUEST_TIMEOUT_MS, - }; - } - if (args[0] === "trust" && args[1] === "list") { - const expected = npmTrustListArgs(args[2]); - if (!sameArguments(args, expected)) { - throw error(`refusing unsupported npm trust list arguments ${JSON.stringify(args.slice(3))}`); - } - return { - interactive: interactiveAudit, - networkEnv: NPM_READ_NETWORK_ENV, - timeout: interactiveAudit ? NPM_TRUST_MUTATION_TIMEOUT_MS : REQUEST_TIMEOUT_MS, - }; - } - if (args[0] === "trust" && args[1] === "github") { - if (interactiveAudit) throw error("interactive audit mode is valid only for npm trust list"); - const expected = npmTrustGithubArgs(args[2]); - if (!sameArguments(args, expected)) { - throw error(`refusing unsupported npm trust github arguments ${JSON.stringify(args.slice(3))}`); - } - return { - interactive: true, - networkEnv: NPM_NO_REPLAY_NETWORK_ENV, - timeout: NPM_TRUST_MUTATION_TIMEOUT_MS, - }; - } - throw error(`refusing unsupported npm management command ${JSON.stringify(args.slice(0, 2))}`); -} - -export function runNpmTrustCommand(args, context, { - spawnImpl = undefined, - interactiveAudit = false, - stdinIsTTY = process.stdin.isTTY === true, - stdoutIsTTY = process.stdout.isTTY === true, -} = {}) { - const policy = npmCommandPolicy(args, { interactiveAudit }); - if (policy.interactive && (!stdinIsTTY || !stdoutIsTTY)) { - throw error( - `${context} requires an interactive terminal because npm may require web or classic OTP authentication`, - ); - } - const spawnOptions = { - cwd: ROOT, - ...(policy.interactive ? {} : { encoding: "utf8", maxBuffer: MAX_RESPONSE_BYTES }), - env: { - ...process.env, - ...policy.networkEnv, - }, - // npm's OTP handler deliberately refuses to prompt unless both stdin and - // stdout are TTYs. A single read-only list warm-up and each mutation own - // the terminal; every list used as classification evidence is separately - // captured and bounded. - stdio: policy.interactive ? "inherit" : ["ignore", "pipe", "pipe"], - timeout: policy.timeout, - windowsHide: true, - }; - const result = spawnImpl !== undefined - ? spawnImpl("npm", args, spawnOptions) - : policy.interactive - ? spawnSync("npm", args, { - cwd: ROOT, - env: spawnOptions.env, - stdio: "inherit", - timeout: policy.timeout, - windowsHide: true, - }) - : captureCommandOutput("npm", args, { - cwd: ROOT, - env: spawnOptions.env, - label: `npm ${args.join(" ")}`, - maxOutputBytes: MAX_RESPONSE_BYTES, - timeout: policy.timeout, - windowsHide: true, - }); - if (result.error !== undefined || result.status !== 0) { - const detail = String(result.stderr ?? result.error?.message ?? "") - .replace(/[\r\n\t]+/gu, " ") - .trim() - .slice(0, 300); - const failure = error( - `${context} failed${Number.isInteger(result.status) ? ` with exit ${result.status}` : ""}` - + `${detail ? `: ${detail}` : ""}; no mutation is retried automatically`, - ); - if ( - args[0] === "trust" - && args[1] === "list" - && (/\bEOTP\b/u.test(detail) || /one-time pass(?:word)?/iu.test(detail)) - ) { - failure.npmAuthenticationRequired = true; - } - throw failure; - } - return result.stdout ?? ""; -} - -export function createNpmTrustClient({ - runImpl = runNpmTrustCommand, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), -} = {}) { - return { - checkRuntime() { - const version = runImpl(["--version"], "npm --version").trim(); - validateNpmTrustCliRuntime(version); - validateNpmTrustCliHelp({ - listHelp: runImpl( - ["trust", "list", "--help"], - "npm trust list --help", - ), - githubHelp: runImpl( - ["trust", "github", "--help"], - "npm trust github --help", - ), - }); - return version; - }, - authorizeAudit(name) { - runImpl( - npmTrustListArgs(name), - `npm trust list authentication warm-up for ${name}`, - { interactiveAudit: true }, - ); - // This read-only ceremony's inherited display is deliberately discarded. - // Only a separate captured list can become classification evidence. - }, - async list(name) { - const args = npmTrustListArgs(name); - let output; - try { - output = runImpl(args, `npm trust list ${name}`); - } catch (cause) { - if (cause?.npmAuthenticationRequired !== true) throw cause; - await sleepImpl(NPM_TRUST_REQUEST_SPACING_MS); - this.authorizeAudit(name); - await sleepImpl(NPM_TRUST_REQUEST_SPACING_MS); - try { - output = runImpl(args, `npm trust list ${name} after authentication warm-up`); - } catch (retryCause) { - if (retryCause?.npmAuthenticationRequired === true) { - throw error( - `npm trust list ${name} still requires OTP after the bounded read-only warm-up; ` - + "select npm's five-minute authentication window and retry the command", - ); - } - throw retryCause; - } - } - return parseNpmJson(output, `npm trust list ${name}`); - }, - create(name) { - runImpl(npmTrustGithubArgs(name), `npm trust github ${name}`); - // The interactive command must own stdout so npm can expose its web/OTP - // dialogue. The caller immediately performs an authenticated list and - // accepts only the exact immutable configuration, so command output is - // intentionally not an authorization signal. - }, - }; -} - -function safeToken(value) { - if (typeof value !== "string" || value.length === 0 || value.length > 16 * 1024 || /[\u0000-\u001f\u007f]/u.test(value)) { - throw error("CRATES_IO_TRUST_CONFIG_TOKEN must be a non-empty control-free secret"); - } - return value; -} - -async function boundedText(response, context) { - const declared = Number(response.headers.get("content-length")); - if (Number.isFinite(declared) && declared > MAX_RESPONSE_BYTES) { - await response.body?.cancel?.().catch(() => {}); - throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); - } - const reader = response.body?.getReader?.(); - if (reader === undefined) { - const text = await response.text(); - if (Buffer.byteLength(text) > MAX_RESPONSE_BYTES) throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); - return text; - } - const chunks = []; - let size = 0; - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > MAX_RESPONSE_BYTES) { - await reader.cancel().catch(() => {}); - throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - return Buffer.concat(chunks).toString("utf8"); -} - -async function responseJson(response, context) { - const text = await boundedText(response, context); - if (!response.ok) throw error(`${context} returned HTTP ${response.status}`); - try { - return JSON.parse(text); - } catch { - throw error(`${context} returned invalid JSON`); - } -} - -function requestSignal() { - return AbortSignal.timeout(REQUEST_TIMEOUT_MS); -} - -export function createCratesIoTrustClient({ - token = process.env.CRATES_IO_TRUST_CONFIG_TOKEN, - fetchImpl = fetch, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), -} = {}) { - const secret = safeToken(token); - const headers = { - Accept: "application/json", - Authorization: `Bearer ${secret}`, - "User-Agent": "oliphaunt-trust-config/1; https://github.com/f0rr0/oliphaunt", - }; - return { - async list(name) { - const url = new URL(CRATES_IO_CONFIG_ENDPOINT); - url.searchParams.set("crate", name); - url.searchParams.set("per_page", "100"); - let lastError; - for (let attempt = 0; attempt < MAX_READ_ATTEMPTS; attempt += 1) { - try { - const response = await fetchImpl(url, { - method: "GET", - headers, - redirect: "error", - signal: requestSignal(), - }); - if (registryStatusRetryable(response.status) && attempt + 1 < MAX_READ_ATTEMPTS) { - const seconds = registryRetryDelaySeconds({ headers: response.headers, attempt }); - await boundedText(response, `crates.io trust audit for ${name}`); - await sleepImpl(seconds * 1_000); - continue; - } - const body = await responseJson(response, `crates.io trust audit for ${name}`); - if (!Array.isArray(body?.github_configs)) throw error(`crates.io trust audit for ${name} omitted github_configs`); - if (body.github_configs.length > 5) throw error(`crates.io trust audit for ${name} exceeded the registry's five-config limit`); - return body.github_configs; - } catch (cause) { - lastError = cause; - if ( - attempt + 1 >= MAX_READ_ATTEMPTS - || !(cause?.name === "TimeoutError" || cause instanceof TypeError) - ) throw cause; - await sleepImpl(registryRetryDelaySeconds({ attempt }) * 1_000); - } - } - throw lastError; - }, - async create(name) { - const response = await fetchImpl(CRATES_IO_CONFIG_ENDPOINT, { - method: "POST", - headers: { ...headers, "Content-Type": "application/json" }, - body: JSON.stringify({ - github_config: { - crate: name, - repository_owner: EXPECTED_TRUSTED_PUBLISHER.repositoryOwner, - repository_name: EXPECTED_TRUSTED_PUBLISHER.repositoryName, - workflow_filename: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, - environment: EXPECTED_TRUSTED_PUBLISHER.environment, - }, - }), - redirect: "error", - signal: requestSignal(), - }); - const body = await responseJson(response, `crates.io trust creation for ${name}`); - if (!exactCratesConfig(body?.github_config, name)) { - throw error(`crates.io created an unexpected trusted-publisher configuration for ${name}`); - } - }, - }; -} - -async function auditIdentities({ identities, ecosystem, client, spacingMs, sleepImpl, progress }) { - const results = []; - if (ecosystem === "npm") { - if (typeof client.authorizeAudit !== "function") { - throw error("npm client must implement the read-only interactive audit authentication warm-up"); - } - await client.authorizeAudit(identities[0].name); - await sleepImpl(spacingMs); - } - for (const [index, identity] of identities.entries()) { - const configs = await client.list(identity.name); - const classified = ecosystem === "npm" - ? classifyNpmTrustConfigs(configs) - : classifyCratesIoTrustConfigs(configs, identity.name); - results.push({ id: identity.id, ...classified }); - progress?.(`audit ${index + 1}/${identities.length} ${identity.id}: ${classified.state}`); - await sleepImpl(spacingMs); - } - return results; -} - -function reportEnvelope({ plan, selection, ecosystem, mode, initial, final = initial, created = [] }) { - const states = (rows, state) => rows.filter((row) => row.state === state).map(({ id }) => id); - return { - schema: TRUSTED_PUBLISHER_REPORT_SCHEMA, - mode, - ecosystem, - lockDigest: plan.lockDigest, - catalogDigest: plan.catalogDigest, - selection: { - count: selection.identities.length, - batch: selection.batch, - batches: selection.batches, - }, - exact: states(final, "exact"), - missing: states(final, "missing"), - conflicts: final.filter(({ state }) => state === "conflict").map(({ id, reason }) => ({ id, reason })), - created, - initial: { - exact: states(initial, "exact").length, - missing: states(initial, "missing").length, - conflicts: states(initial, "conflict").length, - }, - }; -} - -export async function reconcileTrustedPublishers({ - plan, - ecosystem, - batch = undefined, - apply = false, - client, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), - progress = undefined, -} = {}) { - const selection = selectTrustedPublisherIdentities(plan, ecosystem, batch); - const spacingMs = ecosystem === "npm" ? NPM_TRUST_REQUEST_SPACING_MS : CRATES_IO_TRUST_REQUEST_SPACING_MS; - const initial = await auditIdentities({ ...selection, ecosystem, client, spacingMs, sleepImpl, progress }); - if (!apply || initial.some(({ state }) => state === "conflict")) { - return reportEnvelope({ plan, selection, ecosystem, mode: apply ? "apply-blocked" : "audit", initial }); - } - const missing = new Set(initial.filter(({ state }) => state === "missing").map(({ id }) => id)); - const created = []; - for (const identity of selection.identities.filter(({ id }) => missing.has(id))) { - let mutationFailure; - try { - await client.create(identity.name); - } catch (cause) { - mutationFailure = cause; - } - // A management request can be applied remotely even when its response is - // lost. Never replay it here: inspect the exact immutable configuration, - // accept only the desired state, and let a later invocation resume if the - // registry still reports absence. - await sleepImpl(spacingMs); - const reconciledConfigs = await client.list(identity.name); - const reconciled = ecosystem === "npm" - ? classifyNpmTrustConfigs(reconciledConfigs) - : classifyCratesIoTrustConfigs(reconciledConfigs, identity.name); - if (reconciled.state !== "exact") { - if (mutationFailure !== undefined) throw mutationFailure; - throw error( - `${identity.id} trusted-publisher mutation returned without the exact configuration becoming observable` - + `${reconciled.reason ? `: ${reconciled.reason}` : ""}`, - ); - } - created.push(identity.id); - progress?.( - `${mutationFailure === undefined ? "created" : "reconciled"} ${created.length}/${missing.size} ${identity.id}`, - ); - await sleepImpl(spacingMs); - } - const final = await auditIdentities({ ...selection, ecosystem, client, spacingMs, sleepImpl, progress }); - return reportEnvelope({ plan, selection, ecosystem, mode: "apply", initial, final, created }); -} - -function parseArgs(argv) { - const allowedValues = new Set([ - "lock", - "products-json", - "ecosystem", - "batch", - "confirm-lock-digest", - "output", - ]); - const values = new Map(); - const booleans = new Set(); - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--apply" || arg === "--audit" || arg === "--help" || arg === "-h") { - booleans.add(arg.replace(/^-+/u, "")); - continue; - } - if (!arg.startsWith("--")) throw error(`unexpected positional argument ${arg}`); - const separator = arg.indexOf("="); - const key = arg.slice(2, separator === -1 ? undefined : separator); - if (!allowedValues.has(key)) throw error(`unknown argument --${key}`); - const value = separator === -1 ? argv[++index] : arg.slice(separator + 1); - if (value === undefined || value.length === 0) throw error(`--${key} requires a value`); - if (values.has(key)) throw error(`--${key} may be specified only once`); - values.set(key, value); - } - return { values, booleans }; -} - -function productsValue(raw) { - if (raw === undefined) return undefined; - try { - return JSON.parse(raw); - } catch { - throw error("--products-json must be strict JSON"); - } -} - -function usage() { - return [ - "usage:", - " trusted-publisher-config.mjs [--lock FILE] [--products-json JSON] [--output FILE]", - " trusted-publisher-config.mjs --audit --ecosystem cargo|npm [--batch N] [--lock FILE] [--products-json JSON] [--output FILE]", - " trusted-publisher-config.mjs --apply --confirm-lock-digest SHA256 --ecosystem cargo|npm [--batch N] [--lock FILE] [--products-json JSON] [--output FILE]", - "", - "No --audit/--apply: print an exact-lock plan without registry authentication or network access.", - "--audit: authenticated read-only comparison. --apply: create only missing exact configs, then re-audit.", - "npm requires deterministic batches sized for its documented five-minute 2FA window.", - "Run npm audit/apply directly in an interactive terminal; a read-only warm-up authenticates each audit pass.", - "npm audit/apply requires --output FILE; the report is atomically created with mode 0600 and never overwritten.", - ].join("\n"); -} - -function prettyJson(value) { - return `${JSON.stringify(value, null, 2)}\n`; -} - -export async function writeJson(value, stream = process.stdout) { - const output = prettyJson(value); - await new Promise((resolve, reject) => { - const onError = (cause) => { - stream.off?.("error", onError); - reject(cause); - }; - stream.once?.("error", onError); - stream.write(output, (cause) => { - stream.off?.("error", onError); - if (cause !== undefined && cause !== null) reject(cause); - else resolve(); - }); - }); -} - -export async function reserveJsonFile(outputFile) { - if (typeof outputFile !== "string" || outputFile.length === 0) { - throw error("--output must be a non-empty file path"); - } - const destination = path.resolve(ROOT, outputFile); - const reservation = `${destination}.oliphaunt-reservation`; - const temporary = path.join( - path.dirname(destination), - `.${path.basename(destination)}.tmp-${process.pid}-${randomUUID()}`, - ); - const probe = path.join( - path.dirname(destination), - `.${path.basename(destination)}.probe-${process.pid}-${randomUUID()}`, - ); - let outputHandle; - let reservationHandle; - let reservationCreated = false; - let probeLinked = false; - try { - reservationHandle = await open(reservation, "wx", 0o600); - reservationCreated = true; - await reservationHandle.writeFile( - `Oliphaunt trusted-publisher report reservation for ${destination}\n`, - "utf8", - ); - await reservationHandle.sync(); - await reservationHandle.close(); - reservationHandle = undefined; - outputHandle = await open(temporary, "wx", 0o600); - try { - await lstat(destination); - const exists = new Error("destination exists"); - exists.code = "EEXIST"; - throw exists; - } catch (cause) { - if (cause?.code !== "ENOENT") throw cause; - } - // Exercise the exact no-overwrite atomic publication primitive before any - // registry request. The deterministic reservation blocks cooperating - // invocations while the final destination remains absent for publication. - await link(temporary, probe); - probeLinked = true; - await unlink(probe); - probeLinked = false; - } catch (cause) { - if (reservationHandle !== undefined) await reservationHandle.close().catch(() => {}); - if (outputHandle !== undefined) await outputHandle.close().catch(() => {}); - if (probeLinked) await unlink(probe).catch(() => {}); - await unlink(temporary).catch(() => {}); - if (reservationCreated) await unlink(reservation).catch(() => {}); - if (cause?.code === "EEXIST") { - if (!reservationCreated) { - throw error(`--output reservation already exists for ${destination}`); - } - throw error(`refusing to overwrite existing --output file ${destination}`); - } - throw error(`could not reserve --output file ${destination}: ${cause?.message ?? cause}`); - } - let active = true; - return { - destination, - async commit(value) { - if (!active) throw error(`--output reservation is no longer active for ${destination}`); - try { - await outputHandle.writeFile(prettyJson(value), "utf8"); - await outputHandle.sync(); - await outputHandle.close(); - outputHandle = undefined; - await link(temporary, destination); - active = false; - await unlink(temporary).catch(() => {}); - await unlink(reservation).catch(() => {}); - return destination; - } catch (cause) { - if (cause?.code === "EEXIST") { - throw error(`refusing to overwrite existing --output file ${destination}`); - } - throw error(`could not publish reserved --output file ${destination}: ${cause?.message ?? cause}`); - } - }, - async abort() { - if (!active) return; - active = false; - if (outputHandle !== undefined) await outputHandle.close().catch(() => {}); - await unlink(temporary).catch(() => {}); - await unlink(reservation).catch(() => {}); - }, - }; -} - -export async function writeJsonFile(value, outputFile) { - const reserved = await reserveJsonFile(outputFile); - try { - return await reserved.commit(value); - } finally { - await reserved.abort(); - } -} - -async function emitJson(value, outputFile) { - if (outputFile === undefined) { - await writeJson(value); - return; - } - const destination = await writeJsonFile(value, outputFile); - console.error(`trusted-publisher-config: wrote exact JSON report to ${destination}`); -} - -export async function reconcileTrustedPublishersToFile({ - outputFile, - initialize = async () => {}, - ...options -}) { - const reserved = await reserveJsonFile(outputFile); - try { - await initialize(); - const report = await reconcileTrustedPublishers(options); - const destination = await reserved.commit(report); - console.error(`trusted-publisher-config: wrote exact JSON report to ${destination}`); - return report; - } finally { - await reserved.abort(); - } -} - -async function main(argv) { - const { values, booleans } = parseArgs(argv); - if (booleans.has("help") || booleans.has("h")) { - console.log(usage()); - return 0; - } - if (booleans.has("audit") && booleans.has("apply")) throw error("--audit and --apply are mutually exclusive"); - const lockFile = path.resolve(ROOT, values.get("lock") ?? DEFAULT_PUBLICATION_LOCK); - const plan = buildTrustedPublisherPlan(loadPublicationLock(lockFile), { - products: productsValue(values.get("products-json")), - }); - if (!booleans.has("audit") && !booleans.has("apply")) { - if (values.has("ecosystem") || values.has("batch") || values.has("confirm-lock-digest")) { - throw error("--ecosystem, --batch, and --confirm-lock-digest require --audit or --apply"); - } - await emitJson(plan, values.get("output")); - return 0; - } - const ecosystem = values.get("ecosystem"); - const batch = values.has("batch") ? Number(values.get("batch")) : undefined; - if (ecosystem === "npm" && !values.has("output")) { - throw error("npm audit/apply requires --output FILE so TTY authentication cannot contaminate report evidence"); - } - if (booleans.has("apply")) { - const confirmed = values.get("confirm-lock-digest"); - if (confirmed !== plan.lockDigest) { - throw error(`--confirm-lock-digest must exactly equal ${plan.lockDigest}`); - } - } else if (values.has("confirm-lock-digest")) { - throw error("--confirm-lock-digest is used only with --apply"); - } - let client; - if (ecosystem === "npm") { - client = createNpmTrustClient(); - } else if (ecosystem === "cargo") { - client = createCratesIoTrustClient(); - } - const reconcileOptions = { - plan, - ecosystem, - batch, - apply: booleans.has("apply"), - client, - progress: (line) => console.error(line), - }; - let report; - if (values.has("output")) { - report = await reconcileTrustedPublishersToFile({ - ...reconcileOptions, - outputFile: values.get("output"), - initialize: async () => client?.checkRuntime?.(), - }); - } else { - client?.checkRuntime?.(); - report = await reconcileTrustedPublishers(reconcileOptions); - await writeJson(report); - } - return report.missing.length === 0 && report.conflicts.length === 0 ? 0 : 1; -} - -if (import.meta.main) { - try { - process.exitCode = await main(Bun.argv.slice(2)); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exitCode = 2; - } -} diff --git a/tools/release/trusted-publisher-config.mts b/tools/release/trusted-publisher-config.mts new file mode 100644 index 000000000..54c341377 --- /dev/null +++ b/tools/release/trusted-publisher-config.mts @@ -0,0 +1,846 @@ +#!/usr/bin/env bun + +import { randomUUID } from 'node:crypto'; +import { link, lstat, open, readFile, unlink, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import process from 'node:process'; +import { ROOT } from './release-graph.mts'; +import { validateNpmTrustCliRuntime } from './npm-trusted-publishing-runtime.mts'; +import { + DEFAULT_PUBLICATION_LOCK, + loadPublicationLock, + lockedCarriers, +} from './publication-lock.mts'; +import { registryRetryDelaySeconds, registryStatusRetryable } from './registry-http-retry.mts'; + +export const TRUSTED_PUBLISHER_PLAN_SCHEMA = 'oliphaunt-trusted-publisher-plan-v1'; +export const TRUSTED_PUBLISHER_REPORT_SCHEMA = 'oliphaunt-trusted-publisher-report-v1'; +export const NPM_TRUST_BATCH_SIZE = 25; +export const CRATES_IO_TRUST_REQUEST_SPACING_MS = 250; + +export const EXPECTED_TRUSTED_PUBLISHER = Object.freeze({ + repository: 'f0rr0/oliphaunt', + repositoryOwner: 'f0rr0', + repositoryName: 'oliphaunt', + workflowFilename: 'release.yml', + environment: 'release-publish', + npmPermissions: Object.freeze(['createPackage']), +}); + +const CRATES_IO_CONFIG_ENDPOINT = 'https://crates.io/api/v1/trusted_publishing/github_configs'; +const MAX_RESPONSE_BYTES = 256 * 1024; +const REQUEST_TIMEOUT_MS = 30_000; +const MAX_READ_ATTEMPTS = 3; + +function error(message) { + return new Error(`trusted-publisher-config: ${message}`); +} + +function compareText(left, right) { + const leftText = String(left); + const rightText = String(right); + return leftText < rightText ? -1 : leftText > rightText ? 1 : 0; +} + +function stableJson(value) { + if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`; + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort(compareText) + .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +function selectedProducts(lock, products) { + if (products === undefined) return undefined; + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string' || product.length === 0) || + new Set(products).size !== products.length + ) { + throw error('products must be a non-empty unique string list'); + } + const known = new Set(lock.products.map(({ id }) => id)); + const unknown = products.filter((product) => !known.has(product)); + if (unknown.length > 0) + throw error(`products are absent from the exact lock: ${unknown.join(', ')}`); + return new Set(products); +} + +function batchRows(identities, size = NPM_TRUST_BATCH_SIZE) { + const batches = []; + for (let start = 0; start < identities.length; start += size) { + const rows = identities.slice(start, start + size); + batches.push({ + number: batches.length + 1, + count: rows.length, + first: rows[0].id, + last: rows.at(-1).id, + }); + } + return batches; +} + +export function buildTrustedPublisherPlan(lock, { products = undefined } = {}) { + const selected = selectedProducts(lock, products); + const identities = lockedCarriers(lock) + .filter((carrier) => selected === undefined || selected.has(carrier.product)) + .filter((carrier) => carrier.ecosystem === 'cargo' || carrier.ecosystem === 'npm') + .map(({ id, ecosystem, name, product, version }) => ({ id, ecosystem, name, product, version })) + .sort((left, right) => compareText(left.id, right.id)); + const unique = new Set(identities.map(({ id }) => id)); + if (unique.size !== identities.length) + throw error('exact lock contains duplicate npm/Cargo identities'); + const npm = identities.filter(({ ecosystem }) => ecosystem === 'npm'); + const cargo = identities.filter(({ ecosystem }) => ecosystem === 'cargo'); + return { + schema: TRUSTED_PUBLISHER_PLAN_SCHEMA, + lockDigest: lock.lockDigest, + catalogDigest: lock.catalogDigest, + source: lock.source, + products: lock.products + .filter(({ id }) => selected === undefined || selected.has(id)) + .map(({ id, version }) => ({ id, version })), + expected: EXPECTED_TRUSTED_PUBLISHER, + counts: { cargo: cargo.length, npm: npm.length, total: identities.length }, + npmBatchSize: NPM_TRUST_BATCH_SIZE, + npmBatches: batchRows(npm), + identities, + }; +} + +export function selectTrustedPublisherIdentities(plan, ecosystem, batch = undefined) { + if (ecosystem !== 'cargo' && ecosystem !== 'npm') { + throw error('--ecosystem must be cargo or npm for audit/apply'); + } + const identities = plan.identities.filter((identity) => identity.ecosystem === ecosystem); + if (identities.length === 0) throw error(`exact lock selects no ${ecosystem} identities`); + if (ecosystem === 'cargo') { + if (batch !== undefined) throw error("--batch is used only for npm's bounded 2FA windows"); + return { identities, batch: null, batches: 1 }; + } + const batches = batchRows(identities); + if (!Number.isSafeInteger(batch) || batch < 1 || batch > batches.length) { + throw error(`npm audit/apply requires --batch N from 1 through ${batches.length}`); + } + const start = (batch - 1) * NPM_TRUST_BATCH_SIZE; + return { + identities: identities.slice(start, start + NPM_TRUST_BATCH_SIZE), + batch, + batches: batches.length, + }; +} + +function relevantNpmConfig(config) { + return { + type: config?.type ?? null, + repository: config?.repository ?? null, + file: config?.file ?? null, + environment: config?.environment ?? null, + permissions: Array.isArray(config?.permissions) + ? [...config.permissions].sort(compareText) + : null, + }; +} + +function relevantCratesConfig(config) { + return { + crate: config?.crate ?? null, + repository_owner: config?.repository_owner ?? null, + repository_name: config?.repository_name ?? null, + workflow_filename: config?.workflow_filename ?? null, + environment: config?.environment ?? null, + }; +} + +function exactNpmConfig(config) { + const expected = { + type: 'github', + repository: EXPECTED_TRUSTED_PUBLISHER.repository, + file: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, + environment: EXPECTED_TRUSTED_PUBLISHER.environment, + permissions: [...EXPECTED_TRUSTED_PUBLISHER.npmPermissions], + }; + return stableJson(relevantNpmConfig(config)) === stableJson(expected); +} + +function exactCratesConfig(config, name) { + const expected = { + crate: name, + repository_owner: EXPECTED_TRUSTED_PUBLISHER.repositoryOwner, + repository_name: EXPECTED_TRUSTED_PUBLISHER.repositoryName, + workflow_filename: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, + environment: EXPECTED_TRUSTED_PUBLISHER.environment, + }; + return stableJson(relevantCratesConfig(config)) === stableJson(expected); +} + +export function classifyNpmTrustConfigs(configs) { + if (!Array.isArray(configs)) + throw error('npm trust list output must be a JSON object, array, or empty output'); + if (configs.length === 0) return { state: 'missing' }; + if (configs.length === 1 && exactNpmConfig(configs[0])) return { state: 'exact' }; + return { + state: 'conflict', + reason: `expected exactly one publish-only GitHub configuration; observed ${JSON.stringify(configs.map(relevantNpmConfig))}`, + }; +} + +export function classifyCratesIoTrustConfigs(configs, name) { + if (!Array.isArray(configs)) throw error('crates.io github_configs must be an array'); + if (configs.length === 0) return { state: 'missing' }; + if (configs.length === 1 && exactCratesConfig(configs[0], name)) return { state: 'exact' }; + return { + state: 'conflict', + reason: `expected exactly one GitHub configuration; observed ${JSON.stringify(configs.map(relevantCratesConfig))}`, + }; +} + +function parseNpmJson(text, context) { + const value = text.trim(); + if (value === '') return []; + let parsed; + try { + parsed = JSON.parse(value); + } catch { + throw error(`${context} returned invalid JSON`); + } + return Array.isArray(parsed) ? parsed : [parsed]; +} + +function npmPackageName(name) { + if ( + typeof name !== 'string' || + name.length === 0 || + name.length > 214 || + /[\u0000-\u0020\u007f]/u.test(name) || + !/^@oliphaunt\/[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/u.test(name) + ) { + throw error('npm package name must be a canonical bounded @oliphaunt identity'); + } + return name; +} + +function safeToken(value) { + if ( + typeof value !== 'string' || + value.length === 0 || + value.length > 16 * 1024 || + /[\u0000-\u001f\u007f]/u.test(value) + ) { + throw error('CRATES_IO_TRUST_CONFIG_TOKEN must be a non-empty control-free secret'); + } + return value; +} + +async function boundedText(response, context) { + const declared = Number(response.headers.get('content-length')); + if (Number.isFinite(declared) && declared > MAX_RESPONSE_BYTES) { + await response.body?.cancel?.().catch(() => {}); + throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); + } + const reader = response.body?.getReader?.(); + if (reader === undefined) { + const text = await response.text(); + if (Buffer.byteLength(text) > MAX_RESPONSE_BYTES) + throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); + return text; + } + const chunks = []; + let size = 0; + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > MAX_RESPONSE_BYTES) { + await reader.cancel().catch(() => {}); + throw error(`${context} response exceeds ${MAX_RESPONSE_BYTES} bytes`); + } + chunks.push(Buffer.from(value)); + } + return Buffer.concat(chunks).toString('utf8'); +} + +async function responseJson(response, context) { + const text = await boundedText(response, context); + if (!response.ok) throw error(`${context} returned HTTP ${response.status}`); + try { + return JSON.parse(text); + } catch { + throw error(`${context} returned invalid JSON`); + } +} + +function requestSignal() { + return AbortSignal.timeout(REQUEST_TIMEOUT_MS); +} + +export function createCratesIoTrustClient({ + token = process.env.CRATES_IO_TRUST_CONFIG_TOKEN, + fetchImpl = fetch, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), +} = {}) { + const secret = safeToken(token); + const headers = { + Accept: 'application/json', + Authorization: `Bearer ${secret}`, + 'User-Agent': 'oliphaunt-trust-config/1; https://github.com/f0rr0/oliphaunt', + }; + return { + async list(name) { + const url = new URL(CRATES_IO_CONFIG_ENDPOINT); + url.searchParams.set('crate', name); + url.searchParams.set('per_page', '100'); + let lastError; + for (let attempt = 0; attempt < MAX_READ_ATTEMPTS; attempt += 1) { + try { + const response = await fetchImpl(url, { + method: 'GET', + headers, + redirect: 'error', + signal: requestSignal(), + }); + if (registryStatusRetryable(response.status) && attempt + 1 < MAX_READ_ATTEMPTS) { + const seconds = registryRetryDelaySeconds({ headers: response.headers, attempt }); + await boundedText(response, `crates.io trust audit for ${name}`); + await sleepImpl(seconds * 1_000); + continue; + } + const body = await responseJson(response, `crates.io trust audit for ${name}`); + if (!Array.isArray(body?.github_configs)) + throw error(`crates.io trust audit for ${name} omitted github_configs`); + if (body.github_configs.length > 5) + throw error( + `crates.io trust audit for ${name} exceeded the registry's five-config limit`, + ); + return body.github_configs; + } catch (cause) { + lastError = cause; + if ( + attempt + 1 >= MAX_READ_ATTEMPTS || + !(cause?.name === 'TimeoutError' || cause instanceof TypeError) + ) + throw cause; + await sleepImpl(registryRetryDelaySeconds({ attempt }) * 1_000); + } + } + throw lastError; + }, + async create(name) { + const response = await fetchImpl(CRATES_IO_CONFIG_ENDPOINT, { + method: 'POST', + headers: { ...headers, 'Content-Type': 'application/json' }, + body: JSON.stringify({ + github_config: { + crate: name, + repository_owner: EXPECTED_TRUSTED_PUBLISHER.repositoryOwner, + repository_name: EXPECTED_TRUSTED_PUBLISHER.repositoryName, + workflow_filename: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, + environment: EXPECTED_TRUSTED_PUBLISHER.environment, + }, + }), + redirect: 'error', + signal: requestSignal(), + }); + const body = await responseJson(response, `crates.io trust creation for ${name}`); + if (!exactCratesConfig(body?.github_config, name)) { + throw error(`crates.io created an unexpected trusted-publisher configuration for ${name}`); + } + }, + }; +} + +async function auditIdentities({ identities, client, spacingMs, sleepImpl, progress }) { + const results = []; + for (const [index, identity] of identities.entries()) { + const configs = await client.list(identity.name); + const classified = classifyCratesIoTrustConfigs(configs, identity.name); + results.push({ id: identity.id, ...classified }); + progress?.(`audit ${index + 1}/${identities.length} ${identity.id}: ${classified.state}`); + await sleepImpl(spacingMs); + } + return results; +} + +function reportEnvelope({ + plan, + selection, + ecosystem, + mode, + initial, + final = initial, + created = [], +}) { + const states = (rows, state) => rows.filter((row) => row.state === state).map(({ id }) => id); + return { + schema: TRUSTED_PUBLISHER_REPORT_SCHEMA, + mode, + ecosystem, + lockDigest: plan.lockDigest, + catalogDigest: plan.catalogDigest, + selection: { + count: selection.identities.length, + batch: selection.batch, + batches: selection.batches, + }, + exact: states(final, 'exact'), + missing: states(final, 'missing'), + conflicts: final + .filter(({ state }) => state === 'conflict') + .map(({ id, reason }) => ({ id, reason })), + created, + initial: { + exact: states(initial, 'exact').length, + missing: states(initial, 'missing').length, + conflicts: states(initial, 'conflict').length, + }, + }; +} + +export async function reconcileTrustedPublishers({ + plan, + ecosystem, + batch = undefined, + apply = false, + client, + sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), + progress = undefined, +} = {}) { + const selection = selectTrustedPublisherIdentities(plan, ecosystem, batch); + if (ecosystem !== 'cargo') + throw error('npm configuration commands belong to trusted-publisher-config.sh'); + const spacingMs = CRATES_IO_TRUST_REQUEST_SPACING_MS; + const initial = await auditIdentities({ + ...selection, + ecosystem, + client, + spacingMs, + sleepImpl, + progress, + }); + if (!apply || initial.some(({ state }) => state === 'conflict')) { + return reportEnvelope({ + plan, + selection, + ecosystem, + mode: apply ? 'apply-blocked' : 'audit', + initial, + }); + } + const missing = new Set(initial.filter(({ state }) => state === 'missing').map(({ id }) => id)); + const created = []; + for (const identity of selection.identities.filter(({ id }) => missing.has(id))) { + let mutationFailure; + try { + await client.create(identity.name); + } catch (cause) { + mutationFailure = cause; + } + // A management request can be applied remotely even when its response is + // lost. Never replay it here: inspect the exact immutable configuration, + // accept only the desired state, and let a later invocation resume if the + // registry still reports absence. + await sleepImpl(spacingMs); + const reconciledConfigs = await client.list(identity.name); + const reconciled = classifyCratesIoTrustConfigs(reconciledConfigs, identity.name); + if (reconciled.state !== 'exact') { + if (mutationFailure !== undefined) throw mutationFailure; + throw error( + `${identity.id} trusted-publisher mutation returned without the exact configuration becoming observable` + + `${reconciled.reason ? `: ${reconciled.reason}` : ''}`, + ); + } + created.push(identity.id); + progress?.( + `${mutationFailure === undefined ? 'created' : 'reconciled'} ${created.length}/${missing.size} ${identity.id}`, + ); + await sleepImpl(spacingMs); + } + const final = await auditIdentities({ + ...selection, + ecosystem, + client, + spacingMs, + sleepImpl, + progress, + }); + return reportEnvelope({ plan, selection, ecosystem, mode: 'apply', initial, final, created }); +} + +function parseArgs(argv) { + const allowedValues = new Set([ + 'lock', + 'products-json', + 'ecosystem', + 'batch', + 'confirm-lock-digest', + 'output', + ]); + const values = new Map(); + const booleans = new Set(); + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--apply' || arg === '--audit' || arg === '--help' || arg === '-h') { + booleans.add(arg.replace(/^-+/u, '')); + continue; + } + if (!arg.startsWith('--')) throw error(`unexpected positional argument ${arg}`); + const separator = arg.indexOf('='); + const key = arg.slice(2, separator === -1 ? undefined : separator); + if (!allowedValues.has(key)) throw error(`unknown argument --${key}`); + const value = separator === -1 ? argv[++index] : arg.slice(separator + 1); + if (value === undefined || value.length === 0) throw error(`--${key} requires a value`); + if (values.has(key)) throw error(`--${key} may be specified only once`); + values.set(key, value); + } + return { values, booleans }; +} + +function productsValue(raw) { + if (raw === undefined) return undefined; + try { + return JSON.parse(raw); + } catch { + throw error('--products-json must be strict JSON'); + } +} + +function usage() { + return [ + 'usage:', + ' trusted-publisher-config.sh [--lock FILE] [--products-json JSON] [--output FILE]', + ' trusted-publisher-config.sh --audit --ecosystem cargo|npm [--batch N] [--lock FILE] [--products-json JSON] [--output FILE]', + ' trusted-publisher-config.sh --apply --confirm-lock-digest SHA256 --ecosystem cargo|npm [--batch N] [--lock FILE] [--products-json JSON] [--output FILE]', + '', + 'No --audit/--apply: print an exact-lock plan without registry authentication or network access.', + '--audit: authenticated read-only comparison. --apply: create only missing exact configs, then re-audit.', + 'npm requires deterministic batches sized for its documented five-minute 2FA window.', + 'Run npm audit/apply directly in an interactive terminal; a read-only warm-up authenticates each audit pass.', + 'npm audit/apply requires --output FILE; the report is atomically created with mode 0600 and never overwritten.', + ].join('\n'); +} + +function prettyJson(value) { + return `${JSON.stringify(value, null, 2)}\n`; +} + +export async function writeJson(value, stream = process.stdout) { + const output = prettyJson(value); + await new Promise((resolve, reject) => { + const onError = (cause) => { + stream.off?.('error', onError); + reject(cause); + }; + stream.once?.('error', onError); + stream.write(output, (cause) => { + stream.off?.('error', onError); + if (cause !== undefined && cause !== null) reject(cause); + else resolve(); + }); + }); +} + +export async function reserveJsonFile(outputFile) { + if (typeof outputFile !== 'string' || outputFile.length === 0) { + throw error('--output must be a non-empty file path'); + } + const destination = path.resolve(ROOT, outputFile); + const reservation = `${destination}.oliphaunt-reservation`; + const temporary = path.join( + path.dirname(destination), + `.${path.basename(destination)}.tmp-${process.pid}-${randomUUID()}`, + ); + const probe = path.join( + path.dirname(destination), + `.${path.basename(destination)}.probe-${process.pid}-${randomUUID()}`, + ); + let outputHandle; + let reservationHandle; + let reservationCreated = false; + let probeLinked = false; + try { + reservationHandle = await open(reservation, 'wx', 0o600); + reservationCreated = true; + await reservationHandle.writeFile( + `Oliphaunt trusted-publisher report reservation for ${destination}\n`, + 'utf8', + ); + await reservationHandle.sync(); + await reservationHandle.close(); + reservationHandle = undefined; + outputHandle = await open(temporary, 'wx', 0o600); + try { + await lstat(destination); + const exists = new Error('destination exists'); + exists.code = 'EEXIST'; + throw exists; + } catch (cause) { + if (cause?.code !== 'ENOENT') throw cause; + } + // Exercise the exact no-overwrite atomic publication primitive before any + // registry request. The deterministic reservation blocks cooperating + // invocations while the final destination remains absent for publication. + await link(temporary, probe); + probeLinked = true; + await unlink(probe); + probeLinked = false; + } catch (cause) { + if (reservationHandle !== undefined) await reservationHandle.close().catch(() => {}); + if (outputHandle !== undefined) await outputHandle.close().catch(() => {}); + if (probeLinked) await unlink(probe).catch(() => {}); + await unlink(temporary).catch(() => {}); + if (reservationCreated) await unlink(reservation).catch(() => {}); + if (cause?.code === 'EEXIST') { + if (!reservationCreated) { + throw error(`--output reservation already exists for ${destination}`); + } + throw error(`refusing to overwrite existing --output file ${destination}`); + } + throw error(`could not reserve --output file ${destination}: ${cause?.message ?? cause}`); + } + let active = true; + return { + destination, + async commit(value) { + if (!active) throw error(`--output reservation is no longer active for ${destination}`); + try { + await outputHandle.writeFile(prettyJson(value), 'utf8'); + await outputHandle.sync(); + await outputHandle.close(); + outputHandle = undefined; + await link(temporary, destination); + active = false; + await unlink(temporary).catch(() => {}); + await unlink(reservation).catch(() => {}); + return destination; + } catch (cause) { + if (cause?.code === 'EEXIST') { + throw error(`refusing to overwrite existing --output file ${destination}`); + } + throw error( + `could not publish reserved --output file ${destination}: ${cause?.message ?? cause}`, + ); + } + }, + async abort() { + if (!active) return; + active = false; + if (outputHandle !== undefined) await outputHandle.close().catch(() => {}); + await unlink(temporary).catch(() => {}); + await unlink(reservation).catch(() => {}); + }, + }; +} + +export async function writeJsonFile(value, outputFile) { + const reserved = await reserveJsonFile(outputFile); + try { + return await reserved.commit(value); + } finally { + await reserved.abort(); + } +} + +async function emitJson(value, outputFile) { + if (outputFile === undefined) { + await writeJson(value); + return; + } + const destination = await writeJsonFile(value, outputFile); + console.error(`trusted-publisher-config: wrote exact JSON report to ${destination}`); +} + +export async function reconcileTrustedPublishersToFile({ outputFile, ...options }) { + const reserved = await reserveJsonFile(outputFile); + try { + const report = await reconcileTrustedPublishers(options); + const destination = await reserved.commit(report); + console.error(`trusted-publisher-config: wrote exact JSON report to ${destination}`); + return report; + } finally { + await reserved.abort(); + } +} + +async function main(argv, scratch) { + const { values, booleans } = parseArgs(argv); + if (booleans.has('help') || booleans.has('h')) { + console.log(usage()); + return 0; + } + if (booleans.has('audit') && booleans.has('apply')) + throw error('--audit and --apply are mutually exclusive'); + const lockFile = path.resolve(ROOT, values.get('lock') ?? DEFAULT_PUBLICATION_LOCK); + const plan = buildTrustedPublisherPlan(loadPublicationLock(lockFile), { + products: productsValue(values.get('products-json')), + }); + if (!booleans.has('audit') && !booleans.has('apply')) { + if (values.has('ecosystem') || values.has('batch') || values.has('confirm-lock-digest')) { + throw error('--ecosystem, --batch, and --confirm-lock-digest require --audit or --apply'); + } + await emitJson(plan, values.get('output')); + return 0; + } + const ecosystem = values.get('ecosystem'); + const batch = values.has('batch') ? Number(values.get('batch')) : undefined; + if (ecosystem === 'npm' && !values.has('output')) { + throw error( + 'npm audit/apply requires --output FILE so TTY authentication cannot contaminate report evidence', + ); + } + if (booleans.has('apply')) { + const confirmed = values.get('confirm-lock-digest'); + if (confirmed !== plan.lockDigest) { + throw error(`--confirm-lock-digest must exactly equal ${plan.lockDigest}`); + } + } else if (values.has('confirm-lock-digest')) { + throw error('--confirm-lock-digest is used only with --apply'); + } + const selection = selectTrustedPublisherIdentities(plan, ecosystem, batch); + if (ecosystem === 'npm') { + if (!scratch) + throw error( + 'npm audit/apply must run through bash tools/release/trusted-publisher-config.sh', + ); + for (const identity of selection.identities) npmPackageName(identity.name); + await writeFile( + path.join(scratch, 'context.json'), + prettyJson({ + plan: { lockDigest: plan.lockDigest, catalogDigest: plan.catalogDigest }, + selection, + apply: booleans.has('apply'), + output: path.resolve(ROOT, values.get('output')), + }), + { flag: 'wx', mode: 0o600 }, + ); + return 0; + } + const client = createCratesIoTrustClient(); + const reconcileOptions = { + plan, + ecosystem, + batch, + apply: booleans.has('apply'), + client, + progress: (line) => console.error(line), + }; + let report; + if (values.has('output')) { + report = await reconcileTrustedPublishersToFile({ + ...reconcileOptions, + outputFile: values.get('output'), + }); + } else { + report = await reconcileTrustedPublishers(reconcileOptions); + await writeJson(report); + } + return report.missing.length === 0 && report.conflicts.length === 0 ? 0 : 1; +} + +// npm owns its TTY and commands in Shell; these phases consume only captured data. +async function npmPhase(phase, scratch, index) { + const read = async (file) => { + const metadata = await lstat(file); + if (!metadata.isFile() || metadata.size > MAX_RESPONSE_BYTES) + throw error('invalid bounded npm trust evidence: ' + file); + return await readFile(file, 'utf8'); + }; + if (phase === '--npm-runtime') { + validateNpmTrustCliRuntime((await read(path.join(scratch, 'npm-version'))).trim()); + return; + } + const { plan, selection, apply, output } = JSON.parse( + await read(path.join(scratch, 'context.json')), + ); + if (phase === '--npm-commit') { + const report = JSON.parse(await read(index)); + await link(index, output); + console.error('trusted-publisher-config: wrote exact JSON report to ' + output); + process.exitCode = report.missing.length === 0 && report.conflicts.length === 0 ? 0 : 1; + return; + } + const classify = async (pass) => + await Promise.all( + selection.identities.map(async ({ id }, number) => ({ + id, + ...classifyNpmTrustConfigs( + parseNpmJson(await read(path.join(scratch, pass + '-' + number)), id), + ), + })), + ); + if (phase === '--npm-reconcile') { + const identity = selection.identities[Number(index)]; + if (!identity) throw error('unknown npm trust identity'); + const row = classifyNpmTrustConfigs( + parseNpmJson(await read(path.join(scratch, 'reconcile-' + index)), identity.id), + ); + if (row.state !== 'exact') + throw error(identity.id + ' trusted-publisher mutation did not reconcile: ' + row.state); + await writeFile(path.join(scratch, 'created-' + index), identity.id, { + flag: 'wx', + mode: 0o600, + }); + return; + } + const initial = await classify('initial'); + const blocked = initial.some((row) => row.state === 'conflict'); + if (phase === '--npm-initial') { + const missing = + !apply || blocked + ? [] + : selection.identities.flatMap((identity, number) => + initial[number].state === 'missing' ? [number] : [], + ); + await writeFile(path.join(scratch, 'missing.json'), prettyJson(missing)); + await writeFile( + path.join(scratch, 'initial-report.json'), + prettyJson( + reportEnvelope({ + plan, + selection, + ecosystem: 'npm', + mode: apply && blocked ? 'apply-blocked' : 'audit', + initial, + }), + ), + ); + return; + } + if (phase !== '--npm-report') throw error('unknown npm data phase ' + phase); + const final = apply && !blocked ? await classify('final') : initial; + const created = []; + if (apply && !blocked) { + for (const [number, identity] of selection.identities.entries()) { + if (initial[number].state !== 'missing') continue; + if ((await read(path.join(scratch, 'created-' + number))) !== identity.id) + throw error('missing exact npm mutation receipt'); + created.push(identity.id); + } + } + await writeJson( + reportEnvelope({ + plan, + selection, + ecosystem: 'npm', + mode: !apply ? 'audit' : blocked ? 'apply-blocked' : 'apply', + initial, + final, + created, + }), + ); +} + +if (import.meta.main) { + try { + const args = Bun.argv.slice(2); + if (args[0]?.startsWith('--npm-')) await npmPhase(...args); + else if (args[0] === '--prepare') process.exitCode = await main(args.slice(2), args[1]); + else process.exitCode = await main(args); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exitCode = 2; + } +} diff --git a/tools/release/trusted-publisher-config.sh b/tools/release/trusted-publisher-config.sh new file mode 100644 index 000000000..443225877 --- /dev/null +++ b/tools/release/trusted-publisher-config.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -euo pipefail +umask 077 +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$root" +tool="$root/tools/release/trusted-publisher-config.mts" +scratch="$(mktemp -d)" +reservation='' +temporary='' +cleanup() { + [ -z "$temporary" ] || rm -f "$temporary" + [ -z "$reservation" ] || rmdir "$reservation" + rm -rf "$scratch" +} +trap cleanup EXIT +trap 'exit 130' INT TERM +if [ "${1:-}" = --npm ]; then + cp "$2/context.json" "$scratch/context.json" +else + bash tools/dev/bun.sh "$tool" --prepare "$scratch" "$@" +fi +[ -f "$scratch/context.json" ] || exit 0 +command -v jq >/dev/null +deadline="$(command -v gtimeout || command -v timeout)" +output="$(jq -r '.output' "$scratch/context.json")" +# Reserve the report before authentication or mutation. Final publication is an +# atomic no-overwrite hard link; the output path stays absent until it is complete. +mkdir "$output.oliphaunt-reservation" +reservation="$output.oliphaunt-reservation" +if [ -e "$output" ] || [ -L "$output" ]; then echo "refusing to overwrite $output" >&2; exit 2; fi +temporary="$(mktemp "$(dirname "$output")/.trusted-publisher-report.XXXXXX")" +ln "$temporary" "$reservation/probe" +rm "$reservation/probe" +if [ ! -t 0 ] || [ ! -t 1 ]; then echo 'npm trust audit/apply requires an interactive terminal for authentication' >&2; exit 2; fi +"$deadline" --foreground --kill-after=5s 30s npm --version > "$scratch/npm-version" +bash tools/dev/bun.sh "$tool" --npm-runtime "$scratch" +export NPM_CONFIG_FETCH_RETRY_MINTIMEOUT=1000 NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT=5000 NPM_CONFIG_FETCH_TIMEOUT=20000 +npm_names=() +while IFS= read -r name; do npm_names+=("$name"); done < <(jq -r '.selection.identities[].name' "$scratch/context.json") +# npm's authentication dialog requires both stdin and stdout to remain TTYs. +warmup() { + NPM_CONFIG_FETCH_RETRIES=3 "$deadline" --foreground --kill-after=5s 300s npm trust list "$1" --json --registry https://registry.npmjs.org/ + sleep 2 +} +list() { + local name="$1" destination="$2" status=0 + NPM_CONFIG_FETCH_RETRIES=3 "$deadline" --foreground --kill-after=5s 30s npm trust list "$name" --json --registry https://registry.npmjs.org/ > "$destination" 2> "$scratch/list-error" || status=$? + if [ "$status" != 0 ]; then + if grep -Eqi '(^|[^[:alnum:]_])EOTP([^[:alnum:]_]|$)|one-time pass(word)?' "$scratch/list-error"; then + sleep 2 + warmup "$name" + # Only one read-only authentication retry. Never replay a mutation. + NPM_CONFIG_FETCH_RETRIES=3 "$deadline" --foreground --kill-after=5s 30s npm trust list "$name" --json --registry https://registry.npmjs.org/ > "$destination" + else + tail -c 8192 "$scratch/list-error" >&2 + return "$status" + fi + fi +} +audit() { + local pass="$1" index + warmup "${npm_names[0]}" + for index in "${!npm_names[@]}"; do + list "${npm_names[$index]}" "$scratch/$pass-$index" + sleep 2 + done +} +audit initial +bash tools/dev/bun.sh "$tool" --npm-initial "$scratch" +if jq -e '.apply' "$scratch/context.json" >/dev/null && jq -e '.conflicts | length == 0' "$scratch/initial-report.json" >/dev/null; then + while IFS= read -r index; do + name="${npm_names[$index]}" + status=0 + NPM_CONFIG_FETCH_RETRIES=0 "$deadline" --foreground --kill-after=5s 300s npm trust github "$name" --file release.yml --repo f0rr0/oliphaunt --env release-publish --allow-publish --yes --json --registry https://registry.npmjs.org/ || status=$? + sleep 2 + list "$name" "$scratch/reconcile-$index" + bash tools/dev/bun.sh "$tool" --npm-reconcile "$scratch" "$index" + [ "$status" = 0 ] || echo "reconciled $name after an ambiguous npm exit $status" >&2 + sleep 2 + done < <(jq -r '.[]' "$scratch/missing.json") + audit final +fi +bash tools/dev/bun.sh "$tool" --npm-report "$scratch" > "$temporary" +bash tools/dev/bun.sh "$tool" --npm-commit "$scratch" "$temporary" diff --git a/tools/release/trusted-publisher-config.test.mjs b/tools/release/trusted-publisher-config.test.mjs deleted file mode 100644 index a66eb55a0..000000000 --- a/tools/release/trusted-publisher-config.test.mjs +++ /dev/null @@ -1,611 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { spawn } from "node:child_process"; -import { mkdtemp, readFile, readdir, rm, stat } from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import process from "node:process"; -import test from "node:test"; - -import { - EXPECTED_TRUSTED_PUBLISHER, - NPM_TRUST_BATCH_SIZE, - buildTrustedPublisherPlan, - classifyCratesIoTrustConfigs, - classifyNpmTrustConfigs, - createCratesIoTrustClient, - createNpmTrustClient, - npmTrustGithubArgs, - npmTrustListArgs, - reconcileTrustedPublishers, - reconcileTrustedPublishersToFile, - reserveJsonFile, - runNpmTrustCommand, - selectTrustedPublisherIdentities, - writeJsonFile, -} from "./trusted-publisher-config.mjs"; - -const NPM_LIST_HELP = "Options: --json --registry"; -const NPM_GITHUB_HELP = - "Options: --file --repository --environment --allow-publish --json --registry --yes"; -const MODULE_URL = new URL("trusted-publisher-config.mjs", import.meta.url).href; - -function carrier(ecosystem, name, product = "one") { - return { - id: `${ecosystem}:${name}`, - ecosystem, - name, - product, - version: "1.2.3", - }; -} - -function lock(carriers) { - return { - lockDigest: "a".repeat(64), - catalogDigest: "b".repeat(64), - source: { commit: "c".repeat(40), tree: "d".repeat(40) }, - products: [ - { id: "one", version: "1.2.3" }, - { id: "two", version: "2.0.0" }, - ], - carriers, - }; -} - -function exactNpm() { - return { - id: "publisher-id", - type: "github", - repository: EXPECTED_TRUSTED_PUBLISHER.repository, - file: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, - environment: EXPECTED_TRUSTED_PUBLISHER.environment, - permissions: [...EXPECTED_TRUSTED_PUBLISHER.npmPermissions], - }; -} - -function exactCrates(name) { - return { - id: 1, - crate: name, - repository_owner: EXPECTED_TRUSTED_PUBLISHER.repositoryOwner, - repository_name: EXPECTED_TRUSTED_PUBLISHER.repositoryName, - workflow_filename: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, - environment: EXPECTED_TRUSTED_PUBLISHER.environment, - }; -} - -test("derives exact npm/Cargo identities and bounded npm batches from the lock", () => { - const npm = Array.from({ length: NPM_TRUST_BATCH_SIZE + 1 }, (_, index) => - carrier("npm", `@oliphaunt/package-${String(index).padStart(2, "0")}`)); - const plan = buildTrustedPublisherPlan(lock([ - carrier("cargo", "oliphaunt-one"), - ...npm, - ])); - assert.deepEqual(plan.counts, { cargo: 1, npm: NPM_TRUST_BATCH_SIZE + 1, total: NPM_TRUST_BATCH_SIZE + 2 }); - assert.equal(plan.npmBatches.length, 2); - assert.deepEqual(plan.npmBatches.map(({ count }) => count), [NPM_TRUST_BATCH_SIZE, 1]); - assert.equal(plan.expected.workflowFilename, "release.yml"); - assert.equal(plan.expected.environment, "release-publish"); - - assert.throws(() => selectTrustedPublisherIdentities(plan, "npm"), /requires --batch/u); - assert.equal(selectTrustedPublisherIdentities(plan, "npm", 2).identities.length, 1); - assert.equal(selectTrustedPublisherIdentities(plan, "cargo").identities.length, 1); - assert.throws(() => selectTrustedPublisherIdentities(plan, "cargo", 1), /used only for npm/u); -}); - -test("rejects unknown or duplicate product selection", () => { - const value = lock([carrier("cargo", "oliphaunt-one")]); - assert.throws(() => buildTrustedPublisherPlan(value, { products: ["missing"] }), /absent from the exact lock/u); - assert.throws(() => buildTrustedPublisherPlan(value, { products: ["one", "one"] }), /unique string list/u); -}); - -test("classifies only the exact npm publish permission and caller identity as trusted", () => { - assert.deepEqual(classifyNpmTrustConfigs([]), { state: "missing" }); - assert.deepEqual(classifyNpmTrustConfigs([exactNpm()]), { state: "exact" }); - assert.equal(classifyNpmTrustConfigs([{ ...exactNpm(), file: "wrong.yml" }]).state, "conflict"); - assert.equal(classifyNpmTrustConfigs([{ - ...exactNpm(), - permissions: ["createPackage", "createStagedPackage"], - }]).state, "conflict"); - assert.equal(classifyNpmTrustConfigs([exactNpm(), exactNpm()]).state, "conflict"); -}); - -test("classifies crates.io configuration strictly and treats extras as conflicts", () => { - assert.deepEqual(classifyCratesIoTrustConfigs([], "oliphaunt-one"), { state: "missing" }); - assert.deepEqual(classifyCratesIoTrustConfigs([exactCrates("oliphaunt-one")], "oliphaunt-one"), { state: "exact" }); - assert.equal(classifyCratesIoTrustConfigs([{ - ...exactCrates("oliphaunt-one"), - environment: null, - }], "oliphaunt-one").state, "conflict"); - assert.equal(classifyCratesIoTrustConfigs([ - exactCrates("oliphaunt-one"), - { ...exactCrates("oliphaunt-one"), id: 2, repository_name: "other" }, - ], "oliphaunt-one").state, "conflict"); -}); - -test("npm client checks the management CLI and sends exact non-staged flags", async () => { - const calls = []; - const client = createNpmTrustClient({ - runImpl(args, _context, options) { - calls.push({ args, options }); - if (args[0] === "--version") return "11.15.0\n"; - if (args[2] === "--help" && args[1] === "list") return NPM_LIST_HELP; - if (args[2] === "--help" && args[1] === "github") return NPM_GITHUB_HELP; - if (args[1] === "list") return `${JSON.stringify(exactNpm())}\n`; - return `${JSON.stringify(exactNpm())}\n`; - }, - }); - assert.equal(client.checkRuntime(), "11.15.0"); - client.authorizeAudit("@oliphaunt/example"); - assert.deepEqual(await client.list("@oliphaunt/example"), [exactNpm()]); - client.create("@oliphaunt/example"); - assert.deepEqual(calls[3].args, npmTrustListArgs("@oliphaunt/example")); - assert.deepEqual(calls[3].options, { interactiveAudit: true }); - assert.deepEqual(calls[4].args, npmTrustListArgs("@oliphaunt/example")); - assert.deepEqual(calls[5].args, npmTrustGithubArgs("@oliphaunt/example")); - assert.ok(calls[5].args.includes("release.yml")); - assert.ok(calls[5].args.includes("release-publish")); - assert.ok(calls[5].args.includes("--allow-publish")); - assert.ok(!calls[5].args.includes("--allow-stage-publish")); - assert.ok(calls.every(({ args }) => args.every((arg) => !arg.startsWith("--fetch-")))); - assert.throws(() => npmTrustListArgs("--fetch-retries"), /canonical bounded @oliphaunt identity/u); - assert.throws(() => npmTrustGithubArgs("@other/example"), /canonical bounded @oliphaunt identity/u); - assert.throws( - () => createNpmTrustClient({ - runImpl: (args) => args[0] === "--version" ? "11.14.9\n" : "", - }).checkRuntime(), - /too old/u, - ); -}); - -test("npm captured list retries once through a read-only TTY warm-up only for OTP", async () => { - const events = []; - let capturedAttempts = 0; - const client = createNpmTrustClient({ - runImpl(args, _context, options) { - if (options?.interactiveAudit === true) { - events.push("warm-up"); - return ""; - } - events.push("captured"); - capturedAttempts += 1; - if (capturedAttempts === 1) { - throw Object.assign(new Error("npm error code EOTP"), { - npmAuthenticationRequired: true, - }); - } - return `${JSON.stringify(exactNpm())}\n`; - }, - sleepImpl: async (milliseconds) => events.push(`sleep:${milliseconds}`), - }); - assert.deepEqual(await client.list("@oliphaunt/example"), [exactNpm()]); - assert.deepEqual(events, [ - "captured", - "sleep:2000", - "warm-up", - "sleep:2000", - "captured", - ]); - - let boundedCalls = 0; - const expired = createNpmTrustClient({ - runImpl(_args, _context, options) { - boundedCalls += 1; - if (options?.interactiveAudit === true) return ""; - throw Object.assign(new Error("npm error code EOTP"), { - npmAuthenticationRequired: true, - }); - }, - sleepImpl: async () => {}, - }); - await assert.rejects( - () => expired.list("@oliphaunt/example"), - /still requires OTP after the bounded read-only warm-up/u, - ); - assert.equal(boundedCalls, 3); - - let ordinaryCalls = 0; - const ordinaryFailure = createNpmTrustClient({ - runImpl() { - ordinaryCalls += 1; - throw new Error("network unavailable"); - }, - }); - await assert.rejects(() => ordinaryFailure.list("@oliphaunt/example"), /network unavailable/u); - assert.equal(ordinaryCalls, 1, "non-authentication failures must not be retried"); -}); - -test("npm command policy captures bounded evidence and reserves inherited TTYs for warm-up and mutation", () => { - const calls = []; - const spawnImpl = (command, args, options) => { - calls.push({ command, args, options }); - return { - error: undefined, - status: 0, - stderr: options.stdio === "inherit" ? null : "", - stdout: options.stdio === "inherit" ? null : "read output\n", - }; - }; - - assert.equal( - runNpmTrustCommand(["--version"], "npm --version", { spawnImpl }), - "read output\n", - ); - assert.equal( - runNpmTrustCommand( - npmTrustListArgs("@oliphaunt/example"), - "npm trust list @oliphaunt/example", - { spawnImpl }, - ), - "read output\n", - ); - assert.equal( - runNpmTrustCommand( - npmTrustListArgs("@oliphaunt/example"), - "npm trust list authentication warm-up for @oliphaunt/example", - { - spawnImpl, - interactiveAudit: true, - stdinIsTTY: true, - stdoutIsTTY: true, - }, - ), - "", - ); - assert.equal( - runNpmTrustCommand( - npmTrustGithubArgs("@oliphaunt/example"), - "npm trust github @oliphaunt/example", - { spawnImpl, stdinIsTTY: true, stdoutIsTTY: true }, - ), - "", - ); - - for (const call of calls.slice(0, 2)) { - assert.equal(call.command, "npm"); - assert.deepEqual(call.options.stdio, ["ignore", "pipe", "pipe"]); - assert.equal(call.options.timeout, 30_000); - assert.equal(call.options.maxBuffer, 256 * 1024); - assert.equal(call.options.encoding, "utf8"); - } - assert.equal(calls[0].options.env.NPM_CONFIG_FETCH_RETRIES, "0"); - assert.equal(calls[1].options.env.NPM_CONFIG_FETCH_RETRIES, "3"); - assert.equal(calls[1].options.env.NPM_CONFIG_FETCH_RETRY_MINTIMEOUT, "1000"); - assert.equal(calls[1].options.env.NPM_CONFIG_FETCH_RETRY_MAXTIMEOUT, "5000"); - assert.equal(calls[1].options.env.NPM_CONFIG_FETCH_TIMEOUT, "20000"); - for (const interactive of calls.slice(2)) { - assert.equal(interactive.options.stdio, "inherit"); - assert.equal(interactive.options.timeout, 5 * 60_000); - assert.equal("encoding" in interactive.options, false); - assert.equal("maxBuffer" in interactive.options, false); - } - assert.equal(calls[2].options.env.NPM_CONFIG_FETCH_RETRIES, "3"); - assert.equal(calls[3].options.env.NPM_CONFIG_FETCH_RETRIES, "0"); - assert.ok(calls.every(({ args }) => args.every((arg) => !arg.startsWith("--fetch-")))); - assert.throws( - () => runNpmTrustCommand( - [...npmTrustListArgs("@oliphaunt/example"), "--fetch-retries", "3"], - "npm trust list @oliphaunt/example", - { spawnImpl }, - ), - /refusing unsupported npm trust list arguments/u, - ); - assert.throws( - () => runNpmTrustCommand(["publish", "package.tgz"], "npm publish", { spawnImpl }), - /refusing unsupported npm management command/u, - ); - assert.throws( - () => runNpmTrustCommand( - npmTrustGithubArgs("@oliphaunt/example"), - "npm trust github @oliphaunt/example", - { spawnImpl, stdinIsTTY: false, stdoutIsTTY: true }, - ), - /requires an interactive terminal/u, - ); - assert.equal(calls.length, 4, "unsupported and non-TTY npm commands must fail before spawn"); - - assert.throws( - () => runNpmTrustCommand( - npmTrustListArgs("@oliphaunt/example"), - "npm trust list @oliphaunt/example", - { - spawnImpl: () => ({ - status: 1, - stdout: "", - stderr: "npm error code EOTP\nnpm error This operation requires a one-time password", - }), - }, - ), - (cause) => cause.npmAuthenticationRequired === true, - ); -}); - -test("awaited JSON output remains complete through a pipe beyond Bun's 64 KiB console boundary", async () => { - const script = [ - `const { writeJson } = await import(${JSON.stringify(MODULE_URL)});`, - 'await writeJson({ payload: "x".repeat(90_000), tail: "complete" });', - ].join("\n"); - const result = await new Promise((resolve, reject) => { - const child = spawn(process.execPath, ["--eval", script], { - stdio: ["ignore", "pipe", "pipe"], - }); - const stdout = []; - const stderr = []; - child.stdout.on("data", (chunk) => stdout.push(Buffer.from(chunk))); - child.stderr.on("data", (chunk) => stderr.push(Buffer.from(chunk))); - child.once("error", reject); - child.once("close", (status, signal) => resolve({ - signal, - status, - stderr: Buffer.concat(stderr).toString("utf8"), - stdout: Buffer.concat(stdout), - })); - }); - assert.equal(result.signal, null); - assert.equal(result.status, 0, result.stderr); - assert.ok(result.stdout.length > 80 * 1024); - assert.equal(result.stdout.at(-1), 0x0a); - assert.deepEqual(JSON.parse(result.stdout.toString("utf8")), { - payload: "x".repeat(90_000), - tail: "complete", - }); -}); - -test("file reports are atomically created as mode 0600, complete, and never overwritten", async () => { - const directory = await mkdtemp(path.join(os.tmpdir(), "oliphaunt-trust-report-")); - try { - const output = path.join(directory, "npm-audit.json"); - const report = { - payload: "x".repeat(90_000), - tail: "complete", - }; - assert.equal(await writeJsonFile(report, output), output); - assert.equal((await stat(output)).mode & 0o777, 0o600); - const bytes = await readFile(output, "utf8"); - assert.ok(Buffer.byteLength(bytes) > 80 * 1024); - assert.equal(bytes.at(-1), "\n"); - assert.deepEqual(JSON.parse(bytes), report); - await assert.rejects( - () => writeJsonFile({ replaced: true }, output), - /refusing to overwrite existing --output file/u, - ); - assert.deepEqual(JSON.parse(await readFile(output, "utf8")), report); - assert.deepEqual(await readdir(directory), ["npm-audit.json"]); - } finally { - await rm(directory, { force: true, recursive: true }); - } -}); - -test("reservation never exposes the final path before a complete commit", async () => { - const directory = await mkdtemp(path.join(os.tmpdir(), "oliphaunt-trust-atomic-")); - try { - const output = path.join(directory, "pending.json"); - const reserved = await reserveJsonFile(output); - await assert.rejects(() => stat(output), (cause) => cause.code === "ENOENT"); - const during = await readdir(directory); - assert.ok(during.some((entry) => entry.endsWith(".oliphaunt-reservation"))); - assert.ok(during.some((entry) => entry.includes(".tmp-"))); - assert.ok(!during.includes("pending.json")); - assert.ok(!during.some((entry) => entry.includes(".probe-"))); - await reserved.abort(); - assert.deepEqual(await readdir(directory), []); - } finally { - await rm(directory, { force: true, recursive: true }); - } -}); - -test("report reservation fails before every registry or initialization call", async () => { - const directory = await mkdtemp(path.join(os.tmpdir(), "oliphaunt-trust-reservation-")); - try { - const existing = path.join(directory, "existing.json"); - await writeJsonFile({ existing: true }, existing); - const plan = buildTrustedPublisherPlan(lock([ - carrier("npm", "@oliphaunt/example"), - ])); - let calls = 0; - const options = { - plan, - ecosystem: "npm", - batch: 1, - apply: true, - client: { - authorizeAudit() { calls += 1; }, - async list() { - calls += 1; - return []; - }, - async create() { calls += 1; }, - }, - initialize: async () => { calls += 1; }, - sleepImpl: async () => {}, - }; - await assert.rejects( - () => reconcileTrustedPublishersToFile({ - ...options, - outputFile: existing, - }), - /refusing to overwrite existing --output file/u, - ); - await assert.rejects( - () => reconcileTrustedPublishersToFile({ - ...options, - outputFile: path.join(directory, "missing-parent", "report.json"), - }), - /could not reserve --output file/u, - ); - assert.equal(calls, 0, "output reservation must precede client initialization and registry calls"); - assert.deepEqual(await readdir(directory), ["existing.json"]); - } finally { - await rm(directory, { force: true, recursive: true }); - } -}); - -test("crates.io client uses scoped bearer auth, exact payload, and no delete path", async () => { - const calls = []; - const client = createCratesIoTrustClient({ - token: "configuration-secret", - fetchImpl: async (url, init) => { - calls.push({ url: String(url), init }); - if (init.method === "GET") { - return new Response(JSON.stringify({ github_configs: [exactCrates("oliphaunt-one")], meta: { total: 1, next_page: null } })); - } - return new Response(JSON.stringify({ github_config: exactCrates("oliphaunt-one") })); - }, - sleepImpl: async () => {}, - }); - assert.deepEqual(await client.list("oliphaunt-one"), [exactCrates("oliphaunt-one")]); - await client.create("oliphaunt-one"); - const getUrl = new URL(calls[0].url); - assert.equal(getUrl.origin + getUrl.pathname, "https://crates.io/api/v1/trusted_publishing/github_configs"); - assert.equal(getUrl.searchParams.get("crate"), "oliphaunt-one"); - assert.equal(new Headers(calls[0].init.headers).get("authorization"), "Bearer configuration-secret"); - assert.deepEqual(JSON.parse(calls[1].init.body), { - github_config: { - crate: "oliphaunt-one", - repository_owner: "f0rr0", - repository_name: "oliphaunt", - workflow_filename: "release.yml", - environment: "release-publish", - }, - }); - assert.ok(calls.every(({ init }) => init.method !== "DELETE")); -}); - -test("crates.io read audit retries bounded retryable responses but create is not replayed", async () => { - let reads = 0; - const sleeps = []; - const client = createCratesIoTrustClient({ - token: "configuration-secret", - fetchImpl: async (_url, init) => { - if (init.method === "POST") return new Response("unavailable", { status: 503 }); - reads += 1; - if (reads === 1) return new Response("busy", { status: 503, headers: { "Retry-After": "0" } }); - return new Response(JSON.stringify({ github_configs: [], meta: { total: 0, next_page: null } })); - }, - sleepImpl: async (milliseconds) => sleeps.push(milliseconds), - }); - assert.deepEqual(await client.list("oliphaunt-one"), []); - assert.equal(reads, 2); - assert.deepEqual(sleeps, [0]); - await assert.rejects(() => client.create("oliphaunt-one"), /HTTP 503/u); -}); - -test("apply is pre-audited, idempotent, and verified after each missing configuration", async () => { - const plan = buildTrustedPublisherPlan(lock([ - carrier("npm", "@oliphaunt/one"), - carrier("npm", "@oliphaunt/two"), - ])); - const state = new Map([ - ["@oliphaunt/one", [exactNpm()]], - ["@oliphaunt/two", []], - ]); - const creates = []; - const sleeps = []; - const events = []; - const client = { - async authorizeAudit(name) { events.push(`authorize:${name}`); }, - async list(name) { - events.push(`list:${name}`); - return structuredClone(state.get(name)); - }, - async create(name) { - events.push(`create:${name}`); - creates.push(name); - state.set(name, [exactNpm()]); - }, - }; - const report = await reconcileTrustedPublishers({ - plan, - ecosystem: "npm", - batch: 1, - apply: true, - client, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - events.push(`sleep:${milliseconds}`); - }, - }); - assert.equal(report.mode, "apply"); - assert.deepEqual(report.missing, []); - assert.deepEqual(report.conflicts, []); - assert.deepEqual(report.created, ["npm:@oliphaunt/two"]); - assert.deepEqual(creates, ["@oliphaunt/two"]); - assert.equal(sleeps.length, 8); - assert.deepEqual(events.slice(0, 7), [ - "authorize:@oliphaunt/one", - "sleep:2000", - "list:@oliphaunt/one", - "sleep:2000", - "list:@oliphaunt/two", - "sleep:2000", - "create:@oliphaunt/two", - ]); - assert.equal(events.filter((event) => event.startsWith("authorize:")).length, 2); - assert.ok( - events.lastIndexOf("authorize:@oliphaunt/one") > events.indexOf("create:@oliphaunt/two"), - "the final audit pass must refresh the read-only authentication window", - ); - - const second = await reconcileTrustedPublishers({ - plan, - ecosystem: "npm", - batch: 1, - apply: true, - client, - sleepImpl: async () => {}, - }); - assert.deepEqual(second.created, []); - assert.deepEqual(creates, ["@oliphaunt/two"]); -}); - -test("an applied trusted-publisher mutation with a lost response reconciles without replay", async () => { - const plan = buildTrustedPublisherPlan(lock([carrier("cargo", "oliphaunt-one")])); - let present = false; - let creates = 0; - const report = await reconcileTrustedPublishers({ - plan, - ecosystem: "cargo", - apply: true, - client: { - async list() { return present ? [exactCrates("oliphaunt-one")] : []; }, - async create() { - creates += 1; - present = true; - throw new Error("response timed out after the registry applied the configuration"); - }, - }, - sleepImpl: async () => {}, - }); - assert.equal(creates, 1); - assert.deepEqual(report.created, ["cargo:oliphaunt-one"]); - assert.deepEqual(report.missing, []); - assert.deepEqual(report.conflicts, []); -}); - -test("any conflicting configuration blocks every mutation in the selected batch", async () => { - const plan = buildTrustedPublisherPlan(lock([ - carrier("cargo", "oliphaunt-one"), - carrier("cargo", "oliphaunt-two"), - ])); - let creates = 0; - const client = { - async list(name) { - return name === "oliphaunt-one" - ? [] - : [{ ...exactCrates(name), workflow_filename: "wrong.yml" }]; - }, - async create() { creates += 1; }, - }; - const report = await reconcileTrustedPublishers({ - plan, - ecosystem: "cargo", - apply: true, - client, - sleepImpl: async () => {}, - }); - assert.equal(report.mode, "apply-blocked"); - assert.equal(report.conflicts.length, 1); - assert.equal(creates, 0); -}); diff --git a/tools/release/trusted-publisher-config.test.mts b/tools/release/trusted-publisher-config.test.mts new file mode 100644 index 000000000..5e0343510 --- /dev/null +++ b/tools/release/trusted-publisher-config.test.mts @@ -0,0 +1,478 @@ +#!/usr/bin/env bun + +import assert from 'node:assert/strict'; +import { mkdtemp, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; +import test from 'node:test'; + +import { + buildTrustedPublisherPlan, + classifyCratesIoTrustConfigs, + classifyNpmTrustConfigs, + createCratesIoTrustClient, + EXPECTED_TRUSTED_PUBLISHER, + NPM_TRUST_BATCH_SIZE, + reconcileTrustedPublishers, + reconcileTrustedPublishersToFile, + reserveJsonFile, + selectTrustedPublisherIdentities, + writeJson, + writeJsonFile, +} from './trusted-publisher-config.mts'; + +function carrier(ecosystem, name, product = 'one') { + return { + id: `${ecosystem}:${name}`, + ecosystem, + name, + product, + version: '1.2.3', + }; +} + +function lock(carriers) { + return { + lockDigest: 'a'.repeat(64), + catalogDigest: 'b'.repeat(64), + source: { commit: 'c'.repeat(40), tree: 'd'.repeat(40) }, + products: [ + { id: 'one', version: '1.2.3' }, + { id: 'two', version: '2.0.0' }, + ], + carriers, + }; +} + +function exactNpm() { + return { + id: 'publisher-id', + type: 'github', + repository: EXPECTED_TRUSTED_PUBLISHER.repository, + file: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, + environment: EXPECTED_TRUSTED_PUBLISHER.environment, + permissions: [...EXPECTED_TRUSTED_PUBLISHER.npmPermissions], + }; +} + +function exactCrates(name) { + return { + id: 1, + crate: name, + repository_owner: EXPECTED_TRUSTED_PUBLISHER.repositoryOwner, + repository_name: EXPECTED_TRUSTED_PUBLISHER.repositoryName, + workflow_filename: EXPECTED_TRUSTED_PUBLISHER.workflowFilename, + environment: EXPECTED_TRUSTED_PUBLISHER.environment, + }; +} + +const [fixtureMode, fixtureRoot, scenario] = process.argv.slice(2); +if (fixtureMode === 'pipe') { + await writeJson({ payload: 'x'.repeat(90000), tail: 'complete' }); + process.exit(0); +} +if (fixtureMode === 'assert-pipe') { + const output = await readFile(fixtureRoot); + assert(output.length > 80 * 1024); + assert.equal(output.at(-1), 0x0a); + assert.deepEqual(JSON.parse(output.toString('utf8')), { + payload: 'x'.repeat(90000), + tail: 'complete', + }); + process.exit(0); +} +if (fixtureMode === 'prepare') { + const plan = buildTrustedPublisherPlan(lock([carrier('npm', '@oliphaunt/example')])); + const selection = selectTrustedPublisherIdentities(plan, 'npm', 1); + await writeFile( + path.join(fixtureRoot, 'context.json'), + JSON.stringify({ + plan, + selection, + apply: true, + output: path.join(fixtureRoot, scenario + '.json'), + }), + ); + await writeFile(path.join(fixtureRoot, 'exact.json'), JSON.stringify([exactNpm()])); + await writeFile( + path.join(fixtureRoot, 'conflicting.json'), + JSON.stringify([{ ...exactNpm(), repository: 'wrong/repo' }]), + ); + if (scenario === 'rerun') + await writeFile(path.join(fixtureRoot, scenario + '.state'), 'published'); + process.exit(0); +} +if (fixtureMode === 'assert') { + const output = path.join(fixtureRoot, scenario + '.json'); + const log = await readFile(path.join(fixtureRoot, scenario + '.events'), 'utf8'); + assert.equal( + log.split('\n').filter((line) => line.startsWith('github ')).length, + ['ambiguous', 'missing'].includes(scenario) ? 1 : 0, + ); + assert( + !(await readdir(fixtureRoot)).some( + (name) => + name.endsWith('.oliphaunt-reservation') || name.startsWith('.trusted-publisher-report.'), + ), + ); + if (scenario === 'missing') + await assert.rejects(stat(output), (cause) => cause.code === 'ENOENT'); + else { + const report = JSON.parse(await readFile(output, 'utf8')); + assert.equal((await stat(output)).mode & 0o777, 0o600); + assert.deepEqual(report.created, scenario === 'ambiguous' ? ['npm:@oliphaunt/example'] : []); + assert.equal(report.conflicts.length, scenario === 'conflict' ? 1 : 0); + } + process.exit(0); +} + +test('derives exact npm/Cargo identities and bounded npm batches from the lock', () => { + const npm = Array.from({ length: NPM_TRUST_BATCH_SIZE + 1 }, (_, index) => + carrier('npm', `@oliphaunt/package-${String(index).padStart(2, '0')}`), + ); + const plan = buildTrustedPublisherPlan(lock([carrier('cargo', 'oliphaunt-one'), ...npm])); + assert.deepEqual(plan.counts, { + cargo: 1, + npm: NPM_TRUST_BATCH_SIZE + 1, + total: NPM_TRUST_BATCH_SIZE + 2, + }); + assert.equal(plan.npmBatches.length, 2); + assert.deepEqual( + plan.npmBatches.map(({ count }) => count), + [NPM_TRUST_BATCH_SIZE, 1], + ); + assert.equal(plan.expected.workflowFilename, 'release.yml'); + assert.equal(plan.expected.environment, 'release-publish'); + + assert.throws(() => selectTrustedPublisherIdentities(plan, 'npm'), /requires --batch/u); + assert.equal(selectTrustedPublisherIdentities(plan, 'npm', 2).identities.length, 1); + assert.equal(selectTrustedPublisherIdentities(plan, 'cargo').identities.length, 1); + assert.throws(() => selectTrustedPublisherIdentities(plan, 'cargo', 1), /used only for npm/u); +}); + +test('rejects unknown or duplicate product selection', () => { + const value = lock([carrier('cargo', 'oliphaunt-one')]); + assert.throws( + () => buildTrustedPublisherPlan(value, { products: ['missing'] }), + /absent from the exact lock/u, + ); + assert.throws( + () => buildTrustedPublisherPlan(value, { products: ['one', 'one'] }), + /unique string list/u, + ); +}); + +test('classifies only the exact npm publish permission and caller identity as trusted', () => { + assert.deepEqual(classifyNpmTrustConfigs([]), { state: 'missing' }); + assert.deepEqual(classifyNpmTrustConfigs([exactNpm()]), { state: 'exact' }); + assert.equal(classifyNpmTrustConfigs([{ ...exactNpm(), file: 'wrong.yml' }]).state, 'conflict'); + assert.equal( + classifyNpmTrustConfigs([ + { + ...exactNpm(), + permissions: ['createPackage', 'createStagedPackage'], + }, + ]).state, + 'conflict', + ); + assert.equal(classifyNpmTrustConfigs([exactNpm(), exactNpm()]).state, 'conflict'); +}); + +test('classifies crates.io configuration strictly and treats extras as conflicts', () => { + assert.deepEqual(classifyCratesIoTrustConfigs([], 'oliphaunt-one'), { state: 'missing' }); + assert.deepEqual(classifyCratesIoTrustConfigs([exactCrates('oliphaunt-one')], 'oliphaunt-one'), { + state: 'exact', + }); + assert.equal( + classifyCratesIoTrustConfigs( + [ + { + ...exactCrates('oliphaunt-one'), + environment: null, + }, + ], + 'oliphaunt-one', + ).state, + 'conflict', + ); + assert.equal( + classifyCratesIoTrustConfigs( + [ + exactCrates('oliphaunt-one'), + { ...exactCrates('oliphaunt-one'), id: 2, repository_name: 'other' }, + ], + 'oliphaunt-one', + ).state, + 'conflict', + ); +}); + +test('file reports are atomically created as mode 0600, complete, and never overwritten', async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), 'oliphaunt-trust-report-')); + try { + const output = path.join(directory, 'npm-audit.json'); + const report = { + payload: 'x'.repeat(90_000), + tail: 'complete', + }; + assert.equal(await writeJsonFile(report, output), output); + assert.equal((await stat(output)).mode & 0o777, 0o600); + const bytes = await readFile(output, 'utf8'); + assert.ok(Buffer.byteLength(bytes) > 80 * 1024); + assert.equal(bytes.at(-1), '\n'); + assert.deepEqual(JSON.parse(bytes), report); + await assert.rejects( + () => writeJsonFile({ replaced: true }, output), + /refusing to overwrite existing --output file/u, + ); + assert.deepEqual(JSON.parse(await readFile(output, 'utf8')), report); + assert.deepEqual(await readdir(directory), ['npm-audit.json']); + } finally { + await rm(directory, { force: true, recursive: true }); + } +}); + +test('reservation never exposes the final path before a complete commit', async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), 'oliphaunt-trust-atomic-')); + try { + const output = path.join(directory, 'pending.json'); + const reserved = await reserveJsonFile(output); + await assert.rejects( + () => stat(output), + (cause) => cause.code === 'ENOENT', + ); + const during = await readdir(directory); + assert.ok(during.some((entry) => entry.endsWith('.oliphaunt-reservation'))); + assert.ok(during.some((entry) => entry.includes('.tmp-'))); + assert.ok(!during.includes('pending.json')); + assert.ok(!during.some((entry) => entry.includes('.probe-'))); + await reserved.abort(); + assert.deepEqual(await readdir(directory), []); + } finally { + await rm(directory, { force: true, recursive: true }); + } +}); + +test('report reservation fails before every registry call', async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), 'oliphaunt-trust-reservation-')); + try { + const existing = path.join(directory, 'existing.json'); + await writeJsonFile({ existing: true }, existing); + const plan = buildTrustedPublisherPlan(lock([carrier('npm', '@oliphaunt/example')])); + let calls = 0; + const options = { + plan, + ecosystem: 'npm', + batch: 1, + apply: true, + client: { + authorizeAudit() { + calls += 1; + }, + async list() { + calls += 1; + return []; + }, + async create() { + calls += 1; + }, + }, + sleepImpl: async () => {}, + }; + await assert.rejects( + () => + reconcileTrustedPublishersToFile({ + ...options, + outputFile: existing, + }), + /refusing to overwrite existing --output file/u, + ); + await assert.rejects( + () => + reconcileTrustedPublishersToFile({ + ...options, + outputFile: path.join(directory, 'missing-parent', 'report.json'), + }), + /could not reserve --output file/u, + ); + assert.equal(calls, 0, 'output reservation must precede registry calls'); + assert.deepEqual(await readdir(directory), ['existing.json']); + } finally { + await rm(directory, { force: true, recursive: true }); + } +}); + +test('crates.io client uses scoped bearer auth, exact payload, and no delete path', async () => { + const calls = []; + const client = createCratesIoTrustClient({ + token: 'configuration-secret', + fetchImpl: async (url, init) => { + calls.push({ url: String(url), init }); + if (init.method === 'GET') { + return new Response( + JSON.stringify({ + github_configs: [exactCrates('oliphaunt-one')], + meta: { total: 1, next_page: null }, + }), + ); + } + return new Response(JSON.stringify({ github_config: exactCrates('oliphaunt-one') })); + }, + sleepImpl: async () => {}, + }); + assert.deepEqual(await client.list('oliphaunt-one'), [exactCrates('oliphaunt-one')]); + await client.create('oliphaunt-one'); + const getUrl = new URL(calls[0].url); + assert.equal( + getUrl.origin + getUrl.pathname, + 'https://crates.io/api/v1/trusted_publishing/github_configs', + ); + assert.equal(getUrl.searchParams.get('crate'), 'oliphaunt-one'); + assert.equal( + new Headers(calls[0].init.headers).get('authorization'), + 'Bearer configuration-secret', + ); + assert.deepEqual(JSON.parse(calls[1].init.body), { + github_config: { + crate: 'oliphaunt-one', + repository_owner: 'f0rr0', + repository_name: 'oliphaunt', + workflow_filename: 'release.yml', + environment: 'release-publish', + }, + }); + assert.ok(calls.every(({ init }) => init.method !== 'DELETE')); +}); + +test('crates.io read audit retries bounded retryable responses but create is not replayed', async () => { + let reads = 0; + const sleeps = []; + const client = createCratesIoTrustClient({ + token: 'configuration-secret', + fetchImpl: async (_url, init) => { + if (init.method === 'POST') return new Response('unavailable', { status: 503 }); + reads += 1; + if (reads === 1) + return new Response('busy', { status: 503, headers: { 'Retry-After': '0' } }); + return new Response( + JSON.stringify({ github_configs: [], meta: { total: 0, next_page: null } }), + ); + }, + sleepImpl: async (milliseconds) => sleeps.push(milliseconds), + }); + assert.deepEqual(await client.list('oliphaunt-one'), []); + assert.equal(reads, 2); + assert.deepEqual(sleeps, [0]); + await assert.rejects(() => client.create('oliphaunt-one'), /HTTP 503/u); +}); + +test('apply is pre-audited, idempotent, and verified after each missing configuration', async () => { + const plan = buildTrustedPublisherPlan( + lock([carrier('cargo', 'oliphaunt-one'), carrier('cargo', 'oliphaunt-two')]), + ); + const state = new Map([ + ['oliphaunt-one', [exactCrates('oliphaunt-one')]], + ['oliphaunt-two', []], + ]); + const creates = []; + const sleeps = []; + const events = []; + const client = { + async list(name) { + events.push(`list:${name}`); + return structuredClone(state.get(name)); + }, + async create(name) { + events.push(`create:${name}`); + creates.push(name); + state.set(name, [exactCrates(name)]); + }, + }; + const report = await reconcileTrustedPublishers({ + plan, + ecosystem: 'cargo', + apply: true, + client, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + events.push(`sleep:${milliseconds}`); + }, + }); + assert.equal(report.mode, 'apply'); + assert.deepEqual(report.missing, []); + assert.deepEqual(report.conflicts, []); + assert.deepEqual(report.created, ['cargo:oliphaunt-two']); + assert.deepEqual(creates, ['oliphaunt-two']); + assert.equal(sleeps.length, 6); + assert.deepEqual(events.slice(0, 5), [ + 'list:oliphaunt-one', + 'sleep:250', + 'list:oliphaunt-two', + 'sleep:250', + 'create:oliphaunt-two', + ]); + + const second = await reconcileTrustedPublishers({ + plan, + ecosystem: 'cargo', + apply: true, + client, + sleepImpl: async () => {}, + }); + assert.deepEqual(second.created, []); + assert.deepEqual(creates, ['oliphaunt-two']); +}); + +test('an applied trusted-publisher mutation with a lost response reconciles without replay', async () => { + const plan = buildTrustedPublisherPlan(lock([carrier('cargo', 'oliphaunt-one')])); + let present = false; + let creates = 0; + const report = await reconcileTrustedPublishers({ + plan, + ecosystem: 'cargo', + apply: true, + client: { + async list() { + return present ? [exactCrates('oliphaunt-one')] : []; + }, + async create() { + creates += 1; + present = true; + throw new Error('response timed out after the registry applied the configuration'); + }, + }, + sleepImpl: async () => {}, + }); + assert.equal(creates, 1); + assert.deepEqual(report.created, ['cargo:oliphaunt-one']); + assert.deepEqual(report.missing, []); + assert.deepEqual(report.conflicts, []); +}); + +test('any conflicting configuration blocks every mutation in the selected batch', async () => { + const plan = buildTrustedPublisherPlan( + lock([carrier('cargo', 'oliphaunt-one'), carrier('cargo', 'oliphaunt-two')]), + ); + let creates = 0; + const client = { + async list(name) { + return name === 'oliphaunt-one' + ? [] + : [{ ...exactCrates(name), workflow_filename: 'wrong.yml' }]; + }, + async create() { + creates += 1; + }, + }; + const report = await reconcileTrustedPublishers({ + plan, + ecosystem: 'cargo', + apply: true, + client, + sleepImpl: async () => {}, + }); + assert.equal(report.mode, 'apply-blocked'); + assert.equal(report.conflicts.length, 1); + assert.equal(creates, 0); +}); diff --git a/tools/release/trusted-publisher-config.test.sh b/tools/release/trusted-publisher-config.test.sh new file mode 100644 index 000000000..4ffbdd937 --- /dev/null +++ b/tools/release/trusted-publisher-config.test.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +source_root="$PWD" +bun test ./tools/release/trusted-publisher-config.test.mts +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +bun tools/release/trusted-publisher-config.test.mts pipe | cat > "$scratch/pipe.json" +bun tools/release/trusted-publisher-config.test.mts assert-pipe "$scratch/pipe.json" +if [[ "$(uname -s)" != Linux ]]; then + echo 'Trusted publisher: JSON pipe passed; Linux script(1) terminal test not run on this host' + exit 0 +fi +mkdir "$scratch/bin" +printf '#!/usr/bin/env bash\n[ "$1" = 2 ]\n' > "$scratch/bin/sleep" +cat > "$scratch/bin/npm" <<'SH' +#!/usr/bin/env bash +set -eu +if [ "$1" = --version ]; then echo 11.15.0; exit; fi +[ "$1" = trust ] +printf '%s %s %s\n' "$2" "$3" "$NPM_CONFIG_FETCH_RETRIES" >> "$TEST_EVENTS" +if [ "$2" = list ]; then + [ "$#" = 6 ] && [ "$4" = --json ] && [ "$5" = --registry ] && [ "$6" = https://registry.npmjs.org/ ] + [ "$NPM_CONFIG_FETCH_RETRIES" = 3 ] + if [ -t 1 ]; then [ -t 0 ]; echo 'discard this authentication display'; exit; fi + if [ "$TEST_SCENARIO" = conflict ]; then echo "$TEST_CONFLICT"; exit; fi + if [ -f "$TEST_STATE" ]; then echo "$TEST_EXACT"; else echo '[]'; fi +elif [ "$2" = github ]; then + [ -t 0 ] && [ -t 1 ] + [ "$NPM_CONFIG_FETCH_RETRIES" = 0 ] + [ "$*" = 'trust github @oliphaunt/example --file release.yml --repo f0rr0/oliphaunt --env release-publish --allow-publish --yes --json --registry https://registry.npmjs.org/' ] + if [ "$TEST_SCENARIO" != missing ]; then touch "$TEST_STATE"; fi + exit 7 +else exit 91; fi +SH +chmod +x "$scratch/bin/"* +export SHELL=/bin/bash BASH_ENV=/dev/null PATH="$scratch/bin:$PATH" +export TEST_SHELL="$source_root/tools/release/trusted-publisher-config.sh" TEST_ROOT="$scratch" +invoke() { + status=0 + timeout 15 script --return --quiet --command 'bash "$TEST_SHELL" --npm "$TEST_ROOT"' /dev/null > "$scratch/result" 2>&1 || status=$? +} +for scenario in ambiguous rerun conflict missing; do + bun tools/release/trusted-publisher-config.test.mts prepare "$scratch" "$scenario" + export TEST_EVENTS="$scratch/$scenario.events" TEST_STATE="$scratch/$scenario.state" TEST_SCENARIO="$scenario" + export TEST_EXACT="$(cat "$scratch/exact.json")" TEST_CONFLICT="$(cat "$scratch/conflicting.json")" + invoke + expected=0 + [[ "$scenario" != conflict ]] || expected=1 + [[ "$scenario" != missing ]] || expected=2 + if [[ "$status" != "$expected" ]]; then cat "$scratch/result" >&2; exit 1; fi + bun tools/release/trusted-publisher-config.test.mts assert "$scratch" "$scenario" + if [[ "$scenario" == missing ]]; then continue; fi + cp "$scratch/$scenario.json" "$scratch/before.json" + cp "$TEST_EVENTS" "$scratch/before.events" + invoke + [[ "$status" != 0 && "$status" != 124 ]] + cmp "$scratch/before.json" "$scratch/$scenario.json" + cmp "$scratch/before.events" "$TEST_EVENTS" +done +echo 'Trusted publisher: complete pipe output, terminal auth, conflict blocking and one-mutation reconciliation passed' diff --git a/tools/release/upload-github-release-assets.test.mjs b/tools/release/upload-github-release-assets.test.mjs deleted file mode 100644 index 3c7bb1dd2..000000000 --- a/tools/release/upload-github-release-assets.test.mjs +++ /dev/null @@ -1,599 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { createHash } from "node:crypto"; -import { - existsSync, - mkdtempSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { - exactReleaseMetadata, - readReleaseByTagSync, -} from "./github-release-mutations.mjs"; -import { readGitHubCoreRequestJournal } from "./github-core-request-journal.mjs"; -import { - assertExactFrozenUploadSelection, - DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, - exactReleaseAssetUploadArgs, - githubReleaseAssetUploadWindowMs, - GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, - MAX_SAFE_EMBEDDED_RELEASE_ASSETS, - readExactReleaseAssetSnapshotSync, - uploadFrozenReleaseAssetsSync, - withStagedFrozenAssetSync, -} from "./upload_github_release_assets.mjs"; -import { GITHUB_CONTENT_WRITE_INTERVAL_MS } from "./github-content-write-pacer.mjs"; - -const HEAD = "a".repeat(40); - -function budget(environment = {}) { - return { deadlineMs: 60_000, environment, now: () => 0, startedAtMs: 0 }; -} - -function frozenAsset(name, index, size = index + 1) { - return { - file: `/unused/${name}`, - name, - sha256: index.toString(16).padStart(64, "0"), - size, - }; -} - -function plan( - assets = [frozenAsset("one.tgz", 1)], - product = "oliphaunt-js", -) { - const tag = `${product}-v0.1.0`; - return { - assets, - headRef: HEAD, - lockDigest: "f".repeat(64), - metadata: exactReleaseMetadata({ - body: "immutable notes", - headRef: HEAD, - product, - tag, - version: "0.1.0", - }), - product, - repo: "o/r", - tag, - }; -} - -function remoteAsset(asset, id, digest = `sha256:${asset.sha256}`) { - return { - digest, - id, - name: asset.name, - size: asset.size, - state: "uploaded", - }; -} - -function releaseFor(uploadPlan, remote, { draft = true, id = 73 } = {}) { - return { - ...uploadPlan.metadata, - assets: [...remote.values()], - draft, - id, - }; -} - -function deterministicReads(maxAttempts = 1) { - return { - baseDelayMs: 0, - maxAttempts, - maxDelayMs: 0, - sleep: () => {}, - }; -} - -function includedJson(data) { - return [ - "HTTP/2.0 200 OK", - "Content-Type: application/json; charset=utf-8", - "", - JSON.stringify(data), - ].join("\n"); -} - -test("the upload operation window is derived from the exact frozen asset count", () => { - const assetCount = 19; - const required = (assetCount * ( - GITHUB_CONTENT_WRITE_INTERVAL_MS + DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS - )) + GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS; - assert.equal(githubReleaseAssetUploadWindowMs(assetCount), required); - assert.ok(required > 20 * 60_000); - assert.throws( - () => githubReleaseAssetUploadWindowMs(294), - /package the product into fewer aggregate assets/u, - ); -}); - -function uploadDependencies(uploadPlan, remote, overrides = {}) { - let lastRelease = null; - const selectedReadRelease = overrides.readRelease ?? (() => releaseFor(uploadPlan, remote)); - const selectedReadAssets = overrides.readAssets ?? (() => new Map( - (lastRelease?.assets ?? []).map((asset) => [asset.name, asset]), - )); - return { - budget: budget(), - environment: {}, - readReleaseById: (...args) => { - lastRelease = selectedReadRelease(...args); - return lastRelease; - }, - readReleaseMap: (...args) => { - lastRelease = selectedReadRelease(...args); - return lastRelease === null - ? new Map() - : new Map([[lastRelease.tag_name, lastRelease]]); - }, - readAssets: (...args) => selectedReadAssets(...args), - snapshotReadOptions: deterministicReads(), - uploadAsset: ({ asset }) => { - remote.set(asset.name, remoteAsset(asset, 100 + remote.size)); - }, - withStagedAsset: (asset, operation) => operation(`/staged/${asset.name}`), - ...Object.fromEntries(Object.entries(overrides).filter(([key]) => - key !== "readAssets" && key !== "readRelease")), - }; -} - -test("an intentional empty frozen upload selection is exact and source-only", () => { - assert.doesNotThrow(() => - assertExactFrozenUploadSelection([], new Set(), "oliphaunt-swift")); - assert.throws( - () => assertExactFrozenUploadSelection( - [{ path: "/frozen/unexpected.tgz", type: "file" }], - new Set(), - "oliphaunt-swift", - ), - /do not exactly match/u, - ); - assert.throws( - () => assertExactFrozenUploadSelection( - [{ path: "/frozen/tree", type: "directory" }], - new Set([path.resolve("/frozen/tree")]), - "oliphaunt-swift", - ), - /only regular files/u, - ); -}); - -test("the upload request is bound to one immutable release id and frozen asset name", () => { - assert.deepEqual( - exactReleaseAssetUploadArgs({ - assetName: "one+linux.tgz", - file: "/staged/one+linux.tgz", - releaseId: 73, - repo: "o/r", - }), - [ - "api", - "https://uploads.github.com/repos/o/r/releases/73/assets?name=one%2Blinux.tgz", - "-X", - "POST", - "-H", - "Accept: application/vnd.github+json", - "-H", - "Content-Type: application/octet-stream", - "-H", - "X-GitHub-Api-Version: 2022-11-28", - "--input", - "/staged/one+linux.tgz", - ], - ); - assert.throws( - () => exactReleaseAssetUploadArgs({ - assetName: "one.tgz", - file: "/staged/two.tgz", - releaseId: 73, - repo: "o/r", - }), - /retain its frozen asset name/u, - ); -}); - -test("draft upload discovery uses the complete release list, then the exact release id", (t) => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-draft-upload-discovery-")); - t.after(() => rmSync(root, { force: true, recursive: true })); - const environment = { - GITHUB_ACTIONS: "true", - GITHUB_REPOSITORY: "o/r", - GITHUB_RUN_ATTEMPT: "1", - GITHUB_RUN_ID: "123", - GITHUB_SHA: HEAD, - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, "journal.json"), - OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: "true", - }; - const uploadPlan = plan(); - const draft = releaseFor(uploadPlan, new Map(), { draft: true, id: 73 }); - const endpoints = []; - const spawn = (_command, args) => { - const endpoint = args.at(-1); - endpoints.push(endpoint); - if (endpoint.includes("/releases/tags/")) { - return { status: 1, stderr: "gh: Not Found (HTTP 404)", stdout: "" }; - } - if (endpoint === "repos/o/r/releases?per_page=100&page=1") { - return { status: 0, stderr: "", stdout: includedJson([draft]) }; - } - if (endpoint === "repos/o/r/releases/73") { - return { status: 0, stderr: "", stdout: JSON.stringify(draft) }; - } - if (endpoint === "repos/o/r/releases/73/assets?per_page=100&page=1") { - return { status: 0, stderr: "", stdout: includedJson([]) }; - } - return { status: 1, stderr: `unexpected endpoint ${endpoint}`, stdout: "" }; - }; - const readOptions = { - baseDelayMs: 0, - coreJournalOptions: { now: () => 20_000 }, - deadlineMs: 10_000, - environment, - maxAttempts: 1, - maxDelayMs: 0, - now: () => 20_000, - sleep: () => {}, - spawn, - }; - - assert.equal( - readReleaseByTagSync("o/r", uploadPlan.tag, readOptions), - null, - "GitHub's by-tag endpoint does not expose the draft", - ); - endpoints.length = 0; - - const initial = readExactReleaseAssetSnapshotSync({ - budget: budget(environment), - expectedReleaseId: undefined, - phase: "pre-upload", - plan: uploadPlan, - }, { singleReadOptions: readOptions }); - assert.equal(initial.release.draft, true); - assert.equal(initial.releaseId, 73); - assert.deepEqual(endpoints, [ - "repos/o/r/releases?per_page=100&page=1", - "repos/o/r/releases/73/assets?per_page=100&page=1", - ]); - - endpoints.length = 0; - const later = readExactReleaseAssetSnapshotSync({ - budget: budget(environment), - expectedReleaseId: 73, - phase: "post-upload", - plan: uploadPlan, - }, { singleReadOptions: readOptions }); - assert.equal(later.release.draft, true); - assert.equal(later.releaseId, 73); - assert.deepEqual(endpoints, [ - "repos/o/r/releases/73", - "repos/o/r/releases/73/assets?per_page=100&page=1", - ]); - assert.deepEqual( - readGitHubCoreRequestJournal({ environment, now: () => 20_000 }), - { enabled: true, rollingCount: 5, sequence: 5 }, - ); -}); - -test("one product snapshot skips matching assets and uploads missing assets sequentially", () => { - const assets = [frozenAsset("one.tgz", 1), frozenAsset("two.tgz", 2)]; - const uploadPlan = plan(assets); - const remote = new Map([[assets[0].name, remoteAsset(assets[0], 80)]]); - const uploaded = []; - let activeStages = 0; - let maximumActiveStages = 0; - const result = uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, remote, { - uploadAsset: ({ asset }) => { - uploaded.push(asset.name); - remote.set(asset.name, remoteAsset(asset, 81)); - }, - withStagedAsset: (asset, operation) => { - activeStages += 1; - maximumActiveStages = Math.max(maximumActiveStages, activeStages); - try { - return operation(`/staged/${asset.name}`); - } finally { - activeStages -= 1; - } - }, - })); - assert.deepEqual(uploaded, ["two.tgz"]); - assert.equal(maximumActiveStages, 1); - assert.deepEqual(result, { recoveredUploads: 0, uploadedAssets: 1 }); -}); - -test("a peer abort stops the next mutation only after reconciling an in-flight exact upload", (t) => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-upload-peer-abort-")); - t.after(() => rmSync(root, { force: true, recursive: true })); - const abortPath = path.join(root, "abort.json"); - const uploadPlan = plan([ - frozenAsset("first.tgz", 1), - frozenAsset("must-not-upload.tgz", 2), - ]); - const remote = new Map(); - let mutationCalls = 0; - let snapshotReads = 0; - assert.throws( - () => uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, remote, { - environment: { OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH: abortPath }, - readAssets: () => { - snapshotReads += 1; - return new Map(remote); - }, - uploadAsset: ({ asset }) => { - mutationCalls += 1; - remote.set(asset.name, remoteAsset(asset, 900 + mutationCalls)); - writeFileSync(abortPath, '{"reason":"peer failed"}\n', { flag: "wx" }); - }, - })), - /peer product upload lane failed/u, - ); - assert.equal(mutationCalls, 1); - assert.deepEqual([...remote.keys()], ["first.tgz"]); - assert.ok(snapshotReads >= 2, "the completed immutable upload is re-snapshotted before aborting"); -}); - -for (const product of ["oliphaunt-swift", "oliphaunt-kotlin", "oliphaunt-react-native"]) { - test(`${product} accepts only an exact empty remote GitHub asset set`, () => { - const emptyPlan = plan([], product); - const remote = new Map(); - assert.deepEqual( - uploadFrozenReleaseAssetsSync(emptyPlan, uploadDependencies(emptyPlan, remote, { - uploadAsset: () => assert.fail("an empty frozen asset set must not upload"), - withStagedAsset: () => assert.fail("an empty frozen asset set must not stage files"), - })), - { recoveredUploads: 0, uploadedAssets: 0 }, - ); - - const unexpected = frozenAsset("unexpected.tgz", 9); - remote.set(unexpected.name, remoteAsset(unexpected, 91)); - assert.throws( - () => uploadFrozenReleaseAssetsSync(emptyPlan, uploadDependencies(emptyPlan, remote)), - /excludes unexpected remote assets: unexpected\.tgz/u, - ); - }); -} - -test("an applied-but-ambiguous upload is reconciled once without replay", () => { - const uploadPlan = plan(); - const remote = new Map(); - let mutationCalls = 0; - const result = uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, remote, { - uploadAsset: ({ asset }) => { - mutationCalls += 1; - remote.set(asset.name, remoteAsset(asset, 82)); - throw new Error("response timed out after upload"); - }, - })); - assert.equal(mutationCalls, 1); - assert.deepEqual(result, { recoveredUploads: 1, uploadedAssets: 1 }); -}); - -test("a failed upload is never replayed while its immutable asset remains absent", () => { - const uploadPlan = plan(); - const remote = new Map(); - let mutationCalls = 0; - assert.throws( - () => uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, remote, { - uploadAsset: () => { - mutationCalls += 1; - throw new Error("connection refused before send"); - }, - })), - /upload failed.*did not reconcile/isu, - ); - assert.equal(mutationCalls, 1); -}); - -test("size, digest, and extra-asset conflicts are terminal before mutation", () => { - const uploadPlan = plan(); - const asset = uploadPlan.assets[0]; - const conflicts = [ - new Map([[asset.name, { ...remoteAsset(asset, 80), size: asset.size + 1 }]]), - new Map([[asset.name, remoteAsset(asset, 80, `sha256:${"9".repeat(64)}`)]]), - new Map([["extra.tgz", remoteAsset({ ...asset, name: "extra.tgz" }, 80)]]), - ]; - for (const remote of conflicts) { - let mutationCalls = 0; - assert.throws( - () => uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, remote, { - uploadAsset: () => { mutationCalls += 1; }, - })), - /remote size|remote digest|unexpected remote assets/u, - ); - assert.equal(mutationCalls, 0); - } -}); - -test("an already-public release cannot receive a missing frozen asset", () => { - const uploadPlan = plan(); - const remote = new Map(); - let mutationCalls = 0; - assert.throws( - () => uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, remote, { - readRelease: () => releaseFor(uploadPlan, remote, { draft: false }), - uploadAsset: () => { mutationCalls += 1; }, - })), - /already public but is missing frozen assets/u, - ); - assert.equal(mutationCalls, 0); -}); - -test("missing releases and authentication failures issue no upload", () => { - const uploadPlan = plan(); - for (const [expected, readRelease] of [ - [/does not exist/u, () => null], - [/HTTP 401/u, () => { throw Object.assign(new Error("HTTP 401 bad credentials"), { retryable: false }); }], - ]) { - let mutationCalls = 0; - assert.throws( - () => uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, new Map(), { - readRelease, - uploadAsset: () => { mutationCalls += 1; }, - })), - expected, - ); - assert.equal(mutationCalls, 0); - } -}); - -test("a pending GitHub SHA-256 digest converges through bounded product snapshots", () => { - const uploadPlan = plan(); - const asset = uploadPlan.assets[0]; - let reads = 0; - const result = uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, new Map(), { - readRelease: () => { - reads += 1; - const digest = reads === 1 ? null : `sha256:${asset.sha256}`; - return releaseFor(uploadPlan, new Map([[asset.name, remoteAsset(asset, 80, digest)]])); - }, - snapshotReadOptions: deterministicReads(2), - uploadAsset: () => assert.fail("a converged existing asset must not upload"), - })); - assert.equal(reads, 2); - assert.deepEqual(result, { recoveredUploads: 0, uploadedAssets: 0 }); -}); - -test("GitHub open state and empty digest converge without losing immutable asset identity", () => { - const uploadPlan = plan(); - const asset = uploadPlan.assets[0]; - let reads = 0; - const result = uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, new Map(), { - readRelease: () => { - reads += 1; - const remote = remoteAsset(asset, 80, reads === 2 ? "" : `sha256:${asset.sha256}`); - if (reads === 1) { - remote.digest = null; - remote.size = 0; - remote.state = "open"; - } - return releaseFor(uploadPlan, new Map([[asset.name, remote]])); - }, - snapshotReadOptions: deterministicReads(3), - uploadAsset: () => assert.fail("a converging existing asset must not upload"), - })); - assert.equal(reads, 3); - assert.deepEqual(result, { recoveredUploads: 0, uploadedAssets: 0 }); -}); - -test("a missing GitHub digest fails closed after the bounded snapshot budget", () => { - const uploadPlan = plan(); - const asset = uploadPlan.assets[0]; - let reads = 0; - assert.throws( - () => uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, new Map(), { - readRelease: () => { - reads += 1; - return releaseFor(uploadPlan, new Map([[asset.name, remoteAsset(asset, 80, null)]])); - }, - snapshotReadOptions: deterministicReads(2), - })), - /pending asset metadata/u, - ); - assert.equal(reads, 2); -}); - -test("release replacement during upload is terminal even when the asset bytes match", () => { - const uploadPlan = plan(); - const remote = new Map(); - let releaseReads = 0; - let mutationCalls = 0; - assert.throws( - () => uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, remote, { - readRelease: () => { - releaseReads += 1; - return releaseFor(uploadPlan, remote, { id: releaseReads === 1 ? 73 : 99 }); - }, - uploadAsset: ({ asset }) => { - mutationCalls += 1; - remote.set(asset.name, remoteAsset(asset, 83)); - }, - })), - /release id changed from 73 to 99/u, - ); - assert.equal(mutationCalls, 1); -}); - -test("asset replacement while GitHub digest metadata converges is terminal", () => { - const uploadPlan = plan(); - const asset = uploadPlan.assets[0]; - let releaseReads = 0; - let mutationCalls = 0; - assert.throws( - () => uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, new Map(), { - readRelease: () => { - releaseReads += 1; - if (releaseReads === 1) return releaseFor(uploadPlan, new Map()); - const digest = releaseReads === 2 ? null : `sha256:${asset.sha256}`; - const id = releaseReads === 2 ? 80 : 81; - return releaseFor(uploadPlan, new Map([[asset.name, remoteAsset(asset, id, digest)]])); - }, - snapshotReadOptions: deterministicReads(2), - uploadAsset: () => { mutationCalls += 1; }, - })), - /remote asset id changed from 80 to 81/u, - ); - assert.equal(mutationCalls, 1); -}); - -test("large future product inventories use the paginated asset endpoint", () => { - const assets = Array.from({ length: MAX_SAFE_EMBEDDED_RELEASE_ASSETS + 1 }, (_, index) => - frozenAsset(`asset-${index}.tgz`, index + 1)); - const uploadPlan = plan(assets); - const remote = new Map(assets.map((asset, index) => [asset.name, remoteAsset(asset, index + 1)])); - let releaseReads = 0; - let paginatedReads = 0; - const result = uploadFrozenReleaseAssetsSync(uploadPlan, uploadDependencies(uploadPlan, remote, { - readAssets: () => { - paginatedReads += 1; - return new Map(remote); - }, - readRelease: () => { - releaseReads += 1; - return { ...releaseFor(uploadPlan, remote), assets: [] }; - }, - })); - assert.equal(releaseReads, 1); - assert.equal(paginatedReads, 1); - assert.deepEqual(result, { recoveredUploads: 0, uploadedAssets: 0 }); -}); - -test("staged upload bytes are verified and temporary state is removed on failure", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-upload-stage-test-")); - const source = path.join(root, "one.tgz"); - writeFileSync(source, "exact bytes"); - const asset = { - file: source, - name: "one.tgz", - sha256: createHash("sha256").update("exact bytes").digest("hex"), - size: Buffer.byteLength("exact bytes"), - }; - const stages = []; - try { - assert.throws( - () => withStagedFrozenAssetSync(asset, () => { - throw new Error("simulated upload interruption"); - }, { - mkdtemp: () => { - const directory = mkdtempSync(path.join(root, "stage-")); - stages.push(directory); - return directory; - }, - }), - /simulated upload interruption/u, - ); - assert.equal(stages.length, 1); - assert.equal(existsSync(stages[0]), false); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); diff --git a/tools/release/upload-github-release-assets.test.mts b/tools/release/upload-github-release-assets.test.mts new file mode 100644 index 000000000..8188f6a86 --- /dev/null +++ b/tools/release/upload-github-release-assets.test.mts @@ -0,0 +1,617 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { GITHUB_CONTENT_WRITE_INTERVAL_MS } from './github-content-write-pacer.mts'; +import { readGitHubCoreRequestJournal } from './github-core-request-journal.mts'; +import { exactReleaseMetadata, readReleaseByTag } from './github-release-mutations.mts'; +import { + assertExactFrozenUploadSelection, + DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, + GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, + githubReleaseAssetUploadWindowMs, + MAX_SAFE_EMBEDDED_RELEASE_ASSETS, + readExactReleaseAssetSnapshot, + uploadFrozenReleaseAssets, + withStagedFrozenAsset, +} from './upload_github_release_assets.mts'; + +const HEAD = 'a'.repeat(40); + +function budget(environment = {}) { + return { deadlineMs: 60_000, environment, now: () => 0, startedAtMs: 0 }; +} + +function frozenAsset(name, index, size = index + 1) { + return { + file: `/unused/${name}`, + name, + sha256: index.toString(16).padStart(64, '0'), + size, + }; +} + +function plan(assets = [frozenAsset('one.tgz', 1)], product = 'oliphaunt-js') { + const tag = `${product}-v0.1.0`; + return { + assets, + headRef: HEAD, + lockDigest: 'f'.repeat(64), + metadata: exactReleaseMetadata({ + body: 'immutable notes', + headRef: HEAD, + product, + tag, + version: '0.1.0', + }), + product, + repo: 'o/r', + tag, + }; +} + +function remoteAsset(asset, id, digest = `sha256:${asset.sha256}`) { + return { + digest, + id, + name: asset.name, + size: asset.size, + state: 'uploaded', + }; +} + +function releaseFor(uploadPlan, remote, { draft = true, id = 73 } = {}) { + return { + ...uploadPlan.metadata, + assets: [...remote.values()], + draft, + id, + }; +} + +function deterministicReads(maxAttempts = 1) { + return { + baseDelayMs: 0, + maxAttempts, + maxDelayMs: 0, + sleep: () => {}, + }; +} + +test('the upload operation window is derived from the exact frozen asset count', () => { + const assetCount = 19; + const required = + assetCount * + (GITHUB_CONTENT_WRITE_INTERVAL_MS + DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS) + + GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS; + assert.equal(githubReleaseAssetUploadWindowMs(assetCount), required); + assert.ok(required > 20 * 60_000); + assert.throws( + () => githubReleaseAssetUploadWindowMs(294), + /package the product into fewer aggregate assets/u, + ); +}); + +function uploadDependencies(uploadPlan, remote, overrides = {}) { + let lastRelease = null; + const selectedReadRelease = overrides.readRelease ?? (() => releaseFor(uploadPlan, remote)); + const selectedReadAssets = + overrides.readAssets ?? + (() => new Map((lastRelease?.assets ?? []).map((asset) => [asset.name, asset]))); + return { + budget: budget(), + environment: {}, + readReleaseById: (...args) => { + lastRelease = selectedReadRelease(...args); + return lastRelease; + }, + readReleaseMap: (...args) => { + lastRelease = selectedReadRelease(...args); + return lastRelease === null ? new Map() : new Map([[lastRelease.tag_name, lastRelease]]); + }, + readAssets: (...args) => selectedReadAssets(...args), + snapshotReadOptions: deterministicReads(), + uploadAsset: ({ asset }) => { + remote.set(asset.name, remoteAsset(asset, 100 + remote.size)); + }, + withStagedAsset: async (asset, operation) => await operation(`/staged/${asset.name}`), + ...Object.fromEntries( + Object.entries(overrides).filter(([key]) => key !== 'readAssets' && key !== 'readRelease'), + ), + }; +} + +test('an intentional empty frozen upload selection is exact and source-only', () => { + assert.doesNotThrow(() => assertExactFrozenUploadSelection([], new Set(), 'oliphaunt-swift')); + assert.throws( + () => + assertExactFrozenUploadSelection( + [{ path: '/frozen/unexpected.tgz', type: 'file' }], + new Set(), + 'oliphaunt-swift', + ), + /do not exactly match/u, + ); + assert.throws( + () => + assertExactFrozenUploadSelection( + [{ path: '/frozen/tree', type: 'directory' }], + new Set([path.resolve('/frozen/tree')]), + 'oliphaunt-swift', + ), + /only regular files/u, + ); +}); + +test('draft upload discovery uses the complete release list, then the exact release id', async (t) => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-draft-upload-discovery-')); + t.after(() => rmSync(root, { force: true, recursive: true })); + const environment = { + GITHUB_ACTIONS: 'true', + GITHUB_REPOSITORY: 'o/r', + GITHUB_RUN_ATTEMPT: '1', + GITHUB_RUN_ID: '123', + GITHUB_SHA: HEAD, + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: path.join(root, 'journal.json'), + OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: 'true', + }; + const uploadPlan = plan(); + const draft = releaseFor(uploadPlan, new Map(), { draft: true, id: 73 }); + const endpoints = []; + const fetchImpl = (url) => { + const endpoint = String(url).replace('https://api.github.com/', ''); + endpoints.push(endpoint); + if (endpoint.includes('/releases/tags/')) { + return new Response('', { status: 404 }); + } + if (endpoint === 'repos/o/r/releases?per_page=100&page=1') { + return Response.json([draft]); + } + if (endpoint === 'repos/o/r/releases/73') { + return Response.json(draft); + } + if (endpoint === 'repos/o/r/releases/73/assets?per_page=100&page=1') { + return Response.json([]); + } + throw new Error(`unexpected endpoint ${endpoint}`); + }; + const readOptions = { + baseDelayMs: 0, + coreJournalOptions: { now: () => 20_000 }, + deadlineMs: 10_000, + environment, + maxAttempts: 1, + maxDelayMs: 0, + now: () => 20_000, + sleep: () => {}, + fetchImpl, + }; + + assert.equal( + await readReleaseByTag('o/r', uploadPlan.tag, readOptions), + null, + "GitHub's by-tag endpoint does not expose the draft", + ); + endpoints.length = 0; + + const initial = await readExactReleaseAssetSnapshot( + { + budget: budget(environment), + expectedReleaseId: undefined, + phase: 'pre-upload', + plan: uploadPlan, + }, + { singleReadOptions: readOptions }, + ); + assert.equal(initial.release.draft, true); + assert.equal(initial.releaseId, 73); + assert.deepEqual(endpoints, [ + 'repos/o/r/releases?per_page=100&page=1', + 'repos/o/r/releases/73/assets?per_page=100&page=1', + ]); + + endpoints.length = 0; + const later = await readExactReleaseAssetSnapshot( + { + budget: budget(environment), + expectedReleaseId: 73, + phase: 'post-upload', + plan: uploadPlan, + }, + { singleReadOptions: readOptions }, + ); + assert.equal(later.release.draft, true); + assert.equal(later.releaseId, 73); + assert.deepEqual(endpoints, [ + 'repos/o/r/releases/73', + 'repos/o/r/releases/73/assets?per_page=100&page=1', + ]); + assert.deepEqual(readGitHubCoreRequestJournal({ environment, now: () => 20_000 }), { + enabled: true, + rollingCount: 5, + sequence: 5, + }); +}); + +test('one product snapshot skips matching assets and uploads missing assets sequentially', async () => { + const assets = [frozenAsset('one.tgz', 1), frozenAsset('two.tgz', 2)]; + const uploadPlan = plan(assets); + const remote = new Map([[assets[0].name, remoteAsset(assets[0], 80)]]); + const uploaded = []; + let activeStages = 0; + let maximumActiveStages = 0; + const result = await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, remote, { + uploadAsset: ({ asset }) => { + uploaded.push(asset.name); + remote.set(asset.name, remoteAsset(asset, 81)); + }, + withStagedAsset: async (asset, operation) => { + activeStages += 1; + maximumActiveStages = Math.max(maximumActiveStages, activeStages); + try { + return await operation(`/staged/${asset.name}`); + } finally { + activeStages -= 1; + } + }, + }), + ); + assert.deepEqual(uploaded, ['two.tgz']); + assert.equal(maximumActiveStages, 1); + assert.deepEqual(result, { recoveredUploads: 0, uploadedAssets: 1 }); +}); + +test('a peer abort stops the next mutation only after reconciling an in-flight exact upload', async (t) => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-upload-peer-abort-')); + t.after(() => rmSync(root, { force: true, recursive: true })); + const abortPath = path.join(root, 'abort.json'); + const uploadPlan = plan([frozenAsset('first.tgz', 1), frozenAsset('must-not-upload.tgz', 2)]); + const remote = new Map(); + let mutationCalls = 0; + let snapshotReads = 0; + await assert.rejects( + async () => + await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, remote, { + environment: { OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH: abortPath }, + readAssets: () => { + snapshotReads += 1; + return new Map(remote); + }, + uploadAsset: ({ asset }) => { + mutationCalls += 1; + remote.set(asset.name, remoteAsset(asset, 900 + mutationCalls)); + writeFileSync(abortPath, '{"reason":"peer failed"}\n', { flag: 'wx' }); + }, + }), + ), + /peer product upload lane failed/u, + ); + assert.equal(mutationCalls, 1); + assert.deepEqual([...remote.keys()], ['first.tgz']); + assert.ok(snapshotReads >= 2, 'the completed immutable upload is re-snapshotted before aborting'); +}); + +for (const product of ['oliphaunt-swift', 'oliphaunt-kotlin', 'oliphaunt-react-native']) { + test(`${product} accepts only an exact empty remote GitHub asset set`, async () => { + const emptyPlan = plan([], product); + const remote = new Map(); + assert.deepEqual( + await uploadFrozenReleaseAssets( + emptyPlan, + uploadDependencies(emptyPlan, remote, { + uploadAsset: () => assert.fail('an empty frozen asset set must not upload'), + withStagedAsset: () => assert.fail('an empty frozen asset set must not stage files'), + }), + ), + { recoveredUploads: 0, uploadedAssets: 0 }, + ); + + const unexpected = frozenAsset('unexpected.tgz', 9); + remote.set(unexpected.name, remoteAsset(unexpected, 91)); + await assert.rejects( + async () => await uploadFrozenReleaseAssets(emptyPlan, uploadDependencies(emptyPlan, remote)), + /excludes unexpected remote assets: unexpected\.tgz/u, + ); + }); +} + +test('an applied-but-ambiguous upload is reconciled once without replay', async () => { + const uploadPlan = plan(); + const remote = new Map(); + let mutationCalls = 0; + const result = await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, remote, { + uploadAsset: ({ asset }) => { + mutationCalls += 1; + remote.set(asset.name, remoteAsset(asset, 82)); + throw new Error('response timed out after upload'); + }, + }), + ); + assert.equal(mutationCalls, 1); + assert.deepEqual(result, { recoveredUploads: 1, uploadedAssets: 1 }); +}); + +test('a failed upload is never replayed while its immutable asset remains absent', async () => { + const uploadPlan = plan(); + const remote = new Map(); + let mutationCalls = 0; + await assert.rejects( + async () => + await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, remote, { + uploadAsset: () => { + mutationCalls += 1; + throw new Error('connection refused before send'); + }, + }), + ), + /upload failed.*did not reconcile/isu, + ); + assert.equal(mutationCalls, 1); +}); + +test('size, digest, and extra-asset conflicts are terminal before mutation', async () => { + const uploadPlan = plan(); + const asset = uploadPlan.assets[0]; + const conflicts = [ + new Map([[asset.name, { ...remoteAsset(asset, 80), size: asset.size + 1 }]]), + new Map([[asset.name, remoteAsset(asset, 80, `sha256:${'9'.repeat(64)}`)]]), + new Map([['extra.tgz', remoteAsset({ ...asset, name: 'extra.tgz' }, 80)]]), + ]; + for (const remote of conflicts) { + let mutationCalls = 0; + await assert.rejects( + async () => + await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, remote, { + uploadAsset: () => { + mutationCalls += 1; + }, + }), + ), + /remote size|remote digest|unexpected remote assets/u, + ); + assert.equal(mutationCalls, 0); + } +}); + +test('an already-public release cannot receive a missing frozen asset', async () => { + const uploadPlan = plan(); + const remote = new Map(); + let mutationCalls = 0; + await assert.rejects( + async () => + await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, remote, { + readRelease: () => releaseFor(uploadPlan, remote, { draft: false }), + uploadAsset: () => { + mutationCalls += 1; + }, + }), + ), + /already public but is missing frozen assets/u, + ); + assert.equal(mutationCalls, 0); +}); + +test('missing releases and authentication failures issue no upload', async () => { + const uploadPlan = plan(); + for (const [expected, readRelease] of [ + [/does not exist/u, () => null], + [ + /HTTP 401/u, + () => { + throw Object.assign(new Error('HTTP 401 bad credentials'), { retryable: false }); + }, + ], + ]) { + let mutationCalls = 0; + await assert.rejects( + async () => + await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, new Map(), { + readRelease, + uploadAsset: () => { + mutationCalls += 1; + }, + }), + ), + expected, + ); + assert.equal(mutationCalls, 0); + } +}); + +test('a pending GitHub SHA-256 digest converges through bounded product snapshots', async () => { + const uploadPlan = plan(); + const asset = uploadPlan.assets[0]; + let reads = 0; + const result = await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, new Map(), { + readRelease: () => { + reads += 1; + const digest = reads === 1 ? null : `sha256:${asset.sha256}`; + return releaseFor(uploadPlan, new Map([[asset.name, remoteAsset(asset, 80, digest)]])); + }, + snapshotReadOptions: deterministicReads(2), + uploadAsset: () => assert.fail('a converged existing asset must not upload'), + }), + ); + assert.equal(reads, 2); + assert.deepEqual(result, { recoveredUploads: 0, uploadedAssets: 0 }); +}); + +test('GitHub open state and empty digest converge without losing immutable asset identity', async () => { + const uploadPlan = plan(); + const asset = uploadPlan.assets[0]; + let reads = 0; + const result = await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, new Map(), { + readRelease: () => { + reads += 1; + const remote = remoteAsset(asset, 80, reads === 2 ? '' : `sha256:${asset.sha256}`); + if (reads === 1) { + remote.digest = null; + remote.size = 0; + remote.state = 'open'; + } + return releaseFor(uploadPlan, new Map([[asset.name, remote]])); + }, + snapshotReadOptions: deterministicReads(3), + uploadAsset: () => assert.fail('a converging existing asset must not upload'), + }), + ); + assert.equal(reads, 3); + assert.deepEqual(result, { recoveredUploads: 0, uploadedAssets: 0 }); +}); + +test('a missing GitHub digest fails closed after the bounded snapshot budget', async () => { + const uploadPlan = plan(); + const asset = uploadPlan.assets[0]; + let reads = 0; + await assert.rejects( + async () => + await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, new Map(), { + readRelease: () => { + reads += 1; + return releaseFor(uploadPlan, new Map([[asset.name, remoteAsset(asset, 80, null)]])); + }, + snapshotReadOptions: deterministicReads(2), + }), + ), + /pending asset metadata/u, + ); + assert.equal(reads, 2); +}); + +test('release replacement during upload is terminal even when the asset bytes match', async () => { + const uploadPlan = plan(); + const remote = new Map(); + let releaseReads = 0; + let mutationCalls = 0; + await assert.rejects( + async () => + await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, remote, { + readRelease: () => { + releaseReads += 1; + return releaseFor(uploadPlan, remote, { id: releaseReads === 1 ? 73 : 99 }); + }, + uploadAsset: ({ asset }) => { + mutationCalls += 1; + remote.set(asset.name, remoteAsset(asset, 83)); + }, + }), + ), + /release id changed from 73 to 99/u, + ); + assert.equal(mutationCalls, 1); +}); + +test('asset replacement while GitHub digest metadata converges is terminal', async () => { + const uploadPlan = plan(); + const asset = uploadPlan.assets[0]; + let releaseReads = 0; + let mutationCalls = 0; + await assert.rejects( + async () => + await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, new Map(), { + readRelease: () => { + releaseReads += 1; + if (releaseReads === 1) return releaseFor(uploadPlan, new Map()); + const digest = releaseReads === 2 ? null : `sha256:${asset.sha256}`; + const id = releaseReads === 2 ? 80 : 81; + return releaseFor(uploadPlan, new Map([[asset.name, remoteAsset(asset, id, digest)]])); + }, + snapshotReadOptions: deterministicReads(2), + uploadAsset: () => { + mutationCalls += 1; + }, + }), + ), + /remote asset id changed from 80 to 81/u, + ); + assert.equal(mutationCalls, 1); +}); + +test('large future product inventories use the paginated asset endpoint', async () => { + const assets = Array.from({ length: MAX_SAFE_EMBEDDED_RELEASE_ASSETS + 1 }, (_, index) => + frozenAsset(`asset-${index}.tgz`, index + 1), + ); + const uploadPlan = plan(assets); + const remote = new Map(assets.map((asset, index) => [asset.name, remoteAsset(asset, index + 1)])); + let releaseReads = 0; + let paginatedReads = 0; + const result = await uploadFrozenReleaseAssets( + uploadPlan, + uploadDependencies(uploadPlan, remote, { + readAssets: () => { + paginatedReads += 1; + return new Map(remote); + }, + readRelease: () => { + releaseReads += 1; + return { ...releaseFor(uploadPlan, remote), assets: [] }; + }, + }), + ); + assert.equal(releaseReads, 1); + assert.equal(paginatedReads, 1); + assert.deepEqual(result, { recoveredUploads: 0, uploadedAssets: 0 }); +}); + +test('staged upload bytes are verified and temporary state is removed on failure', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-upload-stage-test-')); + const source = path.join(root, 'one.tgz'); + writeFileSync(source, 'exact bytes'); + const asset = { + file: source, + name: 'one.tgz', + sha256: createHash('sha256').update('exact bytes').digest('hex'), + size: Buffer.byteLength('exact bytes'), + }; + const stages = []; + try { + await assert.rejects( + async () => + await withStagedFrozenAsset( + asset, + () => { + throw new Error('simulated upload interruption'); + }, + { + mkdtemp: () => { + const directory = mkdtempSync(path.join(root, 'stage-')); + stages.push(directory); + return directory; + }, + }, + ), + /simulated upload interruption/u, + ); + assert.equal(stages.length, 1); + assert.equal(existsSync(stages[0]), false); + } finally { + rmSync(root, { force: true, recursive: true }); + } +}); diff --git a/tools/release/upload_github_release_assets.mjs b/tools/release/upload_github_release_assets.mjs deleted file mode 100644 index c738b5662..000000000 --- a/tools/release/upload_github_release_assets.mjs +++ /dev/null @@ -1,724 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from "node:crypto"; -import { - closeSync, - constants, - copyFileSync, - existsSync, - lstatSync, - mkdtempSync, - openSync, - readSync, - readFileSync, - rmSync, -} from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import process from "node:process"; - -import { - redactGitHubReadDetail, - RetryableReadError, - retryReadOperationSync, -} from "./github-read.mjs"; -import { - assertResumableReleaseMetadata, - createGitHubOperationBudget, - exactReleaseMetadata, - readReleaseAssetsSync, - readReleaseByIdSync, - readReleaseMapSync, - releaseNotesForVersion, - remainingGitHubReadOptions, - runGitHubMutationSync, -} from "./github-release-mutations.mjs"; -import { GITHUB_CONTENT_WRITE_INTERVAL_MS } from "./github-content-write-pacer.mjs"; -import { loadGraph } from "./release-graph.mjs"; -import { - DEFAULT_PUBLICATION_LOCK, - loadPublicationLock, - lockedProductArtifactPaths, -} from "./publication-lock.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const FULL_SHA = /^[0-9a-f]{40}$/u; -const GITHUB_ASSET_ROLES = new Set(["github-release-asset", "github-release-metadata"]); -const GITHUB_ASSET_STATES = new Set(["open", "uploaded"]); -// Retained for compatibility with policy/tests that document the old embedded -// optimization. Exact inventories now always use the dedicated paginated -// release-assets endpoint because the release object's embedded array has no -// separately documented completeness contract. -export const MAX_SAFE_EMBEDDED_RELEASE_ASSETS = 0; -export const DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS = 60_000; -// Two complete default three-minute GitHub read windows: one for the frozen -// pre-upload snapshot and one for final exact-set verification. Fast failed -// transports leave their separately reserved timeout available for ambiguity -// reconciliation. -export const GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS = 6 * 60_000; -export const MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS = 60 * 60_000; -const MIN_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS = 20 * 60_000; -const SHARED_UPLOAD_ABORT_CODE = "OLIPHAUNT_SHARED_UPLOAD_ABORT"; - -function error(message, options = {}) { - return new Error(`upload_github_release_assets.mjs: ${message}`, options); -} - -export function assertSharedUploadMutationAllowed(environment = process.env) { - const configured = environment.OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH?.trim() ?? ""; - if (configured === "") return; - if (configured.includes("\0")) throw error("shared upload abort path contains a NUL byte"); - const marker = path.resolve(configured); - const metadata = lstatSync(marker, { throwIfNoEntry: false }); - if (metadata === undefined) return; - if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size > 4 * 1024) { - throw error("shared upload abort marker must be a bounded regular non-symlink file"); - } - const cause = error("a peer product upload lane failed; refusing a new GitHub release asset mutation"); - cause.code = SHARED_UPLOAD_ABORT_CODE; - throw cause; -} - -function positiveSafeInteger(value, label, { allowZero = false } = {}) { - if ( - !Number.isSafeInteger(value) - || value < (allowZero ? 0 : 1) - ) { - throw error(`${label} must be ${allowZero ? "a non-negative" : "a positive"} safe integer`); - } - return value; -} - -/** - * Return a fail-closed per-product upload window derived from the frozen asset - * count. The bound reserves a complete transport timeout and one content-write - * pacing interval for every asset, plus a shared window for the exact pre/post - * snapshots and any ambiguity reconciliation reads. - * - * A product whose worst-case bounded upload cannot fit the one-hour operation - * ceiling must be repackaged into fewer aggregate assets instead of beginning - * a release that cannot complete deterministically. - */ -export function githubReleaseAssetUploadWindowMs( - assetCount, - { - contentWriteIntervalMs = GITHUB_CONTENT_WRITE_INTERVAL_MS, - snapshotReserveMs = GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, - uploadTimeoutMs = DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, - } = {}, -) { - positiveSafeInteger(assetCount, "GitHub release asset count", { allowZero: true }); - positiveSafeInteger(contentWriteIntervalMs, "GitHub content-write interval"); - positiveSafeInteger(snapshotReserveMs, "GitHub release asset snapshot reserve"); - positiveSafeInteger(uploadTimeoutMs, "GitHub release asset upload timeout"); - const perAssetMs = contentWriteIntervalMs + uploadTimeoutMs; - if (!Number.isSafeInteger(perAssetMs)) { - throw error("GitHub release asset per-upload budget exceeds the safe integer range"); - } - const requiredMs = (assetCount * perAssetMs) + snapshotReserveMs; - if (!Number.isSafeInteger(requiredMs)) { - throw error("GitHub release asset upload budget exceeds the safe integer range"); - } - const windowMs = Math.max(MIN_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS, requiredMs); - if (windowMs > MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS) { - throw error( - `${assetCount} frozen GitHub release assets require ${requiredMs}ms, exceeding the ` - + `${MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS}ms per-product ceiling; package the product into fewer aggregate assets`, - ); - } - return windowMs; -} - -function usageError() { - return error( - "usage: upload_github_release_assets.mjs [--tag TAG] [--repo OWNER/NAME] " - + "[--publication-lock FILE] [--asset PATH]...", - ); -} - -function valueArg(argv, index, name) { - const value = argv[index + 1]; - if (value === undefined || value.startsWith("--")) throw usageError(); - return value; -} - -function parseArgs(argv, environment) { - const args = { - assets: [], - product: undefined, - publicationLock: environment.OLIPHAUNT_PUBLICATION_LOCK ?? DEFAULT_PUBLICATION_LOCK, - repo: environment.GITHUB_REPOSITORY || "", - tag: undefined, - }; - let index = 0; - while (index < argv.length) { - const arg = argv[index]; - if (arg === "--tag") { - args.tag = valueArg(argv, index, arg); - index += 2; - } else if (arg === "--repo") { - args.repo = valueArg(argv, index, arg); - index += 2; - } else if (arg === "--publication-lock") { - args.publicationLock = valueArg(argv, index, arg); - index += 2; - } else if (arg === "--asset") { - args.assets.push(valueArg(argv, index, arg)); - index += 2; - } else if (arg.startsWith("--") || args.product !== undefined) { - throw usageError(); - } else { - args.product = arg; - index += 1; - } - } - if (!args.product) throw usageError(); - return args; -} - -function sha256FileSync(file) { - const digest = createHash("sha256"); - const descriptor = openSync(file, "r"); - const buffer = Buffer.allocUnsafe(1024 * 1024); - try { - for (;;) { - const length = readSync(descriptor, buffer, 0, buffer.length, null); - if (length === 0) break; - digest.update(buffer.subarray(0, length)); - } - } finally { - closeSync(descriptor); - } - return digest.digest("hex"); -} - -function assertSafeAssetName(name) { - if ( - typeof name !== "string" - || name.length === 0 - || path.basename(name) !== name - || /[\u0000-\u001f\u007f]/u.test(name) - || ["#", "*", "?", "[", "]", "\\"].some((character) => name.includes(character)) - ) { - throw error(`release asset has an unsafe or glob-ambiguous name: ${JSON.stringify(name)}`); - } -} - -function resolveAssetSync(asset) { - for (const candidate of [path.join(ROOT, asset), path.resolve(asset)]) { - try { - const stat = lstatSync(candidate); - if (stat.isFile() && !stat.isSymbolicLink()) return candidate; - } catch { - // Try the next exact path. - } - } - throw error(`release asset is not a regular non-symlink file: ${asset}`); -} - -function sameSet(left, right) { - return left.size === right.size && [...left].every((value) => right.has(value)); -} - -export function assertExactFrozenUploadSelection(frozen, requestedPaths, product) { - if (!Array.isArray(frozen) || !(requestedPaths instanceof Set)) { - throw new TypeError("frozen GitHub release assets and requested paths must be canonical collections"); - } - if (frozen.some(({ type }) => type !== "file")) { - throw error(`${product} frozen GitHub release asset set must contain only regular files`); - } - const frozenPaths = new Set(frozen.map(({ path: file }) => path.resolve(file))); - if (!sameSet(requestedPaths, frozenPaths)) { - throw error("requested GitHub release assets do not exactly match the frozen product asset set"); - } -} - -export function frozenUploadPlan({ assets, product, publicationLock, repo, tag }) { - if (!/^[^/\s]+\/[^/\s]+$/u.test(repo)) { - throw error("--repo or GITHUB_REPOSITORY must be OWNER/NAME"); - } - const lockFile = path.resolve(ROOT, publicationLock); - if (!existsSync(lockFile)) throw error(`frozen publication lock does not exist: ${lockFile}`); - const lock = loadPublicationLock(lockFile); - if (!FULL_SHA.test(lock.source.commit)) { - throw error("frozen publication lock source commit is not a full lowercase SHA"); - } - const lockedProduct = lock.products.find((row) => row.id === product); - if (lockedProduct === undefined) { - throw error(`frozen publication lock does not select ${product}`); - } - const graph = loadGraph("github-release-assets"); - const config = graph.products[product]; - if (config === undefined || config.version !== lockedProduct.version) { - throw error(`${product} release graph does not match frozen version ${lockedProduct.version}`); - } - const expectedTag = `${config.tag_prefix}${lockedProduct.version}`; - if (tag !== undefined && tag !== expectedTag) { - throw error(`requested tag ${tag} does not match frozen product tag ${expectedTag}`); - } - let body; - try { - body = releaseNotesForVersion( - readFileSync(path.resolve(ROOT, config.changelog_path), "utf8"), - lockedProduct.version, - ); - } catch (cause) { - throw error(`${product} frozen release notes are invalid: ${cause.message}`, { cause }); - } - const metadata = exactReleaseMetadata({ - body, - headRef: lock.source.commit, - product, - tag: expectedTag, - version: lockedProduct.version, - }); - const frozen = lockedProductArtifactPaths(lock, product) - .filter(({ artifact }) => GITHUB_ASSET_ROLES.has(artifact.role)); - const requestedPaths = new Set(assets.map(resolveAssetSync).map((file) => path.resolve(file))); - if (requestedPaths.size !== assets.length) { - throw error("requested GitHub release assets contain duplicate paths"); - } - assertExactFrozenUploadSelection(frozen, requestedPaths, product); - const names = new Set(); - const plannedAssets = frozen.map(({ artifact, path: file }) => { - assertSafeAssetName(artifact.name); - if (path.basename(file) !== artifact.name || names.has(artifact.name)) { - throw error(`${product} frozen GitHub release asset names are non-canonical or duplicated`); - } - names.add(artifact.name); - return { - file, - name: artifact.name, - sha256: artifact.sha256, - size: artifact.size, - }; - }); - return { - assets: plannedAssets, - headRef: lock.source.commit, - lockDigest: lock.lockDigest, - metadata, - product, - repo, - tag: expectedTag, - }; -} - -export function withStagedFrozenAssetSync(asset, operation, dependencies = {}) { - const makeTemporary = dependencies.mkdtemp ?? mkdtempSync; - const removeTemporary = dependencies.rm ?? rmSync; - const temporary = makeTemporary(path.join(tmpdir(), "oliphaunt-release-upload-")); - try { - const staged = path.join(temporary, asset.name); - copyFileSync(asset.file, staged, constants.COPYFILE_EXCL); - const stat = lstatSync(staged); - const digest = sha256FileSync(staged); - if (!stat.isFile() || stat.isSymbolicLink() || stat.size !== asset.size || digest !== asset.sha256) { - throw error(`${asset.name} staged bytes do not match the frozen publication lock`); - } - return operation(staged); - } finally { - removeTemporary(temporary, { force: true, recursive: true }); - } -} - -function exactReleaseState(release, plan, releaseId) { - if (release === null) { - return { detail: `${plan.tag} GitHub release is missing`, kind: "conflict" }; - } - try { - assertResumableReleaseMetadata(release, plan.metadata); - } catch (cause) { - return { detail: cause.message, kind: "conflict" }; - } - if (release.id !== releaseId) { - return { - detail: `${plan.tag} release id changed from ${releaseId} to ${release.id}`, - kind: "conflict", - }; - } - return null; -} - -function permanentError(message, options = {}) { - const cause = error(message, options); - cause.retryable = false; - return cause; -} - -function pendingError(message, options = {}) { - return new RetryableReadError(`upload_github_release_assets.mjs: ${message}`, options); -} - -function singleSnapshotReadOptions(budget, dependencies) { - return remainingGitHubReadOptions(budget, { - ...dependencies.singleReadOptions, - maxAttempts: 1, - }); -} - -function assertRemoteAssetInventory(value, plan) { - if (!(value instanceof Map)) { - throw permanentError(`${plan.product} GitHub release ${plan.tag} returned a non-canonical asset inventory`); - } - const ids = new Set(); - for (const [name, asset] of value) { - if ( - typeof name !== "string" - || asset === null - || Array.isArray(asset) - || typeof asset !== "object" - || asset.name !== name - || !Number.isSafeInteger(asset.id) - || asset.id <= 0 - || !Number.isSafeInteger(asset.size) - || asset.size < 0 - || !GITHUB_ASSET_STATES.has(asset.state) - || ( - asset.digest !== null - && asset.digest !== undefined - && asset.digest !== "" - && !/^sha256:[0-9a-f]{64}$/u.test(asset.digest) - ) - || ids.has(asset.id) - ) { - throw permanentError(`${plan.product} GitHub release ${plan.tag} returned malformed asset metadata`); - } - ids.add(asset.id); - } - return value; -} - -export function readExactReleaseAssetSnapshotSync( - { budget, expectedReleaseId, phase, plan }, - dependencies = {}, -) { - const context = { expectedReleaseId, phase, plan }; - const readOptions = () => singleSnapshotReadOptions(budget, dependencies); - const readReleaseMap = dependencies.readReleaseMap ?? (() => - readReleaseMapSync(plan.repo, readOptions())); - const readReleaseById = dependencies.readReleaseById ?? ((releaseId) => - readReleaseByIdSync(plan.repo, releaseId, readOptions())); - const readAssets = dependencies.readAssets ?? ((releaseId) => - readReleaseAssetsSync(plan.repo, releaseId, readOptions())); - - let release; - if (expectedReleaseId === undefined) { - const releasesByTag = readReleaseMap(context); - if (!(releasesByTag instanceof Map)) { - throw permanentError( - `${plan.product} GitHub release ${plan.tag} returned a non-canonical release inventory`, - ); - } - release = releasesByTag.get(plan.tag) ?? null; - } else { - release = readReleaseById(expectedReleaseId, context); - } - if (release === null) { - throw permanentError( - `${plan.product} GitHub release ${plan.tag} does not exist. ` - + "The protected workflow must stage the exact-SHA draft before asset publication.", - ); - } - const releaseId = expectedReleaseId ?? release.id; - const releaseConflict = exactReleaseState(release, plan, releaseId); - if (releaseConflict !== null) throw permanentError(releaseConflict.detail); - const assets = assertRemoteAssetInventory(readAssets(releaseId, context), plan); - return { assets, release, releaseId }; -} - -function inspectFrozenReleaseAssetSnapshot( - { allowMissing, knownAssetIds, plan, requiredNames, snapshot }, -) { - const expected = new Map(plan.assets.map((asset) => [asset.name, asset])); - if (expected.size !== plan.assets.length) { - throw permanentError(`${plan.product} frozen GitHub release assets contain duplicate names`); - } - for (const name of requiredNames) { - if (!expected.has(name)) { - throw permanentError(`${plan.product} snapshot required unknown frozen asset ${name}`); - } - } - const extras = [...snapshot.assets.keys()].filter((name) => !expected.has(name)).sort(); - if (extras.length > 0) { - throw permanentError( - `${plan.product} frozen GitHub release asset set excludes unexpected remote assets: ${extras.join(", ")}`, - ); - } - - const pendingMetadata = []; - for (const [name, remote] of snapshot.assets) { - const asset = expected.get(name); - const knownId = knownAssetIds.get(name); - if (knownId !== undefined && knownId !== remote.id) { - throw permanentError(`${name} remote asset id changed from ${knownId} to ${remote.id}`); - } - knownAssetIds.set(name, remote.id); - if (remote.state !== "uploaded") { - pendingMetadata.push(`${name} (state=${remote.state})`); - continue; - } - if (remote.size !== asset.size) { - throw permanentError(`${name} remote size ${remote.size} conflicts with frozen size ${asset.size}`); - } - if (remote.digest === null || remote.digest === undefined || remote.digest === "") { - pendingMetadata.push(`${name} (SHA-256 digest)`); - } else if (remote.digest !== `sha256:${asset.sha256}`) { - throw permanentError(`${name} remote digest conflicts with frozen bytes`); - } - } - - const missing = plan.assets.filter((asset) => !snapshot.assets.has(asset.name)); - if (!snapshot.release.draft && missing.length > 0) { - throw permanentError( - `${plan.tag} is already public but is missing frozen assets: ${missing.map(({ name }) => name).join(", ")}`, - ); - } - const requiredMissing = missing.filter(({ name }) => requiredNames.has(name)); - if (pendingMetadata.length > 0 || requiredMissing.length > 0 || (!allowMissing && missing.length > 0)) { - const details = []; - if (pendingMetadata.length > 0) details.push(`pending asset metadata: ${pendingMetadata.sort().join(", ")}`); - if (requiredMissing.length > 0) details.push(`required asset absent: ${requiredMissing.map(({ name }) => name).join(", ")}`); - if (!allowMissing && missing.length > 0) details.push(`frozen asset absent: ${missing.map(({ name }) => name).join(", ")}`); - throw pendingError(`${plan.tag} exact asset snapshot is not ready (${details.join("; ")})`); - } - return { ...snapshot, missing }; -} - -export function requireExactReleaseAssetSnapshotSync( - { - allowMissing, - budget, - expectedReleaseId, - knownAssetIds, - phase, - plan, - requiredNames = new Set(), - }, - dependencies = {}, -) { - const options = remainingGitHubReadOptions(budget, dependencies.snapshotReadOptions); - return retryReadOperationSync( - `${plan.product} ${phase} exact GitHub release asset snapshot`, - () => inspectFrozenReleaseAssetSnapshot({ - allowMissing, - knownAssetIds, - plan, - requiredNames, - snapshot: readExactReleaseAssetSnapshotSync( - { budget, expectedReleaseId, phase, plan }, - dependencies, - ), - }), - options, - ); -} - -export function exactReleaseAssetUploadArgs({ assetName, file, releaseId, repo }) { - assertSafeAssetName(assetName); - if (!Number.isSafeInteger(releaseId) || releaseId <= 0) { - throw error("release asset upload requires a positive release id"); - } - if (!/^[^/\s]+\/[^/\s]+$/u.test(repo)) { - throw error("release asset upload repository must be OWNER/NAME"); - } - if (typeof file !== "string" || file.length === 0 || path.basename(file) !== assetName) { - throw error("release asset upload file must retain its frozen asset name"); - } - return [ - "api", - `https://uploads.github.com/repos/${repo}/releases/${releaseId}/assets?name=${encodeURIComponent(assetName)}`, - "-X", - "POST", - "-H", - "Accept: application/vnd.github+json", - "-H", - "Content-Type: application/octet-stream", - "-H", - "X-GitHub-Api-Version: 2022-11-28", - "--input", - file, - ]; -} - -export function uploadFrozenReleaseAssetsSync(plan, dependencies = {}) { - const environment = dependencies.environment ?? process.env; - const uploadTimeoutMs = dependencies.uploadTimeoutMs - ?? DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS; - if ( - !Number.isSafeInteger(uploadTimeoutMs) - || uploadTimeoutMs <= 0 - || uploadTimeoutMs > 120_000 - ) { - throw error("GitHub release asset upload timeout must be between 1 and 120000 milliseconds"); - } - let budget = dependencies.budget; - if (budget === undefined) { - const requiredWindowMs = githubReleaseAssetUploadWindowMs(plan.assets.length, { uploadTimeoutMs }); - budget = createGitHubOperationBudget({ - defaultWindowMs: requiredWindowMs, - environment, - now: dependencies.now ?? Date.now, - }); - const availableMs = budget.deadlineMs - budget.startedAtMs; - const requiredMs = (plan.assets.length * (GITHUB_CONTENT_WRITE_INTERVAL_MS + uploadTimeoutMs)) - + GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS; - if (availableMs < requiredMs) { - throw error( - `${plan.product} exact ${plan.assets.length}-asset upload requires at least ${requiredMs}ms before mutation, ` - + `but the configured/hard GitHub deadline permits ${Math.max(0, availableMs)}ms`, - ); - } - } - const knownAssetIds = new Map(); - const initial = requireExactReleaseAssetSnapshotSync({ - allowMissing: true, - budget, - expectedReleaseId: undefined, - knownAssetIds, - phase: "pre-upload", - plan, - }, dependencies); - const releaseId = initial.releaseId; - if (initial.missing.length === 0) { - console.log( - `${plan.product} GitHub release ${plan.tag} already has its exact ${plan.assets.length}-asset frozen set ` - + `(publication lock ${plan.lockDigest}).`, - ); - return { recoveredUploads: 0, uploadedAssets: 0 }; - } - const stage = dependencies.withStagedAsset ?? withStagedFrozenAssetSync; - let recoveredUploads = 0; - let uploadedAssets = 0; - const completedMutationNames = new Set(); - const reconcileCompletedMutationsBeforeAbort = () => { - if (completedMutationNames.size === 0) return; - requireExactReleaseAssetSnapshotSync({ - allowMissing: true, - budget, - expectedReleaseId: releaseId, - knownAssetIds, - phase: "peer-abort-reconciliation", - plan, - requiredNames: completedMutationNames, - }, dependencies); - }; - for (const asset of initial.missing) { - try { - assertSharedUploadMutationAllowed(environment); - } catch (cause) { - if (cause?.code === SHARED_UPLOAD_ABORT_CODE) { - reconcileCompletedMutationsBeforeAbort(); - } - throw cause; - } - let mutationFailure; - stage(asset, (stagedFile) => { - const remainingMs = budget.deadlineMs - budget.now(); - if (remainingMs <= 0) { - throw error(`${plan.product} GitHub asset upload deadline reached before ${asset.name}`); - } - if (remainingMs < uploadTimeoutMs) { - throw error( - `${plan.product} GitHub asset upload requires its complete ${uploadTimeoutMs}ms timeout before ` - + `${asset.name}; ${Math.max(0, remainingMs)}ms remains`, - ); - } - const timeoutMs = uploadTimeoutMs; - try { - if (dependencies.uploadAsset === undefined) { - runGitHubMutationSync( - exactReleaseAssetUploadArgs({ - assetName: asset.name, - file: stagedFile, - releaseId, - repo: plan.repo, - }), - { - assertMutationAllowed: () => assertSharedUploadMutationAllowed(environment), - deadlineMs: budget.deadlineMs, - environment, - now: budget.now, - timeoutMs, - }, - ); - } else { - dependencies.uploadAsset({ - asset, - assertMutationAllowed: () => assertSharedUploadMutationAllowed(environment), - deadlineMs: budget.deadlineMs, - now: budget.now, - plan, - releaseId, - stagedFile, - timeoutMs, - }); - } - } catch (cause) { - mutationFailure = cause; - } - }); - uploadedAssets += 1; - if (mutationFailure === undefined) { - completedMutationNames.add(asset.name); - continue; - } - if (mutationFailure?.code === SHARED_UPLOAD_ABORT_CODE) { - reconcileCompletedMutationsBeforeAbort(); - throw mutationFailure; - } - - try { - requireExactReleaseAssetSnapshotSync({ - allowMissing: true, - budget, - expectedReleaseId: releaseId, - knownAssetIds, - phase: `ambiguous-${asset.name}`, - plan, - requiredNames: new Set([asset.name]), - }, dependencies); - } catch (reconciliationFailure) { - const mutationDetail = mutationFailure instanceof Error ? mutationFailure.message : String(mutationFailure); - const reconciliationDetail = reconciliationFailure instanceof Error - ? reconciliationFailure.message - : String(reconciliationFailure); - throw error( - `${asset.name} upload failed (${mutationDetail}) and exact immutable state did not reconcile: ` - + reconciliationDetail, - { cause: mutationFailure }, - ); - } - recoveredUploads += 1; - completedMutationNames.add(asset.name); - console.log(`${asset.name} became exact after an ambiguous upload response; the mutation was not replayed.`); - } - - requireExactReleaseAssetSnapshotSync({ - allowMissing: false, - budget, - expectedReleaseId: releaseId, - knownAssetIds, - phase: "post-upload", - plan, - }, dependencies); - console.log( - `${plan.product} GitHub release ${plan.tag} has all ${plan.assets.length} frozen assets ` - + `(publication lock ${plan.lockDigest}).`, - ); - return { recoveredUploads, uploadedAssets }; -} - -export function main(argv, { environment = process.env } = {}) { - const args = parseArgs([...argv], environment); - const plan = frozenUploadPlan(args); - uploadFrozenReleaseAssetsSync(plan, { environment }); -} - -if (import.meta.main) { - try { - main(Bun.argv.slice(2)); - } catch (cause) { - console.error(redactGitHubReadDetail(cause instanceof Error ? cause.message : String(cause))); - process.exit(1); - } -} diff --git a/tools/release/upload_github_release_assets.mts b/tools/release/upload_github_release_assets.mts new file mode 100644 index 000000000..0a587c201 --- /dev/null +++ b/tools/release/upload_github_release_assets.mts @@ -0,0 +1,731 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +import { + closeSync, + constants, + copyFileSync, + existsSync, + lstatSync, + mkdtempSync, + openSync, + readFileSync, + readSync, + rmSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; +import { loadProducts } from './release-graph.mts'; +import { GITHUB_CONTENT_WRITE_INTERVAL_MS } from './github-content-write-pacer.mts'; +import { RetryableReadError, redactGitHubReadDetail, retryReadOperation } from './github-read.mts'; +import { + assertResumableReleaseMetadata, + createGitHubOperationBudget, + exactReleaseMetadata, + readReleaseById as githubReleaseById, + readReleaseMap as githubReleaseMap, + readReleaseAssets, + releaseNotesForVersion, + remainingGitHubReadOptions, + requestGithubMutation, +} from './github-release-mutations.mts'; +import { + DEFAULT_PUBLICATION_LOCK, + loadPublicationLock, + lockedProductArtifactPaths, +} from './publication-lock.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); +const FULL_SHA = /^[0-9a-f]{40}$/u; +const GITHUB_ASSET_ROLES = new Set(['github-release-asset', 'github-release-metadata']); +const GITHUB_ASSET_STATES = new Set(['open', 'uploaded']); +// Retained for compatibility with policy/tests that document the old embedded +// optimization. Exact inventories now always use the dedicated paginated +// release-assets endpoint because the release object's embedded array has no +// separately documented completeness contract. +export const MAX_SAFE_EMBEDDED_RELEASE_ASSETS = 0; +export const DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS = 60_000; +// Two complete default three-minute GitHub read windows: one for the frozen +// pre-upload snapshot and one for final exact-set verification. Fast failed +// transports leave their separately reserved timeout available for ambiguity +// reconciliation. +export const GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS = 6 * 60_000; +export const MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS = 60 * 60_000; +const MIN_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS = 20 * 60_000; +const SHARED_UPLOAD_ABORT_CODE = 'OLIPHAUNT_SHARED_UPLOAD_ABORT'; + +function error(message, options = {}) { + return new Error(`upload_github_release_assets.mts: ${message}`, options); +} + +export function assertSharedUploadMutationAllowed(environment = process.env) { + const configured = environment.OLIPHAUNT_GITHUB_UPLOAD_ABORT_PATH?.trim() ?? ''; + if (configured === '') return; + if (configured.includes('\0')) throw error('shared upload abort path contains a NUL byte'); + const marker = path.resolve(configured); + const metadata = lstatSync(marker, { throwIfNoEntry: false }); + if (metadata === undefined) return; + if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size > 4 * 1024) { + throw error('shared upload abort marker must be a bounded regular non-symlink file'); + } + const cause = error( + 'a peer product upload lane failed; refusing a new GitHub release asset mutation', + ); + cause.code = SHARED_UPLOAD_ABORT_CODE; + throw cause; +} + +function positiveSafeInteger(value, label, { allowZero = false } = {}) { + if (!Number.isSafeInteger(value) || value < (allowZero ? 0 : 1)) { + throw error(`${label} must be ${allowZero ? 'a non-negative' : 'a positive'} safe integer`); + } + return value; +} + +/** + * Return a fail-closed per-product upload window derived from the frozen asset + * count. The bound reserves a complete transport timeout and one content-write + * pacing interval for every asset, plus a shared window for the exact pre/post + * snapshots and any ambiguity reconciliation reads. + * + * A product whose worst-case bounded upload cannot fit the one-hour operation + * ceiling must be repackaged into fewer aggregate assets instead of beginning + * a release that cannot complete deterministically. + */ +export function githubReleaseAssetUploadWindowMs( + assetCount, + { + contentWriteIntervalMs = GITHUB_CONTENT_WRITE_INTERVAL_MS, + snapshotReserveMs = GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS, + uploadTimeoutMs = DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS, + } = {}, +) { + positiveSafeInteger(assetCount, 'GitHub release asset count', { allowZero: true }); + positiveSafeInteger(contentWriteIntervalMs, 'GitHub content-write interval'); + positiveSafeInteger(snapshotReserveMs, 'GitHub release asset snapshot reserve'); + positiveSafeInteger(uploadTimeoutMs, 'GitHub release asset upload timeout'); + const perAssetMs = contentWriteIntervalMs + uploadTimeoutMs; + if (!Number.isSafeInteger(perAssetMs)) { + throw error('GitHub release asset per-upload budget exceeds the safe integer range'); + } + const requiredMs = assetCount * perAssetMs + snapshotReserveMs; + if (!Number.isSafeInteger(requiredMs)) { + throw error('GitHub release asset upload budget exceeds the safe integer range'); + } + const windowMs = Math.max(MIN_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS, requiredMs); + if (windowMs > MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS) { + throw error( + `${assetCount} frozen GitHub release assets require ${requiredMs}ms, exceeding the ` + + `${MAX_GITHUB_RELEASE_ASSET_UPLOAD_WINDOW_MS}ms per-product ceiling; package the product into fewer aggregate assets`, + ); + } + return windowMs; +} + +function usageError() { + return error( + 'usage: upload_github_release_assets.mts [--tag TAG] [--repo OWNER/NAME] ' + + '[--publication-lock FILE] [--asset PATH]...', + ); +} + +function valueArg(argv, index, name) { + const value = argv[index + 1]; + if (value === undefined || value.startsWith('--')) throw usageError(); + return value; +} + +function parseArgs(argv, environment) { + const args = { + assets: [], + product: undefined, + publicationLock: environment.OLIPHAUNT_PUBLICATION_LOCK ?? DEFAULT_PUBLICATION_LOCK, + repo: environment.GITHUB_REPOSITORY || '', + tag: undefined, + }; + let index = 0; + while (index < argv.length) { + const arg = argv[index]; + if (arg === '--tag') { + args.tag = valueArg(argv, index, arg); + index += 2; + } else if (arg === '--repo') { + args.repo = valueArg(argv, index, arg); + index += 2; + } else if (arg === '--publication-lock') { + args.publicationLock = valueArg(argv, index, arg); + index += 2; + } else if (arg === '--asset') { + args.assets.push(valueArg(argv, index, arg)); + index += 2; + } else if (arg.startsWith('--') || args.product !== undefined) { + throw usageError(); + } else { + args.product = arg; + index += 1; + } + } + if (!args.product) throw usageError(); + return args; +} + +function sha256FileSync(file) { + const digest = createHash('sha256'); + const descriptor = openSync(file, 'r'); + const buffer = Buffer.allocUnsafe(1024 * 1024); + try { + for (;;) { + const length = readSync(descriptor, buffer, 0, buffer.length, null); + if (length === 0) break; + digest.update(buffer.subarray(0, length)); + } + } finally { + closeSync(descriptor); + } + return digest.digest('hex'); +} + +function assertSafeAssetName(name) { + if ( + typeof name !== 'string' || + name.length === 0 || + path.basename(name) !== name || + /[\u0000-\u001f\u007f]/u.test(name) || + ['#', '*', '?', '[', ']', '\\'].some((character) => name.includes(character)) + ) { + throw error(`release asset has an unsafe or glob-ambiguous name: ${JSON.stringify(name)}`); + } +} + +function resolveAssetSync(asset) { + for (const candidate of [path.join(ROOT, asset), path.resolve(asset)]) { + try { + const stat = lstatSync(candidate); + if (stat.isFile() && !stat.isSymbolicLink()) return candidate; + } catch { + // Try the next exact path. + } + } + throw error(`release asset is not a regular non-symlink file: ${asset}`); +} + +function sameSet(left, right) { + return left.size === right.size && [...left].every((value) => right.has(value)); +} + +export function assertExactFrozenUploadSelection(frozen, requestedPaths, product) { + if (!Array.isArray(frozen) || !(requestedPaths instanceof Set)) { + throw new TypeError( + 'frozen GitHub release assets and requested paths must be canonical collections', + ); + } + if (frozen.some(({ type }) => type !== 'file')) { + throw error(`${product} frozen GitHub release asset set must contain only regular files`); + } + const frozenPaths = new Set(frozen.map(({ path: file }) => path.resolve(file))); + if (!sameSet(requestedPaths, frozenPaths)) { + throw error( + 'requested GitHub release assets do not exactly match the frozen product asset set', + ); + } +} + +export function frozenUploadPlan({ assets, product, publicationLock, repo, tag }) { + if (!/^[^/\s]+\/[^/\s]+$/u.test(repo)) { + throw error('--repo or GITHUB_REPOSITORY must be OWNER/NAME'); + } + const lockFile = path.resolve(ROOT, publicationLock); + if (!existsSync(lockFile)) throw error(`frozen publication lock does not exist: ${lockFile}`); + const lock = loadPublicationLock(lockFile); + if (!FULL_SHA.test(lock.source.commit)) { + throw error('frozen publication lock source commit is not a full lowercase SHA'); + } + const lockedProduct = lock.products.find((row) => row.id === product); + if (lockedProduct === undefined) { + throw error(`frozen publication lock does not select ${product}`); + } + const productMetadata = loadProducts('github-release-assets'); + const config = productMetadata[product]; + if (config === undefined || config.version !== lockedProduct.version) { + throw error(`${product} release graph does not match frozen version ${lockedProduct.version}`); + } + const expectedTag = `${config.tag_prefix}${lockedProduct.version}`; + if (tag !== undefined && tag !== expectedTag) { + throw error(`requested tag ${tag} does not match frozen product tag ${expectedTag}`); + } + let body; + try { + body = releaseNotesForVersion( + readFileSync(path.resolve(ROOT, config.changelog_path), 'utf8'), + lockedProduct.version, + ); + } catch (cause) { + throw error(`${product} frozen release notes are invalid: ${cause.message}`, { cause }); + } + const metadata = exactReleaseMetadata({ + body, + headRef: lock.source.commit, + product, + tag: expectedTag, + version: lockedProduct.version, + }); + const frozen = lockedProductArtifactPaths(lock, product).filter(({ artifact }) => + GITHUB_ASSET_ROLES.has(artifact.role), + ); + const requestedPaths = new Set(assets.map(resolveAssetSync).map((file) => path.resolve(file))); + if (requestedPaths.size !== assets.length) { + throw error('requested GitHub release assets contain duplicate paths'); + } + assertExactFrozenUploadSelection(frozen, requestedPaths, product); + const names = new Set(); + const plannedAssets = frozen.map(({ artifact, path: file }) => { + assertSafeAssetName(artifact.name); + if (path.basename(file) !== artifact.name || names.has(artifact.name)) { + throw error(`${product} frozen GitHub release asset names are non-canonical or duplicated`); + } + names.add(artifact.name); + return { + file, + name: artifact.name, + sha256: artifact.sha256, + size: artifact.size, + }; + }); + return { + assets: plannedAssets, + headRef: lock.source.commit, + lockDigest: lock.lockDigest, + metadata, + product, + repo, + tag: expectedTag, + }; +} + +export async function withStagedFrozenAsset(asset, operation, dependencies = {}) { + const makeTemporary = dependencies.mkdtemp ?? mkdtempSync; + const removeTemporary = dependencies.rm ?? rmSync; + const temporary = makeTemporary(path.join(tmpdir(), 'oliphaunt-release-upload-')); + try { + const staged = path.join(temporary, asset.name); + copyFileSync(asset.file, staged, constants.COPYFILE_EXCL); + const stat = lstatSync(staged); + const digest = sha256FileSync(staged); + if ( + !stat.isFile() || + stat.isSymbolicLink() || + stat.size !== asset.size || + digest !== asset.sha256 + ) { + throw error(`${asset.name} staged bytes do not match the frozen publication lock`); + } + return await operation(staged); + } finally { + removeTemporary(temporary, { force: true, recursive: true }); + } +} + +function exactReleaseState(release, plan, releaseId) { + if (release === null) { + return { detail: `${plan.tag} GitHub release is missing`, kind: 'conflict' }; + } + try { + assertResumableReleaseMetadata(release, plan.metadata); + } catch (cause) { + return { detail: cause.message, kind: 'conflict' }; + } + if (release.id !== releaseId) { + return { + detail: `${plan.tag} release id changed from ${releaseId} to ${release.id}`, + kind: 'conflict', + }; + } + return null; +} + +function permanentError(message, options = {}) { + const cause = error(message, options); + cause.retryable = false; + return cause; +} + +function pendingError(message, options = {}) { + return new RetryableReadError(`upload_github_release_assets.mts: ${message}`, options); +} + +function singleSnapshotReadOptions(budget, dependencies) { + return remainingGitHubReadOptions(budget, { + ...dependencies.singleReadOptions, + maxAttempts: 1, + }); +} + +function assertRemoteAssetInventory(value, plan) { + if (!(value instanceof Map)) { + throw permanentError( + `${plan.product} GitHub release ${plan.tag} returned a non-canonical asset inventory`, + ); + } + const ids = new Set(); + for (const [name, asset] of value) { + if ( + typeof name !== 'string' || + asset === null || + Array.isArray(asset) || + typeof asset !== 'object' || + asset.name !== name || + !Number.isSafeInteger(asset.id) || + asset.id <= 0 || + !Number.isSafeInteger(asset.size) || + asset.size < 0 || + !GITHUB_ASSET_STATES.has(asset.state) || + (asset.digest !== null && + asset.digest !== undefined && + asset.digest !== '' && + !/^sha256:[0-9a-f]{64}$/u.test(asset.digest)) || + ids.has(asset.id) + ) { + throw permanentError( + `${plan.product} GitHub release ${plan.tag} returned malformed asset metadata`, + ); + } + ids.add(asset.id); + } + return value; +} + +export async function readExactReleaseAssetSnapshot( + { budget, expectedReleaseId, phase, plan }, + dependencies = {}, +) { + const context = { expectedReleaseId, phase, plan }; + const readOptions = () => singleSnapshotReadOptions(budget, dependencies); + const readReleaseMap = + dependencies.readReleaseMap ?? (async () => await githubReleaseMap(plan.repo, readOptions())); + const readReleaseById = + dependencies.readReleaseById ?? + (async (releaseId) => await githubReleaseById(plan.repo, releaseId, readOptions())); + const readAssets = + dependencies.readAssets ?? + (async (releaseId) => await readReleaseAssets(plan.repo, releaseId, readOptions())); + + let release; + if (expectedReleaseId === undefined) { + const releasesByTag = await readReleaseMap(context); + if (!(releasesByTag instanceof Map)) { + throw permanentError( + `${plan.product} GitHub release ${plan.tag} returned a non-canonical release inventory`, + ); + } + release = releasesByTag.get(plan.tag) ?? null; + } else { + release = await readReleaseById(expectedReleaseId, context); + } + if (release === null) { + throw permanentError( + `${plan.product} GitHub release ${plan.tag} does not exist. ` + + 'The protected workflow must stage the exact-SHA draft before asset publication.', + ); + } + const releaseId = expectedReleaseId ?? release.id; + const releaseConflict = exactReleaseState(release, plan, releaseId); + if (releaseConflict !== null) throw permanentError(releaseConflict.detail); + const assets = assertRemoteAssetInventory(await readAssets(releaseId, context), plan); + return { assets, release, releaseId }; +} + +function inspectFrozenReleaseAssetSnapshot({ + allowMissing, + knownAssetIds, + plan, + requiredNames, + snapshot, +}) { + const expected = new Map(plan.assets.map((asset) => [asset.name, asset])); + if (expected.size !== plan.assets.length) { + throw permanentError(`${plan.product} frozen GitHub release assets contain duplicate names`); + } + for (const name of requiredNames) { + if (!expected.has(name)) { + throw permanentError(`${plan.product} snapshot required unknown frozen asset ${name}`); + } + } + const extras = [...snapshot.assets.keys()].filter((name) => !expected.has(name)).sort(); + if (extras.length > 0) { + throw permanentError( + `${plan.product} frozen GitHub release asset set excludes unexpected remote assets: ${extras.join(', ')}`, + ); + } + + const pendingMetadata = []; + for (const [name, remote] of snapshot.assets) { + const asset = expected.get(name); + const knownId = knownAssetIds.get(name); + if (knownId !== undefined && knownId !== remote.id) { + throw permanentError(`${name} remote asset id changed from ${knownId} to ${remote.id}`); + } + knownAssetIds.set(name, remote.id); + if (remote.state !== 'uploaded') { + pendingMetadata.push(`${name} (state=${remote.state})`); + continue; + } + if (remote.size !== asset.size) { + throw permanentError( + `${name} remote size ${remote.size} conflicts with frozen size ${asset.size}`, + ); + } + if (remote.digest === null || remote.digest === undefined || remote.digest === '') { + pendingMetadata.push(`${name} (SHA-256 digest)`); + } else if (remote.digest !== `sha256:${asset.sha256}`) { + throw permanentError(`${name} remote digest conflicts with frozen bytes`); + } + } + + const missing = plan.assets.filter((asset) => !snapshot.assets.has(asset.name)); + if (!snapshot.release.draft && missing.length > 0) { + throw permanentError( + `${plan.tag} is already public but is missing frozen assets: ${missing.map(({ name }) => name).join(', ')}`, + ); + } + const requiredMissing = missing.filter(({ name }) => requiredNames.has(name)); + if ( + pendingMetadata.length > 0 || + requiredMissing.length > 0 || + (!allowMissing && missing.length > 0) + ) { + const details = []; + if (pendingMetadata.length > 0) + details.push(`pending asset metadata: ${pendingMetadata.sort().join(', ')}`); + if (requiredMissing.length > 0) + details.push(`required asset absent: ${requiredMissing.map(({ name }) => name).join(', ')}`); + if (!allowMissing && missing.length > 0) + details.push(`frozen asset absent: ${missing.map(({ name }) => name).join(', ')}`); + throw pendingError(`${plan.tag} exact asset snapshot is not ready (${details.join('; ')})`); + } + return { ...snapshot, missing }; +} + +export async function requireExactReleaseAssetSnapshot( + { + allowMissing, + budget, + expectedReleaseId, + knownAssetIds, + phase, + plan, + requiredNames = new Set(), + }, + dependencies = {}, +) { + const options = remainingGitHubReadOptions(budget, dependencies.snapshotReadOptions); + return await retryReadOperation( + `${plan.product} ${phase} exact GitHub release asset snapshot`, + async () => + inspectFrozenReleaseAssetSnapshot({ + allowMissing, + knownAssetIds, + plan, + requiredNames, + snapshot: await readExactReleaseAssetSnapshot( + { budget, expectedReleaseId, phase, plan }, + dependencies, + ), + }), + options, + ); +} + +export async function uploadFrozenReleaseAssets(plan, dependencies = {}) { + const environment = dependencies.environment ?? process.env; + const uploadTimeoutMs = + dependencies.uploadTimeoutMs ?? DEFAULT_GITHUB_RELEASE_ASSET_UPLOAD_TIMEOUT_MS; + if (!Number.isSafeInteger(uploadTimeoutMs) || uploadTimeoutMs <= 0 || uploadTimeoutMs > 120_000) { + throw error('GitHub release asset upload timeout must be between 1 and 120000 milliseconds'); + } + let budget = dependencies.budget; + if (budget === undefined) { + const requiredWindowMs = githubReleaseAssetUploadWindowMs(plan.assets.length, { + uploadTimeoutMs, + }); + budget = createGitHubOperationBudget({ + defaultWindowMs: requiredWindowMs, + environment, + now: dependencies.now ?? Date.now, + }); + const availableMs = budget.deadlineMs - budget.startedAtMs; + const requiredMs = + plan.assets.length * (GITHUB_CONTENT_WRITE_INTERVAL_MS + uploadTimeoutMs) + + GITHUB_RELEASE_ASSET_UPLOAD_SNAPSHOT_RESERVE_MS; + if (availableMs < requiredMs) { + throw error( + `${plan.product} exact ${plan.assets.length}-asset upload requires at least ${requiredMs}ms before mutation, ` + + `but the configured/hard GitHub deadline permits ${Math.max(0, availableMs)}ms`, + ); + } + } + const knownAssetIds = new Map(); + const initial = await requireExactReleaseAssetSnapshot( + { + allowMissing: true, + budget, + expectedReleaseId: undefined, + knownAssetIds, + phase: 'pre-upload', + plan, + }, + dependencies, + ); + const releaseId = initial.releaseId; + if (initial.missing.length === 0) { + console.log( + `${plan.product} GitHub release ${plan.tag} already has its exact ${plan.assets.length}-asset frozen set ` + + `(publication lock ${plan.lockDigest}).`, + ); + return { recoveredUploads: 0, uploadedAssets: 0 }; + } + const stage = dependencies.withStagedAsset ?? withStagedFrozenAsset; + let recoveredUploads = 0; + let uploadedAssets = 0; + const completedMutationNames = new Set(); + const reconcileCompletedMutationsBeforeAbort = async () => { + if (completedMutationNames.size === 0) return; + await requireExactReleaseAssetSnapshot( + { + allowMissing: true, + budget, + expectedReleaseId: releaseId, + knownAssetIds, + phase: 'peer-abort-reconciliation', + plan, + requiredNames: completedMutationNames, + }, + dependencies, + ); + }; + for (const asset of initial.missing) { + try { + assertSharedUploadMutationAllowed(environment); + } catch (cause) { + if (cause?.code === SHARED_UPLOAD_ABORT_CODE) { + await reconcileCompletedMutationsBeforeAbort(); + } + throw cause; + } + let mutationFailure; + await stage(asset, async (stagedFile) => { + const remainingMs = budget.deadlineMs - budget.now(); + if (remainingMs <= 0) { + throw error(`${plan.product} GitHub asset upload deadline reached before ${asset.name}`); + } + if (remainingMs < uploadTimeoutMs) { + throw error( + `${plan.product} GitHub asset upload requires its complete ${uploadTimeoutMs}ms timeout before ` + + `${asset.name}; ${Math.max(0, remainingMs)}ms remains`, + ); + } + const timeoutMs = uploadTimeoutMs; + try { + if (dependencies.uploadAsset === undefined) { + await requestGithubMutation( + `https://uploads.github.com/repos/${plan.repo}/releases/${releaseId}/assets?name=${encodeURIComponent(asset.name)}`, + { + method: 'POST', + file: stagedFile, + assertMutationAllowed: () => assertSharedUploadMutationAllowed(environment), + deadlineMs: budget.deadlineMs, + environment, + now: budget.now, + timeoutMs, + }, + ); + } else { + await dependencies.uploadAsset({ + asset, + assertMutationAllowed: () => assertSharedUploadMutationAllowed(environment), + deadlineMs: budget.deadlineMs, + now: budget.now, + plan, + releaseId, + stagedFile, + timeoutMs, + }); + } + } catch (cause) { + mutationFailure = cause; + } + }); + uploadedAssets += 1; + if (mutationFailure === undefined) { + completedMutationNames.add(asset.name); + continue; + } + if (mutationFailure?.code === SHARED_UPLOAD_ABORT_CODE) { + await reconcileCompletedMutationsBeforeAbort(); + throw mutationFailure; + } + + try { + await requireExactReleaseAssetSnapshot( + { + allowMissing: true, + budget, + expectedReleaseId: releaseId, + knownAssetIds, + phase: `ambiguous-${asset.name}`, + plan, + requiredNames: new Set([asset.name]), + }, + dependencies, + ); + } catch (reconciliationFailure) { + const mutationDetail = + mutationFailure instanceof Error ? mutationFailure.message : String(mutationFailure); + const reconciliationDetail = + reconciliationFailure instanceof Error + ? reconciliationFailure.message + : String(reconciliationFailure); + throw error( + `${asset.name} upload failed (${mutationDetail}) and exact immutable state did not reconcile: ` + + reconciliationDetail, + { cause: mutationFailure }, + ); + } + recoveredUploads += 1; + completedMutationNames.add(asset.name); + console.log( + `${asset.name} became exact after an ambiguous upload response; the mutation was not replayed.`, + ); + } + + await requireExactReleaseAssetSnapshot( + { + allowMissing: false, + budget, + expectedReleaseId: releaseId, + knownAssetIds, + phase: 'post-upload', + plan, + }, + dependencies, + ); + console.log( + `${plan.product} GitHub release ${plan.tag} has all ${plan.assets.length} frozen assets ` + + `(publication lock ${plan.lockDigest}).`, + ); + return { recoveredUploads, uploadedAssets }; +} + +export async function main(argv, { environment = process.env } = {}) { + const args = parseArgs([...argv], environment); + const plan = frozenUploadPlan(args); + await uploadFrozenReleaseAssets(plan, { environment }); +} + +if (import.meta.main) { + try { + await main(Bun.argv.slice(2)); + } catch (cause) { + console.error(redactGitHubReadDetail(cause instanceof Error ? cause.message : String(cause))); + process.exit(1); + } +} diff --git a/tools/release/validate-ios-carrier-zips.mjs b/tools/release/validate-ios-carrier-zips.mjs deleted file mode 100644 index 581ce942d..000000000 --- a/tools/release/validate-ios-carrier-zips.mjs +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env node - -import fs from "node:fs/promises"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -import { - DEFAULT_PORTABLE_ARCHIVE_LIMITS, - readPortableArchiveEntries, -} from "../../src/shared/artifact-packaging/portable-archive.mjs"; - -const PREFIX = "validate-ios-carrier-zips.mjs"; -const XCFRAMEWORK_ROOT = /^[A-Za-z0-9][A-Za-z0-9._-]*[.]xcframework$/u; -// Match the shipped Apple carrier envelope. The shared verifier processes one -// expanded ZIP member at a time, so the logical aggregate bound does not become -// a same-sized in-memory allocation. -const IOS_ZIP_LIMITS = Object.freeze({ - format: "zip", - maxArchiveBytes: 512 * 1024 * 1024, - maxEntries: DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxEntries, - maxEntryBytes: 1024 * 1024 * 1024, - maxExpandedBytes: 4 * 1024 * 1024 * 1024, -}); - -function fail(message) { - throw new Error(`${PREFIX}: ${message}`); -} - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -async function regularDirectory(directory, label) { - let stat; - try { - stat = await fs.lstat(directory); - } catch (error) { - if (error?.code === "ENOENT") fail(`${label} does not exist: ${directory}`); - throw error; - } - if (!stat.isDirectory() || stat.isSymbolicLink()) { - fail(`${label} must be a real directory: ${directory}`); - } -} - -async function zipFiles(root) { - const files = []; - const pending = [root]; - while (pending.length > 0) { - const directory = pending.pop(); - const entries = await fs.readdir(directory, { withFileTypes: true }); - entries.sort((left, right) => compareText(left.name, right.name)); - for (const entry of entries) { - const file = path.join(directory, entry.name); - if (entry.isSymbolicLink()) { - fail(`carrier root contains a symbolic link: ${path.relative(root, file)}`); - } - if (entry.isDirectory()) { - pending.push(file); - } else if (entry.isFile()) { - if (entry.name.endsWith(".zip")) files.push(file); - else if (entry.name.toLowerCase().endsWith(".zip")) { - fail(`ZIP carrier names must use the canonical lowercase suffix: ${path.relative(root, file)}`); - } - } else { - fail(`carrier root contains an unsupported filesystem entry: ${path.relative(root, file)}`); - } - } - } - files.sort((left, right) => compareText(path.relative(root, left), path.relative(root, right))); - if (files.length === 0) fail(`found no ZIP carriers under ${root}`); - return files; -} - -function validateCarrierEntries(entries, archive) { - const roots = new Set([...entries.keys()].map((name) => name.split("/", 1)[0])); - if (roots.size !== 1) { - fail(`${archive} must contain exactly one top-level XCFramework root; found ${[...roots].sort(compareText).join(",")}`); - } - const [root] = roots; - if (!XCFRAMEWORK_ROOT.test(root) || root === "." || root === "..") { - fail(`${archive} has unsafe or non-XCFramework top-level root ${JSON.stringify(root)}`); - } - if (entries.get(root)?.isDirectory !== true) { - fail(`${archive} does not materialize ${root} as a directory`); - } - if (entries.get(`${root}/Info.plist`)?.isFile !== true) { - fail(`${archive} XCFramework root lacks a regular Info.plist`); - } - return root; -} - -export async function validateIosCarrierZipRoot(root) { - const carrierRoot = path.resolve(root); - await regularDirectory(carrierRoot, "carrier root"); - const archives = await zipFiles(carrierRoot); - const validated = []; - for (const archive of archives) { - const entries = readPortableArchiveEntries(archive, IOS_ZIP_LIMITS); - validated.push({ - archive, - framework: validateCarrierEntries(entries, archive), - }); - } - return validated; -} - -function parseArgs(argv) { - if (argv.includes("--help") || argv.includes("-h")) { - console.log("usage: validate-ios-carrier-zips.mjs --root DIRECTORY"); - return null; - } - if (argv.length !== 2 || argv[0] !== "--root" || argv[1].length === 0) { - fail("usage: validate-ios-carrier-zips.mjs --root DIRECTORY"); - } - return { root: argv[1] }; -} - -async function main() { - const args = parseArgs(process.argv.slice(2)); - if (args === null) return; - const rows = await validateIosCarrierZipRoot(args.root); - console.log(`${PREFIX}: validated ${rows.length} iOS XCFramework ZIP carrier(s) under ${path.resolve(args.root)}`); -} - -if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { - main().catch((error) => { - console.error(error instanceof Error ? error.stack : String(error)); - process.exit(1); - }); -} diff --git a/tools/release/validate-ios-carrier-zips.test.mjs b/tools/release/validate-ios-carrier-zips.test.mjs deleted file mode 100644 index 1518ee3b6..000000000 --- a/tools/release/validate-ios-carrier-zips.test.mjs +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env node - -import assert from "node:assert/strict"; -import { mkdtempSync, mkdirSync, readdirSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import test from "node:test"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); -const TOOL = path.join(ROOT, "tools/release/validate-ios-carrier-zips.mjs"); -const ARCHIVER = path.join(ROOT, "src/shared/artifact-packaging/archive-directory.mjs"); - -function run(command, args, { expectFailure = false, ...options } = {}) { - const result = spawnSync(command, args, { - cwd: ROOT, - encoding: "utf8", - ...options, - }); - if (expectFailure) { - assert.notEqual(result.status, 0, `${command} unexpectedly succeeded:\n${result.stdout}`); - } else { - assert.equal(result.status, 0, `${command} failed:\n${result.stderr || result.stdout}`); - } - return result; -} - -function makeCarrier(root, relativeArchive, frameworkName) { - const framework = path.join(root, "source", relativeArchive.replaceAll("/", "-"), frameworkName); - mkdirSync(path.join(framework, "ios-arm64", "libFixture.framework"), { recursive: true }); - writeFileSync(path.join(framework, "Info.plist"), "\n"); - writeFileSync( - path.join(framework, "ios-arm64", "libFixture.framework", "libFixture"), - "fixture-binary\n", - ); - const archive = path.join(root, "carriers", relativeArchive); - mkdirSync(path.dirname(archive), { recursive: true }); - run("bash", ["tools/dev/bun.sh", ARCHIVER, "--keep-parent", framework, archive]); - return archive; -} - -function fixture() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-ios-carrier-gate-test-")); - const temp = path.join(root, "tmp"); - mkdirSync(temp, { recursive: true }); - return { - root, - temp, - env: { ...process.env, TMPDIR: temp }, - }; -} - -test("validates every recursively produced XCFramework ZIP under Node without archive subprocesses", () => { - const { env, root, temp } = fixture(); - try { - makeCarrier(root, "nested/base.zip", "liboliphaunt.xcframework"); - makeCarrier(root, "extensions/vector.zip", "liboliphaunt_extension_vector.xcframework"); - const result = run(process.execPath, [TOOL, "--root", path.join(root, "carriers")], { env }); - assert.match(result.stdout, /validated 2 iOS XCFramework ZIP carrier\(s\)/u); - assert.deepEqual(readdirSync(temp), [], "isolated extraction root must be removed after success"); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("fails closed when a producer emits no ZIP carrier", () => { - const { env, root, temp } = fixture(); - try { - const carriers = path.join(root, "carriers"); - mkdirSync(carriers, { recursive: true }); - const result = run(process.execPath, [TOOL, "--root", carriers], { env, expectFailure: true }); - assert.match(result.stderr, /found no ZIP carriers/u); - assert.deepEqual(readdirSync(temp), []); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("fails the complete producer set on a structurally valid non-XCFramework ZIP without temp state", () => { - const { env, root, temp } = fixture(); - try { - makeCarrier(root, "a-valid.zip", "liboliphaunt.xcframework"); - makeCarrier(root, "z-invalid.zip", "not-a-framework"); - const result = run(process.execPath, [TOOL, "--root", path.join(root, "carriers")], { - env, - expectFailure: true, - }); - assert.match(result.stderr, /z-invalid[.]zip has unsafe or non-XCFramework top-level root/u); - assert.deepEqual(readdirSync(temp), [], "isolated extraction root must be removed after failure"); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); - -test("rejects an ambiguous producer tree instead of following carrier-root symlinks", () => { - const { env, root, temp } = fixture(); - try { - makeCarrier(root, "valid.zip", "liboliphaunt.xcframework"); - const outside = path.join(root, "outside.zip"); - writeFileSync(outside, "not a carrier\n"); - const link = path.join(root, "carriers", "linked.zip"); - const result = spawnSync("ln", ["-s", outside, link], { encoding: "utf8" }); - assert.equal(result.status, 0, result.stderr); - const validation = run(process.execPath, [TOOL, "--root", path.join(root, "carriers")], { - env, - expectFailure: true, - }); - assert.match(validation.stderr, /carrier root contains a symbolic link: linked[.]zip/u); - assert.deepEqual(readdirSync(temp), []); - } finally { - rmSync(root, { force: true, recursive: true }); - } -}); diff --git a/tools/release/validate-release-workflow-inputs.test.mts b/tools/release/validate-release-workflow-inputs.test.mts new file mode 100644 index 000000000..f53b93859 --- /dev/null +++ b/tools/release/validate-release-workflow-inputs.test.mts @@ -0,0 +1,18 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import test from 'node:test'; + +const ROOT = path.resolve(import.meta.dir, '../..'); +test('both npm publication jobs can generate required provenance', () => { + const workflow = Bun.YAML.parse( + readFileSync(path.join(ROOT, '.github/workflows/release.yml'), 'utf8'), + ); + for (const job of ['publish', 'publish-bootstrap']) { + assert.equal( + workflow.jobs[job].permissions['id-token'], + 'write', + `${job} requires OIDC for npm --provenance even with token authentication`, + ); + } +}); diff --git a/tools/release/validate-release-workflow-inputs.test.sh b/tools/release/validate-release-workflow-inputs.test.sh new file mode 100644 index 000000000..4f55fbee3 --- /dev/null +++ b/tools/release/validate-release-workflow-inputs.test.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/validate-release-workflow-inputs.test.mts +output="$(mktemp)" +trap 'rm -f "$output"' EXIT +sha=84d90b9853530ab72e48a1aa6fb616aaed7a0dc6 +validator="${OLIPHAUNT_TEST_BASH:-bash}" +validate() { + env -i PATH="$PATH" HOME="$HOME" GITHUB_SHA="${4:-$sha}" GITHUB_REF="${5:-refs/heads/main}" \ + RELEASE_OPERATION="$1" RELEASE_COMMIT="${2:-}" RELEASE_APPROVAL_RUN_ID="${3:-}" \ + "$validator" .github/scripts/validate-release-workflow-inputs.sh > "$output" 2>&1 +} +reject() { + local message="$1"; shift + if validate "$@"; then echo 'Release inputs unexpectedly accepted' >&2; exit 1; fi + rg -q -F "$message" "$output" +} +validate prepare-release-pr +validate publish +validate prepare-release-pr "$sha" +validate prepare-release-pr "$(printf '%s' "$sha" | tr '[:lower:]' '[:upper:]')" +reject 'release_commit must be a full 40-character commit SHA' prepare-release-pr 84d90b9 +reject 'release_commit must equal the exact workflow SHA' publish 1111111111111111111111111111111111111111 +validate publish 1111111111111111111111111111111111111111 123 +reject 'release operations must execute from refs/heads/main' publish '' 33989155433 "$sha" "refs/tags/oliphaunt-release-transport/$sha" +for approval in 0 latest 12.5; do + reject 'approval_run_id is valid only' publish '' "$approval" +done +reject 'approval_run_id is valid only' prepare-release-pr '' 33989155433 +reject 'Unsupported release operation' delete-everything +reject 'GITHUB_SHA must be a full 40-character commit SHA' publish '' '' 84d90b9 +echo 'Release inputs: exact main identity and bounded recovery assertions passed' diff --git a/tools/release/verify-extension-release-identity.test.mjs b/tools/release/verify-extension-release-identity.test.mjs deleted file mode 100644 index e580b3dc4..000000000 --- a/tools/release/verify-extension-release-identity.test.mjs +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env bun -import { readFileSync } from "node:fs"; -import path from "node:path"; -import { describe, expect, test } from "bun:test"; - -import { - extensionMetadata, - extensionReleaseProduct, - extensionSourceIdentity, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { assertCanonicalExtensionReleaseIdentity } from "./verify_github_release_attestations.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const generated = JSON.parse(readFileSync(path.join(ROOT, "src/extensions/generated/sdk/extensions.json"), "utf8")); -const staticLines = readFileSync(path.join(ROOT, "src/extensions/generated/mobile/static-extensions.tsv"), "utf8") - .split(/\r?\n/u) - .filter((line) => line.length > 0 && !line.startsWith("#")); -const staticHeader = staticLines.shift().split("\t"); -const staticRows = new Map(staticLines.map((line) => { - const cells = line.split("\t"); - const row = Object.fromEntries(staticHeader.map((key, index) => [key, cells[index] ?? ""])); - return [row["sql-name"], row]; -})); - -function member(product, sqlName) { - const row = generated.extensions.find((candidate) => candidate["sql-name"] === sqlName); - const nativeModuleStem = row["native-module-stem"]; - const prefix = nativeModuleStem === null - ? null - : `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`; - return { - sqlName, - createsExtension: row["creates-extension"] !== false, - dependencies: [...row["selected-extension-dependencies"]].sort(), - dataFiles: [...row["runtime-share-data-files"]].sort(), - extensionSqlFileNames: [...row["extension-sql-file-names"]].sort(), - extensionSqlFilePrefixes: [...row["extension-sql-file-prefixes"]].sort(), - nativeModuleStem, - iosNativeDependencies: nativeModuleStem === null - ? [] - : (staticRows.get(sqlName)?.["ios-static-dependencies"] ?? "").split(",").filter(Boolean).sort(), - iosRegistration: nativeModuleStem === null ? null : { - schema: "oliphaunt-ios-extension-registration-v1", - sqlName, - nativeModuleStem, - magicSymbol: `${prefix}_Pg_magic_func`, - initSymbol: null, - symbols: [], - }, - sharedPreloadLibraries: [...row["shared-preload-libraries"]].sort(), - assets: [], - }; -} - -function manifest(product, version = "1.2.3") { - const metadata = extensionMetadata(product, "verify-extension-release-identity.test"); - const family = metadata.versioning === "runtime-bound" ? "native" : "combined"; - const releaseProduct = family === "combined" - ? product - : extensionReleaseProduct(product, family, "verify-extension-release-identity.test"); - const members = extensionSqlNames(product, "verify-extension-release-identity.test") - .map((sqlName) => member(product, sqlName)); - const root = { - product, - ...(metadata.versioning === "runtime-bound" ? { - releaseProduct, - family, - } : {}), - version, - extensionClass: metadata.class, - versioning: metadata.versioning, - sourceIdentity: extensionSourceIdentity(product, "verify-extension-release-identity.test"), - compatibility: metadata.compatibility, - }; - return members.length === 1 - ? { schema: "oliphaunt-extension-release-manifest-v1", ...root, ...members[0] } - : { schema: "oliphaunt-extension-release-manifest-v2", ...root, extensions: members, assets: [] }; -} - -describe("canonical extension release identity", () => { - for (const product of ["oliphaunt-extension-pgtap", "oliphaunt-extension-contrib-pg18"]) { - test(`${product} rejects forged root compatibility`, () => { - const value = manifest(product); - expect(() => assertCanonicalExtensionReleaseIdentity(product, value.version, value)).not.toThrow(); - value.compatibility.wasixRuntimeVersion = "9.9.9"; - expect(() => assertCanonicalExtensionReleaseIdentity(product, value.version, value)).toThrow(/compatibility differs/u); - }); - } - - test("rejects forged source, versioning, and semantic member metadata", () => { - const product = "oliphaunt-extension-contrib-pg18"; - const value = manifest(product); - value.sourceIdentity.sha256 = "0".repeat(64); - expect(() => assertCanonicalExtensionReleaseIdentity(product, value.version, value)).toThrow(/sourceIdentity differs/u); - - const forgedVersioning = manifest(product); - forgedVersioning.versioning = "independent"; - expect(() => assertCanonicalExtensionReleaseIdentity(product, forgedVersioning.version, forgedVersioning)).toThrow(/versioning differs/u); - - const forgedInventory = manifest(product); - forgedInventory.extensions[0].dataFiles = [...forgedInventory.extensions[0].dataFiles, "undeclared/foreign.sql"].sort(); - expect(() => assertCanonicalExtensionReleaseIdentity(product, forgedInventory.version, forgedInventory)).toThrow(/dataFiles differs/u); - - const unsortedInventory = manifest("oliphaunt-extension-postgis"); - unsortedInventory.extensionSqlFilePrefixes.reverse(); - expect(() => assertCanonicalExtensionReleaseIdentity( - "oliphaunt-extension-postgis", - unsortedInventory.version, - unsortedInventory, - )).toThrow(/extensionSqlFilePrefixes differs/u); - }); -}); diff --git a/tools/release/verify-extension-release-identity.test.mts b/tools/release/verify-extension-release-identity.test.mts new file mode 100644 index 000000000..e6d80ca7b --- /dev/null +++ b/tools/release/verify-extension-release-identity.test.mts @@ -0,0 +1,152 @@ +#!/usr/bin/env bun +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { describe, expect, test } from 'bun:test'; + +import { + extensionMetadata, + extensionReleaseProduct, + extensionSourceIdentity, + extensionSqlNames, +} from './release-artifact-targets.mts'; +import { assertCanonicalExtensionReleaseIdentity } from './verify_github_release_attestations.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); +const generated = JSON.parse( + readFileSync(path.join(ROOT, 'src/extensions/generated/sdk/extensions.json'), 'utf8'), +); +const staticLines = readFileSync( + path.join(ROOT, 'src/extensions/generated/mobile/static-extensions.tsv'), + 'utf8', +) + .split(/\r?\n/u) + .filter((line) => line.length > 0 && !line.startsWith('#')); +const staticHeader = staticLines.shift().split('\t'); +const staticRows = new Map( + staticLines.map((line) => { + const cells = line.split('\t'); + const row = Object.fromEntries(staticHeader.map((key, index) => [key, cells[index] ?? ''])); + return [row['sql-name'], row]; + }), +); + +function member(product, sqlName) { + const row = generated.extensions.find((candidate) => candidate['sql-name'] === sqlName); + const nativeModuleStem = row['native-module-stem']; + const prefix = + nativeModuleStem === null + ? null + : `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`; + return { + sqlName, + createsExtension: row['creates-extension'] !== false, + dependencies: [...row['selected-extension-dependencies']].sort(), + dataFiles: [...row['runtime-share-data-files']].sort(), + extensionSqlFileNames: [...row['extension-sql-file-names']].sort(), + extensionSqlFilePrefixes: [...row['extension-sql-file-prefixes']].sort(), + nativeModuleStem, + iosNativeDependencies: + nativeModuleStem === null + ? [] + : (staticRows.get(sqlName)?.['ios-static-dependencies'] ?? '') + .split(',') + .filter(Boolean) + .sort(), + iosRegistration: + nativeModuleStem === null + ? null + : { + schema: 'oliphaunt-ios-extension-registration-v1', + sqlName, + nativeModuleStem, + magicSymbol: `${prefix}_Pg_magic_func`, + initSymbol: null, + symbols: [], + }, + sharedPreloadLibraries: [...row['shared-preload-libraries']].sort(), + assets: [], + }; +} + +function manifest(product, version = '1.2.3') { + const metadata = extensionMetadata(product, 'verify-extension-release-identity.test'); + const family = metadata.versioning === 'runtime-bound' ? 'native' : 'combined'; + const releaseProduct = + family === 'combined' + ? product + : extensionReleaseProduct(product, family, 'verify-extension-release-identity.test'); + const members = extensionSqlNames(product, 'verify-extension-release-identity.test').map( + (sqlName) => member(product, sqlName), + ); + const root = { + product, + ...(metadata.versioning === 'runtime-bound' + ? { + releaseProduct, + family, + } + : {}), + version, + extensionClass: metadata.class, + versioning: metadata.versioning, + sourceIdentity: extensionSourceIdentity(product, 'verify-extension-release-identity.test'), + compatibility: metadata.compatibility, + }; + return members.length === 1 + ? { schema: 'oliphaunt-extension-release-manifest-v1', ...root, ...members[0] } + : { + schema: 'oliphaunt-extension-release-manifest-v2', + ...root, + extensions: members, + assets: [], + }; +} + +describe('canonical extension release identity', () => { + for (const product of ['oliphaunt-extension-pgtap', 'oliphaunt-extension-contrib-pg18']) { + test(`${product} rejects forged root compatibility`, () => { + const value = manifest(product); + expect(() => + assertCanonicalExtensionReleaseIdentity(product, value.version, value), + ).not.toThrow(); + value.compatibility.wasixRuntimeVersion = '9.9.9'; + expect(() => assertCanonicalExtensionReleaseIdentity(product, value.version, value)).toThrow( + /compatibility differs/u, + ); + }); + } + + test('rejects forged source, versioning, and semantic member metadata', () => { + const product = 'oliphaunt-extension-contrib-pg18'; + const value = manifest(product); + value.sourceIdentity.sha256 = '0'.repeat(64); + expect(() => assertCanonicalExtensionReleaseIdentity(product, value.version, value)).toThrow( + /sourceIdentity differs/u, + ); + + const forgedVersioning = manifest(product); + forgedVersioning.versioning = 'independent'; + expect(() => + assertCanonicalExtensionReleaseIdentity(product, forgedVersioning.version, forgedVersioning), + ).toThrow(/versioning differs/u); + + const forgedInventory = manifest(product); + forgedInventory.extensions[0].dataFiles = [ + ...forgedInventory.extensions[0].dataFiles, + 'undeclared/foreign.sql', + ].sort(); + expect(() => + assertCanonicalExtensionReleaseIdentity(product, forgedInventory.version, forgedInventory), + ).toThrow(/dataFiles differs/u); + + const unsortedInventory = manifest('oliphaunt-extension-postgis'); + unsortedInventory.extensionSqlFilePrefixes.reverse(); + expect(() => + assertCanonicalExtensionReleaseIdentity( + 'oliphaunt-extension-postgis', + unsortedInventory.version, + unsortedInventory, + ), + ).toThrow(/extensionSqlFilePrefixes differs/u); + }); +}); diff --git a/tools/release/verify-github-oidc-identity.test.mjs b/tools/release/verify-github-oidc-identity.test.mjs deleted file mode 100644 index 736b3c79b..000000000 --- a/tools/release/verify-github-oidc-identity.test.mjs +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - decodeJwtPayload, - expectedOidcIdentity, - oidcRequestUrl, - readBoundedOidcResponse, - verifyGithubOidcIdentity, - verifyOidcClaims, -} from "../../.github/scripts/verify-github-oidc-identity.mjs"; - -const SHA = "0123456789abcdef0123456789abcdef01234567"; - -function environment(operation = "publish") { - return { - ACTIONS_ID_TOKEN_REQUEST_TOKEN: "request-token", - ACTIONS_ID_TOKEN_REQUEST_URL: "https://token.actions.githubusercontent.com/example?api-version=2.0", - CANONICAL_RELEASE_REPOSITORY: "f0rr0/oliphaunt", - GITHUB_EVENT_NAME: "workflow_dispatch", - GITHUB_REF: "refs/heads/main", - GITHUB_SHA: SHA, - RELEASE_OPERATION: operation, - }; -} - -function jwt(payload) { - return [ - Buffer.from(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString("base64url"), - Buffer.from(JSON.stringify(payload)).toString("base64url"), - "signature", - ].join("."); -} - -test("models the direct release workflow identity", () => { - const publish = expectedOidcIdentity(environment("publish")); - assert.equal( - publish.workflow_ref, - `f0rr0/oliphaunt/.github/workflows/release.yml@refs/heads/main`, - ); - assert.equal(Object.hasOwn(publish, "job_workflow_ref"), false); - assert.equal(Object.hasOwn(publish, "job_workflow_sha"), false); - assert.equal(publish.environment, "release-publish"); -}); - -test("requires the exact direct workflow, environment, SHA, and hosted runner claims", () => { - const expected = expectedOidcIdentity(environment()); - assert.doesNotThrow(() => verifyOidcClaims({ ...expected }, expected)); - - for (const [claim, value] of [ - ["workflow_ref", `f0rr0/oliphaunt/.github/workflows/other.yml@refs/heads/main`], - ["environment", "release-bootstrap"], - ["sha", "f".repeat(40)], - ["workflow_sha", "f".repeat(40)], - ["runner_environment", "self-hosted"], - ]) { - assert.throws( - () => verifyOidcClaims({ ...expected, [claim]: value }, expected), - new RegExp(`claim ${claim} mismatch`, "u"), - ); - } -}); - -test("accepts an exact optional current-job workflow ref with or without its SHA", () => { - const expected = expectedOidcIdentity(environment()); - for (const aliases of [ - {}, - { job_workflow_ref: expected.workflow_ref }, - { - job_workflow_ref: expected.workflow_ref, - job_workflow_sha: expected.workflow_sha, - }, - ]) { - assert.doesNotThrow(() => verifyOidcClaims({ ...expected, ...aliases }, expected)); - } -}); - -test("rejects a current-job workflow SHA without the file-identifying ref", () => { - const expected = expectedOidcIdentity(environment()); - assert.throws( - () => verifyOidcClaims({ - ...expected, - job_workflow_sha: expected.workflow_sha, - }, expected), - /claim job_workflow_sha requires claim job_workflow_ref/u, - ); -}); - -test("rejects substituted or malformed current-job workflow aliases", () => { - const expected = expectedOidcIdentity(environment()); - for (const [claim, aliases] of [ - ["job_workflow_ref", { - job_workflow_ref: `f0rr0/oliphaunt/.github/workflows/ci.yml@refs/heads/main`, - }], - ["job_workflow_ref", { job_workflow_ref: null }], - ["job_workflow_ref", { job_workflow_ref: "" }], - ["job_workflow_sha", { - job_workflow_ref: expected.workflow_ref, - job_workflow_sha: "f".repeat(40), - }], - ["job_workflow_sha", { - job_workflow_ref: expected.workflow_ref, - job_workflow_sha: null, - }], - ["job_workflow_sha", { - job_workflow_ref: expected.workflow_ref, - job_workflow_sha: "", - }], - ["job_workflow_ref", { - job_workflow_ref: `f0rr0/oliphaunt/.github/workflows/ci.yml@refs/heads/main`, - job_workflow_sha: expected.workflow_sha, - }], - ]) { - assert.throws( - () => verifyOidcClaims({ ...expected, ...aliases }, expected), - new RegExp(`claim ${claim} mismatch`, "u"), - ); - } -}); - -test("rejects unsupported events, refs, operations, and malformed SHAs", () => { - assert.throws( - () => expectedOidcIdentity({ ...environment(), GITHUB_EVENT_NAME: "push" }), - /must originate from workflow_dispatch/u, - ); - assert.throws( - () => expectedOidcIdentity({ ...environment(), GITHUB_REF: "refs/heads/release" }), - /trusted publication ref mismatch/u, - ); - assert.throws( - () => expectedOidcIdentity({ ...environment(), RELEASE_OPERATION: "publish-dry-run" }), - /must be publish/u, - ); - assert.throws( - () => expectedOidcIdentity({ ...environment(), GITHUB_SHA: "HEAD" }), - /must be a lowercase full commit SHA/u, - ); -}); - -test("constructs a bounded HTTPS OIDC request without losing GitHub query parameters", () => { - const url = oidcRequestUrl(environment().ACTIONS_ID_TOKEN_REQUEST_URL); - assert.equal(url.protocol, "https:"); - assert.equal(url.searchParams.get("api-version"), "2.0"); - assert.equal(url.searchParams.get("audience"), "oliphaunt-release-identity-preflight"); - assert.throws(() => oidcRequestUrl("http://token.actions.example/request"), /must use HTTPS/u); -}); - -test("decodes only a bounded three-part JWT object", () => { - const payload = { repository: "f0rr0/oliphaunt" }; - assert.deepEqual(decodeJwtPayload(jwt(payload)), payload); - assert.throws(() => decodeJwtPayload("not-a-jwt"), /three-part JWT/u); - assert.throws(() => decodeJwtPayload(`a.${Buffer.from("[]").toString("base64url")}.c`), /must be an object/u); -}); - -test("requests and validates the live-token response without exposing it", async () => { - const env = environment(); - const expected = expectedOidcIdentity(env); - let request; - const fetchImpl = async (url, options) => { - request = { url, options }; - return new Response(JSON.stringify({ - value: jwt({ - ...expected, - job_workflow_ref: expected.workflow_ref, - }), - }), { - status: 200, - headers: { "content-type": "application/json" }, - }); - }; - - assert.deepEqual(await verifyGithubOidcIdentity(env, fetchImpl), expected); - assert.equal(request.url.searchParams.get("audience"), "oliphaunt-release-identity-preflight"); - assert.equal(request.options.headers.Authorization, "Bearer request-token"); - assert.equal(request.options.redirect, "error"); -}); - -test("rejects oversized OIDC responses before JSON or JWT parsing", async () => { - const oversized = "x".repeat(128 * 1024 + 1); - await assert.rejects( - () => readBoundedOidcResponse(new Response(oversized)), - /response exceeded the byte limit/u, - ); - await assert.rejects( - () => - readBoundedOidcResponse( - new Response("{}", { headers: { "content-length": String(128 * 1024 + 1) } }), - ), - /response exceeded the byte limit/u, - ); -}); diff --git a/tools/release/verify-github-oidc-identity.test.mts b/tools/release/verify-github-oidc-identity.test.mts new file mode 100644 index 000000000..1816ade6c --- /dev/null +++ b/tools/release/verify-github-oidc-identity.test.mts @@ -0,0 +1,219 @@ +#!/usr/bin/env bun + +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + decodeJwtPayload, + expectedOidcIdentity, + oidcRequestUrl, + readBoundedOidcResponse, + verifyGithubOidcIdentity, + verifyOidcClaims, +} from '../../.github/scripts/verify-github-oidc-identity.mts'; + +const SHA = '0123456789abcdef0123456789abcdef01234567'; + +function environment(operation = 'publish') { + return { + ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'request-token', + ACTIONS_ID_TOKEN_REQUEST_URL: + 'https://token.actions.githubusercontent.com/example?api-version=2.0', + CANONICAL_RELEASE_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_EVENT_NAME: 'workflow_dispatch', + GITHUB_REF: 'refs/heads/main', + GITHUB_SHA: SHA, + RELEASE_OPERATION: operation, + }; +} + +function jwt(payload) { + return [ + Buffer.from(JSON.stringify({ alg: 'RS256', typ: 'JWT' })).toString('base64url'), + Buffer.from(JSON.stringify(payload)).toString('base64url'), + 'signature', + ].join('.'); +} + +test('models the direct release workflow identity', () => { + const publish = expectedOidcIdentity(environment('publish')); + assert.equal( + publish.workflow_ref, + `f0rr0/oliphaunt/.github/workflows/release.yml@refs/heads/main`, + ); + assert.equal(Object.hasOwn(publish, 'job_workflow_ref'), false); + assert.equal(Object.hasOwn(publish, 'job_workflow_sha'), false); + assert.equal(publish.environment, 'release-publish'); +}); + +test('requires the exact direct workflow, environment, SHA, and hosted runner claims', () => { + const expected = expectedOidcIdentity(environment()); + assert.doesNotThrow(() => verifyOidcClaims({ ...expected }, expected)); + + for (const [claim, value] of [ + ['workflow_ref', `f0rr0/oliphaunt/.github/workflows/other.yml@refs/heads/main`], + ['environment', 'release-bootstrap'], + ['sha', 'f'.repeat(40)], + ['workflow_sha', 'f'.repeat(40)], + ['runner_environment', 'self-hosted'], + ]) { + assert.throws( + () => verifyOidcClaims({ ...expected, [claim]: value }, expected), + new RegExp(`claim ${claim} mismatch`, 'u'), + ); + } +}); + +test('accepts an exact optional current-job workflow ref with or without its SHA', () => { + const expected = expectedOidcIdentity(environment()); + for (const aliases of [ + {}, + { job_workflow_ref: expected.workflow_ref }, + { + job_workflow_ref: expected.workflow_ref, + job_workflow_sha: expected.workflow_sha, + }, + ]) { + assert.doesNotThrow(() => verifyOidcClaims({ ...expected, ...aliases }, expected)); + } +}); + +test('rejects a current-job workflow SHA without the file-identifying ref', () => { + const expected = expectedOidcIdentity(environment()); + assert.throws( + () => + verifyOidcClaims( + { + ...expected, + job_workflow_sha: expected.workflow_sha, + }, + expected, + ), + /claim job_workflow_sha requires claim job_workflow_ref/u, + ); +}); + +test('rejects substituted or malformed current-job workflow aliases', () => { + const expected = expectedOidcIdentity(environment()); + for (const [claim, aliases] of [ + [ + 'job_workflow_ref', + { + job_workflow_ref: `f0rr0/oliphaunt/.github/workflows/ci.yml@refs/heads/main`, + }, + ], + ['job_workflow_ref', { job_workflow_ref: null }], + ['job_workflow_ref', { job_workflow_ref: '' }], + [ + 'job_workflow_sha', + { + job_workflow_ref: expected.workflow_ref, + job_workflow_sha: 'f'.repeat(40), + }, + ], + [ + 'job_workflow_sha', + { + job_workflow_ref: expected.workflow_ref, + job_workflow_sha: null, + }, + ], + [ + 'job_workflow_sha', + { + job_workflow_ref: expected.workflow_ref, + job_workflow_sha: '', + }, + ], + [ + 'job_workflow_ref', + { + job_workflow_ref: `f0rr0/oliphaunt/.github/workflows/ci.yml@refs/heads/main`, + job_workflow_sha: expected.workflow_sha, + }, + ], + ]) { + assert.throws( + () => verifyOidcClaims({ ...expected, ...aliases }, expected), + new RegExp(`claim ${claim} mismatch`, 'u'), + ); + } +}); + +test('rejects unsupported events, refs, operations, and malformed SHAs', () => { + assert.throws( + () => expectedOidcIdentity({ ...environment(), GITHUB_EVENT_NAME: 'push' }), + /must originate from workflow_dispatch/u, + ); + assert.throws( + () => expectedOidcIdentity({ ...environment(), GITHUB_REF: 'refs/heads/release' }), + /trusted publication ref mismatch/u, + ); + assert.throws( + () => expectedOidcIdentity({ ...environment(), RELEASE_OPERATION: 'publish-dry-run' }), + /must be publish/u, + ); + assert.throws( + () => expectedOidcIdentity({ ...environment(), GITHUB_SHA: 'HEAD' }), + /must be a lowercase full commit SHA/u, + ); +}); + +test('constructs a bounded HTTPS OIDC request without losing GitHub query parameters', () => { + const url = oidcRequestUrl(environment().ACTIONS_ID_TOKEN_REQUEST_URL); + assert.equal(url.protocol, 'https:'); + assert.equal(url.searchParams.get('api-version'), '2.0'); + assert.equal(url.searchParams.get('audience'), 'oliphaunt-release-identity-preflight'); + assert.throws(() => oidcRequestUrl('http://token.actions.example/request'), /must use HTTPS/u); +}); + +test('decodes only a bounded three-part JWT object', () => { + const payload = { repository: 'f0rr0/oliphaunt' }; + assert.deepEqual(decodeJwtPayload(jwt(payload)), payload); + assert.throws(() => decodeJwtPayload('not-a-jwt'), /three-part JWT/u); + assert.throws( + () => decodeJwtPayload(`a.${Buffer.from('[]').toString('base64url')}.c`), + /must be an object/u, + ); +}); + +test('requests and validates the live-token response without exposing it', async () => { + const env = environment(); + const expected = expectedOidcIdentity(env); + let request; + const fetchImpl = async (url, options) => { + request = { url, options }; + return new Response( + JSON.stringify({ + value: jwt({ + ...expected, + job_workflow_ref: expected.workflow_ref, + }), + }), + { + status: 200, + headers: { 'content-type': 'application/json' }, + }, + ); + }; + + assert.deepEqual(await verifyGithubOidcIdentity(env, fetchImpl), expected); + assert.equal(request.url.searchParams.get('audience'), 'oliphaunt-release-identity-preflight'); + assert.equal(request.options.headers.Authorization, 'Bearer request-token'); + assert.equal(request.options.redirect, 'error'); +}); + +test('rejects oversized OIDC responses before JSON or JWT parsing', async () => { + const oversized = 'x'.repeat(128 * 1024 + 1); + await assert.rejects( + () => readBoundedOidcResponse(new Response(oversized)), + /response exceeded the byte limit/u, + ); + await assert.rejects( + () => + readBoundedOidcResponse( + new Response('{}', { headers: { 'content-length': String(128 * 1024 + 1) } }), + ), + /response exceeded the byte limit/u, + ); +}); diff --git a/tools/release/verify-github-release-attestation-receipt.test.mjs b/tools/release/verify-github-release-attestation-receipt.test.mjs deleted file mode 100644 index ca7351334..000000000 --- a/tools/release/verify-github-release-attestation-receipt.test.mjs +++ /dev/null @@ -1,997 +0,0 @@ -import { createHash } from "node:crypto"; -import { rmSync } from "node:fs"; -import fs from "node:fs/promises"; -import path from "node:path"; - -import { afterAll, describe, expect, test } from "bun:test"; - -import { - assertAttestationSubjectCoverage, - assertGhVerifiedBundleMatchesSupplied, - assertGithubReleaseSnapshotMatchesReceipt, - buildGithubAttestationReceipt, - frozenGithubReleaseAssets, - ghBundleVerifyArgs, - queryLockedGithubReleases, - requestGithubJsonWithRetry, - validateGithubAttestationReceipt, - verifyAttestationBundles, - writeImmutableReceipt, -} from "./verify_github_release_attestations.mjs"; - -const COMMIT = "1".repeat(40); -const TREE = "2".repeat(40); -const LOCK_DIGEST = "3".repeat(64); -const ASSET_SHA = createHash("sha256").update("asset bytes\n").digest("hex"); -const REPO = "f0rr0/oliphaunt"; -const TOKEN = "github-test-token"; -const fixtureRoots = []; - -function lockFixture({ withAsset = true } = {}) { - return { - lockDigest: LOCK_DIGEST, - productArtifacts: withAsset - ? [{ - id: "github-release:product-a-1.2.3.tar.zst", - kind: "runtime", - name: "product-a-1.2.3.tar.zst", - path: "target/receipt-fixture/product-a-1.2.3.tar.zst", - product: "product-a", - role: "github-release-asset", - sha256: ASSET_SHA, - size: Buffer.byteLength("asset bytes\n"), - target: "portable", - }] - : [], - products: [ - { id: "product-zero", version: "2.0.0" }, - { id: "product-a", version: "1.2.3" }, - ], - source: { commit: COMMIT, tree: TREE }, - }; -} - -function zeroAssetLock(productCount) { - return { - lockDigest: LOCK_DIGEST, - productArtifacts: [], - products: Array.from({ length: productCount }, (_, index) => ({ - id: `product-${String(index).padStart(2, "0")}`, - version: "1.0.0", - })), - source: { commit: COMMIT, tree: TREE }, - }; -} - -function manyAssetLock(assetCount) { - const product = { id: "large-product", version: "1.0.0" }; - return { - lockDigest: LOCK_DIGEST, - productArtifacts: Array.from({ length: assetCount }, (_, index) => { - const name = `large-product-${String(index).padStart(3, "0")}.bin`; - return { - id: `github-release:${name}`, - kind: "runtime", - name, - path: `target/receipt-fixture/${name}`, - product: product.id, - role: "github-release-asset", - sha256: createHash("sha256").update(name).digest("hex"), - size: index + 1, - target: "portable", - }; - }), - products: [product], - source: { commit: COMMIT, tree: TREE }, - }; -} - -function remoteRelease(product, { assets, releaseId }) { - return { - assets, - draft: true, - id: releaseId, - name: `${product.id} v${product.version}`, - prerelease: product.version.includes("-"), - tag_name: `${product.id}-v${product.version}`, - target_commitish: COMMIT, - }; -} - -function remoteAsset({ digest = `sha256:${ASSET_SHA}`, id = 101 } = {}) { - return { - digest, - id, - name: "product-a-1.2.3.tar.zst", - size: Buffer.byteLength("asset bytes\n"), - state: "uploaded", - }; -} - -function releaseFetch(lock, { asset = remoteAsset(), contaminateZero = false } = {}) { - const calls = []; - const fetchImpl = async (url, options) => { - calls.push({ options, url }); - const parsed = new URL(url); - const assetsFor = (product) => product.id === "product-a" - ? (asset === null ? [] : [asset]) - : contaminateZero - ? [{ ...remoteAsset(), id: 202, name: "unexpected.bin" }] - : []; - if (parsed.pathname.endsWith("/releases") && parsed.searchParams.get("page") === "1") { - return Response.json(lock.products.map((product, index) => - remoteRelease(product, { assets: assetsFor(product), releaseId: index + 1 }))); - } - const match = /\/releases\/([1-9][0-9]*)\/assets$/u.exec(parsed.pathname); - if (match !== null && parsed.searchParams.get("page") === "1") { - const product = lock.products[Number(match[1]) - 1]; - return product === undefined - ? new Response("not found", { status: 404 }) - : Response.json(assetsFor(product)); - } - return new Response("not found", { status: 404 }); - }; - return { calls, fetchImpl }; -} - -function receiptSubjects() { - return [{ - bundleSha256: "a".repeat(64), - subjects: [{ name: "product-a-1.2.3.tar.zst", sha256: ASSET_SHA }], - }]; -} - -function bundleFor(subjects) { - const statement = { - _type: "https://in-toto.io/Statement/v1", - predicate: {}, - predicateType: "https://slsa.dev/provenance/v1", - subject: subjects.map(({ name, sha256 }) => ({ digest: { sha256 }, name })), - }; - return { - dsseEnvelope: { - payload: Buffer.from(JSON.stringify(statement)).toString("base64"), - payloadType: "application/vnd.in-toto+json", - signatures: [{ keyid: "", sig: "test" }], - }, - mediaType: "application/vnd.dev.sigstore.bundle.v0.3+json", - verificationMaterial: {}, - }; -} - -afterAll(async () => { - await Promise.all(fixtureRoots.map((root) => fs.rm(root, { force: true, recursive: true }))); -}); - -describe("GitHub release attestation receipt", () => { - test("uses one release page plus one exact asset inventory per product in both phases", async () => { - const lock = zeroAssetLock(49); - const calls = []; - const fetchImpl = async (url, options) => { - calls.push({ options, url }); - const parsed = new URL(url); - return Response.json(parsed.pathname.endsWith("/releases") - ? lock.products.map((product, index) => - remoteRelease(product, { assets: [], releaseId: index + 1 })) - : []); - }; - - const preMutation = await queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl, - repo: REPO, - }); - const finalize = await queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl, - repo: REPO, - }); - - expect(preMutation).toHaveLength(49); - expect(finalize).toEqual(preMutation); - expect(calls).toHaveLength(100); - expect(calls.filter(({ url }) => url.endsWith("/releases?per_page=100&page=1"))).toHaveLength(2); - expect(calls.filter(({ url }) => /\/releases\/[1-9][0-9]*\/assets\?per_page=100&page=1$/u.test(url))).toHaveLength(98); - expect(calls.every(({ options }) => options.headers.Authorization === `Bearer ${TOKEN}`)).toBe(true); - }); - - test("queries one authenticated draft-inclusive release snapshot and proves a zero-asset product has exactly no assets", async () => { - const lock = lockFixture(); - const { calls, fetchImpl } = releaseFetch(lock); - const releases = await queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl, - repo: REPO, - }); - - expect(calls).toHaveLength(3); - expect(calls[0].url).toEndWith("/releases?per_page=100&page=1"); - expect(calls.every(({ options }) => options.headers.Authorization === `Bearer ${TOKEN}`)).toBe(true); - expect(releases.map((release) => release.product)).toEqual(["product-a", "product-zero"]); - expect(releases.every((release) => release.draft)).toBe(true); - expect(releases.find((release) => release.product === "product-zero").assets).toEqual([]); - expect(releases.find((release) => release.product === "product-a").assets).toEqual([{ - assetId: "101", - name: "product-a-1.2.3.tar.zst", - sha256: ASSET_SHA, - size: Buffer.byteLength("asset bytes\n"), - }]); - }); - - test("serializes authoritative asset inventories so a backoff stops the request stream", async () => { - const lock = lockFixture(); - const assetReads = []; - let firstAssetAttempts = 0; - let now = 1_000; - let releaseBackoff; - const backoffReleased = new Promise((resolve) => { - releaseBackoff = resolve; - }); - let reportBackoff; - const backoffStarted = new Promise((resolve) => { - reportBackoff = resolve; - }); - const query = queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl: async (url) => { - const parsed = new URL(url); - if (parsed.pathname.endsWith("/releases")) { - return Response.json(lock.products.map((product, index) => - remoteRelease(product, { assets: [], releaseId: index + 1 }))); - } - assetReads.push(parsed.pathname); - if (parsed.pathname.endsWith("/releases/2/assets")) { - firstAssetAttempts += 1; - if (firstAssetAttempts === 1) { - return Response.json({ message: "secondary rate limit" }, { status: 429 }); - } - } - return Response.json(parsed.pathname.endsWith("/releases/2/assets") ? [remoteAsset()] : []); - }, - deadlineMs: 180_000, - nowImpl: () => now, - repo: REPO, - sleepImpl: async (milliseconds) => { - expect(milliseconds).toBe(60_000); - reportBackoff(); - await backoffReleased; - now += milliseconds; - }, - }); - await backoffStarted; - expect(assetReads).toEqual(["/repos/f0rr0/oliphaunt/releases/2/assets"]); - releaseBackoff(); - const releases = await query; - expect(releases).toHaveLength(2); - expect(assetReads).toEqual([ - "/repos/f0rr0/oliphaunt/releases/2/assets", - "/repos/f0rr0/oliphaunt/releases/2/assets", - "/repos/f0rr0/oliphaunt/releases/1/assets", - ]); - }); - - test("paginates the repository release inventory and rejects duplicate selected tags", async () => { - const lock = lockFixture(); - const historical = Array.from({ length: 100 }, (_, index) => - remoteRelease({ id: `historical-${index}`, version: "0.1.0" }, { - assets: [], - releaseId: index + 1_000, - })); - const selected = lock.products.map((product, index) => - remoteRelease(product, { - assets: product.id === "product-a" ? [remoteAsset()] : [], - releaseId: index + 1, - })); - const calls = []; - const releases = await queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl: async (url) => { - calls.push(url); - const parsed = new URL(url); - if (parsed.pathname.endsWith("/releases")) { - return parsed.searchParams.get("page") === "1" - ? Response.json(historical, { - headers: { Link: `<${url.replace("page=1", "page=2")}>; rel="next"` }, - }) - : Response.json(selected); - } - const match = /\/releases\/([1-9][0-9]*)\/assets$/u.exec(parsed.pathname); - const product = match === null ? undefined : lock.products[Number(match[1]) - 1]; - return Response.json(product?.id === "product-a" ? [remoteAsset()] : []); - }, - repo: REPO, - }); - expect(releases).toHaveLength(2); - expect(calls.filter((url) => new URL(url).pathname.endsWith("/releases")) - .map((url) => new URL(url).searchParams.get("page"))).toEqual(["1", "2"]); - - const duplicatePages = [ - [selected[0], ...historical.slice(0, 99)], - [{ ...selected[0], id: 999 }, selected[1]], - ]; - await expect(queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl: async (url) => { - const page = Number(new URL(url).searchParams.get("page")); - return Response.json(duplicatePages[page - 1], page === 1 - ? { headers: { Link: `<${url.replace("page=1", "page=2")}>; rel="next"` } } - : undefined); - }, - repo: REPO, - })).rejects.toThrow("duplicate releases for selected tag"); - }); - - test("exact 100- and 200-row release inventories do not request an empty trailing page", async () => { - const lock = lockFixture(); - for (const totalRows of [100, 200]) { - const historical = Array.from({ length: totalRows - lock.products.length }, (_, index) => - remoteRelease({ id: `historical-${totalRows}-${index}`, version: "0.1.0" }, { - assets: [], - releaseId: index + 1_000, - })); - const selected = lock.products.map((product, index) => - remoteRelease(product, { assets: [], releaseId: index + 1 })); - const pages = [...historical, ...selected].reduce((output, row, index) => { - const page = Math.floor(index / 100); - (output[page] ??= []).push(row); - return output; - }, []); - const releasePageCalls = []; - const releases = await queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl: async (url) => { - const parsed = new URL(url); - if (parsed.pathname.endsWith("/releases")) { - const page = Number(parsed.searchParams.get("page")); - releasePageCalls.push(page); - return Response.json(pages[page - 1], page < pages.length - ? { headers: { Link: `<${url.replace(`page=${page}`, `page=${page + 1}`)}>; rel="next"` } } - : undefined); - } - return Response.json(parsed.pathname.endsWith("/releases/2/assets") ? [remoteAsset()] : []); - }, - repo: REPO, - }); - expect(releases).toHaveLength(2); - expect(releasePageCalls).toEqual(Array.from({ length: totalRows / 100 }, (_, index) => index + 1)); - } - }); - - test("rejects selected release metadata conflicts without readiness retries", async () => { - const lock = lockFixture(); - let calls = 0; - let sleeps = 0; - await expect(queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl: async () => { - calls += 1; - return Response.json(lock.products.map((product, index) => ({ - ...remoteRelease(product, { - assets: product.id === "product-a" ? [remoteAsset()] : [], - releaseId: index + 1, - }), - ...(product.id === "product-a" ? { target_commitish: "f".repeat(40) } : {}), - }))); - }, - repo: REPO, - sleepImpl: async () => { - sleeps += 1; - }, - })).rejects.toThrow("metadata does not match the frozen publication lock"); - expect(calls).toBe(1); - expect(sleeps).toBe(0); - }); - - test("uses a paginated per-release asset inventory above the safe embedded bound", async () => { - const lock = manyAssetLock(30); - const remoteAssets = lock.productArtifacts.map((asset, index) => ({ - digest: `sha256:${asset.sha256}`, - id: index + 100, - name: asset.name, - size: asset.size, - state: "uploaded", - })); - const calls = []; - const releases = await queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl: async (url) => { - calls.push(url); - const parsed = new URL(url); - if (parsed.pathname.endsWith("/releases")) { - return Response.json([ - remoteRelease(lock.products[0], { assets: remoteAssets.slice(0, 29), releaseId: 77 }), - ]); - } - if (parsed.pathname.endsWith("/releases/77/assets")) return Response.json(remoteAssets); - return new Response("not found", { status: 404 }); - }, - repo: REPO, - }); - expect(releases[0].assets).toHaveLength(30); - expect(calls).toEqual([ - "https://api.github.com/repos/f0rr0/oliphaunt/releases?per_page=100&page=1", - "https://api.github.com/repos/f0rr0/oliphaunt/releases/77/assets?per_page=100&page=1", - ]); - }); - - test("refuses to query draft releases without an explicit authenticated token", async () => { - let calls = 0; - await expect(queryLockedGithubReleases(lockFixture(), { - authToken: "", - fetchImpl: async () => { - calls += 1; - return Response.json([]); - }, - repo: REPO, - })).rejects.toThrow("require GH_TOKEN or GITHUB_TOKEN"); - expect(calls).toBe(0); - }); - - test("rejects a missing GitHub digest and contamination of a zero-asset release", async () => { - const lock = lockFixture(); - await expect(queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl: releaseFetch(lock, { asset: remoteAsset({ digest: null }) }).fetchImpl, - repo: REPO, - snapshotMaxAttempts: 1, - })).rejects.toThrow("missing GitHub digest metadata"); - - const zeroLock = lockFixture({ withAsset: false }); - await expect(queryLockedGithubReleases(zeroLock, { - authToken: TOKEN, - fetchImpl: releaseFetch(zeroLock, { asset: null, contaminateZero: true }).fetchImpl, - repo: REPO, - })).rejects.toThrow("asset set mismatch"); - }); - - test("retries the whole exact snapshot beyond three seconds while GitHub digest metadata converges", async () => { - const lock = lockFixture(); - let snapshotQueries = 0; - let now = 1_000; - const sleeps = []; - const fetchImpl = async (url) => { - const parsed = new URL(url); - if (parsed.pathname.endsWith("/releases")) { - snapshotQueries += 1; - return Response.json(lock.products.map((product, index) => - remoteRelease(product, { assets: [], releaseId: index + 1 }))); - } - return Response.json(parsed.pathname.endsWith("/releases/2/assets") - ? [remoteAsset({ digest: snapshotQueries <= 3 ? null : `sha256:${ASSET_SHA}` })] - : []); - }; - const releases = await queryLockedGithubReleases(lock, { - authToken: TOKEN, - deadlineMs: 20_000, - fetchImpl, - nowImpl: () => now, - repo: REPO, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - }); - expect(snapshotQueries).toBe(4); - expect(sleeps).toEqual([1_000, 2_000, 4_000]); - expect(releases.find((release) => release.product === "product-a").assets[0].sha256).toBe(ASSET_SHA); - }); - - test("bounds whole-snapshot readiness retries by the shared deadline", async () => { - const lock = lockFixture(); - let snapshotQueries = 0; - let now = 1_000; - const sleeps = []; - const { fetchImpl } = releaseFetch(lock, { asset: remoteAsset({ digest: null }) }); - await expect(queryLockedGithubReleases(lock, { - authToken: TOKEN, - deadlineMs: 5_000, - fetchImpl: async (...args) => { - if (new URL(args[0]).pathname.endsWith("/releases")) snapshotQueries += 1; - const response = await fetchImpl(...args); - return response; - }, - nowImpl: () => now, - repo: REPO, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - })).rejects.toThrow("GitHub release snapshot retry would exceed its deadline"); - expect(snapshotQueries).toBe(3); - expect(sleeps).toEqual([1_000, 2_000]); - }); - - test("caps persistent whole-snapshot readiness retries after a ninety-second schedule", async () => { - const lock = lockFixture(); - let now = 0; - const sleeps = []; - await expect(queryLockedGithubReleases(lock, { - authToken: TOKEN, - deadlineMs: 120_000, - fetchImpl: releaseFetch(lock, { asset: remoteAsset({ digest: null }) }).fetchImpl, - nowImpl: () => now, - repo: REPO, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - })).rejects.toThrow("readiness retries exhausted after 10 attempts"); - expect(sleeps).toEqual([1_000, 2_000, 4_000, 8_000, 15_000, 15_000, 15_000, 15_000, 15_000]); - expect(now).toBe(90_000); - }); - - test("does not retry a non-null digest mismatch or an extra release asset", async () => { - const lock = lockFixture(); - let sleeps = 0; - await expect(queryLockedGithubReleases(lock, { - authToken: TOKEN, - deadlineMs: 120_000, - fetchImpl: releaseFetch(lock, { - asset: remoteAsset({ digest: `sha256:${"f".repeat(64)}` }), - }).fetchImpl, - nowImpl: () => 0, - repo: REPO, - sleepImpl: async () => { - sleeps += 1; - }, - })).rejects.toThrow("does not match"); - expect(sleeps).toBe(0); - - const zeroLock = lockFixture({ withAsset: false }); - await expect(queryLockedGithubReleases(zeroLock, { - authToken: TOKEN, - deadlineMs: 120_000, - fetchImpl: releaseFetch(zeroLock, { asset: null, contaminateZero: true }).fetchImpl, - nowImpl: () => 0, - repo: REPO, - sleepImpl: async () => { - sleeps += 1; - }, - })).rejects.toThrow("asset set mismatch"); - expect(sleeps).toBe(0); - }); - - test("retries transient GitHub responses and honors bounded rate-limit waits", async () => { - let attempts = 0; - let now = 1_000; - const sleeps = []; - const value = await requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 20_000, - fetchImpl: async () => { - attempts += 1; - return attempts === 1 - ? new Response("busy", { status: 502 }) - : Response.json({ ok: true }); - }, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - }); - expect(value).toEqual({ ok: true }); - expect(attempts).toBe(2); - expect(sleeps).toEqual([250]); - - attempts = 0; - now = 1_000; - sleeps.length = 0; - const unavailable = await requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 30_000, - fetchImpl: async () => { - attempts += 1; - return attempts === 1 - ? new Response("temporarily unavailable", { - headers: { "retry-after": "2" }, - status: 503, - }) - : Response.json({ ok: true }); - }, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - }); - expect(unavailable).toEqual({ ok: true }); - expect(attempts).toBe(2); - expect(sleeps).toEqual([2_000]); - - attempts = 0; - now = 1_000; - sleeps.length = 0; - const rateLimited = await requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 180_000, - fetchImpl: async () => { - attempts += 1; - return attempts === 1 - ? new Response("slow down", { headers: { "retry-after": "60" }, status: 429 }) - : Response.json({ ok: true }); - }, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - }); - expect(rateLimited).toEqual({ ok: true }); - expect(attempts).toBe(2); - expect(sleeps).toEqual([60_000]); - - attempts = 0; - now = 1_000; - sleeps.length = 0; - const secondary = await requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 180_000, - fetchImpl: async () => { - attempts += 1; - return attempts === 1 - ? Response.json({ message: "You have exceeded a secondary rate limit." }, { status: 403 }) - : Response.json({ ok: true }); - }, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - }); - expect(secondary).toEqual({ ok: true }); - expect(attempts).toBe(2); - expect(sleeps).toEqual([60_000]); - - attempts = 0; - now = 1_000_000; - sleeps.length = 0; - const primary = await requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 1_180_000, - fetchImpl: async () => { - attempts += 1; - return attempts === 1 - ? Response.json({ message: "API rate limit exceeded" }, { - headers: { - "x-ratelimit-remaining": "0", - "x-ratelimit-reset": "1060", - }, - status: 403, - }) - : Response.json({ ok: true }); - }, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - }); - expect(primary).toEqual({ ok: true }); - expect(attempts).toBe(2); - expect(sleeps).toEqual([61_000]); - - let missingResetSleeps = 0; - await expect(requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 180_000, - fetchImpl: async () => Response.json({ message: "API rate limit exceeded" }, { - headers: { "x-ratelimit-remaining": "0" }, - status: 403, - }), - nowImpl: () => 1_000, - sleepImpl: async () => { - missingResetSleeps += 1; - }, - })).rejects.toThrow("without X-RateLimit-Reset"); - expect(missingResetSleeps).toBe(0); - - attempts = 0; - now = 1_000; - sleeps.length = 0; - const exponential = await requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 240_000, - fetchImpl: async () => { - attempts += 1; - return attempts < 3 - ? Response.json({ message: "secondary rate limit" }, { status: 429 }) - : Response.json({ ok: true }); - }, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - }); - expect(exponential).toEqual({ ok: true }); - expect(attempts).toBe(3); - expect(sleeps).toEqual([60_000, 120_000]); - - attempts = 0; - now = 1_000; - sleeps.length = 0; - const mixedTransient = await requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 180_000, - fetchImpl: async () => { - attempts += 1; - if (attempts === 1) return new Response("busy", { status: 502 }); - return attempts === 2 - ? Response.json({ message: "secondary rate limit" }, { status: 429 }) - : Response.json({ ok: true }); - }, - nowImpl: () => now, - sleepImpl: async (milliseconds) => { - sleeps.push(milliseconds); - now += milliseconds; - }, - }); - expect(mixedTransient).toEqual({ ok: true }); - expect(attempts).toBe(3); - expect(sleeps).toEqual([250, 60_000]); - - let forbiddenSleeps = 0; - await expect(requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 180_000, - fetchImpl: async () => Response.json( - { message: "Resource not accessible by integration" }, - { status: 403 }, - ), - nowImpl: () => 1_000, - sleepImpl: async () => { - forbiddenSleeps += 1; - }, - })).rejects.toThrow("HTTP 403"); - expect(forbiddenSleeps).toBe(0); - - await expect(requestGithubJsonWithRetry("https://api.github.com/example", { - deadlineMs: 600_000, - fetchImpl: async () => new Response("slow down", { - headers: { "retry-after": "300" }, - status: 429, - }), - nowImpl: () => 1_000, - sleepImpl: async () => { - throw new Error("must not sleep"); - }, - })).rejects.toThrow("exceeding the 240000ms retry cap"); - }); - - test("recomputes the transport deadline after request-journal admission", async () => { - const root = await fs.mkdtemp(path.join(process.cwd(), "target/github-receipt-journal-test.")); - fixtureRoots.push(root); - const journal = path.join(root, "journal.json"); - const lock = `${journal}.lock`; - await fs.writeFile(lock, "occupied\n"); - let fetches = 0; - let now = 1_000; - await expect(requestGithubJsonWithRetry("https://api.github.com/example", { - coreJournalOptions: { - environment: { - GITHUB_REPOSITORY: "f0rr0/oliphaunt", - GITHUB_RUN_ATTEMPT: "1", - GITHUB_RUN_ID: "123", - GITHUB_SHA: COMMIT, - OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: journal, - OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: "true", - }, - now: () => now, - sleep: (milliseconds) => { - now += milliseconds; - rmSync(lock, { force: true }); - }, - }, - deadlineMs: 1_075, - fetchImpl: async () => { - fetches += 1; - return Response.json({ ok: true }); - }, - nowImpl: () => now, - sleepImpl: async () => { - throw new Error("must not retry"); - }, - })).rejects.toThrow("deadline expired during request-journal admission"); - expect(fetches).toBe(0); - }); - - test("requires an exact non-overlapping signed subject union", () => { - const assets = frozenGithubReleaseAssets(lockFixture()); - expect(assertAttestationSubjectCoverage(assets, receiptSubjects())).toEqual(receiptSubjects()); - expect(() => assertAttestationSubjectCoverage(assets, [])).toThrow("missing signed subjects"); - expect(() => assertAttestationSubjectCoverage(assets, [ - ...receiptSubjects(), - { bundleSha256: "b".repeat(64), subjects: receiptSubjects()[0].subjects }, - ])).toThrow("overlaps multiple attestation bundles"); - expect(() => assertAttestationSubjectCoverage(assets, [{ - bundleSha256: "b".repeat(64), - subjects: [{ name: "unlocked.bin", sha256: "c".repeat(64) }], - }])).toThrow("contains non-frozen subject unlocked.bin"); - expect(() => assertAttestationSubjectCoverage([], receiptSubjects())).toThrow( - "contaminate a release selection with no frozen GitHub assets", - ); - - const repeatedNameAssets = [ - { product: "liboliphaunt-native", name: "contrib-control.json", sha256: "1".repeat(64) }, - { product: "liboliphaunt-wasix", name: "contrib-control.json", sha256: "2".repeat(64) }, - ]; - const repeatedNameAttestation = [{ - bundleSha256: "3".repeat(64), - subjects: repeatedNameAssets.map(({ name, sha256 }) => ({ name, sha256 })), - }]; - expect(assertAttestationSubjectCoverage(repeatedNameAssets, repeatedNameAttestation)) - .toEqual(repeatedNameAttestation); - expect(() => assertAttestationSubjectCoverage(repeatedNameAssets, [{ - bundleSha256: "4".repeat(64), - subjects: [{ name: "contrib-control.json", sha256: "5".repeat(64) }], - }])).toThrow("digest differs from the frozen GitHub asset"); - }); - - test("builds a deterministic lock/head/release-ID-bound receipt", async () => { - const lock = lockFixture(); - const releases = await queryLockedGithubReleases(lock, { - authToken: TOKEN, - fetchImpl: releaseFetch(lock).fetchImpl, - repo: REPO, - }); - const receipt = buildGithubAttestationReceipt({ - attestations: receiptSubjects(), - lock, - releases: [...releases].reverse(), - repo: REPO, - }); - expect(validateGithubAttestationReceipt(receipt, lock, { repo: REPO })).toBe(receipt); - expect(receipt.signerWorkflow).toBe("f0rr0/oliphaunt/.github/workflows/release.yml"); - expect(receipt.head).toBe(COMMIT); - expect(receipt.lockDigest).toBe(LOCK_DIGEST); - const publisherReceipt = buildGithubAttestationReceipt({ - attestations: receiptSubjects(), lock, releases, repo: REPO, publisherSha: "4".repeat(40), - }); - expect(validateGithubAttestationReceipt(publisherReceipt, lock, { repo: REPO }).publisherSha).toBe("4".repeat(40)); - expect(publisherReceipt.head).toBe(COMMIT); - publisherReceipt.publisherSha = "5".repeat(40); - expect(() => validateGithubAttestationReceipt(publisherReceipt, lock, { repo: REPO })).toThrow(/digest mismatch/u); - - const changed = structuredClone(releases); - changed[0].assets[0].assetId = "999"; - expect(() => assertGithubReleaseSnapshotMatchesReceipt(receipt, changed)).toThrow( - "IDs, names, sizes, or digests changed", - ); - - const tampered = structuredClone(receipt); - tampered.releases[0].releaseId = "999"; - expect(() => validateGithubAttestationReceipt(tampered, lock, { repo: REPO })).toThrow( - "receipt digest mismatch", - ); - }); - - test("verifies one locked local subject per bundle and checks the complete signed statement", async () => { - const root = await fs.mkdtemp(path.join(process.cwd(), "target/receipt-verifier-test.")); - fixtureRoots.push(root); - const local = path.join(root, "product-a-1.2.3.tar.zst"); - await fs.writeFile(local, "asset bytes\n"); - const lock = lockFixture(); - lock.productArtifacts[0].path = path.relative(process.cwd(), local).split(path.sep).join("/"); - const subjects = [{ name: "product-a-1.2.3.tar.zst", sha256: ASSET_SHA }]; - const bundlePath = path.join(root, "attestation.json"); - await fs.writeFile(bundlePath, JSON.stringify(bundleFor(subjects))); - const calls = []; - const records = await verifyAttestationBundles(lock, [bundlePath], { - repo: REPO, - verifyBundleImpl: async (options) => { - calls.push(options); - return subjects; - }, - }); - expect(calls).toHaveLength(1); - expect(calls[0].file).toBe(local); - expect(records[0].subjects).toEqual(subjects); - const publisherSha = "4".repeat(40); - await verifyAttestationBundles(lock, [bundlePath], { - repo: REPO, publisherSha, - verifyBundleImpl: async (options) => { - expect(options.head).toBe(publisherSha); - return subjects; - }, - }); - - await expect(verifyAttestationBundles(lock, [bundlePath], { - repo: REPO, - verifyBundleImpl: async () => [{ name: "different.bin", sha256: ASSET_SHA }], - })).rejects.toThrow("differ from its DSSE statement"); - }); - - test("builds exact direct-workflow signer and exact-source gh verification arguments", () => { - const args = ghBundleVerifyArgs({ - bundlePath: "/tmp/bundle.json", - file: "/tmp/asset.tar.zst", - head: COMMIT, - repo: REPO, - }); - expect(args).toContain("f0rr0/oliphaunt/.github/workflows/release.yml"); - expect(args.slice(args.indexOf("--source-ref"), args.indexOf("--source-ref") + 2)).toEqual([ - "--source-ref", - "refs/heads/main", - ]); - expect(args.slice(args.indexOf("--source-digest"), args.indexOf("--source-digest") + 2)).toEqual([ - "--source-digest", - COMMIT, - ]); - expect(args.slice(args.indexOf("--signer-digest"), args.indexOf("--signer-digest") + 2)).toEqual([ - "--signer-digest", - COMMIT, - ]); - expect(args.slice(args.indexOf("--predicate-type"), args.indexOf("--predicate-type") + 2)).toEqual([ - "--predicate-type", - "https://slsa.dev/provenance/v1", - ]); - expect(args).toContain("--deny-self-hosted-runners"); - - }); - - test("accepts only gh's known empty signature key ID and RFC3161 protobuf defaults", () => { - const supplied = bundleFor(receiptSubjects()[0].subjects); - supplied.dsseEnvelope.signatures[0].keyid = ""; - supplied.verificationMaterial = { - certificate: { rawBytes: "certificate" }, - timestampVerificationData: { rfc3161Timestamps: [] }, - tlogEntries: [{ logIndex: "1" }], - }; - const verified = structuredClone(supplied); - delete verified.dsseEnvelope.signatures[0].keyid; - verified.verificationMaterial.timestampVerificationData = {}; - - expect(() => assertGhVerifiedBundleMatchesSupplied(verified, supplied)).not.toThrow(); - expect(() => assertGhVerifiedBundleMatchesSupplied(supplied, verified)).not.toThrow(); - - for (const keyid of ["different", null, 0]) { - const changedKeyId = structuredClone(verified); - changedKeyId.dsseEnvelope.signatures[0].keyid = keyid; - expect(() => assertGhVerifiedBundleMatchesSupplied(changedKeyId, supplied)).toThrow( - "does not contain the supplied bundle", - ); - } - - const changedEnvelope = structuredClone(verified); - changedEnvelope.dsseEnvelope.signatures[0].sig = "different"; - expect(() => assertGhVerifiedBundleMatchesSupplied(changedEnvelope, supplied)).toThrow( - "does not contain the supplied bundle", - ); - - const changedCertificate = structuredClone(verified); - changedCertificate.verificationMaterial.certificate.rawBytes = "different"; - expect(() => assertGhVerifiedBundleMatchesSupplied(changedCertificate, supplied)).toThrow( - "does not contain the supplied bundle", - ); - - const unexpectedCanonicalization = structuredClone(verified); - unexpectedCanonicalization.verificationMaterial.tlogEntries = []; - expect(() => assertGhVerifiedBundleMatchesSupplied(unexpectedCanonicalization, supplied)).toThrow( - "does not contain the supplied bundle", - ); - }); - - test("publishes receipt files atomically, cleans interrupted temps, and permits only identical reruns", async () => { - const root = await fs.mkdtemp(path.join(process.cwd(), "target/github-receipt-write-test.")); - fixtureRoots.push(root); - const output = path.join(root, "receipt.json"); - const receipt = { lockDigest: LOCK_DIGEST, schema: "test-receipt" }; - - await expect(writeImmutableReceipt(output, receipt, { - linkImpl: async () => { - const error = new Error("simulated interruption before atomic publication"); - error.code = "EINTR"; - throw error; - }, - })).rejects.toThrow("simulated interruption"); - await expect(fs.access(output)).rejects.toThrow(); - expect(await fs.readdir(root)).toEqual([]); - - await writeImmutableReceipt(output, receipt); - expect(JSON.parse(await fs.readFile(output, "utf8"))).toEqual(receipt); - await expect(writeImmutableReceipt(output, receipt)).resolves.toBe(output); - await expect(writeImmutableReceipt(output, { ...receipt, changed: true })).rejects.toThrow( - "refusing to replace existing non-identical", - ); - expect((await fs.readdir(root)).every((name) => !name.includes(".tmp-"))).toBe(true); - - await fs.rm(output); - const decoy = path.join(root, "decoy.json"); - await fs.writeFile(decoy, JSON.stringify(receipt)); - await fs.symlink(decoy, output); - await expect(writeImmutableReceipt(output, receipt)).rejects.toThrow("regular non-symlink file"); - expect((await fs.readdir(root)).every((name) => !name.includes(".tmp-"))).toBe(true); - }); -}); diff --git a/tools/release/verify-github-release-attestation-receipt.test.mts b/tools/release/verify-github-release-attestation-receipt.test.mts new file mode 100644 index 000000000..377f20c7d --- /dev/null +++ b/tools/release/verify-github-release-attestation-receipt.test.mts @@ -0,0 +1,1178 @@ +import { afterAll, describe, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { rmSync } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; + +import { + assertAttestationSubjectCoverage, + assertGhVerifiedBundleMatchesSupplied, + assertGithubReleaseSnapshotMatchesReceipt, + buildGithubAttestationReceipt, + frozenGithubReleaseAssets, + prepareBundleVerification, + queryLockedGithubReleases, + requestGithubJsonWithRetry, + validateGithubAttestationReceipt, + verifyAttestationBundles, + writeImmutableReceipt, +} from './verify_github_release_attestations.mts'; + +const COMMIT = '1'.repeat(40); +const TREE = '2'.repeat(40); +const LOCK_DIGEST = '3'.repeat(64); +const ASSET_SHA = createHash('sha256').update('asset bytes\n').digest('hex'); +const REPO = 'f0rr0/oliphaunt'; +const TOKEN = 'github-test-token'; +const fixtureRoots = []; +await fs.mkdir(path.join(process.cwd(), 'target'), { recursive: true }); + +function lockFixture({ withAsset = true } = {}) { + return { + lockDigest: LOCK_DIGEST, + productArtifacts: withAsset + ? [ + { + id: 'github-release:product-a-1.2.3.tar.zst', + kind: 'runtime', + name: 'product-a-1.2.3.tar.zst', + path: 'target/receipt-fixture/product-a-1.2.3.tar.zst', + product: 'product-a', + role: 'github-release-asset', + sha256: ASSET_SHA, + size: Buffer.byteLength('asset bytes\n'), + target: 'portable', + }, + ] + : [], + products: [ + { id: 'product-zero', version: '2.0.0' }, + { id: 'product-a', version: '1.2.3' }, + ], + source: { commit: COMMIT, tree: TREE }, + }; +} + +function zeroAssetLock(productCount) { + return { + lockDigest: LOCK_DIGEST, + productArtifacts: [], + products: Array.from({ length: productCount }, (_, index) => ({ + id: `product-${String(index).padStart(2, '0')}`, + version: '1.0.0', + })), + source: { commit: COMMIT, tree: TREE }, + }; +} + +function manyAssetLock(assetCount) { + const product = { id: 'large-product', version: '1.0.0' }; + return { + lockDigest: LOCK_DIGEST, + productArtifacts: Array.from({ length: assetCount }, (_, index) => { + const name = `large-product-${String(index).padStart(3, '0')}.bin`; + return { + id: `github-release:${name}`, + kind: 'runtime', + name, + path: `target/receipt-fixture/${name}`, + product: product.id, + role: 'github-release-asset', + sha256: createHash('sha256').update(name).digest('hex'), + size: index + 1, + target: 'portable', + }; + }), + products: [product], + source: { commit: COMMIT, tree: TREE }, + }; +} + +function remoteRelease(product, { assets, releaseId }) { + return { + assets, + draft: true, + id: releaseId, + name: `${product.id} v${product.version}`, + prerelease: product.version.includes('-'), + tag_name: `${product.id}-v${product.version}`, + target_commitish: COMMIT, + }; +} + +function remoteAsset({ digest = `sha256:${ASSET_SHA}`, id = 101 } = {}) { + return { + digest, + id, + name: 'product-a-1.2.3.tar.zst', + size: Buffer.byteLength('asset bytes\n'), + state: 'uploaded', + }; +} + +function releaseFetch(lock, { asset = remoteAsset(), contaminateZero = false } = {}) { + const calls = []; + const fetchImpl = async (url, options) => { + calls.push({ options, url }); + const parsed = new URL(url); + const assetsFor = (product) => + product.id === 'product-a' + ? asset === null + ? [] + : [asset] + : contaminateZero + ? [{ ...remoteAsset(), id: 202, name: 'unexpected.bin' }] + : []; + if (parsed.pathname.endsWith('/releases') && parsed.searchParams.get('page') === '1') { + return Response.json( + lock.products.map((product, index) => + remoteRelease(product, { assets: assetsFor(product), releaseId: index + 1 }), + ), + ); + } + const match = /\/releases\/([1-9][0-9]*)\/assets$/u.exec(parsed.pathname); + if (match !== null && parsed.searchParams.get('page') === '1') { + const product = lock.products[Number(match[1]) - 1]; + return product === undefined + ? new Response('not found', { status: 404 }) + : Response.json(assetsFor(product)); + } + return new Response('not found', { status: 404 }); + }; + return { calls, fetchImpl }; +} + +function receiptSubjects() { + return [ + { + bundleSha256: 'a'.repeat(64), + subjects: [{ name: 'product-a-1.2.3.tar.zst', sha256: ASSET_SHA }], + }, + ]; +} + +function bundleFor(subjects) { + const statement = { + _type: 'https://in-toto.io/Statement/v1', + predicate: {}, + predicateType: 'https://slsa.dev/provenance/v1', + subject: subjects.map(({ name, sha256 }) => ({ digest: { sha256 }, name })), + }; + return { + dsseEnvelope: { + payload: Buffer.from(JSON.stringify(statement)).toString('base64'), + payloadType: 'application/vnd.in-toto+json', + signatures: [{ keyid: '', sig: 'test' }], + }, + mediaType: 'application/vnd.dev.sigstore.bundle.v0.3+json', + verificationMaterial: {}, + }; +} + +if ( + [ + 'prepare-verifier', + 'verify-success', + 'verify-unavailable', + 'prepare-tampered', + 'verify-tampered', + ].includes(process.argv[2]) +) { + if (process.argv[2] === 'prepare-verifier') { + const root = process.argv[3]; + const local = path.join(root, 'product-a-1.2.3.tar.zst'); + await fs.writeFile(local, 'asset bytes\n'); + const lock = lockFixture(); + lock.productArtifacts[0].path = path.relative(process.cwd(), local).split(path.sep).join('/'); + const subjects = [{ name: 'product-a-1.2.3.tar.zst', sha256: ASSET_SHA }]; + const bundlePath = path.join(root, 'attestation.json'); + await fs.writeFile(bundlePath, JSON.stringify(bundleFor(subjects))); + const records = await verifyAttestationBundles(lock, [bundlePath], { + repo: REPO, + verifyBundleImpl: async (options) => { + await prepareBundleVerification(options, root); + return subjects; + }, + }); + const response = path.join(root, 'gh-output.json'); + const bundle = bundleFor(subjects); + const verified = [ + { + attestation: { bundle }, + verificationResult: { + statement: JSON.parse(Buffer.from(bundle.dsseEnvelope.payload, 'base64').toString()), + }, + }, + ]; + await fs.writeFile(response, JSON.stringify(verified)); + await fs.writeFile( + path.join(root, 'state.json'), + JSON.stringify({ lock, bundlePath, local, records }), + ); + } else { + const root = process.argv[3]; + const { lock, bundlePath, local, records } = JSON.parse( + await fs.readFile(path.join(root, 'state.json'), 'utf8'), + ); + const log = path.join(root, 'gh-args'); + const publisherSha = '4'.repeat(40); + if (process.argv[2] === 'verify-success') { + expect((await fs.readFile(log, 'utf8')).split('\0').slice(0, -1)).toEqual([ + 'attestation', + 'verify', + local, + '--repo', + REPO, + '--bundle', + bundlePath, + '--format', + 'json', + '--predicate-type', + 'https://slsa.dev/provenance/v1', + '--signer-workflow', + REPO + '/.github/workflows/release.yml', + '--signer-digest', + COMMIT, + '--source-ref', + 'refs/heads/main', + '--source-digest', + COMMIT, + '--deny-self-hosted-runners', + ]); + expect(await verifyAttestationBundles(lock, [bundlePath], { repo: REPO })).toEqual(records); + await expect( + verifyAttestationBundles(lock, [bundlePath], { repo: REPO, publisherSha }), + ).rejects.toThrow('unavailable'); + } else if (process.argv[2] === 'prepare-tampered') { + const response = path.join(root, 'gh-output.json'); + const verified = JSON.parse(await fs.readFile(response, 'utf8')); + verified[0].attestation.bundle.dsseEnvelope.signatures[0].sig = 'different'; + await fs.writeFile(response, JSON.stringify(verified)); + } else { + await expect(verifyAttestationBundles(lock, [bundlePath], { repo: REPO })).rejects.toThrow( + process.argv[2] === 'verify-unavailable' ? 'unavailable' : 'supplied', + ); + } + } + process.exit(0); +} + +afterAll(async () => { + await Promise.all(fixtureRoots.map((root) => fs.rm(root, { force: true, recursive: true }))); +}); + +describe('GitHub release attestation receipt', () => { + test('uses one release page plus one exact asset inventory per product in both phases', async () => { + const lock = zeroAssetLock(49); + const calls = []; + const fetchImpl = async (url, options) => { + calls.push({ options, url }); + const parsed = new URL(url); + return Response.json( + parsed.pathname.endsWith('/releases') + ? lock.products.map((product, index) => + remoteRelease(product, { assets: [], releaseId: index + 1 }), + ) + : [], + ); + }; + + const preMutation = await queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl, + repo: REPO, + }); + const finalize = await queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl, + repo: REPO, + }); + + expect(preMutation).toHaveLength(49); + expect(finalize).toEqual(preMutation); + expect(calls).toHaveLength(100); + expect(calls.filter(({ url }) => url.endsWith('/releases?per_page=100&page=1'))).toHaveLength( + 2, + ); + expect( + calls.filter(({ url }) => /\/releases\/[1-9][0-9]*\/assets\?per_page=100&page=1$/u.test(url)), + ).toHaveLength(98); + expect(calls.every(({ options }) => options.headers.Authorization === `Bearer ${TOKEN}`)).toBe( + true, + ); + }); + + test('queries one authenticated draft-inclusive release snapshot and proves a zero-asset product has exactly no assets', async () => { + const lock = lockFixture(); + const { calls, fetchImpl } = releaseFetch(lock); + const releases = await queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl, + repo: REPO, + }); + + expect(calls).toHaveLength(3); + expect(calls[0].url).toEndWith('/releases?per_page=100&page=1'); + expect(calls.every(({ options }) => options.headers.Authorization === `Bearer ${TOKEN}`)).toBe( + true, + ); + expect(releases.map((release) => release.product)).toEqual(['product-a', 'product-zero']); + expect(releases.every((release) => release.draft)).toBe(true); + expect(releases.find((release) => release.product === 'product-zero').assets).toEqual([]); + expect(releases.find((release) => release.product === 'product-a').assets).toEqual([ + { + assetId: '101', + name: 'product-a-1.2.3.tar.zst', + sha256: ASSET_SHA, + size: Buffer.byteLength('asset bytes\n'), + }, + ]); + }); + + test('serializes authoritative asset inventories so a backoff stops the request stream', async () => { + const lock = lockFixture(); + const assetReads = []; + let firstAssetAttempts = 0; + let now = 1_000; + let releaseBackoff; + const backoffReleased = new Promise((resolve) => { + releaseBackoff = resolve; + }); + let reportBackoff; + const backoffStarted = new Promise((resolve) => { + reportBackoff = resolve; + }); + const query = queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl: async (url) => { + const parsed = new URL(url); + if (parsed.pathname.endsWith('/releases')) { + return Response.json( + lock.products.map((product, index) => + remoteRelease(product, { assets: [], releaseId: index + 1 }), + ), + ); + } + assetReads.push(parsed.pathname); + if (parsed.pathname.endsWith('/releases/2/assets')) { + firstAssetAttempts += 1; + if (firstAssetAttempts === 1) { + return Response.json({ message: 'secondary rate limit' }, { status: 429 }); + } + } + return Response.json(parsed.pathname.endsWith('/releases/2/assets') ? [remoteAsset()] : []); + }, + deadlineMs: 180_000, + nowImpl: () => now, + repo: REPO, + sleepImpl: async (milliseconds) => { + expect(milliseconds).toBe(60_000); + reportBackoff(); + await backoffReleased; + now += milliseconds; + }, + }); + await backoffStarted; + expect(assetReads).toEqual(['/repos/f0rr0/oliphaunt/releases/2/assets']); + releaseBackoff(); + const releases = await query; + expect(releases).toHaveLength(2); + expect(assetReads).toEqual([ + '/repos/f0rr0/oliphaunt/releases/2/assets', + '/repos/f0rr0/oliphaunt/releases/2/assets', + '/repos/f0rr0/oliphaunt/releases/1/assets', + ]); + }); + + test('paginates the repository release inventory and rejects duplicate selected tags', async () => { + const lock = lockFixture(); + const historical = Array.from({ length: 100 }, (_, index) => + remoteRelease( + { id: `historical-${index}`, version: '0.1.0' }, + { + assets: [], + releaseId: index + 1_000, + }, + ), + ); + const selected = lock.products.map((product, index) => + remoteRelease(product, { + assets: product.id === 'product-a' ? [remoteAsset()] : [], + releaseId: index + 1, + }), + ); + const calls = []; + const releases = await queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl: async (url) => { + calls.push(url); + const parsed = new URL(url); + if (parsed.pathname.endsWith('/releases')) { + return parsed.searchParams.get('page') === '1' + ? Response.json(historical, { + headers: { Link: `<${url.replace('page=1', 'page=2')}>; rel="next"` }, + }) + : Response.json(selected); + } + const match = /\/releases\/([1-9][0-9]*)\/assets$/u.exec(parsed.pathname); + const product = match === null ? undefined : lock.products[Number(match[1]) - 1]; + return Response.json(product?.id === 'product-a' ? [remoteAsset()] : []); + }, + repo: REPO, + }); + expect(releases).toHaveLength(2); + expect( + calls + .filter((url) => new URL(url).pathname.endsWith('/releases')) + .map((url) => new URL(url).searchParams.get('page')), + ).toEqual(['1', '2']); + + const duplicatePages = [ + [selected[0], ...historical.slice(0, 99)], + [{ ...selected[0], id: 999 }, selected[1]], + ]; + await expect( + queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl: async (url) => { + const page = Number(new URL(url).searchParams.get('page')); + return Response.json( + duplicatePages[page - 1], + page === 1 + ? { headers: { Link: `<${url.replace('page=1', 'page=2')}>; rel="next"` } } + : undefined, + ); + }, + repo: REPO, + }), + ).rejects.toThrow('duplicate releases for selected tag'); + }); + + test('exact 100- and 200-row release inventories do not request an empty trailing page', async () => { + const lock = lockFixture(); + for (const totalRows of [100, 200]) { + const historical = Array.from({ length: totalRows - lock.products.length }, (_, index) => + remoteRelease( + { id: `historical-${totalRows}-${index}`, version: '0.1.0' }, + { + assets: [], + releaseId: index + 1_000, + }, + ), + ); + const selected = lock.products.map((product, index) => + remoteRelease(product, { assets: [], releaseId: index + 1 }), + ); + const pages = [...historical, ...selected].reduce((output, row, index) => { + const page = Math.floor(index / 100); + output[page] ??= []; + output[page].push(row); + return output; + }, []); + const releasePageCalls = []; + const releases = await queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl: async (url) => { + const parsed = new URL(url); + if (parsed.pathname.endsWith('/releases')) { + const page = Number(parsed.searchParams.get('page')); + releasePageCalls.push(page); + return Response.json( + pages[page - 1], + page < pages.length + ? { + headers: { + Link: `<${url.replace(`page=${page}`, `page=${page + 1}`)}>; rel="next"`, + }, + } + : undefined, + ); + } + return Response.json( + parsed.pathname.endsWith('/releases/2/assets') ? [remoteAsset()] : [], + ); + }, + repo: REPO, + }); + expect(releases).toHaveLength(2); + expect(releasePageCalls).toEqual( + Array.from({ length: totalRows / 100 }, (_, index) => index + 1), + ); + } + }); + + test('rejects selected release metadata conflicts without readiness retries', async () => { + const lock = lockFixture(); + let calls = 0; + let sleeps = 0; + await expect( + queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl: async () => { + calls += 1; + return Response.json( + lock.products.map((product, index) => ({ + ...remoteRelease(product, { + assets: product.id === 'product-a' ? [remoteAsset()] : [], + releaseId: index + 1, + }), + ...(product.id === 'product-a' ? { target_commitish: 'f'.repeat(40) } : {}), + })), + ); + }, + repo: REPO, + sleepImpl: async () => { + sleeps += 1; + }, + }), + ).rejects.toThrow('metadata does not match the frozen publication lock'); + expect(calls).toBe(1); + expect(sleeps).toBe(0); + }); + + test('uses a paginated per-release asset inventory above the safe embedded bound', async () => { + const lock = manyAssetLock(30); + const remoteAssets = lock.productArtifacts.map((asset, index) => ({ + digest: `sha256:${asset.sha256}`, + id: index + 100, + name: asset.name, + size: asset.size, + state: 'uploaded', + })); + const calls = []; + const releases = await queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl: async (url) => { + calls.push(url); + const parsed = new URL(url); + if (parsed.pathname.endsWith('/releases')) { + return Response.json([ + remoteRelease(lock.products[0], { assets: remoteAssets.slice(0, 29), releaseId: 77 }), + ]); + } + if (parsed.pathname.endsWith('/releases/77/assets')) return Response.json(remoteAssets); + return new Response('not found', { status: 404 }); + }, + repo: REPO, + }); + expect(releases[0].assets).toHaveLength(30); + expect(calls).toEqual([ + 'https://api.github.com/repos/f0rr0/oliphaunt/releases?per_page=100&page=1', + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/77/assets?per_page=100&page=1', + ]); + }); + + test('refuses to query draft releases without an explicit authenticated token', async () => { + let calls = 0; + await expect( + queryLockedGithubReleases(lockFixture(), { + authToken: '', + fetchImpl: async () => { + calls += 1; + return Response.json([]); + }, + repo: REPO, + }), + ).rejects.toThrow('require GH_TOKEN or GITHUB_TOKEN'); + expect(calls).toBe(0); + }); + + test('rejects a missing GitHub digest and contamination of a zero-asset release', async () => { + const lock = lockFixture(); + await expect( + queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl: releaseFetch(lock, { asset: remoteAsset({ digest: null }) }).fetchImpl, + repo: REPO, + snapshotMaxAttempts: 1, + }), + ).rejects.toThrow('missing GitHub digest metadata'); + + const zeroLock = lockFixture({ withAsset: false }); + await expect( + queryLockedGithubReleases(zeroLock, { + authToken: TOKEN, + fetchImpl: releaseFetch(zeroLock, { asset: null, contaminateZero: true }).fetchImpl, + repo: REPO, + }), + ).rejects.toThrow('asset set mismatch'); + }); + + test('retries the whole exact snapshot beyond three seconds while GitHub digest metadata converges', async () => { + const lock = lockFixture(); + let snapshotQueries = 0; + let now = 1_000; + const sleeps = []; + const fetchImpl = async (url) => { + const parsed = new URL(url); + if (parsed.pathname.endsWith('/releases')) { + snapshotQueries += 1; + return Response.json( + lock.products.map((product, index) => + remoteRelease(product, { assets: [], releaseId: index + 1 }), + ), + ); + } + return Response.json( + parsed.pathname.endsWith('/releases/2/assets') + ? [remoteAsset({ digest: snapshotQueries <= 3 ? null : `sha256:${ASSET_SHA}` })] + : [], + ); + }; + const releases = await queryLockedGithubReleases(lock, { + authToken: TOKEN, + deadlineMs: 20_000, + fetchImpl, + nowImpl: () => now, + repo: REPO, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }); + expect(snapshotQueries).toBe(4); + expect(sleeps).toEqual([1_000, 2_000, 4_000]); + expect(releases.find((release) => release.product === 'product-a').assets[0].sha256).toBe( + ASSET_SHA, + ); + }); + + test('bounds whole-snapshot readiness retries by the shared deadline', async () => { + const lock = lockFixture(); + let snapshotQueries = 0; + let now = 1_000; + const sleeps = []; + const { fetchImpl } = releaseFetch(lock, { asset: remoteAsset({ digest: null }) }); + await expect( + queryLockedGithubReleases(lock, { + authToken: TOKEN, + deadlineMs: 5_000, + fetchImpl: async (...args) => { + if (new URL(args[0]).pathname.endsWith('/releases')) snapshotQueries += 1; + const response = await fetchImpl(...args); + return response; + }, + nowImpl: () => now, + repo: REPO, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }), + ).rejects.toThrow('GitHub release snapshot retry would exceed its deadline'); + expect(snapshotQueries).toBe(3); + expect(sleeps).toEqual([1_000, 2_000]); + }); + + test('caps persistent whole-snapshot readiness retries after a ninety-second schedule', async () => { + const lock = lockFixture(); + let now = 0; + const sleeps = []; + await expect( + queryLockedGithubReleases(lock, { + authToken: TOKEN, + deadlineMs: 120_000, + fetchImpl: releaseFetch(lock, { asset: remoteAsset({ digest: null }) }).fetchImpl, + nowImpl: () => now, + repo: REPO, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }), + ).rejects.toThrow('readiness retries exhausted after 10 attempts'); + expect(sleeps).toEqual([1_000, 2_000, 4_000, 8_000, 15_000, 15_000, 15_000, 15_000, 15_000]); + expect(now).toBe(90_000); + }); + + test('does not retry a non-null digest mismatch or an extra release asset', async () => { + const lock = lockFixture(); + let sleeps = 0; + await expect( + queryLockedGithubReleases(lock, { + authToken: TOKEN, + deadlineMs: 120_000, + fetchImpl: releaseFetch(lock, { + asset: remoteAsset({ digest: `sha256:${'f'.repeat(64)}` }), + }).fetchImpl, + nowImpl: () => 0, + repo: REPO, + sleepImpl: async () => { + sleeps += 1; + }, + }), + ).rejects.toThrow('does not match'); + expect(sleeps).toBe(0); + + const zeroLock = lockFixture({ withAsset: false }); + await expect( + queryLockedGithubReleases(zeroLock, { + authToken: TOKEN, + deadlineMs: 120_000, + fetchImpl: releaseFetch(zeroLock, { asset: null, contaminateZero: true }).fetchImpl, + nowImpl: () => 0, + repo: REPO, + sleepImpl: async () => { + sleeps += 1; + }, + }), + ).rejects.toThrow('asset set mismatch'); + expect(sleeps).toBe(0); + }); + + test('retries transient GitHub responses and honors bounded rate-limit waits', async () => { + let attempts = 0; + let now = 1_000; + const sleeps = []; + const value = await requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 20_000, + fetchImpl: async () => { + attempts += 1; + return attempts === 1 ? new Response('busy', { status: 502 }) : Response.json({ ok: true }); + }, + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }); + expect(value).toEqual({ ok: true }); + expect(attempts).toBe(2); + expect(sleeps).toEqual([250]); + + attempts = 0; + now = 1_000; + sleeps.length = 0; + const unavailable = await requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 30_000, + fetchImpl: async () => { + attempts += 1; + return attempts === 1 + ? new Response('temporarily unavailable', { + headers: { 'retry-after': '2' }, + status: 503, + }) + : Response.json({ ok: true }); + }, + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }); + expect(unavailable).toEqual({ ok: true }); + expect(attempts).toBe(2); + expect(sleeps).toEqual([2_000]); + + attempts = 0; + now = 1_000; + sleeps.length = 0; + const rateLimited = await requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 180_000, + fetchImpl: async () => { + attempts += 1; + return attempts === 1 + ? new Response('slow down', { headers: { 'retry-after': '60' }, status: 429 }) + : Response.json({ ok: true }); + }, + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }); + expect(rateLimited).toEqual({ ok: true }); + expect(attempts).toBe(2); + expect(sleeps).toEqual([60_000]); + + attempts = 0; + now = 1_000; + sleeps.length = 0; + const secondary = await requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 180_000, + fetchImpl: async () => { + attempts += 1; + return attempts === 1 + ? Response.json({ message: 'You have exceeded a secondary rate limit.' }, { status: 403 }) + : Response.json({ ok: true }); + }, + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }); + expect(secondary).toEqual({ ok: true }); + expect(attempts).toBe(2); + expect(sleeps).toEqual([60_000]); + + attempts = 0; + now = 1_000_000; + sleeps.length = 0; + const primary = await requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 1_180_000, + fetchImpl: async () => { + attempts += 1; + return attempts === 1 + ? Response.json( + { message: 'API rate limit exceeded' }, + { + headers: { + 'x-ratelimit-remaining': '0', + 'x-ratelimit-reset': '1060', + }, + status: 403, + }, + ) + : Response.json({ ok: true }); + }, + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }); + expect(primary).toEqual({ ok: true }); + expect(attempts).toBe(2); + expect(sleeps).toEqual([61_000]); + + let missingResetSleeps = 0; + await expect( + requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 180_000, + fetchImpl: async () => + Response.json( + { message: 'API rate limit exceeded' }, + { + headers: { 'x-ratelimit-remaining': '0' }, + status: 403, + }, + ), + nowImpl: () => 1_000, + sleepImpl: async () => { + missingResetSleeps += 1; + }, + }), + ).rejects.toThrow('without X-RateLimit-Reset'); + expect(missingResetSleeps).toBe(0); + + attempts = 0; + now = 1_000; + sleeps.length = 0; + const exponential = await requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 240_000, + fetchImpl: async () => { + attempts += 1; + return attempts < 3 + ? Response.json({ message: 'secondary rate limit' }, { status: 429 }) + : Response.json({ ok: true }); + }, + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }); + expect(exponential).toEqual({ ok: true }); + expect(attempts).toBe(3); + expect(sleeps).toEqual([60_000, 120_000]); + + attempts = 0; + now = 1_000; + sleeps.length = 0; + const mixedTransient = await requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 180_000, + fetchImpl: async () => { + attempts += 1; + if (attempts === 1) return new Response('busy', { status: 502 }); + return attempts === 2 + ? Response.json({ message: 'secondary rate limit' }, { status: 429 }) + : Response.json({ ok: true }); + }, + nowImpl: () => now, + sleepImpl: async (milliseconds) => { + sleeps.push(milliseconds); + now += milliseconds; + }, + }); + expect(mixedTransient).toEqual({ ok: true }); + expect(attempts).toBe(3); + expect(sleeps).toEqual([250, 60_000]); + + let forbiddenSleeps = 0; + await expect( + requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 180_000, + fetchImpl: async () => + Response.json({ message: 'Resource not accessible by integration' }, { status: 403 }), + nowImpl: () => 1_000, + sleepImpl: async () => { + forbiddenSleeps += 1; + }, + }), + ).rejects.toThrow('HTTP 403'); + expect(forbiddenSleeps).toBe(0); + + await expect( + requestGithubJsonWithRetry('https://api.github.com/example', { + deadlineMs: 600_000, + fetchImpl: async () => + new Response('slow down', { + headers: { 'retry-after': '300' }, + status: 429, + }), + nowImpl: () => 1_000, + sleepImpl: async () => { + throw new Error('must not sleep'); + }, + }), + ).rejects.toThrow('exceeding the 240000ms retry cap'); + }); + + test('recomputes the transport deadline after request-journal admission', async () => { + const root = await fs.mkdtemp(path.join(process.cwd(), 'target/github-receipt-journal-test.')); + fixtureRoots.push(root); + const journal = path.join(root, 'journal.json'); + const lock = `${journal}.lock`; + await fs.writeFile(lock, 'occupied\n'); + let fetches = 0; + let now = 1_000; + await expect( + requestGithubJsonWithRetry('https://api.github.com/example', { + coreJournalOptions: { + environment: { + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_RUN_ATTEMPT: '1', + GITHUB_RUN_ID: '123', + GITHUB_SHA: COMMIT, + OLIPHAUNT_GITHUB_CORE_REQUEST_JOURNAL_PATH: journal, + OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL: 'true', + }, + now: () => now, + sleep: (milliseconds) => { + now += milliseconds; + rmSync(lock, { force: true }); + }, + }, + deadlineMs: 1_075, + fetchImpl: async () => { + fetches += 1; + return Response.json({ ok: true }); + }, + nowImpl: () => now, + sleepImpl: async () => { + throw new Error('must not retry'); + }, + }), + ).rejects.toThrow('deadline expired during request-journal admission'); + expect(fetches).toBe(0); + }); + + test('requires an exact non-overlapping signed subject union', () => { + const assets = frozenGithubReleaseAssets(lockFixture()); + expect(assertAttestationSubjectCoverage(assets, receiptSubjects())).toEqual(receiptSubjects()); + expect(() => assertAttestationSubjectCoverage(assets, [])).toThrow('missing signed subjects'); + expect(() => + assertAttestationSubjectCoverage(assets, [ + ...receiptSubjects(), + { bundleSha256: 'b'.repeat(64), subjects: receiptSubjects()[0].subjects }, + ]), + ).toThrow('overlaps multiple attestation bundles'); + expect(() => + assertAttestationSubjectCoverage(assets, [ + { + bundleSha256: 'b'.repeat(64), + subjects: [{ name: 'unlocked.bin', sha256: 'c'.repeat(64) }], + }, + ]), + ).toThrow('contains non-frozen subject unlocked.bin'); + expect(() => assertAttestationSubjectCoverage([], receiptSubjects())).toThrow( + 'contaminate a release selection with no frozen GitHub assets', + ); + + const repeatedNameAssets = [ + { product: 'liboliphaunt-native', name: 'contrib-control.json', sha256: '1'.repeat(64) }, + { product: 'liboliphaunt-wasix', name: 'contrib-control.json', sha256: '2'.repeat(64) }, + ]; + const repeatedNameAttestation = [ + { + bundleSha256: '3'.repeat(64), + subjects: repeatedNameAssets.map(({ name, sha256 }) => ({ name, sha256 })), + }, + ]; + expect(assertAttestationSubjectCoverage(repeatedNameAssets, repeatedNameAttestation)).toEqual( + repeatedNameAttestation, + ); + expect(() => + assertAttestationSubjectCoverage(repeatedNameAssets, [ + { + bundleSha256: '4'.repeat(64), + subjects: [{ name: 'contrib-control.json', sha256: '5'.repeat(64) }], + }, + ]), + ).toThrow('digest differs from the frozen GitHub asset'); + }); + + test('builds a deterministic lock/head/release-ID-bound receipt', async () => { + const lock = lockFixture(); + const releases = await queryLockedGithubReleases(lock, { + authToken: TOKEN, + fetchImpl: releaseFetch(lock).fetchImpl, + repo: REPO, + }); + const receipt = buildGithubAttestationReceipt({ + attestations: receiptSubjects(), + lock, + releases: [...releases].reverse(), + repo: REPO, + }); + expect(validateGithubAttestationReceipt(receipt, lock, { repo: REPO })).toBe(receipt); + expect(receipt.signerWorkflow).toBe('f0rr0/oliphaunt/.github/workflows/release.yml'); + expect(receipt.head).toBe(COMMIT); + expect(receipt.lockDigest).toBe(LOCK_DIGEST); + const publisherReceipt = buildGithubAttestationReceipt({ + attestations: receiptSubjects(), + lock, + releases, + repo: REPO, + publisherSha: '4'.repeat(40), + }); + expect( + validateGithubAttestationReceipt(publisherReceipt, lock, { repo: REPO }).publisherSha, + ).toBe('4'.repeat(40)); + expect(publisherReceipt.head).toBe(COMMIT); + publisherReceipt.publisherSha = '5'.repeat(40); + expect(() => validateGithubAttestationReceipt(publisherReceipt, lock, { repo: REPO })).toThrow( + /digest mismatch/u, + ); + + const changed = structuredClone(releases); + changed[0].assets[0].assetId = '999'; + expect(() => assertGithubReleaseSnapshotMatchesReceipt(receipt, changed)).toThrow( + 'IDs, names, sizes, or digests changed', + ); + + const tampered = structuredClone(receipt); + tampered.releases[0].releaseId = '999'; + expect(() => validateGithubAttestationReceipt(tampered, lock, { repo: REPO })).toThrow( + 'receipt digest mismatch', + ); + }); + + test('verifies one locked local subject per bundle and checks the complete signed statement', async () => { + const root = await fs.mkdtemp(path.join(process.cwd(), 'target/receipt-verifier-test.')); + fixtureRoots.push(root); + const local = path.join(root, 'product-a-1.2.3.tar.zst'); + await fs.writeFile(local, 'asset bytes\n'); + const lock = lockFixture(); + lock.productArtifacts[0].path = path.relative(process.cwd(), local).split(path.sep).join('/'); + const subjects = [{ name: 'product-a-1.2.3.tar.zst', sha256: ASSET_SHA }]; + const bundlePath = path.join(root, 'attestation.json'); + await fs.writeFile(bundlePath, JSON.stringify(bundleFor(subjects))); + const calls = []; + const records = await verifyAttestationBundles(lock, [bundlePath], { + repo: REPO, + verifyBundleImpl: async (options) => { + calls.push(options); + return subjects; + }, + }); + expect(calls).toHaveLength(1); + expect(calls[0].file).toBe(local); + expect(records[0].subjects).toEqual(subjects); + const publisherSha = '4'.repeat(40); + await verifyAttestationBundles(lock, [bundlePath], { + repo: REPO, + publisherSha, + verifyBundleImpl: async (options) => { + expect(options.head).toBe(publisherSha); + return subjects; + }, + }); + + await expect( + verifyAttestationBundles(lock, [bundlePath], { + repo: REPO, + verifyBundleImpl: async () => [{ name: 'different.bin', sha256: ASSET_SHA }], + }), + ).rejects.toThrow('differ from its DSSE statement'); + }); + + test("accepts only gh's known empty signature key ID and RFC3161 protobuf defaults", () => { + const supplied = bundleFor(receiptSubjects()[0].subjects); + supplied.dsseEnvelope.signatures[0].keyid = ''; + supplied.verificationMaterial = { + certificate: { rawBytes: 'certificate' }, + timestampVerificationData: { rfc3161Timestamps: [] }, + tlogEntries: [{ logIndex: '1' }], + }; + const verified = structuredClone(supplied); + delete verified.dsseEnvelope.signatures[0].keyid; + verified.verificationMaterial.timestampVerificationData = {}; + + expect(() => assertGhVerifiedBundleMatchesSupplied(verified, supplied)).not.toThrow(); + expect(() => assertGhVerifiedBundleMatchesSupplied(supplied, verified)).not.toThrow(); + + for (const keyid of ['different', null, 0]) { + const changedKeyId = structuredClone(verified); + changedKeyId.dsseEnvelope.signatures[0].keyid = keyid; + expect(() => assertGhVerifiedBundleMatchesSupplied(changedKeyId, supplied)).toThrow( + 'does not contain the supplied bundle', + ); + } + + const changedEnvelope = structuredClone(verified); + changedEnvelope.dsseEnvelope.signatures[0].sig = 'different'; + expect(() => assertGhVerifiedBundleMatchesSupplied(changedEnvelope, supplied)).toThrow( + 'does not contain the supplied bundle', + ); + + const changedCertificate = structuredClone(verified); + changedCertificate.verificationMaterial.certificate.rawBytes = 'different'; + expect(() => assertGhVerifiedBundleMatchesSupplied(changedCertificate, supplied)).toThrow( + 'does not contain the supplied bundle', + ); + + const unexpectedCanonicalization = structuredClone(verified); + unexpectedCanonicalization.verificationMaterial.tlogEntries = []; + expect(() => + assertGhVerifiedBundleMatchesSupplied(unexpectedCanonicalization, supplied), + ).toThrow('does not contain the supplied bundle'); + }); + + test('publishes receipt files atomically, cleans interrupted temps, and permits only identical reruns', async () => { + const root = await fs.mkdtemp(path.join(process.cwd(), 'target/github-receipt-write-test.')); + fixtureRoots.push(root); + const output = path.join(root, 'receipt.json'); + const receipt = { lockDigest: LOCK_DIGEST, schema: 'test-receipt' }; + + await expect( + writeImmutableReceipt(output, receipt, { + linkImpl: async () => { + const error = new Error('simulated interruption before atomic publication'); + error.code = 'EINTR'; + throw error; + }, + }), + ).rejects.toThrow('simulated interruption'); + await expect(fs.access(output)).rejects.toThrow(); + expect(await fs.readdir(root)).toEqual([]); + + await writeImmutableReceipt(output, receipt); + expect(JSON.parse(await fs.readFile(output, 'utf8'))).toEqual(receipt); + await expect(writeImmutableReceipt(output, receipt)).resolves.toBe(output); + await expect(writeImmutableReceipt(output, { ...receipt, changed: true })).rejects.toThrow( + 'refusing to replace existing non-identical', + ); + expect((await fs.readdir(root)).every((name) => !name.includes('.tmp-'))).toBe(true); + + await fs.rm(output); + const decoy = path.join(root, 'decoy.json'); + await fs.writeFile(decoy, JSON.stringify(receipt)); + await fs.symlink(decoy, output); + await expect(writeImmutableReceipt(output, receipt)).rejects.toThrow( + 'regular non-symlink file', + ); + expect((await fs.readdir(root)).every((name) => !name.includes('.tmp-'))).toBe(true); + }); +}); diff --git a/tools/release/verify-github-release-attestation-receipt.test.sh b/tools/release/verify-github-release-attestation-receipt.test.sh new file mode 100644 index 000000000..a148a0061 --- /dev/null +++ b/tools/release/verify-github-release-attestation-receipt.test.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/verify-github-release-attestation-receipt.test.mts +scratch="$(mktemp -d "$PWD/target/receipt-verifier.XXXXXX")" +trap 'rm -rf "$scratch"' EXIT +mkdir "$scratch/bin" +cat > "$scratch/bin/gh" <<'MOCK' +#!/usr/bin/env bash +printf '%s\0' "$@" > "$TEST_ARGS" +cat "$TEST_RESPONSE" +exit "${TEST_STATUS:-0}" +MOCK +chmod +x "$scratch/bin/gh" +export PATH="$scratch/bin:$PATH" +export TEST_ARGS="$scratch/gh-args" TEST_RESPONSE="$scratch/gh-output.json" +export OLIPHAUNT_ATTESTATION_VERIFICATION_DIR="$scratch" +fixture=tools/release/verify-github-release-attestation-receipt.test.mts +bun "$fixture" prepare-verifier "$scratch" +bash tools/release/verify-github-release-attestations.sh --verify-prepared "$scratch" +bun "$fixture" verify-success "$scratch" +status=0 +TEST_STATUS=7 bash tools/release/verify-github-release-attestations.sh --verify-prepared "$scratch" || status=$? +[[ "$status" == 7 ]] +bun "$fixture" verify-unavailable "$scratch" +bun "$fixture" prepare-tampered "$scratch" +bash tools/release/verify-github-release-attestations.sh --verify-prepared "$scratch" +bun "$fixture" verify-tampered "$scratch" +echo 'Attestation CLI identity, failed verification invalidation, and signed bundle integrity passed' diff --git a/tools/release/verify-github-release-attestations.sh b/tools/release/verify-github-release-attestations.sh new file mode 100644 index 000000000..4ab427dfc --- /dev/null +++ b/tools/release/verify-github-release-attestations.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail +owner="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$owner/../.." +native() { bash tools/dev/bun.sh tools/release/verify_github_release_attestations.mts "$@"; } +case "${1:-}" in + finalize|--help|-h) native "$@"; exit ;; +esac +# The prepared-only entry is also usable locally for a previously prepared bundle set. +if [[ "${1:-}" == --verify-prepared ]]; then + scratch="${2:?prepared directory required}" +else + scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-release-attestations.XXXXXX")" + trap 'rm -rf "$scratch"' EXIT +fi +OLIPHAUNT_ATTESTATION_VERIFICATION_DIR="$scratch" +export OLIPHAUNT_ATTESTATION_VERIFICATION_DIR +case "${1:-}" in + pre-mutation) native --prepare-bundles "$scratch" "${@:2}" ;; + --verify-prepared) ;; + *) bash tools/release/with-release-tags.sh bash tools/dev/bun.sh tools/release/verify_github_release_attestations.mts --prepare-public "$scratch" "$@" ;; +esac +bounded="$(command -v timeout || command -v gtimeout)" +for subject in "$scratch"/*.subject; do + [[ -f "$subject" ]] || continue + { IFS= read -r -d '' file; IFS= read -r -d '' bundle; IFS= read -r -d '' head; IFS= read -r -d '' repo; } < "$subject" + rm -f "${subject%.subject}.json" + ( + ulimit -f 65536 || exit $? + "$bounded" --kill-after=5s 300s gh attestation verify "$file" --repo "$repo" --bundle "$bundle" \ + --format json --predicate-type https://slsa.dev/provenance/v1 \ + --signer-workflow "$repo/.github/workflows/release.yml" --signer-digest "$head" \ + --source-ref refs/heads/main --source-digest "$head" --deny-self-hosted-runners \ + > "${subject%.subject}.tmp" + ) || exit $? + mv "${subject%.subject}.tmp" "${subject%.subject}.json" +done +for record in "$scratch"/*/*.public; do + [[ -f "$record" ]] || continue + { IFS= read -r -d '' repo; IFS= read -r -d '' tag; IFS= read -r -d '' asset; IFS= read -r -d '' file; } < "$record" + "$bounded" --kill-after=5s 600s gh release download "$tag" --repo "$repo" --pattern "$asset" --dir "$(dirname "$file")" + "$bounded" --kill-after=5s 300s gh attestation verify "$file" --repo "$repo" \ + --signer-workflow "$repo/.github/workflows/release.yml" --source-ref refs/heads/main --deny-self-hosted-runners +done +if [[ "${1:-}" == pre-mutation ]]; then native "$@"; fi diff --git a/tools/release/verify-github-release-http.test.mjs b/tools/release/verify-github-release-http.test.mjs deleted file mode 100644 index fbbb05fb7..000000000 --- a/tools/release/verify-github-release-http.test.mjs +++ /dev/null @@ -1,99 +0,0 @@ -import { createHash } from "node:crypto"; -import { describe, expect, test } from "bun:test"; - -import { - assertExactReleaseAssetNames, - requestBoundedGithubJson, - requestReleaseAssetProof, - requestReleaseControlBytes, -} from "./verify_github_release_attestations.mjs"; - -describe("GitHub release HTTP boundaries", () => { - test("rejects unexpected assets for a non-extension release", () => { - expect(() => assertExactReleaseAssetNames({ - product: "liboliphaunt-native", - tag: "liboliphaunt-native-v1.2.3", - expectedNames: ["liboliphaunt-1.2.3-runtime-resources-ios-datum64.tar.gz"], - actualNames: [ - "liboliphaunt-1.2.3-runtime-resources-ios-datum64.tar.gz", - "stale-unlocked-binary.tar.gz", - ], - })).toThrow( - "liboliphaunt-native GitHub release liboliphaunt-native-v1.2.3 asset set mismatch " + - "(unexpected: stale-unlocked-binary.tar.gz)", - ); - }); - - test("bounds and times the release metadata request without redirects", async () => { - let request; - const value = await requestBoundedGithubJson("https://api.github.com/repos/f0rr0/oliphaunt/releases/tags/test", { - fetchImpl: async (url, options) => { - request = { url, options }; - return Response.json({ assets: [] }); - }, - timeoutMs: 1_000, - }); - expect(value).toEqual({ assets: [] }); - expect(request.options.redirect).toBe("error"); - expect(request.options.signal).toBeInstanceOf(AbortSignal); - }); - - test("rejects oversized release metadata before JSON parsing", async () => { - await expect(requestBoundedGithubJson("https://api.github.com/repos/f0rr0/oliphaunt/releases/tags/test", { - fetchImpl: async () => new Response("{}", { - headers: { "content-length": String(8 * 1024 * 1024 + 1) }, - }), - })).rejects.toThrow("GitHub API response exceeds 8388608 bytes"); - }); - - test("streams an asset into an exact size and sha256 proof", async () => { - const bytes = Buffer.from("exact release asset bytes\n"); - let request; - const proof = await requestReleaseAssetProof( - "https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1", - "asset.tar.zst", - bytes.length, - { - fetchImpl: async (url, options) => { - request = { url, options }; - return new Response(bytes); - }, - timeoutMs: 1_000, - }, - ); - expect(proof).toEqual({ - bytes: bytes.length, - sha256: createHash("sha256").update(bytes).digest("hex"), - }); - expect(request.options.redirect).toBe("follow"); - expect(request.options.signal).toBeInstanceOf(AbortSignal); - }); - - test("rejects size mismatches before buffering or hashing an unbounded asset", async () => { - await expect(requestReleaseAssetProof( - "https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1", - "asset.tar.zst", - 4, - { - fetchImpl: async () => new Response("x", { - headers: { "content-length": "5" }, - }), - }, - )).rejects.toThrow("Content-Length 5 does not match expected size 4"); - }); - - test("caps control manifests and rejects asset URLs outside the GitHub API origin", async () => { - await expect(requestReleaseControlBytes( - "https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1", - "manifest.json", - 8 * 1024 * 1024 + 1, - { fetchImpl: async () => new Response("{}") }, - )).rejects.toThrow("invalid size"); - await expect(requestReleaseAssetProof( - "https://attacker.invalid/releases/assets/1", - "asset.tar.zst", - 1, - { fetchImpl: async () => new Response("x") }, - )).rejects.toThrow("must use https://api.github.com"); - }); -}); diff --git a/tools/release/verify-github-release-http.test.mts b/tools/release/verify-github-release-http.test.mts new file mode 100644 index 000000000..e1f7c5257 --- /dev/null +++ b/tools/release/verify-github-release-http.test.mts @@ -0,0 +1,111 @@ +import { createHash } from 'node:crypto'; +import { describe, expect, test } from 'bun:test'; + +import { + assertExactReleaseAssetNames, + requestBoundedGithubJson, + requestReleaseAssetProof, + requestReleaseControlBytes, +} from './verify_github_release_attestations.mts'; + +describe('GitHub release HTTP boundaries', () => { + test('rejects unexpected assets for a non-extension release', () => { + expect(() => + assertExactReleaseAssetNames({ + product: 'liboliphaunt-native', + tag: 'liboliphaunt-native-v1.2.3', + expectedNames: ['liboliphaunt-1.2.3-runtime-resources-ios-datum64.tar.gz'], + actualNames: [ + 'liboliphaunt-1.2.3-runtime-resources-ios-datum64.tar.gz', + 'stale-unlocked-binary.tar.gz', + ], + }), + ).toThrow( + 'liboliphaunt-native GitHub release liboliphaunt-native-v1.2.3 asset set mismatch ' + + '(unexpected: stale-unlocked-binary.tar.gz)', + ); + }); + + test('bounds and times the release metadata request without redirects', async () => { + let request; + const value = await requestBoundedGithubJson( + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/tags/test', + { + fetchImpl: async (url, options) => { + request = { url, options }; + return Response.json({ assets: [] }); + }, + timeoutMs: 1_000, + }, + ); + expect(value).toEqual({ assets: [] }); + expect(request.options.redirect).toBe('error'); + expect(request.options.signal).toBeInstanceOf(AbortSignal); + }); + + test('rejects oversized release metadata before JSON parsing', async () => { + await expect( + requestBoundedGithubJson('https://api.github.com/repos/f0rr0/oliphaunt/releases/tags/test', { + fetchImpl: async () => + new Response('{}', { + headers: { 'content-length': String(8 * 1024 * 1024 + 1) }, + }), + }), + ).rejects.toThrow('GitHub API response exceeds 8388608 bytes'); + }); + + test('streams an asset into an exact size and sha256 proof', async () => { + const bytes = Buffer.from('exact release asset bytes\n'); + let request; + const proof = await requestReleaseAssetProof( + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + 'asset.tar.zst', + bytes.length, + { + fetchImpl: async (url, options) => { + request = { url, options }; + return new Response(bytes); + }, + timeoutMs: 1_000, + }, + ); + expect(proof).toEqual({ + bytes: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }); + expect(request.options.redirect).toBe('follow'); + expect(request.options.signal).toBeInstanceOf(AbortSignal); + }); + + test('rejects size mismatches before buffering or hashing an unbounded asset', async () => { + await expect( + requestReleaseAssetProof( + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + 'asset.tar.zst', + 4, + { + fetchImpl: async () => + new Response('x', { + headers: { 'content-length': '5' }, + }), + }, + ), + ).rejects.toThrow('Content-Length 5 does not match expected size 4'); + }); + + test('caps control manifests and rejects asset URLs outside the GitHub API origin', async () => { + await expect( + requestReleaseControlBytes( + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + 'manifest.json', + 8 * 1024 * 1024 + 1, + { fetchImpl: async () => new Response('{}') }, + ), + ).rejects.toThrow('invalid size'); + await expect( + requestReleaseAssetProof('https://attacker.invalid/releases/assets/1', 'asset.tar.zst', 1, { + fetchImpl: async () => new Response('x'), + }), + ).rejects.toThrow('must use https://api.github.com'); + }); +}); diff --git a/tools/release/verify-maven-signing-readiness.mjs b/tools/release/verify-maven-signing-readiness.mjs deleted file mode 100644 index 0501e2c29..000000000 --- a/tools/release/verify-maven-signing-readiness.mjs +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env bun - -import { mkdtempSync, rmSync } from "node:fs"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { - inspectArmoredPublicKeyFingerprints, - verifyGpgSigningCredentials, -} from "./frozen-maven-publish.mjs"; - -const TOOL = "verify-maven-signing-readiness"; -const MAX_PUBLIC_KEY_BYTES = 1024 * 1024; -const SUPPORTED_KEY_SERVERS = [ - { - name: "keyserver.ubuntu.com", - url: (fingerprint) => `https://keyserver.ubuntu.com/pks/lookup?op=get&options=mr&search=0x${fingerprint}`, - }, - { - name: "keys.openpgp.org", - url: (fingerprint) => `https://keys.openpgp.org/vks/v1/by-fingerprint/${fingerprint}`, - }, - { - name: "pgp.mit.edu", - url: (fingerprint) => `https://pgp.mit.edu/pks/lookup?op=get&options=mr&search=0x${fingerprint}`, - }, -]; - -function requiredEnvironment(name) { - const value = process.env[name]; - if (typeof value !== "string" || value.length === 0) { - throw new Error(`${name} is required`); - } - return value; -} - -async function boundedResponseText(response, context) { - const declared = response.headers.get("content-length"); - if (declared !== null) { - const length = Number(declared); - if (!Number.isSafeInteger(length) || length < 0 || length > MAX_PUBLIC_KEY_BYTES) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`${context} returned an invalid or oversized Content-Length`); - } - } - const reader = response.body?.getReader?.(); - if (reader === undefined) { - const bytes = Buffer.from(await response.arrayBuffer()); - if (bytes.byteLength > MAX_PUBLIC_KEY_BYTES) { - throw new Error(`${context} exceeded ${MAX_PUBLIC_KEY_BYTES} bytes`); - } - return bytes.toString("utf8"); - } - const chunks = []; - let size = 0; - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > MAX_PUBLIC_KEY_BYTES) { - await reader.cancel().catch(() => {}); - throw new Error(`${context} exceeded ${MAX_PUBLIC_KEY_BYTES} bytes`); - } - chunks.push(Buffer.from(value)); - } - } finally { - reader.releaseLock(); - } - return Buffer.concat(chunks, size).toString("utf8"); -} - -export async function verifyPublishedMavenSigningKey( - fingerprint, - { - fetchImpl = fetch, - inspectImpl, - keyServers = SUPPORTED_KEY_SERVERS, - } = {}, -) { - const normalized = String(fingerprint).toUpperCase(); - if (!/^(?:[0-9A-F]{40}|[0-9A-F]{64})$/u.test(normalized)) { - throw new Error("primary Maven signing fingerprint must be 40 or 64 hexadecimal characters"); - } - if (typeof inspectImpl !== "function") { - throw new TypeError("inspectImpl is required"); - } - const failures = []; - for (const server of keyServers) { - try { - const response = await fetchImpl(server.url(normalized), { - headers: { - Accept: "application/pgp-keys, application/octet-stream;q=0.9, text/plain;q=0.8", - "User-Agent": "oliphaunt-maven-signing-readiness/1; https://github.com/f0rr0/oliphaunt", - }, - redirect: "error", - signal: AbortSignal.timeout(15_000), - }); - if (!response.ok) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`HTTP ${response.status}`); - } - const armoredKey = await boundedResponseText(response, server.name); - const publishedFingerprints = inspectImpl(armoredKey); - if (!publishedFingerprints.includes(normalized)) { - throw new Error(`response did not contain primary fingerprint ${normalized}`); - } - return { fingerprint: normalized, server: server.name }; - } catch (error) { - failures.push(`${server.name}: ${error instanceof Error ? error.message : String(error)}`); - } - } - throw new Error( - `primary Maven signing key ${normalized} is not verifiably published on a Central-supported keyserver (${failures.join("; ")})`, - ); -} - -async function main() { - const temporaryRoot = process.env.RUNNER_TEMP || tmpdir(); - const home = mkdtempSync(path.join(temporaryRoot, "oliphaunt-maven-signing-preflight-")); - try { - const result = verifyGpgSigningCredentials({ - privateKey: requiredEnvironment("ORG_GRADLE_PROJECT_signingInMemoryKey"), - keyId: requiredEnvironment("ORG_GRADLE_PROJECT_signingInMemoryKeyId"), - passphrase: requiredEnvironment("ORG_GRADLE_PROJECT_signingInMemoryKeyPassword"), - home, - }); - const publication = await verifyPublishedMavenSigningKey(result.primaryFingerprint, { - inspectImpl: (armoredKey) => inspectArmoredPublicKeyFingerprints({ armoredKey, home }), - }); - console.log( - `${TOOL}: imported, primary-key signed, locally verified, and found OpenPGP fingerprint ${result.primaryFingerprint} on ${publication.server}`, - ); - } finally { - rmSync(home, { recursive: true, force: true }); - } -} - -if (import.meta.main) { - try { - await main(); - } catch (error) { - console.error(`${TOOL}: ${error instanceof Error ? error.message : String(error)}`); - process.exitCode = 1; - } -} diff --git a/tools/release/verify-maven-signing-readiness.mts b/tools/release/verify-maven-signing-readiness.mts new file mode 100644 index 000000000..11647a4db --- /dev/null +++ b/tools/release/verify-maven-signing-readiness.mts @@ -0,0 +1,98 @@ +import { readFileSync } from 'node:fs'; + +function error(message) { + return new Error('Maven signing: ' + message); +} + +export function normalizedGpgKeyId(keyId) { + if (typeof keyId !== 'string') { + throw error('Maven signing key ID must be a hexadecimal OpenPGP key ID or fingerprint'); + } + const normalized = keyId.trim().replace(/^0x/iu, '').toUpperCase(); + if (!/^[0-9A-F]{8,64}$/u.test(normalized)) { + throw error( + 'Maven signing key ID must be 8-64 hexadecimal characters, optionally prefixed by 0x', + ); + } + return normalized; +} + +export function verifySigningStatus(status, keyId) { + const signingKeyId = normalizedGpgKeyId(keyId); + const validSignatures = status + .split(/\r?\n/u) + .filter((line) => line.startsWith('[GNUPG:] VALIDSIG ')); + if (validSignatures.length !== 1) { + throw error( + `Maven signing preflight expected one valid signature, got ${validSignatures.length}`, + ); + } + const fingerprints = validSignatures[0] + .trim() + .split(/\s+/u) + .filter((field) => /^(?:[0-9A-F]{40}|[0-9A-F]{64})$/iu.test(field)) + .map((field) => field.toUpperCase()); + if (fingerprints.length === 0) { + throw error('Maven signing preflight did not report a valid signature fingerprint'); + } + const signerFingerprint = fingerprints[0]; + const primaryFingerprint = fingerprints.length > 1 ? fingerprints.at(-1) : signerFingerprint; + if (signerFingerprint !== primaryFingerprint) { + throw error( + 'Maven Central requires artifacts to be signed by the primary OpenPGP key, not a signing subkey', + ); + } + if (!primaryFingerprint.endsWith(signingKeyId)) { + throw error( + 'configured Maven signing key ID does not match the verified signature fingerprint', + ); + } + return { + signerFingerprint, + primaryFingerprint, + }; +} + +export function publicKeyFingerprints(listing) { + const primaryFingerprints = []; + let awaitingPrimaryFingerprint = false; + for (const line of listing.split(/\r?\n/u)) { + const fields = line.split(':'); + if (fields[0] === 'pub') { + awaitingPrimaryFingerprint = true; + continue; + } + if (fields[0] === 'sub') { + awaitingPrimaryFingerprint = false; + continue; + } + if (fields[0] === 'fpr' && awaitingPrimaryFingerprint) { + const fingerprint = fields[9]?.toUpperCase() ?? ''; + if (!/^(?:[0-9A-F]{40}|[0-9A-F]{64})$/u.test(fingerprint)) { + throw error('published Maven signing key reported an invalid primary fingerprint'); + } + primaryFingerprints.push(fingerprint); + awaitingPrimaryFingerprint = false; + } + } + if (primaryFingerprints.length === 0) { + throw error('published Maven signing key did not contain a primary OpenPGP fingerprint'); + } + return primaryFingerprints; +} + +if (import.meta.main) { + try { + const [phase, file, key] = process.argv.slice(2); + if (phase === '--key-id') console.log(normalizedGpgKeyId(file)); + else if (phase === '--signature') + console.log(verifySigningStatus(readFileSync(file, 'utf8'), key).primaryFingerprint); + else if (phase === '--public-key') { + if (!publicKeyFingerprints(readFileSync(file, 'utf8')).includes(key)) + throw error('keyserver response did not contain the exact primary fingerprint'); + } else throw error('unknown signing data phase'); + } catch (cause) { + console.error(cause.message); + process.exitCode = 1; + } +} diff --git a/tools/release/verify-maven-signing-readiness.sh b/tools/release/verify-maven-signing-readiness.sh new file mode 100644 index 000000000..e9b736da7 --- /dev/null +++ b/tools/release/verify-maven-signing-readiness.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$root" +: "${ORG_GRADLE_PROJECT_signingInMemoryKey:?Maven signing key is required}" +: "${ORG_GRADLE_PROJECT_signingInMemoryKeyId:?Maven signing key ID is required}" +: "${ORG_GRADLE_PROJECT_signingInMemoryKeyPassword:?Maven signing passphrase is required}" +data() { bash tools/dev/bun.sh tools/release/verify-maven-signing-readiness.mts "$@"; } +key_id="$(data --key-id "$ORG_GRADLE_PROJECT_signingInMemoryKeyId")" +work="$(mktemp -d "${RUNNER_TEMP:-${TMPDIR:-/tmp}}/oliphaunt-maven-signing.XXXXXX")" +trap 'gpgconf --homedir "$work" --kill all >/dev/null 2>&1 || true; rm -rf "$work"' EXIT +chmod 700 "$work" +printf '%s' "$ORG_GRADLE_PROJECT_signingInMemoryKey" | gpg --batch --homedir "$work" --import +printf 'oliphaunt Maven signing readiness preflight\n' > "$work/payload" +printf '%s\n' "$ORG_GRADLE_PROJECT_signingInMemoryKeyPassword" | \ + gpg --batch --yes --no-tty --pinentry-mode loopback --passphrase-fd 0 --homedir "$work" \ + --local-user "$key_id" --armor --detach-sign --output "$work/payload.asc" "$work/payload" +gpg --batch --no-auto-key-retrieve --homedir "$work" --status-fd 1 \ + --verify "$work/payload.asc" "$work/payload" > "$work/status" +fingerprint="$(data --signature "$work/status" "$key_id")" +for server in keyserver.ubuntu.com keys.openpgp.org pgp.mit.edu; do + if [[ "$server" == keys.openpgp.org ]]; then + url="https://$server/vks/v1/by-fingerprint/$fingerprint" + else + url="https://$server/pks/lookup?op=get&options=mr&search=0x$fingerprint" + fi + if curl --fail --silent --show-error --max-time 15 --max-filesize 1048576 \ + --proto '=https' -H 'Accept: application/pgp-keys, application/octet-stream;q=0.9, text/plain;q=0.8' \ + --user-agent 'oliphaunt-maven-signing-readiness/1; https://github.com/f0rr0/oliphaunt' \ + --output "$work/public.asc" "$url" && + gpg --batch --homedir "$work" --with-colons --import-options show-only \ + --import < "$work/public.asc" > "$work/public-listing" && + data --public-key "$work/public-listing" "$fingerprint"; then + echo "Verified primary Maven signing key $fingerprint locally and on $server" + exit 0 + fi +done +echo "Primary Maven signing key $fingerprint is not verifiably published on a Central-supported keyserver" >&2 +exit 1 diff --git a/tools/release/verify-maven-signing-readiness.test.mjs b/tools/release/verify-maven-signing-readiness.test.mjs deleted file mode 100644 index c943c4a18..000000000 --- a/tools/release/verify-maven-signing-readiness.test.mjs +++ /dev/null @@ -1,51 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { verifyPublishedMavenSigningKey } from "./verify-maven-signing-readiness.mjs"; - -const FINGERPRINT = "A".repeat(40); -const SERVERS = [ - { name: "first.invalid", url: () => "https://first.invalid/key" }, - { name: "second.invalid", url: () => "https://second.invalid/key" }, -]; - -describe("Maven signing key publication readiness", () => { - test("accepts the exact primary fingerprint from a fallback supported keyserver", async () => { - const calls = []; - const result = await verifyPublishedMavenSigningKey(FINGERPRINT, { - keyServers: SERVERS, - fetchImpl: async (url) => { - calls.push(url); - return url.includes("first") - ? new Response("missing", { status: 404 }) - : new Response("armored public key", { status: 200 }); - }, - inspectImpl: () => [FINGERPRINT], - }); - expect(result).toEqual({ fingerprint: FINGERPRINT, server: "second.invalid" }); - expect(calls).toEqual(["https://first.invalid/key", "https://second.invalid/key"]); - }); - - test("rejects keyserver content for a different primary fingerprint", async () => { - await expect(verifyPublishedMavenSigningKey(FINGERPRINT, { - keyServers: SERVERS, - fetchImpl: async () => new Response("armored public key", { status: 200 }), - inspectImpl: () => ["B".repeat(40)], - })).rejects.toThrow("is not verifiably published on a Central-supported keyserver"); - }); - - test("rejects oversized keyserver responses before OpenPGP inspection", async () => { - let inspected = false; - await expect(verifyPublishedMavenSigningKey(FINGERPRINT, { - keyServers: [SERVERS[0]], - fetchImpl: async () => new Response("x", { - status: 200, - headers: { "content-length": String(1024 * 1024 + 1) }, - }), - inspectImpl: () => { - inspected = true; - return [FINGERPRINT]; - }, - })).rejects.toThrow("is not verifiably published on a Central-supported keyserver"); - expect(inspected).toBe(false); - }); -}); diff --git a/tools/release/verify-maven-signing-readiness.test.mts b/tools/release/verify-maven-signing-readiness.test.mts new file mode 100644 index 000000000..f3c754793 --- /dev/null +++ b/tools/release/verify-maven-signing-readiness.test.mts @@ -0,0 +1,32 @@ +import { expect, test } from 'bun:test'; +import { + normalizedGpgKeyId, + publicKeyFingerprints, + verifySigningStatus, +} from './verify-maven-signing-readiness.mts'; + +const primary = 'A'.repeat(40); +const subkey = 'B'.repeat(40); +test('Maven fingerprints require an exact primary signing key and matching public key', () => { + const status = (signer, owner = signer) => + `[GNUPG:] VALIDSIG ${signer} 2026-07-20 0 4 0 1 10 00 ${owner}\n`; + expect(verifySigningStatus(status(primary), '0x' + primary.slice(-16)).primaryFingerprint).toBe( + primary, + ); + expect(() => verifySigningStatus(status(primary), subkey)).toThrow('does not match'); + expect(() => verifySigningStatus(status(subkey, primary), primary)).toThrow( + 'primary OpenPGP key', + ); + expect(() => verifySigningStatus(status(primary) + status(primary), primary)).toThrow( + 'expected one', + ); + expect(() => normalizedGpgKeyId('release@example.invalid')).toThrow('8-64 hexadecimal'); + expect( + publicKeyFingerprints( + `pub:::::::::\nfpr:::::::::${primary}:\nsub:::::::::\nfpr:::::::::${subkey}:\n`, + ), + ).toEqual([primary]); + expect(() => publicKeyFingerprints('pub:::::::::\nfpr:::::::::bad:\n')).toThrow( + 'invalid primary', + ); +}); diff --git a/tools/release/verify-maven-signing-readiness.test.sh b/tools/release/verify-maven-signing-readiness.test.sh new file mode 100644 index 000000000..19ebd4531 --- /dev/null +++ b/tools/release/verify-maven-signing-readiness.test.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" +bun test ./tools/release/verify-maven-signing-readiness.test.mts +scratch="$(mktemp -d)" +cleanup() { + gpgconf --homedir "$scratch/keys" --kill all >/dev/null 2>&1 || true + rm -rf "$scratch" +} +trap cleanup EXIT +mkdir -m 700 "$scratch/keys" +mkdir "$scratch/bin" "$scratch/runs" +gpg_fixture() { gpg --batch --homedir "$scratch/keys" "$@"; } +passphrase='fixture password' +printf '%s\n' "$passphrase" | gpg_fixture --pinentry-mode loopback --passphrase-fd 0 \ + --quick-generate-key 'Maven fixture ' ed25519 sign 0 +gpg_fixture --with-colons --list-keys > "$scratch/key-list" +fingerprint="$(bun -e 'import {readFileSync} from "node:fs"; import {publicKeyFingerprints} from "./tools/release/verify-maven-signing-readiness.mts"; console.log(publicKeyFingerprints(readFileSync(process.argv[1],"utf8"))[0])' "$scratch/key-list")" +export ORG_GRADLE_PROJECT_signingInMemoryKey +ORG_GRADLE_PROJECT_signingInMemoryKey="$(printf '%s\n' "$passphrase" | gpg_fixture \ + --pinentry-mode loopback --passphrase-fd 0 --armor --export-secret-keys "$fingerprint")" +gpg_fixture --armor --export "$fingerprint" > "$scratch/public.asc" +cat > "$scratch/bin/curl" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +output='' timeout='' limit='' +while [[ $# -gt 0 ]]; do + case "$1" in + --output) output="$2"; shift 2 ;; + --max-time) timeout="$2"; shift 2 ;; + --max-filesize) limit="$2"; shift 2 ;; + *) url="$1"; shift ;; + esac +done +[[ "$timeout" == 15 && "$limit" == 1048576 ]] || exit 99 +printf '%s\n' "$url" >> "$MAVEN_CURL_LOG" +[[ "$url" != *keyserver.ubuntu.com* ]] || exit 22 +[[ "${MAVEN_BAD_KEY:-}" != true ]] || { echo 'wrong public key' > "$output"; exit 0; } +cp "$MAVEN_PUBLIC_KEY" "$output" +SH +chmod +x "$scratch/bin/curl" +export PATH="$scratch/bin:$PATH" RUNNER_TEMP="$scratch/runs" +export MAVEN_CURL_LOG="$scratch/requests" MAVEN_PUBLIC_KEY="$scratch/public.asc" +export ORG_GRADLE_PROJECT_signingInMemoryKeyId="$fingerprint" +export ORG_GRADLE_PROJECT_signingInMemoryKeyPassword="$passphrase" +bash tools/release/verify-maven-signing-readiness.sh > "$scratch/result" 2>&1 +rg -q -F "$fingerprint" "$scratch/result" +rg -q -F keys.openpgp.org "$scratch/result" +[[ -z "$(ls -A "$scratch/runs")" ]] +[[ "$(wc -l < "$scratch/requests")" -eq 2 ]] +if MAVEN_BAD_KEY=true bash tools/release/verify-maven-signing-readiness.sh > "$scratch/result" 2>&1; then + echo 'Invalid public signing key accepted' >&2; exit 1 +fi +rg -q 'not verifiably published' "$scratch/result" +[[ -z "$(ls -A "$scratch/runs")" ]] +cp "$scratch/requests" "$scratch/before" +if ORG_GRADLE_PROJECT_signingInMemoryKeyPassword=wrong bash tools/release/verify-maven-signing-readiness.sh > "$scratch/result" 2>&1; then + echo 'Invalid private key password accepted' >&2; exit 1 +fi +cmp "$scratch/before" "$scratch/requests" +[[ -z "$(ls -A "$scratch/runs")" ]] +echo 'Maven signing: real signature, keyserver fallback, invalid keys and cleanup passed' diff --git a/tools/release/verify-native-extension-lifecycle-receipts.mjs b/tools/release/verify-native-extension-lifecycle-receipts.mjs deleted file mode 100644 index 6066f089f..000000000 --- a/tools/release/verify-native-extension-lifecycle-receipts.mjs +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { lstatSync, readFileSync, readdirSync, writeFileSync } from "node:fs"; -import path from "node:path"; - -import { compareText, exactExtensionProducts, extensionSqlNames } from "./release-artifact-targets.mjs"; - -function fail(message) { - throw new Error(`verify-native-extension-lifecycle-receipts.mjs: ${message}`); -} - -function flags(argv) { - const values = {}; - for (let index = 0; index < argv.length; index += 2) { - const name = argv[index]; - const value = argv[index + 1]; - if (!name?.startsWith("--") || value === undefined) fail(`invalid argument ${name ?? ""}`); - values[name.slice(2)] = value; - } - for (const name of [ - "receipts", - "candidate-sha", - "candidate-tree", - "expected-extensions-csv", - "expected-shard-count", - "output", - ]) { - if (values[name] === undefined) fail(`--${name} is required`); - } - return values; -} - -function sha256(value) { - return createHash("sha256").update(value).digest("hex"); -} - -function assertConsumedArtifacts(artifacts, extensions, shardIndex) { - const expectedIdentities = [ - "broker", - "broker-checksum", - "native-extension-index", - "native-extension-legacy-index", - "native-extension-proof-runner", - "native-runtime", - "native-tools", - ...extensions.map((name) => `native-extension:${name}`), - ].sort(compareText); - if (!Array.isArray(artifacts) || artifacts.length !== expectedIdentities.length) { - fail(`shard ${shardIndex} consumed artifact count drift`); - } - if (artifacts.map((artifact) => artifact?.identity).join("\0") !== expectedIdentities.join("\0")) { - fail(`shard ${shardIndex} consumed artifact identities are incomplete or unsorted`); - } - for (const artifact of artifacts) { - if ( - typeof artifact.file !== "string" - || artifact.file.length === 0 - || artifact.file.includes("/") - || artifact.file.includes("\\") - || !Number.isSafeInteger(artifact.bytes) - || artifact.bytes <= 0 - || !/^[0-9a-f]{64}$/u.test(artifact.sha256) - ) fail(`shard ${shardIndex} consumed artifact ${String(artifact.identity)} lacks SHA-256 and byte evidence`); - } -} - -function receiptFiles(root) { - const files = []; - const visit = (directory) => { - for (const entry of readdirSync(directory, { withFileTypes: true })) { - const file = path.join(directory, entry.name); - if (lstatSync(file).isSymbolicLink()) fail(`receipt input contains symbolic link ${file}`); - if (entry.isDirectory()) visit(file); - else if (entry.isFile() && /^receipt-shard-\d+\.json$/u.test(entry.name)) files.push(file); - } - }; - visit(root); - return files.sort(compareText); -} - -export function verifyReceipts(options) { - if (!/^[0-9a-f]{40}$/u.test(options["candidate-sha"]) || !/^[0-9a-f]{40}$/u.test(options["candidate-tree"])) { - fail("candidate SHA and tree must be full 40-character Git object IDs"); - } - const canonical = exactExtensionProducts("native-extension-lifecycle-receipts") - .flatMap((product) => extensionSqlNames(product, "native-extension-lifecycle-receipts")) - .sort(compareText); - if (canonical.length === 0 || new Set(canonical).size !== canonical.length) { - fail("canonical release graph must resolve to a nonempty unique extension set"); - } - const expected = options["expected-extensions-csv"].split(",").filter(Boolean).sort(compareText); - const canonicalSet = new Set(canonical); - if ( - expected.length === 0 - || new Set(expected).size !== expected.length - || expected.some((name) => !canonicalSet.has(name)) - ) fail("expected extension set must be a nonempty unique canonical release-graph subset"); - const expectedShardCount = Number(options["expected-shard-count"]); - if (!Number.isInteger(expectedShardCount) || expectedShardCount < 1 || expectedShardCount > expected.length) { - fail("expected shard count must be a positive integer no greater than the planned extension count"); - } - const files = receiptFiles(options.receipts); - if (files.length !== expectedShardCount) { - fail(`expected exactly ${expectedShardCount} shard receipts, found ${files.length}`); - } - const receipts = files.map((file) => ({ file, receipt: JSON.parse(readFileSync(file, "utf8")) })); - - const seenShards = new Set(); - const seenExtensions = new Set(); - const inputDigests = new Set(); - let consumedArtifacts; - for (const { file, receipt } of receipts) { - const { receiptSha256, ...core } = receipt; - if (receiptSha256 !== sha256(JSON.stringify(core))) fail(`shard ${receipt.shardIndex} receipt digest mismatch`); - if (receipt.schema !== "oliphaunt-native-extension-lifecycle-shard-receipt-v1") fail("unknown shard receipt schema"); - if (receipt.candidateSha !== options["candidate-sha"] || receipt.candidateTree !== options["candidate-tree"]) { - fail(`shard ${receipt.shardIndex} candidate identity mismatch`); - } - if ( - receipt.target !== "linux-x64-gnu" - || receipt.shardCount !== expectedShardCount - || !Number.isInteger(receipt.shardIndex) - || receipt.shardIndex < 0 - || receipt.shardIndex >= expectedShardCount - ) { - fail("receipt has non-canonical target or shard identity"); - } - if (path.basename(file) !== `receipt-shard-${receipt.shardIndex}.json`) { - fail(`receipt filename does not match shard identity ${receipt.shardIndex}`); - } - if (seenShards.has(receipt.shardIndex)) fail(`duplicate shard receipt ${receipt.shardIndex}`); - seenShards.add(receipt.shardIndex); - if (!/^[0-9a-f]{64}$/u.test(receipt.inputEnvelopeSha256) || !/^[0-9a-f]{64}$/u.test(receipt.proofLogSha256)) { - fail(`shard ${receipt.shardIndex} lacks input-envelope or proof-log SHA-256 evidence`); - } - inputDigests.add(receipt.inputEnvelopeSha256); - assertConsumedArtifacts(receipt.consumedArtifacts, expected, receipt.shardIndex); - const artifactJson = JSON.stringify(receipt.consumedArtifacts); - if (consumedArtifacts === undefined) consumedArtifacts = artifactJson; - else if (consumedArtifacts !== artifactJson) fail("shard receipts consumed different artifact envelopes"); - if (receipt.modes.join(",") !== "direct,broker,server" || receipt.lifecycle.join(",") !== "install,load,restart,backup,restore") { - fail(`shard ${receipt.shardIndex} has incomplete modes or lifecycle`); - } - const expectedShardExtensions = expected.filter((_, index) => index % expectedShardCount === receipt.shardIndex); - if ( - receipt.plannedExtensionCount !== expected.length - || receipt.extensionCount !== expectedShardExtensions.length - || !Array.isArray(receipt.extensions) - || receipt.extensions.join("\0") !== expectedShardExtensions.join("\0") - || !Array.isArray(receipt.passRecords) - || receipt.passRecords.length !== expectedShardExtensions.length - ) { - fail(`shard ${receipt.shardIndex} PASS record count drift`); - } - for (const [index, record] of receipt.passRecords.entries()) { - if ( - record.shardIndex !== receipt.shardIndex - || record.shardCount !== expectedShardCount - || record.extension !== expectedShardExtensions[index] - || record.modes?.join(",") !== "direct,broker,server" - || record.lifecycle?.join(",") !== "install,load,restart,backup,restore" - ) fail(`shard ${receipt.shardIndex} has a malformed or misordered extension PASS record`); - } - for (const extension of receipt.extensions) { - if (seenExtensions.has(extension)) fail(`extension ${extension} appears in multiple shard receipts`); - seenExtensions.add(extension); - } - } - if (seenShards.size !== expectedShardCount || inputDigests.size !== 1) { - fail("shard receipts do not form one complete artifact-bound run"); - } - const actual = [...seenExtensions].sort(compareText); - if (actual.length !== expected.length || actual.join("\0") !== expected.join("\0")) { - fail(`aggregate extension coverage drift: expected=${expected.join(",")}; actual=${actual.join(",")}`); - } - const aggregateCore = { - schema: "oliphaunt-native-extension-lifecycle-aggregate-v1", - candidateSha: options["candidate-sha"], - candidateTree: options["candidate-tree"], - target: "linux-x64-gnu", - shardCount: expectedShardCount, - extensionCount: expected.length, - extensions: expected, - modes: ["direct", "broker", "server"], - lifecycle: ["install", "load", "restart", "backup", "restore"], - inputEnvelopeSha256: [...inputDigests][0], - consumedArtifacts: JSON.parse(consumedArtifacts), - shardReceipts: receipts - .map(({ receipt }) => ({ shardIndex: receipt.shardIndex, receiptSha256: receipt.receiptSha256 })) - .sort((left, right) => left.shardIndex - right.shardIndex), - }; - const aggregate = { ...aggregateCore, aggregateSha256: sha256(JSON.stringify(aggregateCore)) }; - writeFileSync(options.output, `${JSON.stringify(aggregate, null, 2)}\n`); - console.log(`native extension lifecycle aggregate verified: ${options.output}`); -} - -if (import.meta.main) { - try { - verifyReceipts(flags(Bun.argv.slice(2))); - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(1); - } -} diff --git a/tools/release/verify-product-tags.sh b/tools/release/verify-product-tags.sh new file mode 100644 index 000000000..2a79bf6cf --- /dev/null +++ b/tools/release/verify-product-tags.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -euo pipefail +helper="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/product-tags.mts" +allow_missing=false +target="${GITHUB_SHA:-HEAD}" +products=() +while [ "$#" -gt 0 ]; do + case "$1" in + --allow-missing) allow_missing=true; shift ;; + --target) target="${2:?--target requires a commit}"; shift 2 ;; + --products-json) + # JSON remains data, including whitespace and shell metacharacters. + products_json="${2:?--products-json requires an array}" + shift 2 + ;; + --*) echo "unknown argument: $1" >&2; exit 2 ;; + *) products+=("$1"); shift ;; + esac +done +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +if [ -n "${products_json:-}" ]; then + [ "${#products[@]}" -eq 0 ] || { echo 'select products by name or JSON, not both' >&2; exit 2; } + bun "$helper" --products-json "$products_json" > "$scratch/tags" +else + bun "$helper" "${products[@]}" > "$scratch/tags" +fi +target_commit="$(git rev-parse --verify --end-of-options "$target^{commit}")" +remote=false +refs=() +while IFS= read -r tag; do refs+=("refs/tags/$tag"); done < "$scratch/tags" +if git remote get-url origin >/dev/null 2>&1; then + remote=true + git ls-remote --refs --tags origin "${refs[@]}" > "$scratch/remote" + awk '{print $2}' "$scratch/remote" > "$scratch/remote-refs" + fetch_refs=() + for ref in "${refs[@]}"; do + if grep -Fxq "$ref" "$scratch/remote-refs"; then fetch_refs+=("$ref:$ref"); fi + done + if [ "${#fetch_refs[@]}" -gt 0 ]; then git fetch --force --no-tags origin "${fetch_refs[@]}"; fi +fi +for ref in "${refs[@]}"; do + if { [ "$remote" = true ] && ! grep -Fxq "$ref" "$scratch/remote-refs"; } || + { [ "$remote" = false ] && ! git show-ref --verify --quiet "$ref"; }; then + [ "$allow_missing" = true ] || { echo "$ref does not exist; stage the exact-SHA draft release before publication" >&2; exit 1; } + echo "$ref is absent and available for exact-SHA release creation" + continue + fi + existing="$(git rev-parse --verify "$ref^{commit}")" + if [ "$existing" != "$target_commit" ]; then + echo "$ref points at $existing, not exact release commit $target_commit" >&2 + exit 1 + else + echo "$ref points at $target_commit" + fi +done diff --git a/tools/release/verify-product-tags.test.sh b/tools/release/verify-product-tags.test.sh new file mode 100644 index 000000000..d46d1226e --- /dev/null +++ b/tools/release/verify-product-tags.test.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail +verifier="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/verify-product-tags.sh" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +mkdir "$scratch/repo" +cd "$scratch/repo" +git init --quiet +git init --quiet --bare "$scratch/remote" +git config user.name Fixture +git config user.email fixture@example.invalid +git remote add origin "$scratch/remote" +cat > release-please-config.json <<'JSON' +{"include-v-in-tag":true,"tag-separator":"-","packages":{".":{"component":"fixture","release-type":"simple","version-file":"VERSION"}}} +JSON +printf '1.2.3\n' > VERSION +git add . +git commit --quiet -m fixture +release="$(git rev-parse HEAD)" +check() { bash "$verifier" --target HEAD "$@" > "$scratch/result" 2>&1; } +reject() { if check "$@"; then echo "Unexpected tag acceptance: $*" >&2; exit 1; fi; } +accept() { if ! check "$@"; then cat "$scratch/result" >&2; exit 1; fi; } +reject fixture +accept --allow-missing fixture +tag=fixture-v1.2.3 +git tag -a "$tag" -m release +reject fixture # A local tag cannot override remote absence. +git push --quiet origin "refs/tags/$tag" +accept --products-json '["fixture","fixture"]' +git commit --quiet --allow-empty -m next +reject --allow-missing fixture +git tag -f "$tag" >/dev/null +git push --quiet --force origin "refs/tags/$tag" +git tag -f "$tag" "$release" >/dev/null +accept fixture # Refresh a stale local tag from the remote. +[[ "$(git rev-parse "refs/tags/$tag")" == "$(git rev-parse HEAD)" ]] +git tag -f "$tag" "$(git rev-parse HEAD:VERSION)" >/dev/null +git push --quiet --force origin "refs/tags/$tag" +reject --allow-missing fixture # A blob tag is not an absent tag. +reject --products-json '[]' +reject --products-json '["$(touch injected)"]' +[[ ! -e injected ]] +git remote remove origin +git tag -f "$tag" >/dev/null +accept fixture +echo 'Product tags: remote authority, annotated tags, drift and invalid inputs passed' diff --git a/tools/release/verify-publication-candidate.mjs b/tools/release/verify-publication-candidate.mjs deleted file mode 100644 index 0d2675b70..000000000 --- a/tools/release/verify-publication-candidate.mjs +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/env bun - -import { appendFileSync } from "node:fs"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { ROOT } from "./release-graph.mjs"; -import { - deriveReleaseProducts, - latestVerifiedReleaseCommit, -} from "./verify-release-commit.mjs"; - -const TOOL = "verify-publication-candidate.mjs"; - -function error(message) { - return new Error(`${TOOL}: ${message}`); -} - -function publicationCommit(repo, headRef) { - const result = captureCommandOutput( - "git", - ["rev-parse", "--verify", `${headRef}^{commit}`], - { cwd: repo, label: `git rev-parse --verify ${headRef}^{commit}` }, - ); - if (result.error !== undefined || result.status !== 0) { - const detail = (result.stderr || result.stdout || result.error?.message || "").trim(); - throw error(`could not resolve publication commit${detail ? `: ${detail}` : ""}`); - } - return result.stdout.trimEnd(); -} - -function sameStrings(left, right) { - return JSON.stringify([...left].sort()) === JSON.stringify([...right].sort()); -} - -function manifestVersions(repo, commit, products) { - const readJson = (file) => { - const result = captureCommandOutput("git", ["show", `${commit}:${file}`], { - cwd: repo, - label: `git show ${commit}:${file}`, - }); - if (result.error !== undefined || result.status !== 0) { - throw error(`could not read ${file} at publication commit ${commit}`); - } - try { - return JSON.parse(result.stdout); - } catch (cause) { - throw error(`${file} at publication commit ${commit} is not valid JSON: ${cause.message}`); - } - }; - const packages = readJson("release-please-config.json").packages; - const manifest = readJson(".release-please-manifest.json"); - return Object.fromEntries(products.map((product) => { - const packagePath = Object.entries(packages ?? {}) - .find(([, config]) => config?.component === product)?.[0]; - const version = manifest?.[packagePath]; - if (packagePath === undefined || typeof version !== "string") { - throw error(`${product} has no publication version at ${commit}`); - } - return [product, version]; - })); -} - -export function derivePublicationProducts({ - repo = ROOT, - headRef = "HEAD", -} = {}) { - return deriveReleaseProducts({ repo, headRef: publicationCommit(repo, headRef) }).products; -} - -export function resolvePublicationPlanningSource({ - repo = ROOT, - headRef = "HEAD", -} = {}) { - const commit = publicationCommit(repo, headRef); - return { - planHeadSha: commit, - publicationSha: commit, - }; -} - -export function verifyPublicationCandidate({ - repo = ROOT, - headRef = "HEAD", - products, -} = {}) { - if ( - !Array.isArray(products) - || products.length === 0 - || products.some((product) => typeof product !== "string" || product.length === 0) - || new Set(products).size !== products.length - ) { - throw error("products must be a non-empty product string list without duplicates"); - } - const commit = publicationCommit(repo, headRef); - const verified = latestVerifiedReleaseCommit({ repo, headRef: commit }); - if (verified === null) { - throw error(`no verified release commit is reachable from publication commit ${commit}`); - } - if (!sameStrings(products, verified.products)) { - throw error( - `selected products do not match release commit ${verified.commit}: ` - + `selected=${JSON.stringify(products)}, released=${JSON.stringify(verified.products)}`, - ); - } - const currentVersions = manifestVersions(repo, commit, verified.products); - if (JSON.stringify(currentVersions) !== JSON.stringify(verified.versions)) { - throw error( - `publication versions at ${commit} do not match release commit ${verified.commit}: ` - + `publication=${JSON.stringify(currentVersions)}, released=${JSON.stringify(verified.versions)}`, - ); - } - return { - mode: "release-bump", - publicationSha: commit, - releaseSha: verified.commit, - products: verified.products, - versions: verified.versions, - }; -} - -function parseArgs(argv) { - let productsJson = ""; - let headRef = "HEAD"; - let githubOutput = ""; - let deriveProducts = false; - let resolvePlanHead = false; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--products-json") { - productsJson = argv[index + 1] ?? ""; - index += 1; - } else if (arg === "--derive-products") { - deriveProducts = true; - } else if (arg === "--resolve-plan-head") { - resolvePlanHead = true; - } else if (arg === "--head-ref") { - headRef = argv[index + 1] ?? ""; - index += 1; - } else if (arg === "--github-output") { - githubOutput = argv[index + 1] ?? ""; - index += 1; - } else { - throw error(`unknown argument ${arg}`); - } - } - if ( - !headRef - || (resolvePlanHead && (deriveProducts || Boolean(productsJson))) - || (!resolvePlanHead && deriveProducts === Boolean(productsJson)) - ) { - throw error( - "usage: verify-publication-candidate.mjs " - + "((--products-json JSON | --derive-products) | --resolve-plan-head) " - + "[--head-ref REF] [--github-output FILE]", - ); - } - if (resolvePlanHead) { - return { githubOutput, headRef, resolvePlanHead }; - } - let products; - if (deriveProducts) { - products = derivePublicationProducts({ headRef }); - } else { - try { - products = JSON.parse(productsJson); - } catch (cause) { - throw error(`--products-json must be valid JSON: ${cause.message}`); - } - } - return { githubOutput, headRef, products, resolvePlanHead }; -} - -if (import.meta.main) { - try { - const args = parseArgs(Bun.argv.slice(2)); - if (args.resolvePlanHead) { - const source = resolvePublicationPlanningSource({ headRef: args.headRef }); - if (args.githubOutput) { - appendFileSync(args.githubOutput, `plan_head_sha=${source.planHeadSha}\n`); - } - console.log(source.planHeadSha); - process.exit(0); - } - const verified = verifyPublicationCandidate(args); - if (args.githubOutput) { - appendFileSync( - args.githubOutput, - [ - `mode=${verified.mode}`, - `publication_sha=${verified.publicationSha}`, - `release_sha=${verified.releaseSha}`, - "", - ].join("\n"), - ); - } - console.log( - `verified publication commit ${verified.publicationSha} for ${verified.products.length} product(s)`, - ); - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/verify-publication-candidate.mts b/tools/release/verify-publication-candidate.mts new file mode 100644 index 000000000..f6605e420 --- /dev/null +++ b/tools/release/verify-publication-candidate.mts @@ -0,0 +1,179 @@ +#!/usr/bin/env bun + +import { appendFileSync } from 'node:fs'; + +import { ROOT } from './release-graph.mts'; +import { + deriveReleaseProducts, + latestVerifiedReleaseCommit, + releaseCommit, + releaseCommitFile, +} from './verify-release-commit.mts'; + +const TOOL = 'verify-publication-candidate.mts'; + +function error(message) { + return new Error(`${TOOL}: ${message}`); +} + +const publicationCommit = releaseCommit; + +function sameStrings(left, right) { + return JSON.stringify([...left].sort()) === JSON.stringify([...right].sort()); +} + +function manifestVersions(repo, commit, products) { + const readJson = (file) => { + try { + return JSON.parse(releaseCommitFile(repo, commit, file)); + } catch (cause) { + throw error(`${file} at publication commit ${commit} is not valid JSON: ${cause.message}`); + } + }; + const packages = readJson('release-please-config.json').packages; + const manifest = readJson('.release-please-manifest.json'); + return Object.fromEntries( + products.map((product) => { + const packagePath = Object.entries(packages ?? {}).find( + ([, config]) => config?.component === product, + )?.[0]; + const version = manifest?.[packagePath]; + if (packagePath === undefined || typeof version !== 'string') { + throw error(`${product} has no publication version at ${commit}`); + } + return [product, version]; + }), + ); +} + +export function derivePublicationProducts({ repo = ROOT, headRef = 'HEAD' } = {}) { + return deriveReleaseProducts({ repo, headRef: publicationCommit(repo, headRef) }).products; +} + +export function resolvePublicationPlanningSource({ repo = ROOT, headRef = 'HEAD' } = {}) { + const commit = publicationCommit(repo, headRef); + return { + planHeadSha: commit, + publicationSha: commit, + }; +} + +export function verifyPublicationCandidate({ repo = ROOT, headRef = 'HEAD', products } = {}) { + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((product) => typeof product !== 'string' || product.length === 0) || + new Set(products).size !== products.length + ) { + throw error('products must be a non-empty product string list without duplicates'); + } + const commit = publicationCommit(repo, headRef); + const verified = latestVerifiedReleaseCommit({ repo, headRef: commit }); + if (verified === null) { + throw error(`no verified release commit is reachable from publication commit ${commit}`); + } + if (!sameStrings(products, verified.products)) { + throw error( + `selected products do not match release commit ${verified.commit}: ` + + `selected=${JSON.stringify(products)}, released=${JSON.stringify(verified.products)}`, + ); + } + const currentVersions = manifestVersions(repo, commit, verified.products); + if (JSON.stringify(currentVersions) !== JSON.stringify(verified.versions)) { + throw error( + `publication versions at ${commit} do not match release commit ${verified.commit}: ` + + `publication=${JSON.stringify(currentVersions)}, released=${JSON.stringify(verified.versions)}`, + ); + } + return { + mode: 'release-bump', + publicationSha: commit, + releaseSha: verified.commit, + products: verified.products, + versions: verified.versions, + }; +} + +function parseArgs(argv) { + let productsJson = ''; + let headRef = 'HEAD'; + let githubOutput = ''; + let deriveProducts = false; + let resolvePlanHead = false; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--products-json') { + productsJson = argv[index + 1] ?? ''; + index += 1; + } else if (arg === '--derive-products') { + deriveProducts = true; + } else if (arg === '--resolve-plan-head') { + resolvePlanHead = true; + } else if (arg === '--head-ref') { + headRef = argv[index + 1] ?? ''; + index += 1; + } else if (arg === '--github-output') { + githubOutput = argv[index + 1] ?? ''; + index += 1; + } else { + throw error(`unknown argument ${arg}`); + } + } + if ( + !headRef || + (resolvePlanHead && (deriveProducts || Boolean(productsJson))) || + (!resolvePlanHead && deriveProducts === Boolean(productsJson)) + ) { + throw error( + 'usage: verify-publication-candidate.mts ' + + '((--products-json JSON | --derive-products) | --resolve-plan-head) ' + + '[--head-ref REF] [--github-output FILE]', + ); + } + if (resolvePlanHead) { + return { githubOutput, headRef, resolvePlanHead }; + } + let products; + if (deriveProducts) { + products = derivePublicationProducts({ headRef }); + } else { + try { + products = JSON.parse(productsJson); + } catch (cause) { + throw error(`--products-json must be valid JSON: ${cause.message}`); + } + } + return { githubOutput, headRef, products, resolvePlanHead }; +} + +if (import.meta.main) { + try { + const args = parseArgs(Bun.argv.slice(2)); + if (args.resolvePlanHead) { + const source = resolvePublicationPlanningSource({ headRef: args.headRef }); + if (args.githubOutput) { + appendFileSync(args.githubOutput, `plan_head_sha=${source.planHeadSha}\n`); + } + console.log(source.planHeadSha); + process.exit(0); + } + const verified = verifyPublicationCandidate(args); + if (args.githubOutput) { + appendFileSync( + args.githubOutput, + [ + `mode=${verified.mode}`, + `publication_sha=${verified.publicationSha}`, + `release_sha=${verified.releaseSha}`, + '', + ].join('\n'), + ); + } + console.log( + `verified publication commit ${verified.publicationSha} for ${verified.products.length} product(s)`, + ); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/verify-publication-candidate.test.mjs b/tools/release/verify-publication-candidate.test.mjs deleted file mode 100644 index ab11d2576..000000000 --- a/tools/release/verify-publication-candidate.test.mjs +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { mkdtempSync, mkdirSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { - derivePublicationProducts, - resolvePublicationPlanningSource, - verifyPublicationCandidate, -} from "./verify-publication-candidate.mjs"; - -const PRODUCT = "alpha"; - -function git(repo, ...args) { - return execFileSync("git", args, { cwd: repo, encoding: "utf8" }).trim(); -} - -function write(repo, file, contents) { - const target = path.join(repo, file); - mkdirSync(path.dirname(target), { recursive: true }); - writeFileSync(target, contents); -} - -function commit(repo, subject) { - git(repo, "add", "."); - git(repo, "commit", "-m", subject); - return git(repo, "rev-parse", "HEAD"); -} - -function fixture() { - const repo = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-publication-candidate-")); - git(repo, "init", "-q"); - git(repo, "config", "user.name", "Release Test"); - git(repo, "config", "user.email", "release@example.invalid"); - write(repo, "release-please-config.json", `${JSON.stringify({ - packages: { - "packages/alpha": { - "release-type": "simple", - component: PRODUCT, - "version-file": "VERSION", - "changelog-path": "CHANGELOG.md", - }, - }, - }, null, 2)}\n`); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.0.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n"); - commit(repo, "feat: introduce fixture"); - - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.1.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.1.0\n"); - write( - repo, - "packages/alpha/CHANGELOG.md", - "# Changelog\n\n## 0.1.0 (2026-07-30)\n\n- Initial release.\n", - ); - const release = commit(repo, "chore(release): publish alpha 0.1.0"); - return { repo, release }; -} - -test("accepts an exact same-SHA rerun after its product tag exists", () => { - const { repo, release } = fixture(); - git(repo, "tag", "alpha-v0.1.0", release); - - assert.deepEqual(derivePublicationProducts({ repo, headRef: release }), [PRODUCT]); - assert.deepEqual(resolvePublicationPlanningSource({ repo, headRef: release }), { - planHeadSha: release, - publicationSha: release, - }); - assert.deepEqual( - verifyPublicationCandidate({ repo, headRef: release, products: [PRODUCT] }), - { - mode: "release-bump", - publicationSha: release, - releaseSha: release, - products: [PRODUCT], - versions: { [PRODUCT]: "0.1.0" }, - }, - ); -}); - -test("accepts a later release-control fix without changing the pending release", () => { - const { repo, release } = fixture(); - write(repo, "tools/release-control.txt", "changed\n"); - const controller = commit(repo, "fix(release): change release control"); - - assert.deepEqual( - verifyPublicationCandidate({ repo, headRef: controller, products: [PRODUCT] }), - { - mode: "release-bump", - publicationSha: controller, - releaseSha: release, - products: [PRODUCT], - versions: { [PRODUCT]: "0.1.0" }, - }, - ); - assert.throws( - () => verifyPublicationCandidate({ repo, headRef: controller, products: ["other"] }), - /selected products do not match release commit/u, - ); -}); - -test("rejects a publication version changed after the verified release", () => { - const { repo, release } = fixture(); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.2.0"}\n'); - const changed = commit(repo, "fix(release): change pending version"); - - assert.throws( - () => verifyPublicationCandidate({ repo, headRef: changed, products: [PRODUCT] }), - /publication versions .* do not match release commit/u, - ); - assert.notEqual(changed, release); -}); diff --git a/tools/release/verify-publication-candidate.test.mts b/tools/release/verify-publication-candidate.test.mts new file mode 100644 index 000000000..d77930ffc --- /dev/null +++ b/tools/release/verify-publication-candidate.test.mts @@ -0,0 +1,50 @@ +import assert from 'node:assert/strict'; +import { + derivePublicationProducts, + resolvePublicationPlanningSource, + verifyPublicationCandidate, +} from './verify-publication-candidate.mts'; + +const [scenario, repo, release, headRef] = process.argv.slice(2); +const options = { repo, headRef, products: ['alpha'] }; +switch (scenario) { + case 'rerun': + assert.equal(headRef, release); + assert.deepEqual(derivePublicationProducts(options), ['alpha']); + assert.deepEqual(resolvePublicationPlanningSource(options), { + planHeadSha: release, + publicationSha: release, + }); + assert.deepEqual(verifyPublicationCandidate(options), { + mode: 'release-bump', + publicationSha: release, + releaseSha: release, + products: ['alpha'], + versions: { alpha: '0.1.0' }, + }); + break; + case 'controller': + assert.notEqual(headRef, release); + assert.deepEqual(verifyPublicationCandidate(options), { + mode: 'release-bump', + publicationSha: headRef, + releaseSha: release, + products: ['alpha'], + versions: { alpha: '0.1.0' }, + }); + assert.throws( + () => verifyPublicationCandidate({ ...options, products: ['other'] }), + /selected products do not match release commit/u, + ); + break; + case 'changed-version': + assert.notEqual(headRef, release); + assert.throws( + () => verifyPublicationCandidate(options), + /publication versions .* do not match release commit/u, + ); + break; + default: + throw new Error('run through verify-publication-candidate.test.sh'); +} +console.log(`publication candidate ${scenario}: passed`); diff --git a/tools/release/verify-publication-candidate.test.sh b/tools/release/verify-publication-candidate.test.sh new file mode 100644 index 000000000..acd9c20d4 --- /dev/null +++ b/tools/release/verify-publication-candidate.test.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +if [[ -z "${OLIPHAUNT_RELEASE_PLEASE_STATE:-}" ]]; then + exec bash "$root/tools/release/release-please-state.sh" "$root" HEAD \ + bash "$root/tools/release/verify-publication-candidate.test.sh" +fi +scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-publication-candidate.XXXXXX")" +trap 'rm -rf "$scratch"' EXIT + +for scenario in rerun controller changed-version; do + repo="$scratch/$scenario" + git init -q "$repo" + git -C "$repo" config user.name 'Release Test' + git -C "$repo" config user.email release@example.invalid + mkdir -p "$repo/packages/alpha" + cat > "$repo/release-please-config.json" <<'JSON' +{"packages":{"packages/alpha":{"release-type":"simple","component":"alpha","version-file":"VERSION","changelog-path":"CHANGELOG.md"}}} +JSON + printf '{"packages/alpha":"0.0.0"}\n' > "$repo/.release-please-manifest.json" + printf '0.0.0\n' > "$repo/packages/alpha/VERSION" + printf '# Changelog\n' > "$repo/packages/alpha/CHANGELOG.md" + git -C "$repo" add . + git -C "$repo" commit -qm 'feat: introduce fixture' + printf '{"packages/alpha":"0.1.0"}\n' > "$repo/.release-please-manifest.json" + printf '0.1.0\n' > "$repo/packages/alpha/VERSION" + printf '# Changelog\n\n## 0.1.0 (2026-07-30)\n\n- Initial release.\n' > "$repo/packages/alpha/CHANGELOG.md" + git -C "$repo" add . + git -C "$repo" commit -qm 'chore(release): publish alpha 0.1.0' + release="$(git -C "$repo" rev-parse HEAD)" + case "$scenario" in + rerun) git -C "$repo" tag alpha-v0.1.0 "$release" ;; + controller) + mkdir -p "$repo/tools" + printf 'changed\n' > "$repo/tools/release-control.txt" + git -C "$repo" add . + git -C "$repo" commit -qm 'fix(release): change release control' ;; + changed-version) + printf '{"packages/alpha":"0.2.0"}\n' > "$repo/.release-please-manifest.json" + git -C "$repo" add . + git -C "$repo" commit -qm 'fix(release): change pending version' ;; + esac + head="$(git -C "$repo" rev-parse HEAD)" + bash "$root/tools/release/with-release-history.sh" "$repo" "$head" \ + bash "$root/tools/dev/bun.sh" "$root/tools/release/verify-publication-candidate.test.mts" \ + "$scenario" "$repo" "$release" "$head" +done diff --git a/tools/release/verify-release-commit.mjs b/tools/release/verify-release-commit.mjs deleted file mode 100644 index 6c07b898f..000000000 --- a/tools/release/verify-release-commit.mjs +++ /dev/null @@ -1,774 +0,0 @@ -#!/usr/bin/env bun -import path from "node:path"; -import process from "node:process"; - -import { electronReleaseDependencies } from "../../examples/tools/example-release-dependencies.mjs"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { exampleCargoReleaseVersionBindings } from "./example-cargo-policy.mjs"; -import { - nativeToolsOptionalPackageProducts, - registryPackageRows, -} from "./release-artifact-targets.mjs"; -import { compatibilityVersionEntries, loadGraph } from "./release-graph.mjs"; -import { - releaseDerivedPathInventory, - SDK_INSTALL_VERSION_RULES, -} from "./sync-release-pr.mjs"; -import { RELEASE_PLEASE_BOOTSTRAP_SHA } from "./release-please-bootstrap.mjs"; - -const TOOL = "verify-release-commit.mjs"; -const ROOT = path.resolve(import.meta.dir, "../.."); -const SEMVER = /^(?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)(?:-(?:(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(?:[.](?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:[.][0-9A-Za-z-]+)*)?$/u; -const CARGO_DEPENDENCY_TABLES = new Set(["dependencies", "dev-dependencies", "build-dependencies"]); -let cachedDerivedRules; - -function error(message) { - return new Error(`${TOOL}: ${message}`); -} - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function sameStrings(left, right) { - return JSON.stringify([...left].sort(compareText)) === JSON.stringify([...right].sort(compareText)); -} - -function git( - repo, - args, - { allowEmptyOutput = false, check = true, stdoutTerminator = undefined } = {}, -) { - const result = captureCommandOutput("git", args, { - allowEmptyOutput, - cwd: repo, - label: `git ${args.join(" ")}`, - stdoutTerminator, - }); - if (result.error !== undefined) { - throw error(result.error.message); - } - if (check && result.status !== 0) { - const detail = (result.stderr || result.stdout || "").trim(); - throw error(`git ${args.join(" ")} failed${detail ? `: ${detail}` : ""}`); - } - return { status: result.status, stdout: result.stdout.trimEnd() }; -} - -function show(repo, commit, file) { - return git(repo, ["show", `${commit}:${file}`]).stdout; -} - -function showJson(repo, commit, file) { - let value; - try { - value = JSON.parse(show(repo, commit, file)); - } catch (cause) { - throw error(`${file} at ${commit} is not valid JSON: ${cause.message}`); - } - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw error(`${file} at ${commit} must contain a JSON object`); - } - return value; -} - -function relativeFile(packagePath, file, context) { - if (typeof file !== "string" || file.length === 0 || path.isAbsolute(file)) { - throw error(`${context} must be a non-empty relative path`); - } - const normalized = path.posix.normalize(path.posix.join(packagePath, file)); - if (normalized === ".." || normalized.startsWith("../") || !(normalized === packagePath || normalized.startsWith(`${packagePath}/`))) { - throw error(`${context} must stay inside ${packagePath}`); - } - return normalized; -} - -function canonicalVersionFile(packagePath, config, product) { - if (typeof config["version-file"] === "string" && config["version-file"].length > 0) { - return relativeFile(packagePath, config["version-file"], `${product}.version-file`); - } - if (config["release-type"] === "rust") { - return relativeFile(packagePath, "Cargo.toml", `${product}.Cargo.toml`); - } - if (config["release-type"] === "node" || config["release-type"] === "expo") { - return relativeFile(packagePath, "package.json", `${product}.package.json`); - } - throw error(`${product} has no canonical version file`); -} - -function versionFromCanonicalFile(text, config, file, product) { - if (config["release-type"] === "node" || config["release-type"] === "expo") { - let manifest; - try { - manifest = JSON.parse(text); - } catch (cause) { - throw error(`${file} for ${product} is invalid JSON: ${cause.message}`); - } - return manifest?.version; - } - if (config["release-type"] === "rust" && !config["version-file"]) { - const packageBlock = text.match(/(?:^|\n)\[package\][ \t]*\n([\s\S]*?)(?=\n\[|$)/u)?.[1] ?? ""; - return packageBlock.match(/(?:^|\n)[ \t]*version[ \t]*=[ \t]*["']([^"']+)["']/u)?.[1]; - } - return text.trim(); -} - -function changelogMentionsVersion(text, version) { - return text.split(/\r?\n/u).some((line) => { - const heading = line.match(/^##[ \t]+(?:\[)?([^\] (]+)(?:\])?(?:[ \t(]|$)/u)?.[1]; - return heading === version; - }); -} - -function changedFiles(repo, parent, commit) { - return new Set( - git( - repo, - ["diff", "--no-renames", "--name-only", "--diff-filter=ACDMRT", "-z", parent, commit], - { stdoutTerminator: "\0" }, - ).stdout - .split("\0") - .filter(Boolean), - ); -} - -function jsonPath(expression, context) { - if (typeof expression !== "string" || !/^[$][.][A-Za-z0-9_.-]+$/u.test(expression)) { - throw error(`${context} must use a simple $.path.to.field expression`); - } - return expression.slice(2).split("."); -} - -function pathKey(parts) { - return parts.map(String).join("\0"); -} - -function semanticDiffs(before, after, parts = []) { - if (Object.is(before, after)) return []; - const beforeObject = before !== null && typeof before === "object"; - const afterObject = after !== null && typeof after === "object"; - if (beforeObject && afterObject && Array.isArray(before) === Array.isArray(after)) { - const keys = new Set(Array.isArray(before) - ? Array.from({ length: Math.max(before.length, after.length) }, (_value, index) => index) - : [...Object.keys(before), ...Object.keys(after)]); - return [...keys].flatMap((key) => semanticDiffs(before[key], after[key], [...parts, key])); - } - return [{ parts, before, after }]; -} - -function parseStructured(text, type, file, commit) { - try { - const value = type === "json" ? JSON.parse(text) : type === "toml" ? Bun.TOML.parse(text) : Bun.YAML.parse(text); - if (value === null || typeof value !== "object") { - throw new TypeError("root must be an object or array"); - } - return value; - } catch (cause) { - throw error(`${file} at ${commit} is invalid ${type.toUpperCase()}: ${cause.message}`); - } -} - -function versionTransition(before, after, transitions) { - if (typeof before !== "string" || typeof after !== "string") return false; - return transitions.some((transition) => { - if (!before.includes(transition.before) || !after.includes(transition.after)) return false; - return before.replaceAll(transition.before, "") === - after.replaceAll(transition.after, ""); - }); -} - -function structuredRuleKey(type, file, parts) { - return `${type}\0${file}\0${pathKey(parts)}`; -} - -function derivedVersionRules() { - if (cachedDerivedRules !== undefined) return cachedDerivedRules; - const products = loadGraph(TOOL).products; - const structured = new Map(); - const text = new Map(); - const addStructured = (type, file, parts, sourceProduct, wrapped = false) => { - const key = structuredRuleKey(type, file, parts); - const prior = structured.get(key); - if (prior !== undefined && (prior.sourceProduct !== sourceProduct || prior.wrapped !== wrapped)) { - throw error(`conflicting derived version rules for ${file}:${parts.join(".")}`); - } - structured.set(key, { sourceProduct, wrapped }); - }; - const addText = (file, rule) => { - const prior = text.get(file); - if (prior !== undefined && JSON.stringify(prior) !== JSON.stringify(rule)) { - throw error(`conflicting derived text version rules for ${file}`); - } - text.set(file, rule); - }; - - for (const entry of compatibilityVersionEntries(products, { requireSourceProduct: true, prefix: TOOL })) { - const separator = entry.parser.indexOf(":"); - const parser = separator === -1 ? entry.parser : entry.parser.slice(0, separator); - const expression = separator === -1 ? "" : entry.parser.slice(separator + 1); - if (parser === "json" || parser === "toml") { - addStructured(parser, entry.path, expression.split("."), entry.sourceProduct); - } else if (parser === "raw") { - addText(entry.path, { type: "raw", sourceProduct: entry.sourceProduct }); - } else if (parser === "rust-const") { - addText(entry.path, { type: "rust-const", name: expression, sourceProduct: entry.sourceProduct }); - } else { - throw error(`${entry.id} uses unsupported compatibility parser ${JSON.stringify(entry.parser)}`); - } - } - - for (const { file, product, prefix, suffix } of SDK_INSTALL_VERSION_RULES) { - addText(file, { type: "embedded", sourceProduct: product, prefix, suffix }); - } - - for (const { file, versionPaths, sourceProduct, wrapped } of exampleCargoReleaseVersionBindings()) { - for (const parts of versionPaths) { - addStructured("toml", file, parts, sourceProduct, wrapped); - } - } - - for (const { packageName, product } of nativeToolsOptionalPackageProducts(TOOL)) { - addStructured( - "json", - "src/runtimes/liboliphaunt/native/tools-npm/package.json", - ["optionalDependencies", packageName], - product, - true, - ); - addStructured( - "yaml", - "pnpm-lock.yaml", - [ - "importers", - "src/runtimes/liboliphaunt/native/tools-npm", - "optionalDependencies", - packageName, - "specifier", - ], - product, - true, - ); - } - - for (const { packageName } of electronReleaseDependencies(ROOT)) { - const owners = Object.keys(products) - .flatMap((product) => registryPackageRows({ product, packageKind: "npm" }, TOOL)) - .filter((row) => row.packageName === packageName) - .map((row) => row.product); - if (owners.length !== 1) { - throw error( - `Electron release dependency ${packageName} must map to exactly one release product; ` - + `got ${owners.join(", ") || "none"}`, - ); - } - addStructured("json", "examples/electron/package.json", ["dependencies", packageName], owners[0]); - } - - cachedDerivedRules = { structured, text }; - return cachedDerivedRules; -} - -function productTransition(rule, before, after, transitions) { - const transition = transitions.find(({ product }) => product === rule.sourceProduct); - if (transition === undefined) return false; - return rule.wrapped - ? versionTransition(before, after, [transition]) - : before === transition.before && after === transition.after; -} - -function embeddedTextTransition(rule, before, after, transitions) { - const transition = transitions.find(({ product }) => product === rule.sourceProduct); - if (transition === undefined) return false; - const prior = `${rule.prefix}${transition.before}${rule.suffix}`; - const next = `${rule.prefix}${transition.after}${rule.suffix}`; - return before.split(prior).length === 2 && after === before.replace(prior, next); -} - -function valueAt(root, parts) { - let current = root; - for (const part of parts) { - if (current === null || typeof current !== "object") return undefined; - current = current[part]; - } - return current; -} - -function cargoDependencyEntryPath(parts) { - const names = parts.map(String); - if (names.length === 3 && CARGO_DEPENDENCY_TABLES.has(names[0]) && names[2] === "version") { - return names.slice(0, 2); - } - if (names.length === 5 && names[0] === "target" && CARGO_DEPENDENCY_TABLES.has(names[2]) && names[4] === "version") { - return names.slice(0, 4); - } - return undefined; -} - -function parseCargoManifest(repo, commit, file) { - return parseStructured(show(repo, commit, file), "toml", file, commit); -} - -function cargoDependencyVersionChange({ repo, parent, commit, file, parts, beforeRoot, afterRoot, before, after }) { - if (path.posix.basename(file) !== "Cargo.toml") return false; - const entryPath = cargoDependencyEntryPath(parts); - if (entryPath === undefined) return false; - const priorEntry = valueAt(beforeRoot, entryPath); - const nextEntry = valueAt(afterRoot, entryPath); - if ( - priorEntry === null || Array.isArray(priorEntry) || typeof priorEntry !== "object" || - nextEntry === null || Array.isArray(nextEntry) || typeof nextEntry !== "object" || - typeof priorEntry.path !== "string" || priorEntry.path !== nextEntry.path - ) { - return false; - } - const dependencyManifest = path.posix.normalize(path.posix.join(path.posix.dirname(file), priorEntry.path, "Cargo.toml")); - if (dependencyManifest === ".." || dependencyManifest.startsWith("../") || path.posix.isAbsolute(dependencyManifest)) return false; - const priorPackage = parseCargoManifest(repo, parent, dependencyManifest).package; - const nextPackage = parseCargoManifest(repo, commit, dependencyManifest).package; - if ( - priorPackage === null || Array.isArray(priorPackage) || typeof priorPackage !== "object" || - nextPackage === null || Array.isArray(nextPackage) || typeof nextPackage !== "object" || - typeof priorPackage.version !== "string" || typeof nextPackage.version !== "string" || - priorPackage.name !== nextPackage.name - ) { - return false; - } - const exact = typeof before === "string" && before.startsWith("="); - return before === `${exact ? "=" : ""}${priorPackage.version}` && - after === `${exact ? "=" : ""}${nextPackage.version}`; -} - -function localCargoPackageVersions(repo, commit, cache) { - if (cache.has(commit)) return cache.get(commit); - const versions = new Map(); - const manifests = git( - repo, - ["ls-tree", "-r", "-z", "--name-only", commit], - { allowEmptyOutput: true, stdoutTerminator: "\0" }, - ).stdout - .split("\0") - .filter((file) => file === "Cargo.toml" || file.endsWith("/Cargo.toml")); - for (const file of manifests) { - const packageConfig = parseCargoManifest(repo, commit, file).package; - if ( - packageConfig === null || Array.isArray(packageConfig) || typeof packageConfig !== "object" || - typeof packageConfig.name !== "string" || typeof packageConfig.version !== "string" - ) { - continue; - } - const packageVersions = versions.get(packageConfig.name) ?? new Set(); - packageVersions.add(packageConfig.version); - versions.set(packageConfig.name, packageVersions); - } - cache.set(commit, versions); - return versions; -} - -function cargoLockVersionChange({ repo, parent, commit, file, parts, beforeRoot, afterRoot, before, after, cargoVersions }) { - const names = parts.map(String); - if (path.posix.basename(file) !== "Cargo.lock" || names.length !== 3 || names[0] !== "package" || !/^[0-9]+$/u.test(names[1]) || names[2] !== "version") { - return false; - } - const priorPackage = valueAt(beforeRoot, ["package", Number(names[1])]); - const nextPackage = valueAt(afterRoot, ["package", Number(names[1])]); - if ( - priorPackage === null || Array.isArray(priorPackage) || typeof priorPackage !== "object" || - nextPackage === null || Array.isArray(nextPackage) || typeof nextPackage !== "object" || - typeof priorPackage.name !== "string" || priorPackage.name !== nextPackage.name || - priorPackage.source !== undefined || nextPackage.source !== undefined - ) { - return false; - } - return localCargoPackageVersions(repo, parent, cargoVersions).get(priorPackage.name)?.has(before) === true && - localCargoPackageVersions(repo, commit, cargoVersions).get(priorPackage.name)?.has(after) === true; -} - -function authorizedDerivedStructuredChange(context, rules) { - if ( - context.type === "json" && - context.file === "release-please-config.json" && - pathKey(context.parts) === "bootstrap-sha" && - context.before === RELEASE_PLEASE_BOOTSTRAP_SHA && - context.after === undefined && - context.transitions.length > 0 - ) { - return true; - } - const rule = rules.structured.get(structuredRuleKey(context.type, context.file, context.parts)); - if (rule !== undefined) return productTransition(rule, context.before, context.after, context.transitions); - if (context.type !== "toml") return false; - return cargoDependencyVersionChange(context) || cargoLockVersionChange(context); -} - -function structuredType(file) { - const basename = path.posix.basename(file); - if (file === "release-please-config.json" || basename === "package.json") return "json"; - if (basename === "pnpm-lock.yaml") return "yaml"; - if (basename === "Cargo.toml" || basename === "Cargo.lock" || file.endsWith(".toml")) return "toml"; - return undefined; -} - -function maskGenericVersion(text, file, commit) { - const single = text.split(/\r?\n/u).filter((line) => line.includes("x-release-please-version")); - if (single.length === 1) { - const versions = single[0].match(/[0-9]+[.][0-9]+[.][0-9]+(?:[-+][0-9A-Za-z.-]+)?/gu) ?? []; - if (versions.length !== 1) throw error(`${file} at ${commit} release version marker must contain exactly one version`); - return { version: versions[0], text: text.replace(single[0], single[0].replace(versions[0], "")) }; - } - const block = /x-release-please-start-version(?[\s\S]*?)x-release-please-end/u.exec(text)?.groups?.body; - if (single.length !== 0 || block === undefined) throw error(`${file} at ${commit} must contain one Release Please version marker`); - const versions = block.match(/[0-9]+[.][0-9]+[.][0-9]+(?:[-+][0-9A-Za-z.-]+)?/gu) ?? []; - if (versions.length !== 1) throw error(`${file} at ${commit} release version block must contain exactly one version`); - return { version: versions[0], text: text.replace(block, block.replace(versions[0], "")) }; -} - -function validateTextSemanticDiff({ repo, parent, commit, file, fields, derived, transitions, derivedRules }) { - const before = show(repo, parent, file); - const after = show(repo, commit, file); - if (fields.some(({ type }) => type === "raw")) { - const field = fields.find(({ type }) => type === "raw"); - if (before.trim() !== field.before || after.trim() !== field.after) { - throw error(`canonical version file ${file} contains a non-version semantic change`); - } - return; - } - if (fields.some(({ type }) => type === "generic")) { - const prior = maskGenericVersion(before, file, parent); - const next = maskGenericVersion(after, file, commit); - if (prior.text !== next.text || !fields.some(({ before: oldVersion, after: newVersion }) => prior.version === oldVersion && next.version === newVersion)) { - throw error(`Release Please generic file ${file} contains a non-version semantic change`); - } - return; - } - const derivedRule = derived ? derivedRules.text.get(file) : undefined; - if (derivedRule?.type === "rust-const") { - const pattern = new RegExp(`(const\\s+${derivedRule.name.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")}\\s*:\\s*&str\\s*=\\s*")([^"]+)(";)`, "u"); - const prior = pattern.exec(before); - const next = pattern.exec(after); - if ( - prior === null || next === null || !productTransition(derivedRule, prior[2], next[2], transitions) || - before.replace(pattern, "$1$3") !== after.replace(pattern, "$1$3") - ) { - throw error(`derived file ${file} contains a non-version semantic change`); - } - return; - } - if ( - derivedRule?.type === "raw" && productTransition(derivedRule, before.trim(), after.trim(), transitions) && - before.replace(before.trim(), "") === after.replace(after.trim(), "") - ) { - return; - } - if (derivedRule?.type === "embedded" && embeddedTextTransition(derivedRule, before, after, transitions)) return; - throw error(`${derived ? "derived file" : "release file"} ${file} contains a non-version semantic change`); -} - -function validateAllowedFileSemantics({ - repo, - parent, - commit, - changed, - changelogs, - fieldsByFile, - derivedFiles, - transitions, -}) { - const derivedRules = derivedVersionRules(); - const cargoVersions = new Map(); - for (const file of changed) { - if (file === ".release-please-manifest.json" || changelogs.has(file)) continue; - const fields = fieldsByFile.get(file) ?? []; - const derived = derivedFiles.has(file); - const type = structuredType(file); - if (type === undefined) { - validateTextSemanticDiff({ repo, parent, commit, file, fields, derived, transitions, derivedRules }); - continue; - } - const before = parseStructured(show(repo, parent, file), type, file, parent); - const after = parseStructured(show(repo, commit, file), type, file, commit); - const releaseFields = new Map(fields.filter(({ parts }) => parts !== undefined).map((field) => [pathKey(field.parts), field])); - for (const difference of semanticDiffs(before, after)) { - const releaseField = releaseFields.get(pathKey(difference.parts)); - if (releaseField !== undefined) { - if (difference.before !== releaseField.before || difference.after !== releaseField.after) { - throw error(`${releaseField.role} ${file} contains a non-version semantic change at ${difference.parts.join(".")}`); - } - continue; - } - if (derived && authorizedDerivedStructuredChange({ - repo, - parent, - commit, - file, - type, - parts: difference.parts, - beforeRoot: before, - afterRoot: after, - before: difference.before, - after: difference.after, - transitions, - cargoVersions, - }, derivedRules)) continue; - const label = fields.some(({ role }) => role === "canonical version file") ? "canonical version file" : derived ? "derived file" : "release file"; - throw error(`${label} ${file} contains a non-version semantic change at ${difference.parts.join(".") || ""}`); - } - } -} - -export function deriveReleaseProducts({ repo = ROOT, headRef = "HEAD" } = {}) { - const commit = git(repo, ["rev-parse", "--verify", `${headRef}^{commit}`]).stdout; - const ancestry = git(repo, ["rev-list", "--parents", "-n", "1", commit]).stdout.split(/\s+/u); - if (ancestry.length !== 2) { - throw error(`release commit ${commit} must have exactly one parent, found ${Math.max(0, ancestry.length - 1)}`); - } - const parent = ancestry[1]; - const config = showJson(repo, commit, "release-please-config.json"); - const packageConfigs = config.packages; - if (packageConfigs === null || Array.isArray(packageConfigs) || typeof packageConfigs !== "object") { - throw error("release-please-config.json must define a packages object"); - } - const byPath = new Map(); - const products = new Set(); - for (const [packagePath, packageConfig] of Object.entries(packageConfigs)) { - if (packageConfig === null || Array.isArray(packageConfig) || typeof packageConfig !== "object") { - throw error(`release-please package ${packagePath} must be an object`); - } - const product = packageConfig.component; - if (typeof product !== "string" || product.length === 0 || products.has(product)) { - throw error(`release-please package ${packagePath} has a missing or duplicate component`); - } - products.add(product); - byPath.set(packagePath, product); - } - const before = showJson(repo, parent, ".release-please-manifest.json"); - const after = showJson(repo, commit, ".release-please-manifest.json"); - const changedProducts = [...new Set([...Object.keys(before), ...Object.keys(after)])] - .filter((packagePath) => before[packagePath] !== after[packagePath]) - .map((packagePath) => { - const product = byPath.get(packagePath); - if (product === undefined) { - throw error(`release manifest changed unknown package path ${packagePath}`); - } - return product; - }) - .sort(compareText); - if (changedProducts.length === 0) { - throw error("release commit must advance at least one release-please manifest version"); - } - return { commit, parent, products: changedProducts }; -} - -export function verifyReleaseCommit({ repo = ROOT, headRef = "HEAD", products }) { - if (!Array.isArray(products) || products.length === 0 || products.some((item) => typeof item !== "string" || item.length === 0)) { - throw error("products must be a non-empty product string list"); - } - const selected = [...new Set(products)].sort(compareText); - if (selected.length !== products.length) { - throw error("products must not contain duplicates"); - } - - const commit = git(repo, ["rev-parse", "--verify", `${headRef}^{commit}`]).stdout; - const ancestry = git(repo, ["rev-list", "--parents", "-n", "1", commit]).stdout.split(/\s+/u); - if (ancestry.length !== 2) { - throw error(`release commit ${commit} must have exactly one parent, found ${Math.max(0, ancestry.length - 1)}`); - } - const parent = ancestry[1]; - const subject = git(repo, ["show", "-s", "--format=%s", commit]).stdout; - if (!/^chore\(release\): .+/u.test(subject)) { - throw error(`release commit ${commit} subject must start with "chore(release): "; got ${JSON.stringify(subject)}`); - } - - const config = showJson(repo, commit, "release-please-config.json"); - const packageConfigs = config.packages; - if (packageConfigs === null || Array.isArray(packageConfigs) || typeof packageConfigs !== "object") { - throw error("release-please-config.json must define a packages object"); - } - const byProduct = new Map(); - const byPath = new Map(); - for (const [packagePath, packageConfig] of Object.entries(packageConfigs)) { - if (packageConfig === null || Array.isArray(packageConfig) || typeof packageConfig !== "object") { - throw error(`release-please package ${packagePath} must be an object`); - } - const product = packageConfig.component; - if (typeof product !== "string" || product.length === 0 || byProduct.has(product)) { - throw error(`release-please package ${packagePath} has a missing or duplicate component`); - } - byProduct.set(product, { packagePath, config: packageConfig }); - byPath.set(packagePath, product); - } - for (const product of selected) { - if (!byProduct.has(product)) { - throw error(`selected release product ${product} is absent from release-please-config.json`); - } - } - - const before = showJson(repo, parent, ".release-please-manifest.json"); - const after = showJson(repo, commit, ".release-please-manifest.json"); - const changedPaths = [...new Set([...Object.keys(before), ...Object.keys(after)])] - .filter((packagePath) => before[packagePath] !== after[packagePath]) - .sort(compareText); - const changedProducts = changedPaths.map((packagePath) => { - const product = byPath.get(packagePath); - if (product === undefined) { - throw error(`release manifest changed unknown package path ${packagePath}`); - } - return product; - }).sort(compareText); - if (!sameStrings(changedProducts, selected)) { - throw error(`selected products do not exactly match this commit's release bumps: selected=${JSON.stringify(selected)}, bumped=${JSON.stringify(changedProducts)}`); - } - - const changed = changedFiles(repo, parent, commit); - if (!changed.has(".release-please-manifest.json")) { - throw error("release commit must change .release-please-manifest.json"); - } - const versions = {}; - const derivedFiles = new Set(releaseDerivedPathInventory()); - const allowedChangedFiles = new Set([".release-please-manifest.json", ...derivedFiles]); - const fieldsByFile = new Map(); - const changelogs = new Set(); - const transitions = []; - const addField = (file, field) => fieldsByFile.set(file, [...(fieldsByFile.get(file) ?? []), field]); - for (const product of selected) { - const { packagePath, config: packageConfig } = byProduct.get(product); - const version = after[packagePath]; - const priorVersion = before[packagePath]; - if ( - typeof priorVersion !== "string" || !SEMVER.test(priorVersion) || - typeof version !== "string" || !SEMVER.test(version) || - Bun.semver.order(version, priorVersion) <= 0 - ) { - throw error(`${product} must advance to a semver version in .release-please-manifest.json`); - } - const versionFile = canonicalVersionFile(packagePath, packageConfig, product); - const changelogFile = relativeFile( - packagePath, - packageConfig["changelog-path"] ?? "CHANGELOG.md", - `${product}.changelog-path`, - ); - if (!changed.has(versionFile)) { - throw error(`${product} release commit did not change canonical version file ${versionFile}`); - } - if (!changed.has(changelogFile)) { - throw error(`${product} release commit did not change changelog ${changelogFile}`); - } - allowedChangedFiles.add(versionFile); - allowedChangedFiles.add(changelogFile); - changelogs.add(changelogFile); - transitions.push({ product, before: priorVersion, after: version }); - if (packageConfig["release-type"] === "node" || packageConfig["release-type"] === "expo") { - addField(versionFile, { type: "json", parts: ["version"], before: priorVersion, after: version, role: "canonical version file" }); - } else if (packageConfig["release-type"] === "rust" && !packageConfig["version-file"]) { - addField(versionFile, { type: "toml", parts: ["package", "version"], before: priorVersion, after: version, role: "canonical version file" }); - } else { - addField(versionFile, { type: "raw", before: priorVersion, after: version, role: "canonical version file" }); - } - for (const [index, entry] of (packageConfig["extra-files"] ?? []).entries()) { - const extraPath = typeof entry === "string" ? entry : entry?.path; - const file = relativeFile(packagePath, extraPath, `${product}.extra-files[${index}]`); - allowedChangedFiles.add(file); - const type = typeof entry === "string" ? "generic" : entry.type ?? "generic"; - const field = { type, before: priorVersion, after: version, role: `${product} extra file` }; - if (type === "json" || type === "toml") { - field.parts = jsonPath(entry.jsonpath, `${product}.extra-files[${index}].jsonpath`); - } - addField(file, field); - } - const fileVersion = versionFromCanonicalFile(show(repo, commit, versionFile), packageConfig, versionFile, product); - if (fileVersion !== version) { - throw error(`${product} canonical version file ${versionFile} contains ${JSON.stringify(fileVersion)}, expected ${version}`); - } - if (!changelogMentionsVersion(show(repo, commit, changelogFile), version)) { - throw error(`${product} changelog ${changelogFile} has no release heading for ${version}`); - } - versions[product] = version; - } - - const unexpected = [...changed].filter((file) => !allowedChangedFiles.has(file)).sort(compareText); - if (unexpected.length > 0) { - throw error( - `release-bump commit contains non-release-derived path(s): ${unexpected.join(", ")}; ` + - "only Release Please version/changelog/extra-file outputs and sync-release-pr's structured derived-path inventory are allowed", - ); - } - - validateAllowedFileSemantics({ - repo, - parent, - commit, - changed, - changelogs, - fieldsByFile, - derivedFiles, - transitions, - }); - - return { - commit, - parent, - products: selected, - versions, - verifiedDerivedPaths: [...changed].filter((file) => derivedFiles.has(file)).sort(compareText), - }; -} - -export function latestVerifiedReleaseCommit({ repo = ROOT, headRef = "HEAD" } = {}) { - const release = git(repo, [ - "log", - "-1", - "--format=%H", - "--grep=^chore(release): ", - headRef, - "--", - ".release-please-manifest.json", - ], { allowEmptyOutput: true, stdoutTerminator: "\n" }).stdout; - if (release === "") return null; - const { products } = deriveReleaseProducts({ repo, headRef: release }); - return verifyReleaseCommit({ repo, headRef: release, products }); -} - -function parseArgs(argv) { - let productsJson = ""; - let headRef = "HEAD"; - let deriveProducts = false; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === "--products-json") { - productsJson = argv[index + 1] ?? ""; - index += 1; - } else if (arg === "--derive-products") { - deriveProducts = true; - } else if (arg === "--head-ref") { - headRef = argv[index + 1] ?? ""; - index += 1; - } else { - throw error(`unknown argument ${arg}`); - } - } - if (!headRef || deriveProducts === Boolean(productsJson)) { - throw error("usage: verify-release-commit.mjs (--products-json JSON | --derive-products) [--head-ref REF]"); - } - if (deriveProducts) return { deriveProducts, headRef }; - let products; - try { - products = JSON.parse(productsJson); - } catch (cause) { - throw error(`--products-json must be valid JSON: ${cause.message}`); - } - return { deriveProducts, headRef, products }; -} - -if (import.meta.main) { - try { - const args = parseArgs(Bun.argv.slice(2)); - if (args.deriveProducts) { - console.log(JSON.stringify(deriveReleaseProducts(args).products)); - } else { - const verified = verifyReleaseCommit(args); - console.log(`verified release-bump commit ${verified.commit} for ${verified.products.length} product(s): ${verified.products.join(", ")}`); - } - } catch (cause) { - console.error(cause instanceof Error ? cause.message : String(cause)); - process.exit(1); - } -} diff --git a/tools/release/verify-release-commit.mts b/tools/release/verify-release-commit.mts new file mode 100644 index 000000000..439d4cc81 --- /dev/null +++ b/tools/release/verify-release-commit.mts @@ -0,0 +1,1081 @@ +#!/usr/bin/env bun +import { existsSync, readdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; + +import { electronReleaseDependencies } from '../../src/examples/tools/example-release-dependencies.mts'; +import { + nativeToolsOptionalPackageProducts, + registryPackageRows, +} from './release-artifact-targets.mts'; +import { compatibilityVersionEntries, loadProducts } from './release-graph.mts'; +import { exampleCargoReleaseVersionBindings } from './example-cargo-versions.mts'; +import { RELEASE_PLEASE_BOOTSTRAP_SHA } from './release-please-bootstrap.mts'; +import { releaseDerivedPathInventory, SDK_INSTALL_VERSION_RULES } from './sync-release-pr.mts'; + +const TOOL = 'verify-release-commit.mts'; +const ROOT = path.resolve(import.meta.dir, '../..'); +const SEMVER = + /^(?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)(?:-(?:(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(?:[.](?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:[.][0-9A-Za-z-]+)*)?$/u; +const CARGO_DEPENDENCY_TABLES = new Set(['dependencies', 'dev-dependencies', 'build-dependencies']); +let cachedDerivedRules; + +function error(message) { + return new Error(`${TOOL}: ${message}`); +} + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function sameStrings(left, right) { + return ( + JSON.stringify([...left].sort(compareText)) === JSON.stringify([...right].sort(compareText)) + ); +} + +function releaseHistory(repo) { + const directory = process.env.OLIPHAUNT_RELEASE_HISTORY; + if (!directory) throw error('run through with-release-history.sh'); + const [source, ref, commit, release] = readFileSync( + path.join(directory, 'context'), + 'utf8', + ).split('\0'); + if (source !== realpathSync(repo)) throw error('release history belongs to another repository'); + return { directory, ref, commit, release }; +} + +export function releaseCommit(repo, ref) { + const state = releaseHistory(repo); + const commit = ref === state.ref ? state.commit : ref; + if (!/^[0-9a-f]{40}$/.test(commit) || !existsSync(path.join(state.directory, commit, 'files'))) + throw error('release history does not include ' + ref); + return commit; +} + +function commitData(repo, commit, name) { + return readFileSync( + path.join(releaseHistory(repo).directory, releaseCommit(repo, commit), name), + 'utf8', + ); +} + +export function releaseCommitFile(repo, commit, file) { + if ( + path.isAbsolute(file) || + file.split('/').some((part) => !part || part === '.' || part === '..') + ) + throw error('unsafe release file path: ' + file); + return commitData(repo, commit, 'blobs/' + file).trimEnd(); +} + +const show = releaseCommitFile; + +function snapshotPaths() { + const directory = process.env.OLIPHAUNT_RELEASE_HISTORY; + if (!directory) throw error('missing release history destination'); + const common = [ + 'release-please-config.json', + '.release-please-manifest.json', + ...releaseDerivedPathInventory(), + ]; + for (const entry of readdirSync(directory, { withFileTypes: true })) { + if (!entry.isDirectory()) continue; + const stage = path.join(directory, entry.name); + const files = new Set( + readFileSync(path.join(stage, 'files'), 'utf8').split('\0').filter(Boolean), + ); + const selected = new Set([ + ...common, + ...[...files].filter((file) => file === 'Cargo.toml' || file.endsWith('/Cargo.toml')), + ]); + const config = path.join(stage, 'config.json'); + if (existsSync(config)) { + const packages = JSON.parse(readFileSync(config, 'utf8')).packages ?? {}; + for (const [packagePath, value] of Object.entries(packages)) { + selected.add(canonicalVersionFile(packagePath, value, value.component)); + selected.add( + relativeFile(packagePath, value['changelog-path'] ?? 'CHANGELOG.md', 'changelog'), + ); + for (const extra of value['extra-files'] ?? []) + selected.add( + relativeFile(packagePath, typeof extra === 'string' ? extra : extra.path, 'extra file'), + ); + } + } + writeFileSync( + path.join(stage, 'paths'), + [...selected] + .filter((file) => files.has(file)) + .map((file) => file + '\0') + .join(''), + ); + } +} + +function showJson(repo, commit, file) { + let value; + try { + value = JSON.parse(show(repo, commit, file)); + } catch (cause) { + throw error(`${file} at ${commit} is not valid JSON: ${cause.message}`); + } + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw error(`${file} at ${commit} must contain a JSON object`); + } + return value; +} + +function relativeFile(packagePath, file, context) { + if (typeof file !== 'string' || file.length === 0 || path.isAbsolute(file)) { + throw error(`${context} must be a non-empty relative path`); + } + const normalized = path.posix.normalize(path.posix.join(packagePath, file)); + if ( + normalized === '..' || + normalized.startsWith('../') || + !(normalized === packagePath || normalized.startsWith(`${packagePath}/`)) + ) { + throw error(`${context} must stay inside ${packagePath}`); + } + return normalized; +} + +function canonicalVersionFile(packagePath, config, product) { + if (typeof config['version-file'] === 'string' && config['version-file'].length > 0) { + return relativeFile(packagePath, config['version-file'], `${product}.version-file`); + } + if (config['release-type'] === 'rust') { + return relativeFile(packagePath, 'Cargo.toml', `${product}.Cargo.toml`); + } + if (config['release-type'] === 'node' || config['release-type'] === 'expo') { + return relativeFile(packagePath, 'package.json', `${product}.package.json`); + } + throw error(`${product} has no canonical version file`); +} + +function versionFromCanonicalFile(text, config, file, product) { + if (config['release-type'] === 'node' || config['release-type'] === 'expo') { + let manifest; + try { + manifest = JSON.parse(text); + } catch (cause) { + throw error(`${file} for ${product} is invalid JSON: ${cause.message}`); + } + return manifest?.version; + } + if (config['release-type'] === 'rust' && !config['version-file']) { + const packageBlock = text.match(/(?:^|\n)\[package\][ \t]*\n([\s\S]*?)(?=\n\[|$)/u)?.[1] ?? ''; + return packageBlock.match(/(?:^|\n)[ \t]*version[ \t]*=[ \t]*["']([^"']+)["']/u)?.[1]; + } + return text.trim(); +} + +function changelogMentionsVersion(text, version) { + return text.split(/\r?\n/u).some((line) => { + const heading = line.match(/^##[ \t]+(?:\[)?([^\] (]+)(?:\])?(?:[ \t(]|$)/u)?.[1]; + return heading === version; + }); +} + +function changedFiles(repo, _parent, commit) { + return new Set(commitData(repo, commit, 'changed').split('\0').filter(Boolean)); +} + +function jsonPath(expression, context) { + if (typeof expression !== 'string' || !/^[$][.][A-Za-z0-9_.-]+$/u.test(expression)) { + throw error(`${context} must use a simple $.path.to.field expression`); + } + return expression.slice(2).split('.'); +} + +function pathKey(parts) { + return parts.map(String).join('\0'); +} + +function semanticDiffs(before, after, parts = []) { + if (Object.is(before, after)) return []; + const beforeObject = before !== null && typeof before === 'object'; + const afterObject = after !== null && typeof after === 'object'; + if (beforeObject && afterObject && Array.isArray(before) === Array.isArray(after)) { + const keys = new Set( + Array.isArray(before) + ? Array.from({ length: Math.max(before.length, after.length) }, (_value, index) => index) + : [...Object.keys(before), ...Object.keys(after)], + ); + return [...keys].flatMap((key) => semanticDiffs(before[key], after[key], [...parts, key])); + } + return [{ parts, before, after }]; +} + +function parseStructured(text, type, file, commit) { + try { + const value = + type === 'json' + ? JSON.parse(text) + : type === 'jsonc' + ? Bun.JSONC.parse(text) + : type === 'toml' + ? Bun.TOML.parse(text) + : Bun.YAML.parse(text); + if (value === null || typeof value !== 'object') { + throw new TypeError('root must be an object or array'); + } + return value; + } catch (cause) { + throw error(`${file} at ${commit} is invalid ${type.toUpperCase()}: ${cause.message}`); + } +} + +function versionTransition(before, after, transitions) { + if (typeof before !== 'string' || typeof after !== 'string') return false; + return transitions.some((transition) => { + if (!before.includes(transition.before) || !after.includes(transition.after)) return false; + return ( + before.replaceAll(transition.before, '') === + after.replaceAll(transition.after, '') + ); + }); +} + +function structuredRuleKey(type, file, parts) { + return `${type}\0${file}\0${pathKey(parts)}`; +} + +function derivedVersionRules() { + if (cachedDerivedRules !== undefined) return cachedDerivedRules; + const products = loadProducts(TOOL); + const structured = new Map(); + const text = new Map(); + const addStructured = (type, file, parts, sourceProduct, wrapped = false) => { + const key = structuredRuleKey(type, file, parts); + const prior = structured.get(key); + if ( + prior !== undefined && + (prior.sourceProduct !== sourceProduct || prior.wrapped !== wrapped) + ) { + throw error(`conflicting derived version rules for ${file}:${parts.join('.')}`); + } + structured.set(key, { sourceProduct, wrapped }); + if ( + type === 'json' && + file.endsWith('/package.json') && + [ + 'version', + 'dependencies', + 'devDependencies', + 'optionalDependencies', + 'peerDependencies', + ].includes(parts[0]) + ) { + structured.set( + structuredRuleKey('jsonc', 'bun.lock', ['workspaces', path.posix.dirname(file), ...parts]), + { sourceProduct, wrapped }, + ); + } + }; + const addText = (file, rule) => { + const prior = text.get(file); + if (prior !== undefined && JSON.stringify(prior) !== JSON.stringify(rule)) { + throw error(`conflicting derived text version rules for ${file}`); + } + text.set(file, rule); + }; + + for (const entry of compatibilityVersionEntries(products, { + requireSourceProduct: true, + prefix: TOOL, + })) { + const separator = entry.parser.indexOf(':'); + const parser = separator === -1 ? entry.parser : entry.parser.slice(0, separator); + const expression = separator === -1 ? '' : entry.parser.slice(separator + 1); + if (parser === 'json' || parser === 'toml') { + addStructured(parser, entry.path, expression.split('.'), entry.sourceProduct); + } else if (parser === 'raw') { + addText(entry.path, { type: 'raw', sourceProduct: entry.sourceProduct }); + } else if (parser === 'rust-const') { + addText(entry.path, { + type: 'rust-const', + name: expression, + sourceProduct: entry.sourceProduct, + }); + } else { + throw error( + `${entry.id} uses unsupported compatibility parser ${JSON.stringify(entry.parser)}`, + ); + } + } + + for (const { file, product, prefix, suffix } of SDK_INSTALL_VERSION_RULES) { + addText(file, { type: 'embedded', sourceProduct: product, prefix, suffix }); + } + + for (const { + file, + versionPaths, + sourceProduct, + wrapped, + } of exampleCargoReleaseVersionBindings()) { + for (const parts of versionPaths) { + addStructured('toml', file, parts, sourceProduct, wrapped); + } + } + + for (const { packageName, product } of nativeToolsOptionalPackageProducts(TOOL)) { + addStructured( + 'json', + 'src/postgres-tools/native/npm/package.json', + ['optionalDependencies', packageName], + product, + true, + ); + } + + for (const { packageName } of electronReleaseDependencies(ROOT)) { + const owners = Object.keys(products) + .flatMap((product) => registryPackageRows({ product, packageKind: 'npm' }, TOOL)) + .filter((row) => row.packageName === packageName) + .map((row) => row.product); + if (owners.length !== 1) { + throw error( + `Electron release dependency ${packageName} must map to exactly one release product; ` + + `got ${owners.join(', ') || 'none'}`, + ); + } + addStructured( + 'json', + 'src/examples/electron/package.json', + ['dependencies', packageName], + owners[0], + ); + } + + cachedDerivedRules = { structured, text }; + return cachedDerivedRules; +} + +function productTransition(rule, before, after, transitions) { + const transition = transitions.find(({ product }) => product === rule.sourceProduct); + if (transition === undefined) return false; + return rule.wrapped + ? versionTransition(before, after, [transition]) + : before === transition.before && after === transition.after; +} + +function embeddedTextTransition(rule, before, after, transitions) { + const transition = transitions.find(({ product }) => product === rule.sourceProduct); + if (transition === undefined) return false; + const prior = `${rule.prefix}${transition.before}${rule.suffix}`; + const next = `${rule.prefix}${transition.after}${rule.suffix}`; + return before.split(prior).length === 2 && after === before.replace(prior, next); +} + +function valueAt(root, parts) { + let current = root; + for (const part of parts) { + if (current === null || typeof current !== 'object') return undefined; + current = current[part]; + } + return current; +} + +function cargoDependencyEntryPath(parts) { + const names = parts.map(String); + if (names.length === 3 && CARGO_DEPENDENCY_TABLES.has(names[0]) && names[2] === 'version') { + return names.slice(0, 2); + } + if ( + names.length === 5 && + names[0] === 'target' && + CARGO_DEPENDENCY_TABLES.has(names[2]) && + names[4] === 'version' + ) { + return names.slice(0, 4); + } + return undefined; +} + +function parseCargoManifest(repo, commit, file) { + return parseStructured(show(repo, commit, file), 'toml', file, commit); +} + +function cargoDependencyVersionChange({ + repo, + parent, + commit, + file, + parts, + beforeRoot, + afterRoot, + before, + after, +}) { + if (path.posix.basename(file) !== 'Cargo.toml') return false; + const entryPath = cargoDependencyEntryPath(parts); + if (entryPath === undefined) return false; + const priorEntry = valueAt(beforeRoot, entryPath); + const nextEntry = valueAt(afterRoot, entryPath); + if ( + priorEntry === null || + Array.isArray(priorEntry) || + typeof priorEntry !== 'object' || + nextEntry === null || + Array.isArray(nextEntry) || + typeof nextEntry !== 'object' || + typeof priorEntry.path !== 'string' || + priorEntry.path !== nextEntry.path + ) { + return false; + } + const dependencyManifest = path.posix.normalize( + path.posix.join(path.posix.dirname(file), priorEntry.path, 'Cargo.toml'), + ); + if ( + dependencyManifest === '..' || + dependencyManifest.startsWith('../') || + path.posix.isAbsolute(dependencyManifest) + ) + return false; + const priorPackage = parseCargoManifest(repo, parent, dependencyManifest).package; + const nextPackage = parseCargoManifest(repo, commit, dependencyManifest).package; + if ( + priorPackage === null || + Array.isArray(priorPackage) || + typeof priorPackage !== 'object' || + nextPackage === null || + Array.isArray(nextPackage) || + typeof nextPackage !== 'object' || + typeof priorPackage.version !== 'string' || + typeof nextPackage.version !== 'string' || + priorPackage.name !== nextPackage.name + ) { + return false; + } + const exact = typeof before === 'string' && before.startsWith('='); + return ( + before === `${exact ? '=' : ''}${priorPackage.version}` && + after === `${exact ? '=' : ''}${nextPackage.version}` + ); +} + +function localCargoPackageVersions(repo, commit, cache) { + if (cache.has(commit)) return cache.get(commit); + const versions = new Map(); + const manifests = commitData(repo, commit, 'files') + .split('\0') + .filter((file) => file === 'Cargo.toml' || file.endsWith('/Cargo.toml')); + for (const file of manifests) { + const packageConfig = parseCargoManifest(repo, commit, file).package; + if ( + packageConfig === null || + Array.isArray(packageConfig) || + typeof packageConfig !== 'object' || + typeof packageConfig.name !== 'string' || + typeof packageConfig.version !== 'string' + ) { + continue; + } + const packageVersions = versions.get(packageConfig.name) ?? new Set(); + packageVersions.add(packageConfig.version); + versions.set(packageConfig.name, packageVersions); + } + cache.set(commit, versions); + return versions; +} + +function cargoLockVersionChange({ + repo, + parent, + commit, + file, + parts, + beforeRoot, + afterRoot, + before, + after, + cargoVersions, +}) { + const names = parts.map(String); + if ( + path.posix.basename(file) !== 'Cargo.lock' || + names.length !== 3 || + names[0] !== 'package' || + !/^[0-9]+$/u.test(names[1]) || + names[2] !== 'version' + ) { + return false; + } + const priorPackage = valueAt(beforeRoot, ['package', Number(names[1])]); + const nextPackage = valueAt(afterRoot, ['package', Number(names[1])]); + if ( + priorPackage === null || + Array.isArray(priorPackage) || + typeof priorPackage !== 'object' || + nextPackage === null || + Array.isArray(nextPackage) || + typeof nextPackage !== 'object' || + typeof priorPackage.name !== 'string' || + priorPackage.name !== nextPackage.name || + priorPackage.source !== undefined || + nextPackage.source !== undefined + ) { + return false; + } + return ( + localCargoPackageVersions(repo, parent, cargoVersions).get(priorPackage.name)?.has(before) === + true && + localCargoPackageVersions(repo, commit, cargoVersions).get(priorPackage.name)?.has(after) === + true + ); +} + +function authorizedDerivedStructuredChange(context, rules) { + if ( + context.type === 'json' && + context.file === 'release-please-config.json' && + pathKey(context.parts) === 'bootstrap-sha' && + context.before === RELEASE_PLEASE_BOOTSTRAP_SHA && + context.after === undefined && + context.transitions.length > 0 + ) { + return true; + } + const rule = rules.structured.get(structuredRuleKey(context.type, context.file, context.parts)); + if (rule !== undefined) + return productTransition(rule, context.before, context.after, context.transitions); + if (context.type !== 'toml') return false; + return cargoDependencyVersionChange(context) || cargoLockVersionChange(context); +} + +function structuredType(file) { + const basename = path.posix.basename(file); + if (file === 'release-please-config.json' || basename === 'package.json') return 'json'; + if (basename === 'bun.lock') return 'jsonc'; + if (basename === 'Cargo.toml' || basename === 'Cargo.lock' || file.endsWith('.toml')) + return 'toml'; + return undefined; +} + +function maskGenericVersion(text, file, commit) { + const single = text.split(/\r?\n/u).filter((line) => line.includes('x-release-please-version')); + if (single.length === 1) { + const versions = single[0].match(/[0-9]+[.][0-9]+[.][0-9]+(?:[-+][0-9A-Za-z.-]+)?/gu) ?? []; + if (versions.length !== 1) + throw error(`${file} at ${commit} release version marker must contain exactly one version`); + return { + version: versions[0], + text: text.replace(single[0], single[0].replace(versions[0], '')), + }; + } + const block = /x-release-please-start-version(?[\s\S]*?)x-release-please-end/u.exec(text) + ?.groups?.body; + if (single.length !== 0 || block === undefined) + throw error(`${file} at ${commit} must contain one Release Please version marker`); + const versions = block.match(/[0-9]+[.][0-9]+[.][0-9]+(?:[-+][0-9A-Za-z.-]+)?/gu) ?? []; + if (versions.length !== 1) + throw error(`${file} at ${commit} release version block must contain exactly one version`); + return { + version: versions[0], + text: text.replace(block, block.replace(versions[0], '')), + }; +} + +function validateTextSemanticDiff({ + repo, + parent, + commit, + file, + fields, + derived, + transitions, + derivedRules, +}) { + const before = show(repo, parent, file); + const after = show(repo, commit, file); + if (fields.some(({ type }) => type === 'raw')) { + const field = fields.find(({ type }) => type === 'raw'); + if (before.trim() !== field.before || after.trim() !== field.after) { + throw error(`canonical version file ${file} contains a non-version semantic change`); + } + return; + } + if (fields.some(({ type }) => type === 'generic')) { + const prior = maskGenericVersion(before, file, parent); + const next = maskGenericVersion(after, file, commit); + if ( + prior.text !== next.text || + !fields.some( + ({ before: oldVersion, after: newVersion }) => + prior.version === oldVersion && next.version === newVersion, + ) + ) { + throw error(`Release Please generic file ${file} contains a non-version semantic change`); + } + return; + } + const derivedRule = derived ? derivedRules.text.get(file) : undefined; + if (derivedRule?.type === 'rust-const') { + const pattern = new RegExp( + `(const\\s+${derivedRule.name.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}\\s*:\\s*&str\\s*=\\s*")([^"]+)(";)`, + 'u', + ); + const prior = pattern.exec(before); + const next = pattern.exec(after); + if ( + prior === null || + next === null || + !productTransition(derivedRule, prior[2], next[2], transitions) || + before.replace(pattern, '$1$3') !== + after.replace(pattern, '$1$3') + ) { + throw error(`derived file ${file} contains a non-version semantic change`); + } + return; + } + if ( + derivedRule?.type === 'raw' && + productTransition(derivedRule, before.trim(), after.trim(), transitions) && + before.replace(before.trim(), '') === + after.replace(after.trim(), '') + ) { + return; + } + if ( + derivedRule?.type === 'embedded' && + embeddedTextTransition(derivedRule, before, after, transitions) + ) + return; + throw error( + `${derived ? 'derived file' : 'release file'} ${file} contains a non-version semantic change`, + ); +} + +function validateAllowedFileSemantics({ + repo, + parent, + commit, + changed, + changelogs, + fieldsByFile, + derivedFiles, + transitions, +}) { + const derivedRules = derivedVersionRules(); + const cargoVersions = new Map(); + for (const file of changed) { + if (file === '.release-please-manifest.json' || changelogs.has(file)) continue; + const fields = fieldsByFile.get(file) ?? []; + const derived = derivedFiles.has(file); + const type = structuredType(file); + if (type === undefined) { + validateTextSemanticDiff({ + repo, + parent, + commit, + file, + fields, + derived, + transitions, + derivedRules, + }); + continue; + } + const before = parseStructured(show(repo, parent, file), type, file, parent); + const after = parseStructured(show(repo, commit, file), type, file, commit); + const releaseFields = new Map( + fields + .filter(({ parts }) => parts !== undefined) + .map((field) => [pathKey(field.parts), field]), + ); + for (const difference of semanticDiffs(before, after)) { + const releaseField = releaseFields.get(pathKey(difference.parts)); + if (releaseField !== undefined) { + if (difference.before !== releaseField.before || difference.after !== releaseField.after) { + throw error( + `${releaseField.role} ${file} contains a non-version semantic change at ${difference.parts.join('.')}`, + ); + } + continue; + } + if ( + derived && + authorizedDerivedStructuredChange( + { + repo, + parent, + commit, + file, + type, + parts: difference.parts, + beforeRoot: before, + afterRoot: after, + before: difference.before, + after: difference.after, + transitions, + cargoVersions, + }, + derivedRules, + ) + ) + continue; + const label = fields.some(({ role }) => role === 'canonical version file') + ? 'canonical version file' + : derived + ? 'derived file' + : 'release file'; + throw error( + `${label} ${file} contains a non-version semantic change at ${difference.parts.join('.') || ''}`, + ); + } + } +} + +export function deriveReleaseProducts({ repo = ROOT, headRef = 'HEAD' } = {}) { + const commit = releaseCommit(repo, headRef); + const ancestry = commitData(repo, commit, 'ancestry').trimEnd().split(/\s+/u); + if (ancestry.length !== 2) { + throw error( + `release commit ${commit} must have exactly one parent, found ${Math.max(0, ancestry.length - 1)}`, + ); + } + const parent = ancestry[1]; + const config = showJson(repo, commit, 'release-please-config.json'); + const before = showJson(repo, parent, '.release-please-manifest.json'); + const after = showJson(repo, commit, '.release-please-manifest.json'); + return { commit, parent, products: releaseProductsFromManifests(config, before, after) }; +} + +export function releaseProductsFromManifests(config, before, after) { + for (const [name, value] of Object.entries({ config, before, after })) { + if (value === null || typeof value !== 'object' || Array.isArray(value)) + throw error(`${name} must contain a JSON object`); + } + const packageConfigs = config.packages; + if ( + packageConfigs === null || + Array.isArray(packageConfigs) || + typeof packageConfigs !== 'object' + ) { + throw error('release-please-config.json must define a packages object'); + } + const byPath = new Map(); + const products = new Set(); + for (const [packagePath, packageConfig] of Object.entries(packageConfigs)) { + if ( + packageConfig === null || + Array.isArray(packageConfig) || + typeof packageConfig !== 'object' + ) { + throw error(`release-please package ${packagePath} must be an object`); + } + const product = packageConfig.component; + if (typeof product !== 'string' || product.length === 0 || products.has(product)) { + throw error(`release-please package ${packagePath} has a missing or duplicate component`); + } + products.add(product); + byPath.set(packagePath, product); + } + const changedProducts = [...new Set([...Object.keys(before), ...Object.keys(after)])] + .filter((packagePath) => before[packagePath] !== after[packagePath]) + .map((packagePath) => { + const product = byPath.get(packagePath); + if (product === undefined) { + throw error(`release manifest changed unknown package path ${packagePath}`); + } + return product; + }) + .sort(compareText); + if (changedProducts.length === 0) { + throw error('release commit must advance at least one release-please manifest version'); + } + return changedProducts; +} + +export function verifyReleaseCommit({ repo = ROOT, headRef = 'HEAD', products }) { + if ( + !Array.isArray(products) || + products.length === 0 || + products.some((item) => typeof item !== 'string' || item.length === 0) + ) { + throw error('products must be a non-empty product string list'); + } + const selected = [...new Set(products)].sort(compareText); + if (selected.length !== products.length) { + throw error('products must not contain duplicates'); + } + + const commit = releaseCommit(repo, headRef); + const ancestry = commitData(repo, commit, 'ancestry').trimEnd().split(/\s+/u); + if (ancestry.length !== 2) { + throw error( + `release commit ${commit} must have exactly one parent, found ${Math.max(0, ancestry.length - 1)}`, + ); + } + const parent = ancestry[1]; + const subject = commitData(repo, commit, 'subject').trimEnd(); + if (!/^chore\(release\): .+/u.test(subject)) { + throw error( + `release commit ${commit} subject must start with "chore(release): "; got ${JSON.stringify(subject)}`, + ); + } + + const config = showJson(repo, commit, 'release-please-config.json'); + const packageConfigs = config.packages; + if ( + packageConfigs === null || + Array.isArray(packageConfigs) || + typeof packageConfigs !== 'object' + ) { + throw error('release-please-config.json must define a packages object'); + } + const byProduct = new Map(); + const byPath = new Map(); + for (const [packagePath, packageConfig] of Object.entries(packageConfigs)) { + if ( + packageConfig === null || + Array.isArray(packageConfig) || + typeof packageConfig !== 'object' + ) { + throw error(`release-please package ${packagePath} must be an object`); + } + const product = packageConfig.component; + if (typeof product !== 'string' || product.length === 0 || byProduct.has(product)) { + throw error(`release-please package ${packagePath} has a missing or duplicate component`); + } + byProduct.set(product, { packagePath, config: packageConfig }); + byPath.set(packagePath, product); + } + for (const product of selected) { + if (!byProduct.has(product)) { + throw error(`selected release product ${product} is absent from release-please-config.json`); + } + } + + const before = showJson(repo, parent, '.release-please-manifest.json'); + const after = showJson(repo, commit, '.release-please-manifest.json'); + const changedPaths = [...new Set([...Object.keys(before), ...Object.keys(after)])] + .filter((packagePath) => before[packagePath] !== after[packagePath]) + .sort(compareText); + const changedProducts = changedPaths + .map((packagePath) => { + const product = byPath.get(packagePath); + if (product === undefined) { + throw error(`release manifest changed unknown package path ${packagePath}`); + } + return product; + }) + .sort(compareText); + if (!sameStrings(changedProducts, selected)) { + throw error( + `selected products do not exactly match this commit's release bumps: selected=${JSON.stringify(selected)}, bumped=${JSON.stringify(changedProducts)}`, + ); + } + + const changed = changedFiles(repo, parent, commit); + if (!changed.has('.release-please-manifest.json')) { + throw error('release commit must change .release-please-manifest.json'); + } + const versions = {}; + const derivedFiles = new Set(releaseDerivedPathInventory()); + const allowedChangedFiles = new Set(['.release-please-manifest.json', ...derivedFiles]); + const fieldsByFile = new Map(); + const changelogs = new Set(); + const transitions = []; + const addField = (file, field) => + fieldsByFile.set(file, [...(fieldsByFile.get(file) ?? []), field]); + for (const product of selected) { + const { packagePath, config: packageConfig } = byProduct.get(product); + const version = after[packagePath]; + const priorVersion = before[packagePath]; + if ( + typeof priorVersion !== 'string' || + !SEMVER.test(priorVersion) || + typeof version !== 'string' || + !SEMVER.test(version) || + Bun.semver.order(version, priorVersion) <= 0 + ) { + throw error(`${product} must advance to a semver version in .release-please-manifest.json`); + } + const versionFile = canonicalVersionFile(packagePath, packageConfig, product); + const changelogFile = relativeFile( + packagePath, + packageConfig['changelog-path'] ?? 'CHANGELOG.md', + `${product}.changelog-path`, + ); + if (!changed.has(versionFile)) { + throw error(`${product} release commit did not change canonical version file ${versionFile}`); + } + if (!changed.has(changelogFile)) { + throw error(`${product} release commit did not change changelog ${changelogFile}`); + } + allowedChangedFiles.add(versionFile); + allowedChangedFiles.add(changelogFile); + changelogs.add(changelogFile); + transitions.push({ product, before: priorVersion, after: version }); + if (packageConfig['release-type'] === 'node' || packageConfig['release-type'] === 'expo') { + if (changed.has('bun.lock')) + addField('bun.lock', { + type: 'jsonc', + parts: ['workspaces', packagePath, 'version'], + before: priorVersion, + after: version, + role: 'workspace lock version', + }); + addField(versionFile, { + type: 'json', + parts: ['version'], + before: priorVersion, + after: version, + role: 'canonical version file', + }); + } else if (packageConfig['release-type'] === 'rust' && !packageConfig['version-file']) { + addField(versionFile, { + type: 'toml', + parts: ['package', 'version'], + before: priorVersion, + after: version, + role: 'canonical version file', + }); + } else { + addField(versionFile, { + type: 'raw', + before: priorVersion, + after: version, + role: 'canonical version file', + }); + } + for (const [index, entry] of (packageConfig['extra-files'] ?? []).entries()) { + const extraPath = typeof entry === 'string' ? entry : entry?.path; + const file = relativeFile(packagePath, extraPath, `${product}.extra-files[${index}]`); + allowedChangedFiles.add(file); + const type = typeof entry === 'string' ? 'generic' : (entry.type ?? 'generic'); + const field = { type, before: priorVersion, after: version, role: `${product} extra file` }; + if (type === 'json' || type === 'toml') { + field.parts = jsonPath(entry.jsonpath, `${product}.extra-files[${index}].jsonpath`); + } + addField(file, field); + } + const fileVersion = versionFromCanonicalFile( + show(repo, commit, versionFile), + packageConfig, + versionFile, + product, + ); + if (fileVersion !== version) { + throw error( + `${product} canonical version file ${versionFile} contains ${JSON.stringify(fileVersion)}, expected ${version}`, + ); + } + if (!changelogMentionsVersion(show(repo, commit, changelogFile), version)) { + throw error(`${product} changelog ${changelogFile} has no release heading for ${version}`); + } + versions[product] = version; + } + + const unexpected = [...changed] + .filter((file) => !allowedChangedFiles.has(file)) + .sort(compareText); + if (unexpected.length > 0) { + throw error( + `release-bump commit contains non-release-derived path(s): ${unexpected.join(', ')}; ` + + "only Release Please version/changelog/extra-file outputs and sync-release-pr's structured derived-path inventory are allowed", + ); + } + + validateAllowedFileSemantics({ + repo, + parent, + commit, + changed, + changelogs, + fieldsByFile, + derivedFiles, + transitions, + }); + + return { + commit, + parent, + products: selected, + versions, + verifiedDerivedPaths: [...changed].filter((file) => derivedFiles.has(file)).sort(compareText), + }; +} + +export function latestVerifiedReleaseCommit({ repo = ROOT, headRef = 'HEAD' } = {}) { + const { release, commit } = releaseHistory(repo); + if (releaseCommit(repo, headRef) !== commit) + throw error('latest release history belongs to another head'); + if (release === '') return null; + const { products } = deriveReleaseProducts({ repo, headRef: release }); + return verifyReleaseCommit({ repo, headRef: release, products }); +} + +function parseArgs(argv) { + let repo = ROOT; + let productsJson = ''; + let headRef = 'HEAD'; + let deriveProducts = false; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--repo') { + repo = path.resolve(argv[++index] ?? ''); + } else if (arg === '--products-json') { + productsJson = argv[index + 1] ?? ''; + index += 1; + } else if (arg === '--derive-products') { + deriveProducts = true; + } else if (arg === '--head-ref') { + headRef = argv[index + 1] ?? ''; + index += 1; + } else { + throw error(`unknown argument ${arg}`); + } + } + if (!headRef || deriveProducts === Boolean(productsJson)) { + throw error( + 'usage: verify-release-commit.mts (--products-json JSON | --derive-products) [--head-ref REF] [--repo PATH]', + ); + } + if (deriveProducts) return { deriveProducts, headRef, repo }; + let products; + try { + products = JSON.parse(productsJson); + } catch (cause) { + throw error(`--products-json must be valid JSON: ${cause.message}`); + } + return { deriveProducts, headRef, products, repo }; +} + +if (import.meta.main) { + try { + if (process.argv[2] === '--manifest-transition') { + if (process.argv.length !== 6) + throw error('usage: verify-release-commit.mts --manifest-transition CONFIG BEFORE AFTER'); + console.log( + JSON.stringify( + releaseProductsFromManifests( + ...process.argv.slice(3).map((file) => JSON.parse(readFileSync(file, 'utf8'))), + ), + ), + ); + process.exit(0); + } + if (process.argv[2] === '--snapshot-paths') { + snapshotPaths(); + process.exit(0); + } + const args = parseArgs(Bun.argv.slice(2)); + if (args.deriveProducts) { + console.log(JSON.stringify(deriveReleaseProducts(args).products)); + } else { + const verified = verifyReleaseCommit(args); + console.log( + `verified release-bump commit ${verified.commit} for ${verified.products.length} product(s): ${verified.products.join(', ')}`, + ); + } + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exit(1); + } +} diff --git a/tools/release/verify-release-commit.test.mjs b/tools/release/verify-release-commit.test.mjs deleted file mode 100644 index 0b8fccb93..000000000 --- a/tools/release/verify-release-commit.test.mjs +++ /dev/null @@ -1,535 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import { execFileSync } from "../test/fd-backed-spawn-sync.mjs"; -import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import test from "node:test"; - -import { RELEASE_PLEASE_BOOTSTRAP_SHA } from "./release-please-bootstrap.mjs"; -import { - deriveReleaseProducts, - latestVerifiedReleaseCommit, - verifyReleaseCommit, -} from "./verify-release-commit.mjs"; - -const RELEASE_PRODUCT = "oliphaunt-broker"; -const KNOWN_DERIVED_PACKAGE = "@oliphaunt/broker-linux-x64-gnu"; -const UNRELATED_DERIVED_PACKAGE = "@oliphaunt/unrelated"; - -function git(repo, ...args) { - return execFileSync("git", args, { cwd: repo, encoding: "utf8" }).trim(); -} - -function write(repo, file, contents) { - const target = path.join(repo, file); - mkdirSync(path.dirname(target), { recursive: true }); - writeFileSync(target, contents); -} - -function commit(repo, subject) { - git(repo, "add", "."); - git(repo, "commit", "-m", subject); - return git(repo, "rev-parse", "HEAD"); -} - -test("permits only the exact one-time bootstrap-sha removal in a release commit", { timeout: 20_000 }, () => { - const repo = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-bootstrap-")); - git(repo, "init", "-q"); - git(repo, "config", "user.name", "Release Test"); - git(repo, "config", "user.email", "release@example.invalid"); - const config = (bootstrapSha) => `${JSON.stringify({ - ...(bootstrapSha === undefined ? {} : { "bootstrap-sha": bootstrapSha }), - packages: { - "packages/alpha": { - "release-type": "simple", - component: RELEASE_PRODUCT, - "version-file": "VERSION", - "changelog-path": "CHANGELOG.md", - }, - }, - }, null, 2)}\n`; - write(repo, "release-please-config.json", config(RELEASE_PLEASE_BOOTSTRAP_SHA)); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.0.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n"); - const base = commit(repo, "feat: introduce bootstrap fixture"); - assert.equal(latestVerifiedReleaseCommit({ repo, headRef: base }), null); - - const writeRelease = (bootstrapSha) => { - write(repo, "release-please-config.json", config(bootstrapSha)); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.1.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.1.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n"); - }; - - writeRelease(undefined); - const clean = commit(repo, "chore(release): prepare bootstrap release"); - assert.deepEqual( - verifyReleaseCommit({ repo, headRef: clean, products: [RELEASE_PRODUCT] }).products, - [RELEASE_PRODUCT], - ); - - git(repo, "switch", "-q", "-c", "mutated-bootstrap", base); - writeRelease("1111111111111111111111111111111111111111"); - const mutated = commit(repo, "chore(release): prepare mutated bootstrap release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: mutated, products: [RELEASE_PRODUCT] }), - /release-please-config[.]json contains a non-version semantic change/u, - ); -}); - -test("accepts the exact one-parent release-bump commit and exact selected product set", { timeout: 20_000 }, () => { - const repo = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-commit-")); - git(repo, "init", "-q"); - git(repo, "config", "user.name", "Release Test"); - git(repo, "config", "user.email", "release@example.invalid"); - write(repo, "release-please-config.json", `${JSON.stringify({ - packages: { - "packages/alpha": { "release-type": "simple", component: RELEASE_PRODUCT, "version-file": "VERSION", "changelog-path": "CHANGELOG.md" }, - "packages/beta": { "release-type": "node", component: "beta", "changelog-path": "CHANGELOG.md" }, - }, - }, null, 2)}\n`); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.0.0","packages/beta":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.0.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n"); - write(repo, "packages/beta/package.json", '{"name":"beta","version":"0.0.0"}\n'); - write(repo, "packages/beta/CHANGELOG.md", "# Changelog\n"); - write(repo, "src/removable.rs", "pub fn must_not_disappear() {}\n"); - write(repo, "src/future-version.txt", "0.1.0\n"); - write(repo, "src/sdks/js/package.json", `${JSON.stringify({ - name: "shadow-derived", - oliphaunt: { brokerVersion: "0.0.0" }, - optionalDependencies: { - [KNOWN_DERIVED_PACKAGE]: "workspace:*", - [UNRELATED_DERIVED_PACKAGE]: "workspace:*", - }, - dangerous: false, - })}\n`); - const base = commit(repo, "feat: introduce fixture"); - - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.1.0","packages/beta":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.1.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n\n- Initial release.\n"); - const release = commit(repo, "chore(release): prepare alpha release"); - - assert.deepEqual(deriveReleaseProducts({ repo, headRef: release }).products, [RELEASE_PRODUCT]); - - const verified = verifyReleaseCommit({ repo, headRef: release, products: [RELEASE_PRODUCT] }); - assert.deepEqual(verified.products, [RELEASE_PRODUCT]); - assert.equal(verified.versions[RELEASE_PRODUCT], "0.1.0"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: release, products: [RELEASE_PRODUCT, "beta"] }), - /do not exactly match/u, - ); - - write(repo, "fix.txt", "post-release fix\n"); - const laterFix = commit(repo, "fix(tools): repair publication"); - assert.equal(latestVerifiedReleaseCommit({ repo, headRef: laterFix }).commit, release); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: laterFix, products: [RELEASE_PRODUCT] }), - /subject must start/u, - "a bb7c release-bump followed by an a51c fix must be rejected before tag mutation", - ); - - git(repo, "switch", "-q", "-c", "release-downgrade", release); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.0.0","packages/beta":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.0.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n\n## 0.0.0 (2026-07-14)\n"); - const releaseDowngrade = commit(repo, "chore(release): prepare alpha downgrade"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: releaseDowngrade, products: [RELEASE_PRODUCT] }), - /must advance to a semver version/u, - ); - - git(repo, "switch", "-q", "-c", "tainted-release", `${release}^`); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.1.0","packages/beta":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.1.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n"); - write(repo, "src/fix.rs", "pub fn hidden_fix() {}\n"); - const tainted = commit(repo, "chore(release): prepare alpha release with hidden fix"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: tainted, products: [RELEASE_PRODUCT] }), - /non-release-derived path.*src\/fix[.]rs/u, - ); - - git(repo, "switch", "-q", "-c", "release-with-deletion", base); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.1.0","packages/beta":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.1.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n"); - git(repo, "rm", "src/removable.rs"); - const releaseWithDeletion = commit(repo, "chore(release): prepare alpha release with deletion"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: releaseWithDeletion, products: [RELEASE_PRODUCT] }), - /non-release-derived path.*src\/removable[.]rs/u, - ); - - git(repo, "switch", "-q", "-c", "release-with-hidden-rename", base); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.1.0","packages/beta":"0.0.0"}\n'); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n"); - git(repo, "rm", "packages/alpha/VERSION"); - git(repo, "mv", "src/future-version.txt", "packages/alpha/VERSION"); - const releaseWithHiddenRename = commit(repo, "chore(release): prepare alpha release with hidden rename"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: releaseWithHiddenRename, products: [RELEASE_PRODUCT] }), - /non-release-derived path.*src\/future-version[.]txt/u, - "a rename into an allowed release-derived path must still expose the renamed-away source", - ); - - git(repo, "switch", "-q", "-c", "hidden-version-config", base); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.0.0","packages/beta":"0.1.0"}\n'); - write(repo, "packages/beta/package.json", '{"name":"beta","version":"0.1.0","scripts":{"postinstall":"hidden-code"}}\n'); - write(repo, "packages/beta/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n"); - const hiddenVersionConfig = commit(repo, "chore(release): prepare beta release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: hiddenVersionConfig, products: ["beta"] }), - /canonical version file.*non-version semantic change/u, - ); - - git(repo, "switch", "-q", "-c", "hidden-derived-config", base); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.1.0","packages/beta":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.1.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n"); - write(repo, "src/sdks/js/package.json", `${JSON.stringify({ - name: "shadow-derived", - oliphaunt: { brokerVersion: "0.0.0" }, - optionalDependencies: { - [KNOWN_DERIVED_PACKAGE]: "workspace:*", - [UNRELATED_DERIVED_PACKAGE]: "workspace:*", - }, - dangerous: true, - })}\n`); - const hiddenDerivedConfig = commit(repo, "chore(release): prepare alpha release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: hiddenDerivedConfig, products: [RELEASE_PRODUCT] }), - /derived file.*non-version semantic change/u, - ); - - git(repo, "switch", "-q", "-c", "derived-version-only", base); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.1.0","packages/beta":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.1.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n"); - write(repo, "src/sdks/js/package.json", `${JSON.stringify({ - name: "shadow-derived", - oliphaunt: { brokerVersion: "0.1.0" }, - optionalDependencies: { - [KNOWN_DERIVED_PACKAGE]: "workspace:*", - [UNRELATED_DERIVED_PACKAGE]: "workspace:*", - }, - dangerous: false, - })}\n`); - const derivedVersionOnly = commit(repo, "chore(release): prepare alpha release"); - assert.deepEqual( - verifyReleaseCommit({ repo, headRef: derivedVersionOnly, products: [RELEASE_PRODUCT] }).products, - [RELEASE_PRODUCT], - ); - - git(repo, "switch", "-q", "-c", "unrelated-derived-dependency", base); - write(repo, ".release-please-manifest.json", '{"packages/alpha":"0.1.0","packages/beta":"0.0.0"}\n'); - write(repo, "packages/alpha/VERSION", "0.1.0\n"); - write(repo, "packages/alpha/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n"); - write(repo, "src/sdks/js/package.json", `${JSON.stringify({ - name: "shadow-derived", - oliphaunt: { brokerVersion: "0.0.0" }, - optionalDependencies: { - [KNOWN_DERIVED_PACKAGE]: "workspace:*", - [UNRELATED_DERIVED_PACKAGE]: "workspace:0.1.0", - }, - dangerous: false, - })}\n`); - const unrelatedDerivedDependency = commit(repo, "chore(release): prepare alpha release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: unrelatedDerivedDependency, products: [RELEASE_PRODUCT] }), - /derived file.*optionalDependencies[.]@oliphaunt\/unrelated/u, - "an unrelated dependency cannot borrow another product's coincident old/new version transition", - ); -}); - -test("binds derived Cargo pins and lock entries to the referenced local package", { timeout: 20_000 }, () => { - const repo = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-cargo-")); - const lockfile = "Cargo.lock"; - git(repo, "init", "-q"); - git(repo, "config", "user.name", "Release Test"); - git(repo, "config", "user.email", "release@example.invalid"); - write(repo, "release-please-config.json", `${JSON.stringify({ - packages: { - "src/runtimes/broker": { - "release-type": "rust", - component: RELEASE_PRODUCT, - "changelog-path": "CHANGELOG.md", - }, - }, - }, null, 2)}\n`); - write(repo, ".release-please-manifest.json", '{"src/runtimes/broker":"0.0.0"}\n'); - write(repo, "src/runtimes/broker/Cargo.toml", '[package]\nname = "oliphaunt-broker"\nversion = "0.0.0"\n'); - write(repo, "src/runtimes/broker/CHANGELOG.md", "# Changelog\n"); - write(repo, "src/shared/unrelated/Cargo.toml", '[package]\nname = "unrelated"\nversion = "0.0.0"\n'); - write( - repo, - "src/sdks/rust/Cargo.toml", - '[package]\nname = "shadow-sdk"\nversion = "0.0.0"\n\n[dependencies]\noliphaunt-broker = { path = "../../runtimes/broker", version = "0.0.0" }\nunrelated = { path = "../../shared/unrelated", version = "0.0.0" }\n', - ); - write(repo, lockfile, 'version = 4\n\n[[package]]\nname = "oliphaunt-broker"\nversion = "0.0.0"\n\n[[package]]\nname = "unrelated"\nversion = "0.0.0"\n'); - const base = commit(repo, "feat: introduce Cargo fixture"); - - const writeRelease = () => { - write(repo, ".release-please-manifest.json", '{"src/runtimes/broker":"0.1.0"}\n'); - write(repo, "src/runtimes/broker/Cargo.toml", '[package]\nname = "oliphaunt-broker"\nversion = "0.1.0"\n'); - write(repo, "src/runtimes/broker/CHANGELOG.md", "# Changelog\n\n## 0.1.0 (2026-07-14)\n"); - }; - - writeRelease(); - write( - repo, - "src/sdks/rust/Cargo.toml", - '[package]\nname = "shadow-sdk"\nversion = "0.0.0"\n\n[dependencies]\noliphaunt-broker = { path = "../../runtimes/broker", version = "0.1.0" }\nunrelated = { path = "../../shared/unrelated", version = "0.0.0" }\n', - ); - write(repo, lockfile, 'version = 4\n\n[[package]]\nname = "oliphaunt-broker"\nversion = "0.1.0"\n\n[[package]]\nname = "unrelated"\nversion = "0.0.0"\n'); - const exactCargoRelease = commit(repo, "chore(release): prepare broker release"); - assert.deepEqual( - verifyReleaseCommit({ repo, headRef: exactCargoRelease, products: [RELEASE_PRODUCT] }).products, - [RELEASE_PRODUCT], - ); - - git(repo, "switch", "-q", "-c", "unrelated-cargo-pin", base); - writeRelease(); - write( - repo, - "src/sdks/rust/Cargo.toml", - '[package]\nname = "shadow-sdk"\nversion = "0.0.0"\n\n[dependencies]\noliphaunt-broker = { path = "../../runtimes/broker", version = "0.1.0" }\nunrelated = { path = "../../shared/unrelated", version = "0.1.0" }\n', - ); - const unrelatedCargoPin = commit(repo, "chore(release): prepare broker release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: unrelatedCargoPin, products: [RELEASE_PRODUCT] }), - /derived file.*dependencies[.]unrelated[.]version/u, - ); - - git(repo, "switch", "-q", "-c", "unrelated-cargo-package-version", base); - writeRelease(); - write( - repo, - "src/sdks/rust/Cargo.toml", - '[package]\nname = "shadow-sdk"\nversion = "0.1.0"\n\n[dependencies]\noliphaunt-broker = { path = "../../runtimes/broker", version = "0.1.0" }\nunrelated = { path = "../../shared/unrelated", version = "0.0.0" }\n', - ); - const unrelatedCargoPackageVersion = commit(repo, "chore(release): prepare broker release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: unrelatedCargoPackageVersion, products: [RELEASE_PRODUCT] }), - /derived file.*package[.]version/u, - ); - - git(repo, "switch", "-q", "-c", "unrelated-cargo-lock", base); - writeRelease(); - write(repo, lockfile, 'version = 4\n\n[[package]]\nname = "oliphaunt-broker"\nversion = "0.1.0"\n\n[[package]]\nname = "unrelated"\nversion = "0.1.0"\n'); - const unrelatedCargoLock = commit(repo, "chore(release): prepare broker release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: unrelatedCargoLock, products: [RELEASE_PRODUCT] }), - /derived file.*package[.]1[.]version/u, - ); -}); - -test("keeps wildcard Cargo pins independent of release versions", { timeout: 20_000 }, (t) => { - const repo = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-cargo-wildcard-")); - t.after(() => rmSync(repo, { recursive: true, force: true })); - const packagePath = "src/runtimes/broker"; - const dependency = 'oliphaunt = { path = "../../sdks/rust", version = "*", features = [] }'; - const cargo = (version, entry) => `[package]\nname = "oliphaunt-broker"\nversion = "${version}"\n` - + ["dependencies", "dev-dependencies", "build-dependencies"].flatMap((table) => [ - `\n[${table}]\n${entry}\n`, - `\n[target.'cfg(unix)'.${table}]\n${entry}\n`, - ]).join(""); - git(repo, "init", "-q"); - git(repo, "config", "user.name", "Release Test"); - git(repo, "config", "user.email", "release@example.invalid"); - write(repo, "release-please-config.json", JSON.stringify({ - packages: { [packagePath]: { "release-type": "rust", component: RELEASE_PRODUCT } }, - })); - write(repo, ".release-please-manifest.json", JSON.stringify({ [packagePath]: "0.1.0" })); - write(repo, `${packagePath}/Cargo.toml`, cargo("0.1.0", dependency)); - write(repo, `${packagePath}/CHANGELOG.md`, "# Changelog\n"); - write(repo, "src/sdks/rust/Cargo.toml", '[package]\nname = "oliphaunt"\nversion = "0.2.0"\n'); - const base = commit(repo, "feat: introduce wildcard Cargo fixture"); - - const pinned = dependency.replace('"*"', '"0.2.0"'); - for (const [name, entry] of [ - ["workspace-wildcard", dependency], - ["local-version", pinned], - ["wrong-version", pinned.replace('"0.2.0"', '"0.3.0"')], - ["changed-path", pinned.replace("../../sdks/rust", "../../sdks/other")], - ["removed-path", pinned.replace('path = "../../sdks/rust", ', "")], - ["changed-features", pinned.replace("features = []", 'features = ["extra"]')], - ]) { - git(repo, "switch", "-q", "-c", name, base); - write(repo, ".release-please-manifest.json", JSON.stringify({ [packagePath]: "0.2.0" })); - write(repo, `${packagePath}/Cargo.toml`, cargo("0.2.0", entry)); - write(repo, `${packagePath}/CHANGELOG.md`, "# Changelog\n\n## 0.2.0\n"); - const headRef = commit(repo, "chore(release): prepare broker release"); - const verify = () => verifyReleaseCommit({ repo, headRef, products: [RELEASE_PRODUCT] }); - if (name === "workspace-wildcard") { - assert.deepEqual(verify().products, [RELEASE_PRODUCT]); - } else { - assert.throws(verify, /canonical version file.*non-version semantic change/u, name); - } - } -}); - -test("keeps WASIX tools workspace links independent of release versions", { timeout: 20_000 }, () => { - const repo = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-wasix-tools-")); - git(repo, "init", "-q"); - git(repo, "config", "user.name", "Release Test"); - git(repo, "config", "user.email", "release@example.invalid"); - write(repo, "release-please-config.json", `${JSON.stringify({ - packages: { - "src/runtimes/liboliphaunt/wasix": { - "release-type": "simple", - component: "liboliphaunt-wasix", - "version-file": "VERSION", - "changelog-path": "CHANGELOG.md", - }, - "src/bindings/wasix-ts": { - "release-type": "node", - component: "oliphaunt-wasix-ts", - "changelog-path": "CHANGELOG.md", - }, - }, - }, null, 2)}\n`); - const writeVersion = (version) => { - write(repo, ".release-please-manifest.json", `${JSON.stringify({ - "src/runtimes/liboliphaunt/wasix": version, - "src/bindings/wasix-ts": version, - })}\n`); - write(repo, "src/runtimes/liboliphaunt/wasix/VERSION", `${version}\n`); - write(repo, "src/runtimes/liboliphaunt/wasix/CHANGELOG.md", `# Changelog\n\n## ${version}\n`); - write(repo, "src/bindings/wasix-ts/package.json", `${JSON.stringify({ - name: "@oliphaunt/wasix-ts", - version, - })}\n`); - write(repo, "src/bindings/wasix-ts/CHANGELOG.md", `# Changelog\n\n## ${version}\n`); - write(repo, "src/bindings/wasix-ts/tools-package/package.json", `${JSON.stringify({ - dependencies: { "@oliphaunt/liboliphaunt-wasix-tools": "workspace:*" }, - peerDependencies: { "@oliphaunt/wasix-ts": "workspace:*" }, - devDependencies: { "@oliphaunt/wasix-ts": "workspace:*" }, - })}\n`); - write(repo, "pnpm-lock.yaml", `lockfileVersion: '9.0'\nimporters:\n src/bindings/wasix-ts/tools-package:\n dependencies:\n '@oliphaunt/liboliphaunt-wasix-tools':\n specifier: workspace:*\n version: link:../../../runtimes/liboliphaunt/wasix/tools-npm\n devDependencies:\n '@oliphaunt/wasix-ts':\n specifier: workspace:*\n version: link:..\n`); - }; - writeVersion("0.1.0"); - commit(repo, "feat: introduce WASIX tools fixture"); - writeVersion("0.2.0"); - const release = commit(repo, "chore(release): prepare WASIX releases"); - - assert.deepEqual( - verifyReleaseCommit({ - repo, - headRef: release, - products: ["liboliphaunt-wasix", "oliphaunt-wasix-ts"], - }).products, - ["liboliphaunt-wasix", "oliphaunt-wasix-ts"], - ); -}); - -test("binds example Cargo registry pins and runtime metadata to their release product", { timeout: 20_000 }, () => { - const repo = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-release-example-cargo-")); - const nativeProduct = "liboliphaunt-native"; - const nativePath = "src/runtimes/liboliphaunt/native"; - const brokerProduct = "oliphaunt-broker"; - const brokerPath = "src/runtimes/broker"; - const exampleManifest = "examples/tauri/src-tauri/Cargo.toml"; - const target = "cfg(all(target_os = \"linux\", target_arch = \"x86_64\", target_env = \"gnu\"))"; - - const releaseConfig = `${JSON.stringify({ - packages: { - [nativePath]: { - "release-type": "simple", - component: nativeProduct, - "version-file": "VERSION", - "changelog-path": "CHANGELOG.md", - }, - [brokerPath]: { - "release-type": "simple", - component: brokerProduct, - "version-file": "VERSION", - "changelog-path": "CHANGELOG.md", - }, - }, - }, null, 2)}\n`; - const releaseManifest = (nativeVersion, brokerVersion) => `${JSON.stringify({ - [nativePath]: nativeVersion, - [brokerPath]: brokerVersion, - })}\n`; - const exampleCargo = ({ carrierVersion, runtimeVersion = carrierVersion, unrelatedVersion = "9.0.0" }) => `[package] -name = "release-example" -version = "0.0.0" - -[package.metadata.oliphaunt] -runtime = "liboliphaunt-native" -runtime-version = "${runtimeVersion}" - -[target.'${target}'.dependencies] -liboliphaunt-native-linux-x64-gnu = { version = "=${carrierVersion}" } -unrelated = { version = "${unrelatedVersion}" } -`; - - git(repo, "init", "-q"); - git(repo, "config", "user.name", "Release Test"); - git(repo, "config", "user.email", "release@example.invalid"); - write(repo, "release-please-config.json", releaseConfig); - write(repo, ".release-please-manifest.json", releaseManifest("0.1.0", "0.1.0")); - write(repo, `${nativePath}/VERSION`, "0.1.0\n"); - write(repo, `${nativePath}/CHANGELOG.md`, "# Changelog\n"); - write(repo, `${brokerPath}/VERSION`, "0.1.0\n"); - write(repo, `${brokerPath}/CHANGELOG.md`, "# Changelog\n"); - write(repo, exampleManifest, exampleCargo({ carrierVersion: "0.1.0" })); - const base = commit(repo, "feat: introduce registry example fixture"); - - const writeNativeRelease = ({ - carrierVersion = "0.1.1", - runtimeVersion = "0.1.1", - unrelatedVersion = "9.0.0", - } = {}) => { - write(repo, ".release-please-manifest.json", releaseManifest("0.1.1", "0.1.0")); - write(repo, `${nativePath}/VERSION`, "0.1.1\n"); - write(repo, `${nativePath}/CHANGELOG.md`, "# Changelog\n\n## 0.1.1 (2026-08-08)\n"); - write(repo, exampleManifest, exampleCargo({ carrierVersion, runtimeVersion, unrelatedVersion })); - }; - - writeNativeRelease(); - const exact = commit(repo, "chore(release): prepare exact registry example release"); - assert.deepEqual( - verifyReleaseCommit({ repo, headRef: exact, products: [nativeProduct] }).products, - [nativeProduct], - ); - - git(repo, "switch", "-q", "-c", "wrong-registry-version", base); - writeNativeRelease({ carrierVersion: "0.1.2" }); - const wrongRegistryVersion = commit(repo, "chore(release): prepare wrong registry example release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: wrongRegistryVersion, products: [nativeProduct] }), - /derived file.*liboliphaunt-native-linux-x64-gnu[.]version/u, - ); - - git(repo, "switch", "-q", "-c", "wrong-runtime-version", base); - writeNativeRelease({ runtimeVersion: "0.1.2" }); - const wrongRuntimeVersion = commit(repo, "chore(release): prepare wrong runtime example release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: wrongRuntimeVersion, products: [nativeProduct] }), - /derived file.*runtime-version/u, - ); - - git(repo, "switch", "-q", "-c", "unrelated-registry-version", base); - writeNativeRelease({ unrelatedVersion: "9.0.1" }); - const unrelatedRegistryVersion = commit(repo, "chore(release): prepare unrelated registry example release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: unrelatedRegistryVersion, products: [nativeProduct] }), - /derived file.*unrelated[.]version/u, - ); - - git(repo, "switch", "-q", "-c", "missing-native-transition", base); - write(repo, ".release-please-manifest.json", releaseManifest("0.1.0", "0.1.1")); - write(repo, `${brokerPath}/VERSION`, "0.1.1\n"); - write(repo, `${brokerPath}/CHANGELOG.md`, "# Changelog\n\n## 0.1.1 (2026-08-08)\n"); - write(repo, exampleManifest, exampleCargo({ carrierVersion: "0.1.1" })); - const missingNativeTransition = commit(repo, "chore(release): prepare unrelated product release"); - assert.throws( - () => verifyReleaseCommit({ repo, headRef: missingNativeTransition, products: [brokerProduct] }), - /derived file examples\/tauri\/src-tauri\/Cargo[.]toml contains a non-version semantic change/u, - ); -}); diff --git a/tools/release/verify-release-commit.test.mts b/tools/release/verify-release-commit.test.mts new file mode 100644 index 000000000..c23176249 --- /dev/null +++ b/tools/release/verify-release-commit.test.mts @@ -0,0 +1,270 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + deriveReleaseProducts, + latestVerifiedReleaseCommit, + verifyReleaseCommit, +} from './verify-release-commit.mts'; +import { RELEASE_PLEASE_BOOTSTRAP_SHA } from './release-please-bootstrap.mts'; +const [phase, repo, family, scenario, headRef, releaseRef] = process.argv.slice(2); +const broker = 'oliphaunt-broker'; +const native = 'liboliphaunt-native'; +const nativePath = 'src/runtimes/liboliphaunt-native'; +const exampleManifest = 'src/examples/tauri/src-tauri/Cargo.toml'; +function write(file, contents) { + const target = path.join(repo, file); + mkdirSync(path.dirname(target), { recursive: true }); + writeFileSync(target, contents); +} +function json(file, data) { + write(file, JSON.stringify(data) + '\n'); +} +function simple(component) { + return { + 'release-type': 'simple', + component, + 'version-file': 'VERSION', + 'changelog-path': 'CHANGELOG.md', + }; +} +function changelog(folder, version) { + write(`${folder}/CHANGELOG.md`, `# Changelog\n\n## ${version} (2026-07-14)\n`); +} +function cargo(name, version) { + return `[package]\nname = "${name}"\nversion = "${version}"\n`; +} +function prepareBasic(base) { + const bootstrap = family === 'bootstrap'; + const config = { packages: { 'packages/alpha': simple(broker) } }; + if (bootstrap && base) config['bootstrap-sha'] = RELEASE_PLEASE_BOOTSTRAP_SHA; + if (bootstrap && scenario === 'mutated') + config['bootstrap-sha'] = '1111111111111111111111111111111111111111'; + if (!bootstrap) + config.packages['packages/beta'] = { + 'release-type': 'node', + component: 'beta', + 'changelog-path': 'CHANGELOG.md', + }; + json('release-please-config.json', config); + const alpha = + base || ['downgrade', 'hidden-version-config'].includes(scenario) ? '0.0.0' : '0.1.0'; + const beta = scenario === 'hidden-version-config' ? '0.1.0' : '0.0.0'; + json('.release-please-manifest.json', { + 'packages/alpha': alpha, + ...(!bootstrap ? { 'packages/beta': beta } : {}), + }); + write('packages/alpha/VERSION', `${alpha}\n`); + if (base) write('packages/alpha/CHANGELOG.md', '# Changelog\n'); + else if (scenario !== 'hidden-version-config') changelog('packages/alpha', alpha); + if (bootstrap) return; + json('packages/beta/package.json', { + name: 'beta', + version: beta, + ...(scenario === 'hidden-version-config' ? { scripts: { postinstall: 'hidden-code' } } : {}), + }); + if (base) { + write('packages/beta/CHANGELOG.md', '# Changelog\n'); + write('src/removable.rs', 'pub fn must_not_disappear() {}\n'); + write('src/future-version.txt', '0.1.0\n'); + } else if (scenario === 'hidden-version-config') changelog('packages/beta', beta); + if ( + base || + ['hidden-derived-config', 'derived-version-only', 'unrelated-derived-dependency'].includes( + scenario, + ) + ) + json('src/sdks/ts/sdk/package.json', { + name: 'shadow-derived', + oliphaunt: { brokerVersion: scenario === 'derived-version-only' ? '0.1.0' : '0.0.0' }, + optionalDependencies: { + '@oliphaunt/broker-linux-x64-gnu': 'workspace:*', + '@oliphaunt/unrelated': + scenario === 'unrelated-derived-dependency' ? 'workspace:0.1.0' : 'workspace:*', + }, + dangerous: scenario === 'hidden-derived-config', + }); + if (scenario === 'tainted') write('src/fix.rs', 'pub fn hidden_fix() {}\n'); +} +function prepareCargo(base) { + json('release-please-config.json', { + packages: { + 'src/broker': { 'release-type': 'rust', component: broker, 'changelog-path': 'CHANGELOG.md' }, + }, + }); + const version = base ? '0.0.0' : '0.1.0'; + json('.release-please-manifest.json', { 'src/broker': version }); + write('src/broker/Cargo.toml', cargo(broker, version)); + if (base) { + write('src/broker/CHANGELOG.md', '# Changelog\n'); + write('src/shared/unrelated/Cargo.toml', cargo('unrelated', '0.0.0')); + } else changelog('src/broker', version); + if (base || scenario !== 'unrelated-lock') + write( + 'src/sdks/rust/sdk/Cargo.toml', + cargo('shadow-sdk', scenario === 'unrelated-package' ? '0.1.0' : '0.0.0') + + `\n[dependencies]\noliphaunt-broker = { path = "../../../broker", version = "${version}" }\nunrelated = { path = "../../../../src/shared/unrelated", version = "${scenario === 'unrelated-pin' ? '0.1.0' : '0.0.0'}" }\n`, + ); + if (base || ['exact', 'unrelated-lock'].includes(scenario)) + write( + 'Cargo.lock', + `version = 4\n\n[[package]]\nname = "oliphaunt-broker"\nversion = "${version}"\n\n[[package]]\nname = "unrelated"\nversion = "${scenario === 'unrelated-lock' ? '0.1.0' : '0.0.0'}"\n`, + ); +} +function prepareWildcard(base) { + json('release-please-config.json', { + packages: { 'src/broker': { 'release-type': 'rust', component: broker } }, + }); + const version = base ? '0.1.0' : '0.2.0'; + json('.release-please-manifest.json', { 'src/broker': version }); + let entry = 'oliphaunt = { path = "../sdks/rust/sdk", version = "*", features = [] }'; + if (!base && scenario !== 'workspace-wildcard') { + entry = entry.replace('"*"', scenario === 'wrong-version' ? '"0.3.0"' : '"0.2.0"'); + if (scenario === 'changed-path') entry = entry.replace('../sdks/rust/sdk', '../sdks/other'); + if (scenario === 'removed-path') entry = entry.replace('path = "../sdks/rust/sdk", ', ''); + if (scenario === 'changed-features') + entry = entry.replace('features = []', 'features = ["extra"]'); + } + write( + 'src/broker/Cargo.toml', + cargo(broker, version) + + ['dependencies', 'dev-dependencies', 'build-dependencies'] + .flatMap((table) => [ + `\n[${table}]\n${entry}\n`, + `\n[target.'cfg(unix)'.${table}]\n${entry}\n`, + ]) + .join(''), + ); + if (base) { + write('src/broker/CHANGELOG.md', '# Changelog\n'); + write('src/sdks/rust/sdk/Cargo.toml', cargo('oliphaunt', '0.2.0')); + } else changelog('src/broker', version); +} +function prepareWasix(base) { + const runtime = 'src/runtimes/liboliphaunt-wasix', + sdk = 'src/sdks/ts-wasix/sdk', + tools = 'src/postgres-tools/wasix/ts'; + const version = base ? '0.1.0' : '0.2.0'; + json('release-please-config.json', { + packages: { + [runtime]: simple('liboliphaunt-wasix'), + [sdk]: { + 'release-type': 'node', + component: 'oliphaunt-wasix-ts', + 'changelog-path': 'CHANGELOG.md', + }, + }, + }); + json('.release-please-manifest.json', { [runtime]: version, [sdk]: version }); + write(`${runtime}/VERSION`, `${version}\n`); + changelog(runtime, version); + json(`${sdk}/package.json`, { name: '@oliphaunt/wasix-ts', version }); + changelog(sdk, version); + const dependencies = { '@oliphaunt/liboliphaunt-wasix-tools': 'workspace:*' }, + devDependencies = { '@oliphaunt/wasix-ts': 'workspace:*' }; + json(`${tools}/package.json`, { + dependencies, + peerDependencies: devDependencies, + devDependencies, + }); + json('bun.lock', { + lockfileVersion: 2, + workspaces: { + [sdk]: { name: '@oliphaunt/wasix-ts', version }, + [tools]: { dependencies, devDependencies }, + }, + }); +} +function prepareExample(base) { + json('release-please-config.json', { + packages: { [nativePath]: simple(native), 'src/broker': simple(broker) }, + }); + const missing = scenario === 'missing-native-transition'; + const nativeVersion = base || missing ? '0.1.0' : '0.1.1', + brokerVersion = !base && missing ? '0.1.1' : '0.1.0'; + json('.release-please-manifest.json', { + [nativePath]: nativeVersion, + 'src/broker': brokerVersion, + }); + write(`${nativePath}/VERSION`, `${nativeVersion}\n`); + write('src/broker/VERSION', `${brokerVersion}\n`); + if (base) { + write(`${nativePath}/CHANGELOG.md`, '# Changelog\n'); + write('src/broker/CHANGELOG.md', '# Changelog\n'); + } else changelog(missing ? 'src/broker' : nativePath, missing ? brokerVersion : nativeVersion); + const carrierVersion = base ? '0.1.0' : scenario === 'wrong-registry-version' ? '0.1.2' : '0.1.1'; + const runtimeVersion = base ? '0.1.0' : scenario === 'wrong-runtime-version' ? '0.1.2' : '0.1.1'; + const unrelatedVersion = scenario === 'unrelated-registry-version' ? '9.0.1' : '9.0.0'; + write( + exampleManifest, + `[package]\nname = "release-example"\nversion = "0.0.0"\n\n[package.metadata.oliphaunt]\nruntime = "liboliphaunt-native"\nruntime-version = "${runtimeVersion}"\n\n[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dependencies]\nliboliphaunt-native-linux-x64-gnu = { version = "=${carrierVersion}" }\nunrelated = { version = "${unrelatedVersion}" }\n`, + ); +} +if (phase === 'write') { + if (scenario === 'later-fix') write('fix.txt', 'post-release fix\n'); + else { + const prepare = { + bootstrap: prepareBasic, + basic: prepareBasic, + cargo: prepareCargo, + wildcard: prepareWildcard, + wasix: prepareWasix, + example: prepareExample, + }[family]; + if (!prepare) throw new Error('unknown release fixture family'); + prepare(scenario === 'base'); + } +} else if (phase === 'assert') { + const products = + family === 'wasix' + ? ['liboliphaunt-wasix', 'oliphaunt-wasix-ts'] + : family === 'example' && scenario !== 'missing-native-transition' + ? [native] + : scenario === 'hidden-version-config' + ? ['beta'] + : [broker]; + const verify = () => verifyReleaseCommit({ repo, headRef, products }); + if (scenario === 'base') assert.equal(latestVerifiedReleaseCommit({ repo, headRef }), null); + else if (scenario === 'later-fix') { + assert.equal(latestVerifiedReleaseCommit({ repo, headRef }).commit, releaseRef); + assert.throws(verify, /subject must start/u); + } else { + const rejected = + { + mutated: /release-please-config[.]json contains a non-version semantic change/u, + downgrade: /must advance to a semver version/u, + tainted: /non-release-derived path.*src\/fix[.]rs/u, + deletion: /non-release-derived path.*src\/removable[.]rs/u, + rename: /non-release-derived path.*src\/future-version[.]txt/u, + 'hidden-version-config': /canonical version file.*non-version semantic change/u, + 'hidden-derived-config': /derived file.*non-version semantic change/u, + 'unrelated-derived-dependency': + /derived file.*optionalDependencies[.]@oliphaunt\/unrelated/u, + 'unrelated-pin': /derived file.*dependencies[.]unrelated[.]version/u, + 'unrelated-package': /derived file.*package[.]version/u, + 'unrelated-lock': /derived file.*package[.]1[.]version/u, + 'wrong-registry-version': /derived file.*liboliphaunt-native-linux-x64-gnu[.]version/u, + 'wrong-runtime-version': /derived file.*runtime-version/u, + 'unrelated-registry-version': /derived file.*unrelated[.]version/u, + 'missing-native-transition': + /derived file src\/examples\/tauri\/src-tauri\/Cargo[.]toml contains a non-version semantic change/u, + }[scenario] ?? + (family === 'wildcard' && scenario !== 'workspace-wildcard' + ? /canonical version file.*non-version semantic change/u + : undefined); + if (rejected) assert.throws(verify, rejected); + else { + const result = verify(); + assert.deepEqual(result.products, products); + if (family === 'basic' && scenario === 'clean') { + assert.deepEqual(deriveReleaseProducts({ repo, headRef }).products, [broker]); + assert.equal(result.versions[broker], '0.1.0'); + assert.throws( + () => verifyReleaseCommit({ repo, headRef, products: [broker, 'beta'] }), + /do not exactly match/u, + ); + } + } + } + console.log(`release commit ${family}/${scenario}: passed`); +} else throw new Error('run through verify-release-commit.test.sh'); diff --git a/tools/release/verify-release-commit.test.sh b/tools/release/verify-release-commit.test.sh new file mode 100644 index 000000000..dae78cd25 --- /dev/null +++ b/tools/release/verify-release-commit.test.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +if [[ -z "${OLIPHAUNT_RELEASE_PLEASE_STATE:-}" ]]; then + exec bash "$root/tools/release/release-please-state.sh" "$root" HEAD \ + bash "$root/tools/release/verify-release-commit.test.sh" +fi +scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-release-commit.XXXXXX")" +trap 'rm -rf "$scratch"' EXIT +fixture="$root/tools/release/verify-release-commit.test.mts" +commit() { git -C "$repo" add .; git -C "$repo" commit -qm "$1"; } +assert_history() { + local head + head="$(git -C "$repo" rev-parse HEAD)" + bash "$root/tools/release/with-release-history.sh" "$repo" "$head" \ + bash "$root/tools/dev/bun.sh" "$fixture" assert "$repo" "$family" "$1" "$head" "${release:-}" +} +for family in bootstrap basic cargo wildcard wasix example; do + repo="$scratch/$family" + git init -q "$repo" + git -C "$repo" config user.name 'Release Test' + git -C "$repo" config user.email release@example.invalid + bash "$root/tools/dev/bun.sh" "$fixture" write "$repo" "$family" base + commit 'feat: introduce release fixture' + base="$(git -C "$repo" rev-parse HEAD)" + release='' + case "$family" in + bootstrap) assert_history base; scenarios=(clean mutated) ;; + basic) scenarios=(clean later-fix downgrade tainted deletion rename hidden-version-config hidden-derived-config derived-version-only unrelated-derived-dependency) ;; + cargo) scenarios=(exact unrelated-pin unrelated-package unrelated-lock) ;; + wildcard) scenarios=(workspace-wildcard local-version wrong-version changed-path removed-path changed-features) ;; + wasix) scenarios=(workspace-links) ;; + example) scenarios=(exact wrong-registry-version wrong-runtime-version unrelated-registry-version missing-native-transition) ;; + esac + for scenario in "${scenarios[@]}"; do + start="$base" + if [[ "$scenario" == later-fix || "$scenario" == downgrade ]]; then start="$release"; fi + git -C "$repo" switch -qc "$scenario" "$start" + bash "$root/tools/dev/bun.sh" "$fixture" write "$repo" "$family" "$scenario" + case "$scenario" in + deletion) git -C "$repo" rm -q src/removable.rs ;; + rename) + git -C "$repo" rm -qf packages/alpha/VERSION + git -C "$repo" mv src/future-version.txt packages/alpha/VERSION ;; + esac + if [[ "$scenario" == later-fix ]]; then commit 'fix(tools): repair publication'; + else commit 'chore(release): prepare product release'; fi + if [[ "$scenario" == clean ]]; then release="$(git -C "$repo" rev-parse HEAD)"; fi + assert_history "$scenario" + done +done diff --git a/tools/release/verify_github_release_attestations.mjs b/tools/release/verify_github_release_attestations.mjs deleted file mode 100755 index d2dcc27f1..000000000 --- a/tools/release/verify_github_release_attestations.mjs +++ /dev/null @@ -1,2744 +0,0 @@ -#!/usr/bin/env bun -// Verify GitHub artifact attestations for asset-backed product releases. - -import { createHash, randomUUID } from "node:crypto"; -import { spawnSync } from "node:child_process"; -import { readFileSync } from "node:fs"; -import fs from "node:fs/promises"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { runMoon } from "../policy/moon.mjs"; -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { CONTRIB_CARRIERS_PATH } from "./contrib-carriers.mjs"; -import { - contribCarrierDescriptor, - expectedAssets as expectedDesktopAssets, - extensionArtifactProductRoot, - extensionMetadata, - extensionReleaseProduct, - extensionSourceIdentity, - extensionSqlNames, -} from "./release-artifact-targets.mjs"; -import { currentVersion } from "./product-version.mjs"; -import { - assertPublicationLockSource, - loadPublicationLock, -} from "./publication-lock.mjs"; -import { reserveGitHubCoreRequestSync } from "./github-core-request-journal.mjs"; -import { swiftExtensionCarrierAssetName } from "./ios-carrier-manifest.mjs"; -import { assertPublicationController } from "./publication-controller.mjs"; -import { assertWasixExtensionMemberInstall } from "../../src/shared/extension-runtime-contract/wasix-extension-install.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const PREFIX = "verify_github_release_attestations.mjs"; -const GITHUB_API = process.env.GITHUB_API ?? "https://api.github.com"; -const MAX_GITHUB_JSON_BYTES = 8 * 1024 * 1024; -const MAX_GITHUB_ERROR_BYTES = 64 * 1024; -const MAX_CONTROL_ASSET_BYTES = 8 * 1024 * 1024; -const MAX_RELEASE_ASSET_BYTES = 2 * 1024 * 1024 * 1024; -const GITHUB_API_TIMEOUT_MS = 30_000; -const RELEASE_ASSET_TIMEOUT_MS = 10 * 60 * 1000; -const MAX_ATTESTATION_BUNDLE_BYTES = 32 * 1024 * 1024; -const MAX_ATTESTATION_RECEIPT_BYTES = 16 * 1024 * 1024; -const GITHUB_RELEASE_QUERY_WINDOW_MS = 5 * 60 * 1000; -const GITHUB_RELEASE_QUERY_MAX_ATTEMPTS = 3; -const GITHUB_RELEASE_SNAPSHOT_MAX_ATTEMPTS = 10; -const GITHUB_RELEASE_SNAPSHOT_MAX_RETRY_DELAY_MS = 15_000; -const GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS = 4 * 60 * 1000; -const GITHUB_RELEASE_LIST_PAGE_SIZE = 100; -const GITHUB_RELEASE_LIST_MAX_PAGES = 1_000; -const GITHUB_RELEASE_FALLBACK_QUERY_CONCURRENCY = 1; -const GH_ATTESTATION_VERIFY_TIMEOUT_MS = 5 * 60 * 1000; -const GH_ATTESTATION_VERIFY_MAX_OUTPUT_BYTES = 64 * 1024 * 1024; -const GITHUB_ATTESTATION_RECEIPT_SCHEMA = "oliphaunt-github-release-attestation-receipt-v1"; -const SLSA_PROVENANCE_V1 = "https://slsa.dev/provenance/v1"; -const IN_TOTO_STATEMENT_V1 = "https://in-toto.io/Statement/v1"; -const GITHUB_RELEASE_ARTIFACT_ROLES = new Set([ - "github-release-asset", - "github-release-metadata", -]); - -const BASE_ASSET_BACKED_PRODUCTS = new Set([ - "liboliphaunt-native", - "liboliphaunt-wasix", - "liboliphaunt-wasix-postmaster", - "oliphaunt-broker", - "oliphaunt-node-direct", - "oliphaunt-wasix-napi", -]); - -const DESKTOP_TARGETS = new Set([ - "linux-arm64-gnu", - "linux-x64-gnu", - "macos-arm64", - "windows-x64-msvc", -]); - -const PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS = new Set([ - "schema", - "product", - "releaseProduct", - "family", - "version", - "sqlName", - "extensionClass", - "versioning", - "sourceIdentity", - "compatibility", - "createsExtension", - "dependencies", - "dataFiles", - "extensionSqlFileNames", - "extensionSqlFilePrefixes", - "nativeModuleStem", - "iosNativeDependencies", - "iosRegistration", - "wasixInstall", - "sharedPreloadLibraries", - "assets", -]); -const EXTENSION_OWNERSHIP_KEYS = ["releaseProduct", "family"]; -const PUBLIC_EXTENSION_RELEASE_LEGACY_KEYS = new Set( - [...PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS].filter((key) => !EXTENSION_OWNERSHIP_KEYS.includes(key)), -); - -const PUBLIC_EXTENSION_RELEASE_ASSET_KEYS = new Set([ - "name", - "family", - "target", - "kind", - "identity", - "sha256", - "bytes", -]); -const PUBLIC_EXTENSION_BUNDLE_MANIFEST_KEYS = new Set([ - "schema", - "product", - "releaseProduct", - "family", - "version", - "extensionClass", - "versioning", - "sourceIdentity", - "compatibility", - "extensions", - "assets", -]); -const PUBLIC_EXTENSION_BUNDLE_LEGACY_KEYS = new Set( - [...PUBLIC_EXTENSION_BUNDLE_MANIFEST_KEYS].filter((key) => !EXTENSION_OWNERSHIP_KEYS.includes(key)), -); -const PUBLIC_EXTENSION_BUNDLE_MEMBER_KEYS = new Set([ - "sqlName", - "createsExtension", - "dependencies", - "dataFiles", - "extensionSqlFileNames", - "extensionSqlFilePrefixes", - "nativeModuleStem", - "iosNativeDependencies", - "iosRegistration", - "wasixInstall", - "sharedPreloadLibraries", - "assets", -]); -const PUBLIC_EXTENSION_BUNDLE_ASSET_KEYS = new Set([ - "name", - "family", - "target", - "kind", - "sha256", - "bytes", - "memberCount", -]); -const PUBLIC_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS = new Set([ - ...PUBLIC_EXTENSION_RELEASE_ASSET_KEYS, - "carrierAsset", - "carrierRoot", - "memberPath", -]); - -function fail(message) { - console.error(`${PREFIX}: ${message}`); - process.exit(1); -} - -function rel(file) { - return path.relative(ROOT, file).split(path.sep).join("/"); -} - -async function readJson(file) { - try { - const value = JSON.parse(await fs.readFile(file, "utf8")); - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(`${rel(file)} must contain a JSON object`); - } - return value; - } catch (error) { - fail(`failed to read ${rel(file)}: ${error.message}`); - } -} - -async function readToml(file) { - try { - const value = Bun.TOML.parse(await fs.readFile(file, "utf8")); - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(`${rel(file)} must contain a TOML table`); - } - return value; - } catch (error) { - fail(`failed to read ${rel(file)}: ${error.message}`); - } -} - -let releaseConfigCache; -async function releaseConfig() { - releaseConfigCache ??= readJson(path.join(ROOT, "release-please-config.json")); - return releaseConfigCache; -} - -let packagePathsCache; -async function packagePathsByProduct() { - if (packagePathsCache !== undefined) { - return packagePathsCache; - } - const config = await releaseConfig(); - const packages = config.packages; - if (packages === null || Array.isArray(packages) || typeof packages !== "object") { - fail("release-please-config.json must define packages"); - } - const paths = new Map(); - for (const [packagePath, packageConfig] of Object.entries(packages)) { - const component = packageConfig?.component; - if (typeof component !== "string" || component.length === 0) { - fail(`${packagePath}.component must be a non-empty string`); - } - if (paths.has(component)) { - fail(`duplicate release-please component ${component}`); - } - paths.set(component, packagePath); - } - packagePathsCache = paths; - return paths; -} - -async function packagePath(product) { - const paths = await packagePathsByProduct(); - const value = paths.get(product); - if (typeof value !== "string" || value.length === 0) { - fail(`unknown release product ${JSON.stringify(product)}`); - } - return value; -} - -async function productConfig(product) { - const productPath = await packagePath(product); - const metadata = await readToml(path.join(ROOT, productPath, "release.toml")); - if (metadata.id !== product) { - fail(`${productPath}/release.toml must declare id = ${JSON.stringify(product)}`); - } - return metadata; -} - -async function exactExtensionProducts() { - const paths = await packagePathsByProduct(); - const products = []; - for (const product of paths.keys()) { - const config = await productConfig(product); - if (["exact-extension-artifact", "exact-extension-bundle"].includes(config.kind)) { - products.push(product); - } - } - return products.sort(compareText); -} - -async function assetBackedProducts() { - return new Set([...BASE_ASSET_BACKED_PRODUCTS, ...(await exactExtensionProducts())]); -} - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -async function tagPrefix(product) { - const config = await releaseConfig(); - if (config["include-v-in-tag"] !== true) { - fail("release-please must include v in product tags"); - } - if (config["tag-separator"] !== "-") { - fail("release-please tag-separator must be '-'"); - } - return `${product}-v`; -} - -async function productTag(product, version) { - return `${await tagPrefix(product)}${version}`; -} - -function repository() { - return process.env.GITHUB_REPOSITORY || "f0rr0/oliphaunt"; -} - -let moonReleaseProductsCache; -function moonReleaseProducts() { - if (moonReleaseProductsCache !== undefined) { - return moonReleaseProductsCache; - } - const value = JSON.parse(runMoon(["query", "projects"])); - if (!Array.isArray(value.projects)) { - fail("moon query projects did not return a projects array"); - } - const products = new Map(); - for (const project of value.projects) { - const id = project?.id; - const tags = project?.config?.tags; - const release = project?.config?.project?.metadata?.release; - if (!Array.isArray(tags) || !tags.includes("release-product")) { - continue; - } - if (typeof id !== "string" || release === null || typeof release !== "object") { - fail("Moon release metadata returned an invalid product row"); - } - if (release.component !== id) { - fail(`Moon release product ${id} release.component must match project id`); - } - products.set(id, release); - } - moonReleaseProductsCache = products; - return products; -} - -function productTargets(product, preset) { - const release = moonReleaseProducts().get(product); - if (!release) { - fail(`Moon release metadata does not include ${product}`); - } - const artifactTargets = release.artifactTargets; - if ( - artifactTargets === null || - typeof artifactTargets !== "object" || - artifactTargets.preset !== preset - ) { - fail(`Moon release metadata for ${product} must use artifactTargets preset ${preset}`); - } - const targets = artifactTargets.targets; - if (!Array.isArray(targets) || !targets.every((target) => typeof target === "string" && target)) { - fail(`Moon release metadata for ${product} must declare artifactTargets.targets`); - } - return [...targets].sort(compareText); -} - -function archiveSuffix(target) { - return target === "windows-x64-msvc" ? "zip" : "tar.gz"; -} - -function liboliphauntNativeAssets(version) { - const targets = productTargets("liboliphaunt-native", "liboliphaunt-native"); - const assets = targets.map((target) => `liboliphaunt-${version}-${target}.${archiveSuffix(target)}`); - for (const target of targets.filter((target) => DESKTOP_TARGETS.has(target))) { - assets.push(`oliphaunt-tools-${version}-${target}.${archiveSuffix(target)}`); - } - assets.push( - `liboliphaunt-${version}-apple-spm-xcframework.zip`, - `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`, - `liboliphaunt-${version}-runtime-resources-android-datum64.tar.gz`, - `liboliphaunt-${version}-icu-data.tar.gz`, - `liboliphaunt-${version}-release-assets.sha256`, - ); - return [...new Set(assets)].sort(compareText); -} - -function liboliphauntWasixAssets(version) { - const targets = productTargets("liboliphaunt-wasix", "liboliphaunt-wasix"); - if (!targets.includes("portable")) { - fail("Moon release metadata for liboliphaunt-wasix must include portable"); - } - const assets = [ - `liboliphaunt-wasix-${version}-runtime-portable.tar.zst`, - `liboliphaunt-wasix-${version}-icu-data.tar.zst`, - `liboliphaunt-wasix-${version}-release-assets.sha256`, - ]; - for (const target of targets.filter((target) => target !== "portable")) { - assets.push(`liboliphaunt-wasix-${version}-runtime-aot-${target}.tar.zst`); - } - return assets.sort(compareText); -} - -async function productTagContains(product, version, relativePath) { - const tag = await productTag(product, version); - const tree = spawnSync("git", ["cat-file", "-e", `${tag}^{tree}`], { - cwd: ROOT, - stdio: "ignore", - }); - if (tree.error || tree.status !== 0) { - fail(`cannot inspect exact product tag tree ${tag}`); - } - const entry = spawnSync("git", ["cat-file", "-e", `${tag}:${relativePath}`], { - cwd: ROOT, - stdio: "ignore", - }); - if (entry.error) fail(`cannot inspect ${relativePath} in exact product tag tree ${tag}`); - return entry.status === 0; -} - -async function expectedExtensionAssets(product, version, family = "combined") { - const rootFamily = family === "combined" ? "native" : family; - const releaseProduct = family === "combined" - ? product - : extensionReleaseProduct(product, family, PREFIX); - const releaseAssetRoot = path.join( - ROOT, - extensionArtifactProductRoot(product, rootFamily, "target/extension-artifacts", PREFIX), - "release-assets", - ); - const manifestPath = path.join(releaseAssetRoot, `${product}-${version}-manifest.json`); - const manifest = await readJson(manifestPath); - const extensionAssets = await validateExtensionManifest(product, version, manifest, manifestPath, { - family, - releaseProduct, - }); - const names = extensionAssets.map((asset) => asset.name); - names.push( - `${product}-${version}-manifest.json`, - `${product}-${version}-manifest.properties`, - `${product}-${version}-release-assets.sha256`, - ); - if (family !== "wasix") names.push(swiftExtensionCarrierAssetName(product, version)); - return [...new Set(names)].sort(compareText); -} - -async function expectedAssets(product, version) { - const config = await productConfig(product); - if (["exact-extension-artifact", "exact-extension-bundle"].includes(config.kind)) { - return expectedExtensionAssets(product, version); - } - if (product === "liboliphaunt-native") { - const assets = liboliphauntNativeAssets(version); - if (await productTagContains(product, version, CONTRIB_CARRIERS_PATH)) { - const contrib = contribCarrierDescriptor(PREFIX); - assets.push(...await expectedExtensionAssets(contrib.artifactProduct, version, "native")); - } - return [...new Set(assets)].sort(compareText); - } - if (product === "liboliphaunt-wasix") { - const assets = liboliphauntWasixAssets(version); - if (await productTagContains(product, version, CONTRIB_CARRIERS_PATH)) { - const contrib = contribCarrierDescriptor(PREFIX); - assets.push(...await expectedExtensionAssets(contrib.artifactProduct, version, "wasix")); - } - return [...new Set(assets)].sort(compareText); - } - if (product === "liboliphaunt-wasix-postmaster") { - return [ - ...productTargets(product, "liboliphaunt-wasix-postmaster") - .map((target) => `${product}-${version}-${target}.tar.zst`), - `${product}-${version}-release-assets.sha256`, - ].sort(compareText); - } - if (product === "oliphaunt-broker") { - return expectedDesktopAssets(product, "broker-helper", version, PREFIX); - } - if (product === "oliphaunt-node-direct") { - return expectedDesktopAssets(product, "node-direct-addon", version, PREFIX); - } - if (product === "oliphaunt-wasix-napi") { - return expectedDesktopAssets(product, "wasix-napi-addon", version, PREFIX); - } - fail(`asset expectation is not defined for ${product}`); -} - -function authHeaders(accept, token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN) { - const headers = { - Accept: accept, - "User-Agent": "oliphaunt-release-check", - "X-GitHub-Api-Version": "2022-11-28", - }; - if (token) { - if (typeof token !== "string" || /[\0\r\n]/u.test(token)) { - throw new Error("GitHub API token is invalid"); - } - headers.Authorization = `Bearer ${token}`; - } - return headers; -} - -function responseContentLength(response, context) { - const raw = response.headers?.get?.("content-length"); - if (raw === null || raw === undefined) return null; - const value = Number(raw); - if (!Number.isSafeInteger(value) || value < 0) { - throw new Error(`${context} returned an invalid Content-Length`); - } - return value; -} - -async function boundedResponseBytes(response, maximum, context) { - const declared = responseContentLength(response, context); - if (declared !== null && declared > maximum) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`${context} exceeds ${maximum} bytes`); - } - const reader = response.body?.getReader?.(); - if (reader === undefined) { - const bytes = new Uint8Array(await response.arrayBuffer()); - if (bytes.byteLength > maximum) throw new Error(`${context} exceeds ${maximum} bytes`); - return bytes; - } - const chunks = []; - let size = 0; - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > maximum) { - await reader.cancel().catch(() => {}); - throw new Error(`${context} exceeds ${maximum} bytes`); - } - chunks.push(Buffer.from(value)); - } - } finally { - reader.releaseLock(); - } - return new Uint8Array(Buffer.concat(chunks, size)); -} - -async function exactResponseProof(response, expectedSize, context) { - const declared = responseContentLength(response, context); - if (declared !== null && declared !== expectedSize) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`${context} Content-Length ${declared} does not match expected size ${expectedSize}`); - } - const hash = createHash("sha256"); - let size = 0; - const reader = response.body?.getReader?.(); - if (reader === undefined) { - const bytes = new Uint8Array(await response.arrayBuffer()); - size = bytes.byteLength; - if (size > expectedSize) throw new Error(`${context} exceeds expected size ${expectedSize}`); - hash.update(bytes); - } else { - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - size += value.byteLength; - if (size > expectedSize) { - await reader.cancel().catch(() => {}); - throw new Error(`${context} exceeds expected size ${expectedSize}`); - } - hash.update(value); - } - } finally { - reader.releaseLock(); - } - } - if (size !== expectedSize) { - throw new Error(`${context} size ${size} does not match expected size ${expectedSize}`); - } - return { bytes: size, sha256: hash.digest("hex") }; -} - -function releaseAssetApiUrl(rawUrl, name) { - let url; - try { - url = new URL(rawUrl); - } catch { - throw new Error(`GitHub release asset ${name} has an invalid API download URL`); - } - const api = new URL(GITHUB_API); - if (url.protocol !== "https:" || url.origin !== api.origin) { - throw new Error(`GitHub release asset ${name} API download URL must use ${api.origin}`); - } - return url; -} - -function expectedAssetSize(value, name, maximum = MAX_RELEASE_ASSET_BYTES) { - if (!Number.isSafeInteger(value) || value < 0 || value > maximum) { - throw new Error(`GitHub release asset ${name} has invalid size ${JSON.stringify(value)}`); - } - return value; -} - -export async function requestBoundedGithubJson(url, { - fetchImpl = fetch, - timeoutMs = GITHUB_API_TIMEOUT_MS, -} = {}) { - const response = await fetchImpl(url, { - headers: authHeaders("application/vnd.github+json"), - redirect: "error", - signal: AbortSignal.timeout(timeoutMs), - }); - if (!response.ok) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`GitHub API returned HTTP ${response.status} for ${url}`); - } - const bytes = await boundedResponseBytes(response, MAX_GITHUB_JSON_BYTES, "GitHub API response"); - try { - return JSON.parse(new TextDecoder().decode(bytes)); - } catch (error) { - throw new Error(`GitHub API returned invalid JSON for ${url}: ${error.message}`); - } -} - -function githubRateLimitedResponse(response, detail) { - if (response.status === 429) return true; - if (response.status !== 403) return false; - return response.headers?.has?.("retry-after") === true - || response.headers?.get?.("x-ratelimit-remaining")?.trim() === "0" - || /(?:abuse|rate limit|secondary limit)/iu.test(detail); -} - -function retryableGithubResponse(response, rateLimited) { - return rateLimited - || response.status === 408 - || response.status === 425 - || response.status >= 500 && response.status <= 599; -} - -async function githubErrorDetail(response) { - try { - const bytes = await boundedResponseBytes( - response, - MAX_GITHUB_ERROR_BYTES, - `GitHub API HTTP ${response.status} error response`, - ); - const text = new TextDecoder().decode(bytes); - try { - const parsed = JSON.parse(text); - return typeof parsed?.message === "string" ? parsed.message : text; - } catch { - return text; - } - } catch { - await response.body?.cancel?.().catch(() => {}); - return ""; - } -} - -function retryAfterDelay(response, nowMs, context) { - const raw = response.headers?.get?.("retry-after")?.trim(); - if (!raw) return null; - let delay; - if (/^[0-9]+$/u.test(raw)) { - delay = Number(raw) * 1000; - } else { - const date = Date.parse(raw); - if (!Number.isFinite(date)) { - throw new Error(`${context} returned an invalid Retry-After header`); - } - delay = Math.max(0, date - nowMs); - } - if (!Number.isSafeInteger(delay) || delay > GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS) { - throw new Error( - `${context} requested Retry-After ${JSON.stringify(raw)}, exceeding the ${GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS}ms retry cap`, - ); - } - return delay; -} - -function rateLimitDelay(response, nowMs, headerlessSecondaryAttempt, context) { - const retryAfter = retryAfterDelay(response, nowMs, context); - if (retryAfter !== null) return retryAfter; - - if (response.headers?.get?.("x-ratelimit-remaining")?.trim() === "0") { - const rawReset = response.headers?.get?.("x-ratelimit-reset")?.trim(); - if (rawReset === undefined || rawReset === null || rawReset === "") { - throw new Error(`${context} exhausted the primary rate limit without X-RateLimit-Reset`); - } - if (!/^[1-9][0-9]*$/u.test(rawReset)) { - throw new Error(`${context} returned an invalid X-RateLimit-Reset header`); - } - const resetMs = Number(rawReset) * 1000; - const delay = Math.max(0, resetMs - nowMs) + 1_000; - if (!Number.isSafeInteger(resetMs) || delay > GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS) { - throw new Error( - `${context} requires a primary-rate-limit wait exceeding the ${GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS}ms retry cap`, - ); - } - return delay; - } - - // GitHub requires at least a one-minute pause for a secondary limit without - // usable rate-limit headers, followed by exponential backoff. - return Math.min( - GITHUB_RELEASE_QUERY_MAX_RETRY_AFTER_MS, - 60_000 * 2 ** Math.max(0, headerlessSecondaryAttempt - 1), - ); -} - -function githubReleaseQueryDeadline(nowMs = Date.now(), env = process.env) { - let deadline = nowMs + GITHUB_RELEASE_QUERY_WINDOW_MS; - const raw = env.REGISTRY_JOB_HARD_DEADLINE_EPOCH?.trim(); - if (raw !== undefined && raw !== "") { - if (!/^[1-9][0-9]*$/u.test(raw)) { - throw new Error("REGISTRY_JOB_HARD_DEADLINE_EPOCH must be a positive Unix timestamp"); - } - const hardDeadline = Number(raw) * 1000; - if (!Number.isSafeInteger(hardDeadline)) { - throw new Error("REGISTRY_JOB_HARD_DEADLINE_EPOCH exceeds the safe timestamp range"); - } - deadline = Math.min(deadline, hardDeadline); - } - if (deadline <= nowMs) { - throw new Error("GitHub release query deadline has already expired"); - } - return deadline; -} - -export async function requestGithubJsonWithRetry(url, { - authToken, - coreJournalOptions, - deadlineMs, - fetchImpl = fetch, - maxAttempts = GITHUB_RELEASE_QUERY_MAX_ATTEMPTS, - nowImpl = Date.now, - responseMetadata = false, - sleepImpl = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)), -} = {}) { - if (!Number.isSafeInteger(maxAttempts) || maxAttempts <= 0) { - throw new Error("GitHub request maxAttempts must be a positive safe integer"); - } - const effectiveDeadline = deadlineMs ?? githubReleaseQueryDeadline(nowImpl()); - let headerlessSecondaryFailures = 0; - let lastError; - for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { - const now = nowImpl(); - const remaining = effectiveDeadline - now; - if (remaining <= 0) { - throw new Error(`GitHub release query deadline expired for ${url}`); - } - let response; - let rateLimited = false; - reserveGitHubCoreRequestSync({ - ...(coreJournalOptions ?? {}), - label: `GitHub release JSON ${new URL(url).pathname}`, - }); - const transportRemaining = effectiveDeadline - nowImpl(); - if (transportRemaining <= 0) { - throw new Error(`GitHub release query deadline expired during request-journal admission for ${url}`); - } - try { - response = await fetchImpl(url, { - headers: authHeaders("application/vnd.github+json", authToken), - redirect: "error", - signal: AbortSignal.timeout(Math.max(1, Math.min(GITHUB_API_TIMEOUT_MS, transportRemaining))), - }); - } catch (error) { - lastError = error; - if (attempt === maxAttempts) break; - } - if (response?.ok) { - const bytes = await boundedResponseBytes(response, MAX_GITHUB_JSON_BYTES, "GitHub API response"); - try { - const data = JSON.parse(new TextDecoder().decode(bytes)); - return responseMetadata - ? { data, link: response.headers?.get?.("link") ?? "" } - : data; - } catch (error) { - throw new Error(`GitHub API returned invalid JSON for ${url}: ${error.message}`); - } - } - if (response !== undefined) { - const detail = await githubErrorDetail(response); - rateLimited = githubRateLimitedResponse(response, detail); - if (!retryableGithubResponse(response, rateLimited)) { - throw new Error(`GitHub API returned HTTP ${response.status} for ${url}`); - } - lastError = new Error(`GitHub API returned transient HTTP ${response.status} for ${url}`); - if (attempt === maxAttempts) break; - } - const current = nowImpl(); - const retryAfter = response === undefined - ? null - : retryAfterDelay(response, current, `GitHub API HTTP ${response.status}`); - const headerlessSecondary = response !== undefined - && rateLimited - && retryAfter === null - && response.headers?.get?.("x-ratelimit-remaining")?.trim() !== "0"; - headerlessSecondaryFailures = headerlessSecondary - ? headerlessSecondaryFailures + 1 - : 0; - const delay = retryAfter ?? (rateLimited - ? rateLimitDelay( - response, - current, - headerlessSecondaryFailures, - `GitHub API HTTP ${response.status}`, - ) - : Math.min(2_000, 250 * 2 ** (attempt - 1))); - if (current + delay >= effectiveDeadline) { - throw new Error(`GitHub release query retry for ${url} would exceed its deadline`); - } - await sleepImpl(delay); - } - throw new Error(`${lastError?.message ?? `GitHub API request failed for ${url}`} after ${maxAttempts} attempts`); -} - -export async function requestReleaseControlBytes(url, name, expectedSize, { - fetchImpl = fetch, - timeoutMs = RELEASE_ASSET_TIMEOUT_MS, -} = {}) { - const size = expectedAssetSize(expectedSize, name, MAX_CONTROL_ASSET_BYTES); - reserveGitHubCoreRequestSync({ label: `download GitHub release control asset ${name}` }); - const response = await fetchImpl(releaseAssetApiUrl(url, name), { - headers: authHeaders("application/octet-stream"), - redirect: "follow", - signal: AbortSignal.timeout(timeoutMs), - }); - if (!response.ok) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`GitHub asset download returned HTTP ${response.status} for ${name}`); - } - const bytes = await boundedResponseBytes(response, size, `GitHub release asset ${name}`); - if (bytes.byteLength !== size) { - throw new Error(`GitHub release asset ${name} size ${bytes.byteLength} does not match expected size ${size}`); - } - return bytes; -} - -export async function requestReleaseAssetProof(url, name, expectedSize, { - fetchImpl = fetch, - timeoutMs = RELEASE_ASSET_TIMEOUT_MS, -} = {}) { - const size = expectedAssetSize(expectedSize, name); - reserveGitHubCoreRequestSync({ label: `prove GitHub release asset ${name}` }); - const response = await fetchImpl(releaseAssetApiUrl(url, name), { - headers: authHeaders("application/octet-stream"), - redirect: "follow", - signal: AbortSignal.timeout(timeoutMs), - }); - if (!response.ok) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`GitHub asset download returned HTTP ${response.status} for ${name}`); - } - return exactResponseProof(response, size, `GitHub release asset ${name}`); -} - -async function githubJson(url) { - try { - return await requestBoundedGithubJson(url); - } catch (error) { - fail(`failed to query GitHub release URL ${url}: ${error.message}`); - } -} - -async function releaseAssets(repo, tag) { - const repoPath = encodeURIComponent(repo).replaceAll("%2F", "/"); - const tagPath = encodeURIComponent(tag); - const url = `${GITHUB_API.replace(/\/$/u, "")}/repos/${repoPath}/releases/tags/${tagPath}`; - const data = await githubJson(url); - if (data === null || Array.isArray(data) || typeof data !== "object") { - fail(`GitHub release response for ${tag} was not an object`); - } - if (!Array.isArray(data.assets)) { - fail(`GitHub release response for ${tag} did not include assets`); - } - const assets = new Map(); - for (const asset of data.assets) { - if (asset === null || typeof asset !== "object" || typeof asset.name !== "string") { - continue; - } - if (assets.has(asset.name)) { - fail(`GitHub release ${tag} declares duplicate asset ${asset.name}`); - } - assets.set(asset.name, asset); - } - return assets; -} - -async function requestBytes(url, name, expectedSize) { - if (typeof url !== "string" || url.length === 0) { - fail(`GitHub release asset ${name} did not include an API download URL`); - } - try { - return await requestReleaseControlBytes(url, name, expectedSize); - } catch (error) { - fail(`failed to download GitHub asset ${name}: ${error.message}`); - } -} - -async function requestAssetProof(url, name, expectedSize) { - if (typeof url !== "string" || url.length === 0) { - fail(`GitHub release asset ${name} did not include an API download URL`); - } - try { - return await requestReleaseAssetProof(url, name, expectedSize); - } catch (error) { - fail(`failed to verify GitHub asset ${name}: ${error.message}`); - } -} - -function sha256Bytes(data) { - return createHash("sha256").update(data).digest("hex"); -} - -function validateKeySet(object, expected, context) { - const actual = new Set(Object.keys(object)); - const missing = [...expected].filter((key) => !actual.has(key)); - const unexpected = [...actual].filter((key) => !expected.has(key)); - if (missing.length > 0 || unexpected.length > 0) { - fail(`${context} keys must be ${JSON.stringify([...expected].sort())}, got ${JSON.stringify([...actual].sort())}`); - } -} - -function validateSha256(value, context) { - if (typeof value !== "string" || !/^[0-9a-f]{64}$/u.test(value)) { - fail(`${context} has invalid sha256 ${JSON.stringify(value)}`); - } -} - -function validateExtensionAssets(assets, context, seen) { - if (!Array.isArray(assets) || assets.length === 0) { - fail(`${context} must declare a non-empty assets array`); - } - for (const [index, asset] of assets.entries()) { - const assetContext = `${context} assets[${index}]`; - if (asset === null || Array.isArray(asset) || typeof asset !== "object") { - fail(`${assetContext} must be an object`); - } - validateKeySet(asset, PUBLIC_EXTENSION_RELEASE_ASSET_KEYS, assetContext); - for (const key of ["name", "family", "target", "kind", "sha256"]) { - if (typeof asset[key] !== "string" || asset[key].length === 0) { - fail(`${assetContext}.${key} must be a non-empty string`); - } - } - if (!(asset.identity === null || typeof asset.identity === "string" && asset.identity.length > 0)) { - fail(`${assetContext}.identity must be null or a non-empty string`); - } - if (asset.kind === "ios-dependency-xcframework" && asset.identity === null) { - fail(`${assetContext} iOS dependency XCFramework must declare its identity`); - } - validateSha256(asset.sha256, `${assetContext}.${asset.name}`); - if (!Number.isInteger(asset.bytes) || asset.bytes <= 0) { - fail(`${assetContext}.${asset.name} must declare positive bytes`); - } - if (seen.has(asset.name)) { - fail(`${context} declares duplicate asset ${asset.name}`); - } - seen.add(asset.name); - } -} - -function validateBundleCarrierAssets(assets, context, expectedMemberCount) { - if (!Array.isArray(assets) || assets.length === 0) { - fail(`${context} must declare a non-empty aggregate assets array`); - } - const byName = new Map(); - const groups = new Set(); - for (const [index, asset] of assets.entries()) { - const assetContext = `${context} assets[${index}]`; - if (asset === null || Array.isArray(asset) || typeof asset !== "object") fail(`${assetContext} must be an object`); - validateKeySet(asset, PUBLIC_EXTENSION_BUNDLE_ASSET_KEYS, assetContext); - for (const key of ["name", "family", "target", "kind", "sha256"]) { - if (typeof asset[key] !== "string" || asset[key].length === 0) fail(`${assetContext}.${key} must be a non-empty string`); - } - if (asset.kind !== "extension-bundle") fail(`${assetContext}.kind must be extension-bundle`); - validateSha256(asset.sha256, `${assetContext}.${asset.name}`); - if (!Number.isSafeInteger(asset.bytes) || asset.bytes <= 0) fail(`${assetContext}.${asset.name} must declare positive bytes`); - if (asset.memberCount !== expectedMemberCount) { - fail(`${assetContext}.${asset.name} must declare memberCount=${expectedMemberCount}`); - } - const group = `${asset.family}\0${asset.target}`; - if (byName.has(asset.name) || groups.has(group)) fail(`${context} repeats an aggregate carrier name or family/target`); - byName.set(asset.name, asset); - groups.add(group); - } - return byName; -} - -function validateBundleMemberAssets(assets, context, carriers, seenLocators) { - if (!Array.isArray(assets) || assets.length === 0) fail(`${context} must declare a non-empty assets array`); - for (const [index, asset] of assets.entries()) { - const assetContext = `${context} assets[${index}]`; - if (asset === null || Array.isArray(asset) || typeof asset !== "object") fail(`${assetContext} must be an object`); - validateKeySet(asset, PUBLIC_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS, assetContext); - for (const key of [ - "name", "family", "target", "kind", "sha256", "carrierAsset", "carrierRoot", "memberPath", - ]) { - if (typeof asset[key] !== "string" || asset[key].length === 0) fail(`${assetContext}.${key} must be a non-empty string`); - } - if (!(asset.identity === null || typeof asset.identity === "string" && asset.identity.length > 0)) { - fail(`${assetContext}.identity must be null or a non-empty string`); - } - validateSha256(asset.sha256, `${assetContext}.${asset.name}`); - if (!Number.isSafeInteger(asset.bytes) || asset.bytes <= 0) fail(`${assetContext}.${asset.name} must declare positive bytes`); - const carrier = carriers.get(asset.carrierAsset); - if (carrier === undefined || carrier.family !== asset.family || carrier.target !== asset.target) { - fail(`${assetContext} references a missing or wrong-family aggregate carrier`); - } - const expectedRoot = asset.carrierAsset.replace(/\.tar\.gz$/u, ""); - if (asset.carrierRoot !== expectedRoot) fail(`${assetContext}.carrierRoot does not match ${asset.carrierAsset}`); - if ( - asset.memberPath.includes("\\") - || asset.memberPath.startsWith("/") - || asset.memberPath.split("/").some((part) => !part || part === "." || part === "..") - ) fail(`${assetContext}.memberPath must be a safe POSIX path`); - const locator = `${asset.carrierAsset}\0${asset.memberPath}`; - if (seenLocators.has(locator)) fail(`${context} repeats aggregate member locator ${asset.memberPath}`); - seenLocators.add(locator); - } -} - -let canonicalExtensionRowsCache; -let canonicalIosDependenciesCache; - -function canonicalExtensionRows() { - canonicalExtensionRowsCache ??= JSON.parse( - readFileSync(path.join(ROOT, "src/extensions/generated/sdk/extensions.json"), "utf8"), - ).extensions; - if (!Array.isArray(canonicalExtensionRowsCache)) { - throw new Error("generated React Native extension catalog has no extensions array"); - } - return canonicalExtensionRowsCache; -} - -function canonicalIosDependencies() { - if (canonicalIosDependenciesCache !== undefined) return canonicalIosDependenciesCache; - const lines = readFileSync(path.join(ROOT, "src/extensions/generated/mobile/static-extensions.tsv"), "utf8") - .split(/\r?\n/u) - .filter((line) => line.length > 0 && !line.startsWith("#")); - const header = lines.shift()?.split("\t") ?? []; - canonicalIosDependenciesCache = new Map(lines.map((line) => { - const fields = line.split("\t"); - const row = Object.fromEntries(header.map((key, index) => [key, fields[index] ?? ""])); - return [row["sql-name"], (row["ios-static-dependencies"] ?? "").split(",").filter(Boolean).sort(compareText)]; - })); - return canonicalIosDependenciesCache; -} - -function canonicalSortedUniqueStrings(value, context) { - if ( - !Array.isArray(value) - || value.some((item) => typeof item !== "string" || item.length === 0) - || new Set(value).size !== value.length - ) { - throw new Error(`${context} must be a unique non-empty string list`); - } - return [...value].sort(compareText); -} - -function canonicalMemberSemantics(product, sqlName) { - if (!extensionSqlNames(product, PREFIX).includes(sqlName)) { - throw new Error(`${product} does not own extension SQL name ${JSON.stringify(sqlName)}`); - } - const row = canonicalExtensionRows().find((candidate) => candidate?.["sql-name"] === sqlName); - if (row === undefined || row["artifact-product"] !== product) { - throw new Error(`${product}/${sqlName} is absent from canonical generated extension metadata`); - } - const nativeModuleStem = typeof row["native-module-stem"] === "string" && row["native-module-stem"].length > 0 - ? row["native-module-stem"] - : null; - return { - sqlName, - createsExtension: row["creates-extension"] !== false, - dependencies: canonicalSortedUniqueStrings(row["selected-extension-dependencies"], `${product}/${sqlName}.selected-extension-dependencies`), - dataFiles: canonicalSortedUniqueStrings(row["runtime-share-data-files"], `${product}/${sqlName}.runtime-share-data-files`), - extensionSqlFileNames: canonicalSortedUniqueStrings(row["extension-sql-file-names"], `${product}/${sqlName}.extension-sql-file-names`), - extensionSqlFilePrefixes: canonicalSortedUniqueStrings(row["extension-sql-file-prefixes"], `${product}/${sqlName}.extension-sql-file-prefixes`), - nativeModuleStem, - iosNativeDependencies: nativeModuleStem === null ? [] : (canonicalIosDependencies().get(sqlName) ?? []), - sharedPreloadLibraries: canonicalSortedUniqueStrings(row["shared-preload-libraries"], `${product}/${sqlName}.shared-preload-libraries`), - }; -} - -function assertCanonicalIosRegistration(member, expected, context) { - if (expected.nativeModuleStem === null) { - if (member.iosRegistration !== null) throw new Error(`${context} SQL-only extension fabricates iOS registration metadata`); - return; - } - const registration = member.iosRegistration; - if (registration === null || Array.isArray(registration) || typeof registration !== "object") { - throw new Error(`${context} native extension lacks iOS registration metadata`); - } - const expectedKeys = ["initSymbol", "magicSymbol", "nativeModuleStem", "schema", "sqlName", "symbols"].sort(compareText); - if (stableStringify(Object.keys(registration).sort(compareText)) !== stableStringify(expectedKeys)) { - throw new Error(`${context}.iosRegistration has a non-canonical key set`); - } - const prefix = `oliphaunt_static_${expected.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, "_")}`; - if ( - registration.schema !== "oliphaunt-ios-extension-registration-v1" - || registration.sqlName !== expected.sqlName - || registration.nativeModuleStem !== expected.nativeModuleStem - || registration.magicSymbol !== `${prefix}_Pg_magic_func` - || ![null, `${prefix}__PG_init`].includes(registration.initSymbol) - || !Array.isArray(registration.symbols) - ) { - throw new Error(`${context}.iosRegistration does not match its canonical native module identity`); - } - const normalizedSymbols = registration.symbols.map((row, index) => { - if ( - row === null - || Array.isArray(row) - || typeof row !== "object" - || stableStringify(Object.keys(row).sort(compareText)) !== stableStringify(["address", "name"]) - || typeof row.name !== "string" - || typeof row.address !== "string" - || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(row.name) - || !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(row.address) - ) { - throw new Error(`${context}.iosRegistration.symbols[${index}] is not a canonical C symbol mapping`); - } - return `${row.name}\0${row.address}`; - }); - if ( - new Set(registration.symbols.map((row) => row.name)).size !== registration.symbols.length - || stableStringify(normalizedSymbols) !== stableStringify([...normalizedSymbols].sort(compareText)) - ) { - throw new Error(`${context}.iosRegistration.symbols must be sorted with unique public names`); - } -} - -function assertCanonicalMemberSemantics(product, member, context) { - const expected = canonicalMemberSemantics(product, member?.sqlName); - for (const key of Object.keys(expected)) { - if (stableStringify(member?.[key]) !== stableStringify(expected[key])) { - throw new Error(`${context}.${key} differs from canonical generated extension metadata`); - } - } - assertCanonicalIosRegistration(member, expected, context); -} - -function assertCanonicalWasixInstall(member, context) { - assertWasixExtensionMemberInstall(member, { label: context }); -} - -export function assertCanonicalExtensionReleaseIdentity( - product, - version, - manifest, - context = "extension release manifest", - { family = manifest?.family ?? "combined", releaseProduct = manifest?.releaseProduct ?? product } = {}, -) { - if (manifest === null || Array.isArray(manifest) || typeof manifest !== "object") { - throw new Error(`${context} must be an object`); - } - const ownershipFieldCount = EXTENSION_OWNERSHIP_KEYS.filter((key) => manifest[key] !== undefined).length; - const metadata = extensionMetadata(product, PREFIX); - if (ownershipFieldCount !== 0 && ownershipFieldCount !== EXTENSION_OWNERSHIP_KEYS.length) { - throw new Error(`${context} must declare releaseProduct and family together`); - } - if (metadata.versioning === "runtime-bound" && ownershipFieldCount !== EXTENSION_OWNERSHIP_KEYS.length) { - throw new Error(`${context} runtime-owned carrier must declare releaseProduct and family`); - } - if (!["native", "wasix", "combined"].includes(family)) { - throw new Error(`${context}.family must be native, wasix, or combined`); - } - const expectedReleaseProduct = family === "combined" - ? product - : extensionReleaseProduct(product, family, PREFIX); - if (releaseProduct !== expectedReleaseProduct) { - throw new Error(`${context}.releaseProduct differs from canonical ${family} ownership`); - } - const expectedRoot = { - product, - ...(ownershipFieldCount === EXTENSION_OWNERSHIP_KEYS.length ? { - releaseProduct: expectedReleaseProduct, - family, - } : {}), - version, - extensionClass: metadata.class, - versioning: metadata.versioning, - sourceIdentity: extensionSourceIdentity(product, PREFIX), - compatibility: metadata.compatibility, - }; - for (const [key, expected] of Object.entries(expectedRoot)) { - if (stableStringify(manifest[key]) !== stableStringify(expected)) { - throw new Error(`${context}.${key} differs from canonical release identity`); - } - } - const expectedSqlNames = extensionSqlNames(product, PREFIX); - if (manifest.schema === "oliphaunt-extension-release-manifest-v1") { - if (expectedSqlNames.length !== 1 || manifest.sqlName !== expectedSqlNames[0]) { - throw new Error(`${context}.sqlName differs from its canonical release owner`); - } - assertCanonicalMemberSemantics(product, manifest, context); - return manifest; - } - if (manifest.schema === "oliphaunt-extension-release-manifest-v2") { - const actualSqlNames = Array.isArray(manifest.extensions) - ? manifest.extensions.map((member) => member?.sqlName) - : []; - if (stableStringify(actualSqlNames) !== stableStringify(expectedSqlNames)) { - throw new Error(`${context}.extensions differs from its canonical sorted member set`); - } - manifest.extensions.forEach((member, index) => - assertCanonicalMemberSemantics(product, member, `${context}.extensions[${index}]`)); - return manifest; - } - throw new Error(`${context} has unsupported extension release manifest schema ${JSON.stringify(manifest.schema)}`); -} - -async function validateExtensionManifest( - product, - version, - manifest, - context, - { family = manifest?.family, releaseProduct = manifest?.releaseProduct } = {}, -) { - try { - assertCanonicalExtensionReleaseIdentity(product, version, manifest, context, { - family, - releaseProduct, - }); - } catch (error) { - fail(error.message); - } - const seen = new Set(); - if (manifest.schema === "oliphaunt-extension-release-manifest-v1") { - validateKeySet( - manifest, - manifest.releaseProduct === undefined - ? PUBLIC_EXTENSION_RELEASE_LEGACY_KEYS - : PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS, - context, - ); - validateExtensionAssets(manifest.assets, context, seen); - try { - assertCanonicalWasixInstall(manifest, context); - } catch (error) { - fail(error.message); - } - return manifest.assets; - } - if (manifest.schema !== "oliphaunt-extension-release-manifest-v2") { - fail(`${context} has unsupported extension release manifest schema ${JSON.stringify(manifest.schema)}`); - } - validateKeySet( - manifest, - manifest.releaseProduct === undefined - ? PUBLIC_EXTENSION_BUNDLE_LEGACY_KEYS - : PUBLIC_EXTENSION_BUNDLE_MANIFEST_KEYS, - context, - ); - if (!Array.isArray(manifest.extensions) || manifest.extensions.length < 2) { - fail(`${context}.extensions must be a non-empty bundle member array`); - } - const expectedSqlNames = extensionSqlNames(product, PREFIX); - const actualSqlNames = manifest.extensions.map((member) => member?.sqlName); - if (stableStringify(actualSqlNames) !== stableStringify(expectedSqlNames)) { - fail(`${context}.extensions must exactly match the sorted release bundle member set`); - } - const carriers = validateBundleCarrierAssets(manifest.assets, context, expectedSqlNames.length); - const seenLocators = new Set(); - for (const [index, member] of manifest.extensions.entries()) { - const memberContext = `${context}.extensions[${index}]`; - if (member === null || Array.isArray(member) || typeof member !== "object") { - fail(`${memberContext} must be an object`); - } - validateKeySet(member, PUBLIC_EXTENSION_BUNDLE_MEMBER_KEYS, memberContext); - validateBundleMemberAssets(member.assets, memberContext, carriers, seenLocators); - try { - assertCanonicalWasixInstall(member, memberContext); - } catch (error) { - fail(error.message); - } - for (const asset of member.assets) { - const expectedMemberPath = `extensions/${member.sqlName}/${asset.name}`; - if (asset.memberPath !== expectedMemberPath) { - fail(`${memberContext} asset ${asset.name} must use memberPath ${expectedMemberPath}`); - } - } - } - return manifest.assets; -} - -function parseChecksumManifest(data, context) { - const checksums = new Map(); - const text = new TextDecoder().decode(data); - for (const [index, rawLine] of text.split(/\r?\n/u).entries()) { - const line = rawLine.trim(); - if (!line) { - continue; - } - const parts = line.split(/\s+/u); - if (parts.length !== 2) { - fail(`${context}:${index + 1} must contain ' ./'`); - } - const [sha, name] = parts; - validateSha256(sha, `${context}:${index + 1}`); - if (!name.startsWith("./") || name.slice(2).includes("/")) { - fail(`${context}:${index + 1} must reference a direct asset path like ./name`); - } - const assetName = name.slice(2); - if (checksums.has(assetName)) { - fail(`${context} declares duplicate checksum entry for ${assetName}`); - } - checksums.set(assetName, sha); - } - return checksums; -} - -function stableStringify(value) { - if (Array.isArray(value)) { - return `[${value.map(stableStringify).join(",")}]`; - } - if (value !== null && typeof value === "object") { - return `{${Object.keys(value) - .sort(compareText) - .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`) - .join(",")}}`; - } - return JSON.stringify(value); -} - -function canonicalSigstoreBundleForGhComparison(bundle) { - const canonical = structuredClone(bundle); - // The signing action emits an empty protobuf key ID; gh omits that default. - // Nonempty key IDs and every signature byte must still compare exactly. - if (Array.isArray(canonical?.dsseEnvelope?.signatures)) { - for (const signature of canonical.dsseEnvelope.signatures) { - if (signature?.keyid === "") delete signature.keyid; - } - } - const timestampVerificationData = - canonical?.verificationMaterial?.timestampVerificationData; - if ( - timestampVerificationData !== null - && !Array.isArray(timestampVerificationData) - && typeof timestampVerificationData === "object" - && Array.isArray(timestampVerificationData.rfc3161Timestamps) - && timestampVerificationData.rfc3161Timestamps.length === 0 - ) { - // actions/attest v3 serializes this protobuf default as an empty repeated - // field, while gh's Go protobuf serializer omits it after successfully - // verifying the exact supplied bundle. Canonicalize only that known - // representation difference; every signed and verification-material byte - // represented by the bundle must still compare exactly. - delete timestampVerificationData.rfc3161Timestamps; - } - return canonical; -} - -export function assertGhVerifiedBundleMatchesSupplied( - verifiedBundle, - suppliedBundle, - context = "gh verification output", -) { - if ( - stableStringify(canonicalSigstoreBundleForGhComparison(verifiedBundle)) - !== stableStringify(canonicalSigstoreBundleForGhComparison(suppliedBundle)) - ) { - throw new Error(`${context} does not contain the supplied bundle`); - } -} - -export function assertExactReleaseAssetNames({ product, tag, expectedNames, actualNames }) { - const expected = new Set(expectedNames); - const actual = new Set(actualNames); - const missing = [...expected].filter((name) => !actual.has(name)).sort(compareText); - const unexpected = [...actual].filter((name) => !expected.has(name)).sort(compareText); - if (missing.length > 0 || unexpected.length > 0) { - const details = [ - ...(missing.length > 0 ? [`missing: ${missing.join(", ")}`] : []), - ...(unexpected.length > 0 ? [`unexpected: ${unexpected.join(", ")}`] : []), - ]; - throw new Error(`${product} GitHub release ${tag} asset set mismatch (${details.join("; ")})`); - } -} - -function requireObject(value, context) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - throw new Error(`${context} must be an object`); - } - return value; -} - -function assertKeySet(value, keys, context) { - requireObject(value, context); - const actual = Object.keys(value).sort(compareText); - const expected = [...keys].sort(compareText); - if (stableStringify(actual) !== stableStringify(expected)) { - throw new Error(`${context} keys must be ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`); - } -} - -function requireSha256(value, context) { - if (typeof value !== "string" || !/^[0-9a-f]{64}$/u.test(value)) { - throw new Error(`${context} must be a lowercase SHA-256 digest`); - } - return value; -} - -function normalizeGithubId(value, context) { - if (Number.isSafeInteger(value) && value > 0) { - return String(value); - } - if (typeof value === "string" && /^[1-9][0-9]*$/u.test(value)) { - return value; - } - throw new Error(`${context} must be a positive integer ID`); -} - -function normalizedRepository(value) { - if ( - typeof value !== "string" - || !/^[^/\s\0]+\/[^/\s\0]+$/u.test(value) - || value.includes("..") - ) { - throw new Error(`GitHub repository must be an owner/name pair, got ${JSON.stringify(value)}`); - } - return value; -} - -function frozenProductTag(product) { - if ( - product === null - || Array.isArray(product) - || typeof product !== "object" - || typeof product.id !== "string" - || product.id.length === 0 - || typeof product.version !== "string" - || product.version.length === 0 - ) { - throw new Error("publication lock contains an invalid product row"); - } - return `${product.id}-v${product.version}`; -} - -export function frozenGithubReleaseAssets(lock) { - if (!Array.isArray(lock?.products) || !Array.isArray(lock?.productArtifacts)) { - throw new Error("publication lock must contain products and productArtifacts arrays"); - } - const products = new Set(); - for (const product of lock.products) { - frozenProductTag(product); - if (products.has(product.id)) { - throw new Error(`publication lock contains duplicate product ${product.id}`); - } - products.add(product.id); - } - const identities = new Set(); - const assets = []; - for (const artifact of lock.productArtifacts) { - if (!GITHUB_RELEASE_ARTIFACT_ROLES.has(artifact?.role)) continue; - if (!products.has(artifact.product)) { - throw new Error(`frozen GitHub asset ${artifact?.name ?? ""} belongs to unselected product ${artifact?.product ?? ""}`); - } - if ( - typeof artifact.name !== "string" - || artifact.name.length === 0 - || artifact.name.includes("/") - || artifact.name.includes("\\") - || /[\0\r\n]/u.test(artifact.name) - ) { - throw new Error(`${artifact.product} contains an invalid frozen GitHub asset name`); - } - requireSha256(artifact.sha256, `${artifact.product}/${artifact.name} frozen sha256`); - if (!Number.isSafeInteger(artifact.size) || artifact.size < 0) { - throw new Error(`${artifact.product}/${artifact.name} frozen size must be a non-negative safe integer`); - } - if (typeof artifact.path !== "string" || artifact.path.length === 0) { - throw new Error(`${artifact.product}/${artifact.name} frozen path must be non-empty`); - } - const identity = `${artifact.product}\0${artifact.name}`; - if (identities.has(identity)) { - throw new Error(`publication lock contains duplicate GitHub asset ${artifact.product}/${artifact.name}`); - } - identities.add(identity); - assets.push({ - name: artifact.name, - path: artifact.path, - product: artifact.product, - sha256: artifact.sha256, - size: artifact.size, - }); - } - return assets.sort((left, right) => - compareText(left.product, right.product) || compareText(left.name, right.name)); -} - -function expectedAssetsByProduct(lock) { - const grouped = new Map(lock.products.map((product) => [product.id, []])); - for (const asset of frozenGithubReleaseAssets(lock)) { - grouped.get(asset.product).push(asset); - } - return grouped; -} - -async function mapConcurrent(values, concurrency, worker) { - if (!Number.isSafeInteger(concurrency) || concurrency <= 0) { - throw new Error("concurrency must be a positive safe integer"); - } - const output = new Array(values.length); - let next = 0; - let failure; - const runWorker = async () => { - for (;;) { - if (failure !== undefined) return; - const index = next; - next += 1; - if (index >= values.length) return; - try { - output[index] = await worker(values[index], index); - } catch (error) { - failure ??= error; - return; - } - } - }; - await Promise.all(Array.from( - { length: Math.min(values.length, concurrency) }, - () => runWorker(), - )); - if (failure !== undefined) throw failure; - return output; -} - -function repositoryApiBase(repo) { - const repoPath = encodeURIComponent(repo).replaceAll("%2F", "/"); - return `${GITHUB_API.replace(/\/$/u, "")}/repos/${repoPath}`; -} - -function releasesListApiUrl(repo, page) { - return `${repositoryApiBase(repo)}/releases?per_page=${GITHUB_RELEASE_LIST_PAGE_SIZE}&page=${page}`; -} - -function releaseAssetsListApiUrl(repo, releaseId, page) { - return `${repositoryApiBase(repo)}/releases/${releaseId}/assets?per_page=${GITHUB_RELEASE_LIST_PAGE_SIZE}&page=${page}`; -} - -function requiredGithubAuthToken(value = process.env.GH_TOKEN || process.env.GITHUB_TOKEN) { - if ( - typeof value !== "string" - || value.length === 0 - || value.trim() !== value - || /[\0\r\n]/u.test(value) - ) { - throw new Error("authenticated GitHub release snapshots require GH_TOKEN or GITHUB_TOKEN"); - } - return value; -} - -async function requestGithubArrayPages({ - authToken, - context, - deadlineMs, - fetchImpl, - nowImpl, - sleepImpl, - urlForPage, -}) { - const rows = []; - for (let page = 1; page <= GITHUB_RELEASE_LIST_MAX_PAGES; page += 1) { - const url = urlForPage(page); - const { data, link } = await requestGithubJsonWithRetry(url, { - authToken, - deadlineMs, - fetchImpl, - nowImpl, - responseMetadata: true, - sleepImpl, - }); - if (!Array.isArray(data)) { - throw new Error(`${context} page ${page} must be an array`); - } - if (data.length > GITHUB_RELEASE_LIST_PAGE_SIZE) { - throw new Error( - `${context} page ${page} exceeds ${GITHUB_RELEASE_LIST_PAGE_SIZE} rows`, - ); - } - rows.push(...data); - const hasNext = /(?:^|,)\s*<[^>]+>\s*;\s*rel="next"(?:\s*;[^,]*)?(?:,|$)/iu.test(link); - if (!hasNext) return rows; - if (data.length !== GITHUB_RELEASE_LIST_PAGE_SIZE) { - throw new Error(`${context} advertises another page after only ${data.length} rows`); - } - } - throw new Error(`${context} exceeds ${GITHUB_RELEASE_LIST_MAX_PAGES} pages`); -} - -function normalizeRemoteAsset(asset, expected, product, tag) { - requireObject(asset, `${product} GitHub release ${tag} asset ${expected.name}`); - if (asset.name !== expected.name) { - throw new Error(`${product} GitHub release ${tag} asset name changed while it was being validated`); - } - if (asset.state !== "uploaded") { - throw new GithubReleaseSnapshotNotReadyError( - `${product} GitHub release ${tag} asset ${expected.name} is not fully uploaded`, - ); - } - if (!Number.isSafeInteger(asset.size) || asset.size < 0 || asset.size !== expected.size) { - throw new Error( - `${product} GitHub release ${tag} asset ${expected.name} size ${JSON.stringify(asset.size)} does not match frozen size ${expected.size}`, - ); - } - const expectedDigest = `sha256:${expected.sha256}`; - if (asset.digest !== expectedDigest) { - if (asset.digest === null || asset.digest === undefined || asset.digest === "") { - throw new GithubReleaseSnapshotNotReadyError( - `${product} GitHub release ${tag} asset ${expected.name} is missing GitHub digest metadata`, - ); - } - throw new Error( - `${product} GitHub release ${tag} asset ${expected.name} digest ${JSON.stringify(asset.digest)} does not match ${expectedDigest}`, - ); - } - return { - assetId: normalizeGithubId(asset.id, `${product} GitHub release ${tag} asset ${expected.name} id`), - name: expected.name, - sha256: expected.sha256, - size: expected.size, - }; -} - -class GithubReleaseSnapshotNotReadyError extends Error { - constructor(message) { - super(message); - this.name = "GithubReleaseSnapshotNotReadyError"; - } -} - -function exactProductSet(expected, actual, context) { - const expectedSet = new Set(expected); - const actualSet = new Set(actual); - const missing = [...expectedSet].filter((value) => !actualSet.has(value)).sort(compareText); - const extra = [...actualSet].filter((value) => !expectedSet.has(value)).sort(compareText); - if (missing.length > 0 || extra.length > 0 || actual.length !== actualSet.size) { - throw new Error(`${context} mismatch: missing=${JSON.stringify(missing)}, extra=${JSON.stringify(extra)}, duplicate=${actual.length !== actualSet.size}`); - } -} - -export function normalizeGithubReleaseSnapshot(lock, releases) { - if (!Array.isArray(releases)) { - throw new Error("GitHub release snapshot must be an array"); - } - const products = [...lock.products].sort((left, right) => compareText(left.id, right.id)); - exactProductSet( - products.map((product) => product.id), - releases.map((release) => release?.product), - "GitHub release snapshot product set", - ); - const expectedByProduct = expectedAssetsByProduct(lock); - const releaseIds = new Set(); - const assetIds = new Set(); - const normalized = []; - for (const product of products) { - const release = releases.find((candidate) => candidate?.product === product.id); - const context = `${product.id} GitHub release snapshot`; - assertKeySet(release, [ - "assets", - "draft", - "prerelease", - "product", - "releaseId", - "releaseName", - "tag", - "targetCommitish", - "version", - ], context); - const tag = frozenProductTag(product); - if ( - release.version !== product.version - || release.tag !== tag - || release.releaseName !== `${product.id} v${product.version}` - || release.targetCommitish !== lock.source.commit - || release.prerelease !== product.version.includes("-") - || typeof release.draft !== "boolean" - ) { - throw new Error(`${context} metadata does not match the frozen publication lock`); - } - const releaseId = normalizeGithubId(release.releaseId, `${context} id`); - if (releaseIds.has(releaseId)) { - throw new Error(`GitHub release snapshot reuses release id ${releaseId}`); - } - releaseIds.add(releaseId); - if (!Array.isArray(release.assets)) { - throw new Error(`${context}.assets must be an array`); - } - const expectedAssets = expectedByProduct.get(product.id); - assertExactReleaseAssetNames({ - product: product.id, - tag, - expectedNames: expectedAssets.map((asset) => asset.name), - actualNames: release.assets.map((asset) => asset?.name), - }); - if (new Set(release.assets.map((asset) => asset?.name)).size !== release.assets.length) { - throw new Error(`${context} contains duplicate asset names`); - } - const assets = []; - for (const expected of expectedAssets) { - const asset = release.assets.find((candidate) => candidate?.name === expected.name); - assertKeySet(asset, ["assetId", "name", "sha256", "size"], `${context} asset ${expected.name}`); - if (asset.sha256 !== expected.sha256 || asset.size !== expected.size) { - throw new Error(`${context} asset ${expected.name} differs from the frozen publication lock`); - } - const assetId = normalizeGithubId(asset.assetId, `${context} asset ${expected.name} id`); - if (assetIds.has(assetId)) { - throw new Error(`GitHub release snapshot reuses asset id ${assetId}`); - } - assetIds.add(assetId); - assets.push({ - assetId, - name: expected.name, - sha256: expected.sha256, - size: expected.size, - }); - } - normalized.push({ - assets, - draft: release.draft, - prerelease: release.prerelease, - product: product.id, - releaseId, - releaseName: release.releaseName, - tag, - targetCommitish: lock.source.commit, - version: product.version, - }); - } - return normalized; -} - -async function queryLockedGithubReleasesOnce(lock, { - authToken, - deadlineMs, - fetchImpl = fetch, - nowImpl = Date.now, - repo = repository(), - sleepImpl, -} = {}) { - const canonicalRepo = normalizedRepository(repo); - const token = requiredGithubAuthToken(authToken); - const effectiveDeadline = deadlineMs ?? githubReleaseQueryDeadline(nowImpl()); - const expectedByProduct = expectedAssetsByProduct(lock); - const products = [...lock.products].sort((left, right) => compareText(left.id, right.id)); - const selectedTags = new Set(products.map(frozenProductTag)); - const listedReleases = await requestGithubArrayPages({ - authToken: token, - context: `${canonicalRepo} GitHub release list`, - deadlineMs: effectiveDeadline, - fetchImpl, - nowImpl, - sleepImpl, - urlForPage: (page) => releasesListApiUrl(canonicalRepo, page), - }); - const releasesByTag = new Map(); - const releaseIds = new Set(); - for (const [index, release] of listedReleases.entries()) { - const context = `${canonicalRepo} GitHub release list row ${index}`; - requireObject(release, context); - if (typeof release.tag_name !== "string" || release.tag_name.length === 0) { - throw new Error(`${context}.tag_name must be a non-empty string`); - } - const releaseId = normalizeGithubId(release.id, `${context}.id`); - if (releaseIds.has(releaseId)) { - throw new Error(`${canonicalRepo} GitHub release list reuses release id ${releaseId}`); - } - releaseIds.add(releaseId); - if (!selectedTags.has(release.tag_name)) continue; - if (releasesByTag.has(release.tag_name)) { - throw new Error(`${canonicalRepo} returned duplicate releases for selected tag ${release.tag_name}`); - } - releasesByTag.set(release.tag_name, release); - } - const missingTags = [...selectedTags] - .filter((tag) => !releasesByTag.has(tag)) - .sort(compareText); - if (missingTags.length > 0) { - throw new GithubReleaseSnapshotNotReadyError( - `${canonicalRepo} GitHub release list is not yet exposing selected release(s): ${missingTags.join(", ")}`, - ); - } - - // Reject immutable release identity/metadata conflicts before fanning out - // to the per-release asset endpoints. The embedded assets field is neither - // authoritative nor required; every product is inventoried separately. - for (const product of products) { - const tag = frozenProductTag(product); - const data = releasesByTag.get(tag); - requireObject(data, `${product.id} GitHub release ${tag}`); - if ( - data.tag_name !== tag - || data.name !== `${product.id} v${product.version}` - || data.target_commitish !== lock.source.commit - || data.prerelease !== product.version.includes("-") - || typeof data.draft !== "boolean" - ) { - throw new Error(`${product.id} GitHub release ${tag} metadata does not match the frozen publication lock`); - } - } - - const exactAssetRows = new Map(await mapConcurrent( - products, - GITHUB_RELEASE_FALLBACK_QUERY_CONCURRENCY, - async (product) => { - const tag = frozenProductTag(product); - const release = releasesByTag.get(tag); - const releaseId = normalizeGithubId(release.id, `${product.id} GitHub release ${tag} id`); - const assets = await requestGithubArrayPages({ - authToken: token, - context: `${product.id} GitHub release ${tag} asset list`, - deadlineMs: effectiveDeadline, - fetchImpl, - nowImpl, - sleepImpl, - urlForPage: (page) => releaseAssetsListApiUrl(canonicalRepo, releaseId, page), - }); - return [product.id, assets]; - }, - )); - - const releases = products.map((product) => { - const tag = frozenProductTag(product); - const data = releasesByTag.get(tag); - requireObject(data, `${product.id} GitHub release ${tag}`); - const expectedAssets = expectedByProduct.get(product.id); - const remoteAssets = exactAssetRows.get(product.id); - const names = remoteAssets.map((asset) => { - if (asset === null || Array.isArray(asset) || typeof asset !== "object" || typeof asset.name !== "string") { - throw new Error(`${product.id} GitHub release ${tag} contains an invalid asset row`); - } - return asset.name; - }); - const expectedNames = expectedAssets.map((asset) => asset.name); - const actualNameSet = new Set(names); - const expectedNameSet = new Set(expectedNames); - const missing = expectedNames.filter((name) => !actualNameSet.has(name)); - const unexpected = names.filter((name) => !expectedNameSet.has(name)); - if (unexpected.length > 0) { - assertExactReleaseAssetNames({ - product: product.id, - tag, - expectedNames, - actualNames: names, - }); - } - if (missing.length > 0) { - throw new GithubReleaseSnapshotNotReadyError( - `${product.id} GitHub release ${tag} is not yet exposing frozen asset(s): ${missing.sort(compareText).join(", ")}`, - ); - } - if (new Set(names).size !== names.length) { - throw new Error(`${product.id} GitHub release ${tag} contains duplicate asset names`); - } - const byName = new Map(remoteAssets.map((asset) => [asset.name, asset])); - return { - assets: expectedAssets.map((expected) => - normalizeRemoteAsset(byName.get(expected.name), expected, product.id, tag)), - draft: data.draft, - prerelease: data.prerelease, - product: product.id, - releaseId: normalizeGithubId(data.id, `${product.id} GitHub release ${tag} id`), - releaseName: data.name, - tag, - targetCommitish: data.target_commitish, - version: product.version, - }; - }); - return normalizeGithubReleaseSnapshot(lock, releases); -} - -export async function queryLockedGithubReleases(lock, options = {}) { - const nowImpl = options.nowImpl ?? Date.now; - const sleepImpl = options.sleepImpl - ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds))); - const deadlineMs = options.deadlineMs ?? githubReleaseQueryDeadline(nowImpl()); - const maxAttempts = options.snapshotMaxAttempts ?? GITHUB_RELEASE_SNAPSHOT_MAX_ATTEMPTS; - if (!Number.isSafeInteger(maxAttempts) || maxAttempts <= 0) { - throw new Error("GitHub release snapshot maxAttempts must be a positive safe integer"); - } - let lastError; - for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { - try { - return await queryLockedGithubReleasesOnce(lock, { - ...options, - deadlineMs, - nowImpl, - sleepImpl, - }); - } catch (error) { - if (!(error instanceof GithubReleaseSnapshotNotReadyError)) { - throw error; - } - lastError = error; - if (attempt === maxAttempts) { - throw new Error( - `GitHub release snapshot readiness retries exhausted after ${maxAttempts} attempts: ${error.message}`, - { cause: error }, - ); - } - } - const delay = Math.min( - GITHUB_RELEASE_SNAPSHOT_MAX_RETRY_DELAY_MS, - 1_000 * 2 ** (attempt - 1), - ); - const now = nowImpl(); - if (now + delay >= deadlineMs) { - throw new Error(`GitHub release snapshot retry would exceed its deadline: ${lastError.message}`); - } - await sleepImpl(delay); - } - throw lastError; -} - -function normalizeAttestationSubjects(subjects, context) { - if (!Array.isArray(subjects) || subjects.length === 0) { - throw new Error(`${context} must contain a non-empty subject array`); - } - const keys = new Set(); - const normalized = []; - for (const [index, subject] of subjects.entries()) { - const subjectContext = `${context} subject[${index}]`; - assertKeySet(subject, ["digest", "name"], subjectContext); - if ( - typeof subject.name !== "string" - || subject.name.length === 0 - || subject.name.includes("/") - || subject.name.includes("\\") - || /[\0\r\n]/u.test(subject.name) - ) { - throw new Error(`${subjectContext}.name must be a direct asset basename`); - } - assertKeySet(subject.digest, ["sha256"], `${subjectContext}.digest`); - const sha256 = requireSha256(subject.digest.sha256, `${subjectContext}.digest.sha256`); - const key = `${subject.name}\0${sha256}`; - if (keys.has(key)) { - throw new Error(`${context} contains duplicate subject ${subject.name}/${sha256}`); - } - keys.add(key); - normalized.push({ name: subject.name, sha256 }); - } - return normalized.sort((left, right) => - compareText(left.name, right.name) || compareText(left.sha256, right.sha256)); -} - -function normalizedReceiptSubjects(subjects, context) { - if (!Array.isArray(subjects)) { - throw new Error(`${context} subjects must be an array`); - } - return normalizeAttestationSubjects( - subjects.map((subject) => ({ - digest: { sha256: subject?.sha256 }, - name: subject?.name, - })), - context, - ); -} - -function githubAssetSubjectKey(value) { - return `${value.name}\0${value.sha256}`; -} - -export function assertAttestationSubjectCoverage(assets, attestations) { - if (!Array.isArray(assets) || !Array.isArray(attestations)) { - throw new Error("attestation coverage requires asset and attestation arrays"); - } - if (assets.length === 0 && attestations.length > 0) { - throw new Error("attestation bundles contaminate a release selection with no frozen GitHub assets"); - } - const expectedByName = new Map(); - const expectedByKey = new Map(); - for (const asset of assets) { - requireSha256(asset?.sha256, `${asset?.product ?? ""}/${asset?.name ?? ""} sha256`); - const key = githubAssetSubjectKey(asset); - const namedDigests = expectedByName.get(asset.name) ?? new Set(); - namedDigests.add(asset.sha256); - expectedByName.set(asset.name, namedDigests); - const matchingAssets = expectedByKey.get(key) ?? []; - matchingAssets.push(asset); - expectedByKey.set(key, matchingAssets); - } - const covered = new Set(); - const bundleDigests = new Set(); - const normalized = []; - for (const [index, attestation] of attestations.entries()) { - assertKeySet(attestation, ["bundleSha256", "subjects"], `attestation[${index}]`); - const bundleSha256 = requireSha256(attestation.bundleSha256, `attestation[${index}].bundleSha256`); - if (bundleDigests.has(bundleSha256)) { - throw new Error(`attestation bundle ${bundleSha256} was supplied more than once`); - } - bundleDigests.add(bundleSha256); - const subjects = normalizedReceiptSubjects(attestation.subjects, `attestation bundle ${bundleSha256}`); - for (const subject of subjects) { - const key = githubAssetSubjectKey(subject); - if (!expectedByKey.has(key)) { - if (expectedByName.has(subject.name)) { - throw new Error(`attestation bundle ${bundleSha256} subject ${subject.name} digest differs from the frozen GitHub asset`); - } - throw new Error(`attestation bundle ${bundleSha256} contains non-frozen subject ${subject.name}`); - } - if (covered.has(key)) { - throw new Error(`signed subject ${subject.name} overlaps multiple attestation bundles`); - } - covered.add(key); - } - normalized.push({ bundleSha256, subjects }); - } - const missing = [...expectedByKey] - .filter(([key]) => !covered.has(key)) - .flatMap(([, matchingAssets]) => matchingAssets.map((asset) => `${asset.product}/${asset.name}`)) - .sort(compareText); - if (missing.length > 0) { - throw new Error(`frozen GitHub assets are missing signed subjects: ${missing.join(", ")}`); - } - return normalized.sort((left, right) => compareText(left.bundleSha256, right.bundleSha256)); -} - -function receiptDigest(receipt) { - const copy = structuredClone(receipt); - delete copy.receiptDigest; - return createHash("sha256").update(stableStringify(copy)).digest("hex"); -} - -function githubSignerWorkflow(repo) { - return `${repo}/.github/workflows/release.yml`; -} - -export function buildGithubAttestationReceipt({ - attestations, - lock, - releases, - repo = repository(), - publisherSha = lock.source.commit, -}) { - const canonicalRepo = normalizedRepository(repo); - const normalizedReleases = normalizeGithubReleaseSnapshot(lock, releases); - const normalizedAttestations = assertAttestationSubjectCoverage( - frozenGithubReleaseAssets(lock), - attestations, - ); - const receipt = { - attestations: normalizedAttestations, - head: lock.source.commit, - lockDigest: lock.lockDigest, - releases: normalizedReleases, - repository: canonicalRepo, - schema: GITHUB_ATTESTATION_RECEIPT_SCHEMA, - signerWorkflow: githubSignerWorkflow(canonicalRepo), - sourceRef: "refs/heads/main", - sourceTree: lock.source.tree, - ...(publisherSha === lock.source.commit ? {} : { publisherSha }), - }; - receipt.receiptDigest = receiptDigest(receipt); - return receipt; -} - -export function validateGithubAttestationReceipt(receipt, lock, { repo = repository() } = {}) { - const canonicalRepo = normalizedRepository(repo); - assertKeySet(receipt, [ - "attestations", - "head", - "lockDigest", - "receiptDigest", - "releases", - "repository", - "schema", - "signerWorkflow", - "sourceRef", - "sourceTree", - ...(Object.hasOwn(receipt, "publisherSha") ? ["publisherSha"] : []), - ], "GitHub attestation receipt"); - if (receipt.publisherSha !== undefined && !/^[0-9a-f]{40}$/u.test(receipt.publisherSha)) { - throw new Error("GitHub attestation receipt publisher SHA is invalid"); - } - if ( - receipt.schema !== GITHUB_ATTESTATION_RECEIPT_SCHEMA - || receipt.repository !== canonicalRepo - || receipt.head !== lock.source.commit - || receipt.sourceTree !== lock.source.tree - || receipt.lockDigest !== lock.lockDigest - || receipt.signerWorkflow !== githubSignerWorkflow(canonicalRepo) - || receipt.sourceRef !== "refs/heads/main" - ) { - throw new Error("GitHub attestation receipt identity does not match the repository, source, or publication lock"); - } - requireSha256(receipt.receiptDigest, "GitHub attestation receipt digest"); - const expectedDigest = receiptDigest(receipt); - if (receipt.receiptDigest !== expectedDigest) { - throw new Error(`GitHub attestation receipt digest mismatch: expected ${expectedDigest}, got ${receipt.receiptDigest}`); - } - const releases = normalizeGithubReleaseSnapshot(lock, receipt.releases); - const attestations = assertAttestationSubjectCoverage( - frozenGithubReleaseAssets(lock), - receipt.attestations, - ); - if ( - stableStringify(releases) !== stableStringify(receipt.releases) - || stableStringify(attestations) !== stableStringify(receipt.attestations) - ) { - throw new Error("GitHub attestation receipt is not in deterministic canonical order"); - } - return receipt; -} - -export function assertGithubReleaseSnapshotMatchesReceipt(receipt, releases) { - if (stableStringify(releases) !== stableStringify(receipt?.releases)) { - throw new Error("GitHub release or asset IDs, names, sizes, or digests changed after the pre-mutation receipt was created"); - } -} - -async function verifyExtensionReleaseAssets( - product, - releaseProduct, - version, - family, - actualAssets, -) { - const manifestName = `${product}-${version}-manifest.json`; - const propertiesName = `${product}-${version}-manifest.properties`; - const swiftCarrierName = swiftExtensionCarrierAssetName(product, version); - const checksumName = `${product}-${version}-release-assets.sha256`; - const rootFamily = family === "combined" ? "native" : family; - const localReleaseAssetRoot = path.join( - ROOT, - extensionArtifactProductRoot(product, rootFamily, "target/extension-artifacts", PREFIX), - "release-assets", - ); - const localManifestPath = path.join(localReleaseAssetRoot, manifestName); - const localSwiftCarrierPath = path.join(localReleaseAssetRoot, swiftCarrierName); - const localManifest = await readJson(localManifestPath); - const includeSwiftCarrier = family !== "wasix"; - const localSwiftCarrier = includeSwiftCarrier ? await readJson(localSwiftCarrierPath) : null; - const proofs = new Map(); - - const manifestAsset = actualAssets.get(manifestName); - const manifestSize = expectedAssetSize(manifestAsset.size, manifestName, MAX_CONTROL_ASSET_BYTES); - const manifestBytes = await requestBytes(manifestAsset.url, manifestName, manifestSize); - proofs.set(manifestName, { bytes: manifestBytes.byteLength, sha256: sha256Bytes(manifestBytes) }); - const remoteManifest = JSON.parse(new TextDecoder().decode(manifestBytes)); - if (stableStringify(remoteManifest) !== stableStringify(localManifest)) { - fail(`${product} GitHub release ${await productTag(releaseProduct, version)} public manifest differs from staged manifest`); - } - const extensionAssets = await validateExtensionManifest( - product, - version, - remoteManifest, - `${product} ${version} public extension manifest`, - { family, releaseProduct }, - ); - - if (includeSwiftCarrier) { - const swiftCarrierAsset = actualAssets.get(swiftCarrierName); - const swiftCarrierSize = expectedAssetSize(swiftCarrierAsset.size, swiftCarrierName, MAX_CONTROL_ASSET_BYTES); - const swiftCarrierBytes = await requestBytes(swiftCarrierAsset.url, swiftCarrierName, swiftCarrierSize); - proofs.set(swiftCarrierName, { bytes: swiftCarrierBytes.byteLength, sha256: sha256Bytes(swiftCarrierBytes) }); - const remoteSwiftCarrier = JSON.parse(new TextDecoder().decode(swiftCarrierBytes)); - if (stableStringify(remoteSwiftCarrier) !== stableStringify(localSwiftCarrier)) { - fail(`${product} GitHub release ${await productTag(releaseProduct, version)} Swift iOS carrier differs from staged carrier`); - } - } - - const checksumAsset = actualAssets.get(checksumName); - const checksumSize = expectedAssetSize(checksumAsset.size, checksumName, MAX_CONTROL_ASSET_BYTES); - const checksumBytes = await requestBytes(checksumAsset.url, checksumName, checksumSize); - proofs.set(checksumName, { bytes: checksumBytes.byteLength, sha256: sha256Bytes(checksumBytes) }); - const checksums = parseChecksumManifest(checksumBytes, checksumName); - const checksumCoveredNames = new Set(extensionAssets.map((asset) => asset.name)); - checksumCoveredNames.add(manifestName); - checksumCoveredNames.add(propertiesName); - if (includeSwiftCarrier) checksumCoveredNames.add(swiftCarrierName); - if ( - stableStringify([...checksums.keys()].sort(compareText)) !== - stableStringify([...checksumCoveredNames].sort(compareText)) - ) { - fail( - `${product} GitHub release ${await productTag(releaseProduct, version)} checksum manifest must cover release assets exactly`, - ); - } - - for (const name of [...checksumCoveredNames].sort(compareText)) { - if (!actualAssets.has(name)) { - fail(`${product} GitHub release ${await productTag(releaseProduct, version)} is missing checksum-covered asset ${name}`); - } - const actualAsset = actualAssets.get(name); - const manifestAsset = extensionAssets.find((asset) => asset.name === name); - const remoteSize = expectedAssetSize(actualAsset.size, name); - if (manifestAsset !== undefined && remoteSize !== manifestAsset.bytes) { - fail(`${product} GitHub release ${await productTag(releaseProduct, version)} asset ${name} size metadata mismatch`); - } - let proof = proofs.get(name); - if (proof === undefined) { - proof = await requestAssetProof(actualAsset.url, name, manifestAsset?.bytes ?? remoteSize); - proofs.set(name, proof); - } - if (proof.sha256 !== checksums.get(name)) { - fail(`${product} GitHub release ${await productTag(releaseProduct, version)} asset ${name} checksum mismatch`); - } - if (remoteSize !== proof.bytes) { - fail(`${product} GitHub release ${await productTag(releaseProduct, version)} asset ${name} size mismatch`); - } - } - - for (const asset of extensionAssets) { - const proof = proofs.get(asset.name); - if (proof.bytes !== asset.bytes || proof.sha256 !== asset.sha256) { - fail(`${product} GitHub release ${await productTag(releaseProduct, version)} asset ${asset.name} public manifest mismatch`); - } - } -} - -async function verifyReleaseAssets(product, version, assets) { - const repo = repository(); - const tag = await productTag(product, version); - const actualAssets = await releaseAssets(repo, tag); - const expectedNames = new Set(assets); - try { - assertExactReleaseAssetNames({ - product, - tag, - expectedNames, - actualNames: actualAssets.keys(), - }); - } catch (error) { - fail(error.message); - } - const config = await productConfig(product); - if (["exact-extension-artifact", "exact-extension-bundle"].includes(config.kind)) { - await verifyExtensionReleaseAssets(product, product, version, "combined", actualAssets); - } else if (product === "liboliphaunt-native" || product === "liboliphaunt-wasix") { - const contrib = contribCarrierDescriptor(PREFIX); - if (assets.includes(`${contrib.artifactProduct}-${version}-manifest.json`)) { - await verifyExtensionReleaseAssets( - contrib.artifactProduct, - product, - version, - product === "liboliphaunt-native" ? "native" : "wasix", - actualAssets, - ); - } - } - console.log(`${product} GitHub release assets verified for ${tag}: ${assets.join(", ")}`); -} - -async function readBoundedRegularFile(file, maximum, context) { - let stat; - try { - stat = await fs.lstat(file); - } catch (error) { - throw new Error(`${context} is unavailable: ${error.message}`); - } - if (stat.isSymbolicLink() || !stat.isFile()) { - throw new Error(`${context} must be a regular non-symlink file`); - } - if (!Number.isSafeInteger(stat.size) || stat.size < 0 || stat.size > maximum) { - throw new Error(`${context} exceeds ${maximum} bytes`); - } - const bytes = await fs.readFile(file); - if (bytes.byteLength !== stat.size || bytes.byteLength > maximum) { - throw new Error(`${context} changed while it was being read`); - } - return bytes; -} - -function parseJsonBytes(bytes, context) { - let text; - try { - text = new TextDecoder("utf-8", { fatal: true }).decode(bytes); - } catch (error) { - throw new Error(`${context} is not valid UTF-8: ${error.message}`); - } - try { - return JSON.parse(text); - } catch (error) { - throw new Error(`${context} is not one JSON value: ${error.message}`); - } -} - -function decodeBundleStatement(bundle, context) { - requireObject(bundle, context); - const payload = bundle.dsseEnvelope?.payload; - if (typeof payload !== "string" || payload.length === 0 || !/^[A-Za-z0-9+/]+={0,2}$/u.test(payload)) { - throw new Error(`${context} lacks a canonical base64 DSSE payload`); - } - const bytes = Buffer.from(payload, "base64"); - if (bytes.toString("base64") !== payload) { - throw new Error(`${context} DSSE payload is not canonical base64`); - } - const statement = parseJsonBytes(bytes, `${context} DSSE statement`); - requireObject(statement, `${context} DSSE statement`); - return statement; -} - -function statementSubjects(statement, context) { - if (statement._type !== IN_TOTO_STATEMENT_V1) { - throw new Error(`${context} must be an in-toto v1 statement`); - } - if (statement.predicateType !== SLSA_PROVENANCE_V1) { - throw new Error(`${context} must be an in-toto v1 SLSA provenance v1 statement`); - } - return normalizeAttestationSubjects(statement.subject, context); -} - -async function lockedLocalSubject(asset) { - const file = path.resolve(ROOT, asset.path); - const relative = path.relative(ROOT, file); - if (relative === "" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { - throw new Error(`${asset.product}/${asset.name} frozen path must remain inside the repository`); - } - let stat; - try { - stat = await fs.lstat(file); - } catch (error) { - throw new Error(`${asset.product}/${asset.name} frozen local subject is missing: ${error.message}`); - } - if (stat.isSymbolicLink() || !stat.isFile()) { - throw new Error(`${asset.product}/${asset.name} frozen local subject must be a regular non-symlink file`); - } - if (stat.size !== asset.size || path.basename(file) !== asset.name) { - throw new Error(`${asset.product}/${asset.name} frozen local subject path or size differs from the publication lock`); - } - return file; -} - -export function ghBundleVerifyArgs({ - bundlePath, - file, - head, - repo, -}) { - if (typeof head !== "string" || !/^[0-9a-f]{40}$/u.test(head)) { - throw new Error("attestation source head must be a full lowercase commit SHA"); - } - const canonicalRepo = normalizedRepository(repo); - if (typeof file !== "string" || file.length === 0 || typeof bundlePath !== "string" || bundlePath.length === 0) { - throw new Error("attestation verification requires local subject and bundle paths"); - } - return [ - "attestation", - "verify", - file, - "--repo", - canonicalRepo, - "--bundle", - bundlePath, - "--format", - "json", - "--predicate-type", - SLSA_PROVENANCE_V1, - "--signer-workflow", - githubSignerWorkflow(canonicalRepo), - "--signer-digest", - head, - "--source-ref", - "refs/heads/main", - "--source-digest", - head, - "--deny-self-hosted-runners", - ]; -} - -function runGhBundleVerification({ - bundle, - bundlePath, - file, - head, - repo, -}) { - const args = ghBundleVerifyArgs({ - bundlePath, - file, - head, - repo, - }); - const result = captureCommandOutput("gh", args, { - cwd: ROOT, - label: `gh attestation verify for ${bundlePath}`, - maxOutputBytes: GH_ATTESTATION_VERIFY_MAX_OUTPUT_BYTES, - timeout: GH_ATTESTATION_VERIFY_TIMEOUT_MS, - }); - if (result.error !== undefined) { - throw new Error(`gh attestation verify failed to start or timed out for ${bundlePath}: ${result.error.message}`); - } - if (result.status !== 0) { - const detail = (result.stderr || result.stdout || "").trim(); - throw new Error(`gh attestation verify failed for ${bundlePath}${detail ? `: ${detail}` : ""}`); - } - const output = parseJsonBytes(Buffer.from(result.stdout), `gh verification output for ${bundlePath}`); - if (!Array.isArray(output) || output.length !== 1) { - throw new Error(`gh verification output for ${bundlePath} must contain exactly one verified attestation`); - } - const verified = requireObject(output[0], `gh verification output for ${bundlePath}`); - const verifiedBundle = verified.attestation?.bundle; - assertGhVerifiedBundleMatchesSupplied( - verifiedBundle, - bundle, - `gh verification output for ${bundlePath}`, - ); - const statement = verified.verificationResult?.statement; - requireObject(statement, `gh verification statement for ${bundlePath}`); - return statementSubjects(statement, `gh verified statement for ${bundlePath}`); -} - -export async function verifyAttestationBundles(lock, bundlePaths, { - repo = repository(), - verifyBundleImpl = runGhBundleVerification, - publisherSha = lock.source.commit, -} = {}) { - const canonicalRepo = normalizedRepository(repo); - if (!Array.isArray(bundlePaths)) { - throw new Error("attestation bundle paths must be an array"); - } - const assets = frozenGithubReleaseAssets(lock); - if (assets.length === 0 && bundlePaths.length > 0) { - throw new Error("attestation bundles contaminate a release selection with no frozen GitHub assets"); - } - const expectedByKey = new Map(assets.map((asset) => [githubAssetSubjectKey(asset), asset])); - const signerHead = publisherSha; - const records = []; - const suppliedPaths = new Set(); - const suppliedDigests = new Set(); - for (const bundlePath of bundlePaths) { - const absolute = path.resolve(bundlePath); - if (suppliedPaths.has(absolute)) { - throw new Error(`attestation bundle path was supplied more than once: ${bundlePath}`); - } - suppliedPaths.add(absolute); - const bytes = await readBoundedRegularFile(absolute, MAX_ATTESTATION_BUNDLE_BYTES, `attestation bundle ${bundlePath}`); - const bundleSha256 = sha256Bytes(bytes); - if (suppliedDigests.has(bundleSha256)) { - throw new Error(`attestation bundle ${bundleSha256} was supplied more than once`); - } - suppliedDigests.add(bundleSha256); - const bundle = parseJsonBytes(bytes, `attestation bundle ${bundlePath}`); - const untrustedSubjects = statementSubjects( - decodeBundleStatement(bundle, `attestation bundle ${bundlePath}`), - `unverified statement for ${bundlePath}`, - ); - const representatives = untrustedSubjects - .map((subject) => expectedByKey.get(githubAssetSubjectKey(subject))) - .filter((asset) => asset !== undefined) - .sort((left, right) => left.size - right.size || compareText(left.name, right.name)); - if (representatives.length === 0) { - throw new Error(`attestation bundle ${bundlePath} contains no frozen GitHub asset subject`); - } - const file = await lockedLocalSubject(representatives[0]); - const verifiedSubjects = await verifyBundleImpl({ - bundle, - bundlePath: absolute, - file, - head: signerHead, - repo: canonicalRepo, - }); - if (stableStringify(verifiedSubjects) !== stableStringify(untrustedSubjects)) { - throw new Error(`cryptographically verified subjects for ${bundlePath} differ from its DSSE statement`); - } - records.push({ bundleSha256, subjects: verifiedSubjects }); - } - return assertAttestationSubjectCoverage(assets, records); -} - -async function readReceipt(file) { - const absolute = path.resolve(file); - const bytes = await readBoundedRegularFile(absolute, MAX_ATTESTATION_RECEIPT_BYTES, `GitHub attestation receipt ${file}`); - return parseJsonBytes(bytes, `GitHub attestation receipt ${file}`); -} - -export async function writeImmutableReceipt(file, receipt, { - linkImpl = (source, target) => fs.link(source, target), -} = {}) { - const absolute = path.resolve(file); - const body = `${JSON.stringify(receipt, null, 2)}\n`; - if (Buffer.byteLength(body) > MAX_ATTESTATION_RECEIPT_BYTES) { - throw new Error(`GitHub attestation receipt ${file} exceeds ${MAX_ATTESTATION_RECEIPT_BYTES} bytes`); - } - await fs.mkdir(path.dirname(absolute), { recursive: true }); - const temporary = `${absolute}.tmp-${process.pid}-${randomUUID()}`; - let operationError; - try { - await fs.writeFile(temporary, body, { encoding: "utf8", flag: "wx", mode: 0o600 }); - try { - // Linking a fully-written temporary inode publishes the receipt in one - // filesystem operation. An interruption can leave a disposable temp, - // never a truncated immutable target that blocks a safe rerun. - await linkImpl(temporary, absolute); - } catch (error) { - if (error?.code !== "EEXIST") throw error; - const existing = await readBoundedRegularFile( - absolute, - MAX_ATTESTATION_RECEIPT_BYTES, - `GitHub attestation receipt ${file}`, - ); - if (existing.toString("utf8") !== body) { - throw new Error(`refusing to replace existing non-identical GitHub attestation receipt ${file}`); - } - } - } catch (error) { - operationError = error; - } - let cleanupError; - try { - await fs.unlink(temporary); - } catch (error) { - if (error?.code !== "ENOENT") cleanupError = error; - } - if (operationError !== undefined && cleanupError !== undefined) { - throw new AggregateError( - [operationError, cleanupError], - `GitHub attestation receipt ${file} failed and its temporary file could not be removed`, - ); - } - if (operationError !== undefined) throw operationError; - if (cleanupError !== undefined) throw cleanupError; - return absolute; -} - -function parseReceiptArgs(command, argv) { - const args = { - attestationBundles: [], - headRef: "HEAD", - output: undefined, - productsJson: undefined, - publicationLock: undefined, - receipt: undefined, - repo: repository(), - }; - const assign = (key, value, flag) => { - if (value === undefined || (value.length === 0 && flag !== "--attestation-bundle")) { - throw new Error(`${flag} requires a value`); - } - args[key] = value; - }; - for (let index = 0; index < argv.length; index += 1) { - const argument = argv[index]; - const separator = argument.indexOf("="); - const flag = separator === -1 ? argument : argument.slice(0, separator); - const value = separator === -1 ? argv[++index] : argument.slice(separator + 1); - if (flag === "--attestation-bundle") { - if (value === undefined) throw new Error("--attestation-bundle requires a value"); - if (value.length > 0) args.attestationBundles.push(value); - } else if (flag === "--head-ref") { - assign("headRef", value, flag); - } else if (flag === "--output") { - assign("output", value, flag); - } else if (flag === "--products-json") { - assign("productsJson", value, flag); - } else if (flag === "--publication-lock") { - assign("publicationLock", value, flag); - } else if (flag === "--receipt") { - assign("receipt", value, flag); - } else if (flag === "--repo") { - assign("repo", value, flag); - } else if (flag === "--help" || flag === "-h") { - return { help: true }; - } else { - throw new Error(`unknown ${command} argument ${argument}`); - } - } - if (!args.publicationLock) { - throw new Error(`${command} requires --publication-lock`); - } - if (command === "pre-mutation" && !args.output) { - throw new Error("pre-mutation requires --output"); - } - if (command === "finalize" && !args.receipt) { - throw new Error("finalize requires --receipt"); - } - if (command === "pre-mutation" && args.receipt !== undefined) { - throw new Error("pre-mutation does not accept --receipt"); - } - if (command === "finalize" && (args.output !== undefined || args.attestationBundles.length > 0)) { - throw new Error("finalize does not accept --output or --attestation-bundle"); - } - return args; -} - -function assertRequestedProducts(lock, productsJson) { - if (productsJson === undefined) return; - let products; - try { - products = JSON.parse(productsJson); - } catch (error) { - throw new Error(`--products-json must be valid JSON: ${error.message}`); - } - if (!Array.isArray(products) || products.some((product) => typeof product !== "string" || product.length === 0)) { - throw new Error("--products-json must be a JSON string array"); - } - exactProductSet( - lock.products.map((product) => product.id), - products, - "requested products and frozen publication lock products", - ); -} - -function receiptUsage() { - console.log("usage:"); - console.log(" tools/release/verify_github_release_attestations.mjs pre-mutation --publication-lock FILE --head-ref REF --output FILE [--products-json JSON] [--attestation-bundle FILE ...]"); - console.log(" tools/release/verify_github_release_attestations.mjs finalize --publication-lock FILE --head-ref REF --receipt FILE [--products-json JSON]"); -} - -async function receiptMain(command, argv) { - const args = parseReceiptArgs(command, argv); - if (args.help) { - receiptUsage(); - return; - } - const lock = loadPublicationLock(path.resolve(args.publicationLock)); - assertPublicationLockSource(lock, args.headRef); - assertRequestedProducts(lock, args.productsJson); - const repo = normalizedRepository(args.repo); - if (command === "pre-mutation") { - const publisherSha = process.env.GITHUB_SHA || lock.source.commit; - assertPublicationController({ source: lock.source.commit, controller: publisherSha }); - const releases = await queryLockedGithubReleases(lock, { repo }); - const attestations = await verifyAttestationBundles( - lock, - args.attestationBundles, - { repo, publisherSha }, - ); - const receipt = buildGithubAttestationReceipt({ - attestations, - lock, - releases, - repo, - publisherSha, - }); - const output = await writeImmutableReceipt(args.output, receipt); - console.log( - `GitHub release attestation receipt created at ${rel(output)} ` - + `(${receipt.releases.length} releases, ${frozenGithubReleaseAssets(lock).length} assets, ` - + `${receipt.attestations.length} signed bundles, ${receipt.receiptDigest})`, - ); - return; - } - const receipt = validateGithubAttestationReceipt(await readReceipt(args.receipt), lock, { repo }); - const releases = await queryLockedGithubReleases(lock, { repo }); - assertGithubReleaseSnapshotMatchesReceipt(receipt, releases); - console.log( - `GitHub release attestation receipt finalized (${receipt.releases.length} releases, ` - + `${frozenGithubReleaseAssets(lock).length} assets, ${receipt.receiptDigest})`, - ); -} - -function run(args, options = {}) { - console.log(`\n==> ${args.join(" ")}`); - const result = spawnSync(args[0], args.slice(1), { - cwd: ROOT, - stdio: "inherit", - ...options, - }); - if (result.error) { - fail(`${args[0]} failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - process.exit(result.status ?? 1); - } -} - -function parseLegacyArgs(argv) { - const args = { product: [], productsJson: undefined }; - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - if (value === "--product") { - const product = argv[++index]; - if (!product) { - fail("--product requires a value"); - } - args.product.push(product); - } else if (value.startsWith("--product=")) { - args.product.push(value.slice("--product=".length)); - } else if (value === "--products-json") { - args.productsJson = argv[++index]; - if (args.productsJson === undefined) { - fail("--products-json requires a value"); - } - } else if (value.startsWith("--products-json=")) { - args.productsJson = value.slice("--products-json=".length); - } else if (value === "--head-ref") { - index += 1; - } else if (value.startsWith("--head-ref=")) { - continue; - } else if (value === "--help" || value === "-h") { - console.log("usage: tools/release/verify_github_release_attestations.mjs [--product ID...] [--products-json JSON] [--head-ref REF]"); - receiptUsage(); - process.exit(0); - } else { - fail(`unknown argument ${value}`); - } - } - return args; -} - -async function parseProducts(value) { - const backed = await assetBackedProducts(); - if (!value) { - return [...backed].sort(compareText); - } - let parsed; - try { - parsed = JSON.parse(value); - } catch (error) { - fail(`--products-json must be valid JSON: ${error.message}`); - } - if (!Array.isArray(parsed) || !parsed.every((item) => typeof item === "string")) { - fail("--products-json must be a JSON string array"); - } - return parsed.filter((product) => backed.has(product)); -} - -function requireGh() { - const result = spawnSync("gh", ["--version"], { stdio: "ignore" }); - if (result.error || result.status !== 0) { - fail("gh CLI is required to verify GitHub release attestations"); - } -} - -async function verifyProduct(product, destination) { - const version = await currentVersion(product); - const tag = await productTag(product, version); - const repo = repository(); - const signerWorkflow = githubSignerWorkflow(repo); - const assets = await expectedAssets(product, version); - await verifyReleaseAssets(product, version, assets); - const productDir = path.join(destination, product); - await fs.mkdir(productDir, { recursive: true }); - for (const asset of assets) { - run(["gh", "release", "download", tag, "--repo", repo, "--pattern", asset, "--dir", productDir]); - run([ - "gh", - "attestation", - "verify", - path.join(productDir, asset), - "--repo", - repo, - "--signer-workflow", - signerWorkflow, - "--source-ref", - "refs/heads/main", - "--deny-self-hosted-runners", - ]); - } - console.log(`${product} GitHub release attestations verified for ${tag}`); -} - -export { assetBackedProducts, expectedAssets, productTag, verifyReleaseAssets }; - -async function legacyMain(argv) { - const args = parseLegacyArgs(argv); - requireGh(); - const products = args.product.length > 0 ? args.product : await parseProducts(args.productsJson); - const backed = await assetBackedProducts(); - const unknown = products.filter((product) => !backed.has(product)).sort(compareText); - if (unknown.length > 0) { - fail(`attestation verification is only defined for asset-backed products: ${unknown.join(", ")}`); - } - if (products.length === 0) { - console.log("no asset-backed products selected; GitHub attestation verification skipped"); - return; - } - const destination = await fs.mkdtemp(path.join(tmpdir(), "oliphaunt-release-attestations.")); - try { - for (const product of products) { - await verifyProduct(product, destination); - } - } finally { - await fs.rm(destination, { recursive: true, force: true }); - } -} - -async function main(argv) { - const command = argv[0]; - if (command === "pre-mutation" || command === "finalize") { - try { - await receiptMain(command, argv.slice(1)); - } catch (error) { - fail(error instanceof Error ? error.message : String(error)); - } - return; - } - await legacyMain(argv); -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/verify_github_release_attestations.mts b/tools/release/verify_github_release_attestations.mts new file mode 100755 index 000000000..bdec25802 --- /dev/null +++ b/tools/release/verify_github_release_attestations.mts @@ -0,0 +1,2589 @@ +#!/usr/bin/env bun + +// Verify GitHub artifact attestations for asset-backed product releases. + +import { createHash, randomUUID } from 'node:crypto'; +import { readFileSync } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { currentVersion } from './product-version.mts'; +import { + contribCarrierDescriptor, + expectedAssets as expectedDesktopAssets, + extensionArtifactProductRoot, + extensionMetadata, + extensionReleaseProduct, + extensionSourceIdentity, + extensionSqlNames, + releaseMetadata, +} from './release-artifact-targets.mts'; +import { reserveGitHubCoreRequest } from './github-core-request-journal.mts'; +import { + authHeaders, + boundedResponseBytes, + githubReleaseQueryDeadline, + requestBoundedGithubJson, + requestGithubJsonWithRetry, + responseContentLength, +} from './github-read.mts'; +import { assertPublicationLockSource, loadPublicationLock } from './publication-lock.mts'; + +export { requestBoundedGithubJson, requestGithubJsonWithRetry } from './github-read.mts'; + +import { swiftExtensionCarrierAssetName } from '../../src/sdks/swift/tools/ios-carrier-manifest.mts'; +import { assertWasixExtensionMemberInstall } from '../../src/extensions/contracts/wasix-extension-install.mts'; +import { assertPublicationController } from './publication-controller.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); +const PREFIX = 'verify_github_release_attestations.mts'; +const GITHUB_API = process.env.GITHUB_API ?? 'https://api.github.com'; +const MAX_CONTROL_ASSET_BYTES = 8 * 1024 * 1024; +const MAX_RELEASE_ASSET_BYTES = 2 * 1024 * 1024 * 1024; +const RELEASE_ASSET_TIMEOUT_MS = 10 * 60 * 1000; +const MAX_ATTESTATION_BUNDLE_BYTES = 32 * 1024 * 1024; +const MAX_ATTESTATION_RECEIPT_BYTES = 16 * 1024 * 1024; +const GITHUB_RELEASE_SNAPSHOT_MAX_ATTEMPTS = 10; +const GITHUB_RELEASE_SNAPSHOT_MAX_RETRY_DELAY_MS = 15_000; +const GITHUB_RELEASE_LIST_PAGE_SIZE = 100; +const GITHUB_RELEASE_LIST_MAX_PAGES = 1_000; +const GITHUB_RELEASE_FALLBACK_QUERY_CONCURRENCY = 1; +const GH_ATTESTATION_VERIFY_MAX_OUTPUT_BYTES = 64 * 1024 * 1024; +const GITHUB_ATTESTATION_RECEIPT_SCHEMA = 'oliphaunt-github-release-attestation-receipt-v1'; +const SLSA_PROVENANCE_V1 = 'https://slsa.dev/provenance/v1'; +const IN_TOTO_STATEMENT_V1 = 'https://in-toto.io/Statement/v1'; +const GITHUB_RELEASE_ARTIFACT_ROLES = new Set(['github-release-asset', 'github-release-metadata']); + +const BASE_ASSET_BACKED_PRODUCTS = new Set([ + 'liboliphaunt-native', + 'liboliphaunt-wasix', + 'liboliphaunt-wasix-postmaster', + 'oliphaunt-broker', + 'oliphaunt-node-direct', + 'oliphaunt-wasix-napi', +]); + +const PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS = new Set([ + 'schema', + 'product', + 'releaseProduct', + 'family', + 'version', + 'sqlName', + 'extensionClass', + 'versioning', + 'sourceIdentity', + 'compatibility', + 'createsExtension', + 'dependencies', + 'dataFiles', + 'extensionSqlFileNames', + 'extensionSqlFilePrefixes', + 'nativeModuleStem', + 'iosNativeDependencies', + 'iosRegistration', + 'wasixInstall', + 'sharedPreloadLibraries', + 'assets', +]); +const EXTENSION_OWNERSHIP_KEYS = ['releaseProduct', 'family']; +const PUBLIC_EXTENSION_RELEASE_LEGACY_KEYS = new Set( + [...PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS].filter( + (key) => !EXTENSION_OWNERSHIP_KEYS.includes(key), + ), +); + +const PUBLIC_EXTENSION_RELEASE_ASSET_KEYS = new Set([ + 'name', + 'family', + 'target', + 'kind', + 'identity', + 'sha256', + 'bytes', +]); +const PUBLIC_EXTENSION_BUNDLE_MANIFEST_KEYS = new Set([ + 'schema', + 'product', + 'releaseProduct', + 'family', + 'version', + 'extensionClass', + 'versioning', + 'sourceIdentity', + 'compatibility', + 'extensions', + 'assets', +]); +const PUBLIC_EXTENSION_BUNDLE_LEGACY_KEYS = new Set( + [...PUBLIC_EXTENSION_BUNDLE_MANIFEST_KEYS].filter( + (key) => !EXTENSION_OWNERSHIP_KEYS.includes(key), + ), +); +const PUBLIC_EXTENSION_BUNDLE_MEMBER_KEYS = new Set([ + 'sqlName', + 'createsExtension', + 'dependencies', + 'dataFiles', + 'extensionSqlFileNames', + 'extensionSqlFilePrefixes', + 'nativeModuleStem', + 'iosNativeDependencies', + 'iosRegistration', + 'wasixInstall', + 'sharedPreloadLibraries', + 'assets', +]); +const PUBLIC_EXTENSION_BUNDLE_ASSET_KEYS = new Set([ + 'name', + 'family', + 'target', + 'kind', + 'sha256', + 'bytes', + 'memberCount', +]); +const PUBLIC_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS = new Set([ + ...PUBLIC_EXTENSION_RELEASE_ASSET_KEYS, + 'carrierAsset', + 'carrierRoot', + 'memberPath', +]); + +function fail(message) { + console.error(`${PREFIX}: ${message}`); + process.exit(1); +} + +function rel(file) { + return path.relative(ROOT, file).split(path.sep).join('/'); +} + +async function readJson(file) { + try { + const value = JSON.parse(await fs.readFile(file, 'utf8')); + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(`${rel(file)} must contain a JSON object`); + } + return value; + } catch (error) { + fail(`failed to read ${rel(file)}: ${error.message}`); + } +} + +async function readToml(file) { + try { + const value = Bun.TOML.parse(await fs.readFile(file, 'utf8')); + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(`${rel(file)} must contain a TOML table`); + } + return value; + } catch (error) { + fail(`failed to read ${rel(file)}: ${error.message}`); + } +} + +let releaseConfigCache; +async function releaseConfig() { + releaseConfigCache ??= readJson(path.join(ROOT, 'release-please-config.json')); + return releaseConfigCache; +} + +let packagePathsCache; +async function packagePathsByProduct() { + if (packagePathsCache !== undefined) { + return packagePathsCache; + } + const config = await releaseConfig(); + const packages = config.packages; + if (packages === null || Array.isArray(packages) || typeof packages !== 'object') { + fail('release-please-config.json must define packages'); + } + const paths = new Map(); + for (const [packagePath, packageConfig] of Object.entries(packages)) { + const component = packageConfig?.component; + if (typeof component !== 'string' || component.length === 0) { + fail(`${packagePath}.component must be a non-empty string`); + } + if (paths.has(component)) { + fail(`duplicate release-please component ${component}`); + } + paths.set(component, packagePath); + } + packagePathsCache = paths; + return paths; +} + +async function packagePath(product) { + const paths = await packagePathsByProduct(); + const value = paths.get(product); + if (typeof value !== 'string' || value.length === 0) { + fail(`unknown release product ${JSON.stringify(product)}`); + } + return value; +} + +async function productConfig(product) { + const productPath = await packagePath(product); + const metadata = await readToml(path.join(ROOT, productPath, 'release.toml')); + if (metadata.id !== product) { + fail(`${productPath}/release.toml must declare id = ${JSON.stringify(product)}`); + } + return metadata; +} + +async function exactExtensionProducts() { + const paths = await packagePathsByProduct(); + const products = []; + for (const product of paths.keys()) { + const config = await productConfig(product); + if (['exact-extension-artifact', 'exact-extension-bundle'].includes(config.kind)) { + products.push(product); + } + } + return products.sort(compareText); +} + +async function assetBackedProducts() { + return new Set([...BASE_ASSET_BACKED_PRODUCTS, ...(await exactExtensionProducts())]); +} + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +async function tagPrefix(product) { + const config = await releaseConfig(); + if (config['include-v-in-tag'] !== true) { + fail('release-please must include v in product tags'); + } + if (config['tag-separator'] !== '-') { + fail("release-please tag-separator must be '-'"); + } + return `${product}-v`; +} + +async function productTag(product, version) { + return `${await tagPrefix(product)}${version}`; +} + +function repository() { + return process.env.GITHUB_REPOSITORY || 'f0rr0/oliphaunt'; +} + +function productTargets(product, preset) { + const release = releaseMetadata(product, PREFIX); + if (!release) { + fail(`Moon release metadata does not include ${product}`); + } + const artifactTargets = release.artifactTargets; + if ( + artifactTargets === null || + typeof artifactTargets !== 'object' || + artifactTargets.preset !== preset + ) { + fail(`Moon release metadata for ${product} must use artifactTargets preset ${preset}`); + } + const targets = artifactTargets.targets; + if (!Array.isArray(targets) || !targets.every((target) => typeof target === 'string' && target)) { + fail(`Moon release metadata for ${product} must declare artifactTargets.targets`); + } + return [...targets].sort(compareText); +} + +function archiveSuffix(target) { + return target === 'windows-x64-msvc' ? 'zip' : 'tar.gz'; +} + +function liboliphauntNativeAssets(version) { + const targets = productTargets('liboliphaunt-native', 'liboliphaunt-native'); + const assets = targets.map( + (target) => `liboliphaunt-${version}-${target}.${archiveSuffix(target)}`, + ); + assets.push( + `liboliphaunt-${version}-apple-spm-xcframework.zip`, + `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`, + `liboliphaunt-${version}-runtime-resources-android-datum64.tar.gz`, + `liboliphaunt-${version}-release-assets.sha256`, + ); + return [...new Set(assets)].sort(compareText); +} + +function liboliphauntWasixAssets(version) { + const targets = productTargets('liboliphaunt-wasix', 'liboliphaunt-wasix'); + if (!targets.includes('portable')) { + fail('Moon release metadata for liboliphaunt-wasix must include portable'); + } + const assets = [ + `liboliphaunt-wasix-${version}-runtime-portable.tar.zst`, + `liboliphaunt-wasix-${version}-release-assets.sha256`, + ]; + for (const target of targets.filter((target) => target !== 'portable')) { + assets.push(`liboliphaunt-wasix-${version}-runtime-aot-${target}.tar.zst`); + } + return assets.sort(compareText); +} + +async function productTagHasContrib(product, version) { + const tag = await productTag(product, version); + const snapshot = process.env.RELEASE_TAG_CONTRIB; + if (!snapshot) fail('release tag inspection requires with-release-tags.sh'); + const rows = readFileSync(snapshot, 'utf8').split('\0'); + if (rows.pop() !== '' || rows.length % 2 !== 0) fail('invalid release tag snapshot'); + const tags = new Map(); + for (let i = 0; i < rows.length; i += 2) { + if (tags.has(rows[i]) || !['true', 'false'].includes(rows[i + 1])) + fail('invalid release tag snapshot'); + tags.set(rows[i], rows[i + 1] === 'true'); + } + if (!tags.has(tag)) fail(`cannot inspect exact product tag tree ${tag}`); + return tags.get(tag); +} + +async function expectedExtensionAssets(product, version, family = 'combined') { + const rootFamily = family === 'combined' ? 'native' : family; + const releaseProduct = + family === 'combined' ? product : extensionReleaseProduct(product, family, PREFIX); + const releaseAssetRoot = path.join( + ROOT, + extensionArtifactProductRoot(product, rootFamily, 'target/extension-artifacts', PREFIX), + 'release-assets', + ); + const manifestPath = path.join(releaseAssetRoot, `${product}-${version}-manifest.json`); + const manifest = await readJson(manifestPath); + const extensionAssets = await validateExtensionManifest( + product, + version, + manifest, + manifestPath, + { + family, + releaseProduct, + }, + ); + const names = extensionAssets.map((asset) => asset.name); + names.push( + `${product}-${version}-manifest.json`, + `${product}-${version}-manifest.properties`, + `${product}-${version}-release-assets.sha256`, + ); + if (family !== 'wasix') names.push(swiftExtensionCarrierAssetName(product, version)); + return [...new Set(names)].sort(compareText); +} + +async function expectedAssets(product, version) { + const config = await productConfig(product); + if (['exact-extension-artifact', 'exact-extension-bundle'].includes(config.kind)) { + return expectedExtensionAssets(product, version); + } + if (product === 'liboliphaunt-native') { + const assets = liboliphauntNativeAssets(version); + if (await productTagHasContrib(product, version)) { + const contrib = contribCarrierDescriptor(PREFIX); + assets.push(...(await expectedExtensionAssets(contrib.artifactProduct, version, 'native'))); + } + return [...new Set(assets)].sort(compareText); + } + if (product === 'liboliphaunt-wasix') { + const assets = liboliphauntWasixAssets(version); + if (await productTagHasContrib(product, version)) { + const contrib = contribCarrierDescriptor(PREFIX); + assets.push(...(await expectedExtensionAssets(contrib.artifactProduct, version, 'wasix'))); + } + return [...new Set(assets)].sort(compareText); + } + if (product === 'liboliphaunt-wasix-postmaster') { + return [ + ...productTargets(product, 'liboliphaunt-wasix-postmaster').map( + (target) => `${product}-${version}-${target}.tar.zst`, + ), + `${product}-${version}-release-assets.sha256`, + ].sort(compareText); + } + if (product === 'oliphaunt-broker') { + return expectedDesktopAssets(product, 'broker-helper', version, PREFIX); + } + if (product === 'oliphaunt-node-direct') { + return expectedDesktopAssets(product, 'node-direct-addon', version, PREFIX); + } + if (product === 'oliphaunt-wasix-napi') { + return expectedDesktopAssets(product, 'wasix-napi-addon', version, PREFIX); + } + fail(`asset expectation is not defined for ${product}`); +} + +async function exactResponseProof(response, expectedSize, context) { + const declared = responseContentLength(response, context); + if (declared !== null && declared !== expectedSize) { + await response.body?.cancel?.().catch(() => {}); + throw new Error( + `${context} Content-Length ${declared} does not match expected size ${expectedSize}`, + ); + } + const hash = createHash('sha256'); + let size = 0; + const reader = response.body?.getReader?.(); + if (reader === undefined) { + const bytes = new Uint8Array(await response.arrayBuffer()); + size = bytes.byteLength; + if (size > expectedSize) throw new Error(`${context} exceeds expected size ${expectedSize}`); + hash.update(bytes); + } else { + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + size += value.byteLength; + if (size > expectedSize) { + await reader.cancel().catch(() => {}); + throw new Error(`${context} exceeds expected size ${expectedSize}`); + } + hash.update(value); + } + } finally { + reader.releaseLock(); + } + } + if (size !== expectedSize) { + throw new Error(`${context} size ${size} does not match expected size ${expectedSize}`); + } + return { bytes: size, sha256: hash.digest('hex') }; +} + +function releaseAssetApiUrl(rawUrl, name) { + let url; + try { + url = new URL(rawUrl); + } catch { + throw new Error(`GitHub release asset ${name} has an invalid API download URL`); + } + const api = new URL(GITHUB_API); + if (url.protocol !== 'https:' || url.origin !== api.origin) { + throw new Error(`GitHub release asset ${name} API download URL must use ${api.origin}`); + } + return url; +} + +function expectedAssetSize(value, name, maximum = MAX_RELEASE_ASSET_BYTES) { + if (!Number.isSafeInteger(value) || value < 0 || value > maximum) { + throw new Error(`GitHub release asset ${name} has invalid size ${JSON.stringify(value)}`); + } + return value; +} + +export async function requestReleaseControlBytes( + url, + name, + expectedSize, + { fetchImpl = fetch, timeoutMs = RELEASE_ASSET_TIMEOUT_MS } = {}, +) { + const size = expectedAssetSize(expectedSize, name, MAX_CONTROL_ASSET_BYTES); + await reserveGitHubCoreRequest({ label: `download GitHub release control asset ${name}` }); + const response = await fetchImpl(releaseAssetApiUrl(url, name), { + headers: authHeaders('application/octet-stream'), + redirect: 'follow', + signal: AbortSignal.timeout(timeoutMs), + }); + if (!response.ok) { + await response.body?.cancel?.().catch(() => {}); + throw new Error(`GitHub asset download returned HTTP ${response.status} for ${name}`); + } + const bytes = await boundedResponseBytes(response, size, `GitHub release asset ${name}`); + if (bytes.byteLength !== size) { + throw new Error( + `GitHub release asset ${name} size ${bytes.byteLength} does not match expected size ${size}`, + ); + } + return bytes; +} + +export async function requestReleaseAssetProof( + url, + name, + expectedSize, + { fetchImpl = fetch, timeoutMs = RELEASE_ASSET_TIMEOUT_MS } = {}, +) { + const size = expectedAssetSize(expectedSize, name); + await reserveGitHubCoreRequest({ label: `prove GitHub release asset ${name}` }); + const response = await fetchImpl(releaseAssetApiUrl(url, name), { + headers: authHeaders('application/octet-stream'), + redirect: 'follow', + signal: AbortSignal.timeout(timeoutMs), + }); + if (!response.ok) { + await response.body?.cancel?.().catch(() => {}); + throw new Error(`GitHub asset download returned HTTP ${response.status} for ${name}`); + } + return exactResponseProof(response, size, `GitHub release asset ${name}`); +} + +async function githubJson(url) { + try { + return await requestBoundedGithubJson(url); + } catch (error) { + fail(`failed to query GitHub release URL ${url}: ${error.message}`); + } +} + +async function releaseAssets(repo, tag) { + const repoPath = encodeURIComponent(repo).replaceAll('%2F', '/'); + const tagPath = encodeURIComponent(tag); + const url = `${GITHUB_API.replace(/\/$/u, '')}/repos/${repoPath}/releases/tags/${tagPath}`; + const data = await githubJson(url); + if (data === null || Array.isArray(data) || typeof data !== 'object') { + fail(`GitHub release response for ${tag} was not an object`); + } + if (!Array.isArray(data.assets)) { + fail(`GitHub release response for ${tag} did not include assets`); + } + const assets = new Map(); + for (const asset of data.assets) { + if (asset === null || typeof asset !== 'object' || typeof asset.name !== 'string') { + continue; + } + if (assets.has(asset.name)) { + fail(`GitHub release ${tag} declares duplicate asset ${asset.name}`); + } + assets.set(asset.name, asset); + } + return assets; +} + +async function requestBytes(url, name, expectedSize) { + if (typeof url !== 'string' || url.length === 0) { + fail(`GitHub release asset ${name} did not include an API download URL`); + } + try { + return await requestReleaseControlBytes(url, name, expectedSize); + } catch (error) { + fail(`failed to download GitHub asset ${name}: ${error.message}`); + } +} + +async function requestAssetProof(url, name, expectedSize) { + if (typeof url !== 'string' || url.length === 0) { + fail(`GitHub release asset ${name} did not include an API download URL`); + } + try { + return await requestReleaseAssetProof(url, name, expectedSize); + } catch (error) { + fail(`failed to verify GitHub asset ${name}: ${error.message}`); + } +} + +function sha256Bytes(data) { + return createHash('sha256').update(data).digest('hex'); +} + +function validateKeySet(object, expected, context) { + const actual = new Set(Object.keys(object)); + const missing = [...expected].filter((key) => !actual.has(key)); + const unexpected = [...actual].filter((key) => !expected.has(key)); + if (missing.length > 0 || unexpected.length > 0) { + fail( + `${context} keys must be ${JSON.stringify([...expected].sort())}, got ${JSON.stringify([...actual].sort())}`, + ); + } +} + +function validateSha256(value, context) { + if (typeof value !== 'string' || !/^[0-9a-f]{64}$/u.test(value)) { + fail(`${context} has invalid sha256 ${JSON.stringify(value)}`); + } +} + +function validateExtensionAssets(assets, context, seen) { + if (!Array.isArray(assets) || assets.length === 0) { + fail(`${context} must declare a non-empty assets array`); + } + for (const [index, asset] of assets.entries()) { + const assetContext = `${context} assets[${index}]`; + if (asset === null || Array.isArray(asset) || typeof asset !== 'object') { + fail(`${assetContext} must be an object`); + } + validateKeySet(asset, PUBLIC_EXTENSION_RELEASE_ASSET_KEYS, assetContext); + for (const key of ['name', 'family', 'target', 'kind', 'sha256']) { + if (typeof asset[key] !== 'string' || asset[key].length === 0) { + fail(`${assetContext}.${key} must be a non-empty string`); + } + } + if ( + !( + asset.identity === null || + (typeof asset.identity === 'string' && asset.identity.length > 0) + ) + ) { + fail(`${assetContext}.identity must be null or a non-empty string`); + } + if (asset.kind === 'ios-dependency-xcframework' && asset.identity === null) { + fail(`${assetContext} iOS dependency XCFramework must declare its identity`); + } + validateSha256(asset.sha256, `${assetContext}.${asset.name}`); + if (!Number.isInteger(asset.bytes) || asset.bytes <= 0) { + fail(`${assetContext}.${asset.name} must declare positive bytes`); + } + if (seen.has(asset.name)) { + fail(`${context} declares duplicate asset ${asset.name}`); + } + seen.add(asset.name); + } +} + +function validateBundleCarrierAssets(assets, context, expectedMemberCount) { + if (!Array.isArray(assets) || assets.length === 0) { + fail(`${context} must declare a non-empty aggregate assets array`); + } + const byName = new Map(); + const groups = new Set(); + for (const [index, asset] of assets.entries()) { + const assetContext = `${context} assets[${index}]`; + if (asset === null || Array.isArray(asset) || typeof asset !== 'object') + fail(`${assetContext} must be an object`); + validateKeySet(asset, PUBLIC_EXTENSION_BUNDLE_ASSET_KEYS, assetContext); + for (const key of ['name', 'family', 'target', 'kind', 'sha256']) { + if (typeof asset[key] !== 'string' || asset[key].length === 0) + fail(`${assetContext}.${key} must be a non-empty string`); + } + if (asset.kind !== 'extension-bundle') fail(`${assetContext}.kind must be extension-bundle`); + validateSha256(asset.sha256, `${assetContext}.${asset.name}`); + if (!Number.isSafeInteger(asset.bytes) || asset.bytes <= 0) + fail(`${assetContext}.${asset.name} must declare positive bytes`); + if (asset.memberCount !== expectedMemberCount) { + fail(`${assetContext}.${asset.name} must declare memberCount=${expectedMemberCount}`); + } + const group = `${asset.family}\0${asset.target}`; + if (byName.has(asset.name) || groups.has(group)) + fail(`${context} repeats an aggregate carrier name or family/target`); + byName.set(asset.name, asset); + groups.add(group); + } + return byName; +} + +function validateBundleMemberAssets(assets, context, carriers, seenLocators) { + if (!Array.isArray(assets) || assets.length === 0) + fail(`${context} must declare a non-empty assets array`); + for (const [index, asset] of assets.entries()) { + const assetContext = `${context} assets[${index}]`; + if (asset === null || Array.isArray(asset) || typeof asset !== 'object') + fail(`${assetContext} must be an object`); + validateKeySet(asset, PUBLIC_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS, assetContext); + for (const key of [ + 'name', + 'family', + 'target', + 'kind', + 'sha256', + 'carrierAsset', + 'carrierRoot', + 'memberPath', + ]) { + if (typeof asset[key] !== 'string' || asset[key].length === 0) + fail(`${assetContext}.${key} must be a non-empty string`); + } + if ( + !( + asset.identity === null || + (typeof asset.identity === 'string' && asset.identity.length > 0) + ) + ) { + fail(`${assetContext}.identity must be null or a non-empty string`); + } + validateSha256(asset.sha256, `${assetContext}.${asset.name}`); + if (!Number.isSafeInteger(asset.bytes) || asset.bytes <= 0) + fail(`${assetContext}.${asset.name} must declare positive bytes`); + const carrier = carriers.get(asset.carrierAsset); + if ( + carrier === undefined || + carrier.family !== asset.family || + carrier.target !== asset.target + ) { + fail(`${assetContext} references a missing or wrong-family aggregate carrier`); + } + const expectedRoot = asset.carrierAsset.replace(/\.tar\.gz$/u, ''); + if (asset.carrierRoot !== expectedRoot) + fail(`${assetContext}.carrierRoot does not match ${asset.carrierAsset}`); + if ( + asset.memberPath.includes('\\') || + asset.memberPath.startsWith('/') || + asset.memberPath.split('/').some((part) => !part || part === '.' || part === '..') + ) + fail(`${assetContext}.memberPath must be a safe POSIX path`); + const locator = `${asset.carrierAsset}\0${asset.memberPath}`; + if (seenLocators.has(locator)) + fail(`${context} repeats aggregate member locator ${asset.memberPath}`); + seenLocators.add(locator); + } +} + +let canonicalExtensionRowsCache; +let canonicalIosDependenciesCache; + +function canonicalExtensionRows() { + canonicalExtensionRowsCache ??= JSON.parse( + readFileSync(path.join(ROOT, 'src/extensions/generated/sdk/extensions.json'), 'utf8'), + ).extensions; + if (!Array.isArray(canonicalExtensionRowsCache)) { + throw new Error('generated React Native extension catalog has no extensions array'); + } + return canonicalExtensionRowsCache; +} + +function canonicalIosDependencies() { + if (canonicalIosDependenciesCache !== undefined) return canonicalIosDependenciesCache; + const lines = readFileSync( + path.join(ROOT, 'src/extensions/generated/mobile/static-extensions.tsv'), + 'utf8', + ) + .split(/\r?\n/u) + .filter((line) => line.length > 0 && !line.startsWith('#')); + const header = lines.shift()?.split('\t') ?? []; + canonicalIosDependenciesCache = new Map( + lines.map((line) => { + const fields = line.split('\t'); + const row = Object.fromEntries(header.map((key, index) => [key, fields[index] ?? ''])); + return [ + row['sql-name'], + (row['ios-static-dependencies'] ?? '').split(',').filter(Boolean).sort(compareText), + ]; + }), + ); + return canonicalIosDependenciesCache; +} + +function canonicalSortedUniqueStrings(value, context) { + if ( + !Array.isArray(value) || + value.some((item) => typeof item !== 'string' || item.length === 0) || + new Set(value).size !== value.length + ) { + throw new Error(`${context} must be a unique non-empty string list`); + } + return [...value].sort(compareText); +} + +function canonicalMemberSemantics(product, sqlName) { + if (!extensionSqlNames(product, PREFIX).includes(sqlName)) { + throw new Error(`${product} does not own extension SQL name ${JSON.stringify(sqlName)}`); + } + const row = canonicalExtensionRows().find((candidate) => candidate?.['sql-name'] === sqlName); + if (row === undefined || row['artifact-product'] !== product) { + throw new Error(`${product}/${sqlName} is absent from canonical generated extension metadata`); + } + const nativeModuleStem = + typeof row['native-module-stem'] === 'string' && row['native-module-stem'].length > 0 + ? row['native-module-stem'] + : null; + return { + sqlName, + createsExtension: row['creates-extension'] !== false, + dependencies: canonicalSortedUniqueStrings( + row['selected-extension-dependencies'], + `${product}/${sqlName}.selected-extension-dependencies`, + ), + dataFiles: canonicalSortedUniqueStrings( + row['runtime-share-data-files'], + `${product}/${sqlName}.runtime-share-data-files`, + ), + extensionSqlFileNames: canonicalSortedUniqueStrings( + row['extension-sql-file-names'], + `${product}/${sqlName}.extension-sql-file-names`, + ), + extensionSqlFilePrefixes: canonicalSortedUniqueStrings( + row['extension-sql-file-prefixes'], + `${product}/${sqlName}.extension-sql-file-prefixes`, + ), + nativeModuleStem, + iosNativeDependencies: + nativeModuleStem === null ? [] : (canonicalIosDependencies().get(sqlName) ?? []), + sharedPreloadLibraries: canonicalSortedUniqueStrings( + row['shared-preload-libraries'], + `${product}/${sqlName}.shared-preload-libraries`, + ), + }; +} + +function assertCanonicalIosRegistration(member, expected, context) { + if (expected.nativeModuleStem === null) { + if (member.iosRegistration !== null) + throw new Error(`${context} SQL-only extension fabricates iOS registration metadata`); + return; + } + const registration = member.iosRegistration; + if (registration === null || Array.isArray(registration) || typeof registration !== 'object') { + throw new Error(`${context} native extension lacks iOS registration metadata`); + } + const expectedKeys = [ + 'initSymbol', + 'magicSymbol', + 'nativeModuleStem', + 'schema', + 'sqlName', + 'symbols', + ].sort(compareText); + if ( + stableStringify(Object.keys(registration).sort(compareText)) !== stableStringify(expectedKeys) + ) { + throw new Error(`${context}.iosRegistration has a non-canonical key set`); + } + const prefix = `oliphaunt_static_${expected.nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`; + if ( + registration.schema !== 'oliphaunt-ios-extension-registration-v1' || + registration.sqlName !== expected.sqlName || + registration.nativeModuleStem !== expected.nativeModuleStem || + registration.magicSymbol !== `${prefix}_Pg_magic_func` || + ![null, `${prefix}__PG_init`].includes(registration.initSymbol) || + !Array.isArray(registration.symbols) + ) { + throw new Error( + `${context}.iosRegistration does not match its canonical native module identity`, + ); + } + const normalizedSymbols = registration.symbols.map((row, index) => { + if ( + row === null || + Array.isArray(row) || + typeof row !== 'object' || + stableStringify(Object.keys(row).sort(compareText)) !== + stableStringify(['address', 'name']) || + typeof row.name !== 'string' || + typeof row.address !== 'string' || + !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(row.name) || + !/^[A-Za-z_][A-Za-z0-9_]*$/u.test(row.address) + ) { + throw new Error( + `${context}.iosRegistration.symbols[${index}] is not a canonical C symbol mapping`, + ); + } + return `${row.name}\0${row.address}`; + }); + if ( + new Set(registration.symbols.map((row) => row.name)).size !== registration.symbols.length || + stableStringify(normalizedSymbols) !== stableStringify([...normalizedSymbols].sort(compareText)) + ) { + throw new Error(`${context}.iosRegistration.symbols must be sorted with unique public names`); + } +} + +function assertCanonicalMemberSemantics(product, member, context) { + const expected = canonicalMemberSemantics(product, member?.sqlName); + for (const key of Object.keys(expected)) { + if (stableStringify(member?.[key]) !== stableStringify(expected[key])) { + throw new Error(`${context}.${key} differs from canonical generated extension metadata`); + } + } + assertCanonicalIosRegistration(member, expected, context); +} + +function assertCanonicalWasixInstall(member, context) { + assertWasixExtensionMemberInstall(member, { label: context }); +} + +export function assertCanonicalExtensionReleaseIdentity( + product, + version, + manifest, + context = 'extension release manifest', + { + family = manifest?.family ?? 'combined', + releaseProduct = manifest?.releaseProduct ?? product, + } = {}, +) { + if (manifest === null || Array.isArray(manifest) || typeof manifest !== 'object') { + throw new Error(`${context} must be an object`); + } + const ownershipFieldCount = EXTENSION_OWNERSHIP_KEYS.filter( + (key) => manifest[key] !== undefined, + ).length; + const metadata = extensionMetadata(product, PREFIX); + if (ownershipFieldCount !== 0 && ownershipFieldCount !== EXTENSION_OWNERSHIP_KEYS.length) { + throw new Error(`${context} must declare releaseProduct and family together`); + } + if ( + metadata.versioning === 'runtime-bound' && + ownershipFieldCount !== EXTENSION_OWNERSHIP_KEYS.length + ) { + throw new Error(`${context} runtime-owned carrier must declare releaseProduct and family`); + } + if (!['native', 'wasix', 'combined'].includes(family)) { + throw new Error(`${context}.family must be native, wasix, or combined`); + } + const expectedReleaseProduct = + family === 'combined' ? product : extensionReleaseProduct(product, family, PREFIX); + if (releaseProduct !== expectedReleaseProduct) { + throw new Error(`${context}.releaseProduct differs from canonical ${family} ownership`); + } + const expectedRoot = { + product, + ...(ownershipFieldCount === EXTENSION_OWNERSHIP_KEYS.length + ? { + releaseProduct: expectedReleaseProduct, + family, + } + : {}), + version, + extensionClass: metadata.class, + versioning: metadata.versioning, + sourceIdentity: extensionSourceIdentity(product, PREFIX), + compatibility: metadata.compatibility, + }; + for (const [key, expected] of Object.entries(expectedRoot)) { + if (stableStringify(manifest[key]) !== stableStringify(expected)) { + throw new Error(`${context}.${key} differs from canonical release identity`); + } + } + const expectedSqlNames = extensionSqlNames(product, PREFIX); + if (manifest.schema === 'oliphaunt-extension-release-manifest-v1') { + if (expectedSqlNames.length !== 1 || manifest.sqlName !== expectedSqlNames[0]) { + throw new Error(`${context}.sqlName differs from its canonical release owner`); + } + assertCanonicalMemberSemantics(product, manifest, context); + return manifest; + } + if (manifest.schema === 'oliphaunt-extension-release-manifest-v2') { + const actualSqlNames = Array.isArray(manifest.extensions) + ? manifest.extensions.map((member) => member?.sqlName) + : []; + if (stableStringify(actualSqlNames) !== stableStringify(expectedSqlNames)) { + throw new Error(`${context}.extensions differs from its canonical sorted member set`); + } + manifest.extensions.forEach((member, index) => { + assertCanonicalMemberSemantics(product, member, `${context}.extensions[${index}]`); + }); + return manifest; + } + throw new Error( + `${context} has unsupported extension release manifest schema ${JSON.stringify(manifest.schema)}`, + ); +} + +async function validateExtensionManifest( + product, + version, + manifest, + context, + { family = manifest?.family, releaseProduct = manifest?.releaseProduct } = {}, +) { + try { + assertCanonicalExtensionReleaseIdentity(product, version, manifest, context, { + family, + releaseProduct, + }); + } catch (error) { + fail(error.message); + } + const seen = new Set(); + if (manifest.schema === 'oliphaunt-extension-release-manifest-v1') { + validateKeySet( + manifest, + manifest.releaseProduct === undefined + ? PUBLIC_EXTENSION_RELEASE_LEGACY_KEYS + : PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS, + context, + ); + validateExtensionAssets(manifest.assets, context, seen); + try { + assertCanonicalWasixInstall(manifest, context); + } catch (error) { + fail(error.message); + } + return manifest.assets; + } + if (manifest.schema !== 'oliphaunt-extension-release-manifest-v2') { + fail( + `${context} has unsupported extension release manifest schema ${JSON.stringify(manifest.schema)}`, + ); + } + validateKeySet( + manifest, + manifest.releaseProduct === undefined + ? PUBLIC_EXTENSION_BUNDLE_LEGACY_KEYS + : PUBLIC_EXTENSION_BUNDLE_MANIFEST_KEYS, + context, + ); + if (!Array.isArray(manifest.extensions) || manifest.extensions.length < 2) { + fail(`${context}.extensions must be a non-empty bundle member array`); + } + const expectedSqlNames = extensionSqlNames(product, PREFIX); + const actualSqlNames = manifest.extensions.map((member) => member?.sqlName); + if (stableStringify(actualSqlNames) !== stableStringify(expectedSqlNames)) { + fail(`${context}.extensions must exactly match the sorted release bundle member set`); + } + const carriers = validateBundleCarrierAssets(manifest.assets, context, expectedSqlNames.length); + const seenLocators = new Set(); + for (const [index, member] of manifest.extensions.entries()) { + const memberContext = `${context}.extensions[${index}]`; + if (member === null || Array.isArray(member) || typeof member !== 'object') { + fail(`${memberContext} must be an object`); + } + validateKeySet(member, PUBLIC_EXTENSION_BUNDLE_MEMBER_KEYS, memberContext); + validateBundleMemberAssets(member.assets, memberContext, carriers, seenLocators); + try { + assertCanonicalWasixInstall(member, memberContext); + } catch (error) { + fail(error.message); + } + for (const asset of member.assets) { + const expectedMemberPath = `extensions/${member.sqlName}/${asset.name}`; + if (asset.memberPath !== expectedMemberPath) { + fail(`${memberContext} asset ${asset.name} must use memberPath ${expectedMemberPath}`); + } + } + } + return manifest.assets; +} + +function parseChecksumManifest(data, context) { + const checksums = new Map(); + const text = new TextDecoder().decode(data); + for (const [index, rawLine] of text.split(/\r?\n/u).entries()) { + const line = rawLine.trim(); + if (!line) { + continue; + } + const parts = line.split(/\s+/u); + if (parts.length !== 2) { + fail(`${context}:${index + 1} must contain ' ./'`); + } + const [sha, name] = parts; + validateSha256(sha, `${context}:${index + 1}`); + if (!name.startsWith('./') || name.slice(2).includes('/')) { + fail(`${context}:${index + 1} must reference a direct asset path like ./name`); + } + const assetName = name.slice(2); + if (checksums.has(assetName)) { + fail(`${context} declares duplicate checksum entry for ${assetName}`); + } + checksums.set(assetName, sha); + } + return checksums; +} + +function stableStringify(value) { + if (Array.isArray(value)) { + return `[${value.map(stableStringify).join(',')}]`; + } + if (value !== null && typeof value === 'object') { + return `{${Object.keys(value) + .sort(compareText) + .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +function canonicalSigstoreBundleForGhComparison(bundle) { + const canonical = structuredClone(bundle); + // The signing action emits an empty protobuf key ID; gh omits that default. + // Nonempty key IDs and every signature byte must still compare exactly. + if (Array.isArray(canonical?.dsseEnvelope?.signatures)) { + for (const signature of canonical.dsseEnvelope.signatures) { + if (signature?.keyid === '') delete signature.keyid; + } + } + const timestampVerificationData = canonical?.verificationMaterial?.timestampVerificationData; + if ( + timestampVerificationData !== null && + !Array.isArray(timestampVerificationData) && + typeof timestampVerificationData === 'object' && + Array.isArray(timestampVerificationData.rfc3161Timestamps) && + timestampVerificationData.rfc3161Timestamps.length === 0 + ) { + // actions/attest v3 serializes this protobuf default as an empty repeated + // field, while gh's Go protobuf serializer omits it after successfully + // verifying the exact supplied bundle. Canonicalize only that known + // representation difference; every signed and verification-material byte + // represented by the bundle must still compare exactly. + delete timestampVerificationData.rfc3161Timestamps; + } + return canonical; +} + +export function assertGhVerifiedBundleMatchesSupplied( + verifiedBundle, + suppliedBundle, + context = 'gh verification output', +) { + if ( + stableStringify(canonicalSigstoreBundleForGhComparison(verifiedBundle)) !== + stableStringify(canonicalSigstoreBundleForGhComparison(suppliedBundle)) + ) { + throw new Error(`${context} does not contain the supplied bundle`); + } +} + +export function assertExactReleaseAssetNames({ product, tag, expectedNames, actualNames }) { + const expected = new Set(expectedNames); + const actual = new Set(actualNames); + const missing = [...expected].filter((name) => !actual.has(name)).sort(compareText); + const unexpected = [...actual].filter((name) => !expected.has(name)).sort(compareText); + if (missing.length > 0 || unexpected.length > 0) { + const details = [ + ...(missing.length > 0 ? [`missing: ${missing.join(', ')}`] : []), + ...(unexpected.length > 0 ? [`unexpected: ${unexpected.join(', ')}`] : []), + ]; + throw new Error(`${product} GitHub release ${tag} asset set mismatch (${details.join('; ')})`); + } +} + +function requireObject(value, context) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw new Error(`${context} must be an object`); + } + return value; +} + +function assertKeySet(value, keys, context) { + requireObject(value, context); + const actual = Object.keys(value).sort(compareText); + const expected = [...keys].sort(compareText); + if (stableStringify(actual) !== stableStringify(expected)) { + throw new Error( + `${context} keys must be ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`, + ); + } +} + +function requireSha256(value, context) { + if (typeof value !== 'string' || !/^[0-9a-f]{64}$/u.test(value)) { + throw new Error(`${context} must be a lowercase SHA-256 digest`); + } + return value; +} + +function normalizeGithubId(value, context) { + if (Number.isSafeInteger(value) && value > 0) { + return String(value); + } + if (typeof value === 'string' && /^[1-9][0-9]*$/u.test(value)) { + return value; + } + throw new Error(`${context} must be a positive integer ID`); +} + +function normalizedRepository(value) { + if (typeof value !== 'string' || !/^[^/\s\0]+\/[^/\s\0]+$/u.test(value) || value.includes('..')) { + throw new Error(`GitHub repository must be an owner/name pair, got ${JSON.stringify(value)}`); + } + return value; +} + +function frozenProductTag(product) { + if ( + product === null || + Array.isArray(product) || + typeof product !== 'object' || + typeof product.id !== 'string' || + product.id.length === 0 || + typeof product.version !== 'string' || + product.version.length === 0 + ) { + throw new Error('publication lock contains an invalid product row'); + } + return `${product.id}-v${product.version}`; +} + +export function frozenGithubReleaseAssets(lock) { + if (!Array.isArray(lock?.products) || !Array.isArray(lock?.productArtifacts)) { + throw new Error('publication lock must contain products and productArtifacts arrays'); + } + const products = new Set(); + for (const product of lock.products) { + frozenProductTag(product); + if (products.has(product.id)) { + throw new Error(`publication lock contains duplicate product ${product.id}`); + } + products.add(product.id); + } + const identities = new Set(); + const assets = []; + for (const artifact of lock.productArtifacts) { + if (!GITHUB_RELEASE_ARTIFACT_ROLES.has(artifact?.role)) continue; + if (!products.has(artifact.product)) { + throw new Error( + `frozen GitHub asset ${artifact?.name ?? ''} belongs to unselected product ${artifact?.product ?? ''}`, + ); + } + if ( + typeof artifact.name !== 'string' || + artifact.name.length === 0 || + artifact.name.includes('/') || + artifact.name.includes('\\') || + /[\0\r\n]/u.test(artifact.name) + ) { + throw new Error(`${artifact.product} contains an invalid frozen GitHub asset name`); + } + requireSha256(artifact.sha256, `${artifact.product}/${artifact.name} frozen sha256`); + if (!Number.isSafeInteger(artifact.size) || artifact.size < 0) { + throw new Error( + `${artifact.product}/${artifact.name} frozen size must be a non-negative safe integer`, + ); + } + if (typeof artifact.path !== 'string' || artifact.path.length === 0) { + throw new Error(`${artifact.product}/${artifact.name} frozen path must be non-empty`); + } + const identity = `${artifact.product}\0${artifact.name}`; + if (identities.has(identity)) { + throw new Error( + `publication lock contains duplicate GitHub asset ${artifact.product}/${artifact.name}`, + ); + } + identities.add(identity); + assets.push({ + name: artifact.name, + path: artifact.path, + product: artifact.product, + sha256: artifact.sha256, + size: artifact.size, + }); + } + return assets.sort( + (left, right) => compareText(left.product, right.product) || compareText(left.name, right.name), + ); +} + +function expectedAssetsByProduct(lock) { + const grouped = new Map(lock.products.map((product) => [product.id, []])); + for (const asset of frozenGithubReleaseAssets(lock)) { + grouped.get(asset.product).push(asset); + } + return grouped; +} + +async function mapConcurrent(values, concurrency, worker) { + if (!Number.isSafeInteger(concurrency) || concurrency <= 0) { + throw new Error('concurrency must be a positive safe integer'); + } + const output = new Array(values.length); + let next = 0; + let failure; + const runWorker = async () => { + for (;;) { + if (failure !== undefined) return; + const index = next; + next += 1; + if (index >= values.length) return; + try { + output[index] = await worker(values[index], index); + } catch (error) { + failure ??= error; + return; + } + } + }; + await Promise.all( + Array.from({ length: Math.min(values.length, concurrency) }, () => runWorker()), + ); + if (failure !== undefined) throw failure; + return output; +} + +function repositoryApiBase(repo) { + const repoPath = encodeURIComponent(repo).replaceAll('%2F', '/'); + return `${GITHUB_API.replace(/\/$/u, '')}/repos/${repoPath}`; +} + +function releasesListApiUrl(repo, page) { + return `${repositoryApiBase(repo)}/releases?per_page=${GITHUB_RELEASE_LIST_PAGE_SIZE}&page=${page}`; +} + +function releaseAssetsListApiUrl(repo, releaseId, page) { + return `${repositoryApiBase(repo)}/releases/${releaseId}/assets?per_page=${GITHUB_RELEASE_LIST_PAGE_SIZE}&page=${page}`; +} + +function requiredGithubAuthToken(value = process.env.GH_TOKEN || process.env.GITHUB_TOKEN) { + if ( + typeof value !== 'string' || + value.length === 0 || + value.trim() !== value || + /[\0\r\n]/u.test(value) + ) { + throw new Error('authenticated GitHub release snapshots require GH_TOKEN or GITHUB_TOKEN'); + } + return value; +} + +async function requestGithubArrayPages({ + authToken, + context, + deadlineMs, + fetchImpl, + nowImpl, + sleepImpl, + urlForPage, +}) { + const rows = []; + for (let page = 1; page <= GITHUB_RELEASE_LIST_MAX_PAGES; page += 1) { + const url = urlForPage(page); + const { data, link } = await requestGithubJsonWithRetry(url, { + authToken, + deadlineMs, + fetchImpl, + nowImpl, + responseMetadata: true, + sleepImpl, + }); + if (!Array.isArray(data)) { + throw new Error(`${context} page ${page} must be an array`); + } + if (data.length > GITHUB_RELEASE_LIST_PAGE_SIZE) { + throw new Error(`${context} page ${page} exceeds ${GITHUB_RELEASE_LIST_PAGE_SIZE} rows`); + } + rows.push(...data); + const hasNext = /(?:^|,)\s*<[^>]+>\s*;\s*rel="next"(?:\s*;[^,]*)?(?:,|$)/iu.test(link); + if (!hasNext) return rows; + if (data.length !== GITHUB_RELEASE_LIST_PAGE_SIZE) { + throw new Error(`${context} advertises another page after only ${data.length} rows`); + } + } + throw new Error(`${context} exceeds ${GITHUB_RELEASE_LIST_MAX_PAGES} pages`); +} + +function normalizeRemoteAsset(asset, expected, product, tag) { + requireObject(asset, `${product} GitHub release ${tag} asset ${expected.name}`); + if (asset.name !== expected.name) { + throw new Error( + `${product} GitHub release ${tag} asset name changed while it was being validated`, + ); + } + if (asset.state !== 'uploaded') { + throw new GithubReleaseSnapshotNotReadyError( + `${product} GitHub release ${tag} asset ${expected.name} is not fully uploaded`, + ); + } + if (!Number.isSafeInteger(asset.size) || asset.size < 0 || asset.size !== expected.size) { + throw new Error( + `${product} GitHub release ${tag} asset ${expected.name} size ${JSON.stringify(asset.size)} does not match frozen size ${expected.size}`, + ); + } + const expectedDigest = `sha256:${expected.sha256}`; + if (asset.digest !== expectedDigest) { + if (asset.digest === null || asset.digest === undefined || asset.digest === '') { + throw new GithubReleaseSnapshotNotReadyError( + `${product} GitHub release ${tag} asset ${expected.name} is missing GitHub digest metadata`, + ); + } + throw new Error( + `${product} GitHub release ${tag} asset ${expected.name} digest ${JSON.stringify(asset.digest)} does not match ${expectedDigest}`, + ); + } + return { + assetId: normalizeGithubId( + asset.id, + `${product} GitHub release ${tag} asset ${expected.name} id`, + ), + name: expected.name, + sha256: expected.sha256, + size: expected.size, + }; +} + +class GithubReleaseSnapshotNotReadyError extends Error { + constructor(message) { + super(message); + this.name = 'GithubReleaseSnapshotNotReadyError'; + } +} + +function exactProductSet(expected, actual, context) { + const expectedSet = new Set(expected); + const actualSet = new Set(actual); + const missing = [...expectedSet].filter((value) => !actualSet.has(value)).sort(compareText); + const extra = [...actualSet].filter((value) => !expectedSet.has(value)).sort(compareText); + if (missing.length > 0 || extra.length > 0 || actual.length !== actualSet.size) { + throw new Error( + `${context} mismatch: missing=${JSON.stringify(missing)}, extra=${JSON.stringify(extra)}, duplicate=${actual.length !== actualSet.size}`, + ); + } +} + +export function normalizeGithubReleaseSnapshot(lock, releases) { + if (!Array.isArray(releases)) { + throw new Error('GitHub release snapshot must be an array'); + } + const products = [...lock.products].sort((left, right) => compareText(left.id, right.id)); + exactProductSet( + products.map((product) => product.id), + releases.map((release) => release?.product), + 'GitHub release snapshot product set', + ); + const expectedByProduct = expectedAssetsByProduct(lock); + const releaseIds = new Set(); + const assetIds = new Set(); + const normalized = []; + for (const product of products) { + const release = releases.find((candidate) => candidate?.product === product.id); + const context = `${product.id} GitHub release snapshot`; + assertKeySet( + release, + [ + 'assets', + 'draft', + 'prerelease', + 'product', + 'releaseId', + 'releaseName', + 'tag', + 'targetCommitish', + 'version', + ], + context, + ); + const tag = frozenProductTag(product); + if ( + release.version !== product.version || + release.tag !== tag || + release.releaseName !== `${product.id} v${product.version}` || + release.targetCommitish !== lock.source.commit || + release.prerelease !== product.version.includes('-') || + typeof release.draft !== 'boolean' + ) { + throw new Error(`${context} metadata does not match the frozen publication lock`); + } + const releaseId = normalizeGithubId(release.releaseId, `${context} id`); + if (releaseIds.has(releaseId)) { + throw new Error(`GitHub release snapshot reuses release id ${releaseId}`); + } + releaseIds.add(releaseId); + if (!Array.isArray(release.assets)) { + throw new Error(`${context}.assets must be an array`); + } + const expectedAssets = expectedByProduct.get(product.id); + assertExactReleaseAssetNames({ + product: product.id, + tag, + expectedNames: expectedAssets.map((asset) => asset.name), + actualNames: release.assets.map((asset) => asset?.name), + }); + if (new Set(release.assets.map((asset) => asset?.name)).size !== release.assets.length) { + throw new Error(`${context} contains duplicate asset names`); + } + const assets = []; + for (const expected of expectedAssets) { + const asset = release.assets.find((candidate) => candidate?.name === expected.name); + assertKeySet( + asset, + ['assetId', 'name', 'sha256', 'size'], + `${context} asset ${expected.name}`, + ); + if (asset.sha256 !== expected.sha256 || asset.size !== expected.size) { + throw new Error( + `${context} asset ${expected.name} differs from the frozen publication lock`, + ); + } + const assetId = normalizeGithubId(asset.assetId, `${context} asset ${expected.name} id`); + if (assetIds.has(assetId)) { + throw new Error(`GitHub release snapshot reuses asset id ${assetId}`); + } + assetIds.add(assetId); + assets.push({ + assetId, + name: expected.name, + sha256: expected.sha256, + size: expected.size, + }); + } + normalized.push({ + assets, + draft: release.draft, + prerelease: release.prerelease, + product: product.id, + releaseId, + releaseName: release.releaseName, + tag, + targetCommitish: lock.source.commit, + version: product.version, + }); + } + return normalized; +} + +async function queryLockedGithubReleasesOnce( + lock, + { + authToken, + deadlineMs, + fetchImpl = fetch, + nowImpl = Date.now, + repo = repository(), + sleepImpl, + } = {}, +) { + const canonicalRepo = normalizedRepository(repo); + const token = requiredGithubAuthToken(authToken); + const effectiveDeadline = deadlineMs ?? githubReleaseQueryDeadline(nowImpl()); + const expectedByProduct = expectedAssetsByProduct(lock); + const products = [...lock.products].sort((left, right) => compareText(left.id, right.id)); + const selectedTags = new Set(products.map(frozenProductTag)); + const listedReleases = await requestGithubArrayPages({ + authToken: token, + context: `${canonicalRepo} GitHub release list`, + deadlineMs: effectiveDeadline, + fetchImpl, + nowImpl, + sleepImpl, + urlForPage: (page) => releasesListApiUrl(canonicalRepo, page), + }); + const releasesByTag = new Map(); + const releaseIds = new Set(); + for (const [index, release] of listedReleases.entries()) { + const context = `${canonicalRepo} GitHub release list row ${index}`; + requireObject(release, context); + if (typeof release.tag_name !== 'string' || release.tag_name.length === 0) { + throw new Error(`${context}.tag_name must be a non-empty string`); + } + const releaseId = normalizeGithubId(release.id, `${context}.id`); + if (releaseIds.has(releaseId)) { + throw new Error(`${canonicalRepo} GitHub release list reuses release id ${releaseId}`); + } + releaseIds.add(releaseId); + if (!selectedTags.has(release.tag_name)) continue; + if (releasesByTag.has(release.tag_name)) { + throw new Error( + `${canonicalRepo} returned duplicate releases for selected tag ${release.tag_name}`, + ); + } + releasesByTag.set(release.tag_name, release); + } + const missingTags = [...selectedTags].filter((tag) => !releasesByTag.has(tag)).sort(compareText); + if (missingTags.length > 0) { + throw new GithubReleaseSnapshotNotReadyError( + `${canonicalRepo} GitHub release list is not yet exposing selected release(s): ${missingTags.join(', ')}`, + ); + } + + // Reject immutable release identity/metadata conflicts before fanning out + // to the per-release asset endpoints. The embedded assets field is neither + // authoritative nor required; every product is inventoried separately. + for (const product of products) { + const tag = frozenProductTag(product); + const data = releasesByTag.get(tag); + requireObject(data, `${product.id} GitHub release ${tag}`); + if ( + data.tag_name !== tag || + data.name !== `${product.id} v${product.version}` || + data.target_commitish !== lock.source.commit || + data.prerelease !== product.version.includes('-') || + typeof data.draft !== 'boolean' + ) { + throw new Error( + `${product.id} GitHub release ${tag} metadata does not match the frozen publication lock`, + ); + } + } + + const exactAssetRows = new Map( + await mapConcurrent(products, GITHUB_RELEASE_FALLBACK_QUERY_CONCURRENCY, async (product) => { + const tag = frozenProductTag(product); + const release = releasesByTag.get(tag); + const releaseId = normalizeGithubId(release.id, `${product.id} GitHub release ${tag} id`); + const assets = await requestGithubArrayPages({ + authToken: token, + context: `${product.id} GitHub release ${tag} asset list`, + deadlineMs: effectiveDeadline, + fetchImpl, + nowImpl, + sleepImpl, + urlForPage: (page) => releaseAssetsListApiUrl(canonicalRepo, releaseId, page), + }); + return [product.id, assets]; + }), + ); + + const releases = products.map((product) => { + const tag = frozenProductTag(product); + const data = releasesByTag.get(tag); + requireObject(data, `${product.id} GitHub release ${tag}`); + const expectedAssets = expectedByProduct.get(product.id); + const remoteAssets = exactAssetRows.get(product.id); + const names = remoteAssets.map((asset) => { + if ( + asset === null || + Array.isArray(asset) || + typeof asset !== 'object' || + typeof asset.name !== 'string' + ) { + throw new Error(`${product.id} GitHub release ${tag} contains an invalid asset row`); + } + return asset.name; + }); + const expectedNames = expectedAssets.map((asset) => asset.name); + const actualNameSet = new Set(names); + const expectedNameSet = new Set(expectedNames); + const missing = expectedNames.filter((name) => !actualNameSet.has(name)); + const unexpected = names.filter((name) => !expectedNameSet.has(name)); + if (unexpected.length > 0) { + assertExactReleaseAssetNames({ + product: product.id, + tag, + expectedNames, + actualNames: names, + }); + } + if (missing.length > 0) { + throw new GithubReleaseSnapshotNotReadyError( + `${product.id} GitHub release ${tag} is not yet exposing frozen asset(s): ${missing.sort(compareText).join(', ')}`, + ); + } + if (new Set(names).size !== names.length) { + throw new Error(`${product.id} GitHub release ${tag} contains duplicate asset names`); + } + const byName = new Map(remoteAssets.map((asset) => [asset.name, asset])); + return { + assets: expectedAssets.map((expected) => + normalizeRemoteAsset(byName.get(expected.name), expected, product.id, tag), + ), + draft: data.draft, + prerelease: data.prerelease, + product: product.id, + releaseId: normalizeGithubId(data.id, `${product.id} GitHub release ${tag} id`), + releaseName: data.name, + tag, + targetCommitish: data.target_commitish, + version: product.version, + }; + }); + return normalizeGithubReleaseSnapshot(lock, releases); +} + +export async function queryLockedGithubReleases(lock, options = {}) { + const nowImpl = options.nowImpl ?? Date.now; + const sleepImpl = + options.sleepImpl ?? + ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds))); + const deadlineMs = options.deadlineMs ?? githubReleaseQueryDeadline(nowImpl()); + const maxAttempts = options.snapshotMaxAttempts ?? GITHUB_RELEASE_SNAPSHOT_MAX_ATTEMPTS; + if (!Number.isSafeInteger(maxAttempts) || maxAttempts <= 0) { + throw new Error('GitHub release snapshot maxAttempts must be a positive safe integer'); + } + let lastError; + for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { + try { + return await queryLockedGithubReleasesOnce(lock, { + ...options, + deadlineMs, + nowImpl, + sleepImpl, + }); + } catch (error) { + if (!(error instanceof GithubReleaseSnapshotNotReadyError)) { + throw error; + } + lastError = error; + if (attempt === maxAttempts) { + throw new Error( + `GitHub release snapshot readiness retries exhausted after ${maxAttempts} attempts: ${error.message}`, + { cause: error }, + ); + } + } + const delay = Math.min(GITHUB_RELEASE_SNAPSHOT_MAX_RETRY_DELAY_MS, 1_000 * 2 ** (attempt - 1)); + const now = nowImpl(); + if (now + delay >= deadlineMs) { + throw new Error( + `GitHub release snapshot retry would exceed its deadline: ${lastError.message}`, + ); + } + await sleepImpl(delay); + } + throw lastError; +} + +function normalizeAttestationSubjects(subjects, context) { + if (!Array.isArray(subjects) || subjects.length === 0) { + throw new Error(`${context} must contain a non-empty subject array`); + } + const keys = new Set(); + const normalized = []; + for (const [index, subject] of subjects.entries()) { + const subjectContext = `${context} subject[${index}]`; + assertKeySet(subject, ['digest', 'name'], subjectContext); + if ( + typeof subject.name !== 'string' || + subject.name.length === 0 || + subject.name.includes('/') || + subject.name.includes('\\') || + /[\0\r\n]/u.test(subject.name) + ) { + throw new Error(`${subjectContext}.name must be a direct asset basename`); + } + assertKeySet(subject.digest, ['sha256'], `${subjectContext}.digest`); + const sha256 = requireSha256(subject.digest.sha256, `${subjectContext}.digest.sha256`); + const key = `${subject.name}\0${sha256}`; + if (keys.has(key)) { + throw new Error(`${context} contains duplicate subject ${subject.name}/${sha256}`); + } + keys.add(key); + normalized.push({ name: subject.name, sha256 }); + } + return normalized.sort( + (left, right) => compareText(left.name, right.name) || compareText(left.sha256, right.sha256), + ); +} + +function normalizedReceiptSubjects(subjects, context) { + if (!Array.isArray(subjects)) { + throw new Error(`${context} subjects must be an array`); + } + return normalizeAttestationSubjects( + subjects.map((subject) => ({ + digest: { sha256: subject?.sha256 }, + name: subject?.name, + })), + context, + ); +} + +function githubAssetSubjectKey(value) { + return `${value.name}\0${value.sha256}`; +} + +export function assertAttestationSubjectCoverage(assets, attestations) { + if (!Array.isArray(assets) || !Array.isArray(attestations)) { + throw new Error('attestation coverage requires asset and attestation arrays'); + } + if (assets.length === 0 && attestations.length > 0) { + throw new Error( + 'attestation bundles contaminate a release selection with no frozen GitHub assets', + ); + } + const expectedByName = new Map(); + const expectedByKey = new Map(); + for (const asset of assets) { + requireSha256( + asset?.sha256, + `${asset?.product ?? ''}/${asset?.name ?? ''} sha256`, + ); + const key = githubAssetSubjectKey(asset); + const namedDigests = expectedByName.get(asset.name) ?? new Set(); + namedDigests.add(asset.sha256); + expectedByName.set(asset.name, namedDigests); + const matchingAssets = expectedByKey.get(key) ?? []; + matchingAssets.push(asset); + expectedByKey.set(key, matchingAssets); + } + const covered = new Set(); + const bundleDigests = new Set(); + const normalized = []; + for (const [index, attestation] of attestations.entries()) { + assertKeySet(attestation, ['bundleSha256', 'subjects'], `attestation[${index}]`); + const bundleSha256 = requireSha256( + attestation.bundleSha256, + `attestation[${index}].bundleSha256`, + ); + if (bundleDigests.has(bundleSha256)) { + throw new Error(`attestation bundle ${bundleSha256} was supplied more than once`); + } + bundleDigests.add(bundleSha256); + const subjects = normalizedReceiptSubjects( + attestation.subjects, + `attestation bundle ${bundleSha256}`, + ); + for (const subject of subjects) { + const key = githubAssetSubjectKey(subject); + if (!expectedByKey.has(key)) { + if (expectedByName.has(subject.name)) { + throw new Error( + `attestation bundle ${bundleSha256} subject ${subject.name} digest differs from the frozen GitHub asset`, + ); + } + throw new Error( + `attestation bundle ${bundleSha256} contains non-frozen subject ${subject.name}`, + ); + } + if (covered.has(key)) { + throw new Error(`signed subject ${subject.name} overlaps multiple attestation bundles`); + } + covered.add(key); + } + normalized.push({ bundleSha256, subjects }); + } + const missing = [...expectedByKey] + .filter(([key]) => !covered.has(key)) + .flatMap(([, matchingAssets]) => + matchingAssets.map((asset) => `${asset.product}/${asset.name}`), + ) + .sort(compareText); + if (missing.length > 0) { + throw new Error(`frozen GitHub assets are missing signed subjects: ${missing.join(', ')}`); + } + return normalized.sort((left, right) => compareText(left.bundleSha256, right.bundleSha256)); +} + +function receiptDigest(receipt) { + const copy = structuredClone(receipt); + delete copy.receiptDigest; + return createHash('sha256').update(stableStringify(copy)).digest('hex'); +} + +function githubSignerWorkflow(repo) { + return `${repo}/.github/workflows/release.yml`; +} + +export function buildGithubAttestationReceipt({ + attestations, + lock, + releases, + repo = repository(), + publisherSha = lock.source.commit, +}) { + const canonicalRepo = normalizedRepository(repo); + const normalizedReleases = normalizeGithubReleaseSnapshot(lock, releases); + const normalizedAttestations = assertAttestationSubjectCoverage( + frozenGithubReleaseAssets(lock), + attestations, + ); + const receipt = { + attestations: normalizedAttestations, + head: lock.source.commit, + lockDigest: lock.lockDigest, + releases: normalizedReleases, + repository: canonicalRepo, + schema: GITHUB_ATTESTATION_RECEIPT_SCHEMA, + signerWorkflow: githubSignerWorkflow(canonicalRepo), + sourceRef: 'refs/heads/main', + sourceTree: lock.source.tree, + ...(publisherSha === lock.source.commit ? {} : { publisherSha }), + }; + receipt.receiptDigest = receiptDigest(receipt); + return receipt; +} + +export function validateGithubAttestationReceipt(receipt, lock, { repo = repository() } = {}) { + const canonicalRepo = normalizedRepository(repo); + assertKeySet( + receipt, + [ + 'attestations', + 'head', + 'lockDigest', + 'receiptDigest', + 'releases', + 'repository', + 'schema', + 'signerWorkflow', + 'sourceRef', + 'sourceTree', + ...(Object.hasOwn(receipt, 'publisherSha') ? ['publisherSha'] : []), + ], + 'GitHub attestation receipt', + ); + if (receipt.publisherSha !== undefined && !/^[0-9a-f]{40}$/u.test(receipt.publisherSha)) { + throw new Error('GitHub attestation receipt publisher SHA is invalid'); + } + if ( + receipt.schema !== GITHUB_ATTESTATION_RECEIPT_SCHEMA || + receipt.repository !== canonicalRepo || + receipt.head !== lock.source.commit || + receipt.sourceTree !== lock.source.tree || + receipt.lockDigest !== lock.lockDigest || + receipt.signerWorkflow !== githubSignerWorkflow(canonicalRepo) || + receipt.sourceRef !== 'refs/heads/main' + ) { + throw new Error( + 'GitHub attestation receipt identity does not match the repository, source, or publication lock', + ); + } + requireSha256(receipt.receiptDigest, 'GitHub attestation receipt digest'); + const expectedDigest = receiptDigest(receipt); + if (receipt.receiptDigest !== expectedDigest) { + throw new Error( + `GitHub attestation receipt digest mismatch: expected ${expectedDigest}, got ${receipt.receiptDigest}`, + ); + } + const releases = normalizeGithubReleaseSnapshot(lock, receipt.releases); + const attestations = assertAttestationSubjectCoverage( + frozenGithubReleaseAssets(lock), + receipt.attestations, + ); + if ( + stableStringify(releases) !== stableStringify(receipt.releases) || + stableStringify(attestations) !== stableStringify(receipt.attestations) + ) { + throw new Error('GitHub attestation receipt is not in deterministic canonical order'); + } + return receipt; +} + +export function assertGithubReleaseSnapshotMatchesReceipt(receipt, releases) { + if (stableStringify(releases) !== stableStringify(receipt?.releases)) { + throw new Error( + 'GitHub release or asset IDs, names, sizes, or digests changed after the pre-mutation receipt was created', + ); + } +} + +async function verifyExtensionReleaseAssets( + product, + releaseProduct, + version, + family, + actualAssets, +) { + const manifestName = `${product}-${version}-manifest.json`; + const propertiesName = `${product}-${version}-manifest.properties`; + const swiftCarrierName = swiftExtensionCarrierAssetName(product, version); + const checksumName = `${product}-${version}-release-assets.sha256`; + const rootFamily = family === 'combined' ? 'native' : family; + const localReleaseAssetRoot = path.join( + ROOT, + extensionArtifactProductRoot(product, rootFamily, 'target/extension-artifacts', PREFIX), + 'release-assets', + ); + const localManifestPath = path.join(localReleaseAssetRoot, manifestName); + const localSwiftCarrierPath = path.join(localReleaseAssetRoot, swiftCarrierName); + const localManifest = await readJson(localManifestPath); + const includeSwiftCarrier = family !== 'wasix'; + const localSwiftCarrier = includeSwiftCarrier ? await readJson(localSwiftCarrierPath) : null; + const proofs = new Map(); + + const manifestAsset = actualAssets.get(manifestName); + const manifestSize = expectedAssetSize(manifestAsset.size, manifestName, MAX_CONTROL_ASSET_BYTES); + const manifestBytes = await requestBytes(manifestAsset.url, manifestName, manifestSize); + proofs.set(manifestName, { bytes: manifestBytes.byteLength, sha256: sha256Bytes(manifestBytes) }); + const remoteManifest = JSON.parse(new TextDecoder().decode(manifestBytes)); + if (stableStringify(remoteManifest) !== stableStringify(localManifest)) { + fail( + `${product} GitHub release ${await productTag(releaseProduct, version)} public manifest differs from staged manifest`, + ); + } + const extensionAssets = await validateExtensionManifest( + product, + version, + remoteManifest, + `${product} ${version} public extension manifest`, + { family, releaseProduct }, + ); + + if (includeSwiftCarrier) { + const swiftCarrierAsset = actualAssets.get(swiftCarrierName); + const swiftCarrierSize = expectedAssetSize( + swiftCarrierAsset.size, + swiftCarrierName, + MAX_CONTROL_ASSET_BYTES, + ); + const swiftCarrierBytes = await requestBytes( + swiftCarrierAsset.url, + swiftCarrierName, + swiftCarrierSize, + ); + proofs.set(swiftCarrierName, { + bytes: swiftCarrierBytes.byteLength, + sha256: sha256Bytes(swiftCarrierBytes), + }); + const remoteSwiftCarrier = JSON.parse(new TextDecoder().decode(swiftCarrierBytes)); + if (stableStringify(remoteSwiftCarrier) !== stableStringify(localSwiftCarrier)) { + fail( + `${product} GitHub release ${await productTag(releaseProduct, version)} Swift iOS carrier differs from staged carrier`, + ); + } + } + + const checksumAsset = actualAssets.get(checksumName); + const checksumSize = expectedAssetSize(checksumAsset.size, checksumName, MAX_CONTROL_ASSET_BYTES); + const checksumBytes = await requestBytes(checksumAsset.url, checksumName, checksumSize); + proofs.set(checksumName, { bytes: checksumBytes.byteLength, sha256: sha256Bytes(checksumBytes) }); + const checksums = parseChecksumManifest(checksumBytes, checksumName); + const checksumCoveredNames = new Set(extensionAssets.map((asset) => asset.name)); + checksumCoveredNames.add(manifestName); + checksumCoveredNames.add(propertiesName); + if (includeSwiftCarrier) checksumCoveredNames.add(swiftCarrierName); + if ( + stableStringify([...checksums.keys()].sort(compareText)) !== + stableStringify([...checksumCoveredNames].sort(compareText)) + ) { + fail( + `${product} GitHub release ${await productTag(releaseProduct, version)} checksum manifest must cover release assets exactly`, + ); + } + + for (const name of [...checksumCoveredNames].sort(compareText)) { + if (!actualAssets.has(name)) { + fail( + `${product} GitHub release ${await productTag(releaseProduct, version)} is missing checksum-covered asset ${name}`, + ); + } + const actualAsset = actualAssets.get(name); + const manifestAsset = extensionAssets.find((asset) => asset.name === name); + const remoteSize = expectedAssetSize(actualAsset.size, name); + if (manifestAsset !== undefined && remoteSize !== manifestAsset.bytes) { + fail( + `${product} GitHub release ${await productTag(releaseProduct, version)} asset ${name} size metadata mismatch`, + ); + } + let proof = proofs.get(name); + if (proof === undefined) { + proof = await requestAssetProof(actualAsset.url, name, manifestAsset?.bytes ?? remoteSize); + proofs.set(name, proof); + } + if (proof.sha256 !== checksums.get(name)) { + fail( + `${product} GitHub release ${await productTag(releaseProduct, version)} asset ${name} checksum mismatch`, + ); + } + if (remoteSize !== proof.bytes) { + fail( + `${product} GitHub release ${await productTag(releaseProduct, version)} asset ${name} size mismatch`, + ); + } + } + + for (const asset of extensionAssets) { + const proof = proofs.get(asset.name); + if (proof.bytes !== asset.bytes || proof.sha256 !== asset.sha256) { + fail( + `${product} GitHub release ${await productTag(releaseProduct, version)} asset ${asset.name} public manifest mismatch`, + ); + } + } +} + +async function verifyReleaseAssets(product, version, assets) { + const repo = repository(); + const tag = await productTag(product, version); + const actualAssets = await releaseAssets(repo, tag); + const expectedNames = new Set(assets); + try { + assertExactReleaseAssetNames({ + product, + tag, + expectedNames, + actualNames: actualAssets.keys(), + }); + } catch (error) { + fail(error.message); + } + const config = await productConfig(product); + if (['exact-extension-artifact', 'exact-extension-bundle'].includes(config.kind)) { + await verifyExtensionReleaseAssets(product, product, version, 'combined', actualAssets); + } else if (product === 'liboliphaunt-native' || product === 'liboliphaunt-wasix') { + const contrib = contribCarrierDescriptor(PREFIX); + if (assets.includes(`${contrib.artifactProduct}-${version}-manifest.json`)) { + await verifyExtensionReleaseAssets( + contrib.artifactProduct, + product, + version, + product === 'liboliphaunt-native' ? 'native' : 'wasix', + actualAssets, + ); + } + } + console.log(`${product} GitHub release assets verified for ${tag}: ${assets.join(', ')}`); +} + +async function readBoundedRegularFile(file, maximum, context) { + let stat; + try { + stat = await fs.lstat(file); + } catch (error) { + throw new Error(`${context} is unavailable: ${error.message}`); + } + if (stat.isSymbolicLink() || !stat.isFile()) { + throw new Error(`${context} must be a regular non-symlink file`); + } + if (!Number.isSafeInteger(stat.size) || stat.size < 0 || stat.size > maximum) { + throw new Error(`${context} exceeds ${maximum} bytes`); + } + const bytes = await fs.readFile(file); + if (bytes.byteLength !== stat.size || bytes.byteLength > maximum) { + throw new Error(`${context} changed while it was being read`); + } + return bytes; +} + +function parseJsonBytes(bytes, context) { + let text; + try { + text = new TextDecoder('utf-8', { fatal: true }).decode(bytes); + } catch (error) { + throw new Error(`${context} is not valid UTF-8: ${error.message}`); + } + try { + return JSON.parse(text); + } catch (error) { + throw new Error(`${context} is not one JSON value: ${error.message}`); + } +} + +function decodeBundleStatement(bundle, context) { + requireObject(bundle, context); + const payload = bundle.dsseEnvelope?.payload; + if ( + typeof payload !== 'string' || + payload.length === 0 || + !/^[A-Za-z0-9+/]+={0,2}$/u.test(payload) + ) { + throw new Error(`${context} lacks a canonical base64 DSSE payload`); + } + const bytes = Buffer.from(payload, 'base64'); + if (bytes.toString('base64') !== payload) { + throw new Error(`${context} DSSE payload is not canonical base64`); + } + const statement = parseJsonBytes(bytes, `${context} DSSE statement`); + requireObject(statement, `${context} DSSE statement`); + return statement; +} + +function statementSubjects(statement, context) { + if (statement._type !== IN_TOTO_STATEMENT_V1) { + throw new Error(`${context} must be an in-toto v1 statement`); + } + if (statement.predicateType !== SLSA_PROVENANCE_V1) { + throw new Error(`${context} must be an in-toto v1 SLSA provenance v1 statement`); + } + return normalizeAttestationSubjects(statement.subject, context); +} + +async function lockedLocalSubject(asset) { + const file = path.resolve(ROOT, asset.path); + const relative = path.relative(ROOT, file); + if (relative === '' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) { + throw new Error(`${asset.product}/${asset.name} frozen path must remain inside the repository`); + } + let stat; + try { + stat = await fs.lstat(file); + } catch (error) { + throw new Error( + `${asset.product}/${asset.name} frozen local subject is missing: ${error.message}`, + ); + } + if (stat.isSymbolicLink() || !stat.isFile()) { + throw new Error( + `${asset.product}/${asset.name} frozen local subject must be a regular non-symlink file`, + ); + } + if (stat.size !== asset.size || path.basename(file) !== asset.name) { + throw new Error( + `${asset.product}/${asset.name} frozen local subject path or size differs from the publication lock`, + ); + } + return file; +} + +function bundleVerificationFile({ bundlePath, file, head, repo }, directory) { + if (!/^[0-9a-f]{40}$/u.test(head ?? '')) + throw new Error('attestation source head must be a full lowercase commit SHA'); + const fields = [file, bundlePath, head, normalizedRepository(repo)]; + if ( + !directory || + fields.some((value) => typeof value !== 'string' || !value || value.includes('\0')) + ) + throw new Error('attestation verification requires verify-github-release-attestations.sh'); + return { fields, stem: path.join(directory, sha256Bytes(Buffer.from(JSON.stringify(fields)))) }; +} + +export async function prepareBundleVerification(options, directory) { + const { fields, stem } = bundleVerificationFile(options, directory); + await fs.writeFile(stem + '.subject', fields.join('\0') + '\0', { flag: 'wx', mode: 0o600 }); + return statementSubjects( + decodeBundleStatement(options.bundle, options.bundlePath), + options.bundlePath, + ); +} + +async function readGhBundleVerification(options) { + const { bundle, bundlePath } = options; + const { stem } = bundleVerificationFile( + options, + process.env.OLIPHAUNT_ATTESTATION_VERIFICATION_DIR, + ); + const output = parseJsonBytes( + await readBoundedRegularFile( + stem + '.json', + GH_ATTESTATION_VERIFY_MAX_OUTPUT_BYTES, + `gh verification output for ${bundlePath}`, + ), + `gh verification output for ${bundlePath}`, + ); + if (!Array.isArray(output) || output.length !== 1) { + throw new Error( + `gh verification output for ${bundlePath} must contain exactly one verified attestation`, + ); + } + const verified = requireObject(output[0], `gh verification output for ${bundlePath}`); + const verifiedBundle = verified.attestation?.bundle; + assertGhVerifiedBundleMatchesSupplied( + verifiedBundle, + bundle, + `gh verification output for ${bundlePath}`, + ); + const statement = verified.verificationResult?.statement; + requireObject(statement, `gh verification statement for ${bundlePath}`); + return statementSubjects(statement, `gh verified statement for ${bundlePath}`); +} + +export async function verifyAttestationBundles( + lock, + bundlePaths, + { + repo = repository(), + verifyBundleImpl = readGhBundleVerification, + publisherSha = lock.source.commit, + } = {}, +) { + const canonicalRepo = normalizedRepository(repo); + if (!Array.isArray(bundlePaths)) { + throw new Error('attestation bundle paths must be an array'); + } + const assets = frozenGithubReleaseAssets(lock); + if (assets.length === 0 && bundlePaths.length > 0) { + throw new Error( + 'attestation bundles contaminate a release selection with no frozen GitHub assets', + ); + } + const expectedByKey = new Map(assets.map((asset) => [githubAssetSubjectKey(asset), asset])); + const signerHead = publisherSha; + const records = []; + const suppliedPaths = new Set(); + const suppliedDigests = new Set(); + for (const bundlePath of bundlePaths) { + const absolute = path.resolve(bundlePath); + if (suppliedPaths.has(absolute)) { + throw new Error(`attestation bundle path was supplied more than once: ${bundlePath}`); + } + suppliedPaths.add(absolute); + const bytes = await readBoundedRegularFile( + absolute, + MAX_ATTESTATION_BUNDLE_BYTES, + `attestation bundle ${bundlePath}`, + ); + const bundleSha256 = sha256Bytes(bytes); + if (suppliedDigests.has(bundleSha256)) { + throw new Error(`attestation bundle ${bundleSha256} was supplied more than once`); + } + suppliedDigests.add(bundleSha256); + const bundle = parseJsonBytes(bytes, `attestation bundle ${bundlePath}`); + const untrustedSubjects = statementSubjects( + decodeBundleStatement(bundle, `attestation bundle ${bundlePath}`), + `unverified statement for ${bundlePath}`, + ); + const representatives = untrustedSubjects + .map((subject) => expectedByKey.get(githubAssetSubjectKey(subject))) + .filter((asset) => asset !== undefined) + .sort((left, right) => left.size - right.size || compareText(left.name, right.name)); + if (representatives.length === 0) { + throw new Error(`attestation bundle ${bundlePath} contains no frozen GitHub asset subject`); + } + const file = await lockedLocalSubject(representatives[0]); + const verifiedSubjects = await verifyBundleImpl({ + bundle, + bundlePath: absolute, + file, + head: signerHead, + repo: canonicalRepo, + }); + if (stableStringify(verifiedSubjects) !== stableStringify(untrustedSubjects)) { + throw new Error( + `cryptographically verified subjects for ${bundlePath} differ from its DSSE statement`, + ); + } + records.push({ bundleSha256, subjects: verifiedSubjects }); + } + return assertAttestationSubjectCoverage(assets, records); +} + +async function readReceipt(file) { + const absolute = path.resolve(file); + const bytes = await readBoundedRegularFile( + absolute, + MAX_ATTESTATION_RECEIPT_BYTES, + `GitHub attestation receipt ${file}`, + ); + return parseJsonBytes(bytes, `GitHub attestation receipt ${file}`); +} + +export async function writeImmutableReceipt( + file, + receipt, + { linkImpl = (source, target) => fs.link(source, target) } = {}, +) { + const absolute = path.resolve(file); + const body = `${JSON.stringify(receipt, null, 2)}\n`; + if (Buffer.byteLength(body) > MAX_ATTESTATION_RECEIPT_BYTES) { + throw new Error( + `GitHub attestation receipt ${file} exceeds ${MAX_ATTESTATION_RECEIPT_BYTES} bytes`, + ); + } + await fs.mkdir(path.dirname(absolute), { recursive: true }); + const temporary = `${absolute}.tmp-${process.pid}-${randomUUID()}`; + let operationError; + try { + await fs.writeFile(temporary, body, { encoding: 'utf8', flag: 'wx', mode: 0o600 }); + try { + // Linking a fully-written temporary inode publishes the receipt in one + // filesystem operation. An interruption can leave a disposable temp, + // never a truncated immutable target that blocks a safe rerun. + await linkImpl(temporary, absolute); + } catch (error) { + if (error?.code !== 'EEXIST') throw error; + const existing = await readBoundedRegularFile( + absolute, + MAX_ATTESTATION_RECEIPT_BYTES, + `GitHub attestation receipt ${file}`, + ); + if (existing.toString('utf8') !== body) { + throw new Error( + `refusing to replace existing non-identical GitHub attestation receipt ${file}`, + ); + } + } + } catch (error) { + operationError = error; + } + let cleanupError; + try { + await fs.unlink(temporary); + } catch (error) { + if (error?.code !== 'ENOENT') cleanupError = error; + } + if (operationError !== undefined && cleanupError !== undefined) { + throw new AggregateError( + [operationError, cleanupError], + `GitHub attestation receipt ${file} failed and its temporary file could not be removed`, + ); + } + if (operationError !== undefined) throw operationError; + if (cleanupError !== undefined) throw cleanupError; + return absolute; +} + +function parseReceiptArgs(command, argv) { + const args = { + attestationBundles: [], + headRef: 'HEAD', + output: undefined, + productsJson: undefined, + publicationLock: undefined, + receipt: undefined, + repo: repository(), + }; + const assign = (key, value, flag) => { + if (value === undefined || (value.length === 0 && flag !== '--attestation-bundle')) { + throw new Error(`${flag} requires a value`); + } + args[key] = value; + }; + for (let index = 0; index < argv.length; index += 1) { + const argument = argv[index]; + const separator = argument.indexOf('='); + const flag = separator === -1 ? argument : argument.slice(0, separator); + const value = separator === -1 ? argv[++index] : argument.slice(separator + 1); + if (flag === '--attestation-bundle') { + if (value === undefined) throw new Error('--attestation-bundle requires a value'); + if (value.length > 0) args.attestationBundles.push(value); + } else if (flag === '--head-ref') { + assign('headRef', value, flag); + } else if (flag === '--output') { + assign('output', value, flag); + } else if (flag === '--products-json') { + assign('productsJson', value, flag); + } else if (flag === '--publication-lock') { + assign('publicationLock', value, flag); + } else if (flag === '--receipt') { + assign('receipt', value, flag); + } else if (flag === '--repo') { + assign('repo', value, flag); + } else if (flag === '--help' || flag === '-h') { + return { help: true }; + } else { + throw new Error(`unknown ${command} argument ${argument}`); + } + } + if (!args.publicationLock) { + throw new Error(`${command} requires --publication-lock`); + } + if (command === 'pre-mutation' && !args.output) { + throw new Error('pre-mutation requires --output'); + } + if (command === 'finalize' && !args.receipt) { + throw new Error('finalize requires --receipt'); + } + if (command === 'pre-mutation' && args.receipt !== undefined) { + throw new Error('pre-mutation does not accept --receipt'); + } + if (command === 'finalize' && (args.output !== undefined || args.attestationBundles.length > 0)) { + throw new Error('finalize does not accept --output or --attestation-bundle'); + } + return args; +} + +function assertRequestedProducts(lock, productsJson) { + if (productsJson === undefined) return; + let products; + try { + products = JSON.parse(productsJson); + } catch (error) { + throw new Error(`--products-json must be valid JSON: ${error.message}`); + } + if ( + !Array.isArray(products) || + products.some((product) => typeof product !== 'string' || product.length === 0) + ) { + throw new Error('--products-json must be a JSON string array'); + } + exactProductSet( + lock.products.map((product) => product.id), + products, + 'requested products and frozen publication lock products', + ); +} + +function receiptUsage() { + console.log('usage:'); + console.log( + ' bash tools/release/verify-github-release-attestations.sh pre-mutation --publication-lock FILE --head-ref REF --output FILE [--products-json JSON] [--attestation-bundle FILE ...]', + ); + console.log( + ' bash tools/release/verify-github-release-attestations.sh finalize --publication-lock FILE --head-ref REF --receipt FILE [--products-json JSON]', + ); +} + +async function receiptMain(command, argv, prepareDirectory) { + const args = parseReceiptArgs(command, argv); + if (args.help) { + receiptUsage(); + return; + } + const lock = loadPublicationLock(path.resolve(args.publicationLock)); + assertPublicationLockSource(lock, args.headRef); + assertRequestedProducts(lock, args.productsJson); + const repo = normalizedRepository(args.repo); + if (command === 'pre-mutation') { + const publisherSha = process.env.GITHUB_SHA || lock.source.commit; + assertPublicationController({ source: lock.source.commit, controller: publisherSha }); + const attestations = await verifyAttestationBundles(lock, args.attestationBundles, { + repo, + publisherSha, + ...(prepareDirectory + ? { verifyBundleImpl: (options) => prepareBundleVerification(options, prepareDirectory) } + : {}), + }); + if (prepareDirectory) return; + const releases = await queryLockedGithubReleases(lock, { repo }); + const receipt = buildGithubAttestationReceipt({ + attestations, + lock, + releases, + repo, + publisherSha, + }); + const output = await writeImmutableReceipt(args.output, receipt); + console.log( + `GitHub release attestation receipt created at ${rel(output)} ` + + `(${receipt.releases.length} releases, ${frozenGithubReleaseAssets(lock).length} assets, ` + + `${receipt.attestations.length} signed bundles, ${receipt.receiptDigest})`, + ); + return; + } + const receipt = validateGithubAttestationReceipt(await readReceipt(args.receipt), lock, { repo }); + const releases = await queryLockedGithubReleases(lock, { repo }); + assertGithubReleaseSnapshotMatchesReceipt(receipt, releases); + console.log( + `GitHub release attestation receipt finalized (${receipt.releases.length} releases, ` + + `${frozenGithubReleaseAssets(lock).length} assets, ${receipt.receiptDigest})`, + ); +} + +function parseLegacyArgs(argv) { + const args = { product: [], productsJson: undefined }; + for (let index = 0; index < argv.length; index += 1) { + const value = argv[index]; + if (value === '--product') { + const product = argv[++index]; + if (!product) { + fail('--product requires a value'); + } + args.product.push(product); + } else if (value.startsWith('--product=')) { + args.product.push(value.slice('--product='.length)); + } else if (value === '--products-json') { + args.productsJson = argv[++index]; + if (args.productsJson === undefined) { + fail('--products-json requires a value'); + } + } else if (value.startsWith('--products-json=')) { + args.productsJson = value.slice('--products-json='.length); + } else if (value === '--head-ref') { + index += 1; + } else if (value.startsWith('--head-ref=')) { + continue; + } else if (value === '--help' || value === '-h') { + console.log( + 'usage: bash tools/release/verify-github-release-attestations.sh [--product ID...] [--products-json JSON] [--head-ref REF]', + ); + receiptUsage(); + process.exit(0); + } else { + fail(`unknown argument ${value}`); + } + } + return args; +} + +async function parseProducts(value) { + const backed = await assetBackedProducts(); + if (!value) { + return [...backed].sort(compareText); + } + let parsed; + try { + parsed = JSON.parse(value); + } catch (error) { + fail(`--products-json must be valid JSON: ${error.message}`); + } + if (!Array.isArray(parsed) || !parsed.every((item) => typeof item === 'string')) { + fail('--products-json must be a JSON string array'); + } + return parsed.filter((product) => backed.has(product)); +} + +export { assetBackedProducts, expectedAssets, productTag, verifyReleaseAssets }; + +async function legacyMain(argv, destination) { + const args = parseLegacyArgs(argv); + const products = args.product.length > 0 ? args.product : await parseProducts(args.productsJson); + const backed = await assetBackedProducts(); + const unknown = products.filter((product) => !backed.has(product)).sort(compareText); + if (unknown.length > 0) { + fail( + `attestation verification is only defined for asset-backed products: ${unknown.join(', ')}`, + ); + } + if (products.length === 0) { + console.log('no asset-backed products selected; GitHub attestation verification skipped'); + return; + } + for (const product of products) { + const version = await currentVersion(product); + const tag = await productTag(product, version); + const repo = normalizedRepository(repository()); + const assets = await expectedAssets(product, version); + await verifyReleaseAssets(product, version, assets); + const productDir = path.join(destination, product); + await fs.mkdir(productDir, { recursive: true }); + for (const asset of assets) { + const file = path.join(productDir, asset); + await fs.writeFile(file + '.public', [repo, tag, asset, file].join('\0') + '\0'); + } + } +} + +async function main(argv) { + const command = argv[0]; + if (command === '--prepare-bundles') return receiptMain('pre-mutation', argv.slice(2), argv[1]); + if (command === '--prepare-public') return legacyMain(argv.slice(2), argv[1]); + if (command === 'pre-mutation' || command === 'finalize') { + try { + await receiptMain(command, argv.slice(1)); + } catch (error) { + fail(error instanceof Error ? error.message : String(error)); + } + return; + } + if (argv.includes('--help') || argv.includes('-h')) return parseLegacyArgs(argv); + throw new Error('use verify-github-release-attestations.sh'); +} + +if (import.meta.main) { + await main(Bun.argv.slice(2)); +} diff --git a/tools/release/verify_product_tag.mjs b/tools/release/verify_product_tag.mjs deleted file mode 100755 index 56dee30eb..000000000 --- a/tools/release/verify_product_tag.mjs +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env bun -import fs from 'node:fs/promises'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import { captureCommandOutput } from '../dev/capture-command-output.mjs'; - -const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..'); - -function fail(message) { - console.error(`verify_product_tag.mjs: ${message}`); - process.exit(1); -} - -function parseArgs(argv) { - let allowMissing = false; - let product = null; - let target = process.env.GITHUB_SHA || 'HEAD'; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === '--target') { - target = argv[index + 1] ?? ''; - index += 1; - continue; - } - if (arg === '--allow-missing') { - allowMissing = true; - continue; - } - if (arg.startsWith('--')) { - fail(`unknown argument: ${arg}`); - } - if (product !== null) { - fail('usage: tools/release/verify_product_tag.mjs [--target ] [--allow-missing]'); - } - product = arg; - } - if (!product || !target) { - fail('usage: tools/release/verify_product_tag.mjs [--target ] [--allow-missing]'); - } - return { allowMissing, product, target }; -} - -function git(args, { check = true } = {}) { - const result = captureCommandOutput('git', args, { - cwd: root, - label: `git ${args.join(' ')}`, - }); - if (result.error !== undefined) { - fail(`git ${args.join(' ')} failed to start: ${result.error.message}`); - } - if (check && result.status !== 0) { - const stderr = result.stderr.trim(); - fail(`git ${args.join(' ')} failed${stderr ? `: ${stderr}` : ''}`); - } - return { - exitCode: result.status, - stdout: result.stdout.trim(), - stderr: result.stderr.trim(), - }; -} - -function commitForRef(ref) { - return git(['rev-parse', `${ref}^{commit}`]).stdout; -} - -function tagCommit(tag) { - const result = git(['rev-parse', '--verify', '--quiet', `refs/tags/${tag}^{commit}`], { - check: false, - }); - return result.exitCode === 0 ? result.stdout : null; -} - -function refreshTagFromOrigin(tag) { - const remote = git(['remote', 'get-url', 'origin'], { check: false }); - if (remote.exitCode !== 0) { - return tagCommit(tag); - } - const advertised = git( - ['ls-remote', '--exit-code', '--tags', 'origin', `refs/tags/${tag}`, `refs/tags/${tag}^{}`], - { check: false }, - ); - if (advertised.exitCode === 2 || (advertised.exitCode === 0 && advertised.stdout.length === 0)) { - return null; - } - if (advertised.exitCode !== 0) { - fail(`could not inspect ${tag} on origin before verification${advertised.stderr ? `: ${advertised.stderr}` : ''}`); - } - const result = git(['fetch', '--force', '--no-tags', 'origin', `refs/tags/${tag}:refs/tags/${tag}`], { - check: false, - }); - if (result.exitCode !== 0) { - fail(`could not refresh ${tag} from origin before verification${result.stderr ? `: ${result.stderr}` : ''}`); - } - const commit = tagCommit(tag); - if (commit === null) { - fail(`${tag} was advertised by origin but could not be resolved to a commit`); - } - return commit; -} - -async function releasePleaseProduct(product) { - const config = JSON.parse(await fs.readFile(path.join(root, 'release-please-config.json'), 'utf8')); - if (config['include-v-in-tag'] !== true) { - fail('release-please must include v in product tags'); - } - if (config['tag-separator'] !== '-') { - fail("release-please tag-separator must be '-'"); - } - const packages = config.packages; - if (typeof packages !== 'object' || packages === null) { - fail('release-please-config.json must define packages'); - } - for (const [packagePath, packageConfig] of Object.entries(packages)) { - if (packageConfig?.component === product) { - return { packagePath, packageConfig }; - } - } - fail(`unknown release product '${product}'`); -} - -function parseCargoVersion(text) { - let inPackage = false; - for (const rawLine of text.split(/\r?\n/u)) { - const line = rawLine.trim(); - if (line === '[package]') { - inPackage = true; - continue; - } - if (inPackage && line.startsWith('[')) { - break; - } - if (!inPackage) { - continue; - } - const match = line.match(/^version\s*=\s*"([^"]+)"/u); - if (match) { - return match[1]; - } - } - return ''; -} - -async function currentProductVersion(product) { - const { packagePath, packageConfig } = await releasePleaseProduct(product); - const releaseType = packageConfig['release-type']; - const versionFile = - typeof packageConfig['version-file'] === 'string' - ? packageConfig['version-file'] - : releaseType === 'rust' - ? 'Cargo.toml' - : releaseType === 'node' || releaseType === 'expo' - ? 'package.json' - : null; - if (!versionFile) { - fail(`${product} release-please config must declare version-file for release type '${releaseType}'`); - } - if (path.isAbsolute(versionFile) || versionFile.split(/[\\/]/u).includes('..')) { - fail(`${product}.version-file must stay inside release package path`); - } - const versionPath = path.join(root, packagePath, versionFile); - const text = await fs.readFile(versionPath, 'utf8'); - const fileName = path.basename(versionFile); - let version = ''; - if (fileName === 'Cargo.toml') { - version = parseCargoVersion(text); - } else if (fileName === 'package.json') { - version = JSON.parse(text).version ?? ''; - } else if (fileName === 'VERSION' || fileName === 'LIBOLIPHAUNT_VERSION') { - version = text.trim(); - } else { - fail(`${product}.version-file has unsupported version file type: ${versionFile}`); - } - if (typeof version !== 'string' || version.length === 0) { - fail(`${path.relative(root, versionPath)} does not define a release version for ${product}`); - } - return version; -} - -const { allowMissing, product, target } = parseArgs(Bun.argv.slice(2)); -const version = await currentProductVersion(product); -const tag = `${product}-v${version}`; -const targetCommit = commitForRef(target); -const existing = refreshTagFromOrigin(tag); -if (existing === null) { - if (allowMissing) { - console.log(`${tag} is absent and available for exact-SHA release creation`); - process.exit(0); - } - fail(`${tag} does not exist. Stage the exact-SHA draft release before registry publish steps.`); -} -if (existing !== targetCommit) { - fail(`${tag} points at ${existing}, not exact release commit ${targetCommit}`); -} else { - console.log(`${tag} points at ${targetCommit}`); -} diff --git a/tools/release/verify_product_tags.mjs b/tools/release/verify_product_tags.mjs deleted file mode 100644 index 86d21f069..000000000 --- a/tools/release/verify_product_tags.mjs +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env bun -import { captureCommandOutput } from '../dev/capture-command-output.mjs'; -import { compareText, loadGraph } from './release-graph.mjs'; - -const root = new URL('../..', import.meta.url).pathname; - -function fail(message) { - console.error(`verify_product_tags.mjs: ${message}`); - process.exit(1); -} - -function parseArgs(argv) { - let allowMissing = false; - let productsJson = ''; - let target = process.env.GITHUB_SHA || 'HEAD'; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - if (arg === '--products-json') { - productsJson = argv[index + 1] ?? ''; - index += 1; - continue; - } - if (arg === '--target') { - target = argv[index + 1] ?? ''; - index += 1; - continue; - } - if (arg === '--allow-missing') { - allowMissing = true; - continue; - } - fail(`unknown argument: ${arg}`); - } - if (!productsJson || !target) { - fail('usage: tools/release/verify_product_tags.mjs --products-json [--target ] [--allow-missing]'); - } - return { allowMissing, productsJson, target }; -} - -function parseProducts(productsJson) { - let products; - try { - products = JSON.parse(productsJson); - } catch (error) { - fail(`--products-json must be valid JSON: ${error.message}`); - } - if (!Array.isArray(products) || products.length === 0 || !products.every((product) => typeof product === 'string' && product)) { - fail('--products-json must be a non-empty JSON string array'); - } - return [...new Set(products)].sort(compareText); -} - -function git(args, { check = true } = {}) { - const result = captureCommandOutput('git', args, { - cwd: root, - label: `git ${args.join(' ')}`, - }); - if (result.error) { - fail(result.error.message); - } - if (check && result.status !== 0) { - fail(`git ${args.join(' ')} failed${result.stderr.trim() ? `: ${result.stderr.trim()}` : ''}`); - } - return { status: result.status, stdout: result.stdout.trim(), stderr: result.stderr.trim() }; -} - -const { allowMissing, productsJson, target } = parseArgs(Bun.argv.slice(2)); -const products = parseProducts(productsJson); -const graph = loadGraph('verify_product_tags.mjs'); -const rows = products.map((product) => { - const config = graph.products[product]; - if (!config) { - fail(`unknown release product '${product}'`); - } - return { product, tag: `${config.tag_prefix}${config.version}` }; -}); -const targetCommit = git(['rev-parse', '--verify', `${target}^{commit}`]).stdout; - -let remoteTags = null; -if (git(['remote', 'get-url', 'origin'], { check: false }).status === 0) { - const advertised = git(['ls-remote', '--tags', 'origin']); - remoteTags = new Set( - advertised.stdout - .split(/\r?\n/u) - .map((line) => line.split(/\s+/u)[1] ?? '') - .filter((ref) => ref.startsWith('refs/tags/')) - .map((ref) => ref.replace(/\^\{\}$/u, '')), - ); - const existingRefs = rows - .filter(({ tag }) => remoteTags.has(`refs/tags/${tag}`)) - .map(({ tag }) => `refs/tags/${tag}:refs/tags/${tag}`); - if (existingRefs.length > 0) { - git(['fetch', '--force', '--no-tags', 'origin', ...existingRefs]); - } -} - -let absent = 0; -let exact = 0; -for (const { product, tag } of rows) { - const advertised = remoteTags === null ? null : remoteTags.has(`refs/tags/${tag}`); - const resolved = advertised === false - ? { status: 1, stdout: '' } - : git(['rev-parse', '--verify', '--quiet', `refs/tags/${tag}^{commit}`], { check: false }); - if (resolved.status !== 0) { - absent += 1; - if (!allowMissing) { - fail(`${product} release tag ${tag} does not exist; stage the exact-SHA draft release before publication`); - } - continue; - } - if (resolved.stdout !== targetCommit) { - fail(`${product} release tag ${tag} points at ${resolved.stdout}, not exact release commit ${targetCommit}`); - } - exact += 1; -} -console.log( - `${allowMissing ? 'preflighted' : 'verified'} ${products.length} release product tag(s) at ${targetCommit}: ` + - `${exact} exact, ${absent} absent`, -); diff --git a/tools/release/wasix-aot-manifest.mjs b/tools/release/wasix-aot-manifest.mjs deleted file mode 100644 index 963cde5ac..000000000 --- a/tools/release/wasix-aot-manifest.mjs +++ /dev/null @@ -1,58 +0,0 @@ -import { ROOT } from "./release-artifact-targets.mjs"; -import { - WASIX_TOOLCHAIN_PATH, - canonicalWasixCargoToolchainVersions, -} from "./wasix-cargo-toolchain-policy.mjs"; - -export { WASIX_TOOLCHAIN_PATH }; -export const STABLE_WASIX_SOURCE_LANE = "stable"; -export const WASIX_AOT_ENGINE = "llvm-opta"; - -function requiredString(value, context) { - if (typeof value !== "string" || value.length === 0) { - throw new Error(`${context} must be a non-empty string`); - } - return value; -} - -export function canonicalWasixAotMetadata(root = ROOT) { - const toolchain = canonicalWasixCargoToolchainVersions(root); - return { - sourceLane: STABLE_WASIX_SOURCE_LANE, - engine: WASIX_AOT_ENGINE, - wasmerVersion: toolchain.wasmer, - wasmerWasixVersion: toolchain.wasmerWasix, - }; -} - -export function assertCanonicalWasixAotManifest( - manifest, - { - context = "WASIX AOT manifest", - expectedTarget, - canonical = canonicalWasixAotMetadata(), - } = {}, -) { - if (manifest === null || typeof manifest !== "object" || Array.isArray(manifest)) { - throw new Error(`${context} must be a JSON object`); - } - const expected = [ - ["format-version", 1], - ["source-lane", canonical.sourceLane], - ["engine", canonical.engine], - ["wasmer-version", canonical.wasmerVersion], - ["wasmer-wasix-version", canonical.wasmerWasixVersion], - ]; - if (expectedTarget !== undefined) { - expected.push(["target-triple", requiredString(expectedTarget, `${context} expected target`)]); - } - for (const [field, expectedValue] of expected) { - const actualValue = manifest[field]; - if (actualValue !== expectedValue) { - throw new Error( - `${context} ${field} must match canonical WASIX metadata: ` + - `expected ${JSON.stringify(expectedValue)}, got ${JSON.stringify(actualValue)}`, - ); - } - } -} diff --git a/tools/release/wasix-aot-manifest.test.mjs b/tools/release/wasix-aot-manifest.test.mjs deleted file mode 100644 index 4bf80193c..000000000 --- a/tools/release/wasix-aot-manifest.test.mjs +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bun -import assert from "node:assert/strict"; -import test from "node:test"; - -import { - assertCanonicalWasixAotManifest, - canonicalWasixAotMetadata, -} from "./wasix-aot-manifest.mjs"; - -function manifest(overrides = {}) { - const canonical = canonicalWasixAotMetadata(); - return { - "format-version": 1, - "source-lane": canonical.sourceLane, - "target-triple": "x86_64-unknown-linux-gnu", - engine: canonical.engine, - "wasmer-version": canonical.wasmerVersion, - "wasmer-wasix-version": canonical.wasmerWasixVersion, - artifacts: [{ name: "runtime:oliphaunt", path: "oliphaunt.aot.zst" }], - ...overrides, - }; -} - -test("accepts AOT metadata that exactly matches the canonical WASIX toolchain", () => { - assert.doesNotThrow(() => - assertCanonicalWasixAotManifest(manifest(), { - expectedTarget: "x86_64-unknown-linux-gnu", - }), - ); -}); - -test("rejects stale prerelease Wasmer metadata", () => { - assert.throws( - () => - assertCanonicalWasixAotManifest( - manifest({ - "wasmer-version": "7.2.1-alpha.3", - "wasmer-wasix-version": "0.702.1-alpha.3", - }), - { expectedTarget: "x86_64-unknown-linux-gnu" }, - ), - /wasmer-version must match canonical WASIX metadata/u, - ); -}); - -test("rejects stale prerelease Wasmer-WASIX metadata", () => { - assert.throws( - () => - assertCanonicalWasixAotManifest( - manifest({ "wasmer-wasix-version": "0.702.1-alpha.3" }), - { expectedTarget: "x86_64-unknown-linux-gnu" }, - ), - /wasmer-wasix-version must match canonical WASIX metadata/u, - ); -}); - -test("rejects an AOT archive labeled for another target", () => { - assert.throws( - () => - assertCanonicalWasixAotManifest(manifest(), { - expectedTarget: "aarch64-apple-darwin", - }), - /target-triple must match canonical WASIX metadata/u, - ); -}); diff --git a/tools/release/wasix-cargo-artifact-contract.mjs b/tools/release/wasix-cargo-artifact-contract.mjs deleted file mode 100644 index ce51b45fb..000000000 --- a/tools/release/wasix-cargo-artifact-contract.mjs +++ /dev/null @@ -1,174 +0,0 @@ -import { compareText } from "./release-graph.mjs"; - -export const WASIX_CARGO_ARTIFACT_SCHEMA = "oliphaunt-liboliphaunt-wasix-cargo-artifacts-v2"; -export const EXTENSION_PORTABLE_TARGET = "wasix-portable"; -export const RUNTIME_PACKAGE = "liboliphaunt-wasix-portable"; -export const TOOLS_PACKAGE = "oliphaunt-wasix-tools"; -export const ICU_PACKAGE = "oliphaunt-icu"; -export const ICU_PAYLOAD_ARCHIVE = "icu-data.tar.zst"; - -export const TOOLS_PAYLOAD_FILES = [ - "bin/pg_dump.wasix.wasm", - "bin/psql.wasix.wasm", -]; - -export const SNOWBALL_STOPWORD_LANGUAGES = [ - "danish", - "dutch", - "english", - "finnish", - "french", - "german", - "hungarian", - "italian", - "nepali", - "norwegian", - "portuguese", - "russian", - "spanish", - "swedish", - "turkish", -]; - -export const CORE_RUNTIME_ARCHIVE_FILES = [ - "oliphaunt/bin/initdb", - "oliphaunt/bin/postgres", - "oliphaunt/lib/postgresql/dict_snowball.so", - "oliphaunt/lib/postgresql/plpgsql.so", - "oliphaunt/share/postgresql/extension/plpgsql--1.0.sql", - "oliphaunt/share/postgresql/extension/plpgsql.control", - "oliphaunt/share/postgresql/snowball_create.sql", - ...SNOWBALL_STOPWORD_LANGUAGES.map( - (language) => `oliphaunt/share/postgresql/tsearch_data/${language}.stop`, - ), -]; - -export const FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES = [ - "oliphaunt/bin/pg_ctl", - "oliphaunt/bin/pg_dump", - "oliphaunt/bin/psql", -]; - -export const TOOLS_AOT_ARTIFACTS = [ - "tool:pg_dump", - "tool:psql", -]; - -export const AOT_PACKAGES = { - "macos-arm64": "liboliphaunt-wasix-aot-aarch64-apple-darwin", - "linux-arm64-gnu": "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", - "linux-x64-gnu": "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", - "windows-x64-msvc": "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", -}; - -export const TOOLS_AOT_PACKAGES = { - "macos-arm64": "oliphaunt-wasix-tools-aot-aarch64-apple-darwin", - "linux-arm64-gnu": "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu", - "linux-x64-gnu": "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", - "windows-x64-msvc": "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc", -}; - -export const AOT_TARGET_TRIPLES = { - "macos-arm64": "aarch64-apple-darwin", - "linux-arm64-gnu": "aarch64-unknown-linux-gnu", - "linux-x64-gnu": "x86_64-unknown-linux-gnu", - "windows-x64-msvc": "x86_64-pc-windows-msvc", -}; - -// crates.io limits package names to 64 characters. Extension AOT carriers can -// be split into `-part-NNN` crates, so their stable parent names must leave -// nine characters of headroom. These aliases are package identities only; -// manifests continue to record the full compilation triple. -export const EXTENSION_AOT_PACKAGE_SUFFIXES = { - "aarch64-apple-darwin": "macos-arm64", - "aarch64-unknown-linux-gnu": "linux-arm64", - "x86_64-unknown-linux-gnu": "linux-x64", - "x86_64-pc-windows-msvc": "windows-x64", -}; - -export const AOT_TARGET_CFGS = { - "aarch64-apple-darwin": 'cfg(all(target_os = "macos", target_arch = "aarch64"))', - "aarch64-unknown-linux-gnu": 'cfg(all(target_os = "linux", target_arch = "aarch64", target_env = "gnu"))', - "x86_64-unknown-linux-gnu": 'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))', - "x86_64-pc-windows-msvc": 'cfg(all(target_os = "windows", target_arch = "x86_64", target_env = "msvc"))', -}; - -export function publicCargoPackageNames() { - return [ - ICU_PACKAGE, - RUNTIME_PACKAGE, - TOOLS_PACKAGE, - ...Object.values(AOT_PACKAGES), - ...Object.values(TOOLS_AOT_PACKAGES), - ].sort(compareText); -} - -export function publicAotCargoDependencies() { - return Object.fromEntries( - Object.keys(AOT_PACKAGES) - .sort(compareText) - .map((target) => [ - AOT_TARGET_CFGS[AOT_TARGET_TRIPLES[target]], - AOT_PACKAGES[target], - ]), - ); -} - -export function publicToolsAotCargoDependencies() { - return Object.fromEntries( - Object.keys(TOOLS_AOT_PACKAGES) - .sort(compareText) - .map((target) => [ - AOT_TARGET_CFGS[AOT_TARGET_TRIPLES[target]], - TOOLS_AOT_PACKAGES[target], - ]), - ); -} - -export function publicToolsFeatureDependencies() { - return [ - `dep:${TOOLS_PACKAGE}`, - ...Object.values(TOOLS_AOT_PACKAGES).map((name) => `dep:${name}`), - ].sort(compareText); -} - -export function wasixExtensionPackageName(product) { - return `${product}-wasix`; -} - -export function wasixExtensionAotPackageName(product, target) { - const suffix = EXTENSION_AOT_PACKAGE_SUFFIXES[target]; - if (suffix === undefined) { - throw new TypeError(`unknown extension AOT package target ${JSON.stringify(target)}`); - } - return `${product}-aot-${suffix}`; -} - -export function expectedExtensionAotTargets() { - return [...new Set(Object.values(AOT_TARGET_TRIPLES))].sort(compareText); -} - -export function wasixCargoArtifactContract() { - return { - schema: WASIX_CARGO_ARTIFACT_SCHEMA, - extensionPortableTarget: EXTENSION_PORTABLE_TARGET, - runtimePackage: RUNTIME_PACKAGE, - toolsPackage: TOOLS_PACKAGE, - icuPackage: ICU_PACKAGE, - icuPayloadArchive: ICU_PAYLOAD_ARCHIVE, - coreRuntimeArchiveFiles: [...CORE_RUNTIME_ARCHIVE_FILES], - toolsPayloadFiles: [...TOOLS_PAYLOAD_FILES], - forbiddenRuntimeArchiveToolFiles: [...FORBIDDEN_RUNTIME_ARCHIVE_TOOL_FILES], - toolsAotArtifacts: [...TOOLS_AOT_ARTIFACTS], - aotPackages: { ...AOT_PACKAGES }, - toolsAotPackages: { ...TOOLS_AOT_PACKAGES }, - aotTargetTriples: { ...AOT_TARGET_TRIPLES }, - aotTargetCfgs: { ...AOT_TARGET_CFGS }, - extensionAotPackageSuffixes: { ...EXTENSION_AOT_PACKAGE_SUFFIXES }, - expectedExtensionAotTargets: expectedExtensionAotTargets(), - publicCargoPackageNames: publicCargoPackageNames(), - publicAotCargoDependencies: publicAotCargoDependencies(), - publicToolsAotCargoDependencies: publicToolsAotCargoDependencies(), - publicToolsFeatureDependencies: publicToolsFeatureDependencies(), - }; -} diff --git a/tools/release/wasix-cargo-license-contract.test.mjs b/tools/release/wasix-cargo-license-contract.test.mjs deleted file mode 100644 index 7e551d0d4..000000000 --- a/tools/release/wasix-cargo-license-contract.test.mjs +++ /dev/null @@ -1,61 +0,0 @@ -import assert from "node:assert/strict"; -import { readFileSync } from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { - releaseNoticeRows, - releaseProfilePackageLicense, -} from "./release-notices.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); - -const CORE_TEMPLATES = [ - ["src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml", "wasix-runtime"], - ["src/runtimes/liboliphaunt/wasix/crates/tools/Cargo.toml", "wasix-tools"], - ["src/runtimes/liboliphaunt/icu/Cargo.toml", "wasix-icu-data-crate"], - ...[ - "aarch64-apple-darwin", - "aarch64-unknown-linux-gnu", - "x86_64-pc-windows-msvc", - "x86_64-unknown-linux-gnu", - ].flatMap((target) => [ - [`src/runtimes/liboliphaunt/wasix/crates/aot/${target}/Cargo.toml`, "wasix-aot"], - [`src/runtimes/liboliphaunt/wasix/crates/tools-aot/${target}/Cargo.toml`, "wasix-aot"], - ]), -]; - -const ALL_NOTICE_MEMBERS = new Set( - releaseNoticeRows({ - products: ["native", "wasix"], - components: ["postgresql", "icu", "openssl"], - }).map((row) => row.member), -); - -function manifest(relative) { - return Bun.TOML.parse(readFileSync(path.join(ROOT, relative), "utf8")); -} - -test("oliphaunt-wasix source SDK remains an MIT-only facade", () => { - assert.equal(manifest("Cargo.toml").workspace.package.license, "MIT"); - const source = manifest("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"); - assert.equal(source.package.license, "MIT"); -}); - -test("every WASIX payload Cargo template includes its exact legal profile", () => { - for (const [relative, profile] of CORE_TEMPLATES) { - const cargo = manifest(relative); - assert.equal( - cargo.package.license, - releaseProfilePackageLicense(profile).spdx, - `${relative} license`, - ); - assert.ok(Array.isArray(cargo.package.include), `${relative} must declare package.include`); - const includedNotices = cargo.package.include.filter((member) => ALL_NOTICE_MEMBERS.has(member)); - assert.deepEqual( - includedNotices.sort(), - releaseNoticeRows({ profile }).map((row) => row.member).sort(), - `${relative} notice include closure`, - ); - } -}); diff --git a/tools/release/wasix-cargo-license-contract.test.mts b/tools/release/wasix-cargo-license-contract.test.mts new file mode 100644 index 000000000..3aa2472f8 --- /dev/null +++ b/tools/release/wasix-cargo-license-contract.test.mts @@ -0,0 +1,62 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import test from 'node:test'; + +import { releaseNoticeRows, releaseProfilePackageLicense } from '../packaging/release-notices.mts'; + +const ROOT = path.resolve(import.meta.dirname, '../..'); + +const CORE_TEMPLATES = [ + ['src/runtimes/liboliphaunt-wasix/crates/assets/Cargo.toml', 'wasix-runtime'], + ['src/postgres-tools/wasix/crates/tools/Cargo.toml', 'wasix-tools'], + ['src/database-resources/icu/cargo/Cargo.toml', 'wasix-icu-data-crate'], + ...[ + 'aarch64-apple-darwin', + 'aarch64-unknown-linux-gnu', + 'x86_64-pc-windows-msvc', + 'x86_64-unknown-linux-gnu', + ].flatMap((target) => [ + [`src/runtimes/liboliphaunt-wasix/crates/aot/${target}/Cargo.toml`, 'wasix-aot'], + [`src/postgres-tools/wasix/crates/aot/${target}/Cargo.toml`, 'wasix-aot'], + ]), +]; + +const ALL_NOTICE_MEMBERS = new Set( + releaseNoticeRows({ + products: ['native', 'wasix'], + components: ['postgresql', 'icu', 'openssl'], + }).map((row) => row.member), +); + +function manifest(relative) { + return Bun.TOML.parse(readFileSync(path.join(ROOT, relative), 'utf8')); +} + +test('oliphaunt-wasix source SDK remains an MIT-only facade', () => { + assert.equal(manifest('Cargo.toml').workspace.package.license, 'MIT'); + const source = manifest('src/sdks/rust-wasix/Cargo.toml'); + assert.equal(source.package.license, 'MIT'); +}); + +test('every WASIX payload Cargo template includes its exact legal profile', () => { + for (const [relative, profile] of CORE_TEMPLATES) { + const cargo = manifest(relative); + assert.equal( + cargo.package.license, + releaseProfilePackageLicense(profile).spdx, + `${relative} license`, + ); + assert.ok(Array.isArray(cargo.package.include), `${relative} must declare package.include`); + const includedNotices = cargo.package.include.filter((member) => + ALL_NOTICE_MEMBERS.has(member), + ); + assert.deepEqual( + includedNotices.sort(), + releaseNoticeRows({ profile }) + .map((row) => row.member) + .sort(), + `${relative} notice include closure`, + ); + } +}); diff --git a/tools/release/wasix-cargo-toolchain-policy.mjs b/tools/release/wasix-cargo-toolchain-policy.mjs deleted file mode 100644 index e37f6cce1..000000000 --- a/tools/release/wasix-cargo-toolchain-policy.mjs +++ /dev/null @@ -1,225 +0,0 @@ -import { readFileSync } from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const CRATES_IO_SOURCE = "registry+https://github.com/rust-lang/crates.io-index"; -const CARGO_DEPENDENCY_SOURCE_KEYS = Object.freeze([ - "branch", - "git", - "path", - "registry", - "rev", - "tag", - "workspace", -]); - -export const WASIX_TOOLCHAIN_PATH = "src/sources/toolchains/wasix.toml"; - -const REQUIRED_WASIX_TOOLCHAIN_PACKAGES = new Map([ - ["wasmer", "wasmer"], - ["wasmer-compiler", "wasmer"], - ["wasmer-derive", "wasmer"], - ["wasmer-types", "wasmer"], - ["wasmer-vm", "wasmer"], - ["wasmer-config", "wasmerWasix"], - ["wasmer-journal", "wasmerWasix"], - ["wasmer-package", "wasmerWasix"], - ["wasmer-wasix", "wasmerWasix"], - ["wasmer-wasix-types", "wasmerWasix"], - ["virtual-fs", "wasmerWasix"], - ["virtual-mio", "wasmerWasix"], - ["virtual-net", "wasmerWasix"], - ["webc", "webc"], -]); - -const REQUIRED_CONSUMER_PIN_POLICIES = new Map( - [...REQUIRED_WASIX_TOOLCHAIN_PACKAGES] - .filter(([, versionKey]) => versionKey === "wasmerWasix") - .map(([name, versionKey]) => [ - name, - Object.freeze({ versionKey, defaultFeaturesDisabled: true }), - ]), -); -REQUIRED_CONSUMER_PIN_POLICIES.set( - "webc", - Object.freeze({ versionKey: "webc", defaultFeaturesDisabled: false }), -); - -export const REQUIRED_WASIX_CONSUMER_PINS = Object.freeze( - [...REQUIRED_CONSUMER_PIN_POLICIES.keys()], -); - -function objectTable(value) { - return value !== null && typeof value === "object" && !Array.isArray(value) - ? value - : {}; -} - -function requiredString(value, context) { - if (typeof value !== "string" || value.length === 0) { - throw new Error(`${context} must be a non-empty string`); - } - return value; -} - -export function canonicalWasixCargoToolchainVersions(root = ROOT) { - const file = path.join(root, WASIX_TOOLCHAIN_PATH); - let data; - try { - data = Bun.TOML.parse(readFileSync(file, "utf8")); - } catch (cause) { - throw new Error(`${WASIX_TOOLCHAIN_PATH} cannot be read as TOML: ${cause.message}`); - } - const toolchain = objectTable(data.toolchain); - return Object.freeze({ - wasmer: requiredString( - toolchain.wasmer, - `${WASIX_TOOLCHAIN_PATH} toolchain.wasmer`, - ), - wasmerWasix: requiredString( - toolchain["wasmer-wasix"], - `${WASIX_TOOLCHAIN_PATH} toolchain.wasmer-wasix`, - ), - webc: requiredString( - toolchain.webc, - `${WASIX_TOOLCHAIN_PATH} toolchain.webc`, - ), - }); -} - -function dependencyVersion(spec) { - if (typeof spec === "string") return spec; - return typeof spec?.version === "string" ? spec.version : null; -} - -function dependencyName(key, spec) { - return typeof spec?.package === "string" ? spec.package : key; -} - -export function validateWasixConsumerDependencyPins( - manifest, - { - manifestPath = "src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml", - toolchainVersions, - } = {}, -) { - const failures = []; - const dependencies = objectTable(manifest?.dependencies); - for (const [name, policy] of REQUIRED_CONSUMER_PIN_POLICIES) { - const expectedVersion = toolchainVersions?.[policy.versionKey]; - if (typeof expectedVersion !== "string" || expectedVersion.length === 0) { - failures.push( - `${manifestPath}: missing canonical ${policy.versionKey} toolchain version for ${name}`, - ); - continue; - } - const matches = Object.entries(dependencies) - .filter(([key, spec]) => dependencyName(key, spec) === name); - if (matches.length !== 1) { - failures.push( - `${manifestPath} must declare non-optional ${name} exactly once, found ${matches.length}`, - ); - continue; - } - const [[key, spec]] = matches; - const actualVersion = dependencyVersion(spec); - if (actualVersion !== `=${expectedVersion}`) { - failures.push( - `${manifestPath} dependencies.${key} must pin ${name} exactly to =${expectedVersion}, got ${JSON.stringify(actualVersion)}`, - ); - } - if (typeof spec === "object" && spec !== null && spec.optional === true) { - failures.push(`${manifestPath} dependencies.${key} must keep ${name} non-optional`); - } - if ( - policy.defaultFeaturesDisabled - && ( - typeof spec !== "object" - || spec === null - || spec["default-features"] !== false - ) - ) { - failures.push( - `${manifestPath} dependencies.${key} must set default-features = false for ${name}`, - ); - } - if (typeof spec === "object" && spec !== null) { - const sourceKeys = CARGO_DEPENDENCY_SOURCE_KEYS.filter((sourceKey) => - Object.hasOwn(spec, sourceKey) - ); - if (sourceKeys.length > 0) { - failures.push( - `${manifestPath} dependencies.${key} must resolve ${name} from crates.io without source selectors, found ${sourceKeys.join(", ")}`, - ); - } - } - } - return failures; -} - -function optionalWasixToolchainVersionKey(name) { - if (name.startsWith("wasmer-compiler-")) return "wasmer"; - if (name.startsWith("wasmer-wasix-")) return "wasmerWasix"; - return null; -} - -export function isWasixToolchainPackageName(name) { - return ( - name === "webc" - || name === "wasmer" - || name.startsWith("wasmer-") - || name.startsWith("virtual-") - ); -} - -export function validateResolvedWasixToolchainPolicy( - lockfile, - packages, - { toolchainVersions } = {}, -) { - const failures = []; - const byName = new Map(); - for (const pkg of packages) { - const rows = byName.get(pkg.name) ?? []; - rows.push(pkg); - byName.set(pkg.name, rows); - } - for (const [name, versionKey] of REQUIRED_WASIX_TOOLCHAIN_PACKAGES) { - const entries = byName.get(name) ?? []; - const expected = toolchainVersions?.[versionKey]; - if (entries.length !== 1) { - failures.push(`${lockfile}: expected exactly one resolved ${name} package, found ${entries.length}`); - continue; - } - if (entries[0].source !== CRATES_IO_SOURCE) { - failures.push(`${lockfile}: ${name} must resolve from crates.io, got ${entries[0].source ?? "path"}`); - } - if (entries[0].version !== expected) { - failures.push(`${lockfile}: ${name} resolved ${entries[0].version}; expected ${expected}`); - } - } - for (const pkg of packages) { - if (REQUIRED_WASIX_TOOLCHAIN_PACKAGES.has(pkg.name)) continue; - if (!isWasixToolchainPackageName(pkg.name)) continue; - const versionKey = optionalWasixToolchainVersionKey(pkg.name); - if ( - (pkg.name === "wasmer" || pkg.name.startsWith("wasmer-")) - && pkg.source !== CRATES_IO_SOURCE - ) { - failures.push( - `${lockfile}: ${pkg.name} must resolve from crates.io, got ${pkg.source ?? "path"}`, - ); - } - if (versionKey !== null && pkg.version !== toolchainVersions?.[versionKey]) { - failures.push( - `${lockfile}: ${pkg.name} resolved ${pkg.version}; expected ${toolchainVersions?.[versionKey]}`, - ); - } else if (versionKey === null) { - failures.push( - `${lockfile}: unexpected non-canonical WASIX toolchain package ${pkg.name}@${pkg.version}`, - ); - } - } - return failures; -} diff --git a/tools/release/wasix-extension-cargo-artifact-inventory.mjs b/tools/release/wasix-extension-cargo-artifact-inventory.mjs deleted file mode 100644 index 9a81a6832..000000000 --- a/tools/release/wasix-extension-cargo-artifact-inventory.mjs +++ /dev/null @@ -1,178 +0,0 @@ -import { - exactExtensionProducts, - extensionReleaseProduct, -} from "./release-artifact-targets.mjs"; -import { - declaredCarrierMap, - loadPublicationCatalog, - resolveActualCarrier, -} from "./publication-catalog.mjs"; -import { - expectedExtensionAotTargets, - wasixExtensionAotPackageName, - wasixExtensionPackageName, -} from "./wasix-cargo-artifact-contract.mjs"; - -const PORTABLE_KIND = "wasix-extension"; -const AOT_KIND = "wasix-extension-aot"; -const EXTENSION_KINDS = new Set([PORTABLE_KIND, AOT_KIND]); -const ROLE_KINDS = new Map([ - ["portable-leaf", PORTABLE_KIND], - ["aot-leaf", AOT_KIND], -]); - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -export function expectedWasixExtensionPackageInventory( - tool = "wasix-extension-cargo-artifact-inventory.mjs", - products = exactExtensionProducts(tool), -) { - const selectedProducts = [...new Set(products)].sort(compareText); - const releaseProducts = [...new Set( - selectedProducts.map((product) => extensionReleaseProduct(product, "wasix", tool)), - )].sort(compareText); - const catalog = loadPublicationCatalog(tool, { products: releaseProducts }); - const expectedPackageKinds = new Map(); - const portableProducts = new Set(); - const carrierProducts = new Map(); - for (const product of selectedProducts) { - carrierProducts.set(wasixExtensionPackageName(product), { kind: PORTABLE_KIND, product }); - for (const target of expectedExtensionAotTargets()) { - carrierProducts.set(wasixExtensionAotPackageName(product, target), { kind: AOT_KIND, product }); - } - } - for (const carrier of catalog.carriers) { - if (carrier.ecosystem !== "cargo") { - continue; - } - const expected = carrierProducts.get(carrier.name); - if (expected === undefined || ROLE_KINDS.get(carrier.role) !== expected.kind) { - continue; - } - expectedPackageKinds.set(carrier.name, expected.kind); - if (carrier.role === "portable-leaf") { - portableProducts.add(expected.product); - } - } - const missingPortable = selectedProducts.filter((product) => !portableProducts.has(product)); - if (missingPortable.length > 0) { - throw new Error( - `public Cargo inventory is missing WASIX portable carriers for: ${missingPortable.join(", ")}`, - ); - } - return { - catalog, - declaredCarriers: declaredCarrierMap(catalog), - expectedPackageKinds, - products: selectedProducts, - }; -} - -export function expectedWasixExtensionPackageKinds( - tool = "wasix-extension-cargo-artifact-inventory.mjs", - products = exactExtensionProducts(tool), -) { - return expectedWasixExtensionPackageInventory(tool, products).expectedPackageKinds; -} - -function expectedCarrier(inventory, name, prefix) { - const carrier = resolveActualCarrier(inventory.catalog, "cargo", name, prefix); - const base = carrier.role === "payload-part" - ? inventory.declaredCarriers.get(carrier.parentCarrier) - : carrier; - const kind = base === undefined ? undefined : inventory.expectedPackageKinds.get(base.name); - if (kind === undefined) { - return null; - } - return { base, carrier, kind }; -} - -export function isExpectedWasixExtensionPackage(name, kind, inventory) { - try { - return expectedCarrier(inventory, name, "WASIX extension Cargo inventory")?.kind === kind; - } catch { - return false; - } -} - -export function validateWasixExtensionArtifactInventory( - packages, - inventory, -) { - const generatedBases = new Set(); - const partsByParent = new Map(); - const seenNames = new Set(); - for (const item of packages) { - if (item === null || Array.isArray(item) || typeof item !== "object") { - throw new Error("WASIX Cargo artifact package entries must be objects"); - } - const { name, kind } = item; - if (typeof name !== "string" || name.length === 0 || typeof kind !== "string") { - throw new Error(`WASIX Cargo artifact package entry has an invalid name/kind: ${JSON.stringify(item)}`); - } - if (seenNames.has(name)) { - throw new Error(`duplicate WASIX Cargo artifact package ${name}`); - } - seenNames.add(name); - - let expected; - try { - expected = expectedCarrier( - inventory, - name, - "WASIX extension Cargo artifact inventory", - ); - } catch (error) { - if (EXTENSION_KINDS.has(kind)) { - throw error; - } - continue; - } - if (expected === null) { - if (EXTENSION_KINDS.has(kind)) { - throw new Error(`unexpected WASIX extension Cargo artifact package ${name}`); - } - continue; - } - if (kind !== expected.kind) { - throw new Error( - `WASIX extension Cargo artifact package ${name} has kind ${kind}; expected ${expected.kind}`, - ); - } - if (expected.carrier.role === "payload-part") { - const parts = partsByParent.get(expected.carrier.parentCarrier) ?? []; - parts.push(expected.carrier.part); - partsByParent.set(expected.carrier.parentCarrier, parts); - } else { - generatedBases.add(expected.carrier.name); - } - } - - const missing = [...inventory.expectedPackageKinds.keys()] - .filter((name) => !generatedBases.has(name)) - .sort(compareText); - if (missing.length > 0) { - throw new Error( - `generated liboliphaunt-wasix Cargo artifacts are missing configured extension base crates: ${missing.join(", ")}`, - ); - } - - for (const [parent, numbers] of [...partsByParent].sort(([left], [right]) => compareText(left, right))) { - const parentName = parent.slice("cargo:".length); - if (!generatedBases.has(parentName)) { - throw new Error(`WASIX extension Cargo payload parts require their declared parent ${parent}`); - } - const actual = [...numbers].sort((left, right) => left - right); - const expected = Array.from({ length: actual.length }, (_, index) => index + 1); - if ( - actual.length !== expected.length - || actual.some((part, index) => part !== expected[index]) - ) { - throw new Error( - `${parent} Cargo payload parts must be contiguous from part-001; found ${actual.map((part) => String(part).padStart(3, "0")).join(", ")}`, - ); - } - } -} diff --git a/tools/release/wasix-extension-features.mjs b/tools/release/wasix-extension-features.mjs deleted file mode 100755 index 21575f831..000000000 --- a/tools/release/wasix-extension-features.mjs +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env bun - -import { readFileSync } from "node:fs"; - -const TOOL = "wasix-extension-features.mjs"; -const DEFAULT_MANIFEST = "target/oliphaunt-wasix/assets/manifest.json"; -const SQL_NAME_RE = /^[a-z0-9][a-z0-9_-]*$/u; - -function invariant(condition, message) { - if (!condition) throw new Error(`${TOOL}: ${message}`); -} - -export function extensionFeatures(manifest) { - invariant(manifest !== null && typeof manifest === "object" && !Array.isArray(manifest), "asset manifest must be an object"); - invariant(Array.isArray(manifest.extensions), "asset manifest must contain an extensions array"); - - const features = []; - const sqlNames = new Set(); - for (const extension of manifest.extensions) { - invariant(extension !== null && typeof extension === "object" && !Array.isArray(extension), "extension manifest rows must be objects"); - const sqlName = extension["sql-name"]; - invariant(typeof sqlName === "string" && SQL_NAME_RE.test(sqlName), "extensions must have a portable sql-name"); - invariant(!sqlNames.has(sqlName), `asset manifest repeats extension ${sqlName}`); - sqlNames.add(sqlName); - features.push(`extension-${sqlName.replaceAll("_", "-")}`); - } - - invariant(features.length > 0, "full WASIX evidence requires at least one extension"); - return features.sort(); -} - -export function fullEvidenceFeatures(manifest) { - return ["extensions", "tools", ...extensionFeatures(manifest)].join(","); -} - -function main(argv) { - if (argv.length > 1 || argv[0] === "--help" || argv[0] === "-h") { - console.log(`usage: ${TOOL} [ASSET_MANIFEST]`); - return; - } - const file = argv[0] ?? DEFAULT_MANIFEST; - const manifest = JSON.parse(readFileSync(file, "utf8")); - console.log(fullEvidenceFeatures(manifest)); -} - -if (import.meta.main) { - try { - main(Bun.argv.slice(2)); - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(1); - } -} diff --git a/tools/release/wasix-extension-features.test.mjs b/tools/release/wasix-extension-features.test.mjs deleted file mode 100644 index dc6f9265f..000000000 --- a/tools/release/wasix-extension-features.test.mjs +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bun - -import assert from "node:assert/strict"; -import { readFileSync } from "node:fs"; -import path from "node:path"; -import test from "node:test"; - -import { - extensionFeatures, - fullEvidenceFeatures, -} from "./wasix-extension-features.mjs"; - -const ROOT = path.resolve(import.meta.dirname, "../.."); - -test("the live WASIX public surface includes the PostGIS product", () => { - const manifest = JSON.parse(readFileSync( - path.join(ROOT, "src/extensions/generated/wasix/extensions.json"), - "utf8", - )); - assert.equal(manifest.extensions.some((row) => row["sql-name"] === "postgis"), true); - - for (const relative of [ - "src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml", - "src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml", - ]) { - const cargo = Bun.TOML.parse(readFileSync(path.join(ROOT, relative), "utf8")); - assert.equal(Object.hasOwn(cargo.features ?? {}, "extension-postgis"), true, relative); - } -}); - -test("full WASIX evidence enables every extension feature", () => { - const manifest = { - extensions: [ - { "sql-name": "vector" }, - { "sql-name": "pg_trgm" }, - ], - }; - - assert.deepEqual(extensionFeatures(manifest), ["extension-pg-trgm", "extension-vector"]); - assert.equal( - fullEvidenceFeatures(manifest), - "extensions,tools,extension-pg-trgm,extension-vector", - ); -}); - -test("full WASIX evidence rejects empty or ambiguous extension identities", () => { - assert.throws( - () => extensionFeatures({ extensions: [] }), - /at least one extension/u, - ); - assert.throws( - () => extensionFeatures({ - extensions: [ - { "sql-name": "vector" }, - { "sql-name": "vector" }, - ], - }), - /repeats extension vector/u, - ); - assert.throws( - () => extensionFeatures({ - extensions: [{ "sql-name": "bad/name" }], - }), - /portable sql-name/u, - ); -}); diff --git a/tools/release/wasix-icu-npm-carrier.mjs b/tools/release/wasix-icu-npm-carrier.mjs deleted file mode 100644 index 2a94eb96c..000000000 --- a/tools/release/wasix-icu-npm-carrier.mjs +++ /dev/null @@ -1,249 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { - chmodSync, - mkdirSync, - mkdtempSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { zstdCompressSync } from "node:zlib"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { validateNpmTrustedPublishingManifest } from "./npm-trusted-publishing.mjs"; -import { readPortableArchiveEntries } from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releaseNoticeRows, - releaseProfilePackageLicense, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { - WASIX_PORTABLE_RELEASE_MEMBERS, - WASIX_RUNTIME_NPM_PACKAGE, - WASIX_RUNTIME_PRODUCT, -} from "./wasix-runtime-npm-contract.mjs"; -import { - WASIX_ICU_DATA_ARCHIVE_PATH, - WASIX_ICU_DESCRIPTOR_SCHEMA, - WASIX_ICU_NPM_ASSET_PATHS, - WASIX_ICU_NPM_PACKAGE, - WASIX_ICU_PRODUCT, -} from "./wasix-icu-npm-contract.mjs"; - -const TOOL = "wasix-icu-npm-carrier.mjs"; -const ROOT = path.resolve(import.meta.dirname, "../.."); -const LOWER_SHA256 = /^[0-9a-f]{64}$/u; -const NOTICE_OPTIONS = Object.freeze({ profile: "wasix-icu-data" }); -const ICU_RELEASE_PREFIX = "target/oliphaunt-wasix/icu/share/icu/"; - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function sha256(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function requireEntry(entries, member, label) { - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${label} must contain ${member} as a non-empty regular file`); - } - return Buffer.from(entry.data()); -} - -function parseJson(bytes, label) { - try { - const value = JSON.parse(bytes.toString("utf8")); - if (value === null || Array.isArray(value) || typeof value !== "object") fail(`${label} must be an object`); - return value; - } catch (error) { - fail(`${label} is not valid UTF-8 JSON: ${error.message}`); - } -} - -function checkedDigest(value, label) { - if (typeof value !== "string" || !LOWER_SHA256.test(value)) fail(`${label} is not a lowercase SHA-256 digest`); - return value; -} - -function logicalTreeDigest(rows) { - const digest = createHash("sha256"); - for (const row of [...rows].sort((left, right) => Buffer.compare(Buffer.from(left.path), Buffer.from(right.path)))) { - digest.update(row.path); - digest.update(Buffer.of(0)); - digest.update(String(row.bytes.length)); - digest.update(Buffer.of(0)); - digest.update(row.bytes); - digest.update("\n"); - } - return digest.digest("hex"); -} - -function canonicalIcuArchive(icuReleaseArchive) { - const entries = readPortableArchiveEntries(path.resolve(icuReleaseArchive)); - const rows = []; - for (const [member, entry] of entries) { - if (!member.startsWith(ICU_RELEASE_PREFIX) || !entry.isFile) continue; - if (entry.isSymbolicLink) fail(`ICU release data must not contain links: ${member}`); - rows.push({ path: member.slice(ICU_RELEASE_PREFIX.length), bytes: Buffer.from(entry.data()) }); - } - if (rows.length === 0 || !rows.some(({ path }) => path.split("/")[0]?.startsWith("icudt"))) { - fail("ICU release asset has no icudt files-data tree"); - } - const scratch = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-wasix-icu-npm-")); - try { - const stage = path.join(scratch, "stage"); - for (const row of rows) { - const output = path.join(stage, "share/icu", ...row.path.split("/")); - mkdirSync(path.dirname(output), { recursive: true }); - writeFileSync(output, row.bytes, { mode: 0o644 }); - } - const tar = createDeterministicTar(stage, ".", { fail, fixedFileMode: 0o644 }); - return Object.freeze({ bytes: zstdCompressSync(tar), dataTreeSha256: logicalTreeDigest(rows) }); - } finally { - rmSync(scratch, { recursive: true, force: true }); - } -} - -export function wasixIcuNpmInputs({ version, portableReleaseArchive, icuDataReleaseArchive }) { - const runtimeEntries = readPortableArchiveEntries(path.resolve(portableReleaseArchive)); - const manifest = parseJson( - requireEntry(runtimeEntries, WASIX_PORTABLE_RELEASE_MEMBERS.manifest, "WASIX runtime release"), - "WASIX runtime manifest", - ); - const seedArchiveBytes = requireEntry( - runtimeEntries, - WASIX_PORTABLE_RELEASE_MEMBERS.icuSeedArchive, - "WASIX runtime release", - ); - const seedManifestBytes = requireEntry( - runtimeEntries, - WASIX_PORTABLE_RELEASE_MEMBERS.icuSeedManifest, - "WASIX runtime release", - ); - const seed = parseJson(seedManifestBytes, "WASIX ICU cluster seed manifest"); - const outer = manifest["cluster-seeds"]?.icu; - const data = canonicalIcuArchive(icuDataReleaseArchive); - if ( - manifest["format-version"] !== 2 - || seed.schema !== "oliphaunt-cluster-seed-v1" - || seed.catalogProfile !== "icu" - || seed.artifactRole !== "cluster-seed-icu" - || seed.runtime?.product !== WASIX_RUNTIME_PRODUCT - || seed.runtime?.version !== version - || seed.runtime?.physicalFormat !== "wasix-pg18-v1" - || seed.runtime?.compatibilityKey !== "wasix-pg18-datum32-v1" - || seed.icu?.artifactRole !== "icu-data" - || seed.icu?.dataVersion !== "76.1" - || seed.icu?.dataForm !== "files-le" - || seed.icu?.dataTreeSha256 !== data.dataTreeSha256 - || outer?.sha256 !== sha256(seedArchiveBytes) - || outer?.size !== seedArchiveBytes.length - || outer?.["icu-data-tree-sha256"] !== data.dataTreeSha256 - ) { - fail("ICU data, ICU cluster seed, and WASIX runtime do not form one compatible closure"); - } - checkedDigest(seed.icu.dataTreeSha256, "ICU logical data tree"); - return Object.freeze({ - compatibility: Object.freeze({ - runtimeProduct: WASIX_RUNTIME_PRODUCT, - runtimeVersion: version, - postgresMajor: "18", - physicalFormat: "wasix-pg18-v1", - compatibilityKey: "wasix-pg18-datum32-v1", - dataVersion: "76.1", - dataForm: "files-le", - dataTreeSha256: data.dataTreeSha256, - }), - dataArchive: Object.freeze({ archive: WASIX_ICU_DATA_ARCHIVE_PATH, bytes: data.bytes, sha256: sha256(data.bytes), size: data.bytes.length }), - clusterSeedArchive: Object.freeze({ archive: outer.archive, bytes: seedArchiveBytes, sha256: outer.sha256, size: outer.size }), - clusterSeedManifest: Object.freeze({ bytes: seedManifestBytes, sha256: sha256(seedManifestBytes), size: seedManifestBytes.length }), - }); -} - -function asset(value, sourcePath, includeArchive) { - return Object.freeze({ - ...(includeArchive ? { archive: value.archive } : {}), - sha256: value.sha256, - size: value.size, - source: new URL(`./${sourcePath}`, import.meta.url), - }); -} - -function renderDescriptor({ version, inputs }) { - const literal = JSON.stringify({ - schema: WASIX_ICU_DESCRIPTOR_SCHEMA, - runtime: "wasix", - product: WASIX_ICU_PRODUCT, - version, - compatibility: inputs.compatibility, - dataArchive: { archive: inputs.dataArchive.archive, sha256: inputs.dataArchive.sha256, size: inputs.dataArchive.size }, - clusterSeedArchive: { archive: inputs.clusterSeedArchive.archive, sha256: inputs.clusterSeedArchive.sha256, size: inputs.clusterSeedArchive.size }, - clusterSeedManifest: { sha256: inputs.clusterSeedManifest.sha256, size: inputs.clusterSeedManifest.size }, - }, null, 2); - return `const descriptor = ${literal};\nconst paths = ${JSON.stringify(WASIX_ICU_NPM_ASSET_PATHS)};\nfor (const name of ["dataArchive", "clusterSeedArchive", "clusterSeedManifest"]) {\n descriptor[name].source = new URL(\`./\${paths[name]}\`, import.meta.url);\n Object.freeze(descriptor[name]);\n}\nObject.freeze(descriptor.compatibility);\nObject.freeze(descriptor);\nexport { descriptor };\nexport default descriptor;\n`; -} - -function descriptorTypes() { - return `export type OliphauntWasixIcuDescriptor = Readonly<{\n schema: "${WASIX_ICU_DESCRIPTOR_SCHEMA}"; runtime: "wasix"; product: "${WASIX_ICU_PRODUCT}"; version: string;\n compatibility: Readonly<{ runtimeProduct: "${WASIX_RUNTIME_PRODUCT}"; runtimeVersion: string; postgresMajor: "18"; physicalFormat: "wasix-pg18-v1"; compatibilityKey: "wasix-pg18-datum32-v1"; dataVersion: "76.1"; dataForm: "files-le"; dataTreeSha256: string }>;\n dataArchive: Readonly<{ archive: string; sha256: string; size: number; source: URL }>;\n clusterSeedArchive: Readonly<{ archive: string; sha256: string; size: number; source: URL }>;\n clusterSeedManifest: Readonly<{ sha256: string; size: number; source: URL }>;\n}>;\ndeclare const descriptor: OliphauntWasixIcuDescriptor;\nexport { descriptor };\nexport default descriptor;\n`; -} - -export function stageWasixIcuNpmCarrier({ version, portableReleaseArchive, icuDataReleaseArchive, packageDir }) { - const output = path.resolve(packageDir); - const inputs = wasixIcuNpmInputs({ version, portableReleaseArchive, icuDataReleaseArchive }); - rmSync(output, { recursive: true, force: true }); - mkdirSync(path.join(output, "assets"), { recursive: true }); - for (const name of ["dataArchive", "clusterSeedArchive", "clusterSeedManifest"]) { - const destination = path.join(output, ...WASIX_ICU_NPM_ASSET_PATHS[name].split("/")); - writeFileSync(destination, inputs[name].bytes, { mode: 0o644 }); - chmodSync(destination, 0o644); - } - writeFileSync(path.join(output, "index.js"), renderDescriptor({ version, inputs }), { mode: 0o644 }); - writeFileSync(path.join(output, "index.d.ts"), descriptorTypes(), { mode: 0o644 }); - writeFileSync(path.join(output, "README.md"), `# ${WASIX_ICU_NPM_PACKAGE}\n\nOptional ICU data and matching ICU catalog cluster seed for ${WASIX_RUNTIME_NPM_PACKAGE}.\n\n\`import icu from '${WASIX_ICU_NPM_PACKAGE}'\` and pass \`{ icu }\` to \`Oliphaunt.open\`.\n`, { mode: 0o644 }); - stageReleaseNotices(output, NOTICE_OPTIONS); - const packageJson = { - name: WASIX_ICU_NPM_PACKAGE, - version, - description: "Optional ICU data and matching cluster seed for Oliphaunt WASIX.", - license: releaseProfilePackageLicense("wasix-icu-data").spdx, - type: "module", - sideEffects: false, - repository: { type: "git", url: "git+https://github.com/f0rr0/oliphaunt.git" }, - oliphaunt: { product: WASIX_ICU_PRODUCT, kind: "icu-data", runtime: "wasix", descriptorSchema: WASIX_ICU_DESCRIPTOR_SCHEMA }, - publishConfig: { access: "public", provenance: true }, - files: ["README.md", "index.js", "index.d.ts", "assets", ...releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => member)], - exports: { ".": { types: "./index.d.ts", import: "./index.js", default: "./index.js" }, "./package.json": "./package.json" }, - }; - validateNpmTrustedPublishingManifest(packageJson, `${WASIX_ICU_NPM_PACKAGE} generated package`); - writeFileSync(path.join(output, "package.json"), `${JSON.stringify(packageJson, null, 2)}\n`, { mode: 0o644 }); - assertReleaseNoticesInDirectory(output, NOTICE_OPTIONS); - return Object.freeze({ packageDir: output, packageName: WASIX_ICU_NPM_PACKAGE, descriptor: inputs }); -} - -export function packWasixIcuNpmCarrier({ - version, - portableReleaseArchive, - icuDataReleaseArchive, - packageDir = path.join(ROOT, "target/release/npm-package-sources/wasix-icu"), - tarballRoot = path.join(ROOT, "target/release/npm-packages/wasix-icu"), -}) { - const staged = stageWasixIcuNpmCarrier({ version, portableReleaseArchive, icuDataReleaseArchive, packageDir }); - rmSync(tarballRoot, { recursive: true, force: true }); - mkdirSync(tarballRoot, { recursive: true }); - const result = captureCommandOutput(process.platform === "win32" ? "pnpm.cmd" : "pnpm", ["pack", "--pack-destination", tarballRoot, "--json"], { cwd: staged.packageDir, label: `pnpm pack for ${WASIX_ICU_NPM_PACKAGE}`, maxOutputBytes: 32 * 1024 * 1024, shell: process.platform === "win32" }); - if (result.status !== 0) fail(`pnpm pack failed: ${String(result.stderr || result.stdout).trim()}`); - const packed = JSON.parse(result.stdout); - const filename = Array.isArray(packed) ? packed[0]?.filename : packed?.filename; - if (typeof filename !== "string") fail("pnpm pack did not report a filename"); - const tarball = path.isAbsolute(filename) ? filename : path.join(tarballRoot, filename); - assertReleaseNoticesInArchive(tarball, { ...NOTICE_OPTIONS, prefix: "package" }); - return Object.freeze({ ...staged, tarball }); -} diff --git a/tools/release/wasix-icu-npm-carrier.test.mjs b/tools/release/wasix-icu-npm-carrier.test.mjs deleted file mode 100644 index 4a494e29f..000000000 --- a/tools/release/wasix-icu-npm-carrier.test.mjs +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { zstdCompressSync } from "node:zlib"; -import { afterAll, expect, test } from "bun:test"; - -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { stageWasixIcuNpmCarrier } from "./wasix-icu-npm-carrier.mjs"; -import { WASIX_PORTABLE_RELEASE_MEMBERS } from "./wasix-runtime-npm-contract.mjs"; - -const roots = []; -afterAll(() => roots.forEach((root) => rmSync(root, { recursive: true, force: true }))); - -function digest(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function write(root, member, bytes) { - const file = path.join(root, ...member.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, bytes); -} - -function archive(root) { - return zstdCompressSync(createDeterministicTar(root, ".", { - fail(message) { throw new Error(message); }, - fixedFileMode: 0o644, - })); -} - -function fixture() { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-wasix-icu-carrier-")); - roots.push(root); - const dataPath = "icudt76l/coll/en.res"; - const dataBytes = Buffer.from("fixture ICU data\n"); - const tree = createHash("sha256") - .update(dataPath).update(Buffer.of(0)).update(String(dataBytes.length)).update(Buffer.of(0)) - .update(dataBytes).update("\n").digest("hex"); - const seedBytes = Buffer.from("seed\n"); - const moduleSha = "1".repeat(64); - const source = "fixture-source"; - const seedManifest = { - schema: "oliphaunt-cluster-seed-v1", - artifactRole: "cluster-seed-icu", - catalogProfile: "icu", - runtime: { - product: "liboliphaunt-wasix", version: "7.8.9", engineFamily: "wasix", - physicalFormat: "wasix-pg18-v1", postgresMajor: 18, - compatibilityKey: "wasix-pg18-datum32-v1", consumerSha256: moduleSha, - producerSha256: moduleSha, initdbSha256: "2".repeat(64), - }, - source: { fingerprint: source, catalogVersion: "1", lane: "stable", producer: "wasix-initdb" }, - initProfile: "fixture", archive: { path: "cluster-seeds/icu.tar.zst", sha256: digest(seedBytes), compressedBytes: seedBytes.length, expandedBytes: 1, regularFiles: 1, directories: 1 }, - requiredRuntimeFeatures: ["icu"], extensions: { selected: [], startupConfiguration: [] }, - icu: { artifactRole: "icu-data", upstreamVersion: "76.1", sourceCommit: "3".repeat(40), dataTreeSha256: tree, dataVersion: "76.1", dataForm: "files-le" }, - }; - const runtimeManifest = { - "format-version": 2, - "cluster-seeds": { icu: { archive: "cluster-seeds/icu.tar.zst", sha256: digest(seedBytes), size: seedBytes.length, "icu-data-tree-sha256": tree } }, - }; - const portableStage = path.join(root, "portable"); - write(portableStage, WASIX_PORTABLE_RELEASE_MEMBERS.manifest, `${JSON.stringify(runtimeManifest)}\n`); - write(portableStage, "target/oliphaunt-wasix/assets/cluster-seeds/icu.tar.zst", seedBytes); - write(portableStage, "target/oliphaunt-wasix/assets/cluster-seeds/icu.json", `${JSON.stringify(seedManifest)}\n`); - const portableReleaseArchive = path.join(root, "runtime.tar.zst"); - writeFileSync(portableReleaseArchive, archive(portableStage)); - - const icuStage = path.join(root, "icu"); - write(icuStage, `target/oliphaunt-wasix/icu/share/icu/${dataPath}`, dataBytes); - const icuDataReleaseArchive = path.join(root, "icu.tar.zst"); - writeFileSync(icuDataReleaseArchive, archive(icuStage)); - return { root, portableReleaseArchive, icuDataReleaseArchive, tree }; -} - -test("stages one exact ICU data and ICU cluster-seed closure", () => { - const value = fixture(); - const staged = stageWasixIcuNpmCarrier({ - version: "7.8.9", - portableReleaseArchive: value.portableReleaseArchive, - icuDataReleaseArchive: value.icuDataReleaseArchive, - packageDir: path.join(value.root, "package"), - }); - const packageJson = JSON.parse(readFileSync(path.join(staged.packageDir, "package.json"), "utf8")); - expect(packageJson.name).toBe("@oliphaunt/wasix-icu"); - expect(staged.descriptor.compatibility.dataTreeSha256).toBe(value.tree); - expect(readFileSync(path.join(staged.packageDir, "index.js"), "utf8")).toContain("oliphaunt-wasix-icu-v1"); - expect(readFileSync(path.join(staged.packageDir, "assets/cluster-seed-icu.tar.zst"))).toEqual(Buffer.from("seed\n")); -}); - -test("rejects ICU data that does not match the ICU seed catalog identity", () => { - const value = fixture(); - const wrong = path.join(value.root, "wrong-icu"); - write(wrong, "target/oliphaunt-wasix/icu/share/icu/icudt76l/coll/en.res", "wrong\n"); - writeFileSync(value.icuDataReleaseArchive, archive(wrong)); - expect(() => stageWasixIcuNpmCarrier({ - version: "7.8.9", - portableReleaseArchive: value.portableReleaseArchive, - icuDataReleaseArchive: value.icuDataReleaseArchive, - packageDir: path.join(value.root, "bad-package"), - })).toThrow(/no icudt files-data tree|compatible closure/u); -}); diff --git a/tools/release/wasix-icu-npm-contract.mjs b/tools/release/wasix-icu-npm-contract.mjs deleted file mode 100644 index 1b6ffe900..000000000 --- a/tools/release/wasix-icu-npm-contract.mjs +++ /dev/null @@ -1,10 +0,0 @@ -export const WASIX_ICU_NPM_PACKAGE = "@oliphaunt/wasix-icu"; -export const WASIX_ICU_DESCRIPTOR_SCHEMA = "oliphaunt-wasix-icu-v1"; -export const WASIX_ICU_PRODUCT = "oliphaunt-icu"; -export const WASIX_ICU_DATA_ARCHIVE_PATH = "icu-data/icu-data.tar.zst"; - -export const WASIX_ICU_NPM_ASSET_PATHS = Object.freeze({ - dataArchive: "assets/icu-data.tar.zst", - clusterSeedArchive: "assets/cluster-seed-icu.tar.zst", - clusterSeedManifest: "assets/cluster-seed-icu.json", -}); diff --git a/tools/release/wasix-napi-package-contract.test.mjs b/tools/release/wasix-napi-package-contract.test.mjs deleted file mode 100644 index dba8a2eb0..000000000 --- a/tools/release/wasix-napi-package-contract.test.mjs +++ /dev/null @@ -1,145 +0,0 @@ -import { createHash } from "node:crypto"; - -import { describe, expect, test } from "bun:test"; -import productManifest from "../../src/runtimes/wasix-napi/package.json" with { type: "json" }; - -import { - assertSingleWasixNapiAddonMember, - assertWasixNapiCarrierManifest, - assertWasixNapiPlatformEntries, -} from "./check-wasix-napi-release-assets.mjs"; -import { windowsPeFixture } from "../test/release-fixture-utils.mjs"; - -const target = Object.freeze({ - npmPackage: "@oliphaunt/wasix-napi-linux-x64-gnu", - target: "linux-x64-gnu", - npmOs: "linux", - npmCpu: "x64", - npmLibc: "glibc", -}); -function manifest() { - return { - name: target.npmPackage, - version: "1.2.3", - license: "MIT AND PostgreSQL AND Unicode-3.0 AND Apache-2.0", - type: "commonjs", - os: ["linux"], - cpu: ["x64"], - libc: ["glibc"], - optional: true, - oliphaunt: { - target: target.target, - runtimeProduct: "liboliphaunt-wasix", - runtimeVersion: productManifest.oliphaunt.runtimeVersion, - addonAbiVersion: 1, - nodeApiVersion: 8, - profiles: ["standard", "icu"], - }, - exports: { - "./oliphaunt_wasix_napi.node": "./prebuilds/oliphaunt_wasix_napi.node", - "./artifact-provenance.json": "./artifact-provenance.json", - "./package.json": "./package.json", - }, - files: [ - "prebuilds", - "artifact-provenance.json", - "README.md", - "LICENSE", - "THIRD_PARTY_NOTICES.md", - "THIRD_PARTY_NOTICES.oliphaunt-wasix.md", - "THIRD_PARTY_LICENSES", - ], - }; -} - -function archiveEntry(data) { - return { - data: () => data, - isFile: true, - isSymbolicLink: false, - size: data.length, - }; -} - -describe("WASIX Node-API carrier fail-closed package contract", () => { - test("accepts the one-binary, two-profile carrier", () => { - expect(() => assertWasixNapiCarrierManifest(manifest(), target, "1.2.3")) - .not.toThrow(); - }); - - test("rejects a wrong target, addon ABI, or profile inventory", () => { - for (const mutate of [ - (candidate) => { candidate.oliphaunt.target = "linux-arm64-gnu"; }, - (candidate) => { candidate.oliphaunt.addonAbiVersion = 2; }, - (candidate) => { candidate.oliphaunt.profiles = ["standard"]; }, - ]) { - const candidate = manifest(); - mutate(candidate); - expect(() => assertWasixNapiCarrierManifest(candidate, target, "1.2.3")) - .toThrow("target/runtime/ABI/profile metadata"); - } - }); - - test("rejects a second native binary export", () => { - const candidate = manifest(); - candidate.exports["./oliphaunt_wasix_napi_icu.node"] = - "./prebuilds/oliphaunt_wasix_napi_icu.node"; - expect(() => assertWasixNapiCarrierManifest(candidate, target, "1.2.3")) - .toThrow("exactly one stable addon binary"); - }); - - test("rejects a hidden second native binary archive member", () => { - const binary = "package/prebuilds/oliphaunt_wasix_napi.node"; - expect(() => assertSingleWasixNapiAddonMember(new Map([[binary, {}]]), binary)) - .not.toThrow(); - expect(() => assertSingleWasixNapiAddonMember(new Map([ - [binary, {}], - ["package/prebuilds/oliphaunt_wasix_napi_icu.node", {}], - ]), binary)).toThrow("exactly one native addon member"); - }); - - test("rejects incompatible npm platform, lifecycle, or file metadata", () => { - for (const mutate of [ - (candidate) => { candidate.cpu = ["arm64"]; }, - (candidate) => { candidate.libc = ["musl"]; }, - (candidate) => { candidate.scripts = { install: "node install.js" }; }, - (candidate) => { candidate.files.push("install.js"); }, - ]) { - const candidate = manifest(); - mutate(candidate); - expect(() => assertWasixNapiCarrierManifest(candidate, target, "1.2.3")) - .toThrow(); - } - }); - - test("requires the exact Windows VC runtime closure beside the npm addon", () => { - const binary = windowsPeFixture({ imports: ["VCRUNTIME140.dll"] }); - const runtime = windowsPeFixture(); - const digest = createHash("sha256").update(runtime).digest("hex"); - const entries = new Map([ - ["package/prebuilds/oliphaunt_wasix_napi.node", archiveEntry(binary)], - ["package/prebuilds/vcruntime140.dll", archiveEntry(runtime)], - [ - "package/prebuilds/windows-vc-runtime.sha256", - archiveEntry(Buffer.from(`${digest} vcruntime140.dll\n`)), - ], - ]); - const options = { - target: "windows-x64-msvc", - prefix: "package", - binaryDirectory: "prebuilds", - }; - expect(() => assertWasixNapiPlatformEntries(entries, options)).not.toThrow(); - - entries.delete("package/prebuilds/windows-vc-runtime.sha256"); - expect(() => assertWasixNapiPlatformEntries(entries, options)).toThrow(/VC runtime receipt/u); - - entries.set( - "package/prebuilds/windows-vc-runtime.sha256", - archiveEntry(Buffer.from(`${digest} vcruntime140.dll\n`)), - ); - entries.set("package/vcruntime140.dll", entries.get("package/prebuilds/vcruntime140.dll")); - entries.delete("package/prebuilds/vcruntime140.dll"); - expect(() => assertWasixNapiPlatformEntries(entries, options)).toThrow(/beside/u); - }); -}); diff --git a/tools/release/wasix-runtime-npm-carrier.mjs b/tools/release/wasix-runtime-npm-carrier.mjs deleted file mode 100644 index 4822038c2..000000000 --- a/tools/release/wasix-runtime-npm-carrier.mjs +++ /dev/null @@ -1,602 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { - chmodSync, - lstatSync, - mkdirSync, - rmSync, - statSync, - writeFileSync, -} from "node:fs"; -import { isDeepStrictEqual } from "node:util"; -import path from "node:path"; - -import { captureCommandOutput } from "../dev/capture-command-output.mjs"; -import { validatePortableReleaseAsset } from "./check-liboliphaunt-wasix-release-assets.mjs"; -import { - NPM_TRUSTED_PUBLISHING_REPOSITORY, - validateNpmTrustedPublishingManifest, -} from "./npm-trusted-publishing.mjs"; -import { - readPortableArchiveEntries, - readPortableTarZstdBufferEntries, -} from "../../src/shared/artifact-packaging/portable-archive.mjs"; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releaseNoticeRows, - releaseProfilePackageLicense, - stageReleaseNotices, -} from "./release-notices.mjs"; -import { - WASIX_STANDARD_SEED_ARCHIVE_PATH, - WASIX_STANDARD_SEED_MANIFEST_PATH, - WASIX_PORTABLE_RELEASE_MEMBERS, - WASIX_RUNTIME_ARCHIVE_PATH, - WASIX_RUNTIME_NPM_ASSET_PATHS, - WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA, - WASIX_RUNTIME_NPM_PACKAGE, - WASIX_RUNTIME_NPM_TARGET, - WASIX_RUNTIME_PRODUCT, -} from "./wasix-runtime-npm-contract.mjs"; -import { - renderWasixRuntimeDescriptorModule, - renderWasixRuntimeDescriptorTypes, -} from "./wasix-runtime-npm-descriptor.mjs"; - -export { - renderWasixRuntimeDescriptorModule, - renderWasixRuntimeDescriptorTypes, -} from "./wasix-runtime-npm-descriptor.mjs"; - -const TOOL = "wasix-runtime-npm-carrier.mjs"; -const ROOT = path.resolve(import.meta.dirname, "../.."); -const LOWER_SHA256 = /^[0-9a-f]{64}$/u; -const SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/u; -const RUNTIME_MODULE_MEMBER = "oliphaunt/bin/postgres"; -const NPM_PACKAGE_SAFETY_LIMIT_BYTES = 100 * 1024 * 1024; -const MAX_COMMAND_CAPTURE_BYTES = 32 * 1024 * 1024; -const NOTICE_OPTIONS = Object.freeze({ profile: "wasix-runtime" }); - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function rel(file) { - const relative = path.relative(ROOT, file).split(path.sep).join("/"); - return relative && !relative.startsWith("../") ? relative : String(file); -} - -function sha256Bytes(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function regularFile(file, label) { - let metadata; - try { - metadata = lstatSync(file); - } catch (cause) { - fail(`${label} cannot be inspected: ${cause.message}`); - } - if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) { - fail(`${label} must be a non-empty regular non-symlink file: ${rel(file)}`); - } - return metadata; -} - -function parseJsonBytes(bytes, label) { - let value; - try { - value = JSON.parse(Buffer.from(bytes).toString("utf8")); - } catch (cause) { - fail(`${label} must contain UTF-8 JSON: ${cause.message}`); - } - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(`${label} must contain a JSON object`); - } - return value; -} - -function object(value, label) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(`${label} must be an object`); - } - return value; -} - -function nonEmptyString(value, label) { - if (typeof value !== "string" || value.length === 0 || value.includes("\0")) { - fail(`${label} must be a non-empty string without NUL bytes`); - } - return value; -} - -function checkedSha256(value, label) { - if (typeof value !== "string" || !LOWER_SHA256.test(value)) { - fail(`${label} must be a lowercase SHA-256 digest`); - } - return value; -} - -function safeRelativePath(value, label) { - const result = nonEmptyString(value, label); - const segments = result.split("/"); - if ( - result.startsWith("/") - || result.includes("\\") - || segments.some((segment) => segment.length === 0 || segment === "." || segment === "..") - ) { - fail(`${label} must be a canonical safe relative path`); - } - return result; -} - -function postgresMajor(value, label) { - return nonEmptyString(value, label).split(".")[0]; -} - -function requireRegularEntry(entries, member, label) { - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${label} must contain ${member} as one non-empty regular file`); - } - return entry; -} - -/** - * Validate the complete core-manifest projection consumed by WASIX hosts. - * Keep this producer-side gate in lockstep with the binding's parser so a - * package cannot be publishable but unusable by every consumer. - */ -function assertCoreManifestContract(manifest, runtimeEntries, standardSeedEntries, seedManifest) { - if (manifest["format-version"] !== 2) { - fail("frozen WASIX core manifest must use format-version 2"); - } - const sourceFingerprint = nonEmptyString( - manifest["source-fingerprint"], - "frozen WASIX core manifest source-fingerprint", - ); - const runtime = object(manifest.runtime, "frozen WASIX core manifest runtime"); - safeRelativePath(runtime.archive, "frozen WASIX core manifest runtime.archive"); - checkedSha256(runtime.sha256, "frozen WASIX core manifest runtime.sha256"); - if ( - runtime.size !== undefined - && (!Number.isSafeInteger(runtime.size) || runtime.size <= 0) - ) { - fail("frozen WASIX core manifest runtime.size must be a positive safe integer when present"); - } - const runtimeModuleSha256 = checkedSha256( - runtime["module-sha256"], - "frozen WASIX core manifest runtime.module-sha256", - ); - const runtimePostgresMajor = postgresMajor( - runtime["postgres-version"], - "frozen WASIX core manifest runtime.postgres-version", - ); - const link = object(runtime.link, "frozen WASIX core manifest runtime.link"); - if (!Array.isArray(link.exports)) { - fail("frozen WASIX core manifest runtime.link.exports must be an array"); - } - for (const [index, value] of link.exports.entries()) { - const entry = object(value, `frozen WASIX core manifest runtime.link.exports[${index}]`); - nonEmptyString(entry.name, `frozen WASIX core manifest runtime.link.exports[${index}].name`); - nonEmptyString(entry.kind, `frozen WASIX core manifest runtime.link.exports[${index}].kind`); - } - - if (!Array.isArray(manifest["runtime-support"])) { - fail("frozen WASIX core manifest runtime-support must be an array"); - } - const supportNames = new Set(); - const supportPaths = new Set(); - for (const [index, value] of manifest["runtime-support"].entries()) { - const entry = object(value, `frozen WASIX core manifest runtime-support[${index}]`); - const name = nonEmptyString( - entry.name, - `frozen WASIX core manifest runtime-support[${index}].name`, - ); - if (!SQL_NAME.test(name) || supportNames.has(name)) { - fail(`frozen WASIX core manifest runtime-support[${index}].name must be unique and portable`); - } - supportNames.add(name); - const supportPath = safeRelativePath( - entry.path, - `frozen WASIX core manifest runtime-support[${index}].path`, - ); - if (!supportPath.startsWith("lib/postgresql/") || supportPaths.has(supportPath)) { - fail(`frozen WASIX core manifest runtime-support[${index}].path must be unique under lib/postgresql/`); - } - supportPaths.add(supportPath); - checkedSha256( - entry.sha256, - `frozen WASIX core manifest runtime-support[${index}].sha256`, - ); - } - - const seeds = object(manifest["cluster-seeds"], "frozen WASIX core manifest cluster-seeds"); - if (Object.keys(seeds).sort().join(",") !== "icu,standard") { - fail("frozen WASIX core manifest must contain exactly standard and icu cluster seeds"); - } - const standardSeed = object(seeds.standard, "frozen WASIX standard cluster seed"); - if ( - standardSeed["artifact-role"] !== "cluster-seed-standard" - || standardSeed["catalog-profile"] !== "standard" - || standardSeed["physical-format"] !== "wasix-pg18-v1" - || standardSeed["compatibility-key"] !== "wasix-pg18-datum32-v1" - || standardSeed.manifest !== WASIX_STANDARD_SEED_MANIFEST_PATH - ) { - fail("frozen WASIX standard cluster seed has an incompatible identity"); - } - safeRelativePath(standardSeed.archive, "frozen WASIX standard cluster seed archive"); - checkedSha256(standardSeed.sha256, "frozen WASIX standard cluster seed archive SHA-256"); - if (!Number.isSafeInteger(standardSeed.size) || standardSeed.size <= 0) { - fail("frozen WASIX standard cluster seed size must be a positive safe integer"); - } - const standardSeedRuntimeModuleSha256 = checkedSha256( - standardSeed["runtime-module-sha256"], - "frozen WASIX standard cluster seed runtime-module-sha256", - ); - const standardSeedFingerprint = nonEmptyString( - standardSeed["source-fingerprint"], - "frozen WASIX standard cluster seed source-fingerprint", - ); - const standardSeedPostgresMajor = postgresMajor( - standardSeed["postgres-version"], - "frozen WASIX standard cluster seed postgres-version", - ); - if (runtimeModuleSha256 !== standardSeedRuntimeModuleSha256) { - fail("frozen WASIX core manifest runtime and standard cluster seed identify different runtime modules"); - } - if (sourceFingerprint !== standardSeedFingerprint) { - fail("frozen WASIX core manifest runtime and standard cluster seed identify different source fingerprints"); - } - if (runtimePostgresMajor !== standardSeedPostgresMajor) { - fail("frozen WASIX core manifest runtime and standard cluster seed identify different PostgreSQL majors"); - } - - const runtimeModule = requireRegularEntry( - runtimeEntries, - RUNTIME_MODULE_MEMBER, - "frozen WASIX runtime archive", - ); - if (sha256Bytes(runtimeModule.data()) !== runtimeModuleSha256) { - fail("frozen WASIX runtime module does not match manifest runtime.module-sha256"); - } - const pgVersion = Buffer.from( - requireRegularEntry(standardSeedEntries, "PG_VERSION", "frozen WASIX standard cluster seed archive").data(), - ).toString("utf8").trim(); - if (pgVersion !== runtimePostgresMajor || pgVersion !== standardSeedPostgresMajor) { - fail("frozen WASIX cluster seed PG_VERSION does not match the manifest PostgreSQL major"); - } - if ( - seedManifest.schema !== "oliphaunt-cluster-seed-v1" - || seedManifest.artifactRole !== "cluster-seed-standard" - || seedManifest.catalogProfile !== "standard" - || seedManifest.archive?.path !== WASIX_STANDARD_SEED_ARCHIVE_PATH - || seedManifest.archive?.sha256 !== standardSeed.sha256 - || seedManifest.archive?.compressedBytes !== standardSeed.size - || seedManifest.runtime?.consumerSha256 !== runtimeModuleSha256 - || seedManifest.runtime?.producerSha256 !== runtimeModuleSha256 - || seedManifest.source?.fingerprint !== sourceFingerprint - || JSON.stringify(seedManifest.requiredRuntimeFeatures) !== "[]" - || seedManifest.icu !== null - ) { - fail("frozen WASIX standard cluster seed manifest does not match the runtime closure"); - } -} - -function checkedAssetMetadata(value, expectedArchive, label) { - if (value === null || Array.isArray(value) || typeof value !== "object") { - fail(`${label} must be an object`); - } - if (value.archive !== expectedArchive) { - fail(`${label}.archive must be ${expectedArchive}, got ${JSON.stringify(value.archive)}`); - } - if (typeof value.sha256 !== "string" || !LOWER_SHA256.test(value.sha256)) { - fail(`${label}.sha256 must be a lowercase SHA-256 digest`); - } - return value; -} - -function requireArchiveEntry(entries, member, archive) { - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${rel(archive)} must contain ${member} as one non-empty regular file`); - } - return Buffer.from(entry.data()); -} - -function checkedInputArchive(bytes, label) { - try { - return readPortableTarZstdBufferEntries(bytes, { label }); - } catch (cause) { - fail(cause.message); - } -} - -export function wasixRuntimeNpmInputs({ - portableReleaseArchive, -}) { - const releaseArchive = path.resolve(portableReleaseArchive); - regularFile(releaseArchive, "portable WASIX release archive"); - validatePortableReleaseAsset(releaseArchive); - - const releaseEntries = readPortableArchiveEntries(releaseArchive); - const manifestBytes = requireArchiveEntry( - releaseEntries, - WASIX_PORTABLE_RELEASE_MEMBERS.manifest, - releaseArchive, - ); - const runtimeBytes = requireArchiveEntry( - releaseEntries, - WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive, - releaseArchive, - ); - const standardSeedBytes = requireArchiveEntry( - releaseEntries, - WASIX_PORTABLE_RELEASE_MEMBERS.standardSeedArchive, - releaseArchive, - ); - const standardSeedManifestBytes = requireArchiveEntry( - releaseEntries, - WASIX_PORTABLE_RELEASE_MEMBERS.standardSeedManifest, - releaseArchive, - ); - const manifest = parseJsonBytes( - manifestBytes, - `${rel(releaseArchive)} ${WASIX_PORTABLE_RELEASE_MEMBERS.manifest}`, - ); - const standardSeedManifest = parseJsonBytes( - standardSeedManifestBytes, - `${rel(releaseArchive)} ${WASIX_PORTABLE_RELEASE_MEMBERS.standardSeedManifest}`, - ); - if (!Array.isArray(manifest.extensions) || manifest.extensions.length !== 0) { - fail("frozen WASIX core manifest must contain an empty extensions array"); - } - if (Object.hasOwn(manifest, "pg-dump") || Object.hasOwn(manifest, "psql")) { - fail("frozen WASIX core manifest must not claim split tool payloads"); - } - const runtime = checkedAssetMetadata( - manifest.runtime, - WASIX_RUNTIME_ARCHIVE_PATH, - "frozen WASIX core manifest runtime", - ); - const standardSeed = checkedAssetMetadata( - object(manifest["cluster-seeds"], "frozen WASIX core manifest cluster-seeds").standard, - WASIX_STANDARD_SEED_ARCHIVE_PATH, - "frozen WASIX standard cluster seed", - ); - if (!Number.isSafeInteger(standardSeed.size) || standardSeed.size <= 0) { - fail("frozen WASIX standard cluster seed size must be a positive safe integer"); - } - if (sha256Bytes(runtimeBytes) !== runtime.sha256) { - fail("frozen WASIX runtime archive does not match manifest.runtime.sha256"); - } - if (runtime.size !== undefined && runtimeBytes.length !== runtime.size) { - fail("frozen WASIX runtime archive does not match manifest.runtime.size"); - } - if (standardSeedBytes.length !== standardSeed.size || sha256Bytes(standardSeedBytes) !== standardSeed.sha256) { - fail("frozen WASIX standard cluster seed archive does not match the manifest size/digest"); - } - const runtimeEntries = checkedInputArchive( - runtimeBytes, - `${rel(releaseArchive)} runtime archive`, - ); - const standardSeedEntries = checkedInputArchive( - standardSeedBytes, - `${rel(releaseArchive)} standard cluster seed archive`, - ); - assertCoreManifestContract(manifest, runtimeEntries, standardSeedEntries, standardSeedManifest); - - return Object.freeze({ - manifest: Object.freeze({ - bytes: manifestBytes, - sha256: sha256Bytes(manifestBytes), - size: manifestBytes.length, - }), - runtimeArchive: Object.freeze({ - archive: runtime.archive, - bytes: runtimeBytes, - sha256: runtime.sha256, - size: runtimeBytes.length, - }), - standardSeedArchive: Object.freeze({ - archive: standardSeed.archive, - bytes: standardSeedBytes, - sha256: standardSeed.sha256, - size: standardSeedBytes.length, - }), - standardSeedManifest: Object.freeze({ - bytes: standardSeedManifestBytes, - sha256: sha256Bytes(standardSeedManifestBytes), - size: standardSeedManifestBytes.length, - }), - }); -} - -function writeJson(file, value) { - writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o644 }); - chmodSync(file, 0o644); -} - -function writeReadme(packageDir) { - writeFileSync(path.join(packageDir, "README.md"), `# ${WASIX_RUNTIME_NPM_PACKAGE} - -Internal host-neutral portable runtime carrier for \`@oliphaunt/wasix-ts\`. -Application code should depend on the binding, which selects this matching -carrier automatically. The descriptor and assets can be consumed by browser -or Node/Bun/Deno/Electron WASIX hosts; importing them alone is not a host-support claim. -The public binding declares this carrier as an exact release-staged dependency; -applications do not configure its package-relative assets. - -The carried manifest retains the exact qualified core identity projection and -an empty extension inventory. Extension metadata and bytes remain in their -independently versioned \`@oliphaunt/extension-*-wasix\` packages, so an -extension release never mutates this runtime carrier. -`); -} - -export function stageWasixRuntimeNpmCarrier({ - version, - portableReleaseArchive, - packageDir, -}) { - if (typeof version !== "string" || version.length === 0) { - throw new TypeError(`${TOOL}: version must be a non-empty string`); - } - const output = path.resolve(packageDir); - const inputs = wasixRuntimeNpmInputs({ portableReleaseArchive }); - rmSync(output, { recursive: true, force: true }); - mkdirSync(path.join(output, "assets"), { recursive: true }); - for (const [name, input] of Object.entries({ - runtimeArchive: inputs.runtimeArchive, - standardSeedArchive: inputs.standardSeedArchive, - standardSeedManifest: inputs.standardSeedManifest, - manifest: inputs.manifest, - })) { - const destination = path.join(output, ...WASIX_RUNTIME_NPM_ASSET_PATHS[name].split("/")); - writeFileSync(destination, input.bytes, { flag: "wx", mode: 0o644 }); - chmodSync(destination, 0o644); - } - - const descriptorInput = { version, ...inputs }; - writeFileSync(path.join(output, "index.js"), renderWasixRuntimeDescriptorModule(descriptorInput)); - writeFileSync(path.join(output, "index.d.ts"), renderWasixRuntimeDescriptorTypes()); - chmodSync(path.join(output, "index.js"), 0o644); - chmodSync(path.join(output, "index.d.ts"), 0o644); - writeReadme(output); - chmodSync(path.join(output, "README.md"), 0o644); - stageReleaseNotices(output, NOTICE_OPTIONS); - - const noticeFiles = releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => member); - const packageJson = { - name: WASIX_RUNTIME_NPM_PACKAGE, - version, - description: "Portable liboliphaunt WASIX runtime assets for Oliphaunt hosts.", - license: releaseProfilePackageLicense("wasix-runtime").spdx, - type: "module", - sideEffects: false, - repository: { type: "git", url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, - oliphaunt: { - product: WASIX_RUNTIME_PRODUCT, - kind: "wasix-runtime", - runtime: "wasix", - target: WASIX_RUNTIME_NPM_TARGET, - descriptorSchema: WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA, - manifestProjection: "core", - }, - publishConfig: { access: "public", provenance: true }, - files: ["README.md", "index.js", "index.d.ts", "assets", ...noticeFiles], - exports: { - ".": { types: "./index.d.ts", import: "./index.js", default: "./index.js" }, - "./package.json": "./package.json", - }, - }; - validateNpmTrustedPublishingManifest(packageJson, `${WASIX_RUNTIME_NPM_PACKAGE} generated package`); - writeJson(path.join(output, "package.json"), packageJson); - assertReleaseNoticesInDirectory(output, NOTICE_OPTIONS); - return Object.freeze({ descriptor: descriptorInput, packageDir: output, packageName: WASIX_RUNTIME_NPM_PACKAGE }); -} - -function safeNpmFilename(name) { - return name.replace(/^@/u, "").replaceAll("/", "-"); -} - -function packedFileEntries(entries) { - return [...entries] - .filter(([, entry]) => entry.isFile) - .map(([member]) => member) - .sort(); -} - -export function assertWasixRuntimeNpmArchive(archive, { version, descriptor }) { - const file = path.resolve(archive); - regularFile(file, "WASIX runtime npm carrier"); - if (statSync(file).size > NPM_PACKAGE_SAFETY_LIMIT_BYTES) { - fail(`${rel(file)} exceeds the ${NPM_PACKAGE_SAFETY_LIMIT_BYTES}-byte npm carrier safety limit`); - } - assertReleaseNoticesInArchive(file, { ...NOTICE_OPTIONS, prefix: "package" }); - const entries = readPortableArchiveEntries(file); - const expectedFiles = [ - "package/package.json", - "package/README.md", - "package/index.js", - "package/index.d.ts", - ...Object.values(WASIX_RUNTIME_NPM_ASSET_PATHS).map((member) => `package/${member}`), - ...releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => `package/${member}`), - ].sort(); - const actualFiles = packedFileEntries(entries); - if (!isDeepStrictEqual(actualFiles, expectedFiles)) { - fail(`${rel(file)} regular file inventory differs from the generated package allowlist`); - } - for (const [member, entry] of entries) { - if (entry.isSymbolicLink) fail(`${rel(file)} must not contain symbolic link ${member}`); - } - - const packageJson = parseJsonBytes( - requireArchiveEntry(entries, "package/package.json", file), - `${rel(file)} package/package.json`, - ); - validateNpmTrustedPublishingManifest(packageJson, `${rel(file)} package/package.json`); - if (packageJson.name !== WASIX_RUNTIME_NPM_PACKAGE || packageJson.version !== version) { - fail(`${rel(file)} must identify ${WASIX_RUNTIME_NPM_PACKAGE}@${version}`); - } - for (const name of ["runtimeArchive", "standardSeedArchive", "standardSeedManifest", "manifest"]) { - const bytes = requireArchiveEntry(entries, `package/${WASIX_RUNTIME_NPM_ASSET_PATHS[name]}`, file); - if (bytes.length !== descriptor[name].size || sha256Bytes(bytes) !== descriptor[name].sha256) { - fail(`${rel(file)} ${name} bytes differ from the generated descriptor`); - } - } - return packageJson; -} - -export function packWasixRuntimeNpmCarrier({ - version, - portableReleaseArchive, - packageDir = path.join(ROOT, "target/release/npm-package-sources/liboliphaunt-wasix"), - tarballRoot = path.join(ROOT, "target/release/npm-packages/liboliphaunt-wasix"), -}) { - const staged = stageWasixRuntimeNpmCarrier({ - version, - portableReleaseArchive, - packageDir, - }); - const outputRoot = path.resolve(tarballRoot); - rmSync(outputRoot, { recursive: true, force: true }); - mkdirSync(outputRoot, { recursive: true }); - const command = process.platform === "win32" ? "pnpm.cmd" : "pnpm"; - const result = captureCommandOutput( - command, - ["pack", "--pack-destination", outputRoot, "--json"], - { - cwd: staged.packageDir, - label: `pnpm pack for ${WASIX_RUNTIME_NPM_PACKAGE}`, - maxOutputBytes: MAX_COMMAND_CAPTURE_BYTES, - shell: process.platform === "win32", - }, - ); - if (result.error !== undefined) { - fail(`pnpm pack failed to start: ${result.error.message}`); - } - if (result.status !== 0) { - const detail = String(result.stderr || result.stdout || "").trim(); - fail(`pnpm pack failed${detail ? `: ${detail}` : ""}`); - } - let packed; - try { - packed = JSON.parse(result.stdout); - } catch (cause) { - fail(`pnpm pack did not emit JSON: ${cause.message}`); - } - const filename = Array.isArray(packed) ? packed[0]?.filename : packed?.filename; - if (typeof filename !== "string" || !filename.endsWith(".tgz")) { - fail("pnpm pack did not report a .tgz filename"); - } - const tarball = path.isAbsolute(filename) ? filename : path.join(outputRoot, filename); - assertWasixRuntimeNpmArchive(tarball, { version, descriptor: staged.descriptor }); - const expectedName = `${safeNpmFilename(WASIX_RUNTIME_NPM_PACKAGE)}-${version}.tgz`; - if (path.basename(tarball) !== expectedName) { - fail(`pnpm pack emitted ${path.basename(tarball)} instead of ${expectedName}`); - } - return Object.freeze({ ...staged, tarball }); -} diff --git a/tools/release/wasix-runtime-npm-carrier.test.mjs b/tools/release/wasix-runtime-npm-carrier.test.mjs deleted file mode 100644 index 5ca13cd86..000000000 --- a/tools/release/wasix-runtime-npm-carrier.test.mjs +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env bun -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { zstdCompressSync } from "node:zlib"; -import { afterAll, expect, test } from "bun:test"; - -import { createDeterministicTar } from "./cargo-source-package.mjs"; -import { stageReleaseNotices } from "./release-notices.mjs"; -import { CORE_RUNTIME_ARCHIVE_FILES } from "./wasix-cargo-artifact-contract.mjs"; -import { - packWasixRuntimeNpmCarrier, - renderWasixRuntimeDescriptorModule, -} from "./wasix-runtime-npm-carrier.mjs"; -import { packWasixToolsNpmCarrier } from "./wasix-tools-npm-carrier.mjs"; -import { - WASIX_PORTABLE_RELEASE_MEMBERS, - WASIX_RUNTIME_NPM_PACKAGE, -} from "./wasix-runtime-npm-contract.mjs"; - -const directories = []; - -afterAll(() => { - for (const directory of directories) rmSync(directory, { recursive: true, force: true }); -}); - -function temporaryRoot(name) { - const root = mkdtempSync(path.join(os.tmpdir(), name)); - directories.push(root); - return root; -} - -function sha256(bytes) { - return createHash("sha256").update(bytes).digest("hex"); -} - -function deterministicTar(stage, archiveRoot) { - return createDeterministicTar(stage, archiveRoot, { - fail(message) { - throw new Error(message); - }, - fixedFileMode: 0o644, - }); -} - -function writeMember(stage, member, bytes) { - const output = path.join(stage, ...member.split("/")); - mkdirSync(path.dirname(output), { recursive: true }); - writeFileSync(output, bytes); -} - -function portableReleaseFixture(root, { transformManifest = (manifest) => manifest } = {}) { - const runtimeStage = path.join(root, "runtime-stage"); - for (const member of CORE_RUNTIME_ARCHIVE_FILES) { - expect(member.startsWith("oliphaunt/")).toBe(true); - writeMember(runtimeStage, member.slice("oliphaunt/".length), `fixture:${member}\n`); - } - const runtimeBytes = zstdCompressSync(deterministicTar(runtimeStage, "oliphaunt")); - - const seedStage = path.join(root, "seed-stage"); - writeMember(seedStage, "PG_VERSION", "18\n"); - const seedBytes = zstdCompressSync(deterministicTar(seedStage, ".")); - - const sourceFingerprint = "fixture-postgres-source-fingerprint"; - const runtimeModuleSha256 = sha256(Buffer.from("fixture:oliphaunt/bin/postgres\n")); - const manifest = transformManifest({ - "format-version": 2, - "source-fingerprint": sourceFingerprint, - runtime: { - archive: "oliphaunt.wasix.tar.zst", - sha256: sha256(runtimeBytes), - size: runtimeBytes.length, - "module-sha256": runtimeModuleSha256, - "postgres-version": "18.4", - link: { exports: [] }, - }, - "runtime-support": [], - "cluster-seeds": { - standard: { - "artifact-role": "cluster-seed-standard", - "catalog-profile": "standard", - archive: "cluster-seeds/standard.tar.zst", - manifest: "cluster-seeds/standard.json", - sha256: sha256(seedBytes), - size: seedBytes.length, - "runtime-module-sha256": runtimeModuleSha256, - "source-fingerprint": sourceFingerprint, - "postgres-version": "18", - "physical-format": "wasix-pg18-v1", - "compatibility-key": "wasix-pg18-datum32-v1", - }, - icu: { - "artifact-role": "cluster-seed-icu", - "catalog-profile": "icu", - archive: "cluster-seeds/icu.tar.zst", - manifest: "cluster-seeds/icu.json", - sha256: "c".repeat(64), - size: 1, - "runtime-module-sha256": runtimeModuleSha256, - "source-fingerprint": sourceFingerprint, - "postgres-version": "18", - "physical-format": "wasix-pg18-v1", - "compatibility-key": "wasix-pg18-datum32-v1", - "icu-data-tree-sha256": "d".repeat(64), - }, - }, - extensions: [], - }); - const seedManifestBytes = Buffer.from(`${JSON.stringify({ - schema: "oliphaunt-cluster-seed-v1", - artifactRole: "cluster-seed-standard", - catalogProfile: "standard", - runtime: { - product: "liboliphaunt-wasix", - version: "7.8.9", - engineFamily: "wasix", - physicalFormat: "wasix-pg18-v1", - postgresMajor: 18, - compatibilityKey: "wasix-pg18-datum32-v1", - consumerSha256: runtimeModuleSha256, - producerSha256: runtimeModuleSha256, - initdbSha256: "e".repeat(64), - }, - source: { fingerprint: sourceFingerprint, catalogVersion: "202505281", lane: "stable", producer: "wasix-initdb" }, - initProfile: "encoding=UTF8,locale=C.UTF-8,locale-provider=libc,auth=trust,no-sync", - archive: { - path: "cluster-seeds/standard.tar.zst", - sha256: sha256(seedBytes), - compressedBytes: seedBytes.length, - expandedBytes: 3, - regularFiles: 1, - directories: 1, - }, - requiredRuntimeFeatures: [], - extensions: { selected: [], startupConfiguration: [] }, - icu: null, - }, null, 2)}\n`); - const manifestBytes = Buffer.from(`${JSON.stringify(manifest, null, 2)}\n`); - const releaseStage = path.join(root, "release-stage"); - writeMember(releaseStage, WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive, runtimeBytes); - writeMember(releaseStage, WASIX_PORTABLE_RELEASE_MEMBERS.standardSeedArchive, seedBytes); - writeMember(releaseStage, WASIX_PORTABLE_RELEASE_MEMBERS.standardSeedManifest, seedManifestBytes); - writeMember(releaseStage, WASIX_PORTABLE_RELEASE_MEMBERS.manifest, manifestBytes); - writeMember(releaseStage, "target/oliphaunt-wasix/assets/bin/pg_dump.wasix.wasm", "pg_dump"); - writeMember(releaseStage, "target/oliphaunt-wasix/assets/bin/psql.wasix.wasm", "psql"); - stageReleaseNotices(releaseStage, { profile: "wasix-runtime" }); - const archive = path.join(root, "liboliphaunt-wasix-7.8.9-runtime-portable.tar.zst"); - writeFileSync(archive, zstdCompressSync(deterministicTar(releaseStage, "."))); - return { archive, manifestBytes }; -} - -test("renders the package-authored runtime identity without consumer asset URLs", () => { - const digest = "a".repeat(64); - const module = renderWasixRuntimeDescriptorModule({ - version: "7.8.9", - runtimeArchive: { - archive: "oliphaunt.wasix.tar.zst", - sha256: digest, - size: 1, - }, - standardSeedArchive: { - archive: "cluster-seeds/standard.tar.zst", - sha256: digest, - size: 2, - }, - standardSeedManifest: { sha256: digest, size: 4 }, - manifest: { sha256: digest, size: 3 }, - }); - expect(module).toContain('product: "liboliphaunt-wasix"'); - expect(module).toContain('source: new URL("./assets/oliphaunt.wasix.tar.zst", import.meta.url)'); - expect(module).not.toContain('new URL("/assets/'); -}); - -test("rejects a core manifest that omits host-required identity metadata", () => { - const root = temporaryRoot("oliphaunt-wasix-runtime-invalid-manifest-"); - const fixture = portableReleaseFixture(root, { - transformManifest(manifest) { - delete manifest.runtime.link; - return manifest; - }, - }); - expect(() => - packWasixRuntimeNpmCarrier({ - version: "7.8.9", - portableReleaseArchive: fixture.archive, - packageDir: path.join(root, "package"), - tarballRoot: path.join(root, "tarballs"), - })).toThrow(/runtime[.]link must be an object/u); -}); - -test("rejects a core manifest whose optional runtime size differs from its bytes", () => { - const root = temporaryRoot("oliphaunt-wasix-runtime-invalid-size-"); - const fixture = portableReleaseFixture(root, { - transformManifest(manifest) { - manifest.runtime.size += 1; - return manifest; - }, - }); - expect(() => - packWasixRuntimeNpmCarrier({ - version: "7.8.9", - portableReleaseArchive: fixture.archive, - packageDir: path.join(root, "package"), - tarballRoot: path.join(root, "tarballs"), - })).toThrow(/runtime archive does not match manifest[.]runtime[.]size/u); -}); - -test("packs the exact qualified core projection as one host-neutral npm carrier", () => { - const root = temporaryRoot("oliphaunt-wasix-runtime-npm-"); - const fixture = portableReleaseFixture(root); - const packed = packWasixRuntimeNpmCarrier({ - version: "7.8.9", - portableReleaseArchive: fixture.archive, - packageDir: path.join(root, "package"), - tarballRoot: path.join(root, "tarballs"), - }); - const packageJson = JSON.parse(readFileSync(path.join(packed.packageDir, "package.json"), "utf8")); - expect(packageJson.name).toBe(WASIX_RUNTIME_NPM_PACKAGE); - expect(packageJson.version).toBe("7.8.9"); - expect(packageJson.oliphaunt.manifestProjection).toBe("core"); - expect(readFileSync(path.join(packed.packageDir, "README.md"), "utf8")).toContain( - "public binding declares this carrier as an exact release-staged dependency", - ); - expect(readFileSync(path.join(packed.packageDir, "assets/manifest.json"))).toEqual( - fixture.manifestBytes, - ); - - const script = ` -import { pathToFileURL } from "node:url"; -const descriptor = (await import(pathToFileURL(process.env.ENTRYPOINT).href)).default; -if (!Object.isFrozen(descriptor)) throw new Error("descriptor is mutable"); -for (const value of [descriptor.runtimeArchive, descriptor.standardSeedArchive, descriptor.standardSeedManifest, descriptor.manifest]) { - if (!Object.isFrozen(value)) throw new Error("asset descriptor is mutable"); -} -console.log(JSON.stringify({ - product: descriptor.product, - runtime: descriptor.runtime, - runtimeSource: descriptor.runtimeArchive.source.href, - seedSource: descriptor.standardSeedArchive.source.href, - manifestSource: descriptor.manifest.source.href, -})); -`; - const imported = spawnSync("node", ["--input-type=module", "--eval", script], { - encoding: "utf8", - env: { ...process.env, ENTRYPOINT: path.join(packed.packageDir, "index.js") }, - }); - expect(imported.status, `${imported.stdout}\n${imported.stderr}`).toBe(0); - expect(JSON.parse(imported.stdout)).toMatchObject({ - product: "liboliphaunt-wasix", - runtime: "wasix", - }); -}); - -test("packs split pg_dump and psql bytes from the same qualified release archive", () => { - const root = temporaryRoot("oliphaunt-wasix-tools-npm-"); - const fixture = portableReleaseFixture(root); - const packed = packWasixToolsNpmCarrier({ - version: "7.8.9", - portableReleaseArchive: fixture.archive, - packageDir: path.join(root, "package"), - tarballRoot: path.join(root, "tarballs"), - }); - const packageJson = JSON.parse(readFileSync(path.join(packed.packageDir, "package.json"), "utf8")); - expect(packageJson.name).toBe("@oliphaunt/liboliphaunt-wasix-tools"); - expect(packageJson.version).toBe("7.8.9"); - expect(readFileSync(path.join(packed.packageDir, "assets/pg_dump.wasix.wasm"), "utf8")).toBe("pg_dump"); - expect(readFileSync(path.join(packed.packageDir, "assets/psql.wasix.wasm"), "utf8")).toBe("psql"); - expect(packed.descriptor.pgDump.sha256).toBe(sha256(Buffer.from("pg_dump"))); - expect(packed.descriptor.psql.sha256).toBe(sha256(Buffer.from("psql"))); -}); diff --git a/tools/release/wasix-runtime-npm-contract.mjs b/tools/release/wasix-runtime-npm-contract.mjs deleted file mode 100644 index 248b07979..000000000 --- a/tools/release/wasix-runtime-npm-contract.mjs +++ /dev/null @@ -1,26 +0,0 @@ -export const WASIX_RUNTIME_PRODUCT = "liboliphaunt-wasix"; -export const WASIX_RUNTIME_NPM_PACKAGE = "@oliphaunt/liboliphaunt-wasix"; -export const WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA = "oliphaunt-wasix-runtime-v2"; -export const WASIX_RUNTIME_NPM_TARGET = "portable"; - -export const WASIX_RUNTIME_ARCHIVE_PATH = "oliphaunt.wasix.tar.zst"; -export const WASIX_STANDARD_SEED_ARCHIVE_PATH = "cluster-seeds/standard.tar.zst"; -export const WASIX_STANDARD_SEED_MANIFEST_PATH = "cluster-seeds/standard.json"; - -const RELEASE_ASSET_ROOT = "target/oliphaunt-wasix/assets"; - -export const WASIX_PORTABLE_RELEASE_MEMBERS = Object.freeze({ - runtimeArchive: `${RELEASE_ASSET_ROOT}/${WASIX_RUNTIME_ARCHIVE_PATH}`, - standardSeedArchive: `${RELEASE_ASSET_ROOT}/${WASIX_STANDARD_SEED_ARCHIVE_PATH}`, - standardSeedManifest: `${RELEASE_ASSET_ROOT}/${WASIX_STANDARD_SEED_MANIFEST_PATH}`, - icuSeedArchive: `${RELEASE_ASSET_ROOT}/cluster-seeds/icu.tar.zst`, - icuSeedManifest: `${RELEASE_ASSET_ROOT}/cluster-seeds/icu.json`, - manifest: `${RELEASE_ASSET_ROOT}/manifest.json`, -}); - -export const WASIX_RUNTIME_NPM_ASSET_PATHS = Object.freeze({ - runtimeArchive: "assets/oliphaunt.wasix.tar.zst", - standardSeedArchive: "assets/cluster-seed-standard.tar.zst", - standardSeedManifest: "assets/cluster-seed-standard.json", - manifest: "assets/manifest.json", -}); diff --git a/tools/release/wasix-runtime-npm-descriptor.mjs b/tools/release/wasix-runtime-npm-descriptor.mjs deleted file mode 100644 index 803aa2da4..000000000 --- a/tools/release/wasix-runtime-npm-descriptor.mjs +++ /dev/null @@ -1,111 +0,0 @@ -import { - WASIX_STANDARD_SEED_ARCHIVE_PATH, - WASIX_RUNTIME_ARCHIVE_PATH, - WASIX_RUNTIME_NPM_ASSET_PATHS, - WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA, - WASIX_RUNTIME_PRODUCT, -} from './wasix-runtime-npm-contract.mjs'; - -const TOOL = 'wasix-runtime-npm-carrier.mjs'; -const LOWER_SHA256 = /^[0-9a-f]{64}$/u; - -function checkedDescriptorInput({ version, runtimeArchive, standardSeedArchive, standardSeedManifest, manifest }) { - if (typeof version !== 'string' || version.length === 0) { - throw new TypeError(`${TOOL}: runtime descriptor version must be a non-empty string`); - } - for (const [name, value] of Object.entries({ runtimeArchive, standardSeedArchive, standardSeedManifest, manifest })) { - if ( - value === null || - Array.isArray(value) || - typeof value !== 'object' || - typeof value.sha256 !== 'string' || - !LOWER_SHA256.test(value.sha256) || - !Number.isSafeInteger(value.size) || - value.size <= 0 - ) { - throw new TypeError(`${TOOL}: invalid ${name} descriptor input`); - } - } - if (runtimeArchive.archive !== WASIX_RUNTIME_ARCHIVE_PATH) { - throw new TypeError(`${TOOL}: invalid runtime archive descriptor path`); - } - if (standardSeedArchive.archive !== WASIX_STANDARD_SEED_ARCHIVE_PATH) { - throw new TypeError(`${TOOL}: invalid standard cluster seed archive descriptor path`); - } -} - -export function renderWasixRuntimeDescriptorModule(input) { - checkedDescriptorInput(input); - const { version, runtimeArchive, standardSeedArchive, standardSeedManifest, manifest } = input; - const asset = (value, sourcePath, includeArchive) => - [ - ' Object.freeze({', - ...(includeArchive ? [` archive: ${JSON.stringify(value.archive)},`] : []), - ` sha256: ${JSON.stringify(value.sha256)},`, - ` size: ${value.size},`, - ` source: new URL(${JSON.stringify(`./${sourcePath}`)}, import.meta.url),`, - ' })', - ].join('\n'); - return [ - 'export const POSTGRES_MAJOR = 18;', - 'export const PHYSICAL_FORMAT = "wasix-pg18-v1";', - '', - 'const runtimeArchive =', - `${asset(runtimeArchive, WASIX_RUNTIME_NPM_ASSET_PATHS.runtimeArchive, true)};`, - 'const standardSeedArchive =', - `${asset(standardSeedArchive, WASIX_RUNTIME_NPM_ASSET_PATHS.standardSeedArchive, true)};`, - 'const standardSeedManifest =', - `${asset(standardSeedManifest, WASIX_RUNTIME_NPM_ASSET_PATHS.standardSeedManifest, false)};`, - 'const manifest =', - `${asset(manifest, WASIX_RUNTIME_NPM_ASSET_PATHS.manifest, false)};`, - '', - 'const descriptor = Object.freeze({', - ` schema: ${JSON.stringify(WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA)},`, - ' runtime: "wasix",', - ` product: ${JSON.stringify(WASIX_RUNTIME_PRODUCT)},`, - ` version: ${JSON.stringify(version)},`, - ' runtimeArchive,', - ' standardSeedArchive,', - ' standardSeedManifest,', - ' manifest,', - '});', - '', - 'export { descriptor };', - 'export default descriptor;', - '', - ].join('\n'); -} - -export function renderWasixRuntimeDescriptorTypes() { - return `export declare const POSTGRES_MAJOR: 18; -export declare const PHYSICAL_FORMAT: "wasix-pg18-v1"; - -export type OliphauntWasixRuntimeAsset = Readonly<{ - archive: string; - sha256: string; - size: number; - source: URL; -}>; - -export type OliphauntWasixRuntimeManifest = Readonly<{ - sha256: string; - size: number; - source: URL; -}>; - -export type OliphauntWasixRuntimeDescriptor = Readonly<{ - schema: "${WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA}"; - runtime: "wasix"; - product: "${WASIX_RUNTIME_PRODUCT}"; - version: string; - runtimeArchive: OliphauntWasixRuntimeAsset; - standardSeedArchive: OliphauntWasixRuntimeAsset; - standardSeedManifest: OliphauntWasixRuntimeManifest; - manifest: OliphauntWasixRuntimeManifest; -}>; - -declare const descriptor: OliphauntWasixRuntimeDescriptor; -export { descriptor }; -export default descriptor; -`; -} diff --git a/tools/release/wasix-tools-npm-carrier.mjs b/tools/release/wasix-tools-npm-carrier.mjs deleted file mode 100644 index e540e93c9..000000000 --- a/tools/release/wasix-tools-npm-carrier.mjs +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from 'node:crypto'; -import { - lstatSync, - mkdirSync, - rmSync, - statSync, - writeFileSync, -} from 'node:fs'; -import { isDeepStrictEqual } from 'node:util'; -import path from 'node:path'; - -import { captureCommandOutput } from '../dev/capture-command-output.mjs'; -import { validatePortableReleaseAsset } from './check-liboliphaunt-wasix-release-assets.mjs'; -import { - NPM_TRUSTED_PUBLISHING_REPOSITORY, - validateNpmTrustedPublishingManifest, -} from './npm-trusted-publishing.mjs'; -import { readPortableArchiveEntries } from '../../src/shared/artifact-packaging/portable-archive.mjs'; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releaseNoticeRows, - releaseProfilePackageLicense, - stageReleaseNotices, -} from './release-notices.mjs'; - -const TOOL = 'wasix-tools-npm-carrier.mjs'; -const ROOT = path.resolve(import.meta.dirname, '../..'); -const PACKAGE_NAME = '@oliphaunt/liboliphaunt-wasix-tools'; -const DESCRIPTOR_SCHEMA = 'oliphaunt-wasix-tools-v1'; -const RELEASE_TOOLS = Object.freeze({ - pgDump: Object.freeze({ name: 'pg_dump', member: 'target/oliphaunt-wasix/assets/bin/pg_dump.wasix.wasm' }), - psql: Object.freeze({ name: 'psql', member: 'target/oliphaunt-wasix/assets/bin/psql.wasix.wasm' }), -}); -const NOTICE_OPTIONS = Object.freeze({ profile: 'wasix-runtime' }); - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function sha256(bytes) { - return createHash('sha256').update(bytes).digest('hex'); -} - -function requiredEntry(entries, member, label) { - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${label} must contain ${member} as a non-empty regular file`); - } - return Buffer.from(entry.data()); -} - -function regularArchive(file) { - try { - const metadata = lstatSync(file); - if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) { - fail(`${file} must be a non-empty regular non-symlink archive`); - } - } catch (cause) { - fail(`${file} cannot be inspected: ${cause.message}`); - } -} - -export function wasixToolsNpmInputs({ portableReleaseArchive }) { - const archive = path.resolve(portableReleaseArchive); - regularArchive(archive); - validatePortableReleaseAsset(archive); - const entries = readPortableArchiveEntries(archive); - const tools = {}; - for (const [descriptorName, spec] of Object.entries(RELEASE_TOOLS)) { - const bytes = requiredEntry(entries, spec.member, archive); - tools[descriptorName] = Object.freeze({ - name: spec.name, - sha256: sha256(bytes), - size: bytes.length, - bytes, - }); - } - return Object.freeze(tools); -} - -export function stageWasixToolsNpmCarrier({ version, portableReleaseArchive, packageDir }) { - if (typeof version !== 'string' || !/^\d+\.\d+\.\d+$/u.test(version)) { - throw new TypeError(`${TOOL}: version must be an exact semantic version`); - } - const output = path.resolve(packageDir); - const tools = wasixToolsNpmInputs({ portableReleaseArchive }); - rmSync(output, { recursive: true, force: true }); - mkdirSync(path.join(output, 'assets'), { recursive: true }); - for (const [name, tool] of Object.entries(tools)) { - const filename = name === 'pgDump' ? 'pg_dump.wasix.wasm' : 'psql.wasix.wasm'; - writeFileSync(path.join(output, 'assets', filename), tool.bytes, { mode: 0o644 }); - } - const descriptor = Object.freeze({ version, runtimeVersion: version, ...tools }); - writeFileSync(path.join(output, 'index.js'), renderDescriptor(descriptor), { mode: 0o644 }); - writeFileSync(path.join(output, 'index.d.ts'), renderTypes(), { mode: 0o644 }); - writeFileSync( - path.join(output, 'README.md'), - `# ${PACKAGE_NAME}\n\nPortable PostgreSQL \`pg_dump\` and \`psql\` modules used by \`@oliphaunt/wasix-tools\`. Application code should depend on the facade rather than this asset carrier.\n`, - { mode: 0o644 }, - ); - stageReleaseNotices(output, NOTICE_OPTIONS); - const notices = releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => member); - const manifest = { - name: PACKAGE_NAME, - version, - description: 'Portable WASIX pg_dump and psql modules for Oliphaunt hosts.', - license: releaseProfilePackageLicense('wasix-runtime').spdx, - type: 'module', - sideEffects: false, - repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, - oliphaunt: { - product: 'liboliphaunt-wasix', - kind: 'wasix-tools', - runtime: 'wasix', - target: 'portable', - runtimeVersion: version, - descriptorSchema: DESCRIPTOR_SCHEMA, - }, - publishConfig: { access: 'public', provenance: true }, - files: ['README.md', 'index.js', 'index.d.ts', 'assets', ...notices], - exports: { - '.': { types: './index.d.ts', import: './index.js', default: './index.js' }, - './package.json': './package.json', - }, - }; - validateNpmTrustedPublishingManifest(manifest, `${PACKAGE_NAME} generated package`); - writeFileSync(path.join(output, 'package.json'), `${JSON.stringify(manifest, null, 2)}\n`, { - mode: 0o644, - }); - assertReleaseNoticesInDirectory(output, NOTICE_OPTIONS); - return Object.freeze({ packageDir: output, descriptor }); -} - -export function packWasixToolsNpmCarrier({ - version, - portableReleaseArchive, - packageDir = path.join(ROOT, 'target/release/npm-package-sources/liboliphaunt-wasix-tools'), - tarballRoot = path.join(ROOT, 'target/release/npm-packages/liboliphaunt-wasix-tools'), -}) { - const staged = stageWasixToolsNpmCarrier({ version, portableReleaseArchive, packageDir }); - const output = path.resolve(tarballRoot); - rmSync(output, { recursive: true, force: true }); - mkdirSync(output, { recursive: true }); - const command = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'; - const result = captureCommandOutput( - command, - ['pack', '--pack-destination', output, '--json'], - { cwd: staged.packageDir, label: `pnpm pack for ${PACKAGE_NAME}`, maxOutputBytes: 4 * 1024 * 1024 }, - ); - if (result.error !== undefined || result.status !== 0) { - fail(`pnpm pack failed: ${String(result.stderr || result.error?.message || '').trim()}`); - } - const packed = JSON.parse(result.stdout); - const filename = Array.isArray(packed) ? packed[0]?.filename : packed?.filename; - if (typeof filename !== 'string') fail('pnpm pack did not report its filename'); - const tarball = path.isAbsolute(filename) ? filename : path.join(output, filename); - assertWasixToolsNpmArchive(tarball, staged.descriptor); - return Object.freeze({ ...staged, tarball }); -} - -export function assertWasixToolsNpmArchive(archive, descriptor) { - if (statSync(archive).size > 20 * 1024 * 1024) fail(`${archive} exceeds the package size limit`); - assertReleaseNoticesInArchive(archive, { ...NOTICE_OPTIONS, prefix: 'package' }); - const entries = readPortableArchiveEntries(archive); - const expected = [ - 'package/package.json', - 'package/README.md', - 'package/index.js', - 'package/index.d.ts', - 'package/assets/pg_dump.wasix.wasm', - 'package/assets/psql.wasix.wasm', - ...releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => `package/${member}`), - ].sort(); - const actual = [...entries] - .filter(([, entry]) => entry.isFile) - .map(([member]) => member) - .sort(); - if (!isDeepStrictEqual(actual, expected)) fail(`${archive} file inventory differs from its allowlist`); - const manifest = JSON.parse( - requiredEntry(entries, 'package/package.json', archive).toString('utf8'), - ); - validateNpmTrustedPublishingManifest(manifest, `${archive} package.json`); - if (manifest.name !== PACKAGE_NAME || manifest.version !== descriptor.version) { - fail(`${archive} has the wrong package identity`); - } - for (const [name, tool] of Object.entries({ - 'pg_dump.wasix.wasm': descriptor.pgDump, - 'psql.wasix.wasm': descriptor.psql, - })) { - const bytes = requiredEntry(entries, `package/assets/${name}`, archive); - if (bytes.length !== tool.size || sha256(bytes) !== tool.sha256) { - fail(`${archive} contains unexpected ${name} bytes`); - } - } - return manifest; -} - -function renderDescriptor(descriptor) { - const tool = (name, value) => `Object.freeze({ name: ${JSON.stringify(value.name)}, sha256: ${JSON.stringify(value.sha256)}, size: ${value.size}, source: new URL('./assets/${name}.wasix.wasm', import.meta.url).href })`; - return `export default Object.freeze({\n schema: '${DESCRIPTOR_SCHEMA}',\n product: 'oliphaunt-wasix-tools',\n version: ${JSON.stringify(descriptor.version)},\n runtimeProduct: 'liboliphaunt-wasix',\n runtimeVersion: ${JSON.stringify(descriptor.runtimeVersion)},\n pgDump: ${tool('pg_dump', descriptor.pgDump)},\n psql: ${tool('psql', descriptor.psql)},\n});\n`; -} - -function renderTypes() { - return `export type WasixToolModule = Readonly<{ name: 'pg_dump' | 'psql'; sha256: string; size: number; source: string }>;\nexport type WasixToolsDescriptor = Readonly<{ schema: '${DESCRIPTOR_SCHEMA}'; product: 'oliphaunt-wasix-tools'; version: string; runtimeProduct: 'liboliphaunt-wasix'; runtimeVersion: string; pgDump: WasixToolModule; psql: WasixToolModule }>;\ndeclare const descriptor: WasixToolsDescriptor;\nexport default descriptor;\n`; -} diff --git a/tools/release/wasix-tools-typescript-package.mjs b/tools/release/wasix-tools-typescript-package.mjs deleted file mode 100644 index 7c2aa8829..000000000 --- a/tools/release/wasix-tools-typescript-package.mjs +++ /dev/null @@ -1,108 +0,0 @@ -import path from 'node:path'; - -import { prepareWasixToolsTypescriptPackage as prepareProductPackage } from '../../src/bindings/wasix-ts/tools-package/tools/package.mjs'; - -import { validateNpmTrustedPublishingManifest } from './npm-trusted-publishing.mjs'; -import { readPortableArchiveEntries } from '../../src/shared/artifact-packaging/portable-archive.mjs'; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releasePackageLicense, - stageReleaseNotices, -} from './release-notices.mjs'; - -const TOOL = 'wasix-tools-typescript-package.mjs'; -const PACKAGE_NAME = '@oliphaunt/wasix-tools'; -const TOOLS_CARRIER = '@oliphaunt/liboliphaunt-wasix-tools'; -const WASIX_BINDING = '@oliphaunt/wasix-ts'; -const NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' }); -const EXACT_VERSION = /^\d+\.\d+\.\d+$/u; - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -export function prepareWasixToolsTypescriptPackage(packageDir, bindingVersion) { - const root = path.resolve(packageDir); - const manifest = prepareProductPackage(root, bindingVersion); - stageReleaseNotices(root, NOTICE_OPTIONS); - assertReleaseNoticesInDirectory(root, NOTICE_OPTIONS); - assertWasixToolsTypescriptManifest(manifest, `${PACKAGE_NAME} staged package`); - return manifest; -} - -export function assertWasixToolsTypescriptManifest(manifest, label = PACKAGE_NAME) { - validateNpmTrustedPublishingManifest(manifest, label); - if ( - manifest.name !== PACKAGE_NAME || - !EXACT_VERSION.test(manifest.version) || - manifest.private === true || - manifest.license !== releasePackageLicense().spdx || - manifest.type !== 'module' || - manifest.scripts !== undefined || - manifest.devDependencies !== undefined - ) { - fail(`${label} is not the exact public source-only tools package`); - } - const dependencies = manifest.dependencies ?? {}; - const peerDependencies = manifest.peerDependencies ?? {}; - if ( - JSON.stringify(Object.keys(dependencies)) !== JSON.stringify([TOOLS_CARRIER]) || - !EXACT_VERSION.test(dependencies[TOOLS_CARRIER]) || - JSON.stringify(Object.keys(peerDependencies)) !== JSON.stringify([WASIX_BINDING]) || - peerDependencies[WASIX_BINDING] !== manifest.version || - manifest.oliphaunt?.runtimeProduct !== 'liboliphaunt-wasix' || - manifest.oliphaunt?.runtimeVersion !== dependencies[TOOLS_CARRIER] || - Object.keys(manifest.optionalDependencies ?? {}).length > 0 - ) { - fail(`${label} must depend on the exact tools carrier and peer with its exact WASIX binding`); - } - if ( - manifest.exports?.['.']?.types !== './lib/index.d.ts' || - manifest.exports?.['.']?.default !== './lib/index.js' || - manifest.exports?.['./package.json'] !== './package.json' - ) { - fail(`${label} exports differ from the two-function public package surface`); - } - return manifest; -} - -export function assertWasixToolsTypescriptNpmArchive(archive) { - const file = path.resolve(archive); - assertReleaseNoticesInArchive(file, { ...NOTICE_OPTIONS, prefix: 'package' }); - const entries = readPortableArchiveEntries(file); - const manifest = assertWasixToolsTypescriptManifest( - JSON.parse(required(entries, 'package/package.json').toString('utf8')), - `${path.basename(file)} package.json`, - ); - if ( - JSON.stringify([...(manifest.files ?? [])].sort()) !== - JSON.stringify(['CHANGELOG.md', 'LICENSE', 'README.md', 'THIRD_PARTY_NOTICES.md', 'lib']) - ) { - fail(`${file} package.json files differ from the owned package roots`); - } - const allowed = new Set(['package.json', ...manifest.files.filter((name) => name !== 'lib')]); - for (const [name, entry] of entries) { - if (entry.isSymbolicLink) fail(`${file} contains symbolic link ${name}`); - const relative = name.replace(/^package\//u, ''); - if (entry.isFile && !allowed.has(relative) && !relative.startsWith('lib/')) { - fail(`${file} contains file outside package.json files: ${name}`); - } - } - for (const name of ['README.md', 'LICENSE', 'THIRD_PARTY_NOTICES.md', 'lib/index.d.ts', 'lib/index.js']) { - required(entries, `package/${name}`); - } - for (const name of ['CHANGELOG.md']) { - if (name === 'CHANGELOG.md' && manifest.version === '0.0.0') continue; - required(entries, `package/${name}`); - } - return manifest; -} - -function required(entries, member) { - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`package is missing non-empty regular ${member}`); - } - return Buffer.from(entry.data()); -} diff --git a/tools/release/wasix-tools-typescript-package.test.mjs b/tools/release/wasix-tools-typescript-package.test.mjs deleted file mode 100644 index 8d6db11e8..000000000 --- a/tools/release/wasix-tools-typescript-package.test.mjs +++ /dev/null @@ -1,47 +0,0 @@ -import { describe, expect, test } from 'bun:test'; - -import { assertWasixToolsTypescriptManifest } from './wasix-tools-typescript-package.mjs'; - -function manifest() { - return { - name: '@oliphaunt/wasix-tools', - version: '1.2.3', - license: 'MIT', - type: 'module', - repository: { - type: 'git', - url: 'git+https://github.com/f0rr0/oliphaunt.git', - directory: 'src/bindings/wasix-ts/tools-package', - }, - publishConfig: { access: 'public', provenance: true }, - oliphaunt: { - runtimeProduct: 'liboliphaunt-wasix', - runtimeVersion: '4.5.6', - }, - dependencies: { - '@oliphaunt/liboliphaunt-wasix-tools': '4.5.6', - }, - peerDependencies: { - '@oliphaunt/wasix-ts': '1.2.3', - }, - exports: { - '.': { types: './lib/index.d.ts', default: './lib/index.js' }, - './package.json': './package.json', - }, - }; -} - -describe('WASIX TypeScript tools package contract', () => { - test('accepts only the exact binding and carrier closure', () => { - expect(() => assertWasixToolsTypescriptManifest(manifest())).not.toThrow(); - }); - - test('rejects semver ranges and extra dependencies', () => { - const range = manifest(); - range.peerDependencies['@oliphaunt/wasix-ts'] = '^1.2.3'; - expect(() => assertWasixToolsTypescriptManifest(range)).toThrow(/exact WASIX binding/); - const extra = manifest(); - extra.dependencies.other = '1.0.0'; - expect(() => assertWasixToolsTypescriptManifest(extra)).toThrow(/exact WASIX binding/); - }); -}); diff --git a/tools/release/wasix-typescript-package.mjs b/tools/release/wasix-typescript-package.mjs deleted file mode 100644 index 410be819c..000000000 --- a/tools/release/wasix-typescript-package.mjs +++ /dev/null @@ -1,296 +0,0 @@ -import path from 'node:path'; - -import { prepareWasixTypescriptPackage as prepareProductPackage } from '../../src/bindings/wasix-ts/tools/package.mjs'; -import { - assertJsCoreBundleInventory, - JS_CORE_PACKAGE, -} from '../../src/shared/js-core/tools/stage-package.mjs'; - -import { readPortableArchiveEntries } from '../../src/shared/artifact-packaging/portable-archive.mjs'; -import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releasePackageLicense, - stageReleaseNotices, -} from './release-notices.mjs'; - -const TOOL = 'wasix-typescript-package.mjs'; -const PACKAGE_NAME = '@oliphaunt/wasix-ts'; -const RUNTIME_PACKAGE = '@oliphaunt/liboliphaunt-wasix'; -const FZSTD_PACKAGE = 'fzstd'; -const FZSTD_VERSION = '0.1.1'; -const NATIVE_PRODUCT = 'oliphaunt-wasix-napi'; -const NATIVE_PACKAGES = Object.freeze([ - '@oliphaunt/wasix-napi-darwin-arm64', - '@oliphaunt/wasix-napi-linux-arm64-gnu', - '@oliphaunt/wasix-napi-linux-x64-gnu', - '@oliphaunt/wasix-napi-win32-x64-msvc', -]); -const NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' }); - -function fail(message) { - throw new Error(`${TOOL}: ${message}`); -} - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function sortedKeys(value) { - return Object.keys(value ?? {}).sort(compareText); -} - -export function assertWasixTypescriptManifest(manifest, label = `${PACKAGE_NAME} package.json`) { - if ( - manifest.name !== PACKAGE_NAME - || typeof manifest.version !== 'string' - || !/^\d+\.\d+\.\d+$/u.test(manifest.version) - || manifest.private === true - || manifest.license !== releasePackageLicense().spdx - || manifest.type !== 'module' - || manifest.publishConfig?.access !== 'public' - || manifest.publishConfig?.provenance !== true - ) { - fail(`${label} is not the stable-version public ESM ${PACKAGE_NAME} package`); - } - if (manifest.scripts !== undefined || manifest.devDependencies !== undefined) { - fail(`${label} must not publish development scripts or dependencies`); - } - const dependencies = manifest.dependencies ?? {}; - const optionalDependencies = manifest.optionalDependencies ?? {}; - const expectedDependencies = [FZSTD_PACKAGE, JS_CORE_PACKAGE, RUNTIME_PACKAGE].sort(compareText); - const nativeVersion = manifest.oliphaunt?.wasixNapiVersion; - if ( - JSON.stringify(sortedKeys(dependencies)) !== JSON.stringify(expectedDependencies) - || typeof dependencies[RUNTIME_PACKAGE] !== 'string' - || !/^\d+\.\d+\.\d+$/u.test(dependencies[RUNTIME_PACKAGE]) - || dependencies[FZSTD_PACKAGE] !== FZSTD_VERSION - || dependencies[JS_CORE_PACKAGE] !== '0.0.0' - || typeof nativeVersion !== 'string' - || !/^\d+\.\d+\.\d+$/u.test(nativeVersion) - || JSON.stringify(sortedKeys(optionalDependencies)) - !== JSON.stringify([...NATIVE_PACKAGES].sort(compareText)) - || NATIVE_PACKAGES.some((name) => optionalDependencies[name] !== nativeVersion) - || sortedKeys(manifest.peerDependencies).length !== 0 - || manifest.peerDependenciesMeta !== undefined - || JSON.stringify(manifest.bundledDependencies) !== JSON.stringify([JS_CORE_PACKAGE]) - || manifest.bundleDependencies !== undefined - ) { - fail( - `${label} must depend only on its bundled JavaScript core, portable runtime, decompressor, and native platform carriers`, - ); - } - const root = manifest.exports?.['.']; - const expectedExports = [ - '.', - './direct', - './worker', - './package.json', - './internal/tools', - './server', - './storage/bun', - './storage/deno', - './storage/indexed-db', - './storage/node', - './storage/opfs', - ].sort(compareText); - if (JSON.stringify(sortedKeys(manifest.exports)) !== JSON.stringify(expectedExports)) { - fail(`${label} exports do not match the deliberate public package surface`); - } - if ( - JSON.stringify(Object.keys(root ?? {})) - !== JSON.stringify(['types', 'deno', 'bun', 'node', 'browser', 'default']) - || root?.types !== './lib/index.d.ts' - || root?.deno !== './lib/index.deno.js' - || root?.bun !== './lib/index.bun.js' - || root?.browser !== './lib/index.js' - || root?.node !== './lib/index.node.js' - || root?.default !== './lib/index.js' - ) { - fail(`${label} must expose exact browser, Node, Bun, and Deno conditional entrypoints`); - } - const worker = manifest.exports?.['./worker']; - if ( - JSON.stringify(Object.keys(worker ?? {})) - !== JSON.stringify(['types', 'deno', 'bun', 'node', 'browser', 'default']) - || worker?.types !== './lib/worker-entry.d.ts' - || worker?.deno !== './lib/worker-entry.deno.js' - || worker?.bun !== './lib/worker-entry.bun.js' - || worker?.node !== './lib/worker-entry.node.js' - || worker?.browser !== './lib/worker-entry.js' - || worker?.default !== './lib/worker-entry.js' - ) { - fail(`${label} must expose the exact browser, Node, Bun, and Deno worker entrypoint`); - } - const direct = manifest.exports?.['./direct']; - if ( - JSON.stringify(Object.keys(direct ?? {})) - !== JSON.stringify(['types', 'deno', 'bun', 'node']) - || direct?.types !== './lib/direct.node.d.ts' - || direct?.deno !== './lib/direct.node.js' - || direct?.bun !== './lib/direct.node.js' - || direct?.node !== './lib/direct.node.js' - ) { - fail(`${label} must expose one exact host-only conditional direct entrypoint`); - } - const internalTools = manifest.exports?.['./internal/tools']; - if ( - internalTools?.types !== './lib/internal.d.ts' - || internalTools?.deno !== './lib/internal.node.js' - || internalTools?.bun !== './lib/internal.node.js' - || internalTools?.node !== './lib/internal.node.js' - || internalTools?.browser !== './lib/internal.js' - || internalTools?.default !== './lib/internal.js' - ) { - fail(`${label} must expose the exact version-locked optional-tools bridge`); - } - const server = manifest.exports?.['./server']; - if ( - JSON.stringify(Object.keys(server ?? {})) - !== JSON.stringify(['types', 'deno', 'bun', 'node']) - || server?.types !== './lib/server.node.d.ts' - || server?.deno !== './lib/server.node.js' - || server?.bun !== './lib/server.node.js' - || server?.node !== './lib/server.node.js' - ) { - fail(`${label} must expose one exact host-only conditional local-server entrypoint`); - } - const nodeStorage = manifest.exports?.['./storage/node']; - if ( - JSON.stringify(sortedKeys(nodeStorage)) !== JSON.stringify(['node', 'types']) - || nodeStorage?.types !== './lib/storage/node.d.ts' - || nodeStorage?.node !== './lib/storage/node.js' - || nodeStorage?.browser !== undefined - || nodeStorage?.default !== undefined - ) { - fail(`${label} must expose directory storage only under the Node condition`); - } - const bunStorage = manifest.exports?.['./storage/bun']; - if ( - bunStorage?.types !== './lib/storage/bun.d.ts' - || bunStorage?.bun !== './lib/storage/bun.js' - || sortedKeys(bunStorage).some((condition) => !['bun', 'types'].includes(condition)) - ) { - fail(`${label} must expose Bun directory storage only under the Bun condition`); - } - const denoStorage = manifest.exports?.['./storage/deno']; - if ( - denoStorage?.types !== './lib/storage/deno.d.ts' - || denoStorage?.deno !== './lib/storage/deno.js' - || sortedKeys(denoStorage).some((condition) => !['deno', 'types'].includes(condition)) - ) { - fail(`${label} must expose Deno directory storage only under the Deno condition`); - } - const indexedDbStorage = manifest.exports?.['./storage/indexed-db']; - if ( - JSON.stringify(sortedKeys(indexedDbStorage)) !== JSON.stringify(['default', 'types']) - || indexedDbStorage?.types !== './lib/storage/indexed-db.d.ts' - || indexedDbStorage?.default !== './lib/storage/indexed-db.js' - ) { - fail(`${label} must expose the exact IndexedDB storage entrypoint`); - } - const opfsStorage = manifest.exports?.['./storage/opfs']; - if ( - JSON.stringify(sortedKeys(opfsStorage)) !== JSON.stringify(['default', 'types']) - || opfsStorage?.types !== './lib/storage/opfs.d.ts' - || opfsStorage?.default !== './lib/storage/opfs.js' - ) { - fail(`${label} must expose the exact OPFS storage entrypoint`); - } - const packageJson = manifest.exports?.['./package.json']; - if ( - JSON.stringify(sortedKeys(packageJson)) !== JSON.stringify(['default']) - || packageJson?.default !== './package.json' - ) { - fail(`${label} must expose only its package.json at the package metadata entrypoint`); - } - if ( - manifest.engines?.node !== '>=22.13 <25' - || manifest.engines?.bun !== '>=1.3.14' - || manifest.engines?.deno !== '>=2.8.1' - ) { - fail(`${label} must declare the qualified Node, Bun, and Deno runtime floors`); - } - if ( - manifest.oliphaunt?.runtimeProduct !== 'liboliphaunt-wasix' - || manifest.oliphaunt?.runtimeVersion !== dependencies[RUNTIME_PACKAGE] - || manifest.oliphaunt?.wasixNapiProduct !== NATIVE_PRODUCT - || manifest.oliphaunt?.wasixAddonAbiVersion !== 1 - || manifest.oliphaunt?.nodeApiVersion !== 8 - || manifest.oliphaunt?.browserHost !== 'wasmer-js-patched' - || manifest.oliphaunt?.serverHost !== 'wasix-rust-napi' - ) { - fail(`${label} runtime compatibility metadata differs from its exact dependencies`); - } - return manifest; -} - -export function prepareWasixTypescriptPackage(packageDir) { - const root = path.resolve(packageDir); - const manifest = prepareProductPackage(root); - stageReleaseNotices(root, NOTICE_OPTIONS); - assertReleaseNoticesInDirectory(root, NOTICE_OPTIONS); - assertWasixTypescriptManifest(manifest, `${PACKAGE_NAME} staged package.json`); - return manifest; -} - -export function assertWasixTypescriptNpmArchive(archive) { - const file = path.resolve(archive); - assertReleaseNoticesInArchive(file, { - ...NOTICE_OPTIONS, - prefix: 'package', - label: path.basename(file), - }); - const entries = readPortableArchiveEntries(file); - assertJsCoreBundleInventory(entries.keys(), 'package/node_modules/@oliphaunt/js-core/'); - const requireFile = (name) => { - const entry = entries.get(`package/${name}`); - if (!entry?.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${path.basename(file)} is missing non-empty regular package/${name}`); - } - return Buffer.from(entry.data()); - }; - const manifest = assertWasixTypescriptManifest( - JSON.parse(requireFile('package.json').toString('utf8')), - `${path.basename(file)} package.json`, - ); - const packageFiles = [ - 'ARCHITECTURE.md', - 'CHANGELOG.md', - 'LICENSE', - 'README.md', - 'THIRD_PARTY_NOTICES.md', - 'lib', - ]; - if (JSON.stringify([...(manifest.files ?? [])].sort(compareText)) !== JSON.stringify(packageFiles)) { - fail(`${path.basename(file)} package.json files differ from the owned package roots`); - } - const allowedFiles = new Set(['package.json', ...manifest.files.filter((name) => name !== 'lib')]); - for (const [name, entry] of entries) { - if (entry.isSymbolicLink) fail(`${path.basename(file)} contains symbolic link ${name}`); - const relative = name.replace(/^package\//u, ''); - if ( - entry.isFile - && !allowedFiles.has(relative) - && !relative.startsWith('lib/') - && !relative.startsWith('node_modules/@oliphaunt/js-core/') - ) { - fail(`${path.basename(file)} contains file outside package.json files: ${name}`); - } - } - for (const name of manifest.files) { - if (name === 'lib' || (name === 'CHANGELOG.md' && manifest.version === '0.0.0')) continue; - requireFile(name); - } - const exportedFiles = new Set(); - const visit = (value) => { - if (typeof value === 'string' && value.startsWith('./')) exportedFiles.add(value.slice(2)); - else if (value && typeof value === 'object') Object.values(value).forEach(visit); - }; - visit(manifest.exports); - for (const name of exportedFiles) { - requireFile(name); - } - JSON.parse(requireFile('lib/host/provenance.json').toString('utf8')); - return manifest; -} diff --git a/tools/release/wasix-typescript-package.test.mjs b/tools/release/wasix-typescript-package.test.mjs deleted file mode 100644 index b282dd1d6..000000000 --- a/tools/release/wasix-typescript-package.test.mjs +++ /dev/null @@ -1,255 +0,0 @@ -import { describe, expect, test } from 'bun:test'; - -import { assertWasixTypescriptManifest } from './wasix-typescript-package.mjs'; - -function manifest() { - return { - name: '@oliphaunt/wasix-ts', - version: '1.2.3', - license: 'MIT', - type: 'module', - publishConfig: { access: 'public', provenance: true }, - dependencies: { - '@oliphaunt/js-core': '0.0.0', - '@oliphaunt/liboliphaunt-wasix': '1.2.3', - fzstd: '0.1.1', - }, - bundledDependencies: ['@oliphaunt/js-core'], - optionalDependencies: { - '@oliphaunt/wasix-napi-darwin-arm64': '1.2.3', - '@oliphaunt/wasix-napi-linux-arm64-gnu': '1.2.3', - '@oliphaunt/wasix-napi-linux-x64-gnu': '1.2.3', - '@oliphaunt/wasix-napi-win32-x64-msvc': '1.2.3', - }, - exports: { - '.': { - types: './lib/index.d.ts', - deno: './lib/index.deno.js', - bun: './lib/index.bun.js', - node: './lib/index.node.js', - browser: './lib/index.js', - default: './lib/index.js', - }, - './worker': { - types: './lib/worker-entry.d.ts', - deno: './lib/worker-entry.deno.js', - bun: './lib/worker-entry.bun.js', - node: './lib/worker-entry.node.js', - browser: './lib/worker-entry.js', - default: './lib/worker-entry.js', - }, - './direct': { - types: './lib/direct.node.d.ts', - deno: './lib/direct.node.js', - bun: './lib/direct.node.js', - node: './lib/direct.node.js', - }, - './internal/tools': { - types: './lib/internal.d.ts', - deno: './lib/internal.node.js', - bun: './lib/internal.node.js', - node: './lib/internal.node.js', - browser: './lib/internal.js', - default: './lib/internal.js', - }, - './server': { - types: './lib/server.node.d.ts', - deno: './lib/server.node.js', - bun: './lib/server.node.js', - node: './lib/server.node.js', - }, - './storage/node': { - types: './lib/storage/node.d.ts', - node: './lib/storage/node.js', - }, - './storage/bun': { - types: './lib/storage/bun.d.ts', - bun: './lib/storage/bun.js', - }, - './storage/deno': { - types: './lib/storage/deno.d.ts', - deno: './lib/storage/deno.js', - }, - './storage/indexed-db': { - types: './lib/storage/indexed-db.d.ts', - default: './lib/storage/indexed-db.js', - }, - './storage/opfs': { - types: './lib/storage/opfs.d.ts', - default: './lib/storage/opfs.js', - }, - './package.json': { - default: './package.json', - }, - }, - engines: { - node: '>=22.13 <25', - bun: '>=1.3.14', - deno: '>=2.8.1', - }, - oliphaunt: { - runtimeProduct: 'liboliphaunt-wasix', - runtimeVersion: '1.2.3', - wasixNapiProduct: 'oliphaunt-wasix-napi', - wasixNapiVersion: '1.2.3', - wasixAddonAbiVersion: 1, - nodeApiVersion: 8, - browserHost: 'wasmer-js-patched', - serverHost: 'wasix-rust-napi', - }, - }; -} - -describe('WASIX TypeScript package dependency contract', () => { - test('accepts the portable browser runtime and exact native platform carriers', () => { - expect(() => assertWasixTypescriptManifest(manifest())).not.toThrow(); - }); - - test('rejects a missing native platform carrier', () => { - const candidate = manifest(); - delete candidate.optionalDependencies['@oliphaunt/wasix-napi-linux-x64-gnu']; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - /must depend only/u, - ); - }); - - test('rejects a native platform carrier outside the pinned N-API release', () => { - const candidate = manifest(); - candidate.optionalDependencies['@oliphaunt/wasix-napi-linux-x64-gnu'] = '1.2.4'; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - /must depend only/u, - ); - }); - - test('rejects compatibility metadata that could route a server runtime back to Wasmer', () => { - const candidate = manifest(); - candidate.oliphaunt.serverHost = 'wasmer-js-patched'; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'runtime compatibility metadata differs from its exact dependencies', - ); - }); - - test('rejects a carrier ABI outside the qualified Node-API contract', () => { - const candidate = manifest(); - candidate.oliphaunt.nodeApiVersion = 9; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'runtime compatibility metadata differs from its exact dependencies', - ); - }); - - test('rejects a root condition order that lets Node shadow Deno or Bun', () => { - const candidate = manifest(); - candidate.exports['.'] = { - types: './lib/index.d.ts', - node: './lib/index.node.js', - deno: './lib/index.deno.js', - bun: './lib/index.bun.js', - browser: './lib/index.js', - default: './lib/index.js', - }; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'must expose exact browser, Node, Bun, and Deno conditional entrypoints', - ); - }); - - test('rejects a worker condition order that lets Node shadow Deno or Bun', () => { - const candidate = manifest(); - candidate.exports['./worker'] = { - types: './lib/worker-entry.d.ts', - node: './lib/worker-entry.node.js', - deno: './lib/worker-entry.deno.js', - bun: './lib/worker-entry.bun.js', - browser: './lib/worker-entry.js', - default: './lib/worker-entry.js', - }; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'must expose the exact browser, Node, Bun, and Deno worker entrypoint', - ); - }); - - test('rejects a server condition order that lets Node shadow Deno or Bun', () => { - const candidate = manifest(); - candidate.exports['./server'] = { - types: './lib/server.node.d.ts', - node: './lib/server.node.js', - deno: './lib/server.node.js', - bun: './lib/server.node.js', - }; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'must expose one exact host-only conditional local-server entrypoint', - ); - }); - - test('rejects a browser fallback for the host-only server', () => { - const candidate = manifest(); - candidate.exports['./server'].default = './lib/server.node.js'; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'must expose one exact host-only conditional local-server entrypoint', - ); - }); - - test('rejects a browser fallback for the blocking host-only direct placement', () => { - const candidate = manifest(); - candidate.exports['./direct'].default = './lib/direct.node.js'; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'must expose one exact host-only conditional direct entrypoint', - ); - }); - - test('rejects a cross-runtime directory storage fallback', () => { - const candidate = manifest(); - candidate.exports['./storage/deno'].default = './lib/storage/deno.js'; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'must expose Deno directory storage only under the Deno condition', - ); - }); - - test('rejects an accidental low-level query entrypoint', () => { - const candidate = manifest(); - candidate.exports['./query'] = { - types: './lib/query.d.ts', - default: './lib/query.js', - }; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'exports do not match the deliberate public package surface', - ); - }); - - test('rejects an extra Node storage export condition', () => { - const candidate = manifest(); - candidate.exports['./storage/node'].development = './lib/storage/node.js'; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'must expose directory storage only under the Node condition', - ); - }); - - test('rejects runtime floors outside the qualified envelope', () => { - const candidate = manifest(); - candidate.engines.bun = '>=1'; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - 'must declare the qualified Node, Bun, and Deno runtime floors', - ); - }); - - for (const [family, dependency] of [ - ['dependencies', 'unrelated'], - ['optionalDependencies', '@wasmer/sdk'], - ['peerDependencies', '@oliphaunt/native-host'], - ]) { - test(`rejects an extra ${family} entry`, () => { - const candidate = manifest(); - candidate[family] = { ...candidate[family], [dependency]: '1.0.0' }; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - /must depend only/u, - ); - }); - } - - test('rejects bundling anything except the JavaScript core', () => { - const candidate = manifest(); - candidate.bundledDependencies = ['fzstd']; - expect(() => assertWasixTypescriptManifest(candidate)).toThrow( - /must depend only/u, - ); - }); -}); diff --git a/tools/release/wasmer-llvm-matrix.test.mjs b/tools/release/wasmer-llvm-matrix.test.mjs deleted file mode 100644 index b4cb5c65b..000000000 --- a/tools/release/wasmer-llvm-matrix.test.mjs +++ /dev/null @@ -1,45 +0,0 @@ -import { describe, expect, test } from "bun:test"; - -import { liboliphauntWasixAotRuntimeMatrix } from "./artifact_target_matrix.mjs"; - -const expected = new Map([ - ["macos-arm64", { - archive: "llvm-darwin-aarch64.tar.xz", - sha256: "f64460f6c8a28876737402542fc5b28bb1f4262cef85f799b65ce2a7ee6f8847", - bytes: 479103872, - }], - ["linux-x64-gnu", { - archive: "llvm-linux-amd64.tar.xz", - sha256: "5fb1c687c5e895d517a23e7aabea9ec3557e3a3e33f8a8d3a8d21395157b3906", - bytes: 741670068, - }], - ["linux-arm64-gnu", { - archive: "llvm-linux-aarch64.tar.xz", - sha256: "1fddcf5b30f9d3e073eb161509220b4136ea8e2f114f23084bdec33e40fa87c1", - bytes: 668873496, - }], - ["windows-x64-msvc", { - archive: "llvm-windows-amd64.tar.xz", - sha256: "19ff22b0cf74b53dad2fc717db2209f8162b768fc6dede9e2caa6a83c724496e", - bytes: 757929860, - }], -]); - -describe("Wasmer LLVM AOT matrix", () => { - test("binds every supported host archive to its reviewed digest and exact size", () => { - const matrix = liboliphauntWasixAotRuntimeMatrix(); - expect(matrix.include).toHaveLength(expected.size); - for (const row of matrix.include) { - const pin = expected.get(row.target_id); - expect(pin, row.target_id).toBeDefined(); - expect(row.llvm_url).toBe( - `https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/${pin.archive}`, - ); - expect(row.llvm_sha256).toBe(pin.sha256); - expect(row.llvm_bytes).toBe(pin.bytes); - expect(row.llvm_sha256).toMatch(/^[0-9a-f]{64}$/u); - expect(row.llvm_bytes).toBeGreaterThan(0); - expect(row.llvm_bytes).toBeLessThanOrEqual(2 * 1024 * 1024 * 1024); - } - }); -}); diff --git a/tools/release/windows-extension-binary-contract.test.mjs b/tools/release/windows-extension-binary-contract.test.mjs deleted file mode 100644 index 1d5f9f79e..000000000 --- a/tools/release/windows-extension-binary-contract.test.mjs +++ /dev/null @@ -1,713 +0,0 @@ -import { afterEach, describe, expect, test } from "bun:test"; -import { - mkdtemp, - mkdir, - readFile, - readdir, - rm, - symlink, - writeFile, -} from "node:fs/promises"; -import { tmpdir } from "node:os"; -import path from "node:path"; - -import { - parseExtensionCatalog, - stageWindowsExtensionBinaryContract, - validateWindowsEmbeddedModuleImports, - validateWindowsExtensionArtifactBinaryContract, - validateWindowsServerModuleImports, -} from "../../src/extensions/artifacts/native/tools/stage-windows-binary-contract.mjs"; -import { validateExactArtifactBinaryContract } from "../../src/extensions/artifacts/native/tools/extension-artifact-packager.mjs"; -import { inspectPlatformBinaryTree } from "./platform-binary-contract.mjs"; -import { WINDOWS_VC_RUNTIME_DLLS } from "./windows-vc-runtime-closure.mjs"; -import { elfFixture, machoFixture } from "../test/release-fixture-utils.mjs"; - -const ROOT = path.resolve(import.meta.dir, "../.."); -const temporaryRoots = []; -const CATALOG_HEADER = [ - "sql_name", - "pg_major", - "creates_extension", - "native_module_stem", - "dependencies", - "shared_preload", - "desktop_prebuilt", - "mobile_prebuilt", - "mobile_static_registry_required", - "mobile_static_archive_targets", - "data_files", - "artifact", -].join("\t"); - -afterEach(async () => { - await Promise.all( - temporaryRoots - .splice(0) - .map((root) => rm(root, { recursive: true, force: true })), - ); -}); - -async function fixture(name) { - const root = await mkdtemp( - path.join(tmpdir(), `oliphaunt-windows-extension-contract-${name}-`), - ); - temporaryRoots.push(root); - return root; -} - -function catalog(...rows) { - return `${[CATALOG_HEADER, ...rows.map((row) => row.join("\t"))].join("\n")}\n`; -} - -const vectorRow = [ - "vector", - "18", - "yes", - "vector", - "-", - "-", - "yes", - "yes", - "yes", - "-", - "-", - "first-party", -]; -const postgisRow = [ - "postgis", - "18", - "yes", - "postgis-3", - "-", - "-", - "yes", - "yes", - "yes", - "-", - "-", - "first-party", -]; -const desktopOnlyRow = [ - "desktop_extension", - "18", - "yes", - "desktop_extension", - "-", - "-", - "yes", - "no", - "yes", - "-", - "-", - "contrib", -]; -const HOSTED_EARTHDISTANCE_IMPORTS = Object.freeze([ - "VCRUNTIME140.dll", - "api-ms-win-crt-math-l1-1-0.dll", - "api-ms-win-crt-runtime-l1-1-0.dll", - "KERNEL32.dll", -]); - -function pe({ - machine = 0x8664, - imports = ["KERNEL32.dll"], - delayImports = [], -} = {}) { - const peOffset = 0x80; - const optionalSize = 240; - const sectionTable = peOffset + 24 + optionalSize; - const rawOffset = 0x200; - const rawSize = 0x400; - const virtualAddress = 0x1000; - const buffer = Buffer.alloc(rawOffset + rawSize); - buffer.write("MZ", 0, "ascii"); - buffer.writeUInt32LE(peOffset, 0x3c); - buffer.write("PE\0\0", peOffset, "ascii"); - const coff = peOffset + 4; - buffer.writeUInt16LE(machine, coff); - buffer.writeUInt16LE(1, coff + 2); - buffer.writeUInt16LE(optionalSize, coff + 16); - buffer.writeUInt16LE(0x2022, coff + 18); - const optional = coff + 20; - buffer.writeUInt16LE(0x20b, optional); - buffer.writeBigUInt64LE(0x140000000n, optional + 24); - buffer.writeUInt32LE(rawOffset, optional + 60); - buffer.writeUInt32LE(16, optional + 108); - buffer.writeUInt32LE(virtualAddress, optional + 120); - buffer.writeUInt32LE((imports.length + 1) * 20, optional + 124); - if (delayImports.length > 0) { - const delayDescriptorOffset = rawOffset + 0x100; - buffer.writeUInt32LE( - virtualAddress + (delayDescriptorOffset - rawOffset), - optional + 216, - ); - buffer.writeUInt32LE( - (delayImports.length + 1) * 32, - optional + 220, - ); - } - buffer.write(".rdata\0\0", sectionTable, "ascii"); - buffer.writeUInt32LE(rawSize, sectionTable + 8); - buffer.writeUInt32LE(virtualAddress, sectionTable + 12); - buffer.writeUInt32LE(rawSize, sectionTable + 16); - buffer.writeUInt32LE(rawOffset, sectionTable + 20); - let nameOffset = rawOffset + 0x200; - for (const [index, name] of imports.entries()) { - buffer.writeUInt32LE( - virtualAddress + (nameOffset - rawOffset), - rawOffset + index * 20 + 12, - ); - buffer.write(`${name}\0`, nameOffset, "ascii"); - nameOffset += Buffer.byteLength(name) + 1; - } - for (const [index, name] of delayImports.entries()) { - const descriptor = rawOffset + 0x100 + index * 32; - buffer.writeUInt32LE(1, descriptor); - buffer.writeUInt32LE( - virtualAddress + (nameOffset - rawOffset), - descriptor + 4, - ); - buffer.write(`${name}\0`, nameOffset, "ascii"); - nameOffset += Buffer.byteLength(name) + 1; - } - return buffer; -} - -async function writeRuntimeFile(runtime, relative, data) { - const file = path.join(runtime, ...relative.split("/")); - await mkdir(path.dirname(file), { recursive: true }); - await writeFile(file, data); -} - -async function createProviderRuntime(runtime) { - for (const name of WINDOWS_VC_RUNTIME_DLLS) { - await writeRuntimeFile(runtime, `bin/${name}`, pe()); - } -} - -async function relativeFiles(root, relative = "") { - const files = []; - for (const entry of await readdir(path.join(root, relative), { - withFileTypes: true, - })) { - const child = relative ? `${relative}/${entry.name}` : entry.name; - if (entry.isDirectory()) files.push(...(await relativeFiles(root, child))); - else files.push(child); - } - return files.sort(); -} - -describe("desktop exact-extension post-strip binary qualification", () => { - test("validates both Linux profiles and rejects a corrupt or over-floor embedded module", async () => { - const root = await fixture("linux-exact-profiles"); - const artifact = path.join(root, "artifact"); - const server = "files/lib/postgresql/vector.so"; - const embedded = "files/lib/modules/vector.so"; - await writeRuntimeFile( - artifact, - server, - elfFixture({ machine: 62, requiredVersions: ["GLIBC_2.17"] }), - ); - await writeRuntimeFile( - artifact, - embedded, - elfFixture({ machine: 62, requiredVersions: ["GLIBC_2.27"] }), - ); - await writeRuntimeFile( - artifact, - "files/share/licenses/libcharset/COPYING.LIB", - Buffer.from("GNU LIBRARY GENERAL PUBLIC LICENSE\n"), - ); - const args = { - nativeModuleStem: "vector", - nativeTarget: "linux-x64-gnu", - }; - await expect(validateExactArtifactBinaryContract(artifact, args)).resolves.toMatchObject({ - target: "linux-x64-gnu", - binaries: 2, - }); - - await writeRuntimeFile( - artifact, - embedded, - elfFixture({ machine: 62, requiredVersions: ["GLIBC_2.39"] }), - ); - await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow( - /GLIBC_2\.39 exceeds/u, - ); - - await writeRuntimeFile(artifact, embedded, Buffer.from("truncated ELF")); - await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow( - /expected native binary is malformed or truncated/u, - ); - }); - - test("validates both macOS profiles against the exact post-strip minimum-OS floor", async () => { - const root = await fixture("macos-exact-profiles"); - const artifact = path.join(root, "artifact"); - const server = "files/lib/postgresql/vector.dylib"; - const embedded = "files/lib/modules/vector.dylib"; - await writeRuntimeFile(artifact, server, machoFixture({ minos: [11, 0, 0] })); - await writeRuntimeFile(artifact, embedded, machoFixture({ minos: [11, 0, 0] })); - const args = { - nativeModuleStem: "vector", - nativeTarget: "macos-arm64", - }; - await expect(validateExactArtifactBinaryContract(artifact, args)).resolves.toMatchObject({ - target: "macos-arm64", - binaries: 2, - }); - - await writeRuntimeFile(artifact, embedded, machoFixture({ minos: [14, 0, 0] })); - await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow( - /minimum OS 14\.0 exceeds/u, - ); - }); -}); - -describe("Windows exact-extension binary-contract staging", () => { - test("validates an explicitly selected desktop extension set while excluding every development/archive class", async () => { - const root = await fixture("selected"); - const runtime = path.join(root, "install"); - const output = path.join(root, "contract-view"); - await createProviderRuntime(runtime); - await writeRuntimeFile( - runtime, - "lib/postgresql/vector.dll", - pe({ imports: ["postgres.exe", "VCRUNTIME140.dll"] }), - ); - await writeRuntimeFile( - runtime, - "lib/postgresql/desktop_extension.dll", - pe({ imports: HOSTED_EARTHDISTANCE_IMPORTS }), - ); - await writeRuntimeFile( - runtime, - "lib/postgresql/postgis-3.dll", - pe({ machine: 0xaa64 }), - ); - const installedDevelopmentArchives = [ - "lib/libpgport.a", - "lib/libpgport_shlib.a", - "lib/libpgcommon.a", - "lib/libpgcommon_shlib.a", - "lib/libpq.a", - "lib/libpgfeutils.a", - "lib/libpgtypes.a", - "lib/libecpg.a", - "lib/libecpg_compat.a", - "lib/libpq.lib", - "lib/postgres.lib", - "lib/postgresql/pgevent.lib", - "lib/libpgtypes.lib", - "lib/libecpg.lib", - "lib/libecpg_compat.lib", - ]; - for (const relative of installedDevelopmentArchives) { - await writeRuntimeFile( - runtime, - relative, - Buffer.from("!\n", "ascii"), - ); - } - await writeRuntimeFile( - runtime, - "lib/libpgcommon.la", - "development metadata\n", - ); - await writeRuntimeFile( - runtime, - "lib/postgresql/pgevent.lib", - Buffer.from("!\n", "ascii"), - ); - await writeRuntimeFile(runtime, "bin/postgres.pdb", "debug symbols\n"); - await writeRuntimeFile( - runtime, - "include/postgresql/server/postgres.h", - "development header\n", - ); - - const result = await stageWindowsExtensionBinaryContract({ - runtimeRoot: runtime, - catalogText: catalog(vectorRow, postgisRow, desktopOnlyRow), - selectedSqlNames: "vector,desktop_extension", - outputRoot: output, - }); - - expect(result.schema).toBe( - "oliphaunt-windows-extension-binary-contract-v4", - ); - expect(result.standaloneBackendProvider).toBe("postgres.exe"); - expect(result.forbiddenEmbeddedBackendProvider).toBe("oliphaunt.dll"); - expect(result.extensionModules).toEqual([ - "desktop_extension.dll", - "vector.dll", - ]); - expect(result.serverBoundExtensionModules).toEqual(["vector.dll"]); - expect(result.hostNeutralServerModules).toEqual(["desktop_extension.dll"]); - expect(result.providerRuntimeDlls).toEqual([...WINDOWS_VC_RUNTIME_DLLS]); - expect(await relativeFiles(output)).toEqual( - [ - ...WINDOWS_VC_RUNTIME_DLLS.map((name) => `bin/${name}`), - "binary-contract-manifest.json", - "lib/postgresql/desktop_extension.dll", - "lib/postgresql/vector.dll", - ].sort(), - ); - const inspected = await inspectPlatformBinaryTree(output, { - target: "windows-x64-msvc", - windowsVcRuntimeProfile: "provider", - }); - expect(inspected.files).toContain("lib/postgresql/vector.dll"); - expect(inspected.files).toContain("lib/postgresql/desktop_extension.dll"); - expect(inspected.files).not.toContain("lib/postgresql/postgis-3.dll"); - for (const relative of installedDevelopmentArchives) { - expect(inspected.files).not.toContain(relative); - } - expect(inspected.binaries).toBe(WINDOWS_VC_RUNTIME_DLLS.length + 2); - }); - - test("still rejects a selected wrong-architecture extension DLL", async () => { - const root = await fixture("wrong-architecture"); - const runtime = path.join(root, "install"); - const output = path.join(root, "contract-view"); - await createProviderRuntime(runtime); - await writeRuntimeFile( - runtime, - "lib/postgresql/vector.dll", - pe({ machine: 0xaa64 }), - ); - await expect( - stageWindowsExtensionBinaryContract({ - runtimeRoot: runtime, - catalogText: catalog(vectorRow), - selectedSqlNames: "vector", - outputRoot: output, - }), - ).rejects.toThrow(/PE machine 0xaa64 is not x64/u); - }); - - test("classifies backend bindings from direct and delay import inventories, independent of module name", () => { - expect( - validateWindowsServerModuleImports( - pe({ imports: HOSTED_EARTHDISTANCE_IMPORTS }), - "earthdistance.dll", - ), - ).toMatchObject({ - backendProvider: "host-neutral", - hostNeutral: true, - serverBound: false, - }); - expect( - validateWindowsEmbeddedModuleImports( - pe({ imports: HOSTED_EARTHDISTANCE_IMPORTS }), - "earthdistance.dll", - ), - ).toMatchObject({ - backendProvider: "host-neutral", - hostNeutral: true, - providerBound: false, - }); - expect( - validateWindowsServerModuleImports( - pe({ imports: ["VCRUNTIME140.dll"], delayImports: ["PoStGrEs.ExE"] }), - "earthdistance.dll", - ), - ).toMatchObject({ - backendProvider: "postgres.exe", - hostNeutral: false, - serverBound: true, - }); - expect(() => - validateWindowsEmbeddedModuleImports( - pe({ imports: ["VCRUNTIME140.dll"], delayImports: ["PoStGrEs.ExE"] }), - "earthdistance.dll", - ), - ).toThrow(/imports postgres\.exe/u); - }); - - test("validates exact post-strip artifact bytes and never ignores an archive that enters the carrier", async () => { - const root = await fixture("exact-artifact"); - const runtime = path.join(root, "install"); - const artifact = path.join(root, "artifact"); - await createProviderRuntime(runtime); - await writeRuntimeFile( - artifact, - "files/lib/postgresql/vector.dll", - pe({ imports: ["postgres.exe", "VCRUNTIME140.dll"] }), - ); - await writeRuntimeFile( - artifact, - "files/lib/modules/vector.dll", - pe({ imports: ["oliphaunt.dll", "VCRUNTIME140.dll"] }), - ); - const neutralEarthdistance = pe({ - imports: HOSTED_EARTHDISTANCE_IMPORTS, - }); - await writeRuntimeFile( - artifact, - "files/lib/postgresql/earthdistance.dll", - neutralEarthdistance, - ); - await writeRuntimeFile( - artifact, - "files/lib/modules/earthdistance.dll", - neutralEarthdistance, - ); - await writeRuntimeFile( - artifact, - "files/share/postgresql/extension/vector.control", - "default_version = '0.8.2'\n", - ); - await writeRuntimeFile( - artifact, - "files/share/licenses/libcharset/COPYING.LIB", - "GNU LIBRARY GENERAL PUBLIC LICENSE\n", - ); - await writeRuntimeFile( - artifact, - "files/share/licenses/libiconv/COPYING.LIB", - "GNU LIBRARY GENERAL PUBLIC LICENSE\n", - ); - - const result = await validateWindowsExtensionArtifactBinaryContract({ - artifactRoot: artifact, - providerRuntimeRoot: runtime, - }); - expect(result.files).toContain("artifact/files/lib/postgresql/vector.dll"); - expect(result.files).toContain("artifact/files/lib/modules/vector.dll"); - expect(result.files).not.toContain( - "artifact/files/share/licenses/libcharset/COPYING.LIB", - ); - expect(result.files).not.toContain( - "artifact/files/share/licenses/libiconv/COPYING.LIB", - ); - expect(result.serverBoundExtensionModules).toEqual(["vector.dll"]); - expect(result.providerBoundEmbeddedModules).toEqual(["vector.dll"]); - expect(result.hostNeutralServerModules).toEqual(["earthdistance.dll"]); - expect(result.hostNeutralEmbeddedModules).toEqual(["earthdistance.dll"]); - expect(result.byteIdenticalHostNeutralModules).toEqual([ - "earthdistance.dll", - ]); - expect(result.profileBindings).toEqual({ - "earthdistance.dll": { - embedded: "host-neutral", - server: "host-neutral", - }, - "vector.dll": { - embedded: "oliphaunt.dll", - server: "postgres.exe", - }, - }); - expect(result.profileSha256["earthdistance.dll"].server).toBe( - result.profileSha256["earthdistance.dll"].embedded, - ); - expect(result.profileSha256["vector.dll"].server).not.toBe( - result.profileSha256["vector.dll"].embedded, - ); - - await writeRuntimeFile( - artifact, - "files/lib/accidental-development.a", - Buffer.from("!\n", "ascii"), - ); - await expect( - validateWindowsExtensionArtifactBinaryContract({ - artifactRoot: artifact, - providerRuntimeRoot: runtime, - }), - ).rejects.toThrow( - /static \.a archives are not permitted in a Windows release carrier/u, - ); - await rm(path.join(artifact, "files/lib/accidental-development.a")); - - await writeRuntimeFile( - artifact, - "files/lib/postgresql/vector.dll", - pe({ machine: 0xaa64 }), - ); - await expect( - validateWindowsExtensionArtifactBinaryContract({ - artifactRoot: artifact, - providerRuntimeRoot: runtime, - }), - ).rejects.toThrow(/PE machine 0xaa64 is not x64/u); - }); - - test("fails closed for unknown selections, missing modules, malformed catalogs, and overlapping output", async () => { - const root = await fixture("fail-closed"); - const runtime = path.join(root, "install"); - await createProviderRuntime(runtime); - - expect(() => parseExtensionCatalog(catalog(vectorRow), "missing")).toThrow( - /absent from the extension catalog/u, - ); - expect(() => - parseExtensionCatalog(`${CATALOG_HEADER}\nvector\t18\n`, "vector"), - ).toThrow(/has 2 columns/u); - await expect( - stageWindowsExtensionBinaryContract({ - runtimeRoot: runtime, - catalogText: catalog(vectorRow), - selectedSqlNames: "vector", - outputRoot: path.join(root, "contract-view"), - }), - ).rejects.toThrow( - /lib\/postgresql\/vector\.dll must be a real regular file/u, - ); - await expect( - stageWindowsExtensionBinaryContract({ - runtimeRoot: runtime, - catalogText: catalog(vectorRow), - selectedSqlNames: "vector", - outputRoot: path.join(runtime, "contract-view"), - }), - ).rejects.toThrow(/must not overlap/u); - - const runtimeAlias = path.join(root, "runtime-alias"); - await symlink( - runtime, - runtimeAlias, - process.platform === "win32" ? "junction" : "dir", - ); - await expect( - stageWindowsExtensionBinaryContract({ - runtimeRoot: runtime, - catalogText: catalog(vectorRow), - selectedSqlNames: "vector", - outputRoot: path.join(runtimeAlias, "missing-stage", "contract-view"), - }), - ).rejects.toThrow(/must not overlap/u); - expect(await readdir(runtime)).not.toContain("missing-stage"); - - const protectedOutput = path.join(root, "protected-output"); - await writeFile(protectedOutput, "do not replace\n"); - await expect( - stageWindowsExtensionBinaryContract({ - runtimeRoot: runtime, - catalogText: catalog(vectorRow), - selectedSqlNames: "vector", - outputRoot: protectedOutput, - }), - ).rejects.toThrow(/must be a real directory/u); - expect(await readFile(protectedOutput, "utf8")).toBe("do not replace\n"); - }); - - test("rejects direct and delay-loaded embedded-provider imports in the standalone server profile", async () => { - const root = await fixture("server-provider-confusion"); - const runtime = path.join(root, "install"); - const output = path.join(root, "contract-view"); - await createProviderRuntime(runtime); - await writeRuntimeFile( - runtime, - "lib/postgresql/vector.dll", - pe({ imports: ["oliphaunt.dll", "VCRUNTIME140.dll"] }), - ); - - await expect( - stageWindowsExtensionBinaryContract({ - runtimeRoot: runtime, - catalogText: catalog(vectorRow), - selectedSqlNames: "vector", - outputRoot: output, - }), - ).rejects.toThrow( - /imports oliphaunt\.dll; standalone PostgreSQL extension DLLs must not bind to the embedded provider/u, - ); - - await writeRuntimeFile( - runtime, - "lib/postgresql/vector.dll", - pe({ - imports: ["postgres.exe", "VCRUNTIME140.dll"], - delayImports: ["OlIpHaUnT.DlL"], - }), - ); - await expect( - stageWindowsExtensionBinaryContract({ - runtimeRoot: runtime, - catalogText: catalog(vectorRow), - selectedSqlNames: "vector", - outputRoot: output, - }), - ).rejects.toThrow( - /imports oliphaunt\.dll; standalone PostgreSQL extension DLLs must not bind to the embedded provider/u, - ); - }); - - test("accepts byte-identical neutral profiles but rejects every crossed provider and a missing profile", async () => { - const root = await fixture("exact-profile-confusion"); - const runtime = path.join(root, "install"); - const artifact = path.join(root, "artifact"); - await createProviderRuntime(runtime); - const neutral = pe({ imports: HOSTED_EARTHDISTANCE_IMPORTS }); - await writeRuntimeFile( - artifact, - "files/lib/postgresql/earthdistance.dll", - neutral, - ); - await writeRuntimeFile( - artifact, - "files/lib/modules/earthdistance.dll", - neutral, - ); - - await expect( - validateWindowsExtensionArtifactBinaryContract({ - artifactRoot: artifact, - providerRuntimeRoot: runtime, - }), - ).resolves.toMatchObject({ - byteIdenticalHostNeutralModules: ["earthdistance.dll"], - hostNeutralEmbeddedModules: ["earthdistance.dll"], - hostNeutralServerModules: ["earthdistance.dll"], - providerBoundEmbeddedModules: [], - serverBoundExtensionModules: [], - }); - - const crossed = pe({ imports: ["postgres.exe", "VCRUNTIME140.dll"] }); - await writeRuntimeFile(artifact, "files/lib/modules/earthdistance.dll", crossed); - await expect( - validateWindowsExtensionArtifactBinaryContract({ - artifactRoot: artifact, - providerRuntimeRoot: runtime, - }), - ).rejects.toThrow( - /imports postgres\.exe; embedded extension DLLs must not bind to the standalone server provider/u, - ); - - await writeRuntimeFile( - artifact, - "files/lib/modules/earthdistance.dll", - neutral, - ); - await writeRuntimeFile( - artifact, - "files/lib/postgresql/earthdistance.dll", - pe({ imports: ["oliphaunt.dll", "VCRUNTIME140.dll"] }), - ); - await expect( - validateWindowsExtensionArtifactBinaryContract({ - artifactRoot: artifact, - providerRuntimeRoot: runtime, - }), - ).rejects.toThrow( - /imports oliphaunt\.dll; standalone PostgreSQL extension DLLs must not bind to the embedded provider/u, - ); - - await writeRuntimeFile( - artifact, - "files/lib/postgresql/earthdistance.dll", - neutral, - ); - await rm(path.join(artifact, "files/lib/modules/earthdistance.dll")); - await expect( - validateWindowsExtensionArtifactBinaryContract({ - artifactRoot: artifact, - providerRuntimeRoot: runtime, - }), - ).rejects.toThrow(/missing embedded provider profile/u); - }); - -}); diff --git a/tools/release/windows-vc-runtime-closure.mjs b/tools/release/windows-vc-runtime-closure.mjs deleted file mode 100644 index 65509e55d..000000000 --- a/tools/release/windows-vc-runtime-closure.mjs +++ /dev/null @@ -1,646 +0,0 @@ -#!/usr/bin/env bun -import { createHash, randomUUID } from "node:crypto"; -import { - closeSync, - constants, - copyFileSync, - existsSync, - fsyncSync, - lstatSync, - mkdirSync, - openSync, - readFileSync, - readdirSync, - renameSync, - rmSync, - writeFileSync, -} from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; - -const TOOL = "windows-vc-runtime-closure.mjs"; -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); -const POLICY = JSON.parse( - readFileSync(path.join(ROOT, "tools/release/native-runtime-payload-policy.json"), "utf8"), -); -const PE_MACHINE_AMD64 = 0x8664; -const PE_MAGIC_32 = 0x10b; -const PE_MAGIC_64 = 0x20b; -// Treat every Microsoft C/C++ runtime family as policy-controlled. This makes -// debug/non-redistributable or future runtime imports fail closed instead of -// silently relying on whatever happens to be installed on a build host. -const VC_RUNTIME_IMPORT = /^(?:atl|concrt|mfc|mfcm|msvcp|ucrtbase|vcamp|vcomp|vcruntime)[a-z0-9_]*\.dll$/iu; -const CRT_DIRECTORY = "Microsoft.VC145.CRT"; - -export const WINDOWS_VC_RUNTIME_DLLS = Object.freeze( - [...POLICY.windowsVcRuntimeDlls].map((name) => String(name).toLowerCase()).sort(), -); -export const WINDOWS_VC_RUNTIME_PROFILES = Object.freeze( - Object.fromEntries( - Object.entries(POLICY.windowsVcRuntimeProfiles ?? {}).map(([profile, names]) => [ - profile, - Object.freeze([...names].map((name) => String(name).toLowerCase()).sort()), - ]), - ), -); -export const WINDOWS_VC_RUNTIME_RECEIPT = String(POLICY.windowsVcRuntimeReceipt); - -function failure(message) { - return new Error(`${TOOL}: ${message}`); -} - -function fail(message) { - console.error(`${TOOL}: ${message}`); - process.exit(1); -} - -function requireRange(buffer, offset, length, label) { - if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(length) || offset < 0 || length < 0 || offset + length > buffer.length) { - throw failure(`${label} is truncated at byte ${offset}`); - } -} - -function readAsciiZ(buffer, offset, label) { - requireRange(buffer, offset, 1, label); - const limit = Math.min(buffer.length, offset + 4096); - let end = offset; - while (end < limit && buffer[end] !== 0) { - const byte = buffer[end]; - if (byte < 0x20 || byte > 0x7e) { - throw failure(`${label} contains a non-ASCII import name`); - } - end += 1; - } - if (end === limit || buffer[end] !== 0) { - throw failure(`${label} has an unterminated import name`); - } - const value = buffer.subarray(offset, end).toString("ascii"); - if (!value || value.includes("/") || value.includes("\\")) { - throw failure(`${label} has an invalid import basename ${JSON.stringify(value)}`); - } - return value; -} - -function parsePortableExecutable(input, label = "portable executable") { - const buffer = Buffer.isBuffer(input) ? input : Buffer.from(input); - requireRange(buffer, 0, 0x40, label); - if (buffer.subarray(0, 2).toString("ascii") !== "MZ") { - throw failure(`${label} is not a PE image`); - } - const peOffset = buffer.readUInt32LE(0x3c); - requireRange(buffer, peOffset, 24, label); - if (!buffer.subarray(peOffset, peOffset + 4).equals(Buffer.from("PE\0\0", "binary"))) { - throw failure(`${label} has no PE signature`); - } - const coff = peOffset + 4; - const machine = buffer.readUInt16LE(coff); - const sectionCount = buffer.readUInt16LE(coff + 2); - const optionalSize = buffer.readUInt16LE(coff + 16); - const optional = coff + 20; - requireRange(buffer, optional, optionalSize, label); - const magic = buffer.readUInt16LE(optional); - if (magic !== PE_MAGIC_32 && magic !== PE_MAGIC_64) { - throw failure(`${label} has unsupported PE optional-header magic 0x${magic.toString(16)}`); - } - const imageBase = magic === PE_MAGIC_64 - ? Number(buffer.readBigUInt64LE(optional + 24)) - : buffer.readUInt32LE(optional + 28); - if (!Number.isSafeInteger(imageBase)) { - throw failure(`${label} has an unsupported image base`); - } - const dataDirectoryOffset = optional + (magic === PE_MAGIC_64 ? 112 : 96); - const directoryCountOffset = optional + (magic === PE_MAGIC_64 ? 108 : 92); - requireRange(buffer, directoryCountOffset, 4, label); - const directoryCount = buffer.readUInt32LE(directoryCountOffset); - - const sections = []; - let sectionOffset = optional + optionalSize; - for (let index = 0; index < sectionCount; index += 1) { - requireRange(buffer, sectionOffset, 40, label); - sections.push({ - virtualSize: buffer.readUInt32LE(sectionOffset + 8), - virtualAddress: buffer.readUInt32LE(sectionOffset + 12), - rawSize: buffer.readUInt32LE(sectionOffset + 16), - rawOffset: buffer.readUInt32LE(sectionOffset + 20), - }); - sectionOffset += 40; - } - - const rvaOffset = (rva, field) => { - for (const section of sections) { - const span = Math.max(section.virtualSize, section.rawSize); - if (rva >= section.virtualAddress && rva < section.virtualAddress + span) { - const delta = rva - section.virtualAddress; - if (delta >= section.rawSize) { - throw failure(`${label} ${field} points outside section file data`); - } - const offset = section.rawOffset + delta; - requireRange(buffer, offset, 1, label); - return offset; - } - } - throw failure(`${label} ${field} RVA 0x${rva.toString(16)} is not mapped by a section`); - }; - - const directory = (index) => { - if (directoryCount <= index || dataDirectoryOffset + (index + 1) * 8 > optional + optionalSize) { - return { rva: 0, size: 0 }; - } - return { - rva: buffer.readUInt32LE(dataDirectoryOffset + index * 8), - size: buffer.readUInt32LE(dataDirectoryOffset + index * 8 + 4), - }; - }; - - const imports = new Set(); - const normal = directory(1); - if (normal.rva !== 0) { - let descriptor = rvaOffset(normal.rva, "import directory"); - const end = normal.size > 0 ? Math.min(buffer.length, descriptor + normal.size) : buffer.length; - let terminated = false; - for (let count = 0; descriptor + 20 <= end && count < 4096; count += 1) { - requireRange(buffer, descriptor, 20, label); - const empty = buffer.subarray(descriptor, descriptor + 20).every((byte) => byte === 0); - if (empty) { - terminated = true; - break; - } - const nameRva = buffer.readUInt32LE(descriptor + 12); - if (nameRva === 0) { - throw failure(`${label} has an import descriptor without a DLL name`); - } - imports.add(readAsciiZ(buffer, rvaOffset(nameRva, "import name"), label)); - descriptor += 20; - } - if (!terminated) { - throw failure(`${label} has an unterminated import descriptor table`); - } - } - - const delayed = directory(13); - if (delayed.rva !== 0) { - let descriptor = rvaOffset(delayed.rva, "delay import directory"); - const end = delayed.size > 0 ? Math.min(buffer.length, descriptor + delayed.size) : buffer.length; - let terminated = false; - for (let count = 0; descriptor + 32 <= end && count < 4096; count += 1) { - requireRange(buffer, descriptor, 32, label); - const empty = buffer.subarray(descriptor, descriptor + 32).every((byte) => byte === 0); - if (empty) { - terminated = true; - break; - } - const attributes = buffer.readUInt32LE(descriptor); - const rawName = buffer.readUInt32LE(descriptor + 4); - const nameRva = (attributes & 1) !== 0 ? rawName : rawName - imageBase; - if (!Number.isSafeInteger(nameRva) || nameRva <= 0) { - throw failure(`${label} has an invalid delay-import DLL name`); - } - imports.add(readAsciiZ(buffer, rvaOffset(nameRva, "delay import name"), label)); - descriptor += 32; - } - if (!terminated) { - throw failure(`${label} has an unterminated delay-import descriptor table`); - } - } - - return { - machine, - magic, - imports: [...imports].sort(), - }; -} - -export function inspectPortableExecutable(input, label) { - const buffer = Buffer.isBuffer(input) ? input : readFileSync(input); - return parsePortableExecutable(buffer, label ?? String(input)); -} - -export function windowsVcRuntimeImports(input, label) { - return inspectPortableExecutable(input, label).imports.filter((name) => VC_RUNTIME_IMPORT.test(name)); -} - -function isRegularFile(file) { - try { - const stat = lstatSync(file); - return stat.isFile() && !stat.isSymbolicLink(); - } catch { - return false; - } -} - -function requireDirectory(directory, label) { - let stat; - try { - stat = lstatSync(directory); - } catch (error) { - throw failure(`${label} does not exist at ${directory}: ${error.message}`); - } - if (!stat.isDirectory() || stat.isSymbolicLink()) { - throw failure(`${label} must be a real directory: ${directory}`); - } -} - -function entriesByLowercase(directory) { - const result = new Map(); - for (const name of readdirSync(directory)) { - const key = name.toLowerCase(); - if (result.has(key)) { - throw failure(`${directory} has case-colliding entries ${result.get(key)} and ${name}`); - } - result.set(key, name); - } - return result; -} - -export function resolveInitializedVcRuntimeDirectory(redistRoot = process.env.VCToolsRedistDir) { - if (typeof redistRoot !== "string" || !redistRoot.trim()) { - throw failure("VCToolsRedistDir is not set; initialize the exact x64 MSVC developer environment first"); - } - const root = path.resolve(redistRoot); - requireDirectory(root, "VCToolsRedistDir"); - const x64 = path.join(root, "x64"); - requireDirectory(x64, "x64 VC redistributable directory"); - const candidates = readdirSync(x64, { withFileTypes: true }) - .filter((entry) => entry.isDirectory() && !entry.isSymbolicLink() && entry.name === CRT_DIRECTORY) - .map((entry) => path.join(x64, entry.name)) - .filter((directory) => { - const names = entriesByLowercase(directory); - return WINDOWS_VC_RUNTIME_DLLS.every((name) => names.has(name)); - }); - if (candidates.length !== 1) { - throw failure( - `${x64} must contain exactly one initialized ${CRT_DIRECTORY} directory with ${WINDOWS_VC_RUNTIME_DLLS.join(", ")}; found ${candidates.length}`, - ); - } - return candidates[0]; -} - -function requiredSource(sourceDirectory, expected) { - requireDirectory(sourceDirectory, "VC runtime source directory"); - const names = entriesByLowercase(sourceDirectory); - const actual = names.get(expected); - if (!actual) { - throw failure(`${sourceDirectory} is missing import-derived ${expected}`); - } - const source = path.join(sourceDirectory, actual); - if (!isRegularFile(source) || path.basename(source).toLowerCase() !== expected) { - throw failure(`${source} must be a regular file with exact basename ${expected}`); - } - const pe = inspectPortableExecutable(source); - if (pe.machine !== PE_MACHINE_AMD64 || pe.magic !== PE_MAGIC_64) { - throw failure( - `${source} is not an x64 PE32+ image (machine 0x${pe.machine.toString(16)}, magic 0x${pe.magic.toString(16)})`, - ); - } - return { expected, source, pe }; -} - -function sha256(file) { - return createHash("sha256").update(readFileSync(file)).digest("hex"); -} - -function copyAtomic(source, destination) { - mkdirSync(path.dirname(destination), { recursive: true }); - const sourceDigest = sha256(source); - if (existsSync(destination)) { - if (!isRegularFile(destination)) { - throw failure(`${destination} already exists and is not a regular file`); - } - if (sha256(destination) === sourceDigest) return; - } - const temporary = path.join( - path.dirname(destination), - `.${path.basename(destination)}.partial.${process.pid}.${randomUUID()}`, - ); - let descriptor; - try { - copyFileSync(source, temporary, constants.COPYFILE_EXCL); - // FlushFileBuffers requires a handle opened with write access on Windows. - // Bun forwards fsyncSync to that API, so reopening the copied file read-only - // makes an otherwise valid atomic stage fail with EPERM on Windows runners. - descriptor = openSync(temporary, "r+"); - fsyncSync(descriptor); - closeSync(descriptor); - descriptor = undefined; - if (sha256(temporary) !== sourceDigest) { - throw failure(`atomic copy of ${source} changed bytes before promotion`); - } - // libuv maps rename-over-file to an atomic replace on Windows. If the - // replace is denied (for example, a locked DLL), the old durable file is - // retained and the unique partial is removed in finally. - renameSync(temporary, destination); - } finally { - if (descriptor !== undefined) closeSync(descriptor); - rmSync(temporary, { force: true }); - } -} - -function writeAtomic(destination, content) { - mkdirSync(path.dirname(destination), { recursive: true }); - const temporary = path.join( - path.dirname(destination), - `.${path.basename(destination)}.partial.${process.pid}.${randomUUID()}`, - ); - let descriptor; - try { - descriptor = openSync(temporary, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o644); - writeFileSync(descriptor, content, "utf8"); - fsyncSync(descriptor); - closeSync(descriptor); - descriptor = undefined; - renameSync(temporary, destination); - } finally { - if (descriptor !== undefined) closeSync(descriptor); - rmSync(temporary, { force: true }); - } -} - -function checkedRuntimeImport(name, importer) { - const normalized = name.toLowerCase(); - if (!WINDOWS_VC_RUNTIME_DLLS.includes(normalized)) { - throw failure(`${importer} imports undeclared or debug VC runtime ${name}; update the audited production closure from actual binary evidence`); - } - return normalized; -} - -export function windowsVcRuntimeProfileNames(profile) { - if (profile === undefined || profile === null || profile === "") return []; - const names = WINDOWS_VC_RUNTIME_PROFILES[profile]; - if (names === undefined) { - throw failure( - `unknown VC runtime profile ${profile}; expected one of ${Object.keys(WINDOWS_VC_RUNTIME_PROFILES).sort().join(", ")}`, - ); - } - for (const name of names) checkedRuntimeImport(name, `VC runtime profile ${profile}`); - return [...names]; -} - -function carrierInventory(root) { - const inventory = []; - const direct = new Set(); - for (const file of walkRegularFiles(root)) { - if (!isPe(file)) continue; - const pe = inspectPortableExecutable(file); - if (pe.machine !== PE_MACHINE_AMD64 || pe.magic !== PE_MAGIC_64) { - throw failure( - `${file} is not an x64 PE32+ image (machine 0x${pe.machine.toString(16)}, magic 0x${pe.magic.toString(16)})`, - ); - } - const imports = pe.imports.filter((name) => VC_RUNTIME_IMPORT.test(name)); - const basename = path.basename(file).toLowerCase(); - if (!WINDOWS_VC_RUNTIME_DLLS.includes(basename)) { - for (const imported of imports) direct.add(checkedRuntimeImport(imported, file)); - } - inventory.push({ - file: path.relative(root, file).split(path.sep).join("/"), - vcRuntimeImports: imports, - }); - } - return { direct, inventory }; -} - -function closureFromSource(direct, sourceDirectory) { - const required = new Map(); - const pending = [...direct].sort(); - while (pending.length > 0) { - const name = pending.shift(); - if (required.has(name)) continue; - const source = requiredSource(sourceDirectory, name); - required.set(name, source); - for (const imported of source.pe.imports.filter((value) => VC_RUNTIME_IMPORT.test(value))) { - const dependency = checkedRuntimeImport(imported, source.source); - if (!required.has(dependency)) pending.push(dependency); - } - pending.sort(); - } - return required; -} - -function receiptText(required) { - return [...required] - .sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0) - .map(([name, { source }]) => `${sha256(source)} ${name}\n`) - .join(""); -} - -export function parseWindowsVcRuntimeReceipt(input, label = WINDOWS_VC_RUNTIME_RECEIPT) { - const text = Buffer.isBuffer(input) ? input.toString("utf8") : String(input); - const values = new Map(); - for (const [index, raw] of text.split(/\r?\n/u).entries()) { - if (!raw) continue; - const match = /^([0-9a-f]{64}) ([a-z0-9_]+\.dll)$/u.exec(raw); - if (!match) throw failure(`${label} has malformed line ${index + 1}`); - const [, digest, name] = match; - if (!WINDOWS_VC_RUNTIME_DLLS.includes(name) || values.has(name)) { - throw failure(`${label} has undeclared or duplicate entry ${name}`); - } - values.set(name, digest); - } - if (values.size === 0) throw failure(`${label} must not be empty`); - const sorted = [...values.keys()].sort(); - if (text !== sorted.map((name) => `${values.get(name)} ${name}\n`).join("")) { - throw failure(`${label} must be lowercase, sorted, and canonical`); - } - return values; -} - -function parseReceipt(directory) { - const receipt = path.join(directory, WINDOWS_VC_RUNTIME_RECEIPT); - if (!isRegularFile(receipt)) { - throw failure(`${directory} is missing regular VC runtime digest receipt ${WINDOWS_VC_RUNTIME_RECEIPT}`); - } - const values = parseWindowsVcRuntimeReceipt(readFileSync(receipt), receipt); - for (const [name, digest] of values) { - const file = path.join(directory, name); - if (!isRegularFile(file) || sha256(file) !== digest) { - throw failure(`${receipt} does not match regular ${file}`); - } - } - return values; -} - -function removeStaleRuntimeFiles(destination, requiredNames) { - const names = entriesByLowercase(destination); - for (const allowed of WINDOWS_VC_RUNTIME_DLLS) { - const actual = names.get(allowed); - if (actual === undefined || requiredNames.has(allowed)) continue; - const stale = path.join(destination, actual); - if (!isRegularFile(stale)) throw failure(`refusing to remove non-regular stale VC runtime ${stale}`); - rmSync(stale); - } -} - -export function stageWindowsVcRuntime({ root, redistRoot, sourceDirectory, destinations, profile }) { - const resolvedRoot = path.resolve(root); - requireDirectory(resolvedRoot, "dependency-closure root"); - if (!Array.isArray(destinations) || destinations.length === 0) { - throw failure("at least one destination is required"); - } - if (redistRoot !== undefined && sourceDirectory !== undefined) { - throw failure("redistRoot and sourceDirectory are mutually exclusive"); - } - const source = sourceDirectory === undefined - ? resolveInitializedVcRuntimeDirectory(redistRoot) - : path.resolve(sourceDirectory); - if (sourceDirectory !== undefined) parseReceipt(source); - const { direct } = carrierInventory(resolvedRoot); - for (const name of windowsVcRuntimeProfileNames(profile)) direct.add(name); - const sources = closureFromSource(direct, source); - const requiredNames = new Set(sources.keys()); - for (const destinationValue of destinations) { - const destination = path.resolve(destinationValue); - if (!within(resolvedRoot, destination)) { - throw failure(`VC runtime destination must stay within ${resolvedRoot}: ${destination}`); - } - mkdirSync(destination, { recursive: true }); - requireDirectory(destination, "VC runtime destination"); - for (const entry of sources.values()) { - copyAtomic(entry.source, path.join(destination, entry.expected)); - } - removeStaleRuntimeFiles(destination, requiredNames); - const receipt = path.join(destination, WINDOWS_VC_RUNTIME_RECEIPT); - if (sources.size === 0) rmSync(receipt, { force: true }); - else writeAtomic(receipt, receiptText(sources)); - } - return verifyWindowsVcRuntimeClosure({ root: resolvedRoot, searchRoots: destinations, profile }); -} - -function walkRegularFiles(root) { - const files = []; - const visit = (directory) => { - for (const entry of readdirSync(directory, { withFileTypes: true })) { - const file = path.join(directory, entry.name); - if (entry.isSymbolicLink()) { - throw failure(`dependency-closure root contains a symbolic link: ${file}`); - } - if (entry.isDirectory()) visit(file); - else if (entry.isFile()) files.push(file); - } - }; - visit(root); - return files.sort(); -} - -function isPe(file) { - if (!isRegularFile(file)) return false; - const buffer = readFileSync(file); - return buffer.length >= 2 && buffer[0] === 0x4d && buffer[1] === 0x5a; -} - -function within(parent, child) { - const relative = path.relative(parent, child); - return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative)); -} - -export function verifyWindowsVcRuntimeClosure({ root, searchRoots, profile }) { - const resolvedRoot = path.resolve(root); - requireDirectory(resolvedRoot, "dependency-closure root"); - if (!Array.isArray(searchRoots) || searchRoots.length === 0) { - throw failure("at least one dependency search root is required"); - } - const resolvedSearchRoots = searchRoots.map((value) => path.resolve(value)); - const { direct, inventory } = carrierInventory(resolvedRoot); - for (const name of windowsVcRuntimeProfileNames(profile)) direct.add(name); - const sourceRoot = resolvedSearchRoots[0]; - const required = closureFromSource(direct, sourceRoot); - const expected = new Set(required.keys()); - for (const searchRoot of resolvedSearchRoots) { - if (!within(resolvedRoot, searchRoot)) { - throw failure(`dependency search root must stay within ${resolvedRoot}: ${searchRoot}`); - } - requireDirectory(searchRoot, "dependency search root"); - const names = entriesByLowercase(searchRoot); - const actual = new Set(WINDOWS_VC_RUNTIME_DLLS.filter((name) => names.has(name))); - const missing = [...expected].filter((name) => !actual.has(name)); - const extra = [...actual].filter((name) => !expected.has(name)); - if (missing.length > 0 || extra.length > 0) { - throw failure(`${searchRoot} VC runtime closure mismatch; missing [${missing.sort().join(", ")}], extra [${extra.sort().join(", ")}]`); - } - if (expected.size === 0) { - if (names.has(WINDOWS_VC_RUNTIME_RECEIPT.toLowerCase())) { - throw failure(`${searchRoot} has a VC runtime receipt but its carrier imports no VC runtime`); - } - continue; - } - const receipt = parseReceipt(searchRoot); - if ([...receipt.keys()].sort().join("\0") !== [...expected].sort().join("\0")) { - throw failure(`${searchRoot} digest receipt does not exactly describe its import-derived VC runtime closure`); - } - } - return { required: [...expected].sort(), inventory }; -} - -function parseArgs(argv) { - const command = argv[0]; - const args = { - command, - redistRoot: undefined, - sourceDirectory: undefined, - profile: undefined, - destinations: [], - root: undefined, - searchRoots: [], - json: false, - printRequired: false, - }; - for (let index = 1; index < argv.length; index += 1) { - const flag = argv[index]; - if (flag === "--json") { - args.json = true; - continue; - } - if (flag === "--print-required") { - args.printRequired = true; - continue; - } - const value = argv[++index]; - if (value === undefined) throw failure(`${flag} requires a value`); - if (flag === "--redist-root") args.redistRoot = value; - else if (flag === "--source-dir") args.sourceDirectory = value; - else if (flag === "--destination") args.destinations.push(value); - else if (flag === "--profile") args.profile = value; - else if (flag === "--root") args.root = value; - else if (flag === "--search-root") args.searchRoots.push(value); - else throw failure(`unknown argument ${flag}`); - } - return args; -} - -function usage() { - return `Usage: - ${TOOL} stage --root DIR [--redist-root DIR | --source-dir DIR] [--profile NAME] --destination DIR [--destination DIR ...] [--print-required] - ${TOOL} verify --root DIR [--profile NAME] --search-root DIR [--search-root DIR ...] [--json] [--print-required] -`; -} - -export function main(argv = process.argv.slice(2)) { - let args; - try { - args = parseArgs(argv); - if (args.command === "stage") { - if (!args.root) throw failure("stage requires --root"); - const result = stageWindowsVcRuntime({ - root: args.root, - redistRoot: args.redistRoot, - sourceDirectory: args.sourceDirectory, - destinations: args.destinations, - profile: args.profile, - }); - if (args.printRequired) console.log(result.required.join(",")); - return; - } - if (args.command === "verify") { - if (!args.root) throw failure("verify requires --root"); - const result = verifyWindowsVcRuntimeClosure({ root: args.root, searchRoots: args.searchRoots, profile: args.profile }); - if (args.json) console.log(JSON.stringify(result, null, 2)); - if (args.printRequired) console.log(result.required.join(",")); - return; - } - console.error(usage()); - process.exit(2); - } catch (error) { - fail(error instanceof Error ? error.message.replace(`${TOOL}: `, "") : String(error)); - } -} - -if (import.meta.main) main(); diff --git a/tools/release/windows-vc-runtime-closure.test.mjs b/tools/release/windows-vc-runtime-closure.test.mjs deleted file mode 100644 index d1e26e290..000000000 --- a/tools/release/windows-vc-runtime-closure.test.mjs +++ /dev/null @@ -1,254 +0,0 @@ -import { strict as assert } from "node:assert"; -import { chmodSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { tmpdir } from "node:os"; -import path from "node:path"; -import { describe, test } from "node:test"; - -import { - WINDOWS_VC_RUNTIME_DLLS, - WINDOWS_VC_RUNTIME_PROFILES, - WINDOWS_VC_RUNTIME_RECEIPT, - inspectPortableExecutable, - resolveInitializedVcRuntimeDirectory, - stageWindowsVcRuntime, - verifyWindowsVcRuntimeClosure, -} from "./windows-vc-runtime-closure.mjs"; - -function pe({ machine = 0x8664, imports = [], delayImports = [] } = {}) { - const buffer = Buffer.alloc(0x800); - buffer.write("MZ", 0, "ascii"); - buffer.writeUInt32LE(0x80, 0x3c); - buffer.write("PE\0\0", 0x80, "binary"); - const coff = 0x84; - buffer.writeUInt16LE(machine, coff); - buffer.writeUInt16LE(1, coff + 2); - buffer.writeUInt16LE(0xf0, coff + 16); - const optional = coff + 20; - buffer.writeUInt16LE(0x20b, optional); - buffer.writeBigUInt64LE(0x140000000n, optional + 24); - buffer.writeUInt32LE(16, optional + 108); - const directories = optional + 112; - const section = optional + 0xf0; - buffer.write(".rdata", section, "ascii"); - buffer.writeUInt32LE(0x600, section + 8); - buffer.writeUInt32LE(0x1000, section + 12); - buffer.writeUInt32LE(0x600, section + 16); - buffer.writeUInt32LE(0x200, section + 20); - - let strings = 0x600; - const writeName = (name) => { - const offset = strings; - buffer.write(`${name}\0`, offset, "ascii"); - strings += Buffer.byteLength(name) + 1; - return 0x1000 + offset - 0x200; - }; - if (imports.length > 0) { - buffer.writeUInt32LE(0x1000, directories + 8); - buffer.writeUInt32LE((imports.length + 1) * 20, directories + 12); - imports.forEach((name, index) => buffer.writeUInt32LE(writeName(name), 0x200 + index * 20 + 12)); - } - if (delayImports.length > 0) { - const delayRva = 0x1200; - buffer.writeUInt32LE(delayRva, directories + 13 * 8); - buffer.writeUInt32LE((delayImports.length + 1) * 32, directories + 13 * 8 + 4); - delayImports.forEach((name, index) => { - const descriptor = 0x400 + index * 32; - buffer.writeUInt32LE(1, descriptor); - buffer.writeUInt32LE(writeName(name), descriptor + 4); - }); - } - return buffer.subarray(0, strings); -} - -function fixture() { - const root = mkdtempSync(path.join(tmpdir(), "oliphaunt-vc-runtime-")); - const redist = path.join(root, "redist"); - const source = path.join(redist, "x64/Microsoft.VC145.CRT"); - mkdirSync(source, { recursive: true }); - for (const name of WINDOWS_VC_RUNTIME_DLLS) { - writeFileSync(path.join(source, name), pe({ imports: ["KERNEL32.dll"] })); - } - return { root, redist, source }; -} - -describe("Windows VC runtime dependency closure", () => { - test("parses normal and delay-load imports without an external Windows tool", () => { - const parsed = inspectPortableExecutable(pe({ - imports: ["VCRUNTIME140.dll"], - delayImports: ["MSVCP140.dll"], - }), "fixture"); - assert.equal(parsed.machine, 0x8664); - assert.equal(parsed.magic, 0x20b); - assert.deepEqual(parsed.imports, ["MSVCP140.dll", "VCRUNTIME140.dll"]); - }); - - test("the provider profile carries the exact supported-extension union", () => { - const { root, redist } = fixture(); - try { - const carrier = path.join(root, "carrier"); - const bin = path.join(carrier, "bin"); - mkdirSync(bin, { recursive: true }); - writeFileSync(path.join(bin, "oliphaunt.dll"), pe({ imports: ["VCRUNTIME140.dll"] })); - const result = stageWindowsVcRuntime({ - root: carrier, - redistRoot: redist, - destinations: [bin], - profile: "provider", - }); - assert.deepEqual(result.required, WINDOWS_VC_RUNTIME_PROFILES.provider); - assert.deepEqual( - readFileSync(path.join(bin, WINDOWS_VC_RUNTIME_RECEIPT), "utf8").trim().split("\n").map((line) => line.split(" ")[1]), - WINDOWS_VC_RUNTIME_PROFILES.provider, - ); - assert.throws( - () => verifyWindowsVcRuntimeClosure({ root: carrier, searchRoots: [bin] }), - /extra \[msvcp140\.dll, vcruntime140_1\.dll\]/u, - ); - assert.deepEqual( - verifyWindowsVcRuntimeClosure({ root: carrier, searchRoots: [bin], profile: "provider" }).required, - WINDOWS_VC_RUNTIME_PROFILES.provider, - ); - } finally { - rmSync(root, { recursive: true, force: true }); - } - }); - - test("resolves exactly one initialized x64 CRT and atomically stages the audited union", () => { - const { root, redist, source } = fixture(); - try { - assert.equal(resolveInitializedVcRuntimeDirectory(redist), source); - const first = path.join(root, "stage/bin"); - const second = path.join(root, "stage/runtime/bin"); - mkdirSync(path.join(root, "stage"), { recursive: true }); - writeFileSync(path.join(root, "stage/app.exe"), pe({ imports: ["VCRUNTIME140.dll"] })); - stageWindowsVcRuntime({ root: path.join(root, "stage"), redistRoot: redist, destinations: [first, second] }); - stageWindowsVcRuntime({ root: path.join(root, "stage"), redistRoot: redist, destinations: [first, second] }); - assert.deepEqual(readFileSync(path.join(first, "vcruntime140.dll")), readFileSync(path.join(source, "vcruntime140.dll"))); - assert.deepEqual(readFileSync(path.join(second, "vcruntime140.dll")), readFileSync(path.join(source, "vcruntime140.dll"))); - assert.match(readFileSync(path.join(first, WINDOWS_VC_RUNTIME_RECEIPT), "utf8"), /^[0-9a-f]{64} vcruntime140\.dll\n$/u); - assert.equal(WINDOWS_VC_RUNTIME_DLLS.filter((name) => name !== "vcruntime140.dll").some((name) => readFileSync(path.join(first, WINDOWS_VC_RUNTIME_RECEIPT), "utf8").includes(name)), false); - } finally { - rmSync(root, { recursive: true, force: true }); - } - }); - - test("requires the exact VC145 redistributable directory and x64 source DLLs", () => { - const { root, redist, source } = fixture(); - try { - rmSync(source, { recursive: true, force: true }); - const duplicate = path.join(redist, "x64/Microsoft.VC143.CRT"); - mkdirSync(duplicate, { recursive: true }); - for (const name of WINDOWS_VC_RUNTIME_DLLS) writeFileSync(path.join(duplicate, name), pe()); - assert.throws(() => resolveInitializedVcRuntimeDirectory(redist), /exactly one initialized/u); - rmSync(duplicate, { recursive: true, force: true }); - mkdirSync(source, { recursive: true }); - for (const name of WINDOWS_VC_RUNTIME_DLLS) writeFileSync(path.join(source, name), pe()); - writeFileSync(path.join(source, WINDOWS_VC_RUNTIME_DLLS[0]), pe({ machine: 0x14c })); - const carrier = path.join(root, "carrier"); - mkdirSync(carrier); - writeFileSync(path.join(carrier, "app.exe"), pe({ imports: [WINDOWS_VC_RUNTIME_DLLS[0]] })); - assert.throws( - () => stageWindowsVcRuntime({ root: carrier, redistRoot: redist, destinations: [path.join(carrier, "bin")] }), - /not an x64 PE32\+ image/u, - ); - const pe32 = pe(); - pe32.writeUInt16LE(0x10b, 0x98); - writeFileSync(path.join(source, WINDOWS_VC_RUNTIME_DLLS[0]), pe32); - assert.throws( - () => stageWindowsVcRuntime({ root: carrier, redistRoot: redist, destinations: [path.join(carrier, "bin")] }), - /not an x64 PE32\+ image/u, - ); - } finally { - rmSync(root, { recursive: true, force: true }); - } - }); - - test("atomically replaces a stale regular destination from the initialized toolchain", () => { - const { root, redist, source } = fixture(); - try { - const destination = path.join(root, "out"); - mkdirSync(destination); - writeFileSync(path.join(destination, "app.exe"), pe({ imports: [WINDOWS_VC_RUNTIME_DLLS[0]] })); - stageWindowsVcRuntime({ root: destination, redistRoot: redist, destinations: [destination] }); - writeFileSync(path.join(destination, WINDOWS_VC_RUNTIME_DLLS[0]), "tampered"); - stageWindowsVcRuntime({ root: destination, redistRoot: redist, destinations: [destination] }); - assert.deepEqual( - readFileSync(path.join(destination, WINDOWS_VC_RUNTIME_DLLS[0])), - readFileSync(path.join(source, WINDOWS_VC_RUNTIME_DLLS[0])), - ); - } finally { - rmSync(root, { recursive: true, force: true }); - } - }); - - test("binary stripping cannot mutate redistributable bytes or invalidate their receipt", () => { - if (process.platform === "win32") return; - const { root, redist } = fixture(); - try { - const carrier = path.join(root, "carrier"); - const bin = path.join(carrier, "bin"); - mkdirSync(bin, { recursive: true }); - const producer = path.join(bin, "app.exe"); - const runtime = path.join(bin, "vcruntime140.dll"); - const receipt = path.join(bin, WINDOWS_VC_RUNTIME_RECEIPT); - writeFileSync(producer, pe({ imports: ["VCRUNTIME140.dll"] })); - stageWindowsVcRuntime({ root: carrier, redistRoot: redist, destinations: [bin] }); - const runtimeBefore = readFileSync(runtime); - const receiptBefore = readFileSync(receipt); - const producerBefore = readFileSync(producer); - const fakeStrip = path.join(root, "fake-strip.sh"); - writeFileSync(fakeStrip, "#!/bin/sh\nfor value do last=$value; done\nprintf X >> \"$last\"\n"); - chmodSync(fakeStrip, 0o755); - const result = spawnSync( - process.execPath, - ["tools/release/strip_native_release_binaries.mjs", "--target", "windows-x64-msvc", carrier], - { - cwd: path.resolve(import.meta.dir, "../.."), - env: { ...process.env, OLIPHAUNT_PE_STRIP: fakeStrip }, - encoding: "utf8", - }, - ); - assert.equal(result.status, 0, result.stderr); - assert.notDeepEqual(readFileSync(producer), producerBefore); - assert.deepEqual(readFileSync(runtime), runtimeBefore); - assert.deepEqual(readFileSync(receipt), receiptBefore); - assert.match(result.stderr, /preservedAppLocalVcRuntime=.*vcruntime140\.dll/u); - verifyWindowsVcRuntimeClosure({ root: carrier, searchRoots: [bin] }); - } finally { - rmSync(root, { recursive: true, force: true }); - } - }); - - test("rejects a missing app-local DLL and an undeclared future VC runtime import", () => { - const { root, redist } = fixture(); - try { - const payload = path.join(root, "payload"); - const bin = path.join(payload, "bin"); - mkdirSync(bin, { recursive: true }); - writeFileSync(path.join(bin, "postgres.exe"), pe({ imports: ["VCRUNTIME140.dll"] })); - stageWindowsVcRuntime({ root: payload, redistRoot: redist, destinations: [bin] }); - assert.equal(verifyWindowsVcRuntimeClosure({ root: payload, searchRoots: [bin] }).inventory.length, 2); - - rmSync(path.join(bin, "vcruntime140.dll")); - assert.throws( - () => verifyWindowsVcRuntimeClosure({ root: payload, searchRoots: [bin] }), - /is missing import-derived vcruntime140\.dll/u, - ); - writeFileSync(path.join(bin, "vcruntime140.dll"), pe()); - writeFileSync(path.join(bin, "future.dll"), pe({ delayImports: ["MSVCP999.dll"] })); - assert.throws( - () => verifyWindowsVcRuntimeClosure({ root: payload, searchRoots: [bin] }), - /imports undeclared or debug VC runtime MSVCP999\.dll/u, - ); - rmSync(path.join(bin, "future.dll")); - writeFileSync(path.join(bin, "debug.dll"), pe({ imports: ["ucrtbased.dll"] })); - assert.throws( - () => verifyWindowsVcRuntimeClosure({ root: payload, searchRoots: [bin] }), - /imports undeclared or debug VC runtime ucrtbased\.dll/u, - ); - } finally { - rmSync(root, { recursive: true, force: true }); - } - }); -}); diff --git a/tools/release/with-product-history.sh b/tools/release/with-product-history.sh new file mode 100644 index 000000000..e287c4a31 --- /dev/null +++ b/tools/release/with-product-history.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +set -euo pipefail +owner="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +[[ "$#" -ge 5 ]] || { echo 'usage: with-product-history.sh REPO HEAD BASE GRAPH COMMAND [ARGS...]' >&2; exit 2; } +repo="$(cd -P "$1" && pwd)"; head_ref="$2"; base_ref="$3"; graph="$4"; shift 4 +state="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-product-history.XXXXXX")" +trap 'rm -rf "$state"' EXIT +export OLIPHAUNT_PRODUCT_HISTORY="$state" +reader="$owner/release-history.mts" +bash "$owner/../dev/bun.sh" "$owner/release-graph.mts" --history-inputs "$repo" "$graph" +head="$(git -C "$repo" rev-parse --verify "$head_ref^{commit}")" +empty=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +printf '%s\0%s\0%s\0' "$repo" "$head_ref" "$head" > "$state/context" +printf '%s\0%s\0%s\0%s\0%s\0%s\0' "$head_ref" "$head" "$head" "$head" "$empty" "$empty" > "$state/refs" +mkdir -p "$state/trees/$head" "$state/changes" +: > "$state/ancestors" +: > "$state/latest" +record_ref() { + local ref="$1" commit + commit="$(git -C "$repo" rev-parse --verify --quiet "$ref^{commit}" || true)" + printf '%s\0%s\0' "$ref" "$commit" >> "$state/refs" + if [[ -n "$commit" ]]; then + printf '%s\0%s\0' "$commit" "$commit" >> "$state/refs" + mkdir -p "$state/trees/$commit" + if git -C "$repo" merge-base --is-ancestor "$commit" "$head"; then printf '%s\n' "$commit" >> "$state/ancestors"; fi + fi +} +record_diff() { + local base="$1" commit="$1" + if [[ "$base" != "$empty" ]]; then commit="$(git -C "$repo" rev-parse --verify "$base^{commit}")"; fi + [[ ! -f "$state/changes/$commit" ]] || return 0 + if [[ "$base" == "$empty" ]]; then + git -C "$repo" diff --name-only -z "$empty" "$head" -- > "$state/changes/$commit" + else + git -C "$repo" diff --name-only -z "$commit...$head" -- > "$state/changes/$commit" + fi +} +record_diff "$empty" +if [[ -n "$base_ref" && "$base_ref" != "$empty" ]]; then record_ref "$base_ref"; record_diff "$base_ref"; fi +while IFS= read -r -d '' prefix; do + tag="$(git -C "$repo" describe --tags --abbrev=0 --match "${prefix}[0-9]*" "$head" 2>/dev/null || true)" + printf '%s\0%s\0' "$prefix" "$tag" >> "$state/latest" + if [[ -n "$tag" ]]; then record_ref "$tag"; record_diff "$tag"; fi +done < "$state/prefixes" +while IFS= read -r -d '' ref; do record_ref "$ref"; done < "$state/current-tags" +release="$(git -C "$repo" log -1 --format=%H '--grep=^chore(release): ' "$head" -- .release-please-manifest.json)" +if [[ -n "$release" ]]; then record_ref "$release"; fi +for directory in "$state"/trees/*; do + git -C "$repo" ls-tree -r -z --name-only "$(basename "$directory")" > "$directory/files" + if git -C "$repo" cat-file -e "$(basename "$directory"):release-please-config.json" 2>/dev/null; then + mkdir -p "$directory/blobs" + git -C "$repo" show "$(basename "$directory"):release-please-config.json" > "$directory/blobs/release-please-config.json" + fi +done +bash "$owner/../dev/bun.sh" "$reader" files +for directory in "$state"/trees/*; do + commit="$(basename "$directory")" + while IFS= read -r -d '' file; do + mkdir -p "$directory/blobs/$(dirname "$file")" + git -C "$repo" show "$commit:$file" > "$directory/blobs/$file" + done < "$directory/selected" +done +"$@" diff --git a/tools/release/with-release-history.sh b/tools/release/with-release-history.sh new file mode 100644 index 000000000..31582b594 --- /dev/null +++ b/tools/release/with-release-history.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail +owner="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +[[ "$#" -ge 3 ]] || { echo 'usage: with-release-history.sh REPO REF COMMAND [ARGS...]' >&2; exit 2; } +repo="$(cd -P "$1" && pwd)"; ref="$2"; shift 2 +state="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-release-history.XXXXXX")" +trap 'rm -rf "$state"' EXIT +export OLIPHAUNT_RELEASE_HISTORY="$state" +head="$(git -C "$repo" rev-parse --verify "$ref^{commit}")" +release="$(git -C "$repo" log -1 --format=%H '--grep=^chore(release): ' "$head" -- .release-please-manifest.json)" +printf '%s\0%s\0%s\0%s\0' "$repo" "$ref" "$head" "$release" > "$state/context" +for commit in "$head" "$release"; do + [[ -n "$commit" && ! -f "$state/$commit/ancestry" ]] || continue + mkdir -p "$state/$commit" + git -C "$repo" rev-list --parents -n 1 "$commit" > "$state/$commit/ancestry" + git -C "$repo" show -s --format=%s "$commit" > "$state/$commit/subject" + read -r _ parent extra < "$state/$commit/ancestry" + if [[ -n "$parent" && -z "$extra" ]]; then + mkdir -p "$state/$parent" + git -C "$repo" diff --no-renames --name-only --diff-filter=ACDMRT -z "$parent" "$commit" -- > "$state/$commit/changed" + fi +done +for directory in "$state"/*/; do + commit="$(basename "$directory")" + git -C "$repo" ls-tree -r -z --name-only "$commit" > "$directory/files" + if git -C "$repo" cat-file -e "$commit:release-please-config.json" 2>/dev/null; then + git -C "$repo" show "$commit:release-please-config.json" > "$directory/config.json" + fi +done +bash "$owner/../dev/bun.sh" "$owner/verify-release-commit.mts" --snapshot-paths +for directory in "$state"/*/; do + commit="$(basename "$directory")" + while IFS= read -r -d '' file; do + mkdir -p "$directory/blobs/$(dirname "$file")" + git -C "$repo" show "$commit:$file" > "$directory/blobs/$file" + done < "$directory/paths" +done +"$@" diff --git a/tools/release/with-release-tags.sh b/tools/release/with-release-tags.sh new file mode 100644 index 000000000..5b7bb227e --- /dev/null +++ b/tools/release/with-release-tags.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail +[[ "$#" -gt 0 ]] || { echo 'usage: with-release-tags.sh COMMAND [ARGS...]' >&2; exit 2; } +scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-release-tags.XXXXXX")" +trap 'rm -rf "$scratch"' EXIT +RELEASE_TAG_REFS="$scratch/refs" +RELEASE_TAG_COMMITS="$scratch/commits" +RELEASE_TAG_CONTRIB="$scratch/contrib" +export RELEASE_TAG_REFS RELEASE_TAG_COMMITS RELEASE_TAG_CONTRIB +git show-ref --tags --dereference > "$RELEASE_TAG_REFS" || { + status=$?; [[ "$status" == 1 ]] || exit "$status"; +} +git log --no-walk --tags --format='%H %P' > "$RELEASE_TAG_COMMITS" +: > "$RELEASE_TAG_CONTRIB" +while read -r _ ref; do + case "$ref" in + *'^{}') continue ;; + refs/tags/liboliphaunt-native-v*|refs/tags/liboliphaunt-wasix-v*) + git ls-tree --name-only -z "$ref" -- src/extensions/contrib/carriers.toml extensions/contrib/carriers.toml > "$scratch/entry" + present=false + [[ ! -s "$scratch/entry" ]] || present=true + printf '%s\0%s\0' "${ref#refs/tags/}" "$present" >> "$RELEASE_TAG_CONTRIB" ;; + esac +done < "$RELEASE_TAG_REFS" +"$@" diff --git a/tools/release/with-source.sh b/tools/release/with-source.sh new file mode 100644 index 000000000..461a66910 --- /dev/null +++ b/tools/release/with-source.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail +[[ "$#" -ge 2 ]] || { echo 'usage: with-source.sh REF COMMAND [ARG...]' >&2; exit 2; } +cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +ref="$1" +shift +commit="$(git rev-parse --verify --end-of-options "$ref^{commit}")" +tree="$(git rev-parse "$commit^{tree}")" +checkout="$(git rev-parse --verify "HEAD^{commit}")" +OLIPHAUNT_GIT_SOURCE_JSON="$(jq -nc --arg ref "$ref" --arg commit "$commit" --arg tree "$tree" --arg checkout "$checkout" '{ref:$ref,commit:$commit,tree:$tree,checkout:$checkout}')" +export OLIPHAUNT_GIT_SOURCE_JSON +exec "$@" diff --git a/tools/release/write-icu-package-size-report.mjs b/tools/release/write-icu-package-size-report.mjs deleted file mode 100644 index 44d971102..000000000 --- a/tools/release/write-icu-package-size-report.mjs +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bun - -import { writeFileSync } from "node:fs"; -import path from "node:path"; - -import { filesystemTreeRows } from "./native-cluster-seed-contract.mjs"; - -function treeBytes(root) { - return filesystemTreeRows(root).reduce((total, row) => total + row.bytes.length, 0); -} - -export function icuPackageSizeReport(icuData) { - const icuDataBytes = treeBytes(icuData); - return [ - "kind\tid\textensions\tfiles\tbytes", - `package\ttotal\t-\t-\t${icuDataBytes}`, - `package\ticu-data\t-\t-\t${icuDataBytes}`, - "", - ].join("\n"); -} - -if (import.meta.main) { - const [icuData, output] = process.argv.slice(2); - if (!icuData || !output) { - throw new Error("usage: write-icu-package-size-report.mjs ICU_DATA_DIR OUTPUT"); - } - writeFileSync(path.resolve(output), icuPackageSizeReport(path.resolve(icuData))); -} diff --git a/tools/release/write-native-extension-lifecycle-receipt.mjs b/tools/release/write-native-extension-lifecycle-receipt.mjs deleted file mode 100644 index e102f6e1a..000000000 --- a/tools/release/write-native-extension-lifecycle-receipt.mjs +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env bun - -import { createHash } from "node:crypto"; -import { readFileSync, writeFileSync } from "node:fs"; - -import { compareText, exactExtensionProducts, extensionSqlNames } from "./release-artifact-targets.mjs"; - -function fail(message) { - throw new Error(`write-native-extension-lifecycle-receipt.mjs: ${message}`); -} - -function flags(argv) { - const values = {}; - for (let index = 0; index < argv.length; index += 2) { - const name = argv[index]; - const value = argv[index + 1]; - if (!name?.startsWith("--") || value === undefined) fail(`invalid argument ${name ?? ""}`); - values[name.slice(2)] = value; - } - for (const name of ["inputs", "log", "output", "shard-index", "shard-count"]) { - if (values[name] === undefined) fail(`--${name} is required`); - } - return values; -} - -function sha256(value) { - return createHash("sha256").update(value).digest("hex"); -} - -function canonicalExtensions() { - const names = exactExtensionProducts("write-native-extension-lifecycle-receipt.mjs") - .flatMap((product) => extensionSqlNames(product, "write-native-extension-lifecycle-receipt.mjs")) - .sort(compareText); - if (names.length === 0 || new Set(names).size !== names.length) { - fail("canonical release graph must resolve to a nonempty unique extension set"); - } - return names; -} - -function verifyInputEnvelope(inputs) { - const { inputEnvelopeSha256, ...core } = inputs; - if (inputEnvelopeSha256 !== sha256(JSON.stringify(core))) fail("input envelope digest mismatch"); - if (inputs.schema !== "oliphaunt-native-extension-lifecycle-inputs-v1") fail("unknown input envelope schema"); - if (!/^[0-9a-f]{40}$/u.test(inputs.candidateSha) || !/^[0-9a-f]{40}$/u.test(inputs.candidateTree)) { - fail("input candidate SHA and tree must be full Git object IDs"); - } - if (inputs.target !== "linux-x64-gnu") fail("input envelope must target canonical linux-x64-gnu"); - const canonical = canonicalExtensions(); - const selected = Array.isArray(inputs.extensions) ? inputs.extensions : []; - const canonicalSet = new Set(canonical); - if ( - selected.length === 0 - || inputs.extensionCount !== selected.length - || new Set(selected).size !== selected.length - || selected.some((name) => !canonicalSet.has(name)) - || selected.join("\0") !== [...selected].sort(compareText).join("\0") - ) fail("input envelope extensions must be a nonempty unique sorted subset of the canonical release graph set"); - if (inputs.modes?.join(",") !== "direct,broker,server") fail("input envelope has incomplete modes"); - if (inputs.lifecycle?.join(",") !== "install,load,restart,backup,restore") { - fail("input envelope has incomplete lifecycle"); - } - const expectedIdentities = [ - "broker", - "broker-checksum", - "native-extension-index", - "native-extension-legacy-index", - "native-extension-proof-runner", - "native-runtime", - "native-tools", - ...inputs.extensions.map((name) => `native-extension:${name}`), - ].sort(); - if (!Array.isArray(inputs.consumedArtifacts) || inputs.consumedArtifacts.length !== expectedIdentities.length) { - fail(`input envelope must enumerate all ${expectedIdentities.length} consumed artifacts`); - } - const actualIdentities = inputs.consumedArtifacts.map((artifact) => artifact?.identity); - if (actualIdentities.join("\0") !== expectedIdentities.join("\0")) { - fail("input envelope consumed artifact identities are incomplete or unsorted"); - } - for (const artifact of inputs.consumedArtifacts) { - if ( - typeof artifact.file !== "string" - || artifact.file.length === 0 - || artifact.file.includes("/") - || artifact.file.includes("\\") - || !Number.isSafeInteger(artifact.bytes) - || artifact.bytes <= 0 - || !/^[0-9a-f]{64}$/u.test(artifact.sha256) - ) fail(`consumed artifact ${String(artifact.identity)} lacks canonical file, byte, or SHA-256 evidence`); - } -} - -export function writeReceipt(options) { - const inputs = JSON.parse(readFileSync(options.inputs, "utf8")); - verifyInputEnvelope(inputs); - const plannedCount = inputs.extensions.length; - const log = readFileSync(options.log, "utf8"); - const shardIndex = Number(options["shard-index"]); - const shardCount = Number(options["shard-count"]); - if ( - !Number.isInteger(shardIndex) - || !Number.isInteger(shardCount) - || shardCount < 1 - || shardCount > plannedCount - || shardIndex < 0 - || shardIndex >= shardCount - ) { - fail(`receipt requires a shard index in [0, ${Math.max(0, shardCount - 1)}] and no more shards than planned extensions`); - } - const expected = inputs.extensions.filter((_, index) => index % shardCount === shardIndex); - const passPattern = /OLIPHAUNT_NATIVE_EXTENSION_PROOF_EXTENSION_PASS shard=(\d+)\/(\d+) extension=([^ ]+) modes=([^ ]+) lifecycle=([^\s]+)/gu; - const passRecords = [...log.matchAll(passPattern)].map((match) => ({ - shardIndex: Number(match[1]), - shardCount: Number(match[2]), - extension: match[3], - modes: match[4].split(","), - lifecycle: match[5].split("-"), - })); - if (passRecords.length !== expected.length || new Set(passRecords.map((row) => row.extension)).size !== passRecords.length) { - fail(`shard ${shardIndex} must contain ${expected.length} unique extension PASS records`); - } - for (const record of passRecords) { - if (record.shardIndex !== shardIndex || record.shardCount !== shardCount) fail("extension PASS record has wrong shard identity"); - if (record.modes.join(",") !== "direct,broker,server") fail(`${record.extension} PASS record has incomplete modes`); - if (record.lifecycle.join(",") !== "install,load,restart,backup,restore") fail(`${record.extension} PASS record has incomplete lifecycle`); - } - const actual = passRecords.map((row) => row.extension).sort(); - if (actual.join("\0") !== [...expected].sort().join("\0")) { - fail(`shard ${shardIndex} extension set drift: expected=${expected.join(",")}; actual=${actual.join(",")}`); - } - const finalMarker = `OLIPHAUNT_NATIVE_EXTENSION_PROOF_PASS shard=${shardIndex}/${shardCount} planned=${plannedCount} modes=direct,broker,server`; - if (log.split(finalMarker).length !== 2) fail(`shard ${shardIndex} must contain exactly one final PASS marker`); - - const receiptCore = { - schema: "oliphaunt-native-extension-lifecycle-shard-receipt-v1", - candidateSha: inputs.candidateSha, - candidateTree: inputs.candidateTree, - target: inputs.target, - shardIndex, - shardCount, - plannedExtensionCount: plannedCount, - extensionCount: expected.length, - extensions: expected, - modes: inputs.modes, - lifecycle: inputs.lifecycle, - inputEnvelopeSha256: inputs.inputEnvelopeSha256, - consumedArtifacts: inputs.consumedArtifacts, - proofLogSha256: sha256(log), - passRecords, - }; - const receipt = { ...receiptCore, receiptSha256: sha256(JSON.stringify(receiptCore)) }; - writeFileSync(options.output, `${JSON.stringify(receipt, null, 2)}\n`); - console.log(`native extension lifecycle shard receipt written: ${options.output}`); -} - -if (import.meta.main) { - try { - writeReceipt(flags(Bun.argv.slice(2))); - } catch (error) { - console.error(error instanceof Error ? error.message : String(error)); - process.exit(1); - } -} diff --git a/tools/release/write_checksum_manifest.mjs b/tools/release/write_checksum_manifest.mjs deleted file mode 100755 index cb1cb612d..000000000 --- a/tools/release/write_checksum_manifest.mjs +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from 'node:crypto'; -import { createReadStream, readdirSync } from 'node:fs'; -import fs from 'node:fs/promises'; -import path from 'node:path'; - -function fail(message) { - console.error(`write_checksum_manifest.mjs: ${message}`); - process.exit(2); -} - -function parseArgs(argv) { - const patterns = []; - let assetDir = null; - let output = null; - for (let index = 0; index < argv.length; index += 1) { - const arg = argv[index]; - switch (arg) { - case '--asset-dir': - assetDir = argv[index + 1] ?? null; - index += 1; - break; - case '--output': - output = argv[index + 1] ?? null; - index += 1; - break; - case '--pattern': - patterns.push(argv[index + 1] ?? ''); - index += 1; - break; - default: - fail(`unknown argument: ${arg}`); - } - } - if (!assetDir || !output || patterns.length === 0 || patterns.some((pattern) => pattern.length === 0)) { - fail( - 'usage: tools/release/write_checksum_manifest.mjs --asset-dir --output --pattern [--pattern ...]', - ); - } - return { - assetDir: path.resolve(assetDir), - output, - patterns, - }; -} - -async function sha256(file) { - const digest = createHash('sha256'); - for await (const chunk of createReadStream(file)) { - digest.update(chunk); - } - return digest.digest('hex'); -} - -function baseName(relativePath) { - return relativePath.split(/[\\/]/u).pop(); -} - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - -function releaseAssetFiles(assetDir) { - const files = []; - const visit = (directory, segments) => { - const entries = readdirSync(directory, { withFileTypes: true }) - .sort((left, right) => compareText(left.name, right.name)); - for (const entry of entries) { - // Bun's filesystem globbing defaults to dot=false. Keep hidden files - // and hidden directory subtrees outside the candidate set before using - // its pure matcher so this replacement does not broaden release inputs. - if (entry.name.startsWith('.')) { - continue; - } - const nextSegments = [...segments, entry.name]; - const absolutePath = path.join(directory, entry.name); - if (entry.isDirectory()) { - visit(absolutePath, nextSegments); - } else if (entry.isFile()) { - files.push({ - absolutePath, - relativePath: nextSegments.join('/'), - }); - } - } - }; - visit(assetDir, []); - return files.sort((left, right) => compareText(left.relativePath, right.relativePath)); -} - -export function matchingAssets(assetDir, patterns) { - const assets = new Map(); - const files = releaseAssetFiles(assetDir); - for (const pattern of patterns) { - const glob = new Bun.Glob(pattern); - const explicitRelativePrefix = pattern.startsWith('./'); - for (const file of files) { - const matchPath = explicitRelativePrefix ? `./${file.relativePath}` : file.relativePath; - if (glob.match(matchPath)) { - assets.set(baseName(file.relativePath), file.absolutePath); - } - } - } - return [...assets.keys()].sort(compareText).map((name) => assets.get(name)); -} - -async function main(argv) { - const args = parseArgs(argv); - const outputPath = path.join(args.assetDir, args.output); - const lines = []; - const assets = matchingAssets(args.assetDir, args.patterns); - if (assets.length === 0) { - fail(`no release assets found in ${args.assetDir} matching ${args.patterns.join(', ')}`); - } - for (const asset of assets) { - if (path.resolve(asset) === path.resolve(outputPath)) { - continue; - } - lines.push(`${await sha256(asset)} ./${path.basename(asset)}\n`); - } - await fs.writeFile(outputPath, lines.join('')); -} - -if (import.meta.main) { - await main(Bun.argv.slice(2)); -} diff --git a/tools/release/write_checksum_manifest.test.mjs b/tools/release/write_checksum_manifest.test.mjs deleted file mode 100644 index 79eac6355..000000000 --- a/tools/release/write_checksum_manifest.test.mjs +++ /dev/null @@ -1,117 +0,0 @@ -import { expect, test } from "bun:test"; -import { spawnSync } from "../test/fd-backed-spawn-sync.mjs"; -import { createHash } from "node:crypto"; -import { - mkdirSync, - mkdtempSync, - readFileSync, - rmSync, - symlinkSync, - writeFileSync, -} from "node:fs"; -import os from "node:os"; -import path from "node:path"; - -import { matchingAssets } from "./write_checksum_manifest.mjs"; - -const TOOL = path.join(import.meta.dir, "write_checksum_manifest.mjs"); - -function writeFixture(root, relativePath, contents = `${relativePath}\n`) { - const file = path.join(root, ...relativePath.split("/")); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, contents); - return file; -} - -function relativeFiles(root, files) { - return files.map((file) => path.relative(root, file).split(path.sep).join("/")); -} - -function sha256(contents) { - return createHash("sha256").update(contents).digest("hex"); -} - -test("preserves recursive and root-relative glob semantics with deterministic output order", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-checksum-walk-")); - try { - writeFixture(root, "z.zip"); - writeFixture(root, "root.tar.gz"); - writeFixture(root, "nested/b.tar.gz"); - writeFixture(root, "nested/deeper/a.tar.gz"); - writeFixture(root, "nested/ignored.txt"); - writeFixture(root, ".hidden.tar.gz"); - writeFixture(root, ".hidden/also-hidden.tar.gz"); - writeFixture(root, "nested/.hidden-too.tar.gz"); - - expect(relativeFiles(root, matchingAssets(root, ["**/*.tar.gz", "*.zip"]))).toEqual([ - "nested/deeper/a.tar.gz", - "nested/b.tar.gz", - "root.tar.gz", - "z.zip", - ]); - expect(relativeFiles(root, matchingAssets(root, ["*.tar.gz"]))).toEqual([ - "root.tar.gz", - ]); - expect(relativeFiles(root, matchingAssets(root, ["nested/*.tar.gz"]))).toEqual([ - "nested/b.tar.gz", - ]); - expect(relativeFiles(root, matchingAssets(root, ["./*.zip"]))).toEqual([ - "z.zip", - ]); - expect(matchingAssets(root, [".hidden.tar.gz", "**/.hidden*.tar.gz"])).toEqual([]); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test("does not follow file or directory symlinks while walking assets", () => { - const parent = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-checksum-symlink-")); - try { - const root = path.join(parent, "assets"); - const outside = path.join(parent, "outside"); - mkdirSync(root); - mkdirSync(outside); - writeFixture(root, "real.tar.gz"); - const outsideAsset = writeFixture(outside, "outside.tar.gz"); - symlinkSync( - outside, - path.join(root, "linked-directory"), - process.platform === "win32" ? "junction" : "dir", - ); - if (process.platform !== "win32") { - symlinkSync(outsideAsset, path.join(root, "linked-file.tar.gz"), "file"); - } - - expect(relativeFiles(root, matchingAssets(root, ["**/*.tar.gz"]))).toEqual([ - "real.tar.gz", - ]); - } finally { - rmSync(parent, { recursive: true, force: true }); - } -}); - -test("writes the caller-facing checksum manifest deterministically", () => { - const root = mkdtempSync(path.join(os.tmpdir(), "oliphaunt-checksum-output-")); - try { - writeFixture(root, "z.zip", "zip payload\n"); - writeFixture(root, "a.tar.gz", "tar payload\n"); - const result = spawnSync(process.execPath, [ - TOOL, - "--asset-dir", - root, - "--output", - "release-assets.sha256", - "--pattern", - "*.zip", - "--pattern", - "*.tar.gz", - ], { encoding: "utf8" }); - expect(result.status, result.stderr || result.stdout).toBe(0); - expect(readFileSync(path.join(root, "release-assets.sha256"), "utf8")).toBe( - `${sha256("tar payload\n")} ./a.tar.gz\n` - + `${sha256("zip payload\n")} ./z.zip\n`, - ); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/tools/sdk-contracts/moon.yml b/tools/sdk-contracts/moon.yml deleted file mode 100644 index f7d4c688d..000000000 --- a/tools/sdk-contracts/moon.yml +++ /dev/null @@ -1,140 +0,0 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "sdk-contracts" -language: "javascript" -layer: "tool" -stack: "infrastructure" -tags: ["sdk", "contract"] -dependsOn: - - id: "cluster-seed-contract" - scope: "development" - - id: "shared-test-fixtures" - scope: "development" - - id: "shared-rust-query-core" - scope: "development" - -project: - title: "SDK Contracts" - description: "Generated API, ownership, native boundary, header, and extension-model contracts shared by product SDKs." - owner: "oliphaunt" - -owners: - defaultOwner: "@oliphaunt/core" - paths: - "**/*": ["@oliphaunt/core"] - -tasks: - check: - tags: ["quality", "static"] - command: "node tools/policy/generate-sdk-api-surface.mjs --check" - inputs: - - "/docs/maintainers/sdk-api-surface.md" - - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h" - - "/src/sdks/js/src/**/*.ts" - - "/src/sdks/js/package.json" - - "/src/sdks/kotlin/oliphaunt/src/{androidMain,commonMain,jvmMain}/**/*.kt" - - "/src/sdks/kotlin/oliphaunt-android-gradle-plugin/build.gradle.kts" - - "/src/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntAndroidExtension.java" - - "/src/sdks/react-native/src/**/*.ts" - - "/src/sdks/react-native/package.json" - - "/src/sdks/rust/src/**/*.rs" - - project: "shared-rust-query-core" - group: "sources" - - "/src/sdks/rust/crates/oliphaunt-build/src/**/*.rs" - - "/src/sdks/swift/Sources/Oliphaunt/**/*.swift" - - "/src/sdks/swift/Sources/OliphauntExtensionSupport/**/*.swift" - - "/src/bindings/wasix-rust/crates/oliphaunt-wasix/src/**/*.rs" - - "/src/bindings/wasix-ts/src/**/*.ts" - - "/src/bindings/wasix-ts/package.json" - - "/tools/policy/generate-sdk-api-surface.mjs" - options: - cache: true - runFromWorkspaceRoot: true - all: - command: "true" - deps: - - "sdk-contracts:check" - - "sdk-contracts:cluster-seeds" - - "sdk-contracts:fixtures" - - "sdk-contracts:headers" - - "sdk-contracts:manifest" - - "sdk-contracts:native-boundaries" - - "shared-rust-query-core:check" - inputs: [] - options: - cache: false - runFromWorkspaceRoot: true - runInCI: false - cluster-seeds: - tags: ["quality", "static"] - command: "bun tools/policy/check-cluster-seed-contract.mjs" - inputs: - - project: "cluster-seed-contract" - group: "contract" - - "/tools/policy/check-cluster-seed-contract.mjs" - - "/tools/release/native-cluster-seed-contract.mjs" - options: - cache: true - runFromWorkspaceRoot: true - fixtures: - tags: ["quality", "static"] - command: "bun tools/policy/check-shared-fixtures.mjs" - inputs: - - project: "shared-test-fixtures" - group: "fixtures" - - "/tools/policy/check-shared-fixtures.mjs" - options: - cache: true - runFromWorkspaceRoot: true - headers: - tags: ["quality", "static"] - command: "bun tools/policy/check-sdk-header-copies.mjs" - inputs: - - "/src/runtimes/liboliphaunt/native/include/oliphaunt.h" - - "/src/sdks/kotlin/oliphaunt/src/androidMain/cpp/include/oliphaunt.h" - - "/src/sdks/react-native/android/src/main/cpp/include/oliphaunt.h" - - "/src/sdks/swift/Sources/COliphaunt/include/oliphaunt.h" - - "/tools/policy/check-sdk-header-copies.mjs" - options: - cache: true - runFromWorkspaceRoot: true - manifest: - tags: ["quality", "static"] - command: "bun tools/policy/check-sdk-manifest.mjs" - inputs: - - "/src/bindings/wasix-rust/moon.yml" - - "/src/bindings/wasix-ts/moon.yml" - - "/src/bindings/wasix-ts/package.json" - - "/src/sdks/*/moon.yml" - - "/src/sdks/js/package.json" - - "/src/sdks/react-native/package.json" - - "/docs/maintainers/sdk-parity-policy.md" - - "/tools/policy/check-sdk-manifest.mjs" - - "/tools/policy/sdk-manifest.toml" - - "/tools/release/release-graph.mjs" - - "/src/**/release.toml" - options: - cache: true - runFromWorkspaceRoot: true - native-boundaries: - tags: ["quality", "static"] - command: "bun tools/policy/check-native-boundaries.mjs" - inputs: - - "/examples/react-native-expo/package.json" - - "/src/sdks/rust/Cargo.toml" - - "/src/sdks/react-native/package.json" - - "/src/sdks/{rust/src,rust/tests,swift/Sources,swift/Tests,kotlin/oliphaunt/src,react-native/src,react-native/ios,react-native/android/src}/**/*.{c,cpp,h,java,kt,m,mm,rs,swift,ts,tsx}" - - "/src/runtimes/liboliphaunt/native/{include,src}/**/*.{c,h}" - - "/src/sdks/swift/Package.swift" - - "/src/sdks/react-native/OliphauntReactNative.podspec" - - "/src/sdks/kotlin/build.gradle.kts" - - "/src/sdks/kotlin/oliphaunt/build.gradle.kts" - - "/src/sdks/react-native/android/build.gradle" - - "/src/sdks/react-native/android/settings.gradle" - - "/tools/perf/runner/Cargo.toml" - - "/tools/policy/sdk-manifest.toml" - - "/tools/policy/check-native-boundaries.mjs" - - "/tools/xtask/Cargo.toml" - options: - cache: true - runFromWorkspaceRoot: true diff --git a/tools/test/create-broker-release-fixture.mjs b/tools/test/create-broker-release-fixture.mjs deleted file mode 100644 index 0a4b6fa07..000000000 --- a/tools/test/create-broker-release-fixture.mjs +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env bun -import { createHash } from 'node:crypto'; -import fs from 'node:fs/promises'; -import os from 'node:os'; -import path from 'node:path'; - -import { stageBrokerDependencyLicenses } from '../release/broker-dependency-license-contract.mjs'; -import { stageReleaseNotices } from '../release/release-notices.mjs'; - -import { - elfFixture, - machoFixture, - parseCommonArgs, - windowsPeFixture, - writeChecksumManifest, - writeEntriesArchive, -} from './release-fixture-utils.mjs'; - -function brokerBinary(target) { - if (target === 'macos-arm64') { - return machoFixture({ platform: 1, minos: [11, 0, 0] }); - } - if (target === 'linux-x64-gnu') { - return elfFixture({ machine: 62, requiredVersions: ['GLIBC_2.17'] }); - } - if (target === 'linux-arm64-gnu') { - return elfFixture({ machine: 183, requiredVersions: ['GLIBC_2.17'] }); - } - throw new Error(`unsupported broker release fixture target ${target}`); -} - -async function carrierLegalEntries(target) { - const stage = await fs.realpath( - await fs.mkdtemp(path.join(os.tmpdir(), 'oliphaunt-broker-fixture-legal-')), - ); - await fs.chmod(stage, 0o755); - try { - stageReleaseNotices(stage, { profile: 'broker' }); - stageBrokerDependencyLicenses(stage, target); - const entries = {}; - async function walk(directory, relative = '') { - for (const entry of await fs.readdir(directory, { withFileTypes: true })) { - const member = relative ? `${relative}/${entry.name}` : entry.name; - const file = path.join(directory, entry.name); - if (entry.isDirectory()) { - await walk(file, member); - } else if (entry.isFile()) { - entries[member] = await fs.readFile(file); - } else { - throw new Error(`unexpected broker legal fixture entry ${file}`); - } - } - } - await walk(stage); - return entries; - } finally { - await fs.rm(stage, { recursive: true, force: true }); - } -} - -async function brokerEntries(target, executable) { - return { - ...(await carrierLegalEntries(target)), - [executable]: brokerBinary(target), - 'manifest.properties': [ - 'schema=oliphaunt-broker-release-assets-v1', - 'product=oliphaunt-broker', - `target=${target}`, - `binary=${executable}`, - '', - ].join('\n'), - }; -} - -async function windowsBrokerEntries() { - const runtimeName = 'vcruntime140.dll'; - const executable = windowsPeFixture({ imports: ['VCRUNTIME140.dll'] }); - const runtime = windowsPeFixture({ imports: ['KERNEL32.dll'] }); - const digest = createHash('sha256').update(runtime).digest('hex'); - return { - ...(await carrierLegalEntries('windows-x64-msvc')), - 'bin/oliphaunt-broker.exe': executable, - [`bin/${runtimeName}`]: runtime, - 'bin/windows-vc-runtime.sha256': `${digest} ${runtimeName}\n`, - 'manifest.properties': [ - 'schema=oliphaunt-broker-release-assets-v1', - 'product=oliphaunt-broker', - 'target=windows-x64-msvc', - 'binary=bin/oliphaunt-broker.exe', - `windowsVcRuntimeDlls=${runtimeName}`, - '', - ].join('\n'), - }; -} - -async function writeFixtureAssets(assetDir, version) { - await fs.mkdir(assetDir, { recursive: true }); - const executableModes = { - 'bin/oliphaunt-broker': 0o755, - 'bin/oliphaunt-broker.exe': 0o755, - }; - - for (const target of ['macos-arm64', 'linux-x64-gnu', 'linux-arm64-gnu']) { - await writeEntriesArchive( - path.join(assetDir, `oliphaunt-broker-${version}-${target}.tar.gz`), - await brokerEntries(target, 'bin/oliphaunt-broker'), - executableModes, - ); - } - - await writeEntriesArchive( - path.join(assetDir, `oliphaunt-broker-${version}-windows-x64-msvc.zip`), - await windowsBrokerEntries(), - executableModes, - ); - await writeChecksumManifest(assetDir, `oliphaunt-broker-${version}-release-assets.sha256`); -} - -const { assetDir, version } = parseCommonArgs( - Bun.argv.slice(2), - 'Create small oliphaunt-broker release-shaped assets for SDK checks.', -); -await writeFixtureAssets(assetDir, version); diff --git a/tools/test/create-liboliphaunt-release-fixture.mjs b/tools/test/create-liboliphaunt-release-fixture.mjs deleted file mode 100644 index 1da124ea7..000000000 --- a/tools/test/create-liboliphaunt-release-fixture.mjs +++ /dev/null @@ -1,546 +0,0 @@ -#!/usr/bin/env bun -import fs from 'node:fs/promises'; -import { createHash } from 'node:crypto'; -import path from 'node:path'; - -import { releaseNoticeRows } from '../release/release-notices.mjs'; -import { - logicalTreeSha256, - nativeClusterSeedCompatibilityKey, -} from '../release/native-cluster-seed-contract.mjs'; -import { NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN } from '../release/native-mobile-abi-contract.mjs'; - -import { - elfFixture, - machoFixture, - parseCommonArgs, - windowsImportLibraryFixture, - windowsPeFixture, - writeChecksumManifest, - writeEntriesArchive, -} from './release-fixture-utils.mjs'; -import { nativeRuntimeResourceManifestFixture } from './native-runtime-fixture.mjs'; - -const NATIVE_RUNTIME_TOOL_STEMS = ['initdb', 'pg_ctl', 'postgres']; -const NATIVE_TOOLS_TOOL_STEMS = ['pg_basebackup', 'pg_dump', 'psql']; -const SNOWBALL_STOPWORDS = [ - 'danish.stop', - 'dutch.stop', - 'english.stop', - 'finnish.stop', - 'french.stop', - 'german.stop', - 'hungarian.stop', - 'italian.stop', - 'nepali.stop', - 'norwegian.stop', - 'portuguese.stop', - 'russian.stop', - 'spanish.stop', - 'swedish.stop', - 'turkish.stop', -]; -const WINDOWS_VC_RUNTIME_DLLS = ['msvcp140.dll', 'vcruntime140.dll', 'vcruntime140_1.dll']; -const WINDOWS_ICU_RUNTIME_DLLS = ['icudt76.dll', 'icuin76.dll', 'icuuc76.dll']; - -function windowsVcRuntimeEntries() { - const entries = {}; - for (const directory of ['bin', 'runtime/bin']) { - for (const name of WINDOWS_VC_RUNTIME_DLLS) { - entries[`${directory}/${name}`] = windowsPeFixture({ imports: ['KERNEL32.dll'] }); - } - entries[`${directory}/windows-vc-runtime.sha256`] = - WINDOWS_VC_RUNTIME_DLLS.map((name) => { - const digest = createHash('sha256').update(entries[`${directory}/${name}`]).digest('hex'); - return `${digest} ${name}`; - }).join('\n') + '\n'; - } - return entries; -} - -function windowsIcuRuntimeEntries() { - const entries = {}; - for (const directory of ['bin', 'runtime/bin']) { - for (const name of WINDOWS_ICU_RUNTIME_DLLS) { - entries[`${directory}/${name}`] = nativeBinary('windows-x64-msvc', { provider: true }); - } - } - return entries; -} - -function nativeBinary(target, { provider = false } = {}) { - if (target === 'macos-arm64') { - return machoFixture({ platform: 1, minos: [11, 0, 0] }); - } - if (target === 'linux-x64-gnu') { - return elfFixture({ machine: 62, requiredVersions: ['GLIBC_2.17'] }); - } - if (target === 'linux-arm64-gnu') { - return elfFixture({ machine: 183, requiredVersions: ['GLIBC_2.17'] }); - } - if (target === 'android-arm64-v8a') { - return elfFixture({ machine: 183, androidApi: 24 }); - } - if (target === 'android-x86_64') { - return elfFixture({ machine: 62, androidApi: 24 }); - } - if (target === 'windows-x64-msvc') { - return windowsPeFixture({ imports: [provider ? 'VCRUNTIME140.dll' : 'KERNEL32.dll'] }); - } - throw new Error(`unsupported liboliphaunt release fixture target ${target}`); -} - -function nativeRuntimeEntries(target, icuDataTreeSha256) { - const windows = target === 'windows-x64-msvc'; - const suffix = windows ? '.exe' : ''; - const moduleSuffix = windows ? '.dll' : target === 'macos-arm64' ? '.dylib' : '.so'; - const entries = Object.fromEntries( - NATIVE_RUNTIME_TOOL_STEMS.map((tool) => [ - `runtime/bin/${tool}${suffix}`, - nativeBinary(target, { provider: windows }), - ]), - ); - entries['runtime/share/postgresql/README.release-fixture'] = - 'release-shaped native runtime fixture\n'; - entries['runtime/manifest.properties'] = nativeRuntimeResourceManifestFixture({ - cacheKey: 'release-fixture-runtime', - target, - }); - entries[`runtime/lib/postgresql/dict_snowball${moduleSuffix}`] = nativeBinary(target); - entries[`runtime/lib/postgresql/plpgsql${moduleSuffix}`] = nativeBinary(target); - entries['runtime/share/postgresql/extension/plpgsql.control'] = "default_version = '1.0'\n"; - entries['runtime/share/postgresql/extension/plpgsql--1.0.sql'] = - '-- release-shaped PL/pgSQL fixture\n'; - entries['runtime/share/postgresql/snowball_create.sql'] = - '-- release-shaped Snowball dictionary fixture\n'; - for (const stopword of SNOWBALL_STOPWORDS) { - entries[`runtime/share/postgresql/tsearch_data/${stopword}`] = `${stopword}\n`; - } - Object.assign( - entries, - nativeRuntimeCarrierReceipt(target), - nativeClusterSeedEntries('standard', 'cluster-seed', target), - nativeClusterSeedEntries('icu', 'cluster-seed-icu', target, icuDataTreeSha256), - ); - return entries; -} - -function nativeRuntimeModes(target) { - const windows = target === 'windows-x64-msvc'; - const suffix = windows ? '.exe' : ''; - return Object.fromEntries( - NATIVE_RUNTIME_TOOL_STEMS.map((tool) => [`runtime/bin/${tool}${suffix}`, 0o755]), - ); -} - -function nativeToolsEntries(target) { - const windows = target === 'windows-x64-msvc'; - const suffix = windows ? '.exe' : ''; - return Object.fromEntries( - NATIVE_TOOLS_TOOL_STEMS.map((tool) => [`runtime/bin/${tool}${suffix}`, nativeBinary(target)]), - ); -} - -function nativeToolsModes(target) { - const windows = target === 'windows-x64-msvc'; - const suffix = windows ? '.exe' : ''; - return Object.fromEntries( - NATIVE_TOOLS_TOOL_STEMS.map((tool) => [`runtime/bin/${tool}${suffix}`, 0o755]), - ); -} - -function emptyStaticRegistryManifest() { - return [ - 'packageLayout=oliphaunt-static-registry-v1', - 'abiVersion=1', - 'state=not-required', - 'source=', - 'registeredExtensions=', - 'pendingExtensions=', - 'nativeModuleStems=', - 'modules=', - 'archiveTargets=', - 'dependencyArchiveTargets=', - 'dependencyArchives=', - '', - ].join('\n'); -} - -function byteSize(entries, prefix) { - return Object.entries(entries) - .filter(([name]) => name.startsWith(prefix)) - .reduce((total, [, data]) => total + Buffer.byteLength(data), 0); -} - -function runtimeResourcePackageSizeReport(entries, prefix = 'oliphaunt/') { - const runtimeBytes = byteSize(entries, `${prefix}runtime/files/`); - const clusterSeedBytes = byteSize(entries, `${prefix}cluster-seed/files/`); - const icuClusterSeedBytes = byteSize(entries, `${prefix}cluster-seed-icu/files/`); - const staticRegistryBytes = byteSize(entries, `${prefix}static-registry/`); - return [ - 'kind\tid\textensions\tfiles\tbytes', - `package\ttotal\t-\t-\t${runtimeBytes + clusterSeedBytes + icuClusterSeedBytes + staticRegistryBytes}`, - `package\truntime\t-\t-\t${runtimeBytes}`, - `package\tcluster-seed\t-\t-\t${clusterSeedBytes}`, - `package\tcluster-seed-icu\t-\t-\t${icuClusterSeedBytes}`, - `package\tstatic-registry\t-\t-\t${staticRegistryBytes}`, - 'extensions\tselected\t-\t-\t0', - '', - ].join('\n'); -} - -function nativeRuntimeCarrierReceipt(target, prefix = '') { - return { - [`${prefix}manifest.properties`]: [ - 'schema=oliphaunt-native-runtime-carrier-v1', - `clusterSeedTarget=${target}`, - 'clusterSeedRelativePath=cluster-seed', - 'icuClusterSeedRelativePath=cluster-seed-icu', - '', - ].join('\n'), - }; -} - -function runtimeResourceEntries(target, icuDataTreeSha256) { - const entries = { - 'oliphaunt/runtime/files/share/postgresql/README.release-fixture': - 'release-shaped runtime fixture\n', - 'oliphaunt/static-registry/manifest.properties': emptyStaticRegistryManifest(), - 'oliphaunt/runtime/manifest.properties': nativeRuntimeResourceManifestFixture({ - cacheKey: 'release-fixture-runtime', - target, - }), - ...nativeRuntimeCarrierReceipt(target, 'oliphaunt/'), - ...nativeClusterSeedEntries('standard', 'oliphaunt/cluster-seed', target), - ...nativeClusterSeedEntries('icu', 'oliphaunt/cluster-seed-icu', target, icuDataTreeSha256), - }; - entries['oliphaunt/runtime/files/share/postgresql/extension/plpgsql.control'] = - "default_version = '1.0'\n"; - entries['oliphaunt/runtime/files/share/postgresql/extension/plpgsql--1.0.sql'] = - '-- release-shaped PL/pgSQL fixture\n'; - entries['oliphaunt/runtime/files/share/postgresql/snowball_create.sql'] = - '-- release-shaped Snowball dictionary fixture\n'; - for (const stopword of SNOWBALL_STOPWORDS) { - entries[`oliphaunt/runtime/files/share/postgresql/tsearch_data/${stopword}`] = `${stopword}\n`; - } - if (NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[target] !== undefined) { - Object.assign(entries, mobileAbiProofEntries(target)); - } - entries['oliphaunt/package-size.tsv'] = runtimeResourcePackageSizeReport(entries); - return entries; -} - -function mobileAbiProofEntries(domain) { - return Object.fromEntries( - NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[domain].map((target) => [ - `oliphaunt/provenance/native-mobile-abi/${target}.properties`, - [ - 'schema=oliphaunt-native-mobile-abi-v1', - `target=${target}`, - 'byteOrder=little', - 'datumBytes=8', - 'maximumAlignof=8', - 'float8ByVal=1', - 'blockSize=8192', - 'walBlockSize=8192', - 'relationSegmentSize=131072', - 'nameDataLength=64', - 'indexMaxKeys=32', - 'catalogVersion=202506291', - 'pgControlVersion=1800', - '', - ].join('\n'), - ]), - ); -} - -function nativeClusterSeedEntries(profile, prefix, target, icuDataTreeSha256 = '') { - const runtimeFeatures = profile === 'icu' ? 'icu' : ''; - const manifest = [ - 'schema=oliphaunt-runtime-resources-v1', - 'layout=oliphaunt-cluster-seed-v1', - `artifactRole=cluster-seed-${profile}`, - `catalogProfile=${profile}`, - `target=${target}`, - 'postgresMajor=18', - 'physicalFormat=native-pg18-v1', - `compatibilityKey=${nativeClusterSeedCompatibilityKey(target)}`, - 'initialSuperuser=postgres', - `icuDataVersion=${profile === 'icu' ? '76.1' : ''}`, - `icuDataForm=${profile === 'icu' ? 'files-le' : ''}`, - `icuDataTreeSha256=${icuDataTreeSha256}`, - `runtimeFeatures=${runtimeFeatures}`, - `cacheKey=${createHash('sha256').update(`${target}:${profile}`).digest('hex').slice(0, 16)}`, - '', - ].join('\n'); - return { - [`${prefix}/manifest.properties`]: manifest, - [`${prefix}/files/PG_VERSION`]: '18\n', - [`${prefix}/files/global/pg_control`]: `${profile}-fixture-control\n`, - [`${prefix}/files/pg_wal/`]: '', - }; -} - -function icuClosure() { - const data = Buffer.from('not-real-icu-data\n'); - const entries = { - 'share/icu/icudt76l.dat': data, - }; - const icuDataTreeSha256 = logicalTreeSha256([{ path: 'icudt76l.dat', bytes: data }]); - const icuDataBytes = byteSize(entries, 'share/icu/'); - entries['manifest.properties'] = [ - 'schema=oliphaunt-icu-data-v1', - 'artifactRole=icu-data', - 'icuDataVersion=76.1', - 'icuDataForm=files-le', - `icuDataTreeSha256=${icuDataTreeSha256}`, - '', - ].join('\n'); - entries['package-size.tsv'] = [ - 'kind\tid\textensions\tfiles\tbytes', - `package\ttotal\t-\t-\t${icuDataBytes}`, - `package\ticu-data\t-\t-\t${icuDataBytes}`, - '', - ].join('\n'); - return { entries, icuDataTreeSha256 }; -} - -function xmlEscape(value) { - return value - .replaceAll('&', '&') - .replaceAll('<', '<') - .replaceAll('>', '>') - .replaceAll('"', '"'); -} - -function plistValue(value, indent = ' ') { - if (Array.isArray(value)) { - const lines = [`${indent}`]; - for (const item of value) { - lines.push(plistValue(item, `${indent} `)); - } - lines.push(`${indent}`); - return lines.join('\n'); - } - if (value && typeof value === 'object') { - const lines = [`${indent}`]; - for (const key of Object.keys(value).sort()) { - lines.push(`${indent} ${xmlEscape(key)}`); - lines.push(plistValue(value[key], `${indent} `)); - } - lines.push(`${indent}`); - return lines.join('\n'); - } - return `${indent}${xmlEscape(String(value))}`; -} - -function plist(dictionary) { - return [ - '', - '', - '', - plistValue(dictionary, ' '), - '', - '', - ].join('\n'); -} - -function xcframeworkEntries({ macosRuntimeResources, iosRuntimeResources }) { - const libraries = [ - { - LibraryIdentifier: 'macos-arm64', - LibraryPath: 'liboliphaunt.framework', - SupportedArchitectures: ['arm64'], - SupportedPlatform: 'macos', - }, - { - LibraryIdentifier: 'ios-arm64', - LibraryPath: 'liboliphaunt.framework', - SupportedArchitectures: ['arm64'], - SupportedPlatform: 'ios', - }, - { - LibraryIdentifier: 'ios-arm64-simulator', - LibraryPath: 'liboliphaunt.framework', - SupportedArchitectures: ['arm64'], - SupportedPlatform: 'ios', - SupportedPlatformVariant: 'simulator', - }, - ]; - const entries = { - 'liboliphaunt.xcframework/Info.plist': plist({ - AvailableLibraries: libraries, - CFBundlePackageType: 'XFWK', - XCFrameworkFormatVersion: '1.0', - }), - }; - for (const library of libraries) { - const frameworkRoot = `liboliphaunt.xcframework/${library.LibraryIdentifier}/liboliphaunt.framework`; - const appleTarget = - library.SupportedPlatform === 'macos' - ? { platform: 1, minos: [14, 0, 0] } - : library.SupportedPlatformVariant === 'simulator' - ? { platform: 7, minos: [17, 0, 0] } - : { platform: 2, minos: [17, 0, 0] }; - entries[`${frameworkRoot}/liboliphaunt`] = machoFixture(appleTarget); - entries[`${frameworkRoot}/Info.plist`] = plist({ - CFBundleExecutable: 'liboliphaunt', - CFBundleIdentifier: 'dev.oliphaunt.liboliphaunt.fixture', - CFBundleName: 'liboliphaunt', - CFBundlePackageType: 'FMWK', - }); - const runtimeResources = - library.SupportedPlatform === 'macos' ? macosRuntimeResources : iosRuntimeResources; - for (const [name, data] of Object.entries(runtimeResources)) { - entries[`${frameworkRoot}/Resources/${name}`] = data; - } - } - return entries; -} - -function xcframeworkModes() { - return { - 'liboliphaunt.xcframework/macos-arm64/liboliphaunt.framework/liboliphaunt': 0o755, - 'liboliphaunt.xcframework/ios-arm64/liboliphaunt.framework/liboliphaunt': 0o755, - 'liboliphaunt.xcframework/ios-arm64-simulator/liboliphaunt.framework/liboliphaunt': 0o755, - }; -} - -async function writeProfiledArchive(output, entries, profile, modes = {}, noticePrefix = '') { - const notices = {}; - for (const row of releaseNoticeRows({ profile })) { - const member = noticePrefix ? `${noticePrefix}/${row.member}` : row.member; - notices[member] = await fs.readFile(row.source); - } - await writeEntriesArchive(output, { ...entries, ...notices }, modes); -} - -async function writeFixtureAssets(assetDir, version) { - await fs.mkdir(assetDir, { recursive: true }); - const icu = icuClosure(); - const macosRuntimeResources = runtimeResourceEntries('macos-arm64', icu.icuDataTreeSha256); - const iosRuntimeResources = runtimeResourceEntries('ios-datum64', icu.icuDataTreeSha256); - const androidRuntimeResources = runtimeResourceEntries('android-datum64', icu.icuDataTreeSha256); - const appleXcframeworkEntries = xcframeworkEntries({ - macosRuntimeResources, - iosRuntimeResources, - }); - - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`), - iosRuntimeResources, - 'native-runtime-resources', - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-runtime-resources-android-datum64.tar.gz`), - androidRuntimeResources, - 'native-runtime-resources', - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-icu-data.tar.gz`), - icu.entries, - 'native-icu-data', - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-macos-arm64.tar.gz`), - { - 'lib/liboliphaunt.dylib': nativeBinary('macos-arm64'), - 'lib/modules/dict_snowball.dylib': nativeBinary('macos-arm64'), - 'lib/modules/plpgsql.dylib': nativeBinary('macos-arm64'), - ...nativeRuntimeEntries('macos-arm64', icu.icuDataTreeSha256), - }, - 'native-runtime', - nativeRuntimeModes('macos-arm64'), - ); - await writeProfiledArchive( - path.join(assetDir, `oliphaunt-tools-${version}-macos-arm64.tar.gz`), - nativeToolsEntries('macos-arm64'), - 'native-tools', - nativeToolsModes('macos-arm64'), - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-linux-x64-gnu.tar.gz`), - { - 'lib/liboliphaunt.so': nativeBinary('linux-x64-gnu'), - 'lib/modules/dict_snowball.so': nativeBinary('linux-x64-gnu'), - 'lib/modules/plpgsql.so': nativeBinary('linux-x64-gnu'), - ...nativeRuntimeEntries('linux-x64-gnu', icu.icuDataTreeSha256), - }, - 'native-runtime', - nativeRuntimeModes('linux-x64-gnu'), - ); - await writeProfiledArchive( - path.join(assetDir, `oliphaunt-tools-${version}-linux-x64-gnu.tar.gz`), - nativeToolsEntries('linux-x64-gnu'), - 'native-tools', - nativeToolsModes('linux-x64-gnu'), - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-linux-arm64-gnu.tar.gz`), - { - 'lib/liboliphaunt.so': nativeBinary('linux-arm64-gnu'), - 'lib/modules/dict_snowball.so': nativeBinary('linux-arm64-gnu'), - 'lib/modules/plpgsql.so': nativeBinary('linux-arm64-gnu'), - ...nativeRuntimeEntries('linux-arm64-gnu', icu.icuDataTreeSha256), - }, - 'native-runtime', - nativeRuntimeModes('linux-arm64-gnu'), - ); - await writeProfiledArchive( - path.join(assetDir, `oliphaunt-tools-${version}-linux-arm64-gnu.tar.gz`), - nativeToolsEntries('linux-arm64-gnu'), - 'native-tools', - nativeToolsModes('linux-arm64-gnu'), - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-ios-xcframework.tar.gz`), - appleXcframeworkEntries, - 'native-runtime', - xcframeworkModes(), - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-android-arm64-v8a.tar.gz`), - { 'jni/arm64-v8a/liboliphaunt.so': nativeBinary('android-arm64-v8a') }, - 'native-runtime', - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-android-x86_64.tar.gz`), - { 'jni/x86_64/liboliphaunt.so': nativeBinary('android-x86_64') }, - 'native-runtime', - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-windows-x64-msvc.zip`), - { - 'bin/oliphaunt.dll': nativeBinary('windows-x64-msvc', { provider: true }), - 'lib/oliphaunt.lib': windowsImportLibraryFixture(), - 'lib/modules/dict_snowball.dll': nativeBinary('windows-x64-msvc', { provider: true }), - 'lib/modules/plpgsql.dll': nativeBinary('windows-x64-msvc', { provider: true }), - ...nativeRuntimeEntries('windows-x64-msvc', icu.icuDataTreeSha256), - ...windowsIcuRuntimeEntries(), - ...windowsVcRuntimeEntries(), - }, - 'native-runtime', - nativeRuntimeModes('windows-x64-msvc'), - ); - await writeProfiledArchive( - path.join(assetDir, `oliphaunt-tools-${version}-windows-x64-msvc.zip`), - nativeToolsEntries('windows-x64-msvc'), - 'native-tools', - nativeToolsModes('windows-x64-msvc'), - ); - await writeProfiledArchive( - path.join(assetDir, `liboliphaunt-${version}-apple-spm-xcframework.zip`), - appleXcframeworkEntries, - 'native-runtime', - xcframeworkModes(), - 'liboliphaunt.xcframework', - ); - - await writeChecksumManifest(assetDir, `liboliphaunt-${version}-release-assets.sha256`); -} - -const { assetDir, version } = parseCommonArgs( - Bun.argv.slice(2), - 'Create small liboliphaunt release-shaped assets for SDK package checks.', -); -await writeFixtureAssets(assetDir, version); diff --git a/tools/test/fd-backed-spawn-sync.mjs b/tools/test/fd-backed-spawn-sync.mjs deleted file mode 100644 index 031162470..000000000 --- a/tools/test/fd-backed-spawn-sync.mjs +++ /dev/null @@ -1,193 +0,0 @@ -import { spawnSync as nativeSpawnSync } from 'node:child_process'; - -import { captureCommandBytes } from '../dev/capture-command-output.mjs'; - -const DEFAULT_MAX_BUFFER_BYTES = 1024 * 1024; -const SUPPORTED_CAPTURE_OPTIONS = new Set([ - 'argv0', - 'cwd', - 'encoding', - 'env', - 'gid', - 'input', - 'killSignal', - 'maxBuffer', - 'shell', - 'stdio', - 'timeout', - 'uid', - 'windowsHide', - 'windowsVerbatimArguments', -]); - -function fail(message) { - throw new Error(`fd-backed-spawn-sync: ${message}`); -} - -function invocation(command, argsOrOptions, maybeOptions) { - if (typeof command !== 'string' || command.length === 0) { - fail('command must be a non-empty string'); - } - if (Array.isArray(argsOrOptions)) { - return { args: argsOrOptions, options: maybeOptions ?? {} }; - } - if (argsOrOptions === undefined || argsOrOptions === null) { - return { args: [], options: maybeOptions ?? {} }; - } - if (typeof argsOrOptions === 'object' && maybeOptions === undefined) { - return { args: [], options: argsOrOptions }; - } - fail('arguments must be an array followed by an optional options object'); -} - -function stdioModes(stdio) { - if (stdio === undefined || stdio === null || stdio === 'pipe') { - return ['pipe', 'pipe', 'pipe']; - } - if (stdio === 'ignore' || stdio === 'inherit') { - return [stdio, stdio, stdio]; - } - if (!Array.isArray(stdio) || stdio.length < 3) { - fail('stdio must be pipe, ignore, inherit, or an array with stdin/stdout/stderr entries'); - } - return stdio.slice(0, 3).map((mode) => mode ?? 'pipe'); -} - -function isPipe(mode) { - return mode === 'pipe'; -} - -function safelyClosedOutput(mode) { - return ( - mode === 'ignore' || - mode === 'inherit' || - (Number.isSafeInteger(mode) && mode >= 0) || - (mode !== null && typeof mode === 'object') - ); -} - -function encoded(bytes, encoding) { - if (encoding === undefined || encoding === null || encoding === 'buffer') { - return Buffer.from(bytes); - } - if (typeof encoding !== 'string' || !Buffer.isEncoding(encoding)) { - fail(`unsupported output encoding ${JSON.stringify(encoding)}`); - } - return Buffer.from(bytes).toString(encoding); -} - -function boundedMaxBuffer(value) { - const result = value ?? DEFAULT_MAX_BUFFER_BYTES; - if (!Number.isSafeInteger(result) || result <= 0) { - fail('maxBuffer must be a positive safe integer'); - } - return result; -} - -function throwResult(command, args, result) { - if (result.error !== undefined) throw result.error; - const stderr = - typeof result.stderr === 'string' - ? result.stderr - : Buffer.from(result.stderr ?? []).toString('utf8'); - const detail = stderr.trim(); - const error = new Error( - `Command failed: ${command}${args.length === 0 ? '' : ` ${args.join(' ')}`}` + - (detail ? `\n${detail}` : ''), - ); - Object.assign(error, { - code: result.status, - output: result.output, - pid: result.pid, - signal: result.signal, - status: result.status, - stderr: result.stderr, - stdout: result.stdout, - }); - throw error; -} - -/** - * Test-only synchronous child facade. - * - * Bun 1.3.14 can return from a successful synchronous child before a piped - * stdout/stderr stream has been completely drained. Tests need Node's familiar - * result shape, so capture both output streams through regular files and - * reconstruct that shape after the child has exited. Calls whose output is - * explicitly inherited, ignored, or redirected to caller-owned descriptors do - * not create a pipe and are delegated unchanged. - */ -export function spawnSync(command, argsOrOptions, maybeOptions) { - const { args, options } = invocation(command, argsOrOptions, maybeOptions); - if (options === null || Array.isArray(options) || typeof options !== 'object') { - fail('options must be an object'); - } - const modes = stdioModes(options.stdio); - const capturesStdout = isPipe(modes[1]); - const capturesStderr = isPipe(modes[2]); - if (!capturesStdout && !capturesStderr) { - if (!safelyClosedOutput(modes[1]) || !safelyClosedOutput(modes[2])) { - fail('delegated stdout and stderr must be inherited, ignored, or explicitly redirected'); - } - return nativeSpawnSync(command, args, options); - } - if (!capturesStdout || !capturesStderr) { - fail('mixed captured and delegated stdout/stderr is unsupported'); - } - if (!['pipe', 'ignore'].includes(modes[0])) { - fail('captured calls require piped or ignored stdin'); - } - if (options.input !== undefined && modes[0] !== 'pipe') { - fail('input requires piped stdin'); - } - const unsupported = Object.keys(options).filter((key) => !SUPPORTED_CAPTURE_OPTIONS.has(key)); - if (unsupported.length > 0) { - fail(`captured call uses unsupported options: ${unsupported.sort().join(',')}`); - } - const result = captureCommandBytes(command, args, { - argv0: options.argv0, - cwd: options.cwd, - env: options.env, - gid: options.gid, - input: options.input, - killSignal: options.killSignal, - label: command, - maxOutputBytes: boundedMaxBuffer(options.maxBuffer), - shell: options.shell, - timeout: options.timeout, - uid: options.uid, - windowsHide: options.windowsHide, - windowsVerbatimArguments: options.windowsVerbatimArguments, - }); - const stdout = encoded(result.stdout, options.encoding); - const stderr = encoded(result.stderr, options.encoding); - return { - error: result.error, - output: [null, stdout, stderr], - pid: result.pid, - signal: result.signal, - status: result.status, - stderr, - stdout, - }; -} - -export function execFileSync(command, argsOrOptions, maybeOptions) { - const { args, options } = invocation(command, argsOrOptions, maybeOptions); - const result = spawnSync(command, args, options); - if (result.error !== undefined || result.status !== 0) { - throwResult(command, args, result); - } - return result.stdout; -} - -export function execSync(command, options = {}) { - if (typeof command !== 'string' || command.length === 0) { - fail('execSync command must be a non-empty string'); - } - const result = spawnSync(command, [], { ...options, shell: options.shell ?? true }); - if (result.error !== undefined || result.status !== 0) { - throwResult(command, [], result); - } - return result.stdout; -} diff --git a/tools/test/moon.yml b/tools/test/moon.yml deleted file mode 100644 index 9cf94b8b5..000000000 --- a/tools/test/moon.yml +++ /dev/null @@ -1,27 +0,0 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "test-tools" -language: "javascript" -layer: "tool" -stack: "infrastructure" -tags: ["tools", "testing", "repo-hygiene"] - -project: - title: "Test Tools" - description: "Fixture builders used by repository integration tests." - owner: "oliphaunt" - -owners: - defaultOwner: "@oliphaunt/core" - paths: - "**/*": ["@oliphaunt/core"] - -tasks: - check: - tags: ["quality", "static"] - command: "bun build tools/test/create-liboliphaunt-release-fixture.mjs tools/test/create-broker-release-fixture.mjs --target=bun --outdir target/moon/test-tools/check" - inputs: - - "**/*" - options: - cache: true - runFromWorkspaceRoot: true diff --git a/tools/test/release-fixture-utils.mjs b/tools/test/release-fixture-utils.mjs deleted file mode 100644 index 7baed0fb5..000000000 --- a/tools/test/release-fixture-utils.mjs +++ /dev/null @@ -1,351 +0,0 @@ -import { createHash } from 'node:crypto'; -import { spawnSync } from 'node:child_process'; -import fs from 'node:fs/promises'; -import os from 'node:os'; -import path from 'node:path'; - -const ARCHIVE_DIR = path.resolve( - import.meta.dir, - '../../src/shared/artifact-packaging/archive-directory.mjs', -); - -export function fail(message) { - console.error(`release-fixture-utils.mjs: ${message}`); - process.exit(1); -} - -export function parseCommonArgs(argv, description) { - const args = new Map(); - for (let index = 0; index < argv.length; index += 1) { - const key = argv[index]; - const value = argv[index + 1]; - if (!key.startsWith('--') || value === undefined || value.startsWith('--')) { - fail(`${description}\nusage: --asset-dir --version `); - } - args.set(key, value); - index += 1; - } - const assetDir = args.get('--asset-dir'); - const version = args.get('--version'); - if (!assetDir || !version || args.size !== 2) { - fail(`${description}\nusage: --asset-dir --version `); - } - return { assetDir: path.resolve(assetDir), version }; -} - -export async function writeEntriesArchive(output, entries, modes = {}) { - const stage = await fs.mkdtemp(path.join(os.tmpdir(), 'oliphaunt-release-fixture-')); - try { - for (const [name, data] of Object.entries(entries).sort(([left], [right]) => - left.localeCompare(right), - )) { - const file = path.join(stage, ...name.split('/')); - if (name.endsWith('/')) { - await fs.mkdir(file, { recursive: true }); - continue; - } - await fs.mkdir(path.dirname(file), { recursive: true }); - await fs.writeFile(file, data); - await fs.chmod(file, modes[name] ?? 0o644); - } - await archiveDirectory(stage, output); - } finally { - await fs.rm(stage, { recursive: true, force: true }); - } -} - -export async function archiveDirectory(source, output) { - const result = spawnSync(process.execPath, [ARCHIVE_DIR, source, output], { - stdio: 'inherit', - }); - if (result.status !== 0) { - fail(`failed to create archive ${output}`); - } -} - -export async function writeChecksumManifest(assetDir, name) { - const checksumAsset = path.join(assetDir, name); - const dirents = await fs.readdir(assetDir, { withFileTypes: true }); - const files = dirents - .filter((entry) => entry.isFile() && entry.name !== name) - .map((entry) => entry.name) - .sort(); - const lines = []; - for (const file of files) { - const digest = createHash('sha256') - .update(await fs.readFile(path.join(assetDir, file))) - .digest('hex'); - lines.push(`${digest} ./${file}`); - } - await fs.writeFile(checksumAsset, `${lines.join('\n')}\n`, 'utf8'); -} - -function packedAppleVersion(major, minor = 0, patch = 0) { - return (major << 16) | (minor << 8) | patch; -} - -export function machoFixture({ - platform = 1, - minos = [11, 0, 0], - cpu = 0x0100000c, - cpuSubtype = 0, -} = {}) { - const commandSize = 24; - const buffer = Buffer.alloc(32 + commandSize); - buffer.writeUInt32LE(0xfeedfacf, 0); - buffer.writeUInt32LE(cpu, 4); - buffer.writeUInt32LE(cpuSubtype, 8); - buffer.writeUInt32LE(6, 12); - buffer.writeUInt32LE(1, 16); - buffer.writeUInt32LE(commandSize, 20); - buffer.writeUInt32LE(0, 24); - buffer.writeUInt32LE(0, 28); - buffer.writeUInt32LE(0x32, 32); - buffer.writeUInt32LE(commandSize, 36); - buffer.writeUInt32LE(platform, 40); - buffer.writeUInt32LE(packedAppleVersion(...minos), 44); - buffer.writeUInt32LE(packedAppleVersion(...minos), 48); - buffer.writeUInt32LE(0, 52); - return buffer; -} - -function align(value, alignment) { - return Math.ceil(value / alignment) * alignment; -} - -export function elfFixture({ - machine = 62, - requiredVersions = [], - androidApi = null, - type = 3, -} = {}) { - const versionBytes = Buffer.from(`\0${requiredVersions.join('\0')}\0`, 'ascii'); - const note = androidApi === null ? null : Buffer.alloc(24); - if (note !== null) { - note.writeUInt32LE(8, 0); - note.writeUInt32LE(4, 4); - note.writeUInt32LE(1, 8); - note.write('Android\0', 12, 'ascii'); - note.writeUInt32LE(androidApi, 20); - } - const noteOffset = align(64 + versionBytes.length, 4); - const sectionOffset = note === null ? 0 : align(noteOffset + note.length, 8); - const buffer = Buffer.alloc(note === null ? 64 + versionBytes.length : sectionOffset + 128); - Buffer.from([0x7f, 0x45, 0x4c, 0x46]).copy(buffer, 0); - buffer[4] = 2; - buffer[5] = 1; - buffer[6] = 1; - buffer.writeUInt16LE(type, 16); - buffer.writeUInt16LE(machine, 18); - buffer.writeUInt32LE(1, 20); - buffer.writeUInt16LE(64, 52); - versionBytes.copy(buffer, 64); - if (note !== null) { - note.copy(buffer, noteOffset); - buffer.writeBigUInt64LE(BigInt(sectionOffset), 40); - buffer.writeUInt16LE(64, 58); - buffer.writeUInt16LE(2, 60); - const noteSection = sectionOffset + 64; - buffer.writeUInt32LE(7, noteSection + 4); - buffer.writeBigUInt64LE(BigInt(noteOffset), noteSection + 24); - buffer.writeBigUInt64LE(BigInt(note.length), noteSection + 32); - buffer.writeBigUInt64LE(4n, noteSection + 48); - } - return buffer; -} - -export function windowsPeFixture({ machine = 0x8664, imports = [], delayImports = [] } = {}) { - const peOffset = 0x80; - const optionalSize = 240; - const sectionTable = peOffset + 24 + optionalSize; - const rawOffset = 0x200; - const rawSize = 0x400; - const virtualAddress = 0x1000; - const buffer = Buffer.alloc(rawOffset + rawSize); - buffer.write('MZ', 0, 'ascii'); - buffer.writeUInt32LE(peOffset, 0x3c); - buffer.write('PE\0\0', peOffset, 'ascii'); - const coff = peOffset + 4; - buffer.writeUInt16LE(machine, coff); - buffer.writeUInt16LE(1, coff + 2); - buffer.writeUInt16LE(optionalSize, coff + 16); - buffer.writeUInt16LE(0x2022, coff + 18); - const optional = coff + 20; - buffer.writeUInt16LE(0x20b, optional); - buffer.writeBigUInt64LE(0x140000000n, optional + 24); - buffer.writeUInt32LE(rawOffset, optional + 60); - buffer.writeUInt32LE(16, optional + 108); - const descriptorBytes = (imports.length + 1) * 20; - if (imports.length > 0) { - buffer.writeUInt32LE(virtualAddress, optional + 120); - buffer.writeUInt32LE(descriptorBytes, optional + 124); - } - if (delayImports.length > 0) { - const delayDescriptorOffset = rawOffset + 0x100; - buffer.writeUInt32LE(virtualAddress + delayDescriptorOffset - rawOffset, optional + 216); - buffer.writeUInt32LE((delayImports.length + 1) * 32, optional + 220); - } - buffer.write('.rdata\0\0', sectionTable, 'ascii'); - buffer.writeUInt32LE(rawSize, sectionTable + 8); - buffer.writeUInt32LE(virtualAddress, sectionTable + 12); - buffer.writeUInt32LE(rawSize, sectionTable + 16); - buffer.writeUInt32LE(rawOffset, sectionTable + 20); - let nameOffset = rawOffset + 0x200; - for (let index = 0; index < imports.length; index += 1) { - const descriptor = rawOffset + index * 20; - buffer.writeUInt32LE(virtualAddress + nameOffset - rawOffset, descriptor + 12); - buffer.write(`${imports[index]}\0`, nameOffset, 'ascii'); - nameOffset += Buffer.byteLength(imports[index]) + 1; - } - for (let index = 0; index < delayImports.length; index += 1) { - const descriptor = rawOffset + 0x100 + index * 32; - buffer.writeUInt32LE(1, descriptor); - buffer.writeUInt32LE(virtualAddress + nameOffset - rawOffset, descriptor + 4); - buffer.write(`${delayImports[index]}\0`, nameOffset, 'ascii'); - nameOffset += Buffer.byteLength(delayImports[index]) + 1; - } - return buffer; -} - -function coffArchiveMember(rawName, data) { - if (!Buffer.isBuffer(data)) { - throw new TypeError('COFF archive fixture member data must be a Buffer'); - } - if (!rawName || Buffer.byteLength(rawName, 'ascii') > 16) { - throw new Error(`invalid COFF archive fixture member name ${JSON.stringify(rawName)}`); - } - const header = Buffer.from( - `${rawName.padEnd(16, ' ')}${'0'.padEnd(12, ' ')}${'0'.padEnd(6, ' ')}${'0'.padEnd(6, ' ')}${'100644'.padEnd(8, ' ')}${String(data.length).padEnd(10, ' ')}\`\n`, - 'ascii', - ); - return Buffer.concat([ - header, - data, - ...(data.length % 2 === 0 ? [] : [Buffer.from('\n', 'ascii')]), - ]); -} - -function coffObjectFixture(machine, symbol) { - const symbolBytes = Buffer.from(`${symbol}\0`, 'ascii'); - const symbolTable = 20 + 40; - const stringTable = symbolTable + 18; - const buffer = Buffer.alloc(stringTable + 4 + symbolBytes.length); - buffer.writeUInt16LE(machine, 0); - buffer.writeUInt16LE(1, 2); - buffer.writeUInt32LE(symbolTable, 8); - buffer.writeUInt32LE(1, 12); - buffer.writeUInt16LE(0, 16); - buffer.write('.drectve', 20, 'ascii'); - buffer.writeUInt32LE(0, symbolTable); - buffer.writeUInt32LE(4, symbolTable + 4); - buffer.writeInt16LE(1, symbolTable + 12); - buffer.writeUInt8(2, symbolTable + 16); - buffer.writeUInt32LE(4 + symbolBytes.length, stringTable); - symbolBytes.copy(buffer, stringTable + 4); - return buffer; -} - -function coffImportObjectFixture({ dllName, machine, symbol }) { - const strings = Buffer.from(`${symbol}\0${dllName}\0`, 'ascii'); - const buffer = Buffer.alloc(20 + strings.length); - buffer.writeUInt16LE(0, 0); - buffer.writeUInt16LE(0xffff, 2); - buffer.writeUInt16LE(0, 4); - buffer.writeUInt16LE(machine, 6); - buffer.writeUInt32LE(strings.length, 12); - buffer.writeUInt16LE(1 << 2, 18); - strings.copy(buffer, 20); - return buffer; -} - -function nullTerminatedAscii(values) { - return Buffer.from(`${values.join('\0')}\0`, 'ascii'); -} - -export const OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS = Object.freeze([ - 'oliphaunt_backup', - 'oliphaunt_backup_with_error', - 'oliphaunt_cancel', - 'oliphaunt_close', - 'oliphaunt_close_if_generation', - 'oliphaunt_copy_last_error', - 'oliphaunt_detach', - 'oliphaunt_detach_with_error', - 'oliphaunt_exec_protocol', - 'oliphaunt_exec_protocol_raw_stream', - 'oliphaunt_exec_protocol_raw_stream_with_error', - 'oliphaunt_exec_protocol_with_error', - 'oliphaunt_exec_simple_query', - 'oliphaunt_exec_simple_query_with_error', - 'oliphaunt_free_response', - 'oliphaunt_init', - 'oliphaunt_init_with_error', - 'oliphaunt_logical_generation', - 'oliphaunt_register_static_extensions', - 'oliphaunt_restore', - 'oliphaunt_restore_with_error', - 'oliphaunt_version', -]); - -export function windowsImportLibraryFixture({ - dllName = 'oliphaunt.dll', - importMachine = 0x8664, - objectMachine = 0x8664, - symbol, - importSymbols = symbol === undefined ? OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS : [symbol], -} = {}) { - if (!Array.isArray(importSymbols) || importSymbols.length === 0) { - throw new Error('Windows import-library fixture requires at least one import symbol'); - } - const descriptorSymbol = '__IMPORT_DESCRIPTOR_oliphaunt'; - const symbols = [descriptorSymbol, ...importSymbols]; - const firstNames = nullTerminatedAscii(symbols); - const secondNames = nullTerminatedAscii(symbols); - const firstSize = 4 + symbols.length * 4 + firstNames.length; - const memberCount = 1 + importSymbols.length; - const secondSize = 4 + memberCount * 4 + 4 + symbols.length * 2 + secondNames.length; - const paddedMemberSize = (size) => 60 + size + (size % 2); - const firstOffset = 8; - const secondOffset = firstOffset + paddedMemberSize(firstSize); - const descriptorOffset = secondOffset + paddedMemberSize(secondSize); - const descriptor = coffObjectFixture(objectMachine, descriptorSymbol); - const memberOffsets = [descriptorOffset]; - let nextOffset = descriptorOffset + paddedMemberSize(descriptor.length); - const importObjects = importSymbols.map((importSymbol) => { - const object = coffImportObjectFixture({ - dllName, - machine: importMachine, - symbol: importSymbol, - }); - memberOffsets.push(nextOffset); - nextOffset += paddedMemberSize(object.length); - return object; - }); - - const first = Buffer.alloc(firstSize); - first.writeUInt32BE(symbols.length, 0); - for (let index = 0; index < memberOffsets.length; index += 1) { - first.writeUInt32BE(memberOffsets[index], 4 + index * 4); - } - firstNames.copy(first, 4 + memberOffsets.length * 4); - - const second = Buffer.alloc(secondSize); - second.writeUInt32LE(memberCount, 0); - for (let index = 0; index < memberOffsets.length; index += 1) { - second.writeUInt32LE(memberOffsets[index], 4 + index * 4); - } - const symbolCountOffset = 4 + memberCount * 4; - second.writeUInt32LE(symbols.length, symbolCountOffset); - for (let index = 0; index < symbols.length; index += 1) { - second.writeUInt16LE(index + 1, symbolCountOffset + 4 + index * 2); - } - secondNames.copy(second, symbolCountOffset + 4 + symbols.length * 2); - - return Buffer.concat([ - Buffer.from('!\n', 'ascii'), - coffArchiveMember('/', first), - coffArchiveMember('/', second), - coffArchiveMember('descr.obj/', descriptor), - ...importObjects.map((object, index) => coffArchiveMember(`import${index}.obj/`, object)), - ]); -} diff --git a/tools/xtask/Cargo.toml b/tools/xtask/Cargo.toml deleted file mode 100644 index c489886bc..000000000 --- a/tools/xtask/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -[package] -name = "xtask" -version = "0.0.0" -edition = "2024" -rust-version = "1.93" -license.workspace = true -publish = false - -[features] -default = [] -wasix-runner = ["dep:wasmer", "dep:wasmer-wasix", "dep:webc"] -cluster-seed-runner = [ - "wasix-runner", - "wasmer/llvm", - "wasmer-wasix/host-fs", - "dep:tokio", -] -aot-serializer = [ - "cluster-seed-runner", - "wasmer/wasmer-artifact-create", - "dep:wasmer-types", -] - -[dependencies] -anyhow = "1" -async-trait = "0.1" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -sha2 = "0.10" -tar = "0.4" -tokio = { version = "1", features = ["rt-multi-thread"], optional = true } -toml = "0.9" -walkdir = "2" -wasmer = { version = "=7.2.1", default-features = false, features = [ - "sys", -], optional = true } -wasmer-types = { version = "=7.2.1", optional = true } -wasmer-wasix = { version = "=0.702.1", default-features = false, features = [ - "sys-minimal", - "sys-poll", - "sys-thread", - "time", -], optional = true } -wasmparser = "0.250.0" -webc = { version = "=12.0.0", optional = true } -zstd = "0.13" diff --git a/tools/xtask/moon.yml b/tools/xtask/moon.yml deleted file mode 100644 index 73e9c1323..000000000 --- a/tools/xtask/moon.yml +++ /dev/null @@ -1,54 +0,0 @@ -$schema: "https://moonrepo.dev/schemas/project.json" - -id: "xtask" -language: "rust" -layer: "tool" -stack: "systems" -tags: ["tools", "rust", "xtask", "wasix"] - -project: - title: "WASIX and Extension Asset Tooling" - description: "Rust checks and generators shared by WASIX runtime and extension assets." - owner: "oliphaunt" - -owners: - defaultOwner: "@oliphaunt/wasix" - paths: - "**/*.rs": ["@oliphaunt/wasix"] - "Cargo.toml": ["@oliphaunt/wasix"] - -tasks: - unit: - tags: ["quality", "unit", "requires-rust"] - command: "cargo test -p xtask --locked" - env: - CARGO_TARGET_DIR: "target/moon/xtask/unit" - inputs: - - "@group(cargo-workspace)" - - "**/*" - options: - cache: true - runFromWorkspaceRoot: true - cluster-seed-compile: - tags: ["quality", "static", "wasix"] - command: "cargo check -p xtask --features cluster-seed-runner --locked" - env: - CARGO_TARGET_DIR: "target/moon/xtask/cluster-seed-compile" - inputs: - - "@group(cargo-workspace)" - - "**/*" - options: - cache: true - runFromWorkspaceRoot: true - runInCI: skip - aot-serializer-compile: - tags: ["quality", "static", "requires-rust", "requires-wasmer-llvm"] - command: "cargo check -p xtask --features aot-serializer --locked" - env: - CARGO_TARGET_DIR: "target/moon/xtask/aot-serializer-compile" - inputs: - - "@group(cargo-workspace)" - - "**/*" - options: - cache: true - runFromWorkspaceRoot: true diff --git a/tools/xtask/src/asset_checks.rs b/tools/xtask/src/asset_checks.rs deleted file mode 100644 index 6a8d65231..000000000 --- a/tools/xtask/src/asset_checks.rs +++ /dev/null @@ -1,1497 +0,0 @@ -use super::*; -use crate::source_spine::source_checkout_path; - -pub(crate) fn check_generated_manifest(manifest: &SourcesManifest, strict: bool) -> Result<()> { - check_generated_manifest_with_outputs( - manifest, - strict, - BuildOutputs::discover_for_source_lane(DEFAULT_SOURCE_LANE), - ) -} - -pub(crate) fn check_generated_manifest_for_aot( - manifest: &SourcesManifest, - strict: bool, -) -> Result<()> { - check_generated_manifest_with_outputs( - manifest, - strict, - BuildOutputs::discover_for_aot(DEFAULT_SOURCE_LANE), - ) -} - -fn check_generated_manifest_with_outputs( - manifest: &SourcesManifest, - strict: bool, - outputs: Result, -) -> Result<()> { - let source_lane = DEFAULT_SOURCE_LANE; - match outputs.and_then(|outputs| effective_source_pins(manifest, &outputs)) { - Ok(expected_sources) => check_generated_manifest_sources_in( - generated_assets_dir_for_source_lane(source_lane)?, - &expected_sources, - source_lane, - strict, - ), - Err(err) if !strict => { - eprintln!( - "warning: skipping generated asset manifest source-pin check for {source_lane}: {err:#}" - ); - Ok(()) - } - Err(err) => Err(err).context("derive expected generated asset manifest source pins"), - } -} - -pub(crate) fn check_generated_manifest_sources_in( - asset_dir: &Path, - expected_sources: &[SourcePin], - expected_label: &str, - strict: bool, -) -> Result<()> { - let path = asset_dir.join("manifest.json"); - if !path.exists() { - if strict { - bail!("generated asset manifest is missing at {}", path.display()); - } - eprintln!( - "warning: generated asset manifest is missing at {}", - path.display() - ); - return Ok(()); - } - - let text = fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?; - let generated: GeneratedAssetManifest = - serde_json::from_str(&text).with_context(|| format!("parse {}", path.display()))?; - if expected_label == DEFAULT_SOURCE_LANE { - let actual = generated.source_lane.as_deref().unwrap_or(""); - ensure_eq( - actual, - expected_label, - "generated asset manifest source-lane", - )?; - } - - let mut drift = Vec::new(); - for source in expected_sources { - match generated - .sources - .iter() - .find(|generated| generated.name == source.name) - { - Some(generated) - if generated.url == source.url - && generated.branch == source.branch - && generated.commit == source.commit => {} - Some(generated) => drift.push(format!( - "{} generated={}/{}@{} expected={}/{}@{}", - source.name, - generated.url, - generated.branch, - generated.commit, - source.url, - source.branch, - source.commit - )), - None => drift.push(format!("{} missing from generated manifest", source.name)), - } - } - let expected_source_names = expected_sources - .iter() - .map(|source| source.name.as_str()) - .collect::>(); - for source in &generated.sources { - if !expected_source_names.contains(source.name.as_str()) { - drift.push(format!( - "{} is unexpected in generated manifest", - source.name - )); - } - } - - if drift.is_empty() { - println!("generated asset manifest source pins match {expected_label}"); - return Ok(()); - } - - let details = drift.join("; "); - if strict { - bail!("generated asset manifest has stale source pins: {details}"); - } - eprintln!("warning: generated asset manifest has stale source pins: {details}"); - Ok(()) -} - -pub(crate) fn verify_committed_assets() -> Result<()> { - check_source_free_repo()?; - let manifest = load_sources_manifest()?; - validate_sources_manifest(&manifest)?; - check_no_legacy_runtime_shims()?; - check_production_wasix_build_inputs()?; - check_postgres_source_spine()?; - check_source_lane_isolation()?; - check_rust_startup_abi_boundary()?; - check_no_committed_portable_asset_blobs()?; - check_no_committed_aot_artifacts()?; - check_aot_crate_templates(&manifest)?; - verify_generated_extension_surface_if_available()?; - check_source_controlled_wasix_export_list()?; - println!("source-controlled asset inputs and crate templates passed"); - Ok(()) -} - -pub(crate) fn check_source_free_repo() -> Result<()> { - if Path::new(".gitmodules").exists() { - bail!("tracked upstream source checkouts are not allowed: remove .gitmodules"); - } - if is_release_staged_workspace() && !Path::new(".git").exists() { - return Ok(()); - } - for path in [ - "src/runtimes/liboliphaunt/wasix/assets/build/build", - "src/runtimes/liboliphaunt/wasix/assets/build/work", - ] { - if Path::new(path).exists() { - bail!( - "{path} must not exist under source control roots; generated WASIX build/work data lives under target/oliphaunt-wasix/wasix-build" - ); - } - } - for path in [ - "assets", - SOURCE_CHECKOUT_ROOT, - WASIX_GENERATED_BUILD_DIR, - WASIX_GENERATED_WORK_DIR, - GENERATED_ASSETS_DIR, - RELEASE_STAGE_DIR, - ] { - let tracked = command_output("git", &["ls-files", path], Path::new("."))?; - if !tracked.trim().is_empty() { - bail!( - "{path} contains tracked generated/source checkout files:\n{}", - tracked.trim() - ); - } - } - Ok(()) -} - -pub(crate) fn is_release_staged_workspace() -> bool { - env::var_os("OLIPHAUNT_WASM_RELEASE_STAGED").as_deref() == Some(std::ffi::OsStr::new("1")) -} - -fn check_no_committed_portable_asset_blobs() -> Result<()> { - let tracked = command_output( - "git", - &[ - "ls-files", - ASSET_CRATE_PAYLOAD_DIR, - LEGACY_STATIC_WASI_ARCHIVE, - "assets/bin", - "assets/prepopulated", - "src/extensions/artifacts/*.tar.gz", - ], - Path::new("."), - )?; - if !tracked.trim().is_empty() { - bail!( - "portable WASIX asset payloads must be generated by CI/release and must not be committed:\n{}", - tracked.trim() - ); - } - println!("committed repo contains no portable WASIX asset blobs"); - Ok(()) -} - -pub(crate) fn verify_asset_manifest_hashes() -> Result<()> { - let manifest_path = Path::new(GENERATED_ASSETS_DIR).join("manifest.json"); - let text = fs::read_to_string(&manifest_path) - .with_context(|| format!("read {}", manifest_path.display()))?; - let manifest: AssetManifestOut = - serde_json::from_str(&text).context("parse generated asset manifest")?; - let base = Path::new(GENERATED_ASSETS_DIR); - - let runtime_archive = base.join(&manifest.runtime.archive); - verify_file_sha256( - &runtime_archive, - &manifest.runtime.sha256, - "runtime archive", - )?; - let runtime_module = archive_entry_bytes(&runtime_archive, RUNTIME_MODULE_ARCHIVE_MEMBER)?; - ensure_eq( - &sha256_bytes(&runtime_module), - &manifest.runtime.module_sha256, - "runtime module sha256", - )?; - for module in &manifest.runtime_support { - let bytes = archive_entry_bytes(&runtime_archive, &format!("oliphaunt/{}", module.path))?; - ensure_eq( - &sha256_bytes(&bytes), - &module.sha256, - &format!("runtime support {} sha256", module.name), - )?; - ensure_eq( - &sha256_bytes(&bytes), - &module.module_sha256, - &format!("runtime support {} module sha256", module.name), - )?; - } - - if let Some(pg_dump) = &manifest.pg_dump { - verify_file_sha256(&base.join(&pg_dump.path), &pg_dump.sha256, "pg_dump wasm")?; - ensure_eq( - &pg_dump.sha256, - &pg_dump.module_sha256, - "pg_dump module sha256", - )?; - } - if let Some(psql) = &manifest.psql { - verify_file_sha256(&base.join(&psql.path), &psql.sha256, "psql wasm")?; - ensure_eq(&psql.sha256, &psql.module_sha256, "psql module sha256")?; - } - if let Some(initdb) = &manifest.initdb { - verify_file_sha256(&base.join(&initdb.path), &initdb.sha256, "initdb wasm")?; - ensure_eq( - &initdb.sha256, - &initdb.module_sha256, - "initdb module sha256", - )?; - } - - for extension in &manifest.extensions { - let archive = base.join(&extension.archive); - verify_file_sha256( - &archive, - &extension.sha256, - &format!("extension {} archive", extension.sql_name), - )?; - if let Some(native_module) = &extension.native_module { - let entry = format!("lib/postgresql/{native_module}"); - let bytes = archive_entry_bytes(&archive, &entry)?; - ensure_eq( - &sha256_bytes(&bytes), - &extension.module_sha256, - &format!("extension {} module sha256", extension.sql_name), - )?; - } - for module in &extension.native_modules { - let bytes = archive_entry_bytes(&archive, &module.path)?; - ensure_eq( - &sha256_bytes(&bytes), - &module.module_sha256, - &format!( - "extension {} native module {} sha256", - extension.sql_name, module.name - ), - )?; - } - } - - for (profile, seed) in &manifest.cluster_seeds { - verify_cluster_seed_hash( - profile, - &base.join(&seed.archive), - &base.join(&seed.manifest), - )?; - verify_file_sha256( - &base.join(&seed.archive), - &seed.sha256, - &format!("{profile} cluster seed"), - )?; - ensure_file(&base.join(&seed.manifest))?; - ensure_eq( - &seed.runtime_module_sha256, - &manifest.runtime.module_sha256, - &format!("{profile} cluster seed runtime module sha256"), - )?; - if let Some(initdb) = &manifest.initdb { - ensure_eq( - &seed.initdb_module_sha256, - &initdb.module_sha256, - &format!("{profile} cluster seed initdb module sha256"), - )?; - } - } - ensure!( - manifest - .cluster_seeds - .keys() - .map(String::as_str) - .collect::>() - == ["icu", "standard"], - "generated asset manifest must contain exactly the icu and standard cluster seeds" - ); - - if is_release_staged_workspace() { - verify_root_asset_metadata(&manifest, &manifest.runtime.module_sha256)?; - } - - println!("generated asset hashes match manifests"); - Ok(()) -} - -fn verify_cluster_seed_hash(profile: &str, archive: &Path, manifest_path: &Path) -> Result<()> { - ensure!( - manifest_path.exists() && archive.exists(), - "generated assets must include the {profile} cluster seed archive and manifest; expected both {} and {}", - manifest_path.display(), - archive.display() - ); - let text = fs::read_to_string(manifest_path) - .with_context(|| format!("read {}", manifest_path.display()))?; - let manifest: serde_json::Value = serde_json::from_str(&text) - .with_context(|| format!("parse {}", manifest_path.display()))?; - let expected = manifest - .get("archive") - .and_then(serde_json::Value::as_object) - .and_then(|archive| archive.get("sha256")) - .and_then(serde_json::Value::as_str) - .ok_or_else(|| anyhow!("{} is missing archive.sha256", manifest_path.display()))?; - ensure_eq( - manifest - .get("catalogProfile") - .and_then(serde_json::Value::as_str) - .unwrap_or(""), - profile, - "cluster seed catalogProfile", - )?; - verify_file_sha256( - archive, - expected, - &format!("{profile} cluster seed archive"), - )?; - Ok(()) -} - -fn verify_root_asset_metadata( - manifest: &AssetManifestOut, - runtime_module_sha256: &str, -) -> Result<()> { - verify_root_metadata_value( - "runtime-archive-sha256", - &manifest.runtime.sha256, - "runtime archive metadata", - )?; - verify_root_metadata_value( - "oliphaunt-wasix-sha256", - runtime_module_sha256, - "runtime module metadata", - )?; - verify_root_metadata_value( - "postgres-version", - &manifest.runtime.postgres_version, - "PostgreSQL version metadata", - )?; - let pg18 = load_postgres_source_manifest()?; - verify_root_metadata_value( - "postgres-source-url", - &pg18.postgresql.url, - "PostgreSQL source URL metadata", - )?; - verify_root_metadata_value( - "postgres-source-sha256", - &pg18.postgresql.sha256, - "PostgreSQL source sha256 metadata", - )?; - verify_root_metadata_value( - "postgres-patch-count", - &pg18.patches.series.len().to_string(), - "PostgreSQL patch count metadata", - )?; - for profile in ["standard", "icu"] { - let seed = manifest.cluster_seeds.get(profile).with_context(|| { - format!("generated asset manifest is missing {profile} cluster seed") - })?; - verify_root_metadata_value( - &format!("cluster-seed-{profile}-archive-sha256"), - &seed.sha256, - &format!("{profile} cluster seed archive metadata"), - )?; - } - if let Some(pg_dump) = &manifest.pg_dump { - verify_tools_metadata_value("pg-dump-wasix-sha256", &pg_dump.sha256, "pg_dump metadata")?; - } - if let Some(psql) = &manifest.psql { - verify_tools_metadata_value("psql-wasix-sha256", &psql.sha256, "psql metadata")?; - } - if let Some(initdb) = &manifest.initdb { - verify_root_metadata_value("initdb-wasix-sha256", &initdb.sha256, "initdb metadata")?; - } - verify_wasix_tools_npm_descriptor(manifest)?; - Ok(()) -} - -fn verify_wasix_tools_npm_descriptor(manifest: &AssetManifestOut) -> Result<()> { - let actual = fs::read_to_string(WASIX_TOOLS_NPM_DESCRIPTOR_PATH) - .with_context(|| format!("read {WASIX_TOOLS_NPM_DESCRIPTOR_PATH}"))?; - let expected = update_wasix_tools_npm_descriptor(&actual, manifest)?; - ensure_eq( - &actual, - &expected, - "WASIX tools npm workspace descriptor metadata", - ) -} - -fn verify_root_metadata_value(key: &str, expected: &str, field: &str) -> Result<()> { - let actual = cargo_metadata_value( - "src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml", - key, - )?; - ensure_eq(&actual, expected, field) -} - -fn verify_tools_metadata_value(key: &str, expected: &str, field: &str) -> Result<()> { - let actual = cargo_metadata_value( - "src/runtimes/liboliphaunt/wasix/crates/tools/Cargo.toml", - key, - )?; - ensure_eq(&actual, expected, field) -} - -fn cargo_metadata_value(path: &str, key: &str) -> Result { - let text = fs::read_to_string(path).with_context(|| format!("read {path}"))?; - let needle = format!("{key} = \""); - let start = text - .find(&needle) - .ok_or_else(|| anyhow!("{path} metadata key '{key}' is missing"))? - + needle.len(); - let end = text[start..] - .find('"') - .ok_or_else(|| anyhow!("{path} metadata key '{key}' is unterminated"))?; - Ok(text[start..start + end].to_owned()) -} - -fn verify_file_sha256(path: &Path, expected: &str, field: &str) -> Result<()> { - ensure_file(path)?; - let actual = sha256_file(path)?; - ensure_eq(&actual, expected, field) -} - -fn check_no_committed_aot_artifacts() -> Result<()> { - let tracked = command_output( - "git", - &["ls-files", "src/runtimes/liboliphaunt/wasix/crates/aot"], - Path::new("."), - )?; - let committed_artifacts = tracked - .lines() - .filter(|path| path.contains("/artifacts/")) - .collect::>(); - if !committed_artifacts.is_empty() { - bail!( - "native AOT artifacts must be generated by CI and must not be committed:\n{}", - committed_artifacts.join("\n") - ); - } - println!("committed repo contains no native AOT artifact blobs"); - Ok(()) -} - -fn check_aot_crate_templates(sources: &SourcesManifest) -> Result<()> { - let expected = supported_aot_targets(); - for target in expected { - let crate_dir = Path::new("src/runtimes/liboliphaunt/wasix/crates/aot").join(target); - ensure_file(&crate_dir.join("Cargo.toml"))?; - ensure_file(&crate_dir.join("README.md"))?; - ensure_file(&crate_dir.join("build.rs"))?; - let lib = crate_dir.join("src/lib.rs"); - ensure_file(&lib)?; - - let cargo_toml = fs::read_to_string(crate_dir.join("Cargo.toml")) - .with_context(|| format!("read {}/Cargo.toml", crate_dir.display()))?; - if !cargo_toml.contains("\"build.rs\"") || !cargo_toml.contains("\"artifacts/**\"") { - bail!( - "{} must include build.rs and generated artifacts/** when CI materializes the AOT crate", - crate_dir.join("Cargo.toml").display() - ); - } - - let lib_text = - fs::read_to_string(&lib).with_context(|| format!("read {}", lib.display()))?; - for required in [ - "#![deny(unsafe_code)]", - "include!(concat!(env!(\"OUT_DIR\")", - ] { - if !lib_text.contains(required) { - bail!("{} is not a source-only AOT crate template", lib.display()); - } - } - if lib_text.contains("include_bytes!") || lib_text.contains("include_str!(\"../artifacts/") - { - bail!( - "{} embeds generated AOT artifacts; generated artifacts belong only in CI/release workspaces", - lib.display() - ); - } - let build_rs = fs::read_to_string(crate_dir.join("build.rs")) - .with_context(|| format!("read {}/build.rs", crate_dir.display()))?; - for required in [ - "OLIPHAUNT_WASM_GENERATED_AOT_DIR", - "target/oliphaunt-wasix/aot", - "wasmer-version", - sources.toolchain.wasmer.as_str(), - "wasmer-wasix-version", - sources.toolchain.wasmer_wasix.as_str(), - ] { - if !build_rs.contains(required) { - bail!( - "{} build.rs is missing source-only AOT marker {required}", - crate_dir.display() - ); - } - } - } - println!("AOT crates are source-only templates for CI-generated release artifacts"); - Ok(()) -} - -#[derive(Debug, Clone, Copy)] -struct AotTargetSpec { - triple: &'static str, - target_id: &'static str, - runner_os: &'static str, - package: &'static str, - llvm_url: &'static str, - llvm_sha256: &'static str, - llvm_bytes: u64, -} - -#[derive(Debug, Serialize)] -struct AotCiMatrix { - include: Vec, -} - -#[derive(Debug, Serialize)] -struct AotCiTarget { - os: &'static str, - target: &'static str, - target_id: &'static str, - package: &'static str, - artifact: String, - llvm_url: &'static str, - llvm_sha256: &'static str, - llvm_bytes: u64, -} - -fn aot_target_specs() -> &'static [AotTargetSpec] { - &[ - AotTargetSpec { - triple: "aarch64-apple-darwin", - target_id: "macos-arm64", - runner_os: "macos-26", - package: "liboliphaunt-wasix-aot-aarch64-apple-darwin", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-darwin-aarch64.tar.xz", - llvm_sha256: "f64460f6c8a28876737402542fc5b28bb1f4262cef85f799b65ce2a7ee6f8847", - llvm_bytes: 479_103_872, - }, - AotTargetSpec { - triple: "x86_64-unknown-linux-gnu", - target_id: "linux-x64-gnu", - runner_os: "ubuntu-24.04", - package: "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-linux-amd64.tar.xz", - llvm_sha256: "5fb1c687c5e895d517a23e7aabea9ec3557e3a3e33f8a8d3a8d21395157b3906", - llvm_bytes: 741_670_068, - }, - AotTargetSpec { - triple: "aarch64-unknown-linux-gnu", - target_id: "linux-arm64-gnu", - runner_os: "ubuntu-24.04-arm", - package: "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-linux-aarch64.tar.xz", - llvm_sha256: "1fddcf5b30f9d3e073eb161509220b4136ea8e2f114f23084bdec33e40fa87c1", - llvm_bytes: 668_873_496, - }, - AotTargetSpec { - triple: "x86_64-pc-windows-msvc", - target_id: "windows-x64-msvc", - runner_os: "windows-2025-vs2026", - package: "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", - llvm_url: "https://github.com/wasmerio/llvm-custom-builds/releases/download/22.x/llvm-windows-amd64.tar.xz", - llvm_sha256: "19ff22b0cf74b53dad2fc717db2209f8162b768fc6dede9e2caa6a83c724496e", - llvm_bytes: 757_929_860, - }, - ] -} - -pub(crate) fn supported_aot_targets() -> Vec<&'static str> { - aot_target_specs().iter().map(|spec| spec.triple).collect() -} - -pub(crate) fn supported_aot_target_ids() -> Vec<&'static str> { - aot_target_specs() - .iter() - .map(|spec| spec.target_id) - .collect() -} - -pub(crate) fn aot_target_id_for_triple(target_triple: &str) -> Result<&'static str> { - aot_target_specs() - .iter() - .find(|spec| spec.triple == target_triple) - .map(|spec| spec.target_id) - .with_context(|| { - format!( - "unsupported AOT target triple {target_triple}; supported triples are {}", - supported_aot_targets().join(", ") - ) - }) -} - -pub(crate) fn aot_triple_for_target_selector(selector: &str) -> Result<&'static str> { - aot_target_specs() - .iter() - .find(|spec| selector == spec.triple || selector == spec.target_id) - .map(|spec| spec.triple) - .with_context(|| { - format!( - "unsupported AOT target {selector}; supported target ids are {}", - supported_aot_target_ids().join(", ") - ) - }) -} - -pub(crate) fn aot_artifact_name(target_triple: &str) -> String { - let target_id = aot_target_id_for_triple(target_triple) - .expect("AOT artifact names are only generated for supported target triples"); - format!("liboliphaunt-wasix-runtime-aot-{target_id}") -} - -fn portable_wasix_artifact_name() -> &'static str { - "liboliphaunt-wasix-runtime-portable" -} - -pub(crate) fn print_supported_aot_targets() -> Result<()> { - for spec in aot_target_specs() { - println!("{}", spec.target_id); - } - Ok(()) -} - -pub(crate) fn print_internal_asset_packages() -> Result<()> { - println!("liboliphaunt-wasix-portable"); - for spec in aot_target_specs() { - println!("{}", spec.package); - } - Ok(()) -} - -pub(crate) fn print_ci_artifact_names() -> Result<()> { - println!("{}", portable_wasix_artifact_name()); - for spec in aot_target_specs() { - println!("{}", aot_artifact_name(spec.triple)); - } - Ok(()) -} - -pub(crate) fn print_aot_ci_matrix(args: &[String]) -> Result<()> { - let requested = value_after(args, "--target") - .or_else(|| value_after(args, "--target-triple")) - .unwrap_or("all"); - let github_output = args.iter().any(|arg| arg == "--github-output"); - let targets = aot_target_specs() - .iter() - .filter(|spec| { - requested == "all" || requested == spec.triple || requested == spec.target_id - }) - .map(|spec| AotCiTarget { - os: spec.runner_os, - target: spec.triple, - target_id: spec.target_id, - package: spec.package, - artifact: aot_artifact_name(spec.triple), - llvm_url: spec.llvm_url, - llvm_sha256: spec.llvm_sha256, - llvm_bytes: spec.llvm_bytes, - }) - .collect::>(); - ensure!( - !targets.is_empty(), - "unsupported native AOT target: {requested}" - ); - let matrix = AotCiMatrix { include: targets }; - let json = serde_json::to_string(&matrix).context("serialize AOT CI matrix")?; - if github_output { - println!("matrix={json}"); - } else { - println!("{}", serde_json::to_string_pretty(&matrix)?); - } - Ok(()) -} - -pub(crate) fn ensure_supported_aot_target(target: &str) -> Result<()> { - if aot_target_specs().iter().any(|spec| spec.triple == target) { - return Ok(()); - } - bail!( - "unsupported AOT target {target}; supported targets are {}", - supported_aot_targets().join(", ") - ) -} - -pub(crate) fn verify_generated_extension_surface() -> Result<()> { - let manifest_path = Path::new(GENERATED_ASSETS_DIR).join("manifest.json"); - let manifest_text = fs::read_to_string(&manifest_path) - .with_context(|| format!("read {}", manifest_path.display()))?; - let manifest: AssetManifestOut = - serde_json::from_str(&manifest_text).context("parse committed asset manifest")?; - if skip_extensions_for_perf_probe() && manifest.extensions.is_empty() { - println!("core-only asset manifest detected; skipping generated extension surface guard"); - return Ok(()); - } - let catalog_text = fs::read_to_string("src/extensions/generated/extensions.catalog.json") - .context("read src/extensions/generated/extensions.catalog.json")?; - let catalog: serde_json::Value = - serde_json::from_str(&catalog_text).context("parse generated extension catalog")?; - let generated = fs::read_to_string( - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/generated_extensions.rs", - ) - .context( - "read src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/generated_extensions.rs", - )?; - - let mut supported_constants = BTreeMap::new(); - for entry in catalog - .get("extensions") - .and_then(|value| value.as_array()) - .ok_or_else(|| anyhow!("extension catalog is missing extensions array"))? - { - let sql_name = entry - .get("sql-name") - .and_then(|value| value.as_str()) - .ok_or_else(|| anyhow!("extension is missing sql-name"))?; - let rust_constant = entry - .get("rust-constant") - .and_then(|value| value.as_str()) - .ok_or_else(|| anyhow!("extension {sql_name} is missing rust-constant"))?; - supported_constants.insert(sql_name.to_owned(), rust_constant.to_owned()); - } - - let manifest_sql_names = manifest - .extensions - .iter() - .map(|extension| extension.sql_name.clone()) - .collect::>(); - let catalog_sql_names = supported_constants.keys().cloned().collect::>(); - if manifest_sql_names != catalog_sql_names { - bail!( - "supported extension catalog and asset manifest disagree: manifest-only={:?} catalog-only={:?}", - manifest_sql_names - .difference(&catalog_sql_names) - .collect::>(), - catalog_sql_names - .difference(&manifest_sql_names) - .collect::>() - ); - } - - for extension in &manifest.extensions { - let rust_constant = supported_constants - .get(&extension.sql_name) - .ok_or_else(|| { - anyhow!( - "extension {} missing from supported catalog", - extension.sql_name - ) - })?; - let definition_const = format!("DEFINITION_{rust_constant}"); - let cargo_feature = format!("extension-{}", extension.sql_name.replace('_', "-")); - for (needle, description) in [ - ( - format!( - "#[cfg(feature = {cargo_feature:?})]\nconst {definition_const}: Extension =" - ), - "feature-gated extension definition constant", - ), - ( - format!( - "#[cfg(feature = {cargo_feature:?})]\n pub const {rust_constant}: Self = {definition_const};" - ), - "feature-gated public extension constant", - ), - ( - format!("#[cfg(feature = {cargo_feature:?})]\n Self::{rust_constant},"), - "feature-gated Extension::ALL entry", - ), - (format!("{:?}", extension.sql_name), "extension SQL name"), - ] { - if !generated.contains(&needle) { - bail!("generated extension API is stale: missing {description} {needle}"); - } - } - } - println!("generated extension API matches asset manifest and catalog"); - Ok(()) -} - -fn verify_generated_extension_surface_if_available() -> Result<()> { - let manifest_path = Path::new(GENERATED_ASSETS_DIR).join("manifest.json"); - if !manifest_path.exists() { - eprintln!( - "warning: generated asset manifest is unavailable at {}; skipping generated extension manifest parity in source-only verification", - manifest_path.display() - ); - return Ok(()); - } - let manifest_text = fs::read_to_string(&manifest_path) - .with_context(|| format!("read {}", manifest_path.display()))?; - let manifest: AssetManifestOut = - serde_json::from_str(&manifest_text).context("parse generated asset manifest")?; - if manifest.extensions.is_empty() { - eprintln!( - "warning: generated asset manifest is core-only; skipping generated extension manifest parity in source-only verification" - ); - return Ok(()); - } - verify_generated_extension_surface() -} - -pub(crate) fn check_no_legacy_runtime_shims() -> Result<()> { - let banned = [ - ( - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/base.rs", - &[ - "normalize_runtime_tree", - "mirror_configured_share_layout", - "mirror_configured_lib_layout", - "normalize_pgdata_config", - "share/timezonesets/Default", - "write minimal timezoneset", - "log_timezone = UTC", - "timezone = UTC", - ][..], - ), - ( - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod.rs", - &[ - "\"oliphaunt_wasix_initdb\"", - "\"oliphaunt_wasix_backend\"", - "PostgresRecoverProtocolError", - ][..], - ), - ]; - - let mut failures = Vec::new(); - for (path, patterns) in banned { - let text = fs::read_to_string(path).with_context(|| format!("read {path}"))?; - for pattern in patterns { - if text.contains(pattern) { - failures.push(format!( - "{path} contains legacy runtime shim marker {pattern:?}" - )); - } - } - } - - if !failures.is_empty() { - bail!("{}", failures.join("; ")); - } - println!("legacy runtime shim source guard passed"); - Ok(()) -} - -pub(crate) fn check_production_wasix_build_inputs() -> Result<()> { - for required in [ - WASIX_BRIDGE_PATH, - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge_abi_test.c", - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim_abi_test.c", - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_shim.c", - "src/runtimes/liboliphaunt/wasix/assets/build/analyze_pgl_stubs.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker_wasix_env.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/profile_flags.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/source_lane.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/prepare_postgres_source.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/configure_wasix_dl.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/pg_config_wasix.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker/Dockerfile", - "src/runtimes/liboliphaunt/wasix/assets/build/docker/isrg-root-x1.pem", - "src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker_oliphaunt.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker_runtime_support.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_third_party.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_icu_link.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_frontend_tools.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_openssl.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_sqlite.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_geos.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libxml2.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_jsonc.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_proj.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libiconv.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh", - "src/runtimes/liboliphaunt/native/bin/icu.sh", - "src/extensions/external/postgis/tools/build_wasix.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker_pgxs_extensions.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker_contrib_extensions.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker_pgdump.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker_psql.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker_initdb.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim.c", - "src/runtimes/liboliphaunt/native/portable-uuid/include/uuid/uuid.h", - "src/runtimes/liboliphaunt/native/portable-uuid/portable_uuid.c", - POSTGRES_SOURCE_MANIFEST_PATH, - POSTGRES_PATCH_SERIES_PATH, - POSTGRES_EXPERIMENT_DISPOSITION_PATH, - ] { - ensure_file(Path::new(required))?; - } - - check_wasix_shell_script_syntax()?; - check_root_asset_metadata_keys()?; - ensure_file_not_contains_any( - "src/runtimes/liboliphaunt/wasix/assets/build/configure_wasix_dl.sh", - &["--disable-spinlocks"], - )?; - check_wasix_bridge_abi_harness()?; - check_wasix_initdb_shim_abi_harness()?; - - println!("production WASIX build input guard passed"); - Ok(()) -} - -fn check_root_asset_metadata_keys() -> Result<()> { - let path = "src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"; - let text = fs::read_to_string(path).with_context(|| format!("read {path}"))?; - for required in [ - "postgres-version", - "postgres-source-url", - "postgres-source-sha256", - "postgres-patch-count", - "runtime-archive-sha256", - "oliphaunt-wasix-sha256", - "cluster-seed-standard-archive-sha256", - "cluster-seed-icu-archive-sha256", - "initdb-wasix-sha256", - ] { - let needle = format!("{required} = \""); - ensure!( - text.contains(&needle), - "{path} is missing WASIX asset metadata key {required}" - ); - } - let tools_path = "src/runtimes/liboliphaunt/wasix/crates/tools/Cargo.toml"; - let tools_text = - fs::read_to_string(tools_path).with_context(|| format!("read {tools_path}"))?; - for required in ["pg-dump-wasix-sha256", "psql-wasix-sha256"] { - let needle = format!("{required} = \""); - ensure!( - tools_text.contains(&needle), - "{tools_path} is missing WASIX tools asset metadata key {required}" - ); - } - Ok(()) -} - -pub(crate) fn check_canonical_asset_layout(strict: bool) -> Result<()> { - check_canonical_asset_layout_in(Path::new(GENERATED_ASSETS_DIR), strict) -} - -pub(crate) fn check_canonical_asset_layout_in(asset_dir: &Path, strict: bool) -> Result<()> { - let runtime_archive = asset_dir.join("oliphaunt.wasix.tar.zst"); - if !runtime_archive.exists() { - if strict { - bail!( - "runtime asset archive is missing at {}", - runtime_archive.display() - ); - } - eprintln!( - "warning: runtime asset archive is missing at {}", - runtime_archive.display() - ); - return Ok(()); - } - - let runtime_entries = archive_entries(&runtime_archive)?; - let required_paths = [ - RUNTIME_MODULE_ARCHIVE_MEMBER, - "oliphaunt/bin/initdb", - "oliphaunt/lib/postgresql/dict_snowball.so", - "oliphaunt/lib/postgresql/plpgsql.so", - "oliphaunt/share/postgresql/snowball_create.sql", - "oliphaunt/share/postgresql/extension/plpgsql--1.0.sql", - "oliphaunt/share/postgresql/extension/plpgsql.control", - "oliphaunt/share/postgresql/timezone/UTC", - "oliphaunt/share/postgresql/timezone/America/New_York", - "oliphaunt/share/postgresql/timezonesets/Default", - ]; - for required in required_paths { - if !runtime_entries.contains(required) { - bail!( - "runtime archive {} is missing canonical path {required}", - runtime_archive.display() - ); - } - } - for language in [ - "danish", - "dutch", - "english", - "finnish", - "french", - "german", - "hungarian", - "italian", - "nepali", - "norwegian", - "portuguese", - "russian", - "spanish", - "swedish", - "turkish", - ] { - let required = format!("oliphaunt/share/postgresql/tsearch_data/{language}.stop"); - if !runtime_entries.contains(required.as_str()) { - bail!( - "runtime archive {} is missing canonical path {required}", - runtime_archive.display() - ); - } - } - if runtime_entries - .iter() - .any(|entry| entry == "oliphaunt/share/icu" || entry.starts_with("oliphaunt/share/icu/")) - { - bail!( - "runtime archive {} must not bundle ICU data under oliphaunt/share/icu; ICU is published as the separate oliphaunt-icu package", - runtime_archive.display() - ); - } - for forbidden in [ - "oliphaunt/share/extension", - "oliphaunt/share/timezonesets", - "oliphaunt/lib/plpgsql.so", - "oliphaunt/lib/dict_snowball.so", - "oliphaunt/bin/pg_dump", - "oliphaunt/bin/psql", - "oliphaunt/bin/oliphaunt", - ] { - if runtime_entries.contains(forbidden) - || runtime_entries - .iter() - .any(|entry| entry.starts_with(&format!("{forbidden}/"))) - { - bail!( - "runtime archive {} contains non-canonical duplicate path {forbidden}", - runtime_archive.display() - ); - } - } - - let extensions_dir = asset_dir.join("extensions"); - if extensions_dir.exists() { - for entry in fs::read_dir(&extensions_dir) - .with_context(|| format!("read {}", extensions_dir.display()))? - { - let path = entry?.path(); - if path.extension().and_then(|ext| ext.to_str()) != Some("zst") { - continue; - } - check_extension_archive_layout(&path)?; - } - } else if strict && !skip_extensions_for_perf_probe() { - bail!( - "extension asset directory is missing at {}", - extensions_dir.display() - ); - } - - println!("canonical asset layout guard passed"); - Ok(()) -} - -fn check_extension_archive_layout(path: &Path) -> Result<()> { - let entries = archive_entries(path)?; - for entry in entries { - if matches!( - entry.as_str(), - "lib" - | "lib/postgresql" - | "share" - | "share/proj" - | "share/postgresql" - | "share/postgresql/extension" - | "share/postgresql/tsearch_data" - ) { - continue; - } - if entry.starts_with("lib/postgresql/") - || entry.starts_with("share/proj/") - || entry.starts_with("share/postgresql/extension/") - || entry.starts_with("share/postgresql/tsearch_data/") - { - continue; - } - bail!( - "extension archive {} contains non-canonical path {entry}", - path.display() - ); - } - Ok(()) -} - -pub(crate) fn audit_upstream_fixes(_manifest: &SourcesManifest, _strict: bool) -> Result<()> { - check_postgres_source_spine()?; - check_production_wasix_build_inputs()?; - check_no_legacy_runtime_shims()?; - check_source_lane_isolation()?; - println!("audited PG18 WASIX runtime guards"); - Ok(()) -} - -pub(crate) fn ensure_file_not_contains_any(path: &str, markers: &[&str]) -> Result<()> { - let text = fs::read_to_string(path).with_context(|| format!("read {path}"))?; - let present = markers - .iter() - .copied() - .filter(|marker| text.contains(marker)) - .collect::>(); - if !present.is_empty() { - bail!( - "{path} contains production-excluded markers: {}", - present.join(", ") - ); - } - Ok(()) -} - -pub(crate) fn check_manifest_source_checkouts_filtered( - manifest: &SourcesManifest, - strict_local: bool, - include: F, -) -> Result<()> -where - F: Fn(&SourcePin) -> bool, -{ - for source in &manifest.sources { - if !include(source) { - continue; - } - let Some(path) = source_checkout_path(source.name.as_str()) else { - if strict_local { - bail!("source '{}' has no configured checkout path", source.name); - } - eprintln!( - "warning: source '{}' has no configured checkout path", - source.name - ); - continue; - }; - if source.kind == SourceKind::Archive { - check_archive_source_path(source, &path, strict_local)?; - continue; - } - if !path.join(".git").exists() { - if strict_local { - bail!("missing local checkout {}", path.display()); - } - eprintln!("warning: local checkout {} is missing", path.display()); - continue; - } - let head = command_output("git", &["rev-parse", "HEAD"], &path) - .with_context(|| format!("read HEAD for {}", path.display()))?; - if head.trim() != source.commit { - if strict_local { - bail!( - "local {} checkout is at {}, expected {} from source metadata", - path.display(), - head.trim(), - source.commit - ); - } - eprintln!( - "warning: local {} checkout is at {}, expected {}", - path.display(), - head.trim(), - source.commit - ); - } - if head.trim() == source.commit - && let Some(expected_epoch) = source.source_date_epoch - { - let actual_epoch = - command_output("git", &["show", "-s", "--format=%ct", "HEAD"], &path) - .with_context(|| { - format!("read pinned source timestamp for {}", path.display()) - })?; - if actual_epoch.trim() != expected_epoch.to_string() { - if strict_local { - bail!( - "local {} checkout commit timestamp is {}, expected source_date_epoch {}", - path.display(), - actual_epoch.trim(), - expected_epoch - ); - } - eprintln!( - "warning: local {} checkout commit timestamp is {}, expected source_date_epoch {}", - path.display(), - actual_epoch.trim(), - expected_epoch - ); - } - } - let branch = command_output("git", &["branch", "--show-current"], &path) - .unwrap_or_else(|_| String::from("")); - if strict_local && branch.trim() != source.branch { - bail!( - "local {} checkout is on branch '{}', expected '{}'", - path.display(), - branch.trim(), - source.branch - ); - } - let status = source_checkout_status_for_source(source.name.as_str(), &path) - .with_context(|| format!("read status for {}", path.display()))?; - if !status.trim().is_empty() { - if strict_local { - bail!( - "local {} checkout ({}) has uncommitted changes; preserve them before strict asset builds", - path.display(), - source.name - ); - } - eprintln!( - "warning: local {} checkout ({}) has uncommitted changes", - path.display(), - source.name - ); - } - } - Ok(()) -} - -fn check_archive_source_path(source: &SourcePin, path: &Path, strict_local: bool) -> Result<()> { - let stamp_path = path.join(".oliphaunt-source-pin"); - if !path.is_dir() || !stamp_path.is_file() { - if strict_local { - bail!("missing local archive source {}", path.display()); - } - eprintln!( - "warning: local archive source {} is missing", - path.display() - ); - return Ok(()); - } - let actual = fs::read_to_string(&stamp_path) - .with_context(|| format!("read {}", stamp_path.display()))?; - let tree_sha256 = match archive_source_tree_digest(path) { - Ok(digest) => digest, - Err(error) if strict_local => { - return Err(error).with_context(|| { - format!( - "verify local archive source {} ({})", - path.display(), - source.name - ) - }); - } - Err(error) => { - eprintln!( - "warning: local archive source {} ({}) has unverifiable contents: {error}", - path.display(), - source.name - ); - return Ok(()); - } - }; - let expected = source.archive_stamp(&tree_sha256); - if actual != expected { - if strict_local { - bail!( - "local archive source {} ({}) does not match source metadata", - path.display(), - source.name - ); - } - eprintln!( - "warning: local archive source {} ({}) does not match source metadata", - path.display(), - source.name - ); - } - Ok(()) -} - -fn archive_source_tree_digest(path: &Path) -> Result { - const MAX_ENTRIES: usize = 500_000; - const MAX_BYTES: u64 = 8 * 1024 * 1024 * 1024; - - let mut entries: Vec<(Vec, &'static str, String)> = Vec::new(); - let mut total_bytes = 0_u64; - for entry in WalkDir::new(path).follow_links(false).into_iter() { - let entry = entry.with_context(|| format!("walk archive source {}", path.display()))?; - if entry.path() == path { - continue; - } - let relative = entry - .path() - .strip_prefix(path) - .with_context(|| format!("derive path below {}", path.display()))?; - if relative == Path::new(".oliphaunt-source-pin") { - continue; - } - let relative = relative - .components() - .map(|component| { - component.as_os_str().to_str().ok_or_else(|| { - anyhow!( - "archive source path is not UTF-8: {}", - entry.path().display() - ) - }) - }) - .collect::>>()? - .join("/"); - let metadata = fs::symlink_metadata(entry.path()) - .with_context(|| format!("inspect {}", entry.path().display()))?; - let (kind, detail) = if metadata.is_dir() { - ("directory", String::new()) - } else if metadata.is_file() { - total_bytes = total_bytes - .checked_add(metadata.len()) - .ok_or_else(|| anyhow!("archive source byte count overflow"))?; - ensure!( - total_bytes <= MAX_BYTES, - "archive source {} exceeds {MAX_BYTES} bytes", - path.display() - ); - ( - "file", - format!("{}:{}", metadata.len(), sha256_file(entry.path())?), - ) - } else if metadata.file_type().is_symlink() { - let target = fs::read_link(entry.path()) - .with_context(|| format!("read symlink {}", entry.path().display()))?; - let target = target.to_str().ok_or_else(|| { - anyhow!("symlink target is not UTF-8: {}", entry.path().display()) - })?; - ("symlink", target.to_owned()) - } else { - bail!( - "archive source contains unsupported filesystem object {}", - entry.path().display() - ); - }; - entries.push((relative.as_bytes().to_vec(), kind, detail)); - ensure!( - entries.len() <= MAX_ENTRIES, - "archive source {} exceeds {MAX_ENTRIES} entries", - path.display() - ); - } - - entries.sort_by(|left, right| left.0.cmp(&right.0)); - let mut hasher = Sha256::new(); - for (relative, kind, detail) in entries { - for field in [kind.as_bytes(), relative.as_slice(), detail.as_bytes()] { - hasher.update(field); - hasher.update([0]); - } - } - Ok(format!("{:x}", hasher.finalize())) -} - -fn source_checkout_status(path: &Path) -> Result { - command_output("git", &["status", "--porcelain"], path) -} - -pub(crate) fn source_checkout_status_for_source(name: &str, path: &Path) -> Result { - if name == "postgres18-extension-sources" { - return command_output( - "git", - &["status", "--porcelain", "--ignore-submodules=all"], - path, - ); - } - source_checkout_status(path) -} - -#[cfg(unix)] -fn check_wasix_bridge_abi_harness() -> Result<()> { - let bridge = Path::new(WASIX_BRIDGE_PATH); - let harness = Path::new( - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge_abi_test.c", - ); - if !harness.exists() { - bail!("missing WASIX bridge ABI harness at {}", harness.display()); - } - - let out_dir = Path::new("target/xtask"); - fs::create_dir_all(out_dir).with_context(|| format!("create {}", out_dir.display()))?; - let binary = out_dir.join("oliphaunt_wasix_bridge_abi_test"); - let cc = env::var("CC").unwrap_or_else(|_| "cc".to_owned()); - let status = Command::new(&cc) - .args(["-std=c11", "-Wall", "-Wextra"]) - .arg(bridge) - .arg(harness) - .arg("-o") - .arg(&binary) - .status() - .with_context(|| format!("compile WASIX bridge ABI harness with {cc}"))?; - if !status.success() { - bail!("WASIX bridge ABI harness compilation failed with {status}"); - } - let status = Command::new(&binary) - .stdout(Stdio::null()) - .status() - .with_context(|| format!("run {}", binary.display()))?; - if !status.success() { - bail!("WASIX bridge ABI harness failed with {status}"); - } - println!("WASIX bridge ABI harness passed"); - Ok(()) -} - -#[cfg(unix)] -fn check_wasix_initdb_shim_abi_harness() -> Result<()> { - let shim = Path::new( - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim.c", - ); - let harness = Path::new( - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_initdb_shim_abi_test.c", - ); - if !harness.exists() { - bail!( - "missing WASIX initdb shim ABI harness at {}", - harness.display() - ); - } - - let out_dir = Path::new("target/xtask"); - fs::create_dir_all(out_dir).with_context(|| format!("create {}", out_dir.display()))?; - let binary = out_dir.join("oliphaunt_wasix_initdb_shim_abi_test"); - let cc = env::var("CC").unwrap_or_else(|_| "cc".to_owned()); - let status = Command::new(&cc) - .args(["-std=c11", "-Wall", "-Wextra"]) - .arg(shim) - .arg(harness) - .arg("-o") - .arg(&binary) - .status() - .with_context(|| format!("compile {}", harness.display()))?; - if !status.success() { - bail!("failed to compile {}", harness.display()); - } - - let status = Command::new(&binary) - .status() - .with_context(|| format!("run {}", binary.display()))?; - if !status.success() { - bail!("WASIX initdb shim ABI harness failed"); - } - Ok(()) -} - -#[cfg(not(unix))] -fn check_wasix_initdb_shim_abi_harness() -> Result<()> { - println!("skipping WASIX initdb shim ABI harness on non-Unix host"); - Ok(()) -} - -#[cfg(not(unix))] -fn check_wasix_bridge_abi_harness() -> Result<()> { - eprintln!("warning: skipping POSIX WASIX bridge ABI harness on non-Unix host"); - Ok(()) -} diff --git a/tools/xtask/src/asset_io.rs b/tools/xtask/src/asset_io.rs deleted file mode 100644 index 5ae63afcd..000000000 --- a/tools/xtask/src/asset_io.rs +++ /dev/null @@ -1,1149 +0,0 @@ -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::Command; -use std::thread; -use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; - -use anyhow::{Context, Result, bail, ensure}; - -use super::*; - -const GITHUB_READ_HELPER: &str = "tools/release/github-read.mjs"; -const DOWNLOAD_MAX_ATTEMPTS: usize = 4; -const DOWNLOAD_ATTEMPT_TIMEOUT: Duration = Duration::from_secs(10 * 60); -const DOWNLOAD_DEADLINE: Duration = Duration::from_secs(30 * 60); - -#[derive(Debug)] -enum DownloadAttemptError { - Permanent(anyhow::Error), - Retryable(anyhow::Error), -} - -impl DownloadAttemptError { - fn retryable(error: impl Into) -> Self { - Self::Retryable(error.into()) - } - - fn permanent(error: impl Into) -> Self { - Self::Permanent(error.into()) - } -} - -struct TemporaryDirectory { - path: PathBuf, - remove: bool, -} - -impl TemporaryDirectory { - fn new(path: PathBuf) -> Self { - Self { path, remove: true } - } - - fn path(&self) -> &Path { - &self.path - } - - fn disarm(&mut self) { - self.remove = false; - } -} - -impl Drop for TemporaryDirectory { - fn drop(&mut self) { - if self.remove { - let _ = fs::remove_dir_all(&self.path); - } - } -} - -#[derive(Clone, Copy)] -struct DownloadRetryPolicy { - base_delay: Duration, - deadline: Duration, - max_attempts: usize, -} - -impl Default for DownloadRetryPolicy { - fn default() -> Self { - Self { - base_delay: Duration::from_secs(1), - deadline: DOWNLOAD_DEADLINE, - max_attempts: DOWNLOAD_MAX_ATTEMPTS, - } - } -} - -pub(super) fn download_assets(args: &[String]) -> Result<()> { - let targets = asset_download_targets(args)?; - let required_job = value_after(args, "--required-job"); - if args.iter().any(|arg| arg == "--release") { - let tag = value_after(args, "--release").context("--release requires a tag")?; - ensure!( - value_after(args, "--run-id").is_none() - && value_after(args, "--sha").is_none() - && required_job.is_none(), - "assets download accepts only one of --run-id, --sha, or --release; --required-job applies only to workflow-run downloads" - ); - download_assets_from_release(tag, &targets)?; - let target_list = targets.join(", "); - println!("downloaded and installed release assets from {tag} / {target_list}"); - return Ok(()); - } - - let candidates = asset_download_run_candidates(args, required_job)?; - let mut last_error = None; - - let candidate_count = candidates.len(); - for (index, run_id) in candidates.into_iter().enumerate() { - match download_assets_from_run(&run_id, &targets) { - Ok(()) => { - let target_list = targets.join(", "); - println!( - "downloaded and installed CI workflow runtime artifacts from run {run_id} / {target_list}" - ); - return Ok(()); - } - Err(error) => { - if index + 1 < candidate_count { - eprintln!( - "CI workflow run {run_id} does not contain compatible runtime artifacts: {error:#}" - ); - last_error = Some(error); - continue; - } - return Err(error); - } - } - } - - if let Some(error) = last_error { - Err(error).context("no compatible CI workflow runtime artifact found") - } else { - bail!("no CI workflow runtime artifact found") - } -} - -fn asset_download_targets(args: &[String]) -> Result> { - let all_targets = args.iter().any(|arg| arg == "--all-targets"); - let explicit_target = - value_after(args, "--target").or_else(|| value_after(args, "--target-triple")); - if all_targets && explicit_target.is_some() { - bail!("assets download accepts either --all-targets or --target/--target-triple, not both"); - } - if all_targets { - Ok(supported_aot_targets() - .iter() - .map(|target| (*target).to_owned()) - .collect()) - } else { - let target = explicit_target - .map(aot_triple_for_target_selector) - .transpose()? - .unwrap_or(host_target_triple()); - ensure_supported_aot_target(target)?; - Ok(vec![target.to_owned()]) - } -} - -fn asset_download_run_candidates( - args: &[String], - required_job: Option<&str>, -) -> Result> { - let run_id = value_after(args, "--run-id"); - let sha = value_after(args, "--sha"); - match (run_id, sha) { - (Some(run_id), None) => filter_runs_by_required_job(vec![run_id.to_owned()], required_job), - (None, Some(sha)) => { - ensure!( - sha.len() == 40 && sha.bytes().all(|byte| byte.is_ascii_hexdigit()), - "assets download --sha requires a full 40-character commit SHA" - ); - let output = github_read_output( - &[ - "run", - "list", - "--workflow", - "CI", - "--commit", - sha, - "--limit", - "20", - "--json", - "databaseId,status,headSha", - ], - &format!("find CI workflow run for SHA {sha}"), - ) - .with_context(|| format!("find CI workflow run for SHA {sha}"))?; - filter_runs_by_required_job(parse_exact_sha_run_ids(&output, sha)?, required_job) - } - _ => bail!("assets download requires exactly one of --run-id or --sha "), - } -} - -fn parse_exact_sha_run_ids(output: &str, sha: &str) -> Result> { - let value: serde_json::Value = - serde_json::from_str(output).context("parse exact-SHA CI workflow run search")?; - let rows = value - .as_array() - .context("exact-SHA CI workflow run search must return a list")?; - let mut runs = Vec::new(); - for row in rows { - let head_sha = row - .get("headSha") - .and_then(serde_json::Value::as_str) - .context("exact-SHA CI workflow run is missing headSha")?; - ensure!( - head_sha.eq_ignore_ascii_case(sha), - "GitHub returned CI workflow run for {head_sha}, not requested SHA {sha}" - ); - let run_id = row - .get("databaseId") - .and_then(serde_json::Value::as_u64) - .filter(|run_id| *run_id > 0) - .context("exact-SHA CI workflow run has invalid databaseId")?; - runs.push(run_id.to_string()); - } - ensure!(!runs.is_empty(), "no CI workflow artifact found"); - Ok(runs) -} - -fn filter_runs_by_required_job( - run_ids: Vec, - required_job: Option<&str>, -) -> Result> { - let Some(required_job) = required_job else { - return Ok(run_ids); - }; - - let mut matched = Vec::new(); - for run_id in run_ids { - if run_has_required_job_success(&run_id, required_job)? { - matched.push(run_id); - } - } - ensure!( - !matched.is_empty(), - "no CI workflow artifact run has required job '{required_job}' with conclusion 'success'" - ); - Ok(matched) -} - -fn run_has_required_job_success(run_id: &str, required_job: &str) -> Result { - let output = github_read_output( - &["run", "view", run_id, "--json", "jobs"], - &format!("inspect CI workflow run {run_id}"), - ) - .with_context(|| format!("inspect CI workflow run {run_id}"))?; - let value: serde_json::Value = serde_json::from_str(&output) - .with_context(|| format!("parse CI workflow run {run_id} job JSON"))?; - let conclusion = value - .get("jobs") - .and_then(serde_json::Value::as_array) - .and_then(|jobs| { - jobs.iter().find(|job| { - job.get("name").and_then(serde_json::Value::as_str) == Some(required_job) - }) - }) - .and_then(|job| job.get("conclusion")) - .and_then(serde_json::Value::as_str); - Ok(conclusion == Some("success")) -} - -fn github_read_output(args: &[&str], label: &str) -> Result { - let output = Command::new("node") - .arg(GITHUB_READ_HELPER) - .arg("--label") - .arg(label) - .arg("--") - .args(args) - .output() - .with_context(|| format!("start bounded GitHub read for {label}"))?; - if !output.status.success() { - let detail = String::from_utf8_lossy(&output.stderr).trim().to_owned(); - bail!( - "bounded GitHub read for {label} failed{}", - if detail.is_empty() { - String::new() - } else { - format!(": {detail}") - } - ); - } - String::from_utf8(output.stdout).context("GitHub read output was not valid UTF-8") -} - -fn github_read_once( - args: &[&str], - label: &str, - timeout: Duration, -) -> std::result::Result<(), DownloadAttemptError> { - let timeout_ms = timeout.as_millis().clamp(1, u128::from(u64::MAX)); - let status = Command::new("node") - .arg(GITHUB_READ_HELPER) - .arg("--label") - .arg(label) - .arg("--") - .args(args) - .env("OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS", "1") - .env( - "OLIPHAUNT_GITHUB_READ_ATTEMPT_TIMEOUT_MS", - timeout_ms.to_string(), - ) - .env("OLIPHAUNT_GITHUB_READ_DEADLINE_MS", timeout_ms.to_string()) - .env("OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS", "0") - .env("OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS", "0") - .stdout(Stdio::null()) - .status() - .map_err(|error| { - DownloadAttemptError::retryable(anyhow!( - "start bounded GitHub read for {label}: {error}" - )) - })?; - match status.code() { - Some(0) => Ok(()), - Some(64) => Err(DownloadAttemptError::permanent(anyhow!( - "GitHub permanently rejected {label}" - ))), - Some(75) => Err(DownloadAttemptError::retryable(anyhow!( - "GitHub read budget was exhausted for {label}" - ))), - Some(code) => Err(DownloadAttemptError::permanent(anyhow!( - "GitHub read helper failed for {label} with unexpected exit code {code}" - ))), - None => Err(DownloadAttemptError::retryable(anyhow!( - "GitHub read helper was interrupted for {label}" - ))), - } -} - -fn unique_sibling_directory(destination: &Path, label: &str) -> Result { - let parent = destination.parent().unwrap_or_else(|| Path::new(".")); - fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?; - let basename = destination - .file_name() - .and_then(|name| name.to_str()) - .unwrap_or("download"); - let timestamp = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_nanos(); - for sequence in 0..100_u32 { - let candidate = parent.join(format!( - ".{basename}.{label}-{}-{timestamp}-{sequence}", - std::process::id() - )); - match fs::create_dir(&candidate) { - Ok(()) => return Ok(candidate), - Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => continue, - Err(error) => { - return Err(error).with_context(|| format!("create {}", candidate.display())); - } - } - } - bail!( - "could not allocate a unique sibling directory for {}", - destination.display() - ) -} - -fn promote_staged_directory(stage: &Path, destination: &Path) -> Result<()> { - ensure!( - stage.parent() == destination.parent(), - "atomic stage {} must be a sibling of {}", - stage.display(), - destination.display() - ); - let backup = unique_sibling_directory(destination, "previous")?; - fs::remove_dir(&backup).with_context(|| format!("prepare backup {}", backup.display()))?; - let had_destination = destination.exists(); - if had_destination { - fs::rename(destination, &backup).with_context(|| { - format!( - "move existing directory {} -> {}", - destination.display(), - backup.display() - ) - })?; - } - if let Err(error) = fs::rename(stage, destination) { - if had_destination { - let _ = fs::rename(&backup, destination); - } - return Err(error).with_context(|| { - format!( - "promote staged directory {} -> {}", - stage.display(), - destination.display() - ) - }); - } - if had_destination { - fs::remove_dir_all(&backup).with_context(|| format!("remove {}", backup.display()))?; - } - Ok(()) -} - -fn retry_delay(base: Duration, attempt: usize) -> Duration { - if base.is_zero() { - return Duration::ZERO; - } - let multiplier = 1_u32 << attempt.saturating_sub(1).min(3); - let exponential = base.saturating_mul(multiplier); - let entropy = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .subsec_nanos(); - let jitter_percent = 80 + (entropy % 41); - exponential.saturating_mul(jitter_percent) / 100 -} - -fn retry_staged_download( - destination: &Path, - label: &str, - policy: DownloadRetryPolicy, - mut attempt_download: F, -) -> Result<()> -where - F: FnMut(&Path, Instant) -> std::result::Result<(), DownloadAttemptError>, -{ - ensure!( - policy.max_attempts > 0, - "download retry policy must permit an attempt" - ); - let deadline = Instant::now() + policy.deadline; - let mut last_error = None; - for attempt in 1..=policy.max_attempts { - if Instant::now() >= deadline { - break; - } - let mut stage = TemporaryDirectory::new(unique_sibling_directory(destination, "attempt")?); - match attempt_download(stage.path(), deadline) { - Ok(()) => { - promote_staged_directory(stage.path(), destination) - .with_context(|| format!("atomically promote {label}"))?; - stage.disarm(); - return Ok(()); - } - Err(DownloadAttemptError::Permanent(error)) => { - return Err(error).with_context(|| format!("permanent failure while {label}")); - } - Err(DownloadAttemptError::Retryable(error)) => { - eprintln!("{label} attempt {attempt} failed transiently: {error:#}"); - last_error = Some(error); - } - } - if attempt == policy.max_attempts { - break; - } - let delay = retry_delay(policy.base_delay, attempt); - let remaining = deadline.saturating_duration_since(Instant::now()); - if remaining <= delay { - break; - } - thread::sleep(delay); - } - let context = format!( - "{label} exhausted {} attempts or its {}s overall deadline", - policy.max_attempts, - policy.deadline.as_secs() - ); - match last_error { - Some(error) => Err(error).context(context), - None => bail!(context), - } -} - -fn remaining_attempt_timeout(deadline: Instant, maximum: Duration) -> Result { - let remaining = deadline.saturating_duration_since(Instant::now()); - ensure!(!remaining.is_zero(), "download overall deadline exhausted"); - Ok(remaining.min(maximum)) -} - -fn download_assets_from_run(run_id: &str, targets: &[String]) -> Result<()> { - let download_dir = Path::new("target/oliphaunt-wasix/downloads").join(run_id); - retry_staged_download( - &download_dir, - &format!("download CI workflow runtime artifacts from run {run_id}"), - DownloadRetryPolicy::default(), - |stage, deadline| { - let timeout = remaining_attempt_timeout(deadline, DOWNLOAD_ATTEMPT_TIMEOUT) - .map_err(DownloadAttemptError::retryable)?; - github_read_once( - &[ - "run", - "download", - run_id, - "--name", - "liboliphaunt-wasix-runtime-portable", - "--dir", - stage.to_str().expect("download stage is utf-8"), - ], - &format!("download portable runtime artifact from run {run_id}"), - timeout, - )?; - for target in targets { - let target_download_dir = stage.join(generated_aot_dir(target)); - fs::create_dir_all(&target_download_dir).map_err(|error| { - DownloadAttemptError::retryable(anyhow!( - "create {}: {error}", - target_download_dir.display() - )) - })?; - let artifact = aot_artifact_name(target); - let timeout = remaining_attempt_timeout(deadline, DOWNLOAD_ATTEMPT_TIMEOUT) - .map_err(DownloadAttemptError::retryable)?; - github_read_once( - &[ - "run", - "download", - run_id, - "--name", - &artifact, - "--dir", - target_download_dir - .to_str() - .expect("target download stage is utf-8"), - ], - &format!("download {artifact} from run {run_id}"), - timeout, - )?; - normalize_downloaded_aot_artifact(target, &target_download_dir) - .map_err(DownloadAttemptError::retryable)?; - } - validate_downloaded_artifacts(stage, targets).map_err(DownloadAttemptError::retryable) - }, - )?; - install_downloaded_artifacts(&download_dir, targets)?; - for target in targets { - install_local_assets_for_target(target)?; - } - Ok(()) -} - -fn normalize_downloaded_aot_artifact(target: &str, artifact_dir: &Path) -> Result<()> { - let marker = artifact_dir.join("target-triple.txt"); - let files = artifact_dir.join("files"); - if !marker.exists() && !files.exists() { - return Ok(()); - } - - ensure_file(&marker)?; - ensure!( - files.is_dir(), - "downloaded AOT artifact envelope is missing files directory: {}", - files.display() - ); - let actual = fs::read_to_string(&marker) - .with_context(|| format!("read {}", marker.display()))? - .trim() - .to_owned(); - ensure_eq( - &actual, - target, - "downloaded AOT artifact target-triple marker", - )?; - - let normalized = artifact_dir.with_extension("normalized"); - if normalized.exists() { - fs::remove_dir_all(&normalized) - .with_context(|| format!("remove {}", normalized.display()))?; - } - copy_dir_all(&files, &normalized)?; - fs::remove_dir_all(artifact_dir) - .with_context(|| format!("remove {}", artifact_dir.display()))?; - fs::rename(&normalized, artifact_dir).with_context(|| { - format!( - "rename normalized AOT artifact {} -> {}", - normalized.display(), - artifact_dir.display() - ) - })?; - Ok(()) -} - -fn download_assets_from_release(tag: &str, targets: &[String]) -> Result<()> { - ensure!( - !tag.is_empty() - && tag - .chars() - .all(|character| character.is_ascii_alphanumeric() || "-._".contains(character)), - "release tag contains unsupported URL characters" - ); - let download_dir = Path::new("target/oliphaunt-wasix/downloads").join(format!("release-{tag}")); - let version = wasm_release_version_from_tag(tag); - let checksum_asset = format!("liboliphaunt-wasix-{version}-release-assets.sha256"); - let mut assets = vec![format!( - "liboliphaunt-wasix-{version}-runtime-portable.tar.zst" - )]; - for target in targets { - assets.push(format!( - "liboliphaunt-wasix-{version}-runtime-aot-{}.tar.zst", - aot_target_id_for_triple(target)? - )); - } - - retry_staged_download( - &download_dir, - &format!("download release runtime artifacts from {tag}"), - DownloadRetryPolicy::default(), - |stage, deadline| { - let timeout = remaining_attempt_timeout(deadline, DOWNLOAD_ATTEMPT_TIMEOUT) - .map_err(DownloadAttemptError::retryable)?; - let checksum_path = stage.join(&checksum_asset); - curl_release_asset_once(tag, &checksum_asset, &checksum_path, timeout)?; - let checksum_manifest = fs::read_to_string(&checksum_path).map_err(|error| { - DownloadAttemptError::retryable(anyhow!( - "read release checksum manifest {}: {error}", - checksum_path.display() - )) - })?; - for asset in &assets { - let expected = release_asset_checksum(&checksum_manifest, asset) - .map_err(DownloadAttemptError::permanent)?; - let archive = stage.join(asset); - let timeout = remaining_attempt_timeout(deadline, DOWNLOAD_ATTEMPT_TIMEOUT) - .map_err(DownloadAttemptError::retryable)?; - curl_release_asset_once(tag, asset, &archive, timeout)?; - let actual = sha256_file(&archive).map_err(DownloadAttemptError::retryable)?; - if actual != expected { - return Err(DownloadAttemptError::retryable(anyhow!( - "release asset {asset} checksum mismatch: expected {expected}, got {actual}" - ))); - } - extract_tar_zst(&archive, stage).map_err(DownloadAttemptError::retryable)?; - } - validate_downloaded_artifacts(stage, targets).map_err(DownloadAttemptError::retryable) - }, - )?; - install_downloaded_artifacts(&download_dir, targets)?; - for target in targets { - install_local_assets_for_target(target)?; - } - Ok(()) -} - -fn curl_release_asset_once( - tag: &str, - asset: &str, - destination: &Path, - timeout: Duration, -) -> std::result::Result<(), DownloadAttemptError> { - let url = format!("https://github.com/f0rr0/oliphaunt/releases/download/{tag}/{asset}"); - let timeout_seconds = timeout.as_secs().clamp(1, 10 * 60).to_string(); - let args = curl_release_asset_args(&url, destination, &timeout_seconds, cfg!(windows)); - let output = Command::new("curl").args(args).output().map_err(|error| { - DownloadAttemptError::retryable(anyhow!( - "start HTTPS download for release asset {asset}: {error}" - )) - })?; - if output.status.success() { - return Ok(()); - } - let http_status = String::from_utf8_lossy(&output.stdout).trim().to_owned(); - let detail = String::from_utf8_lossy(&output.stderr).trim().to_owned(); - let error = anyhow!( - "HTTPS download for release asset {asset} failed (HTTP {}{})", - if http_status.is_empty() { - "unknown" - } else { - &http_status - }, - if detail.is_empty() { - String::new() - } else { - format!(": {detail}") - } - ); - let permanent = matches!( - http_status.parse::(), - Ok(400 | 401 | 404 | 405 | 410 | 422) - ); - if permanent { - Err(DownloadAttemptError::permanent(error)) - } else { - Err(DownloadAttemptError::retryable(error)) - } -} - -fn curl_release_asset_args( - url: &str, - destination: &Path, - timeout_seconds: &str, - windows: bool, -) -> Vec { - let mut args = [ - "--fail-with-body", - "--location", - "--silent", - "--show-error", - "--proto", - "=https", - "--proto-redir", - "=https", - "--tlsv1.2", - "--connect-timeout", - "20", - "--max-time", - timeout_seconds, - "--speed-limit", - "1024", - "--speed-time", - "60", - ] - .map(str::to_owned) - .to_vec(); - if windows { - // Windows curl uses Schannel. A temporarily unreachable revocation - // distribution point must not make a verified release artifact - // unavailable; this still rejects certificates known to be revoked. - args.push("--ssl-revoke-best-effort".to_owned()); - } - args.extend([ - "--output".to_owned(), - destination - .to_str() - .expect("release download path is utf-8") - .to_owned(), - "--write-out".to_owned(), - "%{http_code}".to_owned(), - url.to_owned(), - ]); - args -} - -fn release_asset_checksum(manifest: &str, asset: &str) -> Result { - let mut matches = Vec::new(); - for line in manifest - .lines() - .map(str::trim) - .filter(|line| !line.is_empty()) - { - let mut fields = line.split_whitespace(); - let digest = fields.next().unwrap_or_default(); - let filename = fields.next().unwrap_or_default().trim_start_matches('*'); - ensure!( - fields.next().is_none() - && digest.len() == 64 - && digest.bytes().all(|byte| byte.is_ascii_hexdigit()) - && !filename.is_empty(), - "release checksum manifest contains malformed line {line:?}" - ); - if filename.trim_start_matches("./") == asset { - matches.push(digest.to_ascii_lowercase()); - } - } - ensure!( - matches.len() == 1, - "release checksum manifest must contain exactly one entry for {asset}, found {}", - matches.len() - ); - Ok(matches.remove(0)) -} - -fn wasm_release_version_from_tag(tag: &str) -> String { - tag.rsplit_once("-v") - .map(|(_, version)| version) - .filter(|version| !version.is_empty()) - .unwrap_or(tag) - .to_owned() -} - -fn extract_tar_zst(archive: &Path, destination: &Path) -> Result<()> { - let file = fs::File::open(archive).with_context(|| format!("open {}", archive.display()))?; - let decoder = zstd::stream::read::Decoder::new(file) - .with_context(|| format!("create zstd decoder for {}", archive.display()))?; - let mut tar = tar::Archive::new(decoder); - tar.unpack(destination).with_context(|| { - format!( - "unpack {} into {}", - archive.display(), - destination.display() - ) - }) -} - -fn validate_downloaded_artifacts(download_dir: &Path, targets: &[String]) -> Result<()> { - for entry in WalkDir::new(download_dir).follow_links(false) { - let entry = entry.with_context(|| format!("walk {}", download_dir.display()))?; - let file_type = entry.file_type(); - ensure!( - file_type.is_dir() || file_type.is_file(), - "downloaded artifact envelope contains a symbolic link or special file: {}", - entry.path().display() - ); - } - let downloaded_assets = download_dir.join(GENERATED_ASSETS_DIR); - ensure_file(&downloaded_assets.join("manifest.json"))?; - let downloaded_manifest = read_asset_manifest_from(&downloaded_assets)?; - ensure_packaged_asset_matches_source_lane(&downloaded_manifest, DEFAULT_SOURCE_LANE)?; - - for target in targets { - let downloaded_aot = download_dir.join("target/oliphaunt-wasix/aot").join(target); - ensure_file(&downloaded_aot.join("manifest.json"))?; - ensure_aot_manifest_matches_source_lane( - &downloaded_aot.join("manifest.json"), - target, - DEFAULT_SOURCE_LANE, - )?; - } - Ok(()) -} - -struct PreparedPromotion { - backup: Option, - destination: PathBuf, - promoted: bool, - stage: TemporaryDirectory, -} - -fn promote_directories_transactionally(entries: &[(PathBuf, PathBuf)]) -> Result<()> { - let mut prepared = Vec::new(); - for (source, destination) in entries { - let stage_path = unique_sibling_directory(destination, "install")?; - let stage = TemporaryDirectory::new(stage_path); - copy_dir_all(source, stage.path()).with_context(|| { - format!( - "stage validated directory {} for {}", - source.display(), - destination.display() - ) - })?; - let backup = if destination.exists() { - let backup = unique_sibling_directory(destination, "previous")?; - fs::remove_dir(&backup).with_context(|| format!("prepare {}", backup.display()))?; - Some(backup) - } else { - None - }; - prepared.push(PreparedPromotion { - backup, - destination: destination.clone(), - promoted: false, - stage, - }); - } - - for index in 0..prepared.len() { - let destination = prepared[index].destination.clone(); - if let Some(backup) = prepared[index].backup.clone() - && let Err(error) = fs::rename(&destination, &backup) - { - rollback_promotions(&mut prepared, index); - return Err(error).with_context(|| { - format!( - "move existing install {} -> {}", - destination.display(), - backup.display() - ) - }); - } - if let Err(error) = fs::rename(prepared[index].stage.path(), &destination) { - if let Some(backup) = prepared[index].backup.take() { - let _ = fs::rename(backup, &destination); - } - rollback_promotions(&mut prepared, index); - return Err(error).with_context(|| { - format!( - "promote validated install {} -> {}", - prepared[index].stage.path().display(), - destination.display() - ) - }); - } - prepared[index].stage.disarm(); - prepared[index].promoted = true; - } - for item in &mut prepared { - if let Some(backup) = item.backup.take() { - fs::remove_dir_all(&backup) - .with_context(|| format!("remove prior install {}", backup.display()))?; - } - } - Ok(()) -} - -fn rollback_promotions(prepared: &mut [PreparedPromotion], before: usize) { - for item in prepared[..before].iter_mut().rev() { - if !item.promoted { - continue; - } - let _ = fs::remove_dir_all(&item.destination); - if let Some(backup) = item.backup.take() { - let _ = fs::rename(backup, &item.destination); - } - item.promoted = false; - } -} - -fn install_downloaded_artifacts(download_dir: &Path, targets: &[String]) -> Result<()> { - validate_downloaded_artifacts(download_dir, targets)?; - let mut entries = vec![( - download_dir.join(GENERATED_ASSETS_DIR), - PathBuf::from(GENERATED_ASSETS_DIR), - )]; - for target in targets { - entries.push(( - download_dir.join("target/oliphaunt-wasix/aot").join(target), - generated_aot_dir(target), - )); - } - promote_directories_transactionally(&entries) -} - -pub(super) fn ensure_aot_manifest_matches_source_lane( - manifest_path: &Path, - target: &str, - source_lane: &str, -) -> Result<()> { - let expected = canonical_source_lane(source_lane)?; - let text = fs::read_to_string(manifest_path) - .with_context(|| format!("read {}", manifest_path.display()))?; - let manifest: AotManifest = serde_json::from_str(&text) - .with_context(|| format!("parse {}", manifest_path.display()))?; - ensure!( - manifest.format_version == AOT_MANIFEST_FORMAT_VERSION, - "AOT manifest format-version must be {AOT_MANIFEST_FORMAT_VERSION}, got {}", - manifest.format_version - ); - let actual = manifest.source_lane.as_deref().unwrap_or(""); - ensure_eq(actual, expected, "AOT manifest source-lane")?; - ensure_eq( - &manifest.target_triple, - target, - "AOT manifest target-triple", - )?; - let sources = load_wasix_toolchain_manifest()?; - ensure_eq( - &manifest.wasmer_version, - &sources.toolchain.wasmer, - "AOT manifest wasmer-version", - )?; - ensure_eq( - &manifest.wasmer_wasix_version, - &sources.toolchain.wasmer_wasix, - "AOT manifest wasmer-wasix-version", - )?; - ensure!( - !manifest.artifacts.is_empty(), - "AOT manifest {} contains no artifacts", - manifest_path.display() - ); - match expected { - "stable" => { - ensure_postgres_source_fingerprint_matches_current( - manifest.source_fingerprint.as_deref(), - "PG18 AOT manifest source-fingerprint", - )?; - if let Some(postgres_version) = manifest.postgres_version.as_deref() { - ensure!( - postgres_version.starts_with("18."), - "AOT manifest is PostgreSQL {postgres_version}, not the PG18 WASIX runtime" - ); - } - } - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } - Ok(()) -} - -pub(super) fn install_local_assets(args: &[String]) -> Result<()> { - let target = value_after(args, "--target-triple").unwrap_or(host_target_triple()); - install_local_assets_for_target(target) -} - -fn install_local_assets_for_target(target: &str) -> Result<()> { - ensure_supported_aot_target(target)?; - let generated_assets = Path::new(GENERATED_ASSETS_DIR); - ensure_file(&generated_assets.join("manifest.json"))?; - let generated_manifest = read_asset_manifest_from(generated_assets)?; - ensure_packaged_asset_matches_source_lane(&generated_manifest, DEFAULT_SOURCE_LANE)?; - check_canonical_asset_layout(true)?; - check_generated_manifest_for_aot(&load_sources_manifest()?, true)?; - verify_asset_manifest_hashes()?; - verify_generated_extension_surface()?; - - find_aot_artifact_dir(target)?; - check_aot_package_manifest(target, DEFAULT_SOURCE_LANE)?; - println!("local generated assets are installed for {target}"); - Ok(()) -} - -pub(super) fn run_asset_smoke_tests(args: &[String]) -> Result<()> { - let mode = match args { - [] => "smoke", - [arg] if arg == "--core-only" => "core-smoke", - [arg] => bail!("unknown assets smoke flag: {arg}"), - _ => bail!("assets smoke accepts at most one flag"), - }; - if mode == "smoke" { - run( - "src/runtimes/liboliphaunt/wasix/tools/runtime-smoke.sh", - &[], - ) - } else { - run( - "src/runtimes/liboliphaunt/wasix/tools/runtime-smoke.sh", - &[mode], - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn test_root(label: &str) -> PathBuf { - let nonce = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos(); - let root = std::env::temp_dir().join(format!( - "oliphaunt-asset-io-{label}-{}-{nonce}", - std::process::id() - )); - fs::create_dir_all(&root).unwrap(); - root - } - - #[test] - fn staged_retry_uses_fresh_bytes_and_preserves_no_partial_result() { - let root = test_root("retry"); - let destination = root.join("durable"); - fs::create_dir_all(&destination).unwrap(); - fs::write(destination.join("old"), b"old").unwrap(); - let policy = DownloadRetryPolicy { - base_delay: Duration::ZERO, - deadline: Duration::from_secs(5), - max_attempts: 2, - }; - let mut attempts = 0; - retry_staged_download(&destination, "test download", policy, |stage, _| { - attempts += 1; - assert!( - !stage.join("partial").exists(), - "retry inherited a prior partial file" - ); - if attempts == 1 { - fs::write(stage.join("partial"), b"truncated").unwrap(); - return Err(DownloadAttemptError::retryable(anyhow!("unexpected EOF"))); - } - fs::write(stage.join("complete"), b"complete").unwrap(); - Ok(()) - }) - .unwrap(); - assert_eq!(attempts, 2); - assert_eq!(fs::read(destination.join("complete")).unwrap(), b"complete"); - assert!(!destination.join("partial").exists()); - assert!(!destination.join("old").exists()); - assert!(fs::read_dir(&root).unwrap().all(|entry| { - !entry - .unwrap() - .file_name() - .to_string_lossy() - .starts_with(".durable.") - })); - fs::remove_dir_all(root).unwrap(); - } - - #[test] - fn permanent_staged_failure_preserves_existing_destination() { - let root = test_root("permanent"); - let destination = root.join("durable"); - fs::create_dir_all(&destination).unwrap(); - fs::write(destination.join("existing"), b"preserve").unwrap(); - let policy = DownloadRetryPolicy { - base_delay: Duration::ZERO, - deadline: Duration::from_secs(5), - max_attempts: 4, - }; - let error = retry_staged_download(&destination, "test download", policy, |stage, _| { - fs::write(stage.join("partial"), b"partial").unwrap(); - Err(DownloadAttemptError::permanent(anyhow!("HTTP 404"))) - }) - .unwrap_err(); - assert!(format!("{error:#}").contains("HTTP 404")); - assert_eq!(fs::read(destination.join("existing")).unwrap(), b"preserve"); - assert!(!destination.join("partial").exists()); - fs::remove_dir_all(root).unwrap(); - } - - #[test] - fn install_staging_failure_cannot_partially_replace_destinations() { - let root = test_root("transaction"); - let source = root.join("source"); - let missing = root.join("missing"); - let first = root.join("first"); - let second = root.join("second"); - fs::create_dir_all(&source).unwrap(); - fs::create_dir_all(&first).unwrap(); - fs::create_dir_all(&second).unwrap(); - fs::write(source.join("new"), b"new").unwrap(); - fs::write(first.join("old-first"), b"old-first").unwrap(); - fs::write(second.join("old-second"), b"old-second").unwrap(); - assert!( - promote_directories_transactionally(&[ - (source, first.clone()), - (missing, second.clone()) - ]) - .is_err() - ); - assert_eq!(fs::read(first.join("old-first")).unwrap(), b"old-first"); - assert_eq!(fs::read(second.join("old-second")).unwrap(), b"old-second"); - fs::remove_dir_all(root).unwrap(); - } - - #[test] - fn checksum_manifest_requires_one_exact_asset_identity() { - let digest = "a".repeat(64); - let asset = "liboliphaunt-wasix-1.0.0-runtime-portable.tar.zst"; - let manifest = format!("{digest} ./{asset}\n{digest} ./{asset}-near-match\n"); - assert_eq!(release_asset_checksum(&manifest, asset).unwrap(), digest); - let duplicate = format!("{manifest}{} ./{asset}\n", "b".repeat(64)); - assert!(release_asset_checksum(&duplicate, asset).is_err()); - assert!(release_asset_checksum("not-a-digest ./asset\n", "asset").is_err()); - } - - #[test] - fn release_asset_curl_uses_https_only_and_schannel_best_effort_on_windows() { - let destination = Path::new("release-asset.tar.zst"); - let windows = curl_release_asset_args( - "https://github.com/f0rr0/oliphaunt/releases/download/product-v1.0.0/release-asset.tar.zst", - destination, - "600", - true, - ); - assert!(windows.windows(2).any(|pair| pair == ["--proto", "=https"])); - assert!( - windows - .windows(2) - .any(|pair| pair == ["--proto-redir", "=https"]) - ); - assert!(windows.iter().any(|arg| arg == "--ssl-revoke-best-effort")); - assert!(!windows.iter().any(|arg| arg == "--insecure" || arg == "-k")); - - let unix = curl_release_asset_args( - "https://github.com/f0rr0/oliphaunt/releases/download/product-v1.0.0/release-asset.tar.zst", - destination, - "600", - false, - ); - assert!(!unix.iter().any(|arg| arg == "--ssl-revoke-best-effort")); - } - - #[test] - fn exact_sha_run_inventory_rejects_mismatched_or_malformed_identity() { - let sha = "a".repeat(40); - let exact = format!(r#"[{{"databaseId":77,"status":"completed","headSha":"{sha}"}}]"#); - assert_eq!(parse_exact_sha_run_ids(&exact, &sha).unwrap(), ["77"]); - let mismatch = format!( - r#"[{{"databaseId":77,"status":"completed","headSha":"{}"}}]"#, - "b".repeat(40) - ); - assert!(parse_exact_sha_run_ids(&mismatch, &sha).is_err()); - assert!(parse_exact_sha_run_ids( - r#"[{"databaseId":"77","status":"completed","headSha":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}]"#, - &sha - ) - .is_err()); - } -} diff --git a/tools/xtask/src/asset_pipeline.rs b/tools/xtask/src/asset_pipeline.rs deleted file mode 100644 index 6bfac5c7c..000000000 --- a/tools/xtask/src/asset_pipeline.rs +++ /dev/null @@ -1,4068 +0,0 @@ -use super::*; - -pub(crate) struct BuildOutputs { - source_lane: String, - source_fingerprint: Option, - postgres_version: String, - build_dir: PathBuf, - source_dir: PathBuf, - package_stage: PathBuf, - modules: Vec, -} - -struct BuildModuleOutput { - name: String, - kind: String, - path: PathBuf, - aot_file: String, - requires_aot: bool, -} - -fn postgres_source_dir() -> Result { - let manifest = load_postgres_source_manifest()?; - let source = postgres_default_source_dir(&manifest); - ensure!( - source.join(".oliphaunt-wasix-source-fingerprint").is_file(), - "missing prepared PG18 WASIX source at {}; run {POSTGRES_PREPARE_SCRIPT}", - source.display() - ); - check_prepared_postgres_source(&manifest, &source, Path::new(WASIX_POSTGRES_WORK_DIR))?; - Ok(source) -} - -fn postgres_version_for_source_lane(source_lane: &str, source_dir: &Path) -> Result { - match source_lane { - "stable" => { - let version_path = source_dir.join(".oliphaunt-wasix-postgres-version"); - let version = fs::read_to_string(&version_path) - .with_context(|| format!("read {}", version_path.display()))?; - let version = version.trim(); - ensure!( - !version.is_empty(), - "{} must contain a PostgreSQL version", - version_path.display() - ); - Ok(version.to_owned()) - } - other => bail!("unsupported WASIX asset source lane {other:?}"), - } -} - -fn source_fingerprint_for_source_lane( - source_lane: &str, - source_dir: &Path, -) -> Result> { - match source_lane { - "stable" => { - let path = source_dir.join(".oliphaunt-wasix-source-fingerprint"); - let fingerprint = - fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?; - let fingerprint = fingerprint.trim(); - ensure!( - !fingerprint.is_empty(), - "{} must contain a PG18 source fingerprint", - path.display() - ); - Ok(Some(fingerprint.to_owned())) - } - other => bail!("unsupported WASIX asset source lane {other:?}"), - } -} - -fn expected_postgres_source_fingerprint() -> Result { - let manifest = load_postgres_source_manifest()?; - postgres_expected_source_fingerprint(&manifest) -} - -pub(crate) fn ensure_postgres_source_fingerprint_matches_current( - actual: Option<&str>, - field: &str, -) -> Result<()> { - let expected = expected_postgres_source_fingerprint()?; - ensure_eq(actual.unwrap_or(""), &expected, field) -} - -fn postgres_major_version(postgres_version: &str) -> String { - postgres_version - .split('.') - .next() - .filter(|major| !major.is_empty()) - .unwrap_or(postgres_version) - .to_owned() -} - -pub(crate) fn ensure_packaged_asset_matches_source_lane( - manifest: &AssetManifestOut, - source_lane: &str, -) -> Result<()> { - let expected = canonical_source_lane(source_lane)?; - if let Some(actual) = manifest.source_lane.as_deref() { - ensure_eq(actual, expected, "packaged asset manifest source-lane")?; - } - match expected { - "stable" => ensure!( - manifest.runtime.postgres_version.starts_with("18."), - "packaged assets are PostgreSQL {}, not the PG18 WASIX runtime", - manifest.runtime.postgres_version - ), - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } - if expected == "stable" { - ensure_postgres_source_fingerprint_matches_current( - manifest.source_fingerprint.as_deref(), - "packaged asset manifest source-fingerprint", - )?; - } - Ok(()) -} - -fn ensure_build_output_manifest_matches_source_lane( - manifest: &BuildOutputManifestOut, - source_lane: &str, -) -> Result<()> { - let expected = canonical_source_lane(source_lane)?; - let actual = manifest.source_lane.as_deref().unwrap_or(""); - match expected { - "stable" => { - ensure_eq(actual, "stable", "WASIX build output manifest source-lane")?; - let pg18 = load_postgres_source_manifest()?; - ensure_eq( - manifest.postgres_version.as_deref().unwrap_or(""), - pg18.postgresql.version.as_str(), - "WASIX build output manifest postgres-version", - )?; - ensure_postgres_source_fingerprint_matches_current( - manifest.source_fingerprint.as_deref(), - "WASIX build output manifest source-fingerprint", - )?; - ensure_postgres_build_output_manifest_paths_are_stable(manifest)?; - } - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } - if let Some(postgres_version) = manifest.postgres_version.as_deref() { - match expected { - "stable" => ensure!( - postgres_version.starts_with("18."), - "WASIX build output manifest is PostgreSQL {postgres_version}, not the PG18 WASIX runtime" - ), - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } - } - Ok(()) -} - -fn ensure_postgres_build_output_manifest_paths_are_stable( - manifest: &BuildOutputManifestOut, -) -> Result<()> { - let postgres_root = Path::new(WASIX_POSTGRES_DOCKER_BUILD_DIR); - for module in &manifest.modules { - let path = Path::new(&module.path); - ensure!( - path.starts_with(postgres_root), - "PostgreSQL build output manifest module {} points outside the stable build root: {}", - module.name, - module.path - ); - } - Ok(()) -} - -pub(crate) fn canonical_source_lane(source_lane: &str) -> Result<&'static str> { - match source_lane { - "stable" | "released" | "packaged" | "default" => Ok(DEFAULT_SOURCE_LANE), - other => bail!("unsupported WASIX asset source lane {other:?}"), - } -} - -pub(crate) fn build_output_manifest_path_for_source_lane( - source_lane: &str, -) -> Result<&'static Path> { - match canonical_source_lane(source_lane)? { - "stable" => Ok(Path::new(WASIX_POSTGRES_BUILD_MANIFEST_PATH)), - other => bail!("unsupported WASIX asset source lane {other:?}"), - } -} - -pub(crate) fn build_output_manifest_paths_for_source_lane( - source_lane: &str, -) -> Result> { - let primary = build_output_manifest_path_for_source_lane(source_lane)?; - let _ = canonical_source_lane(source_lane)?; - Ok(vec![primary]) -} - -pub(crate) fn generated_assets_dir_for_source_lane(source_lane: &str) -> Result<&'static Path> { - match canonical_source_lane(source_lane)? { - "stable" => Ok(Path::new(GENERATED_ASSETS_DIR)), - other => bail!("unsupported WASIX asset source lane {other:?}"), - } -} - -pub(crate) fn generated_aot_source_dir_for_source_lane( - target: &str, - source_lane: &str, -) -> Result { - match canonical_source_lane(source_lane)? { - "stable" => Ok(Path::new(WASIX_POSTGRES_GENERATED_BUILD_DIR) - .join("aot") - .join(target)), - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } -} - -fn generated_aot_inputs_dir_for_source_lane(source_lane: &str) -> Result { - match canonical_source_lane(source_lane)? { - "stable" => Ok(Path::new(WASIX_POSTGRES_GENERATED_BUILD_DIR).join("aot-inputs")), - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } -} - -pub(crate) fn generated_aot_dir_for_source_lane( - target: &str, - source_lane: &str, -) -> Result { - match canonical_source_lane(source_lane)? { - "stable" => Ok(Path::new(GENERATED_AOT_DIR).join(target)), - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } -} - -pub(crate) fn skip_extensions_for_perf_probe() -> bool { - env::var("OLIPHAUNT_WASM_SKIP_EXTENSIONS_FOR_PERF").as_deref() == Ok("1") -} - -impl BuildOutputs { - pub(crate) fn discover_for_source_lane(source_lane: &str) -> Result { - let source_lane = canonical_source_lane(source_lane)?; - let (canonical_source_lane, build_dir, source_dir, package_stage) = match source_lane { - "stable" => ( - "stable".to_owned(), - PathBuf::from(WASIX_POSTGRES_DOCKER_BUILD_DIR), - postgres_source_dir()?, - PathBuf::from(WASIX_POSTGRES_GENERATED_BUILD_DIR).join("package-stage"), - ), - other => unreachable!("canonical_source_lane returned an unsupported lane: {other}"), - }; - let mut modules = vec![ - BuildModuleOutput { - name: "runtime:oliphaunt".to_owned(), - kind: "runtime".to_owned(), - path: build_dir.join("src/backend/oliphaunt"), - aot_file: "oliphaunt-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }, - BuildModuleOutput { - name: "runtime-support:plpgsql".to_owned(), - kind: "runtime-support".to_owned(), - path: build_dir.join("src/pl/plpgsql/src/plpgsql.so"), - aot_file: "plpgsql-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }, - BuildModuleOutput { - name: "runtime-support:dict_snowball".to_owned(), - kind: "runtime-support".to_owned(), - path: build_dir.join("src/backend/snowball/dict_snowball.so"), - aot_file: "dict_snowball-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }, - BuildModuleOutput { - name: "tool:initdb".to_owned(), - kind: "tool".to_owned(), - path: build_dir.join("src/bin/initdb/initdb"), - aot_file: "initdb-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }, - ]; - if !skip_extensions_for_perf_probe() { - modules.push(BuildModuleOutput { - name: "tool:pg_dump".to_owned(), - kind: "tool".to_owned(), - path: build_dir.join("src/bin/pg_dump/pg_dump"), - aot_file: "pg_dump-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }); - modules.push(BuildModuleOutput { - name: "tool:psql".to_owned(), - kind: "tool".to_owned(), - path: build_dir.join("src/bin/psql/psql"), - aot_file: "psql-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }); - } - if !skip_extensions_for_perf_probe() { - for extension in extension_catalog::extension_build_specs()? { - for support_module in &extension.native_support_modules { - modules.push(BuildModuleOutput { - name: format!("extension:{}:{}", extension.sql_name, support_module.name), - kind: "extension".to_owned(), - path: build_dir.join(&support_module.build_path), - aot_file: support_module.aot_file.clone(), - requires_aot: true, - }); - } - if extension.module_file.is_some() { - modules.push(BuildModuleOutput { - name: format!("extension:{}", extension.sql_name), - kind: "extension".to_owned(), - path: extension_build_module_path(&build_dir, &extension)?, - aot_file: format!( - "{}-llvm-opta.bin.zst", - extension_aot_file_stem(&extension) - ), - requires_aot: true, - }); - } - } - } - - let outputs = Self { - postgres_version: postgres_version_for_source_lane( - &canonical_source_lane, - &source_dir, - )?, - source_fingerprint: source_fingerprint_for_source_lane( - &canonical_source_lane, - &source_dir, - )?, - source_lane: canonical_source_lane, - build_dir, - source_dir, - package_stage, - modules, - }; - outputs.ensure_required_files()?; - Ok(outputs) - } - - pub(crate) fn discover_for_aot(source_lane: &str) -> Result { - let canonical = canonical_source_lane(source_lane)?; - if canonical == DEFAULT_SOURCE_LANE { - return Self::discover_for_source_lane(source_lane).or_else(|build_err| { - eprintln!( - "warning: transient WASIX build tree unavailable for {source_lane} AOT packaging: {build_err:#}" - ); - Self::from_packaged_assets_for_source_lane(source_lane) - }); - } - unreachable!("canonical_source_lane returned an unsupported lane: {canonical}") - } - - fn from_packaged_assets_for_source_lane(source_lane: &str) -> Result { - let manifest = read_asset_manifest_for_source_lane(source_lane)?; - ensure_packaged_asset_matches_source_lane(&manifest, source_lane)?; - let canonical_source_lane = canonical_source_lane(source_lane)?; - let base = generated_aot_inputs_dir_for_source_lane(source_lane)?; - if base.exists() { - fs::remove_dir_all(&base).with_context(|| format!("remove {}", base.display()))?; - } - fs::create_dir_all(&base).with_context(|| format!("create {}", base.display()))?; - - let assets_base = generated_assets_dir_for_source_lane(source_lane)?; - let runtime_archive = assets_base.join(&manifest.runtime.archive); - let runtime_path = base.join("runtime/oliphaunt"); - write_bytes_file( - &runtime_path, - &archive_entry_bytes(&runtime_archive, RUNTIME_MODULE_ARCHIVE_MEMBER)?, - )?; - - let mut modules = vec![BuildModuleOutput { - name: "runtime:oliphaunt".to_owned(), - kind: "runtime".to_owned(), - path: runtime_path, - aot_file: "oliphaunt-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }]; - - for support in &manifest.runtime_support { - let path = base.join("runtime-support").join(&support.name); - write_bytes_file( - &path, - &archive_entry_bytes(&runtime_archive, &format!("oliphaunt/{}", support.path))?, - )?; - modules.push(BuildModuleOutput { - name: format!("runtime-support:{}", support.name), - kind: "runtime-support".to_owned(), - path, - aot_file: format!("{}-llvm-opta.bin.zst", support.name), - requires_aot: true, - }); - } - - if let Some(pg_dump) = &manifest.pg_dump { - let path = base.join("tools/pg_dump"); - copy_file(&assets_base.join(&pg_dump.path), &path)?; - modules.push(BuildModuleOutput { - name: "tool:pg_dump".to_owned(), - kind: "tool".to_owned(), - path, - aot_file: "pg_dump-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }); - } - if let Some(psql) = &manifest.psql { - let path = base.join("tools/psql"); - copy_file(&assets_base.join(&psql.path), &path)?; - modules.push(BuildModuleOutput { - name: "tool:psql".to_owned(), - kind: "tool".to_owned(), - path, - aot_file: "psql-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }); - } - if let Some(initdb) = &manifest.initdb { - let path = base.join("tools/initdb"); - copy_file(&assets_base.join(&initdb.path), &path)?; - modules.push(BuildModuleOutput { - name: "tool:initdb".to_owned(), - kind: "tool".to_owned(), - path, - aot_file: "initdb-llvm-opta.bin.zst".to_owned(), - requires_aot: true, - }); - } - - for extension in &manifest.extensions { - let mut native_modules = extension.native_modules.clone(); - if native_modules.is_empty() - && let Some(native_module) = extension.native_module.as_deref() - && !extension.module_sha256.is_empty() - { - native_modules.push(BinaryAssetOut { - name: extension.sql_name.clone(), - path: format!("lib/postgresql/{native_module}"), - sha256: extension.module_sha256.clone(), - module_sha256: extension.module_sha256.clone(), - size: 0, - link: extension.link.clone().unwrap_or_default(), - }); - } - for native_module in native_modules { - if native_module.module_sha256.is_empty() { - continue; - } - let path = base.join("extensions").join(&extension.sql_name).join( - Path::new(&native_module.path) - .file_name() - .unwrap_or_default(), - ); - write_bytes_file( - &path, - &archive_entry_bytes( - &assets_base.join(&extension.archive), - &native_module.path, - )?, - )?; - modules.push(BuildModuleOutput { - name: if native_module.name == extension.sql_name { - format!("extension:{}", extension.sql_name) - } else { - format!("extension:{}:{}", extension.sql_name, native_module.name) - }, - kind: "extension".to_owned(), - path, - aot_file: format!("{}-llvm-opta.bin.zst", native_module.name.replace('/', "_")), - requires_aot: true, - }); - } - } - - Ok(Self { - source_lane: canonical_source_lane.to_owned(), - source_fingerprint: manifest.source_fingerprint.clone(), - postgres_version: manifest.runtime.postgres_version.clone(), - build_dir: base.clone(), - source_dir: base.clone(), - package_stage: base, - modules, - }) - } - - fn ensure_required_files(&self) -> Result<()> { - for module in &self.modules { - ensure_file(&module.path)?; - } - self.ensure_build_source_markers()?; - ensure_file(&self.build_dir.join("src/timezone/compiled/UTC"))?; - ensure_file( - &self - .build_dir - .join("src/backend/snowball/snowball_create.sql"), - )?; - for language in [ - "danish", - "dutch", - "english", - "finnish", - "french", - "german", - "hungarian", - "italian", - "nepali", - "norwegian", - "portuguese", - "russian", - "spanish", - "swedish", - "turkish", - ] { - ensure_file( - &self - .source_dir - .join(format!("src/backend/snowball/stopwords/{language}.stop")), - )?; - } - Ok(()) - } - - fn ensure_build_source_markers(&self) -> Result<()> { - match self.source_lane.as_str() { - "stable" => { - let source_fingerprint = self - .source_fingerprint - .as_deref() - .ok_or_else(|| anyhow!("PG18 build outputs are missing source fingerprint"))?; - ensure_matching_marker( - source_fingerprint, - &self.build_dir.join(".oliphaunt-wasix-source-fingerprint"), - "PG18 build source fingerprint", - )?; - ensure_matching_marker( - &self.postgres_version, - &self.build_dir.join(".oliphaunt-wasix-postgres-version"), - "PG18 build PostgreSQL version marker", - )?; - } - other => bail!("unsupported WASIX asset source lane {other:?}"), - } - Ok(()) - } - - fn module_path(&self, name: &str) -> Result<&Path> { - self.modules - .iter() - .find(|module| module.name == name) - .map(|module| module.path.as_path()) - .ok_or_else(|| anyhow!("missing build output module {name}")) - } - - fn manifest_path(&self) -> Result<&'static Path> { - build_output_manifest_path_for_source_lane(&self.source_lane) - } - - fn write_manifest(&self) -> Result<()> { - let manifest = BuildOutputManifestOut { - format_version: 1, - source_lane: Some(self.source_lane.clone()), - source_fingerprint: self.source_fingerprint.clone(), - postgres_version: Some(self.postgres_version.clone()), - build_profile: fs::read_to_string( - self.build_dir.join(".oliphaunt-wasix-build-profile"), - ) - .context("read WASIX build profile signature")?, - modules: self - .modules - .iter() - .map(|module| { - Ok(BuildModuleManifestOut { - name: module.name.clone(), - kind: module.kind.clone(), - path: module.path.to_string_lossy().into_owned(), - sha256: sha256_file(&module.path)?, - link: read_wasm_link_metadata(&module.path)?, - }) - }) - .collect::>>()?, - }; - for module in &manifest.modules { - validate_module_link_metadata(module)?; - } - ensure_build_output_manifest_matches_source_lane(&manifest, &self.source_lane)?; - let text = serde_json::to_string_pretty(&manifest) - .context("serialize WASIX build output manifest")?; - let path = self.manifest_path()?; - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?; - } - fs::write(path, format!("{text}\n")).with_context(|| format!("write {}", path.display())) - } -} - -fn extension_build_module_path( - build_dir: &Path, - extension: &extension_catalog::ExtensionBuildSpec, -) -> Result { - let module_file = extension - .module_file - .as_deref() - .ok_or_else(|| anyhow!("extension {} has no native module", extension.sql_name))?; - match extension.build_kind.as_str() { - "postgres-contrib" => { - let contrib_dir = extension - .contrib_dir - .as_deref() - .ok_or_else(|| anyhow!("contrib extension {} has no contrib_dir", extension.id))?; - Ok(build_dir - .join("contrib") - .join(contrib_dir) - .join(module_file)) - } - kind if extension_catalog::is_pgxs_style_build_kind(kind) => { - Ok(pgxs_extension_build_dir(build_dir, extension).join(module_file)) - } - kind if extension_catalog::is_recipe_staged_build_kind(kind) => { - let staging = extension - .staging - .as_ref() - .ok_or_else(|| anyhow!("extension {} has no staging metadata", extension.id))?; - let module_source_dir = staging.module_source_dir.as_deref().ok_or_else(|| { - anyhow!( - "extension {} staging metadata has no module_source_dir", - extension.id - ) - })?; - Ok(build_dir.join(module_source_dir).join(module_file)) - } - other => bail!( - "supported extension {} has unsupported build kind {other}", - extension.sql_name - ), - } -} - -fn pgxs_extension_build_dir( - build_dir: &Path, - extension: &extension_catalog::ExtensionBuildSpec, -) -> PathBuf { - build_dir.join("pgxs").join(&extension.id) -} - -fn extension_aot_file_stem(extension: &extension_catalog::ExtensionBuildSpec) -> String { - extension.sql_name.replace('/', "_") -} - -fn validate_build_profile_outputs(outputs: &BuildOutputs, profile: &str) -> Result<()> { - let signature_path = outputs.build_dir.join(".oliphaunt-wasix-build-profile"); - let signature = fs::read_to_string(&signature_path) - .with_context(|| format!("read {}", signature_path.display()))?; - let profile_line = format!("profile={profile}"); - if !signature.lines().any(|line| line == profile_line) { - bail!( - "WASIX build profile signature does not match requested profile {profile}: {}", - signature_path.display() - ); - } - - if profile.starts_with("release") { - let cflags = signature - .lines() - .find_map(|line| line.strip_prefix("cflags=")) - .unwrap_or_default(); - let has_release_opt = ["-O2", "-O3", "-Os", "-Oz"] - .iter() - .any(|flag| cflags.split_whitespace().any(|part| part == *flag)); - if !has_release_opt || !cflags.split_whitespace().any(|part| part == "-g0") { - bail!( - "release WASIX profile must include an optimizing -O flag and -g0; got cflags={cflags:?}" - ); - } - - let makefile = outputs.build_dir.join("src/Makefile.global"); - let makefile_text = fs::read_to_string(&makefile) - .with_context(|| format!("read {}", makefile.display()))?; - if !["-O2", "-O3", "-Os", "-Oz"] - .iter() - .any(|flag| makefile_text.contains(flag)) - { - bail!( - "release WASIX build did not propagate optimization flags into {}", - makefile.display() - ); - } - } - - Ok(()) -} - -fn validate_module_link_metadata(module: &BuildModuleManifestOut) -> Result<()> { - if module.link.exports.is_empty() { - bail!("{} has no WASM exports", module.name); - } - - match module.kind.as_str() { - "runtime" => { - let thread_spawn_imports = module - .link - .imports - .iter() - .filter(|import| is_thread_spawn_import(import)) - .map(|import| format!("{}.{}", import.module, import.name)) - .collect::>(); - ensure!( - thread_spawn_imports.is_empty(), - "{} violates the single-backend contract with thread-spawn imports: {}", - module.name, - thread_spawn_imports.join(", ") - ); - let missing = required_runtime_abi_exports() - .iter() - .copied() - .filter(|export| !has_wasm_export(&module.link, export)) - .collect::>(); - if !missing.is_empty() { - bail!( - "{} is missing required Rust/WASIX ABI exports: {}", - module.name, - missing.join(", ") - ); - } - for banned in [ - "oliphaunt_wasix_initdb", - "oliphaunt_wasix_backend", - "PostgresRecoverProtocolError", - ] { - if has_wasm_export(&module.link, banned) { - bail!( - "{} exports legacy builder-branch lifecycle entrypoint {banned}", - module.name - ); - } - } - } - "runtime-support" | "extension" => { - if !module.link.has_dylink0 { - bail!("{} is not a WASM dynamic-linking side module", module.name); - } - if module.link.imports.is_empty() && module.link.dylink_imports.is_empty() { - bail!( - "{} has no imports; side-module linkage is suspicious", - module.name - ); - } - } - "tool" => {} - other => bail!("{} has unknown build output kind {other}", module.name), - } - - Ok(()) -} - -fn is_thread_spawn_import(import: &WasmImportOut) -> bool { - matches!( - import.name.trim_start_matches('_'), - "thread-spawn" - | "thread_spawn" - | "thread_spawn_v2" - | "wasi_thread_spawn" - | "wasi_thread_spawn_v2" - | "pthread_create" - ) -} - -fn validate_build_output_link_closure(outputs: &BuildOutputs) -> Result<()> { - let runtime = outputs - .modules - .iter() - .find(|module| module.kind == "runtime") - .ok_or_else(|| anyhow!("build outputs are missing runtime module"))?; - let runtime_link = read_wasm_link_metadata(&runtime.path)?; - validate_sealed_runtime_exports(&runtime_link)?; - let side_modules = outputs - .modules - .iter() - .filter(|module| matches!(module.kind.as_str(), "runtime-support" | "extension")) - .collect::>(); - let side_module_links = side_modules - .iter() - .map(|module| { - Ok::<_, anyhow::Error>((module.name.clone(), read_wasm_link_metadata(&module.path)?)) - }) - .collect::>>()?; - let side_module_basenames = side_module_basename_index( - side_modules - .iter() - .map(|module| (module.name.as_str(), module.path.as_path())), - )?; - - let mut failures = Vec::new(); - for module in side_modules { - let link = side_module_links - .get(&module.name) - .ok_or_else(|| anyhow!("missing link metadata for {}", module.name))?; - let provider_exports = - side_module_provider_exports(&module.name, &side_module_links, &side_module_basenames)?; - for import in &link.imports { - if !import_should_resolve_from_runtime(import) { - continue; - } - if import_resolves_from_wasm_exports(import, &provider_exports, &module.name)? { - continue; - } - if !import_resolves_from_wasm_exports(import, &runtime_link.exports, "runtime")? { - failures.push(format!( - "{} imports {}.{}", - module.name, import.module, import.name - )); - } - } - } - - if !failures.is_empty() { - bail!( - "WASIX dynamic-link closure has unresolved side-module imports: {}", - failures.join(", ") - ); - } - Ok(()) -} - -fn validate_sealed_runtime_exports(runtime: &WasmLinkMetadataOut) -> Result<()> { - let policy_path = - repo_relative_path("src/runtimes/liboliphaunt/wasix/assets/generated/wasix-dl.exports"); - let policy = fs::read_to_string(&policy_path) - .with_context(|| format!("read {}", policy_path.display()))?; - let mut expected = policy - .lines() - .filter(|line| !line.is_empty()) - .map(str::to_owned) - .collect::>(); - expected.extend( - WASIX_LINKER_RUNTIME_EXPORTS - .iter() - .map(|name| (*name).to_owned()), - ); - let actual = runtime - .exports - .iter() - .map(|export| export.name.clone()) - .collect::>(); - ensure_exact_runtime_export_surface(&actual, &expected) -} - -fn ensure_exact_runtime_export_surface( - actual: &BTreeSet, - expected: &BTreeSet, -) -> Result<()> { - let missing = expected.difference(actual).cloned().collect::>(); - let unexpected = actual.difference(expected).cloned().collect::>(); - ensure!( - missing.is_empty() && unexpected.is_empty(), - "sealed WASIX runtime export surface differs: missing={missing:?} unexpected={unexpected:?}" - ); - Ok(()) -} - -fn side_module_provider_exports( - module_name: &str, - links_by_name: &BTreeMap, - names_by_basename: &BTreeMap, -) -> Result> { - let mut provider_names = BTreeSet::from([module_name.to_owned()]); - let mut pending = vec![module_name.to_owned()]; - while let Some(name) = pending.pop() { - let link = links_by_name - .get(&name) - .ok_or_else(|| anyhow!("missing side-module link metadata for {name}"))?; - for needed in &link.dylink_needed { - let dependency = names_by_basename.get(needed).ok_or_else(|| { - anyhow!("{name} declares missing WASIX dynamic dependency {needed}") - })?; - if provider_names.insert(dependency.clone()) { - pending.push(dependency.clone()); - } - } - } - Ok(provider_names - .into_iter() - .flat_map(|name| { - links_by_name - .get(&name) - .into_iter() - .flat_map(|link| link.exports.iter().cloned()) - }) - .collect()) -} - -fn side_module_basename_index<'a>( - modules: impl IntoIterator, -) -> Result> { - let mut names_by_basename = BTreeMap::new(); - for (name, path) in modules { - let basename = path - .file_name() - .and_then(|value| value.to_str()) - .ok_or_else(|| anyhow!("side-module {name} path has no UTF-8 basename"))?; - if let Some(previous) = names_by_basename.insert(basename.to_owned(), name.to_owned()) { - bail!("WASIX side modules {previous} and {name} share dynamic basename {basename}"); - } - } - Ok(names_by_basename) -} - -fn extension_module_sql_name(module_name: &str) -> Option<&str> { - module_name - .strip_prefix("extension:") - .and_then(|rest| rest.split(':').next()) - .filter(|sql_name| !sql_name.is_empty()) -} - -pub(crate) fn generate_wasix_export_list(write: bool, source_lane: &str) -> Result<()> { - let output = wasix_export_list_text(source_lane)?; - if write { - let path = Path::new("src/runtimes/liboliphaunt/wasix/assets/generated/wasix-dl.exports"); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?; - } - fs::write(path, output).with_context(|| format!("write {}", path.display()))?; - } else { - print!("{output}"); - } - Ok(()) -} - -pub(crate) fn check_generated_wasix_export_list(strict: bool) -> Result<()> { - let expected = match wasix_export_list_text(DEFAULT_SOURCE_LANE) { - Ok(expected) => expected, - Err(err) if !strict => { - eprintln!("warning: skipping generated WASIX export-list check: {err:#}"); - return Ok(()); - } - Err(err) => return Err(err).context("generate expected WASIX export list"), - }; - let path = Path::new("src/runtimes/liboliphaunt/wasix/assets/generated/wasix-dl.exports"); - if !path.exists() { - if strict { - bail!( - "generated WASIX export list is missing at {}; run `cargo run -p xtask -- assets export-list --write`", - path.display() - ); - } - eprintln!( - "warning: generated WASIX export list is missing at {}", - path.display() - ); - return Ok(()); - } - let actual = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?; - if actual != expected { - if strict { - bail!( - "generated WASIX export list is stale at {}; run `cargo run -p xtask -- assets export-list --write`", - path.display() - ); - } - eprintln!( - "warning: generated WASIX export list is stale at {}", - path.display() - ); - } - Ok(()) -} - -pub(crate) fn check_source_controlled_wasix_export_list() -> Result<()> { - let path = Path::new("src/runtimes/liboliphaunt/wasix/assets/generated/wasix-dl.exports"); - ensure_file(path)?; - let text = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?; - ensure!( - !text.trim().is_empty(), - "{} must not be empty", - path.display() - ); - for symbol in [ - "ProcessStartupPacket", - "PostgresMainLoopOnce", - "PostgresMainLongJmp", - "PostgresSendReadyForQueryIfNecessary", - "oliphaunt_wasix_get_proc_port", - "oliphaunt_wasix_pq_flush", - "oliphaunt_wasix_send_conn_data", - "oliphaunt_wasix_set_active", - "oliphaunt_wasix_set_force_host_error_recovery", - "oliphaunt_wasix_protocol_stream_active", - "oliphaunt_wasix_start", - "oliphaunt_wasix_set_protocol_transport", - "oliphaunt_wasix_input_reserve", - "oliphaunt_wasix_input_commit", - "oliphaunt_wasix_output_data", - "oliphaunt_wasix_output_contains_error", - "__wasm_longjmp", - "__wasm_setjmp", - "__wasm_setjmp_test", - "malloc", - "free", - ] { - ensure!( - text.lines().any(|line| line == symbol), - "{} is missing required runtime/protocol export symbol {symbol}", - path.display() - ); - } - let mut previous: Option<&str> = None; - for line in text.lines().filter(|line| !line.trim().is_empty()) { - if let Some(previous) = previous { - ensure!( - previous <= line, - "{} must stay sorted for deterministic reviews; {previous} appears before {line}", - path.display() - ); - } - previous = Some(line); - } - println!("source-controlled WASIX export-list guard passed"); - Ok(()) -} - -fn wasix_export_list_text(source_lane: &str) -> Result { - for manifest_path in build_output_manifest_paths_for_source_lane(source_lane)? { - if !manifest_path.exists() { - continue; - } - let manifest = read_build_output_manifest(manifest_path)?; - match ensure_build_output_manifest_matches_source_lane(&manifest, source_lane) { - Ok(()) => return wasix_export_list_from_modules(&manifest.modules), - Err(err) => { - eprintln!( - "warning: ignoring WASIX build output manifest {} while generating export list for {source_lane}: {err:#}", - manifest_path.display() - ); - } - } - } - let asset_dir = generated_assets_dir_for_source_lane(source_lane)?; - if asset_dir.join("manifest.json").exists() { - let manifest = read_asset_manifest_for_source_lane(source_lane)?; - if ensure_packaged_asset_matches_source_lane(&manifest, source_lane).is_ok() { - let modules = build_output_modules_from_asset_manifest(&manifest); - return wasix_export_list_from_modules(&modules); - } - eprintln!( - "warning: ignoring generated asset manifest for PostgreSQL {} while generating export list for {source_lane}", - manifest.runtime.postgres_version - ); - } - - let outputs = BuildOutputs::discover_for_source_lane(source_lane)?; - let modules = outputs - .modules - .iter() - .map(|module| { - Ok(BuildModuleManifestOut { - name: module.name.clone(), - kind: module.kind.clone(), - path: module.path.to_string_lossy().into_owned(), - sha256: String::new(), - link: read_wasm_link_metadata(&module.path)?, - }) - }) - .collect::>>()?; - wasix_export_list_from_modules(&modules) -} - -fn read_build_output_manifest(path: &Path) -> Result { - let text = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?; - serde_json::from_str(&text).with_context(|| format!("parse {}", path.display())) -} - -pub(crate) fn read_asset_manifest_for_source_lane(source_lane: &str) -> Result { - read_asset_manifest_from(generated_assets_dir_for_source_lane(source_lane)?) -} - -pub(crate) fn read_asset_manifest_from(asset_dir: &Path) -> Result { - let path = asset_dir.join("manifest.json"); - let text = fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?; - let manifest: AssetManifestOut = - serde_json::from_str(&text).with_context(|| format!("parse {}", path.display()))?; - ensure!( - manifest.format_version == ASSET_MANIFEST_FORMAT_VERSION, - "{} must use WASIX asset manifest format {}", - path.display(), - ASSET_MANIFEST_FORMAT_VERSION, - ); - Ok(manifest) -} - -fn build_output_modules_from_asset_manifest( - manifest: &AssetManifestOut, -) -> Vec { - let mut modules = vec![BuildModuleManifestOut { - name: "runtime:oliphaunt".to_owned(), - kind: "runtime".to_owned(), - path: manifest.runtime.archive.clone(), - sha256: manifest.runtime.module_sha256.clone(), - link: manifest.runtime.link.clone(), - }]; - - modules.extend( - manifest - .runtime_support - .iter() - .map(|module| BuildModuleManifestOut { - name: format!("runtime-support:{}", module.name), - kind: "runtime-support".to_owned(), - path: module.path.clone(), - sha256: module.module_sha256.clone(), - link: module.link.clone(), - }), - ); - - if let Some(pg_dump) = &manifest.pg_dump { - modules.push(BuildModuleManifestOut { - name: "tool:pg_dump".to_owned(), - kind: "tool".to_owned(), - path: pg_dump.path.clone(), - sha256: pg_dump.module_sha256.clone(), - link: pg_dump.link.clone(), - }); - } - if let Some(psql) = &manifest.psql { - modules.push(BuildModuleManifestOut { - name: "tool:psql".to_owned(), - kind: "tool".to_owned(), - path: psql.path.clone(), - sha256: psql.module_sha256.clone(), - link: psql.link.clone(), - }); - } - if let Some(initdb) = &manifest.initdb { - modules.push(BuildModuleManifestOut { - name: "tool:initdb".to_owned(), - kind: "tool".to_owned(), - path: initdb.path.clone(), - sha256: initdb.module_sha256.clone(), - link: initdb.link.clone(), - }); - } - - for extension in &manifest.extensions { - for native_module in &extension.native_modules { - modules.push(BuildModuleManifestOut { - name: if native_module.name == extension.sql_name { - format!("extension:{}", extension.sql_name) - } else { - format!("extension:{}:{}", extension.sql_name, native_module.name) - }, - kind: "extension".to_owned(), - path: native_module.path.clone(), - sha256: native_module.module_sha256.clone(), - link: native_module.link.clone(), - }); - } - let has_primary_native_module = extension - .native_modules - .iter() - .any(|module| module.name == extension.sql_name); - if !has_primary_native_module && let Some(link) = extension.link.clone() { - modules.push(BuildModuleManifestOut { - name: format!("extension:{}", extension.sql_name), - kind: "extension".to_owned(), - path: extension.archive.clone(), - sha256: extension.module_sha256.clone(), - link, - }); - } - } - - modules -} - -fn wasix_export_list_from_modules(modules: &[BuildModuleManifestOut]) -> Result { - for module in modules { - validate_module_link_metadata(module)?; - } - - let _runtime = modules - .iter() - .find(|module| module.kind == "runtime") - .ok_or_else(|| anyhow!("build outputs are missing runtime module"))?; - let side_modules = modules - .iter() - .filter(|module| matches!(module.kind.as_str(), "runtime-support" | "extension")) - .collect::>(); - let side_module_links = side_modules - .iter() - .map(|module| (module.name.clone(), module.link.clone())) - .collect::>(); - let side_module_basenames = side_module_basename_index( - side_modules - .iter() - .map(|module| (module.name.as_str(), Path::new(&module.path))), - )?; - let mut required_exports = BTreeSet::::new(); - - for &abi_export in required_runtime_abi_exports() { - required_exports.insert(abi_export.to_owned()); - } - - for module in side_modules { - let module_exports = - side_module_provider_exports(&module.name, &side_module_links, &side_module_basenames)?; - for import in &module.link.imports { - if !import_should_resolve_from_runtime(import) { - continue; - } - if import_resolves_from_wasm_exports(import, &module_exports, &module.name)? { - continue; - } - // The strict final link proves that the runtime defines every policy symbol. Do not - // consult the previously sealed runtime here: doing so would make adding a new side - // module import impossible without first restoring an ambient export surface. - required_exports.insert(runtime_export_name_for_side_import(import)); - } - } - - Ok(required_exports.into_iter().collect::>().join("\n") + "\n") -} - -pub(crate) fn required_runtime_abi_exports() -> &'static [&'static str] { - REQUIRED_RUNTIME_ABI_EXPORTS -} - -const WASIX_LINKER_RUNTIME_EXPORTS: &[&str] = &[ - "__data_end", - "__tls_align", - "__tls_base", - "__tls_size", - "__wasm_apply_data_relocs", - "__wasm_call_ctors", - "__wasm_init_tls", - "__wasm_sigaction", - "__wasm_signal", - "wasi_thread_start", -]; - -fn import_should_resolve_from_runtime(import: &WasmImportOut) -> bool { - if import_is_wasix_linker_provided(import) { - return false; - } - matches!(import.module.as_str(), "env" | "GOT.func" | "GOT.mem") -} - -fn import_is_wasix_linker_provided(import: &WasmImportOut) -> bool { - matches!( - (import.module.as_str(), import.name.as_str()), - ( - "env", - "__c_longjmp" - | "__cpp_exception" - | "__indirect_function_table" - | "__memory_base" - | "__stack_pointer" - | "__table_base" - | "memory", - ) | ("GOT.mem", "__heap_base" | "__stack_high" | "__stack_low") - ) -} - -fn import_resolves_from_wasm_exports( - import: &WasmImportOut, - exports: &[WasmExportOut], - provider: &str, -) -> Result { - Ok(resolved_wasm_export_name(import, exports, provider)?.is_some()) -} - -fn resolved_wasm_export_name( - import: &WasmImportOut, - exports: &[WasmExportOut], - provider: &str, -) -> Result> { - let mut candidates = exports - .iter() - .filter(|export| export.name == import.name) - .collect::>(); - if candidates.is_empty() { - let normalized = import.name.trim_start_matches('_'); - candidates = exports - .iter() - .filter(|export| export.name.trim_start_matches('_') == normalized) - .collect(); - } - if candidates.is_empty() { - return Ok(None); - } - let expected_kind = match import.module.as_str() { - "GOT.func" => "func", - "GOT.mem" => "global", - _ => import.kind.as_str(), - }; - ensure!( - candidates.iter().any(|export| export.kind == expected_kind), - "{provider} provides {}.{} as {:?}, expected {expected_kind}", - import.module, - import.name, - candidates - .iter() - .map(|export| export.kind.as_str()) - .collect::>() - ); - Ok(candidates - .into_iter() - .find(|export| export.kind == expected_kind) - .map(|export| export.name.clone())) -} - -fn runtime_export_name_for_side_import(import: &WasmImportOut) -> String { - import.name.clone() -} - -fn extension_asset_provider_exports( - primary_link: &WasmLinkMetadataOut, - primary_path: &Path, - sql_name: &str, - native_modules: &[OwnedExtensionNativeModule], - native_module_links: &BTreeMap, -) -> Result> { - let root_name = format!("extension:{sql_name}"); - let mut links = BTreeMap::from([(root_name.clone(), primary_link.clone())]); - let mut paths = vec![(root_name.as_str(), primary_path)]; - let mut dependency_names = Vec::new(); - for module in native_modules { - if module.name == sql_name { - continue; - } - let name = format!("extension:{sql_name}:{}", module.name); - let link = native_module_links - .get(&module.name) - .ok_or_else(|| anyhow!("missing link metadata for {name}"))?; - links.insert(name.clone(), link.clone()); - dependency_names.push((name, module.path.as_path())); - } - paths.extend( - dependency_names - .iter() - .map(|(name, path)| (name.as_str(), *path)), - ); - let basenames = side_module_basename_index(paths)?; - side_module_provider_exports(&root_name, &links, &basenames) -} - -fn has_wasm_export(link: &WasmLinkMetadataOut, name: &str) -> bool { - link.exports - .iter() - .any(|export| export.name == name || export.name == format!("_{name}")) -} - -pub(crate) fn build_asset_spine( - _manifest: &SourcesManifest, - profile: &str, - target: &str, - args: &[String], -) -> Result<()> { - let execute = args.iter().any(|arg| arg == "--execute") - || env::var("OLIPHAUNT_WASM_EXECUTE_ASSET_BUILD").as_deref() == Ok("1"); - let source_lane = - canonical_source_lane(value_after(args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE))?; - let backend_script = match source_lane { - "stable" => "src/runtimes/liboliphaunt/wasix/assets/build/docker_oliphaunt.sh", - other => bail!("unsupported WASIX asset source lane {other:?}"), - }; - - println!("asset build inputs validated"); - println!("profile={profile}"); - println!("target-triple={target}"); - - let commands = asset_build_commands(backend_script)?; - - if !execute { - println!("source-spine build is ready but not executed by default"); - println!("run with --execute or OLIPHAUNT_WASM_EXECUTE_ASSET_BUILD=1 to invoke:"); - for command in &commands { - println!(" {}", command.script); - } - println!("follow with `assets package` and `assets aot` to refresh publishable artifacts"); - return Ok(()); - } - - for command_spec in commands { - if skip_extensions_for_perf_probe() && command_spec.skip_for_core_probe { - println!("skipping {} for core-only perf probe", command_spec.script); - continue; - } - let mut command = Command::new("bash"); - command - .arg(&command_spec.script) - .env("OLIPHAUNT_WASM_BUILD_PROFILE", profile); - run_command(&mut command)?; - } - - let outputs = BuildOutputs::discover_for_source_lane(source_lane)?; - validate_build_profile_outputs(&outputs, profile)?; - outputs.write_manifest()?; - validate_build_output_link_closure(&outputs)?; - println!( - "wrote WASIX build output manifest to {}", - outputs.manifest_path()?.display() - ); - Ok(()) -} - -struct AssetBuildCommand { - script: String, - skip_for_core_probe: bool, -} - -fn asset_build_commands(backend_script: &str) -> Result> { - let mut commands = vec![ - AssetBuildCommand { - script: backend_script.to_owned(), - skip_for_core_probe: false, - }, - AssetBuildCommand { - script: "src/runtimes/liboliphaunt/wasix/assets/build/docker_runtime_support.sh" - .to_owned(), - skip_for_core_probe: false, - }, - AssetBuildCommand { - script: "src/runtimes/liboliphaunt/wasix/assets/build/docker_initdb.sh".to_owned(), - skip_for_core_probe: false, - }, - AssetBuildCommand { - script: "src/runtimes/liboliphaunt/wasix/assets/build/docker_pgxs_extensions.sh" - .to_owned(), - skip_for_core_probe: true, - }, - AssetBuildCommand { - script: "src/runtimes/liboliphaunt/wasix/assets/build/docker_contrib_extensions.sh" - .to_owned(), - skip_for_core_probe: true, - }, - ]; - for extension in extension_catalog::extension_build_specs()? { - if !extension_catalog::is_recipe_staged_build_kind(&extension.build_kind) { - continue; - } - let script = extension.build_script.clone().ok_or_else(|| { - anyhow!( - "recipe-staged extension {} has no WASIX build script", - extension.sql_name - ) - })?; - commands.push(AssetBuildCommand { - script, - skip_for_core_probe: true, - }); - } - commands.push(AssetBuildCommand { - script: "src/runtimes/liboliphaunt/wasix/assets/build/docker_pgdump.sh".to_owned(), - skip_for_core_probe: true, - }); - commands.push(AssetBuildCommand { - script: "src/runtimes/liboliphaunt/wasix/assets/build/docker_psql.sh".to_owned(), - skip_for_core_probe: true, - }); - Ok(commands) -} - -pub(crate) fn release_build_assets( - manifest: &SourcesManifest, - profile: &str, - target: &str, - args: &[String], -) -> Result<()> { - let source_lane = value_after(args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); - let mut build_args = vec![ - "build".to_owned(), - "--profile".to_owned(), - profile.to_owned(), - "--target-triple".to_owned(), - target.to_owned(), - "--execute".to_owned(), - ]; - build_args.extend( - args.iter() - .filter(|arg| matches!(arg.as_str(), "--skip-build" | "--skip-aot")) - .cloned(), - ); - - if !args.iter().any(|arg| arg == "--skip-build") { - build_asset_spine(manifest, profile, target, &build_args)?; - } else { - eprintln!("warning: skipping WASIX rebuild by request"); - } - - let outputs = BuildOutputs::discover_for_source_lane(source_lane)?; - validate_build_profile_outputs(&outputs, profile)?; - outputs.write_manifest()?; - validate_build_output_link_closure(&outputs)?; - - let skip_aot = args.iter().any(|arg| arg == "--skip-aot"); - package_assets_with_options(manifest, target, false, source_lane)?; - let asset_dir = generated_assets_dir_for_source_lane(source_lane)?; - check_canonical_asset_layout_in(asset_dir, true)?; - let expected_sources = effective_source_pins(manifest, &outputs)?; - check_generated_manifest_sources_in(asset_dir, &expected_sources, source_lane, true)?; - - if !skip_aot { - generate_aot_artifacts(target, source_lane)?; - package_aot_artifacts(target, &outputs, manifest)?; - check_aot_package_manifest(target, source_lane)?; - } else { - eprintln!("warning: skipping AOT generation by request"); - } - - Ok(()) -} - -pub(crate) fn generate_aot_artifacts(target: &str, source_lane: &str) -> Result<()> { - let outputs = BuildOutputs::discover_for_aot(source_lane)?; - let source_dir = generated_aot_source_dir_for_source_lane(target, &outputs.source_lane)?; - if source_dir.exists() { - fs::remove_dir_all(&source_dir) - .with_context(|| format!("remove {}", source_dir.display()))?; - } - fs::create_dir_all(&source_dir).with_context(|| format!("create {}", source_dir.display()))?; - let serializer = ensure_aot_serializer_binary()?; - - for module in outputs.modules.iter().filter(|module| module.requires_aot) { - let output = source_dir.join(&module.aot_file); - generate_one_aot_artifact(&serializer, &module.path, &output)?; - } - Ok(()) -} - -fn is_core_aot_module(name: &str) -> bool { - !name.starts_with("extension:") -} - -pub(crate) fn package_aot_only( - manifest: &SourcesManifest, - target: &str, - source_lane: &str, -) -> Result<()> { - let outputs = BuildOutputs::discover_for_aot(source_lane)?; - package_aot_artifacts(target, &outputs, manifest)?; - check_aot_package_manifest(target, source_lane) -} - -fn ensure_aot_serializer_binary() -> Result { - let mut command = Command::new("cargo"); - command - .args([ - "build", - "-p", - "xtask", - "--release", - "--locked", - "--features", - "aot-serializer", - ]) - .env("CARGO_INCREMENTAL", "0"); - if env::var_os("LLVM_SYS_221_PREFIX").is_none() && Path::new("/opt/homebrew/opt/llvm").exists() - { - command.env("LLVM_SYS_221_PREFIX", "/opt/homebrew/opt/llvm"); - } - configure_windows_llvm_aot_link(&mut command); - run_command(&mut command).context("build maintainer AOT serializer")?; - - let target_dir = env::var_os("CARGO_TARGET_DIR") - .map(PathBuf::from) - .unwrap_or_else(|| PathBuf::from("target")); - let target_dir = if target_dir.is_absolute() { - target_dir - } else { - env::current_dir() - .context("read current directory")? - .join(target_dir) - }; - let serializer = target_dir - .join("release") - .join(format!("xtask{}", env::consts::EXE_SUFFIX)); - ensure_file(&serializer)?; - Ok(serializer) -} - -fn generate_one_aot_artifact(serializer: &Path, input: &Path, output: &Path) -> Result<()> { - ensure_file(input)?; - let input = - fs::canonicalize(input).with_context(|| format!("canonicalize {}", input.display()))?; - let output = if output.is_absolute() { - output.to_path_buf() - } else { - env::current_dir() - .context("read current directory")? - .join(output) - }; - if let Some(parent) = output.parent() { - fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?; - } - - let mut command = Command::new(serializer); - command - .args(["aot-serializer", "serialize", "--input"]) - .arg(&input) - .arg("--output") - .arg(output) - .env("CARGO_INCREMENTAL", "0"); - if env::var_os("LLVM_SYS_221_PREFIX").is_none() && Path::new("/opt/homebrew/opt/llvm").exists() - { - command.env("LLVM_SYS_221_PREFIX", "/opt/homebrew/opt/llvm"); - } - configure_windows_llvm_aot_link(&mut command); - run_command(&mut command) - .with_context(|| format!("generate AOT artifact for {}", input.display())) -} - -fn configure_windows_llvm_aot_link(command: &mut Command) { - if !cfg!(windows) { - return; - } - - let Some(prefix) = env::var_os("LLVM_SYS_221_PREFIX").or_else(|| env::var_os("LLVM_PATH")) - else { - return; - }; - let llvm_lib = PathBuf::from(prefix).join("lib"); - if llvm_lib.is_dir() { - let mut lib = llvm_lib.display().to_string(); - if let Some(existing) = env::var_os("LIB").and_then(|value| value.into_string().ok()) - && !existing.is_empty() - { - lib.push(';'); - lib.push_str(&existing); - } - command.env("LIB", lib); - } -} - -pub(crate) fn package_assets( - manifest: &SourcesManifest, - target: &str, - source_lane: &str, -) -> Result<()> { - package_assets_with_options(manifest, target, true, source_lane) -} - -pub(crate) fn package_assets_without_aot( - manifest: &SourcesManifest, - source_lane: &str, -) -> Result<()> { - package_assets_with_options(manifest, host_target_triple(), false, source_lane) -} - -fn package_assets_with_options( - manifest: &SourcesManifest, - target: &str, - include_aot: bool, - source_lane: &str, -) -> Result<()> { - let outputs = BuildOutputs::discover_for_source_lane(source_lane)?; - outputs.write_manifest()?; - validate_build_output_link_closure(&outputs)?; - let build = &outputs.build_dir; - let source = &outputs.source_dir; - let stage = &outputs.package_stage; - - if stage.exists() { - fs::remove_dir_all(stage).with_context(|| format!("remove {}", stage.display()))?; - } - fs::create_dir_all(stage).with_context(|| format!("create {}", stage.display()))?; - - let runtime_stage = stage.join("runtime/oliphaunt"); - stage_runtime_tree(build, source, &runtime_stage)?; - let assets_dir = generated_assets_dir_for_source_lane(source_lane)?; - if assets_dir.exists() { - fs::remove_dir_all(assets_dir) - .with_context(|| format!("remove {}", assets_dir.display()))?; - } - fs::create_dir_all(assets_dir).with_context(|| format!("create {}", assets_dir.display()))?; - if skip_extensions_for_perf_probe() { - fs::create_dir_all(assets_dir.join("extensions")) - .with_context(|| format!("create {}", assets_dir.join("extensions").display()))?; - } - - let runtime_archive = assets_dir.join("oliphaunt.wasix.tar.zst"); - deterministic_tar_zst(&runtime_stage, Path::new("oliphaunt"), &runtime_archive)?; - - let pg_dump = if skip_extensions_for_perf_probe() { - None - } else { - let pg_dump = assets_dir.join("bin/pg_dump.wasix.wasm"); - copy_file(outputs.module_path("tool:pg_dump")?, &pg_dump)?; - Some(pg_dump) - }; - let psql = if skip_extensions_for_perf_probe() { - None - } else { - let psql = assets_dir.join("bin/psql.wasix.wasm"); - copy_file(outputs.module_path("tool:psql")?, &psql)?; - Some(psql) - }; - let initdb = assets_dir.join("bin/initdb.wasix.wasm"); - copy_file(outputs.module_path("tool:initdb")?, &initdb)?; - - let extension_artifacts = - build_extension_artifacts(source, build, stage, assets_dir, &outputs)?; - let extension_artifact_refs = extension_artifacts - .iter() - .map(|extension| ExtensionArtifact { - name: extension.name.as_str(), - sql_name: extension.sql_name.as_str(), - archive: extension.archive.as_str(), - path: extension.path.as_path(), - module_path: extension.module_path.as_deref(), - native_module: extension.native_module.as_deref(), - native_modules: &extension.native_modules, - }) - .collect::>(); - - if include_aot { - package_aot_artifacts(target, &outputs, manifest)?; - } - generate_cluster_seed_assets_from_runtime_stage( - manifest, - &outputs, - &runtime_stage, - assets_dir, - )?; - write_asset_manifest( - manifest, - &outputs, - assets_dir, - outputs.module_path("runtime:oliphaunt")?, - &runtime_archive, - pg_dump.as_deref(), - psql.as_deref(), - &initdb, - &[ - BinaryPackage { - name: "plpgsql", - path: outputs.module_path("runtime-support:plpgsql")?, - runtime_path: "lib/postgresql/plpgsql.so", - }, - BinaryPackage { - name: "dict_snowball", - path: outputs.module_path("runtime-support:dict_snowball")?, - runtime_path: "lib/postgresql/dict_snowball.so", - }, - ], - &extension_artifact_refs, - )?; - - println!("packaged runtime assets into {}", assets_dir.display()); - if include_aot { - println!("packaged {target} AOT artifacts"); - } else { - println!("skipped {target} AOT artifact packaging by request"); - } - Ok(()) -} - -pub(crate) fn generate_cluster_seed_assets( - manifest: &SourcesManifest, - source_lane: &str, -) -> Result<()> { - let outputs = BuildOutputs::discover_for_source_lane(source_lane)?; - let stage_root = outputs.package_stage.join("cluster-seed-runtime"); - if stage_root.exists() { - fs::remove_dir_all(&stage_root) - .with_context(|| format!("remove {}", stage_root.display()))?; - } - stage_runtime_tree(&outputs.build_dir, &outputs.source_dir, &stage_root)?; - generate_cluster_seed_assets_from_runtime_stage( - manifest, - &outputs, - &stage_root, - generated_assets_dir_for_source_lane(source_lane)?, - ) -} - -fn generate_cluster_seed_assets_from_runtime_stage( - manifest: &SourcesManifest, - outputs: &BuildOutputs, - runtime_stage: &Path, - assets_dir: &Path, -) -> Result<()> { - let output_dir = assets_dir.join("cluster-seeds"); - if output_dir.exists() { - fs::remove_dir_all(&output_dir) - .with_context(|| format!("remove {}", output_dir.display()))?; - } - fs::create_dir_all(&output_dir).with_context(|| format!("create {}", output_dir.display()))?; - - let source_pins = effective_source_pins(manifest, outputs)?; - let source_fingerprint = outputs - .source_fingerprint - .as_deref() - .ok_or_else(|| anyhow!("cluster seeds require an exact PostgreSQL source fingerprint"))?; - let runtime_sha256 = sha256_file(outputs.module_path("runtime:oliphaunt")?)?; - let initdb_sha256 = sha256_file(outputs.module_path("tool:initdb")?)?; - let catalog_version = postgres_catalog_version(&outputs.source_dir)?; - let runtime_version = release_product_version("src/runtimes/liboliphaunt/wasix")?; - let icu_data_root = wasix_icu_data_root()?; - let icu_tree_sha256 = logical_tree_sha256(&icu_data_root)?; - let icu_source = source_pins - .iter() - .find(|source| source.name == "icu") - .ok_or_else(|| anyhow!("WASIX cluster-seed source pins do not contain ICU"))?; - - for profile in cluster_seed_runner::CatalogProfile::ALL { - let work_root = assets_dir.join(format!("cluster-seed-work-{}", profile.as_str())); - if work_root.exists() { - fs::remove_dir_all(&work_root) - .with_context(|| format!("remove {}", work_root.display()))?; - } - fs::create_dir_all(&work_root) - .with_context(|| format!("create {}", work_root.display()))?; - cluster_seed_runner::run_wasix_initdb_cluster_seed( - runtime_stage, - &work_root, - profile, - (profile == cluster_seed_runner::CatalogProfile::Icu) - .then_some(icu_data_root.as_path()), - )?; - - let pgdata = work_root.join("pgdata"); - ensure!( - pgdata.join("PG_VERSION").is_file() && pgdata.join("global/pg_control").is_file(), - "WASIX initdb did not create a complete {} cluster seed at {}", - profile.as_str(), - pgdata.display() - ); - cluster_seed_runner::clean_generated_cluster_seed(&pgdata)?; - - let archive_relative = format!("cluster-seeds/{}.tar.zst", profile.as_str()); - let archive = assets_dir.join(&archive_relative); - deterministic_tar_zst(&pgdata, Path::new(""), &archive)?; - let (expanded_bytes, regular_files, directories) = tree_stats(&pgdata)?; - let icu = (profile == cluster_seed_runner::CatalogProfile::Icu).then(|| { - serde_json::json!({ - "artifactRole": "icu-data", - "upstreamVersion": "76.1", - "sourceCommit": icu_source.commit, - "dataTreeSha256": icu_tree_sha256, - "dataVersion": "76.1", - "dataForm": "files-le" - }) - }); - let seed_manifest = serde_json::json!({ - "schema": "oliphaunt-cluster-seed-v1", - "artifactRole": profile.artifact_role(), - "catalogProfile": profile.as_str(), - "runtime": { - "product": "liboliphaunt-wasix", - "version": runtime_version, - "engineFamily": "wasix", - "physicalFormat": "wasix-pg18-v1", - "postgresMajor": 18, - "compatibilityKey": "wasix-pg18-datum32-v1", - "consumerSha256": runtime_sha256, - "producerSha256": runtime_sha256, - "initdbSha256": initdb_sha256 - }, - "source": { - "fingerprint": source_fingerprint, - "catalogVersion": catalog_version, - "lane": outputs.source_lane, - "producer": "wasix-initdb" - }, - "initProfile": cluster_seed_runner::default_initdb_profile(), - "archive": { - "path": archive_relative, - "sha256": sha256_file(&archive)?, - "compressedBytes": fs::metadata(&archive) - .with_context(|| format!("metadata {}", archive.display()))? - .len(), - "expandedBytes": expanded_bytes, - "regularFiles": regular_files, - "directories": directories - }, - "requiredRuntimeFeatures": if profile == cluster_seed_runner::CatalogProfile::Icu { - vec!["icu"] - } else { - Vec::<&str>::new() - }, - "extensions": { - "selected": Vec::::new(), - "startupConfiguration": Vec::::new() - }, - "icu": icu - }); - let manifest_path = output_dir.join(format!("{}.json", profile.as_str())); - fs::write( - &manifest_path, - format!("{}\n", serde_json::to_string_pretty(&seed_manifest)?), - ) - .with_context(|| format!("write {}", manifest_path.display()))?; - fs::remove_dir_all(&work_root) - .with_context(|| format!("remove {}", work_root.display()))?; - } - Ok(()) -} - -fn build_extension_artifacts( - source: &Path, - build: &Path, - stage: &Path, - assets_dir: &Path, - outputs: &BuildOutputs, -) -> Result> { - if skip_extensions_for_perf_probe() { - return Ok(Vec::new()); - } - - let mut packages = Vec::new(); - for extension in extension_catalog::extension_build_specs()? { - let extension_stage = stage.join("extensions").join(&extension.sql_name); - stage_extension(source, build, &extension, &extension_stage)?; - let archive_path = assets_dir.join(&extension.archive); - deterministic_tar_zst(&extension_stage, Path::new(""), &archive_path)?; - let native_modules = extension_native_module_artifacts(&extension, outputs)?; - packages.push(OwnedExtensionArtifact { - name: extension.display_name, - sql_name: extension.sql_name.clone(), - archive: extension.archive.clone(), - path: archive_path, - module_path: if extension.module_file.is_some() { - Some( - outputs - .module_path(&format!("extension:{}", extension.sql_name))? - .to_path_buf(), - ) - } else { - None - }, - native_module: extension.module_file.clone(), - native_modules, - }); - } - Ok(packages) -} - -fn extension_native_module_artifacts( - extension: &extension_catalog::ExtensionBuildSpec, - outputs: &BuildOutputs, -) -> Result> { - let mut modules = Vec::new(); - for support_module in &extension.native_support_modules { - modules.push(OwnedExtensionNativeModule { - name: support_module.name.clone(), - runtime_path: support_module.runtime_path.clone(), - path: outputs - .module_path(&format!( - "extension:{}:{}", - extension.sql_name, support_module.name - ))? - .to_path_buf(), - }); - } - if let Some(module_file) = &extension.module_file { - modules.push(OwnedExtensionNativeModule { - name: extension.sql_name.clone(), - runtime_path: format!("lib/postgresql/{module_file}"), - path: outputs - .module_path(&format!("extension:{}", extension.sql_name))? - .to_path_buf(), - }); - } - Ok(modules) -} - -fn stage_extension( - source: &Path, - build: &Path, - extension: &extension_catalog::ExtensionBuildSpec, - stage: &Path, -) -> Result<()> { - match extension.build_kind.as_str() { - "postgres-contrib" => stage_contrib_extension(source, build, extension, stage), - kind if extension_catalog::is_pgxs_style_build_kind(kind) => { - stage_pgxs_style_extension(build, extension, stage) - } - kind if extension_catalog::is_recipe_staged_build_kind(kind) => { - stage_recipe_staged_extension(build, extension, stage) - } - other => bail!( - "supported extension {} has unsupported packaging build kind {other}", - extension.sql_name - ), - } -} - -fn stage_recipe_staged_extension( - build: &Path, - extension: &extension_catalog::ExtensionBuildSpec, - stage: &Path, -) -> Result<()> { - let staging = extension - .staging - .as_ref() - .ok_or_else(|| anyhow!("extension {} has no staging metadata", extension.id))?; - let extension_sql_dir = stage.join("share/postgresql/extension"); - let module_dir = stage.join("lib/postgresql"); - fs::create_dir_all(&extension_sql_dir) - .with_context(|| format!("create {}", extension_sql_dir.display()))?; - fs::create_dir_all(&module_dir).with_context(|| format!("create {}", module_dir.display()))?; - - let module_file = extension - .module_file - .as_deref() - .ok_or_else(|| anyhow!("extension {} has no native module file", extension.id))?; - let module_source_dir = staging.module_source_dir.as_deref().ok_or_else(|| { - anyhow!( - "extension {} staging metadata has no module_source_dir", - extension.id - ) - })?; - copy_file( - &build.join(module_source_dir).join(module_file), - &module_dir.join(module_file), - )?; - for support_module in &extension.native_support_modules { - let source = build.join(&support_module.build_path); - ensure!( - source.is_file(), - "extension {} build did not produce support module {}", - extension.id, - source.display() - ); - copy_file(&source, &stage.join(&support_module.runtime_path))?; - } - let control_source = staging.control_source.as_deref().ok_or_else(|| { - anyhow!( - "extension {} staging metadata has no control_source", - extension.id - ) - })?; - let control_source = build.join(control_source); - let control_file_name = control_source.file_name().ok_or_else(|| { - anyhow!( - "control source has no file name: {}", - control_source.display() - ) - })?; - copy_file(&control_source, &extension_sql_dir.join(control_file_name))?; - - let sql_source_dir = staging.sql_source_dir.as_deref().ok_or_else(|| { - anyhow!( - "extension {} staging metadata has no sql_source_dir", - extension.id - ) - })?; - let sql_source_dir = build.join(sql_source_dir); - let copied_sql = copy_extension_sql_dir(&sql_source_dir, &extension_sql_dir)?; - ensure!( - copied_sql, - "extension {} build did not produce extension SQL files under {}", - extension.id, - sql_source_dir.display() - ); - for excluded in &extension.excluded_sql_extensions { - let excluded_control = format!("{excluded}.control"); - ensure!( - !extension_sql_dir.join(&excluded_control).exists(), - "extension {} archive must not include excluded extension control file {excluded_control}", - extension.id - ); - } - for data_dir in &staging.data_dirs { - let source = build.join(&data_dir.source); - ensure!( - source.is_dir(), - "extension {} staging data directory is missing: {}", - extension.id, - source.display() - ); - copy_dir_all(&source, &stage.join(&data_dir.destination))?; - } - Ok(()) -} - -fn stage_pgxs_style_extension( - build: &Path, - extension: &extension_catalog::ExtensionBuildSpec, - stage: &Path, -) -> Result<()> { - let source = Path::new(&extension.source_dir); - let build_dir = pgxs_extension_build_dir(build, extension); - let sql_name = extension.sql_name.as_str(); - let extension_sql_dir = stage.join("share/postgresql/extension"); - fs::create_dir_all(stage.join("share/postgresql/extension")) - .with_context(|| format!("create {}", extension_sql_dir.display()))?; - if let Some(module_file) = &extension.module_file { - fs::create_dir_all(stage.join("lib/postgresql")) - .with_context(|| format!("create {}", stage.join("lib/postgresql").display()))?; - copy_file( - &build_dir.join(module_file), - &stage.join("lib/postgresql").join(module_file), - )?; - } - if extension.lifecycle.create_extension || extension.control_file.is_some() { - let control_file = extension - .control_file - .as_deref() - .map(Path::new) - .filter(|path| path.is_file()) - .map(Path::to_path_buf) - .unwrap_or_else(|| source.join(format!("{sql_name}.control"))); - copy_file( - &control_file, - &stage - .join("share/postgresql/extension") - .join(control_file.file_name().unwrap_or_default()), - )?; - } - let mut copied_root_sql = copy_extension_sql_files(&build_dir, sql_name, &extension_sql_dir)?; - if !copied_root_sql { - copied_root_sql = copy_extension_sql_files(source, sql_name, &extension_sql_dir)?; - } - if !copied_root_sql { - let copied_build_sql_dir = - copy_extension_sql_dir(&build_dir.join("sql"), &extension_sql_dir)?; - if !copied_build_sql_dir { - copy_extension_sql_dir(&source.join("sql"), &extension_sql_dir)?; - } - } - if extension.id == "age" { - let age_sql = extension_sql_dir.join("age--1.7.0.sql"); - let age_sql_text = - fs::read_to_string(&age_sql).with_context(|| format!("read {}", age_sql.display()))?; - ensure!( - age_sql_text.contains("CREATE TYPE graphid"), - "{} must contain AGE graphid type definition", - age_sql.display() - ); - ensure!( - !age_sql_text - .lines() - .any(|line| line.trim() == "PASSEDBYVALUE,"), - "{} still declares graphid PASSEDBYVALUE for wasm32/WASIX; rebuild AGE with SIZEOF_DATUM=4", - age_sql.display() - ); - } - Ok(()) -} - -fn copy_extension_sql_files(source: &Path, sql_name: &str, destination: &Path) -> Result { - if !source.is_dir() { - return Ok(false); - } - let mut copied = false; - for entry in sorted_children(source)? { - if !entry.is_file() { - continue; - } - let Some(name) = entry.file_name().and_then(|name| name.to_str()) else { - continue; - }; - if (name.starts_with(&format!("{sql_name}--")) || name == format!("{sql_name}.sql")) - && name.ends_with(".sql") - { - copy_file(&entry, &destination.join(name))?; - copied = true; - } - } - Ok(copied) -} - -fn copy_extension_sql_dir(source: &Path, destination: &Path) -> Result { - if !source.is_dir() { - return Ok(false); - } - let mut copied = false; - for entry in sorted_files(source)? { - if entry.extension().and_then(|ext| ext.to_str()) != Some("sql") { - continue; - } - let file_name = entry - .file_name() - .ok_or_else(|| anyhow!("SQL file has no name: {}", entry.display()))?; - copy_file(&entry, &destination.join(file_name))?; - copied = true; - } - Ok(copied) -} - -fn stage_contrib_extension( - source: &Path, - build: &Path, - extension: &extension_catalog::ExtensionBuildSpec, - stage: &Path, -) -> Result<()> { - let contrib_dir = extension - .contrib_dir - .as_deref() - .ok_or_else(|| anyhow!("contrib extension {} has no contrib_dir", extension.id))?; - let extension_source = source.join("contrib").join(contrib_dir); - fs::create_dir_all(stage.join("share/postgresql/extension")).with_context(|| { - format!( - "create {}", - stage.join("share/postgresql/extension").display() - ) - })?; - if let Some(module_file) = &extension.module_file { - fs::create_dir_all(stage.join("lib/postgresql")) - .with_context(|| format!("create {}", stage.join("lib/postgresql").display()))?; - copy_file( - &build.join("contrib").join(contrib_dir).join(module_file), - &stage.join("lib/postgresql").join(module_file), - )?; - } - if extension.lifecycle.create_extension || extension.control_file.is_some() { - let control_file = extension_source.join(format!("{}.control", extension.sql_name)); - copy_file( - &control_file, - &stage - .join("share/postgresql/extension") - .join(control_file.file_name().unwrap_or_default()), - )?; - } - for entry in sorted_children(&extension_source)? { - if !entry.is_file() { - continue; - } - let Some(name) = entry.file_name().and_then(|name| name.to_str()) else { - continue; - }; - if (name.starts_with(&format!("{}--", extension.sql_name)) - || name == format!("{}.sql", extension.sql_name)) - && name.ends_with(".sql") - { - copy_file(&entry, &stage.join("share/postgresql/extension").join(name))?; - } else if name.ends_with(".rules") { - let tsearch_data = stage.join("share/postgresql/tsearch_data"); - fs::create_dir_all(&tsearch_data) - .with_context(|| format!("create {}", tsearch_data.display()))?; - copy_file(&entry, &tsearch_data.join(name))?; - } - } - Ok(()) -} - -fn stage_runtime_tree(build: &Path, source: &Path, runtime: &Path) -> Result<()> { - let bin = runtime.join("bin"); - let lib = runtime.join("lib/postgresql"); - let share = runtime.join("share/postgresql"); - fs::create_dir_all(&bin).with_context(|| format!("create {}", bin.display()))?; - fs::create_dir_all(&lib).with_context(|| format!("create {}", lib.display()))?; - fs::create_dir_all(&share).with_context(|| format!("create {}", share.display()))?; - - copy_file(&build.join("src/backend/oliphaunt"), &bin.join("postgres"))?; - copy_file(&build.join("src/bin/initdb/initdb"), &bin.join("initdb"))?; - fs::write(runtime.join("password"), b"password\n") - .with_context(|| format!("write {}", runtime.join("password").display()))?; - - copy_file( - &build.join("src/include/catalog/postgres.bki"), - &share.join("postgres.bki"), - )?; - copy_file( - &build.join("src/include/catalog/system_constraints.sql"), - &share.join("system_constraints.sql"), - )?; - for relative in [ - "src/backend/catalog/system_functions.sql", - "src/backend/catalog/system_views.sql", - "src/backend/catalog/information_schema.sql", - "src/backend/catalog/sql_features.txt", - "src/backend/libpq/pg_hba.conf.sample", - "src/backend/libpq/pg_ident.conf.sample", - "src/backend/utils/misc/postgresql.conf.sample", - ] { - let source_path = source.join(relative); - let file_name = source_path - .file_name() - .ok_or_else(|| anyhow!("source file has no name: {}", source_path.display()))?; - copy_file(&source_path, &share.join(file_name))?; - } - - copy_file( - &build.join("src/backend/snowball/snowball_create.sql"), - &share.join("snowball_create.sql"), - )?; - copy_file( - &build.join("src/backend/snowball/dict_snowball.so"), - &lib.join("dict_snowball.so"), - )?; - copy_file( - &build.join("src/pl/plpgsql/src/plpgsql.so"), - &lib.join("plpgsql.so"), - )?; - - let extension_dir = share.join("extension"); - fs::create_dir_all(&extension_dir) - .with_context(|| format!("create {}", extension_dir.display()))?; - for relative in [ - "src/pl/plpgsql/src/plpgsql.control", - "src/pl/plpgsql/src/plpgsql--1.0.sql", - ] { - let source_path = source.join(relative); - let file_name = source_path - .file_name() - .ok_or_else(|| anyhow!("source file has no name: {}", source_path.display()))?; - copy_file(&source_path, &extension_dir.join(file_name))?; - } - - copy_tree_filtered( - &source.join("src/backend/tsearch/dicts"), - &share.join("tsearch_data"), - None, - )?; - copy_tree_filtered( - &source.join("src/backend/snowball/stopwords"), - &share.join("tsearch_data"), - None, - )?; - copy_tree_filtered( - &source.join("src/timezone/tznames"), - &share.join("timezonesets"), - Some(&["Makefile", "meson.build", "README"]), - )?; - stage_timezone_database(source, build, &share)?; - Ok(()) -} - -fn stage_timezone_database(source: &Path, build: &Path, share: &Path) -> Result<()> { - let tzdata = source.join("src/timezone/data/tzdata.zi"); - ensure_file(&tzdata)?; - let compiled_timezone_dir = build.join("src/timezone/compiled"); - - let timezone_dir = share.join("timezone"); - if timezone_dir.exists() { - fs::remove_dir_all(&timezone_dir) - .with_context(|| format!("remove {}", timezone_dir.display()))?; - } - fs::create_dir_all(&timezone_dir) - .with_context(|| format!("create {}", timezone_dir.display()))?; - copy_tree_filtered(&compiled_timezone_dir, &timezone_dir, None).with_context(|| { - format!( - "copy compiled PostgreSQL timezone database from {}", - compiled_timezone_dir.display() - ) - })?; - - for required in ["UTC", "GMT", "Etc/UTC", "America/New_York"] { - let path = timezone_dir.join(required); - if !path.is_file() { - bail!( - "compiled PostgreSQL timezone database is missing required zone {}", - path.display() - ); - } - } - Ok(()) -} - -fn package_aot_artifacts( - target: &str, - outputs: &BuildOutputs, - sources: &SourcesManifest, -) -> Result<()> { - let source_dir = generated_aot_source_dir_for_source_lane(target, &outputs.source_lane)?; - if !source_dir.exists() { - let source_lane_arg = if outputs.source_lane == DEFAULT_SOURCE_LANE { - String::new() - } else { - format!(" --source-lane {}", outputs.source_lane) - }; - bail!( - "AOT source directory {} is missing; run `cargo run -p xtask -- assets aot --target-triple {target}{source_lane_arg}` before packaging", - source_dir.display() - ); - } - - let artifacts_dir = generated_aot_dir_for_source_lane(target, &outputs.source_lane)?; - if artifacts_dir.exists() { - fs::remove_dir_all(&artifacts_dir) - .with_context(|| format!("remove {}", artifacts_dir.display()))?; - } - fs::create_dir_all(&artifacts_dir) - .with_context(|| format!("create {}", artifacts_dir.display()))?; - - let mut manifest_artifacts = Vec::new(); - for module in outputs - .modules - .iter() - .filter(|module| module.requires_aot && is_core_aot_module(&module.name)) - { - let name = module.name.as_str(); - let file = module.aot_file.as_str(); - let source = source_dir.join(file); - if !source.exists() { - bail!( - "missing AOT artifact {}; run AOT generation for target {target} before packaging", - source.display() - ); - } - let destination = artifacts_dir.join(file); - copy_file(&source, &destination)?; - let raw_artifact = decode_zstd_file(&destination) - .with_context(|| format!("decode AOT artifact {}", destination.display()))?; - let module_sha256 = outputs - .modules - .iter() - .find(|module| module.name == name) - .map(|module| sha256_file(&module.path)) - .transpose()? - .ok_or_else(|| anyhow!("missing build output module {name} for AOT manifest"))?; - manifest_artifacts.push(AotManifestArtifact { - name: name.to_owned(), - path: file.to_owned(), - sha256: sha256_file(&destination)?, - raw_sha256: sha256_bytes(&raw_artifact), - raw_size: raw_artifact.len() as u64, - module_sha256, - compressed: true, - }); - } - ensure!( - !manifest_artifacts.is_empty(), - "AOT packaging produced an empty manifest for {target}" - ); - - let manifest = AotManifest { - format_version: AOT_MANIFEST_FORMAT_VERSION, - source_lane: Some(outputs.source_lane.clone()), - source_fingerprint: outputs.source_fingerprint.clone(), - postgres_version: Some(outputs.postgres_version.clone()), - target_triple: target.to_owned(), - engine: "llvm-opta".to_owned(), - wasmer_version: sources.toolchain.wasmer.clone(), - wasmer_wasix_version: sources.toolchain.wasmer_wasix.clone(), - artifacts: manifest_artifacts, - }; - let manifest_json = - serde_json::to_string_pretty(&manifest).context("serialize AOT manifest")?; - fs::write( - artifacts_dir.join("manifest.json"), - format!("{manifest_json}\n"), - ) - .with_context(|| format!("write {}", artifacts_dir.join("manifest.json").display()))?; - Ok(()) -} - -pub(crate) fn package_extension_aot_artifacts( - sources: &SourcesManifest, - target: &str, - source_lane: &str, -) -> Result<()> { - let outputs = BuildOutputs::discover_for_aot(source_lane)?; - let source_dir = generated_aot_source_dir_for_source_lane(target, &outputs.source_lane)?; - if !source_dir.exists() { - let source_lane_arg = if outputs.source_lane == DEFAULT_SOURCE_LANE { - String::new() - } else { - format!(" --source-lane {}", outputs.source_lane) - }; - bail!( - "AOT source directory {} is missing; run `cargo run -p xtask -- assets aot --target-triple {target}{source_lane_arg}` before packaging extension AOT artifacts", - source_dir.display() - ); - } - - let target_id = aot_target_id_for_triple(target)?; - let artifacts_root = Path::new("target/extensions/wasix/aot-artifacts").join(target_id); - if artifacts_root.exists() { - fs::remove_dir_all(&artifacts_root) - .with_context(|| format!("remove {}", artifacts_root.display()))?; - } - fs::create_dir_all(&artifacts_root) - .with_context(|| format!("create {}", artifacts_root.display()))?; - - let mut grouped: BTreeMap> = BTreeMap::new(); - for module in outputs - .modules - .iter() - .filter(|module| module.requires_aot && !is_core_aot_module(&module.name)) - { - let Some(sql_name) = extension_module_sql_name(&module.name) else { - bail!("extension AOT module has invalid name {}", module.name); - }; - let source = source_dir.join(&module.aot_file); - if !source.exists() { - bail!( - "missing extension AOT artifact {}; run AOT generation for target {target} before packaging", - source.display() - ); - } - let extension_dir = artifacts_root.join(sql_name); - fs::create_dir_all(&extension_dir) - .with_context(|| format!("create {}", extension_dir.display()))?; - let destination = extension_dir.join(&module.aot_file); - copy_file(&source, &destination)?; - let raw_artifact = decode_zstd_file(&destination) - .with_context(|| format!("decode extension AOT artifact {}", destination.display()))?; - grouped - .entry(sql_name.to_owned()) - .or_default() - .push(AotManifestArtifact { - name: module.name.clone(), - path: module.aot_file.clone(), - sha256: sha256_file(&destination)?, - raw_sha256: sha256_bytes(&raw_artifact), - raw_size: raw_artifact.len() as u64, - module_sha256: sha256_file(&module.path)?, - compressed: true, - }); - } - - ensure!( - !grouped.is_empty(), - "extension AOT packaging produced no artifacts for {target}" - ); - - for (sql_name, mut artifacts) in grouped { - artifacts.sort_by(|left, right| left.name.cmp(&right.name)); - let manifest = AotManifest { - format_version: AOT_MANIFEST_FORMAT_VERSION, - source_lane: Some(outputs.source_lane.clone()), - source_fingerprint: outputs.source_fingerprint.clone(), - postgres_version: Some(outputs.postgres_version.clone()), - target_triple: target.to_owned(), - engine: "llvm-opta".to_owned(), - wasmer_version: sources.toolchain.wasmer.clone(), - wasmer_wasix_version: sources.toolchain.wasmer_wasix.clone(), - artifacts, - }; - let manifest_json = - serde_json::to_string_pretty(&manifest).context("serialize extension AOT manifest")?; - let manifest_path = artifacts_root.join(&sql_name).join("manifest.json"); - fs::write(&manifest_path, format!("{manifest_json}\n")) - .with_context(|| format!("write {}", manifest_path.display()))?; - } - Ok(()) -} - -pub(crate) fn check_aot_package_manifest(target: &str, source_lane: &str) -> Result<()> { - let sources = load_wasix_toolchain_manifest()?; - let outputs = BuildOutputs::discover_for_aot(source_lane)?; - let artifacts_dir = find_aot_artifact_dir_for_source_lane(target, &outputs.source_lane)?; - let manifest_path = artifacts_dir.join("manifest.json"); - ensure_file(&manifest_path)?; - let text = fs::read_to_string(&manifest_path) - .with_context(|| format!("read {}", manifest_path.display()))?; - let manifest: AotManifest = serde_json::from_str(&text) - .with_context(|| format!("parse {}", manifest_path.display()))?; - ensure!( - manifest.format_version == AOT_MANIFEST_FORMAT_VERSION, - "AOT manifest format-version must be {AOT_MANIFEST_FORMAT_VERSION}, got {}", - manifest.format_version - ); - let actual_lane = manifest.source_lane.as_deref().unwrap_or(""); - ensure_eq( - actual_lane, - outputs.source_lane.as_str(), - "AOT manifest source-lane", - )?; - if let Some(source_fingerprint) = outputs.source_fingerprint.as_deref() { - ensure_eq( - manifest - .source_fingerprint - .as_deref() - .unwrap_or(""), - source_fingerprint, - "AOT manifest source-fingerprint", - )?; - } - if let Some(postgres_version) = manifest.postgres_version.as_deref() { - ensure_eq( - postgres_version, - outputs.postgres_version.as_str(), - "AOT manifest postgres-version", - )?; - } - ensure_eq( - &manifest.target_triple, - target, - "AOT manifest target-triple", - )?; - ensure_eq(&manifest.engine, "llvm-opta", "AOT manifest engine")?; - ensure_eq( - &manifest.wasmer_version, - &sources.toolchain.wasmer, - "AOT manifest wasmer-version", - )?; - ensure_eq( - &manifest.wasmer_wasix_version, - &sources.toolchain.wasmer_wasix, - "AOT manifest wasmer-wasix-version", - )?; - ensure!( - !manifest.artifacts.is_empty(), - "AOT manifest {} contains no artifacts", - manifest_path.display() - ); - - for artifact in &manifest.artifacts { - let artifact_relative_path = Path::new(&artifact.path); - ensure!( - artifact_relative_path.is_relative() - && artifact_relative_path - .components() - .all(|component| matches!(component, std::path::Component::Normal(_))), - "AOT artifact {} path must be a simple relative file path, got {}", - artifact.name, - artifact.path - ); - let path = artifacts_dir.join(&artifact.path); - ensure_file(&path)?; - let actual_hash = sha256_file(&path)?; - ensure_eq( - &actual_hash, - &artifact.sha256, - &format!("AOT artifact {} sha256", artifact.name), - )?; - if artifact.compressed { - let raw = decode_zstd_file(&path) - .with_context(|| format!("decode AOT artifact {}", path.display()))?; - ensure_eq( - &sha256_bytes(&raw), - &artifact.raw_sha256, - &format!("AOT artifact {} raw sha256", artifact.name), - )?; - let actual_raw_size = raw.len() as u64; - if actual_raw_size != artifact.raw_size { - bail!( - "AOT artifact {} raw size mismatch: expected {} got {}", - artifact.name, - artifact.raw_size, - actual_raw_size - ); - } - } - let module = outputs - .modules - .iter() - .find(|module| module.name == artifact.name) - .ok_or_else(|| anyhow!("AOT manifest references unknown module {}", artifact.name))?; - ensure!( - module.requires_aot, - "AOT manifest references non-release-AOT module {}", - artifact.name - ); - ensure!( - is_core_aot_module(&artifact.name), - "core AOT manifest must not reference extension module {}", - artifact.name - ); - let module_hash = sha256_file(&module.path)?; - ensure_eq( - &module_hash, - &artifact.module_sha256, - &format!("AOT artifact {} source module sha256", artifact.name), - )?; - } - let expected = outputs - .modules - .iter() - .filter(|module| module.requires_aot && is_core_aot_module(&module.name)) - .map(|module| module.name.as_str()) - .collect::>(); - let actual = manifest - .artifacts - .iter() - .map(|artifact| artifact.name.as_str()) - .collect::>(); - ensure!( - actual == expected, - "AOT manifest module set mismatch: expected {expected:?} got {actual:?}" - ); - let expected_files = manifest - .artifacts - .iter() - .map(|artifact| artifact.path.as_str()) - .collect::>(); - let actual_files = sorted_files(&artifacts_dir)? - .into_iter() - .map(|path| { - path.strip_prefix(&artifacts_dir) - .with_context(|| { - format!("strip {} from {}", artifacts_dir.display(), path.display()) - }) - .and_then(|relative| { - relative.to_str().map(str::to_owned).ok_or_else(|| { - anyhow!("AOT artifact path is not UTF-8: {}", path.display()) - }) - }) - }) - .collect::>>()?; - let mut expected_package_files = expected_files - .into_iter() - .map(str::to_owned) - .collect::>(); - expected_package_files.insert("manifest.json".to_owned()); - ensure!( - actual_files == expected_package_files, - "AOT artifact file set mismatch: expected {expected_package_files:?} got {actual_files:?}" - ); - Ok(()) -} - -pub(crate) fn generated_aot_dir(target: &str) -> PathBuf { - Path::new(GENERATED_AOT_DIR).join(target) -} - -fn crate_aot_artifact_dir(target: &str) -> PathBuf { - Path::new("src/runtimes/liboliphaunt/wasix/crates/aot") - .join(target) - .join("artifacts") -} - -pub(crate) fn find_aot_artifact_dir(target: &str) -> Result { - find_aot_artifact_dir_for_source_lane(target, DEFAULT_SOURCE_LANE) -} - -fn find_aot_artifact_dir_for_source_lane(target: &str, source_lane: &str) -> Result { - let generated = generated_aot_dir_for_source_lane(target, source_lane)?; - if generated.join("manifest.json").is_file() { - return Ok(generated); - } - let crate_dir = crate_aot_artifact_dir(target); - if crate_dir.join("manifest.json").is_file() { - return Ok(crate_dir); - } - bail!( - "missing AOT artifacts for {target}; expected {} or {}", - generated.display(), - crate_dir.display() - ) -} - -#[allow(clippy::too_many_arguments)] // Each parameter is a distinct frozen asset-manifest input. -fn write_asset_manifest( - sources: &SourcesManifest, - outputs: &BuildOutputs, - assets_dir: &Path, - runtime_module: &Path, - runtime_archive: &Path, - pg_dump: Option<&Path>, - psql: Option<&Path>, - initdb: &Path, - runtime_support: &[BinaryPackage<'_>], - extensions: &[ExtensionArtifact<'_>], -) -> Result<()> { - let runtime_link = read_wasm_link_metadata(runtime_module)?; - let extension_metadata = extension_catalog::manifest_metadata_by_sql_name()?; - let effective_sources = effective_source_pins(sources, outputs)?; - let manifest = AssetManifestOut { - format_version: ASSET_MANIFEST_FORMAT_VERSION, - source_lane: Some(outputs.source_lane.clone()), - source_fingerprint: outputs.source_fingerprint.clone(), - runtime: RuntimeAssetOut { - archive: "oliphaunt.wasix.tar.zst".to_owned(), - sha256: sha256_file(runtime_archive)?, - module_sha256: sha256_file(runtime_module)?, - postgres_version: outputs.postgres_version.clone(), - runtime_kind: "wasix-dynamic-main".to_owned(), - link: runtime_link.clone(), - }, - runtime_support: runtime_support - .iter() - .map(|module| { - Ok::<_, anyhow::Error>(BinaryAssetOut { - name: module.name.to_owned(), - path: module.runtime_path.to_owned(), - sha256: sha256_file(module.path)?, - module_sha256: sha256_file(module.path)?, - size: fs::metadata(module.path) - .with_context(|| format!("metadata {}", module.path.display()))? - .len(), - link: read_wasm_link_metadata(module.path)?, - }) - }) - .collect::>>()?, - pg_dump: pg_dump - .map(|pg_dump| { - Ok::<_, anyhow::Error>(BinaryAssetOut { - name: "pg_dump".to_owned(), - path: "bin/pg_dump.wasix.wasm".to_owned(), - sha256: sha256_file(pg_dump)?, - module_sha256: sha256_file(pg_dump)?, - size: fs::metadata(pg_dump) - .with_context(|| format!("metadata {}", pg_dump.display()))? - .len(), - link: read_wasm_link_metadata(pg_dump)?, - }) - }) - .transpose()?, - psql: psql - .map(|psql| { - Ok::<_, anyhow::Error>(BinaryAssetOut { - name: "psql".to_owned(), - path: "bin/psql.wasix.wasm".to_owned(), - sha256: sha256_file(psql)?, - module_sha256: sha256_file(psql)?, - size: fs::metadata(psql) - .with_context(|| format!("metadata {}", psql.display()))? - .len(), - link: read_wasm_link_metadata(psql)?, - }) - }) - .transpose()?, - initdb: Some(BinaryAssetOut { - name: "initdb".to_owned(), - path: "bin/initdb.wasix.wasm".to_owned(), - sha256: sha256_file(initdb)?, - module_sha256: sha256_file(initdb)?, - size: fs::metadata(initdb) - .with_context(|| format!("metadata {}", initdb.display()))? - .len(), - link: read_wasm_link_metadata(initdb)?, - }), - cluster_seeds: cluster_seed_runner::CatalogProfile::ALL - .into_iter() - .map(|profile| { - cluster_seed_asset_out( - sources, - outputs, - runtime_module, - initdb, - assets_dir, - profile, - ) - .map(|asset| (profile.as_str().to_owned(), asset)) - }) - .collect::>>()?, - extensions: extensions - .iter() - .map(|extension| { - let link = extension - .module_path - .map(read_wasm_link_metadata) - .transpose()?; - let native_module_links = extension - .native_modules - .iter() - .map(|module| { - Ok::<_, anyhow::Error>(( - module.name.clone(), - read_wasm_link_metadata(&module.path)?, - )) - }) - .collect::>>()?; - let metadata = extension_metadata.get(extension.sql_name).ok_or_else(|| { - anyhow!( - "extension {} is missing from generated extension catalog", - extension.sql_name - ) - })?; - let mut core_exports_required = Vec::new(); - let mut unresolved_imports = Vec::new(); - if let Some(link) = &link { - let primary_path = extension.module_path.ok_or_else(|| { - anyhow!( - "extension {} has link metadata without a module", - extension.sql_name - ) - })?; - let module_exports = extension_asset_provider_exports( - link, - primary_path, - extension.sql_name, - extension.native_modules, - &native_module_links, - )?; - for import in &link.imports { - if !import_should_resolve_from_runtime(import) { - continue; - } - if import_resolves_from_wasm_exports( - import, - &module_exports, - extension.sql_name, - )? { - continue; - } - if let Some(name) = - resolved_wasm_export_name(import, &runtime_link.exports, "runtime")? - { - core_exports_required.push(name); - } else { - unresolved_imports.push(import.clone()); - } - } - } - core_exports_required.sort(); - core_exports_required.dedup(); - let installed_files = archive_file_list(extension.path)?; - let control_files = extension_control_files_for_asset_manifest( - outputs.source_lane.as_str(), - metadata, - &installed_files, - extension.sql_name, - )?; - let native_modules = extension - .native_modules - .iter() - .map(|module| { - let link = native_module_links - .get(&module.name) - .cloned() - .ok_or_else(|| anyhow!("missing link metadata for {}", module.name))?; - Ok::<_, anyhow::Error>(BinaryAssetOut { - name: module.name.clone(), - path: module.runtime_path.clone(), - sha256: sha256_file(&module.path)?, - module_sha256: sha256_file(&module.path)?, - size: fs::metadata(&module.path) - .with_context(|| format!("metadata {}", module.path.display()))? - .len(), - link, - }) - }) - .collect::>>()?; - Ok(ExtensionAssetOut { - name: extension.name.to_owned(), - sql_name: extension.sql_name.to_owned(), - source_kind: metadata.source_kind.clone(), - archive: extension.archive.to_owned(), - sha256: sha256_file(extension.path)?, - module_sha256: extension - .module_path - .map(sha256_file) - .transpose()? - .unwrap_or_default(), - native_module: extension.native_module.map(str::to_owned), - native_modules, - size: fs::metadata(extension.path) - .with_context(|| format!("metadata {}", extension.path.display()))? - .len(), - control_files, - dependencies: metadata.dependencies.clone(), - load_order: metadata.load_order.clone(), - lifecycle: ExtensionLifecycleOut { - create_extension: metadata.lifecycle.create_extension, - create_schema: metadata.lifecycle.create_schema.clone(), - load_sql: metadata.lifecycle.load_sql.clone(), - post_create_sql: metadata.lifecycle.post_create_sql.clone(), - startup_config: metadata.lifecycle.startup_config.clone(), - preload_required: metadata.lifecycle.preload_required, - restart_required: metadata.lifecycle.restart_required, - shared_memory_required: metadata.lifecycle.shared_memory_required, - }, - extension_imports: link - .as_ref() - .map(|link| link.imports.clone()) - .unwrap_or_default(), - core_exports_required, - unresolved_imports, - installed_files, - link, - }) - }) - .collect::>>()?, - sources: effective_sources, - }; - - let text = serde_json::to_string_pretty(&manifest).context("serialize asset manifest")?; - let manifest_path = assets_dir.join("manifest.json"); - fs::write(&manifest_path, format!("{text}\n")) - .with_context(|| format!("write {}", manifest_path.display()))?; - Ok(()) -} - -fn extension_control_files_for_asset_manifest( - source_lane: &str, - metadata: &extension_catalog::ManifestExtensionMetadata, - installed_files: &[String], - sql_name: &str, -) -> Result> { - ensure_eq( - canonical_source_lane(source_lane)?, - DEFAULT_SOURCE_LANE, - "extension manifest source lane", - )?; - - let mut control_files = installed_files - .iter() - .filter(|path| { - path.starts_with("share/postgresql/extension/") && path.ends_with(".control") - }) - .cloned() - .collect::>(); - control_files.sort(); - control_files.dedup(); - if metadata.lifecycle.create_extension || !metadata.control_files.is_empty() { - ensure!( - !control_files.is_empty(), - "PG18 extension {sql_name} manifest control-files must come from packaged extension archive contents" - ); - } - ensure!( - control_files - .iter() - .all(|path| !path.contains("removed-fork")), - "PG18 extension {sql_name} manifest control-files must not reference removed source paths" - ); - Ok(control_files) -} - -#[allow(clippy::items_after_test_module)] // Later helpers are shared by production and these focused tests. -#[cfg(test)] -mod tests { - use super::*; - - fn test_binary_asset(name: &str, path: &str, sha256: &str, size: u64) -> BinaryAssetOut { - BinaryAssetOut { - name: name.to_owned(), - path: path.to_owned(), - sha256: sha256.to_owned(), - module_sha256: sha256.to_owned(), - size, - link: WasmLinkMetadataOut { - has_dylink0: false, - dylink_needed: Vec::new(), - dylink_runtime_paths: Vec::new(), - dylink_memory: None, - dylink_imports: Vec::new(), - dylink_exports: Vec::new(), - imports: Vec::new(), - exports: Vec::new(), - memories: Vec::new(), - }, - } - } - - #[test] - fn wasix_tools_npm_descriptor_metadata_is_updated_together() { - let pg_dump = test_binary_asset( - "pg_dump", - "bin/pg_dump.wasix.wasm", - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - 1_234, - ); - let psql = test_binary_asset( - "psql", - "bin/psql.wasix.wasm", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - 5_678, - ); - let original = concat!( - "// Preserve the workspace descriptor around its generated rows.\n", - "export default Object.freeze({\n", - " pgDump: Object.freeze({\n", - " name: 'pg_dump',\n", - " sha256: 'old-pg-dump',\n", - " size: 12,\n", - " source: new URL('pg_dump.wasix.wasm', import.meta.url).href,\n", - " }),\n", - " psql: Object.freeze({\n", - " name: 'psql',\n", - " sha256: 'old-psql',\n", - " size: 34,\n", - " source: new URL('psql.wasix.wasm', import.meta.url).href,\n", - " }),\n", - "});\n", - ); - - let updated = update_wasix_tools_npm_descriptor_rows(original, &pg_dump, &psql) - .expect("update descriptor metadata"); - - assert!(updated.starts_with("// Preserve the workspace descriptor")); - assert!(updated.contains( - "sha256: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',\n size: 1234,\n source: new URL('pg_dump.wasix.wasm'" - )); - assert!(updated.contains( - "sha256: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',\n size: 5678,\n source: new URL('psql.wasix.wasm'" - )); - assert_eq!(updated.matches("sha256:").count(), 2); - assert_eq!(updated.matches("size:").count(), 2); - assert!(updated.ends_with("});\n")); - assert_eq!( - update_wasix_tools_npm_descriptor_rows(&updated, &pg_dump, &psql) - .expect("update already-current descriptor"), - updated - ); - } - - #[test] - fn wasix_icu_data_uses_the_canonical_work_root() { - assert_eq!( - wasix_icu_data_path(), - Path::new(WASIX_GENERATED_WORK_DIR).join("icu-wasix/share/icu") - ); - assert!(!wasix_icu_data_path().starts_with(WASIX_POSTGRES_GENERATED_BUILD_DIR)); - } - - #[test] - fn wasix_icu_identity_rejects_install_scaffolding() -> Result<()> { - let now = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .expect("system time") - .as_nanos(); - let root = std::env::temp_dir().join(format!( - "oliphaunt-wasix-icu-identity-{}-{now}", - std::process::id() - )); - fs::create_dir_all(root.join("icudt76l/coll"))?; - fs::write(root.join("icudt76l/root.res"), b"root")?; - fs::write(root.join("icudt76l/coll/en.res"), b"en")?; - validate_canonical_wasix_icu_data_root(&root)?; - - fs::create_dir_all(root.join("76.1/config"))?; - fs::write(root.join("76.1/config/mh-linux"), b"build-only")?; - let error = validate_canonical_wasix_icu_data_root(&root) - .expect_err("install scaffolding must not enter the logical ICU identity"); - assert!(error.to_string().contains("only canonical icudt")); - fs::remove_dir_all(root)?; - Ok(()) - } - - fn manifest_extension_metadata( - create_extension: bool, - control_files: Vec<&str>, - ) -> extension_catalog::ManifestExtensionMetadata { - extension_catalog::ManifestExtensionMetadata { - source_kind: "postgres-contrib".to_owned(), - control_files: control_files.into_iter().map(str::to_owned).collect(), - dependencies: Vec::new(), - load_order: Vec::new(), - lifecycle: extension_catalog::ManifestExtensionLifecycle { - create_extension, - create_schema: None, - load_sql: Vec::new(), - post_create_sql: Vec::new(), - startup_config: Vec::new(), - preload_required: false, - restart_required: false, - shared_memory_required: false, - }, - } - } - - #[test] - fn pg18_lane_uses_packaged_control_files() { - let metadata = manifest_extension_metadata( - true, - vec!["target/oliphaunt-sources/checkouts/removed-fork/contrib/pg_trgm/pg_trgm.control"], - ); - let installed_files = vec![ - "share/postgresql/extension/pg_trgm.control".to_owned(), - "share/postgresql/extension/pg_trgm--1.6.sql".to_owned(), - "share/postgresql/extension/pg_trgm.control".to_owned(), - ]; - - let control_files = extension_control_files_for_asset_manifest( - "stable", - &metadata, - &installed_files, - "pg_trgm", - ) - .expect("PG18 packaged control files"); - - assert_eq!( - control_files, - vec!["share/postgresql/extension/pg_trgm.control"] - ); - } - - #[test] - fn legacy_pg17_lane_is_not_selectable_for_control_files() { - let metadata = manifest_extension_metadata( - true, - vec!["target/oliphaunt-sources/checkouts/removed-fork/contrib/pg_trgm/pg_trgm.control"], - ); - let installed_files = vec!["share/postgresql/extension/pg_trgm.control".to_owned()]; - - let error = extension_control_files_for_asset_manifest( - "pg17", - &metadata, - &installed_files, - "pg_trgm", - ) - .expect_err("PG17 lane must no longer be selectable"); - - assert!( - error - .to_string() - .contains("unsupported WASIX asset source lane") - ); - } - - #[test] - fn pg18_lane_requires_packaged_control_files_for_create_extension() { - let metadata = manifest_extension_metadata( - true, - vec!["target/oliphaunt-sources/checkouts/removed-fork/contrib/pg_trgm/pg_trgm.control"], - ); - let error = extension_control_files_for_asset_manifest("stable", &metadata, &[], "pg_trgm") - .expect_err("PG18 missing packaged control file should fail"); - - assert!( - error - .to_string() - .contains("must come from packaged extension archive contents") - ); - } - - #[test] - fn pg18_lane_rejects_released_control_paths() { - let metadata = manifest_extension_metadata(true, Vec::new()); - let installed_files = - vec!["share/postgresql/extension/removed-fork-leak.control".to_owned()]; - let error = extension_control_files_for_asset_manifest( - "stable", - &metadata, - &installed_files, - "pg_trgm", - ) - .expect_err("PG18 released path leak should fail"); - - assert!( - error - .to_string() - .contains("must not reference removed source paths") - ); - } - - fn temp_aot_manifest_path(label: &str) -> PathBuf { - let now = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .expect("system time") - .as_nanos(); - std::env::temp_dir().join(format!( - "oliphaunt-xtask-aot-manifest-{}-{now}-{label}.json", - std::process::id() - )) - } - - fn write_downloaded_aot_manifest( - path: &Path, - source_lane: Option<&str>, - source_fingerprint: Option<&str>, - postgres_version: Option<&str>, - ) { - let manifest = AotManifest { - format_version: AOT_MANIFEST_FORMAT_VERSION, - source_lane: source_lane.map(str::to_owned), - source_fingerprint: source_fingerprint.map(str::to_owned), - postgres_version: postgres_version.map(str::to_owned), - target_triple: "aarch64-apple-darwin".to_owned(), - engine: "llvm-opta".to_owned(), - wasmer_version: "7.2.1".to_owned(), - wasmer_wasix_version: "0.702.1".to_owned(), - artifacts: vec![AotManifestArtifact { - name: "runtime:oliphaunt".to_owned(), - path: "oliphaunt.aot.zst".to_owned(), - sha256: "archive".to_owned(), - raw_sha256: "raw".to_owned(), - raw_size: 1, - module_sha256: "module".to_owned(), - compressed: true, - }], - }; - fs::write( - path, - serde_json::to_string(&manifest).expect("serialize AOT manifest"), - ) - .expect("write AOT manifest"); - } - - #[test] - fn downloaded_stable_pg18_aot_manifest_is_validated_before_install() { - let path = temp_aot_manifest_path("pg18-ok"); - let fingerprint = expected_postgres_source_fingerprint().expect("PG18 fingerprint"); - write_downloaded_aot_manifest( - &path, - Some("stable"), - Some(&fingerprint), - Some("18.4-wasix-oliphaunt"), - ); - - ensure_aot_manifest_matches_source_lane(&path, "aarch64-apple-darwin", DEFAULT_SOURCE_LANE) - .expect("stable downloaded AOT manifest"); - - let _ = fs::remove_file(path); - } - - #[test] - fn downloaded_stable_pg18_aot_manifest_requires_source_fingerprint() { - let path = temp_aot_manifest_path("pg18-missing-fingerprint"); - write_downloaded_aot_manifest(&path, Some("stable"), None, Some("18.4-wasix-oliphaunt")); - - let error = ensure_aot_manifest_matches_source_lane( - &path, - "aarch64-apple-darwin", - DEFAULT_SOURCE_LANE, - ) - .expect_err("PG18 downloaded AOT manifest should require source fingerprint"); - - assert!( - error - .to_string() - .contains("PG18 AOT manifest source-fingerprint") - ); - let _ = fs::remove_file(path); - } - - #[test] - fn downloaded_stable_aot_manifest_rejects_noncanonical_format_version() { - let path = temp_aot_manifest_path("wrong-format-version"); - let fingerprint = expected_postgres_source_fingerprint().expect("PG18 fingerprint"); - write_downloaded_aot_manifest( - &path, - Some("stable"), - Some(&fingerprint), - Some("18.4-wasix-oliphaunt"), - ); - let mut manifest: AotManifest = - serde_json::from_str(&fs::read_to_string(&path).expect("read AOT manifest")) - .expect("parse AOT manifest"); - manifest.format_version = AOT_MANIFEST_FORMAT_VERSION + 1; - fs::write( - &path, - serde_json::to_string(&manifest).expect("serialize AOT manifest"), - ) - .expect("write AOT manifest"); - - let error = ensure_aot_manifest_matches_source_lane( - &path, - "aarch64-apple-darwin", - DEFAULT_SOURCE_LANE, - ) - .expect_err("downloaded AOT manifest with a noncanonical format version should fail"); - - assert!( - error.to_string().contains("AOT manifest format-version"), - "unexpected validation error: {error:#}" - ); - let _ = fs::remove_file(path); - } - - #[test] - fn downloaded_stable_aot_manifest_rejects_stale_wasmer_metadata() { - let path = temp_aot_manifest_path("stale-wasmer"); - let fingerprint = expected_postgres_source_fingerprint().expect("PG18 fingerprint"); - write_downloaded_aot_manifest( - &path, - Some("stable"), - Some(&fingerprint), - Some("18.4-wasix-oliphaunt"), - ); - let mut manifest: AotManifest = - serde_json::from_str(&fs::read_to_string(&path).expect("read AOT manifest")) - .expect("parse AOT manifest"); - manifest.wasmer_version = "7.2.1-alpha.3".to_owned(); - manifest.wasmer_wasix_version = "0.702.1-alpha.3".to_owned(); - fs::write( - &path, - serde_json::to_string(&manifest).expect("serialize AOT manifest"), - ) - .expect("write AOT manifest"); - - let error = ensure_aot_manifest_matches_source_lane( - &path, - "aarch64-apple-darwin", - DEFAULT_SOURCE_LANE, - ) - .expect_err("downloaded AOT manifest with stale Wasmer metadata should fail"); - - let error = format!("{error:#}"); - assert!( - error.contains("AOT manifest wasmer-version"), - "unexpected validation error: {error}" - ); - let _ = fs::remove_file(path); - } - - fn wasm_import(module: &str, name: &str, kind: &str) -> WasmImportOut { - WasmImportOut { - module: module.to_owned(), - name: name.to_owned(), - kind: kind.to_owned(), - } - } - - fn wasm_export(name: &str, kind: &str) -> WasmExportOut { - WasmExportOut { - name: name.to_owned(), - kind: kind.to_owned(), - } - } - - #[test] - fn wasix_linker_provided_imports_do_not_require_runtime_exports() { - for import in [ - wasm_import("env", "memory", "memory"), - wasm_import("env", "__indirect_function_table", "table"), - wasm_import("env", "__stack_pointer", "global"), - wasm_import("env", "__c_longjmp", "tag"), - wasm_import("env", "__cpp_exception", "tag"), - wasm_import("env", "__memory_base", "global"), - wasm_import("env", "__table_base", "global"), - wasm_import("GOT.mem", "__heap_base", "global"), - wasm_import("GOT.mem", "__stack_high", "global"), - wasm_import("GOT.mem", "__stack_low", "global"), - ] { - assert!( - !import_should_resolve_from_runtime(&import), - "{import:?} should be provided by the WASIX dynamic linker" - ); - } - } - - #[test] - fn single_backend_runtime_rejects_thread_creation_imports() { - for import in [ - wasm_import("wasi", "thread-spawn", "func"), - wasm_import("wasix_32v1", "thread_spawn_v2", "func"), - wasm_import("env", "__pthread_create", "func"), - ] { - assert!(is_thread_spawn_import(&import), "{import:?}"); - } - - for import in [ - wasm_import("wasix_32v1", "thread_exit", "func"), - wasm_import("wasix_32v1", "thread_signal", "func"), - wasm_import("wasix_32v1", "thread_parallelism", "func"), - ] { - assert!(!is_thread_spawn_import(&import), "{import:?}"); - } - } - - #[test] - fn side_module_exports_satisfy_their_own_dynamic_symbol_imports() { - let module_exports = vec![ - wasm_export("GEOSArea_r", "func"), - wasm_export("_ZN10FlatGeobuf11PackedRTree4initEt", "func"), - wasm_export("ZN10FlatGeobuf11PackedRTree4initEt", "func"), - ]; - - for import in [ - wasm_import("env", "GEOSArea_r", "func"), - wasm_import("GOT.func", "_ZN10FlatGeobuf11PackedRTree4initEt", "global"), - wasm_import("GOT.func", "ZN10FlatGeobuf11PackedRTree4initEt", "global"), - ] { - assert!(import_should_resolve_from_runtime(&import)); - assert!( - import_resolves_from_wasm_exports(&import, &module_exports, "test module") - .expect("valid typed provider"), - "{import:?} should be self-resolved by the linked side module" - ); - } - } - - #[test] - fn new_extension_imports_extend_the_sealed_runtime_policy() { - let runtime_import = wasm_import("env", "SearchSysCache1", "func"); - let module_exports = vec![wasm_export("GEOSArea_r", "func")]; - - assert!(import_should_resolve_from_runtime(&runtime_import)); - assert!( - !import_resolves_from_wasm_exports(&runtime_import, &module_exports, "test module") - .expect("absent export") - ); - assert_eq!( - runtime_export_name_for_side_import(&runtime_import), - "SearchSysCache1" - ); - } - - #[test] - fn side_module_provider_kinds_must_match_dynamic_imports() { - let error = import_resolves_from_wasm_exports( - &wasm_import("GOT.func", "SearchSysCache1", "global"), - &[wasm_export("SearchSysCache1", "global")], - "test module", - ) - .expect_err("function-address imports must resolve to functions"); - assert!(error.to_string().contains("expected func")); - } - - #[test] - fn side_module_providers_follow_declared_dynamic_dependencies() { - let root = WasmLinkMetadataOut { - dylink_needed: vec!["declared.so".to_owned()], - exports: vec![wasm_export("root_symbol", "func")], - ..Default::default() - }; - let declared = WasmLinkMetadataOut { - exports: vec![wasm_export("declared_symbol", "func")], - ..Default::default() - }; - let undeclared = WasmLinkMetadataOut { - exports: vec![wasm_export("undeclared_symbol", "func")], - ..Default::default() - }; - let links = BTreeMap::from([ - ("extension:test".to_owned(), root), - ("extension:test:declared".to_owned(), declared), - ("extension:test:undeclared".to_owned(), undeclared), - ]); - let basenames = BTreeMap::from([ - ("root.so".to_owned(), "extension:test".to_owned()), - ( - "declared.so".to_owned(), - "extension:test:declared".to_owned(), - ), - ( - "undeclared.so".to_owned(), - "extension:test:undeclared".to_owned(), - ), - ]); - - let exports = side_module_provider_exports("extension:test", &links, &basenames) - .expect("declared provider graph"); - assert!( - import_resolves_from_wasm_exports( - &wasm_import("env", "declared_symbol", "func"), - &exports, - "test graph", - ) - .expect("declared provider") - ); - assert!( - !import_resolves_from_wasm_exports( - &wasm_import("env", "undeclared_symbol", "func"), - &exports, - "test graph", - ) - .expect("undeclared provider") - ); - } - - #[test] - fn sealed_runtime_export_policy_requires_exact_surface() { - let expected = BTreeSet::from(["_start".to_owned(), "runtime_abi".to_owned()]); - ensure_exact_runtime_export_surface(&expected, &expected).expect("exact export surface"); - - let error = ensure_exact_runtime_export_surface( - &BTreeSet::from(["_start".to_owned(), "ambient".to_owned()]), - &expected, - ) - .expect_err("ambient export must fail"); - let message = error.to_string(); - assert!(message.contains("runtime_abi")); - assert!(message.contains("ambient")); - } -} - -fn cluster_seed_asset_out( - sources: &SourcesManifest, - outputs: &BuildOutputs, - runtime_module: &Path, - initdb_module: &Path, - assets_dir: &Path, - profile: cluster_seed_runner::CatalogProfile, -) -> Result { - let archive_relative = format!("cluster-seeds/{}.tar.zst", profile.as_str()); - let manifest_relative = format!("cluster-seeds/{}.json", profile.as_str()); - let archive = assets_dir.join(&archive_relative); - let manifest = assets_dir.join(&manifest_relative); - ensure_file(&archive)?; - ensure_file(&manifest)?; - let manifest_text = - fs::read_to_string(&manifest).with_context(|| format!("read {}", manifest.display()))?; - let manifest_json: serde_json::Value = serde_json::from_str(&manifest_text) - .with_context(|| format!("parse {}", manifest.display()))?; - let seed_source = manifest_json - .get("source") - .and_then(serde_json::Value::as_object) - .ok_or_else(|| anyhow!("{} is missing source identity", manifest.display()))?; - let seed_runtime = manifest_json - .get("runtime") - .and_then(serde_json::Value::as_object) - .ok_or_else(|| anyhow!("{} is missing runtime identity", manifest.display()))?; - let seed_source_lane = seed_source - .get("lane") - .and_then(serde_json::Value::as_str) - .unwrap_or(""); - ensure_eq( - seed_source_lane, - outputs.source_lane.as_str(), - "cluster seed manifest source.lane", - )?; - if let Some(source_fingerprint) = outputs.source_fingerprint.as_deref() { - let seed_source_fingerprint = seed_source - .get("fingerprint") - .and_then(serde_json::Value::as_str) - .unwrap_or(""); - ensure_eq( - seed_source_fingerprint, - source_fingerprint, - "cluster seed manifest source.fingerprint", - )?; - } - ensure_eq( - manifest_json - .get("catalogProfile") - .and_then(serde_json::Value::as_str) - .unwrap_or(""), - profile.as_str(), - "cluster seed manifest catalogProfile", - )?; - ensure_eq( - manifest_json - .get("artifactRole") - .and_then(serde_json::Value::as_str) - .unwrap_or(""), - profile.artifact_role(), - "cluster seed manifest artifactRole", - )?; - let runtime_module_sha256 = sha256_file(runtime_module)?; - let initdb_module_sha256 = sha256_file(initdb_module)?; - ensure_eq( - seed_runtime - .get("consumerSha256") - .and_then(serde_json::Value::as_str) - .unwrap_or(""), - &runtime_module_sha256, - "cluster seed manifest runtime.consumerSha256", - )?; - ensure_eq( - seed_runtime - .get("initdbSha256") - .and_then(serde_json::Value::as_str) - .unwrap_or(""), - &initdb_module_sha256, - "cluster seed manifest runtime.initdbSha256", - )?; - let source_pins = effective_source_pins(sources, outputs)?; - Ok(ClusterSeedAssetOut { - artifact_role: profile.artifact_role().to_owned(), - catalog_profile: profile.as_str().to_owned(), - archive: archive_relative, - manifest: manifest_relative, - sha256: sha256_file(&archive)?, - size: fs::metadata(&archive) - .with_context(|| format!("metadata {}", archive.display()))? - .len(), - runtime_module_sha256, - initdb_module_sha256, - source_pins_sha256: source_pins_sha256(&source_pins)?, - source_lane: Some(outputs.source_lane.clone()), - source_fingerprint: outputs.source_fingerprint.clone(), - postgres_version: postgres_major_version(&outputs.postgres_version), - catalog_version: seed_source - .get("catalogVersion") - .and_then(serde_json::Value::as_str) - .unwrap_or("unknown") - .to_owned(), - init_profile: cluster_seed_runner::default_initdb_profile().to_owned(), - wasmer_version: sources.toolchain.wasmer.clone(), - physical_format: seed_runtime - .get("physicalFormat") - .and_then(serde_json::Value::as_str) - .unwrap_or("") - .to_owned(), - compatibility_key: seed_runtime - .get("compatibilityKey") - .and_then(serde_json::Value::as_str) - .unwrap_or("") - .to_owned(), - icu_data_tree_sha256: manifest_json - .get("icu") - .and_then(serde_json::Value::as_object) - .and_then(|icu| icu.get("dataTreeSha256")) - .and_then(serde_json::Value::as_str) - .map(str::to_owned), - }) -} - -pub(crate) fn effective_source_pins( - sources: &SourcesManifest, - outputs: &BuildOutputs, -) -> Result> { - let mut pins = sources - .sources - .iter() - .filter(|source| !is_released_source_pin_for_pg18_manifest(source)) - .cloned() - .collect::>(); - let pg18 = load_postgres_source_manifest()?; - pins.push(SourcePin { - name: "postgresql".to_owned(), - kind: SourceKind::Git, - url: pg18.postgresql.url, - mirror_url: None, - branch: format!("v{}", pg18.postgresql.version), - commit: pg18.postgresql.sha256, - source_date_epoch: None, - sha256: None, - strip_prefix: None, - origin: SourceOrigin::Generated, - }); - - let fingerprint = if let Some(fingerprint) = outputs.source_fingerprint.as_deref() { - fingerprint.to_owned() - } else { - let fingerprint_path = outputs - .source_dir - .join(".oliphaunt-wasix-source-fingerprint"); - fs::read_to_string(&fingerprint_path) - .with_context(|| format!("read {}", fingerprint_path.display()))? - .trim() - .to_owned() - }; - let patch_fingerprint = fingerprint - .trim() - .rsplit(':') - .next() - .filter(|value| !value.is_empty()) - .ok_or_else(|| anyhow!("PG18 source fingerprint is invalid: {fingerprint:?}"))?; - pins.push(SourcePin { - name: "oliphaunt-wasix-stable-patches".to_owned(), - kind: SourceKind::Git, - url: "src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches".to_owned(), - mirror_url: None, - branch: "series".to_owned(), - commit: patch_fingerprint.to_owned(), - source_date_epoch: None, - sha256: None, - strip_prefix: None, - origin: SourceOrigin::Generated, - }); - - Ok(pins) -} - -fn is_released_source_pin_for_pg18_manifest(source: &SourcePin) -> bool { - source.name.contains("removed-fork") - || source.branch.contains("removed-fork") - || source.url.contains("removed-fork") -} - -pub(crate) fn load_postgres_source_manifest() -> Result { - let shared_path = repo_relative_path(POSTGRES_SHARED_SOURCE_MANIFEST_PATH); - let product_path = repo_relative_path(POSTGRES_SOURCE_MANIFEST_PATH); - let shared_text = fs::read_to_string(&shared_path) - .with_context(|| format!("read {}", shared_path.display()))?; - let product_text = fs::read_to_string(&product_path) - .with_context(|| format!("read {}", product_path.display()))?; - let shared: PostgresSharedSourceManifest = - toml::from_str(&shared_text).with_context(|| format!("parse {}", shared_path.display()))?; - let product: PostgresProductPatchManifest = toml::from_str(&product_text) - .with_context(|| format!("parse {}", product_path.display()))?; - Ok(PostgresSourceManifest { - postgresql: shared.postgresql, - patches: product.patches, - }) -} - -pub(crate) fn repo_relative_path(path: impl AsRef) -> PathBuf { - let path = path.as_ref(); - if path.is_absolute() || path.exists() { - return path.to_path_buf(); - } - Path::new(env!("CARGO_MANIFEST_DIR")) - .join("../..") - .join(path) -} - -fn source_pins_sha256(sources: &[SourcePin]) -> Result { - let pins = serde_json::to_vec(sources).context("serialize source pins")?; - Ok(sha256_bytes(&pins)) -} - -fn release_product_version(product_path: &str) -> Result { - let path = Path::new(".release-please-manifest.json"); - let text = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?; - let manifest: serde_json::Value = - serde_json::from_str(&text).with_context(|| format!("parse {}", path.display()))?; - manifest - .get(product_path) - .and_then(serde_json::Value::as_str) - .filter(|version| !version.is_empty()) - .map(str::to_owned) - .ok_or_else(|| { - anyhow!( - "{} does not identify release product {product_path}", - path.display() - ) - }) -} - -fn wasix_icu_data_root() -> Result { - let root = wasix_icu_data_path(); - validate_canonical_wasix_icu_data_root(&root)?; - Ok(root) -} - -fn validate_canonical_wasix_icu_data_root(root: &Path) -> Result<()> { - ensure!( - root.is_dir() && tree_contains_icu_files_data(root)?, - "ICU cluster-seed generation requires the exact WASIX ICU files-data tree at {}; build the WASIX runtime first", - root.display() - ); - for file in sorted_files(root)? { - let relative = file - .strip_prefix(root) - .with_context(|| format!("strip {} from {}", root.display(), file.display()))?; - let first = relative - .components() - .next() - .and_then(|component| component.as_os_str().to_str()) - .unwrap_or_default(); - ensure!( - first.starts_with("icudt"), - "WASIX ICU data root must contain only canonical icudt files-data payloads, found {}", - relative.display() - ); - } - Ok(()) -} - -fn wasix_icu_data_path() -> PathBuf { - Path::new(WASIX_GENERATED_WORK_DIR).join("icu-wasix/share/icu") -} - -fn tree_contains_icu_files_data(root: &Path) -> Result { - for file in sorted_files(root)? { - let relative = file - .strip_prefix(root) - .with_context(|| format!("strip {} from {}", root.display(), file.display()))?; - if relative.components().any(|component| { - component - .as_os_str() - .to_str() - .is_some_and(|name| name.starts_with("icudt")) - }) { - return Ok(true); - } - } - Ok(false) -} - -/// Digest the logical portable files tree, independent of host metadata. -/// Each sorted row is `path NUL size NUL file-bytes LF`. -fn logical_tree_sha256(root: &Path) -> Result { - let mut digest = Sha256::new(); - for file in sorted_files(root)? { - let relative = file - .strip_prefix(root) - .with_context(|| format!("strip {} from {}", root.display(), file.display()))?; - let relative = relative - .to_str() - .ok_or_else(|| anyhow!("ICU data path is not UTF-8: {}", file.display()))? - .replace('\\', "/"); - ensure!( - !relative.is_empty() && !relative.contains('\0'), - "ICU data path is not portable: {}", - file.display() - ); - let size = fs::metadata(&file) - .with_context(|| format!("metadata {}", file.display()))? - .len(); - digest.update(relative.as_bytes()); - digest.update([0]); - digest.update(size.to_string().as_bytes()); - digest.update([0]); - digest.update(fs::read(&file).with_context(|| format!("read {}", file.display()))?); - digest.update([b'\n']); - } - Ok(format!("{:x}", digest.finalize())) -} - -fn tree_stats(root: &Path) -> Result<(u64, u64, u64)> { - let mut expanded_bytes = 0_u64; - let mut regular_files = 0_u64; - let mut directories = 0_u64; - for entry in WalkDir::new(root) { - let entry = entry.with_context(|| format!("walk {}", root.display()))?; - if entry.path() == root { - continue; - } - if entry.file_type().is_file() { - regular_files += 1; - expanded_bytes = expanded_bytes - .checked_add(entry.metadata()?.len()) - .ok_or_else(|| { - anyhow!("expanded tree size overflow at {}", entry.path().display()) - })?; - } else if entry.file_type().is_dir() { - directories += 1; - } else { - bail!( - "cluster seed must contain only regular files and directories: {}", - entry.path().display() - ); - } - } - ensure!( - regular_files > 0 && directories > 0, - "cluster seed tree {} must contain files and directories", - root.display() - ); - Ok((expanded_bytes, regular_files, directories)) -} - -fn postgres_catalog_version(source_dir: &Path) -> Result { - let path = source_dir.join("src/include/catalog/catversion.h"); - let text = fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?; - for line in text.lines() { - let line = line.trim(); - if let Some(rest) = line.strip_prefix("#define CATALOG_VERSION_NO") { - let value = rest.trim(); - if !value.is_empty() { - return Ok(value.to_owned()); - } - } - } - bail!("{} does not define CATALOG_VERSION_NO", path.display()) -} - -pub(crate) fn update_staged_root_asset_metadata(workspace: &Path) -> Result<()> { - let asset_dir = workspace.join(GENERATED_ASSETS_DIR); - let manifest = read_asset_manifest_from(&asset_dir)?; - let runtime_archive = asset_dir.join(&manifest.runtime.archive); - let runtime_module = archive_entry_bytes(&runtime_archive, RUNTIME_MODULE_ARCHIVE_MEMBER)?; - update_root_asset_metadata_in(workspace, &manifest, &sha256_bytes(&runtime_module)) -} - -fn update_root_asset_metadata_in( - workspace: &Path, - manifest: &AssetManifestOut, - runtime_module_sha256: &str, -) -> Result<()> { - let path = workspace.join("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"); - let tools_path = workspace.join("src/runtimes/liboliphaunt/wasix/crates/tools/Cargo.toml"); - let tools_npm_path = workspace.join(WASIX_TOOLS_NPM_DESCRIPTOR_PATH); - let mut text = fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?; - let mut tools_text = fs::read_to_string(&tools_path) - .with_context(|| format!("read {}", tools_path.display()))?; - let tools_npm_text = fs::read_to_string(&tools_npm_path) - .with_context(|| format!("read {}", tools_npm_path.display()))?; - let pg18 = load_postgres_source_manifest()?; - text = replace_metadata_value(text, "postgres-version", &manifest.runtime.postgres_version); - text = replace_metadata_value(text, "postgres-source-url", &pg18.postgresql.url); - text = replace_metadata_value(text, "postgres-source-sha256", &pg18.postgresql.sha256); - text = replace_metadata_value( - text, - "postgres-patch-count", - &pg18.patches.series.len().to_string(), - ); - text = replace_metadata_value(text, "runtime-archive-sha256", &manifest.runtime.sha256); - text = replace_metadata_value(text, "oliphaunt-wasix-sha256", runtime_module_sha256); - for profile in ["standard", "icu"] { - let seed = manifest.cluster_seeds.get(profile).with_context(|| { - format!("generated asset manifest is missing {profile} cluster seed") - })?; - text = replace_metadata_value( - text, - &format!("cluster-seed-{profile}-archive-sha256"), - &seed.sha256, - ); - } - let (pg_dump, psql) = required_wasix_tool_assets(manifest)?; - let tools_npm_text = update_wasix_tools_npm_descriptor_rows(&tools_npm_text, pg_dump, psql)?; - tools_text = replace_metadata_value(tools_text, "pg-dump-wasix-sha256", &pg_dump.sha256); - tools_text = replace_metadata_value(tools_text, "psql-wasix-sha256", &psql.sha256); - if let Some(initdb) = &manifest.initdb { - text = replace_metadata_value(text, "initdb-wasix-sha256", &initdb.sha256); - } - fs::write(&path, text).with_context(|| format!("write {}", path.display()))?; - fs::write(&tools_path, tools_text) - .with_context(|| format!("write {}", tools_path.display()))?; - fs::write(&tools_npm_path, tools_npm_text) - .with_context(|| format!("write {}", tools_npm_path.display())) -} - -pub(crate) const WASIX_TOOLS_NPM_DESCRIPTOR_PATH: &str = - "src/runtimes/liboliphaunt/wasix/tools-npm/index.js"; - -fn required_wasix_tool_asset<'a>( - asset: Option<&'a BinaryAssetOut>, - expected_name: &str, - expected_path: &str, -) -> Result<&'a BinaryAssetOut> { - let asset = asset - .with_context(|| format!("generated asset manifest is missing the {expected_name} tool"))?; - ensure_eq( - &asset.name, - expected_name, - &format!("{expected_name} tool name"), - )?; - ensure_eq( - &asset.path, - expected_path, - &format!("{expected_name} tool path"), - )?; - Ok(asset) -} - -pub(crate) fn update_wasix_tools_npm_descriptor( - text: &str, - manifest: &AssetManifestOut, -) -> Result { - let (pg_dump, psql) = required_wasix_tool_assets(manifest)?; - update_wasix_tools_npm_descriptor_rows(text, pg_dump, psql) -} - -fn required_wasix_tool_assets( - manifest: &AssetManifestOut, -) -> Result<(&BinaryAssetOut, &BinaryAssetOut)> { - Ok(( - required_wasix_tool_asset( - manifest.pg_dump.as_ref(), - "pg_dump", - "bin/pg_dump.wasix.wasm", - )?, - required_wasix_tool_asset(manifest.psql.as_ref(), "psql", "bin/psql.wasix.wasm")?, - )) -} - -fn update_wasix_tools_npm_descriptor_rows( - text: &str, - pg_dump: &BinaryAssetOut, - psql: &BinaryAssetOut, -) -> Result { - let mut updated = text.to_owned(); - for asset in [pg_dump, psql] { - let marker = format!(" name: '{}',", asset.name); - let marker_count = updated.matches(&marker).count(); - ensure!( - marker_count == 1, - "WASIX tools npm workspace descriptor must contain exactly one {marker:?} row, found {marker_count}" - ); - let block_start = updated - .find(&marker) - .expect("validated descriptor marker must exist"); - let block_end = updated[block_start..] - .find(" }),") - .map(|offset| block_start + offset) - .context("WASIX tools npm workspace descriptor has an unterminated tool row")?; - let block = &updated[block_start..block_end]; - let block = replace_wasix_tools_npm_field( - block, - "sha256", - &format!("'{}'", asset.sha256), - &asset.name, - )?; - let block = - replace_wasix_tools_npm_field(&block, "size", &asset.size.to_string(), &asset.name)?; - updated.replace_range(block_start..block_end, &block); - } - Ok(updated) -} - -fn replace_wasix_tools_npm_field( - block: &str, - field: &str, - value: &str, - tool: &str, -) -> Result { - let prefix = format!(" {field}: "); - let matches = block.match_indices(&prefix).collect::>(); - ensure!( - matches.len() == 1, - "WASIX tools npm workspace descriptor {tool} row must contain exactly one {field} field, found {}", - matches.len() - ); - let start = matches[0].0; - let end = block[start..] - .find('\n') - .map(|offset| start + offset) - .unwrap_or(block.len()); - let mut updated = block.to_owned(); - updated.replace_range(start..end, &format!("{prefix}{value},")); - Ok(updated) -} - -fn replace_metadata_value(mut text: String, key: &str, value: &str) -> String { - let needle = format!("{key} = \""); - let Some(start) = text.find(&needle) else { - eprintln!("warning: Cargo.toml metadata key '{key}' is missing; not updating it"); - return text; - }; - let value_start = start + needle.len(); - let Some(relative_end) = text[value_start..].find('"') else { - return text; - }; - text.replace_range(value_start..value_start + relative_end, value); - text -} - -fn ensure_matching_marker(expected: &str, actual_path: &Path, field: &str) -> Result<()> { - let actual = fs::read_to_string(actual_path) - .with_context(|| format!("read {}", actual_path.display()))?; - ensure_eq(actual.trim(), expected, field) -} diff --git a/tools/xtask/src/cluster_seed_runner.rs b/tools/xtask/src/cluster_seed_runner.rs deleted file mode 100644 index 262007eb4..000000000 --- a/tools/xtask/src/cluster_seed_runner.rs +++ /dev/null @@ -1,564 +0,0 @@ -use std::fs; -use std::path::Path; - -use anyhow::{Context, Result, bail}; - -#[cfg(feature = "cluster-seed-runner")] -pub(crate) const INTERNAL_ICU_READY_ENV: &str = "OLIPHAUNT_INTERNAL_ICU_READY"; -#[cfg(feature = "cluster-seed-runner")] -pub(crate) const INTERNAL_ICU_READY_VALUE: &str = "1"; -#[cfg(feature = "cluster-seed-runner")] -const SKIP_SYSTEM_COLLATION_DISCOVERY_ENV: &str = - "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY"; -#[cfg(feature = "cluster-seed-runner")] -const SKIP_ICU_COLLATION_DISCOVERY_ENV: &str = "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY"; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum CatalogProfile { - Standard, - Icu, -} - -impl CatalogProfile { - pub(crate) const ALL: [Self; 2] = [Self::Standard, Self::Icu]; - - pub(crate) const fn as_str(self) -> &'static str { - match self { - Self::Standard => "standard", - Self::Icu => "icu", - } - } - - pub(crate) const fn artifact_role(self) -> &'static str { - match self { - Self::Standard => "cluster-seed-standard", - Self::Icu => "cluster-seed-icu", - } - } -} - -pub(crate) fn default_initdb_profile() -> &'static str { - "allow-group-access,encoding=UTF8,locale=C.UTF-8,locale-provider=libc,auth=trust,no-sync" -} - -pub(crate) fn clean_generated_cluster_seed(pgdata: &Path) -> Result<()> { - for name in ["postmaster.pid", "postmaster.opts"] { - let path = pgdata.join(name); - if path.exists() { - fs::remove_file(&path).with_context(|| format!("remove {}", path.display()))?; - } - } - Ok(()) -} - -#[cfg(feature = "cluster-seed-runner")] -pub(crate) fn run_wasix_initdb_cluster_seed( - runtime_stage: &Path, - work_root: &Path, - profile: CatalogProfile, - icu_data_root: Option<&Path>, -) -> Result<()> { - use std::env; - use std::sync::Arc; - - use wasmer::Engine; - use wasmer_wasix::bin_factory::BinaryPackage; - use wasmer_wasix::runners::wasi::{RuntimeOrEngine, WasiRunner}; - use wasmer_wasix::runtime::task_manager::tokio::TokioTaskManager; - use wasmer_wasix::runtime::{PluggableRuntime, Runtime}; - use wasmer_wasix::virtual_fs; - use wasmer_wasix::virtual_fs::null_file::NullFile; - - use crate::fs_utils::{copy_file, copy_tree_filtered}; - - let package_dir = work_root.join("package"); - let package_root = work_root.join("root"); - let pgdata_root = work_root.join("pgdata"); - fs::create_dir_all(package_dir.join("modules")) - .with_context(|| format!("create {}", package_dir.join("modules").display()))?; - fs::create_dir_all(&pgdata_root) - .with_context(|| format!("create {}", pgdata_root.display()))?; - copy_tree_filtered(runtime_stage, &package_root, None)?; - let staged_icu_data = package_root.join("share/icu"); - if staged_icu_data.exists() { - fs::remove_dir_all(&staged_icu_data) - .with_context(|| format!("remove {}", staged_icu_data.display()))?; - } - match (profile, icu_data_root) { - (CatalogProfile::Standard, None) => {} - (CatalogProfile::Standard, Some(_)) => { - bail!("standard cluster-seed generation must not receive ICU data") - } - (CatalogProfile::Icu, Some(icu_data_root)) => { - copy_tree_filtered(icu_data_root, &staged_icu_data, None)?; - } - (CatalogProfile::Icu, None) => { - bail!("ICU cluster-seed generation requires verified ICU data") - } - } - copy_file( - &runtime_stage.join("bin/initdb"), - &package_dir.join("modules/initdb.wasm"), - )?; - copy_file( - &runtime_stage.join("bin/postgres"), - &package_dir.join("modules/postgres.wasm"), - )?; - let wasmer_toml = r#" -[package] -name = "oliphaunt-wasix/cluster-seed-producer" -version = "0.0.0" -description = "Oliphaunt WASIX cluster seed producer" - -[[module]] -name = "initdb" -source = "modules/initdb.wasm" -abi = "wasi" - -[[module]] -name = "postgres" -source = "modules/postgres.wasm" -abi = "wasi" - -[[command]] -name = "initdb" -module = "initdb" - -[[command]] -name = "postgres" -module = "postgres" -"#; - fs::write(package_dir.join("wasmer.toml"), wasmer_toml) - .with_context(|| format!("write {}", package_dir.join("wasmer.toml").display()))?; - - let tokio_runtime = tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() - .context("create Tokio runtime for WASIX cluster-seed generation")?; - let _guard = tokio_runtime.enter(); - let engine = Engine::default(); - let task_manager = Arc::new(TokioTaskManager::new(tokio_runtime.handle().clone())); - let mut runtime = PluggableRuntime::new(task_manager); - runtime.set_engine(engine.clone()); - runtime.set_package_loader(LocalOnlyPackageLoader); - let runtime: Arc = Arc::new(runtime); - let package = tokio_runtime - .block_on(BinaryPackage::from_dir(&package_dir, runtime.as_ref())) - .context("load WASIX initdb package")?; - let root_fs = Arc::new( - virtual_fs::host_fs::FileSystem::new(tokio_runtime.handle().clone(), &package_root) - .with_context(|| { - format!( - "create WASIX cluster-seed root filesystem at {}", - package_root.display() - ) - })?, - ) as Arc; - let pgdata_fs = Arc::new( - virtual_fs::host_fs::FileSystem::new(tokio_runtime.handle().clone(), &pgdata_root) - .with_context(|| { - format!( - "create WASIX cluster-seed PGDATA filesystem at {}", - pgdata_root.display() - ) - })?, - ) as Arc; - - let (stdout_file, stdout_capture) = TailCaptureFile::new(64 * 1024); - let (stderr_file, stderr_capture) = TailCaptureFile::new(64 * 1024); - let run_result = { - let mut runner = WasiRunner::new(); - runner.with_current_dir("/"); - runner.with_mount("/".to_owned(), root_fs.clone()); - runner.with_mount("/base".to_owned(), pgdata_fs.clone()); - runner.with_args(default_initdb_args()); - runner.with_envs(cluster_seed_producer_environment(profile)); - runner.with_stdin(Box::::default()); - runner.with_stdout(Box::new(stdout_file)); - runner.with_stderr(Box::new(stderr_file)); - runner.run_command( - "initdb", - &package, - RuntimeOrEngine::Runtime(runtime.clone()), - ) - }; - let stdout = stdout_capture.text(); - let stderr = stderr_capture.text(); - if env::var_os("OLIPHAUNT_WASM_CLUSTER_SEED_LOG").is_some() || run_result.is_err() { - print_captured_wasix_output("initdb stdout", &stdout); - print_captured_wasix_output("initdb stderr", &stderr); - } - run_result.context("run WASIX initdb to generate cluster seed")?; - verify_wasix_cluster_seed_profile(&package, runtime, root_fs, pgdata_fs, profile) -} - -#[cfg(not(feature = "cluster-seed-runner"))] -pub(crate) fn run_wasix_initdb_cluster_seed( - _runtime_stage: &Path, - _work_root: &Path, - _profile: CatalogProfile, - _icu_data_root: Option<&Path>, -) -> Result<()> { - bail!( - "`assets cluster-seeds` and seed generation during release-build require `cargo run -p xtask --features cluster-seed-runner -- ...` so xtask has a maintainer-only Wasmer compiler backend" - ) -} - -#[cfg_attr(not(feature = "cluster-seed-runner"), allow(dead_code))] -fn default_initdb_args() -> Vec<&'static str> { - vec![ - "--allow-group-access", - "--encoding", - "UTF8", - "--locale=C.UTF-8", - "--locale-provider=libc", - "--auth=trust", - "--no-sync", - "-D", - "/base", - ] -} - -#[cfg(feature = "cluster-seed-runner")] -fn cluster_seed_environment(profile: CatalogProfile) -> Vec<(&'static str, &'static str)> { - let mut environment = vec![ - ("PGDATA", "/base"), - ("PGSYSCONFDIR", "/base"), - ("HOME", "/home/postgres"), - ("USER", "postgres"), - ("LOGNAME", "postgres"), - ("PGCLIENTENCODING", "UTF8"), - ("PATH", "/bin"), - ("LC_CTYPE", "C.UTF-8"), - ("TZ", "UTC"), - ("PGTZ", "UTC"), - ("PG_COLOR", "never"), - ]; - if profile == CatalogProfile::Icu { - environment.push(("ICU_DATA", "/share/icu")); - } - environment -} - -#[cfg(feature = "cluster-seed-runner")] -fn cluster_seed_producer_environment(profile: CatalogProfile) -> Vec<(&'static str, &'static str)> { - let mut environment = cluster_seed_environment(profile); - environment.push((SKIP_SYSTEM_COLLATION_DISCOVERY_ENV, "1")); - if profile == CatalogProfile::Standard { - environment.push((SKIP_ICU_COLLATION_DISCOVERY_ENV, "1")); - } else { - environment.push((INTERNAL_ICU_READY_ENV, INTERNAL_ICU_READY_VALUE)); - } - environment -} - -#[cfg(feature = "cluster-seed-runner")] -fn verify_wasix_cluster_seed_profile( - package: &wasmer_wasix::bin_factory::BinaryPackage, - runtime: std::sync::Arc, - root_fs: std::sync::Arc, - pgdata_fs: std::sync::Arc, - profile: CatalogProfile, -) -> Result<()> { - use wasmer_wasix::runners::wasi::{RuntimeOrEngine, WasiRunner}; - use wasmer_wasix::virtual_fs; - - const CONTRACT_JSON: &str = include_str!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/../../src/shared/cluster-seed-contract/profile-probe.json" - )); - - let contract: ClusterSeedProfileProbeContract = - serde_json::from_str(CONTRACT_JSON).context("parse shared cluster-seed profile probe")?; - if contract.schema != "oliphaunt-cluster-seed-profile-probe-v1" { - bail!( - "unsupported shared cluster-seed profile probe schema {}", - contract.schema - ); - } - let probe = match profile { - CatalogProfile::Standard => &contract.profiles.standard, - CatalogProfile::Icu => &contract.profiles.icu, - }; - - for attempt in 1..=2 { - let (stdout_file, stdout_capture) = TailCaptureFile::new(64 * 1024); - let (stderr_file, stderr_capture) = TailCaptureFile::new(64 * 1024); - let mut runner = WasiRunner::new(); - runner.with_current_dir("/"); - runner.with_mount("/".to_owned(), root_fs.clone()); - runner.with_mount("/base".to_owned(), pgdata_fs.clone()); - runner.with_args(vec!["--single", "-D", "/base", "postgres"]); - runner.with_envs(cluster_seed_environment(profile)); - runner.with_stdin(Box::new(virtual_fs::StaticFile::new( - format!("{};\n", probe.sql).into_bytes(), - ))); - runner.with_stdout(Box::new(stdout_file)); - runner.with_stderr(Box::new(stderr_file)); - let result = runner.run_command( - "postgres", - package, - RuntimeOrEngine::Runtime(runtime.clone()), - ); - let stdout = stdout_capture.text(); - let stderr = stderr_capture.text(); - let failed = result.is_err() || !stdout.contains(&probe.expected); - if std::env::var_os("OLIPHAUNT_WASM_CLUSTER_SEED_LOG").is_some() || failed { - print_captured_wasix_output("profile probe stdout", &stdout); - print_captured_wasix_output("profile probe stderr", &stderr); - } - result.with_context(|| { - format!( - "run {} WASIX cluster-seed profile probe (attempt {attempt})", - profile.as_str() - ) - })?; - if !stdout.contains(&probe.expected) { - bail!( - "{} WASIX cluster-seed profile probe attempt {attempt} did not emit {:?}", - profile.as_str(), - probe.expected - ); - } - } - Ok(()) -} - -#[cfg(feature = "cluster-seed-runner")] -#[derive(Debug, serde::Deserialize)] -struct ClusterSeedProfileProbeContract { - schema: String, - profiles: ClusterSeedProfileProbes, -} - -#[cfg(feature = "cluster-seed-runner")] -#[derive(Debug, serde::Deserialize)] -struct ClusterSeedProfileProbes { - standard: ClusterSeedProfileProbe, - icu: ClusterSeedProfileProbe, -} - -#[cfg(feature = "cluster-seed-runner")] -#[derive(Debug, serde::Deserialize)] -struct ClusterSeedProfileProbe { - sql: String, - expected: String, -} - -#[cfg(feature = "cluster-seed-runner")] -fn print_captured_wasix_output(label: &str, output: &str) { - if output.trim().is_empty() { - eprintln!("{label}: "); - } else { - eprintln!("--- {label} ---"); - eprint!("{output}"); - if !output.ends_with('\n') { - eprintln!(); - } - eprintln!("--- end {label} ---"); - } -} - -#[cfg(feature = "cluster-seed-runner")] -#[derive(Debug, Default)] -struct LocalOnlyPackageLoader; - -#[cfg(feature = "cluster-seed-runner")] -#[derive(Debug, Clone)] -struct TailCaptureFile { - inner: std::sync::Arc>, - limit: usize, -} - -#[cfg(feature = "cluster-seed-runner")] -#[derive(Debug, Default)] -struct TailCaptureState { - bytes: std::collections::VecDeque, -} - -#[cfg(feature = "cluster-seed-runner")] -#[derive(Debug, Clone)] -struct TailCaptureHandle { - inner: std::sync::Arc>, -} - -#[cfg(feature = "cluster-seed-runner")] -impl TailCaptureFile { - fn new(limit: usize) -> (Self, TailCaptureHandle) { - let inner = std::sync::Arc::new(std::sync::Mutex::new(TailCaptureState::default())); - ( - Self { - inner: inner.clone(), - limit, - }, - TailCaptureHandle { inner }, - ) - } - - fn push_tail(&self, bytes: &[u8]) { - let Ok(mut state) = self.inner.lock() else { - return; - }; - for byte in bytes { - state.bytes.push_back(*byte); - while state.bytes.len() > self.limit { - state.bytes.pop_front(); - } - } - } -} - -#[cfg(feature = "cluster-seed-runner")] -impl TailCaptureHandle { - fn text(&self) -> String { - let Ok(state) = self.inner.lock() else { - return "".to_owned(); - }; - let bytes = state.bytes.iter().copied().collect::>(); - String::from_utf8_lossy(&bytes).into_owned() - } -} - -#[cfg(feature = "cluster-seed-runner")] -impl wasmer_wasix::virtual_fs::AsyncSeek for TailCaptureFile { - fn start_seek( - self: std::pin::Pin<&mut Self>, - _position: std::io::SeekFrom, - ) -> std::io::Result<()> { - Ok(()) - } - - fn poll_complete( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - std::task::Poll::Ready(Ok(0)) - } -} - -#[cfg(feature = "cluster-seed-runner")] -impl wasmer_wasix::virtual_fs::AsyncRead for TailCaptureFile { - fn poll_read( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - _buf: &mut wasmer_wasix::virtual_fs::ReadBuf<'_>, - ) -> std::task::Poll> { - std::task::Poll::Ready(Ok(())) - } -} - -#[cfg(feature = "cluster-seed-runner")] -impl wasmer_wasix::virtual_fs::AsyncWrite for TailCaptureFile { - fn poll_write( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - buf: &[u8], - ) -> std::task::Poll> { - self.push_tail(buf); - std::task::Poll::Ready(Ok(buf.len())) - } - - fn poll_flush( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - std::task::Poll::Ready(Ok(())) - } - - fn poll_shutdown( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - std::task::Poll::Ready(Ok(())) - } - - fn poll_write_vectored( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - bufs: &[std::io::IoSlice<'_>], - ) -> std::task::Poll> { - let mut total = 0; - for buf in bufs { - self.push_tail(buf); - total += buf.len(); - } - std::task::Poll::Ready(Ok(total)) - } - - fn is_write_vectored(&self) -> bool { - true - } -} - -#[cfg(feature = "cluster-seed-runner")] -impl wasmer_wasix::virtual_fs::VirtualFile for TailCaptureFile { - fn last_accessed(&self) -> u64 { - 0 - } - - fn last_modified(&self) -> u64 { - 0 - } - - fn created_time(&self) -> u64 { - 0 - } - - fn size(&self) -> u64 { - self.inner - .lock() - .map(|state| state.bytes.len() as u64) - .unwrap_or(0) - } - - fn set_len(&mut self, _new_size: u64) -> wasmer_wasix::virtual_fs::Result<()> { - Ok(()) - } - - fn unlink(&mut self) -> wasmer_wasix::virtual_fs::Result<()> { - Ok(()) - } - - fn poll_read_ready( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - std::task::Poll::Ready(Ok(0)) - } - - fn poll_write_ready( - self: std::pin::Pin<&mut Self>, - _cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - std::task::Poll::Ready(Ok(self.limit)) - } -} - -#[cfg(feature = "cluster-seed-runner")] -#[async_trait::async_trait] -impl wasmer_wasix::runtime::package_loader::PackageLoader for LocalOnlyPackageLoader { - async fn load( - &self, - summary: &wasmer_wasix::runtime::resolver::PackageSummary, - ) -> Result { - bail!( - "WASIX cluster-seed generation only supports local packages; unexpected dependency {}", - summary.pkg.id - ) - } - - async fn load_package_tree( - &self, - root: &webc::Container, - resolution: &wasmer_wasix::runtime::resolver::Resolution, - root_is_local_dir: bool, - ) -> Result { - wasmer_wasix::runtime::package_loader::load_package_tree( - root, - self, - resolution, - root_is_local_dir, - ) - .await - } -} diff --git a/tools/xtask/src/extension_catalog.rs b/tools/xtask/src/extension_catalog.rs deleted file mode 100644 index 44ffc602c..000000000 --- a/tools/xtask/src/extension_catalog.rs +++ /dev/null @@ -1,1448 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet}; -use std::fs; -use std::path::Path; -use std::process::Command; - -use anyhow::{Context, Result, anyhow, bail, ensure}; -use serde::{Deserialize, Serialize}; - -const CATALOG_PATH: &str = "src/extensions/generated/extensions.catalog.json"; -const SOURCE_CATALOG_PATH: &str = "src/extensions/catalog/extensions.source.json"; -const CONTRIB_BUILD_PLAN_PATH: &str = "src/extensions/generated/contrib-build.tsv"; -const PGXS_BUILD_PLAN_PATH: &str = "src/extensions/generated/pgxs-build.tsv"; -const CONTRIB_MANIFEST_PATH: &str = "src/extensions/contrib/postgres18.toml"; -const POSTGRES_CONTRIB: &str = "src/postgres/versions/18/contrib"; -const POSTGRES_OTHER_EXTENSIONS: &str = "src/extensions/external"; -const EXTERNAL_EXTENSION_RECIPE_ROOT: &str = "src/extensions/external"; -const PGVECTOR_CHECKOUT: &str = "target/oliphaunt-sources/checkouts/pgvector"; -const EXTERNAL_EXTENSION_CHECKOUT_ROOT: &str = "target/oliphaunt-sources/checkouts"; - -pub(crate) fn extensions(args: Vec) -> Result<()> { - match args.first().map(String::as_str) { - Some("discover") => { - let catalog = discover_catalog()?; - validate_catalog(&catalog)?; - let text = serde_json::to_string_pretty(&catalog).context("serialize catalog")?; - if args.iter().any(|arg| arg == "--write") { - write_catalog(&text)?; - } else { - println!("{text}"); - } - Ok(()) - } - Some("generate") => { - let catalog = discover_catalog()?; - validate_catalog(&catalog)?; - let text = serde_json::to_string_pretty(&catalog).context("serialize catalog")?; - write_catalog(&text)?; - write_build_plan_files(&catalog)?; - write_generated_extension_api(&catalog)?; - Ok(()) - } - Some("build-plan") => { - let catalog = discover_catalog()?; - validate_catalog(&catalog)?; - if args.iter().any(|arg| arg == "--write") { - write_build_plan_files(&catalog) - } else if args.iter().any(|arg| arg == "--check") { - check_build_plan_file(true) - } else { - let plan = build_plan(&catalog)?; - println!( - "{}", - serde_json::to_string_pretty(&plan) - .context("serialize extension build plan")? - ); - Ok(()) - } - } - Some("check") => { - check_catalog_file(true)?; - check_build_plan_file(true) - } - Some(other) => bail!("unknown extensions subcommand: {other}"), - None => { - bail!( - "usage: cargo run -p xtask -- extensions [--write|--check]" - ) - } - } -} - -pub(crate) fn check_catalog_file(strict: bool) -> Result<()> { - if !extension_discovery_inputs_available(strict)? { - return Ok(()); - } - let catalog = discover_catalog()?; - validate_catalog(&catalog)?; - let expected = serde_json::to_string_pretty(&catalog).context("serialize extension catalog")?; - let path = Path::new(CATALOG_PATH); - if !path.exists() { - if strict { - bail!( - "generated extension catalog is missing at {}; run `cargo run -p xtask -- extensions discover --write`", - path.display() - ); - } - eprintln!( - "warning: generated extension catalog is missing at {}", - path.display() - ); - return Ok(()); - } - let actual = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?; - if !extension_catalog_text_matches_source_control(&actual, &expected)? { - if strict { - bail!( - "generated extension catalog is stale at {}; run `cargo run -p xtask -- extensions discover --write`", - path.display() - ); - } - eprintln!( - "warning: generated extension catalog is stale at {}", - path.display() - ); - } - Ok(()) -} - -pub(crate) fn check_build_plan_file(strict: bool) -> Result<()> { - if !extension_discovery_inputs_available(strict)? { - return Ok(()); - } - let catalog = discover_catalog()?; - validate_catalog(&catalog)?; - let expected = build_plan_texts(&catalog)?; - for (path, text, command) in [ - ( - CONTRIB_BUILD_PLAN_PATH, - expected.contrib_tsv.as_str(), - "cargo run -p xtask -- extensions build-plan --write", - ), - ( - PGXS_BUILD_PLAN_PATH, - expected.pgxs_tsv.as_str(), - "cargo run -p xtask -- extensions build-plan --write", - ), - ] { - let path = Path::new(path); - if !path.exists() { - if strict { - bail!( - "generated extension build plan is missing at {}; run `{command}`", - path.display() - ); - } - eprintln!( - "warning: generated extension build plan is missing at {}", - path.display() - ); - continue; - } - let actual = - fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?; - let matches = extension_build_plan_tsv_matches_source_control(&actual, text); - if !matches { - if strict { - bail!( - "generated extension build plan is stale at {}; run `{command}`", - path.display() - ); - } - eprintln!( - "warning: generated extension build plan is stale at {}", - path.display() - ); - } - } - Ok(()) -} - -fn extension_build_plan_tsv_matches_source_control(actual: &str, expected: &str) -> bool { - normalize_extension_build_plan_tsv(actual) == normalize_extension_build_plan_tsv(expected) -} - -fn normalize_extension_build_plan_tsv(text: &str) -> String { - text.replace("\r\n", "\n") - .replace('\r', "\n") - .trim_end() - .to_owned() -} - -fn extension_discovery_inputs_available(strict: bool) -> Result { - for required in [SOURCE_CATALOG_PATH, CATALOG_PATH, CONTRIB_MANIFEST_PATH] { - let path = Path::new(required); - if path.exists() { - continue; - } - if strict { - bail!( - "extension graph input is missing at {}; restore the committed extension catalog/config", - path.display() - ); - } - eprintln!( - "warning: extension graph input is missing at {}; skipping generated extension catalog checks in source-only verification", - path.display() - ); - return Ok(false); - } - Ok(true) -} - -fn extension_catalog_text_matches_source_control(actual: &str, expected: &str) -> Result { - let actual: serde_json::Value = - serde_json::from_str(actual).context("parse generated extension catalog")?; - let expected: serde_json::Value = - serde_json::from_str(expected).context("parse expected extension catalog")?; - Ok(normalize_extension_catalog_for_source_control(actual) - == normalize_extension_catalog_for_source_control(expected)) -} - -fn normalize_extension_catalog_for_source_control(value: serde_json::Value) -> serde_json::Value { - normalize_generated_inputs_for_source_control(value) -} - -fn normalize_generated_inputs_for_source_control( - mut value: serde_json::Value, -) -> serde_json::Value { - if let Some(inputs) = value - .get_mut("generated-from") - .and_then(serde_json::Value::as_array_mut) - { - inputs.retain(|input| { - input.get("name").and_then(serde_json::Value::as_str) != Some("asset-manifest-evidence") - }); - } - value -} - -pub(crate) fn manifest_metadata_by_sql_name() -> Result> -{ - ensure!( - extension_discovery_inputs_available(false)?, - "extension manifest metadata requires the extension source catalog and recipes" - ); - let catalog = discover_catalog()?; - validate_catalog(&catalog)?; - Ok(catalog - .extensions - .into_iter() - .map(|extension| { - ( - extension.sql_name.clone(), - manifest_metadata_from_catalog_entry(extension), - ) - }) - .collect()) -} - -pub(crate) fn extension_build_specs() -> Result> { - ensure!( - extension_discovery_inputs_available(false)?, - "extension build specs require the extension source catalog and recipes" - ); - let catalog = discover_catalog()?; - validate_catalog(&catalog)?; - build_specs(&catalog) -} - -fn build_specs(catalog: &ExtensionCatalog) -> Result> { - build_specs_at(catalog, Path::new(".")) -} - -fn build_specs_at( - catalog: &ExtensionCatalog, - repository_root: &Path, -) -> Result> { - let mut specs = Vec::new(); - for extension in &catalog.extensions { - let archive = format!("extensions/{}.tar.zst", extension.sql_name); - let wasix_target = wasix_target_recipe_at(repository_root, &extension.sql_name)?; - let mut native_support_modules = wasix_target - .as_ref() - .map(|target| target.native_support_modules.clone()) - .unwrap_or_default(); - native_support_modules.sort_by(|left, right| left.name.cmp(&right.name)); - let build_kind = build_kind(extension, wasix_target.as_ref())?; - specs.push(ExtensionBuildSpec { - id: extension.id.clone(), - display_name: extension.display_name.clone(), - sql_name: extension.sql_name.clone(), - source_kind: extension.source_kind.clone(), - build_kind, - build_script: wasix_target - .as_ref() - .and_then(|target| target.build_script.clone()), - required_build_files: wasix_target - .as_ref() - .map(|target| target.required_build_files.clone()) - .unwrap_or_default(), - required_build_globs: wasix_target - .as_ref() - .map(|target| target.required_build_globs.clone()) - .unwrap_or_default(), - source_dir: extension_source_dir(extension), - make_args: pgxs_make_args(extension), - contrib_dir: (extension.source_kind == "postgres-contrib") - .then(|| extension_contrib_dir_name(&extension.id)), - module_file: extension.native_module_file.clone(), - archive, - control_file: extension.control_file.clone(), - dependencies: extension.dependencies.clone(), - native_support_modules, - excluded_sql_extensions: wasix_target - .as_ref() - .map(|target| target.excluded_sql_extensions.clone()) - .unwrap_or_default(), - staging: wasix_target.and_then(|target| target.staging), - load_order: extension.load_order.clone(), - lifecycle: extension.lifecycle.clone(), - tests: extension.tests.clone(), - }); - } - specs.sort_by(|left, right| left.sql_name.cmp(&right.sql_name)); - Ok(specs) -} - -#[derive(Debug, Clone)] -pub(crate) struct ExtensionBuildSpec { - pub(crate) id: String, - pub(crate) display_name: String, - pub(crate) sql_name: String, - pub(crate) source_kind: String, - pub(crate) build_kind: String, - pub(crate) build_script: Option, - pub(crate) required_build_files: Vec, - pub(crate) required_build_globs: Vec, - pub(crate) source_dir: String, - pub(crate) make_args: Vec, - pub(crate) contrib_dir: Option, - pub(crate) module_file: Option, - pub(crate) archive: String, - pub(crate) control_file: Option, - pub(crate) dependencies: Vec, - pub(crate) native_support_modules: Vec, - pub(crate) excluded_sql_extensions: Vec, - pub(crate) staging: Option, - pub(crate) load_order: Vec, - pub(crate) lifecycle: ExtensionLifecycle, - pub(crate) tests: Vec, -} - -#[derive(Debug, Clone)] -pub(crate) struct ManifestExtensionMetadata { - pub(crate) source_kind: String, - pub(crate) control_files: Vec, - pub(crate) dependencies: Vec, - pub(crate) load_order: Vec, - pub(crate) lifecycle: ManifestExtensionLifecycle, -} - -#[derive(Debug, Clone)] -pub(crate) struct ManifestExtensionLifecycle { - pub(crate) create_extension: bool, - pub(crate) create_schema: Option, - pub(crate) load_sql: Vec, - pub(crate) post_create_sql: Vec, - pub(crate) startup_config: Vec, - pub(crate) preload_required: bool, - pub(crate) restart_required: bool, - pub(crate) shared_memory_required: bool, -} - -fn write_catalog(text: &str) -> Result<()> { - let path = Path::new(CATALOG_PATH); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?; - } - fs::write(path, format!("{text}\n")).with_context(|| format!("write {}", path.display())) -} - -fn write_build_plan_files(catalog: &ExtensionCatalog) -> Result<()> { - let texts = build_plan_texts(catalog)?; - for (path, text) in [ - (CONTRIB_BUILD_PLAN_PATH, texts.contrib_tsv), - (PGXS_BUILD_PLAN_PATH, texts.pgxs_tsv), - ] { - let path = Path::new(path); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).with_context(|| format!("create {}", parent.display()))?; - } - fs::write(path, text).with_context(|| format!("write {}", path.display()))?; - } - Ok(()) -} - -fn build_plan_texts(catalog: &ExtensionCatalog) -> Result { - let plan = build_plan(catalog)?; - let mut contrib_tsv = "# id\tsql_name\tcontrib_dir\tmodule_file\tarchive\n".to_owned(); - let mut pgxs_tsv = "# id\tsql_name\tsource_dir\tmodule_file\tarchive\tmake_args\n".to_owned(); - for extension in &plan.extensions { - match extension.build_kind.as_str() { - "postgres-contrib" => { - let contrib_dir = extension.contrib_dir.as_deref().ok_or_else(|| { - anyhow!("contrib extension {} has no contrib_dir", extension.id) - })?; - contrib_tsv.push_str(&format!( - "{}\t{}\t{}\t{}\t{}\n", - extension.id, - extension.sql_name, - contrib_dir, - extension.module_file.as_deref().unwrap_or("-"), - extension.archive - )); - } - kind if is_pgxs_style_build_kind(kind) => { - pgxs_tsv.push_str(&format!( - "{}\t{}\t{}\t{}\t{}\t{}\n", - extension.id, - extension.sql_name, - extension.source_dir, - extension.module_file.as_deref().unwrap_or("-"), - extension.archive, - shell_words(&extension.make_args) - )); - } - kind if is_recipe_staged_build_kind(kind) => {} - other => bail!( - "extension {} has unsupported build kind {other}", - extension.id - ), - } - } - Ok(BuildPlanTexts { - contrib_tsv, - pgxs_tsv, - }) -} - -fn build_plan(catalog: &ExtensionCatalog) -> Result { - let specs = build_specs(catalog)?; - Ok(ExtensionBuildPlan { - format_version: 1, - generated_from: vec![CatalogInput { - name: "extension-catalog".to_owned(), - path: CATALOG_PATH.to_owned(), - }], - extensions: specs - .into_iter() - .map(|spec| ExtensionBuildPlanEntry { - id: spec.id, - sql_name: spec.sql_name, - display_name: spec.display_name, - source_kind: spec.source_kind, - build_kind: spec.build_kind, - build_script: spec.build_script, - required_build_files: spec.required_build_files, - required_build_globs: spec.required_build_globs, - source_dir: spec.source_dir, - make_args: spec.make_args, - contrib_dir: spec.contrib_dir, - module_file: spec.module_file, - archive: spec.archive, - control_file: spec.control_file, - dependencies: spec.dependencies, - native_support_modules: spec.native_support_modules, - excluded_sql_extensions: spec.excluded_sql_extensions, - staging: spec.staging, - load_order: spec.load_order, - lifecycle: spec.lifecycle, - tests: spec.tests, - }) - .collect(), - }) -} - -fn manifest_metadata_from_catalog_entry( - extension: ExtensionCatalogEntry, -) -> ManifestExtensionMetadata { - ManifestExtensionMetadata { - source_kind: extension.source_kind, - control_files: extension.control_file.into_iter().collect(), - dependencies: extension.dependencies, - load_order: extension.load_order, - lifecycle: manifest_lifecycle_from_extension(extension.lifecycle), - } -} - -fn manifest_lifecycle_from_extension(lifecycle: ExtensionLifecycle) -> ManifestExtensionLifecycle { - ManifestExtensionLifecycle { - create_extension: lifecycle.create_extension, - create_schema: lifecycle.create_schema, - load_sql: lifecycle.load_sql, - post_create_sql: lifecycle.post_create_sql, - startup_config: lifecycle.startup_config, - preload_required: lifecycle.preload_required, - restart_required: lifecycle.restart_required, - shared_memory_required: lifecycle.shared_memory_required, - } -} - -fn write_generated_extension_api(catalog: &ExtensionCatalog) -> Result<()> { - validate_wasix_sdk_extension_features(catalog)?; - let extensions = &catalog.extensions; - let mut text = String::new(); - text.push_str("// @generated by `cargo run -p xtask -- extensions generate`\n\n"); - text.push_str("use super::Extension;\n\n"); - - for extension in extensions { - let prefix = extension.rust_constant.as_str(); - let definition_const = format!("DEFINITION_{prefix}"); - let feature = wasix_extension_feature(extension); - let dependencies = api_dependencies(extension); - let native_support_modules = api_native_support_modules(extension)?; - let native_modules = native_support_modules - .iter() - .map(|(runtime_path, aot_name)| { - format!( - "super::ExtensionNativeModule {{ runtime_path: {runtime_path:?}, aot_name: {} }}", - option_string_literal(aot_name.as_deref()) - ) - }) - .collect::>() - .join(", "); - let aot_name = extension - .native_module_file - .as_ref() - .map(|_| format!("extension:{}", extension.sql_name)); - text.push_str(&format!( - "#[cfg(feature = {feature:?})]\nconst {definition_const}: Extension = Extension {{\n sql_name: {:?},\n native_support_modules: &[{native_modules}],\n native_module_file: {},\n aot_name: {},\n dependencies: &{},\n startup_config: &{},\n}};\n\n", - extension.sql_name, - option_string_literal(extension.native_module_file.as_deref()), - option_string_literal(aot_name.as_deref()), - rust_string_array(&dependencies), - rust_string_array(&extension.lifecycle.startup_config), - )); - } - - text.push_str("impl Extension {\n"); - for extension in extensions { - let prefix = extension.rust_constant.as_str(); - let feature = wasix_extension_feature(extension); - text.push_str(&format!( - " /// Select the `{}` artifact.\n #[cfg(feature = {feature:?})]\n pub const {prefix}: Self = DEFINITION_{prefix};\n", - extension.sql_name - )); - } - - let all = extensions - .iter() - .map(|extension| { - format!( - " #[cfg(feature = {:?})]\n Self::{},", - wasix_extension_feature(extension), - extension.rust_constant - ) - }) - .collect::>() - .join("\n"); - text.push_str(&format!( - "\n /// Extension artifacts enabled in this Cargo build.\n pub const ALL: &'static [Self] = &[\n{all}\n ];\n}}\n" - )); - - text.push_str( - "\n#[cfg(test)]\npub(super) fn creates_database_object_for_test(extension: Extension) -> bool {\n match extension.sql_name() {\n", - ); - for extension in extensions { - let feature = wasix_extension_feature(extension); - text.push_str(&format!( - " #[cfg(feature = {feature:?})]\n {:?} => {},\n", - extension.sql_name, extension.lifecycle.create_extension - )); - } - text.push_str(" _ => false,\n }\n}\n"); - - text.push_str( - "\n#[cfg(test)]\npub(super) fn activation_sql_for_test(extension: Extension) -> &'static [&'static str] {\n match extension.sql_name() {\n", - ); - for extension in extensions { - let feature = wasix_extension_feature(extension); - let activation_sql = api_test_activation_sql(extension); - text.push_str(&format!( - " #[cfg(feature = {feature:?})]\n {:?} => &{},\n", - extension.sql_name, - rust_string_array(&activation_sql) - )); - } - text.push_str(" _ => &[],\n }\n}\n"); - - let path = Path::new( - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/generated_extensions.rs", - ); - fs::write(path, text).with_context(|| format!("write {}", path.display()))?; - format_rust_source(path) -} - -fn validate_wasix_sdk_extension_features(catalog: &ExtensionCatalog) -> Result<()> { - let manifest_path = Path::new("src/bindings/wasix-rust/crates/oliphaunt-wasix/Cargo.toml"); - let manifest_text = fs::read_to_string(manifest_path) - .with_context(|| format!("read {}", manifest_path.display()))?; - let manifest: toml::Value = toml::from_str(&manifest_text) - .with_context(|| format!("parse {}", manifest_path.display()))?; - let features = manifest - .get("features") - .and_then(toml::Value::as_table) - .ok_or_else(|| anyhow!("{} is missing [features]", manifest_path.display()))?; - - for extension in &catalog.extensions { - let feature = wasix_extension_feature(extension); - let members = features - .get(&feature) - .and_then(toml::Value::as_array) - .ok_or_else(|| { - anyhow!( - "{} is missing WASIX SDK feature {feature} for extension {}", - manifest_path.display(), - extension.sql_name - ) - })?; - let members = members - .iter() - .filter_map(toml::Value::as_str) - .collect::>(); - ensure!( - members.contains("extensions"), - "WASIX SDK feature {feature} must enable the extensions carrier" - ); - let portable_feature = format!("liboliphaunt-wasix-portable/{feature}"); - ensure!( - members.contains(portable_feature.as_str()), - "WASIX SDK feature {feature} must enable bundled asset feature {portable_feature}" - ); - - for dependency in api_dependencies(extension) { - let dependency_extension = catalog - .extensions - .iter() - .find(|candidate| candidate.sql_name == dependency || candidate.id == dependency) - .ok_or_else(|| { - anyhow!( - "extension {} has unknown WASIX API dependency {dependency}", - extension.sql_name - ) - })?; - let dependency_feature = wasix_extension_feature(dependency_extension); - ensure!( - members.contains(dependency_feature.as_str()), - "WASIX SDK feature {feature} must enable dependency feature {dependency_feature} so Extension::by_sql_name can resolve it" - ); - } - } - Ok(()) -} - -fn wasix_extension_feature(extension: &ExtensionCatalogEntry) -> String { - format!("extension-{}", extension.sql_name.replace('_', "-")) -} - -fn api_test_activation_sql(extension: &ExtensionCatalogEntry) -> Vec { - let mut statements = Vec::new(); - if extension.lifecycle.create_extension { - if let Some(schema) = extension - .lifecycle - .create_schema - .as_deref() - .filter(|schema| *schema != "pg_catalog") - { - statements.push(format!( - "CREATE SCHEMA IF NOT EXISTS {};", - quote_sql_identifier(schema) - )); - } - let mut create = format!( - "CREATE EXTENSION IF NOT EXISTS {}", - quote_sql_identifier(&extension.sql_name) - ); - if let Some(schema) = extension.lifecycle.create_schema.as_deref() { - create.push_str(" WITH SCHEMA "); - create.push_str("e_sql_identifier(schema)); - } - create.push(';'); - statements.push(create); - } - statements.extend(extension.lifecycle.load_sql.iter().cloned()); - statements.extend(extension.lifecycle.post_create_sql.iter().cloned()); - statements -} - -fn quote_sql_identifier(identifier: &str) -> String { - format!("\"{}\"", identifier.replace('"', "\"\"")) -} - -fn format_rust_source(path: &Path) -> Result<()> { - let status = Command::new("rustfmt") - .arg(path) - .status() - .with_context(|| format!("run rustfmt on {}", path.display()))?; - ensure!( - status.success(), - "rustfmt failed for {} with status {status}", - path.display() - ); - Ok(()) -} - -fn rust_string_array(values: &[String]) -> String { - let items = values - .iter() - .map(|value| format!("{value:?}")) - .collect::>() - .join(", "); - format!("[{items}]") -} - -fn option_string_literal(value: Option<&str>) -> String { - value - .map(|value| format!("Some({value:?})")) - .unwrap_or_else(|| "None".to_owned()) -} - -fn discover_catalog() -> Result { - let mut catalog = read_source_catalog()?; - merge_source_owned_default_versions(&mut catalog)?; - catalog - .extensions - .sort_by(|left, right| left.id.cmp(&right.id)); - catalog.generated_from = catalog_inputs(); - Ok(catalog) -} - -fn read_source_catalog() -> Result { - read_source_catalog_at(Path::new(".")) -} - -fn read_source_catalog_at(repository_root: &Path) -> Result { - let path = repository_root.join(SOURCE_CATALOG_PATH); - let text = fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?; - let catalog: ExtensionCatalog = - serde_json::from_str(&text).with_context(|| format!("parse {}", path.display()))?; - ensure!( - catalog.generated_from.is_empty(), - "{} is a curated input and must not contain generated-from", - path.display() - ); - for extension in &catalog.extensions { - ensure!( - extension - .control - .as_ref() - .and_then(|control| control.default_version.as_ref()) - .is_none(), - "{} extension {} must not own control.default-version; use source-owned extension metadata", - path.display(), - extension.id - ); - } - Ok(catalog) -} - -fn merge_source_owned_default_versions(catalog: &mut ExtensionCatalog) -> Result<()> { - let versions = source_owned_default_versions()?; - let catalog_sql_names = catalog - .extensions - .iter() - .map(|extension| extension.sql_name.as_str()) - .collect::>(); - for sql_name in versions.keys() { - ensure!( - catalog_sql_names.contains(sql_name.as_str()), - "source-owned default-version metadata names unknown SQL extension {sql_name}" - ); - } - - for extension in &mut catalog.extensions { - let version = versions.get(extension.sql_name.as_str()); - if extension.lifecycle.create_extension { - let version = version.ok_or_else(|| { - anyhow!( - "extension {} creates a SQL extension but has no source-owned default-version metadata", - extension.id - ) - })?; - let control = extension.control.as_mut().ok_or_else(|| { - anyhow!( - "extension {} creates a SQL extension but has no structural control metadata", - extension.id - ) - })?; - control.default_version = Some(version.clone()); - } else { - ensure!( - version.is_none(), - "module-only extension {} must not declare a control default-version", - extension.id - ); - } - } - Ok(()) -} - -fn source_owned_default_versions() -> Result> { - source_owned_default_versions_at(Path::new(".")) -} - -fn source_owned_default_versions_at(repository_root: &Path) -> Result> { - let mut versions = BTreeMap::new(); - let contrib_path = repository_root.join(CONTRIB_MANIFEST_PATH); - let contrib_text = fs::read_to_string(&contrib_path) - .with_context(|| format!("read {}", contrib_path.display()))?; - let contrib: ContribSourceManifest = toml::from_str(&contrib_text) - .with_context(|| format!("parse {}", contrib_path.display()))?; - for row in contrib.extensions { - let Some(version) = row.default_version else { - continue; - }; - validate_default_version(&version, &format!("{} {}", contrib_path.display(), row.id))?; - let previous = versions.insert(row.sql_name.clone(), version); - ensure!( - previous.is_none(), - "{} repeats default-version metadata for {}", - contrib_path.display(), - row.sql_name - ); - } - - let external_root = repository_root.join(EXTERNAL_EXTENSION_RECIPE_ROOT); - let mut source_paths = fs::read_dir(&external_root) - .with_context(|| format!("read {}", external_root.display()))? - .filter_map(|entry| entry.ok()) - .map(|entry| entry.path().join("source.toml")) - .filter(|path| path.is_file()) - .collect::>(); - source_paths.sort(); - for source_path in source_paths { - let text = fs::read_to_string(&source_path) - .with_context(|| format!("read {}", source_path.display()))?; - let source: ExternalSourceMetadata = - toml::from_str(&text).with_context(|| format!("parse {}", source_path.display()))?; - let Some(control) = source.extension_control else { - continue; - }; - validate_default_version( - &control.default_version, - &format!("{} extension-control", source_path.display()), - )?; - ensure!( - !control.source_path.is_empty() && !Path::new(&control.source_path).is_absolute(), - "{} extension-control.source-path must be a non-empty relative path", - source_path.display() - ); - let expected_control_file = Path::new(EXTERNAL_EXTENSION_CHECKOUT_ROOT) - .join(&source.name) - .join(&control.source_path) - .to_string_lossy() - .replace('\\', "/"); - let catalog_control_file = read_source_catalog_at(repository_root)? - .extensions - .into_iter() - .find(|extension| extension.sql_name == control.sql_name) - .and_then(|extension| extension.control_file); - ensure!( - catalog_control_file.as_deref() == Some(expected_control_file.as_str()), - "{} extension-control provenance resolves to {}, but {} declares {:?}", - source_path.display(), - expected_control_file, - SOURCE_CATALOG_PATH, - catalog_control_file - ); - if let Some(source_default_version) = control.source_default_version.as_deref() { - ensure!( - source_default_version == "@EXTVERSION@", - "{} has unsupported templated source default-version {source_default_version:?}", - source_path.display() - ); - } - let previous = versions.insert(control.sql_name.clone(), control.default_version); - ensure!( - previous.is_none(), - "source metadata repeats default-version for {}", - control.sql_name - ); - } - Ok(versions) -} - -fn validate_default_version(version: &str, context: &str) -> Result<()> { - ensure!( - !version.is_empty() - && version.len() <= 128 - && !version.contains("--") - && version - .chars() - .all(|character| character.is_ascii_alphanumeric() - || matches!(character, '.' | '_' | '-')), - "{context} has invalid literal default-version {version:?}" - ); - Ok(()) -} - -fn catalog_inputs() -> Vec { - vec![ - CatalogInput { - name: "postgres18-source".to_owned(), - path: "src/postgres/versions/18/source.toml".to_owned(), - }, - CatalogInput { - name: "extension-catalog".to_owned(), - path: SOURCE_CATALOG_PATH.to_owned(), - }, - CatalogInput { - name: "postgres-contrib".to_owned(), - path: CONTRIB_MANIFEST_PATH.to_owned(), - }, - CatalogInput { - name: "external-extension-recipes".to_owned(), - path: POSTGRES_OTHER_EXTENSIONS.to_owned(), - }, - ] -} - -fn validate_catalog(catalog: &ExtensionCatalog) -> Result<()> { - ensure!( - catalog.format_version == 1, - "extension catalog format must be 1" - ); - let mut ids = BTreeSet::new(); - let mut sql_names = BTreeSet::new(); - for extension in &catalog.extensions { - ensure!( - ids.insert(extension.id.as_str()), - "duplicate extension id {}", - extension.id - ); - ensure!( - extension.id != "live", - "live must not be included in SQL extension catalog" - ); - ensure!( - sql_names.insert(extension.sql_name.as_str()), - "duplicate SQL extension name {}", - extension.sql_name - ); - ensure!( - extension.source_kind != "oliphaunt-plugin", - "supported extension {} is not a SQL extension", - extension.id - ); - ensure!( - !extension.tests.is_empty(), - "supported extension {} must have a smoke test source", - extension.id - ); - ensure!( - extension.lifecycle.create_extension || !extension.lifecycle.load_sql.is_empty(), - "supported extension {} must declare a lifecycle operation", - extension.id - ); - for dependency in &extension.dependencies { - if runtime_provided_sql_extensions().contains(&dependency.as_str()) { - continue; - } - ensure!( - catalog - .extensions - .iter() - .any(|candidate| candidate.sql_name == *dependency - || candidate.id == *dependency), - "{} depends on unknown extension {}", - extension.id, - dependency - ); - } - } - - for required in [ - "vector", "pg_trgm", "hstore", "pgcrypto", "pgtap", "postgis", - ] { - ensure!( - catalog - .extensions - .iter() - .any(|extension| extension.id == required || extension.sql_name == required), - "extension catalog is missing required Oliphaunt extension {required}" - ); - } - Ok(()) -} - -fn api_dependencies(extension: &ExtensionCatalogEntry) -> Vec { - extension - .dependencies - .iter() - .filter(|dependency| !runtime_provided_sql_extensions().contains(&dependency.as_str())) - .cloned() - .collect() -} - -fn api_native_support_modules( - extension: &ExtensionCatalogEntry, -) -> Result)>> { - Ok(wasix_native_support_modules(&extension.sql_name)? - .into_iter() - .map(|module| { - ( - module.runtime_path, - Some(format!("extension:{}:{}", extension.sql_name, module.name)), - ) - }) - .collect()) -} - -fn wasix_native_support_modules(sql_name: &str) -> Result> { - let mut modules = wasix_target_recipe(sql_name)? - .map(|recipe| recipe.native_support_modules) - .unwrap_or_default(); - modules.sort_by(|left, right| left.name.cmp(&right.name)); - Ok(modules) -} - -fn wasix_target_recipe(sql_name: &str) -> Result> { - wasix_target_recipe_at(Path::new("."), sql_name) -} - -fn wasix_target_recipe_at( - repository_root: &Path, - sql_name: &str, -) -> Result> { - let path = repository_root - .join(EXTERNAL_EXTENSION_RECIPE_ROOT) - .join(sql_name) - .join("targets/wasix.toml"); - if !path.exists() { - return Ok(None); - } - let text = fs::read_to_string(&path).with_context(|| format!("read {}", path.display()))?; - let mut recipe: ExtensionTargetRecipe = - toml::from_str(&text).with_context(|| format!("parse {}", path.display()))?; - recipe - .native_support_modules - .sort_by(|left, right| left.name.cmp(&right.name)); - recipe.excluded_sql_extensions.sort(); - Ok(Some(recipe)) -} - -fn runtime_provided_sql_extensions() -> &'static [&'static str] { - &["plpgsql"] -} - -pub(crate) fn is_pgxs_style_build_kind(kind: &str) -> bool { - matches!(kind, "pgxs-external" | "pgxs-sql-only") -} - -pub(crate) fn is_recipe_staged_build_kind(kind: &str) -> bool { - matches!(kind, "autotools") -} - -fn build_kind( - extension: &ExtensionCatalogEntry, - wasix_target: Option<&ExtensionTargetRecipe>, -) -> Result { - match extension.source_kind.as_str() { - "postgres-contrib" => Ok("postgres-contrib".to_owned()), - "oliphaunt-other-extension" => { - let Some(kind) = wasix_target - .and_then(|target| target.build_kind.as_deref()) - .filter(|kind| !kind.is_empty()) - else { - return Ok("pgxs-external".to_owned()); - }; - ensure!( - is_pgxs_style_build_kind(kind), - "extension {} has unsupported oliphaunt-other-extension WASIX build kind {kind}", - extension.id - ); - Ok(kind.to_owned()) - } - "postgis" => { - let kind = wasix_target - .and_then(|target| target.build_kind.as_deref()) - .ok_or_else(|| { - anyhow!("extension {} has no WASIX target build_kind", extension.id) - })?; - ensure!( - is_recipe_staged_build_kind(kind), - "extension {} has unsupported recipe-staged WASIX build kind {kind}", - extension.id - ); - Ok(kind.to_owned()) - } - other => bail!( - "extension {} has unsupported source kind {other}", - extension.id - ), - } -} - -fn extension_source_dir(extension: &ExtensionCatalogEntry) -> String { - extension_source_dir_for(&extension.id, &extension.source_kind) -} - -fn pgxs_make_args(extension: &ExtensionCatalogEntry) -> Vec { - match extension.id.as_str() { - // AGE's graphid SQL is target-ABI sensitive. wasm32/WASIX has a 4-byte - // Datum, so AGE must generate pass-by-reference graphid SQL. - "age" => vec!["SIZEOF_DATUM=4".to_owned()], - _ => Vec::new(), - } -} - -fn extension_source_dir_for(id: &str, source_kind: &str) -> String { - match source_kind { - "postgres-contrib" => Path::new(POSTGRES_CONTRIB) - .join(extension_contrib_dir_name(id)) - .to_string_lossy() - .replace('\\', "/"), - "oliphaunt-other-extension" if id == "vector" => PGVECTOR_CHECKOUT.to_owned(), - "oliphaunt-other-extension" | "postgis" => Path::new(EXTERNAL_EXTENSION_CHECKOUT_ROOT) - .join(id) - .to_string_lossy() - .replace('\\', "/"), - _ => String::new(), - } -} - -fn extension_contrib_dir_name(id: &str) -> String { - match id { - "uuid_ossp" => "uuid-ossp".to_owned(), - other => other.to_owned(), - } -} - -fn shell_words(words: &[String]) -> String { - if words.is_empty() { - "-".to_owned() - } else { - words.join(" ") - } -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -struct ExtensionCatalog { - format_version: u32, - #[serde(default)] - generated_from: Vec, - extensions: Vec, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -struct CatalogInput { - name: String, - path: String, -} - -struct BuildPlanTexts { - contrib_tsv: String, - pgxs_tsv: String, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -struct ExtensionBuildPlan { - format_version: u32, - generated_from: Vec, - extensions: Vec, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -struct ExtensionBuildPlanEntry { - id: String, - sql_name: String, - display_name: String, - source_kind: String, - build_kind: String, - #[serde(skip_serializing_if = "Option::is_none")] - build_script: Option, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - required_build_files: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - required_build_globs: Vec, - source_dir: String, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - make_args: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - contrib_dir: Option, - #[serde(skip_serializing_if = "Option::is_none")] - module_file: Option, - archive: String, - #[serde(skip_serializing_if = "Option::is_none")] - control_file: Option, - dependencies: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - native_support_modules: Vec, - #[serde(default, skip_serializing_if = "Vec::is_empty")] - excluded_sql_extensions: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - staging: Option, - load_order: Vec, - lifecycle: ExtensionLifecycle, - tests: Vec, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)] -struct ExtensionTargetRecipe { - #[serde(default)] - build_kind: Option, - #[serde(default)] - build_script: Option, - #[serde(default)] - required_build_files: Vec, - #[serde(default)] - required_build_globs: Vec, - #[serde(default)] - native_support_modules: Vec, - #[serde(default)] - excluded_sql_extensions: Vec, - #[serde(default)] - staging: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(deny_unknown_fields)] -pub(crate) struct NativeSupportModuleSpec { - pub(crate) name: String, - #[serde(rename = "runtime-path", alias = "runtime_path")] - pub(crate) runtime_path: String, - #[serde(rename = "build-path", alias = "build_path")] - pub(crate) build_path: String, - #[serde(rename = "aot-file", alias = "aot_file")] - pub(crate) aot_file: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(deny_unknown_fields)] -pub(crate) struct ExtensionStagingSpec { - #[serde(rename = "module-source-dir", alias = "module_source_dir")] - pub(crate) module_source_dir: Option, - #[serde(rename = "control-source", alias = "control_source")] - pub(crate) control_source: Option, - #[serde(rename = "sql-source-dir", alias = "sql_source_dir")] - pub(crate) sql_source_dir: Option, - #[serde(default, rename = "data-dirs", alias = "data_dirs")] - pub(crate) data_dirs: Vec, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(deny_unknown_fields)] -pub(crate) struct ExtensionStagingDataDirSpec { - pub(crate) source: String, - pub(crate) destination: String, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -struct ExtensionCatalogEntry { - id: String, - sql_name: String, - rust_constant: String, - display_name: String, - source_kind: String, - upstream_import_name: String, - #[serde(skip_serializing_if = "Option::is_none")] - upstream_import_path: Option, - #[serde(skip_serializing_if = "Option::is_none")] - package_export: Option, - tags: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - bundle_size: Option, - #[serde(skip_serializing_if = "Option::is_none")] - control_file: Option, - #[serde(skip_serializing_if = "Option::is_none")] - control: Option, - dependencies: Vec, - load_order: Vec, - lifecycle: ExtensionLifecycle, - tests: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - native_module_file: Option, - notes: Vec, -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -struct ControlMetadata { - #[serde(skip_serializing_if = "Option::is_none")] - default_version: Option, - #[serde(skip_serializing_if = "Option::is_none")] - module_pathname: Option, - requires: Vec, - #[serde(skip_serializing_if = "Option::is_none")] - relocatable: Option, - #[serde(skip_serializing_if = "Option::is_none")] - schema: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -pub(crate) struct ExtensionLifecycle { - pub(crate) create_extension: bool, - #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) create_schema: Option, - pub(crate) load_sql: Vec, - pub(crate) post_create_sql: Vec, - pub(crate) startup_config: Vec, - pub(crate) preload_required: bool, - pub(crate) restart_required: bool, - pub(crate) shared_memory_required: bool, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "kebab-case")] -struct ContribSourceManifest { - #[serde(default)] - extensions: Vec, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "kebab-case")] -struct ContribSourceExtension { - id: String, - sql_name: String, - #[serde(default)] - default_version: Option, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "kebab-case")] -struct ExternalSourceMetadata { - name: String, - #[serde(default)] - extension_control: Option, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "kebab-case")] -struct ExternalExtensionControl { - sql_name: String, - source_path: String, - #[serde(default)] - source_default_version: Option, - default_version: String, -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn extension_build_plan_tsv_freshness_is_checkout_line_ending_stable() { - let expected = "# id\tsql_name\tcontrib_dir\tmodule_file\tarchive\namcheck\tamcheck\tamcheck\tamcheck.so\textensions/amcheck.tar.zst\n"; - let windows_checkout = "# id\tsql_name\tcontrib_dir\tmodule_file\tarchive\r\namcheck\tamcheck\tamcheck\tamcheck.so\textensions/amcheck.tar.zst\r\n"; - - assert!(extension_build_plan_tsv_matches_source_control( - windows_checkout, - expected - )); - } - - #[test] - fn generated_catalog_versions_are_merged_from_non_generated_source_metadata() -> Result<()> { - assert_ne!(SOURCE_CATALOG_PATH, CATALOG_PATH); - let repo_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../.."); - let source_catalog = read_source_catalog_at(&repo_root)?; - let versions = source_owned_default_versions_at(&repo_root)?; - let generated_text = fs::read_to_string(repo_root.join(CATALOG_PATH))?; - let catalog: ExtensionCatalog = serde_json::from_str(&generated_text)?; - - assert!(source_catalog.generated_from.is_empty()); - assert!(source_catalog.extensions.iter().all(|extension| { - extension - .control - .as_ref() - .and_then(|control| control.default_version.as_ref()) - .is_none() - })); - - assert_eq!( - catalog - .generated_from - .iter() - .find(|input| input.name == "extension-catalog") - .map(|input| input.path.as_str()), - Some(SOURCE_CATALOG_PATH) - ); - assert!( - !catalog.generated_from.iter().any(|input| { - input.name == "postgres-contrib" && input.path == POSTGRES_CONTRIB - }) - ); - for extension in catalog.extensions { - let generated = extension - .control - .as_ref() - .and_then(|control| control.default_version.as_ref()); - assert_eq!(generated, versions.get(&extension.sql_name)); - if let Some(version) = generated { - assert!(!version.contains('@')); - } - } - Ok(()) - } - - #[test] - fn generated_postgis_build_spec_preserves_wasix_target_recipe_metadata() -> Result<()> { - let repo_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../.."); - let catalog = read_source_catalog_at(&repo_root)?; - let specs = build_specs_at(&catalog, &repo_root)?; - let postgis = specs - .iter() - .find(|extension| extension.sql_name == "postgis") - .expect("postgis must be a supported build spec"); - - assert_eq!(postgis.build_kind, "autotools"); - assert_eq!( - postgis.build_script.as_deref(), - Some("src/extensions/external/postgis/tools/build_wasix.sh") - ); - assert_eq!( - postgis.required_build_files, - vec![ - "postgis/postgis-3.so", - "postgis/liboliphaunt_postgis_deps.so", - "extensions/postgis/postgis.control", - "share/proj/proj.db", - ] - ); - assert_eq!( - postgis.required_build_globs, - vec!["extensions/postgis/sql/postgis--*.sql"] - ); - assert_eq!( - postgis - .native_support_modules - .iter() - .map(|module| module.name.as_str()) - .collect::>(), - vec!["postgis_deps"] - ); - assert!( - postgis - .excluded_sql_extensions - .contains(&"postgis_raster".to_owned()) - ); - - let staging = postgis - .staging - .as_ref() - .expect("postgis must declare WASIX staging metadata"); - assert_eq!( - staging.module_source_dir.as_deref(), - Some("postgis/postgis") - ); - assert_eq!( - staging.control_source.as_deref(), - Some("postgis/extensions/postgis/postgis.control") - ); - assert_eq!( - staging.sql_source_dir.as_deref(), - Some("postgis/extensions/postgis/sql") - ); - assert_eq!(staging.data_dirs.len(), 1); - assert_eq!(staging.data_dirs[0].source, "postgis/share/proj"); - assert_eq!(staging.data_dirs[0].destination, "share/proj"); - Ok(()) - } -} diff --git a/tools/xtask/src/main.rs b/tools/xtask/src/main.rs deleted file mode 100644 index e06f41cb9..000000000 --- a/tools/xtask/src/main.rs +++ /dev/null @@ -1,460 +0,0 @@ -use std::collections::{BTreeMap, BTreeSet}; -use std::env; -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; - -use anyhow::{Context, Result, anyhow, bail, ensure}; -use serde::Serialize; -use sha2::{Digest, Sha256}; -use walkdir::WalkDir; - -mod aot_serializer; -mod asset_checks; -mod asset_io; -mod asset_manifest; -mod asset_pipeline; -mod cluster_seed_runner; -mod extension_catalog; -mod fs_utils; -mod postgres_guard; -mod release_workspace; -mod source_spine; - -use crate::aot_serializer::aot_serializer; -use crate::asset_checks::*; -#[cfg(test)] -use crate::asset_io::ensure_aot_manifest_matches_source_lane; -use crate::asset_io::{download_assets, install_local_assets, run_asset_smoke_tests}; -use crate::asset_manifest::*; -use crate::asset_pipeline::*; -use crate::fs_utils::*; -use crate::postgres_guard::{ - check_postgres_source_spine, check_prepared_postgres_source, check_rust_startup_abi_boundary, - check_source_lane_isolation, check_wasix_shell_script_syntax, postgres_default_source_dir, - postgres_expected_source_fingerprint, -}; -use crate::release_workspace::{package_release_assets, stage_release_workspace}; -use crate::source_spine::{ - SourceFetchScope, check_source_spine_for_source_lane, check_sources_manifest, - check_sources_manifest_for_wasix_asset_build, fetch_pinned_sources_for_source_lane, - load_sources_manifest, load_wasix_toolchain_manifest, validate_sources_manifest, -}; - -const WASIX_BUILD_SOURCE_ROOT: &str = "src/runtimes/liboliphaunt/wasix/assets/build"; -const WASIX_GENERATED_BUILD_DIR: &str = "target/oliphaunt-wasix/wasix-build/build"; -const WASIX_GENERATED_WORK_DIR: &str = "target/oliphaunt-wasix/wasix-build/work"; -const WASIX_DOCKER_BUILD_DIR: &str = "target/oliphaunt-wasix/wasix-build/work/docker-oliphaunt"; -const WASIX_POSTGRES_WORK_DIR: &str = "target/oliphaunt-wasix/wasix-build"; -const WASIX_POSTGRES_GENERATED_BUILD_DIR: &str = WASIX_GENERATED_BUILD_DIR; -const WASIX_POSTGRES_DOCKER_BUILD_DIR: &str = WASIX_DOCKER_BUILD_DIR; -const WASIX_PATCHED_SOURCE_DIR: &str = - "target/oliphaunt-wasix/wasix-build/work/postgres18-wasix-src"; -const WASIX_BUILD_MANIFEST_PATH: &str = "target/oliphaunt-wasix/wasix-build/build/outputs.json"; -const WASIX_POSTGRES_BUILD_MANIFEST_PATH: &str = WASIX_BUILD_MANIFEST_PATH; -const WASIX_BRIDGE_PATH: &str = - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_shim/oliphaunt_wasix_bridge.c"; -const POSTGRES_SOURCE_MANIFEST_PATH: &str = - "src/runtimes/liboliphaunt/wasix/assets/build/postgres/source.toml"; -const POSTGRES_SHARED_SOURCE_MANIFEST_PATH: &str = "src/postgres/versions/18/source.toml"; -const POSTGRES_PATCH_DIR: &str = "src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches"; -const POSTGRES_PATCH_SERIES_PATH: &str = - "src/runtimes/liboliphaunt/wasix/assets/build/postgres/patches/series"; -const POSTGRES_EXPERIMENT_DISPOSITION_PATH: &str = - "src/runtimes/liboliphaunt/wasix/assets/build/postgres/experiment-patch-disposition.toml"; -const POSTGRES_PREPARE_SCRIPT: &str = - "src/runtimes/liboliphaunt/wasix/assets/build/prepare_postgres_source.sh"; -const DEFAULT_SOURCE_LANE: &str = "stable"; -const DEFAULT_ASSET_BUILD_PROFILE: &str = "release"; -const SOURCE_CHECKOUT_ROOT: &str = "target/oliphaunt-sources/checkouts"; -const GENERATED_ASSETS_DIR: &str = "target/oliphaunt-wasix/assets"; -const GENERATED_AOT_DIR: &str = "target/oliphaunt-wasix/aot"; -const RUNTIME_MODULE_ARCHIVE_MEMBER: &str = "oliphaunt/bin/postgres"; -const ASSET_CRATE_PAYLOAD_DIR: &str = "src/runtimes/liboliphaunt/wasix/crates/assets/payload"; -const RELEASE_STAGE_DIR: &str = "target/oliphaunt-wasix/release"; -const RELEASE_ASSET_BUNDLE_DIR: &str = "target/oliphaunt-wasix/release-assets"; -const LEGACY_STATIC_WASI_ARCHIVE: &str = concat!("assets/", "oliphaunt-", "wasi.tar.zst"); -const RUST_HOST_REQUIRED_RUNTIME_EXPORTS: &[&str] = &[ - "_start", - "oliphaunt_wasix_set_active", - "oliphaunt_wasix_start", - "oliphaunt_wasix_get_proc_port", - "ProcessStartupPacket", - "oliphaunt_wasix_send_conn_data", - "oliphaunt_wasix_pq_flush", - "pq_buffer_remaining_data", - "PostgresMainLoopOnce", - "PostgresSendReadyForQueryIfNecessary", - "PostgresMainLongJmp", - "oliphaunt_wasix_protocol_stream_active", - "oliphaunt_wasix_input_reset", - "oliphaunt_wasix_input_reserve", - "oliphaunt_wasix_input_commit", - "oliphaunt_wasix_input_available", - "oliphaunt_wasix_output_reset", - "oliphaunt_wasix_output_len", - "oliphaunt_wasix_output_data", - "oliphaunt_wasix_output_contains_error", -]; -const RUST_HOST_OPTIONAL_RUNTIME_EXPORTS: &[&str] = &[ - "oliphaunt_wasix_set_force_host_error_recovery", - "oliphaunt_wasix_run_atexit_funcs", - "oliphaunt_wasix_set_protocol_transport", -]; -const RUNTIME_EXPORT_LIST_COMPAT_EXPORTS: &[&str] = &[ - "oliphaunt_wasix_set_force_host_error_recovery", - "oliphaunt_wasix_set_protocol_transport", -]; -const REQUIRED_RUNTIME_ABI_EXPORTS: &[&str] = &[ - "_start", - "oliphaunt_wasix_set_active", - "oliphaunt_wasix_start", - "oliphaunt_wasix_get_proc_port", - "ProcessStartupPacket", - "oliphaunt_wasix_send_conn_data", - "oliphaunt_wasix_pq_flush", - "pq_buffer_remaining_data", - "PostgresMainLoopOnce", - "PostgresSendReadyForQueryIfNecessary", - "PostgresMainLongJmp", - "oliphaunt_wasix_set_force_host_error_recovery", - "oliphaunt_wasix_protocol_stream_active", - "oliphaunt_wasix_input_reset", - "oliphaunt_wasix_input_reserve", - "oliphaunt_wasix_input_commit", - "oliphaunt_wasix_input_available", - "oliphaunt_wasix_output_reset", - "oliphaunt_wasix_output_len", - "oliphaunt_wasix_output_data", - "oliphaunt_wasix_output_contains_error", - "oliphaunt_wasix_set_protocol_transport", -]; -fn main() -> Result<()> { - let mut args = env::args().skip(1); - match args.next().as_deref() { - Some("assets") => assets(args.collect()), - Some("extensions") => extension_catalog::extensions(args.collect()), - Some("release") => release(args.collect()), - Some("aot-serializer") => aot_serializer(args.collect()), - Some("help") | None => { - print_usage(); - Ok(()) - } - Some(other) => bail!("unknown xtask command: {other}"), - } -} - -fn assets(args: Vec) -> Result<()> { - match args.first().map(String::as_str) { - Some("check") => { - let strict_local = args.iter().any(|arg| arg == "--strict-local"); - let strict_generated = args.iter().any(|arg| arg == "--strict-generated"); - let release_staged = is_release_staged_workspace(); - let manifest = check_sources_manifest(strict_local)?; - check_source_free_repo()?; - check_no_legacy_runtime_shims()?; - check_production_wasix_build_inputs()?; - check_postgres_source_spine()?; - check_source_lane_isolation()?; - check_rust_startup_abi_boundary()?; - check_canonical_asset_layout(strict_generated)?; - check_generated_manifest(&manifest, strict_generated)?; - if strict_generated { - verify_asset_manifest_hashes()?; - verify_generated_extension_surface()?; - } - if !release_staged { - extension_catalog::check_catalog_file(strict_generated)?; - extension_catalog::check_build_plan_file(strict_generated)?; - } - check_generated_wasix_export_list(strict_generated) - } - Some("verify-committed") => verify_committed_assets(), - Some("audit-upstream") => { - let strict = args.iter().any(|arg| arg == "--strict"); - let manifest = check_sources_manifest(false)?; - audit_upstream_fixes(&manifest, strict) - } - Some("build") => { - let manifest = check_sources_manifest(false)?; - let profile = value_after(&args, "--profile").unwrap_or(DEFAULT_ASSET_BUILD_PROFILE); - let target = value_after(&args, "--target-triple").unwrap_or(env::consts::ARCH); - build_asset_spine(&manifest, profile, target, &args) - } - Some("cluster-seeds") => { - let manifest = check_sources_manifest(false)?; - let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); - generate_cluster_seed_assets(&manifest, source_lane) - } - Some("fetch") => { - let manifest = load_sources_manifest()?; - validate_sources_manifest(&manifest)?; - let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); - let prepare_postgres_source = !args.iter().any(|arg| arg == "--skip-postgres-prepare"); - let source_scope = - SourceFetchScope::parse(value_after(&args, "--scope").unwrap_or("production-all"))?; - fetch_pinned_sources_for_source_lane( - &manifest, - source_lane, - prepare_postgres_source, - source_scope, - ) - } - Some("release-build") => { - let manifest = check_sources_manifest_for_wasix_asset_build(&args)?; - let profile = value_after(&args, "--profile").unwrap_or(DEFAULT_ASSET_BUILD_PROFILE); - let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple()); - release_build_assets(&manifest, profile, target, &args) - } - Some("build-host") => { - let manifest = check_sources_manifest_for_wasix_asset_build(&args)?; - release_build_assets( - &manifest, - DEFAULT_ASSET_BUILD_PROFILE, - host_target_triple(), - &args, - ) - } - Some("download") => download_assets(&args), - Some("install-local") => install_local_assets(&args), - Some("update-root-metadata") => update_staged_root_asset_metadata(Path::new(".")), - Some("ci-matrix") => print_aot_ci_matrix(&args), - Some("ci-artifacts") => print_ci_artifact_names(), - Some("aot-targets") => print_supported_aot_targets(), - Some("internal-packages") => print_internal_asset_packages(), - Some("package") => { - let manifest = check_sources_manifest(false)?; - let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple()); - let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); - if args.iter().any(|arg| arg == "--skip-aot") { - package_assets_without_aot(&manifest, source_lane) - } else { - package_assets(&manifest, target, source_lane) - } - } - Some("package-aot") => { - let manifest = check_sources_manifest(false)?; - let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple()); - let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); - package_aot_only(&manifest, target, source_lane) - } - Some("package-extension-aot") => { - let manifest = check_sources_manifest(false)?; - let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple()); - let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); - package_extension_aot_artifacts(&manifest, target, source_lane) - } - Some("check-aot") => { - let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple()); - let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); - check_aot_package_manifest(target, source_lane) - } - Some("export-list") => { - let write = args.iter().any(|arg| arg == "--write"); - let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); - generate_wasix_export_list(write, source_lane) - } - Some("aot") => { - let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple()); - let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); - generate_aot_artifacts(target, source_lane) - } - Some("source-spine") => { - let check_patch = args.iter().any(|arg| arg == "--check-patch-applies"); - let source_lane = canonical_source_lane( - value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE), - )?; - let manifest = load_sources_manifest()?; - validate_sources_manifest(&manifest)?; - println!( - "validated {} pinned asset sources for {source_lane}", - manifest.sources.len() - ); - let strict_local = source_lane == DEFAULT_SOURCE_LANE - || args.iter().any(|arg| arg == "--strict-local"); - check_source_spine_for_source_lane(&manifest, source_lane, strict_local, check_patch) - } - Some("smoke") => run_asset_smoke_tests(&args[1..]), - Some(other) => bail!("unknown assets subcommand: {other}"), - None => { - bail!( - "usage: cargo run -p xtask -- assets " - ) - } - } -} - -fn release(args: Vec) -> Result<()> { - match args.first().map(String::as_str) { - Some("stage") => stage_release_workspace(), - Some("package-assets") => package_release_assets(), - Some(other) => bail!("unknown release subcommand: {other}"), - None => bail!("usage: cargo run -p xtask -- release "), - } -} - -fn host_target_triple() -> &'static str { - #[cfg(all(target_os = "macos", target_arch = "aarch64"))] - { - return "aarch64-apple-darwin"; - } - #[cfg(all(target_os = "linux", target_arch = "x86_64"))] - { - return "x86_64-unknown-linux-gnu"; - } - #[cfg(all(target_os = "linux", target_arch = "aarch64"))] - { - return "aarch64-unknown-linux-gnu"; - } - #[cfg(all(target_os = "windows", target_arch = "x86_64"))] - { - return "x86_64-pc-windows-msvc"; - } - #[allow(unreachable_code)] - "unsupported" -} - -fn ensure_eq(actual: &str, expected: &str, field: &str) -> Result<()> { - if actual != expected { - bail!("{field} must be '{expected}', got '{actual}'"); - } - Ok(()) -} - -fn ensure_contains(values: &[String], expected: &str, field: &str) -> Result<()> { - if !values.iter().any(|value| value == expected) { - bail!("{field} must contain '{expected}'"); - } - Ok(()) -} - -fn ensure_no_flag_contains(values: &[String], forbidden: &str, field: &str) -> Result<()> { - let forbidden_lower = forbidden.to_ascii_lowercase(); - if let Some(value) = values - .iter() - .find(|value| value.to_ascii_lowercase().contains(&forbidden_lower)) - { - bail!("{field} must not contain '{forbidden}', got '{value}'"); - } - Ok(()) -} - -fn command_output(command: &str, args: &[&str], cwd: &Path) -> Result { - let output = Command::new(command) - .args(args) - .current_dir(cwd) - .stderr(Stdio::inherit()) - .output() - .map_err(|err| anyhow!("failed to spawn {command}: {err}"))?; - if !output.status.success() { - bail!("{command} {} failed with {}", args.join(" "), output.status); - } - String::from_utf8(output.stdout).context("command output was not valid UTF-8") -} - -pub(crate) fn value_after<'a>(args: &'a [String], name: &str) -> Option<&'a str> { - args.windows(2) - .find(|window| window[0] == name) - .map(|window| window[1].as_str()) -} - -fn run(command: &str, args: &[&str]) -> Result<()> { - let mut command = command_for_host(command); - command.args(args); - run_command(&mut command) -} - -fn command_for_host(command: &str) -> Command { - if cfg!(windows) - && Path::new(command) - .extension() - .and_then(|ext| ext.to_str()) - .is_some_and(|ext| ext.eq_ignore_ascii_case("sh")) - { - let mut shell = Command::new(windows_bash_path()); - shell.arg("--noprofile").arg("--norc"); - shell.arg(command); - return shell; - } - Command::new(command) -} - -#[cfg(windows)] -fn windows_bash_path() -> PathBuf { - for path in [ - r"C:\Program Files\Git\bin\bash.exe", - r"C:\Program Files\Git\usr\bin\bash.exe", - ] { - let path = PathBuf::from(path); - if path.is_file() { - return path; - } - } - PathBuf::from("bash") -} - -#[cfg(not(windows))] -fn windows_bash_path() -> &'static str { - "bash" -} - -fn run_command(command: &mut Command) -> Result<()> { - let status = command - .status() - .map_err(|err| anyhow!("failed to spawn command: {err}"))?; - if !status.success() { - bail!("command failed with {status}"); - } - Ok(()) -} - -fn print_usage() { - eprintln!("usage:"); - eprintln!(" cargo run -p xtask -- assets check [--strict-local] [--strict-generated]"); - eprintln!(" cargo run -p xtask -- assets verify-committed"); - eprintln!(" cargo run -p xtask -- assets audit-upstream [--strict]"); - eprintln!( - " cargo run -p xtask -- assets source-spine [--strict-local] [--check-patch-applies]" - ); - eprintln!( - " cargo run -p xtask -- assets fetch [--skip-postgres-prepare] [--scope production-all|all|native-runtime|wasix-runtime|extensions]" - ); - eprintln!(" cargo run -p xtask --features aot-serializer -- assets build-host"); - eprintln!( - " cargo run -p xtask -- assets download --sha [--required-job ] --target " - ); - eprintln!(" cargo run -p xtask -- assets download --run-id --all-targets"); - eprintln!(" cargo run -p xtask -- assets download --release --target "); - eprintln!(" cargo run -p xtask -- assets install-local --target-triple "); - eprintln!( - " cargo run -p xtask -- assets ci-matrix [--target ] [--github-output]" - ); - eprintln!(" cargo run -p xtask -- assets ci-artifacts"); - eprintln!(" cargo run -p xtask -- assets aot-targets"); - eprintln!(" cargo run -p xtask -- assets internal-packages"); - eprintln!( - " cargo run -p xtask -- assets build --profile release --target-triple [--execute]" - ); - eprintln!(" cargo run -p xtask --features cluster-seed-runner -- assets cluster-seeds"); - eprintln!( - " cargo run -p xtask --features cluster-seed-runner -- assets release-build --profile release --target-triple [--fetch]" - ); - eprintln!(" cargo run -p xtask -- assets aot --target-triple "); - eprintln!( - " cargo run -p xtask --features aot-serializer -- assets package [--target-triple ] [--skip-aot]" - ); - eprintln!(" cargo run -p xtask -- assets package-aot [--target-triple ]"); - eprintln!(" cargo run -p xtask -- assets package-extension-aot [--target-triple ]"); - eprintln!(" cargo run -p xtask -- assets check-aot [--target-triple ]"); - eprintln!(" cargo run -p xtask -- assets export-list [--write]"); - eprintln!(" cargo run -p xtask -- assets smoke"); - eprintln!(" cargo run -p xtask -- release stage"); - eprintln!(" cargo run -p xtask -- release package-assets"); - eprintln!(" cargo run -p xtask -- extensions discover [--write]"); - eprintln!(" cargo run -p xtask -- extensions build-plan [--write|--check]"); - eprintln!(" cargo run -p xtask -- extensions generate"); - eprintln!(" cargo run -p xtask -- extensions check"); - eprintln!(" cargo run -p oliphaunt-perf -- bench"); - eprintln!(" cargo run -p oliphaunt-perf -- native-liboliphaunt --engine direct --suite rtt"); - eprintln!(" cargo run -p oliphaunt-perf -- native-postgres --suite rtt"); -} diff --git a/tools/xtask/src/postgres_guard.rs b/tools/xtask/src/postgres_guard.rs deleted file mode 100644 index 00d6803b9..000000000 --- a/tools/xtask/src/postgres_guard.rs +++ /dev/null @@ -1,880 +0,0 @@ -use super::*; -use crate::source_spine::source_checkout_path; - -pub(crate) fn check_wasix_shell_script_syntax() -> Result<()> { - for script in wasix_build_shell_scripts()? { - let mut command = Command::new("bash"); - command.arg("-n").arg(&script); - run_command(&mut command).with_context(|| format!("syntax check {}", script.display()))?; - } - Ok(()) -} - -pub(crate) fn wasix_build_shell_scripts() -> Result> { - let mut scripts = sorted_children(Path::new(WASIX_BUILD_SOURCE_ROOT))? - .into_iter() - .filter(|path| path.is_file()) - .filter(|path| path.extension().and_then(|extension| extension.to_str()) == Some("sh")) - .collect::>(); - let external_root = Path::new("src/extensions/external"); - if external_root.exists() { - for entry in WalkDir::new(external_root) - .into_iter() - .filter_map(|entry| entry.ok()) - .filter(|entry| entry.file_type().is_file()) - .map(|entry| entry.into_path()) - .filter(|path| path.extension().and_then(|extension| extension.to_str()) == Some("sh")) - { - scripts.push(entry); - } - } - scripts.sort(); - scripts.dedup(); - ensure!( - !scripts.is_empty(), - "WASIX build source root has no shell scripts: {WASIX_BUILD_SOURCE_ROOT}" - ); - Ok(scripts) -} - -pub(crate) fn check_postgres_source_spine() -> Result<()> { - let manifest = load_postgres_source_manifest()?; - let series_text = fs::read_to_string(POSTGRES_PATCH_SERIES_PATH) - .with_context(|| format!("read {POSTGRES_PATCH_SERIES_PATH}"))?; - let series = series_text - .lines() - .map(str::trim) - .filter(|line| !line.is_empty() && !line.starts_with('#')) - .collect::>(); - let file_series = series - .iter() - .map(|entry| (*entry).to_owned()) - .collect::>(); - ensure!( - manifest.patches.series == file_series, - "{} [patches].series must exactly match {}", - POSTGRES_SOURCE_MANIFEST_PATH, - POSTGRES_PATCH_SERIES_PATH - ); - - let mut seen = BTreeSet::new(); - for patch_name in &series { - ensure!( - !patch_name.contains('/') && patch_name.ends_with(".patch"), - "{} contains invalid PG18 patch entry {patch_name:?}", - POSTGRES_PATCH_SERIES_PATH - ); - ensure!( - seen.insert(*patch_name), - "{} contains duplicate PG18 patch entry {patch_name}", - POSTGRES_PATCH_SERIES_PATH - ); - ensure_file(&Path::new(POSTGRES_PATCH_DIR).join(patch_name))?; - } - - for entry in - fs::read_dir(POSTGRES_PATCH_DIR).with_context(|| format!("read {POSTGRES_PATCH_DIR}"))? - { - let entry = entry.with_context(|| format!("read entry in {POSTGRES_PATCH_DIR}"))?; - let path = entry.path(); - if path.extension().and_then(|extension| extension.to_str()) != Some("patch") { - continue; - } - let patch_name = path - .file_name() - .and_then(|name| name.to_str()) - .ok_or_else(|| anyhow!("invalid PG18 patch filename {}", path.display()))?; - ensure!( - seen.contains(patch_name), - "{} contains orphan patch file {} not listed in {}", - POSTGRES_PATCH_DIR, - patch_name, - POSTGRES_PATCH_SERIES_PATH - ); - } - - check_prepared_postgres_source_if_present(&manifest)?; - check_postgres_legacy_symbol_leaks(&manifest)?; - check_postgres_released_lane_boundary()?; - ensure_pg18_experiment_patch_disposition()?; - - println!("PostgreSQL source-spine guard passed"); - Ok(()) -} - -fn check_postgres_legacy_symbol_leaks(manifest: &PostgresSourceManifest) -> Result<()> { - let mut roots = vec![ - PathBuf::from(POSTGRES_SOURCE_MANIFEST_PATH), - PathBuf::from(POSTGRES_PATCH_DIR), - PathBuf::from(POSTGRES_PREPARE_SCRIPT), - PathBuf::from("src/runtimes/liboliphaunt/wasix/assets/build/configure_wasix_dl.sh"), - PathBuf::from("src/runtimes/liboliphaunt/wasix/assets/build/docker_oliphaunt.sh"), - PathBuf::from( - "src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod.rs", - ), - ]; - - let prepared_source = postgres_default_source_dir(manifest); - if prepared_source.exists() { - roots.push(prepared_source); - } - for generated_root in [Path::new(WASIX_POSTGRES_DOCKER_BUILD_DIR)] { - if generated_root.exists() { - roots.push(generated_root.to_path_buf()); - } - } - - let banned = [ - concat!("__PG", "LITE__"), - concat!("PG", "LITE_"), - concat!("PG", "L_"), - "pgl_", - concat!("pgl_startPG", "lite"), - concat!("pgl_setPG", "liteActive"), - concat!("pg", "lite_"), - ]; - let mut leaks = Vec::new(); - for root in roots { - if !root.exists() { - continue; - } - if root.is_file() { - collect_pg18_legacy_symbol_leaks(&root, &banned, &mut leaks)?; - continue; - } - for entry in WalkDir::new(&root) { - let entry = entry.with_context(|| format!("walk {}", root.display()))?; - if !entry.file_type().is_file() { - continue; - } - collect_pg18_legacy_symbol_leaks(entry.path(), &banned, &mut leaks)?; - } - } - - ensure!( - leaks.is_empty(), - "PG18 WASIX runtime must not leak legacy fork ABI markers:\n{}", - leaks.join("\n") - ); - Ok(()) -} - -fn collect_pg18_legacy_symbol_leaks( - path: &Path, - banned: &[&str], - leaks: &mut Vec, -) -> Result<()> { - if matches!( - path.extension().and_then(|extension| extension.to_str()), - Some("wasm") - | Some("o") - | Some("a") - | Some("so") - | Some("dylib") - | Some("dll") - | Some("zst") - ) { - return Ok(()); - } - let bytes = fs::read(path).with_context(|| format!("read {}", path.display()))?; - if bytes.contains(&0) { - return Ok(()); - } - let Ok(text) = String::from_utf8(bytes) else { - return Ok(()); - }; - for (line_no, line) in text.lines().enumerate() { - for marker in banned { - if line.contains(marker) { - leaks.push(format!( - "{}:{} contains {marker:?}", - path.display(), - line_no + 1 - )); - } - } - } - Ok(()) -} - -fn check_prepared_postgres_source_if_present(manifest: &PostgresSourceManifest) -> Result<()> { - let source = postgres_default_source_dir(manifest); - if !source.exists() { - return Ok(()); - } - check_prepared_postgres_source(manifest, &source, Path::new(WASIX_POSTGRES_WORK_DIR)) -} - -pub(crate) fn check_prepared_postgres_source( - manifest: &PostgresSourceManifest, - source: &Path, - work_root: &Path, -) -> Result<()> { - ensure!( - source.is_dir(), - "prepared PG18 source path is not a directory: {}", - source.display() - ); - - let version_path = source.join(".oliphaunt-wasix-postgres-version"); - let version = fs::read_to_string(&version_path) - .with_context(|| format!("read {}", version_path.display()))?; - ensure_eq( - version.trim(), - manifest.postgresql.version.as_str(), - "prepared PG18 source version marker", - )?; - let expected_fingerprint = postgres_expected_source_fingerprint(manifest)?; - let source_fingerprint_path = source.join(".oliphaunt-wasix-source-fingerprint"); - let source_fingerprint = fs::read_to_string(&source_fingerprint_path) - .with_context(|| format!("read {}", source_fingerprint_path.display()))?; - ensure_eq( - source_fingerprint.trim(), - &expected_fingerprint, - "prepared PG18 source fingerprint marker", - )?; - let work_fingerprint_path = work_root.join(".source-fingerprint"); - let work_fingerprint = fs::read_to_string(&work_fingerprint_path) - .with_context(|| format!("read {}", work_fingerprint_path.display()))?; - ensure_eq( - work_fingerprint.trim(), - &expected_fingerprint, - "prepared PG18 work fingerprint marker", - )?; - - let mut artifacts = Vec::new(); - for entry in WalkDir::new(source) { - let entry = entry.with_context(|| format!("walk {}", source.display()))?; - if !entry.file_type().is_file() { - continue; - } - let path = entry.path(); - if matches!( - path.extension().and_then(|extension| extension.to_str()), - Some("orig" | "rej") - ) { - artifacts.push(path.display().to_string()); - } - } - ensure!( - artifacts.is_empty(), - "prepared PG18 source contains patch backup/reject artifacts: {}", - artifacts.join(", ") - ); - - check_postgres_packaging_inputs(source)?; - - Ok(()) -} - -pub(crate) fn postgres_default_source_dir(manifest: &PostgresSourceManifest) -> PathBuf { - Path::new(WASIX_POSTGRES_WORK_DIR) - .join("work") - .join(format!( - "postgresql-{}-oliphaunt-wasix-src", - manifest.postgresql.version - )) -} - -pub(crate) fn postgres_work_root_for_source(source: &Path) -> Result { - let work_dir = source.parent().ok_or_else(|| { - anyhow!( - "prepared PG18 source path has no parent work directory: {}", - source.display() - ) - })?; - let work_root = work_dir.parent().ok_or_else(|| { - anyhow!( - "prepared PG18 source path has no parent work root: {}", - source.display() - ) - })?; - Ok(work_root.to_path_buf()) -} - -pub(crate) fn postgres_expected_source_fingerprint( - manifest: &PostgresSourceManifest, -) -> Result { - Ok(format!( - "{}:{}:{}", - manifest.postgresql.version, - manifest.postgresql.sha256, - postgres_patch_series_hash()? - )) -} - -fn postgres_patch_series_hash() -> Result { - let mut hasher = Sha256::new(); - for path in postgres_fingerprint_inputs()? { - let hash = sha256_text_file_lf(&path)?; - hasher.update(hash.as_bytes()); - hasher.update(b"\n"); - } - Ok(format!("{:x}", hasher.finalize())) -} - -fn postgres_fingerprint_inputs() -> Result> { - let mut paths = vec![repo_relative_path(POSTGRES_PATCH_SERIES_PATH)]; - for entry in sorted_children(&repo_relative_path(POSTGRES_PATCH_DIR))? { - if entry.extension().and_then(|extension| extension.to_str()) == Some("patch") { - paths.push(entry); - } - } - Ok(paths) -} - -pub(crate) fn check_source_lane_isolation() -> Result<()> { - ensure!( - canonical_source_lane("pg17").is_err(), - "legacy PG17 source lane must not remain selectable after PG18 promotion" - ); - ensure_eq( - canonical_source_lane("released")?, - DEFAULT_SOURCE_LANE, - "canonical stable released alias", - )?; - ensure_eq( - canonical_source_lane("stable")?, - "stable", - "canonical PG18 source lane", - )?; - ensure!( - build_output_manifest_paths_for_source_lane(DEFAULT_SOURCE_LANE)? - .contains(&Path::new(WASIX_BUILD_MANIFEST_PATH)), - "stable PG18 build output manifest fallback path drifted" - ); - ensure!( - build_output_manifest_path_for_source_lane(DEFAULT_SOURCE_LANE)? - == Path::new(WASIX_POSTGRES_BUILD_MANIFEST_PATH), - "stable PG18 build output manifest path drifted" - ); - ensure!( - generated_assets_dir_for_source_lane(DEFAULT_SOURCE_LANE)? - == Path::new(GENERATED_ASSETS_DIR), - "stable portable asset path drifted" - ); - ensure!( - generated_aot_source_dir_for_source_lane("aarch64", "stable")? - == Path::new(WASIX_POSTGRES_GENERATED_BUILD_DIR) - .join("aot") - .join("aarch64"), - "PG18 AOT source path drifted" - ); - ensure!( - generated_aot_dir_for_source_lane("aarch64", DEFAULT_SOURCE_LANE)? - == Path::new(GENERATED_AOT_DIR).join("aarch64"), - "stable AOT artifact path drifted" - ); - - check_postgres_released_lane_boundary()?; - println!("stable source isolation guard passed"); - Ok(()) -} - -fn check_postgres_released_lane_boundary() -> Result<()> { - let pg18_owned_files = [ - POSTGRES_SOURCE_MANIFEST_PATH, - POSTGRES_PREPARE_SCRIPT, - "src/runtimes/liboliphaunt/wasix/assets/build/configure_wasix_dl.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/docker_oliphaunt.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/wasix_third_party.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_openssl.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_sqlite.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_geos.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libxml2.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_jsonc.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_proj.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_libiconv.sh", - "src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh", - "src/extensions/external/postgis/tools/build_wasix.sh", - ]; - let released_lane_markers = [ - WASIX_PATCHED_SOURCE_DIR, - "prepare_patched_source.sh", - concat!("__PG", "LITE__"), - concat!("PG", "LITE_WASIX_DL"), - concat!("PG", "LITE_HOST_EXPORT"), - ]; - - let mut failures = Vec::new(); - for path in pg18_owned_files { - let text = fs::read_to_string(path).with_context(|| format!("read {path}"))?; - for marker in released_lane_markers { - if text.contains(marker) { - failures.push(format!( - "{path} must not depend on released PG17/Oliphaunt marker {marker:?}" - )); - } - } - } - - ensure!(failures.is_empty(), "{}", failures.join("; ")); - Ok(()) -} - -fn check_postgres_packaging_inputs(source: &Path) -> Result<()> { - for required in [ - "src/bin/initdb/initdb.c", - "src/bin/pg_dump/pg_dump.c", - "src/bin/pg_dump/connectdb.c", - "src/bin/pg_dump/connectdb.h", - "src/pl/plpgsql/src/Makefile", - "src/pl/plpgsql/src/plpgsql.control", - "src/pl/plpgsql/src/plpgsql--1.0.sql", - "src/pl/plpgsql/src/pl_handler.c", - "src/backend/snowball/Makefile", - "src/backend/snowball/dict_snowball.c", - "src/backend/snowball/snowball_create.pl", - "src/backend/snowball/snowball.sql.in", - "src/backend/snowball/snowball_func.sql.in", - "src/backend/snowball/stopwords/english.stop", - "src/timezone/data/tzdata.zi", - "src/timezone/tznames/Default", - ] { - ensure_file(&source.join(required))?; - } - - let extension_specs = extension_catalog::extension_build_specs()?; - for extension in extension_specs - .iter() - .filter(|extension| extension.source_kind == "postgis") - { - let source_dir = Path::new(&extension.source_dir); - ensure_file(&source_dir.join("configure.ac"))?; - ensure_file(&source_dir.join("extensions/postgis/Makefile.in"))?; - ensure_file(&source_dir.join("postgis/postgis.sql.in"))?; - ensure_file(&source_dir.join("libpgcommon/sql/AddToSearchPath.sql.inc"))?; - } - - let mut checked_contrib = 0usize; - let mut missing = Vec::new(); - for extension in extension_specs - .iter() - .filter(|extension| extension.build_kind == "postgres-contrib") - { - checked_contrib += 1; - let Some(contrib_dir) = extension.contrib_dir.as_deref() else { - missing.push(format!("{}: missing generated contrib_dir", extension.id)); - continue; - }; - let extension_source = source.join("contrib").join(contrib_dir); - if !extension_source.is_dir() { - missing.push(format!( - "{}: missing PG18 contrib source directory {}", - extension.id, - extension_source.display() - )); - continue; - } - let makefile = extension_source.join("Makefile"); - if !makefile.is_file() { - missing.push(format!( - "{}: missing PG18 contrib Makefile {}", - extension.id, - makefile.display() - )); - } - if extension.lifecycle.create_extension || extension.control_file.is_some() { - let control = extension_source.join(format!("{}.control", extension.sql_name)); - if !control.is_file() { - missing.push(format!( - "{}: missing PG18 contrib control file {}", - extension.id, - control.display() - )); - } - } - if extension.lifecycle.create_extension - && !extension_source_contains_packaged_sql(&extension_source, &extension.sql_name)? - { - missing.push(format!( - "{}: missing PG18 contrib SQL file for CREATE EXTENSION {} in {}", - extension.id, - extension.sql_name, - extension_source.display() - )); - } - } - - ensure!( - checked_contrib > 0, - "PG18 packaging input guard did not find any public postgres-contrib extensions" - ); - ensure!( - missing.is_empty(), - "PG18 prepared source is missing promoted contrib packaging inputs: {}", - missing.join("; ") - ); - check_postgres_pgxs_packaging_inputs()?; - Ok(()) -} - -fn check_postgres_pgxs_packaging_inputs() -> Result<()> { - let manifest = load_sources_manifest()?; - let mut checked_pgxs = 0usize; - let mut missing = Vec::new(); - for extension in extension_catalog::extension_build_specs()? - .iter() - .filter(|extension| extension_catalog::is_pgxs_style_build_kind(&extension.build_kind)) - { - checked_pgxs += 1; - ensure!( - extension - .source_dir - .starts_with("target/oliphaunt-sources/checkouts/"), - "PG18 PGXS extension {} source dir must be lane-neutral under target/oliphaunt-sources/checkouts, got {}", - extension.id, - extension.source_dir - ); - ensure!( - !extension - .source_dir - .contains(concat!("postgres-", "pg", "lite")), - "PG18 PGXS extension {} must not use removed fork source dir {}", - extension.id, - extension.source_dir - ); - ensure!( - source_pin_for_checkout_dir(&manifest, &extension.source_dir).is_some(), - "PG18 PGXS extension {} source dir {} is not pinned in source metadata", - extension.id, - extension.source_dir - ); - if let Some(module_file) = extension.module_file.as_deref() { - ensure!( - module_file.ends_with(".so"), - "PG18 PGXS extension {} native module must be a WASIX side module name, got {}", - extension.id, - module_file - ); - } - - let source = Path::new(&extension.source_dir); - if !source.is_dir() { - eprintln!( - "warning: PG18 PGXS extension {} source checkout is missing at {}; run source-spine --strict-local after fetching shared extension checkouts", - extension.id, - source.display() - ); - continue; - } - if !source.join("Makefile").is_file() { - missing.push(format!( - "{}: missing PGXS Makefile {}", - extension.id, - source.join("Makefile").display() - )); - } - if extension.lifecycle.create_extension || extension.control_file.is_some() { - let control_file = extension - .control_file - .as_deref() - .map(Path::new) - .filter(|path| path.is_file()) - .map(Path::to_path_buf) - .unwrap_or_else(|| source.join(format!("{}.control", extension.sql_name))); - if !control_file.is_file() { - missing.push(format!( - "{}: missing PGXS control file {}", - extension.id, - control_file.display() - )); - } - } - if extension.lifecycle.create_extension - && !pgxs_extension_source_contains_packaged_sql(source, &extension.sql_name)? - { - missing.push(format!( - "{}: missing PGXS SQL file for CREATE EXTENSION {} in {} or {}/sql", - extension.id, - extension.sql_name, - source.display(), - source.display() - )); - } - } - - ensure!( - checked_pgxs > 0, - "PG18 packaging input guard did not find any public PGXS external extensions" - ); - ensure!( - missing.is_empty(), - "PG18 promoted PGXS packaging inputs are incomplete: {}", - missing.join("; ") - ); - Ok(()) -} - -fn extension_source_contains_packaged_sql(source: &Path, sql_name: &str) -> Result { - if !source.is_dir() { - return Ok(false); - } - for entry in sorted_children(source)? { - if !entry.is_file() { - continue; - } - let Some(name) = entry.file_name().and_then(|name| name.to_str()) else { - continue; - }; - if (name.starts_with(&format!("{sql_name}--")) || name == format!("{sql_name}.sql")) - && name.ends_with(".sql") - { - return Ok(true); - } - } - Ok(false) -} - -fn pgxs_extension_source_contains_packaged_sql(source: &Path, sql_name: &str) -> Result { - if extension_source_contains_packaged_sql(source, sql_name)? { - return Ok(true); - } - extension_source_contains_any_sql(&source.join("sql")) -} - -fn extension_source_contains_any_sql(source: &Path) -> Result { - if !source.is_dir() { - return Ok(false); - } - for entry in sorted_children(source)? { - if entry.extension().and_then(|extension| extension.to_str()) == Some("sql") { - return Ok(true); - } - } - Ok(false) -} - -fn source_pin_for_checkout_dir<'a>( - manifest: &'a SourcesManifest, - source_dir: &str, -) -> Option<&'a SourcePin> { - let expected = normalize_manifest_path(Path::new(source_dir)); - manifest.sources.iter().find(|source| { - source_checkout_path(source.name.as_str()) - .map(|path| normalize_manifest_path(&path)) - .as_deref() - == Some(expected.as_str()) - }) -} - -fn normalize_manifest_path(path: &Path) -> String { - path.to_string_lossy().replace('\\', "/") -} - -fn ensure_pg18_experiment_patch_disposition() -> Result<()> { - let text = fs::read_to_string(POSTGRES_EXPERIMENT_DISPOSITION_PATH) - .with_context(|| format!("read {POSTGRES_EXPERIMENT_DISPOSITION_PATH}"))?; - for required in [ - "0001-wasix-use-posix-dsm-not-sysv.patch", - "0003-wasix-libpq-static-encoding-shim.patch", - "0004-wasix-core-execbackend-initdb-runtime.patch", - "0005-pg-dump-avoid-lto-executequery-collision.patch", - "0006-like-literal-substring-fast-path.patch", - "0007-top-xid-current-transaction-fast-path.patch", - "0008-btree-int4-compare-fast-path.patch", - "0009-btree-delete-stack-state.patch", - "0010-btree-bottomup-delete-runtime-toggle.patch", - "0011-btree-first-int4-compare-fast-path.patch", - "0012-hash-bytes-unaligned-load-fast-path.patch", - "do-not-port-experiment-patches-without-a-recorded-wasix-runtime-rationale", - "ported as 0014-oliphaunt-wasix-speed-up-hash-bytes-unaligned-loads.patch", - "ported as 0015-oliphaunt-wasix-add-top-xid-current-transaction-fast-path.patch", - "ported as 0016-oliphaunt-wasix-add-btree-int4-compare-fast-path.patch", - "ported as 0017-oliphaunt-wasix-keep-btree-delete-scratch-on-stack.patch", - "ported as 0018-oliphaunt-wasix-avoid-pg-dump-executequery-lto-collision.patch", - "rejected-for-default-lane", - "deferred", - ] { - ensure!( - text.contains(required), - "{} must record experiment patch disposition marker {required:?}", - POSTGRES_EXPERIMENT_DISPOSITION_PATH - ); - } - for banned in ["adopt-without-review", "blind-port", "TODO decide"] { - ensure!( - !text.contains(banned), - "{} contains unresolved experiment disposition marker {banned:?}", - POSTGRES_EXPERIMENT_DISPOSITION_PATH - ); - } - - let disposition_experiments = text - .lines() - .filter_map(|line| { - line.trim() - .strip_prefix("experiment = ") - .and_then(parse_toml_string_literal) - }) - .collect::>(); - let source_path = text - .lines() - .find_map(|line| { - line.trim() - .strip_prefix("source_path = ") - .and_then(parse_toml_string_literal) - }) - .ok_or_else(|| { - anyhow!( - "{} must record the source_path for the full-PG experiment patches", - POSTGRES_EXPERIMENT_DISPOSITION_PATH - ) - })?; - let experiment_patch_dir = Path::new(&source_path); - if experiment_patch_dir.is_dir() { - let mut experiment_patches = BTreeSet::new(); - for entry in fs::read_dir(experiment_patch_dir) - .with_context(|| format!("read {}", experiment_patch_dir.display()))? - { - let entry = entry - .with_context(|| format!("read entry in {}", experiment_patch_dir.display()))?; - let path = entry.path(); - if path.extension().and_then(|extension| extension.to_str()) != Some("patch") { - continue; - } - let patch_name = path - .file_name() - .and_then(|name| name.to_str()) - .ok_or_else(|| anyhow!("invalid experiment patch filename {}", path.display()))?; - experiment_patches.insert(patch_name.to_owned()); - } - ensure!( - disposition_experiments == experiment_patches, - "{} must exactly cover experiment patches under {}; missing={:?} stale={:?}", - POSTGRES_EXPERIMENT_DISPOSITION_PATH, - experiment_patch_dir.display(), - experiment_patches - .difference(&disposition_experiments) - .collect::>(), - disposition_experiments - .difference(&experiment_patches) - .collect::>() - ); - } - Ok(()) -} - -fn parse_toml_string_literal(value: &str) -> Option { - let value = value.trim().trim_end_matches(','); - let value = value.strip_prefix('"')?.strip_suffix('"')?; - Some(value.to_owned()) -} - -pub(crate) fn check_rust_startup_abi_boundary() -> Result<()> { - let path = - Path::new("src/bindings/wasix-rust/crates/oliphaunt-wasix/src/oliphaunt/postgres_mod.rs"); - let text = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?; - - for marker in [ - "struct OliphauntLifecycleExports", - "struct WasixProtocolExports", - "fn ensure_integrated_oliphaunt_contract", - "fn host_requires_process_exit_error_recovery() -> bool", - "cfg!(target_env = \"msvc\")", - "oliphaunt_wasix_set_force_host_error_recovery", - "oliphaunt_wasix_set_protocol_transport", - "oliphaunt_wasix_protocol_stream_active", - "The upstream lifecycle is already running by this point", - "[\"-D\", PGDATA_DIR, \"--\", startup_config.database.as_str()]", - ] { - if !text.contains(marker) { - bail!( - "{} must keep upstream lifecycle exports separate from WASIX protocol ABI; missing {marker:?}", - path.display() - ); - } - } - if text.contains("struct Exports") { - bail!( - "{} must not collapse Oliphaunt lifecycle and WASIX protocol exports into a generic Exports struct", - path.display() - ); - } - check_rust_host_runtime_abi_surface(&text)?; - - let lifecycle_start = text - .find("struct OliphauntLifecycleExports") - .ok_or_else(|| anyhow!("missing OliphauntLifecycleExports"))?; - let protocol_start = text - .find("struct WasixProtocolExports") - .ok_or_else(|| anyhow!("missing WasixProtocolExports"))?; - let lifecycle_block = &text[lifecycle_start..protocol_start]; - for protocol_marker in [ - "ProcessStartupPacket", - "PostgresMainLoopOnce", - "oliphaunt_wasix_input", - ] { - if lifecycle_block.contains(protocol_marker) { - bail!( - "{} lifecycle export block leaked WASIX protocol marker {protocol_marker:?}", - path.display() - ); - } - } - for lifecycle_marker in [ - "wasi_start", - "set_force_host_error_recovery", - "set_active", - "start_oliphaunt", - ] { - if !lifecycle_block.contains(lifecycle_marker) { - bail!( - "{} must drive the integrated Oliphaunt lifecycle; missing {lifecycle_marker:?}", - path.display() - ); - } - } - - println!("Rust startup ABI boundary guard passed"); - Ok(()) -} - -fn check_rust_host_runtime_abi_surface(postgres_mod: &str) -> Result<()> { - let runtime_exports = required_runtime_abi_exports() - .iter() - .copied() - .collect::>(); - for &export in RUST_HOST_REQUIRED_RUNTIME_EXPORTS { - ensure!( - postgres_mod.contains(&format!("\"{export}\"")), - "Rust WASIX host must load required runtime export {export}" - ); - ensure!( - runtime_exports.contains(export), - "WASIX runtime export validator must require Rust host export {export}" - ); - } - for &export in RUST_HOST_OPTIONAL_RUNTIME_EXPORTS { - ensure!( - postgres_mod.contains(&format!("\"{export}\"")), - "Rust WASIX host must consciously load optional runtime export {export}" - ); - } - for &export in RUNTIME_EXPORT_LIST_COMPAT_EXPORTS { - ensure!( - runtime_exports.contains(export), - "WASIX runtime export validator must keep compatibility export {export}" - ); - } - for export in [ - "oliphaunt_wasix_set_force_host_error_recovery", - "oliphaunt_wasix_set_protocol_transport", - ] { - ensure!( - runtime_exports.contains(export), - "WASIX runtime export validator must require optional Rust host export {export} for current generated assets" - ); - } - for legacy in [ - "oliphaunt_wasix_initdb", - "oliphaunt_wasix_backend", - "PostgresRecoverProtocolError", - ] { - ensure!( - !postgres_mod.contains(&format!("\"{legacy}\"")), - "Rust WASIX host must not load legacy builder-branch export {legacy}" - ); - } - Ok(()) -} diff --git a/tools/xtask/src/release_workspace.rs b/tools/xtask/src/release_workspace.rs deleted file mode 100644 index 1b3fbe285..000000000 --- a/tools/xtask/src/release_workspace.rs +++ /dev/null @@ -1,853 +0,0 @@ -use std::fs; -use std::path::{Path, PathBuf}; - -use anyhow::{Context, Result, anyhow}; - -use super::*; -use crate::asset_io::ensure_aot_manifest_matches_source_lane; - -const RELEASE_RELEVANT_UNTRACKED_PATHS: &[&str] = &[ - "Cargo.lock", - "Cargo.toml", - "rust-toolchain.toml", - "src/extensions", - "src/bindings/wasix-rust", - "src/runtimes/liboliphaunt/wasix", - "tools/xtask", -]; -const SPLIT_WASIX_TOOL_PAYLOAD_FILES: &[&str] = &["bin/pg_dump.wasix.wasm", "bin/psql.wasix.wasm"]; -const SPLIT_WASIX_TOOL_AOT_ARTIFACTS: &[&str] = &["tool:pg_dump", "tool:psql"]; - -fn stage_release_notices(staging: &Path, profile: &str) -> Result<()> { - let mut command = command_for_host("bun"); - command - .arg("tools/release/release-notices.mjs") - .arg("stage") - .arg(staging) - .arg("--profile") - .arg(profile); - run_command(&mut command).with_context(|| { - format!( - "stage release notices with profile {profile} in {}", - staging.display() - ) - }) -} - -fn check_release_notices(archive: &Path, profile: &str, prefix: Option<&Path>) -> Result<()> { - let mut command = command_for_host("bun"); - command - .arg("tools/release/release-notices.mjs") - .arg("check-archive") - .arg(archive) - .arg("--profile") - .arg(profile); - if let Some(prefix) = prefix { - command.arg("--prefix").arg(prefix); - } - run_command(&mut command).with_context(|| { - format!( - "verify release notices with profile {profile} in {}", - archive.display() - ) - }) -} - -fn check_release_asset_set(output_dir: &Path, version: &str) -> Result<()> { - let mut command = command_for_host("bun"); - command - .arg("tools/release/check-liboliphaunt-wasix-release-assets.mjs") - .arg("--asset-dir") - .arg(output_dir) - .arg("--version") - .arg(version); - run_command(&mut command).with_context(|| { - format!( - "verify complete liboliphaunt-wasix release asset set in {}", - output_dir.display() - ) - }) -} - -pub(super) fn stage_release_workspace() -> Result<()> { - let stage_root = Path::new(RELEASE_STAGE_DIR); - let workspace = stage_root.join("workspace"); - if stage_root.exists() { - fs::remove_dir_all(stage_root) - .with_context(|| format!("remove {}", stage_root.display()))?; - } - fs::create_dir_all(&workspace).with_context(|| format!("create {}", workspace.display()))?; - - ensure_no_unexpected_untracked_release_files()?; - let tracked = command_output("git", &["ls-files", "-z", "--cached"], Path::new("."))?; - for path in tracked.split('\0').filter(|path| !path.is_empty()) { - let source = Path::new(path); - let destination = workspace.join(path); - copy_file(source, &destination)?; - } - - let generated_assets = Path::new(GENERATED_ASSETS_DIR); - ensure_file(&generated_assets.join("manifest.json"))?; - let generated_manifest = read_asset_manifest_from(generated_assets)?; - ensure_packaged_asset_matches_source_lane(&generated_manifest, DEFAULT_SOURCE_LANE)?; - copy_core_wasix_asset_payload( - generated_assets, - &workspace.join(ASSET_CRATE_PAYLOAD_DIR), - false, - )?; - copy_core_wasix_asset_payload( - generated_assets, - &workspace.join(GENERATED_ASSETS_DIR), - true, - )?; - update_staged_root_asset_metadata(&workspace)?; - - for target in supported_aot_targets() { - let generated_aot = generated_aot_dir(target); - if generated_aot.join("manifest.json").is_file() { - ensure_aot_manifest_matches_source_lane( - &generated_aot.join("manifest.json"), - target, - DEFAULT_SOURCE_LANE, - )?; - copy_core_wasix_aot_payload( - &generated_aot, - &workspace - .join("src/runtimes/liboliphaunt/wasix/crates/aot") - .join(target) - .join("artifacts"), - false, - )?; - copy_core_wasix_aot_payload( - &generated_aot, - &workspace.join("target/oliphaunt-wasix/aot").join(target), - true, - )?; - } - } - - fs::write( - stage_root.join("README.txt"), - "Generated liboliphaunt-wasix release workspace.\n", - ) - .with_context(|| format!("write {}", stage_root.join("README.txt").display()))?; - println!("staged release workspace at {}", workspace.display()); - Ok(()) -} - -fn ensure_no_unexpected_untracked_release_files() -> Result<()> { - let mut args = vec!["ls-files", "-z", "--others", "--exclude-standard", "--"]; - args.extend(RELEASE_RELEVANT_UNTRACKED_PATHS); - let untracked = command_output("git", &args, Path::new("."))? - .split('\0') - .filter(|path| !path.is_empty()) - .map(str::to_owned) - .collect::>(); - if !untracked.is_empty() { - return Err(anyhow!( - "WASM release staging refuses untracked release-relevant files; add them to git or move them out of release roots: {}", - untracked.join(", ") - )); - } - Ok(()) -} - -fn copy_core_wasix_asset_payload( - source: &Path, - destination: &Path, - retain_split_tools: bool, -) -> Result<()> { - copy_dir_all(source, destination)?; - let extension_dir = destination.join("extensions"); - if extension_dir.exists() { - fs::remove_dir_all(&extension_dir) - .with_context(|| format!("remove {}", extension_dir.display()))?; - } - if !retain_split_tools { - remove_split_wasix_tool_payload(destination)?; - } - strip_core_asset_manifest_extensions(&destination.join("manifest.json"))?; - ensure_core_wasix_asset_payload(destination, retain_split_tools) -} - -fn remove_split_wasix_tool_payload(root: &Path) -> Result<()> { - for relative in SPLIT_WASIX_TOOL_PAYLOAD_FILES { - let path = root.join(relative); - if path.exists() { - fs::remove_file(&path).with_context(|| format!("remove {}", path.display()))?; - } - } - Ok(()) -} - -fn strip_core_asset_manifest_extensions(manifest_path: &Path) -> Result<()> { - let text = fs::read_to_string(manifest_path) - .with_context(|| format!("read {}", manifest_path.display()))?; - let mut manifest: serde_json::Value = serde_json::from_str(&text) - .with_context(|| format!("parse {}", manifest_path.display()))?; - let extensions = manifest - .get_mut("extensions") - .and_then(|value| value.as_array_mut()) - .ok_or_else(|| { - anyhow!( - "{} must contain an extensions array", - manifest_path.display() - ) - })?; - extensions.clear(); - let object = manifest - .as_object_mut() - .ok_or_else(|| anyhow!("{} must contain a JSON object", manifest_path.display()))?; - object.remove("pg-dump"); - object.remove("psql"); - let rendered = - serde_json::to_string_pretty(&manifest).context("serialize core WASIX asset manifest")?; - fs::write(manifest_path, format!("{rendered}\n")) - .with_context(|| format!("write {}", manifest_path.display()))?; - Ok(()) -} - -fn ensure_core_wasix_asset_payload(root: &Path, retain_split_tools: bool) -> Result<()> { - ensure_file(&root.join("manifest.json"))?; - for relative in SPLIT_WASIX_TOOL_PAYLOAD_FILES { - let path = root.join(relative); - if retain_split_tools { - ensure_file(&path)?; - } else { - ensure!( - !path.exists(), - "core WASIX root crate payload must not contain split tool {}", - path.display() - ); - } - } - for file in sorted_files(root)? { - let relative = file - .strip_prefix(root) - .with_context(|| format!("strip {} from {}", root.display(), file.display()))?; - if relative - .components() - .next() - .and_then(|component| component.as_os_str().to_str()) - == Some("extensions") - { - bail!( - "core WASIX asset payload must not contain extension archive {}", - file.display() - ); - } - } - Ok(()) -} - -fn copy_core_wasix_aot_payload( - source: &Path, - destination: &Path, - retain_split_tools: bool, -) -> Result<()> { - copy_dir_all(source, destination)?; - let manifest_path = destination.join("manifest.json"); - let text = fs::read_to_string(&manifest_path) - .with_context(|| format!("read {}", manifest_path.display()))?; - let mut manifest: serde_json::Value = serde_json::from_str(&text) - .with_context(|| format!("parse {}", manifest_path.display()))?; - let artifacts = manifest - .get_mut("artifacts") - .and_then(|value| value.as_array_mut()) - .ok_or_else(|| { - anyhow!( - "{} must contain an artifacts array", - manifest_path.display() - ) - })?; - let mut retained = Vec::new(); - let mut retained_paths = BTreeSet::new(); - for artifact in artifacts.drain(..) { - let name = artifact - .get("name") - .and_then(|value| value.as_str()) - .ok_or_else(|| { - anyhow!( - "{} contains an artifact without a name", - manifest_path.display() - ) - })?; - let path = artifact - .get("path") - .and_then(|value| value.as_str()) - .ok_or_else(|| { - anyhow!( - "{} contains artifact {name} without a path", - manifest_path.display() - ) - })?; - let relative_path = validated_aot_artifact_path(path, &manifest_path, name)?; - if name.starts_with("extension:") - || (!retain_split_tools && SPLIT_WASIX_TOOL_AOT_ARTIFACTS.contains(&name)) - { - let artifact_path = destination.join(&relative_path); - if artifact_path.exists() { - fs::remove_file(&artifact_path) - .with_context(|| format!("remove {}", artifact_path.display()))?; - } - } else { - let artifact_path = destination.join(&relative_path); - ensure_file(&artifact_path)?; - retained_paths.insert(relative_path); - retained.push(artifact); - } - } - ensure!( - !retained.is_empty(), - "{} core WASIX AOT manifest would contain no artifacts", - manifest_path.display() - ); - *artifacts = retained; - remove_unretained_aot_payload_files(destination, &retained_paths)?; - let rendered = - serde_json::to_string_pretty(&manifest).context("serialize core WASIX AOT manifest")?; - fs::write(&manifest_path, format!("{rendered}\n")) - .with_context(|| format!("write {}", manifest_path.display()))?; - ensure_core_wasix_aot_payload(destination, retain_split_tools) -} - -fn validated_aot_artifact_path(path: &str, manifest_path: &Path, name: &str) -> Result { - let relative_path = Path::new(path); - ensure!( - relative_path.is_relative() - && relative_path - .components() - .all(|component| matches!(component, std::path::Component::Normal(_))), - "{} artifact {name} path must be a simple relative file path, got {path}", - manifest_path.display() - ); - Ok(relative_path.to_path_buf()) -} - -fn remove_unretained_aot_payload_files( - root: &Path, - retained_paths: &BTreeSet, -) -> Result<()> { - for file in sorted_files(root)? { - let relative = file - .strip_prefix(root) - .with_context(|| format!("strip {} from {}", root.display(), file.display()))?; - if relative == Path::new("manifest.json") || retained_paths.contains(relative) { - continue; - } - fs::remove_file(&file).with_context(|| format!("remove {}", file.display()))?; - } - Ok(()) -} - -fn ensure_core_wasix_aot_payload(root: &Path, retain_split_tools: bool) -> Result<()> { - ensure_file(&root.join("manifest.json"))?; - let text = fs::read_to_string(root.join("manifest.json")) - .with_context(|| format!("read {}", root.join("manifest.json").display()))?; - let manifest: serde_json::Value = serde_json::from_str(&text) - .with_context(|| format!("parse {}", root.join("manifest.json").display()))?; - let mut retained_paths = BTreeSet::new(); - let mut retained_split_tools = BTreeSet::new(); - for artifact in manifest - .get("artifacts") - .and_then(|value| value.as_array()) - .ok_or_else(|| { - anyhow!( - "{} must contain an artifacts array", - root.join("manifest.json").display() - ) - })? - { - let name = artifact - .get("name") - .and_then(|value| value.as_str()) - .ok_or_else(|| anyhow!("{} contains an artifact without a name", root.display()))?; - if SPLIT_WASIX_TOOL_AOT_ARTIFACTS.contains(&name) { - ensure!( - retain_split_tools, - "core WASIX AOT payload must not contain split tool artifact {name}" - ); - retained_split_tools.insert(name.to_owned()); - } - ensure!( - !name.starts_with("extension:"), - "core WASIX AOT payload must not contain extension artifact {name}" - ); - let path = artifact - .get("path") - .and_then(|value| value.as_str()) - .ok_or_else(|| anyhow!("{} contains artifact {name} without a path", root.display()))?; - let relative_path = validated_aot_artifact_path(path, &root.join("manifest.json"), name)?; - ensure_file(&root.join(&relative_path))?; - retained_paths.insert(relative_path); - } - if retain_split_tools { - for required in SPLIT_WASIX_TOOL_AOT_ARTIFACTS { - ensure!( - retained_split_tools.contains(*required), - "WASIX AOT payload retained for tools must contain split tool artifact {required}" - ); - } - } - for file in sorted_files(root)? { - let relative = file - .strip_prefix(root) - .with_context(|| format!("strip {} from {}", root.display(), file.display()))?; - ensure!( - relative == Path::new("manifest.json") || retained_paths.contains(relative), - "core WASIX AOT payload contains unmanifested artifact {}", - file.display() - ); - } - Ok(()) -} - -pub(super) fn package_release_assets() -> Result<()> { - let output_dir = Path::new(RELEASE_ASSET_BUNDLE_DIR); - if output_dir.exists() { - fs::remove_dir_all(output_dir) - .with_context(|| format!("remove {}", output_dir.display()))?; - } - fs::create_dir_all(output_dir).with_context(|| format!("create {}", output_dir.display()))?; - - let version = wasix_runtime_release_version()?; - let mut bundles = Vec::new(); - bundles.push(package_release_portable_assets(output_dir, &version)?); - bundles.push(package_release_icu_assets(output_dir, &version)?); - for target in supported_aot_targets() { - bundles.push(package_release_aot_assets(output_dir, target, &version)?); - } - let staging_root = output_dir.join("staging"); - if staging_root.exists() { - fs::remove_dir_all(&staging_root).with_context(|| { - format!( - "remove completed release staging root {}", - staging_root.display() - ) - })?; - } - - let mut checksum_lines = Vec::new(); - for bundle in &bundles { - let name = bundle - .file_name() - .and_then(|name| name.to_str()) - .ok_or_else(|| { - anyhow!( - "release asset path is not valid UTF-8: {}", - bundle.display() - ) - })?; - checksum_lines.push(format!("{} ./{name}", sha256_file(bundle)?)); - } - checksum_lines.sort(); - let checksum_path = output_dir.join(format!( - "liboliphaunt-wasix-{version}-release-assets.sha256" - )); - fs::write(&checksum_path, format!("{}\n", checksum_lines.join("\n"))) - .with_context(|| format!("write {}", checksum_path.display()))?; - - check_release_asset_set(output_dir, &version)?; - println!("packaged public release assets in {}", output_dir.display()); - Ok(()) -} - -fn package_release_portable_assets(output_dir: &Path, version: &str) -> Result { - let generated_assets = Path::new(GENERATED_ASSETS_DIR); - ensure_file(&generated_assets.join("manifest.json"))?; - let manifest = read_asset_manifest_from(generated_assets)?; - ensure_packaged_asset_matches_source_lane(&manifest, DEFAULT_SOURCE_LANE)?; - - let staging = output_dir.join("staging/portable-wasix"); - if staging.exists() { - fs::remove_dir_all(&staging).with_context(|| format!("remove {}", staging.display()))?; - } - copy_core_wasix_asset_payload(generated_assets, &staging.join(GENERATED_ASSETS_DIR), true)?; - copy_dir_all( - Path::new("src/extensions/generated"), - &staging.join("src/extensions/generated"), - )?; - copy_dir_all( - Path::new("src/runtimes/liboliphaunt/wasix/assets/generated"), - &staging.join("src/runtimes/liboliphaunt/wasix/assets/generated"), - )?; - stage_release_notices(&staging, "wasix-runtime")?; - - let output = output_dir.join(format!( - "liboliphaunt-wasix-{version}-runtime-portable.tar.zst" - )); - deterministic_tar_zst(&staging, Path::new(""), &output)?; - check_release_notices(&output, "wasix-runtime", None)?; - fs::remove_dir_all(&staging).with_context(|| format!("remove {}", staging.display()))?; - Ok(output) -} - -fn package_release_icu_assets(output_dir: &Path, version: &str) -> Result { - let staging = output_dir.join("staging/icu-data"); - if staging.exists() { - fs::remove_dir_all(&staging).with_context(|| format!("remove {}", staging.display()))?; - } - copy_wasix_icu_sidecar(&staging.join("target/oliphaunt-wasix/icu/share/icu"))?; - stage_release_notices(&staging, "wasix-icu-data")?; - let output = output_dir.join(format!("liboliphaunt-wasix-{version}-icu-data.tar.zst")); - deterministic_tar_zst(&staging, Path::new(""), &output)?; - check_release_notices(&output, "wasix-icu-data", None)?; - fs::remove_dir_all(&staging).with_context(|| format!("remove {}", staging.display()))?; - Ok(output) -} - -fn copy_wasix_icu_sidecar(destination: &Path) -> Result<()> { - let installed_icu = Path::new(WASIX_GENERATED_WORK_DIR).join("icu-wasix/share/icu"); - let installed_type = portable_icu_entry_type(&installed_icu).with_context(|| { - format!( - "missing or unsafe WASIX ICU files data at {}; run src/runtimes/liboliphaunt/wasix/assets/build/build_wasix_icu.sh before packaging", - installed_icu.display() - ) - })?; - ensure!( - installed_type.is_dir(), - "WASIX ICU files data root is not a directory: {}", - installed_icu.display() - ); - let source = canonical_icu_data_root(&installed_icu)?; - if destination.exists() { - fs::remove_dir_all(destination) - .with_context(|| format!("remove {}", destination.display()))?; - } - copy_wasix_icu_data_payload(&source, destination) - .with_context(|| format!("copy WASIX ICU files data from {}", source.display()))?; - ensure!( - icu_data_root_contains_data(destination)?, - "staged WASIX ICU sidecar at {} does not contain icudt files", - destination.display() - ); - Ok(()) -} - -fn copy_wasix_icu_data_payload(source: &Path, destination: &Path) -> Result<()> { - let source_type = portable_icu_entry_type(source)?; - ensure!( - source_type.is_dir(), - "ICU data root is not a directory: {}", - source.display() - ); - fs::create_dir_all(destination).with_context(|| format!("create {}", destination.display()))?; - let mut copied = 0usize; - for child in sorted_children(source)? { - let name = child - .file_name() - .and_then(|name| name.to_str()) - .ok_or_else(|| anyhow!("ICU data path is not valid UTF-8: {}", child.display()))?; - let child_type = portable_icu_entry_type(&child)?; - if child_type.is_file() && name.starts_with("icudt") && name.ends_with(".dat") { - copy_file(&child, &destination.join(name))?; - copied += 1; - } else if child_type.is_dir() && name.starts_with("icudt") { - let file_count = validate_portable_icu_tree(&child)?; - if file_count > 0 { - copy_dir_all(&child, &destination.join(name))?; - copied += 1; - } - } - } - ensure!( - copied > 0, - "ICU data root {} has no icudt files-data payload", - source.display() - ); - Ok(()) -} - -fn canonical_icu_data_root(installed_icu: &Path) -> Result { - if icu_data_root_contains_data(installed_icu)? { - return Ok(installed_icu.to_path_buf()); - } - - let mut candidates = Vec::new(); - for child in sorted_children(installed_icu)? { - if portable_icu_entry_type(&child)?.is_dir() && icu_data_root_contains_data(&child)? { - candidates.push(child); - } - } - ensure!( - candidates.len() == 1, - "WASIX ICU install root {} must contain exactly one data directory, found {}", - installed_icu.display(), - candidates.len() - ); - Ok(candidates.remove(0)) -} - -fn portable_icu_entry_type(path: &Path) -> Result { - let metadata = fs::symlink_metadata(path) - .with_context(|| format!("inspect ICU data path {}", path.display()))?; - let file_type = metadata.file_type(); - ensure!( - !file_type.is_symlink(), - "ICU data tree must not contain a symbolic link: {}", - path.display() - ); - ensure!( - file_type.is_file() || file_type.is_dir(), - "ICU data tree must contain only regular files and directories: {}", - path.display() - ); - Ok(file_type) -} - -fn validate_portable_icu_tree(root: &Path) -> Result { - ensure!( - portable_icu_entry_type(root)?.is_dir(), - "ICU data subtree is not a directory: {}", - root.display() - ); - let mut file_count = 0usize; - for child in sorted_children(root)? { - let child_type = portable_icu_entry_type(&child)?; - if child_type.is_dir() { - file_count += validate_portable_icu_tree(&child)?; - } else { - file_count += 1; - } - } - Ok(file_count) -} - -fn icu_data_root_contains_data(root: &Path) -> Result { - let root_type = portable_icu_entry_type(root)?; - if !root_type.is_dir() { - return Ok(false); - } - for child in sorted_children(root)? { - let Some(name) = child.file_name().and_then(|name| name.to_str()) else { - continue; - }; - let child_type = portable_icu_entry_type(&child)?; - if child_type.is_file() && name.starts_with("icudt") && name.ends_with(".dat") { - return Ok(true); - } - if child_type.is_dir() - && name.starts_with("icudt") - && validate_portable_icu_tree(&child)? > 0 - { - return Ok(true); - } - } - Ok(false) -} - -fn package_release_aot_assets(output_dir: &Path, target: &str, version: &str) -> Result { - ensure_supported_aot_target(target)?; - let generated_aot = generated_aot_dir(target); - ensure_file(&generated_aot.join("manifest.json"))?; - ensure_aot_manifest_matches_source_lane( - &generated_aot.join("manifest.json"), - target, - DEFAULT_SOURCE_LANE, - )?; - - let target_id = aot_target_id_for_triple(target)?; - let output = output_dir.join(format!( - "liboliphaunt-wasix-{version}-runtime-aot-{target_id}.tar.zst" - )); - let staging = output_dir.join("staging").join(target); - if staging.exists() { - fs::remove_dir_all(&staging).with_context(|| format!("remove {}", staging.display()))?; - } - copy_core_wasix_aot_payload(&generated_aot, &staging, true)?; - stage_release_notices(&staging, "wasix-aot")?; - let archive_prefix = Path::new("target/oliphaunt-wasix/aot").join(target); - deterministic_tar_zst(&staging, &archive_prefix, &output)?; - check_release_notices(&output, "wasix-aot", Some(&archive_prefix))?; - fs::remove_dir_all(&staging).with_context(|| format!("remove {}", staging.display()))?; - Ok(output) -} - -fn wasix_runtime_release_version() -> Result { - let manifest = fs::read_to_string("src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml") - .context("read src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml")?; - let mut in_package = false; - for line in manifest.lines() { - let trimmed = line.trim(); - if trimmed == "[package]" { - in_package = true; - continue; - } - if in_package && trimmed.starts_with('[') { - break; - } - if in_package && trimmed.starts_with("version") { - let Some((_, raw_value)) = trimmed.split_once('=') else { - continue; - }; - let version = raw_value.trim().trim_matches('"'); - if !version.is_empty() { - return Ok(version.to_owned()); - } - } - } - Err(anyhow!( - "src/runtimes/liboliphaunt/wasix/crates/assets/Cargo.toml [package].version is missing" - )) -} - -#[cfg(test)] -mod tests { - use super::*; - - fn fixture_root(name: &str) -> PathBuf { - std::env::temp_dir().join(format!( - "oliphaunt-release-workspace-{name}-{}", - std::process::id() - )) - } - - #[test] - fn public_wasix_payload_excludes_private_extension_bytes_and_metadata() -> Result<()> { - let root = fixture_root("deferred-extension-boundary"); - if root.exists() { - fs::remove_dir_all(&root)?; - } - let raw_assets = root.join("raw-assets"); - fs::create_dir_all(raw_assets.join("extensions"))?; - fs::write( - raw_assets.join("manifest.json"), - r#"{"extensions":[{"sql-name":"example_deferred"}],"pg-dump":{},"psql":{}}"#, - )?; - fs::write( - raw_assets.join("extensions/example_deferred.tar.zst"), - b"candidate", - )?; - fs::write(raw_assets.join("oliphaunt.wasix.tar.zst"), b"runtime")?; - - let public_assets = root.join("public-assets"); - copy_core_wasix_asset_payload(&raw_assets, &public_assets, false)?; - assert!(!public_assets.join("extensions").exists()); - let manifest: serde_json::Value = - serde_json::from_str(&fs::read_to_string(public_assets.join("manifest.json"))?)?; - assert_eq!(manifest["extensions"], serde_json::json!([])); - assert!(manifest.get("pg-dump").is_none()); - assert!(manifest.get("psql").is_none()); - - let generated = root.join("generated"); - fs::create_dir_all(generated.join("mobile"))?; - fs::write(generated.join("mobile/static-extensions.tsv"), b"public\n")?; - let public_generated = root.join("public-generated"); - copy_dir_all(&generated, &public_generated)?; - assert!( - public_generated - .join("mobile/static-extensions.tsv") - .is_file() - ); - fs::remove_dir_all(root)?; - Ok(()) - } - - #[test] - fn wasix_icu_sidecar_contains_only_icudt_payload() -> Result<()> { - let root = fixture_root("icu-data-boundary"); - if root.exists() { - fs::remove_dir_all(&root)?; - } - let source = root.join("source"); - fs::create_dir_all(source.join("icudt76l/coll"))?; - fs::create_dir_all(source.join("config"))?; - fs::write(source.join("icudt76l/root.res"), b"root-data")?; - fs::write(source.join("icudt76l/coll/en.res"), b"collation-data")?; - fs::write(source.join("LICENSE"), b"upstream-license")?; - fs::write(source.join("config/mh-linux"), b"build-only-config")?; - fs::write(source.join("install-sh"), b"build-only-helper")?; - - let destination = root.join("destination"); - copy_wasix_icu_data_payload(&source, &destination)?; - assert!(destination.join("icudt76l/root.res").is_file()); - assert!(destination.join("icudt76l/coll/en.res").is_file()); - assert!(!destination.join("LICENSE").exists()); - assert!(!destination.join("config").exists()); - assert!(!destination.join("install-sh").exists()); - assert!(icu_data_root_contains_data(&destination)?); - - let empty = root.join("empty"); - fs::create_dir_all(&empty)?; - let error = copy_wasix_icu_data_payload(&empty, &root.join("empty-output")) - .expect_err("empty ICU data roots must fail"); - assert!( - error - .to_string() - .contains("has no icudt files-data payload") - ); - - fs::remove_dir_all(root)?; - Ok(()) - } - - #[cfg(unix)] - #[test] - fn wasix_icu_sidecar_rejects_symlinks_at_every_selected_payload_depth() -> Result<()> { - use std::os::unix::fs::symlink; - - let root = fixture_root("icu-data-symlinks"); - if root.exists() { - fs::remove_dir_all(&root)?; - } - fs::create_dir_all(&root)?; - let outside_file = root.join("outside.dat"); - let outside_directory = root.join("outside-directory"); - fs::write(&outside_file, b"outside")?; - fs::create_dir_all(&outside_directory)?; - fs::write(outside_directory.join("payload.res"), b"outside")?; - - let linked_file_root = root.join("linked-file-root"); - fs::create_dir_all(&linked_file_root)?; - symlink(&outside_file, linked_file_root.join("icudt76l.dat"))?; - let error = - copy_wasix_icu_data_payload(&linked_file_root, &root.join("linked-file-output")) - .expect_err("top-level ICU data symlinks must fail"); - assert!( - error - .to_string() - .contains("must not contain a symbolic link") - ); - - let linked_directory_root = root.join("linked-directory-root"); - fs::create_dir_all(&linked_directory_root)?; - symlink(&outside_directory, linked_directory_root.join("icudt76l"))?; - let error = copy_wasix_icu_data_payload( - &linked_directory_root, - &root.join("linked-directory-output"), - ) - .expect_err("top-level ICU directory symlinks must fail"); - assert!( - error - .to_string() - .contains("must not contain a symbolic link") - ); - - let nested_link_root = root.join("nested-link-root"); - fs::create_dir_all(nested_link_root.join("icudt76l/coll"))?; - fs::write(nested_link_root.join("icudt76l/root.res"), b"root")?; - symlink(&outside_file, nested_link_root.join("icudt76l/coll/en.res"))?; - let error = - copy_wasix_icu_data_payload(&nested_link_root, &root.join("nested-link-output")) - .expect_err("nested ICU data symlinks must fail"); - assert!( - error - .to_string() - .contains("must not contain a symbolic link") - ); - - let canonical_link_root = root.join("canonical-link-root"); - fs::create_dir_all(&canonical_link_root)?; - symlink(&outside_directory, canonical_link_root.join("76.1"))?; - let error = canonical_icu_data_root(&canonical_link_root) - .expect_err("canonical ICU root discovery must not follow symlinks"); - assert!( - error - .to_string() - .contains("must not contain a symbolic link") - ); - - fs::remove_dir_all(root)?; - Ok(()) - } -} diff --git a/tools/xtask/src/source_spine.rs b/tools/xtask/src/source_spine.rs deleted file mode 100644 index 0a5137510..000000000 --- a/tools/xtask/src/source_spine.rs +++ /dev/null @@ -1,1021 +0,0 @@ -use std::collections::BTreeSet; -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::Command; - -use anyhow::{Context, Result, anyhow, bail}; - -use crate::postgres_guard::{ - check_postgres_source_spine, check_prepared_postgres_source, check_source_lane_isolation, - postgres_work_root_for_source, -}; - -use super::*; - -pub(super) fn check_sources_manifest(strict_local: bool) -> Result { - let manifest = load_sources_manifest()?; - validate_sources_manifest(&manifest)?; - if strict_local { - check_source_spine_for_source_lane(&manifest, DEFAULT_SOURCE_LANE, true, false)?; - } - println!("validated {} pinned asset sources", manifest.sources.len()); - Ok(manifest) -} - -pub(super) fn check_sources_manifest_for_wasix_asset_build( - args: &[String], -) -> Result { - let manifest = load_sources_manifest()?; - validate_sources_manifest(&manifest)?; - let source_lane = - canonical_source_lane(value_after(args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE))?; - let source_scope = SourceFetchScope::WasixRuntime; - if args.iter().any(|arg| arg == "--fetch") { - fetch_pinned_sources_for_source_lane(&manifest, source_lane, true, source_scope)?; - } else { - prepare_postgres_source_tree()?; - check_source_spine_for_source_lane_filtered( - &manifest, - source_lane, - true, - false, - |source| source_scope.includes(source.origin), - )?; - } - println!( - "validated {} pinned asset sources for {source_lane}", - manifest - .sources - .iter() - .filter(|source| source_scope.includes(source.origin)) - .count() - ); - Ok(manifest) -} - -pub(super) fn fetch_pinned_sources_for_source_lane( - manifest: &SourcesManifest, - source_lane: &str, - prepare_postgres_source: bool, - source_scope: SourceFetchScope, -) -> Result<()> { - match canonical_source_lane(source_lane)? { - "stable" => { - run_hardened_source_fetch(source_scope)?; - if prepare_postgres_source { - prepare_postgres_source_tree()?; - } - check_source_spine_for_source_lane_filtered(manifest, "stable", true, false, |source| { - source_scope.includes(source.origin) - }) - } - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(super) enum SourceFetchScope { - ProductionAll, - All, - NativeRuntime, - WasixRuntime, - Extensions, -} - -impl SourceFetchScope { - pub(super) fn parse(value: &str) -> Result { - match value { - "production-all" => Ok(Self::ProductionAll), - "all" => Ok(Self::All), - "native-runtime" => Ok(Self::NativeRuntime), - "wasix-runtime" => Ok(Self::WasixRuntime), - "extensions" => Ok(Self::Extensions), - other => bail!( - "unsupported source fetch scope {other:?}; expected one of: production-all, all, native-runtime, wasix-runtime, extensions" - ), - } - } - - fn as_arg(self) -> &'static str { - match self { - Self::ProductionAll => "production-all", - Self::All => "all", - Self::NativeRuntime => "native-runtime", - Self::WasixRuntime => "wasix-runtime", - Self::Extensions => "extensions", - } - } - - fn includes(self, origin: SourceOrigin) -> bool { - match self { - Self::ProductionAll | Self::All => true, - Self::NativeRuntime => matches!( - origin, - SourceOrigin::SharedThirdParty - | SourceOrigin::NativeThirdParty - | SourceOrigin::Extension - ), - Self::WasixRuntime => matches!( - origin, - SourceOrigin::SharedThirdParty - | SourceOrigin::WasixThirdParty - | SourceOrigin::Extension - ), - Self::Extensions => matches!(origin, SourceOrigin::Extension), - } - } -} - -fn run_hardened_source_fetch(scope: SourceFetchScope) -> Result<()> { - let mut command = Command::new("tools/dev/bun.sh"); - command.args([ - "src/sources/tools/fetch-sources.mjs", - scope.as_arg(), - "--force", - ]); - run_command(&mut command).with_context(|| { - format!( - "materialize {} sources through the hardened source acquisition spine", - scope.as_arg() - ) - }) -} - -fn archive_sha256(source: &SourcePin) -> Result { - let sha256 = source - .sha256 - .as_deref() - .ok_or_else(|| anyhow!("archive source '{}' is missing sha256", source.name))?; - ensure!( - sha256.len() == 64 - && sha256 - .chars() - .all(|ch| ch.is_ascii_digit() || ('a'..='f').contains(&ch)), - "archive source '{}' has invalid lowercase sha256 {}", - source.name, - sha256 - ); - Ok(sha256.to_owned()) -} - -fn archive_strip_prefix(source: &SourcePin) -> Result<&str> { - source - .strip_prefix - .as_deref() - .filter(|prefix| { - *prefix == "." - || (!prefix.is_empty() - && !prefix.contains("..") - && prefix - .chars() - .next() - .is_some_and(|ch| ch.is_ascii_alphanumeric()) - && prefix.chars().all(|ch| { - ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.' | '+') - })) - }) - .ok_or_else(|| anyhow!("archive source '{}' has invalid strip-prefix", source.name)) -} -pub(super) fn check_source_spine_for_source_lane( - manifest: &SourcesManifest, - source_lane: &str, - strict_local: bool, - check_patch_applies: bool, -) -> Result<()> { - match canonical_source_lane(source_lane)? { - "stable" => { - check_source_free_repo()?; - check_manifest_source_checkouts_filtered(manifest, strict_local, |_| true)?; - check_postgres_source_spine()?; - if check_patch_applies { - prepare_postgres_source_tree()?; - } - check_source_lane_isolation()?; - Ok(()) - } - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } -} - -fn check_source_spine_for_source_lane_filtered( - manifest: &SourcesManifest, - source_lane: &str, - strict_local: bool, - check_patch_applies: bool, - include: F, -) -> Result<()> -where - F: Fn(&SourcePin) -> bool, -{ - match canonical_source_lane(source_lane)? { - "stable" => { - check_source_free_repo()?; - check_manifest_source_checkouts_filtered(manifest, strict_local, include)?; - check_postgres_source_spine()?; - if check_patch_applies { - prepare_postgres_source_tree()?; - } - check_source_lane_isolation()?; - Ok(()) - } - _ => unreachable!("canonical_source_lane returned an unsupported lane"), - } -} - -fn prepare_postgres_source_tree() -> Result { - let output = command_output("bash", &[POSTGRES_PREPARE_SCRIPT], Path::new("."))?; - let source = output - .lines() - .rev() - .map(str::trim) - .find(|line| !line.is_empty()) - .ok_or_else(|| anyhow!("{POSTGRES_PREPARE_SCRIPT} did not print a source path"))?; - let source = PathBuf::from(source); - ensure!( - source.join(".oliphaunt-wasix-source-fingerprint").is_file(), - "PG18 source-prep script did not produce a fingerprinted source tree at {}", - source.display() - ); - ensure_file(&source.join(".oliphaunt-wasix-postgres-version"))?; - let manifest = load_postgres_source_manifest()?; - let work_root = postgres_work_root_for_source(&source)?; - check_prepared_postgres_source(&manifest, &source, &work_root)?; - Ok(source) -} - -pub(super) fn source_checkout_path(name: &str) -> Option { - if !valid_source_name_component(name) { - return None; - } - Some(Path::new(SOURCE_CHECKOUT_ROOT).join(name)) -} - -fn valid_source_name_component(name: &str) -> bool { - !name.is_empty() - && !name.contains("..") - && !name.contains('/') - && !name.contains('\\') - && name - .chars() - .all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.')) -} - -fn valid_https_source_url(url: &str) -> bool { - let Some(rest) = url.strip_prefix("https://") else { - return false; - }; - if rest.is_empty() - || rest.contains('#') - || rest.contains('\\') - || rest.chars().any(char::is_whitespace) - { - return false; - } - let authority = rest.split(['/', '?']).next().unwrap_or_default(); - if authority.is_empty() || authority.contains('@') { - return false; - } - let (host, valid_port) = match authority.rsplit_once(':') { - Some((host, port)) => ( - host, - !port.is_empty() && port.chars().all(|ch| ch.is_ascii_digit()), - ), - None => (authority, true), - }; - valid_port - && !host.is_empty() - && host - .chars() - .all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '-' | '.')) -} - -fn valid_git_branch_name(branch: &str) -> bool { - !branch.is_empty() - && !branch.starts_with(['-', '/']) - && !branch.ends_with(['/', '.']) - && !branch.contains("..") - && !branch.contains("@{") - && !branch.chars().any(|ch| { - ch.is_ascii_control() - || ch.is_ascii_whitespace() - || matches!(ch, '~' | '^' | ':' | '?' | '*' | '[' | '\\') - }) - && branch - .split('/') - .all(|part| !part.is_empty() && !part.ends_with(".lock")) -} - -pub(super) fn load_wasix_toolchain_manifest() -> Result { - let toolchain_path = Path::new(env!("CARGO_MANIFEST_DIR")) - .join("../..") - .join("src/sources/toolchains/wasix.toml"); - let toolchain_text = fs::read_to_string(&toolchain_path) - .with_context(|| format!("read {}", toolchain_path.display()))?; - toml::from_str(&toolchain_text).with_context(|| format!("parse {}", toolchain_path.display())) -} - -pub(super) fn load_sources_manifest() -> Result { - let wasix = load_wasix_toolchain_manifest()?; - - let mut sources = Vec::new(); - let mut names = BTreeSet::new(); - let sources_root = Path::new("src/sources/third-party"); - for domain in ["shared", "native", "wasix"] { - let domain_dir = sources_root.join(domain); - if !domain_dir.exists() { - continue; - } - let mut entries = fs::read_dir(&domain_dir) - .with_context(|| format!("read {}", domain_dir.display()))? - .collect::>>() - .with_context(|| format!("list {}", domain_dir.display()))?; - entries.sort_by_key(|entry| entry.path()); - for entry in entries { - let path = entry.path(); - if path.extension().and_then(|ext| ext.to_str()) != Some("toml") { - continue; - } - let origin = match domain { - "shared" => SourceOrigin::SharedThirdParty, - "native" => SourceOrigin::NativeThirdParty, - "wasix" => SourceOrigin::WasixThirdParty, - _ => unreachable!("source domain list is closed"), - }; - push_source_pin(&mut sources, &mut names, &path, origin)?; - } - } - for path in extension_source_pin_paths()? { - push_source_pin(&mut sources, &mut names, &path, SourceOrigin::Extension)?; - } - - Ok(SourcesManifest { - toolchain: wasix.toolchain, - builder: wasix.builder, - build: wasix.build, - sources, - }) -} - -pub(super) fn validate_sources_manifest(manifest: &SourcesManifest) -> Result<()> { - if manifest.sources.is_empty() { - bail!("source metadata must contain at least one source pin"); - } - ensure_eq(&manifest.toolchain.wasmer, "7.2.1", "toolchain.wasmer")?; - ensure_eq( - &manifest.toolchain.wasmer_wasix, - "0.702.1", - "toolchain.wasmer-wasix", - )?; - ensure_eq(&manifest.toolchain.webc, "12.0.0", "toolchain.webc")?; - ensure_eq( - &manifest.toolchain.wasmer_llvm, - "22.1", - "toolchain.wasmer_llvm", - )?; - ensure_eq( - &manifest.toolchain.wasixcc.version, - "0.4.3", - "toolchain.wasixcc.version", - )?; - ensure_eq( - &manifest.toolchain.wasixcc.target, - "x86_64-unknown-linux-gnu", - "toolchain.wasixcc.target", - )?; - ensure_eq( - &manifest.toolchain.sysroots.version, - "2026-03-02.1", - "toolchain.sysroots.version", - )?; - ensure_eq( - &manifest.toolchain.llvm.release, - "21.1.204", - "toolchain.llvm.release", - )?; - ensure_eq( - &manifest.toolchain.llvm.reported_version, - "21.1.2", - "toolchain.llvm.reported_version", - )?; - ensure_eq( - &manifest.toolchain.binaryen.release, - "version_130", - "toolchain.binaryen.release", - )?; - ensure_eq( - &manifest.toolchain.binaryen.reported_version, - "130", - "toolchain.binaryen.reported_version", - )?; - ensure_eq( - &manifest.toolchain.assets_manifest, - "src/runtimes/liboliphaunt/wasix/assets/build/docker/pinned-wasixcc-assets.tsv", - "toolchain.assets_manifest", - )?; - if !manifest - .toolchain - .assets_manifest_sha256 - .chars() - .all(|ch| ch.is_ascii_hexdigit() && !ch.is_ascii_uppercase()) - || manifest.toolchain.assets_manifest_sha256.len() != 64 - { - bail!( - "toolchain.assets_manifest_sha256 must be a lowercase sha256 digest, got {}", - manifest.toolchain.assets_manifest_sha256 - ); - } - let assets_manifest_path = Path::new(&manifest.toolchain.assets_manifest); - ensure_eq( - &sha256_file(assets_manifest_path)?, - &manifest.toolchain.assets_manifest_sha256, - "toolchain assets manifest SHA-256", - )?; - let assets_manifest = fs::read_to_string(assets_manifest_path) - .with_context(|| format!("read {}", assets_manifest_path.display()))?; - for (asset, digest) in [ - ( - manifest.toolchain.wasixcc.asset.as_str(), - manifest.toolchain.wasixcc.sha256.as_str(), - ), - ( - "sysroot.tar.gz", - manifest.toolchain.sysroots.sysroot_sha256.as_str(), - ), - ( - "sysroot-eh.tar.gz", - manifest.toolchain.sysroots.sysroot_eh_sha256.as_str(), - ), - ( - "sysroot-ehpic.tar.gz", - manifest.toolchain.sysroots.sysroot_ehpic_sha256.as_str(), - ), - ( - "sysroot-exnref-eh.tar.gz", - manifest - .toolchain - .sysroots - .sysroot_exnref_eh_sha256 - .as_str(), - ), - ( - "sysroot-exnref-ehpic.tar.gz", - manifest - .toolchain - .sysroots - .sysroot_exnref_ehpic_sha256 - .as_str(), - ), - ( - manifest.toolchain.llvm.asset.as_str(), - manifest.toolchain.llvm.sha256.as_str(), - ), - ( - manifest.toolchain.binaryen.asset.as_str(), - manifest.toolchain.binaryen.sha256.as_str(), - ), - ] { - if !assets_manifest.lines().any(|line| { - let fields = line.split('\t').collect::>(); - fields.len() == 5 && fields[1] == asset && fields[3] == digest - }) { - bail!("toolchain assets manifest does not bind {asset} to metadata digest {digest}"); - } - } - ensure_eq( - &manifest.builder.base_image, - "ubuntu:24.04", - "builder.base_image", - )?; - if !manifest - .builder - .base_image_digest - .strip_prefix("sha256:") - .is_some_and(|digest| digest.len() == 64 && digest.chars().all(|ch| ch.is_ascii_hexdigit())) - { - bail!( - "builder.base_image_digest must pin a concrete sha256 digest, got {}", - manifest.builder.base_image_digest - ); - } - if manifest.builder.apt_snapshot.len() != 16 - || !manifest.builder.apt_snapshot.ends_with('Z') - || manifest.builder.apt_snapshot.as_bytes()[8] != b'T' - || !manifest - .builder - .apt_snapshot - .bytes() - .enumerate() - .all(|(index, byte)| index == 8 || index == 15 || byte.is_ascii_digit()) - { - bail!( - "builder.apt_snapshot must be a fixed YYYYMMDDTHHMMSSZ timestamp, got {}", - manifest.builder.apt_snapshot - ); - } - if manifest.builder.apt_snapshot_retention.trim().is_empty() { - bail!("builder.apt_snapshot_retention must document the snapshot retention boundary"); - } - let dockerfile_frontend = manifest - .builder - .dockerfile_frontend - .strip_prefix("docker/dockerfile:") - .and_then(|frontend| frontend.split_once("@sha256:")); - if !dockerfile_frontend.is_some_and(|(version, digest)| { - !version.is_empty() - && version != "latest" - && version - .bytes() - .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-')) - && digest.len() == 64 - && digest - .bytes() - .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) - }) { - bail!( - "builder.dockerfile_frontend must pin docker/dockerfile by lowercase sha256 digest, got {}", - manifest.builder.dockerfile_frontend - ); - } - ensure_eq( - &manifest.builder.snapshot_tls_root, - "src/runtimes/liboliphaunt/wasix/assets/build/docker/isrg-root-x1.pem", - "builder.snapshot_tls_root", - )?; - if manifest.builder.snapshot_tls_root_sha256.len() != 64 - || !manifest - .builder - .snapshot_tls_root_sha256 - .bytes() - .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) - { - bail!( - "builder.snapshot_tls_root_sha256 must be a lowercase sha256 digest, got {}", - manifest.builder.snapshot_tls_root_sha256 - ); - } - let tls_root_not_after = manifest.builder.snapshot_tls_root_not_after.as_bytes(); - if tls_root_not_after.len() != 20 - || !tls_root_not_after.iter().enumerate().all(|(index, byte)| { - matches!(index, 4 | 7) && *byte == b'-' - || index == 10 && *byte == b'T' - || matches!(index, 13 | 16) && *byte == b':' - || index == 19 && *byte == b'Z' - || !matches!(index, 4 | 7 | 10 | 13 | 16 | 19) && byte.is_ascii_digit() - }) - { - bail!( - "builder.snapshot_tls_root_not_after must be a UTC YYYY-MM-DDTHH:MM:SSZ timestamp, got {}", - manifest.builder.snapshot_tls_root_not_after - ); - } - ensure_eq( - &sha256_file(Path::new(&manifest.builder.snapshot_tls_root))?, - &manifest.builder.snapshot_tls_root_sha256, - "builder snapshot TLS root SHA-256", - )?; - let dockerfile = - fs::read_to_string("src/runtimes/liboliphaunt/wasix/assets/build/docker/Dockerfile") - .context("read WASIX build Dockerfile")?; - let apt_installer = fs::read_to_string( - "src/runtimes/liboliphaunt/wasix/assets/build/docker/install-pinned-apt-packages.sh", - ) - .context("read WASIX pinned APT installer")?; - if !dockerfile.contains(&format!( - "FROM {}@{}", - manifest.builder.base_image, manifest.builder.base_image_digest - )) { - bail!( - "WASIX build Dockerfile must pin the same builder base image digest as src/sources/toolchains/wasix.toml" - ); - } - if dockerfile.lines().next() - != Some(format!("# syntax={}", manifest.builder.dockerfile_frontend).as_str()) - { - bail!("WASIX build Dockerfile must pin the declared Dockerfile frontend digest"); - } - if !dockerfile.contains(&format!( - "OLIPHAUNT_WASIXCC_ASSET_MANIFEST_SHA256={}", - manifest.toolchain.assets_manifest_sha256 - )) { - bail!("WASIX build Dockerfile must pin the toolchain asset manifest SHA-256"); - } - if !dockerfile.contains(&format!( - "OLIPHAUNT_UBUNTU_APT_SNAPSHOT={}", - manifest.builder.apt_snapshot - )) || !dockerfile.contains("COPY --chmod=0555 install-pinned-apt-packages.sh") - || !dockerfile.contains("--snapshot \"$OLIPHAUNT_UBUNTU_APT_SNAPSHOT\"") - { - bail!( - "WASIX build Dockerfile must pass the declared Ubuntu snapshot to the pinned APT installer" - ); - } - if !dockerfile.contains(&format!( - "OLIPHAUNT_UBUNTU_SNAPSHOT_TLS_ROOT_SHA256={}", - manifest.builder.snapshot_tls_root_sha256 - )) || !dockerfile - .contains("COPY --chmod=0444 isrg-root-x1.pem /usr/local/share/oliphaunt/isrg-root-x1.pem") - || !dockerfile.contains("/etc/ssl/certs/ca-certificates.crt") - || !dockerfile.contains("sha256sum --check --strict") - { - bail!("WASIX build Dockerfile must verify and install the declared snapshot TLS root"); - } - if dockerfile.contains("Verify-Peer=false") || apt_installer.contains("Verify-Peer=false") { - bail!("WASIX snapshot acquisition must not disable TLS peer verification"); - } - for forbidden in ["raw.githubusercontent.com/wasix-org/wasixcc", "latest"] { - if dockerfile.contains(forbidden) { - bail!( - "WASIX build Dockerfile contains forbidden mutable installer input {forbidden:?}" - ); - } - } - ensure_eq( - &manifest.build.postgres_prefix, - "/", - "build.postgres_prefix", - )?; - ensure_eq( - &manifest.build.postgres_pkglibdir, - "/lib/postgresql", - "build.postgres_pkglibdir", - )?; - ensure_eq( - &manifest.build.postgres_sharedir, - "/share/postgresql", - "build.postgres_sharedir", - )?; - ensure_contains( - &manifest.build.main_flags, - "-fwasm-exceptions", - "build.main_flags", - )?; - ensure_no_flag_contains(&manifest.build.main_flags, "asyncify", "build.main_flags")?; - ensure_contains( - &manifest.build.extension_flags, - "-fwasm-exceptions", - "build.extension_flags", - )?; - ensure_no_flag_contains( - &manifest.build.extension_flags, - "asyncify", - "build.extension_flags", - )?; - ensure_contains( - &manifest.build.extension_flags, - "-fPIC", - "build.extension_flags", - )?; - ensure_contains( - &manifest.build.extension_flags, - "-Wl,-shared", - "build.extension_flags", - )?; - ensure_eq( - &manifest.build.archive_format, - "tar.zst", - "build.archive_format", - )?; - if !manifest.build.deterministic_archives { - bail!("build.deterministic_archives must be true"); - } - for source in &manifest.sources { - validate_source_pin(source)?; - } - Ok(()) -} - -fn validate_source_pin(source: &SourcePin) -> Result<()> { - if !valid_source_name_component(&source.name) - || !valid_https_source_url(&source.url) - || source - .mirror_url - .as_deref() - .is_some_and(|url| !valid_https_source_url(url)) - || !valid_git_branch_name(&source.branch) - { - bail!("invalid source pin in source metadata: {source:?}"); - } - if source - .source_date_epoch - .is_some_and(|epoch| epoch == 0 || epoch > 253_402_300_799) - { - bail!( - "source '{}' source_date_epoch must be within the portable UTC range 1..=253402300799", - source.name - ); - } - if source.name == "postgis" && source.source_date_epoch.is_none() { - bail!("PostGIS source metadata must pin source_date_epoch"); - } - match source.kind { - SourceKind::Git => { - if source.commit.len() != 40 - || !source - .commit - .chars() - .all(|ch| ch.is_ascii_digit() || ('a'..='f').contains(&ch)) - { - bail!( - "git source '{}' must pin an exact lowercase 40-hex commit", - source.name - ); - } - if source.sha256.is_some() || source.strip_prefix.is_some() { - bail!( - "git source '{}' must not set sha256 or strip-prefix", - source.name - ); - } - if source.mirror_url.as_deref() == Some(source.url.as_str()) { - bail!( - "git source '{}' mirror URL must differ from its primary URL", - source.name - ); - } - } - SourceKind::Archive => { - if source.mirror_url.is_some() { - bail!("archive source '{}' must not set mirror_url", source.name); - } - let sha256 = archive_sha256(source)?; - archive_strip_prefix(source)?; - ensure_eq( - &source.commit, - &sha256, - &format!("{} archive commit must equal archive sha256", source.name), - )?; - let url_path = source.url.split('?').next().unwrap_or_default(); - if !url_path.ends_with(".tar.gz") - && !url_path.ends_with(".tgz") - && !url_path.ends_with(".zip") - { - bail!( - "archive source '{}' must point at a .tar.gz, .tgz, or .zip URL", - source.name - ); - } - if source.strip_prefix.as_deref() == Some(".") && !url_path.ends_with(".zip") { - bail!( - "archive source '{}' may use a rootless strip prefix only for ZIP releases", - source.name - ); - } - } - } - Ok(()) -} - -fn extension_source_pin_paths() -> Result> { - let root = Path::new("src/extensions/external"); - if !root.exists() { - return Ok(Vec::new()); - } - let mut paths = Vec::new(); - collect_extension_source_pin_paths(root, &mut paths)?; - paths.sort(); - Ok(paths) -} - -fn collect_extension_source_pin_paths(dir: &Path, paths: &mut Vec) -> Result<()> { - let mut entries = fs::read_dir(dir) - .with_context(|| format!("read {}", dir.display()))? - .collect::>>() - .with_context(|| format!("list {}", dir.display()))?; - entries.sort_by_key(|entry| entry.path()); - for entry in entries { - let path = entry.path(); - if path.is_dir() { - collect_extension_source_pin_paths(&path, paths)?; - } else if path.file_name().and_then(|name| name.to_str()) == Some("source.toml") { - paths.push(path); - } - } - Ok(()) -} - -fn push_source_pin( - sources: &mut Vec, - names: &mut BTreeSet, - path: &Path, - origin: SourceOrigin, -) -> Result<()> { - let text = fs::read_to_string(path).with_context(|| format!("read {}", path.display()))?; - let mut source: SourcePin = - toml::from_str(&text).with_context(|| format!("parse {}", path.display()))?; - source.origin = origin; - if !names.insert(source.name.clone()) { - bail!("duplicate source pin '{}' in source metadata", source.name); - } - sources.push(source); - Ok(()) -} - -#[cfg(test)] -mod tests { - use std::path::Path; - - use super::{ - SourceFetchScope, source_checkout_path, valid_git_branch_name, valid_https_source_url, - validate_source_pin, - }; - use crate::{SOURCE_CHECKOUT_ROOT, SourceKind, SourceOrigin, SourcePin}; - - fn git_source(mirror_url: Option<&str>) -> SourcePin { - SourcePin { - name: "libxml2".to_owned(), - kind: SourceKind::Git, - url: "https://gitlab.gnome.org/GNOME/libxml2.git".to_owned(), - mirror_url: mirror_url.map(str::to_owned), - branch: "v2.14.6".to_owned(), - commit: "d23960a130c5bb82779c9405fbbf85e65fb3c57c".to_owned(), - source_date_epoch: None, - sha256: None, - strip_prefix: None, - origin: SourceOrigin::Extension, - } - } - - #[test] - fn source_checkout_path_is_derived_from_portable_source_name() { - assert_eq!( - source_checkout_path("postgis").expect("valid source"), - Path::new(SOURCE_CHECKOUT_ROOT).join("postgis") - ); - assert_eq!( - source_checkout_path("json-c").expect("valid source"), - Path::new(SOURCE_CHECKOUT_ROOT).join("json-c") - ); - - assert!(source_checkout_path("").is_none()); - assert!(source_checkout_path("../postgis").is_none()); - assert!(source_checkout_path("nested/postgis").is_none()); - assert!(source_checkout_path("nested\\postgis").is_none()); - } - - #[test] - fn rust_fetch_scopes_delegate_to_the_authoritative_fetcher() { - assert_eq!(SourceFetchScope::ProductionAll.as_arg(), "production-all"); - assert_eq!(SourceFetchScope::All.as_arg(), "all"); - assert_eq!(SourceFetchScope::NativeRuntime.as_arg(), "native-runtime"); - assert_eq!(SourceFetchScope::WasixRuntime.as_arg(), "wasix-runtime"); - assert_eq!(SourceFetchScope::Extensions.as_arg(), "extensions"); - assert_eq!( - SourceFetchScope::parse("all").unwrap(), - SourceFetchScope::All - ); - } - - #[test] - fn runtime_fetch_scopes_include_only_their_platform_sources() { - for origin in [SourceOrigin::SharedThirdParty, SourceOrigin::Extension] { - assert!(SourceFetchScope::NativeRuntime.includes(origin)); - assert!(SourceFetchScope::WasixRuntime.includes(origin)); - } - assert!(SourceFetchScope::NativeRuntime.includes(SourceOrigin::NativeThirdParty)); - assert!(!SourceFetchScope::NativeRuntime.includes(SourceOrigin::WasixThirdParty)); - assert!(SourceFetchScope::WasixRuntime.includes(SourceOrigin::WasixThirdParty)); - assert!(!SourceFetchScope::WasixRuntime.includes(SourceOrigin::NativeThirdParty)); - assert!(!SourceFetchScope::NativeRuntime.includes(SourceOrigin::Generated)); - assert!(!SourceFetchScope::WasixRuntime.includes(SourceOrigin::Generated)); - } - - #[test] - fn source_transport_and_branch_validation_reject_unsafe_inputs() { - assert!(valid_https_source_url( - "https://github.com/example/source.git" - )); - assert!(valid_https_source_url( - "https://example.test:8443/source.tgz?mirror=1" - )); - for url in [ - "http://github.com/example/source.git", - "ssh://git@github.com/example/source.git", - "https://user:secret@example.test/source.git", - "https://example.test/source.git#mutable", - "https://example.test\\source.git", - ] { - assert!(!valid_https_source_url(url), "unexpectedly accepted {url}"); - } - - assert!(valid_git_branch_name("oliphaunt/pinned-source")); - for branch in ["", "-force", "../main", "main.lock", "main~1", "bad name"] { - assert!( - !valid_git_branch_name(branch), - "unexpectedly accepted {branch}" - ); - } - } - - #[test] - fn git_source_mirror_must_be_a_distinct_canonical_https_url() { - validate_source_pin(&git_source(Some("https://github.com/GNOME/libxml2.git"))) - .expect("valid HTTPS mirror"); - - for mirror_url in [ - "http://github.com/GNOME/libxml2.git", - "https://user:secret@github.com/GNOME/libxml2.git", - "https://github.com/GNOME/libxml2.git#mutable", - ] { - let error = validate_source_pin(&git_source(Some(mirror_url))) - .expect_err("unsafe mirror URL must fail"); - assert!( - error.to_string().contains("invalid source pin"), - "unexpected error for {mirror_url}: {error:#}" - ); - } - - let primary = "https://gitlab.gnome.org/GNOME/libxml2.git"; - let error = validate_source_pin(&git_source(Some(primary))) - .expect_err("primary URL reused as mirror must fail"); - assert!( - error - .to_string() - .contains("mirror URL must differ from its primary URL"), - "unexpected error: {error:#}" - ); - } - - #[test] - fn postgis_requires_one_portable_source_date_epoch() { - let mut source = git_source(None); - source.name = "postgis".to_owned(); - source.url = "https://github.com/postgis/postgis.git".to_owned(); - source.branch = "3.6.3".to_owned(); - source.commit = "3d12666588a84b23a3147618eaa9b40b0fe5e796".to_owned(); - - let error = validate_source_pin(&source).expect_err("missing epoch must fail"); - assert!( - error - .to_string() - .contains("PostGIS source metadata must pin source_date_epoch"), - "unexpected error: {error:#}" - ); - - for invalid_epoch in [0, 253_402_300_800] { - source.source_date_epoch = Some(invalid_epoch); - let error = validate_source_pin(&source).expect_err("invalid epoch must fail"); - assert!( - error - .to_string() - .contains("source_date_epoch must be within the portable UTC range"), - "unexpected error for {invalid_epoch}: {error:#}" - ); - } - - source.source_date_epoch = Some(1_776_193_981); - validate_source_pin(&source).expect("canonical PostGIS epoch must pass"); - } - - #[test] - fn archive_sources_reject_git_mirror_metadata() { - let sha256 = "88dd96a8c0464eca144fc791ae60cd31cd8ee78321e67397e25fc095c4a19aa6"; - let source = SourcePin { - name: "libiconv".to_owned(), - kind: SourceKind::Archive, - url: "https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz".to_owned(), - mirror_url: Some("https://example.test/libiconv-1.19.tar.gz".to_owned()), - branch: "1.19".to_owned(), - commit: sha256.to_owned(), - source_date_epoch: None, - sha256: Some(sha256.to_owned()), - strip_prefix: Some("libiconv-1.19".to_owned()), - origin: SourceOrigin::Extension, - }; - - let error = validate_source_pin(&source).expect_err("archive mirror metadata must fail"); - assert!( - error - .to_string() - .contains("archive source 'libiconv' must not set mirror_url"), - "unexpected error: {error:#}" - ); - } - - #[test] - fn rootless_zip_release_is_a_valid_pinned_archive_source() { - let sha256 = "8577bb036a5c08204b1622a85485b92cdfaea521c251d22fd36899e99e426d9a"; - let mut source = SourcePin { - name: "icu-data".to_owned(), - kind: SourceKind::Archive, - url: "https://github.com/unicode-org/icu/releases/download/release-76-1/icu4c-76_1-data-bin-l.zip".to_owned(), - mirror_url: None, - branch: "release-76-1".to_owned(), - commit: sha256.to_owned(), - source_date_epoch: None, - sha256: Some(sha256.to_owned()), - strip_prefix: Some(".".to_owned()), - origin: SourceOrigin::SharedThirdParty, - }; - validate_source_pin(&source).expect("pinned rootless ZIP release must pass"); - - source.url = "https://example.test/icu-data.tar.gz".to_owned(); - let error = validate_source_pin(&source) - .expect_err("rootless tar releases must remain unsupported"); - assert!( - error - .to_string() - .contains("rootless strip prefix only for ZIP releases"), - "unexpected error: {error:#}" - ); - } -}